diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/CREDITS linux.ac/CREDITS --- linux.vanilla/CREDITS Tue Apr 3 17:31:50 2001 +++ linux.ac/CREDITS Sat Apr 14 01:13:50 2001 @@ -311,9 +311,6 @@ W: http://samba.org/~anton/ P: 1024/8462A731 4C 55 86 34 44 59 A7 99 2B 97 88 4A 88 9A 0D 97 D: sun4 port, Sparc hacker -S: 47 Robert Street -S: Marrickville NSW 2204 -S: Australia N: Hugh Blemings E: hugh@misc.nu @@ -331,6 +328,9 @@ D: AUN network protocols D: Co-architect of the parallel port sharing system D: IPv6 netfilter +S: FutureTV Labs Ltd +S: Brunswick House, 61-69 Newmarket Rd, Cambridge CB5 8EG +S: United Kingdom N: Thomas Bogendörfer E: tsbogend@alpha.franken.de @@ -666,6 +666,14 @@ S: K1N 6Z9 S: CANADA +N: Jeff Dike +E: jdike@karaya.com +W: http://user-mode-linux.sourceforge.net +D: User mode kernel port +S: RR1 Box 67C +S: Deering NH 03244 +S: USA + N: Eddie C. Dost E: ecd@skynet.be D: Linux/Sparc kernel hacker @@ -766,6 +774,11 @@ S: S-114 53 Stockholm S: Sweden +N: Michael Engel +E: engel@unix-ag.org +D: DECstation framebuffer drivers +S: Germany + N: Paal-Kristian Engstad E: engstad@intermetrics.com D: Kernel smbfs (to mount WfW, NT and OS/2 network drives.) @@ -1220,13 +1233,12 @@ S: USA N: Harald Hoyer -E: HarryH@Royal.Net -W: http://hot.spotline.de/ -W: http://home.pages.de/~saturn +E: harald.hoyer@parzelle.de +W: http://parzelle.de/ D: ip_masq_quake D: md boot support -S: Alleenstrasse 27 -S: D-71679 Asperg +S: Hohe Strasse 30 +S: D-70176 Stuttgart S: Germany N: Jan Hubicka @@ -1725,12 +1737,8 @@ S: Czech Republic N: Paul Mackerras -E: paulus@linuxcare.com +E: paulus@samba.org D: Linux port for PCI Power Macintosh -S: Linuxcare, Inc. -S: 24 Marcus Clarke Street -S: Canberra ACT 2601 -S: Australia N: Pat Mackinlay E: pat@it.com.au @@ -1879,6 +1887,11 @@ S: 80050-430 - Curitiba - Paraná S: Brazil +N: Karsten Merker +E: merker@linuxtag.org +D: DECstation framebuffer drivers +S: Germany + N: Michael Meskes E: meskes@debian.org P: 1024/04B6E8F5 6C 77 33 CA CC D6 22 03 AB AB 15 A3 AE AD 39 7D @@ -2359,8 +2372,8 @@ S: Brazil N: Stephen Rothwell -E: sfr@linuxcare.com.au -W: http://linuxcare.com.au/sfr +E: sfr@canb.auug.org.au +W: http://www.canb.auug.org.au/~sfr P: 1024/BD8C7805 CD A4 9D 01 10 6E 7E 3B 91 88 FA D9 C8 40 AA 02 D: Boot/setup/build work for setup > 2K D: Author, APM driver @@ -2403,12 +2416,12 @@ S: Germany N: Paul `Rusty' Russell -E: rusty@linuxcare.com +E: rusty@rustcorp.com.au W: http://www.samba.org/netfilter D: Ruggedly handsome. D: netfilter, ipchains with Michael Neuling. -S: 301/222 City Walk -S: Canberra ACT 2601 +S: 52 Moore St +S: Turner ACT 2612 S: Australia N: Bill Ryder @@ -2429,11 +2442,11 @@ S: Finland N: Thomas Sailer -E: sailer@ife.ee.ethz.ch +E: t.sailer@alumni.ethz.ch E: HB9JNX@HB9W.CHE.EU (packet radio) D: hfmodem, Baycom and sound card radio modem driver -S: Weinbergstrasse 76 -S: 8408 Winterthur +S: Markusstrasse 18 +S: 8006 Zuerich S: Switzerland N: Robert Sanders @@ -2516,6 +2529,14 @@ S: San Jose, California S: USA +N: Robert Siemer +E: Robert.Siemer@gmx.de +P: 2048/C99A4289 2F DC 17 2E 56 62 01 C8 3D F2 AC 09 F2 E5 DD EE +D: miroSOUND PCM20 radio RDS driver, ACI rewrite +S: Klosterweg 28 / i309 +S: 76131 Karlsruhe +S: Germany + N: Jaspreet Singh E: jaspreet@sangoma.com W: www.sangoma.com @@ -2696,7 +2717,7 @@ N: Andrew Tridgell E: tridge@samba.org -W: http://linuxcare.com.au/tridge/ +W: http://samba.org/tridge/ D: dosemu, networking, samba S: 3 Ballow Crescent S: MacGregor A.C.T 2615 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/Changes linux.ac/Documentation/Changes --- linux.vanilla/Documentation/Changes Tue Apr 3 17:31:51 2001 +++ linux.ac/Documentation/Changes Thu Apr 12 11:47:29 2001 @@ -31,7 +31,7 @@ Eine deutsche Version dieser Datei finden Sie unter . -Last updated: January 11, 2001 +Last updated: April 6, 2001 Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu). @@ -54,7 +54,7 @@ o util-linux 2.10o # fdformat --version o modutils 2.4.2 # insmod -V o e2fsprogs 1.19 # tune2fs -o reiserfsprogs 3.x.0d # reiserfsck 2>&1|grep reiserfsprogs +o reiserfsprogs 3.x.0j # reiserfsck 2>&1|grep reiserfsprogs o pcmcia-cs 3.1.21 # cardmgr -V o PPP 2.4.0 # pppd --version o isdn4k-utils 3.1pre1 # isdnctrl 2>&1|grep version @@ -148,7 +148,7 @@ -------- Upgrade to recent modutils to fix various outstanding bugs which are -seen more frequently under 2.3.x, and to enable auto-loading of USB +seen more frequently under 2.4.x, and to enable auto-loading of USB modules. In addition, the layout of modules under /lib/modules/`uname -r`/ has been made more sane. This change also requires that you upgrade to a recent modutils. @@ -227,7 +227,7 @@ The PPP driver has been restructured to support multilink and to enable it to operate over diverse media layers. If you use PPP, -upgrade pppd to at least 2.4.0b1. +upgrade pppd to at least 2.4.0. If you are not using devfs, you must have the device file /dev/ppp which can be made by: @@ -307,16 +307,16 @@ Mkinitrd -------- -o +o E2fsprogs --------- -o -o +o +o Reiserfsprogs ------------- -o +o LVM toolset ----------- @@ -347,7 +347,7 @@ PPP --- -o +o Isdn4k-utils ------------ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/Configure.help linux.ac/Documentation/Configure.help --- linux.vanilla/Documentation/Configure.help Tue Apr 3 17:31:51 2001 +++ linux.ac/Documentation/Configure.help Tue Apr 17 16:37:18 2001 @@ -13,8 +13,10 @@ # http://www.traduc.org/kernelfr # - Spanish, by Carlos Perelló Marín (fperllo@ehome.encis.es), at # http://visar.csustan.edu/~carlos/ +# XXX: Site has moved, new location has no Configure.help trans. # - Italian, by Alessandro Rubini (rubini@linux.it), at # ftp://ftp-pavia1.linux.it/pub/linux/Configure.help +# XXX: ftp-pavia1.linux.it: Non-existent host/domain # - Polish, by Cezar Cichocki (cezar@cs.net.pl), at # http://www.cs.net.pl/~cezar/Kernel # - German, by SuSE, at http://www.suse.de/~ke/kernel . This patch @@ -113,22 +115,40 @@ Management" code will be disabled if you say Y here. See also the files Documentation/smp.tex, Documentation/smp.txt, - Documentation/i386/IO-APIC.txt, Documentation/nmi_watchdog.txt and the - SMP-FAQ on the WWW at http://www.irisa.fr/prive/mentre/smp-faq/ . + Documentation/i386/IO-APIC.txt, Documentation/nmi_watchdog.txt and + the SMP-FAQ on the WWW at http://www.irisa.fr/prive/mentre/smp-faq/ If you don't know what to do here, say N. -APIC and IO-APIC Support on Uniprocessors +IO-APIC Support on Uniprocessors CONFIG_X86_UP_IOAPIC APIC (Advanced Programmable Interrupt Controller) is a scheme for delivering hardware interrupt requests to the CPU. It is commonly - used on systems with several CPU's. If you have a single-CPU system - which uses APIC, you can say Y here to use it. If you say Y here - even though your machine doesn't have APIC, then the kernel will - still run with no slowdown at all. + used on systems with several CPUs. If you have a single-CPU system + which has a processor that has an integrated APIC, you can say Y + here to enable and use it. If you say Y here even though your + machine doesn't have an APIC, then the kernel will still run with no + slowdown at all. The advantage of APIC support is the possibility + to use performance counters, and the APIC based NMI watchdog which + detects hard lockups. + + An IO-APIC is an SMP-capable replacement for PC-style interrupts + controllers, most SMP systems and a small number of uniprocessor + systems have these chips. Linux will try to detect and use this + chip, if it's not found then Linux falls back to PC-style interrupt + handling. - If you have system with several CPU's, you do not need to say Y - here: APIC will be used automatically. +APIC Support on Uniprocessors +CONFIG_X86_UP_APIC + APIC (Advanced Programmable Interrupt Controller) is a scheme for + delivering hardware interrupt requests to the CPU. It is commonly + used on systems with several CPUs. If you have a single-CPU system + which has a processor that has an integrated APIC, you can say Y + here to enable and use it. If you say Y here even though your + machine doesn't have an APIC, then the kernel will still run with no + slowdown at all. The advantage of APIC support is the possibility + to use performance counters, and the APIC based NMI watchdog which + detects hard lockups. Kernel math emulation CONFIG_MATH_EMULATION @@ -268,6 +288,11 @@ Most normal users won't need the RAM disk functionality, and can thus say N here. +Default RAM disk size +CONFIG_BLK_DEV_RAM_SIZE + The default value is 4096. Only change this if you know what are + you doing. If you are using IBM S/390, then set this to 8192. + Initial RAM disk (initrd) support CONFIG_BLK_DEV_INITRD The initial RAM disk is a RAM disk that is loaded by the boot loader @@ -415,7 +440,7 @@ To fine-tune ATA/IDE drive/interface parameters for improved performance, look for the hdparm package at - ftp://metalab.unc.edu/pub/Linux/kernel/patches/diskdrives/ . + http://www.ibiblio.org/pub/Linux/system/hardware . 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), @@ -711,7 +736,7 @@ IGNORE word93 Validation BITS CONFIG_IDEDMA_IVB Since various rules were applied and created ... et al. as it relates - the detection of vaild cable signals. This is a result of unclear terms + the detection of valid cable signals. This is a result of unclear terms in ATA-4 and ATA-5 standards. It is normally safe to answer Y; however, the default is N. @@ -868,9 +893,9 @@ This is a driver for the OPTi 82C621 EIDE controller. Please read the comments at the top of drivers/ide/opti621.c. -ServerWorks OSB4 chipset support (EXPERIMENTAL) +ServerWorks OSB4 chipset support CONFIG_BLK_DEV_OSB4 - This driver adds PIO/DMA support for the Serverworks OSB4 chipset + This driver adds PIO/(U)DMA support for the ServerWorks OSB4 chipset. Intel PIIXn chipsets support CONFIG_BLK_DEV_PIIX @@ -898,7 +923,7 @@ If unsure, say N. -PROMISE PDC20246/PDC20262/PDC20267 support +PROMISE PDC20246/PDC20262/PDC20265/PDC20267 support CONFIG_BLK_DEV_PDC202XX Promise Ultra33 or PDC20246 Promise Ultra66 or PDC20262 @@ -972,12 +997,10 @@ VIA82CXXX chipset support CONFIG_BLK_DEV_VIA82CXXX This allows you to configure your chipset for a better use while - running (U)DMA: it will allow you to enable efficiently the second - channel dma usage, as it may not be set by BIOS. It allows you to - pass a kernel command line at boot time in order to set fifo - config. If no command line is provided, it will try to set fifo + running PIO/(U)DMA, it will allow you to enable efficiently the second + channel dma usage, as it may not be set by BIOS. It will try to set fifo configuration at its best. It will allow you to get information from - /proc/ide/via provided you enabled "proc" support. + /proc/ide/via provided you enabled "/proc file system" support. Please read the comments at the top of drivers/ide/via82cxxx.c @@ -986,12 +1009,6 @@ If unsure, say N. -VIA82CXXX Tuning support (WIP) -CONFIG_VIA82CXXX_TUNING - Please read the comments at the top of drivers/ide/via82cxxx.c - - If unsure, say N. - Other IDE chipset support CONFIG_IDE_CHIPSETS Say Y here if you want to include enhanced support for various IDE @@ -1299,14 +1316,37 @@ have a high-level driver for the type of device that you want to support. -MicroSolutions backpack protocol +Micro Solutions BACKPACK Series 5 protocol CONFIG_PARIDE_BPCK - This option enables support for the MicroSolutions backpack parallel - port IDE protocol. If you chose to build PARIDE support into your - kernel, you may answer Y here to build in the protocol driver, - otherwise you should answer M to build it as a loadable module. The - module will be called bpck.o. You must also have a high-level driver - for the type of device that you want to support. + This option enables support for the Micro Solutions BACKPACK parallel + port Series 5 IDE protocol. (Most BACKPACK drives made before 1999 were + Series 5) Series 5 drives will NOT always have the Series noted on the + bottom of the drive. Series 6 drivers will. + + In other words, if your BACKPACK drive dosen't say "Series 6" on the + bottom, enable this option. + + If you chose to build PARIDE support into your kernel, you may answer Y + here to build in the protocol driver, otherwise you should answer M to + build it as a loadable module. The module will be called bpck.o. You + must also have a high-level driver for the type of device that you want + to support. + +Micro Solutions BACKPACK Series 6 protocol +CONFIG_PARIDE_BPCK6 + This option enables support for the Micro Solutions BACKPACK parallel + port Series 6 IDE protocol. (Most BACKPACK drives made after 1999 were + Series 6) Series 6 drives will have the Series noted on the bottom of + the drive. Series 5 drivers don't always have it noted. + + In other words, if your BACKPACK drive says "Series 6" on the bottom, + enable this option. + + If you chose to build PARIDE support into your kernel, you may answer Y + here to build in the protocol driver, otherwise you should answer M to + build it as a loadable module. The module will be called bpck6.o. You + must also have a high-level driver for the type of device that you want + to support. DataStor Commuter protocol CONFIG_PARIDE_COMM @@ -1501,6 +1541,15 @@ If unsure, say Y. +RAID-1/RAID-5 code (DANGEROUS) +CONFIG_RAID15_DANGEROUS + This new RAID1/RAID5 code has been freshly merged, and has not seen + enough testing yet. While there are no known bugs in it, it might + destroy your file systems, eat your data and start World War III. + You have been warned. + + If unsure, say N. + RAID-1 (mirroring) mode CONFIG_MD_RAID1 A RAID-1 set consists of several disk drives which are exact copies @@ -1616,12 +1665,12 @@ CONFIG_SGI_SN0_N_MODE The nodes of Origin 200, Origin 2000 and Onyx 2 systems can be configured in either N-Modes which allows for more nodes or M-Mode - which allows for more more memory. Your system is most probably + which allows for more memory. Your system is most probably running in M-Mode, so you should say N here. MIPS JAZZ onboard SONIC Ethernet support CONFIG_MIPS_JAZZ_SONIC - This is the driver for the onboard card of of MIPS Magnum 4000, + This is the driver for the onboard card of MIPS Magnum 4000, Acer PICA, Olivetti M700-10 and a few other identical OEM systems. MIPS JAZZ FAS216 SCSI support @@ -1630,6 +1679,12 @@ 4000, Acer PICA, Olivetti M700-10 and a few other identical OEM systems. +Kernel floating-point instruction emulation +CONFIG_MIPS_FPU_EMULATOR + This option enables the MIPS software floatingpoint support. Due to the + way floatingpoint works you should always enable this option unless + you exactly know what you're doing. + PCMCIA SCSI adapter support CONFIG_SCSI_PCMCIA Say Y here if you intend to attach a PCMCIA or CardBus card to your @@ -1680,6 +1735,16 @@ whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. +NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support +CONFIG_PCMCIA_NINJA_SCSI + If you intend to attach this type of PCMCIA SCSI host adapter to + your computer, say Y here and read Documentation/README.nsp_cs. + + This driver is also available as a module called nsp_cs.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. + CPU type CONFIG_CPU_R3000 Please make sure to pick the right CPU type. Linux/MIPS is not @@ -1837,8 +1902,8 @@ MAC address match support CONFIG_IP_NF_MATCH_MAC - mac matching allows you to match packets based on the source - ethernet address of the packet. + MAC matching allows you to match packets based on the source + Ethernet address of the packet. If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. @@ -1972,7 +2037,7 @@ CONFIG_IP_NF_TARGET_MARK This option adds a `MARK' target, which allows you to create rules in the `mangle' table which alter the netfilter mark (nfmark) field - associated with the packet packet prior to routing. This can change + associated with the packet prior to routing. This can change the routing method (see `IP: use netfilter MARK value as routing key') and can also be used by other subsystems to change their behavior. @@ -2110,7 +2175,6 @@ If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. - TCP Explicit Congestion Notification support CONFIG_INET_ECN Explicit Congestion Notification (ECN) allows routers to notify @@ -2128,72 +2192,6 @@ If in doubt, say N. -IP6 tables support (required for filtering/masq/NAT) -CONFIG_IP6_NF_IPTABLES - ip6tables is a general, extensible packet identification framework. - Currently only the packet filtering and packet mangling subsystem - for IPv6 use this, but connection tracking is going to follow. - Say 'Y' or 'M' here if you want to use either of those. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -IPv6 limit match support -CONFIG_IP6_NF_MATCH_LIMIT - limit matching allows you to control the rate at which a rule can be - matched: mainly useful in combination with the LOG target ("LOG - target support", below) and to avoid some Denial of Service attacks. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -MAC address match support -CONFIG_IP6_NF_MATCH_MAC - mac matching allows you to match packets based on the source - ethernet address of the packet. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -netfilter mark match support -CONFIG_IP6_NF_MATCH_MARK - Netfilter mark matching allows you to match packets based on the - `nfmark' value in the packet. This can be set by the MARK target - (see below). - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -Packet filtering -CONFIG_IP6_NF_FILTER - Packet filtering defines a table `filter', which has a series of - rules for simple packet filtering at local input, forwarding and - local output. See the man page for iptables(8). - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -Packet mangling -CONFIG_IP6_NF_MANGLE - This option adds a `mangle' table to iptables: see the man page for - iptables(8). This table is used for various packet alterations - which can effect how the packet is routed. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -MARK target support -CONFIG_IP6_NF_TARGET_MARK - This option adds a `MARK' target, which allows you to create rules - in the `mangle' table which alter the netfilter mark (nfmark) field - associated with the packet packet prior to routing. This can change - the routing method (see `IP: use netfilter MARK value as routing - key') and can also be used by other subsystems to change their - behavior. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - SYN flood protection CONFIG_SYN_COOKIES Normal TCP/IP networking is open to an attack known as "SYN @@ -2433,20 +2431,6 @@ a module, say M here and read Documentation/modules.txt. If unsure, say N. -CardBus serial device support -CONFIG_PCMCIA_SERIAL_CB - Say Y here to enable support for CardBus serial devices, including - serial port cards, modems, and the modem functions of multi-function - ethernet/modem devices. (CardBus cards are the newer and better - version of PCMCIA- or PC-cards: credit card size devices often - used with laptops.) - - 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 serial_cb.o. If you want to compile it as - a module, say M here and read Documentation/modules.txt. If unsure, - say N. - /dev/agpgart (AGP Support) (EXPERIMENTAL) CONFIG_AGP AGP (Accelerated Graphics Port) is a bus system mainly used to @@ -2522,12 +2506,15 @@ the GLX component for XFree86 3.3.6, which can be downloaded from http://utah-glx.sourceforge.net/ . -ALI M1541 support +ALI chipset support CONFIG_AGP_ALI This option gives you AGP support for the GLX component of the - XFree86 4.x on the ALi M1541 chipset. + XFree86 4.x on the following ALi chipsets. The supported chipsets + include M1541, M1621, M1631, M1632, M1641,M1647,and M1651. + For ALi-chipset question, ALi welcome you refer to + http://www.ali.com.tw/eng/support/index.shtml - This chipset can do AGP 1x and 2x, but note that there is an + The M1541 chipset can do AGP 1x and 2x, but note that there is an acknowledged incompatibility with Matrox G200 cards. Due to timing issues, this chipset cannot do AGP 2x with the G200. This is a hardware limitation. AGP 1x seems to be fine, though. @@ -2742,6 +2729,23 @@ If unsure, say Y. +PNPBIOS support +CONFIG_PNPBIOS + The PNPBIOS as defined in "Plug and Play BIOS Specification Version 1.0A + May 5, 1994" is used in Linux to autodetect built-in mainboard resources + (e.g. parallel port resources). + + Other features (e.g. change resources, ESCD, event notification, Docking + station information, ISAPNP services) are not used. + + Note: ACPI is expected to supersede PNPBIOS some day, currently it + co-exists nicely. + + See latest pcmcia-cs (stand-alone package) for a nice "lspnp" tools, + or have a look at /proc/bus/pnp. + + If unsure, say Y. + Support for hot-pluggable devices CONFIG_HOTPLUG Say Y here if you want to plug devices into your computer while @@ -2821,14 +2825,6 @@ section 6.4 of the Linux Programmer's Guide, available from http://www.linuxdoc.org/docs.html#guide . - Shared memory is now implemented using a new (minimal) virtual file - system. To mount it automatically at system startup just add the - following line to your /etc/fstab: - - none /dev/shm shm defaults 0 0 - - Saying Y here enlarges your kernel by about 18 KB. Just say Y. - BSD Process Accounting CONFIG_BSD_PROCESS_ACCT If you say Y here, a user level program will be able to instruct the @@ -2994,14 +2990,16 @@ - "Pentium-Classic" for the Intel Pentium. - "Pentium-MMX" for the Intel Pentium MMX. - "Pentium-Pro" for the Intel Pentium Pro/Celeron/Pentium II. - - "Pentium-III" for the Intel Pentium III. - - "Pentium-4" for the Intel Pentium 4 + - "Pentium-III" for the Intel Pentium III + and Celerons based on the coppermine core. + - "Pentium-4" for the Intel Pentium 4. - "K6" for the AMD K6, K6-II and K6-III (aka K6-3D). - - "Athlon" for the AMD Athlon (K7). + - "Athlon" for the AMD K7 family (Athlon/Duron/Thunderbird). - "Crusoe" for the Transmeta Crusoe series. - "Winchip-C6" for original IDT Winchip. - "Winchip-2" for IDT Winchip 2. - "Winchip-2A" for IDT Winchips with 3dNow! capabilities. + - "CyrixIII" for VIA Cyrix III or VIA C3. If you don't know what to do, choose "386". @@ -3216,6 +3214,11 @@ module will be called aty128fb.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Link-Up Systems LCD support (EXPERIMENTAL) +CONFIG_FB_L7200 + This driver supports the L7200 Color LCD. + Say Y if you want graphics support. + PowerMac "control" frame buffer device support CONFIG_FB_CONTROL This driver supports a frame buffer for the graphics adapter in the @@ -3509,7 +3512,7 @@ Virtual Frame Buffer support (ONLY FOR TESTING!) CONFIG_FB_VIRTUAL This is a `virtual' frame buffer device. It operates on a chunk of - unswapable kernel memory instead of on the memory of a graphics + unswappable kernel memory instead of on the memory of a graphics board. This means you cannot see any output sent to this frame buffer device, while it does consume precious memory. The main use of this frame buffer device is testing and debugging the frame @@ -4301,7 +4304,7 @@ packets with different FWMARK ("firewalling mark") values (see ipchains(8), "-m" argument). -Appletalk interfaces support +AppleTalk interfaces support CONFIG_APPLETALK AppleTalk is the way Apple computers speak to each other on a network. If your Linux box is connected to such a network and you @@ -4314,11 +4317,10 @@ want to join the conversation, say Y. You will need to use the netatalk package so that your Linux box can act as a print and file server for Macs as well as access AppleTalk printers. Check out - http://threepio.hitchcock.org/cgi-bin/faq/netatalk/faq.pl on the WWW - for details. EtherTalk is the name used for AppleTalk over Ethernet - and the cheaper and slower LocalTalk is AppleTalk over a proprietary - Apple network using serial links. EtherTalk and LocalTalk are fully - supported by Linux. + http://www.zettabyte.net/netatalk/ on the WWW for details. EtherTalk + is the name used for AppleTalk over Ethernet and the cheaper and + slower LocalTalk is AppleTalk over a proprietary Apple network using + serial links. EtherTalk and LocalTalk are fully supported by Linux. General information about how to connect Linux, Windows machines and Macs is on the WWW at http://www.eats.com/linux_mac_win.html . The @@ -4329,8 +4331,10 @@ 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 is called appletalk.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. I hear that - the GNU boycott of Apple is over, so even politically correct people + module, say M here and read Documentation/modules.txt. You almost + certainly want to compile it as a module so you can restart your + AppleTalk stack without rebooting your machine. I hear that the + GNU boycott of Apple is over, so even politically correct people are allowed to say Y here. AppleTalk-IP driver support @@ -4831,7 +4835,7 @@ with the Frames Diverter on, can do some *really* transparent www caching using a Squid proxy for example. - This is very usefull when you don't want to change your router's + 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: @@ -4916,7 +4920,7 @@ Routing messages CONFIG_RTNETLINK - If you say Y here, userspace programs can receive some network + If you say Y here, user space programs can receive some network related routing information over the netlink. 'rtmon', supplied with the iproute2 package (ftp://ftp.inr.ac.ru), can read and interpret this data. Information sent to the kernel over this link @@ -5084,6 +5088,15 @@ Note that extended debugging may create certain race conditions itself. Enable this ONLY if you suspect problems with the driver. +Fujitsu FireStream (FS50/FS155) +CONFIG_ATM_FIRESTREAM + Driver for the Fujitsu FireStream 155 (MB86697) and + FireStream 50 (MB86695) ATM PCI chips. + + This driver is also available as a module. If you want to compile + it as a module, say M here and read Documentation/modules.txt. The + module will be called firestream.o. + Enable usec resolution timestamps CONFIG_ATM_ZATM_EXACT_TS The uPD98401 SAR chip supports a high-resolution timer (approx. 30 @@ -5304,6 +5317,117 @@ the performances of the driver, and the size of your syslog files! Keep the debugging level to 0 during normal operations. +Fusion MPT device support +CONFIG_FUSION + LSI Logic Fusion(TM) Message Passing Technology (MPT) device support + provides high performance SCSI host initiator, and LAN [1] interface + services to a host system. The Fusion architecture is capable of + duplexing these protocols on high-speed Fibre Channel + (up to 2 GHz x 2 ports = 4 GHz) and parallel SCSI (up to Ultra-320) + physical medium. + + [1] LAN is not supported on parallel SCSI medium. + + These drivers require a Fusion MPT compatible PCI adapter installed in + the host system. MPT adapters contain specialized I/O processors + to handle I/O workload, and more importantly to offload this work + from the host CPU(s). + + If you have Fusion MPT hardware and want to use it, you can say + Y or M here to add MPT (base + ScsiHost) drivers. + = build lib (fusion.o), and link [static] into the kernel [2] proper + = compiled as [dynamic] modules [3] named: (mptbase.o, mptscsih.o) + + [2] In order enable capability to boot the linux kernel natively + from a Fusion MPT target device, you MUST answer Y here! + (currently requires CONFIG_BLK_DEV_SD) + [3] 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 as modules, say M here and read + Documentation/modules.txt. + + If unsure, say N. + + If you say Y or M here you will get a choice of these + additional protocol and support module options: Module Name: + Enhanced SCSI error reporting (isense.o) + Fusion MPT misc device (ioctl) driver (mptctl.o) + Fusion MPT LAN driver (mptlan.o) + + --- + Fusion MPT is trademark of LSI Logic Corporation, and it's architecture + is based on LSI Logic's Message Passing Interface (MPI) specification. + +Fusion MPT enhanced SCSI error reporting [optional] module +CONFIG_FUSION_ISENSE + The isense module (roughly stands for Interpret SENSE data) is + completely optional. It simply provides extra English readable + strings in SCSI Error Report(s) that might be generated from the + Fusion MPT SCSI Host driver, for example when a target device + returns a SCSI check condition on a I/O. Without this module + loaded you might see: + + SCSI Error Report =-=-= (ioc0,scsi5:0) + SCSI_Status=02h (CHECK_CONDITION) + Original_CDB[]: 2A 00 00 00 00 41 00 00 02 00 + SenseData[12h]: 70 00 02 00 00 00 00 0A 00 00 00 00 04 02 02 00 00 00 + SenseKey=2h (NOT READY); FRU=02h + ASC/ASCQ=29h/00h + + Where otherwise, if this module had been loaded, you would see: + + SCSI Error Report =-=-= (ioc0,scsi5:0) + SCSI_Status=02h (CHECK_CONDITION) + Original_CDB[]: 2A 00 00 00 00 41 00 00 02 00 - "WRITE(10)" + SenseData[12h]: 70 00 02 00 00 00 00 0A 00 00 00 00 04 02 02 00 00 00 + SenseKey=2h (NOT READY); FRU=02h + ASC/ASCQ=29h/00h "LOGICAL UNIT NOT READY, INITIALIZING CMD. REQUIRED" + + Say M for "Enhanced SCSI error reporting" to compile this optional module, + creating a driver named: isense.o + + NOTE: Support for building this feature into the kernel is not + available, due to kernel size considerations. + +Fusion MPT misc device (ioctl) driver [optional] module +CONFIG_FUSION_CTL + The Fusion MPT misc device driver provides specialized control + of MPT adapters via system ioctl calls. Use of ioctl calls to + the MPT driver requires that you create and use a misc device + node ala: + mknod /dev/mptctl c 10 240 + + One use of this ioctl interface is to perform an upgrade (reflash) + of the MPT adapter firmware. Refer to readme file(s) distributed + with the Fusion MPT linux driver for additional details. + + If enabled by saying M to this, a driver named: mptctl.o + will be compiled. + + If unsure whether you really want or need this, say no. + +Fusion MPT LAN driver [optional] +CONFIG_FUSION_LAN + This module supports LAN IP traffic over Fibre Channel port(s) + on Fusion MPT compatible hardware (LSIFC9xx chips). + The physical interface used is defined in RFC 2625. + Please refer to that document for details. + + Installing this driver requires the knowledge to configure and + activate a new network interface, "fc0", using standard Linux tools. + + If enabled by saying M to this, a driver named: mptlan.o + will be compiled. + + If unsure whether you really want or need this, say no. + + NOTES: This feature is NOT available nor supported for linux-2.2.x + kernels. You must be building a linux-2.3.x or linux-2.4.x kernel + in order to configure this option. + Support for building this feature into the linux kernel is not + yet available. + SCSI support? CONFIG_SCSI If you want to use a SCSI hard disk, SCSI tape drive, SCSI CDROM or @@ -5585,7 +5709,7 @@ Default: 253 Initial Bus Reset Settle Delay -CONFIG_AIC7XXX_RESET_DELAY +CONFIG_AIC7XXX_RESET_DELAY_MS The number of milliseconds to delay after an initial bus reset. The bus settle delay following all error recovery actions is dictated by the SCSI layer and is not affected by this value. @@ -7030,14 +7154,14 @@ PPP (Point to Point Protocol) is a newer and better SLIP. It serves the same purpose: sending Internet traffic over telephone (and other serial) lines. Ask your access provider if they support it, because - otherwise you can't use it; most internet access providers these + otherwise you can't use it; most Internet access providers these days support PPP rather than SLIP. To use PPP, you need an additional program called pppd as described - in Documentation/networking/ppp.txt and in the PPP-HOWTO, available - at http://www.linuxdoc.org/docs.html#howto . If you upgrade - from an older kernel, you might need to upgrade pppd as well. The - PPP option enlarges your kernel by about 16 KB. + in the PPP-HOWTO, available at http://www.linuxdoc.org/docs.html#howto + Make sure that you have the version of pppd recommended in + Documentation/Changes. The PPP option enlarges your kernel by about + 16 KB. There are actually two versions of PPP: the traditional PPP for asynchronous lines, such as regular analog phone lines, and @@ -8078,6 +8202,18 @@ The module will be called cosa.o. For general information about modules read Documentation/modules.txt. +Etinc PCISYNC serial boards support +CONFIG_DSCC4 + This is a driver for Etinc PCISYNC boards based on the Infineon + (ex. Siemens) DSCC4 chipset. It is supposed to work with the four + ports card. Take a look at http://www.cogenit.fr/dscc4 + for further informations about the driver and his configuration. + + The driver will be compiled as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called dscc4.o. For general information about + modules read Documentation/modules.txt. + Lan Media sync serial boards support CONFIG_LANMEDIA This is a driver for the following Lan Media family of serial boards. @@ -8164,13 +8300,26 @@ Sangoma WANPIPE(tm) multiprotocol cards CONFIG_VENDOR_SANGOMA - WANPIPE from Sangoma Technologies Inc. (http://www.sangoma.com ) is - a family of intelligent multiprotocol WAN adapters with data - transfer rates up to T1 (1.544 Mbps). They are also known as - Synchronous Data Link Adapters (SDLA) and designated S502E(A), S503 - or S508. These cards support the X.25, Frame Relay, and PPP - protocols. If you have one or more of these cards, say Y to this - option; you may then also want to read the file + + WANPIPE from Sangoma Technologies Inc. (http://www.sangoma.com) + is a family of intelligent multiprotocol WAN adapters with data + transfer rates up to 4Mbps. They are also known as Synchronous + Data Link Adapters (SDLA) and are designated as S514-PCI or S508-ISA. + These cards support + + - X.25, Frame Relay, PPP, Cisco HDLC protocols. + + - API support for protocols like HDLC (LAPB), + HDLC Streaming, X.25, Frame Relay and BiSync. + + - Ethernet Bridging over Frame Relay protocol. + + - MULTILINK PPP + + - Async PPP (Modem Dialup) + + If you have one or more of these cards, say M to this option; you + may then also want to read the file Documentation/networking/wanpipe.txt. The next questions will ask you about the protocols you want the driver to support. @@ -8179,44 +8328,58 @@ The module will be called wanpipe.o. For general information about modules read Documentation/modules.txt. -Maximum number of cards -CONFIG_WANPIPE_CARDS - Enter number of WANPIPE adapters installed in your machine. The - driver can support up to 8 cards. You may enter more than you - actually have if you plan to add more cards in the future without - re-compiling the driver, but remember that in this case you'll waste - some kernel memory (about 1K per card). - -WANPIPE Cisco HDLC support -CONFIG_WANPIPE_CHDLC - Say Y to this option if you are planning to connect a WANPIPE card - to a connection which uses the synchronous Cisco HDLC (High-level - Data Link Control) protocol. This protocol is often used on - high-speed leased lines like T1/E1. - WANPIPE X.25 support CONFIG_WANPIPE_X25 Say Y to this option if you are planning to connect a WANPIPE card - to an X.25 network. You should then also have said Y to "CCITT X.25 - Packet Layer" and "LAPB Data Link Driver", above. If you say N, the - X.25 support will not be included in the driver (saves about 16 KB - of kernel memory). + to an X.25 network. Note, this feature also includes the X.25 API + support used to develope custom applications over the X.25 protocol. + If you say N, the X.25 support will not be included in the driver. + The X.25 option is supported on S514-PCI and S508-ISA cards. WANPIPE Frame Relay support CONFIG_WANPIPE_FR Say Y to this option if you are planning to connect a WANPIPE card - to a frame relay network. You should then also have said Y to "Frame - Relay (DLCI) support", above. If you say N, the frame relay - support will not be included in the driver (saves about 16 KB of - kernel memory). + to a frame relay network, or use frame relay API to develope + custom applications over the Frame Relay protocol. + This feature also contains the Ethernet Bridging over Frame Relay, + where a WANPIPE frame relay link can be directly connected to the Linux + kernel bridge. If you say N, the frame relay support will + not be included in the driver. The Frame Relay option is + supported on S514-PCI and S508-ISA cards. WANPIPE PPP support CONFIG_WANPIPE_PPP Say Y to this option if you are planning to connect a WANPIPE card - to a leased line using Point-to-Point protocol (PPP). You should - then also have said Y to "PPP (point-to-point) support", above. If - you say N, the PPP support will not be included in the driver (saves - about 16 KB of kernel memory). + to a leased line using Point-to-Point protocol (PPP). If you say N, + the PPP support will not be included in the driver. The PPP option + is supported on S514-PCI/S508-ISA cards. + +WANPIPE MultiPort PPP support +CONFIG_WANPIPE_MULTPPP + Say Y to this option if you are planning to connect a WANPIPE card + to a leased line using Point-to-Point protocol (PPP). Note, the + MultiPort PPP uses the Linux Kernel SyncPPP protocol over the Sangoma + HDLC Streaming adapter. In this case each Sangoma adapter port + can support an independent PPP connection. For example, a single + Quad-Port PCI adapter can support up to four independent + PPP links. If you say N,the PPP support will not be included + in the driver. The PPP option is supported on S514-PCI/S508-ISA cards. + +WANPIPE Cisco HDLC support +CONFIG_WANPIPE_CHDLC + Say Y to this option if you are planning to connect a WANPIPE card + to a leased line using the Cisco HDLC protocol. This now supports + Dual Port Cisco HDLC on the S514-PCI/S508-ISA cards. + This support also allows user to build applications using the + HDLC streaming API. + + CHDLC Streaming driver also supports MULTILINK PPP + support that can bind multiple WANPIPE T1 cards into + a single logical channel. + + If you say N, the Cisco HDLC support and + HDLC streaming API and MULTILINK PPP will not be + included in the driver. MultiGate/COMX support CONFIG_COMX @@ -8288,7 +8451,7 @@ If you want to compile this as a module, say M and read Documentation/modules.txt. The module will be called i810-tco.o. - + MultiGate Cisco-HDLC and synchronous PPP protocol support CONFIG_COMX_PROTO_PPP Cisco-HDLC and synchronous PPP protocol driver for all MultiGate @@ -8351,6 +8514,49 @@ If you say N, the X.25 support will not be included in the driver (saves about 11 KB of kernel memory). +Generic HDLC driver +CONFIG_HDLC + Say Y to this option if your Linux box contains a WAN card supported + by this driver and you are planning to connect the box to a WAN + ( = Wide Area Network). You will need supporting software from + http://hq.pm.waw.pl/hdlc/. + Generic HDLC driver currently supports raw HDLC, Cisco HDLC, Frame + Relay, synchronous Point-to-Point Protocol (PPP) and X.25. + + If unsure, say N here. + +Synchronous Point-to-Point Protocol (PPP) +CONFIG_HDLC_PPP + Say Y to this option if you want generic HDLC driver to support + PPP over WAN (Wide Area Network) connections. + + If unsure, say N here. + +CCITT X.25 protocol +CONFIG_HDLC_X25 + Say Y to this option if you want generic HDLC driver to support + X.25 protocol over WAN (Wide Area Network) connections. + + If unsure, say N here. + +SDL RISCom/N2 driver +CONFIG_N2 + This driver is for RISCom/N2 single or dual channel ISA cards + made by SDL Communications Inc. If you have such a card, + say Y here and see http://hq.pm.waw.pl/pub/hdlc/ + + Note that N2csu and N2dds cards are not supported by this driver. + + If unsure, say N here. + +Moxa C101 driver +CONFIG_C101 + This driver is for C101 SuperSync ISA cards made by Moxa + Technologies Co., Ltd. If you have such a card, + say Y here and see http://hq.pm.waw.pl/pub/hdlc/ + + If unsure, say N here. + Ethernet (10 or 100Mbit) CONFIG_NET_ETHERNET Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common @@ -9595,6 +9801,18 @@ The module will be called tmspci.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Generic TMS380 ISA support +CONFIG_TMSISA + This tms380 module supports generic TMS380-based ISA cards. + + These cards are known to work: + - SysKonnect TR4/16 ISA (SK-4190) + + This driver is available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called tmsisa.o. If you want to compile it + as a module, say M here and read Documentation/modules.txt. + Madge Smart 16/4 PCI Mk2 support CONFIG_ABYSS This tms380 module supports the Madge Smart 16/4 PCI Mk2 @@ -10055,62 +10273,100 @@ Memory Technology Device (MTD) support CONFIG_MTD Memory Technology Devices are flash, RAM and similar chips, often - used for solid state filesystems on embedded devices. This option + used for solid state file systems on embedded devices. This option will provide the generic support for MTD drivers to register themselves with the kernel and for potential users of MTD devices to enumerate the devices which are present and obtain a handle on them. It will also allow you to select individual drivers for particular hardware and users of MTD device. If unsure, say N. +MTD debugging support +CONFIG_MTD_DEBUG + This turns on low-level debugging for the entire MTD sub-system. + +MTD debugging verbosity +CONFIG_MTD_DEBUG_VERBOSE + Determines the verbosity level of the MTD debugging messages. + M-Systems Disk-On-Chip 1000 support CONFIG_MTD_DOC1000 This provides an MTD device driver for the M-Systems DiskOnChip 1000 devices, which are obsolete so you probably want to say 'N'. -M-Systems Disk-On-Chip 2000 support +M-Systems Disk-On-Chip 2000 and Millennium support CONFIG_MTD_DOC2000 This provides an MTD device driver for the M-Systems DiskOnChip - 2000 devices. If you use this, you probably also want the NFTL - 'NAND Flash Translation Layer' below, which is used to emulate + 2000 and Millennium devices. Originally designed for the DiskOnChip + 2000, it also now includes support for the DiskOnChip Millennium. + If you have problems with this driver and the DiskOnChip Millennium, + you may wish to try the alternative Millennium driver below. To use + the alternative driver, you will need to undefine DOC_SINGLE_DRIVER + in the drivers/mtd/docprobe.c source code. + + If you use this device, you probably also want to enable the NFTL + 'NAND Flash Translation Layer' option below, which is used to emulate a block device by using a kind of filesystem on the flash chips. -M-Systems Disk-On-Chip Millennium support +Alternative Disk-On-Chip Millennium support CONFIG_MTD_DOC2001 - This provides an MTD device driver for the M-Systems DiskOnChip - Millennium devices. If you use this, you probably also want the - NFTL 'NAND Flash Translation Layer' below, which is used to emulate + This provides an alternative MTD device driver for the M-Systems + DiskOnChip Millennium devices. Use this if you have problems with + the combined DiskOnChip 2000 and Millennium driver above. To get + the DiskOnChip probe code to load and use this driver instead of + the other one, you will need to undefine DOC_SINGLE_DRIVER near + the beginning of drivers/mtd/docprobe.c + + If you use this device, you probably also want to enable the NFTL + 'NAND Flash Translation Layer' option below, which is used to emulate a block device by using a kind of filesystem on the flash chips. +Ramix PMC551 PCI Mezzanine ram card support +CONFIG_MTD_PMC551 + This provides a MTD device driver for the Ramix PMC551 RAM PCI card + from Ramix Inc. (http://www.ramix.com/products/memory/pmc551.html). + These devices come in memory configurations from 32M - 1G. If you + have one, you probably want to enable this. + + If this driver is compiled as a module you get the ability to select the + size of the aperture window pointing into the devices memory. What this + means is that if you have a 1G card, normally the kernel will use a 1G + memory map as it's view of the device. As a module, you can select a + 1M window into the memory and the driver will "slide" the window around + the PMC551's memory. This was particularly useful on the 2.2 kernels + on PPC architectures as there was limited kernel space to deal with. + Use extra onboard system memory as MTD device CONFIG_MTD_SLRAM If your CPU cannot cache all of the physical memory in your machine, you can still use it for storage or swap by using this driver to present it to the system as a Memory Technology Device. -Ramix PMC551 PCI Mezzanine ram card support -CONFIG_MTD_PMC551 - This provides an MTD device driver for the Ramix PMC551 RAM card. - If you have one, you probably want to enable this. - -PMC551 256M DRAM Bugfix. +PMC551 256M DRAM Bugfix CONFIG_MTD_PMC551_BUGFIX - Some PMC551 boards hacve invalid column and row mux values. This - option will fix them, but will break other memory configurations. + Some of Ramix's PMC551 boards with 256M configurations have invalid + column and row mux values. This option will fix them, but will break + other memory configurations. If unsure say N. + +PMC551 Debugging +CONFIG_MTD_PMC551_DEBUG + This option makes the PMC551 more verbose during it's operation and is + only really useful if you are developing on this driver or suspect a + possible hardware or driver bug. If unsure say N. Debugging RAM test driver CONFIG_MTD_MTDRAM - This enables a test MTD device driver which uses vmalloc() to - provide storage. You probably want to say 'N' unless you're - testing stuff, or unless you want to use it in place of a ramdisk - when I've eventually got round to making the CONFIG_BLK_DEV option - and you've turned it off. + This enables a test MTD device driver which uses vmalloc() to + provide storage. You probably want to say 'N' unless you're + testing stuff. Common Flash Interface (CFI) support CONFIG_MTD_CFI - Intel's Common Flash Interface specification provides a universal - method for probing the capabilities of flash devices. If you wish - to support any device which uses CFI-compliant devices, you need - to enable this option. + The Common Flash Interface specification was developed by Intel, + AMD and other flash manufactures that provides a universal method + for probing the capabilities of flash devices. If you wish to + support any device that is CFI-compliant, you need to enable this + option. Visit (http://www.amd.com/products/nvd/overview/cfi.html) + for more information on CFI. CFI support for Intel/Sharp Extended Command Set chips CONFIG_MTD_CFI_INTELEXT @@ -10122,10 +10378,10 @@ Flash chip mapping in physical memory CONFIG_MTD_PHYSMAP This provides a 'mapping' driver which allows the CFI probe and - command set driver code to communicate with flash chips which + command set driver code to communicate with flash chips which are mapped physically into the CPU's memory. You will need to configure the physical address and size of the flash chips on - your particular board. + your particular board as well as the bus width. Physical start location of flash chip mapping CONFIG_MTD_PHYSMAP_START @@ -10143,38 +10399,51 @@ map which should hopefully be in the documentation for your board. +CONFIG_MTD_PHYSMAP_BUSWIDTH + This is the total width of the data bus of the flash devices + in octets. For example, if you have a data bus width of 32 + bits, you would set the bus width octect value to 4. This is + used internally by the CFI drivers. + Flash chip mapping on Mixcom piggyback card CONFIG_MTD_MIXMEM This supports the paging arrangement for access to flash chips - on the Mixcom piggyback card, allowing the flash chip drivers - to get on with their job of driving the flash chips without + on the MixCOM piggyback card, allowing the flash chip drivers + to get on with their job of driving the flash chips without having to know about the paging. If you have one of these boards, - you probably want to enable this mapping driver. + you probably want to enable this mapping driver. More info is at + (http://www.itc.hu/). Flash chip mapping on Nora CONFIG_MTD_NORA If you had to ask, you don't have one. Say 'N'. +Flash chip mapping on PNC2000 +CONFIG_MTD_PNC2000 + PNC-2000 is the name of Network Camera product from PHOTRON + Ltd. in Japan. It uses CFI-compliant flash. + Flash chip mapping on Octagon 5066 SBC CONFIG_MTD_OCTAGON This provides a 'mapping' driver which supports the way in which the flash chips are connected in the Octagon-5066 Single Board - Computer. You will also need to complete and enable the driver - for JEDEC flash chips. + Computer. More information on the board is available at + (http://www.octagonsystems.com/Products/5066/5066.html). Flash chip mapping on RPXlite PPC board CONFIG_MTD_RPXLITE - The RPXLite PowerPC board has CFI-compliant chips mapped in + The RPXLite PowerPC board has CFI-compliant chips mapped in a strange sparse mapping. This 'mapping' driver supports that arrangement, allowing the CFI probe and command set driver code - to communicate with the chips on the RPXLite board. + to communicate with the chips on the RPXLite board. More at + (http://www.embeddedplanet.com/rpx_lite_specification_sheet.htm). Flash chip mapping on Tempustech VMAX SBC301 CONFIG_MTD_VMAX This provides a 'mapping' driver which supports the way in which the flash chips are connected in the Tempustech VMAX SBC301 Single - Board Computer. You will also need to complete and enable the driver - for JEDEC flash chips. + Board Computer. More information on the board is available at + (http://www.tempustech.com/tt301.htm). Direct chardevice access to MTD devices CONFIG_MTD_CHAR @@ -10195,15 +10464,15 @@ Later, it may be extended to perform read/erase/modify/write cycles on flash chips to emulate a smaller block size. Needless to say, - this is very unsafe, but could be useful for filesystems which are + this is very unsafe, but could be useful for file systems which are almost never written to. FTL (Flash Translation Layer) support CONFIG_FTL This provides support for the original Flash Translation Layer which is part of the PCMCIA specification. It uses a kind of pseudo- - filesystem on a flash device to emulate a block device with 512-byte - sectors, on top of which you put a 'normal' filesystem. You may find + file system on a flash device to emulate a block device with 512-byte + sectors, on top of which you put a 'normal' file system. You may find that the algorithms used in this code are patented unless you live in the Free World where software patents aren't legal - in the USA you are only permitted to use this on PCMCIA hardware, although @@ -10214,8 +10483,8 @@ CONFIG_NFTL This provides support for the NAND Flash Translation Layer which is used on M-Systems' DiskOnChip devices. It uses a kind of pseudo- - filesystem on a flash device to emulate a block device with 512-byte - sectors, on top of which you put a 'normal' filesystem. You may find + file system on a flash device to emulate a block device with 512-byte + sectors, on top of which you put a 'normal' file system. You may find that the algorithms used in this code are patented unless you live in the Free World where software patents aren't legal - in the USA you are only permitted to use this on DiskOnChip hardware, although @@ -10224,8 +10493,8 @@ Write support for NFTL (EXPERIMENTAL) CONFIG_NFTL_RW - If you're lucky, this will actually work. Don't whinge if it doesn't. - Contact dwmw2@infradead.org if you want to help to make it more + If you're lucky, this will actually work. Don't whine if it doesn't. + Contact (dwmw2@infradead.org) if you want to help to make it more reliable. Support for USB @@ -10399,6 +10668,16 @@ If unsure, say Y. +Input core support +CONFIG_INPUT + Say Y here if you want to enable any of the following options for + USB Human Interface Device (HID) support. + + Say Y here if you want to enable any of the USB HID options in the + USB support section which require Input core support. + + Otherwise, say N. + Keyboard support CONFIG_INPUT_KEYBDEV Say Y here if you want your USB HID keyboard (or an ADB keyboard @@ -10729,6 +11008,19 @@ 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 Communication Class Ethernet driver +CONFIG_USB_CDCETHER + This driver supports devices conforming to the Communication + Device Class Ethernet Control Model. This is used in some + cable modems (Ericsson, Broadcom and others). For more + details on the specification, get the Communication + Device Class specification from http://www.usb.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 CDCether.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 @@ -10755,6 +11047,36 @@ 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 KLSI KL5USB101-based ethernet device support (EXPERIMENTAL)' +CONFIG_USB_KAWETH + Say Y here if you want to use one of the following 10Mbps only + USB Ethernet adapters based on the KLSI KL5KUSB101B chipset: + 3Com 3C19250 + ADS USB-10BT + ATEN USB Ethernet + ASANTE USB To Ethernet Adapter + AOX Endpoints USB Ethernet + Correga K.K. + D-Link DSB-650C and DU-E10 + Entrega / Portgear E45 + Jaton USB Ethernet Device Adapter + Kingston Technology USB Ethernet Adapter + Linksys USB10T + Mobility USB-Ethernet Adapter + NetGear EA-101 + Peracom Enet and Enet2 + Portsmith Express Ethernet Adapter + Shark Pocket Adapter + SMC 2202USB + Sony Vaio port extender + + This driver is likely to work with most 10Mbps only USB Ethernet + adapters, including some "no brand" devices. + 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. + USB Kodak DC-2xx Camera support CONFIG_USB_DC2XX Say Y here if you want to connect this type of still camera to @@ -10867,12 +11189,29 @@ The module will be called dabusb.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Host-to-Host USB networking +CONFIG_USB_USBNET + This driver supports network links over USB with USB "Network" + or "data transfer" cables, often used to network laptops to PCs. + Such cables have chips from suppliers such as NetChip and Prolific. + Intelligent USB devices could also use this approach to provide + Internet access, using standard USB cabling. + + These links will have names like "usb0", "usb1", etc. They act + like two-node Ethernets, so you can use 802.1d Ethernet Bridging + (CONFIG_BRIDGE) to simplify your network routing. + + This code is also available as a kernel module (code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called usbnet.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 + bandwidth of 6 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 @@ -10909,6 +11248,49 @@ The module will be called dsbr100.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Always do synchronous disk IO for UBD +CONFIG_BLK_DEV_UBD_SYNC + The User-Mode Linux port includes a driver called UBD which will let + you access arbitrary files on the host computer as block devices. + Writes to such a block device are not immediately written to the + host's disk; this may cause problems if, for example, the User-Mode + Linux 'Virtual Machine' uses a journalling filesystem and the host + computer crashes. + + Synchronous operation (i.e. always writing data to the host's disk + immediately) is configurable on a per-UBD basis by using a special + kernel command line option. Alternatively, you can say Y here to turn + on synchronous operation by default for all block. + + If you're running a journalling filesystem (like reiserfs, for example) + in your virtual machine, you will want to say Y here. If you care for + the safety of the data in your virtual machine, Y is a wise choice too. + In all other cases (for example, if you're just playing around with + User-Mode Linux) you can choose N. + +Prompt for filesystems other than ext2, proc, /dev/pts, /dev +CONFIG_PROMPT_FS + Most User-Mode Linux users will use one of the pre-built root + filesystem images, and won't access any other filesystems. + + If you say N here, then the kernel will be compiled with support + for quota, procfs, ext2, the /dev/pts filesystem, optionally the + /dev filesystem, and no other filesystem options. + + If you are doing filesystem hacking, or want to use NFS or cramfs + (or any other filesystem option), you should say Y here and you'll + be asked the normal filesystem questions. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause this configure script to skip all + the questions about filesystems except devfs. If unsure, say N. + +Enable ptrace proxy +CONFIG_PT_PROXY + This option enables a debugging interface which allows gdb to debug + the kernel without needing to actually attach to kernel threads. + If you want to do kernel debugging, say Y here; otherwise say N. + Microtek USB scanner support CONFIG_USB_MICROTEK Say Y here if you want support for the Microtek X6USB and possibly @@ -11053,6 +11435,12 @@ called bfs.o. Note that the file system of your root partition (the one containing the directory /) cannot be compiled as a module. +CMS file system support +CONFIG_CMS_FS + Read only support for CMS minidisk file systems found on IBM mainframe + systems. Only the basic format is supported so far. + If you don't know what CMS is you probably don't want to know any more. + Compressed ROM file system support CONFIG_CRAMFS Saying Y here includes support for CramFs (Compressed ROM File @@ -11072,23 +11460,44 @@ If unsure, say N. +Virtual memory file system support +CONFIG_TMPFS + Tmpfs is a file system which keeps all files in virtual memory. + + In contrast to RAM disks, which get allocated a fixed amount of + physical RAM, tmpfs grows and shrinks to accommodate the files it + contains and is able to swap unneeded pages out to swap space. + + Everything is "virtual" in the sense that no files will be created + on your hard drive; if you reboot, everything in tmpfs will be + lost. + + You should mount the filesystem somewhere to be able to use + POSIX shared memory. Adding the following line to /etc/fstab should + take care of things: + + tmpfs /dev/shm tmpfs defaults 0 0 + + Remember to create the directory that you intend to mount tmpfs on + if necessary (/dev/shm is automagically created if you use devfs). + + You can set limits for the number of blocks and inodes used by the + filesystem with the mount options "size", "nr_blocks" and + "nr_inodes". These parameters accept a suffix k, m or g for kilo, + mega and giga and can be changed on remount. + + The initial permissions of the root directory can be set with the + mount option "mode". + Simple RAM-based file system support CONFIG_RAMFS Ramfs is a file system which keeps all files in RAM. It allows read and write access. - In contrast to RAM disks, which get allocated a fixed amount of RAM, - ramfs grows and shrinks to accommodate the files it contains. + It is more of an programming example than a useable filesystem. If + you need a file system which lives in RAM with limit checking use + tmpfs. - Before you can use this RAM-based file system, it has to be mounted, - meaning it has to be given a location in the directory hierarchy. If - you want to use the location /ramfiles for example, you would have - to create that directory first and then mount the file system by - saying "mount -t ramfs ramfs /ramfiles" or the equivalent line in - /etc/fstab. Everything is "virtual" in the sense that no files will - be created on your hard drive; if you reboot, everything in - /ramfiles will be lost. - If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be @@ -11264,6 +11673,16 @@ (the one containing the directory /) cannot be a module, so saying M could be dangerous. If unsure, say N. +PReP residual data support +CONFIG_PREP_RESIDUAL + Some PReP systems have residual data passed to the kernel by the + firmware. This allows detection of memory size, devices present and + other useful pieces of information. Sometimes this information is not + present or incorrect. + + Unless you expect to boot on a PReP system, there is not need to select + yes. + /proc file system support CONFIG_PROC_FS This is a virtual file system providing information about the status @@ -11448,12 +11867,16 @@ NTFS write support (DANGEROUS) CONFIG_NTFS_RW If you say Y here, you will (maybe) be able to write to NTFS file - systems as well as read from them. The read-write support in - NTFS is far from being complete and is not well tested. If you - say Y here, back up your NTFS volume first since it may get - damaged. Also, make sure to run chkdsk from within Microsoft - Windows NT after having performed any writes to a NTFS partition - from Linux to detect any problems as early as possible. + systems as well as read from them. The read-write support in NTFS + is far from being complete and is not well tested. If you say Y + here, back up your NTFS volume first, since it will probably get + damaged. Also, download the Linux-NTFS project distribution from + Sourceforge at http://sourceforge.net/projects/linux-ntfs/ and + always run the included ntfsfix utility after writing to an NTFS + partition from Linux to fix some of the damage done by the driver. + You should run ntfsfix _after_ unmounting the partition in Linux + but _before_ rebooting into Windows. When Windows next boots, + chkdsk will be run automatically to fix the remaining damage. Please note that write support is limited to Windows NT4 and earlier versions. @@ -11634,21 +12057,16 @@ whenever you want), say M here and read Documentation/modules.txt. The module will be called efs.o. -Journalling Flash File System (JFFS) support (EXPERIMENTAL) +Support for the Journalling Flash Filesystem CONFIG_JFFS_FS - JFFS is a new file system designed for use on flash memory devices - rather than on block devices. It was developed on the 2.0 kernel - by Axis Communications AB for use on their Linux-based products, - and released under GPL, then 'borrowed' and ported to work with - the 2.4 kernel and the new Memory Technology Device system. - - The 2.4 port is experimental and not yet supported by Axis. Basically, - the good bits are probably theirs, and if it's broken in 2.4 it's - probably our fault. See http://www.developer.axis.com/software/jffs/ - for more information about JFFS. - - Any potential patches or queries should be sent to Axis' mailing - list for JFFS: + JFFS is the Journaling Flash File System developed by Axis + Communications in Sweden, aimed at providing a crash/powerdown-safe + filesystem for disk-less embedded devices. Further information is + available at (http://developer.axis.com/software/jffs/). + +JFFS debugging verbosity +CONFIG_JFFS_FS_VERBOSE + Determines the verbosity level of the JFFS debugging messages. UFS file system support (read-only) CONFIG_UFS_FS @@ -11723,6 +12141,12 @@ file system support", above. If you don't know what all this is about, say N. +Minix subpartition support +CONFIG_MINIX_SUBPARTITION + Minix 2.0.0/2.0.2 subpartition table support for Linux. + Say Y here if you want to mount and use Minix 2.0.0/2.0.2 + subpartitions. + Sun partition tables support CONFIG_SUN_PARTITION Like most systems, SunOS uses its own hard disk partition table @@ -11749,6 +12173,12 @@ Say Y here if you would like to be able to read the hard disk partition table format used by SGI machines. +Ultrix partition support +CONFIG_ULTRIX_PARTITION + Say Y here if you would like to be able to read the hard disk + partition table format used by DEC (now Compaq) Ultrix machines. + Otherwise, say N. + ADFS file system support (EXPERIMENTAL) CONFIG_ADFS_FS The Acorn Disc Filing System is the standard file system of the @@ -11998,7 +12428,7 @@ nls default codepage CONFIG_NLS_DEFAULT - The default NLS used when mounting filesystem. Currently, the valid + The default NLS used when mounting file system. Currently, the valid values are: big5, cp437, cp737, cp775, cp850, cp852, cp855, cp857, cp860, cp861, cp862, cp863, cp864, cp865, cp866, cp869, cp874, cp932, cp936, @@ -12187,7 +12617,7 @@ nls codepage 932 CONFIG_NLS_CODEPAGE_932 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -12199,7 +12629,7 @@ nls codepage 936 CONFIG_NLS_CODEPAGE_936 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -12210,7 +12640,7 @@ nls codepage 949 CONFIG_NLS_CODEPAGE_949 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -12220,7 +12650,7 @@ nls codepage 950 CONFIG_NLS_CODEPAGE_950 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -12402,7 +12832,7 @@ If unsure, say Y. Support for PowerMac keyboard -CONFIG_MAC_KEYBOARD +CONFIG_ADB_KEYBOARD This option allows you to use an ADB keyboard attached to your machine. Note that this disables any other (ie. PS/2) keyboard support, even if your machine is physically capable of using both at @@ -12736,8 +13166,8 @@ how to pass options to the kernel at boot time.) The syntax of the "lp" command line option can be found in drivers/char/lp.c. - If you have more than 3 printers, you need to increase the LP_NO - variable in lp.c. + If you have more than 8 printers, you need to increase the LP_NO + macro in lp.c and the PARPORT_MAX macro in parport.h. Support for console on line printer CONFIG_LP_CONSOLE @@ -13333,6 +13763,11 @@ is selected, the module will be called r128.o. AGP support for this card is strongly suggested (unless you have a PCI version). +ATI Radeon +CONFIG_DRM_RADEON + Choose this option if you have a ATI Radeon graphics card. + If M is selected, the module will be called radeon.o. + Intel I810 CONFIG_DRM_I810 Choose this option if you have an Intel I810 graphics card. If M is @@ -13742,17 +14177,32 @@ module, say M here and read Documentation/modules.txt. Most people will say N. +ZF MachZ Watchdog +CONFIG_MACHZ_WDT + If you are using a ZF Micro MachZ processor, say Y here, otherwise N. + This is the driver for the watchdog timer builtin on that processor + using ZF-Logic interface. This watchdog simply watches your kernel to + make sure it doesn't freeze, and if it does, it reboots your computer + after a certain amount of time. + + 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 is called machzwd.o. If you want to compile it as a module, + say M here and read Documentation/modules.txt. + Toshiba Laptop support CONFIG_TOSHIBA - If you intend to run this the kernel on a Toshiba portable say yes - here. This adds a driver to safely access the System Management - Mode of the CPU on Toshiba portables. The System Management Mode + This adds a driver to safely access the System Management Mode + of the CPU on Toshiba portables. The System Management Mode is used to set the BIOS and power saving options on Toshiba portables. For information on utilities to make use of this driver see the - Toshiba Linux utilities website at: + Toshiba Linux utilities web site at: http://www.buzzard.org.uk/toshiba/ + Say Y if you intend to run this kernel on a Toshiba portable. + Say N otherwise. + /dev/cpu/microcode - Intel IA32 CPU microcode support CONFIG_MICROCODE If you say Y here and also to "/dev file system support" in the @@ -13787,6 +14237,18 @@ with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to /dev/cpu/31/cpuid. +SBC-60XX Watchdog Timer +CONFIG_60XX_WDT + This driver can be used with the watchdog timer found on some + single board computers, namely the 6010 PII based computer. + It may well work with other cards. It reads port 0x443 to enable + and re-set the watchdog timer, and reads port 0x45 to disable + the watchdog. If you have a card that behave in similar ways, + you can probably make this driver work with your card as well. + + You can compile this driver directly into the kernel, or use + it as a module. The module will be called sbc60xxwdt.o. + Enhanced Real Time Clock Support CONFIG_RTC If you say Y here and create a character special file /dev/rtc with @@ -14253,6 +14715,8 @@ 16 or Logitech SoundMan 16 sound card. Answer N if you have some other card made by Media Vision or Logitech since those are not PAS16 compatible. Please read Documentation/sound/PAS16. + It is not necessary to add Sound Blaster support separately; it + is included in PAS support. If you compile the driver into the kernel, you have to add "pas2=,,,,,,, @@ -14459,13 +14923,15 @@ See Documentation/sound/CS4232 for more information on configuring this card. -Support for Yamaha OPL3-SA2, SA3, and SAx based PnP cards +Support for Yamaha OPL3-SA2 and SA3 based PnP cards CONFIG_SOUND_OPL3SA2 Say Y or M if you have a card based on one of these Yamaha - sound chipsets. Read Documentation/sound/OPL3-SA2 for more - information on configuring these cards. + sound chipsets or the "SAx", which is actually a SA3. Read + Documentation/sound/OPL3-SA2 for more information on configuring + these cards. - If you compile the driver into the kernel, you have to add + If you compile the driver into the kernel and do not also + configure in the optional ISA PnP support, you will have to add "opl3sa2=,,,,," to the kernel command line. @@ -14578,17 +15044,30 @@ If unsure, say Y. -ACI mixer (miroPCM12/PCM20) +Yamaha PCI native mode support (EXPERIMENTAL) +CONFIG_SOUND_YMFPCI + This is an experimental driver that uses Yamaha PCI sound cards in + the native mode. You may also want to try another driver, + "Yamaha PCI legacy mode support" under the OSS drivers. + +Yamaha PCI legacy mode support +CONFIG_SOUND_YMPCI + This is a driver for Yamaha PCI sound cards that turns them + to the Sound Blaster compatible mode. You don't need to enable + Sound Blaster support to use it. + +ACI mixer (miroSOUND PCM1-pro/PCM12/PCM20 radio) CONFIG_SOUND_ACI_MIXER ACI (Audio Command Interface) is a protocol used to communicate with - the microcontroller on some sound cards produced by miro, e.g. the - miroSOUND PCM12 and PCM20. The main function of the ACI is to - control the mixer and to get a product identification. - - This Voxware ACI driver currently only supports the ACI functions on - the miroSOUND PCM12 and PCM20 cards. On the PCM20, ACI also controls - the radio tuner. This is supported in the video4linux - radio-miropcm20 driver. + the microcontroller on some sound cards produced by miro and Cardinal + Technologies. The main function of the ACI is to control the mixer + and to get a product identification. + + This Voxware ACI driver currently supports the ACI functions on the + miroSOUND PCM1-pro, PCM12 and PCM20 radio. On the PCM20 radio, ACI + also controls the radio tuner. This is supported in the video4linux + miropcm20 driver (say M or Y here and go back to "Multimedia devices" + -> "Radio Adapters"). SB32/AWE support CONFIG_SOUND_AWE32_SYNTH @@ -14647,7 +15126,7 @@ SC-6600 CDROM Interface CONFIG_SC6600_CDROM - This is used to activate the the CDROM interface of the Audio Excel + This is used to activate the CDROM interface of the Audio Excel DSP 16 card. Enter: 0 for Sony, 1 for Panasonic, 2 for IDE, 4 for no CDROM present. @@ -14661,6 +15140,11 @@ driver as a module you have to specify the MPU I/O base address with the parameter 'mpu_base=0xNNN'. +C-Media PCI (CMI8338/8378) +CONFIG_SOUND_CMPCI + Say Y or M if you have a PCI sound card using the CMI8338 + or the CMI8378 chip.set. + Creative EMU10K1 based PCI sound cards CONFIG_SOUND_EMU10K1 Say Y or M if you have a PCI sound card using the EMU10K1 @@ -15221,6 +15705,11 @@ latest isdn4k-utils package. Please read the file Documentation/isdn/README.eicon for more information. +Eicon legacy driver +CONFIG_ISDN_DRV_EICON_OLD + Say Y here to use your Eicon active ISDN card with ISDN4Linux + isdn module. + Eicon Diva Server card support CONFIG_ISDN_DRV_EICON_PCI Say Y here if you have an Eicon Diva Server (BRI/PRI/4BRI) ISDN card. @@ -15235,7 +15724,7 @@ Documentation/isdn/README.eicon for more information. Eicon driver type standalone -CONFIG_ISDN_DRV_EICON_STANDALONE +CONFIG_ISDN_DRV_EICON_DIVAS Enable this option if you want the eicon driver as standalone version with no interface to the ISDN4Linux isdn module. If you say Y here, the eicon module only supports the Diva Server PCI @@ -15981,22 +16470,34 @@ Processor Type CONFIG_6xx There are four types of PowerPC chips supported. The more common - types (601, 603, 604, 740, 750), the Motorola embedded versions - (821, 823, 850, 855, 860), the IBM embedded versions (403 and + types (601, 603, 604, 740, 750, 7400), the Motorola embedded versions + (821, 823, 850, 855, 860, 8260), the IBM embedded versions (403 and 405) and the high end 64 bit Power processors (Power 3, Power 4). - Unless you are building a kernel for one of the embedded - processor systems, or a 64 bit IBM RS/6000, choose 6xx. Note that - the kernel runs in 32-bit mode even on 64-bit chips. + Unless you are building a kernel for one of the embedded processor + systems, or a 64 bit IBM RS/6000, choose 6xx. Note that the kernel + runs in 32-bit mode even on 64-bit chips. + +Workarounds for PPC601 bugs +CONFIG_PPC601_SYNC_FIX + Some versions of the PPC601 (the first PowerPC chip) have bugs which + mean that extra synchronization instructions are required near certain + instructions, typically those that make major changes to the CPU state. + These extra instructions reduce performance slightly. If you say N + here, these extra instructions will not be included, resulting in a + kernel which will run faster but may not run at all on some systems + with the PPC601 chip. + + If in doubt, say Y here. Machine Type -CONFIG_PMAC +CONFIG_ALL_PPC Linux currently supports several different kinds of PowerPC-based machines: Apple Power Macintoshes and clones (such as the Motorola Starmax series), PReP (PowerPC Reference Platform) machines such as - the Motorola PowerStack, Amiga Power-Up systems (APUS), CHRP and the - embedded MBX boards from Motorola. Currently, a single kernel binary - only supports one type or the other. However, there is very early - work on support for CHRP, PReP and PowerMac's from a single binary. + the Motorola PowerStack, CHRP (Common Hardware Reference Platform), + the embedded MBX boards from Motorola and many others. Currently, + the default option is to build a kernel which works on the first + three. Support for other machines is currently incomplete. Power management support for PowerBooks CONFIG_PMAC_PBOOK @@ -16006,7 +16507,7 @@ must get the power management daemon, pmud, to make it work and you must have the /dev/pmu device (see the pmud README). - Get pmud from ftp://linuxcare.com.au/pub/ppclinux/pmud/ + Get pmud from ftp://ftp.samba.org/pub/ppclinux/pmud/ If you have a PowerBook, you should say Y. @@ -16056,6 +16557,37 @@ an image of the device tree that the kernel copies from Open Firmware. If unsure, say Y here. +RTAS proc interface +CONFIG_PPC_RTAS + When you use this option, you will be able to use RTAS from + userspace. + + RTAS stands for RunTime Abstraction Services and should + provide a portable way to access and set system information. This is + commonly used on RS/6000 (pSeries) computers. + + You can access RTAS via the special proc filesystem entry rtas. + Don't confuse this rtas entry with the one in /proc/device-tree/rtas + which is readonly. + + If you don't know if you can use RTAS look into + /proc/device-tree/rtas. If there are some entries, it is very likely + that you will be able to use RTAS. + + You can do cool things with rtas. To print out information about + various sensors in the system, just do a + + $ cat /proc/rtas/sensors + + or if you power off your machine at night but want it running when + you enter your office at 7:45 am, do a + + # date -d 'tomorrow 7:30' +%s > /proc/rtas/poweron + + and shutdown. + + If unsure, say Y + MESH (Power Mac internal SCSI) support CONFIG_SCSI_MESH Many Power Macintoshes and clones have a MESH (Macintosh Enhanced @@ -16120,16 +16652,6 @@ whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. -Symbios 53c885 (Synergy ethernet) support -CONFIG_NCR885E - This is and Ethernet driver for the dual-function NCR 53C885 - SCSI/Ethernet controller. - - This driver is also available as a module called ncr885e.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. - National DP83902AV (Oak ethernet) support CONFIG_OAKNET Say Y if your machine has this type of Ethernet network card. @@ -16337,11 +16859,11 @@ say M here and read Documentation/modules.txt. The module will be called i2c-parport.o. -Miro PCM20 Radio +miroSOUND PCM20 radio CONFIG_RADIO_MIROPCM20 Choose Y here if you have this FM radio card. You also need to say Y - to "ACI mixer (miroPCM12/PCM20)" (in "additional low level sound - drivers") for this to work. + to "ACI mixer (miroSOUND PCM1-pro/PCM12/PCM20 radio)" (in "Sound") + for this to work. In order to control your radio card, you will need to use programs that are compatible with the Video for Linux API. Information on @@ -16351,7 +16873,22 @@ 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-miropcm20.o + called miropcm20.o + +Guillemot MAXI Radio FM 2000 Radio Card +CONFIG_RADIO_MAXIRADIO + Choose Y here if you have this radio card. This card may also be + found as Gemtek PCI FM. + + 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 . + + 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-maxiradio.o GemTek Radio Card CONFIG_RADIO_GEMTEK @@ -16486,6 +17023,17 @@ monochrome Quickcam, Quickcam VC or QuickClip. It is also available as a module (c-qcam.o). Read Documentation/video4linux/CQcam.txt for more information. + +Winbond W9966CF Webcam Video For Linux +CONFIG_VIDEO_W9966 + Video4linux driver for Winbond's w9966 based Webcams. + Currently tested with the LifeView FlyCam Supra. + If you have one of these cameras, say Y here + otherwise say N. + This driver is also available as a module (w9966.o) + + Checkout Documentation/video4linux/w9966.txt and w9966.c + for more information. CPiA Video For Linux CONFIG_VIDEO_CPIA @@ -16523,6 +17071,68 @@ from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. +IBM's S/390 architecture +CONFIG_ARCH_S390 + Select this option, if you want to run the Kernel on one of IBM's + mainframes of the S/390 generation. You should have installed the + s390-compiler released by IBM (based on gcc-2.95.1) before. + +Merge some code into the kernel to make the image IPLable +CONFIG_IPLABLE + If you want to use the produced kernel to IPL directly from a + device, you have to merge a bootsector specific to the device + into the first bytes of the kernel. You will have to select the + IPL device on another question, that pops up, when you select + CONFIG_IPLABE. + +IPL from a /390 tape unit +CONFIG_IPL_TAPE + Select this option if you want to IPL the image from a Tape. + +IPL from a virtual card reader emulated by VM/ESA +CONFIG_IPL_RDR_VM + Select this option if you are running under VM/ESA and want + to IPL the image from the emulated card reader. + +IPL from a real card reader +CONFIG_IPL_RDR + Select this option if you want to IPL the image from a real + card reader. Maybe you still got one and want to try. We didn't + test. + +IBMs S/390 Harddisks (DASDs) +CONFIG_DASD + Enable this option if you want to access DASDs directly utilizing + S/390s channel subsystem commands. This is necessary for running + natively on a single image or an LPAR. + +Enable DASD fast write +CONFIG_DASD_FAST_IO + Enable fast I/O for DASDs. That means that the next I/O command + is already issued at interrupt time, if an I/O request is pending. + This option gives significant speedup of I/O, because we don't + schedule the bottom-halves as often as Intel. + +Support for IBM-style disk-labels (S/390) +CONFIG_S390_PARTITION + Enable this option to assure standard IBM labels on the DASDs. + You must enable it, if you are planning to access DASDs also + attached to another IBM mainframe operation system (OS/390, + VM/ESA, VSE/ESA). + +ECKD devices +CONFIG_DASD_ECKD + ECKD devices are the most commonly used devices. you should enable + this option unless you are very sure to have no ECKD device. + +CKD devices +CONFIG_DASD_CKD + CKD devices are currently unsupported. + +FBA devices +CONFIG_DASD_FBA + FBA devices are currently unsupported. + SAB3036 tuner support CONFIG_TUNER_3036 Say Y here to include support for Philips SAB3036 compatible tuners. @@ -16559,7 +17169,7 @@ Saying N will reduce the size of the Footbridge kernel. Include support for the EBSA285 -CONFIG_ARCH_EBSA285 +CONFIG_ARCH_EBSA285_HOST Say Y here if you intend to run this kernel on the EBSA285 card in host ("central function") mode. @@ -16645,50 +17255,14 @@ http://www.visuaide.com/pagevictor.en.html for information on this system. -Support ARM610 processor -CONFIG_CPU_ARM6 - Say Y here if you wish to include support for the ARM610 processor. - -Support ARM710 processor -CONFIG_CPU_ARM7 - Say Y here if you wish to include support for the ARM710 processor. - -Support StrongARM(R) SA-110 processor -CONFIG_CPU_SA110 - Say Y here if you wish to include support for the Intel(R) - StrongARM(R) SA-110 processor. - -Support ARM720 processor -CONFIG_CPU_ARM720 - Say Y here if you wish to include support for the ARM720 processor. - -Support ARM920 -CONFIG_CPU_ARM920 - Say Y here if you wish to include support for the ARM920 processor. - -Support ARM610 processor -CONFIG_CPU_ARM6 - Say Y here if you wish to include support for the ARM610 processor. - -Support ARM710 processor -CONFIG_CPU_ARM7 - Say Y here if you wish to include support for the ARM710 processor. - -Support StrongARM(R) SA-110 processor -CONFIG_CPU_SA110 - Say Y here if you wish to include support for the Intel(R) - StrongARM(R) SA-110 processor. - -Support ARM720 processor -CONFIG_CPU_ARM720 - Say Y here if you wish to include support for the ARM720 processor. - -Support ARM920 -CONFIG_CPU_ARM920 - Say Y here if you wish to include support for the ARM920 processor. +Load kernel using Angel Debug Monitor +CONFIG_ANGELBOOT + Say Y if you plan to load the kernel using Angel, ARM Ltd's target + debug stub. If you are not using Angel, you must say N. It is + important to get this setting correct. Math emulation -CONFIG_NWFPE +CONFIG_FPE_NWFPE Say Y to include the NWFPE floating point emulator in the kernel. This is necessary to run most binaries. Linux does not currently support floating point hardware so you need to say Y here even if @@ -16702,6 +17276,23 @@ You may say N here if you are going to load the Acorn FPEmulator early in the bootup. +CONFIG_FPE_FASTFPE + Say Y here to include the FAST floating point emulator in the kernel. + This is an experimental much faster emulator which has only 32 bit + precision for the mantissa. It does not support any exceptions. This + makes it very simple, it is approximately 4-8 times faster than NWFPE. + + It should be sufficient for most programs. It is definitely not + suitable if you do scientific calculations that need double precision + for iteration formulas that sum up lots of very small numbers. If you + do not feel you need a faster FP emulation you should better choose + NWFPE. + + It is also possible to say M to build the emulator as a module + (fastfpe.o). But keep in mind that you should only load the FP emulator + early in the bootup. You should never change from NWFPE to FASTFPE or + vice versa in an active system! + DS1620 Thermometer support CONFIG_DS1620 Say Y here to include support for the thermal management hardware @@ -16721,11 +17312,12 @@ you are concerned with the code size or don't want to see these messages. -Compile kernel with frame pointer -CONFIG_FRAME_POINTER - If you say Y here, the resulting kernel will be slightly larger and - slower, but it will give useful debugging information. If you don't - debug the kernel, you can say N. +Compile kernel without frame pointer +CONFIG_NO_FRAME_POINTER + If you say Y here, the resulting kernel will be slightly smaller and + faster. However, when a problem occurs with the kernel, the + information that is reported is severely limited. Most people + should say N here. User fault debugging CONFIG_DEBUG_USER @@ -16833,6 +17425,21 @@ you can make the first serial port the console by answering Y to this option. +L7200 SDB keyboard support +CONFIG_KEYBOARD_L7200 + Enable this option if you would like to be able to use a keyboard + on a LinkUp Systems L7200 board. + +L7200 SDB Fujitsu keyboard support +CONFIG_KEYBOARD_L7200_NORM + Select the Fujitsu keyboard if you want a normal QWERTY style + keyboard on the LinkUp SDB. + +L7200 SDB Prototype keyboard support +CONFIG_KEYBOARD_L7200_DEMO + Select the prototype keyboard if you want to play with the + LCD/keyboard combination on the LinkUp SDB. + Footbridge Mode CONFIG_HOST_FOOTBRIDGE The 21285 Footbridge chip can operate in either `host mode' or @@ -16903,8 +17510,7 @@ infrared communication and is supported by most laptops and PDA's. To use Linux support for the IrDA (tm) protocols, you will also need - some user-space utilities like the irmanager and probably irattach - as well. For more information, see the file + some user-space utilities like irattach. For more information, see the file Documentation/networking/irda.txt. You also want to read the IR-HOWTO, available at http://www.linuxdoc.org/docs.html#howto . @@ -16912,6 +17518,10 @@ want to compile it as a module, say M here and read Documentation/modules.txt. +IrDA protocol options +CONFIG_IRDA_OPTIONS + Say Y here if you want to configure any of the following IrDA options. + IrDA Cache last LSAP CONFIG_IRDA_CACHE_LAST_LSAP Say Y here if you want IrLMP to cache the last LSAP used. This makes @@ -16976,6 +17586,17 @@ to another Linux machine running the IrLAN protocol for ad-hoc networking! +IrNET Protocol +CONFIG_IRNET + Say Y here if you want to build support for the IrNET protocol. If + you want to compile it as a module (irnet.o), say M here and read + Documentation/modules.txt. IrNET is a PPP driver, so you will also + need a working PPP subsystem (driver, daemon and config)... + + IrNET is an alternate way to tranfer TCP/IP traffic over IrDA. It + uses synchronous PPP over a set of point to point IrDA sockets. You + can use it between Linux machine or with W2k. + IrCOMM Protocol CONFIG_IRCOMM Say Y here if you want to build support for the IrCOMM protocol. If @@ -17014,6 +17635,19 @@ If unsure, say Y. +USB IrDA FIR Dongle Device Driver +CONFIG_USB_IRDA + Say Y here if you want to build support for the USB IrDA FIR Dongle + device driver. If you want to compile it as a module (irda-usb.o), + say M here and read Documentation/modules.txt. IrDA-USB support the + various IrDA USB dongles available and most of their pecularities. + Those dongles plug in the USB port of your computer, are plug and + play, and support SIR and FIR (4Mbps) speeds. On the other hand, + those dongles tend to be less efficient than a FIR chipset. + + Please note that the driver is still experimental. And of course, + you will need both USB and IrDA support in your kernel... + Winbond W83977AF IrDA Device Driver CONFIG_WINBOND_FIR Say Y here if you want to build IrDA support for the Winbond @@ -17324,7 +17958,39 @@ and the PAL firmware version in use. To use this option, you have to check that the "/proc file system - support" (CONFIG_PROC_FS) is enabled, too. + support" (CONFIG_PROC_FS) is enabled, too + +Kernel debugging +CONFIG_DEBUG_KERNEL + Say Y here if you are developing drivers or trying to debug and identify + kernel problems. + +Debug memory allocations +CONFIG_DEBUG_SLAB + Say Y here to have the kernel do limited verification on memory + allocation as well as poisoning memory on free to catch use of freed + memory. + +Memory mapped I/O debug support +CONFIG_DEBUG_IOVIRT + Say Y here to get warned whenever an attempt is made to do I/O on + obviously invalid addresses such as those generated when ioremap() + calls are forgotten. Memory mapped I/O will go through an extra check to + catch access to unmapped ISA addresses, an access method that can still + be used by old drivers that are being ported from 2.0/2.2. + +Spinlock debugging +CONFIG_DEBUG_SPINLOCK + Say Y here and build SMP to catch missing spinlock initialisation and + certain other kinds of spinlock errors commonly made. This is best used + in conjunction with the NMI watchdog so that spinlock deadlocks are also + debuggable + +Verbose BUG() reporting (adds 70K) +CONFIG_DEBUG_BUGVERBOSE + Say Y here to make BUG() panics output the file name and line number of + the BUG call as well as the EIP and oops trace. This aids debugging but + costs about 70-100K of memory. # # A couple of things I keep forgetting: @@ -17350,7 +18016,7 @@ # LocalWords: howto multicasting MULTICAST MBONE firewalling ipfw ACCT resp ip # LocalWords: proc acct IPIP encapsulator decapsulator klogd PCTCP RARP EXT PS # LocalWords: telnetting subnetted NAGLE rlogin NOSR ttyS TGA techinfo mbone nl -# LocalWords: Mb SKB IPX Novell dosemu Appletalk DDP ATALK vmalloc visar ehome +# LocalWords: Mb SKB IPX Novell dosemu DDP ATALK vmalloc visar ehome # LocalWords: SD CHR scsi thingy SG CD LUNs LUN jukebox Adaptec BusLogic EATA # LocalWords: buslogic DMA DPT ATT eata dma PIO UltraStor fdomain umsdos ext # LocalWords: QLOGIC qlogic TMC seagate Trantor ultrastor FASST wd NETDEVICES @@ -17378,7 +18044,7 @@ # LocalWords: Brumby pci TNC cis ohio faq usenet NETLINK dev hydra ca Tyne mem # LocalWords: carleton DECstation SUNFD JENSEN Noname XXXM SLiRP LILO's amifb # LocalWords: pppd Zilog ZS SRM bootloader ez mainmenu rarp ipfwadm paride pcd -# LocalWords: RTNETLINK mknod xos MTU lwared Macs mac netatalk macs cs Wolff +# LocalWords: RTNETLINK mknod xos MTU lwared Macs netatalk macs cs Wolff # LocalWords: dartmouth flowerpt MultiMaster FlashPoint tudelft etherexpress # LocalWords: ICL EtherTeam ETH IDESCSI TXC SmartRAID SmartCache httpd sjc dlp # LocalWords: thesphere TwoServers BOOTP DHCP ncpfs BPQETHER BPQ MG HIPPI cern @@ -17395,7 +18061,7 @@ # LocalWords: Keepalive linefill RELCOM keepalive analogue CDR conf CDI INIT # LocalWords: OPTi isp irq noisp VFAT vfat NTFS losetup dmsdosfs dosfs ISDN MP # LocalWords: NOWAYOUT behaviour dialin isdn callback BTX Teles XXXX LVM lvm -ICN EDSS Cisco +# LocalWords: ICN EDSS Cisco # LocalWords: ipppd syncppp RFC MPP VJ downloaded icn NICCY Creatix shmem ufr # LocalWords: ibp md ARCnet ether encap NDIS arcether ODI Amigas AmiTCP NetBSD # LocalWords: initrd tue util DES funet des OnNet BIOSP smc Travan Iomega CMS @@ -17522,7 +18188,7 @@ # LocalWords: AudioPCI lspci SonicVibes sonicvibes SPARCs roadrunner CLgen UPA # LocalWords: swansea shtml Zoltrix zoltrix BINUTILS EGCS binutils VIDC DACs # LocalWords: CyberVision Cirrus PowerBooks Topcat SBUS CGsix TurboGX BWtwo SS -# LocalWords: CGthree TCX unswapable vfb fbcon hicolor truecolor AFB ILBM SOC +# LocalWords: CGthree TCX unswappable vfb fbcon hicolor truecolor AFB ILBM SOC # LocalWords: IPLAN gracilis Fibre SBus SparcSTORAGE SV jnewbigin swin QNX qnx # LocalWords: PTY PTYS ptyxx ttyxx PTYs ssh sb Avance ALS pss pvv kerneli hd # LocalWords: synth WaveFront MSND NONPNP AudioExcelDSP STRAM APUS CHRP MBX Nx diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/DocBook/Makefile linux.ac/Documentation/DocBook/Makefile --- linux.vanilla/Documentation/DocBook/Makefile Sat Feb 3 20:43:55 2001 +++ linux.ac/Documentation/DocBook/Makefile Tue Apr 10 18:03:31 2001 @@ -1,6 +1,7 @@ BOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \ kernel-api.sgml parportbook.sgml kernel-hacking.sgml \ - kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml + kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \ + deviceiobook.sgml PS := $(patsubst %.sgml, %.ps, $(BOOKS)) PDF := $(patsubst %.sgml, %.pdf, $(BOOKS)) @@ -9,12 +10,12 @@ EPS-parportbook := $(patsubst %.fig, %.eps, $(IMG-parportbook)) JPG-parportbook := $(patsubst %.fig, %.jpeg, $(IMG-parportbook)) +books: $(BOOKS) + $(BOOKS): $(TOPDIR)/scripts/docproc .PHONY: books ps pdf html clean mrproper -books: $(BOOKS) - ps: $(PS) pdf: $(PDF) @@ -55,6 +56,9 @@ $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/sis900.c \ sis900.sgml +deviceiobook.sgml: deviceiobook.tmpl + $(TOPDIR)/scripts/docgen deviceiobook.sgml + mcabook.sgml: mcabook.tmpl $(TOPDIR)/arch/i386/kernel/mca.c $(TOPDIR)/scripts/docgen $(TOPDIR)/arch/i386/kernel/mca.c \ mcabook.sgml @@ -64,6 +68,7 @@ videobook.sgml APISOURCES := $(TOPDIR)/drivers/media/video/videodev.c \ + $(TOPDIR)/arch/i386/kernel/irq.c \ $(TOPDIR)/arch/i386/kernel/mca.c \ $(TOPDIR)/arch/i386/kernel/mtrr.c \ $(TOPDIR)/drivers/char/misc.c \ @@ -77,11 +82,24 @@ $(TOPDIR)/drivers/net/wan/syncppp.c \ $(TOPDIR)/drivers/net/wan/z85230.c \ $(TOPDIR)/drivers/usb/usb.c \ - $(TOPDIR)/fs/locks.c \ + $(TOPDIR)/drivers/video/fbmem.c \ + $(TOPDIR)/drivers/video/fbcmap.c \ + $(TOPDIR)/drivers/video/fbcon.c \ + $(TOPDIR)/drivers/video/fbgen.c \ + $(TOPDIR)/drivers/video/fonts.c \ + $(TOPDIR)/drivers/video/macmodes.c \ + $(TOPDIR)/drivers/video/modedb.c \ $(TOPDIR)/fs/devfs/base.c \ + $(TOPDIR)/fs/locks.c \ + $(TOPDIR)/include/asm-i386/bitops.h \ $(TOPDIR)/kernel/pm.c \ $(TOPDIR)/kernel/ksyms.c \ $(TOPDIR)/kernel/kmod.c \ + $(TOPDIR)/kernel/printk.c \ + $(TOPDIR)/kernel/sched.c \ + $(TOPDIR)/kernel/sysctl.c \ + $(TOPDIR)/lib/string.c \ + $(TOPDIR)/lib/vsprintf.c \ $(TOPDIR)/net/netsyms.c kernel-api.sgml: kernel-api.tmpl $(APISOURCES) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/DocBook/deviceiobook.tmpl linux.ac/Documentation/DocBook/deviceiobook.tmpl --- linux.vanilla/Documentation/DocBook/deviceiobook.tmpl Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/DocBook/deviceiobook.tmpl Tue Apr 10 18:03:42 2001 @@ -0,0 +1,232 @@ + + + + + Bus-Independent Device Accesses + + + + Matthew + Wilcox + +
+ matthew@wil.cx +
+
+
+
+ + + + Alan + Cox + +
+ alan@redhat.com +
+
+
+
+ + + 2001 + Matthew Wilcox + + + + + This documentation 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 + + + + For more details see the file COPYING in the source + distribution of Linux. + + +
+ + + + + Introduction + + Linux provides an API which abstracts performing IO across all busses + and devices, allowing device drivers to be written independently of + bus type. + + + + + Known Bugs And Assumptions + + None. + + + + + Memory Mapped IO + + Getting Access to the Device + + The most widely supported form of IO is memory mapped IO. + That is, a part of the CPU's address space is interpreted + not as accesses to memory, but as accesses to a device. Some + architectures define devices to be at a fixed address, but most + have some method of discovering devices. The PCI bus walk is a + good example of such a scheme. This document does not cover how + to receive such an address, but assumes you are starting with one. + Physical addresses are of type unsigned long. + + + + This address should not be used directly. Instead, to get an + address suitable for passing to the accessor functions described + below, you should call ioremap. + An address suitable for accessing the device will be returned to you. + + + + After you've finished using the device (say, in your module's + exit routine), call iounmap in order to return + the address space to the kernel. Most architectures allocate new + address space each time you call ioremap, and + they can run out unless you call iounmap. + + + + + Accessing the device + + The part of the interface most used by drivers is reading and + writing memory-mapped registers on the device. Linux provides + interfaces to read and write 8-bit, 16-bit, 32-bit and 64-bit + quantities. Due to a historical accident, these are named byte, + word, long and quad accesses. Both read and write accesses are + supported; there is no prefetch support at this time. + + + + The functions are named readb, + readw, readl, + readq, writeb, + writew, writel and + writeq. + + + + Some devices (such as framebuffers) would like to use larger + transfers than 8 bytes at a time. For these devices, the + memcpy_toio, memcpy_fromio + and memset_io functions are provided. + Do not use memset or memcpy on IO addresses; they + are not guaranteed to copy data in order. + + + + The read and write functions are defined to be ordered. That is the + compiler is not permitted to reorder the I/O sequence. When the + ordering can be compiler optimised, you can use + __readb and friends to indicate the relaxed ordering. Use + this with care. The rmb provides a read memory + barrier. The wmb provides a write memory barrier. + + + + While the basic functions are defined to be synchronous with respect + to each other and ordered with respect to each other the busses the + devices sit on may themselves have asynchronocity. In paticular many + authors are burned by the fact that PCI bus writes are posted + asynchronously. A driver author must issue a read from the same + device to ensure that writes have occurred in the specific cases the + author cares. This kind of property cannot be hidden from driver + writers in the API. + + + + + ISA legacy functions + + On older kernels (2.2 and earlier) the ISA bus could be read or + written with these functions and without ioremap being used. This is + no longer true in Linux 2.4. A set of equivalent functions exist for + easy legacy driver porting. The functions available are prefixed + with 'isa_' and are isa_readb, + isa_writeb, isa_readw, + isa_writew, isa_readl, + isa_writelisa_memcpy_fromio + and isa_memcpy_toio + + + These functions should not be used in new drivers, and will + eventually be going away. + + + + + + + Port Space Accesses + + Port Space Explained + + + Another form of IO commonly supported is Port Space. This is a + range of addresses separate to the normal memory address space. + Access to these addresses is generally not as fast as accesses + to the memory mapped addresses, and it also has a potentially + smaller address space. + + + + Unlike memory mapped IO, no preparation is required + to access port space. + + + + + Accessing Port Space + + Accesses to this space are provided through a set of functions + which allow 8-bit, 16-bit and 32-bit accesses; also + known as byte, word and long. These functions are + inb, inw, + inl, outb, + outw and outl. + + + + Some variants are provided for these functions. Some devices + require that accesses to their ports are slowed down. This + functionality is provided by appending a _p + to the end of the function. There are also equivalents to memcpy. + The ins and outs + functions copy bytes, words or longs to the given port. + + + + + + + Public Functions Provided +!Einclude/asm-i386/io.h + + +
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/DocBook/kernel-api.tmpl linux.ac/Documentation/DocBook/kernel-api.tmpl --- linux.vanilla/Documentation/DocBook/kernel-api.tmpl Tue Apr 3 17:31:51 2001 +++ linux.ac/Documentation/DocBook/kernel-api.tmpl Tue Apr 10 18:03:42 2001 @@ -36,7 +36,7 @@ - Driver Basic + Driver Basics Driver Entry and Exit points !Iinclude/linux/init.h @@ -44,6 +44,10 @@ Atomics !Iinclude/asm-i386/atomic.h + + Delaying, scheduling, and timer routines +!Ekernel/sched.c + @@ -53,6 +57,29 @@ + + Basic C Library Functions + + + When writing drivers, you cannot in general use routines which are + from the C Library. Some of the functions have been found generally + useful and they are listed below. The behaviour of these functions + may vary slightly from those defined by ANSI, and these deviations + are noted in the text. + + + String Conversions +!Ilib/vsprintf.c +!Elib/vsprintf.c + + String Manipulation +!Ilib/string.c + + Bit Operations +!Iinclude/asm-i386/bitops.h + + + Memory Management in Linux The Slab Cache @@ -60,6 +87,14 @@ + + The proc filesystem + + sysctl interface +!Ekernel/sysctl.c + + + The Linux VFS The Directory Cache @@ -177,5 +212,68 @@ !Edrivers/net/wan/z85230.c + + Frame Buffer Library + + + The frame buffer drivers depend heavily on four data structures. + These structures are declared in include/linux/fb.h. They are + fb_info, fb_var_screeninfo, fb_fix_screeninfo and fb_monospecs. + The last three can be made available to and from userland. + + + + fb_info defines the current state of a particular video card. + Inside fb_info, there exists a fb_ops structure which is a + collection of needed functions to make fbdev and fbcon work. + fb_info is only visible to the kernel. + + + + fb_var_screeninfo is used to describe the features of a video card + that are user defined. With fb_var_screeninfo, things such as + depth and the resolution may be defined. + + + + The next structure is fb_fix_screeninfo. This defines the + properties of a card that are created when a mode is set and can't + be changed otherwise. A good example of this is the start of the + frame buffer memory. This "locks" the address of the frame buffer + memory, so that it cannot be changed or moved. + + + + The last structure is fb_monospecs. In the old API, there was + little importance for fb_monospecs. This allowed for forbidden things + such as setting a mode of 800x600 on a fix frequency monitor. With + the new API, fb_monospecs prevents such things, and if used + correctly, can prevent a monitor from being cooked. fb_monospecs + will not be useful until kernels 2.5.x. + + + Frame Buffer Memory +!Edrivers/video/fbmem.c + + Frame Buffer Console +!Edrivers/video/fbcon.c + + Frame Buffer Colormap +!Edrivers/video/fbcmap.c + + Frame Buffer Generic Functions +!Idrivers/video/fbgen.c + + Frame Buffer Video Mode Database +!Idrivers/video/modedb.c +!Edrivers/video/modedb.c + + Frame Buffer Macintosh Video Mode Database +!Idrivers/video/macmodes.c + + Frame Buffer Fonts +!Idrivers/video/fonts.c + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/DocBook/kernel-hacking.tmpl linux.ac/Documentation/DocBook/kernel-hacking.tmpl --- linux.vanilla/Documentation/DocBook/kernel-hacking.tmpl Fri Feb 9 00:32:44 2001 +++ linux.ac/Documentation/DocBook/kernel-hacking.tmpl Tue Apr 10 18:03:42 2001 @@ -11,7 +11,7 @@ Russell
- rusty@linuxcare.com + rusty@rustcorp.com.au
@@ -336,6 +336,11 @@ + If all your routine does is read or write some parameter, consider + implementing a sysctl interface instead. + + + Inside the ioctl you're in user context to a process. When a error occurs you return a negated errno (see include/linux/errno.h), @@ -407,7 +412,7 @@ Note that some functions may sleep implicitly: common ones are the user space access functions (*_user) and memory allocation - functions without GFP_ATOMIC. + functions without GFP_ATOMIC. @@ -608,7 +613,8 @@ for some weird device, you have a problem: it is poorly supported in Linux because after some time memory fragmentation in a running kernel makes it hard. The best way is to allocate the block early - in the boot process. + in the boot process via the alloc_bootmem() + routine. @@ -631,6 +637,20 @@ + + <function>udelay()</function>/<function>mdelay()</function> + <filename class=headerfile>include/asm/delay.h</filename> + <filename class=headerfile>include/linux/delay.h</filename> + + + + The udelay() function can be used for small pauses. + Do not use large values with udelay() as you risk + overflow - the helper function mdelay() is useful + here, or even consider schedule_timeout(). + + + <function>local_irq_save()</function>/<function>local_irq_restore()</function> <filename class=headerfile>include/asm/system.h</filename> @@ -687,8 +707,14 @@ modules this directive is currently ignored). <type>__exit</type> is used to declare a function which is only required on exit: the function will be dropped if this file is not compiled as a module. - See the header file for use. + See the header file for use. Note that it makes no sense for a function + marked with <type>__init</type> to be exported to modules with + <function>EXPORT_SYMBOL()</function> - this will break. </para> + <para> + Static data structures marked as <type>__initdata</type> must be initialised + (as opposed to ordinary static data which is zeroed BSS). + </para> </sect1> @@ -775,6 +801,21 @@ return 0; } </programlisting> + + <para> + You can often avoid having to deal with these problems by using the + <structfield>owner</structfield> field of the + <structname>file_operations</structname> structure. Set this field + as the macro <symbol>THIS_MODULE</symbol>. + </para> + + <para> + For more complicated module unload locking requirements, you can set the + <structfield>can_unload</structfield> function pointer to your own routine, + which should return <returnvalue>0</returnvalue> if the module is + unloadable, or <returnvalue>-EBUSY</returnvalue> otherwise. + </para> + </sect1> </chapter> @@ -822,6 +863,17 @@ <returnvalue>-ERESTARTSYS</returnvalue> if a signal is received. The <function>wait_event()</function> version ignores signals. </para> + <para> + Do not use the <function>sleep_on()</function> function family - + it is very easy to accidentally introduce races; almost certainly + one of the <function>wait_event()</function> family will do, or a + loop around <function>schedule_timeout()</function>. If you choose + to loop around <function>schedule_timeout()</function> remember + you must set the task state (with + <function>set_current_state()</function>) on each iteration to avoid + busy-looping. + </para> + </sect1> <sect1 id="queue-waking"> @@ -1212,6 +1264,13 @@ <filename>MAINTAINERS</filename> means you want to be consulted when changes are made to a subsystem, and hear about bugs; it implies a more-than-passing commitment to some part of the code. + </para> + </listitem> + + <listitem> + <para> + Finally, don't forget to read <filename>Documentation/SubmittingPatches</filename> + and possibly <filename>Documentation/SubmittingDrivers</filename>. </para> </listitem> </itemizedlist> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/DocBook/kernel-locking.tmpl linux.ac/Documentation/DocBook/kernel-locking.tmpl --- linux.vanilla/Documentation/DocBook/kernel-locking.tmpl Fri Feb 16 23:53:08 2001 +++ linux.ac/Documentation/DocBook/kernel-locking.tmpl Tue Apr 10 18:03:42 2001 @@ -11,7 +11,7 @@ <surname>Russell</surname> <affiliation> <address> - <email>rusty@linuxcare.com</email> + <email>rusty@rustcorp.com.au</email> </address> </affiliation> </author> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/DocBook/parportbook.tmpl linux.ac/Documentation/DocBook/parportbook.tmpl --- linux.vanilla/Documentation/DocBook/parportbook.tmpl Thu Jul 13 00:24:33 2000 +++ linux.ac/Documentation/DocBook/parportbook.tmpl Sat Apr 14 01:14:13 2001 @@ -2079,7 +2079,7 @@ | PARPORT_STATUS_BUSY); unsigned char val = (PARPORT_STATUS_ERROR | PARPORT_STATUS_BUSY); - struct parport_frob_struct frob; + struct ppdev_frob_struct frob; struct timespec ts; /* Wait for printer to be ready */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/README.DAC960 linux.ac/Documentation/README.DAC960 --- linux.vanilla/Documentation/README.DAC960 Fri Dec 8 01:05:41 2000 +++ linux.ac/Documentation/README.DAC960 Tue Apr 3 17:54:28 2001 @@ -1,17 +1,17 @@ Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers - Version 2.2.9 for Linux 2.2.17 - Version 2.4.9 for Linux 2.4.0 + Version 2.2.10 for Linux 2.2.18 + Version 2.4.10 for Linux 2.4.1 PRODUCTION RELEASE - 7 September 2000 + 1 February 2001 Leonard N. Zubkoff Dandelion Digital lnz@dandelion.com - Copyright 1998-2000 by Leonard N. Zubkoff <lnz@dandelion.com> + Copyright 1998-2001 by Leonard N. Zubkoff <lnz@dandelion.com> INTRODUCTION @@ -197,19 +197,19 @@ properly initializes the AcceleRAID 250, AcceleRAID 200, AcceleRAID 150, DAC960PJ, and DAC960PG because the Intel i960RD/RP is a multi-function device. If in doubt, contact Mylex RAID Technical Support (support@mylex.com) to verify -compatibility. Mylex makes available a hard disk compatibility list by FTP at -ftp://ftp.mylex.com/pub/dac960/diskcomp.html. +compatibility. Mylex makes available a hard disk compatibility list at +http://www.mylex.com/support/hdcomp/hd-lists.html. DRIVER INSTALLATION -This distribution was prepared for Linux kernel version 2.2.17 or 2.4.0. +This distribution was prepared for Linux kernel version 2.2.18 or 2.4.1. 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.9.tar.gz (or DAC960-2.4.9.tar.gz) + tar -xvzf DAC960-2.2.10.tar.gz (or DAC960-2.4.10.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 linux.vanilla/Documentation/README.nsp_cs.eng linux.ac/Documentation/README.nsp_cs.eng --- linux.vanilla/Documentation/README.nsp_cs.eng Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/README.nsp_cs.eng Tue Apr 3 17:54:28 2001 @@ -0,0 +1,127 @@ + + WorkBiT NinjaSCSI-3/32Bi driver for Linux + +1. Comment + This is Workbit corp.'s(http://www.workbit.co.jp/) NinjaSCSI-3 +(http://www.workbit.co.jp/ts/z_nj3r.html) and NinjaSCSI-32Bi +(http://www.workbit.co.jp/ts/z_njsc32bi.html) PCMCIA card driver module +for Linux. + +2. My Linux environment +Linux kernel: 2.4.0 / 2.2.18 +pcmcia-cs: 3.1.24 +gcc: gcc-2.95.2 +PC card: I-O data PCSC-F (NinjaSCSI-3) + I-O data CBSC-II in 16 bit mode (NinjaSCSI-32Bi) +SCSI device: I-O data CDPS-PX24 (CD-ROM drive) + Media Intelligent MMO-640GT (Optical disk drive) + +3. Install +[1] Check your PC card is true "NinjaSCSI-3" card. + If you installed pcmcia-cs already, pcmcia reports your card as UNKNOWN + card, and write ["WBT", "NinjaSCSI-3", "R1.0"] or some other string to + your console or log file. + You can also use "cardctl" program (this program is in pcmcia-cs source + code) to get more info. + +# cat /var/log/messgaes +... +Jan 2 03:45:06 lindberg cardmgr[78]: unsupported card in socket 1 +Jan 2 03:45:06 lindberg cardmgr[78]: product info: "WBT", "NinjaSCSI-3", "R1.0" +... +# cardctl ident +Socket 0: + no product info available +Socket 1: + product info: "IO DATA", "CBSC16 ", "1" + + +[2] Get Linux kernel source, and extract it to /usr/src. + Because NinjaSCSI driver requiers some SCSI header files in Linux kernel + source. + I recomend rebuilding your kernel. This eliminate some versioning problem. +$ cd /usr/src +$ tar -zxvf linux-x.x.x.tar.gz +$ cd linux +$ make config +... + +[3] If you use this driver with Kernel 2.2, Unpack pcmcia-cs in some directory + and make & install. This driver requies pcmcia-cs header file. +$ cd /usr/src +$ tar zxvf cs-pcmcia-cs-3.x.x.tar.gz +... + +[4] Extract this driver's archive somewhere, and edit Makefile, then do make. +$ tar -zxvf nsp_cs-x.x.tar.gz +$ cd nsp_cs-x.x +$ make + +[5] Copy nsp_cs.o to suitable plase, like /lib/modules/<Kernel version>/pcmcia/ . + +[6] Add these lines to /etc/pcmcia/config . + If you yse pcmcia-cs-3.1.8 or later, we can use "nsp_cs.conf" file. + So, you don't need to edit file. Just copy to /etc/pcmcia/ . + +------------------------------------- +device "nsp_cs" + class "scsi" module "nsp_cs" + +card "WorkBit NinjaSCSI-3" + version "WBT", "NinjaSCSI-3", "R1.0" + bind "nsp_cs" + +card "WorkBit NinjaSCSI-32Bi (16bit)" + version "WORKBIT", "UltraNinja-16", "1" + bind "nsp_cs" + +# OEM +card "WorkBit NinjaSCSI-32Bi (16bit) / IO-DATA" + version "IO DATA", "CBSC16 ", "1" + bind "nsp_cs" + +# OEM +card "WorkBit NinjaSCSI-32Bi (16bit) / KME-1" + version "KME ", "SCSI-CARD-001", "1" + bind "nsp_cs" +card "WorkBit NinjaSCSI-32Bi (16bit) / KME-2" + version "KME ", "SCSI-CARD-002", "1" + bind "nsp_cs" +card "WorkBit NinjaSCSI-32Bi (16bit) / KME-3" + version "KME ", "SCSI-CARD-003", "1" + bind "nsp_cs" +card "WorkBit NinjaSCSI-32Bi (16bit) / KME-4" + version "KME ", "SCSI-CARD-004", "1" + bind "nsp_cs" +------------------------------------- + +[7] Boot (or reboot) pcmcia-cs. +# /etc/rc.d/rc.pcmcia start (BSD style) +or +# /etc/init.d/pcmcia start (SYSV style) + + +4. History +See README.nin_cs . + +5. Caution + If you eject card when doing some operation for your SCSI device or suspend +your computer, you encount some *BAD* error like disk crash. + It works good when I using this driver right way. But I'm not guarantee +your data. Please backup your data when you use this driver. + +6. Known Bugs + Some write error occurs when you use slow device. + +7. Testing + Please send me some reports(bug reports etc..) of this software. +When you send report, please tell me these or more. + card name + kernel version + your SCSI device name(hard drive, CD-ROM, etc...) + +8. Copyright + See GPL. + + +2001/02/01 yokota@netlab.is.tsukuba.ac.jp <YOKOTA Hiroshi> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/SubmittingDrivers linux.ac/Documentation/SubmittingDrivers --- linux.vanilla/Documentation/SubmittingDrivers Fri Feb 9 00:32:44 2001 +++ linux.ac/Documentation/SubmittingDrivers Tue Apr 10 18:03:49 2001 @@ -111,7 +111,7 @@ Kernel traffic: Weekly summary of kernel list activity (much easier to read) - [http://kt.linuxcare.com/kernel-traffic] + [http://kt.zork.net/kernel-traffic] Linux USB project: http://sourceforge.net/projects/linux-usb/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/arm/README linux.ac/Documentation/arm/README --- linux.vanilla/Documentation/arm/README Tue Nov 28 01:07:59 2000 +++ linux.ac/Documentation/arm/README Thu Apr 12 11:47:46 2001 @@ -1,5 +1,5 @@ - ARM Linux 2.4.0test1 - ==================== + ARM Linux 2.4 + ============= Please check ftp.arm.linux.org.uk:/pub/armlinux for latest updates. @@ -7,9 +7,8 @@ --------------------- 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 ELF, GCC 2.8.1 - and EGCS are good compilers. Note that GCC-2.7.2.2 ELF is rare, and - you probably don't have it. + generating ARM ELF code with GNU extensions. GCC 2.95.1 and EGCS 1.1.2 + are good compilers. 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 @@ -166,4 +165,4 @@ receive a reply within one day. --- -Russell King (12/06/2000) +Russell King (26/01/2001) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/cris/README linux.ac/Documentation/cris/README --- linux.vanilla/Documentation/cris/README Fri Feb 9 00:32:44 2001 +++ linux.ac/Documentation/cris/README Tue Apr 10 18:03:49 2001 @@ -1,20 +1,22 @@ Linux 2.4 on the CRIS architecture ================================== -$Id: README,v 1.5 2001/01/10 17:20:55 bjornw Exp $ +$Id: README,v 1.6 2001/02/21 15:27:25 bjornw Exp $ -This is a port of Linux 2.4 to Axis Communications ETRAX 100LX embedded network CPU. For -more information about CRIS and ETRAX please see further below. +This is a port of Linux 2.4 to Axis Communications ETRAX 100LX embedded +network CPU. For more information about CRIS and ETRAX please see further +below. -<... to come: instructions on how to grab the right gcc, compiling and booting ...> +<to come: instructions on how to grab the right gcc, compiling and booting> What is CRIS ? -------------- -CRIS is an acronym for 'Code Reduced Instruction Set'. It is the CPU architecture in Axis -Communication AB's range of embedded network CPU's, called ETRAX. The latest CPU is called -ETRAX 100LX, where LX stands for 'Linux' because the chip was designed to be a good host for -the Linux operating system. +CRIS is an acronym for 'Code Reduced Instruction Set'. It is the CPU +architecture in Axis Communication AB's range of embedded network CPU's, +called ETRAX. The latest CPU is called ETRAX 100LX, where LX stands for +'Linux' because the chip was designed to be a good host for the Linux +operating system. The ETRAX 100LX chip -------------------- @@ -23,8 +25,8 @@ http://www.axis.com/news/us/001101_etrax.htm -The ETRAX 100LX is a 100 MIPS processor with 8kB cache, MMU, and a very broad range of -built-in interfaces, all with modern scatter/gather DMA. +The ETRAX 100LX is a 100 MIPS processor with 8kB cache, MMU, and a very broad +range of built-in interfaces, all with modern scatter/gather DMA. Memory interfaces: @@ -44,40 +46,41 @@ * two parallel-ports * two generic 8-bit ports - (not all interfaces are available at the same time due to chip pin multiplexing) + (not all interfaces are available at the same time due to chip pin + multiplexing) -The previous version of the ETRAX, the ETRAX 100, sits in almost all of Axis shipping -thin-servers like the Axis 2100 web camera or the developer-board. It lacks an MMU so the -Linux we run on that is a version of uClinux (Linux 2.0 without MM-support) ported to the CRIS -architecture. The new Linux 2.4 port has full MM and needs a CPU with an MMU, so it will not -run on the ETRAX 100. - -A version of the Axis developer-board with ETRAX 100LX will be available as soon as the chip -is ramped up (please see http://developer.axis.com for further information on that). +The previous version of the ETRAX, the ETRAX 100, sits in almost all of +Axis shipping thin-servers like the Axis 2100 web camera or the ETRAX 100 +developer-board. It lacks an MMU so the Linux we run on that is a version +of uClinux (Linux 2.0 without MM-support) ported to the CRIS architecture. +The new Linux 2.4 port has full MM and needs a CPU with an MMU, so it will +not run on the ETRAX 100. +A version of the Axis developer-board with ETRAX 100LX (running Linux +2.4) is now available. For more information please see developer.axis.com. Bootlog ------- -Just as an example, this is the debug-output from a boot of Linux 2.4 on an Axis -developer-board with ETRAX 100LX. The displayed BogoMIPS value is 5 times too small :) +Just as an example, this is the debug-output from a boot of Linux 2.4 on +a board with ETRAX 100LX. The displayed BogoMIPS value is 5 times too small :) At the end you see some user-mode programs booting like telnet and ftp daemons. -Linux version 2.4.0-test11 (bjornw@godzilla.axis.se) (gcc version 2.96 20000427 (experimental)) #358 Wed Nov 22 19:29:15 CET 2000 -ROM fs in RAM, size 368640 bytes +Linux version 2.4.1 (bjornw@godzilla.axis.se) (gcc version 2.96 20000427 (experimental)) #207 Wed Feb 21 15:48:15 CET 2001 +ROM fs in RAM, size 1376256 bytes Setting up paging and the MMU. -On node 0 totalpages: 1024 -zone(0): 1024 pages. +On node 0 totalpages: 2048 +zone(0): 2048 pages. zone(1): 0 pages. zone(2): 0 pages. -Linux/CRIS port (c) 2000 Axis Communications AB +Linux/CRIS port on ETRAX 100LX (c) 2001 Axis Communications AB Kernel command line: -Calibrating delay loop... 19.92 BogoMIPS -Memory: 6864k/8192k available (531k kernel code, 1328k reserved, 85k data, 24k init) +Calibrating delay loop... 19.91 BogoMIPS +Memory: 13872k/16384k available (587k kernel code, 2512k reserved, 44k data, 24k init) kmem_create: Forcing size word alignment - vm_area_struct kmem_create: Forcing size word alignment - filp -Dentry-cache hash table entries: 1024 (order: 0, 8192 bytes) +Dentry-cache hash table entries: 2048 (order: 1, 16384 bytes) Buffer-cache hash table entries: 2048 (order: 0, 8192 bytes) Page-cache hash table entries: 2048 (order: 0, 8192 bytes) kmem_create: Forcing size word alignment - kiobuf @@ -87,41 +90,52 @@ POSIX conformance testing by UNIFIX Linux NET4.0 for Linux 2.4 Based upon Swansea University Computer Society NET3.039 -kmem_create: Forcing size word alignment - skbuff_head_cache Starting kswapd v1.8 kmem_create: Forcing size word alignment - file lock cache kmem_create: Forcing size word alignment - blkdev_requests +block: queued sectors max/low 9109kB/3036kB, 64 slots per queue ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000 Axis Communications AB eth0 initialized eth0: changed MAC to 00:40:8C:CD:00:00 -ETRAX 100LX serial-driver $Revision: 1.5 $, (c) 2000 Axis Communications AB +ETRAX 100LX serial-driver $Revision: 1.6 $, (c) 2000 Axis Communications AB ttyS0 at 0xb0000060 is a builtin UART with DMA ttyS1 at 0xb0000068 is a builtin UART with DMA ttyS2 at 0xb0000070 is a builtin UART with DMA ttyS3 at 0xb0000078 is a builtin UART with DMA +Axis flash mapping: 200000 at 50000000 +Axis flash: Found 1 x16 CFI device at 0x0 in 16 bit mode + Amd/Fujitsu Extended Query Table v1.0 at 0x0040 +Axis flash: JEDEC Device ID is 0xC4. Assuming broken CFI table. +Axis flash: Swapping erase regions for broken CFI table. +number of CFI chips: 1 + Using default partition table +I2C driver v2.2, (c) 1999-2001 Axis Communications AB +ETRAX 100LX GPIO driver v2.1, (c) 2001 Axis Communications AB NET4: Linux TCP/IP 1.0 for NET4.0 IP Protocols: ICMP, UDP, TCP kmem_create: Forcing size word alignment - ip_dst_cache IP: routing cache hash table of 1024 buckets, 8Kbytes -TCP: Hash tables configured (established 1024 bind 1024) +TCP: Hash tables configured (established 2048 bind 2048) NET4: Unix domain sockets 1.0/SMP for Linux NET4.0. VFS: Mounted root (cramfs filesystem) readonly. Init starts up... +Mounted none on /proc ok. Setting up eth0 with ip 10.13.9.116 and mac 00:40:8c:18:04:60 eth0: changed MAC to 00:40:8C:18:04:60 Setting up lo with ip 127.0.0.1 Default gateway is 10.13.9.1 Hostname is bbox1 Telnetd starting, using port 23. - using /bin/sh as shell. -sftpd[14]: sftpd $Revision: 1.5 $ starting up + using /bin/sash as shell. +sftpd[15]: sftpd $Revision: 1.6 $ starting up + And here is how some /proc entries look: 17# cd /proc 17# cat cpuinfo -cpu : ETRAX +cpu : CRIS cpu revision : 10 cpu model : ETRAX 100LX cache size : 8 kB @@ -133,6 +147,7 @@ ata : yes usb : yes bogomips : 99.84 + 17# cat meminfo total: used: free: shared: buffers: cached: Mem: 7028736 925696 6103040 114688 0 229376 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/devices.txt linux.ac/Documentation/devices.txt --- linux.vanilla/Documentation/devices.txt Sat Dec 30 19:26:10 2000 +++ linux.ac/Documentation/devices.txt Tue Apr 3 17:54:28 2001 @@ -660,6 +660,12 @@ 29 char Universal frame buffer 0 = /dev/fb0 First frame buffer + 1 = /dev/fb1 Second frame buffer + ... + 31 = /dev/fb31 32nd frame buffer + + Backward compatibility aliases {2.6} + 32 = /dev/fb1 Second frame buffer ... 224 = /dev/fb7 Eighth frame buffer @@ -765,7 +771,7 @@ 36 char Netlink support 0 = /dev/route Routing, device updates, kernel to user 1 = /dev/skip enSKIP security cache control - 3 = /dec/fwmonitor Firewall packet copies + 3 = /dev/fwmonitor Firewall packet copies 16 = /dev/tap0 First Ethertap device ... 31 = /dev/tap15 16th Ethertap device @@ -2436,7 +2442,7 @@ 224 char A2232 serial card 0 = /dev/ttyY0 First A2232 port - 1 = /dev/cuy0 Second A2232 port + 1 = /dev/ttyY1 Second A2232 port ... 225 char A2232 serial card (alternate devices) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/dnotify.txt linux.ac/Documentation/dnotify.txt --- linux.vanilla/Documentation/dnotify.txt Tue Apr 3 17:31:51 2001 +++ linux.ac/Documentation/dnotify.txt Tue Apr 10 18:03:56 2001 @@ -1,7 +1,7 @@ Linux Directory Notification ============================ - Stephen Rothwell <sfr@linuxcare.com.au> + Stephen Rothwell <sfr@canb.auug.org.au> The intention of directory notification is to allow user applications to be notified when a directory, or any of the files in it, are changed. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/filesystems/devfs/ChangeLog linux.ac/Documentation/filesystems/devfs/ChangeLog --- linux.vanilla/Documentation/filesystems/devfs/ChangeLog Thu Jul 6 05:36:49 2000 +++ linux.ac/Documentation/filesystems/devfs/ChangeLog Tue Apr 10 18:03:56 2001 @@ -495,7 +495,7 @@ - Replaced dummy .epoch inode with .devfsd character device -- Modified rc.devfs to take acount of above change +- Modified rc.devfs to take account of above change - Removed spurious driver warning messages when CONFIG_DEVFS_FS=n diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/filesystems/proc.txt linux.ac/Documentation/filesystems/proc.txt --- linux.vanilla/Documentation/filesystems/proc.txt Tue Nov 28 01:47:38 2000 +++ linux.ac/Documentation/filesystems/proc.txt Tue Apr 10 18:04:02 2001 @@ -49,7 +49,7 @@ the SuSE Linux distribution. As there is no complete documentation for the /proc file system and we've used many freely available sources to write these chapters, it seems only fair to give the work back to the Linux community. -This work is based on the 2.2.* kernel version and the upcomming 2.4.*. I'm +This work is based on the 2.2.* kernel version and the upcoming 2.4.*. I'm afraid it's still far from complete, but we hope it will be useful. As far as we know, it is the first 'all-in-one' document about the /proc file system. It is focused on the Intel x86 hardware, so if you are looking for PPC, ARM, @@ -281,7 +281,7 @@ ERR is incremented in the case of errors in the IO-APIC bus (the bus that connects the CPUs in a SMP system. This means that an error has been detected, -the IO-APIC automatically retry the transmision, so it should not be a big +the IO-APIC automatically retry the transmission, so it should not be a big problem, but you should read the SMP-FAQ. In this context it could be interesting to note the new irq directory in 2.4. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/filesystems/ramfs.txt linux.ac/Documentation/filesystems/ramfs.txt --- linux.vanilla/Documentation/filesystems/ramfs.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/filesystems/ramfs.txt Tue Apr 3 17:54:28 2001 @@ -0,0 +1,47 @@ + ramfs - An automatically resizing memory based filesystem + + + Ramfs is a file system which keeps all files in RAM. It allows read + and write access. In contrast to RAM disks, which get allocated a + fixed amount of RAM, ramfs grows and shrinks to accommodate the + files it contains. + + You can mount the ramfs with: + mount -t ramfs none /mnt/wherever + + Then just create and use files. When the filesystem is unmounted, all + its contents are lost. + + NOTE! This filesystem is probably most useful not as a real + filesystem, but as an example of how virtual filesystems can be + written. + +Resource limits: + +By default a ramfs will be limited to using half of (physical) memory +for storing file contents, a bit over that when the metadata is +included. The resource usage limits of ramfs can be controlled with +the following mount options: + + maxsize=NNN + Sets the maximum allowed memory usage of the +filesystem to NNN kilobytes. This will be rounded down to a multiple +of the page size. The default is half of physical memory. NB. unlike +most of the other limits, setting this to zero does *not* mean no +limit, but will actually limit the size of the filesystem data to zero +pages. There might be a use for this in some perverse situation. + + maxfilesize=NNN + Sets the maximum size of a single file on the +filesystem to NNN kilobytes. This will be rounded down to a multiple +of the page size. If NNN=0 there is no limit. The default is no limit. + + maxdentries=NNN + Sets the maximum number of directory entries (hard +links) on the filesystem to NNN. If NNN=0 there is no limit. By +default this is set to maxsize/4. + + maxinodes=NNN + Sets the maximum number of inodes (i.e. distinct +files) on the filesystem to NNN. If NNN=0 there is no limit. The +default is no limit (but there can never be more inodes than dentries). diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/filesystems/vfat.txt linux.ac/Documentation/filesystems/vfat.txt --- linux.vanilla/Documentation/filesystems/vfat.txt Tue Dec 21 22:28:39 1999 +++ linux.ac/Documentation/filesystems/vfat.txt Thu Apr 12 11:47:46 2001 @@ -48,6 +48,9 @@ r: relaxed, case insensitive n: normal, default setting, currently case insensitive +nocase -- Returning with having the 8.3 format alias kept in + the disk. Default, return lowercase letter. + <bool>: 0,1,yes,no,true,false TODO diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/i386/boot.txt linux.ac/Documentation/i386/boot.txt --- linux.vanilla/Documentation/i386/boot.txt Fri Jul 28 00:52:08 2000 +++ linux.ac/Documentation/i386/boot.txt Thu Apr 12 11:47:52 2001 @@ -146,9 +146,16 @@ filled out, however: type_of_loader: - If your boot loader has an identifier assigned in - arch/i386/boot/setup.S, enter that value. Otherwise, enter - 0xFF here. + If your boot loader has an assigned id (see table below), enter + 0xTV here, where T is an identifier for the boot loader and V is + a version number. Otherwise, enter 0xFF here. + + Assigned boot loader ids: + 0 LILO + 1 Loadlin + 2 bootsect-loader + 3 SYSLINUX + 4 EtherBoot loadflags, heap_end_ptr: If the protocol version is 2.01 or higher, enter the diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/isapnp.txt linux.ac/Documentation/isapnp.txt --- linux.vanilla/Documentation/isapnp.txt Tue Oct 10 01:53:05 2000 +++ linux.ac/Documentation/isapnp.txt Tue Apr 3 17:54:28 2001 @@ -7,14 +7,14 @@ Read commands: -------------- -No comment.. +No comment. Write commands: --------------- -With the write interface you can simply activate or modify the configuration -for ISA Plug & Play devices. It is mainly useable for drivers which has not -use the ISA Plug & Play kernel support yet. +With the write interface you can activate or modify the configuration of +ISA Plug & Play devices. It is mainly useful for drivers which have not +been rewritten to use the ISA Plug & Play kernel support yet. card <idx> <vendor> - select PnP device by vendor identification csn <CSN> - select PnP device by CSN @@ -33,8 +33,8 @@ Explanation: - variable <idx> begins with zero - variable <CSN> begins with one - - <vendor> is in format 'PNP0000' - - <logdev> is in format 'PNP0000' + - <vendor> is in the standard format 'ABC1234' + - <logdev> is in the standard format 'ABC1234' Example: @@ -58,38 +58,38 @@ Information for developers ========================== -Finding appropriate device --------------------------- +Finding a device +---------------- extern struct pci_bus *isapnp_find_card(unsigned short vendor, unsigned short device, struct pci_bus *from); -This function finds a ISA PnP card. For the vendor device should -be used ISAPNP_VENDOR(a,b,c) where a,b,c are characters or integers. -For the device number should be used ISAPNP_DEVICE(x) macro where x is -integer value. Both vendor and device numbers can be taken from contents -of the /proc/isapnp file. +This function finds an ISA PnP card. For the vendor argument, the +ISAPNP_VENDOR(a,b,c) macro should be used, where a,b,c are characters or +integers. For the device argument the ISAPNP_DEVICE(x) macro should be +used, where x is an integer value. Both vendor and device arguments +can be taken from contents of the /proc/isapnp file. extern struct pci_dev *isapnp_find_dev(struct pci_bus *card, unsigned short vendor, unsigned short function, struct pci_dev *from); -This function finds the ISA PnP device. If card is NULL, then -the global search mode is used (all devices are used for the searching). -Otherwise only devices which belongs to the specified card are verified. -For the function number can be used ISAPNP_FUNCTION(x) macro which works -similarly as the ISAPNP_DEVICE(x) macro. +This function finds an ISA PnP device. If card is NULL, then the global +search mode is used (all devices are used for the searching). Otherwise +only devices which belong to the specified card are checked. For the +function number the ISAPNP_FUNCTION(x) macro can be used; it works +similarly to the ISAPNP_DEVICE(x) macro. extern int isapnp_probe_cards(const struct isapnp_card_id *ids, - int (*probe)(struct pci_bus *card, - const struct isapnp_card_id *id)); + int (*probe)(struct pci_bus *card, + const struct isapnp_card_id *id)); -This function is a helper for drivers which requires to use more than -one device from an ISA PnP card. For each cards is called the probe -callback with appropriate information. +This function is a helper for drivers which need to use more than +one device from an ISA PnP card. The probe callback is called with +appropriate arguments for each card. Example for ids parameter initialization: @@ -109,13 +109,13 @@ ISAPNP_CARD_TABLE(card_ids); extern int isapnp_probe_devs(const struct isapnp_device_id *ids, - int (*probe)(struct pci_bus *card, - const struct isapnp_device_id *id)); + int (*probe)(struct pci_bus *card, + const struct isapnp_device_id *id)); -This function is a helper for drivers which requires to use one -device from an ISA PnP card. For each matched devices is called the probe -callback with appropriate information. +This function is a helper for drivers which need to use one +device from an ISA PnP card. The probe callback is called with +appropriate arguments for each matched device. Example for ids parameter initialization: @@ -129,25 +129,25 @@ ISA PnP configuration ===================== -There are two ways how can be ISA PnP interface used. +There are two ways in which the ISA PnP interface can be used. -First way is lowlevel ---------------------- +First way: low-level +-------------------- -All ISA PNP configuration registers are accessible via lowlevel +All ISA PNP configuration registers are accessible via the low-level isapnp_(read|write)_(byte|word|dword) functions. The function isapnp_cfg_begin() must be called before any lowlevel function. The function isapnp_cfg_end() must be always called after configuration otherwise the access to the ISA PnP configuration functions will be blocked. -Second way is auto-configuration --------------------------------- +Second way: auto-configuration +------------------------------ -This feature gives to the driver the real power of the ISA PnP code. -Function dev->prepare() initializes the resource members in the device -structure. This structure contains all resources set to auto configuration -values after the initialization. The device driver may modify some resources +This feature gives to the driver the real power of the ISA PnP driver. +The function dev->prepare() initializes the resource members in the device +structure. This structure contains all resources set to auto configuration +values after the initialization. The device driver may modify some resources to skip the auto configuration for a given resource. Once the device structure contains all requested resource values, the function @@ -155,12 +155,12 @@ with the auto configuration value. Function dev->activate() does: - - resources with the auto configuration value are configured - - the auto configuration is created using ISA PnP resource map - - the function writes configuration to ISA PnP configuration registers - - the function returns to the caller actual used resources + - resources with the auto configuration value are configured + - the auto configuration is created using ISA PnP resource map + - the function writes configuration to ISA PnP configuration registers + - the function returns to the caller actual used resources -When the device driver is removing, function dev->deactivate() has to be +When the device driver is removed, function dev->deactivate() has to be called to free all assigned resources. Example (game port initialization) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/joystick-api.txt linux.ac/Documentation/joystick-api.txt --- linux.vanilla/Documentation/joystick-api.txt Fri Jul 28 20:50:51 2000 +++ linux.ac/Documentation/joystick-api.txt Tue Apr 10 18:04:02 2001 @@ -114,7 +114,7 @@ ~~~~~~~~~~~~~~~~~ The time an event was generated is stored in ``js_event.time''. It's a time -in miliseconds since ... well, since sometime in the past. This eases the +in milliseconds since ... well, since sometime in the past. This eases the task of detecting double clicks, figuring out if movement of axis and button presses happened at the same time, and similar. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/kernel-docs.txt linux.ac/Documentation/kernel-docs.txt --- linux.vanilla/Documentation/kernel-docs.txt Wed Aug 23 17:33:09 2000 +++ linux.ac/Documentation/kernel-docs.txt Tue Apr 10 18:04:08 2001 @@ -608,7 +608,7 @@ produced during the week. Published every Thursday. * Name: "Kernel Traffic" - URL: http://kt.linuxcare.com + URL: http://kt.zork.net Keywords: linux-kernel mailing list, weekly kernel news. Description: Weekly newsletter covering the most relevant discussions of the linux-kernel mailing list. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/kernel-parameters.txt linux.ac/Documentation/kernel-parameters.txt --- linux.vanilla/Documentation/kernel-parameters.txt Tue Apr 3 17:31:51 2001 +++ linux.ac/Documentation/kernel-parameters.txt Tue Apr 3 17:54:28 2001 @@ -22,6 +22,7 @@ HW Appropriate hardware is enabled. IA-32 IA-32 aka i386 architecture is enabled. IA-64 IA-64 architecture is enabled. + ISAPNP ISA PnP code is enabled. ISDN Appropriate ISDN support is enabled. JOY Appropriate joystick support is enabled. LP Printer support is enabled. @@ -246,6 +247,18 @@ ip= [PNP] + isapnp= [ISAPNP] Specify RDP, reset, pci_scan and verbosity. + + isapnp_reserve_irq= [ISAPNP] Exclude IRQs for the autoconfiguration. + + isapnp_reserve_dma= [ISAPNP] Exclude DMAs for the autoconfiguration. + + isapnp_reserve_io= [ISAPNP] Exclude I/O ports for the autoconfiguration. + Ranges are in pairs (I/O port base and size). + + isapnp_reserve_mem= [ISAPNP] Exclude memory regions for the autoconfiguration. + Ranges are in pairs (memory base and size). + isp16= [HW,CD] iucv= [HW,NET] @@ -361,6 +374,8 @@ nohlt [BUGS=ARM] no-hlt [BUGS=ix86] + + noisapnp [ISAPNP] Disables ISA PnP code. noinitrd [RAM] Tells the kernel not to load any configured initial RAM disk. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/memory.txt linux.ac/Documentation/memory.txt --- linux.vanilla/Documentation/memory.txt Tue Dec 22 16:31:07 1998 +++ linux.ac/Documentation/memory.txt Tue Apr 3 17:54:28 2001 @@ -37,7 +37,7 @@ * Not overclocking your CPU. * Having the memory tested in a memory tester or exchanged - with the vendor. + with the vendor. Consider testing it with memtest86 yourself. * Exchanging your CPU, cache, or motherboard for one that works. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/mtrr.txt linux.ac/Documentation/mtrr.txt --- linux.vanilla/Documentation/mtrr.txt Fri Jul 28 20:50:51 2000 +++ linux.ac/Documentation/mtrr.txt Thu Apr 12 11:48:05 2001 @@ -16,10 +16,13 @@ these, the ARRs are used to emulate the MTRRs. The AMD K6-2 (stepping 8 and above) and K6-3 processors have two - MTRRs. These are supported. + MTRRs. These are supported. The AMD Athlon family provide 8 Intel + style MTRRs. The Centaur C6 (WinChip) has 8 MCRs, allowing write-combining. These are supported. + + The VIA Cyrix III and VIA C3 CPUs offer 8 Intel style MTRRs. The CONFIG_MTRR option creates a /proc/mtrr file which may be used to manipulate your MTRRs. Typically the X server should use diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/networking/comx.txt linux.ac/Documentation/networking/comx.txt --- linux.vanilla/Documentation/networking/comx.txt Fri Jul 28 20:50:51 2000 +++ linux.ac/Documentation/networking/comx.txt Tue Apr 10 18:04:08 2001 @@ -162,7 +162,7 @@ some restricions in order to be able to use non-async lines too. If configured, this driver can use Van Jacobson TCP header compression (you'll need the slhc.o module for this). -Additionaly to use this protocol, enable async ppp in your kernel config, and +Additionally to use this protocol, enable async ppp in your kernel config, and create the comx device special files in /dev. They're character special files with major 88, and their names must be the same as their network interface counterparts (i.e /dev/comx0 with minor 0 corresponds interface comx0 and so diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/networking/wan-router.txt linux.ac/Documentation/networking/wan-router.txt --- linux.vanilla/Documentation/networking/wan-router.txt Fri Jul 28 20:50:52 2000 +++ linux.ac/Documentation/networking/wan-router.txt Sat Apr 14 01:14:20 2001 @@ -1,27 +1,12 @@ ------------------------------------------------------------------------------ -WAN Router for Linux Operating System +Linux WAN Router Utilities Package ------------------------------------------------------------------------------ -Version 2.1.1 - Nov 08, 1999 -Version 2.0.8 - Nov 02, 1999 -Version 2.0.7 - Aug 26, 1999 -Version 2.0.6 - Aug 17, 1999 -Version 2.0.5 - Aug 12, 1999 -Version 2.0.4 - Nov 26, 1998 -Version 2.0.3 - Aug 25, 1998 -Version 2.0.2 - Dec 09, 1997 -Version 2.0.1 - Nov 28, 1997 -Version 2.0.0 - Nov 06, 1997 -Version 1.0.3 - June 3, 1997 -Version 1.0.1 - January 30, 1997 +Version 2.2.1 +Mar 28, 2001 Author: Nenad Corbic <ncorbic@sangoma.com> -Copyright (c) 1995-1999 Sangoma Technologies Inc. +Copyright (c) 1995-2001 Sangoma Technologies Inc. ------------------------------------------------------------------------------ - -WARNING: This Version of WANPIPE supports only the S508 and S508/FT1 cards. -IF YOU OWN A S502E OR A S508 CARD THEN PLEASE CONTACT SANGOMA TECHNOLOGIES FOR -AN UPGRADE. ONLY THE BiSYNC STREAMING CODE IS SUPPORTED ON S502E/S503 cards. - INTRODUCTION Wide Area Networks (WANs) are used to interconnect Local Area Networks (LANs) @@ -41,7 +26,7 @@ Unix-like operating system anyway). With a number of relatively inexpensive WAN interface cards available on the market, a perfectly usable router can be built for less than half a price of an external router. Yet a Linux box -acting as a router can still be used for other purposes, such as firewalling, +acting as a router can still be used for other purposes, such as fire-walling, running FTP, WWW or DNS server, etc. This kernel module introduces the notion of a WAN Link Driver (WLD) to Linux @@ -87,15 +72,28 @@ To ba able to use the Linux WAN Router you will also need a WAN Tools package available from - ftp.sangoma.com/pub/linux/vX.Y.Z/wantools-X.Y.Z.tgz - or - ftp.sangoma.com/pub/linux/vX.Y.Z/wanpipe-X.Y.Z.tgz + ftp.sangoma.com/pub/linux/current_wanpipe/wanpipe-X.Y.Z.tgz + +where vX.Y.Z represent the wanpipe version number. + +For technical questions and/or comments please e-mail to ncorbic@sangoma.com. +For general inquiries please contact Sangoma Technologies Inc. by -where vX.Y.Z represent the Linux kernel version number. + Hotline: 1-800-388-2475 (USA and Canada, toll free) + Phone: (905) 474-1990 ext: 106 + Fax: (905) 474-9223 + E-mail: dm@sangoma.com (David Mandelstam) + WWW: http://www.sangoma.com -For technical questions and/or comments regarding this product please e-mail -to jaspreet@sangoma.com or dm@sangoma.com. +INSTALLATION + +Please read the WanpipeForLinux.pdf manual on how to +install the WANPIPE tools and drivers properly. + + +After installing wanpipe package: /usr/local/wanrouter/doc. +On the ftp.sangoma.com : /linux/current_wanpipe/doc COPYRIGHT AND LICENSING INFORMATION @@ -114,120 +112,511 @@ -ACKNOWLEDGMENTS +ACKNOWLEDGEMENTS This product is based on the WANPIPE(tm) Multiprotocol WAN Router developed -by Sangoma Technologies Inc. for Linux 1.2.x. Release of Linux 2.0 in summer -1996 commanded adequate changes to the WANPIPE code to take full advantage of -new Linux features. Instead of continuing developing proprietary interface -specific to Sangoma WAN cards, we decided to put all hardware-independent code -into a separate module and define two levels of interfaces - one for user- -level applications and another for kernel-level WAN drivers. +by Sangoma Technologies Inc. for Linux 2.0.x and 2.2.x. Success of the WANPIPE +together with the next major release of Linux kernel in summer 1996 commanded +adequate changes to the WANPIPE code to take full advantage of new Linux +features. + +Instead of continuing developing proprietary interface tied to Sangoma WAN +cards, we decided to separate all hardware-independent code into a separate +module and defined two levels of interfaces - one for user-level applications +and another for kernel-level WAN drivers. WANPIPE is now implemented as a +WAN driver compliant with the WAN Link Driver interface. Also a general +purpose WAN configuration utility and a set of shell scripts was developed to +support WAN router at the user level. Many useful ideas concerning hardware-independent interface implementation were given by Mike McLagan <mike.mclagan@linux.org> and his implementation of the Frame Relay router and drivers for Sangoma cards (dlci/sdla). +With the new implementation of the APIs being incorporated into the WANPIPE, +a special thank goes to Alan Cox in providing insight into BSD sockets. + Special thanks to all the WANPIPE users who performed field-testing, reported bugs and made valuable comments and suggestions that help us to improve this product. +NEW IN THIS RELEASE + + o Updated the WANCFG utility + Calls the pppconfig to configure the PPPD + for async connections. + + o Added the PPPCONFIG utility + Used to configure the PPPD dameon for the + WANPIPE Async PPP and standard serial port. + The wancfg calls the pppconfig to configure + the pppd. + + o Fixed the PCI autodetect feature. + The SLOT 0 was used as an autodetect option + however, some high end PC's slot numbers start + from 0. + + o This release has been tested with the new backupd + daemon release. + + +PRODUCT COMPONENTS AND RELATED FILES + +/etc: (or user defined) + wanpipe1.conf default router configuration file + +/lib/modules/X.Y.Z/misc: + wanrouter.o router kernel loadable module + af_wanpipe.o wanpipe api socket module + +/lib/modules/X.Y.Z/net: + sdladrv.o Sangoma SDLA support module + wanpipe.o Sangoma WANPIPE(tm) driver module + +/proc/net/wanrouter + Config reads current router configuration + Status reads current router status + {name} reads WAN driver statistics + +/usr/sbin: + wanrouter wanrouter start-up script + wanconfig wanrouter configuration utility + sdladump WANPIPE adapter memory dump utility + fpipemon Monitor for Frame Relay + cpipemon Monitor for Cisco HDLC + ppipemon Monitor for PPP + xpipemon Monitor for X25 + wpkbdmon WANPIPE keyboard led monitor/debugger + +/usr/local/wanrouter: + README this file + COPYING GNU General Public License + Setup installation script + Filelist distribution definition file + wanrouter.rc meta-configuration file + (used by the Setup and wanrouter script) + +/usr/local/wanrouter/doc: + wanpipeForLinux.pdf WAN Router User's Manual + +/usr/local/wanrouter/patches: + wanrouter-v2213.gz patch for Linux kernels 2.2.11 up to 2.2.13. + wanrouter-v2214.gz patch for Linux kernel 2.2.14. + wanrouter-v2215.gz patch for Linux kernels 2.2.15 to 2.2.17. + wanrouter-v2218.gz patch for Linux kernels 2.2.18 and up. + wanrouter-v240.gz patch for Linux kernel 2.4.0. + wanrouter-v242.gz patch for Linux kernel 2.4.2 and up. + wanrouter-v2034.gz patch for Linux kernel 2.0.34 + wanrouter-v2036.gz patch for Linux kernel 2.0.36 and up. + +/usr/local/wanrouter/patches/kdrivers: + Sources of the latest WANPIPE device drivers. + These are used to UPGRADE the linux kernel to the newest + version if the kernel source has already been pathced with + WANPIPE drivers. + +/usr/local/wanrouter/samples: + interface sample interface configuration file + wanpipe1.cpri CHDLC primary port + wanpipe2.csec CHDLC secondary port + wanpipe1.fr Frame Relay protocol + wanpipe1.ppp PPP protocol ) + wanpipe1.asy CHDLC ASYNC protocol + wanpipe1.x25 X25 protocol + wanpipe1.stty Sync TTY driver (Used by Kernel PPPD daemon) + wanpipe1.atty Async TTY driver (Used by Kernel PPPD daemon) + wanrouter.rc sample meta-configuration file + +/usr/local/wanrouter/util: + * wan-tools utilities source code + +/usr/local/wanrouter/api/x25: + * x25 api sample programs. +/usr/local/wanrouter/api/chdlc: + * chdlc api sample programs. +/usr/local/wanrouter/api/fr: + * fr api sample programs. +/usr/local/wanrouter/config/wancfg: + wancfg WANPIPE GUI configuration program. + Creates wanpipe#.conf files. +/usr/local/wanrouter/config/cfgft1: + cfgft1 GUI CSU/DSU configuration program. + +/usr/include/linux: + wanrouter.h router API definitions + wanpipe.h WANPIPE API definitions + sdladrv.h SDLA support module API definitions + sdlasfm.h SDLA firmware module definitions + if_wanpipe.h WANPIPE Socket definitions + if_wanpipe_common.h WANPIPE Socket/Driver common definitions. + sdlapci.h WANPIPE PCI definitions + + +/usr/src/linux/net/wanrouter: + * wanrouter source code + +/var/log: + wanrouter wanrouter start-up log (created by the Setup script) + +/var/lock: (or /var/lock/subsys for RedHat) + wanrouter wanrouter lock file (created by the Setup script) + +/usr/local/wanrouter/firmware: + fr514.sfm Frame relay firmware for Sangoma S508/S514 card + cdual514.sfm Dual Port Cisco HDLC firmware for Sangoma S508/S514 card + ppp514.sfm PPP Firmware for Sangoma S508 and S514 cards + x25_508.sfm X25 Firmware for Sangoma S508 card. + + REVISION HISTORY -2.1.1 Nov 09, 1999 - New code for S514PCI card - - Completely redesigned drivers - fully tested and optimized. - -2.0.8 Nov 02, 1999 - Fixed up the X25API code. - - Clear call bug fixed.i - - Enabled driver for multi-card - operation. - -2.0.7 Aug 26, 1999 - Merged X25API code into WANPIPE. - - Fixed a memory leak for X25API - - Updated the X25API code for 2.2.X kernels. - - Improved NEM handling. - -2.0.6 Aug 17, 1999 - Kernel patch works for both 2.2.10 and 2.2.11 kernels - - Fixed up 2.0.5 installation bugs - - No functional difference between 2.0.6 and 2.0.5 - -2.0.5 Aug 12, 1999 - NEW PPP, interrupt drive code - - NEW X25 Xpipmon debugger - - Comments added to setup scripts - - Numerous bug fixes - -2.0.4 Nov 26, 1998 - NEW Cisco Dual Port support. - - NEW support for BiSync Streaming API. - - NEW support for HDLC (LAPB) API. - - WANPIPE provides an API for application - development using the BSD socket interface. - -2.0.3 Aug 25, 1998 - NEW support for Cisco HDLC, with cpipemon - utility for monitoring - - CIR support for Frame-relay - - Support for PAP and CHAP for ppp has been - implemented - - Dynamic IP assignment for PPP - - Multiple channel IPX support for Frame-relay - and X25 - - Inverse Arp support for Frame-relay - - FT1 Configuration utility for linux - - Man Pages for router.conf, router, sdladump, - cfgft1, fpipemon, ppipemon and cpipemon - -2.0.2 Dev 09, 1997 - Implemented PAP and CHAP for ppp. - -2.0.1 Nov 28, 1997 - Protection of "enable_irq()" while - "disable_irq()" has been enabled from any other - routine (for Frame Relay, PPP and X25). - - Added additional Stats for Fpipemon and Ppipemon - - Improved Load Sharing for multiple boards. - -2.0.0 Nov 07, 1997 - Implemented protection of RACE conditions by - critical flags for FRAME RELAY and PPP. - - DLCI List interrupt mode implemented. - - IPX support in FRAME RELAY and PPP. - - IPX Server Support (MARS) - - More driver specific stats included in FPIPEMON - and PIPEMON. - -1.0.5 July 28, 1997 - Configurable T391,T392,N391,N392,N393 for Frame - Relay in router.conf. - - Configurable Memory Address through router.conf - for Frame Relay, PPP and X.25. (commenting this - out enables auto-detection). - - Fixed freeing up received buffers using kfree() - for Frame Relay and X.25. - - Protect sdla_peek() by calling save_flags(), - cli() and restore_flags(). - - Changed number of Trace elements from 32 to 20 - - Added DLCI specific data monitoring in FPIPEMON. - -1.0.4 July 10, 1997 - S508/FT1 monitoring capability in fpipemon and - ppipemon utilities. - - Configurable TTL for UDP packets. - - Multicast and Broadcast IP source addresses are - silently discarded. - -1.0.3 June 3, 1997 - - UDP port for multiple boards (Frame relay, PPP) - Continuous Transmission of Configure Request - - Packet for PPP (this support is only added for - 508 cards) - - Connection Timeout for PPP changed from 900 to 0 - - Flow Control for multiple boards and multiple - channels (Frame Relay) - -1.0.1 January 30, 1997 +1.0.0 December 31, 1996 Initial version + +1.0.1 January 30, 1997 Status and statistics can be read via /proc + filesystem entries. + +1.0.2 April 30, 1997 Added UDP management via monitors. + +1.0.3 June 3, 1997 UDP management for multiple boards using Frame + Relay and PPP + Enabled continuous transmission of Configure + Request Packet for PPP (for 508 only) + Connection Timeout for PPP changed from 900 to 0 + Flow Control Problem fixed for Frame Relay + +1.0.4 July 10, 1997 S508/FT1 monitoring capability in fpipemon and + ppipemon utilities. + Configurable TTL for UDP packets. + Multicast and Broadcast IP source addresses are + silently discarded. + +1.0.5 July 28, 1997 Configurable T391,T392,N391,N392,N393 for Frame + Relay in router.conf. + Configurable Memory Address through router.conf + for Frame Relay, PPP and X.25. (commenting this + out enables auto-detection). + Fixed freeing up received buffers using kfree() + for Frame Relay and X.25. + Protect sdla_peek() by calling save_flags(), + cli() and restore_flags(). + Changed number of Trace elements from 32 to 20 + Added DLCI specific data monitoring in FPIPEMON. +2.0.0 Nov 07, 1997 Implemented protection of RACE conditions by + critical flags for FRAME RELAY and PPP. + DLCI List interrupt mode implemented. + IPX support in FRAME RELAY and PPP. + IPX Server Support (MARS) + More driver specific stats included in FPIPEMON + and PIPEMON. + +2.0.1 Nov 28, 1997 Bug Fixes for version 2.0.0. + Protection of "enable_irq()" while + "disable_irq()" has been enabled from any other + routine (for Frame Relay, PPP and X25). + Added additional Stats for Fpipemon and Ppipemon + Improved Load Sharing for multiple boards + +2.0.2 Dec 09, 1997 Support for PAP and CHAP for ppp has been + implemented. + +2.0.3 Aug 15, 1998 New release supporting Cisco HDLC, CIR for Frame + relay, Dynamic IP assignment for PPP and Inverse + Arp support for Frame-relay. Man Pages are + included for better support and a new utility + for configuring FT1 cards. + +2.0.4 Dec 09, 1998 Dual Port support for Cisco HDLC. + Support for HDLC (LAPB) API. + Supports BiSync Streaming code for S502E + and S503 cards. + Support for Streaming HDLC API. + Provides a BSD socket interface for + creating applications using BiSync + streaming. + +2.0.5 Aug 04, 1999 CHDLC initializatin bug fix. + PPP interrupt driven driver: + Fix to the PPP line hangup problem. + New PPP firmware + Added comments to the startup SYSTEM ERROR messages + Xpipemon debugging application for the X25 protocol + New USER_MANUAL.txt + Fixed the odd boundary 4byte writes to the board. + BiSync Streaming code has been taken out. + Available as a patch. + 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 + 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 Updated the X25API code for 2.2.X kernels. + o Improved NEM handling. + +2.1.0 Oct 25, 1999 o New code for S514 PCI Card + o New CHDLC and Frame Relay drivers + o PPP and X25 are not supported in this release + +2.1.1 Nov 30, 1999 o PPP support for S514 PCI Cards + +2.1.3 Apr 06, 2000 o Socket based x25api + o Socket based chdlc api + o Socket based fr api + o Dual Port Receive only CHDLC support. + o Asynchronous CHDLC support (Secondary Port) + o cfgft1 GUI csu/dsu configurator + o wancfg GUI configuration file + configurator. + o Architectual directory changes. + +beta-2.1.4 Jul 2000 o Dynamic interface configuration: + Network interfaces reflect the state + of protocol layer. If the protocol becomes + disconnected, driver will bring down + the interface. Once the protocol reconnects + the interface will be brought up. + + Note: This option is turned off by default. + + o Dynamic wanrouter setup using 'wanconfig': + wanconfig utility can be used to + shutdown,restart,start or reconfigure + a virtual circuit dynamically. + + Frame Relay: Each DLCI can be: + created,stopped,restarted and reconfigured + dynamically using wanconfig. + + ex: wanconfig card wanpipe1 dev wp1_fr16 up + + o Wanrouter startup via command line arguments: + wanconfig also supports wanrouter startup via command line + arguments. Thus, there is no need to create a wanpipe#.conf + configuration file. + + o Socket based x25api update/bug fixes. + Added support for LCN numbers greater than 255. + Option to pass up modem messages. + Provided a PCI IRQ check, so a single S514 + card is guaranteed to have a non-sharing interrupt. + + o Fixes to the wancfg utility. + o New FT1 debugging support via *pipemon utilities. + o Frame Relay ARP support Enabled. + +beta3-2.1.4 Jul 2000 o X25 M_BIT Problem fix. + o Added the Multi-Port PPP + Updated utilites for the Multi-Port PPP. + +2.1.4 Aut 2000 + o In X25API: + Maximum packet an application can send + to the driver has been extended to 4096 bytes. + + Fixed the x25 startup bug. Enable + communications only after all interfaces + come up. HIGH SVC/PVC is used to calculate + the number of channels. + Enable protocol only after all interfaces + are enabled. + + o Added an extra state to the FT1 config, kernel module. + o Updated the pipemon debuggers. + + o Blocked the Multi-Port PPP from running on kernels + 2.2.16 or greater, due to syncppp kernel module + change. + +beta1-2.1.5 Nov 15 2000 + o Fixed the MulitPort PPP Support for kernels 2.2.16 and above. + 2.2.X kernels only + + o Secured the driver UDP debugging calls + - All illegal netowrk debugging calls are reported to + the log. + - Defined a set of allowed commands, all other denied. + + o Cpipemon + - Added set FT1 commands to the cpipemon. Thus CSU/DSU + configuraiton can be performed using cpipemon. + All systems that cannot run cfgft1 GUI utility should + use cpipemon to configure the on board CSU/DSU. + + + o Keyboard Led Monitor/Debugger + - A new utilty /usr/sbin/wpkbdmon uses keyboard leds + to convey operatinal statistic information of the + Sangoma WANPIPE cards. + NUM_LOCK = Line State (On=connected, Off=disconnected) + CAPS_LOCK = Tx data (On=transmitting, Off=no tx data) + SCROLL_LOCK = Rx data (On=receiving, Off=no rx data + + o Hardware probe on module load and dynamic device allocation + - During WANPIPE module load, all Sangoma cards are probed + and found information is printed in the /var/log/messages. + - If no cards are found, the module load fails. + - Appropriate number of devices are dynamically loaded + based on the number of Sangoma cards found. + + Note: The kernel configuraiton option + CONFIG_WANPIPE_CARDS has been taken out. + + o Fixed the Frame Relay and Chdlc network interfaces so they are + compatible with libpcap libraries. Meaning, tcpdump, snort, + ethereal, and all other packet sniffers and debuggers work on + all WANPIPE netowrk interfaces. + - Set the network interface encoding type to ARPHRD_PPP. + This tell the sniffers that data obtained from the + network interface is in pure IP format. + Fix for 2.2.X kernels only. + + o True interface encoding option for Frame Relay and CHDLC + - The above fix sets the network interface encoding + type to ARPHRD_PPP, however some customers use + the encoding interface type to determine the + protocol running. Therefore, the TURE ENCODING + option will set the interface type back to the + original value. + + NOTE: If this option is used with Frame Relay and CHDLC + libpcap library support will be broken. + i.e. tcpdump will not work. + Fix for 2.2.x Kernels only. + + o Ethernet Bridgind over Frame Relay + - The Frame Relay bridging has been developed by + Kristian Hoffmann and Mark Wells. + - The Linux kernel bridge is used to send ethernet + data over the frame relay links. + For 2.2.X Kernels only. + + o Added extensive 2.0.X support. Most new features of + 2.1.5 for protocols Frame Relay, PPP and CHDLC are + supported under 2.0.X kernels. + +beta1-2.2.0 Dec 30 2000 + o Updated drivers for 2.4.X kernels. + o Updated drivers for SMP support. + o X25API is now able to share PCI interrupts. + o Took out a general polling routine that was used + only by X25API. + o Added appropriate locks to the dynamic reconfiguration + code. + o Fixed a bug in the keyboard debug monitor. + +beta2-2.2.0 Jan 8 2001 + o Patches for 2.4.0 kernel + o Patches for 2.2.18 kernel + o Minor updates to PPP and CHLDC drivers. + Note: No functinal difference. + +beta3-2.2.9 Jan 10 2001 + o I missed the 2.2.18 kernel patches in beta2-2.2.0 + release. They are included in this release. + +Stable Release +2.2.0 Feb 01 2001 + o Bug fix in wancfg GUI configurator. + The edit function didn't work properly. + + +bata1-2.2.1 Feb 09 2001 + o WANPIPE TTY Driver emulation. + Two modes of operation Sync and Async. + Sync: Using the PPPD daemon, kernel SyncPPP layer + and the Wanpipe sync TTY driver: a PPP protocol + connection can be established via Sangoma adapter, over + a T1 leased line. + + The 2.4.0 kernel PPP layer supports MULTILINK + protocol, that can be used to bundle any number of Sangoma + adapters (T1 lines) into one, under a single IP address. + Thus, efficiently obtaining multiple T1 throughput. + + NOTE: The remote side must also implement MULTILINK PPP + protocol. + + Async:Using the PPPD daemon, kernel AsyncPPP layer + and the WANPIPE async TTY driver: a PPP protocol + connection can be established via Sangoma adapter and + a modem, over a telephone line. + + Thus, the WANPIPE async TTY driver simulates a serial + TTY driver that would normally be used to interface the + MODEM to the linux kernel. + + o WANPIPE PPP Backup Utility + This utility will monitor the state of the PPP T1 line. + In case of failure, a dial up connection will be established + via pppd daemon, ether via a serial tty driver (serial port), + or a WANPIPE async TTY driver (in case serial port is unavailable). + + Furthermore, while in dial up mode, the primary PPP T1 link + will be monitored for signs of life. + + If the PPP T1 link comes back to life, the dial up connection + will be shutdown and T1 line re-established. + + + o New Setup installation script. + Option to UPGRADE device drivers if the kernel source has + already been patched with WANPIPE. + + Option to COMPILE WANPIPE modules against the currently + running kernel, thus no need for manual kernel and module + re-compilatin. + + o Updates and Bug Fixes to wancfg utility. + +bata2-2.2.1 Feb 20 2001 + + o Bug fixes to the CHDLC device drivers. + The driver had compilation problmes under kernels + 2.2.14 or lower. + + o Bug fixes to the Setup installation script. + The device drivers compilation options didn't work + properly. + + o Update to the wpbackupd daemon. + Optimized the cross-over times, between the primary + link and the backup dialup. + +beta3-2.2.1 Mar 02 2001 + o Patches for 2.4.2 kernel. + + o Bug fixes to util/ make files. + o Bug fixes to the Setup installation script. + + o Took out the backupd support and made it into + as separate package. + +beta4-2.2.1 Mar 12 2001 + + o Fix to the Frame Relay Device driver. + IPSAC sends a packet of zero length + header to the frame relay driver. The + driver tries to push its own 2 byte header + into the packet, which causes the driver to + crash. + + o Fix the WANPIPE re-configuration code. + Bug was found by trying to run the cfgft1 while the + interface was already running. + + o Updates to cfgft1. + Writes a wanpipe#.cfgft1 configuration file + once the CSU/DSU is configured. This file can + holds the current CSU/DSU configuration. + - - Implemented user-readable status and statistics - via /proc filesystem -1.0.0 December 31, 1996 +>>>>>> END OF README <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - - Initial version ->>>>>> END <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/networking/wanpipe.txt linux.ac/Documentation/networking/wanpipe.txt --- linux.vanilla/Documentation/networking/wanpipe.txt Fri Jul 28 20:50:52 2000 +++ linux.ac/Documentation/networking/wanpipe.txt Sat Apr 14 01:14:20 2001 @@ -1,32 +1,100 @@ ------------------------------------------------------------------------------ Linux WAN Router Utilities Package ------------------------------------------------------------------------------ -Version 2.1.1 -Nov 08, 1999 +Version 2.2.1 +Mar 28, 2001 Author: Nenad Corbic <ncorbic@sangoma.com> -Copyright (c) 1995-1999 Sangoma Technologies Inc. +Copyright (c) 1995-2001 Sangoma Technologies Inc. ------------------------------------------------------------------------------ INTRODUCTION -This is a set of utilities and shell scripts you need in order to be able to -use Linux kernel-level WAN Router. Please read WAN Router User's manual -(router.txt) and WANPIPE driver documentation found in /usr/lib/router/doc -directory for installation and configuration instructions. +Wide Area Networks (WANs) are used to interconnect Local Area Networks (LANs) +and/or stand-alone hosts over vast distances with data transfer rates +significantly higher than those achievable with commonly used dial-up +connections. + +Usually an external device called `WAN router' sitting on your local network +or connected to your machine's serial port provides physical connection to +WAN. Although router's job may be as simple as taking your local network +traffic, converting it to WAN format and piping it through the WAN link, these +devices are notoriously expensive, with prices as much as 2 - 5 times higher +then the price of a typical PC box. + +Alternatively, considering robustness and multitasking capabilities of Linux, +an internal router can be built (most routers use some sort of stripped down +Unix-like operating system anyway). With a number of relatively inexpensive WAN +interface cards available on the market, a perfectly usable router can be +built for less than half a price of an external router. Yet a Linux box +acting as a router can still be used for other purposes, such as fire-walling, +running FTP, WWW or DNS server, etc. + +This kernel module introduces the notion of a WAN Link Driver (WLD) to Linux +operating system and provides generic hardware-independent services for such +drivers. Why can existing Linux network device interface not be used for +this purpose? Well, it can. However, there are a few key differences between +a typical network interface (e.g. Ethernet) and a WAN link. + +Many WAN protocols, such as X.25 and frame relay, allow for multiple logical +connections (known as `virtual circuits' in X.25 terminology) over a single +physical link. Each such virtual circuit may (and almost always does) lead +to a different geographical location and, therefore, different network. As a +result, it is the virtual circuit, not the physical link, that represents a +route and, therefore, a network interface in Linux terms. + +To further complicate things, virtual circuits are usually volatile in nature +(excluding so called `permanent' virtual circuits or PVCs). With almost no +time required to set up and tear down a virtual circuit, it is highly desirable +to implement on-demand connections in order to minimize network charges. So +unlike a typical network driver, the WAN driver must be able to handle multiple +network interfaces and cope as multiple virtual circuits come into existence +and go away dynamically. + +Last, but not least, WAN configuration is much more complex than that of say +Ethernet and may well amount to several dozens of parameters. Some of them +are "link-wide" while others are virtual circuit-specific. The same holds +true for WAN statistics which is by far more extensive and extremely useful +when troubleshooting WAN connections. Extending the ifconfig utility to suit +these needs may be possible, but does not seem quite reasonable. Therefore, a +WAN configuration utility and corresponding application programmer's interface +is needed for this purpose. + +Most of these problems are taken care of by this module. Its goal is to +provide a user with more-or-less standard look and feel for all WAN devices and +assist a WAN device driver writer by providing common services, such as: + + o User-level interface via /proc file system + o Centralized configuration + o Device management (setup, shutdown, etc.) + o Network interface management (dynamic creation/destruction) + o Protocol encapsulation/decapsulation -You can find the latest version of this software in /pub/linux directory on -Sangoma Technologies' anonymous FTP server (ftp.sangoma.com). +To ba able to use the Linux WAN Router you will also need a WAN Tools package +available from + + ftp.sangoma.com/pub/linux/current_wanpipe/wanpipe-X.Y.Z.tgz + +where vX.Y.Z represent the wanpipe version number. For technical questions and/or comments please e-mail to ncorbic@sangoma.com. For general inquiries please contact Sangoma Technologies Inc. by Hotline: 1-800-388-2475 (USA and Canada, toll free) - Phone: (905) 474-1990 + Phone: (905) 474-1990 ext: 106 Fax: (905) 474-9223 E-mail: dm@sangoma.com (David Mandelstam) WWW: http://www.sangoma.com +INSTALLATION + +Please read the WanpipeForLinux.pdf manual on how to +install the WANPIPE tools and drivers properly. + + +After installing wanpipe package: /usr/local/wanrouter/doc. +On the ftp.sangoma.com : /linux/current_wanpipe/doc + COPYRIGHT AND LICENSING INFORMATION @@ -47,7 +115,7 @@ ACKNOWLEDGEMENTS This product is based on the WANPIPE(tm) Multiprotocol WAN Router developed -by Sangoma Technologies Inc. for Linux 2.2.x. Success of the WANPIPE +by Sangoma Technologies Inc. for Linux 2.0.x and 2.2.x. Success of the WANPIPE together with the next major release of Linux kernel in summer 1996 commanded adequate changes to the WANPIPE code to take full advantage of new Linux features. @@ -75,22 +143,33 @@ NEW IN THIS RELEASE -o Renamed startup script to wanrouter -o Option to turn off/on each router - separately -o New source directory /usr/lib/wanrouter -o New PPP driver -o X25 is not supported in this release + o Updated the WANCFG utility + Calls the pppconfig to configure the PPPD + for async connections. + + o Added the PPPCONFIG utility + Used to configure the PPPD dameon for the + WANPIPE Async PPP and standard serial port. + The wancfg calls the pppconfig to configure + the pppd. + + o Fixed the PCI autodetect feature. + The SLOT 0 was used as an autodetect option + however, some high end PC's slot numbers start + from 0. + o This release has been tested with the new backupd + daemon release. + PRODUCT COMPONENTS AND RELATED FILES -/etc: +/etc: (or user defined) wanpipe1.conf default router configuration file - wanrouter.rc meta-configuration file (used by the Setup script) /lib/modules/X.Y.Z/misc: wanrouter.o router kernel loadable module + af_wanpipe.o wanpipe api socket module /lib/modules/X.Y.Z/net: sdladrv.o Sangoma SDLA support module @@ -102,64 +181,93 @@ {name} reads WAN driver statistics /usr/sbin: - wanrouter router start-up script - wanconfig router configuration utility + wanrouter wanrouter start-up script + wanconfig wanrouter configuration utility sdladump WANPIPE adapter memory dump utility fpipemon Monitor for Frame Relay cpipemon Monitor for Cisco HDLC + ppipemon Monitor for PPP + xpipemon Monitor for X25 + wpkbdmon WANPIPE keyboard led monitor/debugger -/usr/lib/wanrouter: +/usr/local/wanrouter: README this file COPYING GNU General Public License Setup installation script - Configure configuration script Filelist distribution definition file + wanrouter.rc meta-configuration file + (used by the Setup and wanrouter script) -/usr/lib/wanrouter/doc: - WANPIPE_USER_MANUAL.txt WAN Router User's Manual - WANPIPE_CONFIG.txt WAN Configuration Manual - -/usr/lib/wanrouter/interfaces: - * interface configuration files (TCP/IP configuration) - -/usr/lib/wanrouter/patches: - wanrouter-22.gz patch for Linux kernel 2.2.10 and 2.2.11 - (compatible for all 2.2.X kernels) - wanrouter-20.gz patch for Linux kernel 2.0.36 +/usr/local/wanrouter/doc: + wanpipeForLinux.pdf WAN Router User's Manual - Fix_2.2.11.gz patch to fix the 2.2.11 kernel so other patches - can be applied properly. +/usr/local/wanrouter/patches: + wanrouter-v2213.gz patch for Linux kernels 2.2.11 up to 2.2.13. + wanrouter-v2214.gz patch for Linux kernel 2.2.14. + wanrouter-v2215.gz patch for Linux kernels 2.2.15 to 2.2.17. + wanrouter-v2218.gz patch for Linux kernels 2.2.18 and up. + wanrouter-v240.gz patch for Linux kernel 2.4.0. + wanrouter-v242.gz patch for Linux kernel 2.4.2 and up. + wanrouter-v2034.gz patch for Linux kernel 2.0.34 + wanrouter-v2036.gz patch for Linux kernel 2.0.36 and up. + +/usr/local/wanrouter/patches/kdrivers: + Sources of the latest WANPIPE device drivers. + These are used to UPGRADE the linux kernel to the newest + version if the kernel source has already been pathced with + WANPIPE drivers. -/usr/lib/wanrouter/samples: +/usr/local/wanrouter/samples: interface sample interface configuration file wanpipe1.cpri CHDLC primary port wanpipe2.csec CHDLC secondary port wanpipe1.fr Frame Relay protocol wanpipe1.ppp PPP protocol ) + wanpipe1.asy CHDLC ASYNC protocol + wanpipe1.x25 X25 protocol + wanpipe1.stty Sync TTY driver (Used by Kernel PPPD daemon) + wanpipe1.atty Async TTY driver (Used by Kernel PPPD daemon) wanrouter.rc sample meta-configuration file -/usr/lib/wanrouter/src: - * wan-tools source code +/usr/local/wanrouter/util: + * wan-tools utilities source code + +/usr/local/wanrouter/api/x25: + * x25 api sample programs. +/usr/local/wanrouter/api/chdlc: + * chdlc api sample programs. +/usr/local/wanrouter/api/fr: + * fr api sample programs. +/usr/local/wanrouter/config/wancfg: + wancfg WANPIPE GUI configuration program. + Creates wanpipe#.conf files. +/usr/local/wanrouter/config/cfgft1: + cfgft1 GUI CSU/DSU configuration program. /usr/include/linux: wanrouter.h router API definitions wanpipe.h WANPIPE API definitions sdladrv.h SDLA support module API definitions sdlasfm.h SDLA firmware module definitions + if_wanpipe.h WANPIPE Socket definitions + if_wanpipe_common.h WANPIPE Socket/Driver common definitions. + sdlapci.h WANPIPE PCI definitions + -/usr/src/linux/net/router: - * router source code +/usr/src/linux/net/wanrouter: + * wanrouter source code /var/log: - wanrouter router start-up log (created by the Setup script) + wanrouter wanrouter start-up log (created by the Setup script) -/var/lock: - wanrouter router lock file (created by the Setup script) +/var/lock: (or /var/lock/subsys for RedHat) + wanrouter wanrouter lock file (created by the Setup script) -/usr/lib/wanrouter/wanpipe: +/usr/local/wanrouter/firmware: fr514.sfm Frame relay firmware for Sangoma S508/S514 card cdual514.sfm Dual Port Cisco HDLC firmware for Sangoma S508/S514 card ppp514.sfm PPP Firmware for Sangoma S508 and S514 cards + x25_508.sfm X25 Firmware for Sangoma S508 card. REVISION HISTORY @@ -228,7 +336,7 @@ creating applications using BiSync streaming. -2.0.5 Aug 04, 1999 CHDLC initialization bug fix. +2.0.5 Aug 04, 1999 CHDLC initializatin bug fix. PPP interrupt driven driver: Fix to the PPP line hangup problem. New PPP firmware @@ -241,17 +349,274 @@ Streaming HDLC API has been taken out. Available as a patch. -2.0.6 Aug 17, 1999 Increased debugging in startup scripts - Fixed installation bugs from 2.0.5 +2.0.6 Aug 17, 1999 Increased debugging in statup scripts + Fixed insallation 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 memory leak for X25API + o Fixed a memeory leak for X25API o Updated the X25API code for 2.2.X kernels. o Improved NEM handling. 2.1.0 Oct 25, 1999 o New code for S514 PCI Card o New CHDLC and Frame Relay drivers o PPP and X25 are not supported in this release + +2.1.1 Nov 30, 1999 o PPP support for S514 PCI Cards + +2.1.3 Apr 06, 2000 o Socket based x25api + o Socket based chdlc api + o Socket based fr api + o Dual Port Receive only CHDLC support. + o Asynchronous CHDLC support (Secondary Port) + o cfgft1 GUI csu/dsu configurator + o wancfg GUI configuration file + configurator. + o Architectual directory changes. + +beta-2.1.4 Jul 2000 o Dynamic interface configuration: + Network interfaces reflect the state + of protocol layer. If the protocol becomes + disconnected, driver will bring down + the interface. Once the protocol reconnects + the interface will be brought up. + + Note: This option is turned off by default. + + o Dynamic wanrouter setup using 'wanconfig': + wanconfig utility can be used to + shutdown,restart,start or reconfigure + a virtual circuit dynamically. + + Frame Relay: Each DLCI can be: + created,stopped,restarted and reconfigured + dynamically using wanconfig. + + ex: wanconfig card wanpipe1 dev wp1_fr16 up + + o Wanrouter startup via command line arguments: + wanconfig also supports wanrouter startup via command line + arguments. Thus, there is no need to create a wanpipe#.conf + configuration file. + + o Socket based x25api update/bug fixes. + Added support for LCN numbers greater than 255. + Option to pass up modem messages. + Provided a PCI IRQ check, so a single S514 + card is guaranteed to have a non-sharing interrupt. + + o Fixes to the wancfg utility. + o New FT1 debugging support via *pipemon utilities. + o Frame Relay ARP support Enabled. + +beta3-2.1.4 Jul 2000 o X25 M_BIT Problem fix. + o Added the Multi-Port PPP + Updated utilites for the Multi-Port PPP. + +2.1.4 Aut 2000 + o In X25API: + Maximum packet an application can send + to the driver has been extended to 4096 bytes. + + Fixed the x25 startup bug. Enable + communications only after all interfaces + come up. HIGH SVC/PVC is used to calculate + the number of channels. + Enable protocol only after all interfaces + are enabled. + + o Added an extra state to the FT1 config, kernel module. + o Updated the pipemon debuggers. + + o Blocked the Multi-Port PPP from running on kernels + 2.2.16 or greater, due to syncppp kernel module + change. + +beta1-2.1.5 Nov 15 2000 + o Fixed the MulitPort PPP Support for kernels 2.2.16 and above. + 2.2.X kernels only + + o Secured the driver UDP debugging calls + - All illegal netowrk debugging calls are reported to + the log. + - Defined a set of allowed commands, all other denied. + + o Cpipemon + - Added set FT1 commands to the cpipemon. Thus CSU/DSU + configuraiton can be performed using cpipemon. + All systems that cannot run cfgft1 GUI utility should + use cpipemon to configure the on board CSU/DSU. + + + o Keyboard Led Monitor/Debugger + - A new utilty /usr/sbin/wpkbdmon uses keyboard leds + to convey operatinal statistic information of the + Sangoma WANPIPE cards. + NUM_LOCK = Line State (On=connected, Off=disconnected) + CAPS_LOCK = Tx data (On=transmitting, Off=no tx data) + SCROLL_LOCK = Rx data (On=receiving, Off=no rx data + + o Hardware probe on module load and dynamic device allocation + - During WANPIPE module load, all Sangoma cards are probed + and found information is printed in the /var/log/messages. + - If no cards are found, the module load fails. + - Appropriate number of devices are dynamically loaded + based on the number of Sangoma cards found. + + Note: The kernel configuraiton option + CONFIG_WANPIPE_CARDS has been taken out. + + o Fixed the Frame Relay and Chdlc network interfaces so they are + compatible with libpcap libraries. Meaning, tcpdump, snort, + ethereal, and all other packet sniffers and debuggers work on + all WANPIPE netowrk interfaces. + - Set the network interface encoding type to ARPHRD_PPP. + This tell the sniffers that data obtained from the + network interface is in pure IP format. + Fix for 2.2.X kernels only. + + o True interface encoding option for Frame Relay and CHDLC + - The above fix sets the network interface encoding + type to ARPHRD_PPP, however some customers use + the encoding interface type to determine the + protocol running. Therefore, the TURE ENCODING + option will set the interface type back to the + original value. + + NOTE: If this option is used with Frame Relay and CHDLC + libpcap library support will be broken. + i.e. tcpdump will not work. + Fix for 2.2.x Kernels only. + + o Ethernet Bridgind over Frame Relay + - The Frame Relay bridging has been developed by + Kristian Hoffmann and Mark Wells. + - The Linux kernel bridge is used to send ethernet + data over the frame relay links. + For 2.2.X Kernels only. + + o Added extensive 2.0.X support. Most new features of + 2.1.5 for protocols Frame Relay, PPP and CHDLC are + supported under 2.0.X kernels. + +beta1-2.2.0 Dec 30 2000 + o Updated drivers for 2.4.X kernels. + o Updated drivers for SMP support. + o X25API is now able to share PCI interrupts. + o Took out a general polling routine that was used + only by X25API. + o Added appropriate locks to the dynamic reconfiguration + code. + o Fixed a bug in the keyboard debug monitor. + +beta2-2.2.0 Jan 8 2001 + o Patches for 2.4.0 kernel + o Patches for 2.2.18 kernel + o Minor updates to PPP and CHLDC drivers. + Note: No functinal difference. + +beta3-2.2.9 Jan 10 2001 + o I missed the 2.2.18 kernel patches in beta2-2.2.0 + release. They are included in this release. + +Stable Release +2.2.0 Feb 01 2001 + o Bug fix in wancfg GUI configurator. + The edit function didn't work properly. + + +bata1-2.2.1 Feb 09 2001 + o WANPIPE TTY Driver emulation. + Two modes of operation Sync and Async. + Sync: Using the PPPD daemon, kernel SyncPPP layer + and the Wanpipe sync TTY driver: a PPP protocol + connection can be established via Sangoma adapter, over + a T1 leased line. + + The 2.4.0 kernel PPP layer supports MULTILINK + protocol, that can be used to bundle any number of Sangoma + adapters (T1 lines) into one, under a single IP address. + Thus, efficiently obtaining multiple T1 throughput. + + NOTE: The remote side must also implement MULTILINK PPP + protocol. + + Async:Using the PPPD daemon, kernel AsyncPPP layer + and the WANPIPE async TTY driver: a PPP protocol + connection can be established via Sangoma adapter and + a modem, over a telephone line. + + Thus, the WANPIPE async TTY driver simulates a serial + TTY driver that would normally be used to interface the + MODEM to the linux kernel. + + o WANPIPE PPP Backup Utility + This utility will monitor the state of the PPP T1 line. + In case of failure, a dial up connection will be established + via pppd daemon, ether via a serial tty driver (serial port), + or a WANPIPE async TTY driver (in case serial port is unavailable). + + Furthermore, while in dial up mode, the primary PPP T1 link + will be monitored for signs of life. + + If the PPP T1 link comes back to life, the dial up connection + will be shutdown and T1 line re-established. + + + o New Setup installation script. + Option to UPGRADE device drivers if the kernel source has + already been patched with WANPIPE. + + Option to COMPILE WANPIPE modules against the currently + running kernel, thus no need for manual kernel and module + re-compilatin. + + o Updates and Bug Fixes to wancfg utility. + +bata2-2.2.1 Feb 20 2001 + + o Bug fixes to the CHDLC device drivers. + The driver had compilation problmes under kernels + 2.2.14 or lower. + + o Bug fixes to the Setup installation script. + The device drivers compilation options didn't work + properly. + + o Update to the wpbackupd daemon. + Optimized the cross-over times, between the primary + link and the backup dialup. + +beta3-2.2.1 Mar 02 2001 + o Patches for 2.4.2 kernel. + + o Bug fixes to util/ make files. + o Bug fixes to the Setup installation script. + + o Took out the backupd support and made it into + as separate package. + +beta4-2.2.1 Mar 12 2001 + + o Fix to the Frame Relay Device driver. + IPSAC sends a packet of zero length + header to the frame relay driver. The + driver tries to push its own 2 byte header + into the packet, which causes the driver to + crash. + + o Fix the WANPIPE re-configuration code. + Bug was found by trying to run the cfgft1 while the + interface was already running. + + o Updates to cfgft1. + Writes a wanpipe#.cfgft1 configuration file + once the CSU/DSU is configured. This file can + holds the current CSU/DSU configuration. + + + >>>>>> END OF README <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/nmi_watchdog.txt linux.ac/Documentation/nmi_watchdog.txt --- linux.vanilla/Documentation/nmi_watchdog.txt Mon Aug 21 16:57:35 2000 +++ linux.ac/Documentation/nmi_watchdog.txt Tue Apr 3 17:54:28 2001 @@ -1,19 +1,27 @@ -Is your SMP system locking up unpredictably? No keyboard activity, just +Is your ix86 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 whether 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: +On Intel and similar ix86 type hardware there is a feature that enables +us to generate 'watchdog NMI interrupts'. (NMI: Non Maskable Interrupt +which 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 whether any CPU has locked up, +and print out debugging messages if so. You must enable the NMI +watchdog at boot time with the 'nmi_watchdog=n' boot parameter. Eg. +the relevant lilo.conf entry: append="nmi_watchdog=1" +For SMP machines and UP machines with an IO-APIC use nmi_watchdog=1. +For UP machines without an IO-APIC use nmi_watchdog=2, this only works +for some processor types. If in doubt, boot with nmi_watchdog=1 and +check the NMI count in /proc/interrupts; if the count is zero then +reboot with nmi_watchdog=2 and check the NMI count. If it is still +zero then log a problem, you probably have a processor that needs to be +added to the nmi code. + 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 @@ -24,8 +32,9 @@ cannot even accept NMI interrupts, or the crash has made the kernel unable to print messages. -NOTE: currently the NMI-oopser is enabled unconditionally on x86 SMP -boxes. +NOTE: starting with 2.4.2-ac18 the NMI-oopser is disabled by default, +you have to enable it with a boot time parameter. Prior to 2.4.2-ac18 +the NMI-oopser is enabled unconditionally on x86 SMP boxes. [ feel free to send bug reports, suggestions and patches to Ingo Molnar <mingo@redhat.com> or the Linux SMP mailing diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/parisc/00-INDEX linux.ac/Documentation/parisc/00-INDEX --- linux.vanilla/Documentation/parisc/00-INDEX Tue Dec 5 20:29:38 2000 +++ linux.ac/Documentation/parisc/00-INDEX Tue Apr 3 17:54:28 2001 @@ -1,10 +1,8 @@ 00-INDEX - this file. IODC.txt - - Documentation IODC + - Documentation for IODC debugging - some debugging hints for real-mode code -mm - - Documentation on parisc mm status registers - current/planned usage of registers diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/parisc/mm linux.ac/Documentation/parisc/mm --- linux.vanilla/Documentation/parisc/mm Tue Dec 5 20:29:38 2000 +++ linux.ac/Documentation/parisc/mm Thu Jan 1 01:00:00 1970 @@ -1,31 +0,0 @@ - -The current state of Linux/PA-RISC mm is BROKEN. - -Someone needs to sit down and thoroughly rewrite all the cache flushing -macro definitions. Here are some of the problems, followed by what I -think needs to be done about them. - -(1) We're using fdce / fice everywhere. This has to stop (except in -the routines which flush the entire cache). The right instructions to -be using are fdc/fic. - -(2) fdc/fic will throw exceptions if the address they reference isn't -mapped. Therefore we need to check the page is mapped before flushing -(we're guaranteed not to have the page dirty if we don't have a software -mapping for it any longer, right?) - -(3) the flush macros are right now tunnelled down to one routine to flush -the data cache and one routine to flush the insn cache. this is wrong. -we should take hints from how we're called and optimise our routines -accordingly. - -(4) fdc/fic actually take space register arguments. fic takes an 3-bit sr -argument and fdc takes a 2-bit sr argument. right now, there's a lot of -pissing about with %sr1 and all the macros use %sr1. This is crazy. We -normally _know_ what's being referred to, and it's the current task. So -if we want to flush that, just use %sr3. If it happens to be kernel, -use %sr0 for fdc and %sr4 for fic. - -(5) we need to write flush_kernel_dcache_range and use it on kernel -addresses. all the macros are defined to work on the _current task's_ -virtual address space. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/parisc/registers linux.ac/Documentation/parisc/registers --- linux.vanilla/Documentation/parisc/registers Tue Dec 5 20:29:38 2000 +++ linux.ac/Documentation/parisc/registers Tue Apr 3 17:54:28 2001 @@ -16,9 +16,9 @@ CR11 as specified by ABI CR14 (interruption vector) initialized to fault_vector CR15 (EIEM) initialized to all ones* -CR16 (Interval Timer) timer interrupt +CR16 (Interval Timer) read for cycle count/write starts Interval Tmr CR17-CR22 interruption parameters -CR23 (EIRR) read for pending interrupts +CR23 (EIRR) read for pending interrupts/write clears bits CR24 (TR 0) Kernel Space Page Directory Pointer CR25 (TR 1) User Space Page Directory Pointer CR26 (TR 2) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/parport.txt linux.ac/Documentation/parport.txt --- linux.vanilla/Documentation/parport.txt Tue Apr 3 17:31:51 2001 +++ linux.ac/Documentation/parport.txt Tue Apr 10 18:04:17 2001 @@ -174,7 +174,7 @@ peripherals. This is a port-wide setting, i.e. it applies to all devices on a particular port. -timeslice The number of miliseconds that a device driver is +timeslice The number of milliseconds that a device driver is allowed to keep a port claimed for. This is advisory, and driver can ignore it if it must. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/pm.txt linux.ac/Documentation/pm.txt --- linux.vanilla/Documentation/pm.txt Thu Oct 26 22:22:24 2000 +++ linux.ac/Documentation/pm.txt Tue Apr 10 18:04:17 2001 @@ -33,7 +33,7 @@ Go ahead and start both. If ACPI or APM is not available on your system the associated daemon will exit gracefully. - apmd: http://linuxcare.com.au/apm/ + apmd: http://worldvisions.ca/~apenwarr/apmd/ acpid: http://phobos.fs.tum.de/acpi/ Driver Interface diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/s390/3270.ChangeLog linux.ac/Documentation/s390/3270.ChangeLog --- linux.vanilla/Documentation/s390/3270.ChangeLog Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/s390/3270.ChangeLog Sat Apr 14 01:14:27 2001 @@ -0,0 +1,15 @@ +ChangeLog for the UTS Global 3270-support patch + +Feb 6, 2001: + * This changelog is new + * tub3270 now supports 3270 console: + Specify y for CONFIG_3270 and y for CONFIG_3270_CONSOLE. + Support for 3215 will not appear if 3270 console support + is chosen. + NOTE: The default is 3270 console support, NOT 3215. + * the components are remodularized: added source modules are + tubttybld.c and tubttyscl.c, for screen-building code and + scroll-timeout code. + * tub3270 source for this (2.4.0) version is #ifdeffed to + build with both 2.4.0 and 2.2.16.2. + * color support and minimal other ESC-sequence support is added. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/s390/3270.txt linux.ac/Documentation/s390/3270.txt --- linux.vanilla/Documentation/s390/3270.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/s390/3270.txt Sat Apr 14 01:14:27 2001 @@ -0,0 +1,280 @@ +IBM 3270 Display System support + +This file describes the driver that supports local channel attachment +of IBM 3270 devices. It consists of three sections: + * Introduction + * Installation + * Operation + + +INTRODUCTION. + +This paper describes installing and operating 3270 devices under +Linux/390. A 3270 device is a block-mode rows-and-columns terminal of +which I'm sure hundreds of millions were sold by IBM and clonemakers +twenty and thirty years ago. + +You may have 3270s in-house and not know it. If you're using the +VM-ESA operating system, define a 3270 to your virtual machine by using +the command "DEF GRAF <hex-address>" This paper presumes you will be +defining four 3270s with the CP/CMS commands + + DEF GRAF 620 + DEF GRAF 621 + DEF GRAF 622 + DEF GRAF 623 + +Your network connection from VM-ESA allows you to use x3270, tn3270, or +another 3270 emulator, started from an xterm window on your PC or +workstation. With the DEF GRAF command, an application such as xterm, +and this Linux-390 3270 driver, you have another way of talking to your +Linux box. + +This paper covers installation of the driver and operation of a +dialed-in x3270. + + +HELP !!! + +The device name of e.g. /dev/3270/tty620 noted below is at variance +with "standard" Linux device names. What should it be? The portion +"/dev/3270" was recommended by H. Peter Anvin, maintainer of the +official Linux major-numbers list; the portion "tty620" was recommended +by me. Please send your thoughts on this issue at least to me at +rbh00@utsglobal.com. Even if you think it's okay as is, please let me +know. Thanks. + + +INSTALLATION. + +You install the driver by installing a patch, doing a kernel build, and +running the configuration script (config3270.sh, in this directory). + +WARNING: If you are using 3270 console support, you must rerun the +configuration script every time you change the console's address (perhaps +by using the condev= parameter in silo's /boot/parmfile). More precisely, +you should rerun the configuration script every time your set of 3270s, +including the console 3270, changes subchannel identifier relative to +one another. ReIPL as soon as possible after running the configuration +script and the resulting /tmp/mkdev3270. + +If you have chosen to make tub3270 a module, you add a line to +/etc/modules.conf. If you are working on a VM virtual machine, you +can use DEF GRAF to define virtual 3270 devices. If you generate 3270 +console support, the driver automatically converts your console at boot +time to a 3270 if it is a 3215. + +In brief, these are the steps: + 1. Install the tub3270 patch + 2. (If a module) add a line to /etc/modules.conf + 3. (If VM) define devices with DEF GRAF + 4. Reboot + 5. Configure + +To test that everything works, assuming VM and x3270, + 1. Bring up an x3270 window. + 2. Use the DIAL command in that window. + 3. You should immediately see a Linux login screen. + +Here are the installation steps in detail: + + 0. Retrieve the patch file via anonymous ftp from + ftp://ftp.utsglobal.com/pub/tub3270. The patch is designed + to apply smoothly to an IBM 2.4.0 system with no other + UTS-Global patches applied. We know of some easily resolvable + conflicts between this and other of our patches. + + 1. Apply the patch. Then do + make oldconfig + (Reply "y" or "m" for CONFIG_3270; if "y", + reply "y" or "n" for CONFIG_3270_CONSOLE) + make dep + make image + make modules + make modules_install + <run silo in the usual way> + + 2. (Perform this step only if you have configured tub3270 as a + module.) Add a line to /etc/modules.conf to automatically + load the driver when it's needed. With this line added, + you will see login prompts appear on your 3270s as soon as + boot is complete (or with emulated 3270s, as soon as you dial + into your vm guest using the command "DIAL <vmguestname>"). + Since the line-mode major number is 212, the line to add to + /etc/modules.conf should be: + alias char-major-212 tub3270 + + 3. Define graphic devices to your vm guest machine, if you + haven't already. Define them before you reboot (reipl): + DEFINE GRAF 620 + DEFINE GRAF 621 + DEFINE GRAF 622 + DEFINE GRAF 623 + + 4. Reboot. The reboot process scans hardware devices, including + 3270s, and this enables the tub3270 driver once loaded to respond + correctly to the configuration requests of the next step. If + you have chosen 3270 console support, your console now behaves + as a 3270, not a 3215. + + 5. Run the 3270 configuration script config3270. It is + distributed in this same directory, Documentation/s390, as + config3270.sh. Inspect the output script it produces, + /tmp/mkdev3270, and then run that script. This will create the + necessary character special device files and make the necessary + changes to /etc/inittab. Then notify /sbin/init that /etc/inittab + has changed, by issuing the telinit command with the q operand: + cd /usr/src/linux/Documentation/s390 + sh config3270.sh + sh /tmp/mkdev3270 + telinit q + This should be sufficient for your first time. If your 3270 + configuration has changed and you're reusing config3270, you + should follow these steps: + Change 3270 configuration + Reboot + Run config3270 and /tmp/mkdev3270 + Reboot + +Here are the testing steps in detail: + + 1. Bring up an x3270 window, or use an actual hardware 3278 or + 3279, or use the 3270 emulator of your choice. You would be + running the emulator on your PC or workstation. You would use + the command, for example, + x3270 vm-esa-domain-name & + if you wanted a 3278 Model 4 with 43 rows of 80 columns, the + default model number. The driver does not take advantage of + extended attributes. + + The screen you should now see contains a VM logo with input + lines near the bottom. Use TAB to move to the bottom line, + probably labeled "COMMAND ===>". + + 2. Use the DIAL command instead of the LOGIN command to connect + to one of the virtual 3270s you defined with the DEF GRAF + commands: + dial my-vm-guest-name + + 3. You should immediately see a login prompt from your + Linux-390 operating system. If that does not happen, you would + see instead the line "DIALED TO my-vm-guest-name 0620". + + To troubleshoot: do these things. + + A. Is the driver loaded? Use the lsmod command (no operands) + to find out. Probably it isn't. Try loading it manually, with + the command "insmod tub3270". Does that command give error + messages? Ha! There's your problem. + + B. Is the /etc/inittab file modified as in installation step 3 + above? Use the grep command to find out; for instance, issue + "grep 3270 /etc/inittab". Nothing found? There's your + problem! + + C. Are the device special files created, as in installation + step 2 above? Use the ls -l command to find out; for instance, + issue "ls -l /dev/3270/tty620". The output should start with the + letter "c" meaning character device and should contain "212, 1" + just to the left of the device name. No such file? no "c"? + Wrong major number? Wrong minor number? There's your + problem! + + D. Do you get the message + "HCPDIA047E my-vm-guest-name 0620 does not exist"? + If so, you must issue the command "DEF GRAF 620" from your VM + 3215 console and then reboot the system. + + + +OPERATION. + +The driver defines three areas on the 3270 screen: the log area, the +input area, and the status area. + +The log area takes up all but the bottom two lines of the screen. The +driver writes terminal output to it, starting at the top line and going +down. When it fills, the status area changes from "Linux Running" to +"Linux More...". After a scrolling timeout of (default) 5 sec, the +screen clears and more output is written, from the top down. + +The input area extends from the beginning of the second-to-last screen +line to the start of the status area. You type commands in this area +and hit ENTER to execute them. + +The status area initializes to "Linux Running" to give you a warm +fuzzy feeling. When the log area fills up and output awaits, it +changes to "Linux More...". At this time you can do several things or +nothing. If you do nothing, the screen will clear in (default) 5 sec +and more output will appear. You may hit ENTER with nothing typed in +the input area to toggle between "Linux More..." and "Linux Holding", +which indicates no scrolling will occur. (If you hit ENTER with "Linux +Running" and nothing typed, the application receives a newline.) + +You may change the scrolling timeout value. For example, the following +command line: + echo scrolltime=60 > /proc/tty/driver/tty3270 +changes the scrolling timeout value to 60 sec. Set scrolltime to 0 if +you wish to prevent scrolling entirely. + +Other things you may do when the log area fills up are: hit PA2 to +clear the log area and write more output to it, or hit CLEAR to clear +the log area and the input area and write more output to the log area. + +Some of the Program Function (PF) and Program Attention (PA) keys are +preassigned special functions. The ones that are not yield an alarm +when pressed. + +PA1 causes a SIGINT to the currently running application. You may do +the same thing from the input area, by typing "^C" and hitting ENTER. + +PA2 causes the log area to be cleared. If output awaits, it is then +written to the log area. + +PF3 causes an EOF to be received as input by the application. You may +cause an EOF also by typing "^D" and hitting ENTER. + +No PF key is preassigned to cause a job suspension, but you may cause a +job suspension by typing "^Z" and hitting ENTER. You may wish to +assign this function to a PF key. To make PF7 cause job suspension, +execute the command: + echo pf7=^z > /proc/tty/driver/tty3270 + +If the input you type does not end with the two characters "^n", the +driver appends a newline character and sends it to the tty driver; +otherwise the driver strips the "^n" and does not append a newline. +The IBM 3215 driver behaves similarly. + +Pf10 causes the most recent command to be retrieved from the tube's +command stack (default depth 20) and displayed in the input area. You +may hit PF10 again for the next-most-recent command, and so on. A +command is entered into the stack only when the input area is not made +invisible (such as for password entry) and it is not identical to the +current top entry. PF10 rotates backward through the command stack; +PF11 rotates forward. You may assign the backward function to any PF +key (or PA key, for that matter), say, PA3, with the command: + echo -e pa3=\\033k > /proc/tty/driver/tty3270 +This assigns the string ESC-k to PA3. Similarly, the string ESC-j +performs the forward function. (Rationale: In bash with vi-mode line +editing, ESC-k and ESC-j retrieve backward and forward history. +Suggestions welcome.) + +Is a stack size of twenty commands not to your liking? Change it on +the fly. To change to saving the last 100 commands, execute the +command: + echo recallsize=100 > /proc/tty/driver/tty3270 + +Have a command you issue frequently? Assign it to a PF or PA key! Use +the command + echo pf24="mkdir foobar; cd foobar" > /proc/tty/driver/tty3270 +to execute the commands mkdir foobar and cd foobar immediately when you +hit PF24. Want to see the command line first, before you execute it? +Use the -n option of the echo command: + echo -n pf24="mkdir foo; cd foo" > /proc/tty/driver/tty3270 + + + +Happy testing! I welcome any and all comments about this document, the +driver, etc etc. + +Dick Hitt <rbh00@utsglobal.com> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/s390/Debugging390.txt linux.ac/Documentation/s390/Debugging390.txt --- linux.vanilla/Documentation/s390/Debugging390.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/s390/Debugging390.txt Thu Apr 12 11:48:05 2001 @@ -0,0 +1,2439 @@ + + Debugging on Linux for s/390 & zSeries + by + Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) + Copyright (C) 2000-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + Best viewed with fixed width fonts + +Overview of Document: +===================== +This document is intended to give an good overview of how to debug +Linux for s/390 & zSeries it isn't intended as a complete reference & not a +tutorial on the fundamentals of C & assembly, it dosen't go into +390 IO in any detail. It is intended to compliment the documents in the +reference section below & any other worthwhile references you get. + +It is intended like the Enterprise Systems Architecture/390 Reference Summary +to be printed out & used as a quick cheat sheet self help style reference when +problems occur. + +Contents +======== +Register Set +Address Spaces on Intel Linux +Address Spaces on Linux for s/390 & zSeries +The Linux for s/390 & zSeries Kernel Task Structure +Register Usage & Stackframes on Linux for s/390 & zSeries +A sample program with comments +Compiling programs for debugging on Linux for s/390 & zSeries +Figuring out gcc compile errors +Debugging Tools +objdump +strace +Performance Debugging +Debugging under VM +s/390 & zSeries IO Overview +Debugging IO on s/390 & zSeries under VM +GDB on s/390 & zSeries +Stack chaining in gdb by hand +Examining core dumps +ldd +Debugging modules +The proc file system +Starting points for debugging scripting languages etc. +Tools soon to be available +SysRq +References + +Register Set +============ +The current architectures have the following registers. + +16 General propose registers, 32 bit on s/390 64 bit on zSeries, r0-r15 or gpr0-gpr15 used for arithmetic & addressing. + +16 Control registers, 32 bit on s/390 64 bit on zSeries, ( cr0-cr15 kernel usage only ) used for memory managment, +interrupt control,debugging control etc. + +16 Access registers ( ar0-ar15 ) 32 bit on s/390 & zSeries +not used by normal programs but potentially could +be used as temporary storage. Their main purpose is their 1 to 1 +association with general purpose registers and are used in +the kernel for copying data between kernel & user address spaces. +Access register 0 ( & access register 1 on z/Series ( needs 64 bit pointer ) ) +is currently used by the pthread library as a pointer to +the current running threads private area. + +16 64 bit floating point registers (fp0-fp15 ) IEEE & HFP floating +point format compliant on G5 upwards & a Floating point control reg (FPC) +4 64 bit registers (fp0,fp2,fp4 & fp6) HFP only on older machines. +Note: +Linux (currently) always uses IEEE & emulates G5 IEEE format on older machines, +( provided the kernel is configured for this ). + + +The PSW is the most important register on the machine it +is 64 bit on s/390 & 128 bit on zSeries & serves the roles of +a program counter (pc), condition code register,memory space designator. +In IBM standard notation I am counting bit 0 as the MSB. +It has several advantages over a normal program counter +in that you can change address translation & program counter +in a single instruction. To change address translation, +e.g. switching address translation off requires that you +have a logical=physical mapping for the address you are +currently running at. + + Bit Value +s/390 zSeries +0 0 Reserved ( must be 0 ) otherwise specification exception occurs. + +1 1 Program Event Recording 1 PER enabled, + PER is used to facilititate debugging e.g. single stepping. + +2-4 2-4 Reserved ( must be 0 ). + +5 5 Dynamic address translation 1=DAT on. + +6 6 Input/Output interrupt Mask + +7 7 External interrupt Mask used primarily for interprocessor signalling & + clock interupts. + +8-11 8-11 PSW Key used for complex memory protection mechanism not used under linux + +12 12 1 on s/390 0 on zSeries + +13 13 Machine Check Mask 1=enable machine check interrupts + +14 14 Wait State set this to 1 to stop the processor except for interrupts & give + time to other LPARS used in CPU idle in the kernel to increase overall + usage of processor resources. + +15 15 Problem state ( if set to 1 certain instructions are disabled ) + all linux user programs run with this bit 1 + ( useful info for debugging under VM ). + +16-17 16-17 Address Space Control + + 00 Primary Space Mode when DAT on + The linux kernel currently runs in this mode, CR1 is affiliated with + this mode & points to the primary segment table origin etc. + + 01 Access register mode this mode is used in functions to + copy data between kernel & user space. + + 10 Secondary space mode not used in linux however CR7 the + register affiliated with this mode is & this & normally + CR13=CR7 to allow us to copy data between kernel & user space. + We do this as follows: + We set ar2 to 0 to designate its + affiliated gpr ( gpr2 )to point to primary=kernel space. + We set ar4 to 1 to designate its + affiliated gpr ( gpr4 ) to point to secondary=home=user space + & then essentially do a memcopy(gpr2,gpr4,size) to + copy data between the address spaces, the reason we use home space for the + kernel & don't keep secondary space free is that code will not run in + secondary space. + + 11 Home Space Mode all user programs run in this mode. + it is affiliated with CR13. + +18-19 18-19 Condition codes (CC) + +20 20 Fixed point overflow mask if 1=FPU exceptions for this event + occur ( normally 0 ) + +21 21 Decimal overflow mask if 1=FPU exceptions for this event occur + ( normally 0 ) + +22 22 Exponent underflow mask if 1=FPU exceptions for this event occur + ( normally 0 ) + +23 23 Significance Mask if 1=FPU exceptions for this event occur + ( normally 0 ) + +24-31 24-30 Reserved Must be 0. + + 31 Extended Addressing Mode + 32 Basic Addressing Mode + Used to set addressing mode + PSW 31 PSW 32 + 0 0 24 bit + 0 1 31 bit + 1 1 64 bit + +32 1=31 bit addressing mode 0=24 bit addressing mode (for backward + compatibility ), linux always runs with this bit set to 1 + +33-64 Instruction address. + 33-63 Reserved must be 0 + 64-127 Address + In 24 bits mode bits 64-103=0 bits 104-127 Address + In 31 bits mode bits 64-96=0 bits 97-127 Address + Note: unlike 31 bit mode on s/390 bit 96 must be zero + when loading the address with LPSWE otherwise a + specification exception occurs, LPSW is fully backward + compatible. + + +Prefix Page +----------- +This per cpu memory area is too intimately tied to the processor not to mention. +It exists between the real addresses 0-4096 on the processor & is exchanged +with a page in absolute storage by the set prefix instruction in linux'es startup. +This page different on each processor. +Bytes 0-512 ( 200 hex ) are used by the processor itself for holding such +information as exception indications & entry points for exceptions. +Bytes after 0xc00 hex are used by linux for per processor globals. +The closest thing to this on traditional architectures is the interrupt +vector table. This is a good thing & does simplify some of the kernel coding +however it means that we now cannot catch stray NULL pointers in the +kernel without hard coded checks. + + + +Address Spaces on Intel Linux +============================= + +The traditional Intel Linux is approximately mapped as follows forgive +the ascii art. +0xFFFFFFFF 4GB Himem ***************** + * * + * Kernel Space * + * * + ***************** **************** +User Space Himem (typically 0xC0000000 3GB )* User Stack * * * + ***************** * * + * Shared Libs * * Next Process * + ***************** * to * + * * <== * Run * <== + * User Program * * * + * Data BSS * * * + * Text * * * + * Sections * * * +0x00000000 ***************** **************** + +Now it is easy to see that on Intel it is quite easy to recognise a kernel address +as being one greater than user space himem ( in this case 0xC0000000). +& addresses of less than this are the ones in the current running program on this +processor ( if an smp box ). +If using the virtual machine ( VM ) as a debugger it is quite difficult to +know which user process is running as the address space you are looking at +could be from any process in the run queue. +Thankfully you normally get lucky as address spaces don't overlap that & +you can recognise the code at by cross referencing with a dump made by objdump +( more about that later ). + +The limitation of Intels addressing technique is that the linux +kernel uses a very simple real address to virtual addressing technique +of Real Address=Virtual Address-User Space Himem. +This means that on Intel the kernel linux can typically only address +Himem=0xFFFFFFFF-0xC0000000=1GB & this is all the RAM these machines +can typically use. +They can lower User Himem to 2GB or lower & thus be +able to use 2GB of RAM however this shrinks the maximum size +of User Space from 3GB to 2GB they have a no win limit of 4GB unless +they go to 64 Bit. + + +On 390 our limitations & strengths make us slightly different. +For backward compatibility we are only allowed use 31 bits (2GB) +of our 32 bit addresses,however, we use entirely separate address +spaces for the user & kernel. + +This means we can support 2GB of non Extended RAM, & more +with the Extended memory managment swap device & 64 Bit +when it comes along. + + +Address Spaces on Linux for S390 +================================ + +Our addressing scheme is as follows + + +Himem 0x7fffffff 2GB on s/390 ***************** **************** +2^64 bytes on zSeries * User Stack * * * + ***************** * * + * Shared Libs * * * + ***************** * * + * * * Kernel * + * User Program * * * + * Data BSS * * * + * Text * * * + * Sections * * * +0x00000000 ***************** **************** + +This also means that we need to look at the PSW problem state bit +or the addressing mode to decide whether we are looking at +user or kernel space. + +The Linux for s/390 & zSeries Kernel Task Structure +=================================================== +Each process/thread under Linux for S390 has its own kernel task_struct +defined in linux/include/linux/sched.h +The S390 on initialisation & resuming of a process on a cpu sets +the __LC_KERNEL_STACK variable in the spare prefix area for this cpu +( which we use for per processor globals). + +The kernel stack pointer is intimately tied with the task stucture for +each processor as follows. + + s/390 + ************************ + * 1 page kernel stack * + * ( 4K ) * + ************************ + * 1 page task_struct * + * ( 4K ) * +8K aligned ************************ + + zSeries + ************************ + * 2 page kernel stack * + * ( 8K ) * + ************************ + * 2 page task_struct * + * ( 8K ) * +16K aligned ************************ + +What this means is that we don't need to dedicate any register or global variable +to point to the current running process & can retrieve it with the following +very simple construct for s/390 & one very similar for zSeries. + +static inline struct task_struct * get_current(void) +{ + struct task_struct *current; + __asm__("lhi %0,-8192\n\t" + "nr %0,15" + : "=r" (current) ); + return current; +} + +i.e. just anding the current kernel stack pointer with the mask -8192. +Thankfully because Linux dosen't have support for nested IO interrupts +& our devices have large buffers can survive interrupts being shut for +short amounts of time we don't need a separate stack for interrupts. + + + + +Register Usage & Stackframes on Linux for s/390 & zSeries +========================================================= +Overview: +--------- +This is the code that gcc produces at the top & the bottom of +each function, it usually is fairly consistent & similar from +function to function & if you know its layout you can probalby +make some headway in finding the ultimate cause of a problem +after a crash without a source level debugger. + +Note: To follow stackframes requires a knowledge of C or Pascal & +limited knowledge of one assembly language. + +It should be noted that there are some differences between the +s/390 & zSeries stack layouts as the zSeries stack layout didn't have +to maintain compatibility with older linkage formats. + +Glossary: +--------- +alloca: +This is a built in compiler function for runtime allocation +of extra space on the callers stack which is obviously freed +up on function exit ( e.g. the caller may choose to allocate nothing +of a buffer of 4k if required for temporary purposes ), it generates +very efficent code ( a few cycles ) when compared to alternatives +like malloc. + +automatics: These are local variables on the stack, +i.e they aren't in registers & they aren't static. + +back-chain: +This is a pointer to the stack pointer before entering a +framed functions ( see frameless function ) prologue got by +deferencing the address of the current stack pointer, + i.e. got by accessing the 32 bit value at the stack pointers +current location. + +base-pointer: +This is a pointer to the back of the literal pool which +is an area just behind each procedure used to store constants +in each function. + +call-clobbered: The caller probably needs to save these registers if there +is something of value in them, on the stack or elsewhere before making a +call to another procedure so that it can restore it later. + +epilogue: +The code generated by the compiler to return to the caller. + +frameless-function +A frameless function in Linux for s390 & zSeries is one which doesn't need +more than the register save area ( 96 bytes on s/390, 160 on zSeries ) +given to it by the caller. +A frameless function never: +1) Sets up a back chain. +2) Calls alloca. +3) Calls other normal functions +4) Has automatics. + +GOT-pointer: +This is a pointer to the global-offset-table in ELF +( Executable Linkable Format, Linux'es most common executable format ), +all globals & shared library objects are found using this pointer. + +lazy-binding +ELF shared libraries are typically only loaded when routines in the shared +library are actually first called at runtime. This is lazy binding. + +procedure-linkage-table +This is a table found from the GOT which contains pointers to routines +in other shared libraries which can't be called to by easier means. + +prologue: +The code generated by the compiler to set up the stack frame. + +outgoing-args: +This is extra area allocated on the stack of the calling function if the +parameters for the callee's cannot all be put in registers, the same +area can be reused by each function the caller calls. + +routine-descriptor: +A COFF executable format based concept of a procedure reference +actually being 8 bytes or more as opposed to a simple pointer to the routine. +This is typically defined as follows +Routine Descriptor offset 0=Pointer to Function +Routine Descriptor offset 4=Pointer to Table of Contents +The table of contents/TOC is roughly equivalent to a GOT pointer. +& it means that shared libraries etc. can be shared between several +environments each with their own TOC. + + +static-chain: This is used in nested functions a concept adopted from pascal +by gcc not used in ansi C or C++ ( although quite useful ), basically it +is a pointer used to reference local variables of enclosing functions. +You might come across this stuff once or twice in your lifetime. + +e.g. +The function below should return 11 though gcc may get upset & toss warnings +about unused variables. +int FunctionA(int a) +{ + int b; + FunctionC(int c) + { + b=c+1; + } + FunctionC(10); + return(b); +} + + +s/390 & zSeries Register usage +============================== +r0 used by syscalls/assembly call-clobbered +r1 used by syscalls/assembly call-clobbered +r2 argument 0 / return value 0 call-clobbered +r3 argument 1 / return value 1 (if long long) call-clobbered +r4 argument 2 call-clobbered +r5 argument 3 call-clobbered +r6 argument 5 saved +r7 pointer-to arguments 5 to ... saved +r8 this & that saved +r9 this & that saved +r10 static-chain ( if nested function ) saved +r11 frame-pointer ( if function used alloca ) saved +r12 got-pointer saved +r13 base-pointer saved +r14 return-address saved +r15 stack-pointer saved + +f0 argument 0 / return value ( float/double ) call-clobbered +f2 argument 1 call-clobbered +f4 zSeries argument 2 saved +f6 zSeries argument 3 saved +The remaining floating points +f1,f3,f5 f7-f15 are call-clobbered. + +Notes: +------ +1) The only requirement is that registers which are used +by the callee are saved, e.g. the compiler is perfectly +capible of using r11 for purposes other than a frame a +frame pointer if a frame pointer is not needed. +2) In functions with variable arguments e.g. printf the calling procedure +is identical to one without variable arguments & the same number of +parameters. However, the prologue of this function is somewhat more +hairy owing to it having to move these parameters to the stack to +get va_start, va_arg & va_end to work. +3) Access registers are currently unused by gcc but are used in +the kernel. Possibilities exist to use them at the moment for +temporary storage but it isn't recommended. +4) Only 4 of the floating point registers are used for +parameter passing as older machines such as G3 only have only 4 +& it keeps the stack frame compatible with other compilers. +However with IEEE floating point emulation under linux on the +older machines you are free to use the other 12. +5) A long long or double parameter cannot be have the +first 4 bytes in a register & the second four bytes in the +outgoing args area. It must be purely in the outgoing args +area if crossing this boundary. +6) Floating point parameters are mixed with outgoing args +on the outgoing args area in the order the are passed in as parameters. +7) Floating point arguments 2 & 3 are saved in the outgoing args area for zSeries + + +Stack Frame Layout +------------------ +s/390 zSeries +0 0 back chain ( a 0 here signifies end of back chain ) +4 8 eos ( end of stack, not used on Linux for S390 used in other linkage formats ) +8 16 glue used in other s/390 linkage formats for saved routine descriptors etc. +12 24 glue used in other s/390 linkage formats for saved routine descriptors etc. +16 32 scratch area +20 40 scratch area +24 48 saved r6 of caller function +28 56 saved r7 of caller function +32 64 saved r8 of caller function +36 72 saved r9 of caller function +40 80 saved r10 of caller function +44 88 saved r11 of caller function +48 96 saved r12 of caller function +52 104 saved r13 of caller function +56 112 saved r14 of caller function +60 120 saved r15 of caller function +64 128 saved f4 of caller function +72 132 saved f6 of caller function +80 undefined +96 160 outgoing args passed from caller to callee +96+x 160+x possible stack alignment ( 8 bytes desirable ) +96+x+y 160+x+y alloca space of caller ( if used ) +96+x+y+z 160+x+y+z automatics of caller ( if used ) +0 back-chain + +A sample program with comments. +=============================== + +Comments on the function test +----------------------------- +1) It didn't need to set up a pointer to the constant pool gpr13 as it isn't used +( :-( ). +2) This is a frameless function & no stack is bought. +3) The compiler was clever enough to recognise that it could return the +value in r2 as well as use it for the passed in parameter ( :-) ). +4) The basr ( branch relative & save ) trick works as follows the instruction +has a special case with r0,r0 with some instruction operands is understood as +the literal value 0, some risc architectures also do this ). So now +we are branching to the next address & the address new program counter is +in r13,so now we subtract the size of the function prologue we have executed ++ the size of the literal pool to get to the top of the literal pool +0040037c int test(int b) +{ # Function prologue below + 40037c: 90 de f0 34 stm %r13,%r14,52(%r15) # Save registers r13 & r14 + 400380: 0d d0 basr %r13,%r0 # Set up pointer to constant pool using + 400382: a7 da ff fa ahi %r13,-6 # basr trick + return(5+b); + # Huge main program + 400386: a7 2a 00 05 ahi %r2,5 # add 5 to r2 + + # Function epilogue below + 40038a: 98 de f0 34 lm %r13,%r14,52(%r15) # restore registers r13 & 14 + 40038e: 07 fe br %r14 # return +} + +Comments on the function main +----------------------------- +1) The compiler did this function optimally ( 8-) ) + +Literal pool for main. +400390: ff ff ff ec .long 0xffffffec +main(int argc,char *argv[]) +{ # Function prologue below + 400394: 90 bf f0 2c stm %r11,%r15,44(%r15) # Save necessary registers + 400398: 18 0f lr %r0,%r15 # copy stack pointer to r0 + 40039a: a7 fa ff a0 ahi %r15,-96 # Make area for callee saving + 40039e: 0d d0 basr %r13,%r0 # Set up r13 to point to + 4003a0: a7 da ff f0 ahi %r13,-16 # literal pool + 4003a4: 50 00 f0 00 st %r0,0(%r15) # Save backchain + + return(test(5)); # Main Program Below + 4003a8: 58 e0 d0 00 l %r14,0(%r13) # load relative address of test from + # literal pool + 4003ac: a7 28 00 05 lhi %r2,5 # Set first parameter to 5 + 4003b0: 4d ee d0 00 bas %r14,0(%r14,%r13) # jump to test setting r14 as return + # address using branch & save instruction. + + # Function Epilogue below + 4003b4: 98 bf f0 8c lm %r11,%r15,140(%r15)# Restore necessary registers. + 4003b8: 07 fe br %r14 # return to do program exit +} + + +Compiler updates +---------------- + +main(int argc,char *argv[]) +{ + 4004fc: 90 7f f0 1c stm %r7,%r15,28(%r15) + 400500: a7 d5 00 04 bras %r13,400508 <main+0xc> + 400504: 00 40 04 f4 .long 0x004004f4 + # compiler now puts constant pool in code to so it saves an instruction + 400508: 18 0f lr %r0,%r15 + 40050a: a7 fa ff a0 ahi %r15,-96 + 40050e: 50 00 f0 00 st %r0,0(%r15) + return(test(5)); + 400512: 58 10 d0 00 l %r1,0(%r13) + 400516: a7 28 00 05 lhi %r2,5 + 40051a: 0d e1 basr %r14,%r1 + # compiler adds 1 extra instruction to epilogue this is done to + # avoid processor pipeline stalls owing to data dependencies on g5 & + # above as register 14 in the old code was needed directly after being loaded + # by the lm %r11,%r15,140(%r15) for the br %14. + 40051c: 58 40 f0 98 l %r4,152(%r15) + 400520: 98 7f f0 7c lm %r7,%r15,124(%r15) + 400524: 07 f4 br %r4 +} + + +Hartmut ( our compiler developer ) also has been threatening to take out the +stack backchain in optimised code as this also causes pipeline stalls, you +have been warned. + +64 bit zSeries code disassembly +------------------------------- + +If you understand the stuff above you'll understand the stuff +below too so I'll avoid repeating myself & just say that +some of the instructions have g's on the end of them to indicate +they are 64 bit & the stack offsets are a bigger, +the only other difference you'll find between 32 & 64 bit is that +we now use f4 & f6 for floating point arguments on 64 bit. +00000000800005b0 <test>: +int test(int b) +{ + return(5+b); + 800005b0: a7 2a 00 05 ahi %r2,5 + 800005b4: b9 14 00 22 lgfr %r2,%r2 # downcast to integer + 800005b8: 07 fe br %r14 + 800005ba: 07 07 bcr 0,%r7 + + +} + +00000000800005bc <main>: +main(int argc,char *argv[]) +{ + 800005bc: eb bf f0 58 00 24 stmg %r11,%r15,88(%r15) + 800005c2: b9 04 00 1f lgr %r1,%r15 + 800005c6: a7 fb ff 60 aghi %r15,-160 + 800005ca: e3 10 f0 00 00 24 stg %r1,0(%r15) + return(test(5)); + 800005d0: a7 29 00 05 lghi %r2,5 + # brasl allows jumps > 64k & is overkill here bras would do fune + 800005d4: c0 e5 ff ff ff ee brasl %r14,800005b0 <test> + 800005da: e3 40 f1 10 00 04 lg %r4,272(%r15) + 800005e0: eb bf f0 f8 00 04 lmg %r11,%r15,248(%r15) + 800005e6: 07 f4 br %r4 +} + + + +Compiling programs for debugging on Linux for s/390 & zSeries +============================================================= +-gdwarf2 now works & normal -g debugging works much better now +Thanks to the IBM java compiler developers bug reports. + +This is typically done adding/appending the flags -g to the +CFLAGS & LDFLAGS variables Makefile of the program concerned. + +If using gdb & you would like accurate displays of registers & + stack traces compile without optimisation i.e make sure +that there is no -O2 or similar on the CFLAGS line of the Makefile & +the emitted gcc commands, obviously this will produce worse code +( not advisable for shipment ) but it is an aid to the debugging process. + +This aids debugging because the compiler will copy parameters passed in +in registers onto the stack so backtracing & looking at passed in +parameters will work, however some larger programs which use inline functions +will not compile without optimisation. + +Debugging with optimisation has since much improved after fixing +some bugs, please make sure you are using gdb-5.0 or later developed +after Nov'2000. + +Figuring out gcc compile errors +=============================== +If you are getting a lot of syntax errors compiling a program & the problem +isn't blatantly obvious from the source. +It often helps to just preprocess the file, this is done with the -E +option in gcc. +What this does is that it runs through the very first phase of compilation +( compilation in gcc is done in several stages & gcc calls many programs to +achieve its end result ) with the -E option gcc just calls the gcc preprocessor (cpp). +The c preprocessor does the following, it joins all the files #included together +recursively ( #include files can #include other files ) & also the c file you wish to compile. +It puts a fully qualified path of the #included files in a comment & it +does macro expansion. +This is useful for debugging because +1) You can double check whether the files you expect to be included are the ones +that are being included ( e.g. double check that you aren't going to the i386 asm directory ). +2) Check that macro definitions aren't clashing with typedefs, +3) Check that definitons aren't being used before they are being included. +4) Helps put the line emitting the error under the microscope if it contains macros. + +For convenience the Linux kernel's makefile will do preprocessing automatically for you +by suffixing the file you want built with .i ( instead of .o ) + +e.g. +from the linux directory type +make arch/s390/kernel/signal.i +this will build + +s390-gcc -D__KERNEL__ -I/home1/barrow/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer +-fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -E arch/s390/kernel/signal.c +> arch/s390/kernel/signal.i + +Now look at signal.i you should see something like. + + +# 1 "/home1/barrow/linux/include/asm/types.h" 1 +typedef unsigned short umode_t; +typedef __signed__ char __s8; +typedef unsigned char __u8; +typedef __signed__ short __s16; +typedef unsigned short __u16; + +If instead you are getting errors further down e.g. +unknown instruction:2515 "move.l" or better still unknown instruction:2515 +"Fixme not implemented yet, call Martin" you are probably are attempting to compile some code +meant for another architecture or code that is simply not implemented, with a fixme statement +stuck into the inline assembly code so that the author of the file now knows he has work to do. +To look at the assembly emitted by gcc just before it is about to call gas ( the gnu assembler ) +use the -S option. +Again for your convenience the Linux kernel's Makefile will hold your hand & +do all this donkey work for you also by building the file with the .s suffix. +e.g. +from the Linux directory type +make arch/s390/kernel/signal.s + +s390-gcc -D__KERNEL__ -I/home1/barrow/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer +-fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -S arch/s390/kernel/signal.c +-o arch/s390/kernel/signal.s + + +This will output something like, ( please note the constant pool & the useful comments +in the prologue to give you a hand at interpreting it ). + +.LC54: + .string "misaligned (__u16 *) in __xchg\n" +.LC57: + .string "misaligned (__u32 *) in __xchg\n" +.L$PG1: # Pool sys_sigsuspend +.LC192: + .long -262401 +.LC193: + .long -1 +.LC194: + .long schedule-.L$PG1 +.LC195: + .long do_signal-.L$PG1 + .align 4 +.globl sys_sigsuspend + .type sys_sigsuspend,@function +sys_sigsuspend: +# leaf function 0 +# automatics 16 +# outgoing args 0 +# need frame pointer 0 +# call alloca 0 +# has varargs 0 +# incoming args (stack) 0 +# function length 168 + STM 8,15,32(15) + LR 0,15 + AHI 15,-112 + BASR 13,0 +.L$CO1: AHI 13,.L$PG1-.L$CO1 + ST 0,0(15) + LR 8,2 + N 5,.LC192-.L$PG1(13) + +Adding -g to the above output makes the output even more useful +e.g. typing +make CC:="s390-gcc -g" kernel/sched.s + +which compiles. +s390-gcc -g -D__KERNEL__ -I/home/barrow/linux-2.3/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -S kernel/sched.c -o kernel/sched.s + +also outputs stabs ( debugger ) info, from this info you can find out the +offsets & sizes of various elements in structures. +e.g. the stab for the structure +struct rlimit { + unsigned long rlim_cur; + unsigned long rlim_max; +}; +is +.stabs "rlimit:T(151,2)=s8rlim_cur:(0,5),0,32;rlim_max:(0,5),32,32;;",128,0,0,0 +from this stab you can see that +rlimit_cur starts at bit offset 0 & is 32 bits in size +rlimit_max starts at bit offset 32 & is 32 bits in size. + + +Debugging Tools: +================ + +objdump +======= +This is a tool with many options the most useful being ( if compiled with -g). +objdump --source <victim program or object file> > <victims debug listing > + + +The whole kernel can be compiled like this ( Doing this will make a 17MB kernel +& a 200 MB listing ) however you have to strip it before building the image +using the strip command to make it a more reasonable size to boot it. + +A source/assembly mixed dump of the kernel can be done with the line +objdump --source vmlinux > vmlinux.lst +Also if the file isn't compiled -g this will output as much debugging information +as it can ( e.g. function names ), however, this is very slow as it spends lots +of time searching for debugging info, the following self explanitory line should be used +instead if the code isn't compiled -g. +objdump --disassemble-all --syms vmlinux > vmlinux.lst +as it is much faster + +As hard drive space is valuble most of us use the following approach. +1) Look at the emitted psw on the console to find the crash address in the kernel. +2) Look at the file System.map ( in the linux directory ) produced when building +the kernel to find the closest address less than the current PSW to find the +offending function. +3) use grep or similar to search the source tree looking for the source file + with this function if you don't know where it is. +4) rebuild this object file with -g on, as an example suppose the file was +( /arch/s390/kernel/signal.o ) +5) Assuming the file with the erroneous function is signal.c Move to the base of the +Linux source tree. +6) rm /arch/s390/kernel/signal.o +7) make /arch/s390/kernel/signal.o +8) watch the gcc command line emitted +9) type it in again or alernatively cut & paste it on the console adding the -g option. +10) objdump --source arch/s390/kernel/signal.o > signal.lst +This will output the source & the assembly intermixed, as the snippet below shows +This will unfortunately output addresses which aren't the same +as the kernel ones you should be able to get around the mental arithmetic +by playing with the --adjust-vma parameter to objdump. + + + + +extern inline void spin_lock(spinlock_t *lp) +{ + a0: 18 34 lr %r3,%r4 + a2: a7 3a 03 bc ahi %r3,956 + __asm__ __volatile(" lhi 1,-1\n" + a6: a7 18 ff ff lhi %r1,-1 + aa: 1f 00 slr %r0,%r0 + ac: ba 01 30 00 cs %r0,%r1,0(%r3) + b0: a7 44 ff fd jm aa <sys_sigsuspend+0x2e> + saveset = current->blocked; + b4: d2 07 f0 68 mvc 104(8,%r15),972(%r4) + b8: 43 cc + return (set->sig[0] & mask) != 0; +} + +6) If debugging under VM go down to that section in the document for more info. + + +I now have a tool which takes the pain out of --adjust-vma +& you are able to do something like +make /arch/s390/kernel/traps.lst +& it automatically generates the correctly relocated entries for +the text segment in traps.lst. +This tool is now standard in linux distro's in scripts/makelst + +strace: +------- +Q. What is it ? +A. It is a tool for intercepting calls to the kernel & logging them +to a file & on the screen. + +Q. What use is it ? +A. You can used it to find out what files a particular program opens. + + + +Example 1 +--------- +If you wanted to know does ping work but didn't have the source +strace ping -c 1 127.0.0.1 +& then look at the man pages for each of the syscalls below, +( In fact this is sometimes easier than looking at some spagetti +source which conditionally compiles for several architectures ) +Not everything that it throws out needs to make sense immeadiately + +Just looking quickly you can see that it is making up a RAW socket +for the ICMP protocol. +Doing an alarm(10) for a 10 second timeout +& doing a gettimeofday call before & after each read to see +how long the replies took, & writing some text to stdout so the user +has an idea what is going on. + +socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 3 +getuid() = 0 +setuid(0) = 0 +stat("/usr/share/locale/C/libc.cat", 0xbffff134) = -1 ENOENT (No such file or directory) +stat("/usr/share/locale/libc/C", 0xbffff134) = -1 ENOENT (No such file or directory) +stat("/usr/local/share/locale/C/libc.cat", 0xbffff134) = -1 ENOENT (No such file or directory) +getpid() = 353 +setsockopt(3, SOL_SOCKET, SO_BROADCAST, [1], 4) = 0 +setsockopt(3, SOL_SOCKET, SO_RCVBUF, [49152], 4) = 0 +fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(3, 1), ...}) = 0 +mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40008000 +ioctl(1, TCGETS, {B9600 opost isig icanon echo ...}) = 0 +write(1, "PING 127.0.0.1 (127.0.0.1): 56 d"..., 42PING 127.0.0.1 (127.0.0.1): 56 data bytes +) = 42 +sigaction(SIGINT, {0x8049ba0, [], SA_RESTART}, {SIG_DFL}) = 0 +sigaction(SIGALRM, {0x8049600, [], SA_RESTART}, {SIG_DFL}) = 0 +gettimeofday({948904719, 138951}, NULL) = 0 +sendto(3, "\10\0D\201a\1\0\0\17#\2178\307\36"..., 64, 0, {sin_family=AF_INET, +sin_port=htons(0), sin_addr=inet_addr("127.0.0.1")}, 16) = 64 +sigaction(SIGALRM, {0x8049600, [], SA_RESTART}, {0x8049600, [], SA_RESTART}) = 0 +sigaction(SIGALRM, {0x8049ba0, [], SA_RESTART}, {0x8049600, [], SA_RESTART}) = 0 +alarm(10) = 0 +recvfrom(3, "E\0\0T\0005\0\0@\1|r\177\0\0\1\177"..., 192, 0, +{sin_family=AF_INET, sin_port=htons(50882), sin_addr=inet_addr("127.0.0.1")}, [16]) = 84 +gettimeofday({948904719, 160224}, NULL) = 0 +recvfrom(3, "E\0\0T\0006\0\0\377\1\275p\177\0"..., 192, 0, +{sin_family=AF_INET, sin_port=htons(50882), sin_addr=inet_addr("127.0.0.1")}, [16]) = 84 +gettimeofday({948904719, 166952}, NULL) = 0 +write(1, "64 bytes from 127.0.0.1: icmp_se"..., +5764 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=28.0 ms + +Example 2 +--------- +strace passwd 2>&1 | grep open +produces the following output +open("/etc/ld.so.cache", O_RDONLY) = 3 +open("/opt/kde/lib/libc.so.5", O_RDONLY) = -1 ENOENT (No such file or directory) +open("/lib/libc.so.5", O_RDONLY) = 3 +open("/dev", O_RDONLY) = 3 +open("/var/run/utmp", O_RDONLY) = 3 +open("/etc/passwd", O_RDONLY) = 3 +open("/etc/shadow", O_RDONLY) = 3 +open("/etc/login.defs", O_RDONLY) = 4 +open("/dev/tty", O_RDONLY) = 4 + +The 2>&1 is done to redirect stderr to stdout & grep is then filtering this input +through the pipe for each line containing the string open. + + +Example 3 +--------- +Getting sophistocated +telnetd crashes on & I don't know why +Steps +----- +1) Replace the following line in /etc/inetd.conf +telnet stream tcp nowait root /usr/sbin/in.telnetd -h +with +telnet stream tcp nowait root /blah + +2) Create the file /blah with the following contents to start tracing telnetd +#!/bin/bash +/usr/bin/strace -o/t1 -f /usr/sbin/in.telnetd -h +3) chmod 700 /blah to make it executable only to root +4) +killall -HUP inetd +or ps aux | grep inetd +get inetd's process id +& kill -HUP inetd to restart it. + +Important options +----------------- +-o is used to tell strace to output to a file in our case t1 in the root directory +-f is to follow children i.e. +e.g in our case above telnetd will start the login process & subsequently a shell like bash. +You will be able to tell which is which from the process ID's listed on the left hand side +of the strace output. +-p<pid> will tell strace to attach to a running process, yup this can be done provided + it isn't being traced or debugged already & you have enough privileges, +the reason 2 processes cannot trace or debug the same program is that strace +becomes the parent process of the one being debugged & processes ( unlike people ) +can have only one parent. + + +However the file /t1 will get big quite quickly +to test it telnet 127.0.0.1 + +now look at what files in.telnetd execve'd +413 execve("/usr/sbin/in.telnetd", ["/usr/sbin/in.telnetd", "-h"], [/* 17 vars */]) = 0 +414 execve("/bin/login", ["/bin/login", "-h", "localhost", "-p"], [/* 2 vars */]) = 0 + +Whey it worked!. + + +Other hints: +------------ +If the program is not very interactive ( i.e. not much keyboard input ) +& is crashing in one architecture but not in another you can do +an strace of both programs under as identical a scenario as you can +on both architectures outputting to a file then. +do a diff of the two traces using the diff program +i.e. +diff output1 output2 +& maybe you'll be able to see where the call paths differed, this +is possibly near the cause of the crash. + +More info +--------- +Look at man pages for strace & the various syscalls +e.g. man strace, man alarm, man socket. + + +Performance Debugging +===================== +gcc is capible of compiling in profiling code just add the -p option +to the CFLAGS, this obviously affects program size & performance. +This can be used by the gprof gnu profiling tool or the +gcov the gnu code coverage tool ( code coverage is a means of testing +code quality by checking if all the code in an executable in exercised by +a tester ). + + +Using top to find out where processes are sleeping in the kernel +---------------------------------------------------------------- +To do this copy the System.map from the root directory where +the linux kernel was built to the /boot directory on your +linux machine. +Start top +Now type fU<return> +You should see a new field called WCHAN which +tells you where each process is sleeping here is a typical output. + + 6:59pm up 41 min, 1 user, load average: 0.00, 0.00, 0.00 +28 processes: 27 sleeping, 1 running, 0 zombie, 0 stopped +CPU states: 0.0% user, 0.1% system, 0.0% nice, 99.8% idle +Mem: 254900K av, 45976K used, 208924K free, 0K shrd, 28636K buff +Swap: 0K av, 0K used, 0K free 8620K cached + + PID USER PRI NI SIZE RSS SHARE WCHAN STAT LIB %CPU %MEM TIME COMMAND + 750 root 12 0 848 848 700 do_select S 0 0.1 0.3 0:00 in.telnetd + 767 root 16 0 1140 1140 964 R 0 0.1 0.4 0:00 top + 1 root 8 0 212 212 180 do_select S 0 0.0 0.0 0:00 init + 2 root 9 0 0 0 0 down_inte SW 0 0.0 0.0 0:00 kmcheck + +The time command +---------------- +Another related command is the time command which gives you an indication +of where a process is spending the majority of its time. +e.g. +time ping -c 5 nc +outputs +real 0m4.054s +user 0m0.010s +sys 0m0.010s + +Debugging under VM +================== + +Notes +----- +Addresses & values in the VM debugger are always hex never decimal +Address ranges are of the format <HexValue1>-<HexValue2> or <HexValue1>.<HexValue2> +e.g. The address range 0x2000 to 0x3000 can be described described as +2000-3000 or 2000.1000 + +The VM Debugger is case insensitive. + +VM's strengths are usually other debuggers weaknesses you can get at any resource +no matter how sensitive e.g. memory managment resources,change address translation +in the PSW. For kernel hacking you will reap dividends if you get good at it. + +The VM Debugger displays operators but not operands, probably because some +of it was written when memory was expensive & the programmer was probably proud that +it fitted into 2k of memory & the programmers & didn't want to shock hardcore VM'ers by +changing the interface :-), also the debugger displays useful information on the same line & +the author of the code probably felt that it was a good idea not to go over +the 80 columns on the screen. + +As some of you are probably in a panic now this isn't as unintuitive as it may seem +as the 390 instructions are easy to decode mentally & you can make a good guess at a lot +of them as all the operands are nibble ( half byte aligned ) & if you have an objdump listing +also it is quite easy to follow, if you don't have an objdump listing keep a copy of +the s/390 Reference Summary & look at between pages 2 & 7 or alternatively the +s/390 principles of operation. +e.g. even I can guess that +0001AFF8' LR 180F CC 0 +is a ( load register ) lr r0,r15 + +Also it is very easy to tell the length of a 390 instruction from the 2 most significant +bits in the instruction ( not that this info is really useful except if you are trying to +make sense of a hexdump of code ). +Here is a table +Bits Instruction Length +------------------------------------------ +00 2 Bytes +01 4 Bytes +10 4 Bytes +11 6 Bytes + + + + +The debugger also displays other useful info on the same line such as the +addresses being operated on destination addresses of branches & condition codes. +e.g. +00019736' AHI A7DAFF0E CC 1 +000198BA' BRC A7840004 -> 000198C2' CC 0 +000198CE' STM 900EF068 >> 0FA95E78 CC 2 + + + +Useful VM debugger commands +--------------------------- + +I suppose I'd better mention this before I start +to list the current active traces do +Q TR +there can be a maximum of 255 of these per set +( more about trace sets later ). +To stop traces issue a +TR END. +To delete a particular breakpoint issue +TR DEL <breakpoint number> + +The PA1 key drops to CP mode so you can issue debugger commands, +Doing alt c (on my 3270 console at least ) clears the screen. +hitting b <enter> comes back to the running operating system +from cp mode ( in our case linux ). +It is typically useful to add shortcuts to your profile.exec file +if you have one ( this is roughly equivalent to autoexec.bat in DOS ). +file here are a few from mine. +/* this gives me command history on issuing f12 */ +set pf12 retrieve +/* this continues */ +set pf8 imm b +/* goes to trace set a */ +set pf1 imm tr goto a +/* goes to trace set b */ +set pf2 imm tr goto b +/* goes to trace set c */ +set pf3 imm tr goto c + + + +Instruction Tracing +------------------- +Setting a simple breakpoint +TR I PSWA <address> +To debug a particular function try +TR I R <function address range> +TR I on its own will single step. +TR I DATA <MNEMONIC> <OPTIONAL RANGE> will trace for particular mnemonics +e.g. +TR I DATA 4D R 0197BC.4000 +will trace for BAS'es ( opcode 4D ) in the range 0197BC.4000 +if you were inclined you could add traces for all branch instructions & +suffix them with the run prefix so you would have a backtrace on screen +when a program crashes. +TR BR <INTO OR FROM> will trace branches into or out of an address. +e.g. +TR BR INTO 0 is often quite useful if a program is getting awkward & deciding +to branch to 0 & crashing as this will stop at the address before in jumps to 0. +TR I R <address range> RUN cmd d g +single steps a range of addresses but stays running & +displays the gprs on each step. + + + +Displaying & modifying Registers +-------------------------------- +D G will display all the gprs +Adding a extra G to all the commands is neccessary to access the full 64 bit +content in VM on zSeries obviously this isn't required for access registers +as these are still 32 bit. +e.g. DGG instead of DG +D X will display all the control registers +D AR will display all the access registers +D AR4-7 will display access registers 4 to 7 +CPU ALL D G will display the GRPS of all CPUS in the configuration +D PSW will display the current PSW +st PSW 2000 will put the value 2000 into the PSW & +cause crash your machine. +D PREFIX displays the prefix offset + + +Displaying Memory +----------------- +To display memory mapped using the current PSW's mapping try +D <range> +To make VM display a message each time it hits a particular address & continue try +D I<range> will disassemble/display a range of instructions. +ST addr 32 bit word will store a 32 bit aligned address +D T<range> will display the EBCDIC in an address ( if you are that way inclined ) +D R<range> will display real addresses ( without DAT ) but with prefixing. +There are other complex options to display if you need to get at say home space +but are in primary space the easiest thing to do is to temporarily +modify the PSW to the other addressing mode, display the stuff & then +restore it. + + + +Hints +----- +If you want to issue a debugger command without halting your virtual machine with the +PA1 key try prefixing the command with #CP e.g. +#cp tr i pswa 2000 +also suffixing most debugger commands with RUN will cause them not +to stop just display the mnemonic at the current instruction on the console. +If you have several breakpoints you want to put into your program & +you get fed up of cross referencing with System.map +you can do the following trick for several symbols. +grep do_signal System.map +which emits the following among other things +0001f4e0 T do_signal +now you can do + +TR I PSWA 0001f4e0 cmd msg * do_signal +This sends a message to your own console each time do_signal is entered. +( As an aside I wrote a perl script once which automatically generated a REXX +script with breakpoints on every kernel procedure, this isn't a good idea +because there are thousands of these routines & VM can only set 255 breakpoints +at a time so you nearly had to spend as long pruning the file down as you would +entering the msg's by hand ),however, the trick might be useful for a single object file. +On linux'es 3270 emulator x3270 there is a very useful option under the file ment +Save Screens In File this is very good of keeping a copy of traces. + +From CMS help <command name> will give you online help on a particular command. +e.g. +HELP DISPLAY + +Also CP has a file called profile.exec which automatically gets called +on startup of CMS ( like autoexec.bat ), keeping on a DOS analogy session +CP has a feature similar to doskey, it may be useful for you to +use profile.exec to define some keystrokes. +e.g. +SET PF9 IMM B +This does a single step in VM on pressing F8. +SET PF10 ^ +This sets up the ^ key. +which can be used for ^c (ctrl-c),^z (ctrl-z) which can't be typed directly into some 3270 consoles. +SET PF11 ^- +This types the starting keystrokes for a sysrq see SysRq below. +SET PF12 RETRIEVE +This retrieves command history on pressing F12. + + +Sometimes in VM the display is set up to scroll automatically this +can be very annoying if there are messages you wish to look at +to stop this do +TERM MORE 255 255 +This will nearly stop automatic screen updates, however it will +cause a denial of service if lots of messages go to the 3270 console, +so it would be foolish to use this as the default on a production machine. + + +Tracing particular processes +---------------------------- +The kernels text segment is intentionally at an address in memory that it will +very seldom collide with text segments of user programs ( thanks Martin ), +this simplifies debugging the kernel. +However it is quite common for user processes to have addresses which collide +this can make debugging a particular process under VM painful under normal +circumstances as the process may change when doing a +TR I R <address range>. +Thankfully after reading VM's online help I figured out how to debug +I particular process. + +Your first problem is to find the STD ( segment table designation ) +of the program you wish to debug. +There are several ways you can do this here are a few +1) objdump --syms <program to be debugged> | grep main +To get the address of main in the program. +tr i pswa <address of main> +Start the program, if VM drops to CP on what looks like the entry +point of the main function this is most likely the process you wish to debug. +Now do a D X13 or D XG13 on zSeries. +On 31 bit the STD is bits 1-19 ( the STO segment table origin ) +& 25-31 ( the STL segment table length ) of CR13. +now type +TR I R STD <CR13's value> 0.7fffffff +e.g. +TR I R STD 8F32E1FF 0.7fffffff +Another very useful variation is +TR STORE INTO STD <CR13's value> <address range> + + + + +Tracing Program Exceptions +-------------------------- +If you get a crash which says something like +illegal operation or specification exception followed by a register dump +You can restart linux & trace these using the tr prog <range or value> trace option. + + + +The most common ones you will normally be tracing for is +1=operation exception +2=privileged operation exception +4=protection exception +5=addressing exception +6=specification exception +10=segment translation exception +11=page translation exception + +The full list of these is on page 22 of the current s/390 Reference Summary. +e.g. +tr prog 10 will trace segment translation exceptions. +tr prog on its own will trace all program interruption codes. + +Trace Sets +---------- +On starting VM you are initially in the INITIAL trace set. +You can do a Q TR to verify this. +If you have a complex tracing situation where you wish to wait for instance +till a driver is open before you start tracing IO, but know in your +heart that you are going to have to make several runs through the code till you +have a clue whats going on. + +What you can do is +TR I PSWA <Driver open address> +hit b to continue till breakpoint +reach the breakpoint +now do your +TR GOTO B +TR IO 7c08-7c09 inst int run +or whatever the IO channels you wish to trace are & hit b + +To got back to the initial trace set do +TR GOTO INITIAL +& the TR I PSWA <Driver open address> will be the only active breakpoint again. + + +Tracing linux syscalls under VM +------------------------------- +Syscalls are implemented on Linux for S390 by the Supervisor call instruction (SVC) there 256 +possibilities of these as the instruction is made up of a 0xA opcode & the second byte being +the syscall number. They are traced using the simple command. +TR SVC <Optional value or range> +the syscalls are defined in linux/include/asm-s390/unistd.h +e.g. to trace all file opens just do +TR SVC 5 ( as this is the syscall number of open ) + + +SMP Specific commands +--------------------- +To find out how many cpus you have +Q CPUS displays all the CPU's available to your virtual machine +To find the cpu that the current cpu VM debugger commands are being directed at do +Q CPU to change the current cpu cpu VM debugger commands are being directed at do +CPU <desired cpu no> + +On a SMP guest issue a command to all CPUs try prefixing the command with cpu all. +To issue a command to a particular cpu try cpu <cpu number> e.g. +CPU 01 TR I R 2000.3000 +If you are running on a guest with several cpus & you have a IO related problem +& cannot follow the flow of code but you know it isnt smp related. +from the bash prompt issue +shutdown -h now or halt. +do a Q CPUS to find out how many cpus you have +detach each one of them from cp except cpu 0 +by issueing a +DETACH CPU 01-(number of cpus in configuration) +& boot linux again. +TR SIGP will trace inter processor signal processor instructions. +DEFINE CPU 01-(number in configuration) +will get your guests cpus back. + + +Help for displaying ascii textstrings +------------------------------------- +As textstrings are cannot be displayed in ASCII under the VM debugger ( I love EBDIC too ) I have +written this little program which will convert a command line of hex digits to ascii text +which can be compiled under linux & you can copy the hex digits from your x3270 terminal to +your xterm if you are debugging from a linuxbox. + +This is quite useful when looking at a parameter passed in as a text string +under VM ( unless you are good at decoding ASCII in your head ). + +e.g. consider tracing an open syscall +TR SVC 5 +We have stopped at a breakpoint +000151B0' SVC 0A05 -> 0001909A' CC 0 + +D 20.8 to check the SVC old psw in the prefix area & see was it from userspace +( for the layout of the prefix area consult P18 of the s/390 390 Reference Summary +if you have it available ). +V00000020 070C2000 800151B2 +The problem state bit wasn't set & it's also too early in the boot sequence +for it to be a userspace SVC if it was we would have to temporarily switch the +psw to user space addressing so we could get at the first parameter of the open in +gpr2. +Next do a +D G2 +GPR 2 = 00014CB4 +Now display what gpr2 is pointing to +D 00014CB4.20 +V00014CB4 2F646576 2F636F6E 736F6C65 00001BF5 +V00014CC4 FC00014C B4001001 E0001000 B8070707 +Now copy the text till the first 00 hex ( which is the end of the string +to an xterm & do hex2ascii on it. +hex2ascii 2F646576 2F636F6E 736F6C65 00 +outputs +Decoded Hex:=/ d e v / c o n s o l e 0x00 +We were opening the console device, + +You can compile the code below yourself for practice :-), +/* + * hex2ascii.c + * a useful little tool for converting a hexadecimal command line to ascii + * + * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) + * (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation. + */ +#include <stdio.h> + +int main(int argc,char *argv[]) +{ + int cnt1,cnt2,len,toggle=0; + int startcnt=1; + unsigned char c,hex; + + if(argc>1&&(strcmp(argv[1],"-a")==0)) + startcnt=2; + printf("Decoded Hex:="); + for(cnt1=startcnt;cnt1<argc;cnt1++) + { + len=strlen(argv[cnt1]); + for(cnt2=0;cnt2<len;cnt2++) + { + c=argv[cnt1][cnt2]; + if(c>='0'&&c<='9') + c=c-'0'; + if(c>='A'&&c<='F') + c=c-'A'+10; + if(c>='a'&&c<='F') + c=c-'a'+10; + switch(toggle) + { + case 0: + hex=c<<4; + toggle=1; + break; + case 1: + hex+=c; + if(hex<32||hex>127) + { + if(startcnt==1) + printf("0x%02X ",(int)hex); + else + printf("."); + } + else + { + printf("%c",hex); + if(startcnt==1) + printf(" "); + } + toggle=0; + break; + } + } + } + printf("\n"); +} + + + + +Stack tracing under VM +---------------------- +A basic backtrace +----------------- + +Here are the tricks I use 9 out of 10 times it works pretty well, + +When your backchain reaches a dead end +-------------------------------------- +This can happen when an exception happens in the kernel & the kernel is entered twice +if you reach the NULL pointer at the end of the back chain you should be +able to sniff further back if you follow the following tricks. +1) A kernel address should be easy to recognise since it is in +primary space & the problem state bit isn't set & also +The Hi bit of the address is set. +2) Another backchain should also be easy to recognise since it is an +address pointing to another address approximately 100 bytes or 0x70 hex +behind the current stackpointer. + + +Here is some practice. +boot the kernel & hit PA1 at some random time +d g to display the gprs, this should display something like +GPR 0 = 00000001 00156018 0014359C 00000000 +GPR 4 = 00000001 001B8888 000003E0 00000000 +GPR 8 = 00100080 00100084 00000000 000FE000 +GPR 12 = 00010400 8001B2DC 8001B36A 000FFED8 +Note that GPR14 is a return address but as we are real men we are going to +trace the stack. +display 0x40 bytes after the stack pointer. + +V000FFED8 000FFF38 8001B838 80014C8E 000FFF38 +V000FFEE8 00000000 00000000 000003E0 00000000 +V000FFEF8 00100080 00100084 00000000 000FE000 +V000FFF08 00010400 8001B2DC 8001B36A 000FFED8 + + +Ah now look at whats in sp+56 (sp+0x38) this is 8001B36A our saved r14 if +you look above at our stackframe & also agrees with GPR14. + +now backchain +d 000FFF38.40 +we now are taking the contents of SP to get our first backchain. + +V000FFF38 000FFFA0 00000000 00014995 00147094 +V000FFF48 00147090 001470A0 000003E0 00000000 +V000FFF58 00100080 00100084 00000000 001BF1D0 +V000FFF68 00010400 800149BA 80014CA6 000FFF38 + +This displays a 2nd return address of 80014CA6 + +now do d 000FFFA0.40 for our 3rd backchain + +V000FFFA0 04B52002 0001107F 00000000 00000000 +V000FFFB0 00000000 00000000 FF000000 0001107F +V000FFFC0 00000000 00000000 00000000 00000000 +V000FFFD0 00010400 80010802 8001085A 000FFFA0 + + +our 3rd return address is 8001085A + +as the 04B52002 looks suspiciously like rubbish it is fair to assume that the kernel entry routines +for the sake of optimisation dont set up a backchain. + +now look at System.map to see if the addresses make any sense. + +grep -i 0001b3 System.map +outputs among other things +0001b304 T cpu_idle +so 8001B36A +is cpu_idle+0x66 ( quiet the cpu is asleep, don't wake it ) + + +grep -i 00014 System.map +produces among other things +00014a78 T start_kernel +so 0014CA6 is start_kernel+some hex number I can't add in my head. + +grep -i 00108 System.map +this produces +00010800 T _stext +so 8001085A is _stext+0x5a + +Congrats you've done your first backchain. + + + +s/390 & zSeries IO Overview +=========================== + +I am not going to give a course in 390 IO architecture as this would take me quite a +while & I'm no expert. Instead I'll give a 390 IO architecture summary for Dummies if you have +the s/390 principles of operation available read this instead. If nothing else you may find a few +useful keywords in here & be able to use them on a web search engine like altavista to find +more useful information. + +Unlike other bus architectures modern 390 systems do their IO using mostly +fibre optics & devices such as tapes & disks can be shared between several mainframes, +also S390 can support upto 65536 devices while a high end PC based system might be choking +with around 64. Here is some of the common IO terminology + +Subchannel: +This is the logical number most IO commands use to talk to an IO device there can be upto +0x10000 (65536) of these in a configuration typically there is a few hundred. Under VM +for simplicity they are allocated contiguously, however on the native hardware they are not +they typically stay consistent between boots provided no new hardware is inserted or removed. +Under Linux for 390 we use these as IRQ's & also when issuing an IO command (CLEAR SUBCHANNEL, +HALT SUBCHANNEL,MODIFY SUBCHANNEL,RESUME SUBCHANNEL,START SUBCHANNEL,STORE SUBCHANNEL & +TEST SUBCHANNEL ) we use this as the ID of the device we wish to talk to, the most +important of these instructions are START SUBCHANNEL ( to start IO ), TEST SUBCHANNEL ( to check +whether the IO completed successfully ), & HALT SUBCHANNEL ( to kill IO ), a subchannel +can have up to 8 channel paths to a device this offers redunancy if one is not available. + + +Device Number: +This number remains static & Is closely tied to the hardware, there are 65536 of these +also they are made up of a CHPID ( Channel Path ID, the most significant 8 bits ) +& another lsb 8 bits. These remain static even if more devices are inserted or removed +from the hardware, there is a 1 to 1 mapping between Subchannels & Device Numbers provided +devices arent inserted or removed. + +Channel Control Words: +CCWS are linked lists of instructions initially pointed to by an operation request block (ORB), +which is initially given to Start Subchannel (SSCH) command along with the subchannel number +for the IO subsystem to process while the CPU continues executing normal code. +These come in two flavours, Format 0 ( 24 bit for backward ) +compatibility & Format 1 ( 31 bit ). These are typically used to issue read & write +( & many other instructions ) they consist of a length field & an absolute address field. +For each IO typically get 1 or 2 interrupts one for channel end ( primary status ) when the +channel is idle & the second for device end ( secondary status ) sometimes you get both +concurrently, you check how the IO went on by issueing a TEST SUBCHANNEL at each interrupt, +from which you receive an Interruption response block (IRB). If you get channel & device end +status in the IRB without channel checks etc. your IO probably went okay. If you didn't you +probably need a doctorto examine the IRB & extended status word etc. +If an error occurs more sophistocated control units have a facitity known as +concurrent sense this means that if an error occurs Extended sense information will +be presented in the Extended status word in the IRB if not you have to issue a +subsequent SENSE CCW command after the test subchannel. + + +TPI( Test pending interrupt) can also be used for polled IO but in multitasking multiprocessor +systems it isn't recommended except for checking special cases ( i.e. non looping checks for +pending IO etc. ). + +Store Subchannel & Modify Subchannel can be used to examine & modify operating characteristics +of a subchannel ( e.g. channel paths ). + +Other IO related Terms: +Sysplex: S390's Clustering Technology +QDIO: S390's new high speed IO architecture to support devices such as gigabit ethernet, +this architecture is also designed to be forward compatible with up & coming 64 bit machines. + + +General Concepts + +Input Output Processors (IOP's) are responsible for communicating between +the mainframe CPU's & the channel & relieve the mainframe CPU's from the +burden of communicating with IO devices directly, this allows the CPU's to +concentrate on data processing. + +IOP's can use one or more links ( known as channel paths ) to talk to each +IO device. It first checks for path availability & chooses an available one, +then starts ( & sometimes terminates IO ). +There are two types of channel path ESCON & the Paralell IO interface. + +IO devices are attached to control units, control units provide the +logic to interface the channel paths & channel path IO protocols to +the IO devices, they can be integrated with the devices or housed separately +& often talk to several similar devices ( typical examples would be raid +controllers or a control unit which connects to 1000 3270 terminals ). + + + +---------------------------------------------------------------+ + | +-----+ +-----+ +-----+ +-----+ +----------+ +----------+ | + | | CPU | | CPU | | CPU | | CPU | | Main | | Expanded | | + | | | | | | | | | | Memory | | Storage | | + | +-----+ +-----+ +-----+ +-----+ +----------+ +----------+ | + |---------------------------------------------------------------+ + | IOP | IOP | IOP | + |--------------------------------------------------------------- + | C | C | C | C | C | C | C | C | C | C | C | C | C | C | C | C | + ---------------------------------------------------------------- + || || + || Bus & Tag Channel Path || ESCON + || ====================== || Channel + || || || || Path + +----------+ +----------+ +----------+ + | | | | | | + | CU | | CU | | CU | + | | | | | | + +----------+ +----------+ +----------+ + | | | | | ++----------+ +----------+ +----------+ +----------+ +----------+ +|I/O Device| |I/O Device| |I/O Device| |I/O Device| |I/O Device| ++----------+ +----------+ +----------+ +----------+ +----------+ + CPU = Central Processing Unit + C = Channel + IOP = IP Processor + CU = Control Unit + +The 390 IO systems come in 2 flavours the current 390 machines support both + +The Older 360 & 370 Interface,sometimes called the paralell I/O interface, +sometimes called Bus-and Tag & sometimes Original Equipment Manufacturers +Interface (OEMI). + +This byte wide paralell channel path/bus has parity & data on the "Bus" cable +& control lines on the "Tag" cable. These can operate in byte multiplex mode for +sharing between several slow devices or burst mode & monopolize the channel for the +whole burst. Upto 256 devices can be addressed on one of these cables. These cables are +about one inch in diameter. The maximum unextended length supported by these cables is +125 Meters but this can be extended up to 2km with a fibre optic channel extended +such as a 3044. The maximum burst speed supported is 4.5 megabytes per second however +some really old processors support only transfer rates of 3.0, 2.0 & 1.0 MB/sec. +One of these paths can be daisy chained to up to 8 control units. + + +ESCON if fibre optic it is also called FICON +Was introduced by IBM in 1990. Has 2 fibre optic cables & uses either leds or lasers +for communication at a signaling rate of upto 200 megabits/sec. As 10bits are transferred +for every 8 bits info this drops to 160 megabits/sec & to 18.6 Megabytes/sec once +control info & CRC are added. ESCON only operates in burst mode. + +ESCONs typical max cable length is 3km for the led version & 20km for the laser version +known as XDF ( extended distance facility ). This can be further extended by using an +ESCON director which triples the above mentioned ranges. Unlike Bus & Tag as ESCON is +serial it uses a packet switching architecture the standard Bus & Tag control protocol +is however present within the packets. Upto 256 devices can be attached to each control +unit that uses one of these interfaces. + +Common 390 Devices include: +Network adapters typically OSA2,3172's,2116's & OSA-E gigabit ethernet adapters, +Consoles 3270 & 3215 ( a teletype emulated under linux for a line mode console ). +DASD's direct access storage devices ( otherwise known as hard disks ). +Tape Drives. +CTC ( Channel to Channel Adapters ), +ESCON or Paralell Cables used as a very high speed serial link +between 2 machines. We use 2 cables under linux to do a bi-directional serial link. + + +Debugging IO on s/390 & zSeries under VM +========================================= + +Now we are ready to go on with IO tracing commands under VM + +A few self explanatory queries: +Q OSA +Q CTC +Q DISK +Q DASD + + + + + + +Q OSA on my machine returns +OSA 7C08 ON OSA 7C08 SUBCHANNEL = 0000 +OSA 7C09 ON OSA 7C09 SUBCHANNEL = 0001 +OSA 7C14 ON OSA 7C14 SUBCHANNEL = 0002 +OSA 7C15 ON OSA 7C15 SUBCHANNEL = 0003 + +If you have a guest with certain priviliges you may be able to see devices +which don't belong to you to avoid this do add the option V. +e.g. +Q V OSA + +Now using the device numbers returned by this command we will +Trace the io starting up on the first device 7c08 & 7c09 +In our simplest case we can trace the +start subchannels +like TR SSCH 7C08-7C09 +or the halt subchannels +or TR HSCH 7C08-7C09 +MSCH's ,STSCH's I think you can guess the rest + +Ingo's favourite trick is tracing all the IO's & CCWS & spooling them into the reader of another +VM guest so he can ftp the logfile back to his own machine.I'll do a small bit of this & give you + a look at the output. + +1) Spool stdout to VM reader +SP PRT TO (another vm guest ) or * for the local vm guest +2) Fill the reader with the trace +TR IO 7c08-7c09 INST INT CCW PRT RUN +3) Start up linux +i 00c +4) Finish the trace +TR END +5) close the reader +C PRT +6) list reader contents +RDRLIST +7) copy it to linux4's minidisk +RECEIVE / LOG TXT A1 ( replace +8) +filel & press F11 to look at it +You should see someting like. + +00020942' SSCH B2334000 0048813C CC 0 SCH 0000 DEV 7C08 + CPA 000FFDF0 PARM 00E2C9C4 KEY 0 FPI C0 LPM 80 + CCW 000FFDF0 E4200100 00487FE8 0000 E4240100 ........ + IDAL 43D8AFE8 + IDAL 0FB76000 +00020B0A' I/O DEV 7C08 -> 000197BC' SCH 0000 PARM 00E2C9C4 +00021628' TSCH B2354000 >> 00488164 CC 0 SCH 0000 DEV 7C08 + CCWA 000FFDF8 DEV STS 0C SCH STS 00 CNT 00EC + KEY 0 FPI C0 CC 0 CTLS 4007 +00022238' STSCH B2344000 >> 00488108 CC 0 SCH 0000 DEV 7C08 + +If you don't like messing up your readed ( because you possibly booted from it ) +you can alternatively spool it to another readers guest. + + +Other common VM device related commands +--------------------------------------------- +These commands are listed only because they have +been of use to me in the past & may be of use to +you too. For more complete info on each of the commands +use type HELP <command> from CMS. +detaching devices +DET <devno range> +ATT <devno range> <guest> +attach a device to guest * for your own guest +READY <devno> cause VM to issue a fake interrupt. + +The VARY command is normally only available to VM administrators. +VARY ON PATH <path> TO <devno range> +VARY OFF PATH <PATH> FROM <devno range> +This is used to switch on or off channel paths to devices. + +Q CHPID <channel path ID> +This displays state of devices using this channel path +D SCHIB <subchannel> +This displays the subchannel information SCHIB block for the device. +this I believe is also only available to administrators. +DEFINE CTC <devno> +defines a virtual CTC channel to channel connection +2 need to be defined on each guest for the CTC driver to use. +COUPLE devno userid remote devno +Joins a local virtual device to a remote virtual device +( commonly used for the CTC driver ). + +Building a VM ramdisk under CMS which linux can use +def vfb-<blocksize> <subchannel> <number blocks> +blocksize is commonly 4096 for linux. +Formatting it +format <subchannel> <driver letter e.g. x> (blksize <blocksize> + +Sharing a disk between multiple guests +LINK userid devno1 devno2 mode password + + + +GDB on S390 +=========== +N.B. if compiling for debugging gdb works better without optimisation +( see Compiling programs for debugging ) + +invocation +---------- +gdb <victim program> <optional corefile> + +Online help +----------- +help: gives help on commands +e.g. +help +help display +Note gdb's online help is very good use it. + + +Assembly +-------- +info registers: displays registers other than floating point. +info all-registers: displays floating points as well. +disassemble: dissassembles +e.g. +disassemble without parameters will disassemble the current function +disassemble $pc $pc+10 + +Viewing & modifying variables +----------------------------- +print or p: displays variable or register +e.g. p/x $sp will display the stack pointer + +display: prints variable or register each time program stops +e.g. +display/x $pc will display the program counter +display argc + +undisplay : undo's display's + +info breakpoints: shows all current breakpoints + +info stack: shows stack back trace ( if this dosent work too well, I'll show you the +stacktrace by hand below ). + +info locals: displays local variables. + +info args: display current procedure arguments. + +set args: will set argc & argv each time the victim program is invoked. + +set <variable>=value +set argc=100 +set $pc=0 + + + +Modifying execution +------------------- +step: steps n lines of sourcecode +step steps 1 line. +step 100 steps 100 lines of code. + +next: like step except this will not step into subroutines + +stepi: steps a single machine code instruction. +e.g. stepi 100 + +nexti: steps a single machine code instruction but will not step into subroutines. + +finish: will run until exit of the current routine + +run: (re)starts a program + +cont: continues a program + +quit: exits gdb. + + +breakpoints +------------ + +break +sets a breakpoint +e.g. + +break main + +break *$pc + +break *0x400618 + +heres a really useful one for large programs +rbr +Set a breakpoint for all functions matching REGEXP +e.g. +rbr 390 +will set a breakpoint with all functions with 390 in their name. + +info breakpoints +lists all breakpoints + +delete: delete breakpoint by number or delete them all +e.g. +delete 1 will delete the first breakpoint +delete will delete them all + +watch: This will set a watchpoint ( usually hardware assisted ), +This will watch a variable till it changes +e.g. +watch cnt, will watch the variable cnt till it changes. +As an aside unfortunately gdb's, architecture independent watchpoint code +is inconsistent & not very good, watchpoints usually work but not always. + +info watchpoints: Display currently active watchpoints + +condition: ( another useful one ) +Specify breakpoint number N to break only if COND is true. +Usage is `condition N COND', where N is an integer and COND is an +expression to be evaluated whenever breakpoint N is reached. + + + +User defined functions/macros +----------------------------- +define: ( Note this is very very useful,simple & powerful ) +usage define <name> <list of commands> end + +examples which you should consider putting into .gdbinit in your home directory +define d +stepi +disassemble $pc $pc+10 +end + +define e +nexti +disassemble $pc $pc+10 +end + + +Other hard to classify stuff +---------------------------- +signal n: +sends the victim program a signal. +e.g. signal 3 will send a SIGQUIT. + +info signals: +what gdb does when the victim receives certain signals. + +list: +e.g. +list lists current function source +list 1,10 list first 10 lines of curret file. +list test.c:1,10 + + +directory: +Adds directories to be searched for source if gdb cannot find the source. +(note it is a bit sensititive about slashes ) +e.g. To add the root of the filesystem to the searchpath do +directory // + + +call <function> +This calls a function in the victim program, this is pretty powerful +e.g. +(gdb) call printf("hello world") +outputs: +$1 = 11 + +You might now be thinking that the line above didn't work, something extra had to be done. +(gdb) call fflush(stdout) +hello world$2 = 0 +As an aside the debugger also calls malloc & free under the hood +to make space for the "hello world" string. + + + +hints +----- +1) command completion works just like bash +( if you are a bad typist like me this really helps ) +e.g. hit br <TAB> & cursor up & down :-). + +2) if you have a debugging problem that takes a few steps to recreate +put the steps into a file called .gdbinit in your current working directory +if you have defined a few extra useful user defined commands put these in +your home directory & they will be read each time gdb is launched. + +A typical .gdbinit file might be. +break main +run +break runtime_exception +cont + + +stack chaining in gdb by hand +----------------------------- +This is done using a the same trick described for VM +p/x (*($sp+56))&0x7fffffff get the first backchain. + +For zSeries do +p/x *($sp+112) i.e. replace 56 with 112 & ignore the &0x7fffffff +in the macros below. + +this outputs +$5 = 0x528f18 +on my machine. +Now you can use +info symbol (*($sp+56))&0x7fffffff +you might see something like. +rl_getc + 36 in section .text telling you what is located at address 0x528f18 +Now do. +p/x (*(*$sp+56))&0x7fffffff +This outputs +$6 = 0x528ed0 +Now do. +info symbol (*(*$sp+56))&0x7fffffff +rl_read_key + 180 in section .text +now do +p/x (*(**$sp+56))&0x7fffffff +& so on. + +Disassembling instructions without debug info +--------------------------------------------- +gdb typically compains if there is a lack of debugging +symbols in the disassemble command with +"No function contains specified address." to get around +this do +x/<number lines to disassemble>xi <address> +e.g. +x/20xi 0x400730 + + + +Note: Remember gdb has history just like bash you don't need to retype the +whole line just use the up & down arrows. + + + +For more info +------------- +From your linuxbox do +man gdb or info gdb. + +core dumps +---------- +What a core dump ?, +A core dump is a file generated by the kernel ( if allowed ) which contains the registers, +& all active pages of the program which has crashed. +From this file gdb will allow you to look at the registers & stack trace & memory of the +program as if it just crashed on your system, it is usually called core & created in the +current working directory. +This is very useful in that a customer can mail a core dump to a technical support department +& the technical support department can reconstruct what happened. +Provided the have an indentical copy of this program with debugging symbols compiled in & +the source base of this build is available. +In short it is far more useful than something like a crash log could ever hope to be. + +In theory all that is missing to restart a core dumped program is a kernel patch which +will do the following. +1) Make a new kernel task structure +2) Reload all the dumped pages back into the kernels memory managment structures. +3) Do the required clock fixups +4) Get all files & network connections for the process back into an identical state ( really difficult ). +5) A few more difficult things I haven't thought of. + + + +Why have I never seen one ?. +Probably because you haven't used the command +ulimit -c unlimited in bash +to allow core dumps, now do +ulimit -a +to verify that the limit was accepted. + +A sample core dump +To create this I'm going to do +ulimit -c unlimited +gdb +to launch gdb (my victim app. ) now be bad & do the following from another +telnet/xterm session to the same machine +ps -aux | grep gdb +kill -SIGSEGV <gdb's pid> +or alternatively use killall -SIGSEGV gdb if you have the killall command. +Now look at the core dump. +./gdb ./gdb core +Displays the following +GNU gdb 4.18 +Copyright 1998 Free Software Foundation, Inc. +GDB is free software, covered by the GNU General Public License, and you are +welcome to change it and/or distribute copies of it under certain conditions. +Type "show copying" to see the conditions. +There is absolutely no warranty for GDB. Type "show warranty" for details. +This GDB was configured as "s390-ibm-linux"... +Core was generated by `./gdb'. +Program terminated with signal 11, Segmentation fault. +Reading symbols from /usr/lib/libncurses.so.4...done. +Reading symbols from /lib/libm.so.6...done. +Reading symbols from /lib/libc.so.6...done. +Reading symbols from /lib/ld-linux.so.2...done. +#0 0x40126d1a in read () from /lib/libc.so.6 +Setting up the environment for debugging gdb. +Breakpoint 1 at 0x4dc6f8: file utils.c, line 471. +Breakpoint 2 at 0x4d87a4: file top.c, line 2609. +(top-gdb) info stack +#0 0x40126d1a in read () from /lib/libc.so.6 +#1 0x528f26 in rl_getc (stream=0x7ffffde8) at input.c:402 +#2 0x528ed0 in rl_read_key () at input.c:381 +#3 0x5167e6 in readline_internal_char () at readline.c:454 +#4 0x5168ee in readline_internal_charloop () at readline.c:507 +#5 0x51692c in readline_internal () at readline.c:521 +#6 0x5164fe in readline (prompt=0x7ffff810 "\177˙řx\177˙÷Ř\177˙řxŔ") + at readline.c:349 +#7 0x4d7a8a in command_line_input (prrompt=0x564420 "(gdb) ", repeat=1, + annotation_suffix=0x4d6b44 "prompt") at top.c:2091 +#8 0x4d6cf0 in command_loop () at top.c:1345 +#9 0x4e25bc in main (argc=1, argv=0x7ffffdf4) at main.c:635 + + +LDD +=== +This is a program which lists the shared libraries which a library needs, +Note you also get the relocations of the shared library text segments which +help when using objdump --source. +e.g. + ldd ./gdb +outputs +libncurses.so.4 => /usr/lib/libncurses.so.4 (0x40018000) +libm.so.6 => /lib/libm.so.6 (0x4005e000) +libc.so.6 => /lib/libc.so.6 (0x40084000) +/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) + + +Debugging shared libraries +========================== +Most programs use shared libraries, however it can be very painful +when you single step instruction into a function like printf for the +first time & you end up in functions like _dl_runtime_resolve this is +the ld.so doing lazy binding, lazy binding is a concept in ELF where +shared library functions are not loaded into memory unless they are +actually used, great for saving memory but a pain to debug. +To get around this either relink the program -static or exit gdb type +export LD_BIND_NOW=true this will stop lazy binding & restart the gdb'ing +the program in question. + + + +Debugging modules +================= +As modules are dynamically loaded into the kernel their address can be +anywhere to get around this use the -m option with insmod to emit a load +map which can be piped into a file if required. + +The proc file system +==================== +What is it ?. +It is a filesystem created by the kernel with files which are created on demand +by the kernel if read, or can be used to modify kernel parameters, +it is a powerful concept. + +e.g. + +cat /proc/sys/net/ipv4/ip_forward +On my machine outputs +0 +telling me ip_forwarding is not on to switch it on I can do +echo 1 > /proc/sys/net/ipv4/ip_forward +cat it again +cat /proc/sys/net/ipv4/ip_forward +On my machine now outputs +1 +IP forwarding is on. +There is a lot of useful info in here best found by going in & having a look around, +so I'll take you through some entries I consider important. + +All the processes running on the machine have there own entry defined by +/proc/<pid> +So lets have a look at the init process +cd /proc/1 + +cat cmdline +emits +init [2] + +cd /proc/1/fd +This contains numerical entries of all the open files, +some of these you can cat e.g. stdout (2) + +cat /proc/29/maps +on my machine emits + +00400000-00478000 r-xp 00000000 5f:00 4103 /bin/bash +00478000-0047e000 rw-p 00077000 5f:00 4103 /bin/bash +0047e000-00492000 rwxp 00000000 00:00 0 +40000000-40015000 r-xp 00000000 5f:00 14382 /lib/ld-2.1.2.so +40015000-40016000 rw-p 00014000 5f:00 14382 /lib/ld-2.1.2.so +40016000-40017000 rwxp 00000000 00:00 0 +40017000-40018000 rw-p 00000000 00:00 0 +40018000-4001b000 r-xp 00000000 5f:00 14435 /lib/libtermcap.so.2.0.8 +4001b000-4001c000 rw-p 00002000 5f:00 14435 /lib/libtermcap.so.2.0.8 +4001c000-4010d000 r-xp 00000000 5f:00 14387 /lib/libc-2.1.2.so +4010d000-40111000 rw-p 000f0000 5f:00 14387 /lib/libc-2.1.2.so +40111000-40114000 rw-p 00000000 00:00 0 +40114000-4011e000 r-xp 00000000 5f:00 14408 /lib/libnss_files-2.1.2.so +4011e000-4011f000 rw-p 00009000 5f:00 14408 /lib/libnss_files-2.1.2.so +7fffd000-80000000 rwxp ffffe000 00:00 0 + + +Showing us the shared libraries init uses where they are in memory +& memory access permissions for each virtual memory area. + +/proc/1/cwd is a softlink to the current working directory. +/proc/1/root is the root of the filesystem for this process. + +/proc/1/mem is the current running processes memory which you +can read & write to like a file. +strace uses this sometimes as it is a bit faster than the +rather inefficent ptrace interface for peeking at DATA. + + +cat status + +Name: init +State: S (sleeping) +Pid: 1 +PPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +Groups: +VmSize: 408 kB +VmLck: 0 kB +VmRSS: 208 kB +VmData: 24 kB +VmStk: 8 kB +VmExe: 368 kB +VmLib: 0 kB +SigPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 7fffffffd7f0d8fc +SigCgt: 00000000280b2603 +CapInh: 00000000fffffeff +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff + +User PSW: 070de000 80414146 +task: 004b6000 tss: 004b62d8 ksp: 004b7ca8 pt_regs: 004b7f68 +User GPRS: +00000400 00000000 0000000b 7ffffa90 +00000000 00000000 00000000 0045d9f4 +0045cafc 7ffffa90 7fffff18 0045cb08 +00010400 804039e8 80403af8 7ffff8b0 +User ACRS: +00000000 00000000 00000000 00000000 +00000001 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +Kernel BackChain CallChain BackChain CallChain + 004b7ca8 8002bd0c 004b7d18 8002b92c + 004b7db8 8005cd50 004b7e38 8005d12a + 004b7f08 80019114 +Showing among other things memory usage & status of some signals & +the processes'es registers from the kernel task_structure +as well as a backchain which may be useful if a process crashes +in the kernel for some unknown reason. + +Some driver debugging techniques +================================ +high level debugging network drivers +------------------------------------ +ifconfig is a quite useful command +it gives the current state of network drivers. + +If you suspect your network device driver is dead +one way to check is type +ifconfig <network device> +e.g. tr0 +You should see something like +tr0 Link encap:16/4 Mbps Token Ring (New) HWaddr 00:04:AC:20:8E:48 + inet addr:9.164.185.132 Bcast:9.164.191.255 Mask:255.255.224.0 + UP BROADCAST RUNNING MULTICAST MTU:2000 Metric:1 + RX packets:246134 errors:0 dropped:0 overruns:0 frame:0 + TX packets:5 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:100 + +if the device doesn't say up +try +/etc/rc.d/init.d/network start +( this starts the network stack & hopefully calls ifconfig tr0 up ). +ifconfig looks at the output of /proc/net/dev & presents it in a more presentable form +Now ping the device from a machine in the same subnet. +if the RX packets count & TX packets counts don't increment you probably +have problems. +next +cat /proc/net/arp +Do you see any hardware addresses in the cache if not you may have problems. +Next try +ping -c 5 <broadcast_addr> i.e. the Bcast field above in the output of +ifconfig. Do you see any replies from machines other than the local machine +if not you may have problems. also if the TX packets count in ifconfig +hasn't incremented either you have serious problems in your driver +(e.g. the txbusy field of the network device being stuck on ) +or you may have multiple network devices connected. + + +chandev +------- +There is a new device layer for channel devices, some +drivers e.g. lcs are registered with this layer. +If the device uses the channel device layer you'll be +able to find what interupts it uses & the current state +of the device. +See the manpage chandev.8 &type cat /proc/chandev for more info. + + + +Starting points for debugging scripting languages etc. +====================================================== + +bash/sh + +bash -x <scriptname> +e.g. bash -x /usr/bin/bashbug +displays the following lines as it executes them. ++ MACHINE=i586 ++ OS=linux-gnu ++ CC=gcc ++ CFLAGS= -DPROGRAM='bash' -DHOSTTYPE='i586' -DOSTYPE='linux-gnu' -DMACHTYPE='i586-pc-linux-gnu' -DSHELL -DHAVE_CONFIG_H -I. -I. -I./lib -O2 -pipe ++ RELEASE=2.01 ++ PATCHLEVEL=1 ++ RELSTATUS=release ++ MACHTYPE=i586-pc-linux-gnu + +perl -d <scriptname> runs the perlscript in a fully intercative debugger +<like gdb>. +Type 'h' in the debugger for help. + +for debugging java type +jdb <filename> another fully interactive gdb style debugger. +& type ? in the debugger for help. + + +Debugging Drivers +================= +Some of our drivers now support a debug logging feature in +/proc/s390dbf see s390dbf.txt in the linux/Documentation directory +for more info. +e.g. +to switch on lcs debugging +echo 5 > /proc/s390dbf/lcs/level +& then after the error occured. +cat /proc/s390dbf/lcs/sprintf >/logfile +the logfile now contains some information which may help +tech support resolve a problem in the field. + +If you have VM look at the chapter Debugging IO on S390 under VM. + + + + +Tools soon to be available +========================== + +Dumptool & Lcrash +----------------- +Michael Holzheu & others here at IBM have a fairly mature port of +SGI's lcrash tool which allows one to look at kernel structures in a +running kernel. + +It also complements a tool called dumptool which dumps all the kernels +memory pages & registers to either a tape or a disk. +This can be used by tech support or an ambitous end user do +post mortem debugging of a machine like gdb core dumps. + +Going into how to use this tool in detail will be explained +in other documentation supplied by IBM & the lcrash homepage +http://oss.sgi.com/projects/lkcd/. + +How they work +------------- +Lcrash is a perfectly normal application +however it requires an additional file. +It is built using a patch to the kernel source base. + + +Debugging a live system it uses /dev/mem +alternatively for post mortem debugging it uses the data +collected by dumptool. + + +Ltrace +------ +We also have a tool called ltrace in our CVS repository +no plans on a delivery date yet. +ltrace is a superset of strace in that it also allows +tracing of shared libraries calls as well as system calls, +man ltrace for more info. + +SysRq +===== +This is now supported by linux for s/390 & zSeries. +To enable it do compile the kernel with +Kernel Hacking -> Magic SysRq Key Enabled +echo "1" > /proc/sys/kernel/sysrq. +On 390 all commands are prefixed with +^- +e.g. +^-t will show tasks. +^-? or some unknown command will display help. +The sysrq key reading is very picky ( I have to type the keys in an + xterm session & paste them into the x3270 console ) +& it may be wise to predefine the keys as described in the VM hints above + +This is particularly useful for syncing disks unmounting & rebooting +if the machine gets partially hung. + +Read Documentation/sysrq.txt for more info + +References: +=========== +Enterprise Systems Architecture Reference Summary +Enterprise Systems Architecture Principles of Operation +Hartmut Penners s390 stack frame sheet. +IBM Mainframe Channel Attachment a technology brief from a CISCO webpage +Various bits of man & info pages of Linux. +Linux & GDB source. +Various info & man pages. +CMS Help on tracing commands. +Linux for s/390 Elf Application Binary Interface +Linux for zSeries Elf Application Binary Interface ( Both Highly Recommended ) +z/Architecture Principles of Operation SA22-7832-00 +Enterprise Systems Architecture/390 Reference Summary SA22-7209-01 & the +Enterprise Systems Architecture/390 Principles of Operation SA22-7201-05 + + + + + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/s390/chandev.8 linux.ac/Documentation/s390/chandev.8 --- linux.vanilla/Documentation/s390/chandev.8 Fri Feb 16 23:53:08 2001 +++ linux.ac/Documentation/s390/chandev.8 Thu Apr 12 11:48:05 2001 @@ -42,8 +42,16 @@ .It Or from the boot command line using the 'chandev=' keyword .El +.Bl -item +.It Multiple options can be passed separated by semicolons but no spaces are allowed between parameters. The script /bin/chandev will be called automatically on startup or a machine check of a device as follows. /bin/chandev <start starting_devnames> <machine_check (devnames pre_recovery_action_status) (post_recovery_action_status)>. +The chandev layer doesn't open stdin stdout or stderr so it is advisable that you add the following lines to the start of your script. +.It +#!/bin/bash +.It +exec >/dev/console 2>&1 0>&1 +.El e.g. if tr0 & ctc0 were starting up & eth0 & eth1 didn't recover from a gone machine check at the same instant the parameters would be. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/s390/config3270.sh linux.ac/Documentation/s390/config3270.sh --- linux.vanilla/Documentation/s390/config3270.sh Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/s390/config3270.sh Thu Apr 12 11:48:15 2001 @@ -0,0 +1,66 @@ +#!/bin/sh +# +# config3270 -- Autoconfigure /dev/3270/* and /etc/inittab +# +# Usage: +# config3270 +# +# Output: +# /tmp/mkdev3270 +# +# Operation: +# 1. Run this script +# 2. Run the script it produces: /tmp/mkdev3270 +# 3. Issue "telinit q" or reboot, as appropriate. +# +P=/proc/tty/driver/tty3270 +ROOT= +D=$ROOT/dev +SUBD=3270 +TTY=$SUBD/tty +TUB=$SUBD/tub +SCR=$ROOT/tmp/mkdev3270 +SCRTMP=$SCR.a +GETTYLINE=:2345:respawn:/sbin/mingetty +INITTAB=$ROOT/etc/inittab +NINITTAB=$ROOT/etc/NEWinittab +OINITTAB=$ROOT/etc/OLDinittab +ADDNOTE=\\"# Additional mingettys for the 3270/tty* driver, tub3270 ---\\" + +if ! ls $P > /dev/null 2>&1; then + modprobe tub3270 > /dev/null 2>&1 +fi +ls $P > /dev/null 2>&1 || exit 1 + +# Initialize two files, one for /dev/3270 commands and one +# to replace the /etc/inittab file (old one saved in OLDinittab) +echo "#!/bin/sh" > $SCR || exit 1 +echo " " >> $SCR +echo "# Script built by /sbin/config3270" >> $SCR +echo rm -rf "$D/$SUBD/*" >> $SCR +echo "grep -v $TTY $INITTAB > $NINITTAB" > $SCRTMP || exit 1 +echo "echo $ADDNOTE >> $NINITTAB" >> $SCRTMP +echo mkdir -p $D/$SUBD >> $SCR + +# Now query the tub3270 driver for 3270 device information +# and add appropriate mknod and mingetty lines to our files +echo what=config > $P +while read devno maj min;do + if [ $min = 0 ]; then + fsmaj=$maj + echo mknod $D/$TUB c $fsmaj 0 >> $SCR + echo chmod 666 $D/$TUB >> $SCR + elif [ $maj = CONSOLE ]; then + echo mknod $D/$TUB$devno c $fsmaj $min >> $SCR + else + echo mknod $D/$TTY$devno c $maj $min >>$SCR + echo mknod $D/$TUB$devno c $fsmaj $min >> $SCR + echo "echo t$min$GETTYLINE $TTY$devno >> $NINITTAB" >> $SCRTMP + fi +done < $P + +echo mv $INITTAB $OINITTAB >> $SCRTMP || exit 1 +echo mv $NINITTAB $INITTAB >> $SCRTMP +cat $SCRTMP >> $SCR +rm $SCRTMP +exit 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/s390/s390dbf.txt linux.ac/Documentation/s390/s390dbf.txt --- linux.vanilla/Documentation/s390/s390dbf.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/s390/s390dbf.txt Thu Apr 12 11:48:15 2001 @@ -0,0 +1,558 @@ +S390 Debug Feature +================== + +files: arch/s390/kernel/debug.c + include/asm-s390/debug.h + +Description: +------------ +The goal of this feature is to provide a kernel debug logging API +where log records can be stored efficiently in memory, where each component +(e.g. device drivers) can have one seperate debug log. +One purpose of this is to inspect the debug logs after a production system crash +in order to analyze the reason for the crash. +If the system still runs but only a subcomponent which uses dbf failes, +it is possible to look at the debug logs on a live system via the Linux proc +filesystem. +The debug feature may also very usefull for kernel and driver development. + +Design: +------- +Kernel components (e.g. device drivers) can register themselves at the debug +feature with the function call debug_register(). This function initializes a +debug log for the caller. For each debug log exists a number of debug areas +where exactly one is active at one time. Each debug area consists of contiguous +pages in memory. In the debug areas there are stored debug entries (log records) +which are written by event- and exception-calls. + +An event-call writes the specified debug entry to the active debug +area and updates the log pointer for the active area. If the end +of the active debug area is reached, a wrap around is done (ring buffer) +and the next debug entry will be written at the beginning of the active +debug area. + +An exception-call writes the specified debug entry to the log and +switches to the next debug area. This is done in order to be sure +that the records which describe the origin of the exception are not +overwritten when a wrap around for the current area occurs. + +The debug areas itselve are also ordered in form of a ring buffer. +When an exception is thrown in the last debug area, the following debug +entries are then written again in the very first area. + +There are three versions for the event- and exception-calls: One for +logging raw data, one for text and one for numbers. + +Each debug entry contains the following data: + +- Timestamp +- Cpu-Number of calling task +- Level of debug entry (0...6) +- Return Address to caller +- Flag, if entry is an exception or not + +The debug logs can be inspected in a live system through entries in +the proc-filesystem. Under the path /proc/s390dbf there is +a directory for each registered component, which is named like the +corresponding component. + +The content of the directories are files which represent different views +to the debug log. Each component can decide which views should be +used through registering them with the function debug_register_view(). +Predefined views for hex/ascii, sprintf and raw binary data are provided. +It is also possible to define other views. The content of +a view can be inspected simply by reading the corresponding proc file. + +All debug logs have an an actual debug level (range from 0 to 6). +The default level is 3. Event and Exception functions have a 'level' +parameter. Only debug entries with a level that is lower or equal +than the actual level are written to the log. This means that high +priority log entries should have a low level value whereas low priority +entries should have a high one. +The actual debug level can be changed with the help of the proc-filesystem +through writing a number string "x" to the 'level' proc file which is +provided for every debug log. Debugging can be switched off completely +by using "-" on the 'level' proc file. + +Example: + +> echo "-" > /proc/s390dbf/dasd/level + +Kernel Interfaces: +------------------ + +---------------------------------------------------------------------------- +debug_info_t *debug_register(char *name, int pages_index, int nr_areas, + int buf_size); + +Parameter: name: Name of debug log (e.g. used for proc entry) + pages_index: 2^pages_index pages will be allocated per area + nr_areas: number of debug areas + buf_size: size of data area in each debug entry + +Return Value: Handle for generated debug area + NULL if register failed + +Description: Allocates memory for a debug log + Must not be called within an interrupt handler + +--------------------------------------------------------------------------- +void debug_unregister (debug_info_t * id); + +Parameter: id: handle for debug log + +Return Value: none + +Description: frees memory for a debug log + Must not be called within an interrupt handler + +--------------------------------------------------------------------------- +void debug_set_level (debug_info_t * id, int new_level); + +Parameter: id: handle for debug log + new_level: new debug level + +Return Value: none + +Description: Sets new actual debug level if new_level is valid. +--------------------------------------------------------------------------- +debug_entry_t* debug_event (debug_info_t* id, int level, void* data, + int length); + +Parameter: id: handle for debug log + level: debug level + data: pointer to data for debug entry + length: length of data in bytes + +Return Value: Address of written debug entry + +Description: writes debug entry to active debug area (if level <= actual + debug level) + +--------------------------------------------------------------------------- +debug_entry_t* debug_int_event (debug_info_t * id, int level, + unsigned int data); +debug_entry_t* debug_long_event(debug_info_t * id, int level, + unsigned long data); + +Parameter: id: handle for debug log + level: debug level + data: integer value for debug entry + +Return Value: Address of written debug entry + +Description: writes debug entry to active debug area (if level <= actual + debug level) + +--------------------------------------------------------------------------- +debug_entry_t* debug_text_event (debug_info_t * id, int level, + const char* data); + +Parameter: id: handle for debug log + level: debug level + data: string for debug entry + +Return Value: Address of written debug entry + +Description: writes debug entry in ascii format to active debug area + (if level <= actual debug level) + +--------------------------------------------------------------------------- +debug_entry_t* debug_sprintf_event (debug_info_t * id, int level, + char* string,...); + +Parameter: id: handle for debug log + level: debug level + string: format string for debug entry + ...: varargs used as in sprintf() + +Return Value: Address of written debug entry + +Description: writes debug entry with format string and varargs (longs) to + active debug area (if level $<=$ actual debug level). + floats and long long datatypes cannot be used as varargs. + +--------------------------------------------------------------------------- + +debug_entry_t* debug_exception (debug_info_t* id, int level, void* data, + int length); + +Parameter: id: handle for debug log + level: debug level + data: pointer to data for debug entry + length: length of data in bytes + +Return Value: Address of written debug entry + +Description: writes debug entry to active debug area (if level <= actual + debug level) and switches to next debug area + +--------------------------------------------------------------------------- +debug_entry_t* debug_int_exception (debug_info_t * id, int level, + unsigned int data); +debug_entry_t* debug_long_exception(debug_info_t * id, int level, + unsigned long data); + +Parameter: id: handle for debug log + level: debug level + data: integer value for debug entry + +Return Value: Address of written debug entry + +Description: writes debug entry to active debug area (if level <= actual + debug level) and switches to next debug area + +--------------------------------------------------------------------------- +debug_entry_t* debug_text_exception (debug_info_t * id, int level, + const char* data); + +Parameter: id: handle for debug log + level: debug level + data: string for debug entry + +Return Value: Address of written debug entry + +Description: writes debug entry in ascii format to active debug area + (if level <= actual debug level) and switches to next debug + area + +--------------------------------------------------------------------------- +debug_entry_t* debug_sprintf_exception (debug_info_t * id, int level, + char* string,...); + +Parameter: id: handle for debug log + level: debug level + string: format string for debug entry + ...: varargs used as in sprintf() + +Return Value: Address of written debug entry + +Description: writes debug entry with format string and varargs (longs) to + active debug area (if level $<=$ actual debug level) and + switches to next debug area. + floats and long long datatypes cannot be used as varargs. + +--------------------------------------------------------------------------- + +int debug_register_view (debug_info_t * id, struct debug_view *view); + +Parameter: id: handle for debug log + view: pointer to debug view struct + +Return Value: 0 : ok + < 0: Error + +Description: registers new debug view and creates proc dir entry + +--------------------------------------------------------------------------- +int debug_unregister_view (debug_info_t * id, struct debug_view *view); + +Parameter: id: handle for debug log + view: pointer to debug view struct + +Return Value: 0 : ok + < 0: Error + +Description: unregisters debug view and removes proc dir entry + + + +Predefined views: +----------------- + +extern struct debug_view debug_hex_ascii_view; +extern struct debug_view debug_raw_view; +extern struct debug_view debug_sprintf_view; + +Examples +-------- + +/* + * hex_ascii- + raw-view Example + */ + +#include <linux/module.h> +#include <asm/debug.h> + +static debug_info_t* debug_info; + +int init_module(void) +{ + /* register 4 debug areas with one page each and 4 byte data field */ + + debug_info = debug_register ("test", 0, 4, 4 ); + debug_register_view(debug_info,&debug_hex_ascii_view); + debug_register_view(debug_info,&debug_raw_view); + + debug_text_event(debug_info, 4 , "one "); + debug_int_exception(debug_info, 4, 4711); + debug_event(debug_info, 3, &debug_info, 4); + + return 0; +} + +void cleanup_module(void) +{ + debug_unregister (debug_info); +} + +--------------------------------------------------------------------------- + +/* + * sprintf-view Example + */ + +#include <linux/module.h> +#include <asm/debug.h> + +static debug_info_t* debug_info; + +int init_module(void) +{ + /* register 4 debug areas with one page each and data field for */ + /* format string pointer + 2 varargs (= 3 * sizeof(long)) */ + + debug_info = debug_register ("test", 0, 4, sizeof(long) * 3); + debug_register_view(debug_info,&debug_sprintf_view); + + debug_sprintf_event(debug_info, 2 , "first event in %s:%i\n",__FILE__,__LINE__); + debug_sprintf_exception(debug_info, 1, "pointer to debug info: %p\n",&debug_info); + + return 0; +} + +void cleanup_module(void) +{ + debug_unregister (debug_info); +} + + + +ProcFS Interface +---------------- +Views to the debug logs can be investigated through reading the corresponding +proc-files: + +Example: + +> ls /proc/s390dbf/dasd +hex_ascii level raw +> cat /proc/s390dbf/dasd/hex_ascii | sort +1 +00 00974733272:680099 2 - 02 0006ad7e 07 ea 4a 90 | .... +00 00974733272:682210 2 - 02 0006ade6 46 52 45 45 | FREE +00 00974733272:682213 2 - 02 0006adf6 07 ea 4a 90 | .... +00 00974733272:682281 1 * 02 0006ab08 41 4c 4c 43 | EXCP +01 00974733272:682284 2 - 02 0006ab16 45 43 4b 44 | ECKD +01 00974733272:682287 2 - 02 0006ab28 00 00 00 04 | .... +01 00974733272:682289 2 - 02 0006ab3e 00 00 00 20 | ... +01 00974733272:682297 2 - 02 0006ad7e 07 ea 4a 90 | .... +01 00974733272:684384 2 - 00 0006ade6 46 52 45 45 | FREE +01 00974733272:684388 2 - 00 0006adf6 07 ea 4a 90 | .... + +See section about predefined views for explanation of the above output! + +Changing the debug level +------------------------ + +Example: + + +> cat /proc/s390dbf/dasd/level +3 +> echo "5" > /proc/s390dbf/dasd/level +> cat /proc/s390dbf/dasd/level +5 + +lcrash Interface +---------------- +It is planned that the dump analysis tool lcrash gets an additional command +'s390dbf' to display all the debug logs. With this tool it will be possible +to investigate the debug logs on a live system and with a memory dump after +a system crash. + +Investigating raw memory +------------------------ +One last possibility to investigate the debug logs at a live +system and after a system crash is to look at the raw memory +under VM or at the Service Element. +It is possible to find the anker of the debug-logs through +the 'debug_area_first' symbol in the System map. Then one has +to follow the correct pointers of the data-structures defined +in debug.h and find the debug-areas in memory. +Normally modules which use the debug feature will also have +a global variable with the pointer to the debug-logs. Following +this pointer it will also be possible to find the debug logs in +memory. + +For this method it is recommended to use '16 * x + 4' byte (x = 0..n) +for the length of the data field in debug_register() in +order to see the debug entries well formatted. + + +Predefined Views +---------------- + +There are three predefined views: hex_ascii, raw and sprintf. +The hex_ascii view shows the data field in hex and ascii representation +(e.g. '45 43 4b 44 | ECKD'). +The raw view returns a bytestream as the debug areas are stored in memory. + +The sprintf view formats the debug entries in the same way as the sprintf +function would do. The sprintf event/expection fuctions write to the +debug entry a pointer to the format string (size = sizeof(long)) +and for each vararg a long value. So e.g. for a debug entry with a format +string plus two varargs one would need to allocate a (3 * sizeof(long)) +byte data area in the debug_register() function. + + +NOTE: If using the sprintf view do NOT use other event/exception functions +than the sprintf-event and -exception functions. + +The format of the hex_ascii and sprintf view is as follows: +- Number of area +- Timestamp (formatted as seconds and microseconds since 00:00:00 Coordinated + Universal Time (UTC), January 1, 1970) +- level of debug entry +- Exception flag (* = Exception) +- Cpu-Number of calling task +- Return Address to caller +- data field + +The format of the raw view is: +- Header as described in debug.h +- datafield + +A typical line of the hex_ascii view will look like the following (first line +is only for explanation and will not be displayed when 'cating' the view): + +area time level exception cpu caller data (hex + ascii) +-------------------------------------------------------------------------- +00 00964419409:440690 1 - 00 88023fe + + +Defining views +-------------- + +Views are specified with the 'debug_view' structure. There are defined +callback functions which are used for reading and writing the proc files: + +struct debug_view { + char name[DEBUG_MAX_PROCF_LEN]; + debug_prolog_proc_t* prolog_proc; + debug_header_proc_t* header_proc; + debug_format_proc_t* format_proc; + debug_input_proc_t* input_proc; + void* private_data; +}; + +where + +typedef int (debug_header_proc_t) (debug_info_t* id, + struct debug_view* view, + int area, + debug_entry_t* entry, + char* out_buf); + +typedef int (debug_format_proc_t) (debug_info_t* id, + struct debug_view* view, char* out_buf, + const char* in_buf); +typedef int (debug_prolog_proc_t) (debug_info_t* id, + struct debug_view* view, + char* out_buf); +typedef int (debug_input_proc_t) (debug_info_t* id, + struct debug_view* view, + struct file* file, const char* user_buf, + size_t in_buf_size, loff_t* offset); + + +The "private_data" member can be used as pointer to view specific data. +It is not used by the debug feature itself. + +The output when reading a debug-proc file is structured like this: + +"prolog_proc output" + +"header_proc output 1" "format_proc output 1" +"header_proc output 2" "format_proc output 2" +"header_proc output 3" "format_proc output 3" +... + +When a view is read from the proc fs, the Debug Feature calls the +'prolog_proc' once for writing the prolog. +Then 'header_proc' and 'format_proc' are called for each +existing debug entry. + +The input_proc can be used to implement functionality when it is written to +the view (e.g. like with 'echo "0" > /proc/s390dbf/dasd/level). + +For header_proc there can be used the default function +debug_dflt_header_fn() which is defined in in debug.h. +and which produces the same header output as the predefined views. +E.g: +00 00964419409:440761 2 - 00 88023ec + +In order to see how to use the callback functions check the implementation +of the default views! + +Example + +#include <asm/debug.h> + +#define UNKNOWNSTR "data: %08x" + +const char* messages[] = +{"This error...........\n", + "That error...........\n", + "Problem..............\n", + "Something went wrong.\n", + "Everything ok........\n", + NULL +}; + +static int debug_test_format_fn( + debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf +) +{ + int i, rc = 0; + + if(id->buf_size >= 4) { + int msg_nr = *((int*)in_buf); + if(msg_nr < sizeof(messages)/sizeof(char*) - 1) + rc += sprintf(out_buf, "%s", messages[msg_nr]); + else + rc += sprintf(out_buf, UNKNOWNSTR, msg_nr); + } + out: + return rc; +} + +struct debug_view debug_test_view = { + "myview", /* name of view */ + NULL, /* no prolog */ + &debug_dflt_header_fn, /* default header for each entry */ + &debug_test_format_fn, /* our own format function */ + NULL, /* no input function */ + NULL /* no private data */ +}; + +===== +test: +===== +debug_info_t *debug_info; +... +debug_info = debug_register ("test", 0, 4, 4 )); +debug_register_view(debug_info, &debug_test_view); +for(i = 0; i < 10; i ++) debug_int_event(debug_info, 1, i); + +> cat /proc/s390dbf/test/myview +00 00964419734:611402 1 - 00 88042ca This error........... +00 00964419734:611405 1 - 00 88042ca That error........... +00 00964419734:611408 1 - 00 88042ca Problem.............. +00 00964419734:611411 1 - 00 88042ca Something went wrong. +00 00964419734:611414 1 - 00 88042ca Everything ok........ +00 00964419734:611417 1 - 00 88042ca data: 00000005 +00 00964419734:611419 1 - 00 88042ca data: 00000006 +00 00964419734:611422 1 - 00 88042ca data: 00000007 +00 00964419734:611425 1 - 00 88042ca data: 00000008 +00 00964419734:611428 1 - 00 88042ca data: 00000009 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/scsi-generic.txt linux.ac/Documentation/scsi-generic.txt --- linux.vanilla/Documentation/scsi-generic.txt Fri Feb 9 00:32:44 2001 +++ linux.ac/Documentation/scsi-generic.txt Sat Apr 14 01:14:37 2001 @@ -1,6 +1,6 @@ - Notes on Linux's SG driver version 2.1.36 + Notes on Linux's SG driver version 2.1.39 ----------------------------------------- - 20000110 + 20010329 Introduction ============ @@ -12,7 +12,7 @@ amongst other things. These are notes on the Linux SCSI generic packet device driver (sg) -describing version 2.1.36 . The original driver was written by Lawrence +describing version 2.1.39 . The original driver was written by Lawrence Foard and remained in place with minimal changes since circa 1992. Version 2 of this driver remains backward compatible (binary and source **) with the original. It adds scatter gather, command queuing, @@ -23,6 +23,10 @@ at the linux/Documentation directory. The full document can be found at http://www.torque.net/sg/p/scsi-generic_long.txt . +The Linux 2.4 series kernels have now been released. Lk 2.4 contains +an upgraded "version 3" sg driver which is described in a supplementary +document at http://www.torque.net/sg/p/scsi-generic_v3.txt . + The interface and usage of the original sg driver have been documented by Heiko Eissfeldt in a HOWTO called SCSI-Programming-HOWTO. My copy of the document is version 1.5 dated 7th May 1996. It can found at @@ -41,7 +45,8 @@ The SCSI generic packet device driver (sg) is a character based device. It is one of the four high level device driver in the SCSI sub-system; the others are sd (for direct-access devices - disks), st (for tapes) -and sr (for data cdroms). The other three devices are block devices. +and sr (for data cdroms). Sd and sr are block devices while st (like sg) +is a character device. The unifying layer of the SCSI sub-system is the so-called mid-level. Below that are the "low level" drivers which are the drivers for the @@ -233,13 +238,14 @@ open(const char * filename, int flags) -------------------------------------- The filename should be an 'sg' device such as -/dev/sg[a-z] /dev/sg[0,1,2,...] +/dev/sg[a-z] <<< now deprecated >>> or a symbolic link to one of these. [Devfs has its own sub-directory for -sg devices with entries like: /dev/sg/c1b2t3u4 .] It seems as though SCSI -devices are allocated to sg minor numbers in the same order as they appear -in 'cat /proc/scsi/scsi'. Sg is a "character" based Linux device driver. -This means it has an open/close/read/write/ioctl type interface. +sg devices with entries like: /dev/scsi/host1/bus2/target3/lun4/generic .] +It seems as though SCSI devices are allocated to sg minor numbers in the +same order as they appear in 'cat /proc/scsi/scsi'. Sg is a "character" +based Linux device driver. This means it has an open/close/read/write/ioctl +type interface. Flags can be either O_RDONLY or O_RDWR or-ed with either O_EXCL waits for other opens on sg device to be closed before @@ -396,7 +402,7 @@ (which is called 'sg_release()' in the version 2 driver) to facilitate the cleanup mentioned above. -A problem persists in version 2.1.36 if the sg driver is a module and is +A problem persists in version 2.1.39 if the sg driver is a module and is removed while packets are still "in flight". Returns 0 if successful, otherwise -1 implies an error. @@ -595,6 +601,8 @@ do much (may in the future after other issues are resolved). Yields an EBUSY error if the SCSI bus or the associated device is being reset when this ioctl() is called, otherwise returns 0. +N.B. In some recent distributions there is a patch to the SCSI mid level +code that activates this ioctl. Check your distribution. SG_SET_DEBUG +: Assumes 3rd argument is pointing to an int. 0 (default) turns debugging @@ -640,7 +648,7 @@ found, switching to normal blocked io. A working example of this logic is in the sg_scan utility program. -open("/dev/sga", O_RDONLY | O_NONBLOCK) +open("/dev/sg0", O_RDONLY | O_NONBLOCK) /* check device, EBUSY means some other process has O_EXCL lock on it */ /* when the device you want is found then ... */ flags = fcntl(sg_fd, F_GETFL) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sound/PAS16 linux.ac/Documentation/sound/PAS16 --- linux.vanilla/Documentation/sound/PAS16 Sun Apr 2 23:38:53 2000 +++ linux.ac/Documentation/sound/PAS16 Thu Apr 12 11:48:29 2001 @@ -1,7 +1,7 @@ Pro Audio Spectrum 16 for 2.3.99 and later ========================================= by Thomas Molina (tmolina@home.com) -last modified 26 Mar 2000 +last modified 3 Mar 2001 Acknowledgement to Axel Boldt (boldt@math.ucsb.edu) for stuff taken from Configure.help, Riccardo Facchetti for stuff from README.OSS, and others whose names I could not find. @@ -48,14 +48,6 @@ if you want to use the SB emulation of PAS16. It's also possible to the emulation if you want to use a true SB card together with PAS16 (there is another question about this that is asked later). - "Sound Blaster support", - - Answer 'y' if you have an original SB card made by Creative Labs - or a full 100% hardware compatible clone (like Thunderboard or - SM Games). If your card was in the list of supported cards (above), - please look at the card specific instructions later in this file - before answering this question. For an unknown card you may answer - 'y' if the card claims to be SB compatible. - Enable this option also with PAS16. "Generic OPL2/OPL3 FM synthesizer support", - Answer 'y' if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). @@ -113,27 +105,13 @@ Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio 16 or Logitech SoundMan 16 sound card. Don't answer Y if you have some other card made by Media Vision or Logitech since they are not - PAS16 compatible. + PAS16 compatible. It is not necessary to enable the separate + Sound Blaster support; it is included in the PAS driver. + If you compile the driver into the kernel, you have to add "pas2=<io>,<irq>,<dma>,<dma2>,<sbio>,<sbirq>,<sbdma>,<sbdma2> to the kernel command line. -100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support -CONFIG_SOUND_SB - Answer Y if you have an original Sound Blaster card made by Creative - Labs or a 100% hardware compatible clone (like the Thunderboard or - SM Games). For an unknown card you may answer Y if the card claims - to be Sound Blaster-compatible. The PAS16 has 8-bit Soundblaster - support, so you can answer Y here for it. - - Please read the file Documentation/sound/Soundblaster. - - If you compile the driver into the kernel and don't want to use isapnp, - you have to add "sb=<io>,<irq>,<dma>,<dma2>" to the kernel command line. - - You can say M here to compile this driver as a module; the module is - called sb.o. - FM Synthesizer (YM3812/OPL-3) support CONFIG_SOUND_YM3812 Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). @@ -167,7 +145,7 @@ CONFIG_SOUND_TRACEINIT=y CONFIG_SOUND_DMAP=y CONFIG_SOUND_PAS=y -CONFIG_SOUND_SB=y +CONFIG_SOUND_SB=n CONFIG_SOUND_YM3812=m I have also included the following append line in /etc/lilo.conf: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sound/PCM1-pro linux.ac/Documentation/sound/PCM1-pro --- linux.vanilla/Documentation/sound/PCM1-pro Tue Apr 13 00:18:27 1999 +++ linux.ac/Documentation/sound/PCM1-pro Thu Jan 1 01:00:00 1970 @@ -1,17 +0,0 @@ -In Documentation/sound/README.OSS was a remark saying noone was sure the -mixer on the PCM1-pro worked with the ACI driver. Well, it does. -I've been using the drivers for the MAD16 and the driver for the mixer -since kernel 2.0.32 with a MiroSound PCM1-pro and it works great. - -I've got it working with the following configuration: - -MAD16 audio I/O base = 530 -MAD16 audio IRQ = 7 -MAD16 Audio DMA = 1 -MAD16 MIDI I/O = 330 -MAD16 MIDI IRQ = 9 - -And I've enabled the ACI mixer (miro PCM12) . - - -Bas van der Linden. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sound/README.OSS linux.ac/Documentation/sound/README.OSS --- linux.vanilla/Documentation/sound/README.OSS Fri Jul 28 20:50:52 2000 +++ linux.ac/Documentation/sound/README.OSS Thu Apr 12 11:48:29 2001 @@ -17,6 +17,7 @@ document can be still interesting and very helpful. [ File edited 17.01.1999 - Riccardo Facchetti ] +[ Edited miroSOUND section 17.09.2000 - Robert Siemer ] OSS/Free version 3.8 release notes ---------------------------------- @@ -1325,26 +1326,38 @@ miroSOUND --------- -The miroSOUND PCM12 has been used successfully. This card is based on -the MAD16, OPL4, and CS4231A chips and everything said in the section -about MAD16 cards applies here, too. The only major difference between -the PCM12 and other MAD16 cards is that instead of the mixer in the -CS4231 codec a separate mixer controlled by an on-board 80C32 -microcontroller is used. Control of the mixer takes place via the ACI -(miro's audio control interface) protocol that is implemented in a -separate lowlevel driver. Make sure you compile this ACI driver -together with the normal MAD16 support when you use a miroSOUND PCM12 -card. The ACI mixer is controlled by /dev/mixer and the CS4231 mixer -by /dev/mixer2. You usually don't want to change anything on the -CS4231 mixer. - -The miroSOUND PCM12 is capable of full duplex operation (simultaneous -PCM replay and recording), which allows you to implement nice -real-time signal processing audio effect software and network -telephones. The ACI mixer has to be configured into a special "solo" +The miroSOUND PCM1-pro, PCM12 and PCM20 radio has been used +successfully. This card is based on the MAD16, OPL4, and CS4231A chips +and everything said in the section about MAD16 cards applies here, +too. The only major difference between the PCMxx and other MAD16 cards +is that instead of the mixer in the CS4231 codec a separate mixer +controlled by an on-board 80C32 microcontroller is used. Control of +the mixer takes place via the ACI (miro's audio control interface) +protocol that is implemented in a separate lowlevel driver. Make sure +you compile this ACI driver together with the normal MAD16 support +when you use a miroSOUND PCMxx card. The ACI mixer is controlled by +/dev/mixer and the CS4231 mixer by /dev/mixer1 (depends on load +time). Only in special cases you want to change something on the CS4231 +mixer. + +The miroSOUND PCM12 and PCM20 radio is capable of full duplex +operation (simultaneous PCM replay and recording), which allows you to +implement nice real-time signal processing audio effect software and +network telephones. The ACI mixer has to be switched into the "solo" mode for duplex operation in order to avoid feedback caused by the -mixer (input hears output signal). See lowlevel/aci.c for details on -the ioctl() for activating the "solo" mode. +mixer (input hears output signal). You can de-/activate this mode +through toggleing the record button for the wave controller with an +OSS-mixer. + +The PCM20 contains a radio tuner, which is also controlled by +ACI. This radio tuner is supported by the ACI driver together with the +miropcm20.o module. Also the 7-band equalizer is integrated +(limited by the OSS-design). Developement has started and maybe +finished for the RDS decoder on this card, too. You will be able to +read radio text, the program service name, program type and +others. Even the v4l radio module benefits from it with a refined +strength value. See aci.c, radio-miropcm20.c and rds-miropcm20.c for +more details. The following configuration parameters have worked fine for the PCM12 in Markus Kuhn's system, many other configurations might work, too: @@ -1352,13 +1365,8 @@ CONFIG_MAD16_DMA2=0, CONFIG_MAD16_MPU_BASE=0x330, CONFIG_MAD16_MPU_IRQ=10, DSP_BUFFSIZE=65536, SELECTED_SOUND_OPTIONS=0x00281000. -The miroSOUND PCM1 pro and the PCM20 are very similar to the PCM12. -Perhaps the same ACI driver also works for these cards, however this -has never actually been tested. The PCM20 contains a radio tuner, -which is also controlled by ACI. This radio tuner is currently not -supported by the ACI driver, but documentation for it was provided by -miro and ACI tuner support could easily be added if someone is really -interested. +Bas van der Linden is using his PCM1-pro with a configuration that +differs in: CONFIG_MAD16_IRQ=7, CONFIG_MAD16_DMA=1, CONFIG_MAD16_MPU_IRQ=9 Compaq Deskpro XL ----------------- diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sound/es1370 linux.ac/Documentation/sound/es1370 --- linux.vanilla/Documentation/sound/es1370 Fri Jul 10 22:03:35 1998 +++ linux.ac/Documentation/sound/es1370 Thu Apr 12 11:48:29 2001 @@ -1,3 +1,11 @@ +/proc/sound, /dev/sndstat +------------------------- + +/proc/sound and /dev/sndstat is not supported by the +driver. To find out whether the driver succeeded loading, +check the kernel log (dmesg). + + ALaw/uLaw sample formats ------------------------ @@ -59,4 +67,4 @@ Thomas Sailer -sailer@ife.ee.ethz.ch +t.sailer@alumni.ethz.ch diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sound/es1371 linux.ac/Documentation/sound/es1371 --- linux.vanilla/Documentation/sound/es1371 Fri Jul 10 22:03:35 1998 +++ linux.ac/Documentation/sound/es1371 Thu Apr 12 11:48:29 2001 @@ -1,3 +1,11 @@ +/proc/sound, /dev/sndstat +------------------------- + +/proc/sound and /dev/sndstat is not supported by the +driver. To find out whether the driver succeeded loading, +check the kernel log (dmesg). + + ALaw/uLaw sample formats ------------------------ @@ -53,4 +61,4 @@ Thomas Sailer -sailer@ife.ee.ethz.ch +t.sailer@alumni.ethz.ch diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sound/solo1 linux.ac/Documentation/sound/solo1 --- linux.vanilla/Documentation/sound/solo1 Mon Aug 23 19:15:27 1999 +++ linux.ac/Documentation/sound/solo1 Thu Apr 12 11:48:29 2001 @@ -1,3 +1,25 @@ +Recording +--------- + +Recording does not work on the author's card, but there +is at least one report of it working on later silicon. +The chip behaves differently than described in the data sheet, +likely due to a chip bug. Working around this would require +the help of ESS (for example by publishing an errata sheet), +but ESS has not done so so far. + +Also, the chip only supports 24 bit addresses for recording, +which means it cannot work on some Alpha mainboards. + + +/proc/sound, /dev/sndstat +------------------------- + +/proc/sound and /dev/sndstat is not supported by the +driver. To find out whether the driver succeeded loading, +check the kernel log (dmesg). + + ALaw/uLaw sample formats ------------------------ @@ -45,4 +67,4 @@ The card has an OPL compatible FM synthesizer. Thomas Sailer -sailer@ife.ee.ethz.ch +t.sailer@alumni.ethz.ch diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sound/sonicvibes linux.ac/Documentation/sound/sonicvibes --- linux.vanilla/Documentation/sound/sonicvibes Fri Jul 10 22:03:35 1998 +++ linux.ac/Documentation/sound/sonicvibes Thu Apr 12 11:48:29 2001 @@ -1,3 +1,11 @@ +/proc/sound, /dev/sndstat +------------------------- + +/proc/sound and /dev/sndstat is not supported by the +driver. To find out whether the driver succeeded loading, +check the kernel log (dmesg). + + ALaw/uLaw sample formats ------------------------ @@ -70,4 +78,4 @@ Thomas Sailer -sailer@ife.ee.ethz.ch +t.sailer@alumni.ethz.ch diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sysctl/vm.txt linux.ac/Documentation/sysctl/vm.txt --- linux.vanilla/Documentation/sysctl/vm.txt Tue Apr 3 17:31:51 2001 +++ linux.ac/Documentation/sysctl/vm.txt Tue Apr 3 17:54:29 2001 @@ -21,6 +21,7 @@ - buffermem - freepages - kswapd +- max_map_count - overcommit_memory - page-cluster - pagecache @@ -171,6 +172,19 @@ and don't use much of it. Look at: mm/mmap.c::vm_enough_memory() for more information. + +============================================================== + +max_map_count: + +This file contains the maximum number of memory map areas a +process may have. Memory map areas are used as a side-effect +of calling malloc, directly by mmap and mprotect, and also +when loading shared libraries. + +While most applications need less than a thousand maps, +certain programs, particularly malloc debuggers, may consume +lots of them, e.g. up to one or two maps per allocation. ============================================================== diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sysrq.txt linux.ac/Documentation/sysrq.txt --- linux.vanilla/Documentation/sysrq.txt Tue Apr 3 17:31:51 2001 +++ linux.ac/Documentation/sysrq.txt Tue Apr 17 15:43:17 2001 @@ -1,26 +1,27 @@ +Linux Magic System Request Key Hacks +Documentation for sysrq.c version 1.15 +Last update: $Date: 2001/01/28 10:15:59 $ - MAGIC SYSRQ KEY DOCUMENTATION v1.32 - ------------------------------------ - [Sat Apr 8 22:15:03 CEST 2000] - -* What is the magic SysRQ key? +* What is the magic SysRq key? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -It is a 'magical' key combo you can hit which kernel will respond to +It is a 'magical' key combo you can hit which the kernel will respond to regardless of whatever else it is doing, unless it is completely locked up. -* How do I enable the magic SysRQ key? +* How do I enable the magic SysRq key? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You need to say "yes" to 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' when -configuring the kernel. This option is only available in 2.1.x or later -kernels. Once you boot the new kernel, you need to enable it manually -using following command: +configuring the kernel. When running on a kernel with SysRq compiled in, it +may be DISABLED at run-time using following command: + + echo "0" > /proc/sys/kernel/sysrq - echo "1" > /proc/sys/kernel/sysrq +Note that previous versions disabled sysrq by default, and you were required +to specifically enable it at run-time. That is not the case any longer. -* How do I use the magic SysRQ key? +* How do I use the magic SysRq key? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -On x86 - You press the key combo 'ALT-SysRQ-<command key>'. Note - Some - (older?) may not have a key labeled 'SysRQ'. The 'SysRQ' key is +On x86 - You press the key combo 'ALT-SysRq-<command key>'. Note - Some + keyboards may not have a key labeled 'SysRq'. The 'SysRq' key is also known as the 'Print Screen' key. On SPARC - You press 'ALT-STOP-<command key>', I believe. @@ -32,14 +33,14 @@ On Mac - Press 'Keypad+-F13-<command key>' On other - If you know of the key combos for other architectures, please - let me know so I can add them to this section. + let me know so I can add them to this section. * What are the 'command' keys? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'r' - Turns off keyboard raw mode and sets it to XLATE. -'k' - Secure Access Key (SAK) Kills all programs on the current virtual - console. NOTE: See important comments below in SAK section. +'k' - Secure Access Key (SAK) Kills all programs on the current virtual + console. NOTE: See important comments below in SAK section. 'b' - Will immediately reboot the system without syncing or unmounting your disks. @@ -69,8 +70,8 @@ 'l' - Send a SIGKILL to all processes, INCLUDING init. (Your system will be non-functional after this.) -'h' - Will display help ( actually any other key than those listed - above will display help. but 'h' is easy to remember :-) +'h' - Will display help ( actually any other key than those listed + above will display help. but 'h' is easy to remember :-) * Okay, so what can I use them for? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -82,8 +83,8 @@ and thus letting you make sure that the login prompt you see is actually the one from init, not some trojan program. IMPORTANT:In its true form it is not a true SAK like the one in :IMPORTANT -IMPORTATN:c2 compliant systems, and it should be mistook as such. :IMPORTANT - It seems other find it useful as (System Attention Key) which is +IMPORTANT:c2 compliant systems, and it should be mistook as such. :IMPORTANT + It seems other find it useful as (System Attention Key) which is useful when you want to exit a program that will not let you switch consoles. (For example, X or a svgalib program.) @@ -92,7 +93,7 @@ 'S'ync is great when your system is locked up, it allows you to sync your disks and will certainly lessen the chance of data loss and fscking. Note -that the sync hasn't taken place until you see the "OK" and "Done" appear +that the sync hasn't taken place until you see the "OK" and "Done" appear on the screen. (If the kernel is really in strife, you may not ever get the OK or Done message...) @@ -110,30 +111,72 @@ are unable to kill any other way, especially if it's spawning other processes. -* Sometimes SysRQ seems to get 'stuck' after using it, what can I do? +* Sometimes SysRq seems to get 'stuck' after using it, what can I do? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ That happens to me, also. I've found that tapping shift, alt, and control on both sides of the keyboard, and hitting an invalid sysrq sequence again will fix the problem. (ie, something like alt-sysrq-z). Switching to another virtual console (ALT+Fn) and then back again should also help. -* I hit SysRQ, but nothing seems to happen, what's wrong? +* I hit SysRq, but nothing seems to happen, what's wrong? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -There are some keyboards that send different scancodes for SysRQ than the -pre-defined 0x54. So if SysRQ doesn't work out of the box for a certain -keyboard, run 'showkey -s' to find out the proper scancode sequence. Then -use 'setkeycodes <sequence> 84' to define this sequence to the usual SysRQ +There are some keyboards that send different scancodes for SysRq than the +pre-defined 0x54. So if SysRq doesn't work out of the box for a certain +keyboard, run 'showkey -s' to find out the proper scancode sequence. Then +use 'setkeycodes <sequence> 84' to define this sequence to the usual SysRq code (84 is decimal for 0x54). It's probably best to put this command in a -boot script. Oh, and by the way, you exit 'showkey' by not typing anything +boot script. Oh, and by the way, you exit 'showkey' by not typing anything for ten seconds. +* I want to add SysRQ key events to a module, how does it work? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +In order to register a basic function with the table, you must first include +the header 'include/linux/sysrq.h', this will define everything else you need. +Next, you must create a sysrq_key_op struct, and populate it with A) the key +handler function you will use, B) a help_msg string, that will print when SysRQ +prints help, and C) an action_msg string, that will print right before your +handler is called. Your handler must conform to the protoype in 'sysrq.h'. + +After the sysrq_key_op is created, you can call the macro +register_sysrq_key(int key, struct sysrq_key_op *op_p) that is defined in +sysrq.h, this will register the operation pointed to by 'op_p' at table +key 'key', if that slot in the table is blank. At module unload time, you must +call the macro unregister_sysrq_key(int key, struct sysrq_key_op *op_p), which +will remove the key op pointed to by 'op_p' from the key 'key', if and only if +it is currently registered in that slot. This is in case the slot has been +overwritten since you registered it. + +The Magic SysRQ system works by registering key operations against a key op +lookup table, which is defined in 'drivers/char/sysrq.c'. This key table has +a number of operations registered into it at compile time, but is mutable, +and 4 functions are exported for interface to it: __sysrq_lock_table, +__sysrq_unlock_table, __sysrq_get_key_op, and __sysrq_put_key_op. The +functions __sysrq_swap_key_ops and __sysrq_swap_key_ops_nolock are defined +in the header itself, and the REGISTER and UNREGISTER macros are built fromi +these. More complex (and dangerous!) manipulations of the table are possible +using these functions, but you must be careful to always lock the table before +you read or write from it, and to unlock it again when you are done. (And of +course, to never ever leave an invalid pointer in the table). Null pointers in +the table are always safe :) + +If for some reason you feel the need to call the handle_sysrq function from +within a function called by handle_sysrq, you must be aware that you are in +a lock (you are also in an interupt handler, which means don't sleep!), so +you must call __handle_sysrq_nolock instead. + * I have more questions, who can I ask? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You may feel free to send email to myrdraal@deathsdoor.com, and I will -respond as soon as possible. +respond as soon as possible. -Myrdraal +And I'll answer any questions about the registration system you got, also +responding as soon as possible. + -Crutcher + * Credits ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Written by Mydraal <myrdraal@deathsdoor.com> Updated by Adam Sulmicki <adam@cfar.umd.edu> +Updated by Jeremy M. Dolan <jmd@turbogeek.org> 2001/01/28 10:15:59 +Added to by Crutcher Dunnavant <crutcher@redhat.com> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/video4linux/Zoran linux.ac/Documentation/video4linux/Zoran --- linux.vanilla/Documentation/video4linux/Zoran Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/video4linux/Zoran Tue Apr 3 17:54:29 2001 @@ -0,0 +1,517 @@ +DC10/DC10plus/LML33/Buz Driver for Linux +========================================= + +by Rainer Johanni <Rainer@Johanni.de> (for Iomega Buz Driver) + +Adapted for DC10/DC10plus by Wolfgang Scherr <scherr@net4you.net> + +Further changes for DC10/DC10plus and LML33 cards by +Serguei Miridonov <mirsev@cicese.mx> + +Current homepage: http://www.cicese.mx/~mirsev/Linux/DC10plus/ +Current maintainer: Serguei Miridonov <mirsev@cicese.mx> + + This is a driver for DC10plus capture cards from Pinnacle Systems + Inc., LML33 cards from Linux Media Labs and Buz from Iomega. + It also works with many old Miro DC10 cards with SAA7110A TV decoder + and ADV7176 TV encoder (please, make sure that your card has these + chips, otherwise the driver will not work). + + The driver is Video4Linux compliant and contains extensions to + provide hardware support for full motion MJPEG compression and + decompression. Since this driver is a derivative from the driver for + Buz Iomega cards written by Dr. Rainer Johanni, + http://www.johanni.de/munich-vision/buz/ they both have compatible + API. I hope that this API will become a part of V4L standard. + +Copyright: This driver is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License. Please, +check http://www.gnu.org/ for details. + +No warranty: This software is provided on AN "AS-IS" basis WITHOUT +WARRANTY OF ANY KIND. YOU USE IT AT YOUR OWN RISK. + + + +CONTENTS +~~~~~~~~ + +Supported Formats +Hardware compression +Compiling and Loading the Driver +Driver Options +Tested applications +Programming interface +Features for testing +Mailing lists +Bug Reports + + +Supported Formats +================= + +Card: DC10/DC10plus LML33/Buz + +TV standard: NTSC/PAL/SECAM(*) NTSC/PAL + +Format: Square pixel CCIR.601 + 640x480 NTSC 720x480 NTSC + 768x576 PAL/SECAM(*) 720x576 PAL + +Frame rates: 30 frames/60 fields per second NTSC + 25 frames/50 fields per second PAL/SECAM(*) + +(*) - SECAM is supported for input only in DC10/DC10plus cards. The +output of the recorded SECAM video stream will be in PAL standard. +Also, please, note that monitoring of the SECAM input signal at the +DC10/DC10plus analog output may not be available. Please, use +appropriate application like XawTV to watch full color SECAM video at +the card input. + +Hardware compression +==================== + +Since the card provides hardware compression, even low end machines can +be successfully used for movie capture and playback. I'm testing the +driver with with 2.2.16 kernel running on 233 MHz Pentium MMX with 64M +RAM on 430TX motherboard and with 10GB IDE drive from Western Digital +Corp. + +On one test run with DC10plus card I've got 0 frames dropped during +about 20 minutes of full motion NTSC (I live in Mexico) video capture +with fully synchronized audio. The command was + + lavrec -fa -in -d1 -l -1 -q30 -w /dos/g/capture/Linux/test%03d.avi + +for recording, and + + lavplay -n128 /dos/g/capture/Linux/test*.avi + +for playback. (See lavtools distribution for more information). + +Typical run of similar test can provide as few as 6-8 dropped frames per +half of an hour. You mileage may vary, though. + +Compiling and Loading the Driver +================================ + +You should run a 2.2.x kernel in order to use this driver. The driver +was also tested with 2.4-test6 kernel, so hopefully it will work +with 2.4 kernels too. + +I would recommend to use only official kernels from www.kernel.org and +its mirrors. Kernels supplied with some Linux distributions may be +patched in some way to meet specific needs of particular Linux +distributor and could be incompatible with this driver. As a driver +maintainer, I am not able to follow every unofficial kernel release, +and no unofficial kernels will be supported. + +Besides the files in this directory, the driver needs the 'videodev' +and the 'i2c' module from the Linux kernel (i2c-old for 2.4 kernels). +In order to get these modules available, enable module support for +VIDEODEV and BTTV (which implies i2c) in your 2.2.x kernel +configuration. You will find these devices in the menu "Character +Devices" in your Kernel Configuration. + +In newer kernels (2.4) instead of BTTV you should enable support for +Iomega Buz cards and for Zoran 36060/36067 chipset. This will include +i2c or i2c-old modules and Buz/LML33 driver. However, instead of +modules for Buz/LML33 driver from the kernel, use modules from _this_ +driver. + +To compile the driver, just type make. + +Before you load the driver you must have a video device at major device +node 81. If you don't have it yet, do the following (as root!): + +cd /dev +mknod video0 c 81 0 +ln -s video0 video + +If you have more than one card, add more nodes in /dev directory: + +mknod video1 c 81 1 +mknod video2 c 81 2 +... + +The driver should operate properly with several cards. It was tested +with one DC10plus and one LML33 cards installed together and the driver +correctly identifies both cards and works with both of them. + +Currently the driver does not support LML33 and Buz cards installed +together in the same system. This will be fixed in future versions. + +Edit the 'update' script if you want to give the driver special options +(see below for options descriptions) and then type (as root) + +./update <card_list> + +to insert all necessary modules into the kernel. <card_list> is a list of +cards installed in your system separated by white space. Supported cards +are dc10, dc10plus, lml33, and buz. For example, if you have both dc10plus +and lml33 cards, please type + +./update dc10 lml33 + +If you want to make full use of the Video for Linux _uncompressed_ +grabbing facilities, you must either + +- obtain and install the "big_physarea patch" for your kernel and + set aside the necessary memory during boot time. There seem to be + several versions of this patch against various kernel versions + floating around in the net, you may obtain one e.g. from: + http://www.polyware.nl/~middelin/patch/bigphysarea-2.2.1.tar.gz You + also have to compile your driver AFTER installing that patch in order + to get it working + + or + +- start your kernel with the mem=xxx option, where xxx is your + real memory minus the memory needed for the buffers. + For doing this add an entry in lilo.conf (if you use lilo): + append "mem=xxxM" + or add a line in your linux.par file (if you use loadlin): + mem=xxxM + +The second method is by far easier, however it is dangerous if more +than one driver at a time has the idea to use the memory leftover by +setting the mem=xxx parameter below the actual memory size. + +Read also below how to use this memory! + + + If you use only MJPEG compressed capture provided by the driver, you + should not need large memory areas for DMA. In this case, you will be + able to capture and playback movies with lavtools, however you will + not be able to use capture features of XawTV and other similar + programs (you can still watch video on the screen). + + + +Driver Options +============== + +You are able to customize the behavior of the driver by giving +it some options at start time. + +default_input, default_norm +--------------------------- + +As soon as the driver is loaded, the Buz samples video signals +from one of its input ports and displays it on its output. +The driver uses the Composite Input and the video norm PAL for this. +If you want to change this default behavior, set default_input=1 +(for S-VHS input) or default_norm=1 for NTSC or default_norm=2 +for SECAM (DC10/DC10plus only). + +lock_norm +--------- + +This option was introduced to disable norm (TV standard) change by some +not well behaving programs. For example, if you have some application +which was written by somebody who lives in a country with PAL standard, +this program may not have NTSC option and may always try to set the +driver to PAL. In this case, you may load the driver with +default_norm=1 and lock_norm=1 and the card will be forced to work in +NTSC standard only. + + Options: + + lock_norm=0 default, TV standard change is enabled; + lock_norm=1 TV standard change is disabled but the driver + will not notify the application about any error; + lock_norm=2 TV standard change is disabled and the driver + will notify the program that TV standards other + than set by default_norm=X option are not + supported. + +pass_through +------------ + +When the driver is not in use (device is not opened by any program) and +pass_through=0 (default) the driver will set the TV encoder to produce +color bar signal at the output. If the driver was loaded with +pass_through=1, the color bar will be disabled and input signal will be +sent to the output even if the driver not in use. If you have LML33 card +and wish the color bar signal at the output, you will also need to set +lml33dpath=1 (please, see next section). + +lml33dpath +---------- + +LML33 card normally (lml33dpath=0) connects its output to the input +using analog switch. Additionally, it also allows real-time monitoring +of digitized video using TV monitor connected to the output. This +"digital path" option can be enabled setting lml33dpath=1. In this +mode, the input is connected only to the TV decoder, digital video data +is sent via internal video bus to the TV encoder and resulting analog +signal is sent to the output. This mode could be very useful for testing and +picture adjustment while watching video at the TV monitor connected to +the output. However, because of lack of 75 ohm terminating resistors at +TV decoder input, the signal will suffer serious distortions. + +# These distortions could be eliminated by soldering two 75 ohm resistors +# in LML33 card: in parallel to capacitors C73 and C82 (see schematics of +# H33 board available at www.linuxmedialabs.com and www.zoran.com). Be +# aware, however, that doing so will void card warranty and the card, +# after this change, must always be used with loading option lml33dpath=1. +# +# WARNING: I DID NOT TRY THIS CARD CHANGE YET, THIS IS JUST AN ASSUMPTION +# AND I WILL NOT BE RESPONSIBLE FOR ANY DAMAGE ASSOCIATED WITH THIS +# CHANGE. IF YOU WISH TO TRY IT, DO IT AT YOUR OWN RISK. + +Please, note that DC10/DC10plus cards always use "digital path" for +signal monitoring. Its input and output are both properly terminated +and the digitized signal quality does not depend on the connection of +the output load. + + +v4l_nbufs, v4l_bufsize +---------------------- + +In order to make to make full use of the Video for Linux uncompressed +picture grabbing facilities of the driver (which are needed by many +Video for Linux applications), the driver needs a set of physically +contiguous buffers for grabbing. These parameters determine how many +buffers of which size the driver will allocate at open (the open will +fail if it is unable to do so!). + +These values do not affect the MJPEG grabbing facilities of the driver, +they are needed for uncompressed image grabbing only!!! + +v4l_nbufs is the number of buffers to allocate, a value of 2 (the default) +should be sufficient in almost all cases. Only special applications +(streaming captures) will need more buffers and then mostly the +MJPEG capturing features of the Buz will be more appropriate. +So leave this parameter at it's default unless you know what you do. + +The things for v4l_bufsize are more complicated: v4l_bufsize is set by +default to 128 [KB] which is the maximum amount of physically +contiguous memory Linux is able to allocate without kernel changes. +This is sufficient for grabbing 24 bit color images up to sizes of +approx. 240x180 pixels (240*180*3 = 129600, 128 KB = 131072). + +In order to be able to capture bigger images you have either to +- obtain and install the "big_physarea patch" and set aside + the necessary memory during boot time or +- start your kernel with the mem=xxx option, where xxx is your + real memory minus the memory needed for the buffers. +In that case, useful settings for v4l_bufsize are +- 1296 [Kb] for grabbing 24 bit images of max size 768*576 +- 1728 [Kb] for 32bit images of same size (4*768*576 = 1728 Kb!) +You may reduce these numbers accordingly if you know you are only +grabbing 720 pixels wide images or NTSC images (max height 480). + +In some cases it may happen that Linux isn't even able to obtain +the default 128 KB buffers. If you don't need uncompressed image +grabbing at all, set v4l_bufsize to an arbitrary small value (e.g. 4) +in order to be able to open the video device. + +triton, natoma +-------------- + +The driver tries to detect if you have a triton or natoma chipset +in order to take special measures for these chipsets. +If this detection fails but you are sure you have such a chipset, +set the corresponding variable to 1. +This is a very special option and may go away in the future. + + +Tested applications +=================== + + XawTV to watch video on your computer monitor. + + kwintv the same (you might need to use option lock_norm=1). + + lavtools To record and playback AVI or Quicktime files. Note: you + will need patched version, lavtools-1.2p2 to support new + features of this driver. Please visit driver homepage for + more info. + + Broadcast2000 reportedly (I didn't try that) can accept movies recorded + by lavrec in Quicktime format for editing and then edited + movie can be played back by lavplay program. + + MainActor 3.5x also can accept movies recorded by lavrec for editing. + + +The driver can to be used by two programs at the same time +(please, see warning note below regarding this feature). Using XawTV +you can watch what you are recording or playing back with lavtools. +I've tested the following sequence and it worked for me: + +* start xawtv and switch inputs, TV standards, and adjust video + (contrast, saturation, etc.). You may also run your favorite + audio mixer application to adjust audio inputs. + +* run lavrec with options: + + -i<set your input and norm here> (to choose proper input + and TV standard) + + -l -1 (to use audio mixer settings) + + Other lavrec option can be added at your choice. + +* watch the movie in xawtv window while recording it as AVI or + Quicktime file. + +* when recording is finished, run lavplay or xlav and watch your + clip in xawtv window. + +* Note: you should not quit xawtv during recording or playing back. + If you quit xawtv during recording or playback, another lavtools + program will stop and may even crash. + +I'm not sure that the same will work for you. You can try but, +please, be careful. + +WARNING! This is an experimental feature and I'm not sure if it will be +supported in the future. The original driver was not designed to be +used like this and it has no protection against any interference +between two running programs. THEREFORE, IT IS POTENTIALLY DANGEROUS +AND SINCE THE DRIVER OPERATES IN KERNEL SPACE, USING THIS FEATURE MAY +CRASH YOUR ENTIRE SYSTEM. + + +Programming interface +===================== + +This driver should be fully compliant to Video for Linux, so all +tools working with Video for Linux should work with (hopefully) +no problems. + +A description of the Video for Linux programming interface can be found at: +http://roadrunner.swansea.linux.org.uk/v4lapi.shtml + +Besides the Video for Linux interface, the driver has a "proprietary" +interface for accessing the Buz's MJPEG capture and playback facilities. + +For a full description of all members and ioctls see "zoran.h" (used to +be buz.h or dc10.h in previous versions, so, please, update your +programs accordingly). + +The ioctls for that interface are as follows: + +BUZIOC_G_PARAMS +BUZIOC_S_PARAMS + +Get and set the parameters of the buz. The user should always do a +BUZIOC_G_PARAMS (with a struct buz_params) to obtain the default +settings, change what he likes and then make a BUZIOC_S_PARAMS call. + +BUZIOC_REQBUFS + +Before being able to capture/playback, the user has to request +the buffers he is wanting to use. Fill the structure +zoran_requestbuffers with the size (recommended: 256*1024) and +the number (recommended 32 up to 256). There are no such restrictions +as for the Video for Linux buffers, you should LEAVE SUFFICIENT +MEMORY for your system however, else strange things will happen .... +On return, the zoran_requestbuffers structure contains number and +size of the actually allocated buffers. +You should use these numbers for doing a mmap of the buffers +into the user space. +The BUZIOC_REQBUFS ioctl also makes it happen, that the next mmap +maps the MJPEG buffer instead of the V4L buffers. + +BUZIOC_QBUF_CAPT +BUZIOC_QBUF_PLAY + +Queue a buffer for capture or playback. The first call also starts +streaming capture. When streaming capture is going on, you may +only queue further buffers or issue syncs until streaming +capture is switched off again with a argument of -1 to +a BUZIOC_QBUF_CAPT/BUZIOC_QBUF_PLAY ioctl. + +BUZIOC_SYNC + +Issue this ioctl when all buffers are queued. This ioctl will +block until the first buffer becomes free for saving its +data to disk (after BUZIOC_QBUF_CAPT) or for reuse (after BUZIOC_QBUF_PLAY). + +BUZIOC_G_STATUS + +Get the status of the input lines (video source connected/norm). +This ioctl may be subject to change. + +For programming example, please, look at lavrec.c and lavplay.c code in +lavtools-1.2p2 package (URL: http://www.cicese.mx/~mirsev/DC10plus/) +and the 'examples' directory in the original Buz driver distribution. + +Additional notes for software developers: + + The driver returns maxwidth and maxheight parameters according to + the current TV standard (norm). Therefore, the software which + communicates with the driver and "asks" for these parameters should + first set the correct norm. Well, it seems logically correct: TV + standard is "more constant" for current country than geometry + settings of a variety of TV capture cards which may work in ITU or + square pixel format. Remember that users now can lock the norm to + avoid any ambiguity. + +Features for testing +==================== + +When loaded, the driver creates a /proc/zoranX entry for each card: +using 'cat /proc/zoran0' for your first card you can see the contents +of ZR36057/67 chip registers. It is also possible to modify the +contents of some registers directly. WARNING: modified contents is not +stored in the driver memory, if you restart any program which uses this +driver or even change position or cause redraw of a window of xawtv or +other program, the original registers contents will be restored by the +driver. However, it can be used to change ZR36067 registers on the fly +for fine tuning and then to include these changes into driver code. +This feature is very limited and still requires some documentation. +However, if you are impatient, look at zoran_procfs.c code and +(IMPORTANT!) read ZR36057/67 manual. To set TopField bit, for example, +you need to type as root: + +echo TopField=1 > /proc/zoranX # change X to 0 for your first card, + # 1 for second and so on... + +If you use this feature and have found some interesting result, please, let +me know. + +Mailing lists +============= + +There are two mailing lists available to discuss application issues and +suggest driver improvements: + +1. A mailing list buz-linux was set up to discuss Iomega Buz driver. +Since this driver is derivative of that driver, you can also post your +questions and suggestions there. Subscribe with a message (with +"subscribe" in the subject) to buz-linux-subscribe@webmages.com. +Unsubscribe with a message (with "unsubscribe" in the subject) to +buz-linux-unsubscribe@webmages.com. The mailing list archive can be +found at http://buz.webmages.com/list/. + +2. Video4Linux mailing list is set for more general discussions related +to uncompressed video capture, V4L and V4L2 API, many Video4Linux +applications, etc. to subscribe to this mailing list, please, visit +https://listman.redhat.com/mailman/listinfo/video4linux-list + +Bug Reports +=========== + +If you have found a bug, please, do the following: + +1. Edit first line of zoran.c file and set DEBUGLEVEL to 3; +2. Recompile the driver and install it running update script + in the driver directory; +3. Run the application(s) which you used when you had found a + suspisious behavior; +4. When application stops, look at you /var/log/messages file + (or whatever file you use to log kernel messages) and copy + all lines related to the driver activity to a separate file + in the same order of their appearence in your log file. +5. Mail a message to <mirsev@cicese.mx> with a subject + "Linux DC10(plus)/LML33/Buz driver bug report" with a detailed + description of your problem, kernel version, application name and + attach that file with kernel messages as plain text (please, don't + attach it using base64, uuencode, or any other encoding). + + If you have a Buz card, please, also mail the same message to + Wolfgang Scherr <scherr@net4you.net> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/video4linux/w9966.txt linux.ac/Documentation/video4linux/w9966.txt --- linux.vanilla/Documentation/video4linux/w9966.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/video4linux/w9966.txt Tue Apr 3 23:40:38 2001 @@ -0,0 +1,37 @@ + +W9966 Camera driver, written by Jakob Kemi (jakob.kemi@post.utfors.se) + +Ok, after a lot of work in softice, wdasm, reading pdf-files +and trial-and-error work I've finally got everything to work. +Since I needed some vision for a robotics project I borrowed +this camera from a friend and started hacking. Anyway I've +converted my original code from the AVR 8bit RISC C/asm +into a working linux driver. I would really appreciate _any_ +kind of feedback regarding this driver. + +To get it working quickly configure your kernel +to support parport, ieee1284, video4linux, experimental drivers +and w9966 + +If w9966 is statically linked it will perform aggressive probing +for the camera. If built as a module you have more configuration options. + +Options: +modprobe w9966.o pardev=parport0(or whatever) parmode=0 rgb=1(or 0 if + your programs can handle 16bit yuv422, which is faster) + +voila! + +you can also type 'modinfo -p w9966.o' for option usage +(or checkout w9966.c) + +I've only tested it with custom built testprograms and with gqcam. +(you'll need to change the w9966_v4l_ioctl function to report max +dimensions of 200x200 for gqcam to work) + +The slow framerate is due to missing DMA ECP read support in the +parport drivers. I might add EPP support later. + +Good luck! + + /Jakob diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/MAINTAINERS linux.ac/MAINTAINERS --- linux.vanilla/MAINTAINERS Tue Apr 3 17:31:51 2001 +++ linux.ac/MAINTAINERS Sat Apr 14 01:14:35 2001 @@ -106,6 +106,13 @@ L: linux-net@vger.kernel.org S: Maintained +ACI MIXER DRIVER +P: Robert Siemer +M: Robert.Siemer@gmx.de +L: linux-sound@vger.kernel.org +W: http://www.uni-karlsruhe.de/~Robert.Siemer/Private/ +S: Maintained + ACPI P: Andy Grover M: andrew.grover@intel.com @@ -141,9 +148,9 @@ APM DRIVER P: Stephen Rothwell -M: apm@linuxcare.com.au +M: sfr@canb.auug.org.au L: linux-laptop@vger.kernel.org -W: http://linuxcare.com.au/apm/ +W: http://www.canb.auug.org.au/~sfr/ S: Supported APPLETALK NETWORK LAYER @@ -293,6 +300,13 @@ M: jam@acm.org S: Maintained +CRIS PORT +P: Bjorn Wesen +M: bjornw@axis.com +L: dev-etrax@axis.com +W: http://developer.axis.com +S: Maintained + CYBERPRO FB DRIVER P: Russell King M: linux@arm.linux.org.uk @@ -368,7 +382,7 @@ DIRECTORY NOTIFICATION P: Stephen Rothwell -M: sfr@linuxcare.com.au +M: sfr@canb.auug.org.au L: linux-kernel@vger.kernel.org S: Supported @@ -398,6 +412,12 @@ L: dri-devel@lists.sourceforge.net S: Supported +DSCC4 DRIVER +P: François Romieu +M: romieu@cogenit.fr +M: romieu@ensta.fr +S: Maintained + EATA-DMA SCSI DRIVER P: Michael Neuffer M: mike@i-Connect.Net @@ -490,6 +510,12 @@ W: http://www.icp-vortex.com/ S: Supported +GENERIC HDLC DRIVER, N2 AND C101 DRIVERS +P: Krzysztof Halasa +M: khc@pm.waw.pl +W: http://hq.pm.waw.pl/hdlc/ +S: Maintained + HAYES ESP SERIAL DRIVER P: Andrew J. Robinson M: arobinso@nyx.net @@ -535,7 +561,7 @@ HIPPI P: Jes Sorensen -M: Jes.Sorensen@cern.ch +M: jes@linuxcare.com L: linux-hippi@sunsite.auc.dk S: Maintained @@ -600,7 +626,14 @@ W: http://www.kernel.dk S: Maintained -IDE/ATAPI TAPE/FLOPPY DRIVERS +IDE/ATAPI FLOPPY DRIVERS +P: Paul Bristow +M: Paul Bristow <paul@paulbristow.net> +W: http://paulbristow.net/linux/idefloppy.html +L: linux-kernel@vger.kernel.org +S: Maintained + +IDE/ATAPI TAPE DRIVERS P: Gadi Oxman M: Gadi Oxman <gadio@netvision.net.il> L: linux-kernel@vger.kernel.org @@ -750,14 +783,14 @@ LINUX FOR POWER MACINTOSH P: Paul Mackerras -M: paulus@linuxcare.com +M: paulus@samba.org W: http://www.linuxppc.org/ L: linuxppc-dev@lists.linuxppc.org S: Maintained M68K P: Jes Sorensen -M: Jes.Sorensen@cern.ch +M: jes@linuxcare.com W: http://www.clark.net/pub/lawrencc/linux/index.html L: linux-m68k@lists.linux-m68k.org S: Maintained @@ -775,7 +808,7 @@ W: http://www.tazenda.demon.co.uk/phil/linux-hp S: Maintained -MAESTRO PCI SOUND DRIVER +MAESTRO PCI SOUND DRIVERS P: Zach Brown M: zab@zabbo.net S: Odd Fixes @@ -787,6 +820,12 @@ L: mtd@infradead.org S: Maintained +MICROTEK X6 SCANNER +P: Oliver Neukum +M: drivers@neukum.org +W: http://fachschaft.cup.uni-muenchen.de/~neukum/scanner.html +S: Maintained + MIPS P: Ralf Baechle M: ralf@gnu.ai.mit.edu @@ -837,10 +876,14 @@ NETFILTER P: Rusty Russell -M: rusty@linuxcare.com +M: rusty@rustcorp.com.au P: Marc Boucher M: marc@mbsi.ca -W: http://www.samba.org/netfilter/ +P: James Morris +M: jamesm@intercode.com.au +P: Harald Welte +M: laforge@gnumonks.org +W: http://netfilter.samba.org W: http://netfilter.kernelnotes.org W: http://netfilter.filewatcher.org L: netfilter@lists.samba.org @@ -904,8 +947,9 @@ NTFS FILESYSTEM P: Anton Altaparmakov M: aia21@cus.cam.ac.uk +L: linux-ntfs-dev@lists.sourceforge.net L: linux-kernel@vger.kernel.org -S: Odd Fixes +S: Maintained NVIDIA (RIVA) FRAMEBUFFER DRIVER P: Ani Joshi @@ -997,7 +1041,7 @@ PPP PROTOCOL DRIVERS AND COMPRESSORS P: Paul Mackerras -M: paulus@linuxcare.com +M: paulus@samba.org L: linux-ppp@vger.kernel.org S: Maintained @@ -1037,6 +1081,13 @@ L: linux-kernel@vger.kernel.org S: Maintained +REISERFS FILE SYSTEM +P: Hans Reiser +M: reiserfs-dev@namesys.com +L: reiserfs-list@namesys.com +W: http://www.namesys.com +S: Supported + ROSE NETWORK LAYER P: Jean-Paul Roubelat M: jpr@f6fbb.org @@ -1056,6 +1107,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 + SA1100 SUPPORT P: Nicolas Pitre M: nico@cam.org @@ -1174,6 +1233,11 @@ W: http://www.stallion.com S: Supported +STARFIRE/DURALAN NETWORK DRIVER +P: Ion Badulescu +M: ionut@cs.columbia.edu +S: Maintained + STARMODE RADIO IP (STRIP) PROTOCOL DRIVER W: http://mosquitonet.Stanford.EDU/strip.html S: Unsupported ? @@ -1302,6 +1366,13 @@ S: Maintained W: http://www.kroah.com/linux-usb/ +USB CDC ETHERNET DRIVER +P: Brad Hards +M: bhards@bigpond.net.au +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +S: Maintained + USB HID/HIDBP/INPUT DRIVERS P: Vojtech Pavlik M: vojtech@suse.cz @@ -1318,6 +1389,13 @@ L: linux-usb-devel@lists.sourceforge.net S: Maintained +USB KAWASAKI LSI DRIVER +P: Brad Hards +M: bhards@bigpond.net.au +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +S: Maintained + USB OHCI DRIVER P: Roman Weissgaerber M: weissg@vienna.at @@ -1357,11 +1435,11 @@ USB SERIAL KEYSPAN DRIVER P: Hugh Blemings -M: hugh@linuxcare.com +M: hugh@misc.nu 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 +W: http://misc.nu/hugh/keyspan/ USB SERIAL DRIVER P: Greg Kroah-Hartman @@ -1401,6 +1479,14 @@ L: linux-usb-devel@lists.sourceforge.net W: http://usb.in.tum.de S: Maintained + +USER-MODE PORT +P: Jeff Dike +M: jdike@karaya.com +L: user-mode-linux-devel@lists.sourceforge.net +L: user-mode-linux-user@lists.sourceforge.net +W: http://user-mode-linux.sourceforge.net +S: Maintained VFAT FILESYSTEM: P: Gordon Chaffee @@ -1430,8 +1516,8 @@ S: Maintained for 2.2 only WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC) -P: Jaspreet Singh -M: jaspreet@sangoma.com +P: Nenad Corbic +M: ncorbic@sangoma.com M: dm@sangoma.com W: http://www.sangoma.com S: Supported @@ -1457,6 +1543,12 @@ X86 3-LEVEL PAGING (PAE) SUPPORT P: Ingo Molnar M: mingo@redhat.com +S: Maintained + +YAM DRIVER FOR AX.25 +P: Jean-Paul Roubelat +M: jpr@f6fbb.org +L: linux-hams@vger.kernel.org S: Maintained Z85230 SYNCHRONOUS DRIVER diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Makefile linux.ac/Makefile --- linux.vanilla/Makefile Tue Apr 3 17:31:52 2001 +++ linux.ac/Makefile Tue Apr 17 20:54:59 2001 @@ -1,11 +1,18 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 3 -EXTRAVERSION = +EXTRAVERSION = -ac8 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) -ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) +# SUBARCH tells the usermode build what the underlying arch is. That is set +# first, and if a usermode build is happening, the "ARCH=um" on the command +# line overrides the setting of ARCH below. If a native build is happening, +# then ARCH is assigned, getting whatever value it gets normally, and +# SUBARCH is subsequently ignored. + +SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) +ARCH := $(SUBARCH) CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ else if [ -x /bin/bash ]; then echo /bin/bash; \ @@ -144,7 +151,7 @@ DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.o DRIVERS-$(CONFIG_IDE) += drivers/ide/idedriver.o DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsidrv.o -DRIVERS-$(CONFIG_SCSI_AIC7XXX) += drivers/scsi/aic7xxx/aic7xxx_drv.o +DRIVERS-$(CONFIG_FUSION_BOOT) += drivers/message/fusion/fusion.o DRIVERS-$(CONFIG_IEEE1394) += drivers/ieee1394/ieee1394drv.o ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),) @@ -171,7 +178,7 @@ DRIVERS-$(CONFIG_TC) += drivers/tc/tc.a DRIVERS-$(CONFIG_USB) += drivers/usb/usbdrv.o DRIVERS-$(CONFIG_INPUT) += drivers/input/inputdrv.o -DRIVERS-$(CONFIG_I2O) += drivers/i2o/i2o.o +DRIVERS-$(CONFIG_I2O) += drivers/message/i2o/i2o.o DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o @@ -330,14 +337,14 @@ TAGS: dummy etags `find include/asm-$(ARCH) -name '*.h'` find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print | xargs etags -a - find $(SUBDIRS) init -name '*.c' | xargs etags -a + find $(SUBDIRS) init -name '*.[ch]' | xargs etags -a # Exuberant ctags works better with -I tags: dummy CTAGSF=`ctags --version | grep -i exuberant >/dev/null && echo "-I __initdata,__exitdata,EXPORT_SYMBOL,EXPORT_SYMBOL_NOVERS"`; \ ctags $$CTAGSF `find include/asm-$(ARCH) -name '*.h'` && \ find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print | xargs ctags $$CTAGSF -a && \ - find $(SUBDIRS) init -name '*.c' | xargs ctags $$CTAGSF -a + find $(SUBDIRS) init -name '*.[ch]' | xargs ctags $$CTAGSF -a ifdef CONFIG_MODULES ifdef CONFIG_MODVERSIONS @@ -493,7 +500,7 @@ # scripts/mkdep: scripts/mkdep.c - $(HOSTCC) $(HOSTCFLAGS) -o scripts/mkdep scripts/mkdep.c + $(HOSTCC) $(HOSTCFLAGS) -g -o scripts/mkdep scripts/mkdep.c scripts/split-include: scripts/split-include.c $(HOSTCC) $(HOSTCFLAGS) -o scripts/split-include scripts/split-include.c diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/REPORTING-BUGS linux.ac/REPORTING-BUGS --- linux.vanilla/REPORTING-BUGS Mon Aug 21 16:57:35 2000 +++ linux.ac/REPORTING-BUGS Tue Apr 10 18:04:40 2001 @@ -25,10 +25,9 @@ overlook things, and easier for the developers to find the pieces of information they're really interested in. Don't feel you have to follow it. - First run the ver_linux script included as scripts/ver_linux or -at <URL:ftp://ftp.sai.msu.su/pub/Linux/ver_linux> It checks out -the version of some important subsystems. Run it with the command -"sh scripts/ver_linux" + First run the ver_linux script included as scripts/ver_linux, which +reports the version of some important subsystems. Run this script with +the command "sh scripts/ver_linux". Use that information to fill in all fields of the bug report form, and post it to the mailing list with a subject of "PROBLEM: <one line diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/acpi-20010413.diff linux.ac/acpi-20010413.diff --- linux.vanilla/acpi-20010413.diff Thu Jan 1 01:00:00 1970 +++ linux.ac/acpi-20010413.diff Tue Apr 17 16:37:12 2001 @@ -0,0 +1,72741 @@ +diff -Naur -X bin/dontdiff /usr/src/linux/Documentation/Configure.help linux/Documentation/Configure.help +--- /usr/src/linux/Documentation/Configure.help Sun Mar 25 18:24:31 2001 ++++ linux/Documentation/Configure.help Wed Apr 11 14:33:51 2001 +@@ -13456,7 +13456,7 @@ + will issue the hlt instruction if nothing is to be done, thereby + sending the processor to sleep and saving power. + +-ACPI Support ++ACPI support + CONFIG_ACPI + ACPI/OSPM support for Linux is currently under development. As such, + this support is preliminary and EXPERIMENTAL. Configuring ACPI support +@@ -13485,6 +13485,56 @@ + + The ACPI mailing list may also be of interest: + http://phobos.fs.tum.de/acpi/index.html ++ ++ACPI Debug Statements ++CONFIG_ACPI_DEBUG ++ The ACPI driver can optionally report errors with a great deal ++ of verbosity. Saying Y enables these statements. This will increase ++ your kernel size by around 50K. ++ ++ACPI Bus Manager ++CONFIG_ACPI_BUSMGR ++ The ACPI Bus Manager enumerates devices in the ACPI namespace, and ++ handles PnP messages. All ACPI devices use its services, so using them ++ requires saying Y here. ++ ++ACPI System Driver ++CONFIG_ACPI_SYS ++ This driver will enable your system to shut down using ACPI. ++ ++ACPI Processor Driver ++CONFIG_ACPI_CPU ++ This driver installs ACPI as the idle handler for Linux, and uses ACPI ++ C2 and C3 processor states to save power, on systems that support it. ++ ++ACPI Button ++CONFIG_ACPI_BUTTON ++ This driver registers for events based on buttons, such as the power, ++ sleep, and lid switch. In the future, a daemon will read ++ /proc/acpi/event and perform user-defined actions such as shutting ++ down the system, but until then, you can cat it, and see output when ++ a button is pressed. ++ ++ACPI AC Adapter ++CONFIG_ACPI_AC ++ This driver adds support for the AC Adapter object, which indicates ++ whether a system is on AC, or not. Typically, only laptops have this ++ object, since desktops are always on AC. ++ ++ACPI Embedded Controller ++CONFIG_ACPI_EC ++ This driver is required on some systems for the proper operation of the ++ battery and thermal drivers. If you are compiling for a laptop, say Y. ++ ++ACPI Control Method ++CONFIG_ACPI_CMBATT ++ This driver adds support for battery information through ++ /proc/acpi/battery. If you have a laptop with a battery, say Y. ++ ++ACPI Thermal ++CONFIG_ACPI_THERMAL ++ This driver handles overheating conditions on laptops. It is HIGHLY ++ recommended, as your laptop CPU may be damaged without it. + + Advanced Power Management BIOS support + CONFIG_APM +diff -Naur -X bin/dontdiff /usr/src/linux/arch/i386/config.in linux/arch/i386/config.in +--- /usr/src/linux/arch/i386/config.in Mon Jan 8 13:27:56 2001 ++++ linux/arch/i386/config.in Mon Apr 2 15:39:51 2001 +@@ -231,6 +231,10 @@ + + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_bool ' ACPI support' CONFIG_ACPI $CONFIG_PM ++ ++ if [ "$CONFIG_ACPI" != "n" ]; then ++ source drivers/acpi/Config.in ++ fi + fi + + dep_tristate ' Advanced Power Management BIOS support' CONFIG_APM $CONFIG_PM +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/Config.in linux/drivers/acpi/Config.in +--- /usr/src/linux/drivers/acpi/Config.in Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/Config.in Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,17 @@ ++# ++# ACPI configuration ++# ++#mainmenu_option next_comment ++#comment 'ACPI Configuration' ++ ++dep_bool ' ACPI Debug Statements' CONFIG_ACPI_DEBUG $CONFIG_ACPI ++dep_tristate ' ACPI Bus Manager' CONFIG_ACPI_BUSMGR $CONFIG_ACPI ++ ++dep_tristate ' System' CONFIG_ACPI_SYS $CONFIG_ACPI_BUSMGR $CONFIG_ACPI ++dep_tristate ' Processor' CONFIG_ACPI_CPU $CONFIG_ACPI_BUSMGR $CONFIG_ACPI ++dep_tristate ' Button' CONFIG_ACPI_BUTTON $CONFIG_ACPI_BUSMGR $CONFIG_ACPI ++dep_tristate ' AC Adapter' CONFIG_ACPI_AC $CONFIG_ACPI_BUSMGR $CONFIG_ACPI ++dep_tristate ' Embedded Controller' CONFIG_ACPI_EC $CONFIG_ACPI_BUSMGR $CONFIG_ACPI ++dep_tristate ' Control Method Battery' CONFIG_ACPI_CMBATT $CONFIG_ACPI_BUSMGR $CONFIG_ACPI $CONFIG_ACPI_EC ++dep_tristate ' Thermal' CONFIG_ACPI_THERMAL $CONFIG_ACPI_BUSMGR $CONFIG_ACPI $CONFIG_ACPI_EC ++#endmenu +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/Makefile linux/drivers/acpi/Makefile +--- /usr/src/linux/drivers/acpi/Makefile Sat Mar 3 17:46:47 2001 ++++ linux/drivers/acpi/Makefile Fri Apr 13 11:57:11 2001 +@@ -1,12 +1,14 @@ + # + # Makefile for the Linux ACPI interpreter +-# ++# (It's a mess, but it's all here for a reason.) ++# + + O_TARGET := acpi.o + + export-objs := acpi_ksyms.o + + export ACPI_CFLAGS ++ + ACPI_CFLAGS := -D_LINUX + + # +@@ -16,25 +18,47 @@ + ACPI_CFLAGS += -DCONFIG_ACPI_KERNEL_CONFIG_ONLY + endif + ++acpi-subdirs := utils dispatcher events hardware \ ++ executer namespace parser resource tables ++ + EXTRA_CFLAGS += -I./include + +-EXTRA_CFLAGS += $(ACPI_CFLAGS) ++ifdef CONFIG_ACPI_DEBUG ++ ACPI_CFLAGS += -DACPI_DEBUG -Wno-unused #-DENABLE_DEBUGGER + +-acpi-subdirs := common dispatcher events hardware \ +- interpreter namespace parser resources tables ++ #acpi-subdirs += debugger ++endif ++ ++EXTRA_CFLAGS += $(ACPI_CFLAGS) + +-subdir-$(CONFIG_ACPI) += $(acpi-subdirs) ++mod-subdirs := ospm + +-obj-$(CONFIG_ACPI) := $(patsubst %,%.o,$(acpi-subdirs)) +-obj-$(CONFIG_ACPI) += os.o acpi_ksyms.o ++subdir-$(CONFIG_ACPI) += $(acpi-subdirs) ++subdir-$(CONFIG_ACPI_BUSMGR) += ospm + ++list-multi := acpicore.o ++acpicore-objs := os.o acpi_ksyms.o ++acpicore-objs += $(patsubst %,%.o,$(acpi-subdirs)) + ifdef CONFIG_ACPI_KERNEL_CONFIG +- obj-$(CONFIG_ACPI) += acpiconf.o osconf.o ++ acpicore-objs += acpiconf.o osconf.o + else +- obj-$(CONFIG_ACPI) += driver.o cmbatt.o cpu.o ec.o acpi_ksyms.o sys.o table.o power.o ++ acpicore-objs += driver.o ++endif ++ ++obj-$(CONFIG_ACPI) += acpicore.o ++ ++ifeq ($(CONFIG_ACPI_BUSMGR),y) ++ obj-y += ospm/ospm.o ++endif ++ ++ifeq ($(CONFIG_KDB),y) ++ obj-m += kdb/kdbm_acpi.o + endif + + include $(TOPDIR)/Rules.make + + clean: + $(RM) *.o */*.o ++ ++acpicore.o: $(acpicore-objs) ++ $(LD) -r -o $@ $(acpicore-objs) +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/acpi_ksyms.c linux/drivers/acpi/acpi_ksyms.c +--- /usr/src/linux/drivers/acpi/acpi_ksyms.c Fri Feb 16 16:06:17 2001 ++++ linux/drivers/acpi/acpi_ksyms.c Fri Apr 13 11:57:11 2001 +@@ -18,6 +18,7 @@ + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + ++#include <linux/config.h> + #include <linux/module.h> + #include <linux/init.h> + #include <linux/kernel.h> +@@ -27,6 +28,7 @@ + #include "acdebug.h" + + extern int acpi_in_debugger; ++extern FADT_DESCRIPTOR acpi_fadt; + + #define _COMPONENT OS_DEPENDENT + MODULE_NAME ("symbols") +@@ -58,6 +60,7 @@ + EXPORT_SYMBOL(acpi_cm_strncmp); + EXPORT_SYMBOL(acpi_cm_memcpy); + EXPORT_SYMBOL(acpi_cm_memset); ++EXPORT_SYMBOL(acpi_cm_format_exception); + + EXPORT_SYMBOL(acpi_get_handle); + EXPORT_SYMBOL(acpi_get_parent); +@@ -73,6 +76,11 @@ + EXPORT_SYMBOL(acpi_remove_gpe_handler); + EXPORT_SYMBOL(acpi_install_address_space_handler); + EXPORT_SYMBOL(acpi_remove_address_space_handler); ++EXPORT_SYMBOL(acpi_install_fixed_event_handler); ++EXPORT_SYMBOL(acpi_remove_fixed_event_handler); ++ ++EXPORT_SYMBOL(acpi_acquire_global_lock); ++EXPORT_SYMBOL(acpi_release_global_lock); + + EXPORT_SYMBOL(acpi_get_current_resources); + EXPORT_SYMBOL(acpi_get_possible_resources); +@@ -81,3 +89,20 @@ + EXPORT_SYMBOL(acpi_enable_event); + EXPORT_SYMBOL(acpi_disable_event); + EXPORT_SYMBOL(acpi_clear_event); ++ ++EXPORT_SYMBOL(acpi_get_timer_duration); ++EXPORT_SYMBOL(acpi_get_timer); ++ ++EXPORT_SYMBOL(acpi_os_signal_semaphore); ++EXPORT_SYMBOL(acpi_os_create_semaphore); ++EXPORT_SYMBOL(acpi_os_delete_semaphore); ++EXPORT_SYMBOL(acpi_os_wait_semaphore); ++ ++EXPORT_SYMBOL(acpi_os_in32); ++EXPORT_SYMBOL(acpi_os_out32); ++EXPORT_SYMBOL(acpi_fadt); ++EXPORT_SYMBOL(acpi_hw_register_bit_access); ++EXPORT_SYMBOL(acpi_hw_obtain_sleep_type_register_data); ++EXPORT_SYMBOL(acpi_enter_sleep_state); ++EXPORT_SYMBOL(acpi_get_system_info); ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/cmbatt.c linux/drivers/acpi/cmbatt.c +--- /usr/src/linux/drivers/acpi/cmbatt.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/cmbatt.c Wed Dec 31 16:00:00 1969 +@@ -1,390 +0,0 @@ +-/* +- * cmbatt.c - Control Method Battery driver +- * +- * Copyright (C) 2000 Andrew Grover +- * +- * 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 +- */ +-/* +- * Changes: +- * Brendan Burns <bburns@wso.williams.edu> 2000-11-15 +- * - added proc battery interface +- * - parse returned data from _BST and _BIF +- * Andy Grover <andrew.grover@intel.com> 2000-12-8 +- * - improved proc interface +- * Pavel Machek <pavel@suse.cz> 2001-1-31 +- * - fixed oops on NULLs in return from _BIF +- */ +- +-#include <linux/kernel.h> +-#include <linux/types.h> +-#include <linux/proc_fs.h> +-#include "acpi.h" +-#include "driver.h" +- +-#define _COMPONENT OS_DEPENDENT +- MODULE_NAME ("cmbatt") +- +-/* ACPI-specific defines */ +-#define ACPI_CMBATT_HID "PNP0C0A" +-#define ACPI_BATT_PRESENT 0x10 +-#define ACPI_BATT_UNKNOWN 0xFFFFFFFF +- +-/* driver-specific defines */ +-#define MAX_CM_BATTERIES 0x8 +-#define MAX_BATT_STRLEN 0x20 +- +-#define Xstrncpy(a, b, c) if (b) strncpy(a,b,c); else strncpy(a, "unknown", c) +- +-struct cmbatt_info +-{ +- u32 power_unit; +- u32 design_capacity; +- u32 last_full_capacity; +- u32 battery_technology; +- u32 design_voltage; +- u32 design_capacity_warning; +- u32 design_capacity_low; +- u32 battery_capacity_granularity_1; +- u32 battery_capacity_granularity_2; +- +- char model_number[MAX_BATT_STRLEN]; +- char serial_number[MAX_BATT_STRLEN]; +- char battery_type[MAX_BATT_STRLEN]; +- char oem_info[MAX_BATT_STRLEN]; +-}; +- +-struct cmbatt_context +-{ +- u32 is_present; +- ACPI_HANDLE handle; +- char UID[9]; +- char *power_unit; +- struct cmbatt_info info; +-}; +- +-struct cmbatt_status +-{ +- u32 state; +- u32 present_rate; +- u32 remaining_capacity; +- u32 present_voltage; +-}; +- +-static u32 batt_count = 0; +- +-static struct cmbatt_context batt_list[MAX_CM_BATTERIES]; +- +-static ACPI_STATUS +-acpi_get_battery_status(ACPI_HANDLE handle, struct cmbatt_status *result) +-{ +- ACPI_OBJECT *obj; +- ACPI_OBJECT *objs; +- ACPI_BUFFER buf; +- +- buf.length = 0; +- buf.pointer = NULL; +- +- /* determine buffer length needed */ +- if (acpi_evaluate_object(handle, "_BST", NULL, &buf) != AE_BUFFER_OVERFLOW) { +- printk(KERN_ERR "Cmbatt: Could not get battery status struct length\n"); +- return AE_NOT_FOUND; +- } +- +- buf.pointer = kmalloc(buf.length, GFP_KERNEL); +- if (!buf.pointer) +- return AE_NO_MEMORY; +- +- /* get the data */ +- if (!ACPI_SUCCESS(acpi_evaluate_object(handle, "_BST", NULL, &buf))) { +- printk(KERN_ERR "Cmbatt: Could not get battery status\n"); +- kfree (buf.pointer); +- return AE_NOT_FOUND; +- } +- +- obj = (ACPI_OBJECT *) buf.pointer; +- objs = obj->package.elements; +- +- result->state = objs[0].integer.value; +- result->present_rate = objs[1].integer.value; +- result->remaining_capacity = objs[2].integer.value; +- result->present_voltage = objs[3].integer.value; +- +- kfree(buf.pointer); +- +- return AE_OK; +-} +- +-static ACPI_STATUS +-acpi_get_battery_info(ACPI_HANDLE handle, struct cmbatt_info *result) +-{ +- ACPI_OBJECT *obj; +- ACPI_OBJECT *objs; +- ACPI_BUFFER buf; +- +- buf.length = 0; +- buf.pointer = NULL; +- +- /* determine the length of the data */ +- if (acpi_evaluate_object(handle, "_BIF", NULL, &buf) != AE_BUFFER_OVERFLOW) { +- printk(KERN_ERR "Cmbatt: Could not get battery info struct length\n"); +- return AE_NOT_FOUND; +- } +- +- buf.pointer = kmalloc(buf.length, GFP_KERNEL); +- if (!buf.pointer) +- return AE_NO_MEMORY; +- +- /* get the data */ +- if (!ACPI_SUCCESS(acpi_evaluate_object(handle, "_BIF", NULL, &buf))) { +- printk(KERN_ERR "Cmbatt: Could not get battery info\n"); +- kfree (buf.pointer); +- return AE_NOT_FOUND; +- } +- +- obj = (ACPI_OBJECT *) buf.pointer; +- objs = obj->package.elements; +- +- result->power_unit=objs[0].integer.value; +- result->design_capacity=objs[1].integer.value; +- result->last_full_capacity=objs[2].integer.value; +- result->battery_technology=objs[3].integer.value; +- result->design_voltage=objs[4].integer.value; +- result->design_capacity_warning=objs[5].integer.value; +- result->design_capacity_low=objs[6].integer.value; +- result->battery_capacity_granularity_1=objs[7].integer.value; +- result->battery_capacity_granularity_2=objs[8].integer.value; +- +- /* BUG: trailing NULL issue */ +- Xstrncpy(result->model_number, objs[9].string.pointer, MAX_BATT_STRLEN-1); +- Xstrncpy(result->serial_number, objs[10].string.pointer, MAX_BATT_STRLEN-1); +- Xstrncpy(result->battery_type, objs[11].string.pointer, MAX_BATT_STRLEN-1); +- Xstrncpy(result->oem_info, objs[12].string.pointer, MAX_BATT_STRLEN-1); +- +- kfree(buf.pointer); +- +- return AE_OK; +-} +- +-/* +- * We found a device with the correct HID +- */ +-static ACPI_STATUS +-acpi_found_cmbatt(ACPI_HANDLE handle, u32 level, void *ctx, void **value) +-{ +- ACPI_DEVICE_INFO info; +- +- if (batt_count >= MAX_CM_BATTERIES) { +- printk(KERN_ERR "Cmbatt: MAX_CM_BATTERIES exceeded\n"); +- return AE_OK; +- } +- +- if (!ACPI_SUCCESS(acpi_get_object_info(handle, &info))) { +- printk(KERN_ERR "Cmbatt: Could not get battery object info\n"); +- return (AE_OK); +- } +- +- if (info.valid & ACPI_VALID_UID) { +- strncpy(batt_list[batt_count].UID, info.unique_id, 9); +- } +- else if (batt_count > 1) { +- printk(KERN_WARNING "Cmbatt: No UID but more than 1 battery\n"); +- } +- +- if (!(info.valid & ACPI_VALID_STA)) { +- printk(KERN_ERR "Cmbatt: Battery _STA invalid\n"); +- return AE_OK; +- } +- +- if (!(info.current_status & ACPI_BATT_PRESENT)) { +- printk(KERN_INFO "Cmbatt: Battery socket %d empty\n", batt_count); +- batt_list[batt_count].is_present = FALSE; +- } +- else { +- printk(KERN_INFO "Cmbatt: Battery socket %d occupied\n", batt_count); +- batt_list[batt_count].is_present = TRUE; +- if (acpi_get_battery_info(handle, &batt_list[batt_count].info) != AE_OK) { +- printk(KERN_ERR "acpi_get_battery_info failed\n"); +- return AE_OK; +- } +- +- batt_list[batt_count].power_unit = (batt_list[batt_count].info.power_unit) ? "mA" : "mW"; +- } +- +- batt_list[batt_count].handle = handle; +- +- batt_count++; +- +- return AE_OK; +-} +- +-static int +-proc_read_batt_info(char *page, char **start, off_t off, +- int count, int *eof, void *data) +-{ +- struct cmbatt_info *info; +- u32 batt_num = (u32) data; +- char *p = page; +- int len; +- +- info = &batt_list[batt_num].info; +- +- /* don't get info more than once for a single proc read */ +- if (off != 0) +- goto end; +- +- if (!batt_list[batt_num].is_present) { +- p += sprintf(p, "battery %d not present\n", batt_num); +- goto end; +- } +- +- if (info->last_full_capacity != ACPI_BATT_UNKNOWN) +- p += sprintf(p, "Last Full Capacity: %d %sh\n", +- info->last_full_capacity, batt_list[batt_num].power_unit); +- +- if (info->design_capacity != ACPI_BATT_UNKNOWN) +- p += sprintf(p, "Design Capacity: %d %sh\n", +- info->design_capacity, batt_list[batt_num].power_unit); +- +- if (info->battery_technology) +- p += sprintf(p, "Battery Technology: Secondary\n"); +- else +- p += sprintf(p, "Battery Technology: Primary\n"); +- +- if (info->design_voltage != ACPI_BATT_UNKNOWN) +- p += sprintf(p, "Design Voltage: %d mV\n", +- info->design_voltage); +- +- p += sprintf(p, "Design Capacity Warning: %d %sh\n", +- info->design_capacity_warning, batt_list[batt_num].power_unit); +- p += sprintf(p, "Design Capacity Low: %d %sh\n", +- info->design_capacity_low, batt_list[batt_num].power_unit); +- p += sprintf(p, "Battery Capacity Granularity 1: %d\n", +- info->battery_capacity_granularity_1); +- p += sprintf(p, "Battery Capacity Granularity 2: %d\n", +- info->battery_capacity_granularity_2); +- p += sprintf(p, "Model number; %s\nSerial number: %s\nBattery type: %s\nOEM info: %s\n", +- info->model_number,info->serial_number, +- info->battery_type,info->oem_info); +-end: +- len = (p - page); +- if (len <= off+count) *eof = 1; +- *start = page + off; +- len -= off; +- if (len>count) len = count; +- if (len<0) len = 0; +- return len; +-} +- +-static int +-proc_read_batt_status(char *page, char **start, off_t off, +- int count, int *eof, void *data) +-{ +- struct cmbatt_status status; +- u32 batt_num = (u32) data; +- char *p = page; +- int len; +- +- /* don't get status more than once for a single proc read */ +- if (off != 0) +- goto end; +- +- if (!batt_list[batt_num].is_present) { +- p += sprintf(p, "battery %d not present\n", batt_num); +- goto end; +- } +- +- if (acpi_get_battery_status(batt_list[batt_num].handle, &status) != AE_OK) { +- printk(KERN_ERR "Cmbatt: acpi_get_battery_status failed\n"); +- goto end; +- } +- +- p += sprintf(p, "Battery discharging: %s\n", +- (status.state & 0x1)?"yes":"no"); +- p += sprintf(p, "Battery charging: %s\n", +- (status.state & 0x2)?"yes":"no"); +- p += sprintf(p, "Battery critically low: %s\n", +- (status.state & 0x4)?"yes":"no"); +- +- if (status.present_rate != ACPI_BATT_UNKNOWN) +- p += sprintf(p, "Battery rate: %d %s\n", +- status.present_rate, batt_list[batt_num].power_unit); +- +- if (status.remaining_capacity != ACPI_BATT_UNKNOWN) +- p += sprintf(p, "Battery capacity: %d %sh\n", +- status.remaining_capacity, batt_list[batt_num].power_unit); +- +- if (status.present_voltage != ACPI_BATT_UNKNOWN) +- p += sprintf(p, "Battery voltage: %d mV\n", +- status.present_voltage); +- +-end: +- +- len = (p - page); +- if (len <= off+count) *eof = 1; +- *start = page + off; +- len -= off; +- if (len>count) len = count; +- if (len<0) len = 0; +- return len; +-} +- +- +- +-int +-acpi_cmbatt_init(void) +-{ +- int i; +- +- acpi_get_devices(ACPI_CMBATT_HID, +- acpi_found_cmbatt, +- NULL, +- NULL); +- +- for (i = 0; i < batt_count; i++) { +- +- char batt_name[20]; +- +- sprintf(batt_name, "power/batt%d_info", i); +- create_proc_read_entry(batt_name, 0, NULL, +- proc_read_batt_info, (void *) i); +- +- sprintf(batt_name, "power/batt%d_status", i); +- create_proc_read_entry(batt_name, 0, NULL, +- proc_read_batt_status, (void *) i); +- +- } +- +- return 0; +-} +- +-int +-acpi_cmbatt_terminate(void) +-{ +- int i; +- +- for (i = 0; i < batt_count; i++) { +- +- char batt_name[20]; +- +- sprintf(batt_name, "power/batt%d_info", i); +- remove_proc_entry(batt_name, NULL); +- +- sprintf(batt_name, "power/batt%d_status", i); +- remove_proc_entry(batt_name, NULL); +- } +- +- return 0; +-} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/common/Makefile linux/drivers/acpi/common/Makefile +--- /usr/src/linux/drivers/acpi/common/Makefile Fri Dec 29 14:07:21 2000 ++++ linux/drivers/acpi/common/Makefile Wed Dec 31 16:00:00 1969 +@@ -1,16 +0,0 @@ +-# +-# Makefile for all Linux ACPI interpreter subdirectories +-# +- +-O_TARGET := ../$(shell basename `pwd`).o +- +-obj-$(CONFIG_ACPI) := $(patsubst %.c,%.o,$(wildcard *.c)) +- +-EXTRA_CFLAGS += -I../include +- +-EXTRA_CFLAGS += $(ACPI_CFLAGS) +- +-include $(TOPDIR)/Rules.make +- +-clean: +- $(RM) *.o +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/common/cmalloc.c linux/drivers/acpi/common/cmalloc.c +--- /usr/src/linux/drivers/acpi/common/cmalloc.c Mon Jan 29 10:15:58 2001 ++++ linux/drivers/acpi/common/cmalloc.c Wed Dec 31 16:00:00 1969 +@@ -1,170 +0,0 @@ +-/****************************************************************************** +- * +- * Module Name: cmalloc - local memory allocation routines +- * $Revision: 84 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acparser.h" +-#include "acinterp.h" +-#include "acnamesp.h" +-#include "acglobal.h" +- +-#define _COMPONENT MISCELLANEOUS +- MODULE_NAME ("cmalloc") +- +- +-/***************************************************************************** +- * +- * FUNCTION: _Cm_allocate +- * +- * PARAMETERS: Size - Size of the allocation +- * Component - Component type of caller +- * Module - Source file name of caller +- * Line - Line number of caller +- * +- * RETURN: Address of the allocated memory on success, NULL on failure. +- * +- * DESCRIPTION: The subsystem's equivalent of malloc. +- * +- ****************************************************************************/ +- +-void * +-_cm_allocate ( +- u32 size, +- u32 component, +- NATIVE_CHAR *module, +- u32 line) +-{ +- void *address = NULL; +- +- +- /* Check for an inadvertent size of zero bytes */ +- +- if (!size) { +- _REPORT_ERROR (module, line, component, +- ("Cm_allocate: Attempt to allocate zero bytes\n")); +- size = 1; +- } +- +- address = acpi_os_allocate (size); +- if (!address) { +- /* Report allocation error */ +- +- _REPORT_ERROR (module, line, component, +- ("Cm_allocate: Could not allocate size %X\n", size)); +- +- return (NULL); +- } +- +- +- return (address); +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: _Cm_callocate +- * +- * PARAMETERS: Size - Size of the allocation +- * Component - Component type of caller +- * Module - Source file name of caller +- * Line - Line number of caller +- * +- * RETURN: Address of the allocated memory on success, NULL on failure. +- * +- * DESCRIPTION: Subsystem equivalent of calloc. +- * +- ****************************************************************************/ +- +-void * +-_cm_callocate ( +- u32 size, +- u32 component, +- NATIVE_CHAR *module, +- u32 line) +-{ +- void *address = NULL; +- +- +- /* Check for an inadvertent size of zero bytes */ +- +- if (!size) { +- _REPORT_ERROR (module, line, component, +- ("Cm_callocate: Attempt to allocate zero bytes\n")); +- return (NULL); +- } +- +- +- address = acpi_os_callocate (size); +- +- if (!address) { +- /* Report allocation error */ +- +- _REPORT_ERROR (module, line, component, +- ("Cm_callocate: Could not allocate size %X\n", size)); +- return (NULL); +- } +- +- +- return (address); +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: _Cm_free +- * +- * PARAMETERS: Address - Address of the memory to deallocate +- * Component - Component type of caller +- * Module - Source file name of caller +- * Line - Line number of caller +- * +- * RETURN: None +- * +- * DESCRIPTION: Frees the memory at Address +- * +- ****************************************************************************/ +- +-void +-_cm_free ( +- void *address, +- u32 component, +- NATIVE_CHAR *module, +- u32 line) +-{ +- +- if (NULL == address) { +- _REPORT_ERROR (module, line, component, +- ("_Cm_free: Trying to delete a NULL address\n")); +- +- return; +- } +- +- +- acpi_os_free (address); +- +- return; +-} +- +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/common/cmclib.c linux/drivers/acpi/common/cmclib.c +--- /usr/src/linux/drivers/acpi/common/cmclib.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/common/cmclib.c Wed Dec 31 16:00:00 1969 +@@ -1,818 +0,0 @@ +-/****************************************************************************** +- * +- * Module Name: cmclib - Local implementation of C library functions +- * $Revision: 32 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acevents.h" +-#include "achware.h" +-#include "acnamesp.h" +-#include "acinterp.h" +-#include "amlcode.h" +- +-/* +- * These implementations of standard C Library routines can optionally be +- * used if a C library is not available. In general, they are less efficient +- * than an inline or assembly implementation +- */ +- +-#define _COMPONENT MISCELLANEOUS +- MODULE_NAME ("cmclib") +- +- +-#ifndef ACPI_USE_SYSTEM_CLIBRARY +- +-/******************************************************************************* +- * +- * FUNCTION: strlen +- * +- * PARAMETERS: String - Null terminated string +- * +- * RETURN: Length +- * +- * DESCRIPTION: Returns the length of the input string +- * +- ******************************************************************************/ +- +- +-NATIVE_UINT +-acpi_cm_strlen ( +- const NATIVE_CHAR *string) +-{ +- NATIVE_UINT length = 0; +- +- +- /* Count the string until a null is encountered */ +- +- while (*string) { +- length++; +- string++; +- } +- +- return (length); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: strcpy +- * +- * PARAMETERS: Dst_string - Target of the copy +- * Src_string - The source string to copy +- * +- * RETURN: Dst_string +- * +- * DESCRIPTION: Copy a null terminated string +- * +- ******************************************************************************/ +- +-NATIVE_CHAR * +-acpi_cm_strcpy ( +- NATIVE_CHAR *dst_string, +- const NATIVE_CHAR *src_string) +-{ +- NATIVE_CHAR *string = dst_string; +- +- +- /* Move bytes brute force */ +- +- while (*src_string) { +- *string = *src_string; +- +- string++; +- src_string++; +- } +- +- /* Null terminate */ +- +- *string = 0; +- +- return (dst_string); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: strncpy +- * +- * PARAMETERS: Dst_string - Target of the copy +- * Src_string - The source string to copy +- * Count - Maximum # of bytes to copy +- * +- * RETURN: Dst_string +- * +- * DESCRIPTION: Copy a null terminated string, with a maximum length +- * +- ******************************************************************************/ +- +-NATIVE_CHAR * +-acpi_cm_strncpy ( +- NATIVE_CHAR *dst_string, +- const NATIVE_CHAR *src_string, +- NATIVE_UINT count) +-{ +- NATIVE_CHAR *string = dst_string; +- +- +- /* Copy the string */ +- +- for (string = dst_string; +- count && (count--, (*string++ = *src_string++)); ) +- {;} +- +- /* Pad with nulls if necessary */ +- +- while (count--) { +- *string = 0; +- string++; +- } +- +- /* Return original pointer */ +- +- return (dst_string); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: strcmp +- * +- * PARAMETERS: String1 - First string +- * String2 - Second string +- * +- * RETURN: Index where strings mismatched, or 0 if strings matched +- * +- * DESCRIPTION: Compare two null terminated strings +- * +- ******************************************************************************/ +- +-u32 +-acpi_cm_strcmp ( +- const NATIVE_CHAR *string1, +- const NATIVE_CHAR *string2) +-{ +- +- +- for ( ; (*string1 == *string2); string2++) { +- if (!*string1++) { +- return (0); +- } +- } +- +- +- return ((unsigned char) *string1 - (unsigned char) *string2); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: strncmp +- * +- * PARAMETERS: String1 - First string +- * String2 - Second string +- * Count - Maximum # of bytes to compare +- * +- * RETURN: Index where strings mismatched, or 0 if strings matched +- * +- * DESCRIPTION: Compare two null terminated strings, with a maximum length +- * +- ******************************************************************************/ +- +-u32 +-acpi_cm_strncmp ( +- const NATIVE_CHAR *string1, +- const NATIVE_CHAR *string2, +- NATIVE_UINT count) +-{ +- +- +- for ( ; count-- && (*string1 == *string2); string2++) { +- if (!*string1++) { +- return (0); +- } +- } +- +- return ((count == -1) ? 0 : ((unsigned char) *string1 - +- (unsigned char) *string2)); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Strcat +- * +- * PARAMETERS: Dst_string - Target of the copy +- * Src_string - The source string to copy +- * +- * RETURN: Dst_string +- * +- * DESCRIPTION: Append a null terminated string to a null terminated string +- * +- ******************************************************************************/ +- +-NATIVE_CHAR * +-acpi_cm_strcat ( +- NATIVE_CHAR *dst_string, +- const NATIVE_CHAR *src_string) +-{ +- NATIVE_CHAR *string; +- +- +- /* Find end of the destination string */ +- +- for (string = dst_string; *string++; ) { ; } +- +- /* Concatinate the string */ +- +- for (--string; (*string++ = *src_string++); ) { ; } +- +- return (dst_string); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: strncat +- * +- * PARAMETERS: Dst_string - Target of the copy +- * Src_string - The source string to copy +- * Count - Maximum # of bytes to copy +- * +- * RETURN: Dst_string +- * +- * DESCRIPTION: Append a null terminated string to a null terminated string, +- * with a maximum count. +- * +- ******************************************************************************/ +- +-NATIVE_CHAR * +-acpi_cm_strncat ( +- NATIVE_CHAR *dst_string, +- const NATIVE_CHAR *src_string, +- NATIVE_UINT count) +-{ +- NATIVE_CHAR *string; +- +- +- if (count) { +- /* Find end of the destination string */ +- +- for (string = dst_string; *string++; ) { ; } +- +- /* Concatinate the string */ +- +- for (--string; (*string++ = *src_string++) && --count; ) { ; } +- +- /* Null terminate if necessary */ +- +- if (!count) { +- *string = 0; +- } +- } +- +- return (dst_string); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: memcpy +- * +- * PARAMETERS: Dest - Target of the copy +- * Src - Source buffer to copy +- * Count - Number of bytes to copy +- * +- * RETURN: Dest +- * +- * DESCRIPTION: Copy arbitrary bytes of memory +- * +- ******************************************************************************/ +- +-void * +-acpi_cm_memcpy ( +- void *dest, +- const void *src, +- NATIVE_UINT count) +-{ +- NATIVE_CHAR *new = (NATIVE_CHAR *) dest; +- NATIVE_CHAR *old = (NATIVE_CHAR *) src; +- +- +- while (count) { +- *new = *old; +- new++; +- old++; +- count--; +- } +- +- return (dest); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: memset +- * +- * PARAMETERS: Dest - Buffer to set +- * Value - Value to set each byte of memory +- * Count - Number of bytes to set +- * +- * RETURN: Dest +- * +- * DESCRIPTION: Initialize a buffer to a known value. +- * +- ******************************************************************************/ +- +-void * +-acpi_cm_memset ( +- void *dest, +- NATIVE_UINT value, +- NATIVE_UINT count) +-{ +- NATIVE_CHAR *new = (NATIVE_CHAR *) dest; +- +- +- while (count) { +- *new = (char) value; +- new++; +- count--; +- } +- +- return (dest); +-} +- +- +-#define NEGATIVE 1 +-#define POSITIVE 0 +- +- +-#define _ACPI_XA 0x00 /* extra alphabetic - not supported */ +-#define _ACPI_XS 0x40 /* extra space */ +-#define _ACPI_BB 0x00 /* BEL, BS, etc. - not supported */ +-#define _ACPI_CN 0x20 /* CR, FF, HT, NL, VT */ +-#define _ACPI_DI 0x04 /* '0'-'9' */ +-#define _ACPI_LO 0x02 /* 'a'-'z' */ +-#define _ACPI_PU 0x10 /* punctuation */ +-#define _ACPI_SP 0x08 /* space */ +-#define _ACPI_UP 0x01 /* 'A'-'Z' */ +-#define _ACPI_XD 0x80 /* '0'-'9', 'A'-'F', 'a'-'f' */ +- +-static const u8 _acpi_ctype[257] = { +- _ACPI_CN, /* 0x0 0. */ +- _ACPI_CN, /* 0x1 1. */ +- _ACPI_CN, /* 0x2 2. */ +- _ACPI_CN, /* 0x3 3. */ +- _ACPI_CN, /* 0x4 4. */ +- _ACPI_CN, /* 0x5 5. */ +- _ACPI_CN, /* 0x6 6. */ +- _ACPI_CN, /* 0x7 7. */ +- _ACPI_CN, /* 0x8 8. */ +- _ACPI_CN|_ACPI_SP, /* 0x9 9. */ +- _ACPI_CN|_ACPI_SP, /* 0xA 10. */ +- _ACPI_CN|_ACPI_SP, /* 0xB 11. */ +- _ACPI_CN|_ACPI_SP, /* 0xC 12. */ +- _ACPI_CN|_ACPI_SP, /* 0xD 13. */ +- _ACPI_CN, /* 0xE 14. */ +- _ACPI_CN, /* 0xF 15. */ +- _ACPI_CN, /* 0x10 16. */ +- _ACPI_CN, /* 0x11 17. */ +- _ACPI_CN, /* 0x12 18. */ +- _ACPI_CN, /* 0x13 19. */ +- _ACPI_CN, /* 0x14 20. */ +- _ACPI_CN, /* 0x15 21. */ +- _ACPI_CN, /* 0x16 22. */ +- _ACPI_CN, /* 0x17 23. */ +- _ACPI_CN, /* 0x18 24. */ +- _ACPI_CN, /* 0x19 25. */ +- _ACPI_CN, /* 0x1A 26. */ +- _ACPI_CN, /* 0x1B 27. */ +- _ACPI_CN, /* 0x1C 28. */ +- _ACPI_CN, /* 0x1D 29. */ +- _ACPI_CN, /* 0x1E 30. */ +- _ACPI_CN, /* 0x1F 31. */ +- _ACPI_XS|_ACPI_SP, /* 0x20 32. ' ' */ +- _ACPI_PU, /* 0x21 33. '!' */ +- _ACPI_PU, /* 0x22 34. '"' */ +- _ACPI_PU, /* 0x23 35. '#' */ +- _ACPI_PU, /* 0x24 36. '$' */ +- _ACPI_PU, /* 0x25 37. '%' */ +- _ACPI_PU, /* 0x26 38. '&' */ +- _ACPI_PU, /* 0x27 39. ''' */ +- _ACPI_PU, /* 0x28 40. '(' */ +- _ACPI_PU, /* 0x29 41. ')' */ +- _ACPI_PU, /* 0x2A 42. '*' */ +- _ACPI_PU, /* 0x2B 43. '+' */ +- _ACPI_PU, /* 0x2C 44. ',' */ +- _ACPI_PU, /* 0x2D 45. '-' */ +- _ACPI_PU, /* 0x2E 46. '.' */ +- _ACPI_PU, /* 0x2F 47. '/' */ +- _ACPI_XD|_ACPI_DI, /* 0x30 48. '0' */ +- _ACPI_XD|_ACPI_DI, /* 0x31 49. '1' */ +- _ACPI_XD|_ACPI_DI, /* 0x32 50. '2' */ +- _ACPI_XD|_ACPI_DI, /* 0x33 51. '3' */ +- _ACPI_XD|_ACPI_DI, /* 0x34 52. '4' */ +- _ACPI_XD|_ACPI_DI, /* 0x35 53. '5' */ +- _ACPI_XD|_ACPI_DI, /* 0x36 54. '6' */ +- _ACPI_XD|_ACPI_DI, /* 0x37 55. '7' */ +- _ACPI_XD|_ACPI_DI, /* 0x38 56. '8' */ +- _ACPI_XD|_ACPI_DI, /* 0x39 57. '9' */ +- _ACPI_PU, /* 0x3A 58. ':' */ +- _ACPI_PU, /* 0x3B 59. ';' */ +- _ACPI_PU, /* 0x3C 60. '<' */ +- _ACPI_PU, /* 0x3D 61. '=' */ +- _ACPI_PU, /* 0x3E 62. '>' */ +- _ACPI_PU, /* 0x3F 63. '?' */ +- _ACPI_PU, /* 0x40 64. '@' */ +- _ACPI_XD|_ACPI_UP, /* 0x41 65. 'A' */ +- _ACPI_XD|_ACPI_UP, /* 0x42 66. 'B' */ +- _ACPI_XD|_ACPI_UP, /* 0x43 67. 'C' */ +- _ACPI_XD|_ACPI_UP, /* 0x44 68. 'D' */ +- _ACPI_XD|_ACPI_UP, /* 0x45 69. 'E' */ +- _ACPI_XD|_ACPI_UP, /* 0x46 70. 'F' */ +- _ACPI_UP, /* 0x47 71. 'G' */ +- _ACPI_UP, /* 0x48 72. 'H' */ +- _ACPI_UP, /* 0x49 73. 'I' */ +- _ACPI_UP, /* 0x4A 74. 'J' */ +- _ACPI_UP, /* 0x4B 75. 'K' */ +- _ACPI_UP, /* 0x4C 76. 'L' */ +- _ACPI_UP, /* 0x4D 77. 'M' */ +- _ACPI_UP, /* 0x4E 78. 'N' */ +- _ACPI_UP, /* 0x4F 79. 'O' */ +- _ACPI_UP, /* 0x50 80. 'P' */ +- _ACPI_UP, /* 0x51 81. 'Q' */ +- _ACPI_UP, /* 0x52 82. 'R' */ +- _ACPI_UP, /* 0x53 83. 'S' */ +- _ACPI_UP, /* 0x54 84. 'T' */ +- _ACPI_UP, /* 0x55 85. 'U' */ +- _ACPI_UP, /* 0x56 86. 'V' */ +- _ACPI_UP, /* 0x57 87. 'W' */ +- _ACPI_UP, /* 0x58 88. 'X' */ +- _ACPI_UP, /* 0x59 89. 'Y' */ +- _ACPI_UP, /* 0x5A 90. 'Z' */ +- _ACPI_PU, /* 0x5B 91. '[' */ +- _ACPI_PU, /* 0x5C 92. '\' */ +- _ACPI_PU, /* 0x5D 93. ']' */ +- _ACPI_PU, /* 0x5E 94. '^' */ +- _ACPI_PU, /* 0x5F 95. '_' */ +- _ACPI_PU, /* 0x60 96. '`' */ +- _ACPI_XD|_ACPI_LO, /* 0x61 97. 'a' */ +- _ACPI_XD|_ACPI_LO, /* 0x62 98. 'b' */ +- _ACPI_XD|_ACPI_LO, /* 0x63 99. 'c' */ +- _ACPI_XD|_ACPI_LO, /* 0x64 100. 'd' */ +- _ACPI_XD|_ACPI_LO, /* 0x65 101. 'e' */ +- _ACPI_XD|_ACPI_LO, /* 0x66 102. 'f' */ +- _ACPI_LO, /* 0x67 103. 'g' */ +- _ACPI_LO, /* 0x68 104. 'h' */ +- _ACPI_LO, /* 0x69 105. 'i' */ +- _ACPI_LO, /* 0x6A 106. 'j' */ +- _ACPI_LO, /* 0x6B 107. 'k' */ +- _ACPI_LO, /* 0x6C 108. 'l' */ +- _ACPI_LO, /* 0x6D 109. 'm' */ +- _ACPI_LO, /* 0x6E 110. 'n' */ +- _ACPI_LO, /* 0x6F 111. 'o' */ +- _ACPI_LO, /* 0x70 112. 'p' */ +- _ACPI_LO, /* 0x71 113. 'q' */ +- _ACPI_LO, /* 0x72 114. 'r' */ +- _ACPI_LO, /* 0x73 115. 's' */ +- _ACPI_LO, /* 0x74 116. 't' */ +- _ACPI_LO, /* 0x75 117. 'u' */ +- _ACPI_LO, /* 0x76 118. 'v' */ +- _ACPI_LO, /* 0x77 119. 'w' */ +- _ACPI_LO, /* 0x78 120. 'x' */ +- _ACPI_LO, /* 0x79 121. 'y' */ +- _ACPI_LO, /* 0x7A 122. 'z' */ +- _ACPI_PU, /* 0x7B 123. '{' */ +- _ACPI_PU, /* 0x7C 124. '|' */ +- _ACPI_PU, /* 0x7D 125. '}' */ +- _ACPI_PU, /* 0x7E 126. '~' */ +- _ACPI_CN, /* 0x7F 127. */ +- +- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80 to 0x8F */ +- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x90 to 0x9F */ +- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xA0 to 0xAF */ +- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xB0 to 0xBF */ +- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xC0 to 0xCF */ +- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xD0 to 0xDF */ +- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xE0 to 0xEF */ +- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* 0xF0 to 0x100 */ +-}; +- +-#define IS_UPPER(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_UP)) +-#define IS_LOWER(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO)) +-#define IS_DIGIT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_DI)) +-#define IS_SPACE(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_SP)) +-#define IS_XDIGIT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_XD)) +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_to_upper +- * +- * PARAMETERS: +- * +- * RETURN: +- * +- * DESCRIPTION: Convert character to uppercase +- * +- ******************************************************************************/ +- +-u32 +-acpi_cm_to_upper ( +- u32 c) +-{ +- +- return (IS_LOWER(c) ? ((c)-0x20) : (c)); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_to_lower +- * +- * PARAMETERS: +- * +- * RETURN: +- * +- * DESCRIPTION: Convert character to lowercase +- * +- ******************************************************************************/ +- +-u32 +-acpi_cm_to_lower ( +- u32 c) +-{ +- +- return (IS_UPPER(c) ? ((c)+0x20) : (c)); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: strupr +- * +- * PARAMETERS: Src_string - The source string to convert to +- * +- * RETURN: Src_string +- * +- * DESCRIPTION: Convert string to uppercase +- * +- ******************************************************************************/ +- +-NATIVE_CHAR * +-acpi_cm_strupr ( +- NATIVE_CHAR *src_string) +-{ +- NATIVE_CHAR *string; +- +- +- /* Walk entire string, uppercasing the letters */ +- +- for (string = src_string; *string; ) { +- *string = (char) acpi_cm_to_upper (*string); +- string++; +- } +- +- +- return (src_string); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: strstr +- * +- * PARAMETERS: String1 - +- * String2 +- * +- * RETURN: +- * +- * DESCRIPTION: Checks if String2 occurs in String1. This is not really a +- * full implementation of strstr, only sufficient for command +- * matching +- * +- ******************************************************************************/ +- +-NATIVE_CHAR * +-acpi_cm_strstr ( +- NATIVE_CHAR *string1, +- NATIVE_CHAR *string2) +-{ +- NATIVE_CHAR *string; +- +- +- if (acpi_cm_strlen (string2) > acpi_cm_strlen (string1)) { +- return (NULL); +- } +- +- /* Walk entire string, comparing the letters */ +- +- for (string = string1; *string2; ) { +- if (*string2 != *string) { +- return (NULL); +- } +- +- string2++; +- string++; +- } +- +- +- return (string1); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: strtoul +- * +- * PARAMETERS: String - Null terminated string +- * Terminater - Where a pointer to the terminating byte is returned +- * Base - Radix of the string +- * +- * RETURN: Converted value +- * +- * DESCRIPTION: Convert a string into an unsigned value. +- * +- ******************************************************************************/ +- +-u32 +-acpi_cm_strtoul ( +- const NATIVE_CHAR *string, +- NATIVE_CHAR **terminator, +- NATIVE_UINT base) +-{ +- u32 converted = 0; +- u32 index; +- u32 sign; +- const NATIVE_CHAR *string_start; +- u32 return_value = 0; +- ACPI_STATUS status = AE_OK; +- +- +- /* +- * Save the value of the pointer to the buffer's first +- * character, save the current errno value, and then +- * skip over any white space in the buffer: +- */ +- string_start = string; +- while (IS_SPACE (*string) || *string == '\t') { +- ++string; +- } +- +- /* +- * The buffer may contain an optional plus or minus sign. +- * If it does, then skip over it but remember what is was: +- */ +- if (*string == '-') { +- sign = NEGATIVE; +- ++string; +- } +- +- else if (*string == '+') { +- ++string; +- sign = POSITIVE; +- } +- +- else { +- sign = POSITIVE; +- } +- +- /* +- * If the input parameter Base is zero, then we need to +- * determine if it is octal, decimal, or hexadecimal: +- */ +- if (base == 0) { +- if (*string == '0') { +- if (acpi_cm_to_lower (*(++string)) == 'x') { +- base = 16; +- ++string; +- } +- +- else { +- base = 8; +- } +- } +- +- else { +- base = 10; +- } +- } +- +- else if (base < 2 || base > 36) { +- /* +- * The specified Base parameter is not in the domain of +- * this function: +- */ +- goto done; +- } +- +- /* +- * For octal and hexadecimal bases, skip over the leading +- * 0 or 0x, if they are present. +- */ +- if (base == 8 && *string == '0') { +- string++; +- } +- +- if (base == 16 && +- *string == '0' && +- acpi_cm_to_lower (*(++string)) == 'x') +- { +- string++; +- } +- +- +- /* +- * Main loop: convert the string to an unsigned long: +- */ +- while (*string) { +- if (IS_DIGIT (*string)) { +- index = *string - '0'; +- } +- +- else { +- index = acpi_cm_to_upper (*string); +- if (IS_UPPER (index)) { +- index = index - 'A' + 10; +- } +- +- else { +- goto done; +- } +- } +- +- if (index >= base) { +- goto done; +- } +- +- /* +- * Check to see if value is out of range: +- */ +- +- if (return_value > ((ACPI_UINT32_MAX - (u32) index) / +- (u32) base)) +- { +- status = AE_ERROR; +- return_value = 0L; /* reset */ +- } +- +- else { +- return_value *= base; +- return_value += index; +- converted = 1; +- } +- +- ++string; +- } +- +-done: +- /* +- * If appropriate, update the caller's pointer to the next +- * unconverted character in the buffer. +- */ +- if (terminator) { +- if (converted == 0 && return_value == 0L && string != NULL) { +- *terminator = (NATIVE_CHAR *) string_start; +- } +- +- else { +- *terminator = (NATIVE_CHAR *) string; +- } +- } +- +- if (status == AE_ERROR) { +- return_value = ACPI_UINT32_MAX; +- } +- +- /* +- * If a minus sign was present, then "the conversion is negated": +- */ +- if (sign == NEGATIVE) { +- return_value = (ACPI_UINT32_MAX - return_value) + 1; +- } +- +- return (return_value); +-} +- +-#endif /* ACPI_USE_SYSTEM_CLIBRARY */ +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/common/cmcopy.c linux/drivers/acpi/common/cmcopy.c +--- /usr/src/linux/drivers/acpi/common/cmcopy.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/common/cmcopy.c Wed Dec 31 16:00:00 1969 +@@ -1,708 +0,0 @@ +-/****************************************************************************** +- * +- * Module Name: cmcopy - Internal to external object translation utilities +- * $Revision: 66 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acinterp.h" +-#include "acnamesp.h" +-#include "amlcode.h" +- +- +-#define _COMPONENT MISCELLANEOUS +- MODULE_NAME ("cmcopy") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_copy_isimple_to_esimple +- * +- * PARAMETERS: *Internal_object - Pointer to the object we are examining +- * *Buffer - Where the object is returned +- * *Space_used - Where the data length is returned +- * +- * RETURN: Status +- * +- * DESCRIPTION: This function is called to place a simple object in a user +- * buffer. +- * +- * The buffer is assumed to have sufficient space for the object. +- * +- ******************************************************************************/ +- +-static ACPI_STATUS +-acpi_cm_copy_isimple_to_esimple ( +- ACPI_OPERAND_OBJECT *internal_object, +- ACPI_OBJECT *external_object, +- u8 *data_space, +- u32 *buffer_space_used) +-{ +- u32 length = 0; +- ACPI_STATUS status = AE_OK; +- +- +- /* +- * Check for NULL object case (could be an uninitialized +- * package element +- */ +- +- if (!internal_object) { +- *buffer_space_used = 0; +- return (AE_OK); +- } +- +- /* Always clear the external object */ +- +- MEMSET (external_object, 0, sizeof (ACPI_OBJECT)); +- +- /* +- * In general, the external object will be the same type as +- * the internal object +- */ +- +- external_object->type = internal_object->common.type; +- +- /* However, only a limited number of external types are supported */ +- +- switch (internal_object->common.type) +- { +- +- case ACPI_TYPE_STRING: +- +- length = internal_object->string.length + 1; +- external_object->string.length = internal_object->string.length; +- external_object->string.pointer = (NATIVE_CHAR *) data_space; +- MEMCPY ((void *) data_space, (void *) internal_object->string.pointer, length); +- break; +- +- +- case ACPI_TYPE_BUFFER: +- +- length = internal_object->buffer.length; +- external_object->buffer.length = internal_object->buffer.length; +- external_object->buffer.pointer = data_space; +- MEMCPY ((void *) data_space, (void *) internal_object->buffer.pointer, length); +- break; +- +- +- case ACPI_TYPE_INTEGER: +- +- external_object->integer.value= internal_object->integer.value; +- break; +- +- +- case INTERNAL_TYPE_REFERENCE: +- +- /* +- * This is an object reference. Attempt to dereference it. +- */ +- +- switch (internal_object->reference.op_code) +- { +- case AML_ZERO_OP: +- external_object->type = ACPI_TYPE_INTEGER; +- external_object->integer.value = 0; +- break; +- +- case AML_ONE_OP: +- external_object->type = ACPI_TYPE_INTEGER; +- external_object->integer.value = 1; +- break; +- +- case AML_ONES_OP: +- external_object->type = ACPI_TYPE_INTEGER; +- external_object->integer.value = ACPI_INTEGER_MAX; +- break; +- +- case AML_NAMEPATH_OP: +- /* +- * This is a named reference, get the string. We already know that +- * we have room for it, use max length +- */ +- length = MAX_STRING_LENGTH; +- external_object->type = ACPI_TYPE_STRING; +- external_object->string.pointer = (NATIVE_CHAR *) data_space; +- status = acpi_ns_handle_to_pathname ((ACPI_HANDLE *) internal_object->reference.node, +- &length, (char *) data_space); +- break; +- +- default: +- /* +- * Use the object type of "Any" to indicate a reference +- * to object containing a handle to an ACPI named object. +- */ +- external_object->type = ACPI_TYPE_ANY; +- external_object->reference.handle = internal_object->reference.node; +- break; +- } +- break; +- +- +- case ACPI_TYPE_PROCESSOR: +- +- external_object->processor.proc_id = internal_object->processor.proc_id; +- external_object->processor.pblk_address = internal_object->processor.address; +- external_object->processor.pblk_length = internal_object->processor.length; +- break; +- +- +- case ACPI_TYPE_POWER: +- +- external_object->power_resource.system_level = +- internal_object->power_resource.system_level; +- +- external_object->power_resource.resource_order = +- internal_object->power_resource.resource_order; +- break; +- +- +- default: +- /* +- * There is no corresponding external object type +- */ +- return (AE_SUPPORT); +- break; +- } +- +- +- *buffer_space_used = (u32) ROUND_UP_TO_NATIVE_WORD (length); +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_copy_ielement_to_eelement +- * +- * PARAMETERS: ACPI_PKG_CALLBACK +- * +- * RETURN: Status +- * +- * DESCRIPTION: Copy one package element to another package element +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_copy_ielement_to_eelement ( +- u8 object_type, +- ACPI_OPERAND_OBJECT *source_object, +- ACPI_GENERIC_STATE *state, +- void *context) +-{ +- ACPI_STATUS status = AE_OK; +- ACPI_PKG_INFO *info = (ACPI_PKG_INFO *) context; +- u32 object_space; +- u32 this_index; +- ACPI_OBJECT *target_object; +- +- +- this_index = state->pkg.index; +- target_object = (ACPI_OBJECT *) +- &((ACPI_OBJECT *)(state->pkg.dest_object))->package.elements[this_index]; +- +- +- switch (object_type) +- { +- case 0: +- +- /* +- * This is a simple or null object -- get the size +- */ +- +- status = acpi_cm_copy_isimple_to_esimple (source_object, +- target_object, info->free_space, &object_space); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- break; +- +- case 1: +- +- /* +- * Build the package object +- */ +- target_object->type = ACPI_TYPE_PACKAGE; +- target_object->package.count = source_object->package.count; +- target_object->package.elements = (ACPI_OBJECT *) info->free_space; +- +- /* +- * Pass the new package object back to the package walk routine +- */ +- state->pkg.this_target_obj = target_object; +- +- /* +- * Save space for the array of objects (Package elements) +- * update the buffer length counter +- */ +- object_space = (u32) ROUND_UP_TO_NATIVE_WORD ( +- target_object->package.count * sizeof (ACPI_OBJECT)); +- break; +- +- default: +- return (AE_BAD_PARAMETER); +- } +- +- +- info->free_space += object_space; +- info->length += object_space; +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_copy_ipackage_to_epackage +- * +- * PARAMETERS: *Internal_object - Pointer to the object we are returning +- * *Buffer - Where the object is returned +- * *Space_used - Where the object length is returned +- * +- * RETURN: Status +- * +- * DESCRIPTION: This function is called to place a package object in a user +- * buffer. A package object by definition contains other objects. +- * +- * The buffer is assumed to have sufficient space for the object. +- * The caller must have verified the buffer length needed using the +- * Acpi_cm_get_object_size function before calling this function. +- * +- ******************************************************************************/ +- +-static ACPI_STATUS +-acpi_cm_copy_ipackage_to_epackage ( +- ACPI_OPERAND_OBJECT *internal_object, +- u8 *buffer, +- u32 *space_used) +-{ +- ACPI_OBJECT *external_object; +- ACPI_STATUS status; +- ACPI_PKG_INFO info; +- +- +- /* +- * First package at head of the buffer +- */ +- external_object = (ACPI_OBJECT *) buffer; +- +- /* +- * Free space begins right after the first package +- */ +- info.length = 0; +- info.object_space = 0; +- info.num_packages = 1; +- info.free_space = buffer + ROUND_UP_TO_NATIVE_WORD (sizeof (ACPI_OBJECT)); +- +- +- external_object->type = internal_object->common.type; +- external_object->package.count = internal_object->package.count; +- external_object->package.elements = (ACPI_OBJECT *) info.free_space; +- +- +- /* +- * Build an array of ACPI_OBJECTS in the buffer +- * and move the free space past it +- */ +- +- info.free_space += external_object->package.count * +- ROUND_UP_TO_NATIVE_WORD (sizeof (ACPI_OBJECT)); +- +- +- status = acpi_cm_walk_package_tree (internal_object, external_object, +- acpi_cm_copy_ielement_to_eelement, &info); +- +- *space_used = info.length; +- +- return (status); +- +-} +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_copy_iobject_to_eobject +- * +- * PARAMETERS: *Internal_object - The internal object to be converted +- * *Buffer_ptr - Where the object is returned +- * +- * RETURN: Status +- * +- * DESCRIPTION: This function is called to build an API object to be returned to +- * the caller. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_copy_iobject_to_eobject ( +- ACPI_OPERAND_OBJECT *internal_object, +- ACPI_BUFFER *ret_buffer) +-{ +- ACPI_STATUS status; +- +- +- if (IS_THIS_OBJECT_TYPE (internal_object, ACPI_TYPE_PACKAGE)) { +- /* +- * Package object: Copy all subobjects (including +- * nested packages) +- */ +- status = acpi_cm_copy_ipackage_to_epackage (internal_object, +- ret_buffer->pointer, &ret_buffer->length); +- } +- +- else { +- /* +- * Build a simple object (no nested objects) +- */ +- status = acpi_cm_copy_isimple_to_esimple (internal_object, +- (ACPI_OBJECT *) ret_buffer->pointer, +- ((u8 *) ret_buffer->pointer + +- ROUND_UP_TO_NATIVE_WORD (sizeof (ACPI_OBJECT))), +- &ret_buffer->length); +- /* +- * build simple does not include the object size in the length +- * so we add it in here +- */ +- ret_buffer->length += sizeof (ACPI_OBJECT); +- } +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_copy_esimple_to_isimple +- * +- * PARAMETERS: *External_object - The external object to be converted +- * *Internal_object - Where the internal object is returned +- * +- * RETURN: Status +- * +- * DESCRIPTION: This function copies an external object to an internal one. +- * NOTE: Pointers can be copied, we don't need to copy data. +- * (The pointers have to be valid in our address space no matter +- * what we do with them!) +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_copy_esimple_to_isimple ( +- ACPI_OBJECT *external_object, +- ACPI_OPERAND_OBJECT *internal_object) +-{ +- +- +- internal_object->common.type = (u8) external_object->type; +- +- switch (external_object->type) +- { +- +- case ACPI_TYPE_STRING: +- +- internal_object->string.length = external_object->string.length; +- internal_object->string.pointer = external_object->string.pointer; +- break; +- +- +- case ACPI_TYPE_BUFFER: +- +- internal_object->buffer.length = external_object->buffer.length; +- internal_object->buffer.pointer = external_object->buffer.pointer; +- break; +- +- +- case ACPI_TYPE_INTEGER: +- /* +- * Number is included in the object itself +- */ +- internal_object->integer.value = external_object->integer.value; +- break; +- +- +- default: +- return (AE_CTRL_RETURN_VALUE); +- break; +- } +- +- +- return (AE_OK); +-} +- +- +-#ifdef ACPI_FUTURE_IMPLEMENTATION +- +-/* Code to convert packages that are parameters to control methods */ +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_copy_epackage_to_ipackage +- * +- * PARAMETERS: *Internal_object - Pointer to the object we are returning +- * *Buffer - Where the object is returned +- * *Space_used - Where the length of the object is returned +- * +- * RETURN: Status - the status of the call +- * +- * DESCRIPTION: This function is called to place a package object in a user +- * buffer. A package object by definition contains other objects. +- * +- * The buffer is assumed to have sufficient space for the object. +- * The caller must have verified the buffer length needed using the +- * Acpi_cm_get_object_size function before calling this function. +- * +- ******************************************************************************/ +- +-static ACPI_STATUS +-acpi_cm_copy_epackage_to_ipackage ( +- ACPI_OPERAND_OBJECT *internal_object, +- u8 *buffer, +- u32 *space_used) +-{ +- u8 *free_space; +- ACPI_OBJECT *external_object; +- u32 length = 0; +- u32 this_index; +- u32 object_space = 0; +- ACPI_OPERAND_OBJECT *this_internal_obj; +- ACPI_OBJECT *this_external_obj; +- +- +- /* +- * First package at head of the buffer +- */ +- external_object = (ACPI_OBJECT *)buffer; +- +- /* +- * Free space begins right after the first package +- */ +- free_space = buffer + sizeof(ACPI_OBJECT); +- +- +- external_object->type = internal_object->common.type; +- external_object->package.count = internal_object->package.count; +- external_object->package.elements = (ACPI_OBJECT *)free_space; +- +- +- /* +- * Build an array of ACPI_OBJECTS in the buffer +- * and move the free space past it +- */ +- +- free_space += external_object->package.count * sizeof(ACPI_OBJECT); +- +- +- /* Call Walk_package */ +- +-} +- +-#endif /* Future implementation */ +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_copy_eobject_to_iobject +- * +- * PARAMETERS: *Internal_object - The external object to be converted +- * *Buffer_ptr - Where the internal object is returned +- * +- * RETURN: Status - the status of the call +- * +- * DESCRIPTION: Converts an external object to an internal object. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_copy_eobject_to_iobject ( +- ACPI_OBJECT *external_object, +- ACPI_OPERAND_OBJECT *internal_object) +-{ +- ACPI_STATUS status; +- +- +- if (external_object->type == ACPI_TYPE_PACKAGE) { +- /* +- * Package objects contain other objects (which can be objects) +- * buildpackage does it all +- * +- * TBD: Package conversion must be completed and tested +- * NOTE: this code converts packages as input parameters to +- * control methods only. This is a very, very rare case. +- */ +-/* +- Status = Acpi_cm_copy_epackage_to_ipackage(Internal_object, +- Ret_buffer->Pointer, +- &Ret_buffer->Length); +-*/ +- return (AE_NOT_IMPLEMENTED); +- } +- +- else { +- /* +- * Build a simple object (no nested objects) +- */ +- status = acpi_cm_copy_esimple_to_isimple (external_object, internal_object); +- /* +- * build simple does not include the object size in the length +- * so we add it in here +- */ +- } +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_copy_ielement_to_ielement +- * +- * PARAMETERS: ACPI_PKG_CALLBACK +- * +- * RETURN: Status - the status of the call +- * +- * DESCRIPTION: Copy one package element to another package element +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_copy_ielement_to_ielement ( +- u8 object_type, +- ACPI_OPERAND_OBJECT *source_object, +- ACPI_GENERIC_STATE *state, +- void *context) +-{ +- ACPI_STATUS status = AE_OK; +- u32 this_index; +- ACPI_OPERAND_OBJECT **this_target_ptr; +- ACPI_OPERAND_OBJECT *target_object; +- +- +- this_index = state->pkg.index; +- this_target_ptr = (ACPI_OPERAND_OBJECT **) +- &state->pkg.dest_object->package.elements[this_index]; +- +- switch (object_type) +- { +- case 0: +- +- /* +- * This is a simple object, just copy it +- */ +- target_object = acpi_cm_create_internal_object (source_object->common.type); +- if (!target_object) { +- return (AE_NO_MEMORY); +- } +- +- status = acpi_aml_store_object_to_object (source_object, target_object, +- (ACPI_WALK_STATE *) context); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- *this_target_ptr = target_object; +- break; +- +- +- case 1: +- /* +- * This object is a package - go down another nesting level +- * Create and build the package object +- */ +- target_object = acpi_cm_create_internal_object (ACPI_TYPE_PACKAGE); +- if (!target_object) { +- /* TBD: must delete package created up to this point */ +- +- return (AE_NO_MEMORY); +- } +- +- target_object->package.count = source_object->package.count; +- +- /* +- * Pass the new package object back to the package walk routine +- */ +- state->pkg.this_target_obj = target_object; +- +- /* +- * Store the object pointer in the parent package object +- */ +- *this_target_ptr = target_object; +- break; +- +- default: +- return (AE_BAD_PARAMETER); +- } +- +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_copy_ipackage_to_ipackage +- * +- * PARAMETERS: *Source_obj - Pointer to the source package object +- * *Dest_obj - Where the internal object is returned +- * +- * RETURN: Status - the status of the call +- * +- * DESCRIPTION: This function is called to copy an internal package object +- * into another internal package object. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_copy_ipackage_to_ipackage ( +- ACPI_OPERAND_OBJECT *source_obj, +- ACPI_OPERAND_OBJECT *dest_obj, +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_STATUS status = AE_OK; +- +- +- dest_obj->common.type = source_obj->common.type; +- dest_obj->package.count = source_obj->package.count; +- +- +- /* +- * Create the object array and walk the source package tree +- */ +- +- dest_obj->package.elements = acpi_cm_callocate ((source_obj->package.count + 1) * +- sizeof (void *)); +- dest_obj->package.next_element = dest_obj->package.elements; +- +- if (!dest_obj->package.elements) { +- REPORT_ERROR ( +- ("Aml_build_copy_internal_package_object: Package allocation failure\n")); +- return (AE_NO_MEMORY); +- } +- +- +- status = acpi_cm_walk_package_tree (source_obj, dest_obj, +- acpi_cm_copy_ielement_to_ielement, walk_state); +- +- return (status); +-} +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/common/cmdebug.c linux/drivers/acpi/common/cmdebug.c +--- /usr/src/linux/drivers/acpi/common/cmdebug.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/common/cmdebug.c Wed Dec 31 16:00:00 1969 +@@ -1,559 +0,0 @@ +-/****************************************************************************** +- * +- * Module Name: cmdebug - Debug print routines +- * $Revision: 64 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +- +-#define _COMPONENT MISCELLANEOUS +- MODULE_NAME ("cmdebug") +- +- +-/***************************************************************************** +- * +- * FUNCTION: Get/Set debug level +- * +- * DESCRIPTION: Get or set value of the debug flag +- * +- * These are used to allow user's to get/set the debug level +- * +- ****************************************************************************/ +- +- +-u32 +-get_debug_level (void) +-{ +- +- return (acpi_dbg_level); +-} +- +-void +-set_debug_level ( +- u32 new_debug_level) +-{ +- +- acpi_dbg_level = new_debug_level; +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Function_trace +- * +- * PARAMETERS: Module_name - Caller's module name (for error output) +- * Line_number - Caller's line number (for error output) +- * Component_id - Caller's component ID (for error output) +- * Function_name - Name of Caller's function +- * +- * RETURN: None +- * +- * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is +- * set in Debug_level +- * +- ****************************************************************************/ +- +-void +-function_trace ( +- NATIVE_CHAR *module_name, +- u32 line_number, +- u32 component_id, +- NATIVE_CHAR *function_name) +-{ +- +- acpi_gbl_nesting_level++; +- +- debug_print (module_name, line_number, component_id, +- TRACE_FUNCTIONS, +- " %2.2ld Entered Function: %s\n", +- acpi_gbl_nesting_level, function_name); +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Function_trace_ptr +- * +- * PARAMETERS: Module_name - Caller's module name (for error output) +- * Line_number - Caller's line number (for error output) +- * Component_id - Caller's component ID (for error output) +- * Function_name - Name of Caller's function +- * Pointer - Pointer to display +- * +- * RETURN: None +- * +- * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is +- * set in Debug_level +- * +- ****************************************************************************/ +- +-void +-function_trace_ptr ( +- NATIVE_CHAR *module_name, +- u32 line_number, +- u32 component_id, +- NATIVE_CHAR *function_name, +- void *pointer) +-{ +- +- acpi_gbl_nesting_level++; +- debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS, +- " %2.2ld Entered Function: %s, %p\n", +- acpi_gbl_nesting_level, function_name, pointer); +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Function_trace_str +- * +- * PARAMETERS: Module_name - Caller's module name (for error output) +- * Line_number - Caller's line number (for error output) +- * Component_id - Caller's component ID (for error output) +- * Function_name - Name of Caller's function +- * String - Additional string to display +- * +- * RETURN: None +- * +- * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is +- * set in Debug_level +- * +- ****************************************************************************/ +- +-void +-function_trace_str ( +- NATIVE_CHAR *module_name, +- u32 line_number, +- u32 component_id, +- NATIVE_CHAR *function_name, +- NATIVE_CHAR *string) +-{ +- +- acpi_gbl_nesting_level++; +- debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS, +- " %2.2ld Entered Function: %s, %s\n", +- acpi_gbl_nesting_level, function_name, string); +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Function_trace_u32 +- * +- * PARAMETERS: Module_name - Caller's module name (for error output) +- * Line_number - Caller's line number (for error output) +- * Component_id - Caller's component ID (for error output) +- * Function_name - Name of Caller's function +- * Integer - Integer to display +- * +- * RETURN: None +- * +- * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is +- * set in Debug_level +- * +- ****************************************************************************/ +- +-void +-function_trace_u32 ( +- NATIVE_CHAR *module_name, +- u32 line_number, +- u32 component_id, +- NATIVE_CHAR *function_name, +- u32 integer) +-{ +- +- acpi_gbl_nesting_level++; +- debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS, +- " %2.2ld Entered Function: %s, %lX\n", +- acpi_gbl_nesting_level, function_name, integer); +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Function_exit +- * +- * PARAMETERS: Module_name - Caller's module name (for error output) +- * Line_number - Caller's line number (for error output) +- * Component_id - Caller's component ID (for error output) +- * Function_name - Name of Caller's function +- * +- * RETURN: None +- * +- * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is +- * set in Debug_level +- * +- ****************************************************************************/ +- +-void +-function_exit ( +- NATIVE_CHAR *module_name, +- u32 line_number, +- u32 component_id, +- NATIVE_CHAR *function_name) +-{ +- +- debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS, +- " %2.2ld Exiting Function: %s\n", +- acpi_gbl_nesting_level, function_name); +- +- acpi_gbl_nesting_level--; +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Function_status_exit +- * +- * PARAMETERS: Module_name - Caller's module name (for error output) +- * Line_number - Caller's line number (for error output) +- * Component_id - Caller's component ID (for error output) +- * Function_name - Name of Caller's function +- * Status - Exit status code +- * +- * RETURN: None +- * +- * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is +- * set in Debug_level. Prints exit status also. +- * +- ****************************************************************************/ +- +-void +-function_status_exit ( +- NATIVE_CHAR *module_name, +- u32 line_number, +- u32 component_id, +- NATIVE_CHAR *function_name, +- ACPI_STATUS status) +-{ +- +- debug_print (module_name, line_number, component_id, +- TRACE_FUNCTIONS, +- " %2.2ld Exiting Function: %s, %s\n", +- acpi_gbl_nesting_level, +- function_name, +- acpi_cm_format_exception (status)); +- +- acpi_gbl_nesting_level--; +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Function_value_exit +- * +- * PARAMETERS: Module_name - Caller's module name (for error output) +- * Line_number - Caller's line number (for error output) +- * Component_id - Caller's component ID (for error output) +- * Function_name - Name of Caller's function +- * Value - Value to be printed with exit msg +- * +- * RETURN: None +- * +- * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is +- * set in Debug_level. Prints exit value also. +- * +- ****************************************************************************/ +- +-void +-function_value_exit ( +- NATIVE_CHAR *module_name, +- u32 line_number, +- u32 component_id, +- NATIVE_CHAR *function_name, +- ACPI_INTEGER value) +-{ +- +- debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS, +- " %2.2ld Exiting Function: %s, %X\n", +- acpi_gbl_nesting_level, function_name, value); +- +- acpi_gbl_nesting_level--; +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Function_ptr_exit +- * +- * PARAMETERS: Module_name - Caller's module name (for error output) +- * Line_number - Caller's line number (for error output) +- * Component_id - Caller's component ID (for error output) +- * Function_name - Name of Caller's function +- * Value - Value to be printed with exit msg +- * +- * RETURN: None +- * +- * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is +- * set in Debug_level. Prints exit value also. +- * +- ****************************************************************************/ +- +-void +-function_ptr_exit ( +- NATIVE_CHAR *module_name, +- u32 line_number, +- u32 component_id, +- NATIVE_CHAR *function_name, +- u8 *ptr) +-{ +- +- debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS, +- " %2.2ld Exiting Function: %s, %p\n", +- acpi_gbl_nesting_level, function_name, ptr); +- +- acpi_gbl_nesting_level--; +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Debug_print +- * +- * PARAMETERS: Module_name - Caller's module name (for error output) +- * Line_number - Caller's line number (for error output) +- * Component_id - Caller's component ID (for error output) +- * Print_level - Requested debug print level +- * Format - Printf format field +- * ... - Optional printf arguments +- * +- * RETURN: None +- * +- * DESCRIPTION: Print error message with prefix consisting of the module name, +- * line number, and component ID. +- * +- ****************************************************************************/ +- +-void +-debug_print ( +- NATIVE_CHAR *module_name, +- u32 line_number, +- u32 component_id, +- u32 print_level, +- NATIVE_CHAR *format, +- ...) +-{ +- va_list args; +- +- +- /* Both the level and the component must be enabled */ +- +- if ((print_level & acpi_dbg_level) && +- (component_id & acpi_dbg_layer)) +- { +- va_start (args, format); +- +- acpi_os_printf ("%8s-%04d: ", module_name, line_number); +- acpi_os_vprintf (format, args); +- } +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Debug_print_prefix +- * +- * PARAMETERS: Module_name - Caller's module name (for error output) +- * Line_number - Caller's line number (for error output) +- * Component_id - Caller's component ID (for error output) +- * +- * RETURN: None +- * +- * DESCRIPTION: Print the prefix part of an error message, consisting of the +- * module name, and line number +- * +- ****************************************************************************/ +- +-void +-debug_print_prefix ( +- NATIVE_CHAR *module_name, +- u32 line_number) +-{ +- +- +- acpi_os_printf ("%8s-%04d: ", module_name, line_number); +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Debug_print_raw +- * +- * PARAMETERS: Format - Printf format field +- * ... - Optional printf arguments +- * +- * RETURN: None +- * +- * DESCRIPTION: Print error message -- without module/line indentifiers +- * +- ****************************************************************************/ +- +-void +-debug_print_raw ( +- NATIVE_CHAR *format, +- ...) +-{ +- va_list args; +- +- +- va_start (args, format); +- +- acpi_os_vprintf (format, args); +- +- va_end (args); +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Acpi_cm_dump_buffer +- * +- * PARAMETERS: Buffer - Buffer to dump +- * Count - Amount to dump, in bytes +- * Component_iD - Caller's component ID +- * +- * RETURN: None +- * +- * DESCRIPTION: Generic dump buffer in both hex and ascii. +- * +- ****************************************************************************/ +- +-void +-acpi_cm_dump_buffer ( +- u8 *buffer, +- u32 count, +- u32 display, +- u32 component_id) +-{ +- u32 i = 0; +- u32 j; +- u32 temp32; +- u8 buf_char; +- +- +- /* Only dump the buffer if tracing is enabled */ +- +- if (!((TRACE_TABLES & acpi_dbg_level) && +- (component_id & acpi_dbg_layer))) +- { +- return; +- } +- +- +- /* +- * Nasty little dump buffer routine! +- */ +- while (i < count) { +- /* Print current offset */ +- +- acpi_os_printf ("%05X ", i); +- +- +- /* Print 16 hex chars */ +- +- for (j = 0; j < 16;) { +- if (i + j >= count) { +- acpi_os_printf ("\n"); +- return; +- } +- +- /* Make sure that the s8 doesn't get sign-extended! */ +- +- switch (display) +- { +- /* Default is BYTE display */ +- +- default: +- +- acpi_os_printf ("%02X ", +- *((u8 *) &buffer[i + j])); +- j += 1; +- break; +- +- +- case DB_WORD_DISPLAY: +- +- MOVE_UNALIGNED16_TO_32 (&temp32, +- &buffer[i + j]); +- acpi_os_printf ("%04X ", temp32); +- j += 2; +- break; +- +- +- case DB_DWORD_DISPLAY: +- +- MOVE_UNALIGNED32_TO_32 (&temp32, +- &buffer[i + j]); +- acpi_os_printf ("%08X ", temp32); +- j += 4; +- break; +- +- +- case DB_QWORD_DISPLAY: +- +- MOVE_UNALIGNED32_TO_32 (&temp32, +- &buffer[i + j]); +- acpi_os_printf ("%08X", temp32); +- +- MOVE_UNALIGNED32_TO_32 (&temp32, +- &buffer[i + j + 4]); +- acpi_os_printf ("%08X ", temp32); +- j += 8; +- break; +- } +- } +- +- +- /* +- * Print the ASCII equivalent characters +- * But watch out for the bad unprintable ones... +- */ +- +- for (j = 0; j < 16; j++) { +- if (i + j >= count) { +- acpi_os_printf ("\n"); +- return; +- } +- +- buf_char = buffer[i + j]; +- if ((buf_char > 0x1F && buf_char < 0x2E) || +- (buf_char > 0x2F && buf_char < 0x61) || +- (buf_char > 0x60 && buf_char < 0x7F)) +- { +- acpi_os_printf ("%c", buf_char); +- } +- else { +- acpi_os_printf ("."); +- } +- } +- +- /* Done with that line. */ +- +- acpi_os_printf ("\n"); +- i += 16; +- } +- +- return; +-} +- +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/common/cmdelete.c linux/drivers/acpi/common/cmdelete.c +--- /usr/src/linux/drivers/acpi/common/cmdelete.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/common/cmdelete.c Wed Dec 31 16:00:00 1969 +@@ -1,591 +0,0 @@ +-/******************************************************************************* +- * +- * Module Name: cmdelete - object deletion and reference count utilities +- * $Revision: 62 $ +- * +- ******************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acinterp.h" +-#include "acnamesp.h" +-#include "actables.h" +-#include "acparser.h" +- +-#define _COMPONENT MISCELLANEOUS +- MODULE_NAME ("cmdelete") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_delete_internal_obj +- * +- * PARAMETERS: *Object - Pointer to the list to be deleted +- * +- * RETURN: None +- * +- * DESCRIPTION: Low level object deletion, after reference counts have been +- * updated (All reference counts, including sub-objects!) +- * +- ******************************************************************************/ +- +-void +-acpi_cm_delete_internal_obj ( +- ACPI_OPERAND_OBJECT *object) +-{ +- void *obj_pointer = NULL; +- ACPI_OPERAND_OBJECT *handler_desc; +- +- +- if (!object) { +- return; +- } +- +- /* +- * Must delete or free any pointers within the object that are not +- * actual ACPI objects (for example, a raw buffer pointer). +- */ +- +- switch (object->common.type) +- { +- +- case ACPI_TYPE_STRING: +- +- /* Free the actual string buffer */ +- +- obj_pointer = object->string.pointer; +- break; +- +- +- case ACPI_TYPE_BUFFER: +- +- /* Free the actual buffer */ +- +- obj_pointer = object->buffer.pointer; +- break; +- +- +- case ACPI_TYPE_PACKAGE: +- +- /* +- * Elements of the package are not handled here, they are deleted +- * separately +- */ +- +- /* Free the (variable length) element pointer array */ +- +- obj_pointer = object->package.elements; +- break; +- +- +- case ACPI_TYPE_MUTEX: +- +- acpi_os_delete_semaphore (object->mutex.semaphore); +- break; +- +- +- case ACPI_TYPE_EVENT: +- +- acpi_os_delete_semaphore (object->event.semaphore); +- object->event.semaphore = NULL; +- break; +- +- +- case ACPI_TYPE_METHOD: +- +- /* Delete the method semaphore if it exists */ +- +- if (object->method.semaphore) { +- acpi_os_delete_semaphore (object->method.semaphore); +- object->method.semaphore = NULL; +- } +- +- break; +- +- +- case ACPI_TYPE_REGION: +- +- +- if (object->region.extra) { +- /* +- * Free the Region_context if and only if the handler is one of the +- * default handlers -- and therefore, we created the context object +- * locally, it was not created by an external caller. +- */ +- handler_desc = object->region.addr_handler; +- if ((handler_desc) && +- (handler_desc->addr_handler.hflags == ADDR_HANDLER_DEFAULT_INSTALLED)) +- { +- obj_pointer = object->region.extra->extra.region_context; +- } +- +- /* Now we can free the Extra object */ +- +- acpi_cm_delete_object_desc (object->region.extra); +- } +- break; +- +- +- case ACPI_TYPE_FIELD_UNIT: +- +- if (object->field_unit.extra) { +- acpi_cm_delete_object_desc (object->field_unit.extra); +- } +- break; +- +- default: +- break; +- } +- +- +- /* +- * Delete any allocated memory found above +- */ +- +- if (obj_pointer) { +- if (!acpi_tb_system_table_pointer (obj_pointer)) { +- acpi_cm_free (obj_pointer); +- } +- } +- +- +- /* Only delete the object if it was dynamically allocated */ +- +- +- if (!(object->common.flags & AOPOBJ_STATIC_ALLOCATION)) { +- acpi_cm_delete_object_desc (object); +- +- } +- +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_delete_internal_object_list +- * +- * PARAMETERS: *Obj_list - Pointer to the list to be deleted +- * +- * RETURN: Status - the status of the call +- * +- * DESCRIPTION: This function deletes an internal object list, including both +- * simple objects and package objects +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_delete_internal_object_list ( +- ACPI_OPERAND_OBJECT **obj_list) +-{ +- ACPI_OPERAND_OBJECT **internal_obj; +- +- +- /* Walk the null-terminated internal list */ +- +- for (internal_obj = obj_list; *internal_obj; internal_obj++) { +- /* +- * Check for a package +- * Simple objects are simply stored in the array and do not +- * need to be deleted separately. +- */ +- +- if (IS_THIS_OBJECT_TYPE ((*internal_obj), ACPI_TYPE_PACKAGE)) { +- /* Delete the package */ +- +- /* +- * TBD: [Investigate] This might not be the right thing to do, +- * depending on how the internal package object was allocated!!! +- */ +- acpi_cm_delete_internal_obj (*internal_obj); +- } +- +- } +- +- /* Free the combined parameter pointer list and object array */ +- +- acpi_cm_free (obj_list); +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_update_ref_count +- * +- * PARAMETERS: *Object - Object whose ref count is to be updated +- * Action - What to do +- * +- * RETURN: New ref count +- * +- * DESCRIPTION: Modify the ref count and return it. +- * +- ******************************************************************************/ +- +-static void +-acpi_cm_update_ref_count ( +- ACPI_OPERAND_OBJECT *object, +- u32 action) +-{ +- u16 count; +- u16 new_count; +- +- +- if (!object) { +- return; +- } +- +- +- count = object->common.reference_count; +- new_count = count; +- +- /* +- * Reference count action (increment, decrement, or force delete) +- */ +- +- switch (action) +- { +- +- case REF_INCREMENT: +- +- new_count++; +- object->common.reference_count = new_count; +- +- break; +- +- +- case REF_DECREMENT: +- +- if (count < 1) { +- new_count = 0; +- } +- +- else { +- new_count--; +- +- } +- +- +- object->common.reference_count = new_count; +- if (new_count == 0) { +- acpi_cm_delete_internal_obj (object); +- } +- +- break; +- +- +- case REF_FORCE_DELETE: +- +- new_count = 0; +- object->common.reference_count = new_count; +- acpi_cm_delete_internal_obj (object); +- break; +- +- +- default: +- +- break; +- } +- +- +- /* +- * Sanity check the reference count, for debug purposes only. +- * (A deleted object will have a huge reference count) +- */ +- +- +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_update_object_reference +- * +- * PARAMETERS: *Object - Increment ref count for this object +- * and all sub-objects +- * Action - Either REF_INCREMENT or REF_DECREMENT or +- * REF_FORCE_DELETE +- * +- * RETURN: Status +- * +- * DESCRIPTION: Increment the object reference count +- * +- * Object references are incremented when: +- * 1) An object is attached to a Node (namespace object) +- * 2) An object is copied (all subobjects must be incremented) +- * +- * Object references are decremented when: +- * 1) An object is detached from an Node +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_update_object_reference ( +- ACPI_OPERAND_OBJECT *object, +- u16 action) +-{ +- ACPI_STATUS status; +- u32 i; +- ACPI_OPERAND_OBJECT *next; +- ACPI_OPERAND_OBJECT *new; +- ACPI_GENERIC_STATE *state_list = NULL; +- ACPI_GENERIC_STATE *state; +- +- +- /* Ignore a null object ptr */ +- +- if (!object) { +- return (AE_OK); +- } +- +- +- /* +- * Make sure that this isn't a namespace handle or an AML pointer +- */ +- +- if (VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_NAMED)) { +- return (AE_OK); +- } +- +- if (acpi_tb_system_table_pointer (object)) { +- return (AE_OK); +- } +- +- +- state = acpi_cm_create_update_state (object, action); +- +- while (state) { +- +- object = state->update.object; +- action = state->update.value; +- acpi_cm_delete_generic_state (state); +- +- /* +- * All sub-objects must have their reference count incremented also. +- * Different object types have different subobjects. +- */ +- switch (object->common.type) +- { +- +- case ACPI_TYPE_DEVICE: +- +- status = acpi_cm_create_update_state_and_push (object->device.addr_handler, +- action, &state_list); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- acpi_cm_update_ref_count (object->device.sys_handler, action); +- acpi_cm_update_ref_count (object->device.drv_handler, action); +- break; +- +- +- case INTERNAL_TYPE_ADDRESS_HANDLER: +- +- /* Must walk list of address handlers */ +- +- next = object->addr_handler.next; +- while (next) { +- new = next->addr_handler.next; +- acpi_cm_update_ref_count (next, action); +- +- next = new; +- } +- break; +- +- +- case ACPI_TYPE_PACKAGE: +- +- /* +- * We must update all the sub-objects of the package +- * (Each of whom may have their own sub-objects, etc. +- */ +- for (i = 0; i < object->package.count; i++) { +- /* +- * Push each element onto the stack for later processing. +- * Note: There can be null elements within the package, +- * these are simply ignored +- */ +- +- status = acpi_cm_create_update_state_and_push ( +- object->package.elements[i], action, &state_list); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- } +- break; +- +- +- case ACPI_TYPE_FIELD_UNIT: +- +- status = acpi_cm_create_update_state_and_push ( +- object->field_unit.container, action, &state_list); +- +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- break; +- +- +- case INTERNAL_TYPE_DEF_FIELD: +- +- status = acpi_cm_create_update_state_and_push ( +- object->field.container, action, &state_list); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- break; +- +- +- case INTERNAL_TYPE_BANK_FIELD: +- +- status = acpi_cm_create_update_state_and_push ( +- object->bank_field.bank_select, action, &state_list); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- status = acpi_cm_create_update_state_and_push ( +- object->bank_field.container, action, &state_list); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- break; +- +- +- case ACPI_TYPE_REGION: +- +- /* TBD: [Investigate] +- Acpi_cm_update_ref_count (Object->Region.Addr_handler, Action); +- */ +-/* +- Status = +- Acpi_cm_create_update_state_and_push (Object->Region.Addr_handler, +- Action, &State_list); +- if (ACPI_FAILURE (Status)) { +- return (Status); +- } +-*/ +- break; +- +- +- case INTERNAL_TYPE_REFERENCE: +- +- break; +- } +- +- +- /* +- * Now we can update the count in the main object. This can only +- * happen after we update the sub-objects in case this causes the +- * main object to be deleted. +- */ +- +- acpi_cm_update_ref_count (object, action); +- +- +- /* Move on to the next object to be updated */ +- +- state = acpi_cm_pop_generic_state (&state_list); +- } +- +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_add_reference +- * +- * PARAMETERS: *Object - Object whose reference count is to be +- * incremented +- * +- * RETURN: None +- * +- * DESCRIPTION: Add one reference to an ACPI object +- * +- ******************************************************************************/ +- +-void +-acpi_cm_add_reference ( +- ACPI_OPERAND_OBJECT *object) +-{ +- +- +- /* +- * Ensure that we have a valid object +- */ +- +- if (!acpi_cm_valid_internal_object (object)) { +- return; +- } +- +- /* +- * We have a valid ACPI internal object, now increment the reference count +- */ +- +- acpi_cm_update_object_reference (object, REF_INCREMENT); +- +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_remove_reference +- * +- * PARAMETERS: *Object - Object whose ref count will be decremented +- * +- * RETURN: None +- * +- * DESCRIPTION: Decrement the reference count of an ACPI internal object +- * +- ******************************************************************************/ +- +-void +-acpi_cm_remove_reference ( +- ACPI_OPERAND_OBJECT *object) +-{ +- +- +- /* +- * Ensure that we have a valid object +- */ +- +- if (!acpi_cm_valid_internal_object (object)) { +- return; +- } +- +- /* +- * Decrement the reference count, and only actually delete the object +- * if the reference count becomes 0. (Must also decrement the ref count +- * of all subobjects!) +- */ +- +- acpi_cm_update_object_reference (object, REF_DECREMENT); +- +- return; +-} +- +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/common/cmeval.c linux/drivers/acpi/common/cmeval.c +--- /usr/src/linux/drivers/acpi/common/cmeval.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/common/cmeval.c Wed Dec 31 16:00:00 1969 +@@ -1,308 +0,0 @@ +-/****************************************************************************** +- * +- * Module Name: cmeval - Object evaluation +- * $Revision: 21 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acnamesp.h" +-#include "acinterp.h" +- +- +-#define _COMPONENT MISCELLANEOUS +- MODULE_NAME ("cmeval") +- +- +-/**************************************************************************** +- * +- * FUNCTION: Acpi_cm_evaluate_numeric_object +- * +- * PARAMETERS: *Object_name - Object name to be evaluated +- * Device_node - Node for the device +- * *Address - Where the value is returned +- * +- * RETURN: Status +- * +- * DESCRIPTION: evaluates a numeric namespace object for a selected device +- * and stores results in *Address. +- * +- * NOTE: Internal function, no parameter validation +- * +- ***************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_evaluate_numeric_object ( +- NATIVE_CHAR *object_name, +- ACPI_NAMESPACE_NODE *device_node, +- ACPI_INTEGER *address) +-{ +- ACPI_OPERAND_OBJECT *obj_desc; +- ACPI_STATUS status; +- +- +- /* Execute the method */ +- +- status = acpi_ns_evaluate_relative (device_node, object_name, NULL, &obj_desc); +- if (ACPI_FAILURE (status)) { +- +- return (status); +- } +- +- +- /* Did we get a return object? */ +- +- if (!obj_desc) { +- return (AE_TYPE); +- } +- +- /* Is the return object of the correct type? */ +- +- if (obj_desc->common.type != ACPI_TYPE_INTEGER) { +- status = AE_TYPE; +- } +- else { +- /* +- * Since the structure is a union, setting any field will set all +- * of the variables in the union +- */ +- *address = obj_desc->integer.value; +- } +- +- /* On exit, we must delete the return object */ +- +- acpi_cm_remove_reference (obj_desc); +- +- return (status); +-} +- +- +-/**************************************************************************** +- * +- * FUNCTION: Acpi_cm_execute_HID +- * +- * PARAMETERS: Device_node - Node for the device +- * *Hid - Where the HID is returned +- * +- * RETURN: Status +- * +- * DESCRIPTION: Executes the _HID control method that returns the hardware +- * ID of the device. +- * +- * NOTE: Internal function, no parameter validation +- * +- ***************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_execute_HID ( +- ACPI_NAMESPACE_NODE *device_node, +- DEVICE_ID *hid) +-{ +- ACPI_OPERAND_OBJECT *obj_desc; +- ACPI_STATUS status; +- +- +- /* Execute the method */ +- +- status = acpi_ns_evaluate_relative (device_node, +- METHOD_NAME__HID, NULL, &obj_desc); +- if (ACPI_FAILURE (status)) { +- +- +- return (status); +- } +- +- /* Did we get a return object? */ +- +- if (!obj_desc) { +- return (AE_TYPE); +- } +- +- /* +- * A _HID can return either a Number (32 bit compressed EISA ID) or +- * a string +- */ +- +- if ((obj_desc->common.type != ACPI_TYPE_INTEGER) && +- (obj_desc->common.type != ACPI_TYPE_STRING)) +- { +- status = AE_TYPE; +- } +- +- else { +- if (obj_desc->common.type == ACPI_TYPE_INTEGER) { +- /* Convert the Numeric HID to string */ +- +- acpi_aml_eisa_id_to_string ((u32) obj_desc->integer.value, hid->buffer); +- } +- +- else { +- /* Copy the String HID from the returned object */ +- +- STRNCPY(hid->buffer, obj_desc->string.pointer, sizeof(hid->buffer)); +- } +- } +- +- +- /* On exit, we must delete the return object */ +- +- acpi_cm_remove_reference (obj_desc); +- +- return (status); +-} +- +- +-/**************************************************************************** +- * +- * FUNCTION: Acpi_cm_execute_UID +- * +- * PARAMETERS: Device_node - Node for the device +- * *Uid - Where the UID is returned +- * +- * RETURN: Status +- * +- * DESCRIPTION: Executes the _UID control method that returns the hardware +- * ID of the device. +- * +- * NOTE: Internal function, no parameter validation +- * +- ***************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_execute_UID ( +- ACPI_NAMESPACE_NODE *device_node, +- DEVICE_ID *uid) +-{ +- ACPI_OPERAND_OBJECT *obj_desc; +- ACPI_STATUS status; +- +- +- /* Execute the method */ +- +- status = acpi_ns_evaluate_relative (device_node, +- METHOD_NAME__UID, NULL, &obj_desc); +- if (ACPI_FAILURE (status)) { +- +- +- return (status); +- } +- +- /* Did we get a return object? */ +- +- if (!obj_desc) { +- return (AE_TYPE); +- } +- +- /* +- * A _UID can return either a Number (32 bit compressed EISA ID) or +- * a string +- */ +- +- if ((obj_desc->common.type != ACPI_TYPE_INTEGER) && +- (obj_desc->common.type != ACPI_TYPE_STRING)) +- { +- status = AE_TYPE; +- } +- +- else { +- if (obj_desc->common.type == ACPI_TYPE_INTEGER) { +- /* Convert the Numeric UID to string */ +- +- acpi_aml_unsigned_integer_to_string (obj_desc->integer.value, uid->buffer); +- } +- +- else { +- /* Copy the String UID from the returned object */ +- +- STRNCPY(uid->buffer, obj_desc->string.pointer, sizeof(uid->buffer)); +- } +- } +- +- +- /* On exit, we must delete the return object */ +- +- acpi_cm_remove_reference (obj_desc); +- +- return (status); +-} +- +-/**************************************************************************** +- * +- * FUNCTION: Acpi_cm_execute_STA +- * +- * PARAMETERS: Device_node - Node for the device +- * *Flags - Where the status flags are returned +- * +- * RETURN: Status +- * +- * DESCRIPTION: Executes _STA for selected device and stores results in +- * *Flags. +- * +- * NOTE: Internal function, no parameter validation +- * +- ***************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_execute_STA ( +- ACPI_NAMESPACE_NODE *device_node, +- u32 *flags) +-{ +- ACPI_OPERAND_OBJECT *obj_desc; +- ACPI_STATUS status; +- +- +- /* Execute the method */ +- +- status = acpi_ns_evaluate_relative (device_node, +- METHOD_NAME__STA, NULL, &obj_desc); +- if (AE_NOT_FOUND == status) { +- *flags = 0x0F; +- status = AE_OK; +- } +- +- +- else /* success */ { +- /* Did we get a return object? */ +- +- if (!obj_desc) { +- return (AE_TYPE); +- } +- +- /* Is the return object of the correct type? */ +- +- if (obj_desc->common.type != ACPI_TYPE_INTEGER) { +- status = AE_TYPE; +- } +- +- else { +- /* Extract the status flags */ +- +- *flags = (u32) obj_desc->integer.value; +- } +- +- /* On exit, we must delete the return object */ +- +- acpi_cm_remove_reference (obj_desc); +- } +- +- return (status); +-} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/common/cmglobal.c linux/drivers/acpi/common/cmglobal.c +--- /usr/src/linux/drivers/acpi/common/cmglobal.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/common/cmglobal.c Wed Dec 31 16:00:00 1969 +@@ -1,472 +0,0 @@ +-/****************************************************************************** +- * +- * Module Name: cmglobal - Global variables for the ACPI subsystem +- * $Revision: 116 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * 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 +- */ +- +-#define DEFINE_ACPI_GLOBALS +- +-#include "acpi.h" +-#include "acevents.h" +-#include "acnamesp.h" +-#include "acinterp.h" +-#include "amlcode.h" +- +- +-#define _COMPONENT MISCELLANEOUS +- MODULE_NAME ("cmglobal") +- +- +-/****************************************************************************** +- * +- * Static global variable initialization. +- * +- ******************************************************************************/ +- +-/* +- * We want the debug switches statically initialized so they +- * are already set when the debugger is entered. +- */ +- +-/* Debug switch - level and trace mask */ +- +-u32 acpi_dbg_level = NORMAL_DEFAULT; +- +-/* Debug switch - layer (component) mask */ +- +-u32 acpi_dbg_layer = COMPONENT_DEFAULT; +-u32 acpi_gbl_nesting_level = 0; +- +- +-/* Debugger globals */ +- +-u8 acpi_gbl_db_terminate_threads = FALSE; +-u8 acpi_gbl_method_executing = FALSE; +- +-/* System flags */ +- +-u32 acpi_gbl_system_flags = 0; +-u32 acpi_gbl_startup_flags = 0; +- +-/* System starts unitialized! */ +-u8 acpi_gbl_shutdown = TRUE; +- +- +-u8 acpi_gbl_decode_to8bit [8] = {1,2,4,8,16,32,64,128}; +- +- +-/****************************************************************************** +- * +- * Namespace globals +- * +- ******************************************************************************/ +- +- +-/* +- * Names built-in to the interpreter +- * +- * Initial values are currently supported only for types String and Number. +- * To avoid type punning, both are specified as strings in this table. +- */ +- +-PREDEFINED_NAMES acpi_gbl_pre_defined_names[] = +-{ +- {"_GPE", INTERNAL_TYPE_DEF_ANY}, +- {"_PR_", INTERNAL_TYPE_DEF_ANY}, +- {"_SB_", INTERNAL_TYPE_DEF_ANY}, +- {"_SI_", INTERNAL_TYPE_DEF_ANY}, +- {"_TZ_", INTERNAL_TYPE_DEF_ANY}, +- {"_REV", ACPI_TYPE_INTEGER, "2"}, +- {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME}, +- {"_GL_", ACPI_TYPE_MUTEX, "0"}, +- +- /* Table terminator */ +- +- {NULL, ACPI_TYPE_ANY} +-}; +- +- +-/* +- * Properties of the ACPI Object Types, both internal and external. +- * +- * Elements of Acpi_ns_properties are bit significant +- * and the table is indexed by values of ACPI_OBJECT_TYPE +- */ +- +-u8 acpi_gbl_ns_properties[] = +-{ +- NSP_NORMAL, /* 00 Any */ +- NSP_NORMAL, /* 01 Number */ +- NSP_NORMAL, /* 02 String */ +- NSP_NORMAL, /* 03 Buffer */ +- NSP_LOCAL, /* 04 Package */ +- NSP_NORMAL, /* 05 Field_unit */ +- NSP_NEWSCOPE | NSP_LOCAL, /* 06 Device */ +- NSP_LOCAL, /* 07 Acpi_event */ +- NSP_NEWSCOPE | NSP_LOCAL, /* 08 Method */ +- NSP_LOCAL, /* 09 Mutex */ +- NSP_LOCAL, /* 10 Region */ +- NSP_NEWSCOPE | NSP_LOCAL, /* 11 Power */ +- NSP_NEWSCOPE | NSP_LOCAL, /* 12 Processor */ +- NSP_NEWSCOPE | NSP_LOCAL, /* 13 Thermal */ +- NSP_NORMAL, /* 14 Buffer_field */ +- NSP_NORMAL, /* 15 Ddb_handle */ +- NSP_NORMAL, /* 16 Debug Object */ +- NSP_NORMAL, /* 17 Def_field */ +- NSP_NORMAL, /* 18 Bank_field */ +- NSP_NORMAL, /* 19 Index_field */ +- NSP_NORMAL, /* 20 Reference */ +- NSP_NORMAL, /* 21 Alias */ +- NSP_NORMAL, /* 22 Notify */ +- NSP_NORMAL, /* 23 Address Handler */ +- NSP_NEWSCOPE | NSP_LOCAL, /* 24 Resource */ +- NSP_NORMAL, /* 25 Def_field_defn */ +- NSP_NORMAL, /* 26 Bank_field_defn */ +- NSP_NORMAL, /* 27 Index_field_defn */ +- NSP_NORMAL, /* 28 If */ +- NSP_NORMAL, /* 29 Else */ +- NSP_NORMAL, /* 30 While */ +- NSP_NEWSCOPE, /* 31 Scope */ +- NSP_LOCAL, /* 32 Def_any */ +- NSP_NORMAL, /* 33 Extra */ +- NSP_NORMAL /* 34 Invalid */ +-}; +- +- +-/* Hex to ASCII conversion table */ +- +-NATIVE_CHAR acpi_gbl_hex_to_ascii[] = +- {'0','1','2','3','4','5','6','7', +- '8','9','A','B','C','D','E','F'}; +- +- +-/****************************************************************************** +- * +- * Table globals +- * +- * NOTE: This table includes ONLY the ACPI tables that the subsystem consumes. +- * it is NOT an exhaustive list of all possible ACPI tables. All ACPI tables +- * that are not used by the subsystem are simply ignored. +- * +- ******************************************************************************/ +- +- +-ACPI_TABLE_DESC acpi_gbl_acpi_tables[NUM_ACPI_TABLES]; +- +- +-ACPI_TABLE_SUPPORT acpi_gbl_acpi_table_data[NUM_ACPI_TABLES] = +-{ +- /*********** Name, Signature, Signature size, How many allowed?, Supported? Global typed pointer */ +- +- /* RSDP 0 */ {RSDP_NAME, RSDP_SIG, sizeof (RSDP_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, NULL}, +- /* DSDT 1 */ {DSDT_SIG, DSDT_SIG, sizeof (DSDT_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, (void **) &acpi_gbl_DSDT}, +- /* FADT 2 */ {FADT_SIG, FADT_SIG, sizeof (FADT_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, (void **) &acpi_gbl_FADT}, +- /* FACS 3 */ {FACS_SIG, FACS_SIG, sizeof (FACS_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, (void **) &acpi_gbl_FACS}, +- /* PSDT 4 */ {PSDT_SIG, PSDT_SIG, sizeof (PSDT_SIG)-1, ACPI_TABLE_MULTIPLE, AE_OK, NULL}, +- /* SSDT 5 */ {SSDT_SIG, SSDT_SIG, sizeof (SSDT_SIG)-1, ACPI_TABLE_MULTIPLE, AE_OK, NULL}, +- /* XSDT 6 */ {XSDT_SIG, XSDT_SIG, sizeof (RSDT_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, NULL}, +-}; +- +- +-/***************************************************************************** +- * +- * FUNCTION: Acpi_cm_valid_object_type +- * +- * PARAMETERS: None. +- * +- * RETURN: TRUE if valid object type +- * +- * DESCRIPTION: Validate an object type +- * +- ****************************************************************************/ +- +-u8 +-acpi_cm_valid_object_type ( +- u32 type) +-{ +- +- if (type > ACPI_TYPE_MAX) { +- if ((type < INTERNAL_TYPE_BEGIN) || +- (type > INTERNAL_TYPE_MAX)) +- { +- return (FALSE); +- } +- } +- +- return (TRUE); +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Acpi_cm_format_exception +- * +- * PARAMETERS: Status - Acpi status to be formatted +- * +- * RETURN: Formatted status string +- * +- * DESCRIPTION: Convert an ACPI exception to a string +- * +- ****************************************************************************/ +- +-NATIVE_CHAR * +-acpi_cm_format_exception ( +- ACPI_STATUS status) +-{ +- NATIVE_CHAR *exception = "UNKNOWN_STATUS"; +- ACPI_STATUS sub_status; +- +- +- sub_status = (status & ~AE_CODE_MASK); +- +- +- switch (status & AE_CODE_MASK) +- { +- case AE_CODE_ENVIRONMENTAL: +- +- if (sub_status <= AE_CODE_ENV_MAX) { +- exception = acpi_gbl_exception_names_env [sub_status]; +- } +- break; +- +- case AE_CODE_PROGRAMMER: +- +- if (sub_status <= AE_CODE_PGM_MAX) { +- exception = acpi_gbl_exception_names_pgm [sub_status -1]; +- } +- break; +- +- case AE_CODE_ACPI_TABLES: +- +- if (sub_status <= AE_CODE_TBL_MAX) { +- exception = acpi_gbl_exception_names_tbl [sub_status -1]; +- } +- break; +- +- case AE_CODE_AML: +- +- if (sub_status <= AE_CODE_AML_MAX) { +- exception = acpi_gbl_exception_names_aml [sub_status -1]; +- } +- break; +- +- case AE_CODE_CONTROL: +- +- if (sub_status <= AE_CODE_CTRL_MAX) { +- exception = acpi_gbl_exception_names_ctrl [sub_status -1]; +- } +- break; +- +- default: +- break; +- } +- +- +- return (exception); +-} +- +- +-/**************************************************************************** +- * +- * FUNCTION: Acpi_cm_allocate_owner_id +- * +- * PARAMETERS: Id_type - Type of ID (method or table) +- * +- * DESCRIPTION: Allocate a table or method owner id +- * +- ***************************************************************************/ +- +-ACPI_OWNER_ID +-acpi_cm_allocate_owner_id ( +- u32 id_type) +-{ +- ACPI_OWNER_ID owner_id = 0xFFFF; +- +- +- acpi_cm_acquire_mutex (ACPI_MTX_CACHES); +- +- switch (id_type) +- { +- case OWNER_TYPE_TABLE: +- +- owner_id = acpi_gbl_next_table_owner_id; +- acpi_gbl_next_table_owner_id++; +- +- if (acpi_gbl_next_table_owner_id == FIRST_METHOD_ID) { +- acpi_gbl_next_table_owner_id = FIRST_TABLE_ID; +- } +- break; +- +- +- case OWNER_TYPE_METHOD: +- +- owner_id = acpi_gbl_next_method_owner_id; +- acpi_gbl_next_method_owner_id++; +- +- if (acpi_gbl_next_method_owner_id == FIRST_TABLE_ID) { +- acpi_gbl_next_method_owner_id = FIRST_METHOD_ID; +- } +- break; +- } +- +- +- acpi_cm_release_mutex (ACPI_MTX_CACHES); +- +- return (owner_id); +-} +- +- +-/**************************************************************************** +- * +- * FUNCTION: Acpi_cm_init_globals +- * +- * PARAMETERS: none +- * +- * DESCRIPTION: Init library globals. All globals that require specific +- * initialization should be initialized here! +- * +- ***************************************************************************/ +- +-void +-acpi_cm_init_globals ( +- void) +-{ +- u32 i; +- +- +- /* ACPI table structure */ +- +- for (i = 0; i < NUM_ACPI_TABLES; i++) { +- acpi_gbl_acpi_tables[i].prev = &acpi_gbl_acpi_tables[i]; +- acpi_gbl_acpi_tables[i].next = &acpi_gbl_acpi_tables[i]; +- acpi_gbl_acpi_tables[i].pointer = NULL; +- acpi_gbl_acpi_tables[i].length = 0; +- acpi_gbl_acpi_tables[i].allocation = ACPI_MEM_NOT_ALLOCATED; +- acpi_gbl_acpi_tables[i].count = 0; +- } +- +- +- /* Address Space handler array */ +- +- for (i = 0; i < ACPI_NUM_ADDRESS_SPACES; i++) { +- acpi_gbl_address_spaces[i].handler = NULL; +- acpi_gbl_address_spaces[i].context = NULL; +- } +- +- /* Mutex locked flags */ +- +- for (i = 0; i < NUM_MTX; i++) { +- acpi_gbl_acpi_mutex_info[i].mutex = NULL; +- acpi_gbl_acpi_mutex_info[i].locked = FALSE; +- acpi_gbl_acpi_mutex_info[i].use_count = 0; +- } +- +- /* Global notify handlers */ +- +- acpi_gbl_sys_notify.handler = NULL; +- acpi_gbl_drv_notify.handler = NULL; +- +- /* Global "typed" ACPI table pointers */ +- +- acpi_gbl_RSDP = NULL; +- acpi_gbl_XSDT = NULL; +- acpi_gbl_FACS = NULL; +- acpi_gbl_FADT = NULL; +- acpi_gbl_DSDT = NULL; +- +- +- /* Global Lock support */ +- +- acpi_gbl_global_lock_acquired = FALSE; +- acpi_gbl_global_lock_thread_count = 0; +- +- /* Miscellaneous variables */ +- +- acpi_gbl_system_flags = 0; +- acpi_gbl_startup_flags = 0; +- acpi_gbl_global_lock_set = FALSE; +- acpi_gbl_rsdp_original_location = 0; +- acpi_gbl_cm_single_step = FALSE; +- acpi_gbl_db_terminate_threads = FALSE; +- acpi_gbl_shutdown = FALSE; +- acpi_gbl_ns_lookup_count = 0; +- acpi_gbl_ps_find_count = 0; +- acpi_gbl_acpi_hardware_present = TRUE; +- acpi_gbl_next_table_owner_id = FIRST_TABLE_ID; +- acpi_gbl_next_method_owner_id = FIRST_METHOD_ID; +- acpi_gbl_debugger_configuration = DEBUGGER_THREADING; +- +- /* Cache of small "state" objects */ +- +- acpi_gbl_generic_state_cache = NULL; +- acpi_gbl_generic_state_cache_depth = 0; +- acpi_gbl_state_cache_requests = 0; +- acpi_gbl_state_cache_hits = 0; +- +- acpi_gbl_parse_cache = NULL; +- acpi_gbl_parse_cache_depth = 0; +- acpi_gbl_parse_cache_requests = 0; +- acpi_gbl_parse_cache_hits = 0; +- +- acpi_gbl_ext_parse_cache = NULL; +- acpi_gbl_ext_parse_cache_depth = 0; +- acpi_gbl_ext_parse_cache_requests = 0; +- acpi_gbl_ext_parse_cache_hits = 0; +- +- acpi_gbl_object_cache = NULL; +- acpi_gbl_object_cache_depth = 0; +- acpi_gbl_object_cache_requests = 0; +- acpi_gbl_object_cache_hits = 0; +- +- acpi_gbl_walk_state_cache = NULL; +- acpi_gbl_walk_state_cache_depth = 0; +- acpi_gbl_walk_state_cache_requests = 0; +- acpi_gbl_walk_state_cache_hits = 0; +- +- /* Hardware oriented */ +- +- acpi_gbl_gpe0enable_register_save = NULL; +- acpi_gbl_gpe1_enable_register_save = NULL; +- acpi_gbl_original_mode = SYS_MODE_UNKNOWN; /* original ACPI/legacy mode */ +- acpi_gbl_gpe_registers = NULL; +- acpi_gbl_gpe_info = NULL; +- +- /* Namespace */ +- +- acpi_gbl_root_node = NULL; +- +- acpi_gbl_root_node_struct.name = ACPI_ROOT_NAME; +- acpi_gbl_root_node_struct.data_type = ACPI_DESC_TYPE_NAMED; +- acpi_gbl_root_node_struct.type = ACPI_TYPE_ANY; +- acpi_gbl_root_node_struct.child = NULL; +- acpi_gbl_root_node_struct.peer = NULL; +- acpi_gbl_root_node_struct.object = NULL; +- acpi_gbl_root_node_struct.flags = ANOBJ_END_OF_PEER_LIST; +- +- /* Memory allocation metrics - compiled out in non-debug mode. */ +- +- INITIALIZE_ALLOCATION_METRICS(); +- +- return; +-} +- +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/common/cminit.c linux/drivers/acpi/common/cminit.c +--- /usr/src/linux/drivers/acpi/common/cminit.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/common/cminit.c Wed Dec 31 16:00:00 1969 +@@ -1,250 +0,0 @@ +-/****************************************************************************** +- * +- * Module Name: cminit - Common ACPI subsystem initialization +- * $Revision: 93 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "achware.h" +-#include "acnamesp.h" +-#include "acevents.h" +-#include "acparser.h" +-#include "acdispat.h" +- +-#define _COMPONENT MISCELLANEOUS +- MODULE_NAME ("cminit") +- +- +-#define ACPI_OFFSET(d,o) ((u32) &(((d *)0)->o)) +-#define ACPI_FADT_OFFSET(o) ACPI_OFFSET (FADT_DESCRIPTOR, o) +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_fadt_register_error +- * +- * PARAMETERS: *Register_name - Pointer to string identifying register +- * Value - Actual register contents value +- * Acpi_test_spec_section - TDS section containing assertion +- * Acpi_assertion - Assertion number being tested +- * +- * RETURN: AE_BAD_VALUE +- * +- * DESCRIPTION: Display failure message and link failure to TDS assertion +- * +- ******************************************************************************/ +- +-static ACPI_STATUS +-acpi_cm_fadt_register_error ( +- NATIVE_CHAR *register_name, +- u32 value, +- u32 offset) +-{ +- +- REPORT_ERROR ( +- ("Invalid FADT value %s=%lX at offset %lX FADT=%p\n", +- register_name, value, offset, acpi_gbl_FADT)); +- +- +- return (AE_BAD_VALUE); +-} +- +- +-/****************************************************************************** +- * +- * FUNCTION: Acpi_cm_validate_fadt +- * +- * PARAMETERS: None +- * +- * RETURN: Status +- * +- * DESCRIPTION: Validate various ACPI registers in the FADT +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_validate_fadt ( +- void) +-{ +- ACPI_STATUS status = AE_OK; +- +- +- /* +- * Verify Fixed ACPI Description Table fields, +- * but don't abort on any problems, just display error +- */ +- +- if (acpi_gbl_FADT->pm1_evt_len < 4) { +- status = acpi_cm_fadt_register_error ("PM1_EVT_LEN", +- (u32) acpi_gbl_FADT->pm1_evt_len, +- ACPI_FADT_OFFSET (pm1_evt_len)); +- } +- +- if (!acpi_gbl_FADT->pm1_cnt_len) { +- status = acpi_cm_fadt_register_error ("PM1_CNT_LEN", 0, +- ACPI_FADT_OFFSET (pm1_cnt_len)); +- } +- +- if (!ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm1a_evt_blk.address)) { +- status = acpi_cm_fadt_register_error ("X_PM1a_EVT_BLK", 0, +- ACPI_FADT_OFFSET (Xpm1a_evt_blk.address)); +- } +- +- if (!ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm1a_cnt_blk.address)) { +- status = acpi_cm_fadt_register_error ("X_PM1a_CNT_BLK", 0, +- ACPI_FADT_OFFSET (Xpm1a_cnt_blk.address)); +- } +- +- if (!ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm_tmr_blk.address)) { +- status = acpi_cm_fadt_register_error ("X_PM_TMR_BLK", 0, +- ACPI_FADT_OFFSET (Xpm_tmr_blk.address)); +- } +- +- if ((ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm2_cnt_blk.address) && +- !acpi_gbl_FADT->pm2_cnt_len)) +- { +- status = acpi_cm_fadt_register_error ("PM2_CNT_LEN", +- (u32) acpi_gbl_FADT->pm2_cnt_len, +- ACPI_FADT_OFFSET (pm2_cnt_len)); +- } +- +- if (acpi_gbl_FADT->pm_tm_len < 4) { +- status = acpi_cm_fadt_register_error ("PM_TM_LEN", +- (u32) acpi_gbl_FADT->pm_tm_len, +- ACPI_FADT_OFFSET (pm_tm_len)); +- } +- +- /* length of GPE blocks must be a multiple of 2 */ +- +- +- if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xgpe0blk.address) && +- (acpi_gbl_FADT->gpe0blk_len & 1)) +- { +- status = acpi_cm_fadt_register_error ("(x)GPE0_BLK_LEN", +- (u32) acpi_gbl_FADT->gpe0blk_len, +- ACPI_FADT_OFFSET (gpe0blk_len)); +- } +- +- if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xgpe1_blk.address) && +- (acpi_gbl_FADT->gpe1_blk_len & 1)) +- { +- status = acpi_cm_fadt_register_error ("(x)GPE1_BLK_LEN", +- (u32) acpi_gbl_FADT->gpe1_blk_len, +- ACPI_FADT_OFFSET (gpe1_blk_len)); +- } +- +- return (status); +-} +- +- +-/****************************************************************************** +- * +- * FUNCTION: Acpi_cm_terminate +- * +- * PARAMETERS: none +- * +- * RETURN: none +- * +- * DESCRIPTION: free memory allocated for table storage. +- * +- ******************************************************************************/ +- +-void +-acpi_cm_terminate (void) +-{ +- +- +- /* Free global tables, etc. */ +- +- if (acpi_gbl_gpe0enable_register_save) { +- acpi_cm_free (acpi_gbl_gpe0enable_register_save); +- } +- +- if (acpi_gbl_gpe1_enable_register_save) { +- acpi_cm_free (acpi_gbl_gpe1_enable_register_save); +- } +- +- +- return; +-} +- +- +-/****************************************************************************** +- * +- * FUNCTION: Acpi_cm_subsystem_shutdown +- * +- * PARAMETERS: none +- * +- * RETURN: none +- * +- * DESCRIPTION: Shutdown the various subsystems. Don't delete the mutex +- * objects here -- because the AML debugger may be still running. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_subsystem_shutdown (void) +-{ +- +- /* Just exit if subsystem is already shutdown */ +- +- if (acpi_gbl_shutdown) { +- return (AE_OK); +- } +- +- /* Subsystem appears active, go ahead and shut it down */ +- +- acpi_gbl_shutdown = TRUE; +- +- /* Close the Namespace */ +- +- acpi_ns_terminate (); +- +- /* Close the Acpi_event Handling */ +- +- acpi_ev_terminate (); +- +- /* Close the globals */ +- +- acpi_cm_terminate (); +- +- /* Flush the local cache(s) */ +- +- acpi_cm_delete_generic_state_cache (); +- acpi_cm_delete_object_cache (); +- acpi_ds_delete_walk_state_cache (); +- +- /* Close the Parser */ +- +- /* TBD: [Restructure] Acpi_ps_terminate () */ +- +- acpi_ps_delete_parse_cache (); +- +- /* Debug only - display leftover memory allocation, if any */ +-#ifdef ENABLE_DEBUGGER +- acpi_cm_dump_current_allocations (ACPI_UINT32_MAX, NULL); +-#endif +- +- return (AE_OK); +-} +- +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/common/cmobject.c linux/drivers/acpi/common/cmobject.c +--- /usr/src/linux/drivers/acpi/common/cmobject.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/common/cmobject.c Wed Dec 31 16:00:00 1969 +@@ -1,618 +0,0 @@ +-/****************************************************************************** +- * +- * Module Name: cmobject - ACPI object create/delete/size/cache routines +- * $Revision: 36 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acinterp.h" +-#include "acnamesp.h" +-#include "actables.h" +-#include "amlcode.h" +- +- +-#define _COMPONENT MISCELLANEOUS +- MODULE_NAME ("cmobject") +- +- +-/******************************************************************************* +- * +- * FUNCTION: _Cm_create_internal_object +- * +- * PARAMETERS: Address - Address of the memory to deallocate +- * Component - Component type of caller +- * Module - Source file name of caller +- * Line - Line number of caller +- * Type - ACPI Type of the new object +- * +- * RETURN: Object - The new object. Null on failure +- * +- * DESCRIPTION: Create and initialize a new internal object. +- * +- * NOTE: We always allocate the worst-case object descriptor because +- * these objects are cached, and we want them to be +- * one-size-satisifies-any-request. This in itself may not be +- * the most memory efficient, but the efficiency of the object +- * cache should more than make up for this! +- * +- ******************************************************************************/ +- +-ACPI_OPERAND_OBJECT * +-_cm_create_internal_object ( +- NATIVE_CHAR *module_name, +- u32 line_number, +- u32 component_id, +- OBJECT_TYPE_INTERNAL type) +-{ +- ACPI_OPERAND_OBJECT *object; +- +- +- /* Allocate the raw object descriptor */ +- +- object = _cm_allocate_object_desc (module_name, line_number, component_id); +- if (!object) { +- /* Allocation failure */ +- +- return (NULL); +- } +- +- /* Save the object type in the object descriptor */ +- +- object->common.type = type; +- +- /* Init the reference count */ +- +- object->common.reference_count = 1; +- +- /* Any per-type initialization should go here */ +- +- +- return (object); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_valid_internal_object +- * +- * PARAMETERS: Operand - Object to be validated +- * +- * RETURN: Validate a pointer to be an ACPI_OPERAND_OBJECT +- * +- ******************************************************************************/ +- +-u8 +-acpi_cm_valid_internal_object ( +- void *object) +-{ +- +- /* Check for a null pointer */ +- +- if (!object) { +- return (FALSE); +- } +- +- /* Check for a pointer within one of the ACPI tables */ +- +- if (acpi_tb_system_table_pointer (object)) { +- return (FALSE); +- } +- +- /* Check the descriptor type field */ +- +- if (!VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_INTERNAL)) { +- /* Not an ACPI internal object, do some further checking */ +- +- +- +- +- return (FALSE); +- } +- +- +- /* The object appears to be a valid ACPI_OPERAND_OBJECT */ +- +- return (TRUE); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: _Cm_allocate_object_desc +- * +- * PARAMETERS: Module_name - Caller's module name (for error output) +- * Line_number - Caller's line number (for error output) +- * Component_id - Caller's component ID (for error output) +- * Message - Error message to use on failure +- * +- * RETURN: Pointer to newly allocated object descriptor. Null on error +- * +- * DESCRIPTION: Allocate a new object descriptor. Gracefully handle +- * error conditions. +- * +- ******************************************************************************/ +- +-void * +-_cm_allocate_object_desc ( +- NATIVE_CHAR *module_name, +- u32 line_number, +- u32 component_id) +-{ +- ACPI_OPERAND_OBJECT *object; +- +- +- acpi_cm_acquire_mutex (ACPI_MTX_CACHES); +- +- acpi_gbl_object_cache_requests++; +- +- /* Check the cache first */ +- +- if (acpi_gbl_object_cache) { +- /* There is an object available, use it */ +- +- object = acpi_gbl_object_cache; +- acpi_gbl_object_cache = object->cache.next; +- object->cache.next = NULL; +- +- acpi_gbl_object_cache_hits++; +- acpi_gbl_object_cache_depth--; +- +- acpi_cm_release_mutex (ACPI_MTX_CACHES); +- } +- +- else { +- /* The cache is empty, create a new object */ +- +- acpi_cm_release_mutex (ACPI_MTX_CACHES); +- +- /* Attempt to allocate new descriptor */ +- +- object = _cm_callocate (sizeof (ACPI_OPERAND_OBJECT), component_id, +- module_name, line_number); +- if (!object) { +- /* Allocation failed */ +- +- _REPORT_ERROR (module_name, line_number, component_id, +- ("Could not allocate an object descriptor\n")); +- +- return (NULL); +- } +- +- /* Memory allocation metrics - compiled out in non debug mode. */ +- +- INCREMENT_OBJECT_METRICS (sizeof (ACPI_OPERAND_OBJECT)); +- } +- +- /* Mark the descriptor type */ +- +- object->common.data_type = ACPI_DESC_TYPE_INTERNAL; +- +- return (object); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_delete_object_desc +- * +- * PARAMETERS: Object - Acpi internal object to be deleted +- * +- * RETURN: None. +- * +- * DESCRIPTION: Free an ACPI object descriptor or add it to the object cache +- * +- ******************************************************************************/ +- +-void +-acpi_cm_delete_object_desc ( +- ACPI_OPERAND_OBJECT *object) +-{ +- +- +- /* Make sure that the object isn't already in the cache */ +- +- if (object->common.data_type == (ACPI_DESC_TYPE_INTERNAL | ACPI_CACHED_OBJECT)) { +- return; +- } +- +- /* Object must be an ACPI_OPERAND_OBJECT */ +- +- if (object->common.data_type != ACPI_DESC_TYPE_INTERNAL) { +- return; +- } +- +- +- /* If cache is full, just free this object */ +- +- if (acpi_gbl_object_cache_depth >= MAX_OBJECT_CACHE_DEPTH) { +- /* +- * Memory allocation metrics. Call the macro here since we only +- * care about dynamically allocated objects. +- */ +- DECREMENT_OBJECT_METRICS (sizeof (ACPI_OPERAND_OBJECT)); +- +- acpi_cm_free (object); +- return; +- } +- +- acpi_cm_acquire_mutex (ACPI_MTX_CACHES); +- +- /* Clear the entire object. This is important! */ +- +- MEMSET (object, 0, sizeof (ACPI_OPERAND_OBJECT)); +- object->common.data_type = ACPI_DESC_TYPE_INTERNAL | ACPI_CACHED_OBJECT; +- +- /* Put the object at the head of the global cache list */ +- +- object->cache.next = acpi_gbl_object_cache; +- acpi_gbl_object_cache = object; +- acpi_gbl_object_cache_depth++; +- +- +- acpi_cm_release_mutex (ACPI_MTX_CACHES); +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_delete_object_cache +- * +- * PARAMETERS: None +- * +- * RETURN: Status +- * +- * DESCRIPTION: Purge the global state object cache. Used during subsystem +- * termination. +- * +- ******************************************************************************/ +- +-void +-acpi_cm_delete_object_cache ( +- void) +-{ +- ACPI_OPERAND_OBJECT *next; +- +- +- /* Traverse the global cache list */ +- +- while (acpi_gbl_object_cache) { +- /* Delete one cached state object */ +- +- next = acpi_gbl_object_cache->cache.next; +- acpi_gbl_object_cache->cache.next = NULL; +- +- /* +- * Memory allocation metrics. Call the macro here since we only +- * care about dynamically allocated objects. +- */ +- DECREMENT_OBJECT_METRICS (sizeof (ACPI_OPERAND_OBJECT)); +- +- acpi_cm_free (acpi_gbl_object_cache); +- acpi_gbl_object_cache = next; +- acpi_gbl_object_cache_depth--; +- } +- +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_init_static_object +- * +- * PARAMETERS: Obj_desc - Pointer to a "static" object - on stack +- * or in the data segment. +- * +- * RETURN: None. +- * +- * DESCRIPTION: Initialize a static object. Sets flags to disallow dynamic +- * deletion of the object. +- * +- ******************************************************************************/ +- +-void +-acpi_cm_init_static_object ( +- ACPI_OPERAND_OBJECT *obj_desc) +-{ +- +- +- if (!obj_desc) { +- return; +- } +- +- +- /* +- * Clear the entire descriptor +- */ +- MEMSET ((void *) obj_desc, 0, sizeof (ACPI_OPERAND_OBJECT)); +- +- +- /* +- * Initialize the header fields +- * 1) This is an ACPI_OPERAND_OBJECT descriptor +- * 2) The size is the full object (worst case) +- * 3) The flags field indicates static allocation +- * 4) Reference count starts at one (not really necessary since the +- * object can't be deleted, but keeps everything sane) +- */ +- +- obj_desc->common.data_type = ACPI_DESC_TYPE_INTERNAL; +- obj_desc->common.flags = AOPOBJ_STATIC_ALLOCATION; +- obj_desc->common.reference_count = 1; +- +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_get_simple_object_size +- * +- * PARAMETERS: *Internal_object - Pointer to the object we are examining +- * *Ret_length - Where the length is returned +- * +- * RETURN: Status +- * +- * DESCRIPTION: This function is called to determine the space required to +- * contain a simple object for return to an API user. +- * +- * The length includes the object structure plus any additional +- * needed space. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_get_simple_object_size ( +- ACPI_OPERAND_OBJECT *internal_object, +- u32 *obj_length) +-{ +- u32 length; +- ACPI_STATUS status = AE_OK; +- +- +- /* Handle a null object (Could be a uninitialized package element -- which is legal) */ +- +- if (!internal_object) { +- *obj_length = 0; +- return (AE_OK); +- } +- +- +- /* Start with the length of the Acpi object */ +- +- length = sizeof (ACPI_OBJECT); +- +- if (VALID_DESCRIPTOR_TYPE (internal_object, ACPI_DESC_TYPE_NAMED)) { +- /* Object is a named object (reference), just return the length */ +- +- *obj_length = (u32) ROUND_UP_TO_NATIVE_WORD (length); +- return (status); +- } +- +- +- /* +- * The final length depends on the object type +- * Strings and Buffers are packed right up against the parent object and +- * must be accessed bytewise or there may be alignment problems. +- * +- * TBD:[Investigate] do strings and buffers require alignment also? +- */ +- +- switch (internal_object->common.type) +- { +- +- case ACPI_TYPE_STRING: +- +- length += internal_object->string.length + 1; +- break; +- +- +- case ACPI_TYPE_BUFFER: +- +- length += internal_object->buffer.length; +- break; +- +- +- case ACPI_TYPE_INTEGER: +- case ACPI_TYPE_PROCESSOR: +- case ACPI_TYPE_POWER: +- +- /* +- * No extra data for these types +- */ +- break; +- +- +- case INTERNAL_TYPE_REFERENCE: +- +- /* +- * The only type that should be here is opcode AML_NAMEPATH_OP -- since +- * this means an object reference +- */ +- if (internal_object->reference.op_code != AML_NAMEPATH_OP) { +- status = AE_TYPE; +- } +- break; +- +- +- default: +- +- status = AE_TYPE; +- break; +- } +- +- +- /* +- * Account for the space required by the object rounded up to the next +- * multiple of the machine word size. This keeps each object aligned +- * on a machine word boundary. (preventing alignment faults on some +- * machines.) +- */ +- *obj_length = (u32) ROUND_UP_TO_NATIVE_WORD (length); +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_copy_package_to_internal +- * +- * PARAMETERS: ACPI_PKG_CALLBACK +- * +- * RETURN: Status - the status of the call +- * +- * DESCRIPTION: +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_get_element_length ( +- u8 object_type, +- ACPI_OPERAND_OBJECT *source_object, +- ACPI_GENERIC_STATE *state, +- void *context) +-{ +- ACPI_STATUS status = AE_OK; +- ACPI_PKG_INFO *info = (ACPI_PKG_INFO *) context; +- u32 object_space; +- +- +- switch (object_type) +- { +- case 0: +- +- /* +- * Simple object - just get the size (Null object/entry is handled +- * here also) and sum it into the running package length +- */ +- status = acpi_cm_get_simple_object_size (source_object, &object_space); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- info->length += object_space; +- break; +- +- +- case 1: +- /* Package - nothing much to do here, let the walk handle it */ +- +- info->num_packages++; +- state->pkg.this_target_obj = NULL; +- break; +- +- default: +- return (AE_BAD_PARAMETER); +- } +- +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_get_package_object_size +- * +- * PARAMETERS: *Internal_object - Pointer to the object we are examining +- * *Ret_length - Where the length is returned +- * +- * RETURN: Status +- * +- * DESCRIPTION: This function is called to determine the space required to +- * contain a package object for return to an API user. +- * +- * This is moderately complex since a package contains other +- * objects including packages. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_get_package_object_size ( +- ACPI_OPERAND_OBJECT *internal_object, +- u32 *obj_length) +-{ +- ACPI_STATUS status; +- ACPI_PKG_INFO info; +- +- +- info.length = 0; +- info.object_space = 0; +- info.num_packages = 1; +- +- status = acpi_cm_walk_package_tree (internal_object, NULL, +- acpi_cm_get_element_length, &info); +- +- /* +- * We have handled all of the objects in all levels of the package. +- * just add the length of the package objects themselves. +- * Round up to the next machine word. +- */ +- info.length += ROUND_UP_TO_NATIVE_WORD (sizeof (ACPI_OBJECT)) * +- info.num_packages; +- +- /* Return the total package length */ +- +- *obj_length = info.length; +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_get_object_size +- * +- * PARAMETERS: *Internal_object - Pointer to the object we are examining +- * *Ret_length - Where the length will be returned +- * +- * RETURN: Status +- * +- * DESCRIPTION: This function is called to determine the space required to +- * contain an object for return to an API user. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_get_object_size( +- ACPI_OPERAND_OBJECT *internal_object, +- u32 *obj_length) +-{ +- ACPI_STATUS status; +- +- +- if ((VALID_DESCRIPTOR_TYPE (internal_object, ACPI_DESC_TYPE_INTERNAL)) && +- (IS_THIS_OBJECT_TYPE (internal_object, ACPI_TYPE_PACKAGE))) +- { +- status = acpi_cm_get_package_object_size (internal_object, obj_length); +- } +- +- else { +- status = acpi_cm_get_simple_object_size (internal_object, obj_length); +- } +- +- return (status); +-} +- +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/common/cmutils.c linux/drivers/acpi/common/cmutils.c +--- /usr/src/linux/drivers/acpi/common/cmutils.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/common/cmutils.c Wed Dec 31 16:00:00 1969 +@@ -1,952 +0,0 @@ +-/******************************************************************************* +- * +- * Module Name: cmutils - common utility procedures +- * $Revision: 27 $ +- * +- ******************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acevents.h" +-#include "achware.h" +-#include "acnamesp.h" +-#include "acinterp.h" +-#include "amlcode.h" +-#include "acdebug.h" +- +- +-#define _COMPONENT MISCELLANEOUS +- MODULE_NAME ("cmutils") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_valid_acpi_name +- * +- * PARAMETERS: Character - The character to be examined +- * +- * RETURN: 1 if Character may appear in a name, else 0 +- * +- * DESCRIPTION: Check for a valid ACPI name. Each character must be one of: +- * 1) Upper case alpha +- * 2) numeric +- * 3) underscore +- * +- ******************************************************************************/ +- +-u8 +-acpi_cm_valid_acpi_name ( +- u32 name) +-{ +- NATIVE_CHAR *name_ptr = (NATIVE_CHAR *) &name; +- u32 i; +- +- +- for (i = 0; i < ACPI_NAME_SIZE; i++) { +- if (!((name_ptr[i] == '_') || +- (name_ptr[i] >= 'A' && name_ptr[i] <= 'Z') || +- (name_ptr[i] >= '0' && name_ptr[i] <= '9'))) +- { +- return (FALSE); +- } +- } +- +- +- return (TRUE); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_valid_acpi_character +- * +- * PARAMETERS: Character - The character to be examined +- * +- * RETURN: 1 if Character may appear in a name, else 0 +- * +- * DESCRIPTION: Check for a printable character +- * +- ******************************************************************************/ +- +-u8 +-acpi_cm_valid_acpi_character ( +- NATIVE_CHAR character) +-{ +- +- return ((u8) ((character == '_') || +- (character >= 'A' && character <= 'Z') || +- (character >= '0' && character <= '9'))); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_mutex_initialize +- * +- * PARAMETERS: None. +- * +- * RETURN: Status +- * +- * DESCRIPTION: Create the system mutex objects. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_mutex_initialize ( +- void) +-{ +- u32 i; +- ACPI_STATUS status; +- +- +- /* +- * Create each of the predefined mutex objects +- */ +- for (i = 0; i < NUM_MTX; i++) { +- status = acpi_cm_create_mutex (i); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- } +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_mutex_terminate +- * +- * PARAMETERS: None. +- * +- * RETURN: None. +- * +- * DESCRIPTION: Delete all of the system mutex objects. +- * +- ******************************************************************************/ +- +-void +-acpi_cm_mutex_terminate ( +- void) +-{ +- u32 i; +- +- +- /* +- * Delete each predefined mutex object +- */ +- for (i = 0; i < NUM_MTX; i++) { +- acpi_cm_delete_mutex (i); +- } +- +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_create_mutex +- * +- * PARAMETERS: Mutex_iD - ID of the mutex to be created +- * +- * RETURN: Status +- * +- * DESCRIPTION: Create a mutex object. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_create_mutex ( +- ACPI_MUTEX_HANDLE mutex_id) +-{ +- ACPI_STATUS status = AE_OK; +- +- +- if (mutex_id > MAX_MTX) { +- return (AE_BAD_PARAMETER); +- } +- +- +- if (!acpi_gbl_acpi_mutex_info[mutex_id].mutex) { +- status = acpi_os_create_semaphore (1, 1, +- &acpi_gbl_acpi_mutex_info[mutex_id].mutex); +- acpi_gbl_acpi_mutex_info[mutex_id].locked = FALSE; +- acpi_gbl_acpi_mutex_info[mutex_id].use_count = 0; +- } +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_delete_mutex +- * +- * PARAMETERS: Mutex_iD - ID of the mutex to be deleted +- * +- * RETURN: Status +- * +- * DESCRIPTION: Delete a mutex object. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_delete_mutex ( +- ACPI_MUTEX_HANDLE mutex_id) +-{ +- ACPI_STATUS status; +- +- +- if (mutex_id > MAX_MTX) { +- return (AE_BAD_PARAMETER); +- } +- +- +- status = acpi_os_delete_semaphore (acpi_gbl_acpi_mutex_info[mutex_id].mutex); +- +- acpi_gbl_acpi_mutex_info[mutex_id].mutex = NULL; +- acpi_gbl_acpi_mutex_info[mutex_id].locked = FALSE; +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_acquire_mutex +- * +- * PARAMETERS: Mutex_iD - ID of the mutex to be acquired +- * +- * RETURN: Status +- * +- * DESCRIPTION: Acquire a mutex object. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_acquire_mutex ( +- ACPI_MUTEX_HANDLE mutex_id) +-{ +- ACPI_STATUS status; +- +- +- if (mutex_id > MAX_MTX) { +- return (AE_BAD_PARAMETER); +- } +- +- +- status = acpi_os_wait_semaphore (acpi_gbl_acpi_mutex_info[mutex_id].mutex, +- 1, WAIT_FOREVER); +- +- if (ACPI_SUCCESS (status)) { +- acpi_gbl_acpi_mutex_info[mutex_id].locked = TRUE; +- acpi_gbl_acpi_mutex_info[mutex_id].use_count++; +- } +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_release_mutex +- * +- * PARAMETERS: Mutex_iD - ID of the mutex to be released +- * +- * RETURN: Status +- * +- * DESCRIPTION: Release a mutex object. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_release_mutex ( +- ACPI_MUTEX_HANDLE mutex_id) +-{ +- ACPI_STATUS status; +- +- +- if (mutex_id > MAX_MTX) { +- return (AE_BAD_PARAMETER); +- } +- +- +- acpi_gbl_acpi_mutex_info[mutex_id].locked = FALSE; /* Mark before unlocking */ +- +- status = acpi_os_signal_semaphore (acpi_gbl_acpi_mutex_info[mutex_id].mutex, 1); +- +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_create_update_state_and_push +- * +- * PARAMETERS: *Object - Object to be added to the new state +- * Action - Increment/Decrement +- * State_list - List the state will be added to +- * +- * RETURN: None +- * +- * DESCRIPTION: Create a new state and push it +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_create_update_state_and_push ( +- ACPI_OPERAND_OBJECT *object, +- u16 action, +- ACPI_GENERIC_STATE **state_list) +-{ +- ACPI_GENERIC_STATE *state; +- +- +- /* Ignore null objects; these are expected */ +- +- if (!object) { +- return (AE_OK); +- } +- +- state = acpi_cm_create_update_state (object, action); +- if (!state) { +- return (AE_NO_MEMORY); +- } +- +- +- acpi_cm_push_generic_state (state_list, state); +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_create_pkg_state_and_push +- * +- * PARAMETERS: *Object - Object to be added to the new state +- * Action - Increment/Decrement +- * State_list - List the state will be added to +- * +- * RETURN: None +- * +- * DESCRIPTION: Create a new state and push it +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_create_pkg_state_and_push ( +- void *internal_object, +- void *external_object, +- u16 index, +- ACPI_GENERIC_STATE **state_list) +-{ +- ACPI_GENERIC_STATE *state; +- +- +- state = acpi_cm_create_pkg_state (internal_object, external_object, index); +- if (!state) { +- return (AE_NO_MEMORY); +- } +- +- +- acpi_cm_push_generic_state (state_list, state); +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_push_generic_state +- * +- * PARAMETERS: List_head - Head of the state stack +- * State - State object to push +- * +- * RETURN: Status +- * +- * DESCRIPTION: Push a state object onto a state stack +- * +- ******************************************************************************/ +- +-void +-acpi_cm_push_generic_state ( +- ACPI_GENERIC_STATE **list_head, +- ACPI_GENERIC_STATE *state) +-{ +- /* Push the state object onto the front of the list (stack) */ +- +- state->common.next = *list_head; +- *list_head = state; +- +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_pop_generic_state +- * +- * PARAMETERS: List_head - Head of the state stack +- * +- * RETURN: Status +- * +- * DESCRIPTION: Pop a state object from a state stack +- * +- ******************************************************************************/ +- +-ACPI_GENERIC_STATE * +-acpi_cm_pop_generic_state ( +- ACPI_GENERIC_STATE **list_head) +-{ +- ACPI_GENERIC_STATE *state; +- +- +- /* Remove the state object at the head of the list (stack) */ +- +- state = *list_head; +- if (state) { +- /* Update the list head */ +- +- *list_head = state->common.next; +- } +- +- return (state); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_create_generic_state +- * +- * PARAMETERS: None +- * +- * RETURN: Status +- * +- * DESCRIPTION: Create a generic state object. Attempt to obtain one from +- * the global state cache; If none available, create a new one. +- * +- ******************************************************************************/ +- +-ACPI_GENERIC_STATE * +-acpi_cm_create_generic_state (void) +-{ +- ACPI_GENERIC_STATE *state; +- +- +- acpi_cm_acquire_mutex (ACPI_MTX_CACHES); +- +- acpi_gbl_state_cache_requests++; +- +- /* Check the cache first */ +- +- if (acpi_gbl_generic_state_cache) { +- /* There is an object available, use it */ +- +- state = acpi_gbl_generic_state_cache; +- acpi_gbl_generic_state_cache = state->common.next; +- state->common.next = NULL; +- +- acpi_gbl_state_cache_hits++; +- acpi_gbl_generic_state_cache_depth--; +- +- acpi_cm_release_mutex (ACPI_MTX_CACHES); +- +- } +- +- else { +- /* The cache is empty, create a new object */ +- +- acpi_cm_release_mutex (ACPI_MTX_CACHES); +- +- state = acpi_cm_callocate (sizeof (ACPI_GENERIC_STATE)); +- } +- +- /* Initialize */ +- +- if (state) { +- /* Always zero out the object before init */ +- +- MEMSET (state, 0, sizeof (ACPI_GENERIC_STATE)); +- +- state->common.data_type = ACPI_DESC_TYPE_STATE; +- } +- +- return (state); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_create_update_state +- * +- * PARAMETERS: Object - Initial Object to be installed in the +- * state +- * Action - Update action to be performed +- * +- * RETURN: Status +- * +- * DESCRIPTION: Create an "Update State" - a flavor of the generic state used +- * to update reference counts and delete complex objects such +- * as packages. +- * +- ******************************************************************************/ +- +-ACPI_GENERIC_STATE * +-acpi_cm_create_update_state ( +- ACPI_OPERAND_OBJECT *object, +- u16 action) +-{ +- ACPI_GENERIC_STATE *state; +- +- +- /* Create the generic state object */ +- +- state = acpi_cm_create_generic_state (); +- if (!state) { +- return (NULL); +- } +- +- /* Init fields specific to the update struct */ +- +- state->update.object = object; +- state->update.value = action; +- +- return (state); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_create_pkg_state +- * +- * PARAMETERS: Object - Initial Object to be installed in the +- * state +- * Action - Update action to be performed +- * +- * RETURN: Status +- * +- * DESCRIPTION: Create an "Update State" - a flavor of the generic state used +- * to update reference counts and delete complex objects such +- * as packages. +- * +- ******************************************************************************/ +- +-ACPI_GENERIC_STATE * +-acpi_cm_create_pkg_state ( +- void *internal_object, +- void *external_object, +- u16 index) +-{ +- ACPI_GENERIC_STATE *state; +- +- +- /* Create the generic state object */ +- +- state = acpi_cm_create_generic_state (); +- if (!state) { +- return (NULL); +- } +- +- /* Init fields specific to the update struct */ +- +- state->pkg.source_object = (ACPI_OPERAND_OBJECT *) internal_object; +- state->pkg.dest_object = external_object; +- state->pkg.index = index; +- state->pkg.num_packages = 1; +- +- return (state); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_create_control_state +- * +- * PARAMETERS: None +- * +- * RETURN: Status +- * +- * DESCRIPTION: Create a "Control State" - a flavor of the generic state used +- * to support nested IF/WHILE constructs in the AML. +- * +- ******************************************************************************/ +- +-ACPI_GENERIC_STATE * +-acpi_cm_create_control_state ( +- void) +-{ +- ACPI_GENERIC_STATE *state; +- +- +- /* Create the generic state object */ +- +- state = acpi_cm_create_generic_state (); +- if (!state) { +- return (NULL); +- } +- +- +- /* Init fields specific to the control struct */ +- +- state->common.state = CONTROL_CONDITIONAL_EXECUTING; +- +- return (state); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_delete_generic_state +- * +- * PARAMETERS: State - The state object to be deleted +- * +- * RETURN: Status +- * +- * DESCRIPTION: Put a state object back into the global state cache. The object +- * is not actually freed at this time. +- * +- ******************************************************************************/ +- +-void +-acpi_cm_delete_generic_state ( +- ACPI_GENERIC_STATE *state) +-{ +- +- /* If cache is full, just free this state object */ +- +- if (acpi_gbl_generic_state_cache_depth >= MAX_STATE_CACHE_DEPTH) { +- acpi_cm_free (state); +- } +- +- /* Otherwise put this object back into the cache */ +- +- else { +- acpi_cm_acquire_mutex (ACPI_MTX_CACHES); +- +- /* Clear the state */ +- +- MEMSET (state, 0, sizeof (ACPI_GENERIC_STATE)); +- state->common.data_type = ACPI_DESC_TYPE_STATE; +- +- /* Put the object at the head of the global cache list */ +- +- state->common.next = acpi_gbl_generic_state_cache; +- acpi_gbl_generic_state_cache = state; +- acpi_gbl_generic_state_cache_depth++; +- +- +- acpi_cm_release_mutex (ACPI_MTX_CACHES); +- } +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_delete_generic_state_cache +- * +- * PARAMETERS: None +- * +- * RETURN: Status +- * +- * DESCRIPTION: Purge the global state object cache. Used during subsystem +- * termination. +- * +- ******************************************************************************/ +- +-void +-acpi_cm_delete_generic_state_cache ( +- void) +-{ +- ACPI_GENERIC_STATE *next; +- +- +- /* Traverse the global cache list */ +- +- while (acpi_gbl_generic_state_cache) { +- /* Delete one cached state object */ +- +- next = acpi_gbl_generic_state_cache->common.next; +- acpi_cm_free (acpi_gbl_generic_state_cache); +- acpi_gbl_generic_state_cache = next; +- acpi_gbl_generic_state_cache_depth--; +- } +- +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_resolve_package_references +- * +- * PARAMETERS: Obj_desc - The Package object on which to resolve refs +- * +- * RETURN: Status +- * +- * DESCRIPTION: Walk through a package and turn internal references into values +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_resolve_package_references ( +- ACPI_OPERAND_OBJECT *obj_desc) +-{ +- u32 count; +- ACPI_OPERAND_OBJECT *sub_object; +- +- +- if (obj_desc->common.type != ACPI_TYPE_PACKAGE) { +- /* The object must be a package */ +- +- REPORT_ERROR (("Must resolve Package Refs on a Package\n")); +- return(AE_ERROR); +- } +- +- /* +- * TBD: what about nested packages? */ +- +- for (count = 0; count < obj_desc->package.count; count++) { +- sub_object = obj_desc->package.elements[count]; +- +- if (sub_object->common.type == INTERNAL_TYPE_REFERENCE) { +- if (sub_object->reference.op_code == AML_ZERO_OP) { +- sub_object->common.type = ACPI_TYPE_INTEGER; +- sub_object->integer.value = 0; +- } +- else if (sub_object->reference.op_code == AML_ONE_OP) { +- sub_object->common.type = ACPI_TYPE_INTEGER; +- sub_object->integer.value = 1; +- } +- else if (sub_object->reference.op_code == AML_ONES_OP) { +- sub_object->common.type = ACPI_TYPE_INTEGER; +- sub_object->integer.value = ACPI_INTEGER_MAX; +- } +- } +- } +- +- return(AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_cm_walk_package_tree +- * +- * PARAMETERS: Obj_desc - The Package object on which to resolve refs +- * +- * RETURN: Status +- * +- * DESCRIPTION: Walk through a package +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_cm_walk_package_tree ( +- ACPI_OPERAND_OBJECT *source_object, +- void *target_object, +- ACPI_PKG_CALLBACK walk_callback, +- void *context) +-{ +- ACPI_STATUS status = AE_OK; +- ACPI_GENERIC_STATE *state_list = NULL; +- ACPI_GENERIC_STATE *state; +- u32 this_index; +- ACPI_OPERAND_OBJECT *this_source_obj; +- +- +- state = acpi_cm_create_pkg_state (source_object, target_object, 0); +- if (!state) { +- return (AE_NO_MEMORY); +- } +- +- while (state) { +- this_index = state->pkg.index; +- this_source_obj = (ACPI_OPERAND_OBJECT *) +- state->pkg.source_object->package.elements[this_index]; +- +- /* +- * Check for +- * 1) An uninitialized package element. It is completely +- * legal to declare a package and leave it uninitialized +- * 2) Not an internal object - can be a namespace node instead +- * 3) Any type other than a package. Packages are handled in else case below. +- */ +- if ((!this_source_obj) || +- (!VALID_DESCRIPTOR_TYPE ( +- this_source_obj, ACPI_DESC_TYPE_INTERNAL)) || +- (!IS_THIS_OBJECT_TYPE ( +- this_source_obj, ACPI_TYPE_PACKAGE))) +- { +- +- status = walk_callback (0, this_source_obj, state, context); +- if (ACPI_FAILURE (status)) { +- /* TBD: must delete package created up to this point */ +- +- return (status); +- } +- +- state->pkg.index++; +- while (state->pkg.index >= state->pkg.source_object->package.count) { +- /* +- * We've handled all of the objects at this level, This means +- * that we have just completed a package. That package may +- * have contained one or more packages itself. +- * +- * Delete this state and pop the previous state (package). +- */ +- acpi_cm_delete_generic_state (state); +- state = acpi_cm_pop_generic_state (&state_list); +- +- +- /* Finished when there are no more states */ +- +- if (!state) { +- /* +- * We have handled all of the objects in the top level +- * package just add the length of the package objects +- * and exit +- */ +- return (AE_OK); +- } +- +- /* +- * Go back up a level and move the index past the just +- * completed package object. +- */ +- state->pkg.index++; +- } +- } +- +- else { +- /* This is a sub-object of type package */ +- +- status = walk_callback (1, this_source_obj, state, context); +- if (ACPI_FAILURE (status)) { +- /* TBD: must delete package created up to this point */ +- +- return (status); +- } +- +- +- /* +- * The callback above returned a new target package object. +- */ +- +- /* +- * Push the current state and create a new one +- */ +- acpi_cm_push_generic_state (&state_list, state); +- state = acpi_cm_create_pkg_state (this_source_obj, state->pkg.this_target_obj, 0); +- if (!state) { +- /* TBD: must delete package created up to this point */ +- +- return (AE_NO_MEMORY); +- } +- } +- } +- +- /* We should never get here */ +- +- return (AE_AML_INTERNAL); +- +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: _Report_error +- * +- * PARAMETERS: Module_name - Caller's module name (for error output) +- * Line_number - Caller's line number (for error output) +- * Component_id - Caller's component ID (for error output) +- * Message - Error message to use on failure +- * +- * RETURN: None +- * +- * DESCRIPTION: Print error message +- * +- ******************************************************************************/ +- +-void +-_report_error ( +- NATIVE_CHAR *module_name, +- u32 line_number, +- u32 component_id) +-{ +- +- +- acpi_os_printf ("%8s-%04d: *** Error: ", module_name, line_number); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: _Report_warning +- * +- * PARAMETERS: Module_name - Caller's module name (for error output) +- * Line_number - Caller's line number (for error output) +- * Component_id - Caller's component ID (for error output) +- * Message - Error message to use on failure +- * +- * RETURN: None +- * +- * DESCRIPTION: Print warning message +- * +- ******************************************************************************/ +- +-void +-_report_warning ( +- NATIVE_CHAR *module_name, +- u32 line_number, +- u32 component_id) +-{ +- +- acpi_os_printf ("%8s-%04d: *** Warning: ", module_name, line_number); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: _Report_info +- * +- * PARAMETERS: Module_name - Caller's module name (for error output) +- * Line_number - Caller's line number (for error output) +- * Component_id - Caller's component ID (for error output) +- * Message - Error message to use on failure +- * +- * RETURN: None +- * +- * DESCRIPTION: Print information message +- * +- ******************************************************************************/ +- +-void +-_report_info ( +- NATIVE_CHAR *module_name, +- u32 line_number, +- u32 component_id) +-{ +- +- acpi_os_printf ("%8s-%04d: *** Info: ", module_name, line_number); +-} +- +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/common/cmxface.c linux/drivers/acpi/common/cmxface.c +--- /usr/src/linux/drivers/acpi/common/cmxface.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/common/cmxface.c Wed Dec 31 16:00:00 1969 +@@ -1,396 +0,0 @@ +-/****************************************************************************** +- * +- * Module Name: cmxface - External interfaces for "global" ACPI functions +- * $Revision: 64 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acevents.h" +-#include "achware.h" +-#include "acnamesp.h" +-#include "acinterp.h" +-#include "amlcode.h" +-#include "acdebug.h" +- +- +-#define _COMPONENT MISCELLANEOUS +- MODULE_NAME ("cmxface") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_initialize_subsystem +- * +- * PARAMETERS: None +- * +- * RETURN: Status +- * +- * DESCRIPTION: Initializes all global variables. This is the first function +- * called, so any early initialization belongs here. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_initialize_subsystem ( +- void) +-{ +- ACPI_STATUS status; +- +- +- /* Initialize all globals used by the subsystem */ +- +- acpi_cm_init_globals (); +- +- /* Initialize the OS-Dependent layer */ +- +- status = acpi_os_initialize (); +- if (ACPI_FAILURE (status)) { +- REPORT_ERROR (("OSD failed to initialize, %s\n", +- acpi_cm_format_exception (status))); +- return (status); +- } +- +- /* Create the default mutex objects */ +- +- status = acpi_cm_mutex_initialize (); +- if (ACPI_FAILURE (status)) { +- REPORT_ERROR (("Global mutex creation failure, %s\n", +- acpi_cm_format_exception (status))); +- return (status); +- } +- +- /* +- * Initialize the namespace manager and +- * the root of the namespace tree +- */ +- +- status = acpi_ns_root_initialize (); +- if (ACPI_FAILURE (status)) { +- REPORT_ERROR (("Namespace initialization failure, %s\n", +- acpi_cm_format_exception (status))); +- return (status); +- } +- +- +- /* If configured, initialize the AML debugger */ +- +- DEBUGGER_EXEC (acpi_db_initialize ()); +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_enable_subsystem +- * +- * PARAMETERS: Flags - Init/enable Options +- * +- * RETURN: Status +- * +- * DESCRIPTION: Completes the subsystem initialization including hardware. +- * Puts system into ACPI mode if it isn't already. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_enable_subsystem ( +- u32 flags) +-{ +- ACPI_STATUS status = AE_OK; +- +- +- /* Sanity check the FADT for valid values */ +- +- status = acpi_cm_validate_fadt (); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- /* +- * Install the default Op_region handlers. These are +- * installed unless other handlers have already been +- * installed via the Install_address_space_handler interface +- */ +- +- if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { +- status = acpi_ev_install_default_address_space_handlers (); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- } +- +- /* +- * We must initialize the hardware before we can enable ACPI. +- */ +- +- if (!(flags & ACPI_NO_HARDWARE_INIT)) { +- status = acpi_hw_initialize (); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- } +- +- /* +- * Enable ACPI on this platform +- */ +- +- if (!(flags & ACPI_NO_ACPI_ENABLE)) { +- status = acpi_enable (); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- } +- +- /* +- * Note: +- * We must have the hardware AND events initialized before we can execute +- * ANY control methods SAFELY. Any control method can require ACPI hardware +- * support, so the hardware MUST be initialized before execution! +- */ +- +- if (!(flags & ACPI_NO_EVENT_INIT)) { +- status = acpi_ev_initialize (); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- } +- +- +- /* +- * Initialize all device objects in the namespace +- * This runs the _STA and _INI methods. +- */ +- +- if (!(flags & ACPI_NO_DEVICE_INIT)) { +- status = acpi_ns_initialize_devices (); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- } +- +- +- /* +- * Initialize the objects that remain uninitialized. This +- * runs the executable AML that is part of the declaration of Op_regions +- * and Fields. +- */ +- +- if (!(flags & ACPI_NO_OBJECT_INIT)) { +- status = acpi_ns_initialize_objects (); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- } +- +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_terminate +- * +- * PARAMETERS: None +- * +- * RETURN: Status +- * +- * DESCRIPTION: Shutdown the ACPI subsystem. Release all resources. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_terminate (void) +-{ +- +- /* Terminate the AML Debuger if present */ +- +- DEBUGGER_EXEC(acpi_gbl_db_terminate_threads = TRUE); +- +- /* TBD: [Investigate] This is no longer needed?*/ +-/* Acpi_cm_release_mutex (ACPI_MTX_DEBUG_CMD_READY); */ +- +- +- /* Shutdown and free all resources */ +- +- acpi_cm_subsystem_shutdown (); +- +- +- /* Free the mutex objects */ +- +- acpi_cm_mutex_terminate (); +- +- +- /* Now we can shutdown the OS-dependent layer */ +- +- acpi_os_terminate (); +- +- return (AE_OK); +-} +- +- +-/****************************************************************************** +- * +- * FUNCTION: Acpi_get_system_info +- * +- * PARAMETERS: Out_buffer - a pointer to a buffer to receive the +- * resources for the device +- * Buffer_length - the number of bytes available in the buffer +- * +- * RETURN: Status - the status of the call +- * +- * DESCRIPTION: This function is called to get information about the current +- * state of the ACPI subsystem. It will return system information +- * in the Out_buffer. +- * +- * If the function fails an appropriate status will be returned +- * and the value of Out_buffer is undefined. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_get_system_info ( +- ACPI_BUFFER *out_buffer) +-{ +- ACPI_SYSTEM_INFO *info_ptr; +- u32 i; +- +- +- /* +- * Must have a valid buffer +- */ +- if ((!out_buffer) || +- (!out_buffer->pointer)) +- { +- return (AE_BAD_PARAMETER); +- } +- +- if (out_buffer->length < sizeof (ACPI_SYSTEM_INFO)) { +- /* +- * Caller's buffer is too small +- */ +- out_buffer->length = sizeof (ACPI_SYSTEM_INFO); +- +- return (AE_BUFFER_OVERFLOW); +- } +- +- +- /* +- * Set return length and get data +- */ +- out_buffer->length = sizeof (ACPI_SYSTEM_INFO); +- info_ptr = (ACPI_SYSTEM_INFO *) out_buffer->pointer; +- +- info_ptr->acpi_ca_version = ACPI_CA_VERSION; +- +- /* System flags (ACPI capabilities) */ +- +- info_ptr->flags = acpi_gbl_system_flags; +- +- /* Timer resolution - 24 or 32 bits */ +- if (!acpi_gbl_FADT) { +- info_ptr->timer_resolution = 0; +- } +- else if (acpi_gbl_FADT->tmr_val_ext == 0) { +- info_ptr->timer_resolution = 24; +- } +- else { +- info_ptr->timer_resolution = 32; +- } +- +- /* Clear the reserved fields */ +- +- info_ptr->reserved1 = 0; +- info_ptr->reserved2 = 0; +- +- /* Current debug levels */ +- +- info_ptr->debug_layer = acpi_dbg_layer; +- info_ptr->debug_level = acpi_dbg_level; +- +- /* Current status of the ACPI tables, per table type */ +- +- info_ptr->num_table_types = NUM_ACPI_TABLES; +- for (i = 0; i < NUM_ACPI_TABLES; i++) { +- info_ptr->table_info[i].count = acpi_gbl_acpi_tables[i].count; +- } +- +- return (AE_OK); +-} +- +- +-/****************************************************************************** +- * +- * FUNCTION: Acpi_format_exception +- * +- * PARAMETERS: Out_buffer - a pointer to a buffer to receive the +- * exception name +- * +- * RETURN: Status - the status of the call +- * +- * DESCRIPTION: This function translates an ACPI exception into an ASCII string. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_format_exception ( +- ACPI_STATUS exception, +- ACPI_BUFFER *out_buffer) +-{ +- u32 length; +- NATIVE_CHAR *formatted_exception; +- +- +- /* +- * Must have a valid buffer +- */ +- if ((!out_buffer) || +- (!out_buffer->pointer)) +- { +- return (AE_BAD_PARAMETER); +- } +- +- +- /* Convert the exception code (Handles bad exception codes) */ +- +- formatted_exception = acpi_cm_format_exception (exception); +- +- /* +- * Get length of string and check if it will fit in caller's buffer +- */ +- +- length = STRLEN (formatted_exception); +- if (out_buffer->length < length) { +- out_buffer->length = length; +- return (AE_BUFFER_OVERFLOW); +- } +- +- +- /* Copy the string, all done */ +- +- STRCPY (out_buffer->pointer, formatted_exception); +- +- return (AE_OK); +-} +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/cpu.c linux/drivers/acpi/cpu.c +--- /usr/src/linux/drivers/acpi/cpu.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/cpu.c Wed Dec 31 16:00:00 1969 +@@ -1,353 +0,0 @@ +-/* +- * cpu.c - Processor handling +- * +- * Copyright (C) 2000 Andrew Henroid +- * Copyright (C) 2001 Andrew Grover +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +-#include <linux/config.h> +-#include <linux/kernel.h> +-#include <linux/pm.h> +-#include <linux/acpi.h> +-#include "acpi.h" +-#include "driver.h" +- +-#define _COMPONENT OS_DEPENDENT +- MODULE_NAME ("cpu") +- +-u32 acpi_c2_exit_latency = ACPI_INFINITE; +-u32 acpi_c3_exit_latency = ACPI_INFINITE; +-u32 acpi_c2_enter_latency = ACPI_INFINITE; +-u32 acpi_c3_enter_latency = ACPI_INFINITE; +-u32 acpi_use_idle = TRUE; +- +-u32 acpi_c1_count = 0; +-u32 acpi_c2_count = 0; +-u32 acpi_c3_count = 0; +- +-static u32 acpi_pblk = ACPI_INVALID; +-static int acpi_c2_tested = 0; +-static int acpi_c3_tested = 0; +-static int acpi_max_c_state = 1; +-static int acpi_pm_tmr_len = 24; +- +-#define CPU_POWER_STATES 3 +-#define MAX_C2_LATENCY 100 +-#define MAX_C3_LATENCY 1000 +- +-#define ACPI_STATE_C1 0 +-#define ACPI_STATE_C2 1 +-#define ACPI_STATE_C3 2 +- +-/* +- * Clear busmaster activity flag +- */ +-static inline void +-acpi_clear_bm_activity(void) +-{ +- acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_LOCK, BM_STS, 1); +-} +- +-/* +- * Returns 1 if there has been busmaster activity +- */ +-static inline int +-acpi_bm_activity(void) +-{ +- return acpi_hw_register_bit_access(ACPI_READ, ACPI_MTX_LOCK, BM_STS); +-} +- +-/* +- * Set system to sleep through busmaster requests +- */ +-static void +-acpi_sleep_on_busmaster(void) +-{ +- acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, BM_RLD, 1); +-} +- +-/* +- * Set system to wake on busmaster requests +- */ +-static void +-acpi_wake_on_busmaster(void) +-{ +- acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, BM_RLD, 0); +-} +- +-u32 +-acpi_read_pm_timer(void) +-{ +- return acpi_hw_register_read(ACPI_MTX_LOCK, PM_TIMER); +-} +- +-/* +- * Do a compare, accounting for 24/32bit rollover +- */ +-static u32 +-acpi_compare_pm_timers(u32 first, u32 second) +-{ +- if (first < second) { +- return (second - first); +- } else { +- if (acpi_pm_tmr_len == 24) +- return (second + (0xFFFFFF - first)); +- else +- return (second + (0xFFFFFFFF - first)); +- } +-} +- +- +-/* +- * Idle loop (uniprocessor only) +- */ +-static void +-acpi_idle(void) +-{ +- static int sleep_level = 1; +- FADT_DESCRIPTOR *fadt = &acpi_fadt; +- +- /* +- * start from the previous sleep level. +- * if not initialized, we goto sleep1 +- */ +- if (sleep_level == 1 +- || acpi_max_c_state < 2) +- goto sleep1; +- +- if (sleep_level == 2 +- || acpi_max_c_state < 3) +- goto sleep2; +- +-sleep3: +- sleep_level = 3; +- if (!acpi_c3_tested) { +- DEBUG_PRINT(ACPI_INFO, ("C3 works\n")); +- acpi_c3_tested = 1; +- } +- acpi_wake_on_busmaster(); +- if (fadt->Xpm2_cnt_blk.address) +- goto sleep3_with_arbiter; +- +- for (;;) { +- unsigned long time; +- unsigned long diff; +- +- __cli(); +- if (current->need_resched) +- goto out; +- if (acpi_bm_activity()) +- goto sleep2; +- +- time = acpi_read_pm_timer(); +- acpi_c3_count++; +- inb(acpi_pblk + ACPI_P_LVL3); +- /* Dummy read, force synchronization with the PMU */ +- acpi_read_pm_timer(); +- diff = acpi_compare_pm_timers(time, acpi_read_pm_timer()); +- +- __sti(); +- if (diff < acpi_c3_exit_latency) +- goto sleep1; +- } +- +-sleep3_with_arbiter: +- for (;;) { +- unsigned long time; +- unsigned long diff; +- +- __cli(); +- if (current->need_resched) +- goto out; +- if (acpi_bm_activity()) +- goto sleep2; +- +- time = acpi_read_pm_timer(); +- +- /* Disable arbiter, park on CPU */ +- acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_LOCK, ARB_DIS, 1); +- acpi_c3_count++; +- inb(acpi_pblk + ACPI_P_LVL3); +- /* Dummy read, force synchronization with the PMU */ +- acpi_read_pm_timer(); +- diff = acpi_compare_pm_timers(time, acpi_read_pm_timer()); +- /* Enable arbiter again.. */ +- acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_LOCK, ARB_DIS, 0); +- +- __sti(); +- if (diff < acpi_c3_exit_latency) +- goto sleep1; +- } +- +-sleep2: +- sleep_level = 2; +- if (!acpi_c2_tested) { +- DEBUG_PRINT(ACPI_INFO, ("C2 works\n")); +- acpi_c2_tested = 1; +- } +- acpi_wake_on_busmaster(); /* Required to track BM activity.. */ +- for (;;) { +- unsigned long time; +- unsigned long diff; +- +- __cli(); +- if (current->need_resched) +- goto out; +- +- time = acpi_read_pm_timer(); +- acpi_c2_count++; +- inb(acpi_pblk + ACPI_P_LVL2); +- /* Dummy read, force synchronization with the PMU */ +- acpi_read_pm_timer(); +- diff = acpi_compare_pm_timers(time, acpi_read_pm_timer()); +- +- __sti(); +- if (diff < acpi_c2_exit_latency) +- goto sleep1; +- if (acpi_bm_activity()) { +- acpi_clear_bm_activity(); +- continue; +- } +- if (diff > acpi_c3_enter_latency +- && acpi_max_c_state >= 3) +- goto sleep3; +- } +- +-sleep1: +- sleep_level = 1; +- acpi_sleep_on_busmaster(); +- for (;;) { +- unsigned long time; +- unsigned long diff; +- +- __cli(); +- if (current->need_resched) +- goto out; +- time = acpi_read_pm_timer(); +- acpi_c1_count++; +- safe_halt(); +- diff = acpi_compare_pm_timers(time, acpi_read_pm_timer()); +- if (diff > acpi_c2_enter_latency +- && acpi_max_c_state >= 2) +- goto sleep2; +- } +- +-out: +- __sti(); +-} +- +-/* +- * Get processor information +- */ +-static ACPI_STATUS +-acpi_found_cpu(ACPI_HANDLE handle, u32 level, void *ctx, void **value) +-{ +- ACPI_OBJECT obj; +- ACPI_BUFFER buf; +- +- buf.length = sizeof(obj); +- buf.pointer = &obj; +- if (!ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buf))) +- return AE_OK; +- +- DEBUG_PRINT(ACPI_INFO, ("PBLK %d @ 0x%04x:%d\n", +- obj.processor.proc_id, +- obj.processor.pblk_address, +- obj.processor.pblk_length)); +- +- if (acpi_pblk != ACPI_INVALID +- || !obj.processor.pblk_address +- || obj.processor.pblk_length != 6) +- return AE_OK; +- +- acpi_pblk = obj.processor.pblk_address; +- +- if (acpi_fadt.plvl2_lat +- && acpi_fadt.plvl2_lat <= MAX_C2_LATENCY) { +- acpi_c2_exit_latency +- = ACPI_MICROSEC_TO_TMR_TICKS(acpi_fadt.plvl2_lat); +- acpi_c2_enter_latency +- = ACPI_MICROSEC_TO_TMR_TICKS(acpi_fadt.plvl2_lat * 4); +- acpi_max_c_state = 2; +- +- printk(KERN_INFO "ACPI: System firmware supports: C2"); +- +- if (acpi_fadt.plvl3_lat +- && acpi_fadt.plvl3_lat <= MAX_C3_LATENCY) { +- acpi_c3_exit_latency +- = ACPI_MICROSEC_TO_TMR_TICKS(acpi_fadt.plvl3_lat); +- acpi_c3_enter_latency +- = ACPI_MICROSEC_TO_TMR_TICKS(acpi_fadt.plvl3_lat * 12); +- acpi_max_c_state = 3; +- +- printk(" C3"); +- } +- +- printk("\n"); +- } +- +- printk(KERN_INFO "ACPI: plvl2lat=%d plvl3lat=%d\n", acpi_fadt.plvl2_lat, acpi_fadt.plvl3_lat); +- printk(KERN_INFO "ACPI: C2 enter=%d C2 exit=%d\n", acpi_c2_enter_latency, acpi_c2_exit_latency); +- printk(KERN_INFO "ACPI: C3 enter=%d C3 exit=%d\n", acpi_c3_enter_latency, acpi_c3_exit_latency); +- +- return AE_OK; +-} +- +-static int +-acpi_pm_timer_init(void) +-{ +- FADT_DESCRIPTOR *fadt = &acpi_fadt; +- +- if (fadt->tmr_val_ext) { +- acpi_pm_tmr_len = 32; +- } else { +- acpi_pm_tmr_len = 24; +- } +- +- DEBUG_PRINT(ACPI_INFO, ("PM Timer width: %d bits\n", acpi_pm_tmr_len)); +- +- return AE_OK; +-} +- +-int +-acpi_cpu_init(void) +-{ +- acpi_walk_namespace(ACPI_TYPE_PROCESSOR, +- ACPI_ROOT_OBJECT, +- ACPI_UINT32_MAX, +- acpi_found_cpu, +- NULL, +- NULL); +- +- acpi_pm_timer_init(); +- +- if (acpi_use_idle) { +-#ifdef CONFIG_SMP +- if (smp_num_cpus == 1) +- pm_idle = acpi_idle; +-#else +- pm_idle = acpi_idle; +-#endif +- printk(KERN_INFO "ACPI: Using ACPI idle\n"); +- printk(KERN_INFO "ACPI: If experiencing system slowness, try adding \"acpi=no-idle\" to cmdline\n"); +- } +- else { +- printk(KERN_INFO "ACPI: Not using ACPI idle\n"); +- } +- +- return 0; +-} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/dispatcher/Makefile linux/drivers/acpi/dispatcher/Makefile +--- /usr/src/linux/drivers/acpi/dispatcher/Makefile Fri Dec 29 14:07:21 2000 ++++ linux/drivers/acpi/dispatcher/Makefile Fri Apr 13 11:57:11 2001 +@@ -1,5 +1,6 @@ + # + # Makefile for all Linux ACPI interpreter subdirectories ++# EXCEPT for the ospm directory + # + + O_TARGET := ../$(shell basename `pwd`).o +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/dispatcher/dsfield.c linux/drivers/acpi/dispatcher/dsfield.c +--- /usr/src/linux/drivers/acpi/dispatcher/dsfield.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/dispatcher/dsfield.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: dsfield - Dispatcher field routines +- * $Revision: 31 $ ++ * $Revision: 37 $ + * + *****************************************************************************/ + +@@ -31,7 +31,7 @@ + #include "acnamesp.h" + + +-#define _COMPONENT DISPATCHER ++#define _COMPONENT ACPI_DISPATCHER + MODULE_NAME ("dsfield") + + +@@ -51,7 +51,8 @@ + * FUNCTION: Acpi_ds_create_field + * + * PARAMETERS: Op - Op containing the Field definition and args +- * Region_node - Object for the containing Operation Region ++ * Region_node - Object for the containing Operation Region ++ * ` Walk_state - Current method state + * + * RETURN: Status + * +@@ -69,7 +70,6 @@ + ACPI_PARSE_OBJECT *arg; + ACPI_NAMESPACE_NODE *node; + u8 field_flags; +- u8 access_attribute = 0; + u32 field_bit_position = 0; + + +@@ -78,10 +78,8 @@ + arg = op->value.arg; + if (!region_node) { + status = acpi_ns_lookup (walk_state->scope_info, arg->value.name, +- ACPI_TYPE_REGION, IMODE_EXECUTE, +- NS_SEARCH_PARENT, walk_state, +- ®ion_node); +- ++ ACPI_TYPE_REGION, IMODE_EXECUTE, ++ NS_SEARCH_PARENT, walk_state, ®ion_node); + if (ACPI_FAILURE (status)) { + return (status); + } +@@ -96,8 +94,7 @@ + + arg = arg->next; + while (arg) { +- switch (arg->opcode) +- { ++ switch (arg->opcode) { + case AML_RESERVEDFIELD_OP: + + field_bit_position += arg->value.size; +@@ -110,11 +107,8 @@ + * Get a new Access_type and Access_attribute for all + * entries (until end or another Access_as keyword) + */ +- +- access_attribute = (u8) arg->value.integer; +- field_flags = (u8) +- ((field_flags & FIELD_ACCESS_TYPE_MASK) || +- ((u8) (arg->value.integer >> 8))); ++ field_flags = (u8) ((field_flags & FIELD_ACCESS_TYPE_MASK) || ++ ((u8) (arg->value.integer >> 8))); + break; + + +@@ -122,11 +116,9 @@ + + status = acpi_ns_lookup (walk_state->scope_info, + (NATIVE_CHAR *) &((ACPI_PARSE2_OBJECT *)arg)->name, +- INTERNAL_TYPE_DEF_FIELD, +- IMODE_LOAD_PASS1, ++ INTERNAL_TYPE_REGION_FIELD, IMODE_LOAD_PASS1, + NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, + NULL, &node); +- + if (ACPI_FAILURE (status)) { + return (status); + } +@@ -136,9 +128,8 @@ + * the object stack + */ + +- status = acpi_aml_prep_def_field_value (node, region_node, field_flags, +- access_attribute, field_bit_position, arg->value.size); +- ++ status = acpi_aml_prep_region_field_value (node, region_node, field_flags, ++ field_bit_position, arg->value.size); + if (ACPI_FAILURE (status)) { + return (status); + } +@@ -161,7 +152,8 @@ + * FUNCTION: Acpi_ds_create_bank_field + * + * PARAMETERS: Op - Op containing the Field definition and args +- * Region_node - Object for the containing Operation Region ++ * Region_node - Object for the containing Operation Region ++ * ` Walk_state - Current method state + * + * RETURN: Status + * +@@ -181,7 +173,6 @@ + ACPI_NAMESPACE_NODE *node; + u32 bank_value; + u8 field_flags; +- u8 access_attribute = 0; + u32 field_bit_position = 0; + + +@@ -190,10 +181,8 @@ + arg = op->value.arg; + if (!region_node) { + status = acpi_ns_lookup (walk_state->scope_info, arg->value.name, +- ACPI_TYPE_REGION, IMODE_EXECUTE, +- NS_SEARCH_PARENT, walk_state, +- ®ion_node); +- ++ ACPI_TYPE_REGION, IMODE_EXECUTE, ++ NS_SEARCH_PARENT, walk_state, ®ion_node); + if (ACPI_FAILURE (status)) { + return (status); + } +@@ -204,11 +193,9 @@ + arg = arg->next; + + status = acpi_ns_lookup (walk_state->scope_info, arg->value.string, +- INTERNAL_TYPE_BANK_FIELD_DEFN, +- IMODE_LOAD_PASS1, +- NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, +- NULL, ®ister_node); +- ++ INTERNAL_TYPE_BANK_FIELD_DEFN, IMODE_LOAD_PASS1, ++ NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, ++ NULL, ®ister_node); + if (ACPI_FAILURE (status)) { + return (status); + } +@@ -228,8 +215,7 @@ + + arg = arg->next; + while (arg) { +- switch (arg->opcode) +- { ++ switch (arg->opcode) { + case AML_RESERVEDFIELD_OP: + + field_bit_position += arg->value.size; +@@ -242,11 +228,8 @@ + * Get a new Access_type and Access_attribute for + * all entries (until end or another Access_as keyword) + */ +- +- access_attribute = (u8) arg->value.integer; +- field_flags = (u8) +- ((field_flags & FIELD_ACCESS_TYPE_MASK) || +- ((u8) (arg->value.integer >> 8))); ++ field_flags = (u8) ((field_flags & FIELD_ACCESS_TYPE_MASK) || ++ ((u8) (arg->value.integer >> 8))); + break; + + +@@ -254,11 +237,9 @@ + + status = acpi_ns_lookup (walk_state->scope_info, + (NATIVE_CHAR *) &((ACPI_PARSE2_OBJECT *)arg)->name, +- INTERNAL_TYPE_DEF_FIELD, +- IMODE_LOAD_PASS1, ++ INTERNAL_TYPE_REGION_FIELD, IMODE_LOAD_PASS1, + NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, + NULL, &node); +- + if (ACPI_FAILURE (status)) { + return (status); + } +@@ -269,9 +250,8 @@ + */ + + status = acpi_aml_prep_bank_field_value (node, region_node, register_node, +- bank_value, field_flags, access_attribute, +- field_bit_position, arg->value.size); +- ++ bank_value, field_flags, field_bit_position, ++ arg->value.size); + if (ACPI_FAILURE (status)) { + return (status); + } +@@ -295,7 +275,8 @@ + * FUNCTION: Acpi_ds_create_index_field + * + * PARAMETERS: Op - Op containing the Field definition and args +- * Region_node - Object for the containing Operation Region ++ * Region_node - Object for the containing Operation Region ++ * ` Walk_state - Current method state + * + * RETURN: Status + * +@@ -306,7 +287,7 @@ + ACPI_STATUS + acpi_ds_create_index_field ( + ACPI_PARSE_OBJECT *op, +- ACPI_HANDLE region_node, ++ ACPI_NAMESPACE_NODE *region_node, + ACPI_WALK_STATE *walk_state) + { + ACPI_STATUS status; +@@ -315,7 +296,6 @@ + ACPI_NAMESPACE_NODE *index_register_node; + ACPI_NAMESPACE_NODE *data_register_node; + u8 field_flags; +- u8 access_attribute = 0; + u32 field_bit_position = 0; + + +@@ -324,10 +304,9 @@ + /* First arg is the name of the Index register */ + + status = acpi_ns_lookup (walk_state->scope_info, arg->value.string, +- ACPI_TYPE_ANY, IMODE_LOAD_PASS1, +- NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, +- NULL, &index_register_node); +- ++ ACPI_TYPE_ANY, IMODE_LOAD_PASS1, ++ NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, ++ NULL, &index_register_node); + if (ACPI_FAILURE (status)) { + return (status); + } +@@ -337,11 +316,9 @@ + arg = arg->next; + + status = acpi_ns_lookup (walk_state->scope_info, arg->value.string, +- INTERNAL_TYPE_INDEX_FIELD_DEFN, +- IMODE_LOAD_PASS1, +- NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, +- NULL, &data_register_node); +- ++ INTERNAL_TYPE_INDEX_FIELD_DEFN, IMODE_LOAD_PASS1, ++ NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, ++ NULL, &data_register_node); + if (ACPI_FAILURE (status)) { + return (status); + } +@@ -357,8 +334,7 @@ + + arg = arg->next; + while (arg) { +- switch (arg->opcode) +- { ++ switch (arg->opcode) { + case AML_RESERVEDFIELD_OP: + + field_bit_position += arg->value.size; +@@ -371,23 +347,18 @@ + * Get a new Access_type and Access_attribute for all + * entries (until end or another Access_as keyword) + */ +- +- access_attribute = (u8) arg->value.integer; +- field_flags = (u8) +- ((field_flags & FIELD_ACCESS_TYPE_MASK) || +- ((u8) (arg->value.integer >> 8))); ++ field_flags = (u8) ((field_flags & FIELD_ACCESS_TYPE_MASK) || ++ ((u8) (arg->value.integer >> 8))); + break; + + + case AML_NAMEDFIELD_OP: + + status = acpi_ns_lookup (walk_state->scope_info, +- (NATIVE_CHAR *) &((ACPI_PARSE2_OBJECT *)arg)->name, +- INTERNAL_TYPE_INDEX_FIELD, +- IMODE_LOAD_PASS1, +- NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, +- NULL, &node); +- ++ (NATIVE_CHAR *) &((ACPI_PARSE2_OBJECT *)arg)->name, ++ INTERNAL_TYPE_INDEX_FIELD, IMODE_LOAD_PASS1, ++ NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, ++ NULL, &node); + if (ACPI_FAILURE (status)) { + return (status); + } +@@ -397,10 +368,9 @@ + * the object stack + */ + +- status = acpi_aml_prep_index_field_value (node, index_register_node, data_register_node, +- field_flags, access_attribute, ++ status = acpi_aml_prep_index_field_value (node, index_register_node, ++ data_register_node, field_flags, + field_bit_position, arg->value.size); +- + if (ACPI_FAILURE (status)) { + return (status); + } +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/dispatcher/dsmethod.c linux/drivers/acpi/dispatcher/dsmethod.c +--- /usr/src/linux/drivers/acpi/dispatcher/dsmethod.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/dispatcher/dsmethod.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: dsmethod - Parser/Interpreter interface - control method parsing +- * $Revision: 56 $ ++ * $Revision: 61 $ + * + *****************************************************************************/ + +@@ -34,7 +34,7 @@ + #include "acdebug.h" + + +-#define _COMPONENT DISPATCHER ++#define _COMPONENT ACPI_DISPATCHER + MODULE_NAME ("dsmethod") + + +@@ -85,9 +85,9 @@ + /* Create a mutex for the method if there is a concurrency limit */ + + if ((obj_desc->method.concurrency != INFINITE_CONCURRENCY) && +- (!obj_desc->method.semaphore)) +- { +- status = acpi_os_create_semaphore (1,obj_desc->method.concurrency, ++ (!obj_desc->method.semaphore)) { ++ status = acpi_os_create_semaphore (obj_desc->method.concurrency, ++ obj_desc->method.concurrency, + &obj_desc->method.semaphore); + if (ACPI_FAILURE (status)) { + return (status); +@@ -98,7 +98,6 @@ + * Allocate a new parser op to be the root of the parsed + * method tree + */ +- + op = acpi_ps_alloc_op (AML_METHOD_OP); + if (!op) { + return (AE_NO_MEMORY); +@@ -121,7 +120,6 @@ + * method so that operands to the named objects can + * take on dynamic run-time values. + */ +- + status = acpi_ps_parse_aml (op, obj_desc->method.pcode, + obj_desc->method.pcode_length, + ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE, +@@ -151,8 +149,9 @@ + * + * FUNCTION: Acpi_ds_begin_method_execution + * +- * PARAMETERS: Method_node - Node of the method ++ * PARAMETERS: Method_node - Node of the method + * Obj_desc - The method object ++ * Calling_method_node - Caller of this method (if non-null) + * + * RETURN: Status + * +@@ -167,7 +166,8 @@ + ACPI_STATUS + acpi_ds_begin_method_execution ( + ACPI_NAMESPACE_NODE *method_node, +- ACPI_OPERAND_OBJECT *obj_desc) ++ ACPI_OPERAND_OBJECT *obj_desc, ++ ACPI_NAMESPACE_NODE *calling_method_node) + { + ACPI_STATUS status = AE_OK; + +@@ -176,34 +176,41 @@ + return (AE_NULL_ENTRY); + } + +- obj_desc = acpi_ns_get_attached_object (method_node); +- if (!obj_desc) { +- return (AE_NULL_OBJECT); +- } +- + + /* + * If there is a concurrency limit on this method, we need to +- * obtain a unit from the method semaphore. This releases the +- * interpreter if we block ++ * obtain a unit from the method semaphore. + */ +- + if (obj_desc->method.semaphore) { ++ /* ++ * Allow recursive method calls, up to the reentrancy/concurrency ++ * limit imposed by the SERIALIZED rule and the Sync_level method ++ * parameter. ++ * ++ * The point of this code is to avoid permanently blocking a ++ * thread that is making recursive method calls. ++ */ ++ if (method_node == calling_method_node) { ++ if (obj_desc->method.thread_count >= obj_desc->method.concurrency) { ++ return (AE_AML_METHOD_LIMIT); ++ } ++ } ++ ++ /* ++ * Get a unit from the method semaphore. This releases the ++ * interpreter if we block ++ */ + status = acpi_aml_system_wait_semaphore (obj_desc->method.semaphore, + WAIT_FOREVER); + } + + + /* +- * Increment the method parse tree thread count since there +- * is one additional thread executing in it. If configured +- * for deletion-on-exit, the parse tree will be deleted when +- * the last thread completes execution of the method ++ * Increment the method parse tree thread count since it has been ++ * reentered one more time (even if it is the same thread) + */ +- + obj_desc->method.thread_count++; + +- + return (status); + } + +@@ -238,7 +245,6 @@ + /* + * Get the namespace entry for the control method we are about to call + */ +- + method_node = this_walk_state->method_call_node; + if (!method_node) { + return (AE_NULL_ENTRY); +@@ -252,12 +258,12 @@ + + /* Init for new method, wait on concurrency semaphore */ + +- status = acpi_ds_begin_method_execution (method_node, obj_desc); ++ status = acpi_ds_begin_method_execution (method_node, obj_desc, ++ this_walk_state->method_node); + if (ACPI_FAILURE (status)) { + return (status); + } + +- + /* Create and initialize a new parser state */ + + parser_state = acpi_ps_create_state (obj_desc->method.pcode, +@@ -307,7 +313,6 @@ + * stack. Operands on the previous walk state stack always + * start at index 0. + */ +- + status = acpi_ds_method_data_init_args (&this_walk_state->operands[0], + this_walk_state->num_operands, + next_walk_state); +@@ -335,7 +340,6 @@ + * Delete the operands on the previous walkstate operand stack + * (they were copied to new objects) + */ +- + for (i = 0; i < obj_desc->method.param_count; i++) { + acpi_cm_remove_reference (this_walk_state->operands [i]); + this_walk_state->operands [i] = NULL; +@@ -386,7 +390,6 @@ + * Get the return value (if any) from the previous method. + * NULL if no return value + */ +- + status = acpi_ds_result_push (return_desc, walk_state); + if (ACPI_FAILURE (status)) { + acpi_cm_remove_reference (return_desc); +@@ -427,7 +430,6 @@ + acpi_ds_terminate_control_method ( + ACPI_WALK_STATE *walk_state) + { +- ACPI_STATUS status; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_NAMESPACE_NODE *method_node; + +@@ -448,15 +450,14 @@ + * If this is the last thread executing the method, + * we have additional cleanup to perform + */ +- + acpi_cm_acquire_mutex (ACPI_MTX_PARSER); + + + /* Signal completion of the execution of this method if necessary */ + + if (walk_state->method_desc->method.semaphore) { +- status = acpi_os_signal_semaphore ( +- walk_state->method_desc->method.semaphore, 1); ++ acpi_os_signal_semaphore ( ++ walk_state->method_desc->method.semaphore, 1); + } + + /* Decrement the thread count on the method parse tree */ +@@ -470,6 +471,7 @@ + * The method Node is stored in the walk state + */ + method_node = walk_state->method_node; ++ + /* + * Delete any namespace entries created immediately underneath + * the method +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/dispatcher/dsmthdat.c linux/drivers/acpi/dispatcher/dsmthdat.c +--- /usr/src/linux/drivers/acpi/dispatcher/dsmthdat.c Mon Jan 29 10:15:58 2001 ++++ linux/drivers/acpi/dispatcher/dsmthdat.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /******************************************************************************* + * + * Module Name: dsmthdat - control method arguments and local variables +- * $Revision: 39 $ ++ * $Revision: 43 $ + * + ******************************************************************************/ + +@@ -32,7 +32,7 @@ + #include "acnamesp.h" + + +-#define _COMPONENT DISPATCHER ++#define _COMPONENT ACPI_DISPATCHER + MODULE_NAME ("dsmthdat") + + +@@ -182,15 +182,14 @@ + + for (pindex = mindex = 0; + (mindex < MTH_NUM_ARGS) && (pindex < max_param_count); +- mindex++) +- { ++ mindex++) { + if (params[pindex]) { + /* + * A valid parameter. + * Set the current method argument to the + * Params[Pindex++] argument object descriptor + */ +- status = acpi_ds_method_data_set_value (MTH_TYPE_ARG, mindex, ++ status = acpi_ds_store_object_to_local (AML_ARG_OP, mindex, + params[pindex], walk_state); + if (ACPI_FAILURE (status)) { + break; +@@ -212,7 +211,7 @@ + * + * FUNCTION: Acpi_ds_method_data_get_entry + * +- * PARAMETERS: Type - Either MTH_TYPE_LOCAL or MTH_TYPE_ARG ++ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP + * Index - Which local_var or argument to get + * Entry - Pointer to where a pointer to the stack + * entry is returned. +@@ -220,13 +219,13 @@ + * + * RETURN: Status + * +- * DESCRIPTION: Get the address of the stack entry given by Type:Index ++ * DESCRIPTION: Get the address of the object entry given by Opcode:Index + * + ******************************************************************************/ + + ACPI_STATUS + acpi_ds_method_data_get_entry ( +- u32 type, ++ u16 opcode, + u32 index, + ACPI_WALK_STATE *walk_state, + ACPI_OPERAND_OBJECT ***entry) +@@ -235,31 +234,30 @@ + + /* + * Get the requested object. +- * The stack "Type" is either a Local_variable or an Argument ++ * The stack "Opcode" is either a Local_variable or an Argument + */ + +- switch (type) +- { ++ switch (opcode) { + +- case MTH_TYPE_LOCAL: ++ case AML_LOCAL_OP: + + if (index > MTH_MAX_LOCAL) { + return (AE_BAD_PARAMETER); + } + +- *entry = +- (ACPI_OPERAND_OBJECT **) &walk_state->local_variables[index].object; ++ *entry = (ACPI_OPERAND_OBJECT **) ++ &walk_state->local_variables[index].object; + break; + + +- case MTH_TYPE_ARG: ++ case AML_ARG_OP: + + if (index > MTH_MAX_ARG) { + return (AE_BAD_PARAMETER); + } + +- *entry = +- (ACPI_OPERAND_OBJECT **) &walk_state->arguments[index].object; ++ *entry = (ACPI_OPERAND_OBJECT **) ++ &walk_state->arguments[index].object; + break; + + +@@ -276,20 +274,20 @@ + * + * FUNCTION: Acpi_ds_method_data_set_entry + * +- * PARAMETERS: Type - Either MTH_TYPE_LOCAL or MTH_TYPE_ARG ++ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP + * Index - Which local_var or argument to get + * Object - Object to be inserted into the stack entry + * Walk_state - Current walk state object + * + * RETURN: Status + * +- * DESCRIPTION: Insert an object onto the method stack at entry Type:Index. ++ * DESCRIPTION: Insert an object onto the method stack at entry Opcode:Index. + * + ******************************************************************************/ + + ACPI_STATUS + acpi_ds_method_data_set_entry ( +- u32 type, ++ u16 opcode, + u32 index, + ACPI_OPERAND_OBJECT *object, + ACPI_WALK_STATE *walk_state) +@@ -300,7 +298,7 @@ + + /* Get a pointer to the stack entry to set */ + +- status = acpi_ds_method_data_get_entry (type, index, walk_state, &entry); ++ status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry); + if (ACPI_FAILURE (status)) { + return (status); + } +@@ -321,7 +319,7 @@ + * + * FUNCTION: Acpi_ds_method_data_get_type + * +- * PARAMETERS: Type - Either MTH_TYPE_LOCAL or MTH_TYPE_ARG ++ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP + * Index - Which local_var or argument whose type + * to get + * Walk_state - Current walk state object +@@ -333,7 +331,7 @@ + + OBJECT_TYPE_INTERNAL + acpi_ds_method_data_get_type ( +- u32 type, ++ u16 opcode, + u32 index, + ACPI_WALK_STATE *walk_state) + { +@@ -344,7 +342,7 @@ + + /* Get a pointer to the requested stack entry */ + +- status = acpi_ds_method_data_get_entry (type, index, walk_state, &entry); ++ status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry); + if (ACPI_FAILURE (status)) { + return ((ACPI_TYPE_NOT_FOUND)); + } +@@ -366,9 +364,9 @@ + + /******************************************************************************* + * +- * FUNCTION: Acpi_ds_method_data_get_nte ++ * FUNCTION: Acpi_ds_method_data_get_node + * +- * PARAMETERS: Type - Either MTH_TYPE_LOCAL or MTH_TYPE_ARG ++ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP + * Index - Which local_var or argument whose type + * to get + * Walk_state - Current walk state object +@@ -378,18 +376,17 @@ + ******************************************************************************/ + + ACPI_NAMESPACE_NODE * +-acpi_ds_method_data_get_nte ( +- u32 type, ++acpi_ds_method_data_get_node ( ++ u16 opcode, + u32 index, + ACPI_WALK_STATE *walk_state) + { + ACPI_NAMESPACE_NODE *node = NULL; + + +- switch (type) +- { ++ switch (opcode) { + +- case MTH_TYPE_LOCAL: ++ case AML_LOCAL_OP: + + if (index > MTH_MAX_LOCAL) { + return (node); +@@ -399,7 +396,7 @@ + break; + + +- case MTH_TYPE_ARG: ++ case AML_ARG_OP: + + if (index > MTH_MAX_ARG) { + return (node); +@@ -422,7 +419,7 @@ + * + * FUNCTION: Acpi_ds_method_data_get_value + * +- * PARAMETERS: Type - Either MTH_TYPE_LOCAL or MTH_TYPE_ARG ++ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP + * Index - Which local_var or argument to get + * Walk_state - Current walk state object + * *Dest_desc - Ptr to Descriptor into which selected Arg +@@ -438,7 +435,7 @@ + + ACPI_STATUS + acpi_ds_method_data_get_value ( +- u32 type, ++ u16 opcode, + u32 index, + ACPI_WALK_STATE *walk_state, + ACPI_OPERAND_OBJECT **dest_desc) +@@ -457,7 +454,7 @@ + + /* Get a pointer to the requested method stack entry */ + +- status = acpi_ds_method_data_get_entry (type, index, walk_state, &entry); ++ status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry); + if (ACPI_FAILURE (status)) { + return (status); + } +@@ -478,14 +475,13 @@ + * before it was initialized. Either case is an error. + */ + +- switch (type) +- { +- case MTH_TYPE_ARG: ++ switch (opcode) { ++ case AML_ARG_OP: + + return (AE_AML_UNINITIALIZED_ARG); + break; + +- case MTH_TYPE_LOCAL: ++ case AML_LOCAL_OP: + + return (AE_AML_UNINITIALIZED_LOCAL); + break; +@@ -509,20 +505,20 @@ + * + * FUNCTION: Acpi_ds_method_data_delete_value + * +- * PARAMETERS: Type - Either MTH_TYPE_LOCAL or MTH_TYPE_ARG ++ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP + * Index - Which local_var or argument to delete + * Walk_state - Current walk state object + * + * RETURN: Status + * +- * DESCRIPTION: Delete the entry at Type:Index on the method stack. Inserts ++ * DESCRIPTION: Delete the entry at Opcode:Index on the method stack. Inserts + * a null into the stack slot after the object is deleted. + * + ******************************************************************************/ + + ACPI_STATUS + acpi_ds_method_data_delete_value ( +- u32 type, ++ u16 opcode, + u32 index, + ACPI_WALK_STATE *walk_state) + { +@@ -533,7 +529,7 @@ + + /* Get a pointer to the requested entry */ + +- status = acpi_ds_method_data_get_entry (type, index, walk_state, &entry); ++ status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry); + if (ACPI_FAILURE (status)) { + return (status); + } +@@ -551,8 +547,7 @@ + + + if ((object) && +- (VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_INTERNAL))) +- { ++ (VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_INTERNAL))) { + /* + * There is a valid object in this slot + * Decrement the reference count by one to balance the +@@ -568,9 +563,9 @@ + + /******************************************************************************* + * +- * FUNCTION: Acpi_ds_method_data_set_value ++ * FUNCTION: Acpi_ds_store_object_to_local + * +- * PARAMETERS: Type - Either MTH_TYPE_LOCAL or MTH_TYPE_ARG ++ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP + * Index - Which local_var or argument to set + * Src_desc - Value to be stored + * Walk_state - Current walk state +@@ -584,8 +579,8 @@ + ******************************************************************************/ + + ACPI_STATUS +-acpi_ds_method_data_set_value ( +- u32 type, ++acpi_ds_store_object_to_local ( ++ u16 opcode, + u32 index, + ACPI_OPERAND_OBJECT *src_desc, + ACPI_WALK_STATE *walk_state) +@@ -603,7 +598,7 @@ + + /* Get a pointer to the requested method stack entry */ + +- status = acpi_ds_method_data_get_entry (type, index, walk_state, &entry); ++ status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry); + if (ACPI_FAILURE (status)) { + goto cleanup; + } +@@ -638,9 +633,8 @@ + * Weird, but true. + */ + +- if ((type == MTH_TYPE_ARG) && +- (VALID_DESCRIPTOR_TYPE (*entry, ACPI_DESC_TYPE_NAMED))) +- { ++ if ((opcode == AML_ARG_OP) && ++ (VALID_DESCRIPTOR_TYPE (*entry, ACPI_DESC_TYPE_NAMED))) { + /* Detach an existing object from the Node */ + + acpi_ns_detach_object ((ACPI_NAMESPACE_NODE *) *entry); +@@ -655,6 +649,7 @@ + } + + ++#ifdef ACPI_ENABLE_IMPLICIT_CONVERSION + /* + * Perform "Implicit conversion" of the new object to the type of the + * existing object +@@ -663,12 +658,13 @@ + if (ACPI_FAILURE (status)) { + goto cleanup; + } ++#endif + + /* + * Delete the existing object + * before storing the new one + */ +- acpi_ds_method_data_delete_value (type, index, walk_state); ++ acpi_ds_method_data_delete_value (opcode, index, walk_state); + } + + +@@ -678,7 +674,7 @@ + * Install the new object in the stack entry + * (increments the object reference count by one) + */ +- status = acpi_ds_method_data_set_entry (type, index, src_desc, walk_state); ++ status = acpi_ds_method_data_set_entry (opcode, index, src_desc, walk_state); + if (ACPI_FAILURE (status)) { + goto cleanup; + } +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/dispatcher/dsobject.c linux/drivers/acpi/dispatcher/dsobject.c +--- /usr/src/linux/drivers/acpi/dispatcher/dsobject.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/dispatcher/dsobject.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: dsobject - Dispatcher object management routines +- * $Revision: 57 $ ++ * $Revision: 60 $ + * + *****************************************************************************/ + +@@ -31,7 +31,7 @@ + #include "acinterp.h" + #include "acnamesp.h" + +-#define _COMPONENT DISPATCHER ++#define _COMPONENT ACPI_DISPATCHER + MODULE_NAME ("dsobject") + + +@@ -77,8 +77,7 @@ + */ + + if (((ACPI_NAMESPACE_NODE *) obj_handle)->owner_id != +- info->table_desc->table_id) +- { ++ info->table_desc->table_id) { + return (AE_OK); + } + +@@ -87,8 +86,7 @@ + + type = acpi_ns_get_type (obj_handle); + +- switch (type) +- { ++ switch (type) { + + case ACPI_TYPE_REGION: + +@@ -174,9 +172,8 @@ + + /* Walk entire namespace from the supplied root */ + +- status = acpi_walk_namespace (ACPI_TYPE_ANY, start_node, +- ACPI_UINT32_MAX, acpi_ds_init_one_object, +- &info, NULL); ++ status = acpi_walk_namespace (ACPI_TYPE_ANY, start_node, ACPI_UINT32_MAX, ++ acpi_ds_init_one_object, &info, NULL); + + return (AE_OK); + } +@@ -222,8 +219,7 @@ + + /* Get and prepare the first argument */ + +- switch ((*obj_desc)->common.type) +- { ++ switch ((*obj_desc)->common.type) { + case ACPI_TYPE_BUFFER: + + /* First arg is a number */ +@@ -322,13 +318,12 @@ + + case INTERNAL_TYPE_REFERENCE: + +- switch (ACPI_GET_OP_CLASS (op_info)) +- { ++ switch (ACPI_GET_OP_CLASS (op_info)) { + case OPTYPE_LOCAL_VARIABLE: + + /* Split the opcode into a base opcode + offset */ + +- (*obj_desc)->reference.op_code = AML_LOCAL_OP; ++ (*obj_desc)->reference.opcode = AML_LOCAL_OP; + (*obj_desc)->reference.offset = opcode - AML_LOCAL_OP; + break; + +@@ -336,7 +331,7 @@ + + /* Split the opcode into a base opcode + offset */ + +- (*obj_desc)->reference.op_code = AML_ARG_OP; ++ (*obj_desc)->reference.opcode = AML_ARG_OP; + (*obj_desc)->reference.offset = opcode - AML_ARG_OP; + break; + +@@ -348,7 +343,7 @@ + (*obj_desc)->reference.node = op->node; + } + +- (*obj_desc)->reference.op_code = opcode; ++ (*obj_desc)->reference.opcode = opcode; + break; + } + +@@ -449,9 +444,7 @@ + return (AE_NO_MEMORY); + } + +- status = acpi_ds_init_object_from_op (walk_state, op, +- op->opcode, &obj_desc); +- ++ status = acpi_ds_init_object_from_op (walk_state, op, op->opcode, &obj_desc); + if (ACPI_FAILURE (status)) { + acpi_cm_remove_reference (obj_desc); + return (status); +@@ -505,14 +498,9 @@ + */ + + obj_desc->package.elements = +- acpi_cm_callocate ((obj_desc->package.count + 1) * +- sizeof (void *)); ++ acpi_cm_callocate ((obj_desc->package.count + 1) * sizeof (void *)); + + if (!obj_desc->package.elements) { +- /* Package vector allocation failure */ +- +- REPORT_ERROR (("Ds_build_internal_package_obj: Package vector allocation failure\n")); +- + acpi_cm_delete_object_desc (obj_desc); + return (AE_NO_MEMORY); + } +@@ -568,13 +556,11 @@ + + + if (op->opcode == AML_PACKAGE_OP) { +- status = acpi_ds_build_internal_package_obj (walk_state, op, +- obj_desc_ptr); ++ status = acpi_ds_build_internal_package_obj (walk_state, op, obj_desc_ptr); + } + + else { +- status = acpi_ds_build_internal_simple_obj (walk_state, op, +- obj_desc_ptr); ++ status = acpi_ds_build_internal_simple_obj (walk_state, op, obj_desc_ptr); + } + + return (status); +@@ -613,8 +599,7 @@ + + /* Build an internal object for the argument(s) */ + +- status = acpi_ds_build_internal_object (walk_state, +- op->value.arg, &obj_desc); ++ status = acpi_ds_build_internal_object (walk_state, op->value.arg, &obj_desc); + if (ACPI_FAILURE (status)) { + return (status); + } +@@ -626,8 +611,7 @@ + + /* Init obj */ + +- status = acpi_ns_attach_object ((ACPI_HANDLE) node, obj_desc, +- (u8) node->type); ++ status = acpi_ns_attach_object (node, obj_desc, (u8) node->type); + if (ACPI_FAILURE (status)) { + goto cleanup; + } +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/dispatcher/dsopcode.c linux/drivers/acpi/dispatcher/dsopcode.c +--- /usr/src/linux/drivers/acpi/dispatcher/dsopcode.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/dispatcher/dsopcode.c Fri Apr 13 11:57:11 2001 +@@ -2,7 +2,7 @@ + * + * Module Name: dsopcode - Dispatcher Op Region support and handling of + * "control" opcodes +- * $Revision: 32 $ ++ * $Revision: 41 $ + * + *****************************************************************************/ + +@@ -34,25 +34,25 @@ + #include "acevents.h" + #include "actables.h" + +-#define _COMPONENT DISPATCHER ++#define _COMPONENT ACPI_DISPATCHER + MODULE_NAME ("dsopcode") + + + /***************************************************************************** + * +- * FUNCTION: Acpi_ds_get_field_unit_arguments ++ * FUNCTION: Acpi_ds_get_buffer_field_arguments + * +- * PARAMETERS: Obj_desc - A valid Field_unit object ++ * PARAMETERS: Obj_desc - A valid Buffer_field object + * + * RETURN: Status. + * +- * DESCRIPTION: Get Field_unit Buffer and Index. This implements the late ++ * DESCRIPTION: Get Buffer_field Buffer and Index. This implements the late + * evaluation of these field attributes. + * + ****************************************************************************/ + + ACPI_STATUS +-acpi_ds_get_field_unit_arguments ( ++acpi_ds_get_buffer_field_arguments ( + ACPI_OPERAND_OBJECT *obj_desc) + { + ACPI_OPERAND_OBJECT *extra_desc; +@@ -68,10 +68,10 @@ + } + + +- /* Get the AML pointer (method object) and Field_unit node */ ++ /* Get the AML pointer (method object) and Buffer_field node */ + +- extra_desc = obj_desc->field_unit.extra; +- node = obj_desc->field_unit.node; ++ extra_desc = obj_desc->buffer_field.extra; ++ node = obj_desc->buffer_field.node; + + /* + * Allocate a new parser op to be the root of the parsed +@@ -94,7 +94,7 @@ + return (status); + } + +- /* Pass1: Parse the entire Field_unit declaration */ ++ /* Pass1: Parse the entire Buffer_field declaration */ + + status = acpi_ps_parse_aml (op, extra_desc->extra.pcode, + extra_desc->extra.pcode_length, 0, +@@ -138,8 +138,8 @@ + * The pseudo-method object is no longer needed since the region is + * now initialized + */ +- acpi_cm_remove_reference (obj_desc->field_unit.extra); +- obj_desc->field_unit.extra = NULL; ++ acpi_cm_remove_reference (obj_desc->buffer_field.extra); ++ obj_desc->buffer_field.extra = NULL; + + return (status); + } +@@ -278,29 +278,45 @@ + + /***************************************************************************** + * +- * FUNCTION: Acpi_ds_eval_field_unit_operands ++ * FUNCTION: Acpi_ds_eval_buffer_field_operands + * +- * PARAMETERS: Op - A valid Field_unit Op object ++ * PARAMETERS: Op - A valid Buffer_field Op object + * + * RETURN: Status + * +- * DESCRIPTION: Get Field_unit Buffer and Index +- * Called from Acpi_ds_exec_end_op during Field_unit parse tree walk ++ * DESCRIPTION: Get Buffer_field Buffer and Index ++ * Called from Acpi_ds_exec_end_op during Buffer_field parse tree walk ++ * ++ * ACPI SPECIFICATION REFERENCES: ++ * Each of the Buffer Field opcodes is defined as specified in in-line ++ * comments below. For each one, use the following definitions. ++ * ++ * Def_bit_field := Bit_field_op Src_buf Bit_idx Destination ++ * Def_byte_field := Byte_field_op Src_buf Byte_idx Destination ++ * Def_create_field := Create_field_op Src_buf Bit_idx Num_bits Name_string ++ * Def_dWord_field := DWord_field_op Src_buf Byte_idx Destination ++ * Def_word_field := Word_field_op Src_buf Byte_idx Destination ++ * Bit_index := Term_arg=>Integer ++ * Byte_index := Term_arg=>Integer ++ * Destination := Name_string ++ * Num_bits := Term_arg=>Integer ++ * Source_buf := Term_arg=>Buffer + * + ****************************************************************************/ + + ACPI_STATUS +-acpi_ds_eval_field_unit_operands ( ++acpi_ds_eval_buffer_field_operands ( + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT *op) + { + ACPI_STATUS status; +- ACPI_OPERAND_OBJECT *field_desc; ++ ACPI_OPERAND_OBJECT *obj_desc; + ACPI_NAMESPACE_NODE *node; + ACPI_PARSE_OBJECT *next_op; + u32 offset; + u32 bit_offset; +- u16 bit_count; ++ u32 bit_count; ++ u8 field_flags; + + + ACPI_OPERAND_OBJECT *res_desc = NULL; +@@ -311,12 +327,14 @@ + + + /* +- * This is where we evaluate the address and length fields of the Op_field_unit declaration ++ * This is where we evaluate the address and length fields of the ++ * Create_xxx_field declaration + */ + + node = op->node; + + /* Next_op points to the op that holds the Buffer */ ++ + next_op = op->value.arg; + + /* Acpi_evaluate/create the address and length operands */ +@@ -326,8 +344,8 @@ + return (status); + } + +- field_desc = acpi_ns_get_attached_object (node); +- if (!field_desc) { ++ obj_desc = acpi_ns_get_attached_object (node); ++ if (!obj_desc) { + return (AE_NOT_EXIST); + } + +@@ -372,61 +390,77 @@ + * Setup the Bit offsets and counts, according to the opcode + */ + +- switch (op->opcode) +- { ++ switch (op->opcode) { ++ ++ /* Def_create_field */ ++ ++ case AML_CREATE_FIELD_OP: ++ ++ /* Offset is in bits, count is in bits */ ++ ++ bit_offset = offset; ++ bit_count = (u32) cnt_desc->integer.value; ++ field_flags = ACCESS_BYTE_ACC; ++ break; ++ + + /* Def_create_bit_field */ + +- case AML_BIT_FIELD_OP: ++ case AML_CREATE_BIT_FIELD_OP: + +- /* Offset is in bits, Field is a bit */ ++ /* Offset is in bits, Field is one bit */ + +- bit_offset = offset; +- bit_count = 1; ++ bit_offset = offset; ++ bit_count = 1; ++ field_flags = ACCESS_BYTE_ACC; + break; + + + /* Def_create_byte_field */ + +- case AML_BYTE_FIELD_OP: ++ case AML_CREATE_BYTE_FIELD_OP: + +- /* Offset is in bytes, field is a byte */ ++ /* Offset is in bytes, field is one byte */ + +- bit_offset = 8 * offset; +- bit_count = 8; ++ bit_offset = 8 * offset; ++ bit_count = 8; ++ field_flags = ACCESS_BYTE_ACC; + break; + + + /* Def_create_word_field */ + +- case AML_WORD_FIELD_OP: ++ case AML_CREATE_WORD_FIELD_OP: + +- /* Offset is in bytes, field is a word */ ++ /* Offset is in bytes, field is one word */ + +- bit_offset = 8 * offset; +- bit_count = 16; ++ bit_offset = 8 * offset; ++ bit_count = 16; ++ field_flags = ACCESS_WORD_ACC; + break; + + + /* Def_create_dWord_field */ + +- case AML_DWORD_FIELD_OP: ++ case AML_CREATE_DWORD_FIELD_OP: + +- /* Offset is in bytes, field is a dword */ ++ /* Offset is in bytes, field is one dword */ + +- bit_offset = 8 * offset; +- bit_count = 32; ++ bit_offset = 8 * offset; ++ bit_count = 32; ++ field_flags = ACCESS_DWORD_ACC; + break; + + +- /* Def_create_field */ ++ /* Def_create_qWord_field */ + +- case AML_CREATE_FIELD_OP: ++ case AML_CREATE_QWORD_FIELD_OP: + +- /* Offset is in bits, count is in bits */ ++ /* Offset is in bytes, field is one qword */ + +- bit_offset = offset; +- bit_count = (u16) cnt_desc->integer.value; ++ bit_offset = 8 * offset; ++ bit_count = 64; ++ field_flags = ACCESS_QWORD_ACC; + break; + + +@@ -441,35 +475,35 @@ + * Setup field according to the object type + */ + +- switch (src_desc->common.type) +- { ++ switch (src_desc->common.type) { + + /* Source_buff := Term_arg=>Buffer */ + + case ACPI_TYPE_BUFFER: + +- if (bit_offset + (u32) bit_count > +- (8 * (u32) src_desc->buffer.length)) +- { ++ if ((bit_offset + bit_count) > ++ (8 * (u32) src_desc->buffer.length)) { + status = AE_AML_BUFFER_LIMIT; + goto cleanup; + } + + +- /* Construct the remainder of the field object */ ++ /* ++ * Initialize areas of the field object that are common to all fields ++ * For Field_flags, use LOCK_RULE = 0 (NO_LOCK), UPDATE_RULE = 0 (UPDATE_PRESERVE) ++ */ ++ status = acpi_aml_prep_common_field_object (obj_desc, field_flags, ++ bit_offset, bit_count); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } + +- field_desc->field_unit.access = (u8) ACCESS_ANY_ACC; +- field_desc->field_unit.lock_rule = (u8) GLOCK_NEVER_LOCK; +- field_desc->field_unit.update_rule = (u8) UPDATE_PRESERVE; +- field_desc->field_unit.length = bit_count; +- field_desc->field_unit.bit_offset = (u8) (bit_offset % 8); +- field_desc->field_unit.offset = DIV_8 (bit_offset); +- field_desc->field_unit.container = src_desc; ++ obj_desc->buffer_field.buffer_obj = src_desc; + +- /* Reference count for Src_desc inherits Field_desc count */ ++ /* Reference count for Src_desc inherits Obj_desc count */ + + src_desc->common.reference_count = (u16) (src_desc->common.reference_count + +- field_desc->common.reference_count); ++ obj_desc->common.reference_count); + + break; + +@@ -478,8 +512,6 @@ + + default: + +- if ((src_desc->common.type > (u8) INTERNAL_TYPE_REFERENCE) || +- !acpi_cm_valid_object_type (src_desc->common.type)) + + + status = AE_AML_OPERAND_TYPE; +@@ -513,9 +545,9 @@ + } + + else { +- /* Now the address and length are valid for this op_field_unit */ ++ /* Now the address and length are valid for this Buffer_field */ + +- field_desc->field_unit.flags |= AOPOBJ_DATA_VALID; ++ obj_desc->buffer_field.flags |= AOPOBJ_DATA_VALID; + } + + return (status); +@@ -629,8 +661,7 @@ + ACPI_GENERIC_STATE *control_state; + + +- switch (op->opcode) +- { ++ switch (op->opcode) { + case AML_IF_OP: + case AML_WHILE_OP: + +@@ -708,8 +739,7 @@ + ACPI_GENERIC_STATE *control_state; + + +- switch (op->opcode) +- { ++ switch (op->opcode) { + case AML_IF_OP: + + /* +@@ -779,7 +809,6 @@ + * an arg or local), resolve it now because it may + * cease to exist at the end of the method. + */ +- + status = acpi_aml_resolve_to_value (&walk_state->operands [0], walk_state); + if (ACPI_FAILURE (status)) { + return (status); +@@ -795,19 +824,24 @@ + } + + else if ((walk_state->results) && +- (walk_state->results->results.num_results > 0)) +- { ++ (walk_state->results->results.num_results > 0)) { + /* + * The return value has come from a previous calculation. + * + * If value being returned is a Reference (such as + * an arg or local), resolve it now because it may + * cease to exist at the end of the method. ++ * ++ * Allow references created by the Index operator to return unchanged. + */ + +- status = acpi_aml_resolve_to_value (&walk_state->results->results.obj_desc [0], walk_state); +- if (ACPI_FAILURE (status)) { +- return (status); ++ if (VALID_DESCRIPTOR_TYPE (walk_state->results->results.obj_desc [0], ACPI_DESC_TYPE_INTERNAL) && ++ ((walk_state->results->results.obj_desc [0])->common.type == INTERNAL_TYPE_REFERENCE) && ++ ((walk_state->results->results.obj_desc [0])->reference.opcode != AML_INDEX_OP)) { ++ status = acpi_aml_resolve_to_value (&walk_state->results->results.obj_desc [0], walk_state); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } + } + + walk_state->return_desc = walk_state->results->results.obj_desc [0]; +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/dispatcher/dsutils.c linux/drivers/acpi/dispatcher/dsutils.c +--- /usr/src/linux/drivers/acpi/dispatcher/dsutils.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/dispatcher/dsutils.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /******************************************************************************* + * + * Module Name: dsutils - Dispatcher utilities +- * $Revision: 52 $ ++ * $Revision: 54 $ + * + ******************************************************************************/ + +@@ -32,7 +32,7 @@ + #include "acnamesp.h" + #include "acdebug.h" + +-#define _COMPONENT PARSER ++#define _COMPONENT ACPI_DISPATCHER + MODULE_NAME ("dsutils") + + +@@ -93,15 +93,13 @@ + * as an operand later. + */ + +- switch (ACPI_GET_OP_CLASS (parent_info)) +- { ++ switch (ACPI_GET_OP_CLASS (parent_info)) { + /* + * In these cases, the parent will never use the return object + */ + case OPTYPE_CONTROL: /* IF, ELSE, WHILE only */ + +- switch (op->parent->opcode) +- { ++ switch (op->parent->opcode) { + case AML_RETURN_OP: + + /* Never delete the return value associated with a return opcode */ +@@ -118,8 +116,7 @@ + */ + + if ((walk_state->control_state->common.state == CONTROL_PREDICATE_EXECUTING) && +- (walk_state->control_state->control.predicate_op == op)) +- { ++ (walk_state->control_state->control.predicate_op == op)) { + return (TRUE); + } + +@@ -136,14 +133,13 @@ + * These opcodes allow Term_arg(s) as operands and therefore + * method calls. The result is used. + */ +- if ((op->parent->opcode == AML_REGION_OP) || +- (op->parent->opcode == AML_CREATE_FIELD_OP) || +- (op->parent->opcode == AML_BIT_FIELD_OP) || +- (op->parent->opcode == AML_BYTE_FIELD_OP) || +- (op->parent->opcode == AML_WORD_FIELD_OP) || +- (op->parent->opcode == AML_DWORD_FIELD_OP) || +- (op->parent->opcode == AML_QWORD_FIELD_OP)) +- { ++ if ((op->parent->opcode == AML_REGION_OP) || ++ (op->parent->opcode == AML_CREATE_FIELD_OP) || ++ (op->parent->opcode == AML_CREATE_BIT_FIELD_OP) || ++ (op->parent->opcode == AML_CREATE_BYTE_FIELD_OP) || ++ (op->parent->opcode == AML_CREATE_WORD_FIELD_OP) || ++ (op->parent->opcode == AML_CREATE_DWORD_FIELD_OP) || ++ (op->parent->opcode == AML_CREATE_QWORD_FIELD_OP)) { + return (TRUE); + } + +@@ -250,8 +246,7 @@ + /* A valid name must be looked up in the namespace */ + + if ((arg->opcode == AML_NAMEPATH_OP) && +- (arg->value.string)) +- { ++ (arg->value.string)) { + /* Get the entire name string from the AML stream */ + + status = acpi_aml_get_name_string (ACPI_TYPE_ANY, +@@ -279,8 +274,7 @@ + if ((acpi_ps_is_node_op (parent_op->opcode)) && + (parent_op->opcode != AML_METHODCALL_OP) && + (parent_op->opcode != AML_REGION_OP) && +- (parent_op->opcode != AML_NAMEPATH_OP)) +- { ++ (parent_op->opcode != AML_NAMEPATH_OP)) { + /* Enter name into namespace if not found */ + + interpreter_mode = IMODE_LOAD_PASS2; +@@ -555,13 +549,11 @@ + return (data_type); + } + +- switch (ACPI_GET_OP_CLASS (op_info)) +- { ++ switch (ACPI_GET_OP_CLASS (op_info)) { + + case OPTYPE_LITERAL: + +- switch (opcode) +- { ++ switch (opcode) { + case AML_BYTE_OP: + case AML_WORD_OP: + case AML_DWORD_OP: +@@ -587,8 +579,7 @@ + + case OPTYPE_DATA_TERM: + +- switch (opcode) +- { ++ switch (opcode) { + case AML_BUFFER_OP: + + data_type = ACPI_TYPE_BUFFER; +@@ -684,8 +675,7 @@ + + /* Decode Opcode */ + +- switch (opcode) +- { ++ switch (opcode) { + case AML_SCOPE_OP: + data_type = INTERNAL_TYPE_SCOPE; + break; +@@ -710,8 +700,8 @@ + data_type = ACPI_TYPE_PROCESSOR; + break; + +- case AML_DEF_FIELD_OP: /* Def_field_op */ +- data_type = INTERNAL_TYPE_DEF_FIELD_DEFN; ++ case AML_FIELD_OP: /* Field_op */ ++ data_type = INTERNAL_TYPE_FIELD_DEFN; + break; + + case AML_INDEX_FIELD_OP: /* Index_field_op */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/dispatcher/dswexec.c linux/drivers/acpi/dispatcher/dswexec.c +--- /usr/src/linux/drivers/acpi/dispatcher/dswexec.c Mon Jan 29 10:15:58 2001 ++++ linux/drivers/acpi/dispatcher/dswexec.c Fri Apr 13 11:57:11 2001 +@@ -2,7 +2,7 @@ + * + * Module Name: dswexec - Dispatcher method execution callbacks; + * dispatch to interpreter. +- * $Revision: 55 $ ++ * $Revision: 58 $ + * + *****************************************************************************/ + +@@ -34,7 +34,7 @@ + #include "acdebug.h" + + +-#define _COMPONENT DISPATCHER ++#define _COMPONENT ACPI_DISPATCHER + MODULE_NAME ("dswexec") + + +@@ -194,8 +194,7 @@ + + if ((walk_state->control_state) && + (walk_state->control_state->common.state == +- CONTROL_CONDITIONAL_EXECUTING)) +- { ++ CONTROL_CONDITIONAL_EXECUTING)) { + walk_state->control_state->common.state = CONTROL_PREDICATE_EXECUTING; + + /* Save start of predicate */ +@@ -217,8 +216,7 @@ + * Handle the opcode based upon the opcode type + */ + +- switch (ACPI_GET_OP_CLASS (op_info)) +- { ++ switch (ACPI_GET_OP_CLASS (op_info)) { + case OPTYPE_CONTROL: + + status = acpi_ds_result_stack_push (walk_state); +@@ -308,11 +306,9 @@ + u16 opcode; + u8 optype; + ACPI_PARSE_OBJECT *next_op; +- ACPI_NAMESPACE_NODE *node; + ACPI_PARSE_OBJECT *first_arg; + ACPI_OPERAND_OBJECT *result_obj = NULL; + ACPI_OPCODE_INFO *op_info; +- u32 operand_index; + + + opcode = (u16) op->opcode; +@@ -342,8 +338,7 @@ + + /* Decode the opcode */ + +- switch (optype) +- { ++ switch (optype) { + case OPTYPE_UNDEFINED: + + return (AE_NOT_IMPLEMENTED); +@@ -383,9 +378,6 @@ + goto cleanup; + } + +- operand_index = walk_state->num_operands - 1; +- +- + /* Done with this result state (Now that operand stack is built) */ + + status = acpi_ds_result_stack_pop (walk_state); +@@ -393,8 +385,7 @@ + goto cleanup; + } + +- switch (optype) +- { ++ switch (optype) { + case OPTYPE_MONADIC1: + + /* 1 Operand, 0 External_result, 0 Internal_result */ +@@ -488,8 +479,7 @@ + * current result stack + */ + if (ACPI_SUCCESS (status) && +- result_obj) +- { ++ result_obj) { + status = acpi_ds_result_push (result_obj, walk_state); + } + +@@ -515,7 +505,6 @@ + /* Next_op points to the op that holds the method name */ + + next_op = first_arg; +- node = next_op->node; + + /* Next_op points to first argument op */ + +@@ -562,7 +551,7 @@ + break; + } + +- status = acpi_ds_eval_field_unit_operands (walk_state, op); ++ status = acpi_ds_eval_buffer_field_operands (walk_state, op); + break; + + +@@ -573,8 +562,7 @@ + break; + } + +- switch (op->opcode) +- { ++ switch (op->opcode) { + case AML_REGION_OP: + + status = acpi_ds_eval_region_operands (walk_state, op); +@@ -627,8 +615,7 @@ + if ((walk_state->control_state) && + (walk_state->control_state->common.state == + CONTROL_PREDICATE_EXECUTING) && +- (walk_state->control_state->control.predicate_op == op)) +- { ++ (walk_state->control_state->control.predicate_op == op)) { + status = acpi_ds_get_predicate_value (walk_state, op, (u32) result_obj); + result_obj = NULL; + } +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/dispatcher/dswload.c linux/drivers/acpi/dispatcher/dswload.c +--- /usr/src/linux/drivers/acpi/dispatcher/dswload.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/dispatcher/dswload.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: dswload - Dispatcher namespace load callbacks +- * $Revision: 26 $ ++ * $Revision: 32 $ + * + *****************************************************************************/ + +@@ -33,11 +33,11 @@ + #include "acevents.h" + + +-#define _COMPONENT DISPATCHER ++#define _COMPONENT ACPI_DISPATCHER + MODULE_NAME ("dswload") + + +-/***************************************************************************** ++/******************************************************************************* + * + * FUNCTION: Acpi_ds_load1_begin_op + * +@@ -49,7 +49,7 @@ + * + * DESCRIPTION: Descending callback used during the loading of ACPI tables. + * +- ****************************************************************************/ ++ ******************************************************************************/ + + ACPI_STATUS + acpi_ds_load1_begin_op ( +@@ -128,7 +128,7 @@ + } + + +-/***************************************************************************** ++/******************************************************************************* + * + * FUNCTION: Acpi_ds_load1_end_op + * +@@ -141,7 +141,7 @@ + * DESCRIPTION: Ascending callback used during the loading of the namespace, + * both control methods and everything else. + * +- ****************************************************************************/ ++ ******************************************************************************/ + + ACPI_STATUS + acpi_ds_load1_end_op ( +@@ -186,7 +186,7 @@ + } + + +-/***************************************************************************** ++/******************************************************************************* + * + * FUNCTION: Acpi_ds_load2_begin_op + * +@@ -198,7 +198,7 @@ + * + * DESCRIPTION: Descending callback used during the loading of ACPI tables. + * +- ****************************************************************************/ ++ ******************************************************************************/ + + ACPI_STATUS + acpi_ds_load2_begin_op ( +@@ -217,8 +217,7 @@ + /* We only care about Namespace opcodes here */ + + if (!acpi_ps_is_namespace_op (opcode) && +- opcode != AML_NAMEPATH_OP) +- { ++ opcode != AML_NAMEPATH_OP) { + return (AE_OK); + } + +@@ -261,10 +260,9 @@ + data_type = acpi_ds_map_named_opcode_to_data_type (opcode); + + +- if (opcode == AML_DEF_FIELD_OP || ++ if (opcode == AML_FIELD_OP || + opcode == AML_BANK_FIELD_OP || +- opcode == AML_INDEX_FIELD_OP) +- { ++ opcode == AML_INDEX_FIELD_OP) { + node = NULL; + status = AE_OK; + } +@@ -337,7 +335,7 @@ + } + + +-/***************************************************************************** ++/******************************************************************************* + * + * FUNCTION: Acpi_ds_load2_end_op + * +@@ -350,7 +348,7 @@ + * DESCRIPTION: Ascending callback used during the loading of the namespace, + * both control methods and everything else. + * +- ****************************************************************************/ ++ ******************************************************************************/ + + ACPI_STATUS + acpi_ds_load2_end_op ( +@@ -422,6 +420,7 @@ + * AML_CREATEBYTEFIELD + * AML_CREATEWORDFIELD + * AML_CREATEDWORDFIELD ++ * AML_CREATEQWORDFIELD + * AML_METHODCALL + */ + +@@ -430,14 +429,14 @@ + + arg = op->value.arg; + +- switch (op->opcode) +- { ++ switch (op->opcode) { + + case AML_CREATE_FIELD_OP: +- case AML_BIT_FIELD_OP: +- case AML_BYTE_FIELD_OP: +- case AML_WORD_FIELD_OP: +- case AML_DWORD_FIELD_OP: ++ case AML_CREATE_BIT_FIELD_OP: ++ case AML_CREATE_BYTE_FIELD_OP: ++ case AML_CREATE_WORD_FIELD_OP: ++ case AML_CREATE_DWORD_FIELD_OP: ++ case AML_CREATE_QWORD_FIELD_OP: + + /* + * Create the field object, but the field buffer and index must +@@ -455,41 +454,42 @@ + arg = acpi_ps_get_arg (op, 2); + } + ++ if (!arg) { ++ status = AE_AML_NO_OPERAND; ++ goto cleanup; ++ } ++ + /* + * Enter the Name_string into the namespace + */ +- +- status = acpi_ns_lookup (walk_state->scope_info, +- arg->value.string, +- INTERNAL_TYPE_DEF_ANY, +- IMODE_LOAD_PASS1, ++ status = acpi_ns_lookup (walk_state->scope_info, arg->value.string, ++ INTERNAL_TYPE_DEF_ANY, IMODE_LOAD_PASS1, + NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, + walk_state, &(new_node)); ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } + +- if (ACPI_SUCCESS (status)) { +- /* We could put the returned object (Node) on the object stack for later, but +- * for now, we will put it in the "op" object that the parser uses, so we +- * can get it again at the end of this scope +- */ +- op->node = new_node; ++ /* We could put the returned object (Node) on the object stack for later, but ++ * for now, we will put it in the "op" object that the parser uses, so we ++ * can get it again at the end of this scope ++ */ ++ op->node = new_node; + ++ /* ++ * If there is no object attached to the node, this node was just created and ++ * we need to create the field object. Otherwise, this was a lookup of an ++ * existing node and we don't want to create the field object again. ++ */ ++ if (!new_node->object) { + /* +- * If there is no object attached to the node, this node was just created and +- * we need to create the field object. Otherwise, this was a lookup of an +- * existing node and we don't want to create the field object again. ++ * The Field definition is not fully parsed at this time. ++ * (We must save the address of the AML for the buffer and index operands) + */ +- if (!new_node->object) { +- /* +- * The Field definition is not fully parsed at this time. +- * (We must save the address of the AML for the buffer and index operands) +- */ +- status = acpi_aml_exec_create_field (((ACPI_PARSE2_OBJECT *) op)->data, +- ((ACPI_PARSE2_OBJECT *) op)->length, +- new_node, walk_state); +- } ++ status = acpi_aml_create_buffer_field (((ACPI_PARSE2_OBJECT *) op)->data, ++ ((ACPI_PARSE2_OBJECT *) op)->length, ++ new_node, walk_state); + } +- +- + break; + + +@@ -506,7 +506,7 @@ + + if (ACPI_SUCCESS (status)) { + +-/* has name already been resolved by here ??*/ ++ /* TBD: has name already been resolved by here ??*/ + + /* TBD: [Restructure] Make sure that what we found is indeed a method! */ + /* We didn't search for a method on purpose, to see if the name would resolve! */ +@@ -526,7 +526,7 @@ + + /* Nothing to do other than enter object into namespace */ + +- status = acpi_aml_exec_create_processor (op, (ACPI_HANDLE) node); ++ status = acpi_aml_exec_create_processor (op, node); + if (ACPI_FAILURE (status)) { + goto cleanup; + } +@@ -538,7 +538,7 @@ + + /* Nothing to do other than enter object into namespace */ + +- status = acpi_aml_exec_create_power_resource (op, (ACPI_HANDLE) node); ++ status = acpi_aml_exec_create_power_resource (op, node); + if (ACPI_FAILURE (status)) { + goto cleanup; + } +@@ -553,13 +553,11 @@ + break; + + +- case AML_DEF_FIELD_OP: ++ case AML_FIELD_OP: + + arg = op->value.arg; + +- status = acpi_ds_create_field (op, +- arg->node, +- walk_state); ++ status = acpi_ds_create_field (op, arg->node, walk_state); + break; + + +@@ -567,8 +565,7 @@ + + arg = op->value.arg; + +- status = acpi_ds_create_index_field (op, +- (ACPI_HANDLE) arg->node, ++ status = acpi_ds_create_index_field (op, (ACPI_HANDLE) arg->node, + walk_state); + break; + +@@ -576,9 +573,7 @@ + case AML_BANK_FIELD_OP: + + arg = op->value.arg; +- status = acpi_ds_create_bank_field (op, +- arg->node, +- walk_state); ++ status = acpi_ds_create_bank_field (op, arg->node, walk_state); + break; + + +@@ -590,7 +585,7 @@ + if (!node->object) { + status = acpi_aml_exec_create_method (((ACPI_PARSE2_OBJECT *) op)->data, + ((ACPI_PARSE2_OBJECT *) op)->length, +- arg->value.integer, (ACPI_HANDLE) node); ++ arg->value.integer, node); + } + + break; +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/dispatcher/dswscope.c linux/drivers/acpi/dispatcher/dswscope.c +--- /usr/src/linux/drivers/acpi/dispatcher/dswscope.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/dispatcher/dswscope.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: dswscope - Scope stack manipulation +- * $Revision: 42 $ ++ * $Revision: 43 $ + * + *****************************************************************************/ + +@@ -29,7 +29,7 @@ + #include "acdispat.h" + + +-#define _COMPONENT NAMESPACE ++#define _COMPONENT ACPI_DISPATCHER + MODULE_NAME ("dswscope") + + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/dispatcher/dswstate.c linux/drivers/acpi/dispatcher/dswstate.c +--- /usr/src/linux/drivers/acpi/dispatcher/dswstate.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/dispatcher/dswstate.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: dswstate - Dispatcher parse tree walk management routines +- * $Revision: 38 $ ++ * $Revision: 42 $ + * + *****************************************************************************/ + +@@ -31,7 +31,7 @@ + #include "acnamesp.h" + #include "acinterp.h" + +-#define _COMPONENT DISPATCHER ++#define _COMPONENT ACPI_DISPATCHER + MODULE_NAME ("dswstate") + + +@@ -730,6 +730,7 @@ + walk_state->owner_id = owner_id; + walk_state->origin = origin; + walk_state->method_desc = mth_desc; ++ walk_state->walk_list = walk_list; + + /* Init the method args/local */ + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/driver.c linux/drivers/acpi/driver.c +--- /usr/src/linux/drivers/acpi/driver.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/driver.c Fri Apr 13 11:57:11 2001 +@@ -2,6 +2,7 @@ + * driver.c - ACPI driver + * + * Copyright (C) 2000 Andrew Henroid ++ * Copyright (C) 2001 Andrew Grover + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -21,6 +22,8 @@ + * Changes + * David Woodhouse <dwmw2@redhat.com> 2000-12-6 + * - Fix interruptible_sleep_on() races ++ * Andrew Grover <andrew.grover@intel.com> 2001-2-28 ++ * - Major revamping + */ + + #include <linux/config.h> +@@ -46,143 +49,15 @@ + #define _COMPONENT OS_DEPENDENT + MODULE_NAME ("driver") + +-struct acpi_run_entry +-{ +- void (*callback)(void*); +- void *context; +- struct tq_struct task; +-}; + + static spinlock_t acpi_event_lock = SPIN_LOCK_UNLOCKED; + static volatile u32 acpi_event_status = 0; + static volatile acpi_sstate_t acpi_event_state = ACPI_STATE_S0; + static DECLARE_WAIT_QUEUE_HEAD(acpi_event_wait); + +-static volatile int acpi_thread_pid = -1; +- +-static int acpi_start = 1; +- +-/************************************************/ +-/* DECLARE_TASK_QUEUE is defined in */ +-/* /usr/src/linux/include/linux/tqueue.h */ +-/* So, acpi_thread_run is a pointer to a */ +-/* tq_struct structure,defined in the same file.*/ +-/************************************************/ +-static DECLARE_TASK_QUEUE(acpi_thread_run); +- +-static DECLARE_WAIT_QUEUE_HEAD(acpi_thread_wait); +- + static struct ctl_table_header *acpi_sysctl = NULL; + +-/* +- * Examine/modify value +- */ +-static int +-acpi_do_ulong(ctl_table * ctl, +- int write, +- struct file *file, +- void *buffer, +- size_t * len) +-{ +- char str[2 * sizeof(unsigned long) + 4], *strend; +- unsigned long val; +- int size; +- +- if (!write) { +- if (file->f_pos) { +- *len = 0; +- return 0; +- } +- +- val = *(unsigned long *) ctl->data; +- size = sprintf(str, "0x%08lx\n", val); +- if (*len >= size) { +- copy_to_user(buffer, str, size); +- *len = size; +- } +- else +- *len = 0; +- } +- else { +- size = sizeof(str) - 1; +- if (size > *len) +- size = *len; +- copy_from_user(str, buffer, size); +- str[size] = '\0'; +- val = simple_strtoul(str, &strend, 0); +- if (strend == str) +- return -EINVAL; +- *(unsigned long *) ctl->data = val; +- } +- +- file->f_pos += *len; +- return 0; +-} +- +-static int +-acpi_do_pm_timer(ctl_table * ctl, +- int write, +- struct file *file, +- void *buffer, +- size_t * len) +-{ +- int size; +- u32 val = 0; +- +- char str[12]; +- +- if (file->f_pos) { +- *len = 0; +- return 0; +- } +- +- val = acpi_read_pm_timer(); +- +- size = sprintf(str, "0x%08x\n", val); +- if (*len >= size) { +- copy_to_user(buffer, str, size); +- *len = size; +- } +- else +- *len = 0; +- +- file->f_pos += *len; +- +- return 0; +-} +- +-/* +- * Handle ACPI event +- */ +-static u32 +-acpi_event(void *context) +-{ +- unsigned long flags; +- int event = (int)(long)context; +- int mask = 0; +- +- switch (event) { +- case ACPI_EVENT_POWER_BUTTON: +- mask = ACPI_PWRBTN; +- break; +- case ACPI_EVENT_SLEEP_BUTTON: +- mask = ACPI_SLPBTN; +- break; +- default: +- return AE_ERROR; +- } +- +- if (mask) { +- // notify process waiting on /dev/acpi +- spin_lock_irqsave(&acpi_event_lock, flags); +- acpi_event_status |= mask; +- spin_unlock_irqrestore(&acpi_event_lock, flags); +- acpi_event_state = acpi_sleep_state; +- wake_up_interruptible(&acpi_event_wait); +- } +- +- return AE_OK; +-} ++FADT_DESCRIPTOR acpi_fadt; + + /* + * Wait for next event +@@ -322,83 +197,14 @@ + return 0; + } + +-/********************************************************************/ +-/* R U N Q U E U E D C A L L B A C K */ +-/* */ +-/* The "callback" function address that was tramped through via */ +-/* "acpi_run" below is finally called and executed. If we trace all */ +-/* this down, the function is acpi_ev_asynch_execute_gpe_method, in */ +-/* evevent.c The only other function that is ever queued is */ +-/* acpi_ev_global_lock_thread in evmisc.c. */ +-/********************************************************************/ +-static void +-acpi_run_exec(void *context) +-{ +- struct acpi_run_entry *entry +- = (struct acpi_run_entry*) context; +- (*entry->callback)(entry->context); +- kfree(entry); +-} +- +-/* +- * Queue for execution by the ACPI thread +- */ +-int +-acpi_run(void (*callback)(void*), void *context) +-{ +- struct acpi_run_entry *entry; +- +- entry = kmalloc(sizeof(*entry), GFP_ATOMIC); +- if (!entry) +- return -1; +- +- memset(entry, 0, sizeof(entry)); +- entry->callback = callback; +- entry->context = context; +- entry->task.routine = acpi_run_exec; +- entry->task.data = entry; +- +- queue_task(&entry->task, &acpi_thread_run); +- +- if (waitqueue_active(&acpi_thread_wait)) +- wake_up(&acpi_thread_wait); +- +- return 0; +-} +- + static struct ctl_table acpi_table[] = + { +- {ACPI_P_LVL2_LAT, "c2_exit_latency", +- &acpi_c2_exit_latency, sizeof(acpi_c2_exit_latency), +- 0644, NULL, &acpi_do_ulong}, +- +- {ACPI_ENTER_LVL2_LAT, "c2_enter_latency", +- &acpi_c2_enter_latency, sizeof(acpi_c2_enter_latency), +- 0644, NULL, &acpi_do_ulong}, +- +- {ACPI_P_LVL3_LAT, "c3_exit_latency", +- &acpi_c3_exit_latency, sizeof(acpi_c3_exit_latency), +- 0644, NULL, &acpi_do_ulong}, +- +- {ACPI_ENTER_LVL3_LAT, "c3_enter_latency", +- &acpi_c3_enter_latency, sizeof(acpi_c3_enter_latency), +- 0644, NULL, &acpi_do_ulong}, +- +- {ACPI_C1_COUNT, "c1_count", +- &acpi_c1_count, sizeof(acpi_c1_count), +- 0644, NULL, &acpi_do_ulong}, +- +- {ACPI_C2_COUNT, "c2_count", +- &acpi_c2_count, sizeof(acpi_c2_count), +- 0644, NULL, &acpi_do_ulong}, +- +- {ACPI_C3_COUNT, "c3_count", +- &acpi_c3_count, sizeof(acpi_c3_count), +- 0644, NULL, &acpi_do_ulong}, + +- +-/* until it actually works */ +-/* {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &acpi_do_sleep},*/ ++ /* TODO reimplement C2/C3 latency values in processor driver */ ++ /* TODO re-expose pm_timer values */ ++ ++ /* until it actually works */ ++ /* {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &acpi_do_sleep},*/ + + {ACPI_EVENT, "event", NULL, 0, 0400, NULL, &acpi_do_event}, + +@@ -414,8 +220,6 @@ + {ACPI_XSDT, "xsdt", (void *) ACPI_TABLE_XSDT, sizeof(int), + 0444, NULL, &acpi_do_table}, + +- {ACPI_PMTIMER, "pm_timer", NULL, 0, 0444, NULL, &acpi_do_pm_timer}, +- + {0} + }; + +@@ -426,21 +230,15 @@ + }; + + /* +- * Initialize and run interpreter within a kernel thread ++ * Start the interpreter + */ +-static int +-acpi_thread(void *context) ++int ++acpi_init(void) + { + ACPI_PHYSICAL_ADDRESS rsdp_phys; + ACPI_BUFFER buffer; + ACPI_SYSTEM_INFO sys_info; + +- /* +- * initialize +- */ +- daemonize(); +- strcpy(current->comm, "kacpid"); +- + if (!ACPI_SUCCESS(acpi_initialize_subsystem())) { + printk(KERN_ERR "ACPI: Driver initialization failed\n"); + return -ENODEV; +@@ -454,9 +252,25 @@ + #else + rsdp_phys = efi.acpi; + #endif +- +- if (!ACPI_SUCCESS(acpi_find_and_load_tables(rsdp_phys))) ++ ++ /* from this point on, on error we must call acpi_terminate() */ ++ ++ if (!ACPI_SUCCESS(acpi_load_tables(rsdp_phys))) { ++ printk(KERN_ERR "ACPI: System description table load failed\n"); ++ acpi_terminate(); + return -ENODEV; ++ } ++ ++ /* get a separate copy of the FADT for use by other drivers */ ++ memset(&acpi_fadt, 0, sizeof(acpi_fadt)); ++ buffer.pointer = &acpi_fadt; ++ buffer.length = sizeof(acpi_fadt); ++ ++ if (!ACPI_SUCCESS(acpi_get_table(ACPI_TABLE_FADT, 1, &buffer))) { ++ printk(KERN_ERR "ACPI: Could not get FADT\n"); ++ acpi_terminate(); ++ return -ENODEV; ++ } + + if (PM_IS_ACTIVE()) { + printk(KERN_NOTICE "ACPI: APM is already active, exiting\n"); +@@ -481,132 +295,29 @@ + return -ENODEV; + } + +- printk(KERN_ERR "ACPI: Subsystem enabled\n"); ++ printk(KERN_INFO "ACPI: Subsystem enabled\n"); + + pm_active = 1; + +- acpi_cpu_init(); +- acpi_sys_init(); +- acpi_ec_init(); +- acpi_power_init(); +- +- /* +- * Non-intuitive: 0 means pwr and sleep are implemented using the fixed +- * feature model, so we install handlers. 1 means a control method +- * implementation, or none at all, so do nothing. See ACPI spec. +- */ +- if (acpi_fadt.pwr_button == 0) { +- if (!ACPI_SUCCESS(acpi_install_fixed_event_handler( +- ACPI_EVENT_POWER_BUTTON, +- acpi_event, +- (void *) ACPI_EVENT_POWER_BUTTON))) { +- printk(KERN_ERR "ACPI: power button enable failed\n"); +- } +- } +- +- if (acpi_fadt.sleep_button == 0) { +- if (!ACPI_SUCCESS(acpi_install_fixed_event_handler( +- ACPI_EVENT_SLEEP_BUTTON, +- acpi_event, +- (void *) ACPI_EVENT_SLEEP_BUTTON))) { +- printk(KERN_ERR "ACPI: sleep button enable failed\n"); +- } +- } +- + acpi_sysctl = register_sysctl_table(acpi_dir_table, 1); + +- /* +- * run +- */ +- for (;;) { +- DECLARE_WAITQUEUE(wait, current); +- +- set_current_state(TASK_INTERRUPTIBLE); +- add_wait_queue(&acpi_thread_wait, &wait); +- +- if (list_empty(&acpi_thread_run)) +- schedule(); +- +- remove_wait_queue(&acpi_thread_wait, &wait); +- set_current_state(TASK_RUNNING); +- +- if (signal_pending(current)) +- break; +- +- run_task_queue(&acpi_thread_run); +- } +- +- /* +- * terminate +- */ +- unregister_sysctl_table(acpi_sysctl); +- +- /* do not terminate, because we need acpi in order to shut down */ +- /*acpi_terminate();*/ +- +- acpi_thread_pid = -1; +- + return 0; + } + + /* +- * Start the interpreter +- */ +-int __init +-acpi_init(void) +-{ +- if (acpi_start) { +- acpi_thread_pid = kernel_thread(acpi_thread, +- NULL, +- (CLONE_FS | CLONE_FILES +- | CLONE_SIGHAND | SIGCHLD)); +- } +- else { +- printk(KERN_INFO "ACPI: Disabled\n"); +- } +- +- return ((acpi_thread_pid >= 0) ? 0:-ENODEV); +-} +- +-/* + * Terminate the interpreter + */ +-void __exit ++void + acpi_exit(void) + { +- int count; ++ unregister_sysctl_table(acpi_sysctl); + +- if (!kill_proc(acpi_thread_pid, SIGTERM, 1)) { +- // wait until thread terminates (at most 5 seconds) +- count = 5 * HZ; +- while (acpi_thread_pid >= 0 && --count) { +- current->state = TASK_INTERRUPTIBLE; +- schedule_timeout(1); +- } +- } ++ acpi_terminate(); + +- pm_idle = NULL; +- pm_power_off = NULL; + pm_active = 0; ++ ++ printk(KERN_ERR "ACPI: Subsystem disabled\n"); + } + + module_init(acpi_init); + module_exit(acpi_exit); +- +-#ifndef MODULE +-static int __init acpi_setup(char *str) +-{ +- while ((str != NULL) && (*str != '\0')) { +- if (strncmp(str, "no-idle", 7) == 0) +- acpi_use_idle = 0; +- if (strncmp(str, "off", 3) == 0) +- acpi_start = 0; +- str = strchr(str, ','); +- if (str != NULL) +- str += strspn(str, ", \t"); +- } +- return 1; +-} +- +-__setup("acpi=", acpi_setup); +-#endif +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/driver.h linux/drivers/acpi/driver.h +--- /usr/src/linux/drivers/acpi/driver.h Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/driver.h Fri Apr 13 11:57:11 2001 +@@ -69,11 +69,4 @@ + + extern volatile acpi_sstate_t acpi_sleep_state; + +-/* +- * table.c +- */ +-extern FADT_DESCRIPTOR acpi_fadt; +- +-int acpi_find_and_load_tables(u64 rsdp); +- + #endif /* __DRIVER_H */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ec.c linux/drivers/acpi/ec.c +--- /usr/src/linux/drivers/acpi/ec.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/ec.c Wed Dec 31 16:00:00 1969 +@@ -1,600 +0,0 @@ +-/* +- * ec.c - Embedded controller support +- * +- * Copyright (C) 2000 Andrew Henroid +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +-#include <linux/kernel.h> +-#include <linux/acpi.h> +-#include <linux/slab.h> +-#include "acpi.h" +-#include "driver.h" +-#include "ec.h" +- +-#define _COMPONENT OS_DEPENDENT +- MODULE_NAME ("ec") +- +-#define ACPI_EC_HID "PNP0C09" +- +-enum +-{ +- ACPI_EC_SMI = 0x40, +- ACPI_EC_SCI = 0x20, +- ACPI_EC_BURST = 0x10, +- ACPI_EC_CMD = 0x08, +- ACPI_EC_IBF = 0x02, +- ACPI_EC_OBF = 0x01 +-}; +- +-enum +-{ +- ACPI_EC_READ = 0x80, +- ACPI_EC_WRITE = 0x81, +- ACPI_EC_BURST_ENABLE = 0x82, +- ACPI_EC_BURST_DISABLE = 0x83, +- ACPI_EC_QUERY = 0x84, +-}; +- +-typedef struct +-{ +- ACPI_HANDLE acpi_handle; +- u32 gpe_bit; +- ACPI_IO_ADDRESS status_port; +- ACPI_IO_ADDRESS data_port; +- u32 need_global_lock; +-} ec_context_t; +- +- +-typedef struct +-{ +- ec_context_t *ec; +- u8 data; +- +-} EC_QUERY_DATA; +- +-static char object_name[] = {'_', 'Q', '0', '0', '\0'}; +- +-static char hex[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; +- +- +-static ACPI_STATUS +-ec_io_wait ( +- ec_context_t *ec, +- EC_EVENT wait_event) +-{ +- EC_STATUS ec_status = 0; +- UINT32 i = 100; +- +- if (!ec || ((wait_event != EC_EVENT_OUTPUT_BUFFER_FULL) +- && (wait_event != EC_EVENT_INPUT_BUFFER_EMPTY))) +- return(AE_BAD_PARAMETER); +- +- /* +- * Wait for Event: +- * --------------- +- * Poll the EC status register waiting for the event to occur. +- * Note that we'll wait a maximum of 1ms in 10us chunks. +- */ +- switch (wait_event) { +- case EC_EVENT_OUTPUT_BUFFER_FULL: +- do { +- ec_status = acpi_os_in8(ec->status_port); +- if (ec_status & EC_FLAG_OUTPUT_BUFFER) +- return(AE_OK); +- acpi_os_sleep_usec(10); +- } while (--i>0); +- break; +- case EC_EVENT_INPUT_BUFFER_EMPTY: +- do { +- ec_status = acpi_os_in8(ec->status_port); +- if (!(ec_status & EC_FLAG_INPUT_BUFFER)) +- return(AE_OK); +- acpi_os_sleep_usec(10); +- } while (--i>0); +- break; +- } +- +- return(AE_TIME); +-} +- +-static ACPI_STATUS +-ec_io_read ( +- ec_context_t *ec, +- ACPI_IO_ADDRESS io_port, +- UINT8 *data, +- EC_EVENT wait_event) +-{ +- ACPI_STATUS status = AE_OK; +- +- if (!ec || !data) +- return(AE_BAD_PARAMETER); +- +- *data = acpi_os_in8(io_port); +- +- if (wait_event) +- status = ec_io_wait(ec, wait_event); +- +- return(status); +-} +- +-static ACPI_STATUS +-ec_io_write ( +- ec_context_t *ec, +- ACPI_IO_ADDRESS io_port, +- UINT8 data, +- EC_EVENT wait_event) +-{ +- ACPI_STATUS status = AE_OK; +- +- if (!ec) +- return(AE_BAD_PARAMETER); +- +- acpi_os_out8(io_port, data); +- +- if (wait_event) +- status = ec_io_wait(ec, wait_event); +- +- return(status); +-} +- +-static ACPI_STATUS +-ec_read ( +- ec_context_t *ec, +- UINT8 address, +- UINT8 *data) +-{ +- ACPI_STATUS status = AE_OK; +- +- FUNCTION_TRACE("ec_read"); +- +- if (!ec || !data) +- return_ACPI_STATUS(AE_BAD_PARAMETER); +- +- status = ec_io_write(ec, ec->status_port, EC_COMMAND_READ, EC_EVENT_INPUT_BUFFER_EMPTY); +- if (ACPI_FAILURE(status)) { +- DEBUG_PRINT(ACPI_WARN, ("Unable to send 'read command' to EC.\n")); +- return_ACPI_STATUS(status); +- } +- +- status = ec_io_write(ec, ec->data_port, address, EC_EVENT_OUTPUT_BUFFER_FULL); +- if (ACPI_FAILURE(status)) { +- DEBUG_PRINT(ACPI_WARN, ("Unable to send 'read address' to EC.\n")); +- return_ACPI_STATUS(status); +- } +- +- status = ec_io_read(ec, ec->data_port, data, EC_EVENT_NONE); +- +- DEBUG_PRINT(ACPI_INFO, ("Read data[0x%02x] from address[0x%02x] on ec.\n", (*data), address)); +- +- return_ACPI_STATUS(status); +-} +- +-static ACPI_STATUS +-ec_write ( +- ec_context_t *ec, +- UINT8 address, +- UINT8 data) +-{ +- ACPI_STATUS status = AE_OK; +- +- FUNCTION_TRACE("ec_write"); +- +- if (!ec) +- return_ACPI_STATUS(AE_BAD_PARAMETER); +- +- status = ec_io_write(ec, ec->status_port, EC_COMMAND_WRITE, EC_EVENT_INPUT_BUFFER_EMPTY); +- if (ACPI_FAILURE(status)) { +- DEBUG_PRINT(ACPI_WARN, ("Unable to send 'write command' to EC.\n")); +- return_ACPI_STATUS(status); +- } +- +- status = ec_io_write(ec, ec->data_port, address, EC_EVENT_INPUT_BUFFER_EMPTY); +- if (ACPI_FAILURE(status)) { +- DEBUG_PRINT(ACPI_WARN, ("Unable to send 'write address' to EC.\n")); +- return_ACPI_STATUS(status); +- } +- +- status = ec_io_write(ec, ec->data_port, data, EC_EVENT_INPUT_BUFFER_EMPTY); +- if (ACPI_FAILURE(status)) { +- DEBUG_PRINT(ACPI_WARN, ("Unable to send 'write data' to EC.\n")); +- return_ACPI_STATUS(status); +- } +- +- DEBUG_PRINT(ACPI_INFO, ("Wrote data[0x%02x] to address[0x%02x] on ec.\n", data, address)); +- +- return_ACPI_STATUS(status); +-} +- +-static ACPI_STATUS +-ec_transaction ( +- ec_context_t *ec, +- EC_REQUEST *request) +-{ +- ACPI_STATUS status = AE_OK; +- +- FUNCTION_TRACE("ec_transaction"); +- +- if (!ec || !request) +- return_ACPI_STATUS(AE_BAD_PARAMETER); +- +- /* +- * Obtaining semaphore (mutex) to serialize all EC transactions. +- */ +- /* +- DEBUG_PRINT(ACPI_INFO, ("Calling acpi_os_wait_semaphore(%p, 1, %d)\n", ec->mutex, EC_DEFAULT_TIMEOUT)); +- status = acpi_os_wait_semaphore(ec->mutex, 1, EC_DEFAULT_TIMEOUT); +- if (ACPI_FAILURE(status)) +- return_ACPI_STATUS(status); +- */ +- +- /* +- * Perform the transaction. +- */ +- switch (request->command) { +- +- case EC_COMMAND_READ: +- status = ec_read(ec, request->address, &(request->data)); +- break; +- +- case EC_COMMAND_WRITE: +- status = ec_write(ec, request->address, request->data); +- break; +- +- default: +- status = AE_SUPPORT; +- break; +- } +- +- /* +- * Signal the semaphore (mutex) to indicate transaction completion. +- */ +- /* +- DEBUG_PRINT(ACPI_INFO, ("Calling acpi_os_signal_semaphore(%p, 1)\n", ec->mutex)); +- acpi_os_signal_semaphore(ec->mutex, 1); +- */ +- +- return_ACPI_STATUS(status); +-} +- +- +-static void +-ec_query_handler ( +- void *context) +-{ +- ACPI_STATUS status = AE_OK; +- EC_QUERY_DATA *ec_q = (EC_QUERY_DATA*)context; +- +- FUNCTION_TRACE("ec_query_handler"); +- +- if (!ec_q || !ec_q->ec) { +- DEBUG_PRINT(ACPI_ERROR, ("Invalid (NULL) context.\n")); +- return_VOID; +- } +- +- /* +- * Evaluate _Qxx: +- * -------------- +- * Evaluate corresponding _Qxx method. Note that a zero query +- * value indicates a spurious EC_SCI (no such thing as _Q00). +- */ +- object_name[2] = hex[((ec_q->data >> 4) & 0x0F)]; +- object_name[3] = hex[(ec_q->data & 0x0F)]; +- +- DEBUG_PRINT(ACPI_INFO, ("Read query data[0x%02x] from ec - evaluating [%s].\n", ec_q->data, object_name)); +- +- status = acpi_evaluate_object(ec_q->ec->acpi_handle, object_name, NULL, NULL); +- +- kfree(ec_q); +- +- return_VOID; +-} +- +-/* +- * handle GPE +- */ +-static void +-ec_gpe_handler(void *context) +-{ +- ACPI_STATUS status = AE_OK; +- ec_context_t *ec = (ec_context_t *) context; +- EC_QUERY_DATA *ec_q = NULL; +- EC_STATUS ec_status = 0; +- +- FUNCTION_TRACE("ec_gpe_handler"); +- +- if (!ec) { +- DEBUG_PRINT(ACPI_INFO, ("Invalid (NULL) context.\n")); +- return_VOID; +- } +- +- // GET SPINLOCK! +- +- /* +- * EC_SCI? +- * ------- +- * Check the EC_SCI bit to see if this is an EC_SCI event. If not (e.g. +- * OBF/IBE) just return, as we already poll to detect these events. +- */ +- ec_status = acpi_os_in8(ec->status_port); +- DEBUG_PRINT(ACPI_INFO, ("EC Status Register: [0x%02x]\n", ec_status)); +- if (!(ec_status & EC_FLAG_SCI)) +- return_VOID; +- +- DEBUG_PRINT(ACPI_INFO, ("EC_SCI detected - running QUERY.\n")); +- +- // TODO: Need GFP_ATOMIC 'switch' for OSL interface... +- ec_q = kmalloc(sizeof(EC_QUERY_DATA), GFP_ATOMIC); +- if (!ec_q) { +- DEBUG_PRINT(ACPI_INFO, ("Memory allocation failure.\n")); +- return_VOID; +- } +- +- ec_q->ec = ec; +- ec_q->data = 0; +- +- /* +- * Run Query: +- * ---------- +- * Query the EC to find out which _Qxx method we need to evaluate. +- * Note that successful completion of the query causes the EC_SCI +- * bit to be cleared (and thus clearing the interrupt source). +- */ +- status = ec_io_write(ec, ec->status_port, EC_COMMAND_QUERY, EC_EVENT_OUTPUT_BUFFER_FULL); +- if (ACPI_FAILURE(status)) { +- DEBUG_PRINT(ACPI_WARN, ("Unable to send 'query command' to EC.\n")); +- goto End; +- } +- +- status = ec_io_read(ec, ec->data_port, &(ec_q->data), EC_EVENT_NONE); +- if (ACPI_FAILURE(status)) { +- DEBUG_PRINT(ACPI_WARN, ("Error reading query data.\n")); +- goto End; +- } +- +- // RELEASE SPINLOCK! +- +- if (!ec_q->data) { +- DEBUG_PRINT(ACPI_WARN, ("Spurious EC SCI detected.\n")); +- status = AE_ERROR; +- goto End; +- } +- +- /* +- * Defer _Qxx Execution: +- * --------------------- +- * Can't evaluate this method now 'cause we're at interrupt-level. +- */ +- status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, ec_query_handler, ec_q); +- if (ACPI_FAILURE(status)) { +- DEBUG_PRINT(ACPI_ERROR, ("Unable to defer _Qxx method evaluation.\n")); +- goto End; +- } +- +-End: +- if (ACPI_FAILURE(status)) +- kfree(ec_q); +- +- return_VOID; +-} +- +-static ACPI_STATUS +-ec_region_setup ( +- ACPI_HANDLE handle, +- u32 function, +- void *handler_context, +- void **region_context) +-{ +- FUNCTION_TRACE("acpi_ec_region_setup"); +- +- if (function == ACPI_REGION_DEACTIVATE) +- { +- if (*region_context) +- { +- acpi_cm_free (*region_context); +- *region_context = NULL; +- } +- +- return_ACPI_STATUS (AE_OK); +- } +- +- *region_context = NULL; +- +- return_ACPI_STATUS (AE_OK); +-} +- +-/***************************************************************************** +- * +- * FUNCTION: ec_region_handler +- * +- * PARAMETERS: function - Read or Write operation +- * address - Where in the space to read or write +- * bit_width - Field width in bits (8, 16, or 32) +- * value - Pointer to in or out value +- * context - context pointer +- * +- * RETURN: <TBD> +- * +- * DESCRIPTION: Handler for the Embedded Controller (EC) address space +- * (Op Region) +- * +- ****************************************************************************/ +- +-static ACPI_STATUS +-ec_region_handler ( +- UINT32 function, +- ACPI_PHYSICAL_ADDRESS address, +- UINT32 bit_width, +- UINT32 *value, +- void *handler_context, +- void *region_context) +-{ +- ACPI_STATUS status = AE_OK; +- ec_context_t *ec = NULL; +- EC_REQUEST ec_request; +- +- FUNCTION_TRACE("ec_space_handler"); +- +- if (address > 0xFF || bit_width != 8 || !value || !handler_context) +- return_ACPI_STATUS(AE_BAD_PARAMETER); +- +- ec = (ec_context_t*)handler_context; +- +- switch (function) { +- +- case ADDRESS_SPACE_READ: +- ec_request.command = EC_COMMAND_READ; +- ec_request.address = address; +- ec_request.data = 0; +- break; +- +- case ADDRESS_SPACE_WRITE: +- ec_request.command = EC_COMMAND_WRITE; +- ec_request.address = address; +- ec_request.data = (UINT8)(*value); +- break; +- +- default: +- DEBUG_PRINT(ACPI_WARN, ("Received request with invalid function [0x%08X].\n", function)); +- return_ACPI_STATUS(AE_BAD_PARAMETER); +- break; +- } +- +- DEBUG_PRINT(ACPI_INFO, ("device[ec] command[0x%02X] address[0x%02X] data[0x%02X]\n", ec_request.command, ec_request.address, ec_request.data)); +- +- /* +- * Perform the Transaction. +- */ +- status = ec_transaction(ec, &ec_request); +- if (ACPI_SUCCESS(status)) +- (*value) = (UINT32)ec_request.data; +- +- return_ACPI_STATUS(status); +-} +- +-/* +- * Get Embedded Controller information +- */ +-static ACPI_STATUS +-found_ec( +- ACPI_HANDLE handle, +- u32 level, +- void *ctx, +- void **value) +-{ +- ACPI_STATUS status; +- ACPI_OBJECT obj; +- ACPI_BUFFER buf; +- RESOURCE *res; +- ec_context_t *ec_cxt; +- +- buf.length = 0; +- buf.pointer = NULL; +- if (acpi_get_current_resources(handle, &buf) != AE_BUFFER_OVERFLOW) +- return AE_OK; +- +- buf.pointer = kmalloc(buf.length, GFP_KERNEL); +- if (!buf.pointer) +- return AE_NO_MEMORY; +- +- if (!ACPI_SUCCESS(acpi_get_current_resources(handle, &buf))) { +- kfree(buf.pointer); +- return AE_OK; +- } +- +- ec_cxt = kmalloc(sizeof(ec_context_t), GFP_KERNEL); +- if (!ec_cxt) { +- kfree(buf.pointer); +- return AE_NO_MEMORY; +- } +- +- ec_cxt->acpi_handle = handle; +- +- res = (RESOURCE*) buf.pointer; +- ec_cxt->data_port = res->data.io.min_base_address; +- res = NEXT_RESOURCE(res); +- ec_cxt->status_port = (int) res->data.io.min_base_address; +- +- kfree(buf.pointer); +- +- /* determine GPE bit */ +- /* BUG: in acpi 2.0 this could return a package */ +- buf.length = sizeof(obj); +- buf.pointer = &obj; +- if (!ACPI_SUCCESS(acpi_evaluate_object(handle, "_GPE", NULL, &buf)) +- || obj.type != ACPI_TYPE_INTEGER) +- return AE_OK; +- +- ec_cxt->gpe_bit = obj.integer.value; +- +- /* determine if we need the Global Lock when accessing */ +- buf.length = sizeof(obj); +- buf.pointer = &obj; +- +- status = acpi_evaluate_object(handle, "_GLK", NULL, &buf); +- if (status == AE_NOT_FOUND) +- ec_cxt->need_global_lock = 0; +- else if (!ACPI_SUCCESS(status) || obj.type != ACPI_TYPE_INTEGER) { +- DEBUG_PRINT(ACPI_ERROR, ("_GLK failed\n")); +- return AE_OK; +- } +- +- ec_cxt->need_global_lock = obj.integer.value; +- +- printk(KERN_INFO "ACPI: found EC @ (0x%02x,0x%02x,GPE %d GL %d)\n", +- ec_cxt->data_port, ec_cxt->status_port, ec_cxt->gpe_bit, +- ec_cxt->need_global_lock); +- +- if (!ACPI_SUCCESS(acpi_install_gpe_handler( +- ec_cxt->gpe_bit, +- ACPI_EVENT_EDGE_TRIGGERED, +- ec_gpe_handler, +- ec_cxt))) { +- +- REPORT_ERROR(("Could not install GPE handler for EC.\n")); +- return AE_OK; +- } +- +- status = acpi_install_address_space_handler (handle, ADDRESS_SPACE_EC, +- ec_region_handler, ec_region_setup, ec_cxt); +- +- if (!ACPI_SUCCESS(status)) { +- REPORT_ERROR(("Could not install EC address " +- "space handler, error %s\n", acpi_cm_format_exception (status))); +- } +- +- return AE_OK; +-} +- +-int +-acpi_ec_init(void) +-{ +- acpi_get_devices(ACPI_EC_HID, +- found_ec, +- NULL, +- NULL); +- +- return 0; +-} +- +-int +-acpi_ec_terminate(void) +-{ +- /* TODO */ +- /* walk list of EC's */ +- /* free their context and release resources */ +- return 0; +-} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ec.h linux/drivers/acpi/ec.h +--- /usr/src/linux/drivers/acpi/ec.h Fri Dec 29 14:07:21 2000 ++++ linux/drivers/acpi/ec.h Wed Dec 31 16:00:00 1969 +@@ -1,100 +0,0 @@ +-/* +- * Copyright (C) 2000 Andrew Grover +- * +- * 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 +- */ +- +- +-#ifndef __EC_H__ +-#define __EC_H__ +- +-// TODO: Linux-specific +-#include <linux/spinlock.h> +-#include <asm/semaphore.h> +- +-#include <actypes.h> +-#include <acexcep.h> +- +-/***************************************************************************** +- * Types & Other Defines +- *****************************************************************************/ +- +-#define EC_DEFAULT_TIMEOUT 1000 /* 1 second */ +-#define EC_GPE_UNKNOWN 0xFFFFFFFF +-#define EC_PORT_UNKNOWN 0x00000000 +-#define EC_BURST_ENABLE_ACKNOWLEDGE 0x90 +- +-/* +- * EC_COMMAND: +- * ----------- +- */ +-typedef UINT8 EC_COMMAND; +- +-#define EC_COMMAND_UNKNOWN ((EC_COMMAND) 0x00) +-#define EC_COMMAND_READ ((EC_COMMAND) 0x80) +-#define EC_COMMAND_WRITE ((EC_COMMAND) 0x81) +-#define EC_COMMAND_QUERY ((EC_COMMAND) 0x84) +- +-/* +- * EC_STATUS: +- * ---------- +- * The encoding of the EC status register is illustrated below. +- * Note that a set bit (1) indicates the property is TRUE +- * (e.g. if bit 0 is set then the output buffer is full). +- * +-+-+-+-+-+-+-+-+ +- * |7|6|5|4|3|2|1|0| +- * +-+-+-+-+-+-+-+-+ +- * | | | | | | | | +- * | | | | | | | +- Output Buffer Full (OBF)? +- * | | | | | | +--- Input Buffer Full (IBF)? +- * | | | | | +----- <reserved> +- * | | | | +------- data Register is command Byte? +- * | | | +--------- Burst Mode Enabled? +- * | | +----------- SCI event? +- * | +------------- SMI event? +- * +--------------- <Reserved> +- * +- */ +-typedef UINT8 EC_STATUS; +- +-#define EC_FLAG_OUTPUT_BUFFER ((EC_STATUS) 0x01) +-#define EC_FLAG_INPUT_BUFFER ((EC_STATUS) 0x02) +-#define EC_FLAG_BURST_MODE ((EC_STATUS) 0x10) +-#define EC_FLAG_SCI ((EC_STATUS) 0x20) +- +-/* +- * EC_EVENT: +- * --------- +- */ +-typedef UINT8 EC_EVENT; +- +-#define EC_EVENT_UNKNOWN ((EC_EVENT) 0x00) +-#define EC_EVENT_NONE ((EC_EVENT) 0x00) +-#define EC_EVENT_OUTPUT_BUFFER_FULL ((EC_EVENT) 0x01) +-#define EC_EVENT_INPUT_BUFFER_EMPTY ((EC_EVENT) 0x02) +-#define EC_EVENT_SCI ((EC_EVENT) 0x03) +- +-/* +- * EC_REQUEST: +- * ----------- +- */ +-typedef struct +-{ +- EC_COMMAND command; +- UINT8 address; +- UINT8 data; +-} EC_REQUEST; +- +-#endif /* __EC_H__ */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/events/Makefile linux/drivers/acpi/events/Makefile +--- /usr/src/linux/drivers/acpi/events/Makefile Fri Dec 29 14:07:21 2000 ++++ linux/drivers/acpi/events/Makefile Fri Apr 13 11:57:11 2001 +@@ -1,5 +1,6 @@ + # + # Makefile for all Linux ACPI interpreter subdirectories ++# EXCEPT for the ospm directory + # + + O_TARGET := ../$(shell basename `pwd`).o +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/events/evevent.c linux/drivers/acpi/events/evevent.c +--- /usr/src/linux/drivers/acpi/events/evevent.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/events/evevent.c Fri Apr 13 11:57:11 2001 +@@ -2,7 +2,7 @@ + * + * Module Name: evevent - Fixed and General Purpose Acpi_event + * handling and dispatch +- * $Revision: 34 $ ++ * $Revision: 39 $ + * + *****************************************************************************/ + +@@ -30,7 +30,7 @@ + #include "acnamesp.h" + #include "accommon.h" + +-#define _COMPONENT EVENT_HANDLING ++#define _COMPONENT ACPI_EVENTS + MODULE_NAME ("evevent") + + +@@ -179,32 +179,28 @@ + /* power management timer roll over */ + + if ((status_register & ACPI_STATUS_PMTIMER) && +- (enable_register & ACPI_ENABLE_PMTIMER)) +- { ++ (enable_register & ACPI_ENABLE_PMTIMER)) { + int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_PMTIMER); + } + + /* global event (BIOS want's the global lock) */ + + if ((status_register & ACPI_STATUS_GLOBAL) && +- (enable_register & ACPI_ENABLE_GLOBAL)) +- { ++ (enable_register & ACPI_ENABLE_GLOBAL)) { + int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_GLOBAL); + } + + /* power button event */ + + if ((status_register & ACPI_STATUS_POWER_BUTTON) && +- (enable_register & ACPI_ENABLE_POWER_BUTTON)) +- { ++ (enable_register & ACPI_ENABLE_POWER_BUTTON)) { + int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_POWER_BUTTON); + } + + /* sleep button event */ + + if ((status_register & ACPI_STATUS_SLEEP_BUTTON) && +- (enable_register & ACPI_ENABLE_SLEEP_BUTTON)) +- { ++ (enable_register & ACPI_ENABLE_SLEEP_BUTTON)) { + int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_SLEEP_BUTTON); + } + +@@ -233,8 +229,7 @@ + + /* Clear the status bit */ + +- switch (event) +- { ++ switch (event) { + case ACPI_EVENT_PMTIMER: + register_id = TMR_STS; + break; +@@ -706,8 +701,6 @@ + { + ACPI_GPE_LEVEL_INFO gpe_info; + +- /*DEBUG_INCREMENT_EVENT_COUNT (EVENT_GENERAL);*/ +- + /* + * Valid GPE number? + */ +@@ -751,8 +744,7 @@ + */ + else if (gpe_info.method_handle) { + if (ACPI_FAILURE(acpi_os_queue_for_execution (OSD_PRIORITY_GPE, +- acpi_ev_asynch_execute_gpe_method, (void*)(NATIVE_UINT)gpe_number))) +- { ++ acpi_ev_asynch_execute_gpe_method, (void*) gpe_number))) { + /* + * Shoudn't occur, but if it does report an error. Note that + * the GPE will remain disabled until the ACPI Core Subsystem +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/events/evmisc.c linux/drivers/acpi/events/evmisc.c +--- /usr/src/linux/drivers/acpi/events/evmisc.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/events/evmisc.c Fri Apr 13 11:57:11 2001 +@@ -2,7 +2,7 @@ + * + * Module Name: evmisc - ACPI device notification handler dispatch + * and ACPI Global Lock support +- * $Revision: 22 $ ++ * $Revision: 28 $ + * + *****************************************************************************/ + +@@ -30,13 +30,13 @@ + #include "acinterp.h" + #include "achware.h" + +-#define _COMPONENT EVENT_HANDLING ++#define _COMPONENT ACPI_EVENTS + MODULE_NAME ("evmisc") + + + /************************************************************************** + * +- * FUNCTION: Acpi_ev_notify_dispatch ++ * FUNCTION: Acpi_ev_queue_notify_request + * + * PARAMETERS: + * +@@ -47,14 +47,15 @@ + * + *************************************************************************/ + +-void +-acpi_ev_notify_dispatch ( +- ACPI_HANDLE device, ++ACPI_STATUS ++acpi_ev_queue_notify_request ( ++ ACPI_NAMESPACE_NODE *node, + u32 notify_value) + { + ACPI_OPERAND_OBJECT *obj_desc; +- ACPI_OPERAND_OBJECT *handler_obj; +- NOTIFY_HANDLER handler; ++ ACPI_OPERAND_OBJECT *handler_obj = NULL; ++ ACPI_GENERIC_STATE *notify_info; ++ ACPI_STATUS status = AE_OK; + + + /* +@@ -64,9 +65,7 @@ + * initiate soft-off or sleep operation? + */ + +- +- switch (notify_value) +- { ++ switch (notify_value) { + case 0: + break; + +@@ -85,63 +84,133 @@ + + + /* +- * Invoke a global notify handler if installed. +- * This is done _before_ we invoke the per-device handler attached to the device. ++ * Get the notify object attached to the device Node + */ + +- if (notify_value <= MAX_SYS_NOTIFY) { +- /* Global system notification handler */ ++ obj_desc = acpi_ns_get_attached_object (node); ++ if (obj_desc) { + +- if (acpi_gbl_sys_notify.handler) { +- acpi_gbl_sys_notify.handler (device, notify_value, +- acpi_gbl_sys_notify.context); ++ /* We have the notify object, Get the right handler */ ++ ++ switch (node->type) { ++ case ACPI_TYPE_DEVICE: ++ if (notify_value <= MAX_SYS_NOTIFY) { ++ handler_obj = obj_desc->device.sys_handler; ++ } ++ else { ++ handler_obj = obj_desc->device.drv_handler; ++ } ++ break; ++ ++ case ACPI_TYPE_THERMAL: ++ if (notify_value <= MAX_SYS_NOTIFY) { ++ handler_obj = obj_desc->thermal_zone.sys_handler; ++ } ++ else { ++ handler_obj = obj_desc->thermal_zone.drv_handler; ++ } ++ break; + } + } + +- else { +- /* Global driver notification handler */ + +- if (acpi_gbl_drv_notify.handler) { +- acpi_gbl_drv_notify.handler (device, notify_value, +- acpi_gbl_drv_notify.context); ++ /* If there is any handler to run, schedule the dispatcher */ ++ ++ if ((acpi_gbl_sys_notify.handler && (notify_value <= MAX_SYS_NOTIFY)) || ++ (acpi_gbl_drv_notify.handler && (notify_value > MAX_SYS_NOTIFY)) || ++ handler_obj) { ++ ++ notify_info = acpi_cm_create_generic_state (); ++ if (!notify_info) { ++ return (AE_NO_MEMORY); ++ } ++ ++ notify_info->notify.node = node; ++ notify_info->notify.value = (u16) notify_value; ++ notify_info->notify.handler_obj = handler_obj; ++ ++ status = acpi_os_queue_for_execution (OSD_PRIORITY_HIGH, ++ acpi_ev_notify_dispatch, notify_info); ++ if (ACPI_FAILURE (status)) { ++ acpi_cm_delete_generic_state (notify_info); + } + } + ++ if (!handler_obj) { ++ /* There is no per-device notify handler for this device */ + +- /* +- * Get the notify object which must be attached to the device Node +- */ ++ } + +- obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) device); +- if (!obj_desc) { +- /* There can be no notify handler for this device */ + +- return; +- } ++ return (status); ++} + + +- /* We have the notify object, Get the right handler */ ++/************************************************************************** ++ * ++ * FUNCTION: Acpi_ev_notify_dispatch ++ * ++ * PARAMETERS: ++ * ++ * RETURN: None. ++ * ++ * DESCRIPTION: Dispatch a device notification event to a previously ++ * installed handler. ++ * ++ *************************************************************************/ ++ ++void ++acpi_ev_notify_dispatch ( ++ void *context) ++{ ++ ACPI_GENERIC_STATE *notify_info = (ACPI_GENERIC_STATE *) context; ++ NOTIFY_HANDLER global_handler = NULL; ++ void *global_context = NULL; ++ ACPI_OPERAND_OBJECT *handler_obj; ++ + +- if (notify_value <= MAX_SYS_NOTIFY) { +- handler_obj = obj_desc->device.sys_handler; ++ /* ++ * We will invoke a global notify handler if installed. ++ * This is done _before_ we invoke the per-device handler attached to the device. ++ */ ++ ++ if (notify_info->notify.value <= MAX_SYS_NOTIFY) { ++ /* Global system notification handler */ ++ ++ if (acpi_gbl_sys_notify.handler) { ++ global_handler = acpi_gbl_sys_notify.handler; ++ global_context = acpi_gbl_sys_notify.context; ++ } + } ++ + else { +- handler_obj = obj_desc->device.drv_handler; ++ /* Global driver notification handler */ ++ ++ if (acpi_gbl_drv_notify.handler) { ++ global_handler = acpi_gbl_drv_notify.handler; ++ global_context = acpi_gbl_drv_notify.context; ++ } + } + +- /* Validate the handler */ + +- if (!handler_obj) { +- /* There is no notify handler for this device */ ++ /* Invoke the system handler first, if present */ ++ ++ if (global_handler) { ++ global_handler (notify_info->notify.node, notify_info->notify.value, global_context); ++ } + +- return; ++ /* Now invoke the per-device handler, if present */ ++ ++ handler_obj = notify_info->notify.handler_obj; ++ if (handler_obj) { ++ handler_obj->notify_handler.handler (notify_info->notify.node, notify_info->notify.value, ++ handler_obj->notify_handler.context); + } + +- /* There is a handler, invoke it */ + +- handler = handler_obj->notify_handler.handler; +- handler (device, notify_value, handler_obj->notify_handler.context); ++ /* All done with the info object */ + ++ acpi_cm_delete_generic_state (notify_info); + } + + +@@ -232,9 +301,22 @@ + ACPI_STATUS status; + + ++ acpi_gbl_global_lock_present = TRUE; + status = acpi_install_fixed_event_handler (ACPI_EVENT_GLOBAL, + acpi_ev_global_lock_handler, NULL); + ++ /* ++ * If the global lock does not exist on this platform, the attempt ++ * to enable GBL_STS will fail (the GBL_EN bit will not stick) ++ * Map to AE_OK, but mark global lock as not present. ++ * Any attempt to actually use the global lock will be flagged ++ * with an error. ++ */ ++ if (status == AE_NO_HARDWARE_RESPONSE) { ++ acpi_gbl_global_lock_present = FALSE; ++ status = AE_OK; ++ } ++ + return (status); + } + +@@ -257,6 +339,12 @@ + void *global_lock; + + ++ /* Make sure that we actually have a global lock */ ++ ++ if (!acpi_gbl_global_lock_present) { ++ return (AE_NO_GLOBAL_LOCK); ++ } ++ + /* One more thread wants the global lock */ + + acpi_gbl_global_lock_thread_count++; +@@ -321,7 +409,7 @@ + + + if (!acpi_gbl_global_lock_thread_count) { +- REPORT_WARNING(("Releasing a non-acquired Global Lock\n")); ++ REPORT_WARNING(("Global Lock has not be acquired, cannot release\n")); + return; + } + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/events/evregion.c linux/drivers/acpi/events/evregion.c +--- /usr/src/linux/drivers/acpi/events/evregion.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/events/evregion.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: evregion - ACPI Address_space (Op_region) handler dispatch +- * $Revision: 96 $ ++ * $Revision: 100 $ + * + *****************************************************************************/ + +@@ -30,7 +30,7 @@ + #include "acinterp.h" + #include "amlcode.h" + +-#define _COMPONENT EVENT_HANDLING ++#define _COMPONENT ACPI_EVENTS + MODULE_NAME ("evregion") + + +@@ -73,8 +73,7 @@ + ADDRESS_SPACE_SYSTEM_MEMORY, + ACPI_DEFAULT_HANDLER, NULL, NULL); + if ((ACPI_FAILURE (status)) && +- (status != AE_EXIST)) +- { ++ (status != AE_EXIST)) { + return (status); + } + +@@ -82,8 +81,7 @@ + ADDRESS_SPACE_SYSTEM_IO, + ACPI_DEFAULT_HANDLER, NULL, NULL); + if ((ACPI_FAILURE (status)) && +- (status != AE_EXIST)) +- { ++ (status != AE_EXIST)) { + return (status); + } + +@@ -91,8 +89,7 @@ + ADDRESS_SPACE_PCI_CONFIG, + ACPI_DEFAULT_HANDLER, NULL, NULL); + if ((ACPI_FAILURE (status)) && +- (status != AE_EXIST)) +- { ++ (status != AE_EXIST)) { + return (status); + } + +@@ -202,21 +199,20 @@ + + + /* +- * Check for an installed handler ++ * Ensure that there is a handler associated with this region + */ + handler_desc = region_obj->region.addr_handler; +- + if (!handler_desc) { + return(AE_NOT_EXIST); + } + + /* +- * It may be the case that the region has never been initialized +- * Some types of regions require special init code ++ * It may be the case that the region has never been initialized ++ * Some types of regions require special init code + */ + if (!(region_obj->region.flags & AOPOBJ_INITIALIZED)) { + /* +- * This region has not been initialized yet, do it ++ * This region has not been initialized yet, do it + */ + region_setup = handler_desc->addr_handler.setup; + if (!region_setup) { +@@ -524,14 +520,13 @@ + + if ((node->type != ACPI_TYPE_DEVICE) && + (node->type != ACPI_TYPE_REGION) && +- (node != acpi_gbl_root_node)) +- { ++ (node != acpi_gbl_root_node)) { + return (AE_OK); + } + + /* Check for an existing internal object */ + +- obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) node); ++ obj_desc = acpi_ns_get_attached_object (node); + if (!obj_desc) { + /* + * The object DNE, we don't care about it +@@ -555,7 +550,6 @@ + /* + * It's for the same address space + */ +- + /* + * Since the object we found it on was a device, then it + * means that someone has already installed a handler for +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/events/evrgnini.c linux/drivers/acpi/events/evrgnini.c +--- /usr/src/linux/drivers/acpi/events/evrgnini.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/events/evrgnini.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: evrgnini- ACPI Address_space (Op_region) init +- * $Revision: 33 $ ++ * $Revision: 36 $ + * + *****************************************************************************/ + +@@ -30,7 +30,7 @@ + #include "acinterp.h" + #include "amlcode.h" + +-#define _COMPONENT EVENT_HANDLING ++#define _COMPONENT ACPI_EVENTS + MODULE_NAME ("evrgnini") + + +@@ -219,8 +219,7 @@ + + if (ACPI_SUCCESS (status)) { + if (!(STRNCMP(object_hID.buffer, PCI_ROOT_HID_STRING, +- sizeof (PCI_ROOT_HID_STRING)))) +- { ++ sizeof (PCI_ROOT_HID_STRING)))) { + acpi_install_address_space_handler(node, + ADDRESS_SPACE_PCI_CONFIG, + ACPI_DEFAULT_HANDLER, NULL, NULL); +@@ -307,7 +306,7 @@ + * + * This also performs address space specific intialization. For + * example, PCI regions must have an _ADR object that contains +- * a PCI address in the scope of the defintion. This address is ++ * a PCI address in the scope of the definition. This address is + * required to perform an access to PCI config space. + * + ******************************************************************************/ +@@ -362,13 +361,12 @@ + * Check to see if a handler exists + */ + handler_obj = NULL; +- obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) node); ++ obj_desc = acpi_ns_get_attached_object (node); + if (obj_desc) { + /* + * can only be a handler if the object exists + */ +- switch (node->type) +- { ++ switch (node->type) { + case ACPI_TYPE_DEVICE: + + handler_obj = obj_desc->device.addr_handler; +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/events/evsci.c linux/drivers/acpi/events/evsci.c +--- /usr/src/linux/drivers/acpi/events/evsci.c Tue Mar 6 19:44:36 2001 ++++ linux/drivers/acpi/events/evsci.c Fri Apr 13 11:57:11 2001 +@@ -2,7 +2,7 @@ + * + * Module Name: evsci - System Control Interrupt configuration and + * legacy to ACPI mode state transition functions +- * $Revision: 69 $ ++ * $Revision: 71 $ + * + ******************************************************************************/ + +@@ -30,7 +30,7 @@ + #include "acevents.h" + + +-#define _COMPONENT EVENT_HANDLING ++#define _COMPONENT ACPI_EVENTS + MODULE_NAME ("evsci") + + +@@ -172,21 +172,6 @@ + + /******************************************************************************* + * +- * FUNCTION: Acpi_ev_sci_count +- * +- * PARAMETERS: Event Event that generated an SCI. +- * +- * RETURN: Number of SCI's for requested event since last time +- * Sci_occurred() was called for this event. +- * +- * DESCRIPTION: Checks to see if SCI has been generated from requested source +- * since the last time this function was called. +- * +- ******************************************************************************/ +- +- +-/******************************************************************************* +- * + * FUNCTION: Acpi_ev_restore_acpi_state + * + * PARAMETERS: none +@@ -209,8 +194,7 @@ + /* Restore the fixed events */ + + if (acpi_hw_register_read (ACPI_MTX_LOCK, PM1_EN) != +- acpi_gbl_pm1_enable_register_save) +- { ++ acpi_gbl_pm1_enable_register_save) { + acpi_hw_register_write (ACPI_MTX_LOCK, PM1_EN, + acpi_gbl_pm1_enable_register_save); + } +@@ -225,8 +209,7 @@ + + for (index = 0; index < DIV_2 (acpi_gbl_FADT->gpe0blk_len); index++) { + if (acpi_hw_register_read (ACPI_MTX_LOCK, GPE0_EN_BLOCK | index) != +- acpi_gbl_gpe0enable_register_save[index]) +- { ++ acpi_gbl_gpe0enable_register_save[index]) { + acpi_hw_register_write (ACPI_MTX_LOCK, GPE0_EN_BLOCK | index, + acpi_gbl_gpe0enable_register_save[index]); + } +@@ -237,8 +220,7 @@ + if (acpi_gbl_FADT->gpe1_blk_len) { + for (index = 0; index < DIV_2 (acpi_gbl_FADT->gpe1_blk_len); index++) { + if (acpi_hw_register_read (ACPI_MTX_LOCK, GPE1_EN_BLOCK | index) != +- acpi_gbl_gpe1_enable_register_save[index]) +- { ++ acpi_gbl_gpe1_enable_register_save[index]) { + acpi_hw_register_write (ACPI_MTX_LOCK, GPE1_EN_BLOCK | index, + acpi_gbl_gpe1_enable_register_save[index]); + } +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/events/evxface.c linux/drivers/acpi/events/evxface.c +--- /usr/src/linux/drivers/acpi/events/evxface.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/events/evxface.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: evxface - External interfaces for ACPI events +- * $Revision: 101 $ ++ * $Revision: 106 $ + * + *****************************************************************************/ + +@@ -31,7 +31,7 @@ + #include "amlcode.h" + #include "acinterp.h" + +-#define _COMPONENT EVENT_HANDLING ++#define _COMPONENT ACPI_EVENTS + MODULE_NAME ("evxface") + + +@@ -57,10 +57,10 @@ + FIXED_EVENT_HANDLER handler, + void *context) + { +- ACPI_STATUS status = AE_OK; ++ ACPI_STATUS status; + + +- /* Sanity check the parameters. */ ++ /* Parameter validation */ + + if (event >= NUM_FIXED_EVENTS) { + return (AE_BAD_PARAMETER); +@@ -81,19 +81,16 @@ + acpi_gbl_fixed_event_handlers[event].handler = handler; + acpi_gbl_fixed_event_handlers[event].context = context; + +- status = acpi_enable_event(event, ACPI_EVENT_FIXED); +- +- if (!ACPI_SUCCESS(status)) { ++ status = acpi_enable_event (event, ACPI_EVENT_FIXED); ++ if (!ACPI_SUCCESS (status)) { + /* Remove the handler */ + + acpi_gbl_fixed_event_handlers[event].handler = NULL; + acpi_gbl_fixed_event_handlers[event].context = NULL; +- +- status = AE_ERROR; +- goto cleanup; + } + + ++ + cleanup: + acpi_cm_release_mutex (ACPI_MTX_EVENTS); + return (status); +@@ -121,7 +118,7 @@ + ACPI_STATUS status = AE_OK; + + +- /* Sanity check the parameters. */ ++ /* Parameter validation */ + + if (event >= NUM_FIXED_EVENTS) { + return (AE_BAD_PARAMETER); +@@ -133,17 +130,14 @@ + + status = acpi_disable_event(event, ACPI_EVENT_FIXED); + +- if (!ACPI_SUCCESS(status)) { +- status = AE_ERROR; +- acpi_cm_release_mutex (ACPI_MTX_EVENTS); +- return (status); +- } +- +- /* Remove the handler */ ++ /* Always Remove the handler */ + + acpi_gbl_fixed_event_handlers[event].handler = NULL; + acpi_gbl_fixed_event_handlers[event].context = NULL; + ++ ++ ++ + acpi_cm_release_mutex (ACPI_MTX_EVENTS); + return (status); + } +@@ -182,8 +176,7 @@ + /* Parameter validation */ + + if ((!handler) || +- (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) +- { ++ (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) { + return (AE_BAD_PARAMETER); + } + +@@ -210,8 +203,7 @@ + if (((handler_type == ACPI_SYSTEM_NOTIFY) && + acpi_gbl_sys_notify.handler) || + ((handler_type == ACPI_DEVICE_NOTIFY) && +- acpi_gbl_drv_notify.handler)) +- { ++ acpi_gbl_drv_notify.handler)) { + status = AE_EXIST; + goto unlock_and_exit; + } +@@ -243,15 +235,14 @@ + if ((device_node->type != ACPI_TYPE_DEVICE) && + (device_node->type != ACPI_TYPE_PROCESSOR) && + (device_node->type != ACPI_TYPE_POWER) && +- (device_node->type != ACPI_TYPE_THERMAL)) +- { ++ (device_node->type != ACPI_TYPE_THERMAL)) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + /* Check for an existing internal object */ + +- obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) device_node); ++ obj_desc = acpi_ns_get_attached_object (device_node); + if (obj_desc) { + + /* Object exists - make sure there's no handler */ +@@ -259,8 +250,7 @@ + if (((handler_type == ACPI_SYSTEM_NOTIFY) && + obj_desc->device.sys_handler) || + ((handler_type == ACPI_DEVICE_NOTIFY) && +- obj_desc->device.drv_handler)) +- { ++ obj_desc->device.drv_handler)) { + status = AE_EXIST; + goto unlock_and_exit; + } +@@ -278,7 +268,6 @@ + /* Attach new object to the Node */ + + status = acpi_ns_attach_object (device, obj_desc, (u8) device_node->type); +- + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } +@@ -300,6 +289,7 @@ + if (handler_type == ACPI_SYSTEM_NOTIFY) { + obj_desc->device.sys_handler = notify_obj; + } ++ + else /* ACPI_DEVICE_NOTIFY */ { + obj_desc->device.drv_handler = notify_obj; + } +@@ -340,8 +330,7 @@ + /* Parameter validation */ + + if ((!handler) || +- (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) +- { ++ (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) { + return (AE_BAD_PARAMETER); + } + +@@ -364,8 +353,7 @@ + if (((handler_type == ACPI_SYSTEM_NOTIFY) && + !acpi_gbl_sys_notify.handler) || + ((handler_type == ACPI_DEVICE_NOTIFY) && +- !acpi_gbl_drv_notify.handler)) +- { ++ !acpi_gbl_drv_notify.handler)) { + status = AE_NOT_EXIST; + goto unlock_and_exit; + } +@@ -393,15 +381,14 @@ + if ((device_node->type != ACPI_TYPE_DEVICE) && + (device_node->type != ACPI_TYPE_PROCESSOR) && + (device_node->type != ACPI_TYPE_POWER) && +- (device_node->type != ACPI_TYPE_THERMAL)) +- { ++ (device_node->type != ACPI_TYPE_THERMAL)) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + /* Check for an existing internal object */ + +- obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) device_node); ++ obj_desc = acpi_ns_get_attached_object (device_node); + if (!obj_desc) { + status = AE_NOT_EXIST; + goto unlock_and_exit; +@@ -417,8 +404,7 @@ + } + + if ((!notify_obj) || +- (notify_obj->notify_handler.handler != handler)) +- { ++ (notify_obj->notify_handler.handler != handler)) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } +@@ -583,7 +569,10 @@ + ACPI_STATUS status; + + +- acpi_aml_enter_interpreter (); ++ status = acpi_aml_enter_interpreter (); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } + + /* + * TBD: [Restructure] add timeout param to internal interface, and +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/events/evxfevnt.c linux/drivers/acpi/events/evxfevnt.c +--- /usr/src/linux/drivers/acpi/events/evxfevnt.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/events/evxfevnt.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: evxfevnt - External Interfaces, ACPI event disable/enable +- * $Revision: 28 $ ++ * $Revision: 30 $ + * + *****************************************************************************/ + +@@ -31,7 +31,7 @@ + #include "amlcode.h" + #include "acinterp.h" + +-#define _COMPONENT EVENT_HANDLING ++#define _COMPONENT ACPI_EVENTS + MODULE_NAME ("evxfevnt") + + +@@ -135,15 +135,13 @@ + + /* The Type must be either Fixed Acpi_event or GPE */ + +- switch (type) +- { ++ switch (type) { + + case ACPI_EVENT_FIXED: + + /* Decode the Fixed Acpi_event */ + +- switch (event) +- { ++ switch (event) { + case ACPI_EVENT_PMTIMER: + register_id = TMR_EN; + break; +@@ -177,7 +175,7 @@ + acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, register_id, 1); + + if (1 != acpi_hw_register_bit_access(ACPI_READ, ACPI_MTX_LOCK, register_id)) { +- return (AE_ERROR); ++ return (AE_NO_HARDWARE_RESPONSE); + } + + break; +@@ -188,8 +186,7 @@ + /* Ensure that we have a valid GPE number */ + + if ((event >= NUM_GPE) || +- (acpi_gbl_gpe_valid[event] == ACPI_GPE_INVALID)) +- { ++ (acpi_gbl_gpe_valid[event] == ACPI_GPE_INVALID)) { + return (AE_BAD_PARAMETER); + } + +@@ -234,15 +231,13 @@ + + /* The Type must be either Fixed Acpi_event or GPE */ + +- switch (type) +- { ++ switch (type) { + + case ACPI_EVENT_FIXED: + + /* Decode the Fixed Acpi_event */ + +- switch (event) +- { ++ switch (event) { + case ACPI_EVENT_PMTIMER: + register_id = TMR_EN; + break; +@@ -276,7 +271,7 @@ + acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, register_id, 0); + + if (0 != acpi_hw_register_bit_access(ACPI_READ, ACPI_MTX_LOCK, register_id)) { +- return (AE_ERROR); ++ return (AE_NO_HARDWARE_RESPONSE); + } + + break; +@@ -287,8 +282,7 @@ + /* Ensure that we have a valid GPE number */ + + if ((event >= NUM_GPE) || +- (acpi_gbl_gpe_valid[event] == ACPI_GPE_INVALID)) +- { ++ (acpi_gbl_gpe_valid[event] == ACPI_GPE_INVALID)) { + return (AE_BAD_PARAMETER); + } + +@@ -330,15 +324,13 @@ + + /* The Type must be either Fixed Acpi_event or GPE */ + +- switch (type) +- { ++ switch (type) { + + case ACPI_EVENT_FIXED: + + /* Decode the Fixed Acpi_event */ + +- switch (event) +- { ++ switch (event) { + case ACPI_EVENT_PMTIMER: + register_id = TMR_STS; + break; +@@ -378,8 +370,7 @@ + /* Ensure that we have a valid GPE number */ + + if ((event >= NUM_GPE) || +- (acpi_gbl_gpe_valid[event] == ACPI_GPE_INVALID)) +- { ++ (acpi_gbl_gpe_valid[event] == ACPI_GPE_INVALID)) { + return (AE_BAD_PARAMETER); + } + +@@ -430,15 +421,13 @@ + + /* The Type must be either Fixed Acpi_event or GPE */ + +- switch (type) +- { ++ switch (type) { + + case ACPI_EVENT_FIXED: + + /* Decode the Fixed Acpi_event */ + +- switch (event) +- { ++ switch (event) { + case ACPI_EVENT_PMTIMER: + register_id = TMR_STS; + break; +@@ -475,8 +464,7 @@ + /* Ensure that we have a valid GPE number */ + + if ((event >= NUM_GPE) || +- (acpi_gbl_gpe_valid[event] == ACPI_GPE_INVALID)) +- { ++ (acpi_gbl_gpe_valid[event] == ACPI_GPE_INVALID)) { + return (AE_BAD_PARAMETER); + } + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/events/evxfregn.c linux/drivers/acpi/events/evxfregn.c +--- /usr/src/linux/drivers/acpi/events/evxfregn.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/events/evxfregn.c Fri Apr 13 11:57:11 2001 +@@ -2,7 +2,7 @@ + * + * Module Name: evxfregn - External Interfaces, ACPI Operation Regions and + * Address Spaces. +- * $Revision: 27 $ ++ * $Revision: 29 $ + * + *****************************************************************************/ + +@@ -32,7 +32,7 @@ + #include "amlcode.h" + #include "acinterp.h" + +-#define _COMPONENT EVENT_HANDLING ++#define _COMPONENT ACPI_EVENTS + MODULE_NAME ("evxfregn") + + +@@ -72,8 +72,7 @@ + + if ((!device) || + ((!handler) && (handler != ACPI_DEFAULT_HANDLER)) || +- (space_id > ACPI_MAX_ADDRESS_SPACE)) +- { ++ (space_id > ACPI_MAX_ADDRESS_SPACE)) { + return (AE_BAD_PARAMETER); + } + +@@ -96,8 +95,7 @@ + if ((node->type != ACPI_TYPE_DEVICE) && + (node->type != ACPI_TYPE_PROCESSOR) && + (node->type != ACPI_TYPE_THERMAL) && +- (node != acpi_gbl_root_node)) +- { ++ (node != acpi_gbl_root_node)) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } +@@ -105,8 +103,7 @@ + if (handler == ACPI_DEFAULT_HANDLER) { + flags = ADDR_HANDLER_DEFAULT_INSTALLED; + +- switch (space_id) +- { ++ switch (space_id) { + case ADDRESS_SPACE_SYSTEM_MEMORY: + handler = acpi_aml_system_memory_space_handler; + setup = acpi_ev_system_memory_region_setup; +@@ -140,7 +137,7 @@ + * Check for an existing internal object + */ + +- obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) node); ++ obj_desc = acpi_ns_get_attached_object (node); + if (obj_desc) { + /* + * The object exists. +@@ -283,8 +280,7 @@ + + if ((!device) || + ((!handler) && (handler != ACPI_DEFAULT_HANDLER)) || +- (space_id > ACPI_MAX_ADDRESS_SPACE)) +- { ++ (space_id > ACPI_MAX_ADDRESS_SPACE)) { + return (AE_BAD_PARAMETER); + } + +@@ -301,7 +297,7 @@ + + /* Make sure the internal object exists */ + +- obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) node); ++ obj_desc = acpi_ns_get_attached_object (node); + if (!obj_desc) { + /* + * The object DNE. +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/Makefile linux/drivers/acpi/executer/Makefile +--- /usr/src/linux/drivers/acpi/executer/Makefile Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/Makefile Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,17 @@ ++# ++# Makefile for all Linux ACPI interpreter subdirectories ++# EXCEPT for the ospm directory ++# ++ ++O_TARGET := ../$(shell basename `pwd`).o ++ ++obj-$(CONFIG_ACPI) := $(patsubst %.c,%.o,$(wildcard *.c)) ++ ++EXTRA_CFLAGS += -I../include ++ ++EXTRA_CFLAGS += $(ACPI_CFLAGS) ++ ++include $(TOPDIR)/Rules.make ++ ++clean: ++ $(RM) *.o +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/amconfig.c linux/drivers/acpi/executer/amconfig.c +--- /usr/src/linux/drivers/acpi/executer/amconfig.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/amconfig.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,304 @@ ++/****************************************************************************** ++ * ++ * Module Name: amconfig - Namespace reconfiguration (Load/Unload opcodes) ++ * $Revision: 31 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acparser.h" ++#include "acinterp.h" ++#include "amlcode.h" ++#include "acnamesp.h" ++#include "acevents.h" ++#include "actables.h" ++#include "acdispat.h" ++ ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("amconfig") ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Acpi_aml_exec_load_table ++ * ++ * PARAMETERS: Rgn_desc - Op region where the table will be obtained ++ * Ddb_handle - Where a handle to the table will be returned ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Load an ACPI table ++ * ++ ****************************************************************************/ ++ ++static ACPI_STATUS ++acpi_aml_exec_load_table ( ++ ACPI_OPERAND_OBJECT *rgn_desc, ++ ACPI_HANDLE *ddb_handle) ++{ ++ ACPI_STATUS status; ++ ACPI_OPERAND_OBJECT *table_desc = NULL; ++ u8 *table_ptr; ++ u8 *table_data_ptr; ++ ACPI_TABLE_HEADER table_header; ++ ACPI_TABLE_DESC table_info; ++ u32 i; ++ ++ ++ /* TBD: [Unhandled] Object can be either a field or an opregion */ ++ ++ ++ /* Get the table header */ ++ ++ table_header.length = 0; ++ for (i = 0; i < sizeof (ACPI_TABLE_HEADER); i++) { ++ status = acpi_ev_address_space_dispatch (rgn_desc, ADDRESS_SPACE_READ, ++ (ACPI_PHYSICAL_ADDRESS) i, 8, ++ (u32 *) ((u8 *) &table_header + i)); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ } ++ ++ /* Allocate a buffer for the entire table */ ++ ++ table_ptr = acpi_cm_allocate (table_header.length); ++ if (!table_ptr) { ++ return (AE_NO_MEMORY); ++ } ++ ++ /* Copy the header to the buffer */ ++ ++ MEMCPY (table_ptr, &table_header, sizeof (ACPI_TABLE_HEADER)); ++ table_data_ptr = table_ptr + sizeof (ACPI_TABLE_HEADER); ++ ++ ++ /* Get the table from the op region */ ++ ++ for (i = 0; i < table_header.length; i++) { ++ status = acpi_ev_address_space_dispatch (rgn_desc, ADDRESS_SPACE_READ, ++ (ACPI_PHYSICAL_ADDRESS)i, 8, ++ (u32 *) (table_data_ptr + i)); ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ } ++ ++ ++ /* Table must be either an SSDT or a PSDT */ ++ ++ if ((!STRNCMP (table_header.signature, ++ acpi_gbl_acpi_table_data[ACPI_TABLE_PSDT].signature, ++ acpi_gbl_acpi_table_data[ACPI_TABLE_PSDT].sig_length)) && ++ (!STRNCMP (table_header.signature, ++ acpi_gbl_acpi_table_data[ACPI_TABLE_SSDT].signature, ++ acpi_gbl_acpi_table_data[ACPI_TABLE_SSDT].sig_length))) { ++ status = AE_BAD_SIGNATURE; ++ goto cleanup; ++ } ++ ++ /* Create an object to be the table handle */ ++ ++ table_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_REFERENCE); ++ if (!table_desc) { ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ ++ /* Install the new table into the local data structures */ ++ ++ table_info.pointer = (ACPI_TABLE_HEADER *) table_ptr; ++ table_info.length = table_header.length; ++ table_info.allocation = ACPI_MEM_ALLOCATED; ++ table_info.base_pointer = table_ptr; ++ ++ status = acpi_tb_install_table (NULL, &table_info); ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ ++ /* Add the table to the namespace */ ++ ++ /* TBD: [Restructure] - change to whatever new interface is appropriate */ ++/* ++ Status = Acpi_load_namespace (); ++ if (ACPI_FAILURE (Status)) ++ { ++*/ ++ /* TBD: [Errors] Unload the table on failure ? */ ++/* ++ goto Cleanup; ++ } ++*/ ++ ++ ++ /* TBD: [Investigate] we need a pointer to the table desc */ ++ ++ /* Init the table handle */ ++ ++ table_desc->reference.opcode = AML_LOAD_OP; ++ table_desc->reference.object = table_info.installed_desc; ++ ++ *ddb_handle = table_desc; ++ ++ return (status); ++ ++ ++cleanup: ++ ++ acpi_cm_free (table_desc); ++ acpi_cm_free (table_ptr); ++ return (status); ++ ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Acpi_aml_exec_unload_table ++ * ++ * PARAMETERS: Ddb_handle - Handle to a previously loaded table ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Unload an ACPI table ++ * ++ ****************************************************************************/ ++ ++static ACPI_STATUS ++acpi_aml_exec_unload_table ( ++ ACPI_HANDLE ddb_handle) ++{ ++ ACPI_STATUS status = AE_NOT_IMPLEMENTED; ++ ACPI_OPERAND_OBJECT *table_desc = (ACPI_OPERAND_OBJECT *) ddb_handle; ++ ACPI_TABLE_DESC *table_info; ++ ++ ++ /* Validate the handle */ ++ /* Although the handle is partially validated in Acpi_aml_exec_reconfiguration(), ++ * when it calls Acpi_aml_resolve_operands(), the handle is more completely ++ * validated here. ++ */ ++ ++ if ((!ddb_handle) || ++ (!VALID_DESCRIPTOR_TYPE (ddb_handle, ACPI_DESC_TYPE_INTERNAL)) || ++ (((ACPI_OPERAND_OBJECT *)ddb_handle)->common.type != ++ INTERNAL_TYPE_REFERENCE)) { ++ return (AE_BAD_PARAMETER); ++ } ++ ++ ++ /* Get the actual table descriptor from the Ddb_handle */ ++ ++ table_info = (ACPI_TABLE_DESC *) table_desc->reference.object; ++ ++ /* ++ * Delete the entire namespace under this table Node ++ * (Offset contains the Table_id) ++ */ ++ ++ status = acpi_ns_delete_namespace_by_owner (table_info->table_id); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ /* Delete the table itself */ ++ ++ acpi_tb_uninstall_table (table_info->installed_desc); ++ ++ /* Delete the table descriptor (Ddb_handle) */ ++ ++ acpi_cm_remove_reference (table_desc); ++ ++ return (status); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Acpi_aml_exec_reconfiguration ++ * ++ * PARAMETERS: Opcode - The opcode to be executed ++ * Walk_state - Current state of the parse tree walk ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Reconfiguration opcodes such as LOAD and UNLOAD ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_exec_reconfiguration ( ++ u16 opcode, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_STATUS status; ++ ACPI_OPERAND_OBJECT *region_desc = NULL; ++ ACPI_HANDLE *ddb_handle; ++ ++ ++ /* Resolve the operands */ ++ ++ status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); ++ /* Get the table handle, common for both opcodes */ ++ ++ status |= acpi_ds_obj_stack_pop_object ((ACPI_OPERAND_OBJECT **) &ddb_handle, ++ walk_state); ++ ++ switch (opcode) { ++ ++ case AML_LOAD_OP: ++ ++ /* Get the region or field descriptor */ ++ ++ status |= acpi_ds_obj_stack_pop_object (®ion_desc, walk_state); ++ if (ACPI_FAILURE (status)) { ++ acpi_cm_remove_reference (region_desc); ++ return (status); ++ } ++ ++ status = acpi_aml_exec_load_table (region_desc, ddb_handle); ++ break; ++ ++ ++ case AML_UNLOAD_OP: ++ ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ status = acpi_aml_exec_unload_table (ddb_handle); ++ break; ++ ++ ++ default: ++ ++ status = AE_AML_BAD_OPCODE; ++ break; ++ } ++ ++ ++ return (status); ++} ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/amconvrt.c linux/drivers/acpi/executer/amconvrt.c +--- /usr/src/linux/drivers/acpi/executer/amconvrt.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/amconvrt.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,518 @@ ++/****************************************************************************** ++ * ++ * Module Name: amconvrt - Object conversion routines ++ * $Revision: 10 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acparser.h" ++#include "acnamesp.h" ++#include "acinterp.h" ++#include "acevents.h" ++#include "amlcode.h" ++#include "acdispat.h" ++ ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("amconvrt") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_convert_to_integer ++ * ++ * PARAMETERS: *Obj_desc - Object to be converted. Must be an ++ * Integer, Buffer, or String ++ * Walk_state - Current method state ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Convert an ACPI Object to an integer. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_convert_to_integer ( ++ ACPI_OPERAND_OBJECT **obj_desc, ++ ACPI_WALK_STATE *walk_state) ++{ ++ u32 i; ++ ACPI_OPERAND_OBJECT *ret_desc; ++ u32 count; ++ char *pointer; ++ ACPI_INTEGER result; ++ u32 integer_size = sizeof (ACPI_INTEGER); ++ ++ ++ switch ((*obj_desc)->common.type) { ++ case ACPI_TYPE_INTEGER: ++ return (AE_OK); ++ ++ case ACPI_TYPE_STRING: ++ pointer = (*obj_desc)->string.pointer; ++ count = (*obj_desc)->string.length; ++ break; ++ ++ case ACPI_TYPE_BUFFER: ++ pointer = (char *) (*obj_desc)->buffer.pointer; ++ count = (*obj_desc)->buffer.length; ++ break; ++ ++ default: ++ return (AE_TYPE); ++ } ++ ++ /* ++ * Create a new integer ++ */ ++ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); ++ if (!ret_desc) { ++ return (AE_NO_MEMORY); ++ } ++ ++ ++ /* Handle both ACPI 1.0 and ACPI 2.0 Integer widths */ ++ ++ if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) { ++ /* ++ * We are running a method that exists in a 32-bit ACPI table. ++ * Truncate the value to 32 bits by zeroing out the upper 32-bit field ++ */ ++ integer_size = sizeof (u32); ++ } ++ ++ ++ /* ++ * Convert the buffer/string to an integer. Note that both buffers and ++ * strings are treated as raw data - we don't convert ascii to hex for ++ * strings. ++ * ++ * There are two terminating conditions for the loop: ++ * 1) The size of an integer has been reached, or ++ * 2) The end of the buffer or string has been reached ++ */ ++ result = 0; ++ ++ /* Transfer no more than an integer's worth of data */ ++ ++ if (count > integer_size) { ++ count = integer_size; ++ } ++ ++ /* ++ * String conversion is different than Buffer conversion ++ */ ++ switch ((*obj_desc)->common.type) { ++ case ACPI_TYPE_STRING: ++ ++ /* TBD: Need to use 64-bit STRTOUL */ ++ ++ /* ++ * Convert string to an integer ++ * String must be hexadecimal as per the ACPI specification ++ */ ++ ++ result = STRTOUL (pointer, NULL, 16); ++ break; ++ ++ ++ case ACPI_TYPE_BUFFER: ++ ++ /* ++ * Buffer conversion - we simply grab enough raw data from the ++ * buffer to fill an integer ++ */ ++ for (i = 0; i < count; i++) { ++ /* ++ * Get next byte and shift it into the Result. ++ * Little endian is used, meaning that the first byte of the buffer ++ * is the LSB of the integer ++ */ ++ result |= (((ACPI_INTEGER) pointer[i]) << (i * 8)); ++ } ++ ++ break; ++ } ++ ++ /* Save the Result, delete original descriptor, store new descriptor */ ++ ++ ret_desc->integer.value = result; ++ ++ if (walk_state->opcode != AML_STORE_OP) { ++ acpi_cm_remove_reference (*obj_desc); ++ } ++ ++ *obj_desc = ret_desc; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_convert_to_buffer ++ * ++ * PARAMETERS: *Obj_desc - Object to be converted. Must be an ++ * Integer, Buffer, or String ++ * Walk_state - Current method state ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Convert an ACPI Object to an Buffer ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_convert_to_buffer ( ++ ACPI_OPERAND_OBJECT **obj_desc, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_OPERAND_OBJECT *ret_desc; ++ u32 i; ++ u32 integer_size = sizeof (ACPI_INTEGER); ++ u8 *new_buf; ++ ++ ++ switch ((*obj_desc)->common.type) { ++ case ACPI_TYPE_INTEGER: ++ ++ /* ++ * Create a new Buffer ++ */ ++ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_BUFFER); ++ if (!ret_desc) { ++ return (AE_NO_MEMORY); ++ } ++ ++ /* Handle both ACPI 1.0 and ACPI 2.0 Integer widths */ ++ ++ if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) { ++ /* ++ * We are running a method that exists in a 32-bit ACPI table. ++ * Truncate the value to 32 bits by zeroing out the upper ++ * 32-bit field ++ */ ++ integer_size = sizeof (u32); ++ } ++ ++ /* Need enough space for one integers */ ++ ++ ret_desc->buffer.length = integer_size; ++ new_buf = acpi_cm_callocate (integer_size); ++ if (!new_buf) { ++ REPORT_ERROR ++ (("Aml_exec_dyadic2_r/Concat_op: Buffer allocation failure\n")); ++ acpi_cm_remove_reference (ret_desc); ++ return (AE_NO_MEMORY); ++ } ++ ++ /* Copy the integer to the buffer */ ++ ++ for (i = 0; i < integer_size; i++) { ++ new_buf[i] = (u8) ((*obj_desc)->integer.value >> (i * 8)); ++ } ++ ret_desc->buffer.pointer = new_buf; ++ ++ /* Return the new buffer descriptor */ ++ ++ if (walk_state->opcode != AML_STORE_OP) { ++ acpi_cm_remove_reference (*obj_desc); ++ } ++ *obj_desc = ret_desc; ++ break; ++ ++ ++ case ACPI_TYPE_STRING: ++ break; ++ ++ ++ case ACPI_TYPE_BUFFER: ++ break; ++ ++ ++ default: ++ return (AE_TYPE); ++ break; ++ } ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_convert_to_string ++ * ++ * PARAMETERS: *Obj_desc - Object to be converted. Must be an ++ * Integer, Buffer, or String ++ * Walk_state - Current method state ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Convert an ACPI Object to a string ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_convert_to_string ( ++ ACPI_OPERAND_OBJECT **obj_desc, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_OPERAND_OBJECT *ret_desc; ++ u32 i; ++ u32 index; ++ u32 integer_size = sizeof (ACPI_INTEGER); ++ u8 *new_buf; ++ u8 *pointer; ++ ++ ++ switch ((*obj_desc)->common.type) { ++ case ACPI_TYPE_INTEGER: ++ ++ /* ++ * Create a new String ++ */ ++ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_STRING); ++ if (!ret_desc) { ++ return (AE_NO_MEMORY); ++ } ++ ++ /* Handle both ACPI 1.0 and ACPI 2.0 Integer widths */ ++ ++ if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) { ++ /* ++ * We are running a method that exists in a 32-bit ACPI table. ++ * Truncate the value to 32 bits by zeroing out the upper ++ * 32-bit field ++ */ ++ integer_size = sizeof (u32); ++ } ++ ++ /* Need enough space for one ASCII integer plus null terminator */ ++ ++ ret_desc->string.length = (integer_size * 2) + 1; ++ new_buf = acpi_cm_callocate (ret_desc->string.length); ++ if (!new_buf) { ++ REPORT_ERROR ++ (("Aml_exec_dyadic2_r/Concat_op: Buffer allocation failure\n")); ++ acpi_cm_remove_reference (ret_desc); ++ return (AE_NO_MEMORY); ++ } ++ ++ /* Copy the integer to the buffer */ ++ ++ for (i = 0; i < (integer_size * 2); i++) { ++ new_buf[i] = acpi_gbl_hex_to_ascii [((*obj_desc)->integer.value >> (i * 4)) & 0xF]; ++ } ++ ++ /* Null terminate */ ++ ++ new_buf [i] = 0; ++ ret_desc->buffer.pointer = new_buf; ++ ++ /* Return the new buffer descriptor */ ++ ++ if (walk_state->opcode != AML_STORE_OP) { ++ acpi_cm_remove_reference (*obj_desc); ++ } ++ *obj_desc = ret_desc; ++ ++ return (AE_OK); ++ ++ ++ case ACPI_TYPE_BUFFER: ++ ++ if (((*obj_desc)->buffer.length * 3) > ACPI_MAX_STRING_CONVERSION) { ++ return (AE_AML_STRING_LIMIT); ++ } ++ ++ /* ++ * Create a new String ++ */ ++ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_STRING); ++ if (!ret_desc) { ++ return (AE_NO_MEMORY); ++ } ++ ++ /* Need enough space for one ASCII integer plus null terminator */ ++ ++ ret_desc->string.length = (*obj_desc)->buffer.length * 3; ++ new_buf = acpi_cm_callocate (ret_desc->string.length + 1); ++ if (!new_buf) { ++ REPORT_ERROR ++ (("Aml_exec_dyadic2_r/Concat_op: Buffer allocation failure\n")); ++ acpi_cm_remove_reference (ret_desc); ++ return (AE_NO_MEMORY); ++ } ++ ++ /* ++ * Convert each byte of the buffer to two ASCII characters plus a space. ++ */ ++ pointer = (*obj_desc)->buffer.pointer; ++ index = 0; ++ for (i = 0; i < (*obj_desc)->buffer.length; i++) { ++ new_buf[index + 0] = acpi_gbl_hex_to_ascii [pointer[i] & 0x0F]; ++ new_buf[index + 1] = acpi_gbl_hex_to_ascii [(pointer[i] >> 4) & 0x0F]; ++ new_buf[index + 2] = ' '; ++ index += 3; ++ } ++ ++ /* Null terminate */ ++ ++ new_buf [index] = 0; ++ ret_desc->buffer.pointer = new_buf; ++ ++ /* Return the new buffer descriptor */ ++ ++ if (walk_state->opcode != AML_STORE_OP) { ++ acpi_cm_remove_reference (*obj_desc); ++ } ++ *obj_desc = ret_desc; ++ break; ++ ++ ++ case ACPI_TYPE_STRING: ++ break; ++ ++ ++ default: ++ return (AE_TYPE); ++ break; ++ } ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_convert_to_target_type ++ * ++ * PARAMETERS: *Obj_desc - Object to be converted. ++ * Walk_state - Current method state ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_convert_to_target_type ( ++ OBJECT_TYPE_INTERNAL destination_type, ++ ACPI_OPERAND_OBJECT **obj_desc, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ ++ /* ++ * If required by the target, ++ * perform implicit conversion on the source before we store it. ++ */ ++ ++ switch (GET_CURRENT_ARG_TYPE (walk_state->op_info->runtime_args)) { ++ case ARGI_SIMPLE_TARGET: ++ case ARGI_FIXED_TARGET: ++ case ARGI_INTEGER_REF: /* Handles Increment, Decrement cases */ ++ ++ switch (destination_type) { ++ case INTERNAL_TYPE_REGION_FIELD: ++ /* ++ * Named field can always handle conversions ++ */ ++ break; ++ ++ default: ++ /* No conversion allowed for these types */ ++ ++ if (destination_type != (*obj_desc)->common.type) { ++ status = AE_TYPE; ++ } ++ } ++ break; ++ ++ ++ case ARGI_TARGETREF: ++ ++ switch (destination_type) { ++ case ACPI_TYPE_INTEGER: ++ case ACPI_TYPE_BUFFER_FIELD: ++ case INTERNAL_TYPE_BANK_FIELD: ++ case INTERNAL_TYPE_INDEX_FIELD: ++ /* ++ * These types require an Integer operand. We can convert ++ * a Buffer or a String to an Integer if necessary. ++ */ ++ status = acpi_aml_convert_to_integer (obj_desc, walk_state); ++ break; ++ ++ ++ case ACPI_TYPE_STRING: ++ ++ /* ++ * The operand must be a String. We can convert an ++ * Integer or Buffer if necessary ++ */ ++ status = acpi_aml_convert_to_string (obj_desc, walk_state); ++ break; ++ ++ ++ case ACPI_TYPE_BUFFER: ++ ++ /* ++ * The operand must be a String. We can convert an ++ * Integer or Buffer if necessary ++ */ ++ status = acpi_aml_convert_to_buffer (obj_desc, walk_state); ++ break; ++ } ++ break; ++ ++ ++ case ARGI_REFERENCE: ++ /* ++ * Create_xxxx_field cases - we are storing the field object into the name ++ */ ++ break; ++ ++ ++ default: ++ status = AE_AML_INTERNAL; ++ } ++ ++ ++ /* ++ * Source-to-Target conversion semantics: ++ * ++ * If conversion to the target type cannot be performed, then simply ++ * overwrite the target with the new object and type. ++ */ ++ if (status == AE_TYPE) { ++ status = AE_OK; ++ } ++ ++ return (status); ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/amcreate.c linux/drivers/acpi/executer/amcreate.c +--- /usr/src/linux/drivers/acpi/executer/amcreate.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/amcreate.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,706 @@ ++/****************************************************************************** ++ * ++ * Module Name: amcreate - Named object creation ++ * $Revision: 60 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acparser.h" ++#include "acinterp.h" ++#include "amlcode.h" ++#include "acnamesp.h" ++#include "acevents.h" ++#include "acdispat.h" ++ ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("amcreate") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_create_buffer_field ++ * ++ * PARAMETERS: Opcode - The opcode to be executed ++ * Operands - List of operands for the opcode ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Execute Create_field operators: Create_bit_field_op, ++ * Create_byte_field_op, Create_word_field_op, Create_dWord_field_op, ++ * Create_field_op (which define fields in buffers) ++ * ++ * ALLOCATION: Deletes Create_field_op's count operand descriptor ++ * ++ * ++ * ACPI SPECIFICATION REFERENCES: ++ * Def_create_bit_field := Create_bit_field_op Src_buf Bit_idx Name_string ++ * Def_create_byte_field := Create_byte_field_op Src_buf Byte_idx Name_string ++ * Def_create_dWord_field := Create_dWord_field_op Src_buf Byte_idx Name_string ++ * Def_create_field := Create_field_op Src_buf Bit_idx Num_bits Name_string ++ * Def_create_word_field := Create_word_field_op Src_buf Byte_idx Name_string ++ * Bit_index := Term_arg=>Integer ++ * Byte_index := Term_arg=>Integer ++ * Num_bits := Term_arg=>Integer ++ * Source_buff := Term_arg=>Buffer ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_create_buffer_field ( ++ u8 *aml_ptr, ++ u32 aml_length, ++ ACPI_NAMESPACE_NODE *node, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_STATUS status; ++ ACPI_OPERAND_OBJECT *obj_desc; ++ ACPI_OPERAND_OBJECT *tmp_desc; ++ ++ ++ /* Create the descriptor */ ++ ++ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_BUFFER_FIELD); ++ if (!obj_desc) { ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ ++ /* ++ * Allocate a method object for this field unit ++ */ ++ ++ obj_desc->buffer_field.extra = acpi_cm_create_internal_object ( ++ INTERNAL_TYPE_EXTRA); ++ if (!obj_desc->buffer_field.extra) { ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ /* ++ * Remember location in AML stream of the field unit ++ * opcode and operands -- since the buffer and index ++ * operands must be evaluated. ++ */ ++ ++ obj_desc->buffer_field.extra->extra.pcode = aml_ptr; ++ obj_desc->buffer_field.extra->extra.pcode_length = aml_length; ++ obj_desc->buffer_field.node = node; ++ ++ ++ /* ++ * This operation is supposed to cause the destination Name to refer ++ * to the defined Buffer_field -- it must not store the constructed ++ * Buffer_field object (or its current value) in some location that the ++ * Name may already be pointing to. So, if the Name currently contains ++ * a reference which would cause Acpi_aml_exec_store() to perform an indirect ++ * store rather than setting the value of the Name itself, clobber that ++ * reference before calling Acpi_aml_exec_store(). ++ */ ++ ++ /* Type of Name's existing value */ ++ ++ switch (acpi_ns_get_type (node)) { ++ ++ case ACPI_TYPE_BUFFER_FIELD: ++ case INTERNAL_TYPE_ALIAS: ++ case INTERNAL_TYPE_REGION_FIELD: ++ case INTERNAL_TYPE_BANK_FIELD: ++ case INTERNAL_TYPE_INDEX_FIELD: ++ ++ tmp_desc = acpi_ns_get_attached_object (node); ++ if (tmp_desc) { ++ /* ++ * There is an existing object here; delete it and zero out the ++ * object field within the Node ++ */ ++ ++ acpi_cm_remove_reference (tmp_desc); ++ acpi_ns_attach_object ((ACPI_NAMESPACE_NODE *) node, NULL, ++ ACPI_TYPE_ANY); ++ } ++ ++ /* Set the type to ANY (or the store below will fail) */ ++ ++ ((ACPI_NAMESPACE_NODE *) node)->type = ACPI_TYPE_ANY; ++ ++ break; ++ ++ ++ default: ++ ++ break; ++ } ++ ++ ++ /* Store constructed field descriptor in result location */ ++ ++ status = acpi_aml_exec_store (obj_desc, (ACPI_OPERAND_OBJECT *) node, ++ walk_state); ++ ++ /* ++ * If the field descriptor was not physically stored (or if a failure ++ * above), we must delete it ++ */ ++ if (obj_desc->common.reference_count <= 1) { ++ acpi_cm_remove_reference (obj_desc); ++ } ++ ++ ++ return (AE_OK); ++ ++ ++cleanup: ++ ++ /* Delete region object and method subobject */ ++ ++ if (obj_desc) { ++ /* Remove deletes both objects! */ ++ ++ acpi_cm_remove_reference (obj_desc); ++ obj_desc = NULL; ++ } ++ ++ return (status); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Acpi_aml_exec_create_alias ++ * ++ * PARAMETERS: Walk_state - Current state, contains List of ++ * operands for the opcode ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Create a new named alias ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_exec_create_alias ( ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_NAMESPACE_NODE *source_node; ++ ACPI_NAMESPACE_NODE *alias_node; ++ ACPI_STATUS status; ++ ++ ++ /* Get the source/alias operands (both namespace nodes) */ ++ ++ status = acpi_ds_obj_stack_pop_object ((ACPI_OPERAND_OBJECT **) &source_node, ++ walk_state); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ /* ++ * Don't pop it, it gets removed in the calling routine ++ */ ++ alias_node = acpi_ds_obj_stack_get_value (0, walk_state); ++ ++ /* Add an additional reference to the object */ ++ ++ acpi_cm_add_reference (source_node->object); ++ ++ /* ++ * Attach the original source Node to the new Alias Node. ++ */ ++ status = acpi_ns_attach_object (alias_node, source_node->object, ++ source_node->type); ++ ++ ++ /* ++ * The new alias assumes the type of the source, but it points ++ * to the same object. The reference count of the object has two ++ * additional references to prevent deletion out from under either the ++ * source or the alias Node ++ */ ++ ++ /* Since both operands are Nodes, we don't need to delete them */ ++ ++ return (status); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Acpi_aml_exec_create_event ++ * ++ * PARAMETERS: None ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Create a new event object ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_exec_create_event ( ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_STATUS status; ++ ACPI_OPERAND_OBJECT *obj_desc; ++ ++ ++ BREAKPOINT3; ++ ++ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_EVENT); ++ if (!obj_desc) { ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ /* Create the actual OS semaphore */ ++ ++ /* TBD: [Investigate] should be created with 0 or 1 units? */ ++ ++ status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, 1, ++ &obj_desc->event.semaphore); ++ if (ACPI_FAILURE (status)) { ++ acpi_cm_remove_reference (obj_desc); ++ goto cleanup; ++ } ++ ++ /* Attach object to the Node */ ++ ++ status = acpi_ns_attach_object (acpi_ds_obj_stack_get_value (0, walk_state), ++ obj_desc, (u8) ACPI_TYPE_EVENT); ++ if (ACPI_FAILURE (status)) { ++ acpi_os_delete_semaphore (obj_desc->event.semaphore); ++ acpi_cm_remove_reference (obj_desc); ++ goto cleanup; ++ } ++ ++ ++cleanup: ++ ++ return (status); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Acpi_aml_exec_create_mutex ++ * ++ * PARAMETERS: Interpreter_mode - Current running mode (load1/Load2/Exec) ++ * Operands - List of operands for the opcode ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Create a new mutex object ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_exec_create_mutex ( ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_STATUS status = AE_OK; ++ ACPI_OPERAND_OBJECT *sync_desc; ++ ACPI_OPERAND_OBJECT *obj_desc; ++ ++ ++ /* Get the operand */ ++ ++ status = acpi_ds_obj_stack_pop_object (&sync_desc, walk_state); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ /* Attempt to allocate a new object */ ++ ++ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_MUTEX); ++ if (!obj_desc) { ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ /* Create the actual OS semaphore */ ++ ++ status = acpi_os_create_semaphore (1, 1, &obj_desc->mutex.semaphore); ++ if (ACPI_FAILURE (status)) { ++ acpi_cm_remove_reference (obj_desc); ++ goto cleanup; ++ } ++ ++ obj_desc->mutex.sync_level = (u8) sync_desc->integer.value; ++ ++ /* Obj_desc was on the stack top, and the name is below it */ ++ ++ status = acpi_ns_attach_object (acpi_ds_obj_stack_get_value (0, walk_state), ++ obj_desc, (u8) ACPI_TYPE_MUTEX); ++ if (ACPI_FAILURE (status)) { ++ acpi_os_delete_semaphore (obj_desc->mutex.semaphore); ++ acpi_cm_remove_reference (obj_desc); ++ goto cleanup; ++ } ++ ++ ++cleanup: ++ ++ /* Always delete the operand */ ++ ++ acpi_cm_remove_reference (sync_desc); ++ ++ return (status); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Acpi_aml_exec_create_region ++ * ++ * PARAMETERS: Aml_ptr - Pointer to the region declaration AML ++ * Aml_length - Max length of the declaration AML ++ * Operands - List of operands for the opcode ++ * Interpreter_mode - Load1/Load2/Execute ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Create a new operation region object ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_exec_create_region ( ++ u8 *aml_ptr, ++ u32 aml_length, ++ u8 region_space, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_STATUS status; ++ ACPI_OPERAND_OBJECT *obj_desc; ++ ACPI_NAMESPACE_NODE *node; ++ ++ ++ /* ++ * Space ID must be one of the predefined IDs, or in the user-defined ++ * range ++ */ ++ if ((region_space >= NUM_REGION_TYPES) && ++ (region_space < USER_REGION_BEGIN)) { ++ REPORT_ERROR (("Invalid Address_space type %X\n", region_space)); ++ return (AE_AML_INVALID_SPACE_ID); ++ } ++ ++ ++ /* Get the Node from the object stack */ ++ ++ node = (ACPI_NAMESPACE_NODE *) acpi_ds_obj_stack_get_value (0, walk_state); ++ ++ /* Create the region descriptor */ ++ ++ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_REGION); ++ if (!obj_desc) { ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ /* ++ * Allocate a method object for this region. ++ */ ++ ++ obj_desc->region.extra = acpi_cm_create_internal_object ( ++ INTERNAL_TYPE_EXTRA); ++ if (!obj_desc->region.extra) { ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ /* ++ * Remember location in AML stream of address & length ++ * operands since they need to be evaluated at run time. ++ */ ++ ++ obj_desc->region.extra->extra.pcode = aml_ptr; ++ obj_desc->region.extra->extra.pcode_length = aml_length; ++ ++ /* Init the region from the operands */ ++ ++ obj_desc->region.space_id = region_space; ++ obj_desc->region.address = 0; ++ obj_desc->region.length = 0; ++ ++ ++ /* Install the new region object in the parent Node */ ++ ++ obj_desc->region.node = node; ++ ++ status = acpi_ns_attach_object (node, obj_desc, ++ (u8) ACPI_TYPE_REGION); ++ ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ ++ /* ++ * If we have a valid region, initialize it ++ * Namespace is NOT locked at this point. ++ */ ++ ++ status = acpi_ev_initialize_region (obj_desc, FALSE); ++ ++ if (ACPI_FAILURE (status)) { ++ /* ++ * If AE_NOT_EXIST is returned, it is not fatal ++ * because many regions get created before a handler ++ * is installed for said region. ++ */ ++ if (AE_NOT_EXIST == status) { ++ status = AE_OK; ++ } ++ } ++ ++cleanup: ++ ++ if (ACPI_FAILURE (status)) { ++ /* Delete region object and method subobject */ ++ ++ if (obj_desc) { ++ /* Remove deletes both objects! */ ++ ++ acpi_cm_remove_reference (obj_desc); ++ obj_desc = NULL; ++ } ++ } ++ ++ return (status); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Acpi_aml_exec_create_processor ++ * ++ * PARAMETERS: Op - Op containing the Processor definition and ++ * args ++ * Processor_node - Parent Node for the processor object ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Create a new processor object and populate the fields ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_exec_create_processor ( ++ ACPI_PARSE_OBJECT *op, ++ ACPI_NAMESPACE_NODE *processor_node) ++{ ++ ACPI_STATUS status; ++ ACPI_PARSE_OBJECT *arg; ++ ACPI_OPERAND_OBJECT *obj_desc; ++ ++ ++ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_PROCESSOR); ++ if (!obj_desc) { ++ return (AE_NO_MEMORY); ++ } ++ ++ /* Install the new processor object in the parent Node */ ++ ++ status = acpi_ns_attach_object (processor_node, obj_desc, ++ (u8) ACPI_TYPE_PROCESSOR); ++ if (ACPI_FAILURE (status)) { ++ acpi_cm_delete_object_desc (obj_desc); ++ return (status); ++ } ++ ++ /* Get first arg and verify existence */ ++ ++ arg = op->value.arg; ++ if (!arg) { ++ return (AE_AML_NO_OPERAND); ++ } ++ ++ /* First arg is the Processor ID */ ++ ++ obj_desc->processor.proc_id = (u8) arg->value.integer; ++ ++ /* Get second arg and verify existence */ ++ ++ arg = arg->next; ++ if (!arg) { ++ return (AE_AML_NO_OPERAND); ++ } ++ ++ /* Second arg is the PBlock Address */ ++ ++ obj_desc->processor.address = (ACPI_IO_ADDRESS) arg->value.integer; ++ ++ /* Get third arg and verify existence */ ++ ++ arg = arg->next; ++ if (!arg) { ++ return (AE_AML_NO_OPERAND); ++ } ++ ++ /* Third arg is the PBlock Length */ ++ ++ obj_desc->processor.length = (u8) arg->value.integer; ++ return (AE_OK); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Acpi_aml_exec_create_power_resource ++ * ++ * PARAMETERS: Op - Op containing the Power_resource definition ++ * and args ++ * Power_node - Parent Node for the power object ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Create a new Power_resource object and populate the fields ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_exec_create_power_resource ( ++ ACPI_PARSE_OBJECT *op, ++ ACPI_NAMESPACE_NODE *power_node) ++{ ++ ACPI_STATUS status; ++ ACPI_PARSE_OBJECT *arg; ++ ACPI_OPERAND_OBJECT *obj_desc; ++ ++ ++ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_POWER); ++ if (!obj_desc) { ++ return (AE_NO_MEMORY); ++ } ++ ++ /* Install the new power resource object in the parent Node */ ++ ++ status = acpi_ns_attach_object (power_node, obj_desc, ++ (u8) ACPI_TYPE_POWER); ++ if (ACPI_FAILURE (status)) { ++ return(status); ++ } ++ ++ ++ /* Get first arg and verify existence */ ++ ++ arg = op->value.arg; ++ if (!arg) { ++ return (AE_AML_NO_OPERAND); ++ } ++ ++ /* First arg is the System_level */ ++ ++ obj_desc->power_resource.system_level = (u8) arg->value.integer; ++ ++ /* Get second arg and check existence */ ++ ++ arg = arg->next; ++ if (!arg) { ++ return (AE_AML_NO_OPERAND); ++ } ++ ++ /* Second arg is the PBlock Address */ ++ ++ obj_desc->power_resource.resource_order = (u16) arg->value.integer; ++ ++ return (AE_OK); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Acpi_aml_exec_create_method ++ * ++ * PARAMETERS: Aml_ptr - First byte of the method's AML ++ * Aml_length - AML byte count for this method ++ * Method_flags - AML method flag byte ++ * Method - Method Node ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Create a new method object ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_exec_create_method ( ++ u8 *aml_ptr, ++ u32 aml_length, ++ u32 method_flags, ++ ACPI_NAMESPACE_NODE *method) ++{ ++ ACPI_OPERAND_OBJECT *obj_desc; ++ ACPI_STATUS status; ++ ++ ++ /* Create a new method object */ ++ ++ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_METHOD); ++ if (!obj_desc) { ++ return (AE_NO_MEMORY); ++ } ++ ++ /* Get the method's AML pointer/length from the Op */ ++ ++ obj_desc->method.pcode = aml_ptr; ++ obj_desc->method.pcode_length = aml_length; ++ ++ /* ++ * First argument is the Method Flags (contains parameter count for the ++ * method) ++ */ ++ ++ obj_desc->method.method_flags = (u8) method_flags; ++ obj_desc->method.param_count = (u8) (method_flags & ++ METHOD_FLAGS_ARG_COUNT); ++ ++ /* ++ * Get the concurrency count. If required, a semaphore will be ++ * created for this method when it is parsed. ++ */ ++ if (method_flags & METHOD_FLAGS_SERIALIZED) { ++ /* ++ * ACPI 1.0: Concurrency = 1 ++ * ACPI 2.0: Concurrency = (Sync_level (in method declaration) + 1) ++ */ ++ obj_desc->method.concurrency = (u8) ++ (((method_flags & METHOD_FLAGS_SYNCH_LEVEL) >> 4) + 1); ++ } ++ ++ else { ++ obj_desc->method.concurrency = INFINITE_CONCURRENCY; ++ } ++ ++ /* Attach the new object to the method Node */ ++ ++ status = acpi_ns_attach_object (method, obj_desc, (u8) ACPI_TYPE_METHOD); ++ if (ACPI_FAILURE (status)) { ++ acpi_cm_delete_object_desc (obj_desc); ++ } ++ ++ return (status); ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/amdump.c linux/drivers/acpi/executer/amdump.c +--- /usr/src/linux/drivers/acpi/executer/amdump.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/amdump.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,41 @@ ++/****************************************************************************** ++ * ++ * Module Name: amdump - Interpreter debug output routines ++ * $Revision: 109 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acinterp.h" ++#include "amlcode.h" ++#include "acnamesp.h" ++#include "actables.h" ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("amdump") ++ ++ ++/* ++ * The following routines are used for debug output only ++ */ ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/amdyadic.c linux/drivers/acpi/executer/amdyadic.c +--- /usr/src/linux/drivers/acpi/executer/amdyadic.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/amdyadic.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,875 @@ ++/****************************************************************************** ++ * ++ * Module Name: amdyadic - ACPI AML (p-code) execution for dyadic operators ++ * $Revision: 75 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acparser.h" ++#include "acnamesp.h" ++#include "acinterp.h" ++#include "acevents.h" ++#include "amlcode.h" ++#include "acdispat.h" ++ ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("amdyadic") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_do_concatenate ++ * ++ * PARAMETERS: *Obj_desc - Object to be converted. Must be an ++ * Integer, Buffer, or String ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Concatenate two objects OF THE SAME TYPE. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_do_concatenate ( ++ ACPI_OPERAND_OBJECT *obj_desc, ++ ACPI_OPERAND_OBJECT *obj_desc2, ++ ACPI_OPERAND_OBJECT **actual_ret_desc, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_STATUS status; ++ u32 i; ++ ACPI_INTEGER this_integer; ++ ACPI_OPERAND_OBJECT *ret_desc; ++ NATIVE_CHAR *new_buf; ++ u32 integer_size = sizeof (ACPI_INTEGER); ++ ++ ++ /* ++ * There are three cases to handle: ++ * 1) Two Integers concatenated to produce a buffer ++ * 2) Two Strings concatenated to produce a string ++ * 3) Two Buffers concatenated to produce a buffer ++ */ ++ switch (obj_desc->common.type) { ++ case ACPI_TYPE_INTEGER: ++ ++ /* Handle both ACPI 1.0 and ACPI 2.0 Integer widths */ ++ ++ if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) { ++ /* ++ * We are running a method that exists in a 32-bit ACPI table. ++ * Truncate the value to 32 bits by zeroing out the upper ++ * 32-bit field ++ */ ++ integer_size = sizeof (u32); ++ } ++ ++ /* Result of two integers is a buffer */ ++ ++ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_BUFFER); ++ if (!ret_desc) { ++ return (AE_NO_MEMORY); ++ } ++ ++ /* Need enough space for two integers */ ++ ++ ret_desc->buffer.length = integer_size * 2; ++ new_buf = acpi_cm_callocate (ret_desc->buffer.length); ++ if (!new_buf) { ++ REPORT_ERROR ++ (("Aml_exec_dyadic2_r/Concat_op: Buffer allocation failure\n")); ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ ret_desc->buffer.pointer = (u8 *) new_buf; ++ ++ /* Convert the first integer */ ++ ++ this_integer = obj_desc->integer.value; ++ for (i = 0; i < integer_size; i++) { ++ new_buf[i] = (u8) this_integer; ++ this_integer >>= 8; ++ } ++ ++ /* Convert the second integer */ ++ ++ this_integer = obj_desc2->integer.value; ++ for (; i < (integer_size * 2); i++) { ++ new_buf[i] = (u8) this_integer; ++ this_integer >>= 8; ++ } ++ ++ break; ++ ++ ++ case ACPI_TYPE_STRING: ++ ++ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_STRING); ++ if (!ret_desc) { ++ return (AE_NO_MEMORY); ++ } ++ ++ /* Operand1 is string */ ++ ++ new_buf = acpi_cm_allocate (obj_desc->string.length + ++ obj_desc2->string.length + 1); ++ if (!new_buf) { ++ REPORT_ERROR ++ (("Aml_exec_dyadic2_r/Concat_op: String allocation failure\n")); ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ STRCPY (new_buf, obj_desc->string.pointer); ++ STRCPY (new_buf + obj_desc->string.length, ++ obj_desc2->string.pointer); ++ ++ /* Point the return object to the new string */ ++ ++ ret_desc->string.pointer = new_buf; ++ ret_desc->string.length = obj_desc->string.length += ++ obj_desc2->string.length; ++ break; ++ ++ ++ case ACPI_TYPE_BUFFER: ++ ++ /* Operand1 is a buffer */ ++ ++ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_BUFFER); ++ if (!ret_desc) { ++ return (AE_NO_MEMORY); ++ } ++ ++ new_buf = acpi_cm_allocate (obj_desc->buffer.length + ++ obj_desc2->buffer.length); ++ if (!new_buf) { ++ REPORT_ERROR ++ (("Aml_exec_dyadic2_r/Concat_op: Buffer allocation failure\n")); ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ MEMCPY (new_buf, obj_desc->buffer.pointer, ++ obj_desc->buffer.length); ++ MEMCPY (new_buf + obj_desc->buffer.length, obj_desc2->buffer.pointer, ++ obj_desc2->buffer.length); ++ ++ /* ++ * Point the return object to the new buffer ++ */ ++ ++ ret_desc->buffer.pointer = (u8 *) new_buf; ++ ret_desc->buffer.length = obj_desc->buffer.length + ++ obj_desc2->buffer.length; ++ break; ++ ++ default: ++ status = AE_AML_INTERNAL; ++ ret_desc = NULL; ++ } ++ ++ ++ *actual_ret_desc = ret_desc; ++ return (AE_OK); ++ ++ ++cleanup: ++ ++ acpi_cm_remove_reference (ret_desc); ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_exec_dyadic1 ++ * ++ * PARAMETERS: Opcode - The opcode to be executed ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Execute Type 1 dyadic operator with numeric operands: ++ * Notify_op ++ * ++ * ALLOCATION: Deletes both operands ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_exec_dyadic1 ( ++ u16 opcode, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_OPERAND_OBJECT *obj_desc = NULL; ++ ACPI_OPERAND_OBJECT *val_desc = NULL; ++ ACPI_NAMESPACE_NODE *node; ++ ACPI_STATUS status = AE_OK; ++ ++ ++ /* Resolve all operands */ ++ ++ status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); ++ /* Get the operands */ ++ ++ status |= acpi_ds_obj_stack_pop_object (&val_desc, walk_state); ++ status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); ++ if (ACPI_FAILURE (status)) { ++ /* Invalid parameters on object stack */ ++ ++ goto cleanup; ++ } ++ ++ ++ /* Examine the opcode */ ++ ++ switch (opcode) { ++ ++ /* Def_notify := Notify_op Notify_object Notify_value */ ++ ++ case AML_NOTIFY_OP: ++ ++ /* The Obj_desc is actually an Node */ ++ ++ node = (ACPI_NAMESPACE_NODE *) obj_desc; ++ obj_desc = NULL; ++ ++ /* Object must be a device or thermal zone */ ++ ++ if (node && val_desc) { ++ switch (node->type) { ++ case ACPI_TYPE_DEVICE: ++ case ACPI_TYPE_THERMAL: ++ ++ /* ++ * Dispatch the notify to the appropriate handler ++ * NOTE: the request is queued for execution after this method ++ * completes. The notify handlers are NOT invoked synchronously ++ * from this thread -- because handlers may in turn run other ++ * control methods. ++ */ ++ ++ status = acpi_ev_queue_notify_request (node, ++ (u32) val_desc->integer.value); ++ break; ++ ++ default: ++ status = AE_AML_OPERAND_TYPE; ++ break; ++ } ++ } ++ break; ++ ++ default: ++ ++ REPORT_ERROR (("Acpi_aml_exec_dyadic1: Unknown dyadic opcode %X\n", ++ opcode)); ++ status = AE_AML_BAD_OPCODE; ++ } ++ ++ ++cleanup: ++ ++ /* Always delete both operands */ ++ ++ acpi_cm_remove_reference (val_desc); ++ acpi_cm_remove_reference (obj_desc); ++ ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_exec_dyadic2_r ++ * ++ * PARAMETERS: Opcode - The opcode to be executed ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Execute Type 2 dyadic operator with numeric operands and ++ * one or two result operands. ++ * ++ * ALLOCATION: Deletes one operand descriptor -- other remains on stack ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_exec_dyadic2_r ( ++ u16 opcode, ++ ACPI_WALK_STATE *walk_state, ++ ACPI_OPERAND_OBJECT **return_desc) ++{ ++ ACPI_OPERAND_OBJECT *obj_desc = NULL; ++ ACPI_OPERAND_OBJECT *obj_desc2 = NULL; ++ ACPI_OPERAND_OBJECT *res_desc = NULL; ++ ACPI_OPERAND_OBJECT *res_desc2 = NULL; ++ ACPI_OPERAND_OBJECT *ret_desc = NULL; ++ ACPI_OPERAND_OBJECT *ret_desc2 = NULL; ++ ACPI_STATUS status = AE_OK; ++ u32 num_operands = 3; ++ ++ ++ /* Resolve all operands */ ++ ++ status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); ++ /* Get all operands */ ++ ++ if (AML_DIVIDE_OP == opcode) { ++ num_operands = 4; ++ status |= acpi_ds_obj_stack_pop_object (&res_desc2, walk_state); ++ } ++ ++ status |= acpi_ds_obj_stack_pop_object (&res_desc, walk_state); ++ status |= acpi_ds_obj_stack_pop_object (&obj_desc2, walk_state); ++ status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ ++ ++ /* Create an internal return object if necessary */ ++ ++ switch (opcode) { ++ case AML_ADD_OP: ++ case AML_BIT_AND_OP: ++ case AML_BIT_NAND_OP: ++ case AML_BIT_OR_OP: ++ case AML_BIT_NOR_OP: ++ case AML_BIT_XOR_OP: ++ case AML_DIVIDE_OP: ++ case AML_MULTIPLY_OP: ++ case AML_SHIFT_LEFT_OP: ++ case AML_SHIFT_RIGHT_OP: ++ case AML_SUBTRACT_OP: ++ ++ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); ++ if (!ret_desc) { ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ break; ++ } ++ ++ ++ /* ++ * Execute the opcode ++ */ ++ ++ switch (opcode) { ++ ++ /* Def_add := Add_op Operand1 Operand2 Result */ ++ ++ case AML_ADD_OP: ++ ++ ret_desc->integer.value = obj_desc->integer.value + ++ obj_desc2->integer.value; ++ break; ++ ++ ++ /* Def_and := And_op Operand1 Operand2 Result */ ++ ++ case AML_BIT_AND_OP: ++ ++ ret_desc->integer.value = obj_desc->integer.value & ++ obj_desc2->integer.value; ++ break; ++ ++ ++ /* Def_nAnd := NAnd_op Operand1 Operand2 Result */ ++ ++ case AML_BIT_NAND_OP: ++ ++ ret_desc->integer.value = ~(obj_desc->integer.value & ++ obj_desc2->integer.value); ++ break; ++ ++ ++ /* Def_or := Or_op Operand1 Operand2 Result */ ++ ++ case AML_BIT_OR_OP: ++ ++ ret_desc->integer.value = obj_desc->integer.value | ++ obj_desc2->integer.value; ++ break; ++ ++ ++ /* Def_nOr := NOr_op Operand1 Operand2 Result */ ++ ++ case AML_BIT_NOR_OP: ++ ++ ret_desc->integer.value = ~(obj_desc->integer.value | ++ obj_desc2->integer.value); ++ break; ++ ++ ++ /* Def_xOr := XOr_op Operand1 Operand2 Result */ ++ ++ case AML_BIT_XOR_OP: ++ ++ ret_desc->integer.value = obj_desc->integer.value ^ ++ obj_desc2->integer.value; ++ break; ++ ++ ++ /* Def_divide := Divide_op Dividend Divisor Remainder Quotient */ ++ ++ case AML_DIVIDE_OP: ++ ++ if (!obj_desc2->integer.value) { ++ REPORT_ERROR ++ (("Aml_exec_dyadic2_r/Divide_op: Divide by zero\n")); ++ ++ status = AE_AML_DIVIDE_BY_ZERO; ++ goto cleanup; ++ } ++ ++ ret_desc2 = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); ++ if (!ret_desc2) { ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ /* Remainder (modulo) */ ++ ++ ret_desc->integer.value = ACPI_MODULO (obj_desc->integer.value, ++ obj_desc2->integer.value); ++ ++ /* Result (what we used to call the quotient) */ ++ ++ ret_desc2->integer.value = ACPI_DIVIDE (obj_desc->integer.value, ++ obj_desc2->integer.value); ++ break; ++ ++ ++ /* Def_multiply := Multiply_op Operand1 Operand2 Result */ ++ ++ case AML_MULTIPLY_OP: ++ ++ ret_desc->integer.value = obj_desc->integer.value * ++ obj_desc2->integer.value; ++ break; ++ ++ ++ /* Def_shift_left := Shift_left_op Operand Shift_count Result */ ++ ++ case AML_SHIFT_LEFT_OP: ++ ++ ret_desc->integer.value = obj_desc->integer.value << ++ obj_desc2->integer.value; ++ break; ++ ++ ++ /* Def_shift_right := Shift_right_op Operand Shift_count Result */ ++ ++ case AML_SHIFT_RIGHT_OP: ++ ++ ret_desc->integer.value = obj_desc->integer.value >> ++ obj_desc2->integer.value; ++ break; ++ ++ ++ /* Def_subtract := Subtract_op Operand1 Operand2 Result */ ++ ++ case AML_SUBTRACT_OP: ++ ++ ret_desc->integer.value = obj_desc->integer.value - ++ obj_desc2->integer.value; ++ break; ++ ++ ++ /* Def_concat := Concat_op Data1 Data2 Result */ ++ ++ case AML_CONCAT_OP: ++ ++ ++ /* ++ * Convert the second operand if necessary. The first operand ++ * determines the type of the second operand, (See the Data Types ++ * section of the ACPI specification.) Both object types are ++ * guaranteed to be either Integer/String/Buffer by the operand ++ * resolution mechanism above. ++ */ ++ ++ switch (obj_desc->common.type) { ++ case ACPI_TYPE_INTEGER: ++ status = acpi_aml_convert_to_integer (&obj_desc2, walk_state); ++ break; ++ ++ case ACPI_TYPE_STRING: ++ status = acpi_aml_convert_to_string (&obj_desc2, walk_state); ++ break; ++ ++ case ACPI_TYPE_BUFFER: ++ status = acpi_aml_convert_to_buffer (&obj_desc2, walk_state); ++ break; ++ ++ default: ++ status = AE_AML_INTERNAL; ++ } ++ ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ ++ ++ /* ++ * Both operands are now known to be the same object type ++ * (Both are Integer, String, or Buffer), and we can now perform the ++ * concatenation. ++ */ ++ status = acpi_aml_do_concatenate (obj_desc, obj_desc2, &ret_desc, walk_state); ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ break; ++ ++ ++ default: ++ ++ REPORT_ERROR (("Acpi_aml_exec_dyadic2_r: Unknown dyadic opcode %X\n", ++ opcode)); ++ status = AE_AML_BAD_OPCODE; ++ goto cleanup; ++ } ++ ++ ++ /* ++ * Store the result of the operation (which is now in Obj_desc) into ++ * the result descriptor, or the location pointed to by the result ++ * descriptor (Res_desc). ++ */ ++ ++ status = acpi_aml_exec_store (ret_desc, res_desc, walk_state); ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ ++ if (AML_DIVIDE_OP == opcode) { ++ status = acpi_aml_exec_store (ret_desc2, res_desc2, walk_state); ++ ++ /* ++ * Since the remainder is not returned, remove a reference to ++ * the object we created earlier ++ */ ++ ++ acpi_cm_remove_reference (ret_desc2); ++ } ++ ++ ++cleanup: ++ ++ /* Always delete the operands */ ++ ++ acpi_cm_remove_reference (obj_desc); ++ acpi_cm_remove_reference (obj_desc2); ++ ++ ++ /* Delete return object on error */ ++ ++ if (ACPI_FAILURE (status)) { ++ /* On failure, delete the result ops */ ++ ++ acpi_cm_remove_reference (res_desc); ++ acpi_cm_remove_reference (res_desc2); ++ ++ if (ret_desc) { ++ /* And delete the internal return object */ ++ ++ acpi_cm_remove_reference (ret_desc); ++ ret_desc = NULL; ++ } ++ } ++ ++ /* Set the return object and exit */ ++ ++ *return_desc = ret_desc; ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_exec_dyadic2_s ++ * ++ * PARAMETERS: Opcode - The opcode to be executed ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Execute Type 2 dyadic synchronization operator ++ * ++ * ALLOCATION: Deletes one operand descriptor -- other remains on stack ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_exec_dyadic2_s ( ++ u16 opcode, ++ ACPI_WALK_STATE *walk_state, ++ ACPI_OPERAND_OBJECT **return_desc) ++{ ++ ACPI_OPERAND_OBJECT *obj_desc; ++ ACPI_OPERAND_OBJECT *time_desc; ++ ACPI_OPERAND_OBJECT *ret_desc = NULL; ++ ACPI_STATUS status; ++ ++ ++ /* Resolve all operands */ ++ ++ status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); ++ /* Get all operands */ ++ ++ status |= acpi_ds_obj_stack_pop_object (&time_desc, walk_state); ++ status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); ++ if (ACPI_FAILURE (status)) { ++ /* Invalid parameters on object stack */ ++ ++ goto cleanup; ++ } ++ ++ ++ /* Create the internal return object */ ++ ++ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); ++ if (!ret_desc) { ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ /* Default return value is FALSE, operation did not time out */ ++ ++ ret_desc->integer.value = 0; ++ ++ ++ /* Examine the opcode */ ++ ++ switch (opcode) { ++ ++ /* Def_acquire := Acquire_op Mutex_object Timeout */ ++ ++ case AML_ACQUIRE_OP: ++ ++ status = acpi_aml_acquire_mutex (time_desc, obj_desc, walk_state); ++ break; ++ ++ ++ /* Def_wait := Wait_op Acpi_event_object Timeout */ ++ ++ case AML_WAIT_OP: ++ ++ status = acpi_aml_system_wait_event (time_desc, obj_desc); ++ break; ++ ++ ++ default: ++ ++ REPORT_ERROR (("Acpi_aml_exec_dyadic2_s: Unknown dyadic synchronization opcode %X\n", opcode)); ++ status = AE_AML_BAD_OPCODE; ++ goto cleanup; ++ } ++ ++ ++ /* ++ * Return a boolean indicating if operation timed out ++ * (TRUE) or not (FALSE) ++ */ ++ ++ if (status == AE_TIME) { ++ ret_desc->integer.value = ACPI_INTEGER_MAX; /* TRUE, op timed out */ ++ status = AE_OK; ++ } ++ ++ ++cleanup: ++ ++ /* Delete params */ ++ ++ acpi_cm_remove_reference (time_desc); ++ acpi_cm_remove_reference (obj_desc); ++ ++ /* Delete return object on error */ ++ ++ if (ACPI_FAILURE (status) && ++ (ret_desc)) { ++ acpi_cm_remove_reference (ret_desc); ++ ret_desc = NULL; ++ } ++ ++ ++ /* Set the return object and exit */ ++ ++ *return_desc = ret_desc; ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_exec_dyadic2 ++ * ++ * PARAMETERS: Opcode - The opcode to be executed ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Execute Type 2 dyadic operator with numeric operands and ++ * no result operands ++ * ++ * ALLOCATION: Deletes one operand descriptor -- other remains on stack ++ * containing result value ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_exec_dyadic2 ( ++ u16 opcode, ++ ACPI_WALK_STATE *walk_state, ++ ACPI_OPERAND_OBJECT **return_desc) ++{ ++ ACPI_OPERAND_OBJECT *obj_desc; ++ ACPI_OPERAND_OBJECT *obj_desc2; ++ ACPI_OPERAND_OBJECT *ret_desc = NULL; ++ ACPI_STATUS status; ++ u8 lboolean; ++ ++ ++ /* Resolve all operands */ ++ ++ status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); ++ /* Get all operands */ ++ ++ status |= acpi_ds_obj_stack_pop_object (&obj_desc2, walk_state); ++ status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); ++ if (ACPI_FAILURE (status)) { ++ /* Invalid parameters on object stack */ ++ ++ goto cleanup; ++ } ++ ++ ++ /* Create the internal return object */ ++ ++ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); ++ if (!ret_desc) { ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ /* ++ * Execute the Opcode ++ */ ++ ++ lboolean = FALSE; ++ switch (opcode) { ++ ++ /* Def_lAnd := LAnd_op Operand1 Operand2 */ ++ ++ case AML_LAND_OP: ++ ++ lboolean = (u8) (obj_desc->integer.value && ++ obj_desc2->integer.value); ++ break; ++ ++ ++ /* Def_lEqual := LEqual_op Operand1 Operand2 */ ++ ++ case AML_LEQUAL_OP: ++ ++ lboolean = (u8) (obj_desc->integer.value == ++ obj_desc2->integer.value); ++ break; ++ ++ ++ /* Def_lGreater := LGreater_op Operand1 Operand2 */ ++ ++ case AML_LGREATER_OP: ++ ++ lboolean = (u8) (obj_desc->integer.value > ++ obj_desc2->integer.value); ++ break; ++ ++ ++ /* Def_lLess := LLess_op Operand1 Operand2 */ ++ ++ case AML_LLESS_OP: ++ ++ lboolean = (u8) (obj_desc->integer.value < ++ obj_desc2->integer.value); ++ break; ++ ++ ++ /* Def_lOr := LOr_op Operand1 Operand2 */ ++ ++ case AML_LOR_OP: ++ ++ lboolean = (u8) (obj_desc->integer.value || ++ obj_desc2->integer.value); ++ break; ++ ++ ++ default: ++ ++ REPORT_ERROR (("Acpi_aml_exec_dyadic2: Unknown dyadic opcode %X\n", opcode)); ++ status = AE_AML_BAD_OPCODE; ++ goto cleanup; ++ break; ++ } ++ ++ ++ /* Set return value to logical TRUE (all ones) or FALSE (zero) */ ++ ++ if (lboolean) { ++ ret_desc->integer.value = ACPI_INTEGER_MAX; ++ } ++ else { ++ ret_desc->integer.value = 0; ++ } ++ ++ ++cleanup: ++ ++ /* Always delete operands */ ++ ++ acpi_cm_remove_reference (obj_desc); ++ acpi_cm_remove_reference (obj_desc2); ++ ++ ++ /* Delete return object on error */ ++ ++ if (ACPI_FAILURE (status) && ++ (ret_desc)) { ++ acpi_cm_remove_reference (ret_desc); ++ ret_desc = NULL; ++ } ++ ++ ++ /* Set the return object and exit */ ++ ++ *return_desc = ret_desc; ++ return (status); ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/amfield.c linux/drivers/acpi/executer/amfield.c +--- /usr/src/linux/drivers/acpi/executer/amfield.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/amfield.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,536 @@ ++/****************************************************************************** ++ * ++ * Module Name: amfield - ACPI AML (p-code) execution - field manipulation ++ * $Revision: 86 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acdispat.h" ++#include "acinterp.h" ++#include "amlcode.h" ++#include "acnamesp.h" ++#include "achware.h" ++#include "acevents.h" ++ ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("amfield") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_read_data_from_field ++ * ++ * PARAMETERS: Mode - ACPI_READ or ACPI_WRITE ++ * *Field_node - Parent node for field to be accessed ++ * *Buffer - Value(s) to be read or written ++ * Buffer_length - Number of bytes to transfer ++ * ++ * RETURN: Status3 ++ * ++ * DESCRIPTION: Read or write a named field ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_read_data_from_field ( ++ ACPI_OPERAND_OBJECT *obj_desc, ++ ACPI_OPERAND_OBJECT **ret_buffer_desc) ++{ ++ ACPI_STATUS status; ++ ACPI_OPERAND_OBJECT *buffer_desc; ++ u32 length; ++ void *buffer; ++ ++ ++ /* Parameter validation */ ++ ++ if (!obj_desc) { ++ return (AE_AML_NO_OPERAND); ++ } ++ ++ /* ++ * Allocate a buffer for the contents of the field. ++ * ++ * If the field is larger than the size of an ACPI_INTEGER, create ++ * a BUFFER to hold it. Otherwise, use an INTEGER. This allows ++ * the use of arithmetic operators on the returned value if the ++ * field size is equal or smaller than an Integer. ++ * ++ * Note: Field.length is in bits. ++ */ ++ ++ length = ROUND_BITS_UP_TO_BYTES (obj_desc->field.bit_length); ++ ++ if (length > sizeof (ACPI_INTEGER)) { ++ /* Field is too large for an Integer, create a Buffer instead */ ++ ++ buffer_desc = acpi_cm_create_internal_object (ACPI_TYPE_BUFFER); ++ if (!buffer_desc) { ++ return (AE_NO_MEMORY); ++ } ++ ++ /* Create the actual read buffer */ ++ ++ buffer_desc->buffer.pointer = acpi_cm_callocate (length); ++ if (!buffer_desc->buffer.pointer) { ++ acpi_cm_remove_reference (buffer_desc); ++ return (AE_NO_MEMORY); ++ } ++ ++ buffer_desc->buffer.length = length; ++ buffer = buffer_desc->buffer.pointer; ++ } ++ ++ else { ++ /* Field will fit within an Integer (normal case) */ ++ ++ buffer_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); ++ if (!buffer_desc) { ++ return (AE_NO_MEMORY); ++ } ++ ++ length = sizeof (buffer_desc->integer.value); ++ buffer = &buffer_desc->integer.value; ++ } ++ ++ ++ /* Read from the appropriate field */ ++ ++ switch (obj_desc->common.type) { ++ case ACPI_TYPE_BUFFER_FIELD: ++ status = acpi_aml_access_buffer_field (ACPI_READ, obj_desc, buffer, length); ++ break; ++ ++ case INTERNAL_TYPE_REGION_FIELD: ++ status = acpi_aml_access_region_field (ACPI_READ, obj_desc, buffer, length); ++ break; ++ ++ case INTERNAL_TYPE_BANK_FIELD: ++ status = acpi_aml_access_bank_field (ACPI_READ, obj_desc, buffer, length); ++ break; ++ ++ case INTERNAL_TYPE_INDEX_FIELD: ++ status = acpi_aml_access_index_field (ACPI_READ, obj_desc, buffer, length); ++ break; ++ ++ default: ++ status = AE_AML_INTERNAL; ++ } ++ ++ ++ if (ACPI_FAILURE (status)) { ++ acpi_cm_remove_reference (buffer_desc); ++ } ++ ++ else if (ret_buffer_desc) { ++ *ret_buffer_desc = buffer_desc; ++ } ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_write_data_to_field ++ * ++ * PARAMETERS: Mode - ACPI_READ or ACPI_WRITE ++ * *Field_node - Parent node for field to be accessed ++ * *Buffer - Value(s) to be read or written ++ * Buffer_length - Number of bytes to transfer ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Read or write a named field ++ * ++ ******************************************************************************/ ++ ++ ++ACPI_STATUS ++acpi_aml_write_data_to_field ( ++ ACPI_OPERAND_OBJECT *source_desc, ++ ACPI_OPERAND_OBJECT *obj_desc) ++{ ++ ACPI_STATUS status; ++ u32 length; ++ void *buffer; ++ ++ ++ /* Parameter validation */ ++ ++ if (!source_desc || !obj_desc) { ++ return (AE_AML_NO_OPERAND); ++ } ++ ++ ++ /* ++ * Get a pointer to the data to be written ++ */ ++ switch (source_desc->common.type) { ++ case ACPI_TYPE_INTEGER: ++ buffer = &source_desc->integer.value; ++ length = sizeof (source_desc->integer.value); ++ break; ++ ++ case ACPI_TYPE_BUFFER: ++ buffer = source_desc->buffer.pointer; ++ length = source_desc->buffer.length; ++ break; ++ ++ case ACPI_TYPE_STRING: ++ buffer = source_desc->string.pointer; ++ length = source_desc->string.length; ++ break; ++ ++ default: ++ return (AE_AML_OPERAND_TYPE); ++ } ++ ++ ++ /* ++ * Decode the type of field to be written ++ */ ++ switch (obj_desc->common.type) { ++ case ACPI_TYPE_BUFFER_FIELD: ++ status = acpi_aml_access_buffer_field (ACPI_WRITE, obj_desc, buffer, length); ++ break; ++ ++ case INTERNAL_TYPE_REGION_FIELD: ++ status = acpi_aml_access_region_field (ACPI_WRITE, obj_desc, buffer, length); ++ break; ++ ++ case INTERNAL_TYPE_BANK_FIELD: ++ status = acpi_aml_access_bank_field (ACPI_WRITE, obj_desc, buffer, length); ++ break; ++ ++ case INTERNAL_TYPE_INDEX_FIELD: ++ status = acpi_aml_access_index_field (ACPI_WRITE, obj_desc, buffer, length); ++ break; ++ ++ default: ++ return (AE_AML_INTERNAL); ++ } ++ ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_access_buffer_field ++ * ++ * PARAMETERS: Mode - ACPI_READ or ACPI_WRITE ++ * *Field_node - Parent node for field to be accessed ++ * *Buffer - Value(s) to be read or written ++ * Buffer_length - Number of bytes to transfer ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Read or write a named field ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_access_buffer_field ( ++ u32 mode, ++ ACPI_OPERAND_OBJECT *obj_desc, ++ void *buffer, ++ u32 buffer_length) ++{ ++ ACPI_STATUS status; ++ ++ ++ /* ++ * If the Buffer_field arguments have not been previously evaluated, ++ * evaluate them now and save the results. ++ */ ++ if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { ++ status = acpi_ds_get_buffer_field_arguments (obj_desc); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ } ++ ++ ++ status = acpi_aml_common_access_field (mode, obj_desc, buffer, buffer_length); ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_access_region_field ++ * ++ * PARAMETERS: Mode - ACPI_READ or ACPI_WRITE ++ * *Field_node - Parent node for field to be accessed ++ * *Buffer - Value(s) to be read or written ++ * Buffer_length - Number of bytes to transfer ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Read or write a named field ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_access_region_field ( ++ u32 mode, ++ ACPI_OPERAND_OBJECT *obj_desc, ++ void *buffer, ++ u32 buffer_length) ++{ ++ ACPI_STATUS status; ++ u8 locked; ++ ++ ++ /* ++ * Get the global lock if needed ++ */ ++ locked = acpi_aml_acquire_global_lock (obj_desc->field.lock_rule); ++ ++ status = acpi_aml_common_access_field (mode, obj_desc, buffer, buffer_length); ++ ++ ++ /* ++ * Release global lock if we acquired it earlier ++ */ ++ acpi_aml_release_global_lock (locked); ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_access_bank_field ++ * ++ * PARAMETERS: Mode - ACPI_READ or ACPI_WRITE ++ * *Field_node - Parent node for field to be accessed ++ * *Buffer - Value(s) to be read or written ++ * Buffer_length - Number of bytes to transfer ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Read or write a Bank Field ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_access_bank_field ( ++ u32 mode, ++ ACPI_OPERAND_OBJECT *obj_desc, ++ void *buffer, ++ u32 buffer_length) ++{ ++ ACPI_STATUS status; ++ u8 locked; ++ ++ ++ /* ++ * Get the global lock if needed ++ */ ++ locked = acpi_aml_acquire_global_lock (obj_desc->bank_field.lock_rule); ++ ++ ++ /* ++ * Write the Bank_value to the Bank_register to select the bank. ++ * The Bank_value for this Bank_field is specified in the ++ * Bank_field ASL declaration. The Bank_register is always a Field in ++ * an operation region. ++ */ ++ ++ status = acpi_aml_common_access_field (ACPI_WRITE, ++ obj_desc->bank_field.bank_register_obj, ++ &obj_desc->bank_field.value, ++ sizeof (obj_desc->bank_field.value)); ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ ++ /* ++ * The bank was successfully selected, now read or write the actual ++ * data. ++ */ ++ status = acpi_aml_common_access_field (mode, obj_desc, buffer, buffer_length); ++ ++ ++cleanup: ++ /* ++ * Release global lock if we acquired it earlier ++ */ ++ acpi_aml_release_global_lock (locked); ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_access_index_field ++ * ++ * PARAMETERS: Mode - ACPI_READ or ACPI_WRITE ++ * *Field_node - Parent node for field to be accessed ++ * *Buffer - Value(s) to be read or written ++ * Buffer_length - Number of bytes to transfer ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Read or write a Index Field ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_access_index_field ( ++ u32 mode, ++ ACPI_OPERAND_OBJECT *obj_desc, ++ void *buffer, ++ u32 buffer_length) ++{ ++ ACPI_STATUS status; ++ u8 locked; ++ ++ ++ /* ++ * Get the global lock if needed ++ */ ++ locked = acpi_aml_acquire_global_lock (obj_desc->index_field.lock_rule); ++ ++ ++ /* ++ * Set Index value to select proper Data register ++ */ ++ status = acpi_aml_common_access_field (ACPI_WRITE, ++ obj_desc->index_field.index_obj, ++ &obj_desc->index_field.value, ++ sizeof (obj_desc->index_field.value)); ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ ++ /* Now read/write the data register */ ++ ++ status = acpi_aml_common_access_field (mode, obj_desc->index_field.data_obj, ++ buffer, buffer_length); ++ ++cleanup: ++ /* ++ * Release global lock if we acquired it earlier ++ */ ++ acpi_aml_release_global_lock (locked); ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_common_access_field ++ * ++ * PARAMETERS: Mode - ACPI_READ or ACPI_WRITE ++ * *Field_node - Parent node for field to be accessed ++ * *Buffer - Value(s) to be read or written ++ * Buffer_length - Size of buffer, in bytes. Must be large ++ * enough for all bits of the field. ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Read or write a named field ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_common_access_field ( ++ u32 mode, ++ ACPI_OPERAND_OBJECT *obj_desc, ++ void *buffer, ++ u32 buffer_length) ++{ ++ ACPI_STATUS status; ++ u32 bit_granularity; ++ u32 byte_granularity; ++ u32 datum_length; ++ u32 actual_byte_length; ++ u32 byte_field_length; ++ ++ ++ /* ++ * Granularity was decoded from the field access type ++ * (Any_acc will be the same as Byte_acc) ++ */ ++ ++ bit_granularity = obj_desc->common_field.granularity; ++ byte_granularity = DIV_8 (bit_granularity); ++ ++ /* ++ * Check if request is too large for the field, and silently truncate ++ * the request to fit the field (if necessary). This allows full ++ * Integer writes to small bit fields (lower bits of integer are used) ++ */ ++ ++ /* TBD: what about reads? Should this code be in the write code only? */ ++ ++ byte_field_length = ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length); ++ actual_byte_length = buffer_length; ++ ++ if (buffer_length > byte_field_length) { ++ actual_byte_length = byte_field_length; ++ } ++ ++ ++ /* Convert byte count to datum count, round up if necessary */ ++ ++ datum_length = (actual_byte_length + (byte_granularity-1)) / byte_granularity; ++ ++ ++ /* Perform the actual read or write of the buffer */ ++ ++ switch (mode) { ++ case ACPI_READ: ++ ++ status = acpi_aml_extract_from_field (obj_desc, buffer, buffer_length, ++ actual_byte_length, datum_length, ++ bit_granularity, byte_granularity); ++ break; ++ ++ ++ case ACPI_WRITE: ++ ++ status = acpi_aml_insert_into_field (obj_desc, buffer, buffer_length, ++ actual_byte_length, datum_length, ++ bit_granularity, byte_granularity); ++ break; ++ ++ ++ default: ++ ++ status = AE_BAD_PARAMETER; ++ break; ++ } ++ ++ ++ return (status); ++} ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/amfldio.c linux/drivers/acpi/executer/amfldio.c +--- /usr/src/linux/drivers/acpi/executer/amfldio.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/amfldio.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,818 @@ ++/****************************************************************************** ++ * ++ * Module Name: amfldio - Aml Field I/O ++ * $Revision: 45 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acinterp.h" ++#include "amlcode.h" ++#include "acnamesp.h" ++#include "achware.h" ++#include "acevents.h" ++#include "acdispat.h" ++ ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("amfldio") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_setup_field ++ * ++ * PARAMETERS: *Obj_desc - Field to be read or written ++ * *Rgn_desc - Region containing field ++ * Field_bit_width - Field Width in bits (8, 16, or 32) ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Common processing for Acpi_aml_extract_from_field and ++ * Acpi_aml_insert_into_field ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_setup_field ( ++ ACPI_OPERAND_OBJECT *obj_desc, ++ ACPI_OPERAND_OBJECT *rgn_desc, ++ u32 field_bit_width) ++{ ++ ACPI_STATUS status = AE_OK; ++ u32 field_byte_width; ++ ++ ++ /* Parameter validation */ ++ ++ if (!obj_desc || !rgn_desc) { ++ return (AE_AML_NO_OPERAND); ++ } ++ ++ if (ACPI_TYPE_REGION != rgn_desc->common.type) { ++ return (AE_AML_OPERAND_TYPE); ++ } ++ ++ ++ /* ++ * Init and validate Field width. Possible values are 1, 2, 4, 8 ++ */ ++ ++ field_byte_width = DIV_8 (field_bit_width); ++ ++ if ((field_bit_width != 8) && ++ (field_bit_width != 16) && ++ (field_bit_width != 32) && ++ (field_bit_width != 64)) /* ACPI 2.0 Qword support */ { ++ return (AE_AML_OPERAND_VALUE); ++ } ++ ++ ++ /* ++ * If the Region Address and Length have not been previously evaluated, ++ * evaluate them and save the results. ++ */ ++ if (!(rgn_desc->region.flags & AOPOBJ_DATA_VALID)) { ++ ++ status = acpi_ds_get_region_arguments (rgn_desc); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ } ++ ++ ++ if (rgn_desc->region.length < ++ (obj_desc->common_field.byte_offset & ~((u32) field_byte_width - 1)) + ++ field_byte_width) { ++ /* ++ * Offset rounded up to next multiple of field width ++ * exceeds region length, indicate an error ++ */ ++ ++ return (AE_AML_REGION_LIMIT); ++ } ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_read_field_datum ++ * ++ * PARAMETERS: *Obj_desc - Field to be read ++ * *Value - Where to store value ++ * Field_bit_width - Field Width in bits (8, 16, or 32) ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Retrieve the value of the given field ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_read_field_datum ( ++ ACPI_OPERAND_OBJECT *obj_desc, ++ u32 field_byte_offset, ++ u32 field_bit_width, ++ u32 *value) ++{ ++ ACPI_STATUS status; ++ ACPI_OPERAND_OBJECT *rgn_desc; ++ ACPI_PHYSICAL_ADDRESS address; ++ u32 local_value; ++ u32 field_byte_width; ++ ++ ++ field_byte_width = DIV_8 (field_bit_width); ++ if (!value) { ++ local_value = 0; ++ value = &local_value; /* support reads without saving value */ ++ } ++ ++ ++ /* ++ * Buffer_fields - Read from a Buffer ++ * Other Fields - Read from a Operation Region. ++ */ ++ ++ switch (obj_desc->common.type) { ++ case ACPI_TYPE_BUFFER_FIELD: ++ ++ /* ++ * For Buffer_fields, we only need to copy the data from the ++ * source buffer. Length is the field width in bytes. ++ */ ++ MEMCPY (value, (obj_desc->buffer_field.buffer_obj)->buffer.pointer ++ + obj_desc->buffer_field.byte_offset + field_byte_offset, ++ field_byte_width); ++ status = AE_OK; ++ break; ++ ++ ++ case INTERNAL_TYPE_REGION_FIELD: ++ case INTERNAL_TYPE_BANK_FIELD: ++ ++ /* ++ * For other fields, we need to go through an Operation Region ++ * (Only types that will get here are Region_fields and Bank_fields) ++ */ ++ ++ rgn_desc = obj_desc->common_field.region_obj; ++ status = acpi_aml_setup_field (obj_desc, rgn_desc, field_bit_width); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ ++ /* ++ * Set offset to next multiple of field width, ++ * add region base address and offset within the field ++ */ ++ address = rgn_desc->region.address + ++ (obj_desc->common_field.byte_offset * field_byte_width) + ++ field_byte_offset; ++ ++ ++ /* Invoke the appropriate Address_space/Op_region handler */ ++ ++ status = acpi_ev_address_space_dispatch (rgn_desc, ADDRESS_SPACE_READ, ++ address, field_bit_width, value); ++ ++ ++ break; ++ ++ ++ default: ++ ++ status = AE_AML_INTERNAL; ++ break; ++ } ++ ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_extract_from_field ++ * ++ * PARAMETERS: *Obj_desc - Field to be read ++ * *Value - Where to store value ++ * Field_bit_width - Field Width in bits (8, 16, or 32) ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Retrieve the value of the given field ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_extract_from_field ( ++ ACPI_OPERAND_OBJECT *obj_desc, ++ void *buffer, ++ u32 buffer_length, ++ u32 byte_length, ++ u32 datum_length, ++ u32 bit_granularity, ++ u32 byte_granularity) ++{ ++ ACPI_STATUS status; ++ u32 this_field_byte_offset; ++ u32 this_field_datum_offset; ++ u32 previous_raw_datum; ++ u32 this_raw_datum = 0; ++ u32 valid_field_bits; ++ u32 mask; ++ u32 merged_datum = 0; ++ ++ ++ /* ++ * Clear the caller's buffer (the whole buffer length as given) ++ * This is very important, especially in the cases where a byte is read, ++ * but the buffer is really a u32 (4 bytes). ++ */ ++ ++ MEMSET (buffer, 0, buffer_length); ++ ++ /* Read the first raw datum to prime the loop */ ++ ++ this_field_byte_offset = 0; ++ this_field_datum_offset= 0; ++ ++ status = acpi_aml_read_field_datum (obj_desc, this_field_byte_offset, ++ bit_granularity, &previous_raw_datum); ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ ++ /* We might actually be done if the request fits in one datum */ ++ ++ if ((datum_length == 1) && ++ ((obj_desc->common_field.bit_offset + obj_desc->common_field.bit_length) <= ++ (u16) bit_granularity)) { ++ merged_datum = previous_raw_datum; ++ merged_datum = (merged_datum >> obj_desc->common_field.bit_offset); ++ ++ valid_field_bits = obj_desc->common_field.bit_length % bit_granularity; ++ if (valid_field_bits) { ++ mask = (((u32) 1 << valid_field_bits) - (u32) 1); ++ merged_datum &= mask; ++ } ++ ++ ++ /* ++ * Place the Merged_datum into the proper format and return buffer ++ * field ++ */ ++ ++ switch (byte_granularity) { ++ case 1: ++ ((u8 *) buffer) [this_field_datum_offset] = (u8) merged_datum; ++ break; ++ ++ case 2: ++ MOVE_UNALIGNED16_TO_16 (&(((u16 *) buffer)[this_field_datum_offset]), &merged_datum); ++ break; ++ ++ case 4: ++ MOVE_UNALIGNED32_TO_32 (&(((u32 *) buffer)[this_field_datum_offset]), &merged_datum); ++ break; ++ } ++ ++ this_field_byte_offset = 1; ++ this_field_datum_offset = 1; ++ } ++ ++ else { ++ /* We need to get more raw data to complete one or more field data */ ++ ++ while (this_field_datum_offset < datum_length) { ++ /* ++ * If the field is aligned on a byte boundary, we don't want ++ * to perform a final read, since this would potentially read ++ * past the end of the region. ++ * ++ * TBD: [Investigate] It may make more sense to just split the aligned ++ * and non-aligned cases since the aligned case is so very simple, ++ */ ++ if ((obj_desc->common_field.bit_offset != 0) || ++ ((obj_desc->common_field.bit_offset == 0) && ++ (this_field_datum_offset < (datum_length -1)))) { ++ /* ++ * Get the next raw datum, it contains some or all bits ++ * of the current field datum ++ */ ++ ++ status = acpi_aml_read_field_datum (obj_desc, ++ this_field_byte_offset + byte_granularity, ++ bit_granularity, &this_raw_datum); ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ ++ /* Before merging the data, make sure the unused bits are clear */ ++ ++ switch (byte_granularity) { ++ case 1: ++ this_raw_datum &= 0x000000FF; ++ previous_raw_datum &= 0x000000FF; ++ break; ++ ++ case 2: ++ this_raw_datum &= 0x0000FFFF; ++ previous_raw_datum &= 0x0000FFFF; ++ break; ++ } ++ } ++ ++ ++ /* ++ * Put together bits of the two raw data to make a complete ++ * field datum ++ */ ++ ++ ++ if (obj_desc->common_field.bit_offset != 0) { ++ merged_datum = ++ (previous_raw_datum >> obj_desc->common_field.bit_offset) | ++ (this_raw_datum << (bit_granularity - obj_desc->common_field.bit_offset)); ++ } ++ ++ else { ++ merged_datum = previous_raw_datum; ++ } ++ ++ /* ++ * Prepare the merged datum for storing into the caller's ++ * buffer. It is possible to have a 32-bit buffer ++ * (Byte_granularity == 4), but a Obj_desc->Common_field.Bit_length ++ * of 8 or 16, meaning that the upper bytes of merged data ++ * are undesired. This section fixes that. ++ */ ++ switch (obj_desc->common_field.bit_length) { ++ case 8: ++ merged_datum &= 0x000000FF; ++ break; ++ ++ case 16: ++ merged_datum &= 0x0000FFFF; ++ break; ++ } ++ ++ /* ++ * Now store the datum in the caller's buffer, according to ++ * the data type ++ */ ++ switch (byte_granularity) { ++ case 1: ++ ((u8 *) buffer) [this_field_datum_offset] = (u8) merged_datum; ++ break; ++ ++ case 2: ++ MOVE_UNALIGNED16_TO_16 (&(((u16 *) buffer) [this_field_datum_offset]), &merged_datum); ++ break; ++ ++ case 4: ++ MOVE_UNALIGNED32_TO_32 (&(((u32 *) buffer) [this_field_datum_offset]), &merged_datum); ++ break; ++ } ++ ++ /* ++ * Save the most recent datum since it contains bits of ++ * the *next* field datum ++ */ ++ ++ previous_raw_datum = this_raw_datum; ++ ++ this_field_byte_offset += byte_granularity; ++ this_field_datum_offset++; ++ ++ } /* while */ ++ } ++ ++cleanup: ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_write_field_datum ++ * ++ * PARAMETERS: *Obj_desc - Field to be set ++ * Value - Value to store ++ * Field_bit_width - Field Width in bits (8, 16, or 32) ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Store the value into the given field ++ * ++ ******************************************************************************/ ++ ++static ACPI_STATUS ++acpi_aml_write_field_datum ( ++ ACPI_OPERAND_OBJECT *obj_desc, ++ u32 field_byte_offset, ++ u32 field_bit_width, ++ u32 value) ++{ ++ ACPI_STATUS status = AE_OK; ++ ACPI_OPERAND_OBJECT *rgn_desc = NULL; ++ ACPI_PHYSICAL_ADDRESS address; ++ u32 field_byte_width; ++ ++ ++ field_byte_width = DIV_8 (field_bit_width); ++ ++ /* ++ * Buffer_fields - Read from a Buffer ++ * Other Fields - Read from a Operation Region. ++ */ ++ ++ switch (obj_desc->common.type) { ++ case ACPI_TYPE_BUFFER_FIELD: ++ ++ /* ++ * For Buffer_fields, we only need to copy the data to the ++ * target buffer. Length is the field width in bytes. ++ */ ++ MEMCPY ((obj_desc->buffer_field.buffer_obj)->buffer.pointer ++ + obj_desc->buffer_field.byte_offset + field_byte_offset, ++ &value, field_byte_width); ++ status = AE_OK; ++ break; ++ ++ ++ case INTERNAL_TYPE_REGION_FIELD: ++ case INTERNAL_TYPE_BANK_FIELD: ++ ++ /* ++ * For other fields, we need to go through an Operation Region ++ * (Only types that will get here are Region_fields and Bank_fields) ++ */ ++ rgn_desc = obj_desc->common_field.region_obj; ++ status = acpi_aml_setup_field (obj_desc, rgn_desc, field_bit_width); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ ++ /* ++ * Set offset to next multiple of field width, ++ * add region base address and offset within the field ++ */ ++ address = rgn_desc->region.address + ++ (obj_desc->common_field.byte_offset * field_byte_width) + ++ field_byte_offset; ++ ++ /* Invoke the appropriate Address_space/Op_region handler */ ++ ++ status = acpi_ev_address_space_dispatch (rgn_desc, ADDRESS_SPACE_WRITE, ++ address, field_bit_width, &value); ++ ++ ++ ++ break; ++ ++ ++ default: ++ ++ status = AE_AML_INTERNAL; ++ break; ++ } ++ ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_write_field_datum_with_update_rule ++ * ++ * PARAMETERS: *Obj_desc - Field to be set ++ * Value - Value to store ++ * Field_bit_width - Field Width in bits (8, 16, or 32) ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Apply the field update rule to a field write ++ * ++ ******************************************************************************/ ++ ++static ACPI_STATUS ++acpi_aml_write_field_datum_with_update_rule ( ++ ACPI_OPERAND_OBJECT *obj_desc, ++ u32 mask, ++ u32 field_value, ++ u32 this_field_byte_offset, ++ u32 bit_granularity) ++{ ++ ACPI_STATUS status = AE_OK; ++ u32 merged_value; ++ u32 current_value; ++ ++ ++ /* Start with the new bits */ ++ ++ merged_value = field_value; ++ ++ ++ /* Decode the update rule */ ++ ++ switch (obj_desc->common_field.update_rule) { ++ ++ case UPDATE_PRESERVE: ++ ++ /* Check if update rule needs to be applied (not if mask is all ones) */ ++ ++ /* The left shift drops the bits we want to ignore. */ ++ if ((~mask << (sizeof(mask)*8 - bit_granularity)) != 0) { ++ /* ++ * Read the current contents of the byte/word/dword containing ++ * the field, and merge with the new field value. ++ */ ++ status = acpi_aml_read_field_datum (obj_desc, this_field_byte_offset, ++ bit_granularity, ¤t_value); ++ merged_value |= (current_value & ~mask); ++ } ++ break; ++ ++ ++ case UPDATE_WRITE_AS_ONES: ++ ++ /* Set positions outside the field to all ones */ ++ ++ merged_value |= ~mask; ++ break; ++ ++ ++ case UPDATE_WRITE_AS_ZEROS: ++ ++ /* Set positions outside the field to all zeros */ ++ ++ merged_value &= mask; ++ break; ++ ++ ++ default: ++ status = AE_AML_OPERAND_VALUE; ++ } ++ ++ ++ /* Write the merged value */ ++ ++ if (ACPI_SUCCESS (status)) { ++ status = acpi_aml_write_field_datum (obj_desc, this_field_byte_offset, ++ bit_granularity, merged_value); ++ } ++ ++ return (status); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Acpi_aml_insert_into_field ++ * ++ * PARAMETERS: *Obj_desc - Field to be set ++ * Value - Value to store ++ * Field_bit_width - Field Width in bits (8, 16, or 32) ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Store the value into the given field ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_insert_into_field ( ++ ACPI_OPERAND_OBJECT *obj_desc, ++ void *buffer, ++ u32 buffer_length, ++ u32 byte_length, ++ u32 datum_length, ++ u32 bit_granularity, ++ u32 byte_granularity) ++{ ++ ACPI_STATUS status; ++ u32 this_field_byte_offset; ++ u32 this_field_datum_offset; ++ u32 mask; ++ u32 merged_datum; ++ u32 previous_raw_datum; ++ u32 this_raw_datum; ++ u32 field_value; ++ u32 valid_field_bits; ++ ++ ++ /* ++ * Break the request into up to three parts: ++ * non-aligned part at start, aligned part in middle, non-aligned part ++ * at end --- Just like an I/O request --- ++ */ ++ ++ this_field_byte_offset = 0; ++ this_field_datum_offset= 0; ++ ++ /* Get a datum */ ++ ++ switch (byte_granularity) { ++ case 1: ++ previous_raw_datum = ((u8 *) buffer) [this_field_datum_offset]; ++ break; ++ ++ case 2: ++ MOVE_UNALIGNED16_TO_32 (&previous_raw_datum, ++ &(((u16 *) buffer) [this_field_datum_offset])); ++ break; ++ ++ case 4: ++ MOVE_UNALIGNED32_TO_32 (&previous_raw_datum, ++ &(((u32 *) buffer) [this_field_datum_offset])); ++ break; ++ ++ default: ++ status = AE_AML_OPERAND_VALUE; ++ goto cleanup; ++ } ++ ++ ++ /* ++ * Write a partial field datum if field does not begin on a datum boundary ++ * ++ * Construct Mask with 1 bits where the field is, 0 bits elsewhere ++ * ++ * 1) Bits above the field ++ */ ++ ++ mask = (((u32)(-1)) << (u32) obj_desc->common_field.bit_offset); ++ ++ /* 2) Only the bottom 5 bits are valid for a shift operation. */ ++ ++ if ((obj_desc->common_field.bit_offset + obj_desc->common_field.bit_length) < 32) { ++ /* Bits above the field */ ++ ++ mask &= (~(((u32) (-1)) << ((u32) obj_desc->common_field.bit_offset + ++ (u32) obj_desc->common_field.bit_length))); ++ } ++ ++ /* 3) Shift and mask the value into the field position */ ++ ++ field_value = (previous_raw_datum << obj_desc->common_field.bit_offset) & mask; ++ ++ status = acpi_aml_write_field_datum_with_update_rule (obj_desc, mask, field_value, ++ this_field_byte_offset, bit_granularity); ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ ++ ++ /* If the field fits within one datum, we are done. */ ++ ++ if ((datum_length == 1) && ++ ((obj_desc->common_field.bit_offset + obj_desc->common_field.bit_length) <= ++ (u16) bit_granularity)) { ++ goto cleanup; ++ } ++ ++ /* ++ * We don't need to worry about the update rule for these data, because ++ * all of the bits are part of the field. ++ * ++ * Can't write the last datum, however, because it might contain bits that ++ * are not part of the field -- the update rule must be applied. ++ */ ++ ++ while (this_field_datum_offset < (datum_length - 1)) { ++ this_field_datum_offset++; ++ ++ /* Get the next raw datum, it contains bits of the current field datum... */ ++ ++ switch (byte_granularity) { ++ case 1: ++ this_raw_datum = ((u8 *) buffer) [this_field_datum_offset]; ++ break; ++ ++ case 2: ++ MOVE_UNALIGNED16_TO_32 (&this_raw_datum, ++ &(((u16 *) buffer) [this_field_datum_offset])); ++ break; ++ ++ case 4: ++ MOVE_UNALIGNED32_TO_32 (&this_raw_datum, ++ &(((u32 *) buffer) [this_field_datum_offset])); ++ break; ++ ++ default: ++ status = AE_AML_OPERAND_VALUE; ++ goto cleanup; ++ } ++ ++ /* ++ * Put together bits of the two raw data to make a complete field ++ * datum ++ */ ++ ++ if (obj_desc->common_field.bit_offset != 0) { ++ merged_datum = (previous_raw_datum >> ++ (bit_granularity - obj_desc->common_field.bit_offset)) | ++ (this_raw_datum << obj_desc->common_field.bit_offset); ++ } ++ ++ else { ++ merged_datum = this_raw_datum; ++ } ++ ++ /* Now write the completed datum */ ++ ++ ++ status = acpi_aml_write_field_datum (obj_desc, ++ this_field_byte_offset + byte_granularity, ++ bit_granularity, merged_datum); ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ ++ ++ /* ++ * Save the most recent datum since it contains bits of ++ * the *next* field datum ++ */ ++ ++ previous_raw_datum = this_raw_datum; ++ ++ this_field_byte_offset += byte_granularity; ++ ++ } /* while */ ++ ++ ++ /* Write a partial field datum if field does not end on a datum boundary */ ++ ++ if ((obj_desc->common_field.bit_length + obj_desc->common_field.bit_offset) % ++ bit_granularity) { ++ switch (byte_granularity) { ++ case 1: ++ this_raw_datum = ((u8 *) buffer) [this_field_datum_offset]; ++ break; ++ ++ case 2: ++ MOVE_UNALIGNED16_TO_32 (&this_raw_datum, ++ &(((u16 *) buffer) [this_field_datum_offset])); ++ break; ++ ++ case 4: ++ MOVE_UNALIGNED32_TO_32 (&this_raw_datum, ++ &(((u32 *) buffer) [this_field_datum_offset])); ++ break; ++ } ++ ++ /* Construct Mask with 1 bits where the field is, 0 bits elsewhere */ ++ ++ valid_field_bits = ((obj_desc->common_field.bit_length % bit_granularity) + ++ obj_desc->common_field.bit_offset); ++ ++ mask = (((u32) 1 << valid_field_bits) - (u32) 1); ++ ++ /* Shift and mask the value into the field position */ ++ ++ field_value = (previous_raw_datum >> ++ (bit_granularity - obj_desc->common_field.bit_offset)) & mask; ++ ++ status = acpi_aml_write_field_datum_with_update_rule (obj_desc, mask, ++ field_value, this_field_byte_offset + byte_granularity, ++ bit_granularity); ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ } ++ ++ ++cleanup: ++ ++ return (status); ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/ammisc.c linux/drivers/acpi/executer/ammisc.c +--- /usr/src/linux/drivers/acpi/executer/ammisc.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/ammisc.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,513 @@ ++ ++/****************************************************************************** ++ * ++ * Module Name: ammisc - ACPI AML (p-code) execution - specific opcodes ++ * $Revision: 75 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acparser.h" ++#include "acinterp.h" ++#include "amlcode.h" ++#include "acdispat.h" ++ ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("ammisc") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_exec_fatal ++ * ++ * PARAMETERS: none ++ * ++ * RETURN: Status. If the OS returns from the OSD call, we just keep ++ * on going. ++ * ++ * DESCRIPTION: Execute Fatal operator ++ * ++ * ACPI SPECIFICATION REFERENCES: ++ * Def_fatal := Fatal_op Fatal_type Fatal_code Fatal_arg ++ * Fatal_type := Byte_data ++ * Fatal_code := DWord_data ++ * Fatal_arg := Term_arg=>Integer ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_exec_fatal ( ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_OPERAND_OBJECT *type_desc; ++ ACPI_OPERAND_OBJECT *code_desc; ++ ACPI_OPERAND_OBJECT *arg_desc; ++ ACPI_STATUS status; ++ ++ ++ /* Resolve operands */ ++ ++ status = acpi_aml_resolve_operands (AML_FATAL_OP, WALK_OPERANDS, walk_state); ++ /* Get operands */ ++ ++ status |= acpi_ds_obj_stack_pop_object (&arg_desc, walk_state); ++ status |= acpi_ds_obj_stack_pop_object (&code_desc, walk_state); ++ status |= acpi_ds_obj_stack_pop_object (&type_desc, walk_state); ++ if (ACPI_FAILURE (status)) { ++ /* Invalid parameters on object stack */ ++ ++ goto cleanup; ++ } ++ ++ ++ /* Def_fatal := Fatal_op Fatal_type Fatal_code Fatal_arg */ ++ ++ ++ /* ++ * TBD: [Unhandled] call OSD interface to notify OS of fatal error ++ * requiring shutdown! ++ */ ++ ++ ++cleanup: ++ ++ /* Free the operands */ ++ ++ acpi_cm_remove_reference (arg_desc); ++ acpi_cm_remove_reference (code_desc); ++ acpi_cm_remove_reference (type_desc); ++ ++ ++ /* If we get back from the OS call, we might as well keep going. */ ++ ++ REPORT_WARNING (("An AML \"fatal\" Opcode (Fatal_op) was executed\n")); ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_exec_index ++ * ++ * PARAMETERS: none ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Execute Index operator ++ * ++ * ALLOCATION: Deletes one operand descriptor -- other remains on stack ++ * ++ * ACPI SPECIFICATION REFERENCES: ++ * Def_index := Index_op Buff_pkg_obj Index_value Result ++ * Index_value := Term_arg=>Integer ++ * Name_string := <Root_char Name_path> | <Prefix_path Name_path> ++ * Result := Super_name ++ * Super_name := Name_string | Arg_obj | Local_obj | Debug_obj | Def_index ++ * Local4_op | Local5_op | Local6_op | Local7_op ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_exec_index ( ++ ACPI_WALK_STATE *walk_state, ++ ACPI_OPERAND_OBJECT **return_desc) ++{ ++ ACPI_OPERAND_OBJECT *obj_desc; ++ ACPI_OPERAND_OBJECT *idx_desc; ++ ACPI_OPERAND_OBJECT *res_desc; ++ ACPI_OPERAND_OBJECT *ret_desc = NULL; ++ ACPI_OPERAND_OBJECT *tmp_desc; ++ ACPI_STATUS status; ++ ++ ++ /* Resolve operands */ ++ /* First operand can be either a package or a buffer */ ++ ++ status = acpi_aml_resolve_operands (AML_INDEX_OP, WALK_OPERANDS, walk_state); ++ /* Get all operands */ ++ ++ status |= acpi_ds_obj_stack_pop_object (&res_desc, walk_state); ++ status |= acpi_ds_obj_stack_pop_object (&idx_desc, walk_state); ++ status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); ++ if (ACPI_FAILURE (status)) { ++ /* Invalid parameters on object stack */ ++ ++ goto cleanup; ++ } ++ ++ ++ /* Create the internal return object */ ++ ++ ret_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_REFERENCE); ++ if (!ret_desc) { ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ ++ /* ++ * At this point, the Obj_desc operand is either a Package or a Buffer ++ */ ++ ++ if (obj_desc->common.type == ACPI_TYPE_PACKAGE) { ++ /* Object to be indexed is a Package */ ++ ++ if (idx_desc->integer.value >= obj_desc->package.count) { ++ status = AE_AML_PACKAGE_LIMIT; ++ goto cleanup; ++ } ++ ++ if ((res_desc->common.type == INTERNAL_TYPE_REFERENCE) && ++ (res_desc->reference.opcode == AML_ZERO_OP)) { ++ /* ++ * There is no actual result descriptor (the Zero_op Result ++ * descriptor is a placeholder), so just delete the placeholder and ++ * return a reference to the package element ++ */ ++ ++ acpi_cm_remove_reference (res_desc); ++ } ++ ++ else { ++ /* ++ * Each element of the package is an internal object. Get the one ++ * we are after. ++ */ ++ ++ tmp_desc = obj_desc->package.elements[idx_desc->integer.value]; ++ ret_desc->reference.opcode = AML_INDEX_OP; ++ ret_desc->reference.target_type = tmp_desc->common.type; ++ ret_desc->reference.object = tmp_desc; ++ ++ status = acpi_aml_exec_store (ret_desc, res_desc, walk_state); ++ ret_desc->reference.object = NULL; ++ } ++ ++ /* ++ * The local return object must always be a reference to the package element, ++ * not the element itself. ++ */ ++ ret_desc->reference.opcode = AML_INDEX_OP; ++ ret_desc->reference.target_type = ACPI_TYPE_PACKAGE; ++ ret_desc->reference.where = &obj_desc->package.elements[idx_desc->integer.value]; ++ } ++ ++ else { ++ /* Object to be indexed is a Buffer */ ++ ++ if (idx_desc->integer.value >= obj_desc->buffer.length) { ++ status = AE_AML_BUFFER_LIMIT; ++ goto cleanup; ++ } ++ ++ ret_desc->reference.opcode = AML_INDEX_OP; ++ ret_desc->reference.target_type = ACPI_TYPE_BUFFER_FIELD; ++ ret_desc->reference.object = obj_desc; ++ ret_desc->reference.offset = (u32) idx_desc->integer.value; ++ ++ status = acpi_aml_exec_store (ret_desc, res_desc, walk_state); ++ } ++ ++ ++cleanup: ++ ++ /* Always delete operands */ ++ ++ acpi_cm_remove_reference (obj_desc); ++ acpi_cm_remove_reference (idx_desc); ++ ++ /* Delete return object on error */ ++ ++ if (ACPI_FAILURE (status)) { ++ acpi_cm_remove_reference (res_desc); ++ ++ if (ret_desc) { ++ acpi_cm_remove_reference (ret_desc); ++ ret_desc = NULL; ++ } ++ } ++ ++ /* Set the return object and exit */ ++ ++ *return_desc = ret_desc; ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_exec_match ++ * ++ * PARAMETERS: none ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Execute Match operator ++ * ++ * ACPI SPECIFICATION REFERENCES: ++ * Def_match := Match_op Search_pkg Opcode1 Operand1 ++ * Opcode2 Operand2 Start_index ++ * Opcode1 := Byte_data: MTR, MEQ, MLE, MLT, MGE, or MGT ++ * Opcode2 := Byte_data: MTR, MEQ, MLE, MLT, MGE, or MGT ++ * Operand1 := Term_arg=>Integer ++ * Operand2 := Term_arg=>Integer ++ * Search_pkg := Term_arg=>Package_object ++ * Start_index := Term_arg=>Integer ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_exec_match ( ++ ACPI_WALK_STATE *walk_state, ++ ACPI_OPERAND_OBJECT **return_desc) ++{ ++ ACPI_OPERAND_OBJECT *pkg_desc; ++ ACPI_OPERAND_OBJECT *op1_desc; ++ ACPI_OPERAND_OBJECT *V1_desc; ++ ACPI_OPERAND_OBJECT *op2_desc; ++ ACPI_OPERAND_OBJECT *V2_desc; ++ ACPI_OPERAND_OBJECT *start_desc; ++ ACPI_OPERAND_OBJECT *ret_desc = NULL; ++ ACPI_STATUS status; ++ u32 index; ++ u32 match_value = (u32) -1; ++ ++ ++ /* Resolve all operands */ ++ ++ status = acpi_aml_resolve_operands (AML_MATCH_OP, WALK_OPERANDS, walk_state); ++ /* Get all operands */ ++ ++ status |= acpi_ds_obj_stack_pop_object (&start_desc, walk_state); ++ status |= acpi_ds_obj_stack_pop_object (&V2_desc, walk_state); ++ status |= acpi_ds_obj_stack_pop_object (&op2_desc, walk_state); ++ status |= acpi_ds_obj_stack_pop_object (&V1_desc, walk_state); ++ status |= acpi_ds_obj_stack_pop_object (&op1_desc, walk_state); ++ status |= acpi_ds_obj_stack_pop_object (&pkg_desc, walk_state); ++ ++ if (ACPI_FAILURE (status)) { ++ /* Invalid parameters on object stack */ ++ ++ goto cleanup; ++ } ++ ++ /* Validate match comparison sub-opcodes */ ++ ++ if ((op1_desc->integer.value > MAX_MATCH_OPERATOR) || ++ (op2_desc->integer.value > MAX_MATCH_OPERATOR)) { ++ status = AE_AML_OPERAND_VALUE; ++ goto cleanup; ++ } ++ ++ index = (u32) start_desc->integer.value; ++ if (index >= (u32) pkg_desc->package.count) { ++ status = AE_AML_PACKAGE_LIMIT; ++ goto cleanup; ++ } ++ ++ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); ++ if (!ret_desc) { ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ ++ } ++ ++ /* ++ * Examine each element until a match is found. Within the loop, ++ * "continue" signifies that the current element does not match ++ * and the next should be examined. ++ * Upon finding a match, the loop will terminate via "break" at ++ * the bottom. If it terminates "normally", Match_value will be -1 ++ * (its initial value) indicating that no match was found. When ++ * returned as a Number, this will produce the Ones value as specified. ++ */ ++ ++ for ( ; index < pkg_desc->package.count; ++index) { ++ /* ++ * Treat any NULL or non-numeric elements as non-matching. ++ * TBD [Unhandled] - if an element is a Name, ++ * should we examine its value? ++ */ ++ if (!pkg_desc->package.elements[index] || ++ ACPI_TYPE_INTEGER != pkg_desc->package.elements[index]->common.type) { ++ continue; ++ } ++ ++ /* ++ * Within these switch statements: ++ * "break" (exit from the switch) signifies a match; ++ * "continue" (proceed to next iteration of enclosing ++ * "for" loop) signifies a non-match. ++ */ ++ switch (op1_desc->integer.value) { ++ ++ case MATCH_MTR: /* always true */ ++ ++ break; ++ ++ ++ case MATCH_MEQ: /* true if equal */ ++ ++ if (pkg_desc->package.elements[index]->integer.value ++ != V1_desc->integer.value) { ++ continue; ++ } ++ break; ++ ++ ++ case MATCH_MLE: /* true if less than or equal */ ++ ++ if (pkg_desc->package.elements[index]->integer.value ++ > V1_desc->integer.value) { ++ continue; ++ } ++ break; ++ ++ ++ case MATCH_MLT: /* true if less than */ ++ ++ if (pkg_desc->package.elements[index]->integer.value ++ >= V1_desc->integer.value) { ++ continue; ++ } ++ break; ++ ++ ++ case MATCH_MGE: /* true if greater than or equal */ ++ ++ if (pkg_desc->package.elements[index]->integer.value ++ < V1_desc->integer.value) { ++ continue; ++ } ++ break; ++ ++ ++ case MATCH_MGT: /* true if greater than */ ++ ++ if (pkg_desc->package.elements[index]->integer.value ++ <= V1_desc->integer.value) { ++ continue; ++ } ++ break; ++ ++ ++ default: /* undefined */ ++ ++ continue; ++ } ++ ++ ++ switch(op2_desc->integer.value) { ++ ++ case MATCH_MTR: ++ ++ break; ++ ++ ++ case MATCH_MEQ: ++ ++ if (pkg_desc->package.elements[index]->integer.value ++ != V2_desc->integer.value) { ++ continue; ++ } ++ break; ++ ++ ++ case MATCH_MLE: ++ ++ if (pkg_desc->package.elements[index]->integer.value ++ > V2_desc->integer.value) { ++ continue; ++ } ++ break; ++ ++ ++ case MATCH_MLT: ++ ++ if (pkg_desc->package.elements[index]->integer.value ++ >= V2_desc->integer.value) { ++ continue; ++ } ++ break; ++ ++ ++ case MATCH_MGE: ++ ++ if (pkg_desc->package.elements[index]->integer.value ++ < V2_desc->integer.value) { ++ continue; ++ } ++ break; ++ ++ ++ case MATCH_MGT: ++ ++ if (pkg_desc->package.elements[index]->integer.value ++ <= V2_desc->integer.value) { ++ continue; ++ } ++ break; ++ ++ ++ default: ++ ++ continue; ++ } ++ ++ /* Match found: exit from loop */ ++ ++ match_value = index; ++ break; ++ } ++ ++ /* Match_value is the return value */ ++ ++ ret_desc->integer.value = match_value; ++ ++ ++cleanup: ++ ++ /* Free the operands */ ++ ++ acpi_cm_remove_reference (start_desc); ++ acpi_cm_remove_reference (V2_desc); ++ acpi_cm_remove_reference (op2_desc); ++ acpi_cm_remove_reference (V1_desc); ++ acpi_cm_remove_reference (op1_desc); ++ acpi_cm_remove_reference (pkg_desc); ++ ++ ++ /* Delete return object on error */ ++ ++ if (ACPI_FAILURE (status) && ++ (ret_desc)) { ++ acpi_cm_remove_reference (ret_desc); ++ ret_desc = NULL; ++ } ++ ++ ++ /* Set the return object and exit */ ++ ++ *return_desc = ret_desc; ++ return (status); ++} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/ammonad.c linux/drivers/acpi/executer/ammonad.c +--- /usr/src/linux/drivers/acpi/executer/ammonad.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/ammonad.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,973 @@ ++ ++/****************************************************************************** ++ * ++ * Module Name: ammonad - ACPI AML (p-code) execution for monadic operators ++ * $Revision: 96 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acparser.h" ++#include "acdispat.h" ++#include "acinterp.h" ++#include "amlcode.h" ++#include "acnamesp.h" ++ ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("ammonad") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_get_object_reference ++ * ++ * PARAMETERS: Obj_desc - Create a reference to this object ++ * Ret_desc - Where to store the reference ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Obtain and return a "reference" to the target object ++ * Common code for the Ref_of_op and the Cond_ref_of_op. ++ * ++ ******************************************************************************/ ++ ++static ACPI_STATUS ++acpi_aml_get_object_reference ( ++ ACPI_OPERAND_OBJECT *obj_desc, ++ ACPI_OPERAND_OBJECT **ret_desc, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ ++ if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_INTERNAL)) { ++ if (obj_desc->common.type != INTERNAL_TYPE_REFERENCE) { ++ *ret_desc = NULL; ++ status = AE_TYPE; ++ goto cleanup; ++ } ++ ++ /* ++ * Not a Name -- an indirect name pointer would have ++ * been converted to a direct name pointer in Acpi_aml_resolve_operands ++ */ ++ switch (obj_desc->reference.opcode) { ++ case AML_LOCAL_OP: ++ case AML_ARG_OP: ++ ++ *ret_desc = (void *) acpi_ds_method_data_get_node (obj_desc->reference.opcode, ++ obj_desc->reference.offset, walk_state); ++ break; ++ ++ default: ++ ++ *ret_desc = NULL; ++ status = AE_AML_INTERNAL; ++ goto cleanup; ++ } ++ ++ } ++ ++ else if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) { ++ /* Must be a named object; Just return the Node */ ++ ++ *ret_desc = obj_desc; ++ } ++ ++ else { ++ *ret_desc = NULL; ++ status = AE_TYPE; ++ } ++ ++ ++cleanup: ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_exec_monadic1 ++ * ++ * PARAMETERS: Opcode - The opcode to be executed ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Execute Type 1 monadic operator with numeric operand on ++ * object stack ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_exec_monadic1 ( ++ u16 opcode, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_OPERAND_OBJECT *obj_desc; ++ ACPI_STATUS status; ++ ++ ++ /* Resolve all operands */ ++ ++ status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); ++ /* Get all operands */ ++ ++ status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ ++ ++ /* Examine the opcode */ ++ ++ switch (opcode) { ++ ++ /* Def_release := Release_op Mutex_object */ ++ ++ case AML_RELEASE_OP: ++ ++ status = acpi_aml_release_mutex (obj_desc, walk_state); ++ break; ++ ++ ++ /* Def_reset := Reset_op Acpi_event_object */ ++ ++ case AML_RESET_OP: ++ ++ status = acpi_aml_system_reset_event (obj_desc); ++ break; ++ ++ ++ /* Def_signal := Signal_op Acpi_event_object */ ++ ++ case AML_SIGNAL_OP: ++ ++ status = acpi_aml_system_signal_event (obj_desc); ++ break; ++ ++ ++ /* Def_sleep := Sleep_op Msec_time */ ++ ++ case AML_SLEEP_OP: ++ ++ acpi_aml_system_do_suspend ((u32) obj_desc->integer.value); ++ break; ++ ++ ++ /* Def_stall := Stall_op Usec_time */ ++ ++ case AML_STALL_OP: ++ ++ acpi_aml_system_do_stall ((u32) obj_desc->integer.value); ++ break; ++ ++ ++ /* Unknown opcode */ ++ ++ default: ++ ++ REPORT_ERROR (("Acpi_aml_exec_monadic1: Unknown monadic opcode %X\n", ++ opcode)); ++ status = AE_AML_BAD_OPCODE; ++ break; ++ ++ } /* switch */ ++ ++ ++cleanup: ++ ++ /* Always delete the operand */ ++ ++ acpi_cm_remove_reference (obj_desc); ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_exec_monadic2_r ++ * ++ * PARAMETERS: Opcode - The opcode to be executed ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Execute Type 2 monadic operator with numeric operand and ++ * result operand on operand stack ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_exec_monadic2_r ( ++ u16 opcode, ++ ACPI_WALK_STATE *walk_state, ++ ACPI_OPERAND_OBJECT **return_desc) ++{ ++ ACPI_OPERAND_OBJECT *obj_desc; ++ ACPI_OPERAND_OBJECT *res_desc; ++ ACPI_OPERAND_OBJECT *ret_desc = NULL; ++ ACPI_OPERAND_OBJECT *ret_desc2 = NULL; ++ u32 res_val; ++ ACPI_STATUS status; ++ u32 i; ++ u32 j; ++ ACPI_INTEGER digit; ++ ++ ++ /* Resolve all operands */ ++ ++ status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); ++ /* Get all operands */ ++ ++ status |= acpi_ds_obj_stack_pop_object (&res_desc, walk_state); ++ status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ ++ ++ /* Create a return object of type NUMBER for most opcodes */ ++ ++ switch (opcode) { ++ case AML_BIT_NOT_OP: ++ case AML_FIND_SET_LEFT_BIT_OP: ++ case AML_FIND_SET_RIGHT_BIT_OP: ++ case AML_FROM_BCD_OP: ++ case AML_TO_BCD_OP: ++ case AML_COND_REF_OF_OP: ++ ++ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); ++ if (!ret_desc) { ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ break; ++ } ++ ++ ++ switch (opcode) { ++ /* Def_not := Not_op Operand Result */ ++ ++ case AML_BIT_NOT_OP: ++ ++ ret_desc->integer.value = ~obj_desc->integer.value; ++ break; ++ ++ ++ /* Def_find_set_left_bit := Find_set_left_bit_op Operand Result */ ++ ++ case AML_FIND_SET_LEFT_BIT_OP: ++ ++ ret_desc->integer.value = obj_desc->integer.value; ++ ++ /* ++ * Acpi specification describes Integer type as a little ++ * endian unsigned value, so this boundry condition is valid. ++ */ ++ for (res_val = 0; ret_desc->integer.value && res_val < ACPI_INTEGER_BIT_SIZE; ++res_val) { ++ ret_desc->integer.value >>= 1; ++ } ++ ++ ret_desc->integer.value = res_val; ++ break; ++ ++ ++ /* Def_find_set_right_bit := Find_set_right_bit_op Operand Result */ ++ ++ case AML_FIND_SET_RIGHT_BIT_OP: ++ ++ ret_desc->integer.value = obj_desc->integer.value; ++ ++ /* ++ * Acpi specification describes Integer type as a little ++ * endian unsigned value, so this boundry condition is valid. ++ */ ++ for (res_val = 0; ret_desc->integer.value && res_val < ACPI_INTEGER_BIT_SIZE; ++res_val) { ++ ret_desc->integer.value <<= 1; ++ } ++ ++ /* Since returns must be 1-based, subtract from 33 (65) */ ++ ++ ret_desc->integer.value = res_val == 0 ? 0 : (ACPI_INTEGER_BIT_SIZE + 1) - res_val; ++ break; ++ ++ ++ /* Def_from_bDC := From_bCDOp BCDValue Result */ ++ ++ case AML_FROM_BCD_OP: ++ ++ /* ++ * The 64-bit ACPI integer can hold 16 4-bit BCD integers ++ */ ++ ret_desc->integer.value = 0; ++ for (i = 0; i < ACPI_MAX_BCD_DIGITS; i++) { ++ /* Get one BCD digit */ ++ ++ digit = (ACPI_INTEGER) ((obj_desc->integer.value >> (i * 4)) & 0xF); ++ ++ /* Check the range of the digit */ ++ ++ if (digit > 9) { ++ status = AE_AML_NUMERIC_OVERFLOW; ++ goto cleanup; ++ } ++ ++ if (digit > 0) { ++ /* Sum into the result with the appropriate power of 10 */ ++ ++ for (j = 0; j < i; j++) { ++ digit *= 10; ++ } ++ ++ ret_desc->integer.value += digit; ++ } ++ } ++ break; ++ ++ ++ /* Def_to_bDC := To_bCDOp Operand Result */ ++ ++ case AML_TO_BCD_OP: ++ ++ ++ if (obj_desc->integer.value > ACPI_MAX_BCD_VALUE) { ++ status = AE_AML_NUMERIC_OVERFLOW; ++ goto cleanup; ++ } ++ ++ ret_desc->integer.value = 0; ++ for (i = 0; i < ACPI_MAX_BCD_DIGITS; i++) { ++ /* Divide by nth factor of 10 */ ++ ++ digit = obj_desc->integer.value; ++ for (j = 0; j < i; j++) { ++ digit /= 10; ++ } ++ ++ /* Create the BCD digit */ ++ ++ if (digit > 0) { ++ ret_desc->integer.value += (ACPI_MODULO (digit, 10) << (i * 4)); ++ } ++ } ++ break; ++ ++ ++ /* Def_cond_ref_of := Cond_ref_of_op Source_object Result */ ++ ++ case AML_COND_REF_OF_OP: ++ ++ /* ++ * This op is a little strange because the internal return value is ++ * different than the return value stored in the result descriptor ++ * (There are really two return values) ++ */ ++ ++ if ((ACPI_NAMESPACE_NODE *) obj_desc == acpi_gbl_root_node) { ++ /* ++ * This means that the object does not exist in the namespace, ++ * return FALSE ++ */ ++ ++ ret_desc->integer.value = 0; ++ ++ /* ++ * Must delete the result descriptor since there is no reference ++ * being returned ++ */ ++ ++ acpi_cm_remove_reference (res_desc); ++ goto cleanup; ++ } ++ ++ /* Get the object reference and store it */ ++ ++ status = acpi_aml_get_object_reference (obj_desc, &ret_desc2, walk_state); ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ ++ status = acpi_aml_exec_store (ret_desc2, res_desc, walk_state); ++ ++ /* The object exists in the namespace, return TRUE */ ++ ++ ret_desc->integer.value = ACPI_INTEGER_MAX; ++ goto cleanup; ++ break; ++ ++ ++ case AML_STORE_OP: ++ ++ /* ++ * A store operand is typically a number, string, buffer or lvalue ++ * TBD: [Unhandled] What about a store to a package? ++ */ ++ ++ /* ++ * Do the store, and be careful about deleting the source object, ++ * since the object itself may have been stored. ++ */ ++ ++ status = acpi_aml_exec_store (obj_desc, res_desc, walk_state); ++ if (ACPI_FAILURE (status)) { ++ /* On failure, just delete the Obj_desc */ ++ ++ acpi_cm_remove_reference (obj_desc); ++ } ++ ++ else { ++ /* ++ * Normally, we would remove a reference on the Obj_desc parameter; ++ * But since it is being used as the internal return object ++ * (meaning we would normally increment it), the two cancel out, ++ * and we simply don't do anything. ++ */ ++ *return_desc = obj_desc; ++ } ++ ++ obj_desc = NULL; ++ return (status); ++ ++ break; ++ ++ ++ case AML_DEBUG_OP: ++ ++ /* Reference, returning an Reference */ ++ ++ return (AE_OK); ++ break; ++ ++ ++ /* ++ * These are obsolete opcodes ++ */ ++ ++ /* Def_shift_left_bit := Shift_left_bit_op Source Bit_num */ ++ /* Def_shift_right_bit := Shift_right_bit_op Source Bit_num */ ++ ++ case AML_SHIFT_LEFT_BIT_OP: ++ case AML_SHIFT_RIGHT_BIT_OP: ++ ++ status = AE_SUPPORT; ++ goto cleanup; ++ break; ++ ++ ++ default: ++ ++ REPORT_ERROR (("Acpi_aml_exec_monadic2_r: Unknown monadic opcode %X\n", ++ opcode)); ++ status = AE_AML_BAD_OPCODE; ++ goto cleanup; ++ } ++ ++ ++ status = acpi_aml_exec_store (ret_desc, res_desc, walk_state); ++ ++ ++cleanup: ++ /* Always delete the operand object */ ++ ++ acpi_cm_remove_reference (obj_desc); ++ ++ /* Delete return object(s) on error */ ++ ++ if (ACPI_FAILURE (status)) { ++ acpi_cm_remove_reference (res_desc); /* Result descriptor */ ++ if (ret_desc) { ++ acpi_cm_remove_reference (ret_desc); ++ ret_desc = NULL; ++ } ++ } ++ ++ /* Set the return object and exit */ ++ ++ *return_desc = ret_desc; ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_exec_monadic2 ++ * ++ * PARAMETERS: Opcode - The opcode to be executed ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Execute Type 2 monadic operator with numeric operand: ++ * Deref_of_op, Ref_of_op, Size_of_op, Type_op, Increment_op, ++ * Decrement_op, LNot_op, ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_exec_monadic2 ( ++ u16 opcode, ++ ACPI_WALK_STATE *walk_state, ++ ACPI_OPERAND_OBJECT **return_desc) ++{ ++ ACPI_OPERAND_OBJECT *obj_desc; ++ ACPI_OPERAND_OBJECT *tmp_desc; ++ ACPI_OPERAND_OBJECT *ret_desc = NULL; ++ ACPI_STATUS resolve_status; ++ ACPI_STATUS status; ++ u32 type; ++ ACPI_INTEGER value; ++ ++ ++ /* Attempt to resolve the operands */ ++ ++ resolve_status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); ++ /* Always get all operands */ ++ ++ status = acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); ++ ++ ++ /* Now we can check the status codes */ ++ ++ if (ACPI_FAILURE (resolve_status)) { ++ goto cleanup; ++ } ++ ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ ++ ++ /* Get the operand and decode the opcode */ ++ ++ ++ switch (opcode) { ++ ++ /* Def_lNot := LNot_op Operand */ ++ ++ case AML_LNOT_OP: ++ ++ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); ++ if (!ret_desc) { ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ ret_desc->integer.value = !obj_desc->integer.value; ++ break; ++ ++ ++ /* Def_decrement := Decrement_op Target */ ++ /* Def_increment := Increment_op Target */ ++ ++ case AML_DECREMENT_OP: ++ case AML_INCREMENT_OP: ++ ++ /* ++ * Since we are expecting an Reference on the top of the stack, it ++ * can be either an Node or an internal object. ++ * ++ * TBD: [Future] This may be the prototype code for all cases where ++ * an Reference is expected!! 10/99 ++ */ ++ ++ if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) { ++ ret_desc = obj_desc; ++ } ++ ++ else { ++ /* ++ * Duplicate the Reference in a new object so that we can resolve it ++ * without destroying the original Reference object ++ */ ++ ++ ret_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_REFERENCE); ++ if (!ret_desc) { ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ ret_desc->reference.opcode = obj_desc->reference.opcode; ++ ret_desc->reference.offset = obj_desc->reference.offset; ++ ret_desc->reference.object = obj_desc->reference.object; ++ } ++ ++ ++ /* ++ * Convert the Ret_desc Reference to a Number ++ * (This deletes the original Ret_desc) ++ */ ++ ++ status = acpi_aml_resolve_operands (AML_LNOT_OP, &ret_desc, walk_state); ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ ++ /* Do the actual increment or decrement */ ++ ++ if (AML_INCREMENT_OP == opcode) { ++ ret_desc->integer.value++; ++ } ++ else { ++ ret_desc->integer.value--; ++ } ++ ++ /* Store the result back in the original descriptor */ ++ ++ status = acpi_aml_exec_store (ret_desc, obj_desc, walk_state); ++ ++ /* Objdesc was just deleted (because it is an Reference) */ ++ ++ obj_desc = NULL; ++ ++ break; ++ ++ ++ /* Def_object_type := Object_type_op Source_object */ ++ ++ case AML_TYPE_OP: ++ ++ if (INTERNAL_TYPE_REFERENCE == obj_desc->common.type) { ++ /* ++ * Not a Name -- an indirect name pointer would have ++ * been converted to a direct name pointer in Resolve_operands ++ */ ++ switch (obj_desc->reference.opcode) { ++ case AML_ZERO_OP: ++ case AML_ONE_OP: ++ case AML_ONES_OP: ++ ++ /* Constants are of type Number */ ++ ++ type = ACPI_TYPE_INTEGER; ++ break; ++ ++ ++ case AML_DEBUG_OP: ++ ++ /* Per 1.0b spec, Debug object is of type Debug_object */ ++ ++ type = ACPI_TYPE_DEBUG_OBJECT; ++ break; ++ ++ ++ case AML_INDEX_OP: ++ ++ /* Get the type of this reference (index into another object) */ ++ ++ type = obj_desc->reference.target_type; ++ if (type == ACPI_TYPE_PACKAGE) { ++ /* ++ * The main object is a package, we want to get the type ++ * of the individual package element that is referenced by ++ * the index. ++ */ ++ type = (*(obj_desc->reference.where))->common.type; ++ } ++ ++ break; ++ ++ ++ case AML_LOCAL_OP: ++ case AML_ARG_OP: ++ ++ type = acpi_ds_method_data_get_type (obj_desc->reference.opcode, ++ obj_desc->reference.offset, walk_state); ++ break; ++ ++ ++ default: ++ ++ REPORT_ERROR (("Acpi_aml_exec_monadic2/Type_op: Internal error - Unknown Reference subtype %X\n", ++ obj_desc->reference.opcode)); ++ status = AE_AML_INTERNAL; ++ goto cleanup; ++ } ++ } ++ ++ else { ++ /* ++ * It's not a Reference, so it must be a direct name pointer. ++ */ ++ type = acpi_ns_get_type ((ACPI_NAMESPACE_NODE *) obj_desc); ++ ++ /* Convert internal types to external types */ ++ ++ switch (type) { ++ case INTERNAL_TYPE_REGION_FIELD: ++ case INTERNAL_TYPE_BANK_FIELD: ++ case INTERNAL_TYPE_INDEX_FIELD: ++ ++ type = ACPI_TYPE_FIELD_UNIT; ++ } ++ ++ } ++ ++ /* Allocate a descriptor to hold the type. */ ++ ++ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); ++ if (!ret_desc) { ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ ret_desc->integer.value = type; ++ break; ++ ++ ++ /* Def_size_of := Size_of_op Source_object */ ++ ++ case AML_SIZE_OF_OP: ++ ++ if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) { ++ obj_desc = acpi_ns_get_attached_object ((ACPI_NAMESPACE_NODE *) obj_desc); ++ } ++ ++ if (!obj_desc) { ++ value = 0; ++ } ++ ++ else { ++ switch (obj_desc->common.type) { ++ ++ case ACPI_TYPE_BUFFER: ++ ++ value = obj_desc->buffer.length; ++ break; ++ ++ ++ case ACPI_TYPE_STRING: ++ ++ value = obj_desc->string.length; ++ break; ++ ++ ++ case ACPI_TYPE_PACKAGE: ++ ++ value = obj_desc->package.count; ++ break; ++ ++ case INTERNAL_TYPE_REFERENCE: ++ ++ value = 4; ++ break; ++ ++ default: ++ ++ status = AE_AML_OPERAND_TYPE; ++ goto cleanup; ++ } ++ } ++ ++ /* ++ * Now that we have the size of the object, create a result ++ * object to hold the value ++ */ ++ ++ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); ++ if (!ret_desc) { ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ ret_desc->integer.value = value; ++ break; ++ ++ ++ /* Def_ref_of := Ref_of_op Source_object */ ++ ++ case AML_REF_OF_OP: ++ ++ status = acpi_aml_get_object_reference (obj_desc, &ret_desc, walk_state); ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ break; ++ ++ ++ /* Def_deref_of := Deref_of_op Obj_reference */ ++ ++ case AML_DEREF_OF_OP: ++ ++ ++ /* Check for a method local or argument */ ++ ++ if (!VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) { ++ /* ++ * Must resolve/dereference the local/arg reference first ++ */ ++ switch (obj_desc->reference.opcode) { ++ /* Set Obj_desc to the value of the local/arg */ ++ ++ case AML_LOCAL_OP: ++ case AML_ARG_OP: ++ ++ acpi_ds_method_data_get_value (obj_desc->reference.opcode, ++ obj_desc->reference.offset, walk_state, &tmp_desc); ++ ++ /* ++ * Delete our reference to the input object and ++ * point to the object just retrieved ++ */ ++ acpi_cm_remove_reference (obj_desc); ++ obj_desc = tmp_desc; ++ break; ++ ++ default: ++ ++ /* Index op - handled below */ ++ break; ++ } ++ } ++ ++ ++ /* Obj_desc may have changed from the code above */ ++ ++ if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) { ++ /* Get the actual object from the Node (This is the dereference) */ ++ ++ ret_desc = ((ACPI_NAMESPACE_NODE *) obj_desc)->object; ++ ++ /* Returning a pointer to the object, add another reference! */ ++ ++ acpi_cm_add_reference (ret_desc); ++ } ++ ++ else { ++ /* ++ * This must be a reference object produced by the Index ++ * ASL operation -- check internal opcode ++ */ ++ ++ if ((obj_desc->reference.opcode != AML_INDEX_OP) && ++ (obj_desc->reference.opcode != AML_REF_OF_OP)) { ++ status = AE_TYPE; ++ goto cleanup; ++ } ++ ++ ++ switch (obj_desc->reference.opcode) { ++ case AML_INDEX_OP: ++ ++ /* ++ * Supported target types for the Index operator are ++ * 1) A Buffer ++ * 2) A Package ++ */ ++ ++ if (obj_desc->reference.target_type == ACPI_TYPE_BUFFER_FIELD) { ++ /* ++ * The target is a buffer, we must create a new object that ++ * contains one element of the buffer, the element pointed ++ * to by the index. ++ * ++ * NOTE: index into a buffer is NOT a pointer to a ++ * sub-buffer of the main buffer, it is only a pointer to a ++ * single element (byte) of the buffer! ++ */ ++ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); ++ if (!ret_desc) { ++ status = AE_NO_MEMORY; ++ goto cleanup; ++ } ++ ++ tmp_desc = obj_desc->reference.object; ++ ret_desc->integer.value = ++ tmp_desc->buffer.pointer[obj_desc->reference.offset]; ++ ++ /* TBD: [Investigate] (see below) Don't add an additional ++ * ref! ++ */ ++ } ++ ++ else if (obj_desc->reference.target_type == ACPI_TYPE_PACKAGE) { ++ /* ++ * The target is a package, we want to return the referenced ++ * element of the package. We must add another reference to ++ * this object, however. ++ */ ++ ++ ret_desc = *(obj_desc->reference.where); ++ if (!ret_desc) { ++ /* ++ * We can't return a NULL dereferenced value. This is ++ * an uninitialized package element and is thus a ++ * severe error. ++ */ ++ ++ status = AE_AML_UNINITIALIZED_ELEMENT; ++ goto cleanup; ++ } ++ ++ acpi_cm_add_reference (ret_desc); ++ } ++ ++ else { ++ status = AE_AML_OPERAND_TYPE; ++ goto cleanup; ++ } ++ ++ break; ++ ++ ++ case AML_REF_OF_OP: ++ ++ ret_desc = obj_desc->reference.object; ++ ++ /* Add another reference to the object! */ ++ ++ acpi_cm_add_reference (ret_desc); ++ break; ++ } ++ } ++ ++ break; ++ ++ ++ default: ++ ++ REPORT_ERROR (("Acpi_aml_exec_monadic2: Unknown monadic opcode %X\n", ++ opcode)); ++ status = AE_AML_BAD_OPCODE; ++ goto cleanup; ++ } ++ ++ ++cleanup: ++ ++ if (obj_desc) { ++ acpi_cm_remove_reference (obj_desc); ++ } ++ ++ /* Delete return object on error */ ++ ++ if (ACPI_FAILURE (status) && ++ (ret_desc)) { ++ acpi_cm_remove_reference (ret_desc); ++ ret_desc = NULL; ++ } ++ ++ *return_desc = ret_desc; ++ return (status); ++} ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/ammutex.c linux/drivers/acpi/executer/ammutex.c +--- /usr/src/linux/drivers/acpi/executer/ammutex.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/ammutex.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,281 @@ ++ ++/****************************************************************************** ++ * ++ * Module Name: ammutex - ASL Mutex Acquire/Release functions ++ * $Revision: 4 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acinterp.h" ++#include "acnamesp.h" ++#include "achware.h" ++#include "acevents.h" ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("ammutex") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_unlink_mutex ++ * ++ * PARAMETERS: *Obj_desc - The mutex to be unlinked ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Remove a mutex from the "Acquired_mutex" list ++ * ++ ******************************************************************************/ ++ ++void ++acpi_aml_unlink_mutex ( ++ ACPI_OPERAND_OBJECT *obj_desc) ++{ ++ ++ if (obj_desc->mutex.next) { ++ (obj_desc->mutex.next)->mutex.prev = obj_desc->mutex.prev; ++ } ++ if (obj_desc->mutex.prev) { ++ (obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next; ++ } ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_link_mutex ++ * ++ * PARAMETERS: *Obj_desc - The mutex to be linked ++ * *List_head - head of the "Acquired_mutex" list ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Add a mutex to the "Acquired_mutex" list for this walk ++ * ++ ******************************************************************************/ ++ ++void ++acpi_aml_link_mutex ( ++ ACPI_OPERAND_OBJECT *obj_desc, ++ ACPI_OPERAND_OBJECT *list_head) ++{ ++ ++ /* This object will be the first object in the list */ ++ ++ obj_desc->mutex.prev = list_head; ++ obj_desc->mutex.next = list_head->mutex.next; ++ ++ /* Update old first object to point back to this object */ ++ ++ if (list_head->mutex.next) { ++ (list_head->mutex.next)->mutex.prev = obj_desc; ++ } ++ ++ /* Update list head */ ++ ++ list_head->mutex.next = obj_desc; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_acquire_mutex ++ * ++ * PARAMETERS: *Time_desc - The 'time to delay' object descriptor ++ * *Obj_desc - The object descriptor for this op ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Acquire an AML mutex ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_acquire_mutex ( ++ ACPI_OPERAND_OBJECT *time_desc, ++ ACPI_OPERAND_OBJECT *obj_desc, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_STATUS status; ++ ++ ++ if (!obj_desc) { ++ return (AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Current Sync must be less than or equal to the sync level of the ++ * mutex. This mechanism provides some deadlock prevention ++ */ ++ if (walk_state->current_sync_level > obj_desc->mutex.sync_level) { ++ return (AE_AML_MUTEX_ORDER); ++ } ++ ++ /* ++ * If the mutex is already owned by this thread, ++ * just increment the acquisition depth ++ */ ++ if (obj_desc->mutex.owner == walk_state) { ++ obj_desc->mutex.acquisition_depth++; ++ return (AE_OK); ++ } ++ ++ /* Acquire the mutex, wait if necessary */ ++ ++ status = acpi_aml_system_acquire_mutex (time_desc, obj_desc); ++ if (ACPI_FAILURE (status)) { ++ /* Includes failure from a timeout on Time_desc */ ++ ++ return (status); ++ } ++ ++ /* Have the mutex, update mutex and walk info */ ++ ++ obj_desc->mutex.owner = walk_state; ++ obj_desc->mutex.acquisition_depth = 1; ++ walk_state->current_sync_level = obj_desc->mutex.sync_level; ++ ++ /* Link the mutex to the walk state for force-unlock at method exit */ ++ ++ acpi_aml_link_mutex (obj_desc, (ACPI_OPERAND_OBJECT *) ++ &(walk_state->walk_list->acquired_mutex_list)); ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_release_mutex ++ * ++ * PARAMETERS: *Obj_desc - The object descriptor for this op ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Release a previously acquired Mutex. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_release_mutex ( ++ ACPI_OPERAND_OBJECT *obj_desc, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_STATUS status; ++ ++ ++ if (!obj_desc) { ++ return (AE_BAD_PARAMETER); ++ } ++ ++ /* The mutex must have been previously acquired in order to release it */ ++ ++ if (!obj_desc->mutex.owner) { ++ return (AE_AML_MUTEX_NOT_ACQUIRED); ++ } ++ ++ /* The Mutex is owned, but this thread must be the owner */ ++ ++ if (obj_desc->mutex.owner != walk_state) { ++ return (AE_AML_NOT_OWNER); ++ } ++ ++ /* ++ * The sync level of the mutex must be less than or ++ * equal to the current sync level ++ */ ++ if (obj_desc->mutex.sync_level > walk_state->current_sync_level) { ++ return (AE_AML_MUTEX_ORDER); ++ } ++ ++ /* ++ * Match multiple Acquires with multiple Releases ++ */ ++ obj_desc->mutex.acquisition_depth--; ++ if (obj_desc->mutex.acquisition_depth != 0) { ++ /* Just decrement the depth and return */ ++ ++ return (AE_OK); ++ } ++ ++ ++ /* Release the mutex */ ++ ++ status = acpi_aml_system_release_mutex (obj_desc); ++ ++ /* Update the mutex and walk state */ ++ ++ obj_desc->mutex.owner = NULL; ++ walk_state->current_sync_level = obj_desc->mutex.sync_level; ++ ++ /* Unlink the mutex from the owner's list */ ++ ++ acpi_aml_unlink_mutex (obj_desc); ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_release_all_mutexes ++ * ++ * PARAMETERS: *Mutex_list - Head of the mutex list ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Release all mutexes in the list ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_release_all_mutexes ( ++ ACPI_OPERAND_OBJECT *list_head) ++{ ++ ACPI_OPERAND_OBJECT *next = list_head->mutex.next; ++ ACPI_OPERAND_OBJECT *this; ++ ++ ++ /* ++ * Traverse the list of owned mutexes, releasing each one. ++ */ ++ while (next) { ++ this = next; ++ next = this->mutex.next; ++ ++ /* Mark mutex un-owned */ ++ ++ this->mutex.owner = NULL; ++ this->mutex.prev = NULL; ++ this->mutex.next = NULL; ++ this->mutex.acquisition_depth = 0; ++ ++ /* Release the mutex */ ++ ++ acpi_aml_system_release_mutex (this); ++ } ++ ++ return (AE_OK); ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/amnames.c linux/drivers/acpi/executer/amnames.c +--- /usr/src/linux/drivers/acpi/executer/amnames.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/amnames.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,389 @@ ++ ++/****************************************************************************** ++ * ++ * Module Name: amnames - interpreter/scanner name load/execute ++ * $Revision: 76 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acinterp.h" ++#include "amlcode.h" ++#include "acnamesp.h" ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("amnames") ++ ++ ++/* AML Package Length encodings */ ++ ++#define ACPI_AML_PACKAGE_TYPE1 0x40 ++#define ACPI_AML_PACKAGE_TYPE2 0x4000 ++#define ACPI_AML_PACKAGE_TYPE3 0x400000 ++#define ACPI_AML_PACKAGE_TYPE4 0x40000000 ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_allocate_name_string ++ * ++ * PARAMETERS: Prefix_count - Count of parent levels. Special cases: ++ * (-1) = root, 0 = none ++ * Num_name_segs - count of 4-character name segments ++ * ++ * RETURN: A pointer to the allocated string segment. This segment must ++ * be deleted by the caller. ++ * ++ * DESCRIPTION: Allocate a buffer for a name string. Ensure allocated name ++ * string is long enough, and set up prefix if any. ++ * ++ ******************************************************************************/ ++ ++NATIVE_CHAR * ++acpi_aml_allocate_name_string ( ++ u32 prefix_count, ++ u32 num_name_segs) ++{ ++ NATIVE_CHAR *temp_ptr; ++ NATIVE_CHAR *name_string; ++ u32 size_needed; ++ ++ ++ /* ++ * Allow room for all \ and ^ prefixes, all segments, and a Multi_name_prefix. ++ * Also, one byte for the null terminator. ++ * This may actually be somewhat longer than needed. ++ */ ++ ++ if (prefix_count == (u32) -1) { ++ /* Special case for root */ ++ ++ size_needed = 1 + (ACPI_NAME_SIZE * num_name_segs) + 2 + 1; ++ } ++ else { ++ size_needed = prefix_count + (ACPI_NAME_SIZE * num_name_segs) + 2 + 1; ++ } ++ ++ /* ++ * Allocate a buffer for the name. ++ * This buffer must be deleted by the caller! ++ */ ++ ++ name_string = acpi_cm_allocate (size_needed); ++ if (!name_string) { ++ REPORT_ERROR (("Aml_allocate_name_string: name allocation failure\n")); ++ return (NULL); ++ } ++ ++ temp_ptr = name_string; ++ ++ /* Set up Root or Parent prefixes if needed */ ++ ++ if (prefix_count == (u32) -1) { ++ *temp_ptr++ = AML_ROOT_PREFIX; ++ } ++ ++ else { ++ while (prefix_count--) { ++ *temp_ptr++ = AML_PARENT_PREFIX; ++ } ++ } ++ ++ ++ /* Set up Dual or Multi prefixes if needed */ ++ ++ if (num_name_segs > 2) { ++ /* Set up multi prefixes */ ++ ++ *temp_ptr++ = AML_MULTI_NAME_PREFIX_OP; ++ *temp_ptr++ = (char) num_name_segs; ++ } ++ ++ else if (2 == num_name_segs) { ++ /* Set up dual prefixes */ ++ ++ *temp_ptr++ = AML_DUAL_NAME_PREFIX; ++ } ++ ++ /* ++ * Terminate string following prefixes. Acpi_aml_exec_name_segment() will ++ * append the segment(s) ++ */ ++ ++ *temp_ptr = 0; ++ ++ return (name_string); ++} ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_exec_name_segment ++ * ++ * PARAMETERS: Interpreter_mode - Current running mode (load1/Load2/Exec) ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Execute a name segment (4 bytes) ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_exec_name_segment ( ++ u8 **in_aml_address, ++ NATIVE_CHAR *name_string) ++{ ++ u8 *aml_address = *in_aml_address; ++ ACPI_STATUS status = AE_OK; ++ u32 index; ++ NATIVE_CHAR char_buf[5]; ++ ++ ++ /* ++ * If first character is a digit, then we know that we aren't looking at a ++ * valid name segment ++ */ ++ ++ char_buf[0] = *aml_address; ++ ++ if ('0' <= char_buf[0] && char_buf[0] <= '9') { ++ return (AE_CTRL_PENDING); ++ } ++ ++ for (index = 4; ++ (index > 0) && (acpi_cm_valid_acpi_character (*aml_address)); ++ --index) { ++ char_buf[4 - index] = *aml_address++; ++ } ++ ++ ++ /* Valid name segment */ ++ ++ if (0 == index) { ++ /* Found 4 valid characters */ ++ ++ char_buf[4] = '\0'; ++ ++ if (name_string) { ++ STRCAT (name_string, char_buf); ++ } ++ ++ } ++ ++ else if (4 == index) { ++ /* ++ * First character was not a valid name character, ++ * so we are looking at something other than a name. ++ */ ++ status = AE_CTRL_PENDING; ++ } ++ ++ else { ++ /* Segment started with one or more valid characters, but fewer than 4 */ ++ ++ status = AE_AML_BAD_NAME; ++ } ++ ++ *in_aml_address = aml_address; ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_get_name_string ++ * ++ * PARAMETERS: Data_type - Data type to be associated with this name ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Get a name, including any prefixes. ++ * ++ ******************************************************************************/ ++ ++ ++ACPI_STATUS ++acpi_aml_get_name_string ( ++ OBJECT_TYPE_INTERNAL data_type, ++ u8 *in_aml_address, ++ NATIVE_CHAR **out_name_string, ++ u32 *out_name_length) ++{ ++ ACPI_STATUS status = AE_OK; ++ u8 *aml_address = in_aml_address; ++ NATIVE_CHAR *name_string = NULL; ++ u32 num_segments; ++ u32 prefix_count = 0; ++ u8 prefix = 0; ++ u8 has_prefix = FALSE; ++ ++ ++ if (INTERNAL_TYPE_REGION_FIELD == data_type || ++ INTERNAL_TYPE_BANK_FIELD == data_type || ++ INTERNAL_TYPE_INDEX_FIELD == data_type) { ++ /* Disallow prefixes for types associated with Field_unit names */ ++ ++ name_string = acpi_aml_allocate_name_string (0, 1); ++ if (!name_string) { ++ status = AE_NO_MEMORY; ++ } ++ else { ++ status = acpi_aml_exec_name_segment (&aml_address, name_string); ++ } ++ } ++ ++ else { ++ /* ++ * Data_type is not a field name. ++ * Examine first character of name for root or parent prefix operators ++ */ ++ ++ switch (*aml_address) { ++ ++ case AML_ROOT_PREFIX: ++ ++ prefix = *aml_address++; ++ /* ++ * Remember that we have a Root_prefix -- ++ * see comment in Acpi_aml_allocate_name_string() ++ */ ++ prefix_count = (u32) -1; ++ has_prefix = TRUE; ++ break; ++ ++ ++ case AML_PARENT_PREFIX: ++ ++ /* Increment past possibly multiple parent prefixes */ ++ ++ do { ++ prefix = *aml_address++; ++ ++prefix_count; ++ ++ } while (*aml_address == AML_PARENT_PREFIX); ++ has_prefix = TRUE; ++ break; ++ ++ ++ default: ++ ++ break; ++ } ++ ++ ++ /* Examine first character of name for name segment prefix operator */ ++ ++ switch (*aml_address) { ++ ++ case AML_DUAL_NAME_PREFIX: ++ ++ prefix = *aml_address++; ++ name_string = acpi_aml_allocate_name_string (prefix_count, 2); ++ if (!name_string) { ++ status = AE_NO_MEMORY; ++ break; ++ } ++ ++ /* Indicate that we processed a prefix */ ++ has_prefix = TRUE; ++ ++ status = acpi_aml_exec_name_segment (&aml_address, name_string); ++ if (ACPI_SUCCESS (status)) { ++ status = acpi_aml_exec_name_segment (&aml_address, name_string); ++ } ++ break; ++ ++ ++ case AML_MULTI_NAME_PREFIX_OP: ++ ++ prefix = *aml_address++; ++ /* Fetch count of segments remaining in name path */ ++ ++ num_segments = *aml_address++; ++ ++ name_string = acpi_aml_allocate_name_string (prefix_count, num_segments); ++ if (!name_string) { ++ status = AE_NO_MEMORY; ++ break; ++ } ++ ++ /* Indicate that we processed a prefix */ ++ has_prefix = TRUE; ++ ++ while (num_segments && ++ (status = acpi_aml_exec_name_segment (&aml_address, name_string)) == AE_OK) { ++ --num_segments; ++ } ++ ++ break; ++ ++ ++ case 0: ++ ++ /* Null_name valid as of 8-12-98 ASL/AML Grammar Update */ ++ ++ ++ /* Consume the NULL byte */ ++ ++ aml_address++; ++ name_string = acpi_aml_allocate_name_string (prefix_count, 0); ++ if (!name_string) { ++ status = AE_NO_MEMORY; ++ break; ++ } ++ ++ break; ++ ++ ++ default: ++ ++ /* Name segment string */ ++ ++ name_string = acpi_aml_allocate_name_string (prefix_count, 1); ++ if (!name_string) { ++ status = AE_NO_MEMORY; ++ break; ++ } ++ ++ status = acpi_aml_exec_name_segment (&aml_address, name_string); ++ break; ++ ++ } /* Switch (Peek_op ()) */ ++ } ++ ++ ++ if (AE_CTRL_PENDING == status && has_prefix) { ++ /* Ran out of segments after processing a prefix */ ++ ++ REPORT_ERROR ( ++ ("Aml_do_name: Malformed Name at %p\n", name_string)); ++ status = AE_AML_BAD_NAME; ++ } ++ ++ ++ *out_name_string = name_string; ++ *out_name_length = (u32) (aml_address - in_aml_address); ++ ++ return (status); ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/amprep.c linux/drivers/acpi/executer/amprep.c +--- /usr/src/linux/drivers/acpi/executer/amprep.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/amprep.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,421 @@ ++ ++/****************************************************************************** ++ * ++ * Module Name: amprep - ACPI AML (p-code) execution - field prep utilities ++ * $Revision: 82 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acinterp.h" ++#include "amlcode.h" ++#include "acnamesp.h" ++#include "acparser.h" ++ ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("amprep") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_decode_field_access_type ++ * ++ * PARAMETERS: Access - Encoded field access bits ++ * Length - Field length. ++ * ++ * RETURN: Field granularity (8, 16, or 32) ++ * ++ * DESCRIPTION: Decode the Access_type bits of a field definition. ++ * ++ ******************************************************************************/ ++ ++static u32 ++acpi_aml_decode_field_access_type ( ++ u32 access, ++ u16 length) ++{ ++ ++ switch (access) { ++ case ACCESS_ANY_ACC: ++ ++ /* Use the length to set the access type */ ++ ++ if (length <= 8) { ++ return (8); ++ } ++ else if (length <= 16) { ++ return (16); ++ } ++ else if (length <= 32) { ++ return (32); ++ } ++ else if (length <= 64) { ++ return (64); ++ } ++ ++ /* Default is 8 (byte) */ ++ ++ return (8); ++ break; ++ ++ case ACCESS_BYTE_ACC: ++ return (8); ++ break; ++ ++ case ACCESS_WORD_ACC: ++ return (16); ++ break; ++ ++ case ACCESS_DWORD_ACC: ++ return (32); ++ break; ++ ++ case ACCESS_QWORD_ACC: /* ACPI 2.0 */ ++ return (64); ++ break; ++ ++ default: ++ /* Invalid field access type */ ++ ++ return (0); ++ } ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_prep_common_field_object ++ * ++ * PARAMETERS: Obj_desc - The field object ++ * Field_flags - Access, Lock_rule, and Update_rule. ++ * The format of a Field_flag is described ++ * in the ACPI specification ++ * Field_position - Field position ++ * Field_length - Field length ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Initialize the areas of the field object that are common ++ * to the various types of fields. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_prep_common_field_object ( ++ ACPI_OPERAND_OBJECT *obj_desc, ++ u8 field_flags, ++ u32 field_position, ++ u32 field_length) ++{ ++ u32 granularity; ++ ++ ++ /* ++ * Note: the structure being initialized is the ++ * ACPI_COMMON_FIELD_INFO; No structure fields outside of the common area ++ * are initialized by this procedure. ++ */ ++ ++ /* Demultiplex the Field_flags byte */ ++ ++ obj_desc->common_field.access = (u8) ((field_flags & ACCESS_TYPE_MASK) ++ >> ACCESS_TYPE_SHIFT); ++ obj_desc->common_field.lock_rule = (u8) ((field_flags & LOCK_RULE_MASK) ++ >> LOCK_RULE_SHIFT); ++ obj_desc->common_field.update_rule = (u8) ((field_flags & UPDATE_RULE_MASK) ++ >> UPDATE_RULE_SHIFT); ++ /* Other misc fields */ ++ ++ obj_desc->common_field.bit_length = (u16) field_length; ++ ++ /* Decode the access type so we can compute offsets */ ++ ++ granularity = acpi_aml_decode_field_access_type (obj_desc->field.access, ++ obj_desc->field.bit_length); ++ if (!granularity) { ++ return (AE_AML_OPERAND_VALUE); ++ } ++ ++ /* Setup granularity-based fields */ ++ ++ obj_desc->common_field.granularity = (u8) granularity; ++ ++ if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) { ++ /* ++ * Buffer_field access can be on any byte boundary, so the ++ * granularity is always 8 ++ */ ++ granularity = 8; ++ } ++ ++ obj_desc->common_field.bit_offset = (u8) (field_position % granularity); ++ obj_desc->common_field.byte_offset = field_position / granularity; ++ ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_prep_region_field_value ++ * ++ * PARAMETERS: Node - Owning Node ++ * Region_node - Region in which field is being defined ++ * Field_flags - Access, Lock_rule, and Update_rule. ++ * Field_position - Field position ++ * Field_length - Field length ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Construct an ACPI_OPERAND_OBJECT of type Def_field and ++ * connect it to the parent Node. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_prep_region_field_value ( ++ ACPI_NAMESPACE_NODE *node, ++ ACPI_HANDLE region_node, ++ u8 field_flags, ++ u32 field_position, ++ u32 field_length) ++{ ++ ACPI_OPERAND_OBJECT *obj_desc; ++ u32 type; ++ ACPI_STATUS status; ++ ++ ++ /* Parameter validation */ ++ ++ if (!region_node) { ++ return (AE_AML_NO_OPERAND); ++ } ++ ++ type = acpi_ns_get_type (region_node); ++ if (type != ACPI_TYPE_REGION) { ++ return (AE_AML_OPERAND_TYPE); ++ } ++ ++ /* Allocate a new object */ ++ ++ obj_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_REGION_FIELD); ++ if (!obj_desc) { ++ return (AE_NO_MEMORY); ++ } ++ ++ ++ /* Obj_desc and Region valid */ ++ ++ /* Initialize areas of the object that are common to all fields */ ++ ++ status = acpi_aml_prep_common_field_object (obj_desc, field_flags, ++ field_position, field_length); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ /* Initialize areas of the object that are specific to this field type */ ++ ++ obj_desc->field.region_obj = acpi_ns_get_attached_object (region_node); ++ ++ /* An additional reference for the container */ ++ ++ acpi_cm_add_reference (obj_desc->field.region_obj); ++ ++ ++ /* Debug info */ ++ ++ ++ /* ++ * Store the constructed descriptor (Obj_desc) into the parent Node, ++ * preserving the current type of that Named_obj. ++ */ ++ status = acpi_ns_attach_object (node, obj_desc, (u8) acpi_ns_get_type (node)); ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_prep_bank_field_value ++ * ++ * PARAMETERS: Node - Owning Node ++ * Region_node - Region in which field is being defined ++ * Bank_register_node - Bank selection register node ++ * Bank_val - Value to store in selection register ++ * Field_flags - Access, Lock_rule, and Update_rule ++ * Field_position - Field position ++ * Field_length - Field length ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Construct an object of type Bank_field and attach it to the ++ * parent Node. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_prep_bank_field_value ( ++ ACPI_NAMESPACE_NODE *node, ++ ACPI_NAMESPACE_NODE *region_node, ++ ACPI_NAMESPACE_NODE *bank_register_node, ++ u32 bank_val, ++ u8 field_flags, ++ u32 field_position, ++ u32 field_length) ++{ ++ ACPI_OPERAND_OBJECT *obj_desc; ++ u32 type; ++ ACPI_STATUS status; ++ ++ ++ /* Parameter validation */ ++ ++ if (!region_node) { ++ return (AE_AML_NO_OPERAND); ++ } ++ ++ type = acpi_ns_get_type (region_node); ++ if (type != ACPI_TYPE_REGION) { ++ return (AE_AML_OPERAND_TYPE); ++ } ++ ++ /* Allocate a new object */ ++ ++ obj_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_BANK_FIELD); ++ if (!obj_desc) { ++ return (AE_NO_MEMORY); ++ } ++ ++ /* Obj_desc and Region valid */ ++ ++ /* Initialize areas of the object that are common to all fields */ ++ ++ status = acpi_aml_prep_common_field_object (obj_desc, field_flags, ++ field_position, field_length); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ /* Initialize areas of the object that are specific to this field type */ ++ ++ obj_desc->bank_field.value = bank_val; ++ obj_desc->bank_field.region_obj = acpi_ns_get_attached_object (region_node); ++ obj_desc->bank_field.bank_register_obj = acpi_ns_get_attached_object (bank_register_node); ++ ++ /* An additional reference for the attached objects */ ++ ++ acpi_cm_add_reference (obj_desc->bank_field.region_obj); ++ acpi_cm_add_reference (obj_desc->bank_field.bank_register_obj); ++ ++ /* Debug info */ ++ ++ ++ /* ++ * Store the constructed descriptor (Obj_desc) into the parent Node, ++ * preserving the current type of that Named_obj. ++ */ ++ status = acpi_ns_attach_object (node, obj_desc, (u8) acpi_ns_get_type (node)); ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_prep_index_field_value ++ * ++ * PARAMETERS: Node - Owning Node ++ * Index_reg - Index register ++ * Data_reg - Data register ++ * Field_flags - Access, Lock_rule, and Update_rule ++ * Field_position - Field position ++ * Field_length - Field length ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Construct an ACPI_OPERAND_OBJECT of type Index_field and ++ * connect it to the parent Node. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_prep_index_field_value ( ++ ACPI_NAMESPACE_NODE *node, ++ ACPI_NAMESPACE_NODE *index_reg, ++ ACPI_NAMESPACE_NODE *data_reg, ++ u8 field_flags, ++ u32 field_position, ++ u32 field_length) ++{ ++ ACPI_OPERAND_OBJECT *obj_desc; ++ ACPI_STATUS status; ++ ++ ++ /* Parameter validation */ ++ ++ if (!index_reg || !data_reg) { ++ return (AE_AML_NO_OPERAND); ++ } ++ ++ /* Allocate a new object descriptor */ ++ ++ obj_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_INDEX_FIELD); ++ if (!obj_desc) { ++ return (AE_NO_MEMORY); ++ } ++ ++ /* Initialize areas of the object that are common to all fields */ ++ ++ status = acpi_aml_prep_common_field_object (obj_desc, field_flags, ++ field_position, field_length); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ /* Initialize areas of the object that are specific to this field type */ ++ ++ obj_desc->index_field.data_obj = acpi_ns_get_attached_object (data_reg); ++ obj_desc->index_field.index_obj = acpi_ns_get_attached_object (index_reg); ++ obj_desc->index_field.value = (u32) (field_position / ++ obj_desc->field.granularity); ++ ++ /* An additional reference for the attached objects */ ++ ++ acpi_cm_add_reference (obj_desc->index_field.data_obj); ++ acpi_cm_add_reference (obj_desc->index_field.index_obj); ++ ++ /* Debug info */ ++ ++ ++ /* ++ * Store the constructed descriptor (Obj_desc) into the parent Node, ++ * preserving the current type of that Named_obj. ++ */ ++ status = acpi_ns_attach_object (node, obj_desc, (u8) acpi_ns_get_type (node)); ++ ++ return (status); ++} ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/amregion.c linux/drivers/acpi/executer/amregion.c +--- /usr/src/linux/drivers/acpi/executer/amregion.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/amregion.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,409 @@ ++ ++/****************************************************************************** ++ * ++ * Module Name: amregion - ACPI default Op_region (address space) handlers ++ * $Revision: 45 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acinterp.h" ++#include "amlcode.h" ++#include "acnamesp.h" ++#include "achware.h" ++#include "acevents.h" ++ ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("amregion") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_system_memory_space_handler ++ * ++ * PARAMETERS: Function - Read or Write operation ++ * Address - Where in the space to read or write ++ * Bit_width - Field width in bits (8, 16, or 32) ++ * Value - Pointer to in or out value ++ * Handler_context - Pointer to Handler's context ++ * Region_context - Pointer to context specific to the ++ * accessed region ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Handler for the System Memory address space (Op Region) ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_system_memory_space_handler ( ++ u32 function, ++ ACPI_PHYSICAL_ADDRESS address, ++ u32 bit_width, ++ u32 *value, ++ void *handler_context, ++ void *region_context) ++{ ++ ACPI_STATUS status = AE_OK; ++ void *logical_addr_ptr = NULL; ++ MEM_HANDLER_CONTEXT *mem_info = region_context; ++ u32 length; ++ ++ ++ /* Validate and translate the bit width */ ++ ++ switch (bit_width) { ++ case 8: ++ length = 1; ++ break; ++ ++ case 16: ++ length = 2; ++ break; ++ ++ case 32: ++ length = 4; ++ break; ++ ++ default: ++ return (AE_AML_OPERAND_VALUE); ++ break; ++ } ++ ++ ++ /* ++ * Does the request fit into the cached memory mapping? ++ * Is 1) Address below the current mapping? OR ++ * 2) Address beyond the current mapping? ++ */ ++ ++ if ((address < mem_info->mapped_physical_address) || ++ (((ACPI_INTEGER) address + length) > ++ ((ACPI_INTEGER) mem_info->mapped_physical_address + mem_info->mapped_length))) { ++ /* ++ * The request cannot be resolved by the current memory mapping; ++ * Delete the existing mapping and create a new one. ++ */ ++ ++ if (mem_info->mapped_length) { ++ /* Valid mapping, delete it */ ++ ++ acpi_os_unmap_memory (mem_info->mapped_logical_address, ++ mem_info->mapped_length); ++ } ++ ++ mem_info->mapped_length = 0; /* In case of failure below */ ++ ++ /* Create a new mapping starting at the address given */ ++ ++ status = acpi_os_map_memory (address, SYSMEM_REGION_WINDOW_SIZE, ++ (void **) &mem_info->mapped_logical_address); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ /* TBD: should these pointers go to 64-bit in all cases ? */ ++ ++ mem_info->mapped_physical_address = address; ++ mem_info->mapped_length = SYSMEM_REGION_WINDOW_SIZE; ++ } ++ ++ ++ /* ++ * Generate a logical pointer corresponding to the address we want to ++ * access ++ */ ++ ++ /* TBD: should these pointers go to 64-bit in all cases ? */ ++ ++ logical_addr_ptr = mem_info->mapped_logical_address + ++ ((ACPI_INTEGER) address - (ACPI_INTEGER) mem_info->mapped_physical_address); ++ ++ /* Perform the memory read or write */ ++ ++ switch (function) { ++ ++ case ADDRESS_SPACE_READ: ++ ++ switch (bit_width) { ++ case 8: ++ *value = (u32)* (u8 *) logical_addr_ptr; ++ break; ++ ++ case 16: ++ MOVE_UNALIGNED16_TO_32 (value, logical_addr_ptr); ++ break; ++ ++ case 32: ++ MOVE_UNALIGNED32_TO_32 (value, logical_addr_ptr); ++ break; ++ } ++ ++ break; ++ ++ ++ case ADDRESS_SPACE_WRITE: ++ ++ switch (bit_width) { ++ case 8: ++ *(u8 *) logical_addr_ptr = (u8) *value; ++ break; ++ ++ case 16: ++ MOVE_UNALIGNED16_TO_16 (logical_addr_ptr, value); ++ break; ++ ++ case 32: ++ MOVE_UNALIGNED32_TO_32 (logical_addr_ptr, value); ++ break; ++ } ++ ++ break; ++ ++ ++ default: ++ status = AE_BAD_PARAMETER; ++ break; ++ } ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_system_io_space_handler ++ * ++ * PARAMETERS: Function - Read or Write operation ++ * Address - Where in the space to read or write ++ * Bit_width - Field width in bits (8, 16, or 32) ++ * Value - Pointer to in or out value ++ * Handler_context - Pointer to Handler's context ++ * Region_context - Pointer to context specific to the ++ * accessed region ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Handler for the System IO address space (Op Region) ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_system_io_space_handler ( ++ u32 function, ++ ACPI_PHYSICAL_ADDRESS address, ++ u32 bit_width, ++ u32 *value, ++ void *handler_context, ++ void *region_context) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ ++ /* Decode the function parameter */ ++ ++ switch (function) { ++ ++ case ADDRESS_SPACE_READ: ++ ++ switch (bit_width) { ++ /* I/O Port width */ ++ ++ case 8: ++ *value = (u32) acpi_os_in8 ((ACPI_IO_ADDRESS) address); ++ break; ++ ++ case 16: ++ *value = (u32) acpi_os_in16 ((ACPI_IO_ADDRESS) address); ++ break; ++ ++ case 32: ++ *value = acpi_os_in32 ((ACPI_IO_ADDRESS) address); ++ break; ++ ++ default: ++ status = AE_AML_OPERAND_VALUE; ++ } ++ ++ break; ++ ++ ++ case ADDRESS_SPACE_WRITE: ++ ++ switch (bit_width) { ++ /* I/O Port width */ ++ case 8: ++ acpi_os_out8 ((ACPI_IO_ADDRESS) address, (u8) *value); ++ break; ++ ++ case 16: ++ acpi_os_out16 ((ACPI_IO_ADDRESS) address, (u16) *value); ++ break; ++ ++ case 32: ++ acpi_os_out32 ((ACPI_IO_ADDRESS) address, *value); ++ break; ++ ++ default: ++ status = AE_AML_OPERAND_VALUE; ++ } ++ ++ break; ++ ++ ++ default: ++ status = AE_BAD_PARAMETER; ++ break; ++ } ++ ++ return (status); ++} ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_pci_config_space_handler ++ * ++ * PARAMETERS: Function - Read or Write operation ++ * Address - Where in the space to read or write ++ * Bit_width - Field width in bits (8, 16, or 32) ++ * Value - Pointer to in or out value ++ * Handler_context - Pointer to Handler's context ++ * Region_context - Pointer to context specific to the ++ * accessed region ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Handler for the PCI Config address space (Op Region) ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_pci_config_space_handler ( ++ u32 function, ++ ACPI_PHYSICAL_ADDRESS address, ++ u32 bit_width, ++ u32 *value, ++ void *handler_context, ++ void *region_context) ++{ ++ ACPI_STATUS status = AE_OK; ++ u32 pci_bus; ++ u32 dev_func; ++ u8 pci_reg; ++ PCI_HANDLER_CONTEXT *PCIcontext; ++ ++ ++ /* ++ * The arguments to Acpi_os(Read|Write)Pci_cfg(Byte|Word|Dword) are: ++ * ++ * Seg_bus - 0xSSSSBBBB - SSSS is the PCI bus segment ++ * BBBB is the PCI bus number ++ * ++ * Dev_func - 0xDDDDFFFF - DDDD is the PCI device number ++ * FFFF is the PCI device function number ++ * ++ * Reg_num - Config space register must be < 40h ++ * ++ * Value - input value for write, output for read ++ * ++ */ ++ ++ PCIcontext = (PCI_HANDLER_CONTEXT *) region_context; ++ ++ pci_bus = LOWORD(PCIcontext->seg) << 16; ++ pci_bus |= LOWORD(PCIcontext->bus); ++ ++ dev_func = PCIcontext->dev_func; ++ ++ pci_reg = (u8) address; ++ ++ switch (function) { ++ ++ case ADDRESS_SPACE_READ: ++ ++ *value = 0; ++ ++ switch (bit_width) { ++ /* PCI Register width */ ++ ++ case 8: ++ status = acpi_os_read_pci_cfg_byte (pci_bus, dev_func, pci_reg, ++ (u8 *) value); ++ break; ++ ++ case 16: ++ status = acpi_os_read_pci_cfg_word (pci_bus, dev_func, pci_reg, ++ (u16 *) value); ++ break; ++ ++ case 32: ++ status = acpi_os_read_pci_cfg_dword (pci_bus, dev_func, pci_reg, ++ value); ++ break; ++ ++ default: ++ status = AE_AML_OPERAND_VALUE; ++ ++ } /* Switch bit_width */ ++ ++ break; ++ ++ ++ case ADDRESS_SPACE_WRITE: ++ ++ switch (bit_width) { ++ /* PCI Register width */ ++ ++ case 8: ++ status = acpi_os_write_pci_cfg_byte (pci_bus, dev_func, pci_reg, ++ *(u8 *) value); ++ break; ++ ++ case 16: ++ status = acpi_os_write_pci_cfg_word (pci_bus, dev_func, pci_reg, ++ *(u16 *) value); ++ break; ++ ++ case 32: ++ status = acpi_os_write_pci_cfg_dword (pci_bus, dev_func, pci_reg, ++ *value); ++ break; ++ ++ default: ++ status = AE_AML_OPERAND_VALUE; ++ ++ } /* Switch bit_width */ ++ ++ break; ++ ++ ++ default: ++ ++ status = AE_BAD_PARAMETER; ++ break; ++ ++ } ++ ++ return (status); ++} ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/amresnte.c linux/drivers/acpi/executer/amresnte.c +--- /usr/src/linux/drivers/acpi/executer/amresnte.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/amresnte.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,321 @@ ++ ++/****************************************************************************** ++ * ++ * Module Name: amresnte - AML Interpreter object resolution ++ * $Revision: 33 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "amlcode.h" ++#include "acparser.h" ++#include "acdispat.h" ++#include "acinterp.h" ++#include "acnamesp.h" ++#include "actables.h" ++#include "acevents.h" ++ ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("amresnte") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_resolve_node_to_value ++ * ++ * PARAMETERS: Stack_ptr - Pointer to a location on a stack that contains ++ * a pointer to a Node ++ * Walk_state - Current state ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Resolve a Namespace node (AKA a "direct name pointer") to ++ * a valued object ++ * ++ * Note: for some of the data types, the pointer attached to the Node ++ * can be either a pointer to an actual internal object or a pointer into the ++ * AML stream itself. These types are currently: ++ * ++ * ACPI_TYPE_INTEGER ++ * ACPI_TYPE_STRING ++ * ACPI_TYPE_BUFFER ++ * ACPI_TYPE_MUTEX ++ * ACPI_TYPE_PACKAGE ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_resolve_node_to_value ( ++ ACPI_NAMESPACE_NODE **stack_ptr, ++ ACPI_WALK_STATE *walk_state) ++ ++{ ++ ACPI_STATUS status = AE_OK; ++ ACPI_OPERAND_OBJECT *val_desc; ++ ACPI_OPERAND_OBJECT *obj_desc = NULL; ++ ACPI_NAMESPACE_NODE *node; ++ u8 *aml_pointer = NULL; ++ OBJECT_TYPE_INTERNAL entry_type; ++ ACPI_INTEGER temp_val; ++ u8 attached_aml_pointer = FALSE; ++ u8 aml_opcode = 0; ++ ++ ++ /* ++ * The stack pointer points to a ACPI_NAMESPACE_NODE (Node). Get the ++ * object that is attached to the Node. ++ */ ++ ++ node = *stack_ptr; ++ val_desc = acpi_ns_get_attached_object (node); ++ entry_type = acpi_ns_get_type ((ACPI_HANDLE) node); ++ ++ /* ++ * The Val_desc attached to the Node can be either: ++ * 1) An internal ACPI object ++ * 2) A pointer into the AML stream (into one of the ACPI system tables) ++ */ ++ ++ if (acpi_tb_system_table_pointer (val_desc)) { ++ /* CAN THIS EVERY HAPPEN NOW? TBD!!! */ ++ ++ attached_aml_pointer = TRUE; ++ aml_opcode = *((u8 *) val_desc); ++ aml_pointer = ((u8 *) val_desc) + 1; ++ ++ } ++ ++ ++ /* ++ * Several Entry_types do not require further processing, so ++ * we will return immediately ++ */ ++ /* Devices rarely have an attached object, return the Node ++ * and Method locals and arguments have a pseudo-Node ++ */ ++ if (entry_type == ACPI_TYPE_DEVICE || ++ (node->flags & (ANOBJ_METHOD_ARG | ANOBJ_METHOD_LOCAL))) { ++ return (AE_OK); ++ } ++ ++ if (!val_desc) { ++ return (AE_AML_NO_OPERAND); ++ } ++ ++ /* ++ * Action is based on the type of the Node, which indicates the type ++ * of the attached object or pointer ++ */ ++ switch (entry_type) { ++ ++ case ACPI_TYPE_PACKAGE: ++ ++ if (attached_aml_pointer) { ++ /* ++ * This means that the package initialization is not parsed ++ * -- should not happen ++ */ ++ return (AE_NOT_IMPLEMENTED); ++ } ++ ++ /* Val_desc is an internal object in all cases by the time we get here */ ++ ++ if (ACPI_TYPE_PACKAGE != val_desc->common.type) { ++ return (AE_AML_OPERAND_TYPE); ++ } ++ ++ /* Return an additional reference to the object */ ++ ++ obj_desc = val_desc; ++ acpi_cm_add_reference (obj_desc); ++ break; ++ ++ ++ case ACPI_TYPE_BUFFER: ++ ++ if (attached_aml_pointer) { ++ /* ++ * This means that the buffer initialization is not parsed ++ * -- should not happen ++ */ ++ return (AE_NOT_IMPLEMENTED); ++ } ++ ++ /* Val_desc is an internal object in all cases by the time we get here */ ++ ++ if (ACPI_TYPE_BUFFER != val_desc->common.type) { ++ return (AE_AML_OPERAND_TYPE); ++ } ++ ++ /* Return an additional reference to the object */ ++ ++ obj_desc = val_desc; ++ acpi_cm_add_reference (obj_desc); ++ break; ++ ++ ++ case ACPI_TYPE_STRING: ++ ++ if (attached_aml_pointer) { ++ /* Allocate a new string object */ ++ ++ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_STRING); ++ if (!obj_desc) { ++ return (AE_NO_MEMORY); ++ } ++ ++ /* Init the internal object */ ++ ++ obj_desc->string.pointer = (NATIVE_CHAR *) aml_pointer; ++ obj_desc->string.length = STRLEN (obj_desc->string.pointer); ++ } ++ ++ else { ++ if (ACPI_TYPE_STRING != val_desc->common.type) { ++ return (AE_AML_OPERAND_TYPE); ++ } ++ ++ /* Return an additional reference to the object */ ++ ++ obj_desc = val_desc; ++ acpi_cm_add_reference (obj_desc); ++ } ++ ++ break; ++ ++ ++ case ACPI_TYPE_INTEGER: ++ ++ /* ++ * The Node has an attached internal object, make sure that it's a ++ * number ++ */ ++ ++ if (ACPI_TYPE_INTEGER != val_desc->common.type) { ++ return (AE_AML_OPERAND_TYPE); ++ } ++ ++ /* Return an additional reference to the object */ ++ ++ obj_desc = val_desc; ++ acpi_cm_add_reference (obj_desc); ++ break; ++ ++ ++ case ACPI_TYPE_BUFFER_FIELD: ++ case INTERNAL_TYPE_REGION_FIELD: ++ case INTERNAL_TYPE_BANK_FIELD: ++ case INTERNAL_TYPE_INDEX_FIELD: ++ ++ status = acpi_aml_read_data_from_field (val_desc, &obj_desc); ++ break; ++ ++ ++ /* ++ * For these objects, just return the object attached to the Node ++ */ ++ ++ case ACPI_TYPE_MUTEX: ++ case ACPI_TYPE_METHOD: ++ case ACPI_TYPE_POWER: ++ case ACPI_TYPE_PROCESSOR: ++ case ACPI_TYPE_THERMAL: ++ case ACPI_TYPE_EVENT: ++ case ACPI_TYPE_REGION: ++ ++ ++ /* Return an additional reference to the object */ ++ ++ obj_desc = val_desc; ++ acpi_cm_add_reference (obj_desc); ++ break; ++ ++ ++ /* TYPE_Any is untyped, and thus there is no object associated with it */ ++ ++ case ACPI_TYPE_ANY: ++ ++ return (AE_AML_OPERAND_TYPE); /* Cannot be AE_TYPE */ ++ break; ++ ++ ++ /* ++ * The only named references allowed are named constants ++ * e.g. -- Name (\OSFL, Ones) ++ */ ++ case INTERNAL_TYPE_REFERENCE: ++ ++ switch (val_desc->reference.opcode) { ++ ++ case AML_ZERO_OP: ++ ++ temp_val = 0; ++ break; ++ ++ case AML_ONE_OP: ++ ++ temp_val = 1; ++ break; ++ ++ case AML_ONES_OP: ++ ++ temp_val = ACPI_INTEGER_MAX; ++ break; ++ ++ default: ++ ++ return (AE_AML_BAD_OPCODE); ++ } ++ ++ /* Create object for result */ ++ ++ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); ++ if (!obj_desc) { ++ return (AE_NO_MEMORY); ++ } ++ ++ obj_desc->integer.value = temp_val; ++ ++ /* Truncate value if we are executing from a 32-bit ACPI table */ ++ ++ acpi_aml_truncate_for32bit_table (obj_desc, walk_state); ++ break; ++ ++ ++ /* Default case is for unknown types */ ++ ++ default: ++ ++ return (AE_AML_OPERAND_TYPE); ++ ++ } /* switch (Entry_type) */ ++ ++ ++ /* Put the object descriptor on the stack */ ++ ++ *stack_ptr = (void *) obj_desc; ++ ++ return (status); ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/amresolv.c linux/drivers/acpi/executer/amresolv.c +--- /usr/src/linux/drivers/acpi/executer/amresolv.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/amresolv.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,410 @@ ++ ++/****************************************************************************** ++ * ++ * Module Name: amresolv - AML Interpreter object resolution ++ * $Revision: 90 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "amlcode.h" ++#include "acparser.h" ++#include "acdispat.h" ++#include "acinterp.h" ++#include "acnamesp.h" ++#include "actables.h" ++#include "acevents.h" ++ ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("amresolv") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_get_buffer_field_value ++ * ++ * PARAMETERS: *Obj_desc - Pointer to a Buffer_field ++ * *Result_desc - Pointer to an empty descriptor which will ++ * become an Integer with the field's value ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Retrieve the value from a Buffer_field ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_get_buffer_field_value ( ++ ACPI_OPERAND_OBJECT *obj_desc, ++ ACPI_OPERAND_OBJECT *result_desc) ++{ ++ ACPI_STATUS status; ++ u32 mask; ++ u8 *location; ++ ++ ++ /* ++ * Parameter validation ++ */ ++ if (!obj_desc) { ++ return (AE_AML_NO_OPERAND); ++ } ++ ++ if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { ++ status = acpi_ds_get_buffer_field_arguments (obj_desc); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ } ++ ++ if (!obj_desc->buffer_field.buffer_obj) { ++ return (AE_AML_INTERNAL); ++ } ++ ++ if (ACPI_TYPE_BUFFER != obj_desc->buffer_field.buffer_obj->common.type) { ++ return (AE_AML_OPERAND_TYPE); ++ } ++ ++ if (!result_desc) { ++ return (AE_AML_INTERNAL); ++ } ++ ++ ++ /* Field location is (base of buffer) + (byte offset) */ ++ ++ location = obj_desc->buffer_field.buffer_obj->buffer.pointer ++ + obj_desc->buffer_field.byte_offset; ++ ++ /* ++ * Construct Mask with as many 1 bits as the field width ++ * ++ * NOTE: Only the bottom 5 bits are valid for a shift operation, so ++ * special care must be taken for any shift greater than 31 bits. ++ * ++ * TBD: [Unhandled] Fields greater than 32 bits will not work. ++ */ ++ ++ if (obj_desc->buffer_field.bit_length < 32) { ++ mask = ((u32) 1 << obj_desc->buffer_field.bit_length) - (u32) 1; ++ } ++ else { ++ mask = ACPI_UINT32_MAX; ++ } ++ ++ result_desc->integer.type = (u8) ACPI_TYPE_INTEGER; ++ ++ /* Get the 32 bit value at the location */ ++ ++ MOVE_UNALIGNED32_TO_32 (&result_desc->integer.value, location); ++ ++ /* ++ * Shift the 32-bit word containing the field, and mask off the ++ * resulting value ++ */ ++ ++ result_desc->integer.value = ++ (result_desc->integer.value >> obj_desc->buffer_field.bit_offset) & mask; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_resolve_to_value ++ * ++ * PARAMETERS: **Stack_ptr - Points to entry on Obj_stack, which can ++ * be either an (ACPI_OPERAND_OBJECT *) ++ * or an ACPI_HANDLE. ++ * Walk_state - Current method state ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Convert Reference objects to values ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_resolve_to_value ( ++ ACPI_OPERAND_OBJECT **stack_ptr, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_STATUS status; ++ ++ ++ if (!stack_ptr || !*stack_ptr) { ++ return (AE_AML_NO_OPERAND); ++ } ++ ++ ++ /* ++ * The entity pointed to by the Stack_ptr can be either ++ * 1) A valid ACPI_OPERAND_OBJECT, or ++ * 2) A ACPI_NAMESPACE_NODE (Named_obj) ++ */ ++ ++ if (VALID_DESCRIPTOR_TYPE (*stack_ptr, ACPI_DESC_TYPE_INTERNAL)) { ++ status = acpi_aml_resolve_object_to_value (stack_ptr, walk_state); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ } ++ ++ /* ++ * Object on the stack may have changed if Acpi_aml_resolve_object_to_value() ++ * was called (i.e., we can't use an _else_ here.) ++ */ ++ ++ if (VALID_DESCRIPTOR_TYPE (*stack_ptr, ACPI_DESC_TYPE_NAMED)) { ++ status = acpi_aml_resolve_node_to_value ((ACPI_NAMESPACE_NODE **) stack_ptr, ++ walk_state); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ } ++ ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_resolve_object_to_value ++ * ++ * PARAMETERS: Stack_ptr - Pointer to a stack location that contains a ++ * ptr to an internal object. ++ * Walk_state - Current method state ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Retrieve the value from an internal object. The Reference type ++ * uses the associated AML opcode to determine the value. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_resolve_object_to_value ( ++ ACPI_OPERAND_OBJECT **stack_ptr, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_STATUS status = AE_OK; ++ ACPI_OPERAND_OBJECT *stack_desc; ++ void *temp_node; ++ ACPI_OPERAND_OBJECT *obj_desc; ++ u16 opcode; ++ ++ ++ stack_desc = *stack_ptr; ++ ++ /* This is an ACPI_OPERAND_OBJECT */ ++ ++ switch (stack_desc->common.type) { ++ ++ case INTERNAL_TYPE_REFERENCE: ++ ++ opcode = stack_desc->reference.opcode; ++ ++ switch (opcode) { ++ ++ case AML_NAME_OP: ++ ++ /* ++ * Convert indirect name ptr to a direct name ptr. ++ * Then, Acpi_aml_resolve_node_to_value can be used to get the value ++ */ ++ ++ temp_node = stack_desc->reference.object; ++ ++ /* Delete the Reference Object */ ++ ++ acpi_cm_remove_reference (stack_desc); ++ ++ /* Put direct name pointer onto stack and exit */ ++ ++ (*stack_ptr) = temp_node; ++ break; ++ ++ ++ case AML_LOCAL_OP: ++ case AML_ARG_OP: ++ ++ /* ++ * Get the local from the method's state info ++ * Note: this increments the local's object reference count ++ */ ++ ++ status = acpi_ds_method_data_get_value (opcode, ++ stack_desc->reference.offset, walk_state, &obj_desc); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ /* ++ * Now we can delete the original Reference Object and ++ * replace it with the resolve value ++ */ ++ ++ acpi_cm_remove_reference (stack_desc); ++ *stack_ptr = obj_desc; ++ ++ break; ++ ++ ++ /* ++ * TBD: [Restructure] These next three opcodes change the type of ++ * the object, which is actually a no-no. ++ */ ++ ++ case AML_ZERO_OP: ++ ++ stack_desc->common.type = (u8) ACPI_TYPE_INTEGER; ++ stack_desc->integer.value = 0; ++ break; ++ ++ ++ case AML_ONE_OP: ++ ++ stack_desc->common.type = (u8) ACPI_TYPE_INTEGER; ++ stack_desc->integer.value = 1; ++ break; ++ ++ ++ case AML_ONES_OP: ++ ++ stack_desc->common.type = (u8) ACPI_TYPE_INTEGER; ++ stack_desc->integer.value = ACPI_INTEGER_MAX; ++ ++ /* Truncate value if we are executing from a 32-bit ACPI table */ ++ ++ acpi_aml_truncate_for32bit_table (stack_desc, walk_state); ++ break; ++ ++ ++ case AML_INDEX_OP: ++ ++ switch (stack_desc->reference.target_type) { ++ case ACPI_TYPE_BUFFER_FIELD: ++ ++ /* Just return - leave the Reference on the stack */ ++ break; ++ ++ ++ case ACPI_TYPE_PACKAGE: ++ obj_desc = *stack_desc->reference.where; ++ if (obj_desc) { ++ /* ++ * Valid obj descriptor, copy pointer to return value ++ * (i.e., dereference the package index) ++ * Delete the ref object, increment the returned object ++ */ ++ acpi_cm_remove_reference (stack_desc); ++ acpi_cm_add_reference (obj_desc); ++ *stack_ptr = obj_desc; ++ } ++ ++ else { ++ /* ++ * A NULL object descriptor means an unitialized element of ++ * the package, can't dereference it ++ */ ++ ++ status = AE_AML_UNINITIALIZED_ELEMENT; ++ } ++ break; ++ ++ default: ++ /* Invalid reference object */ ++ ++ status = AE_AML_INTERNAL; ++ break; ++ } ++ ++ break; ++ ++ ++ case AML_DEBUG_OP: ++ ++ /* Just leave the object as-is */ ++ break; ++ ++ ++ default: ++ ++ status = AE_AML_INTERNAL; ++ break; ++ ++ } /* switch (Opcode) */ ++ ++ break; /* case INTERNAL_TYPE_REFERENCE */ ++ ++ ++ case ACPI_TYPE_BUFFER_FIELD: ++ ++ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_ANY); ++ if (!obj_desc) { ++ return (AE_NO_MEMORY); ++ } ++ ++ status = acpi_aml_get_buffer_field_value (stack_desc, obj_desc); ++ if (ACPI_FAILURE (status)) { ++ acpi_cm_remove_reference (obj_desc); ++ obj_desc = NULL; ++ } ++ ++ *stack_ptr = (void *) obj_desc; ++ break; ++ ++ ++ case INTERNAL_TYPE_BANK_FIELD: ++ ++ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_ANY); ++ if (!obj_desc) { ++ return (AE_NO_MEMORY); ++ } ++ ++ /* TBD: WRONG! */ ++ ++ status = acpi_aml_get_buffer_field_value (stack_desc, obj_desc); ++ if (ACPI_FAILURE (status)) { ++ acpi_cm_remove_reference (obj_desc); ++ obj_desc = NULL; ++ } ++ ++ *stack_ptr = (void *) obj_desc; ++ break; ++ ++ ++ /* TBD: [Future] - may need to handle Index_field, and Def_field someday */ ++ ++ default: ++ ++ break; ++ ++ } /* switch (Stack_desc->Common.Type) */ ++ ++ ++ return (status); ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/amresop.c linux/drivers/acpi/executer/amresop.c +--- /usr/src/linux/drivers/acpi/executer/amresop.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/amresop.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,481 @@ ++ ++/****************************************************************************** ++ * ++ * Module Name: amresop - AML Interpreter operand/object resolution ++ * $Revision: 26 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "amlcode.h" ++#include "acparser.h" ++#include "acdispat.h" ++#include "acinterp.h" ++#include "acnamesp.h" ++#include "actables.h" ++#include "acevents.h" ++ ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("amresop") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_check_object_type ++ * ++ * PARAMETERS: Type_needed Object type needed ++ * This_type Actual object type ++ * Object Object pointer ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Check required type against actual type ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_check_object_type ( ++ ACPI_OBJECT_TYPE type_needed, ++ ACPI_OBJECT_TYPE this_type, ++ void *object) ++{ ++ ++ ++ if (type_needed == ACPI_TYPE_ANY) { ++ /* All types OK, so we don't perform any typechecks */ ++ ++ return (AE_OK); ++ } ++ ++ ++ if (type_needed != this_type) { ++ return (AE_AML_OPERAND_TYPE); ++ } ++ ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_resolve_operands ++ * ++ * PARAMETERS: Opcode Opcode being interpreted ++ * Stack_ptr Top of operand stack ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Convert stack entries to required types ++ * ++ * Each nibble in Arg_types represents one required operand ++ * and indicates the required Type: ++ * ++ * The corresponding stack entry will be converted to the ++ * required type if possible, else return an exception ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_resolve_operands ( ++ u16 opcode, ++ ACPI_OPERAND_OBJECT **stack_ptr, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_OPERAND_OBJECT *obj_desc; ++ ACPI_STATUS status = AE_OK; ++ u8 object_type; ++ void *temp_node; ++ u32 arg_types; ++ ACPI_OPCODE_INFO *op_info; ++ u32 this_arg_type; ++ ACPI_OBJECT_TYPE type_needed; ++ ++ ++ op_info = acpi_ps_get_opcode_info (opcode); ++ if (ACPI_GET_OP_TYPE (op_info) != ACPI_OP_TYPE_OPCODE) { ++ return (AE_AML_BAD_OPCODE); ++ } ++ ++ ++ arg_types = op_info->runtime_args; ++ if (arg_types == ARGI_INVALID_OPCODE) { ++ return (AE_AML_INTERNAL); ++ } ++ ++ ++ /* ++ * Normal exit is with (Arg_types == 0) at end of argument list. ++ * Function will return an exception from within the loop upon ++ * finding an entry which is not (or cannot be converted ++ * to) the required type; if stack underflows; or upon ++ * finding a NULL stack entry (which should not happen). ++ */ ++ ++ while (GET_CURRENT_ARG_TYPE (arg_types)) { ++ if (!stack_ptr || !*stack_ptr) { ++ return (AE_AML_INTERNAL); ++ } ++ ++ /* Extract useful items */ ++ ++ obj_desc = *stack_ptr; ++ ++ /* Decode the descriptor type */ ++ ++ if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) { ++ /* Node */ ++ ++ object_type = ((ACPI_NAMESPACE_NODE *) obj_desc)->type; ++ } ++ ++ else if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_INTERNAL)) { ++ /* ACPI internal object */ ++ ++ object_type = obj_desc->common.type; ++ ++ /* Check for bad ACPI_OBJECT_TYPE */ ++ ++ if (!acpi_aml_validate_object_type (object_type)) { ++ return (AE_AML_OPERAND_TYPE); ++ } ++ ++ if (object_type == (u8) INTERNAL_TYPE_REFERENCE) { ++ /* ++ * Decode the Reference ++ */ ++ ++ op_info = acpi_ps_get_opcode_info (opcode); ++ if (ACPI_GET_OP_TYPE (op_info) != ACPI_OP_TYPE_OPCODE) { ++ return (AE_AML_BAD_OPCODE); ++ } ++ ++ ++ switch (obj_desc->reference.opcode) { ++ case AML_ZERO_OP: ++ case AML_ONE_OP: ++ case AML_ONES_OP: ++ case AML_DEBUG_OP: ++ case AML_NAME_OP: ++ case AML_INDEX_OP: ++ case AML_ARG_OP: ++ case AML_LOCAL_OP: ++ ++ break; ++ ++ default: ++ return (AE_AML_OPERAND_TYPE); ++ break; ++ } ++ } ++ } ++ ++ else { ++ /* Invalid descriptor */ ++ ++ return (AE_AML_OPERAND_TYPE); ++ } ++ ++ ++ /* ++ * Get one argument type, point to the next ++ */ ++ ++ this_arg_type = GET_CURRENT_ARG_TYPE (arg_types); ++ INCREMENT_ARG_LIST (arg_types); ++ ++ ++ /* ++ * Handle cases where the object does not need to be ++ * resolved to a value ++ */ ++ ++ switch (this_arg_type) { ++ ++ case ARGI_REFERENCE: /* References */ ++ case ARGI_INTEGER_REF: ++ case ARGI_OBJECT_REF: ++ case ARGI_DEVICE_REF: ++ case ARGI_TARGETREF: /* TBD: must implement implicit conversion rules before store */ ++ case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */ ++ case ARGI_SIMPLE_TARGET: /* Name, Local, or Arg - no implicit conversion */ ++ ++ /* Need an operand of type INTERNAL_TYPE_REFERENCE */ ++ ++ if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) /* direct name ptr OK as-is */ { ++ goto next_operand; ++ } ++ ++ status = acpi_aml_check_object_type (INTERNAL_TYPE_REFERENCE, ++ object_type, obj_desc); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ ++ if (AML_NAME_OP == obj_desc->reference.opcode) { ++ /* ++ * Convert an indirect name ptr to direct name ptr and put ++ * it on the stack ++ */ ++ ++ temp_node = obj_desc->reference.object; ++ acpi_cm_remove_reference (obj_desc); ++ (*stack_ptr) = temp_node; ++ } ++ ++ goto next_operand; ++ break; ++ ++ ++ case ARGI_ANYTYPE: ++ ++ /* ++ * We don't want to resolve Index_op reference objects during ++ * a store because this would be an implicit De_ref_of operation. ++ * Instead, we just want to store the reference object. ++ * -- All others must be resolved below. ++ */ ++ ++ if ((opcode == AML_STORE_OP) && ++ ((*stack_ptr)->common.type == INTERNAL_TYPE_REFERENCE) && ++ ((*stack_ptr)->reference.opcode == AML_INDEX_OP)) { ++ goto next_operand; ++ } ++ break; ++ } ++ ++ ++ /* ++ * Resolve this object to a value ++ */ ++ ++ status = acpi_aml_resolve_to_value (stack_ptr, walk_state); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ ++ /* ++ * Check the resulting object (value) type ++ */ ++ switch (this_arg_type) { ++ /* ++ * For the simple cases, only one type of resolved object ++ * is allowed ++ */ ++ case ARGI_MUTEX: ++ ++ /* Need an operand of type ACPI_TYPE_MUTEX */ ++ ++ type_needed = ACPI_TYPE_MUTEX; ++ break; ++ ++ case ARGI_EVENT: ++ ++ /* Need an operand of type ACPI_TYPE_EVENT */ ++ ++ type_needed = ACPI_TYPE_EVENT; ++ break; ++ ++ case ARGI_REGION: ++ ++ /* Need an operand of type ACPI_TYPE_REGION */ ++ ++ type_needed = ACPI_TYPE_REGION; ++ break; ++ ++ case ARGI_IF: /* If */ ++ ++ /* Need an operand of type INTERNAL_TYPE_IF */ ++ ++ type_needed = INTERNAL_TYPE_IF; ++ break; ++ ++ case ARGI_PACKAGE: /* Package */ ++ ++ /* Need an operand of type ACPI_TYPE_PACKAGE */ ++ ++ type_needed = ACPI_TYPE_PACKAGE; ++ break; ++ ++ case ARGI_ANYTYPE: ++ ++ /* Any operand type will do */ ++ ++ type_needed = ACPI_TYPE_ANY; ++ break; ++ ++ ++ /* ++ * The more complex cases allow multiple resolved object types ++ */ ++ ++ case ARGI_INTEGER: /* Number */ ++ ++ /* ++ * Need an operand of type ACPI_TYPE_INTEGER, ++ * But we can implicitly convert from a STRING or BUFFER ++ */ ++ status = acpi_aml_convert_to_integer (stack_ptr, walk_state); ++ if (ACPI_FAILURE (status)) { ++ if (status == AE_TYPE) { ++ return (AE_AML_OPERAND_TYPE); ++ } ++ ++ return (status); ++ } ++ ++ goto next_operand; ++ break; ++ ++ ++ case ARGI_BUFFER: ++ ++ /* ++ * Need an operand of type ACPI_TYPE_BUFFER, ++ * But we can implicitly convert from a STRING or INTEGER ++ */ ++ status = acpi_aml_convert_to_buffer (stack_ptr, walk_state); ++ if (ACPI_FAILURE (status)) { ++ if (status == AE_TYPE) { ++ return (AE_AML_OPERAND_TYPE); ++ } ++ ++ return (status); ++ } ++ ++ goto next_operand; ++ break; ++ ++ ++ case ARGI_STRING: ++ ++ /* ++ * Need an operand of type ACPI_TYPE_STRING, ++ * But we can implicitly convert from a BUFFER or INTEGER ++ */ ++ status = acpi_aml_convert_to_string (stack_ptr, walk_state); ++ if (ACPI_FAILURE (status)) { ++ if (status == AE_TYPE) { ++ return (AE_AML_OPERAND_TYPE); ++ } ++ ++ return (status); ++ } ++ ++ goto next_operand; ++ break; ++ ++ ++ case ARGI_COMPUTEDATA: ++ ++ /* Need an operand of type INTEGER, STRING or BUFFER */ ++ ++ if ((ACPI_TYPE_INTEGER != (*stack_ptr)->common.type) && ++ (ACPI_TYPE_STRING != (*stack_ptr)->common.type) && ++ (ACPI_TYPE_BUFFER != (*stack_ptr)->common.type)) { ++ return (AE_AML_OPERAND_TYPE); ++ } ++ goto next_operand; ++ break; ++ ++ ++ case ARGI_DATAOBJECT: ++ /* ++ * ARGI_DATAOBJECT is only used by the Size_of operator. ++ * ++ * The ACPI specification allows Size_of to return the size of ++ * a Buffer, String or Package. However, the MS ACPI.SYS AML ++ * Interpreter also allows an Node reference to return without ++ * error with a size of 4. ++ */ ++ ++ /* Need a buffer, string, package or Node reference */ ++ ++ if (((*stack_ptr)->common.type != ACPI_TYPE_BUFFER) && ++ ((*stack_ptr)->common.type != ACPI_TYPE_STRING) && ++ ((*stack_ptr)->common.type != ACPI_TYPE_PACKAGE) && ++ ((*stack_ptr)->common.type != INTERNAL_TYPE_REFERENCE)) { ++ return (AE_AML_OPERAND_TYPE); ++ } ++ ++ /* ++ * If this is a reference, only allow a reference to an Node. ++ */ ++ if ((*stack_ptr)->common.type == INTERNAL_TYPE_REFERENCE) { ++ if (!(*stack_ptr)->reference.node) { ++ return (AE_AML_OPERAND_TYPE); ++ } ++ } ++ goto next_operand; ++ break; ++ ++ ++ case ARGI_COMPLEXOBJ: ++ ++ /* Need a buffer or package */ ++ ++ if (((*stack_ptr)->common.type != ACPI_TYPE_BUFFER) && ++ ((*stack_ptr)->common.type != ACPI_TYPE_PACKAGE)) { ++ return (AE_AML_OPERAND_TYPE); ++ } ++ goto next_operand; ++ break; ++ ++ ++ default: ++ ++ /* Unknown type */ ++ ++ return (AE_BAD_PARAMETER); ++ } ++ ++ ++ /* ++ * Make sure that the original object was resolved to the ++ * required object type (Simple cases only). ++ */ ++ status = acpi_aml_check_object_type (type_needed, ++ (*stack_ptr)->common.type, *stack_ptr); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ ++next_operand: ++ /* ++ * If more operands needed, decrement Stack_ptr to point ++ * to next operand on stack ++ */ ++ if (GET_CURRENT_ARG_TYPE (arg_types)) { ++ stack_ptr--; ++ } ++ ++ } /* while (*Types) */ ++ ++ ++ return (status); ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/amstore.c linux/drivers/acpi/executer/amstore.c +--- /usr/src/linux/drivers/acpi/executer/amstore.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/amstore.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,578 @@ ++ ++/****************************************************************************** ++ * ++ * Module Name: amstore - AML Interpreter object store support ++ * $Revision: 133 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acparser.h" ++#include "acdispat.h" ++#include "acinterp.h" ++#include "amlcode.h" ++#include "acnamesp.h" ++#include "actables.h" ++ ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("amstore") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_exec_store ++ * ++ * PARAMETERS: *Val_desc - Value to be stored ++ * *Dest_desc - Where to store it. Must be an NS node ++ * or an ACPI_OPERAND_OBJECT of type ++ * Reference; if the latter the descriptor ++ * will be either reused or deleted. ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Store the value described by Val_desc into the location ++ * described by Dest_desc. Called by various interpreter ++ * functions to store the result of an operation into ++ * the destination operand. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_exec_store ( ++ ACPI_OPERAND_OBJECT *val_desc, ++ ACPI_OPERAND_OBJECT *dest_desc, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_STATUS status = AE_OK; ++ ACPI_OPERAND_OBJECT *ref_desc = dest_desc; ++ ++ ++ /* Validate parameters */ ++ ++ if (!val_desc || !dest_desc) { ++ return (AE_AML_NO_OPERAND); ++ } ++ ++ /* Dest_desc can be either a namespace node or an ACPI object */ ++ ++ if (VALID_DESCRIPTOR_TYPE (dest_desc, ACPI_DESC_TYPE_NAMED)) { ++ /* ++ * Dest is a namespace node, ++ * Storing an object into a Name "container" ++ */ ++ status = acpi_aml_store_object_to_node (val_desc, ++ (ACPI_NAMESPACE_NODE *) dest_desc, walk_state); ++ ++ /* All done, that's it */ ++ ++ return (status); ++ } ++ ++ ++ /* Destination object must be an object of type Reference */ ++ ++ if (dest_desc->common.type != INTERNAL_TYPE_REFERENCE) { ++ /* Destination is not an Reference */ ++ ++ return (AE_AML_OPERAND_TYPE); ++ } ++ ++ ++ /* ++ * Examine the Reference opcode. These cases are handled: ++ * ++ * 1) Store to Name (Change the object associated with a name) ++ * 2) Store to an indexed area of a Buffer or Package ++ * 3) Store to a Method Local or Arg ++ * 4) Store to the debug object ++ * 5) Store to a constant -- a noop ++ */ ++ ++ switch (ref_desc->reference.opcode) { ++ ++ case AML_NAME_OP: ++ ++ /* Storing an object into a Name "container" */ ++ ++ status = acpi_aml_store_object_to_node (val_desc, ref_desc->reference.object, ++ walk_state); ++ break; ++ ++ ++ case AML_INDEX_OP: ++ ++ /* Storing to an Index (pointer into a packager or buffer) */ ++ ++ status = acpi_aml_store_object_to_index (val_desc, ref_desc, walk_state); ++ break; ++ ++ ++ case AML_LOCAL_OP: ++ case AML_ARG_OP: ++ ++ /* Store to a method local/arg */ ++ ++ status = acpi_ds_store_object_to_local (ref_desc->reference.opcode, ++ ref_desc->reference.offset, val_desc, walk_state); ++ break; ++ ++ ++ case AML_DEBUG_OP: ++ ++ /* ++ * Storing to the Debug object causes the value stored to be ++ * displayed and otherwise has no effect -- see ACPI Specification ++ * ++ */ ++ if (val_desc->common.type != ACPI_TYPE_STRING) { ++ /* TBD: print known object types "prettier". */ ++ ++ } ++ ++ ++ break; ++ ++ ++ case AML_ZERO_OP: ++ case AML_ONE_OP: ++ case AML_ONES_OP: ++ ++ /* ++ * Storing to a constant is a no-op -- see ACPI Specification ++ * Delete the reference descriptor, however ++ */ ++ break; ++ ++ ++ default: ++ ++ /* TBD: [Restructure] use object dump routine !! */ ++ ++ status = AE_AML_INTERNAL; ++ break; ++ ++ } /* switch (Ref_desc->Reference.Opcode) */ ++ ++ ++ /* Always delete the reference descriptor object */ ++ ++ if (ref_desc) { ++ acpi_cm_remove_reference (ref_desc); ++ } ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_store_object_to_index ++ * ++ * PARAMETERS: *Val_desc - Value to be stored ++ * *Node - Named object to receive the value ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Store the object to the named object. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_store_object_to_index ( ++ ACPI_OPERAND_OBJECT *val_desc, ++ ACPI_OPERAND_OBJECT *dest_desc, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_STATUS status = AE_OK; ++ ACPI_OPERAND_OBJECT *obj_desc; ++ u32 length; ++ u32 i; ++ u8 value = 0; ++ ++ ++ /* ++ * Destination must be a reference pointer, and ++ * must point to either a buffer or a package ++ */ ++ ++ switch (dest_desc->reference.target_type) { ++ case ACPI_TYPE_PACKAGE: ++ /* ++ * Storing to a package element is not simple. The source must be ++ * evaluated and converted to the type of the destination and then the ++ * source is copied into the destination - we can't just point to the ++ * source object. ++ */ ++ if (dest_desc->reference.target_type == ACPI_TYPE_PACKAGE) { ++ /* ++ * The object at *(Dest_desc->Reference.Where) is the ++ * element within the package that is to be modified. ++ */ ++ obj_desc = *(dest_desc->reference.where); ++ if (obj_desc) { ++ /* ++ * If the Destination element is a package, we will delete ++ * that object and construct a new one. ++ * ++ * TBD: [Investigate] Should both the src and dest be required ++ * to be packages? ++ * && (Val_desc->Common.Type == ACPI_TYPE_PACKAGE) ++ */ ++ if (obj_desc->common.type == ACPI_TYPE_PACKAGE) { ++ /* ++ * Take away the reference for being part of a package and ++ * delete ++ */ ++ acpi_cm_remove_reference (obj_desc); ++ acpi_cm_remove_reference (obj_desc); ++ ++ obj_desc = NULL; ++ } ++ } ++ ++ if (!obj_desc) { ++ /* ++ * If the Obj_desc is NULL, it means that an uninitialized package ++ * element has been used as a destination (this is OK), therefore, ++ * we must create the destination element to match the type of the ++ * source element NOTE: Val_desc can be of any type. ++ */ ++ obj_desc = acpi_cm_create_internal_object (val_desc->common.type); ++ if (!obj_desc) { ++ return (AE_NO_MEMORY); ++ } ++ ++ /* ++ * If the source is a package, copy the source to the new dest ++ */ ++ if (ACPI_TYPE_PACKAGE == obj_desc->common.type) { ++ status = acpi_cm_copy_ipackage_to_ipackage (val_desc, obj_desc, walk_state); ++ if (ACPI_FAILURE (status)) { ++ acpi_cm_remove_reference (obj_desc); ++ return (status); ++ } ++ } ++ ++ /* ++ * Install the new descriptor into the package and add a ++ * reference to the newly created descriptor for now being ++ * part of the parent package ++ */ ++ ++ *(dest_desc->reference.where) = obj_desc; ++ acpi_cm_add_reference (obj_desc); ++ } ++ ++ if (ACPI_TYPE_PACKAGE != obj_desc->common.type) { ++ /* ++ * The destination element is not a package, so we need to ++ * convert the contents of the source (Val_desc) and copy into ++ * the destination (Obj_desc) ++ */ ++ status = acpi_aml_store_object_to_object (val_desc, obj_desc, ++ walk_state); ++ if (ACPI_FAILURE (status)) { ++ /* ++ * An error occurrered when copying the internal object ++ * so delete the reference. ++ */ ++ return (AE_AML_OPERAND_TYPE); ++ } ++ } ++ } ++ break; ++ ++ ++ case ACPI_TYPE_BUFFER_FIELD: ++ ++ ++ /* TBD: can probably call the generic Buffer/Field routines */ ++ ++ /* ++ * Storing into a buffer at a location defined by an Index. ++ * ++ * Each 8-bit element of the source object is written to the ++ * 8-bit Buffer Field of the Index destination object. ++ */ ++ ++ /* ++ * Set the Obj_desc to the destination object and type check. ++ */ ++ obj_desc = dest_desc->reference.object; ++ if (obj_desc->common.type != ACPI_TYPE_BUFFER) { ++ return (AE_AML_OPERAND_TYPE); ++ } ++ ++ /* ++ * The assignment of the individual elements will be slightly ++ * different for each source type. ++ */ ++ ++ switch (val_desc->common.type) { ++ /* ++ * If the type is Integer, assign bytewise ++ * This loop to assign each of the elements is somewhat ++ * backward because of the Big Endian-ness of IA-64 ++ */ ++ case ACPI_TYPE_INTEGER: ++ length = sizeof (ACPI_INTEGER); ++ for (i = length; i != 0; i--) { ++ value = (u8)(val_desc->integer.value >> (MUL_8 (i - 1))); ++ obj_desc->buffer.pointer[dest_desc->reference.offset] = value; ++ } ++ break; ++ ++ /* ++ * If the type is Buffer, the Length is in the structure. ++ * Just loop through the elements and assign each one in turn. ++ */ ++ case ACPI_TYPE_BUFFER: ++ length = val_desc->buffer.length; ++ for (i = 0; i < length; i++) { ++ value = *(val_desc->buffer.pointer + i); ++ obj_desc->buffer.pointer[dest_desc->reference.offset] = value; ++ } ++ break; ++ ++ /* ++ * If the type is String, the Length is in the structure. ++ * Just loop through the elements and assign each one in turn. ++ */ ++ case ACPI_TYPE_STRING: ++ length = val_desc->string.length; ++ for (i = 0; i < length; i++) { ++ value = *(val_desc->string.pointer + i); ++ obj_desc->buffer.pointer[dest_desc->reference.offset] = value; ++ } ++ break; ++ ++ /* ++ * If source is not a valid type so return an error. ++ */ ++ default: ++ status = AE_AML_OPERAND_TYPE; ++ break; ++ } ++ break; ++ ++ ++ default: ++ status = AE_AML_OPERAND_TYPE; ++ break; ++ } ++ ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_store_object_to_node ++ * ++ * PARAMETERS: *Source_desc - Value to be stored ++ * *Node - Named object to receive the value ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Store the object to the named object. ++ * ++ * The Assignment of an object to a named object is handled here ++ * The val passed in will replace the current value (if any) ++ * with the input value. ++ * ++ * When storing into an object the data is converted to the ++ * target object type then stored in the object. This means ++ * that the target object type (for an initialized target) will ++ * not be changed by a store operation. ++ * ++ * NOTE: the global lock is acquired early. This will result ++ * in the global lock being held a bit longer. Also, if the ++ * function fails during set up we may get the lock when we ++ * don't really need it. I don't think we care. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_store_object_to_node ( ++ ACPI_OPERAND_OBJECT *source_desc, ++ ACPI_NAMESPACE_NODE *node, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_STATUS status = AE_OK; ++ ACPI_OPERAND_OBJECT *target_desc; ++ OBJECT_TYPE_INTERNAL target_type = ACPI_TYPE_ANY; ++ ++ ++ /* ++ * Assuming the parameters were already validated ++ */ ++ ACPI_ASSERT((node) && (source_desc)); ++ ++ ++ /* ++ * Get current type of the node, and object attached to Node ++ */ ++ target_type = acpi_ns_get_type (node); ++ target_desc = acpi_ns_get_attached_object (node); ++ ++ ++ /* ++ * Resolve the source object to an actual value ++ * (If it is a reference object) ++ */ ++ status = acpi_aml_resolve_object (&source_desc, target_type, walk_state); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ ++ /* ++ * Do the actual store operation ++ */ ++ switch (target_type) { ++ case ACPI_TYPE_BUFFER_FIELD: ++ case INTERNAL_TYPE_REGION_FIELD: ++ case INTERNAL_TYPE_BANK_FIELD: ++ case INTERNAL_TYPE_INDEX_FIELD: ++ ++ /* ++ * For fields, copy the source data to the target field. ++ */ ++ status = acpi_aml_write_data_to_field (source_desc, target_desc); ++ break; ++ ++ ++ case ACPI_TYPE_INTEGER: ++ case ACPI_TYPE_STRING: ++ case ACPI_TYPE_BUFFER: ++ ++ /* ++ * These target types are all of type Integer/String/Buffer, and ++ * therefore support implicit conversion before the store. ++ * ++ * Copy and/or convert the source object to a new target object ++ */ ++ status = acpi_aml_store_object (source_desc, target_type, &target_desc, walk_state); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ /* ++ * Store the new Target_desc as the new value of the Name, and set ++ * the Name's type to that of the value being stored in it. ++ * Source_desc reference count is incremented by Attach_object. ++ */ ++ status = acpi_ns_attach_object (node, target_desc, target_type); ++ break; ++ ++ ++ default: ++ ++ /* No conversions for all other types. Just attach the source object */ ++ ++ status = acpi_ns_attach_object (node, source_desc, source_desc->common.type); ++ ++ break; ++ } ++ ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_store_object_to_object ++ * ++ * PARAMETERS: *Source_desc - Value to be stored ++ * *Dest_desc - Object to receive the value ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Store an object to another object. ++ * ++ * The Assignment of an object to another (not named) object ++ * is handled here. ++ * The val passed in will replace the current value (if any) ++ * with the input value. ++ * ++ * When storing into an object the data is converted to the ++ * target object type then stored in the object. This means ++ * that the target object type (for an initialized target) will ++ * not be changed by a store operation. ++ * ++ * This module allows destination types of Number, String, ++ * and Buffer. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_store_object_to_object ( ++ ACPI_OPERAND_OBJECT *source_desc, ++ ACPI_OPERAND_OBJECT *dest_desc, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_STATUS status = AE_OK; ++ OBJECT_TYPE_INTERNAL destination_type = dest_desc->common.type; ++ ++ ++ /* ++ * Assuming the parameters are valid! ++ */ ++ ACPI_ASSERT((dest_desc) && (source_desc)); ++ ++ ++ /* ++ * From this interface, we only support Integers/Strings/Buffers ++ */ ++ switch (destination_type) { ++ case ACPI_TYPE_INTEGER: ++ case ACPI_TYPE_STRING: ++ case ACPI_TYPE_BUFFER: ++ break; ++ ++ default: ++ return (AE_NOT_IMPLEMENTED); ++ } ++ ++ ++ /* ++ * Resolve the source object to an actual value ++ * (If it is a reference object) ++ */ ++ status = acpi_aml_resolve_object (&source_desc, destination_type, walk_state); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ ++ /* ++ * Copy and/or convert the source object to the destination object ++ */ ++ status = acpi_aml_store_object (source_desc, destination_type, &dest_desc, walk_state); ++ ++ ++ return (status); ++} ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/amstoren.c linux/drivers/acpi/executer/amstoren.c +--- /usr/src/linux/drivers/acpi/executer/amstoren.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/amstoren.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,241 @@ ++ ++/****************************************************************************** ++ * ++ * Module Name: amstoren - AML Interpreter object store support, ++ * Store to Node (namespace object) ++ * $Revision: 35 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acparser.h" ++#include "acdispat.h" ++#include "acinterp.h" ++#include "amlcode.h" ++#include "acnamesp.h" ++#include "actables.h" ++ ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("amstoren") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_resolve_object ++ * ++ * PARAMETERS: Source_desc_ptr - Pointer to the source object ++ * Target_type - Current type of the target ++ * Walk_state - Current walk state ++ * ++ * RETURN: Status, resolved object in Source_desc_ptr. ++ * ++ * DESCRIPTION: Resolve an object. If the object is a reference, dereference ++ * it and return the actual object in the Source_desc_ptr. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_resolve_object ( ++ ACPI_OPERAND_OBJECT **source_desc_ptr, ++ OBJECT_TYPE_INTERNAL target_type, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_OPERAND_OBJECT *source_desc = *source_desc_ptr; ++ ACPI_STATUS status = AE_OK; ++ ++ ++ /* ++ * Ensure we have a Source that can be stored in the target ++ */ ++ switch (target_type) { ++ ++ /* This case handles the "interchangeable" types Integer, String, and Buffer. */ ++ ++ /* ++ * These cases all require only Integers or values that ++ * can be converted to Integers (Strings or Buffers) ++ */ ++ case ACPI_TYPE_BUFFER_FIELD: ++ case INTERNAL_TYPE_REGION_FIELD: ++ case INTERNAL_TYPE_BANK_FIELD: ++ case INTERNAL_TYPE_INDEX_FIELD: ++ ++ /* ++ * Stores into a Field/Region or into a Buffer/String ++ * are all essentially the same. ++ */ ++ case ACPI_TYPE_INTEGER: ++ case ACPI_TYPE_STRING: ++ case ACPI_TYPE_BUFFER: ++ ++ ++ /* TBD: FIX - check for source==REF, resolve, then check type */ ++ ++ /* ++ * If Source_desc is not a valid type, try to resolve it to one. ++ */ ++ if ((source_desc->common.type != ACPI_TYPE_INTEGER) && ++ (source_desc->common.type != ACPI_TYPE_BUFFER) && ++ (source_desc->common.type != ACPI_TYPE_STRING)) { ++ /* ++ * Initially not a valid type, convert ++ */ ++ status = acpi_aml_resolve_to_value (source_desc_ptr, walk_state); ++ if (ACPI_SUCCESS (status) && ++ (source_desc->common.type != ACPI_TYPE_INTEGER) && ++ (source_desc->common.type != ACPI_TYPE_BUFFER) && ++ (source_desc->common.type != ACPI_TYPE_STRING)) { ++ /* ++ * Conversion successful but still not a valid type ++ */ ++ status = AE_AML_OPERAND_TYPE; ++ } ++ } ++ break; ++ ++ ++ case INTERNAL_TYPE_ALIAS: ++ ++ /* ++ * Aliases are resolved by Acpi_aml_prep_operands ++ */ ++ status = AE_AML_INTERNAL; ++ break; ++ ++ ++ case ACPI_TYPE_PACKAGE: ++ default: ++ ++ /* ++ * All other types than Alias and the various Fields come here, ++ * including the untyped case - ACPI_TYPE_ANY. ++ */ ++ break; ++ } ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_store_object ++ * ++ * PARAMETERS: Source_desc - Object to store ++ * Target_type - Current type of the target ++ * Target_desc_ptr - Pointer to the target ++ * Walk_state - Current walk state ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: "Store" an object to another object. This may include ++ * converting the source type to the target type (implicit ++ * conversion), and a copy of the value of the source to ++ * the target. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_store_object ( ++ ACPI_OPERAND_OBJECT *source_desc, ++ OBJECT_TYPE_INTERNAL target_type, ++ ACPI_OPERAND_OBJECT **target_desc_ptr, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_OPERAND_OBJECT *target_desc = *target_desc_ptr; ++ ACPI_STATUS status = AE_OK; ++ ++ ++ /* ++ * Perform the "implicit conversion" of the source to the current type ++ * of the target - As per the ACPI specification. ++ * ++ * If no conversion performed, Source_desc is left alone, otherwise it ++ * is updated with a new object. ++ */ ++ status = acpi_aml_convert_to_target_type (target_type, &source_desc, walk_state); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ /* ++ * We now have two objects of identical types, and we can perform a ++ * copy of the *value* of the source object. ++ */ ++ switch (target_type) { ++ case ACPI_TYPE_ANY: ++ case INTERNAL_TYPE_DEF_ANY: ++ ++ /* ++ * The target namespace node is uninitialized (has no target object), ++ * and will take on the type of the source object ++ */ ++ ++ *target_desc_ptr = source_desc; ++ break; ++ ++ ++ case ACPI_TYPE_INTEGER: ++ ++ target_desc->integer.value = source_desc->integer.value; ++ ++ /* Truncate value if we are executing from a 32-bit ACPI table */ ++ ++ acpi_aml_truncate_for32bit_table (target_desc, walk_state); ++ break; ++ ++ case ACPI_TYPE_STRING: ++ ++ status = acpi_aml_copy_string_to_string (source_desc, target_desc); ++ break; ++ ++ ++ case ACPI_TYPE_BUFFER: ++ ++ status = acpi_aml_copy_buffer_to_buffer (source_desc, target_desc); ++ break; ++ ++ ++ case ACPI_TYPE_PACKAGE: ++ ++ /* ++ * TBD: [Unhandled] Not real sure what to do here ++ */ ++ status = AE_NOT_IMPLEMENTED; ++ break; ++ ++ ++ default: ++ ++ /* ++ * All other types come here. ++ */ ++ status = AE_NOT_IMPLEMENTED; ++ break; ++ } ++ ++ ++ return (status); ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/amstorob.c linux/drivers/acpi/executer/amstorob.c +--- /usr/src/linux/drivers/acpi/executer/amstorob.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/amstorob.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,169 @@ ++ ++/****************************************************************************** ++ * ++ * Module Name: amstorob - AML Interpreter object store support, store to object ++ * $Revision: 30 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acparser.h" ++#include "acdispat.h" ++#include "acinterp.h" ++#include "amlcode.h" ++#include "acnamesp.h" ++#include "actables.h" ++ ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("amstorob") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_copy_buffer_to_buffer ++ * ++ * PARAMETERS: Source_desc - Source object to copy ++ * Target_desc - Destination object of the copy ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Copy a buffer object to another buffer object. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_copy_buffer_to_buffer ( ++ ACPI_OPERAND_OBJECT *source_desc, ++ ACPI_OPERAND_OBJECT *target_desc) ++{ ++ u32 length; ++ u8 *buffer; ++ ++ ++ /* ++ * We know that Source_desc is a buffer by now ++ */ ++ buffer = (u8 *) source_desc->buffer.pointer; ++ length = source_desc->buffer.length; ++ ++ /* ++ * If target is a buffer of length zero, allocate a new ++ * buffer of the proper length ++ */ ++ if (target_desc->buffer.length == 0) { ++ target_desc->buffer.pointer = acpi_cm_allocate (length); ++ if (!target_desc->buffer.pointer) { ++ return (AE_NO_MEMORY); ++ } ++ ++ target_desc->buffer.length = length; ++ } ++ ++ /* ++ * Buffer is a static allocation, ++ * only place what will fit in the buffer. ++ */ ++ if (length <= target_desc->buffer.length) { ++ /* Clear existing buffer and copy in the new one */ ++ ++ MEMSET(target_desc->buffer.pointer, 0, target_desc->buffer.length); ++ MEMCPY(target_desc->buffer.pointer, buffer, length); ++ } ++ ++ else { ++ /* ++ * Truncate the source, copy only what will fit ++ */ ++ MEMCPY(target_desc->buffer.pointer, buffer, target_desc->buffer.length); ++ ++ } ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_copy_string_to_string ++ * ++ * PARAMETERS: Source_desc - Source object to copy ++ * Target_desc - Destination object of the copy ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Copy a String object to another String object ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_copy_string_to_string ( ++ ACPI_OPERAND_OBJECT *source_desc, ++ ACPI_OPERAND_OBJECT *target_desc) ++{ ++ u32 length; ++ u8 *buffer; ++ ++ ++ /* ++ * We know that Source_desc is a string by now. ++ */ ++ buffer = (u8 *) source_desc->string.pointer; ++ length = source_desc->string.length; ++ ++ /* ++ * Setting a string value replaces the old string ++ */ ++ if (length < target_desc->string.length) { ++ /* Clear old string and copy in the new one */ ++ ++ MEMSET(target_desc->string.pointer, 0, target_desc->string.length); ++ MEMCPY(target_desc->string.pointer, buffer, length); ++ } ++ ++ else { ++ /* ++ * Free the current buffer, then allocate a buffer ++ * large enough to hold the value ++ */ ++ if (target_desc->string.pointer && ++ !acpi_tb_system_table_pointer (target_desc->string.pointer)) { ++ /* ++ * Only free if not a pointer into the DSDT ++ */ ++ acpi_cm_free(target_desc->string.pointer); ++ } ++ ++ target_desc->string.pointer = acpi_cm_allocate (length + 1); ++ if (!target_desc->string.pointer) { ++ return (AE_NO_MEMORY); ++ } ++ target_desc->string.length = length; ++ ++ ++ MEMCPY(target_desc->string.pointer, buffer, length); ++ } ++ ++ return (AE_OK); ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/amsystem.c linux/drivers/acpi/executer/amsystem.c +--- /usr/src/linux/drivers/acpi/executer/amsystem.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/amsystem.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,326 @@ ++ ++/****************************************************************************** ++ * ++ * Module Name: amsystem - Interface to OS services ++ * $Revision: 60 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acinterp.h" ++#include "acnamesp.h" ++#include "achware.h" ++#include "acevents.h" ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("amsystem") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_system_wait_semaphore ++ * ++ * PARAMETERS: Semaphore - OSD semaphore to wait on ++ * Timeout - Max time to wait ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Implements a semaphore wait with a check to see if the ++ * semaphore is available immediately. If it is not, the ++ * interpreter is released. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_system_wait_semaphore ( ++ ACPI_HANDLE semaphore, ++ u32 timeout) ++{ ++ ACPI_STATUS status; ++ ++ ++ status = acpi_os_wait_semaphore (semaphore, 1, 0); ++ if (ACPI_SUCCESS (status)) { ++ return (status); ++ } ++ ++ if (status == AE_TIME) { ++ /* We must wait, so unlock the interpreter */ ++ ++ acpi_aml_exit_interpreter (); ++ ++ status = acpi_os_wait_semaphore (semaphore, 1, timeout); ++ ++ /* Reacquire the interpreter */ ++ ++ status = acpi_aml_enter_interpreter (); ++ if (ACPI_SUCCESS (status)) { ++ /* Restore the timeout exception */ ++ ++ status = AE_TIME; ++ } ++ } ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_system_do_stall ++ * ++ * PARAMETERS: How_long - The amount of time to stall ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Suspend running thread for specified amount of time. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_aml_system_do_stall ( ++ u32 how_long) ++{ ++ ++ if (how_long > 1000) /* 1 millisecond */ { ++ /* Since this thread will sleep, we must release the interpreter */ ++ ++ acpi_aml_exit_interpreter (); ++ ++ acpi_os_sleep_usec (how_long); ++ ++ /* And now we must get the interpreter again */ ++ ++ acpi_aml_enter_interpreter (); ++ } ++ ++ else { ++ acpi_os_sleep_usec (how_long); ++ } ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_system_do_suspend ++ * ++ * PARAMETERS: How_long - The amount of time to suspend ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Suspend running thread for specified amount of time. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_aml_system_do_suspend ( ++ u32 how_long) ++{ ++ /* Since this thread will sleep, we must release the interpreter */ ++ ++ acpi_aml_exit_interpreter (); ++ ++ acpi_os_sleep ((u16) (how_long / (u32) 1000), ++ (u16) (how_long % (u32) 1000)); ++ ++ /* And now we must get the interpreter again */ ++ ++ acpi_aml_enter_interpreter (); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_system_acquire_mutex ++ * ++ * PARAMETERS: *Time_desc - The 'time to delay' object descriptor ++ * *Obj_desc - The object descriptor for this op ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Provides an access point to perform synchronization operations ++ * within the AML. This function will cause a lock to be generated ++ * for the Mutex pointed to by Obj_desc. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_system_acquire_mutex ( ++ ACPI_OPERAND_OBJECT *time_desc, ++ ACPI_OPERAND_OBJECT *obj_desc) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ ++ if (!obj_desc) { ++ return (AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Support for the _GL_ Mutex object -- go get the global lock ++ */ ++ ++ if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) { ++ status = acpi_ev_acquire_global_lock (); ++ return (status); ++ } ++ ++ status = acpi_aml_system_wait_semaphore (obj_desc->mutex.semaphore, ++ (u32) time_desc->integer.value); ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_system_release_mutex ++ * ++ * PARAMETERS: *Obj_desc - The object descriptor for this op ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Provides an access point to perform synchronization operations ++ * within the AML. This operation is a request to release a ++ * previously acquired Mutex. If the Mutex variable is set then ++ * it will be decremented. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_system_release_mutex ( ++ ACPI_OPERAND_OBJECT *obj_desc) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ ++ if (!obj_desc) { ++ return (AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Support for the _GL_ Mutex object -- release the global lock ++ */ ++ if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) { ++ acpi_ev_release_global_lock (); ++ return (AE_OK); ++ } ++ ++ status = acpi_os_signal_semaphore (obj_desc->mutex.semaphore, 1); ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_system_signal_event ++ * ++ * PARAMETERS: *Obj_desc - The object descriptor for this op ++ * ++ * RETURN: AE_OK ++ * ++ * DESCRIPTION: Provides an access point to perform synchronization operations ++ * within the AML. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_system_signal_event ( ++ ACPI_OPERAND_OBJECT *obj_desc) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ ++ if (obj_desc) { ++ status = acpi_os_signal_semaphore (obj_desc->event.semaphore, 1); ++ } ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_system_wait_event ++ * ++ * PARAMETERS: *Time_desc - The 'time to delay' object descriptor ++ * *Obj_desc - The object descriptor for this op ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Provides an access point to perform synchronization operations ++ * within the AML. This operation is a request to wait for an ++ * event. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_system_wait_event ( ++ ACPI_OPERAND_OBJECT *time_desc, ++ ACPI_OPERAND_OBJECT *obj_desc) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ ++ if (obj_desc) { ++ status = acpi_aml_system_wait_semaphore (obj_desc->event.semaphore, ++ (u32) time_desc->integer.value); ++ } ++ ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_system_reset_event ++ * ++ * PARAMETERS: *Obj_desc - The object descriptor for this op ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Reset an event to a known state. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_system_reset_event ( ++ ACPI_OPERAND_OBJECT *obj_desc) ++{ ++ ACPI_STATUS status = AE_OK; ++ void *temp_semaphore; ++ ++ ++ /* ++ * We are going to simply delete the existing semaphore and ++ * create a new one! ++ */ ++ ++ status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, 0, &temp_semaphore); ++ if (ACPI_SUCCESS (status)) { ++ acpi_os_delete_semaphore (obj_desc->event.semaphore); ++ obj_desc->event.semaphore = temp_semaphore; ++ } ++ ++ return (status); ++} ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/amutils.c linux/drivers/acpi/executer/amutils.c +--- /usr/src/linux/drivers/acpi/executer/amutils.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/amutils.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,366 @@ ++ ++/****************************************************************************** ++ * ++ * Module Name: amutils - interpreter/scanner utilities ++ * $Revision: 77 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acparser.h" ++#include "acinterp.h" ++#include "amlcode.h" ++#include "acnamesp.h" ++#include "acevents.h" ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("amutils") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_enter_interpreter ++ * ++ * PARAMETERS: None ++ * ++ * DESCRIPTION: Enter the interpreter execution region ++ * TBD: should be a macro ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_enter_interpreter (void) ++{ ++ ACPI_STATUS status; ++ ++ ++ status = acpi_cm_acquire_mutex (ACPI_MTX_EXECUTE); ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_exit_interpreter ++ * ++ * PARAMETERS: None ++ * ++ * DESCRIPTION: Exit the interpreter execution region ++ * ++ * Cases where the interpreter is unlocked: ++ * 1) Completion of the execution of a control method ++ * 2) Method blocked on a Sleep() AML opcode ++ * 3) Method blocked on an Acquire() AML opcode ++ * 4) Method blocked on a Wait() AML opcode ++ * 5) Method blocked to acquire the global lock ++ * 6) Method blocked to execute a serialized control method that is ++ * already executing ++ * 7) About to invoke a user-installed opregion handler ++ * ++ * TBD: should be a macro ++ * ++ ******************************************************************************/ ++ ++void ++acpi_aml_exit_interpreter (void) ++{ ++ ++ acpi_cm_release_mutex (ACPI_MTX_EXECUTE); ++ ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_validate_object_type ++ * ++ * PARAMETERS: Type Object type to validate ++ * ++ * DESCRIPTION: Determine if a type is a valid ACPI object type ++ * ++ ******************************************************************************/ ++ ++u8 ++acpi_aml_validate_object_type ( ++ ACPI_OBJECT_TYPE type) ++{ ++ ++ if ((type > ACPI_TYPE_MAX && type < INTERNAL_TYPE_BEGIN) || ++ (type > INTERNAL_TYPE_MAX)) { ++ return (FALSE); ++ } ++ ++ return (TRUE); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_truncate_for32bit_table ++ * ++ * PARAMETERS: Obj_desc - Object to be truncated ++ * Walk_state - Current walk state ++ * (A method must be executing) ++ * ++ * RETURN: none ++ * ++ * DESCRIPTION: Truncate a number to 32-bits if the currently executing method ++ * belongs to a 32-bit ACPI table. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_aml_truncate_for32bit_table ( ++ ACPI_OPERAND_OBJECT *obj_desc, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ++ /* ++ * Object must be a valid number and we must be executing ++ * a control method ++ */ ++ ++ if ((!obj_desc) || ++ (obj_desc->common.type != ACPI_TYPE_INTEGER) || ++ (!walk_state->method_node)) { ++ return; ++ } ++ ++ if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) { ++ /* ++ * We are running a method that exists in a 32-bit ACPI table. ++ * Truncate the value to 32 bits by zeroing out the upper 32-bit field ++ */ ++ obj_desc->integer.value &= (ACPI_INTEGER) ACPI_UINT32_MAX; ++ } ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_acquire_global_lock ++ * ++ * PARAMETERS: Rule - Lock rule: Always_lock, Never_lock ++ * ++ * RETURN: TRUE/FALSE indicating whether the lock was actually acquired ++ * ++ * DESCRIPTION: Obtain the global lock and keep track of this fact via two ++ * methods. A global variable keeps the state of the lock, and ++ * the state is returned to the caller. ++ * ++ ******************************************************************************/ ++ ++u8 ++acpi_aml_acquire_global_lock ( ++ u32 rule) ++{ ++ u8 locked = FALSE; ++ ACPI_STATUS status; ++ ++ ++ /* Only attempt lock if the Rule says so */ ++ ++ if (rule == (u32) GLOCK_ALWAYS_LOCK) { ++ /* We should attempt to get the lock */ ++ ++ status = acpi_ev_acquire_global_lock (); ++ if (ACPI_SUCCESS (status)) { ++ locked = TRUE; ++ } ++ ++ } ++ ++ return (locked); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_release_global_lock ++ * ++ * PARAMETERS: Locked_by_me - Return value from corresponding call to ++ * Acquire_global_lock. ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Release the global lock if it is locked. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_release_global_lock ( ++ u8 locked_by_me) ++{ ++ ++ ++ /* Only attempt unlock if the caller locked it */ ++ ++ if (locked_by_me) { ++ /* OK, now release the lock */ ++ ++ acpi_ev_release_global_lock (); ++ } ++ ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_digits_needed ++ * ++ * PARAMETERS: val - Value to be represented ++ * base - Base of representation ++ * ++ * RETURN: the number of digits needed to represent val in base ++ * ++ ******************************************************************************/ ++ ++u32 ++acpi_aml_digits_needed ( ++ ACPI_INTEGER val, ++ u32 base) ++{ ++ u32 num_digits = 0; ++ ++ ++ if (base < 1) { ++ REPORT_ERROR (("Aml_digits_needed: Internal error - Invalid base\n")); ++ } ++ ++ else { ++ /* ++ * ACPI_INTEGER is unsigned, which is why we don't worry about the '-' ++ */ ++ for (num_digits = 1; (val = ACPI_DIVIDE (val,base)); ++num_digits) { ; } ++ } ++ ++ return (num_digits); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: ntohl ++ * ++ * PARAMETERS: Value - Value to be converted ++ * ++ * DESCRIPTION: Convert a 32-bit value to big-endian (swap the bytes) ++ * ++ ******************************************************************************/ ++ ++static u32 ++_ntohl ( ++ u32 value) ++{ ++ union { ++ u32 value; ++ u8 bytes[4]; ++ } out; ++ ++ union { ++ u32 value; ++ u8 bytes[4]; ++ } in; ++ ++ ++ in.value = value; ++ ++ out.bytes[0] = in.bytes[3]; ++ out.bytes[1] = in.bytes[2]; ++ out.bytes[2] = in.bytes[1]; ++ out.bytes[3] = in.bytes[0]; ++ ++ return (out.value); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_eisa_id_to_string ++ * ++ * PARAMETERS: Numeric_id - EISA ID to be converted ++ * Out_string - Where to put the converted string (8 bytes) ++ * ++ * DESCRIPTION: Convert a numeric EISA ID to string representation ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_eisa_id_to_string ( ++ u32 numeric_id, ++ NATIVE_CHAR *out_string) ++{ ++ u32 id; ++ ++ /* swap to big-endian to get contiguous bits */ ++ ++ id = _ntohl (numeric_id); ++ ++ out_string[0] = (char) ('@' + ((id >> 26) & 0x1f)); ++ out_string[1] = (char) ('@' + ((id >> 21) & 0x1f)); ++ out_string[2] = (char) ('@' + ((id >> 16) & 0x1f)); ++ out_string[3] = acpi_gbl_hex_to_ascii[(id >> 12) & 0xf]; ++ out_string[4] = acpi_gbl_hex_to_ascii[(id >> 8) & 0xf]; ++ out_string[5] = acpi_gbl_hex_to_ascii[(id >> 4) & 0xf]; ++ out_string[6] = acpi_gbl_hex_to_ascii[id & 0xf]; ++ out_string[7] = 0; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_unsigned_integer_to_string ++ * ++ * PARAMETERS: Value - Value to be converted ++ * Out_string - Where to put the converted string (8 bytes) ++ * ++ * RETURN: Convert a number to string representation ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_unsigned_integer_to_string ( ++ ACPI_INTEGER value, ++ NATIVE_CHAR *out_string) ++{ ++ u32 count; ++ u32 digits_needed; ++ ++ ++ digits_needed = acpi_aml_digits_needed (value, 10); ++ ++ out_string[digits_needed] = '\0'; ++ ++ for (count = digits_needed; count > 0; count--) { ++ out_string[count-1] = (NATIVE_CHAR) ('0' + (ACPI_MODULO (value, 10))); ++ value = ACPI_DIVIDE (value, 10); ++ } ++ ++ return (AE_OK); ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/executer/amxface.c linux/drivers/acpi/executer/amxface.c +--- /usr/src/linux/drivers/acpi/executer/amxface.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/executer/amxface.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,98 @@ ++ ++/****************************************************************************** ++ * ++ * Module Name: amxface - External interpreter interfaces ++ * $Revision: 26 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acinterp.h" ++ ++ ++#define _COMPONENT ACPI_EXECUTER ++ MODULE_NAME ("amxface") ++ ++ ++/* ++ * DEFINE_AML_GLOBALS is tested in amlcode.h ++ * to determine whether certain global names should be "defined" or only ++ * "declared" in the current compilation. This enhances maintainability ++ * by enabling a single header file to embody all knowledge of the names ++ * in question. ++ * ++ * Exactly one module of any executable should #define DEFINE_GLOBALS ++ * before #including the header files which use this convention. The ++ * names in question will be defined and initialized in that module, ++ * and declared as extern in all other modules which #include those ++ * header files. ++ */ ++ ++#define DEFINE_AML_GLOBALS ++#include "amlcode.h" ++#include "acparser.h" ++#include "acnamesp.h" ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_aml_execute_method ++ * ++ * PARAMETERS: Pcode - Pointer to the pcode stream ++ * Pcode_length - Length of pcode that comprises the method ++ * **Params - List of parameters to pass to method, ++ * terminated by NULL. Params itself may be ++ * NULL if no parameters are being passed. ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Execute a control method ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_aml_execute_method ( ++ ACPI_NAMESPACE_NODE *method_node, ++ ACPI_OPERAND_OBJECT **params, ++ ACPI_OPERAND_OBJECT **return_obj_desc) ++{ ++ ACPI_STATUS status; ++ ++ ++ /* ++ * The point here is to lock the interpreter and call the low ++ * level execute. ++ */ ++ ++ status = acpi_aml_enter_interpreter (); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ status = acpi_psx_execute (method_node, params, return_obj_desc); ++ ++ acpi_aml_exit_interpreter (); ++ ++ return (status); ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/hardware/Makefile linux/drivers/acpi/hardware/Makefile +--- /usr/src/linux/drivers/acpi/hardware/Makefile Fri Dec 29 14:07:21 2000 ++++ linux/drivers/acpi/hardware/Makefile Fri Apr 13 11:57:11 2001 +@@ -1,5 +1,6 @@ + # + # Makefile for all Linux ACPI interpreter subdirectories ++# EXCEPT for the ospm directory + # + + O_TARGET := ../$(shell basename `pwd`).o +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/hardware/hwacpi.c linux/drivers/acpi/hardware/hwacpi.c +--- /usr/src/linux/drivers/acpi/hardware/hwacpi.c Mon Jan 29 10:15:58 2001 ++++ linux/drivers/acpi/hardware/hwacpi.c Fri Apr 13 11:57:11 2001 +@@ -2,7 +2,7 @@ + /****************************************************************************** + * + * Module Name: hwacpi - ACPI Hardware Initialization/Mode Interface +- * $Revision: 36 $ ++ * $Revision: 38 $ + * + *****************************************************************************/ + +@@ -29,7 +29,7 @@ + #include "achware.h" + + +-#define _COMPONENT HARDWARE ++#define _COMPONENT ACPI_HARDWARE + MODULE_NAME ("hwacpi") + + +@@ -63,7 +63,8 @@ + + /* Must support *some* mode! */ + /* +- if (!(System_flags & SYS_MODES_MASK)) { ++ if (!(System_flags & SYS_MODES_MASK)) ++ { + Restore_acpi_chipset = FALSE; + + return (AE_ERROR); +@@ -72,8 +73,7 @@ + */ + + +- switch (acpi_gbl_system_flags & SYS_MODES_MASK) +- { ++ switch (acpi_gbl_system_flags & SYS_MODES_MASK) { + /* Identify current ACPI/legacy mode */ + + case (SYS_MODE_ACPI): +@@ -128,8 +128,7 @@ + */ + + if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xgpe0blk.address) && +- acpi_gbl_FADT->gpe0blk_len) +- { ++ acpi_gbl_FADT->gpe0blk_len) { + /* GPE0 specified in FADT */ + + acpi_gbl_gpe0enable_register_save = +@@ -151,8 +150,7 @@ + } + + if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xgpe1_blk.address) && +- acpi_gbl_FADT->gpe1_blk_len) +- { ++ acpi_gbl_FADT->gpe1_blk_len) { + /* GPE1 defined */ + + acpi_gbl_gpe1_enable_register_save = +@@ -196,7 +194,7 @@ + u32 mode) + { + +- ACPI_STATUS status = AE_ERROR; ++ ACPI_STATUS status = AE_NO_HARDWARE_RESPONSE; + + + if (mode == SYS_MODE_ACPI) { +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/hardware/hwgpe.c linux/drivers/acpi/hardware/hwgpe.c +--- /usr/src/linux/drivers/acpi/hardware/hwgpe.c Mon Jan 29 10:15:58 2001 ++++ linux/drivers/acpi/hardware/hwgpe.c Fri Apr 13 11:57:11 2001 +@@ -2,7 +2,7 @@ + /****************************************************************************** + * + * Module Name: hwgpe - Low level GPE enable/disable/clear functions +- * $Revision: 28 $ ++ * $Revision: 29 $ + * + *****************************************************************************/ + +@@ -29,7 +29,7 @@ + #include "acnamesp.h" + #include "acevents.h" + +-#define _COMPONENT HARDWARE ++#define _COMPONENT ACPI_HARDWARE + MODULE_NAME ("hwgpe") + + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/hardware/hwregs.c linux/drivers/acpi/hardware/hwregs.c +--- /usr/src/linux/drivers/acpi/hardware/hwregs.c Mon Jan 29 10:15:58 2001 ++++ linux/drivers/acpi/hardware/hwregs.c Fri Apr 13 11:57:11 2001 +@@ -3,7 +3,7 @@ + * + * Module Name: hwregs - Read/write access functions for the various ACPI + * control and status registers. +- * $Revision: 88 $ ++ * $Revision: 93 $ + * + ******************************************************************************/ + +@@ -30,7 +30,7 @@ + #include "achware.h" + #include "acnamesp.h" + +-#define _COMPONENT HARDWARE ++#define _COMPONENT ACPI_HARDWARE + MODULE_NAME ("hwregs") + + +@@ -55,8 +55,7 @@ + + u32 + acpi_hw_get_bit_shift ( +- u32 mask) +-{ ++ u32 mask) { + u32 shift; + + +@@ -92,7 +91,7 @@ + + if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm1b_evt_blk.address)) { + acpi_os_out16 ((ACPI_IO_ADDRESS) ACPI_GET_ADDRESS (acpi_gbl_FADT->Xpm1b_evt_blk.address), +- (u16) ALL_FIXED_STS_BITS); ++ (u16) ALL_FIXED_STS_BITS); + } + + /* now clear the GPE Bits */ +@@ -101,8 +100,9 @@ + gpe_length = (u16) DIV_2 (acpi_gbl_FADT->gpe0blk_len); + + for (index = 0; index < gpe_length; index++) { +- acpi_os_out8 ((ACPI_IO_ADDRESS) (ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe0blk.address) + index), +- (u8) 0xff); ++ acpi_os_out8 ((ACPI_IO_ADDRESS) ( ++ ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe0blk.address) + index), ++ (u8) 0xff); + } + } + +@@ -110,8 +110,9 @@ + gpe_length = (u16) DIV_2 (acpi_gbl_FADT->gpe1_blk_len); + + for (index = 0; index < gpe_length; index++) { +- acpi_os_out8 ((ACPI_IO_ADDRESS) (ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe1_blk.address) + index), +- (u8) 0xff); ++ acpi_os_out8 ((ACPI_IO_ADDRESS) ( ++ ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe1_blk.address) + index), ++ (u8) 0xff); + } + } + +@@ -150,8 +151,7 @@ + */ + + if ((sleep_state > ACPI_S_STATES_MAX) || +- !slp_typ_a || !slp_typ_b) +- { ++ !slp_typ_a || !slp_typ_b) { + return (AE_BAD_PARAMETER); + } + +@@ -175,6 +175,9 @@ + * two elements + */ + ++ /* Even though Acpi_evaluate_object resolves package references, ++ * Ns_evaluate dpesn't. So, we do it here. ++ */ + status = acpi_cm_resolve_package_references(obj_desc); + + if (obj_desc->package.count < 2) { +@@ -187,8 +190,7 @@ + else if (((obj_desc->package.elements[0])->common.type != + ACPI_TYPE_INTEGER) || + ((obj_desc->package.elements[1])->common.type != +- ACPI_TYPE_INTEGER)) +- { ++ ACPI_TYPE_INTEGER)) { + /* Must have two */ + + REPORT_ERROR (("Sleep State package elements are not both of type Number\n")); +@@ -239,11 +241,10 @@ + u32 register_value = 0; + u32 mask = 0; + u32 value = 0; ++ va_list marker; + + + if (read_write == ACPI_WRITE) { +- va_list marker; +- + va_start (marker, register_id); + value = va_arg (marker, u32); + va_end (marker); +@@ -255,18 +256,16 @@ + + /* + * Decode the Register ID +- * Register id = Register block id | bit id ++ * Register id = Register block id | bit id + * + * Check bit id to fine locate Register offset. +- * check Mask to determine Register offset, and then read-write. ++ * Check Mask to determine Register offset, and then read-write. + */ + +- switch (REGISTER_BLOCK_ID(register_id)) +- { ++ switch (REGISTER_BLOCK_ID (register_id)) { + case PM1_STS: + +- switch (register_id) +- { ++ switch (register_id) { + case TMR_STS: + mask = TMR_STS_MASK; + break; +@@ -315,8 +314,8 @@ + value &= mask; + + if (value) { +- acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, PM1_STS, (u16) value); +- ++ acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, PM1_STS, ++ (u16) value); + register_value = 0; + } + } +@@ -326,8 +325,7 @@ + + case PM1_EN: + +- switch (register_id) +- { ++ switch (register_id) { + case TMR_EN: + mask = TMR_EN_MASK; + break; +@@ -369,8 +367,7 @@ + + case PM1_CONTROL: + +- switch (register_id) +- { ++ switch (register_id) { + case SCI_EN: + mask = SCI_EN_MASK; + break; +@@ -421,16 +418,15 @@ + * because we need to do different things. Yuck. + */ + +- acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, +- register_id, (u16) register_value); ++ acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, register_id, ++ (u16) register_value); + } + break; + + + case PM2_CONTROL: + +- switch (register_id) +- { ++ switch (register_id) { + case ARB_DIS: + mask = ARB_DIS_MASK; + break; +@@ -507,16 +503,18 @@ + /* This write will put the Action state into the General Purpose */ + /* Enable Register indexed by the value in Mask */ + +- acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, +- register_id, (u8) register_value); +- register_value = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, register_id); ++ acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, register_id, ++ (u8) register_value); ++ register_value = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ++ register_id); + } + break; + + + case SMI_CMD_BLOCK: + case PROCESSOR_BLOCK: +- /* not used */ ++ /* Not used by any callers at this time - therefore, not implemented */ ++ + default: + + mask = 0; +@@ -557,13 +555,13 @@ + u32 value = 0; + u32 bank_offset; + ++ + if (ACPI_MTX_LOCK == use_lock) { + acpi_cm_acquire_mutex (ACPI_MTX_HARDWARE); + } + + +- switch (REGISTER_BLOCK_ID(register_id)) +- { ++ switch (REGISTER_BLOCK_ID(register_id)) { + case PM1_STS: /* 16-bit access */ + + value = acpi_hw_low_level_read (16, &acpi_gbl_FADT->Xpm1a_evt_blk, 0); +@@ -672,8 +670,7 @@ + } + + +- switch (REGISTER_BLOCK_ID (register_id)) +- { ++ switch (REGISTER_BLOCK_ID (register_id)) { + case PM1_STS: /* 16-bit access */ + + acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1a_evt_blk, 0); +@@ -751,7 +748,7 @@ + /* For 2.0, SMI_CMD is always in IO space */ + /* TBD: what about 1.0? 0.71? */ + +- acpi_os_out8 (acpi_gbl_FADT->smi_cmd, (u8) value); ++ acpi_os_out8 (acpi_gbl_FADT->smi_cmd, (u8) value); + break; + + +@@ -786,7 +783,7 @@ + u32 + acpi_hw_low_level_read ( + u32 width, +- ACPI_GAS *reg, ++ ACPI_GENERIC_ADDRESS *reg, + u32 offset) + { + u32 value = 0; +@@ -801,8 +798,7 @@ + * a non-zero address within + */ + if ((!reg) || +- (!ACPI_VALID_ADDRESS (reg->address))) +- { ++ (!ACPI_VALID_ADDRESS (reg->address))) { + return 0; + } + +@@ -812,14 +808,12 @@ + * Memory, Io, or PCI config. + */ + +- switch (reg->address_space_id) +- { ++ switch (reg->address_space_id) { + case ADDRESS_SPACE_SYSTEM_MEMORY: + + mem_address = (ACPI_PHYSICAL_ADDRESS) (ACPI_GET_ADDRESS (reg->address) + offset); + +- switch (width) +- { ++ switch (width) { + case 8: + value = acpi_os_mem_in8 (mem_address); + break; +@@ -837,8 +831,7 @@ + + io_address = (ACPI_IO_ADDRESS) (ACPI_GET_ADDRESS (reg->address) + offset); + +- switch (width) +- { ++ switch (width) { + case 8: + value = acpi_os_in8 (io_address); + break; +@@ -857,8 +850,7 @@ + pci_dev_func = ACPI_PCI_DEVFUN (ACPI_GET_ADDRESS (reg->address)); + pci_register = ACPI_PCI_REGISTER (ACPI_GET_ADDRESS (reg->address)) + offset; + +- switch (width) +- { ++ switch (width) { + case 8: + acpi_os_read_pci_cfg_byte (0, pci_dev_func, pci_register, (u8 *) &value); + break; +@@ -896,7 +888,7 @@ + acpi_hw_low_level_write ( + u32 width, + u32 value, +- ACPI_GAS *reg, ++ ACPI_GENERIC_ADDRESS *reg, + u32 offset) + { + ACPI_PHYSICAL_ADDRESS mem_address; +@@ -910,8 +902,7 @@ + * a non-zero address within + */ + if ((!reg) || +- (!ACPI_VALID_ADDRESS (reg->address))) +- { ++ (!ACPI_VALID_ADDRESS (reg->address))) { + return; + } + +@@ -921,14 +912,12 @@ + * Memory, Io, or PCI config. + */ + +- switch (reg->address_space_id) +- { ++ switch (reg->address_space_id) { + case ADDRESS_SPACE_SYSTEM_MEMORY: + + mem_address = (ACPI_PHYSICAL_ADDRESS) (ACPI_GET_ADDRESS (reg->address) + offset); + +- switch (width) +- { ++ switch (width) { + case 8: + acpi_os_mem_out8 (mem_address, (u8) value); + break; +@@ -946,8 +935,7 @@ + + io_address = (ACPI_IO_ADDRESS) (ACPI_GET_ADDRESS (reg->address) + offset); + +- switch (width) +- { ++ switch (width) { + case 8: + acpi_os_out8 (io_address, (u8) value); + break; +@@ -966,8 +954,7 @@ + pci_dev_func = ACPI_PCI_DEVFUN (ACPI_GET_ADDRESS (reg->address)); + pci_register = ACPI_PCI_REGISTER (ACPI_GET_ADDRESS (reg->address)) + offset; + +- switch (width) +- { ++ switch (width) { + case 8: + acpi_os_write_pci_cfg_byte (0, pci_dev_func, pci_register, (u8) value); + break; +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/hardware/hwsleep.c linux/drivers/acpi/hardware/hwsleep.c +--- /usr/src/linux/drivers/acpi/hardware/hwsleep.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/hardware/hwsleep.c Fri Apr 13 11:57:11 2001 +@@ -2,7 +2,7 @@ + /****************************************************************************** + * + * Name: hwsleep.c - ACPI Hardware Sleep/Wake Interface +- * $Revision: 7 $ ++ * $Revision: 10 $ + * + *****************************************************************************/ + +@@ -28,7 +28,7 @@ + #include "acnamesp.h" + #include "achware.h" + +-#define _COMPONENT HARDWARE ++#define _COMPONENT ACPI_HARDWARE + MODULE_NAME ("hwsleep") + + +@@ -179,8 +179,9 @@ + + acpi_hw_register_write(ACPI_MTX_LOCK, PM1_a_CONTROL, PM1_acontrol); + acpi_hw_register_write(ACPI_MTX_LOCK, PM1_b_CONTROL, PM1_bcontrol); +- acpi_hw_register_write(ACPI_MTX_LOCK, PM1_CONTROL, +- (1 << acpi_hw_get_bit_shift (SLP_EN_MASK))); ++ /* one system won't work with this, one won't work without */ ++ /*Acpi_hw_register_write(ACPI_MTX_LOCK, PM1_CONTROL, ++ (1 << Acpi_hw_get_bit_shift (SLP_EN_MASK)));*/ + + enable(); + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/hardware/hwtimer.c linux/drivers/acpi/hardware/hwtimer.c +--- /usr/src/linux/drivers/acpi/hardware/hwtimer.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/hardware/hwtimer.c Fri Apr 13 11:57:11 2001 +@@ -2,7 +2,7 @@ + /****************************************************************************** + * + * Name: hwtimer.c - ACPI Power Management Timer Interface +- * $Revision: 5 $ ++ * $Revision: 7 $ + * + *****************************************************************************/ + +@@ -27,7 +27,7 @@ + #include "acpi.h" + #include "achware.h" + +-#define _COMPONENT HARDWARE ++#define _COMPONENT ACPI_HARDWARE + MODULE_NAME ("hwtimer") + + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/accommon.h linux/drivers/acpi/include/accommon.h +--- /usr/src/linux/drivers/acpi/include/accommon.h Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/include/accommon.h Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Name: accommon.h -- prototypes for the common (subsystem-wide) procedures +- * $Revision: 90 $ ++ * $Revision: 95 $ + * + *****************************************************************************/ + +@@ -126,7 +126,7 @@ + + #ifndef ACPI_USE_SYSTEM_CLIBRARY + +-NATIVE_UINT ++u32 + acpi_cm_strlen ( + const NATIVE_CHAR *string); + +@@ -167,7 +167,7 @@ + acpi_cm_strtoul ( + const NATIVE_CHAR *string, + NATIVE_CHAR **terminator, +- NATIVE_UINT base); ++ u32 base); + + NATIVE_CHAR * + acpi_cm_strstr ( +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/acconfig.h linux/drivers/acpi/include/acconfig.h +--- /usr/src/linux/drivers/acpi/include/acconfig.h Tue Mar 6 19:44:36 2001 ++++ linux/drivers/acpi/include/acconfig.h Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Name: acconfig.h - Global configuration constants +- * $Revision: 55 $ ++ * $Revision: 59 $ + * + *****************************************************************************/ + +@@ -53,7 +53,7 @@ + + /* Version string */ + +-#define ACPI_CA_VERSION 0x20010208 ++#define ACPI_CA_VERSION 0x20010413 + + + /* Maximum objects in the various object caches */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/acdebug.h linux/drivers/acpi/include/acdebug.h +--- /usr/src/linux/drivers/acpi/include/acdebug.h Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/include/acdebug.h Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Name: acdebug.h - ACPI/AML debugger +- * $Revision: 41 $ ++ * $Revision: 42 $ + * + *****************************************************************************/ + +@@ -198,6 +198,10 @@ + void + acpi_db_find_references ( + NATIVE_CHAR *object_arg); ++ ++void ++acpi_db_display_locks (void); ++ + + void + acpi_db_display_resources ( +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/acdispat.h linux/drivers/acpi/include/acdispat.h +--- /usr/src/linux/drivers/acpi/include/acdispat.h Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/include/acdispat.h Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Name: acdispat.h - dispatcher (parser to interpreter interface) +- * $Revision: 35 $ ++ * $Revision: 39 $ + * + *****************************************************************************/ + +@@ -32,12 +32,6 @@ + #define NAMEOF_ARG_NTE "__A0" + + +-/* For Acpi_ds_method_data_set_value */ +- +-#define MTH_TYPE_LOCAL 0 +-#define MTH_TYPE_ARG 1 +- +- + /* Common interfaces */ + + ACPI_STATUS +@@ -64,7 +58,7 @@ + /* dsopcode - support for late evaluation */ + + ACPI_STATUS +-acpi_ds_get_field_unit_arguments ( ++acpi_ds_get_buffer_field_arguments ( + ACPI_OPERAND_OBJECT *obj_desc); + + ACPI_STATUS +@@ -126,7 +120,7 @@ + ACPI_STATUS + acpi_ds_create_index_field ( + ACPI_PARSE_OBJECT *op, +- ACPI_HANDLE region_node, ++ ACPI_NAMESPACE_NODE *region_node, + ACPI_WALK_STATE *walk_state); + + +@@ -173,8 +167,15 @@ + + + ACPI_STATUS ++acpi_ds_store_object_to_local ( ++ u16 opcode, ++ u32 index, ++ ACPI_OPERAND_OBJECT *src_desc, ++ ACPI_WALK_STATE *walk_state); ++ ++ACPI_STATUS + acpi_ds_method_data_get_entry ( +- u32 type, ++ u16 opcode, + u32 index, + ACPI_WALK_STATE *walk_state, + ACPI_OPERAND_OBJECT ***node); +@@ -189,27 +190,20 @@ + + OBJECT_TYPE_INTERNAL + acpi_ds_method_data_get_type ( +- u32 type, ++ u16 opcode, + u32 index, + ACPI_WALK_STATE *walk_state); + + ACPI_STATUS + acpi_ds_method_data_get_value ( +- u32 type, ++ u16 opcode, + u32 index, + ACPI_WALK_STATE *walk_state, + ACPI_OPERAND_OBJECT **dest_desc); + + ACPI_STATUS +-acpi_ds_method_data_set_value ( +- u32 type, +- u32 index, +- ACPI_OPERAND_OBJECT *src_desc, +- ACPI_WALK_STATE *walk_state); +- +-ACPI_STATUS + acpi_ds_method_data_delete_value ( +- u32 type, ++ u16 opcode, + u32 index, + ACPI_WALK_STATE *walk_state); + +@@ -220,8 +214,8 @@ + ACPI_WALK_STATE *walk_state); + + ACPI_NAMESPACE_NODE * +-acpi_ds_method_data_get_nte ( +- u32 type, ++acpi_ds_method_data_get_node ( ++ u16 opcode, + u32 index, + ACPI_WALK_STATE *walk_state); + +@@ -231,7 +225,7 @@ + + ACPI_STATUS + acpi_ds_method_data_set_entry ( +- u32 type, ++ u16 opcode, + u32 index, + ACPI_OPERAND_OBJECT *object, + ACPI_WALK_STATE *walk_state); +@@ -261,7 +255,8 @@ + ACPI_STATUS + acpi_ds_begin_method_execution ( + ACPI_NAMESPACE_NODE *method_node, +- ACPI_OPERAND_OBJECT *obj_desc); ++ ACPI_OPERAND_OBJECT *obj_desc, ++ ACPI_NAMESPACE_NODE *calling_method_node); + + + /* dsobj - Parser/Interpreter interface - object initialization and conversion */ +@@ -307,7 +302,7 @@ + /* dsregn - Parser/Interpreter interface - Op Region parsing */ + + ACPI_STATUS +-acpi_ds_eval_field_unit_operands ( ++acpi_ds_eval_buffer_field_operands ( + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT *op); + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/acenv.h linux/drivers/acpi/include/acenv.h +--- /usr/src/linux/drivers/acpi/include/acenv.h Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/include/acenv.h Wed Dec 31 16:00:00 1969 +@@ -1,288 +0,0 @@ +-/****************************************************************************** +- * +- * Name: acenv.h - Generation environment specific items +- * $Revision: 70 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * 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 +- */ +- +-#ifndef __ACENV_H__ +-#define __ACENV_H__ +- +- +-/* +- * Configuration for ACPI tools and utilities +- */ +- +-#ifdef _ACPI_DUMP_APP +-#define ACPI_DEBUG +-#define ACPI_APPLICATION +-#define ENABLE_DEBUGGER +-#define ACPI_USE_SYSTEM_CLIBRARY +-#define PARSER_ONLY +-#endif +- +-#ifdef _ACPI_EXEC_APP +-#undef DEBUGGER_THREADING +-#define DEBUGGER_THREADING DEBUGGER_SINGLE_THREADED +-#define ACPI_DEBUG +-#define ACPI_APPLICATION +-#define ENABLE_DEBUGGER +-#define ACPI_USE_SYSTEM_CLIBRARY +-#endif +- +-#ifdef _ACPI_ASL_COMPILER +-#define ACPI_DEBUG +-#define ACPI_APPLICATION +-#define ENABLE_DEBUGGER +-#define ACPI_USE_SYSTEM_CLIBRARY +-#endif +- +-/* +- * Memory allocation tracking. Used only if +- * 1) This is the debug version +- * 2) This is NOT a 16-bit version of the code (not enough real-mode memory) +- */ +-#ifdef ACPI_DEBUG +-#ifndef _IA16 +-#define ACPI_DEBUG_TRACK_ALLOCATIONS +-#endif +-#endif +- +-/* +- * Environment configuration. The purpose of this file is to interface to the +- * local generation environment. +- * +- * 1) ACPI_USE_SYSTEM_CLIBRARY - Define this if linking to an actual C library. +- * Otherwise, local versions of string/memory functions will be used. +- * 2) ACPI_USE_STANDARD_HEADERS - Define this if linking to a C library and +- * the standard header files may be used. +- * +- * The ACPI subsystem only uses low level C library functions that do not call +- * operating system services and may therefore be inlined in the code. +- * +- * It may be necessary to tailor these include files to the target +- * generation environment. +- * +- * +- * Functions and constants used from each header: +- * +- * string.h: memcpy +- * memset +- * strcat +- * strcmp +- * strcpy +- * strlen +- * strncmp +- * strncat +- * strncpy +- * +- * stdlib.h: strtoul +- * +- * stdarg.h: va_list +- * va_arg +- * va_start +- * va_end +- * +- */ +- +-/*! [Begin] no source code translation */ +- +-#ifdef _LINUX +-#include "aclinux.h" +- +-#elif _AED_EFI +-#include "acefi.h" +- +-#elif WIN32 +-#include "acwin.h" +- +-#elif __FreeBSD__ +-#include "acfreebsd.h" +- +-#else +- +-/* All other environments */ +- +-#define ACPI_USE_STANDARD_HEADERS +- +-/* Name of host operating system (returned by the _OS_ namespace object) */ +- +-#define ACPI_OS_NAME "Intel ACPI/CA Core Subsystem" +- +-#endif +- +- +-/*! [End] no source code translation !*/ +- +-/****************************************************************************** +- * +- * C library configuration +- * +- *****************************************************************************/ +- +-#ifdef ACPI_USE_SYSTEM_CLIBRARY +-/* +- * Use the standard C library headers. +- * We want to keep these to a minimum. +- * +- */ +- +-#ifdef ACPI_USE_STANDARD_HEADERS +-/* +- * Use the standard headers from the standard locations +- */ +-#include <stdarg.h> +-#include <stdlib.h> +-#include <string.h> +-#include <ctype.h> +- +-#endif /* ACPI_USE_STANDARD_HEADERS */ +- +-/* +- * We will be linking to the standard Clib functions +- */ +- +-#define STRSTR(s1,s2) strstr((s1), (s2)) +-#define STRUPR(s) strupr((s)) +-#define STRLEN(s) strlen((s)) +-#define STRCPY(d,s) strcpy((d), (s)) +-#define STRNCPY(d,s,n) strncpy((d), (s), (NATIVE_INT)(n)) +-#define STRNCMP(d,s,n) strncmp((d), (s), (NATIVE_INT)(n)) +-#define STRCMP(d,s) strcmp((d), (s)) +-#define STRCAT(d,s) strcat((d), (s)) +-#define STRNCAT(d,s,n) strncat((d), (s), (NATIVE_INT)(n)) +-#define STRTOUL(d,s,n) strtoul((d), (s), (NATIVE_INT)(n)) +-#define MEMCPY(d,s,n) memcpy((d), (s), (NATIVE_INT)(n)) +-#define MEMSET(d,s,n) memset((d), (s), (NATIVE_INT)(n)) +-#define TOUPPER toupper +-#define TOLOWER tolower +-#define IS_XDIGIT isxdigit +- +-/****************************************************************************** +- * +- * Not using native C library, use local implementations +- * +- *****************************************************************************/ +-#else +- +-/* +- * Use local definitions of C library macros and functions +- * NOTE: The function implementations may not be as efficient +- * as an inline or assembly code implementation provided by a +- * native C library. +- */ +- +-#ifndef va_arg +- +-#ifndef _VALIST +-#define _VALIST +-typedef char *va_list; +-#endif /* _VALIST */ +- +-/* +- * Storage alignment properties +- */ +- +-#define _AUPBND (sizeof(int) - 1) +-#define _ADNBND (sizeof(int) - 1) +- +-/* +- * Variable argument list macro definitions +- */ +- +-#define _bnd(X, bnd) (((sizeof(X)) + (bnd)) & (~(bnd))) +-#define va_arg(ap, T) (*(T *)(((ap)+=((_bnd(T, _AUPBND)))-(_bnd(T,_ADNBND))))) +-#define va_end(ap) (void)0 +-#define va_start(ap, A) (void)((ap)=(((char*)&(A))+(_bnd(A,_AUPBND)))) +- +-#endif /* va_arg */ +- +- +-#define STRSTR(s1,s2) acpi_cm_strstr ((s1), (s2)) +-#define STRUPR(s) acpi_cm_strupr ((s)) +-#define STRLEN(s) acpi_cm_strlen ((s)) +-#define STRCPY(d,s) acpi_cm_strcpy ((d), (s)) +-#define STRNCPY(d,s,n) acpi_cm_strncpy ((d), (s), (n)) +-#define STRNCMP(d,s,n) acpi_cm_strncmp ((d), (s), (n)) +-#define STRCMP(d,s) acpi_cm_strcmp ((d), (s)) +-#define STRCAT(d,s) acpi_cm_strcat ((d), (s)) +-#define STRNCAT(d,s,n) acpi_cm_strncat ((d), (s), (n)) +-#define STRTOUL(d,s,n) acpi_cm_strtoul ((d), (s),(n)) +-#define MEMCPY(d,s,n) acpi_cm_memcpy ((d), (s), (n)) +-#define MEMSET(d,v,n) acpi_cm_memset ((d), (v), (n)) +-#define TOUPPER acpi_cm_to_upper +-#define TOLOWER acpi_cm_to_lower +- +-#endif /* ACPI_USE_SYSTEM_CLIBRARY */ +- +- +-/****************************************************************************** +- * +- * Assembly code macros +- * +- *****************************************************************************/ +- +-/* +- * Handle platform- and compiler-specific assembly language differences. +- * These should already have been defined by the platform includes above. +- * +- * Notes: +- * 1) Interrupt 3 is used to break into a debugger +- * 2) Interrupts are turned off during ACPI register setup +- */ +- +-/* Unrecognized compiler, use defaults */ +-#ifndef ACPI_ASM_MACROS +- +-#define ACPI_ASM_MACROS +-#define causeinterrupt(level) +-#define BREAKPOINT3 +-#define disable() +-#define enable() +-#define halt() +-#define ACPI_ACQUIRE_GLOBAL_LOCK(Glptr, acq) +-#define ACPI_RELEASE_GLOBAL_LOCK(Glptr, acq) +- +-#endif /* ACPI_ASM_MACROS */ +- +- +-#ifdef ACPI_APPLICATION +- +-/* Don't want software interrupts within a ring3 application */ +- +-#undef causeinterrupt +-#undef BREAKPOINT3 +-#define causeinterrupt(level) +-#define BREAKPOINT3 +-#endif +- +- +-/****************************************************************************** +- * +- * Compiler-specific +- * +- *****************************************************************************/ +- +-/* this has been moved to compiler-specific headers, which are included from the +- platform header. */ +- +- +-#endif /* __ACENV_H__ */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/acevents.h linux/drivers/acpi/include/acevents.h +--- /usr/src/linux/drivers/acpi/include/acevents.h Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/include/acevents.h Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Name: acevents.h - Event subcomponent prototypes and defines +- * $Revision: 63 $ ++ * $Revision: 65 $ + * + *****************************************************************************/ + +@@ -91,11 +91,14 @@ + * Acpi_evnotify - Device Notify handling and dispatch + */ + +-void +-acpi_ev_notify_dispatch ( +- ACPI_HANDLE device, ++ACPI_STATUS ++acpi_ev_queue_notify_request ( ++ ACPI_NAMESPACE_NODE *node, + u32 notify_value); + ++void ++acpi_ev_notify_dispatch ( ++ void *context); + + /* + * Acpi_evregion - Address Space handling +@@ -195,22 +198,6 @@ + void + acpi_ev_terminate ( + void); +- +- +-/* Debug support */ +- +-#ifdef ACPI_DEBUG +- +-u32 +-acpi_ev_sci_count ( +- u32 acpi_event); +- +-#define DEBUG_INCREMENT_EVENT_COUNT(a) acpi_gbl_event_count[a]++; +- +-#else +- +-#define DEBUG_INCREMENT_EVENT_COUNT(a) +-#endif + + + #endif /* __ACEVENTS_H__ */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/acexcep.h linux/drivers/acpi/include/acexcep.h +--- /usr/src/linux/drivers/acpi/include/acexcep.h Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/include/acexcep.h Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Name: acexcep.h - Exception codes returned by the ACPI subsystem +- * $Revision: 41 $ ++ * $Revision: 45 $ + * + *****************************************************************************/ + +@@ -68,8 +68,14 @@ + #define AE_LIMIT (ACPI_STATUS) (0x0012 | AE_CODE_ENVIRONMENTAL) + #define AE_TIME (ACPI_STATUS) (0x0013 | AE_CODE_ENVIRONMENTAL) + #define AE_UNKNOWN_STATUS (ACPI_STATUS) (0x0014 | AE_CODE_ENVIRONMENTAL) ++#define AE_ACQUIRE_DEADLOCK (ACPI_STATUS) (0x0015 | AE_CODE_ENVIRONMENTAL) ++#define AE_RELEASE_DEADLOCK (ACPI_STATUS) (0x0016 | AE_CODE_ENVIRONMENTAL) ++#define AE_NOT_ACQUIRED (ACPI_STATUS) (0x0017 | AE_CODE_ENVIRONMENTAL) ++#define AE_ALREADY_ACQUIRED (ACPI_STATUS) (0x0018 | AE_CODE_ENVIRONMENTAL) ++#define AE_NO_HARDWARE_RESPONSE (ACPI_STATUS) (0x0019 | AE_CODE_ENVIRONMENTAL) ++#define AE_NO_GLOBAL_LOCK (ACPI_STATUS) (0x001A | AE_CODE_ENVIRONMENTAL) + +-#define AE_CODE_ENV_MAX 0x0014 ++#define AE_CODE_ENV_MAX 0x001A + + /* + * Programmer exceptions +@@ -118,8 +124,12 @@ + #define AE_AML_INVALID_SPACE_ID (ACPI_STATUS) (0x0012 | AE_CODE_AML) + #define AE_AML_STRING_LIMIT (ACPI_STATUS) (0x0013 | AE_CODE_AML) + #define AE_AML_NO_RETURN_VALUE (ACPI_STATUS) (0x0014 | AE_CODE_AML) ++#define AE_AML_METHOD_LIMIT (ACPI_STATUS) (0x0015 | AE_CODE_AML) ++#define AE_AML_NOT_OWNER (ACPI_STATUS) (0x0016 | AE_CODE_AML) ++#define AE_AML_MUTEX_ORDER (ACPI_STATUS) (0x0017 | AE_CODE_AML) ++#define AE_AML_MUTEX_NOT_ACQUIRED (ACPI_STATUS) (0x0018 | AE_CODE_AML) + +-#define AE_CODE_AML_MAX 0x0014 ++#define AE_CODE_AML_MAX 0x0018 + + /* + * Internal exceptions used for control +@@ -165,6 +175,12 @@ + "AE_LIMIT", + "AE_TIME", + "AE_UNKNOWN_STATUS", ++ "AE_ACQUIRE_DEADLOCK", ++ "AE_RELEASE_DEADLOCK", ++ "AE_NOT_ACQUIRED", ++ "AE_ALREADY_ACQUIRED", ++ "AE_NO_HARDWARE_RESPONSE", ++ "AE_NO_GLOBAL_LOCK", + }; + + static NATIVE_CHAR *acpi_gbl_exception_names_pgm[] = +@@ -206,6 +222,10 @@ + "AE_AML_INVALID_SPACE_ID", + "AE_AML_STRING_LIMIT", + "AE_AML_NO_RETURN_VALUE", ++ "AE_AML_METHOD_LIMIT", ++ "AE_AML_NOT_OWNER", ++ "AE_AML_MUTEX_ORDER", ++ "AE_AML_MUTEX_NOT_ACQUIRED", + }; + + static NATIVE_CHAR *acpi_gbl_exception_names_ctrl[] = +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/acgcc.h linux/drivers/acpi/include/acgcc.h +--- /usr/src/linux/drivers/acpi/include/acgcc.h Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/include/acgcc.h Wed Dec 31 16:00:00 1969 +@@ -1,147 +0,0 @@ +-/****************************************************************************** +- * +- * Name: acgcc.h - GCC specific defines, etc. +- * $Revision: 5 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * 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 +- */ +- +-#ifndef __ACGCC_H__ +-#define __ACGCC_H__ +- +- +-#ifdef __ia64__ +-#define _IA64 +- +-#define COMPILER_DEPENDENT_UINT64 unsigned long +-/* Single threaded */ +-#define ACPI_APPLICATION +- +-#define ACPI_ASM_MACROS +-#define causeinterrupt(level) +-#define BREAKPOINT3 +-#define disable() __cli() +-#define enable() __sti() +-#define wbinvd() +- +-/*! [Begin] no source code translation */ +- +-#include <asm/pal.h> +- +-#define halt() ia64_pal_halt_light() /* PAL_HALT[_LIGHT] */ +-#define safe_halt() ia64_pal_halt(1) /* PAL_HALT */ +- +- +-#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \ +- do { \ +- __asm__ volatile ("1: ld4 r29=%1\n" \ +- ";;\n" \ +- "mov ar.ccv=r29\n" \ +- "mov r2=r29\n" \ +- "shr.u r30=r29,1\n" \ +- "and r29=-4,r29\n" \ +- ";;\n" \ +- "add r29=2,r29\n" \ +- "and r30=1,r30\n" \ +- ";;\n" \ +- "add r29=r29,r30\n" \ +- ";;\n" \ +- "cmpxchg4.acq r30=%1,r29,ar.ccv\n" \ +- ";;\n" \ +- "cmp.eq p6,p7=r2,r30\n" \ +- "(p7) br.dpnt.few 1b\n" \ +- "cmp.gt p8,p9=3,r29\n" \ +- ";;\n" \ +- "(p8) mov %0=-1\n" \ +- "(p9) mov %0=r0\n" \ +- :"=r"(Acq):"m"(GLptr):"r2","r29","r30","memory"); \ +- } while (0) +- +-#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \ +- do { \ +- __asm__ volatile ("1: ld4 r29=%1\n" \ +- ";;\n" \ +- "mov ar.ccv=r29\n" \ +- "mov r2=r29\n" \ +- "and r29=-4,r29\n" \ +- ";;\n" \ +- "cmpxchg4.acq r30=%1,r29,ar.ccv\n" \ +- ";;\n" \ +- "cmp.eq p6,p7=r2,r30\n" \ +- "(p7) br.dpnt.few 1b\n" \ +- "and %0=1,r2\n" \ +- ";;\n" \ +- :"=r"(Acq):"m"(GLptr):"r2","r29","r30","memory"); \ +- } while (0) +-/*! [End] no source code translation !*/ +- +- +-#else /* DO IA32 */ +-#define COMPILER_DEPENDENT_UINT64 unsigned long long +-#define ACPI_ASM_MACROS +-#define causeinterrupt(level) +-#define BREAKPOINT3 +-#define disable() __cli() +-#define enable() __sti() +-#define halt() __asm__ __volatile__ ("sti; hlt":::"memory") +-#define wbinvd() +- +-/*! [Begin] no source code translation +- * +- * A brief explanation as GNU inline assembly is a bit hairy +- * %0 is the output parameter in EAX ("=a") +- * %1 and %2 are the input parameters in ECX ("c") +- * and an immediate value ("i") respectively +- * All actual register references are preceded with "%%" as in "%%edx" +- * Immediate values in the assembly are preceded by "$" as in "$0x1" +- * The final asm parameter are the operation altered non-output registers. +- */ +-#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \ +- do { \ +- int dummy; \ +- asm("1: movl (%1),%%eax;" \ +- "movl %%eax,%%edx;" \ +- "andl %2,%%edx;" \ +- "btsl $0x1,%%edx;" \ +- "adcl $0x0,%%edx;" \ +- "lock; cmpxchgl %%edx,(%1);" \ +- "jnz 1b;" \ +- "cmpb $0x3,%%dl;" \ +- "sbbl %%eax,%%eax" \ +- :"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~1L):"dx"); \ +- } while(0) +- +-#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \ +- do { \ +- int dummy; \ +- asm("1: movl (%1),%%eax;" \ +- "movl %%eax,%%edx;" \ +- "andl %2,%%edx;" \ +- "lock; cmpxchgl %%edx,(%1);" \ +- "jnz 1b;" \ +- "andl $0x1,%%eax" \ +- :"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~3L):"dx"); \ +- } while(0) +- +-/*! [End] no source code translation !*/ +- +-#endif /* IA 32 */ +- +-#endif /* __ACGCC_H__ */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/acglobal.h linux/drivers/acpi/include/acglobal.h +--- /usr/src/linux/drivers/acpi/include/acglobal.h Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/include/acglobal.h Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Name: acglobal.h - Declarations for global variables +- * $Revision: 96 $ ++ * $Revision: 99 $ + * + *****************************************************************************/ + +@@ -150,19 +150,19 @@ + + ACPI_EXTERN u8 acpi_gbl_debugger_configuration; + ACPI_EXTERN u8 acpi_gbl_global_lock_acquired; +-ACPI_EXTERN u8 acpi_gbl_global_lock_set; /* TBD: [Restructure] OBSOLETE?? */ + ACPI_EXTERN u8 acpi_gbl_step_to_next_call; + ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present; ++ACPI_EXTERN u8 acpi_gbl_global_lock_present; + + ACPI_EXTERN ACPI_OBJECT_NOTIFY_HANDLER acpi_gbl_drv_notify; + ACPI_EXTERN ACPI_OBJECT_NOTIFY_HANDLER acpi_gbl_sys_notify; + + +-extern u8 acpi_gbl_shutdown; +-extern u32 acpi_gbl_system_flags; +-extern u32 acpi_gbl_startup_flags; +-extern u8 acpi_gbl_decode_to8bit[8]; +-extern NATIVE_CHAR acpi_gbl_hex_to_ascii[]; ++extern u8 acpi_gbl_shutdown; ++extern u32 acpi_gbl_system_flags; ++extern u32 acpi_gbl_startup_flags; ++extern u8 acpi_gbl_decode_to8bit[8]; ++extern NATIVE_CHAR acpi_gbl_hex_to_ascii[16]; + + + /***************************************************************************** +@@ -178,8 +178,8 @@ + ACPI_EXTERN ACPI_NAMESPACE_NODE acpi_gbl_root_node_struct; + ACPI_EXTERN ACPI_NAMESPACE_NODE *acpi_gbl_root_node; + +-extern u8 acpi_gbl_ns_properties[NUM_NS_TYPES]; +-extern PREDEFINED_NAMES acpi_gbl_pre_defined_names [NUM_PREDEFINED_NAMES]; ++extern u8 acpi_gbl_ns_properties[NUM_NS_TYPES]; ++extern PREDEFINED_NAMES acpi_gbl_pre_defined_names [NUM_PREDEFINED_NAMES]; + + + /* Used to detect memory leaks (DEBUG ONLY) */ +@@ -200,14 +200,8 @@ + ACPI_EXTERN ACPI_WALK_LIST *acpi_gbl_current_walk_list; + + /* +- * Handle to the last method found - used during pass1 of load +- */ +-ACPI_EXTERN ACPI_HANDLE acpi_gbl_last_method; +- +-/* + * Table of Address Space handlers + */ +- + ACPI_EXTERN ACPI_ADDRESS_SPACE_INFO acpi_gbl_address_spaces[ACPI_NUM_ADDRESS_SPACES]; + + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/achware.h linux/drivers/acpi/include/achware.h +--- /usr/src/linux/drivers/acpi/include/achware.h Mon Jan 29 10:15:59 2001 ++++ linux/drivers/acpi/include/achware.h Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Name: achware.h -- hardware specific interfaces +- * $Revision: 53 $ ++ * $Revision: 55 $ + * + *****************************************************************************/ + +@@ -82,14 +82,14 @@ + u32 + acpi_hw_low_level_read ( + u32 width, +- ACPI_GAS *reg, ++ ACPI_GENERIC_ADDRESS *reg, + u32 offset); + + void + acpi_hw_low_level_write ( + u32 width, + u32 value, +- ACPI_GAS *reg, ++ ACPI_GENERIC_ADDRESS *reg, + u32 offset); + + void +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/acinterp.h linux/drivers/acpi/include/acinterp.h +--- /usr/src/linux/drivers/acpi/include/acinterp.h Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/include/acinterp.h Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Name: acinterp.h - Interpreter subcomponent prototypes and defines +- * $Revision: 92 $ ++ * $Revision: 99 $ + * + *****************************************************************************/ + +@@ -100,7 +100,7 @@ + */ + + ACPI_STATUS +-acpi_aml_read_field ( ++acpi_aml_extract_from_field ( + ACPI_OPERAND_OBJECT *obj_desc, + void *buffer, + u32 buffer_length, +@@ -110,7 +110,7 @@ + u32 byte_granularity); + + ACPI_STATUS +-acpi_aml_write_field ( ++acpi_aml_insert_into_field ( + ACPI_OPERAND_OBJECT *obj_desc, + void *buffer, + u32 buffer_length, +@@ -126,25 +126,65 @@ + u32 field_bit_width); + + ACPI_STATUS +-acpi_aml_read_field_data ( ++acpi_aml_read_field_datum ( + ACPI_OPERAND_OBJECT *obj_desc, + u32 field_byte_offset, + u32 field_bit_width, + u32 *value); + + ACPI_STATUS +-acpi_aml_access_named_field ( ++acpi_aml_common_access_field ( + u32 mode, +- ACPI_HANDLE named_field, ++ ACPI_OPERAND_OBJECT *obj_desc, ++ void *buffer, ++ u32 buffer_length); ++ ++ ++ACPI_STATUS ++acpi_aml_access_index_field ( ++ u32 mode, ++ ACPI_OPERAND_OBJECT *obj_desc, + void *buffer, +- u32 length); ++ u32 buffer_length); ++ ++ACPI_STATUS ++acpi_aml_access_bank_field ( ++ u32 mode, ++ ACPI_OPERAND_OBJECT *obj_desc, ++ void *buffer, ++ u32 buffer_length); ++ ++ACPI_STATUS ++acpi_aml_access_region_field ( ++ u32 mode, ++ ACPI_OPERAND_OBJECT *obj_desc, ++ void *buffer, ++ u32 buffer_length); ++ ++ ++ACPI_STATUS ++acpi_aml_access_buffer_field ( ++ u32 mode, ++ ACPI_OPERAND_OBJECT *obj_desc, ++ void *buffer, ++ u32 buffer_length); ++ ++ACPI_STATUS ++acpi_aml_read_data_from_field ( ++ ACPI_OPERAND_OBJECT *obj_desc, ++ ACPI_OPERAND_OBJECT **ret_buffer_desc); ++ ++ACPI_STATUS ++acpi_aml_write_data_to_field ( ++ ACPI_OPERAND_OBJECT *source_desc, ++ ACPI_OPERAND_OBJECT *obj_desc); + + /* + * ammisc - ACPI AML (p-code) execution - specific opcodes + */ + + ACPI_STATUS +-acpi_aml_exec_create_field ( ++acpi_aml_create_buffer_field ( + u8 *aml_ptr, + u32 aml_length, + ACPI_NAMESPACE_NODE *node, +@@ -176,12 +216,12 @@ + ACPI_STATUS + acpi_aml_exec_create_processor ( + ACPI_PARSE_OBJECT *op, +- ACPI_HANDLE processor_nTE); ++ ACPI_NAMESPACE_NODE *processor_node); + + ACPI_STATUS + acpi_aml_exec_create_power_resource ( + ACPI_PARSE_OBJECT *op, +- ACPI_HANDLE processor_nTE); ++ ACPI_NAMESPACE_NODE *power_node); + + ACPI_STATUS + acpi_aml_exec_create_region ( +@@ -203,7 +243,31 @@ + u8 *aml_ptr, + u32 acpi_aml_length, + u32 method_flags, +- ACPI_HANDLE method); ++ ACPI_NAMESPACE_NODE *method); ++ ++ ++/* ++ * ammutex - mutex support ++ */ ++ ++ACPI_STATUS ++acpi_aml_acquire_mutex ( ++ ACPI_OPERAND_OBJECT *time_desc, ++ ACPI_OPERAND_OBJECT *obj_desc, ++ ACPI_WALK_STATE *walk_state); ++ ++ACPI_STATUS ++acpi_aml_release_mutex ( ++ ACPI_OPERAND_OBJECT *obj_desc, ++ ACPI_WALK_STATE *walk_state); ++ ++ACPI_STATUS ++acpi_aml_release_all_mutexes ( ++ ACPI_OPERAND_OBJECT *mutex_list); ++ ++void ++acpi_aml_unlink_mutex ( ++ ACPI_OPERAND_OBJECT *obj_desc); + + + /* +@@ -211,32 +275,36 @@ + */ + + ACPI_STATUS +-acpi_aml_prep_def_field_value ( ++acpi_aml_prep_common_field_object ( ++ ACPI_OPERAND_OBJECT *obj_desc, ++ u8 field_flags, ++ u32 field_position, ++ u32 field_length); ++ ++ACPI_STATUS ++acpi_aml_prep_region_field_value ( + ACPI_NAMESPACE_NODE *node, + ACPI_HANDLE region, + u8 field_flags, +- u8 field_attribute, + u32 field_position, + u32 field_length); + + ACPI_STATUS + acpi_aml_prep_bank_field_value ( + ACPI_NAMESPACE_NODE *node, +- ACPI_HANDLE region, +- ACPI_HANDLE bank_reg, ++ ACPI_NAMESPACE_NODE *region_node, ++ ACPI_NAMESPACE_NODE *bank_register_node, + u32 bank_val, + u8 field_flags, +- u8 field_attribute, + u32 field_position, + u32 field_length); + + ACPI_STATUS + acpi_aml_prep_index_field_value ( + ACPI_NAMESPACE_NODE *node, +- ACPI_HANDLE index_reg, +- ACPI_HANDLE data_reg, ++ ACPI_NAMESPACE_NODE *index_reg, ++ ACPI_NAMESPACE_NODE *data_reg, + u8 field_flags, +- u8 field_attribute, + u32 field_position, + u32 field_length); + +@@ -245,10 +313,6 @@ + * amsystem - Interface to OS services + */ + +-u16 +-acpi_aml_system_thread_id ( +- void); +- + ACPI_STATUS + acpi_aml_system_do_notify_op ( + ACPI_OPERAND_OBJECT *value, +@@ -360,7 +424,7 @@ + ACPI_WALK_STATE *walk_state); + + ACPI_STATUS +-acpi_aml_get_field_unit_value ( ++acpi_aml_get_buffer_field_value ( + ACPI_OPERAND_OBJECT *field_desc, + ACPI_OPERAND_OBJECT *result_desc); + +@@ -510,7 +574,7 @@ + ACPI_NAMESPACE_NODE *node); + + ACPI_STATUS +-acpi_aml_copy_integer_to_field_unit ( ++acpi_aml_copy_integer_to_buffer_field ( + ACPI_OPERAND_OBJECT *source_desc, + ACPI_OPERAND_OBJECT *target_desc); + +@@ -518,7 +582,7 @@ + * amutils - interpreter/scanner utilities + */ + +-void ++ACPI_STATUS + acpi_aml_enter_interpreter ( + void); + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/aclinux.h linux/drivers/acpi/include/aclinux.h +--- /usr/src/linux/drivers/acpi/include/aclinux.h Fri Feb 16 16:06:17 2001 ++++ linux/drivers/acpi/include/aclinux.h Wed Dec 31 16:00:00 1969 +@@ -1,55 +0,0 @@ +-/****************************************************************************** +- * +- * Name: aclinux.h - OS specific defines, etc. +- * $Revision: 9 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * 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 +- */ +- +-#ifndef __ACLINUX_H__ +-#define __ACLINUX_H__ +- +-#define ACPI_OS_NAME "Linux" +- +-#include <linux/string.h> +-#include <linux/kernel.h> +-#include <linux/ctype.h> +-#include <asm/system.h> +-#include <asm/atomic.h> +-#include <asm/div64.h> +- +-/* Linux uses GCC */ +- +-#include "acgcc.h" +- +-#undef DEBUGGER_THREADING +-#define DEBUGGER_THREADING DEBUGGER_SINGLE_THREADED +- +-#ifndef _IA64 +-/* Linux ia32 can't do int64 well */ +-#define ACPI_NO_INTEGER64_SUPPORT +-/* And the ia32 kernel doesn't include 64-bit divide support */ +-#define ACPI_DIV64(dividend, divisor) do_div(dividend, divisor) +-#else +-#define ACPI_DIV64(dividend, divisor) ACPI_DIVIDE(dividend, divisor) +-#endif +- +- +-#endif /* __ACLINUX_H__ */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/aclocal.h linux/drivers/acpi/include/aclocal.h +--- /usr/src/linux/drivers/acpi/include/aclocal.h Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/include/aclocal.h Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Name: aclocal.h - Internal data types used across the ACPI subsystem +- * $Revision: 104 $ ++ * $Revision: 114 $ + * + *****************************************************************************/ + +@@ -27,20 +27,20 @@ + #define __ACLOCAL_H__ + + +-#define WAIT_FOREVER ((u32) -1) ++#define WAIT_FOREVER ((u32) -1) + +-typedef void* ACPI_MUTEX; +-typedef u32 ACPI_MUTEX_HANDLE; ++typedef void* ACPI_MUTEX; ++typedef u32 ACPI_MUTEX_HANDLE; + + + /* Object descriptor types */ + +-#define ACPI_CACHED_OBJECT 0x11 /* ORed in when object is cached */ +-#define ACPI_DESC_TYPE_STATE 0x22 +-#define ACPI_DESC_TYPE_WALK 0x44 +-#define ACPI_DESC_TYPE_PARSER 0x66 +-#define ACPI_DESC_TYPE_INTERNAL 0x88 +-#define ACPI_DESC_TYPE_NAMED 0xAA ++#define ACPI_CACHED_OBJECT 0x11 /* ORed in when object is cached */ ++#define ACPI_DESC_TYPE_STATE 0x22 ++#define ACPI_DESC_TYPE_WALK 0x44 ++#define ACPI_DESC_TYPE_PARSER 0x66 ++#define ACPI_DESC_TYPE_INTERNAL 0x88 ++#define ACPI_DESC_TYPE_NAMED 0xAA + + + /***************************************************************************** +@@ -53,25 +53,29 @@ + /* + * Predefined handles for the mutex objects used within the subsystem + * All mutex objects are automatically created by Acpi_cm_mutex_initialize. ++ * ++ * The acquire/release ordering protocol is implied via this list. Mutexes ++ * with a lower value must be acquired before mutexes with a higher value. ++ * + * NOTE: any changes here must be reflected in the Acpi_gbl_Mutex_names table also! + */ + +-#define ACPI_MTX_HARDWARE 0 +-#define ACPI_MTX_MEMORY 1 +-#define ACPI_MTX_CACHES 2 +-#define ACPI_MTX_TABLES 3 +-#define ACPI_MTX_PARSER 4 +-#define ACPI_MTX_DISPATCHER 5 +-#define ACPI_MTX_INTERPRETER 6 +-#define ACPI_MTX_EXECUTE 7 +-#define ACPI_MTX_NAMESPACE 8 +-#define ACPI_MTX_EVENTS 9 +-#define ACPI_MTX_OP_REGIONS 10 +-#define ACPI_MTX_DEBUG_CMD_READY 11 +-#define ACPI_MTX_DEBUG_CMD_COMPLETE 12 ++#define ACPI_MTX_EXECUTE 0 ++#define ACPI_MTX_INTERPRETER 1 ++#define ACPI_MTX_PARSER 2 ++#define ACPI_MTX_DISPATCHER 3 ++#define ACPI_MTX_TABLES 4 ++#define ACPI_MTX_OP_REGIONS 5 ++#define ACPI_MTX_NAMESPACE 6 ++#define ACPI_MTX_EVENTS 7 ++#define ACPI_MTX_HARDWARE 8 ++#define ACPI_MTX_CACHES 9 ++#define ACPI_MTX_MEMORY 10 ++#define ACPI_MTX_DEBUG_CMD_COMPLETE 11 ++#define ACPI_MTX_DEBUG_CMD_READY 12 + +-#define MAX_MTX 12 +-#define NUM_MTX MAX_MTX+1 ++#define MAX_MTX 12 ++#define NUM_MTX MAX_MTX+1 + + + #if defined(ACPI_DEBUG) || defined(ENABLE_DEBUGGER) +@@ -81,19 +85,19 @@ + + static NATIVE_CHAR *acpi_gbl_mutex_names[] = + { +- "ACPI_MTX_Hardware", +- "ACPI_MTX_Memory", +- "ACPI_MTX_Caches", +- "ACPI_MTX_Tables", ++ "ACPI_MTX_Execute", ++ "ACPI_MTX_Interpreter", + "ACPI_MTX_Parser", + "ACPI_MTX_Dispatcher", +- "ACPI_MTX_Interpreter", +- "ACPI_MTX_Execute", ++ "ACPI_MTX_Tables", ++ "ACPI_MTX_Op_regions", + "ACPI_MTX_Namespace", + "ACPI_MTX_Events", +- "ACPI_MTX_Op_regions", ++ "ACPI_MTX_Hardware", ++ "ACPI_MTX_Caches", ++ "ACPI_MTX_Memory", ++ "ACPI_MTX_Debug_cmd_complete", + "ACPI_MTX_Debug_cmd_ready", +- "ACPI_MTX_Debug_cmd_complete" + }; + + #endif +@@ -106,26 +110,31 @@ + { + ACPI_MUTEX mutex; + u32 use_count; +- u8 locked; ++ u32 owner_id; + + } ACPI_MUTEX_INFO; + ++/* This owner ID means that the mutex is not in use (unlocked) */ ++ ++#define ACPI_MUTEX_NOT_ACQUIRED (u32) (-1) ++ + + /* Lock flag parameter for various interfaces */ + +-#define ACPI_MTX_DO_NOT_LOCK 0 +-#define ACPI_MTX_LOCK 1 ++#define ACPI_MTX_DO_NOT_LOCK 0 ++#define ACPI_MTX_LOCK 1 + + +-typedef u16 ACPI_OWNER_ID; +-#define OWNER_TYPE_TABLE 0x0 +-#define OWNER_TYPE_METHOD 0x1 +-#define FIRST_METHOD_ID 0x0000 +-#define FIRST_TABLE_ID 0x8000 ++typedef u16 ACPI_OWNER_ID; ++#define OWNER_TYPE_TABLE 0x0 ++#define OWNER_TYPE_METHOD 0x1 ++#define FIRST_METHOD_ID 0x0000 ++#define FIRST_TABLE_ID 0x8000 + + /* TBD: [Restructure] get rid of the need for this! */ + +-#define TABLE_ID_DSDT (ACPI_OWNER_ID) 0x8000 ++#define TABLE_ID_DSDT (ACPI_OWNER_ID) 0x8000 ++ + + /***************************************************************************** + * +@@ -175,13 +184,13 @@ + + /* Node flags */ + +-#define ANOBJ_AML_ATTACHMENT 0x01 +-#define ANOBJ_END_OF_PEER_LIST 0x02 +-#define ANOBJ_DATA_WIDTH_32 0x04 /* Parent table is 64-bits */ +-#define ANOBJ_METHOD_ARG 0x08 +-#define ANOBJ_METHOD_LOCAL 0x10 +-#define ANOBJ_METHOD_NO_RETVAL 0x20 +-#define ANOBJ_METHOD_SOME_NO_RETVAL 0x40 ++#define ANOBJ_AML_ATTACHMENT 0x01 ++#define ANOBJ_END_OF_PEER_LIST 0x02 ++#define ANOBJ_DATA_WIDTH_32 0x04 /* Parent table is 64-bits */ ++#define ANOBJ_METHOD_ARG 0x08 ++#define ANOBJ_METHOD_LOCAL 0x10 ++#define ANOBJ_METHOD_NO_RETVAL 0x20 ++#define ANOBJ_METHOD_SOME_NO_RETVAL 0x40 + + + /* +@@ -225,8 +234,8 @@ + /* + * Predefined Namespace items + */ +-#define ACPI_MAX_ADDRESS_SPACE 255 +-#define ACPI_NUM_ADDRESS_SPACES 256 ++#define ACPI_MAX_ADDRESS_SPACE 255 ++#define ACPI_NUM_ADDRESS_SPACES 256 + + + typedef struct +@@ -238,6 +247,13 @@ + } PREDEFINED_NAMES; + + ++/* Object types used during package copies */ ++ ++ ++#define ACPI_COPY_TYPE_SIMPLE 0 ++#define ACPI_COPY_TYPE_PACKAGE 1 ++ ++ + /***************************************************************************** + * + * Event typedefs and structs +@@ -247,19 +263,19 @@ + + /* Status bits. */ + +-#define ACPI_STATUS_PMTIMER 0x0001 +-#define ACPI_STATUS_GLOBAL 0x0020 +-#define ACPI_STATUS_POWER_BUTTON 0x0100 +-#define ACPI_STATUS_SLEEP_BUTTON 0x0200 +-#define ACPI_STATUS_RTC_ALARM 0x0400 ++#define ACPI_STATUS_PMTIMER 0x0001 ++#define ACPI_STATUS_GLOBAL 0x0020 ++#define ACPI_STATUS_POWER_BUTTON 0x0100 ++#define ACPI_STATUS_SLEEP_BUTTON 0x0200 ++#define ACPI_STATUS_RTC_ALARM 0x0400 + + /* Enable bits. */ + +-#define ACPI_ENABLE_PMTIMER 0x0001 +-#define ACPI_ENABLE_GLOBAL 0x0020 +-#define ACPI_ENABLE_POWER_BUTTON 0x0100 +-#define ACPI_ENABLE_SLEEP_BUTTON 0x0200 +-#define ACPI_ENABLE_RTC_ALARM 0x0400 ++#define ACPI_ENABLE_PMTIMER 0x0001 ++#define ACPI_ENABLE_GLOBAL 0x0020 ++#define ACPI_ENABLE_POWER_BUTTON 0x0100 ++#define ACPI_ENABLE_SLEEP_BUTTON 0x0200 ++#define ACPI_ENABLE_RTC_ALARM 0x0400 + + + /* +@@ -287,8 +303,8 @@ + } ACPI_GPE_REGISTERS; + + +-#define ACPI_GPE_LEVEL_TRIGGERED 1 +-#define ACPI_GPE_EDGE_TRIGGERED 2 ++#define ACPI_GPE_LEVEL_TRIGGERED 1 ++#define ACPI_GPE_EDGE_TRIGGERED 2 + + + /* Information about each particular GPE level */ +@@ -332,16 +348,18 @@ + ****************************************************************************/ + + +-#define CONTROL_NORMAL 0xC0 +-#define CONTROL_CONDITIONAL_EXECUTING 0xC1 +-#define CONTROL_PREDICATE_EXECUTING 0xC2 +-#define CONTROL_PREDICATE_FALSE 0xC3 +-#define CONTROL_PREDICATE_TRUE 0xC4 ++#define CONTROL_NORMAL 0xC0 ++#define CONTROL_CONDITIONAL_EXECUTING 0xC1 ++#define CONTROL_PREDICATE_EXECUTING 0xC2 ++#define CONTROL_PREDICATE_FALSE 0xC3 ++#define CONTROL_PREDICATE_TRUE 0xC4 + + +-/* Forward declaration */ ++/* Forward declarations */ + struct acpi_walk_state; +-struct acpi_parse_obj ; ++struct acpi_walk_list; ++struct acpi_parse_obj; ++struct acpi_obj_mutex; + + + #define ACPI_STATE_COMMON /* Two 32-bit fields and a pointer */\ +@@ -436,6 +454,20 @@ + } ACPI_RESULT_VALUES; + + ++/* ++ * Notify info - used to pass info to the deferred notify ++ * handler/dispatcher. ++ */ ++ ++typedef struct acpi_notify_info ++{ ++ ACPI_STATE_COMMON ++ ACPI_NAMESPACE_NODE *node; ++ union acpi_operand_obj *handler_obj; ++ ++} ACPI_NOTIFY_INFO; ++ ++ + /* Generic state is union of structs above */ + + typedef union acpi_gen_state +@@ -447,6 +479,7 @@ + ACPI_PSCOPE_STATE parse_scope; + ACPI_PKG_STATE pkg; + ACPI_RESULT_VALUES results; ++ ACPI_NOTIFY_INFO notify; + + } ACPI_GENERIC_STATE; + +@@ -471,18 +504,18 @@ + ****************************************************************************/ + + +-#define ACPI_OP_CLASS_MASK 0x1F +-#define ACPI_OP_ARGS_MASK 0x20 +-#define ACPI_OP_TYPE_MASK 0xC0 +- +-#define ACPI_OP_TYPE_OPCODE 0x00 +-#define ACPI_OP_TYPE_ASCII 0x40 +-#define ACPI_OP_TYPE_PREFIX 0x80 +-#define ACPI_OP_TYPE_UNKNOWN 0xC0 +- +-#define ACPI_GET_OP_CLASS(a) ((a)->flags & ACPI_OP_CLASS_MASK) +-#define ACPI_GET_OP_ARGS(a) ((a)->flags & ACPI_OP_ARGS_MASK) +-#define ACPI_GET_OP_TYPE(a) ((a)->flags & ACPI_OP_TYPE_MASK) ++#define ACPI_OP_CLASS_MASK 0x1F ++#define ACPI_OP_ARGS_MASK 0x20 ++#define ACPI_OP_TYPE_MASK 0xC0 ++ ++#define ACPI_OP_TYPE_OPCODE 0x00 ++#define ACPI_OP_TYPE_ASCII 0x40 ++#define ACPI_OP_TYPE_PREFIX 0x80 ++#define ACPI_OP_TYPE_UNKNOWN 0xC0 ++ ++#define ACPI_GET_OP_CLASS(a) ((a)->flags & ACPI_OP_CLASS_MASK) ++#define ACPI_GET_OP_ARGS(a) ((a)->flags & ACPI_OP_ARGS_MASK) ++#define ACPI_GET_OP_TYPE(a) ((a)->flags & ACPI_OP_TYPE_MASK) + + + /* +@@ -572,130 +605,6 @@ + + /***************************************************************************** + * +- * Tree walking typedefs and structs +- * +- ****************************************************************************/ +- +- +-/* +- * Walk state - current state of a parse tree walk. Used for both a leisurely stroll through +- * the tree (for whatever reason), and for control method execution. +- */ +- +-#define NEXT_OP_DOWNWARD 1 +-#define NEXT_OP_UPWARD 2 +- +-#define WALK_NON_METHOD 0 +-#define WALK_METHOD 1 +-#define WALK_METHOD_RESTART 2 +- +-typedef struct acpi_walk_state +-{ +- u8 data_type; /* To differentiate various internal objs */\ +- ACPI_OWNER_ID owner_id; /* Owner of objects created during the walk */ +- u8 last_predicate; /* Result of last predicate */ +- u8 next_op_info; /* Info about Next_op */ +- u8 num_operands; /* Stack pointer for Operands[] array */ +- u8 current_result; /* */ +- +- struct acpi_walk_state *next; /* Next Walk_state in list */ +- ACPI_PARSE_OBJECT *origin; /* Start of walk [Obsolete] */ +- +-/* TBD: Obsolete with removal of WALK procedure ? */ +- ACPI_PARSE_OBJECT *prev_op; /* Last op that was processed */ +- ACPI_PARSE_OBJECT *next_op; /* next op to be processed */ +- +- +- ACPI_GENERIC_STATE *results; /* Stack of accumulated results */ +- ACPI_GENERIC_STATE *control_state; /* List of control states (nested IFs) */ +- ACPI_GENERIC_STATE *scope_info; /* Stack of nested scopes */ +- ACPI_PARSE_STATE *parser_state; /* Current state of parser */ +- u8 *aml_last_while; +- ACPI_OPCODE_INFO *op_info; /* Info on current opcode */ +- ACPI_PARSE_DOWNWARDS descending_callback; +- ACPI_PARSE_UPWARDS ascending_callback; +- +- union acpi_operand_obj *return_desc; /* Return object, if any */ +- union acpi_operand_obj *method_desc; /* Method descriptor if running a method */ +- struct acpi_node *method_node; /* Method Node if running a method */ +- ACPI_PARSE_OBJECT *method_call_op; /* Method_call Op if running a method */ +- struct acpi_node *method_call_node; /* Called method Node*/ +- union acpi_operand_obj *operands[OBJ_NUM_OPERANDS]; /* Operands passed to the interpreter */ +- struct acpi_node arguments[MTH_NUM_ARGS]; /* Control method arguments */ +- struct acpi_node local_variables[MTH_NUM_LOCALS]; /* Control method locals */ +- u32 parse_flags; +- u8 walk_type; +- u8 return_used; +- u16 opcode; /* Current AML opcode */ +- u32 prev_arg_types; +- +- /* Debug support */ +- +- u32 method_breakpoint; +- +- +-} ACPI_WALK_STATE; +- +- +-/* +- * Walk list - head of a tree of walk states. Multiple walk states are created when there +- * are nested control methods executing. +- */ +-typedef struct acpi_walk_list +-{ +- +- ACPI_WALK_STATE *walk_state; +- +-} ACPI_WALK_LIST; +- +- +-/* Info used by Acpi_ps_init_objects */ +- +-typedef struct acpi_init_walk_info +-{ +- u16 method_count; +- u16 op_region_count; +- u16 field_count; +- u16 op_region_init; +- u16 field_init; +- u16 object_count; +- ACPI_TABLE_DESC *table_desc; +- +-} ACPI_INIT_WALK_INFO; +- +- +-/* Info used by TBD */ +- +-typedef struct acpi_device_walk_info +-{ +- u16 device_count; +- u16 num_STA; +- u16 num_INI; +- ACPI_TABLE_DESC *table_desc; +- +-} ACPI_DEVICE_WALK_INFO; +- +- +-/* TBD: [Restructure] Merge with struct above */ +- +-typedef struct acpi_walk_info +-{ +- u32 debug_level; +- u32 owner_id; +- +-} ACPI_WALK_INFO; +- +-typedef struct acpi_get_devices_info +-{ +- WALK_CALLBACK user_function; +- void *context; +- NATIVE_CHAR *hid; +- +-} ACPI_GET_DEVICES_INFO; +- +- +-/***************************************************************************** +- * + * Hardware and PNP + * + ****************************************************************************/ +@@ -703,20 +612,20 @@ + + /* PCI */ + +-#define PCI_ROOT_HID_STRING "PNP0A03" +-#define PCI_ROOT_HID_VALUE 0x030AD041 /* EISAID("PNP0A03") */ ++#define PCI_ROOT_HID_STRING "PNP0A03" ++#define PCI_ROOT_HID_VALUE 0x030AD041 /* EISAID("PNP0A03") */ + + + /* Sleep states */ + +-#define SLWA_DEBUG_LEVEL 4 +-#define GTS_CALL 0 +-#define GTS_WAKE 1 ++#define SLWA_DEBUG_LEVEL 4 ++#define GTS_CALL 0 ++#define GTS_WAKE 1 + + /* Cx States */ + +-#define MAX_CX_STATE_LATENCY 0xFFFFFFFF +-#define MAX_CX_STATES 4 ++#define MAX_CX_STATE_LATENCY 0xFFFFFFFF ++#define MAX_CX_STATES 4 + + + /* +@@ -725,13 +634,13 @@ + * values as they are used in switch statements and offset calculations. + */ + +-#define REGISTER_BLOCK_MASK 0xFF00 /* Register Block Id */ +-#define BIT_IN_REGISTER_MASK 0x00FF /* Bit Id in the Register Block Id */ +-#define BYTE_IN_REGISTER_MASK 0x00FF /* Register Offset in the Register Block */ +- +-#define REGISTER_BLOCK_ID(reg_id) (reg_id & REGISTER_BLOCK_MASK) +-#define REGISTER_BIT_ID(reg_id) (reg_id & BIT_IN_REGISTER_MASK) +-#define REGISTER_OFFSET(reg_id) (reg_id & BYTE_IN_REGISTER_MASK) ++#define REGISTER_BLOCK_MASK 0xFF00 /* Register Block Id */ ++#define BIT_IN_REGISTER_MASK 0x00FF /* Bit Id in the Register Block Id */ ++#define BYTE_IN_REGISTER_MASK 0x00FF /* Register Offset in the Register Block */ ++ ++#define REGISTER_BLOCK_ID(reg_id) (reg_id & REGISTER_BLOCK_MASK) ++#define REGISTER_BIT_ID(reg_id) (reg_id & BIT_IN_REGISTER_MASK) ++#define REGISTER_OFFSET(reg_id) (reg_id & BYTE_IN_REGISTER_MASK) + + /* + * Access Rule +@@ -746,94 +655,94 @@ + /* + * Register Block Id + */ +-#define PM1_STS 0x0100 +-#define PM1_EN 0x0200 +-#define PM1_CONTROL 0x0300 +-#define PM1_a_CONTROL 0x0400 +-#define PM1_b_CONTROL 0x0500 +-#define PM2_CONTROL 0x0600 +-#define PM_TIMER 0x0700 +-#define PROCESSOR_BLOCK 0x0800 +-#define GPE0_STS_BLOCK 0x0900 +-#define GPE0_EN_BLOCK 0x0A00 +-#define GPE1_STS_BLOCK 0x0B00 +-#define GPE1_EN_BLOCK 0x0C00 +-#define SMI_CMD_BLOCK 0x0D00 ++#define PM1_STS 0x0100 ++#define PM1_EN 0x0200 ++#define PM1_CONTROL 0x0300 ++#define PM1_a_CONTROL 0x0400 ++#define PM1_b_CONTROL 0x0500 ++#define PM2_CONTROL 0x0600 ++#define PM_TIMER 0x0700 ++#define PROCESSOR_BLOCK 0x0800 ++#define GPE0_STS_BLOCK 0x0900 ++#define GPE0_EN_BLOCK 0x0A00 ++#define GPE1_STS_BLOCK 0x0B00 ++#define GPE1_EN_BLOCK 0x0C00 ++#define SMI_CMD_BLOCK 0x0D00 + + /* + * Address space bitmasks for mmio or io spaces + */ + +-#define SMI_CMD_ADDRESS_SPACE 0x01 +-#define PM1_BLK_ADDRESS_SPACE 0x02 +-#define PM2_CNT_BLK_ADDRESS_SPACE 0x04 +-#define PM_TMR_BLK_ADDRESS_SPACE 0x08 +-#define GPE0_BLK_ADDRESS_SPACE 0x10 +-#define GPE1_BLK_ADDRESS_SPACE 0x20 ++#define SMI_CMD_ADDRESS_SPACE 0x01 ++#define PM1_BLK_ADDRESS_SPACE 0x02 ++#define PM2_CNT_BLK_ADDRESS_SPACE 0x04 ++#define PM_TMR_BLK_ADDRESS_SPACE 0x08 ++#define GPE0_BLK_ADDRESS_SPACE 0x10 ++#define GPE1_BLK_ADDRESS_SPACE 0x20 + + /* + * Control bit definitions + */ +-#define TMR_STS (PM1_STS | 0x01) +-#define BM_STS (PM1_STS | 0x02) +-#define GBL_STS (PM1_STS | 0x03) +-#define PWRBTN_STS (PM1_STS | 0x04) +-#define SLPBTN_STS (PM1_STS | 0x05) +-#define RTC_STS (PM1_STS | 0x06) +-#define WAK_STS (PM1_STS | 0x07) +- +-#define TMR_EN (PM1_EN | 0x01) +- /* no BM_EN */ +-#define GBL_EN (PM1_EN | 0x03) +-#define PWRBTN_EN (PM1_EN | 0x04) +-#define SLPBTN_EN (PM1_EN | 0x05) +-#define RTC_EN (PM1_EN | 0x06) +-#define WAK_EN (PM1_EN | 0x07) +- +-#define SCI_EN (PM1_CONTROL | 0x01) +-#define BM_RLD (PM1_CONTROL | 0x02) +-#define GBL_RLS (PM1_CONTROL | 0x03) +-#define SLP_TYPE_A (PM1_CONTROL | 0x04) +-#define SLP_TYPE_B (PM1_CONTROL | 0x05) +-#define SLP_EN (PM1_CONTROL | 0x06) +- +-#define ARB_DIS (PM2_CONTROL | 0x01) +- +-#define TMR_VAL (PM_TIMER | 0x01) +- +-#define GPE0_STS (GPE0_STS_BLOCK | 0x01) +-#define GPE0_EN (GPE0_EN_BLOCK | 0x01) +- +-#define GPE1_STS (GPE1_STS_BLOCK | 0x01) +-#define GPE1_EN (GPE1_EN_BLOCK | 0x01) +- +- +-#define TMR_STS_MASK 0x0001 +-#define BM_STS_MASK 0x0010 +-#define GBL_STS_MASK 0x0020 +-#define PWRBTN_STS_MASK 0x0100 +-#define SLPBTN_STS_MASK 0x0200 +-#define RTC_STS_MASK 0x0400 +-#define WAK_STS_MASK 0x8000 +- +-#define ALL_FIXED_STS_BITS (TMR_STS_MASK | BM_STS_MASK | GBL_STS_MASK \ +- | PWRBTN_STS_MASK | SLPBTN_STS_MASK \ +- | RTC_STS_MASK | WAK_STS_MASK) +- +-#define TMR_EN_MASK 0x0001 +-#define GBL_EN_MASK 0x0020 +-#define PWRBTN_EN_MASK 0x0100 +-#define SLPBTN_EN_MASK 0x0200 +-#define RTC_EN_MASK 0x0400 +- +-#define SCI_EN_MASK 0x0001 +-#define BM_RLD_MASK 0x0002 +-#define GBL_RLS_MASK 0x0004 +-#define SLP_TYPE_X_MASK 0x1C00 +-#define SLP_EN_MASK 0x2000 ++#define TMR_STS (PM1_STS | 0x01) ++#define BM_STS (PM1_STS | 0x02) ++#define GBL_STS (PM1_STS | 0x03) ++#define PWRBTN_STS (PM1_STS | 0x04) ++#define SLPBTN_STS (PM1_STS | 0x05) ++#define RTC_STS (PM1_STS | 0x06) ++#define WAK_STS (PM1_STS | 0x07) ++ ++#define TMR_EN (PM1_EN | 0x01) ++ /* no BM_EN */ ++#define GBL_EN (PM1_EN | 0x03) ++#define PWRBTN_EN (PM1_EN | 0x04) ++#define SLPBTN_EN (PM1_EN | 0x05) ++#define RTC_EN (PM1_EN | 0x06) ++#define WAK_EN (PM1_EN | 0x07) ++ ++#define SCI_EN (PM1_CONTROL | 0x01) ++#define BM_RLD (PM1_CONTROL | 0x02) ++#define GBL_RLS (PM1_CONTROL | 0x03) ++#define SLP_TYPE_A (PM1_CONTROL | 0x04) ++#define SLP_TYPE_B (PM1_CONTROL | 0x05) ++#define SLP_EN (PM1_CONTROL | 0x06) ++ ++#define ARB_DIS (PM2_CONTROL | 0x01) ++ ++#define TMR_VAL (PM_TIMER | 0x01) ++ ++#define GPE0_STS (GPE0_STS_BLOCK | 0x01) ++#define GPE0_EN (GPE0_EN_BLOCK | 0x01) ++ ++#define GPE1_STS (GPE1_STS_BLOCK | 0x01) ++#define GPE1_EN (GPE1_EN_BLOCK | 0x01) ++ ++ ++#define TMR_STS_MASK 0x0001 ++#define BM_STS_MASK 0x0010 ++#define GBL_STS_MASK 0x0020 ++#define PWRBTN_STS_MASK 0x0100 ++#define SLPBTN_STS_MASK 0x0200 ++#define RTC_STS_MASK 0x0400 ++#define WAK_STS_MASK 0x8000 ++ ++#define ALL_FIXED_STS_BITS (TMR_STS_MASK | BM_STS_MASK | GBL_STS_MASK \ ++ | PWRBTN_STS_MASK | SLPBTN_STS_MASK \ ++ | RTC_STS_MASK | WAK_STS_MASK) ++ ++#define TMR_EN_MASK 0x0001 ++#define GBL_EN_MASK 0x0020 ++#define PWRBTN_EN_MASK 0x0100 ++#define SLPBTN_EN_MASK 0x0200 ++#define RTC_EN_MASK 0x0400 ++ ++#define SCI_EN_MASK 0x0001 ++#define BM_RLD_MASK 0x0002 ++#define GBL_RLS_MASK 0x0004 ++#define SLP_TYPE_X_MASK 0x1C00 ++#define SLP_EN_MASK 0x2000 + +-#define ARB_DIS_MASK 0x0001 +-#define TMR_VAL_MASK 0xFFFFFFFF ++#define ARB_DIS_MASK 0x0001 ++#define TMR_VAL_MASK 0xFFFFFFFF + + #define GPE0_STS_MASK + #define GPE0_EN_MASK +@@ -842,8 +751,8 @@ + #define GPE1_EN_MASK + + +-#define ACPI_READ 1 +-#define ACPI_WRITE 2 ++#define ACPI_READ 1 ++#define ACPI_WRITE 2 + + + /* Plug and play */ +@@ -881,6 +790,7 @@ + #define DWORD_ADDRESS_SPACE 0x87 + #define WORD_ADDRESS_SPACE 0x88 + #define EXTENDED_IRQ 0x89 ++#define QWORD_ADDRESS_SPACE 0x8A + + /* MUST HAVES */ + +@@ -888,7 +798,7 @@ + + typedef struct + { +- NATIVE_CHAR buffer[DEVICE_ID_LENGTH]; ++ NATIVE_CHAR buffer[DEVICE_ID_LENGTH]; + + } DEVICE_ID; + +@@ -904,9 +814,9 @@ + + #ifdef ACPI_DEBUG + +-#define MEM_MALLOC 0 +-#define MEM_CALLOC 1 +-#define MAX_MODULE_NAME 16 ++#define MEM_MALLOC 0 ++#define MEM_CALLOC 1 ++#define MAX_MODULE_NAME 16 + + typedef struct allocation_info + { +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/acmacros.h linux/drivers/acpi/include/acmacros.h +--- /usr/src/linux/drivers/acpi/include/acmacros.h Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/include/acmacros.h Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Name: acmacros.h - C macros for the entire subsystem. +- * $Revision: 62 $ ++ * $Revision: 65 $ + * + *****************************************************************************/ + +@@ -108,6 +108,7 @@ + #define MOVE_UNALIGNED16_TO_16(d,s) *(u16*)(d) = *(u16*)(s) + #define MOVE_UNALIGNED32_TO_32(d,s) *(u32*)(d) = *(u32*)(s) + #define MOVE_UNALIGNED16_TO_32(d,s) *(u32*)(d) = *(u16*)(s) ++#define MOVE_UNALIGNED64_TO_64(d,s) *(UINT64*)(d) = *(UINT64*)(s) + + #else + /* +@@ -126,6 +127,15 @@ + + #define MOVE_UNALIGNED16_TO_32(d,s) {(*(u32*)(d)) = 0; MOVE_UNALIGNED16_TO_16(d,s);} + ++#define MOVE_UNALIGNED64_TO_64(d,s) {((u8 *)(d))[0] = ((u8 *)(s))[0];\ ++ ((u8 *)(d))[1] = ((u8 *)(s))[1];\ ++ ((u8 *)(d))[2] = ((u8 *)(s))[2];\ ++ ((u8 *)(d))[3] = ((u8 *)(s))[3];\ ++ ((u8 *)(d))[4] = ((u8 *)(s))[4];\ ++ ((u8 *)(d))[5] = ((u8 *)(s))[5];\ ++ ((u8 *)(d))[6] = ((u8 *)(s))[6];\ ++ ((u8 *)(d))[7] = ((u8 *)(s))[7];} ++ + #endif + + +@@ -177,6 +187,8 @@ + #define ROUND_PTR_UP_TO_4(a,b) ((b *)(((NATIVE_UINT)(a) + 3) & ~3)) + #define ROUND_PTR_UP_TO_8(a,b) ((b *)(((NATIVE_UINT)(a) + 7) & ~7)) + ++#define ROUND_BITS_UP_TO_BYTES(a) DIV_8((a) + 7) ++ + #define ROUND_UP_TO_1_k(a) (((a) + 1023) >> 10) + + #ifdef DEBUG_ASSERT +@@ -231,12 +243,12 @@ + + #ifndef _IA16 + #define IS_IN_ACPI_TABLE(a,b) (((u8 *)(a) >= (u8 *)(b + 1)) &&\ +- ((u8 *)(a) < ((u8 *)b + b->length))) ++ ((u8 *)(a) < ((u8 *)b + b->length))) + + #else + #define IS_IN_ACPI_TABLE(a,b) (_segment)(a) == (_segment)(b) &&\ +- (((u8 *)(a) >= (u8 *)(b + 1)) &&\ +- ((u8 *)(a) < ((u8 *)b + b->length))) ++ (((u8 *)(a) >= (u8 *)(b + 1)) &&\ ++ ((u8 *)(a) < ((u8 *)b + b->length))) + #endif + + /* +@@ -290,7 +302,7 @@ + #ifdef ACPI_DEBUG + + #define REPORT_INFO(fp) {_report_info(_THIS_MODULE,__LINE__,_COMPONENT); \ +- debug_print_raw PARAM_LIST(fp);} ++ debug_print_raw PARAM_LIST(fp);} + #define REPORT_ERROR(fp) {_report_error(_THIS_MODULE,__LINE__,_COMPONENT); \ + debug_print_raw PARAM_LIST(fp);} + #define REPORT_WARNING(fp) {_report_warning(_THIS_MODULE,__LINE__,_COMPONENT); \ +@@ -351,7 +363,7 @@ + */ + #define return_VOID {function_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name);return;} + #define return_ACPI_STATUS(s) {function_status_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name,s);return(s);} +-#define return_VALUE(s) {function_value_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name,(ACPI_INTEGER)s);return(s);} ++#define return_VALUE(s) {function_value_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name,s);return(s);} + #define return_PTR(s) {function_ptr_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name,(u8 *)s);return(s);} + + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/acnamesp.h linux/drivers/acpi/include/acnamesp.h +--- /usr/src/linux/drivers/acpi/include/acnamesp.h Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/include/acnamesp.h Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Name: acnamesp.h - Namespace subcomponent prototypes and defines +- * $Revision: 103 $ ++ * $Revision: 104 $ + * + *****************************************************************************/ + +@@ -304,12 +304,6 @@ + ACPI_NAMESPACE_NODE *obj_node, + NATIVE_CHAR *search_for); + +-ACPI_STATUS +-acpi_ns_name_compare ( +- ACPI_HANDLE obj_handle, +- u32 level, +- void *context, +- void **return_value); + + ACPI_STATUS + acpi_ns_get_node ( +@@ -333,13 +327,6 @@ + OBJECT_TYPE_INTERNAL type); + + +-void * +-acpi_ns_compare_value ( +- ACPI_HANDLE obj_handle, +- u32 level, +- void *obj_desc); +- +- + /* + * Namespace searching and entry - nssearch + */ +@@ -383,11 +370,11 @@ + + OBJECT_TYPE_INTERNAL + acpi_ns_get_type ( +- ACPI_HANDLE obj_handle); ++ ACPI_NAMESPACE_NODE *node); + + void * + acpi_ns_get_attached_object ( +- ACPI_HANDLE obj_handle); ++ ACPI_NAMESPACE_NODE *node); + + u32 + acpi_ns_local ( +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/acobject.h linux/drivers/acpi/include/acobject.h +--- /usr/src/linux/drivers/acpi/include/acobject.h Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/include/acobject.h Fri Apr 13 11:57:11 2001 +@@ -2,7 +2,7 @@ + /****************************************************************************** + * + * Name: acobject.h - Definition of ACPI_OPERAND_OBJECT (Internal object only) +- * $Revision: 78 $ ++ * $Revision: 86 $ + * + *****************************************************************************/ + +@@ -58,7 +58,7 @@ + */ + + +-#define ACPI_OBJECT_COMMON_HEADER /* 32-bits plus 8-bit flag */\ ++#define ACPI_OBJECT_COMMON_HEADER /* SIZE/ALIGNMENT: 32-bits plus trailing 8-bit flag */\ + u8 data_type; /* To differentiate various internal objs */\ + u8 type; /* ACPI_OBJECT_TYPE */\ + u16 reference_count; /* For object deletion management */\ +@@ -74,15 +74,15 @@ + /* + * Common bitfield for the field objects + */ +-#define ACPI_COMMON_FIELD_INFO /* Three 32-bit values plus 8*/\ ++#define ACPI_COMMON_FIELD_INFO /* SIZE/ALIGNMENT: 24 bits + three 32-bit values */\ + u8 granularity;\ +- u16 length; \ +- u32 offset; /* Byte offset within containing object */\ +- u8 bit_offset; /* Bit offset within min read/write data unit */\ +- u8 access; /* Access_type */\ +- u8 lock_rule;\ +- u8 update_rule;\ +- u8 access_attribute; ++ u16 bit_length; /* Length of field in bits */\ ++ u32 byte_offset; /* Byte offset within containing object */\ ++ u8 bit_offset; /* Bit offset within min read/write data unit (0-63) */\ ++ u8 access; /* Access_type (Byte_access, Word_access, etc*/\ ++ u8 lock_rule; /* Global Lock: Must Lock = 1 */\ ++ u8 update_rule; /* How neighboring bits are handled */\ ++ u32 value; /* Value to store into the Bank or Index register */ + + + /****************************************************************************** +@@ -121,7 +121,7 @@ + ACPI_OBJECT_COMMON_HEADER + + u32 length; +- NATIVE_CHAR *pointer; /* String value in AML stream or in allocated space */ ++ NATIVE_CHAR *pointer; /* String value in AML stream or in allocated space */ + + } ACPI_OBJECT_STRING; + +@@ -131,7 +131,7 @@ + ACPI_OBJECT_COMMON_HEADER + + u32 length; +- u8 *pointer; /* points to the buffer in allocated space */ ++ u8 *pointer; /* points to the buffer in allocated space */ + + } ACPI_OBJECT_BUFFER; + +@@ -140,27 +140,14 @@ + { + ACPI_OBJECT_COMMON_HEADER + +- u32 count; /* # of elements in package */ ++ u32 count; /* # of elements in package */ + +- union acpi_operand_obj **elements; /* Array of pointers to Acpi_objects */ +- union acpi_operand_obj **next_element; /* used only while initializing */ ++ union acpi_operand_obj **elements; /* Array of pointers to Acpi_objects */ ++ union acpi_operand_obj **next_element; /* used only while initializing */ + + } ACPI_OBJECT_PACKAGE; + + +-typedef struct /* FIELD UNIT */ +-{ +- ACPI_OBJECT_COMMON_HEADER +- +- ACPI_COMMON_FIELD_INFO +- +- union acpi_operand_obj *extra; /* Pointer to executable AML (in field definition) */ +- ACPI_NAMESPACE_NODE *node; /* containing object */ +- union acpi_operand_obj *container; /* Containing object (Buffer) */ +- +-} ACPI_OBJECT_FIELD_UNIT; +- +- + typedef struct /* DEVICE - has handle and notification handler/context */ + { + ACPI_OBJECT_COMMON_HEADER +@@ -175,7 +162,6 @@ + typedef struct /* EVENT */ + { + ACPI_OBJECT_COMMON_HEADER +- + void *semaphore; + + } ACPI_OBJECT_EVENT; +@@ -201,12 +187,16 @@ + } ACPI_OBJECT_METHOD; + + +-typedef struct /* MUTEX */ ++typedef struct acpi_obj_mutex /* MUTEX */ + { + ACPI_OBJECT_COMMON_HEADER + u16 sync_level; ++ u16 acquisition_depth; + + void *semaphore; ++ void *owner; ++ union acpi_operand_obj *prev; /* Link for list of acquired mutexes */ ++ union acpi_operand_obj *next; /* Link for list of acquired mutexes */ + + } ACPI_OBJECT_MUTEX; + +@@ -267,50 +257,71 @@ + + + /* +- * Internal types ++ * Fields. All share a common header/info field. + */ + +- +-typedef struct /* FIELD */ ++typedef struct /* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */ + { + ACPI_OBJECT_COMMON_HEADER +- + ACPI_COMMON_FIELD_INFO ++ union acpi_operand_obj *region_obj; /* Containing Operation Region object */ ++ /* (REGION/BANK fields only) */ ++} ACPI_OBJECT_FIELD_COMMON; + +- union acpi_operand_obj *container; /* Containing object */ + +-} ACPI_OBJECT_FIELD; ++typedef struct /* REGION FIELD */ ++{ ++ ACPI_OBJECT_COMMON_HEADER ++ ACPI_COMMON_FIELD_INFO ++ union acpi_operand_obj *region_obj; /* Containing Op_region object */ ++ ++} ACPI_OBJECT_REGION_FIELD; + + + typedef struct /* BANK FIELD */ + { + ACPI_OBJECT_COMMON_HEADER +- + ACPI_COMMON_FIELD_INFO +- u32 value; /* Value to store into Bank_select */ + +- ACPI_HANDLE bank_select; /* Bank select register */ +- union acpi_operand_obj *container; /* Containing object */ ++ union acpi_operand_obj *region_obj; /* Containing Op_region object */ ++ union acpi_operand_obj *bank_register_obj; /* Bank_select Register object */ + + } ACPI_OBJECT_BANK_FIELD; + + + typedef struct /* INDEX FIELD */ + { ++ ACPI_OBJECT_COMMON_HEADER ++ ACPI_COMMON_FIELD_INFO ++ + /* +- * No container pointer needed since the index and data register definitions +- * will define how to access the respective registers ++ * No "Region_obj" pointer needed since the Index and Data registers ++ * are each field definitions unto themselves. + */ +- ACPI_OBJECT_COMMON_HEADER ++ union acpi_operand_obj *index_obj; /* Index register */ ++ union acpi_operand_obj *data_obj; /* Data register */ ++ ++ ++} ACPI_OBJECT_INDEX_FIELD; ++ + ++/* The Buffer_field is different in that it is part of a Buffer, not an Op_region */ ++ ++typedef struct /* BUFFER FIELD */ ++{ ++ ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_FIELD_INFO +- u32 value; /* Value to store into Index register */ + +- ACPI_HANDLE index; /* Index register */ +- ACPI_HANDLE data; /* Data register */ ++ union acpi_operand_obj *extra; /* Pointer to executable AML (in field definition) */ ++ ACPI_NAMESPACE_NODE *node; /* Parent (containing) object node */ ++ union acpi_operand_obj *buffer_obj; /* Containing Buffer object */ ++ ++} ACPI_OBJECT_BUFFER_FIELD; + +-} ACPI_OBJECT_INDEX_FIELD; + ++/* ++ * Handlers ++ */ + + typedef struct /* NOTIFY HANDLER */ + { +@@ -355,7 +366,7 @@ + ACPI_OBJECT_COMMON_HEADER + + u8 target_type; /* Used for Index_op */ +- u16 op_code; ++ u16 opcode; + u32 offset; /* Used for Arg_op, Local_op, and Index_op */ + + void *object; /* Name_op=>HANDLE to obj, Index_op=>ACPI_OPERAND_OBJECT */ +@@ -400,7 +411,7 @@ + ACPI_OBJECT_STRING string; + ACPI_OBJECT_BUFFER buffer; + ACPI_OBJECT_PACKAGE package; +- ACPI_OBJECT_FIELD_UNIT field_unit; ++ ACPI_OBJECT_BUFFER_FIELD buffer_field; + ACPI_OBJECT_DEVICE device; + ACPI_OBJECT_EVENT event; + ACPI_OBJECT_METHOD method; +@@ -409,7 +420,8 @@ + ACPI_OBJECT_POWER_RESOURCE power_resource; + ACPI_OBJECT_PROCESSOR processor; + ACPI_OBJECT_THERMAL_ZONE thermal_zone; +- ACPI_OBJECT_FIELD field; ++ ACPI_OBJECT_FIELD_COMMON common_field; ++ ACPI_OBJECT_REGION_FIELD field; + ACPI_OBJECT_BANK_FIELD bank_field; + ACPI_OBJECT_INDEX_FIELD index_field; + ACPI_OBJECT_REFERENCE reference; +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/acoutput.h linux/drivers/acpi/include/acoutput.h +--- /usr/src/linux/drivers/acpi/include/acoutput.h Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/include/acoutput.h Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Name: acoutput.h -- debug output +- * $Revision: 70 $ ++ * $Revision: 75 $ + * + *****************************************************************************/ + +@@ -34,34 +34,38 @@ + + /* Component IDs -- used in the global "Debug_layer" */ + +-#define GLOBAL 0x00000001 +-#define COMMON 0x00000002 +-#define PARSER 0x00000004 +-#define DISPATCHER 0x00000008 +-#define INTERPRETER 0x00000010 +-#define NAMESPACE 0x00000020 +-#define RESOURCE_MANAGER 0x00000040 +-#define TABLE_MANAGER 0x00000080 +-#define EVENT_HANDLING 0x00000100 +-#define HARDWARE 0x00000200 +-#define MISCELLANEOUS 0x00000400 +-#define OS_DEPENDENT 0x00000800 +- +-#define BUS_MANAGER 0x00001000 +- +-#define PROCESSOR_CONTROL 0x00002000 +-#define SYSTEM_CONTROL 0x00004000 +-#define THERMAL_CONTROL 0x00008000 +-#define POWER_CONTROL 0x00010000 +- +-#define EMBEDDED_CONTROLLER 0x00020000 +-#define BATTERY 0x00040000 +- +-#define DEBUGGER 0x00100000 +-#define COMPILER 0x00200000 +-#define ALL_COMPONENTS 0x001FFFFF ++#define ACPI_UTILITIES 0x00000001 ++#define ACPI_HARDWARE 0x00000002 ++#define ACPI_EVENTS 0x00000004 ++#define ACPI_TABLES 0x00000008 ++#define ACPI_NAMESPACE 0x00000010 ++#define ACPI_PARSER 0x00000020 ++#define ACPI_DISPATCHER 0x00000040 ++#define ACPI_EXECUTER 0x00000080 ++#define ACPI_RESOURCES 0x00000100 ++#define ACPI_DEVICES 0x00000200 ++#define ACPI_POWER 0x00000400 ++ ++ ++#define ACPI_BUS_MANAGER 0x00001000 ++#define ACPI_POWER_CONTROL 0x00002000 ++#define ACPI_EMBEDDED_CONTROLLER 0x00004000 ++#define ACPI_PROCESSOR_CONTROL 0x00008000 ++#define ACPI_AC_ADAPTER 0x00010000 ++#define ACPI_BATTERY 0x00020000 ++#define ACPI_BUTTON 0x00040000 ++#define ACPI_SYSTEM 0x00080000 ++#define ACPI_THERMAL_ZONE 0x00100000 ++ ++#define ACPI_DEBUGGER 0x01000000 ++#define ACPI_OS_SERVICES 0x02000000 ++#define ACPI_ALL_COMPONENTS 0x01FFFFFF + +-#define COMPONENT_DEFAULT (ALL_COMPONENTS) ++#define ACPI_COMPONENT_DEFAULT (ACPI_ALL_COMPONENTS) ++ ++ ++#define ACPI_COMPILER 0x10000000 ++#define ACPI_TOOLS 0x20000000 + + + /* Exception level -- used in the global "Debug_level" */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/acpi.h linux/drivers/acpi/include/acpi.h +--- /usr/src/linux/drivers/acpi/include/acpi.h Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/include/acpi.h Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Name: acpi.h - Master include file, Publics and external data. +- * $Revision: 50 $ ++ * $Revision: 53 $ + * + *****************************************************************************/ + +@@ -31,20 +31,21 @@ + * We put them here because we don't want to duplicate them + * in the rest of the source code again and again. + */ +-#include "acconfig.h" /* Configuration constants */ +-#include "acenv.h" /* Target environment specific items */ +-#include "actypes.h" /* Fundamental data types */ +-#include "acexcep.h" /* Local exception codes */ +-#include "acmacros.h" /* C macros */ +-#include "actbl.h" /* Acpi table definitions */ +-#include "aclocal.h" /* Internal data types */ +-#include "acoutput.h" /* Error output and Debug macros */ +-#include "acpiosxf.h" /* Interfaces to the Acpi-to-OS layer*/ +-#include "acpixf.h" /* Acpi core external interfaces */ +-#include "acobject.h" /* Acpi internal object */ +-#include "acglobal.h" /* All global variables */ +-#include "achware.h" /* Hardware defines and interfaces */ +-#include "accommon.h" /* Common (global) interfaces */ ++#include "acconfig.h" /* Configuration constants */ ++#include "platform/acenv.h" /* Target environment specific items */ ++#include "actypes.h" /* Fundamental common data types */ ++#include "acexcep.h" /* ACPI exception codes */ ++#include "acmacros.h" /* C macros */ ++#include "actbl.h" /* ACPI table definitions */ ++#include "aclocal.h" /* Internal data types */ ++#include "acoutput.h" /* Error output and Debug macros */ ++#include "acpiosxf.h" /* Interfaces to the ACPI-to-OS layer*/ ++#include "acpixf.h" /* ACPI core subsystem external interfaces */ ++#include "acobject.h" /* ACPI internal object */ ++#include "acstruct.h" /* Common structures */ ++#include "acglobal.h" /* All global variables */ ++#include "achware.h" /* Hardware defines and interfaces */ ++#include "accommon.h" /* Common interfaces */ + + + #endif /* __ACPI_H__ */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/acpiosxf.h linux/drivers/acpi/include/acpiosxf.h +--- /usr/src/linux/drivers/acpi/include/acpiosxf.h Mon Jan 29 10:15:59 2001 ++++ linux/drivers/acpi/include/acpiosxf.h Fri Apr 13 11:57:11 2001 +@@ -1,9 +1,9 @@ + + /****************************************************************************** + * +- * Name: acpiosxf.h - All interfaces to the OS-dependent layer. These +- * interfaces must be implemented by the OS-dependent +- * front-end to the ACPI subsystem. ++ * Name: acpiosxf.h - All interfaces to the OS Services Layer (OSL). These ++ * interfaces must be implemented by OSL to interface the ++ * ACPI components to the host operating system. + * + *****************************************************************************/ + +@@ -26,26 +26,26 @@ + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +-#ifndef __ACPIOSD_H__ +-#define __ACPIOSD_H__ ++#ifndef __ACPIOSXF_H__ ++#define __ACPIOSXF_H__ + +-#include "acenv.h" ++#include "platform/acenv.h" + #include "actypes.h" + + + /* Priorities for Acpi_os_queue_for_execution */ + +-#define OSD_PRIORITY_GPE 1 +-#define OSD_PRIORITY_HIGH 2 +-#define OSD_PRIORITY_MED 3 +-#define OSD_PRIORITY_LO 4 ++#define OSD_PRIORITY_GPE 1 ++#define OSD_PRIORITY_HIGH 2 ++#define OSD_PRIORITY_MED 3 ++#define OSD_PRIORITY_LO 4 + +-#define ACPI_NO_UNIT_LIMIT ((u32) -1) +-#define ACPI_MUTEX_SEM 1 ++#define ACPI_NO_UNIT_LIMIT ((u32) -1) ++#define ACPI_MUTEX_SEM 1 + + + /* +- * Types specific to the OS-dependent layer interfaces ++ * Types specific to the OS service interfaces + */ + + typedef +@@ -58,7 +58,7 @@ + + + /* +- * Initialization and shutdown primitives (Optional) ++ * OSL Initialization and shutdown primitives + */ + + ACPI_STATUS +@@ -69,6 +69,7 @@ + acpi_os_terminate ( + void); + ++ + /* + * Synchronization primitives + */ +@@ -94,6 +95,7 @@ + ACPI_HANDLE handle, + u32 units); + ++ + /* + * Memory allocation and mapping + */ +@@ -126,6 +128,7 @@ + void *logical_address, + ACPI_PHYSICAL_ADDRESS *physical_address); + ++ + /* + * Interrupt handlers + */ +@@ -143,9 +146,13 @@ + + + /* +- * Scheduling ++ * Threads and Scheduling + */ + ++u32 ++acpi_os_get_thread_id ( ++ void); ++ + ACPI_STATUS + acpi_os_queue_for_execution ( + u32 priority, +@@ -161,6 +168,7 @@ + acpi_os_sleep_usec ( + u32 microseconds); + ++ + /* + * Platform/Hardware independent I/O interfaces + */ +@@ -193,6 +201,7 @@ + ACPI_IO_ADDRESS out_port, + u32 value); + ++ + /* + * Platform/Hardware independent physical memory interfaces + */ +@@ -307,6 +316,7 @@ + const NATIVE_CHAR *format, + va_list args); + ++ + /* + * Debug input + */ +@@ -328,4 +338,4 @@ + NATIVE_CHAR *message); + + +-#endif /* __ACPIOSD_H__ */ ++#endif /* __ACPIOSXF_H__ */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/acpixf.h linux/drivers/acpi/include/acpixf.h +--- /usr/src/linux/drivers/acpi/include/acpixf.h Mon Jan 29 10:15:59 2001 ++++ linux/drivers/acpi/include/acpixf.h Fri Apr 13 11:57:11 2001 +@@ -30,6 +30,7 @@ + #include "actypes.h" + #include "actbl.h" + ++ + /* + * Global interfaces + */ +@@ -65,6 +66,23 @@ + + + /* ++ * ACPI Memory manager ++ */ ++ ++void * ++acpi_allocate ( ++ u32 size); ++ ++void * ++acpi_callocate ( ++ u32 size); ++ ++void ++acpi_free ( ++ void *address); ++ ++ ++/* + * ACPI table manipulation interfaces + */ + +@@ -165,7 +183,7 @@ + + + /* +- * Acpi_event handler interfaces ++ * Event handler interfaces + */ + + ACPI_STATUS +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/acresrc.h linux/drivers/acpi/include/acresrc.h +--- /usr/src/linux/drivers/acpi/include/acresrc.h Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/include/acresrc.h Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Name: acresrc.h - Resource Manager function prototypes +- * $Revision: 22 $ ++ * $Revision: 23 $ + * + *****************************************************************************/ + +@@ -191,6 +191,19 @@ + + ACPI_STATUS + acpi_rs_address32_stream ( ++ RESOURCE *linked_list, ++ u8 **output_buffer, ++ u32 *bytes_consumed); ++ ++ACPI_STATUS ++acpi_rs_address64_resource ( ++ u8 *byte_stream_buffer, ++ u32 *bytes_consumed, ++ u8 **output_buffer, ++ u32 *structure_size); ++ ++ACPI_STATUS ++acpi_rs_address64_stream ( + RESOURCE *linked_list, + u8 **output_buffer, + u32 *bytes_consumed); +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/acstruct.h linux/drivers/acpi/include/acstruct.h +--- /usr/src/linux/drivers/acpi/include/acstruct.h Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/include/acstruct.h Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,157 @@ ++/****************************************************************************** ++ * ++ * Name: acstruct.h - Internal structs ++ * $Revision: 2 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * 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 ++ */ ++ ++#ifndef __ACSTRUCT_H__ ++#define __ACSTRUCT_H__ ++ ++ ++/***************************************************************************** ++ * ++ * Tree walking typedefs and structs ++ * ++ ****************************************************************************/ ++ ++ ++/* ++ * Walk state - current state of a parse tree walk. Used for both a leisurely stroll through ++ * the tree (for whatever reason), and for control method execution. ++ */ ++ ++#define NEXT_OP_DOWNWARD 1 ++#define NEXT_OP_UPWARD 2 ++ ++#define WALK_NON_METHOD 0 ++#define WALK_METHOD 1 ++#define WALK_METHOD_RESTART 2 ++ ++typedef struct acpi_walk_state ++{ ++ u8 data_type; /* To differentiate various internal objs */\ ++ ACPI_OWNER_ID owner_id; /* Owner of objects created during the walk */ ++ u8 last_predicate; /* Result of last predicate */ ++ u8 next_op_info; /* Info about Next_op */ ++ u8 num_operands; /* Stack pointer for Operands[] array */ ++ u8 current_result; /* */ ++ ++ struct acpi_walk_state *next; /* Next Walk_state in list */ ++ ACPI_PARSE_OBJECT *origin; /* Start of walk [Obsolete] */ ++ ++/* TBD: Obsolete with removal of WALK procedure ? */ ++ ACPI_PARSE_OBJECT *prev_op; /* Last op that was processed */ ++ ACPI_PARSE_OBJECT *next_op; /* next op to be processed */ ++ ++ ++ ACPI_GENERIC_STATE *results; /* Stack of accumulated results */ ++ ACPI_GENERIC_STATE *control_state; /* List of control states (nested IFs) */ ++ ACPI_GENERIC_STATE *scope_info; /* Stack of nested scopes */ ++ ACPI_PARSE_STATE *parser_state; /* Current state of parser */ ++ u8 *aml_last_while; ++ ACPI_OPCODE_INFO *op_info; /* Info on current opcode */ ++ ACPI_PARSE_DOWNWARDS descending_callback; ++ ACPI_PARSE_UPWARDS ascending_callback; ++ ++ union acpi_operand_obj *return_desc; /* Return object, if any */ ++ union acpi_operand_obj *method_desc; /* Method descriptor if running a method */ ++ struct acpi_node *method_node; /* Method Node if running a method */ ++ ACPI_PARSE_OBJECT *method_call_op; /* Method_call Op if running a method */ ++ struct acpi_node *method_call_node; /* Called method Node*/ ++ union acpi_operand_obj *operands[OBJ_NUM_OPERANDS]; /* Operands passed to the interpreter */ ++ struct acpi_node arguments[MTH_NUM_ARGS]; /* Control method arguments */ ++ struct acpi_node local_variables[MTH_NUM_LOCALS]; /* Control method locals */ ++ struct acpi_walk_list *walk_list; ++ u32 parse_flags; ++ u8 walk_type; ++ u8 return_used; ++ u16 opcode; /* Current AML opcode */ ++ u32 prev_arg_types; ++ u16 current_sync_level; /* Mutex Sync (nested acquire) level */ ++ ++ /* Debug support */ ++ ++ u32 method_breakpoint; ++ ++ ++} ACPI_WALK_STATE; ++ ++ ++/* ++ * Walk list - head of a tree of walk states. Multiple walk states are created when there ++ * are nested control methods executing. ++ */ ++typedef struct acpi_walk_list ++{ ++ ++ ACPI_WALK_STATE *walk_state; ++ ACPI_OBJECT_MUTEX acquired_mutex_list; /* List of all currently acquired mutexes */ ++ ++} ACPI_WALK_LIST; ++ ++ ++/* Info used by Acpi_ps_init_objects */ ++ ++typedef struct acpi_init_walk_info ++{ ++ u16 method_count; ++ u16 op_region_count; ++ u16 field_count; ++ u16 op_region_init; ++ u16 field_init; ++ u16 object_count; ++ ACPI_TABLE_DESC *table_desc; ++ ++} ACPI_INIT_WALK_INFO; ++ ++ ++/* Info used by TBD */ ++ ++typedef struct acpi_device_walk_info ++{ ++ u16 device_count; ++ u16 num_STA; ++ u16 num_INI; ++ ACPI_TABLE_DESC *table_desc; ++ ++} ACPI_DEVICE_WALK_INFO; ++ ++ ++/* TBD: [Restructure] Merge with struct above */ ++ ++typedef struct acpi_walk_info ++{ ++ u32 debug_level; ++ u32 owner_id; ++ ++} ACPI_WALK_INFO; ++ ++typedef struct acpi_get_devices_info ++{ ++ WALK_CALLBACK user_function; ++ void *context; ++ NATIVE_CHAR *hid; ++ ++} ACPI_GET_DEVICES_INFO; ++ ++ ++#endif +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/actbl.h linux/drivers/acpi/include/actbl.h +--- /usr/src/linux/drivers/acpi/include/actbl.h Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/include/actbl.h Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Name: actbl.h - Table data structures defined in ACPI specification +- * $Revision: 45 $ ++ * $Revision: 46 $ + * + *****************************************************************************/ + +@@ -140,7 +140,7 @@ + u8 processor_apic_id; /* ACPI processor id */ + u8 local_apic_id; /* processor's local APIC id */ + u32 processor_enabled: 1; /* Processor is usable if set */ +- u32 reserved1 : 32; ++ u32 reserved1 : 31; + + } PROCESSOR_APIC; + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/actbl2.h linux/drivers/acpi/include/actbl2.h +--- /usr/src/linux/drivers/acpi/include/actbl2.h Mon Jan 29 10:15:59 2001 ++++ linux/drivers/acpi/include/actbl2.h Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Name: actbl2.h - ACPI Specification Revision 2.0 Tables +- * $Revision: 21 $ ++ * $Revision: 23 $ + * + *****************************************************************************/ + +@@ -26,159 +26,156 @@ + #ifndef __ACTBL2_H__ + #define __ACTBL2_H__ + +-/**************************************/ +-/* Prefered Power Management Profiles */ +-/**************************************/ +-#define PM_UNSPECIFIED 0 +-#define PM_DESKTOP 1 +-#define PM_MOBILE 2 +-#define PM_WORKSTATION 3 +-#define PM_ENTERPRISE_SERVER 4 +-#define PM_SOHO_SERVER 5 +-#define PM_APPLIANCE_PC 6 +- +-/*********************************************/ +-/* ACPI Boot Arch Flags, See spec Table 5-10 */ +-/*********************************************/ +-#define BAF_LEGACY_DEVICES 0x0001 +-#define BAF_8042_KEYBOARD_CONTROLLER 0x0002 ++/* ++ * Prefered Power Management Profiles ++ */ ++#define PM_UNSPECIFIED 0 ++#define PM_DESKTOP 1 ++#define PM_MOBILE 2 ++#define PM_WORKSTATION 3 ++#define PM_ENTERPRISE_SERVER 4 ++#define PM_SOHO_SERVER 5 ++#define PM_APPLIANCE_PC 6 ++ ++/* ++ * ACPI Boot Arch Flags ++ */ ++#define BAF_LEGACY_DEVICES 0x0001 ++#define BAF_8042_KEYBOARD_CONTROLLER 0x0002 ++ ++#define FADT2_REVISION_ID 3 + +-#define FADT2_REVISION_ID 3 + + #pragma pack(1) + +-/*************************************/ +-/* ACPI Specification Rev 2.0 for */ +-/* the Root System Description Table */ +-/*************************************/ ++/* ++ * ACPI Specification Rev 2.0 for the Root System Description Table ++ */ + typedef struct + { +- ACPI_TABLE_HEADER header; /* Table header */ +- u32 table_offset_entry [1]; /* Array of pointers to */ +- /* other tables' headers */ ++ ACPI_TABLE_HEADER header; /* Table header */ ++ u32 table_offset_entry [1]; /* Array of pointers to */ ++ /* other tables' headers */ + } RSDT_DESCRIPTOR_REV2; + + +-/********************************************/ +-/* ACPI Specification Rev 2.0 for the */ +-/* Extended System Description Table (XSDT) */ +-/********************************************/ ++/* ++ * ACPI Specification Rev 2.0 for the Extended System Description Table (XSDT) ++ */ + typedef struct + { +- ACPI_TABLE_HEADER header; /* Table header */ +- UINT64 table_offset_entry [1]; /* Array of pointers to */ +- /* other tables' headers */ ++ ACPI_TABLE_HEADER header; /* Table header */ ++ UINT64 table_offset_entry [1]; /* Array of pointers to */ ++ /* other tables' headers */ + } XSDT_DESCRIPTOR_REV2; + +-/***************************************/ +-/* ACPI Specification Rev 2.0 for */ +-/* the Firmware ACPI Control Structure */ +-/***************************************/ ++ ++/* ++ * ACPI Specification Rev 2.0 for the Firmware ACPI Control Structure ++ */ + typedef struct + { +- NATIVE_CHAR signature[4]; /* signature "FACS" */ +- u32 length; /* length of structure, in bytes */ +- u32 hardware_signature; /* hardware configuration signature */ +- u32 firmware_waking_vector; /* 32bit physical address of the Firmware Waking Vector. */ +- u32 global_lock; /* Global Lock used to synchronize access to shared hardware resources */ +- u32 S4_bios_f : 1; /* Indicates if S4_bIOS support is present */ +- u32 reserved1 : 31; /* must be 0 */ +- UINT64 Xfirmware_waking_vector; /* 64bit physical address of the Firmware Waking Vector. */ +- u8 version; /* Version of this table */ +- u8 reserved3 [31]; /* reserved - must be zero */ ++ NATIVE_CHAR signature[4]; /* signature "FACS" */ ++ u32 length; /* length of structure, in bytes */ ++ u32 hardware_signature; /* hardware configuration signature */ ++ u32 firmware_waking_vector; /* 32bit physical address of the Firmware Waking Vector. */ ++ u32 global_lock; /* Global Lock used to synchronize access to shared hardware resources */ ++ u32 S4_bios_f : 1; /* Indicates if S4_bIOS support is present */ ++ u32 reserved1 : 31; /* must be 0 */ ++ UINT64 Xfirmware_waking_vector; /* 64bit physical address of the Firmware Waking Vector. */ ++ u8 version; /* Version of this table */ ++ u8 reserved3 [31]; /* reserved - must be zero */ + + } FACS_DESCRIPTOR_REV2; + + +-/***************************************/ +-/* ACPI Specification Rev 2.0 for */ +-/* the Generic Address Structure (GAS) */ +-/***************************************/ ++/* ++ * ACPI Specification Rev 2.0 for the Generic Address Structure (GAS) ++ */ + typedef struct + { +- u8 address_space_id; /* Address space where struct or register exists. */ +- u8 register_bit_width; /* Size in bits of given register */ +- u8 register_bit_offset; /* Bit offset within the register */ +- u8 reserved; /* Must be 0 */ +- UINT64 address; /* 64-bit address of struct or register */ +- +-} ACPI_GAS; ++ u8 address_space_id; /* Address space where struct or register exists. */ ++ u8 register_bit_width; /* Size in bits of given register */ ++ u8 register_bit_offset; /* Bit offset within the register */ ++ u8 reserved; /* Must be 0 */ ++ UINT64 address; /* 64-bit address of struct or register */ ++ ++} ACPI_GENERIC_ADDRESS; + + +-/************************************/ +-/* ACPI Specification Rev 2.0 for */ +-/* the Fixed ACPI Description Table */ +-/************************************/ ++/* ++ * ACPI Specification Rev 2.0 for the Fixed ACPI Description Table ++ */ + typedef struct + { +- ACPI_TABLE_HEADER header; /* table header */ +- u32 V1_firmware_ctrl; /* 32-bit physical address of FACS */ +- u32 V1_dsdt; /* 32-bit physical address of DSDT */ +- u8 reserved1; /* System Interrupt Model isn't used in ACPI 2.0*/ +- u8 prefer_PM_profile; /* Conveys preferred power management profile to OSPM. */ +- u16 sci_int; /* System vector of SCI interrupt */ +- u32 smi_cmd; /* Port address of SMI command port */ +- u8 acpi_enable; /* value to write to smi_cmd to enable ACPI */ +- u8 acpi_disable; /* value to write to smi_cmd to disable ACPI */ +- u8 S4_bios_req; /* Value to write to SMI CMD to enter S4_bIOS state */ +- u8 pstate_cnt; /* processor performance state control*/ +- u32 V1_pm1a_evt_blk; /* Port address of Power Mgt 1a Acpi_event Reg Blk */ +- u32 V1_pm1b_evt_blk; /* Port address of Power Mgt 1b Acpi_event Reg Blk */ +- u32 V1_pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ +- u32 V1_pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ +- u32 V1_pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ +- u32 V1_pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ +- u32 V1_gpe0blk; /* Port addr of General Purpose Acpi_event 0 Reg Blk */ +- u32 V1_gpe1_blk; /* Port addr of General Purpose Acpi_event 1 Reg Blk */ +- u8 pm1_evt_len; /* Byte Length of ports at pm1_x_evt_blk */ +- u8 pm1_cnt_len; /* Byte Length of ports at pm1_x_cnt_blk */ +- u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ +- u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */ +- u8 gpe0blk_len; /* Byte Length of ports at gpe0_blk */ +- u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ +- u8 gpe1_base; /* offset in gpe model where gpe1 events start */ +- u8 cst_cnt; /* Support for the _CST object and C States change notification.*/ +- u16 plvl2_lat; /* worst case HW latency to enter/exit C2 state */ +- u16 plvl3_lat; /* worst case HW latency to enter/exit C3 state */ +- u16 flush_size; /* number of flush strides that need to be read */ +- u16 flush_stride; /* Processor's memory cache line width, in bytes */ +- u8 duty_offset; /* Processor_’s duty cycle index in processor's P_CNT reg*/ +- u8 duty_width; /* Processor_’s duty cycle value bit width in P_CNT register.*/ +- u8 day_alrm; /* index to day-of-month alarm in RTC CMOS RAM */ +- u8 mon_alrm; /* index to month-of-year alarm in RTC CMOS RAM */ +- u8 century; /* index to century in RTC CMOS RAM */ +- u16 iapc_boot_arch; /* IA-PC Boot Architecture Flags. See Table 5-10 for description*/ +- u8 reserved2; /* reserved */ +- u32 wb_invd : 1; /* wbinvd instruction works properly */ +- u32 wb_invd_flush : 1; /* wbinvd flushes but does not invalidate */ +- u32 proc_c1 : 1; /* all processors support C1 state */ +- u32 plvl2_up : 1; /* C2 state works on MP system */ +- u32 pwr_button : 1; /* Power button is handled as a generic feature */ +- u32 sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */ +- u32 fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */ +- u32 rtcs4 : 1; /* RTC wakeup stat not possible from S4 */ +- u32 tmr_val_ext : 1; /* tmr_val is 32 bits */ +- u32 dock_cap : 1; /* Supports Docking */ +- u32 reset_reg_sup : 1; /* Indicates system supports system reset via the FADT RESET_REG*/ +- u32 sealed_case : 1; /* Indicates system has no internal expansion capabilities and case is sealed. */ +- u32 headless : 1; /* Indicates system does not have local video capabilities or local input devices.*/ +- u32 cpu_sw_sleep : 1; /* Indicates to OSPM that a processor native instruction */ +- /* must be executed after writing the SLP_TYPx register. */ +- u32 reserved6 : 18; /* reserved - must be zero */ +- +- ACPI_GAS reset_register; /* Reset register address in GAS format */ +- u8 reset_value; /* Value to write to the Reset_register port to reset the system. */ +- u8 reserved7[3]; /* These three bytes must be zero */ +- UINT64 Xfirmware_ctrl; /* 64-bit physical address of FACS */ +- UINT64 Xdsdt; /* 64-bit physical address of DSDT */ +- ACPI_GAS Xpm1a_evt_blk; /* Extended Power Mgt 1a Acpi_event Reg Blk address */ +- ACPI_GAS Xpm1b_evt_blk; /* Extended Power Mgt 1b Acpi_event Reg Blk address */ +- ACPI_GAS Xpm1a_cnt_blk; /* Extended Power Mgt 1a Control Reg Blk address */ +- ACPI_GAS Xpm1b_cnt_blk; /* Extended Power Mgt 1b Control Reg Blk address */ +- ACPI_GAS Xpm2_cnt_blk; /* Extended Power Mgt 2 Control Reg Blk address */ +- ACPI_GAS Xpm_tmr_blk; /* Extended Power Mgt Timer Ctrl Reg Blk address */ +- ACPI_GAS Xgpe0blk; /* Extended General Purpose Acpi_event 0 Reg Blk address */ +- ACPI_GAS Xgpe1_blk; /* Extended General Purpose Acpi_event 1 Reg Blk address */ ++ ACPI_TABLE_HEADER header; /* table header */ ++ u32 V1_firmware_ctrl; /* 32-bit physical address of FACS */ ++ u32 V1_dsdt; /* 32-bit physical address of DSDT */ ++ u8 reserved1; /* System Interrupt Model isn't used in ACPI 2.0*/ ++ u8 prefer_PM_profile; /* Conveys preferred power management profile to OSPM. */ ++ u16 sci_int; /* System vector of SCI interrupt */ ++ u32 smi_cmd; /* Port address of SMI command port */ ++ u8 acpi_enable; /* value to write to smi_cmd to enable ACPI */ ++ u8 acpi_disable; /* value to write to smi_cmd to disable ACPI */ ++ u8 S4_bios_req; /* Value to write to SMI CMD to enter S4_bIOS state */ ++ u8 pstate_cnt; /* processor performance state control*/ ++ u32 V1_pm1a_evt_blk; /* Port address of Power Mgt 1a Acpi_event Reg Blk */ ++ u32 V1_pm1b_evt_blk; /* Port address of Power Mgt 1b Acpi_event Reg Blk */ ++ u32 V1_pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ ++ u32 V1_pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ ++ u32 V1_pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ ++ u32 V1_pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ ++ u32 V1_gpe0blk; /* Port addr of General Purpose Acpi_event 0 Reg Blk */ ++ u32 V1_gpe1_blk; /* Port addr of General Purpose Acpi_event 1 Reg Blk */ ++ u8 pm1_evt_len; /* Byte Length of ports at pm1_x_evt_blk */ ++ u8 pm1_cnt_len; /* Byte Length of ports at pm1_x_cnt_blk */ ++ u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ ++ u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */ ++ u8 gpe0blk_len; /* Byte Length of ports at gpe0_blk */ ++ u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ ++ u8 gpe1_base; /* offset in gpe model where gpe1 events start */ ++ u8 cst_cnt; /* Support for the _CST object and C States change notification.*/ ++ u16 plvl2_lat; /* worst case HW latency to enter/exit C2 state */ ++ u16 plvl3_lat; /* worst case HW latency to enter/exit C3 state */ ++ u16 flush_size; /* number of flush strides that need to be read */ ++ u16 flush_stride; /* Processor's memory cache line width, in bytes */ ++ u8 duty_offset; /* Processor_’s duty cycle index in processor's P_CNT reg*/ ++ u8 duty_width; /* Processor_’s duty cycle value bit width in P_CNT register.*/ ++ u8 day_alrm; /* index to day-of-month alarm in RTC CMOS RAM */ ++ u8 mon_alrm; /* index to month-of-year alarm in RTC CMOS RAM */ ++ u8 century; /* index to century in RTC CMOS RAM */ ++ u16 iapc_boot_arch; /* IA-PC Boot Architecture Flags. See Table 5-10 for description*/ ++ u8 reserved2; /* reserved */ ++ u32 wb_invd : 1; /* wbinvd instruction works properly */ ++ u32 wb_invd_flush : 1; /* wbinvd flushes but does not invalidate */ ++ u32 proc_c1 : 1; /* all processors support C1 state */ ++ u32 plvl2_up : 1; /* C2 state works on MP system */ ++ u32 pwr_button : 1; /* Power button is handled as a generic feature */ ++ u32 sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */ ++ u32 fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */ ++ u32 rtcs4 : 1; /* RTC wakeup stat not possible from S4 */ ++ u32 tmr_val_ext : 1; /* tmr_val is 32 bits */ ++ u32 dock_cap : 1; /* Supports Docking */ ++ u32 reset_reg_sup : 1; /* Indicates system supports system reset via the FADT RESET_REG*/ ++ u32 sealed_case : 1; /* Indicates system has no internal expansion capabilities and case is sealed. */ ++ u32 headless : 1; /* Indicates system does not have local video capabilities or local input devices.*/ ++ u32 cpu_sw_sleep : 1; /* Indicates to OSPM that a processor native instruction */ ++ /* must be executed after writing the SLP_TYPx register. */ ++ u32 reserved6 : 18; /* reserved - must be zero */ ++ ++ ACPI_GENERIC_ADDRESS reset_register; /* Reset register address in GAS format */ ++ u8 reset_value; /* Value to write to the Reset_register port to reset the system. */ ++ u8 reserved7[3]; /* These three bytes must be zero */ ++ UINT64 Xfirmware_ctrl; /* 64-bit physical address of FACS */ ++ UINT64 Xdsdt; /* 64-bit physical address of DSDT */ ++ ACPI_GENERIC_ADDRESS Xpm1a_evt_blk; /* Extended Power Mgt 1a Acpi_event Reg Blk address */ ++ ACPI_GENERIC_ADDRESS Xpm1b_evt_blk; /* Extended Power Mgt 1b Acpi_event Reg Blk address */ ++ ACPI_GENERIC_ADDRESS Xpm1a_cnt_blk; /* Extended Power Mgt 1a Control Reg Blk address */ ++ ACPI_GENERIC_ADDRESS Xpm1b_cnt_blk; /* Extended Power Mgt 1b Control Reg Blk address */ ++ ACPI_GENERIC_ADDRESS Xpm2_cnt_blk; /* Extended Power Mgt 2 Control Reg Blk address */ ++ ACPI_GENERIC_ADDRESS Xpm_tmr_blk; /* Extended Power Mgt Timer Ctrl Reg Blk address */ ++ ACPI_GENERIC_ADDRESS Xgpe0blk; /* Extended General Purpose Acpi_event 0 Reg Blk address */ ++ ACPI_GENERIC_ADDRESS Xgpe1_blk; /* Extended General Purpose Acpi_event 1 Reg Blk address */ + + } FADT_DESCRIPTOR_REV2; + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/actypes.h linux/drivers/acpi/include/actypes.h +--- /usr/src/linux/drivers/acpi/include/actypes.h Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/include/actypes.h Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Name: actypes.h - Common data types for the entire ACPI subsystem +- * $Revision: 165 $ ++ * $Revision: 174 $ + * + *****************************************************************************/ + +@@ -231,6 +231,10 @@ + + #define ACPI_ROOT_OBJECT (ACPI_HANDLE)(-1) + ++ ++/* ++ * Initialization sequence ++ */ + #define ACPI_FULL_INITIALIZATION 0x00 + #define ACPI_NO_ADDRESS_SPACE_INIT 0x01 + #define ACPI_NO_HARDWARE_INIT 0x02 +@@ -241,7 +245,7 @@ + + + /* +- * Sleep state constants ++ * System states + */ + #define ACPI_STATE_S0 (u8) 0 + #define ACPI_STATE_S1 (u8) 1 +@@ -252,6 +256,19 @@ + /* let's pretend S4_bIOS didn't exist for now. ASG */ + #define ACPI_STATE_S4_bIOS (u8) 6 + #define ACPI_S_STATES_MAX ACPI_STATE_S5 ++#define ACPI_S_STATE_COUNT 6 ++ ++/* ++ * Device power states ++ */ ++#define ACPI_STATE_D0 (u8) 0 ++#define ACPI_STATE_D1 (u8) 1 ++#define ACPI_STATE_D2 (u8) 2 ++#define ACPI_STATE_D3 (u8) 3 ++#define ACPI_D_STATES_MAX ACPI_STATE_D3 ++#define ACPI_D_STATE_COUNT 4 ++ ++#define ACPI_STATE_UNKNOWN (u8) 0xFF + + + /* +@@ -284,34 +301,6 @@ + typedef u32 ACPI_OBJECT_TYPE; + typedef u8 OBJECT_TYPE_INTERNAL; + +-#define ACPI_BTYPE_ANY 0x00000000 +-#define ACPI_BTYPE_INTEGER 0x00000001 +-#define ACPI_BTYPE_STRING 0x00000002 +-#define ACPI_BTYPE_BUFFER 0x00000004 +-#define ACPI_BTYPE_PACKAGE 0x00000008 +-#define ACPI_BTYPE_FIELD_UNIT 0x00000010 +-#define ACPI_BTYPE_DEVICE 0x00000020 +-#define ACPI_BTYPE_EVENT 0x00000040 +-#define ACPI_BTYPE_METHOD 0x00000080 +-#define ACPI_BTYPE_MUTEX 0x00000100 +-#define ACPI_BTYPE_REGION 0x00000200 +-#define ACPI_BTYPE_POWER 0x00000400 +-#define ACPI_BTYPE_PROCESSOR 0x00000800 +-#define ACPI_BTYPE_THERMAL 0x00001000 +-#define ACPI_BTYPE_BUFFER_FIELD 0x00002000 +-#define ACPI_BTYPE_DDB_HANDLE 0x00004000 +-#define ACPI_BTYPE_DEBUG_OBJECT 0x00008000 +-#define ACPI_BTYPE_REFERENCE 0x00010000 +-#define ACPI_BTYPE_RESOURCE 0x00020000 +- +-#define ACPI_BTYPE_COMPUTE_DATA (ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING | ACPI_BTYPE_BUFFER) +- +-#define ACPI_BTYPE_DATA (ACPI_BTYPE_COMPUTE_DATA | ACPI_BTYPE_PACKAGE) +-#define ACPI_BTYPE_DATA_REFERENCE (ACPI_BTYPE_DATA | ACPI_BTYPE_REFERENCE | ACPI_BTYPE_DDB_HANDLE) +-#define ACPI_BTYPE_DEVICE_OBJECTS (ACPI_BTYPE_DEVICE | ACPI_BTYPE_THERMAL | ACPI_BTYPE_PROCESSOR) +-#define ACPI_BTYPE_OBJECTS_AND_REFS 0x00017FFF /* ARG or LOCAL */ +-#define ACPI_BTYPE_ALL_OBJECTS 0x00007FFF +- + + #define ACPI_TYPE_ANY 0 /* 0x00 */ + #define ACPI_TYPE_INTEGER 1 /* 0x01 Byte/Word/Dword/Zero/One/Ones */ +@@ -342,7 +331,7 @@ + */ + #define INTERNAL_TYPE_BEGIN 17 + +-#define INTERNAL_TYPE_DEF_FIELD 17 /* 0x11 */ ++#define INTERNAL_TYPE_REGION_FIELD 17 /* 0x11 */ + #define INTERNAL_TYPE_BANK_FIELD 18 /* 0x12 */ + #define INTERNAL_TYPE_INDEX_FIELD 19 /* 0x13 */ + #define INTERNAL_TYPE_REFERENCE 20 /* 0x14 Arg#, Local#, Name, Debug; used only in descriptors */ +@@ -356,12 +345,12 @@ + + /* These are pseudo-types because there are never any namespace nodes with these types */ + +-#define INTERNAL_TYPE_DEF_FIELD_DEFN 25 /* 0x19 Name, Byte_const, multiple Field_element */ ++#define INTERNAL_TYPE_FIELD_DEFN 25 /* 0x19 Name, Byte_const, multiple Field_element */ + #define INTERNAL_TYPE_BANK_FIELD_DEFN 26 /* 0x1A 2 Name,DWord_const,Byte_const,multi Field_element */ + #define INTERNAL_TYPE_INDEX_FIELD_DEFN 27 /* 0x1B 2 Name, Byte_const, multiple Field_element */ +-#define INTERNAL_TYPE_IF 28 /* 0x1C Op_code, multiple Code */ +-#define INTERNAL_TYPE_ELSE 29 /* 0x1D multiple Code */ +-#define INTERNAL_TYPE_WHILE 30 /* 0x1E Op_code, multiple Code */ ++#define INTERNAL_TYPE_IF 28 /* 0x1C */ ++#define INTERNAL_TYPE_ELSE 29 /* 0x1D */ ++#define INTERNAL_TYPE_WHILE 30 /* 0x1E */ + #define INTERNAL_TYPE_SCOPE 31 /* 0x1F Name, multiple Node */ + #define INTERNAL_TYPE_DEF_ANY 32 /* 0x20 type is Any, suppress search of enclosing scopes */ + #define INTERNAL_TYPE_EXTRA 33 /* 0x21 */ +@@ -371,6 +360,40 @@ + #define INTERNAL_TYPE_INVALID 34 + #define ACPI_TYPE_NOT_FOUND 0xFF + ++ ++/* ++ * Bitmapped ACPI types ++ * Used internally only ++ */ ++#define ACPI_BTYPE_ANY 0x00000000 ++#define ACPI_BTYPE_INTEGER 0x00000001 ++#define ACPI_BTYPE_STRING 0x00000002 ++#define ACPI_BTYPE_BUFFER 0x00000004 ++#define ACPI_BTYPE_PACKAGE 0x00000008 ++#define ACPI_BTYPE_FIELD_UNIT 0x00000010 ++#define ACPI_BTYPE_DEVICE 0x00000020 ++#define ACPI_BTYPE_EVENT 0x00000040 ++#define ACPI_BTYPE_METHOD 0x00000080 ++#define ACPI_BTYPE_MUTEX 0x00000100 ++#define ACPI_BTYPE_REGION 0x00000200 ++#define ACPI_BTYPE_POWER 0x00000400 ++#define ACPI_BTYPE_PROCESSOR 0x00000800 ++#define ACPI_BTYPE_THERMAL 0x00001000 ++#define ACPI_BTYPE_BUFFER_FIELD 0x00002000 ++#define ACPI_BTYPE_DDB_HANDLE 0x00004000 ++#define ACPI_BTYPE_DEBUG_OBJECT 0x00008000 ++#define ACPI_BTYPE_REFERENCE 0x00010000 ++#define ACPI_BTYPE_RESOURCE 0x00020000 ++ ++#define ACPI_BTYPE_COMPUTE_DATA (ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING | ACPI_BTYPE_BUFFER) ++ ++#define ACPI_BTYPE_DATA (ACPI_BTYPE_COMPUTE_DATA | ACPI_BTYPE_PACKAGE) ++#define ACPI_BTYPE_DATA_REFERENCE (ACPI_BTYPE_DATA | ACPI_BTYPE_REFERENCE | ACPI_BTYPE_DDB_HANDLE) ++#define ACPI_BTYPE_DEVICE_OBJECTS (ACPI_BTYPE_DEVICE | ACPI_BTYPE_THERMAL | ACPI_BTYPE_PROCESSOR) ++#define ACPI_BTYPE_OBJECTS_AND_REFS 0x00017FFF /* ARG or LOCAL */ ++#define ACPI_BTYPE_ALL_OBJECTS 0x00007FFF ++ ++ + /* + * Acpi_event Types: + * ------------ +@@ -495,7 +518,7 @@ + { + ACPI_OBJECT_TYPE type; + u32 proc_id; +- u32 pblk_address; ++ ACPI_IO_ADDRESS pblk_address; + u32 pblk_length; + } processor; + +@@ -928,6 +951,14 @@ + + typedef struct + { ++ u32 index; ++ u32 string_length; ++ NATIVE_CHAR *string_ptr; ++ ++} RESOURCE_SOURCE; ++ ++typedef struct ++{ + u32 resource_type; + u32 producer_consumer; + u32 decode; +@@ -939,9 +970,7 @@ + u32 max_address_range; + u32 address_translation_offset; + u32 address_length; +- u32 resource_source_index; +- u32 resource_source_string_length; +- NATIVE_CHAR resource_source[1]; ++ RESOURCE_SOURCE resource_source; + + } ADDRESS16_RESOURCE; + +@@ -958,23 +987,36 @@ + u32 max_address_range; + u32 address_translation_offset; + u32 address_length; +- u32 resource_source_index; +- u32 resource_source_string_length; +- NATIVE_CHAR resource_source[1]; ++ RESOURCE_SOURCE resource_source; + + } ADDRESS32_RESOURCE; + + typedef struct + { ++ u32 resource_type; ++ u32 producer_consumer; ++ u32 decode; ++ u32 min_address_fixed; ++ u32 max_address_fixed; ++ ATTRIBUTE_DATA attribute; ++ UINT64 granularity; ++ UINT64 min_address_range; ++ UINT64 max_address_range; ++ UINT64 address_translation_offset; ++ UINT64 address_length; ++ RESOURCE_SOURCE resource_source; ++ ++} ADDRESS64_RESOURCE; ++ ++typedef struct ++{ + u32 producer_consumer; + u32 edge_level; + u32 active_high_low; + u32 shared_exclusive; + u32 number_of_interrupts; ++ RESOURCE_SOURCE resource_source; + u32 interrupts[1]; +- u32 resource_source_index; +- u32 resource_source_string_length; +- NATIVE_CHAR resource_source[1]; + + } EXTENDED_IRQ_RESOURCE; + +@@ -993,6 +1035,7 @@ + fixed_memory32, + address16, + address32, ++ address64, + extended_irq + } RESOURCE_TYPE; + +@@ -1009,6 +1052,7 @@ + FIXED_MEMORY32_RESOURCE fixed_memory32; + ADDRESS16_RESOURCE address16; + ADDRESS32_RESOURCE address32; ++ ADDRESS64_RESOURCE address64; + EXTENDED_IRQ_RESOURCE extended_irq; + } RESOURCE_DATA; + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/amlcode.h linux/drivers/acpi/include/amlcode.h +--- /usr/src/linux/drivers/acpi/include/amlcode.h Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/include/amlcode.h Fri Apr 13 11:57:11 2001 +@@ -3,7 +3,7 @@ + * Name: amlcode.h - Definitions for AML, as included in "definition blocks" + * Declarations and definitions contained herein are derived + * directly from the ACPI specification. +- * $Revision: 46 $ ++ * $Revision: 50 $ + * + *****************************************************************************/ + +@@ -98,12 +98,12 @@ + #define AML_SIZE_OF_OP (u16) 0x87 + #define AML_INDEX_OP (u16) 0x88 + #define AML_MATCH_OP (u16) 0x89 +-#define AML_DWORD_FIELD_OP (u16) 0x8a +-#define AML_WORD_FIELD_OP (u16) 0x8b +-#define AML_BYTE_FIELD_OP (u16) 0x8c +-#define AML_BIT_FIELD_OP (u16) 0x8d ++#define AML_CREATE_DWORD_FIELD_OP (u16) 0x8a ++#define AML_CREATE_WORD_FIELD_OP (u16) 0x8b ++#define AML_CREATE_BYTE_FIELD_OP (u16) 0x8c ++#define AML_CREATE_BIT_FIELD_OP (u16) 0x8d + #define AML_TYPE_OP (u16) 0x8e +-#define AML_QWORD_FIELD_OP (u16) 0x8f /* ACPI 2.0 */ ++#define AML_CREATE_QWORD_FIELD_OP (u16) 0x8f /* ACPI 2.0 */ + #define AML_LAND_OP (u16) 0x90 + #define AML_LOR_OP (u16) 0x91 + #define AML_LNOT_OP (u16) 0x92 +@@ -154,7 +154,7 @@ + #define AML_DEBUG_OP (u16) 0x5b31 + #define AML_FATAL_OP (u16) 0x5b32 + #define AML_REGION_OP (u16) 0x5b80 +-#define AML_DEF_FIELD_OP (u16) 0x5b81 ++#define AML_FIELD_OP (u16) 0x5b81 + #define AML_DEVICE_OP (u16) 0x5b82 + #define AML_PROCESSOR_OP (u16) 0x5b83 + #define AML_POWER_RES_OP (u16) 0x5b84 +@@ -222,7 +222,7 @@ + + /* "Standard" ACPI types are 1-15 (0x0F) */ + +-#define ARGI_INTEGER ACPI_TYPE_INTEGER /* 1 */ ++#define ARGI_INTEGER ACPI_TYPE_INTEGER /* 1 */ + #define ARGI_STRING ACPI_TYPE_STRING /* 2 */ + #define ARGI_BUFFER ACPI_TYPE_BUFFER /* 3 */ + #define ARGI_PACKAGE ACPI_TYPE_PACKAGE /* 4 */ +@@ -312,13 +312,14 @@ + + typedef enum + { +- REGION_MEMORY = 0, ++ REGION_MEMORY = 0, + REGION_IO, + REGION_PCI_CONFIG, + REGION_EC, + REGION_SMBUS, + REGION_CMOS, +- REGION_PCI_BAR ++ REGION_PCI_BAR, ++ REGION_FIXED_HW = 0x7F, + + } AML_REGION_TYPES; + +@@ -327,80 +328,82 @@ + + typedef enum + { +- MATCH_MTR = 0, +- MATCH_MEQ = 1, +- MATCH_MLE = 2, +- MATCH_MLT = 3, +- MATCH_MGE = 4, +- MATCH_MGT = 5 ++ MATCH_MTR = 0, ++ MATCH_MEQ = 1, ++ MATCH_MLE = 2, ++ MATCH_MLT = 3, ++ MATCH_MGE = 4, ++ MATCH_MGT = 5 + + } AML_MATCH_OPERATOR; + +-#define MAX_MATCH_OPERATOR 5 ++#define MAX_MATCH_OPERATOR 5 + + + /* Field Access Types */ + +-#define ACCESS_TYPE_MASK 0x0f +-#define ACCESS_TYPE_SHIFT 0 ++#define ACCESS_TYPE_MASK 0x0f ++#define ACCESS_TYPE_SHIFT 0 + + typedef enum + { +- ACCESS_ANY_ACC = 0, +- ACCESS_BYTE_ACC = 1, +- ACCESS_WORD_ACC = 2, +- ACCESS_DWORD_ACC = 3, +- ACCESS_BLOCK_ACC = 4, +- ACCESS_SMBSEND_RECV_ACC = 5, +- ACCESS_SMBQUICK_ACC = 6 ++ ACCESS_ANY_ACC = 0, ++ ACCESS_BYTE_ACC = 1, ++ ACCESS_WORD_ACC = 2, ++ ACCESS_DWORD_ACC = 3, ++ ACCESS_QWORD_ACC = 4, /* ACPI 2.0 */ ++ ACCESS_BLOCK_ACC = 4, ++ ACCESS_SMBSEND_RECV_ACC = 5, ++ ACCESS_SMBQUICK_ACC = 6 + + } AML_ACCESS_TYPE; + + + /* Field Lock Rules */ + +-#define LOCK_RULE_MASK 0x10 +-#define LOCK_RULE_SHIFT 4 ++#define LOCK_RULE_MASK 0x10 ++#define LOCK_RULE_SHIFT 4 + + typedef enum + { +- GLOCK_NEVER_LOCK = 0, +- GLOCK_ALWAYS_LOCK = 1 ++ GLOCK_NEVER_LOCK = 0, ++ GLOCK_ALWAYS_LOCK = 1 + + } AML_LOCK_RULE; + + + /* Field Update Rules */ + +-#define UPDATE_RULE_MASK 0x060 +-#define UPDATE_RULE_SHIFT 5 ++#define UPDATE_RULE_MASK 0x060 ++#define UPDATE_RULE_SHIFT 5 + + typedef enum + { +- UPDATE_PRESERVE = 0, +- UPDATE_WRITE_AS_ONES = 1, +- UPDATE_WRITE_AS_ZEROS = 2 ++ UPDATE_PRESERVE = 0, ++ UPDATE_WRITE_AS_ONES = 1, ++ UPDATE_WRITE_AS_ZEROS = 2 + + } AML_UPDATE_RULE; + + + /* bit fields in Method_flags byte */ + +-#define METHOD_FLAGS_ARG_COUNT 0x07 +-#define METHOD_FLAGS_SERIALIZED 0x08 ++#define METHOD_FLAGS_ARG_COUNT 0x07 ++#define METHOD_FLAGS_SERIALIZED 0x08 ++#define METHOD_FLAGS_SYNCH_LEVEL 0xF0 + + + /* Array sizes. Used for range checking also */ + +-#define NUM_REGION_TYPES 7 +-#define NUM_ACCESS_TYPES 7 +-#define NUM_UPDATE_RULES 3 +-#define NUM_MATCH_OPS 7 +-#define NUM_OPCODES 256 +-#define NUM_FIELD_NAMES 2 ++#define NUM_REGION_TYPES 7 ++#define NUM_ACCESS_TYPES 7 ++#define NUM_UPDATE_RULES 3 ++#define NUM_MATCH_OPS 7 ++#define NUM_OPCODES 256 ++#define NUM_FIELD_NAMES 2 + + +-#define USER_REGION_BEGIN 0x80 ++#define USER_REGION_BEGIN 0x80 + + /* + * AML tables +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/platform/acenv.h linux/drivers/acpi/include/platform/acenv.h +--- /usr/src/linux/drivers/acpi/include/platform/acenv.h Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/include/platform/acenv.h Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,288 @@ ++/****************************************************************************** ++ * ++ * Name: acenv.h - Generation environment specific items ++ * $Revision: 73 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * 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 ++ */ ++ ++#ifndef __ACENV_H__ ++#define __ACENV_H__ ++ ++ ++/* ++ * Configuration for ACPI tools and utilities ++ */ ++ ++#ifdef _ACPI_DUMP_APP ++#define ACPI_DEBUG ++#define ACPI_APPLICATION ++#define ENABLE_DEBUGGER ++#define ACPI_USE_SYSTEM_CLIBRARY ++#define PARSER_ONLY ++#endif ++ ++#ifdef _ACPI_EXEC_APP ++#undef DEBUGGER_THREADING ++#define DEBUGGER_THREADING DEBUGGER_SINGLE_THREADED ++#define ACPI_DEBUG ++#define ACPI_APPLICATION ++#define ENABLE_DEBUGGER ++#define ACPI_USE_SYSTEM_CLIBRARY ++#endif ++ ++#ifdef _ACPI_ASL_COMPILER ++#define ACPI_DEBUG ++#define ACPI_APPLICATION ++#define ENABLE_DEBUGGER ++#define ACPI_USE_SYSTEM_CLIBRARY ++#endif ++ ++/* ++ * Memory allocation tracking. Used only if ++ * 1) This is the debug version ++ * 2) This is NOT a 16-bit version of the code (not enough real-mode memory) ++ */ ++#ifdef ACPI_DEBUG ++#ifndef _IA16 ++#define ACPI_DEBUG_TRACK_ALLOCATIONS ++#endif ++#endif ++ ++/* ++ * Environment configuration. The purpose of this file is to interface to the ++ * local generation environment. ++ * ++ * 1) ACPI_USE_SYSTEM_CLIBRARY - Define this if linking to an actual C library. ++ * Otherwise, local versions of string/memory functions will be used. ++ * 2) ACPI_USE_STANDARD_HEADERS - Define this if linking to a C library and ++ * the standard header files may be used. ++ * ++ * The ACPI subsystem only uses low level C library functions that do not call ++ * operating system services and may therefore be inlined in the code. ++ * ++ * It may be necessary to tailor these include files to the target ++ * generation environment. ++ * ++ * ++ * Functions and constants used from each header: ++ * ++ * string.h: memcpy ++ * memset ++ * strcat ++ * strcmp ++ * strcpy ++ * strlen ++ * strncmp ++ * strncat ++ * strncpy ++ * ++ * stdlib.h: strtoul ++ * ++ * stdarg.h: va_list ++ * va_arg ++ * va_start ++ * va_end ++ * ++ */ ++ ++/*! [Begin] no source code translation */ ++ ++#ifdef _LINUX ++#include "aclinux.h" ++ ++#elif _AED_EFI ++#include "acefi.h" ++ ++#elif WIN32 ++#include "acwin.h" ++ ++#elif __FreeBSD__ ++#include "acfreebsd.h" ++ ++#else ++ ++/* All other environments */ ++ ++#define ACPI_USE_STANDARD_HEADERS ++ ++/* Name of host operating system (returned by the _OS_ namespace object) */ ++ ++#define ACPI_OS_NAME "Intel ACPI/CA Core Subsystem" ++ ++#endif ++ ++ ++/*! [End] no source code translation !*/ ++ ++/****************************************************************************** ++ * ++ * C library configuration ++ * ++ *****************************************************************************/ ++ ++#ifdef ACPI_USE_SYSTEM_CLIBRARY ++/* ++ * Use the standard C library headers. ++ * We want to keep these to a minimum. ++ * ++ */ ++ ++#ifdef ACPI_USE_STANDARD_HEADERS ++/* ++ * Use the standard headers from the standard locations ++ */ ++#include <stdarg.h> ++#include <stdlib.h> ++#include <string.h> ++#include <ctype.h> ++ ++#endif /* ACPI_USE_STANDARD_HEADERS */ ++ ++/* ++ * We will be linking to the standard Clib functions ++ */ ++ ++#define STRSTR(s1,s2) strstr((s1), (s2)) ++#define STRUPR(s) strupr((s)) ++#define STRLEN(s) (u32) strlen((s)) ++#define STRCPY(d,s) strcpy((d), (s)) ++#define STRNCPY(d,s,n) strncpy((d), (s), (NATIVE_INT)(n)) ++#define STRNCMP(d,s,n) strncmp((d), (s), (NATIVE_INT)(n)) ++#define STRCMP(d,s) strcmp((d), (s)) ++#define STRCAT(d,s) strcat((d), (s)) ++#define STRNCAT(d,s,n) strncat((d), (s), (NATIVE_INT)(n)) ++#define STRTOUL(d,s,n) strtoul((d), (s), (NATIVE_INT)(n)) ++#define MEMCPY(d,s,n) memcpy((d), (s), (NATIVE_INT)(n)) ++#define MEMSET(d,s,n) memset((d), (s), (NATIVE_INT)(n)) ++#define TOUPPER toupper ++#define TOLOWER tolower ++#define IS_XDIGIT isxdigit ++ ++/****************************************************************************** ++ * ++ * Not using native C library, use local implementations ++ * ++ *****************************************************************************/ ++#else ++ ++/* ++ * Use local definitions of C library macros and functions ++ * NOTE: The function implementations may not be as efficient ++ * as an inline or assembly code implementation provided by a ++ * native C library. ++ */ ++ ++#ifndef va_arg ++ ++#ifndef _VALIST ++#define _VALIST ++typedef char *va_list; ++#endif /* _VALIST */ ++ ++/* ++ * Storage alignment properties ++ */ ++ ++#define _AUPBND (sizeof (NATIVE_INT) - 1) ++#define _ADNBND (sizeof (NATIVE_INT) - 1) ++ ++/* ++ * Variable argument list macro definitions ++ */ ++ ++#define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd))) ++#define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND)))) ++#define va_end(ap) (void) 0 ++#define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND)))) ++ ++#endif /* va_arg */ ++ ++ ++#define STRSTR(s1,s2) acpi_cm_strstr ((s1), (s2)) ++#define STRUPR(s) acpi_cm_strupr ((s)) ++#define STRLEN(s) acpi_cm_strlen ((s)) ++#define STRCPY(d,s) acpi_cm_strcpy ((d), (s)) ++#define STRNCPY(d,s,n) acpi_cm_strncpy ((d), (s), (n)) ++#define STRNCMP(d,s,n) acpi_cm_strncmp ((d), (s), (n)) ++#define STRCMP(d,s) acpi_cm_strcmp ((d), (s)) ++#define STRCAT(d,s) acpi_cm_strcat ((d), (s)) ++#define STRNCAT(d,s,n) acpi_cm_strncat ((d), (s), (n)) ++#define STRTOUL(d,s,n) acpi_cm_strtoul ((d), (s),(n)) ++#define MEMCPY(d,s,n) acpi_cm_memcpy ((d), (s), (n)) ++#define MEMSET(d,v,n) acpi_cm_memset ((d), (v), (n)) ++#define TOUPPER acpi_cm_to_upper ++#define TOLOWER acpi_cm_to_lower ++ ++#endif /* ACPI_USE_SYSTEM_CLIBRARY */ ++ ++ ++/****************************************************************************** ++ * ++ * Assembly code macros ++ * ++ *****************************************************************************/ ++ ++/* ++ * Handle platform- and compiler-specific assembly language differences. ++ * These should already have been defined by the platform includes above. ++ * ++ * Notes: ++ * 1) Interrupt 3 is used to break into a debugger ++ * 2) Interrupts are turned off during ACPI register setup ++ */ ++ ++/* Unrecognized compiler, use defaults */ ++#ifndef ACPI_ASM_MACROS ++ ++#define ACPI_ASM_MACROS ++#define causeinterrupt(level) ++#define BREAKPOINT3 ++#define disable() ++#define enable() ++#define halt() ++#define ACPI_ACQUIRE_GLOBAL_LOCK(Glptr, acq) ++#define ACPI_RELEASE_GLOBAL_LOCK(Glptr, acq) ++ ++#endif /* ACPI_ASM_MACROS */ ++ ++ ++#ifdef ACPI_APPLICATION ++ ++/* Don't want software interrupts within a ring3 application */ ++ ++#undef causeinterrupt ++#undef BREAKPOINT3 ++#define causeinterrupt(level) ++#define BREAKPOINT3 ++#endif ++ ++ ++/****************************************************************************** ++ * ++ * Compiler-specific ++ * ++ *****************************************************************************/ ++ ++/* this has been moved to compiler-specific headers, which are included from the ++ platform header. */ ++ ++ ++#endif /* __ACENV_H__ */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/platform/acgcc.h linux/drivers/acpi/include/platform/acgcc.h +--- /usr/src/linux/drivers/acpi/include/platform/acgcc.h Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/include/platform/acgcc.h Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,147 @@ ++/****************************************************************************** ++ * ++ * Name: acgcc.h - GCC specific defines, etc. ++ * $Revision: 6 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * 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 ++ */ ++ ++#ifndef __ACGCC_H__ ++#define __ACGCC_H__ ++ ++ ++#ifdef __ia64__ ++#define _IA64 ++ ++#define COMPILER_DEPENDENT_UINT64 unsigned long ++/* Single threaded */ ++#define ACPI_APPLICATION ++ ++#define ACPI_ASM_MACROS ++#define causeinterrupt(level) ++#define BREAKPOINT3 ++#define disable() __cli() ++#define enable() __sti() ++#define wbinvd() ++ ++/*! [Begin] no source code translation */ ++ ++#include <asm/pal.h> ++ ++#define halt() ia64_pal_halt_light() /* PAL_HALT[_LIGHT] */ ++#define safe_halt() ia64_pal_halt(1) /* PAL_HALT */ ++ ++ ++#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \ ++ do { \ ++ __asm__ volatile ("1: ld4 r29=%1\n" \ ++ ";;\n" \ ++ "mov ar.ccv=r29\n" \ ++ "mov r2=r29\n" \ ++ "shr.u r30=r29,1\n" \ ++ "and r29=-4,r29\n" \ ++ ";;\n" \ ++ "add r29=2,r29\n" \ ++ "and r30=1,r30\n" \ ++ ";;\n" \ ++ "add r29=r29,r30\n" \ ++ ";;\n" \ ++ "cmpxchg4.acq r30=%1,r29,ar.ccv\n" \ ++ ";;\n" \ ++ "cmp.eq p6,p7=r2,r30\n" \ ++ "(p7) br.dpnt.few 1b\n" \ ++ "cmp.gt p8,p9=3,r29\n" \ ++ ";;\n" \ ++ "(p8) mov %0=-1\n" \ ++ "(p9) mov %0=r0\n" \ ++ :"=r"(Acq):"m"(GLptr):"r2","r29","r30","memory"); \ ++ } while (0) ++ ++#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \ ++ do { \ ++ __asm__ volatile ("1: ld4 r29=%1\n" \ ++ ";;\n" \ ++ "mov ar.ccv=r29\n" \ ++ "mov r2=r29\n" \ ++ "and r29=-4,r29\n" \ ++ ";;\n" \ ++ "cmpxchg4.acq r30=%1,r29,ar.ccv\n" \ ++ ";;\n" \ ++ "cmp.eq p6,p7=r2,r30\n" \ ++ "(p7) br.dpnt.few 1b\n" \ ++ "and %0=1,r2\n" \ ++ ";;\n" \ ++ :"=r"(Acq):"m"(GLptr):"r2","r29","r30","memory"); \ ++ } while (0) ++/*! [End] no source code translation !*/ ++ ++ ++#else /* DO IA32 */ ++#define COMPILER_DEPENDENT_UINT64 unsigned long long ++#define ACPI_ASM_MACROS ++#define causeinterrupt(level) ++#define BREAKPOINT3 ++#define disable() __cli() ++#define enable() __sti() ++#define halt() __asm__ __volatile__ ("sti; hlt":::"memory") ++#define wbinvd() ++ ++/*! [Begin] no source code translation ++ * ++ * A brief explanation as GNU inline assembly is a bit hairy ++ * %0 is the output parameter in EAX ("=a") ++ * %1 and %2 are the input parameters in ECX ("c") ++ * and an immediate value ("i") respectively ++ * All actual register references are preceded with "%%" as in "%%edx" ++ * Immediate values in the assembly are preceded by "$" as in "$0x1" ++ * The final asm parameter are the operation altered non-output registers. ++ */ ++#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \ ++ do { \ ++ int dummy; \ ++ asm("1: movl (%1),%%eax;" \ ++ "movl %%eax,%%edx;" \ ++ "andl %2,%%edx;" \ ++ "btsl $0x1,%%edx;" \ ++ "adcl $0x0,%%edx;" \ ++ "lock; cmpxchgl %%edx,(%1);" \ ++ "jnz 1b;" \ ++ "cmpb $0x3,%%dl;" \ ++ "sbbl %%eax,%%eax" \ ++ :"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~1L):"dx"); \ ++ } while(0) ++ ++#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \ ++ do { \ ++ int dummy; \ ++ asm("1: movl (%1),%%eax;" \ ++ "movl %%eax,%%edx;" \ ++ "andl %2,%%edx;" \ ++ "lock; cmpxchgl %%edx,(%1);" \ ++ "jnz 1b;" \ ++ "andl $0x1,%%eax" \ ++ :"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~3L):"dx"); \ ++ } while(0) ++ ++/*! [End] no source code translation !*/ ++ ++#endif /* IA 32 */ ++ ++#endif /* __ACGCC_H__ */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/include/platform/aclinux.h linux/drivers/acpi/include/platform/aclinux.h +--- /usr/src/linux/drivers/acpi/include/platform/aclinux.h Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/include/platform/aclinux.h Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,66 @@ ++/****************************************************************************** ++ * ++ * Name: aclinux.h - OS specific defines, etc. ++ * $Revision: 10 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * 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 ++ */ ++ ++#ifndef __ACLINUX_H__ ++#define __ACLINUX_H__ ++ ++#define ACPI_OS_NAME "Linux" ++ ++#undef ACPI_USE_SYSTEM_CLIBRARY ++ ++#ifdef __KERNEL__ ++ ++#include <linux/config.h> ++#include <linux/string.h> ++#include <linux/kernel.h> ++#include <linux/ctype.h> ++#include <asm/system.h> ++#include <asm/atomic.h> ++#include <asm/div64.h> ++ ++#else ++ ++#include <stdarg.h> ++ ++#endif ++ ++/* Linux uses GCC */ ++ ++#include "acgcc.h" ++ ++#undef DEBUGGER_THREADING ++#define DEBUGGER_THREADING DEBUGGER_SINGLE_THREADED ++ ++#ifndef _IA64 ++/* Linux ia32 can't do int64 well */ ++#define ACPI_NO_INTEGER64_SUPPORT ++/* And the ia32 kernel doesn't include 64-bit divide support */ ++#define ACPI_DIV64(dividend, divisor) do_div(dividend, divisor) ++#else ++#define ACPI_DIV64(dividend, divisor) ACPI_DIVIDE(dividend, divisor) ++#endif ++ ++ ++#endif /* __ACLINUX_H__ */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/Makefile linux/drivers/acpi/interpreter/Makefile +--- /usr/src/linux/drivers/acpi/interpreter/Makefile Fri Dec 29 14:07:21 2000 ++++ linux/drivers/acpi/interpreter/Makefile Wed Dec 31 16:00:00 1969 +@@ -1,16 +0,0 @@ +-# +-# Makefile for all Linux ACPI interpreter subdirectories +-# +- +-O_TARGET := ../$(shell basename `pwd`).o +- +-obj-$(CONFIG_ACPI) := $(patsubst %.c,%.o,$(wildcard *.c)) +- +-EXTRA_CFLAGS += -I../include +- +-EXTRA_CFLAGS += $(ACPI_CFLAGS) +- +-include $(TOPDIR)/Rules.make +- +-clean: +- $(RM) *.o +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/amconfig.c linux/drivers/acpi/interpreter/amconfig.c +--- /usr/src/linux/drivers/acpi/interpreter/amconfig.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/interpreter/amconfig.c Wed Dec 31 16:00:00 1969 +@@ -1,306 +0,0 @@ +-/****************************************************************************** +- * +- * Module Name: amconfig - Namespace reconfiguration (Load/Unload opcodes) +- * $Revision: 29 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acparser.h" +-#include "acinterp.h" +-#include "amlcode.h" +-#include "acnamesp.h" +-#include "acevents.h" +-#include "actables.h" +-#include "acdispat.h" +- +- +-#define _COMPONENT INTERPRETER +- MODULE_NAME ("amconfig") +- +- +-/***************************************************************************** +- * +- * FUNCTION: Acpi_aml_exec_load_table +- * +- * PARAMETERS: Rgn_desc - Op region where the table will be obtained +- * Ddb_handle - Where a handle to the table will be returned +- * +- * RETURN: Status +- * +- * DESCRIPTION: Load an ACPI table +- * +- ****************************************************************************/ +- +-static ACPI_STATUS +-acpi_aml_exec_load_table ( +- ACPI_OPERAND_OBJECT *rgn_desc, +- ACPI_HANDLE *ddb_handle) +-{ +- ACPI_STATUS status; +- ACPI_OPERAND_OBJECT *table_desc = NULL; +- u8 *table_ptr; +- u8 *table_data_ptr; +- ACPI_TABLE_HEADER table_header; +- ACPI_TABLE_DESC table_info; +- u32 i; +- +- +- /* TBD: [Unhandled] Object can be either a field or an opregion */ +- +- +- /* Get the table header */ +- +- table_header.length = 0; +- for (i = 0; i < sizeof (ACPI_TABLE_HEADER); i++) { +- status = acpi_ev_address_space_dispatch (rgn_desc, ADDRESS_SPACE_READ, +- (ACPI_PHYSICAL_ADDRESS) i, 8, +- (u32 *) ((u8 *) &table_header + i)); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- } +- +- /* Allocate a buffer for the entire table */ +- +- table_ptr = acpi_cm_allocate (table_header.length); +- if (!table_ptr) { +- return (AE_NO_MEMORY); +- } +- +- /* Copy the header to the buffer */ +- +- MEMCPY (table_ptr, &table_header, sizeof (ACPI_TABLE_HEADER)); +- table_data_ptr = table_ptr + sizeof (ACPI_TABLE_HEADER); +- +- +- /* Get the table from the op region */ +- +- for (i = 0; i < table_header.length; i++) { +- status = acpi_ev_address_space_dispatch (rgn_desc, ADDRESS_SPACE_READ, +- (ACPI_PHYSICAL_ADDRESS)i, 8, +- (u32 *) (table_data_ptr + i)); +- if (ACPI_FAILURE (status)) { +- goto cleanup; +- } +- } +- +- +- /* Table must be either an SSDT or a PSDT */ +- +- if ((!STRNCMP (table_header.signature, +- acpi_gbl_acpi_table_data[ACPI_TABLE_PSDT].signature, +- acpi_gbl_acpi_table_data[ACPI_TABLE_PSDT].sig_length)) && +- (!STRNCMP (table_header.signature, +- acpi_gbl_acpi_table_data[ACPI_TABLE_SSDT].signature, +- acpi_gbl_acpi_table_data[ACPI_TABLE_SSDT].sig_length))) +- { +- status = AE_BAD_SIGNATURE; +- goto cleanup; +- } +- +- /* Create an object to be the table handle */ +- +- table_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_REFERENCE); +- if (!table_desc) { +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- +- /* Install the new table into the local data structures */ +- +- table_info.pointer = (ACPI_TABLE_HEADER *) table_ptr; +- table_info.length = table_header.length; +- table_info.allocation = ACPI_MEM_ALLOCATED; +- table_info.base_pointer = table_ptr; +- +- status = acpi_tb_install_table (NULL, &table_info); +- if (ACPI_FAILURE (status)) { +- goto cleanup; +- } +- +- /* Add the table to the namespace */ +- +- /* TBD: [Restructure] - change to whatever new interface is appropriate */ +-/* +- Status = Acpi_load_namespace (); +- if (ACPI_FAILURE (Status)) { +-*/ +- /* TBD: [Errors] Unload the table on failure ? */ +-/* +- goto Cleanup; +- } +-*/ +- +- +- /* TBD: [Investigate] we need a pointer to the table desc */ +- +- /* Init the table handle */ +- +- table_desc->reference.op_code = AML_LOAD_OP; +- table_desc->reference.object = table_info.installed_desc; +- +- *ddb_handle = table_desc; +- +- return (status); +- +- +-cleanup: +- +- acpi_cm_free (table_desc); +- acpi_cm_free (table_ptr); +- return (status); +- +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Acpi_aml_exec_unload_table +- * +- * PARAMETERS: Ddb_handle - Handle to a previously loaded table +- * +- * RETURN: Status +- * +- * DESCRIPTION: Unload an ACPI table +- * +- ****************************************************************************/ +- +-static ACPI_STATUS +-acpi_aml_exec_unload_table ( +- ACPI_HANDLE ddb_handle) +-{ +- ACPI_STATUS status = AE_NOT_IMPLEMENTED; +- ACPI_OPERAND_OBJECT *table_desc = (ACPI_OPERAND_OBJECT *) ddb_handle; +- ACPI_TABLE_DESC *table_info; +- +- +- /* Validate the handle */ +- /* Although the handle is partially validated in Acpi_aml_exec_reconfiguration(), +- * when it calls Acpi_aml_resolve_operands(), the handle is more completely +- * validated here. +- */ +- +- if ((!ddb_handle) || +- (!VALID_DESCRIPTOR_TYPE (ddb_handle, ACPI_DESC_TYPE_INTERNAL)) || +- (((ACPI_OPERAND_OBJECT *)ddb_handle)->common.type != +- INTERNAL_TYPE_REFERENCE)) +- { +- return (AE_BAD_PARAMETER); +- } +- +- +- /* Get the actual table descriptor from the Ddb_handle */ +- +- table_info = (ACPI_TABLE_DESC *) table_desc->reference.object; +- +- /* +- * Delete the entire namespace under this table Node +- * (Offset contains the Table_id) +- */ +- +- status = acpi_ns_delete_namespace_by_owner (table_info->table_id); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- /* Delete the table itself */ +- +- acpi_tb_uninstall_table (table_info->installed_desc); +- +- /* Delete the table descriptor (Ddb_handle) */ +- +- acpi_cm_remove_reference (table_desc); +- +- return (status); +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Acpi_aml_exec_reconfiguration +- * +- * PARAMETERS: Opcode - The opcode to be executed +- * Walk_state - Current state of the parse tree walk +- * +- * RETURN: Status +- * +- * DESCRIPTION: Reconfiguration opcodes such as LOAD and UNLOAD +- * +- ****************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_exec_reconfiguration ( +- u16 opcode, +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_STATUS status; +- ACPI_OPERAND_OBJECT *region_desc = NULL; +- ACPI_HANDLE *ddb_handle; +- +- +- /* Resolve the operands */ +- +- status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); +- /* Get the table handle, common for both opcodes */ +- +- status |= acpi_ds_obj_stack_pop_object ((ACPI_OPERAND_OBJECT **) &ddb_handle, +- walk_state); +- +- switch (opcode) +- { +- +- case AML_LOAD_OP: +- +- /* Get the region or field descriptor */ +- +- status |= acpi_ds_obj_stack_pop_object (®ion_desc, walk_state); +- if (ACPI_FAILURE (status)) { +- acpi_cm_remove_reference (region_desc); +- return (status); +- } +- +- status = acpi_aml_exec_load_table (region_desc, ddb_handle); +- break; +- +- +- case AML_UNLOAD_OP: +- +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- status = acpi_aml_exec_unload_table (ddb_handle); +- break; +- +- +- default: +- +- status = AE_AML_BAD_OPCODE; +- break; +- } +- +- +- return (status); +-} +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/amconvrt.c linux/drivers/acpi/interpreter/amconvrt.c +--- /usr/src/linux/drivers/acpi/interpreter/amconvrt.c Mon Jan 29 10:15:59 2001 ++++ linux/drivers/acpi/interpreter/amconvrt.c Wed Dec 31 16:00:00 1969 +@@ -1,525 +0,0 @@ +-/****************************************************************************** +- * +- * Module Name: amconvrt - Object conversion routines +- * $Revision: 3 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acparser.h" +-#include "acnamesp.h" +-#include "acinterp.h" +-#include "acevents.h" +-#include "amlcode.h" +-#include "acdispat.h" +- +- +-#define _COMPONENT INTERPRETER +- MODULE_NAME ("amconvrt") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_convert_to_target_type +- * +- * PARAMETERS: *Obj_desc - Object to be converted. +- * Walk_state - Current method state +- * +- * RETURN: Status +- * +- * DESCRIPTION: +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_convert_to_target_type ( +- OBJECT_TYPE_INTERNAL destination_type, +- ACPI_OPERAND_OBJECT **obj_desc, +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_STATUS status = AE_OK; +- +- +- /* +- * If required by the target, +- * perform implicit conversion on the source before we store it. +- */ +- +- switch (GET_CURRENT_ARG_TYPE (walk_state->op_info->runtime_args)) +- { +- case ARGI_SIMPLE_TARGET: +- case ARGI_FIXED_TARGET: +- case ARGI_INTEGER_REF: /* Handles Increment, Decrement cases */ +- +- switch (destination_type) +- { +- case INTERNAL_TYPE_DEF_FIELD: +- /* +- * Named field can always handle conversions +- */ +- break; +- +- default: +- /* No conversion allowed for these types */ +- +- if (destination_type != (*obj_desc)->common.type) { +- status = AE_TYPE; +- } +- } +- break; +- +- +- case ARGI_TARGETREF: +- +- switch (destination_type) +- { +- case ACPI_TYPE_INTEGER: +- case ACPI_TYPE_FIELD_UNIT: +- case INTERNAL_TYPE_BANK_FIELD: +- case INTERNAL_TYPE_INDEX_FIELD: +- /* +- * These types require an Integer operand. We can convert +- * a Buffer or a String to an Integer if necessary. +- */ +- status = acpi_aml_convert_to_integer (obj_desc, walk_state); +- break; +- +- +- case ACPI_TYPE_STRING: +- +- /* +- * The operand must be a String. We can convert an +- * Integer or Buffer if necessary +- */ +- status = acpi_aml_convert_to_string (obj_desc, walk_state); +- break; +- +- +- case ACPI_TYPE_BUFFER: +- +- /* +- * The operand must be a String. We can convert an +- * Integer or Buffer if necessary +- */ +- status = acpi_aml_convert_to_buffer (obj_desc, walk_state); +- break; +- } +- break; +- +- +- case ARGI_REFERENCE: +- /* +- * Create_xxxx_field cases - we are storing the field object into the name +- */ +- break; +- +- +- default: +- status = AE_AML_INTERNAL; +- } +- +- +- /* +- * Source-to-Target conversion semantics: +- * +- * If conversion to the target type cannot be performed, then simply +- * overwrite the target with the new object and type. +- */ +- if (status == AE_TYPE) { +- status = AE_OK; +- } +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_convert_to_integer +- * +- * PARAMETERS: *Obj_desc - Object to be converted. Must be an +- * Integer, Buffer, or String +- * Walk_state - Current method state +- * +- * RETURN: Status +- * +- * DESCRIPTION: Convert an ACPI Object to an integer. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_convert_to_integer ( +- ACPI_OPERAND_OBJECT **obj_desc, +- ACPI_WALK_STATE *walk_state) +-{ +- u32 i; +- ACPI_OPERAND_OBJECT *ret_desc; +- u32 count; +- char *pointer; +- ACPI_INTEGER result; +- u32 integer_size = sizeof (ACPI_INTEGER); +- +- +- switch ((*obj_desc)->common.type) +- { +- case ACPI_TYPE_INTEGER: +- return (AE_OK); +- +- case ACPI_TYPE_STRING: +- pointer = (*obj_desc)->string.pointer; +- count = (*obj_desc)->string.length; +- break; +- +- case ACPI_TYPE_BUFFER: +- pointer = (char *) (*obj_desc)->buffer.pointer; +- count = (*obj_desc)->buffer.length; +- break; +- +- default: +- return (AE_TYPE); +- } +- +- /* +- * Create a new integer +- */ +- ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); +- if (!ret_desc) { +- return (AE_NO_MEMORY); +- } +- +- +- /* Handle both ACPI 1.0 and ACPI 2.0 Integer widths */ +- +- if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) { +- /* +- * We are running a method that exists in a 32-bit ACPI table. +- * Truncate the value to 32 bits by zeroing out the upper 32-bit field +- */ +- integer_size = sizeof (u32); +- } +- +- +- /* +- * Convert the buffer/string to an integer. Note that both buffers and +- * strings are treated as raw data - we don't convert ascii to hex for +- * strings. +- * +- * There are two terminating conditions for the loop: +- * 1) The size of an integer has been reached, or +- * 2) The end of the buffer or string has been reached +- */ +- result = 0; +- +- /* Transfer no more than an integer's worth of data */ +- +- if (count > integer_size) { +- count = integer_size; +- } +- +- /* +- * String conversion is different than Buffer conversion +- */ +- switch ((*obj_desc)->common.type) +- { +- case ACPI_TYPE_STRING: +- +- /* TBD: Need to use 64-bit STRTOUL */ +- +- /* +- * Convert string to an integer +- * String must be hexadecimal as per the ACPI specification +- */ +- +- result = STRTOUL (pointer, NULL, 16); +- break; +- +- +- case ACPI_TYPE_BUFFER: +- +- /* +- * Buffer conversion - we simply grab enough raw data from the +- * buffer to fill an integer +- */ +- for (i = 0; i < count; i++) { +- /* +- * Get next byte and shift it into the Result. +- * Little endian is used, meaning that the first byte of the buffer +- * is the LSB of the integer +- */ +- result |= (((ACPI_INTEGER) pointer[i]) << (i * 8)); +- } +- +- break; +- } +- +- /* Save the Result, delete original descriptor, store new descriptor */ +- +- ret_desc->integer.value = result; +- +- if (walk_state->opcode != AML_STORE_OP) { +- acpi_cm_remove_reference (*obj_desc); +- } +- +- *obj_desc = ret_desc; +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_convert_to_buffer +- * +- * PARAMETERS: *Obj_desc - Object to be converted. Must be an +- * Integer, Buffer, or String +- * Walk_state - Current method state +- * +- * RETURN: Status +- * +- * DESCRIPTION: Convert an ACPI Object to an Buffer +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_convert_to_buffer ( +- ACPI_OPERAND_OBJECT **obj_desc, +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_OPERAND_OBJECT *ret_desc; +- u32 i; +- u32 integer_size = sizeof (ACPI_INTEGER); +- u8 *new_buf; +- +- +- switch ((*obj_desc)->common.type) +- { +- case ACPI_TYPE_INTEGER: +- +- /* +- * Create a new Buffer +- */ +- ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_BUFFER); +- if (!ret_desc) { +- return (AE_NO_MEMORY); +- } +- +- /* Handle both ACPI 1.0 and ACPI 2.0 Integer widths */ +- +- if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) { +- /* +- * We are running a method that exists in a 32-bit ACPI table. +- * Truncate the value to 32 bits by zeroing out the upper +- * 32-bit field +- */ +- integer_size = sizeof (u32); +- } +- +- /* Need enough space for one integers */ +- +- ret_desc->buffer.length = integer_size; +- new_buf = acpi_cm_callocate (integer_size); +- if (!new_buf) { +- REPORT_ERROR +- (("Aml_exec_dyadic2_r/Concat_op: Buffer allocation failure\n")); +- acpi_cm_remove_reference (ret_desc); +- return (AE_NO_MEMORY); +- } +- +- /* Copy the integer to the buffer */ +- +- for (i = 0; i < integer_size; i++) { +- new_buf[i] = (u8) ((*obj_desc)->integer.value >> (i * 8)); +- } +- ret_desc->buffer.pointer = new_buf; +- +- /* Return the new buffer descriptor */ +- +- if (walk_state->opcode != AML_STORE_OP) { +- acpi_cm_remove_reference (*obj_desc); +- } +- *obj_desc = ret_desc; +- break; +- +- +- case ACPI_TYPE_STRING: +- break; +- +- +- case ACPI_TYPE_BUFFER: +- break; +- +- +- default: +- return (AE_TYPE); +- break; +- } +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_convert_to_string +- * +- * PARAMETERS: *Obj_desc - Object to be converted. Must be an +- * Integer, Buffer, or String +- * Walk_state - Current method state +- * +- * RETURN: Status +- * +- * DESCRIPTION: Convert an ACPI Object to a string +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_convert_to_string ( +- ACPI_OPERAND_OBJECT **obj_desc, +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_OPERAND_OBJECT *ret_desc; +- u32 i; +- u32 index; +- u32 integer_size = sizeof (ACPI_INTEGER); +- u8 *new_buf; +- u8 *pointer; +- +- +- switch ((*obj_desc)->common.type) +- { +- case ACPI_TYPE_INTEGER: +- +- /* +- * Create a new String +- */ +- ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_STRING); +- if (!ret_desc) { +- return (AE_NO_MEMORY); +- } +- +- /* Handle both ACPI 1.0 and ACPI 2.0 Integer widths */ +- +- if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) { +- /* +- * We are running a method that exists in a 32-bit ACPI table. +- * Truncate the value to 32 bits by zeroing out the upper +- * 32-bit field +- */ +- integer_size = sizeof (u32); +- } +- +- /* Need enough space for one ASCII integer plus null terminator */ +- +- ret_desc->string.length = (integer_size * 2) + 1; +- new_buf = acpi_cm_callocate (ret_desc->string.length); +- if (!new_buf) { +- REPORT_ERROR +- (("Aml_exec_dyadic2_r/Concat_op: Buffer allocation failure\n")); +- acpi_cm_remove_reference (ret_desc); +- return (AE_NO_MEMORY); +- } +- +- /* Copy the integer to the buffer */ +- +- for (i = 0; i < (integer_size * 2); i++) { +- new_buf[i] = acpi_gbl_hex_to_ascii [((*obj_desc)->integer.value >> (i * 4)) & 0xF]; +- } +- +- /* Null terminate */ +- +- new_buf [i] = 0; +- ret_desc->buffer.pointer = new_buf; +- +- /* Return the new buffer descriptor */ +- +- if (walk_state->opcode != AML_STORE_OP) { +- acpi_cm_remove_reference (*obj_desc); +- } +- *obj_desc = ret_desc; +- +- return (AE_OK); +- +- +- case ACPI_TYPE_BUFFER: +- +- if (((*obj_desc)->buffer.length * 3) > ACPI_MAX_STRING_CONVERSION) { +- return (AE_AML_STRING_LIMIT); +- } +- +- /* +- * Create a new String +- */ +- ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_STRING); +- if (!ret_desc) { +- return (AE_NO_MEMORY); +- } +- +- /* Need enough space for one ASCII integer plus null terminator */ +- +- ret_desc->string.length = (*obj_desc)->buffer.length * 3; +- new_buf = acpi_cm_callocate (ret_desc->string.length + 1); +- if (!new_buf) { +- REPORT_ERROR +- (("Aml_exec_dyadic2_r/Concat_op: Buffer allocation failure\n")); +- acpi_cm_remove_reference (ret_desc); +- return (AE_NO_MEMORY); +- } +- +- /* +- * Convert each byte of the buffer to two ASCII characters plus a space. +- */ +- pointer = (*obj_desc)->buffer.pointer; +- index = 0; +- for (i = 0; i < (*obj_desc)->buffer.length; i++) { +- new_buf[index + 0] = acpi_gbl_hex_to_ascii [pointer[i] & 0x0F]; +- new_buf[index + 1] = acpi_gbl_hex_to_ascii [(pointer[i] >> 4) & 0x0F]; +- new_buf[index + 2] = ' '; +- index += 3; +- } +- +- /* Null terminate */ +- +- new_buf [index] = 0; +- ret_desc->buffer.pointer = new_buf; +- +- /* Return the new buffer descriptor */ +- +- if (walk_state->opcode != AML_STORE_OP) { +- acpi_cm_remove_reference (*obj_desc); +- } +- *obj_desc = ret_desc; +- break; +- +- +- case ACPI_TYPE_STRING: +- break; +- +- +- default: +- return (AE_TYPE); +- break; +- } +- +- return (AE_OK); +-} +- +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/amcreate.c linux/drivers/acpi/interpreter/amcreate.c +--- /usr/src/linux/drivers/acpi/interpreter/amcreate.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/interpreter/amcreate.c Wed Dec 31 16:00:00 1969 +@@ -1,722 +0,0 @@ +-/****************************************************************************** +- * +- * Module Name: amcreate - Named object creation +- * $Revision: 53 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acparser.h" +-#include "acinterp.h" +-#include "amlcode.h" +-#include "acnamesp.h" +-#include "acevents.h" +-#include "acdispat.h" +- +- +-#define _COMPONENT INTERPRETER +- MODULE_NAME ("amcreate") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_exec_create_field +- * +- * PARAMETERS: Opcode - The opcode to be executed +- * Operands - List of operands for the opcode +- * +- * RETURN: Status +- * +- * DESCRIPTION: Execute Create_field operators: Create_bit_field_op, +- * Create_byte_field_op, Create_word_field_op, Create_dWord_field_op, +- * Create_field_op (which define fields in buffers) +- * +- * ALLOCATION: Deletes Create_field_op's count operand descriptor +- * +- * +- * ACPI SPECIFICATION REFERENCES: +- * Def_create_bit_field := Create_bit_field_op Src_buf Bit_idx Name_string +- * Def_create_byte_field := Create_byte_field_op Src_buf Byte_idx Name_string +- * Def_create_dWord_field := Create_dWord_field_op Src_buf Byte_idx Name_string +- * Def_create_field := Create_field_op Src_buf Bit_idx Num_bits Name_string +- * Def_create_word_field := Create_word_field_op Src_buf Byte_idx Name_string +- * Bit_index := Term_arg=>Integer +- * Byte_index := Term_arg=>Integer +- * Num_bits := Term_arg=>Integer +- * Source_buff := Term_arg=>Buffer +- * +- ******************************************************************************/ +- +- +-ACPI_STATUS +-acpi_aml_exec_create_field ( +- u8 *aml_ptr, +- u32 aml_length, +- ACPI_NAMESPACE_NODE *node, +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_STATUS status; +- ACPI_OPERAND_OBJECT *obj_desc; +- ACPI_OPERAND_OBJECT *tmp_desc; +- +- +- /* Create the region descriptor */ +- +- obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_FIELD_UNIT); +- if (!obj_desc) { +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- /* Construct the field object */ +- +- obj_desc->field_unit.access = (u8) ACCESS_ANY_ACC; +- obj_desc->field_unit.lock_rule = (u8) GLOCK_NEVER_LOCK; +- obj_desc->field_unit.update_rule = (u8) UPDATE_PRESERVE; +- +- /* +- * Allocate a method object for this field unit +- */ +- +- obj_desc->field_unit.extra = acpi_cm_create_internal_object ( +- INTERNAL_TYPE_EXTRA); +- if (!obj_desc->field_unit.extra) { +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- /* +- * Remember location in AML stream of the field unit +- * opcode and operands -- since the buffer and index +- * operands must be evaluated. +- */ +- +- obj_desc->field_unit.extra->extra.pcode = aml_ptr; +- obj_desc->field_unit.extra->extra.pcode_length = aml_length; +- obj_desc->field_unit.node = node; +- +- +- /* +- * This operation is supposed to cause the destination Name to refer +- * to the defined Field_unit -- it must not store the constructed +- * Field_unit object (or its current value) in some location that the +- * Name may already be pointing to. So, if the Name currently contains +- * a reference which would cause Acpi_aml_exec_store() to perform an indirect +- * store rather than setting the value of the Name itself, clobber that +- * reference before calling Acpi_aml_exec_store(). +- */ +- +- /* Type of Name's existing value */ +- +- switch (acpi_ns_get_type (node)) +- { +- +- case ACPI_TYPE_FIELD_UNIT: +- +- case INTERNAL_TYPE_ALIAS: +- case INTERNAL_TYPE_BANK_FIELD: +- case INTERNAL_TYPE_DEF_FIELD: +- case INTERNAL_TYPE_INDEX_FIELD: +- +- tmp_desc = acpi_ns_get_attached_object (node); +- if (tmp_desc) { +- /* +- * There is an existing object here; delete it and zero out the +- * object field within the Node +- */ +- +- acpi_cm_remove_reference (tmp_desc); +- acpi_ns_attach_object ((ACPI_NAMESPACE_NODE *) node, NULL, +- ACPI_TYPE_ANY); +- } +- +- /* Set the type to ANY (or the store below will fail) */ +- +- ((ACPI_NAMESPACE_NODE *) node)->type = ACPI_TYPE_ANY; +- +- break; +- +- +- default: +- +- break; +- } +- +- +- /* Store constructed field descriptor in result location */ +- +- status = acpi_aml_exec_store (obj_desc, (ACPI_OPERAND_OBJECT *) node, walk_state); +- +- /* +- * If the field descriptor was not physically stored (or if a failure +- * above), we must delete it +- */ +- if (obj_desc->common.reference_count <= 1) { +- acpi_cm_remove_reference (obj_desc); +- } +- +- +- return (AE_OK); +- +- +-cleanup: +- +- /* Delete region object and method subobject */ +- +- if (obj_desc) { +- /* Remove deletes both objects! */ +- +- acpi_cm_remove_reference (obj_desc); +- obj_desc = NULL; +- } +- +- return (status); +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Acpi_aml_exec_create_alias +- * +- * PARAMETERS: Operands - List of operands for the opcode +- * +- * RETURN: Status +- * +- * DESCRIPTION: Create a new named alias +- * +- ****************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_exec_create_alias ( +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_NAMESPACE_NODE *source_node; +- ACPI_NAMESPACE_NODE *alias_node; +- ACPI_STATUS status; +- +- +- /* Get the source/alias operands (both NTEs) */ +- +- status = acpi_ds_obj_stack_pop_object ((ACPI_OPERAND_OBJECT **) &source_node, +- walk_state); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- /* +- * Don't pop it, it gets removed in the calling routine +- */ +- +- alias_node = acpi_ds_obj_stack_get_value (0, walk_state); +- +- /* Add an additional reference to the object */ +- +- acpi_cm_add_reference (source_node->object); +- +- /* +- * Attach the original source Node to the new Alias Node. +- */ +- status = acpi_ns_attach_object (alias_node, source_node->object, +- source_node->type); +- +- +- /* +- * The new alias assumes the type of the source, but it points +- * to the same object. The reference count of the object has two +- * additional references to prevent deletion out from under either the +- * source or the alias Node +- */ +- +- /* Since both operands are NTEs, we don't need to delete them */ +- +- return (status); +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Acpi_aml_exec_create_event +- * +- * PARAMETERS: None +- * +- * RETURN: Status +- * +- * DESCRIPTION: Create a new event object +- * +- ****************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_exec_create_event ( +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_STATUS status; +- ACPI_OPERAND_OBJECT *obj_desc; +- +- +- BREAKPOINT3; +- +- obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_EVENT); +- if (!obj_desc) { +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- /* Create the actual OS semaphore */ +- +- /* TBD: [Investigate] should be created with 0 or 1 units? */ +- +- status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, 1, +- &obj_desc->event.semaphore); +- if (ACPI_FAILURE (status)) { +- acpi_cm_remove_reference (obj_desc); +- goto cleanup; +- } +- +- /* Attach object to the Node */ +- +- status = acpi_ns_attach_object (acpi_ds_obj_stack_get_value (0, walk_state), +- obj_desc, (u8) ACPI_TYPE_EVENT); +- if (ACPI_FAILURE (status)) { +- acpi_os_delete_semaphore (obj_desc->event.semaphore); +- acpi_cm_remove_reference (obj_desc); +- goto cleanup; +- } +- +- +-cleanup: +- +- return (status); +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Acpi_aml_exec_create_mutex +- * +- * PARAMETERS: Interpreter_mode - Current running mode (load1/Load2/Exec) +- * Operands - List of operands for the opcode +- * +- * RETURN: Status +- * +- * DESCRIPTION: Create a new mutex object +- * +- ****************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_exec_create_mutex ( +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_STATUS status = AE_OK; +- ACPI_OPERAND_OBJECT *sync_desc; +- ACPI_OPERAND_OBJECT *obj_desc; +- +- +- /* Get the operand */ +- +- status = acpi_ds_obj_stack_pop_object (&sync_desc, walk_state); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- /* Attempt to allocate a new object */ +- +- obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_MUTEX); +- if (!obj_desc) { +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- /* Create the actual OS semaphore */ +- +- status = acpi_os_create_semaphore (1, 1, &obj_desc->mutex.semaphore); +- if (ACPI_FAILURE (status)) { +- acpi_cm_remove_reference (obj_desc); +- goto cleanup; +- } +- +- obj_desc->mutex.sync_level = (u8) sync_desc->integer.value; +- +- /* Obj_desc was on the stack top, and the name is below it */ +- +- status = acpi_ns_attach_object (acpi_ds_obj_stack_get_value (0, walk_state), +- obj_desc, (u8) ACPI_TYPE_MUTEX); +- if (ACPI_FAILURE (status)) { +- acpi_os_delete_semaphore (obj_desc->mutex.semaphore); +- acpi_cm_remove_reference (obj_desc); +- goto cleanup; +- } +- +- +-cleanup: +- +- /* Always delete the operand */ +- +- acpi_cm_remove_reference (sync_desc); +- +- return (status); +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Acpi_aml_exec_create_region +- * +- * PARAMETERS: Aml_ptr - Pointer to the region declaration AML +- * Aml_length - Max length of the declaration AML +- * Operands - List of operands for the opcode +- * Interpreter_mode - Load1/Load2/Execute +- * +- * RETURN: Status +- * +- * DESCRIPTION: Create a new operation region object +- * +- ****************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_exec_create_region ( +- u8 *aml_ptr, +- u32 aml_length, +- u8 region_space, +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_STATUS status; +- ACPI_OPERAND_OBJECT *obj_desc; +- ACPI_NAMESPACE_NODE *node; +- +- +- /* +- * Space ID must be one of the predefined IDs, or in the user-defined +- * range +- */ +- if ((region_space >= NUM_REGION_TYPES) && +- (region_space < USER_REGION_BEGIN)) +- { +- REPORT_ERROR (("Invalid Address_space type %X\n", region_space)); +- return (AE_AML_INVALID_SPACE_ID); +- } +- +- +- /* Get the Node from the object stack */ +- +- node = (ACPI_NAMESPACE_NODE *) acpi_ds_obj_stack_get_value (0, walk_state); +- +- /* Create the region descriptor */ +- +- obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_REGION); +- if (!obj_desc) { +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- /* +- * Allocate a method object for this region. +- */ +- +- obj_desc->region.extra = acpi_cm_create_internal_object ( +- INTERNAL_TYPE_EXTRA); +- if (!obj_desc->region.extra) { +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- /* +- * Remember location in AML stream of address & length +- * operands since they need to be evaluated at run time. +- */ +- +- obj_desc->region.extra->extra.pcode = aml_ptr; +- obj_desc->region.extra->extra.pcode_length = aml_length; +- +- /* Init the region from the operands */ +- +- obj_desc->region.space_id = region_space; +- obj_desc->region.address = 0; +- obj_desc->region.length = 0; +- +- +- /* Install the new region object in the parent Node */ +- +- obj_desc->region.node = node; +- +- status = acpi_ns_attach_object (node, obj_desc, +- (u8) ACPI_TYPE_REGION); +- +- if (ACPI_FAILURE (status)) { +- goto cleanup; +- } +- +- /* +- * If we have a valid region, initialize it +- * Namespace is NOT locked at this point. +- */ +- +- status = acpi_ev_initialize_region (obj_desc, FALSE); +- +- if (ACPI_FAILURE (status)) { +- /* +- * If AE_NOT_EXIST is returned, it is not fatal +- * because many regions get created before a handler +- * is installed for said region. +- */ +- if (AE_NOT_EXIST == status) { +- status = AE_OK; +- } +- } +- +-cleanup: +- +- if (ACPI_FAILURE (status)) { +- /* Delete region object and method subobject */ +- +- if (obj_desc) { +- /* Remove deletes both objects! */ +- +- acpi_cm_remove_reference (obj_desc); +- obj_desc = NULL; +- } +- } +- +- return (status); +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Acpi_aml_exec_create_processor +- * +- * PARAMETERS: Op - Op containing the Processor definition and +- * args +- * Processor_nTE - Node for the containing Node +- * +- * RETURN: Status +- * +- * DESCRIPTION: Create a new processor object and populate the fields +- * +- ****************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_exec_create_processor ( +- ACPI_PARSE_OBJECT *op, +- ACPI_HANDLE processor_nTE) +-{ +- ACPI_STATUS status; +- ACPI_PARSE_OBJECT *arg; +- ACPI_OPERAND_OBJECT *obj_desc; +- +- +- obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_PROCESSOR); +- if (!obj_desc) { +- status = AE_NO_MEMORY; +- return (status); +- } +- +- /* Install the new processor object in the parent Node */ +- +- status = acpi_ns_attach_object (processor_nTE, obj_desc, +- (u8) ACPI_TYPE_PROCESSOR); +- if (ACPI_FAILURE (status)) { +- return(status); +- } +- +- arg = op->value.arg; +- +- /* check existence */ +- +- if (!arg) { +- status = AE_AML_NO_OPERAND; +- return (status); +- } +- +- /* First arg is the Processor ID */ +- +- obj_desc->processor.proc_id = (u8) arg->value.integer; +- +- /* Move to next arg and check existence */ +- +- arg = arg->next; +- if (!arg) { +- status = AE_AML_NO_OPERAND; +- return (status); +- } +- +- /* Second arg is the PBlock Address */ +- +- obj_desc->processor.address = (ACPI_IO_ADDRESS) arg->value.integer; +- +- /* Move to next arg and check existence */ +- +- arg = arg->next; +- if (!arg) { +- status = AE_AML_NO_OPERAND; +- return (status); +- } +- +- /* Third arg is the PBlock Length */ +- +- obj_desc->processor.length = (u8) arg->value.integer; +- +- return (AE_OK); +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Acpi_aml_exec_create_power_resource +- * +- * PARAMETERS: Op - Op containing the Power_resource definition +- * and args +- * Power_res_nTE - Node for the containing Node +- * +- * RETURN: Status +- * +- * DESCRIPTION: Create a new Power_resource object and populate the fields +- * +- ****************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_exec_create_power_resource ( +- ACPI_PARSE_OBJECT *op, +- ACPI_HANDLE power_res_nTE) +-{ +- ACPI_STATUS status; +- ACPI_PARSE_OBJECT *arg; +- ACPI_OPERAND_OBJECT *obj_desc; +- +- +- obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_POWER); +- if (!obj_desc) { +- status = AE_NO_MEMORY; +- return (status); +- } +- +- /* Install the new power resource object in the parent Node */ +- +- status = acpi_ns_attach_object (power_res_nTE, obj_desc, +- (u8) ACPI_TYPE_POWER); +- if (ACPI_FAILURE (status)) { +- return(status); +- } +- +- arg = op->value.arg; +- +- /* check existence */ +- +- if (!arg) { +- status = AE_AML_NO_OPERAND; +- return (status); +- } +- +- /* First arg is the System_level */ +- +- obj_desc->power_resource.system_level = (u8) arg->value.integer; +- +- /* Move to next arg and check existence */ +- +- arg = arg->next; +- if (!arg) { +- status = AE_AML_NO_OPERAND; +- return (status); +- } +- +- /* Second arg is the PBlock Address */ +- +- obj_desc->power_resource.resource_order = (u16) arg->value.integer; +- +- return (AE_OK); +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Acpi_aml_exec_create_method +- * +- * PARAMETERS: Aml_ptr - First byte of the method's AML +- * Aml_length - AML byte count for this method +- * Method_flags - AML method flag byte +- * Method - Method Node +- * +- * RETURN: Status +- * +- * DESCRIPTION: Create a new method object +- * +- ****************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_exec_create_method ( +- u8 *aml_ptr, +- u32 aml_length, +- u32 method_flags, +- ACPI_HANDLE method) +-{ +- ACPI_OPERAND_OBJECT *obj_desc; +- ACPI_STATUS status; +- +- +- /* Create a new method object */ +- +- obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_METHOD); +- if (!obj_desc) { +- return (AE_NO_MEMORY); +- } +- +- /* Get the method's AML pointer/length from the Op */ +- +- obj_desc->method.pcode = aml_ptr; +- obj_desc->method.pcode_length = aml_length; +- +- /* +- * First argument is the Method Flags (contains parameter count for the +- * method) +- */ +- +- obj_desc->method.method_flags = (u8) method_flags; +- obj_desc->method.param_count = (u8) (method_flags & +- METHOD_FLAGS_ARG_COUNT); +- +- /* +- * Get the concurrency count. If required, a semaphore will be +- * created for this method when it is parsed. +- * +- * TBD: [Future] for APCI 2.0, there will be a Sync_level value, not +- * just a flag +- * Concurrency = Sync_level + 1;. +- */ +- +- if (method_flags & METHOD_FLAGS_SERIALIZED) { +- obj_desc->method.concurrency = 1; +- } +- +- else { +- obj_desc->method.concurrency = INFINITE_CONCURRENCY; +- } +- +- /* Attach the new object to the method Node */ +- +- status = acpi_ns_attach_object (method, obj_desc, (u8) ACPI_TYPE_METHOD); +- if (ACPI_FAILURE (status)) { +- acpi_cm_delete_object_desc (obj_desc); +- } +- +- return (status); +-} +- +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/amdyadic.c linux/drivers/acpi/interpreter/amdyadic.c +--- /usr/src/linux/drivers/acpi/interpreter/amdyadic.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/interpreter/amdyadic.c Wed Dec 31 16:00:00 1969 +@@ -1,882 +0,0 @@ +-/****************************************************************************** +- * +- * Module Name: amdyadic - ACPI AML (p-code) execution for dyadic operators +- * $Revision: 71 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acparser.h" +-#include "acnamesp.h" +-#include "acinterp.h" +-#include "acevents.h" +-#include "amlcode.h" +-#include "acdispat.h" +- +- +-#define _COMPONENT INTERPRETER +- MODULE_NAME ("amdyadic") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_do_concatenate +- * +- * PARAMETERS: *Obj_desc - Object to be converted. Must be an +- * Integer, Buffer, or String +- * +- * RETURN: Status +- * +- * DESCRIPTION: Concatenate two objects OF THE SAME TYPE. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_do_concatenate ( +- ACPI_OPERAND_OBJECT *obj_desc, +- ACPI_OPERAND_OBJECT *obj_desc2, +- ACPI_OPERAND_OBJECT **actual_ret_desc, +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_STATUS status; +- u32 i; +- ACPI_INTEGER this_integer; +- ACPI_OPERAND_OBJECT *ret_desc; +- NATIVE_CHAR *new_buf; +- u32 integer_size = sizeof (ACPI_INTEGER); +- +- +- /* +- * There are three cases to handle: +- * 1) Two Integers concatenated to produce a buffer +- * 2) Two Strings concatenated to produce a string +- * 3) Two Buffers concatenated to produce a buffer +- */ +- switch (obj_desc->common.type) +- { +- case ACPI_TYPE_INTEGER: +- +- /* Handle both ACPI 1.0 and ACPI 2.0 Integer widths */ +- +- if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) { +- /* +- * We are running a method that exists in a 32-bit ACPI table. +- * Truncate the value to 32 bits by zeroing out the upper +- * 32-bit field +- */ +- integer_size = sizeof (u32); +- } +- +- /* Result of two integers is a buffer */ +- +- ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_BUFFER); +- if (!ret_desc) { +- return (AE_NO_MEMORY); +- } +- +- /* Need enough space for two integers */ +- +- ret_desc->buffer.length = integer_size * 2; +- new_buf = acpi_cm_callocate (ret_desc->buffer.length); +- if (!new_buf) { +- REPORT_ERROR +- (("Aml_exec_dyadic2_r/Concat_op: Buffer allocation failure\n")); +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- ret_desc->buffer.pointer = (u8 *) new_buf; +- +- /* Convert the first integer */ +- +- this_integer = obj_desc->integer.value; +- for (i = 0; i < integer_size; i++) { +- new_buf[i] = (u8) this_integer; +- this_integer >>= 8; +- } +- +- /* Convert the second integer */ +- +- this_integer = obj_desc2->integer.value; +- for (; i < (integer_size * 2); i++) { +- new_buf[i] = (u8) this_integer; +- this_integer >>= 8; +- } +- +- break; +- +- +- case ACPI_TYPE_STRING: +- +- ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_STRING); +- if (!ret_desc) { +- return (AE_NO_MEMORY); +- } +- +- /* Operand1 is string */ +- +- new_buf = acpi_cm_allocate (obj_desc->string.length + +- obj_desc2->string.length + 1); +- if (!new_buf) { +- REPORT_ERROR +- (("Aml_exec_dyadic2_r/Concat_op: String allocation failure\n")); +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- STRCPY (new_buf, obj_desc->string.pointer); +- STRCPY (new_buf + obj_desc->string.length, +- obj_desc2->string.pointer); +- +- /* Point the return object to the new string */ +- +- ret_desc->string.pointer = new_buf; +- ret_desc->string.length = obj_desc->string.length += +- obj_desc2->string.length; +- break; +- +- +- case ACPI_TYPE_BUFFER: +- +- /* Operand1 is a buffer */ +- +- ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_BUFFER); +- if (!ret_desc) { +- return (AE_NO_MEMORY); +- } +- +- new_buf = acpi_cm_allocate (obj_desc->buffer.length + +- obj_desc2->buffer.length); +- if (!new_buf) { +- REPORT_ERROR +- (("Aml_exec_dyadic2_r/Concat_op: Buffer allocation failure\n")); +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- MEMCPY (new_buf, obj_desc->buffer.pointer, +- obj_desc->buffer.length); +- MEMCPY (new_buf + obj_desc->buffer.length, obj_desc2->buffer.pointer, +- obj_desc2->buffer.length); +- +- /* +- * Point the return object to the new buffer +- */ +- +- ret_desc->buffer.pointer = (u8 *) new_buf; +- ret_desc->buffer.length = obj_desc->buffer.length + +- obj_desc2->buffer.length; +- break; +- +- default: +- status = AE_AML_INTERNAL; +- ret_desc = NULL; +- } +- +- +- *actual_ret_desc = ret_desc; +- return (AE_OK); +- +- +-cleanup: +- +- acpi_cm_remove_reference (ret_desc); +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_exec_dyadic1 +- * +- * PARAMETERS: Opcode - The opcode to be executed +- * +- * RETURN: Status +- * +- * DESCRIPTION: Execute Type 1 dyadic operator with numeric operands: +- * Notify_op +- * +- * ALLOCATION: Deletes both operands +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_exec_dyadic1 ( +- u16 opcode, +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_OPERAND_OBJECT *obj_desc = NULL; +- ACPI_OPERAND_OBJECT *val_desc = NULL; +- ACPI_NAMESPACE_NODE *node; +- ACPI_STATUS status = AE_OK; +- +- +- /* Resolve all operands */ +- +- status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); +- /* Get the operands */ +- +- status |= acpi_ds_obj_stack_pop_object (&val_desc, walk_state); +- status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); +- if (ACPI_FAILURE (status)) { +- /* Invalid parameters on object stack */ +- +- goto cleanup; +- } +- +- +- /* Examine the opcode */ +- +- switch (opcode) +- { +- +- /* Def_notify := Notify_op Notify_object Notify_value */ +- +- case AML_NOTIFY_OP: +- +- /* The Obj_desc is actually an Node */ +- +- node = (ACPI_NAMESPACE_NODE *) obj_desc; +- obj_desc = NULL; +- +- /* Object must be a device or thermal zone */ +- +- if (node && val_desc) { +- switch (node->type) +- { +- case ACPI_TYPE_DEVICE: +- case ACPI_TYPE_THERMAL: +- +- /* +- * Requires that Device and Thermal_zone be compatible +- * mappings +- */ +- +- /* Dispatch the notify to the appropriate handler */ +- +- acpi_ev_notify_dispatch (node, (u32) val_desc->integer.value); +- break; +- +- default: +- status = AE_AML_OPERAND_TYPE; +- } +- } +- break; +- +- default: +- +- REPORT_ERROR (("Acpi_aml_exec_dyadic1: Unknown dyadic opcode %X\n", +- opcode)); +- status = AE_AML_BAD_OPCODE; +- } +- +- +-cleanup: +- +- /* Always delete both operands */ +- +- acpi_cm_remove_reference (val_desc); +- acpi_cm_remove_reference (obj_desc); +- +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_exec_dyadic2_r +- * +- * PARAMETERS: Opcode - The opcode to be executed +- * +- * RETURN: Status +- * +- * DESCRIPTION: Execute Type 2 dyadic operator with numeric operands and +- * one or two result operands. +- * +- * ALLOCATION: Deletes one operand descriptor -- other remains on stack +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_exec_dyadic2_r ( +- u16 opcode, +- ACPI_WALK_STATE *walk_state, +- ACPI_OPERAND_OBJECT **return_desc) +-{ +- ACPI_OPERAND_OBJECT *obj_desc = NULL; +- ACPI_OPERAND_OBJECT *obj_desc2 = NULL; +- ACPI_OPERAND_OBJECT *res_desc = NULL; +- ACPI_OPERAND_OBJECT *res_desc2 = NULL; +- ACPI_OPERAND_OBJECT *ret_desc = NULL; +- ACPI_OPERAND_OBJECT *ret_desc2 = NULL; +- ACPI_STATUS status = AE_OK; +- u32 num_operands = 3; +- +- +- /* Resolve all operands */ +- +- status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); +- /* Get all operands */ +- +- if (AML_DIVIDE_OP == opcode) { +- num_operands = 4; +- status |= acpi_ds_obj_stack_pop_object (&res_desc2, walk_state); +- } +- +- status |= acpi_ds_obj_stack_pop_object (&res_desc, walk_state); +- status |= acpi_ds_obj_stack_pop_object (&obj_desc2, walk_state); +- status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); +- if (ACPI_FAILURE (status)) { +- goto cleanup; +- } +- +- +- /* Create an internal return object if necessary */ +- +- switch (opcode) +- { +- case AML_ADD_OP: +- case AML_BIT_AND_OP: +- case AML_BIT_NAND_OP: +- case AML_BIT_OR_OP: +- case AML_BIT_NOR_OP: +- case AML_BIT_XOR_OP: +- case AML_DIVIDE_OP: +- case AML_MULTIPLY_OP: +- case AML_SHIFT_LEFT_OP: +- case AML_SHIFT_RIGHT_OP: +- case AML_SUBTRACT_OP: +- +- ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); +- if (!ret_desc) { +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- break; +- } +- +- +- /* +- * Execute the opcode +- */ +- +- switch (opcode) +- { +- +- /* Def_add := Add_op Operand1 Operand2 Result */ +- +- case AML_ADD_OP: +- +- ret_desc->integer.value = obj_desc->integer.value + +- obj_desc2->integer.value; +- break; +- +- +- /* Def_and := And_op Operand1 Operand2 Result */ +- +- case AML_BIT_AND_OP: +- +- ret_desc->integer.value = obj_desc->integer.value & +- obj_desc2->integer.value; +- break; +- +- +- /* Def_nAnd := NAnd_op Operand1 Operand2 Result */ +- +- case AML_BIT_NAND_OP: +- +- ret_desc->integer.value = ~(obj_desc->integer.value & +- obj_desc2->integer.value); +- break; +- +- +- /* Def_or := Or_op Operand1 Operand2 Result */ +- +- case AML_BIT_OR_OP: +- +- ret_desc->integer.value = obj_desc->integer.value | +- obj_desc2->integer.value; +- break; +- +- +- /* Def_nOr := NOr_op Operand1 Operand2 Result */ +- +- case AML_BIT_NOR_OP: +- +- ret_desc->integer.value = ~(obj_desc->integer.value | +- obj_desc2->integer.value); +- break; +- +- +- /* Def_xOr := XOr_op Operand1 Operand2 Result */ +- +- case AML_BIT_XOR_OP: +- +- ret_desc->integer.value = obj_desc->integer.value ^ +- obj_desc2->integer.value; +- break; +- +- +- /* Def_divide := Divide_op Dividend Divisor Remainder Quotient */ +- +- case AML_DIVIDE_OP: +- +- if (!obj_desc2->integer.value) { +- REPORT_ERROR +- (("Aml_exec_dyadic2_r/Divide_op: Divide by zero\n")); +- +- status = AE_AML_DIVIDE_BY_ZERO; +- goto cleanup; +- } +- +- ret_desc2 = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); +- if (!ret_desc2) { +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- /* Remainder (modulo) */ +- +- ret_desc->integer.value = ACPI_MODULO (obj_desc->integer.value, +- obj_desc2->integer.value); +- +- /* Result (what we used to call the quotient) */ +- +- ret_desc2->integer.value = ACPI_DIVIDE (obj_desc->integer.value, +- obj_desc2->integer.value); +- break; +- +- +- /* Def_multiply := Multiply_op Operand1 Operand2 Result */ +- +- case AML_MULTIPLY_OP: +- +- ret_desc->integer.value = obj_desc->integer.value * +- obj_desc2->integer.value; +- break; +- +- +- /* Def_shift_left := Shift_left_op Operand Shift_count Result */ +- +- case AML_SHIFT_LEFT_OP: +- +- ret_desc->integer.value = obj_desc->integer.value << +- obj_desc2->integer.value; +- break; +- +- +- /* Def_shift_right := Shift_right_op Operand Shift_count Result */ +- +- case AML_SHIFT_RIGHT_OP: +- +- ret_desc->integer.value = obj_desc->integer.value >> +- obj_desc2->integer.value; +- break; +- +- +- /* Def_subtract := Subtract_op Operand1 Operand2 Result */ +- +- case AML_SUBTRACT_OP: +- +- ret_desc->integer.value = obj_desc->integer.value - +- obj_desc2->integer.value; +- break; +- +- +- /* Def_concat := Concat_op Data1 Data2 Result */ +- +- case AML_CONCAT_OP: +- +- +- /* +- * Convert the second operand if necessary. The first operand +- * determines the type of the second operand, (See the Data Types +- * section of the ACPI specification.) Both object types are +- * guaranteed to be either Integer/String/Buffer by the operand +- * resolution mechanism above. +- */ +- +- switch (obj_desc->common.type) +- { +- case ACPI_TYPE_INTEGER: +- status = acpi_aml_convert_to_integer (&obj_desc2, walk_state); +- break; +- +- case ACPI_TYPE_STRING: +- status = acpi_aml_convert_to_string (&obj_desc2, walk_state); +- break; +- +- case ACPI_TYPE_BUFFER: +- status = acpi_aml_convert_to_buffer (&obj_desc2, walk_state); +- break; +- +- default: +- status = AE_AML_INTERNAL; +- } +- +- if (ACPI_FAILURE (status)) { +- goto cleanup; +- } +- +- +- /* +- * Both operands are now known to be the same object type +- * (Both are Integer, String, or Buffer), and we can now perform the +- * concatenation. +- */ +- status = acpi_aml_do_concatenate (obj_desc, obj_desc2, &ret_desc, walk_state); +- if (ACPI_FAILURE (status)) { +- goto cleanup; +- } +- break; +- +- +- default: +- +- REPORT_ERROR (("Acpi_aml_exec_dyadic2_r: Unknown dyadic opcode %X\n", +- opcode)); +- status = AE_AML_BAD_OPCODE; +- goto cleanup; +- } +- +- +- /* +- * Store the result of the operation (which is now in Obj_desc) into +- * the result descriptor, or the location pointed to by the result +- * descriptor (Res_desc). +- */ +- +- status = acpi_aml_exec_store (ret_desc, res_desc, walk_state); +- if (ACPI_FAILURE (status)) { +- goto cleanup; +- } +- +- if (AML_DIVIDE_OP == opcode) { +- status = acpi_aml_exec_store (ret_desc2, res_desc2, walk_state); +- +- /* +- * Since the remainder is not returned, remove a reference to +- * the object we created earlier +- */ +- +- acpi_cm_remove_reference (ret_desc2); +- } +- +- +-cleanup: +- +- /* Always delete the operands */ +- +- acpi_cm_remove_reference (obj_desc); +- acpi_cm_remove_reference (obj_desc2); +- +- +- /* Delete return object on error */ +- +- if (ACPI_FAILURE (status)) { +- /* On failure, delete the result ops */ +- +- acpi_cm_remove_reference (res_desc); +- acpi_cm_remove_reference (res_desc2); +- +- if (ret_desc) { +- /* And delete the internal return object */ +- +- acpi_cm_remove_reference (ret_desc); +- ret_desc = NULL; +- } +- } +- +- /* Set the return object and exit */ +- +- *return_desc = ret_desc; +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_exec_dyadic2_s +- * +- * PARAMETERS: Opcode - The opcode to be executed +- * +- * RETURN: Status +- * +- * DESCRIPTION: Execute Type 2 dyadic synchronization operator +- * +- * ALLOCATION: Deletes one operand descriptor -- other remains on stack +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_exec_dyadic2_s ( +- u16 opcode, +- ACPI_WALK_STATE *walk_state, +- ACPI_OPERAND_OBJECT **return_desc) +-{ +- ACPI_OPERAND_OBJECT *obj_desc; +- ACPI_OPERAND_OBJECT *time_desc; +- ACPI_OPERAND_OBJECT *ret_desc = NULL; +- ACPI_STATUS status; +- +- +- /* Resolve all operands */ +- +- status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); +- /* Get all operands */ +- +- status |= acpi_ds_obj_stack_pop_object (&time_desc, walk_state); +- status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); +- if (ACPI_FAILURE (status)) { +- /* Invalid parameters on object stack */ +- +- goto cleanup; +- } +- +- +- /* Create the internal return object */ +- +- ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); +- if (!ret_desc) { +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- /* Default return value is FALSE, operation did not time out */ +- +- ret_desc->integer.value = 0; +- +- +- /* Examine the opcode */ +- +- switch (opcode) +- { +- +- /* Def_acquire := Acquire_op Mutex_object Timeout */ +- +- case AML_ACQUIRE_OP: +- +- status = acpi_aml_system_acquire_mutex (time_desc, obj_desc); +- break; +- +- +- /* Def_wait := Wait_op Acpi_event_object Timeout */ +- +- case AML_WAIT_OP: +- +- status = acpi_aml_system_wait_event (time_desc, obj_desc); +- break; +- +- +- default: +- +- REPORT_ERROR (("Acpi_aml_exec_dyadic2_s: Unknown dyadic synchronization opcode %X\n", opcode)); +- status = AE_AML_BAD_OPCODE; +- goto cleanup; +- } +- +- +- /* +- * Return a boolean indicating if operation timed out +- * (TRUE) or not (FALSE) +- */ +- +- if (status == AE_TIME) { +- ret_desc->integer.value = ACPI_INTEGER_MAX; /* TRUE, op timed out */ +- status = AE_OK; +- } +- +- +-cleanup: +- +- /* Delete params */ +- +- acpi_cm_remove_reference (time_desc); +- acpi_cm_remove_reference (obj_desc); +- +- /* Delete return object on error */ +- +- if (ACPI_FAILURE (status) && +- (ret_desc)) +- { +- acpi_cm_remove_reference (ret_desc); +- ret_desc = NULL; +- } +- +- +- /* Set the return object and exit */ +- +- *return_desc = ret_desc; +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_exec_dyadic2 +- * +- * PARAMETERS: Opcode - The opcode to be executed +- * +- * RETURN: Status +- * +- * DESCRIPTION: Execute Type 2 dyadic operator with numeric operands and +- * no result operands +- * +- * ALLOCATION: Deletes one operand descriptor -- other remains on stack +- * containing result value +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_exec_dyadic2 ( +- u16 opcode, +- ACPI_WALK_STATE *walk_state, +- ACPI_OPERAND_OBJECT **return_desc) +-{ +- ACPI_OPERAND_OBJECT *obj_desc; +- ACPI_OPERAND_OBJECT *obj_desc2; +- ACPI_OPERAND_OBJECT *ret_desc = NULL; +- ACPI_STATUS status; +- u8 lboolean; +- +- +- /* Resolve all operands */ +- +- status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); +- /* Get all operands */ +- +- status |= acpi_ds_obj_stack_pop_object (&obj_desc2, walk_state); +- status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); +- if (ACPI_FAILURE (status)) { +- /* Invalid parameters on object stack */ +- +- goto cleanup; +- } +- +- +- /* Create the internal return object */ +- +- ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); +- if (!ret_desc) { +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- /* +- * Execute the Opcode +- */ +- +- lboolean = FALSE; +- switch (opcode) +- { +- +- /* Def_lAnd := LAnd_op Operand1 Operand2 */ +- +- case AML_LAND_OP: +- +- lboolean = (u8) (obj_desc->integer.value && +- obj_desc2->integer.value); +- break; +- +- +- /* Def_lEqual := LEqual_op Operand1 Operand2 */ +- +- case AML_LEQUAL_OP: +- +- lboolean = (u8) (obj_desc->integer.value == +- obj_desc2->integer.value); +- break; +- +- +- /* Def_lGreater := LGreater_op Operand1 Operand2 */ +- +- case AML_LGREATER_OP: +- +- lboolean = (u8) (obj_desc->integer.value > +- obj_desc2->integer.value); +- break; +- +- +- /* Def_lLess := LLess_op Operand1 Operand2 */ +- +- case AML_LLESS_OP: +- +- lboolean = (u8) (obj_desc->integer.value < +- obj_desc2->integer.value); +- break; +- +- +- /* Def_lOr := LOr_op Operand1 Operand2 */ +- +- case AML_LOR_OP: +- +- lboolean = (u8) (obj_desc->integer.value || +- obj_desc2->integer.value); +- break; +- +- +- default: +- +- REPORT_ERROR (("Acpi_aml_exec_dyadic2: Unknown dyadic opcode %X\n", opcode)); +- status = AE_AML_BAD_OPCODE; +- goto cleanup; +- break; +- } +- +- +- /* Set return value to logical TRUE (all ones) or FALSE (zero) */ +- +- if (lboolean) { +- ret_desc->integer.value = ACPI_INTEGER_MAX; +- } +- else { +- ret_desc->integer.value = 0; +- } +- +- +-cleanup: +- +- /* Always delete operands */ +- +- acpi_cm_remove_reference (obj_desc); +- acpi_cm_remove_reference (obj_desc2); +- +- +- /* Delete return object on error */ +- +- if (ACPI_FAILURE (status) && +- (ret_desc)) +- { +- acpi_cm_remove_reference (ret_desc); +- ret_desc = NULL; +- } +- +- +- /* Set the return object and exit */ +- +- *return_desc = ret_desc; +- return (status); +-} +- +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/amfield.c linux/drivers/acpi/interpreter/amfield.c +--- /usr/src/linux/drivers/acpi/interpreter/amfield.c Mon Jan 29 10:15:59 2001 ++++ linux/drivers/acpi/interpreter/amfield.c Wed Dec 31 16:00:00 1969 +@@ -1,283 +0,0 @@ +-/****************************************************************************** +- * +- * Module Name: amfield - ACPI AML (p-code) execution - field manipulation +- * $Revision: 77 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acdispat.h" +-#include "acinterp.h" +-#include "amlcode.h" +-#include "acnamesp.h" +-#include "achware.h" +-#include "acevents.h" +- +- +-#define _COMPONENT INTERPRETER +- MODULE_NAME ("amfield") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_setup_field +- * +- * PARAMETERS: *Obj_desc - Field to be read or written +- * *Rgn_desc - Region containing field +- * Field_bit_width - Field Width in bits (8, 16, or 32) +- * +- * RETURN: Status +- * +- * DESCRIPTION: Common processing for Acpi_aml_read_field and Acpi_aml_write_field +- * +- * ACPI SPECIFICATION REFERENCES: +- * Each of the Type1_opcodes is defined as specified in in-line +- * comments below. For each one, use the following definitions. +- * +- * Def_bit_field := Bit_field_op Src_buf Bit_idx Destination +- * Def_byte_field := Byte_field_op Src_buf Byte_idx Destination +- * Def_create_field := Create_field_op Src_buf Bit_idx Num_bits Name_string +- * Def_dWord_field := DWord_field_op Src_buf Byte_idx Destination +- * Def_word_field := Word_field_op Src_buf Byte_idx Destination +- * Bit_index := Term_arg=>Integer +- * Byte_index := Term_arg=>Integer +- * Destination := Name_string +- * Num_bits := Term_arg=>Integer +- * Source_buf := Term_arg=>Buffer +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_setup_field ( +- ACPI_OPERAND_OBJECT *obj_desc, +- ACPI_OPERAND_OBJECT *rgn_desc, +- u32 field_bit_width) +-{ +- ACPI_STATUS status = AE_OK; +- u32 field_byte_width; +- +- +- /* Parameter validation */ +- +- if (!obj_desc || !rgn_desc) { +- return (AE_AML_NO_OPERAND); +- } +- +- if (ACPI_TYPE_REGION != rgn_desc->common.type) { +- return (AE_AML_OPERAND_TYPE); +- } +- +- +- /* +- * TBD: [Future] Acpi 2.0 supports Qword fields +- * +- * Init and validate Field width +- * Possible values are 1, 2, 4 +- */ +- +- field_byte_width = DIV_8 (field_bit_width); +- +- if ((field_bit_width != 8) && +- (field_bit_width != 16) && +- (field_bit_width != 32)) +- { +- return (AE_AML_OPERAND_VALUE); +- } +- +- +- /* +- * If the Region Address and Length have not been previously evaluated, +- * evaluate them and save the results. +- */ +- if (!(rgn_desc->region.flags & AOPOBJ_DATA_VALID)) { +- +- status = acpi_ds_get_region_arguments (rgn_desc); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- } +- +- +- if ((obj_desc->common.type == ACPI_TYPE_FIELD_UNIT) && +- (!(obj_desc->common.flags & AOPOBJ_DATA_VALID))) +- { +- /* +- * Field Buffer and Index have not been previously evaluated, +- */ +- return (AE_AML_INTERNAL); +- } +- +- if (rgn_desc->region.length < +- (obj_desc->field.offset & ~((u32) field_byte_width - 1)) + +- field_byte_width) +- { +- /* +- * Offset rounded up to next multiple of field width +- * exceeds region length, indicate an error +- */ +- +- return (AE_AML_REGION_LIMIT); +- } +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_access_named_field +- * +- * PARAMETERS: Mode - ACPI_READ or ACPI_WRITE +- * Named_field - Handle for field to be accessed +- * *Buffer - Value(s) to be read or written +- * Buffer_length - Number of bytes to transfer +- * +- * RETURN: Status +- * +- * DESCRIPTION: Read or write a named field +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_access_named_field ( +- u32 mode, +- ACPI_HANDLE named_field, +- void *buffer, +- u32 buffer_length) +-{ +- ACPI_OPERAND_OBJECT *obj_desc = NULL; +- ACPI_STATUS status = AE_OK; +- u8 locked = FALSE; +- u32 bit_granularity = 0; +- u32 byte_granularity; +- u32 datum_length; +- u32 actual_byte_length; +- u32 byte_field_length; +- +- +- /* Parameter validation */ +- +- if ((!named_field) || (ACPI_READ == mode && !buffer)) { +- return (AE_AML_INTERNAL); +- } +- +- /* Get the attached field object */ +- +- obj_desc = acpi_ns_get_attached_object (named_field); +- if (!obj_desc) { +- return (AE_AML_INTERNAL); +- } +- +- /* Check the type */ +- +- if (INTERNAL_TYPE_DEF_FIELD != acpi_ns_get_type (named_field)) { +- return (AE_AML_OPERAND_TYPE); +- } +- +- /* Obj_desc valid and Named_field is a defined field */ +- +- +- /* Double-check that the attached object is also a field */ +- +- if (INTERNAL_TYPE_DEF_FIELD != obj_desc->common.type) { +- return (AE_AML_OPERAND_TYPE); +- } +- +- +- /* +- * Granularity was decoded from the field access type +- * (Any_acc will be the same as Byte_acc) +- */ +- +- bit_granularity = obj_desc->field_unit.granularity; +- byte_granularity = DIV_8 (bit_granularity); +- +- /* +- * Check if request is too large for the field, and silently truncate +- * if necessary +- */ +- +- /* TBD: [Errors] should an error be returned in this case? */ +- +- byte_field_length = (u32) DIV_8 (obj_desc->field_unit.length + 7); +- +- +- actual_byte_length = buffer_length; +- if (buffer_length > byte_field_length) { +- actual_byte_length = byte_field_length; +- } +- +- /* TBD: should these round down to a power of 2? */ +- +- if (DIV_8 (bit_granularity) > byte_field_length) { +- bit_granularity = MUL_8(byte_field_length); +- } +- +- if (byte_granularity > byte_field_length) { +- byte_granularity = byte_field_length; +- } +- +- +- /* Convert byte count to datum count, round up if necessary */ +- +- datum_length = (actual_byte_length + (byte_granularity-1)) / byte_granularity; +- +- +- /* Get the global lock if needed */ +- +- locked = acpi_aml_acquire_global_lock (obj_desc->field_unit.lock_rule); +- +- +- /* Perform the actual read or write of the buffer */ +- +- switch (mode) +- { +- case ACPI_READ: +- +- status = acpi_aml_read_field (obj_desc, buffer, buffer_length, +- actual_byte_length, datum_length, +- bit_granularity, byte_granularity); +- break; +- +- +- case ACPI_WRITE: +- +- status = acpi_aml_write_field (obj_desc, buffer, buffer_length, +- actual_byte_length, datum_length, +- bit_granularity, byte_granularity); +- break; +- +- +- default: +- +- status = AE_BAD_PARAMETER; +- break; +- } +- +- +- /* Release global lock if we acquired it earlier */ +- +- acpi_aml_release_global_lock (locked); +- +- return (status); +-} +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/amfldio.c linux/drivers/acpi/interpreter/amfldio.c +--- /usr/src/linux/drivers/acpi/interpreter/amfldio.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/interpreter/amfldio.c Wed Dec 31 16:00:00 1969 +@@ -1,685 +0,0 @@ +-/****************************************************************************** +- * +- * Module Name: amfldio - Aml Field I/O +- * $Revision: 39 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acinterp.h" +-#include "amlcode.h" +-#include "acnamesp.h" +-#include "achware.h" +-#include "acevents.h" +- +- +-#define _COMPONENT INTERPRETER +- MODULE_NAME ("amfldio") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_read_field_data +- * +- * PARAMETERS: *Obj_desc - Field to be read +- * *Value - Where to store value +- * Field_bit_width - Field Width in bits (8, 16, or 32) +- * +- * RETURN: Status +- * +- * DESCRIPTION: Retrieve the value of the given field +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_read_field_data ( +- ACPI_OPERAND_OBJECT *obj_desc, +- u32 field_byte_offset, +- u32 field_bit_width, +- u32 *value) +-{ +- ACPI_STATUS status; +- ACPI_OPERAND_OBJECT *rgn_desc = NULL; +- ACPI_PHYSICAL_ADDRESS address; +- u32 local_value = 0; +- u32 field_byte_width; +- +- +- /* Obj_desc is validated by callers */ +- +- if (obj_desc) { +- rgn_desc = obj_desc->field.container; +- } +- +- +- field_byte_width = DIV_8 (field_bit_width); +- status = acpi_aml_setup_field (obj_desc, rgn_desc, field_bit_width); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- /* Setup_field validated Rgn_desc and Field_bit_width */ +- +- if (!value) { +- value = &local_value; /* support reads without saving value */ +- } +- +- +- /* +- * Set offset to next multiple of field width, +- * add region base address and offset within the field +- */ +- address = rgn_desc->region.address + +- (obj_desc->field.offset * field_byte_width) + +- field_byte_offset; +- +- +- /* Invoke the appropriate Address_space/Op_region handler */ +- +- status = acpi_ev_address_space_dispatch (rgn_desc, ADDRESS_SPACE_READ, +- address, field_bit_width, value); +- +- +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_read_field +- * +- * PARAMETERS: *Obj_desc - Field to be read +- * *Value - Where to store value +- * Field_bit_width - Field Width in bits (8, 16, or 32) +- * +- * RETURN: Status +- * +- * DESCRIPTION: Retrieve the value of the given field +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_read_field ( +- ACPI_OPERAND_OBJECT *obj_desc, +- void *buffer, +- u32 buffer_length, +- u32 byte_length, +- u32 datum_length, +- u32 bit_granularity, +- u32 byte_granularity) +-{ +- ACPI_STATUS status; +- u32 this_field_byte_offset; +- u32 this_field_datum_offset; +- u32 previous_raw_datum; +- u32 this_raw_datum = 0; +- u32 valid_field_bits; +- u32 mask; +- u32 merged_datum = 0; +- +- +- /* +- * Clear the caller's buffer (the whole buffer length as given) +- * This is very important, especially in the cases where a byte is read, +- * but the buffer is really a u32 (4 bytes). +- */ +- +- MEMSET (buffer, 0, buffer_length); +- +- /* Read the first raw datum to prime the loop */ +- +- this_field_byte_offset = 0; +- this_field_datum_offset= 0; +- +- status = acpi_aml_read_field_data (obj_desc, this_field_byte_offset, bit_granularity, +- &previous_raw_datum); +- if (ACPI_FAILURE (status)) { +- goto cleanup; +- } +- +- /* We might actually be done if the request fits in one datum */ +- +- if ((datum_length == 1) && +- ((obj_desc->field.bit_offset + obj_desc->field_unit.length) <= +- (u16) bit_granularity)) +- { +- merged_datum = previous_raw_datum; +- +- merged_datum = (merged_datum >> obj_desc->field.bit_offset); +- +- valid_field_bits = obj_desc->field_unit.length % bit_granularity; +- if (valid_field_bits) { +- mask = (((u32) 1 << valid_field_bits) - (u32) 1); +- merged_datum &= mask; +- } +- +- +- /* +- * Place the Merged_datum into the proper format and return buffer +- * field +- */ +- +- switch (byte_granularity) +- { +- case 1: +- ((u8 *) buffer) [this_field_datum_offset] = (u8) merged_datum; +- break; +- +- case 2: +- MOVE_UNALIGNED16_TO_16 (&(((u16 *) buffer)[this_field_datum_offset]), &merged_datum); +- break; +- +- case 4: +- MOVE_UNALIGNED32_TO_32 (&(((u32 *) buffer)[this_field_datum_offset]), &merged_datum); +- break; +- } +- +- this_field_byte_offset = 1; +- this_field_datum_offset = 1; +- } +- +- else { +- /* We need to get more raw data to complete one or more field data */ +- +- while (this_field_datum_offset < datum_length) { +- /* +- * If the field is aligned on a byte boundary, we don't want +- * to perform a final read, since this would potentially read +- * past the end of the region. +- * +- * TBD: [Investigate] It may make more sense to just split the aligned +- * and non-aligned cases since the aligned case is so very simple, +- */ +- if ((obj_desc->field.bit_offset != 0) || +- ((obj_desc->field.bit_offset == 0) && +- (this_field_datum_offset < (datum_length -1)))) +- { +- /* +- * Get the next raw datum, it contains some or all bits +- * of the current field datum +- */ +- +- status = acpi_aml_read_field_data (obj_desc, +- this_field_byte_offset + byte_granularity, +- bit_granularity, &this_raw_datum); +- if (ACPI_FAILURE (status)) { +- goto cleanup; +- } +- +- /* Before merging the data, make sure the unused bits are clear */ +- +- switch (byte_granularity) +- { +- case 1: +- this_raw_datum &= 0x000000FF; +- previous_raw_datum &= 0x000000FF; +- break; +- +- case 2: +- this_raw_datum &= 0x0000FFFF; +- previous_raw_datum &= 0x0000FFFF; +- break; +- } +- } +- +- +- /* +- * Put together bits of the two raw data to make a complete +- * field datum +- */ +- +- +- if (obj_desc->field.bit_offset != 0) { +- merged_datum = +- (previous_raw_datum >> obj_desc->field.bit_offset) | +- (this_raw_datum << (bit_granularity - obj_desc->field.bit_offset)); +- } +- +- else { +- merged_datum = previous_raw_datum; +- } +- +- /* +- * Prepare the merged datum for storing into the caller's +- * buffer. It is possible to have a 32-bit buffer +- * (Byte_granularity == 4), but a Obj_desc->Field.Length +- * of 8 or 16, meaning that the upper bytes of merged data +- * are undesired. This section fixes that. +- */ +- switch (obj_desc->field.length) +- { +- case 8: +- merged_datum &= 0x000000FF; +- break; +- +- case 16: +- merged_datum &= 0x0000FFFF; +- break; +- } +- +- /* +- * Now store the datum in the caller's buffer, according to +- * the data type +- */ +- switch (byte_granularity) +- { +- case 1: +- ((u8 *) buffer) [this_field_datum_offset] = (u8) merged_datum; +- break; +- +- case 2: +- MOVE_UNALIGNED16_TO_16 (&(((u16 *) buffer) [this_field_datum_offset]), &merged_datum); +- break; +- +- case 4: +- MOVE_UNALIGNED32_TO_32 (&(((u32 *) buffer) [this_field_datum_offset]), &merged_datum); +- break; +- } +- +- /* +- * Save the most recent datum since it contains bits of +- * the *next* field datum +- */ +- +- previous_raw_datum = this_raw_datum; +- +- this_field_byte_offset += byte_granularity; +- this_field_datum_offset++; +- +- } /* while */ +- } +- +-cleanup: +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_write_field_data +- * +- * PARAMETERS: *Obj_desc - Field to be set +- * Value - Value to store +- * Field_bit_width - Field Width in bits (8, 16, or 32) +- * +- * RETURN: Status +- * +- * DESCRIPTION: Store the value into the given field +- * +- ******************************************************************************/ +- +-static ACPI_STATUS +-acpi_aml_write_field_data ( +- ACPI_OPERAND_OBJECT *obj_desc, +- u32 field_byte_offset, +- u32 field_bit_width, +- u32 value) +-{ +- ACPI_STATUS status = AE_OK; +- ACPI_OPERAND_OBJECT *rgn_desc = NULL; +- ACPI_PHYSICAL_ADDRESS address; +- u32 field_byte_width; +- +- +- /* Obj_desc is validated by callers */ +- +- if (obj_desc) { +- rgn_desc = obj_desc->field.container; +- } +- +- field_byte_width = DIV_8 (field_bit_width); +- status = acpi_aml_setup_field (obj_desc, rgn_desc, field_bit_width); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- +- /* +- * Set offset to next multiple of field width, +- * add region base address and offset within the field +- */ +- address = rgn_desc->region.address + +- (obj_desc->field.offset * field_byte_width) + +- field_byte_offset; +- +- /* Invoke the appropriate Address_space/Op_region handler */ +- +- status = acpi_ev_address_space_dispatch (rgn_desc, ADDRESS_SPACE_WRITE, +- address, field_bit_width, &value); +- +- +- +- return (status); +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Acpi_aml_write_field_data_with_update_rule +- * +- * PARAMETERS: *Obj_desc - Field to be set +- * Value - Value to store +- * Field_bit_width - Field Width in bits (8, 16, or 32) +- * +- * RETURN: Status +- * +- * DESCRIPTION: Apply the field update rule to a field write +- * +- ****************************************************************************/ +- +-static ACPI_STATUS +-acpi_aml_write_field_data_with_update_rule ( +- ACPI_OPERAND_OBJECT *obj_desc, +- u32 mask, +- u32 field_value, +- u32 this_field_byte_offset, +- u32 bit_granularity) +-{ +- ACPI_STATUS status = AE_OK; +- u32 merged_value; +- u32 current_value; +- +- +- /* Start with the new bits */ +- +- merged_value = field_value; +- +- +- /* Decode the update rule */ +- +- switch (obj_desc->field.update_rule) +- { +- +- case UPDATE_PRESERVE: +- +- /* Check if update rule needs to be applied (not if mask is all ones) */ +- +- /* The left shift drops the bits we want to ignore. */ +- if ((~mask << (sizeof(mask)*8 - bit_granularity)) != 0) { +- /* +- * Read the current contents of the byte/word/dword containing +- * the field, and merge with the new field value. +- */ +- status = acpi_aml_read_field_data (obj_desc, this_field_byte_offset, +- bit_granularity, ¤t_value); +- merged_value |= (current_value & ~mask); +- } +- break; +- +- +- case UPDATE_WRITE_AS_ONES: +- +- /* Set positions outside the field to all ones */ +- +- merged_value |= ~mask; +- break; +- +- +- case UPDATE_WRITE_AS_ZEROS: +- +- /* Set positions outside the field to all zeros */ +- +- merged_value &= mask; +- break; +- +- +- default: +- status = AE_AML_OPERAND_VALUE; +- } +- +- +- /* Write the merged value */ +- +- if (ACPI_SUCCESS (status)) { +- status = acpi_aml_write_field_data (obj_desc, this_field_byte_offset, +- bit_granularity, merged_value); +- } +- +- return (status); +-} +- +- +-/***************************************************************************** +- * +- * FUNCTION: Acpi_aml_write_field +- * +- * PARAMETERS: *Obj_desc - Field to be set +- * Value - Value to store +- * Field_bit_width - Field Width in bits (8, 16, or 32) +- * +- * RETURN: Status +- * +- * DESCRIPTION: Store the value into the given field +- * +- ****************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_write_field ( +- ACPI_OPERAND_OBJECT *obj_desc, +- void *buffer, +- u32 buffer_length, +- u32 byte_length, +- u32 datum_length, +- u32 bit_granularity, +- u32 byte_granularity) +-{ +- ACPI_STATUS status; +- u32 this_field_byte_offset; +- u32 this_field_datum_offset; +- u32 mask; +- u32 merged_datum; +- u32 previous_raw_datum; +- u32 this_raw_datum; +- u32 field_value; +- u32 valid_field_bits; +- +- +- /* +- * Break the request into up to three parts: +- * non-aligned part at start, aligned part in middle, non-aligned part +- * at end --- Just like an I/O request --- +- */ +- +- this_field_byte_offset = 0; +- this_field_datum_offset= 0; +- +- /* Get a datum */ +- +- switch (byte_granularity) +- { +- case 1: +- previous_raw_datum = ((u8 *) buffer) [this_field_datum_offset]; +- break; +- +- case 2: +- MOVE_UNALIGNED16_TO_32 (&previous_raw_datum, &(((u16 *) buffer) [this_field_datum_offset])); +- break; +- +- case 4: +- MOVE_UNALIGNED32_TO_32 (&previous_raw_datum, &(((u32 *) buffer) [this_field_datum_offset])); +- break; +- +- default: +- status = AE_AML_OPERAND_VALUE; +- goto cleanup; +- } +- +- +- /* +- * Write a partial field datum if field does not begin on a datum boundary +- * +- * Construct Mask with 1 bits where the field is, 0 bits elsewhere +- * +- * 1) Bits above the field +- */ +- +- mask = (((u32)(-1)) << (u32)obj_desc->field.bit_offset); +- +- /* 2) Only the bottom 5 bits are valid for a shift operation. */ +- +- if ((obj_desc->field.bit_offset + obj_desc->field_unit.length) < 32) { +- /* Bits above the field */ +- +- mask &= (~(((u32)(-1)) << ((u32)obj_desc->field.bit_offset + +- (u32)obj_desc->field_unit.length))); +- } +- +- /* 3) Shift and mask the value into the field position */ +- +- field_value = (previous_raw_datum << obj_desc->field.bit_offset) & mask; +- +- status = acpi_aml_write_field_data_with_update_rule (obj_desc, mask, field_value, +- this_field_byte_offset, +- bit_granularity); +- if (ACPI_FAILURE (status)) { +- goto cleanup; +- } +- +- +- /* If the field fits within one datum, we are done. */ +- +- if ((datum_length == 1) && +- ((obj_desc->field.bit_offset + obj_desc->field_unit.length) <= +- (u16) bit_granularity)) +- { +- goto cleanup; +- } +- +- /* +- * We don't need to worry about the update rule for these data, because +- * all of the bits are part of the field. +- * +- * Can't write the last datum, however, because it might contain bits that +- * are not part of the field -- the update rule must be applied. +- */ +- +- while (this_field_datum_offset < (datum_length - 1)) { +- this_field_datum_offset++; +- +- /* Get the next raw datum, it contains bits of the current field datum... */ +- +- switch (byte_granularity) +- { +- case 1: +- this_raw_datum = ((u8 *) buffer) [this_field_datum_offset]; +- break; +- +- case 2: +- MOVE_UNALIGNED16_TO_32 (&this_raw_datum, &(((u16 *) buffer) [this_field_datum_offset])); +- break; +- +- case 4: +- MOVE_UNALIGNED32_TO_32 (&this_raw_datum, &(((u32 *) buffer) [this_field_datum_offset])); +- break; +- +- default: +- status = AE_AML_OPERAND_VALUE; +- goto cleanup; +- } +- +- /* +- * Put together bits of the two raw data to make a complete field +- * datum +- */ +- +- if (obj_desc->field.bit_offset != 0) { +- merged_datum = +- (previous_raw_datum >> (bit_granularity - obj_desc->field.bit_offset)) | +- (this_raw_datum << obj_desc->field.bit_offset); +- } +- +- else { +- merged_datum = this_raw_datum; +- } +- +- /* Now write the completed datum */ +- +- +- status = acpi_aml_write_field_data (obj_desc, +- this_field_byte_offset + byte_granularity, +- bit_granularity, merged_datum); +- if (ACPI_FAILURE (status)) { +- goto cleanup; +- } +- +- +- /* +- * Save the most recent datum since it contains bits of +- * the *next* field datum +- */ +- +- previous_raw_datum = this_raw_datum; +- +- this_field_byte_offset += byte_granularity; +- +- } /* while */ +- +- +- /* Write a partial field datum if field does not end on a datum boundary */ +- +- if ((obj_desc->field_unit.length + obj_desc->field_unit.bit_offset) % +- bit_granularity) +- { +- switch (byte_granularity) +- { +- case 1: +- this_raw_datum = ((u8 *) buffer) [this_field_datum_offset]; +- break; +- +- case 2: +- MOVE_UNALIGNED16_TO_32 (&this_raw_datum, &(((u16 *) buffer) [this_field_datum_offset])); +- break; +- +- case 4: +- MOVE_UNALIGNED32_TO_32 (&this_raw_datum, &(((u32 *) buffer) [this_field_datum_offset])); +- break; +- } +- +- /* Construct Mask with 1 bits where the field is, 0 bits elsewhere */ +- +- valid_field_bits = ((obj_desc->field_unit.length % bit_granularity) + +- obj_desc->field.bit_offset); +- +- mask = (((u32) 1 << valid_field_bits) - (u32) 1); +- +- /* Shift and mask the value into the field position */ +- +- field_value = (previous_raw_datum >> +- (bit_granularity - obj_desc->field.bit_offset)) & mask; +- +- status = acpi_aml_write_field_data_with_update_rule (obj_desc, mask, field_value, +- this_field_byte_offset + byte_granularity, +- bit_granularity); +- if (ACPI_FAILURE (status)) { +- goto cleanup; +- } +- } +- +- +-cleanup: +- +- return (status); +-} +- +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/ammisc.c linux/drivers/acpi/interpreter/ammisc.c +--- /usr/src/linux/drivers/acpi/interpreter/ammisc.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/interpreter/ammisc.c Wed Dec 31 16:00:00 1969 +@@ -1,529 +0,0 @@ +- +-/****************************************************************************** +- * +- * Module Name: ammisc - ACPI AML (p-code) execution - specific opcodes +- * $Revision: 73 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acparser.h" +-#include "acinterp.h" +-#include "amlcode.h" +-#include "acdispat.h" +- +- +-#define _COMPONENT INTERPRETER +- MODULE_NAME ("ammisc") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_exec_fatal +- * +- * PARAMETERS: none +- * +- * RETURN: Status. If the OS returns from the OSD call, we just keep +- * on going. +- * +- * DESCRIPTION: Execute Fatal operator +- * +- * ACPI SPECIFICATION REFERENCES: +- * Def_fatal := Fatal_op Fatal_type Fatal_code Fatal_arg +- * Fatal_type := Byte_data +- * Fatal_code := DWord_data +- * Fatal_arg := Term_arg=>Integer +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_exec_fatal ( +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_OPERAND_OBJECT *type_desc; +- ACPI_OPERAND_OBJECT *code_desc; +- ACPI_OPERAND_OBJECT *arg_desc; +- ACPI_STATUS status; +- +- +- /* Resolve operands */ +- +- status = acpi_aml_resolve_operands (AML_FATAL_OP, WALK_OPERANDS, walk_state); +- /* Get operands */ +- +- status |= acpi_ds_obj_stack_pop_object (&arg_desc, walk_state); +- status |= acpi_ds_obj_stack_pop_object (&code_desc, walk_state); +- status |= acpi_ds_obj_stack_pop_object (&type_desc, walk_state); +- if (ACPI_FAILURE (status)) { +- /* Invalid parameters on object stack */ +- +- goto cleanup; +- } +- +- +- /* Def_fatal := Fatal_op Fatal_type Fatal_code Fatal_arg */ +- +- +- /* +- * TBD: [Unhandled] call OSD interface to notify OS of fatal error +- * requiring shutdown! +- */ +- +- +-cleanup: +- +- /* Free the operands */ +- +- acpi_cm_remove_reference (arg_desc); +- acpi_cm_remove_reference (code_desc); +- acpi_cm_remove_reference (type_desc); +- +- +- /* If we get back from the OS call, we might as well keep going. */ +- +- REPORT_WARNING (("An AML \"fatal\" Opcode (Fatal_op) was executed\n")); +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_exec_index +- * +- * PARAMETERS: none +- * +- * RETURN: Status +- * +- * DESCRIPTION: Execute Index operator +- * +- * ALLOCATION: Deletes one operand descriptor -- other remains on stack +- * +- * ACPI SPECIFICATION REFERENCES: +- * Def_index := Index_op Buff_pkg_obj Index_value Result +- * Index_value := Term_arg=>Integer +- * Name_string := <Root_char Name_path> | <Prefix_path Name_path> +- * Result := Super_name +- * Super_name := Name_string | Arg_obj | Local_obj | Debug_obj | Def_index +- * Local4_op | Local5_op | Local6_op | Local7_op +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_exec_index ( +- ACPI_WALK_STATE *walk_state, +- ACPI_OPERAND_OBJECT **return_desc) +-{ +- ACPI_OPERAND_OBJECT *obj_desc; +- ACPI_OPERAND_OBJECT *idx_desc; +- ACPI_OPERAND_OBJECT *res_desc; +- ACPI_OPERAND_OBJECT *ret_desc = NULL; +- ACPI_OPERAND_OBJECT *tmp_desc; +- ACPI_STATUS status; +- +- +- /* Resolve operands */ +- /* First operand can be either a package or a buffer */ +- +- status = acpi_aml_resolve_operands (AML_INDEX_OP, WALK_OPERANDS, walk_state); +- /* Get all operands */ +- +- status |= acpi_ds_obj_stack_pop_object (&res_desc, walk_state); +- status |= acpi_ds_obj_stack_pop_object (&idx_desc, walk_state); +- status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); +- if (ACPI_FAILURE (status)) { +- /* Invalid parameters on object stack */ +- +- goto cleanup; +- } +- +- +- /* Create the internal return object */ +- +- ret_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_REFERENCE); +- if (!ret_desc) { +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- +- /* +- * At this point, the Obj_desc operand is either a Package or a Buffer +- */ +- +- if (obj_desc->common.type == ACPI_TYPE_PACKAGE) { +- /* Object to be indexed is a Package */ +- +- if (idx_desc->integer.value >= obj_desc->package.count) { +- status = AE_AML_PACKAGE_LIMIT; +- goto cleanup; +- } +- +- if ((res_desc->common.type == INTERNAL_TYPE_REFERENCE) && +- (res_desc->reference.op_code == AML_ZERO_OP)) +- { +- /* +- * There is no actual result descriptor (the Zero_op Result +- * descriptor is a placeholder), so just delete the placeholder and +- * return a reference to the package element +- */ +- +- acpi_cm_remove_reference (res_desc); +- } +- +- else { +- /* +- * Each element of the package is an internal object. Get the one +- * we are after. +- */ +- +- tmp_desc = obj_desc->package.elements[idx_desc->integer.value]; +- ret_desc->reference.op_code = AML_INDEX_OP; +- ret_desc->reference.target_type = tmp_desc->common.type; +- ret_desc->reference.object = tmp_desc; +- +- status = acpi_aml_exec_store (ret_desc, res_desc, walk_state); +- ret_desc->reference.object = NULL; +- } +- +- /* +- * The local return object must always be a reference to the package element, +- * not the element itself. +- */ +- ret_desc->reference.op_code = AML_INDEX_OP; +- ret_desc->reference.target_type = ACPI_TYPE_PACKAGE; +- ret_desc->reference.where = &obj_desc->package.elements[idx_desc->integer.value]; +- } +- +- else { +- /* Object to be indexed is a Buffer */ +- +- if (idx_desc->integer.value >= obj_desc->buffer.length) { +- status = AE_AML_BUFFER_LIMIT; +- goto cleanup; +- } +- +- ret_desc->reference.op_code = AML_INDEX_OP; +- ret_desc->reference.target_type = ACPI_TYPE_BUFFER_FIELD; +- ret_desc->reference.object = obj_desc; +- ret_desc->reference.offset = (u32) idx_desc->integer.value; +- +- status = acpi_aml_exec_store (ret_desc, res_desc, walk_state); +- } +- +- +-cleanup: +- +- /* Always delete operands */ +- +- acpi_cm_remove_reference (obj_desc); +- acpi_cm_remove_reference (idx_desc); +- +- /* Delete return object on error */ +- +- if (ACPI_FAILURE (status)) { +- acpi_cm_remove_reference (res_desc); +- +- if (ret_desc) { +- acpi_cm_remove_reference (ret_desc); +- ret_desc = NULL; +- } +- } +- +- /* Set the return object and exit */ +- +- *return_desc = ret_desc; +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_exec_match +- * +- * PARAMETERS: none +- * +- * RETURN: Status +- * +- * DESCRIPTION: Execute Match operator +- * +- * ACPI SPECIFICATION REFERENCES: +- * Def_match := Match_op Search_pkg Opcode1 Operand1 +- * Opcode2 Operand2 Start_index +- * Opcode1 := Byte_data: MTR, MEQ, MLE, MLT, MGE, or MGT +- * Opcode2 := Byte_data: MTR, MEQ, MLE, MLT, MGE, or MGT +- * Operand1 := Term_arg=>Integer +- * Operand2 := Term_arg=>Integer +- * Search_pkg := Term_arg=>Package_object +- * Start_index := Term_arg=>Integer +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_exec_match ( +- ACPI_WALK_STATE *walk_state, +- ACPI_OPERAND_OBJECT **return_desc) +-{ +- ACPI_OPERAND_OBJECT *pkg_desc; +- ACPI_OPERAND_OBJECT *op1_desc; +- ACPI_OPERAND_OBJECT *V1_desc; +- ACPI_OPERAND_OBJECT *op2_desc; +- ACPI_OPERAND_OBJECT *V2_desc; +- ACPI_OPERAND_OBJECT *start_desc; +- ACPI_OPERAND_OBJECT *ret_desc = NULL; +- ACPI_STATUS status; +- u32 index; +- u32 match_value = (u32) -1; +- +- +- /* Resolve all operands */ +- +- status = acpi_aml_resolve_operands (AML_MATCH_OP, WALK_OPERANDS, walk_state); +- /* Get all operands */ +- +- status |= acpi_ds_obj_stack_pop_object (&start_desc, walk_state); +- status |= acpi_ds_obj_stack_pop_object (&V2_desc, walk_state); +- status |= acpi_ds_obj_stack_pop_object (&op2_desc, walk_state); +- status |= acpi_ds_obj_stack_pop_object (&V1_desc, walk_state); +- status |= acpi_ds_obj_stack_pop_object (&op1_desc, walk_state); +- status |= acpi_ds_obj_stack_pop_object (&pkg_desc, walk_state); +- +- if (ACPI_FAILURE (status)) { +- /* Invalid parameters on object stack */ +- +- goto cleanup; +- } +- +- /* Validate match comparison sub-opcodes */ +- +- if ((op1_desc->integer.value > MAX_MATCH_OPERATOR) || +- (op2_desc->integer.value > MAX_MATCH_OPERATOR)) +- { +- status = AE_AML_OPERAND_VALUE; +- goto cleanup; +- } +- +- index = (u32) start_desc->integer.value; +- if (index >= (u32) pkg_desc->package.count) { +- status = AE_AML_PACKAGE_LIMIT; +- goto cleanup; +- } +- +- ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); +- if (!ret_desc) { +- status = AE_NO_MEMORY; +- goto cleanup; +- +- } +- +- /* +- * Examine each element until a match is found. Within the loop, +- * "continue" signifies that the current element does not match +- * and the next should be examined. +- * Upon finding a match, the loop will terminate via "break" at +- * the bottom. If it terminates "normally", Match_value will be -1 +- * (its initial value) indicating that no match was found. When +- * returned as a Number, this will produce the Ones value as specified. +- */ +- +- for ( ; index < pkg_desc->package.count; ++index) { +- /* +- * Treat any NULL or non-numeric elements as non-matching. +- * TBD [Unhandled] - if an element is a Name, +- * should we examine its value? +- */ +- if (!pkg_desc->package.elements[index] || +- ACPI_TYPE_INTEGER != pkg_desc->package.elements[index]->common.type) +- { +- continue; +- } +- +- /* +- * Within these switch statements: +- * "break" (exit from the switch) signifies a match; +- * "continue" (proceed to next iteration of enclosing +- * "for" loop) signifies a non-match. +- */ +- switch (op1_desc->integer.value) +- { +- +- case MATCH_MTR: /* always true */ +- +- break; +- +- +- case MATCH_MEQ: /* true if equal */ +- +- if (pkg_desc->package.elements[index]->integer.value +- != V1_desc->integer.value) +- { +- continue; +- } +- break; +- +- +- case MATCH_MLE: /* true if less than or equal */ +- +- if (pkg_desc->package.elements[index]->integer.value +- > V1_desc->integer.value) +- { +- continue; +- } +- break; +- +- +- case MATCH_MLT: /* true if less than */ +- +- if (pkg_desc->package.elements[index]->integer.value +- >= V1_desc->integer.value) +- { +- continue; +- } +- break; +- +- +- case MATCH_MGE: /* true if greater than or equal */ +- +- if (pkg_desc->package.elements[index]->integer.value +- < V1_desc->integer.value) +- { +- continue; +- } +- break; +- +- +- case MATCH_MGT: /* true if greater than */ +- +- if (pkg_desc->package.elements[index]->integer.value +- <= V1_desc->integer.value) +- { +- continue; +- } +- break; +- +- +- default: /* undefined */ +- +- continue; +- } +- +- +- switch(op2_desc->integer.value) +- { +- +- case MATCH_MTR: +- +- break; +- +- +- case MATCH_MEQ: +- +- if (pkg_desc->package.elements[index]->integer.value +- != V2_desc->integer.value) +- { +- continue; +- } +- break; +- +- +- case MATCH_MLE: +- +- if (pkg_desc->package.elements[index]->integer.value +- > V2_desc->integer.value) +- { +- continue; +- } +- break; +- +- +- case MATCH_MLT: +- +- if (pkg_desc->package.elements[index]->integer.value +- >= V2_desc->integer.value) +- { +- continue; +- } +- break; +- +- +- case MATCH_MGE: +- +- if (pkg_desc->package.elements[index]->integer.value +- < V2_desc->integer.value) +- { +- continue; +- } +- break; +- +- +- case MATCH_MGT: +- +- if (pkg_desc->package.elements[index]->integer.value +- <= V2_desc->integer.value) +- { +- continue; +- } +- break; +- +- +- default: +- +- continue; +- } +- +- /* Match found: exit from loop */ +- +- match_value = index; +- break; +- } +- +- /* Match_value is the return value */ +- +- ret_desc->integer.value = match_value; +- +- +-cleanup: +- +- /* Free the operands */ +- +- acpi_cm_remove_reference (start_desc); +- acpi_cm_remove_reference (V2_desc); +- acpi_cm_remove_reference (op2_desc); +- acpi_cm_remove_reference (V1_desc); +- acpi_cm_remove_reference (op1_desc); +- acpi_cm_remove_reference (pkg_desc); +- +- +- /* Delete return object on error */ +- +- if (ACPI_FAILURE (status) && +- (ret_desc)) +- { +- acpi_cm_remove_reference (ret_desc); +- ret_desc = NULL; +- } +- +- +- /* Set the return object and exit */ +- +- *return_desc = ret_desc; +- return (status); +-} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/ammonad.c linux/drivers/acpi/interpreter/ammonad.c +--- /usr/src/linux/drivers/acpi/interpreter/ammonad.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/interpreter/ammonad.c Wed Dec 31 16:00:00 1969 +@@ -1,999 +0,0 @@ +- +-/****************************************************************************** +- * +- * Module Name: ammonad - ACPI AML (p-code) execution for monadic operators +- * $Revision: 89 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acparser.h" +-#include "acdispat.h" +-#include "acinterp.h" +-#include "amlcode.h" +-#include "acnamesp.h" +- +- +-#define _COMPONENT INTERPRETER +- MODULE_NAME ("ammonad") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_get_object_reference +- * +- * PARAMETERS: Obj_desc - Create a reference to this object +- * Ret_desc - Where to store the reference +- * +- * RETURN: Status +- * +- * DESCRIPTION: Obtain and return a "reference" to the target object +- * Common code for the Ref_of_op and the Cond_ref_of_op. +- * +- ******************************************************************************/ +- +-static ACPI_STATUS +-acpi_aml_get_object_reference ( +- ACPI_OPERAND_OBJECT *obj_desc, +- ACPI_OPERAND_OBJECT **ret_desc, +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_STATUS status = AE_OK; +- +- +- if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_INTERNAL)) { +- if (obj_desc->common.type != INTERNAL_TYPE_REFERENCE) { +- *ret_desc = NULL; +- status = AE_TYPE; +- goto cleanup; +- } +- +- /* +- * Not a Name -- an indirect name pointer would have +- * been converted to a direct name pointer in Acpi_aml_resolve_operands +- */ +- switch (obj_desc->reference.op_code) +- { +- case AML_LOCAL_OP: +- +- *ret_desc = (void *) acpi_ds_method_data_get_nte (MTH_TYPE_LOCAL, +- (obj_desc->reference.offset), walk_state); +- break; +- +- +- case AML_ARG_OP: +- +- *ret_desc = (void *) acpi_ds_method_data_get_nte (MTH_TYPE_ARG, +- (obj_desc->reference.offset), walk_state); +- break; +- +- +- default: +- +- *ret_desc = NULL; +- status = AE_AML_INTERNAL; +- goto cleanup; +- } +- +- } +- +- else if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) { +- /* Must be a named object; Just return the Node */ +- +- *ret_desc = obj_desc; +- } +- +- else { +- *ret_desc = NULL; +- status = AE_TYPE; +- } +- +- +-cleanup: +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_exec_monadic1 +- * +- * PARAMETERS: Opcode - The opcode to be executed +- * +- * RETURN: Status +- * +- * DESCRIPTION: Execute Type 1 monadic operator with numeric operand on +- * object stack +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_exec_monadic1 ( +- u16 opcode, +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_OPERAND_OBJECT *obj_desc; +- ACPI_STATUS status; +- +- +- /* Resolve all operands */ +- +- status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); +- /* Get all operands */ +- +- status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); +- if (ACPI_FAILURE (status)) { +- goto cleanup; +- } +- +- +- /* Examine the opcode */ +- +- switch (opcode) +- { +- +- /* Def_release := Release_op Mutex_object */ +- +- case AML_RELEASE_OP: +- +- status = acpi_aml_system_release_mutex (obj_desc); +- break; +- +- +- /* Def_reset := Reset_op Acpi_event_object */ +- +- case AML_RESET_OP: +- +- status = acpi_aml_system_reset_event (obj_desc); +- break; +- +- +- /* Def_signal := Signal_op Acpi_event_object */ +- +- case AML_SIGNAL_OP: +- +- status = acpi_aml_system_signal_event (obj_desc); +- break; +- +- +- /* Def_sleep := Sleep_op Msec_time */ +- +- case AML_SLEEP_OP: +- +- acpi_aml_system_do_suspend ((u32) obj_desc->integer.value); +- break; +- +- +- /* Def_stall := Stall_op Usec_time */ +- +- case AML_STALL_OP: +- +- acpi_aml_system_do_stall ((u32) obj_desc->integer.value); +- break; +- +- +- /* Unknown opcode */ +- +- default: +- +- REPORT_ERROR (("Acpi_aml_exec_monadic1: Unknown monadic opcode %X\n", +- opcode)); +- status = AE_AML_BAD_OPCODE; +- break; +- +- } /* switch */ +- +- +-cleanup: +- +- /* Always delete the operand */ +- +- acpi_cm_remove_reference (obj_desc); +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_exec_monadic2_r +- * +- * PARAMETERS: Opcode - The opcode to be executed +- * +- * RETURN: Status +- * +- * DESCRIPTION: Execute Type 2 monadic operator with numeric operand and +- * result operand on operand stack +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_exec_monadic2_r ( +- u16 opcode, +- ACPI_WALK_STATE *walk_state, +- ACPI_OPERAND_OBJECT **return_desc) +-{ +- ACPI_OPERAND_OBJECT *obj_desc; +- ACPI_OPERAND_OBJECT *res_desc; +- ACPI_OPERAND_OBJECT *ret_desc = NULL; +- ACPI_OPERAND_OBJECT *ret_desc2 = NULL; +- u32 res_val; +- ACPI_STATUS status; +- u32 i; +- u32 j; +- ACPI_INTEGER digit; +- +- +- /* Resolve all operands */ +- +- status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); +- /* Get all operands */ +- +- status |= acpi_ds_obj_stack_pop_object (&res_desc, walk_state); +- status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); +- if (ACPI_FAILURE (status)) { +- goto cleanup; +- } +- +- +- /* Create a return object of type NUMBER for most opcodes */ +- +- switch (opcode) +- { +- case AML_BIT_NOT_OP: +- case AML_FIND_SET_LEFT_BIT_OP: +- case AML_FIND_SET_RIGHT_BIT_OP: +- case AML_FROM_BCD_OP: +- case AML_TO_BCD_OP: +- case AML_COND_REF_OF_OP: +- +- ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); +- if (!ret_desc) { +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- break; +- } +- +- +- switch (opcode) +- { +- /* Def_not := Not_op Operand Result */ +- +- case AML_BIT_NOT_OP: +- +- ret_desc->integer.value = ~obj_desc->integer.value; +- break; +- +- +- /* Def_find_set_left_bit := Find_set_left_bit_op Operand Result */ +- +- case AML_FIND_SET_LEFT_BIT_OP: +- +- ret_desc->integer.value = obj_desc->integer.value; +- +- /* +- * Acpi specification describes Integer type as a little +- * endian unsigned value, so this boundry condition is valid. +- */ +- for (res_val = 0; ret_desc->integer.value && res_val < ACPI_INTEGER_BIT_SIZE; ++res_val) { +- ret_desc->integer.value >>= 1; +- } +- +- ret_desc->integer.value = res_val; +- break; +- +- +- /* Def_find_set_right_bit := Find_set_right_bit_op Operand Result */ +- +- case AML_FIND_SET_RIGHT_BIT_OP: +- +- ret_desc->integer.value = obj_desc->integer.value; +- +- /* +- * Acpi specification describes Integer type as a little +- * endian unsigned value, so this boundry condition is valid. +- */ +- for (res_val = 0; ret_desc->integer.value && res_val < ACPI_INTEGER_BIT_SIZE; ++res_val) { +- ret_desc->integer.value <<= 1; +- } +- +- /* Since returns must be 1-based, subtract from 33 (65) */ +- +- ret_desc->integer.value = res_val == 0 ? 0 : (ACPI_INTEGER_BIT_SIZE + 1) - res_val; +- break; +- +- +- /* Def_from_bDC := From_bCDOp BCDValue Result */ +- +- case AML_FROM_BCD_OP: +- +- /* +- * The 64-bit ACPI integer can hold 16 4-bit BCD integers +- */ +- ret_desc->integer.value = 0; +- for (i = 0; i < ACPI_MAX_BCD_DIGITS; i++) { +- /* Get one BCD digit */ +- +- digit = (ACPI_INTEGER) ((obj_desc->integer.value >> (i * 4)) & 0xF); +- +- /* Check the range of the digit */ +- +- if (digit > 9) { +- status = AE_AML_NUMERIC_OVERFLOW; +- goto cleanup; +- } +- +- if (digit > 0) { +- /* Sum into the result with the appropriate power of 10 */ +- +- for (j = 0; j < i; j++) { +- digit *= 10; +- } +- +- ret_desc->integer.value += digit; +- } +- } +- break; +- +- +- /* Def_to_bDC := To_bCDOp Operand Result */ +- +- case AML_TO_BCD_OP: +- +- +- if (obj_desc->integer.value > ACPI_MAX_BCD_VALUE) { +- status = AE_AML_NUMERIC_OVERFLOW; +- goto cleanup; +- } +- +- ret_desc->integer.value = 0; +- for (i = 0; i < ACPI_MAX_BCD_DIGITS; i++) { +- /* Divide by nth factor of 10 */ +- +- digit = obj_desc->integer.value; +- for (j = 0; j < i; j++) { +- digit /= 10; +- } +- +- /* Create the BCD digit */ +- +- if (digit > 0) { +- ret_desc->integer.value += (ACPI_MODULO (digit, 10) << (i * 4)); +- } +- } +- break; +- +- +- /* Def_cond_ref_of := Cond_ref_of_op Source_object Result */ +- +- case AML_COND_REF_OF_OP: +- +- /* +- * This op is a little strange because the internal return value is +- * different than the return value stored in the result descriptor +- * (There are really two return values) +- */ +- +- if ((ACPI_NAMESPACE_NODE *) obj_desc == acpi_gbl_root_node) { +- /* +- * This means that the object does not exist in the namespace, +- * return FALSE +- */ +- +- ret_desc->integer.value = 0; +- +- /* +- * Must delete the result descriptor since there is no reference +- * being returned +- */ +- +- acpi_cm_remove_reference (res_desc); +- goto cleanup; +- } +- +- /* Get the object reference and store it */ +- +- status = acpi_aml_get_object_reference (obj_desc, &ret_desc2, walk_state); +- if (ACPI_FAILURE (status)) { +- goto cleanup; +- } +- +- status = acpi_aml_exec_store (ret_desc2, res_desc, walk_state); +- +- /* The object exists in the namespace, return TRUE */ +- +- ret_desc->integer.value = ACPI_INTEGER_MAX; +- goto cleanup; +- break; +- +- +- case AML_STORE_OP: +- +- /* +- * A store operand is typically a number, string, buffer or lvalue +- * TBD: [Unhandled] What about a store to a package? +- */ +- +- /* +- * Do the store, and be careful about deleting the source object, +- * since the object itself may have been stored. +- */ +- +- status = acpi_aml_exec_store (obj_desc, res_desc, walk_state); +- if (ACPI_FAILURE (status)) { +- /* On failure, just delete the Obj_desc */ +- +- acpi_cm_remove_reference (obj_desc); +- } +- +- else { +- /* +- * Normally, we would remove a reference on the Obj_desc parameter; +- * But since it is being used as the internal return object +- * (meaning we would normally increment it), the two cancel out, +- * and we simply don't do anything. +- */ +- *return_desc = obj_desc; +- } +- +- obj_desc = NULL; +- return (status); +- +- break; +- +- +- case AML_DEBUG_OP: +- +- /* Reference, returning an Reference */ +- +- return (AE_OK); +- break; +- +- +- /* +- * These are obsolete opcodes +- */ +- +- /* Def_shift_left_bit := Shift_left_bit_op Source Bit_num */ +- /* Def_shift_right_bit := Shift_right_bit_op Source Bit_num */ +- +- case AML_SHIFT_LEFT_BIT_OP: +- case AML_SHIFT_RIGHT_BIT_OP: +- +- status = AE_SUPPORT; +- goto cleanup; +- break; +- +- +- default: +- +- REPORT_ERROR (("Acpi_aml_exec_monadic2_r: Unknown monadic opcode %X\n", +- opcode)); +- status = AE_AML_BAD_OPCODE; +- goto cleanup; +- } +- +- +- status = acpi_aml_exec_store (ret_desc, res_desc, walk_state); +- +- +-cleanup: +- /* Always delete the operand object */ +- +- acpi_cm_remove_reference (obj_desc); +- +- /* Delete return object(s) on error */ +- +- if (ACPI_FAILURE (status)) { +- acpi_cm_remove_reference (res_desc); /* Result descriptor */ +- if (ret_desc) { +- acpi_cm_remove_reference (ret_desc); +- ret_desc = NULL; +- } +- } +- +- /* Set the return object and exit */ +- +- *return_desc = ret_desc; +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_exec_monadic2 +- * +- * PARAMETERS: Opcode - The opcode to be executed +- * +- * RETURN: Status +- * +- * DESCRIPTION: Execute Type 2 monadic operator with numeric operand: +- * Deref_of_op, Ref_of_op, Size_of_op, Type_op, Increment_op, +- * Decrement_op, LNot_op, +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_exec_monadic2 ( +- u16 opcode, +- ACPI_WALK_STATE *walk_state, +- ACPI_OPERAND_OBJECT **return_desc) +-{ +- ACPI_OPERAND_OBJECT *obj_desc; +- ACPI_OPERAND_OBJECT *tmp_desc; +- ACPI_OPERAND_OBJECT *ret_desc = NULL; +- ACPI_STATUS resolve_status; +- ACPI_STATUS status; +- u32 type; +- ACPI_INTEGER value; +- +- +- /* Attempt to resolve the operands */ +- +- resolve_status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); +- /* Always get all operands */ +- +- status = acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); +- +- +- /* Now we can check the status codes */ +- +- if (ACPI_FAILURE (resolve_status)) { +- goto cleanup; +- } +- +- if (ACPI_FAILURE (status)) { +- goto cleanup; +- } +- +- +- /* Get the operand and decode the opcode */ +- +- +- switch (opcode) +- { +- +- /* Def_lNot := LNot_op Operand */ +- +- case AML_LNOT_OP: +- +- ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); +- if (!ret_desc) { +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- ret_desc->integer.value = !obj_desc->integer.value; +- break; +- +- +- /* Def_decrement := Decrement_op Target */ +- /* Def_increment := Increment_op Target */ +- +- case AML_DECREMENT_OP: +- case AML_INCREMENT_OP: +- +- /* +- * Since we are expecting an Reference on the top of the stack, it +- * can be either an Node or an internal object. +- * +- * TBD: [Future] This may be the prototype code for all cases where +- * an Reference is expected!! 10/99 +- */ +- +- if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) { +- ret_desc = obj_desc; +- } +- +- else { +- /* +- * Duplicate the Reference in a new object so that we can resolve it +- * without destroying the original Reference object +- */ +- +- ret_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_REFERENCE); +- if (!ret_desc) { +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- ret_desc->reference.op_code = obj_desc->reference.op_code; +- ret_desc->reference.offset = obj_desc->reference.offset; +- ret_desc->reference.object = obj_desc->reference.object; +- } +- +- +- /* +- * Convert the Ret_desc Reference to a Number +- * (This deletes the original Ret_desc) +- */ +- +- status = acpi_aml_resolve_operands (AML_LNOT_OP, &ret_desc, walk_state); +- if (ACPI_FAILURE (status)) { +- goto cleanup; +- } +- +- /* Do the actual increment or decrement */ +- +- if (AML_INCREMENT_OP == opcode) { +- ret_desc->integer.value++; +- } +- else { +- ret_desc->integer.value--; +- } +- +- /* Store the result back in the original descriptor */ +- +- status = acpi_aml_exec_store (ret_desc, obj_desc, walk_state); +- +- /* Objdesc was just deleted (because it is an Reference) */ +- +- obj_desc = NULL; +- +- break; +- +- +- /* Def_object_type := Object_type_op Source_object */ +- +- case AML_TYPE_OP: +- +- if (INTERNAL_TYPE_REFERENCE == obj_desc->common.type) { +- /* +- * Not a Name -- an indirect name pointer would have +- * been converted to a direct name pointer in Resolve_operands +- */ +- switch (obj_desc->reference.op_code) +- { +- case AML_ZERO_OP: +- case AML_ONE_OP: +- case AML_ONES_OP: +- +- /* Constants are of type Number */ +- +- type = ACPI_TYPE_INTEGER; +- break; +- +- +- case AML_DEBUG_OP: +- +- /* Per 1.0b spec, Debug object is of type Debug_object */ +- +- type = ACPI_TYPE_DEBUG_OBJECT; +- break; +- +- +- case AML_INDEX_OP: +- +- /* Get the type of this reference (index into another object) */ +- +- type = obj_desc->reference.target_type; +- if (type == ACPI_TYPE_PACKAGE) { +- /* +- * The main object is a package, we want to get the type +- * of the individual package element that is referenced by +- * the index. +- */ +- type = (*(obj_desc->reference.where))->common.type; +- } +- +- break; +- +- +- case AML_LOCAL_OP: +- +- type = acpi_ds_method_data_get_type (MTH_TYPE_LOCAL, +- (obj_desc->reference.offset), walk_state); +- break; +- +- +- case AML_ARG_OP: +- +- type = acpi_ds_method_data_get_type (MTH_TYPE_ARG, +- (obj_desc->reference.offset), walk_state); +- break; +- +- +- default: +- +- REPORT_ERROR (("Acpi_aml_exec_monadic2/Type_op: Internal error - Unknown Reference subtype %X\n", +- obj_desc->reference.op_code)); +- status = AE_AML_INTERNAL; +- goto cleanup; +- } +- } +- +- else { +- /* +- * It's not a Reference, so it must be a direct name pointer. +- */ +- type = acpi_ns_get_type ((ACPI_HANDLE) obj_desc); +- } +- +- /* Allocate a descriptor to hold the type. */ +- +- ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); +- if (!ret_desc) { +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- ret_desc->integer.value = type; +- break; +- +- +- /* Def_size_of := Size_of_op Source_object */ +- +- case AML_SIZE_OF_OP: +- +- if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) { +- obj_desc = acpi_ns_get_attached_object (obj_desc); +- } +- +- if (!obj_desc) { +- value = 0; +- } +- +- else { +- switch (obj_desc->common.type) +- { +- +- case ACPI_TYPE_BUFFER: +- +- value = obj_desc->buffer.length; +- break; +- +- +- case ACPI_TYPE_STRING: +- +- value = obj_desc->string.length; +- break; +- +- +- case ACPI_TYPE_PACKAGE: +- +- value = obj_desc->package.count; +- break; +- +- case INTERNAL_TYPE_REFERENCE: +- +- value = 4; +- break; +- +- default: +- +- status = AE_AML_OPERAND_TYPE; +- goto cleanup; +- } +- } +- +- /* +- * Now that we have the size of the object, create a result +- * object to hold the value +- */ +- +- ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); +- if (!ret_desc) { +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- ret_desc->integer.value = value; +- break; +- +- +- /* Def_ref_of := Ref_of_op Source_object */ +- +- case AML_REF_OF_OP: +- +- status = acpi_aml_get_object_reference (obj_desc, &ret_desc, walk_state); +- if (ACPI_FAILURE (status)) { +- goto cleanup; +- } +- break; +- +- +- /* Def_deref_of := Deref_of_op Obj_reference */ +- +- case AML_DEREF_OF_OP: +- +- +- /* Check for a method local or argument */ +- +- if (!VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) { +- /* +- * Must resolve/dereference the local/arg reference first +- */ +- switch (obj_desc->reference.op_code) +- { +- /* Set Obj_desc to the value of the local/arg */ +- +- case AML_LOCAL_OP: +- +- acpi_ds_method_data_get_value (MTH_TYPE_LOCAL, +- (obj_desc->reference.offset), walk_state, &tmp_desc); +- +- /* +- * Delete our reference to the input object and +- * point to the object just retrieved +- */ +- acpi_cm_remove_reference (obj_desc); +- obj_desc = tmp_desc; +- break; +- +- +- case AML_ARG_OP: +- +- acpi_ds_method_data_get_value (MTH_TYPE_ARG, +- (obj_desc->reference.offset), walk_state, &tmp_desc); +- +- /* +- * Delete our reference to the input object and +- * point to the object just retrieved +- */ +- acpi_cm_remove_reference (obj_desc); +- obj_desc = tmp_desc; +- break; +- +- default: +- +- /* Index op - handled below */ +- break; +- } +- } +- +- +- /* Obj_desc may have changed from the code above */ +- +- if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) { +- /* Get the actual object from the Node (This is the dereference) */ +- +- ret_desc = ((ACPI_NAMESPACE_NODE *) obj_desc)->object; +- +- /* Returning a pointer to the object, add another reference! */ +- +- acpi_cm_add_reference (ret_desc); +- } +- +- else { +- /* +- * This must be a reference object produced by the Index +- * ASL operation -- check internal opcode +- */ +- +- if ((obj_desc->reference.op_code != AML_INDEX_OP) && +- (obj_desc->reference.op_code != AML_REF_OF_OP)) +- { +- status = AE_TYPE; +- goto cleanup; +- } +- +- +- switch (obj_desc->reference.op_code) +- { +- case AML_INDEX_OP: +- +- /* +- * Supported target types for the Index operator are +- * 1) A Buffer +- * 2) A Package +- */ +- +- if (obj_desc->reference.target_type == ACPI_TYPE_BUFFER_FIELD) { +- /* +- * The target is a buffer, we must create a new object that +- * contains one element of the buffer, the element pointed +- * to by the index. +- * +- * NOTE: index into a buffer is NOT a pointer to a +- * sub-buffer of the main buffer, it is only a pointer to a +- * single element (byte) of the buffer! +- */ +- ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); +- if (!ret_desc) { +- status = AE_NO_MEMORY; +- goto cleanup; +- } +- +- tmp_desc = obj_desc->reference.object; +- ret_desc->integer.value = +- tmp_desc->buffer.pointer[obj_desc->reference.offset]; +- +- /* TBD: [Investigate] (see below) Don't add an additional +- * ref! +- */ +- } +- +- else if (obj_desc->reference.target_type == ACPI_TYPE_PACKAGE) { +- /* +- * The target is a package, we want to return the referenced +- * element of the package. We must add another reference to +- * this object, however. +- */ +- +- ret_desc = *(obj_desc->reference.where); +- if (!ret_desc) { +- /* +- * We can't return a NULL dereferenced value. This is +- * an uninitialized package element and is thus a +- * severe error. +- */ +- +- status = AE_AML_UNINITIALIZED_ELEMENT; +- goto cleanup; +- } +- +- acpi_cm_add_reference (ret_desc); +- } +- +- else { +- status = AE_AML_OPERAND_TYPE; +- goto cleanup; +- } +- +- break; +- +- +- case AML_REF_OF_OP: +- +- ret_desc = obj_desc->reference.object; +- +- /* Add another reference to the object! */ +- +- acpi_cm_add_reference (ret_desc); +- break; +- } +- } +- +- break; +- +- +- default: +- +- REPORT_ERROR (("Acpi_aml_exec_monadic2: Unknown monadic opcode %X\n", +- opcode)); +- status = AE_AML_BAD_OPCODE; +- goto cleanup; +- } +- +- +-cleanup: +- +- if (obj_desc) { +- acpi_cm_remove_reference (obj_desc); +- } +- +- /* Delete return object on error */ +- +- if (ACPI_FAILURE (status) && +- (ret_desc)) +- { +- acpi_cm_remove_reference (ret_desc); +- ret_desc = NULL; +- } +- +- *return_desc = ret_desc; +- return (status); +-} +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/amnames.c linux/drivers/acpi/interpreter/amnames.c +--- /usr/src/linux/drivers/acpi/interpreter/amnames.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/interpreter/amnames.c Wed Dec 31 16:00:00 1969 +@@ -1,395 +0,0 @@ +- +-/****************************************************************************** +- * +- * Module Name: amnames - interpreter/scanner name load/execute +- * $Revision: 73 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acinterp.h" +-#include "amlcode.h" +-#include "acnamesp.h" +- +-#define _COMPONENT INTERPRETER +- MODULE_NAME ("amnames") +- +- +-/* AML Package Length encodings */ +- +-#define ACPI_AML_PACKAGE_TYPE1 0x40 +-#define ACPI_AML_PACKAGE_TYPE2 0x4000 +-#define ACPI_AML_PACKAGE_TYPE3 0x400000 +-#define ACPI_AML_PACKAGE_TYPE4 0x40000000 +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_allocate_name_string +- * +- * PARAMETERS: Prefix_count - Count of parent levels. Special cases: +- * (-1) = root, 0 = none +- * Num_name_segs - count of 4-character name segments +- * +- * RETURN: A pointer to the allocated string segment. This segment must +- * be deleted by the caller. +- * +- * DESCRIPTION: Allocate a buffer for a name string. Ensure allocated name +- * string is long enough, and set up prefix if any. +- * +- ******************************************************************************/ +- +-NATIVE_CHAR * +-acpi_aml_allocate_name_string ( +- u32 prefix_count, +- u32 num_name_segs) +-{ +- NATIVE_CHAR *temp_ptr; +- NATIVE_CHAR *name_string; +- u32 size_needed; +- +- +- /* +- * Allow room for all \ and ^ prefixes, all segments, and a Multi_name_prefix. +- * Also, one byte for the null terminator. +- * This may actually be somewhat longer than needed. +- */ +- +- if (prefix_count == (u32) -1) { +- /* Special case for root */ +- +- size_needed = 1 + (ACPI_NAME_SIZE * num_name_segs) + 2 + 1; +- } +- else { +- size_needed = prefix_count + (ACPI_NAME_SIZE * num_name_segs) + 2 + 1; +- } +- +- /* +- * Allocate a buffer for the name. +- * This buffer must be deleted by the caller! +- */ +- +- name_string = acpi_cm_allocate (size_needed); +- if (!name_string) { +- REPORT_ERROR (("Aml_allocate_name_string: name allocation failure\n")); +- return (NULL); +- } +- +- temp_ptr = name_string; +- +- /* Set up Root or Parent prefixes if needed */ +- +- if (prefix_count == (u32) -1) { +- *temp_ptr++ = AML_ROOT_PREFIX; +- } +- +- else { +- while (prefix_count--) { +- *temp_ptr++ = AML_PARENT_PREFIX; +- } +- } +- +- +- /* Set up Dual or Multi prefixes if needed */ +- +- if (num_name_segs > 2) { +- /* Set up multi prefixes */ +- +- *temp_ptr++ = AML_MULTI_NAME_PREFIX_OP; +- *temp_ptr++ = (char) num_name_segs; +- } +- +- else if (2 == num_name_segs) { +- /* Set up dual prefixes */ +- +- *temp_ptr++ = AML_DUAL_NAME_PREFIX; +- } +- +- /* +- * Terminate string following prefixes. Acpi_aml_exec_name_segment() will +- * append the segment(s) +- */ +- +- *temp_ptr = 0; +- +- return (name_string); +-} +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_exec_name_segment +- * +- * PARAMETERS: Interpreter_mode - Current running mode (load1/Load2/Exec) +- * +- * RETURN: Status +- * +- * DESCRIPTION: Execute a name segment (4 bytes) +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_exec_name_segment ( +- u8 **in_aml_address, +- NATIVE_CHAR *name_string) +-{ +- u8 *aml_address = *in_aml_address; +- ACPI_STATUS status = AE_OK; +- u32 index; +- NATIVE_CHAR char_buf[5]; +- +- +- /* +- * If first character is a digit, then we know that we aren't looking at a +- * valid name segment +- */ +- +- char_buf[0] = *aml_address; +- +- if ('0' <= char_buf[0] && char_buf[0] <= '9') { +- return (AE_CTRL_PENDING); +- } +- +- for (index = 4; +- (index > 0) && (acpi_cm_valid_acpi_character (*aml_address)); +- --index) +- { +- char_buf[4 - index] = *aml_address++; +- } +- +- +- /* Valid name segment */ +- +- if (0 == index) { +- /* Found 4 valid characters */ +- +- char_buf[4] = '\0'; +- +- if (name_string) { +- STRCAT (name_string, char_buf); +- } +- +- } +- +- else if (4 == index) { +- /* +- * First character was not a valid name character, +- * so we are looking at something other than a name. +- */ +- status = AE_CTRL_PENDING; +- } +- +- else { +- /* Segment started with one or more valid characters, but fewer than 4 */ +- +- status = AE_AML_BAD_NAME; +- } +- +- *in_aml_address = aml_address; +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_get_name_string +- * +- * PARAMETERS: Data_type - Data type to be associated with this name +- * +- * RETURN: Status +- * +- * DESCRIPTION: Get a name, including any prefixes. +- * +- ******************************************************************************/ +- +- +-ACPI_STATUS +-acpi_aml_get_name_string ( +- OBJECT_TYPE_INTERNAL data_type, +- u8 *in_aml_address, +- NATIVE_CHAR **out_name_string, +- u32 *out_name_length) +-{ +- ACPI_STATUS status = AE_OK; +- u8 *aml_address = in_aml_address; +- NATIVE_CHAR *name_string = NULL; +- u32 num_segments; +- u32 prefix_count = 0; +- u8 prefix = 0; +- u8 has_prefix = FALSE; +- +- +- if (INTERNAL_TYPE_DEF_FIELD == data_type || +- INTERNAL_TYPE_BANK_FIELD == data_type || +- INTERNAL_TYPE_INDEX_FIELD == data_type) +- { +- /* Disallow prefixes for types associated with field names */ +- +- name_string = acpi_aml_allocate_name_string (0, 1); +- if (!name_string) { +- status = AE_NO_MEMORY; +- } +- else { +- status = acpi_aml_exec_name_segment (&aml_address, name_string); +- } +- } +- +- else { +- /* +- * Data_type is not a field name. +- * Examine first character of name for root or parent prefix operators +- */ +- +- switch (*aml_address) +- { +- +- case AML_ROOT_PREFIX: +- +- prefix = *aml_address++; +- /* +- * Remember that we have a Root_prefix -- +- * see comment in Acpi_aml_allocate_name_string() +- */ +- prefix_count = (u32) -1; +- has_prefix = TRUE; +- break; +- +- +- case AML_PARENT_PREFIX: +- +- /* Increment past possibly multiple parent prefixes */ +- +- do +- { +- prefix = *aml_address++; +- ++prefix_count; +- +- } while (*aml_address == AML_PARENT_PREFIX); +- has_prefix = TRUE; +- break; +- +- +- default: +- +- break; +- } +- +- +- /* Examine first character of name for name segment prefix operator */ +- +- switch (*aml_address) +- { +- +- case AML_DUAL_NAME_PREFIX: +- +- prefix = *aml_address++; +- name_string = acpi_aml_allocate_name_string (prefix_count, 2); +- if (!name_string) { +- status = AE_NO_MEMORY; +- break; +- } +- +- /* Indicate that we processed a prefix */ +- has_prefix = TRUE; +- +- status = acpi_aml_exec_name_segment (&aml_address, name_string); +- if (ACPI_SUCCESS (status)) { +- status = acpi_aml_exec_name_segment (&aml_address, name_string); +- } +- break; +- +- +- case AML_MULTI_NAME_PREFIX_OP: +- +- prefix = *aml_address++; +- /* Fetch count of segments remaining in name path */ +- +- num_segments = *aml_address++; +- +- name_string = acpi_aml_allocate_name_string (prefix_count, num_segments); +- if (!name_string) { +- status = AE_NO_MEMORY; +- break; +- } +- +- /* Indicate that we processed a prefix */ +- has_prefix = TRUE; +- +- while (num_segments && +- (status = acpi_aml_exec_name_segment (&aml_address, name_string)) == AE_OK) +- { +- --num_segments; +- } +- +- break; +- +- +- case 0: +- +- /* Null_name valid as of 8-12-98 ASL/AML Grammar Update */ +- +- +- /* Consume the NULL byte */ +- +- aml_address++; +- name_string = acpi_aml_allocate_name_string (prefix_count, 0); +- if (!name_string) { +- status = AE_NO_MEMORY; +- break; +- } +- +- break; +- +- +- default: +- +- /* Name segment string */ +- +- name_string = acpi_aml_allocate_name_string (prefix_count, 1); +- if (!name_string) { +- status = AE_NO_MEMORY; +- break; +- } +- +- status = acpi_aml_exec_name_segment (&aml_address, name_string); +- break; +- +- } /* Switch (Peek_op ()) */ +- } +- +- +- if (AE_CTRL_PENDING == status && has_prefix) { +- /* Ran out of segments after processing a prefix */ +- +- REPORT_ERROR ( +- ("Aml_do_name: Malformed Name at %p\n", name_string)); +- status = AE_AML_BAD_NAME; +- } +- +- +- *out_name_string = name_string; +- *out_name_length = (u32) (aml_address - in_aml_address); +- +- return (status); +-} +- +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/amprep.c linux/drivers/acpi/interpreter/amprep.c +--- /usr/src/linux/drivers/acpi/interpreter/amprep.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/interpreter/amprep.c Wed Dec 31 16:00:00 1969 +@@ -1,405 +0,0 @@ +- +-/****************************************************************************** +- * +- * Module Name: amprep - ACPI AML (p-code) execution - field prep utilities +- * $Revision: 73 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acinterp.h" +-#include "amlcode.h" +-#include "acnamesp.h" +-#include "acparser.h" +- +- +-#define _COMPONENT INTERPRETER +- MODULE_NAME ("amprep") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_decode_field_access_type +- * +- * PARAMETERS: Access - Encoded field access bits +- * +- * RETURN: Field granularity (8, 16, or 32) +- * +- * DESCRIPTION: Decode the Access_type bits of a field definition. +- * +- ******************************************************************************/ +- +-static u32 +-acpi_aml_decode_field_access_type ( +- u32 access, +- u16 length) +-{ +- +- switch (access) +- { +- case ACCESS_ANY_ACC: +- if (length <= 8) { +- return (8); +- } +- else if (length <= 16) { +- return (16); +- } +- else if (length <= 32) { +- return (32); +- } +- else { +- return (8); +- } +- break; +- +- case ACCESS_BYTE_ACC: +- return (8); +- break; +- +- case ACCESS_WORD_ACC: +- return (16); +- break; +- +- case ACCESS_DWORD_ACC: +- return (32); +- break; +- +- default: +- /* Invalid field access type */ +- +- return (0); +- } +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_prep_common_field_objec +- * +- * PARAMETERS: Obj_desc - The field object +- * Field_flags - Access, Lock_rule, or Update_rule. +- * The format of a Field_flag is described +- * in the ACPI specification +- * Field_position - Field position +- * Field_length - Field length +- * +- * RETURN: Status +- * +- * DESCRIPTION: Initialize the areas of the field object that are common +- * to the various types of fields. +- * +- ******************************************************************************/ +- +-static ACPI_STATUS +-acpi_aml_prep_common_field_object ( +- ACPI_OPERAND_OBJECT *obj_desc, +- u8 field_flags, +- u8 field_attribute, +- u32 field_position, +- u32 field_length) +-{ +- u32 granularity; +- +- +- /* +- * Note: the structure being initialized is the +- * ACPI_COMMON_FIELD_INFO; Therefore, we can just use the Field union to +- * access this common area. No structure fields outside of the common area +- * are initialized by this procedure. +- */ +- +- /* Decode the Field_flags */ +- +- obj_desc->field.access = (u8) ((field_flags & ACCESS_TYPE_MASK) +- >> ACCESS_TYPE_SHIFT); +- obj_desc->field.lock_rule = (u8) ((field_flags & LOCK_RULE_MASK) +- >> LOCK_RULE_SHIFT); +- obj_desc->field.update_rule = (u8) ((field_flags & UPDATE_RULE_MASK) +- >> UPDATE_RULE_SHIFT); +- +- /* Other misc fields */ +- +- obj_desc->field.length = (u16) field_length; +- obj_desc->field.access_attribute = field_attribute; +- +- /* Decode the access type so we can compute offsets */ +- +- granularity = acpi_aml_decode_field_access_type (obj_desc->field.access, obj_desc->field.length); +- if (!granularity) { +- return (AE_AML_OPERAND_VALUE); +- } +- +- /* Access granularity based fields */ +- +- obj_desc->field.granularity = (u8) granularity; +- obj_desc->field.bit_offset = (u8) (field_position % granularity); +- obj_desc->field.offset = (u32) field_position / granularity; +- +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_prep_def_field_value +- * +- * PARAMETERS: Node - Owning Node +- * Region - Region in which field is being defined +- * Field_flags - Access, Lock_rule, or Update_rule. +- * The format of a Field_flag is described +- * in the ACPI specification +- * Field_position - Field position +- * Field_length - Field length +- * +- * RETURN: Status +- * +- * DESCRIPTION: Construct an ACPI_OPERAND_OBJECT of type Def_field and +- * connect it to the parent Node. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_prep_def_field_value ( +- ACPI_NAMESPACE_NODE *node, +- ACPI_HANDLE region, +- u8 field_flags, +- u8 field_attribute, +- u32 field_position, +- u32 field_length) +-{ +- ACPI_OPERAND_OBJECT *obj_desc; +- u32 type; +- ACPI_STATUS status; +- +- +- /* Parameter validation */ +- +- if (!region) { +- return (AE_AML_NO_OPERAND); +- } +- +- type = acpi_ns_get_type (region); +- if (type != ACPI_TYPE_REGION) { +- return (AE_AML_OPERAND_TYPE); +- } +- +- /* Allocate a new object */ +- +- obj_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_DEF_FIELD); +- if (!obj_desc) { +- return (AE_NO_MEMORY); +- } +- +- +- /* Obj_desc and Region valid */ +- +- /* Initialize areas of the object that are common to all fields */ +- +- status = acpi_aml_prep_common_field_object (obj_desc, field_flags, field_attribute, +- field_position, field_length); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- /* Initialize areas of the object that are specific to this field type */ +- +- obj_desc->field.container = acpi_ns_get_attached_object (region); +- +- /* An additional reference for the container */ +- +- acpi_cm_add_reference (obj_desc->field.container); +- +- +- /* Debug info */ +- +- /* +- * Store the constructed descriptor (Obj_desc) into the Named_obj whose +- * handle is on TOS, preserving the current type of that Named_obj. +- */ +- status = acpi_ns_attach_object ((ACPI_HANDLE) node, obj_desc, +- (u8) acpi_ns_get_type ((ACPI_HANDLE) node)); +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_prep_bank_field_value +- * +- * PARAMETERS: Node - Owning Node +- * Region - Region in which field is being defined +- * Bank_reg - Bank selection register +- * Bank_val - Value to store in selection register +- * Field_flags - Access, Lock_rule, or Update_rule +- * Field_position - Field position +- * Field_length - Field length +- * +- * RETURN: Status +- * +- * DESCRIPTION: Construct an ACPI_OPERAND_OBJECT of type Bank_field and +- * connect it to the parent Node. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_prep_bank_field_value ( +- ACPI_NAMESPACE_NODE *node, +- ACPI_HANDLE region, +- ACPI_HANDLE bank_reg, +- u32 bank_val, +- u8 field_flags, +- u8 field_attribute, +- u32 field_position, +- u32 field_length) +-{ +- ACPI_OPERAND_OBJECT *obj_desc; +- u32 type; +- ACPI_STATUS status; +- +- +- /* Parameter validation */ +- +- if (!region) { +- return (AE_AML_NO_OPERAND); +- } +- +- type = acpi_ns_get_type (region); +- if (type != ACPI_TYPE_REGION) { +- return (AE_AML_OPERAND_TYPE); +- } +- +- /* Allocate a new object */ +- +- obj_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_BANK_FIELD); +- if (!obj_desc) { +- return (AE_NO_MEMORY); +- } +- +- /* Obj_desc and Region valid */ +- +- /* Initialize areas of the object that are common to all fields */ +- +- status = acpi_aml_prep_common_field_object (obj_desc, field_flags, field_attribute, +- field_position, field_length); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- /* Initialize areas of the object that are specific to this field type */ +- +- obj_desc->bank_field.value = bank_val; +- obj_desc->bank_field.container = acpi_ns_get_attached_object (region); +- obj_desc->bank_field.bank_select = acpi_ns_get_attached_object (bank_reg); +- +- /* An additional reference for the container and bank select */ +- /* TBD: [Restructure] is "Bank_select" ever a real internal object?? */ +- +- acpi_cm_add_reference (obj_desc->bank_field.container); +- acpi_cm_add_reference (obj_desc->bank_field.bank_select); +- +- /* Debug info */ +- +- /* +- * Store the constructed descriptor (Obj_desc) into the Named_obj whose +- * handle is on TOS, preserving the current type of that Named_obj. +- */ +- status = acpi_ns_attach_object ((ACPI_HANDLE) node, obj_desc, +- (u8) acpi_ns_get_type ((ACPI_HANDLE) node)); +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_prep_index_field_value +- * +- * PARAMETERS: Node - Owning Node +- * Index_reg - Index register +- * Data_reg - Data register +- * Field_flags - Access, Lock_rule, or Update_rule +- * Field_position - Field position +- * Field_length - Field length +- * +- * RETURN: Status +- * +- * DESCRIPTION: Construct an ACPI_OPERAND_OBJECT of type Index_field and +- * connect it to the parent Node. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_prep_index_field_value ( +- ACPI_NAMESPACE_NODE *node, +- ACPI_HANDLE index_reg, +- ACPI_HANDLE data_reg, +- u8 field_flags, +- u8 field_attribute, +- u32 field_position, +- u32 field_length) +-{ +- ACPI_OPERAND_OBJECT *obj_desc; +- ACPI_STATUS status; +- +- +- /* Parameter validation */ +- +- if (!index_reg || !data_reg) { +- return (AE_AML_NO_OPERAND); +- } +- +- /* Allocate a new object descriptor */ +- +- obj_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_INDEX_FIELD); +- if (!obj_desc) { +- return (AE_NO_MEMORY); +- } +- +- /* Initialize areas of the object that are common to all fields */ +- +- status = acpi_aml_prep_common_field_object (obj_desc, field_flags, field_attribute, +- field_position, field_length); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- /* Initialize areas of the object that are specific to this field type */ +- +- obj_desc->index_field.value = (u32) (field_position / +- obj_desc->field.granularity); +- obj_desc->index_field.index = index_reg; +- obj_desc->index_field.data = data_reg; +- +- /* Debug info */ +- +- /* +- * Store the constructed descriptor (Obj_desc) into the Named_obj whose +- * handle is on TOS, preserving the current type of that Named_obj. +- */ +- status = acpi_ns_attach_object ((ACPI_HANDLE) node, obj_desc, +- (u8) acpi_ns_get_type ((ACPI_HANDLE) node)); +- +- return (status); +-} +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/amregion.c linux/drivers/acpi/interpreter/amregion.c +--- /usr/src/linux/drivers/acpi/interpreter/amregion.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/interpreter/amregion.c Wed Dec 31 16:00:00 1969 +@@ -1,420 +0,0 @@ +- +-/****************************************************************************** +- * +- * Module Name: amregion - ACPI default Op_region (address space) handlers +- * $Revision: 44 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acinterp.h" +-#include "amlcode.h" +-#include "acnamesp.h" +-#include "achware.h" +-#include "acevents.h" +- +- +-#define _COMPONENT INTERPRETER +- MODULE_NAME ("amregion") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_system_memory_space_handler +- * +- * PARAMETERS: Function - Read or Write operation +- * Address - Where in the space to read or write +- * Bit_width - Field width in bits (8, 16, or 32) +- * Value - Pointer to in or out value +- * Handler_context - Pointer to Handler's context +- * Region_context - Pointer to context specific to the +- * accessed region +- * +- * RETURN: Status +- * +- * DESCRIPTION: Handler for the System Memory address space (Op Region) +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_system_memory_space_handler ( +- u32 function, +- ACPI_PHYSICAL_ADDRESS address, +- u32 bit_width, +- u32 *value, +- void *handler_context, +- void *region_context) +-{ +- ACPI_STATUS status = AE_OK; +- void *logical_addr_ptr = NULL; +- MEM_HANDLER_CONTEXT *mem_info = region_context; +- u32 length; +- +- +- /* Validate and translate the bit width */ +- +- switch (bit_width) +- { +- case 8: +- length = 1; +- break; +- +- case 16: +- length = 2; +- break; +- +- case 32: +- length = 4; +- break; +- +- default: +- return (AE_AML_OPERAND_VALUE); +- break; +- } +- +- +- /* +- * Does the request fit into the cached memory mapping? +- * Is 1) Address below the current mapping? OR +- * 2) Address beyond the current mapping? +- */ +- +- if ((address < mem_info->mapped_physical_address) || +- (((ACPI_INTEGER) address + length) > +- ((ACPI_INTEGER) mem_info->mapped_physical_address + mem_info->mapped_length))) +- { +- /* +- * The request cannot be resolved by the current memory mapping; +- * Delete the existing mapping and create a new one. +- */ +- +- if (mem_info->mapped_length) { +- /* Valid mapping, delete it */ +- +- acpi_os_unmap_memory (mem_info->mapped_logical_address, +- mem_info->mapped_length); +- } +- +- mem_info->mapped_length = 0; /* In case of failure below */ +- +- /* Create a new mapping starting at the address given */ +- +- status = acpi_os_map_memory (address, SYSMEM_REGION_WINDOW_SIZE, +- (void **) &mem_info->mapped_logical_address); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- /* TBD: should these pointers go to 64-bit in all cases ? */ +- +- mem_info->mapped_physical_address = address; +- mem_info->mapped_length = SYSMEM_REGION_WINDOW_SIZE; +- } +- +- +- /* +- * Generate a logical pointer corresponding to the address we want to +- * access +- */ +- +- /* TBD: should these pointers go to 64-bit in all cases ? */ +- +- logical_addr_ptr = mem_info->mapped_logical_address + +- ((ACPI_INTEGER) address - (ACPI_INTEGER) mem_info->mapped_physical_address); +- +- /* Perform the memory read or write */ +- +- switch (function) +- { +- +- case ADDRESS_SPACE_READ: +- +- switch (bit_width) +- { +- case 8: +- *value = (u32)* (u8 *) logical_addr_ptr; +- break; +- +- case 16: +- MOVE_UNALIGNED16_TO_32 (value, logical_addr_ptr); +- break; +- +- case 32: +- MOVE_UNALIGNED32_TO_32 (value, logical_addr_ptr); +- break; +- } +- +- break; +- +- +- case ADDRESS_SPACE_WRITE: +- +- switch (bit_width) +- { +- case 8: +- *(u8 *) logical_addr_ptr = (u8) *value; +- break; +- +- case 16: +- MOVE_UNALIGNED16_TO_16 (logical_addr_ptr, value); +- break; +- +- case 32: +- MOVE_UNALIGNED32_TO_32 (logical_addr_ptr, value); +- break; +- } +- +- break; +- +- +- default: +- status = AE_BAD_PARAMETER; +- break; +- } +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_system_io_space_handler +- * +- * PARAMETERS: Function - Read or Write operation +- * Address - Where in the space to read or write +- * Bit_width - Field width in bits (8, 16, or 32) +- * Value - Pointer to in or out value +- * Handler_context - Pointer to Handler's context +- * Region_context - Pointer to context specific to the +- * accessed region +- * +- * RETURN: Status +- * +- * DESCRIPTION: Handler for the System IO address space (Op Region) +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_system_io_space_handler ( +- u32 function, +- ACPI_PHYSICAL_ADDRESS address, +- u32 bit_width, +- u32 *value, +- void *handler_context, +- void *region_context) +-{ +- ACPI_STATUS status = AE_OK; +- +- +- /* Decode the function parameter */ +- +- switch (function) +- { +- +- case ADDRESS_SPACE_READ: +- +- switch (bit_width) +- { +- /* I/O Port width */ +- +- case 8: +- *value = (u32) acpi_os_in8 ((ACPI_IO_ADDRESS) address); +- break; +- +- case 16: +- *value = (u32) acpi_os_in16 ((ACPI_IO_ADDRESS) address); +- break; +- +- case 32: +- *value = acpi_os_in32 ((ACPI_IO_ADDRESS) address); +- break; +- +- default: +- status = AE_AML_OPERAND_VALUE; +- } +- +- break; +- +- +- case ADDRESS_SPACE_WRITE: +- +- switch (bit_width) +- { +- /* I/O Port width */ +- case 8: +- acpi_os_out8 ((ACPI_IO_ADDRESS) address, (u8) *value); +- break; +- +- case 16: +- acpi_os_out16 ((ACPI_IO_ADDRESS) address, (u16) *value); +- break; +- +- case 32: +- acpi_os_out32 ((ACPI_IO_ADDRESS) address, *value); +- break; +- +- default: +- status = AE_AML_OPERAND_VALUE; +- } +- +- break; +- +- +- default: +- status = AE_BAD_PARAMETER; +- break; +- } +- +- return (status); +-} +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_pci_config_space_handler +- * +- * PARAMETERS: Function - Read or Write operation +- * Address - Where in the space to read or write +- * Bit_width - Field width in bits (8, 16, or 32) +- * Value - Pointer to in or out value +- * Handler_context - Pointer to Handler's context +- * Region_context - Pointer to context specific to the +- * accessed region +- * +- * RETURN: Status +- * +- * DESCRIPTION: Handler for the PCI Config address space (Op Region) +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_pci_config_space_handler ( +- u32 function, +- ACPI_PHYSICAL_ADDRESS address, +- u32 bit_width, +- u32 *value, +- void *handler_context, +- void *region_context) +-{ +- ACPI_STATUS status = AE_OK; +- u32 pci_bus; +- u32 dev_func; +- u8 pci_reg; +- PCI_HANDLER_CONTEXT *PCIcontext; +- +- +- /* +- * The arguments to Acpi_os(Read|Write)Pci_cfg(Byte|Word|Dword) are: +- * +- * Seg_bus - 0xSSSSBBBB - SSSS is the PCI bus segment +- * BBBB is the PCI bus number +- * +- * Dev_func - 0xDDDDFFFF - DDDD is the PCI device number +- * FFFF is the PCI device function number +- * +- * Reg_num - Config space register must be < 40h +- * +- * Value - input value for write, output for read +- * +- */ +- +- PCIcontext = (PCI_HANDLER_CONTEXT *) region_context; +- +- pci_bus = LOWORD(PCIcontext->seg) << 16; +- pci_bus |= LOWORD(PCIcontext->bus); +- +- dev_func = PCIcontext->dev_func; +- +- pci_reg = (u8) address; +- +- switch (function) +- { +- +- case ADDRESS_SPACE_READ: +- +- *value = 0; +- +- switch (bit_width) +- { +- /* PCI Register width */ +- +- case 8: +- status = acpi_os_read_pci_cfg_byte (pci_bus, dev_func, pci_reg, +- (u8 *) value); +- break; +- +- case 16: +- status = acpi_os_read_pci_cfg_word (pci_bus, dev_func, pci_reg, +- (u16 *) value); +- break; +- +- case 32: +- status = acpi_os_read_pci_cfg_dword (pci_bus, dev_func, pci_reg, +- value); +- break; +- +- default: +- status = AE_AML_OPERAND_VALUE; +- +- } /* Switch bit_width */ +- +- break; +- +- +- case ADDRESS_SPACE_WRITE: +- +- switch (bit_width) +- { +- /* PCI Register width */ +- +- case 8: +- status = acpi_os_write_pci_cfg_byte (pci_bus, dev_func, pci_reg, +- *(u8 *) value); +- break; +- +- case 16: +- status = acpi_os_write_pci_cfg_word (pci_bus, dev_func, pci_reg, +- *(u16 *) value); +- break; +- +- case 32: +- status = acpi_os_write_pci_cfg_dword (pci_bus, dev_func, pci_reg, +- *value); +- break; +- +- default: +- status = AE_AML_OPERAND_VALUE; +- +- } /* Switch bit_width */ +- +- break; +- +- +- default: +- +- status = AE_BAD_PARAMETER; +- break; +- +- } +- +- return (status); +-} +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/amresnte.c linux/drivers/acpi/interpreter/amresnte.c +--- /usr/src/linux/drivers/acpi/interpreter/amresnte.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/interpreter/amresnte.c Wed Dec 31 16:00:00 1969 +@@ -1,509 +0,0 @@ +- +-/****************************************************************************** +- * +- * Module Name: amresnte - AML Interpreter object resolution +- * $Revision: 27 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "amlcode.h" +-#include "acparser.h" +-#include "acdispat.h" +-#include "acinterp.h" +-#include "acnamesp.h" +-#include "actables.h" +-#include "acevents.h" +- +- +-#define _COMPONENT INTERPRETER +- MODULE_NAME ("amresnte") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_resolve_node_to_value +- * +- * PARAMETERS: Stack_ptr - Pointer to a location on a stack that contains +- * a pointer to an Node +- * +- * RETURN: Status +- * +- * DESCRIPTION: Resolve a ACPI_NAMESPACE_NODE (Node, +- * A.K.A. a "direct name pointer") +- * +- * Note: for some of the data types, the pointer attached to the Node +- * can be either a pointer to an actual internal object or a pointer into the +- * AML stream itself. These types are currently: +- * +- * ACPI_TYPE_INTEGER +- * ACPI_TYPE_STRING +- * ACPI_TYPE_BUFFER +- * ACPI_TYPE_MUTEX +- * ACPI_TYPE_PACKAGE +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_resolve_node_to_value ( +- ACPI_NAMESPACE_NODE **stack_ptr, +- ACPI_WALK_STATE *walk_state) +- +-{ +- ACPI_STATUS status = AE_OK; +- ACPI_OPERAND_OBJECT *val_desc = NULL; +- ACPI_OPERAND_OBJECT *obj_desc = NULL; +- ACPI_NAMESPACE_NODE *node; +- u8 *aml_pointer = NULL; +- OBJECT_TYPE_INTERNAL entry_type; +- u8 locked; +- u8 attached_aml_pointer = FALSE; +- u8 aml_opcode = 0; +- ACPI_INTEGER temp_val; +- OBJECT_TYPE_INTERNAL object_type; +- +- +- node = *stack_ptr; +- +- +- /* +- * The stack pointer is a "Direct name ptr", and points to a +- * a ACPI_NAMESPACE_NODE (Node). Get the pointer that is attached to +- * the Node. +- */ +- +- val_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) node); +- entry_type = acpi_ns_get_type ((ACPI_HANDLE) node); +- +- /* +- * The Val_desc attached to the Node can be either: +- * 1) An internal ACPI object +- * 2) A pointer into the AML stream (into one of the ACPI system tables) +- */ +- +- if (acpi_tb_system_table_pointer (val_desc)) { +- attached_aml_pointer = TRUE; +- aml_opcode = *((u8 *) val_desc); +- aml_pointer = ((u8 *) val_desc) + 1; +- +- } +- +- +- /* +- * Several Entry_types do not require further processing, so +- * we will return immediately +- */ +- /* Devices rarely have an attached object, return the Node +- * and Method locals and arguments have a pseudo-Node +- */ +- if (entry_type == ACPI_TYPE_DEVICE || +- (node->flags & (ANOBJ_METHOD_ARG | ANOBJ_METHOD_LOCAL))) +- { +- return (AE_OK); +- } +- +- if (!val_desc) { +- return (AE_AML_NO_OPERAND); +- } +- +- /* +- * Action is based on the type of the Node, which indicates the type +- * of the attached object or pointer +- */ +- switch (entry_type) +- { +- +- case ACPI_TYPE_PACKAGE: +- +- if (attached_aml_pointer) { +- /* +- * This means that the package initialization is not parsed +- * -- should not happen +- */ +- return (AE_NOT_IMPLEMENTED); +- } +- +- /* Val_desc is an internal object in all cases by the time we get here */ +- +- if (ACPI_TYPE_PACKAGE != val_desc->common.type) { +- return (AE_AML_OPERAND_TYPE); +- } +- +- /* Return an additional reference to the object */ +- +- obj_desc = val_desc; +- acpi_cm_add_reference (obj_desc); +- break; +- +- +- case ACPI_TYPE_BUFFER: +- +- if (attached_aml_pointer) { +- /* +- * This means that the buffer initialization is not parsed +- * -- should not happen +- */ +- return (AE_NOT_IMPLEMENTED); +- } +- +- /* Val_desc is an internal object in all cases by the time we get here */ +- +- if (ACPI_TYPE_BUFFER != val_desc->common.type) { +- return (AE_AML_OPERAND_TYPE); +- } +- +- /* Return an additional reference to the object */ +- +- obj_desc = val_desc; +- acpi_cm_add_reference (obj_desc); +- break; +- +- +- case ACPI_TYPE_STRING: +- +- if (attached_aml_pointer) { +- /* Allocate a new string object */ +- +- obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_STRING); +- if (!obj_desc) { +- return (AE_NO_MEMORY); +- } +- +- /* Init the internal object */ +- +- obj_desc->string.pointer = (NATIVE_CHAR *) aml_pointer; +- obj_desc->string.length = STRLEN (obj_desc->string.pointer); +- } +- +- else { +- if (ACPI_TYPE_STRING != val_desc->common.type) { +- return (AE_AML_OPERAND_TYPE); +- } +- +- /* Return an additional reference to the object */ +- +- obj_desc = val_desc; +- acpi_cm_add_reference (obj_desc); +- } +- +- break; +- +- +- case ACPI_TYPE_INTEGER: +- +- /* +- * The Node has an attached internal object, make sure that it's a +- * number +- */ +- +- if (ACPI_TYPE_INTEGER != val_desc->common.type) { +- return (AE_AML_OPERAND_TYPE); +- } +- +- /* Return an additional reference to the object */ +- +- obj_desc = val_desc; +- acpi_cm_add_reference (obj_desc); +- break; +- +- +- case INTERNAL_TYPE_DEF_FIELD: +- +- /* +- * TBD: [Investigate] Is this the correct solution? +- * +- * This section was extended to convert to generic buffer if +- * the return length is greater than 32 bits, but still allows +- * for returning a type Number for smaller values because the +- * caller can then apply arithmetic operators on those fields. +- * +- * XXX - Implementation limitation: Fields are implemented as type +- * XXX - Number, but they really are supposed to be type Buffer. +- * XXX - The two are interchangeable only for lengths <= 32 bits. +- */ +- if(val_desc->field.length > 32) { +- object_type = ACPI_TYPE_BUFFER; +- } +- else { +- object_type = ACPI_TYPE_INTEGER; +- } +- +- /* +- * Create the destination buffer object and the buffer space. +- */ +- obj_desc = acpi_cm_create_internal_object (object_type); +- if (!obj_desc) { +- return (AE_NO_MEMORY); +- } +- +- /* +- * Fill in the object specific details +- */ +- if (ACPI_TYPE_BUFFER == object_type) { +- obj_desc->buffer.pointer = acpi_cm_callocate (val_desc->field.length); +- if (!obj_desc->buffer.pointer) { +- acpi_cm_remove_reference(obj_desc); +- return (AE_NO_MEMORY); +- } +- +- obj_desc->buffer.length = val_desc->field.length; +- +- status = acpi_aml_access_named_field (ACPI_READ, (ACPI_HANDLE) node, +- obj_desc->buffer.pointer, obj_desc->buffer.length); +- +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- } +- else { +- status = acpi_aml_access_named_field (ACPI_READ, (ACPI_HANDLE) node, +- &temp_val, sizeof (temp_val)); +- +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- obj_desc->integer.value = temp_val; +- } +- +- +- break; +- +- +- case INTERNAL_TYPE_BANK_FIELD: +- +- if (attached_aml_pointer) { +- return (AE_AML_OPERAND_TYPE); +- } +- +- if (INTERNAL_TYPE_BANK_FIELD != val_desc->common.type) { +- return (AE_AML_OPERAND_TYPE); +- } +- +- +- /* Get the global lock if needed */ +- +- obj_desc = (ACPI_OPERAND_OBJECT *) *stack_ptr; +- locked = acpi_aml_acquire_global_lock (obj_desc->field_unit.lock_rule); +- +- /* Set Index value to select proper Data register */ +- /* perform the update */ +- +- status = acpi_aml_access_named_field (ACPI_WRITE, +- val_desc->bank_field.bank_select, &val_desc->bank_field.value, +- sizeof (val_desc->bank_field.value)); +- +- acpi_aml_release_global_lock (locked); +- +- +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- /* Read Data value */ +- +- status = acpi_aml_access_named_field (ACPI_READ, +- (ACPI_HANDLE) val_desc->bank_field.container, +- &temp_val, sizeof (temp_val)); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- /* Create an object for the result */ +- +- obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); +- if (!obj_desc) { +- return (AE_NO_MEMORY); +- } +- +- obj_desc->integer.value = temp_val; +- break; +- +- +- case INTERNAL_TYPE_INDEX_FIELD: +- +- if (attached_aml_pointer) { +- return (AE_AML_OPERAND_TYPE); +- } +- +- if (INTERNAL_TYPE_INDEX_FIELD != val_desc->common.type) { +- return (AE_AML_OPERAND_TYPE); +- } +- +- +- /* Set Index value to select proper Data register */ +- /* Get the global lock if needed */ +- +- obj_desc = (ACPI_OPERAND_OBJECT *) *stack_ptr; +- locked = acpi_aml_acquire_global_lock (obj_desc->field_unit.lock_rule); +- +- /* Perform the update */ +- +- status = acpi_aml_access_named_field (ACPI_WRITE, +- val_desc->index_field.index, &val_desc->index_field.value, +- sizeof (val_desc->index_field.value)); +- +- acpi_aml_release_global_lock (locked); +- +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- /* Read Data value */ +- +- status = acpi_aml_access_named_field (ACPI_READ, val_desc->index_field.data, +- &temp_val, sizeof (temp_val)); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- /* Create an object for the result */ +- +- obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); +- if (!obj_desc) { +- return (AE_NO_MEMORY); +- } +- +- obj_desc->integer.value = temp_val; +- break; +- +- +- case ACPI_TYPE_FIELD_UNIT: +- +- if (attached_aml_pointer) { +- return (AE_AML_OPERAND_TYPE); +- } +- +- if (val_desc->common.type != (u8) entry_type) { +- return (AE_AML_OPERAND_TYPE); +- break; +- } +- +- /* Create object for result */ +- +- obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_ANY); +- if (!obj_desc) { +- return (AE_NO_MEMORY); +- } +- +- status = acpi_aml_get_field_unit_value (val_desc, obj_desc); +- if (ACPI_FAILURE (status)) { +- acpi_cm_remove_reference (obj_desc); +- return (status); +- } +- +- break; +- +- +- /* +- * For these objects, just return the object attached to the Node +- */ +- +- case ACPI_TYPE_MUTEX: +- case ACPI_TYPE_METHOD: +- case ACPI_TYPE_POWER: +- case ACPI_TYPE_PROCESSOR: +- case ACPI_TYPE_THERMAL: +- case ACPI_TYPE_EVENT: +- case ACPI_TYPE_REGION: +- +- +- /* Return an additional reference to the object */ +- +- obj_desc = val_desc; +- acpi_cm_add_reference (obj_desc); +- break; +- +- +- /* TYPE_Any is untyped, and thus there is no object associated with it */ +- +- case ACPI_TYPE_ANY: +- +- return (AE_AML_OPERAND_TYPE); /* Cannot be AE_TYPE */ +- break; +- +- +- /* +- * The only named references allowed are named constants +- * +- * e.g. Name (\OSFL, Ones) +- */ +- case INTERNAL_TYPE_REFERENCE: +- +- switch (val_desc->reference.op_code) +- { +- +- case AML_ZERO_OP: +- +- temp_val = 0; +- break; +- +- +- case AML_ONE_OP: +- +- temp_val = 1; +- break; +- +- +- case AML_ONES_OP: +- +- temp_val = ACPI_INTEGER_MAX; +- break; +- +- +- default: +- +- return (AE_AML_BAD_OPCODE); +- } +- +- /* Create object for result */ +- +- obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); +- if (!obj_desc) { +- return (AE_NO_MEMORY); +- } +- +- obj_desc->integer.value = temp_val; +- +- /* Truncate value if we are executing from a 32-bit ACPI table */ +- +- acpi_aml_truncate_for32bit_table (obj_desc, walk_state); +- break; +- +- +- /* Default case is for unknown types */ +- +- default: +- +- return (AE_AML_OPERAND_TYPE); +- +- } /* switch (Entry_type) */ +- +- +- /* Put the object descriptor on the stack */ +- +- *stack_ptr = (void *) obj_desc; +- +- return (status); +-} +- +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/amresolv.c linux/drivers/acpi/interpreter/amresolv.c +--- /usr/src/linux/drivers/acpi/interpreter/amresolv.c Mon Jan 29 10:15:59 2001 ++++ linux/drivers/acpi/interpreter/amresolv.c Wed Dec 31 16:00:00 1969 +@@ -1,465 +0,0 @@ +- +-/****************************************************************************** +- * +- * Module Name: amresolv - AML Interpreter object resolution +- * $Revision: 81 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "amlcode.h" +-#include "acparser.h" +-#include "acdispat.h" +-#include "acinterp.h" +-#include "acnamesp.h" +-#include "actables.h" +-#include "acevents.h" +- +- +-#define _COMPONENT INTERPRETER +- MODULE_NAME ("amresolv") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_get_field_unit_value +- * +- * PARAMETERS: *Field_desc - Pointer to a Field_unit +- * *Result_desc - Pointer to an empty descriptor +- * which will become a Number +- * containing the field's value. +- * +- * RETURN: Status +- * +- * DESCRIPTION: Retrieve the value from a Field_unit +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_get_field_unit_value ( +- ACPI_OPERAND_OBJECT *field_desc, +- ACPI_OPERAND_OBJECT *result_desc) +-{ +- ACPI_STATUS status = AE_OK; +- u32 mask; +- u8 *location = NULL; +- u8 locked = FALSE; +- +- +- if (!field_desc) { +- status = AE_AML_NO_OPERAND; +- } +- +- if (!(field_desc->common.flags & AOPOBJ_DATA_VALID)) { +- status = acpi_ds_get_field_unit_arguments (field_desc); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- } +- +- if (!field_desc->field_unit.container) { +- status = AE_AML_INTERNAL; +- } +- +- else if (ACPI_TYPE_BUFFER != field_desc->field_unit.container->common.type) { +- status = AE_AML_OPERAND_TYPE; +- } +- +- else if (!result_desc) { +- status = AE_AML_INTERNAL; +- } +- +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- +- /* Get the global lock if needed */ +- +- locked = acpi_aml_acquire_global_lock (field_desc->field_unit.lock_rule); +- +- /* Field location is (base of buffer) + (byte offset) */ +- +- location = field_desc->field_unit.container->buffer.pointer +- + field_desc->field_unit.offset; +- +- /* +- * Construct Mask with as many 1 bits as the field width +- * +- * NOTE: Only the bottom 5 bits are valid for a shift operation, so +- * special care must be taken for any shift greater than 31 bits. +- * +- * TBD: [Unhandled] Fields greater than 32-bits will not work. +- */ +- +- if (field_desc->field_unit.length < 32) { +- mask = ((u32) 1 << field_desc->field_unit.length) - (u32) 1; +- } +- else { +- mask = ACPI_UINT32_MAX; +- } +- +- result_desc->integer.type = (u8) ACPI_TYPE_INTEGER; +- +- /* Get the 32 bit value at the location */ +- +- MOVE_UNALIGNED32_TO_32 (&result_desc->integer.value, location); +- +- /* +- * Shift the 32-bit word containing the field, and mask off the +- * resulting value +- */ +- +- result_desc->integer.value = +- (result_desc->integer.value >> field_desc->field_unit.bit_offset) & mask; +- +- /* Release global lock if we acquired it earlier */ +- +- acpi_aml_release_global_lock (locked); +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_resolve_to_value +- * +- * PARAMETERS: **Stack_ptr - Points to entry on Obj_stack, which can +- * be either an (ACPI_OPERAND_OBJECT *) +- * or an ACPI_HANDLE. +- * +- * RETURN: Status +- * +- * DESCRIPTION: Convert Reference objects to values +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_resolve_to_value ( +- ACPI_OPERAND_OBJECT **stack_ptr, +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_STATUS status = AE_OK; +- +- +- if (!stack_ptr || !*stack_ptr) { +- return (AE_AML_NO_OPERAND); +- } +- +- +- /* +- * The entity pointed to by the Stack_ptr can be either +- * 1) A valid ACPI_OPERAND_OBJECT, or +- * 2) A ACPI_NAMESPACE_NODE (Named_obj) +- */ +- +- if (VALID_DESCRIPTOR_TYPE (*stack_ptr, ACPI_DESC_TYPE_INTERNAL)) { +- +- status = acpi_aml_resolve_object_to_value (stack_ptr, walk_state); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- } +- +- /* +- * Object on the stack may have changed if Acpi_aml_resolve_object_to_value() +- * was called (i.e., we can't use an _else_ here.) +- */ +- +- if (VALID_DESCRIPTOR_TYPE (*stack_ptr, ACPI_DESC_TYPE_NAMED)) { +- status = acpi_aml_resolve_node_to_value ((ACPI_NAMESPACE_NODE **) stack_ptr, walk_state); +- } +- +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_resolve_object_to_value +- * +- * PARAMETERS: Stack_ptr - Pointer to a stack location that contains a +- * ptr to an internal object. +- * +- * RETURN: Status +- * +- * DESCRIPTION: Retrieve the value from an internal object. The Reference type +- * uses the associated AML opcode to determine the value. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_resolve_object_to_value ( +- ACPI_OPERAND_OBJECT **stack_ptr, +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_OPERAND_OBJECT *stack_desc; +- ACPI_STATUS status = AE_OK; +- ACPI_HANDLE temp_handle = NULL; +- ACPI_OPERAND_OBJECT *obj_desc = NULL; +- u32 index = 0; +- u16 opcode; +- +- +- stack_desc = *stack_ptr; +- +- /* This is an ACPI_OPERAND_OBJECT */ +- +- switch (stack_desc->common.type) +- { +- +- case INTERNAL_TYPE_REFERENCE: +- +- opcode = stack_desc->reference.op_code; +- +- switch (opcode) +- { +- +- case AML_NAME_OP: +- +- /* +- * Convert indirect name ptr to a direct name ptr. +- * Then, Acpi_aml_resolve_node_to_value can be used to get the value +- */ +- +- temp_handle = stack_desc->reference.object; +- +- /* Delete the Reference Object */ +- +- acpi_cm_remove_reference (stack_desc); +- +- /* Put direct name pointer onto stack and exit */ +- +- (*stack_ptr) = temp_handle; +- status = AE_OK; +- break; +- +- +- case AML_LOCAL_OP: +- +- index = stack_desc->reference.offset; +- +- /* +- * Get the local from the method's state info +- * Note: this increments the local's object reference count +- */ +- +- status = acpi_ds_method_data_get_value (MTH_TYPE_LOCAL, index, +- walk_state, &obj_desc); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- /* +- * Now we can delete the original Reference Object and +- * replace it with the resolve value +- */ +- +- acpi_cm_remove_reference (stack_desc); +- *stack_ptr = obj_desc; +- +- if (ACPI_TYPE_INTEGER == obj_desc->common.type) { +- /* Value is a Number */ +- +- } +- +- break; +- +- +- case AML_ARG_OP: +- +- index = stack_desc->reference.offset; +- +- +- /* +- * Get the argument from the method's state info +- * Note: this increments the object reference count +- */ +- +- status = acpi_ds_method_data_get_value (MTH_TYPE_ARG, index, +- walk_state, &obj_desc); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- /* +- * Now we can delete the original Reference Object and +- * replace it with the resolve value +- */ +- +- acpi_cm_remove_reference (stack_desc); +- *stack_ptr = obj_desc; +- +- if (ACPI_TYPE_INTEGER == obj_desc->common.type) { +- /* Value is a Number */ +- +- } +- +- break; +- +- +- /* +- * TBD: [Restructure] These next three opcodes change the type of +- * the object, which is actually a no-no. +- */ +- +- case AML_ZERO_OP: +- +- stack_desc->common.type = (u8) ACPI_TYPE_INTEGER; +- stack_desc->integer.value = 0; +- break; +- +- +- case AML_ONE_OP: +- +- stack_desc->common.type = (u8) ACPI_TYPE_INTEGER; +- stack_desc->integer.value = 1; +- break; +- +- +- case AML_ONES_OP: +- +- stack_desc->common.type = (u8) ACPI_TYPE_INTEGER; +- stack_desc->integer.value = ACPI_INTEGER_MAX; +- +- /* Truncate value if we are executing from a 32-bit ACPI table */ +- +- acpi_aml_truncate_for32bit_table (stack_desc, walk_state); +- break; +- +- +- case AML_INDEX_OP: +- +- switch (stack_desc->reference.target_type) +- { +- case ACPI_TYPE_BUFFER_FIELD: +- +- /* Just return - leave the Reference on the stack */ +- break; +- +- +- case ACPI_TYPE_PACKAGE: +- obj_desc = *stack_desc->reference.where; +- if (obj_desc) { +- /* +- * Valid obj descriptor, copy pointer to return value +- * (i.e., dereference the package index) +- * Delete the ref object, increment the returned object +- */ +- acpi_cm_remove_reference (stack_desc); +- acpi_cm_add_reference (obj_desc); +- *stack_ptr = obj_desc; +- } +- +- else { +- /* +- * A NULL object descriptor means an unitialized element of +- * the package, can't deref it +- */ +- +- status = AE_AML_UNINITIALIZED_ELEMENT; +- } +- break; +- +- default: +- /* Invalid reference OBJ*/ +- +- status = AE_AML_INTERNAL; +- break; +- } +- +- break; +- +- +- case AML_DEBUG_OP: +- +- /* Just leave the object as-is */ +- break; +- +- +- default: +- +- status = AE_AML_INTERNAL; +- +- } /* switch (Opcode) */ +- +- +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- break; /* case INTERNAL_TYPE_REFERENCE */ +- +- +- case ACPI_TYPE_FIELD_UNIT: +- +- obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_ANY); +- if (!obj_desc) { +- /* Descriptor allocation failure */ +- +- return (AE_NO_MEMORY); +- } +- +- status = acpi_aml_get_field_unit_value (stack_desc, obj_desc); +- if (ACPI_FAILURE (status)) { +- acpi_cm_remove_reference (obj_desc); +- obj_desc = NULL; +- } +- +- *stack_ptr = (void *) obj_desc; +- break; +- +- +- case INTERNAL_TYPE_BANK_FIELD: +- +- obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_ANY); +- if (!obj_desc) { +- /* Descriptor allocation failure */ +- +- return (AE_NO_MEMORY); +- } +- +- status = acpi_aml_get_field_unit_value (stack_desc, obj_desc); +- if (ACPI_FAILURE (status)) { +- acpi_cm_remove_reference (obj_desc); +- obj_desc = NULL; +- } +- +- *stack_ptr = (void *) obj_desc; +- break; +- +- +- /* TBD: [Future] - may need to handle Index_field, and Def_field someday */ +- +- default: +- +- break; +- +- } /* switch (Stack_desc->Common.Type) */ +- +- +- return (status); +-} +- +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/amresop.c linux/drivers/acpi/interpreter/amresop.c +--- /usr/src/linux/drivers/acpi/interpreter/amresop.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/interpreter/amresop.c Wed Dec 31 16:00:00 1969 +@@ -1,488 +0,0 @@ +- +-/****************************************************************************** +- * +- * Module Name: amresop - AML Interpreter operand/object resolution +- * $Revision: 22 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "amlcode.h" +-#include "acparser.h" +-#include "acdispat.h" +-#include "acinterp.h" +-#include "acnamesp.h" +-#include "actables.h" +-#include "acevents.h" +- +- +-#define _COMPONENT INTERPRETER +- MODULE_NAME ("amresop") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_check_object_type +- * +- * PARAMETERS: Type_needed Object type needed +- * This_type Actual object type +- * Object Object pointer +- * +- * RETURN: Status +- * +- * DESCRIPTION: Check required type against actual type +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_check_object_type ( +- ACPI_OBJECT_TYPE type_needed, +- ACPI_OBJECT_TYPE this_type, +- void *object) +-{ +- +- +- if (type_needed == ACPI_TYPE_ANY) { +- /* All types OK, so we don't perform any typechecks */ +- +- return (AE_OK); +- } +- +- +- if (type_needed != this_type) { +- return (AE_AML_OPERAND_TYPE); +- } +- +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_resolve_operands +- * +- * PARAMETERS: Opcode Opcode being interpreted +- * Stack_ptr Top of operand stack +- * +- * RETURN: Status +- * +- * DESCRIPTION: Convert stack entries to required types +- * +- * Each nibble in Arg_types represents one required operand +- * and indicates the required Type: +- * +- * The corresponding stack entry will be converted to the +- * required type if possible, else return an exception +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_resolve_operands ( +- u16 opcode, +- ACPI_OPERAND_OBJECT **stack_ptr, +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_OPERAND_OBJECT *obj_desc; +- ACPI_STATUS status = AE_OK; +- u8 object_type; +- ACPI_HANDLE temp_handle; +- u32 arg_types; +- ACPI_OPCODE_INFO *op_info; +- u32 this_arg_type; +- ACPI_OBJECT_TYPE type_needed; +- +- +- op_info = acpi_ps_get_opcode_info (opcode); +- if (ACPI_GET_OP_TYPE (op_info) != ACPI_OP_TYPE_OPCODE) { +- return (AE_AML_BAD_OPCODE); +- } +- +- +- arg_types = op_info->runtime_args; +- if (arg_types == ARGI_INVALID_OPCODE) { +- return (AE_AML_INTERNAL); +- } +- +- +- /* +- * Normal exit is with *Types == '\0' at end of string. +- * Function will return an exception from within the loop upon +- * finding an entry which is not, and cannot be converted +- * to, the required type; if stack underflows; or upon +- * finding a NULL stack entry (which "should never happen"). +- */ +- +- while (GET_CURRENT_ARG_TYPE (arg_types)) { +- if (!stack_ptr || !*stack_ptr) { +- return (AE_AML_INTERNAL); +- } +- +- /* Extract useful items */ +- +- obj_desc = *stack_ptr; +- +- /* Decode the descriptor type */ +- +- if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) { +- /* Node */ +- +- object_type = ((ACPI_NAMESPACE_NODE *) obj_desc)->type; +- } +- +- else if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_INTERNAL)) { +- /* ACPI internal object */ +- +- object_type = obj_desc->common.type; +- +- /* Check for bad ACPI_OBJECT_TYPE */ +- +- if (!acpi_aml_validate_object_type (object_type)) { +- return (AE_AML_OPERAND_TYPE); +- } +- +- if (object_type == (u8) INTERNAL_TYPE_REFERENCE) { +- /* +- * Decode the Reference +- */ +- +- op_info = acpi_ps_get_opcode_info (opcode); +- if (ACPI_GET_OP_TYPE (op_info) != ACPI_OP_TYPE_OPCODE) { +- return (AE_AML_BAD_OPCODE); +- } +- +- +- switch (obj_desc->reference.op_code) +- { +- case AML_ZERO_OP: +- case AML_ONE_OP: +- case AML_ONES_OP: +- case AML_DEBUG_OP: +- case AML_NAME_OP: +- case AML_INDEX_OP: +- case AML_ARG_OP: +- case AML_LOCAL_OP: +- +- break; +- +- default: +- return (AE_AML_OPERAND_TYPE); +- break; +- } +- } +- } +- +- else { +- /* Invalid descriptor */ +- +- return (AE_AML_OPERAND_TYPE); +- } +- +- +- /* +- * Get one argument type, point to the next +- */ +- +- this_arg_type = GET_CURRENT_ARG_TYPE (arg_types); +- INCREMENT_ARG_LIST (arg_types); +- +- +- /* +- * Handle cases where the object does not need to be +- * resolved to a value +- */ +- +- switch (this_arg_type) +- { +- +- case ARGI_REFERENCE: /* References */ +- case ARGI_INTEGER_REF: +- case ARGI_OBJECT_REF: +- case ARGI_DEVICE_REF: +- case ARGI_TARGETREF: /* TBD: must implement implicit conversion rules before store */ +- case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */ +- case ARGI_SIMPLE_TARGET: /* Name, Local, or Arg - no implicit conversion */ +- +- /* Need an operand of type INTERNAL_TYPE_REFERENCE */ +- +- if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) /* direct name ptr OK as-is */ { +- goto next_operand; +- } +- +- status = acpi_aml_check_object_type (INTERNAL_TYPE_REFERENCE, +- object_type, obj_desc); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- +- if (AML_NAME_OP == obj_desc->reference.op_code) { +- /* +- * Convert an indirect name ptr to direct name ptr and put +- * it on the stack +- */ +- +- temp_handle = obj_desc->reference.object; +- acpi_cm_remove_reference (obj_desc); +- (*stack_ptr) = temp_handle; +- } +- +- goto next_operand; +- break; +- +- +- case ARGI_ANYTYPE: +- +- /* +- * We don't want to resolve Index_op reference objects during +- * a store because this would be an implicit De_ref_of operation. +- * Instead, we just want to store the reference object. +- * -- All others must be resolved below. +- */ +- +- if ((opcode == AML_STORE_OP) && +- ((*stack_ptr)->common.type == INTERNAL_TYPE_REFERENCE) && +- ((*stack_ptr)->reference.op_code == AML_INDEX_OP)) +- { +- goto next_operand; +- } +- break; +- } +- +- +- /* +- * Resolve this object to a value +- */ +- +- status = acpi_aml_resolve_to_value (stack_ptr, walk_state); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- +- /* +- * Check the resulting object (value) type +- */ +- switch (this_arg_type) +- { +- /* +- * For the simple cases, only one type of resolved object +- * is allowed +- */ +- case ARGI_MUTEX: +- +- /* Need an operand of type ACPI_TYPE_MUTEX */ +- +- type_needed = ACPI_TYPE_MUTEX; +- break; +- +- case ARGI_EVENT: +- +- /* Need an operand of type ACPI_TYPE_EVENT */ +- +- type_needed = ACPI_TYPE_EVENT; +- break; +- +- case ARGI_REGION: +- +- /* Need an operand of type ACPI_TYPE_REGION */ +- +- type_needed = ACPI_TYPE_REGION; +- break; +- +- case ARGI_IF: /* If */ +- +- /* Need an operand of type INTERNAL_TYPE_IF */ +- +- type_needed = INTERNAL_TYPE_IF; +- break; +- +- case ARGI_PACKAGE: /* Package */ +- +- /* Need an operand of type ACPI_TYPE_PACKAGE */ +- +- type_needed = ACPI_TYPE_PACKAGE; +- break; +- +- case ARGI_ANYTYPE: +- +- /* Any operand type will do */ +- +- type_needed = ACPI_TYPE_ANY; +- break; +- +- +- /* +- * The more complex cases allow multiple resolved object types +- */ +- +- case ARGI_INTEGER: /* Number */ +- +- /* +- * Need an operand of type ACPI_TYPE_INTEGER, +- * But we can implicitly convert from a STRING or BUFFER +- */ +- status = acpi_aml_convert_to_integer (stack_ptr, walk_state); +- if (ACPI_FAILURE (status)) { +- if (status == AE_TYPE) { +- return (AE_AML_OPERAND_TYPE); +- } +- +- return (status); +- } +- +- goto next_operand; +- break; +- +- +- case ARGI_BUFFER: +- +- /* +- * Need an operand of type ACPI_TYPE_BUFFER, +- * But we can implicitly convert from a STRING or INTEGER +- */ +- status = acpi_aml_convert_to_buffer (stack_ptr, walk_state); +- if (ACPI_FAILURE (status)) { +- if (status == AE_TYPE) { +- return (AE_AML_OPERAND_TYPE); +- } +- +- return (status); +- } +- +- goto next_operand; +- break; +- +- +- case ARGI_STRING: +- +- /* +- * Need an operand of type ACPI_TYPE_STRING, +- * But we can implicitly convert from a BUFFER or INTEGER +- */ +- status = acpi_aml_convert_to_string (stack_ptr, walk_state); +- if (ACPI_FAILURE (status)) { +- if (status == AE_TYPE) { +- return (AE_AML_OPERAND_TYPE); +- } +- +- return (status); +- } +- +- goto next_operand; +- break; +- +- +- case ARGI_COMPUTEDATA: +- +- /* Need an operand of type INTEGER, STRING or BUFFER */ +- +- if ((ACPI_TYPE_INTEGER != (*stack_ptr)->common.type) && +- (ACPI_TYPE_STRING != (*stack_ptr)->common.type) && +- (ACPI_TYPE_BUFFER != (*stack_ptr)->common.type)) +- { +- return (AE_AML_OPERAND_TYPE); +- } +- goto next_operand; +- break; +- +- +- case ARGI_DATAOBJECT: +- /* +- * ARGI_DATAOBJECT is only used by the Size_of operator. +- * +- * The ACPI specification allows Size_of to return the size of +- * a Buffer, String or Package. However, the MS ACPI.SYS AML +- * Interpreter also allows an Node reference to return without +- * error with a size of 4. +- */ +- +- /* Need a buffer, string, package or Node reference */ +- +- if (((*stack_ptr)->common.type != ACPI_TYPE_BUFFER) && +- ((*stack_ptr)->common.type != ACPI_TYPE_STRING) && +- ((*stack_ptr)->common.type != ACPI_TYPE_PACKAGE) && +- ((*stack_ptr)->common.type != INTERNAL_TYPE_REFERENCE)) +- { +- return (AE_AML_OPERAND_TYPE); +- } +- +- /* +- * If this is a reference, only allow a reference to an Node. +- */ +- if ((*stack_ptr)->common.type == INTERNAL_TYPE_REFERENCE) { +- if (!(*stack_ptr)->reference.node) { +- return (AE_AML_OPERAND_TYPE); +- } +- } +- goto next_operand; +- break; +- +- +- case ARGI_COMPLEXOBJ: +- +- /* Need a buffer or package */ +- +- if (((*stack_ptr)->common.type != ACPI_TYPE_BUFFER) && +- ((*stack_ptr)->common.type != ACPI_TYPE_PACKAGE)) +- { +- return (AE_AML_OPERAND_TYPE); +- } +- goto next_operand; +- break; +- +- +- default: +- +- /* Unknown type */ +- +- return (AE_BAD_PARAMETER); +- } +- +- +- /* +- * Make sure that the original object was resolved to the +- * required object type (Simple cases only). +- */ +- status = acpi_aml_check_object_type (type_needed, +- (*stack_ptr)->common.type, *stack_ptr); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- +-next_operand: +- /* +- * If more operands needed, decrement Stack_ptr to point +- * to next operand on stack +- */ +- if (GET_CURRENT_ARG_TYPE (arg_types)) { +- stack_ptr--; +- } +- +- } /* while (*Types) */ +- +- +- return (status); +-} +- +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/amstore.c linux/drivers/acpi/interpreter/amstore.c +--- /usr/src/linux/drivers/acpi/interpreter/amstore.c Tue Mar 6 19:44:36 2001 ++++ linux/drivers/acpi/interpreter/amstore.c Wed Dec 31 16:00:00 1969 +@@ -1,578 +0,0 @@ +- +-/****************************************************************************** +- * +- * Module Name: amstore - AML Interpreter object store support +- * $Revision: 123 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acparser.h" +-#include "acdispat.h" +-#include "acinterp.h" +-#include "amlcode.h" +-#include "acnamesp.h" +-#include "actables.h" +- +- +-#define _COMPONENT INTERPRETER +- MODULE_NAME ("amstore") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_exec_store +- * +- * PARAMETERS: *Val_desc - Value to be stored +- * *Dest_desc - Where to store it 0 Must be (ACPI_HANDLE) +- * or an ACPI_OPERAND_OBJECT of type +- * Reference; if the latter the descriptor +- * will be either reused or deleted. +- * +- * RETURN: Status +- * +- * DESCRIPTION: Store the value described by Val_desc into the location +- * described by Dest_desc. Called by various interpreter +- * functions to store the result of an operation into +- * the destination operand. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_exec_store ( +- ACPI_OPERAND_OBJECT *val_desc, +- ACPI_OPERAND_OBJECT *dest_desc, +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_STATUS status = AE_OK; +- ACPI_OPERAND_OBJECT *ref_desc = dest_desc; +- +- +- /* Validate parameters */ +- +- if (!val_desc || !dest_desc) { +- return (AE_AML_NO_OPERAND); +- } +- +- /* Dest_desc can be either a namespace node or an ACPI object */ +- +- if (VALID_DESCRIPTOR_TYPE (dest_desc, ACPI_DESC_TYPE_NAMED)) { +- /* +- * Dest is a namespace node, +- * Storing an object into a Name "container" +- */ +- status = acpi_aml_store_object_to_node (val_desc, +- (ACPI_NAMESPACE_NODE *) dest_desc, walk_state); +- +- /* All done, that's it */ +- +- return (status); +- } +- +- +- /* Destination object must be an object of type Reference */ +- +- if (dest_desc->common.type != INTERNAL_TYPE_REFERENCE) { +- /* Destination is not an Reference */ +- +- return (AE_AML_OPERAND_TYPE); +- } +- +- +- /* +- * Examine the Reference opcode. These cases are handled: +- * +- * 1) Store to Name (Change the object associated with a name) +- * 2) Store to an indexed area of a Buffer or Package +- * 3) Store to a Method Local or Arg +- * 4) Store to the debug object +- * 5) Store to a constant -- a noop +- */ +- +- switch (ref_desc->reference.op_code) +- { +- +- case AML_NAME_OP: +- +- /* Storing an object into a Name "container" */ +- +- status = acpi_aml_store_object_to_node (val_desc, ref_desc->reference.object, +- walk_state); +- break; +- +- +- case AML_INDEX_OP: +- +- /* Storing to an Index (pointer into a packager or buffer) */ +- +- status = acpi_aml_store_object_to_index (val_desc, ref_desc, walk_state); +- break; +- +- +- case AML_LOCAL_OP: +- +- status = acpi_ds_method_data_set_value (MTH_TYPE_LOCAL, +- (ref_desc->reference.offset), val_desc, walk_state); +- break; +- +- +- case AML_ARG_OP: +- +- status = acpi_ds_method_data_set_value (MTH_TYPE_ARG, +- (ref_desc->reference.offset), val_desc, walk_state); +- break; +- +- +- case AML_DEBUG_OP: +- +- /* +- * Storing to the Debug object causes the value stored to be +- * displayed and otherwise has no effect -- see ACPI Specification +- * +- * TBD: print known object types "prettier". +- */ +- +- break; +- +- +- case AML_ZERO_OP: +- case AML_ONE_OP: +- case AML_ONES_OP: +- +- /* +- * Storing to a constant is a no-op -- see ACPI Specification +- * Delete the reference descriptor, however +- */ +- break; +- +- +- default: +- +- /* TBD: [Restructure] use object dump routine !! */ +- +- status = AE_AML_INTERNAL; +- break; +- +- } /* switch (Ref_desc->Reference.Op_code) */ +- +- +- /* Always delete the reference descriptor object */ +- +- if (ref_desc) { +- acpi_cm_remove_reference (ref_desc); +- } +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_store_object_to_index +- * +- * PARAMETERS: *Val_desc - Value to be stored +- * *Node - Named object to receive the value +- * +- * RETURN: Status +- * +- * DESCRIPTION: Store the object to the named object. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_store_object_to_index ( +- ACPI_OPERAND_OBJECT *val_desc, +- ACPI_OPERAND_OBJECT *dest_desc, +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_STATUS status = AE_OK; +- ACPI_OPERAND_OBJECT *obj_desc; +- u32 length; +- u32 i; +- u8 value = 0; +- +- +- /* +- * Destination must be a reference pointer, and +- * must point to either a buffer or a package +- */ +- +- switch (dest_desc->reference.target_type) +- { +- case ACPI_TYPE_PACKAGE: +- /* +- * Storing to a package element is not simple. The source must be +- * evaluated and converted to the type of the destination and then the +- * source is copied into the destination - we can't just point to the +- * source object. +- */ +- if (dest_desc->reference.target_type == ACPI_TYPE_PACKAGE) { +- /* +- * The object at *(Dest_desc->Reference.Where) is the +- * element within the package that is to be modified. +- */ +- obj_desc = *(dest_desc->reference.where); +- if (obj_desc) { +- /* +- * If the Destination element is a package, we will delete +- * that object and construct a new one. +- * +- * TBD: [Investigate] Should both the src and dest be required +- * to be packages? +- * && (Val_desc->Common.Type == ACPI_TYPE_PACKAGE) +- */ +- if (obj_desc->common.type == ACPI_TYPE_PACKAGE) { +- /* +- * Take away the reference for being part of a package and +- * delete +- */ +- acpi_cm_remove_reference (obj_desc); +- acpi_cm_remove_reference (obj_desc); +- +- obj_desc = NULL; +- } +- } +- +- if (!obj_desc) { +- /* +- * If the Obj_desc is NULL, it means that an uninitialized package +- * element has been used as a destination (this is OK), therefore, +- * we must create the destination element to match the type of the +- * source element NOTE: Val_desc can be of any type. +- */ +- obj_desc = acpi_cm_create_internal_object (val_desc->common.type); +- if (!obj_desc) { +- return (AE_NO_MEMORY); +- } +- +- /* +- * If the source is a package, copy the source to the new dest +- */ +- if (ACPI_TYPE_PACKAGE == obj_desc->common.type) { +- status = acpi_cm_copy_ipackage_to_ipackage (val_desc, obj_desc, walk_state); +- if (ACPI_FAILURE (status)) { +- acpi_cm_remove_reference (obj_desc); +- return (status); +- } +- } +- +- /* +- * Install the new descriptor into the package and add a +- * reference to the newly created descriptor for now being +- * part of the parent package +- */ +- +- *(dest_desc->reference.where) = obj_desc; +- acpi_cm_add_reference (obj_desc); +- } +- +- if (ACPI_TYPE_PACKAGE != obj_desc->common.type) { +- /* +- * The destination element is not a package, so we need to +- * convert the contents of the source (Val_desc) and copy into +- * the destination (Obj_desc) +- */ +- status = acpi_aml_store_object_to_object (val_desc, obj_desc, +- walk_state); +- if (ACPI_FAILURE (status)) { +- /* +- * An error occurrered when copying the internal object +- * so delete the reference. +- */ +- return (AE_AML_OPERAND_TYPE); +- } +- } +- } +- break; +- +- +- case ACPI_TYPE_BUFFER_FIELD: +- /* +- * Storing into a buffer at a location defined by an Index. +- * +- * Each 8-bit element of the source object is written to the +- * 8-bit Buffer Field of the Index destination object. +- */ +- +- /* +- * Set the Obj_desc to the destination object and type check. +- */ +- obj_desc = dest_desc->reference.object; +- if (obj_desc->common.type != ACPI_TYPE_BUFFER) { +- return (AE_AML_OPERAND_TYPE); +- } +- +- /* +- * The assignment of the individual elements will be slightly +- * different for each source type. +- */ +- +- switch (val_desc->common.type) +- { +- /* +- * If the type is Integer, assign bytewise +- * This loop to assign each of the elements is somewhat +- * backward because of the Big Endian-ness of IA-64 +- */ +- case ACPI_TYPE_INTEGER: +- length = sizeof (ACPI_INTEGER); +- for (i = length; i != 0; i--) { +- value = (u8)(val_desc->integer.value >> (MUL_8 (i - 1))); +- obj_desc->buffer.pointer[dest_desc->reference.offset] = value; +- } +- break; +- +- /* +- * If the type is Buffer, the Length is in the structure. +- * Just loop through the elements and assign each one in turn. +- */ +- case ACPI_TYPE_BUFFER: +- length = val_desc->buffer.length; +- for (i = 0; i < length; i++) { +- value = *(val_desc->buffer.pointer + i); +- obj_desc->buffer.pointer[dest_desc->reference.offset] = value; +- } +- break; +- +- /* +- * If the type is String, the Length is in the structure. +- * Just loop through the elements and assign each one in turn. +- */ +- case ACPI_TYPE_STRING: +- length = val_desc->string.length; +- for (i = 0; i < length; i++) { +- value = *(val_desc->string.pointer + i); +- obj_desc->buffer.pointer[dest_desc->reference.offset] = value; +- } +- break; +- +- /* +- * If source is not a valid type so return an error. +- */ +- default: +- status = AE_AML_OPERAND_TYPE; +- break; +- } +- break; +- +- +- default: +- status = AE_AML_OPERAND_TYPE; +- break; +- } +- +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_store_object_to_node +- * +- * PARAMETERS: *Source_desc - Value to be stored +- * *Node - Named object to receive the value +- * +- * RETURN: Status +- * +- * DESCRIPTION: Store the object to the named object. +- * +- * The Assignment of an object to a named object is handled here +- * The val passed in will replace the current value (if any) +- * with the input value. +- * +- * When storing into an object the data is converted to the +- * target object type then stored in the object. This means +- * that the target object type (for an initialized target) will +- * not be changed by a store operation. +- * +- * NOTE: the global lock is acquired early. This will result +- * in the global lock being held a bit longer. Also, if the +- * function fails during set up we may get the lock when we +- * don't really need it. I don't think we care. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_store_object_to_node ( +- ACPI_OPERAND_OBJECT *source_desc, +- ACPI_NAMESPACE_NODE *node, +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_STATUS status = AE_OK; +- ACPI_OPERAND_OBJECT *target_desc; +- OBJECT_TYPE_INTERNAL target_type = ACPI_TYPE_ANY; +- +- +- /* +- * Assuming the parameters were already validated +- */ +- ACPI_ASSERT((node) && (source_desc)); +- +- +- /* +- * Get current type of the node, and object attached to Node +- */ +- target_type = acpi_ns_get_type (node); +- target_desc = acpi_ns_get_attached_object (node); +- +- +- /* +- * Resolve the source object to an actual value +- * (If it is a reference object) +- */ +- status = acpi_aml_resolve_object (&source_desc, target_type, walk_state); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- +- /* +- * Do the actual store operation +- */ +- switch (target_type) +- { +- case INTERNAL_TYPE_DEF_FIELD: +- +- /* Raw data copy for target types Integer/String/Buffer */ +- +- status = acpi_aml_copy_data_to_named_field (source_desc, node); +- break; +- +- +- case ACPI_TYPE_INTEGER: +- case ACPI_TYPE_STRING: +- case ACPI_TYPE_BUFFER: +- case INTERNAL_TYPE_BANK_FIELD: +- case INTERNAL_TYPE_INDEX_FIELD: +- case ACPI_TYPE_FIELD_UNIT: +- +- /* +- * These target types are all of type Integer/String/Buffer, and +- * therefore support implicit conversion before the store. +- * +- * Copy and/or convert the source object to a new target object +- */ +- status = acpi_aml_store_object (source_desc, target_type, &target_desc, walk_state); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- /* +- * Store the new Target_desc as the new value of the Name, and set +- * the Name's type to that of the value being stored in it. +- * Source_desc reference count is incremented by Attach_object. +- */ +- status = acpi_ns_attach_object (node, target_desc, target_type); +- break; +- +- +- default: +- +- /* No conversions for all other types. Just attach the source object */ +- +- status = acpi_ns_attach_object (node, source_desc, source_desc->common.type); +- +- break; +- } +- +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_store_object_to_object +- * +- * PARAMETERS: *Source_desc - Value to be stored +- * *Dest_desc - Object to receive the value +- * +- * RETURN: Status +- * +- * DESCRIPTION: Store an object to another object. +- * +- * The Assignment of an object to another (not named) object +- * is handled here. +- * The val passed in will replace the current value (if any) +- * with the input value. +- * +- * When storing into an object the data is converted to the +- * target object type then stored in the object. This means +- * that the target object type (for an initialized target) will +- * not be changed by a store operation. +- * +- * This module allows destination types of Number, String, +- * and Buffer. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_store_object_to_object ( +- ACPI_OPERAND_OBJECT *source_desc, +- ACPI_OPERAND_OBJECT *dest_desc, +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_STATUS status = AE_OK; +- OBJECT_TYPE_INTERNAL destination_type = dest_desc->common.type; +- +- +- /* +- * Assuming the parameters are valid! +- */ +- ACPI_ASSERT((dest_desc) && (source_desc)); +- +- +- /* +- * From this interface, we only support Integers/Strings/Buffers +- */ +- switch (destination_type) +- { +- case ACPI_TYPE_INTEGER: +- case ACPI_TYPE_STRING: +- case ACPI_TYPE_BUFFER: +- break; +- +- default: +- return (AE_NOT_IMPLEMENTED); +- } +- +- +- /* +- * Resolve the source object to an actual value +- * (If it is a reference object) +- */ +- status = acpi_aml_resolve_object (&source_desc, destination_type, walk_state); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- +- /* +- * Copy and/or convert the source object to the destination object +- */ +- status = acpi_aml_store_object (source_desc, destination_type, &dest_desc, walk_state); +- +- +- return (status); +-} +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/amstoren.c linux/drivers/acpi/interpreter/amstoren.c +--- /usr/src/linux/drivers/acpi/interpreter/amstoren.c Mon Jan 29 10:15:59 2001 ++++ linux/drivers/acpi/interpreter/amstoren.c Wed Dec 31 16:00:00 1969 +@@ -1,262 +0,0 @@ +- +-/****************************************************************************** +- * +- * Module Name: amstoren - AML Interpreter object store support, +- * Store to Node (namespace object) +- * $Revision: 28 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acparser.h" +-#include "acdispat.h" +-#include "acinterp.h" +-#include "amlcode.h" +-#include "acnamesp.h" +-#include "actables.h" +- +- +-#define _COMPONENT INTERPRETER +- MODULE_NAME ("amstoren") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_resolve_object +- * +- * PARAMETERS: Source_desc_ptr - Pointer to the source object +- * Target_type - Current type of the target +- * Walk_state - Current walk state +- * +- * RETURN: Status, resolved object in Source_desc_ptr. +- * +- * DESCRIPTION: Resolve an object. If the object is a reference, dereference +- * it and return the actual object in the Source_desc_ptr. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_resolve_object ( +- ACPI_OPERAND_OBJECT **source_desc_ptr, +- OBJECT_TYPE_INTERNAL target_type, +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_OPERAND_OBJECT *source_desc = *source_desc_ptr; +- ACPI_STATUS status = AE_OK; +- +- +- /* +- * Ensure we have a Source that can be stored in the target +- */ +- switch (target_type) +- { +- +- /* This case handles the "interchangeable" types Integer, String, and Buffer. */ +- +- /* +- * These cases all require only Integers or values that +- * can be converted to Integers (Strings or Buffers) +- */ +- case ACPI_TYPE_INTEGER: +- case ACPI_TYPE_FIELD_UNIT: +- case INTERNAL_TYPE_BANK_FIELD: +- case INTERNAL_TYPE_INDEX_FIELD: +- +- /* +- * Stores into a Field/Region or into a Buffer/String +- * are all essentially the same. +- */ +- case ACPI_TYPE_STRING: +- case ACPI_TYPE_BUFFER: +- case INTERNAL_TYPE_DEF_FIELD: +- +- /* +- * If Source_desc is not a valid type, try to resolve it to one. +- */ +- if ((source_desc->common.type != ACPI_TYPE_INTEGER) && +- (source_desc->common.type != ACPI_TYPE_BUFFER) && +- (source_desc->common.type != ACPI_TYPE_STRING)) +- { +- /* +- * Initially not a valid type, convert +- */ +- status = acpi_aml_resolve_to_value (source_desc_ptr, walk_state); +- if (ACPI_SUCCESS (status) && +- (source_desc->common.type != ACPI_TYPE_INTEGER) && +- (source_desc->common.type != ACPI_TYPE_BUFFER) && +- (source_desc->common.type != ACPI_TYPE_STRING)) +- { +- /* +- * Conversion successful but still not a valid type +- */ +- status = AE_AML_OPERAND_TYPE; +- } +- } +- break; +- +- +- case INTERNAL_TYPE_ALIAS: +- +- /* +- * Aliases are resolved by Acpi_aml_prep_operands +- */ +- status = AE_AML_INTERNAL; +- break; +- +- +- case ACPI_TYPE_PACKAGE: +- default: +- +- /* +- * All other types than Alias and the various Fields come here, +- * including the untyped case - ACPI_TYPE_ANY. +- */ +- break; +- } +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_store_object +- * +- * PARAMETERS: Source_desc - Object to store +- * Target_type - Current type of the target +- * Target_desc_ptr - Pointer to the target +- * Walk_state - Current walk state +- * +- * RETURN: Status +- * +- * DESCRIPTION: "Store" an object to another object. This may include +- * converting the source type to the target type (implicit +- * conversion), and a copy of the value of the source to +- * the target. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_store_object ( +- ACPI_OPERAND_OBJECT *source_desc, +- OBJECT_TYPE_INTERNAL target_type, +- ACPI_OPERAND_OBJECT **target_desc_ptr, +- ACPI_WALK_STATE *walk_state) +-{ +- ACPI_OPERAND_OBJECT *target_desc = *target_desc_ptr; +- ACPI_STATUS status; +- +- +- /* +- * Perform the "implicit conversion" of the source to the current type +- * of the target - As per the ACPI specification. +- * +- * If no conversion performed, Source_desc is left alone, otherwise it +- * is updated with a new object. +- */ +- status = acpi_aml_convert_to_target_type (target_type, &source_desc, walk_state); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- +- /* +- * We now have two objects of identical types, and we can perform a +- * copy of the *value* of the source object. +- */ +- switch (target_type) +- { +- case ACPI_TYPE_ANY: +- case INTERNAL_TYPE_DEF_ANY: +- +- /* +- * The target namespace node is uninitialized (has no target object), +- * and will take on the type of the source object +- */ +- +- *target_desc_ptr = source_desc; +- break; +- +- +- case ACPI_TYPE_INTEGER: +- +- target_desc->integer.value = source_desc->integer.value; +- +- /* Truncate value if we are executing from a 32-bit ACPI table */ +- +- acpi_aml_truncate_for32bit_table (target_desc, walk_state); +- break; +- +- +- case ACPI_TYPE_FIELD_UNIT: +- +- status = acpi_aml_copy_integer_to_field_unit (source_desc, target_desc); +- break; +- +- +- case INTERNAL_TYPE_BANK_FIELD: +- +- status = acpi_aml_copy_integer_to_bank_field (source_desc, target_desc); +- break; +- +- +- case INTERNAL_TYPE_INDEX_FIELD: +- +- status = acpi_aml_copy_integer_to_index_field (source_desc, target_desc); +- break; +- +- +- case ACPI_TYPE_STRING: +- +- status = acpi_aml_copy_string_to_string (source_desc, target_desc); +- break; +- +- +- case ACPI_TYPE_BUFFER: +- +- status = acpi_aml_copy_buffer_to_buffer (source_desc, target_desc); +- break; +- +- +- case ACPI_TYPE_PACKAGE: +- +- /* +- * TBD: [Unhandled] Not real sure what to do here +- */ +- status = AE_NOT_IMPLEMENTED; +- break; +- +- +- default: +- +- /* +- * All other types come here. +- */ +- status = AE_NOT_IMPLEMENTED; +- break; +- } +- +- +- return (status); +-} +- +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/amstorob.c linux/drivers/acpi/interpreter/amstorob.c +--- /usr/src/linux/drivers/acpi/interpreter/amstorob.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/interpreter/amstorob.c Wed Dec 31 16:00:00 1969 +@@ -1,435 +0,0 @@ +- +-/****************************************************************************** +- * +- * Module Name: amstorob - AML Interpreter object store support, store to object +- * $Revision: 23 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acparser.h" +-#include "acdispat.h" +-#include "acinterp.h" +-#include "amlcode.h" +-#include "acnamesp.h" +-#include "actables.h" +- +- +-#define _COMPONENT INTERPRETER +- MODULE_NAME ("amstorob") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_copy_buffer_to_buffer +- * +- * PARAMETERS: Source_desc - Source object to copy +- * Target_desc - Destination object of the copy +- * +- * RETURN: Status +- * +- * DESCRIPTION: Copy a buffer object to another buffer object. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_copy_buffer_to_buffer ( +- ACPI_OPERAND_OBJECT *source_desc, +- ACPI_OPERAND_OBJECT *target_desc) +-{ +- u32 length; +- u8 *buffer; +- +- /* +- * We know that Source_desc is a buffer by now +- */ +- buffer = (u8 *) source_desc->buffer.pointer; +- length = source_desc->buffer.length; +- +- /* +- * If target is a buffer of length zero, allocate a new +- * buffer of the proper length +- */ +- if (target_desc->buffer.length == 0) { +- target_desc->buffer.pointer = acpi_cm_allocate (length); +- if (!target_desc->buffer.pointer) { +- return (AE_NO_MEMORY); +- } +- +- target_desc->buffer.length = length; +- } +- +- /* +- * Buffer is a static allocation, +- * only place what will fit in the buffer. +- */ +- if (length <= target_desc->buffer.length) { +- /* Clear existing buffer and copy in the new one */ +- +- MEMSET(target_desc->buffer.pointer, 0, target_desc->buffer.length); +- MEMCPY(target_desc->buffer.pointer, buffer, length); +- } +- +- else { +- /* +- * Truncate the source, copy only what will fit +- */ +- MEMCPY(target_desc->buffer.pointer, buffer, target_desc->buffer.length); +- +- } +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_copy_string_to_string +- * +- * PARAMETERS: Source_desc - Source object to copy +- * Target_desc - Destination object of the copy +- * +- * RETURN: Status +- * +- * DESCRIPTION: Copy a String object to another String object +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_copy_string_to_string ( +- ACPI_OPERAND_OBJECT *source_desc, +- ACPI_OPERAND_OBJECT *target_desc) +-{ +- u32 length; +- u8 *buffer; +- +- +- /* +- * We know that Source_desc is a string by now. +- */ +- buffer = (u8 *) source_desc->string.pointer; +- length = source_desc->string.length; +- +- /* +- * Setting a string value replaces the old string +- */ +- if (length < target_desc->string.length) { +- /* Clear old string and copy in the new one */ +- +- MEMSET(target_desc->string.pointer, 0, target_desc->string.length); +- MEMCPY(target_desc->string.pointer, buffer, length); +- } +- +- else { +- /* +- * Free the current buffer, then allocate a buffer +- * large enough to hold the value +- */ +- if (target_desc->string.pointer && +- !acpi_tb_system_table_pointer (target_desc->string.pointer)) +- { +- /* +- * Only free if not a pointer into the DSDT +- */ +- acpi_cm_free(target_desc->string.pointer); +- } +- +- target_desc->string.pointer = acpi_cm_allocate (length + 1); +- if (!target_desc->string.pointer) { +- return (AE_NO_MEMORY); +- } +- target_desc->string.length = length; +- +- +- MEMCPY(target_desc->string.pointer, buffer, length); +- } +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_copy_integer_to_index_field +- * +- * PARAMETERS: Source_desc - Source object to copy +- * Target_desc - Destination object of the copy +- * +- * RETURN: Status +- * +- * DESCRIPTION: Write an Integer to an Index Field +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_copy_integer_to_index_field ( +- ACPI_OPERAND_OBJECT *source_desc, +- ACPI_OPERAND_OBJECT *target_desc) +-{ +- ACPI_STATUS status; +- u8 locked; +- +- +- /* +- * Get the global lock if needed +- */ +- locked = acpi_aml_acquire_global_lock (target_desc->index_field.lock_rule); +- +- /* +- * Set Index value to select proper Data register +- * perform the update (Set index) +- */ +- status = acpi_aml_access_named_field (ACPI_WRITE, +- target_desc->index_field.index, +- &target_desc->index_field.value, +- sizeof (target_desc->index_field.value)); +- if (ACPI_SUCCESS (status)) { +- /* Set_index was successful, next set Data value */ +- +- status = acpi_aml_access_named_field (ACPI_WRITE, +- target_desc->index_field.data, +- &source_desc->integer.value, +- sizeof (source_desc->integer.value)); +- +- } +- +- +- +- /* +- * Release global lock if we acquired it earlier +- */ +- acpi_aml_release_global_lock (locked); +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_copy_integer_to_bank_field +- * +- * PARAMETERS: Source_desc - Source object to copy +- * Target_desc - Destination object of the copy +- * +- * RETURN: Status +- * +- * DESCRIPTION: Write an Integer to a Bank Field +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_copy_integer_to_bank_field ( +- ACPI_OPERAND_OBJECT *source_desc, +- ACPI_OPERAND_OBJECT *target_desc) +-{ +- ACPI_STATUS status; +- u8 locked; +- +- +- /* +- * Get the global lock if needed +- */ +- locked = acpi_aml_acquire_global_lock (target_desc->index_field.lock_rule); +- +- +- /* +- * Set Bank value to select proper Bank +- * Perform the update (Set Bank Select) +- */ +- +- status = acpi_aml_access_named_field (ACPI_WRITE, +- target_desc->bank_field.bank_select, +- &target_desc->bank_field.value, +- sizeof (target_desc->bank_field.value)); +- if (ACPI_SUCCESS (status)) { +- /* Set bank select successful, set data value */ +- +- status = acpi_aml_access_named_field (ACPI_WRITE, +- target_desc->bank_field.bank_select, +- &source_desc->bank_field.value, +- sizeof (source_desc->bank_field.value)); +- } +- +- +- +- /* +- * Release global lock if we acquired it earlier +- */ +- acpi_aml_release_global_lock (locked); +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_copy_data_to_named_field +- * +- * PARAMETERS: Source_desc - Source object to copy +- * Node - Destination Namespace node +- * +- * RETURN: Status +- * +- * DESCRIPTION: Copy raw data to a Named Field. No implicit conversion +- * is performed on the source object +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_copy_data_to_named_field ( +- ACPI_OPERAND_OBJECT *source_desc, +- ACPI_NAMESPACE_NODE *node) +-{ +- ACPI_STATUS status; +- u8 locked; +- u32 length; +- u8 *buffer; +- +- +- /* +- * Named fields (Create_xxx_field) - We don't perform any conversions on the +- * source operand, just use the raw data +- */ +- switch (source_desc->common.type) +- { +- case ACPI_TYPE_INTEGER: +- buffer = (u8 *) &source_desc->integer.value; +- length = sizeof (source_desc->integer.value); +- break; +- +- case ACPI_TYPE_BUFFER: +- buffer = (u8 *) source_desc->buffer.pointer; +- length = source_desc->buffer.length; +- break; +- +- case ACPI_TYPE_STRING: +- buffer = (u8 *) source_desc->string.pointer; +- length = source_desc->string.length; +- break; +- +- default: +- return (AE_TYPE); +- } +- +- /* +- * Get the global lock if needed before the update +- * TBD: not needed! +- */ +- locked = acpi_aml_acquire_global_lock (source_desc->field.lock_rule); +- +- status = acpi_aml_access_named_field (ACPI_WRITE, +- node, buffer, length); +- +- acpi_aml_release_global_lock (locked); +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_copy_integer_to_field_unit +- * +- * PARAMETERS: Source_desc - Source object to copy +- * Target_desc - Destination object of the copy +- * +- * RETURN: Status +- * +- * DESCRIPTION: Write an Integer to a Field Unit. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_copy_integer_to_field_unit ( +- ACPI_OPERAND_OBJECT *source_desc, +- ACPI_OPERAND_OBJECT *target_desc) +-{ +- ACPI_STATUS status = AE_OK; +- u8 *location = NULL; +- u32 mask; +- u32 new_value; +- u8 locked = FALSE; +- +- +- /* +- * If the Field Buffer and Index have not been previously evaluated, +- * evaluate them and save the results. +- */ +- if (!(target_desc->common.flags & AOPOBJ_DATA_VALID)) { +- status = acpi_ds_get_field_unit_arguments (target_desc); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- } +- +- if ((!target_desc->field_unit.container || +- ACPI_TYPE_BUFFER != target_desc->field_unit.container->common.type)) +- { +- return (AE_AML_INTERNAL); +- } +- +- /* +- * Get the global lock if needed +- */ +- locked = acpi_aml_acquire_global_lock (target_desc->field_unit.lock_rule); +- +- /* +- * TBD: [Unhandled] REMOVE this limitation +- * Make sure the operation is within the limits of our implementation +- * this is not a Spec limitation!! +- */ +- if (target_desc->field_unit.length + target_desc->field_unit.bit_offset > 32) { +- return (AE_NOT_IMPLEMENTED); +- } +- +- /* Field location is (base of buffer) + (byte offset) */ +- +- location = target_desc->field_unit.container->buffer.pointer +- + target_desc->field_unit.offset; +- +- /* +- * Construct Mask with 1 bits where the field is, +- * 0 bits elsewhere +- */ +- mask = ((u32) 1 << target_desc->field_unit.length) - ((u32)1 +- << target_desc->field_unit.bit_offset); +- +- /* Zero out the field in the buffer */ +- +- MOVE_UNALIGNED32_TO_32 (&new_value, location); +- new_value &= ~mask; +- +- /* +- * Shift and mask the new value into position, +- * and or it into the buffer. +- */ +- new_value |= (source_desc->integer.value << target_desc->field_unit.bit_offset) & +- mask; +- +- /* Store back the value */ +- +- MOVE_UNALIGNED32_TO_32 (location, &new_value); +- +- return (AE_OK); +-} +- +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/amsystem.c linux/drivers/acpi/interpreter/amsystem.c +--- /usr/src/linux/drivers/acpi/interpreter/amsystem.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/interpreter/amsystem.c Wed Dec 31 16:00:00 1969 +@@ -1,344 +0,0 @@ +- +-/****************************************************************************** +- * +- * Module Name: amsystem - Interface to OS services +- * $Revision: 54 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acinterp.h" +-#include "acnamesp.h" +-#include "achware.h" +-#include "acevents.h" +- +-#define _COMPONENT INTERPRETER +- MODULE_NAME ("amsystem") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_system_thread_id +- * +- * PARAMETERS: None +- * +- * RETURN: Current Thread ID (for this implementation a 1 is returned) +- * +- * DESCRIPTION: An invocation is identified by its Thread ID. In a single +- * threaded OS the Thread ID is undefined so a 1 will be +- * returned. +- * +- ******************************************************************************/ +- +-u16 +-acpi_aml_system_thread_id (void) +-{ +- return (1); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_system_wait_semaphore +- * +- * PARAMETERS: Semaphore - OSD semaphore to wait on +- * Timeout - Max time to wait +- * +- * RETURN: Status +- * +- * DESCRIPTION: Implements a semaphore wait with a check to see if the +- * semaphore is available immediately. If it is not, the +- * interpreter is released. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_system_wait_semaphore ( +- ACPI_HANDLE semaphore, +- u32 timeout) +-{ +- ACPI_STATUS status; +- +- +- status = acpi_os_wait_semaphore (semaphore, 1, 0); +- if (ACPI_SUCCESS (status)) { +- return (status); +- } +- +- if (status == AE_TIME) { +- /* We must wait, so unlock the interpreter */ +- +- acpi_aml_exit_interpreter (); +- +- status = acpi_os_wait_semaphore (semaphore, 1, timeout); +- +- /* Reacquire the interpreter */ +- +- acpi_aml_enter_interpreter (); +- +- } +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_system_do_stall +- * +- * PARAMETERS: How_long - The amount of time to stall +- * +- * RETURN: None +- * +- * DESCRIPTION: Suspend running thread for specified amount of time. +- * +- ******************************************************************************/ +- +-void +-acpi_aml_system_do_stall ( +- u32 how_long) +-{ +- +- if (how_long > 1000) /* 1 millisecond */ { +- /* Since this thread will sleep, we must release the interpreter */ +- +- acpi_aml_exit_interpreter (); +- +- acpi_os_sleep_usec (how_long); +- +- /* And now we must get the interpreter again */ +- +- acpi_aml_enter_interpreter (); +- } +- +- else { +- acpi_os_sleep_usec (how_long); +- } +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_system_do_suspend +- * +- * PARAMETERS: How_long - The amount of time to suspend +- * +- * RETURN: None +- * +- * DESCRIPTION: Suspend running thread for specified amount of time. +- * +- ******************************************************************************/ +- +-void +-acpi_aml_system_do_suspend ( +- u32 how_long) +-{ +- /* Since this thread will sleep, we must release the interpreter */ +- +- acpi_aml_exit_interpreter (); +- +- acpi_os_sleep ((u16) (how_long / (u32) 1000), +- (u16) (how_long % (u32) 1000)); +- +- /* And now we must get the interpreter again */ +- +- acpi_aml_enter_interpreter (); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_system_acquire_mutex +- * +- * PARAMETERS: *Time_desc - The 'time to delay' object descriptor +- * *Obj_desc - The object descriptor for this op +- * +- * RETURN: Status +- * +- * DESCRIPTION: Provides an access point to perform synchronization operations +- * within the AML. This function will cause a lock to be generated +- * for the Mutex pointed to by Obj_desc. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_system_acquire_mutex ( +- ACPI_OPERAND_OBJECT *time_desc, +- ACPI_OPERAND_OBJECT *obj_desc) +-{ +- ACPI_STATUS status = AE_OK; +- +- +- if (!obj_desc) { +- return (AE_BAD_PARAMETER); +- } +- +- /* +- * Support for the _GL_ Mutex object -- go get the global lock +- */ +- +- if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) { +- status = acpi_ev_acquire_global_lock (); +- return (status); +- } +- +- status = acpi_aml_system_wait_semaphore (obj_desc->mutex.semaphore, +- (u32) time_desc->integer.value); +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_system_release_mutex +- * +- * PARAMETERS: *Obj_desc - The object descriptor for this op +- * +- * RETURN: Status +- * +- * DESCRIPTION: Provides an access point to perform synchronization operations +- * within the AML. This operation is a request to release a +- * previously acquired Mutex. If the Mutex variable is set then +- * it will be decremented. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_system_release_mutex ( +- ACPI_OPERAND_OBJECT *obj_desc) +-{ +- ACPI_STATUS status = AE_OK; +- +- +- if (!obj_desc) { +- return (AE_BAD_PARAMETER); +- } +- +- /* +- * Support for the _GL_ Mutex object -- release the global lock +- */ +- if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) { +- acpi_ev_release_global_lock (); +- return (AE_OK); +- } +- +- status = acpi_os_signal_semaphore (obj_desc->mutex.semaphore, 1); +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_system_signal_event +- * +- * PARAMETERS: *Obj_desc - The object descriptor for this op +- * +- * RETURN: AE_OK +- * +- * DESCRIPTION: Provides an access point to perform synchronization operations +- * within the AML. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_system_signal_event ( +- ACPI_OPERAND_OBJECT *obj_desc) +-{ +- ACPI_STATUS status = AE_OK; +- +- +- if (obj_desc) { +- status = acpi_os_signal_semaphore (obj_desc->event.semaphore, 1); +- } +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_system_wait_event +- * +- * PARAMETERS: *Time_desc - The 'time to delay' object descriptor +- * *Obj_desc - The object descriptor for this op +- * +- * RETURN: Status +- * +- * DESCRIPTION: Provides an access point to perform synchronization operations +- * within the AML. This operation is a request to wait for an +- * event. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_system_wait_event ( +- ACPI_OPERAND_OBJECT *time_desc, +- ACPI_OPERAND_OBJECT *obj_desc) +-{ +- ACPI_STATUS status = AE_OK; +- +- +- if (obj_desc) { +- status = acpi_aml_system_wait_semaphore (obj_desc->event.semaphore, +- (u32) time_desc->integer.value); +- } +- +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_system_reset_event +- * +- * PARAMETERS: *Obj_desc - The object descriptor for this op +- * +- * RETURN: Status +- * +- * DESCRIPTION: Provides an access point to perform synchronization operations +- * within the AML. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_system_reset_event ( +- ACPI_OPERAND_OBJECT *obj_desc) +-{ +- ACPI_STATUS status = AE_OK; +- void *temp_semaphore; +- +- +- /* +- * We are going to simply delete the existing semaphore and +- * create a new one! +- */ +- +- status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, 0, &temp_semaphore); +- if (ACPI_SUCCESS (status)) { +- acpi_os_delete_semaphore (obj_desc->mutex.semaphore); +- obj_desc->mutex.semaphore = temp_semaphore; +- } +- +- return (status); +-} +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/amutils.c linux/drivers/acpi/interpreter/amutils.c +--- /usr/src/linux/drivers/acpi/interpreter/amutils.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/interpreter/amutils.c Wed Dec 31 16:00:00 1969 +@@ -1,370 +0,0 @@ +- +-/****************************************************************************** +- * +- * Module Name: amutils - interpreter/scanner utilities +- * $Revision: 69 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acparser.h" +-#include "acinterp.h" +-#include "amlcode.h" +-#include "acnamesp.h" +-#include "acevents.h" +- +-#define _COMPONENT INTERPRETER +- MODULE_NAME ("amutils") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_enter_interpreter +- * +- * PARAMETERS: None +- * +- * DESCRIPTION: Enter the interpreter execution region +- * +- ******************************************************************************/ +- +-void +-acpi_aml_enter_interpreter (void) +-{ +- +- acpi_cm_acquire_mutex (ACPI_MTX_EXECUTE); +- +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_exit_interpreter +- * +- * PARAMETERS: None +- * +- * DESCRIPTION: Exit the interpreter execution region +- * +- * Cases where the interpreter is unlocked: +- * 1) Completion of the execution of a control method +- * 2) Method blocked on a Sleep() AML opcode +- * 3) Method blocked on an Acquire() AML opcode +- * 4) Method blocked on a Wait() AML opcode +- * 5) Method blocked to acquire the global lock +- * 6) Method blocked to execute a serialized control method that is +- * already executing +- * 7) About to invoke a user-installed opregion handler +- * +- ******************************************************************************/ +- +-void +-acpi_aml_exit_interpreter (void) +-{ +- +- acpi_cm_release_mutex (ACPI_MTX_EXECUTE); +- +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_validate_object_type +- * +- * PARAMETERS: Type Object type to validate +- * +- * DESCRIPTION: Determine if a type is a valid ACPI object type +- * +- ******************************************************************************/ +- +-u8 +-acpi_aml_validate_object_type ( +- ACPI_OBJECT_TYPE type) +-{ +- +- if ((type > ACPI_TYPE_MAX && type < INTERNAL_TYPE_BEGIN) || +- (type > INTERNAL_TYPE_MAX)) +- { +- return (FALSE); +- } +- +- return (TRUE); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_truncate_for32bit_table +- * +- * PARAMETERS: Obj_desc - Object to be truncated +- * Walk_state - Current walk state +- * (A method must be executing) +- * +- * RETURN: none +- * +- * DESCRIPTION: Truncate a number to 32-bits if the currently executing method +- * belongs to a 32-bit ACPI table. +- * +- ******************************************************************************/ +- +-void +-acpi_aml_truncate_for32bit_table ( +- ACPI_OPERAND_OBJECT *obj_desc, +- ACPI_WALK_STATE *walk_state) +-{ +- +- /* +- * Object must be a valid number and we must be executing +- * a control method +- */ +- +- if ((!obj_desc) || +- (obj_desc->common.type != ACPI_TYPE_INTEGER) || +- (!walk_state->method_node)) +- { +- return; +- } +- +- if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) { +- /* +- * We are running a method that exists in a 32-bit ACPI table. +- * Truncate the value to 32 bits by zeroing out the upper 32-bit field +- */ +- obj_desc->integer.value &= (ACPI_INTEGER) ACPI_UINT32_MAX; +- } +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_acquire_global_lock +- * +- * PARAMETERS: Rule - Lock rule: Always_lock, Never_lock +- * +- * RETURN: TRUE/FALSE indicating whether the lock was actually acquired +- * +- * DESCRIPTION: Obtain the global lock and keep track of this fact via two +- * methods. A global variable keeps the state of the lock, and +- * the state is returned to the caller. +- * +- ******************************************************************************/ +- +-u8 +-acpi_aml_acquire_global_lock ( +- u32 rule) +-{ +- u8 locked = FALSE; +- ACPI_STATUS status; +- +- +- /* Only attempt lock if the Rule says so */ +- +- if (rule == (u32) GLOCK_ALWAYS_LOCK) { +- /* OK to get the lock */ +- +- status = acpi_ev_acquire_global_lock (); +- +- if (ACPI_SUCCESS (status)) { +- acpi_gbl_global_lock_set = TRUE; +- locked = TRUE; +- } +- } +- +- return (locked); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_release_global_lock +- * +- * PARAMETERS: Locked_by_me - Return value from corresponding call to +- * Acquire_global_lock. +- * +- * RETURN: Status +- * +- * DESCRIPTION: Release the global lock if it is locked. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_release_global_lock ( +- u8 locked_by_me) +-{ +- +- +- /* Only attempt unlock if the caller locked it */ +- +- if (locked_by_me) { +- /* Double check against the global flag */ +- +- if (acpi_gbl_global_lock_set) { +- /* OK, now release the lock */ +- +- acpi_ev_release_global_lock (); +- acpi_gbl_global_lock_set = FALSE; +- } +- +- } +- +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_digits_needed +- * +- * PARAMETERS: val - Value to be represented +- * base - Base of representation +- * +- * RETURN: the number of digits needed to represent val in base +- * +- ******************************************************************************/ +- +-u32 +-acpi_aml_digits_needed ( +- ACPI_INTEGER val, +- u32 base) +-{ +- u32 num_digits = 0; +- +- +- if (base < 1) { +- REPORT_ERROR (("Aml_digits_needed: Internal error - Invalid base\n")); +- } +- +- else { +- for (num_digits = 1 + (val < 0); (val = ACPI_DIVIDE (val,base)); ++num_digits) { ; } +- } +- +- return (num_digits); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: ntohl +- * +- * PARAMETERS: Value - Value to be converted +- * +- * DESCRIPTION: Convert a 32-bit value to big-endian (swap the bytes) +- * +- ******************************************************************************/ +- +-static u32 +-_ntohl ( +- u32 value) +-{ +- union +- { +- u32 value; +- u8 bytes[4]; +- } out; +- +- union +- { +- u32 value; +- u8 bytes[4]; +- } in; +- +- +- in.value = value; +- +- out.bytes[0] = in.bytes[3]; +- out.bytes[1] = in.bytes[2]; +- out.bytes[2] = in.bytes[1]; +- out.bytes[3] = in.bytes[0]; +- +- return (out.value); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_eisa_id_to_string +- * +- * PARAMETERS: Numeric_id - EISA ID to be converted +- * Out_string - Where to put the converted string (8 bytes) +- * +- * DESCRIPTION: Convert a numeric EISA ID to string representation +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_eisa_id_to_string ( +- u32 numeric_id, +- NATIVE_CHAR *out_string) +-{ +- u32 id; +- +- /* swap to big-endian to get contiguous bits */ +- +- id = _ntohl (numeric_id); +- +- out_string[0] = (char) ('@' + ((id >> 26) & 0x1f)); +- out_string[1] = (char) ('@' + ((id >> 21) & 0x1f)); +- out_string[2] = (char) ('@' + ((id >> 16) & 0x1f)); +- out_string[3] = acpi_gbl_hex_to_ascii[(id >> 12) & 0xf]; +- out_string[4] = acpi_gbl_hex_to_ascii[(id >> 8) & 0xf]; +- out_string[5] = acpi_gbl_hex_to_ascii[(id >> 4) & 0xf]; +- out_string[6] = acpi_gbl_hex_to_ascii[id & 0xf]; +- out_string[7] = 0; +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_unsigned_integer_to_string +- * +- * PARAMETERS: Value - Value to be converted +- * Out_string - Where to put the converted string (8 bytes) +- * +- * RETURN: Convert a number to string representation +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_unsigned_integer_to_string ( +- ACPI_INTEGER value, +- NATIVE_CHAR *out_string) +-{ +- u32 count; +- u32 digits_needed; +- +- +- digits_needed = acpi_aml_digits_needed (value, 10); +- +- out_string[digits_needed] = '\0'; +- +- for (count = digits_needed; count > 0; count--) { +- out_string[count-1] = (NATIVE_CHAR) ('0' + (ACPI_MODULO (value, 10))); +- value = ACPI_DIVIDE (value, 10); +- } +- +- return (AE_OK); +-} +- +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/interpreter/amxface.c linux/drivers/acpi/interpreter/amxface.c +--- /usr/src/linux/drivers/acpi/interpreter/amxface.c Mon Jan 22 13:23:42 2001 ++++ linux/drivers/acpi/interpreter/amxface.c Wed Dec 31 16:00:00 1969 +@@ -1,95 +0,0 @@ +- +-/****************************************************************************** +- * +- * Module Name: amxface - External interpreter interfaces +- * $Revision: 24 $ +- * +- *****************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acinterp.h" +- +- +-#define _COMPONENT INTERPRETER +- MODULE_NAME ("amxface") +- +- +-/* +- * DEFINE_AML_GLOBALS is tested in amlcode.h +- * to determine whether certain global names should be "defined" or only +- * "declared" in the current compilation. This enhances maintainability +- * by enabling a single header file to embody all knowledge of the names +- * in question. +- * +- * Exactly one module of any executable should #define DEFINE_GLOBALS +- * before #including the header files which use this convention. The +- * names in question will be defined and initialized in that module, +- * and declared as extern in all other modules which #include those +- * header files. +- */ +- +-#define DEFINE_AML_GLOBALS +-#include "amlcode.h" +-#include "acparser.h" +-#include "acnamesp.h" +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_aml_execute_method +- * +- * PARAMETERS: Pcode - Pointer to the pcode stream +- * Pcode_length - Length of pcode that comprises the method +- * **Params - List of parameters to pass to method, +- * terminated by NULL. Params itself may be +- * NULL if no parameters are being passed. +- * +- * RETURN: Status +- * +- * DESCRIPTION: Execute a control method +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_aml_execute_method ( +- ACPI_NAMESPACE_NODE *method_node, +- ACPI_OPERAND_OBJECT **params, +- ACPI_OPERAND_OBJECT **return_obj_desc) +-{ +- ACPI_STATUS status; +- +- +- /* +- * The point here is to lock the interpreter and call the low +- * level execute. +- */ +- +- acpi_aml_enter_interpreter (); +- +- status = acpi_psx_execute (method_node, params, return_obj_desc); +- +- acpi_aml_exit_interpreter (); +- +- return (status); +-} +- +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/namespace/Makefile linux/drivers/acpi/namespace/Makefile +--- /usr/src/linux/drivers/acpi/namespace/Makefile Fri Dec 29 14:07:21 2000 ++++ linux/drivers/acpi/namespace/Makefile Fri Apr 13 11:57:11 2001 +@@ -1,5 +1,6 @@ + # + # Makefile for all Linux ACPI interpreter subdirectories ++# EXCEPT for the ospm directory + # + + O_TARGET := ../$(shell basename `pwd`).o +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/namespace/nsaccess.c linux/drivers/acpi/namespace/nsaccess.c +--- /usr/src/linux/drivers/acpi/namespace/nsaccess.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/namespace/nsaccess.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /******************************************************************************* + * + * Module Name: nsaccess - Top-level functions for accessing ACPI namespace +- * $Revision: 119 $ ++ * $Revision: 123 $ + * + ******************************************************************************/ + +@@ -31,7 +31,7 @@ + #include "acdispat.h" + + +-#define _COMPONENT NAMESPACE ++#define _COMPONENT ACPI_NAMESPACE + MODULE_NAME ("nsaccess") + + +@@ -114,8 +114,7 @@ + * used for initial values are implemented here. + */ + +- switch (init_val->type) +- { ++ switch (init_val->type) { + + case ACPI_TYPE_INTEGER: + +@@ -126,8 +125,7 @@ + + case ACPI_TYPE_STRING: + +- obj_desc->string.length = +- (u16) STRLEN (init_val->val); ++ obj_desc->string.length = STRLEN (init_val->val); + + /* + * Allocate a buffer for the string. All +@@ -149,7 +147,7 @@ + case ACPI_TYPE_MUTEX: + + obj_desc->mutex.sync_level = +- (u16) STRTOUL (init_val->val, NULL, 10); ++ (u16) STRTOUL (init_val->val, NULL, 10); + + if (STRCMP (init_val->name, "_GL_") == 0) { + /* +@@ -193,8 +191,7 @@ + + /* Store pointer to value descriptor in the Node */ + +- acpi_ns_attach_object (new_node, obj_desc, +- obj_desc->common.type); ++ acpi_ns_attach_object (new_node, obj_desc, obj_desc->common.type); + } + } + +@@ -271,8 +268,7 @@ + */ + + if ((!scope_info) || +- (!scope_info->scope.node)) +- { ++ (!scope_info->scope.node)) { + prefix_node = acpi_gbl_root_node; + } + else { +@@ -281,14 +277,14 @@ + + + /* +- * This check is explicitly split provide relax the Type_to_check_for ++ * This check is explicitly split to relax the Type_to_check_for + * conditions for Bank_field_defn. Originally, both Bank_field_defn and + * Def_field_defn caused Type_to_check_for to be set to ACPI_TYPE_REGION, + * but the Bank_field_defn may also check for a Field definition as well + * as an Operation_region. + */ + +- if (INTERNAL_TYPE_DEF_FIELD_DEFN == type) { ++ if (INTERNAL_TYPE_FIELD_DEFN == type) { + /* Def_field_defn defines fields in a Region */ + + type_to_check_for = ACPI_TYPE_REGION; +@@ -376,7 +372,8 @@ + if (!this_node) { + /* Current scope has no parent scope */ + +- REPORT_ERROR (("Too many parent prefixes (^) - reached root\n")); ++ REPORT_ERROR ( ++ ("Too many parent prefixes (^) - reached root\n")); + return (AE_NOT_FOUND); + } + +@@ -480,8 +477,7 @@ + (type_to_check_for != INTERNAL_TYPE_SCOPE) && + (type_to_check_for != INTERNAL_TYPE_INDEX_FIELD_DEFN) && + (this_node->type != ACPI_TYPE_ANY) && +- (this_node->type != type_to_check_for)) +- { ++ (this_node->type != type_to_check_for)) { + /* Complain about a type mismatch */ + + REPORT_WARNING ( +@@ -500,8 +496,7 @@ + } + + if ((num_segments || acpi_ns_opens_scope (type)) && +- (this_node->child == NULL)) +- { ++ (this_node->child == NULL)) { + /* + * More segments or the type implies enclosed scope, + * and the next scope has not been allocated. +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/namespace/nsalloc.c linux/drivers/acpi/namespace/nsalloc.c +--- /usr/src/linux/drivers/acpi/namespace/nsalloc.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/namespace/nsalloc.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /******************************************************************************* + * + * Module Name: nsalloc - Namespace allocation and deletion utilities +- * $Revision: 45 $ ++ * $Revision: 47 $ + * + ******************************************************************************/ + +@@ -29,7 +29,7 @@ + #include "acinterp.h" + + +-#define _COMPONENT NAMESPACE ++#define _COMPONENT ACPI_NAMESPACE + MODULE_NAME ("nsalloc") + + +@@ -197,9 +197,8 @@ + */ + + if ((ACPI_TYPE_ANY == type) || +- (INTERNAL_TYPE_DEF_FIELD_DEFN == type) || +- (INTERNAL_TYPE_BANK_FIELD_DEFN == type)) +- { ++ (INTERNAL_TYPE_FIELD_DEFN == type) || ++ (INTERNAL_TYPE_BANK_FIELD_DEFN == type)) { + /* + * We don't want to abort here, however! + * We will fill in the actual type when the +@@ -213,9 +212,8 @@ + * looking up the Region in which the field will be defined + */ + +- if ((INTERNAL_TYPE_DEF_FIELD_DEFN == type) || +- (INTERNAL_TYPE_BANK_FIELD_DEFN == type)) +- { ++ if ((INTERNAL_TYPE_FIELD_DEFN == type) || ++ (INTERNAL_TYPE_BANK_FIELD_DEFN == type)) { + type = ACPI_TYPE_REGION; + } + +@@ -228,8 +226,7 @@ + + if ((type != INTERNAL_TYPE_SCOPE) && + (type != INTERNAL_TYPE_DEF_ANY) && +- (type != INTERNAL_TYPE_INDEX_FIELD_DEFN)) +- { ++ (type != INTERNAL_TYPE_INDEX_FIELD_DEFN)) { + node->type = (u8) type; + } + +@@ -282,8 +279,7 @@ + /* + * Deallocate all children at this level + */ +- do +- { ++ do { + /* Get the things we need */ + + next_node = child_node->peer; +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/namespace/nseval.c linux/drivers/acpi/namespace/nseval.c +--- /usr/src/linux/drivers/acpi/namespace/nseval.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/namespace/nseval.c Fri Apr 13 11:57:11 2001 +@@ -2,7 +2,7 @@ + * + * Module Name: nseval - Object evaluation interfaces -- includes control + * method lookup and execution. +- * $Revision: 83 $ ++ * $Revision: 89 $ + * + ******************************************************************************/ + +@@ -32,7 +32,7 @@ + #include "acnamesp.h" + + +-#define _COMPONENT NAMESPACE ++#define _COMPONENT ACPI_NAMESPACE + MODULE_NAME ("nseval") + + +@@ -348,6 +348,15 @@ + ACPI_OPERAND_OBJECT *obj_desc; + + ++ /* Verify that there is a method associated with this object */ ++ ++ obj_desc = acpi_ns_get_attached_object (method_node); ++ if (!obj_desc) { ++ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); ++ return (AE_ERROR); ++ } ++ ++ + /* + * Unlock the namespace before execution. This allows namespace access + * via the external Acpi* interfaces while a method is being executed. +@@ -355,17 +364,8 @@ + * interpreter locks to ensure that no thread is using the portion of the + * namespace that is being deleted. + */ +- + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + +- /* Verify that there is a method associated with this object */ +- +- obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) method_node); +- if (!obj_desc) { +- return (AE_ERROR); +- } +- +- + /* + * Execute the method via the interpreter + */ +@@ -404,8 +404,7 @@ + */ + + if ((node->type == ACPI_TYPE_PROCESSOR) || +- (node->type == ACPI_TYPE_POWER)) +- { ++ (node->type == ACPI_TYPE_POWER)) { + /* + * Create a Reference object to contain the object + */ +@@ -434,6 +433,7 @@ + + MEMCPY (obj_desc, val_desc, sizeof (ACPI_OPERAND_OBJECT)); + obj_desc->common.reference_count = 1; ++ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + } + + +@@ -452,28 +452,33 @@ + + /* Construct a descriptor pointing to the name */ + +- obj_desc->reference.op_code = (u8) AML_NAME_OP; ++ obj_desc->reference.opcode = (u8) AML_NAME_OP; + obj_desc->reference.object = (void *) node; + + /* +- * Use Acpi_aml_resolve_to_value() to get the associated value. +- * The call to Acpi_aml_resolve_to_value causes +- * Obj_desc (allocated above) to always be deleted. ++ * Use Resolve_to_value() to get the associated value. This call ++ * always deletes Obj_desc (allocated above). + * + * NOTE: we can get away with passing in NULL for a walk state + * because Obj_desc is guaranteed to not be a reference to either + * a method local or a method argument + * +- * Even though we do not technically need to use the interpreter +- * for this, we must enter it because we could hit an opregion. +- * The opregion access code assumes it is in the interpreter. ++ * Even though we do not directly invoke the interpreter ++ * for this, we must enter it because we could access an opregion. ++ * The opregion access code assumes that the interpreter ++ * is locked. ++ * ++ * We must release the namespace lock before entering the ++ * intepreter. + */ + +- acpi_aml_enter_interpreter(); +- +- status = acpi_aml_resolve_to_value (&obj_desc, NULL); ++ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); ++ status = acpi_aml_enter_interpreter (); ++ if (ACPI_SUCCESS (status)) { ++ status = acpi_aml_resolve_to_value (&obj_desc, NULL); + +- acpi_aml_exit_interpreter(); ++ acpi_aml_exit_interpreter (); ++ } + } + + /* +@@ -486,6 +491,10 @@ + + *return_obj_desc = obj_desc; + } ++ ++ /* Namespace is unlocked */ ++ ++ return (status); + + + unlock_and_exit: +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/namespace/nsinit.c linux/drivers/acpi/namespace/nsinit.c +--- /usr/src/linux/drivers/acpi/namespace/nsinit.c Tue Mar 6 19:44:36 2001 ++++ linux/drivers/acpi/namespace/nsinit.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: nsinit - namespace initialization +- * $Revision: 15 $ ++ * $Revision: 22 $ + * + *****************************************************************************/ + +@@ -28,7 +28,7 @@ + #include "acnamesp.h" + #include "acdispat.h" + +-#define _COMPONENT NAMESPACE ++#define _COMPONENT ACPI_NAMESPACE + MODULE_NAME ("nsinit") + + +@@ -70,7 +70,7 @@ + } + + +-/****************************************************************************** ++/******************************************************************************* + * + * FUNCTION: Acpi_ns_initialize_devices + * +@@ -81,11 +81,10 @@ + * DESCRIPTION: Walk the entire namespace and initialize all ACPI devices. + * This means running _INI on all present devices. + * +- * Also: Install PCI config space handler for all PCI root bridges. +- * A PCI root bridge is found by searching for devices containing +- * a HID with the value EISAID("PNP0A03") ++ * Note: We install PCI config space handler on region access, ++ * not here. + * +- *****************************************************************************/ ++ ******************************************************************************/ + + ACPI_STATUS + acpi_ns_initialize_devices ( +@@ -100,8 +99,8 @@ + info.num_INI = 0; + + +- status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, +- FALSE, acpi_ns_init_one_device, &info, NULL); ++ status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ++ ACPI_UINT32_MAX, FALSE, acpi_ns_init_one_device, &info, NULL); + + + +@@ -154,8 +153,7 @@ + return (AE_OK); + } + +- switch (type) +- { ++ switch (type) { + + case ACPI_TYPE_REGION: + +@@ -171,7 +169,7 @@ + break; + + +- case ACPI_TYPE_FIELD_UNIT: ++ case ACPI_TYPE_BUFFER_FIELD: + + info->field_count++; + if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { +@@ -179,7 +177,7 @@ + } + + info->field_init++; +- status = acpi_ds_get_field_unit_arguments (obj_desc); ++ status = acpi_ds_get_buffer_field_arguments (obj_desc); + + + break; +@@ -196,7 +194,7 @@ + } + + +-/****************************************************************************** ++/******************************************************************************* + * + * FUNCTION: Acpi_ns_init_one_device + * +@@ -208,7 +206,7 @@ + * to initialize each device. It determines if the device is + * present, and if so, calls _INI. + * +- *****************************************************************************/ ++ ******************************************************************************/ + + ACPI_STATUS + acpi_ns_init_one_device ( +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/namespace/nsload.c linux/drivers/acpi/namespace/nsload.c +--- /usr/src/linux/drivers/acpi/namespace/nsload.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/namespace/nsload.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: nsload - namespace loading/expanding/contracting procedures +- * $Revision: 35 $ ++ * $Revision: 39 $ + * + *****************************************************************************/ + +@@ -33,11 +33,11 @@ + #include "acdebug.h" + + +-#define _COMPONENT NAMESPACE ++#define _COMPONENT ACPI_NAMESPACE + MODULE_NAME ("nsload") + + +-/****************************************************************************** ++/******************************************************************************* + * + * FUNCTION: Acpi_load_namespace + * +@@ -107,8 +107,7 @@ + ACPI_STATUS status; + + +- switch (pass_number) +- { ++ switch (pass_number) { + case 1: + descending_callback = acpi_ds_load1_begin_op; + ascending_callback = acpi_ds_load1_end_op; +@@ -140,12 +139,10 @@ + + /* Pass 1: Parse everything except control method bodies */ + +- status = acpi_ps_parse_aml (parse_root, +- table_desc->aml_pointer, ++ status = acpi_ps_parse_aml (parse_root, table_desc->aml_pointer, + table_desc->aml_length, + ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE, +- NULL, NULL, NULL, +- descending_callback, ++ NULL, NULL, NULL, descending_callback, + ascending_callback); + + acpi_ps_delete_parse_tree (parse_root); +@@ -211,7 +208,7 @@ + } + + +-/***************************************************************************** ++/******************************************************************************* + * + * FUNCTION: Acpi_ns_load_table + * +@@ -222,7 +219,7 @@ + * + * DESCRIPTION: Load one ACPI table into the namespace + * +- ****************************************************************************/ ++ ******************************************************************************/ + + ACPI_STATUS + acpi_ns_load_table ( +@@ -273,7 +270,7 @@ + } + + +-/****************************************************************************** ++/******************************************************************************* + * + * FUNCTION: Acpi_ns_load_table_by_type + * +@@ -285,7 +282,7 @@ + * of the given type are loaded. The mechanism allows this + * routine to be called repeatedly. + * +- *****************************************************************************/ ++ ******************************************************************************/ + + ACPI_STATUS + acpi_ns_load_table_by_type ( +@@ -293,7 +290,6 @@ + { + u32 i; + ACPI_STATUS status = AE_OK; +- ACPI_TABLE_HEADER *table_ptr; + ACPI_TABLE_DESC *table_desc; + + +@@ -305,8 +301,7 @@ + * DSDT (one), SSDT/PSDT (multiple) + */ + +- switch (table_type) +- { ++ switch (table_type) { + + case ACPI_TABLE_DSDT: + +@@ -338,16 +333,13 @@ + + table_desc = &acpi_gbl_acpi_tables[ACPI_TABLE_SSDT]; + for (i = 0; i < acpi_gbl_acpi_tables[ACPI_TABLE_SSDT].count; i++) { +- table_ptr = table_desc->pointer; +- + /* + * Only attempt to load table if it is not + * already loaded! + */ + + if (!table_desc->loaded_into_namespace) { +- status = acpi_ns_load_table (table_desc, +- acpi_gbl_root_node); ++ status = acpi_ns_load_table (table_desc, acpi_gbl_root_node); + if (ACPI_FAILURE (status)) { + break; + } +@@ -357,7 +349,6 @@ + + table_desc = table_desc->next; + } +- + break; + + +@@ -370,13 +361,10 @@ + table_desc = &acpi_gbl_acpi_tables[ACPI_TABLE_PSDT]; + + for (i = 0; i < acpi_gbl_acpi_tables[ACPI_TABLE_PSDT].count; i++) { +- table_ptr = table_desc->pointer; +- + /* Only attempt to load table if it is not already loaded! */ + + if (!table_desc->loaded_into_namespace) { +- status = acpi_ns_load_table (table_desc, +- acpi_gbl_root_node); ++ status = acpi_ns_load_table (table_desc, acpi_gbl_root_node); + if (ACPI_FAILURE (status)) { + break; + } +@@ -392,6 +380,7 @@ + + default: + status = AE_SUPPORT; ++ break; + } + + +@@ -404,7 +393,7 @@ + } + + +-/****************************************************************************** ++/******************************************************************************* + * + * FUNCTION: Acpi_ns_delete_subtree + * +@@ -432,9 +421,9 @@ + u32 level; + + +- parent_handle = start_handle; +- child_handle = 0; +- level = 1; ++ parent_handle = start_handle; ++ child_handle = 0; ++ level = 1; + + /* + * Traverse the tree of objects until we bubble back up +@@ -445,8 +434,7 @@ + /* Attempt to get the next object in this scope */ + + status = acpi_get_next_object (ACPI_TYPE_ANY, parent_handle, +- child_handle, +- &next_child_handle); ++ child_handle, &next_child_handle); + + child_handle = next_child_handle; + +@@ -456,18 +444,16 @@ + if (ACPI_SUCCESS (status)) { + /* Check if this object has any children */ + +- if (ACPI_SUCCESS (acpi_get_next_object (ACPI_TYPE_ANY, +- child_handle, 0, +- &dummy))) +- { ++ if (ACPI_SUCCESS (acpi_get_next_object (ACPI_TYPE_ANY, child_handle, ++ 0, &dummy))) { + /* + * There is at least one child of this object, + * visit the object + */ + + level++; +- parent_handle = child_handle; +- child_handle = 0; ++ parent_handle = child_handle; ++ child_handle = 0; + } + } + +@@ -491,12 +477,11 @@ + + acpi_ns_delete_node (child_handle); + +- + return (AE_OK); + } + + +-/**************************************************************************** ++/******************************************************************************* + * + * FUNCTION: Acpi_ns_unload_name_space + * +@@ -508,7 +493,7 @@ + * event. Deletes an entire subtree starting from (and + * including) the given handle. + * +- ****************************************************************************/ ++ ******************************************************************************/ + + ACPI_STATUS + acpi_ns_unload_namespace ( +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/namespace/nsnames.c linux/drivers/acpi/namespace/nsnames.c +--- /usr/src/linux/drivers/acpi/namespace/nsnames.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/namespace/nsnames.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /******************************************************************************* + * + * Module Name: nsnames - Name manipulation and search +- * $Revision: 54 $ ++ * $Revision: 56 $ + * + ******************************************************************************/ + +@@ -30,7 +30,7 @@ + #include "acnamesp.h" + + +-#define _COMPONENT NAMESPACE ++#define _COMPONENT ACPI_NAMESPACE + MODULE_NAME ("nsnames") + + +@@ -95,8 +95,7 @@ + + name_buffer[size] = '\0'; + while ((size > ACPI_NAME_SIZE) && +- acpi_ns_get_parent_object (child_node)) +- { ++ acpi_ns_get_parent_object (child_node)) { + size -= ACPI_NAME_SIZE; + name = acpi_ns_find_parent_name (child_node); + +@@ -138,8 +137,7 @@ + */ + for (size = 0, next_node = node; + acpi_ns_get_parent_object (next_node); +- next_node = acpi_ns_get_parent_object (next_node)) +- { ++ next_node = acpi_ns_get_parent_object (next_node)) { + size += PATH_SEGMENT_LENGTH; + } + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/namespace/nsobject.c linux/drivers/acpi/namespace/nsobject.c +--- /usr/src/linux/drivers/acpi/namespace/nsobject.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/namespace/nsobject.c Fri Apr 13 11:57:11 2001 +@@ -2,7 +2,7 @@ + * + * Module Name: nsobject - Utilities for objects attached to namespace + * table entries +- * $Revision: 49 $ ++ * $Revision: 52 $ + * + ******************************************************************************/ + +@@ -32,7 +32,7 @@ + #include "actables.h" + + +-#define _COMPONENT NAMESPACE ++#define _COMPONENT ACPI_NAMESPACE + MODULE_NAME ("nsobject") + + +@@ -124,8 +124,7 @@ + */ + + else if (VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_NAMED) && +- ((ACPI_NAMESPACE_NODE *) object)->object) +- { ++ ((ACPI_NAMESPACE_NODE *) object)->object) { + /* + * Value passed is a name handle and that name has a + * non-null value. Use that name's value and type. +@@ -183,10 +182,9 @@ + + MOVE_UNALIGNED16_TO_16 (&opcode, object); + +- /* Check for a recognized Op_code */ ++ /* Check for a recognized Opcode */ + +- switch ((u8) opcode) +- { ++ switch ((u8) opcode) { + + case AML_OP_PREFIX: + +@@ -339,7 +337,7 @@ + * + * FUNCTION: Acpi_ns_get_attached_object + * +- * PARAMETERS: Handle - Parent Node to be examined ++ * PARAMETERS: Node - Parent Node to be examined + * + * RETURN: Current value of the object field from the Node whose + * handle is passed +@@ -348,16 +346,16 @@ + + void * + acpi_ns_get_attached_object ( +- ACPI_HANDLE handle) ++ ACPI_NAMESPACE_NODE *node) + { + +- if (!handle) { ++ if (!node) { + /* handle invalid */ + + return (NULL); + } + +- return (((ACPI_NAMESPACE_NODE *) handle)->object); ++ return (node->object); + } + + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/namespace/nssearch.c linux/drivers/acpi/namespace/nssearch.c +--- /usr/src/linux/drivers/acpi/namespace/nssearch.c Mon Jan 29 10:15:59 2001 ++++ linux/drivers/acpi/namespace/nssearch.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /******************************************************************************* + * + * Module Name: nssearch - Namespace search +- * $Revision: 64 $ ++ * $Revision: 67 $ + * + ******************************************************************************/ + +@@ -30,7 +30,7 @@ + #include "acnamesp.h" + + +-#define _COMPONENT NAMESPACE ++#define _COMPONENT ACPI_NAMESPACE + MODULE_NAME ("nssearch") + + +@@ -39,9 +39,9 @@ + * FUNCTION: Acpi_ns_search_node + * + * PARAMETERS: *Target_name - Ascii ACPI name to search for +- * *Node - Starting table where search will begin ++ * *Node - Starting table where search will begin + * Type - Object type to match +- * **Return_node - Where the matched Named obj is returned ++ * **Return_node - Where the matched Named obj is returned + * + * RETURN: Status + * +@@ -81,36 +81,29 @@ + + if (next_node->name == target_name) { + /* +- * Found matching entry. Capture type if +- * appropriate before returning the entry. ++ * Found matching entry. Capture the type if appropriate, before ++ * returning the entry. ++ * ++ * The Def_field_defn and Bank_field_defn cases are actually looking up ++ * the Region in which the field will be defined + */ + +- /* +- * The Def_field_defn and Bank_field_defn cases +- * are actually looking up the Region in which +- * the field will be defined +- */ +- +- if ((INTERNAL_TYPE_DEF_FIELD_DEFN == type) || +- (INTERNAL_TYPE_BANK_FIELD_DEFN == type)) +- { ++ if ((INTERNAL_TYPE_FIELD_DEFN == type) || ++ (INTERNAL_TYPE_BANK_FIELD_DEFN == type)) { + type = ACPI_TYPE_REGION; + } + + /* +- * Scope, Def_any, and Index_field_defn are bogus +- * "types" which do not actually have anything +- * to do with the type of the name being looked +- * up. For any other value of Type, if the type +- * stored in the entry is Any (i.e. unknown), +- * save the actual type. ++ * Scope, Def_any, and Index_field_defn are bogus "types" which do not ++ * actually have anything to do with the type of the name being ++ * looked up. For any other value of Type, if the type stored in ++ * the entry is Any (i.e. unknown), save the actual type. + */ + + if (type != INTERNAL_TYPE_SCOPE && + type != INTERNAL_TYPE_DEF_ANY && + type != INTERNAL_TYPE_INDEX_FIELD_DEFN && +- next_node->type == ACPI_TYPE_ANY) +- { ++ next_node->type == ACPI_TYPE_ANY) { + next_node->type = (u8) type; + } + +@@ -147,9 +140,9 @@ + * FUNCTION: Acpi_ns_search_parent_tree + * + * PARAMETERS: *Target_name - Ascii ACPI name to search for +- * *Node - Starting table where search will begin ++ * *Node - Starting table where search will begin + * Type - Object type to match +- * **Return_node - Where the matched Named Obj is returned ++ * **Return_node - Where the matched Named Obj is returned + * + * RETURN: Status + * +@@ -185,8 +178,7 @@ + * searching the parent tree. + */ + if ((acpi_ns_local (type)) || +- (!parent_node)) +- { ++ (!parent_node)) { + + + return (AE_NOT_FOUND); +@@ -232,12 +224,12 @@ + * + * PARAMETERS: Target_name - Ascii ACPI name to search for (4 chars) + * Walk_state - Current state of the walk +- * *Node - Starting table where search will begin ++ * *Node - Starting table where search will begin + * Interpreter_mode - Add names only in MODE_Load_pass_x. + * Otherwise,search only. + * Type - Object type to match + * Flags - Flags describing the search restrictions +- * **Return_node - Where the Node is returned ++ * **Return_node - Where the Node is returned + * + * RETURN: Status + * +@@ -288,12 +280,11 @@ + type, return_node); + if (status != AE_NOT_FOUND) { + /* +- * If we found it AND the request specifies that a +- * find is an error, return the error ++ * If we found it AND the request specifies that a find is an error, ++ * return the error + */ + if ((status == AE_OK) && +- (flags & NS_ERROR_IF_FOUND)) +- { ++ (flags & NS_ERROR_IF_FOUND)) { + status = AE_EXIST; + } + +@@ -316,8 +307,7 @@ + */ + + if ((interpreter_mode != IMODE_LOAD_PASS1) && +- (flags & NS_SEARCH_PARENT)) +- { ++ (flags & NS_SEARCH_PARENT)) { + /* + * Not found in table - search parent tree according + * to ACPI specification +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/namespace/nsutils.c linux/drivers/acpi/namespace/nsutils.c +--- /usr/src/linux/drivers/acpi/namespace/nsutils.c Mon Jan 29 10:15:59 2001 ++++ linux/drivers/acpi/namespace/nsutils.c Fri Apr 13 11:57:11 2001 +@@ -2,7 +2,7 @@ + * + * Module Name: nsutils - Utilities for accessing ACPI namespace, accessing + * parents and siblings and Scope manipulation +- * $Revision: 77 $ ++ * $Revision: 79 $ + * + *****************************************************************************/ + +@@ -31,7 +31,7 @@ + #include "amlcode.h" + #include "actables.h" + +-#define _COMPONENT NAMESPACE ++#define _COMPONENT ACPI_NAMESPACE + MODULE_NAME ("nsutils") + + +@@ -89,15 +89,15 @@ + + OBJECT_TYPE_INTERNAL + acpi_ns_get_type ( +- ACPI_HANDLE handle) ++ ACPI_NAMESPACE_NODE *node) + { + +- if (!handle) { +- REPORT_WARNING (("Ns_get_type: Null handle\n")); ++ if (!node) { ++ REPORT_WARNING (("Ns_get_type: Null Node ptr")); + return (ACPI_TYPE_ANY); + } + +- return (((ACPI_NAMESPACE_NODE *) handle)->type); ++ return (node->type); + } + + +@@ -158,8 +158,7 @@ + + if ((!external_name) || + (*external_name == 0) || +- (!converted_name)) +- { ++ (!converted_name)) { + return (AE_BAD_PARAMETER); + } + +@@ -270,8 +269,7 @@ + for (; num_segments; num_segments--) { + for (i = 0; i < ACPI_NAME_SIZE; i++) { + if (acpi_ns_valid_path_separator (*external_name) || +- (*external_name == 0)) +- { ++ (*external_name == 0)) { + /* + * Pad the segment with underscore(s) if + * segment is short +@@ -292,8 +290,7 @@ + /* Now we must have a path separator, or the pathname is bad */ + + if (!acpi_ns_valid_path_separator (*external_name) && +- (*external_name != 0)) +- { ++ (*external_name != 0)) { + acpi_cm_free (internal_name); + return (AE_BAD_PARAMETER); + } +@@ -349,8 +346,7 @@ + if (!internal_name_length || + !internal_name || + !converted_name_length || +- !converted_name) +- { ++ !converted_name) { + return (AE_BAD_PARAMETER); + } + +@@ -358,8 +354,7 @@ + /* + * Check for a prefix (one '\' | one or more '^'). + */ +- switch (internal_name[0]) +- { ++ switch (internal_name[0]) { + case '\\': + prefix_length = 1; + break; +@@ -383,8 +378,7 @@ + * 4-byte elements. + */ + if (prefix_length < internal_name_length) { +- switch (internal_name[prefix_length]) +- { ++ switch (internal_name[prefix_length]) { + + /* <count> 4-byte names */ + +@@ -539,11 +533,13 @@ + + /* --------------------------------------------------- + +- if (!Node) { ++ if (!Node) ++ { + return (NULL); + } + +- if (Node == Acpi_gbl_Root_node) { ++ if (Node == Acpi_gbl_Root_node) ++ { + return (ACPI_ROOT_OBJECT); + } + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/namespace/nswalk.c linux/drivers/acpi/namespace/nswalk.c +--- /usr/src/linux/drivers/acpi/namespace/nswalk.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/namespace/nswalk.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: nswalk - Functions for walking the APCI namespace +- * $Revision: 19 $ ++ * $Revision: 20 $ + * + *****************************************************************************/ + +@@ -29,7 +29,7 @@ + #include "acnamesp.h" + + +-#define _COMPONENT NAMESPACE ++#define _COMPONENT ACPI_NAMESPACE + MODULE_NAME ("nswalk") + + +@@ -212,8 +212,7 @@ + acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); + } + +- switch (status) +- { ++ switch (status) { + case AE_OK: + case AE_CTRL_DEPTH: + /* Just keep going */ +@@ -242,8 +241,7 @@ + + if ((level < max_depth) && (status != AE_CTRL_DEPTH)) { + if (acpi_ns_get_next_object (ACPI_TYPE_ANY, +- child_node, 0)) +- { ++ child_node, 0)) { + /* + * There is at least one child of this + * object, visit the object +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/namespace/nsxfname.c linux/drivers/acpi/namespace/nsxfname.c +--- /usr/src/linux/drivers/acpi/namespace/nsxfname.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/namespace/nsxfname.c Fri Apr 13 11:57:11 2001 +@@ -2,7 +2,7 @@ + * + * Module Name: nsxfname - Public interfaces to the ACPI subsystem + * ACPI Namespace oriented interfaces +- * $Revision: 75 $ ++ * $Revision: 76 $ + * + *****************************************************************************/ + +@@ -34,7 +34,7 @@ + #include "acevents.h" + + +-#define _COMPONENT NAMESPACE ++#define _COMPONENT ACPI_NAMESPACE + MODULE_NAME ("nsxfname") + + +@@ -141,8 +141,7 @@ + /* Allow length to be zero and ignore the pointer */ + + if ((ret_path_ptr->length) && +- (!ret_path_ptr->pointer)) +- { ++ (!ret_path_ptr->pointer)) { + return (AE_BAD_PARAMETER); + } + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/namespace/nsxfobj.c linux/drivers/acpi/namespace/nsxfobj.c +--- /usr/src/linux/drivers/acpi/namespace/nsxfobj.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/namespace/nsxfobj.c Fri Apr 13 11:57:11 2001 +@@ -2,7 +2,7 @@ + * + * Module Name: nsxfobj - Public interfaces to the ACPI subsystem + * ACPI Object oriented interfaces +- * $Revision: 80 $ ++ * $Revision: 81 $ + * + ******************************************************************************/ + +@@ -31,7 +31,7 @@ + #include "acdispat.h" + + +-#define _COMPONENT NAMESPACE ++#define _COMPONENT ACPI_NAMESPACE + MODULE_NAME ("nsxfobj") + + +@@ -136,8 +136,7 @@ + */ + + if ((pathname) && +- (acpi_ns_valid_root_prefix (pathname[0]))) +- { ++ (acpi_ns_valid_root_prefix (pathname[0]))) { + /* + * The path is fully qualified, just evaluate by name + */ +@@ -521,8 +520,7 @@ + + if ((type > ACPI_TYPE_MAX) || + (!max_depth) || +- (!user_function)) +- { ++ (!user_function)) { + return (AE_BAD_PARAMETER); + } + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/os.c linux/drivers/acpi/os.c +--- /usr/src/linux/drivers/acpi/os.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/os.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,15 @@ ++/****************************************************************************** ++ * ++ * Module Name: os.c - Linux OSL functions ++ * $Revision: 22 $ ++ * ++ *****************************************************************************/ ++ + /* + * os.c - OS-dependent functions + * + * Copyright (C) 2000 Andrew Henroid ++ * Copyright (C) 2001 Andrew Grover + * + * 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 +@@ -19,22 +27,29 @@ + */ + + #include <linux/kernel.h> +-#include <linux/types.h> + #include <linux/slab.h> + #include <linux/mm.h> + #include <linux/pci.h> +-#include <linux/acpi.h> ++#include <linux/interrupt.h> ++#include <linux/kmod.h> + #include <linux/delay.h> + #include <asm/io.h> +-#include "acpi.h" ++#include <acpi.h> + #include "driver.h" + +-#define _COMPONENT OS_DEPENDENT ++#define _COMPONENT ACPI_OS_SERVICES + MODULE_NAME ("os") + +-static int acpi_irq_irq = 0; +-static OSD_HANDLER acpi_irq_handler = NULL; +-static void *acpi_irq_context = NULL; ++typedef struct ++{ ++ OSD_EXECUTION_CALLBACK function; ++ void *context; ++} ACPI_OS_DPC; ++ ++ ++/***************************************************************************** ++ * Debugger Stuff ++ *****************************************************************************/ + + #ifdef ENABLE_DEBUGGER + +@@ -47,6 +62,19 @@ + #endif + + ++/***************************************************************************** ++ * Globals ++ *****************************************************************************/ ++ ++static int acpi_irq_irq = 0; ++static OSD_HANDLER acpi_irq_handler = NULL; ++static void *acpi_irq_context = NULL; ++ ++ ++/****************************************************************************** ++ * Functions ++ *****************************************************************************/ ++ + ACPI_STATUS + acpi_os_initialize(void) + { +@@ -141,6 +169,17 @@ + iounmap(virt); + } + ++ACPI_STATUS ++acpi_os_get_physical_address(void *virt, ACPI_PHYSICAL_ADDRESS *phys) ++{ ++ if(!phys || !virt) ++ return AE_BAD_PARAMETER; ++ ++ *phys = virt_to_phys(virt); ++ ++ return AE_OK; ++} ++ + static void + acpi_irq(int irq, void *dev_id, struct pt_regs *regs) + { +@@ -171,6 +210,7 @@ + free_irq(irq, acpi_irq); + acpi_irq_handler = NULL; + } ++ + return AE_OK; + } + +@@ -265,10 +305,10 @@ + + ACPI_STATUS + acpi_os_read_pci_cfg_byte( +- u32 bus, +- u32 func, +- u32 addr, +- u8 * val) ++ u32 bus, ++ u32 func, ++ u32 addr, ++ u8 * val) + { + int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff); + struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn); +@@ -279,10 +319,10 @@ + + ACPI_STATUS + acpi_os_read_pci_cfg_word( +- u32 bus, +- u32 func, +- u32 addr, +- u16 * val) ++ u32 bus, ++ u32 func, ++ u32 addr, ++ u16 * val) + { + int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff); + struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn); +@@ -293,10 +333,10 @@ + + ACPI_STATUS + acpi_os_read_pci_cfg_dword( +- u32 bus, +- u32 func, +- u32 addr, +- u32 * val) ++ u32 bus, ++ u32 func, ++ u32 addr, ++ u32 * val) + { + int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff); + struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn); +@@ -307,10 +347,10 @@ + + ACPI_STATUS + acpi_os_write_pci_cfg_byte( +- u32 bus, +- u32 func, +- u32 addr, +- u8 val) ++ u32 bus, ++ u32 func, ++ u32 addr, ++ u8 val) + { + int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff); + struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn); +@@ -321,10 +361,10 @@ + + ACPI_STATUS + acpi_os_write_pci_cfg_word( +- u32 bus, +- u32 func, +- u32 addr, +- u16 val) ++ u32 bus, ++ u32 func, ++ u32 addr, ++ u16 val) + { + int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff); + struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn); +@@ -335,10 +375,10 @@ + + ACPI_STATUS + acpi_os_write_pci_cfg_dword( +- u32 bus, +- u32 func, +- u32 addr, +- u32 val) ++ u32 bus, ++ u32 func, ++ u32 addr, ++ u32 val) + { + int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff); + struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn); +@@ -347,49 +387,295 @@ + return AE_OK; + } + +-/* +- * Queue for interpreter thread +- */ ++ACPI_STATUS ++acpi_os_load_module ( ++ char *module_name) ++{ ++ FUNCTION_TRACE("acpi_os_load_module"); ++ ++ if (!module_name) ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ ++ if (0 > request_module(module_name)) { ++ DEBUG_PRINT(ACPI_WARN, ("Unable to load module [%s].\n", module_name)); ++ return_ACPI_STATUS(AE_ERROR); ++ } ++ ++ return_ACPI_STATUS(AE_OK); ++} + + ACPI_STATUS +-acpi_os_queue_for_execution( +- u32 priority, +- OSD_EXECUTION_CALLBACK callback, +- void *context) ++acpi_os_unload_module ( ++ char *module_name) + { +- if (acpi_run(callback, context)) +- return AE_ERROR; +- return AE_OK; ++ FUNCTION_TRACE("acpi_os_unload_module"); ++ ++ if (!module_name) ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ ++ /* TODO: How on Linux? */ ++ /* this is done automatically for all modules with ++ use_count = 0, I think. see: MOD_INC_USE_COUNT -ASG */ ++ ++ return_ACPI_STATUS(AE_OK); + } + ++ + /* +- * Semaphores are unused, interpreter access is single threaded ++ * See acpi_os_queue_for_execution(), too + */ ++static int ++acpi_os_queue_exec ( ++ void *context) ++{ ++ ACPI_OS_DPC *dpc = (ACPI_OS_DPC*)context; ++ ++ FUNCTION_TRACE("acpi_os_queue_exec"); ++ ++ daemonize(); ++ strcpy(current->comm, "kacpidpc"); ++ ++ if (!dpc || !dpc->function) ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ ++ DEBUG_PRINT(ACPI_INFO, ("Calling [%p]([%p])\n", dpc->function, dpc->context)); ++ ++ dpc->function(dpc->context); ++ ++ acpi_os_free(dpc); ++ ++ return_VALUE(1); ++} + + ACPI_STATUS +-acpi_os_create_semaphore(u32 max_units, u32 init, ACPI_HANDLE * handle) ++acpi_os_queue_for_execution( ++ u32 priority, ++ OSD_EXECUTION_CALLBACK function, ++ void *context) + { +- /* a hack to fake out sems until we implement them */ +- *handle = (ACPI_HANDLE) handle; +- return AE_OK; ++ ACPI_STATUS status = AE_OK; ++ ++ FUNCTION_TRACE("acpi_os_queue_for_execution"); ++ ++ if (!function) ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ ++ DEBUG_PRINT(ACPI_INFO, ("Scheduling task [%p](%p) for execution.\n", function, context)); ++ ++ /* ++ * Queue via DPC: ++ * -------------- ++ * Note that we have to use two different processes for queuing DPCs: ++ * Interrupt-Level: Use schedule_task; can't spawn a new thread. ++ * Kernel-Level: Spawn a new kernel thread, as schedule_task has ++ * its limitations (e.g. single-threaded model), and ++ * all other task queues run at interrupt-level. ++ */ ++ switch (priority) { ++ ++ case OSD_PRIORITY_GPE: ++ { ++ static struct tq_struct dpc; ++ ++ memset(&dpc, 0, sizeof(struct tq_struct)); ++ ++ dpc.routine = function; ++ dpc.data = context; ++ ++ if (schedule_task(&dpc) < 0) { ++ DEBUG_PRINT(ACPI_ERROR, ("Call to schedule_task() failed.\n")); ++ status = AE_ERROR; ++ } ++ } ++ break; ++ ++ default: ++ { ++ ACPI_OS_DPC *dpc = NULL; ++ int thread_pid = -1; ++ ++ dpc = acpi_os_callocate(sizeof(ACPI_OS_DPC)); ++ if (!dpc) ++ return AE_NO_MEMORY; ++ ++ dpc->function = function; ++ dpc->context = context; ++ ++ thread_pid = kernel_thread(acpi_os_queue_exec, dpc, ++ (CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD)); ++ if (thread_pid < 0) { ++ DEBUG_PRINT(ACPI_ERROR, ("Call to kernel_thread() failed.\n")); ++ acpi_os_free(dpc); ++ status = AE_ERROR; ++ } ++ } ++ break; ++ } ++ ++ return_ACPI_STATUS(status); + } + + ACPI_STATUS +-acpi_os_delete_semaphore(ACPI_HANDLE handle) ++acpi_os_create_semaphore( ++ u32 max_units, ++ u32 initial_units, ++ ACPI_HANDLE *handle) + { +- return AE_OK; ++ struct semaphore *sem = NULL; ++ ++ FUNCTION_TRACE("acpi_os_create_semaphore"); ++ ++ sem = acpi_os_callocate(sizeof(struct semaphore)); ++ if (!sem) ++ return_ACPI_STATUS(AE_NO_MEMORY); ++ ++ sema_init(sem, initial_units); ++ ++ *handle = (ACPI_HANDLE*)sem; ++ ++ DEBUG_PRINT(ACPI_INFO, ("Creating semaphore[%p|%d].\n", *handle, initial_units)); ++ ++ return_ACPI_STATUS(AE_OK); + } + ++ ++/* ++ * TODO: A better way to delete semaphores? Linux doesn't have a ++ * 'delete_semaphore()' function -- may result in an invalid ++ * pointer dereference for non-synchronized consumers. Should ++ * we at least check for blocked threads and signal/cancel them? ++ */ ++ + ACPI_STATUS +-acpi_os_wait_semaphore(ACPI_HANDLE handle, u32 units, u32 timeout) ++acpi_os_delete_semaphore( ++ ACPI_HANDLE handle) + { +- return AE_OK; ++ struct semaphore *sem = (struct semaphore*)handle; ++ ++ FUNCTION_TRACE("acpi_os_delete_semaphore"); ++ ++ if (!sem) ++ return AE_BAD_PARAMETER; ++ ++ DEBUG_PRINT(ACPI_INFO, ("Deleting semaphore[%p].\n", handle)); ++ ++ acpi_os_free(sem); sem = NULL; ++ ++ return_ACPI_STATUS(AE_OK); ++} ++ ++ ++/* ++ * TODO: The kernel doesn't have a 'down_timeout' function -- had to ++ * improvise. The process is to sleep for one scheduler quantum ++ * until the semaphore becomes available. Downside is that this ++ * may result in starvation for timeout-based waits when there's ++ * lots of semaphore activity. ++ * ++ * TODO: Support for units > 1? ++ */ ++ACPI_STATUS ++acpi_os_wait_semaphore( ++ ACPI_HANDLE handle, ++ u32 units, ++ u32 timeout) ++{ ++ ACPI_STATUS status = AE_OK; ++ struct semaphore *sem = (struct semaphore*)handle; ++ int ret = 0; ++ ++ FUNCTION_TRACE("acpi_os_wait_semaphore"); ++ ++ if (!sem || (units < 1)) ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ ++ if (units > 1) ++ return_ACPI_STATUS(AE_SUPPORT); ++ ++ DEBUG_PRINT(ACPI_INFO, ("Waiting for semaphore[%p|%d|%d]\n", handle, units, timeout)); ++ ++ switch (timeout) ++ { ++ /* ++ * No Wait: ++ * -------- ++ * A zero timeout value indicates that we shouldn't wait - just ++ * acquire the semaphore if available otherwise return AE_TIME ++ * (a.k.a. 'would block'). ++ */ ++ case 0: ++ ret = down_trylock(sem); ++ if (ret < 0) ++ status = AE_TIME; ++ break; ++ ++ /* ++ * Wait Indefinitely: ++ * ------------------ ++ */ ++ case WAIT_FOREVER: ++ ret = down_interruptible(sem); ++ if (ret < 0) ++ status = AE_ERROR; ++ break; ++ ++ /* ++ * Wait w/ Timeout: ++ * ---------------- ++ */ ++ default: ++ // TODO: A better timeout algorithm? ++ { ++ int i = 0; ++ static const int quantum_ms = 1000/HZ; ++ ++ ret = down_trylock(sem); ++ for (i = timeout; (i > 0 && ret < 0); i -= quantum_ms) { ++ current->state = TASK_INTERRUPTIBLE; ++ schedule_timeout(1); ++ ret = down_trylock(sem); ++ } ++ ++ if (ret < 0) ++ status = AE_TIME; ++ } ++ break; ++ } ++ ++ if (ACPI_FAILURE(status)) { ++ DEBUG_PRINT(ACPI_INFO, ("Failed to acquire semaphore[%p|%d|%d]\n", handle, units, timeout)); ++ } ++ else { ++ DEBUG_PRINT(ACPI_INFO, ("Acquired semaphore[%p|%d|%d]\n", handle, units, timeout)); ++ } ++ ++ return_ACPI_STATUS(status); + } + ++ ++/* ++ * TODO: Support for units > 1? ++ */ + ACPI_STATUS +-acpi_os_signal_semaphore(ACPI_HANDLE handle, u32 units) ++acpi_os_signal_semaphore( ++ ACPI_HANDLE handle, ++ u32 units) + { +- return AE_OK; ++ struct semaphore *sem = (struct semaphore *) handle; ++ ++ FUNCTION_TRACE("acpi_os_signal_semaphore"); ++ ++ if (!sem || (units < 1)) ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ ++ if (units > 1) ++ return_ACPI_STATUS(AE_SUPPORT); ++ ++ DEBUG_PRINT(ACPI_INFO, ("Signaling semaphore[%p|%d]\n", handle, units)); ++ ++ up(sem); ++ ++ return_ACPI_STATUS(AE_OK); + } + + ACPI_STATUS +@@ -399,8 +685,10 @@ + return AE_OK; + } + ++ + void + acpi_os_dbg_trap(char *msg) ++ + { + acpi_os_printf("trap: %s", msg); + } +@@ -421,7 +709,7 @@ + + kdb_read(buffer, sizeof(line_buf)); + +- /* remove the CR kdb includes */ ++ /* remove the CR kdb includes */ + chars = strlen(buffer) - 1; + buffer[chars] = '\0'; + } +@@ -444,4 +732,15 @@ + acpi_os_writable(void *ptr, u32 len) + { + return 1; ++} ++ ++u32 ++acpi_os_get_thread_id (void) ++{ ++ if (!in_interrupt()) ++ return current->pid; ++ ++ acpi_os_printf("acpi_os_get_thread_id called from interrupt level!\n"); ++ ++ return 0; + } +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/Makefile linux/drivers/acpi/ospm/Makefile +--- /usr/src/linux/drivers/acpi/ospm/Makefile Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/Makefile Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,25 @@ ++# ++# Makefile for the Linux OSPM code. ++# ++ ++O_TARGET := $(shell basename `pwd`).o ++ ++EXTRA_CFLAGS += -I./include ++ ++EXTRA_CFLAGS += $(ACPI_CFLAGS) ++ ++subdir-$(CONFIG_ACPI_BUSMGR) += busmgr ++subdir-$(CONFIG_ACPI_EC) += ec ++subdir-$(CONFIG_ACPI_SYS) += system ++subdir-$(CONFIG_ACPI_CPU) += processor ++subdir-$(CONFIG_ACPI_CMBATT) += battery ++subdir-$(CONFIG_ACPI_AC) += ac_adapter ++subdir-$(CONFIG_ACPI_BUTTON) += button ++subdir-$(CONFIG_ACPI_THERMAL) += thermal ++ ++obj-y += $(patsubst %,%.o,$(subdir-y)) ++ ++include $(TOPDIR)/Rules.make ++ ++clean: ++ $(RM) *.o */*.o +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/ac_adapter/Makefile linux/drivers/acpi/ospm/ac_adapter/Makefile +--- /usr/src/linux/drivers/acpi/ospm/ac_adapter/Makefile Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/ac_adapter/Makefile Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,23 @@ ++# ++# Makefile for all Linux ACPI interpreter subdirectories ++# ++ ++O_TARGET := ../$(shell basename `pwd`).o ++ ++EXTRA_CFLAGS += -I../../include -I../include ++ ++EXTRA_CFLAGS += $(ACPI_CFLAGS) ++ ++list-multi := ac_adapter.o ++ac_adapter-objs := $(patsubst %.c,%.o,$(wildcard *.c)) ++ ++obj-$(CONFIG_ACPI_AC) := ac_adapter.o ++ ++include $(TOPDIR)/Rules.make ++ ++clean: ++ $(RM) *.o ++ ++ac_adapter.o: $(ac_adapter-objs) ++ $(LD) -r -o $@ $(ac_adapter-objs) ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/ac_adapter/ac.c linux/drivers/acpi/ospm/ac_adapter/ac.c +--- /usr/src/linux/drivers/acpi/ospm/ac_adapter/ac.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/ac_adapter/ac.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,348 @@ ++/***************************************************************************** ++ * ++ * Module Name: ac.c ++ * $Revision: 16 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <acpi.h> ++#include "ac.h" ++ ++ ++#define _COMPONENT ACPI_AC_ADAPTER ++ MODULE_NAME ("ac") ++ ++ ++/**************************************************************************** ++ * Internal Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ac_print ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: Prints out information on a specific ac_adapter. ++ * ++ ****************************************************************************/ ++ ++void ++ac_print ( ++ AC_CONTEXT *ac_adapter) ++{ ++ ++ return; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ac_add_device ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ac_add_device( ++ BM_HANDLE device_handle, ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE *device = NULL; ++ AC_CONTEXT *ac_adapter = NULL; ++ ACPI_DEVICE_INFO info; ++ ++ if (!context || *context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Get information on this device. ++ */ ++ status = bm_get_device_info(device_handle, &device); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ /* ++ * Allocate a new AC_CONTEXT structure. ++ */ ++ ac_adapter = acpi_os_callocate(sizeof(AC_CONTEXT)); ++ if (!ac_adapter) { ++ return(AE_NO_MEMORY); ++ } ++ ++ ac_adapter->device_handle = device->handle; ++ ac_adapter->acpi_handle = device->acpi_handle; ++ ++ /* ++ * Get information on this object. ++ */ ++ status = acpi_get_object_info(ac_adapter->acpi_handle, &info); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ /* ++ * _UID? ++ * ----- ++ */ ++ if (info.valid & ACPI_VALID_UID) { ++ strncpy(ac_adapter->uid, info.unique_id, sizeof(info.unique_id)); ++ } ++ else { ++ strncpy(ac_adapter->uid, "0", sizeof("0")); ++ } ++ ++ /* ++ * _STA? ++ * ----- ++ */ ++ if (!(info.valid & ACPI_VALID_STA)) { ++ status = AE_ERROR; ++ goto end; ++ } ++ ++ status = ac_osl_add_device(ac_adapter); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ *context = ac_adapter; ++ ++ ac_print(ac_adapter); ++ ++end: ++ if (ACPI_FAILURE(status)) { ++ acpi_os_free(ac_adapter); ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ac_remove_device ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ac_remove_device ( ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ AC_CONTEXT *ac_adapter = NULL; ++ ++ if (!context || !*context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ ac_adapter = (AC_CONTEXT*)*context; ++ ++ ac_osl_remove_device(ac_adapter); ++ ++ acpi_os_free(ac_adapter); ++ ++ *context = NULL; ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * External Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ac_initialize ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ac_initialize (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE_ID criteria; ++ BM_DRIVER driver; ++ ++ MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); ++ MEMSET(&driver, 0, sizeof(BM_DRIVER)); ++ ++ driver.notify = &ac_notify; ++ driver.request = &ac_request; ++ ++ /* ++ * Register driver for AC Adapter devices. ++ */ ++ MEMCPY(criteria.hid, AC_HID_AC_ADAPTER, sizeof(AC_HID_AC_ADAPTER)); ++ ++ status = bm_register_driver(&criteria, &driver); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ac_terminate ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ac_terminate (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE_ID criteria; ++ BM_DRIVER driver; ++ ++ MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); ++ MEMSET(&driver, 0, sizeof(BM_DRIVER)); ++ ++ /* ++ * Unregister driver for AC Adapter devices. ++ */ ++ MEMCPY(criteria.hid, AC_HID_AC_ADAPTER, sizeof(AC_HID_AC_ADAPTER)); ++ ++ driver.notify = &ac_notify; ++ driver.request = &ac_request; ++ ++ status = bm_unregister_driver(&criteria, &driver); ++ ++ return(status); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: ac_notify ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ACPI_STATUS ++ac_notify ( ++ BM_NOTIFY notify_type, ++ BM_HANDLE device_handle, ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ switch (notify_type) { ++ ++ case BM_NOTIFY_DEVICE_ADDED: ++ status = ac_add_device(device_handle, context); ++ break; ++ ++ case BM_NOTIFY_DEVICE_REMOVED: ++ status = ac_remove_device(context); ++ break; ++ ++ case AC_NOTIFY_STATUS_CHANGE: ++ status = ac_osl_generate_event(notify_type, ++ ((AC_CONTEXT*)*context)); ++ break; ++ ++ default: ++ status = AE_SUPPORT; ++ break; ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ac_request ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ac_request ( ++ BM_REQUEST *request, ++ void *context) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ /* ++ * Must have a valid request structure and context. ++ */ ++ if (!request || !context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Handle Request: ++ * --------------- ++ */ ++ switch (request->command) { ++ ++ default: ++ status = AE_SUPPORT; ++ break; ++ } ++ ++ request->status = status; ++ ++ return(status); ++} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/ac_adapter/ac_osl.c linux/drivers/acpi/ospm/ac_adapter/ac_osl.c +--- /usr/src/linux/drivers/acpi/ospm/ac_adapter/ac_osl.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/ac_adapter/ac_osl.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,256 @@ ++/***************************************************************************** ++ * ++ * Module Name: ac_osl.c ++ * $Revision: 7 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/types.h> ++#include <linux/proc_fs.h> ++#include <acpi.h> ++#include "ac.h" ++ ++ ++MODULE_AUTHOR("Andrew Grover"); ++MODULE_DESCRIPTION("ACPI Component Architecture (CA) - AC Adapter Driver"); ++ ++ ++#define AC_PROC_ROOT "ac_adapter" ++#define AC_PROC_STATUS "status" ++#define AC_ON_LINE "on-line" ++#define AC_OFF_LINE "off-line" ++ ++extern struct proc_dir_entry *bm_proc_root; ++static struct proc_dir_entry *ac_proc_root = NULL; ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ac_osl_proc_read_status ++ * ++ ****************************************************************************/ ++ ++static int ++ac_osl_proc_read_status ( ++ char *page, ++ char **start, ++ off_t off, ++ int count, ++ int *eof, ++ void *context) ++{ ++ ACPI_STATUS status = AE_OK; ++ AC_CONTEXT *ac_adapter = NULL; ++ char *p = page; ++ int len; ++ ++ if (!context) { ++ goto end; ++ } ++ ++ ac_adapter = (AC_CONTEXT*)context; ++ ++ /* don't get status more than once for a single proc read */ ++ if (off != 0) { ++ goto end; ++ } ++ ++ status = bm_evaluate_simple_integer(ac_adapter->acpi_handle, ++ "_PSR", &(ac_adapter->is_online)); ++ if (ACPI_FAILURE(status)) { ++ p += sprintf(p, "Error reading AC Adapter status\n"); ++ goto end; ++ } ++ ++ if (ac_adapter->is_online) { ++ p += sprintf(p, "Status: %s\n", ++ AC_ON_LINE); ++ } ++ else { ++ p += sprintf(p, "Status: %s\n", ++ AC_OFF_LINE); ++ } ++ ++end: ++ len = (p - page); ++ if (len <= off+count) *eof = 1; ++ *start = page + off; ++ len -= off; ++ if (len>count) len = count; ++ if (len<0) len = 0; ++ ++ return(len); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ac_osl_add_device ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ac_osl_add_device( ++ AC_CONTEXT *ac_adapter) ++{ ++ struct proc_dir_entry *proc_entry = NULL; ++ ++ if (!ac_adapter) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ printk(KERN_INFO "AC Adapter: found\n"); ++ ++ proc_entry = proc_mkdir(ac_adapter->uid, ac_proc_root); ++ if (!proc_entry) { ++ return(AE_ERROR); ++ } ++ ++ create_proc_read_entry(AC_PROC_STATUS, S_IFREG | S_IRUGO, ++ proc_entry, ac_osl_proc_read_status, (void*)ac_adapter); ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ac_osl_remove_device ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ac_osl_remove_device ( ++ AC_CONTEXT *ac_adapter) ++{ ++ char proc_entry[64]; ++ ++ if (!ac_adapter) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ sprintf(proc_entry, "%s/%s", ac_adapter->uid, AC_PROC_STATUS); ++ remove_proc_entry(proc_entry, ac_proc_root); ++ ++ sprintf(proc_entry, "%s", ac_adapter->uid); ++ remove_proc_entry(proc_entry, ac_proc_root); ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ac_osl_generate_event ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ac_osl_generate_event ( ++ u32 event, ++ AC_CONTEXT *ac_adapter) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!ac_adapter) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ switch (event) { ++ ++ case AC_NOTIFY_STATUS_CHANGE: ++ status = bm_osl_generate_event(ac_adapter->device_handle, ++ AC_PROC_ROOT, ac_adapter->uid, event, 0); ++ break; ++ ++ default: ++ return(AE_BAD_PARAMETER); ++ break; ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ac_osl_init ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: 0: Success ++ * ++ * DESCRIPTION: Module initialization. ++ * ++ ****************************************************************************/ ++ ++static int __init ++ac_osl_init (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ ac_proc_root = proc_mkdir(AC_PROC_ROOT, bm_proc_root); ++ if (!ac_proc_root) { ++ status = AE_ERROR; ++ } ++ else { ++ status = ac_initialize(); ++ if (ACPI_FAILURE(status)) { ++ remove_proc_entry(AC_PROC_ROOT, bm_proc_root); ++ } ++ ++ } ++ ++ return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ac_osl_cleanup ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <none> ++ * ++ * DESCRIPTION: Module cleanup. ++ * ++ ****************************************************************************/ ++ ++static void __exit ++ac_osl_cleanup (void) ++{ ++ ac_terminate(); ++ ++ if (ac_proc_root) { ++ remove_proc_entry(AC_PROC_ROOT, bm_proc_root); ++ } ++ ++ return; ++} ++ ++ ++module_init(ac_osl_init); ++module_exit(ac_osl_cleanup); +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/battery/Makefile linux/drivers/acpi/ospm/battery/Makefile +--- /usr/src/linux/drivers/acpi/ospm/battery/Makefile Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/battery/Makefile Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,23 @@ ++# ++# Makefile for all Linux ACPI interpreter subdirectories ++# ++ ++O_TARGET := ../$(shell basename `pwd`).o ++ ++EXTRA_CFLAGS += -I../../include -I../include ++ ++EXTRA_CFLAGS += $(ACPI_CFLAGS) ++ ++list-multi := battery.o ++battery-objs := $(patsubst %.c,%.o,$(wildcard *.c)) ++ ++obj-$(CONFIG_ACPI_CMBATT) := battery.o ++ ++include $(TOPDIR)/Rules.make ++ ++clean: ++ $(RM) *.o ++ ++battery.o: $(battery-objs) ++ $(LD) -r -o $@ $(battery-objs) ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/battery/bt.c linux/drivers/acpi/ospm/battery/bt.c +--- /usr/src/linux/drivers/acpi/ospm/battery/bt.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/battery/bt.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,593 @@ ++/***************************************************************************** ++ * ++ * Module Name: bt.c ++ * $Revision: 19 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <acpi.h> ++#include "bt.h" ++ ++ ++#define _COMPONENT ACPI_BATTERY ++ MODULE_NAME ("bt") ++ ++ ++/**************************************************************************** ++ * Internal Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bt_print ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: Prints out information on a specific battery. ++ * ++ ****************************************************************************/ ++ ++void ++bt_print ( ++ BT_CONTEXT *battery) ++{ ++ ++ return; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bt_get_info ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ * NOTES: Allocates battery_info - which must be freed by the caller. ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bt_get_info ( ++ BT_CONTEXT *battery, ++ BT_BATTERY_INFO **battery_info) ++{ ++ ACPI_STATUS status = AE_OK; ++ ACPI_BUFFER bif_buffer, package_format, package_data; ++ ACPI_OBJECT *package = NULL; ++ ++ if (!battery || !battery_info || *battery_info) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ MEMSET(&bif_buffer, 0, sizeof(ACPI_BUFFER)); ++ ++ /* ++ * Evalute _BIF: ++ * ------------- ++ * And be sure to deallocate bif_buffer.pointer! ++ */ ++ status = bm_evaluate_object(battery->acpi_handle, "_BIF", NULL, ++ &bif_buffer); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ /* ++ * Extract Package Data: ++ * --------------------- ++ * Type-cast this bif_buffer to a package and use helper ++ * functions to convert results into BT_BATTERY_INFO structure. ++ * The first attempt is just to get the size of the package ++ * data; the second gets the data (once we know the required ++ * bif_buffer size). ++ */ ++ status = bm_cast_buffer(&bif_buffer, (void**)&package, ++ sizeof(ACPI_OBJECT)); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ package_format.length = sizeof("NNNNNNNNNSSSS"); ++ package_format.pointer = "NNNNNNNNNSSSS"; ++ ++ MEMSET(&package_data, 0, sizeof(ACPI_BUFFER)); ++ ++ status = bm_extract_package_data(package, &package_format, ++ &package_data); ++ if (status != AE_BUFFER_OVERFLOW) { ++ if (status == AE_OK) { ++ status = AE_ERROR; ++ } ++ goto end; ++ } ++ ++ package_data.pointer = acpi_os_callocate(package_data.length); ++ if (!package_data.pointer) { ++ return(AE_NO_MEMORY); ++ } ++ ++ status = bm_extract_package_data(package, &package_format, ++ &package_data); ++ if (ACPI_FAILURE(status)) { ++ acpi_os_free(package_data.pointer); ++ goto end; ++ } ++ ++ *battery_info = package_data.pointer; ++ ++end: ++ acpi_os_free(bif_buffer.pointer); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bt_get_status ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bt_get_status ( ++ BT_CONTEXT *battery, ++ BT_BATTERY_STATUS **battery_status) ++{ ++ ACPI_STATUS status = AE_OK; ++ ACPI_BUFFER bst_buffer, package_format, package_data; ++ ACPI_OBJECT *package = NULL; ++ ++ if (!battery || !battery_status || *battery_status) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ MEMSET(&bst_buffer, 0, sizeof(ACPI_BUFFER)); ++ ++ /* ++ * Evalute _BST: ++ * ------------- ++ * And be sure to deallocate bst_buffer.pointer! ++ */ ++ status = bm_evaluate_object(battery->acpi_handle, "_BST", ++ NULL, &bst_buffer); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ /* ++ * Extract Package Data: ++ * --------------------- ++ * Type-cast this bst_buffer to a package and use helper ++ * functions to convert results into BT_BATTERY_STATUS structure. ++ * The first attempt is just to get the size of the package data; ++ * the second gets the data (once we know the required bst_buffer ++ * size). ++ */ ++ status = bm_cast_buffer(&bst_buffer, (void**)&package, ++ sizeof(ACPI_OBJECT)); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ package_format.length = sizeof("NNNN"); ++ package_format.pointer = "NNNN"; ++ ++ MEMSET(&package_data, 0, sizeof(ACPI_BUFFER)); ++ ++ status = bm_extract_package_data(package, &package_format, ++ &package_data); ++ if (status != AE_BUFFER_OVERFLOW) { ++ if (status == AE_OK) { ++ status = AE_ERROR; ++ } ++ goto end; ++ } ++ ++ package_data.pointer = acpi_os_callocate(package_data.length); ++ if (!package_data.pointer) { ++ return(AE_NO_MEMORY); ++ } ++ ++ status = bm_extract_package_data(package, &package_format, ++ &package_data); ++ if (ACPI_FAILURE(status)) { ++ acpi_os_free(package_data.pointer); ++ goto end; ++ } ++ ++ *battery_status = package_data.pointer; ++ ++end: ++ acpi_os_free(bst_buffer.pointer); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bt_check_device ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bt_check_device ( ++ BT_CONTEXT *battery) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE_STATUS battery_status = BM_STATUS_UNKNOWN; ++ u32 was_present = FALSE; ++ BT_BATTERY_INFO *battery_info = NULL; ++ ++ if (!battery) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ was_present = battery->is_present; ++ ++ /* ++ * Battery Present? ++ * ---------------- ++ * Get the device status and check if battery slot is occupied. ++ */ ++ status = bm_get_device_status(battery->device_handle, &battery_status); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ if (battery_status & BM_STATUS_BATTERY_PRESENT) { ++ battery->is_present = TRUE; ++ } ++ else { ++ battery->is_present = FALSE; ++ } ++ ++ /* ++ * Battery Appeared? ++ * ----------------- ++ */ ++ if (!was_present && battery->is_present) { ++ ++ /* ++ * Units of Power? ++ * --------------- ++ * Get the 'units of power', as we'll need this to report ++ * status information. ++ */ ++ status = bt_get_info(battery, &battery_info); ++ if (ACPI_SUCCESS(status)) { ++ battery->power_units = (battery_info->power_unit) ++ ? "m_a":"m_w"; ++ acpi_os_free(battery_info); ++ } ++ } ++ ++ /* ++ * Battery Disappeared? ++ * -------------------- ++ */ ++ else if (was_present && !battery->is_present) { ++ battery->power_units = BT_POWER_UNITS_DEFAULT; ++ } ++ ++ return(status); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: bt_add_device ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bt_add_device ( ++ BM_HANDLE device_handle, ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE *device = NULL; ++ BT_CONTEXT *battery = NULL; ++ ++ if (!context || *context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Get information on this device. ++ */ ++ status = bm_get_device_info(device_handle, &device); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ /* ++ * Allocate a new BT_CONTEXT structure. ++ */ ++ battery = acpi_os_callocate(sizeof(BT_CONTEXT)); ++ if (!battery) { ++ return(AE_NO_MEMORY); ++ } ++ ++ battery->device_handle = device->handle; ++ battery->acpi_handle = device->acpi_handle; ++ strncpy(battery->uid, device->id.uid, sizeof(battery->uid)); ++ ++ battery->power_units = BT_POWER_UNITS_DEFAULT; ++ battery->is_present = FALSE; ++ ++ /* ++ * See if battery is really present. ++ */ ++ status = bt_check_device(battery); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ status = bt_osl_add_device(battery); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ *context = battery; ++ ++ bt_print(battery); ++ ++end: ++ if (ACPI_FAILURE(status)) { ++ acpi_os_free(battery); ++ } ++ ++ return(status); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: bt_remove_device ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bt_remove_device ( ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ BT_CONTEXT *battery = NULL; ++ ++ if (!context || !*context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ battery = (BT_CONTEXT*)*context; ++ ++ bt_osl_remove_device(battery); ++ ++ acpi_os_free(battery); ++ ++ *context = NULL; ++ ++ return(status); ++} ++ ++ ++/***************************************************************************** ++ * External Functions ++ *****************************************************************************/ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: bt_initialize ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bt_initialize (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE_ID criteria; ++ BM_DRIVER driver; ++ ++ MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); ++ MEMSET(&driver, 0, sizeof(BM_DRIVER)); ++ ++ /* ++ * Register driver for driver method battery devices. ++ */ ++ MEMCPY(criteria.hid, BT_HID_CM_BATTERY, sizeof(BT_HID_CM_BATTERY)); ++ ++ driver.notify = &bt_notify; ++ driver.request = &bt_request; ++ ++ status = bm_register_driver(&criteria, &driver); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bt_terminate ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bt_terminate (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE_ID criteria; ++ BM_DRIVER driver; ++ ++ MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); ++ MEMSET(&driver, 0, sizeof(BM_DRIVER)); ++ ++ /* ++ * Unregister driver for driver method battery devices. ++ */ ++ MEMCPY(criteria.hid, BT_HID_CM_BATTERY, sizeof(BT_HID_CM_BATTERY)); ++ ++ driver.notify = &bt_notify; ++ driver.request = &bt_request; ++ ++ status = bm_unregister_driver(&criteria, &driver); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bt_notify ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bt_notify ( ++ BM_NOTIFY notify_type, ++ BM_HANDLE device_handle, ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ switch (notify_type) { ++ ++ case BM_NOTIFY_DEVICE_ADDED: ++ status = bt_add_device(device_handle, context); ++ break; ++ ++ case BM_NOTIFY_DEVICE_REMOVED: ++ status = bt_remove_device(context); ++ break; ++ ++ case BT_NOTIFY_STATUS_CHANGE: ++ status = bt_osl_generate_event(notify_type, ++ ((BT_CONTEXT*)*context)); ++ break; ++ ++ case BT_NOTIFY_INFORMATION_CHANGE: ++ status = bt_check_device((BT_CONTEXT*)*context); ++ if (ACPI_SUCCESS(status)) { ++ status = bt_osl_generate_event(notify_type, ++ ((BT_CONTEXT*)*context)); ++ } ++ break; ++ ++ default: ++ status = AE_SUPPORT; ++ break; ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bt_request ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bt_request ( ++ BM_REQUEST *request, ++ void *context) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ /* ++ * Must have a valid request structure and context. ++ */ ++ if (!request || !context) ++ return(AE_BAD_PARAMETER); ++ ++ /* ++ * Handle request: ++ * --------------- ++ */ ++ switch (request->command) { ++ ++ default: ++ status = AE_SUPPORT; ++ break; ++ } ++ ++ request->status = status; ++ ++ return(status); ++} +\ No newline at end of file +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/battery/bt_osl.c linux/drivers/acpi/ospm/battery/bt_osl.c +--- /usr/src/linux/drivers/acpi/ospm/battery/bt_osl.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/battery/bt_osl.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,443 @@ ++/****************************************************************************** ++ * ++ * Module Name: bt_osl.c ++ * $Revision: 16 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * 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 ++ */ ++ ++/* ++ * Changes: ++ * Brendan Burns <bburns@wso.williams.edu> 2000-11-15 ++ * - added proc battery interface ++ * - parse returned data from _BST and _BIF ++ * Andy Grover <andrew.grover@intel.com> 2000-12-8 ++ * - improved proc interface ++ */ ++ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/types.h> ++#include <linux/proc_fs.h> ++#include <acpi.h> ++#include "bt.h" ++ ++ ++MODULE_AUTHOR("Andrew Grover"); ++MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Control Method Battery Driver"); ++ ++ ++#define BT_PROC_ROOT "battery" ++#define BT_PROC_STATUS "status" ++#define BT_PROC_INFO "info" ++ ++extern struct proc_dir_entry *bm_proc_root; ++static struct proc_dir_entry *bt_proc_root = NULL; ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bt_osl_proc_read_info ++ * ++ ****************************************************************************/ ++ ++static int ++bt_osl_proc_read_info ( ++ char *page, ++ char **start, ++ off_t off, ++ int count, ++ int *eof, ++ void *context) ++{ ++ BT_CONTEXT *battery = NULL; ++ BT_BATTERY_INFO *battery_info = NULL; ++ char *p = page; ++ int len = 0; ++ ++ if (!context || (off != 0)) { ++ goto end; ++ } ++ ++ battery = (BT_CONTEXT*)context; ++ ++ /* ++ * Battery Present? ++ * ---------------- ++ */ ++ if (!battery->is_present) { ++ p += sprintf(p, "Present: no\n"); ++ goto end; ++ } ++ else { ++ p += sprintf(p, "Present: yes\n"); ++ } ++ ++ /* ++ * Get Battery Information: ++ * ------------------------ ++ */ ++ if (ACPI_FAILURE(bt_get_info(battery, &battery_info))) { ++ p += sprintf(p, "Error reading battery information (_BIF)\n"); ++ goto end; ++ } ++ ++ if (battery_info->design_capacity == BT_UNKNOWN) { ++ p += sprintf(p, "Design Capacity: unknown\n"); ++ } ++ else { ++ p += sprintf(p, "Design Capacity: %d %sh\n", ++ battery_info->design_capacity, ++ battery->power_units); ++ } ++ ++ if (battery_info->last_full_capacity == BT_UNKNOWN) { ++ p += sprintf(p, "Last Full Capacity: unknown\n"); ++ } ++ else { ++ p += sprintf(p, "Last Full Capacity: %d %sh\n", ++ battery_info->last_full_capacity, ++ battery->power_units); ++ } ++ ++ if (battery_info->battery_technology == 0) { ++ p += sprintf(p, "Battery Technology: primary (non-rechargeable)\n"); ++ } ++ else if (battery_info->battery_technology == 1) { ++ p += sprintf(p, "Battery Technology: secondary (rechargeable)\n"); ++ } ++ else { ++ p += sprintf(p, "Battery Technology: unknown\n"); ++ } ++ ++ if (battery_info->design_voltage == BT_UNKNOWN) { ++ p += sprintf(p, "Design Voltage: unknown\n"); ++ } ++ else { ++ p += sprintf(p, "Design Voltage: %d mV\n", ++ battery_info->design_voltage); ++ } ++ ++ p += sprintf(p, "Design Capacity Warning: %d %sh\n", ++ battery_info->design_capacity_warning, ++ battery->power_units); ++ p += sprintf(p, "Design Capacity Low: %d %sh\n", ++ battery_info->design_capacity_low, ++ battery->power_units); ++ p += sprintf(p, "Capacity Granularity 1: %d %sh\n", ++ battery_info->battery_capacity_granularity_1, ++ battery->power_units); ++ p += sprintf(p, "Capacity Granularity 2: %d %sh\n", ++ battery_info->battery_capacity_granularity_2, ++ battery->power_units); ++ p += sprintf(p, "Model Number: %s\n", ++ battery_info->model_number); ++ p += sprintf(p, "Serial Number: %s\n", ++ battery_info->serial_number); ++ p += sprintf(p, "Battery Type: %s\n", ++ battery_info->battery_type); ++ p += sprintf(p, "OEM Info: %s\n", ++ battery_info->oem_info); ++ ++end: ++ len = (p - page); ++ if (len <= off+count) *eof = 1; ++ *start = page + off; ++ len -= off; ++ if (len>count) len = count; ++ if (len<0) len = 0; ++ ++ acpi_os_free(battery_info); ++ ++ return(len); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bt_osl_proc_read_status ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++static int ++bt_osl_proc_read_status ( ++ char *page, ++ char **start, ++ off_t off, ++ int count, ++ int *eof, ++ void *context) ++{ ++ BT_CONTEXT *battery = NULL; ++ BT_BATTERY_STATUS *battery_status = NULL; ++ char *p = page; ++ int len = 0; ++ ++ if (!context || (off != 0)) { ++ goto end; ++ } ++ ++ battery = (BT_CONTEXT*)context; ++ ++ /* ++ * Battery Present? ++ * ---------------- ++ */ ++ if (!battery->is_present) { ++ p += sprintf(p, "Present: no\n"); ++ goto end; ++ } ++ else { ++ p += sprintf(p, "Present: yes\n"); ++ } ++ ++ /* ++ * Get Battery Status: ++ * ------------------- ++ */ ++ if (ACPI_FAILURE(bt_get_status(battery, &battery_status))) { ++ p += sprintf(p, "Error reading battery status (_BST)\n"); ++ goto end; ++ } ++ ++ /* ++ * Store Data: ++ * ----------- ++ */ ++ ++ if (!battery_status->state) { ++ p += sprintf(p, "State: ok\n"); ++ } ++ else { ++ if (battery_status->state & 0x1) ++ p += sprintf(p, "State: discharging\n"); ++ if (battery_status->state & 0x2) ++ p += sprintf(p, "State: charging\n"); ++ if (battery_status->state & 0x4) ++ p += sprintf(p, "State: critically low\n"); ++ } ++ ++ if (battery_status->present_rate == BT_UNKNOWN) { ++ p += sprintf(p, "Present Rate: unknown\n"); ++ } ++ else { ++ p += sprintf(p, "Present Rate: %d %s\n", ++ battery_status->present_rate, ++ battery->power_units); ++ } ++ ++ if (battery_status->remaining_capacity == BT_UNKNOWN) { ++ p += sprintf(p, "Remaining Capacity: unknown\n"); ++ } ++ else { ++ p += sprintf(p, "Remaining Capacity: %d %sh\n", ++ battery_status->remaining_capacity, ++ battery->power_units); ++ } ++ ++ if (battery_status->present_voltage == BT_UNKNOWN) { ++ p += sprintf(p, "Battery Voltage: unknown\n"); ++ } ++ else { ++ p += sprintf(p, "Battery Voltage: %d mV\n", ++ battery_status->present_voltage); ++ } ++ ++end: ++ len = (p - page); ++ if (len <= off+count) *eof = 1; ++ *start = page + off; ++ len -= off; ++ if (len>count) len = count; ++ if (len<0) len = 0; ++ ++ acpi_os_free(battery_status); ++ ++ return(len); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bt_osl_add_device ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bt_osl_add_device( ++ BT_CONTEXT *battery) ++{ ++ struct proc_dir_entry *proc_entry = NULL; ++ ++ if (!battery) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ if (battery->is_present) { ++ printk("Battery: socket found, battery present\n"); ++ } ++ else { ++ printk("Battery: socket found, battery absent\n"); ++ } ++ ++ proc_entry = proc_mkdir(battery->uid, bt_proc_root); ++ if (!proc_entry) { ++ return(AE_ERROR); ++ } ++ ++ create_proc_read_entry(BT_PROC_STATUS, S_IFREG | S_IRUGO, ++ proc_entry, bt_osl_proc_read_status, (void*)battery); ++ ++ create_proc_read_entry(BT_PROC_INFO, S_IFREG | S_IRUGO, ++ proc_entry, bt_osl_proc_read_info, (void*)battery); ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bt_osl_remove_device ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bt_osl_remove_device ( ++ BT_CONTEXT *battery) ++{ ++ char proc_entry[64]; ++ ++ if (!battery) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ sprintf(proc_entry, "%s/%s", battery->uid, BT_PROC_INFO); ++ remove_proc_entry(proc_entry, bt_proc_root); ++ ++ sprintf(proc_entry, "%s/%s", battery->uid, BT_PROC_STATUS); ++ remove_proc_entry(proc_entry, bt_proc_root); ++ ++ sprintf(proc_entry, "%s", battery->uid); ++ remove_proc_entry(proc_entry, bt_proc_root); ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bt_osl_generate_event ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bt_osl_generate_event ( ++ u32 event, ++ BT_CONTEXT *battery) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!battery) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ switch (event) { ++ ++ case BT_NOTIFY_STATUS_CHANGE: ++ status = bm_osl_generate_event(battery->device_handle, ++ BT_PROC_ROOT, battery->uid, event, 0); ++ break; ++ ++ default: ++ return(AE_BAD_PARAMETER); ++ break; ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bt_osl_init ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: 0: Success ++ * ++ * DESCRIPTION: Module initialization. ++ * ++ ****************************************************************************/ ++ ++static int __init ++bt_osl_init (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ bt_proc_root = proc_mkdir(BT_PROC_ROOT, bm_proc_root); ++ if (!bt_proc_root) { ++ status = AE_ERROR; ++ } ++ else { ++ status = bt_initialize(); ++ if (ACPI_FAILURE(status)) { ++ remove_proc_entry(BT_PROC_ROOT, bm_proc_root); ++ } ++ } ++ ++ return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bt_osl_cleanup ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <none> ++ * ++ * DESCRIPTION: Module cleanup. ++ * ++ ****************************************************************************/ ++ ++static void __exit ++bt_osl_cleanup (void) ++{ ++ bt_terminate(); ++ ++ if (bt_proc_root) { ++ remove_proc_entry(BT_PROC_ROOT, bm_proc_root); ++ } ++ ++ return; ++} ++ ++ ++module_init(bt_osl_init); ++module_exit(bt_osl_cleanup); +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/busmgr/Makefile linux/drivers/acpi/ospm/busmgr/Makefile +--- /usr/src/linux/drivers/acpi/ospm/busmgr/Makefile Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/busmgr/Makefile Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,23 @@ ++# ++# Makefile for all Linux ACPI interpreter subdirectories ++# ++ ++O_TARGET := ../$(shell basename `pwd`).o ++ ++EXTRA_CFLAGS += -I../../include -I../include ++ ++EXTRA_CFLAGS += $(ACPI_CFLAGS) ++ ++list-multi := busmgr.o ++busmgr-objs := $(patsubst %.c,%.o,$(wildcard *.c)) ++ ++obj-$(CONFIG_ACPI_BUSMGR) := busmgr.o ++ ++include $(TOPDIR)/Rules.make ++ ++clean: ++ $(RM) *.o ++ ++busmgr.o: $(busmgr-objs) ++ $(LD) -r -o $@ $(busmgr-objs) ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/busmgr/bm.c linux/drivers/acpi/ospm/busmgr/bm.c +--- /usr/src/linux/drivers/acpi/ospm/busmgr/bm.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/busmgr/bm.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,1136 @@ ++/****************************************************************************** ++ * ++ * Module Name: bm.c ++ * $Revision: 36 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <acpi.h> ++#include "bm.h" ++ ++ ++#define _COMPONENT ACPI_BUS_MANAGER ++ MODULE_NAME ("bm") ++ ++ ++/**************************************************************************** ++ * Globals ++ ****************************************************************************/ ++ ++extern FADT_DESCRIPTOR_REV2 acpi_fadt; ++/* TODO: Make dynamically sizeable. */ ++BM_NODE_LIST node_list; ++ ++ ++/**************************************************************************** ++ * Internal Functions ++ ****************************************************************************/ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: bm_print_object ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++void ++bm_print_object ( ++ ACPI_HANDLE acpi_handle) ++{ ++ ACPI_BUFFER buffer; ++ ACPI_HANDLE parent; ++ ACPI_OBJECT_TYPE type; ++ ++ buffer.length = 256; ++ buffer.pointer = acpi_os_callocate(buffer.length); ++ if (!buffer.pointer) { ++ return; ++ } ++ ++ acpi_get_name(acpi_handle, ACPI_FULL_PATHNAME, &buffer); ++ acpi_get_parent(acpi_handle, &parent); ++ acpi_get_type(acpi_handle, &type); ++ ++ /* ++ * TODO: Hack to get around scope identification problem. ++ */ ++ if (type == ACPI_TYPE_ANY) { ++ if (ACPI_SUCCESS(acpi_get_next_object(ACPI_TYPE_ANY, ++ acpi_handle, 0, NULL))) { ++ type = INTERNAL_TYPE_SCOPE; ++ } ++ } ++ ++ switch (type) ++ { ++ case INTERNAL_TYPE_SCOPE: ++ acpi_os_printf("SCOPE: "); ++ break; ++ case ACPI_TYPE_INTEGER: ++ acpi_os_printf("SIMPLE (number): "); ++ break; ++ case ACPI_TYPE_STRING: ++ acpi_os_printf("SIMPLE (string): "); ++ break; ++ case ACPI_TYPE_BUFFER: ++ acpi_os_printf("SIMPLE (buffer): "); ++ break; ++ case ACPI_TYPE_PACKAGE: ++ acpi_os_printf("SIMPLE (package): "); ++ break; ++ case ACPI_TYPE_FIELD_UNIT: ++ acpi_os_printf("FIELD UNIT: "); ++ break; ++ case ACPI_TYPE_DEVICE: ++ acpi_os_printf("DEVICE: "); ++ break; ++ case ACPI_TYPE_EVENT: ++ acpi_os_printf("EVENT: "); ++ break; ++ case ACPI_TYPE_METHOD: ++ acpi_os_printf("CONTROL METHOD: "); ++ break; ++ case ACPI_TYPE_MUTEX: ++ acpi_os_printf("MUTEX: "); ++ break; ++ case ACPI_TYPE_REGION: ++ acpi_os_printf("OPERATION REGION: "); ++ break; ++ case ACPI_TYPE_POWER: ++ acpi_os_printf("POWER RESOURCE: "); ++ break; ++ case ACPI_TYPE_PROCESSOR: ++ acpi_os_printf("PROCESSOR: "); ++ break; ++ case ACPI_TYPE_THERMAL: ++ acpi_os_printf("THERMAL ZONE: "); ++ break; ++ case ACPI_TYPE_BUFFER_FIELD: ++ acpi_os_printf("BUFFER FIELD: "); ++ break; ++ case ACPI_TYPE_DDB_HANDLE: ++ acpi_os_printf("DDB HANDLE: "); ++ break; ++ default: ++ acpi_os_printf("OTHER (%d): ", type); ++ break; ++ } ++ ++ acpi_os_printf("Object[%p][%s] parent[%p].\n", acpi_handle, (char*)buffer.pointer, parent); ++ ++ acpi_os_free(buffer.pointer); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_print_node ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++void ++bm_print_node ( ++ BM_NODE *node, ++ u32 flags) ++{ ++#ifdef ACPI_DEBUG ++ ACPI_BUFFER buffer; ++ BM_DEVICE *device = NULL; ++ char *type_string = NULL; ++ ++ if (!node) { ++ return; ++ } ++ ++ device = &(node->device); ++ ++ if (flags & BM_PRINT_PRESENT) { ++ if (!BM_DEVICE_PRESENT(device)) { ++ return; ++ } ++ } ++ ++ buffer.length = 256; ++ buffer.pointer = acpi_os_callocate(buffer.length); ++ if (!buffer.pointer) { ++ return; ++ } ++ ++ acpi_get_name(device->acpi_handle, ACPI_FULL_PATHNAME, &buffer); ++ ++ switch(device->id.type) { ++ case BM_TYPE_SYSTEM: ++ type_string = " System"; ++ break; ++ case BM_TYPE_SCOPE: ++ type_string = " Scope"; ++ break; ++ case BM_TYPE_PROCESSOR: ++ type_string = " Proc"; ++ break; ++ case BM_TYPE_THERMAL_ZONE: ++ type_string = "Thermal"; ++ break; ++ case BM_TYPE_POWER_RESOURCE: ++ type_string = " Power"; ++ break; ++ case BM_TYPE_FIXED_BUTTON: ++ type_string = " Button"; ++ break; ++ case BM_TYPE_DEVICE: ++ type_string = " Device"; ++ break; ++ default: ++ type_string = "Unknown"; ++ break; ++ } ++ ++ if (!(flags & BM_PRINT_GROUP)) { ++ DEBUG_PRINT_RAW(ACPI_INFO, ("+-------------------------------------------------------------------------------\n")); ++ } ++ ++ DEBUG_PRINT_RAW(ACPI_INFO, ("| %s[%02x]:[%p] flags[%02x] hid[%s] %s\n", type_string, device->handle, device->acpi_handle, device->flags, (device->id.hid[0] ? device->id.hid : " "), buffer.pointer)); ++ ++ if (flags & BM_PRINT_IDENTIFICATION) { ++ DEBUG_PRINT_RAW(ACPI_INFO, ("| identification: uid[%s] adr[%08x]\n", device->id.uid, device->id.adr)); ++ } ++ ++ if (flags & BM_PRINT_LINKAGE) { ++ DEBUG_PRINT_RAW(ACPI_INFO, ("| linkage: this[%p] parent[%p] next[%p]\n", node, node->parent, node->next)); ++ DEBUG_PRINT_RAW(ACPI_INFO, ("| scope.head[%p] scope.tail[%p]\n", node->scope.head, node->scope.tail)); ++ } ++ ++ if (flags & BM_PRINT_POWER) { ++ DEBUG_PRINT_RAW(ACPI_INFO, ("| power: state[D%d] flags[%08x]\n", device->power.state, device->power.flags)); ++ DEBUG_PRINT_RAW(ACPI_INFO, ("| S0[%02x] S1[%02x] S2[%02x] S3[%02x] S4[%02x] S5[%02x]\n", device->power.dx_supported[0], device->power.dx_supported[1], device->power.dx_supported[2], device->power.dx_supported[3], device->power.dx_supported[4], device->power.dx_supported[5])); ++ } ++ ++ if (!(flags & BM_PRINT_GROUP)) { ++ DEBUG_PRINT_RAW(ACPI_INFO, ("+-------------------------------------------------------------------------------\n")); ++ } ++ ++ acpi_os_free(buffer.pointer); ++#endif /*ACPI_DEBUG*/ ++ ++ return; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_print_hierarchy ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++void ++bm_print_hierarchy (void) ++{ ++#ifdef ACPI_DEBUG ++ u32 i = 0; ++ ++ FUNCTION_TRACE("bm_print_hierarchy"); ++ ++ DEBUG_PRINT_RAW(ACPI_INFO, ("+------------------------------------------------------------\n")); ++ ++ for (i = 0; i < node_list.count; i++) { ++ bm_print_node(node_list.nodes[i], BM_PRINT_GROUP | BM_PRINT_PRESENT); ++ } ++ ++ DEBUG_PRINT_RAW(ACPI_INFO, ("+------------------------------------------------------------\n")); ++#endif /*ACPI_DEBUG*/ ++ ++ return_VOID; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_get_status ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_get_status ( ++ BM_DEVICE *device) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!device) { ++ return AE_BAD_PARAMETER; ++ } ++ ++ device->status = BM_STATUS_UNKNOWN; ++ ++ /* ++ * Dynamic Status? ++ * --------------- ++ * If _STA isn't present we just return the default status. ++ */ ++ if (!(device->flags & BM_FLAGS_DYNAMIC_STATUS)) { ++ device->status = BM_STATUS_DEFAULT; ++ return AE_OK; ++ } ++ ++ /* ++ * Evaluate _STA: ++ * -------------- ++ */ ++ status = bm_evaluate_simple_integer(device->acpi_handle, "_STA", ++ &(device->status)); ++ ++ return status; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_get_identification ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_get_identification ( ++ BM_DEVICE *device) ++{ ++ ACPI_STATUS status = AE_OK; ++ ACPI_DEVICE_INFO info; ++ ++ if (!device) { ++ return AE_BAD_PARAMETER; ++ } ++ ++ if (!(device->flags & BM_FLAGS_IDENTIFIABLE)) { ++ return AE_OK; ++ } ++ ++ device->id.uid[0] = BM_UID_UNKNOWN; ++ device->id.hid[0] = BM_HID_UNKNOWN; ++ device->id.adr = BM_ADDRESS_UNKNOWN; ++ ++ /* ++ * Get Object Info: ++ * ---------------- ++ * Evalute _UID, _HID, and _ADR... ++ */ ++ status = acpi_get_object_info(device->acpi_handle, &info); ++ if (ACPI_FAILURE(status)) { ++ return status; ++ } ++ ++ if (info.valid & ACPI_VALID_UID) { ++ MEMCPY((void*)device->id.uid, (void*)info.unique_id, ++ sizeof(BM_DEVICE_UID)); ++ } ++ ++ if (info.valid & ACPI_VALID_HID) { ++ MEMCPY((void*)device->id.hid, (void*)info.hardware_id, ++ sizeof(BM_DEVICE_HID)); ++ } ++ ++ if (info.valid & ACPI_VALID_ADR) { ++ device->id.adr = info.address; ++ } ++ ++ return status; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_get_flags ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_get_flags ( ++ BM_DEVICE *device) ++{ ++ ACPI_HANDLE acpi_handle = NULL; ++ ++ if (!device) { ++ return AE_BAD_PARAMETER; ++ } ++ ++ device->flags = BM_FLAGS_UNKNOWN; ++ ++ switch (device->id.type) { ++ ++ case BM_TYPE_DEVICE: ++ ++ /* ++ * Presence of _DCK indicates a docking station. ++ */ ++ if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, ++ "_DCK", &acpi_handle))) { ++ device->flags |= BM_FLAGS_DOCKING_STATION; ++ } ++ ++ /* ++ * Presence of _EJD and/or _EJx indicates 'ejectable'. ++ * TODO: _EJx... ++ */ ++ if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, ++ "_EJD", &acpi_handle))) { ++ device->flags |= BM_FLAGS_EJECTABLE; ++ } ++ ++ /* ++ * Presence of _PR0 or _PS0 indicates 'power manageable'. ++ */ ++ if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, ++ "_PR0", &acpi_handle)) || ++ ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, ++ "_PS0", &acpi_handle))) { ++ device->flags |= BM_FLAGS_POWER_CONTROL; ++ } ++ ++ /* ++ * Presence of _CRS indicates 'configurable'. ++ */ ++ if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, ++ "_CRS", &acpi_handle))) { ++ device->flags |= BM_FLAGS_CONFIGURABLE; ++ } ++ ++ /* Fall through to next case statement. */ ++ ++ case BM_TYPE_PROCESSOR: ++ case BM_TYPE_THERMAL_ZONE: ++ case BM_TYPE_POWER_RESOURCE: ++ /* ++ * Presence of _HID or _ADR indicates 'identifiable'. ++ */ ++ if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, ++ "_HID", &acpi_handle)) || ++ ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, ++ "_ADR", &acpi_handle))) { ++ device->flags |= BM_FLAGS_IDENTIFIABLE; ++ } ++ ++ /* ++ * Presence of _STA indicates 'dynamic status'. ++ */ ++ if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, ++ "_STA", &acpi_handle))) { ++ device->flags |= BM_FLAGS_DYNAMIC_STATUS; ++ } ++ ++ break; ++ } ++ ++ return AE_OK; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_add_namespace_device ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_add_namespace_device ( ++ ACPI_HANDLE acpi_handle, ++ ACPI_OBJECT_TYPE acpi_type, ++ BM_NODE *parent, ++ BM_NODE **child) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_NODE *node = NULL; ++ BM_DEVICE *device = NULL; ++ ++ FUNCTION_TRACE("bm_add_namespace_device"); ++ ++ if (!parent || !child) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ if (node_list.count > BM_HANDLES_MAX) { ++ return_ACPI_STATUS(AE_NO_MEMORY); ++ } ++ ++ (*child) = NULL; ++ ++ /* ++ * Create Node: ++ * ------------ ++ */ ++ node = acpi_os_callocate(sizeof(BM_NODE)); ++ if (!node) { ++ return_ACPI_STATUS(AE_NO_MEMORY); ++ } ++ ++ node->parent = parent; ++ node->next = NULL; ++ ++ device = &(node->device); ++ ++ device->handle = node_list.count; ++ device->acpi_handle = acpi_handle; ++ ++ /* ++ * Device Type: ++ * ------------ ++ */ ++ switch (acpi_type) { ++ case INTERNAL_TYPE_SCOPE: ++ device->id.type = BM_TYPE_SCOPE; ++ break; ++ case ACPI_TYPE_PROCESSOR: ++ device->id.type = BM_TYPE_PROCESSOR; ++ break; ++ case ACPI_TYPE_THERMAL: ++ device->id.type = BM_TYPE_THERMAL_ZONE; ++ break; ++ case ACPI_TYPE_POWER: ++ device->id.type = BM_TYPE_POWER_RESOURCE; ++ break; ++ case ACPI_TYPE_DEVICE: ++ device->id.type = BM_TYPE_DEVICE; ++ break; ++ } ++ ++ /* ++ * Get Other Device Info: ++ * ---------------------- ++ * But only if this device's parent is present (which implies ++ * this device MAY be present). ++ */ ++ if (BM_NODE_PRESENT(node->parent)) { ++ /* ++ * Device Flags ++ */ ++ status = bm_get_flags(device); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ /* ++ * Device Identification ++ */ ++ status = bm_get_identification(device); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ /* ++ * Device Status ++ */ ++ status = bm_get_status(device); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ /* ++ * Power Management: ++ * ----------------- ++ * If this node doesn't provide direct power control ++ * then we inherit PM capabilities from its parent. ++ * ++ * TODO: Inherit! ++ */ ++ if (BM_IS_POWER_CONTROL(device)) { ++ status = bm_get_pm_capabilities(node); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ } ++ } ++ ++end: ++ if (ACPI_FAILURE(status)) { ++ acpi_os_free(node); ++ } ++ else { ++ /* ++ * Add to the node_list. ++ */ ++ node_list.nodes[node_list.count++] = node; ++ ++ /* ++ * Formulate Hierarchy: ++ * -------------------- ++ * Arrange within the namespace by assigning the parent and ++ * adding to the parent device's list of children (scope). ++ */ ++ if (!parent->scope.head) { ++ parent->scope.head = node; ++ } ++ else { ++ if (!parent->scope.tail) { ++ (parent->scope.head)->next = node; ++ } ++ else { ++ (parent->scope.tail)->next = node; ++ } ++ } ++ parent->scope.tail = node; ++ ++ (*child) = node; ++ } ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_enumerate_namespace ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_enumerate_namespace (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ ACPI_HANDLE parent_handle = ACPI_ROOT_OBJECT; ++ ACPI_HANDLE child_handle = NULL; ++ BM_NODE *parent = NULL; ++ BM_NODE *child = NULL; ++ ACPI_OBJECT_TYPE acpi_type = 0; ++ u32 level = 1; ++ ++ FUNCTION_TRACE("bm_enumerate_namespace"); ++ ++ parent = node_list.nodes[0]; ++ ++ /* ++ * Enumerate ACPI Namespace: ++ * ------------------------- ++ * Parse through the ACPI namespace, identify all 'devices', ++ * and create a new entry for each in our collection. ++ */ ++ while (level > 0) { ++ ++ /* ++ * Get the next object at this level. ++ */ ++ status = acpi_get_next_object(ACPI_TYPE_ANY, parent_handle, child_handle, &child_handle); ++ if (ACPI_SUCCESS(status)) { ++ /* ++ * TODO: This is a hack to get around the problem ++ * identifying scope objects. Scopes ++ * somehow need to be uniquely identified. ++ */ ++ status = acpi_get_type(child_handle, &acpi_type); ++ if (ACPI_SUCCESS(status) && (acpi_type == ACPI_TYPE_ANY)) { ++ status = acpi_get_next_object(ACPI_TYPE_ANY, child_handle, 0, NULL); ++ if (ACPI_SUCCESS(status)) { ++ acpi_type = INTERNAL_TYPE_SCOPE; ++ } ++ } ++ ++ /* ++ * Device? ++ * ------- ++ * If this object is a 'device', insert into the ++ * ACPI Bus Manager's local hierarchy and search ++ * the object's scope for any child devices (a ++ * depth-first search). ++ */ ++ switch (acpi_type) { ++ case INTERNAL_TYPE_SCOPE: ++ case ACPI_TYPE_DEVICE: ++ case ACPI_TYPE_PROCESSOR: ++ case ACPI_TYPE_THERMAL: ++ case ACPI_TYPE_POWER: ++ status = bm_add_namespace_device(child_handle, acpi_type, parent, &child); ++ if (ACPI_SUCCESS(status)) { ++ status = acpi_get_next_object(ACPI_TYPE_ANY, child_handle, 0, NULL); ++ if (ACPI_SUCCESS(status)) { ++ level++; ++ parent_handle = child_handle; ++ child_handle = 0; ++ parent = child; ++ } ++ } ++ break; ++ } ++ } ++ ++ /* ++ * Scope Exhausted: ++ * ---------------- ++ * No more children in this object's scope, Go back up ++ * in the namespace tree to the object's parent. ++ */ ++ else { ++ level--; ++ child_handle = parent_handle; ++ acpi_get_parent(parent_handle, ++ &parent_handle); ++ ++ if (parent) { ++ parent = parent->parent; ++ } ++ else { ++ return_ACPI_STATUS(AE_NULL_ENTRY); ++ } ++ } ++ } ++ ++ return_ACPI_STATUS(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_add_fixed_feature_device ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_add_fixed_feature_device ( ++ BM_NODE *parent, ++ BM_DEVICE_TYPE device_type, ++ char *device_hid) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_NODE *node = NULL; ++ ++ FUNCTION_TRACE("bm_add_fixed_feature_device"); ++ ++ if (!parent) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ if (node_list.count > BM_HANDLES_MAX) { ++ return_ACPI_STATUS(AE_NO_MEMORY); ++ } ++ ++ /* ++ * Allocate the new device and add to the device array. ++ */ ++ node = acpi_os_callocate(sizeof(BM_NODE)); ++ if (!node) { ++ return_ACPI_STATUS(AE_NO_MEMORY); ++ } ++ ++ /* ++ * Get device info. ++ */ ++ node->device.handle = node_list.count; ++ node->device.acpi_handle = ACPI_ROOT_OBJECT; ++ node->device.id.type = BM_TYPE_FIXED_BUTTON; ++ if (device_hid) { ++ MEMCPY((void*)node->device.id.hid, device_hid, ++ sizeof(node->device.id.hid)); ++ } ++ node->device.flags = BM_FLAGS_FIXED_FEATURE; ++ node->device.status = BM_STATUS_DEFAULT; ++ /* TODO: Device PM capabilities */ ++ ++ /* ++ * Add to the node_list. ++ */ ++ node_list.nodes[node_list.count++] = node; ++ ++ /* ++ * Formulate Hierarchy: ++ * -------------------- ++ * Arrange within the namespace by assigning the parent and ++ * adding to the parent device's list of children (scope). ++ */ ++ node->parent = parent; ++ node->next = NULL; ++ ++ if (parent) { ++ if (!parent->scope.head) { ++ parent->scope.head = node; ++ } ++ else { ++ if (!parent->scope.tail) { ++ (parent->scope.head)->next = node; ++ } ++ else { ++ (parent->scope.tail)->next = node; ++ } ++ } ++ parent->scope.tail = node; ++ } ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_enumerate_fixed_features ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_enumerate_fixed_features (void) ++{ ++ FUNCTION_TRACE("bm_enumerate_fixed_features"); ++ ++ /* ++ * Root Object: ++ * ------------ ++ * Fabricate the root object, which happens to always get a ++ * device_handle of zero. ++ */ ++ node_list.nodes[0] = acpi_os_callocate(sizeof(BM_NODE)); ++ if (NULL == (node_list.nodes[0])) { ++ return_ACPI_STATUS(AE_NO_MEMORY); ++ } ++ ++ node_list.nodes[0]->device.handle = BM_HANDLE_ROOT; ++ node_list.nodes[0]->device.acpi_handle = ACPI_ROOT_OBJECT; ++ node_list.nodes[0]->device.flags = BM_FLAGS_UNKNOWN; ++ node_list.nodes[0]->device.status = BM_STATUS_DEFAULT; ++ node_list.nodes[0]->device.id.type = BM_TYPE_SYSTEM; ++ /* TODO: Get system PM capabilities (Sx states?) */ ++ ++ node_list.count++; ++ ++ /* ++ * Fixed Features: ++ * --------------- ++ * Enumerate fixed-feature devices (e.g. power and sleep buttons). ++ */ ++ if (acpi_fadt.pwr_button == 0) { ++ bm_add_fixed_feature_device(node_list.nodes[0], ++ BM_TYPE_FIXED_BUTTON, BM_HID_POWER_BUTTON); ++ } ++ ++ if (acpi_fadt.sleep_button == 0) { ++ bm_add_fixed_feature_device(node_list.nodes[0], ++ BM_TYPE_FIXED_BUTTON, BM_HID_SLEEP_BUTTON); ++ } ++ ++ return_ACPI_STATUS(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_get_handle ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_get_handle ( ++ ACPI_HANDLE acpi_handle, ++ BM_HANDLE *device_handle) ++{ ++ ACPI_STATUS status = AE_NOT_FOUND; ++ u32 i = 0; ++ ++ FUNCTION_TRACE("bm_get_handle"); ++ ++ if (!device_handle) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ *device_handle = BM_HANDLE_UNKNOWN; ++ ++ /* ++ * Search all devices for a match on the ACPI handle. ++ */ ++ for (i=0; i<node_list.count; i++) { ++ ++ if (!node_list.nodes[i]) { ++ DEBUG_PRINT(ACPI_ERROR, ("Invalid (NULL) node entry [%02x] detected.\n", device_handle)); ++ status = AE_NULL_ENTRY; ++ break; ++ } ++ ++ if (node_list.nodes[i]->device.acpi_handle == acpi_handle) { ++ *device_handle = node_list.nodes[i]->device.handle; ++ status = AE_OK; ++ break; ++ } ++ } ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_get_node ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_get_node ( ++ BM_HANDLE device_handle, ++ ACPI_HANDLE acpi_handle, ++ BM_NODE **node) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ FUNCTION_TRACE("bm_get_node"); ++ ++ if (!node) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * If no device handle, resolve acpi handle to device handle. ++ */ ++ if (!device_handle && acpi_handle) { ++ status = bm_get_handle(acpi_handle, &device_handle); ++ if (ACPI_FAILURE(status)) ++ return_ACPI_STATUS(status); ++ } ++ ++ /* ++ * Valid device handle? ++ */ ++ if (device_handle > BM_HANDLES_MAX) { ++ DEBUG_PRINT(ACPI_ERROR, ("Invalid node handle [%02x] detected.\n", device_handle)); ++ return_ACPI_STATUS(AE_ERROR); ++ } ++ ++ *node = node_list.nodes[device_handle]; ++ ++ /* ++ * Valid node? ++ */ ++ if (!(*node)) { ++ DEBUG_PRINT(ACPI_ERROR, ("Invalid (NULL) node entry [%02x] detected.\n", device_handle)); ++ return_ACPI_STATUS(AE_NULL_ENTRY); ++ } ++ ++ return_ACPI_STATUS(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * External Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_initialize ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: Exception code. ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_initialize (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ u32 start = 0; ++ u32 stop = 0; ++ u32 elapsed = 0; ++ ++ FUNCTION_TRACE("bm_initialize"); ++ ++ MEMSET(&node_list, 0, sizeof(BM_HANDLE_LIST)); ++ ++ acpi_get_timer(&start); ++ ++ DEBUG_PRINT(ACPI_INFO, ("Building device hierarchy.\n")); ++ ++ /* ++ * Enumerate ACPI fixed-feature devices. ++ */ ++ status = bm_enumerate_fixed_features(); ++ if (ACPI_FAILURE(status)) { ++ return_ACPI_STATUS(status); ++ } ++ ++ /* ++ * Enumerate the ACPI namespace. ++ */ ++ status = bm_enumerate_namespace(); ++ if (ACPI_FAILURE(status)) { ++ return_ACPI_STATUS(status); ++ } ++ ++ acpi_get_timer(&stop); ++ acpi_get_timer_duration(start, stop, &elapsed); ++ ++ DEBUG_PRINT(ACPI_INFO, ("Building device hierarchy took [%d] microseconds.\n", elapsed)); ++ ++ /* ++ * Display hierarchy. ++ */ ++ bm_print_hierarchy(); ++ ++ /* ++ * Register for all standard and device-specific notifications. ++ */ ++ DEBUG_PRINT(ACPI_INFO, ("Registering for all device notifications.\n")); ++ ++ status = acpi_install_notify_handler(ACPI_ROOT_OBJECT, ++ ACPI_SYSTEM_NOTIFY, &bm_notify, NULL); ++ if (ACPI_FAILURE(status)) { ++ DEBUG_PRINT(ACPI_ERROR, ("Unable to register for standard notifications.\n")); ++ return_ACPI_STATUS(status); ++ } ++ ++ status = acpi_install_notify_handler(ACPI_ROOT_OBJECT, ++ ACPI_DEVICE_NOTIFY, &bm_notify, NULL); ++ if (ACPI_FAILURE(status)) { ++ DEBUG_PRINT(ACPI_ERROR, ("Unable to register for device-specific notifications.\n")); ++ return_ACPI_STATUS(status); ++ } ++ ++ DEBUG_PRINT(ACPI_INFO, ("ACPI Bus Manager enabled.\n")); ++ ++ /* ++ * Initialize built-in power resource driver. ++ */ ++ bm_pr_initialize(); ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_terminate ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: Exception code. ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_terminate (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ u32 i = 0; ++ ++ FUNCTION_TRACE("bm_terminate"); ++ ++ /* ++ * Terminate built-in power resource driver. ++ */ ++ bm_pr_terminate(); ++ ++ /* ++ * Unregister for all notifications. ++ */ ++ DEBUG_PRINT(ACPI_INFO, ("Unregistering for device notifications.\n")); ++ ++ status = acpi_remove_notify_handler(ACPI_ROOT_OBJECT, ++ ACPI_SYSTEM_NOTIFY, &bm_notify); ++ if (ACPI_FAILURE(status)) { ++ DEBUG_PRINT(ACPI_ERROR, ("Unable to un-register for standard notifications.\n")); ++ } ++ ++ status = acpi_remove_notify_handler(ACPI_ROOT_OBJECT, ++ ACPI_DEVICE_NOTIFY, &bm_notify); ++ if (ACPI_FAILURE(status)) { ++ DEBUG_PRINT(ACPI_ERROR, ("Unable to un-register for device-specific notifications.\n")); ++ } ++ ++ /* ++ * Parse through the device array, freeing all entries. ++ */ ++ DEBUG_PRINT(ACPI_INFO, ("Removing device hierarchy.\n")); ++ for (i = 0; i < node_list.count; i++) { ++ if (node_list.nodes[i]) { ++ acpi_os_free(node_list.nodes[i]); ++ } ++ } ++ ++ DEBUG_PRINT(ACPI_INFO, ("ACPI Bus Manager disabled.\n")); ++ ++ return_ACPI_STATUS(AE_OK); ++} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/busmgr/bm_osl.c linux/drivers/acpi/ospm/busmgr/bm_osl.c +--- /usr/src/linux/drivers/acpi/ospm/busmgr/bm_osl.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/busmgr/bm_osl.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,346 @@ ++/***************************************************************************** ++ * ++ * Module Name: bm_osl.c ++ * $Revision: 5 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/types.h> ++#include <linux/proc_fs.h> ++#include <linux/spinlock.h> ++#include <acpi.h> ++#include "bm.h" ++ ++ ++MODULE_AUTHOR("Andrew Grover"); ++MODULE_DESCRIPTION("ACPI Component Architecture (CA) - ACPI Bus Manager"); ++ ++ ++#ifdef ACPI_DEBUG ++ ++static int dbg_layer = ACPI_COMPONENT_DEFAULT; ++MODULE_PARM(dbg_layer, "i"); ++MODULE_PARM_DESC(dbg_layer, "Controls debug output (see acpi_dbg_layer).\n"); ++ ++static int dbg_level = DEBUG_DEFAULT; ++MODULE_PARM(dbg_level, "i"); ++MODULE_PARM_DESC(dbg_level, "Controls debug output (see acpi_dbg_level).\n"); ++ ++#endif /*ACPI_DEBUG*/ ++ ++ ++/***************************************************************************** ++ * Types & Defines ++ *****************************************************************************/ ++ ++typedef struct ++{ ++ BM_HANDLE device_handle; ++ char *device_type; ++ char *device_instance; ++ u32 event_type; ++ u32 event_data; ++ struct list_head list; ++} BM_OSL_EVENT; ++ ++ ++#define BM_PROC_ROOT "acpi" ++#define BM_PROC_EVENT "event" ++#define BM_PROC_DEVICES "devices" ++ ++ ++/**************************************************************************** ++ * Globals ++ ****************************************************************************/ ++ ++struct proc_dir_entry *bm_proc_root = NULL; ++static struct proc_dir_entry *bm_proc_event = NULL; ++ ++#ifdef ACPI_DEBUG ++static u32 save_dbg_layer; ++static u32 save_dbg_level; ++#endif ++ ++extern BM_NODE_LIST node_list; ++ ++static spinlock_t bm_osl_event_list_lock = SPIN_LOCK_UNLOCKED; ++ ++static LIST_HEAD(bm_event_list); ++ ++static DECLARE_WAIT_QUEUE_HEAD(bm_event_wait_queue); ++ ++ ++/**************************************************************************** ++ * Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_osl_generate_event ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: Generates an event for user-space consumption by writing ++ * the event data to the 'event' file. ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_osl_generate_event ( ++ BM_HANDLE device_handle, ++ char *device_type, ++ char *device_instance, ++ u32 event_type, ++ u32 event_data) ++{ ++ BM_OSL_EVENT *event = NULL; ++ u32 flags = 0; ++ ++ /* ++ * Allocate a new event structure. ++ */ ++ event = acpi_os_callocate(sizeof(BM_OSL_EVENT)); ++ event->device_type = acpi_os_callocate(strlen(device_type) ++ + sizeof(char)); ++ event->device_instance = acpi_os_callocate(strlen(device_instance) ++ + sizeof(char)); ++ ++ if (!event || !event->device_type || !event->device_instance) { ++ return(AE_NO_MEMORY); ++ } ++ ++ /* ++ * Set event data. ++ */ ++ event->device_handle = device_handle; ++ strcpy(event->device_type, device_type); ++ strcpy(event->device_instance, device_instance); ++ event->event_type = event_type; ++ event->event_data = event_data; ++ ++ /* ++ * Add to the end of our event list. ++ */ ++ spin_lock_irqsave(&bm_osl_event_list_lock, flags); ++ list_add_tail(&event->list, &bm_event_list); ++ spin_unlock_irqrestore(&bm_osl_event_list_lock, flags); ++ ++ /* ++ * Signal waiting threads (if any). ++ */ ++ wake_up_interruptible(&bm_event_wait_queue); ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_osl_event_read ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: Handles reads to the 'event' file by blocking user-mode ++ * threads until data (an event) is generated. ++ * ++ ****************************************************************************/ ++ ++static int ++bm_osl_event_read ( ++ char *page, ++ char **start, ++ off_t off, ++ int count, ++ int *eof, ++ void *context) ++{ ++ char *p = page; ++ int len = 0; ++ unsigned long flags = 0; ++ BM_OSL_EVENT *event = NULL; ++ ++ DECLARE_WAITQUEUE(wait, current); ++ ++ if (off != 0) { ++ goto End; ++ } ++ ++ if (list_empty(&bm_event_list)) { ++ ++ set_current_state(TASK_INTERRUPTIBLE); ++ add_wait_queue(&bm_event_wait_queue, &wait); ++ ++ if (list_empty(&bm_event_list)) { ++ schedule(); ++ } ++ ++ remove_wait_queue(&bm_event_wait_queue, &wait); ++ set_current_state(TASK_RUNNING); ++ ++ if (signal_pending(current)) { ++ return -ERESTARTSYS; ++ } ++ ++ } ++ ++ event = list_entry(bm_event_list.next, BM_OSL_EVENT, list); ++ if (!event) { ++ goto End; ++ } ++ ++ p += sprintf(p, "%s %s %08x %08x\n", event->device_type, ++ event->device_instance, event->event_type, event->event_data); ++ ++ spin_lock_irqsave(&bm_osl_event_list_lock, flags); ++ list_del(&event->list); ++ spin_unlock_irqrestore(&bm_osl_event_list_lock, flags); ++ ++ acpi_os_free(event->device_type); ++ acpi_os_free(event->device_instance); ++ acpi_os_free(event); ++ ++End: ++ len = (p - page); ++ if (len <= off+count) *eof = 1; ++ *start = page + off; ++ len -= off; ++ if (len > count) len = count; ++ if (len < 0) len = 0; ++ ++ return(len); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_osl_init ++ * ++ ****************************************************************************/ ++ ++int bm_osl_init(void) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++#ifdef ACPI_DEBUG ++ save_dbg_layer = acpi_dbg_layer; ++ acpi_dbg_layer = dbg_layer; ++ ++ save_dbg_level = acpi_dbg_level; ++ acpi_dbg_level = dbg_level; ++#endif /*ACPI_DEBUG*/ ++ ++ bm_proc_root = proc_mkdir(BM_PROC_ROOT, NULL); ++ if (!bm_proc_root) { ++ return(AE_ERROR); ++ } ++ ++ bm_proc_event = create_proc_read_entry(BM_PROC_EVENT, S_IFREG | S_IRUGO, ++ bm_proc_root, bm_osl_event_read, NULL); ++ if (!bm_proc_event) { ++ return(AE_ERROR); ++ } ++ ++ status = bm_initialize(); ++ ++ return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_osl_cleanup ++ * ++ ****************************************************************************/ ++ ++void bm_osl_cleanup(void) ++{ ++#ifdef ACPI_DEBUG ++ acpi_dbg_layer = save_dbg_layer; ++ acpi_dbg_level = save_dbg_level; ++#endif /*ACPI_DEBUG*/ ++ ++ bm_terminate(); ++ ++ if (bm_proc_event) { ++ remove_proc_entry(BM_PROC_EVENT, bm_proc_root); ++ bm_proc_event = NULL; ++ } ++ ++ if (bm_proc_root) { ++ remove_proc_entry(BM_PROC_ROOT, NULL); ++ bm_proc_root = NULL; ++ } ++ ++ return; ++} ++ ++ ++module_init(bm_osl_init); ++module_exit(bm_osl_cleanup); ++ ++ ++/**************************************************************************** ++ * Symbols ++ ****************************************************************************/ ++ ++/* bm.c */ ++ ++EXPORT_SYMBOL(bm_get_node); ++ ++/* bmdriver.c */ ++ ++EXPORT_SYMBOL(bm_get_device_power_state); ++EXPORT_SYMBOL(bm_set_device_power_state); ++EXPORT_SYMBOL(bm_get_device_info); ++EXPORT_SYMBOL(bm_get_device_status); ++EXPORT_SYMBOL(bm_get_device_context); ++EXPORT_SYMBOL(bm_register_driver); ++EXPORT_SYMBOL(bm_unregister_driver); ++ ++/* bmsearch.c */ ++ ++EXPORT_SYMBOL(bm_search); ++ ++/* bmrequest.c */ ++ ++EXPORT_SYMBOL(bm_request); ++ ++/* bmutils.c */ ++ ++EXPORT_SYMBOL(bm_extract_package_data); ++EXPORT_SYMBOL(bm_evaluate_object); ++EXPORT_SYMBOL(bm_evaluate_simple_integer); ++EXPORT_SYMBOL(bm_evaluate_reference_list); ++EXPORT_SYMBOL(bm_copy_to_buffer); ++EXPORT_SYMBOL(bm_cast_buffer); ++ ++/* bm_proc.c */ ++ ++EXPORT_SYMBOL(bm_osl_generate_event); ++EXPORT_SYMBOL(bm_proc_root); +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/busmgr/bmdriver.c linux/drivers/acpi/ospm/busmgr/bmdriver.c +--- /usr/src/linux/drivers/acpi/ospm/busmgr/bmdriver.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/busmgr/bmdriver.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,469 @@ ++/***************************************************************************** ++ * ++ * Module Name: bmdriver.c ++ * $Revision: 12 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include <acpi.h> ++#include "bm.h" ++ ++#define _COMPONENT ACPI_BUS_MANAGER ++ MODULE_NAME ("bmdriver") ++ ++ ++/**************************************************************************** ++ * External Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_get_device_power_state ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_get_device_power_state ( ++ BM_HANDLE device_handle, ++ BM_POWER_STATE *state) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_NODE *node = NULL; ++ ++ FUNCTION_TRACE("bm_get_device_power_state"); ++ ++ if (!state) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ *state = ACPI_STATE_UNKNOWN; ++ ++ /* ++ * Resolve device handle to node. ++ */ ++ status = bm_get_node(device_handle, 0, &node); ++ if (ACPI_FAILURE(status)) { ++ return_ACPI_STATUS(status); ++ } ++ ++ /* ++ * Get the current power state. ++ */ ++ status = bm_get_power_state(node); ++ if (ACPI_FAILURE(status)) { ++ return_ACPI_STATUS(status); ++ } ++ ++ *state = node->device.power.state; ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_set_device_power_state ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_set_device_power_state ( ++ BM_HANDLE device_handle, ++ BM_POWER_STATE state) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_NODE *node = NULL; ++ ++ FUNCTION_TRACE("bm_set_device_power_state"); ++ ++ /* ++ * Resolve device handle to node. ++ */ ++ status = bm_get_node(device_handle, 0, &node); ++ if (ACPI_FAILURE(status)) { ++ return_ACPI_STATUS(status); ++ } ++ ++ /* ++ * Set the current power state. ++ */ ++ status = bm_set_power_state(node, state); ++ if (ACPI_FAILURE(status)) { ++ return_ACPI_STATUS(status); ++ } ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_get_device_status ++ * ++ * PARAMETERS: ++ * device_handle is really an index number into the array of BM_DEVICE ++ * structures in info_list. This data item is passed to ++ * the registered program's "notify" callback. It is used ++ * to retrieve the specific BM_DEVICE structure instance ++ * associated with the callback. ++ * device_status is a pointer that receives the result of processing ++ * the device's associated ACPI _STA. ++ * ++ * RETURN: ++ * The ACPI_STATUS value indicates success AE_OK or failure of the function ++ * ++ * DESCRIPTION: Evaluates the device's ACPI _STA, if it is present. ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_get_device_status ( ++ BM_HANDLE device_handle, ++ BM_DEVICE_STATUS *device_status) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_NODE *node = NULL; ++ ++ FUNCTION_TRACE("bm_get_device_status"); ++ ++ if (!device_status) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ *device_status = BM_STATUS_UNKNOWN; ++ ++ /* ++ * Resolve device handle to node. ++ */ ++ status = bm_get_node(device_handle, 0, &node); ++ if (ACPI_FAILURE(status)) { ++ return_ACPI_STATUS(status); ++ } ++ ++ /* ++ * Parent Present? ++ * --------------- ++ * If the parent isn't present we can't evalute _STA on the child. ++ * Return an unknown status. ++ */ ++ if (!BM_NODE_PRESENT(node->parent)) { ++ return_ACPI_STATUS(AE_OK); ++ } ++ ++ /* ++ * Dynamic Status? ++ * --------------- ++ * If _STA isn't present we just return the default status. ++ */ ++ if (!(node->device.flags & BM_FLAGS_DYNAMIC_STATUS)) { ++ *device_status = BM_STATUS_DEFAULT; ++ return_ACPI_STATUS(AE_OK); ++ } ++ ++ /* ++ * Evaluate _STA: ++ * -------------- ++ */ ++ status = bm_evaluate_simple_integer(node->device.acpi_handle, "_STA", ++ &(node->device.status)); ++ if (ACPI_SUCCESS(status)) { ++ *device_status = node->device.status; ++ } ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_get_device_info ++ * ++ * PARAMETERS: ++ * device_handle An index used to retrieve the associated BM_DEVICE info. ++ * device A pointer to a BM_DEVICE structure instance pointer. ++ * This pointed to BM_DEVICE structure will contain the ++ * this device's information. ++ * ++ * RETURN: ++ * The ACPI_STATUS value indicates success AE_OK or failure of the function ++ * ++ * DESCRIPTION: ++ * Using the device_handle this function retrieves this device's ++ * BM_DEVICE structure instance and save's it in device. ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_get_device_info ( ++ BM_HANDLE device_handle, ++ BM_DEVICE **device) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_NODE *node = NULL; ++ ++ FUNCTION_TRACE("bm_get_device_info"); ++ ++ if (!device) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Resolve device handle to internal device. ++ */ ++ status = bm_get_node(device_handle, 0, &node); ++ if (ACPI_FAILURE(status)) { ++ return_ACPI_STATUS(status); ++ } ++ ++ *device = &(node->device); ++ ++ return_ACPI_STATUS(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_get_device_context ++ * ++ * device_handle An index used to retrieve the associated BM_DEVICE info. ++ * context A pointer to a BM_DRIVER_CONTEXT structure instance. ++ * ++ * RETURN: ++ * The ACPI_STATUS value indicates success AE_OK or failure of the function ++ * ++ * DESCRIPTION: ++ * Using the device_handle this function retrieves this device's ++ * BM_DRIVER_CONTEXT structure instance and save's it in context. ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_get_device_context ( ++ BM_HANDLE device_handle, ++ BM_DRIVER_CONTEXT *context) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_NODE *node = NULL; ++ ++ FUNCTION_TRACE("bm_get_device_context"); ++ ++ if (!context) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ *context = NULL; ++ ++ /* ++ * Resolve device handle to internal device. ++ */ ++ status = bm_get_node(device_handle, 0, &node); ++ if (ACPI_FAILURE(status)) { ++ return_ACPI_STATUS(status); ++ } ++ ++ if (!node->driver.context) { ++ return_ACPI_STATUS(AE_NULL_ENTRY); ++ } ++ ++ *context = node->driver.context; ++ ++ return_ACPI_STATUS(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_register_driver ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_register_driver ( ++ BM_DEVICE_ID *criteria, ++ BM_DRIVER *driver) ++{ ++ ACPI_STATUS status = AE_NOT_FOUND; ++ BM_HANDLE_LIST device_list; ++ BM_NODE *node = NULL; ++ BM_DEVICE *device = NULL; ++ u32 i = 0; ++ ++ FUNCTION_TRACE("bm_register_driver"); ++ ++ if (!criteria || !driver || !driver->notify || !driver->request) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ MEMSET(&device_list, 0, sizeof(BM_HANDLE_LIST)); ++ ++ /* ++ * Find Matches: ++ * ------------- ++ * Search through the entire device hierarchy for matches against ++ * the given device criteria. ++ */ ++ status = bm_search(BM_HANDLE_ROOT, criteria, &device_list); ++ if (ACPI_FAILURE(status)) { ++ return_ACPI_STATUS(status); ++ } ++ ++ /* ++ * Install driver: ++ * ---------------- ++ * For each match, record the driver information and execute the ++ * driver's Notify() funciton (if present) to notify the driver ++ * of the device's presence. ++ */ ++ for (i = 0; i < device_list.count; i++) { ++ ++ /* Resolve the device handle. */ ++ status = bm_get_node(device_list.handles[i], 0, &node); ++ if (ACPI_FAILURE(status)) { ++ continue; ++ } ++ ++ device = &(node->device); ++ ++ /* ++ * Make sure another driver hasn't already registered for ++ * this device. ++ */ ++ if (BM_IS_DRIVER_CONTROL(device)) { ++ DEBUG_PRINT(ACPI_INFO, ("Another driver has already registered for device [%02x].\n", device->handle)); ++ continue; ++ } ++ ++ DEBUG_PRINT(ACPI_INFO, ("Registering driver for device [%02x].\n", device->handle)); ++ ++ /* Notify driver of new device. */ ++ status = driver->notify(BM_NOTIFY_DEVICE_ADDED, ++ node->device.handle, &(node->driver.context)); ++ if (ACPI_SUCCESS(status)) { ++ node->driver.notify = driver->notify; ++ node->driver.request = driver->request; ++ node->device.flags |= BM_FLAGS_DRIVER_CONTROL; ++ } ++ } ++ ++ return_ACPI_STATUS(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_unregister_driver ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_unregister_driver ( ++ BM_DEVICE_ID *criteria, ++ BM_DRIVER *driver) ++{ ++ ACPI_STATUS status = AE_NOT_FOUND; ++ BM_HANDLE_LIST device_list; ++ BM_NODE *node = NULL; ++ BM_DEVICE *device = NULL; ++ u32 i = 0; ++ ++ FUNCTION_TRACE("bm_unregister_driver"); ++ ++ if (!criteria || !driver || !driver->notify || !driver->request) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ MEMSET(&device_list, 0, sizeof(BM_HANDLE_LIST)); ++ ++ /* ++ * Find Matches: ++ * ------------- ++ * Search through the entire device hierarchy for matches against ++ * the given device criteria. ++ */ ++ status = bm_search(BM_HANDLE_ROOT, criteria, &device_list); ++ if (ACPI_FAILURE(status)) { ++ return_ACPI_STATUS(status); ++ } ++ ++ /* ++ * Remove driver: ++ * --------------- ++ * For each match, execute the driver's Notify() function to allow ++ * the driver to cleanup each device instance. ++ */ ++ for (i = 0; i < device_list.count; i++) { ++ ++ /* Resolve the device handle. */ ++ status = bm_get_node(device_list.handles[i], 0, &node); ++ if (ACPI_FAILURE(status)) { ++ continue; ++ } ++ ++ device = &(node->device); ++ ++ /* ++ * Make sure driver has really registered for this device. ++ */ ++ if (!BM_IS_DRIVER_CONTROL(device)) { ++ DEBUG_PRINT(ACPI_INFO, ("Driver hasn't registered for device [%02x].\n", device->handle)); ++ continue; ++ } ++ ++ DEBUG_PRINT(ACPI_INFO, ("Unregistering driver for device [%02x].\n", device->handle)); ++ ++ /* Notify driver of device removal. */ ++ status = node->driver.notify(BM_NOTIFY_DEVICE_REMOVED, ++ node->device.handle, &(node->driver.context)); ++ if (ACPI_SUCCESS(status)) { ++ node->driver.notify = NULL; ++ node->driver.request = NULL; ++ node->driver.context = NULL; ++ node->device.flags &= ~BM_FLAGS_DRIVER_CONTROL; ++ } ++ } ++ ++ return_ACPI_STATUS(AE_OK); ++} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/busmgr/bmnotify.c linux/drivers/acpi/ospm/busmgr/bmnotify.c +--- /usr/src/linux/drivers/acpi/ospm/busmgr/bmnotify.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/busmgr/bmnotify.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,312 @@ ++/***************************************************************************** ++ * ++ * Module Name: bmnotify.c ++ * $Revision: 11 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include <acpi.h> ++#include "bm.h" ++ ++ ++#define _COMPONENT ACPI_BUS_MANAGER ++ MODULE_NAME ("bmnotify") ++ ++ ++/**************************************************************************** ++ * Internal Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_generate_notify ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_generate_notify ( ++ BM_NODE *node, ++ u32 notify_type) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE *device = NULL; ++ ++ FUNCTION_TRACE("bm_generate_notify"); ++ ++ if (!node) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ device = &(node->device); ++ ++ DEBUG_PRINT(ACPI_INFO, ("Sending notify [%02x] to device [%02x].\n", notify_type, node->device.handle)); ++ ++ if (!BM_IS_DRIVER_CONTROL(device)) { ++ DEBUG_PRINT(ACPI_WARN, ("No driver installed for device [%02x].\n", device->handle)); ++ return_ACPI_STATUS(AE_NOT_EXIST); ++ } ++ ++ status = node->driver.notify(notify_type, node->device.handle, ++ &(node->driver.context)); ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_device_check ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_device_check ( ++ BM_NODE *node, ++ u32 *status_change) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE *device = NULL; ++ BM_DEVICE_STATUS old_status = BM_STATUS_UNKNOWN; ++ ++ FUNCTION_TRACE("bm_device_check"); ++ ++ if (!node) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ device = &(node->device); ++ ++ if (status_change) { ++ *status_change = FALSE; ++ } ++ ++ old_status = device->status; ++ ++ /* ++ * Parent Present? ++ * --------------- ++ * Only check this device if its parent is present (which implies ++ * this device MAY be present). ++ */ ++ if (!BM_NODE_PRESENT(node->parent)) { ++ return_ACPI_STATUS(AE_OK); ++ } ++ ++ /* ++ * Get Status: ++ * ----------- ++ * And see if the status has changed. ++ */ ++ status = bm_get_status(device); ++ if (ACPI_FAILURE(status)) { ++ return_ACPI_STATUS(status); ++ } ++ ++ if (old_status == node->device.status) { ++ return_ACPI_STATUS(AE_OK); ++ } ++ ++ if (status_change) { ++ *status_change = TRUE; ++ } ++ ++ /* ++ * Device Insertion? ++ * ----------------- ++ */ ++ if ((device->status & BM_STATUS_PRESENT) && ++ !(old_status & BM_STATUS_PRESENT)) { ++ /* TODO: Make sure driver is loaded, and if not, load. */ ++ status = bm_generate_notify(node, BM_NOTIFY_DEVICE_ADDED); ++ } ++ ++ /* ++ * Device Removal? ++ * --------------- ++ */ ++ else if (!(device->status & BM_STATUS_PRESENT) && ++ (old_status & BM_STATUS_PRESENT)) { ++ /* TODO: Unload driver if last device instance. */ ++ status = bm_generate_notify(node, BM_NOTIFY_DEVICE_REMOVED); ++ } ++ ++ return_ACPI_STATUS(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_bus_check ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_bus_check ( ++ BM_NODE *parent_node) ++{ ++ ACPI_STATUS status = AE_OK; ++ u32 status_change = FALSE; ++ ++ FUNCTION_TRACE("bm_bus_check"); ++ ++ if (!parent_node) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Status Change? ++ * -------------- ++ */ ++ status = bm_device_check(parent_node, &status_change); ++ if (ACPI_FAILURE(status) || !status_change) { ++ return_ACPI_STATUS(status); ++ } ++ ++ /* ++ * Enumerate Scope: ++ * ---------------- ++ * TODO: Enumerate child devices within this device's scope and ++ * run bm_device_check()'s on them... ++ */ ++ ++ return_ACPI_STATUS(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * External Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_notify ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++void ++bm_notify ( ++ ACPI_HANDLE acpi_handle, ++ u32 notify_value, ++ void *context) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_NODE *node = NULL; ++ ++ FUNCTION_TRACE("bm_notify"); ++ ++ /* ++ * Resolve the ACPI handle. ++ */ ++ status = bm_get_node(0, acpi_handle, &node); ++ if (ACPI_FAILURE(status)) { ++ DEBUG_PRINT(ACPI_INFO, ("Recieved notify [%02x] for unknown device [%p].\n", notify_value, acpi_handle)); ++ return_VOID; ++ } ++ ++ /* ++ * Device-Specific or Standard? ++ * ---------------------------- ++ * Device-specific notifies are forwarded to the control module's ++ * notify() function for processing. Standard notifies are handled ++ * internally. ++ */ ++ if (notify_value > 0x7F) { ++ status = bm_generate_notify(node, notify_value); ++ } ++ else { ++ switch (notify_value) { ++ ++ case BM_NOTIFY_BUS_CHECK: ++ DEBUG_PRINT(ACPI_INFO, ("Received BUS CHECK notification for device [%02x].\n", node->device.handle)); ++ status = bm_bus_check(node); ++ break; ++ ++ case BM_NOTIFY_DEVICE_CHECK: ++ DEBUG_PRINT(ACPI_INFO, ("Received DEVICE CHECK notification for device [%02x].\n", node->device.handle)); ++ status = bm_device_check(node, NULL); ++ break; ++ ++ case BM_NOTIFY_DEVICE_WAKE: ++ DEBUG_PRINT(ACPI_INFO, ("Received DEVICE WAKE notification for device [%02x].\n", node->device.handle)); ++ /* TODO */ ++ break; ++ ++ case BM_NOTIFY_EJECT_REQUEST: ++ DEBUG_PRINT(ACPI_INFO, ("Received EJECT REQUEST notification for device [%02x].\n", node->device.handle)); ++ /* TODO */ ++ break; ++ ++ case BM_NOTIFY_DEVICE_CHECK_LIGHT: ++ DEBUG_PRINT(ACPI_INFO, ("Received DEVICE CHECK LIGHT notification for device [%02x].\n", node->device.handle)); ++ /* TODO: Exactly what does the 'light' mean? */ ++ status = bm_device_check(node, NULL); ++ break; ++ ++ case BM_NOTIFY_FREQUENCY_MISMATCH: ++ DEBUG_PRINT(ACPI_INFO, ("Received FREQUENCY MISMATCH notification for device [%02x].\n", node->device.handle)); ++ /* TODO */ ++ break; ++ ++ case BM_NOTIFY_BUS_MODE_MISMATCH: ++ DEBUG_PRINT(ACPI_INFO, ("Received BUS MODE MISMATCH notification for device [%02x].\n", node->device.handle)); ++ /* TODO */ ++ break; ++ ++ case BM_NOTIFY_POWER_FAULT: ++ DEBUG_PRINT(ACPI_INFO, ("Received POWER FAULT notification.\n")); ++ /* TODO */ ++ break; ++ ++ default: ++ DEBUG_PRINT(ACPI_INFO, ("Received unknown/unsupported notification.\n")); ++ break; ++ } ++ } ++ ++ return_VOID; ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/busmgr/bmpm.c linux/drivers/acpi/ospm/busmgr/bmpm.c +--- /usr/src/linux/drivers/acpi/ospm/busmgr/bmpm.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/busmgr/bmpm.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,442 @@ ++/***************************************************************************** ++ * ++ * Module Name: bmpm.c ++ * $Revision: 5 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include <acpi.h> ++#include "bm.h" ++#include "bmpower.h" ++ ++ ++#define _COMPONENT ACPI_POWER_CONTROL ++ MODULE_NAME ("bmpm") ++ ++ ++/**************************************************************************** ++ * Internal Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_get_inferred_power_state ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_get_inferred_power_state ( ++ BM_DEVICE *device) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_HANDLE_LIST pr_list; ++ BM_POWER_STATE list_state = ACPI_STATE_UNKNOWN; ++ char object_name[5] = {'_','P','R','0','\0'}; ++ u32 i = 0; ++ ++ FUNCTION_TRACE("bm_get_inferred_power_state"); ++ ++ if (!device) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ MEMSET(&pr_list, 0, sizeof(BM_HANDLE_LIST)); ++ ++ device->power.state = ACPI_STATE_D3; ++ ++ /* ++ * Calculate Power State: ++ * ---------------------- ++ * Try to infer the devices's power state by checking the state of ++ * the devices's power resources. We start by evaluating _PR0 ++ * (resource requirements at D0) and work through _PR1 and _PR2. ++ * We know the current devices power state when all resources (for ++ * a give Dx state) are ON. If no power resources are on then the ++ * device is assumed to be off (D3). ++ */ ++ for (i=ACPI_STATE_D0; i<ACPI_STATE_D3; i++) { ++ ++ object_name[3] = '0' + i; ++ ++ status = bm_evaluate_reference_list(device->acpi_handle, ++ object_name, &pr_list); ++ ++ if (ACPI_SUCCESS(status)) { ++ ++ status = bm_pr_list_get_state(&pr_list, &list_state); ++ ++ if (ACPI_SUCCESS(status)) { ++ ++ if (list_state == ACPI_STATE_D0) { ++ device->power.state = i; ++ break; ++ } ++ } ++ } ++ } ++ ++ return_ACPI_STATUS(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * External Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_get_power_state ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_get_power_state ( ++ BM_NODE *node) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE *device = NULL; ++ ++ FUNCTION_TRACE("bm_get_power_state"); ++ ++ if (!node || !node->parent) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ device = &(node->device); ++ ++ device->power.state = ACPI_STATE_UNKNOWN; ++ ++ /* ++ * Power Control? ++ * -------------- ++ * If this device isn't directly power manageable (e.g. doesn't ++ * include _PR0/_PS0) then there's nothing to do (state is static). ++ */ ++ if (!BM_IS_POWER_CONTROL(device)) { ++ return_ACPI_STATUS(AE_OK); ++ } ++ ++ /* ++ * Parent Present? ++ * --------------- ++ * Make sure the parent is present before mucking with the child. ++ */ ++ if (!BM_NODE_PRESENT(node->parent)) { ++ return_ACPI_STATUS(AE_NOT_EXIST); ++ } ++ ++ /* ++ * Get Power State: ++ * ---------------- ++ * Either directly (via _PSC) or inferred (via power resource ++ * dependencies). ++ */ ++ if (BM_IS_POWER_STATE(device)) { ++ status = bm_evaluate_simple_integer(device->acpi_handle, ++ "_PSC", &(device->power.state)); ++ } ++ else { ++ status = bm_get_inferred_power_state(device); ++ } ++ ++ if (ACPI_SUCCESS(status)) { ++ DEBUG_PRINT(ACPI_INFO, ("Device [%02x] is at power state [D%d].\n", device->handle, device->power.state)); ++ } ++ else { ++ DEBUG_PRINT(ACPI_INFO, ("Error getting power state for device [%02x]\n", device->handle)); ++ } ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_set_power_state ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_set_power_state ( ++ BM_NODE *node, ++ BM_POWER_STATE state) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE *device = NULL; ++ BM_DEVICE *parent_device = NULL; ++ BM_HANDLE_LIST current_list; ++ BM_HANDLE_LIST target_list; ++ char object_name[5] = {'_','P','R','0','\0'}; ++ ++ FUNCTION_TRACE("bm_set_power_state"); ++ ++ if (!node || !node->parent || (state > ACPI_STATE_D3)) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ MEMSET(¤t_list, 0, sizeof(BM_HANDLE_LIST)); ++ MEMSET(&target_list, 0, sizeof(BM_HANDLE_LIST)); ++ ++ device = &(node->device); ++ parent_device = &(node->parent->device); ++ ++ /* ++ * Power Control? ++ * -------------- ++ * If this device isn't directly power manageable (e.g. doesn't ++ * include _PR0/_PS0) then return an error (can't set state). ++ */ ++ if (!BM_IS_POWER_CONTROL(device)) { ++ return_ACPI_STATUS(AE_ERROR); ++ } ++ ++ /* ++ * Parent Present? ++ * --------------- ++ * Make sure the parent is present before mucking with the child. ++ */ ++ if (!BM_NODE_PRESENT(node->parent)) { ++ return_ACPI_STATUS(AE_NOT_EXIST); ++ } ++ ++ /* ++ * Check Parent's Power State: ++ * --------------------------- ++ * Can't be in a higher power state (lower Dx value) than parent. ++ */ ++ if (state < parent_device->power.state) { ++ DEBUG_PRINT(ACPI_WARN, ("Cannot set device [%02x] to a higher-powered state than parent_device.\n", device->handle)); ++ return_ACPI_STATUS(AE_ERROR); ++ } ++ ++ /* ++ * Get Resources: ++ * -------------- ++ * Get the power resources associated with the device's current ++ * and target power states. ++ */ ++ if (device->power.state != ACPI_STATE_UNKNOWN) { ++ object_name[3] = '0' + device->power.state; ++ bm_evaluate_reference_list(device->acpi_handle, ++ object_name, ¤t_list); ++ } ++ ++ object_name[3] = '0' + state; ++ bm_evaluate_reference_list(device->acpi_handle, object_name, ++ &target_list); ++ ++ /* ++ * Transition Resources: ++ * --------------------- ++ * Transition all power resources referenced by this device to ++ * the correct power state (taking into consideration sequencing ++ * and dependencies to other devices). ++ */ ++ if (current_list.count || target_list.count) { ++ status = bm_pr_list_transition(¤t_list, &target_list); ++ } ++ if (ACPI_FAILURE(status)) { ++ return_ACPI_STATUS(status); ++ } ++ ++ /* ++ * Execute _PSx: ++ * ------------- ++ * Execute the _PSx method corresponding to the target Dx state, ++ * if it exists. ++ */ ++ object_name[2] = 'S'; ++ object_name[3] = '0' + state; ++ bm_evaluate_object(device->acpi_handle, object_name, NULL, NULL); ++ ++ if (ACPI_SUCCESS(status)) { ++ DEBUG_PRINT(ACPI_INFO, ("Device [%02x] is now at [D%d].\n", device->handle, state)); ++ device->power.state = state; ++ } ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_get_pm_capabilities ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_get_pm_capabilities ( ++ BM_NODE *node) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE *device = NULL; ++ BM_DEVICE *parent_device = NULL; ++ ACPI_HANDLE acpi_handle = NULL; ++ BM_POWER_STATE dx_supported = ACPI_STATE_UNKNOWN; ++ char object_name[5] = {'_','S','0','D','\0'}; ++ u32 i = 0; ++ ++ FUNCTION_TRACE("bm_get_pm_capabilities"); ++ ++ if (!node || !node->parent) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ device = &(node->device); ++ parent_device = &(node->parent->device); ++ ++ /* ++ * Power Management Flags: ++ * ----------------------- ++ */ ++ if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_PSC", ++ &acpi_handle))) { ++ device->power.flags |= BM_FLAGS_POWER_STATE; ++ } ++ ++ if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_IRC", ++ &acpi_handle))) { ++ device->power.flags |= BM_FLAGS_INRUSH_CURRENT; ++ } ++ ++ if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_PRW", ++ &acpi_handle))) { ++ device->power.flags |= BM_FLAGS_WAKE_CAPABLE; ++ } ++ ++ /* ++ * Device Power State: ++ * ------------------- ++ * Note that we can't get the device's power state until we've ++ * initialized all power resources, so for now we just set to ++ * unknown. ++ */ ++ device->power.state = ACPI_STATE_UNKNOWN; ++ ++ /* ++ * Dx Supported in S0: ++ * ------------------- ++ * Figure out which Dx states are supported by this device for the ++ * S0 (working) state. Note that D0 and D3 are required (assumed). ++ */ ++ device->power.dx_supported[ACPI_STATE_S0] = BM_FLAGS_D0_SUPPORT | ++ BM_FLAGS_D3_SUPPORT; ++ ++ if ((ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_PR1", ++ &acpi_handle))) || ++ (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_PS1", ++ &acpi_handle)))) { ++ device->power.dx_supported[ACPI_STATE_S0] |= ++ BM_FLAGS_D1_SUPPORT; ++ } ++ ++ if ((ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_PR2", ++ &acpi_handle))) || ++ (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_PS2", ++ &acpi_handle)))) { ++ device->power.dx_supported[ACPI_STATE_S0] |= ++ BM_FLAGS_D2_SUPPORT; ++ } ++ ++ /* ++ * Dx Supported in S1-S5: ++ * ---------------------- ++ * Figure out which Dx states are supported by this device for ++ * all other Sx states. ++ */ ++ for (i = ACPI_STATE_S1; i <= ACPI_STATE_S5; i++) { ++ ++ /* ++ * D3 support is assumed (off is always possible!). ++ */ ++ device->power.dx_supported[i] = BM_FLAGS_D3_SUPPORT; ++ ++ /* ++ * Evalute _SxD: ++ * ------------- ++ * Which returns the highest (power) Dx state supported in ++ * this system (Sx) state. We convert this value to a bit ++ * mask of supported states (conceptually simpler). ++ */ ++ status = bm_evaluate_simple_integer(device->acpi_handle, ++ object_name, &dx_supported); ++ if (ACPI_SUCCESS(status)) { ++ switch (dx_supported) { ++ case 0: ++ device->power.dx_supported[i] |= ++ BM_FLAGS_D0_SUPPORT; ++ /* fall through */ ++ case 1: ++ device->power.dx_supported[i] |= ++ BM_FLAGS_D1_SUPPORT; ++ /* fall through */ ++ case 2: ++ device->power.dx_supported[i] |= ++ BM_FLAGS_D2_SUPPORT; ++ /* fall through */ ++ case 3: ++ device->power.dx_supported[i] |= ++ BM_FLAGS_D3_SUPPORT; ++ break; ++ } ++ ++ /* ++ * Validate: ++ * --------- ++ * Mask of any states that _Sx_d falsely advertises ++ * (e.g.claims D1 support but neither _PR2 or _PS2 ++ * exist). In other words, S1-S5 can't offer a Dx ++ * state that isn't supported by S0. ++ */ ++ device->power.dx_supported[i] &= ++ device->power.dx_supported[ACPI_STATE_S0]; ++ } ++ ++ object_name[2]++; ++ } ++ ++ return_ACPI_STATUS(AE_OK); ++} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/busmgr/bmpower.c linux/drivers/acpi/ospm/busmgr/bmpower.c +--- /usr/src/linux/drivers/acpi/ospm/busmgr/bmpower.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/busmgr/bmpower.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,665 @@ ++/**************************************************************************** ++ * ++ * Module Name: bmpower.c - Driver for ACPI Power Resource 'devices' ++ * $Revision: 9 $ ++ * ++ ****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * 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 ++ */ ++ ++/* ++ * TODO: ++ * ----- ++ * 1. Sequencing of power resource list transitions. ++ * 2. Global serialization of power resource transtions (see ACPI ++ * spec section 7.1.2/7.1.3). ++ * 3. Better error handling. ++ */ ++ ++ ++#include <acpi.h> ++#include "bm.h" ++#include "bmpower.h" ++ ++ ++#define _COMPONENT ACPI_POWER_CONTROL ++ MODULE_NAME ("bmpower") ++ ++ ++/**************************************************************************** ++ * Function Prototypes ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_pr_notify ( ++ BM_NOTIFY notify_type, ++ BM_HANDLE device_handle, ++ void **context); ++ ++ACPI_STATUS ++bm_pr_request ( ++ BM_REQUEST *request, ++ void *context); ++ ++ ++/**************************************************************************** ++ * Internal Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_pr_print ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_pr_print ( ++ BM_POWER_RESOURCE *pr) ++{ ++ ACPI_BUFFER buffer; ++ ++ if (!pr) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ buffer.length = 256; ++ buffer.pointer = acpi_os_callocate(buffer.length); ++ if (!buffer.pointer) { ++ return(AE_NO_MEMORY); ++ } ++ ++ acpi_get_name(pr->acpi_handle, ACPI_FULL_PATHNAME, &buffer); ++ ++ acpi_os_printf("Power Resource: found\n"); ++ ++ DEBUG_PRINT_RAW(ACPI_INFO, ("+------------------------------------------------------------\n")); ++ DEBUG_PRINT_RAW(ACPI_INFO, ("| PowerResource[%02x]:[%p] %s\n", pr->device_handle, pr->acpi_handle, buffer.pointer)); ++ DEBUG_PRINT_RAW(ACPI_INFO, ("| system_level[S%d] resource_order[%d]\n", pr->system_level, pr->resource_order)); ++ DEBUG_PRINT_RAW(ACPI_INFO, ("| state[D%d] reference_count[%d]\n", pr->state, pr->reference_count)); ++ DEBUG_PRINT_RAW(ACPI_INFO, ("+------------------------------------------------------------\n")); ++ ++ acpi_os_free(buffer.pointer); ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_pr_get_state ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_pr_get_state ( ++ BM_POWER_RESOURCE *pr) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE_STATUS device_status = BM_STATUS_UNKNOWN; ++ ++ FUNCTION_TRACE("bm_pr_get_state"); ++ ++ if (!pr) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ pr->state = ACPI_STATE_UNKNOWN; ++ ++ /* ++ * Evaluate _STA: ++ * -------------- ++ * Evalute _STA to determine whether the power resource is ON or OFF. ++ * Note that if the power resource isn't present we'll get AE_OK but ++ * an unknown status. ++ */ ++ status = bm_get_device_status(pr->device_handle, &device_status); ++ if (ACPI_FAILURE(status)) { ++ DEBUG_PRINT(ACPI_ERROR, ("Error reading status for power resource [%02x].\n", pr->device_handle)); ++ return_ACPI_STATUS(status); ++ } ++ ++ /* ++ * Mask off all bits but the first as some systems return non-standard ++ * values (e.g. 0x51). ++ */ ++ switch (device_status & 0x01) { ++ case 0: ++ DEBUG_PRINT(ACPI_INFO, ("Power resource [%02x] is OFF.\n", pr->device_handle)); ++ pr->state = ACPI_STATE_D3; ++ break; ++ case 1: ++ DEBUG_PRINT(ACPI_INFO, ("Power resource [%02x] is ON.\n", pr->device_handle)); ++ pr->state = ACPI_STATE_D0; ++ break; ++ } ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_pr_set_state ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_pr_set_state ( ++ BM_POWER_RESOURCE *pr, ++ BM_POWER_STATE target_state) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ FUNCTION_TRACE("bm_pr_set_state"); ++ ++ if (!pr) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ status = bm_pr_get_state(pr); ++ if (ACPI_FAILURE(status)) { ++ return_ACPI_STATUS(status); ++ } ++ ++ if (target_state == pr->state) { ++ DEBUG_PRINT(ACPI_INFO, ("Power resource [%02x] already at target power state [D%d].\n", pr->device_handle, pr->state)); ++ return_ACPI_STATUS(AE_OK); ++ } ++ ++ switch (target_state) { ++ ++ case ACPI_STATE_D0: ++ DEBUG_PRINT(ACPI_INFO, ("Turning power resource [%02x] ON.\n", pr->device_handle)); ++ status = bm_evaluate_object(pr->acpi_handle, "_ON", NULL, NULL); ++ break; ++ ++ case ACPI_STATE_D3: ++ DEBUG_PRINT(ACPI_INFO, ("Turning power resource [%02x] OFF.\n", pr->device_handle)); ++ status = bm_evaluate_object(pr->acpi_handle, "_OFF", NULL, NULL); ++ break; ++ ++ default: ++ status = AE_BAD_PARAMETER; ++ break; ++ } ++ ++ status = bm_pr_get_state(pr); ++ if (ACPI_FAILURE(status)) { ++ return_ACPI_STATUS(status); ++ } ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_pr_list_get_state ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_pr_list_get_state ( ++ BM_HANDLE_LIST *pr_list, ++ BM_POWER_STATE *power_state) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_POWER_RESOURCE *pr = NULL; ++ u32 i = 0; ++ ++ FUNCTION_TRACE("bm_pr_list_get_state"); ++ ++ if (!pr_list || !power_state) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ if (pr_list->count < 1) { ++ pr->state = ACPI_STATE_UNKNOWN; ++ return_ACPI_STATUS(AE_ERROR); ++ } ++ ++ (*power_state) = ACPI_STATE_D0; ++ ++ /* ++ * Calculate Current power_state: ++ * ----------------------------- ++ * The current state of a list of power resources is ON if all ++ * power resources are currently in the ON state. In other words, ++ * if any power resource in the list is OFF then the collection ++ * isn't fully ON. ++ */ ++ for (i = 0; i < pr_list->count; i++) { ++ ++ status = bm_get_device_context(pr_list->handles[i], ++ (BM_DRIVER_CONTEXT*)(&pr)); ++ if (ACPI_FAILURE(status)) { ++ DEBUG_PRINT(ACPI_WARN, ("Invalid reference to power resource [%02x].\n", pr_list->handles[i])); ++ (*power_state) = ACPI_STATE_UNKNOWN; ++ break; ++ } ++ ++ status = bm_pr_get_state(pr); ++ if (ACPI_FAILURE(status)) { ++ (*power_state) = ACPI_STATE_UNKNOWN; ++ break; ++ } ++ ++ if (pr->state != ACPI_STATE_D0) { ++ (*power_state) = pr->state; ++ break; ++ } ++ } ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_pr_list_transition ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_pr_list_transition ( ++ BM_HANDLE_LIST *current_list, ++ BM_HANDLE_LIST *target_list) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_POWER_RESOURCE *pr = NULL; ++ u32 i = 0; ++ ++ FUNCTION_TRACE("bm_pr_list_transition"); ++ ++ if (!current_list || !target_list) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Reference Target: ++ * ----------------- ++ * Reference all resources for the target power state first (so ++ * the device doesn't get turned off while transitioning). Power ++ * resources that aren't on (new reference count of 1) are turned on. ++ */ ++ for (i = 0; i < target_list->count; i++) { ++ ++ status = bm_get_device_context(target_list->handles[i], ++ (BM_DRIVER_CONTEXT*)(&pr)); ++ if (ACPI_FAILURE(status)) { ++ DEBUG_PRINT(ACPI_WARN, ("Invalid reference to power resource [%02x].\n", target_list->handles[i])); ++ continue; ++ } ++ ++ if (++pr->reference_count == 1) { ++ /* TODO: Need ordering based upon resource_order */ ++ status = bm_pr_set_state(pr, ACPI_STATE_D0); ++ if (ACPI_FAILURE(status)) { ++ /* TODO: How do we handle this? */ ++ DEBUG_PRINT(ACPI_WARN, ("Unable to change power state for power resource [%02x].\n", target_list->handles[i])); ++ } ++ } ++ } ++ ++ /* ++ * Dereference Current: ++ * -------------------- ++ * Dereference all resources for the current power state. Power ++ * resources no longer referenced (new reference count of 0) are ++ * turned off. ++ */ ++ for (i = 0; i < current_list->count; i++) { ++ ++ status = bm_get_device_context(current_list->handles[i], ++ (BM_DRIVER_CONTEXT*)(&pr)); ++ if (ACPI_FAILURE(status)) { ++ DEBUG_PRINT(ACPI_WARN, ("Invalid reference to power resource [%02x].\n", target_list->handles[i])); ++ continue; ++ } ++ ++ if (--pr->reference_count == 0) { ++ /* TODO: Need ordering based upon resource_order */ ++ status = bm_pr_set_state(pr, ACPI_STATE_D3); ++ if (ACPI_FAILURE(status)) { ++ /* TODO: How do we handle this? */ ++ DEBUG_PRINT(ACPI_ERROR, ("Unable to change power state for power resource [%02x].\n", current_list->handles[i])); ++ } ++ } ++ } ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_pr_add_device ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_pr_add_device ( ++ BM_HANDLE device_handle, ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_POWER_RESOURCE *pr = NULL; ++ BM_DEVICE *device = NULL; ++ ACPI_BUFFER buffer; ++ ACPI_OBJECT acpi_object; ++ ++ FUNCTION_TRACE("bm_pr_add_device"); ++ ++ DEBUG_PRINT(ACPI_INFO, ("Adding power resource [%02x].\n", device_handle)); ++ ++ if (!context || *context) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ buffer.length = sizeof(ACPI_OBJECT); ++ buffer.pointer = &acpi_object; ++ ++ /* ++ * Get information on this device. ++ */ ++ status = bm_get_device_info(device_handle, &device); ++ if (ACPI_FAILURE(status)) { ++ return_ACPI_STATUS(status); ++ } ++ ++ /* ++ * Allocate a new BM_POWER_RESOURCE structure. ++ */ ++ pr = acpi_os_callocate(sizeof(BM_POWER_RESOURCE)); ++ if (!pr) { ++ return_ACPI_STATUS(AE_NO_MEMORY); ++ } ++ ++ pr->device_handle = device->handle; ++ pr->acpi_handle = device->acpi_handle; ++ ++ /* ++ * Get information on this power resource. ++ */ ++ status = acpi_evaluate_object(pr->acpi_handle, NULL, NULL, &buffer); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ pr->system_level = acpi_object.power_resource.system_level; ++ pr->resource_order = acpi_object.power_resource.resource_order; ++ pr->state = ACPI_STATE_UNKNOWN; ++ pr->reference_count = 0; ++ ++ /* ++ * Get the power resource's current state (ON|OFF). ++ */ ++ status = bm_pr_get_state(pr); ++ ++end: ++ if (ACPI_FAILURE(status)) { ++ acpi_os_free(pr); ++ } ++ else { ++ *context = pr; ++ bm_pr_print(pr); ++ } ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_pr_remove_device ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_pr_remove_device ( ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_POWER_RESOURCE *pr = NULL; ++ ++ FUNCTION_TRACE("bm_pr_remove_device"); ++ ++ if (!context || !*context) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ pr = (BM_POWER_RESOURCE*)*context; ++ ++ DEBUG_PRINT(ACPI_INFO, ("Removing power resource [%02x].\n", pr->device_handle)); ++ ++ acpi_os_free(pr); ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * External Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_pr_initialize ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_pr_initialize (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE_ID criteria; ++ BM_DRIVER driver; ++ ++ FUNCTION_TRACE("bm_pr_initialize"); ++ ++ MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); ++ MEMSET(&driver, 0, sizeof(BM_DRIVER)); ++ ++ criteria.type = BM_TYPE_POWER_RESOURCE; ++ ++ driver.notify = &bm_pr_notify; ++ driver.request = &bm_pr_request; ++ ++ status = bm_register_driver(&criteria, &driver); ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_pr_terminate ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_pr_terminate (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE_ID criteria; ++ BM_DRIVER driver; ++ ++ FUNCTION_TRACE("bm_pr_terminate"); ++ ++ MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); ++ MEMSET(&driver, 0, sizeof(BM_DRIVER)); ++ ++ criteria.type = BM_TYPE_POWER_RESOURCE; ++ ++ driver.notify = &bm_pr_notify; ++ driver.request = &bm_pr_request; ++ ++ status = bm_unregister_driver(&criteria, &driver); ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_pr_notify ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_pr_notify ( ++ BM_NOTIFY notify_type, ++ BM_HANDLE device_handle, ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ FUNCTION_TRACE("bm_pr_notify"); ++ ++ switch (notify_type) { ++ ++ case BM_NOTIFY_DEVICE_ADDED: ++ status = bm_pr_add_device(device_handle, context); ++ break; ++ ++ case BM_NOTIFY_DEVICE_REMOVED: ++ status = bm_pr_remove_device(context); ++ break; ++ ++ default: ++ status = AE_SUPPORT; ++ break; ++ } ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_pr_request ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_pr_request ( ++ BM_REQUEST *request, ++ void *context) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_POWER_RESOURCE *pr = NULL; ++ ++ FUNCTION_TRACE("bm_pr_request"); ++ ++ /* ++ * Must have a valid request structure and context. ++ */ ++ if (!request || !context) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * context contains information specific to this power resource. ++ */ ++ pr = (BM_POWER_RESOURCE*)context; ++ ++ /* ++ * Handle request: ++ * --------------- ++ */ ++ switch (request->command) { ++ ++ default: ++ status = AE_SUPPORT; ++ break; ++ } ++ ++ request->status = status; ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/busmgr/bmrequest.c linux/drivers/acpi/ospm/busmgr/bmrequest.c +--- /usr/src/linux/drivers/acpi/ospm/busmgr/bmrequest.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/busmgr/bmrequest.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,164 @@ ++/****************************************************************************** ++ * ++ * Module Name: bmrequest.c ++ * $Revision: 7 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include <acpi.h> ++#include "bm.h" ++ ++#define _COMPONENT ACPI_BUS_MANAGER ++ MODULE_NAME ("bmrequest") ++ ++ ++/**************************************************************************** ++ * External Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_generate_request ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_generate_request ( ++ BM_NODE *node, ++ BM_REQUEST *request) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE *device = NULL; ++ ++ FUNCTION_TRACE("bm_generate_request"); ++ ++ if (!node || !request) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ device = &(node->device); ++ ++ if (!BM_IS_DRIVER_CONTROL(device)) { ++ DEBUG_PRINT(ACPI_WARN, ("No driver installed for device [%02x].\n", device->handle)); ++ return_ACPI_STATUS(AE_NOT_EXIST); ++ } ++ ++ status = node->driver.request(request, node->driver.context); ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_request ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_request ( ++ BM_REQUEST *request) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_NODE *node = NULL; ++ BM_DEVICE *device = NULL; ++ ++ FUNCTION_TRACE("bm_request"); ++ ++ /* ++ * Must have a valid request structure. ++ */ ++ if (!request) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ DEBUG_PRINT(ACPI_INFO, ("Received request for device [%02x] command [%02x].\n", request->handle, request->command)); ++ ++ /* ++ * Resolve the node. ++ */ ++ status = bm_get_node(request->handle, 0, &node); ++ if (ACPI_FAILURE(status)) { ++ return_ACPI_STATUS(status); ++ } ++ ++ device = &(node->device); ++ ++ /* ++ * Device-Specific Request? ++ * ------------------------ ++ * If a device-specific command (>=0x80) forward this request to ++ * the appropriate driver. ++ */ ++ if (request->command & BM_COMMAND_DEVICE_SPECIFIC) { ++ status = bm_generate_request(node, request); ++ return_ACPI_STATUS(status); ++ } ++ ++ /* ++ * Bus-Specific Requests: ++ * ---------------------- ++ */ ++ switch (request->command) { ++ ++ case BM_COMMAND_GET_POWER_STATE: ++ status = bm_get_power_state(node); ++ if (ACPI_FAILURE(status)) { ++ break; ++ } ++ status = bm_copy_to_buffer(&(request->buffer), ++ &(device->power.state), sizeof(BM_POWER_STATE)); ++ break; ++ ++ case BM_COMMAND_SET_POWER_STATE: ++ { ++ BM_POWER_STATE *power_state = NULL; ++ ++ status = bm_cast_buffer(&(request->buffer), ++ (void**)&power_state, sizeof(BM_POWER_STATE)); ++ if (ACPI_FAILURE(status)) { ++ break; ++ } ++ status = bm_set_power_state(node, *power_state); ++ } ++ break; ++ ++ default: ++ status = AE_SUPPORT; ++ request->status = AE_SUPPORT; ++ break; ++ } ++ ++ return_ACPI_STATUS(status); ++} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/busmgr/bmsearch.c linux/drivers/acpi/ospm/busmgr/bmsearch.c +--- /usr/src/linux/drivers/acpi/ospm/busmgr/bmsearch.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/busmgr/bmsearch.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,192 @@ ++/****************************************************************************** ++ * ++ * Module Name: bmsearch.c ++ * $Revision: 8 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include <acpi.h> ++#include "bm.h" ++ ++ ++#define _COMPONENT ACPI_BUS_MANAGER ++ MODULE_NAME ("bmsearch") ++ ++ ++/**************************************************************************** ++ * External Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_compare ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_compare ( ++ BM_DEVICE *device, ++ BM_DEVICE_ID *criteria) ++{ ++ if (!device || !criteria) { ++ return AE_BAD_PARAMETER; ++ } ++ ++ /* ++ * Present? ++ * -------- ++ * We're only going to match on devices that are present. ++ * TODO: Optimize in bm_search (don't have to call here). ++ */ ++ if (!BM_DEVICE_PRESENT(device)) { ++ return AE_NOT_FOUND; ++ } ++ ++ /* ++ * Type? ++ */ ++ if (criteria->type && (criteria->type != device->id.type)) { ++ return AE_NOT_FOUND; ++ } ++ ++ /* ++ * HID? ++ */ ++ if ((criteria->hid[0]) && (0 != STRNCMP(criteria->hid, ++ device->id.hid, sizeof(BM_DEVICE_HID)))) { ++ return AE_NOT_FOUND; ++ } ++ ++ /* ++ * ADR? ++ */ ++ if ((criteria->adr) && (criteria->adr != device->id.adr)) { ++ return AE_NOT_FOUND; ++ } ++ ++ return AE_OK; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_search ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: AE_BAD_PARAMETER- invalid input parameter ++ * AE_NOT_EXIST - start_device_handle doesn't exist ++ * AE_NOT_FOUND - no matches to Search_info.criteria found ++ * AE_OK - success ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_search( ++ BM_HANDLE device_handle, ++ BM_DEVICE_ID *criteria, ++ BM_HANDLE_LIST *results) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_NODE *node = NULL; ++ ++ FUNCTION_TRACE("bm_search"); ++ ++ if (!criteria || !results) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ results->count = 0; ++ ++ /* ++ * Locate Starting Point: ++ * ---------------------- ++ * Locate the node in the hierarchy where we'll begin our search. ++ */ ++ status = bm_get_node(device_handle, 0, &node); ++ if (ACPI_FAILURE(status)) { ++ return_ACPI_STATUS(status); ++ } ++ ++ /* ++ * Parse Hierarchy: ++ * ---------------- ++ * Parse through the node hierarchy looking for matches. ++ */ ++ while (node && (results->count<=BM_HANDLES_MAX)) { ++ /* ++ * Depth-first: ++ * ------------ ++ * Searches are always performed depth-first. ++ */ ++ if (node->scope.head) { ++ status = bm_compare(&(node->device), criteria); ++ if (ACPI_SUCCESS(status)) { ++ results->handles[results->count++] = ++ node->device.handle; ++ } ++ node = node->scope.head; ++ } ++ ++ /* ++ * Now Breadth: ++ * ------------ ++ * Search all peers until scope is exhausted. ++ */ ++ else { ++ status = bm_compare(&(node->device), criteria); ++ if (ACPI_SUCCESS(status)) { ++ results->handles[results->count++] = ++ node->device.handle; ++ } ++ ++ /* ++ * Locate Next Device: ++ * ------------------- ++ * The next node is either a peer at this level ++ * (node->next is valid), or we work are way back ++ * up the tree until we either find a non-parsed ++ * peer or hit the top (node->parent is NULL). ++ */ ++ while (!node->next && node->parent) { ++ node = node->parent; ++ } ++ node = node->next; ++ } ++ } ++ ++ if (results->count == 0) { ++ return_ACPI_STATUS(AE_NOT_FOUND); ++ } ++ else { ++ return_ACPI_STATUS(AE_OK); ++ } ++} ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/busmgr/bmutils.c linux/drivers/acpi/ospm/busmgr/bmutils.c +--- /usr/src/linux/drivers/acpi/ospm/busmgr/bmutils.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/busmgr/bmutils.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,608 @@ ++/***************************************************************************** ++ * ++ * Module Name: bmutils.c ++ * $Revision: 22 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include <acpi.h> ++#include "bm.h" ++ ++ ++#define _COMPONENT ACPI_BUS_MANAGER ++ MODULE_NAME ("bmutils") ++ ++ ++#ifdef ACPI_DEBUG ++#define DEBUG_EVAL_ERROR(l,h,p,s) bm_print_eval_error(l,h,p,s) ++#else ++#define DEBUG_EVAL_ERROR(l,h,p,s) ++#endif ++ ++ ++/**************************************************************************** ++ * External Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_print_eval_error ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++void ++bm_print_eval_error ( ++ u32 debug_level, ++ ACPI_HANDLE acpi_handle, ++ ACPI_STRING pathname, ++ ACPI_STATUS status) ++{ ++ ACPI_BUFFER buffer; ++ ACPI_STRING status_string = NULL; ++ ++ buffer.length = 256; ++ buffer.pointer = acpi_os_callocate(buffer.length); ++ if (!buffer.pointer) { ++ return; ++ } ++ ++ status_string = acpi_cm_format_exception(status); ++ ++ status = acpi_get_name(acpi_handle, ACPI_FULL_PATHNAME, &buffer); ++ if (ACPI_FAILURE(status)) { ++ DEBUG_PRINT(debug_level, ("Evaluate object [%p], %s\n", acpi_handle, status_string)); ++ return; ++ } ++ ++ if (pathname) { ++ DEBUG_PRINT(ACPI_INFO, ("Evaluate object [%s.%s], %s\n", buffer.pointer, pathname, status_string)); ++ } ++ else { ++ DEBUG_PRINT(ACPI_INFO, ("Evaluate object [%s], %s\n", buffer.pointer, status_string)); ++ } ++ ++ acpi_os_free(buffer.pointer); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_copy_to_buffer ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_copy_to_buffer ( ++ ACPI_BUFFER *buffer, ++ void *data, ++ u32 length) ++{ ++ FUNCTION_TRACE("bm_copy_to_buffer"); ++ ++ if (!buffer || (!buffer->pointer) || !data || (length == 0)) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ if (length > buffer->length) { ++ buffer->length = length; ++ return_ACPI_STATUS(AE_BUFFER_OVERFLOW); ++ } ++ ++ buffer->length = length; ++ MEMCPY(buffer->pointer, data, length); ++ ++ return_ACPI_STATUS(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_cast_buffer ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_cast_buffer ( ++ ACPI_BUFFER *buffer, ++ void **pointer, ++ u32 length) ++{ ++ FUNCTION_TRACE("bm_cast_buffer"); ++ ++ if (!buffer || !buffer->pointer || !pointer || length == 0) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ if (length > buffer->length) { ++ return_ACPI_STATUS(AE_BAD_DATA); ++ } ++ ++ *pointer = buffer->pointer; ++ ++ return_ACPI_STATUS(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_extract_package_data ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++/* ++ TODO: Don't assume numbers (in ASL) are 32-bit values!!!! (IA64) ++ TODO: Issue with 'assumed' types coming out of interpreter... ++ (e.g. toshiba _BIF) ++*/ ++ ++ACPI_STATUS ++bm_extract_package_data ( ++ ACPI_OBJECT *package, ++ ACPI_BUFFER *package_format, ++ ACPI_BUFFER *buffer) ++{ ++ ACPI_STATUS status = AE_OK; ++ u8 *head = NULL; ++ u8 *tail = NULL; ++ u8 **pointer = NULL; ++ u32 tail_offset = 0; ++ ACPI_OBJECT *element = NULL; ++ u32 size_required = 0; ++ char* format = NULL; ++ u32 format_count = 0; ++ u32 i = 0; ++ ++ FUNCTION_TRACE("bm_extract_package_data"); ++ ++ if (!package || (package->type != ACPI_TYPE_PACKAGE) || ++ (package->package.count == 0) || !package_format || ++ (package_format->length < 1) || ++ (!package_format->pointer) || !buffer) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ format_count = package_format->length - 1; ++ ++ if (format_count > package->package.count) { ++ DEBUG_PRINT(ACPI_WARN, ("Format specifies more objects [%d] than exist in package [%d].", format_count, package->package.count)); ++ return_ACPI_STATUS(AE_BAD_DATA); ++ } ++ ++ format = (char*)package_format->pointer; ++ ++ /* ++ * Calculate size_required. ++ */ ++ for (i=0; i<format_count; i++) { ++ element = &(package->package.elements[i]); ++ ++ switch (element->type) { ++ ++ case ACPI_TYPE_INTEGER: ++ switch (format[i]) { ++ case 'N': ++ size_required += sizeof(ACPI_INTEGER); ++ tail_offset += sizeof(ACPI_INTEGER); ++ break; ++ case 'S': ++ size_required += sizeof(u8*) + ++ sizeof(ACPI_INTEGER) + 1; ++ tail_offset += sizeof(ACPI_INTEGER); ++ break; ++ default: ++ DEBUG_PRINT(ACPI_WARN, ("Invalid package element [%d]: got number, expecing [%c].\n", i, format[i])); ++ return_ACPI_STATUS(AE_BAD_DATA); ++ break; ++ } ++ break; ++ ++ case ACPI_TYPE_STRING: ++ case ACPI_TYPE_BUFFER: ++ switch (format[i]) { ++ case 'S': ++ size_required += sizeof(u8*) + ++ element->string.length + 1; ++ tail_offset += sizeof(u8*); ++ break; ++ case 'B': ++ size_required += sizeof(u8*) + ++ element->buffer.length; ++ tail_offset += sizeof(u8*); ++ break; ++ default: ++ DEBUG_PRINT(ACPI_WARN, ("Invalid package element [%d] got string/buffer, expecing [%c].\n", i, format[i])); ++ return_ACPI_STATUS(AE_BAD_DATA); ++ break; ++ } ++ break; ++ ++ case ACPI_TYPE_PACKAGE: ++ default: ++ /* TODO: handle nested packages... */ ++ return_ACPI_STATUS(AE_SUPPORT); ++ break; ++ } ++ } ++ ++ if (size_required > buffer->length) { ++ buffer->length = size_required; ++ return_ACPI_STATUS(AE_BUFFER_OVERFLOW); ++ } ++ ++ buffer->length = size_required; ++ ++ if (!buffer->pointer) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ head = buffer->pointer; ++ tail = buffer->pointer + tail_offset; ++ ++ /* ++ * Extract package data: ++ */ ++ for (i=0; i<format_count; i++) { ++ ++ element = &(package->package.elements[i]); ++ ++ switch (element->type) { ++ ++ case ACPI_TYPE_INTEGER: ++ switch (format[i]) { ++ case 'N': ++ *((ACPI_INTEGER*)head) = ++ element->integer.value; ++ head += sizeof(ACPI_INTEGER); ++ break; ++ case 'S': ++ pointer = (u8**)head; ++ *pointer = tail; ++ *((ACPI_INTEGER*)tail) = ++ element->integer.value; ++ head += sizeof(ACPI_INTEGER*); ++ tail += sizeof(ACPI_INTEGER); ++ /* NULL terminate string */ ++ *tail = 0; ++ tail++; ++ break; ++ default: ++ /* Should never get here */ ++ break; ++ } ++ break; ++ ++ case ACPI_TYPE_STRING: ++ case ACPI_TYPE_BUFFER: ++ switch (format[i]) { ++ case 'S': ++ pointer = (u8**)head; ++ *pointer = tail; ++ memcpy(tail, element->string.pointer, ++ element->string.length); ++ head += sizeof(u8*); ++ tail += element->string.length; ++ /* NULL terminate string */ ++ *tail = 0; ++ tail++; ++ break; ++ case 'B': ++ pointer = (u8**)head; ++ *pointer = tail; ++ memcpy(tail, element->buffer.pointer, ++ element->buffer.length); ++ head += sizeof(u8*); ++ tail += element->buffer.length; ++ break; ++ default: ++ /* Should never get here */ ++ break; ++ } ++ break; ++ ++ case ACPI_TYPE_PACKAGE: ++ /* TODO: handle nested packages... */ ++ default: ++ /* Should never get here */ ++ break; ++ } ++ } ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_evaluate_object ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: AE_OK ++ * AE_BUFFER_OVERFLOW Evaluated object returned data, but ++ * caller did not provide buffer. ++ * ++ * DESCRIPTION: Helper for acpi_evaluate_object that handles buffer ++ * allocation. Note that the caller is responsible for ++ * freeing buffer->pointer! ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_evaluate_object ( ++ ACPI_HANDLE acpi_handle, ++ ACPI_STRING pathname, ++ ACPI_OBJECT_LIST *arguments, ++ ACPI_BUFFER *buffer) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ FUNCTION_TRACE("bm_evaluate_object"); ++ ++ /* If caller provided a buffer it must be unallocated/zero'd. */ ++ if ((buffer) && (buffer->length != 0 || buffer->pointer)) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Evalute Object: ++ * --------------- ++ * The first attempt is just to get the size of the object data ++ * (that is unless there's no return data, e.g. _INI); the second ++ * gets the data. ++ */ ++ status = acpi_evaluate_object(acpi_handle, pathname, arguments, buffer); ++ if (ACPI_SUCCESS(status)) { ++ return_ACPI_STATUS(status); ++ } ++ else if ((buffer) && (status == AE_BUFFER_OVERFLOW)) { ++ ++ /* Gotta allocate -- CALLER MUST FREE! */ ++ buffer->pointer = acpi_os_callocate(buffer->length); ++ if (!buffer->pointer) { ++ return_ACPI_STATUS(AE_NO_MEMORY); ++ } ++ ++ /* Re-evaluate -- this time it should work */ ++ status = acpi_evaluate_object(acpi_handle, pathname, ++ arguments, buffer); ++ } ++ ++ if (ACPI_FAILURE(status)) { ++ if (status != AE_NOT_FOUND) { ++ DEBUG_EVAL_ERROR(ACPI_WARN, acpi_handle, pathname, ++ status); ++ } ++ if (buffer && buffer->pointer) { ++ acpi_os_free(buffer->pointer); ++ buffer->pointer = NULL; ++ buffer->length = 0; ++ } ++ } ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_evaluate_simple_integer ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_evaluate_simple_integer ( ++ ACPI_HANDLE acpi_handle, ++ ACPI_STRING pathname, ++ u32 *data) ++{ ++ ACPI_STATUS status = AE_OK; ++ ACPI_OBJECT *element = NULL; ++ ACPI_BUFFER buffer; ++ ++ FUNCTION_TRACE("bm_evaluate_simple_integer"); ++ ++ if (!data) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ MEMSET(&buffer, 0, sizeof(ACPI_BUFFER)); ++ ++ /* ++ * Evaluate Object: ++ * ---------------- ++ */ ++ status = bm_evaluate_object(acpi_handle, pathname, NULL, &buffer); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ /* ++ * Validate Data: ++ * -------------- ++ */ ++ status = bm_cast_buffer(&buffer, (void**)&element, ++ sizeof(ACPI_OBJECT)); ++ if (ACPI_FAILURE(status)) { ++ DEBUG_EVAL_ERROR(ACPI_WARN, acpi_handle, pathname, status); ++ goto end; ++ } ++ ++ if (element->type != ACPI_TYPE_INTEGER) { ++ status = AE_BAD_DATA; ++ DEBUG_EVAL_ERROR(ACPI_WARN, acpi_handle, pathname, status); ++ goto end; ++ } ++ ++ *data = element->integer.value; ++ ++end: ++ acpi_os_free(buffer.pointer); ++ ++ return_ACPI_STATUS(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bm_evaluate_reference_list ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bm_evaluate_reference_list ( ++ ACPI_HANDLE acpi_handle, ++ ACPI_STRING pathname, ++ BM_HANDLE_LIST *reference_list) ++{ ++ ACPI_STATUS status = AE_OK; ++ ACPI_OBJECT *package = NULL; ++ ACPI_OBJECT *element = NULL; ++ ACPI_HANDLE reference_handle = NULL; ++ ACPI_BUFFER buffer; ++ u32 i = 0; ++ ++ FUNCTION_TRACE("bm_evaluate_reference_list"); ++ ++ if (!reference_list) { ++ return_ACPI_STATUS(AE_BAD_PARAMETER); ++ } ++ ++ MEMSET(&buffer, 0, sizeof(ACPI_BUFFER)); ++ ++ /* ++ * Evaluate Object: ++ * ---------------- ++ */ ++ status = bm_evaluate_object(acpi_handle, pathname, NULL, &buffer); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ /* ++ * Validate Package: ++ * ----------------- ++ */ ++ status = bm_cast_buffer(&buffer, (void**)&package, ++ sizeof(ACPI_OBJECT)); ++ if (ACPI_FAILURE(status)) { ++ DEBUG_EVAL_ERROR(ACPI_WARN, acpi_handle, pathname, status); ++ goto end; ++ } ++ ++ if (package->type != ACPI_TYPE_PACKAGE) { ++ status = AE_BAD_DATA; ++ DEBUG_EVAL_ERROR(ACPI_WARN, acpi_handle, pathname, status); ++ goto end; ++ } ++ ++ if (package->package.count > BM_HANDLES_MAX) { ++ package->package.count = BM_HANDLES_MAX; ++ } ++ ++ /* ++ * Parse Package Data: ++ * ------------------- ++ */ ++ for (i = 0; i < package->package.count; i++) { ++ ++ element = &(package->package.elements[i]); ++ ++ if (!element || (element->type != ACPI_TYPE_STRING)) { ++ status = AE_BAD_DATA; ++ DEBUG_PRINT(ACPI_WARN, ("Invalid element in package (not a device reference).\n")); ++ DEBUG_EVAL_ERROR(ACPI_WARN, acpi_handle, pathname, status); ++ break; ++ } ++ ++ /* ++ * Resolve reference string (e.g. "\_PR_.CPU_") to an ++ * ACPI_HANDLE. ++ */ ++ status = acpi_get_handle(acpi_handle, ++ element->string.pointer, &reference_handle); ++ if (ACPI_FAILURE(status)) { ++ status = AE_BAD_DATA; ++ DEBUG_PRINT(ACPI_WARN, ("Unable to resolve device reference [%s].\n", element->string.pointer)); ++ DEBUG_EVAL_ERROR(ACPI_WARN, acpi_handle, pathname, status); ++ break; ++ } ++ ++ /* ++ * Resolve ACPI_HANDLE to BM_HANDLE. ++ */ ++ status = bm_get_handle(reference_handle, ++ &(reference_list->handles[i])); ++ if (ACPI_FAILURE(status)) { ++ status = AE_BAD_DATA; ++ DEBUG_PRINT(ACPI_WARN, ("Unable to resolve device reference for [%p].\n", reference_handle)); ++ DEBUG_EVAL_ERROR(ACPI_WARN, acpi_handle, pathname, status); ++ break; ++ } ++ ++ DEBUG_PRINT(ACPI_INFO, ("Resolved reference [%s]->[%p]->[%02x]\n", element->string.pointer, reference_handle, reference_list->handles[i])); ++ ++ (reference_list->count)++; ++ } ++ ++end: ++ acpi_os_free(buffer.pointer); ++ ++ return_ACPI_STATUS(status); ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/button/Makefile linux/drivers/acpi/ospm/button/Makefile +--- /usr/src/linux/drivers/acpi/ospm/button/Makefile Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/button/Makefile Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,23 @@ ++# ++# Makefile for all Linux ACPI interpreter subdirectories ++# ++ ++O_TARGET := ../$(shell basename `pwd`).o ++ ++EXTRA_CFLAGS += -I../../include -I../include ++ ++EXTRA_CFLAGS += $(ACPI_CFLAGS) ++ ++list-multi := button.o ++button-objs := $(patsubst %.c,%.o,$(wildcard *.c)) ++ ++obj-$(CONFIG_ACPI_BUTTON) := button.o ++ ++include $(TOPDIR)/Rules.make ++ ++clean: ++ $(RM) *.o ++ ++button.o: $(button-objs) ++ $(LD) -r -o $@ $(button-objs) ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/button/bn.c linux/drivers/acpi/ospm/button/bn.c +--- /usr/src/linux/drivers/acpi/ospm/button/bn.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/button/bn.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,440 @@ ++/***************************************************************************** ++ * ++ * Module Name: bn.c ++ * $Revision: 20 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * 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 Plxxe, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include <acpi.h> ++#include "bn.h" ++ ++ ++#define _COMPONENT ACPI_BUTTON ++ MODULE_NAME ("bn") ++ ++ ++/***************************************************************************** ++ * Internal Functions ++ *****************************************************************************/ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: bn_print ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: Prints out information on a specific button. ++ * ++ ****************************************************************************/ ++ ++void ++bn_print ( ++ BN_CONTEXT *button) ++{ ++ ++ return; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bn_add_device ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bn_add_device( ++ BM_HANDLE device_handle, ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE *device = NULL; ++ BN_CONTEXT *button = NULL; ++ ++ if (!context || *context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Get information on this device. ++ */ ++ status = bm_get_device_info( device_handle, &device ); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ /* ++ * Allocate a new BN_CONTEXT structure. ++ */ ++ button = acpi_os_callocate(sizeof(BN_CONTEXT)); ++ if (!button) { ++ return(AE_NO_MEMORY); ++ } ++ ++ button->device_handle = device->handle; ++ button->acpi_handle = device->acpi_handle; ++ ++ /* ++ * Power Button? ++ * ------------- ++ * Either fixed-feature or generic (namespace) types. ++ */ ++ if (strncmp(device->id.hid, BN_HID_POWER_BUTTON, ++ sizeof(BM_DEVICE_HID)) == 0) { ++ ++ if (device->id.type == BM_TYPE_FIXED_BUTTON) { ++ ++ button->type = BN_TYPE_POWER_BUTTON_FIXED; ++ ++ /* Register for fixed-feature events. */ ++ status = acpi_install_fixed_event_handler( ++ ACPI_EVENT_POWER_BUTTON, bn_notify_fixed, ++ (void*)button); ++ } ++ else { ++ button->type = BN_TYPE_POWER_BUTTON; ++ } ++ ++ } ++ ++ /* ++ * Sleep Button? ++ * ------------- ++ * Either fixed-feature or generic (namespace) types. ++ */ ++ else if (strncmp( device->id.hid, BN_HID_SLEEP_BUTTON, ++ sizeof(BM_DEVICE_HID)) == 0) { ++ ++ if (device->id.type == BM_TYPE_FIXED_BUTTON) { ++ ++ button->type = BN_TYPE_SLEEP_BUTTON_FIXED; ++ ++ /* Register for fixed-feature events. */ ++ status = acpi_install_fixed_event_handler( ++ ACPI_EVENT_SLEEP_BUTTON, bn_notify_fixed, ++ (void*)button); ++ } ++ else { ++ button->type = BN_TYPE_SLEEP_BUTTON; ++ } ++ } ++ ++ /* ++ * LID Switch? ++ * ----------- ++ */ ++ else if (strncmp( device->id.hid, BN_HID_LID_SWITCH, ++ sizeof(BM_DEVICE_HID)) == 0) { ++ button->type = BN_TYPE_LID_SWITCH; ++ } ++ ++ status = bn_osl_add_device(button); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ *context = button; ++ ++ bn_print(button); ++ ++end: ++ if (ACPI_FAILURE(status)) { ++ acpi_os_free(button); ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bn_remove_device ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bn_remove_device( ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ BN_CONTEXT *button = NULL; ++ ++ if (!context || !*context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ button = (BN_CONTEXT*)*context; ++ ++ /* ++ * Unregister for fixed-feature events. ++ */ ++ switch (button->type) { ++ case BN_TYPE_POWER_BUTTON_FIXED: ++ status = acpi_remove_fixed_event_handler( ++ ACPI_EVENT_POWER_BUTTON, bn_notify_fixed); ++ break; ++ case BN_TYPE_SLEEP_BUTTON_FIXED: ++ status = acpi_remove_fixed_event_handler( ++ ACPI_EVENT_SLEEP_BUTTON, bn_notify_fixed); ++ break; ++ } ++ ++ bn_osl_remove_device(button); ++ ++ acpi_os_free(button); ++ ++ *context = NULL; ++ ++ return(status); ++} ++ ++ ++/***************************************************************************** ++ * External Functions ++ *****************************************************************************/ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: bn_initialize ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bn_initialize (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE_ID criteria; ++ BM_DRIVER driver; ++ ++ MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); ++ MEMSET(&driver, 0, sizeof(BM_DRIVER)); ++ ++ driver.notify = &bn_notify; ++ driver.request = &bn_request; ++ ++ /* ++ * Register for power buttons. ++ */ ++ MEMCPY(criteria.hid, BN_HID_POWER_BUTTON, sizeof(BN_HID_POWER_BUTTON)); ++ status = bm_register_driver(&criteria, &driver); ++ ++ /* ++ * Register for sleep buttons. ++ */ ++ MEMCPY(criteria.hid, BN_HID_SLEEP_BUTTON, sizeof(BN_HID_SLEEP_BUTTON)); ++ status = bm_register_driver(&criteria, &driver); ++ ++ /* ++ * Register for LID switches. ++ */ ++ MEMCPY(criteria.hid, BN_HID_LID_SWITCH, sizeof(BN_HID_LID_SWITCH)); ++ status = bm_register_driver(&criteria, &driver); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bn_terminate ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bn_terminate (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE_ID criteria; ++ BM_DRIVER driver; ++ ++ MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); ++ MEMSET(&driver, 0, sizeof(BM_DRIVER)); ++ ++ driver.notify = &bn_notify; ++ driver.request = &bn_request; ++ ++ /* ++ * Unregister for power buttons. ++ */ ++ MEMCPY(criteria.hid, BN_HID_POWER_BUTTON, sizeof(BN_HID_POWER_BUTTON)); ++ status = bm_unregister_driver(&criteria, &driver); ++ ++ /* ++ * Unregister for sleep buttons. ++ */ ++ MEMCPY(criteria.hid, BN_HID_SLEEP_BUTTON, sizeof(BN_HID_SLEEP_BUTTON)); ++ status = bm_unregister_driver(&criteria, &driver); ++ ++ /* ++ * Unregister for LID switches. ++ */ ++ MEMCPY(criteria.hid, BN_HID_LID_SWITCH, sizeof(BN_HID_LID_SWITCH)); ++ status = bm_unregister_driver(&criteria, &driver); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bn_notify_fixed ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bn_notify_fixed ( ++ void *context) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ status = bn_osl_generate_event(BN_NOTIFY_STATUS_CHANGE, ++ ((BN_CONTEXT*)context)); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bn_notify ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bn_notify ( ++ BM_NOTIFY notify_type, ++ BM_HANDLE device_handle, ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ switch (notify_type) { ++ case BM_NOTIFY_DEVICE_ADDED: ++ status = bn_add_device(device_handle, context); ++ break; ++ ++ case BM_NOTIFY_DEVICE_REMOVED: ++ status = bn_remove_device(context); ++ break; ++ ++ case BN_NOTIFY_STATUS_CHANGE: ++ status = bn_osl_generate_event(BN_NOTIFY_STATUS_CHANGE, ++ ((BN_CONTEXT*)*context)); ++ break; ++ ++ default: ++ status = AE_SUPPORT; ++ break; ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bn_request ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bn_request ( ++ BM_REQUEST *request, ++ void *context) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ /* ++ * Must have a valid request structure and context. ++ */ ++ if (!request || !context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Handle Request: ++ * --------------- ++ */ ++ switch (request->command) { ++ ++ default: ++ status = AE_SUPPORT; ++ break; ++ } ++ ++ request->status = status; ++ ++ return(status); ++} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/button/bn_osl.c linux/drivers/acpi/ospm/button/bn_osl.c +--- /usr/src/linux/drivers/acpi/ospm/button/bn_osl.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/button/bn_osl.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,244 @@ ++/****************************************************************************** ++ * ++ * Module Name: bn_osl.c ++ * $Revision: 10 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/types.h> ++#include <linux/proc_fs.h> ++#include <acpi.h> ++#include "bn.h" ++ ++ ++MODULE_AUTHOR("Andrew Grover"); ++MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Button Driver"); ++ ++ ++#define BN_PROC_ROOT "button" ++#define BN_PROC_POWER_BUTTON "power" ++#define BN_PROC_SLEEP_BUTTON "sleep" ++#define BN_PROC_LID_SWITCH "lid" ++ ++extern struct proc_dir_entry *bm_proc_root; ++static struct proc_dir_entry *bn_proc_root = NULL; ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bn_osl_add_device ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bn_osl_add_device( ++ BN_CONTEXT *button) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!button) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ switch (button->type) { ++ ++ case BN_TYPE_POWER_BUTTON: ++ case BN_TYPE_POWER_BUTTON_FIXED: ++ printk(KERN_INFO "Power Button: found\n"); ++ if (!proc_mkdir(BN_PROC_POWER_BUTTON, bn_proc_root)) { ++ status = AE_ERROR; ++ } ++ break; ++ ++ case BN_TYPE_SLEEP_BUTTON: ++ case BN_TYPE_SLEEP_BUTTON_FIXED: ++ printk(KERN_INFO "Sleep Button: found\n"); ++ if (!proc_mkdir(BN_PROC_SLEEP_BUTTON, bn_proc_root)) { ++ status = AE_ERROR; ++ } ++ break; ++ ++ case BN_TYPE_LID_SWITCH: ++ printk(KERN_INFO "Lid Switch: found\n"); ++ if (!proc_mkdir(BN_PROC_LID_SWITCH, bn_proc_root)) { ++ status = AE_ERROR; ++ } ++ break; ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bn_osl_remove_device ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bn_osl_remove_device ( ++ BN_CONTEXT *button) ++{ ++ if (!button) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ switch (button->type) { ++ ++ case BN_TYPE_POWER_BUTTON: ++ case BN_TYPE_POWER_BUTTON_FIXED: ++ remove_proc_entry(BN_PROC_POWER_BUTTON, bn_proc_root); ++ break; ++ ++ case BN_TYPE_SLEEP_BUTTON: ++ case BN_TYPE_SLEEP_BUTTON_FIXED: ++ remove_proc_entry(BN_PROC_SLEEP_BUTTON, bn_proc_root); ++ break; ++ ++ case BN_TYPE_LID_SWITCH: ++ remove_proc_entry(BN_PROC_LID_SWITCH, bn_proc_root); ++ break; ++ } ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bn_osl_generate_event ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++bn_osl_generate_event ( ++ u32 event, ++ BN_CONTEXT *button) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!button) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ switch (event) { ++ ++ case BN_NOTIFY_STATUS_CHANGE: ++ ++ switch(button->type) { ++ ++ case BN_TYPE_POWER_BUTTON: ++ case BN_TYPE_POWER_BUTTON_FIXED: ++ status = bm_osl_generate_event(button->device_handle, ++ BN_PROC_ROOT, BN_PROC_POWER_BUTTON, event, 0); ++ break; ++ ++ case BN_TYPE_SLEEP_BUTTON: ++ case BN_TYPE_SLEEP_BUTTON_FIXED: ++ status = bm_osl_generate_event(button->device_handle, ++ BN_PROC_ROOT, BN_PROC_SLEEP_BUTTON, event, 0); ++ break; ++ ++ case BN_TYPE_LID_SWITCH: ++ status = bm_osl_generate_event(button->device_handle, ++ BN_PROC_ROOT, BN_PROC_LID_SWITCH, event, 0); ++ break; ++ ++ default: ++ status = AE_SUPPORT; ++ break; ++ } ++ ++ break; ++ ++ default: ++ return(AE_BAD_PARAMETER); ++ break; ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bn_osl_init ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: 0: Success ++ * ++ * DESCRIPTION: Module initialization. ++ * ++ ****************************************************************************/ ++ ++static int __init ++bn_osl_init (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ bn_proc_root = proc_mkdir(BN_PROC_ROOT, bm_proc_root); ++ if (!bn_proc_root) { ++ status = AE_ERROR; ++ } ++ else { ++ status = bn_initialize(); ++ if (ACPI_FAILURE(status)) { ++ remove_proc_entry(BN_PROC_ROOT, bm_proc_root); ++ } ++ } ++ ++ return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: bn_osl_cleanup ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <none> ++ * ++ * DESCRIPTION: Module cleanup. ++ * ++ ****************************************************************************/ ++ ++static void __exit ++bn_osl_cleanup (void) ++{ ++ bn_terminate(); ++ ++ if (bn_proc_root) { ++ remove_proc_entry(BN_PROC_ROOT, bm_proc_root); ++ } ++ ++ return; ++} ++ ++ ++module_init(bn_osl_init); ++module_exit(bn_osl_cleanup); +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/ec/Makefile linux/drivers/acpi/ospm/ec/Makefile +--- /usr/src/linux/drivers/acpi/ospm/ec/Makefile Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/ec/Makefile Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,23 @@ ++# ++# Makefile for all Linux ACPI interpreter subdirectories ++# ++ ++O_TARGET := ../$(shell basename `pwd`).o ++ ++EXTRA_CFLAGS += -I../../include -I../include ++ ++EXTRA_CFLAGS += $(ACPI_CFLAGS) ++ ++list-multi := ec.o ++ec-objs := $(patsubst %.c,%.o,$(wildcard *.c)) ++ ++obj-$(CONFIG_ACPI_EC) := ec.o ++ ++include $(TOPDIR)/Rules.make ++ ++clean: ++ $(RM) *.o ++ ++ec.o: $(ec-objs) ++ $(LD) -r -o $@ $(ec-objs) ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/ec/ec_osl.c linux/drivers/acpi/ospm/ec/ec_osl.c +--- /usr/src/linux/drivers/acpi/ospm/ec/ec_osl.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/ec/ec_osl.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,85 @@ ++/***************************************************************************** ++ * ++ * Module Name: ec_osl.c ++ * $Revision: 3 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/types.h> ++#include <linux/proc_fs.h> ++#include <acpi.h> ++#include <bm.h> ++#include "ec.h" ++ ++ ++MODULE_AUTHOR("Andrew Grover"); ++MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Embedded Controller Driver"); ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_osl_init ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: 0: Success ++ * ++ * DESCRIPTION: Module initialization. ++ * ++ ****************************************************************************/ ++ ++static int __init ++ec_osl_init (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ status = ec_initialize(); ++ ++ return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; ++} ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_osl_cleanup ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <none> ++ * ++ * DESCRIPTION: Module cleanup. ++ * ++ ****************************************************************************/ ++ ++static void __exit ++ec_osl_cleanup(void) ++{ ++ ec_terminate(); ++ ++ return; ++} ++ ++ ++module_init(ec_osl_init); ++module_exit(ec_osl_cleanup); +\ No newline at end of file +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/ec/ecgpe.c linux/drivers/acpi/ospm/ec/ecgpe.c +--- /usr/src/linux/drivers/acpi/ospm/ec/ecgpe.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/ec/ecgpe.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,230 @@ ++/***************************************************************************** ++ * ++ * Module Name: ecgpe.c ++ * $Revision: 20 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include <acpi.h> ++#include "ec.h" ++ ++#define _COMPONENT ACPI_EMBEDDED_CONTROLLER ++ MODULE_NAME ("ecgpe") ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_query_handler ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++void ++ec_query_handler ( ++ void *context) ++{ ++ EC_CONTEXT *ec = (EC_CONTEXT*)context; ++ static char object_name[5] = {'_','Q','0','0','\0'}; ++ const char hex[] = {'0','1','2','3','4','5','6','7','8', ++ '9','A','B','C','D','E','F'}; ++ ++ if (!ec) { ++ return; ++ } ++ ++ /* ++ * Evaluate _Qxx: ++ * -------------- ++ * Evaluate corresponding _Qxx method. Note that a zero query value ++ * indicates a spurious EC_SCI (no such thing as _Q00). ++ */ ++ object_name[2] = hex[((ec->query_data >> 4) & 0x0F)]; ++ object_name[3] = hex[(ec->query_data & 0x0F)]; ++ ++ bm_evaluate_object(ec->acpi_handle, object_name, NULL, NULL); ++ ++ return; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_gpe_handler ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++void ++ec_gpe_handler ( ++ void *context) ++{ ++ ACPI_STATUS status = AE_OK; ++ EC_CONTEXT *ec = (EC_CONTEXT*)context; ++ EC_STATUS ec_status = 0; ++ ++ if (!ec) { ++ return; ++ } ++ ++ /* TODO: synchronize w/ transaction (ectransx). */ ++ ++ /* ++ * EC_SCI? ++ * ------- ++ * Check the EC_SCI bit to see if this is an EC_SCI event. If not (e.g. ++ * OBF/IBE) just return, as we already poll to detect these events. ++ */ ++ ec_status = acpi_os_in8(ec->status_port); ++ if (!(ec_status & EC_FLAG_SCI)) { ++ return; ++ } ++ ++ /* ++ * Run Query: ++ * ---------- ++ * Query the EC to find out which _Qxx method we need to evaluate. ++ * Note that successful completion of the query causes the EC_SCI ++ * bit to be cleared (and thus clearing the interrupt source). ++ */ ++ status = ec_io_write(ec, ec->command_port, EC_COMMAND_QUERY, ++ EC_EVENT_OUTPUT_BUFFER_FULL); ++ if (ACPI_FAILURE(status)) { ++ return; ++ } ++ ++ status = ec_io_read(ec, ec->data_port, &(ec->query_data), ++ EC_EVENT_NONE); ++ if (ACPI_FAILURE(status)) { ++ return; ++ } ++ ++ // TODO: un-synchronize w/ transaction (ectransx). ++ ++ /* ++ * Spurious EC_SCI? ++ * ---------------- ++ */ ++ if (!ec->query_data) { ++ return; ++ } ++ ++ /* ++ * Defer _Qxx Execution: ++ * --------------------- ++ * Can't evaluate this method now 'cause we're at interrupt-level. ++ */ ++ status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, ++ ec_query_handler, ec); ++ if (ACPI_FAILURE(status)) { ++ return; ++ } ++ ++ return; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_install_gpe_handler ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ec_install_gpe_handler ( ++ EC_CONTEXT *ec) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!ec) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Evaluate _GPE: ++ * -------------- ++ * Evaluate the "_GPE" object (required) to find out which GPE bit ++ * is used by this EC to signal events (SCIs). ++ */ ++ status = bm_evaluate_simple_integer(ec->acpi_handle, ++ "_GPE", &(ec->gpe_bit)); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ /* ++ * Install GPE Handler: ++ * -------------------- ++ * Install a handler for this EC's GPE bit. ++ */ ++ status = acpi_install_gpe_handler(ec->gpe_bit, ACPI_EVENT_EDGE_TRIGGERED, ++ &ec_gpe_handler, ec); ++ if (ACPI_FAILURE(status)) { ++ ec->gpe_bit = EC_GPE_UNKNOWN; ++ return(status); ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_remove_gpe_handler ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ec_remove_gpe_handler ( ++ EC_CONTEXT *ec) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!ec) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ status = acpi_remove_gpe_handler(ec->gpe_bit, &ec_gpe_handler); ++ ++ return(status); ++} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/ec/ecmain.c linux/drivers/acpi/ospm/ec/ecmain.c +--- /usr/src/linux/drivers/acpi/ospm/ec/ecmain.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/ec/ecmain.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,452 @@ ++/***************************************************************************** ++ * ++ * Module Name: ecmain.c ++ * $Revision: 22 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include <acpi.h> ++#include "ec.h" ++ ++#define _COMPONENT ACPI_EMBEDDED_CONTROLLER ++ MODULE_NAME ("ecmain") ++ ++ ++/**************************************************************************** ++ * Internal Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_print ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: Prints out information on a specific ec. ++ * ++ ****************************************************************************/ ++ ++void ++ec_print ( ++ EC_CONTEXT *ec) ++{ ++ ++ if (!ec) { ++ return; ++ } ++ ++ acpi_os_printf("EC: found, GPE %d\n", ec->gpe_bit); ++ ++ ++ return; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_get_port_values ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: Evaluate _CRS to get the current resources (I/O port ++ * addresses) for this EC. ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ec_get_port_values( ++ EC_CONTEXT *ec) ++{ ++ ACPI_STATUS status = AE_OK; ++ ACPI_BUFFER buffer; ++ RESOURCE *resource = NULL; ++ ++ if (!ec) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ buffer.length = 0; ++ buffer.pointer = NULL; ++ ++ status = acpi_get_current_resources(ec->acpi_handle, &buffer); ++ if (status != AE_BUFFER_OVERFLOW) { ++ return(status); ++ } ++ ++ buffer.pointer = acpi_os_callocate(buffer.length); ++ if (!buffer.pointer) { ++ return(AE_NO_MEMORY); ++ } ++ ++ status = acpi_get_current_resources(ec->acpi_handle, &buffer); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ resource = (RESOURCE *) buffer.pointer; ++ ec->data_port = resource->data.io.min_base_address; ++ ++ resource = NEXT_RESOURCE(resource); ++ ++ ec->status_port = ec->command_port = ++ resource->data.io.min_base_address; ++end: ++ acpi_os_free(buffer.pointer); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_add_device ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ec_add_device( ++ BM_HANDLE device_handle, ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE *device = NULL; ++ EC_CONTEXT *ec = NULL; ++ u8 gpe_handler = FALSE; ++ u8 space_handler = FALSE; ++ ++ if (!context || *context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Get information on this device. ++ */ ++ status = bm_get_device_info(device_handle, &device); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ /* ++ * Allocate a new EC_CONTEXT structure. ++ */ ++ ec = acpi_os_callocate(sizeof(EC_CONTEXT)); ++ if (!ec) { ++ return(AE_NO_MEMORY); ++ } ++ ++ ec->device_handle = device->handle; ++ ec->acpi_handle = device->acpi_handle; ++ ++ /* ++ * Get the I/O port addresses for the command/status and data ports. ++ */ ++ status = ec_get_port_values(ec); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ /* ++ * See if we need to obtain the global lock for EC transactions. ++ */ ++ status = bm_evaluate_simple_integer(ec->acpi_handle, "_GLK", ++ &ec->use_global_lock); ++ if (status == AE_NOT_FOUND) { ++ ec->use_global_lock = 0; ++ } ++ else if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ /* ++ * Install a handler for servicing this EC's GPE. ++ */ ++ status = ec_install_gpe_handler(ec); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ else { ++ gpe_handler = TRUE; ++ } ++ ++ /* ++ * Install a handler for servicing this EC's address space. ++ */ ++ status = ec_install_space_handler(ec); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ else { ++ space_handler = TRUE; ++ } ++ ++ /* ++ * Create a semaphore to serialize EC transactions. ++ */ ++ status = acpi_os_create_semaphore(1,1, &(ec->mutex)); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ /* ++ * Context now contains information specific to this EC. Note ++ * that we'll get this pointer back on every ec_request() and ++ * ec_notify(). ++ */ ++ *context = ec; ++ ++ ec_print(ec); ++ ++end: ++ if (ACPI_FAILURE(status)) { ++ ++ if (gpe_handler) { ++ ec_remove_gpe_handler(ec); ++ } ++ ++ if (space_handler) { ++ ec_remove_space_handler(ec); ++ } ++ ++ if (ec->mutex) { ++ acpi_os_delete_semaphore(ec->mutex); ++ } ++ ++ acpi_os_free(ec); ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_remove_device ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ec_remove_device( ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ EC_CONTEXT *ec = NULL; ++ ++ if (!context || !*context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ ec = (EC_CONTEXT*)*context; ++ ++ ec_remove_space_handler(ec); ++ ++ ec_remove_gpe_handler(ec); ++ ++ if (ec->mutex) { ++ acpi_os_delete_semaphore(ec->mutex); ++ } ++ ++ acpi_os_free(ec); ++ ++ *context = NULL; ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * External Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_initialize ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ec_initialize (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE_ID criteria; ++ BM_DRIVER driver; ++ ++ MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); ++ MEMSET(&driver, 0, sizeof(BM_DRIVER)); ++ ++ /* ++ * Register driver for AC Adapter devices. ++ */ ++ MEMCPY(criteria.hid, EC_HID_EC, sizeof(EC_HID_EC)); ++ ++ driver.notify = &ec_notify; ++ driver.request = &ec_request; ++ ++ status = bm_register_driver(&criteria, &driver); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_terminate ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ec_terminate(void) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE_ID criteria; ++ BM_DRIVER driver; ++ ++ MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); ++ MEMSET(&driver, 0, sizeof(BM_DRIVER)); ++ ++ /* ++ * Unregister driver for AC Adapter devices. ++ */ ++ MEMCPY(criteria.hid, EC_HID_EC, sizeof(EC_HID_EC)); ++ ++ driver.notify = &ec_notify; ++ driver.request = &ec_request; ++ ++ status = bm_unregister_driver(&criteria, &driver); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_notify ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ec_notify ( ++ BM_NOTIFY notify, ++ BM_HANDLE device_handle, ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ switch (notify) { ++ ++ case BM_NOTIFY_DEVICE_ADDED: ++ status = ec_add_device(device_handle, context); ++ break; ++ ++ case BM_NOTIFY_DEVICE_REMOVED: ++ status = ec_remove_device(context); ++ break; ++ ++ default: ++ status = AE_SUPPORT; ++ break; ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_request ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ec_request ( ++ BM_REQUEST *request, ++ void *context) ++{ ++ ACPI_STATUS status = AE_OK; ++ EC_REQUEST *ec_request = NULL; ++ EC_CONTEXT *ec = NULL; ++ ++ /* ++ * Must have a valid request structure and context. ++ */ ++ if (!request || !context) ++ return(AE_BAD_PARAMETER); ++ ++ /* ++ * buffer must contain a valid EC_REQUEST structure. ++ */ ++ status = bm_cast_buffer(&(request->buffer), (void**)&ec_request, ++ sizeof(EC_REQUEST)); ++ if (ACPI_FAILURE(status)) ++ return(status); ++ ++ /* ++ * context contains information specific to this EC. ++ */ ++ ec = (EC_CONTEXT*)context; ++ ++ /* ++ * Perform the Transaction. ++ */ ++ status = ec_transaction(ec, ec_request); ++ ++ return(status); ++} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/ec/ecspace.c linux/drivers/acpi/ospm/ec/ecspace.c +--- /usr/src/linux/drivers/acpi/ospm/ec/ecspace.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/ec/ecspace.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,185 @@ ++/***************************************************************************** ++ * ++ * Module Name: ecspace.c ++ * $Revision: 14 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include <acpi.h> ++#include "ec.h" ++ ++#define _COMPONENT ACPI_EMBEDDED_CONTROLLER ++ MODULE_NAME ("ecspace") ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_space_setup ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ec_space_setup ( ++ ACPI_HANDLE region_handle, ++ u32 function, ++ void *handler_context, ++ void **return_context) ++{ ++ /* ++ * The EC object is in the handler context and is needed ++ * when calling the ec_space_handler. ++ */ ++ *return_context = handler_context; ++ ++ return AE_OK; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_space_handler ++ * ++ * PARAMETERS: function - Read or Write operation ++ * address - Where in the space to read or write ++ * bit_width - Field width in bits (8, 16, or 32) ++ * value - Pointer to in or out value ++ * context - context pointer ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: Handler for the Embedded Controller (EC) address space ++ * (Op Region) ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ec_space_handler ( ++ u32 function, ++ ACPI_PHYSICAL_ADDRESS address, ++ u32 bit_width, ++ u32 *value, ++ void *handler_context, ++ void *region_context) ++{ ++ ACPI_STATUS status = AE_OK; ++ EC_CONTEXT *ec = NULL; ++ EC_REQUEST ec_request; ++ ++ if (address > 0xFF || bit_width != 8 || !value || !handler_context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ ec = (EC_CONTEXT*)handler_context; ++ ++ switch (function) { ++ ++ case ADDRESS_SPACE_READ: ++ ec_request.command = EC_COMMAND_READ; ++ ec_request.address = address; ++ ec_request.data = 0; ++ break; ++ ++ case ADDRESS_SPACE_WRITE: ++ ec_request.command = EC_COMMAND_WRITE; ++ ec_request.address = address; ++ ec_request.data = (u8)(*value); ++ break; ++ ++ default: ++ return(AE_BAD_PARAMETER); ++ break; ++ } ++ ++ /* ++ * Perform the Transaction. ++ */ ++ status = ec_transaction(ec, &ec_request); ++ if (ACPI_SUCCESS(status)) { ++ (*value) = (u32)ec_request.data; ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_install_space_handler ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ec_install_space_handler ( ++ EC_CONTEXT *ec) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!ec) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ status = acpi_install_address_space_handler (ec->acpi_handle, ++ ADDRESS_SPACE_EC, &ec_space_handler, &ec_space_setup, ec); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_remove_space_handler ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ec_remove_space_handler ( ++ EC_CONTEXT *ec) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!ec) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ status = acpi_remove_address_space_handler(ec->acpi_handle, ++ ADDRESS_SPACE_EC, &ec_space_handler); ++ ++ return(status); ++} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/ec/ectransx.c linux/drivers/acpi/ospm/ec/ectransx.c +--- /usr/src/linux/drivers/acpi/ospm/ec/ectransx.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/ec/ectransx.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,326 @@ ++/***************************************************************************** ++ * ++ * Module Name: ectransx.c ++ * $Revision: 16 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include <acpi.h> ++#include "ec.h" ++ ++#define _COMPONENT ACPI_EMBEDDED_CONTROLLER ++ MODULE_NAME ("ectransx") ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_io_wait ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ec_io_wait ( ++ EC_CONTEXT *ec, ++ EC_EVENT wait_event) ++{ ++ EC_STATUS ec_status = 0; ++ u32 i = 100; ++ ++ if (!ec || ((wait_event != EC_EVENT_OUTPUT_BUFFER_FULL) ++ && (wait_event != EC_EVENT_INPUT_BUFFER_EMPTY))) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Wait for Event: ++ * --------------- ++ * Poll the EC status register waiting for the event to occur. ++ * Note that we'll wait a maximum of 1ms in 10us chunks. ++ */ ++ switch (wait_event) { ++ ++ case EC_EVENT_OUTPUT_BUFFER_FULL: ++ do { ++ ec_status = acpi_os_in8(ec->status_port); ++ if (ec_status & EC_FLAG_OUTPUT_BUFFER) { ++ return(AE_OK); ++ } ++ acpi_os_sleep_usec(10); ++ } while (--i>0); ++ break; ++ ++ case EC_EVENT_INPUT_BUFFER_EMPTY: ++ do { ++ ec_status = acpi_os_in8(ec->status_port); ++ if (!(ec_status & EC_FLAG_INPUT_BUFFER)) { ++ return(AE_OK); ++ } ++ acpi_os_sleep_usec(10); ++ } while (--i>0); ++ break; ++ } ++ ++ return(AE_TIME); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_io_read ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ec_io_read ( ++ EC_CONTEXT *ec, ++ ACPI_IO_ADDRESS io_port, ++ u8 *data, ++ EC_EVENT wait_event) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!ec || !data) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ *data = acpi_os_in8(io_port); ++ ++ if (wait_event) { ++ status = ec_io_wait(ec, wait_event); ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_io_write ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ec_io_write ( ++ EC_CONTEXT *ec, ++ ACPI_IO_ADDRESS io_port, ++ u8 data, ++ EC_EVENT wait_event) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!ec) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ acpi_os_out8(io_port, data); ++ ++ if (wait_event) { ++ status = ec_io_wait(ec, wait_event); ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_read ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ec_read ( ++ EC_CONTEXT *ec, ++ u8 address, ++ u8 *data) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!ec || !data) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ if (ec->use_global_lock) { ++ status = acpi_acquire_global_lock(); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ } ++ ++ status = ec_io_write(ec, ec->command_port, EC_COMMAND_READ, ++ EC_EVENT_INPUT_BUFFER_EMPTY); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ status = ec_io_write(ec, ec->data_port, address, ++ EC_EVENT_OUTPUT_BUFFER_FULL); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ status = ec_io_read(ec, ec->data_port, data, EC_EVENT_NONE); ++ ++ if (ec->use_global_lock) { ++ acpi_release_global_lock(); ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_write ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ec_write ( ++ EC_CONTEXT *ec, ++ u8 address, ++ u8 data) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!ec) ++ return(AE_BAD_PARAMETER); ++ ++ if (ec->use_global_lock) { ++ status = acpi_acquire_global_lock(); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ } ++ ++ status = ec_io_write(ec, ec->command_port, EC_COMMAND_WRITE, ++ EC_EVENT_INPUT_BUFFER_EMPTY); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ status = ec_io_write(ec, ec->data_port, address, ++ EC_EVENT_INPUT_BUFFER_EMPTY); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ status = ec_io_write(ec, ec->data_port, data, ++ EC_EVENT_INPUT_BUFFER_EMPTY); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ if (ec->use_global_lock) { ++ acpi_release_global_lock(); ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: ec_transaction ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++ec_transaction ( ++ EC_CONTEXT *ec, ++ EC_REQUEST *request) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!ec || !request) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Obtain mutex to serialize all EC transactions. ++ */ ++ status = acpi_os_wait_semaphore(ec->mutex, 1, EC_DEFAULT_TIMEOUT); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ /* ++ * Perform the transaction. ++ */ ++ switch (request->command) { ++ ++ case EC_COMMAND_READ: ++ status = ec_read(ec, request->address, &(request->data)); ++ break; ++ ++ case EC_COMMAND_WRITE: ++ status = ec_write(ec, request->address, request->data); ++ break; ++ ++ default: ++ status = AE_SUPPORT; ++ break; ++ } ++ ++ /* ++ * Signal the mutex to indicate transaction completion. ++ */ ++ acpi_os_signal_semaphore(ec->mutex, 1); ++ ++ return(status); ++} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/include/ac.h linux/drivers/acpi/ospm/include/ac.h +--- /usr/src/linux/drivers/acpi/ospm/include/ac.h Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/include/ac.h Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,102 @@ ++/***************************************************************************** ++ * ++ * Module Name: ac.h ++ * $Revision: 6 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * 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 ++ */ ++ ++ ++#ifndef __AC_H__ ++#define __AC_H__ ++ ++#include <actypes.h> ++#include <acexcep.h> ++#include <bm.h> ++ ++ ++/***************************************************************************** ++ * Types & Other Defines ++ *****************************************************************************/ ++ ++/* ++ * Notifications: ++ * -------------- ++ */ ++#define AC_NOTIFY_STATUS_CHANGE ((BM_NOTIFY) 0x80) ++ ++/* ++ * Hardware IDs: ++ * ------------- ++ */ ++#define AC_HID_AC_ADAPTER "ACPI0003" ++ ++ ++/* ++ * Device Context: ++ * --------------- ++ */ ++typedef struct ++{ ++ BM_HANDLE device_handle; ++ ACPI_HANDLE acpi_handle; ++ char uid[9]; ++ u32 is_online; ++} AC_CONTEXT; ++ ++ ++/***************************************************************************** ++ * Function Prototypes ++ *****************************************************************************/ ++ ++ACPI_STATUS ++ac_initialize (void); ++ ++ACPI_STATUS ++ac_terminate (void); ++ ++ACPI_STATUS ++ac_notify ( ++ u32 notify_type, ++ u32 device, ++ void **context); ++ ++ACPI_STATUS ++ac_request( ++ BM_REQUEST *request_info, ++ void *context); ++ ++/* AC Adapter Driver OSL */ ++ ++ACPI_STATUS ++ac_osl_add_device ( ++ AC_CONTEXT *ac_adapter); ++ ++ACPI_STATUS ++ac_osl_remove_device ( ++ AC_CONTEXT *ac_adapter); ++ ++ACPI_STATUS ++ac_osl_generate_event ( ++ u32 event, ++ AC_CONTEXT *ac_adapter); ++ ++ ++#endif /* __AC_H__ */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/include/bm.h linux/drivers/acpi/ospm/include/bm.h +--- /usr/src/linux/drivers/acpi/ospm/include/bm.h Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/include/bm.h Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,584 @@ ++/***************************************************************************** ++ * ++ * Module name: bm.h ++ * $Revision: 37 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * 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 ++ */ ++ ++#ifndef __BM_H__ ++#define __BM_H__ ++ ++#include <actypes.h> ++#include <acexcep.h> ++ ++ ++/***************************************************************************** ++ * Types & Defines ++ *****************************************************************************/ ++ ++/* ++ * Output Flags (Debug): ++ * --------------------- ++ */ ++#define BM_PRINT_ALL (0x00000000) ++#define BM_PRINT_GROUP (0x00000001) ++#define BM_PRINT_LINKAGE (0x00000002) ++#define BM_PRINT_IDENTIFICATION (0x00000004) ++#define BM_PRINT_POWER (0x00000008) ++#define BM_PRINT_PRESENT (0x00000010) ++ ++ ++/* ++ * BM_COMMAND: ++ * ----------- ++ */ ++typedef u32 BM_COMMAND; ++ ++#define BM_COMMAND_UNKNOWN ((BM_COMMAND) 0x00) ++ ++#define BM_COMMAND_GET_POWER_STATE ((BM_COMMAND) 0x01) ++#define BM_COMMAND_SET_POWER_STATE ((BM_COMMAND) 0x02) ++ ++#define BM_COMMAND_DEVICE_SPECIFIC ((BM_COMMAND) 0x80) ++ ++/* ++ * BM_NOTIFY: ++ * ---------- ++ * Standard ACPI notification values, from section 5.6.3 of the ACPI 2.0 ++ * specification. Note that the Bus Manager internally handles all ++ * standard ACPI notifications -- driver modules are never sent these ++ * values (see "Bus Manager Notifications", below). ++ */ ++typedef u32 BM_NOTIFY; ++ ++#define BM_NOTIFY_BUS_CHECK ((BM_NOTIFY) 0x00) ++#define BM_NOTIFY_DEVICE_CHECK ((BM_NOTIFY) 0x01) ++#define BM_NOTIFY_DEVICE_WAKE ((BM_NOTIFY) 0x02) ++#define BM_NOTIFY_EJECT_REQUEST ((BM_NOTIFY) 0x03) ++#define BM_NOTIFY_DEVICE_CHECK_LIGHT ((BM_NOTIFY) 0x04) ++#define BM_NOTIFY_FREQUENCY_MISMATCH ((BM_NOTIFY) 0x05) ++#define BM_NOTIFY_BUS_MODE_MISMATCH ((BM_NOTIFY) 0x06) ++#define BM_NOTIFY_POWER_FAULT ((BM_NOTIFY) 0x07) ++ ++/* ++ * These are a higher-level abstraction of ACPI notifications, intended ++ * for consumption by driver modules to facilitate PnP. ++ */ ++#define BM_NOTIFY_UNKNOWN ((BM_NOTIFY) 0x00) ++#define BM_NOTIFY_DEVICE_ADDED ((BM_NOTIFY) 0x01) ++#define BM_NOTIFY_DEVICE_REMOVED ((BM_NOTIFY) 0x02) ++ ++ ++/* ++ * BM_HANDLE: ++ * ---------- ++ */ ++typedef u32 BM_HANDLE; ++ ++#define BM_HANDLE_ROOT ((BM_HANDLE) 0x00000000) ++#define BM_HANDLE_UNKNOWN ((BM_HANDLE) 0xFFFFFFFF) ++#define BM_HANDLES_MAX 256 ++ ++ ++ ++/* ++ * BM_HANDLE_LIST: ++ * --------------- ++ */ ++typedef struct ++{ ++ u32 count; ++ BM_HANDLE handles[BM_HANDLES_MAX]; ++} BM_HANDLE_LIST; ++ ++ ++/* ++ * BM_DEVICE_TYPE: ++ * --------------- ++ */ ++typedef u32 BM_DEVICE_TYPE; ++ ++#define BM_TYPE_UNKNOWN ((BM_DEVICE_TYPE) 0x00000000) ++ ++#define BM_TYPE_SYSTEM ((BM_DEVICE_TYPE) 0x00000001) ++#define BM_TYPE_SCOPE ((BM_DEVICE_TYPE) 0x00000002) ++#define BM_TYPE_PROCESSOR ((BM_DEVICE_TYPE) 0x00000003) ++#define BM_TYPE_THERMAL_ZONE ((BM_DEVICE_TYPE) 0x00000004) ++#define BM_TYPE_POWER_RESOURCE ((BM_DEVICE_TYPE) 0x00000005) ++#define BM_TYPE_DEVICE ((BM_DEVICE_TYPE) 0x00000006) ++#define BM_TYPE_FIXED_BUTTON ((BM_DEVICE_TYPE) 0x00000007) ++ ++ ++/* ++ * BM_DEVICE_UID: ++ * -------------- ++ */ ++typedef char BM_DEVICE_UID[9]; ++ ++#define BM_UID_UNKNOWN '0' ++ ++ ++/* ++ * BM_DEVICE_HID: ++ * -------------- ++ */ ++typedef char BM_DEVICE_HID[9]; ++ ++#define BM_HID_UNKNOWN '\0' ++#define BM_HID_POWER_BUTTON "PNP0C0C" ++#define BM_HID_SLEEP_BUTTON "PNP0C0E" ++ ++/* ++ * BM_DEVICE_ADR: ++ * -------------- ++ */ ++typedef u32 BM_DEVICE_ADR; ++ ++#define BM_ADDRESS_UNKNOWN 0 ++ ++ ++/* ++ * BM_DEVICE_FLAGS: ++ * ---------------- ++ * The encoding of BM_DEVICE_FLAGS is illustrated below. ++ * Note that a set bit (1) indicates the property is TRUE ++ * (e.g. if bit 0 is set then the device has dynamic status). ++ * +--+------------+-+-+-+-+-+-+-+ ++ * |31| Bits 30:7 |6|5|4|3|2|1|0| ++ * +--+------------+-+-+-+-+-+-+-+ ++ * | | | | | | | | | ++ * | | | | | | | | +- Dynamic status? ++ * | | | | | | | +--- Identifiable? ++ * | | | | | | +----- Configurable? ++ * | | | | | +------- Power Control? ++ * | | | | +--------- Ejectable? ++ * | | | +----------- Docking Station? ++ * | | +------------- Fixed-Feature? ++ * | +-------------------- <Reserved> ++ * +---------------------------- Driver Control? ++ * ++ * Dynamic status: Device has a _STA object. ++ * Identifiable: Device has a _HID and/or _ADR and possibly other ++ * identification objects defined. ++ * Configurable: Device has a _CRS and possibly other configuration ++ * objects defined. ++ * Power Control: Device has a _PR0 and/or _PS0 and possibly other ++ * power management objects defined. ++ * Ejectable: Device has an _EJD and/or _EJx and possibly other ++ * dynamic insertion/removal objects defined. ++ * Docking Station: Device has a _DCK object defined. ++ * Fixed-Feature: Device does not exist in the namespace; was ++ * enumerated as a fixed-feature (e.g. power button). ++ * Driver Control: A driver has been installed for this device. ++ */ ++typedef u32 BM_DEVICE_FLAGS; ++ ++#define BM_FLAGS_UNKNOWN ((BM_DEVICE_FLAGS) 0x00000000) ++ ++#define BM_FLAGS_DYNAMIC_STATUS ((BM_DEVICE_FLAGS) 0x00000001) ++#define BM_FLAGS_IDENTIFIABLE ((BM_DEVICE_FLAGS) 0x00000002) ++#define BM_FLAGS_CONFIGURABLE ((BM_DEVICE_FLAGS) 0x00000004) ++#define BM_FLAGS_POWER_CONTROL ((BM_DEVICE_FLAGS) 0x00000008) ++#define BM_FLAGS_EJECTABLE ((BM_DEVICE_FLAGS) 0x00000010) ++#define BM_FLAGS_DOCKING_STATION ((BM_DEVICE_FLAGS) 0x00000020) ++#define BM_FLAGS_FIXED_FEATURE ((BM_DEVICE_FLAGS) 0x00000040) ++#define BM_FLAGS_DRIVER_CONTROL ((BM_DEVICE_FLAGS) 0x80000000) ++ ++ ++/* ++ * Device PM Flags: ++ * ---------------- ++ * +-----------+-+-+-+-+-+-+-+ ++ * | Bits 31:7 |6|5|4|3|2|1|0| ++ * +-----------+-+-+-+-+-+-+-+ ++ * | | | | | | | | ++ * | | | | | | | +- D0 Support? ++ * | | | | | | +--- D1 Support? ++ * | | | | | +----- D2 Support? ++ * | | | | +------- D3 Support? ++ * | | | +--------- Power State Queriable? ++ * | | +----------- Inrush Current? ++ * | +------------- Wake Capable? ++ * +-------------------- <Reserved> ++ * ++ * D0-D3 Support: Device supports corresponding Dx state. ++ * Power State: Device has a _PSC (current power state) object defined. ++ * Inrush Current: Device has an _IRC (inrush current) object defined. ++ * Wake Capable: Device has a _PRW (wake-capable) object defined. ++ */ ++#define BM_FLAGS_D0_SUPPORT ((BM_DEVICE_FLAGS) 0x00000001) ++#define BM_FLAGS_D1_SUPPORT ((BM_DEVICE_FLAGS) 0x00000002) ++#define BM_FLAGS_D2_SUPPORT ((BM_DEVICE_FLAGS) 0x00000004) ++#define BM_FLAGS_D3_SUPPORT ((BM_DEVICE_FLAGS) 0x00000008) ++#define BM_FLAGS_POWER_STATE ((BM_DEVICE_FLAGS) 0x00000010) ++#define BM_FLAGS_INRUSH_CURRENT ((BM_DEVICE_FLAGS) 0x00000020) ++#define BM_FLAGS_WAKE_CAPABLE ((BM_DEVICE_FLAGS) 0x00000040) ++ ++ ++/* ++ * BM_DEVICE_STATUS: ++ * ----------------- ++ * The encoding of BM_DEVICE_STATUS is illustrated below. ++ * Note that a set bit (1) indicates the property is TRUE ++ * (e.g. if bit 0 is set then the device is present). ++ * +-----------+-+-+-+-+-+ ++ * | Bits 31:4 |4|3|2|1|0| ++ * +-----------+-+-+-+-+-+ ++ * | | | | | | ++ * | | | | | +- Present? ++ * | | | | +--- Enabled? ++ * | | | +----- Show in UI? ++ * | | +------- Functioning? ++ * | +--------- Battery Present? ++ * +---------------- <Reserved> ++ */ ++typedef u32 BM_DEVICE_STATUS; ++ ++#define BM_STATUS_UNKNOWN ((BM_DEVICE_STATUS) 0x00000000) ++#define BM_STATUS_PRESENT ((BM_DEVICE_STATUS) 0x00000001) ++#define BM_STATUS_ENABLED ((BM_DEVICE_STATUS) 0x00000002) ++#define BM_STATUS_SHOW_UI ((BM_DEVICE_STATUS) 0x00000004) ++#define BM_STATUS_FUNCTIONING ((BM_DEVICE_STATUS) 0x00000008) ++#define BM_STATUS_BATTERY_PRESENT ((BM_DEVICE_STATUS) 0x00000010) ++#define BM_STATUS_DEFAULT ((BM_DEVICE_STATUS) 0x0000000F) ++ ++ ++/* ++ * BM_POWER_STATE: ++ * --------------- ++ */ ++typedef u32 BM_POWER_STATE; ++ ++ ++/* ++ * BM_DEVICE_ID: ++ * ------------- ++ */ ++typedef struct ++{ ++ BM_DEVICE_TYPE type; ++ BM_DEVICE_UID uid; ++ BM_DEVICE_HID hid; ++ BM_DEVICE_ADR adr; ++} BM_DEVICE_ID; ++ ++ ++/* ++ * BM_DEVICE_POWER: ++ * ---------------- ++ * Structure containing basic device power management information. ++ */ ++typedef struct ++{ ++ BM_DEVICE_FLAGS flags; ++ BM_POWER_STATE state; ++ BM_DEVICE_FLAGS dx_supported[ACPI_S_STATE_COUNT]; ++} BM_DEVICE_POWER; ++ ++ ++/* ++ * BM_DEVICE: ++ * ---------- ++ */ ++typedef struct ++{ ++ BM_HANDLE handle; ++ ACPI_HANDLE acpi_handle; ++ BM_DEVICE_FLAGS flags; ++ BM_DEVICE_STATUS status; ++ BM_DEVICE_ID id; ++ BM_DEVICE_POWER power; ++} BM_DEVICE; ++ ++ ++/* ++ * BM_SEARCH: ++ * ---------- ++ * Structure used for searching the ACPI Bus Manager's device hierarchy. ++ */ ++typedef struct ++{ ++ BM_DEVICE_ID criteria; ++ BM_HANDLE_LIST results; ++} BM_SEARCH; ++ ++ ++/* ++ * BM_REQUEST: ++ * ----------- ++ * Structure used for sending requests to/through the ACPI Bus Manager. ++ */ ++typedef struct ++{ ++ ACPI_STATUS status; ++ BM_COMMAND command; ++ BM_HANDLE handle; ++ ACPI_BUFFER buffer; ++} BM_REQUEST; ++ ++ ++/* ++ * Driver Registration: ++ * -------------------- ++ */ ++ ++/* Driver Context */ ++typedef void * BM_DRIVER_CONTEXT; ++ ++/* Notification Callback Function */ ++typedef ++ACPI_STATUS (*BM_DRIVER_NOTIFY) ( ++ BM_NOTIFY notify_type, ++ BM_HANDLE device_handle, ++ BM_DRIVER_CONTEXT *context); ++ ++/* Request Callback Function */ ++typedef ++ACPI_STATUS (*BM_DRIVER_REQUEST) ( ++ BM_REQUEST *request, ++ BM_DRIVER_CONTEXT context); ++ ++/* Driver Registration */ ++typedef struct ++{ ++ BM_DRIVER_NOTIFY notify; ++ BM_DRIVER_REQUEST request; ++ BM_DRIVER_CONTEXT context; ++} BM_DRIVER; ++ ++ ++/* ++ * BM_NODE: ++ * -------- ++ * Structure used to maintain the device hierarchy. ++ */ ++typedef struct _BM_NODE ++{ ++ BM_DEVICE device; ++ BM_DRIVER driver; ++ struct _BM_NODE *parent; ++ struct _BM_NODE *next; ++ struct ++ { ++ struct _BM_NODE *head; ++ struct _BM_NODE *tail; ++ } scope; ++} BM_NODE; ++ ++ ++/* ++ * BM_NODE_LIST: ++ * ------------- ++ * Structure used to maintain an array of node pointers. ++ */ ++typedef struct ++{ ++ u32 count; ++ BM_NODE *nodes[BM_HANDLES_MAX]; ++} BM_NODE_LIST; ++ ++ ++/***************************************************************************** ++ * Macros ++ *****************************************************************************/ ++ ++/* ++ * Device Presence: ++ * ---------------- ++ * Note that status (_STA) means something different for power resources ++ * (they're assumed to always be present). ++ */ ++#define BM_DEVICE_PRESENT(d) ((d->id.type!=BM_TYPE_POWER_RESOURCE)?(d->status & BM_STATUS_PRESENT):TRUE) ++#define BM_NODE_PRESENT(n) ((n->device.id.type!=BM_TYPE_POWER_RESOURCE)?(n->device.status & BM_STATUS_PRESENT):TRUE) ++ ++/* ++ * Device Flags: ++ * ------------- ++ */ ++#define BM_IS_DRIVER_CONTROL(d) (d->flags & BM_FLAGS_DRIVER_CONTROL) ++#define BM_IS_POWER_CONTROL(d) (d->flags & BM_FLAGS_POWER_CONTROL) ++ ++ /* ++ * Device Power Flags: ++ * ------------------- ++ */ ++#define BM_IS_POWER_STATE(d) (d->power.flags & BM_FLAGS_POWER_STATE) ++ ++/***************************************************************************** ++ * Function Prototypes ++ *****************************************************************************/ ++ ++/* bm.c */ ++ ++ACPI_STATUS ++bm_initialize (void); ++ ++ACPI_STATUS ++bm_terminate (void); ++ ++ACPI_STATUS ++bm_get_status ( ++ BM_DEVICE *device); ++ ++ACPI_STATUS ++bm_get_handle ( ++ ACPI_HANDLE acpi_handle, ++ BM_HANDLE *device_handle); ++ ++ACPI_STATUS ++bm_get_node ( ++ BM_HANDLE device_handle, ++ ACPI_HANDLE acpi_handle, ++ BM_NODE **node); ++ ++/* bmsearch.c */ ++ ++ACPI_STATUS ++bm_search( ++ BM_HANDLE device_handle, ++ BM_DEVICE_ID *criteria, ++ BM_HANDLE_LIST *results); ++ ++/* bmnotify.c */ ++ ++void ++bm_notify ( ++ ACPI_HANDLE acpi_handle, ++ u32 notify_value, ++ void *context); ++ ++/* bm_request.c */ ++ ++ACPI_STATUS ++bm_request ( ++ BM_REQUEST *request_info); ++ ++/* bmdriver.c */ ++ ++ACPI_STATUS ++bm_get_device_power_state ( ++ BM_HANDLE device_handle, ++ BM_POWER_STATE *state); ++ ++ACPI_STATUS ++bm_set_device_power_state ( ++ BM_HANDLE device_handle, ++ BM_POWER_STATE state); ++ ++ACPI_STATUS ++bm_get_device_status ( ++ BM_HANDLE device_handle, ++ BM_DEVICE_STATUS *device_status); ++ ++ACPI_STATUS ++bm_get_device_info ( ++ BM_HANDLE device_handle, ++ BM_DEVICE **device_info); ++ ++ACPI_STATUS ++bm_get_device_context ( ++ BM_HANDLE device_handle, ++ BM_DRIVER_CONTEXT *context); ++ ++ACPI_STATUS ++bm_register_driver ( ++ BM_DEVICE_ID *criteria, ++ BM_DRIVER *driver); ++ ++ACPI_STATUS ++bm_unregister_driver ( ++ BM_DEVICE_ID *criteria, ++ BM_DRIVER *driver); ++ ++/* bmpm.c */ ++ ++ACPI_STATUS ++bm_get_pm_capabilities ( ++ BM_NODE *node); ++ ++ACPI_STATUS ++bm_get_power_state ( ++ BM_NODE *node); ++ ++ACPI_STATUS ++bm_set_power_state ( ++ BM_NODE *node, ++ BM_POWER_STATE target_state); ++ ++/* bmpower.c */ ++ ++ACPI_STATUS ++bm_pr_initialize (void); ++ ++ACPI_STATUS ++bm_pr_terminate (void); ++ ++/* bmutils.c */ ++ ++ACPI_STATUS ++bm_cast_buffer ( ++ ACPI_BUFFER *buffer, ++ void **pointer, ++ u32 length); ++ ++ACPI_STATUS ++bm_copy_to_buffer ( ++ ACPI_BUFFER *buffer, ++ void *data, ++ u32 length); ++ ++ACPI_STATUS ++bm_extract_package_data ( ++ ACPI_OBJECT *package, ++ ACPI_BUFFER *format, ++ ACPI_BUFFER *buffer); ++ ++ACPI_STATUS ++bm_evaluate_object ( ++ ACPI_HANDLE acpi_handle, ++ ACPI_STRING pathname, ++ ACPI_OBJECT_LIST *arguments, ++ ACPI_BUFFER *buffer); ++ ++ACPI_STATUS ++bm_evaluate_simple_integer ( ++ ACPI_HANDLE acpi_handle, ++ ACPI_STRING pathname, ++ u32 *data); ++ ++ACPI_STATUS ++bm_evaluate_reference_list ( ++ ACPI_HANDLE acpi_handle, ++ ACPI_STRING pathname, ++ BM_HANDLE_LIST *reference_list); ++ ++/* ACPI Bus Driver OSL */ ++ ++ACPI_STATUS ++bm_osl_generate_event ( ++ BM_HANDLE device_handle, ++ char *device_type, ++ char *device_instance, ++ u32 event_type, ++ u32 event_data); ++ ++ ++#endif /* __BM_H__ */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/include/bmpower.h linux/drivers/acpi/ospm/include/bmpower.h +--- /usr/src/linux/drivers/acpi/ospm/include/bmpower.h Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/include/bmpower.h Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,75 @@ ++/***************************************************************************** ++ * ++ * Module name: bmpower.h ++ * $Revision: 1 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * 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 ++ */ ++ ++#ifndef __BMPOWER_H__ ++#define __BMPOWER_H__ ++ ++#include "bm.h" ++ ++ ++/***************************************************************************** ++ * Types & Defines ++ *****************************************************************************/ ++ ++ ++/* ++ * BM_POWER_RESOURCE: ++ * ------------------ ++ */ ++typedef struct ++{ ++ BM_HANDLE device_handle; ++ ACPI_HANDLE acpi_handle; ++ BM_POWER_STATE system_level; ++ u32 resource_order; ++ BM_POWER_STATE state; ++ u32 reference_count; ++} BM_POWER_RESOURCE; ++ ++ ++/***************************************************************************** ++ * Function Prototypes ++ *****************************************************************************/ ++ ++/* bmpower.c */ ++ ++ACPI_STATUS ++bm_pr_initialize (void); ++ ++ACPI_STATUS ++bm_pr_terminate (void); ++ ++ACPI_STATUS ++bm_pr_list_get_state ( ++ BM_HANDLE_LIST *resource_list, ++ BM_POWER_STATE *power_state); ++ ++ACPI_STATUS ++bm_pr_list_transition ( ++ BM_HANDLE_LIST *current_list, ++ BM_HANDLE_LIST *target_list); ++ ++ ++#endif /* __BMPOWER_H__ */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/include/bn.h linux/drivers/acpi/ospm/include/bn.h +--- /usr/src/linux/drivers/acpi/ospm/include/bn.h Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/include/bn.h Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,122 @@ ++/****************************************************************************** ++ * ++ * Module Name: bn.h ++ * $Revision: 7 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * 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 ++ */ ++ ++ ++#ifndef __BN_H__ ++#define __BN_H__ ++ ++#include <actypes.h> ++#include <acexcep.h> ++#include <bm.h> ++ ++ ++/***************************************************************************** ++ * Types & Other Defines ++ *****************************************************************************/ ++ ++/* ++ * Notifications: ++ * --------------------- ++ */ ++#define BN_NOTIFY_STATUS_CHANGE ((BM_NOTIFY) 0x80) ++ ++ ++/* ++ * Types: ++ * ------ ++ */ ++#define BN_TYPE_POWER_BUTTON 0x01 ++#define BN_TYPE_POWER_BUTTON_FIXED 0x02 ++#define BN_TYPE_SLEEP_BUTTON 0x03 ++#define BN_TYPE_SLEEP_BUTTON_FIXED 0x04 ++#define BN_TYPE_LID_SWITCH 0x05 ++ ++ ++/* ++ * Hardware IDs: ++ * ------------- ++ * TODO: Power and Sleep button HIDs also exist in <bm.h>. Should all ++ * HIDs (ACPI well-known devices) exist in one place (e.g. ++ * acpi_hid.h)? ++ */ ++#define BN_HID_POWER_BUTTON "PNP0C0C" ++#define BN_HID_SLEEP_BUTTON "PNP0C0E" ++#define BN_HID_LID_SWITCH "PNP0C0D" ++ ++ ++/* ++ * Device Context: ++ * --------------- ++ */ ++typedef struct ++{ ++ BM_HANDLE device_handle; ++ ACPI_HANDLE acpi_handle; ++ u32 type; ++} BN_CONTEXT; ++ ++ ++/****************************************************************************** ++ * Function Prototypes ++ *****************************************************************************/ ++ ++ACPI_STATUS ++bn_initialize (void); ++ ++ACPI_STATUS ++bn_terminate (void); ++ ++ACPI_STATUS ++bn_notify_fixed ( ++ void *context); ++ ++ACPI_STATUS ++bn_notify ( ++ u32 notify_type, ++ u32 device, ++ void **context); ++ ++ACPI_STATUS ++bn_request( ++ BM_REQUEST *request_info, ++ void *context); ++ ++/* Button OSL */ ++ ++ACPI_STATUS ++bn_osl_add_device ( ++ BN_CONTEXT *button); ++ ++ACPI_STATUS ++bn_osl_remove_device ( ++ BN_CONTEXT *button); ++ ++ACPI_STATUS ++bn_osl_generate_event ( ++ u32 event, ++ BN_CONTEXT *button); ++ ++ ++#endif /* __BN_H__ */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/include/bt.h linux/drivers/acpi/ospm/include/bt.h +--- /usr/src/linux/drivers/acpi/ospm/include/bt.h Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/include/bt.h Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,156 @@ ++/****************************************************************************** ++ * ++ * Module Name: bt.h ++ * $Revision: 10 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * 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 ++ */ ++ ++ ++#ifndef __BT_H__ ++#define __BT_H__ ++ ++#include <actypes.h> ++#include <acexcep.h> ++#include <bm.h> ++ ++ ++/***************************************************************************** ++ * Types & Other Defines ++ *****************************************************************************/ ++ ++#define BT_UNKNOWN 0xFFFFFFFF ++#define BT_POWER_UNITS_DEFAULT "?" ++ ++ ++/* ++ * Battery Notifications: ++ * ---------------------- ++ */ ++#define BT_NOTIFY_STATUS_CHANGE ((BM_NOTIFY) 0x80) ++#define BT_NOTIFY_INFORMATION_CHANGE ((BM_NOTIFY) 0x81) ++ ++ ++/* ++ * Hardware IDs: ++ * ------------- ++ */ ++#define BT_HID_CM_BATTERY "PNP0C0A" ++ ++ ++/* ++ * BT_CM_BATTERY_INFO: ++ * ------------------- ++ */ ++typedef struct ++{ ++ u32 power_unit; ++ u32 design_capacity; ++ u32 last_full_capacity; ++ u32 battery_technology; ++ u32 design_voltage; ++ u32 design_capacity_warning; ++ u32 design_capacity_low; ++ u32 battery_capacity_granularity_1; ++ u32 battery_capacity_granularity_2; ++ ACPI_STRING model_number; ++ ACPI_STRING serial_number; ++ ACPI_STRING battery_type; ++ ACPI_STRING oem_info; ++} BT_BATTERY_INFO; ++ ++ ++/* ++ * BT_CM_BATTERY_STATUS: ++ * --------------------- ++ */ ++typedef struct ++{ ++ u32 state; ++ u32 present_rate; ++ u32 remaining_capacity; ++ u32 present_voltage; ++} BT_BATTERY_STATUS; ++ ++ ++/* ++ * BT_CONTEXT: ++ * ----------- ++ */ ++typedef struct ++{ ++ BM_HANDLE device_handle; ++ ACPI_HANDLE acpi_handle; ++ char uid[9]; ++ ACPI_STRING power_units; ++ u8 is_present; ++} BT_CONTEXT; ++ ++ ++/***************************************************************************** ++ * Function Prototypes ++ *****************************************************************************/ ++ ++/* bt.c */ ++ ++ACPI_STATUS ++bt_initialize (void); ++ ++ACPI_STATUS ++bt_terminate (void); ++ ++ACPI_STATUS ++bt_notify ( ++ u32 notify_type, ++ u32 device, ++ void **context); ++ ++ACPI_STATUS ++bt_request( ++ BM_REQUEST *request_info, ++ void *context); ++ ++ACPI_STATUS ++bt_get_status ( ++ BT_CONTEXT *battery, ++ BT_BATTERY_STATUS **battery_status); ++ ++ACPI_STATUS ++bt_get_info ( ++ BT_CONTEXT *battery, ++ BT_BATTERY_INFO **battery_info); ++ ++/* Battery OSL */ ++ ++ACPI_STATUS ++bt_osl_add_device ( ++ BT_CONTEXT *battery); ++ ++ACPI_STATUS ++bt_osl_remove_device ( ++ BT_CONTEXT *battery); ++ ++ACPI_STATUS ++bt_osl_generate_event ( ++ u32 event, ++ BT_CONTEXT *battery); ++ ++ ++#endif /* __BT_H__ */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/include/ec.h linux/drivers/acpi/ospm/include/ec.h +--- /usr/src/linux/drivers/acpi/ospm/include/ec.h Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/include/ec.h Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,202 @@ ++/***************************************************************************** ++ * ++ * Module Name: ec.h ++ * $Revision: 15 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * 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 ++ */ ++ ++ ++#ifndef __EC_H__ ++#define __EC_H__ ++ ++#include <linux/spinlock.h> ++#include <asm/semaphore.h> ++#include <actypes.h> ++#include <acexcep.h> ++#include <bm.h> ++ ++ ++/***************************************************************************** ++ * Types & Other Defines ++ *****************************************************************************/ ++ ++#define EC_DEFAULT_TIMEOUT 1000 /* 1 second */ ++#define EC_GPE_UNKNOWN 0xFFFFFFFF ++#define EC_PORT_UNKNOWN 0x00000000 ++#define EC_BURST_ENABLE_ACKNOWLEDGE 0x90 ++ ++ ++/* ++ * Commands: ++ * --------- ++ */ ++typedef u8 EC_COMMAND; ++ ++#define EC_COMMAND_UNKNOWN ((EC_COMMAND) 0x00) ++#define EC_COMMAND_READ ((EC_COMMAND) 0x80) ++#define EC_COMMAND_WRITE ((EC_COMMAND) 0x81) ++#define EC_COMMAND_QUERY ((EC_COMMAND) 0x84) ++ ++ ++/* ++ * EC_STATUS: ++ * ---------- ++ * The encoding of the EC status register is illustrated below. ++ * Note that a set bit (1) indicates the property is TRUE ++ * (e.g. if bit 0 is set then the output buffer is full). ++ * +-+-+-+-+-+-+-+-+ ++ * |7|6|5|4|3|2|1|0| ++ * +-+-+-+-+-+-+-+-+ ++ * | | | | | | | | ++ * | | | | | | | +- Output Buffer Full (OBF)? ++ * | | | | | | +--- Input Buffer Full (IBF)? ++ * | | | | | +----- <reserved> ++ * | | | | +------- data Register is command Byte? ++ * | | | +--------- Burst Mode Enabled? ++ * | | +----------- SCI event? ++ * | +------------- SMI event? ++ * +--------------- <Reserved> ++ * ++ */ ++typedef u8 EC_STATUS; ++ ++#define EC_FLAG_OUTPUT_BUFFER ((EC_STATUS) 0x01) ++#define EC_FLAG_INPUT_BUFFER ((EC_STATUS) 0x02) ++#define EC_FLAG_BURST_MODE ((EC_STATUS) 0x10) ++#define EC_FLAG_SCI ((EC_STATUS) 0x20) ++ ++ ++/* ++ * EC_EVENT: ++ * --------- ++ */ ++typedef u8 EC_EVENT; ++ ++#define EC_EVENT_UNKNOWN ((EC_EVENT) 0x00) ++#define EC_EVENT_NONE ((EC_EVENT) 0x00) ++#define EC_EVENT_OUTPUT_BUFFER_FULL ((EC_EVENT) 0x01) ++#define EC_EVENT_INPUT_BUFFER_EMPTY ((EC_EVENT) 0x02) ++#define EC_EVENT_SCI ((EC_EVENT) 0x03) ++ ++ ++/* ++ * Hardware IDs: ++ * ------------- ++ */ ++#define EC_HID_EC "PNP0C09" ++ ++ ++/* ++ * EC_REQUEST: ++ * ----------- ++ */ ++typedef struct ++{ ++ EC_COMMAND command; ++ u8 address; ++ u8 data; ++} EC_REQUEST; ++ ++ ++/* ++ * Device Context: ++ * --------------- ++ */ ++typedef struct ++{ ++ BM_HANDLE device_handle; ++ ACPI_HANDLE acpi_handle; ++ u32 gpe_bit; ++ u32 status_port; ++ u32 command_port; ++ u32 data_port; ++ u32 use_global_lock; ++ u8 query_data; ++ ACPI_HANDLE mutex; ++} EC_CONTEXT; ++ ++ ++/***************************************************************************** ++ * Function Prototypes ++ *****************************************************************************/ ++ ++/* ec.c */ ++ ++ACPI_STATUS ++ec_initialize(void); ++ ++ACPI_STATUS ++ec_terminate(void); ++ ++ACPI_STATUS ++ec_notify ( ++ u32 notify_type, ++ u32 device, ++ void **context); ++ ++ACPI_STATUS ++ec_request( ++ BM_REQUEST *request_info, ++ void *context); ++ ++/* ectransx.c */ ++ ++ACPI_STATUS ++ec_transaction ( ++ EC_CONTEXT *ec, ++ EC_REQUEST *ec_request); ++ ++ACPI_STATUS ++ec_io_read ( ++ EC_CONTEXT *ec, ++ u32 io_port, ++ u8 *data, ++ EC_EVENT wait_event); ++ ++ACPI_STATUS ++ec_io_write ( ++ EC_CONTEXT *ec, ++ u32 io_port, ++ u8 data, ++ EC_EVENT wait_event); ++ ++/* ecgpe.c */ ++ ++ACPI_STATUS ++ec_install_gpe_handler ( ++ EC_CONTEXT *ec); ++ ++ACPI_STATUS ++ec_remove_gpe_handler ( ++ EC_CONTEXT *ec); ++ ++/* ecspace.c */ ++ ++ACPI_STATUS ++ec_install_space_handler ( ++ EC_CONTEXT *ec); ++ ++ACPI_STATUS ++ec_remove_space_handler ( ++ EC_CONTEXT *ec); ++ ++ ++#endif /* __EC_H__ */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/include/pr.h linux/drivers/acpi/ospm/include/pr.h +--- /usr/src/linux/drivers/acpi/ospm/include/pr.h Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/include/pr.h Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,265 @@ ++/****************************************************************************** ++ * ++ * Module Name: processor.h ++ * $Revision: 9 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * 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 ++ */ ++ ++#ifndef __PR_H__ ++#define __PR_H__ ++ ++#include <bm.h> ++ ++ ++/***************************************************************************** ++ * Types & Other Defines ++ *****************************************************************************/ ++ ++ ++#define PR_MAX_POWER_STATES 4 ++#define PR_MAX_THROTTLE_STATES 8 ++#define PR_MAX_PERF_STATES 32 ++#define PR_MAX_C2_LATENCY 100 ++#define PR_MAX_C3_LATENCY 1000 ++ ++ ++/* ++ * Commands: ++ * --------- ++ */ ++#define PR_COMMAND_GET_POWER_INFO ((BM_COMMAND) 0x80) ++#define PR_COMMAND_SET_POWER_INFO ((BM_COMMAND) 0x81) ++#define PR_COMMAND_GET_PERF_INFO ((BM_COMMAND) 0x82) ++#define PR_COMMAND_GET_PERF_STATE ((BM_COMMAND) 0x83) ++#define PR_COMMAND_SET_PERF_LIMIT ((BM_COMMAND) 0x84) ++ ++ ++/* ++ * Notifications: ++ * -------------- ++ */ ++#define PR_NOTIFY_PERF_STATES ((BM_NOTIFY) 0x80) ++#define PR_NOTIFY_POWER_STATES ((BM_NOTIFY) 0x81) ++ ++ ++/* ++ * Performance Control: ++ * -------------------- ++ */ ++#define PR_PERF_DEC 0x00 ++#define PR_PERF_INC 0x01 ++#define PR_PERF_MAX 0xFF ++ ++ ++/* ++ * Power States: ++ * ------------- ++ */ ++#define PR_C0 0x00 ++#define PR_C1 0x01 ++#define PR_C2 0x02 ++#define PR_C3 0x03 ++ ++#define PR_C1_FLAG 0x01; ++#define PR_C2_FLAG 0x02; ++#define PR_C3_FLAG 0x04; ++ ++ ++/* ++ * PR_CX_POLICY_VALUES: ++ * -------------------- ++ */ ++typedef struct ++{ ++ u32 time_threshold; ++ u32 count_threshold; ++ u32 bm_threshold; ++ u32 target_state; ++ u32 count; ++} PR_CX_POLICY_VALUES; ++ ++ ++/* ++ * PR_CX: ++ * ------ ++ */ ++typedef struct ++{ ++ u32 latency; ++ u32 utilization; ++ u8 is_valid; ++ PR_CX_POLICY_VALUES promotion; ++ PR_CX_POLICY_VALUES demotion; ++} PR_CX; ++ ++ ++/* ++ * PR_POWER: ++ * --------- ++ */ ++typedef struct ++{ ++ ACPI_PHYSICAL_ADDRESS p_lvl2; ++ ACPI_PHYSICAL_ADDRESS p_lvl3; ++ u32 bm_activity; ++ u32 active_state; ++ u32 default_state; ++ u32 busy_metric; ++ u32 state_count; ++ PR_CX state[PR_MAX_POWER_STATES]; ++} PR_POWER; ++ ++ ++/* ++ * PR_PERFORMANCE_STATE: ++ * --------------------- ++ */ ++typedef struct ++{ ++ u32 performance; ++ u32 power; ++} PR_PERFORMANCE_STATE; ++ ++ ++/* ++ * PR_PERFORMANCE: ++ * --------------- ++ */ ++typedef struct ++{ ++ u32 active_state; ++ u32 thermal_limit; ++ u32 power_limit; ++ u32 state_count; ++ PR_PERFORMANCE_STATE state[PR_MAX_PERF_STATES]; ++} PR_PERFORMANCE; ++ ++ ++/* ++ * PR_PBLOCK: ++ * ---------- ++ */ ++typedef struct ++{ ++ u32 length; ++ ACPI_PHYSICAL_ADDRESS address; ++} PR_PBLOCK; ++ ++ ++/* ++ * PR_CONTEXT: ++ * ----------- ++ */ ++typedef struct ++{ ++ BM_HANDLE device_handle; ++ ACPI_HANDLE acpi_handle; ++ u32 uid; ++ PR_PBLOCK pblk; ++ PR_POWER power; ++ PR_PERFORMANCE performance; ++} PR_CONTEXT; ++ ++ ++/****************************************************************************** ++ * Function Prototypes ++ *****************************************************************************/ ++ ++/* processor.c */ ++ ++ACPI_STATUS ++pr_initialize(void); ++ ++ACPI_STATUS ++pr_terminate(void); ++ ++ACPI_STATUS ++pr_notify ( ++ BM_NOTIFY notify_type, ++ BM_HANDLE device_handle, ++ void **context); ++ ++ACPI_STATUS ++pr_request( ++ BM_REQUEST *request, ++ void *context); ++ ++/* prpower.c */ ++ ++void ++pr_power_idle (void); ++ ++ACPI_STATUS ++pr_power_add_device ( ++ PR_CONTEXT *processor); ++ ++ACPI_STATUS ++pr_power_remove_device ( ++ PR_CONTEXT *processor); ++ ++ACPI_STATUS ++pr_power_initialize (void); ++ ++ACPI_STATUS ++pr_power_terminate (void); ++ ++/* prperf.c */ ++ ++ACPI_STATUS ++pr_perf_get_state ( ++ PR_CONTEXT *processor, ++ u32 *state); ++ ++ACPI_STATUS ++pr_perf_set_state ( ++ PR_CONTEXT *processor, ++ u32 state); ++ ++ACPI_STATUS ++pr_perf_set_limit ( ++ PR_CONTEXT *processor, ++ u32 limit); ++ ++ACPI_STATUS ++pr_perf_add_device ( ++ PR_CONTEXT *processor); ++ ++ACPI_STATUS ++pr_perf_remove_device ( ++ PR_CONTEXT *processor); ++ ++/* Processor Driver OSL */ ++ ++ACPI_STATUS ++pr_osl_add_device ( ++ PR_CONTEXT *processor); ++ ++ACPI_STATUS ++pr_osl_remove_device ( ++ PR_CONTEXT *processor); ++ ++ACPI_STATUS ++pr_osl_generate_event ( ++ u32 event, ++ PR_CONTEXT *processor); ++ ++ ++#endif /* __PR_H__ */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/include/sm.h linux/drivers/acpi/ospm/include/sm.h +--- /usr/src/linux/drivers/acpi/ospm/include/sm.h Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/include/sm.h Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,91 @@ ++/***************************************************************************** ++ * ++ * Module Name: sm.h ++ * $Revision: 3 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * 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 ++ */ ++ ++ ++#ifndef __SM_H__ ++#define __SM_H__ ++ ++#include <actypes.h> ++#include <acexcep.h> ++#include <bm.h> ++ ++ ++/***************************************************************************** ++ * Types & Other Defines ++ *****************************************************************************/ ++ ++#define SM_MAX_SYSTEM_STATES 6 /* S0-S5 */ ++ ++ ++ /* ++ * Device Context: ++ * --------------- ++ */ ++typedef struct ++{ ++ BM_HANDLE device_handle; ++ ACPI_HANDLE acpi_handle; ++ u8 states[SM_MAX_SYSTEM_STATES]; ++} SM_CONTEXT; ++ ++ ++/***************************************************************************** ++ * Function Prototypes ++ *****************************************************************************/ ++ ++ACPI_STATUS ++sm_initialize (void); ++ ++ACPI_STATUS ++sm_terminate (void); ++ ++ACPI_STATUS ++sm_notify ( ++ u32 notify_type, ++ u32 device, ++ void **context); ++ ++ACPI_STATUS ++sm_request( ++ BM_REQUEST *request_info, ++ void *context); ++ ++/* System Driver OSL */ ++ ++ACPI_STATUS ++sm_osl_add_device ( ++ SM_CONTEXT *system); ++ ++ACPI_STATUS ++sm_osl_remove_device ( ++ SM_CONTEXT *system); ++ ++ACPI_STATUS ++sm_osl_generate_event ( ++ u32 event, ++ SM_CONTEXT *system); ++ ++ ++#endif /* __SM_H__ */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/include/tz.h linux/drivers/acpi/ospm/include/tz.h +--- /usr/src/linux/drivers/acpi/ospm/include/tz.h Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/include/tz.h Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,279 @@ ++/***************************************************************************** ++ * ++ * Module Name: tz.h ++ * $Revision: 18 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * 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 ++ */ ++ ++#ifndef __TZ_H__ ++#define __TZ_H__ ++ ++/* TODO: Linux-specific */ ++#include <linux/module.h> ++#include <linux/timer.h> ++ ++#include <bm.h> ++#include <pr.h> ++ ++ ++/***************************************************************************** ++ * Types & Other Defines ++ *****************************************************************************/ ++ ++#define TZ_MAX_THRESHOLDS 12 /* _AC0 through _AC9 + _CRT + _PSV */ ++#define TZ_MAX_ACTIVE_THRESHOLDS 10 /* _AC0 through _AC9 */ ++#define TZ_MAX_COOLING_DEVICES 10 /* TODO: Make size dynamic */ ++ ++ ++/* ++ * Notifications: ++ * -------------- ++ */ ++#define TZ_NOTIFY_TEMPERATURE_CHANGE ((BM_NOTIFY) 0x80) ++#define TZ_NOTIFY_THRESHOLD_CHANGE ((BM_NOTIFY) 0x81) ++#define TZ_NOTIFY_DEVICE_LISTS_CHANGE ((BM_NOTIFY) 0x82) ++ ++ ++/* ++ * TZ_THRESHOLD_TYPE: ++ * ------------------ ++ */ ++typedef u32 TZ_THRESHOLD_TYPE; ++ ++#define TZ_THRESHOLD_UNKNOWN ((TZ_THRESHOLD_TYPE) 0x00) ++#define TZ_THRESHOLD_CRITICAL ((TZ_THRESHOLD_TYPE) 0x01) ++ ++#define TZ_THRESHOLD_PASSIVE ((TZ_THRESHOLD_TYPE) 0x02) ++#define TZ_THRESHOLD_ACTIVE ((TZ_THRESHOLD_TYPE) 0x03) ++ ++ ++/* ++ * TZ_COOLING_STATE: ++ * ----------------- ++ */ ++typedef u32 TZ_COOLING_STATE; ++ ++#define TZ_COOLING_UNKNOWN ((TZ_COOLING_STATE) 0x00) ++#define TZ_COOLING_ENABLED ((TZ_COOLING_STATE) 0x01) ++#define TZ_COOLING_DISABLED ((TZ_COOLING_STATE) 0x02) ++ ++ ++/* ++ * TZ_COOLING_MODE: ++ * ---------------- ++ */ ++typedef u32 TZ_COOLING_MODE; ++ ++#define TZ_COOLING_MODE_ACTIVE ((TZ_COOLING_MODE) 0x00) ++#define TZ_COOLING_MODE_PASSIVE ((TZ_COOLING_MODE) 0x01) ++ ++ ++/* ++ * Thermal State: ++ * -------------- ++ * The encoding of TZ_STATE is illustrated below. ++ * Note that a set bit (1) indicates the property is TRUE ++ * (e.g. if bit 0 is set then the device has dynamic status). ++ * No bits set indicates an OK cooling state. ++ * +--+--+--+-----------+----------+ ++ * |31|30|29| Bits 27:4 | Bits 3:0 | ++ * +--+--+--+-----------+----------+ ++ * | | | | | ++ * | | | | +------ Active Index ++ * | | | +----------------- <reserved> ++ * | | +------------------------- Active ++ * | +---------------------------- Passive ++ * +------------------------------- Critical ++ * ++ * Active Index: Value representing the level of active cooling ++ * presently applied (e.g. 0=_AL0, 9=_AL9). Only ++ * valid when 'Active' is set. ++ * Active: If set, indicates that the system temperature ++ * has crossed at least one active threshold (_ALx). ++ * Passive: If set, indicates that the system temperature ++ * has crossed the passive threshold (_PSL). ++ * Passive: If set, indicates that the system temperature ++ * has crossed the critical threshold (_CRT). ++ */ ++typedef u32 TZ_STATE; ++ ++#define TZ_STATE_OK ((TZ_STATE) 0x00000000) ++#define TZ_STATE_ACTIVE ((TZ_STATE) 0x20000000) ++#define TZ_STATE_PASSIVE ((TZ_STATE) 0x40000000) ++#define TZ_STATE_CRITICAL ((TZ_STATE) 0x80000000) ++ ++ ++/* ++ * TZ_THRESHOLD: ++ * ------------- ++ * Information on an individual threshold. ++ */ ++typedef struct { ++ TZ_THRESHOLD_TYPE type; ++ u32 index; ++ u32 temperature; ++ TZ_COOLING_STATE cooling_state; ++ BM_HANDLE_LIST cooling_devices; ++} TZ_THRESHOLD; ++ ++ ++/* ++ * TZ_THRESHOLD_LIST: ++ * ------------------ ++ * Container for the thresholds of a given thermal zone. ++ * Note that thresholds are always ordered by increasing ++ * temperature value to simplify use by thermal policy. ++ */ ++typedef struct { ++ u32 count; ++ TZ_THRESHOLD thresholds[TZ_MAX_THRESHOLDS]; ++} TZ_THRESHOLD_LIST; ++ ++ ++/* ++ * TZ_CRITICAL_POLICY: ++ * ------------------- ++ */ ++typedef struct { ++ TZ_THRESHOLD *threshold; ++} TZ_CRITICAL_POLICY; ++ ++ ++/* ++ * TZ_PASSIVE_POLICY: ++ * ------------------ ++ */ ++typedef struct { ++ u32 tc1; ++ u32 tc2; ++ u32 tsp; ++ TZ_THRESHOLD *threshold; ++} TZ_PASSIVE_POLICY; ++ ++ ++/* ++ * TZ_ACTIVE_POLICY: ++ * ----------------- ++ */ ++typedef struct { ++ u32 threshold_count; ++ TZ_THRESHOLD *threshold[TZ_MAX_ACTIVE_THRESHOLDS]; ++} TZ_ACTIVE_POLICY; ++ ++ ++/* ++ * TZ_POLICY: ++ * --------- ++ */ ++typedef struct { ++ u32 temperature; ++ TZ_STATE state; ++ TZ_COOLING_MODE cooling_mode; ++ u32 polling_freq; ++ TZ_THRESHOLD_LIST threshold_list; ++ TZ_CRITICAL_POLICY critical; ++ TZ_PASSIVE_POLICY passive; ++ TZ_ACTIVE_POLICY active; ++ /* TODO: Linux-specific */ ++ struct timer_list timer; ++} TZ_POLICY; ++ ++ ++/* ++ * TZ_CONTEXT: ++ * ----------- ++ */ ++typedef struct { ++ BM_HANDLE device_handle; ++ ACPI_HANDLE acpi_handle; ++ char uid[9]; ++ TZ_POLICY policy; ++} TZ_CONTEXT; ++ ++ ++/***************************************************************************** ++ * Function Prototypes ++ *****************************************************************************/ ++ ++/* thermal_zone.c */ ++ ++ACPI_STATUS ++tz_initialize (void); ++ ++ACPI_STATUS ++tz_terminate (void); ++ ++ACPI_STATUS ++tz_notify ( ++ BM_NOTIFY notify_type, ++ BM_HANDLE device_handle, ++ BM_DRIVER_CONTEXT *context); ++ ++ACPI_STATUS ++tz_request ( ++ BM_REQUEST *request, ++ BM_DRIVER_CONTEXT context); ++ ++ACPI_STATUS ++tz_get_temperature ( ++ TZ_CONTEXT *thermal_zone, ++ u32 *temperature); ++ ++ACPI_STATUS ++tz_get_thresholds ( ++ TZ_CONTEXT *thermal_zone, ++ TZ_THRESHOLD_LIST *threshold_list); ++ ++void ++tz_print ( ++ TZ_CONTEXT *thermal_zone); ++ ++/* tzpolicy.c */ ++ ++ACPI_STATUS ++tz_policy_add_device ( ++ TZ_CONTEXT *thermal_zone); ++ ++ACPI_STATUS ++tz_policy_remove_device ( ++ TZ_CONTEXT *thermal_zone); ++ ++void ++tz_policy_check ( ++ void *context); ++ ++/* Thermal Zone Driver OSL */ ++ ++ACPI_STATUS ++tz_osl_add_device ( ++ TZ_CONTEXT *thermal_zone); ++ ++ACPI_STATUS ++tz_osl_remove_device ( ++ TZ_CONTEXT *thermal_zone); ++ ++ACPI_STATUS ++tz_osl_generate_event ( ++ u32 event, ++ TZ_CONTEXT *thermal_zone); ++ ++ ++#endif /* __TZ_H__ */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/processor/Makefile linux/drivers/acpi/ospm/processor/Makefile +--- /usr/src/linux/drivers/acpi/ospm/processor/Makefile Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/processor/Makefile Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,23 @@ ++# ++# Makefile for all Linux ACPI interpreter subdirectories ++# ++ ++O_TARGET := ../$(shell basename `pwd`).o ++ ++EXTRA_CFLAGS += -I../../include -I../include ++ ++EXTRA_CFLAGS += $(ACPI_CFLAGS) ++ ++list-multi := processor.o ++processor-objs := $(patsubst %.c,%.o,$(wildcard *.c)) ++ ++obj-$(CONFIG_ACPI_CPU) := processor.o ++ ++include $(TOPDIR)/Rules.make ++ ++clean: ++ $(RM) *.o ++ ++processor.o: $(processor-objs) ++ $(LD) -r -o $@ $(processor-objs) ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/processor/pr.c linux/drivers/acpi/ospm/processor/pr.c +--- /usr/src/linux/drivers/acpi/ospm/processor/pr.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/processor/pr.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,454 @@ ++/***************************************************************************** ++ * ++ * Module Name: pr.c ++ * $Revision: 24 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include <acpi.h> ++#include <bm.h> ++#include "pr.h" ++ ++ ++#define _COMPONENT ACPI_PROCESSOR_CONTROL ++ MODULE_NAME ("pr") ++ ++ ++/**************************************************************************** ++ * Globals ++ ****************************************************************************/ ++ ++extern FADT_DESCRIPTOR_REV2 acpi_fadt; ++ ++ ++/**************************************************************************** ++ * Internal Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_print ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: Prints out information on a specific thermal zone. ++ * ++ ****************************************************************************/ ++ ++void ++pr_print ( ++ PR_CONTEXT *processor) ++{ ++ ++ return; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_add_device ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++pr_add_device( ++ BM_HANDLE device_handle, ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ PR_CONTEXT *processor = NULL; ++ BM_DEVICE *device = NULL; ++ ACPI_BUFFER buffer; ++ ACPI_OBJECT acpi_object; ++ static u32 processor_count = 0; ++ ++ ++ if (!context || *context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ status = bm_get_device_info(device_handle, &device); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ processor = acpi_os_callocate(sizeof(PR_CONTEXT)); ++ if (!processor) { ++ return AE_NO_MEMORY; ++ } ++ ++ processor->device_handle = device->handle; ++ processor->acpi_handle = device->acpi_handle; ++ ++ /* ++ * Processor Block: ++ * ---------------- ++ */ ++ MEMSET(&acpi_object, 0, sizeof(ACPI_OBJECT)); ++ ++ buffer.length = sizeof(ACPI_OBJECT); ++ buffer.pointer = &acpi_object; ++ ++ status = acpi_evaluate_object(processor->acpi_handle, NULL, NULL, &buffer); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ /* ++ * Processor ID: ++ * ------------- ++ * TODO: We need to synchronize the processor ID values in ACPI ++ * with those of the APIC. For example, an IBM T20 has a ++ * proc_id value of '1', where the Linux value for the ++ * first CPU on this system is '0'. Since x86 CPUs are ++ * mapped 1:1 we can simply use a zero-based counter. Note ++ * that this assumes that processor objects are enumerated ++ * in the proper order. ++ */ ++ /* processor->uid = acpi_object.processor.proc_id; */ ++ processor->uid = processor_count++; ++ ++ processor->pblk.length = acpi_object.processor.pblk_length; ++ processor->pblk.address = acpi_object.processor.pblk_address; ++ ++ status = pr_power_add_device(processor); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ status = pr_perf_add_device(processor); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ status = pr_osl_add_device(processor); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ *context = processor; ++ ++ pr_print(processor); ++ ++end: ++ if (ACPI_FAILURE(status)) { ++ acpi_os_free(processor); ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_remove_device ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++pr_remove_device ( ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ PR_CONTEXT *processor= NULL; ++ ++ if (!context || !*context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ processor = (PR_CONTEXT*)(*context); ++ ++ pr_osl_remove_device(processor); ++ ++ pr_perf_remove_device(processor); ++ ++ pr_power_remove_device(processor); ++ ++ acpi_os_free(processor); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * External Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_initialize ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++pr_initialize (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE_ID criteria; ++ BM_DRIVER driver; ++ ++ MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); ++ MEMSET(&driver, 0, sizeof(BM_DRIVER)); ++ ++ /* ++ * Initialize power (Cx state) policy. ++ */ ++ status = pr_power_initialize(); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ /* ++ * Register driver for processor devices. ++ */ ++ criteria.type = BM_TYPE_PROCESSOR; ++ ++ driver.notify = &pr_notify; ++ driver.request = &pr_request; ++ ++ status = bm_register_driver(&criteria, &driver); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_terminate ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++pr_terminate (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE_ID criteria; ++ BM_DRIVER driver; ++ ++ MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); ++ MEMSET(&driver, 0, sizeof(BM_DRIVER)); ++ ++ /* ++ * Terminate power (Cx state) policy. ++ */ ++ status = pr_power_terminate(); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ /* ++ * Unegister driver for processor devices. ++ */ ++ criteria.type = BM_TYPE_PROCESSOR; ++ ++ driver.notify = &pr_notify; ++ driver.request = &pr_request; ++ ++ status = bm_unregister_driver(&criteria, &driver); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_notify ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++pr_notify ( ++ BM_NOTIFY notify_type, ++ BM_HANDLE device_handle, ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ PR_CONTEXT *processor = NULL; ++ ++ processor = (PR_CONTEXT*)*context; ++ ++ switch (notify_type) { ++ ++ case BM_NOTIFY_DEVICE_ADDED: ++ status = pr_add_device(device_handle, context); ++ break; ++ ++ case BM_NOTIFY_DEVICE_REMOVED: ++ status = pr_remove_device(context); ++ break; ++ ++ case PR_NOTIFY_PERF_STATES: ++ /* TODO: Streamline (this is simple but overkill). */ ++ status = pr_perf_remove_device(processor); ++ if (ACPI_SUCCESS(status)) { ++ status = pr_perf_add_device(processor); ++ } ++ if (ACPI_SUCCESS(status)) { ++ status = pr_osl_generate_event(notify_type, ++ (processor)); ++ } ++ break; ++ ++ case PR_NOTIFY_POWER_STATES: ++ /* TODO: Streamline (this is simple but overkill). */ ++ status = pr_power_remove_device(processor); ++ if (ACPI_SUCCESS(status)) { ++ status = pr_power_add_device(processor); ++ } ++ if (ACPI_SUCCESS(status)) { ++ status = pr_osl_generate_event(notify_type, ++ (processor)); ++ } ++ break; ++ ++ default: ++ status = AE_SUPPORT; ++ break; ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_request ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++pr_request ( ++ BM_REQUEST *request, ++ void *context) ++{ ++ ACPI_STATUS status = AE_OK; ++ PR_CONTEXT *processor = NULL; ++ ++ /* ++ * Must have a valid request structure and context. ++ */ ++ if (!request || !context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ processor = (PR_CONTEXT*)context; ++ ++ /* ++ * Handle request: ++ * --------------- ++ */ ++ switch (request->command) { ++ ++ case PR_COMMAND_GET_POWER_INFO: ++ status = bm_copy_to_buffer(&(request->buffer), ++ &(processor->power), sizeof(PR_POWER)); ++ break; ++ ++ case PR_COMMAND_SET_POWER_INFO: ++ { ++ PR_POWER *power_info = NULL; ++ u32 i = 0; ++ ++ status = bm_cast_buffer(&(request->buffer), ++ (void**)&power_info, sizeof(PR_POWER)); ++ if (ACPI_SUCCESS(status)) { ++ for (i=0; i<processor->power.state_count; i++) { ++ MEMCPY(&(processor->power.state[i].promotion), ++ &(power_info->state[i].promotion), ++ sizeof(PR_CX_POLICY_VALUES)); ++ MEMCPY(&(processor->power.state[i].demotion), ++ &(power_info->state[i].demotion), ++ sizeof(PR_CX_POLICY_VALUES)); ++ } ++ } ++ } ++ break; ++ ++ case PR_COMMAND_GET_PERF_INFO: ++ status = bm_copy_to_buffer(&(request->buffer), ++ &(processor->performance), sizeof(PR_PERFORMANCE)); ++ break; ++ ++ case PR_COMMAND_GET_PERF_STATE: ++ status = bm_copy_to_buffer(&(request->buffer), ++ &(processor->performance.active_state), sizeof(u32)); ++ break; ++ ++ case PR_COMMAND_SET_PERF_LIMIT: ++ { ++ u32 *limit = NULL; ++ ++ status = bm_cast_buffer(&(request->buffer), ++ (void**)&limit, sizeof(u32)); ++ if (ACPI_SUCCESS(status)) { ++ status = pr_perf_set_limit(processor, *limit); ++ } ++ } ++ break; ++ ++ default: ++ status = AE_SUPPORT; ++ break; ++ } ++ ++ request->status = status; ++ ++ return(status); ++} +\ No newline at end of file +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/processor/pr_osl.c linux/drivers/acpi/ospm/processor/pr_osl.c +--- /usr/src/linux/drivers/acpi/ospm/processor/pr_osl.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/processor/pr_osl.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,317 @@ ++/****************************************************************************** ++ * ++ * Module Name: pr_osl.c ++ * $Revision: 13 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/types.h> ++#include <linux/proc_fs.h> ++#include <acpi.h> ++#include <bm.h> ++#include "pr.h" ++ ++ ++MODULE_AUTHOR("Andrew Grover"); ++MODULE_DESCRIPTION("ACPI Component Architecture (CA) - IA32 Processor Driver"); ++ ++ ++#define PR_PROC_ROOT "processor" ++#define PR_PROC_STATUS "status" ++#define PR_PROC_INFO "info" ++ ++extern struct proc_dir_entry *bm_proc_root; ++static struct proc_dir_entry *pr_proc_root = NULL; ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_osl_proc_read_status ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++static int ++pr_osl_proc_read_status ( ++ char *page, ++ char **start, ++ off_t off, ++ int count, ++ int *eof, ++ void *context) ++{ ++ PR_CONTEXT *processor = NULL; ++ char *p = page; ++ int len = 0; ++ ++ if (!context || (off != 0)) { ++ goto end; ++ } ++ ++ processor = (PR_CONTEXT*)context; ++ ++ p += sprintf(p, "Bus Mastering Activity: %08x\n", ++ processor->power.bm_activity); ++ ++ p += sprintf(p, "C-State Utilization: C1[%d] C2[%d] C3[%d]\n", ++ processor->power.state[PR_C1].utilization, ++ processor->power.state[PR_C2].utilization, ++ processor->power.state[PR_C3].utilization); ++ ++end: ++ len = (p - page); ++ if (len <= off+count) *eof = 1; ++ *start = page + off; ++ len -= off; ++ if (len>count) len = count; ++ if (len<0) len = 0; ++ ++ return(len); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_osl_proc_read_info ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++static int ++pr_osl_proc_read_info ( ++ char *page, ++ char **start, ++ off_t off, ++ int count, ++ int *eof, ++ void *context) ++{ ++ PR_CONTEXT *processor = NULL; ++ char *p = page; ++ int len = 0; ++ ++ if (!context || (off != 0)) { ++ goto end; ++ } ++ ++ processor = (PR_CONTEXT*)context; ++ ++ p += sprintf(p, "<TBD>\n"); ++ ++end: ++ len = (p - page); ++ if (len <= off+count) *eof = 1; ++ *start = page + off; ++ len -= off; ++ if (len>count) len = count; ++ if (len<0) len = 0; ++ ++ return(len); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_osl_add_device ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++pr_osl_add_device( ++ PR_CONTEXT *processor) ++{ ++ u32 i = 0; ++ struct proc_dir_entry *proc_entry = NULL; ++ char processor_uid[16]; ++ ++ if (!processor) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ printk("Processor[%x]:", processor->uid); ++ for (i=0; i<processor->power.state_count; i++) { ++ if (processor->power.state[i].is_valid) { ++ printk(" C%d", i); ++ } ++ } ++ ++ if (processor->performance.state_count > 1) { ++ printk(", throttling states: %d", processor->performance.state_count); ++ } ++ ++ printk("\n"); ++ ++ sprintf(processor_uid, "%d", processor->uid); ++ ++ proc_entry = proc_mkdir(processor_uid, pr_proc_root); ++ if (!proc_entry) { ++ return(AE_ERROR); ++ } ++ ++ create_proc_read_entry(PR_PROC_STATUS, S_IFREG | S_IRUGO, ++ proc_entry, pr_osl_proc_read_status, (void*)processor); ++ ++ create_proc_read_entry(PR_PROC_INFO, S_IFREG | S_IRUGO, ++ proc_entry, pr_osl_proc_read_info, (void*)processor); ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_osl_remove_device ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++pr_osl_remove_device ( ++ PR_CONTEXT *processor) ++{ ++ char proc_entry[64]; ++ ++ if (!processor) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ sprintf(proc_entry, "%d/%s", processor->uid, PR_PROC_INFO); ++ remove_proc_entry(proc_entry, pr_proc_root); ++ ++ sprintf(proc_entry, "%d/%s", processor->uid, PR_PROC_STATUS); ++ remove_proc_entry(proc_entry, pr_proc_root); ++ ++ sprintf(proc_entry, "%d", processor->uid); ++ remove_proc_entry(proc_entry, pr_proc_root); ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_osl_generate_event ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++pr_osl_generate_event ( ++ u32 event, ++ PR_CONTEXT *processor) ++{ ++ ACPI_STATUS status = AE_OK; ++ char processor_uid[16]; ++ ++ if (!processor) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ switch (event) { ++ ++ case PR_NOTIFY_PERF_STATES: ++ case PR_NOTIFY_POWER_STATES: ++ sprintf(processor_uid, "%d", processor->uid); ++ status = bm_osl_generate_event(processor->device_handle, ++ PR_PROC_ROOT, processor_uid, event, 0); ++ break; ++ ++ default: ++ return(AE_BAD_PARAMETER); ++ break; ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_osl_init ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: 0: Success ++ * ++ * DESCRIPTION: Module initialization. ++ * ++ ****************************************************************************/ ++ ++static int __init ++pr_osl_init (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ pr_proc_root = proc_mkdir(PR_PROC_ROOT, bm_proc_root); ++ if (!pr_proc_root) { ++ status = AE_ERROR; ++ } ++ else { ++ status = pr_initialize(); ++ if (ACPI_FAILURE(status)) { ++ remove_proc_entry(PR_PROC_ROOT, bm_proc_root); ++ } ++ ++ } ++ ++ return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_osl_cleanup ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <none> ++ * ++ * DESCRIPTION: Module cleanup. ++ * ++ ****************************************************************************/ ++ ++static void __exit ++pr_osl_cleanup (void) ++{ ++ pr_terminate(); ++ ++ if (pr_proc_root) { ++ remove_proc_entry(PR_PROC_ROOT, bm_proc_root); ++ } ++ ++ return; ++} ++ ++ ++module_init(pr_osl_init); ++module_exit(pr_osl_cleanup); +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/processor/prperf.c linux/drivers/acpi/ospm/processor/prperf.c +--- /usr/src/linux/drivers/acpi/ospm/processor/prperf.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/processor/prperf.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,429 @@ ++/***************************************************************************** ++ * ++ * Module Name: prperf.c ++ * $Revision: 11 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * 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 ++ */ ++ ++/* ++ * TODO: ++ * ----- ++ * 1. Support ACPI 2.0 processor performance states (not just throttling). ++ * 2. Fully implement thermal -vs- power management limit control. ++ */ ++ ++ ++#include <acpi.h> ++#include <bm.h> ++#include "pr.h" ++ ++#define _COMPONENT ACPI_PROCESSOR_CONTROL ++ MODULE_NAME ("prperf") ++ ++ ++/**************************************************************************** ++ * Globals ++ ****************************************************************************/ ++ ++extern FADT_DESCRIPTOR_REV2 acpi_fadt; ++const u32 POWER_OF_2[] = {1,2,4,8,16,32,64,128,256,512}; ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_perf_get_frequency ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ * TODO: 1. Generic method to calculate processor frequency. ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++pr_perf_get_frequency ( ++ PR_CONTEXT *processor, ++ u32 *frequency) { ++ ACPI_STATUS status = AE_OK; ++ ++ if (!processor || !frequency) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ /* TODO: Calculate current CPU frequency. */ ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_perf_get_state ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ * TODO: 1. Include support for _real_ performance states (not just ++ * throttling). ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++pr_perf_get_state ( ++ PR_CONTEXT *processor, ++ u32 *state) ++{ ++ u32 pblk_value = 0; ++ u32 duty_mask = 0; ++ u32 duty_cycle = 0; ++ ++ if (!processor || !state) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ if (processor->performance.state_count == 1) { ++ *state = 0; ++ return(AE_OK); ++ } ++ ++ pblk_value = acpi_os_in32(processor->pblk.address); ++ ++ /* ++ * Throttling Enabled? ++ * ------------------- ++ * If so, calculate the current throttling state, otherwise return ++ * '100% performance' (state 0). ++ */ ++ if (pblk_value & 0x00000010) { ++ ++ duty_mask = processor->performance.state_count - 1; ++ duty_mask <<= acpi_fadt.duty_offset; ++ ++ duty_cycle = pblk_value & duty_mask; ++ duty_cycle >>= acpi_fadt.duty_offset; ++ ++ if (duty_cycle == 0) { ++ *state = 0; ++ } ++ else { ++ *state = processor->performance.state_count - ++ duty_cycle; ++ } ++ } ++ else { ++ *state = 0; ++ } ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_perf_set_state ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: AE_OK ++ * AE_BAD_PARAMETER ++ * AE_BAD_DATA Invalid target throttling state. ++ * ++ * DESCRIPTION: <TBD> ++ * ++ * TODO: 1. Include support for _real_ performance states (not just ++ * throttling). ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++pr_perf_set_state ( ++ PR_CONTEXT *processor, ++ u32 state) ++{ ++ u32 pblk_value = 0; ++ u32 duty_mask = 0; ++ u32 duty_cycle = 0; ++ u32 i = 0; ++ ++ if (!processor) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ if (state > (processor->performance.state_count - 1)) { ++ return(AE_BAD_DATA); ++ } ++ ++ if (processor->performance.state_count == 1) { ++ return(AE_OK); ++ } ++ ++ /* ++ * Calculate Duty Cycle/Mask: ++ * -------------------------- ++ * Note that we don't support duty_cycle values that span bit 4. ++ */ ++ if (state) { ++ duty_cycle = processor->performance.state_count - state; ++ duty_cycle <<= acpi_fadt.duty_offset; ++ } ++ else { ++ duty_cycle = 0; ++ } ++ ++ duty_mask = ~((u32)(processor->performance.state_count - 1)); ++ for (i=0; i<acpi_fadt.duty_offset; i++) { ++ duty_mask <<= acpi_fadt.duty_offset; ++ duty_mask += 1; ++ } ++ ++ /* ++ * Disable Throttling: ++ * ------------------- ++ * Got to turn it off before you can change the duty_cycle value. ++ * Throttling is disabled by writing a 0 to bit 4. ++ */ ++ pblk_value = acpi_os_in32(processor->pblk.address); ++ if (pblk_value & 0x00000010) { ++ pblk_value &= 0xFFFFFFEF; ++ acpi_os_out32(processor->pblk.address, pblk_value); ++ } ++ ++ /* ++ * Set Duty Cycle: ++ * --------------- ++ * Mask off the old duty_cycle value, mask in the new. ++ */ ++ pblk_value &= duty_mask; ++ pblk_value |= duty_cycle; ++ acpi_os_out32(processor->pblk.address, pblk_value); ++ ++ /* ++ * Enable Throttling: ++ * ------------------ ++ * But only for non-zero (non-100% performance) states. ++ */ ++ if (state) { ++ pblk_value |= 0x00000010; ++ acpi_os_out32(processor->pblk.address, pblk_value); ++ } ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_perf_set_limit ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++pr_perf_set_limit ( ++ PR_CONTEXT *processor, ++ u32 limit) ++{ ++ ACPI_STATUS status = AE_OK; ++ PR_PERFORMANCE *performance = NULL; ++ ++ if (!processor) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ performance = &(processor->performance); ++ ++ /* ++ * Set Limit: ++ * ---------- ++ * TODO: Properly manage thermal and power limits (only set ++ * performance state iff...). ++ */ ++ switch (limit) { ++ ++ case PR_PERF_DEC: ++ if (performance->active_state < ++ (performance->state_count-1)) { ++ status = pr_perf_set_state(processor, ++ (performance->active_state-1)); ++ } ++ break; ++ ++ case PR_PERF_INC: ++ if (performance->active_state > 0) { ++ status = pr_perf_set_state(processor, ++ (performance->active_state+1)); ++ } ++ break; ++ ++ case PR_PERF_MAX: ++ if (performance->active_state != 0) { ++ status = pr_perf_set_state(processor, 0); ++ } ++ break; ++ ++ default: ++ return(AE_BAD_DATA); ++ break; ++ } ++ ++ if (ACPI_SUCCESS(status)) { ++ performance->thermal_limit = limit; ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * External Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_perf_add_device ++ * ++ * PARAMETERS: processor Our processor-specific context. ++ * ++ * RETURN: AE_OK ++ * AE_BAD_PARAMETER ++ * ++ * DESCRIPTION: Calculates the number of throttling states and the state ++ * performance/power values. ++ * ++ * TODO: 1. Support duty_cycle values that span bit 4. ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++pr_perf_add_device ( ++ PR_CONTEXT *processor) ++{ ++ ACPI_STATUS status = AE_OK; ++ u32 i = 0; ++ u32 performance_step = 0; ++ u32 percentage = 0; ++ ++ if (!processor) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Valid PBLK? ++ * ----------- ++ * For SMP it is common to have the first (boot) processor have a ++ * valid PBLK while all others do not -- which implies that ++ * throttling has system-wide effects (duty_cycle programmed into ++ * the chipset effects all processors). ++ */ ++ if ((processor->pblk.length < 6) || !processor->pblk.address) { ++ processor->performance.state_count = 1; ++ } ++ ++ /* ++ * Valid Duty Offset/Width? ++ * ------------------------ ++ * We currently only support duty_cycle values that fall within ++ * bits 0-3, as things get complicated when this value spans bit 4 ++ * (the throttling enable/disable bit). ++ */ ++ else if ((acpi_fadt.duty_offset + acpi_fadt.duty_width) > 4) { ++ processor->performance.state_count = 1; ++ } ++ ++ /* ++ * Compute State Count: ++ * -------------------- ++ * The number of throttling states is computed as 2^duty_width, ++ * but limited by PR_MAX_THROTTLE_STATES. Note that a duty_width ++ * of zero results is one throttling state (100%). ++ */ ++ else { ++ processor->performance.state_count = ++ POWER_OF_2[acpi_fadt.duty_width]; ++ } ++ ++ if (processor->performance.state_count > PR_MAX_THROTTLE_STATES) { ++ processor->performance.state_count = PR_MAX_THROTTLE_STATES; ++ } ++ ++ /* ++ * Compute State Values: ++ * --------------------- ++ * Note that clock throttling displays a linear power/performance ++ * relationship (at 50% performance the CPU will consume 50% power). ++ */ ++ performance_step = (1000 / processor->performance.state_count); ++ ++ for (i=0; i<processor->performance.state_count; i++) { ++ percentage = (1000 - (performance_step * i))/10; ++ processor->performance.state[i].performance = percentage; ++ processor->performance.state[i].power = percentage; ++ } ++ ++ /* ++ * Get Current State: ++ * ------------------ ++ */ ++ status = pr_perf_get_state(processor, ++ &(processor->performance.active_state)); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_perf_remove_device ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++pr_perf_remove_device ( ++ PR_CONTEXT *processor) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!processor) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ MEMSET(&(processor->performance), 0, sizeof(PR_PERFORMANCE)); ++ ++ return(status); ++} ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/processor/prpower.c linux/drivers/acpi/ospm/processor/prpower.c +--- /usr/src/linux/drivers/acpi/ospm/processor/prpower.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/processor/prpower.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,636 @@ ++/***************************************************************************** ++ * ++ * Module Name: prpower.c ++ * $Revision: 19 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * 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 ++ */ ++ ++ ++/* TODO: Linux specific */ ++#include <linux/sched.h> ++#include <linux/pm.h> ++ ++#include <acpi.h> ++#include <bm.h> ++#include "pr.h" ++ ++#define _COMPONENT ACPI_PROCESSOR_CONTROL ++ MODULE_NAME ("prpower") ++ ++ ++/**************************************************************************** ++ * Globals ++ ****************************************************************************/ ++ ++extern FADT_DESCRIPTOR_REV2 acpi_fadt; ++static u32 last_idle_jiffies = 0; ++static PR_CONTEXT *processor_list[NR_CPUS]; ++static void (*pr_pm_idle_save)(void) = NULL; ++ ++ ++/**************************************************************************** ++ * External Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_power_activate_state ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++void ++pr_power_activate_state ( ++ PR_CONTEXT *processor, ++ u32 next_state) ++{ ++ if (!processor) { ++ return; ++ } ++ ++ processor->power.state[processor->power.active_state].promotion.count = 0; ++ processor->power.state[processor->power.active_state].demotion.count = 0; ++ ++ /* ++ * Cleanup from old state. ++ */ ++ switch (processor->power.active_state) { ++ ++ case PR_C3: ++ /* Disable bus master reload */ ++ acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK, ++ BM_RLD, 0); ++ break; ++ } ++ ++ /* ++ * Prepare to use new state. ++ */ ++ switch (next_state) { ++ ++ case PR_C3: ++ /* Enable bus master reload */ ++ acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK, ++ BM_RLD, 1); ++ break; ++ } ++ ++ processor->power.active_state = next_state; ++ ++ return; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_power_idle ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++void ++pr_power_idle (void) ++{ ++ PR_CX *c_state = NULL; ++ u32 next_state = 0; ++ u32 start_ticks, end_ticks, time_elapsed; ++ PR_CONTEXT *processor = NULL; ++ ++ processor = processor_list[smp_processor_id()]; ++ ++ if (!processor || processor->power.active_state == PR_C0) { ++ return; ++ } ++ ++ next_state = processor->power.active_state; ++ ++ /* ++ * Log BM Activity: ++ * ---------------- ++ * Read BM_STS and record its value for later use by C3 policy. ++ * Note that we save the BM_STS values for the last 32 call to ++ * this function (cycles). Also note that we must clear BM_STS ++ * if set (sticky). ++ */ ++ processor->power.bm_activity <<= 1; ++ if (acpi_hw_register_bit_access(ACPI_READ, ACPI_MTX_DO_NOT_LOCK, BM_STS)) { ++ processor->power.bm_activity |= 1; ++ acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK, ++ BM_STS, 1); ++ } ++ ++ /* ++ * Check OS Idleness: ++ * ------------------ ++ * If the OS has been busy (hasn't called the idle handler in a while) ++ * then automatically demote to the default power state (e.g. C1). ++ * ++ * TODO: Optimize by having scheduler determine business instead ++ * of having us try to calculate it. ++ */ ++ if (processor->power.active_state != processor->power.default_state) { ++ if ((jiffies - last_idle_jiffies) >= processor->power.busy_metric) { ++ next_state = processor->power.default_state; ++ if (next_state != processor->power.active_state) { ++ pr_power_activate_state(processor, next_state); ++ } ++ } ++ } ++ ++ c_state = &(processor->power.state[processor->power.active_state]); ++ ++ c_state->utilization++; ++ ++ /* ++ * Sleep: ++ * ------ ++ * Invoke the current Cx state to put the processor to sleep. ++ */ ++ switch (processor->power.active_state) { ++ ++ case PR_C1: ++ /* See how long we're asleep for */ ++ acpi_get_timer(&start_ticks); ++ /* Invoke C1 */ ++ enable(); halt(); ++ /* Compute time elapsed */ ++ acpi_get_timer(&end_ticks); ++ break; ++ ++ case PR_C2: ++ /* Interrupts must be disabled during C2 transitions */ ++ disable(); ++ /* See how long we're asleep for */ ++ acpi_get_timer(&start_ticks); ++ /* Invoke C2 */ ++ acpi_os_in8(processor->power.p_lvl2); ++ /* Dummy op - must do something useless after P_LVL2 read */ ++ acpi_hw_register_bit_access(ACPI_READ, ACPI_MTX_DO_NOT_LOCK, ++ BM_STS); ++ /* Compute time elapsed */ ++ acpi_get_timer(&end_ticks); ++ /* Re-enable interrupts */ ++ enable(); ++ break; ++ ++ case PR_C3: ++ /* Interrupts must be disabled during C3 transitions */ ++ disable(); ++ /* Disable bus master arbitration */ ++ acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK, ++ ARB_DIS, 1); ++ /* See how long we're asleep for */ ++ acpi_get_timer(&start_ticks); ++ /* Invoke C2 */ ++ acpi_os_in8(processor->power.p_lvl3); ++ /* Dummy op - must do something useless after P_LVL3 read */ ++ acpi_hw_register_bit_access(ACPI_READ, ACPI_MTX_DO_NOT_LOCK, ++ BM_STS); ++ /* Compute time elapsed */ ++ acpi_get_timer(&end_ticks); ++ /* Enable bus master arbitration */ ++ acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK, ++ ARB_DIS, 0); ++ /* Re-enable interrupts */ ++ enable(); ++ break; ++ ++ default: ++ break; ++ } ++ ++ /* ++ * Compute the amount of time asleep (in the Cx state). ++ * ++ * TODO: Convert time_threshold to PM timer ticks initially to ++ * avoid having to do the math (acpi_get_timer_duration). ++ */ ++ acpi_get_timer_duration(start_ticks, end_ticks, &time_elapsed); ++ ++ /* ++ * Promotion? ++ * ---------- ++ * Track the number of successful sleeps (time asleep is greater ++ * than time_threshold) and promote when count_threashold is ++ * reached. ++ */ ++ if ((c_state->promotion.target_state) && ++ (time_elapsed >= c_state->promotion.time_threshold)) { ++ ++ c_state->promotion.count++; ++ c_state->demotion.count = 0; ++ ++ if (c_state->promotion.count >= ++ c_state->promotion.count_threshold) { ++ ++ /* ++ * Bus Mastering Activity, if active and used ++ * by this state's promotion policy, prevents ++ * promotions from occuring. ++ */ ++ if (!(processor->power.bm_activity & ++ c_state->promotion.bm_threshold)) { ++ next_state = c_state->promotion.target_state; ++ } ++ } ++ } ++ ++ /* ++ * Demotion? ++ * --------- ++ * Track the number of shorts (time asleep is less than ++ * time_threshold) and demote when count_threshold is reached. ++ */ ++ if (c_state->demotion.target_state) { ++ ++ if (time_elapsed < c_state->demotion.time_threshold) { ++ ++ c_state->demotion.count++; ++ c_state->promotion.count = 0; ++ ++ if (c_state->demotion.count >= ++ c_state->demotion.count_threshold) { ++ next_state = c_state->demotion.target_state; ++ } ++ } ++ ++ /* ++ * Bus Mastering Activity, if active and used by this ++ * state's promotion policy, causes an immediate demotion ++ * to occur. ++ */ ++ if (processor->power.bm_activity & ++ c_state->demotion.bm_threshold) { ++ next_state = c_state->demotion.target_state; ++ } ++ } ++ ++ /* ++ * New Cx State? ++ * ------------- ++ * If we're going to start using a new Cx state we must clean up ++ * from the previous and prepare to use the new. ++ */ ++ if (next_state != processor->power.active_state) { ++ pr_power_activate_state(processor, next_state); ++ processor->power.active_state = processor->power.active_state; ++ } ++ ++ /* ++ * Track OS Idleness: ++ * ------------------ ++ * Record a jiffies timestamp to compute time elapsed between calls ++ * to the idle handler. ++ */ ++ last_idle_jiffies = jiffies; ++ ++ return; ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: pr_power_set_default_policy ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: Sets the default Cx state policy (OS idle handler). Our ++ * scheme is to promote quickly to C2 but more conservatively ++ * to C3. We're favoring C2 for its characteristics of low ++ * latency (quick response), good power savings, and ability ++ * to allow bus mastering activity. ++ * ++ * Note that Cx state policy is completely customizable, with ++ * the goal of having heuristics to alter policy dynamically. ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++pr_power_set_default_policy ( ++ PR_CONTEXT *processor) ++{ ++ if (!processor) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Busy Metric: ++ * ------------ ++ * Used to determine when the OS has been busy and thus when ++ * policy should return to using the default Cx state (e.g. C1). ++ * On Linux we use the number of jiffies (scheduler quantums) ++ * that transpire between calls to the idle handler. ++ * ++ * TODO: Linux-specific. ++ */ ++ processor->power.busy_metric = 2; ++ ++ /* ++ * C1: ++ * --- ++ * C1 serves as our default state. It must be valid. ++ */ ++ if (processor->power.state[PR_C1].is_valid) { ++ processor->power.active_state = ++ processor->power.default_state = PR_C1; ++ } ++ else { ++ processor->power.active_state = ++ processor->power.default_state = PR_C0; ++ return(AE_OK); ++ } ++ ++ /* ++ * C2: ++ * --- ++ * Set default C1 promotion and C2 demotion policies. ++ */ ++ if (processor->power.state[PR_C2].is_valid) { ++ /* ++ * Promote from C1 to C2 anytime we're asleep in C1 for ++ * longer than two times the C2 latency (to amortize cost ++ * of transition). Demote from C2 to C1 anytime we're ++ * asleep in C2 for less than this time. ++ */ ++ processor->power.state[PR_C1].promotion.count_threshold = 1; ++ processor->power.state[PR_C1].promotion.time_threshold = ++ 2 * processor->power.state[PR_C2].latency; ++ processor->power.state[PR_C1].promotion.target_state = PR_C2; ++ ++ processor->power.state[PR_C2].demotion.count_threshold = 1; ++ processor->power.state[PR_C2].demotion.time_threshold = ++ 2 * processor->power.state[PR_C2].latency; ++ processor->power.state[PR_C2].demotion.target_state = PR_C1; ++ } ++ ++ /* ++ * C3: ++ * --- ++ * Set default C2 promotion and C3 demotion policies. ++ */ ++ if ((processor->power.state[PR_C2].is_valid) && ++ (processor->power.state[PR_C3].is_valid)) { ++ /* ++ * Promote from C2 to C3 after 4 cycles of no bus ++ * mastering activity (while maintaining sleep time ++ * criteria). Demote immediately on a short or ++ * whenever bus mastering activity occurs. ++ */ ++ processor->power.state[PR_C2].promotion.count_threshold = 1; ++ processor->power.state[PR_C2].promotion.time_threshold = ++ 2 * processor->power.state[PR_C3].latency; ++ processor->power.state[PR_C2].promotion.bm_threshold = ++ 0x0000000F; ++ processor->power.state[PR_C2].promotion.target_state = ++ PR_C3; ++ ++ processor->power.state[PR_C3].demotion.count_threshold = 1; ++ processor->power.state[PR_C3].demotion.time_threshold = ++ 2 * processor->power.state[PR_C3].latency; ++ processor->power.state[PR_C3].demotion.bm_threshold = ++ 0x0000000F; ++ processor->power.state[PR_C3].demotion.target_state = ++ PR_C2; ++ } ++ ++ return(AE_OK); ++} ++ ++/***************************************************************************** ++ * ++ * FUNCTION: pr_power_add_device ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: <TBD> ++ * ++ * TODO: 1. PROC_C1 support. ++ * 2. Symmetric Cx state support (different Cx states supported ++ * by different CPUs results in lowest common denominator). ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++pr_power_add_device ( ++ PR_CONTEXT *processor) ++{ ++ if (!processor) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * State Count: ++ * ------------ ++ * Fixed at four (C0-C3). We use is_valid to determine whether or ++ * not a state actually gets used. ++ */ ++ processor->power.state_count = PR_MAX_POWER_STATES; ++ ++ /* ++ * C0: ++ * --- ++ * C0 exists only as filler in our array. (Let's assume its valid!) ++ */ ++ processor->power.state[PR_C0].is_valid = TRUE; ++ ++ /* ++ * C1: ++ * --- ++ * ACPI states that C1 must be supported by all processors ++ * with a latency so small that it can be ignored. ++ * ++ * TODO: What about PROC_C1 support? ++ */ ++ processor->power.state[PR_C1].is_valid = TRUE; ++ ++ /* ++ * C2: ++ * --- ++ * We're only supporting C2 on UP systems with latencies <= 100us. ++ * ++ * TODO: Support for C2 on MP (P_LVL2_UP) -- I'm taking the ++ * conservative approach for now. ++ */ ++ processor->power.state[PR_C2].latency = acpi_fadt.plvl2_lat; ++ ++#ifdef CONFIG_SMP ++ if (smp_num_cpus == 1) { ++#endif /*CONFIG_SMP*/ ++ if (acpi_fadt.plvl2_lat <= PR_MAX_C2_LATENCY) { ++ processor->power.state[PR_C2].is_valid = TRUE; ++ processor->power.p_lvl2 = processor->pblk.address + 4; ++ } ++#ifdef CONFIG_SMP ++ } ++#endif /*CONFIG_SMP*/ ++ ++ ++ /* ++ * C3: ++ * --- ++ * We're only supporting C3 on UP systems with latencies <= 1000us, ++ * and that include the ability to disable bus mastering while in ++ * C3 (ARB_DIS) but allows bus mastering requests to wake the system ++ * from C3 (BM_RLD). Note his method of maintaining cache coherency ++ * (disabling of bus mastering) cannot be used on SMP systems, and ++ * flushing caches (e.g. WBINVD) is simply too costly at this time. ++ * ++ * TODO: Support for C3 on MP -- I'm taking the conservative ++ * approach for now. ++ */ ++ processor->power.state[PR_C3].latency = acpi_fadt.plvl3_lat; ++ ++#ifdef CONFIG_SMP ++ if (smp_num_cpus == 1) { ++#endif /*CONFIG_SMP*/ ++ if ((acpi_fadt.plvl3_lat <= PR_MAX_C3_LATENCY) && ++ (acpi_fadt.V1_pm2_cnt_blk && acpi_fadt.pm2_cnt_len)) { ++ processor->power.state[PR_C3].is_valid = TRUE; ++ processor->power.p_lvl3 = processor->pblk.address + 5; ++ } ++#ifdef CONFIG_SMP ++ } ++#endif /*CONFIG_SMP*/ ++ ++ /* ++ * Set Default Policy: ++ * ------------------- ++ * Now that we know which state are supported, set the default ++ * policy. Note that this policy can be changed dynamically ++ * (e.g. encourage deeper sleeps to conserve battery life when ++ * not on AC). ++ */ ++ pr_power_set_default_policy(processor); ++ ++ /* ++ * Save Processor Context: ++ * ----------------------- ++ * TODO: Enhance Linux idle handler to take processor context ++ * parameter. ++ */ ++ processor_list[processor->uid] = processor; ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_power_remove_device ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++pr_power_remove_device ( ++ PR_CONTEXT *processor) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!processor) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ MEMSET(&(processor->power), 0, sizeof(PR_POWER)); ++ ++ processor_list[processor->uid] = NULL; ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_power_initialize ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++pr_power_initialize (void) ++{ ++ u32 i = 0; ++ ++ /* TODO: Linux-specific. */ ++ for (i=0; i<NR_CPUS; i++) { ++ processor_list[i] = NULL; ++ } ++ ++ /* ++ * Install idle handler. ++ * ++ * TODO: Linux-specific (need OSL function). ++ */ ++ pr_pm_idle_save = pm_idle; ++ pm_idle = pr_power_idle; ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: pr_power_terminate ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++pr_power_terminate (void) ++{ ++ /* ++ * Remove idle handler. ++ * ++ * TODO: Linux-specific (need OSL function). ++ */ ++ pm_idle = pr_pm_idle_save; ++ ++ return(AE_OK); ++} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/system/Makefile linux/drivers/acpi/ospm/system/Makefile +--- /usr/src/linux/drivers/acpi/ospm/system/Makefile Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/system/Makefile Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,23 @@ ++# ++# Makefile for all Linux ACPI interpreter subdirectories ++# ++ ++O_TARGET := ../$(shell basename `pwd`).o ++ ++EXTRA_CFLAGS += -I../../include -I../include ++ ++EXTRA_CFLAGS += $(ACPI_CFLAGS) ++ ++list-multi := system.o ++system-objs := $(patsubst %.c,%.o,$(wildcard *.c)) ++ ++obj-$(CONFIG_ACPI_BUSMGR) := system.o ++ ++include $(TOPDIR)/Rules.make ++ ++clean: ++ $(RM) *.o ++ ++system.o: $(system-objs) ++ $(LD) -r -o $@ $(system-objs) ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/system/sm.c linux/drivers/acpi/ospm/system/sm.c +--- /usr/src/linux/drivers/acpi/ospm/system/sm.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/system/sm.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,330 @@ ++/***************************************************************************** ++ * ++ * Module Name: sm.c ++ * $Revision: 12 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <acpi.h> ++#include "sm.h" ++ ++ ++#define _COMPONENT ACPI_SYSTEM ++ MODULE_NAME ("sm") ++ ++ ++/**************************************************************************** ++ * Internal Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: sm_print ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: Prints out information on a specific system. ++ * ++ ****************************************************************************/ ++ ++void ++sm_print ( ++ SM_CONTEXT *system) ++{ ++ ++ return; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: sm_add_device ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++sm_add_device( ++ BM_HANDLE device_handle, ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE *device = NULL; ++ SM_CONTEXT *system = NULL; ++ u8 i, type_a, type_b; ++ ++ ++ if (!context || *context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Allocate a new SM_CONTEXT structure. ++ */ ++ system = acpi_os_callocate(sizeof(SM_CONTEXT)); ++ if (!system) { ++ return(AE_NO_MEMORY); ++ } ++ ++ /* ++ * Get information on this device. ++ */ ++ status = bm_get_device_info(device_handle, &device); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ system->device_handle = device->handle; ++ system->acpi_handle = device->acpi_handle; ++ ++ /* ++ * Sx States: ++ * ---------- ++ * Figure out which Sx states are supported. ++ */ ++ for (i=0; i<SM_MAX_SYSTEM_STATES; i++) { ++ if (ACPI_SUCCESS(acpi_hw_obtain_sleep_type_register_data( ++ i, ++ &type_a, ++ &type_b))) { ++ system->states[i] = TRUE; ++ } ++ } ++ ++ status = sm_osl_add_device(system); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ *context = system; ++ ++ sm_print(system); ++ ++end: ++ if (ACPI_FAILURE(status)) { ++ acpi_os_free(system); ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: sm_remove_device ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++sm_remove_device ( ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ SM_CONTEXT *system = NULL; ++ ++ if (!context || !*context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ system = (SM_CONTEXT*)*context; ++ ++ status = sm_osl_remove_device(system); ++ ++ acpi_os_free(system); ++ ++ *context = NULL; ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * External Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: sm_initialize ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++sm_initialize (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE_ID criteria; ++ BM_DRIVER driver; ++ ++ MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); ++ MEMSET(&driver, 0, sizeof(BM_DRIVER)); ++ ++ /* ++ * Register driver for the System device. ++ */ ++ criteria.type = BM_TYPE_SYSTEM; ++ ++ driver.notify = &sm_notify; ++ driver.request = &sm_request; ++ ++ status = bm_register_driver(&criteria, &driver); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: sm_terminate ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++sm_terminate (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE_ID criteria; ++ BM_DRIVER driver; ++ ++ MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); ++ MEMSET(&driver, 0, sizeof(BM_DRIVER)); ++ ++ /* ++ * Unregister driver for System devices. ++ */ ++ criteria.type = BM_TYPE_SYSTEM; ++ ++ driver.notify = &sm_notify; ++ driver.request = &sm_request; ++ ++ status = bm_unregister_driver(&criteria, &driver); ++ ++ return(status); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: sm_notify ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ACPI_STATUS ++sm_notify ( ++ BM_NOTIFY notify_type, ++ BM_HANDLE device_handle, ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ switch (notify_type) { ++ ++ case BM_NOTIFY_DEVICE_ADDED: ++ status = sm_add_device(device_handle, context); ++ break; ++ ++ case BM_NOTIFY_DEVICE_REMOVED: ++ status = sm_remove_device(context); ++ break; ++ ++ default: ++ status = AE_SUPPORT; ++ break; ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: sm_request ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++sm_request ( ++ BM_REQUEST *request, ++ void *context) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ /* ++ * Must have a valid request structure and context. ++ */ ++ if (!request || !context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Handle Request: ++ * --------------- ++ */ ++ switch (request->command) { ++ ++ default: ++ status = AE_SUPPORT; ++ break; ++ } ++ ++ request->status = status; ++ ++ return(status); ++} +\ No newline at end of file +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/system/sm_osl.c linux/drivers/acpi/ospm/system/sm_osl.c +--- /usr/src/linux/drivers/acpi/ospm/system/sm_osl.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/system/sm_osl.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,269 @@ ++/****************************************************************************** ++ * ++ * Module Name: sm_osl.c ++ * $Revision: 8 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/types.h> ++#include <linux/proc_fs.h> ++#include <linux/pm.h> ++ ++#include <acpi.h> ++#include "sm.h" ++ ++ ++MODULE_AUTHOR("Andrew Grover"); ++MODULE_DESCRIPTION("ACPI Component Architecture (CA) - ACPI System Driver"); ++ ++ ++#define SM_PROC_INFO "info" ++ ++extern struct proc_dir_entry *bm_proc_root; ++struct proc_dir_entry *sm_proc_root = NULL; ++static void (*sm_pm_power_off)(void) = NULL; ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: sm_osl_proc_read_info ++ * ++ ****************************************************************************/ ++ ++static int ++sm_osl_proc_read_info ( ++ char *page, ++ char **start, ++ off_t off, ++ int count, ++ int *eof, ++ void *context) ++{ ++ ACPI_STATUS status = AE_OK; ++ SM_CONTEXT *system = NULL; ++ char *p = page; ++ int len; ++ ACPI_SYSTEM_INFO system_info; ++ ACPI_BUFFER buffer; ++ u32 i = 0; ++ ++ if (!context) { ++ goto end; ++ } ++ ++ system = (SM_CONTEXT*)context; ++ ++ /* don't get status more than once for a single proc read */ ++ if (off != 0) { ++ goto end; ++ } ++ ++ /* ++ * Get ACPI CA Information. ++ */ ++ buffer.length = sizeof(system_info); ++ buffer.pointer = &system_info; ++ ++ status = acpi_get_system_info(&buffer); ++ if (ACPI_FAILURE(status)) { ++ p += sprintf(p, "ACPI-CA Version: unknown\n"); ++ } ++ else { ++ p += sprintf(p, "ACPI-CA Version: %x\n", ++ system_info.acpi_ca_version); ++ } ++ ++ p += sprintf(p, "Sx States Supported: "); ++ for (i=0; i<SM_MAX_SYSTEM_STATES; i++) { ++ if (system->states[i]) { ++ p += sprintf(p, "S%d ", i); ++ } ++ } ++ p += sprintf(p, "\n"); ++ ++end: ++ len = (p - page); ++ if (len <= off+count) *eof = 1; ++ *start = page + off; ++ len -= off; ++ if (len>count) len = count; ++ if (len<0) len = 0; ++ ++ return(len); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: sm_osl_power_down ++ * ++ ****************************************************************************/ ++ ++void ++sm_osl_power_down (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ /* Power down the system (S5 = soft off). */ ++ status = acpi_enter_sleep_state(ACPI_STATE_S5); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: sm_osl_add_device ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++sm_osl_add_device( ++ SM_CONTEXT *system) ++{ ++ u32 i = 0; ++ ++ if (!system) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ printk("ACPI: System firmware supports"); ++ for (i=0; i<SM_MAX_SYSTEM_STATES; i++) { ++ if (system->states[i]) { ++ printk(" S%d", i); ++ } ++ } ++ printk("\n"); ++ ++ if (system->states[ACPI_STATE_S5]) { ++ sm_pm_power_off = pm_power_off; ++ pm_power_off = sm_osl_power_down; ++ } ++ ++ create_proc_read_entry(SM_PROC_INFO, S_IFREG | S_IRUGO, ++ sm_proc_root, sm_osl_proc_read_info, (void*)system); ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: sm_osl_remove_device ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++sm_osl_remove_device ( ++ SM_CONTEXT *system) ++{ ++ if (!system) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ remove_proc_entry(SM_PROC_INFO, sm_proc_root); ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: sm_osl_generate_event ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++sm_osl_generate_event ( ++ u32 event, ++ SM_CONTEXT *system) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!system) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ switch (event) { ++ ++ default: ++ return(AE_BAD_PARAMETER); ++ break; ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: sm_osl_init ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: 0: Success ++ * ++ * DESCRIPTION: Module initialization. ++ * ++ ****************************************************************************/ ++ ++static int __init ++sm_osl_init (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ sm_proc_root = bm_proc_root; ++ if (!sm_proc_root) { ++ status = AE_ERROR; ++ } ++ else { ++ status = sm_initialize(); ++ } ++ ++ return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: sm_osl_cleanup ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <none> ++ * ++ * DESCRIPTION: Module cleanup. ++ * ++ ****************************************************************************/ ++ ++static void __exit ++sm_osl_cleanup (void) ++{ ++ sm_terminate(); ++ ++ return; ++} ++ ++ ++module_init(sm_osl_init); ++module_exit(sm_osl_cleanup); +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/thermal/Makefile linux/drivers/acpi/ospm/thermal/Makefile +--- /usr/src/linux/drivers/acpi/ospm/thermal/Makefile Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/thermal/Makefile Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,23 @@ ++# ++# Makefile for all Linux ACPI interpreter subdirectories ++# ++ ++O_TARGET := ../$(shell basename `pwd`).o ++ ++EXTRA_CFLAGS += -I../../include -I../include ++ ++EXTRA_CFLAGS += $(ACPI_CFLAGS) ++ ++list-multi := thermal.o ++thermal-objs := $(patsubst %.c,%.o,$(wildcard *.c)) ++ ++obj-$(CONFIG_ACPI_THERMAL) := thermal.o ++ ++include $(TOPDIR)/Rules.make ++ ++clean: ++ $(RM) *.o ++ ++thermal.o: $(thermal-objs) ++ $(LD) -r -o $@ $(thermal-objs) ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/thermal/tz.c linux/drivers/acpi/ospm/thermal/tz.c +--- /usr/src/linux/drivers/acpi/ospm/thermal/tz.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/thermal/tz.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,661 @@ ++/***************************************************************************** ++ * ++ * Module Name: tz.c ++ * $Revision: 35 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * 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 ++ */ ++ ++/* ++ * TODO: ++ * ----- ++ * 0. Finish /proc interface (threshold values, _SCP changes, etc.) ++ * 1. Update policy for ACPI 2.0 compliance ++ * 2. Check for all required methods prior to enabling a threshold ++ * 3. Support for multiple processors in a zone (passive cooling devices) ++ */ ++ ++#include <acpi.h> ++#include <bm.h> ++#include "tz.h" ++ ++#define _COMPONENT ACPI_THERMAL_ZONE ++ MODULE_NAME ("tz") ++ ++ ++/**************************************************************************** ++ * Internal Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_print ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: Prints out information on a specific thermal zone. ++ * ++ ****************************************************************************/ ++ ++void ++tz_print ( ++ TZ_CONTEXT *thermal_zone) ++{ ++ ++ return; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_get_temperaturee ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++tz_get_temperature ( ++ TZ_CONTEXT *thermal_zone, ++ u32 *temperature) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!thermal_zone || !temperature) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Evaluate the _TMP driver method to get the current temperature. ++ */ ++ status = bm_evaluate_simple_integer(thermal_zone->acpi_handle, ++ "_TMP", temperature); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_set_cooling_preference ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++tz_set_cooling_preference ( ++ TZ_CONTEXT *thermal_zone, ++ TZ_COOLING_MODE cooling_mode) ++{ ++ ACPI_STATUS status = AE_OK; ++ ACPI_OBJECT_LIST arg_list; ++ ACPI_OBJECT arg0; ++ ++ if (!thermal_zone || ((cooling_mode != TZ_COOLING_MODE_ACTIVE) && ++ (cooling_mode != TZ_COOLING_MODE_PASSIVE))) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Build the argument list, which simply consists of the current ++ * cooling preference. ++ */ ++ MEMSET(&arg_list, 0, sizeof(ACPI_OBJECT)); ++ arg_list.count = 1; ++ arg_list.pointer = &arg0; ++ ++ MEMSET(&arg0, 0, sizeof(ACPI_OBJECT)); ++ arg0.type = ACPI_TYPE_INTEGER; ++ arg0.integer.value = cooling_mode; ++ ++ /* ++ * Evaluate "_SCP" - setting the new cooling preference. ++ */ ++ status = acpi_evaluate_object(thermal_zone->acpi_handle, "_SCP", ++ &arg_list, NULL); ++ ++ return(status); ++} ++ ++ ++/*************************************************************************** ++ * ++ * FUNCTION: tz_get_single_threshold ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++tz_get_single_threshold ( ++ TZ_CONTEXT *thermal_zone, ++ TZ_THRESHOLD *threshold) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!thermal_zone || !threshold) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ switch (threshold->type) { ++ ++ /* ++ * Critical Threshold: ++ * ------------------- ++ */ ++ case TZ_THRESHOLD_CRITICAL: ++ threshold->index = 0; ++ threshold->cooling_devices.count = 0; ++ status = bm_evaluate_simple_integer( ++ thermal_zone->acpi_handle, "_CRT", ++ &(threshold->temperature)); ++ break; ++ ++ /* ++ * Passive Threshold: ++ * ------------------ ++ * Evaluate _PSV to get the threshold temperature and _PSL to get ++ * references to all passive cooling devices. ++ */ ++ case TZ_THRESHOLD_PASSIVE: ++ threshold->index = 0; ++ threshold->cooling_devices.count = 0; ++ status = bm_evaluate_simple_integer( ++ thermal_zone->acpi_handle, "_PSV", ++ &(threshold->temperature)); ++ if (ACPI_SUCCESS(status)) { ++ status = bm_evaluate_reference_list( ++ thermal_zone->acpi_handle, "_PSL", ++ &(threshold->cooling_devices)); ++ } ++ ++ break; ++ ++ /* ++ * Active Thresholds: ++ * ------------------ ++ * Evaluate _ACx to get all threshold temperatures, and _ALx to get ++ * references to all passive cooling devices. ++ */ ++ case TZ_THRESHOLD_ACTIVE: ++ { ++ char object_name[5] = {'_','A', 'C', ++ ('0'+threshold->index),'\0'}; ++ status = bm_evaluate_simple_integer( ++ thermal_zone->acpi_handle, object_name, ++ &(threshold->temperature)); ++ if (ACPI_SUCCESS(status)) { ++ object_name[2] = 'L'; ++ status = bm_evaluate_reference_list( ++ thermal_zone->acpi_handle, ++ object_name, ++ &(threshold->cooling_devices)); ++ } ++ } ++ break; ++ ++ default: ++ status = AE_SUPPORT; ++ break; ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_get_thresholds ++ * ++ * PARAMETERS: thermal_zone - Identifies the thermal zone to parse. ++ * buffer - Output buffer. ++ * ++ * RETURN: ACPI_STATUS result code. ++ * ++ * DESCRIPTION: Builds a TZ_THRESHOLD_LIST structure containing information ++ * on all thresholds for a given thermal zone. ++ * ++ * NOTES: The current design limits the number of cooling devices ++ * per theshold to the value specified by BM_MAX_HANDLES. ++ * This simplifies parsing of thresholds by allowing a maximum ++ * threshold list size to be computed (and enforced) -- which ++ * allows all thresholds to be parsed in a single pass (since ++ * memory must be contiguous when returned in the ACPI_BUFFER). ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++tz_get_thresholds ( ++ TZ_CONTEXT *thermal_zone, ++ TZ_THRESHOLD_LIST *threshold_list) ++{ ++ ACPI_STATUS status = AE_OK; ++ TZ_THRESHOLD *threshold = NULL; ++ u32 i = 0; ++ ++ if (!thermal_zone || !threshold_list) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ threshold_list->count = 0; ++ ++ /* ++ * Critical threshold: ++ * ------------------- ++ * Every thermal zone must have one! ++ */ ++ threshold = &(threshold_list->thresholds[threshold_list->count]); ++ threshold->type = TZ_THRESHOLD_CRITICAL; ++ ++ status = tz_get_single_threshold(thermal_zone, threshold); ++ if (ACPI_SUCCESS(status)) { ++ (threshold_list->count)++; ++ } ++ else { ++ return(status); ++ } ++ ++ ++ /* ++ * Passive threshold: ++ * ------------------ ++ */ ++ threshold = &(threshold_list->thresholds[threshold_list->count]); ++ threshold->type = TZ_THRESHOLD_PASSIVE; ++ ++ status = tz_get_single_threshold(thermal_zone, threshold); ++ if (ACPI_SUCCESS(status)) { ++ (threshold_list->count)++; ++ } ++ ++ /* ++ * Active threshold: ++ * ----------------- ++ * Note that active thresholds are sorted by index (e.g. _AC0, ++ * _AC1, ...), and thus from highest (_AC0) to lowest (_AC9) ++ * temperature. ++ */ ++ for (i = 0; i < TZ_MAX_ACTIVE_THRESHOLDS; i++) { ++ ++ threshold = &(threshold_list->thresholds[threshold_list->count]); ++ threshold->type = TZ_THRESHOLD_ACTIVE; ++ threshold->index = i; ++ ++ status = tz_get_single_threshold(thermal_zone, threshold); ++ if (ACPI_SUCCESS(status)) { ++ (threshold_list->count)++; ++ } ++ else { ++ threshold->type = TZ_THRESHOLD_UNKNOWN; ++ threshold->index = 0; ++ thermal_zone->policy.active.threshold_count = i; ++ break; ++ } ++ } ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_add_device ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++tz_add_device ( ++ BM_HANDLE device_handle, ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ TZ_CONTEXT *thermal_zone = NULL; ++ BM_DEVICE *device = NULL; ++ ACPI_HANDLE tmp_handle = NULL; ++ static u32 zone_count = 0; ++ ++ if (!context || *context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Get information on this device. ++ */ ++ status = bm_get_device_info(device_handle, &device); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ /* ++ * Allocate a new Thermal Zone device. ++ */ ++ thermal_zone = acpi_os_callocate(sizeof(TZ_CONTEXT)); ++ if (!thermal_zone) { ++ return AE_NO_MEMORY; ++ } ++ ++ thermal_zone->device_handle = device->handle; ++ thermal_zone->acpi_handle = device->acpi_handle; ++ ++ /* TODO: How to manage 'uid' when zones are Pn_p? */ ++ sprintf(thermal_zone->uid, "%d", zone_count++); ++ ++ /* ++ * _TMP? ++ * ----- ++ */ ++ status = acpi_get_handle(thermal_zone->acpi_handle, "_TMP", ++ &tmp_handle); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ /* ++ * Initialize Policy: ++ * ------------------ ++ * TODO: Move all thermal zone policy to user-mode daemon... ++ */ ++ status = tz_policy_add_device(thermal_zone); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ status = tz_osl_add_device(thermal_zone); ++ if (ACPI_FAILURE(status)) { ++ goto end; ++ } ++ ++ *context = thermal_zone; ++ ++ tz_print(thermal_zone); ++ ++end: ++ if (ACPI_FAILURE(status)) { ++ acpi_os_free(thermal_zone); ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_remove_device ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++tz_remove_device ( ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ TZ_CONTEXT *thermal_zone = NULL; ++ ++ if (!context || !*context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ thermal_zone = (TZ_CONTEXT*)(*context); ++ ++ status = tz_osl_remove_device(thermal_zone); ++ ++ /* ++ * Remove Policy: ++ * -------------- ++ * TODO: Move all thermal zone policy to user-mode daemon... ++ */ ++ status = tz_policy_remove_device(thermal_zone); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ acpi_os_free(thermal_zone); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * External Functions ++ ****************************************************************************/ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_initialize ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++tz_initialize (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE_ID criteria; ++ BM_DRIVER driver; ++ ++ MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); ++ MEMSET(&driver, 0, sizeof(BM_DRIVER)); ++ ++ /* ++ * Register driver for thermal zone devices. ++ */ ++ criteria.type = BM_TYPE_THERMAL_ZONE; ++ ++ driver.notify = &tz_notify; ++ driver.request = &tz_request; ++ ++ status = bm_register_driver(&criteria, &driver); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_terminate ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++tz_terminate (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ BM_DEVICE_ID criteria; ++ BM_DRIVER driver; ++ ++ MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); ++ MEMSET(&driver, 0, sizeof(BM_DRIVER)); ++ ++ /* ++ * Unregister driver for thermal zone devices. ++ */ ++ criteria.type = BM_TYPE_THERMAL_ZONE; ++ ++ driver.notify = &tz_notify; ++ driver.request = &tz_request; ++ ++ status = bm_unregister_driver(&criteria, &driver); ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_notify ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ACPI_STATUS ++tz_notify ( ++ BM_NOTIFY notify_type, ++ BM_HANDLE device_handle, ++ void **context) ++{ ++ ACPI_STATUS status = AE_OK; ++ TZ_CONTEXT *thermal_zone = NULL; ++ ++ if (!context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ thermal_zone = (TZ_CONTEXT*)*context; ++ ++ switch (notify_type) { ++ ++ case BM_NOTIFY_DEVICE_ADDED: ++ status = tz_add_device(device_handle, context); ++ break; ++ ++ case BM_NOTIFY_DEVICE_REMOVED: ++ status = tz_remove_device(context); ++ break; ++ ++ case TZ_NOTIFY_TEMPERATURE_CHANGE: ++ /* -------------------------------------------- */ ++ /* TODO: Remove when policy moves to user-mode. */ ++ tz_policy_check(*context); ++ /* -------------------------------------------- */ ++ status = tz_get_temperature(thermal_zone, ++ &(thermal_zone->policy.temperature)); ++ if (ACPI_SUCCESS(status)) { ++ status = tz_osl_generate_event(notify_type, ++ thermal_zone); ++ } ++ break; ++ ++ case TZ_NOTIFY_THRESHOLD_CHANGE: ++ /* -------------------------------------------- */ ++ /* TODO: Remove when policy moves to user-mode. */ ++ status = tz_policy_remove_device(thermal_zone); ++ if (ACPI_SUCCESS(status)) { ++ status = tz_policy_add_device(thermal_zone); ++ } ++ /* -------------------------------------------- */ ++ status = tz_osl_generate_event(notify_type, thermal_zone); ++ break; ++ ++ case TZ_NOTIFY_DEVICE_LISTS_CHANGE: ++ /* -------------------------------------------- */ ++ /* TODO: Remove when policy moves to user-mode. */ ++ status = tz_policy_remove_device(thermal_zone); ++ if (ACPI_SUCCESS(status)) { ++ status = tz_policy_add_device(thermal_zone); ++ } ++ /* -------------------------------------------- */ ++ status = tz_osl_generate_event(notify_type, thermal_zone); ++ break; ++ ++ default: ++ status = AE_SUPPORT; ++ break; ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_request ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: Exception code. ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++tz_request ( ++ BM_REQUEST *request, ++ void *context) ++{ ++ ACPI_STATUS status = AE_OK; ++ TZ_CONTEXT *thermal_zone = NULL; ++ ++ /* ++ * Must have a valid request structure and context. ++ */ ++ if (!request || !context) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ thermal_zone = (TZ_CONTEXT*)context; ++ ++ /* ++ * Handle request: ++ * --------------- ++ */ ++ switch (request->command) { ++ ++ default: ++ status = AE_SUPPORT; ++ break; ++ } ++ ++ request->status = status; ++ ++ return(status); ++} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/thermal/tz_osl.c linux/drivers/acpi/ospm/thermal/tz_osl.c +--- /usr/src/linux/drivers/acpi/ospm/thermal/tz_osl.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/thermal/tz_osl.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,342 @@ ++/****************************************************************************** ++ * ++ * Module Name: tz_osl.c ++ * $Revision: 17 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/types.h> ++#include <linux/proc_fs.h> ++#include <acpi.h> ++#include "tz.h" ++ ++ ++MODULE_AUTHOR("Andrew Grover"); ++MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Thermal Zone Driver"); ++ ++int TZP = 0; ++MODULE_PARM(TZP, "i"); ++MODULE_PARM_DESC(TZP, "Thermal zone polling frequency, in 1/10 seconds.\n"); ++ ++ ++#define TZ_PROC_ROOT "thermal" ++#define TZ_PROC_STATUS "status" ++#define TZ_PROC_INFO "info" ++ ++extern struct proc_dir_entry *bm_proc_root; ++static struct proc_dir_entry *tz_proc_root = NULL; ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_osl_proc_read_info ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++static int ++tz_osl_proc_read_info ( ++ char *page, ++ char **start, ++ off_t off, ++ int count, ++ int *eof, ++ void *context) ++{ ++ TZ_CONTEXT *thermal_zone = NULL; ++ char *p = page; ++ int len = 0; ++ ++ if (!context || (off != 0)) { ++ goto end; ++ } ++ ++ thermal_zone = (TZ_CONTEXT*)context; ++ ++ p += sprintf(p, "<TBD>\n"); ++ ++end: ++ len = (p - page); ++ if (len <= off+count) *eof = 1; ++ *start = page + off; ++ len -= off; ++ if (len>count) len = count; ++ if (len<0) len = 0; ++ ++ return(len); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_osl_proc_read_status ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++static int ++tz_osl_proc_read_status ( ++ char *page, ++ char **start, ++ off_t off, ++ int count, ++ int *eof, ++ void *context) ++{ ++ TZ_CONTEXT *thermal_zone = NULL; ++ char *p = page; ++ int len = 0; ++ ++ if (!context || (off != 0)) { ++ goto end; ++ } ++ ++ thermal_zone = (TZ_CONTEXT*)context; ++ ++ p += sprintf(p, "Temperature: %d (1/10th degrees Kelvin)\n", ++ thermal_zone->policy.temperature); ++ ++ p += sprintf(p, "State: "); ++ if (thermal_zone->policy.state & TZ_STATE_ACTIVE) { ++ p += sprintf(p, "active[%d] ", thermal_zone->policy.state & 0x07); ++ } ++ if (thermal_zone->policy.state & TZ_STATE_PASSIVE) { ++ p += sprintf(p, "passive "); ++ } ++ if (thermal_zone->policy.state & TZ_STATE_CRITICAL) { ++ p += sprintf(p, "critical "); ++ } ++ if (thermal_zone->policy.state == 0) { ++ p += sprintf(p, "ok "); ++ } ++ p += sprintf(p, "\n"); ++ ++ p += sprintf(p, "Cooling Mode: "); ++ switch (thermal_zone->policy.cooling_mode) { ++ case TZ_COOLING_MODE_ACTIVE: ++ p += sprintf(p, "active (noisy)\n"); ++ break; ++ case TZ_COOLING_MODE_PASSIVE: ++ p += sprintf(p, "passive (quiet)\n"); ++ break; ++ default: ++ p += sprintf(p, "unknown\n"); ++ break; ++ } ++ ++ p += sprintf(p, "Polling Frequency: "); ++ switch (thermal_zone->policy.polling_freq) { ++ case 0: ++ p += sprintf(p, "n/a\n"); ++ break; ++ default: ++ p += sprintf(p, "%d (1/10th seconds)\n", thermal_zone->policy.polling_freq); ++ break; ++ } ++ ++end: ++ len = (p - page); ++ if (len <= off+count) *eof = 1; ++ *start = page + off; ++ len -= off; ++ if (len>count) len = count; ++ if (len<0) len = 0; ++ ++ return(len); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_osl_add_device ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++tz_osl_add_device( ++ TZ_CONTEXT *thermal_zone) ++{ ++ struct proc_dir_entry *proc_entry = NULL; ++ ++ if (!thermal_zone) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ printk("Thermal Zone: found\n"); ++ ++ proc_entry = proc_mkdir(thermal_zone->uid, tz_proc_root); ++ if (!proc_entry) { ++ return(AE_ERROR); ++ } ++ ++ create_proc_read_entry(TZ_PROC_STATUS, S_IFREG | S_IRUGO, ++ proc_entry, tz_osl_proc_read_status, (void*)thermal_zone); ++ ++ create_proc_read_entry(TZ_PROC_INFO, S_IFREG | S_IRUGO, ++ proc_entry, tz_osl_proc_read_info, (void*)thermal_zone); ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_osl_remove_device ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++tz_osl_remove_device ( ++ TZ_CONTEXT *thermal_zone) ++{ ++ char proc_entry[64]; ++ ++ if (!thermal_zone) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ sprintf(proc_entry, "%s/%s", thermal_zone->uid, TZ_PROC_INFO); ++ remove_proc_entry(proc_entry, tz_proc_root); ++ ++ sprintf(proc_entry, "%s/%s", thermal_zone->uid, TZ_PROC_STATUS); ++ remove_proc_entry(proc_entry, tz_proc_root); ++ ++ sprintf(proc_entry, "%s", thermal_zone->uid); ++ remove_proc_entry(proc_entry, tz_proc_root); ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_osl_generate_event ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++tz_osl_generate_event ( ++ u32 event, ++ TZ_CONTEXT *thermal_zone) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!thermal_zone) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ switch (event) { ++ ++ case TZ_NOTIFY_TEMPERATURE_CHANGE: ++ status = bm_osl_generate_event(thermal_zone->device_handle, ++ TZ_PROC_ROOT, thermal_zone->uid, event, ++ thermal_zone->policy.temperature); ++ break; ++ ++ case TZ_NOTIFY_THRESHOLD_CHANGE: ++ case TZ_NOTIFY_DEVICE_LISTS_CHANGE: ++ status = bm_osl_generate_event(thermal_zone->device_handle, ++ TZ_PROC_ROOT, thermal_zone->uid, event, 0); ++ break; ++ ++ default: ++ return(AE_BAD_PARAMETER); ++ break; ++ } ++ ++ return(status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_osl_init ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: 0: Success ++ * ++ * DESCRIPTION: Module initialization. ++ * ++ ****************************************************************************/ ++ ++static int __init ++tz_osl_init (void) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ tz_proc_root = proc_mkdir(TZ_PROC_ROOT, bm_proc_root); ++ if (!tz_proc_root) { ++ status = AE_ERROR; ++ } ++ else { ++ status = tz_initialize(); ++ if (ACPI_FAILURE(status)) { ++ remove_proc_entry(TZ_PROC_ROOT, bm_proc_root); ++ } ++ ++ } ++ ++ return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_osl_cleanup ++ * ++ * PARAMETERS: <none> ++ * ++ * RETURN: <none> ++ * ++ * DESCRIPTION: Module cleanup. ++ * ++ ****************************************************************************/ ++ ++static void __exit ++tz_osl_cleanup (void) ++{ ++ tz_terminate(); ++ ++ if (tz_proc_root) { ++ remove_proc_entry(TZ_PROC_ROOT, bm_proc_root); ++ } ++ ++ return; ++} ++ ++ ++module_init(tz_osl_init); ++module_exit(tz_osl_cleanup); +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/ospm/thermal/tzpolicy.c linux/drivers/acpi/ospm/thermal/tzpolicy.c +--- /usr/src/linux/drivers/acpi/ospm/thermal/tzpolicy.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/ospm/thermal/tzpolicy.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,645 @@ ++/**************************************************************************** ++ * ++ * Module Name: tzpolicy.c - <TBD> ++ * $Revision: 22 $ ++ * ++ ****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 Andrew Grover ++ * ++ * 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 ++ */ ++ ++/* ++ * TODO: ++ * ----- ++ * 1. Support ACPI 2.0 items (e.g. _TZD, _HOT). ++ * 2. Support performance-limit control for non-processor devices ++ * (those listed in _TZD, e.g. graphics). ++ */ ++ ++/* TODO: Linux specific */ ++#include <linux/proc_fs.h> ++#include <linux/sysctl.h> ++#include <linux/pm.h> ++ ++#include <acpi.h> ++#include <bm.h> ++#include "tz.h" ++ ++ ++#define _COMPONENT ACPI_THERMAL_ZONE ++ MODULE_NAME ("tzpolicy") ++ ++ ++/**************************************************************************** ++ * Globals ++ ****************************************************************************/ ++ ++extern int TZP; ++ ++void ++tz_policy_run ( ++ unsigned long data); ++ ++ ++/**************************************************************************** ++ * Internal Functions ++ ****************************************************************************/ ++ ++ACPI_STATUS ++set_performance_limit ( ++ BM_HANDLE device_handle, ++ u32 flag) ++{ ++ ACPI_STATUS status; ++ BM_REQUEST request; ++ ++ request.status = AE_OK; ++ request.handle = device_handle; ++ request.command = PR_COMMAND_SET_PERF_LIMIT; ++ request.buffer.length = sizeof(u32); ++ request.buffer.pointer = &flag; ++ ++ status = bm_request(&request); ++ ++ if (ACPI_FAILURE(status)) { ++ return status; ++ } ++ else { ++ return request.status; ++ } ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_policy_critical ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ * TODO: 1. Need method for calling 'halt' - OSL function? ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++tz_policy_critical( ++ TZ_CONTEXT *tz) ++{ ++ if (!tz || !tz->policy.critical.threshold) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ if (tz->policy.temperature >= ++ tz->policy.critical.threshold->temperature) { ++ /* TODO: 'halt' */ ++ } ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_policy_passive ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++tz_policy_passive( ++ TZ_CONTEXT *tz) ++{ ++ TZ_PASSIVE_POLICY *passive = NULL; ++ static u32 last_temperature = 0; ++ s32 trend = 0; ++ u32 i = 0; ++ ++ if (!tz || !tz->policy.passive.threshold) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ passive = &(tz->policy.passive); ++ ++ if (tz->policy.temperature >= passive->threshold->temperature) { ++ /* ++ * Thermal trend? ++ * -------------- ++ * Using the passive cooling equation (see the ACPI ++ * Specification), calculate the current thermal trend ++ * (a.k.a. performance delta). ++ */ ++ trend = passive->tc1 * ++ (tz->policy.temperature - last_temperature) + ++ passive->tc2 * ++ (tz->policy.temperature - passive->threshold->temperature); ++ ++ last_temperature = tz->policy.temperature; ++ ++ /* ++ * Heating Up? ++ * ----------- ++ * Decrease thermal performance limit on all passive ++ * cooling devices (processors). ++ */ ++ if (trend > 0) { ++ for (i=0; i<passive->threshold->cooling_devices.count; i++) { ++ set_performance_limit( ++ passive->threshold->cooling_devices.handles[i], ++ PR_PERF_DEC); ++ } ++ } ++ /* ++ * Cooling Off? ++ * ------------ ++ * Increase thermal performance limit on all passive ++ * cooling devices (processors). ++ */ ++ else if (trend < 0) { ++ for (i=0; i<passive->threshold->cooling_devices.count; i++) { ++ set_performance_limit( ++ passive->threshold->cooling_devices.handles[i], ++ PR_PERF_INC); ++ } ++ } ++ } ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_policy_active ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++tz_policy_active( ++ TZ_CONTEXT *tz) ++{ ++ ACPI_STATUS status = AE_OK; ++ TZ_THRESHOLD *active = NULL; ++ u32 i,j = 0; ++ ++ if (!tz || !tz->policy.active.threshold) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ for (i = 0; i < TZ_MAX_ACTIVE_THRESHOLDS; i++) { ++ ++ active = tz->policy.active.threshold[i]; ++ if (!active) { ++ break; ++ } ++ ++ /* ++ * Above Threshold? ++ * ---------------- ++ * If not already enabled, turn ON all cooling devices ++ * associated with this active threshold. ++ */ ++ if ((tz->policy.temperature >= active->temperature) && ++ (active->cooling_state != TZ_COOLING_ENABLED)) { ++ ++ for (j = 0; j < active->cooling_devices.count; j++) { ++ ++ status = bm_set_device_power_state( ++ active->cooling_devices.handles[j], ++ ACPI_STATE_D0); ++ ++ if (ACPI_SUCCESS(status)) { ++ } ++ else { ++ } ++ } ++ ++ active->cooling_state = TZ_COOLING_ENABLED; ++ } ++ /* ++ * Below Threshold? ++ * ---------------- ++ * Turn OFF all cooling devices associated with this ++ * threshold. Note that by checking "if not disabled" we ++ * turn off all cooling devices for thresholds in the ++ * TZ_COOLING_STATE_UNKNOWN state, useful as a level-set ++ * during the first pass. ++ */ ++ else if (active->cooling_state != TZ_COOLING_DISABLED) { ++ ++ for (j = 0; j < active->cooling_devices.count; j++) { ++ ++ status = bm_set_device_power_state( ++ active->cooling_devices.handles[j], ++ ACPI_STATE_D3); ++ ++ if (ACPI_SUCCESS(status)) { ++ } ++ else { ++ } ++ } ++ ++ active->cooling_state = TZ_COOLING_DISABLED; ++ } ++ } ++ ++ return(AE_OK); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_policy_check ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: Note that this function will get called whenever: ++ * 1. A thermal event occurs. ++ * 2. The polling/sampling time period expires. ++ * ++ ****************************************************************************/ ++ ++void ++tz_policy_check ( ++ void *context) ++{ ++ ACPI_STATUS status = AE_OK; ++ TZ_CONTEXT *tz = NULL; ++ u32 previous_temperature = 0; ++ u32 previous_state = 0; ++ u32 active_index = 0; ++ u32 i = 0; ++ u32 sleep_time = 0; ++ ++ if (!context) { ++ return; ++ } ++ ++ tz = (TZ_CONTEXT*)context; ++ ++ /* ++ * Preserve Previous State: ++ * ------------------------ ++ */ ++ previous_temperature = tz->policy.temperature; ++ previous_state = tz->policy.state; ++ ++ /* ++ * Get Temperature: ++ * ---------------- ++ */ ++ status = tz_get_temperature(tz, &(tz->policy.temperature)); ++ if (ACPI_FAILURE(status)) { ++ return; ++ } ++ ++ /* ++ * Calculate State: ++ * ---------------- ++ */ ++ tz->policy.state = TZ_STATE_OK; ++ ++ /* Critical? */ ++ if ((tz->policy.critical.threshold) && ++ (tz->policy.temperature >= tz->policy.critical.threshold->temperature)) { ++ tz->policy.state |= TZ_STATE_CRITICAL; ++ } ++ ++ /* Passive? */ ++ if ((tz->policy.passive.threshold) && ++ (tz->policy.temperature >= tz->policy.passive.threshold->temperature)) { ++ tz->policy.state |= TZ_STATE_PASSIVE; ++ } ++ ++ /* Active? */ ++ if (tz->policy.active.threshold[0]) { ++ for (i=0; i<tz->policy.active.threshold_count; i++) { ++ if ((tz->policy.active.threshold[i]) && ++ (tz->policy.temperature >= tz->policy.active.threshold[i]->temperature)) { ++ tz->policy.state |= TZ_STATE_ACTIVE; ++ if (tz->policy.active.threshold[i]->index > active_index) { ++ active_index = tz->policy.active.threshold[i]->index; ++ } ++ } ++ } ++ tz->policy.state |= active_index; ++ } ++ ++ /* ++ * Invoke Policy: ++ * -------------- ++ * Note that policy must be invoked both when 'going into' a ++ * policy state (e.g. to allow fans to be turned on) and 'going ++ * out of' a policy state (e.g. to allow fans to be turned off); ++ * thus we must preserve the previous state. ++ */ ++ if (tz->policy.state & TZ_STATE_CRITICAL) { ++ tz_policy_critical(tz); ++ } ++ if ((tz->policy.state & TZ_STATE_PASSIVE) || ++ (previous_state & TZ_STATE_PASSIVE)) { ++ tz_policy_passive(tz); ++ } ++ if ((tz->policy.state & TZ_STATE_ACTIVE) || ++ (previous_state & TZ_STATE_ACTIVE)) { ++ tz_policy_active(tz); ++ } ++ ++ /* ++ * Calculate Sleep Time: ++ * --------------------- ++ * If we're in the passive state, use _TSP's value. Otherwise ++ * use _TZP or the OS's default polling frequency. If no polling ++ * frequency is specified then we'll wait forever (that is, until ++ * a thermal event occurs -- e.g. never poll). Note that _TSP ++ * and _TZD values are given in 1/10th seconds. ++ */ ++ if (tz->policy.state & TZ_STATE_PASSIVE) { ++ sleep_time = tz->policy.passive.tsp * 100; ++ } ++ else if (tz->policy.polling_freq > 0) { ++ sleep_time = tz->policy.polling_freq * 100; ++ } ++ else { ++ sleep_time = WAIT_FOREVER; ++ } ++ ++ ++ /* ++ * Schedule Next Poll: ++ * ------------------- ++ */ ++ if (sleep_time < WAIT_FOREVER) { ++ if (timer_pending(&(tz->policy.timer))) { ++ mod_timer(&(tz->policy.timer), ++ (HZ*sleep_time)/1000); ++ } ++ else { ++ tz->policy.timer.data = (u32)tz; ++ tz->policy.timer.function = tz_policy_run; ++ tz->policy.timer.expires = ++ jiffies + (HZ*sleep_time)/1000; ++ add_timer(&(tz->policy.timer)); ++ } ++ } ++ else { ++ if (timer_pending(&(tz->policy.timer))) { ++ del_timer(&(tz->policy.timer)); ++ } ++ } ++ ++ return; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_policy_run ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++void ++tz_policy_run ( ++ unsigned long data) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ if (!data) { ++ return; ++ } ++ ++ /* ++ * Defer to Non-Interrupt Level: ++ * ----------------------------- ++ * Note that all Linux kernel timers run at interrupt-level (ack!). ++ */ ++ status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, ++ tz_policy_check, (void*)data); ++ if (ACPI_FAILURE(status)) { ++ } ++ ++ return; ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: tz_policy_add_device ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++tz_policy_add_device ( ++ TZ_CONTEXT *tz) ++{ ++ ACPI_STATUS status = AE_OK; ++ TZ_THRESHOLD *threshold = NULL; ++ u32 i,j = 0; ++ ++ if (!tz) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Temperature: ++ * ------------ ++ * Make sure we can read the zone's current temperature (_TMP). ++ * If we can't, there's no use in doing any policy (abort). ++ */ ++ status = tz_get_temperature(tz, &(tz->policy.temperature)); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ /* ++ * Polling Frequency: ++ * ------------------ ++ * If a _TZP object doesn't exist, use the OS default polling ++ * frequency. ++ */ ++ status = bm_evaluate_simple_integer(tz->acpi_handle, "_TZP", ++ &(tz->policy.polling_freq)); ++ if (ACPI_FAILURE(status)) { ++ tz->policy.polling_freq = TZP; ++ } ++ status = AE_OK; ++ ++ /* ++ * Get Thresholds: ++ * --------------- ++ * Get all of the zone's thresholds, parse, and organize for ++ * later use. ++ */ ++ status = tz_get_thresholds(tz, &(tz->policy.threshold_list)); ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ /* ++ * Initialize Policies: ++ * -------------------- ++ */ ++ for (i = 0; i < tz->policy.threshold_list.count; i++) { ++ ++ threshold = &(tz->policy.threshold_list.thresholds[i]); ++ ++ switch (threshold->type) { ++ ++ case TZ_THRESHOLD_CRITICAL: ++ tz->policy.critical.threshold = threshold; ++ break; ++ ++ case TZ_THRESHOLD_PASSIVE: ++ ++ /* ++ * Set thermal performance limit on all processors ++ * to max. ++ */ ++ for (j=0; j<threshold->cooling_devices.count; j++) { ++ set_performance_limit( ++ threshold->cooling_devices.handles[j], ++ PR_PERF_MAX); ++ } ++ ++ /* ++ * Get passive cooling constants. ++ */ ++ status = bm_evaluate_simple_integer(tz->acpi_handle, ++ "_TC1", &(tz->policy.passive.tc1)); ++ if (ACPI_FAILURE(status)) { ++ break; ++ } ++ ++ status = bm_evaluate_simple_integer(tz->acpi_handle, ++ "_TC2", &(tz->policy.passive.tc2)); ++ if (ACPI_FAILURE(status)) { ++ break; ++ } ++ ++ status = bm_evaluate_simple_integer(tz->acpi_handle, ++ "_TSP", &(tz->policy.passive.tsp)); ++ if (ACPI_FAILURE(status)) { ++ break; ++ } ++ ++ tz->policy.passive.threshold = threshold; ++ ++ tz_policy_passive(tz); ++ ++ break; ++ ++ case TZ_THRESHOLD_ACTIVE: ++ tz->policy.active.threshold[threshold->index] = threshold; ++ tz_policy_active(tz); ++ break; ++ } ++ } ++ ++ if (ACPI_FAILURE(status)) { ++ return(status); ++ } ++ ++ /* ++ * Initialize Policy Timer: ++ * ------------------------ ++ * Configure it here in case we need ++ */ ++ init_timer(&(tz->policy.timer)); ++ ++ /* ++ * Start Policy: ++ * ------------- ++ * Run an initial check using this zone's policy. ++ * ++ * TODO: Linux-specific. ++ */ ++ tz_policy_check(tz); ++ ++ return(status); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: tz_policy_remove_device ++ * ++ * PARAMETERS: <TBD> ++ * ++ * RETURN: <TBD> ++ * ++ * DESCRIPTION: <TBD> ++ * ++ ****************************************************************************/ ++ ++ACPI_STATUS ++tz_policy_remove_device( ++ TZ_CONTEXT *tz) ++{ ++ u32 i = 0; ++ ++ if (!tz) { ++ return(AE_BAD_PARAMETER); ++ } ++ ++ /* ++ * Delete the thermal zone policy timer entry, if exists. ++ */ ++ if (timer_pending(&(tz->policy.timer))) { ++ del_timer(&(tz->policy.timer)); ++ } ++ ++ /* ++ * Reset thermal performance limit on all processors back to max. ++ */ ++ if (tz->policy.passive.threshold) { ++ for (i=0; i<tz->policy.passive.threshold->cooling_devices.count; i++) { ++ set_performance_limit( ++ tz->policy.passive.threshold->cooling_devices.handles[i], ++ PR_PERF_MAX); ++ } ++ } ++ ++ return(AE_OK); ++} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/parser/Makefile linux/drivers/acpi/parser/Makefile +--- /usr/src/linux/drivers/acpi/parser/Makefile Fri Dec 29 14:07:21 2000 ++++ linux/drivers/acpi/parser/Makefile Fri Apr 13 11:57:11 2001 +@@ -1,5 +1,6 @@ + # + # Makefile for all Linux ACPI interpreter subdirectories ++# EXCEPT for the ospm directory + # + + O_TARGET := ../$(shell basename `pwd`).o +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/parser/psargs.c linux/drivers/acpi/parser/psargs.c +--- /usr/src/linux/drivers/acpi/parser/psargs.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/parser/psargs.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: psargs - Parse AML opcode arguments +- * $Revision: 43 $ ++ * $Revision: 45 $ + * + *****************************************************************************/ + +@@ -29,7 +29,7 @@ + #include "amlcode.h" + #include "acnamesp.h" + +-#define _COMPONENT PARSER ++#define _COMPONENT ACPI_PARSER + MODULE_NAME ("psargs") + + +@@ -58,8 +58,7 @@ + parser_state->aml++; + + +- switch (encoded_length >> 6) /* bits 6-7 contain encoding scheme */ +- { ++ switch (encoded_length >> 6) /* bits 6-7 contain encoding scheme */ { + case 0: /* 1-byte encoding (bits 0-5) */ + + length = (encoded_length & 0x3F); +@@ -158,8 +157,7 @@ + + /* Decode the path */ + +- switch (GET8 (end)) +- { ++ switch (GET8 (end)) { + case 0: + + /* Null_name */ +@@ -435,8 +433,7 @@ + { + + +- switch (arg_type) +- { ++ switch (arg_type) { + + case ARGP_BYTEDATA: + +@@ -508,7 +505,7 @@ + acpi_ps_get_next_field ( + ACPI_PARSE_STATE *parser_state) + { +- ACPI_PTRDIFF aml_offset = parser_state->aml - ++ u32 aml_offset = parser_state->aml - + parser_state->aml_start; + ACPI_PARSE_OBJECT *field; + u16 opcode; +@@ -517,8 +514,7 @@ + + /* determine field type */ + +- switch (GET8 (parser_state->aml)) +- { ++ switch (GET8 (parser_state->aml)) { + + default: + +@@ -549,8 +545,7 @@ + + /* Decode the field type */ + +- switch (opcode) +- { ++ switch (opcode) { + case AML_NAMEDFIELD_OP: + + /* Get the 4-character name */ +@@ -616,8 +611,7 @@ + u32 subop; + + +- switch (arg_type) +- { ++ switch (arg_type) { + case ARGP_BYTEDATA: + case ARGP_WORDDATA: + case ARGP_DWORDDATA: +@@ -692,13 +686,11 @@ + + + case ARGP_TARGET: +- case ARGP_SUPERNAME: +- { ++ case ARGP_SUPERNAME: { + subop = acpi_ps_peek_opcode (parser_state); + if (subop == 0 || + acpi_ps_is_leading_char (subop) || +- acpi_ps_is_prefix_char (subop)) +- { ++ acpi_ps_is_prefix_char (subop)) { + /* Null_name or Name_string */ + + arg = acpi_ps_alloc_op (AML_NAMEPATH_OP); +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/parser/psopcode.c linux/drivers/acpi/parser/psopcode.c +--- /usr/src/linux/drivers/acpi/parser/psopcode.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/parser/psopcode.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: psopcode - Parser opcode information table +- * $Revision: 27 $ ++ * $Revision: 29 $ + * + *****************************************************************************/ + +@@ -29,7 +29,7 @@ + #include "amlcode.h" + + +-#define _COMPONENT PARSER ++#define _COMPONENT ACPI_PARSER + MODULE_NAME ("psopcode") + + +@@ -130,12 +130,12 @@ + #define ARGP_SIZE_OF_OP ARGP_LIST1 (ARGP_SUPERNAME) + #define ARGP_INDEX_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) + #define ARGP_MATCH_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG) +-#define ARGP_DWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +-#define ARGP_WORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +-#define ARGP_BYTE_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +-#define ARGP_BIT_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) ++#define ARGP_CREATE_DWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) ++#define ARGP_CREATE_WORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) ++#define ARGP_CREATE_BYTE_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) ++#define ARGP_CREATE_BIT_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) + #define ARGP_TYPE_OP ARGP_LIST1 (ARGP_SUPERNAME) +-#define ARGP_QWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) ++#define ARGP_CREATE_QWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) + #define ARGP_LAND_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) + #define ARGP_LOR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) + #define ARGP_LNOT_OP ARGP_LIST1 (ARGP_TERMARG) +@@ -178,7 +178,7 @@ + #define ARGP_DEBUG_OP ARG_NONE + #define ARGP_FATAL_OP ARGP_LIST3 (ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_TERMARG) + #define ARGP_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG) +-#define ARGP_DEF_FIELD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_FIELDLIST) ++#define ARGP_FIELD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_FIELDLIST) + #define ARGP_DEVICE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST) + #define ARGP_PROCESSOR_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_BYTEDATA, ARGP_OBJLIST) + #define ARGP_POWER_RES_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_WORDDATA, ARGP_OBJLIST) +@@ -260,12 +260,12 @@ + #define ARGI_SIZE_OF_OP ARGI_LIST1 (ARGI_DATAOBJECT) + #define ARGI_INDEX_OP ARGI_LIST3 (ARGI_COMPLEXOBJ, ARGI_INTEGER, ARGI_TARGETREF) + #define ARGI_MATCH_OP ARGI_LIST6 (ARGI_PACKAGE, ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER) +-#define ARGI_DWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +-#define ARGI_WORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +-#define ARGI_BYTE_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +-#define ARGI_BIT_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) ++#define ARGI_CREATE_DWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) ++#define ARGI_CREATE_WORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) ++#define ARGI_CREATE_BYTE_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) ++#define ARGI_CREATE_BIT_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) + #define ARGI_TYPE_OP ARGI_LIST1 (ARGI_ANYTYPE) +-#define ARGI_QWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) ++#define ARGI_CREATE_QWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) + #define ARGI_LAND_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) + #define ARGI_LOR_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) + #define ARGI_LNOT_OP ARGI_LIST1 (ARGI_INTEGER) +@@ -308,7 +308,7 @@ + #define ARGI_DEBUG_OP ARG_NONE + #define ARGI_FATAL_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER) + #define ARGI_REGION_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +-#define ARGI_DEF_FIELD_OP ARGI_INVALID_OPCODE ++#define ARGI_FIELD_OP ARGI_INVALID_OPCODE + #define ARGI_DEVICE_OP ARGI_INVALID_OPCODE + #define ARGI_PROCESSOR_OP ARGI_INVALID_OPCODE + #define ARGI_POWER_RES_OP ARGI_INVALID_OPCODE +@@ -335,143 +335,143 @@ + + static ACPI_OPCODE_INFO aml_op_info[] = + { +-/* Index Opcode Type Class Has Arguments? Name Parser Args Interpreter Args */ ++/* Index Opcode Type Class Has Arguments? Name Parser Args Interpreter Args */ + +-/* 00 */ /* AML_ZERO_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "Zero", ARGP_ZERO_OP, ARGI_ZERO_OP), +-/* 01 */ /* AML_ONE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "One", ARGP_ONE_OP, ARGI_ONE_OP), +-/* 02 */ /* AML_ALIAS_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Alias", ARGP_ALIAS_OP, ARGI_ALIAS_OP), +-/* 03 */ /* AML_NAME_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Name", ARGP_NAME_OP, ARGI_NAME_OP), +-/* 04 */ /* AML_BYTE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "Byte_const", ARGP_BYTE_OP, ARGI_BYTE_OP), +-/* 05 */ /* AML_WORD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "Word_const", ARGP_WORD_OP, ARGI_WORD_OP), +-/* 06 */ /* AML_DWORD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "Dword_const", ARGP_DWORD_OP, ARGI_DWORD_OP), +-/* 07 */ /* AML_STRING_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "String", ARGP_STRING_OP, ARGI_STRING_OP), +-/* 08 */ /* AML_SCOPE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Scope", ARGP_SCOPE_OP, ARGI_SCOPE_OP), +-/* 09 */ /* AML_BUFFER_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DATA_TERM| AML_HAS_ARGS, "Buffer", ARGP_BUFFER_OP, ARGI_BUFFER_OP), +-/* 0A */ /* AML_PACKAGE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DATA_TERM| AML_HAS_ARGS, "Package", ARGP_PACKAGE_OP, ARGI_PACKAGE_OP), +-/* 0B */ /* AML_METHOD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Method", ARGP_METHOD_OP, ARGI_METHOD_OP), +-/* 0C */ /* AML_LOCAL0 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local0", ARGP_LOCAL0, ARGI_LOCAL0), +-/* 0D */ /* AML_LOCAL1 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local1", ARGP_LOCAL1, ARGI_LOCAL1), +-/* 0E */ /* AML_LOCAL2 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local2", ARGP_LOCAL2, ARGI_LOCAL2), +-/* 0F */ /* AML_LOCAL3 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local3", ARGP_LOCAL3, ARGI_LOCAL3), +-/* 10 */ /* AML_LOCAL4 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local4", ARGP_LOCAL4, ARGI_LOCAL4), +-/* 11 */ /* AML_LOCAL5 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local5", ARGP_LOCAL5, ARGI_LOCAL5), +-/* 12 */ /* AML_LOCAL6 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local6", ARGP_LOCAL6, ARGI_LOCAL6), +-/* 13 */ /* AML_LOCAL7 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local7", ARGP_LOCAL7, ARGI_LOCAL7), +-/* 14 */ /* AML_ARG0 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg0", ARGP_ARG0, ARGI_ARG0), +-/* 15 */ /* AML_ARG1 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg1", ARGP_ARG1, ARGI_ARG1), +-/* 16 */ /* AML_ARG2 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg2", ARGP_ARG2, ARGI_ARG2), +-/* 17 */ /* AML_ARG3 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg3", ARGP_ARG3, ARGI_ARG3), +-/* 18 */ /* AML_ARG4 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg4", ARGP_ARG4, ARGI_ARG4), +-/* 19 */ /* AML_ARG5 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg5", ARGP_ARG5, ARGI_ARG5), +-/* 1_a */ /* AML_ARG6 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg6", ARGP_ARG6, ARGI_ARG6), +-/* 1_b */ /* AML_STORE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Store", ARGP_STORE_OP, ARGI_STORE_OP), +-/* 1_c */ /* AML_REF_OF_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Ref_of", ARGP_REF_OF_OP, ARGI_REF_OF_OP), +-/* 1_d */ /* AML_ADD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Add", ARGP_ADD_OP, ARGI_ADD_OP), +-/* 1_e */ /* AML_CONCAT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Concatenate", ARGP_CONCAT_OP, ARGI_CONCAT_OP), +-/* 1_f */ /* AML_SUBTRACT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Subtract", ARGP_SUBTRACT_OP, ARGI_SUBTRACT_OP), +-/* 20 */ /* AML_INCREMENT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Increment", ARGP_INCREMENT_OP, ARGI_INCREMENT_OP), +-/* 21 */ /* AML_DECREMENT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Decrement", ARGP_DECREMENT_OP, ARGI_DECREMENT_OP), +-/* 22 */ /* AML_MULTIPLY_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Multiply", ARGP_MULTIPLY_OP, ARGI_MULTIPLY_OP), +-/* 23 */ /* AML_DIVIDE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Divide", ARGP_DIVIDE_OP, ARGI_DIVIDE_OP), +-/* 24 */ /* AML_SHIFT_LEFT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Shift_left", ARGP_SHIFT_LEFT_OP, ARGI_SHIFT_LEFT_OP), +-/* 25 */ /* AML_SHIFT_RIGHT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Shift_right", ARGP_SHIFT_RIGHT_OP, ARGI_SHIFT_RIGHT_OP), +-/* 26 */ /* AML_BIT_AND_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "And", ARGP_BIT_AND_OP, ARGI_BIT_AND_OP), +-/* 27 */ /* AML_BIT_NAND_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "NAnd", ARGP_BIT_NAND_OP, ARGI_BIT_NAND_OP), +-/* 28 */ /* AML_BIT_OR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Or", ARGP_BIT_OR_OP, ARGI_BIT_OR_OP), +-/* 29 */ /* AML_BIT_NOR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "NOr", ARGP_BIT_NOR_OP, ARGI_BIT_NOR_OP), +-/* 2_a */ /* AML_BIT_XOR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "XOr", ARGP_BIT_XOR_OP, ARGI_BIT_XOR_OP), +-/* 2_b */ /* AML_BIT_NOT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Not", ARGP_BIT_NOT_OP, ARGI_BIT_NOT_OP), ++/* 00 */ /* AML_ZERO_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "Zero", ARGP_ZERO_OP, ARGI_ZERO_OP), ++/* 01 */ /* AML_ONE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "One", ARGP_ONE_OP, ARGI_ONE_OP), ++/* 02 */ /* AML_ALIAS_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Alias", ARGP_ALIAS_OP, ARGI_ALIAS_OP), ++/* 03 */ /* AML_NAME_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Name", ARGP_NAME_OP, ARGI_NAME_OP), ++/* 04 */ /* AML_BYTE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "Byte_const", ARGP_BYTE_OP, ARGI_BYTE_OP), ++/* 05 */ /* AML_WORD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "Word_const", ARGP_WORD_OP, ARGI_WORD_OP), ++/* 06 */ /* AML_DWORD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "Dword_const", ARGP_DWORD_OP, ARGI_DWORD_OP), ++/* 07 */ /* AML_STRING_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "String", ARGP_STRING_OP, ARGI_STRING_OP), ++/* 08 */ /* AML_SCOPE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Scope", ARGP_SCOPE_OP, ARGI_SCOPE_OP), ++/* 09 */ /* AML_BUFFER_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DATA_TERM| AML_HAS_ARGS, "Buffer", ARGP_BUFFER_OP, ARGI_BUFFER_OP), ++/* 0A */ /* AML_PACKAGE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DATA_TERM| AML_HAS_ARGS, "Package", ARGP_PACKAGE_OP, ARGI_PACKAGE_OP), ++/* 0B */ /* AML_METHOD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Method", ARGP_METHOD_OP, ARGI_METHOD_OP), ++/* 0C */ /* AML_LOCAL0 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local0", ARGP_LOCAL0, ARGI_LOCAL0), ++/* 0D */ /* AML_LOCAL1 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local1", ARGP_LOCAL1, ARGI_LOCAL1), ++/* 0E */ /* AML_LOCAL2 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local2", ARGP_LOCAL2, ARGI_LOCAL2), ++/* 0F */ /* AML_LOCAL3 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local3", ARGP_LOCAL3, ARGI_LOCAL3), ++/* 10 */ /* AML_LOCAL4 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local4", ARGP_LOCAL4, ARGI_LOCAL4), ++/* 11 */ /* AML_LOCAL5 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local5", ARGP_LOCAL5, ARGI_LOCAL5), ++/* 12 */ /* AML_LOCAL6 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local6", ARGP_LOCAL6, ARGI_LOCAL6), ++/* 13 */ /* AML_LOCAL7 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local7", ARGP_LOCAL7, ARGI_LOCAL7), ++/* 14 */ /* AML_ARG0 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg0", ARGP_ARG0, ARGI_ARG0), ++/* 15 */ /* AML_ARG1 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg1", ARGP_ARG1, ARGI_ARG1), ++/* 16 */ /* AML_ARG2 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg2", ARGP_ARG2, ARGI_ARG2), ++/* 17 */ /* AML_ARG3 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg3", ARGP_ARG3, ARGI_ARG3), ++/* 18 */ /* AML_ARG4 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg4", ARGP_ARG4, ARGI_ARG4), ++/* 19 */ /* AML_ARG5 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg5", ARGP_ARG5, ARGI_ARG5), ++/* 1_a */ /* AML_ARG6 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg6", ARGP_ARG6, ARGI_ARG6), ++/* 1_b */ /* AML_STORE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Store", ARGP_STORE_OP, ARGI_STORE_OP), ++/* 1_c */ /* AML_REF_OF_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Ref_of", ARGP_REF_OF_OP, ARGI_REF_OF_OP), ++/* 1_d */ /* AML_ADD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Add", ARGP_ADD_OP, ARGI_ADD_OP), ++/* 1_e */ /* AML_CONCAT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Concatenate", ARGP_CONCAT_OP, ARGI_CONCAT_OP), ++/* 1_f */ /* AML_SUBTRACT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Subtract", ARGP_SUBTRACT_OP, ARGI_SUBTRACT_OP), ++/* 20 */ /* AML_INCREMENT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Increment", ARGP_INCREMENT_OP, ARGI_INCREMENT_OP), ++/* 21 */ /* AML_DECREMENT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Decrement", ARGP_DECREMENT_OP, ARGI_DECREMENT_OP), ++/* 22 */ /* AML_MULTIPLY_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Multiply", ARGP_MULTIPLY_OP, ARGI_MULTIPLY_OP), ++/* 23 */ /* AML_DIVIDE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Divide", ARGP_DIVIDE_OP, ARGI_DIVIDE_OP), ++/* 24 */ /* AML_SHIFT_LEFT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Shift_left", ARGP_SHIFT_LEFT_OP, ARGI_SHIFT_LEFT_OP), ++/* 25 */ /* AML_SHIFT_RIGHT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Shift_right", ARGP_SHIFT_RIGHT_OP, ARGI_SHIFT_RIGHT_OP), ++/* 26 */ /* AML_BIT_AND_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "And", ARGP_BIT_AND_OP, ARGI_BIT_AND_OP), ++/* 27 */ /* AML_BIT_NAND_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "NAnd", ARGP_BIT_NAND_OP, ARGI_BIT_NAND_OP), ++/* 28 */ /* AML_BIT_OR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Or", ARGP_BIT_OR_OP, ARGI_BIT_OR_OP), ++/* 29 */ /* AML_BIT_NOR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "NOr", ARGP_BIT_NOR_OP, ARGI_BIT_NOR_OP), ++/* 2_a */ /* AML_BIT_XOR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "XOr", ARGP_BIT_XOR_OP, ARGI_BIT_XOR_OP), ++/* 2_b */ /* AML_BIT_NOT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Not", ARGP_BIT_NOT_OP, ARGI_BIT_NOT_OP), + /* 2_c */ /* AML_FIND_SET_LEFT_BIT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Find_set_left_bit", ARGP_FIND_SET_LEFT_BIT_OP, ARGI_FIND_SET_LEFT_BIT_OP), +-/* 2_d */ /* AML_FIND_SET_RIGHT_BIT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Find_set_right_bit", ARGP_FIND_SET_RIGHT_BIT_OP, ARGI_FIND_SET_RIGHT_BIT_OP), +-/* 2_e */ /* AML_DEREF_OF_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Deref_of", ARGP_DEREF_OF_OP, ARGI_DEREF_OF_OP), +-/* 2_f */ /* AML_NOTIFY_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC1| AML_HAS_ARGS, "Notify", ARGP_NOTIFY_OP, ARGI_NOTIFY_OP), +-/* 30 */ /* AML_SIZE_OF_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Size_of", ARGP_SIZE_OF_OP, ARGI_SIZE_OF_OP), +-/* 31 */ /* AML_INDEX_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_INDEX| AML_HAS_ARGS, "Index", ARGP_INDEX_OP, ARGI_INDEX_OP), +-/* 32 */ /* AML_MATCH_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MATCH| AML_HAS_ARGS, "Match", ARGP_MATCH_OP, ARGI_MATCH_OP), +-/* 33 */ /* AML_DWORD_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CREATE_FIELD| AML_HAS_ARGS, "Create_dWord_field", ARGP_DWORD_FIELD_OP, ARGI_DWORD_FIELD_OP), +-/* 34 */ /* AML_WORD_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CREATE_FIELD| AML_HAS_ARGS, "Create_word_field", ARGP_WORD_FIELD_OP, ARGI_WORD_FIELD_OP), +-/* 35 */ /* AML_BYTE_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CREATE_FIELD| AML_HAS_ARGS, "Create_byte_field", ARGP_BYTE_FIELD_OP, ARGI_BYTE_FIELD_OP), +-/* 36 */ /* AML_BIT_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CREATE_FIELD| AML_HAS_ARGS, "Create_bit_field", ARGP_BIT_FIELD_OP, ARGI_BIT_FIELD_OP), +-/* 37 */ /* AML_TYPE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Object_type", ARGP_TYPE_OP, ARGI_TYPE_OP), +-/* 38 */ /* AML_LAND_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2| AML_HAS_ARGS, "LAnd", ARGP_LAND_OP, ARGI_LAND_OP), +-/* 39 */ /* AML_LOR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2| AML_HAS_ARGS, "LOr", ARGP_LOR_OP, ARGI_LOR_OP), +-/* 3_a */ /* AML_LNOT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "LNot", ARGP_LNOT_OP, ARGI_LNOT_OP), +-/* 3_b */ /* AML_LEQUAL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2| AML_HAS_ARGS, "LEqual", ARGP_LEQUAL_OP, ARGI_LEQUAL_OP), +-/* 3_c */ /* AML_LGREATER_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2| AML_HAS_ARGS, "LGreater", ARGP_LGREATER_OP, ARGI_LGREATER_OP), +-/* 3_d */ /* AML_LLESS_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2| AML_HAS_ARGS, "LLess", ARGP_LLESS_OP, ARGI_LLESS_OP), +-/* 3_e */ /* AML_IF_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_HAS_ARGS, "If", ARGP_IF_OP, ARGI_IF_OP), +-/* 3_f */ /* AML_ELSE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_HAS_ARGS, "Else", ARGP_ELSE_OP, ARGI_ELSE_OP), +-/* 40 */ /* AML_WHILE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_HAS_ARGS, "While", ARGP_WHILE_OP, ARGI_WHILE_OP), +-/* 41 */ /* AML_NOOP_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_NO_ARGS, "Noop", ARGP_NOOP_OP, ARGI_NOOP_OP), +-/* 42 */ /* AML_RETURN_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_HAS_ARGS, "Return", ARGP_RETURN_OP, ARGI_RETURN_OP), +-/* 43 */ /* AML_BREAK_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_NO_ARGS, "Break", ARGP_BREAK_OP, ARGI_BREAK_OP), +-/* 44 */ /* AML_BREAK_POINT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_NO_ARGS, "Break_point", ARGP_BREAK_POINT_OP, ARGI_BREAK_POINT_OP), +-/* 45 */ /* AML_ONES_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "Ones", ARGP_ONES_OP, ARGI_ONES_OP), ++/* 2_d */ /* AML_FIND_SET_RIGHT_BIT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Find_set_right_bit", ARGP_FIND_SET_RIGHT_BIT_OP,ARGI_FIND_SET_RIGHT_BIT_OP), ++/* 2_e */ /* AML_DEREF_OF_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Deref_of", ARGP_DEREF_OF_OP, ARGI_DEREF_OF_OP), ++/* 2_f */ /* AML_NOTIFY_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC1| AML_HAS_ARGS, "Notify", ARGP_NOTIFY_OP, ARGI_NOTIFY_OP), ++/* 30 */ /* AML_SIZE_OF_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Size_of", ARGP_SIZE_OF_OP, ARGI_SIZE_OF_OP), ++/* 31 */ /* AML_INDEX_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_INDEX| AML_HAS_ARGS, "Index", ARGP_INDEX_OP, ARGI_INDEX_OP), ++/* 32 */ /* AML_MATCH_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MATCH| AML_HAS_ARGS, "Match", ARGP_MATCH_OP, ARGI_MATCH_OP), ++/* 33 */ /* AML_CREATE_DWORD_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CREATE_FIELD| AML_HAS_ARGS, "Create_dWord_field", ARGP_CREATE_DWORD_FIELD_OP,ARGI_CREATE_DWORD_FIELD_OP), ++/* 34 */ /* AML_CREATE_WORD_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CREATE_FIELD| AML_HAS_ARGS, "Create_word_field", ARGP_CREATE_WORD_FIELD_OP, ARGI_CREATE_WORD_FIELD_OP), ++/* 35 */ /* AML_CREATE_BYTE_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CREATE_FIELD| AML_HAS_ARGS, "Create_byte_field", ARGP_CREATE_BYTE_FIELD_OP, ARGI_CREATE_BYTE_FIELD_OP), ++/* 36 */ /* AML_CREATE_BIT_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CREATE_FIELD| AML_HAS_ARGS, "Create_bit_field", ARGP_CREATE_BIT_FIELD_OP, ARGI_CREATE_BIT_FIELD_OP), ++/* 37 */ /* AML_TYPE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Object_type", ARGP_TYPE_OP, ARGI_TYPE_OP), ++/* 38 */ /* AML_LAND_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2| AML_HAS_ARGS, "LAnd", ARGP_LAND_OP, ARGI_LAND_OP), ++/* 39 */ /* AML_LOR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2| AML_HAS_ARGS, "LOr", ARGP_LOR_OP, ARGI_LOR_OP), ++/* 3_a */ /* AML_LNOT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "LNot", ARGP_LNOT_OP, ARGI_LNOT_OP), ++/* 3_b */ /* AML_LEQUAL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2| AML_HAS_ARGS, "LEqual", ARGP_LEQUAL_OP, ARGI_LEQUAL_OP), ++/* 3_c */ /* AML_LGREATER_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2| AML_HAS_ARGS, "LGreater", ARGP_LGREATER_OP, ARGI_LGREATER_OP), ++/* 3_d */ /* AML_LLESS_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2| AML_HAS_ARGS, "LLess", ARGP_LLESS_OP, ARGI_LLESS_OP), ++/* 3_e */ /* AML_IF_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_HAS_ARGS, "If", ARGP_IF_OP, ARGI_IF_OP), ++/* 3_f */ /* AML_ELSE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_HAS_ARGS, "Else", ARGP_ELSE_OP, ARGI_ELSE_OP), ++/* 40 */ /* AML_WHILE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_HAS_ARGS, "While", ARGP_WHILE_OP, ARGI_WHILE_OP), ++/* 41 */ /* AML_NOOP_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_NO_ARGS, "Noop", ARGP_NOOP_OP, ARGI_NOOP_OP), ++/* 42 */ /* AML_RETURN_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_HAS_ARGS, "Return", ARGP_RETURN_OP, ARGI_RETURN_OP), ++/* 43 */ /* AML_BREAK_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_NO_ARGS, "Break", ARGP_BREAK_OP, ARGI_BREAK_OP), ++/* 44 */ /* AML_BREAK_POINT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_NO_ARGS, "Break_point", ARGP_BREAK_POINT_OP, ARGI_BREAK_POINT_OP), ++/* 45 */ /* AML_ONES_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "Ones", ARGP_ONES_OP, ARGI_ONES_OP), + + /* Prefixed opcodes (Two-byte opcodes with a prefix op) */ + +-/* 46 */ /* AML_MUTEX_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Mutex", ARGP_MUTEX_OP, ARGI_MUTEX_OP), +-/* 47 */ /* AML_EVENT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_NO_ARGS, "Event", ARGP_EVENT_OP, ARGI_EVENT_OP), +-/* 48 */ /* AML_COND_REF_OF_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Cond_ref_of", ARGP_COND_REF_OF_OP, ARGI_COND_REF_OF_OP), +-/* 49 */ /* AML_CREATE_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CREATE_FIELD| AML_HAS_ARGS, "Create_field", ARGP_CREATE_FIELD_OP, ARGI_CREATE_FIELD_OP), +-/* 4_a */ /* AML_LOAD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_RECONFIGURATION| AML_HAS_ARGS, "Load", ARGP_LOAD_OP, ARGI_LOAD_OP), +-/* 4_b */ /* AML_STALL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC1| AML_HAS_ARGS, "Stall", ARGP_STALL_OP, ARGI_STALL_OP), +-/* 4_c */ /* AML_SLEEP_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC1| AML_HAS_ARGS, "Sleep", ARGP_SLEEP_OP, ARGI_SLEEP_OP), +-/* 4_d */ /* AML_ACQUIRE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_s| AML_HAS_ARGS, "Acquire", ARGP_ACQUIRE_OP, ARGI_ACQUIRE_OP), +-/* 4_e */ /* AML_SIGNAL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC1| AML_HAS_ARGS, "Signal", ARGP_SIGNAL_OP, ARGI_SIGNAL_OP), +-/* 4_f */ /* AML_WAIT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_s| AML_HAS_ARGS, "Wait", ARGP_WAIT_OP, ARGI_WAIT_OP), +-/* 50 */ /* AML_RESET_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC1| AML_HAS_ARGS, "Reset", ARGP_RESET_OP, ARGI_RESET_OP), +-/* 51 */ /* AML_RELEASE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC1| AML_HAS_ARGS, "Release", ARGP_RELEASE_OP, ARGI_RELEASE_OP), +-/* 52 */ /* AML_FROM_BCD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "From_bCD", ARGP_FROM_BCD_OP, ARGI_FROM_BCD_OP), +-/* 53 */ /* AML_TO_BCD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "To_bCD", ARGP_TO_BCD_OP, ARGI_TO_BCD_OP), +-/* 54 */ /* AML_UNLOAD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_RECONFIGURATION| AML_HAS_ARGS, "Unload", ARGP_UNLOAD_OP, ARGI_UNLOAD_OP), +-/* 55 */ /* AML_REVISION_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "Revision", ARGP_REVISION_OP, ARGI_REVISION_OP), +-/* 56 */ /* AML_DEBUG_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "Debug", ARGP_DEBUG_OP, ARGI_DEBUG_OP), +-/* 57 */ /* AML_FATAL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_FATAL| AML_HAS_ARGS, "Fatal", ARGP_FATAL_OP, ARGI_FATAL_OP), +-/* 58 */ /* AML_REGION_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Op_region", ARGP_REGION_OP, ARGI_REGION_OP), +-/* 59 */ /* AML_DEF_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Field", ARGP_DEF_FIELD_OP, ARGI_DEF_FIELD_OP), +-/* 5_a */ /* AML_DEVICE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Device", ARGP_DEVICE_OP, ARGI_DEVICE_OP), +-/* 5_b */ /* AML_PROCESSOR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Processor", ARGP_PROCESSOR_OP, ARGI_PROCESSOR_OP), +-/* 5_c */ /* AML_POWER_RES_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Power_resource", ARGP_POWER_RES_OP, ARGI_POWER_RES_OP), +-/* 5_d */ /* AML_THERMAL_ZONE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Thermal_zone", ARGP_THERMAL_ZONE_OP, ARGI_THERMAL_ZONE_OP), +-/* 5_e */ /* AML_INDEX_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Index_field", ARGP_INDEX_FIELD_OP, ARGI_INDEX_FIELD_OP), +-/* 5_f */ /* AML_BANK_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Bank_field", ARGP_BANK_FIELD_OP, ARGI_BANK_FIELD_OP), ++/* 46 */ /* AML_MUTEX_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Mutex", ARGP_MUTEX_OP, ARGI_MUTEX_OP), ++/* 47 */ /* AML_EVENT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_NO_ARGS, "Event", ARGP_EVENT_OP, ARGI_EVENT_OP), ++/* 48 */ /* AML_COND_REF_OF_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Cond_ref_of", ARGP_COND_REF_OF_OP, ARGI_COND_REF_OF_OP), ++/* 49 */ /* AML_CREATE_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CREATE_FIELD| AML_HAS_ARGS, "Create_field", ARGP_CREATE_FIELD_OP, ARGI_CREATE_FIELD_OP), ++/* 4_a */ /* AML_LOAD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_RECONFIGURATION| AML_HAS_ARGS, "Load", ARGP_LOAD_OP, ARGI_LOAD_OP), ++/* 4_b */ /* AML_STALL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC1| AML_HAS_ARGS, "Stall", ARGP_STALL_OP, ARGI_STALL_OP), ++/* 4_c */ /* AML_SLEEP_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC1| AML_HAS_ARGS, "Sleep", ARGP_SLEEP_OP, ARGI_SLEEP_OP), ++/* 4_d */ /* AML_ACQUIRE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_s| AML_HAS_ARGS, "Acquire", ARGP_ACQUIRE_OP, ARGI_ACQUIRE_OP), ++/* 4_e */ /* AML_SIGNAL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC1| AML_HAS_ARGS, "Signal", ARGP_SIGNAL_OP, ARGI_SIGNAL_OP), ++/* 4_f */ /* AML_WAIT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_s| AML_HAS_ARGS, "Wait", ARGP_WAIT_OP, ARGI_WAIT_OP), ++/* 50 */ /* AML_RESET_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC1| AML_HAS_ARGS, "Reset", ARGP_RESET_OP, ARGI_RESET_OP), ++/* 51 */ /* AML_RELEASE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC1| AML_HAS_ARGS, "Release", ARGP_RELEASE_OP, ARGI_RELEASE_OP), ++/* 52 */ /* AML_FROM_BCD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "From_bCD", ARGP_FROM_BCD_OP, ARGI_FROM_BCD_OP), ++/* 53 */ /* AML_TO_BCD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "To_bCD", ARGP_TO_BCD_OP, ARGI_TO_BCD_OP), ++/* 54 */ /* AML_UNLOAD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_RECONFIGURATION| AML_HAS_ARGS, "Unload", ARGP_UNLOAD_OP, ARGI_UNLOAD_OP), ++/* 55 */ /* AML_REVISION_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "Revision", ARGP_REVISION_OP, ARGI_REVISION_OP), ++/* 56 */ /* AML_DEBUG_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "Debug", ARGP_DEBUG_OP, ARGI_DEBUG_OP), ++/* 57 */ /* AML_FATAL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_FATAL| AML_HAS_ARGS, "Fatal", ARGP_FATAL_OP, ARGI_FATAL_OP), ++/* 58 */ /* AML_REGION_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Op_region", ARGP_REGION_OP, ARGI_REGION_OP), ++/* 59 */ /* AML_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Field", ARGP_FIELD_OP, ARGI_FIELD_OP), ++/* 5_a */ /* AML_DEVICE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Device", ARGP_DEVICE_OP, ARGI_DEVICE_OP), ++/* 5_b */ /* AML_PROCESSOR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Processor", ARGP_PROCESSOR_OP, ARGI_PROCESSOR_OP), ++/* 5_c */ /* AML_POWER_RES_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Power_resource", ARGP_POWER_RES_OP, ARGI_POWER_RES_OP), ++/* 5_d */ /* AML_THERMAL_ZONE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Thermal_zone", ARGP_THERMAL_ZONE_OP, ARGI_THERMAL_ZONE_OP), ++/* 5_e */ /* AML_INDEX_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Index_field", ARGP_INDEX_FIELD_OP, ARGI_INDEX_FIELD_OP), ++/* 5_f */ /* AML_BANK_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Bank_field", ARGP_BANK_FIELD_OP, ARGI_BANK_FIELD_OP), + + /* Internal opcodes that map to invalid AML opcodes */ + +-/* 60 */ /* AML_LNOTEQUAL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_HAS_ARGS, "LNot_equal", ARGP_LNOTEQUAL_OP, ARGI_LNOTEQUAL_OP), +-/* 61 */ /* AML_LLESSEQUAL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_HAS_ARGS, "LLess_equal", ARGP_LLESSEQUAL_OP, ARGI_LLESSEQUAL_OP), +-/* 62 */ /* AML_LGREATEREQUAL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_HAS_ARGS, "LGreater_equal", ARGP_LGREATEREQUAL_OP, ARGI_LGREATEREQUAL_OP), +-/* 63 */ /* AML_NAMEPATH_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "Name_path", ARGP_NAMEPATH_OP, ARGI_NAMEPATH_OP), +-/* 64 */ /* AML_METHODCALL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_CALL| AML_HAS_ARGS, "Method_call", ARGP_METHODCALL_OP, ARGI_METHODCALL_OP), +-/* 65 */ /* AML_BYTELIST_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "Byte_list", ARGP_BYTELIST_OP, ARGI_BYTELIST_OP), +-/* 66 */ /* AML_RESERVEDFIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_NO_ARGS, "Reserved_field", ARGP_RESERVEDFIELD_OP, ARGI_RESERVEDFIELD_OP), +-/* 67 */ /* AML_NAMEDFIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_NO_ARGS, "Named_field", ARGP_NAMEDFIELD_OP, ARGI_NAMEDFIELD_OP), +-/* 68 */ /* AML_ACCESSFIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_NO_ARGS, "Access_field", ARGP_ACCESSFIELD_OP, ARGI_ACCESSFIELD_OP), +-/* 69 */ /* AML_STATICSTRING_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_NO_ARGS, "Static_string", ARGP_STATICSTRING_OP, ARGI_STATICSTRING_OP), +-/* 6_a */ /* AML_RETURN_VALUE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_RETURN| AML_HAS_ARGS, "[Return Value]", ARG_NONE, ARG_NONE), +-/* 6_b */ /* UNKNOWN OPCODES */ OP_INFO_ENTRY (ACPI_OP_TYPE_UNKNOWN | OPTYPE_BOGUS| AML_HAS_ARGS, "UNKNOWN_OP!", ARG_NONE, ARG_NONE), +-/* 6_c */ /* ASCII CHARACTERS */ OP_INFO_ENTRY (ACPI_OP_TYPE_ASCII | OPTYPE_BOGUS| AML_HAS_ARGS, "ASCII_ONLY!", ARG_NONE, ARG_NONE), +-/* 6_d */ /* PREFIX CHARACTERS */ OP_INFO_ENTRY (ACPI_OP_TYPE_PREFIX | OPTYPE_BOGUS| AML_HAS_ARGS, "PREFIX_ONLY!", ARG_NONE, ARG_NONE), ++/* 60 */ /* AML_LNOTEQUAL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_HAS_ARGS, "LNot_equal", ARGP_LNOTEQUAL_OP, ARGI_LNOTEQUAL_OP), ++/* 61 */ /* AML_LLESSEQUAL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_HAS_ARGS, "LLess_equal", ARGP_LLESSEQUAL_OP, ARGI_LLESSEQUAL_OP), ++/* 62 */ /* AML_LGREATEREQUAL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_HAS_ARGS, "LGreater_equal", ARGP_LGREATEREQUAL_OP, ARGI_LGREATEREQUAL_OP), ++/* 63 */ /* AML_NAMEPATH_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "Name_path", ARGP_NAMEPATH_OP, ARGI_NAMEPATH_OP), ++/* 64 */ /* AML_METHODCALL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_CALL| AML_HAS_ARGS, "Method_call", ARGP_METHODCALL_OP, ARGI_METHODCALL_OP), ++/* 65 */ /* AML_BYTELIST_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "Byte_list", ARGP_BYTELIST_OP, ARGI_BYTELIST_OP), ++/* 66 */ /* AML_RESERVEDFIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_NO_ARGS, "Reserved_field", ARGP_RESERVEDFIELD_OP, ARGI_RESERVEDFIELD_OP), ++/* 67 */ /* AML_NAMEDFIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_NO_ARGS, "Named_field", ARGP_NAMEDFIELD_OP, ARGI_NAMEDFIELD_OP), ++/* 68 */ /* AML_ACCESSFIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_NO_ARGS, "Access_field", ARGP_ACCESSFIELD_OP, ARGI_ACCESSFIELD_OP), ++/* 69 */ /* AML_STATICSTRING_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_NO_ARGS, "Static_string", ARGP_STATICSTRING_OP, ARGI_STATICSTRING_OP), ++/* 6_a */ /* AML_RETURN_VALUE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_RETURN| AML_HAS_ARGS, "[Return Value]", ARG_NONE, ARG_NONE), ++/* 6_b */ /* UNKNOWN OPCODES */ OP_INFO_ENTRY (ACPI_OP_TYPE_UNKNOWN | OPTYPE_BOGUS| AML_HAS_ARGS, "UNKNOWN_OP!", ARG_NONE, ARG_NONE), ++/* 6_c */ /* ASCII CHARACTERS */ OP_INFO_ENTRY (ACPI_OP_TYPE_ASCII | OPTYPE_BOGUS| AML_HAS_ARGS, "ASCII_ONLY!", ARG_NONE, ARG_NONE), ++/* 6_d */ /* PREFIX CHARACTERS */ OP_INFO_ENTRY (ACPI_OP_TYPE_PREFIX | OPTYPE_BOGUS| AML_HAS_ARGS, "PREFIX_ONLY!", ARG_NONE, ARG_NONE), + + + /* ACPI 2.0 (new) opcodes */ + +-/* 6_e */ /* AML_QWORD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "Qword_const", ARGP_QWORD_OP, ARGI_QWORD_OP), +-/* 6_f */ /* AML_VAR_PACKAGE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DATA_TERM| AML_HAS_ARGS, "Var_package", ARGP_VAR_PACKAGE_OP, ARGI_VAR_PACKAGE_OP), +-/* 70 */ /* AML_CONCAT_RES_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Concat_res", ARGP_CONCAT_RES_OP, ARGI_CONCAT_RES_OP), +-/* 71 */ /* AML_MOD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Mod", ARGP_MOD_OP, ARGI_MOD_OP), +-/* 72 */ /* AML_QWORD_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CREATE_FIELD| AML_HAS_ARGS, "Create_qWord_field", ARGP_QWORD_FIELD_OP, ARGI_QWORD_FIELD_OP), +-/* 73 */ /* AML_TO_BUFFER_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "To_buffer", ARGP_TO_BUFFER_OP, ARGI_TO_BUFFER_OP), +-/* 74 */ /* AML_TO_DEC_STR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "To_dec_string", ARGP_TO_DEC_STR_OP, ARGI_TO_DEC_STR_OP), +-/* 75 */ /* AML_TO_HEX_STR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "To_hex_string", ARGP_TO_HEX_STR_OP, ARGI_TO_HEX_STR_OP), +-/* 76 */ /* AML_TO_INTEGER_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "To_integer", ARGP_TO_INTEGER_OP, ARGI_TO_INTEGER_OP), +-/* 77 */ /* AML_TO_STRING_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "To_string", ARGP_TO_STRING_OP, ARGI_TO_STRING_OP), +-/* 78 */ /* AML_COPY_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Copy", ARGP_COPY_OP, ARGI_COPY_OP), +-/* 79 */ /* AML_MID_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Mid", ARGP_MID_OP, ARGI_MID_OP), +-/* 7_a */ /* AML_CONTINUE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_NO_ARGS, "Continue", ARGP_CONTINUE_OP, ARGI_CONTINUE_OP), +-/* 7_b */ /* AML_LOAD_TABLE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Load_table", ARGP_LOAD_TABLE_OP, ARGI_LOAD_TABLE_OP), +-/* 7_c */ /* AML_DATA_REGION_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Data_op_region", ARGP_DATA_REGION_OP, ARGI_DATA_REGION_OP), ++/* 6_e */ /* AML_QWORD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "Qword_const", ARGP_QWORD_OP, ARGI_QWORD_OP), ++/* 6_f */ /* AML_VAR_PACKAGE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DATA_TERM| AML_HAS_ARGS, "Var_package", ARGP_VAR_PACKAGE_OP, ARGI_VAR_PACKAGE_OP), ++/* 70 */ /* AML_CONCAT_RES_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Concat_res", ARGP_CONCAT_RES_OP, ARGI_CONCAT_RES_OP), ++/* 71 */ /* AML_MOD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Mod", ARGP_MOD_OP, ARGI_MOD_OP), ++/* 72 */ /* AML_CREATE_QWORD_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CREATE_FIELD| AML_HAS_ARGS, "Create_qWord_field", ARGP_CREATE_QWORD_FIELD_OP,ARGI_CREATE_QWORD_FIELD_OP), ++/* 73 */ /* AML_TO_BUFFER_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "To_buffer", ARGP_TO_BUFFER_OP, ARGI_TO_BUFFER_OP), ++/* 74 */ /* AML_TO_DEC_STR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "To_dec_string", ARGP_TO_DEC_STR_OP, ARGI_TO_DEC_STR_OP), ++/* 75 */ /* AML_TO_HEX_STR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "To_hex_string", ARGP_TO_HEX_STR_OP, ARGI_TO_HEX_STR_OP), ++/* 76 */ /* AML_TO_INTEGER_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "To_integer", ARGP_TO_INTEGER_OP, ARGI_TO_INTEGER_OP), ++/* 77 */ /* AML_TO_STRING_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "To_string", ARGP_TO_STRING_OP, ARGI_TO_STRING_OP), ++/* 78 */ /* AML_COPY_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Copy_object", ARGP_COPY_OP, ARGI_COPY_OP), ++/* 79 */ /* AML_MID_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Mid", ARGP_MID_OP, ARGI_MID_OP), ++/* 7_a */ /* AML_CONTINUE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_NO_ARGS, "Continue", ARGP_CONTINUE_OP, ARGI_CONTINUE_OP), ++/* 7_b */ /* AML_LOAD_TABLE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Load_table", ARGP_LOAD_TABLE_OP, ARGI_LOAD_TABLE_OP), ++/* 7_c */ /* AML_DATA_REGION_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Data_op_region", ARGP_DATA_REGION_OP, ARGI_DATA_REGION_OP), + + }; + +@@ -484,38 +484,38 @@ + { + /* 0 1 2 3 4 5 6 7 */ + /* 8 9 A B C D E F */ +-/* 0x00 */ 0x00, 0x01, _UNK, _UNK, _UNK, _UNK, 0x02, _UNK, +-/* 0x08 */ 0x03, _UNK, 0x04, 0x05, 0x06, 0x07, 0x6E, _UNK, +-/* 0x10 */ 0x08, 0x09, 0x0a, 0x6F, 0x0b, _UNK, _UNK, _UNK, +-/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0x20 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0x28 */ _UNK, _UNK, _UNK, _UNK, _UNK, 0x63, _PFX, _PFX, +-/* 0x30 */ 0x67, 0x66, 0x68, 0x65, 0x69, 0x64, 0x6A, _UNK, +-/* 0x38 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0x40 */ _UNK, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, +-/* 0x48 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, +-/* 0x50 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, +-/* 0x58 */ _ASC, _ASC, _ASC, _UNK, _PFX, _UNK, _PFX, _ASC, +-/* 0x60 */ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, +-/* 0x68 */ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, _UNK, +-/* 0x70 */ 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, +-/* 0x78 */ 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, +-/* 0x80 */ 0x2b, 0x2c, 0x2d, 0x2e, 0x70, 0x71, 0x2f, 0x30, +-/* 0x88 */ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x72, +-/* 0x90 */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x73, 0x74, +-/* 0x98 */ 0x75, 0x76, _UNK, _UNK, 0x77, 0x78, 0x79, 0x7A, +-/* 0xA0 */ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x60, 0x61, +-/* 0xA8 */ 0x62, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0xB0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0xB8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0xC0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0xC8 */ _UNK, _UNK, _UNK, _UNK, 0x44, _UNK, _UNK, _UNK, +-/* 0xD0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0xD8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0xE0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0xE8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0xF0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0xF8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x45, ++/* 0x00 */ 0x00, 0x01, _UNK, _UNK, _UNK, _UNK, 0x02, _UNK, ++/* 0x08 */ 0x03, _UNK, 0x04, 0x05, 0x06, 0x07, 0x6E, _UNK, ++/* 0x10 */ 0x08, 0x09, 0x0a, 0x6F, 0x0b, _UNK, _UNK, _UNK, ++/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0x20 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0x28 */ _UNK, _UNK, _UNK, _UNK, _UNK, 0x63, _PFX, _PFX, ++/* 0x30 */ 0x67, 0x66, 0x68, 0x65, 0x69, 0x64, 0x6A, _UNK, ++/* 0x38 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0x40 */ _UNK, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, ++/* 0x48 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, ++/* 0x50 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, ++/* 0x58 */ _ASC, _ASC, _ASC, _UNK, _PFX, _UNK, _PFX, _ASC, ++/* 0x60 */ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, ++/* 0x68 */ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, _UNK, ++/* 0x70 */ 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, ++/* 0x78 */ 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, ++/* 0x80 */ 0x2b, 0x2c, 0x2d, 0x2e, 0x70, 0x71, 0x2f, 0x30, ++/* 0x88 */ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x72, ++/* 0x90 */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x73, 0x74, ++/* 0x98 */ 0x75, 0x76, _UNK, _UNK, 0x77, 0x78, 0x79, 0x7A, ++/* 0xA0 */ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x60, 0x61, ++/* 0xA8 */ 0x62, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0xB0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0xB8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0xC0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0xC8 */ _UNK, _UNK, _UNK, _UNK, 0x44, _UNK, _UNK, _UNK, ++/* 0xD0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0xD8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0xE0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0xE8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0xF0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0xF8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x45, + }; + + +@@ -523,24 +523,24 @@ + { + /* 0 1 2 3 4 5 6 7 */ + /* 8 9 A B C D E F */ +-/* 0x00 */ _UNK, 0x46, 0x47, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0x08 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0x10 */ _UNK, _UNK, 0x48, 0x49, _UNK, _UNK, _UNK, _UNK, +-/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x7B, +-/* 0x20 */ 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, +-/* 0x28 */ 0x52, 0x53, 0x54, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0x30 */ 0x55, 0x56, 0x57, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0x38 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0x40 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0x48 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0x50 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0x58 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0x60 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0x68 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0x70 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0x78 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +-/* 0x80 */ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, +-/* 0x88 */ 0x7C, ++/* 0x00 */ _UNK, 0x46, 0x47, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0x08 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0x10 */ _UNK, _UNK, 0x48, 0x49, _UNK, _UNK, _UNK, _UNK, ++/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x7B, ++/* 0x20 */ 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, ++/* 0x28 */ 0x52, 0x53, 0x54, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0x30 */ 0x55, 0x56, 0x57, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0x38 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0x40 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0x48 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0x50 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0x58 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0x60 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0x68 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0x70 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0x78 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, ++/* 0x80 */ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, ++/* 0x88 */ 0x7C, + }; + + +@@ -581,8 +581,7 @@ + * Detect normal 8-bit opcode or extended 16-bit opcode + */ + +- switch (upper_opcode) +- { ++ switch (upper_opcode) { + case 0: + + /* Simple (8-bit) opcode: 0-255, can't index beyond table */ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/parser/psparse.c linux/drivers/acpi/parser/psparse.c +--- /usr/src/linux/drivers/acpi/parser/psparse.c Mon Jan 29 10:15:59 2001 ++++ linux/drivers/acpi/parser/psparse.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: psparse - Parser top level AML parse routines +- * $Revision: 74 $ ++ * $Revision: 81 $ + * + *****************************************************************************/ + +@@ -39,8 +39,9 @@ + #include "amlcode.h" + #include "acnamesp.h" + #include "acdebug.h" ++#include "acinterp.h" + +-#define _COMPONENT PARSER ++#define _COMPONENT ACPI_PARSER + MODULE_NAME ("psparse") + + +@@ -260,8 +261,7 @@ + (opcode_class != OPTYPE_LOCAL_VARIABLE) && + (opcode_class != OPTYPE_METHOD_ARGUMENT) && + (opcode_class != OPTYPE_DATA_TERM) && +- (op->opcode != AML_NAMEPATH_OP)) +- { ++ (op->opcode != AML_NAMEPATH_OP)) { + /* Make sure that we only delete this subtree */ + + if (op->parent) { +@@ -272,8 +272,7 @@ + + parent_info = acpi_ps_get_opcode_info (op->parent->opcode); + +- switch (ACPI_GET_OP_CLASS (parent_info)) +- { ++ switch (ACPI_GET_OP_CLASS (parent_info)) { + case OPTYPE_CONTROL: /* IF, ELSE, WHILE only */ + break; + +@@ -284,14 +283,13 @@ + * op must be replace by a placeholder return op + */ + +- if ((op->parent->opcode == AML_REGION_OP) || +- (op->parent->opcode == AML_CREATE_FIELD_OP) || +- (op->parent->opcode == AML_BIT_FIELD_OP) || +- (op->parent->opcode == AML_BYTE_FIELD_OP) || +- (op->parent->opcode == AML_WORD_FIELD_OP) || +- (op->parent->opcode == AML_DWORD_FIELD_OP) || +- (op->parent->opcode == AML_QWORD_FIELD_OP)) +- { ++ if ((op->parent->opcode == AML_REGION_OP) || ++ (op->parent->opcode == AML_CREATE_FIELD_OP) || ++ (op->parent->opcode == AML_CREATE_BIT_FIELD_OP) || ++ (op->parent->opcode == AML_CREATE_BYTE_FIELD_OP) || ++ (op->parent->opcode == AML_CREATE_WORD_FIELD_OP) || ++ (op->parent->opcode == AML_CREATE_DWORD_FIELD_OP) || ++ (op->parent->opcode == AML_CREATE_QWORD_FIELD_OP)) { + replacement_op = acpi_ps_alloc_op (AML_RETURN_VALUE_OP); + if (!replacement_op) { + return (FALSE); +@@ -388,8 +386,7 @@ + u32 package_length; + + +- switch (callback_status) +- { ++ switch (callback_status) { + case AE_CTRL_TERMINATE: + + /* +@@ -505,7 +502,7 @@ + ACPI_PARSE2_OBJECT *deferred_op; + u32 arg_count; /* push for fixed or var args */ + u32 arg_types = 0; +- ACPI_PTRDIFF aml_offset; ++ u32 aml_offset; + u16 opcode; + ACPI_PARSE_OBJECT pre_op; + ACPI_PARSE_STATE *parser_state; +@@ -528,8 +525,7 @@ + (parser_state->scope->parse_scope.op->opcode == AML_WHILE_OP)) && + (walk_state->control_state) && + (walk_state->control_state->common.state == +- CONTROL_PREDICATE_EXECUTING)) +- { ++ CONTROL_PREDICATE_EXECUTING)) { + + /* + * A predicate was just completed, get the value of the +@@ -538,8 +534,7 @@ + + status = acpi_ds_get_predicate_value (walk_state, NULL, TRUE); + if (ACPI_FAILURE (status) && +- ((status & AE_CODE_MASK) != AE_CODE_CONTROL)) +- { ++ ((status & AE_CODE_MASK) != AE_CODE_CONTROL)) { + return (status); + } + +@@ -577,8 +572,7 @@ + */ + + op_info = acpi_ps_get_opcode_info (opcode); +- switch (ACPI_GET_OP_TYPE (op_info)) +- { ++ switch (ACPI_GET_OP_TYPE (op_info)) { + case ACPI_OP_TYPE_OPCODE: + + /* Found opcode info, this is a normal opcode */ +@@ -684,12 +678,12 @@ + } + + +- if ((op->opcode == AML_CREATE_FIELD_OP) || +- (op->opcode == AML_BIT_FIELD_OP) || +- (op->opcode == AML_BYTE_FIELD_OP) || +- (op->opcode == AML_WORD_FIELD_OP) || +- (op->opcode == AML_DWORD_FIELD_OP)) +- { ++ if ((op->opcode == AML_CREATE_FIELD_OP) || ++ (op->opcode == AML_CREATE_BIT_FIELD_OP) || ++ (op->opcode == AML_CREATE_BYTE_FIELD_OP) || ++ (op->opcode == AML_CREATE_WORD_FIELD_OP) || ++ (op->opcode == AML_CREATE_DWORD_FIELD_OP) || ++ (op->opcode == AML_CREATE_QWORD_FIELD_OP)) { + /* + * Backup to beginning of Create_xXXfield declaration + * Body_length is unknown until we parse the body +@@ -733,8 +727,7 @@ + if (arg_types) /* Are there any arguments that must be processed? */ { + /* get arguments */ + +- switch (op->opcode) +- { ++ switch (op->opcode) { + case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ + case AML_WORD_OP: /* AML_WORDDATA_ARG */ + case AML_DWORD_OP: /* AML_DWORDATA_ARG */ +@@ -783,8 +776,8 @@ + */ + + deferred_op->data = parser_state->aml; +- deferred_op->length = parser_state->pkg_end - +- parser_state->aml; ++ deferred_op->length = (u32) (parser_state->pkg_end - ++ parser_state->aml); + + /* + * Skip body of method. For Op_regions, we must continue +@@ -824,19 +817,18 @@ + * know the length. + */ + +- deferred_op->length = parser_state->aml - +- deferred_op->data; ++ deferred_op->length = (u32) (parser_state->aml - ++ deferred_op->data); + } + } + } + +- if ((op->opcode == AML_CREATE_FIELD_OP) || +- (op->opcode == AML_BIT_FIELD_OP) || +- (op->opcode == AML_BYTE_FIELD_OP) || +- (op->opcode == AML_WORD_FIELD_OP) || +- (op->opcode == AML_DWORD_FIELD_OP) || +- (op->opcode == AML_QWORD_FIELD_OP)) +- { ++ if ((op->opcode == AML_CREATE_FIELD_OP) || ++ (op->opcode == AML_CREATE_BIT_FIELD_OP) || ++ (op->opcode == AML_CREATE_BYTE_FIELD_OP) || ++ (op->opcode == AML_CREATE_WORD_FIELD_OP) || ++ (op->opcode == AML_CREATE_DWORD_FIELD_OP) || ++ (op->opcode == AML_CREATE_QWORD_FIELD_OP)) { + /* + * Backup to beginning of Create_xXXfield declaration (1 for + * Opcode) +@@ -844,7 +836,8 @@ + * Body_length is unknown until we parse the body + */ + deferred_op = (ACPI_PARSE2_OBJECT *) op; +- deferred_op->length = parser_state->aml - deferred_op->data; ++ deferred_op->length = (u32) (parser_state->aml - ++ deferred_op->data); + } + + /* This op complete, notify the dispatcher */ +@@ -873,8 +866,7 @@ + } + + +- switch (status) +- { ++ switch (status) { + case AE_OK: + break; + +@@ -908,8 +900,7 @@ + status = AE_OK; + + /* Clean up */ +- do +- { ++ do { + if (op) { + acpi_ps_complete_this_op (walk_state, op); + } +@@ -970,8 +961,7 @@ + * sequential closing braces). We want to terminate each one cleanly. + */ + +- do +- { ++ do { + if (op) { + if (walk_state->ascending_callback != NULL) { + status = walk_state->ascending_callback (walk_state, op); +@@ -985,8 +975,7 @@ + status = AE_OK; + + /* Clean up */ +- do +- { ++ do { + if (op) { + acpi_ps_complete_this_op (walk_state, op); + } +@@ -1068,6 +1057,8 @@ + /* Create and initialize a new walk list */ + + walk_list.walk_state = NULL; ++ walk_list.acquired_mutex_list.prev = NULL; ++ walk_list.acquired_mutex_list.next = NULL; + + walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, parser_state->start_op, mth_desc, &walk_list); + if (!walk_state) { +@@ -1187,8 +1178,7 @@ + + walk_state = acpi_ds_get_current_walk_state (&walk_list); + if (walk_state && +- ACPI_SUCCESS (status)) +- { ++ ACPI_SUCCESS (status)) { + /* There is another walk state, restart it */ + + /* +@@ -1219,6 +1209,7 @@ + + /* Normal exit */ + ++ acpi_aml_release_all_mutexes ((ACPI_OPERAND_OBJECT *) &walk_list.acquired_mutex_list); + acpi_gbl_current_walk_list = prev_walk_list; + return (status); + +@@ -1231,6 +1222,7 @@ + acpi_ps_cleanup_scope (parser_state); + acpi_cm_free (parser_state); + ++ acpi_aml_release_all_mutexes ((ACPI_OPERAND_OBJECT *)&walk_list.acquired_mutex_list); + acpi_gbl_current_walk_list = prev_walk_list; + + return (status); +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/parser/psscope.c linux/drivers/acpi/parser/psscope.c +--- /usr/src/linux/drivers/acpi/parser/psscope.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/parser/psscope.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: psscope - Parser scope stack management routines +- * $Revision: 24 $ ++ * $Revision: 25 $ + * + *****************************************************************************/ + +@@ -27,7 +27,7 @@ + #include "acpi.h" + #include "acparser.h" + +-#define _COMPONENT PARSER ++#define _COMPONENT ACPI_PARSER + MODULE_NAME ("psscope") + + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/parser/pstree.c linux/drivers/acpi/parser/pstree.c +--- /usr/src/linux/drivers/acpi/parser/pstree.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/parser/pstree.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: pstree - Parser op tree manipulation/traversal/search +- * $Revision: 27 $ ++ * $Revision: 29 $ + * + *****************************************************************************/ + +@@ -28,7 +28,7 @@ + #include "acparser.h" + #include "amlcode.h" + +-#define _COMPONENT PARSER ++#define _COMPONENT ACPI_PARSER + MODULE_NAME ("pstree") + + +@@ -174,8 +174,7 @@ + ACPI_PARSE_OBJECT *child = NULL; + + +- switch (op->opcode) +- { ++ switch (op->opcode) { + case AML_SCOPE_OP: + case AML_ELSE_OP: + case AML_DEVICE_OP: +@@ -191,7 +190,7 @@ + case AML_METHOD_OP: + case AML_IF_OP: + case AML_WHILE_OP: +- case AML_DEF_FIELD_OP: ++ case AML_FIELD_OP: + + child = acpi_ps_get_arg (op, 1); + break; +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/parser/psutils.c linux/drivers/acpi/parser/psutils.c +--- /usr/src/linux/drivers/acpi/parser/psutils.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/parser/psutils.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: psutils - Parser miscellaneous utilities (Parser only) +- * $Revision: 32 $ ++ * $Revision: 34 $ + * + *****************************************************************************/ + +@@ -28,7 +28,7 @@ + #include "acparser.h" + #include "amlcode.h" + +-#define _COMPONENT PARSER ++#define _COMPONENT ACPI_PARSER + MODULE_NAME ("psutils") + + +@@ -350,27 +350,28 @@ + u16 opcode) + { + return ((u8) +- (opcode == AML_SCOPE_OP || +- opcode == AML_DEVICE_OP || +- opcode == AML_THERMAL_ZONE_OP || +- opcode == AML_METHOD_OP || +- opcode == AML_POWER_RES_OP || +- opcode == AML_PROCESSOR_OP || +- opcode == AML_DEF_FIELD_OP || +- opcode == AML_INDEX_FIELD_OP || +- opcode == AML_BANK_FIELD_OP || +- opcode == AML_NAMEDFIELD_OP || +- opcode == AML_NAME_OP || +- opcode == AML_ALIAS_OP || +- opcode == AML_MUTEX_OP || +- opcode == AML_EVENT_OP || +- opcode == AML_REGION_OP || +- opcode == AML_CREATE_FIELD_OP || +- opcode == AML_BIT_FIELD_OP || +- opcode == AML_BYTE_FIELD_OP || +- opcode == AML_WORD_FIELD_OP || +- opcode == AML_DWORD_FIELD_OP || +- opcode == AML_METHODCALL_OP || ++ (opcode == AML_SCOPE_OP || ++ opcode == AML_DEVICE_OP || ++ opcode == AML_THERMAL_ZONE_OP || ++ opcode == AML_METHOD_OP || ++ opcode == AML_POWER_RES_OP || ++ opcode == AML_PROCESSOR_OP || ++ opcode == AML_FIELD_OP || ++ opcode == AML_INDEX_FIELD_OP || ++ opcode == AML_BANK_FIELD_OP || ++ opcode == AML_NAMEDFIELD_OP || ++ opcode == AML_NAME_OP || ++ opcode == AML_ALIAS_OP || ++ opcode == AML_MUTEX_OP || ++ opcode == AML_EVENT_OP || ++ opcode == AML_REGION_OP || ++ opcode == AML_CREATE_FIELD_OP || ++ opcode == AML_CREATE_BIT_FIELD_OP || ++ opcode == AML_CREATE_BYTE_FIELD_OP || ++ opcode == AML_CREATE_WORD_FIELD_OP || ++ opcode == AML_CREATE_DWORD_FIELD_OP || ++ opcode == AML_CREATE_QWORD_FIELD_OP || ++ opcode == AML_METHODCALL_OP || + opcode == AML_NAMEPATH_OP)); + } + +@@ -385,7 +386,7 @@ + opcode == AML_METHOD_OP || + opcode == AML_POWER_RES_OP || + opcode == AML_PROCESSOR_OP || +- opcode == AML_DEF_FIELD_OP || ++ opcode == AML_FIELD_OP || + opcode == AML_INDEX_FIELD_OP || + opcode == AML_BANK_FIELD_OP || + opcode == AML_NAME_OP || +@@ -408,26 +409,27 @@ + u16 opcode) + { + return ((u8) +- (opcode == AML_SCOPE_OP || +- opcode == AML_DEVICE_OP || +- opcode == AML_THERMAL_ZONE_OP || +- opcode == AML_METHOD_OP || +- opcode == AML_POWER_RES_OP || +- opcode == AML_PROCESSOR_OP || +- opcode == AML_NAMEDFIELD_OP || +- opcode == AML_NAME_OP || +- opcode == AML_ALIAS_OP || +- opcode == AML_MUTEX_OP || +- opcode == AML_EVENT_OP || +- opcode == AML_REGION_OP || +- +- +- opcode == AML_CREATE_FIELD_OP || +- opcode == AML_BIT_FIELD_OP || +- opcode == AML_BYTE_FIELD_OP || +- opcode == AML_WORD_FIELD_OP || +- opcode == AML_DWORD_FIELD_OP || +- opcode == AML_METHODCALL_OP || ++ (opcode == AML_SCOPE_OP || ++ opcode == AML_DEVICE_OP || ++ opcode == AML_THERMAL_ZONE_OP || ++ opcode == AML_METHOD_OP || ++ opcode == AML_POWER_RES_OP || ++ opcode == AML_PROCESSOR_OP || ++ opcode == AML_NAMEDFIELD_OP || ++ opcode == AML_NAME_OP || ++ opcode == AML_ALIAS_OP || ++ opcode == AML_MUTEX_OP || ++ opcode == AML_EVENT_OP || ++ opcode == AML_REGION_OP || ++ ++ ++ opcode == AML_CREATE_FIELD_OP || ++ opcode == AML_CREATE_BIT_FIELD_OP || ++ opcode == AML_CREATE_BYTE_FIELD_OP || ++ opcode == AML_CREATE_WORD_FIELD_OP || ++ opcode == AML_CREATE_DWORD_FIELD_OP || ++ opcode == AML_CREATE_QWORD_FIELD_OP || ++ opcode == AML_METHODCALL_OP || + opcode == AML_NAMEPATH_OP)); + } + +@@ -460,12 +462,13 @@ + u16 opcode) + { + return ((u8) +- (opcode == AML_METHOD_OP || +- opcode == AML_CREATE_FIELD_OP || +- opcode == AML_BIT_FIELD_OP || +- opcode == AML_BYTE_FIELD_OP || +- opcode == AML_WORD_FIELD_OP || +- opcode == AML_DWORD_FIELD_OP || ++ (opcode == AML_METHOD_OP || ++ opcode == AML_CREATE_FIELD_OP || ++ opcode == AML_CREATE_BIT_FIELD_OP || ++ opcode == AML_CREATE_BYTE_FIELD_OP || ++ opcode == AML_CREATE_WORD_FIELD_OP || ++ opcode == AML_CREATE_DWORD_FIELD_OP || ++ opcode == AML_CREATE_QWORD_FIELD_OP || + opcode == AML_REGION_OP)); + } + +@@ -490,7 +493,7 @@ + { + return ((u8) + (opcode == AML_CREATE_FIELD_OP +- || opcode == AML_DEF_FIELD_OP ++ || opcode == AML_FIELD_OP + || opcode == AML_INDEX_FIELD_OP + || opcode == AML_BANK_FIELD_OP)); + } +@@ -504,11 +507,12 @@ + u16 opcode) + { + return ((u8) +- (opcode == AML_CREATE_FIELD_OP || +- opcode == AML_BIT_FIELD_OP || +- opcode == AML_BYTE_FIELD_OP || +- opcode == AML_WORD_FIELD_OP || +- opcode == AML_DWORD_FIELD_OP)); ++ (opcode == AML_CREATE_FIELD_OP || ++ opcode == AML_CREATE_BIT_FIELD_OP || ++ opcode == AML_CREATE_BYTE_FIELD_OP || ++ opcode == AML_CREATE_WORD_FIELD_OP || ++ opcode == AML_CREATE_DWORD_FIELD_OP || ++ opcode == AML_CREATE_QWORD_FIELD_OP)); + } + + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/parser/pswalk.c linux/drivers/acpi/parser/pswalk.c +--- /usr/src/linux/drivers/acpi/parser/pswalk.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/parser/pswalk.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: pswalk - Parser routines to walk parsed op tree(s) +- * $Revision: 52 $ ++ * $Revision: 54 $ + * + *****************************************************************************/ + +@@ -31,7 +31,7 @@ + #include "acnamesp.h" + #include "acinterp.h" + +-#define _COMPONENT PARSER ++#define _COMPONENT ACPI_PARSER + MODULE_NAME ("pswalk") + + +@@ -243,6 +243,9 @@ + /* Create and initialize a new walk list */ + + walk_list.walk_state = NULL; ++ walk_list.acquired_mutex_list.prev = NULL; ++ walk_list.acquired_mutex_list.next = NULL; ++ + walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, NULL, NULL, &walk_list); + if (!walk_state) { + return; +@@ -271,6 +274,7 @@ + + /* We are done with this walk */ + ++ acpi_aml_release_all_mutexes ((ACPI_OPERAND_OBJECT *) &walk_list.acquired_mutex_list); + acpi_ds_delete_walk_state (walk_state); + + return; +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/parser/psxface.c linux/drivers/acpi/parser/psxface.c +--- /usr/src/linux/drivers/acpi/parser/psxface.c Mon Jan 29 10:15:59 2001 ++++ linux/drivers/acpi/parser/psxface.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: psxface - Parser external interfaces +- * $Revision: 40 $ ++ * $Revision: 42 $ + * + *****************************************************************************/ + +@@ -32,7 +32,7 @@ + #include "acnamesp.h" + + +-#define _COMPONENT PARSER ++#define _COMPONENT ACPI_PARSER + MODULE_NAME ("psxface") + + +@@ -79,7 +79,7 @@ + + /* Init for new method, wait on concurrency semaphore */ + +- status = acpi_ds_begin_method_execution (method_node, obj_desc); ++ status = acpi_ds_begin_method_execution (method_node, obj_desc, NULL); + if (ACPI_FAILURE (status)) { + return (status); + } +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/power.c linux/drivers/acpi/power.c +--- /usr/src/linux/drivers/acpi/power.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/power.c Wed Dec 31 16:00:00 1969 +@@ -1,137 +0,0 @@ +-/* +- * power.c - Overall power driver. Also handles AC adapter device. +- * +- * Copyright (C) 2000 Andrew Grover +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +-#include <linux/kernel.h> +-#include <linux/types.h> +-#include <linux/proc_fs.h> +-#include "acpi.h" +-#include "driver.h" +- +-#define _COMPONENT OS_DEPENDENT +- MODULE_NAME ("power") +- +-int acpi_cmbatt_init(void); +-int acpi_cmbatt_terminate(void); +- +-/* ACPI-specific defines */ +-#define ACPI_AC_ADAPTER_HID "ACPI0003" +- +-static int ac_count = 0; +-static ACPI_HANDLE ac_handle = 0; +- +-/* +- * We found a device with the correct HID +- */ +-static ACPI_STATUS +-acpi_found_ac_adapter(ACPI_HANDLE handle, u32 level, void *ctx, void **value) +-{ +- ACPI_DEVICE_INFO info; +- +- if (ac_count > 0) { +- printk(KERN_ERR "AC Adapter: more than one!\n"); +- return (AE_OK); +- } +- +- if (!ACPI_SUCCESS(acpi_get_object_info(handle, &info))) { +- printk(KERN_ERR "AC Adapter: Could not get AC Adapter object info\n"); +- return (AE_OK); +- } +- +- if (!(info.valid & ACPI_VALID_STA)) { +- printk(KERN_ERR "AC Adapter: Battery _STA invalid\n"); +- return AE_OK; +- } +- +- printk(KERN_INFO "AC Adapter: found\n"); +- +- ac_handle = handle; +- +- ac_count++; +- +- return AE_OK; +-} +- +-static int +-proc_read_ac_adapter_status(char *page, char **start, off_t off, +- int count, int *eof, void *data) +-{ +- ACPI_OBJECT obj; +- ACPI_BUFFER buf; +- +- char *p = page; +- int len; +- +- buf.length = sizeof(obj); +- buf.pointer = &obj; +- if (!ACPI_SUCCESS(acpi_evaluate_object(ac_handle, "_PSR", NULL, &buf)) +- || obj.type != ACPI_TYPE_INTEGER) { +- p += sprintf(p, "Could not read AC status\n"); +- goto end; +- } +- +- if (obj.integer.value) +- p += sprintf(p, "on-line\n"); +- else +- p += sprintf(p, "off-line\n"); +- +-end: +- len = (p - page); +- if (len <= off+count) *eof = 1; +- *start = page + off; +- len -= off; +- if (len>count) len = count; +- if (len<0) len = 0; +- return len; +-} +- +-int +-acpi_power_init(void) +-{ +- acpi_get_devices(ACPI_AC_ADAPTER_HID, +- acpi_found_ac_adapter, +- NULL, +- NULL); +- +- if (!proc_mkdir("power", NULL)) +- return 0; +- +- if (ac_handle) { +- create_proc_read_entry("power/ac", 0, NULL, +- proc_read_ac_adapter_status, NULL); +- } +- +- acpi_cmbatt_init(); +- +- return 0; +-} +- +-int +-acpi_power_terminate(void) +-{ +- acpi_cmbatt_terminate(); +- +- if (ac_handle) { +- remove_proc_entry("power/ac", NULL); +- } +- +- remove_proc_entry("power", NULL); +- +- return 0; +-} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resource/Makefile linux/drivers/acpi/resource/Makefile +--- /usr/src/linux/drivers/acpi/resource/Makefile Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/resource/Makefile Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,17 @@ ++# ++# Makefile for all Linux ACPI interpreter subdirectories ++# EXCEPT for the ospm directory ++# ++ ++O_TARGET := ../$(shell basename `pwd`).o ++ ++obj-$(CONFIG_ACPI) := $(patsubst %.c,%.o,$(wildcard *.c)) ++ ++EXTRA_CFLAGS += -I../include ++ ++EXTRA_CFLAGS += $(ACPI_CFLAGS) ++ ++include $(TOPDIR)/Rules.make ++ ++clean: ++ $(RM) *.o +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resource/rsaddr.c linux/drivers/acpi/resource/rsaddr.c +--- /usr/src/linux/drivers/acpi/resource/rsaddr.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/resource/rsaddr.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,1218 @@ ++/******************************************************************************* ++ * ++ * Module Name: rsaddr - Acpi_rs_address16_resource ++ * Acpi_rs_address16_stream ++ * Acpi_rs_address32_resource ++ * Acpi_rs_address32_stream ++ * Acpi_rs_address64_resource ++ * Acpi_rs_address64_stream ++ * ++ * $Revision: 16 $ ++ * ++ ******************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acresrc.h" ++ ++#define _COMPONENT ACPI_RESOURCES ++ MODULE_NAME ("rsaddr") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_address16_resource ++ * ++ * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte ++ * stream ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes consumed from ++ * the Byte_stream_buffer ++ * Output_buffer - Pointer to the user's return buffer ++ * Structure_size - u32 pointer that is filled with ++ * the number of bytes in the filled ++ * in structure ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the resource byte stream and fill out the appropriate ++ * structure pointed to by the Output_buffer. Return the ++ * number of bytes consumed from the byte stream. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_address16_resource ( ++ u8 *byte_stream_buffer, ++ u32 *bytes_consumed, ++ u8 **output_buffer, ++ u32 *structure_size) ++{ ++ u8 *buffer = byte_stream_buffer; ++ RESOURCE *output_struct = (RESOURCE *) * output_buffer; ++ u16 temp16; ++ u8 temp8; ++ NATIVE_CHAR *temp_ptr; ++ u32 index; ++ u32 struct_size = sizeof(ADDRESS16_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA; ++ ++ ++ /* ++ * Point past the Descriptor to get the number of bytes consumed ++ */ ++ buffer += 1; ++ ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ ++ *bytes_consumed = temp16 + 3; ++ ++ output_struct->id = address16; ++ ++ /* ++ * Get the Resource Type (Byte3) ++ */ ++ buffer += 2; ++ temp8 = *buffer; ++ ++ /* Values 0-2 are valid */ ++ if (temp8 > 2) { ++ return (AE_AML_ERROR); ++ } ++ ++ output_struct->data.address16.resource_type = temp8 & 0x03; ++ ++ /* ++ * Get the General Flags (Byte4) ++ */ ++ buffer += 1; ++ temp8 = *buffer; ++ ++ /* ++ * Producer / Consumer ++ */ ++ output_struct->data.address16.producer_consumer = temp8 & 0x01; ++ ++ /* ++ * Decode ++ */ ++ output_struct->data.address16.decode = (temp8 >> 1) & 0x01; ++ ++ /* ++ * Min Address Fixed ++ */ ++ output_struct->data.address16.min_address_fixed = (temp8 >> 2) & 0x01; ++ ++ /* ++ * Max Address Fixed ++ */ ++ output_struct->data.address16.max_address_fixed = (temp8 >> 3) & 0x01; ++ ++ /* ++ * Get the Type Specific Flags (Byte5) ++ */ ++ buffer += 1; ++ temp8 = *buffer; ++ ++ if (MEMORY_RANGE == output_struct->data.address16.resource_type) { ++ output_struct->data.address16.attribute.memory.read_write_attribute = ++ (u16) (temp8 & 0x01); ++ output_struct->data.address16.attribute.memory.cache_attribute = ++ (u16) ((temp8 >> 1) & 0x0F); ++ } ++ ++ else { ++ if (IO_RANGE == output_struct->data.address16.resource_type) { ++ output_struct->data.address16.attribute.io.range_attribute = ++ (u16) (temp8 & 0x03); ++ } ++ ++ else { ++ /* BUS_NUMBER_RANGE == Address16.Data->Resource_type */ ++ /* Nothing needs to be filled in */ ++ } ++ } ++ ++ /* ++ * Get Granularity (Bytes 6-7) ++ */ ++ buffer += 1; ++ MOVE_UNALIGNED16_TO_16 (&output_struct->data.address16.granularity, ++ buffer); ++ ++ /* ++ * Get Min_address_range (Bytes 8-9) ++ */ ++ buffer += 2; ++ MOVE_UNALIGNED16_TO_16 (&output_struct->data.address16.min_address_range, ++ buffer); ++ ++ /* ++ * Get Max_address_range (Bytes 10-11) ++ */ ++ buffer += 2; ++ MOVE_UNALIGNED16_TO_16 ++ (&output_struct->data.address16.max_address_range, ++ buffer); ++ ++ /* ++ * Get Address_translation_offset (Bytes 12-13) ++ */ ++ buffer += 2; ++ MOVE_UNALIGNED16_TO_16 ++ (&output_struct->data.address16.address_translation_offset, ++ buffer); ++ ++ /* ++ * Get Address_length (Bytes 14-15) ++ */ ++ buffer += 2; ++ MOVE_UNALIGNED16_TO_16 ++ (&output_struct->data.address16.address_length, ++ buffer); ++ ++ /* ++ * Resource Source Index (if present) ++ */ ++ buffer += 2; ++ ++ /* ++ * This will leave us pointing to the Resource Source Index ++ * If it is present, then save it off and calculate the ++ * pointer to where the null terminated string goes: ++ * Each Interrupt takes 32-bits + the 5 bytes of the ++ * stream that are default. ++ */ ++ if (*bytes_consumed > 16) { ++ /* Dereference the Index */ ++ ++ temp8 = *buffer; ++ output_struct->data.address16.resource_source.index = ++ (u32) temp8; ++ ++ /* Point to the String */ ++ ++ buffer += 1; ++ ++ /* Point the String pointer to the end of this structure */ ++ ++ output_struct->data.address16.resource_source.string_ptr = ++ (NATIVE_CHAR *)((u8 *)output_struct + struct_size); ++ ++ temp_ptr = output_struct->data.address16.resource_source.string_ptr; ++ ++ /* Copy the string into the buffer */ ++ ++ index = 0; ++ ++ while (0x00 != *buffer) { ++ *temp_ptr = *buffer; ++ ++ temp_ptr += 1; ++ buffer += 1; ++ index += 1; ++ } ++ ++ /* ++ * Add the terminating null ++ */ ++ *temp_ptr = 0x00; ++ ++ output_struct->data.address16.resource_source.string_length = ++ index + 1; ++ ++ /* ++ * In order for the Struct_size to fall on a 32-bit boundry, ++ * calculate the length of the string and expand the ++ * Struct_size to the next 32-bit boundry. ++ */ ++ temp8 = (u8) (index + 1); ++ struct_size += ROUND_UP_TO_32_bITS (temp8); ++ } ++ else { ++ output_struct->data.address16.resource_source.index = 0x00; ++ output_struct->data.address16.resource_source.string_length = 0; ++ output_struct->data.address16.resource_source.string_ptr = NULL; ++ } ++ ++ /* ++ * Set the Length parameter ++ */ ++ output_struct->length = struct_size; ++ ++ /* ++ * Return the final size of the structure ++ */ ++ *structure_size = struct_size; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_address16_stream ++ * ++ * PARAMETERS: Linked_list - Pointer to the resource linked list ++ * Output_buffer - Pointer to the user's return buffer ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes of the ++ * Output_buffer used ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the linked list resource structure and fills in the ++ * the appropriate bytes in a byte stream ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_address16_stream ( ++ RESOURCE *linked_list, ++ u8 **output_buffer, ++ u32 *bytes_consumed) ++{ ++ u8 *buffer = *output_buffer; ++ u8 *length_field; ++ u8 temp8; ++ NATIVE_CHAR *temp_pointer = NULL; ++ u32 actual_bytes; ++ ++ ++ /* ++ * The descriptor field is static ++ */ ++ *buffer = 0x88; ++ buffer += 1; ++ ++ /* ++ * Save a pointer to the Length field - to be filled in later ++ */ ++ length_field = buffer; ++ buffer += 2; ++ ++ /* ++ * Set the Resource Type (Memory, Io, Bus_number) ++ */ ++ temp8 = (u8) (linked_list->data.address16.resource_type & 0x03); ++ *buffer = temp8; ++ buffer += 1; ++ ++ /* ++ * Set the general flags ++ */ ++ temp8 = (u8) (linked_list->data.address16.producer_consumer & 0x01); ++ ++ temp8 |= (linked_list->data.address16.decode & 0x01) << 1; ++ temp8 |= (linked_list->data.address16.min_address_fixed & 0x01) << 2; ++ temp8 |= (linked_list->data.address16.max_address_fixed & 0x01) << 3; ++ ++ *buffer = temp8; ++ buffer += 1; ++ ++ /* ++ * Set the type specific flags ++ */ ++ temp8 = 0; ++ ++ if (MEMORY_RANGE == linked_list->data.address16.resource_type) { ++ temp8 = (u8) ++ (linked_list->data.address16.attribute.memory.read_write_attribute & ++ 0x01); ++ ++ temp8 |= ++ (linked_list->data.address16.attribute.memory.cache_attribute & ++ 0x0F) << 1; ++ } ++ ++ else if (IO_RANGE == linked_list->data.address16.resource_type) { ++ temp8 = (u8) ++ (linked_list->data.address16.attribute.io.range_attribute & ++ 0x03); ++ } ++ ++ *buffer = temp8; ++ buffer += 1; ++ ++ /* ++ * Set the address space granularity ++ */ ++ MOVE_UNALIGNED16_TO_16 (buffer, ++ &linked_list->data.address16.granularity); ++ buffer += 2; ++ ++ /* ++ * Set the address range minimum ++ */ ++ MOVE_UNALIGNED16_TO_16 (buffer, ++ &linked_list->data.address16.min_address_range); ++ buffer += 2; ++ ++ /* ++ * Set the address range maximum ++ */ ++ MOVE_UNALIGNED16_TO_16 (buffer, ++ &linked_list->data.address16.max_address_range); ++ buffer += 2; ++ ++ /* ++ * Set the address translation offset ++ */ ++ MOVE_UNALIGNED16_TO_16 (buffer, ++ &linked_list->data.address16.address_translation_offset); ++ buffer += 2; ++ ++ /* ++ * Set the address length ++ */ ++ MOVE_UNALIGNED16_TO_16 (buffer, ++ &linked_list->data.address16.address_length); ++ buffer += 2; ++ ++ /* ++ * Resource Source Index and Resource Source are optional ++ */ ++ if (0 != linked_list->data.address16.resource_source.string_length) { ++ temp8 = (u8) linked_list->data.address16.resource_source.index; ++ ++ *buffer = temp8; ++ buffer += 1; ++ ++ temp_pointer = (NATIVE_CHAR *) buffer; ++ ++ /* ++ * Copy the string ++ */ ++ STRCPY (temp_pointer, linked_list->data.address16.resource_source.string_ptr); ++ ++ /* ++ * Buffer needs to be set to the length of the sting + one for the ++ * terminating null ++ */ ++ buffer += (STRLEN (linked_list->data.address16.resource_source.string_ptr) + 1); ++ } ++ ++ /* ++ * Return the number of bytes consumed in this operation ++ */ ++ actual_bytes = (u32) ((NATIVE_UINT) buffer - ++ (NATIVE_UINT) *output_buffer); ++ ++ *bytes_consumed = actual_bytes; ++ ++ /* ++ * Set the length field to the number of bytes consumed ++ * minus the header size (3 bytes) ++ */ ++ actual_bytes -= 3; ++ MOVE_UNALIGNED16_TO_16 (length_field, &actual_bytes); ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_address32_resource ++ * ++ * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte ++ * stream ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes consumed from ++ * the Byte_stream_buffer ++ * Output_buffer - Pointer to the user's return buffer ++ * Structure_size - u32 pointer that is filled with ++ * the number of bytes in the filled ++ * in structure ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the resource byte stream and fill out the appropriate ++ * structure pointed to by the Output_buffer. Return the ++ * number of bytes consumed from the byte stream. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_address32_resource ( ++ u8 *byte_stream_buffer, ++ u32 *bytes_consumed, ++ u8 **output_buffer, ++ u32 *structure_size) ++{ ++ u8 *buffer; ++ RESOURCE *output_struct; ++ u16 temp16; ++ u8 temp8; ++ NATIVE_CHAR *temp_ptr; ++ u32 struct_size; ++ u32 index; ++ ++ ++ buffer = byte_stream_buffer; ++ ++ output_struct = (RESOURCE *) *output_buffer; ++ ++ struct_size = sizeof (ADDRESS32_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA; ++ ++ /* ++ * Point past the Descriptor to get the number of bytes consumed ++ */ ++ buffer += 1; ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ ++ *bytes_consumed = temp16 + 3; ++ ++ output_struct->id = address32; ++ ++ /* ++ * Get the Resource Type (Byte3) ++ */ ++ buffer += 2; ++ temp8 = *buffer; ++ ++ /* Values 0-2 are valid */ ++ if(temp8 > 2) { ++ return (AE_AML_ERROR); ++ } ++ ++ output_struct->data.address32.resource_type = temp8 & 0x03; ++ ++ /* ++ * Get the General Flags (Byte4) ++ */ ++ buffer += 1; ++ temp8 = *buffer; ++ ++ /* ++ * Producer / Consumer ++ */ ++ output_struct->data.address32.producer_consumer = temp8 & 0x01; ++ ++ /* ++ * Decode ++ */ ++ output_struct->data.address32.decode = (temp8 >> 1) & 0x01; ++ ++ /* ++ * Min Address Fixed ++ */ ++ output_struct->data.address32.min_address_fixed = (temp8 >> 2) & 0x01; ++ ++ /* ++ * Max Address Fixed ++ */ ++ output_struct->data.address32.max_address_fixed = (temp8 >> 3) & 0x01; ++ ++ /* ++ * Get the Type Specific Flags (Byte5) ++ */ ++ buffer += 1; ++ temp8 = *buffer; ++ ++ if (MEMORY_RANGE == output_struct->data.address32.resource_type) { ++ output_struct->data.address32.attribute.memory.read_write_attribute = ++ (u16) (temp8 & 0x01); ++ ++ output_struct->data.address32.attribute.memory.cache_attribute = ++ (u16) ((temp8 >> 1) & 0x0F); ++ } ++ ++ else { ++ if (IO_RANGE == output_struct->data.address32.resource_type) { ++ output_struct->data.address32.attribute.io.range_attribute = ++ (u16) (temp8 & 0x03); ++ } ++ ++ else { ++ /* BUS_NUMBER_RANGE == Output_struct->Data.Address32.Resource_type */ ++ /* Nothing needs to be filled in */ ++ } ++ } ++ ++ /* ++ * Get Granularity (Bytes 6-9) ++ */ ++ buffer += 1; ++ MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.granularity, ++ buffer); ++ ++ /* ++ * Get Min_address_range (Bytes 10-13) ++ */ ++ buffer += 4; ++ MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.min_address_range, ++ buffer); ++ ++ /* ++ * Get Max_address_range (Bytes 14-17) ++ */ ++ buffer += 4; ++ MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.max_address_range, ++ buffer); ++ ++ /* ++ * Get Address_translation_offset (Bytes 18-21) ++ */ ++ buffer += 4; ++ MOVE_UNALIGNED32_TO_32 ++ (&output_struct->data.address32.address_translation_offset, ++ buffer); ++ ++ /* ++ * Get Address_length (Bytes 22-25) ++ */ ++ buffer += 4; ++ MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.address_length, ++ buffer); ++ ++ /* ++ * Resource Source Index (if present) ++ */ ++ buffer += 4; ++ ++ /* ++ * This will leave us pointing to the Resource Source Index ++ * If it is present, then save it off and calculate the ++ * pointer to where the null terminated string goes: ++ */ ++ if (*bytes_consumed > 26) { ++ /* Dereference the Index */ ++ ++ temp8 = *buffer; ++ output_struct->data.address32.resource_source.index = ++ (u32) temp8; ++ ++ /* Point to the String */ ++ ++ buffer += 1; ++ ++ /* Point the String pointer to the end of this structure */ ++ ++ output_struct->data.address32.resource_source.string_ptr = ++ (NATIVE_CHAR *)((u8 *)output_struct + struct_size); ++ ++ temp_ptr = output_struct->data.address32.resource_source.string_ptr; ++ ++ /* Copy the string into the buffer */ ++ ++ index = 0; ++ ++ while (0x00 != *buffer) { ++ *temp_ptr = *buffer; ++ ++ temp_ptr += 1; ++ buffer += 1; ++ index += 1; ++ } ++ ++ /* ++ * Add the terminating null ++ */ ++ *temp_ptr = 0x00; ++ ++ output_struct->data.address32.resource_source.string_length = ++ index + 1; ++ ++ /* ++ * In order for the Struct_size to fall on a 32-bit boundry, ++ * calculate the length of the string and expand the ++ * Struct_size to the next 32-bit boundry. ++ */ ++ temp8 = (u8) (index + 1); ++ struct_size += ROUND_UP_TO_32_bITS (temp8); ++ } ++ else { ++ output_struct->data.address32.resource_source.index = 0x00; ++ output_struct->data.address32.resource_source.string_length = 0; ++ output_struct->data.address32.resource_source.string_ptr = NULL; ++ } ++ ++ /* ++ * Set the Length parameter ++ */ ++ output_struct->length = struct_size; ++ ++ /* ++ * Return the final size of the structure ++ */ ++ *structure_size = struct_size; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_address32_stream ++ * ++ * PARAMETERS: Linked_list - Pointer to the resource linked list ++ * Output_buffer - Pointer to the user's return buffer ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes of the ++ * Output_buffer used ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the linked list resource structure and fills in the ++ * the appropriate bytes in a byte stream ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_address32_stream ( ++ RESOURCE *linked_list, ++ u8 **output_buffer, ++ u32 *bytes_consumed) ++{ ++ u8 *buffer; ++ u16 *length_field; ++ u8 temp8; ++ NATIVE_CHAR *temp_pointer; ++ ++ ++ buffer = *output_buffer; ++ ++ /* ++ * The descriptor field is static ++ */ ++ *buffer = 0x87; ++ buffer += 1; ++ ++ /* ++ * Set a pointer to the Length field - to be filled in later ++ */ ++ ++ length_field = (u16 *)buffer; ++ buffer += 2; ++ ++ /* ++ * Set the Resource Type (Memory, Io, Bus_number) ++ */ ++ temp8 = (u8) (linked_list->data.address32.resource_type & 0x03); ++ ++ *buffer = temp8; ++ buffer += 1; ++ ++ /* ++ * Set the general flags ++ */ ++ temp8 = (u8) (linked_list->data.address32.producer_consumer & 0x01); ++ temp8 |= (linked_list->data.address32.decode & 0x01) << 1; ++ temp8 |= (linked_list->data.address32.min_address_fixed & 0x01) << 2; ++ temp8 |= (linked_list->data.address32.max_address_fixed & 0x01) << 3; ++ ++ *buffer = temp8; ++ buffer += 1; ++ ++ /* ++ * Set the type specific flags ++ */ ++ temp8 = 0; ++ ++ if(MEMORY_RANGE == linked_list->data.address32.resource_type) { ++ temp8 = (u8) ++ (linked_list->data.address32.attribute.memory.read_write_attribute & ++ 0x01); ++ ++ temp8 |= ++ (linked_list->data.address32.attribute.memory.cache_attribute & ++ 0x0F) << 1; ++ } ++ ++ else if (IO_RANGE == linked_list->data.address32.resource_type) { ++ temp8 = (u8) ++ (linked_list->data.address32.attribute.io.range_attribute & ++ 0x03); ++ } ++ ++ *buffer = temp8; ++ buffer += 1; ++ ++ /* ++ * Set the address space granularity ++ */ ++ MOVE_UNALIGNED32_TO_32 (buffer, ++ &linked_list->data.address32.granularity); ++ buffer += 4; ++ ++ /* ++ * Set the address range minimum ++ */ ++ MOVE_UNALIGNED32_TO_32 (buffer, ++ &linked_list->data.address32.min_address_range); ++ buffer += 4; ++ ++ /* ++ * Set the address range maximum ++ */ ++ MOVE_UNALIGNED32_TO_32 (buffer, ++ &linked_list->data.address32.max_address_range); ++ buffer += 4; ++ ++ /* ++ * Set the address translation offset ++ */ ++ MOVE_UNALIGNED32_TO_32 (buffer, ++ &linked_list->data.address32.address_translation_offset); ++ buffer += 4; ++ ++ /* ++ * Set the address length ++ */ ++ MOVE_UNALIGNED32_TO_32 (buffer, ++ &linked_list->data.address32.address_length); ++ buffer += 4; ++ ++ /* ++ * Resource Source Index and Resource Source are optional ++ */ ++ if (0 != linked_list->data.address32.resource_source.string_length) { ++ temp8 = (u8) linked_list->data.address32.resource_source.index; ++ ++ *buffer = temp8; ++ buffer += 1; ++ ++ temp_pointer = (NATIVE_CHAR *) buffer; ++ ++ /* ++ * Copy the string ++ */ ++ STRCPY (temp_pointer, linked_list->data.address32.resource_source.string_ptr); ++ ++ /* ++ * Buffer needs to be set to the length of the sting + one for the ++ * terminating null ++ */ ++ buffer += (STRLEN (linked_list->data.address32.resource_source.string_ptr) + 1); ++ } ++ ++ /* ++ * Return the number of bytes consumed in this operation ++ */ ++ *bytes_consumed = (u32) ((NATIVE_UINT) buffer - ++ (NATIVE_UINT) *output_buffer); ++ ++ /* ++ * Set the length field to the number of bytes consumed ++ * minus the header size (3 bytes) ++ */ ++ *length_field = (u16) (*bytes_consumed - 3); ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_address64_resource ++ * ++ * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte ++ * stream ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes consumed from ++ * the Byte_stream_buffer ++ * Output_buffer - Pointer to the user's return buffer ++ * Structure_size - u32 pointer that is filled with ++ * the number of bytes in the filled ++ * in structure ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the resource byte stream and fill out the appropriate ++ * structure pointed to by the Output_buffer. Return the ++ * number of bytes consumed from the byte stream. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_address64_resource ( ++ u8 *byte_stream_buffer, ++ u32 *bytes_consumed, ++ u8 **output_buffer, ++ u32 *structure_size) ++{ ++ u8 *buffer; ++ RESOURCE *output_struct; ++ u16 temp16; ++ u8 temp8; ++ NATIVE_CHAR *temp_ptr; ++ u32 struct_size; ++ u32 index; ++ ++ ++ buffer = byte_stream_buffer; ++ ++ output_struct = (RESOURCE *) *output_buffer; ++ ++ struct_size = sizeof (ADDRESS64_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA; ++ ++ /* ++ * Point past the Descriptor to get the number of bytes consumed ++ */ ++ buffer += 1; ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ ++ *bytes_consumed = temp16 + 3; ++ ++ output_struct->id = address64; ++ ++ /* ++ * Get the Resource Type (Byte3) ++ */ ++ buffer += 2; ++ temp8 = *buffer; ++ ++ /* Values 0-2 are valid */ ++ if(temp8 > 2) { ++ return (AE_AML_ERROR); ++ } ++ ++ output_struct->data.address64.resource_type = temp8 & 0x03; ++ ++ /* ++ * Get the General Flags (Byte4) ++ */ ++ buffer += 1; ++ temp8 = *buffer; ++ ++ /* ++ * Producer / Consumer ++ */ ++ output_struct->data.address64.producer_consumer = temp8 & 0x01; ++ ++ /* ++ * Decode ++ */ ++ output_struct->data.address64.decode = (temp8 >> 1) & 0x01; ++ ++ /* ++ * Min Address Fixed ++ */ ++ output_struct->data.address64.min_address_fixed = (temp8 >> 2) & 0x01; ++ ++ /* ++ * Max Address Fixed ++ */ ++ output_struct->data.address64.max_address_fixed = (temp8 >> 3) & 0x01; ++ ++ /* ++ * Get the Type Specific Flags (Byte5) ++ */ ++ buffer += 1; ++ temp8 = *buffer; ++ ++ if (MEMORY_RANGE == output_struct->data.address64.resource_type) { ++ output_struct->data.address64.attribute.memory.read_write_attribute = ++ (u16) (temp8 & 0x01); ++ ++ output_struct->data.address64.attribute.memory.cache_attribute = ++ (u16) ((temp8 >> 1) & 0x0F); ++ } ++ ++ else { ++ if (IO_RANGE == output_struct->data.address64.resource_type) { ++ output_struct->data.address64.attribute.io.range_attribute = ++ (u16) (temp8 & 0x03); ++ } ++ ++ else { ++ /* BUS_NUMBER_RANGE == Output_struct->Data.Address64.Resource_type */ ++ /* Nothing needs to be filled in */ ++ } ++ } ++ ++ /* ++ * Get Granularity (Bytes 6-13) ++ */ ++ buffer += 1; ++ MOVE_UNALIGNED64_TO_64 (&output_struct->data.address64.granularity, ++ buffer); ++ ++ /* ++ * Get Min_address_range (Bytes 14-21) ++ */ ++ buffer += 8; ++ MOVE_UNALIGNED64_TO_64 (&output_struct->data.address64.min_address_range, ++ buffer); ++ ++ /* ++ * Get Max_address_range (Bytes 22-29) ++ */ ++ buffer += 8; ++ MOVE_UNALIGNED64_TO_64 (&output_struct->data.address64.max_address_range, ++ buffer); ++ ++ /* ++ * Get Address_translation_offset (Bytes 30-37) ++ */ ++ buffer += 8; ++ MOVE_UNALIGNED64_TO_64 ++ (&output_struct->data.address64.address_translation_offset, ++ buffer); ++ ++ /* ++ * Get Address_length (Bytes 38-45) ++ */ ++ buffer += 8; ++ MOVE_UNALIGNED64_TO_64 (&output_struct->data.address64.address_length, ++ buffer); ++ ++ /* ++ * Resource Source Index (if present) ++ */ ++ buffer += 8; ++ ++ /* ++ * This will leave us pointing to the Resource Source Index ++ * If it is present, then save it off and calculate the ++ * pointer to where the null terminated string goes: ++ * Each Interrupt takes 32-bits + the 5 bytes of the ++ * stream that are default. ++ */ ++ if (*bytes_consumed > 46) { ++ /* Dereference the Index */ ++ ++ temp8 = *buffer; ++ output_struct->data.address64.resource_source.index = ++ (u32) temp8; ++ ++ /* Point to the String */ ++ ++ buffer += 1; ++ ++ /* Point the String pointer to the end of this structure */ ++ ++ output_struct->data.address64.resource_source.string_ptr = ++ (NATIVE_CHAR *)((u8 *)output_struct + struct_size); ++ ++ temp_ptr = output_struct->data.address64.resource_source.string_ptr; ++ ++ /* Copy the string into the buffer */ ++ ++ index = 0; ++ ++ while (0x00 != *buffer) { ++ *temp_ptr = *buffer; ++ ++ temp_ptr += 1; ++ buffer += 1; ++ index += 1; ++ } ++ ++ /* ++ * Add the terminating null ++ */ ++ *temp_ptr = 0x00; ++ ++ output_struct->data.address64.resource_source.string_length = ++ index + 1; ++ ++ /* ++ * In order for the Struct_size to fall on a 32-bit boundry, ++ * calculate the length of the string and expand the ++ * Struct_size to the next 32-bit boundry. ++ */ ++ temp8 = (u8) (index + 1); ++ struct_size += ROUND_UP_TO_32_bITS (temp8); ++ } ++ else { ++ output_struct->data.address64.resource_source.index = 0x00; ++ output_struct->data.address64.resource_source.string_length = 0; ++ output_struct->data.address64.resource_source.string_ptr = NULL; ++ } ++ ++ /* ++ * Set the Length parameter ++ */ ++ output_struct->length = struct_size; ++ ++ /* ++ * Return the final size of the structure ++ */ ++ *structure_size = struct_size; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_address64_stream ++ * ++ * PARAMETERS: Linked_list - Pointer to the resource linked list ++ * Output_buffer - Pointer to the user's return buffer ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes of the ++ * Output_buffer used ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the linked list resource structure and fills in the ++ * the appropriate bytes in a byte stream ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_address64_stream ( ++ RESOURCE *linked_list, ++ u8 **output_buffer, ++ u32 *bytes_consumed) ++{ ++ u8 *buffer; ++ u16 *length_field; ++ u8 temp8; ++ NATIVE_CHAR *temp_pointer; ++ ++ ++ buffer = *output_buffer; ++ ++ /* ++ * The descriptor field is static ++ */ ++ *buffer = 0x8A; ++ buffer += 1; ++ ++ /* ++ * Set a pointer to the Length field - to be filled in later ++ */ ++ ++ length_field = (u16 *)buffer; ++ buffer += 2; ++ ++ /* ++ * Set the Resource Type (Memory, Io, Bus_number) ++ */ ++ temp8 = (u8) (linked_list->data.address64.resource_type & 0x03); ++ ++ *buffer = temp8; ++ buffer += 1; ++ ++ /* ++ * Set the general flags ++ */ ++ temp8 = (u8) (linked_list->data.address64.producer_consumer & 0x01); ++ temp8 |= (linked_list->data.address64.decode & 0x01) << 1; ++ temp8 |= (linked_list->data.address64.min_address_fixed & 0x01) << 2; ++ temp8 |= (linked_list->data.address64.max_address_fixed & 0x01) << 3; ++ ++ *buffer = temp8; ++ buffer += 1; ++ ++ /* ++ * Set the type specific flags ++ */ ++ temp8 = 0; ++ ++ if(MEMORY_RANGE == linked_list->data.address64.resource_type) { ++ temp8 = (u8) ++ (linked_list->data.address64.attribute.memory.read_write_attribute & ++ 0x01); ++ ++ temp8 |= ++ (linked_list->data.address64.attribute.memory.cache_attribute & ++ 0x0F) << 1; ++ } ++ ++ else if (IO_RANGE == linked_list->data.address64.resource_type) { ++ temp8 = (u8) ++ (linked_list->data.address64.attribute.io.range_attribute & ++ 0x03); ++ } ++ ++ *buffer = temp8; ++ buffer += 1; ++ ++ /* ++ * Set the address space granularity ++ */ ++ MOVE_UNALIGNED64_TO_64 (buffer, ++ &linked_list->data.address64.granularity); ++ buffer += 8; ++ ++ /* ++ * Set the address range minimum ++ */ ++ MOVE_UNALIGNED64_TO_64 (buffer, ++ &linked_list->data.address64.min_address_range); ++ buffer += 8; ++ ++ /* ++ * Set the address range maximum ++ */ ++ MOVE_UNALIGNED64_TO_64 (buffer, ++ &linked_list->data.address64.max_address_range); ++ buffer += 8; ++ ++ /* ++ * Set the address translation offset ++ */ ++ MOVE_UNALIGNED64_TO_64 (buffer, ++ &linked_list->data.address64.address_translation_offset); ++ buffer += 8; ++ ++ /* ++ * Set the address length ++ */ ++ MOVE_UNALIGNED64_TO_64 (buffer, ++ &linked_list->data.address64.address_length); ++ buffer += 8; ++ ++ /* ++ * Resource Source Index and Resource Source are optional ++ */ ++ if (0 != linked_list->data.address64.resource_source.string_length) { ++ temp8 = (u8) linked_list->data.address64.resource_source.index; ++ ++ *buffer = temp8; ++ buffer += 1; ++ ++ temp_pointer = (NATIVE_CHAR *) buffer; ++ ++ /* ++ * Copy the string ++ */ ++ STRCPY (temp_pointer, linked_list->data.address64.resource_source.string_ptr); ++ ++ /* ++ * Buffer needs to be set to the length of the sting + one for the ++ * terminating null ++ */ ++ buffer += (STRLEN (linked_list->data.address64.resource_source.string_ptr) + 1); ++ } ++ ++ /* ++ * Return the number of bytes consumed in this operation ++ */ ++ *bytes_consumed = (u32) ((NATIVE_UINT) buffer - ++ (NATIVE_UINT) *output_buffer); ++ ++ /* ++ * Set the length field to the number of bytes consumed ++ * minus the header size (3 bytes) ++ */ ++ *length_field = (u16) (*bytes_consumed - 3); ++ ++ return (AE_OK); ++} ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resource/rscalc.c linux/drivers/acpi/resource/rscalc.c +--- /usr/src/linux/drivers/acpi/resource/rscalc.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/resource/rscalc.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,924 @@ ++/******************************************************************************* ++ * ++ * Module Name: rscalc - Acpi_rs_calculate_byte_stream_length ++ * Acpi_rs_calculate_list_length ++ * $Revision: 25 $ ++ * ++ ******************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acresrc.h" ++#include "amlcode.h" ++#include "acnamesp.h" ++ ++#define _COMPONENT ACPI_RESOURCES ++ MODULE_NAME ("rscalc") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_calculate_byte_stream_length ++ * ++ * PARAMETERS: Linked_list - Pointer to the resource linked list ++ * Size_needed - u32 pointer of the size buffer needed ++ * to properly return the parsed data ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Takes the resource byte stream and parses it once, calculating ++ * the size buffer needed to hold the linked list that conveys ++ * the resource data. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_calculate_byte_stream_length ( ++ RESOURCE *linked_list, ++ u32 *size_needed) ++{ ++ u32 byte_stream_size_needed = 0; ++ u32 segment_size; ++ EXTENDED_IRQ_RESOURCE *ex_irq = NULL; ++ u8 done = FALSE; ++ ++ ++ while (!done) { ++ ++ /* ++ * Init the variable that will hold the size to add to the ++ * total. ++ */ ++ segment_size = 0; ++ ++ switch (linked_list->id) { ++ case irq: ++ /* ++ * IRQ Resource ++ */ ++ /* ++ * For an IRQ Resource, Byte 3, although optional, will ++ * always be created - it holds IRQ information. ++ */ ++ segment_size = 4; ++ break; ++ ++ case dma: ++ /* ++ * DMA Resource ++ */ ++ /* ++ * For this resource the size is static ++ */ ++ segment_size = 3; ++ break; ++ ++ case start_dependent_functions: ++ /* ++ * Start Dependent Functions Resource ++ */ ++ /* ++ * For a Start_dependent_functions Resource, Byte 1, ++ * although optional, will always be created. ++ */ ++ segment_size = 2; ++ break; ++ ++ case end_dependent_functions: ++ /* ++ * End Dependent Functions Resource ++ */ ++ /* ++ * For this resource the size is static ++ */ ++ segment_size = 1; ++ break; ++ ++ case io: ++ /* ++ * IO Port Resource ++ */ ++ /* ++ * For this resource the size is static ++ */ ++ segment_size = 8; ++ break; ++ ++ case fixed_io: ++ /* ++ * Fixed IO Port Resource ++ */ ++ /* ++ * For this resource the size is static ++ */ ++ segment_size = 4; ++ break; ++ ++ case vendor_specific: ++ /* ++ * Vendor Defined Resource ++ */ ++ /* ++ * For a Vendor Specific resource, if the Length is ++ * between 1 and 7 it will be created as a Small ++ * Resource data type, otherwise it is a Large ++ * Resource data type. ++ */ ++ if(linked_list->data.vendor_specific.length > 7) { ++ segment_size = 3; ++ } ++ else { ++ segment_size = 1; ++ } ++ segment_size += ++ linked_list->data.vendor_specific.length; ++ break; ++ ++ case end_tag: ++ /* ++ * End Tag ++ */ ++ /* ++ * For this resource the size is static ++ */ ++ segment_size = 2; ++ done = TRUE; ++ break; ++ ++ case memory24: ++ /* ++ * 24-Bit Memory Resource ++ */ ++ /* ++ * For this resource the size is static ++ */ ++ segment_size = 12; ++ break; ++ ++ case memory32: ++ /* ++ * 32-Bit Memory Range Resource ++ */ ++ /* ++ * For this resource the size is static ++ */ ++ segment_size = 20; ++ break; ++ ++ case fixed_memory32: ++ /* ++ * 32-Bit Fixed Memory Resource ++ */ ++ /* ++ * For this resource the size is static ++ */ ++ segment_size = 12; ++ break; ++ ++ case address16: ++ /* ++ * 16-Bit Address Resource ++ */ ++ /* ++ * The base size of this byte stream is 16. If a ++ * Resource Source string is not NULL, add 1 for ++ * the Index + the length of the null terminated ++ * string Resource Source + 1 for the null. ++ */ ++ segment_size = 16; ++ ++ if(NULL != linked_list->data.address16.resource_source.string_ptr) { ++ segment_size += (1 + ++ linked_list->data.address16.resource_source.string_length); ++ } ++ break; ++ ++ case address32: ++ /* ++ * 32-Bit Address Resource ++ */ ++ /* ++ * The base size of this byte stream is 26. If a Resource ++ * Source string is not NULL, add 1 for the Index + the ++ * length of the null terminated string Resource Source + ++ * 1 for the null. ++ */ ++ segment_size = 26; ++ ++ if(NULL != linked_list->data.address32.resource_source.string_ptr) { ++ segment_size += (1 + ++ linked_list->data.address32.resource_source.string_length); ++ } ++ break; ++ ++ case address64: ++ /* ++ * 64-Bit Address Resource ++ */ ++ /* ++ * The base size of this byte stream is 46. If a Resource ++ * Source string is not NULL, add 1 for the Index + the ++ * length of the null terminated string Resource Source + ++ * 1 for the null. ++ */ ++ segment_size = 46; ++ ++ if(NULL != linked_list->data.address64.resource_source.string_ptr) { ++ segment_size += (1 + ++ linked_list->data.address64.resource_source.string_length); ++ } ++ break; ++ ++ case extended_irq: ++ /* ++ * Extended IRQ Resource ++ */ ++ /* ++ * The base size of this byte stream is 9. This is for an ++ * Interrupt table length of 1. For each additional ++ * interrupt, add 4. ++ * If a Resource Source string is not NULL, add 1 for the ++ * Index + the length of the null terminated string ++ * Resource Source + 1 for the null. ++ */ ++ segment_size = 9; ++ ++ segment_size += ++ (linked_list->data.extended_irq.number_of_interrupts - ++ 1) * 4; ++ ++ if(NULL != ex_irq->resource_source.string_ptr) { ++ segment_size += (1 + ++ linked_list->data.extended_irq.resource_source.string_length); ++ } ++ break; ++ ++ default: ++ /* ++ * If we get here, everything is out of sync, ++ * so exit with an error ++ */ ++ return (AE_AML_ERROR); ++ break; ++ ++ } /* switch (Linked_list->Id) */ ++ ++ /* ++ * Update the total ++ */ ++ byte_stream_size_needed += segment_size; ++ ++ /* ++ * Point to the next object ++ */ ++ linked_list = (RESOURCE *) ((NATIVE_UINT) linked_list + ++ (NATIVE_UINT) linked_list->length); ++ } ++ ++ /* ++ * This is the data the caller needs ++ */ ++ *size_needed = byte_stream_size_needed; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_calculate_list_length ++ * ++ * PARAMETERS: Byte_stream_buffer - Pointer to the resource byte stream ++ * Byte_stream_buffer_length - Size of Byte_stream_buffer ++ * Size_needed - u32 pointer of the size buffer ++ * needed to properly return the ++ * parsed data ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Takes the resource byte stream and parses it once, calculating ++ * the size buffer needed to hold the linked list that conveys ++ * the resource data. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_calculate_list_length ( ++ u8 *byte_stream_buffer, ++ u32 byte_stream_buffer_length, ++ u32 *size_needed) ++{ ++ u32 buffer_size = 0; ++ u32 bytes_parsed = 0; ++ u8 number_of_interrupts = 0; ++ u8 number_of_channels = 0; ++ u8 resource_type; ++ u32 structure_size; ++ u32 bytes_consumed; ++ u8 *buffer; ++ u8 temp8; ++ u16 temp16; ++ u8 index; ++ u8 additional_bytes; ++ ++ ++ while (bytes_parsed < byte_stream_buffer_length) { ++ /* ++ * Look at the next byte in the stream ++ */ ++ resource_type = *byte_stream_buffer; ++ ++ /* ++ * See if this is a small or large resource ++ */ ++ if(resource_type & 0x80) { ++ /* ++ * Large Resource Type ++ */ ++ switch (resource_type) { ++ case MEMORY_RANGE_24: ++ /* ++ * 24-Bit Memory Resource ++ */ ++ bytes_consumed = 12; ++ ++ structure_size = sizeof (MEMORY24_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA; ++ break; ++ ++ case LARGE_VENDOR_DEFINED: ++ /* ++ * Vendor Defined Resource ++ */ ++ buffer = byte_stream_buffer; ++ ++buffer; ++ ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ bytes_consumed = temp16 + 3; ++ ++ /* ++ * Ensure a 32-bit boundary for the structure ++ */ ++ temp16 = (u16) ROUND_UP_TO_32_bITS (temp16); ++ ++ structure_size = sizeof (VENDOR_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA + ++ (temp16 * sizeof (u8)); ++ break; ++ ++ case MEMORY_RANGE_32: ++ /* ++ * 32-Bit Memory Range Resource ++ */ ++ ++ bytes_consumed = 20; ++ ++ structure_size = sizeof (MEMORY32_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA; ++ break; ++ ++ case FIXED_MEMORY_RANGE_32: ++ /* ++ * 32-Bit Fixed Memory Resource ++ */ ++ bytes_consumed = 12; ++ ++ structure_size = sizeof(FIXED_MEMORY32_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA; ++ break; ++ ++ case QWORD_ADDRESS_SPACE: ++ /* ++ * 64-Bit Address Resource ++ */ ++ buffer = byte_stream_buffer; ++ ++ ++buffer; ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ ++ bytes_consumed = temp16 + 3; ++ ++ /* ++ * Resource Source Index and Resource Source are ++ * optional elements. Check the length of the ++ * Bytestream. If it is greater than 43, that ++ * means that an Index exists and is followed by ++ * a null termininated string. Therefore, set ++ * the temp variable to the length minus the minimum ++ * byte stream length plus the byte for the Index to ++ * determine the size of the NULL terminiated string. ++ */ ++ if (43 < temp16) { ++ temp8 = (u8) (temp16 - 44); ++ } ++ else { ++ temp8 = 0; ++ } ++ ++ /* ++ * Ensure a 64-bit boundary for the structure ++ */ ++ temp8 = (u8) ROUND_UP_TO_64_bITS (temp8); ++ ++ structure_size = sizeof (ADDRESS64_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA + ++ (temp8 * sizeof (u8)); ++ break; ++ ++ case DWORD_ADDRESS_SPACE: ++ /* ++ * 32-Bit Address Resource ++ */ ++ buffer = byte_stream_buffer; ++ ++ ++buffer; ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ ++ bytes_consumed = temp16 + 3; ++ ++ /* ++ * Resource Source Index and Resource Source are ++ * optional elements. Check the length of the ++ * Bytestream. If it is greater than 23, that ++ * means that an Index exists and is followed by ++ * a null termininated string. Therefore, set ++ * the temp variable to the length minus the minimum ++ * byte stream length plus the byte for the Index to ++ * determine the size of the NULL terminiated string. ++ */ ++ if (23 < temp16) { ++ temp8 = (u8) (temp16 - 24); ++ } ++ else { ++ temp8 = 0; ++ } ++ ++ /* ++ * Ensure a 32-bit boundary for the structure ++ */ ++ temp8 = (u8) ROUND_UP_TO_32_bITS (temp8); ++ ++ structure_size = sizeof (ADDRESS32_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA + ++ (temp8 * sizeof (u8)); ++ break; ++ ++ case WORD_ADDRESS_SPACE: ++ /* ++ * 16-Bit Address Resource ++ */ ++ buffer = byte_stream_buffer; ++ ++ ++buffer; ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ ++ bytes_consumed = temp16 + 3; ++ ++ /* ++ * Resource Source Index and Resource Source are ++ * optional elements. Check the length of the ++ * Bytestream. If it is greater than 13, that ++ * means that an Index exists and is followed by ++ * a null termininated string. Therefore, set ++ * the temp variable to the length minus the minimum ++ * byte stream length plus the byte for the Index to ++ * determine the size of the NULL terminiated string. ++ */ ++ if (13 < temp16) { ++ temp8 = (u8) (temp16 - 14); ++ } ++ else { ++ temp8 = 0; ++ } ++ ++ /* ++ * Ensure a 32-bit boundry for the structure ++ */ ++ temp8 = (u8) ROUND_UP_TO_32_bITS (temp8); ++ ++ structure_size = sizeof (ADDRESS16_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA + ++ (temp8 * sizeof (u8)); ++ break; ++ ++ case EXTENDED_IRQ: ++ /* ++ * Extended IRQ ++ */ ++ buffer = byte_stream_buffer; ++ ++ ++buffer; ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ ++ bytes_consumed = temp16 + 3; ++ ++ /* ++ * Point past the length field and the ++ * Interrupt vector flags to save off the ++ * Interrupt table length to the Temp8 variable. ++ */ ++ buffer += 3; ++ temp8 = *buffer; ++ ++ /* ++ * To compensate for multiple interrupt numbers, ++ * Add 4 bytes for each additional interrupts ++ * greater than 1 ++ */ ++ additional_bytes = (u8) ((temp8 - 1) * 4); ++ ++ /* ++ * Resource Source Index and Resource Source are ++ * optional elements. Check the length of the ++ * Bytestream. If it is greater than 9, that ++ * means that an Index exists and is followed by ++ * a null termininated string. Therefore, set ++ * the temp variable to the length minus the minimum ++ * byte stream length plus the byte for the Index to ++ * determine the size of the NULL terminiated string. ++ */ ++ if (9 + additional_bytes < temp16) { ++ temp8 = (u8) (temp16 - (9 + additional_bytes)); ++ } ++ ++ else { ++ temp8 = 0; ++ } ++ ++ /* ++ * Ensure a 32-bit boundry for the structure ++ */ ++ temp8 = (u8) ROUND_UP_TO_32_bITS (temp8); ++ ++ structure_size = sizeof (EXTENDED_IRQ_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA + ++ (additional_bytes * sizeof (u8)) + ++ (temp8 * sizeof (u8)); ++ ++ break; ++ ++/* TBD: [Future] 64-bit not currently supported */ ++/* ++ case 0x8A: ++ break; ++*/ ++ ++ default: ++ /* ++ * If we get here, everything is out of sync, ++ * so exit with an error ++ */ ++ return (AE_AML_ERROR); ++ break; ++ } ++ } ++ ++ else { ++ /* ++ * Small Resource Type ++ * Only bits 7:3 are valid ++ */ ++ resource_type >>= 3; ++ ++ switch (resource_type) { ++ case IRQ_FORMAT: ++ /* ++ * IRQ Resource ++ */ ++ /* ++ * Determine if it there are two or three ++ * trailing bytes ++ */ ++ buffer = byte_stream_buffer; ++ temp8 = *buffer; ++ ++ if(temp8 & 0x01) { ++ bytes_consumed = 4; ++ } ++ ++ else { ++ bytes_consumed = 3; ++ } ++ ++ /* ++ * Point past the descriptor ++ */ ++ ++buffer; ++ ++ /* ++ * Look at the number of bits set ++ */ ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ ++ for (index = 0; index < 16; index++) { ++ if (temp16 & 0x1) { ++ ++number_of_interrupts; ++ } ++ ++ temp16 >>= 1; ++ } ++ ++ structure_size = sizeof (IO_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA + ++ (number_of_interrupts * sizeof (u32)); ++ break; ++ ++ ++ case DMA_FORMAT: ++ ++ /* ++ * DMA Resource ++ */ ++ buffer = byte_stream_buffer; ++ ++ bytes_consumed = 3; ++ ++ /* ++ * Point past the descriptor ++ */ ++ ++buffer; ++ ++ /* ++ * Look at the number of bits set ++ */ ++ temp8 = *buffer; ++ ++ for(index = 0; index < 8; index++) { ++ if(temp8 & 0x1) { ++ ++number_of_channels; ++ } ++ ++ temp8 >>= 1; ++ } ++ ++ structure_size = sizeof (DMA_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA + ++ (number_of_channels * sizeof (u32)); ++ break; ++ ++ ++ case START_DEPENDENT_TAG: ++ ++ /* ++ * Start Dependent Functions Resource ++ */ ++ /* ++ * Determine if it there are two or three trailing bytes ++ */ ++ buffer = byte_stream_buffer; ++ temp8 = *buffer; ++ ++ if(temp8 & 0x01) { ++ bytes_consumed = 2; ++ } ++ else { ++ bytes_consumed = 1; ++ } ++ ++ ++ structure_size = ++ sizeof (START_DEPENDENT_FUNCTIONS_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA; ++ break; ++ ++ ++ case END_DEPENDENT_TAG: ++ ++ /* ++ * End Dependent Functions Resource ++ */ ++ bytes_consumed = 1; ++ structure_size = RESOURCE_LENGTH; ++ break; ++ ++ ++ case IO_PORT_DESCRIPTOR: ++ /* ++ * IO Port Resource ++ */ ++ bytes_consumed = 8; ++ structure_size = sizeof (IO_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA; ++ break; ++ ++ ++ case FIXED_LOCATION_IO_DESCRIPTOR: ++ ++ /* ++ * Fixed IO Port Resource ++ */ ++ bytes_consumed = 4; ++ structure_size = sizeof (FIXED_IO_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA; ++ break; ++ ++ ++ case SMALL_VENDOR_DEFINED: ++ ++ /* ++ * Vendor Specific Resource ++ */ ++ buffer = byte_stream_buffer; ++ ++ temp8 = *buffer; ++ temp8 = (u8) (temp8 & 0x7); ++ bytes_consumed = temp8 + 1; ++ ++ /* ++ * Ensure a 32-bit boundry for the structure ++ */ ++ temp8 = (u8) ROUND_UP_TO_32_bITS (temp8); ++ structure_size = sizeof (VENDOR_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA + ++ (temp8 * sizeof (u8)); ++ break; ++ ++ ++ case END_TAG: ++ ++ /* ++ * End Tag ++ */ ++ bytes_consumed = 2; ++ structure_size = RESOURCE_LENGTH; ++ byte_stream_buffer_length = bytes_parsed; ++ break; ++ ++ ++ default: ++ /* ++ * If we get here, everything is out of sync, ++ * so exit with an error ++ */ ++ return (AE_AML_ERROR); ++ break; ++ ++ } /* switch */ ++ ++ } /* if(Resource_type & 0x80) */ ++ ++ /* ++ * Update the return value and counter ++ */ ++ buffer_size += structure_size; ++ bytes_parsed += bytes_consumed; ++ ++ /* ++ * Set the byte stream to point to the next resource ++ */ ++ byte_stream_buffer += bytes_consumed; ++ ++ } ++ ++ /* ++ * This is the data the caller needs ++ */ ++ *size_needed = buffer_size; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_calculate_pci_routing_table_length ++ * ++ * PARAMETERS: Package_object - Pointer to the package object ++ * Buffer_size_needed - u32 pointer of the size buffer ++ * needed to properly return the ++ * parsed data ++ * ++ * RETURN: Status AE_OK ++ * ++ * DESCRIPTION: Given a package representing a PCI routing table, this ++ * calculates the size of the corresponding linked list of ++ * descriptions. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_calculate_pci_routing_table_length ( ++ ACPI_OPERAND_OBJECT *package_object, ++ u32 *buffer_size_needed) ++{ ++ u32 number_of_elements; ++ u32 temp_size_needed = 0; ++ ACPI_OPERAND_OBJECT **top_object_list; ++ u32 index; ++ ACPI_OPERAND_OBJECT *package_element; ++ ACPI_OPERAND_OBJECT **sub_object_list; ++ u8 name_found; ++ u32 table_index; ++ ++ ++ number_of_elements = package_object->package.count; ++ ++ /* ++ * Calculate the size of the return buffer. ++ * The base size is the number of elements * the sizes of the ++ * structures. Additional space for the strings is added below. ++ * The minus one is to subtract the size of the u8 Source[1] ++ * member because it is added below. ++ */ ++ ++ /* ++ * But each PRT_ENTRY structure has a pointer to a string and ++ * the size of that string must be found. ++ */ ++ top_object_list = package_object->package.elements; ++ ++ for (index = 0; index < number_of_elements; index++) { ++ /* ++ * Dereference the sub-package ++ */ ++ package_element = *top_object_list; ++ ++ /* ++ * The Sub_object_list will now point to an array of the ++ * four IRQ elements: Address, Pin, Source and Source_index ++ */ ++ sub_object_list = package_element->package.elements; ++ ++ /* ++ * Scan the Irq_table_elements for the Source Name String ++ */ ++ name_found = FALSE; ++ ++ for (table_index = 0; table_index < 4 && !name_found; table_index++) { ++ if ((ACPI_TYPE_STRING == (*sub_object_list)->common.type) || ++ ((INTERNAL_TYPE_REFERENCE == (*sub_object_list)->common.type) && ++ ((*sub_object_list)->reference.opcode == AML_NAMEPATH_OP))) { ++ name_found = TRUE; ++ } ++ ++ else { ++ /* ++ * Look at the next element ++ */ ++ sub_object_list++; ++ } ++ } ++ ++ temp_size_needed += (sizeof (PCI_ROUTING_TABLE) - 4); ++ ++ /* ++ * Was a String type found? ++ */ ++ if (TRUE == name_found) { ++ if (ACPI_TYPE_STRING == (*sub_object_list)->common.type) { ++ /* ++ * The length String.Length field includes the ++ * terminating NULL ++ */ ++ temp_size_needed += (*sub_object_list)->string.length; ++ } ++ else { ++ temp_size_needed += acpi_ns_get_pathname_length ((*sub_object_list)->reference.node); ++ } ++ } ++ ++ else { ++ /* ++ * If no name was found, then this is a NULL, which is ++ * translated as a u32 zero. ++ */ ++ temp_size_needed += sizeof(u32); ++ } ++ ++ ++ /* Round up the size since each element must be aligned */ ++ ++ temp_size_needed = ROUND_UP_TO_64_bITS (temp_size_needed); ++ ++ /* ++ * Point to the next ACPI_OPERAND_OBJECT ++ */ ++ top_object_list++; ++ } ++ ++ ++ /* ++ * Adding an extra element to the end of the list, essentially a NULL terminator ++ */ ++ *buffer_size_needed = temp_size_needed + sizeof (PCI_ROUTING_TABLE); ++ ++ return (AE_OK); ++} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resource/rscreate.c linux/drivers/acpi/resource/rscreate.c +--- /usr/src/linux/drivers/acpi/resource/rscreate.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/resource/rscreate.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,425 @@ ++/******************************************************************************* ++ * ++ * Module Name: rscreate - Acpi_rs_create_resource_list ++ * Acpi_rs_create_pci_routing_table ++ * Acpi_rs_create_byte_stream ++ * $Revision: 29 $ ++ * ++ ******************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acresrc.h" ++#include "amlcode.h" ++#include "acnamesp.h" ++ ++#define _COMPONENT ACPI_RESOURCES ++ MODULE_NAME ("rscreate") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_create_resource_list ++ * ++ * PARAMETERS: ++ * Byte_stream_buffer - Pointer to the resource byte stream ++ * Output_buffer - Pointer to the user's buffer ++ * Output_buffer_length - Pointer to the size of Output_buffer ++ * ++ * RETURN: Status - AE_OK if okay, else a valid ACPI_STATUS code ++ * If Output_buffer is not large enough, Output_buffer_length ++ * indicates how large Output_buffer should be, else it ++ * indicates how may u8 elements of Output_buffer are valid. ++ * ++ * DESCRIPTION: Takes the byte stream returned from a _CRS, _PRS control method ++ * execution and parses the stream to create a linked list ++ * of device resources. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_create_resource_list ( ++ ACPI_OPERAND_OBJECT *byte_stream_buffer, ++ u8 *output_buffer, ++ u32 *output_buffer_length) ++{ ++ ++ ACPI_STATUS status; ++ u8 *byte_stream_start = NULL; ++ u32 list_size_needed = 0; ++ u32 byte_stream_buffer_length = 0; ++ ++ ++ /* ++ * Params already validated, so we don't re-validate here ++ */ ++ ++ byte_stream_buffer_length = byte_stream_buffer->buffer.length; ++ byte_stream_start = byte_stream_buffer->buffer.pointer; ++ ++ /* ++ * Pass the Byte_stream_buffer into a module that can calculate ++ * the buffer size needed for the linked list ++ */ ++ status = acpi_rs_calculate_list_length (byte_stream_start, ++ byte_stream_buffer_length, ++ &list_size_needed); ++ ++ /* ++ * Exit with the error passed back ++ */ ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ /* ++ * If the linked list will fit into the available buffer ++ * call to fill in the list ++ */ ++ ++ if (list_size_needed <= *output_buffer_length) { ++ /* ++ * Zero out the return buffer before proceeding ++ */ ++ MEMSET (output_buffer, 0x00, *output_buffer_length); ++ ++ status = acpi_rs_byte_stream_to_list (byte_stream_start, ++ byte_stream_buffer_length, ++ &output_buffer); ++ ++ /* ++ * Exit with the error passed back ++ */ ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ } ++ ++ else { ++ *output_buffer_length = list_size_needed; ++ return (AE_BUFFER_OVERFLOW); ++ } ++ ++ *output_buffer_length = list_size_needed; ++ return (AE_OK); ++ ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_create_pci_routing_table ++ * ++ * PARAMETERS: ++ * Package_object - Pointer to an ACPI_OPERAND_OBJECT ++ * package ++ * Output_buffer - Pointer to the user's buffer ++ * Output_buffer_length - Size of Output_buffer ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code. ++ * If the Output_buffer is too small, the error will be ++ * AE_BUFFER_OVERFLOW and Output_buffer_length will point ++ * to the size buffer needed. ++ * ++ * DESCRIPTION: Takes the ACPI_OPERAND_OBJECT package and creates a ++ * linked list of PCI interrupt descriptions ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_create_pci_routing_table ( ++ ACPI_OPERAND_OBJECT *package_object, ++ u8 *output_buffer, ++ u32 *output_buffer_length) ++{ ++ u8 *buffer = output_buffer; ++ ACPI_OPERAND_OBJECT **top_object_list = NULL; ++ ACPI_OPERAND_OBJECT **sub_object_list = NULL; ++ ACPI_OPERAND_OBJECT *package_element = NULL; ++ u32 buffer_size_needed = 0; ++ u32 number_of_elements = 0; ++ u32 index = 0; ++ PCI_ROUTING_TABLE *user_prt = NULL; ++ ACPI_NAMESPACE_NODE *node; ++ ACPI_STATUS status; ++ ++ ++ /* ++ * Params already validated, so we don't re-validate here ++ */ ++ ++ status = acpi_rs_calculate_pci_routing_table_length(package_object, ++ &buffer_size_needed); ++ ++ if (!ACPI_SUCCESS(status)) { ++ return (status); ++ } ++ ++ /* ++ * If the data will fit into the available buffer ++ * call to fill in the list ++ */ ++ if (buffer_size_needed <= *output_buffer_length) { ++ /* ++ * Zero out the return buffer before proceeding ++ */ ++ MEMSET (output_buffer, 0x00, *output_buffer_length); ++ ++ /* ++ * Loop through the ACPI_INTERNAL_OBJECTS - Each object should ++ * contain a u32 Address, a u8 Pin, a Name and a u8 ++ * Source_index. ++ */ ++ top_object_list = package_object->package.elements; ++ number_of_elements = package_object->package.count; ++ user_prt = (PCI_ROUTING_TABLE *) buffer; ++ ++ ++ buffer = ROUND_PTR_UP_TO_8 (buffer, u8); ++ ++ for (index = 0; index < number_of_elements; index++) { ++ /* ++ * Point User_prt past this current structure ++ * ++ * NOTE: On the first iteration, User_prt->Length will ++ * be zero because we cleared the return buffer earlier ++ */ ++ buffer += user_prt->length; ++ user_prt = (PCI_ROUTING_TABLE *) buffer; ++ ++ ++ /* ++ * Fill in the Length field with the information we ++ * have at this point. ++ * The minus four is to subtract the size of the ++ * u8 Source[4] member because it is added below. ++ */ ++ user_prt->length = (sizeof (PCI_ROUTING_TABLE) -4); ++ ++ /* ++ * Dereference the sub-package ++ */ ++ package_element = *top_object_list; ++ ++ /* ++ * The Sub_object_list will now point to an array of ++ * the four IRQ elements: Address, Pin, Source and ++ * Source_index ++ */ ++ sub_object_list = package_element->package.elements; ++ ++ /* ++ * 1) First subobject: Dereference the Address ++ */ ++ if (ACPI_TYPE_INTEGER == (*sub_object_list)->common.type) { ++ user_prt->address = (*sub_object_list)->integer.value; ++ } ++ ++ else { ++ return (AE_BAD_DATA); ++ } ++ ++ /* ++ * 2) Second subobject: Dereference the Pin ++ */ ++ sub_object_list++; ++ ++ if (ACPI_TYPE_INTEGER == (*sub_object_list)->common.type) { ++ user_prt->pin = ++ (u32) (*sub_object_list)->integer.value; ++ } ++ ++ else { ++ return (AE_BAD_DATA); ++ } ++ ++ /* ++ * 3) Third subobject: Dereference the Source Name ++ */ ++ sub_object_list++; ++ ++ switch ((*sub_object_list)->common.type) { ++ case INTERNAL_TYPE_REFERENCE: ++ if ((*sub_object_list)->reference.opcode != AML_NAMEPATH_OP) { ++ return (AE_BAD_DATA); ++ } ++ ++ node = (*sub_object_list)->reference.node; ++ ++ /* TBD: use *remaining* length of the buffer! */ ++ ++ status = acpi_ns_handle_to_pathname ((ACPI_HANDLE *) node, ++ output_buffer_length, user_prt->source); ++ ++ user_prt->length += STRLEN (user_prt->source) + 1; /* include null terminator */ ++ break; ++ ++ ++ case ACPI_TYPE_STRING: ++ ++ STRCPY (user_prt->source, ++ (*sub_object_list)->string.pointer); ++ ++ /* ++ * Add to the Length field the length of the string ++ */ ++ user_prt->length += (*sub_object_list)->string.length; ++ break; ++ ++ ++ case ACPI_TYPE_INTEGER: ++ /* ++ * If this is a number, then the Source Name ++ * is NULL, since the entire buffer was zeroed ++ * out, we can leave this alone. ++ */ ++ /* ++ * Add to the Length field the length of ++ * the u32 NULL ++ */ ++ user_prt->length += sizeof (u32); ++ break; ++ ++ ++ default: ++ return (AE_BAD_DATA); ++ break; ++ } ++ ++ /* Now align the current length */ ++ ++ user_prt->length = ROUND_UP_TO_64_bITS (user_prt->length); ++ ++ /* ++ * 4) Fourth subobject: Dereference the Source Index ++ */ ++ sub_object_list++; ++ ++ if (ACPI_TYPE_INTEGER == (*sub_object_list)->common.type) { ++ user_prt->source_index = ++ (u32) (*sub_object_list)->integer.value; ++ } ++ ++ else { ++ return (AE_BAD_DATA); ++ } ++ ++ /* ++ * Point to the next ACPI_OPERAND_OBJECT ++ */ ++ top_object_list++; ++ } ++ ++ } ++ ++ else { ++ *output_buffer_length = buffer_size_needed; ++ ++ return (AE_BUFFER_OVERFLOW); ++ } ++ ++ /* ++ * Report the amount of buffer used ++ */ ++ *output_buffer_length = buffer_size_needed; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_create_byte_stream ++ * ++ * PARAMETERS: ++ * Linked_list_buffer - Pointer to the resource linked list ++ * Output_buffer - Pointer to the user's buffer ++ * Output_buffer_length - Size of Output_buffer ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code. ++ * If the Output_buffer is too small, the error will be ++ * AE_BUFFER_OVERFLOW and Output_buffer_length will point ++ * to the size buffer needed. ++ * ++ * DESCRIPTION: Takes the linked list of device resources and ++ * creates a bytestream to be used as input for the ++ * _SRS control method. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_create_byte_stream ( ++ RESOURCE *linked_list_buffer, ++ u8 *output_buffer, ++ u32 *output_buffer_length) ++{ ++ ACPI_STATUS status; ++ u32 byte_stream_size_needed = 0; ++ ++ ++ /* ++ * Params already validated, so we don't re-validate here ++ * ++ * Pass the Linked_list_buffer into a module that can calculate ++ * the buffer size needed for the byte stream. ++ */ ++ status = acpi_rs_calculate_byte_stream_length (linked_list_buffer, ++ &byte_stream_size_needed); ++ ++ /* ++ * Exit with the error passed back ++ */ ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ /* ++ * If the linked list will fit into the available buffer ++ * call to fill in the list ++ */ ++ ++ if (byte_stream_size_needed <= *output_buffer_length) { ++ /* ++ * Zero out the return buffer before proceeding ++ */ ++ MEMSET (output_buffer, 0x00, *output_buffer_length); ++ ++ status = acpi_rs_list_to_byte_stream (linked_list_buffer, ++ byte_stream_size_needed, ++ &output_buffer); ++ ++ /* ++ * Exit with the error passed back ++ */ ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ } ++ else { ++ *output_buffer_length = byte_stream_size_needed; ++ return (AE_BUFFER_OVERFLOW); ++ } ++ ++ return (AE_OK); ++} ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resource/rsdump.c linux/drivers/acpi/resource/rsdump.c +--- /usr/src/linux/drivers/acpi/resource/rsdump.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/resource/rsdump.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,1072 @@ ++/******************************************************************************* ++ * ++ * Module Name: rsdump - Functions do dump out the resource structures. ++ * $Revision: 18 $ ++ * ++ ******************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acresrc.h" ++ ++#define _COMPONENT ACPI_RESOURCES ++ MODULE_NAME ("rsdump") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_dump_irq ++ * ++ * PARAMETERS: Data - pointer to the resource structure to dump. ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: Prints out the various members of the Data structure type. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_rs_dump_irq ( ++ RESOURCE_DATA *data) ++{ ++ IRQ_RESOURCE *irq_data = (IRQ_RESOURCE*) data; ++ u8 index = 0; ++ ++ ++ acpi_os_printf ("\t_iRQ Resource\n"); ++ ++ acpi_os_printf ("\t\t%s Triggered\n", ++ LEVEL_SENSITIVE == irq_data->edge_level ? ++ "Level" : "Edge"); ++ ++ acpi_os_printf ("\t\t_active %s\n", ++ ACTIVE_LOW == irq_data->active_high_low ? ++ "Low" : "High"); ++ ++ acpi_os_printf ("\t\t%s\n", ++ SHARED == irq_data->shared_exclusive ? ++ "Shared" : "Exclusive"); ++ ++ acpi_os_printf ("\t\t%X Interrupts ( ", ++ irq_data->number_of_interrupts); ++ ++ for (index = 0; index < irq_data->number_of_interrupts; index++) { ++ acpi_os_printf ("%X ", irq_data->interrupts[index]); ++ } ++ ++ acpi_os_printf (")\n"); ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_dump_dma ++ * ++ * PARAMETERS: Data - pointer to the resource structure to dump. ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: Prints out the various members of the Data structure type. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_rs_dump_dma ( ++ RESOURCE_DATA *data) ++{ ++ DMA_RESOURCE *dma_data = (DMA_RESOURCE*) data; ++ u8 index = 0; ++ ++ ++ acpi_os_printf ("\t_dMA Resource\n"); ++ ++ switch (dma_data->type) { ++ case COMPATIBILITY: ++ acpi_os_printf ("\t\t_compatibility mode\n"); ++ break; ++ ++ case TYPE_A: ++ acpi_os_printf ("\t\t_type A\n"); ++ break; ++ ++ case TYPE_B: ++ acpi_os_printf ("\t\t_type B\n"); ++ break; ++ ++ case TYPE_F: ++ acpi_os_printf ("\t\t_type F\n"); ++ break; ++ ++ default: ++ acpi_os_printf ("\t\t_invalid DMA type\n"); ++ break; ++ } ++ ++ acpi_os_printf ("\t\t%sBus Master\n", ++ BUS_MASTER == dma_data->bus_master ? ++ "" : "Not a "); ++ ++ switch (dma_data->transfer) { ++ case TRANSFER_8: ++ acpi_os_printf ("\t\t8-bit only transfer\n"); ++ break; ++ ++ case TRANSFER_8_16: ++ acpi_os_printf ("\t\t8 and 16-bit transfer\n"); ++ break; ++ ++ case TRANSFER_16: ++ acpi_os_printf ("\t\t16 bit only transfer\n"); ++ break; ++ ++ default: ++ acpi_os_printf ("\t\t_invalid transfer preference\n"); ++ break; ++ } ++ ++ acpi_os_printf ("\t\t_number of Channels: %X ( ", ++ dma_data->number_of_channels); ++ ++ for (index = 0; index < dma_data->number_of_channels; index++) { ++ acpi_os_printf ("%X ", dma_data->channels[index]); ++ } ++ ++ acpi_os_printf (")\n"); ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_dump_start_dependent_functions ++ * ++ * PARAMETERS: Data - pointer to the resource structure to dump. ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: Prints out the various members of the Data structure type. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_rs_dump_start_dependent_functions ( ++ RESOURCE_DATA *data) ++{ ++ START_DEPENDENT_FUNCTIONS_RESOURCE *sdf_data = ++ (START_DEPENDENT_FUNCTIONS_RESOURCE*) data; ++ ++ ++ acpi_os_printf ("\t_start Dependent Functions Resource\n"); ++ ++ switch (sdf_data->compatibility_priority) { ++ case GOOD_CONFIGURATION: ++ acpi_os_printf ("\t\t_good configuration\n"); ++ break; ++ ++ case ACCEPTABLE_CONFIGURATION: ++ acpi_os_printf ("\t\t_acceptable configuration\n"); ++ break; ++ ++ case SUB_OPTIMAL_CONFIGURATION: ++ acpi_os_printf ("\t\t_sub-optimal configuration\n"); ++ break; ++ ++ default: ++ acpi_os_printf ("\t\t_invalid compatibility priority\n"); ++ break; ++ } ++ ++ switch(sdf_data->performance_robustness) { ++ case GOOD_CONFIGURATION: ++ acpi_os_printf ("\t\t_good configuration\n"); ++ break; ++ ++ case ACCEPTABLE_CONFIGURATION: ++ acpi_os_printf ("\t\t_acceptable configuration\n"); ++ break; ++ ++ case SUB_OPTIMAL_CONFIGURATION: ++ acpi_os_printf ("\t\t_sub-optimal configuration\n"); ++ break; ++ ++ default: ++ acpi_os_printf ("\t\t_invalid performance " ++ "robustness preference\n"); ++ break; ++ } ++ ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_dump_io ++ * ++ * PARAMETERS: Data - pointer to the resource structure to dump. ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: Prints out the various members of the Data structure type. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_rs_dump_io ( ++ RESOURCE_DATA *data) ++{ ++ IO_RESOURCE *io_data = (IO_RESOURCE*) data; ++ ++ ++ acpi_os_printf ("\t_io Resource\n"); ++ ++ acpi_os_printf ("\t\t%d bit decode\n", ++ DECODE_16 == io_data->io_decode ? 16 : 10); ++ ++ acpi_os_printf ("\t\t_range minimum base: %08X\n", ++ io_data->min_base_address); ++ ++ acpi_os_printf ("\t\t_range maximum base: %08X\n", ++ io_data->max_base_address); ++ ++ acpi_os_printf ("\t\t_alignment: %08X\n", ++ io_data->alignment); ++ ++ acpi_os_printf ("\t\t_range Length: %08X\n", ++ io_data->range_length); ++ ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_dump_fixed_io ++ * ++ * PARAMETERS: Data - pointer to the resource structure to dump. ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: Prints out the various members of the Data structure type. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_rs_dump_fixed_io ( ++ RESOURCE_DATA *data) ++{ ++ FIXED_IO_RESOURCE *fixed_io_data = (FIXED_IO_RESOURCE*) data; ++ ++ ++ acpi_os_printf ("\t_fixed Io Resource\n"); ++ acpi_os_printf ("\t\t_range base address: %08X", ++ fixed_io_data->base_address); ++ ++ acpi_os_printf ("\t\t_range length: %08X", ++ fixed_io_data->range_length); ++ ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_dump_vendor_specific ++ * ++ * PARAMETERS: Data - pointer to the resource structure to dump. ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: Prints out the various members of the Data structure type. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_rs_dump_vendor_specific ( ++ RESOURCE_DATA *data) ++{ ++ VENDOR_RESOURCE *vendor_data = (VENDOR_RESOURCE*) data; ++ u16 index = 0; ++ ++ ++ acpi_os_printf ("\t_vendor Specific Resource\n"); ++ ++ acpi_os_printf ("\t\t_length: %08X\n", vendor_data->length); ++ ++ for (index = 0; index < vendor_data->length; index++) { ++ acpi_os_printf ("\t\t_byte %X: %08X\n", ++ index, vendor_data->reserved[index]); ++ } ++ ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_dump_memory24 ++ * ++ * PARAMETERS: Data - pointer to the resource structure to dump. ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: Prints out the various members of the Data structure type. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_rs_dump_memory24 ( ++ RESOURCE_DATA *data) ++{ ++ MEMORY24_RESOURCE *memory24_data = (MEMORY24_RESOURCE*) data; ++ ++ ++ acpi_os_printf ("\t24-Bit Memory Range Resource\n"); ++ ++ acpi_os_printf ("\t\t_read%s\n", ++ READ_WRITE_MEMORY == ++ memory24_data->read_write_attribute ? ++ "/Write" : " only"); ++ ++ acpi_os_printf ("\t\t_range minimum base: %08X\n", ++ memory24_data->min_base_address); ++ ++ acpi_os_printf ("\t\t_range maximum base: %08X\n", ++ memory24_data->max_base_address); ++ ++ acpi_os_printf ("\t\t_alignment: %08X\n", ++ memory24_data->alignment); ++ ++ acpi_os_printf ("\t\t_range length: %08X\n", ++ memory24_data->range_length); ++ ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_dump_memory32 ++ * ++ * PARAMETERS: Data - pointer to the resource structure to dump. ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: Prints out the various members of the Data structure type. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_rs_dump_memory32 ( ++ RESOURCE_DATA *data) ++{ ++ MEMORY32_RESOURCE *memory32_data = (MEMORY32_RESOURCE*) data; ++ ++ ++ acpi_os_printf ("\t32-Bit Memory Range Resource\n"); ++ ++ acpi_os_printf ("\t\t_read%s\n", ++ READ_WRITE_MEMORY == ++ memory32_data->read_write_attribute ? ++ "/Write" : " only"); ++ ++ acpi_os_printf ("\t\t_range minimum base: %08X\n", ++ memory32_data->min_base_address); ++ ++ acpi_os_printf ("\t\t_range maximum base: %08X\n", ++ memory32_data->max_base_address); ++ ++ acpi_os_printf ("\t\t_alignment: %08X\n", ++ memory32_data->alignment); ++ ++ acpi_os_printf ("\t\t_range length: %08X\n", ++ memory32_data->range_length); ++ ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_dump_fixed_memory32 ++ * ++ * PARAMETERS: Data - pointer to the resource structure to dump. ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: Prints out the various members of the Data structure type. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_rs_dump_fixed_memory32 ( ++ RESOURCE_DATA *data) ++{ ++ FIXED_MEMORY32_RESOURCE *fixed_memory32_data = (FIXED_MEMORY32_RESOURCE*) data; ++ ++ ++ acpi_os_printf ("\t32-Bit Fixed Location Memory Range Resource\n"); ++ ++ acpi_os_printf ("\t\t_read%s\n", ++ READ_WRITE_MEMORY == ++ fixed_memory32_data->read_write_attribute ? ++ "/Write" : " Only"); ++ ++ acpi_os_printf ("\t\t_range base address: %08X\n", ++ fixed_memory32_data->range_base_address); ++ ++ acpi_os_printf ("\t\t_range length: %08X\n", ++ fixed_memory32_data->range_length); ++ ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_dump_address16 ++ * ++ * PARAMETERS: Data - pointer to the resource structure to dump. ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: Prints out the various members of the Data structure type. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_rs_dump_address16 ( ++ RESOURCE_DATA *data) ++{ ++ ADDRESS16_RESOURCE *address16_data = (ADDRESS16_RESOURCE*) data; ++ ++ ++ acpi_os_printf ("\t16-Bit Address Space Resource\n"); ++ acpi_os_printf ("\t\t_resource Type: "); ++ ++ switch (address16_data->resource_type) { ++ case MEMORY_RANGE: ++ ++ acpi_os_printf ("Memory Range\n"); ++ ++ switch (address16_data->attribute.memory.cache_attribute) { ++ case NON_CACHEABLE_MEMORY: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Noncacheable memory\n"); ++ break; ++ ++ case CACHABLE_MEMORY: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Cacheable memory\n"); ++ break; ++ ++ case WRITE_COMBINING_MEMORY: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Write-combining memory\n"); ++ break; ++ ++ case PREFETCHABLE_MEMORY: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Prefetchable memory\n"); ++ break; ++ ++ default: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Invalid cache attribute\n"); ++ break; ++ } ++ ++ acpi_os_printf ("\t\t_type Specific: Read%s\n", ++ READ_WRITE_MEMORY == ++ address16_data->attribute.memory.read_write_attribute ? ++ "/Write" : " Only"); ++ break; ++ ++ case IO_RANGE: ++ ++ acpi_os_printf ("I/O Range\n"); ++ ++ switch (address16_data->attribute.io.range_attribute) { ++ case NON_ISA_ONLY_RANGES: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Non-ISA Io Addresses\n"); ++ break; ++ ++ case ISA_ONLY_RANGES: ++ acpi_os_printf ("\t\t_type Specific: " ++ "ISA Io Addresses\n"); ++ break; ++ ++ case ENTIRE_RANGE: ++ acpi_os_printf ("\t\t_type Specific: " ++ "ISA and non-ISA Io Addresses\n"); ++ break; ++ ++ default: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Invalid range attribute\n"); ++ break; ++ } ++ break; ++ ++ case BUS_NUMBER_RANGE: ++ ++ acpi_os_printf ("Bus Number Range\n"); ++ break; ++ ++ default: ++ ++ acpi_os_printf ("Invalid resource type. Exiting.\n"); ++ return; ++ } ++ ++ acpi_os_printf ("\t\t_resource %s\n", ++ CONSUMER == address16_data->producer_consumer ? ++ "Consumer" : "Producer"); ++ ++ acpi_os_printf ("\t\t%s decode\n", ++ SUB_DECODE == address16_data->decode ? ++ "Subtractive" : "Positive"); ++ ++ acpi_os_printf ("\t\t_min address is %s fixed\n", ++ ADDRESS_FIXED == address16_data->min_address_fixed ? ++ "" : "not"); ++ ++ acpi_os_printf ("\t\t_max address is %s fixed\n", ++ ADDRESS_FIXED == address16_data->max_address_fixed ? ++ "" : "not"); ++ ++ acpi_os_printf ("\t\t_granularity: %08X\n", ++ address16_data->granularity); ++ ++ acpi_os_printf ("\t\t_address range min: %08X\n", ++ address16_data->min_address_range); ++ ++ acpi_os_printf ("\t\t_address range max: %08X\n", ++ address16_data->max_address_range); ++ ++ acpi_os_printf ("\t\t_address translation offset: %08X\n", ++ address16_data->address_translation_offset); ++ ++ acpi_os_printf ("\t\t_address Length: %08X\n", ++ address16_data->address_length); ++ ++ if (0xFF != address16_data->resource_source.index) { ++ acpi_os_printf ("\t\t_resource Source Index: %X\n", ++ address16_data->resource_source.index); ++ acpi_os_printf ("\t\t_resource Source: %s\n", ++ address16_data->resource_source.string_ptr); ++ } ++ ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_dump_address32 ++ * ++ * PARAMETERS: Data - pointer to the resource structure to dump. ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: Prints out the various members of the Data structure type. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_rs_dump_address32 ( ++ RESOURCE_DATA *data) ++{ ++ ADDRESS32_RESOURCE *address32_data = (ADDRESS32_RESOURCE*) data; ++ ++ ++ acpi_os_printf ("\t32-Bit Address Space Resource\n"); ++ ++ switch (address32_data->resource_type) { ++ case MEMORY_RANGE: ++ ++ acpi_os_printf ("\t\t_resource Type: Memory Range\n"); ++ ++ switch (address32_data->attribute.memory.cache_attribute) { ++ case NON_CACHEABLE_MEMORY: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Noncacheable memory\n"); ++ break; ++ ++ case CACHABLE_MEMORY: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Cacheable memory\n"); ++ break; ++ ++ case WRITE_COMBINING_MEMORY: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Write-combining memory\n"); ++ break; ++ ++ case PREFETCHABLE_MEMORY: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Prefetchable memory\n"); ++ break; ++ ++ default: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Invalid cache attribute\n"); ++ break; ++ } ++ ++ acpi_os_printf ("\t\t_type Specific: Read%s\n", ++ READ_WRITE_MEMORY == ++ address32_data->attribute.memory.read_write_attribute ? ++ "/Write" : " Only"); ++ break; ++ ++ case IO_RANGE: ++ ++ acpi_os_printf ("\t\t_resource Type: Io Range\n"); ++ ++ switch (address32_data->attribute.io.range_attribute) { ++ case NON_ISA_ONLY_RANGES: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Non-ISA Io Addresses\n"); ++ break; ++ ++ case ISA_ONLY_RANGES: ++ acpi_os_printf ("\t\t_type Specific: " ++ "ISA Io Addresses\n"); ++ break; ++ ++ case ENTIRE_RANGE: ++ acpi_os_printf ("\t\t_type Specific: " ++ "ISA and non-ISA Io Addresses\n"); ++ break; ++ ++ default: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Invalid Range attribute"); ++ break; ++ } ++ break; ++ ++ case BUS_NUMBER_RANGE: ++ ++ acpi_os_printf ("\t\t_resource Type: Bus Number Range\n"); ++ break; ++ ++ default: ++ ++ acpi_os_printf ("\t\t_invalid Resource Type..exiting.\n"); ++ return; ++ } ++ ++ acpi_os_printf ("\t\t_resource %s\n", ++ CONSUMER == address32_data->producer_consumer ? ++ "Consumer" : "Producer"); ++ ++ acpi_os_printf ("\t\t%s decode\n", ++ SUB_DECODE == address32_data->decode ? ++ "Subtractive" : "Positive"); ++ ++ acpi_os_printf ("\t\t_min address is %s fixed\n", ++ ADDRESS_FIXED == address32_data->min_address_fixed ? ++ "" : "not "); ++ ++ acpi_os_printf ("\t\t_max address is %s fixed\n", ++ ADDRESS_FIXED == address32_data->max_address_fixed ? ++ "" : "not "); ++ ++ acpi_os_printf ("\t\t_granularity: %08X\n", ++ address32_data->granularity); ++ ++ acpi_os_printf ("\t\t_address range min: %08X\n", ++ address32_data->min_address_range); ++ ++ acpi_os_printf ("\t\t_address range max: %08X\n", ++ address32_data->max_address_range); ++ ++ acpi_os_printf ("\t\t_address translation offset: %08X\n", ++ address32_data->address_translation_offset); ++ ++ acpi_os_printf ("\t\t_address Length: %08X\n", ++ address32_data->address_length); ++ ++ if(0xFF != address32_data->resource_source.index) { ++ acpi_os_printf ("\t\t_resource Source Index: %X\n", ++ address32_data->resource_source.index); ++ acpi_os_printf ("\t\t_resource Source: %s\n", ++ address32_data->resource_source.string_ptr); ++ } ++ ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_dump_address64 ++ * ++ * PARAMETERS: Data - pointer to the resource structure to dump. ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: Prints out the various members of the Data structure type. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_rs_dump_address64 ( ++ RESOURCE_DATA *data) ++{ ++ ADDRESS64_RESOURCE *address64_data = (ADDRESS64_RESOURCE*) data; ++ ++ ++ acpi_os_printf ("\t64-Bit Address Space Resource\n"); ++ ++ switch (address64_data->resource_type) { ++ case MEMORY_RANGE: ++ ++ acpi_os_printf ("\t\t_resource Type: Memory Range\n"); ++ ++ switch (address64_data->attribute.memory.cache_attribute) { ++ case NON_CACHEABLE_MEMORY: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Noncacheable memory\n"); ++ break; ++ ++ case CACHABLE_MEMORY: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Cacheable memory\n"); ++ break; ++ ++ case WRITE_COMBINING_MEMORY: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Write-combining memory\n"); ++ break; ++ ++ case PREFETCHABLE_MEMORY: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Prefetchable memory\n"); ++ break; ++ ++ default: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Invalid cache attribute\n"); ++ break; ++ } ++ ++ acpi_os_printf ("\t\t_type Specific: Read%s\n", ++ READ_WRITE_MEMORY == ++ address64_data->attribute.memory.read_write_attribute ? ++ "/Write" : " Only"); ++ break; ++ ++ case IO_RANGE: ++ ++ acpi_os_printf ("\t\t_resource Type: Io Range\n"); ++ ++ switch (address64_data->attribute.io.range_attribute) { ++ case NON_ISA_ONLY_RANGES: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Non-ISA Io Addresses\n"); ++ break; ++ ++ case ISA_ONLY_RANGES: ++ acpi_os_printf ("\t\t_type Specific: " ++ "ISA Io Addresses\n"); ++ break; ++ ++ case ENTIRE_RANGE: ++ acpi_os_printf ("\t\t_type Specific: " ++ "ISA and non-ISA Io Addresses\n"); ++ break; ++ ++ default: ++ acpi_os_printf ("\t\t_type Specific: " ++ "Invalid Range attribute"); ++ break; ++ } ++ break; ++ ++ case BUS_NUMBER_RANGE: ++ ++ acpi_os_printf ("\t\t_resource Type: Bus Number Range\n"); ++ break; ++ ++ default: ++ ++ acpi_os_printf ("\t\t_invalid Resource Type..exiting.\n"); ++ return; ++ } ++ ++ acpi_os_printf ("\t\t_resource %s\n", ++ CONSUMER == address64_data->producer_consumer ? ++ "Consumer" : "Producer"); ++ ++ acpi_os_printf ("\t\t%s decode\n", ++ SUB_DECODE == address64_data->decode ? ++ "Subtractive" : "Positive"); ++ ++ acpi_os_printf ("\t\t_min address is %s fixed\n", ++ ADDRESS_FIXED == address64_data->min_address_fixed ? ++ "" : "not "); ++ ++ acpi_os_printf ("\t\t_max address is %s fixed\n", ++ ADDRESS_FIXED == address64_data->max_address_fixed ? ++ "" : "not "); ++ ++ acpi_os_printf ("\t\t_granularity: %16X\n", ++ address64_data->granularity); ++ ++ acpi_os_printf ("\t\t_address range min: %16X\n", ++ address64_data->min_address_range); ++ ++ acpi_os_printf ("\t\t_address range max: %16X\n", ++ address64_data->max_address_range); ++ ++ acpi_os_printf ("\t\t_address translation offset: %16X\n", ++ address64_data->address_translation_offset); ++ ++ acpi_os_printf ("\t\t_address Length: %16X\n", ++ address64_data->address_length); ++ ++ if(0xFF != address64_data->resource_source.index) { ++ acpi_os_printf ("\t\t_resource Source Index: %X\n", ++ address64_data->resource_source.index); ++ acpi_os_printf ("\t\t_resource Source: %s\n", ++ address64_data->resource_source.string_ptr); ++ } ++ ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_dump_extended_irq ++ * ++ * PARAMETERS: Data - pointer to the resource structure to dump. ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: Prints out the various members of the Data structure type. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_rs_dump_extended_irq ( ++ RESOURCE_DATA *data) ++{ ++ EXTENDED_IRQ_RESOURCE *ext_irq_data = (EXTENDED_IRQ_RESOURCE*) data; ++ u8 index = 0; ++ ++ ++ acpi_os_printf ("\t_extended IRQ Resource\n"); ++ ++ acpi_os_printf ("\t\t_resource %s\n", ++ CONSUMER == ext_irq_data->producer_consumer ? ++ "Consumer" : "Producer"); ++ ++ acpi_os_printf ("\t\t%s\n", ++ LEVEL_SENSITIVE == ext_irq_data->edge_level ? ++ "Level" : "Edge"); ++ ++ acpi_os_printf ("\t\t_active %s\n", ++ ACTIVE_LOW == ext_irq_data->active_high_low ? ++ "low" : "high"); ++ ++ acpi_os_printf ("\t\t%s\n", ++ SHARED == ext_irq_data->shared_exclusive ? ++ "Shared" : "Exclusive"); ++ ++ acpi_os_printf ("\t\t_interrupts : %X ( ", ++ ext_irq_data->number_of_interrupts); ++ ++ for (index = 0; index < ext_irq_data->number_of_interrupts; index++) { ++ acpi_os_printf ("%X ", ext_irq_data->interrupts[index]); ++ } ++ ++ acpi_os_printf (")\n"); ++ ++ if(0xFF != ext_irq_data->resource_source.index) { ++ acpi_os_printf ("\t\t_resource Source Index: %X", ++ ext_irq_data->resource_source.index); ++ acpi_os_printf ("\t\t_resource Source: %s", ++ ext_irq_data->resource_source.string_ptr); ++ } ++ ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_dump_resource_list ++ * ++ * PARAMETERS: Data - pointer to the resource structure to dump. ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: Dispatches the structure to the correct dump routine. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_rs_dump_resource_list ( ++ RESOURCE *resource) ++{ ++ u8 count = 0; ++ u8 done = FALSE; ++ ++ ++ if (acpi_dbg_level & TRACE_RESOURCES && _COMPONENT & acpi_dbg_layer) { ++ while (!done) { ++ acpi_os_printf ("\t_resource structure %x.\n", count++); ++ ++ switch (resource->id) { ++ case irq: ++ acpi_rs_dump_irq (&resource->data); ++ break; ++ ++ case dma: ++ acpi_rs_dump_dma (&resource->data); ++ break; ++ ++ case start_dependent_functions: ++ acpi_rs_dump_start_dependent_functions (&resource->data); ++ break; ++ ++ case end_dependent_functions: ++ acpi_os_printf ("\t_end_dependent_functions Resource\n"); ++ /* Acpi_rs_dump_end_dependent_functions (Resource->Data);*/ ++ break; ++ ++ case io: ++ acpi_rs_dump_io (&resource->data); ++ break; ++ ++ case fixed_io: ++ acpi_rs_dump_fixed_io (&resource->data); ++ break; ++ ++ case vendor_specific: ++ acpi_rs_dump_vendor_specific (&resource->data); ++ break; ++ ++ case end_tag: ++ /*Rs_dump_end_tag (Resource->Data);*/ ++ acpi_os_printf ("\t_end_tag Resource\n"); ++ done = TRUE; ++ break; ++ ++ case memory24: ++ acpi_rs_dump_memory24 (&resource->data); ++ break; ++ ++ case memory32: ++ acpi_rs_dump_memory32 (&resource->data); ++ break; ++ ++ case fixed_memory32: ++ acpi_rs_dump_fixed_memory32 (&resource->data); ++ break; ++ ++ case address16: ++ acpi_rs_dump_address16 (&resource->data); ++ break; ++ ++ case address32: ++ acpi_rs_dump_address32 (&resource->data); ++ break; ++ ++ case address64: ++ acpi_rs_dump_address64 (&resource->data); ++ break; ++ ++ case extended_irq: ++ acpi_rs_dump_extended_irq (&resource->data); ++ break; ++ ++ default: ++ acpi_os_printf ("Invalid resource type\n"); ++ break; ++ ++ } ++ ++ resource = (RESOURCE *) ((NATIVE_UINT) resource + ++ (NATIVE_UINT) resource->length); ++ } ++ } ++ ++ return; ++} ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_dump_irq_list ++ * ++ * PARAMETERS: Data - pointer to the routing table to dump. ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: Dispatches the structures to the correct dump routine. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_rs_dump_irq_list ( ++ u8 *route_table) ++{ ++ u8 *buffer = route_table; ++ u8 count = 0; ++ u8 done = FALSE; ++ PCI_ROUTING_TABLE *prt_element; ++ ++ ++ if (acpi_dbg_level & TRACE_RESOURCES && _COMPONENT & acpi_dbg_layer) { ++ prt_element = (PCI_ROUTING_TABLE *) buffer; ++ ++ while (!done) { ++ acpi_os_printf ("\t_pCI IRQ Routing Table structure %X.\n", count++); ++ ++ acpi_os_printf ("\t\t_address: %X\n", ++ prt_element->address); ++ ++ acpi_os_printf ("\t\t_pin: %X\n", prt_element->pin); ++ ++ acpi_os_printf ("\t\t_source: %s\n", prt_element->source); ++ ++ acpi_os_printf ("\t\t_source_index: %X\n", ++ prt_element->source_index); ++ ++ buffer += prt_element->length; ++ ++ prt_element = (PCI_ROUTING_TABLE *) buffer; ++ ++ if(0 == prt_element->length) { ++ done = TRUE; ++ } ++ } ++ } ++ ++ return; ++} ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resource/rsio.c linux/drivers/acpi/resource/rsio.c +--- /usr/src/linux/drivers/acpi/resource/rsio.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/resource/rsio.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,528 @@ ++/******************************************************************************* ++ * ++ * Module Name: rsio - Acpi_rs_io_resource ++ * Acpi_rs_fixed_io_resource ++ * Acpi_rs_io_stream ++ * Acpi_rs_fixed_io_stream ++ * Acpi_rs_dma_resource ++ * Acpi_rs_dma_stream ++ * $Revision: 13 $ ++ * ++ ******************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acresrc.h" ++ ++#define _COMPONENT ACPI_RESOURCES ++ MODULE_NAME ("rsio") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_io_resource ++ * ++ * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte ++ * stream ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes consumed from ++ * the Byte_stream_buffer ++ * Output_buffer - Pointer to the user's return buffer ++ * Structure_size - u32 pointer that is filled with ++ * the number of bytes in the filled ++ * in structure ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the resource byte stream and fill out the appropriate ++ * structure pointed to by the Output_buffer. Return the ++ * number of bytes consumed from the byte stream. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_io_resource ( ++ u8 *byte_stream_buffer, ++ u32 *bytes_consumed, ++ u8 **output_buffer, ++ u32 *structure_size) ++{ ++ u8 *buffer = byte_stream_buffer; ++ RESOURCE *output_struct = (RESOURCE *) * output_buffer; ++ u16 temp16 = 0; ++ u8 temp8 = 0; ++ u32 struct_size = sizeof (IO_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA; ++ ++ ++ /* ++ * The number of bytes consumed are Constant ++ */ ++ *bytes_consumed = 8; ++ ++ output_struct->id = io; ++ ++ /* ++ * Check Decode ++ */ ++ buffer += 1; ++ temp8 = *buffer; ++ ++ output_struct->data.io.io_decode = temp8 & 0x01; ++ ++ /* ++ * Check Min_base Address ++ */ ++ buffer += 1; ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ ++ output_struct->data.io.min_base_address = temp16; ++ ++ /* ++ * Check Max_base Address ++ */ ++ buffer += 2; ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ ++ output_struct->data.io.max_base_address = temp16; ++ ++ /* ++ * Check Base alignment ++ */ ++ buffer += 2; ++ temp8 = *buffer; ++ ++ output_struct->data.io.alignment = temp8; ++ ++ /* ++ * Check Range_length ++ */ ++ buffer += 1; ++ temp8 = *buffer; ++ ++ output_struct->data.io.range_length = temp8; ++ ++ /* ++ * Set the Length parameter ++ */ ++ output_struct->length = struct_size; ++ ++ /* ++ * Return the final size of the structure ++ */ ++ *structure_size = struct_size; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_fixed_io_resource ++ * ++ * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte ++ * stream ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes consumed from ++ * the Byte_stream_buffer ++ * Output_buffer - Pointer to the user's return buffer ++ * Structure_size - u32 pointer that is filled with ++ * the number of bytes in the filled ++ * in structure ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the resource byte stream and fill out the appropriate ++ * structure pointed to by the Output_buffer. Return the ++ * number of bytes consumed from the byte stream. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_fixed_io_resource ( ++ u8 *byte_stream_buffer, ++ u32 *bytes_consumed, ++ u8 **output_buffer, ++ u32 *structure_size) ++{ ++ u8 *buffer = byte_stream_buffer; ++ RESOURCE *output_struct = (RESOURCE *) * output_buffer; ++ u16 temp16 = 0; ++ u8 temp8 = 0; ++ u32 struct_size = sizeof (FIXED_IO_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA; ++ ++ ++ /* ++ * The number of bytes consumed are Constant ++ */ ++ *bytes_consumed = 4; ++ ++ output_struct->id = fixed_io; ++ ++ /* ++ * Check Range Base Address ++ */ ++ buffer += 1; ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ ++ output_struct->data.fixed_io.base_address = temp16; ++ ++ /* ++ * Check Range_length ++ */ ++ buffer += 2; ++ temp8 = *buffer; ++ ++ output_struct->data.fixed_io.range_length = temp8; ++ ++ /* ++ * Set the Length parameter ++ */ ++ output_struct->length = struct_size; ++ ++ /* ++ * Return the final size of the structure ++ */ ++ *structure_size = struct_size; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_io_stream ++ * ++ * PARAMETERS: Linked_list - Pointer to the resource linked list ++ * Output_buffer - Pointer to the user's return buffer ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes of the ++ * Output_buffer used ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the linked list resource structure and fills in the ++ * the appropriate bytes in a byte stream ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_io_stream ( ++ RESOURCE *linked_list, ++ u8 **output_buffer, ++ u32 *bytes_consumed) ++{ ++ u8 *buffer = *output_buffer; ++ u16 temp16 = 0; ++ u8 temp8 = 0; ++ ++ ++ /* ++ * The descriptor field is static ++ */ ++ *buffer = 0x47; ++ buffer += 1; ++ ++ /* ++ * Io Information Byte ++ */ ++ temp8 = (u8) (linked_list->data.io.io_decode & 0x01); ++ ++ *buffer = temp8; ++ buffer += 1; ++ ++ /* ++ * Set the Range minimum base address ++ */ ++ temp16 = (u16) linked_list->data.io.min_base_address; ++ ++ MOVE_UNALIGNED16_TO_16 (buffer, &temp16); ++ buffer += 2; ++ ++ /* ++ * Set the Range maximum base address ++ */ ++ temp16 = (u16) linked_list->data.io.max_base_address; ++ ++ MOVE_UNALIGNED16_TO_16 (buffer, &temp16); ++ buffer += 2; ++ ++ /* ++ * Set the base alignment ++ */ ++ temp8 = (u8) linked_list->data.io.alignment; ++ ++ *buffer = temp8; ++ buffer += 1; ++ ++ /* ++ * Set the range length ++ */ ++ temp8 = (u8) linked_list->data.io.range_length; ++ ++ *buffer = temp8; ++ buffer += 1; ++ ++ /* ++ * Return the number of bytes consumed in this operation ++ */ ++ *bytes_consumed = (u32) ((NATIVE_UINT) buffer - ++ (NATIVE_UINT) *output_buffer); ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_fixed_io_stream ++ * ++ * PARAMETERS: Linked_list - Pointer to the resource linked list ++ * Output_buffer - Pointer to the user's return buffer ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes of the ++ * Output_buffer used ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the linked list resource structure and fills in the ++ * the appropriate bytes in a byte stream ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_fixed_io_stream ( ++ RESOURCE *linked_list, ++ u8 **output_buffer, ++ u32 *bytes_consumed) ++{ ++ u8 *buffer = *output_buffer; ++ u16 temp16 = 0; ++ u8 temp8 = 0; ++ ++ ++ /* ++ * The descriptor field is static ++ */ ++ *buffer = 0x4B; ++ ++ buffer += 1; ++ ++ /* ++ * Set the Range base address ++ */ ++ temp16 = (u16) linked_list->data.fixed_io.base_address; ++ ++ MOVE_UNALIGNED16_TO_16 (buffer, &temp16); ++ buffer += 2; ++ ++ /* ++ * Set the range length ++ */ ++ temp8 = (u8) linked_list->data.fixed_io.range_length; ++ ++ *buffer = temp8; ++ buffer += 1; ++ ++ /* ++ * Return the number of bytes consumed in this operation ++ */ ++ *bytes_consumed = (u32) ((NATIVE_UINT) buffer - ++ (NATIVE_UINT) *output_buffer); ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_dma_resource ++ * ++ * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte ++ * stream ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes consumed from ++ * the Byte_stream_buffer ++ * Output_buffer - Pointer to the user's return buffer ++ * Structure_size - u32 pointer that is filled with ++ * the number of bytes in the filled ++ * in structure ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the resource byte stream and fill out the appropriate ++ * structure pointed to by the Output_buffer. Return the ++ * number of bytes consumed from the byte stream. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_dma_resource ( ++ u8 *byte_stream_buffer, ++ u32 *bytes_consumed, ++ u8 **output_buffer, ++ u32 *structure_size) ++{ ++ u8 *buffer = byte_stream_buffer; ++ RESOURCE *output_struct = (RESOURCE *) * output_buffer; ++ u8 temp8 = 0; ++ u8 index; ++ u8 i; ++ u32 struct_size = sizeof(DMA_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA; ++ ++ ++ /* ++ * The number of bytes consumed are Constant ++ */ ++ *bytes_consumed = 3; ++ output_struct->id = dma; ++ ++ /* ++ * Point to the 8-bits of Byte 1 ++ */ ++ buffer += 1; ++ temp8 = *buffer; ++ ++ /* Decode the IRQ bits */ ++ ++ for (i = 0, index = 0; index < 8; index++) { ++ if ((temp8 >> index) & 0x01) { ++ output_struct->data.dma.channels[i] = index; ++ i++; ++ } ++ } ++ output_struct->data.dma.number_of_channels = i; ++ ++ ++ /* ++ * Calculate the structure size based upon the number of interrupts ++ */ ++ struct_size += (output_struct->data.dma.number_of_channels - 1) * 4; ++ ++ /* ++ * Point to Byte 2 ++ */ ++ buffer += 1; ++ temp8 = *buffer; ++ ++ /* ++ * Check for transfer preference (Bits[1:0]) ++ */ ++ output_struct->data.dma.transfer = temp8 & 0x03; ++ ++ if (0x03 == output_struct->data.dma.transfer) { ++ return (AE_BAD_DATA); ++ } ++ ++ /* ++ * Get bus master preference (Bit[2]) ++ */ ++ output_struct->data.dma.bus_master = (temp8 >> 2) & 0x01; ++ ++ /* ++ * Get channel speed support (Bits[6:5]) ++ */ ++ output_struct->data.dma.type = (temp8 >> 5) & 0x03; ++ ++ /* ++ * Set the Length parameter ++ */ ++ output_struct->length = struct_size; ++ ++ /* ++ * Return the final size of the structure ++ */ ++ *structure_size = struct_size; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_dma_stream ++ * ++ * PARAMETERS: Linked_list - Pointer to the resource linked list ++ * Output_buffer - Pointer to the user's return buffer ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes of the ++ * Output_buffer used ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the linked list resource structure and fills in the ++ * the appropriate bytes in a byte stream ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_dma_stream ( ++ RESOURCE *linked_list, ++ u8 **output_buffer, ++ u32 *bytes_consumed) ++{ ++ u8 *buffer = *output_buffer; ++ u16 temp16 = 0; ++ u8 temp8 = 0; ++ u8 index; ++ ++ ++ /* ++ * The descriptor field is static ++ */ ++ *buffer = 0x2A; ++ buffer += 1; ++ temp8 = 0; ++ ++ /* ++ * Loop through all of the Channels and set the mask bits ++ */ ++ for (index = 0; ++ index < linked_list->data.dma.number_of_channels; ++ index++) { ++ temp16 = (u16) linked_list->data.dma.channels[index]; ++ temp8 |= 0x1 << temp16; ++ } ++ ++ *buffer = temp8; ++ buffer += 1; ++ ++ /* ++ * Set the DMA Info ++ */ ++ temp8 = (u8) ((linked_list->data.dma.type & 0x03) << 5); ++ temp8 |= ((linked_list->data.dma.bus_master & 0x01) << 2); ++ temp8 |= (linked_list->data.dma.transfer & 0x03); ++ ++ *buffer = temp8; ++ buffer += 1; ++ ++ /* ++ * Return the number of bytes consumed in this operation ++ */ ++ *bytes_consumed = (u32) ((NATIVE_UINT) buffer - ++ (NATIVE_UINT) *output_buffer); ++ ++ return (AE_OK); ++} ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resource/rsirq.c linux/drivers/acpi/resource/rsirq.c +--- /usr/src/linux/drivers/acpi/resource/rsirq.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/resource/rsirq.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,565 @@ ++/******************************************************************************* ++ * ++ * Module Name: rsirq - Acpi_rs_irq_resource, ++ * Acpi_rs_irq_stream ++ * Acpi_rs_extended_irq_resource ++ * Acpi_rs_extended_irq_stream ++ * $Revision: 15 $ ++ * ++ ******************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acresrc.h" ++ ++#define _COMPONENT ACPI_RESOURCES ++ MODULE_NAME ("rsirq") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_irq_resource ++ * ++ * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte ++ * stream ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes consumed from ++ * the Byte_stream_buffer ++ * Output_buffer - Pointer to the user's return buffer ++ * Structure_size - u32 pointer that is filled with ++ * the number of bytes in the filled ++ * in structure ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the resource byte stream and fill out the appropriate ++ * structure pointed to by the Output_buffer. Return the ++ * number of bytes consumed from the byte stream. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_irq_resource ( ++ u8 *byte_stream_buffer, ++ u32 *bytes_consumed, ++ u8 **output_buffer, ++ u32 *structure_size) ++{ ++ u8 *buffer = byte_stream_buffer; ++ RESOURCE *output_struct = (RESOURCE *) * output_buffer; ++ u16 temp16 = 0; ++ u8 temp8 = 0; ++ u8 index; ++ u8 i; ++ u32 struct_size = sizeof (IRQ_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA; ++ ++ ++ /* ++ * The number of bytes consumed are contained in the descriptor ++ * (Bits:0-1) ++ */ ++ temp8 = *buffer; ++ *bytes_consumed = (temp8 & 0x03) + 1; ++ output_struct->id = irq; ++ ++ /* ++ * Point to the 16-bits of Bytes 1 and 2 ++ */ ++ buffer += 1; ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ ++ output_struct->data.irq.number_of_interrupts = 0; ++ ++ /* Decode the IRQ bits */ ++ ++ for (i = 0, index = 0; index < 16; index++) { ++ if((temp16 >> index) & 0x01) { ++ output_struct->data.irq.interrupts[i] = index; ++ i++; ++ } ++ } ++ output_struct->data.irq.number_of_interrupts = i; ++ ++ /* ++ * Calculate the structure size based upon the number of interrupts ++ */ ++ struct_size += (output_struct->data.irq.number_of_interrupts - 1) * 4; ++ ++ /* ++ * Point to Byte 3 if it is used ++ */ ++ if (4 == *bytes_consumed) { ++ buffer += 2; ++ temp8 = *buffer; ++ ++ /* ++ * Check for HE, LL or HL ++ */ ++ if (temp8 & 0x01) { ++ output_struct->data.irq.edge_level = EDGE_SENSITIVE; ++ output_struct->data.irq.active_high_low = ACTIVE_HIGH; ++ } ++ ++ else { ++ if (temp8 & 0x8) { ++ output_struct->data.irq.edge_level = LEVEL_SENSITIVE; ++ output_struct->data.irq.active_high_low = ACTIVE_LOW; ++ } ++ ++ else { ++ /* ++ * Only _LL and _HE polarity/trigger interrupts ++ * are allowed (ACPI spec v1.0b ection 6.4.2.1), ++ * so an error will occur if we reach this point ++ */ ++ return (AE_BAD_DATA); ++ } ++ } ++ ++ /* ++ * Check for sharable ++ */ ++ output_struct->data.irq.shared_exclusive = (temp8 >> 3) & 0x01; ++ } ++ ++ else { ++ /* ++ * Assume Edge Sensitive, Active High, Non-Sharable ++ * per ACPI Specification ++ */ ++ output_struct->data.irq.edge_level = EDGE_SENSITIVE; ++ output_struct->data.irq.active_high_low = ACTIVE_HIGH; ++ output_struct->data.irq.shared_exclusive = EXCLUSIVE; ++ } ++ ++ /* ++ * Set the Length parameter ++ */ ++ output_struct->length = struct_size; ++ ++ /* ++ * Return the final size of the structure ++ */ ++ *structure_size = struct_size; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_irq_stream ++ * ++ * PARAMETERS: Linked_list - Pointer to the resource linked list ++ * Output_buffer - Pointer to the user's return buffer ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes of the ++ * Output_buffer used ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the linked list resource structure and fills in the ++ * the appropriate bytes in a byte stream ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_irq_stream ( ++ RESOURCE *linked_list, ++ u8 **output_buffer, ++ u32 *bytes_consumed) ++{ ++ u8 *buffer = *output_buffer; ++ u16 temp16 = 0; ++ u8 temp8 = 0; ++ u8 index; ++ u8 IRQinfo_byte_needed; ++ ++ ++ /* ++ * The descriptor field is set based upon whether a third byte is ++ * needed to contain the IRQ Information. ++ */ ++ if (EDGE_SENSITIVE == linked_list->data.irq.edge_level && ++ ACTIVE_HIGH == linked_list->data.irq.active_high_low && ++ EXCLUSIVE == linked_list->data.irq.shared_exclusive) { ++ *buffer = 0x22; ++ IRQinfo_byte_needed = FALSE; ++ } ++ else { ++ *buffer = 0x23; ++ IRQinfo_byte_needed = TRUE; ++ } ++ ++ buffer += 1; ++ temp16 = 0; ++ ++ /* ++ * Loop through all of the interrupts and set the mask bits ++ */ ++ for(index = 0; ++ index < linked_list->data.irq.number_of_interrupts; ++ index++) { ++ temp8 = (u8) linked_list->data.irq.interrupts[index]; ++ temp16 |= 0x1 << temp8; ++ } ++ ++ MOVE_UNALIGNED16_TO_16 (buffer, &temp16); ++ buffer += 2; ++ ++ /* ++ * Set the IRQ Info byte if needed. ++ */ ++ if (IRQinfo_byte_needed) { ++ temp8 = 0; ++ temp8 = (u8) ((linked_list->data.irq.shared_exclusive & ++ 0x01) << 4); ++ ++ if (LEVEL_SENSITIVE == linked_list->data.irq.edge_level && ++ ACTIVE_LOW == linked_list->data.irq.active_high_low) { ++ temp8 |= 0x08; ++ } ++ ++ else { ++ temp8 |= 0x01; ++ } ++ ++ *buffer = temp8; ++ buffer += 1; ++ } ++ ++ /* ++ * Return the number of bytes consumed in this operation ++ */ ++ *bytes_consumed = (u32) ((NATIVE_UINT) buffer - ++ (NATIVE_UINT) *output_buffer); ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_extended_irq_resource ++ * ++ * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte ++ * stream ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes consumed from ++ * the Byte_stream_buffer ++ * Output_buffer - Pointer to the user's return buffer ++ * Structure_size - u32 pointer that is filled with ++ * the number of bytes in the filled ++ * in structure ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the resource byte stream and fill out the appropriate ++ * structure pointed to by the Output_buffer. Return the ++ * number of bytes consumed from the byte stream. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_extended_irq_resource ( ++ u8 *byte_stream_buffer, ++ u32 *bytes_consumed, ++ u8 **output_buffer, ++ u32 *structure_size) ++{ ++ u8 *buffer = byte_stream_buffer; ++ RESOURCE *output_struct = (RESOURCE *) * output_buffer; ++ u16 temp16 = 0; ++ u8 temp8 = 0; ++ NATIVE_CHAR *temp_ptr; ++ u8 index; ++ u32 struct_size = sizeof (EXTENDED_IRQ_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA; ++ ++ ++ /* ++ * Point past the Descriptor to get the number of bytes consumed ++ */ ++ buffer += 1; ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ ++ *bytes_consumed = temp16 + 3; ++ output_struct->id = extended_irq; ++ ++ /* ++ * Point to the Byte3 ++ */ ++ buffer += 2; ++ temp8 = *buffer; ++ ++ output_struct->data.extended_irq.producer_consumer = temp8 & 0x01; ++ ++ /* ++ * Check for HE, LL or HL ++ */ ++ if(temp8 & 0x02) { ++ output_struct->data.extended_irq.edge_level = EDGE_SENSITIVE; ++ output_struct->data.extended_irq.active_high_low = ACTIVE_HIGH; ++ } ++ ++ else { ++ if(temp8 & 0x4) { ++ output_struct->data.extended_irq.edge_level = LEVEL_SENSITIVE; ++ output_struct->data.extended_irq.active_high_low = ACTIVE_LOW; ++ } ++ ++ else { ++ /* ++ * Only _LL and _HE polarity/trigger interrupts ++ * are allowed (ACPI spec v1.0b ection 6.4.2.1), ++ * so an error will occur if we reach this point ++ */ ++ return (AE_BAD_DATA); ++ } ++ } ++ ++ /* ++ * Check for sharable ++ */ ++ output_struct->data.extended_irq.shared_exclusive = ++ (temp8 >> 3) & 0x01; ++ ++ /* ++ * Point to Byte4 (IRQ Table length) ++ */ ++ buffer += 1; ++ temp8 = *buffer; ++ ++ output_struct->data.extended_irq.number_of_interrupts = temp8; ++ ++ /* ++ * Add any additional structure size to properly calculate ++ * the next pointer at the end of this function ++ */ ++ struct_size += (temp8 - 1) * 4; ++ ++ /* ++ * Point to Byte5 (First IRQ Number) ++ */ ++ buffer += 1; ++ ++ /* ++ * Cycle through every IRQ in the table ++ */ ++ for (index = 0; index < temp8; index++) { ++ output_struct->data.extended_irq.interrupts[index] = ++ (u32)*buffer; ++ ++ /* Point to the next IRQ */ ++ ++ buffer += 4; ++ } ++ ++ /* ++ * This will leave us pointing to the Resource Source Index ++ * If it is present, then save it off and calculate the ++ * pointer to where the null terminated string goes: ++ * Each Interrupt takes 32-bits + the 5 bytes of the ++ * stream that are default. ++ */ ++ if (*bytes_consumed > ++ (u32)(output_struct->data.extended_irq.number_of_interrupts * ++ 4) + 5) { ++ /* Dereference the Index */ ++ ++ temp8 = *buffer; ++ output_struct->data.extended_irq.resource_source.index = ++ (u32) temp8; ++ ++ /* Point to the String */ ++ ++ buffer += 1; ++ ++ /* ++ * Point the String pointer to the end of this structure. ++ */ ++ output_struct->data.extended_irq.resource_source.string_ptr = ++ (NATIVE_CHAR *)(output_struct + struct_size); ++ ++ temp_ptr = output_struct->data.extended_irq.resource_source.string_ptr; ++ ++ /* Copy the string into the buffer */ ++ ++ index = 0; ++ ++ while (0x00 != *buffer) { ++ *temp_ptr = *buffer; ++ ++ temp_ptr += 1; ++ buffer += 1; ++ index += 1; ++ } ++ ++ /* ++ * Add the terminating null ++ */ ++ *temp_ptr = 0x00; ++ ++ output_struct->data.extended_irq.resource_source.string_length = ++ index + 1; ++ ++ /* ++ * In order for the Struct_size to fall on a 32-bit boundry, ++ * calculate the length of the string and expand the ++ * Struct_size to the next 32-bit boundry. ++ */ ++ temp8 = (u8) (index + 1); ++ struct_size += ROUND_UP_TO_32_bITS (temp8); ++ } ++ else { ++ output_struct->data.extended_irq.resource_source.index = 0x00; ++ output_struct->data.extended_irq.resource_source.string_length = 0; ++ output_struct->data.extended_irq.resource_source.string_ptr = NULL; ++ } ++ ++ /* ++ * Set the Length parameter ++ */ ++ output_struct->length = struct_size; ++ ++ /* ++ * Return the final size of the structure ++ */ ++ *structure_size = struct_size; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_extended_irq_stream ++ * ++ * PARAMETERS: Linked_list - Pointer to the resource linked list ++ * Output_buffer - Pointer to the user's return buffer ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes of the ++ * Output_buffer used ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the linked list resource structure and fills in the ++ * the appropriate bytes in a byte stream ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_extended_irq_stream ( ++ RESOURCE *linked_list, ++ u8 **output_buffer, ++ u32 *bytes_consumed) ++{ ++ u8 *buffer = *output_buffer; ++ u16 *length_field; ++ u8 temp8 = 0; ++ u8 index; ++ NATIVE_CHAR *temp_pointer = NULL; ++ ++ ++ /* ++ * The descriptor field is static ++ */ ++ *buffer = 0x89; ++ buffer += 1; ++ ++ /* ++ * Set a pointer to the Length field - to be filled in later ++ */ ++ ++ length_field = (u16 *)buffer; ++ buffer += 2; ++ ++ /* ++ * Set the Interrupt vector flags ++ */ ++ temp8 = (u8)(linked_list->data.extended_irq.producer_consumer & 0x01); ++ ++ temp8 |= ((linked_list->data.extended_irq.shared_exclusive & 0x01) << 3); ++ ++ if (LEVEL_SENSITIVE == linked_list->data.extended_irq.edge_level && ++ ACTIVE_LOW == linked_list->data.extended_irq.active_high_low) { ++ temp8 |= 0x04; ++ } ++ else { ++ temp8 |= 0x02; ++ } ++ ++ *buffer = temp8; ++ buffer += 1; ++ ++ /* ++ * Set the Interrupt table length ++ */ ++ temp8 = (u8) linked_list->data.extended_irq.number_of_interrupts; ++ ++ *buffer = temp8; ++ buffer += 1; ++ ++ for (index = 0; ++ index < linked_list->data.extended_irq.number_of_interrupts; ++ index++) { ++ MOVE_UNALIGNED32_TO_32 (buffer, ++ &linked_list->data.extended_irq.interrupts[index]); ++ buffer += 4; ++ } ++ ++ /* ++ * Resource Source Index and Resource Source are optional ++ */ ++ if (0 != linked_list->data.extended_irq.resource_source.string_length) { ++ *buffer = (u8) linked_list->data.extended_irq.resource_source.index; ++ buffer += 1; ++ ++ temp_pointer = (NATIVE_CHAR *) buffer; ++ ++ /* ++ * Copy the string ++ */ ++ STRCPY (temp_pointer, linked_list->data.extended_irq.resource_source.string_ptr); ++ ++ /* ++ * Buffer needs to be set to the length of the sting + one for the ++ * terminating null ++ */ ++ buffer += (STRLEN (linked_list->data.extended_irq.resource_source.string_ptr) + 1); ++ } ++ ++ /* ++ * Return the number of bytes consumed in this operation ++ */ ++ *bytes_consumed = (u32) ((NATIVE_UINT) buffer - ++ (NATIVE_UINT) *output_buffer); ++ ++ /* ++ * Set the length field to the number of bytes consumed ++ * minus the header size (3 bytes) ++ */ ++ *length_field = (u16) (*bytes_consumed - 3); ++ ++ return (AE_OK); ++} ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resource/rslist.c linux/drivers/acpi/resource/rslist.c +--- /usr/src/linux/drivers/acpi/resource/rslist.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/resource/rslist.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,522 @@ ++/******************************************************************************* ++ * ++ * Module Name: rslist - Acpi_rs_byte_stream_to_list ++ * Acpi_list_to_byte_stream ++ * $Revision: 14 $ ++ * ++ ******************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acresrc.h" ++ ++#define _COMPONENT ACPI_RESOURCES ++ MODULE_NAME ("rslist") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_byte_stream_to_list ++ * ++ * PARAMETERS: Byte_stream_buffer - Pointer to the resource byte stream ++ * Byte_stream_buffer_length - Length of Byte_stream_buffer ++ * Output_buffer - Pointer to the buffer that will ++ * contain the output structures ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Takes the resource byte stream and parses it, creating a ++ * linked list of resources in the caller's output buffer ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_byte_stream_to_list ( ++ u8 *byte_stream_buffer, ++ u32 byte_stream_buffer_length, ++ u8 **output_buffer) ++{ ++ ACPI_STATUS status; ++ u32 bytes_parsed = 0; ++ u8 resource_type = 0; ++ u32 bytes_consumed = 0; ++ u8 **buffer = output_buffer; ++ u32 structure_size = 0; ++ u8 end_tag_processed = FALSE; ++ ++ ++ while (bytes_parsed < byte_stream_buffer_length && ++ FALSE == end_tag_processed) { ++ /* ++ * Look at the next byte in the stream ++ */ ++ resource_type = *byte_stream_buffer; ++ ++ /* ++ * See if this is a small or large resource ++ */ ++ if(resource_type & 0x80) { ++ /* ++ * Large Resource Type ++ */ ++ switch (resource_type) { ++ case MEMORY_RANGE_24: ++ /* ++ * 24-Bit Memory Resource ++ */ ++ status = acpi_rs_memory24_resource(byte_stream_buffer, ++ &bytes_consumed, ++ buffer, ++ &structure_size); ++ ++ break; ++ ++ case LARGE_VENDOR_DEFINED: ++ /* ++ * Vendor Defined Resource ++ */ ++ status = acpi_rs_vendor_resource(byte_stream_buffer, ++ &bytes_consumed, ++ buffer, ++ &structure_size); ++ ++ break; ++ ++ case MEMORY_RANGE_32: ++ /* ++ * 32-Bit Memory Range Resource ++ */ ++ status = acpi_rs_memory32_range_resource(byte_stream_buffer, ++ &bytes_consumed, ++ buffer, ++ &structure_size); ++ ++ break; ++ ++ case FIXED_MEMORY_RANGE_32: ++ /* ++ * 32-Bit Fixed Memory Resource ++ */ ++ status = acpi_rs_fixed_memory32_resource(byte_stream_buffer, ++ &bytes_consumed, ++ buffer, ++ &structure_size); ++ ++ break; ++ ++ case QWORD_ADDRESS_SPACE: ++ /* ++ * 64-Bit Address Resource ++ */ ++ status = acpi_rs_address64_resource(byte_stream_buffer, ++ &bytes_consumed, ++ buffer, ++ &structure_size); ++ ++ break; ++ ++ case DWORD_ADDRESS_SPACE: ++ /* ++ * 32-Bit Address Resource ++ */ ++ status = acpi_rs_address32_resource(byte_stream_buffer, ++ &bytes_consumed, ++ buffer, ++ &structure_size); ++ ++ break; ++ ++ case WORD_ADDRESS_SPACE: ++ /* ++ * 16-Bit Address Resource ++ */ ++ status = acpi_rs_address16_resource(byte_stream_buffer, ++ &bytes_consumed, ++ buffer, ++ &structure_size); ++ ++ break; ++ ++ case EXTENDED_IRQ: ++ /* ++ * Extended IRQ ++ */ ++ status = acpi_rs_extended_irq_resource(byte_stream_buffer, ++ &bytes_consumed, ++ buffer, ++ &structure_size); ++ ++ break; ++ ++ default: ++ /* ++ * If we get here, everything is out of sync, ++ * so exit with an error ++ */ ++ return (AE_AML_ERROR); ++ break; ++ } ++ } ++ ++ else { ++ /* ++ * Small Resource Type ++ * Only bits 7:3 are valid ++ */ ++ resource_type >>= 3; ++ ++ switch(resource_type) { ++ case IRQ_FORMAT: ++ /* ++ * IRQ Resource ++ */ ++ status = acpi_rs_irq_resource(byte_stream_buffer, ++ &bytes_consumed, ++ buffer, ++ &structure_size); ++ ++ break; ++ ++ case DMA_FORMAT: ++ /* ++ * DMA Resource ++ */ ++ status = acpi_rs_dma_resource(byte_stream_buffer, ++ &bytes_consumed, ++ buffer, ++ &structure_size); ++ ++ break; ++ ++ case START_DEPENDENT_TAG: ++ /* ++ * Start Dependent Functions Resource ++ */ ++ status = acpi_rs_start_dependent_functions_resource(byte_stream_buffer, ++ &bytes_consumed, ++ buffer, ++ &structure_size); ++ ++ break; ++ ++ case END_DEPENDENT_TAG: ++ /* ++ * End Dependent Functions Resource ++ */ ++ status = acpi_rs_end_dependent_functions_resource(byte_stream_buffer, ++ &bytes_consumed, ++ buffer, ++ &structure_size); ++ ++ break; ++ ++ case IO_PORT_DESCRIPTOR: ++ /* ++ * IO Port Resource ++ */ ++ status = acpi_rs_io_resource(byte_stream_buffer, ++ &bytes_consumed, ++ buffer, ++ &structure_size); ++ ++ break; ++ ++ case FIXED_LOCATION_IO_DESCRIPTOR: ++ /* ++ * Fixed IO Port Resource ++ */ ++ status = acpi_rs_fixed_io_resource(byte_stream_buffer, ++ &bytes_consumed, ++ buffer, ++ &structure_size); ++ ++ break; ++ ++ case SMALL_VENDOR_DEFINED: ++ /* ++ * Vendor Specific Resource ++ */ ++ status = acpi_rs_vendor_resource(byte_stream_buffer, ++ &bytes_consumed, ++ buffer, ++ &structure_size); ++ ++ break; ++ ++ case END_TAG: ++ /* ++ * End Tag ++ */ ++ status = acpi_rs_end_tag_resource(byte_stream_buffer, ++ &bytes_consumed, ++ buffer, ++ &structure_size); ++ end_tag_processed = TRUE; ++ ++ break; ++ ++ default: ++ /* ++ * If we get here, everything is out of sync, ++ * so exit with an error ++ */ ++ return (AE_AML_ERROR); ++ break; ++ ++ } /* switch */ ++ } /* end else */ ++ ++ if (!ACPI_SUCCESS(status)) { ++ return (status); ++ } ++ ++ /* ++ * Update the return value and counter ++ */ ++ bytes_parsed += bytes_consumed; ++ ++ /* ++ * Set the byte stream to point to the next resource ++ */ ++ byte_stream_buffer += bytes_consumed; ++ ++ /* ++ * Set the Buffer to the next structure ++ */ ++ *buffer += structure_size; ++ ++ } /* end while */ ++ ++ /* ++ * Check the reason for exiting the while loop ++ */ ++ if (TRUE != end_tag_processed) { ++ return (AE_AML_ERROR); ++ } ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_list_to_byte_stream ++ * ++ * PARAMETERS: Linked_list - Pointer to the resource linked list ++ * Byte_steam_size_needed - Calculated size of the byte stream ++ * needed from calling ++ * Acpi_rs_calculate_byte_stream_length() ++ * The size of the Output_buffer is ++ * guaranteed to be >= ++ * Byte_stream_size_needed ++ * Output_buffer - Pointer to the buffer that will ++ * contain the byte stream ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Takes the resource linked list and parses it, creating a ++ * byte stream of resources in the caller's output buffer ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_list_to_byte_stream ( ++ RESOURCE *linked_list, ++ u32 byte_stream_size_needed, ++ u8 **output_buffer) ++{ ++ ACPI_STATUS status; ++ u8 *buffer = *output_buffer; ++ u32 bytes_consumed = 0; ++ u8 done = FALSE; ++ ++ ++ while (!done) { ++ switch (linked_list->id) { ++ case irq: ++ /* ++ * IRQ Resource ++ */ ++ status = acpi_rs_irq_stream (linked_list, ++ &buffer, ++ &bytes_consumed); ++ break; ++ ++ case dma: ++ /* ++ * DMA Resource ++ */ ++ status = acpi_rs_dma_stream (linked_list, ++ &buffer, ++ &bytes_consumed); ++ break; ++ ++ case start_dependent_functions: ++ /* ++ * Start Dependent Functions Resource ++ */ ++ status = acpi_rs_start_dependent_functions_stream (linked_list, ++ &buffer, ++ &bytes_consumed); ++ break; ++ ++ case end_dependent_functions: ++ /* ++ * End Dependent Functions Resource ++ */ ++ status = acpi_rs_end_dependent_functions_stream (linked_list, ++ &buffer, ++ &bytes_consumed); ++ break; ++ ++ case io: ++ /* ++ * IO Port Resource ++ */ ++ status = acpi_rs_io_stream (linked_list, ++ &buffer, ++ &bytes_consumed); ++ break; ++ ++ case fixed_io: ++ /* ++ * Fixed IO Port Resource ++ */ ++ status = acpi_rs_fixed_io_stream (linked_list, ++ &buffer, ++ &bytes_consumed); ++ break; ++ ++ case vendor_specific: ++ /* ++ * Vendor Defined Resource ++ */ ++ status = acpi_rs_vendor_stream (linked_list, ++ &buffer, ++ &bytes_consumed); ++ break; ++ ++ case end_tag: ++ /* ++ * End Tag ++ */ ++ status = acpi_rs_end_tag_stream (linked_list, ++ &buffer, ++ &bytes_consumed); ++ ++ /* ++ * An End Tag indicates the end of the Resource Template ++ */ ++ done = TRUE; ++ break; ++ ++ case memory24: ++ /* ++ * 24-Bit Memory Resource ++ */ ++ status = acpi_rs_memory24_stream (linked_list, ++ &buffer, ++ &bytes_consumed); ++ break; ++ ++ case memory32: ++ /* ++ * 32-Bit Memory Range Resource ++ */ ++ status = acpi_rs_memory32_range_stream (linked_list, ++ &buffer, ++ &bytes_consumed); ++ break; ++ ++ case fixed_memory32: ++ /* ++ * 32-Bit Fixed Memory Resource ++ */ ++ status = acpi_rs_fixed_memory32_stream (linked_list, ++ &buffer, ++ &bytes_consumed); ++ break; ++ ++ case address16: ++ /* ++ * 16-Bit Address Descriptor Resource ++ */ ++ status = acpi_rs_address16_stream (linked_list, ++ &buffer, ++ &bytes_consumed); ++ break; ++ ++ case address32: ++ /* ++ * 32-Bit Address Descriptor Resource ++ */ ++ status = acpi_rs_address32_stream (linked_list, ++ &buffer, ++ &bytes_consumed); ++ break; ++ ++ case address64: ++ /* ++ * 64-Bit Address Descriptor Resource ++ */ ++ status = acpi_rs_address64_stream (linked_list, ++ &buffer, ++ &bytes_consumed); ++ break; ++ ++ case extended_irq: ++ /* ++ * Extended IRQ Resource ++ */ ++ status = acpi_rs_extended_irq_stream (linked_list, ++ &buffer, ++ &bytes_consumed); ++ break; ++ ++ default: ++ /* ++ * If we get here, everything is out of sync, ++ * so exit with an error ++ */ ++ return (AE_BAD_DATA); ++ break; ++ ++ } /* switch (Linked_list->Id) */ ++ ++ if (!ACPI_SUCCESS(status)) { ++ return (status); ++ } ++ ++ /* ++ * Set the Buffer to point to the open byte ++ */ ++ buffer += bytes_consumed; ++ ++ /* ++ * Point to the next object ++ */ ++ linked_list = (RESOURCE *) ((NATIVE_UINT) linked_list + ++ (NATIVE_UINT) linked_list->length); ++ } ++ ++ return (AE_OK); ++} ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resource/rsmemory.c linux/drivers/acpi/resource/rsmemory.c +--- /usr/src/linux/drivers/acpi/resource/rsmemory.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/resource/rsmemory.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,557 @@ ++/******************************************************************************* ++ * ++ * Module Name: rsmem24 - Acpi_rs_memory24_resource ++ * Acpi_rs_memory24_stream ++ * Acpi_rs_memory32_range_resource ++ * Acpi_rs_fixed_memory32_resource ++ * Acpi_rs_memory32_range_stream ++ * Acpi_rs_fixed_memory32_stream ++ * $Revision: 13 $ ++ * ++ ******************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acresrc.h" ++ ++#define _COMPONENT ACPI_RESOURCES ++ MODULE_NAME ("rsmemory") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_memory24_resource ++ * ++ * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte ++ * stream ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes consumed from ++ * the Byte_stream_buffer ++ * Output_buffer - Pointer to the user's return buffer ++ * Structure_size - u32 pointer that is filled with ++ * the number of bytes in the filled ++ * in structure ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the resource byte stream and fill out the appropriate ++ * structure pointed to by the Output_buffer. Return the ++ * number of bytes consumed from the byte stream. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_memory24_resource ( ++ u8 *byte_stream_buffer, ++ u32 *bytes_consumed, ++ u8 **output_buffer, ++ u32 *structure_size) ++{ ++ u8 *buffer = byte_stream_buffer; ++ RESOURCE *output_struct = (RESOURCE *) * output_buffer; ++ u16 temp16 = 0; ++ u8 temp8 = 0; ++ u32 struct_size = sizeof (MEMORY24_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA; ++ ++ ++ /* ++ * Point past the Descriptor to get the number of bytes consumed ++ */ ++ buffer += 1; ++ ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ buffer += 2; ++ *bytes_consumed = temp16 + 3; ++ output_struct->id = memory24; ++ ++ /* ++ * Check Byte 3 the Read/Write bit ++ */ ++ temp8 = *buffer; ++ buffer += 1; ++ output_struct->data.memory24.read_write_attribute = temp8 & 0x01; ++ ++ /* ++ * Get Min_base_address (Bytes 4-5) ++ */ ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ buffer += 2; ++ output_struct->data.memory24.min_base_address = temp16; ++ ++ /* ++ * Get Max_base_address (Bytes 6-7) ++ */ ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ buffer += 2; ++ output_struct->data.memory24.max_base_address = temp16; ++ ++ /* ++ * Get Alignment (Bytes 8-9) ++ */ ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ buffer += 2; ++ output_struct->data.memory24.alignment = temp16; ++ ++ /* ++ * Get Range_length (Bytes 10-11) ++ */ ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ output_struct->data.memory24.range_length = temp16; ++ ++ /* ++ * Set the Length parameter ++ */ ++ output_struct->length = struct_size; ++ ++ /* ++ * Return the final size of the structure ++ */ ++ *structure_size = struct_size; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_memory24_stream ++ * ++ * PARAMETERS: Linked_list - Pointer to the resource linked list ++ * Output_buffer - Pointer to the user's return buffer ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes of the ++ * Output_buffer used ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the linked list resource structure and fills in the ++ * the appropriate bytes in a byte stream ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_memory24_stream ( ++ RESOURCE *linked_list, ++ u8 **output_buffer, ++ u32 *bytes_consumed) ++{ ++ u8 *buffer = *output_buffer; ++ u16 temp16 = 0; ++ u8 temp8 = 0; ++ ++ ++ /* ++ * The descriptor field is static ++ */ ++ *buffer = 0x81; ++ buffer += 1; ++ ++ /* ++ * The length field is static ++ */ ++ temp16 = 0x09; ++ MOVE_UNALIGNED16_TO_16 (buffer, &temp16); ++ buffer += 2; ++ ++ /* ++ * Set the Information Byte ++ */ ++ temp8 = (u8) (linked_list->data.memory24.read_write_attribute & 0x01); ++ *buffer = temp8; ++ buffer += 1; ++ ++ /* ++ * Set the Range minimum base address ++ */ ++ MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.memory24.min_base_address); ++ buffer += 2; ++ ++ /* ++ * Set the Range maximum base address ++ */ ++ MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.memory24.max_base_address); ++ buffer += 2; ++ ++ /* ++ * Set the base alignment ++ */ ++ MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.memory24.alignment); ++ buffer += 2; ++ ++ /* ++ * Set the range length ++ */ ++ MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.memory24.range_length); ++ buffer += 2; ++ ++ /* ++ * Return the number of bytes consumed in this operation ++ */ ++ *bytes_consumed = (u32) ((NATIVE_UINT) buffer - ++ (NATIVE_UINT) *output_buffer); ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_memory32_range_resource ++ * ++ * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte ++ * stream ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes consumed from ++ * the Byte_stream_buffer ++ * Output_buffer - Pointer to the user's return buffer ++ * Structure_size - u32 pointer that is filled with ++ * the number of bytes in the filled ++ * in structure ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the resource byte stream and fill out the appropriate ++ * structure pointed to by the Output_buffer. Return the ++ * number of bytes consumed from the byte stream. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_memory32_range_resource ( ++ u8 *byte_stream_buffer, ++ u32 *bytes_consumed, ++ u8 **output_buffer, ++ u32 *structure_size) ++{ ++ u8 *buffer = byte_stream_buffer; ++ RESOURCE *output_struct = (RESOURCE *) * output_buffer; ++ u16 temp16 = 0; ++ u8 temp8 = 0; ++ u32 struct_size = sizeof (MEMORY32_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA; ++ ++ ++ /* ++ * Point past the Descriptor to get the number of bytes consumed ++ */ ++ buffer += 1; ++ ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ buffer += 2; ++ *bytes_consumed = temp16 + 3; ++ ++ output_struct->id = memory32; ++ ++ /* ++ * Point to the place in the output buffer where the data portion will ++ * begin. ++ * 1. Set the RESOURCE_DATA * Data to point to it's own address, then ++ * 2. Set the pointer to the next address. ++ * ++ * NOTE: Output_struct->Data is cast to u8, otherwise, this addition adds ++ * 4 * sizeof(RESOURCE_DATA) instead of 4 * sizeof(u8) ++ */ ++ ++ /* ++ * Check Byte 3 the Read/Write bit ++ */ ++ temp8 = *buffer; ++ buffer += 1; ++ ++ output_struct->data.memory32.read_write_attribute = temp8 & 0x01; ++ ++ /* ++ * Get Min_base_address (Bytes 4-7) ++ */ ++ MOVE_UNALIGNED32_TO_32 (&output_struct->data.memory32.min_base_address, ++ buffer); ++ buffer += 4; ++ ++ /* ++ * Get Max_base_address (Bytes 8-11) ++ */ ++ MOVE_UNALIGNED32_TO_32 (&output_struct->data.memory32.max_base_address, ++ buffer); ++ buffer += 4; ++ ++ /* ++ * Get Alignment (Bytes 12-15) ++ */ ++ MOVE_UNALIGNED32_TO_32 (&output_struct->data.memory32.alignment, buffer); ++ buffer += 4; ++ ++ /* ++ * Get Range_length (Bytes 16-19) ++ */ ++ MOVE_UNALIGNED32_TO_32 (&output_struct->data.memory32.range_length, buffer); ++ ++ /* ++ * Set the Length parameter ++ */ ++ output_struct->length = struct_size; ++ ++ /* ++ * Return the final size of the structure ++ */ ++ *structure_size = struct_size; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_fixed_memory32_resource ++ * ++ * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte ++ * stream ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes consumed from ++ * the Byte_stream_buffer ++ * Output_buffer - Pointer to the user's return buffer ++ * Structure_size - u32 pointer that is filled with ++ * the number of bytes in the filled ++ * in structure ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the resource byte stream and fill out the appropriate ++ * structure pointed to by the Output_buffer. Return the ++ * number of bytes consumed from the byte stream. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_fixed_memory32_resource ( ++ u8 *byte_stream_buffer, ++ u32 *bytes_consumed, ++ u8 **output_buffer, ++ u32 *structure_size) ++{ ++ u8 *buffer = byte_stream_buffer; ++ RESOURCE *output_struct = (RESOURCE *) * output_buffer; ++ u16 temp16 = 0; ++ u8 temp8 = 0; ++ u32 struct_size = sizeof (FIXED_MEMORY32_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA; ++ ++ ++ /* ++ * Point past the Descriptor to get the number of bytes consumed ++ */ ++ buffer += 1; ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ ++ buffer += 2; ++ *bytes_consumed = temp16 + 3; ++ ++ output_struct->id = fixed_memory32; ++ ++ /* ++ * Check Byte 3 the Read/Write bit ++ */ ++ temp8 = *buffer; ++ buffer += 1; ++ output_struct->data.fixed_memory32.read_write_attribute = temp8 & 0x01; ++ ++ /* ++ * Get Range_base_address (Bytes 4-7) ++ */ ++ MOVE_UNALIGNED32_TO_32 (&output_struct->data.fixed_memory32.range_base_address, ++ buffer); ++ buffer += 4; ++ ++ /* ++ * Get Range_length (Bytes 8-11) ++ */ ++ MOVE_UNALIGNED32_TO_32 (&output_struct->data.fixed_memory32.range_length, ++ buffer); ++ ++ /* ++ * Set the Length parameter ++ */ ++ output_struct->length = struct_size; ++ ++ /* ++ * Return the final size of the structure ++ */ ++ *structure_size = struct_size; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_memory32_range_stream ++ * ++ * PARAMETERS: Linked_list - Pointer to the resource linked list ++ * Output_buffer - Pointer to the user's return buffer ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes of the ++ * Output_buffer used ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the linked list resource structure and fills in the ++ * the appropriate bytes in a byte stream ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_memory32_range_stream ( ++ RESOURCE *linked_list, ++ u8 **output_buffer, ++ u32 *bytes_consumed) ++{ ++ u8 *buffer = *output_buffer; ++ u16 temp16 = 0; ++ u8 temp8 = 0; ++ ++ ++ /* ++ * The descriptor field is static ++ */ ++ *buffer = 0x85; ++ buffer += 1; ++ ++ /* ++ * The length field is static ++ */ ++ temp16 = 0x11; ++ ++ MOVE_UNALIGNED16_TO_16 (buffer, &temp16); ++ buffer += 2; ++ ++ /* ++ * Set the Information Byte ++ */ ++ temp8 = (u8) (linked_list->data.memory32.read_write_attribute & 0x01); ++ *buffer = temp8; ++ buffer += 1; ++ ++ /* ++ * Set the Range minimum base address ++ */ ++ MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.memory32.min_base_address); ++ buffer += 4; ++ ++ /* ++ * Set the Range maximum base address ++ */ ++ MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.memory32.max_base_address); ++ buffer += 4; ++ ++ /* ++ * Set the base alignment ++ */ ++ MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.memory32.alignment); ++ buffer += 4; ++ ++ /* ++ * Set the range length ++ */ ++ MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.memory32.range_length); ++ buffer += 4; ++ ++ /* ++ * Return the number of bytes consumed in this operation ++ */ ++ *bytes_consumed = (u32) ((NATIVE_UINT) buffer - ++ (NATIVE_UINT) *output_buffer); ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_fixed_memory32_stream ++ * ++ * PARAMETERS: Linked_list - Pointer to the resource linked list ++ * Output_buffer - Pointer to the user's return buffer ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes of the ++ * Output_buffer used ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the linked list resource structure and fills in the ++ * the appropriate bytes in a byte stream ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_fixed_memory32_stream ( ++ RESOURCE *linked_list, ++ u8 **output_buffer, ++ u32 *bytes_consumed) ++{ ++ u8 *buffer = *output_buffer; ++ u16 temp16 = 0; ++ u8 temp8 = 0; ++ ++ ++ /* ++ * The descriptor field is static ++ */ ++ *buffer = 0x86; ++ buffer += 1; ++ ++ /* ++ * The length field is static ++ */ ++ temp16 = 0x09; ++ ++ MOVE_UNALIGNED16_TO_16 (buffer, &temp16); ++ buffer += 2; ++ ++ /* ++ * Set the Information Byte ++ */ ++ temp8 = (u8) (linked_list->data.fixed_memory32.read_write_attribute & 0x01); ++ *buffer = temp8; ++ buffer += 1; ++ ++ /* ++ * Set the Range base address ++ */ ++ MOVE_UNALIGNED32_TO_32 (buffer, ++ &linked_list->data.fixed_memory32.range_base_address); ++ buffer += 4; ++ ++ /* ++ * Set the range length ++ */ ++ MOVE_UNALIGNED32_TO_32 (buffer, ++ &linked_list->data.fixed_memory32.range_length); ++ buffer += 4; ++ ++ /* ++ * Return the number of bytes consumed in this operation ++ */ ++ *bytes_consumed = (u32) ((NATIVE_UINT) buffer - ++ (NATIVE_UINT) *output_buffer); ++ ++ return (AE_OK); ++} ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resource/rsmisc.c linux/drivers/acpi/resource/rsmisc.c +--- /usr/src/linux/drivers/acpi/resource/rsmisc.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/resource/rsmisc.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,606 @@ ++/******************************************************************************* ++ * ++ * Module Name: rsmisc - Acpi_rs_end_tag_resource ++ * Acpi_rs_end_tag_stream ++ * Acpi_rs_vendor_resource ++ * Acpi_rs_vendor_stream ++ * Acpi_rs_start_dependent_functions_resource ++ * Acpi_rs_end_dependent_functions_resource ++ * Acpi_rs_start_dependent_functions_stream ++ * Acpi_rs_end_dependent_functions_stream ++ * $Revision: 13 $ ++ * ++ ******************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acresrc.h" ++ ++#define _COMPONENT ACPI_RESOURCES ++ MODULE_NAME ("rsmisc") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_end_tag_resource ++ * ++ * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte ++ * stream ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes consumed from ++ * the Byte_stream_buffer ++ * Output_buffer - Pointer to the user's return buffer ++ * Structure_size - u32 pointer that is filled with ++ * the number of bytes in the filled ++ * in structure ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the resource byte stream and fill out the appropriate ++ * structure pointed to by the Output_buffer. Return the ++ * number of bytes consumed from the byte stream. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_end_tag_resource ( ++ u8 *byte_stream_buffer, ++ u32 *bytes_consumed, ++ u8 **output_buffer, ++ u32 *structure_size) ++{ ++ RESOURCE *output_struct = (RESOURCE *) * output_buffer; ++ u32 struct_size = RESOURCE_LENGTH; ++ ++ ++ /* ++ * The number of bytes consumed is static ++ */ ++ *bytes_consumed = 2; ++ ++ /* ++ * Fill out the structure ++ */ ++ output_struct->id = end_tag; ++ ++ /* ++ * Set the Length parameter ++ */ ++ output_struct->length = 0; ++ ++ /* ++ * Return the final size of the structure ++ */ ++ *structure_size = struct_size; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_end_tag_stream ++ * ++ * PARAMETERS: Linked_list - Pointer to the resource linked list ++ * Output_buffer - Pointer to the user's return buffer ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes of the ++ * Output_buffer used ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the linked list resource structure and fills in the ++ * the appropriate bytes in a byte stream ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_end_tag_stream ( ++ RESOURCE *linked_list, ++ u8 **output_buffer, ++ u32 *bytes_consumed) ++{ ++ u8 *buffer = *output_buffer; ++ u8 temp8 = 0; ++ ++ ++ /* ++ * The descriptor field is static ++ */ ++ *buffer = 0x79; ++ buffer += 1; ++ ++ /* ++ * Set the Checksum - zero means that the resource data is treated as if ++ * the checksum operation succeeded (ACPI Spec 1.0b Section 6.4.2.8) ++ */ ++ temp8 = 0; ++ ++ *buffer = temp8; ++ buffer += 1; ++ ++ /* ++ * Return the number of bytes consumed in this operation ++ */ ++ *bytes_consumed = (u32) ((NATIVE_UINT) buffer - ++ (NATIVE_UINT) *output_buffer); ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_vendor_resource ++ * ++ * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte ++ * stream ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes consumed from ++ * the Byte_stream_buffer ++ * Output_buffer - Pointer to the user's return buffer ++ * Structure_size - u32 pointer that is filled with ++ * the number of bytes in the filled ++ * in structure ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the resource byte stream and fill out the appropriate ++ * structure pointed to by the Output_buffer. Return the ++ * number of bytes consumed from the byte stream. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_vendor_resource ( ++ u8 *byte_stream_buffer, ++ u32 *bytes_consumed, ++ u8 **output_buffer, ++ u32 *structure_size) ++{ ++ u8 *buffer = byte_stream_buffer; ++ RESOURCE *output_struct = (RESOURCE *) * output_buffer; ++ u16 temp16 = 0; ++ u8 temp8 = 0; ++ u8 index; ++ u32 struct_size = sizeof (VENDOR_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA; ++ ++ ++ /* ++ * Dereference the Descriptor to find if this is a large or small item. ++ */ ++ temp8 = *buffer; ++ ++ if (temp8 & 0x80) { ++ /* ++ * Large Item ++ */ ++ /* Point to the length field */ ++ ++ buffer += 1; ++ ++ /* Dereference */ ++ ++ MOVE_UNALIGNED16_TO_16 (&temp16, buffer); ++ ++ /* Calculate bytes consumed */ ++ ++ *bytes_consumed = temp16 + 3; ++ ++ /* Point to the first vendor byte */ ++ ++ buffer += 2; ++ } ++ ++ else { ++ /* ++ * Small Item ++ */ ++ ++ /* Dereference the size */ ++ ++ temp16 = (u8)(*buffer & 0x07); ++ ++ /* Calculate bytes consumed */ ++ ++ *bytes_consumed = temp16 + 1; ++ ++ /* Point to the first vendor byte */ ++ ++ buffer += 1; ++ } ++ ++ output_struct->id = vendor_specific; ++ output_struct->data.vendor_specific.length = temp16; ++ ++ for (index = 0; index < temp16; index++) { ++ output_struct->data.vendor_specific.reserved[index] = *buffer; ++ buffer += 1; ++ } ++ ++ /* ++ * In order for the Struct_size to fall on a 32-bit boundry, ++ * calculate the length of the vendor string and expand the ++ * Struct_size to the next 32-bit boundry. ++ */ ++ struct_size += ROUND_UP_TO_32_bITS (temp16); ++ ++ /* ++ * Set the Length parameter ++ */ ++ output_struct->length = struct_size; ++ ++ /* ++ * Return the final size of the structure ++ */ ++ *structure_size = struct_size; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_vendor_stream ++ * ++ * PARAMETERS: Linked_list - Pointer to the resource linked list ++ * Output_buffer - Pointer to the user's return buffer ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes of the ++ * Output_buffer used ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the linked list resource structure and fills in the ++ * the appropriate bytes in a byte stream ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_vendor_stream ( ++ RESOURCE *linked_list, ++ u8 **output_buffer, ++ u32 *bytes_consumed) ++{ ++ u8 *buffer = *output_buffer; ++ u16 temp16 = 0; ++ u8 temp8 = 0; ++ u8 index; ++ ++ ++ /* ++ * Dereference the length to find if this is a large or small item. ++ */ ++ ++ if(linked_list->data.vendor_specific.length > 7) { ++ /* ++ * Large Item ++ */ ++ /* ++ * Set the descriptor field and length bytes ++ */ ++ *buffer = 0x84; ++ buffer += 1; ++ ++ temp16 = (u16) linked_list->data.vendor_specific.length; ++ ++ MOVE_UNALIGNED16_TO_16 (buffer, &temp16); ++ buffer += 2; ++ } ++ ++ else { ++ /* ++ * Small Item ++ */ ++ ++ /* ++ * Set the descriptor field ++ */ ++ temp8 = 0x70; ++ temp8 |= linked_list->data.vendor_specific.length; ++ ++ *buffer = temp8; ++ buffer += 1; ++ } ++ ++ /* ++ * Loop through all of the Vendor Specific fields ++ */ ++ for (index = 0; index < linked_list->data.vendor_specific.length; index++) { ++ temp8 = linked_list->data.vendor_specific.reserved[index]; ++ ++ *buffer = temp8; ++ buffer += 1; ++ } ++ ++ /* ++ * Return the number of bytes consumed in this operation ++ */ ++ *bytes_consumed = (u32) ((NATIVE_UINT) buffer - ++ (NATIVE_UINT) *output_buffer); ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_start_dependent_functions_resource ++ * ++ * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte ++ * stream ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes consumed from ++ * the Byte_stream_buffer ++ * Output_buffer - Pointer to the user's return buffer ++ * Structure_size - u32 pointer that is filled with ++ * the number of bytes in the filled ++ * in structure ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the resource byte stream and fill out the appropriate ++ * structure pointed to by the Output_buffer. Return the ++ * number of bytes consumed from the byte stream. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_start_dependent_functions_resource ( ++ u8 *byte_stream_buffer, ++ u32 *bytes_consumed, ++ u8 **output_buffer, ++ u32 *structure_size) ++{ ++ u8 *buffer = byte_stream_buffer; ++ RESOURCE *output_struct = (RESOURCE *) * output_buffer; ++ u8 temp8 = 0; ++ u32 struct_size = ++ sizeof(START_DEPENDENT_FUNCTIONS_RESOURCE) + ++ RESOURCE_LENGTH_NO_DATA; ++ ++ ++ /* ++ * The number of bytes consumed are contained in the descriptor (Bits:0-1) ++ */ ++ temp8 = *buffer; ++ ++ *bytes_consumed = (temp8 & 0x01) + 1; ++ ++ output_struct->id = start_dependent_functions; ++ ++ /* ++ * Point to Byte 1 if it is used ++ */ ++ if (2 == *bytes_consumed) { ++ buffer += 1; ++ temp8 = *buffer; ++ ++ /* ++ * Check Compatibility priority ++ */ ++ output_struct->data.start_dependent_functions.compatibility_priority = ++ temp8 & 0x03; ++ ++ if (3 == output_struct->data.start_dependent_functions.compatibility_priority) { ++ return (AE_AML_ERROR); ++ } ++ ++ /* ++ * Check Performance/Robustness preference ++ */ ++ output_struct->data.start_dependent_functions.performance_robustness = ++ (temp8 >> 2) & 0x03; ++ ++ if (3 == output_struct->data.start_dependent_functions.performance_robustness) { ++ return (AE_AML_ERROR); ++ } ++ } ++ ++ else { ++ output_struct->data.start_dependent_functions.compatibility_priority = ++ ACCEPTABLE_CONFIGURATION; ++ ++ output_struct->data.start_dependent_functions.performance_robustness = ++ ACCEPTABLE_CONFIGURATION; ++ } ++ ++ /* ++ * Set the Length parameter ++ */ ++ output_struct->length = struct_size; ++ ++ /* ++ * Return the final size of the structure ++ */ ++ *structure_size = struct_size; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_end_dependent_functions_resource ++ * ++ * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte ++ * stream ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes consumed from ++ * the Byte_stream_buffer ++ * Output_buffer - Pointer to the user's return buffer ++ * Structure_size - u32 pointer that is filled with ++ * the number of bytes in the filled ++ * in structure ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the resource byte stream and fill out the appropriate ++ * structure pointed to by the Output_buffer. Return the ++ * number of bytes consumed from the byte stream. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_end_dependent_functions_resource ( ++ u8 *byte_stream_buffer, ++ u32 *bytes_consumed, ++ u8 **output_buffer, ++ u32 *structure_size) ++{ ++ RESOURCE *output_struct = (RESOURCE *) * output_buffer; ++ u32 struct_size = RESOURCE_LENGTH; ++ ++ ++ /* ++ * The number of bytes consumed is static ++ */ ++ *bytes_consumed = 1; ++ ++ /* ++ * Fill out the structure ++ */ ++ output_struct->id = end_dependent_functions; ++ ++ /* ++ * Set the Length parameter ++ */ ++ output_struct->length = struct_size; ++ ++ /* ++ * Return the final size of the structure ++ */ ++ *structure_size = struct_size; ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_start_dependent_functions_stream ++ * ++ * PARAMETERS: Linked_list - Pointer to the resource linked list ++ * Output_buffer - Pointer to the user's return buffer ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes of the ++ * Output_buffer used ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the linked list resource structure and fills in the ++ * the appropriate bytes in a byte stream ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_start_dependent_functions_stream ( ++ RESOURCE *linked_list, ++ u8 **output_buffer, ++ u32 *bytes_consumed) ++{ ++ u8 *buffer = *output_buffer; ++ u8 temp8 = 0; ++ ++ ++ /* ++ * The descriptor field is set based upon whether a byte is needed ++ * to contain Priority data. ++ */ ++ if (ACCEPTABLE_CONFIGURATION == ++ linked_list->data.start_dependent_functions.compatibility_priority && ++ ACCEPTABLE_CONFIGURATION == ++ linked_list->data.start_dependent_functions.performance_robustness) { ++ *buffer = 0x30; ++ } ++ else { ++ *buffer = 0x31; ++ buffer += 1; ++ ++ /* ++ * Set the Priority Byte Definition ++ */ ++ temp8 = 0; ++ temp8 = (u8) ++ ((linked_list->data.start_dependent_functions.performance_robustness & ++ 0x03) << 2); ++ temp8 |= ++ (linked_list->data.start_dependent_functions.compatibility_priority & ++ 0x03); ++ ++ *buffer = temp8; ++ } ++ ++ buffer += 1; ++ ++ /* ++ * Return the number of bytes consumed in this operation ++ */ ++ *bytes_consumed = (u32) ((NATIVE_UINT) buffer - ++ (NATIVE_UINT) *output_buffer); ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_end_dependent_functions_stream ++ * ++ * PARAMETERS: Linked_list - Pointer to the resource linked list ++ * Output_buffer - Pointer to the user's return buffer ++ * Bytes_consumed - u32 pointer that is filled with ++ * the number of bytes of the ++ * Output_buffer used ++ * ++ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code ++ * ++ * DESCRIPTION: Take the linked list resource structure and fills in the ++ * the appropriate bytes in a byte stream ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_end_dependent_functions_stream ( ++ RESOURCE *linked_list, ++ u8 **output_buffer, ++ u32 *bytes_consumed ++ ) ++{ ++ u8 *buffer = *output_buffer; ++ ++ ++ /* ++ * The descriptor field is static ++ */ ++ *buffer = 0x38; ++ buffer += 1; ++ ++ /* ++ * Return the number of bytes consumed in this operation ++ */ ++ *bytes_consumed = (u32) ((NATIVE_UINT) buffer - ++ (NATIVE_UINT) *output_buffer); ++ ++ return (AE_OK); ++} ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resource/rsutils.c linux/drivers/acpi/resource/rsutils.c +--- /usr/src/linux/drivers/acpi/resource/rsutils.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/resource/rsutils.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,386 @@ ++/******************************************************************************* ++ * ++ * Module Name: rsutils - Utilities for the resource manager ++ * $Revision: 16 $ ++ * ++ ******************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acnamesp.h" ++#include "acresrc.h" ++ ++ ++#define _COMPONENT ACPI_RESOURCES ++ MODULE_NAME ("rsutils") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_get_prt_method_data ++ * ++ * PARAMETERS: Handle - a handle to the containing object ++ * Ret_buffer - a pointer to a buffer structure for the ++ * results ++ * ++ * RETURN: Status - the status of the call ++ * ++ * DESCRIPTION: This function is called to get the _PRT value of an object ++ * contained in an object specified by the handle passed in ++ * ++ * If the function fails an appropriate status will be returned ++ * and the contents of the callers buffer is undefined. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_get_prt_method_data ( ++ ACPI_HANDLE handle, ++ ACPI_BUFFER *ret_buffer) ++{ ++ ACPI_OPERAND_OBJECT *ret_obj; ++ ACPI_STATUS status; ++ u32 buffer_space_needed; ++ ++ ++ /* already validated params, so we won't repeat here */ ++ ++ buffer_space_needed = ret_buffer->length; ++ ++ /* ++ * Execute the method, no parameters ++ */ ++ status = acpi_ns_evaluate_relative (handle, "_PRT", NULL, &ret_obj); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ if (!ret_obj) { ++ /* Return object is required */ ++ ++ return (AE_TYPE); ++ } ++ ++ ++ /* ++ * The return object will be a package, so check the ++ * parameters. If the return object is not a package, ++ * then the underlying AML code is corrupt or improperly ++ * written. ++ */ ++ if (ACPI_TYPE_PACKAGE != ret_obj->common.type) { ++ status = AE_AML_OPERAND_TYPE; ++ goto cleanup; ++ } ++ ++ /* ++ * Make the call to create a resource linked list from the ++ * byte stream buffer that comes back from the _CRS method ++ * execution. ++ */ ++ status = acpi_rs_create_pci_routing_table (ret_obj, ++ ret_buffer->pointer, ++ &buffer_space_needed); ++ ++ /* ++ * Tell the user how much of the buffer we have used or is needed ++ * and return the final status. ++ */ ++ ret_buffer->length = buffer_space_needed; ++ ++ ++ /* On exit, we must delete the object returned by evaluate_object */ ++ ++cleanup: ++ ++ acpi_cm_remove_reference (ret_obj); ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_get_crs_method_data ++ * ++ * PARAMETERS: Handle - a handle to the containing object ++ * Ret_buffer - a pointer to a buffer structure for the ++ * results ++ * ++ * RETURN: Status - the status of the call ++ * ++ * DESCRIPTION: This function is called to get the _CRS value of an object ++ * contained in an object specified by the handle passed in ++ * ++ * If the function fails an appropriate status will be returned ++ * and the contents of the callers buffer is undefined. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_get_crs_method_data ( ++ ACPI_HANDLE handle, ++ ACPI_BUFFER *ret_buffer) ++{ ++ ACPI_OPERAND_OBJECT *ret_obj; ++ ACPI_STATUS status; ++ u32 buffer_space_needed = ret_buffer->length; ++ ++ ++ /* already validated params, so we won't repeat here */ ++ ++ /* ++ * Execute the method, no parameters ++ */ ++ status = acpi_ns_evaluate_relative (handle, "_CRS", NULL, &ret_obj); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ if (!ret_obj) { ++ /* Return object is required */ ++ ++ return (AE_TYPE); ++ } ++ ++ /* ++ * The return object will be a buffer, but check the ++ * parameters. If the return object is not a buffer, ++ * then the underlying AML code is corrupt or improperly ++ * written. ++ */ ++ if (ACPI_TYPE_BUFFER != ret_obj->common.type) { ++ status = AE_AML_OPERAND_TYPE; ++ goto cleanup; ++ } ++ ++ /* ++ * Make the call to create a resource linked list from the ++ * byte stream buffer that comes back from the _CRS method ++ * execution. ++ */ ++ status = acpi_rs_create_resource_list (ret_obj, ++ ret_buffer->pointer, ++ &buffer_space_needed); ++ ++ ++ /* ++ * Tell the user how much of the buffer we have used or is needed ++ * and return the final status. ++ */ ++ ret_buffer->length = buffer_space_needed; ++ ++ ++ /* On exit, we must delete the object returned by evaluate_object */ ++ ++cleanup: ++ ++ acpi_cm_remove_reference (ret_obj); ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_get_prs_method_data ++ * ++ * PARAMETERS: Handle - a handle to the containing object ++ * Ret_buffer - a pointer to a buffer structure for the ++ * results ++ * ++ * RETURN: Status - the status of the call ++ * ++ * DESCRIPTION: This function is called to get the _PRS value of an object ++ * contained in an object specified by the handle passed in ++ * ++ * If the function fails an appropriate status will be returned ++ * and the contents of the callers buffer is undefined. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_get_prs_method_data ( ++ ACPI_HANDLE handle, ++ ACPI_BUFFER *ret_buffer) ++{ ++ ACPI_OPERAND_OBJECT *ret_obj; ++ ACPI_STATUS status; ++ u32 buffer_space_needed = ret_buffer->length; ++ ++ ++ /* already validated params, so we won't repeat here */ ++ ++ /* ++ * Execute the method, no parameters ++ */ ++ status = acpi_ns_evaluate_relative (handle, "_PRS", NULL, &ret_obj); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ if (!ret_obj) { ++ /* Return object is required */ ++ ++ return (AE_TYPE); ++ } ++ ++ /* ++ * The return object will be a buffer, but check the ++ * parameters. If the return object is not a buffer, ++ * then the underlying AML code is corrupt or improperly ++ * written.. ++ */ ++ if (ACPI_TYPE_BUFFER != ret_obj->common.type) { ++ status = AE_AML_OPERAND_TYPE; ++ goto cleanup; ++ } ++ ++ /* ++ * Make the call to create a resource linked list from the ++ * byte stream buffer that comes back from the _CRS method ++ * execution. ++ */ ++ status = acpi_rs_create_resource_list (ret_obj, ++ ret_buffer->pointer, ++ &buffer_space_needed); ++ ++ /* ++ * Tell the user how much of the buffer we have used or is needed ++ * and return the final status. ++ */ ++ ret_buffer->length = buffer_space_needed; ++ ++ ++ /* On exit, we must delete the object returned by evaluate_object */ ++ ++cleanup: ++ ++ acpi_cm_remove_reference (ret_obj); ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_rs_set_srs_method_data ++ * ++ * PARAMETERS: Handle - a handle to the containing object ++ * In_buffer - a pointer to a buffer structure of the ++ * parameter ++ * ++ * RETURN: Status - the status of the call ++ * ++ * DESCRIPTION: This function is called to set the _SRS of an object contained ++ * in an object specified by the handle passed in ++ * ++ * If the function fails an appropriate status will be returned ++ * and the contents of the callers buffer is undefined. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_rs_set_srs_method_data ( ++ ACPI_HANDLE handle, ++ ACPI_BUFFER *in_buffer) ++{ ++ ACPI_OPERAND_OBJECT *params[2]; ++ ACPI_OPERAND_OBJECT param_obj; ++ ACPI_STATUS status; ++ u8 *byte_stream = NULL; ++ u32 buffer_size_needed = 0; ++ ++ ++ /* already validated params, so we won't repeat here */ ++ ++ /* ++ * The In_buffer parameter will point to a linked list of ++ * resource parameters. It needs to be formatted into a ++ * byte stream to be sent in as an input parameter. ++ */ ++ buffer_size_needed = 0; ++ ++ /* ++ * First call is to get the buffer size needed ++ */ ++ status = acpi_rs_create_byte_stream (in_buffer->pointer, ++ byte_stream, ++ &buffer_size_needed); ++ /* ++ * We expect a return of AE_BUFFER_OVERFLOW ++ * if not, exit with the error ++ */ ++ if (AE_BUFFER_OVERFLOW != status) { ++ return (status); ++ } ++ ++ /* ++ * Allocate the buffer needed ++ */ ++ byte_stream = acpi_cm_callocate(buffer_size_needed); ++ if (NULL == byte_stream) { ++ return (AE_NO_MEMORY); ++ } ++ ++ /* ++ * Now call to convert the linked list into a byte stream ++ */ ++ status = acpi_rs_create_byte_stream (in_buffer->pointer, ++ byte_stream, ++ &buffer_size_needed); ++ if (ACPI_FAILURE (status)) { ++ goto cleanup; ++ } ++ ++ /* ++ * Init the param object ++ */ ++ acpi_cm_init_static_object (¶m_obj); ++ ++ /* ++ * Method requires one parameter. Set it up ++ */ ++ params [0] = ¶m_obj; ++ params [1] = NULL; ++ ++ /* ++ * Set up the parameter object ++ */ ++ param_obj.common.type = ACPI_TYPE_BUFFER; ++ param_obj.buffer.length = buffer_size_needed; ++ param_obj.buffer.pointer = byte_stream; ++ ++ /* ++ * Execute the method, no return value ++ */ ++ status = acpi_ns_evaluate_relative (handle, "_SRS", params, NULL); ++ ++ /* ++ * Clean up and return the status from Acpi_ns_evaluate_relative ++ */ ++ ++cleanup: ++ ++ acpi_cm_free (byte_stream); ++ return (status); ++} ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resource/rsxface.c linux/drivers/acpi/resource/rsxface.c +--- /usr/src/linux/drivers/acpi/resource/rsxface.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/resource/rsxface.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,221 @@ ++/******************************************************************************* ++ * ++ * Module Name: rsxface - Public interfaces to the ACPI subsystem ++ * $Revision: 11 $ ++ * ++ ******************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acinterp.h" ++#include "acnamesp.h" ++#include "acresrc.h" ++ ++#define _COMPONENT ACPI_RESOURCES ++ MODULE_NAME ("rsxface") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_get_irq_routing_table ++ * ++ * PARAMETERS: Device_handle - a handle to the Bus device we are querying ++ * Ret_buffer - a pointer to a buffer to receive the ++ * current resources for the device ++ * ++ * RETURN: Status - the status of the call ++ * ++ * DESCRIPTION: This function is called to get the IRQ routing table for a ++ * specific bus. The caller must first acquire a handle for the ++ * desired bus. The routine table is placed in the buffer pointed ++ * to by the Ret_buffer variable parameter. ++ * ++ * If the function fails an appropriate status will be returned ++ * and the value of Ret_buffer is undefined. ++ * ++ * This function attempts to execute the _PRT method contained in ++ * the object indicated by the passed Device_handle. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_get_irq_routing_table ( ++ ACPI_HANDLE device_handle, ++ ACPI_BUFFER *ret_buffer) ++{ ++ ACPI_STATUS status; ++ ++ ++ /* ++ * Must have a valid handle and buffer, So we have to have a handle ++ * and a return buffer structure, and if there is a non-zero buffer length ++ * we also need a valid pointer in the buffer. If it's a zero buffer length, ++ * we'll be returning the needed buffer size, so keep going. ++ */ ++ if ((!device_handle) || ++ (!ret_buffer) || ++ ((!ret_buffer->pointer) && (ret_buffer->length))) { ++ return (AE_BAD_PARAMETER); ++ } ++ ++ status = acpi_rs_get_prt_method_data (device_handle, ret_buffer); ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_get_current_resources ++ * ++ * PARAMETERS: Device_handle - a handle to the device object for the ++ * device we are querying ++ * Ret_buffer - a pointer to a buffer to receive the ++ * current resources for the device ++ * ++ * RETURN: Status - the status of the call ++ * ++ * DESCRIPTION: This function is called to get the current resources for a ++ * specific device. The caller must first acquire a handle for ++ * the desired device. The resource data is placed in the buffer ++ * pointed to by the Ret_buffer variable parameter. ++ * ++ * If the function fails an appropriate status will be returned ++ * and the value of Ret_buffer is undefined. ++ * ++ * This function attempts to execute the _CRS method contained in ++ * the object indicated by the passed Device_handle. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_get_current_resources ( ++ ACPI_HANDLE device_handle, ++ ACPI_BUFFER *ret_buffer) ++{ ++ ACPI_STATUS status; ++ ++ ++ /* ++ * Must have a valid handle and buffer, So we have to have a handle ++ * and a return buffer structure, and if there is a non-zero buffer length ++ * we also need a valid pointer in the buffer. If it's a zero buffer length, ++ * we'll be returning the needed buffer size, so keep going. ++ */ ++ if ((!device_handle) || ++ (!ret_buffer) || ++ ((ret_buffer->length) && (!ret_buffer->pointer))) { ++ return (AE_BAD_PARAMETER); ++ } ++ ++ status = acpi_rs_get_crs_method_data (device_handle, ret_buffer); ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_get_possible_resources ++ * ++ * PARAMETERS: Device_handle - a handle to the device object for the ++ * device we are querying ++ * Ret_buffer - a pointer to a buffer to receive the ++ * resources for the device ++ * ++ * RETURN: Status - the status of the call ++ * ++ * DESCRIPTION: This function is called to get a list of the possible resources ++ * for a specific device. The caller must first acquire a handle ++ * for the desired device. The resource data is placed in the ++ * buffer pointed to by the Ret_buffer variable. ++ * ++ * If the function fails an appropriate status will be returned ++ * and the value of Ret_buffer is undefined. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_get_possible_resources ( ++ ACPI_HANDLE device_handle, ++ ACPI_BUFFER *ret_buffer) ++{ ++ ACPI_STATUS status; ++ ++ ++ /* ++ * Must have a valid handle and buffer, So we have to have a handle ++ * and a return buffer structure, and if there is a non-zero buffer length ++ * we also need a valid pointer in the buffer. If it's a zero buffer length, ++ * we'll be returning the needed buffer size, so keep going. ++ */ ++ if ((!device_handle) || ++ (!ret_buffer) || ++ ((ret_buffer->length) && (!ret_buffer->pointer))) { ++ return (AE_BAD_PARAMETER); ++ } ++ ++ status = acpi_rs_get_prs_method_data (device_handle, ret_buffer); ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_set_current_resources ++ * ++ * PARAMETERS: Device_handle - a handle to the device object for the ++ * device we are changing the resources of ++ * In_buffer - a pointer to a buffer containing the ++ * resources to be set for the device ++ * ++ * RETURN: Status - the status of the call ++ * ++ * DESCRIPTION: This function is called to set the current resources for a ++ * specific device. The caller must first acquire a handle for ++ * the desired device. The resource data is passed to the routine ++ * the buffer pointed to by the In_buffer variable. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_set_current_resources ( ++ ACPI_HANDLE device_handle, ++ ACPI_BUFFER *in_buffer) ++{ ++ ACPI_STATUS status; ++ ++ ++ /* ++ * Must have a valid handle and buffer ++ */ ++ if ((!device_handle) || ++ (!in_buffer) || ++ (!in_buffer->pointer) || ++ (!in_buffer->length)) { ++ return (AE_BAD_PARAMETER); ++ } ++ ++ status = acpi_rs_set_srs_method_data (device_handle, in_buffer); ++ ++ return (status); ++} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resources/Makefile linux/drivers/acpi/resources/Makefile +--- /usr/src/linux/drivers/acpi/resources/Makefile Fri Dec 29 14:07:21 2000 ++++ linux/drivers/acpi/resources/Makefile Wed Dec 31 16:00:00 1969 +@@ -1,16 +0,0 @@ +-# +-# Makefile for all Linux ACPI interpreter subdirectories +-# +- +-O_TARGET := ../$(shell basename `pwd`).o +- +-obj-$(CONFIG_ACPI) := $(patsubst %.c,%.o,$(wildcard *.c)) +- +-EXTRA_CFLAGS += -I../include +- +-EXTRA_CFLAGS += $(ACPI_CFLAGS) +- +-include $(TOPDIR)/Rules.make +- +-clean: +- $(RM) *.o +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resources/rsaddr.c linux/drivers/acpi/resources/rsaddr.c +--- /usr/src/linux/drivers/acpi/resources/rsaddr.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/resources/rsaddr.c Wed Dec 31 16:00:00 1969 +@@ -1,801 +0,0 @@ +-/******************************************************************************* +- * +- * Module Name: rsaddr - Acpi_rs_address16_resource +- * Acpi_rs_address16_stream +- * Acpi_rs_address32_resource +- * Acpi_rs_address32_stream +- * $Revision: 14 $ +- * +- ******************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acresrc.h" +- +-#define _COMPONENT RESOURCE_MANAGER +- MODULE_NAME ("rsaddr") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_address16_resource +- * +- * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte +- * stream +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes consumed from +- * the Byte_stream_buffer +- * Output_buffer - Pointer to the user's return buffer +- * Structure_size - u32 pointer that is filled with +- * the number of bytes in the filled +- * in structure +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the resource byte stream and fill out the appropriate +- * structure pointed to by the Output_buffer. Return the +- * number of bytes consumed from the byte stream. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_address16_resource ( +- u8 *byte_stream_buffer, +- u32 *bytes_consumed, +- u8 **output_buffer, +- u32 *structure_size) +-{ +- u8 *buffer = byte_stream_buffer; +- RESOURCE *output_struct = (RESOURCE *) * output_buffer; +- u16 temp16; +- u8 temp8; +- u32 index; +- u32 struct_size = sizeof(ADDRESS16_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA; +- +- +- /* +- * Point past the Descriptor to get the number of bytes consumed +- */ +- buffer += 1; +- +- MOVE_UNALIGNED16_TO_16 (&temp16, buffer); +- +- *bytes_consumed = temp16 + 3; +- +- output_struct->id = address16; +- +- output_struct->length = struct_size; +- +- /* +- * Get the Resource Type (Byte3) +- */ +- buffer += 2; +- temp8 = *buffer; +- +- /* Values 0-2 are valid */ +- if (temp8 > 2) { +- return (AE_AML_ERROR); +- } +- +- output_struct->data.address16.resource_type = temp8 & 0x03; +- +- /* +- * Get the General Flags (Byte4) +- */ +- buffer += 1; +- temp8 = *buffer; +- +- /* +- * Producer / Consumer +- */ +- output_struct->data.address16.producer_consumer = temp8 & 0x01; +- +- /* +- * Decode +- */ +- output_struct->data.address16.decode = (temp8 >> 1) & 0x01; +- +- /* +- * Min Address Fixed +- */ +- output_struct->data.address16.min_address_fixed = (temp8 >> 2) & 0x01; +- +- /* +- * Max Address Fixed +- */ +- output_struct->data.address16.max_address_fixed = (temp8 >> 3) & 0x01; +- +- /* +- * Get the Type Specific Flags (Byte5) +- */ +- buffer += 1; +- temp8 = *buffer; +- +- if (MEMORY_RANGE == output_struct->data.address16.resource_type) { +- output_struct->data.address16.attribute.memory.read_write_attribute = +- (u16) (temp8 & 0x01); +- output_struct->data.address16.attribute.memory.cache_attribute = +- (u16) ((temp8 >> 1) & 0x0F); +- } +- +- else { +- if (IO_RANGE == output_struct->data.address16.resource_type) { +- output_struct->data.address16.attribute.io.range_attribute = +- (u16) (temp8 & 0x03); +- } +- +- else { +- /* BUS_NUMBER_RANGE == Address32_data->Resource_type */ +- /* Nothing needs to be filled in */ +- } +- } +- +- /* +- * Get Granularity (Bytes 6-7) +- */ +- buffer += 1; +- MOVE_UNALIGNED16_TO_16 (&output_struct->data.address16.granularity, +- buffer); +- +- /* +- * Get Min_address_range (Bytes 8-9) +- */ +- buffer += 2; +- MOVE_UNALIGNED16_TO_16 (&output_struct->data.address16.min_address_range, +- buffer); +- +- /* +- * Get Max_address_range (Bytes 10-11) +- */ +- buffer += 2; +- MOVE_UNALIGNED16_TO_16 +- (&output_struct->data.address16.max_address_range, +- buffer); +- +- /* +- * Get Address_translation_offset (Bytes 12-13) +- */ +- buffer += 2; +- MOVE_UNALIGNED16_TO_16 +- (&output_struct->data.address16.address_translation_offset, +- buffer); +- +- /* +- * Get Address_length (Bytes 14-15) +- */ +- buffer += 2; +- MOVE_UNALIGNED16_TO_16 +- (&output_struct->data.address16.address_length, +- buffer); +- +- /* +- * Resource Source Index (if present) +- */ +- buffer += 2; +- +- /* +- * This will leave us pointing to the Resource Source Index +- * If it is present, then save it off and calculate the +- * pointer to where the null terminated string goes: +- * Each Interrupt takes 32-bits + the 5 bytes of the +- * stream that are default. +- */ +- if (*bytes_consumed > 16) { +- /* Dereference the Index */ +- +- temp8 = *buffer; +- output_struct->data.address16.resource_source_index = +- (u32) temp8; +- +- /* Point to the String */ +- +- buffer += 1; +- +- /* Copy the string into the buffer */ +- +- index = 0; +- +- while (0x00 != *buffer) { +- output_struct->data.address16.resource_source[index] = +- *buffer; +- +- buffer += 1; +- index += 1; +- } +- +- /* +- * Add the terminating null +- */ +- output_struct->data.address16.resource_source[index] = 0x00; +- +- output_struct->data.address16.resource_source_string_length = +- index + 1; +- +- /* +- * In order for the Struct_size to fall on a 32-bit boundry, +- * calculate the length of the string and expand the +- * Struct_size to the next 32-bit boundry. +- */ +- temp8 = (u8) (index + 1); +- struct_size += ROUND_UP_TO_32_bITS (temp8); +- output_struct->length = struct_size; +- } +- else { +- output_struct->data.address16.resource_source_index = 0x00; +- output_struct->data.address16.resource_source_string_length = 0; +- output_struct->data.address16.resource_source[0] = 0x00; +- } +- +- /* +- * Return the final size of the structure +- */ +- *structure_size = struct_size; +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_address16_stream +- * +- * PARAMETERS: Linked_list - Pointer to the resource linked list +- * Output_buffer - Pointer to the user's return buffer +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes of the +- * Output_buffer used +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the linked list resource structure and fills in the +- * the appropriate bytes in a byte stream +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_address16_stream ( +- RESOURCE *linked_list, +- u8 **output_buffer, +- u32 *bytes_consumed) +-{ +- u8 *buffer = *output_buffer; +- u8 *length_field; +- u8 temp8; +- NATIVE_CHAR *temp_pointer = NULL; +- u32 actual_bytes; +- +- +- /* +- * The descriptor field is static +- */ +- *buffer = 0x88; +- buffer += 1; +- +- /* +- * Save a pointer to the Length field - to be filled in later +- */ +- length_field = buffer; +- buffer += 2; +- +- /* +- * Set the Resource Type (Memory, Io, Bus_number) +- */ +- temp8 = (u8) (linked_list->data.address16.resource_type & 0x03); +- *buffer = temp8; +- buffer += 1; +- +- /* +- * Set the general flags +- */ +- temp8 = (u8) (linked_list->data.address16.producer_consumer & 0x01); +- +- temp8 |= (linked_list->data.address16.decode & 0x01) << 1; +- temp8 |= (linked_list->data.address16.min_address_fixed & 0x01) << 2; +- temp8 |= (linked_list->data.address16.max_address_fixed & 0x01) << 3; +- +- *buffer = temp8; +- buffer += 1; +- +- /* +- * Set the type specific flags +- */ +- temp8 = 0; +- +- if (MEMORY_RANGE == linked_list->data.address16.resource_type) { +- temp8 = (u8) +- (linked_list->data.address16.attribute.memory.read_write_attribute & +- 0x01); +- +- temp8 |= +- (linked_list->data.address16.attribute.memory.cache_attribute & +- 0x0F) << 1; +- } +- +- else if (IO_RANGE == linked_list->data.address16.resource_type) { +- temp8 = (u8) +- (linked_list->data.address16.attribute.io.range_attribute & +- 0x03); +- } +- +- *buffer = temp8; +- buffer += 1; +- +- /* +- * Set the address space granularity +- */ +- MOVE_UNALIGNED16_TO_16 (buffer, +- &linked_list->data.address16.granularity); +- buffer += 2; +- +- /* +- * Set the address range minimum +- */ +- MOVE_UNALIGNED16_TO_16 (buffer, +- &linked_list->data.address16.min_address_range); +- buffer += 2; +- +- /* +- * Set the address range maximum +- */ +- MOVE_UNALIGNED16_TO_16 (buffer, +- &linked_list->data.address16.max_address_range); +- buffer += 2; +- +- /* +- * Set the address translation offset +- */ +- MOVE_UNALIGNED16_TO_16 (buffer, +- &linked_list->data.address16.address_translation_offset); +- buffer += 2; +- +- /* +- * Set the address length +- */ +- MOVE_UNALIGNED16_TO_16 (buffer, +- &linked_list->data.address16.address_length); +- buffer += 2; +- +- /* +- * Resource Source Index and Resource Source are optional +- */ +- if (0 != linked_list->data.address16.resource_source_string_length) { +- temp8 = (u8) linked_list->data.address16.resource_source_index; +- +- *buffer = temp8; +- buffer += 1; +- +- temp_pointer = (NATIVE_CHAR *) buffer; +- +- /* +- * Copy the string +- */ +- STRCPY (temp_pointer, linked_list->data.address16.resource_source); +- +- /* +- * Buffer needs to be set to the length of the sting + one for the +- * terminating null +- */ +- buffer += (STRLEN (linked_list->data.address16.resource_source) + 1); +- } +- +- /* +- * Return the number of bytes consumed in this operation +- */ +- actual_bytes = (u32) ((NATIVE_UINT) buffer - +- (NATIVE_UINT) *output_buffer); +- +- *bytes_consumed = actual_bytes; +- +- /* +- * Set the length field to the number of bytes consumed +- * minus the header size (3 bytes) +- */ +- actual_bytes -= 3; +- MOVE_UNALIGNED16_TO_16 (length_field, &actual_bytes); +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_address32_resource +- * +- * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte +- * stream +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes consumed from +- * the Byte_stream_buffer +- * Output_buffer - Pointer to the user's return buffer +- * Structure_size - u32 pointer that is filled with +- * the number of bytes in the filled +- * in structure +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the resource byte stream and fill out the appropriate +- * structure pointed to by the Output_buffer. Return the +- * number of bytes consumed from the byte stream. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_address32_resource ( +- u8 *byte_stream_buffer, +- u32 *bytes_consumed, +- u8 **output_buffer, +- u32 *structure_size) +-{ +- u8 *buffer; +- RESOURCE *output_struct; +- u16 temp16; +- u8 temp8; +- u32 struct_size; +- u32 index; +- +- +- buffer = byte_stream_buffer; +- +- output_struct = (RESOURCE *) *output_buffer; +- +- struct_size = sizeof (ADDRESS32_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA; +- +- /* +- * Point past the Descriptor to get the number of bytes consumed +- */ +- buffer += 1; +- MOVE_UNALIGNED16_TO_16 (&temp16, buffer); +- +- *bytes_consumed = temp16 + 3; +- +- output_struct->id = address32; +- +- /* +- * Get the Resource Type (Byte3) +- */ +- buffer += 2; +- temp8 = *buffer; +- +- /* Values 0-2 are valid */ +- if(temp8 > 2) { +- return (AE_AML_ERROR); +- } +- +- output_struct->data.address32.resource_type = temp8 & 0x03; +- +- /* +- * Get the General Flags (Byte4) +- */ +- buffer += 1; +- temp8 = *buffer; +- +- /* +- * Producer / Consumer +- */ +- output_struct->data.address32.producer_consumer = temp8 & 0x01; +- +- /* +- * Decode +- */ +- output_struct->data.address32.decode = (temp8 >> 1) & 0x01; +- +- /* +- * Min Address Fixed +- */ +- output_struct->data.address32.min_address_fixed = (temp8 >> 2) & 0x01; +- +- /* +- * Max Address Fixed +- */ +- output_struct->data.address32.max_address_fixed = (temp8 >> 3) & 0x01; +- +- /* +- * Get the Type Specific Flags (Byte5) +- */ +- buffer += 1; +- temp8 = *buffer; +- +- if (MEMORY_RANGE == output_struct->data.address32.resource_type) { +- output_struct->data.address32.attribute.memory.read_write_attribute = +- (u16) (temp8 & 0x01); +- +- output_struct->data.address32.attribute.memory.cache_attribute = +- (u16) ((temp8 >> 1) & 0x0F); +- } +- +- else { +- if (IO_RANGE == output_struct->data.address32.resource_type) { +- output_struct->data.address32.attribute.io.range_attribute = +- (u16) (temp8 & 0x03); +- } +- +- else { +- /* BUS_NUMBER_RANGE == Output_struct->Data.Address32.Resource_type */ +- /* Nothing needs to be filled in */ +- } +- } +- +- /* +- * Get Granularity (Bytes 6-9) +- */ +- buffer += 1; +- MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.granularity, +- buffer); +- +- /* +- * Get Min_address_range (Bytes 10-13) +- */ +- buffer += 4; +- MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.min_address_range, +- buffer); +- +- /* +- * Get Max_address_range (Bytes 14-17) +- */ +- buffer += 4; +- MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.max_address_range, +- buffer); +- +- /* +- * Get Address_translation_offset (Bytes 18-21) +- */ +- buffer += 4; +- MOVE_UNALIGNED32_TO_32 +- (&output_struct->data.address32.address_translation_offset, +- buffer); +- +- /* +- * Get Address_length (Bytes 22-25) +- */ +- buffer += 4; +- MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.address_length, +- buffer); +- +- /* +- * Resource Source Index (if present) +- */ +- buffer += 4; +- +- /* +- * This will leave us pointing to the Resource Source Index +- * If it is present, then save it off and calculate the +- * pointer to where the null terminated string goes: +- * Each Interrupt takes 32-bits + the 5 bytes of the +- * stream that are default. +- */ +- if (*bytes_consumed > 26) { +- /* Dereference the Index */ +- +- temp8 = *buffer; +- output_struct->data.address32.resource_source_index = (u32)temp8; +- +- /* Point to the String */ +- +- buffer += 1; +- +- /* Copy the string into the buffer */ +- +- index = 0; +- +- while (0x00 != *buffer) { +- output_struct->data.address32.resource_source[index] = *buffer; +- buffer += 1; +- index += 1; +- } +- +- /* +- * Add the terminating null +- */ +- output_struct->data.address32.resource_source[index] = 0x00; +- +- output_struct->data.address32.resource_source_string_length = index + 1; +- +- /* +- * In order for the Struct_size to fall on a 32-bit boundry, +- * calculate the length of the string and expand the +- * Struct_size to the next 32-bit boundry. +- */ +- temp8 = (u8) (index + 1); +- struct_size += ROUND_UP_TO_32_bITS (temp8); +- } +- +- else { +- output_struct->data.address32.resource_source_index = 0x00; +- output_struct->data.address32.resource_source_string_length = 0; +- output_struct->data.address32.resource_source[0] = 0x00; +- } +- +- /* +- * Set the Length parameter +- */ +- output_struct->length = struct_size; +- +- /* +- * Return the final size of the structure +- */ +- *structure_size = struct_size; +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_address32_stream +- * +- * PARAMETERS: Linked_list - Pointer to the resource linked list +- * Output_buffer - Pointer to the user's return buffer +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes of the +- * Output_buffer used +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the linked list resource structure and fills in the +- * the appropriate bytes in a byte stream +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_address32_stream ( +- RESOURCE *linked_list, +- u8 **output_buffer, +- u32 *bytes_consumed) +-{ +- u8 *buffer; +- u16 *length_field; +- u8 temp8; +- NATIVE_CHAR *temp_pointer; +- +- +- buffer = *output_buffer; +- +- /* +- * The descriptor field is static +- */ +- *buffer = 0x87; +- buffer += 1; +- +- /* +- * Set a pointer to the Length field - to be filled in later +- */ +- +- length_field = (u16 *)buffer; +- buffer += 2; +- +- /* +- * Set the Resource Type (Memory, Io, Bus_number) +- */ +- temp8 = (u8) (linked_list->data.address32.resource_type & 0x03); +- +- *buffer = temp8; +- buffer += 1; +- +- /* +- * Set the general flags +- */ +- temp8 = (u8) (linked_list->data.address32.producer_consumer & 0x01); +- temp8 |= (linked_list->data.address32.decode & 0x01) << 1; +- temp8 |= (linked_list->data.address32.min_address_fixed & 0x01) << 2; +- temp8 |= (linked_list->data.address32.max_address_fixed & 0x01) << 3; +- +- *buffer = temp8; +- buffer += 1; +- +- /* +- * Set the type specific flags +- */ +- temp8 = 0; +- +- if(MEMORY_RANGE == linked_list->data.address32.resource_type) { +- temp8 = (u8) +- (linked_list->data.address32.attribute.memory.read_write_attribute & +- 0x01); +- +- temp8 |= +- (linked_list->data.address32.attribute.memory.cache_attribute & +- 0x0F) << 1; +- } +- +- else if (IO_RANGE == linked_list->data.address32.resource_type) { +- temp8 = (u8) +- (linked_list->data.address32.attribute.io.range_attribute & +- 0x03); +- } +- +- *buffer = temp8; +- buffer += 1; +- +- /* +- * Set the address space granularity +- */ +- MOVE_UNALIGNED32_TO_32 (buffer, +- &linked_list->data.address32.granularity); +- buffer += 4; +- +- /* +- * Set the address range minimum +- */ +- MOVE_UNALIGNED32_TO_32 (buffer, +- &linked_list->data.address32.min_address_range); +- buffer += 4; +- +- /* +- * Set the address range maximum +- */ +- MOVE_UNALIGNED32_TO_32 (buffer, +- &linked_list->data.address32.max_address_range); +- buffer += 4; +- +- /* +- * Set the address translation offset +- */ +- MOVE_UNALIGNED32_TO_32 (buffer, +- &linked_list->data.address32.address_translation_offset); +- buffer += 4; +- +- /* +- * Set the address length +- */ +- MOVE_UNALIGNED32_TO_32 (buffer, +- &linked_list->data.address32.address_length); +- buffer += 4; +- +- /* +- * Resource Source Index and Resource Source are optional +- */ +- if (0 != linked_list->data.address32.resource_source_string_length) { +- temp8 = (u8) linked_list->data.address32.resource_source_index; +- +- *buffer = temp8; +- buffer += 1; +- +- temp_pointer = (NATIVE_CHAR *) buffer; +- +- /* +- * Copy the string +- */ +- STRCPY (temp_pointer, linked_list->data.address32.resource_source); +- +- /* +- * Buffer needs to be set to the length of the sting + one for the +- * terminating null +- */ +- buffer += (STRLEN (linked_list->data.address32.resource_source) + 1); +- } +- +- /* +- * Return the number of bytes consumed in this operation +- */ +- *bytes_consumed = (u32) ((NATIVE_UINT) buffer - +- (NATIVE_UINT) *output_buffer); +- +- /* +- * Set the length field to the number of bytes consumed +- * minus the header size (3 bytes) +- */ +- *length_field = (u16) (*bytes_consumed - 3); +- +- return (AE_OK); +-} +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resources/rscalc.c linux/drivers/acpi/resources/rscalc.c +--- /usr/src/linux/drivers/acpi/resources/rscalc.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/resources/rscalc.c Wed Dec 31 16:00:00 1969 +@@ -1,872 +0,0 @@ +-/******************************************************************************* +- * +- * Module Name: rscalc - Acpi_rs_calculate_byte_stream_length +- * Acpi_rs_calculate_list_length +- * $Revision: 21 $ +- * +- ******************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acresrc.h" +-#include "amlcode.h" +-#include "acnamesp.h" +- +-#define _COMPONENT RESOURCE_MANAGER +- MODULE_NAME ("rscalc") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_calculate_byte_stream_length +- * +- * PARAMETERS: Linked_list - Pointer to the resource linked list +- * Size_needed - u32 pointer of the size buffer needed +- * to properly return the parsed data +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Takes the resource byte stream and parses it once, calculating +- * the size buffer needed to hold the linked list that conveys +- * the resource data. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_calculate_byte_stream_length ( +- RESOURCE *linked_list, +- u32 *size_needed) +-{ +- u32 byte_stream_size_needed = 0; +- u32 segment_size; +- EXTENDED_IRQ_RESOURCE *ex_irq = NULL; +- u8 done = FALSE; +- +- +- while (!done) { +- +- /* +- * Init the variable that will hold the size to add to the +- * total. +- */ +- segment_size = 0; +- +- switch (linked_list->id) +- { +- case irq: +- /* +- * IRQ Resource +- */ +- /* +- * For an IRQ Resource, Byte 3, although optional, will +- * always be created - it holds IRQ information. +- */ +- segment_size = 4; +- break; +- +- case dma: +- /* +- * DMA Resource +- */ +- /* +- * For this resource the size is static +- */ +- segment_size = 3; +- break; +- +- case start_dependent_functions: +- /* +- * Start Dependent Functions Resource +- */ +- /* +- * For a Start_dependent_functions Resource, Byte 1, +- * although optional, will always be created. +- */ +- segment_size = 2; +- break; +- +- case end_dependent_functions: +- /* +- * End Dependent Functions Resource +- */ +- /* +- * For this resource the size is static +- */ +- segment_size = 1; +- break; +- +- case io: +- /* +- * IO Port Resource +- */ +- /* +- * For this resource the size is static +- */ +- segment_size = 8; +- break; +- +- case fixed_io: +- /* +- * Fixed IO Port Resource +- */ +- /* +- * For this resource the size is static +- */ +- segment_size = 4; +- break; +- +- case vendor_specific: +- /* +- * Vendor Defined Resource +- */ +- /* +- * For a Vendor Specific resource, if the Length is +- * between 1 and 7 it will be created as a Small +- * Resource data type, otherwise it is a Large +- * Resource data type. +- */ +- if(linked_list->data.vendor_specific.length > 7) { +- segment_size = 3; +- } +- else { +- segment_size = 1; +- } +- segment_size += +- linked_list->data.vendor_specific.length; +- break; +- +- case end_tag: +- /* +- * End Tag +- */ +- /* +- * For this resource the size is static +- */ +- segment_size = 2; +- done = TRUE; +- break; +- +- case memory24: +- /* +- * 24-Bit Memory Resource +- */ +- /* +- * For this resource the size is static +- */ +- segment_size = 12; +- break; +- +- case memory32: +- /* +- * 32-Bit Memory Range Resource +- */ +- /* +- * For this resource the size is static +- */ +- segment_size = 20; +- break; +- +- case fixed_memory32: +- /* +- * 32-Bit Fixed Memory Resource +- */ +- /* +- * For this resource the size is static +- */ +- segment_size = 12; +- break; +- +- case address16: +- /* +- * 16-Bit Address Resource +- */ +- /* +- * The base size of this byte stream is 16. If a +- * Resource Source string is not NULL, add 1 for +- * the Index + the length of the null terminated +- * string Resource Source + 1 for the null. +- */ +- segment_size = 16; +- +- if(NULL != linked_list->data.address16.resource_source) { +- segment_size += (1 + +- linked_list->data.address16.resource_source_string_length); +- } +- break; +- +- case address32: +- /* +- * 32-Bit Address Resource +- */ +- /* +- * The base size of this byte stream is 26. If a Resource +- * Source string is not NULL, add 1 for the Index + the +- * length of the null terminated string Resource Source + +- * 1 for the null. +- */ +- segment_size = 26; +- +- if(NULL != linked_list->data.address16.resource_source) { +- segment_size += (1 + +- linked_list->data.address16.resource_source_string_length); +- } +- break; +- +- case extended_irq: +- /* +- * Extended IRQ Resource +- */ +- /* +- * The base size of this byte stream is 9. This is for an +- * Interrupt table length of 1. For each additional +- * interrupt, add 4. +- * If a Resource Source string is not NULL, add 1 for the +- * Index + the length of the null terminated string +- * Resource Source + 1 for the null. +- */ +- segment_size = 9; +- +- segment_size += +- (linked_list->data.extended_irq.number_of_interrupts - +- 1) * 4; +- +- if(NULL != ex_irq->resource_source) { +- segment_size += (1 + +- linked_list->data.extended_irq.resource_source_string_length); +- } +- break; +- +- default: +- /* +- * If we get here, everything is out of sync, +- * so exit with an error +- */ +- return (AE_AML_ERROR); +- break; +- +- } /* switch (Linked_list->Id) */ +- +- /* +- * Update the total +- */ +- byte_stream_size_needed += segment_size; +- +- /* +- * Point to the next object +- */ +- linked_list = (RESOURCE *) ((NATIVE_UINT) linked_list + +- (NATIVE_UINT) linked_list->length); +- } +- +- /* +- * This is the data the caller needs +- */ +- *size_needed = byte_stream_size_needed; +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_calculate_list_length +- * +- * PARAMETERS: Byte_stream_buffer - Pointer to the resource byte stream +- * Byte_stream_buffer_length - Size of Byte_stream_buffer +- * Size_needed - u32 pointer of the size buffer +- * needed to properly return the +- * parsed data +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Takes the resource byte stream and parses it once, calculating +- * the size buffer needed to hold the linked list that conveys +- * the resource data. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_calculate_list_length ( +- u8 *byte_stream_buffer, +- u32 byte_stream_buffer_length, +- u32 *size_needed) +-{ +- u32 buffer_size = 0; +- u32 bytes_parsed = 0; +- u8 number_of_interrupts = 0; +- u8 number_of_channels = 0; +- u8 resource_type; +- u32 structure_size; +- u32 bytes_consumed; +- u8 *buffer; +- u8 temp8; +- u16 temp16; +- u8 index; +- u8 additional_bytes; +- +- +- while (bytes_parsed < byte_stream_buffer_length) { +- /* +- * Look at the next byte in the stream +- */ +- resource_type = *byte_stream_buffer; +- +- /* +- * See if this is a small or large resource +- */ +- if(resource_type & 0x80) { +- /* +- * Large Resource Type +- */ +- switch (resource_type) +- { +- case MEMORY_RANGE_24: +- /* +- * 24-Bit Memory Resource +- */ +- bytes_consumed = 12; +- +- structure_size = sizeof (MEMORY24_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA; +- break; +- +- case LARGE_VENDOR_DEFINED: +- /* +- * Vendor Defined Resource +- */ +- buffer = byte_stream_buffer; +- ++buffer; +- +- MOVE_UNALIGNED16_TO_16 (&temp16, buffer); +- bytes_consumed = temp16 + 3; +- +- /* +- * Ensure a 32-bit boundary for the structure +- */ +- temp16 = (u16) ROUND_UP_TO_32_bITS (temp16); +- +- structure_size = sizeof (VENDOR_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA + +- (temp16 * sizeof (u8)); +- break; +- +- case MEMORY_RANGE_32: +- /* +- * 32-Bit Memory Range Resource +- */ +- +- bytes_consumed = 20; +- +- structure_size = sizeof (MEMORY32_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA; +- break; +- +- case FIXED_MEMORY_RANGE_32: +- /* +- * 32-Bit Fixed Memory Resource +- */ +- bytes_consumed = 12; +- +- structure_size = sizeof(FIXED_MEMORY32_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA; +- break; +- +- case DWORD_ADDRESS_SPACE: +- /* +- * 32-Bit Address Resource +- */ +- buffer = byte_stream_buffer; +- +- ++buffer; +- MOVE_UNALIGNED16_TO_16 (&temp16, buffer); +- +- bytes_consumed = temp16 + 3; +- +- /* +- * Resource Source Index and Resource Source are +- * optional elements. Check the length of the +- * Bytestream. If it is greater than 23, that +- * means that an Index exists and is followed by +- * a null termininated string. Therefore, set +- * the temp variable to the length minus the minimum +- * byte stream length plus the byte for the Index to +- * determine the size of the NULL terminiated string. +- */ +- if (23 < temp16) { +- temp8 = (u8) (temp16 - 24); +- } +- else { +- temp8 = 0; +- } +- +- /* +- * Ensure a 32-bit boundary for the structure +- */ +- temp8 = (u8) ROUND_UP_TO_32_bITS (temp8); +- +- structure_size = sizeof (ADDRESS32_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA + +- (temp8 * sizeof (u8)); +- break; +- +- case WORD_ADDRESS_SPACE: +- /* +- * 16-Bit Address Resource +- */ +- buffer = byte_stream_buffer; +- +- ++buffer; +- MOVE_UNALIGNED16_TO_16 (&temp16, buffer); +- +- bytes_consumed = temp16 + 3; +- +- /* +- * Resource Source Index and Resource Source are +- * optional elements. Check the length of the +- * Bytestream. If it is greater than 13, that +- * means that an Index exists and is followed by +- * a null termininated string. Therefore, set +- * the temp variable to the length minus the minimum +- * byte stream length plus the byte for the Index to +- * determine the size of the NULL terminiated string. +- */ +- if (13 < temp16) { +- temp8 = (u8) (temp16 - 14); +- } +- else { +- temp8 = 0; +- } +- +- /* +- * Ensure a 32-bit boundry for the structure +- */ +- temp8 = (u8) ROUND_UP_TO_32_bITS (temp8); +- +- structure_size = sizeof (ADDRESS16_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA + +- (temp8 * sizeof (u8)); +- break; +- +- case EXTENDED_IRQ: +- /* +- * Extended IRQ +- */ +- buffer = byte_stream_buffer; +- +- ++buffer; +- MOVE_UNALIGNED16_TO_16 (&temp16, buffer); +- +- bytes_consumed = temp16 + 3; +- +- /* +- * Point past the length field and the +- * Interrupt vector flags to save off the +- * Interrupt table length to the Temp8 variable. +- */ +- buffer += 3; +- temp8 = *buffer; +- +- /* +- * To compensate for multiple interrupt numbers, +- * Add 4 bytes for each additional interrupts +- * greater than 1 +- */ +- additional_bytes = (u8) ((temp8 - 1) * 4); +- +- /* +- * Resource Source Index and Resource Source are +- * optional elements. Check the length of the +- * Bytestream. If it is greater than 9, that +- * means that an Index exists and is followed by +- * a null termininated string. Therefore, set +- * the temp variable to the length minus the minimum +- * byte stream length plus the byte for the Index to +- * determine the size of the NULL terminiated string. +- */ +- if (9 + additional_bytes < temp16) { +- temp8 = (u8) (temp16 - (9 + additional_bytes)); +- } +- +- else { +- temp8 = 0; +- } +- +- /* +- * Ensure a 32-bit boundry for the structure +- */ +- temp8 = (u8) ROUND_UP_TO_32_bITS (temp8); +- +- structure_size = sizeof (EXTENDED_IRQ_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA + +- (additional_bytes * sizeof (u8)) + +- (temp8 * sizeof (u8)); +- +- break; +- +-/* TBD: [Future] 64-bit not currently supported */ +-/* +- case 0x8A: +- break; +-*/ +- +- default: +- /* +- * If we get here, everything is out of sync, +- * so exit with an error +- */ +- return (AE_AML_ERROR); +- break; +- } +- } +- +- else { +- /* +- * Small Resource Type +- * Only bits 7:3 are valid +- */ +- resource_type >>= 3; +- +- switch (resource_type) +- { +- case IRQ_FORMAT: +- /* +- * IRQ Resource +- */ +- /* +- * Determine if it there are two or three +- * trailing bytes +- */ +- buffer = byte_stream_buffer; +- temp8 = *buffer; +- +- if(temp8 & 0x01) { +- bytes_consumed = 4; +- } +- +- else { +- bytes_consumed = 3; +- } +- +- /* +- * Point past the descriptor +- */ +- ++buffer; +- +- /* +- * Look at the number of bits set +- */ +- MOVE_UNALIGNED16_TO_16 (&temp16, buffer); +- +- for (index = 0; index < 16; index++) { +- if (temp16 & 0x1) { +- ++number_of_interrupts; +- } +- +- temp16 >>= 1; +- } +- +- structure_size = sizeof (IO_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA + +- (number_of_interrupts * sizeof (u32)); +- break; +- +- +- case DMA_FORMAT: +- +- /* +- * DMA Resource +- */ +- buffer = byte_stream_buffer; +- +- bytes_consumed = 3; +- +- /* +- * Point past the descriptor +- */ +- ++buffer; +- +- /* +- * Look at the number of bits set +- */ +- temp8 = *buffer; +- +- for(index = 0; index < 8; index++) { +- if(temp8 & 0x1) { +- ++number_of_channels; +- } +- +- temp8 >>= 1; +- } +- +- structure_size = sizeof (DMA_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA + +- (number_of_channels * sizeof (u32)); +- break; +- +- +- case START_DEPENDENT_TAG: +- +- /* +- * Start Dependent Functions Resource +- */ +- /* +- * Determine if it there are two or three trailing bytes +- */ +- buffer = byte_stream_buffer; +- temp8 = *buffer; +- +- if(temp8 & 0x01) { +- bytes_consumed = 2; +- } +- else { +- bytes_consumed = 1; +- } +- +- +- structure_size = +- sizeof (START_DEPENDENT_FUNCTIONS_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA; +- break; +- +- +- case END_DEPENDENT_TAG: +- +- /* +- * End Dependent Functions Resource +- */ +- bytes_consumed = 1; +- structure_size = RESOURCE_LENGTH; +- break; +- +- +- case IO_PORT_DESCRIPTOR: +- /* +- * IO Port Resource +- */ +- bytes_consumed = 8; +- structure_size = sizeof (IO_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA; +- break; +- +- +- case FIXED_LOCATION_IO_DESCRIPTOR: +- +- /* +- * Fixed IO Port Resource +- */ +- bytes_consumed = 4; +- structure_size = sizeof (FIXED_IO_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA; +- break; +- +- +- case SMALL_VENDOR_DEFINED: +- +- /* +- * Vendor Specific Resource +- */ +- buffer = byte_stream_buffer; +- +- temp8 = *buffer; +- temp8 = (u8) (temp8 & 0x7); +- bytes_consumed = temp8 + 1; +- +- /* +- * Ensure a 32-bit boundry for the structure +- */ +- temp8 = (u8) ROUND_UP_TO_32_bITS (temp8); +- structure_size = sizeof (VENDOR_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA + +- (temp8 * sizeof (u8)); +- break; +- +- +- case END_TAG: +- +- /* +- * End Tag +- */ +- bytes_consumed = 2; +- structure_size = RESOURCE_LENGTH; +- byte_stream_buffer_length = bytes_parsed; +- break; +- +- +- default: +- /* +- * If we get here, everything is out of sync, +- * so exit with an error +- */ +- return (AE_AML_ERROR); +- break; +- +- } /* switch */ +- +- } /* if(Resource_type & 0x80) */ +- +- /* +- * Update the return value and counter +- */ +- buffer_size += structure_size; +- bytes_parsed += bytes_consumed; +- +- /* +- * Set the byte stream to point to the next resource +- */ +- byte_stream_buffer += bytes_consumed; +- +- } +- +- /* +- * This is the data the caller needs +- */ +- *size_needed = buffer_size; +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_calculate_pci_routing_table_length +- * +- * PARAMETERS: Package_object - Pointer to the package object +- * Buffer_size_needed - u32 pointer of the size buffer +- * needed to properly return the +- * parsed data +- * +- * RETURN: Status AE_OK +- * +- * DESCRIPTION: Given a package representing a PCI routing table, this +- * calculates the size of the corresponding linked list of +- * descriptions. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_calculate_pci_routing_table_length ( +- ACPI_OPERAND_OBJECT *package_object, +- u32 *buffer_size_needed) +-{ +- u32 number_of_elements; +- u32 temp_size_needed = 0; +- ACPI_OPERAND_OBJECT **top_object_list; +- u32 index; +- ACPI_OPERAND_OBJECT *package_element; +- ACPI_OPERAND_OBJECT **sub_object_list; +- u8 name_found; +- u32 table_index; +- +- +- number_of_elements = package_object->package.count; +- +- /* +- * Calculate the size of the return buffer. +- * The base size is the number of elements * the sizes of the +- * structures. Additional space for the strings is added below. +- * The minus one is to subtract the size of the u8 Source[1] +- * member because it is added below. +- * +- * NOTE: The Number_of_elements is incremented by one to add an end +- * table structure that is essentially a structure of zeros. +- */ +- +- /* +- * But each PRT_ENTRY structure has a pointer to a string and +- * the size of that string must be found. +- */ +- top_object_list = package_object->package.elements; +- +- for (index = 0; index < number_of_elements; index++) { +- /* +- * Dereference the sub-package +- */ +- package_element = *top_object_list; +- +- /* +- * The Sub_object_list will now point to an array of the +- * four IRQ elements: Address, Pin, Source and Source_index +- */ +- sub_object_list = package_element->package.elements; +- +- /* +- * Scan the Irq_table_elements for the Source Name String +- */ +- name_found = FALSE; +- +- for (table_index = 0; table_index < 4 && !name_found; table_index++) { +- if ((ACPI_TYPE_STRING == (*sub_object_list)->common.type) || +- ((INTERNAL_TYPE_REFERENCE == (*sub_object_list)->common.type) && +- ((*sub_object_list)->reference.op_code == AML_NAMEPATH_OP))) +- { +- name_found = TRUE; +- } +- +- else { +- /* +- * Look at the next element +- */ +- sub_object_list++; +- } +- } +- +- temp_size_needed += (sizeof (PCI_ROUTING_TABLE) - 4); +- +- /* +- * Was a String type found? +- */ +- if (TRUE == name_found) { +- if (ACPI_TYPE_STRING == (*sub_object_list)->common.type) { +- /* +- * The length String.Length field includes the +- * terminating NULL +- */ +- temp_size_needed += (*sub_object_list)->string.length; +- } +- else { +- temp_size_needed += acpi_ns_get_pathname_length ((*sub_object_list)->reference.node); +- } +- } +- +- else { +- /* +- * If no name was found, then this is a NULL, which is +- * translated as a u32 zero. +- */ +- temp_size_needed += sizeof(u32); +- } +- +- +- /* Round up the size since each element must be aligned */ +- +- temp_size_needed = ROUND_UP_TO_64_bITS (temp_size_needed); +- +- /* +- * Point to the next ACPI_OPERAND_OBJECT +- */ +- top_object_list++; +- } +- +- +- *buffer_size_needed = temp_size_needed; +- +- return (AE_OK); +-} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resources/rscreate.c linux/drivers/acpi/resources/rscreate.c +--- /usr/src/linux/drivers/acpi/resources/rscreate.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/resources/rscreate.c Wed Dec 31 16:00:00 1969 +@@ -1,422 +0,0 @@ +-/******************************************************************************* +- * +- * Module Name: rscreate - Acpi_rs_create_resource_list +- * Acpi_rs_create_pci_routing_table +- * Acpi_rs_create_byte_stream +- * $Revision: 25 $ +- * +- ******************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acresrc.h" +-#include "amlcode.h" +-#include "acnamesp.h" +- +-#define _COMPONENT RESOURCE_MANAGER +- MODULE_NAME ("rscreate") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_create_resource_list +- * +- * PARAMETERS: +- * Byte_stream_buffer - Pointer to the resource byte stream +- * Output_buffer - Pointer to the user's buffer +- * Output_buffer_length - Pointer to the size of Output_buffer +- * +- * RETURN: Status - AE_OK if okay, else a valid ACPI_STATUS code +- * If Output_buffer is not large enough, Output_buffer_length +- * indicates how large Output_buffer should be, else it +- * indicates how may u8 elements of Output_buffer are valid. +- * +- * DESCRIPTION: Takes the byte stream returned from a _CRS, _PRS control method +- * execution and parses the stream to create a linked list +- * of device resources. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_create_resource_list ( +- ACPI_OPERAND_OBJECT *byte_stream_buffer, +- u8 *output_buffer, +- u32 *output_buffer_length) +-{ +- +- ACPI_STATUS status; +- u8 *byte_stream_start = NULL; +- u32 list_size_needed = 0; +- u32 byte_stream_buffer_length = 0; +- +- +- /* +- * Params already validated, so we don't re-validate here +- */ +- +- byte_stream_buffer_length = byte_stream_buffer->buffer.length; +- byte_stream_start = byte_stream_buffer->buffer.pointer; +- +- /* +- * Pass the Byte_stream_buffer into a module that can calculate +- * the buffer size needed for the linked list +- */ +- status = acpi_rs_calculate_list_length (byte_stream_start, +- byte_stream_buffer_length, +- &list_size_needed); +- +- /* +- * Exit with the error passed back +- */ +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- /* +- * If the linked list will fit into the available buffer +- * call to fill in the list +- */ +- +- if (list_size_needed <= *output_buffer_length) { +- /* +- * Zero out the return buffer before proceeding +- */ +- MEMSET (output_buffer, 0x00, *output_buffer_length); +- +- status = acpi_rs_byte_stream_to_list (byte_stream_start, +- byte_stream_buffer_length, +- &output_buffer); +- +- /* +- * Exit with the error passed back +- */ +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- } +- +- else { +- *output_buffer_length = list_size_needed; +- return (AE_BUFFER_OVERFLOW); +- } +- +- *output_buffer_length = list_size_needed; +- return (AE_OK); +- +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_create_pci_routing_table +- * +- * PARAMETERS: +- * Package_object - Pointer to an ACPI_OPERAND_OBJECT +- * package +- * Output_buffer - Pointer to the user's buffer +- * Output_buffer_length - Size of Output_buffer +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code. +- * If the Output_buffer is too small, the error will be +- * AE_BUFFER_OVERFLOW and Output_buffer_length will point +- * to the size buffer needed. +- * +- * DESCRIPTION: Takes the ACPI_OPERAND_OBJECT package and creates a +- * linked list of PCI interrupt descriptions +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_create_pci_routing_table ( +- ACPI_OPERAND_OBJECT *package_object, +- u8 *output_buffer, +- u32 *output_buffer_length) +-{ +- u8 *buffer = output_buffer; +- ACPI_OPERAND_OBJECT **top_object_list = NULL; +- ACPI_OPERAND_OBJECT **sub_object_list = NULL; +- ACPI_OPERAND_OBJECT *package_element = NULL; +- u32 buffer_size_needed = 0; +- u32 number_of_elements = 0; +- u32 index = 0; +- PCI_ROUTING_TABLE *user_prt = NULL; +- ACPI_NAMESPACE_NODE *node; +- ACPI_STATUS status; +- +- +- /* +- * Params already validated, so we don't re-validate here +- */ +- +- status = acpi_rs_calculate_pci_routing_table_length(package_object, +- &buffer_size_needed); +- +- /* +- * If the data will fit into the available buffer +- * call to fill in the list +- */ +- if (buffer_size_needed <= *output_buffer_length) { +- /* +- * Zero out the return buffer before proceeding +- */ +- MEMSET (output_buffer, 0x00, *output_buffer_length); +- +- /* +- * Loop through the ACPI_INTERNAL_OBJECTS - Each object should +- * contain a u32 Address, a u8 Pin, a Name and a u8 +- * Source_index. +- */ +- top_object_list = package_object->package.elements; +- number_of_elements = package_object->package.count; +- user_prt = (PCI_ROUTING_TABLE *) buffer; +- +- +- buffer = ROUND_PTR_UP_TO_8 (buffer, u8); +- +- for (index = 0; index < number_of_elements; index++) { +- /* +- * Point User_prt past this current structure +- * +- * NOTE: On the first iteration, User_prt->Length will +- * be zero because we cleared the return buffer earlier +- */ +- buffer += user_prt->length; +- user_prt = (PCI_ROUTING_TABLE *) buffer; +- +- +- /* +- * Fill in the Length field with the information we +- * have at this point. +- * The minus four is to subtract the size of the +- * u8 Source[4] member because it is added below. +- */ +- user_prt->length = (sizeof (PCI_ROUTING_TABLE) -4); +- +- /* +- * Dereference the sub-package +- */ +- package_element = *top_object_list; +- +- /* +- * The Sub_object_list will now point to an array of +- * the four IRQ elements: Address, Pin, Source and +- * Source_index +- */ +- sub_object_list = package_element->package.elements; +- +- /* +- * 1) First subobject: Dereference the Address +- */ +- if (ACPI_TYPE_INTEGER == (*sub_object_list)->common.type) { +- user_prt->address = (*sub_object_list)->integer.value; +- } +- +- else { +- return (AE_BAD_DATA); +- } +- +- /* +- * 2) Second subobject: Dereference the Pin +- */ +- sub_object_list++; +- +- if (ACPI_TYPE_INTEGER == (*sub_object_list)->common.type) { +- user_prt->pin = +- (u32) (*sub_object_list)->integer.value; +- } +- +- else { +- return (AE_BAD_DATA); +- } +- +- /* +- * 3) Third subobject: Dereference the Source Name +- */ +- sub_object_list++; +- +- switch ((*sub_object_list)->common.type) +- { +- case INTERNAL_TYPE_REFERENCE: +- if ((*sub_object_list)->reference.op_code != AML_NAMEPATH_OP) { +- return (AE_BAD_DATA); +- } +- +- node = (*sub_object_list)->reference.node; +- +- /* TBD: use *remaining* length of the buffer! */ +- +- status = acpi_ns_handle_to_pathname ((ACPI_HANDLE *) node, +- output_buffer_length, user_prt->source); +- +- user_prt->length += STRLEN (user_prt->source) + 1; /* include null terminator */ +- break; +- +- +- case ACPI_TYPE_STRING: +- +- STRCPY (user_prt->source, +- (*sub_object_list)->string.pointer); +- +- /* +- * Add to the Length field the length of the string +- */ +- user_prt->length += (*sub_object_list)->string.length; +- break; +- +- +- case ACPI_TYPE_INTEGER: +- /* +- * If this is a number, then the Source Name +- * is NULL, since the entire buffer was zeroed +- * out, we can leave this alone. +- */ +- /* +- * Add to the Length field the length of +- * the u32 NULL +- */ +- user_prt->length += sizeof (u32); +- break; +- +- +- default: +- return (AE_BAD_DATA); +- break; +- } +- +- /* Now align the current length */ +- +- user_prt->length = ROUND_UP_TO_64_bITS (user_prt->length); +- +- /* +- * 4) Fourth subobject: Dereference the Source Index +- */ +- sub_object_list++; +- +- if (ACPI_TYPE_INTEGER == (*sub_object_list)->common.type) { +- user_prt->source_index = +- (u32) (*sub_object_list)->integer.value; +- } +- +- else { +- return (AE_BAD_DATA); +- } +- +- /* +- * Point to the next ACPI_OPERAND_OBJECT +- */ +- top_object_list++; +- } +- +- } +- +- else { +- *output_buffer_length = buffer_size_needed; +- +- return (AE_BUFFER_OVERFLOW); +- } +- +- /* +- * Report the amount of buffer used +- */ +- *output_buffer_length = buffer_size_needed; +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_create_byte_stream +- * +- * PARAMETERS: +- * Linked_list_buffer - Pointer to the resource linked list +- * Output_buffer - Pointer to the user's buffer +- * Output_buffer_length - Size of Output_buffer +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code. +- * If the Output_buffer is too small, the error will be +- * AE_BUFFER_OVERFLOW and Output_buffer_length will point +- * to the size buffer needed. +- * +- * DESCRIPTION: Takes the linked list of device resources and +- * creates a bytestream to be used as input for the +- * _SRS control method. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_create_byte_stream ( +- RESOURCE *linked_list_buffer, +- u8 *output_buffer, +- u32 *output_buffer_length) +-{ +- ACPI_STATUS status; +- u32 byte_stream_size_needed = 0; +- +- +- /* +- * Params already validated, so we don't re-validate here +- * +- * Pass the Linked_list_buffer into a module that can calculate +- * the buffer size needed for the byte stream. +- */ +- status = acpi_rs_calculate_byte_stream_length (linked_list_buffer, +- &byte_stream_size_needed); +- +- /* +- * Exit with the error passed back +- */ +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- /* +- * If the linked list will fit into the available buffer +- * call to fill in the list +- */ +- +- if (byte_stream_size_needed <= *output_buffer_length) { +- /* +- * Zero out the return buffer before proceeding +- */ +- MEMSET (output_buffer, 0x00, *output_buffer_length); +- +- status = acpi_rs_list_to_byte_stream (linked_list_buffer, +- byte_stream_size_needed, +- &output_buffer); +- +- /* +- * Exit with the error passed back +- */ +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- } +- else { +- *output_buffer_length = byte_stream_size_needed; +- return (AE_BUFFER_OVERFLOW); +- } +- +- return (AE_OK); +-} +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resources/rsdump.c linux/drivers/acpi/resources/rsdump.c +--- /usr/src/linux/drivers/acpi/resources/rsdump.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/resources/rsdump.c Wed Dec 31 16:00:00 1969 +@@ -1,940 +0,0 @@ +-/******************************************************************************* +- * +- * Module Name: rsdump - Functions do dump out the resource structures. +- * $Revision: 16 $ +- * +- ******************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acresrc.h" +- +-#define _COMPONENT RESOURCE_MANAGER +- MODULE_NAME ("rsdump") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_dump_irq +- * +- * PARAMETERS: Data - pointer to the resource structure to dump. +- * +- * RETURN: +- * +- * DESCRIPTION: Prints out the various members of the Data structure type. +- * +- ******************************************************************************/ +- +-void +-acpi_rs_dump_irq ( +- RESOURCE_DATA *data) +-{ +- IRQ_RESOURCE *irq_data = (IRQ_RESOURCE*) data; +- u8 index = 0; +- +- +- acpi_os_printf ("\t_iRQ Resource\n"); +- +- acpi_os_printf ("\t\t%s Triggered\n", +- LEVEL_SENSITIVE == irq_data->edge_level ? +- "Level" : "Edge"); +- +- acpi_os_printf ("\t\t_active %s\n", +- ACTIVE_LOW == irq_data->active_high_low ? +- "Low" : "High"); +- +- acpi_os_printf ("\t\t%s\n", +- SHARED == irq_data->shared_exclusive ? +- "Shared" : "Exclusive"); +- +- acpi_os_printf ("\t\t%X Interrupts ( ", +- irq_data->number_of_interrupts); +- +- for (index = 0; index < irq_data->number_of_interrupts; index++) { +- acpi_os_printf ("%X ", irq_data->interrupts[index]); +- } +- +- acpi_os_printf (")\n"); +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_dump_dma +- * +- * PARAMETERS: Data - pointer to the resource structure to dump. +- * +- * RETURN: +- * +- * DESCRIPTION: Prints out the various members of the Data structure type. +- * +- ******************************************************************************/ +- +-void +-acpi_rs_dump_dma ( +- RESOURCE_DATA *data) +-{ +- DMA_RESOURCE *dma_data = (DMA_RESOURCE*) data; +- u8 index = 0; +- +- +- acpi_os_printf ("\t_dMA Resource\n"); +- +- switch (dma_data->type) +- { +- case COMPATIBILITY: +- acpi_os_printf ("\t\t_compatibility mode\n"); +- break; +- +- case TYPE_A: +- acpi_os_printf ("\t\t_type A\n"); +- break; +- +- case TYPE_B: +- acpi_os_printf ("\t\t_type B\n"); +- break; +- +- case TYPE_F: +- acpi_os_printf ("\t\t_type F\n"); +- break; +- +- default: +- acpi_os_printf ("\t\t_invalid DMA type\n"); +- break; +- } +- +- acpi_os_printf ("\t\t%sBus Master\n", +- BUS_MASTER == dma_data->bus_master ? +- "" : "Not a "); +- +- switch (dma_data->transfer) +- { +- case TRANSFER_8: +- acpi_os_printf ("\t\t8-bit only transfer\n"); +- break; +- +- case TRANSFER_8_16: +- acpi_os_printf ("\t\t8 and 16-bit transfer\n"); +- break; +- +- case TRANSFER_16: +- acpi_os_printf ("\t\t16 bit only transfer\n"); +- break; +- +- default: +- acpi_os_printf ("\t\t_invalid transfer preference\n"); +- break; +- } +- +- acpi_os_printf ("\t\t_number of Channels: %X ( ", +- dma_data->number_of_channels); +- +- for (index = 0; index < dma_data->number_of_channels; index++) { +- acpi_os_printf ("%X ", dma_data->channels[index]); +- } +- +- acpi_os_printf (")\n"); +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_dump_start_dependent_functions +- * +- * PARAMETERS: Data - pointer to the resource structure to dump. +- * +- * RETURN: +- * +- * DESCRIPTION: Prints out the various members of the Data structure type. +- * +- ******************************************************************************/ +- +-void +-acpi_rs_dump_start_dependent_functions ( +- RESOURCE_DATA *data) +-{ +- START_DEPENDENT_FUNCTIONS_RESOURCE *sdf_data = +- (START_DEPENDENT_FUNCTIONS_RESOURCE*) data; +- +- +- acpi_os_printf ("\t_start Dependent Functions Resource\n"); +- +- switch (sdf_data->compatibility_priority) +- { +- case GOOD_CONFIGURATION: +- acpi_os_printf ("\t\t_good configuration\n"); +- break; +- +- case ACCEPTABLE_CONFIGURATION: +- acpi_os_printf ("\t\t_acceptable configuration\n"); +- break; +- +- case SUB_OPTIMAL_CONFIGURATION: +- acpi_os_printf ("\t\t_sub-optimal configuration\n"); +- break; +- +- default: +- acpi_os_printf ("\t\t_invalid compatibility priority\n"); +- break; +- } +- +- switch(sdf_data->performance_robustness) +- { +- case GOOD_CONFIGURATION: +- acpi_os_printf ("\t\t_good configuration\n"); +- break; +- +- case ACCEPTABLE_CONFIGURATION: +- acpi_os_printf ("\t\t_acceptable configuration\n"); +- break; +- +- case SUB_OPTIMAL_CONFIGURATION: +- acpi_os_printf ("\t\t_sub-optimal configuration\n"); +- break; +- +- default: +- acpi_os_printf ("\t\t_invalid performance " +- "robustness preference\n"); +- break; +- } +- +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_dump_io +- * +- * PARAMETERS: Data - pointer to the resource structure to dump. +- * +- * RETURN: +- * +- * DESCRIPTION: Prints out the various members of the Data structure type. +- * +- ******************************************************************************/ +- +-void +-acpi_rs_dump_io ( +- RESOURCE_DATA *data) +-{ +- IO_RESOURCE *io_data = (IO_RESOURCE*) data; +- +- +- acpi_os_printf ("\t_io Resource\n"); +- +- acpi_os_printf ("\t\t%d bit decode\n", +- DECODE_16 == io_data->io_decode ? 16 : 10); +- +- acpi_os_printf ("\t\t_range minimum base: %08X\n", +- io_data->min_base_address); +- +- acpi_os_printf ("\t\t_range maximum base: %08X\n", +- io_data->max_base_address); +- +- acpi_os_printf ("\t\t_alignment: %08X\n", +- io_data->alignment); +- +- acpi_os_printf ("\t\t_range Length: %08X\n", +- io_data->range_length); +- +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_dump_fixed_io +- * +- * PARAMETERS: Data - pointer to the resource structure to dump. +- * +- * RETURN: +- * +- * DESCRIPTION: Prints out the various members of the Data structure type. +- * +- ******************************************************************************/ +- +-void +-acpi_rs_dump_fixed_io ( +- RESOURCE_DATA *data) +-{ +- FIXED_IO_RESOURCE *fixed_io_data = (FIXED_IO_RESOURCE*) data; +- +- +- acpi_os_printf ("\t_fixed Io Resource\n"); +- acpi_os_printf ("\t\t_range base address: %08X", +- fixed_io_data->base_address); +- +- acpi_os_printf ("\t\t_range length: %08X", +- fixed_io_data->range_length); +- +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_dump_vendor_specific +- * +- * PARAMETERS: Data - pointer to the resource structure to dump. +- * +- * RETURN: +- * +- * DESCRIPTION: Prints out the various members of the Data structure type. +- * +- ******************************************************************************/ +- +-void +-acpi_rs_dump_vendor_specific ( +- RESOURCE_DATA *data) +-{ +- VENDOR_RESOURCE *vendor_data = (VENDOR_RESOURCE*) data; +- u16 index = 0; +- +- +- acpi_os_printf ("\t_vendor Specific Resource\n"); +- +- acpi_os_printf ("\t\t_length: %08X\n", vendor_data->length); +- +- for (index = 0; index < vendor_data->length; index++) { +- acpi_os_printf ("\t\t_byte %X: %08X\n", +- index, vendor_data->reserved[index]); +- } +- +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_dump_memory24 +- * +- * PARAMETERS: Data - pointer to the resource structure to dump. +- * +- * RETURN: +- * +- * DESCRIPTION: Prints out the various members of the Data structure type. +- * +- ******************************************************************************/ +- +-void +-acpi_rs_dump_memory24 ( +- RESOURCE_DATA *data) +-{ +- MEMORY24_RESOURCE *memory24_data = (MEMORY24_RESOURCE*) data; +- +- +- acpi_os_printf ("\t24-Bit Memory Range Resource\n"); +- +- acpi_os_printf ("\t\t_read%s\n", +- READ_WRITE_MEMORY == +- memory24_data->read_write_attribute ? +- "/Write" : " only"); +- +- acpi_os_printf ("\t\t_range minimum base: %08X\n", +- memory24_data->min_base_address); +- +- acpi_os_printf ("\t\t_range maximum base: %08X\n", +- memory24_data->max_base_address); +- +- acpi_os_printf ("\t\t_alignment: %08X\n", +- memory24_data->alignment); +- +- acpi_os_printf ("\t\t_range length: %08X\n", +- memory24_data->range_length); +- +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_dump_memory32 +- * +- * PARAMETERS: Data - pointer to the resource structure to dump. +- * +- * RETURN: +- * +- * DESCRIPTION: Prints out the various members of the Data structure type. +- * +- ******************************************************************************/ +- +-void +-acpi_rs_dump_memory32 ( +- RESOURCE_DATA *data) +-{ +- MEMORY32_RESOURCE *memory32_data = (MEMORY32_RESOURCE*) data; +- +- +- acpi_os_printf ("\t32-Bit Memory Range Resource\n"); +- +- acpi_os_printf ("\t\t_read%s\n", +- READ_WRITE_MEMORY == +- memory32_data->read_write_attribute ? +- "/Write" : " only"); +- +- acpi_os_printf ("\t\t_range minimum base: %08X\n", +- memory32_data->min_base_address); +- +- acpi_os_printf ("\t\t_range maximum base: %08X\n", +- memory32_data->max_base_address); +- +- acpi_os_printf ("\t\t_alignment: %08X\n", +- memory32_data->alignment); +- +- acpi_os_printf ("\t\t_range length: %08X\n", +- memory32_data->range_length); +- +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_dump_fixed_memory32 +- * +- * PARAMETERS: Data - pointer to the resource structure to dump. +- * +- * RETURN: +- * +- * DESCRIPTION: Prints out the various members of the Data structure type. +- * +- ******************************************************************************/ +- +-void +-acpi_rs_dump_fixed_memory32 ( +- RESOURCE_DATA *data) +-{ +- FIXED_MEMORY32_RESOURCE *fixed_memory32_data = (FIXED_MEMORY32_RESOURCE*) data; +- +- +- acpi_os_printf ("\t32-Bit Fixed Location Memory Range Resource\n"); +- +- acpi_os_printf ("\t\t_read%s\n", +- READ_WRITE_MEMORY == +- fixed_memory32_data->read_write_attribute ? +- "/Write" : " Only"); +- +- acpi_os_printf ("\t\t_range base address: %08X\n", +- fixed_memory32_data->range_base_address); +- +- acpi_os_printf ("\t\t_range length: %08X\n", +- fixed_memory32_data->range_length); +- +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_dump_address16 +- * +- * PARAMETERS: Data - pointer to the resource structure to dump. +- * +- * RETURN: +- * +- * DESCRIPTION: Prints out the various members of the Data structure type. +- * +- ******************************************************************************/ +- +-void +-acpi_rs_dump_address16 ( +- RESOURCE_DATA *data) +-{ +- ADDRESS16_RESOURCE *address16_data = (ADDRESS16_RESOURCE*) data; +- +- +- acpi_os_printf ("\t16-Bit Address Space Resource\n"); +- acpi_os_printf ("\t\t_resource Type: "); +- +- switch (address16_data->resource_type) +- { +- case MEMORY_RANGE: +- +- acpi_os_printf ("Memory Range\n"); +- +- switch (address16_data->attribute.memory.cache_attribute) +- { +- case NON_CACHEABLE_MEMORY: +- acpi_os_printf ("\t\t_type Specific: " +- "Noncacheable memory\n"); +- break; +- +- case CACHABLE_MEMORY: +- acpi_os_printf ("\t\t_type Specific: " +- "Cacheable memory\n"); +- break; +- +- case WRITE_COMBINING_MEMORY: +- acpi_os_printf ("\t\t_type Specific: " +- "Write-combining memory\n"); +- break; +- +- case PREFETCHABLE_MEMORY: +- acpi_os_printf ("\t\t_type Specific: " +- "Prefetchable memory\n"); +- break; +- +- default: +- acpi_os_printf ("\t\t_type Specific: " +- "Invalid cache attribute\n"); +- break; +- } +- +- acpi_os_printf ("\t\t_type Specific: Read%s\n", +- READ_WRITE_MEMORY == +- address16_data->attribute.memory.read_write_attribute ? +- "/Write" : " Only"); +- break; +- +- case IO_RANGE: +- +- acpi_os_printf ("I/O Range\n"); +- +- switch (address16_data->attribute.io.range_attribute) +- { +- case NON_ISA_ONLY_RANGES: +- acpi_os_printf ("\t\t_type Specific: " +- "Non-ISA Io Addresses\n"); +- break; +- +- case ISA_ONLY_RANGES: +- acpi_os_printf ("\t\t_type Specific: " +- "ISA Io Addresses\n"); +- break; +- +- case ENTIRE_RANGE: +- acpi_os_printf ("\t\t_type Specific: " +- "ISA and non-ISA Io Addresses\n"); +- break; +- +- default: +- acpi_os_printf ("\t\t_type Specific: " +- "Invalid range attribute\n"); +- break; +- } +- break; +- +- case BUS_NUMBER_RANGE: +- +- acpi_os_printf ("Bus Number Range\n"); +- break; +- +- default: +- +- acpi_os_printf ("Invalid resource type. Exiting.\n"); +- return; +- } +- +- acpi_os_printf ("\t\t_resource %s\n", +- CONSUMER == address16_data->producer_consumer ? +- "Consumer" : "Producer"); +- +- acpi_os_printf ("\t\t%s decode\n", +- SUB_DECODE == address16_data->decode ? +- "Subtractive" : "Positive"); +- +- acpi_os_printf ("\t\t_min address is %s fixed\n", +- ADDRESS_FIXED == address16_data->min_address_fixed ? +- "" : "not"); +- +- acpi_os_printf ("\t\t_max address is %s fixed\n", +- ADDRESS_FIXED == address16_data->max_address_fixed ? +- "" : "not"); +- +- acpi_os_printf ("\t\t_granularity: %08X\n", +- address16_data->granularity); +- +- acpi_os_printf ("\t\t_address range min: %08X\n", +- address16_data->min_address_range); +- +- acpi_os_printf ("\t\t_address range max: %08X\n", +- address16_data->max_address_range); +- +- acpi_os_printf ("\t\t_address translation offset: %08X\n", +- address16_data->address_translation_offset); +- +- acpi_os_printf ("\t\t_address Length: %08X\n", +- address16_data->address_length); +- +- if (0xFF != address16_data->resource_source_index) { +- acpi_os_printf ("\t\t_resource Source Index: %X\n", +- address16_data->resource_source_index); +- acpi_os_printf ("\t\t_resource Source: %s\n", +- address16_data->resource_source); +- } +- +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_dump_address32 +- * +- * PARAMETERS: Data - pointer to the resource structure to dump. +- * +- * RETURN: +- * +- * DESCRIPTION: Prints out the various members of the Data structure type. +- * +- ******************************************************************************/ +- +-void +-acpi_rs_dump_address32 ( +- RESOURCE_DATA *data) +-{ +- ADDRESS32_RESOURCE *address32_data = (ADDRESS32_RESOURCE*) data; +- +- +- acpi_os_printf ("\t32-Bit Address Space Resource\n"); +- +- switch (address32_data->resource_type) +- { +- case MEMORY_RANGE: +- +- acpi_os_printf ("\t\t_resource Type: Memory Range\n"); +- +- switch (address32_data->attribute.memory.cache_attribute) +- { +- case NON_CACHEABLE_MEMORY: +- acpi_os_printf ("\t\t_type Specific: " +- "Noncacheable memory\n"); +- break; +- +- case CACHABLE_MEMORY: +- acpi_os_printf ("\t\t_type Specific: " +- "Cacheable memory\n"); +- break; +- +- case WRITE_COMBINING_MEMORY: +- acpi_os_printf ("\t\t_type Specific: " +- "Write-combining memory\n"); +- break; +- +- case PREFETCHABLE_MEMORY: +- acpi_os_printf ("\t\t_type Specific: " +- "Prefetchable memory\n"); +- break; +- +- default: +- acpi_os_printf ("\t\t_type Specific: " +- "Invalid cache attribute\n"); +- break; +- } +- +- acpi_os_printf ("\t\t_type Specific: Read%s\n", +- READ_WRITE_MEMORY == +- address32_data->attribute.memory.read_write_attribute ? +- "/Write" : " Only"); +- break; +- +- case IO_RANGE: +- +- acpi_os_printf ("\t\t_resource Type: Io Range\n"); +- +- switch (address32_data->attribute.io.range_attribute) +- { +- case NON_ISA_ONLY_RANGES: +- acpi_os_printf ("\t\t_type Specific: " +- "Non-ISA Io Addresses\n"); +- break; +- +- case ISA_ONLY_RANGES: +- acpi_os_printf ("\t\t_type Specific: " +- "ISA Io Addresses\n"); +- break; +- +- case ENTIRE_RANGE: +- acpi_os_printf ("\t\t_type Specific: " +- "ISA and non-ISA Io Addresses\n"); +- break; +- +- default: +- acpi_os_printf ("\t\t_type Specific: " +- "Invalid Range attribute"); +- break; +- } +- break; +- +- case BUS_NUMBER_RANGE: +- +- acpi_os_printf ("\t\t_resource Type: Bus Number Range\n"); +- break; +- +- default: +- +- acpi_os_printf ("\t\t_invalid Resource Type..exiting.\n"); +- return; +- } +- +- acpi_os_printf ("\t\t_resource %s\n", +- CONSUMER == address32_data->producer_consumer ? +- "Consumer" : "Producer"); +- +- acpi_os_printf ("\t\t%s decode\n", +- SUB_DECODE == address32_data->decode ? +- "Subtractive" : "Positive"); +- +- acpi_os_printf ("\t\t_min address is %s fixed\n", +- ADDRESS_FIXED == address32_data->min_address_fixed ? +- "" : "not "); +- +- acpi_os_printf ("\t\t_max address is %s fixed\n", +- ADDRESS_FIXED == address32_data->max_address_fixed ? +- "" : "not "); +- +- acpi_os_printf ("\t\t_granularity: %08X\n", +- address32_data->granularity); +- +- acpi_os_printf ("\t\t_address range min: %08X\n", +- address32_data->min_address_range); +- +- acpi_os_printf ("\t\t_address range max: %08X\n", +- address32_data->max_address_range); +- +- acpi_os_printf ("\t\t_address translation offset: %08X\n", +- address32_data->address_translation_offset); +- +- acpi_os_printf ("\t\t_address Length: %08X\n", +- address32_data->address_length); +- +- if(0xFF != address32_data->resource_source_index) { +- acpi_os_printf ("\t\t_resource Source Index: %X\n", +- address32_data->resource_source_index); +- acpi_os_printf ("\t\t_resource Source: %s\n", +- address32_data->resource_source); +- } +- +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_dump_extended_irq +- * +- * PARAMETERS: Data - pointer to the resource structure to dump. +- * +- * RETURN: +- * +- * DESCRIPTION: Prints out the various members of the Data structure type. +- * +- ******************************************************************************/ +- +-void +-acpi_rs_dump_extended_irq ( +- RESOURCE_DATA *data) +-{ +- EXTENDED_IRQ_RESOURCE *ext_irq_data = (EXTENDED_IRQ_RESOURCE*) data; +- u8 index = 0; +- +- +- acpi_os_printf ("\t_extended IRQ Resource\n"); +- +- acpi_os_printf ("\t\t_resource %s\n", +- CONSUMER == ext_irq_data->producer_consumer ? +- "Consumer" : "Producer"); +- +- acpi_os_printf ("\t\t%s\n", +- LEVEL_SENSITIVE == ext_irq_data->edge_level ? +- "Level" : "Edge"); +- +- acpi_os_printf ("\t\t_active %s\n", +- ACTIVE_LOW == ext_irq_data->active_high_low ? +- "low" : "high"); +- +- acpi_os_printf ("\t\t%s\n", +- SHARED == ext_irq_data->shared_exclusive ? +- "Shared" : "Exclusive"); +- +- acpi_os_printf ("\t\t_interrupts : %X ( ", +- ext_irq_data->number_of_interrupts); +- +- for (index = 0; index < ext_irq_data->number_of_interrupts; index++) { +- acpi_os_printf ("%X ", ext_irq_data->interrupts[index]); +- } +- +- acpi_os_printf (")\n"); +- +- if(0xFF != ext_irq_data->resource_source_index) { +- acpi_os_printf ("\t\t_resource Source Index: %X", +- ext_irq_data->resource_source_index); +- acpi_os_printf ("\t\t_resource Source: %s", +- ext_irq_data->resource_source); +- } +- +- return; +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_dump_resource_list +- * +- * PARAMETERS: Data - pointer to the resource structure to dump. +- * +- * RETURN: +- * +- * DESCRIPTION: Dispatches the structure to the correct dump routine. +- * +- ******************************************************************************/ +- +-void +-acpi_rs_dump_resource_list ( +- RESOURCE *resource) +-{ +- u8 count = 0; +- u8 done = FALSE; +- +- +- if (acpi_dbg_level & TRACE_RESOURCES && _COMPONENT & acpi_dbg_layer) { +- while (!done) { +- acpi_os_printf ("\t_resource structure %x.\n", count++); +- +- switch (resource->id) +- { +- case irq: +- acpi_rs_dump_irq (&resource->data); +- break; +- +- case dma: +- acpi_rs_dump_dma (&resource->data); +- break; +- +- case start_dependent_functions: +- acpi_rs_dump_start_dependent_functions (&resource->data); +- break; +- +- case end_dependent_functions: +- acpi_os_printf ("\t_end_dependent_functions Resource\n"); +- /* Acpi_rs_dump_end_dependent_functions (Resource->Data);*/ +- break; +- +- case io: +- acpi_rs_dump_io (&resource->data); +- break; +- +- case fixed_io: +- acpi_rs_dump_fixed_io (&resource->data); +- break; +- +- case vendor_specific: +- acpi_rs_dump_vendor_specific (&resource->data); +- break; +- +- case end_tag: +- /*Rs_dump_end_tag (Resource->Data);*/ +- acpi_os_printf ("\t_end_tag Resource\n"); +- done = TRUE; +- break; +- +- case memory24: +- acpi_rs_dump_memory24 (&resource->data); +- break; +- +- case memory32: +- acpi_rs_dump_memory32 (&resource->data); +- break; +- +- case fixed_memory32: +- acpi_rs_dump_fixed_memory32 (&resource->data); +- break; +- +- case address16: +- acpi_rs_dump_address16 (&resource->data); +- break; +- +- case address32: +- acpi_rs_dump_address32 (&resource->data); +- break; +- +- case extended_irq: +- acpi_rs_dump_extended_irq (&resource->data); +- break; +- +- default: +- acpi_os_printf ("Invalid resource type\n"); +- break; +- +- } +- +- resource = (RESOURCE *) ((NATIVE_UINT) resource + +- (NATIVE_UINT) resource->length); +- } +- } +- +- return; +-} +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_dump_irq_list +- * +- * PARAMETERS: Data - pointer to the routing table to dump. +- * +- * RETURN: +- * +- * DESCRIPTION: Dispatches the structures to the correct dump routine. +- * +- ******************************************************************************/ +- +-void +-acpi_rs_dump_irq_list ( +- u8 *route_table) +-{ +- u8 *buffer = route_table; +- u8 count = 0; +- u8 done = FALSE; +- PCI_ROUTING_TABLE *prt_element; +- +- +- if (acpi_dbg_level & TRACE_RESOURCES && _COMPONENT & acpi_dbg_layer) { +- prt_element = (PCI_ROUTING_TABLE *) buffer; +- +- while (!done) { +- acpi_os_printf ("\t_pCI IRQ Routing Table structure %X.\n", count++); +- +- acpi_os_printf ("\t\t_address: %X\n", +- prt_element->address); +- +- acpi_os_printf ("\t\t_pin: %X\n", prt_element->pin); +- +- acpi_os_printf ("\t\t_source: %s\n", prt_element->source); +- +- acpi_os_printf ("\t\t_source_index: %X\n", +- prt_element->source_index); +- +- buffer += prt_element->length; +- +- prt_element = (PCI_ROUTING_TABLE *) buffer; +- +- if(0 == prt_element->length) { +- done = TRUE; +- } +- } +- } +- +- return; +-} +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resources/rsio.c linux/drivers/acpi/resources/rsio.c +--- /usr/src/linux/drivers/acpi/resources/rsio.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/resources/rsio.c Wed Dec 31 16:00:00 1969 +@@ -1,529 +0,0 @@ +-/******************************************************************************* +- * +- * Module Name: rsio - Acpi_rs_io_resource +- * Acpi_rs_fixed_io_resource +- * Acpi_rs_io_stream +- * Acpi_rs_fixed_io_stream +- * Acpi_rs_dma_resource +- * Acpi_rs_dma_stream +- * $Revision: 12 $ +- * +- ******************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acresrc.h" +- +-#define _COMPONENT RESOURCE_MANAGER +- MODULE_NAME ("rsio") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_io_resource +- * +- * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte +- * stream +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes consumed from +- * the Byte_stream_buffer +- * Output_buffer - Pointer to the user's return buffer +- * Structure_size - u32 pointer that is filled with +- * the number of bytes in the filled +- * in structure +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the resource byte stream and fill out the appropriate +- * structure pointed to by the Output_buffer. Return the +- * number of bytes consumed from the byte stream. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_io_resource ( +- u8 *byte_stream_buffer, +- u32 *bytes_consumed, +- u8 **output_buffer, +- u32 *structure_size) +-{ +- u8 *buffer = byte_stream_buffer; +- RESOURCE *output_struct = (RESOURCE *) * output_buffer; +- u16 temp16 = 0; +- u8 temp8 = 0; +- u32 struct_size = sizeof (IO_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA; +- +- +- /* +- * The number of bytes consumed are Constant +- */ +- *bytes_consumed = 8; +- +- output_struct->id = io; +- +- /* +- * Check Decode +- */ +- buffer += 1; +- temp8 = *buffer; +- +- output_struct->data.io.io_decode = temp8 & 0x01; +- +- /* +- * Check Min_base Address +- */ +- buffer += 1; +- MOVE_UNALIGNED16_TO_16 (&temp16, buffer); +- +- output_struct->data.io.min_base_address = temp16; +- +- /* +- * Check Max_base Address +- */ +- buffer += 2; +- MOVE_UNALIGNED16_TO_16 (&temp16, buffer); +- +- output_struct->data.io.max_base_address = temp16; +- +- /* +- * Check Base alignment +- */ +- buffer += 2; +- temp8 = *buffer; +- +- output_struct->data.io.alignment = temp8; +- +- /* +- * Check Range_length +- */ +- buffer += 1; +- temp8 = *buffer; +- +- output_struct->data.io.range_length = temp8; +- +- /* +- * Set the Length parameter +- */ +- output_struct->length = struct_size; +- +- /* +- * Return the final size of the structure +- */ +- *structure_size = struct_size; +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_fixed_io_resource +- * +- * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte +- * stream +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes consumed from +- * the Byte_stream_buffer +- * Output_buffer - Pointer to the user's return buffer +- * Structure_size - u32 pointer that is filled with +- * the number of bytes in the filled +- * in structure +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the resource byte stream and fill out the appropriate +- * structure pointed to by the Output_buffer. Return the +- * number of bytes consumed from the byte stream. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_fixed_io_resource ( +- u8 *byte_stream_buffer, +- u32 *bytes_consumed, +- u8 **output_buffer, +- u32 *structure_size) +-{ +- u8 *buffer = byte_stream_buffer; +- RESOURCE *output_struct = (RESOURCE *) * output_buffer; +- u16 temp16 = 0; +- u8 temp8 = 0; +- u32 struct_size = sizeof (FIXED_IO_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA; +- +- +- /* +- * The number of bytes consumed are Constant +- */ +- *bytes_consumed = 4; +- +- output_struct->id = fixed_io; +- +- /* +- * Check Range Base Address +- */ +- buffer += 1; +- MOVE_UNALIGNED16_TO_16 (&temp16, buffer); +- +- output_struct->data.fixed_io.base_address = temp16; +- +- /* +- * Check Range_length +- */ +- buffer += 2; +- temp8 = *buffer; +- +- output_struct->data.fixed_io.range_length = temp8; +- +- /* +- * Set the Length parameter +- */ +- output_struct->length = struct_size; +- +- /* +- * Return the final size of the structure +- */ +- *structure_size = struct_size; +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_io_stream +- * +- * PARAMETERS: Linked_list - Pointer to the resource linked list +- * Output_buffer - Pointer to the user's return buffer +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes of the +- * Output_buffer used +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the linked list resource structure and fills in the +- * the appropriate bytes in a byte stream +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_io_stream ( +- RESOURCE *linked_list, +- u8 **output_buffer, +- u32 *bytes_consumed) +-{ +- u8 *buffer = *output_buffer; +- u16 temp16 = 0; +- u8 temp8 = 0; +- +- +- /* +- * The descriptor field is static +- */ +- *buffer = 0x47; +- buffer += 1; +- +- /* +- * Io Information Byte +- */ +- temp8 = (u8) (linked_list->data.io.io_decode & 0x01); +- +- *buffer = temp8; +- buffer += 1; +- +- /* +- * Set the Range minimum base address +- */ +- temp16 = (u16) linked_list->data.io.min_base_address; +- +- MOVE_UNALIGNED16_TO_16 (buffer, &temp16); +- buffer += 2; +- +- /* +- * Set the Range maximum base address +- */ +- temp16 = (u16) linked_list->data.io.max_base_address; +- +- MOVE_UNALIGNED16_TO_16 (buffer, &temp16); +- buffer += 2; +- +- /* +- * Set the base alignment +- */ +- temp8 = (u8) linked_list->data.io.alignment; +- +- *buffer = temp8; +- buffer += 1; +- +- /* +- * Set the range length +- */ +- temp8 = (u8) linked_list->data.io.range_length; +- +- *buffer = temp8; +- buffer += 1; +- +- /* +- * Return the number of bytes consumed in this operation +- */ +- *bytes_consumed = (u32) ((NATIVE_UINT) buffer - +- (NATIVE_UINT) *output_buffer); +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_fixed_io_stream +- * +- * PARAMETERS: Linked_list - Pointer to the resource linked list +- * Output_buffer - Pointer to the user's return buffer +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes of the +- * Output_buffer used +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the linked list resource structure and fills in the +- * the appropriate bytes in a byte stream +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_fixed_io_stream ( +- RESOURCE *linked_list, +- u8 **output_buffer, +- u32 *bytes_consumed) +-{ +- u8 *buffer = *output_buffer; +- u16 temp16 = 0; +- u8 temp8 = 0; +- +- +- /* +- * The descriptor field is static +- */ +- *buffer = 0x4B; +- +- buffer += 1; +- +- /* +- * Set the Range base address +- */ +- temp16 = (u16) linked_list->data.fixed_io.base_address; +- +- MOVE_UNALIGNED16_TO_16 (buffer, &temp16); +- buffer += 2; +- +- /* +- * Set the range length +- */ +- temp8 = (u8) linked_list->data.fixed_io.range_length; +- +- *buffer = temp8; +- buffer += 1; +- +- /* +- * Return the number of bytes consumed in this operation +- */ +- *bytes_consumed = (u32) ((NATIVE_UINT) buffer - +- (NATIVE_UINT) *output_buffer); +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_dma_resource +- * +- * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte +- * stream +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes consumed from +- * the Byte_stream_buffer +- * Output_buffer - Pointer to the user's return buffer +- * Structure_size - u32 pointer that is filled with +- * the number of bytes in the filled +- * in structure +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the resource byte stream and fill out the appropriate +- * structure pointed to by the Output_buffer. Return the +- * number of bytes consumed from the byte stream. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_dma_resource ( +- u8 *byte_stream_buffer, +- u32 *bytes_consumed, +- u8 **output_buffer, +- u32 *structure_size) +-{ +- u8 *buffer = byte_stream_buffer; +- RESOURCE *output_struct = (RESOURCE *) * output_buffer; +- u8 temp8 = 0; +- u8 index; +- u8 i; +- u32 struct_size = sizeof(DMA_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA; +- +- +- /* +- * The number of bytes consumed are Constant +- */ +- *bytes_consumed = 3; +- output_struct->id = dma; +- +- /* +- * Point to the 8-bits of Byte 1 +- */ +- buffer += 1; +- temp8 = *buffer; +- +- /* Decode the IRQ bits */ +- +- for (i = 0, index = 0; index < 8; index++) { +- if ((temp8 >> index) & 0x01) { +- output_struct->data.dma.channels[i] = index; +- i++; +- } +- } +- output_struct->data.dma.number_of_channels = i; +- +- +- /* +- * Calculate the structure size based upon the number of interrupts +- */ +- struct_size += (output_struct->data.dma.number_of_channels - 1) * 4; +- +- /* +- * Point to Byte 2 +- */ +- buffer += 1; +- temp8 = *buffer; +- +- /* +- * Check for transfer preference (Bits[1:0]) +- */ +- output_struct->data.dma.transfer = temp8 & 0x03; +- +- if (0x03 == output_struct->data.dma.transfer) { +- return (AE_BAD_DATA); +- } +- +- /* +- * Get bus master preference (Bit[2]) +- */ +- output_struct->data.dma.bus_master = (temp8 >> 2) & 0x01; +- +- /* +- * Get channel speed support (Bits[6:5]) +- */ +- output_struct->data.dma.type = (temp8 >> 5) & 0x03; +- +- /* +- * Set the Length parameter +- */ +- output_struct->length = struct_size; +- +- /* +- * Return the final size of the structure +- */ +- *structure_size = struct_size; +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_dma_stream +- * +- * PARAMETERS: Linked_list - Pointer to the resource linked list +- * Output_buffer - Pointer to the user's return buffer +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes of the +- * Output_buffer used +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the linked list resource structure and fills in the +- * the appropriate bytes in a byte stream +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_dma_stream ( +- RESOURCE *linked_list, +- u8 **output_buffer, +- u32 *bytes_consumed) +-{ +- u8 *buffer = *output_buffer; +- u16 temp16 = 0; +- u8 temp8 = 0; +- u8 index; +- +- +- /* +- * The descriptor field is static +- */ +- *buffer = 0x2A; +- buffer += 1; +- temp8 = 0; +- +- /* +- * Loop through all of the Channels and set the mask bits +- */ +- for (index = 0; +- index < linked_list->data.dma.number_of_channels; +- index++) +- { +- temp16 = (u16) linked_list->data.dma.channels[index]; +- temp8 |= 0x1 << temp16; +- } +- +- *buffer = temp8; +- buffer += 1; +- +- /* +- * Set the DMA Info +- */ +- temp8 = (u8) ((linked_list->data.dma.type & 0x03) << 5); +- temp8 |= ((linked_list->data.dma.bus_master & 0x01) << 2); +- temp8 |= (linked_list->data.dma.transfer & 0x03); +- +- *buffer = temp8; +- buffer += 1; +- +- /* +- * Return the number of bytes consumed in this operation +- */ +- *bytes_consumed = (u32) ((NATIVE_UINT) buffer - +- (NATIVE_UINT) *output_buffer); +- +- return (AE_OK); +-} +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resources/rsirq.c linux/drivers/acpi/resources/rsirq.c +--- /usr/src/linux/drivers/acpi/resources/rsirq.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/resources/rsirq.c Wed Dec 31 16:00:00 1969 +@@ -1,562 +0,0 @@ +-/******************************************************************************* +- * +- * Module Name: rsirq - Acpi_rs_irq_resource, +- * Acpi_rs_irq_stream +- * Acpi_rs_extended_irq_resource +- * Acpi_rs_extended_irq_stream +- * $Revision: 13 $ +- * +- ******************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acresrc.h" +- +-#define _COMPONENT RESOURCE_MANAGER +- MODULE_NAME ("rsirq") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_irq_resource +- * +- * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte +- * stream +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes consumed from +- * the Byte_stream_buffer +- * Output_buffer - Pointer to the user's return buffer +- * Structure_size - u32 pointer that is filled with +- * the number of bytes in the filled +- * in structure +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the resource byte stream and fill out the appropriate +- * structure pointed to by the Output_buffer. Return the +- * number of bytes consumed from the byte stream. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_irq_resource ( +- u8 *byte_stream_buffer, +- u32 *bytes_consumed, +- u8 **output_buffer, +- u32 *structure_size) +-{ +- u8 *buffer = byte_stream_buffer; +- RESOURCE *output_struct = (RESOURCE *) * output_buffer; +- u16 temp16 = 0; +- u8 temp8 = 0; +- u8 index; +- u8 i; +- u32 struct_size = sizeof (IRQ_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA; +- +- +- /* +- * The number of bytes consumed are contained in the descriptor +- * (Bits:0-1) +- */ +- temp8 = *buffer; +- *bytes_consumed = (temp8 & 0x03) + 1; +- output_struct->id = irq; +- +- /* +- * Point to the 16-bits of Bytes 1 and 2 +- */ +- buffer += 1; +- MOVE_UNALIGNED16_TO_16 (&temp16, buffer); +- +- output_struct->data.irq.number_of_interrupts = 0; +- +- /* Decode the IRQ bits */ +- +- for (i = 0, index = 0; index < 16; index++) { +- if((temp16 >> index) & 0x01) { +- output_struct->data.irq.interrupts[i] = index; +- i++; +- } +- } +- output_struct->data.irq.number_of_interrupts = i; +- +- /* +- * Calculate the structure size based upon the number of interrupts +- */ +- struct_size += (output_struct->data.irq.number_of_interrupts - 1) * 4; +- +- /* +- * Point to Byte 3 if it is used +- */ +- if (4 == *bytes_consumed) { +- buffer += 2; +- temp8 = *buffer; +- +- /* +- * Check for HE, LL or HL +- */ +- if (temp8 & 0x01) { +- output_struct->data.irq.edge_level = EDGE_SENSITIVE; +- output_struct->data.irq.active_high_low = ACTIVE_HIGH; +- } +- +- else { +- if (temp8 & 0x8) { +- output_struct->data.irq.edge_level = LEVEL_SENSITIVE; +- output_struct->data.irq.active_high_low = ACTIVE_LOW; +- } +- +- else { +- /* +- * Only _LL and _HE polarity/trigger interrupts +- * are allowed (ACPI spec v1.0b ection 6.4.2.1), +- * so an error will occur if we reach this point +- */ +- return (AE_BAD_DATA); +- } +- } +- +- /* +- * Check for sharable +- */ +- output_struct->data.irq.shared_exclusive = (temp8 >> 3) & 0x01; +- } +- +- else { +- /* +- * Assume Edge Sensitive, Active High, Non-Sharable +- * per ACPI Specification +- */ +- output_struct->data.irq.edge_level = EDGE_SENSITIVE; +- output_struct->data.irq.active_high_low = ACTIVE_HIGH; +- output_struct->data.irq.shared_exclusive = EXCLUSIVE; +- } +- +- /* +- * Set the Length parameter +- */ +- output_struct->length = struct_size; +- +- /* +- * Return the final size of the structure +- */ +- *structure_size = struct_size; +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_irq_stream +- * +- * PARAMETERS: Linked_list - Pointer to the resource linked list +- * Output_buffer - Pointer to the user's return buffer +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes of the +- * Output_buffer used +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the linked list resource structure and fills in the +- * the appropriate bytes in a byte stream +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_irq_stream ( +- RESOURCE *linked_list, +- u8 **output_buffer, +- u32 *bytes_consumed) +-{ +- u8 *buffer = *output_buffer; +- u16 temp16 = 0; +- u8 temp8 = 0; +- u8 index; +- u8 IRQinfo_byte_needed; +- +- +- /* +- * The descriptor field is set based upon whether a third byte is +- * needed to contain the IRQ Information. +- */ +- if (EDGE_SENSITIVE == linked_list->data.irq.edge_level && +- ACTIVE_HIGH == linked_list->data.irq.active_high_low && +- EXCLUSIVE == linked_list->data.irq.shared_exclusive) +- { +- *buffer = 0x22; +- IRQinfo_byte_needed = FALSE; +- } +- else { +- *buffer = 0x23; +- IRQinfo_byte_needed = TRUE; +- } +- +- buffer += 1; +- temp16 = 0; +- +- /* +- * Loop through all of the interrupts and set the mask bits +- */ +- for(index = 0; +- index < linked_list->data.irq.number_of_interrupts; +- index++) +- { +- temp8 = (u8) linked_list->data.irq.interrupts[index]; +- temp16 |= 0x1 << temp8; +- } +- +- MOVE_UNALIGNED16_TO_16 (buffer, &temp16); +- buffer += 2; +- +- /* +- * Set the IRQ Info byte if needed. +- */ +- if (IRQinfo_byte_needed) { +- temp8 = 0; +- temp8 = (u8) ((linked_list->data.irq.shared_exclusive & +- 0x01) << 4); +- +- if (LEVEL_SENSITIVE == linked_list->data.irq.edge_level && +- ACTIVE_LOW == linked_list->data.irq.active_high_low) +- { +- temp8 |= 0x08; +- } +- +- else { +- temp8 |= 0x01; +- } +- +- *buffer = temp8; +- buffer += 1; +- } +- +- /* +- * Return the number of bytes consumed in this operation +- */ +- *bytes_consumed = (u32) ((NATIVE_UINT) buffer - +- (NATIVE_UINT) *output_buffer); +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_extended_irq_resource +- * +- * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte +- * stream +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes consumed from +- * the Byte_stream_buffer +- * Output_buffer - Pointer to the user's return buffer +- * Structure_size - u32 pointer that is filled with +- * the number of bytes in the filled +- * in structure +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the resource byte stream and fill out the appropriate +- * structure pointed to by the Output_buffer. Return the +- * number of bytes consumed from the byte stream. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_extended_irq_resource ( +- u8 *byte_stream_buffer, +- u32 *bytes_consumed, +- u8 **output_buffer, +- u32 *structure_size) +-{ +- u8 *buffer = byte_stream_buffer; +- RESOURCE *output_struct = (RESOURCE *) * output_buffer; +- u16 temp16 = 0; +- u8 temp8 = 0; +- u8 index; +- u32 struct_size = sizeof (EXTENDED_IRQ_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA; +- +- +- /* +- * Point past the Descriptor to get the number of bytes consumed +- */ +- buffer += 1; +- MOVE_UNALIGNED16_TO_16 (&temp16, buffer); +- +- *bytes_consumed = temp16 + 3; +- output_struct->id = extended_irq; +- +- /* +- * Point to the Byte3 +- */ +- buffer += 2; +- temp8 = *buffer; +- +- output_struct->data.extended_irq.producer_consumer = temp8 & 0x01; +- +- /* +- * Check for HE, LL or HL +- */ +- if(temp8 & 0x02) { +- output_struct->data.extended_irq.edge_level = EDGE_SENSITIVE; +- output_struct->data.extended_irq.active_high_low = ACTIVE_HIGH; +- } +- +- else { +- if(temp8 & 0x4) { +- output_struct->data.extended_irq.edge_level = LEVEL_SENSITIVE; +- output_struct->data.extended_irq.active_high_low = ACTIVE_LOW; +- } +- +- else { +- /* +- * Only _LL and _HE polarity/trigger interrupts +- * are allowed (ACPI spec v1.0b ection 6.4.2.1), +- * so an error will occur if we reach this point +- */ +- return (AE_BAD_DATA); +- } +- } +- +- /* +- * Check for sharable +- */ +- output_struct->data.extended_irq.shared_exclusive = +- (temp8 >> 3) & 0x01; +- +- /* +- * Point to Byte4 (IRQ Table length) +- */ +- buffer += 1; +- temp8 = *buffer; +- +- output_struct->data.extended_irq.number_of_interrupts = temp8; +- +- /* +- * Add any additional structure size to properly calculate +- * the next pointer at the end of this function +- */ +- struct_size += (temp8 - 1) * 4; +- +- /* +- * Point to Byte5 (First IRQ Number) +- */ +- buffer += 1; +- +- /* +- * Cycle through every IRQ in the table +- */ +- for (index = 0; index < temp8; index++) { +- output_struct->data.extended_irq.interrupts[index] = +- (u32)*buffer; +- +- /* Point to the next IRQ */ +- +- buffer += 4; +- } +- +- /* +- * This will leave us pointing to the Resource Source Index +- * If it is present, then save it off and calculate the +- * pointer to where the null terminated string goes: +- * Each Interrupt takes 32-bits + the 5 bytes of the +- * stream that are default. +- */ +- if (*bytes_consumed > +- (u32)(output_struct->data.extended_irq.number_of_interrupts * +- 4) + 5) +- { +- /* Dereference the Index */ +- +- temp8 = *buffer; +- output_struct->data.extended_irq.resource_source_index = +- (u32)temp8; +- +- /* Point to the String */ +- +- buffer += 1; +- +- /* Copy the string into the buffer */ +- +- index = 0; +- +- while (0x00 != *buffer) { +- output_struct->data.extended_irq.resource_source[index] = +- *buffer; +- +- buffer += 1; +- index += 1; +- } +- +- /* +- * Add the terminating null +- */ +- output_struct->data.extended_irq.resource_source[index] = 0x00; +- output_struct->data.extended_irq.resource_source_string_length = +- index + 1; +- +- /* +- * In order for the Struct_size to fall on a 32-bit boundry, +- * calculate the length of the string and expand the +- * Struct_size to the next 32-bit boundry. +- */ +- temp8 = (u8) (index + 1); +- temp8 = (u8) ROUND_UP_TO_32_bITS (temp8); +- } +- +- else { +- output_struct->data.extended_irq.resource_source_index = 0x00; +- output_struct->data.extended_irq.resource_source_string_length = 0; +- output_struct->data.extended_irq.resource_source[0] = 0x00; +- } +- +- /* +- * Set the Length parameter +- */ +- output_struct->length = struct_size; +- +- /* +- * Return the final size of the structure +- */ +- *structure_size = struct_size; +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_extended_irq_stream +- * +- * PARAMETERS: Linked_list - Pointer to the resource linked list +- * Output_buffer - Pointer to the user's return buffer +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes of the +- * Output_buffer used +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the linked list resource structure and fills in the +- * the appropriate bytes in a byte stream +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_extended_irq_stream ( +- RESOURCE *linked_list, +- u8 **output_buffer, +- u32 *bytes_consumed) +-{ +- u8 *buffer = *output_buffer; +- u16 *length_field; +- u8 temp8 = 0; +- u8 index; +- NATIVE_CHAR *temp_pointer = NULL; +- +- +- /* +- * The descriptor field is static +- */ +- *buffer = 0x89; +- buffer += 1; +- +- /* +- * Set a pointer to the Length field - to be filled in later +- */ +- +- length_field = (u16 *)buffer; +- buffer += 2; +- +- /* +- * Set the Interrupt vector flags +- */ +- temp8 = (u8)(linked_list->data.extended_irq.producer_consumer & 0x01); +- +- temp8 |= ((linked_list->data.extended_irq.shared_exclusive & 0x01) << 3); +- +- if (LEVEL_SENSITIVE == linked_list->data.extended_irq.edge_level && +- ACTIVE_LOW == linked_list->data.extended_irq.active_high_low) +- { +- temp8 |= 0x04; +- } +- else { +- temp8 |= 0x02; +- } +- +- *buffer = temp8; +- buffer += 1; +- +- /* +- * Set the Interrupt table length +- */ +- temp8 = (u8) linked_list->data.extended_irq.number_of_interrupts; +- +- *buffer = temp8; +- buffer += 1; +- +- for (index = 0; +- index < linked_list->data.extended_irq.number_of_interrupts; +- index++) +- { +- MOVE_UNALIGNED32_TO_32 (buffer, +- &linked_list->data.extended_irq.interrupts[index]); +- buffer += 4; +- } +- +- /* +- * Resource Source Index and Resource Source are optional +- */ +- if (0 != linked_list->data.extended_irq.resource_source_string_length) { +- *buffer = (u8) linked_list->data.extended_irq.resource_source_index; +- buffer += 1; +- +- temp_pointer = (NATIVE_CHAR *) buffer; +- +- /* +- * Copy the string +- */ +- STRCPY (temp_pointer, linked_list->data.extended_irq.resource_source); +- +- /* +- * Buffer needs to be set to the length of the sting + one for the +- * terminating null +- */ +- buffer += (STRLEN (linked_list->data.extended_irq.resource_source) + 1); +- } +- +- /* +- * Return the number of bytes consumed in this operation +- */ +- *bytes_consumed = (u32) ((NATIVE_UINT) buffer - +- (NATIVE_UINT) *output_buffer); +- +- /* +- * Set the length field to the number of bytes consumed +- * minus the header size (3 bytes) +- */ +- *length_field = (u16) (*bytes_consumed - 3); +- +- return (AE_OK); +-} +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resources/rslist.c linux/drivers/acpi/resources/rslist.c +--- /usr/src/linux/drivers/acpi/resources/rslist.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/resources/rslist.c Wed Dec 31 16:00:00 1969 +@@ -1,504 +0,0 @@ +-/******************************************************************************* +- * +- * Module Name: rslist - Acpi_rs_byte_stream_to_list +- * Acpi_list_to_byte_stream +- * $Revision: 11 $ +- * +- ******************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acresrc.h" +- +-#define _COMPONENT RESOURCE_MANAGER +- MODULE_NAME ("rslist") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_byte_stream_to_list +- * +- * PARAMETERS: Byte_stream_buffer - Pointer to the resource byte stream +- * Byte_stream_buffer_length - Length of Byte_stream_buffer +- * Output_buffer - Pointer to the buffer that will +- * contain the output structures +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Takes the resource byte stream and parses it, creating a +- * linked list of resources in the caller's output buffer +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_byte_stream_to_list ( +- u8 *byte_stream_buffer, +- u32 byte_stream_buffer_length, +- u8 **output_buffer) +-{ +- ACPI_STATUS status; +- u32 bytes_parsed = 0; +- u8 resource_type = 0; +- u32 bytes_consumed = 0; +- u8 **buffer = output_buffer; +- u32 structure_size = 0; +- u8 end_tag_processed = FALSE; +- +- +- while (bytes_parsed < byte_stream_buffer_length && +- FALSE == end_tag_processed) +- { +- /* +- * Look at the next byte in the stream +- */ +- resource_type = *byte_stream_buffer; +- +- /* +- * See if this is a small or large resource +- */ +- if(resource_type & 0x80) { +- /* +- * Large Resource Type +- */ +- switch (resource_type) +- { +- case MEMORY_RANGE_24: +- /* +- * 24-Bit Memory Resource +- */ +- status = acpi_rs_memory24_resource(byte_stream_buffer, +- &bytes_consumed, +- buffer, +- &structure_size); +- +- break; +- +- case LARGE_VENDOR_DEFINED: +- /* +- * Vendor Defined Resource +- */ +- status = acpi_rs_vendor_resource(byte_stream_buffer, +- &bytes_consumed, +- buffer, +- &structure_size); +- +- break; +- +- case MEMORY_RANGE_32: +- /* +- * 32-Bit Memory Range Resource +- */ +- status = acpi_rs_memory32_range_resource(byte_stream_buffer, +- &bytes_consumed, +- buffer, +- &structure_size); +- +- break; +- +- case FIXED_MEMORY_RANGE_32: +- /* +- * 32-Bit Fixed Memory Resource +- */ +- status = acpi_rs_fixed_memory32_resource(byte_stream_buffer, +- &bytes_consumed, +- buffer, +- &structure_size); +- +- break; +- +- case DWORD_ADDRESS_SPACE: +- /* +- * 32-Bit Address Resource +- */ +- status = acpi_rs_address32_resource(byte_stream_buffer, +- &bytes_consumed, +- buffer, +- &structure_size); +- +- break; +- +- case WORD_ADDRESS_SPACE: +- /* +- * 16-Bit Address Resource +- */ +- status = acpi_rs_address16_resource(byte_stream_buffer, +- &bytes_consumed, +- buffer, +- &structure_size); +- +- break; +- +- case EXTENDED_IRQ: +- /* +- * Extended IRQ +- */ +- status = acpi_rs_extended_irq_resource(byte_stream_buffer, +- &bytes_consumed, +- buffer, +- &structure_size); +- +- break; +- +-/* TBD: [Future] 64-bit not currently supported */ +-/* +- case 0x8A: +- break; +-*/ +- +- default: +- /* +- * If we get here, everything is out of sync, +- * so exit with an error +- */ +- return (AE_AML_ERROR); +- break; +- } +- } +- +- else { +- /* +- * Small Resource Type +- * Only bits 7:3 are valid +- */ +- resource_type >>= 3; +- +- switch(resource_type) +- { +- case IRQ_FORMAT: +- /* +- * IRQ Resource +- */ +- status = acpi_rs_irq_resource(byte_stream_buffer, +- &bytes_consumed, +- buffer, +- &structure_size); +- +- break; +- +- case DMA_FORMAT: +- /* +- * DMA Resource +- */ +- status = acpi_rs_dma_resource(byte_stream_buffer, +- &bytes_consumed, +- buffer, +- &structure_size); +- +- break; +- +- case START_DEPENDENT_TAG: +- /* +- * Start Dependent Functions Resource +- */ +- status = acpi_rs_start_dependent_functions_resource(byte_stream_buffer, +- &bytes_consumed, +- buffer, +- &structure_size); +- +- break; +- +- case END_DEPENDENT_TAG: +- /* +- * End Dependent Functions Resource +- */ +- status = acpi_rs_end_dependent_functions_resource(byte_stream_buffer, +- &bytes_consumed, +- buffer, +- &structure_size); +- +- break; +- +- case IO_PORT_DESCRIPTOR: +- /* +- * IO Port Resource +- */ +- status = acpi_rs_io_resource(byte_stream_buffer, +- &bytes_consumed, +- buffer, +- &structure_size); +- +- break; +- +- case FIXED_LOCATION_IO_DESCRIPTOR: +- /* +- * Fixed IO Port Resource +- */ +- status = acpi_rs_fixed_io_resource(byte_stream_buffer, +- &bytes_consumed, +- buffer, +- &structure_size); +- +- break; +- +- case SMALL_VENDOR_DEFINED: +- /* +- * Vendor Specific Resource +- */ +- status = acpi_rs_vendor_resource(byte_stream_buffer, +- &bytes_consumed, +- buffer, +- &structure_size); +- +- break; +- +- case END_TAG: +- /* +- * End Tag +- */ +- status = acpi_rs_end_tag_resource(byte_stream_buffer, +- &bytes_consumed, +- buffer, +- &structure_size); +- end_tag_processed = TRUE; +- +- break; +- +- default: +- /* +- * If we get here, everything is out of sync, +- * so exit with an error +- */ +- return (AE_AML_ERROR); +- break; +- +- } /* switch */ +- } /* end else */ +- +- /* +- * Update the return value and counter +- */ +- bytes_parsed += bytes_consumed; +- +- /* +- * Set the byte stream to point to the next resource +- */ +- byte_stream_buffer += bytes_consumed; +- +- /* +- * Set the Buffer to the next structure +- */ +- *buffer += structure_size; +- +- } /* end while */ +- +- /* +- * Check the reason for exiting the while loop +- */ +- if (TRUE != end_tag_processed) { +- return (AE_AML_ERROR); +- } +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_list_to_byte_stream +- * +- * PARAMETERS: Linked_list - Pointer to the resource linked list +- * Byte_steam_size_needed - Calculated size of the byte stream +- * needed from calling +- * Acpi_rs_calculate_byte_stream_length() +- * The size of the Output_buffer is +- * guaranteed to be >= +- * Byte_stream_size_needed +- * Output_buffer - Pointer to the buffer that will +- * contain the byte stream +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Takes the resource linked list and parses it, creating a +- * byte stream of resources in the caller's output buffer +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_list_to_byte_stream ( +- RESOURCE *linked_list, +- u32 byte_stream_size_needed, +- u8 **output_buffer) +-{ +- ACPI_STATUS status; +- u8 *buffer = *output_buffer; +- u32 bytes_consumed = 0; +- u8 done = FALSE; +- +- +- while (!done) { +- switch (linked_list->id) +- { +- case irq: +- /* +- * IRQ Resource +- */ +- status = acpi_rs_irq_stream (linked_list, +- &buffer, +- &bytes_consumed); +- break; +- +- case dma: +- /* +- * DMA Resource +- */ +- status = acpi_rs_dma_stream (linked_list, +- &buffer, +- &bytes_consumed); +- break; +- +- case start_dependent_functions: +- /* +- * Start Dependent Functions Resource +- */ +- status = acpi_rs_start_dependent_functions_stream (linked_list, +- &buffer, +- &bytes_consumed); +- break; +- +- case end_dependent_functions: +- /* +- * End Dependent Functions Resource +- */ +- status = acpi_rs_end_dependent_functions_stream (linked_list, +- &buffer, +- &bytes_consumed); +- break; +- +- case io: +- /* +- * IO Port Resource +- */ +- status = acpi_rs_io_stream (linked_list, +- &buffer, +- &bytes_consumed); +- break; +- +- case fixed_io: +- /* +- * Fixed IO Port Resource +- */ +- status = acpi_rs_fixed_io_stream (linked_list, +- &buffer, +- &bytes_consumed); +- break; +- +- case vendor_specific: +- /* +- * Vendor Defined Resource +- */ +- status = acpi_rs_vendor_stream (linked_list, +- &buffer, +- &bytes_consumed); +- break; +- +- case end_tag: +- /* +- * End Tag +- */ +- status = acpi_rs_end_tag_stream (linked_list, +- &buffer, +- &bytes_consumed); +- +- /* +- * An End Tag indicates the end of the Resource Template +- */ +- done = TRUE; +- break; +- +- case memory24: +- /* +- * 24-Bit Memory Resource +- */ +- status = acpi_rs_memory24_stream (linked_list, +- &buffer, +- &bytes_consumed); +- break; +- +- case memory32: +- /* +- * 32-Bit Memory Range Resource +- */ +- status = acpi_rs_memory32_range_stream (linked_list, +- &buffer, +- &bytes_consumed); +- break; +- +- case fixed_memory32: +- /* +- * 32-Bit Fixed Memory Resource +- */ +- status = acpi_rs_fixed_memory32_stream (linked_list, +- &buffer, +- &bytes_consumed); +- break; +- +- case address16: +- /* +- * 16-Bit Address Descriptor Resource +- */ +- status = acpi_rs_address16_stream (linked_list, +- &buffer, +- &bytes_consumed); +- break; +- +- case address32: +- /* +- * 32-Bit Address Descriptor Resource +- */ +- status = acpi_rs_address32_stream (linked_list, +- &buffer, +- &bytes_consumed); +- break; +- +- case extended_irq: +- /* +- * Extended IRQ Resource +- */ +- status = acpi_rs_extended_irq_stream (linked_list, +- &buffer, +- &bytes_consumed); +- break; +- +- default: +- /* +- * If we get here, everything is out of sync, +- * so exit with an error +- */ +- return (AE_BAD_DATA); +- break; +- +- } /* switch (Linked_list->Id) */ +- +- /* +- * Set the Buffer to point to the open byte +- */ +- buffer += bytes_consumed; +- +- /* +- * Point to the next object +- */ +- linked_list = (RESOURCE *) ((NATIVE_UINT) linked_list + +- (NATIVE_UINT) linked_list->length); +- } +- +- return (AE_OK); +-} +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resources/rsmemory.c linux/drivers/acpi/resources/rsmemory.c +--- /usr/src/linux/drivers/acpi/resources/rsmemory.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/resources/rsmemory.c Wed Dec 31 16:00:00 1969 +@@ -1,557 +0,0 @@ +-/******************************************************************************* +- * +- * Module Name: rsmem24 - Acpi_rs_memory24_resource +- * Acpi_rs_memory24_stream +- * Acpi_rs_memory32_range_resource +- * Acpi_rs_fixed_memory32_resource +- * Acpi_rs_memory32_range_stream +- * Acpi_rs_fixed_memory32_stream +- * $Revision: 12 $ +- * +- ******************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acresrc.h" +- +-#define _COMPONENT RESOURCE_MANAGER +- MODULE_NAME ("rsmemory") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_memory24_resource +- * +- * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte +- * stream +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes consumed from +- * the Byte_stream_buffer +- * Output_buffer - Pointer to the user's return buffer +- * Structure_size - u32 pointer that is filled with +- * the number of bytes in the filled +- * in structure +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the resource byte stream and fill out the appropriate +- * structure pointed to by the Output_buffer. Return the +- * number of bytes consumed from the byte stream. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_memory24_resource ( +- u8 *byte_stream_buffer, +- u32 *bytes_consumed, +- u8 **output_buffer, +- u32 *structure_size) +-{ +- u8 *buffer = byte_stream_buffer; +- RESOURCE *output_struct = (RESOURCE *) * output_buffer; +- u16 temp16 = 0; +- u8 temp8 = 0; +- u32 struct_size = sizeof (MEMORY24_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA; +- +- +- /* +- * Point past the Descriptor to get the number of bytes consumed +- */ +- buffer += 1; +- +- MOVE_UNALIGNED16_TO_16 (&temp16, buffer); +- buffer += 2; +- *bytes_consumed = temp16 + 3; +- output_struct->id = memory24; +- +- /* +- * Check Byte 3 the Read/Write bit +- */ +- temp8 = *buffer; +- buffer += 1; +- output_struct->data.memory24.read_write_attribute = temp8 & 0x01; +- +- /* +- * Get Min_base_address (Bytes 4-5) +- */ +- MOVE_UNALIGNED16_TO_16 (&temp16, buffer); +- buffer += 2; +- output_struct->data.memory24.min_base_address = temp16; +- +- /* +- * Get Max_base_address (Bytes 6-7) +- */ +- MOVE_UNALIGNED16_TO_16 (&temp16, buffer); +- buffer += 2; +- output_struct->data.memory24.max_base_address = temp16; +- +- /* +- * Get Alignment (Bytes 8-9) +- */ +- MOVE_UNALIGNED16_TO_16 (&temp16, buffer); +- buffer += 2; +- output_struct->data.memory24.alignment = temp16; +- +- /* +- * Get Range_length (Bytes 10-11) +- */ +- MOVE_UNALIGNED16_TO_16 (&temp16, buffer); +- output_struct->data.memory24.range_length = temp16; +- +- /* +- * Set the Length parameter +- */ +- output_struct->length = struct_size; +- +- /* +- * Return the final size of the structure +- */ +- *structure_size = struct_size; +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_memory24_stream +- * +- * PARAMETERS: Linked_list - Pointer to the resource linked list +- * Output_buffer - Pointer to the user's return buffer +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes of the +- * Output_buffer used +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the linked list resource structure and fills in the +- * the appropriate bytes in a byte stream +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_memory24_stream ( +- RESOURCE *linked_list, +- u8 **output_buffer, +- u32 *bytes_consumed) +-{ +- u8 *buffer = *output_buffer; +- u16 temp16 = 0; +- u8 temp8 = 0; +- +- +- /* +- * The descriptor field is static +- */ +- *buffer = 0x81; +- buffer += 1; +- +- /* +- * The length field is static +- */ +- temp16 = 0x09; +- MOVE_UNALIGNED16_TO_16 (buffer, &temp16); +- buffer += 2; +- +- /* +- * Set the Information Byte +- */ +- temp8 = (u8) (linked_list->data.memory24.read_write_attribute & 0x01); +- *buffer = temp8; +- buffer += 1; +- +- /* +- * Set the Range minimum base address +- */ +- MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.memory24.min_base_address); +- buffer += 2; +- +- /* +- * Set the Range maximum base address +- */ +- MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.memory24.max_base_address); +- buffer += 2; +- +- /* +- * Set the base alignment +- */ +- MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.memory24.alignment); +- buffer += 2; +- +- /* +- * Set the range length +- */ +- MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.memory24.range_length); +- buffer += 2; +- +- /* +- * Return the number of bytes consumed in this operation +- */ +- *bytes_consumed = (u32) ((NATIVE_UINT) buffer - +- (NATIVE_UINT) *output_buffer); +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_memory32_range_resource +- * +- * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte +- * stream +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes consumed from +- * the Byte_stream_buffer +- * Output_buffer - Pointer to the user's return buffer +- * Structure_size - u32 pointer that is filled with +- * the number of bytes in the filled +- * in structure +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the resource byte stream and fill out the appropriate +- * structure pointed to by the Output_buffer. Return the +- * number of bytes consumed from the byte stream. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_memory32_range_resource ( +- u8 *byte_stream_buffer, +- u32 *bytes_consumed, +- u8 **output_buffer, +- u32 *structure_size) +-{ +- u8 *buffer = byte_stream_buffer; +- RESOURCE *output_struct = (RESOURCE *) * output_buffer; +- u16 temp16 = 0; +- u8 temp8 = 0; +- u32 struct_size = sizeof (MEMORY32_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA; +- +- +- /* +- * Point past the Descriptor to get the number of bytes consumed +- */ +- buffer += 1; +- +- MOVE_UNALIGNED16_TO_16 (&temp16, buffer); +- buffer += 2; +- *bytes_consumed = temp16 + 3; +- +- output_struct->id = memory32; +- +- /* +- * Point to the place in the output buffer where the data portion will +- * begin. +- * 1. Set the RESOURCE_DATA * Data to point to it's own address, then +- * 2. Set the pointer to the next address. +- * +- * NOTE: Output_struct->Data is cast to u8, otherwise, this addition adds +- * 4 * sizeof(RESOURCE_DATA) instead of 4 * sizeof(u8) +- */ +- +- /* +- * Check Byte 3 the Read/Write bit +- */ +- temp8 = *buffer; +- buffer += 1; +- +- output_struct->data.memory32.read_write_attribute = temp8 & 0x01; +- +- /* +- * Get Min_base_address (Bytes 4-7) +- */ +- MOVE_UNALIGNED32_TO_32 (&output_struct->data.memory32.min_base_address, +- buffer); +- buffer += 4; +- +- /* +- * Get Max_base_address (Bytes 8-11) +- */ +- MOVE_UNALIGNED32_TO_32 (&output_struct->data.memory32.max_base_address, +- buffer); +- buffer += 4; +- +- /* +- * Get Alignment (Bytes 12-15) +- */ +- MOVE_UNALIGNED32_TO_32 (&output_struct->data.memory32.alignment, buffer); +- buffer += 4; +- +- /* +- * Get Range_length (Bytes 16-19) +- */ +- MOVE_UNALIGNED32_TO_32 (&output_struct->data.memory32.range_length, buffer); +- +- /* +- * Set the Length parameter +- */ +- output_struct->length = struct_size; +- +- /* +- * Return the final size of the structure +- */ +- *structure_size = struct_size; +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_fixed_memory32_resource +- * +- * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte +- * stream +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes consumed from +- * the Byte_stream_buffer +- * Output_buffer - Pointer to the user's return buffer +- * Structure_size - u32 pointer that is filled with +- * the number of bytes in the filled +- * in structure +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the resource byte stream and fill out the appropriate +- * structure pointed to by the Output_buffer. Return the +- * number of bytes consumed from the byte stream. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_fixed_memory32_resource ( +- u8 *byte_stream_buffer, +- u32 *bytes_consumed, +- u8 **output_buffer, +- u32 *structure_size) +-{ +- u8 *buffer = byte_stream_buffer; +- RESOURCE *output_struct = (RESOURCE *) * output_buffer; +- u16 temp16 = 0; +- u8 temp8 = 0; +- u32 struct_size = sizeof (FIXED_MEMORY32_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA; +- +- +- /* +- * Point past the Descriptor to get the number of bytes consumed +- */ +- buffer += 1; +- MOVE_UNALIGNED16_TO_16 (&temp16, buffer); +- +- buffer += 2; +- *bytes_consumed = temp16 + 3; +- +- output_struct->id = fixed_memory32; +- +- /* +- * Check Byte 3 the Read/Write bit +- */ +- temp8 = *buffer; +- buffer += 1; +- output_struct->data.fixed_memory32.read_write_attribute = temp8 & 0x01; +- +- /* +- * Get Range_base_address (Bytes 4-7) +- */ +- MOVE_UNALIGNED32_TO_32 (&output_struct->data.fixed_memory32.range_base_address, +- buffer); +- buffer += 4; +- +- /* +- * Get Range_length (Bytes 8-11) +- */ +- MOVE_UNALIGNED32_TO_32 (&output_struct->data.fixed_memory32.range_length, +- buffer); +- +- /* +- * Set the Length parameter +- */ +- output_struct->length = struct_size; +- +- /* +- * Return the final size of the structure +- */ +- *structure_size = struct_size; +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_memory32_range_stream +- * +- * PARAMETERS: Linked_list - Pointer to the resource linked list +- * Output_buffer - Pointer to the user's return buffer +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes of the +- * Output_buffer used +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the linked list resource structure and fills in the +- * the appropriate bytes in a byte stream +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_memory32_range_stream ( +- RESOURCE *linked_list, +- u8 **output_buffer, +- u32 *bytes_consumed) +-{ +- u8 *buffer = *output_buffer; +- u16 temp16 = 0; +- u8 temp8 = 0; +- +- +- /* +- * The descriptor field is static +- */ +- *buffer = 0x85; +- buffer += 1; +- +- /* +- * The length field is static +- */ +- temp16 = 0x11; +- +- MOVE_UNALIGNED16_TO_16 (buffer, &temp16); +- buffer += 2; +- +- /* +- * Set the Information Byte +- */ +- temp8 = (u8) (linked_list->data.memory32.read_write_attribute & 0x01); +- *buffer = temp8; +- buffer += 1; +- +- /* +- * Set the Range minimum base address +- */ +- MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.memory32.min_base_address); +- buffer += 4; +- +- /* +- * Set the Range maximum base address +- */ +- MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.memory32.max_base_address); +- buffer += 4; +- +- /* +- * Set the base alignment +- */ +- MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.memory32.alignment); +- buffer += 4; +- +- /* +- * Set the range length +- */ +- MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.memory32.range_length); +- buffer += 4; +- +- /* +- * Return the number of bytes consumed in this operation +- */ +- *bytes_consumed = (u32) ((NATIVE_UINT) buffer - +- (NATIVE_UINT) *output_buffer); +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_fixed_memory32_stream +- * +- * PARAMETERS: Linked_list - Pointer to the resource linked list +- * Output_buffer - Pointer to the user's return buffer +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes of the +- * Output_buffer used +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the linked list resource structure and fills in the +- * the appropriate bytes in a byte stream +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_fixed_memory32_stream ( +- RESOURCE *linked_list, +- u8 **output_buffer, +- u32 *bytes_consumed) +-{ +- u8 *buffer = *output_buffer; +- u16 temp16 = 0; +- u8 temp8 = 0; +- +- +- /* +- * The descriptor field is static +- */ +- *buffer = 0x86; +- buffer += 1; +- +- /* +- * The length field is static +- */ +- temp16 = 0x09; +- +- MOVE_UNALIGNED16_TO_16 (buffer, &temp16); +- buffer += 2; +- +- /* +- * Set the Information Byte +- */ +- temp8 = (u8) (linked_list->data.fixed_memory32.read_write_attribute & 0x01); +- *buffer = temp8; +- buffer += 1; +- +- /* +- * Set the Range base address +- */ +- MOVE_UNALIGNED32_TO_32 (buffer, +- &linked_list->data.fixed_memory32.range_base_address); +- buffer += 4; +- +- /* +- * Set the range length +- */ +- MOVE_UNALIGNED32_TO_32 (buffer, +- &linked_list->data.fixed_memory32.range_length); +- buffer += 4; +- +- /* +- * Return the number of bytes consumed in this operation +- */ +- *bytes_consumed = (u32) ((NATIVE_UINT) buffer - +- (NATIVE_UINT) *output_buffer); +- +- return (AE_OK); +-} +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resources/rsmisc.c linux/drivers/acpi/resources/rsmisc.c +--- /usr/src/linux/drivers/acpi/resources/rsmisc.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/resources/rsmisc.c Wed Dec 31 16:00:00 1969 +@@ -1,607 +0,0 @@ +-/******************************************************************************* +- * +- * Module Name: rsmisc - Acpi_rs_end_tag_resource +- * Acpi_rs_end_tag_stream +- * Acpi_rs_vendor_resource +- * Acpi_rs_vendor_stream +- * Acpi_rs_start_dependent_functions_resource +- * Acpi_rs_end_dependent_functions_resource +- * Acpi_rs_start_dependent_functions_stream +- * Acpi_rs_end_dependent_functions_stream +- * $Revision: 12 $ +- * +- ******************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acresrc.h" +- +-#define _COMPONENT RESOURCE_MANAGER +- MODULE_NAME ("rsmisc") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_end_tag_resource +- * +- * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte +- * stream +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes consumed from +- * the Byte_stream_buffer +- * Output_buffer - Pointer to the user's return buffer +- * Structure_size - u32 pointer that is filled with +- * the number of bytes in the filled +- * in structure +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the resource byte stream and fill out the appropriate +- * structure pointed to by the Output_buffer. Return the +- * number of bytes consumed from the byte stream. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_end_tag_resource ( +- u8 *byte_stream_buffer, +- u32 *bytes_consumed, +- u8 **output_buffer, +- u32 *structure_size) +-{ +- RESOURCE *output_struct = (RESOURCE *) * output_buffer; +- u32 struct_size = RESOURCE_LENGTH; +- +- +- /* +- * The number of bytes consumed is static +- */ +- *bytes_consumed = 2; +- +- /* +- * Fill out the structure +- */ +- output_struct->id = end_tag; +- +- /* +- * Set the Length parameter +- */ +- output_struct->length = 0; +- +- /* +- * Return the final size of the structure +- */ +- *structure_size = struct_size; +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_end_tag_stream +- * +- * PARAMETERS: Linked_list - Pointer to the resource linked list +- * Output_buffer - Pointer to the user's return buffer +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes of the +- * Output_buffer used +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the linked list resource structure and fills in the +- * the appropriate bytes in a byte stream +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_end_tag_stream ( +- RESOURCE *linked_list, +- u8 **output_buffer, +- u32 *bytes_consumed) +-{ +- u8 *buffer = *output_buffer; +- u8 temp8 = 0; +- +- +- /* +- * The descriptor field is static +- */ +- *buffer = 0x79; +- buffer += 1; +- +- /* +- * Set the Checksum - zero means that the resource data is treated as if +- * the checksum operation succeeded (ACPI Spec 1.0b Section 6.4.2.8) +- */ +- temp8 = 0; +- +- *buffer = temp8; +- buffer += 1; +- +- /* +- * Return the number of bytes consumed in this operation +- */ +- *bytes_consumed = (u32) ((NATIVE_UINT) buffer - +- (NATIVE_UINT) *output_buffer); +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_vendor_resource +- * +- * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte +- * stream +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes consumed from +- * the Byte_stream_buffer +- * Output_buffer - Pointer to the user's return buffer +- * Structure_size - u32 pointer that is filled with +- * the number of bytes in the filled +- * in structure +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the resource byte stream and fill out the appropriate +- * structure pointed to by the Output_buffer. Return the +- * number of bytes consumed from the byte stream. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_vendor_resource ( +- u8 *byte_stream_buffer, +- u32 *bytes_consumed, +- u8 **output_buffer, +- u32 *structure_size) +-{ +- u8 *buffer = byte_stream_buffer; +- RESOURCE *output_struct = (RESOURCE *) * output_buffer; +- u16 temp16 = 0; +- u8 temp8 = 0; +- u8 index; +- u32 struct_size = sizeof (VENDOR_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA; +- +- +- /* +- * Dereference the Descriptor to find if this is a large or small item. +- */ +- temp8 = *buffer; +- +- if (temp8 & 0x80) { +- /* +- * Large Item +- */ +- /* Point to the length field */ +- +- buffer += 1; +- +- /* Dereference */ +- +- MOVE_UNALIGNED16_TO_16 (&temp16, buffer); +- +- /* Calculate bytes consumed */ +- +- *bytes_consumed = temp16 + 3; +- +- /* Point to the first vendor byte */ +- +- buffer += 2; +- } +- +- else { +- /* +- * Small Item +- */ +- +- /* Dereference the size */ +- +- temp16 = (u8)(*buffer & 0x07); +- +- /* Calculate bytes consumed */ +- +- *bytes_consumed = temp16 + 1; +- +- /* Point to the first vendor byte */ +- +- buffer += 1; +- } +- +- output_struct->id = vendor_specific; +- output_struct->data.vendor_specific.length = temp16; +- +- for (index = 0; index < temp16; index++) { +- output_struct->data.vendor_specific.reserved[index] = *buffer; +- buffer += 1; +- } +- +- /* +- * In order for the Struct_size to fall on a 32-bit boundry, +- * calculate the length of the vendor string and expand the +- * Struct_size to the next 32-bit boundry. +- */ +- struct_size += ROUND_UP_TO_32_bITS (temp16); +- +- /* +- * Set the Length parameter +- */ +- output_struct->length = struct_size; +- +- /* +- * Return the final size of the structure +- */ +- *structure_size = struct_size; +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_vendor_stream +- * +- * PARAMETERS: Linked_list - Pointer to the resource linked list +- * Output_buffer - Pointer to the user's return buffer +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes of the +- * Output_buffer used +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the linked list resource structure and fills in the +- * the appropriate bytes in a byte stream +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_vendor_stream ( +- RESOURCE *linked_list, +- u8 **output_buffer, +- u32 *bytes_consumed) +-{ +- u8 *buffer = *output_buffer; +- u16 temp16 = 0; +- u8 temp8 = 0; +- u8 index; +- +- +- /* +- * Dereference the length to find if this is a large or small item. +- */ +- +- if(linked_list->data.vendor_specific.length > 7) { +- /* +- * Large Item +- */ +- /* +- * Set the descriptor field and length bytes +- */ +- *buffer = 0x84; +- buffer += 1; +- +- temp16 = (u16) linked_list->data.vendor_specific.length; +- +- MOVE_UNALIGNED16_TO_16 (buffer, &temp16); +- buffer += 2; +- } +- +- else { +- /* +- * Small Item +- */ +- +- /* +- * Set the descriptor field +- */ +- temp8 = 0x70; +- temp8 |= linked_list->data.vendor_specific.length; +- +- *buffer = temp8; +- buffer += 1; +- } +- +- /* +- * Loop through all of the Vendor Specific fields +- */ +- for (index = 0; index < linked_list->data.vendor_specific.length; index++) { +- temp8 = linked_list->data.vendor_specific.reserved[index]; +- +- *buffer = temp8; +- buffer += 1; +- } +- +- /* +- * Return the number of bytes consumed in this operation +- */ +- *bytes_consumed = (u32) ((NATIVE_UINT) buffer - +- (NATIVE_UINT) *output_buffer); +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_start_dependent_functions_resource +- * +- * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte +- * stream +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes consumed from +- * the Byte_stream_buffer +- * Output_buffer - Pointer to the user's return buffer +- * Structure_size - u32 pointer that is filled with +- * the number of bytes in the filled +- * in structure +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the resource byte stream and fill out the appropriate +- * structure pointed to by the Output_buffer. Return the +- * number of bytes consumed from the byte stream. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_start_dependent_functions_resource ( +- u8 *byte_stream_buffer, +- u32 *bytes_consumed, +- u8 **output_buffer, +- u32 *structure_size) +-{ +- u8 *buffer = byte_stream_buffer; +- RESOURCE *output_struct = (RESOURCE *) * output_buffer; +- u8 temp8 = 0; +- u32 struct_size = +- sizeof(START_DEPENDENT_FUNCTIONS_RESOURCE) + +- RESOURCE_LENGTH_NO_DATA; +- +- +- /* +- * The number of bytes consumed are contained in the descriptor (Bits:0-1) +- */ +- temp8 = *buffer; +- +- *bytes_consumed = (temp8 & 0x01) + 1; +- +- output_struct->id = start_dependent_functions; +- +- /* +- * Point to Byte 1 if it is used +- */ +- if (2 == *bytes_consumed) { +- buffer += 1; +- temp8 = *buffer; +- +- /* +- * Check Compatibility priority +- */ +- output_struct->data.start_dependent_functions.compatibility_priority = +- temp8 & 0x03; +- +- if (3 == output_struct->data.start_dependent_functions.compatibility_priority) { +- return (AE_AML_ERROR); +- } +- +- /* +- * Check Performance/Robustness preference +- */ +- output_struct->data.start_dependent_functions.performance_robustness = +- (temp8 >> 2) & 0x03; +- +- if (3 == output_struct->data.start_dependent_functions.performance_robustness) { +- return (AE_AML_ERROR); +- } +- } +- +- else { +- output_struct->data.start_dependent_functions.compatibility_priority = +- ACCEPTABLE_CONFIGURATION; +- +- output_struct->data.start_dependent_functions.performance_robustness = +- ACCEPTABLE_CONFIGURATION; +- } +- +- /* +- * Set the Length parameter +- */ +- output_struct->length = struct_size; +- +- /* +- * Return the final size of the structure +- */ +- *structure_size = struct_size; +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_end_dependent_functions_resource +- * +- * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte +- * stream +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes consumed from +- * the Byte_stream_buffer +- * Output_buffer - Pointer to the user's return buffer +- * Structure_size - u32 pointer that is filled with +- * the number of bytes in the filled +- * in structure +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the resource byte stream and fill out the appropriate +- * structure pointed to by the Output_buffer. Return the +- * number of bytes consumed from the byte stream. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_end_dependent_functions_resource ( +- u8 *byte_stream_buffer, +- u32 *bytes_consumed, +- u8 **output_buffer, +- u32 *structure_size) +-{ +- RESOURCE *output_struct = (RESOURCE *) * output_buffer; +- u32 struct_size = RESOURCE_LENGTH; +- +- +- /* +- * The number of bytes consumed is static +- */ +- *bytes_consumed = 1; +- +- /* +- * Fill out the structure +- */ +- output_struct->id = end_dependent_functions; +- +- /* +- * Set the Length parameter +- */ +- output_struct->length = struct_size; +- +- /* +- * Return the final size of the structure +- */ +- *structure_size = struct_size; +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_start_dependent_functions_stream +- * +- * PARAMETERS: Linked_list - Pointer to the resource linked list +- * Output_buffer - Pointer to the user's return buffer +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes of the +- * Output_buffer used +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the linked list resource structure and fills in the +- * the appropriate bytes in a byte stream +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_start_dependent_functions_stream ( +- RESOURCE *linked_list, +- u8 **output_buffer, +- u32 *bytes_consumed) +-{ +- u8 *buffer = *output_buffer; +- u8 temp8 = 0; +- +- +- /* +- * The descriptor field is set based upon whether a byte is needed +- * to contain Priority data. +- */ +- if (ACCEPTABLE_CONFIGURATION == +- linked_list->data.start_dependent_functions.compatibility_priority && +- ACCEPTABLE_CONFIGURATION == +- linked_list->data.start_dependent_functions.performance_robustness) +- { +- *buffer = 0x30; +- } +- else { +- *buffer = 0x31; +- buffer += 1; +- +- /* +- * Set the Priority Byte Definition +- */ +- temp8 = 0; +- temp8 = (u8) +- ((linked_list->data.start_dependent_functions.performance_robustness & +- 0x03) << 2); +- temp8 |= +- (linked_list->data.start_dependent_functions.compatibility_priority & +- 0x03); +- +- *buffer = temp8; +- } +- +- buffer += 1; +- +- /* +- * Return the number of bytes consumed in this operation +- */ +- *bytes_consumed = (u32) ((NATIVE_UINT) buffer - +- (NATIVE_UINT) *output_buffer); +- +- return (AE_OK); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_end_dependent_functions_stream +- * +- * PARAMETERS: Linked_list - Pointer to the resource linked list +- * Output_buffer - Pointer to the user's return buffer +- * Bytes_consumed - u32 pointer that is filled with +- * the number of bytes of the +- * Output_buffer used +- * +- * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code +- * +- * DESCRIPTION: Take the linked list resource structure and fills in the +- * the appropriate bytes in a byte stream +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_end_dependent_functions_stream ( +- RESOURCE *linked_list, +- u8 **output_buffer, +- u32 *bytes_consumed +- ) +-{ +- u8 *buffer = *output_buffer; +- +- +- /* +- * The descriptor field is static +- */ +- *buffer = 0x38; +- buffer += 1; +- +- /* +- * Return the number of bytes consumed in this operation +- */ +- *bytes_consumed = (u32) ((NATIVE_UINT) buffer - +- (NATIVE_UINT) *output_buffer); +- +- return (AE_OK); +-} +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resources/rsutils.c linux/drivers/acpi/resources/rsutils.c +--- /usr/src/linux/drivers/acpi/resources/rsutils.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/resources/rsutils.c Wed Dec 31 16:00:00 1969 +@@ -1,387 +0,0 @@ +-/******************************************************************************* +- * +- * Module Name: rsutils - Utilities for the resource manager +- * $Revision: 14 $ +- * +- ******************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acnamesp.h" +-#include "acresrc.h" +- +- +-#define _COMPONENT RESOURCE_MANAGER +- MODULE_NAME ("rsutils") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_get_prt_method_data +- * +- * PARAMETERS: Handle - a handle to the containing object +- * Ret_buffer - a pointer to a buffer structure for the +- * results +- * +- * RETURN: Status - the status of the call +- * +- * DESCRIPTION: This function is called to get the _PRT value of an object +- * contained in an object specified by the handle passed in +- * +- * If the function fails an appropriate status will be returned +- * and the contents of the callers buffer is undefined. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_get_prt_method_data ( +- ACPI_HANDLE handle, +- ACPI_BUFFER *ret_buffer) +-{ +- ACPI_OPERAND_OBJECT *ret_obj; +- ACPI_STATUS status; +- u32 buffer_space_needed; +- +- +- /* already validated params, so we won't repeat here */ +- +- buffer_space_needed = ret_buffer->length; +- +- /* +- * Execute the method, no parameters +- */ +- status = acpi_ns_evaluate_relative (handle, "_PRT", NULL, &ret_obj); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- if (!ret_obj) { +- /* Return object is required */ +- +- return (AE_TYPE); +- } +- +- +- /* +- * The return object will be a package, so check the +- * parameters. If the return object is not a package, +- * then the underlying AML code is corrupt or improperly +- * written. +- */ +- if (ACPI_TYPE_PACKAGE != ret_obj->common.type) { +- status = AE_AML_OPERAND_TYPE; +- goto cleanup; +- } +- +- /* +- * Make the call to create a resource linked list from the +- * byte stream buffer that comes back from the _CRS method +- * execution. +- */ +- status = acpi_rs_create_pci_routing_table (ret_obj, +- ret_buffer->pointer, +- &buffer_space_needed); +- +- /* +- * Tell the user how much of the buffer we have used or is needed +- * and return the final status. +- */ +- ret_buffer->length = buffer_space_needed; +- +- +- /* On exit, we must delete the object returned by evaluate_object */ +- +-cleanup: +- +- acpi_cm_remove_reference (ret_obj); +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_get_crs_method_data +- * +- * PARAMETERS: Handle - a handle to the containing object +- * Ret_buffer - a pointer to a buffer structure for the +- * results +- * +- * RETURN: Status - the status of the call +- * +- * DESCRIPTION: This function is called to get the _CRS value of an object +- * contained in an object specified by the handle passed in +- * +- * If the function fails an appropriate status will be returned +- * and the contents of the callers buffer is undefined. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_get_crs_method_data ( +- ACPI_HANDLE handle, +- ACPI_BUFFER *ret_buffer) +-{ +- ACPI_OPERAND_OBJECT *ret_obj; +- ACPI_STATUS status; +- u32 buffer_space_needed = ret_buffer->length; +- +- +- /* already validated params, so we won't repeat here */ +- +- /* +- * Execute the method, no parameters +- */ +- status = acpi_ns_evaluate_relative (handle, "_CRS", NULL, &ret_obj); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- if (!ret_obj) { +- /* Return object is required */ +- +- return (AE_TYPE); +- } +- +- /* +- * The return object will be a buffer, but check the +- * parameters. If the return object is not a buffer, +- * then the underlying AML code is corrupt or improperly +- * written. +- */ +- if (ACPI_TYPE_BUFFER != ret_obj->common.type) { +- status = AE_AML_OPERAND_TYPE; +- goto cleanup; +- } +- +- /* +- * Make the call to create a resource linked list from the +- * byte stream buffer that comes back from the _CRS method +- * execution. +- */ +- status = acpi_rs_create_resource_list (ret_obj, +- ret_buffer->pointer, +- &buffer_space_needed); +- +- +- +- /* +- * Tell the user how much of the buffer we have used or is needed +- * and return the final status. +- */ +- ret_buffer->length = buffer_space_needed; +- +- +- /* On exit, we must delete the object returned by evaluate_object */ +- +-cleanup: +- +- acpi_cm_remove_reference (ret_obj); +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_get_prs_method_data +- * +- * PARAMETERS: Handle - a handle to the containing object +- * Ret_buffer - a pointer to a buffer structure for the +- * results +- * +- * RETURN: Status - the status of the call +- * +- * DESCRIPTION: This function is called to get the _PRS value of an object +- * contained in an object specified by the handle passed in +- * +- * If the function fails an appropriate status will be returned +- * and the contents of the callers buffer is undefined. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_get_prs_method_data ( +- ACPI_HANDLE handle, +- ACPI_BUFFER *ret_buffer) +-{ +- ACPI_OPERAND_OBJECT *ret_obj; +- ACPI_STATUS status; +- u32 buffer_space_needed = ret_buffer->length; +- +- +- /* already validated params, so we won't repeat here */ +- +- /* +- * Execute the method, no parameters +- */ +- status = acpi_ns_evaluate_relative (handle, "_PRS", NULL, &ret_obj); +- if (ACPI_FAILURE (status)) { +- return (status); +- } +- +- if (!ret_obj) { +- /* Return object is required */ +- +- return (AE_TYPE); +- } +- +- /* +- * The return object will be a buffer, but check the +- * parameters. If the return object is not a buffer, +- * then the underlying AML code is corrupt or improperly +- * written.. +- */ +- if (ACPI_TYPE_BUFFER != ret_obj->common.type) { +- status = AE_AML_OPERAND_TYPE; +- goto cleanup; +- } +- +- /* +- * Make the call to create a resource linked list from the +- * byte stream buffer that comes back from the _CRS method +- * execution. +- */ +- status = acpi_rs_create_resource_list (ret_obj, +- ret_buffer->pointer, +- &buffer_space_needed); +- +- /* +- * Tell the user how much of the buffer we have used or is needed +- * and return the final status. +- */ +- ret_buffer->length = buffer_space_needed; +- +- +- /* On exit, we must delete the object returned by evaluate_object */ +- +-cleanup: +- +- acpi_cm_remove_reference (ret_obj); +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_rs_set_srs_method_data +- * +- * PARAMETERS: Handle - a handle to the containing object +- * In_buffer - a pointer to a buffer structure of the +- * parameter +- * +- * RETURN: Status - the status of the call +- * +- * DESCRIPTION: This function is called to set the _SRS of an object contained +- * in an object specified by the handle passed in +- * +- * If the function fails an appropriate status will be returned +- * and the contents of the callers buffer is undefined. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_rs_set_srs_method_data ( +- ACPI_HANDLE handle, +- ACPI_BUFFER *in_buffer) +-{ +- ACPI_OPERAND_OBJECT *params[2]; +- ACPI_OPERAND_OBJECT param_obj; +- ACPI_STATUS status; +- u8 *byte_stream = NULL; +- u32 buffer_size_needed = 0; +- +- +- /* already validated params, so we won't repeat here */ +- +- /* +- * The In_buffer parameter will point to a linked list of +- * resource parameters. It needs to be formatted into a +- * byte stream to be sent in as an input parameter. +- */ +- buffer_size_needed = 0; +- +- /* +- * First call is to get the buffer size needed +- */ +- status = acpi_rs_create_byte_stream (in_buffer->pointer, +- byte_stream, +- &buffer_size_needed); +- /* +- * We expect a return of AE_BUFFER_OVERFLOW +- * if not, exit with the error +- */ +- if (AE_BUFFER_OVERFLOW != status) { +- return (status); +- } +- +- /* +- * Allocate the buffer needed +- */ +- byte_stream = acpi_cm_callocate(buffer_size_needed); +- if (NULL == byte_stream) { +- return (AE_NO_MEMORY); +- } +- +- /* +- * Now call to convert the linked list into a byte stream +- */ +- status = acpi_rs_create_byte_stream (in_buffer->pointer, +- byte_stream, +- &buffer_size_needed); +- if (ACPI_FAILURE (status)) { +- goto cleanup; +- } +- +- /* +- * Init the param object +- */ +- acpi_cm_init_static_object (¶m_obj); +- +- /* +- * Method requires one parameter. Set it up +- */ +- params [0] = ¶m_obj; +- params [1] = NULL; +- +- /* +- * Set up the parameter object +- */ +- param_obj.common.type = ACPI_TYPE_BUFFER; +- param_obj.buffer.length = buffer_size_needed; +- param_obj.buffer.pointer = byte_stream; +- +- /* +- * Execute the method, no return value +- */ +- status = acpi_ns_evaluate_relative (handle, "_SRS", params, NULL); +- +- /* +- * Clean up and return the status from Acpi_ns_evaluate_relative +- */ +- +-cleanup: +- +- acpi_cm_free (byte_stream); +- return (status); +-} +- +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/resources/rsxface.c linux/drivers/acpi/resources/rsxface.c +--- /usr/src/linux/drivers/acpi/resources/rsxface.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/resources/rsxface.c Wed Dec 31 16:00:00 1969 +@@ -1,225 +0,0 @@ +-/******************************************************************************* +- * +- * Module Name: rsxface - Public interfaces to the ACPI subsystem +- * $Revision: 10 $ +- * +- ******************************************************************************/ +- +-/* +- * Copyright (C) 2000, 2001 R. Byron Moore +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +- +-#include "acpi.h" +-#include "acinterp.h" +-#include "acnamesp.h" +-#include "acresrc.h" +- +-#define _COMPONENT RESOURCE_MANAGER +- MODULE_NAME ("rsxface") +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_get_irq_routing_table +- * +- * PARAMETERS: Device_handle - a handle to the Bus device we are querying +- * Ret_buffer - a pointer to a buffer to receive the +- * current resources for the device +- * +- * RETURN: Status - the status of the call +- * +- * DESCRIPTION: This function is called to get the IRQ routing table for a +- * specific bus. The caller must first acquire a handle for the +- * desired bus. The routine table is placed in the buffer pointed +- * to by the Ret_buffer variable parameter. +- * +- * If the function fails an appropriate status will be returned +- * and the value of Ret_buffer is undefined. +- * +- * This function attempts to execute the _PRT method contained in +- * the object indicated by the passed Device_handle. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_get_irq_routing_table ( +- ACPI_HANDLE device_handle, +- ACPI_BUFFER *ret_buffer) +-{ +- ACPI_STATUS status; +- +- +- /* +- * Must have a valid handle and buffer, So we have to have a handle +- * and a return buffer structure, and if there is a non-zero buffer length +- * we also need a valid pointer in the buffer. If it's a zero buffer length, +- * we'll be returning the needed buffer size, so keep going. +- */ +- if ((!device_handle) || +- (!ret_buffer) || +- ((!ret_buffer->pointer) && (ret_buffer->length))) +- { +- return (AE_BAD_PARAMETER); +- } +- +- status = acpi_rs_get_prt_method_data (device_handle, ret_buffer); +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_get_current_resources +- * +- * PARAMETERS: Device_handle - a handle to the device object for the +- * device we are querying +- * Ret_buffer - a pointer to a buffer to receive the +- * current resources for the device +- * +- * RETURN: Status - the status of the call +- * +- * DESCRIPTION: This function is called to get the current resources for a +- * specific device. The caller must first acquire a handle for +- * the desired device. The resource data is placed in the buffer +- * pointed to by the Ret_buffer variable parameter. +- * +- * If the function fails an appropriate status will be returned +- * and the value of Ret_buffer is undefined. +- * +- * This function attempts to execute the _CRS method contained in +- * the object indicated by the passed Device_handle. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_get_current_resources ( +- ACPI_HANDLE device_handle, +- ACPI_BUFFER *ret_buffer) +-{ +- ACPI_STATUS status; +- +- +- /* +- * Must have a valid handle and buffer, So we have to have a handle +- * and a return buffer structure, and if there is a non-zero buffer length +- * we also need a valid pointer in the buffer. If it's a zero buffer length, +- * we'll be returning the needed buffer size, so keep going. +- */ +- if ((!device_handle) || +- (!ret_buffer) || +- ((ret_buffer->length) && (!ret_buffer->pointer))) +- { +- return (AE_BAD_PARAMETER); +- } +- +- status = acpi_rs_get_crs_method_data (device_handle, ret_buffer); +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_get_possible_resources +- * +- * PARAMETERS: Device_handle - a handle to the device object for the +- * device we are querying +- * Ret_buffer - a pointer to a buffer to receive the +- * resources for the device +- * +- * RETURN: Status - the status of the call +- * +- * DESCRIPTION: This function is called to get a list of the possible resources +- * for a specific device. The caller must first acquire a handle +- * for the desired device. The resource data is placed in the +- * buffer pointed to by the Ret_buffer variable. +- * +- * If the function fails an appropriate status will be returned +- * and the value of Ret_buffer is undefined. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_get_possible_resources ( +- ACPI_HANDLE device_handle, +- ACPI_BUFFER *ret_buffer) +-{ +- ACPI_STATUS status; +- +- +- /* +- * Must have a valid handle and buffer, So we have to have a handle +- * and a return buffer structure, and if there is a non-zero buffer length +- * we also need a valid pointer in the buffer. If it's a zero buffer length, +- * we'll be returning the needed buffer size, so keep going. +- */ +- if ((!device_handle) || +- (!ret_buffer) || +- ((ret_buffer->length) && (!ret_buffer->pointer))) +- { +- return (AE_BAD_PARAMETER); +- } +- +- status = acpi_rs_get_prs_method_data (device_handle, ret_buffer); +- +- return (status); +-} +- +- +-/******************************************************************************* +- * +- * FUNCTION: Acpi_set_current_resources +- * +- * PARAMETERS: Device_handle - a handle to the device object for the +- * device we are changing the resources of +- * In_buffer - a pointer to a buffer containing the +- * resources to be set for the device +- * +- * RETURN: Status - the status of the call +- * +- * DESCRIPTION: This function is called to set the current resources for a +- * specific device. The caller must first acquire a handle for +- * the desired device. The resource data is passed to the routine +- * the buffer pointed to by the In_buffer variable. +- * +- ******************************************************************************/ +- +-ACPI_STATUS +-acpi_set_current_resources ( +- ACPI_HANDLE device_handle, +- ACPI_BUFFER *in_buffer) +-{ +- ACPI_STATUS status; +- +- +- /* +- * Must have a valid handle and buffer +- */ +- if ((!device_handle) || +- (!in_buffer) || +- (!in_buffer->pointer) || +- (!in_buffer->length)) +- { +- return (AE_BAD_PARAMETER); +- } +- +- status = acpi_rs_set_srs_method_data (device_handle, in_buffer); +- +- return (status); +-} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/sys.c linux/drivers/acpi/sys.c +--- /usr/src/linux/drivers/acpi/sys.c Mon Jan 29 10:15:59 2001 ++++ linux/drivers/acpi/sys.c Wed Dec 31 16:00:00 1969 +@@ -1,146 +0,0 @@ +-/* +- * sys.c - System management (suspend, ...) +- * +- * Copyright (C) 2000 Andrew Henroid +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +-#include <linux/kernel.h> +-#include <linux/pm.h> +-#include <linux/acpi.h> +-#include "acpi.h" +-#include "driver.h" +- +-#define _COMPONENT OS_DEPENDENT +- MODULE_NAME ("sys") +- +-struct acpi_enter_sx_ctx +-{ +- wait_queue_head_t wait; +- unsigned int state; +-}; +- +-volatile acpi_sstate_t acpi_sleep_state = ACPI_STATE_S0; +- +-/* +- * Enter system sleep state +- */ +-static void +-acpi_enter_sx_async(void *context) +-{ +- struct acpi_enter_sx_ctx *ctx = (struct acpi_enter_sx_ctx*) context; +- ACPI_OBJECT_LIST arg_list; +- ACPI_OBJECT arg; +- +- acpi_enter_sleep_state(ctx->state); +- +- /* either we are in S1, or the transition failed, as the other states resume +- from the waking vector */ +- if (ctx->state != ACPI_STATE_S1) { +- printk(KERN_ERR "Could not enter S%d\n", ctx->state); +- goto out; +- } +- +- /* wait until S1 is entered */ +- while (!(acpi_hw_register_bit_access(ACPI_READ, ACPI_MTX_LOCK, WAK_STS))) +- safe_halt(); +- +- /* run the _WAK method */ +- memset(&arg_list, 0, sizeof(arg_list)); +- arg_list.count = 1; +- arg_list.pointer = &arg; +- +- memset(&arg, 0, sizeof(arg)); +- arg.type = ACPI_TYPE_INTEGER; +- arg.integer.value = ctx->state; +- +- acpi_evaluate_object(NULL, "\\_WAK", &arg_list, NULL); +- +- out: +- acpi_sleep_state = ACPI_STATE_S0; +- +- if (waitqueue_active(&ctx->wait)) +- wake_up_interruptible(&ctx->wait); +-} +- +-/* +- * Enter soft-off (S5) +- */ +-static void +-acpi_power_off(void) +-{ +- struct acpi_enter_sx_ctx ctx; +- +- init_waitqueue_head(&ctx.wait); +- ctx.state = ACPI_STATE_S5; +- acpi_enter_sx_async(&ctx); +-} +- +-/* +- * Enter system sleep state and wait for completion +- */ +-int +-acpi_enter_sx(acpi_sstate_t state) +-{ +- struct acpi_enter_sx_ctx ctx; +- DECLARE_WAITQUEUE(wait, current); +- int ret = 0; +- +- init_waitqueue_head(&ctx.wait); +- ctx.state = state; +- +- set_current_state(TASK_INTERRUPTIBLE); +- add_wait_queue(&ctx.wait, &wait); +- +- if (acpi_os_queue_for_execution(0, acpi_enter_sx_async, &ctx)) +- ret = -1; +- +- if (!ret) +- schedule(); +- +- set_current_state(TASK_RUNNING); +- remove_wait_queue(&ctx.wait, &wait); +- +- if (!ret && signal_pending(current)) +- ret = -ERESTARTSYS; +- +- return ret; +-} +- +-int +-acpi_sys_init(void) +-{ +- u8 sx; +- u8 type_a; +- u8 type_b; +- +- printk(KERN_INFO "ACPI: System firmware supports:"); +- +- for (sx = ACPI_STATE_S0; sx <= ACPI_STATE_S5; sx++) { +- if (ACPI_SUCCESS( +- acpi_hw_obtain_sleep_type_register_data(sx, +- &type_a, +- &type_b))) { +- +- printk(" S%d", sx); +- } +- } +- printk("\n"); +- +- pm_power_off = acpi_power_off; +- +- return 0; +-} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/table.c linux/drivers/acpi/table.c +--- /usr/src/linux/drivers/acpi/table.c Mon Jan 29 10:15:59 2001 ++++ linux/drivers/acpi/table.c Wed Dec 31 16:00:00 1969 +@@ -1,71 +0,0 @@ +-/* +- * table.c - ACPI tables, chipset, and errata handling +- * +- * Copyright (C) 2000 Andrew Henroid +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +-#include <linux/kernel.h> +-#include <linux/types.h> +-#include <linux/pci.h> +-#include <linux/pm.h> +-#include <linux/acpi.h> +-#include "acpi.h" +-#include "driver.h" +- +-#define _COMPONENT OS_DEPENDENT +- MODULE_NAME ("table") +- +-FADT_DESCRIPTOR acpi_fadt; +- +-/* +- * Fetch the fadt information +- */ +-static int +-acpi_fetch_fadt(void) +-{ +- ACPI_BUFFER buffer; +- +- memset(&acpi_fadt, 0, sizeof(acpi_fadt)); +- buffer.pointer = &acpi_fadt; +- buffer.length = sizeof(acpi_fadt); +- if (!ACPI_SUCCESS(acpi_get_table(ACPI_TABLE_FADT, 1, &buffer))) { +- printk(KERN_ERR "ACPI: missing fadt\n"); +- return -ENODEV; +- } +- +- return 0; +-} +- +-/* +- * Find and load ACPI tables +- */ +-int +-acpi_find_and_load_tables(u64 rsdp) +-{ +- if (!ACPI_SUCCESS(acpi_load_tables(rsdp))) { +- printk(KERN_INFO "ACPI: System description table load failed\n"); +- acpi_terminate(); +- return -1; +- } +- +- if (acpi_fetch_fadt()) { +- acpi_terminate(); +- return -1; +- } +- +- return 0; +-} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/tables/Makefile linux/drivers/acpi/tables/Makefile +--- /usr/src/linux/drivers/acpi/tables/Makefile Fri Dec 29 14:07:21 2000 ++++ linux/drivers/acpi/tables/Makefile Fri Apr 13 11:57:11 2001 +@@ -1,5 +1,6 @@ + # + # Makefile for all Linux ACPI interpreter subdirectories ++# EXCEPT for the ospm directory + # + + O_TARGET := ../$(shell basename `pwd`).o +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/tables/tbconvrt.c linux/drivers/acpi/tables/tbconvrt.c +--- /usr/src/linux/drivers/acpi/tables/tbconvrt.c Fri Feb 9 11:45:58 2001 ++++ linux/drivers/acpi/tables/tbconvrt.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: tbconvrt - ACPI Table conversion utilities +- * $Revision: 19 $ ++ * $Revision: 20 $ + * + *****************************************************************************/ + +@@ -30,7 +30,7 @@ + #include "actbl.h" + + +-#define _COMPONENT TABLE_MANAGER ++#define _COMPONENT ACPI_TABLES + MODULE_NAME ("tbconvrt") + + +@@ -70,8 +70,7 @@ + ACPI_STATUS + acpi_tb_convert_to_xsdt ( + ACPI_TABLE_DESC *table_info, +- u32 *number_of_tables) +-{ ++ u32 *number_of_tables) { + u32 table_size; + u32 pointer_size; + u32 i; +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/tables/tbget.c linux/drivers/acpi/tables/tbget.c +--- /usr/src/linux/drivers/acpi/tables/tbget.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/tables/tbget.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: tbget - ACPI Table get* routines +- * $Revision: 43 $ ++ * $Revision: 44 $ + * + *****************************************************************************/ + +@@ -29,7 +29,7 @@ + #include "actables.h" + + +-#define _COMPONENT TABLE_MANAGER ++#define _COMPONENT ACPI_TABLES + MODULE_NAME ("tbget") + + #define RSDP_CHECKSUM_LENGTH 20 +@@ -497,8 +497,7 @@ + /* Check the RSDT or XSDT signature */ + + if (STRNCMP ((char *) table_info.pointer, table_signature, +- signature_length)) +- { ++ signature_length)) { + /* Invalid RSDT or XSDT signature */ + + REPORT_ERROR (("Invalid signature where RSDP indicates %s should be located\n", +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/tables/tbinstal.c linux/drivers/acpi/tables/tbinstal.c +--- /usr/src/linux/drivers/acpi/tables/tbinstal.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/tables/tbinstal.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: tbinstal - ACPI table installation and removal +- * $Revision: 36 $ ++ * $Revision: 37 $ + * + *****************************************************************************/ + +@@ -29,7 +29,7 @@ + #include "actables.h" + + +-#define _COMPONENT TABLE_MANAGER ++#define _COMPONENT ACPI_TABLES + MODULE_NAME ("tbinstal") + + +@@ -127,8 +127,7 @@ + for (i = 1; i < NUM_ACPI_TABLES; i++) { + if (!STRNCMP (table_header->signature, + acpi_gbl_acpi_table_data[i].signature, +- acpi_gbl_acpi_table_data[i].sig_length)) +- { ++ acpi_gbl_acpi_table_data[i].sig_length)) { + /* + * Found a signature match, get the pertinent info from the + * Table_data structure +@@ -346,8 +345,7 @@ + + /* Clear the appropriate "typed" global table pointer */ + +- switch (type) +- { ++ switch (type) { + case ACPI_TABLE_RSDP: + acpi_gbl_RSDP = NULL; + break; +@@ -445,8 +443,7 @@ + if (table_desc->pointer) { + /* Valid table, determine type of memory allocation */ + +- switch (table_desc->allocation) +- { ++ switch (table_desc->allocation) { + + case ACPI_MEM_NOT_ALLOCATED: + break; +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/tables/tbutils.c linux/drivers/acpi/tables/tbutils.c +--- /usr/src/linux/drivers/acpi/tables/tbutils.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/tables/tbutils.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: tbutils - Table manipulation utilities +- * $Revision: 33 $ ++ * $Revision: 35 $ + * + *****************************************************************************/ + +@@ -29,7 +29,7 @@ + #include "acinterp.h" + + +-#define _COMPONENT TABLE_MANAGER ++#define _COMPONENT ACPI_TABLES + MODULE_NAME ("tbutils") + + +@@ -57,8 +57,7 @@ + + for (i = 0; i < ACPI_TABLE_MAX; i++) { + list_head = &acpi_gbl_acpi_tables[i]; +- do +- { ++ do { + if (list_head->table_id == table_id) { + *table_desc = list_head; + return (AE_OK); +@@ -108,8 +107,7 @@ + /* Check for a pointer within the DSDT */ + + if ((acpi_gbl_DSDT) && +- (IS_IN_ACPI_TABLE (where, acpi_gbl_DSDT))) +- { ++ (IS_IN_ACPI_TABLE (where, acpi_gbl_DSDT))) { + return (TRUE); + } + +@@ -188,7 +186,7 @@ + + MOVE_UNALIGNED32_TO_32 (&signature, &table_header->signature); + if (!acpi_cm_valid_acpi_name (signature)) { +- REPORT_WARNING (("Invalid table signature found\n")); ++ REPORT_WARNING (("Invalid table signature %4.4s found\n", &signature)); + return (AE_BAD_SIGNATURE); + } + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/tables/tbxface.c linux/drivers/acpi/tables/tbxface.c +--- /usr/src/linux/drivers/acpi/tables/tbxface.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/tables/tbxface.c Fri Apr 13 11:57:11 2001 +@@ -2,7 +2,7 @@ + * + * Module Name: tbxface - Public interfaces to the ACPI subsystem + * ACPI table oriented interfaces +- * $Revision: 34 $ ++ * $Revision: 35 $ + * + *****************************************************************************/ + +@@ -31,7 +31,7 @@ + #include "actables.h" + + +-#define _COMPONENT TABLE_MANAGER ++#define _COMPONENT ACPI_TABLES + MODULE_NAME ("tbxface") + + +@@ -194,8 +194,7 @@ + /* Find all tables of the requested type */ + + list_head = &acpi_gbl_acpi_tables[table_type]; +- do +- { ++ do { + /* + * Delete all namespace entries owned by this table. Note that these + * entries can appear anywhere in the namespace by virtue of the AML +@@ -251,8 +250,7 @@ + + if ((instance == 0) || + (table_type == ACPI_TABLE_RSDP) || +- (!out_table_header)) +- { ++ (!out_table_header)) { + return (AE_BAD_PARAMETER); + } + +@@ -260,8 +258,7 @@ + + if ((table_type > ACPI_TABLE_MAX) || + (IS_SINGLE_TABLE (acpi_gbl_acpi_table_data[table_type].flags) && +- instance > 1)) +- { ++ instance > 1)) { + return (AE_BAD_PARAMETER); + } + +@@ -332,8 +329,7 @@ + */ + if ((instance == 0) || + (!ret_buffer) || +- ((!ret_buffer->pointer) && (ret_buffer->length))) +- { ++ ((!ret_buffer->pointer) && (ret_buffer->length))) { + return (AE_BAD_PARAMETER); + } + +@@ -341,8 +337,7 @@ + + if ((table_type > ACPI_TABLE_MAX) || + (IS_SINGLE_TABLE (acpi_gbl_acpi_table_data[table_type].flags) && +- instance > 1)) +- { ++ instance > 1)) { + return (AE_BAD_PARAMETER); + } + +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/tables/tbxfroot.c linux/drivers/acpi/tables/tbxfroot.c +--- /usr/src/linux/drivers/acpi/tables/tbxfroot.c Mon Jan 22 13:23:43 2001 ++++ linux/drivers/acpi/tables/tbxfroot.c Fri Apr 13 11:57:11 2001 +@@ -1,7 +1,7 @@ + /****************************************************************************** + * + * Module Name: tbxfroot - Find the root ACPI table (RSDT) +- * $Revision: 35 $ ++ * $Revision: 36 $ + * + *****************************************************************************/ + +@@ -29,7 +29,7 @@ + #include "actables.h" + + +-#define _COMPONENT TABLE_MANAGER ++#define _COMPONENT ACPI_TABLES + MODULE_NAME ("tbxfroot") + + #define RSDP_CHECKSUM_LENGTH 20 +@@ -94,15 +94,13 @@ + + for (offset = 0, mem_rover = start_address; + offset < length; +- offset += RSDP_SCAN_STEP, mem_rover += RSDP_SCAN_STEP) +- { ++ offset += RSDP_SCAN_STEP, mem_rover += RSDP_SCAN_STEP) { + + /* The signature and checksum must both be correct */ + + if (STRNCMP ((NATIVE_CHAR *) mem_rover, + RSDP_SIG, sizeof (RSDP_SIG)-1) == 0 && +- acpi_tb_checksum (mem_rover, RSDP_CHECKSUM_LENGTH) == 0) +- { ++ acpi_tb_checksum (mem_rover, RSDP_CHECKSUM_LENGTH) == 0) { + /* If so, we have found the RSDP */ + + return (mem_rover); +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/utils/Makefile linux/drivers/acpi/utils/Makefile +--- /usr/src/linux/drivers/acpi/utils/Makefile Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/utils/Makefile Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,17 @@ ++# ++# Makefile for all Linux ACPI interpreter subdirectories ++# EXCEPT for the ospm directory ++# ++ ++O_TARGET := ../$(shell basename `pwd`).o ++ ++obj-$(CONFIG_ACPI) := $(patsubst %.c,%.o,$(wildcard *.c)) ++ ++EXTRA_CFLAGS += -I../include ++ ++EXTRA_CFLAGS += $(ACPI_CFLAGS) ++ ++include $(TOPDIR)/Rules.make ++ ++clean: ++ $(RM) *.o +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/utils/cmalloc.c linux/drivers/acpi/utils/cmalloc.c +--- /usr/src/linux/drivers/acpi/utils/cmalloc.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/utils/cmalloc.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,170 @@ ++/****************************************************************************** ++ * ++ * Module Name: cmalloc - local memory allocation routines ++ * $Revision: 87 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acparser.h" ++#include "acinterp.h" ++#include "acnamesp.h" ++#include "acglobal.h" ++ ++#define _COMPONENT ACPI_UTILITIES ++ MODULE_NAME ("cmalloc") ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: _Cm_allocate ++ * ++ * PARAMETERS: Size - Size of the allocation ++ * Component - Component type of caller ++ * Module - Source file name of caller ++ * Line - Line number of caller ++ * ++ * RETURN: Address of the allocated memory on success, NULL on failure. ++ * ++ * DESCRIPTION: The subsystem's equivalent of malloc. ++ * ++ ****************************************************************************/ ++ ++void * ++_cm_allocate ( ++ u32 size, ++ u32 component, ++ NATIVE_CHAR *module, ++ u32 line) ++{ ++ void *address = NULL; ++ ++ ++ /* Check for an inadvertent size of zero bytes */ ++ ++ if (!size) { ++ _REPORT_ERROR (module, line, component, ++ ("Cm_allocate: Attempt to allocate zero bytes\n")); ++ size = 1; ++ } ++ ++ address = acpi_os_allocate (size); ++ if (!address) { ++ /* Report allocation error */ ++ ++ _REPORT_ERROR (module, line, component, ++ ("Cm_allocate: Could not allocate size %X\n", size)); ++ ++ return (NULL); ++ } ++ ++ ++ return (address); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: _Cm_callocate ++ * ++ * PARAMETERS: Size - Size of the allocation ++ * Component - Component type of caller ++ * Module - Source file name of caller ++ * Line - Line number of caller ++ * ++ * RETURN: Address of the allocated memory on success, NULL on failure. ++ * ++ * DESCRIPTION: Subsystem equivalent of calloc. ++ * ++ ****************************************************************************/ ++ ++void * ++_cm_callocate ( ++ u32 size, ++ u32 component, ++ NATIVE_CHAR *module, ++ u32 line) ++{ ++ void *address = NULL; ++ ++ ++ /* Check for an inadvertent size of zero bytes */ ++ ++ if (!size) { ++ _REPORT_ERROR (module, line, component, ++ ("Cm_callocate: Attempt to allocate zero bytes\n")); ++ return (NULL); ++ } ++ ++ ++ address = acpi_os_callocate (size); ++ ++ if (!address) { ++ /* Report allocation error */ ++ ++ _REPORT_ERROR (module, line, component, ++ ("Cm_callocate: Could not allocate size %X\n", size)); ++ return (NULL); ++ } ++ ++ ++ return (address); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: _Cm_free ++ * ++ * PARAMETERS: Address - Address of the memory to deallocate ++ * Component - Component type of caller ++ * Module - Source file name of caller ++ * Line - Line number of caller ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Frees the memory at Address ++ * ++ ****************************************************************************/ ++ ++void ++_cm_free ( ++ void *address, ++ u32 component, ++ NATIVE_CHAR *module, ++ u32 line) ++{ ++ ++ if (NULL == address) { ++ _REPORT_ERROR (module, line, component, ++ ("_Cm_free: Trying to delete a NULL address\n")); ++ ++ return; ++ } ++ ++ ++ acpi_os_free (address); ++ ++ return; ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/utils/cmclib.c linux/drivers/acpi/utils/cmclib.c +--- /usr/src/linux/drivers/acpi/utils/cmclib.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/utils/cmclib.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,815 @@ ++/****************************************************************************** ++ * ++ * Module Name: cmclib - Local implementation of C library functions ++ * $Revision: 36 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acevents.h" ++#include "achware.h" ++#include "acnamesp.h" ++#include "acinterp.h" ++#include "amlcode.h" ++ ++/* ++ * These implementations of standard C Library routines can optionally be ++ * used if a C library is not available. In general, they are less efficient ++ * than an inline or assembly implementation ++ */ ++ ++#define _COMPONENT MISCELLANEOUS ++ MODULE_NAME ("cmclib") ++ ++ ++#ifndef ACPI_USE_SYSTEM_CLIBRARY ++ ++/******************************************************************************* ++ * ++ * FUNCTION: strlen ++ * ++ * PARAMETERS: String - Null terminated string ++ * ++ * RETURN: Length ++ * ++ * DESCRIPTION: Returns the length of the input string ++ * ++ ******************************************************************************/ ++ ++ ++u32 ++acpi_cm_strlen ( ++ const NATIVE_CHAR *string) ++{ ++ u32 length = 0; ++ ++ ++ /* Count the string until a null is encountered */ ++ ++ while (*string) { ++ length++; ++ string++; ++ } ++ ++ return (length); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: strcpy ++ * ++ * PARAMETERS: Dst_string - Target of the copy ++ * Src_string - The source string to copy ++ * ++ * RETURN: Dst_string ++ * ++ * DESCRIPTION: Copy a null terminated string ++ * ++ ******************************************************************************/ ++ ++NATIVE_CHAR * ++acpi_cm_strcpy ( ++ NATIVE_CHAR *dst_string, ++ const NATIVE_CHAR *src_string) ++{ ++ NATIVE_CHAR *string = dst_string; ++ ++ ++ /* Move bytes brute force */ ++ ++ while (*src_string) { ++ *string = *src_string; ++ ++ string++; ++ src_string++; ++ } ++ ++ /* Null terminate */ ++ ++ *string = 0; ++ ++ return (dst_string); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: strncpy ++ * ++ * PARAMETERS: Dst_string - Target of the copy ++ * Src_string - The source string to copy ++ * Count - Maximum # of bytes to copy ++ * ++ * RETURN: Dst_string ++ * ++ * DESCRIPTION: Copy a null terminated string, with a maximum length ++ * ++ ******************************************************************************/ ++ ++NATIVE_CHAR * ++acpi_cm_strncpy ( ++ NATIVE_CHAR *dst_string, ++ const NATIVE_CHAR *src_string, ++ NATIVE_UINT count) ++{ ++ NATIVE_CHAR *string = dst_string; ++ ++ ++ /* Copy the string */ ++ ++ for (string = dst_string; ++ count && (count--, (*string++ = *src_string++)); ) {;} ++ ++ /* Pad with nulls if necessary */ ++ ++ while (count--) { ++ *string = 0; ++ string++; ++ } ++ ++ /* Return original pointer */ ++ ++ return (dst_string); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: strcmp ++ * ++ * PARAMETERS: String1 - First string ++ * String2 - Second string ++ * ++ * RETURN: Index where strings mismatched, or 0 if strings matched ++ * ++ * DESCRIPTION: Compare two null terminated strings ++ * ++ ******************************************************************************/ ++ ++u32 ++acpi_cm_strcmp ( ++ const NATIVE_CHAR *string1, ++ const NATIVE_CHAR *string2) ++{ ++ ++ ++ for ( ; (*string1 == *string2); string2++) { ++ if (!*string1++) { ++ return (0); ++ } ++ } ++ ++ ++ return ((unsigned char) *string1 - (unsigned char) *string2); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: strncmp ++ * ++ * PARAMETERS: String1 - First string ++ * String2 - Second string ++ * Count - Maximum # of bytes to compare ++ * ++ * RETURN: Index where strings mismatched, or 0 if strings matched ++ * ++ * DESCRIPTION: Compare two null terminated strings, with a maximum length ++ * ++ ******************************************************************************/ ++ ++u32 ++acpi_cm_strncmp ( ++ const NATIVE_CHAR *string1, ++ const NATIVE_CHAR *string2, ++ NATIVE_UINT count) ++{ ++ ++ ++ for ( ; count-- && (*string1 == *string2); string2++) { ++ if (!*string1++) { ++ return (0); ++ } ++ } ++ ++ return ((count == -1) ? 0 : ((unsigned char) *string1 - ++ (unsigned char) *string2)); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Strcat ++ * ++ * PARAMETERS: Dst_string - Target of the copy ++ * Src_string - The source string to copy ++ * ++ * RETURN: Dst_string ++ * ++ * DESCRIPTION: Append a null terminated string to a null terminated string ++ * ++ ******************************************************************************/ ++ ++NATIVE_CHAR * ++acpi_cm_strcat ( ++ NATIVE_CHAR *dst_string, ++ const NATIVE_CHAR *src_string) ++{ ++ NATIVE_CHAR *string; ++ ++ ++ /* Find end of the destination string */ ++ ++ for (string = dst_string; *string++; ) { ; } ++ ++ /* Concatinate the string */ ++ ++ for (--string; (*string++ = *src_string++); ) { ; } ++ ++ return (dst_string); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: strncat ++ * ++ * PARAMETERS: Dst_string - Target of the copy ++ * Src_string - The source string to copy ++ * Count - Maximum # of bytes to copy ++ * ++ * RETURN: Dst_string ++ * ++ * DESCRIPTION: Append a null terminated string to a null terminated string, ++ * with a maximum count. ++ * ++ ******************************************************************************/ ++ ++NATIVE_CHAR * ++acpi_cm_strncat ( ++ NATIVE_CHAR *dst_string, ++ const NATIVE_CHAR *src_string, ++ NATIVE_UINT count) ++{ ++ NATIVE_CHAR *string; ++ ++ ++ if (count) { ++ /* Find end of the destination string */ ++ ++ for (string = dst_string; *string++; ) { ; } ++ ++ /* Concatinate the string */ ++ ++ for (--string; (*string++ = *src_string++) && --count; ) { ; } ++ ++ /* Null terminate if necessary */ ++ ++ if (!count) { ++ *string = 0; ++ } ++ } ++ ++ return (dst_string); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: memcpy ++ * ++ * PARAMETERS: Dest - Target of the copy ++ * Src - Source buffer to copy ++ * Count - Number of bytes to copy ++ * ++ * RETURN: Dest ++ * ++ * DESCRIPTION: Copy arbitrary bytes of memory ++ * ++ ******************************************************************************/ ++ ++void * ++acpi_cm_memcpy ( ++ void *dest, ++ const void *src, ++ NATIVE_UINT count) ++{ ++ NATIVE_CHAR *new = (NATIVE_CHAR *) dest; ++ NATIVE_CHAR *old = (NATIVE_CHAR *) src; ++ ++ ++ while (count) { ++ *new = *old; ++ new++; ++ old++; ++ count--; ++ } ++ ++ return (dest); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: memset ++ * ++ * PARAMETERS: Dest - Buffer to set ++ * Value - Value to set each byte of memory ++ * Count - Number of bytes to set ++ * ++ * RETURN: Dest ++ * ++ * DESCRIPTION: Initialize a buffer to a known value. ++ * ++ ******************************************************************************/ ++ ++void * ++acpi_cm_memset ( ++ void *dest, ++ NATIVE_UINT value, ++ NATIVE_UINT count) ++{ ++ NATIVE_CHAR *new = (NATIVE_CHAR *) dest; ++ ++ ++ while (count) { ++ *new = (char) value; ++ new++; ++ count--; ++ } ++ ++ return (dest); ++} ++ ++ ++#define NEGATIVE 1 ++#define POSITIVE 0 ++ ++ ++#define _ACPI_XA 0x00 /* extra alphabetic - not supported */ ++#define _ACPI_XS 0x40 /* extra space */ ++#define _ACPI_BB 0x00 /* BEL, BS, etc. - not supported */ ++#define _ACPI_CN 0x20 /* CR, FF, HT, NL, VT */ ++#define _ACPI_DI 0x04 /* '0'-'9' */ ++#define _ACPI_LO 0x02 /* 'a'-'z' */ ++#define _ACPI_PU 0x10 /* punctuation */ ++#define _ACPI_SP 0x08 /* space */ ++#define _ACPI_UP 0x01 /* 'A'-'Z' */ ++#define _ACPI_XD 0x80 /* '0'-'9', 'A'-'F', 'a'-'f' */ ++ ++static const u8 _acpi_ctype[257] = { ++ _ACPI_CN, /* 0x0 0. */ ++ _ACPI_CN, /* 0x1 1. */ ++ _ACPI_CN, /* 0x2 2. */ ++ _ACPI_CN, /* 0x3 3. */ ++ _ACPI_CN, /* 0x4 4. */ ++ _ACPI_CN, /* 0x5 5. */ ++ _ACPI_CN, /* 0x6 6. */ ++ _ACPI_CN, /* 0x7 7. */ ++ _ACPI_CN, /* 0x8 8. */ ++ _ACPI_CN|_ACPI_SP, /* 0x9 9. */ ++ _ACPI_CN|_ACPI_SP, /* 0xA 10. */ ++ _ACPI_CN|_ACPI_SP, /* 0xB 11. */ ++ _ACPI_CN|_ACPI_SP, /* 0xC 12. */ ++ _ACPI_CN|_ACPI_SP, /* 0xD 13. */ ++ _ACPI_CN, /* 0xE 14. */ ++ _ACPI_CN, /* 0xF 15. */ ++ _ACPI_CN, /* 0x10 16. */ ++ _ACPI_CN, /* 0x11 17. */ ++ _ACPI_CN, /* 0x12 18. */ ++ _ACPI_CN, /* 0x13 19. */ ++ _ACPI_CN, /* 0x14 20. */ ++ _ACPI_CN, /* 0x15 21. */ ++ _ACPI_CN, /* 0x16 22. */ ++ _ACPI_CN, /* 0x17 23. */ ++ _ACPI_CN, /* 0x18 24. */ ++ _ACPI_CN, /* 0x19 25. */ ++ _ACPI_CN, /* 0x1A 26. */ ++ _ACPI_CN, /* 0x1B 27. */ ++ _ACPI_CN, /* 0x1C 28. */ ++ _ACPI_CN, /* 0x1D 29. */ ++ _ACPI_CN, /* 0x1E 30. */ ++ _ACPI_CN, /* 0x1F 31. */ ++ _ACPI_XS|_ACPI_SP, /* 0x20 32. ' ' */ ++ _ACPI_PU, /* 0x21 33. '!' */ ++ _ACPI_PU, /* 0x22 34. '"' */ ++ _ACPI_PU, /* 0x23 35. '#' */ ++ _ACPI_PU, /* 0x24 36. '$' */ ++ _ACPI_PU, /* 0x25 37. '%' */ ++ _ACPI_PU, /* 0x26 38. '&' */ ++ _ACPI_PU, /* 0x27 39. ''' */ ++ _ACPI_PU, /* 0x28 40. '(' */ ++ _ACPI_PU, /* 0x29 41. ')' */ ++ _ACPI_PU, /* 0x2A 42. '*' */ ++ _ACPI_PU, /* 0x2B 43. '+' */ ++ _ACPI_PU, /* 0x2C 44. ',' */ ++ _ACPI_PU, /* 0x2D 45. '-' */ ++ _ACPI_PU, /* 0x2E 46. '.' */ ++ _ACPI_PU, /* 0x2F 47. '/' */ ++ _ACPI_XD|_ACPI_DI, /* 0x30 48. '0' */ ++ _ACPI_XD|_ACPI_DI, /* 0x31 49. '1' */ ++ _ACPI_XD|_ACPI_DI, /* 0x32 50. '2' */ ++ _ACPI_XD|_ACPI_DI, /* 0x33 51. '3' */ ++ _ACPI_XD|_ACPI_DI, /* 0x34 52. '4' */ ++ _ACPI_XD|_ACPI_DI, /* 0x35 53. '5' */ ++ _ACPI_XD|_ACPI_DI, /* 0x36 54. '6' */ ++ _ACPI_XD|_ACPI_DI, /* 0x37 55. '7' */ ++ _ACPI_XD|_ACPI_DI, /* 0x38 56. '8' */ ++ _ACPI_XD|_ACPI_DI, /* 0x39 57. '9' */ ++ _ACPI_PU, /* 0x3A 58. ':' */ ++ _ACPI_PU, /* 0x3B 59. ';' */ ++ _ACPI_PU, /* 0x3C 60. '<' */ ++ _ACPI_PU, /* 0x3D 61. '=' */ ++ _ACPI_PU, /* 0x3E 62. '>' */ ++ _ACPI_PU, /* 0x3F 63. '?' */ ++ _ACPI_PU, /* 0x40 64. '@' */ ++ _ACPI_XD|_ACPI_UP, /* 0x41 65. 'A' */ ++ _ACPI_XD|_ACPI_UP, /* 0x42 66. 'B' */ ++ _ACPI_XD|_ACPI_UP, /* 0x43 67. 'C' */ ++ _ACPI_XD|_ACPI_UP, /* 0x44 68. 'D' */ ++ _ACPI_XD|_ACPI_UP, /* 0x45 69. 'E' */ ++ _ACPI_XD|_ACPI_UP, /* 0x46 70. 'F' */ ++ _ACPI_UP, /* 0x47 71. 'G' */ ++ _ACPI_UP, /* 0x48 72. 'H' */ ++ _ACPI_UP, /* 0x49 73. 'I' */ ++ _ACPI_UP, /* 0x4A 74. 'J' */ ++ _ACPI_UP, /* 0x4B 75. 'K' */ ++ _ACPI_UP, /* 0x4C 76. 'L' */ ++ _ACPI_UP, /* 0x4D 77. 'M' */ ++ _ACPI_UP, /* 0x4E 78. 'N' */ ++ _ACPI_UP, /* 0x4F 79. 'O' */ ++ _ACPI_UP, /* 0x50 80. 'P' */ ++ _ACPI_UP, /* 0x51 81. 'Q' */ ++ _ACPI_UP, /* 0x52 82. 'R' */ ++ _ACPI_UP, /* 0x53 83. 'S' */ ++ _ACPI_UP, /* 0x54 84. 'T' */ ++ _ACPI_UP, /* 0x55 85. 'U' */ ++ _ACPI_UP, /* 0x56 86. 'V' */ ++ _ACPI_UP, /* 0x57 87. 'W' */ ++ _ACPI_UP, /* 0x58 88. 'X' */ ++ _ACPI_UP, /* 0x59 89. 'Y' */ ++ _ACPI_UP, /* 0x5A 90. 'Z' */ ++ _ACPI_PU, /* 0x5B 91. '[' */ ++ _ACPI_PU, /* 0x5C 92. '\' */ ++ _ACPI_PU, /* 0x5D 93. ']' */ ++ _ACPI_PU, /* 0x5E 94. '^' */ ++ _ACPI_PU, /* 0x5F 95. '_' */ ++ _ACPI_PU, /* 0x60 96. '`' */ ++ _ACPI_XD|_ACPI_LO, /* 0x61 97. 'a' */ ++ _ACPI_XD|_ACPI_LO, /* 0x62 98. 'b' */ ++ _ACPI_XD|_ACPI_LO, /* 0x63 99. 'c' */ ++ _ACPI_XD|_ACPI_LO, /* 0x64 100. 'd' */ ++ _ACPI_XD|_ACPI_LO, /* 0x65 101. 'e' */ ++ _ACPI_XD|_ACPI_LO, /* 0x66 102. 'f' */ ++ _ACPI_LO, /* 0x67 103. 'g' */ ++ _ACPI_LO, /* 0x68 104. 'h' */ ++ _ACPI_LO, /* 0x69 105. 'i' */ ++ _ACPI_LO, /* 0x6A 106. 'j' */ ++ _ACPI_LO, /* 0x6B 107. 'k' */ ++ _ACPI_LO, /* 0x6C 108. 'l' */ ++ _ACPI_LO, /* 0x6D 109. 'm' */ ++ _ACPI_LO, /* 0x6E 110. 'n' */ ++ _ACPI_LO, /* 0x6F 111. 'o' */ ++ _ACPI_LO, /* 0x70 112. 'p' */ ++ _ACPI_LO, /* 0x71 113. 'q' */ ++ _ACPI_LO, /* 0x72 114. 'r' */ ++ _ACPI_LO, /* 0x73 115. 's' */ ++ _ACPI_LO, /* 0x74 116. 't' */ ++ _ACPI_LO, /* 0x75 117. 'u' */ ++ _ACPI_LO, /* 0x76 118. 'v' */ ++ _ACPI_LO, /* 0x77 119. 'w' */ ++ _ACPI_LO, /* 0x78 120. 'x' */ ++ _ACPI_LO, /* 0x79 121. 'y' */ ++ _ACPI_LO, /* 0x7A 122. 'z' */ ++ _ACPI_PU, /* 0x7B 123. '{' */ ++ _ACPI_PU, /* 0x7C 124. '|' */ ++ _ACPI_PU, /* 0x7D 125. '}' */ ++ _ACPI_PU, /* 0x7E 126. '~' */ ++ _ACPI_CN, /* 0x7F 127. */ ++ ++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80 to 0x8F */ ++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x90 to 0x9F */ ++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xA0 to 0xAF */ ++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xB0 to 0xBF */ ++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xC0 to 0xCF */ ++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xD0 to 0xDF */ ++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xE0 to 0xEF */ ++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* 0xF0 to 0x100 */ ++}; ++ ++#define IS_UPPER(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_UP)) ++#define IS_LOWER(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO)) ++#define IS_DIGIT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_DI)) ++#define IS_SPACE(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_SP)) ++#define IS_XDIGIT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_XD)) ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_to_upper ++ * ++ * PARAMETERS: ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: Convert character to uppercase ++ * ++ ******************************************************************************/ ++ ++u32 ++acpi_cm_to_upper ( ++ u32 c) ++{ ++ ++ return (IS_LOWER(c) ? ((c)-0x20) : (c)); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_to_lower ++ * ++ * PARAMETERS: ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: Convert character to lowercase ++ * ++ ******************************************************************************/ ++ ++u32 ++acpi_cm_to_lower ( ++ u32 c) ++{ ++ ++ return (IS_UPPER(c) ? ((c)+0x20) : (c)); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: strupr ++ * ++ * PARAMETERS: Src_string - The source string to convert to ++ * ++ * RETURN: Src_string ++ * ++ * DESCRIPTION: Convert string to uppercase ++ * ++ ******************************************************************************/ ++ ++NATIVE_CHAR * ++acpi_cm_strupr ( ++ NATIVE_CHAR *src_string) ++{ ++ NATIVE_CHAR *string; ++ ++ ++ /* Walk entire string, uppercasing the letters */ ++ ++ for (string = src_string; *string; ) { ++ *string = (char) acpi_cm_to_upper (*string); ++ string++; ++ } ++ ++ ++ return (src_string); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: strstr ++ * ++ * PARAMETERS: String1 - ++ * String2 ++ * ++ * RETURN: ++ * ++ * DESCRIPTION: Checks if String2 occurs in String1. This is not really a ++ * full implementation of strstr, only sufficient for command ++ * matching ++ * ++ ******************************************************************************/ ++ ++NATIVE_CHAR * ++acpi_cm_strstr ( ++ NATIVE_CHAR *string1, ++ NATIVE_CHAR *string2) ++{ ++ NATIVE_CHAR *string; ++ ++ ++ if (acpi_cm_strlen (string2) > acpi_cm_strlen (string1)) { ++ return (NULL); ++ } ++ ++ /* Walk entire string, comparing the letters */ ++ ++ for (string = string1; *string2; ) { ++ if (*string2 != *string) { ++ return (NULL); ++ } ++ ++ string2++; ++ string++; ++ } ++ ++ ++ return (string1); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: strtoul ++ * ++ * PARAMETERS: String - Null terminated string ++ * Terminater - Where a pointer to the terminating byte is returned ++ * Base - Radix of the string ++ * ++ * RETURN: Converted value ++ * ++ * DESCRIPTION: Convert a string into an unsigned value. ++ * ++ ******************************************************************************/ ++ ++u32 ++acpi_cm_strtoul ( ++ const NATIVE_CHAR *string, ++ NATIVE_CHAR **terminator, ++ u32 base) ++{ ++ u32 converted = 0; ++ u32 index; ++ u32 sign; ++ const NATIVE_CHAR *string_start; ++ u32 return_value = 0; ++ ACPI_STATUS status = AE_OK; ++ ++ ++ /* ++ * Save the value of the pointer to the buffer's first ++ * character, save the current errno value, and then ++ * skip over any white space in the buffer: ++ */ ++ string_start = string; ++ while (IS_SPACE (*string) || *string == '\t') { ++ ++string; ++ } ++ ++ /* ++ * The buffer may contain an optional plus or minus sign. ++ * If it does, then skip over it but remember what is was: ++ */ ++ if (*string == '-') { ++ sign = NEGATIVE; ++ ++string; ++ } ++ ++ else if (*string == '+') { ++ ++string; ++ sign = POSITIVE; ++ } ++ ++ else { ++ sign = POSITIVE; ++ } ++ ++ /* ++ * If the input parameter Base is zero, then we need to ++ * determine if it is octal, decimal, or hexadecimal: ++ */ ++ if (base == 0) { ++ if (*string == '0') { ++ if (acpi_cm_to_lower (*(++string)) == 'x') { ++ base = 16; ++ ++string; ++ } ++ ++ else { ++ base = 8; ++ } ++ } ++ ++ else { ++ base = 10; ++ } ++ } ++ ++ else if (base < 2 || base > 36) { ++ /* ++ * The specified Base parameter is not in the domain of ++ * this function: ++ */ ++ goto done; ++ } ++ ++ /* ++ * For octal and hexadecimal bases, skip over the leading ++ * 0 or 0x, if they are present. ++ */ ++ if (base == 8 && *string == '0') { ++ string++; ++ } ++ ++ if (base == 16 && ++ *string == '0' && ++ acpi_cm_to_lower (*(++string)) == 'x') { ++ string++; ++ } ++ ++ ++ /* ++ * Main loop: convert the string to an unsigned long: ++ */ ++ while (*string) { ++ if (IS_DIGIT (*string)) { ++ index = *string - '0'; ++ } ++ ++ else { ++ index = acpi_cm_to_upper (*string); ++ if (IS_UPPER (index)) { ++ index = index - 'A' + 10; ++ } ++ ++ else { ++ goto done; ++ } ++ } ++ ++ if (index >= base) { ++ goto done; ++ } ++ ++ /* ++ * Check to see if value is out of range: ++ */ ++ ++ if (return_value > ((ACPI_UINT32_MAX - (u32) index) / ++ (u32) base)) { ++ status = AE_ERROR; ++ return_value = 0L; /* reset */ ++ } ++ ++ else { ++ return_value *= base; ++ return_value += index; ++ converted = 1; ++ } ++ ++ ++string; ++ } ++ ++done: ++ /* ++ * If appropriate, update the caller's pointer to the next ++ * unconverted character in the buffer. ++ */ ++ if (terminator) { ++ if (converted == 0 && return_value == 0L && string != NULL) { ++ *terminator = (NATIVE_CHAR *) string_start; ++ } ++ ++ else { ++ *terminator = (NATIVE_CHAR *) string; ++ } ++ } ++ ++ if (status == AE_ERROR) { ++ return_value = ACPI_UINT32_MAX; ++ } ++ ++ /* ++ * If a minus sign was present, then "the conversion is negated": ++ */ ++ if (sign == NEGATIVE) { ++ return_value = (ACPI_UINT32_MAX - return_value) + 1; ++ } ++ ++ return (return_value); ++} ++ ++#endif /* ACPI_USE_SYSTEM_CLIBRARY */ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/utils/cmcopy.c linux/drivers/acpi/utils/cmcopy.c +--- /usr/src/linux/drivers/acpi/utils/cmcopy.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/utils/cmcopy.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,707 @@ ++/****************************************************************************** ++ * ++ * Module Name: cmcopy - Internal to external object translation utilities ++ * $Revision: 71 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acinterp.h" ++#include "acnamesp.h" ++#include "amlcode.h" ++ ++ ++#define _COMPONENT ACPI_UTILITIES ++ MODULE_NAME ("cmcopy") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_copy_isimple_to_esimple ++ * ++ * PARAMETERS: *Internal_object - Pointer to the object we are examining ++ * *Buffer - Where the object is returned ++ * *Space_used - Where the data length is returned ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: This function is called to place a simple object in a user ++ * buffer. ++ * ++ * The buffer is assumed to have sufficient space for the object. ++ * ++ ******************************************************************************/ ++ ++static ACPI_STATUS ++acpi_cm_copy_isimple_to_esimple ( ++ ACPI_OPERAND_OBJECT *internal_object, ++ ACPI_OBJECT *external_object, ++ u8 *data_space, ++ u32 *buffer_space_used) ++{ ++ u32 length = 0; ++ ACPI_STATUS status = AE_OK; ++ ++ ++ /* ++ * Check for NULL object case (could be an uninitialized ++ * package element ++ */ ++ ++ if (!internal_object) { ++ *buffer_space_used = 0; ++ return (AE_OK); ++ } ++ ++ /* Always clear the external object */ ++ ++ MEMSET (external_object, 0, sizeof (ACPI_OBJECT)); ++ ++ /* ++ * In general, the external object will be the same type as ++ * the internal object ++ */ ++ ++ external_object->type = internal_object->common.type; ++ ++ /* However, only a limited number of external types are supported */ ++ ++ switch (internal_object->common.type) { ++ ++ case ACPI_TYPE_STRING: ++ ++ length = internal_object->string.length + 1; ++ external_object->string.length = internal_object->string.length; ++ external_object->string.pointer = (NATIVE_CHAR *) data_space; ++ MEMCPY ((void *) data_space, (void *) internal_object->string.pointer, length); ++ break; ++ ++ ++ case ACPI_TYPE_BUFFER: ++ ++ length = internal_object->buffer.length; ++ external_object->buffer.length = internal_object->buffer.length; ++ external_object->buffer.pointer = data_space; ++ MEMCPY ((void *) data_space, (void *) internal_object->buffer.pointer, length); ++ break; ++ ++ ++ case ACPI_TYPE_INTEGER: ++ ++ external_object->integer.value= internal_object->integer.value; ++ break; ++ ++ ++ case INTERNAL_TYPE_REFERENCE: ++ ++ /* ++ * This is an object reference. Attempt to dereference it. ++ */ ++ ++ switch (internal_object->reference.opcode) { ++ case AML_ZERO_OP: ++ external_object->type = ACPI_TYPE_INTEGER; ++ external_object->integer.value = 0; ++ break; ++ ++ case AML_ONE_OP: ++ external_object->type = ACPI_TYPE_INTEGER; ++ external_object->integer.value = 1; ++ break; ++ ++ case AML_ONES_OP: ++ external_object->type = ACPI_TYPE_INTEGER; ++ external_object->integer.value = ACPI_INTEGER_MAX; ++ break; ++ ++ case AML_NAMEPATH_OP: ++ /* ++ * This is a named reference, get the string. We already know that ++ * we have room for it, use max length ++ */ ++ length = MAX_STRING_LENGTH; ++ external_object->type = ACPI_TYPE_STRING; ++ external_object->string.pointer = (NATIVE_CHAR *) data_space; ++ status = acpi_ns_handle_to_pathname ((ACPI_HANDLE *) internal_object->reference.node, ++ &length, (char *) data_space); ++ ++ /* Converted (external) string length is returned from above */ ++ ++ external_object->string.length = length; ++ break; ++ ++ default: ++ /* ++ * Use the object type of "Any" to indicate a reference ++ * to object containing a handle to an ACPI named object. ++ */ ++ external_object->type = ACPI_TYPE_ANY; ++ external_object->reference.handle = internal_object->reference.node; ++ break; ++ } ++ break; ++ ++ ++ case ACPI_TYPE_PROCESSOR: ++ ++ external_object->processor.proc_id = internal_object->processor.proc_id; ++ external_object->processor.pblk_address = internal_object->processor.address; ++ external_object->processor.pblk_length = internal_object->processor.length; ++ break; ++ ++ ++ case ACPI_TYPE_POWER: ++ ++ external_object->power_resource.system_level = ++ internal_object->power_resource.system_level; ++ ++ external_object->power_resource.resource_order = ++ internal_object->power_resource.resource_order; ++ break; ++ ++ ++ default: ++ /* ++ * There is no corresponding external object type ++ */ ++ return (AE_SUPPORT); ++ break; ++ } ++ ++ ++ *buffer_space_used = (u32) ROUND_UP_TO_NATIVE_WORD (length); ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_copy_ielement_to_eelement ++ * ++ * PARAMETERS: ACPI_PKG_CALLBACK ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Copy one package element to another package element ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_copy_ielement_to_eelement ( ++ u8 object_type, ++ ACPI_OPERAND_OBJECT *source_object, ++ ACPI_GENERIC_STATE *state, ++ void *context) ++{ ++ ACPI_STATUS status = AE_OK; ++ ACPI_PKG_INFO *info = (ACPI_PKG_INFO *) context; ++ u32 object_space; ++ u32 this_index; ++ ACPI_OBJECT *target_object; ++ ++ ++ this_index = state->pkg.index; ++ target_object = (ACPI_OBJECT *) ++ &((ACPI_OBJECT *)(state->pkg.dest_object))->package.elements[this_index]; ++ ++ ++ switch (object_type) { ++ case ACPI_COPY_TYPE_SIMPLE: ++ ++ /* ++ * This is a simple or null object -- get the size ++ */ ++ ++ status = acpi_cm_copy_isimple_to_esimple (source_object, ++ target_object, info->free_space, &object_space); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ break; ++ ++ case ACPI_COPY_TYPE_PACKAGE: ++ ++ /* ++ * Build the package object ++ */ ++ target_object->type = ACPI_TYPE_PACKAGE; ++ target_object->package.count = source_object->package.count; ++ target_object->package.elements = (ACPI_OBJECT *) info->free_space; ++ ++ /* ++ * Pass the new package object back to the package walk routine ++ */ ++ state->pkg.this_target_obj = target_object; ++ ++ /* ++ * Save space for the array of objects (Package elements) ++ * update the buffer length counter ++ */ ++ object_space = (u32) ROUND_UP_TO_NATIVE_WORD ( ++ target_object->package.count * sizeof (ACPI_OBJECT)); ++ break; ++ ++ default: ++ return (AE_BAD_PARAMETER); ++ } ++ ++ ++ info->free_space += object_space; ++ info->length += object_space; ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_copy_ipackage_to_epackage ++ * ++ * PARAMETERS: *Internal_object - Pointer to the object we are returning ++ * *Buffer - Where the object is returned ++ * *Space_used - Where the object length is returned ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: This function is called to place a package object in a user ++ * buffer. A package object by definition contains other objects. ++ * ++ * The buffer is assumed to have sufficient space for the object. ++ * The caller must have verified the buffer length needed using the ++ * Acpi_cm_get_object_size function before calling this function. ++ * ++ ******************************************************************************/ ++ ++static ACPI_STATUS ++acpi_cm_copy_ipackage_to_epackage ( ++ ACPI_OPERAND_OBJECT *internal_object, ++ u8 *buffer, ++ u32 *space_used) ++{ ++ ACPI_OBJECT *external_object; ++ ACPI_STATUS status; ++ ACPI_PKG_INFO info; ++ ++ ++ /* ++ * First package at head of the buffer ++ */ ++ external_object = (ACPI_OBJECT *) buffer; ++ ++ /* ++ * Free space begins right after the first package ++ */ ++ info.length = 0; ++ info.object_space = 0; ++ info.num_packages = 1; ++ info.free_space = buffer + ROUND_UP_TO_NATIVE_WORD (sizeof (ACPI_OBJECT)); ++ ++ ++ external_object->type = internal_object->common.type; ++ external_object->package.count = internal_object->package.count; ++ external_object->package.elements = (ACPI_OBJECT *) info.free_space; ++ ++ ++ /* ++ * Build an array of ACPI_OBJECTS in the buffer ++ * and move the free space past it ++ */ ++ ++ info.free_space += external_object->package.count * ++ ROUND_UP_TO_NATIVE_WORD (sizeof (ACPI_OBJECT)); ++ ++ ++ status = acpi_cm_walk_package_tree (internal_object, external_object, ++ acpi_cm_copy_ielement_to_eelement, &info); ++ ++ *space_used = info.length; ++ ++ return (status); ++ ++} ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_copy_iobject_to_eobject ++ * ++ * PARAMETERS: *Internal_object - The internal object to be converted ++ * *Buffer_ptr - Where the object is returned ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: This function is called to build an API object to be returned to ++ * the caller. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_copy_iobject_to_eobject ( ++ ACPI_OPERAND_OBJECT *internal_object, ++ ACPI_BUFFER *ret_buffer) ++{ ++ ACPI_STATUS status; ++ ++ ++ if (IS_THIS_OBJECT_TYPE (internal_object, ACPI_TYPE_PACKAGE)) { ++ /* ++ * Package object: Copy all subobjects (including ++ * nested packages) ++ */ ++ status = acpi_cm_copy_ipackage_to_epackage (internal_object, ++ ret_buffer->pointer, &ret_buffer->length); ++ } ++ ++ else { ++ /* ++ * Build a simple object (no nested objects) ++ */ ++ status = acpi_cm_copy_isimple_to_esimple (internal_object, ++ (ACPI_OBJECT *) ret_buffer->pointer, ++ ((u8 *) ret_buffer->pointer + ++ ROUND_UP_TO_NATIVE_WORD (sizeof (ACPI_OBJECT))), ++ &ret_buffer->length); ++ /* ++ * build simple does not include the object size in the length ++ * so we add it in here ++ */ ++ ret_buffer->length += sizeof (ACPI_OBJECT); ++ } ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_copy_esimple_to_isimple ++ * ++ * PARAMETERS: *External_object - The external object to be converted ++ * *Internal_object - Where the internal object is returned ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: This function copies an external object to an internal one. ++ * NOTE: Pointers can be copied, we don't need to copy data. ++ * (The pointers have to be valid in our address space no matter ++ * what we do with them!) ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_copy_esimple_to_isimple ( ++ ACPI_OBJECT *external_object, ++ ACPI_OPERAND_OBJECT *internal_object) ++{ ++ ++ ++ internal_object->common.type = (u8) external_object->type; ++ ++ switch (external_object->type) { ++ ++ case ACPI_TYPE_STRING: ++ ++ internal_object->string.length = external_object->string.length; ++ internal_object->string.pointer = external_object->string.pointer; ++ break; ++ ++ ++ case ACPI_TYPE_BUFFER: ++ ++ internal_object->buffer.length = external_object->buffer.length; ++ internal_object->buffer.pointer = external_object->buffer.pointer; ++ break; ++ ++ ++ case ACPI_TYPE_INTEGER: ++ /* ++ * Number is included in the object itself ++ */ ++ internal_object->integer.value = external_object->integer.value; ++ break; ++ ++ ++ default: ++ return (AE_CTRL_RETURN_VALUE); ++ break; ++ } ++ ++ ++ return (AE_OK); ++} ++ ++ ++#ifdef ACPI_FUTURE_IMPLEMENTATION ++ ++/* Code to convert packages that are parameters to control methods */ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_copy_epackage_to_ipackage ++ * ++ * PARAMETERS: *Internal_object - Pointer to the object we are returning ++ * *Buffer - Where the object is returned ++ * *Space_used - Where the length of the object is returned ++ * ++ * RETURN: Status - the status of the call ++ * ++ * DESCRIPTION: This function is called to place a package object in a user ++ * buffer. A package object by definition contains other objects. ++ * ++ * The buffer is assumed to have sufficient space for the object. ++ * The caller must have verified the buffer length needed using the ++ * Acpi_cm_get_object_size function before calling this function. ++ * ++ ******************************************************************************/ ++ ++static ACPI_STATUS ++acpi_cm_copy_epackage_to_ipackage ( ++ ACPI_OPERAND_OBJECT *internal_object, ++ u8 *buffer, ++ u32 *space_used) ++{ ++ u8 *free_space; ++ ACPI_OBJECT *external_object; ++ u32 length = 0; ++ u32 this_index; ++ u32 object_space = 0; ++ ACPI_OPERAND_OBJECT *this_internal_obj; ++ ACPI_OBJECT *this_external_obj; ++ ++ ++ /* ++ * First package at head of the buffer ++ */ ++ external_object = (ACPI_OBJECT *)buffer; ++ ++ /* ++ * Free space begins right after the first package ++ */ ++ free_space = buffer + sizeof(ACPI_OBJECT); ++ ++ ++ external_object->type = internal_object->common.type; ++ external_object->package.count = internal_object->package.count; ++ external_object->package.elements = (ACPI_OBJECT *)free_space; ++ ++ ++ /* ++ * Build an array of ACPI_OBJECTS in the buffer ++ * and move the free space past it ++ */ ++ ++ free_space += external_object->package.count * sizeof(ACPI_OBJECT); ++ ++ ++ /* Call Walk_package */ ++ ++} ++ ++#endif /* Future implementation */ ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_copy_eobject_to_iobject ++ * ++ * PARAMETERS: *Internal_object - The external object to be converted ++ * *Buffer_ptr - Where the internal object is returned ++ * ++ * RETURN: Status - the status of the call ++ * ++ * DESCRIPTION: Converts an external object to an internal object. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_copy_eobject_to_iobject ( ++ ACPI_OBJECT *external_object, ++ ACPI_OPERAND_OBJECT *internal_object) ++{ ++ ACPI_STATUS status; ++ ++ ++ if (external_object->type == ACPI_TYPE_PACKAGE) { ++ /* ++ * Package objects contain other objects (which can be objects) ++ * buildpackage does it all ++ * ++ * TBD: Package conversion must be completed and tested ++ * NOTE: this code converts packages as input parameters to ++ * control methods only. This is a very, very rare case. ++ */ ++/* ++ Status = Acpi_cm_copy_epackage_to_ipackage(Internal_object, ++ Ret_buffer->Pointer, ++ &Ret_buffer->Length); ++*/ ++ return (AE_NOT_IMPLEMENTED); ++ } ++ ++ else { ++ /* ++ * Build a simple object (no nested objects) ++ */ ++ status = acpi_cm_copy_esimple_to_isimple (external_object, internal_object); ++ /* ++ * build simple does not include the object size in the length ++ * so we add it in here ++ */ ++ } ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_copy_ielement_to_ielement ++ * ++ * PARAMETERS: ACPI_PKG_CALLBACK ++ * ++ * RETURN: Status - the status of the call ++ * ++ * DESCRIPTION: Copy one package element to another package element ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_copy_ielement_to_ielement ( ++ u8 object_type, ++ ACPI_OPERAND_OBJECT *source_object, ++ ACPI_GENERIC_STATE *state, ++ void *context) ++{ ++ ACPI_STATUS status = AE_OK; ++ u32 this_index; ++ ACPI_OPERAND_OBJECT **this_target_ptr; ++ ACPI_OPERAND_OBJECT *target_object; ++ ++ ++ this_index = state->pkg.index; ++ this_target_ptr = (ACPI_OPERAND_OBJECT **) ++ &state->pkg.dest_object->package.elements[this_index]; ++ ++ switch (object_type) { ++ case 0: ++ ++ /* ++ * This is a simple object, just copy it ++ */ ++ target_object = acpi_cm_create_internal_object (source_object->common.type); ++ if (!target_object) { ++ return (AE_NO_MEMORY); ++ } ++ ++ status = acpi_aml_store_object_to_object (source_object, target_object, ++ (ACPI_WALK_STATE *) context); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ *this_target_ptr = target_object; ++ break; ++ ++ ++ case 1: ++ /* ++ * This object is a package - go down another nesting level ++ * Create and build the package object ++ */ ++ target_object = acpi_cm_create_internal_object (ACPI_TYPE_PACKAGE); ++ if (!target_object) { ++ /* TBD: must delete package created up to this point */ ++ ++ return (AE_NO_MEMORY); ++ } ++ ++ target_object->package.count = source_object->package.count; ++ ++ /* ++ * Pass the new package object back to the package walk routine ++ */ ++ state->pkg.this_target_obj = target_object; ++ ++ /* ++ * Store the object pointer in the parent package object ++ */ ++ *this_target_ptr = target_object; ++ break; ++ ++ default: ++ return (AE_BAD_PARAMETER); ++ } ++ ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_copy_ipackage_to_ipackage ++ * ++ * PARAMETERS: *Source_obj - Pointer to the source package object ++ * *Dest_obj - Where the internal object is returned ++ * ++ * RETURN: Status - the status of the call ++ * ++ * DESCRIPTION: This function is called to copy an internal package object ++ * into another internal package object. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_copy_ipackage_to_ipackage ( ++ ACPI_OPERAND_OBJECT *source_obj, ++ ACPI_OPERAND_OBJECT *dest_obj, ++ ACPI_WALK_STATE *walk_state) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ ++ dest_obj->common.type = source_obj->common.type; ++ dest_obj->package.count = source_obj->package.count; ++ ++ ++ /* ++ * Create the object array and walk the source package tree ++ */ ++ ++ dest_obj->package.elements = acpi_cm_callocate ((source_obj->package.count + 1) * ++ sizeof (void *)); ++ dest_obj->package.next_element = dest_obj->package.elements; ++ ++ if (!dest_obj->package.elements) { ++ REPORT_ERROR ( ++ ("Aml_build_copy_internal_package_object: Package allocation failure\n")); ++ return (AE_NO_MEMORY); ++ } ++ ++ ++ status = acpi_cm_walk_package_tree (source_obj, dest_obj, ++ acpi_cm_copy_ielement_to_ielement, walk_state); ++ ++ return (status); ++} ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/utils/cmdebug.c linux/drivers/acpi/utils/cmdebug.c +--- /usr/src/linux/drivers/acpi/utils/cmdebug.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/utils/cmdebug.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,555 @@ ++/****************************************************************************** ++ * ++ * Module Name: cmdebug - Debug print routines ++ * $Revision: 65 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++ ++#define _COMPONENT ACPI_UTILITIES ++ MODULE_NAME ("cmdebug") ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Get/Set debug level ++ * ++ * DESCRIPTION: Get or set value of the debug flag ++ * ++ * These are used to allow user's to get/set the debug level ++ * ++ ****************************************************************************/ ++ ++ ++u32 ++get_debug_level (void) ++{ ++ ++ return (acpi_dbg_level); ++} ++ ++void ++set_debug_level ( ++ u32 new_debug_level) ++{ ++ ++ acpi_dbg_level = new_debug_level; ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Function_trace ++ * ++ * PARAMETERS: Module_name - Caller's module name (for error output) ++ * Line_number - Caller's line number (for error output) ++ * Component_id - Caller's component ID (for error output) ++ * Function_name - Name of Caller's function ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is ++ * set in Debug_level ++ * ++ ****************************************************************************/ ++ ++void ++function_trace ( ++ NATIVE_CHAR *module_name, ++ u32 line_number, ++ u32 component_id, ++ NATIVE_CHAR *function_name) ++{ ++ ++ acpi_gbl_nesting_level++; ++ ++ debug_print (module_name, line_number, component_id, ++ TRACE_FUNCTIONS, ++ " %2.2ld Entered Function: %s\n", ++ acpi_gbl_nesting_level, function_name); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Function_trace_ptr ++ * ++ * PARAMETERS: Module_name - Caller's module name (for error output) ++ * Line_number - Caller's line number (for error output) ++ * Component_id - Caller's component ID (for error output) ++ * Function_name - Name of Caller's function ++ * Pointer - Pointer to display ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is ++ * set in Debug_level ++ * ++ ****************************************************************************/ ++ ++void ++function_trace_ptr ( ++ NATIVE_CHAR *module_name, ++ u32 line_number, ++ u32 component_id, ++ NATIVE_CHAR *function_name, ++ void *pointer) ++{ ++ ++ acpi_gbl_nesting_level++; ++ debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS, ++ " %2.2ld Entered Function: %s, %p\n", ++ acpi_gbl_nesting_level, function_name, pointer); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Function_trace_str ++ * ++ * PARAMETERS: Module_name - Caller's module name (for error output) ++ * Line_number - Caller's line number (for error output) ++ * Component_id - Caller's component ID (for error output) ++ * Function_name - Name of Caller's function ++ * String - Additional string to display ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is ++ * set in Debug_level ++ * ++ ****************************************************************************/ ++ ++void ++function_trace_str ( ++ NATIVE_CHAR *module_name, ++ u32 line_number, ++ u32 component_id, ++ NATIVE_CHAR *function_name, ++ NATIVE_CHAR *string) ++{ ++ ++ acpi_gbl_nesting_level++; ++ debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS, ++ " %2.2ld Entered Function: %s, %s\n", ++ acpi_gbl_nesting_level, function_name, string); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Function_trace_u32 ++ * ++ * PARAMETERS: Module_name - Caller's module name (for error output) ++ * Line_number - Caller's line number (for error output) ++ * Component_id - Caller's component ID (for error output) ++ * Function_name - Name of Caller's function ++ * Integer - Integer to display ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is ++ * set in Debug_level ++ * ++ ****************************************************************************/ ++ ++void ++function_trace_u32 ( ++ NATIVE_CHAR *module_name, ++ u32 line_number, ++ u32 component_id, ++ NATIVE_CHAR *function_name, ++ u32 integer) ++{ ++ ++ acpi_gbl_nesting_level++; ++ debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS, ++ " %2.2ld Entered Function: %s, %lX\n", ++ acpi_gbl_nesting_level, function_name, integer); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Function_exit ++ * ++ * PARAMETERS: Module_name - Caller's module name (for error output) ++ * Line_number - Caller's line number (for error output) ++ * Component_id - Caller's component ID (for error output) ++ * Function_name - Name of Caller's function ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is ++ * set in Debug_level ++ * ++ ****************************************************************************/ ++ ++void ++function_exit ( ++ NATIVE_CHAR *module_name, ++ u32 line_number, ++ u32 component_id, ++ NATIVE_CHAR *function_name) ++{ ++ ++ debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS, ++ " %2.2ld Exiting Function: %s\n", ++ acpi_gbl_nesting_level, function_name); ++ ++ acpi_gbl_nesting_level--; ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Function_status_exit ++ * ++ * PARAMETERS: Module_name - Caller's module name (for error output) ++ * Line_number - Caller's line number (for error output) ++ * Component_id - Caller's component ID (for error output) ++ * Function_name - Name of Caller's function ++ * Status - Exit status code ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is ++ * set in Debug_level. Prints exit status also. ++ * ++ ****************************************************************************/ ++ ++void ++function_status_exit ( ++ NATIVE_CHAR *module_name, ++ u32 line_number, ++ u32 component_id, ++ NATIVE_CHAR *function_name, ++ ACPI_STATUS status) ++{ ++ ++ debug_print (module_name, line_number, component_id, ++ TRACE_FUNCTIONS, ++ " %2.2ld Exiting Function: %s, %s\n", ++ acpi_gbl_nesting_level, ++ function_name, ++ acpi_cm_format_exception (status)); ++ ++ acpi_gbl_nesting_level--; ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Function_value_exit ++ * ++ * PARAMETERS: Module_name - Caller's module name (for error output) ++ * Line_number - Caller's line number (for error output) ++ * Component_id - Caller's component ID (for error output) ++ * Function_name - Name of Caller's function ++ * Value - Value to be printed with exit msg ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is ++ * set in Debug_level. Prints exit value also. ++ * ++ ****************************************************************************/ ++ ++void ++function_value_exit ( ++ NATIVE_CHAR *module_name, ++ u32 line_number, ++ u32 component_id, ++ NATIVE_CHAR *function_name, ++ ACPI_INTEGER value) ++{ ++ ++ debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS, ++ " %2.2ld Exiting Function: %s, %X\n", ++ acpi_gbl_nesting_level, function_name, value); ++ ++ acpi_gbl_nesting_level--; ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Function_ptr_exit ++ * ++ * PARAMETERS: Module_name - Caller's module name (for error output) ++ * Line_number - Caller's line number (for error output) ++ * Component_id - Caller's component ID (for error output) ++ * Function_name - Name of Caller's function ++ * Value - Value to be printed with exit msg ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is ++ * set in Debug_level. Prints exit value also. ++ * ++ ****************************************************************************/ ++ ++void ++function_ptr_exit ( ++ NATIVE_CHAR *module_name, ++ u32 line_number, ++ u32 component_id, ++ NATIVE_CHAR *function_name, ++ u8 *ptr) ++{ ++ ++ debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS, ++ " %2.2ld Exiting Function: %s, %p\n", ++ acpi_gbl_nesting_level, function_name, ptr); ++ ++ acpi_gbl_nesting_level--; ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Debug_print ++ * ++ * PARAMETERS: Module_name - Caller's module name (for error output) ++ * Line_number - Caller's line number (for error output) ++ * Component_id - Caller's component ID (for error output) ++ * Print_level - Requested debug print level ++ * Format - Printf format field ++ * ... - Optional printf arguments ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Print error message with prefix consisting of the module name, ++ * line number, and component ID. ++ * ++ ****************************************************************************/ ++ ++void ++debug_print ( ++ NATIVE_CHAR *module_name, ++ u32 line_number, ++ u32 component_id, ++ u32 print_level, ++ NATIVE_CHAR *format, ++ ...) ++{ ++ va_list args; ++ ++ ++ /* Both the level and the component must be enabled */ ++ ++ if ((print_level & acpi_dbg_level) && ++ (component_id & acpi_dbg_layer)) { ++ va_start (args, format); ++ ++ acpi_os_printf ("%8s-%04d: ", module_name, line_number); ++ acpi_os_vprintf (format, args); ++ } ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Debug_print_prefix ++ * ++ * PARAMETERS: Module_name - Caller's module name (for error output) ++ * Line_number - Caller's line number (for error output) ++ * Component_id - Caller's component ID (for error output) ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Print the prefix part of an error message, consisting of the ++ * module name, and line number ++ * ++ ****************************************************************************/ ++ ++void ++debug_print_prefix ( ++ NATIVE_CHAR *module_name, ++ u32 line_number) ++{ ++ ++ ++ acpi_os_printf ("%8s-%04d: ", module_name, line_number); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Debug_print_raw ++ * ++ * PARAMETERS: Format - Printf format field ++ * ... - Optional printf arguments ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Print error message -- without module/line indentifiers ++ * ++ ****************************************************************************/ ++ ++void ++debug_print_raw ( ++ NATIVE_CHAR *format, ++ ...) ++{ ++ va_list args; ++ ++ ++ va_start (args, format); ++ ++ acpi_os_vprintf (format, args); ++ ++ va_end (args); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Acpi_cm_dump_buffer ++ * ++ * PARAMETERS: Buffer - Buffer to dump ++ * Count - Amount to dump, in bytes ++ * Component_iD - Caller's component ID ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Generic dump buffer in both hex and ascii. ++ * ++ ****************************************************************************/ ++ ++void ++acpi_cm_dump_buffer ( ++ u8 *buffer, ++ u32 count, ++ u32 display, ++ u32 component_id) ++{ ++ u32 i = 0; ++ u32 j; ++ u32 temp32; ++ u8 buf_char; ++ ++ ++ /* Only dump the buffer if tracing is enabled */ ++ ++ if (!((TRACE_TABLES & acpi_dbg_level) && ++ (component_id & acpi_dbg_layer))) { ++ return; ++ } ++ ++ ++ /* ++ * Nasty little dump buffer routine! ++ */ ++ while (i < count) { ++ /* Print current offset */ ++ ++ acpi_os_printf ("%05X ", i); ++ ++ ++ /* Print 16 hex chars */ ++ ++ for (j = 0; j < 16;) { ++ if (i + j >= count) { ++ acpi_os_printf ("\n"); ++ return; ++ } ++ ++ /* Make sure that the s8 doesn't get sign-extended! */ ++ ++ switch (display) { ++ /* Default is BYTE display */ ++ ++ default: ++ ++ acpi_os_printf ("%02X ", ++ *((u8 *) &buffer[i + j])); ++ j += 1; ++ break; ++ ++ ++ case DB_WORD_DISPLAY: ++ ++ MOVE_UNALIGNED16_TO_32 (&temp32, ++ &buffer[i + j]); ++ acpi_os_printf ("%04X ", temp32); ++ j += 2; ++ break; ++ ++ ++ case DB_DWORD_DISPLAY: ++ ++ MOVE_UNALIGNED32_TO_32 (&temp32, ++ &buffer[i + j]); ++ acpi_os_printf ("%08X ", temp32); ++ j += 4; ++ break; ++ ++ ++ case DB_QWORD_DISPLAY: ++ ++ MOVE_UNALIGNED32_TO_32 (&temp32, ++ &buffer[i + j]); ++ acpi_os_printf ("%08X", temp32); ++ ++ MOVE_UNALIGNED32_TO_32 (&temp32, ++ &buffer[i + j + 4]); ++ acpi_os_printf ("%08X ", temp32); ++ j += 8; ++ break; ++ } ++ } ++ ++ ++ /* ++ * Print the ASCII equivalent characters ++ * But watch out for the bad unprintable ones... ++ */ ++ ++ for (j = 0; j < 16; j++) { ++ if (i + j >= count) { ++ acpi_os_printf ("\n"); ++ return; ++ } ++ ++ buf_char = buffer[i + j]; ++ if ((buf_char > 0x1F && buf_char < 0x2E) || ++ (buf_char > 0x2F && buf_char < 0x61) || ++ (buf_char > 0x60 && buf_char < 0x7F)) { ++ acpi_os_printf ("%c", buf_char); ++ } ++ else { ++ acpi_os_printf ("."); ++ } ++ } ++ ++ /* Done with that line. */ ++ ++ acpi_os_printf ("\n"); ++ i += 16; ++ } ++ ++ return; ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/utils/cmdelete.c linux/drivers/acpi/utils/cmdelete.c +--- /usr/src/linux/drivers/acpi/utils/cmdelete.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/utils/cmdelete.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,605 @@ ++/******************************************************************************* ++ * ++ * Module Name: cmdelete - object deletion and reference count utilities ++ * $Revision: 68 $ ++ * ++ ******************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acinterp.h" ++#include "acnamesp.h" ++#include "actables.h" ++#include "acparser.h" ++ ++#define _COMPONENT ACPI_UTILITIES ++ MODULE_NAME ("cmdelete") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_delete_internal_obj ++ * ++ * PARAMETERS: *Object - Pointer to the list to be deleted ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Low level object deletion, after reference counts have been ++ * updated (All reference counts, including sub-objects!) ++ * ++ ******************************************************************************/ ++ ++void ++acpi_cm_delete_internal_obj ( ++ ACPI_OPERAND_OBJECT *object) ++{ ++ void *obj_pointer = NULL; ++ ACPI_OPERAND_OBJECT *handler_desc; ++ ++ ++ if (!object) { ++ return; ++ } ++ ++ /* ++ * Must delete or free any pointers within the object that are not ++ * actual ACPI objects (for example, a raw buffer pointer). ++ */ ++ ++ switch (object->common.type) { ++ ++ case ACPI_TYPE_STRING: ++ ++ /* Free the actual string buffer */ ++ ++ obj_pointer = object->string.pointer; ++ break; ++ ++ ++ case ACPI_TYPE_BUFFER: ++ ++ /* Free the actual buffer */ ++ ++ obj_pointer = object->buffer.pointer; ++ break; ++ ++ ++ case ACPI_TYPE_PACKAGE: ++ ++ /* ++ * Elements of the package are not handled here, they are deleted ++ * separately ++ */ ++ ++ /* Free the (variable length) element pointer array */ ++ ++ obj_pointer = object->package.elements; ++ break; ++ ++ ++ case ACPI_TYPE_MUTEX: ++ ++ acpi_aml_unlink_mutex (object); ++ acpi_os_delete_semaphore (object->mutex.semaphore); ++ break; ++ ++ ++ case ACPI_TYPE_EVENT: ++ ++ acpi_os_delete_semaphore (object->event.semaphore); ++ object->event.semaphore = NULL; ++ break; ++ ++ ++ case ACPI_TYPE_METHOD: ++ ++ /* Delete the method semaphore if it exists */ ++ ++ if (object->method.semaphore) { ++ acpi_os_delete_semaphore (object->method.semaphore); ++ object->method.semaphore = NULL; ++ } ++ ++ break; ++ ++ ++ case ACPI_TYPE_REGION: ++ ++ ++ if (object->region.extra) { ++ /* ++ * Free the Region_context if and only if the handler is one of the ++ * default handlers -- and therefore, we created the context object ++ * locally, it was not created by an external caller. ++ */ ++ handler_desc = object->region.addr_handler; ++ if ((handler_desc) && ++ (handler_desc->addr_handler.hflags == ADDR_HANDLER_DEFAULT_INSTALLED)) { ++ obj_pointer = object->region.extra->extra.region_context; ++ } ++ ++ /* Now we can free the Extra object */ ++ ++ acpi_cm_delete_object_desc (object->region.extra); ++ } ++ break; ++ ++ ++ case ACPI_TYPE_BUFFER_FIELD: ++ ++ if (object->buffer_field.extra) { ++ acpi_cm_delete_object_desc (object->buffer_field.extra); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ ++ /* ++ * Delete any allocated memory found above ++ */ ++ ++ if (obj_pointer) { ++ if (!acpi_tb_system_table_pointer (obj_pointer)) { ++ acpi_cm_free (obj_pointer); ++ } ++ } ++ ++ ++ /* Only delete the object if it was dynamically allocated */ ++ ++ ++ if (!(object->common.flags & AOPOBJ_STATIC_ALLOCATION)) { ++ acpi_cm_delete_object_desc (object); ++ ++ } ++ ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_delete_internal_object_list ++ * ++ * PARAMETERS: *Obj_list - Pointer to the list to be deleted ++ * ++ * RETURN: Status - the status of the call ++ * ++ * DESCRIPTION: This function deletes an internal object list, including both ++ * simple objects and package objects ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_delete_internal_object_list ( ++ ACPI_OPERAND_OBJECT **obj_list) ++{ ++ ACPI_OPERAND_OBJECT **internal_obj; ++ ++ ++ /* Walk the null-terminated internal list */ ++ ++ for (internal_obj = obj_list; *internal_obj; internal_obj++) { ++ /* ++ * Check for a package ++ * Simple objects are simply stored in the array and do not ++ * need to be deleted separately. ++ */ ++ ++ if (IS_THIS_OBJECT_TYPE ((*internal_obj), ACPI_TYPE_PACKAGE)) { ++ /* Delete the package */ ++ ++ /* ++ * TBD: [Investigate] This might not be the right thing to do, ++ * depending on how the internal package object was allocated!!! ++ */ ++ acpi_cm_delete_internal_obj (*internal_obj); ++ } ++ ++ } ++ ++ /* Free the combined parameter pointer list and object array */ ++ ++ acpi_cm_free (obj_list); ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_update_ref_count ++ * ++ * PARAMETERS: *Object - Object whose ref count is to be updated ++ * Action - What to do ++ * ++ * RETURN: New ref count ++ * ++ * DESCRIPTION: Modify the ref count and return it. ++ * ++ ******************************************************************************/ ++ ++static void ++acpi_cm_update_ref_count ( ++ ACPI_OPERAND_OBJECT *object, ++ u32 action) ++{ ++ u16 count; ++ u16 new_count; ++ ++ ++ if (!object) { ++ return; ++ } ++ ++ ++ count = object->common.reference_count; ++ new_count = count; ++ ++ /* ++ * Reference count action (increment, decrement, or force delete) ++ */ ++ ++ switch (action) { ++ ++ case REF_INCREMENT: ++ ++ new_count++; ++ object->common.reference_count = new_count; ++ ++ break; ++ ++ ++ case REF_DECREMENT: ++ ++ if (count < 1) { ++ new_count = 0; ++ } ++ ++ else { ++ new_count--; ++ ++ } ++ ++ ++ object->common.reference_count = new_count; ++ if (new_count == 0) { ++ acpi_cm_delete_internal_obj (object); ++ } ++ ++ break; ++ ++ ++ case REF_FORCE_DELETE: ++ ++ new_count = 0; ++ object->common.reference_count = new_count; ++ acpi_cm_delete_internal_obj (object); ++ break; ++ ++ ++ default: ++ ++ break; ++ } ++ ++ ++ /* ++ * Sanity check the reference count, for debug purposes only. ++ * (A deleted object will have a huge reference count) ++ */ ++ ++ ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_update_object_reference ++ * ++ * PARAMETERS: *Object - Increment ref count for this object ++ * and all sub-objects ++ * Action - Either REF_INCREMENT or REF_DECREMENT or ++ * REF_FORCE_DELETE ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Increment the object reference count ++ * ++ * Object references are incremented when: ++ * 1) An object is attached to a Node (namespace object) ++ * 2) An object is copied (all subobjects must be incremented) ++ * ++ * Object references are decremented when: ++ * 1) An object is detached from an Node ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_update_object_reference ( ++ ACPI_OPERAND_OBJECT *object, ++ u16 action) ++{ ++ ACPI_STATUS status; ++ u32 i; ++ ACPI_OPERAND_OBJECT *next; ++ ACPI_OPERAND_OBJECT *new; ++ ACPI_GENERIC_STATE *state_list = NULL; ++ ACPI_GENERIC_STATE *state; ++ ++ ++ /* Ignore a null object ptr */ ++ ++ if (!object) { ++ return (AE_OK); ++ } ++ ++ ++ /* ++ * Make sure that this isn't a namespace handle or an AML pointer ++ */ ++ ++ if (VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_NAMED)) { ++ return (AE_OK); ++ } ++ ++ if (acpi_tb_system_table_pointer (object)) { ++ return (AE_OK); ++ } ++ ++ ++ state = acpi_cm_create_update_state (object, action); ++ ++ while (state) { ++ ++ object = state->update.object; ++ action = state->update.value; ++ acpi_cm_delete_generic_state (state); ++ ++ /* ++ * All sub-objects must have their reference count incremented also. ++ * Different object types have different subobjects. ++ */ ++ switch (object->common.type) { ++ ++ case ACPI_TYPE_DEVICE: ++ ++ status = acpi_cm_create_update_state_and_push (object->device.addr_handler, ++ action, &state_list); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ acpi_cm_update_ref_count (object->device.sys_handler, action); ++ acpi_cm_update_ref_count (object->device.drv_handler, action); ++ break; ++ ++ ++ case INTERNAL_TYPE_ADDRESS_HANDLER: ++ ++ /* Must walk list of address handlers */ ++ ++ next = object->addr_handler.next; ++ while (next) { ++ new = next->addr_handler.next; ++ acpi_cm_update_ref_count (next, action); ++ ++ next = new; ++ } ++ break; ++ ++ ++ case ACPI_TYPE_PACKAGE: ++ ++ /* ++ * We must update all the sub-objects of the package ++ * (Each of whom may have their own sub-objects, etc. ++ */ ++ for (i = 0; i < object->package.count; i++) { ++ /* ++ * Push each element onto the stack for later processing. ++ * Note: There can be null elements within the package, ++ * these are simply ignored ++ */ ++ ++ status = acpi_cm_create_update_state_and_push ( ++ object->package.elements[i], action, &state_list); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ } ++ break; ++ ++ ++ case ACPI_TYPE_BUFFER_FIELD: ++ ++ status = acpi_cm_create_update_state_and_push ( ++ object->buffer_field.buffer_obj, action, &state_list); ++ ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ break; ++ ++ ++ case INTERNAL_TYPE_REGION_FIELD: ++ ++ status = acpi_cm_create_update_state_and_push ( ++ object->field.region_obj, action, &state_list); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ break; ++ ++ ++ case INTERNAL_TYPE_BANK_FIELD: ++ ++ status = acpi_cm_create_update_state_and_push ( ++ object->bank_field.bank_register_obj, action, &state_list); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ status = acpi_cm_create_update_state_and_push ( ++ object->bank_field.region_obj, action, &state_list); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ break; ++ ++ ++ case INTERNAL_TYPE_INDEX_FIELD: ++ ++ status = acpi_cm_create_update_state_and_push ( ++ object->index_field.index_obj, action, &state_list); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ status = acpi_cm_create_update_state_and_push ( ++ object->index_field.data_obj, action, &state_list); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ break; ++ ++ ++ case ACPI_TYPE_REGION: ++ ++ /* TBD: [Investigate] ++ Acpi_cm_update_ref_count (Object->Region.Addr_handler, Action); ++ */ ++/* ++ Status = ++ Acpi_cm_create_update_state_and_push (Object->Region.Addr_handler, ++ Action, &State_list); ++ if (ACPI_FAILURE (Status)) ++ { ++ return (Status); ++ } ++*/ ++ break; ++ ++ ++ case INTERNAL_TYPE_REFERENCE: ++ ++ break; ++ } ++ ++ ++ /* ++ * Now we can update the count in the main object. This can only ++ * happen after we update the sub-objects in case this causes the ++ * main object to be deleted. ++ */ ++ ++ acpi_cm_update_ref_count (object, action); ++ ++ ++ /* Move on to the next object to be updated */ ++ ++ state = acpi_cm_pop_generic_state (&state_list); ++ } ++ ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_add_reference ++ * ++ * PARAMETERS: *Object - Object whose reference count is to be ++ * incremented ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Add one reference to an ACPI object ++ * ++ ******************************************************************************/ ++ ++void ++acpi_cm_add_reference ( ++ ACPI_OPERAND_OBJECT *object) ++{ ++ ++ ++ /* ++ * Ensure that we have a valid object ++ */ ++ ++ if (!acpi_cm_valid_internal_object (object)) { ++ return; ++ } ++ ++ /* ++ * We have a valid ACPI internal object, now increment the reference count ++ */ ++ ++ acpi_cm_update_object_reference (object, REF_INCREMENT); ++ ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_remove_reference ++ * ++ * PARAMETERS: *Object - Object whose ref count will be decremented ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Decrement the reference count of an ACPI internal object ++ * ++ ******************************************************************************/ ++ ++void ++acpi_cm_remove_reference ( ++ ACPI_OPERAND_OBJECT *object) ++{ ++ ++ ++ /* ++ * Ensure that we have a valid object ++ */ ++ ++ if (!acpi_cm_valid_internal_object (object)) { ++ return; ++ } ++ ++ /* ++ * Decrement the reference count, and only actually delete the object ++ * if the reference count becomes 0. (Must also decrement the ref count ++ * of all subobjects!) ++ */ ++ ++ acpi_cm_update_object_reference (object, REF_DECREMENT); ++ ++ return; ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/utils/cmeval.c linux/drivers/acpi/utils/cmeval.c +--- /usr/src/linux/drivers/acpi/utils/cmeval.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/utils/cmeval.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,306 @@ ++/****************************************************************************** ++ * ++ * Module Name: cmeval - Object evaluation ++ * $Revision: 23 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acnamesp.h" ++#include "acinterp.h" ++ ++ ++#define _COMPONENT ACPI_UTILITIES ++ MODULE_NAME ("cmeval") ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: Acpi_cm_evaluate_numeric_object ++ * ++ * PARAMETERS: *Object_name - Object name to be evaluated ++ * Device_node - Node for the device ++ * *Address - Where the value is returned ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: evaluates a numeric namespace object for a selected device ++ * and stores results in *Address. ++ * ++ * NOTE: Internal function, no parameter validation ++ * ++ ***************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_evaluate_numeric_object ( ++ NATIVE_CHAR *object_name, ++ ACPI_NAMESPACE_NODE *device_node, ++ ACPI_INTEGER *address) ++{ ++ ACPI_OPERAND_OBJECT *obj_desc; ++ ACPI_STATUS status; ++ ++ ++ /* Execute the method */ ++ ++ status = acpi_ns_evaluate_relative (device_node, object_name, NULL, &obj_desc); ++ if (ACPI_FAILURE (status)) { ++ ++ return (status); ++ } ++ ++ ++ /* Did we get a return object? */ ++ ++ if (!obj_desc) { ++ return (AE_TYPE); ++ } ++ ++ /* Is the return object of the correct type? */ ++ ++ if (obj_desc->common.type != ACPI_TYPE_INTEGER) { ++ status = AE_TYPE; ++ } ++ else { ++ /* ++ * Since the structure is a union, setting any field will set all ++ * of the variables in the union ++ */ ++ *address = obj_desc->integer.value; ++ } ++ ++ /* On exit, we must delete the return object */ ++ ++ acpi_cm_remove_reference (obj_desc); ++ ++ return (status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: Acpi_cm_execute_HID ++ * ++ * PARAMETERS: Device_node - Node for the device ++ * *Hid - Where the HID is returned ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Executes the _HID control method that returns the hardware ++ * ID of the device. ++ * ++ * NOTE: Internal function, no parameter validation ++ * ++ ***************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_execute_HID ( ++ ACPI_NAMESPACE_NODE *device_node, ++ DEVICE_ID *hid) ++{ ++ ACPI_OPERAND_OBJECT *obj_desc; ++ ACPI_STATUS status; ++ ++ ++ /* Execute the method */ ++ ++ status = acpi_ns_evaluate_relative (device_node, ++ METHOD_NAME__HID, NULL, &obj_desc); ++ if (ACPI_FAILURE (status)) { ++ ++ ++ return (status); ++ } ++ ++ /* Did we get a return object? */ ++ ++ if (!obj_desc) { ++ return (AE_TYPE); ++ } ++ ++ /* ++ * A _HID can return either a Number (32 bit compressed EISA ID) or ++ * a string ++ */ ++ ++ if ((obj_desc->common.type != ACPI_TYPE_INTEGER) && ++ (obj_desc->common.type != ACPI_TYPE_STRING)) { ++ status = AE_TYPE; ++ } ++ ++ else { ++ if (obj_desc->common.type == ACPI_TYPE_INTEGER) { ++ /* Convert the Numeric HID to string */ ++ ++ acpi_aml_eisa_id_to_string ((u32) obj_desc->integer.value, hid->buffer); ++ } ++ ++ else { ++ /* Copy the String HID from the returned object */ ++ ++ STRNCPY(hid->buffer, obj_desc->string.pointer, sizeof(hid->buffer)); ++ } ++ } ++ ++ ++ /* On exit, we must delete the return object */ ++ ++ acpi_cm_remove_reference (obj_desc); ++ ++ return (status); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: Acpi_cm_execute_UID ++ * ++ * PARAMETERS: Device_node - Node for the device ++ * *Uid - Where the UID is returned ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Executes the _UID control method that returns the hardware ++ * ID of the device. ++ * ++ * NOTE: Internal function, no parameter validation ++ * ++ ***************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_execute_UID ( ++ ACPI_NAMESPACE_NODE *device_node, ++ DEVICE_ID *uid) ++{ ++ ACPI_OPERAND_OBJECT *obj_desc; ++ ACPI_STATUS status; ++ ++ ++ /* Execute the method */ ++ ++ status = acpi_ns_evaluate_relative (device_node, ++ METHOD_NAME__UID, NULL, &obj_desc); ++ if (ACPI_FAILURE (status)) { ++ ++ ++ return (status); ++ } ++ ++ /* Did we get a return object? */ ++ ++ if (!obj_desc) { ++ return (AE_TYPE); ++ } ++ ++ /* ++ * A _UID can return either a Number (32 bit compressed EISA ID) or ++ * a string ++ */ ++ ++ if ((obj_desc->common.type != ACPI_TYPE_INTEGER) && ++ (obj_desc->common.type != ACPI_TYPE_STRING)) { ++ status = AE_TYPE; ++ } ++ ++ else { ++ if (obj_desc->common.type == ACPI_TYPE_INTEGER) { ++ /* Convert the Numeric UID to string */ ++ ++ acpi_aml_unsigned_integer_to_string (obj_desc->integer.value, uid->buffer); ++ } ++ ++ else { ++ /* Copy the String UID from the returned object */ ++ ++ STRNCPY(uid->buffer, obj_desc->string.pointer, sizeof(uid->buffer)); ++ } ++ } ++ ++ ++ /* On exit, we must delete the return object */ ++ ++ acpi_cm_remove_reference (obj_desc); ++ ++ return (status); ++} ++ ++/**************************************************************************** ++ * ++ * FUNCTION: Acpi_cm_execute_STA ++ * ++ * PARAMETERS: Device_node - Node for the device ++ * *Flags - Where the status flags are returned ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Executes _STA for selected device and stores results in ++ * *Flags. ++ * ++ * NOTE: Internal function, no parameter validation ++ * ++ ***************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_execute_STA ( ++ ACPI_NAMESPACE_NODE *device_node, ++ u32 *flags) ++{ ++ ACPI_OPERAND_OBJECT *obj_desc; ++ ACPI_STATUS status; ++ ++ ++ /* Execute the method */ ++ ++ status = acpi_ns_evaluate_relative (device_node, ++ METHOD_NAME__STA, NULL, &obj_desc); ++ if (AE_NOT_FOUND == status) { ++ *flags = 0x0F; ++ status = AE_OK; ++ } ++ ++ ++ else /* success */ { ++ /* Did we get a return object? */ ++ ++ if (!obj_desc) { ++ return (AE_TYPE); ++ } ++ ++ /* Is the return object of the correct type? */ ++ ++ if (obj_desc->common.type != ACPI_TYPE_INTEGER) { ++ status = AE_TYPE; ++ } ++ ++ else { ++ /* Extract the status flags */ ++ ++ *flags = (u32) obj_desc->integer.value; ++ } ++ ++ /* On exit, we must delete the return object */ ++ ++ acpi_cm_remove_reference (obj_desc); ++ } ++ ++ return (status); ++} +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/utils/cmglobal.c linux/drivers/acpi/utils/cmglobal.c +--- /usr/src/linux/drivers/acpi/utils/cmglobal.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/utils/cmglobal.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,482 @@ ++/****************************************************************************** ++ * ++ * Module Name: cmglobal - Global variables for the ACPI subsystem ++ * $Revision: 121 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * 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 ++ */ ++ ++#define DEFINE_ACPI_GLOBALS ++ ++#include "acpi.h" ++#include "acevents.h" ++#include "acnamesp.h" ++#include "acinterp.h" ++#include "amlcode.h" ++ ++ ++#define _COMPONENT ACPI_UTILITIES ++ MODULE_NAME ("cmglobal") ++ ++ ++/****************************************************************************** ++ * ++ * Static global variable initialization. ++ * ++ ******************************************************************************/ ++ ++/* ++ * We want the debug switches statically initialized so they ++ * are already set when the debugger is entered. ++ */ ++ ++/* Debug switch - level and trace mask */ ++ ++u32 acpi_dbg_level = NORMAL_DEFAULT; ++ ++/* Debug switch - layer (component) mask */ ++ ++u32 acpi_dbg_layer = ACPI_COMPONENT_DEFAULT; ++u32 acpi_gbl_nesting_level = 0; ++ ++ ++/* Debugger globals */ ++ ++u8 acpi_gbl_db_terminate_threads = FALSE; ++u8 acpi_gbl_method_executing = FALSE; ++ ++/* System flags */ ++ ++u32 acpi_gbl_system_flags = 0; ++u32 acpi_gbl_startup_flags = 0; ++ ++/* System starts unitialized! */ ++u8 acpi_gbl_shutdown = TRUE; ++ ++ ++u8 acpi_gbl_decode_to8bit [8] = {1,2,4,8,16,32,64,128}; ++ ++ ++/****************************************************************************** ++ * ++ * Namespace globals ++ * ++ ******************************************************************************/ ++ ++ ++/* ++ * Names built-in to the interpreter ++ * ++ * Initial values are currently supported only for types String and Number. ++ * To avoid type punning, both are specified as strings in this table. ++ * ++ * NOTES: ++ * 1) _SB_ is defined to be a device to allow _SB_/_INI to be run ++ * during the initialization sequence. ++ */ ++ ++PREDEFINED_NAMES acpi_gbl_pre_defined_names[] = ++{ {"_GPE", INTERNAL_TYPE_DEF_ANY}, ++ {"_PR_", INTERNAL_TYPE_DEF_ANY}, ++ {"_SB_", ACPI_TYPE_DEVICE}, ++ {"_SI_", INTERNAL_TYPE_DEF_ANY}, ++ {"_TZ_", INTERNAL_TYPE_DEF_ANY}, ++ {"_REV", ACPI_TYPE_INTEGER, "2"}, ++ {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME}, ++ {"_GL_", ACPI_TYPE_MUTEX, "0"}, ++ {NULL, ACPI_TYPE_ANY} /* Table terminator */ ++}; ++ ++ ++/* ++ * Properties of the ACPI Object Types, both internal and external. ++ * ++ * Elements of Acpi_ns_properties are bit significant ++ * and the table is indexed by values of ACPI_OBJECT_TYPE ++ */ ++ ++u8 acpi_gbl_ns_properties[] = ++{ ++ NSP_NORMAL, /* 00 Any */ ++ NSP_NORMAL, /* 01 Number */ ++ NSP_NORMAL, /* 02 String */ ++ NSP_NORMAL, /* 03 Buffer */ ++ NSP_LOCAL, /* 04 Package */ ++ NSP_NORMAL, /* 05 Field_unit */ ++ NSP_NEWSCOPE | NSP_LOCAL, /* 06 Device */ ++ NSP_LOCAL, /* 07 Acpi_event */ ++ NSP_NEWSCOPE | NSP_LOCAL, /* 08 Method */ ++ NSP_LOCAL, /* 09 Mutex */ ++ NSP_LOCAL, /* 10 Region */ ++ NSP_NEWSCOPE | NSP_LOCAL, /* 11 Power */ ++ NSP_NEWSCOPE | NSP_LOCAL, /* 12 Processor */ ++ NSP_NEWSCOPE | NSP_LOCAL, /* 13 Thermal */ ++ NSP_NORMAL, /* 14 Buffer_field */ ++ NSP_NORMAL, /* 15 Ddb_handle */ ++ NSP_NORMAL, /* 16 Debug Object */ ++ NSP_NORMAL, /* 17 Def_field */ ++ NSP_NORMAL, /* 18 Bank_field */ ++ NSP_NORMAL, /* 19 Index_field */ ++ NSP_NORMAL, /* 20 Reference */ ++ NSP_NORMAL, /* 21 Alias */ ++ NSP_NORMAL, /* 22 Notify */ ++ NSP_NORMAL, /* 23 Address Handler */ ++ NSP_NEWSCOPE | NSP_LOCAL, /* 24 Resource */ ++ NSP_NORMAL, /* 25 Def_field_defn */ ++ NSP_NORMAL, /* 26 Bank_field_defn */ ++ NSP_NORMAL, /* 27 Index_field_defn */ ++ NSP_NORMAL, /* 28 If */ ++ NSP_NORMAL, /* 29 Else */ ++ NSP_NORMAL, /* 30 While */ ++ NSP_NEWSCOPE, /* 31 Scope */ ++ NSP_LOCAL, /* 32 Def_any */ ++ NSP_NORMAL, /* 33 Extra */ ++ NSP_NORMAL /* 34 Invalid */ ++}; ++ ++ ++/* Hex to ASCII conversion table */ ++ ++NATIVE_CHAR acpi_gbl_hex_to_ascii[] = ++ {'0','1','2','3','4','5','6','7', ++ '8','9','A','B','C','D','E','F'}; ++ ++ ++/****************************************************************************** ++ * ++ * Table globals ++ * ++ * NOTE: This table includes ONLY the ACPI tables that the subsystem consumes. ++ * it is NOT an exhaustive list of all possible ACPI tables. All ACPI tables ++ * that are not used by the subsystem are simply ignored. ++ * ++ ******************************************************************************/ ++ ++ ++ACPI_TABLE_DESC acpi_gbl_acpi_tables[NUM_ACPI_TABLES]; ++ ++ ++ACPI_TABLE_SUPPORT acpi_gbl_acpi_table_data[NUM_ACPI_TABLES] = ++{ ++ /*********** Name, Signature, Signature size, How many allowed?, Supported? Global typed pointer */ ++ ++ /* RSDP 0 */ {RSDP_NAME, RSDP_SIG, sizeof (RSDP_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, NULL}, ++ /* DSDT 1 */ {DSDT_SIG, DSDT_SIG, sizeof (DSDT_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, (void **) &acpi_gbl_DSDT}, ++ /* FADT 2 */ {FADT_SIG, FADT_SIG, sizeof (FADT_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, (void **) &acpi_gbl_FADT}, ++ /* FACS 3 */ {FACS_SIG, FACS_SIG, sizeof (FACS_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, (void **) &acpi_gbl_FACS}, ++ /* PSDT 4 */ {PSDT_SIG, PSDT_SIG, sizeof (PSDT_SIG)-1, ACPI_TABLE_MULTIPLE, AE_OK, NULL}, ++ /* SSDT 5 */ {SSDT_SIG, SSDT_SIG, sizeof (SSDT_SIG)-1, ACPI_TABLE_MULTIPLE, AE_OK, NULL}, ++ /* XSDT 6 */ {XSDT_SIG, XSDT_SIG, sizeof (RSDT_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, NULL}, ++}; ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Acpi_cm_valid_object_type ++ * ++ * PARAMETERS: None. ++ * ++ * RETURN: TRUE if valid object type ++ * ++ * DESCRIPTION: Validate an object type ++ * ++ ****************************************************************************/ ++ ++u8 ++acpi_cm_valid_object_type ( ++ u32 type) ++{ ++ ++ if (type > ACPI_TYPE_MAX) ++ { ++ if ((type < INTERNAL_TYPE_BEGIN) || ++ (type > INTERNAL_TYPE_MAX)) ++ { ++ return (FALSE); ++ } ++ } ++ ++ return (TRUE); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Acpi_cm_format_exception ++ * ++ * PARAMETERS: Status - Acpi status to be formatted ++ * ++ * RETURN: Formatted status string ++ * ++ * DESCRIPTION: Convert an ACPI exception to a string ++ * ++ ****************************************************************************/ ++ ++NATIVE_CHAR * ++acpi_cm_format_exception ( ++ ACPI_STATUS status) ++{ ++ NATIVE_CHAR *exception = "UNKNOWN_STATUS"; ++ ACPI_STATUS sub_status; ++ ++ ++ sub_status = (status & ~AE_CODE_MASK); ++ ++ ++ switch (status & AE_CODE_MASK) ++ { ++ case AE_CODE_ENVIRONMENTAL: ++ ++ if (sub_status <= AE_CODE_ENV_MAX) ++ { ++ exception = acpi_gbl_exception_names_env [sub_status]; ++ } ++ break; ++ ++ case AE_CODE_PROGRAMMER: ++ ++ if (sub_status <= AE_CODE_PGM_MAX) ++ { ++ exception = acpi_gbl_exception_names_pgm [sub_status -1]; ++ } ++ break; ++ ++ case AE_CODE_ACPI_TABLES: ++ ++ if (sub_status <= AE_CODE_TBL_MAX) ++ { ++ exception = acpi_gbl_exception_names_tbl [sub_status -1]; ++ } ++ break; ++ ++ case AE_CODE_AML: ++ ++ if (sub_status <= AE_CODE_AML_MAX) ++ { ++ exception = acpi_gbl_exception_names_aml [sub_status -1]; ++ } ++ break; ++ ++ case AE_CODE_CONTROL: ++ ++ if (sub_status <= AE_CODE_CTRL_MAX) ++ { ++ exception = acpi_gbl_exception_names_ctrl [sub_status -1]; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ ++ return (exception); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: Acpi_cm_allocate_owner_id ++ * ++ * PARAMETERS: Id_type - Type of ID (method or table) ++ * ++ * DESCRIPTION: Allocate a table or method owner id ++ * ++ ***************************************************************************/ ++ ++ACPI_OWNER_ID ++acpi_cm_allocate_owner_id ( ++ u32 id_type) ++{ ++ ACPI_OWNER_ID owner_id = 0xFFFF; ++ ++ ++ acpi_cm_acquire_mutex (ACPI_MTX_CACHES); ++ ++ switch (id_type) ++ { ++ case OWNER_TYPE_TABLE: ++ ++ owner_id = acpi_gbl_next_table_owner_id; ++ acpi_gbl_next_table_owner_id++; ++ ++ if (acpi_gbl_next_table_owner_id == FIRST_METHOD_ID) ++ { ++ acpi_gbl_next_table_owner_id = FIRST_TABLE_ID; ++ } ++ break; ++ ++ ++ case OWNER_TYPE_METHOD: ++ ++ owner_id = acpi_gbl_next_method_owner_id; ++ acpi_gbl_next_method_owner_id++; ++ ++ if (acpi_gbl_next_method_owner_id == FIRST_TABLE_ID) ++ { ++ acpi_gbl_next_method_owner_id = FIRST_METHOD_ID; ++ } ++ break; ++ } ++ ++ ++ acpi_cm_release_mutex (ACPI_MTX_CACHES); ++ ++ return (owner_id); ++} ++ ++ ++/**************************************************************************** ++ * ++ * FUNCTION: Acpi_cm_init_globals ++ * ++ * PARAMETERS: none ++ * ++ * DESCRIPTION: Init library globals. All globals that require specific ++ * initialization should be initialized here! ++ * ++ ***************************************************************************/ ++ ++void ++acpi_cm_init_globals ( ++ void) ++{ ++ u32 i; ++ ++ ++ /* ACPI table structure */ ++ ++ for (i = 0; i < NUM_ACPI_TABLES; i++) ++ { ++ acpi_gbl_acpi_tables[i].prev = &acpi_gbl_acpi_tables[i]; ++ acpi_gbl_acpi_tables[i].next = &acpi_gbl_acpi_tables[i]; ++ acpi_gbl_acpi_tables[i].pointer = NULL; ++ acpi_gbl_acpi_tables[i].length = 0; ++ acpi_gbl_acpi_tables[i].allocation = ACPI_MEM_NOT_ALLOCATED; ++ acpi_gbl_acpi_tables[i].count = 0; ++ } ++ ++ ++ /* Address Space handler array */ ++ ++ for (i = 0; i < ACPI_NUM_ADDRESS_SPACES; i++) ++ { ++ acpi_gbl_address_spaces[i].handler = NULL; ++ acpi_gbl_address_spaces[i].context = NULL; ++ } ++ ++ /* Mutex locked flags */ ++ ++ for (i = 0; i < NUM_MTX; i++) ++ { ++ acpi_gbl_acpi_mutex_info[i].mutex = NULL; ++ acpi_gbl_acpi_mutex_info[i].owner_id = ACPI_MUTEX_NOT_ACQUIRED; ++ acpi_gbl_acpi_mutex_info[i].use_count = 0; ++ } ++ ++ /* Global notify handlers */ ++ ++ acpi_gbl_sys_notify.handler = NULL; ++ acpi_gbl_drv_notify.handler = NULL; ++ ++ /* Global "typed" ACPI table pointers */ ++ ++ acpi_gbl_RSDP = NULL; ++ acpi_gbl_XSDT = NULL; ++ acpi_gbl_FACS = NULL; ++ acpi_gbl_FADT = NULL; ++ acpi_gbl_DSDT = NULL; ++ ++ ++ /* Global Lock support */ ++ ++ acpi_gbl_global_lock_acquired = FALSE; ++ acpi_gbl_global_lock_thread_count = 0; ++ ++ /* Miscellaneous variables */ ++ ++ acpi_gbl_system_flags = 0; ++ acpi_gbl_startup_flags = 0; ++ acpi_gbl_rsdp_original_location = 0; ++ acpi_gbl_cm_single_step = FALSE; ++ acpi_gbl_db_terminate_threads = FALSE; ++ acpi_gbl_shutdown = FALSE; ++ acpi_gbl_ns_lookup_count = 0; ++ acpi_gbl_ps_find_count = 0; ++ acpi_gbl_acpi_hardware_present = TRUE; ++ acpi_gbl_next_table_owner_id = FIRST_TABLE_ID; ++ acpi_gbl_next_method_owner_id = FIRST_METHOD_ID; ++ acpi_gbl_debugger_configuration = DEBUGGER_THREADING; ++ ++ /* Cache of small "state" objects */ ++ ++ acpi_gbl_generic_state_cache = NULL; ++ acpi_gbl_generic_state_cache_depth = 0; ++ acpi_gbl_state_cache_requests = 0; ++ acpi_gbl_state_cache_hits = 0; ++ ++ acpi_gbl_parse_cache = NULL; ++ acpi_gbl_parse_cache_depth = 0; ++ acpi_gbl_parse_cache_requests = 0; ++ acpi_gbl_parse_cache_hits = 0; ++ ++ acpi_gbl_ext_parse_cache = NULL; ++ acpi_gbl_ext_parse_cache_depth = 0; ++ acpi_gbl_ext_parse_cache_requests = 0; ++ acpi_gbl_ext_parse_cache_hits = 0; ++ ++ acpi_gbl_object_cache = NULL; ++ acpi_gbl_object_cache_depth = 0; ++ acpi_gbl_object_cache_requests = 0; ++ acpi_gbl_object_cache_hits = 0; ++ ++ acpi_gbl_walk_state_cache = NULL; ++ acpi_gbl_walk_state_cache_depth = 0; ++ acpi_gbl_walk_state_cache_requests = 0; ++ acpi_gbl_walk_state_cache_hits = 0; ++ ++ /* Hardware oriented */ ++ ++ acpi_gbl_gpe0enable_register_save = NULL; ++ acpi_gbl_gpe1_enable_register_save = NULL; ++ acpi_gbl_original_mode = SYS_MODE_UNKNOWN; /* original ACPI/legacy mode */ ++ acpi_gbl_gpe_registers = NULL; ++ acpi_gbl_gpe_info = NULL; ++ ++ /* Namespace */ ++ ++ acpi_gbl_root_node = NULL; ++ ++ acpi_gbl_root_node_struct.name = ACPI_ROOT_NAME; ++ acpi_gbl_root_node_struct.data_type = ACPI_DESC_TYPE_NAMED; ++ acpi_gbl_root_node_struct.type = ACPI_TYPE_ANY; ++ acpi_gbl_root_node_struct.child = NULL; ++ acpi_gbl_root_node_struct.peer = NULL; ++ acpi_gbl_root_node_struct.object = NULL; ++ acpi_gbl_root_node_struct.flags = ANOBJ_END_OF_PEER_LIST; ++ ++ /* Memory allocation metrics - compiled out in non-debug mode. */ ++ ++ INITIALIZE_ALLOCATION_METRICS(); ++ ++ return; ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/utils/cminit.c linux/drivers/acpi/utils/cminit.c +--- /usr/src/linux/drivers/acpi/utils/cminit.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/utils/cminit.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,247 @@ ++/****************************************************************************** ++ * ++ * Module Name: cminit - Common ACPI subsystem initialization ++ * $Revision: 94 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "achware.h" ++#include "acnamesp.h" ++#include "acevents.h" ++#include "acparser.h" ++#include "acdispat.h" ++ ++#define _COMPONENT ACPI_UTILITIES ++ MODULE_NAME ("cminit") ++ ++ ++#define ACPI_OFFSET(d,o) ((u32) &(((d *)0)->o)) ++#define ACPI_FADT_OFFSET(o) ACPI_OFFSET (FADT_DESCRIPTOR, o) ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_fadt_register_error ++ * ++ * PARAMETERS: *Register_name - Pointer to string identifying register ++ * Value - Actual register contents value ++ * Acpi_test_spec_section - TDS section containing assertion ++ * Acpi_assertion - Assertion number being tested ++ * ++ * RETURN: AE_BAD_VALUE ++ * ++ * DESCRIPTION: Display failure message and link failure to TDS assertion ++ * ++ ******************************************************************************/ ++ ++static ACPI_STATUS ++acpi_cm_fadt_register_error ( ++ NATIVE_CHAR *register_name, ++ u32 value, ++ u32 offset) ++{ ++ ++ REPORT_ERROR ( ++ ("Invalid FADT value %s=%lX at offset %lX FADT=%p\n", ++ register_name, value, offset, acpi_gbl_FADT)); ++ ++ ++ return (AE_BAD_VALUE); ++} ++ ++ ++/****************************************************************************** ++ * ++ * FUNCTION: Acpi_cm_validate_fadt ++ * ++ * PARAMETERS: None ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Validate various ACPI registers in the FADT ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_validate_fadt ( ++ void) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ ++ /* ++ * Verify Fixed ACPI Description Table fields, ++ * but don't abort on any problems, just display error ++ */ ++ ++ if (acpi_gbl_FADT->pm1_evt_len < 4) { ++ status = acpi_cm_fadt_register_error ("PM1_EVT_LEN", ++ (u32) acpi_gbl_FADT->pm1_evt_len, ++ ACPI_FADT_OFFSET (pm1_evt_len)); ++ } ++ ++ if (!acpi_gbl_FADT->pm1_cnt_len) { ++ status = acpi_cm_fadt_register_error ("PM1_CNT_LEN", 0, ++ ACPI_FADT_OFFSET (pm1_cnt_len)); ++ } ++ ++ if (!ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm1a_evt_blk.address)) { ++ status = acpi_cm_fadt_register_error ("X_PM1a_EVT_BLK", 0, ++ ACPI_FADT_OFFSET (Xpm1a_evt_blk.address)); ++ } ++ ++ if (!ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm1a_cnt_blk.address)) { ++ status = acpi_cm_fadt_register_error ("X_PM1a_CNT_BLK", 0, ++ ACPI_FADT_OFFSET (Xpm1a_cnt_blk.address)); ++ } ++ ++ if (!ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm_tmr_blk.address)) { ++ status = acpi_cm_fadt_register_error ("X_PM_TMR_BLK", 0, ++ ACPI_FADT_OFFSET (Xpm_tmr_blk.address)); ++ } ++ ++ if ((ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm2_cnt_blk.address) && ++ !acpi_gbl_FADT->pm2_cnt_len)) { ++ status = acpi_cm_fadt_register_error ("PM2_CNT_LEN", ++ (u32) acpi_gbl_FADT->pm2_cnt_len, ++ ACPI_FADT_OFFSET (pm2_cnt_len)); ++ } ++ ++ if (acpi_gbl_FADT->pm_tm_len < 4) { ++ status = acpi_cm_fadt_register_error ("PM_TM_LEN", ++ (u32) acpi_gbl_FADT->pm_tm_len, ++ ACPI_FADT_OFFSET (pm_tm_len)); ++ } ++ ++ /* length of GPE blocks must be a multiple of 2 */ ++ ++ ++ if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xgpe0blk.address) && ++ (acpi_gbl_FADT->gpe0blk_len & 1)) { ++ status = acpi_cm_fadt_register_error ("(x)GPE0_BLK_LEN", ++ (u32) acpi_gbl_FADT->gpe0blk_len, ++ ACPI_FADT_OFFSET (gpe0blk_len)); ++ } ++ ++ if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xgpe1_blk.address) && ++ (acpi_gbl_FADT->gpe1_blk_len & 1)) { ++ status = acpi_cm_fadt_register_error ("(x)GPE1_BLK_LEN", ++ (u32) acpi_gbl_FADT->gpe1_blk_len, ++ ACPI_FADT_OFFSET (gpe1_blk_len)); ++ } ++ ++ return (status); ++} ++ ++ ++/****************************************************************************** ++ * ++ * FUNCTION: Acpi_cm_terminate ++ * ++ * PARAMETERS: none ++ * ++ * RETURN: none ++ * ++ * DESCRIPTION: free memory allocated for table storage. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_cm_terminate (void) ++{ ++ ++ ++ /* Free global tables, etc. */ ++ ++ if (acpi_gbl_gpe0enable_register_save) { ++ acpi_cm_free (acpi_gbl_gpe0enable_register_save); ++ } ++ ++ if (acpi_gbl_gpe1_enable_register_save) { ++ acpi_cm_free (acpi_gbl_gpe1_enable_register_save); ++ } ++ ++ ++ return; ++} ++ ++ ++/****************************************************************************** ++ * ++ * FUNCTION: Acpi_cm_subsystem_shutdown ++ * ++ * PARAMETERS: none ++ * ++ * RETURN: none ++ * ++ * DESCRIPTION: Shutdown the various subsystems. Don't delete the mutex ++ * objects here -- because the AML debugger may be still running. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_subsystem_shutdown (void) ++{ ++ ++ /* Just exit if subsystem is already shutdown */ ++ ++ if (acpi_gbl_shutdown) { ++ return (AE_OK); ++ } ++ ++ /* Subsystem appears active, go ahead and shut it down */ ++ ++ acpi_gbl_shutdown = TRUE; ++ ++ /* Close the Namespace */ ++ ++ acpi_ns_terminate (); ++ ++ /* Close the Acpi_event Handling */ ++ ++ acpi_ev_terminate (); ++ ++ /* Close the globals */ ++ ++ acpi_cm_terminate (); ++ ++ /* Flush the local cache(s) */ ++ ++ acpi_cm_delete_generic_state_cache (); ++ acpi_cm_delete_object_cache (); ++ acpi_ds_delete_walk_state_cache (); ++ ++ /* Close the Parser */ ++ ++ /* TBD: [Restructure] Acpi_ps_terminate () */ ++ ++ acpi_ps_delete_parse_cache (); ++ ++ /* Debug only - display leftover memory allocation, if any */ ++#ifdef ENABLE_DEBUGGER ++ acpi_cm_dump_current_allocations (ACPI_UINT32_MAX, NULL); ++#endif ++ ++ return (AE_OK); ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/utils/cmobject.c linux/drivers/acpi/utils/cmobject.c +--- /usr/src/linux/drivers/acpi/utils/cmobject.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/utils/cmobject.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,622 @@ ++/****************************************************************************** ++ * ++ * Module Name: cmobject - ACPI object create/delete/size/cache routines ++ * $Revision: 42 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acinterp.h" ++#include "acnamesp.h" ++#include "actables.h" ++#include "amlcode.h" ++ ++ ++#define _COMPONENT ACPI_UTILITIES ++ MODULE_NAME ("cmobject") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: _Cm_create_internal_object ++ * ++ * PARAMETERS: Address - Address of the memory to deallocate ++ * Component - Component type of caller ++ * Module - Source file name of caller ++ * Line - Line number of caller ++ * Type - ACPI Type of the new object ++ * ++ * RETURN: Object - The new object. Null on failure ++ * ++ * DESCRIPTION: Create and initialize a new internal object. ++ * ++ * NOTE: We always allocate the worst-case object descriptor because ++ * these objects are cached, and we want them to be ++ * one-size-satisifies-any-request. This in itself may not be ++ * the most memory efficient, but the efficiency of the object ++ * cache should more than make up for this! ++ * ++ ******************************************************************************/ ++ ++ACPI_OPERAND_OBJECT * ++_cm_create_internal_object ( ++ NATIVE_CHAR *module_name, ++ u32 line_number, ++ u32 component_id, ++ OBJECT_TYPE_INTERNAL type) ++{ ++ ACPI_OPERAND_OBJECT *object; ++ ++ ++ /* Allocate the raw object descriptor */ ++ ++ object = _cm_allocate_object_desc (module_name, line_number, component_id); ++ if (!object) { ++ /* Allocation failure */ ++ ++ return (NULL); ++ } ++ ++ /* Save the object type in the object descriptor */ ++ ++ object->common.type = type; ++ ++ /* Init the reference count */ ++ ++ object->common.reference_count = 1; ++ ++ /* Any per-type initialization should go here */ ++ ++ ++ return (object); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_valid_internal_object ++ * ++ * PARAMETERS: Operand - Object to be validated ++ * ++ * RETURN: Validate a pointer to be an ACPI_OPERAND_OBJECT ++ * ++ ******************************************************************************/ ++ ++u8 ++acpi_cm_valid_internal_object ( ++ void *object) ++{ ++ ++ /* Check for a null pointer */ ++ ++ if (!object) { ++ return (FALSE); ++ } ++ ++ /* Check for a pointer within one of the ACPI tables */ ++ ++ if (acpi_tb_system_table_pointer (object)) { ++ return (FALSE); ++ } ++ ++ /* Check the descriptor type field */ ++ ++ if (!VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_INTERNAL)) { ++ /* Not an ACPI internal object, do some further checking */ ++ ++ ++ ++ ++ return (FALSE); ++ } ++ ++ ++ /* The object appears to be a valid ACPI_OPERAND_OBJECT */ ++ ++ return (TRUE); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: _Cm_allocate_object_desc ++ * ++ * PARAMETERS: Module_name - Caller's module name (for error output) ++ * Line_number - Caller's line number (for error output) ++ * Component_id - Caller's component ID (for error output) ++ * Message - Error message to use on failure ++ * ++ * RETURN: Pointer to newly allocated object descriptor. Null on error ++ * ++ * DESCRIPTION: Allocate a new object descriptor. Gracefully handle ++ * error conditions. ++ * ++ ******************************************************************************/ ++ ++void * ++_cm_allocate_object_desc ( ++ NATIVE_CHAR *module_name, ++ u32 line_number, ++ u32 component_id) ++{ ++ ACPI_OPERAND_OBJECT *object; ++ ++ ++ acpi_cm_acquire_mutex (ACPI_MTX_CACHES); ++ ++ acpi_gbl_object_cache_requests++; ++ ++ /* Check the cache first */ ++ ++ if (acpi_gbl_object_cache) { ++ /* There is an object available, use it */ ++ ++ object = acpi_gbl_object_cache; ++ acpi_gbl_object_cache = object->cache.next; ++ object->cache.next = NULL; ++ ++ acpi_gbl_object_cache_hits++; ++ acpi_gbl_object_cache_depth--; ++ ++ acpi_cm_release_mutex (ACPI_MTX_CACHES); ++ } ++ ++ else { ++ /* The cache is empty, create a new object */ ++ ++ acpi_cm_release_mutex (ACPI_MTX_CACHES); ++ ++ /* Attempt to allocate new descriptor */ ++ ++ object = _cm_callocate (sizeof (ACPI_OPERAND_OBJECT), component_id, ++ module_name, line_number); ++ if (!object) { ++ /* Allocation failed */ ++ ++ _REPORT_ERROR (module_name, line_number, component_id, ++ ("Could not allocate an object descriptor\n")); ++ ++ return (NULL); ++ } ++ ++ /* Memory allocation metrics - compiled out in non debug mode. */ ++ ++ INCREMENT_OBJECT_METRICS (sizeof (ACPI_OPERAND_OBJECT)); ++ } ++ ++ /* Mark the descriptor type */ ++ ++ object->common.data_type = ACPI_DESC_TYPE_INTERNAL; ++ ++ return (object); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_delete_object_desc ++ * ++ * PARAMETERS: Object - Acpi internal object to be deleted ++ * ++ * RETURN: None. ++ * ++ * DESCRIPTION: Free an ACPI object descriptor or add it to the object cache ++ * ++ ******************************************************************************/ ++ ++void ++acpi_cm_delete_object_desc ( ++ ACPI_OPERAND_OBJECT *object) ++{ ++ ++ ++ /* Make sure that the object isn't already in the cache */ ++ ++ if (object->common.data_type == (ACPI_DESC_TYPE_INTERNAL | ACPI_CACHED_OBJECT)) { ++ return; ++ } ++ ++ /* Object must be an ACPI_OPERAND_OBJECT */ ++ ++ if (object->common.data_type != ACPI_DESC_TYPE_INTERNAL) { ++ return; ++ } ++ ++ ++ /* If cache is full, just free this object */ ++ ++ if (acpi_gbl_object_cache_depth >= MAX_OBJECT_CACHE_DEPTH) { ++ /* ++ * Memory allocation metrics. Call the macro here since we only ++ * care about dynamically allocated objects. ++ */ ++ DECREMENT_OBJECT_METRICS (sizeof (ACPI_OPERAND_OBJECT)); ++ ++ acpi_cm_free (object); ++ return; ++ } ++ ++ acpi_cm_acquire_mutex (ACPI_MTX_CACHES); ++ ++ /* Clear the entire object. This is important! */ ++ ++ MEMSET (object, 0, sizeof (ACPI_OPERAND_OBJECT)); ++ object->common.data_type = ACPI_DESC_TYPE_INTERNAL | ACPI_CACHED_OBJECT; ++ ++ /* Put the object at the head of the global cache list */ ++ ++ object->cache.next = acpi_gbl_object_cache; ++ acpi_gbl_object_cache = object; ++ acpi_gbl_object_cache_depth++; ++ ++ ++ acpi_cm_release_mutex (ACPI_MTX_CACHES); ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_delete_object_cache ++ * ++ * PARAMETERS: None ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Purge the global state object cache. Used during subsystem ++ * termination. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_cm_delete_object_cache ( ++ void) ++{ ++ ACPI_OPERAND_OBJECT *next; ++ ++ ++ /* Traverse the global cache list */ ++ ++ while (acpi_gbl_object_cache) { ++ /* Delete one cached state object */ ++ ++ next = acpi_gbl_object_cache->cache.next; ++ acpi_gbl_object_cache->cache.next = NULL; ++ ++ /* ++ * Memory allocation metrics. Call the macro here since we only ++ * care about dynamically allocated objects. ++ */ ++ DECREMENT_OBJECT_METRICS (sizeof (ACPI_OPERAND_OBJECT)); ++ ++ acpi_cm_free (acpi_gbl_object_cache); ++ acpi_gbl_object_cache = next; ++ acpi_gbl_object_cache_depth--; ++ } ++ ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_init_static_object ++ * ++ * PARAMETERS: Obj_desc - Pointer to a "static" object - on stack ++ * or in the data segment. ++ * ++ * RETURN: None. ++ * ++ * DESCRIPTION: Initialize a static object. Sets flags to disallow dynamic ++ * deletion of the object. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_cm_init_static_object ( ++ ACPI_OPERAND_OBJECT *obj_desc) ++{ ++ ++ ++ if (!obj_desc) { ++ return; ++ } ++ ++ ++ /* ++ * Clear the entire descriptor ++ */ ++ MEMSET ((void *) obj_desc, 0, sizeof (ACPI_OPERAND_OBJECT)); ++ ++ ++ /* ++ * Initialize the header fields ++ * 1) This is an ACPI_OPERAND_OBJECT descriptor ++ * 2) The size is the full object (worst case) ++ * 3) The flags field indicates static allocation ++ * 4) Reference count starts at one (not really necessary since the ++ * object can't be deleted, but keeps everything sane) ++ */ ++ ++ obj_desc->common.data_type = ACPI_DESC_TYPE_INTERNAL; ++ obj_desc->common.flags = AOPOBJ_STATIC_ALLOCATION; ++ obj_desc->common.reference_count = 1; ++ ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_get_simple_object_size ++ * ++ * PARAMETERS: *Internal_object - Pointer to the object we are examining ++ * *Ret_length - Where the length is returned ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: This function is called to determine the space required to ++ * contain a simple object for return to an API user. ++ * ++ * The length includes the object structure plus any additional ++ * needed space. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_get_simple_object_size ( ++ ACPI_OPERAND_OBJECT *internal_object, ++ u32 *obj_length) ++{ ++ u32 length; ++ ACPI_STATUS status = AE_OK; ++ ++ ++ /* Handle a null object (Could be a uninitialized package element -- which is legal) */ ++ ++ if (!internal_object) { ++ *obj_length = 0; ++ return (AE_OK); ++ } ++ ++ ++ /* Start with the length of the Acpi object */ ++ ++ length = sizeof (ACPI_OBJECT); ++ ++ if (VALID_DESCRIPTOR_TYPE (internal_object, ACPI_DESC_TYPE_NAMED)) { ++ /* Object is a named object (reference), just return the length */ ++ ++ *obj_length = (u32) ROUND_UP_TO_NATIVE_WORD (length); ++ return (status); ++ } ++ ++ ++ /* ++ * The final length depends on the object type ++ * Strings and Buffers are packed right up against the parent object and ++ * must be accessed bytewise or there may be alignment problems on ++ * certain processors ++ */ ++ ++ switch (internal_object->common.type) { ++ ++ case ACPI_TYPE_STRING: ++ ++ length += internal_object->string.length + 1; ++ break; ++ ++ ++ case ACPI_TYPE_BUFFER: ++ ++ length += internal_object->buffer.length; ++ break; ++ ++ ++ case ACPI_TYPE_INTEGER: ++ case ACPI_TYPE_PROCESSOR: ++ case ACPI_TYPE_POWER: ++ ++ /* ++ * No extra data for these types ++ */ ++ break; ++ ++ ++ case INTERNAL_TYPE_REFERENCE: ++ ++ /* ++ * The only type that should be here is opcode AML_NAMEPATH_OP -- since ++ * this means an object reference ++ */ ++ if (internal_object->reference.opcode != AML_NAMEPATH_OP) { ++ status = AE_TYPE; ++ } ++ ++ else { ++ /* ++ * Get the actual length of the full pathname to this object. ++ * The reference will be converted to the pathname to the object ++ */ ++ length += ROUND_UP_TO_NATIVE_WORD (acpi_ns_get_pathname_length (internal_object->reference.node)); ++ } ++ break; ++ ++ ++ default: ++ ++ status = AE_TYPE; ++ break; ++ } ++ ++ ++ /* ++ * Account for the space required by the object rounded up to the next ++ * multiple of the machine word size. This keeps each object aligned ++ * on a machine word boundary. (preventing alignment faults on some ++ * machines.) ++ */ ++ *obj_length = (u32) ROUND_UP_TO_NATIVE_WORD (length); ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_get_element_length ++ * ++ * PARAMETERS: ACPI_PKG_CALLBACK ++ * ++ * RETURN: Status - the status of the call ++ * ++ * DESCRIPTION: Get the length of one package element. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_get_element_length ( ++ u8 object_type, ++ ACPI_OPERAND_OBJECT *source_object, ++ ACPI_GENERIC_STATE *state, ++ void *context) ++{ ++ ACPI_STATUS status = AE_OK; ++ ACPI_PKG_INFO *info = (ACPI_PKG_INFO *) context; ++ u32 object_space; ++ ++ ++ switch (object_type) { ++ case 0: ++ ++ /* ++ * Simple object - just get the size (Null object/entry is handled ++ * here also) and sum it into the running package length ++ */ ++ status = acpi_cm_get_simple_object_size (source_object, &object_space); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ info->length += object_space; ++ break; ++ ++ ++ case 1: ++ /* Package - nothing much to do here, let the walk handle it */ ++ ++ info->num_packages++; ++ state->pkg.this_target_obj = NULL; ++ break; ++ ++ default: ++ return (AE_BAD_PARAMETER); ++ } ++ ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_get_package_object_size ++ * ++ * PARAMETERS: *Internal_object - Pointer to the object we are examining ++ * *Ret_length - Where the length is returned ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: This function is called to determine the space required to ++ * contain a package object for return to an API user. ++ * ++ * This is moderately complex since a package contains other ++ * objects including packages. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_get_package_object_size ( ++ ACPI_OPERAND_OBJECT *internal_object, ++ u32 *obj_length) ++{ ++ ACPI_STATUS status; ++ ACPI_PKG_INFO info; ++ ++ ++ info.length = 0; ++ info.object_space = 0; ++ info.num_packages = 1; ++ ++ status = acpi_cm_walk_package_tree (internal_object, NULL, ++ acpi_cm_get_element_length, &info); ++ ++ /* ++ * We have handled all of the objects in all levels of the package. ++ * just add the length of the package objects themselves. ++ * Round up to the next machine word. ++ */ ++ info.length += ROUND_UP_TO_NATIVE_WORD (sizeof (ACPI_OBJECT)) * ++ info.num_packages; ++ ++ /* Return the total package length */ ++ ++ *obj_length = info.length; ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_get_object_size ++ * ++ * PARAMETERS: *Internal_object - Pointer to the object we are examining ++ * *Ret_length - Where the length will be returned ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: This function is called to determine the space required to ++ * contain an object for return to an API user. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_get_object_size( ++ ACPI_OPERAND_OBJECT *internal_object, ++ u32 *obj_length) ++{ ++ ACPI_STATUS status; ++ ++ ++ if ((VALID_DESCRIPTOR_TYPE (internal_object, ACPI_DESC_TYPE_INTERNAL)) && ++ (IS_THIS_OBJECT_TYPE (internal_object, ACPI_TYPE_PACKAGE))) { ++ status = acpi_cm_get_package_object_size (internal_object, obj_length); ++ } ++ ++ else { ++ status = acpi_cm_get_simple_object_size (internal_object, obj_length); ++ } ++ ++ return (status); ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/utils/cmutils.c linux/drivers/acpi/utils/cmutils.c +--- /usr/src/linux/drivers/acpi/utils/cmutils.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/utils/cmutils.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,1007 @@ ++/******************************************************************************* ++ * ++ * Module Name: cmutils - common utility procedures ++ * $Revision: 36 $ ++ * ++ ******************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acevents.h" ++#include "achware.h" ++#include "acnamesp.h" ++#include "acinterp.h" ++#include "amlcode.h" ++#include "acdebug.h" ++ ++ ++#define _COMPONENT ACPI_UTILITIES ++ MODULE_NAME ("cmutils") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_valid_acpi_name ++ * ++ * PARAMETERS: Character - The character to be examined ++ * ++ * RETURN: 1 if Character may appear in a name, else 0 ++ * ++ * DESCRIPTION: Check for a valid ACPI name. Each character must be one of: ++ * 1) Upper case alpha ++ * 2) numeric ++ * 3) underscore ++ * ++ ******************************************************************************/ ++ ++u8 ++acpi_cm_valid_acpi_name ( ++ u32 name) ++{ ++ NATIVE_CHAR *name_ptr = (NATIVE_CHAR *) &name; ++ u32 i; ++ ++ ++ for (i = 0; i < ACPI_NAME_SIZE; i++) { ++ if (!((name_ptr[i] == '_') || ++ (name_ptr[i] >= 'A' && name_ptr[i] <= 'Z') || ++ (name_ptr[i] >= '0' && name_ptr[i] <= '9'))) { ++ return (FALSE); ++ } ++ } ++ ++ ++ return (TRUE); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_valid_acpi_character ++ * ++ * PARAMETERS: Character - The character to be examined ++ * ++ * RETURN: 1 if Character may appear in a name, else 0 ++ * ++ * DESCRIPTION: Check for a printable character ++ * ++ ******************************************************************************/ ++ ++u8 ++acpi_cm_valid_acpi_character ( ++ NATIVE_CHAR character) ++{ ++ ++ return ((u8) ((character == '_') || ++ (character >= 'A' && character <= 'Z') || ++ (character >= '0' && character <= '9'))); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_mutex_initialize ++ * ++ * PARAMETERS: None. ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Create the system mutex objects. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_mutex_initialize ( ++ void) ++{ ++ u32 i; ++ ACPI_STATUS status; ++ ++ ++ /* ++ * Create each of the predefined mutex objects ++ */ ++ for (i = 0; i < NUM_MTX; i++) { ++ status = acpi_cm_create_mutex (i); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ } ++ ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_mutex_terminate ++ * ++ * PARAMETERS: None. ++ * ++ * RETURN: None. ++ * ++ * DESCRIPTION: Delete all of the system mutex objects. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_cm_mutex_terminate ( ++ void) ++{ ++ u32 i; ++ ++ ++ /* ++ * Delete each predefined mutex object ++ */ ++ for (i = 0; i < NUM_MTX; i++) { ++ acpi_cm_delete_mutex (i); ++ } ++ ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_create_mutex ++ * ++ * PARAMETERS: Mutex_iD - ID of the mutex to be created ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Create a mutex object. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_create_mutex ( ++ ACPI_MUTEX_HANDLE mutex_id) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ ++ if (mutex_id > MAX_MTX) { ++ return (AE_BAD_PARAMETER); ++ } ++ ++ ++ if (!acpi_gbl_acpi_mutex_info[mutex_id].mutex) { ++ status = acpi_os_create_semaphore (1, 1, ++ &acpi_gbl_acpi_mutex_info[mutex_id].mutex); ++ acpi_gbl_acpi_mutex_info[mutex_id].owner_id = ACPI_MUTEX_NOT_ACQUIRED; ++ acpi_gbl_acpi_mutex_info[mutex_id].use_count = 0; ++ } ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_delete_mutex ++ * ++ * PARAMETERS: Mutex_iD - ID of the mutex to be deleted ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Delete a mutex object. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_delete_mutex ( ++ ACPI_MUTEX_HANDLE mutex_id) ++{ ++ ACPI_STATUS status; ++ ++ ++ if (mutex_id > MAX_MTX) { ++ return (AE_BAD_PARAMETER); ++ } ++ ++ ++ status = acpi_os_delete_semaphore (acpi_gbl_acpi_mutex_info[mutex_id].mutex); ++ ++ acpi_gbl_acpi_mutex_info[mutex_id].mutex = NULL; ++ acpi_gbl_acpi_mutex_info[mutex_id].owner_id = ACPI_MUTEX_NOT_ACQUIRED; ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_acquire_mutex ++ * ++ * PARAMETERS: Mutex_iD - ID of the mutex to be acquired ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Acquire a mutex object. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_acquire_mutex ( ++ ACPI_MUTEX_HANDLE mutex_id) ++{ ++ ACPI_STATUS status; ++ u32 i; ++ u32 this_thread_id; ++ ++ ++ if (mutex_id > MAX_MTX) { ++ return (AE_BAD_PARAMETER); ++ } ++ ++ ++ this_thread_id = acpi_os_get_thread_id (); ++ ++ /* ++ * Deadlock prevention. Check if this thread owns any mutexes of value ++ * greater than or equal to this one. If so, the thread has violated ++ * the mutex ordering rule. This indicates a coding error somewhere in ++ * the ACPI subsystem code. ++ */ ++ for (i = mutex_id; i < MAX_MTX; i++) { ++ if (acpi_gbl_acpi_mutex_info[i].owner_id == this_thread_id) { ++ if (i == mutex_id) { ++ return (AE_ALREADY_ACQUIRED); ++ } ++ ++ return (AE_ACQUIRE_DEADLOCK); ++ } ++ } ++ ++ ++ status = acpi_os_wait_semaphore (acpi_gbl_acpi_mutex_info[mutex_id].mutex, ++ 1, WAIT_FOREVER); ++ ++ if (ACPI_SUCCESS (status)) { ++ acpi_gbl_acpi_mutex_info[mutex_id].use_count++; ++ acpi_gbl_acpi_mutex_info[mutex_id].owner_id = this_thread_id; ++ } ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_release_mutex ++ * ++ * PARAMETERS: Mutex_iD - ID of the mutex to be released ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Release a mutex object. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_release_mutex ( ++ ACPI_MUTEX_HANDLE mutex_id) ++{ ++ ACPI_STATUS status; ++ u32 i; ++ u32 this_thread_id; ++ ++ ++ if (mutex_id > MAX_MTX) { ++ return (AE_BAD_PARAMETER); ++ } ++ ++ ++ /* ++ * Mutex must be acquired in order to release it! ++ */ ++ if (acpi_gbl_acpi_mutex_info[mutex_id].owner_id == ACPI_MUTEX_NOT_ACQUIRED) { ++ return (AE_NOT_ACQUIRED); ++ } ++ ++ ++ /* ++ * Deadlock prevention. Check if this thread owns any mutexes of value ++ * greater than this one. If so, the thread has violated the mutex ++ * ordering rule. This indicates a coding error somewhere in ++ * the ACPI subsystem code. ++ */ ++ this_thread_id = acpi_os_get_thread_id (); ++ for (i = mutex_id; i < MAX_MTX; i++) { ++ if (acpi_gbl_acpi_mutex_info[i].owner_id == this_thread_id) { ++ if (i == mutex_id) { ++ continue; ++ } ++ ++ return (AE_RELEASE_DEADLOCK); ++ } ++ } ++ ++ ++ status = acpi_os_signal_semaphore (acpi_gbl_acpi_mutex_info[mutex_id].mutex, 1); ++ ++ ++ /* Mark unlocked */ ++ ++ acpi_gbl_acpi_mutex_info[mutex_id].owner_id = ACPI_MUTEX_NOT_ACQUIRED; ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_create_update_state_and_push ++ * ++ * PARAMETERS: *Object - Object to be added to the new state ++ * Action - Increment/Decrement ++ * State_list - List the state will be added to ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Create a new state and push it ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_create_update_state_and_push ( ++ ACPI_OPERAND_OBJECT *object, ++ u16 action, ++ ACPI_GENERIC_STATE **state_list) ++{ ++ ACPI_GENERIC_STATE *state; ++ ++ ++ /* Ignore null objects; these are expected */ ++ ++ if (!object) { ++ return (AE_OK); ++ } ++ ++ state = acpi_cm_create_update_state (object, action); ++ if (!state) { ++ return (AE_NO_MEMORY); ++ } ++ ++ ++ acpi_cm_push_generic_state (state_list, state); ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_create_pkg_state_and_push ++ * ++ * PARAMETERS: *Object - Object to be added to the new state ++ * Action - Increment/Decrement ++ * State_list - List the state will be added to ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Create a new state and push it ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_create_pkg_state_and_push ( ++ void *internal_object, ++ void *external_object, ++ u16 index, ++ ACPI_GENERIC_STATE **state_list) ++{ ++ ACPI_GENERIC_STATE *state; ++ ++ ++ state = acpi_cm_create_pkg_state (internal_object, external_object, index); ++ if (!state) { ++ return (AE_NO_MEMORY); ++ } ++ ++ ++ acpi_cm_push_generic_state (state_list, state); ++ return (AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_push_generic_state ++ * ++ * PARAMETERS: List_head - Head of the state stack ++ * State - State object to push ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Push a state object onto a state stack ++ * ++ ******************************************************************************/ ++ ++void ++acpi_cm_push_generic_state ( ++ ACPI_GENERIC_STATE **list_head, ++ ACPI_GENERIC_STATE *state) ++{ ++ /* Push the state object onto the front of the list (stack) */ ++ ++ state->common.next = *list_head; ++ *list_head = state; ++ ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_pop_generic_state ++ * ++ * PARAMETERS: List_head - Head of the state stack ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Pop a state object from a state stack ++ * ++ ******************************************************************************/ ++ ++ACPI_GENERIC_STATE * ++acpi_cm_pop_generic_state ( ++ ACPI_GENERIC_STATE **list_head) ++{ ++ ACPI_GENERIC_STATE *state; ++ ++ ++ /* Remove the state object at the head of the list (stack) */ ++ ++ state = *list_head; ++ if (state) { ++ /* Update the list head */ ++ ++ *list_head = state->common.next; ++ } ++ ++ return (state); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_create_generic_state ++ * ++ * PARAMETERS: None ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Create a generic state object. Attempt to obtain one from ++ * the global state cache; If none available, create a new one. ++ * ++ ******************************************************************************/ ++ ++ACPI_GENERIC_STATE * ++acpi_cm_create_generic_state (void) ++{ ++ ACPI_GENERIC_STATE *state; ++ ++ ++ acpi_cm_acquire_mutex (ACPI_MTX_CACHES); ++ ++ acpi_gbl_state_cache_requests++; ++ ++ /* Check the cache first */ ++ ++ if (acpi_gbl_generic_state_cache) { ++ /* There is an object available, use it */ ++ ++ state = acpi_gbl_generic_state_cache; ++ acpi_gbl_generic_state_cache = state->common.next; ++ state->common.next = NULL; ++ ++ acpi_gbl_state_cache_hits++; ++ acpi_gbl_generic_state_cache_depth--; ++ ++ acpi_cm_release_mutex (ACPI_MTX_CACHES); ++ ++ } ++ ++ else { ++ /* The cache is empty, create a new object */ ++ ++ acpi_cm_release_mutex (ACPI_MTX_CACHES); ++ ++ state = acpi_cm_callocate (sizeof (ACPI_GENERIC_STATE)); ++ } ++ ++ /* Initialize */ ++ ++ if (state) { ++ /* Always zero out the object before init */ ++ ++ MEMSET (state, 0, sizeof (ACPI_GENERIC_STATE)); ++ ++ state->common.data_type = ACPI_DESC_TYPE_STATE; ++ } ++ ++ return (state); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_create_update_state ++ * ++ * PARAMETERS: Object - Initial Object to be installed in the ++ * state ++ * Action - Update action to be performed ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Create an "Update State" - a flavor of the generic state used ++ * to update reference counts and delete complex objects such ++ * as packages. ++ * ++ ******************************************************************************/ ++ ++ACPI_GENERIC_STATE * ++acpi_cm_create_update_state ( ++ ACPI_OPERAND_OBJECT *object, ++ u16 action) ++{ ++ ACPI_GENERIC_STATE *state; ++ ++ ++ /* Create the generic state object */ ++ ++ state = acpi_cm_create_generic_state (); ++ if (!state) { ++ return (NULL); ++ } ++ ++ /* Init fields specific to the update struct */ ++ ++ state->update.object = object; ++ state->update.value = action; ++ ++ return (state); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_create_pkg_state ++ * ++ * PARAMETERS: Object - Initial Object to be installed in the ++ * state ++ * Action - Update action to be performed ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Create an "Update State" - a flavor of the generic state used ++ * to update reference counts and delete complex objects such ++ * as packages. ++ * ++ ******************************************************************************/ ++ ++ACPI_GENERIC_STATE * ++acpi_cm_create_pkg_state ( ++ void *internal_object, ++ void *external_object, ++ u16 index) ++{ ++ ACPI_GENERIC_STATE *state; ++ ++ ++ /* Create the generic state object */ ++ ++ state = acpi_cm_create_generic_state (); ++ if (!state) { ++ return (NULL); ++ } ++ ++ /* Init fields specific to the update struct */ ++ ++ state->pkg.source_object = (ACPI_OPERAND_OBJECT *) internal_object; ++ state->pkg.dest_object = external_object; ++ state->pkg.index = index; ++ state->pkg.num_packages = 1; ++ ++ return (state); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_create_control_state ++ * ++ * PARAMETERS: None ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Create a "Control State" - a flavor of the generic state used ++ * to support nested IF/WHILE constructs in the AML. ++ * ++ ******************************************************************************/ ++ ++ACPI_GENERIC_STATE * ++acpi_cm_create_control_state ( ++ void) ++{ ++ ACPI_GENERIC_STATE *state; ++ ++ ++ /* Create the generic state object */ ++ ++ state = acpi_cm_create_generic_state (); ++ if (!state) { ++ return (NULL); ++ } ++ ++ ++ /* Init fields specific to the control struct */ ++ ++ state->common.state = CONTROL_CONDITIONAL_EXECUTING; ++ ++ return (state); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_delete_generic_state ++ * ++ * PARAMETERS: State - The state object to be deleted ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Put a state object back into the global state cache. The object ++ * is not actually freed at this time. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_cm_delete_generic_state ( ++ ACPI_GENERIC_STATE *state) ++{ ++ ++ /* If cache is full, just free this state object */ ++ ++ if (acpi_gbl_generic_state_cache_depth >= MAX_STATE_CACHE_DEPTH) { ++ acpi_cm_free (state); ++ } ++ ++ /* Otherwise put this object back into the cache */ ++ ++ else { ++ acpi_cm_acquire_mutex (ACPI_MTX_CACHES); ++ ++ /* Clear the state */ ++ ++ MEMSET (state, 0, sizeof (ACPI_GENERIC_STATE)); ++ state->common.data_type = ACPI_DESC_TYPE_STATE; ++ ++ /* Put the object at the head of the global cache list */ ++ ++ state->common.next = acpi_gbl_generic_state_cache; ++ acpi_gbl_generic_state_cache = state; ++ acpi_gbl_generic_state_cache_depth++; ++ ++ ++ acpi_cm_release_mutex (ACPI_MTX_CACHES); ++ } ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_delete_generic_state_cache ++ * ++ * PARAMETERS: None ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Purge the global state object cache. Used during subsystem ++ * termination. ++ * ++ ******************************************************************************/ ++ ++void ++acpi_cm_delete_generic_state_cache ( ++ void) ++{ ++ ACPI_GENERIC_STATE *next; ++ ++ ++ /* Traverse the global cache list */ ++ ++ while (acpi_gbl_generic_state_cache) { ++ /* Delete one cached state object */ ++ ++ next = acpi_gbl_generic_state_cache->common.next; ++ acpi_cm_free (acpi_gbl_generic_state_cache); ++ acpi_gbl_generic_state_cache = next; ++ acpi_gbl_generic_state_cache_depth--; ++ } ++ ++ return; ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_resolve_package_references ++ * ++ * PARAMETERS: Obj_desc - The Package object on which to resolve refs ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Walk through a package and turn internal references into values ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_resolve_package_references ( ++ ACPI_OPERAND_OBJECT *obj_desc) ++{ ++ u32 count; ++ ACPI_OPERAND_OBJECT *sub_object; ++ ++ ++ if (obj_desc->common.type != ACPI_TYPE_PACKAGE) { ++ /* The object must be a package */ ++ ++ REPORT_ERROR (("Must resolve Package Refs on a Package\n")); ++ return(AE_ERROR); ++ } ++ ++ /* ++ * TBD: what about nested packages? */ ++ ++ for (count = 0; count < obj_desc->package.count; count++) { ++ sub_object = obj_desc->package.elements[count]; ++ ++ if (sub_object->common.type == INTERNAL_TYPE_REFERENCE) { ++ if (sub_object->reference.opcode == AML_ZERO_OP) { ++ sub_object->common.type = ACPI_TYPE_INTEGER; ++ sub_object->integer.value = 0; ++ } ++ ++ else if (sub_object->reference.opcode == AML_ONE_OP) { ++ sub_object->common.type = ACPI_TYPE_INTEGER; ++ sub_object->integer.value = 1; ++ } ++ ++ else if (sub_object->reference.opcode == AML_ONES_OP) { ++ sub_object->common.type = ACPI_TYPE_INTEGER; ++ sub_object->integer.value = ACPI_INTEGER_MAX; ++ } ++ } ++ } ++ ++ return(AE_OK); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_cm_walk_package_tree ++ * ++ * PARAMETERS: Obj_desc - The Package object on which to resolve refs ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Walk through a package ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_cm_walk_package_tree ( ++ ACPI_OPERAND_OBJECT *source_object, ++ void *target_object, ++ ACPI_PKG_CALLBACK walk_callback, ++ void *context) ++{ ++ ACPI_STATUS status = AE_OK; ++ ACPI_GENERIC_STATE *state_list = NULL; ++ ACPI_GENERIC_STATE *state; ++ u32 this_index; ++ ACPI_OPERAND_OBJECT *this_source_obj; ++ ++ ++ state = acpi_cm_create_pkg_state (source_object, target_object, 0); ++ if (!state) { ++ return (AE_NO_MEMORY); ++ } ++ ++ while (state) { ++ this_index = state->pkg.index; ++ this_source_obj = (ACPI_OPERAND_OBJECT *) ++ state->pkg.source_object->package.elements[this_index]; ++ ++ /* ++ * Check for ++ * 1) An uninitialized package element. It is completely ++ * legal to declare a package and leave it uninitialized ++ * 2) Not an internal object - can be a namespace node instead ++ * 3) Any type other than a package. Packages are handled in else ++ * case below. ++ */ ++ if ((!this_source_obj) || ++ (!VALID_DESCRIPTOR_TYPE ( ++ this_source_obj, ACPI_DESC_TYPE_INTERNAL)) || ++ (!IS_THIS_OBJECT_TYPE ( ++ this_source_obj, ACPI_TYPE_PACKAGE))) { ++ ++ status = walk_callback (ACPI_COPY_TYPE_SIMPLE, this_source_obj, ++ state, context); ++ if (ACPI_FAILURE (status)) { ++ /* TBD: must delete package created up to this point */ ++ ++ return (status); ++ } ++ ++ state->pkg.index++; ++ while (state->pkg.index >= state->pkg.source_object->package.count) { ++ /* ++ * We've handled all of the objects at this level, This means ++ * that we have just completed a package. That package may ++ * have contained one or more packages itself. ++ * ++ * Delete this state and pop the previous state (package). ++ */ ++ acpi_cm_delete_generic_state (state); ++ state = acpi_cm_pop_generic_state (&state_list); ++ ++ ++ /* Finished when there are no more states */ ++ ++ if (!state) { ++ /* ++ * We have handled all of the objects in the top level ++ * package just add the length of the package objects ++ * and exit ++ */ ++ return (AE_OK); ++ } ++ ++ /* ++ * Go back up a level and move the index past the just ++ * completed package object. ++ */ ++ state->pkg.index++; ++ } ++ } ++ ++ else { ++ /* This is a sub-object of type package */ ++ ++ status = walk_callback (ACPI_COPY_TYPE_PACKAGE, this_source_obj, ++ state, context); ++ if (ACPI_FAILURE (status)) { ++ /* TBD: must delete package created up to this point */ ++ ++ return (status); ++ } ++ ++ ++ /* ++ * The callback above returned a new target package object. ++ */ ++ ++ /* ++ * Push the current state and create a new one ++ */ ++ acpi_cm_push_generic_state (&state_list, state); ++ state = acpi_cm_create_pkg_state (this_source_obj, ++ state->pkg.this_target_obj, 0); ++ if (!state) { ++ /* TBD: must delete package created up to this point */ ++ ++ return (AE_NO_MEMORY); ++ } ++ } ++ } ++ ++ /* We should never get here */ ++ ++ return (AE_AML_INTERNAL); ++ ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: _Report_error ++ * ++ * PARAMETERS: Module_name - Caller's module name (for error output) ++ * Line_number - Caller's line number (for error output) ++ * Component_id - Caller's component ID (for error output) ++ * Message - Error message to use on failure ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Print error message ++ * ++ ******************************************************************************/ ++ ++void ++_report_error ( ++ NATIVE_CHAR *module_name, ++ u32 line_number, ++ u32 component_id) ++{ ++ ++ ++ acpi_os_printf ("%8s-%04d: *** Error: ", module_name, line_number); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: _Report_warning ++ * ++ * PARAMETERS: Module_name - Caller's module name (for error output) ++ * Line_number - Caller's line number (for error output) ++ * Component_id - Caller's component ID (for error output) ++ * Message - Error message to use on failure ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Print warning message ++ * ++ ******************************************************************************/ ++ ++void ++_report_warning ( ++ NATIVE_CHAR *module_name, ++ u32 line_number, ++ u32 component_id) ++{ ++ ++ acpi_os_printf ("%8s-%04d: *** Warning: ", module_name, line_number); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: _Report_info ++ * ++ * PARAMETERS: Module_name - Caller's module name (for error output) ++ * Line_number - Caller's line number (for error output) ++ * Component_id - Caller's component ID (for error output) ++ * Message - Error message to use on failure ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Print information message ++ * ++ ******************************************************************************/ ++ ++void ++_report_info ( ++ NATIVE_CHAR *module_name, ++ u32 line_number, ++ u32 component_id) ++{ ++ ++ acpi_os_printf ("%8s-%04d: *** Info: ", module_name, line_number); ++} ++ ++ +diff -Naur -X bin/dontdiff /usr/src/linux/drivers/acpi/utils/cmxface.c linux/drivers/acpi/utils/cmxface.c +--- /usr/src/linux/drivers/acpi/utils/cmxface.c Wed Dec 31 16:00:00 1969 ++++ linux/drivers/acpi/utils/cmxface.c Fri Apr 13 11:57:11 2001 +@@ -0,0 +1,459 @@ ++/****************************************************************************** ++ * ++ * Module Name: cmxface - External interfaces for "global" ACPI functions ++ * $Revision: 69 $ ++ * ++ *****************************************************************************/ ++ ++/* ++ * Copyright (C) 2000, 2001 R. Byron Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#include "acpi.h" ++#include "acevents.h" ++#include "achware.h" ++#include "acnamesp.h" ++#include "acinterp.h" ++#include "amlcode.h" ++#include "acdebug.h" ++ ++ ++#define _COMPONENT ACPI_UTILITIES ++ MODULE_NAME ("cmxface") ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_initialize_subsystem ++ * ++ * PARAMETERS: None ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Initializes all global variables. This is the first function ++ * called, so any early initialization belongs here. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_initialize_subsystem ( ++ void) ++{ ++ ACPI_STATUS status; ++ ++ ++ /* Initialize all globals used by the subsystem */ ++ ++ acpi_cm_init_globals (); ++ ++ /* Initialize the OS-Dependent layer */ ++ ++ status = acpi_os_initialize (); ++ if (ACPI_FAILURE (status)) { ++ REPORT_ERROR (("OSD failed to initialize, %s\n", ++ acpi_cm_format_exception (status))); ++ return (status); ++ } ++ ++ /* Create the default mutex objects */ ++ ++ status = acpi_cm_mutex_initialize (); ++ if (ACPI_FAILURE (status)) { ++ REPORT_ERROR (("Global mutex creation failure, %s\n", ++ acpi_cm_format_exception (status))); ++ return (status); ++ } ++ ++ /* ++ * Initialize the namespace manager and ++ * the root of the namespace tree ++ */ ++ ++ status = acpi_ns_root_initialize (); ++ if (ACPI_FAILURE (status)) { ++ REPORT_ERROR (("Namespace initialization failure, %s\n", ++ acpi_cm_format_exception (status))); ++ return (status); ++ } ++ ++ ++ /* If configured, initialize the AML debugger */ ++ ++ DEBUGGER_EXEC (acpi_db_initialize ()); ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_enable_subsystem ++ * ++ * PARAMETERS: Flags - Init/enable Options ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Completes the subsystem initialization including hardware. ++ * Puts system into ACPI mode if it isn't already. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_enable_subsystem ( ++ u32 flags) ++{ ++ ACPI_STATUS status = AE_OK; ++ ++ ++ /* Sanity check the FADT for valid values */ ++ ++ status = acpi_cm_validate_fadt (); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ ++ /* ++ * Install the default Op_region handlers. These are ++ * installed unless other handlers have already been ++ * installed via the Install_address_space_handler interface ++ */ ++ ++ if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { ++ status = acpi_ev_install_default_address_space_handlers (); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ } ++ ++ /* ++ * We must initialize the hardware before we can enable ACPI. ++ */ ++ ++ if (!(flags & ACPI_NO_HARDWARE_INIT)) { ++ status = acpi_hw_initialize (); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ } ++ ++ /* ++ * Enable ACPI on this platform ++ */ ++ ++ if (!(flags & ACPI_NO_ACPI_ENABLE)) { ++ status = acpi_enable (); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ } ++ ++ /* ++ * Note: ++ * We must have the hardware AND events initialized before we can execute ++ * ANY control methods SAFELY. Any control method can require ACPI hardware ++ * support, so the hardware MUST be initialized before execution! ++ */ ++ ++ if (!(flags & ACPI_NO_EVENT_INIT)) { ++ status = acpi_ev_initialize (); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ } ++ ++ ++ /* ++ * Initialize all device objects in the namespace ++ * This runs the _STA and _INI methods. ++ */ ++ ++ if (!(flags & ACPI_NO_DEVICE_INIT)) { ++ status = acpi_ns_initialize_devices (); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ } ++ ++ ++ /* ++ * Initialize the objects that remain uninitialized. This ++ * runs the executable AML that is part of the declaration of Op_regions ++ * and Fields. ++ */ ++ ++ if (!(flags & ACPI_NO_OBJECT_INIT)) { ++ status = acpi_ns_initialize_objects (); ++ if (ACPI_FAILURE (status)) { ++ return (status); ++ } ++ } ++ ++ ++ return (status); ++} ++ ++ ++/******************************************************************************* ++ * ++ * FUNCTION: Acpi_terminate ++ * ++ * PARAMETERS: None ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Shutdown the ACPI subsystem. Release all resources. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_terminate (void) ++{ ++ ++ /* Terminate the AML Debuger if present */ ++ ++ DEBUGGER_EXEC(acpi_gbl_db_terminate_threads = TRUE); ++ ++ /* TBD: [Investigate] This is no longer needed?*/ ++/* Acpi_cm_release_mutex (ACPI_MTX_DEBUG_CMD_READY); */ ++ ++ ++ /* Shutdown and free all resources */ ++ ++ acpi_cm_subsystem_shutdown (); ++ ++ ++ /* Free the mutex objects */ ++ ++ acpi_cm_mutex_terminate (); ++ ++ ++ /* Now we can shutdown the OS-dependent layer */ ++ ++ acpi_os_terminate (); ++ ++ return (AE_OK); ++} ++ ++ ++/****************************************************************************** ++ * ++ * FUNCTION: Acpi_get_system_info ++ * ++ * PARAMETERS: Out_buffer - a pointer to a buffer to receive the ++ * resources for the device ++ * Buffer_length - the number of bytes available in the buffer ++ * ++ * RETURN: Status - the status of the call ++ * ++ * DESCRIPTION: This function is called to get information about the current ++ * state of the ACPI subsystem. It will return system information ++ * in the Out_buffer. ++ * ++ * If the function fails an appropriate status will be returned ++ * and the value of Out_buffer is undefined. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_get_system_info ( ++ ACPI_BUFFER *out_buffer) ++{ ++ ACPI_SYSTEM_INFO *info_ptr; ++ u32 i; ++ ++ ++ /* ++ * Must have a valid buffer ++ */ ++ if ((!out_buffer) || ++ (!out_buffer->pointer)) { ++ return (AE_BAD_PARAMETER); ++ } ++ ++ if (out_buffer->length < sizeof (ACPI_SYSTEM_INFO)) { ++ /* ++ * Caller's buffer is too small ++ */ ++ out_buffer->length = sizeof (ACPI_SYSTEM_INFO); ++ ++ return (AE_BUFFER_OVERFLOW); ++ } ++ ++ ++ /* ++ * Set return length and get data ++ */ ++ out_buffer->length = sizeof (ACPI_SYSTEM_INFO); ++ info_ptr = (ACPI_SYSTEM_INFO *) out_buffer->pointer; ++ ++ info_ptr->acpi_ca_version = ACPI_CA_VERSION; ++ ++ /* System flags (ACPI capabilities) */ ++ ++ info_ptr->flags = acpi_gbl_system_flags; ++ ++ /* Timer resolution - 24 or 32 bits */ ++ if (!acpi_gbl_FADT) { ++ info_ptr->timer_resolution = 0; ++ } ++ else if (acpi_gbl_FADT->tmr_val_ext == 0) { ++ info_ptr->timer_resolution = 24; ++ } ++ else { ++ info_ptr->timer_resolution = 32; ++ } ++ ++ /* Clear the reserved fields */ ++ ++ info_ptr->reserved1 = 0; ++ info_ptr->reserved2 = 0; ++ ++ /* Current debug levels */ ++ ++ info_ptr->debug_layer = acpi_dbg_layer; ++ info_ptr->debug_level = acpi_dbg_level; ++ ++ /* Current status of the ACPI tables, per table type */ ++ ++ info_ptr->num_table_types = NUM_ACPI_TABLES; ++ for (i = 0; i < NUM_ACPI_TABLES; i++) { ++ info_ptr->table_info[i].count = acpi_gbl_acpi_tables[i].count; ++ } ++ ++ return (AE_OK); ++} ++ ++ ++/****************************************************************************** ++ * ++ * FUNCTION: Acpi_format_exception ++ * ++ * PARAMETERS: Out_buffer - a pointer to a buffer to receive the ++ * exception name ++ * ++ * RETURN: Status - the status of the call ++ * ++ * DESCRIPTION: This function translates an ACPI exception into an ASCII string. ++ * ++ ******************************************************************************/ ++ ++ACPI_STATUS ++acpi_format_exception ( ++ ACPI_STATUS exception, ++ ACPI_BUFFER *out_buffer) ++{ ++ u32 length; ++ NATIVE_CHAR *formatted_exception; ++ ++ ++ /* ++ * Must have a valid buffer ++ */ ++ if ((!out_buffer) || ++ (!out_buffer->pointer)) { ++ return (AE_BAD_PARAMETER); ++ } ++ ++ ++ /* Convert the exception code (Handles bad exception codes) */ ++ ++ formatted_exception = acpi_cm_format_exception (exception); ++ ++ /* ++ * Get length of string and check if it will fit in caller's buffer ++ */ ++ ++ length = STRLEN (formatted_exception); ++ if (out_buffer->length < length) { ++ out_buffer->length = length; ++ return (AE_BUFFER_OVERFLOW); ++ } ++ ++ ++ /* Copy the string, all done */ ++ ++ STRCPY (out_buffer->pointer, formatted_exception); ++ ++ return (AE_OK); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Acpi_allocate ++ * ++ * PARAMETERS: Size - Size of the allocation ++ * ++ * RETURN: Address of the allocated memory on success, NULL on failure. ++ * ++ * DESCRIPTION: The subsystem's equivalent of malloc. ++ * External front-end to the Cm* memory manager ++ * ++ ****************************************************************************/ ++ ++void * ++acpi_allocate ( ++ u32 size) ++{ ++ ++ return (acpi_cm_allocate (size)); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Acpi_callocate ++ * ++ * PARAMETERS: Size - Size of the allocation ++ * ++ * RETURN: Address of the allocated memory on success, NULL on failure. ++ * ++ * DESCRIPTION: The subsystem's equivalent of calloc. ++ * External front-end to the Cm* memory manager ++ * ++ ****************************************************************************/ ++ ++void * ++acpi_callocate ( ++ u32 size) ++{ ++ ++ return (acpi_cm_callocate (size)); ++} ++ ++ ++/***************************************************************************** ++ * ++ * FUNCTION: Acpi_free ++ * ++ * PARAMETERS: Address - Address of the memory to deallocate ++ * ++ * RETURN: None ++ * ++ * DESCRIPTION: Frees the memory at Address ++ * External front-end to the Cm* memory manager ++ * ++ ****************************************************************************/ ++ ++void ++acpi_free ( ++ void *address) ++{ ++ ++ acpi_cm_free (address); ++} +diff -Naur -X bin/dontdiff /usr/src/linux/include/linux/acpi.h linux/include/linux/acpi.h +--- /usr/src/linux/include/linux/acpi.h Fri Feb 9 11:45:58 2001 ++++ linux/include/linux/acpi.h Fri Apr 13 11:57:11 2001 +@@ -155,7 +155,7 @@ + ACPI_FACS, + ACPI_XSDT, + ACPI_PMTIMER, +- ACPI_BATTERY, ++ ACPI_BATT, + }; + + #define ACPI_SLP_TYP_DISABLED (~0UL) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/config.in linux.ac/arch/alpha/config.in --- linux.vanilla/arch/alpha/config.in Fri Dec 29 22:07:19 2000 +++ linux.ac/arch/alpha/config.in Tue Apr 3 17:54:29 2001 @@ -278,6 +278,8 @@ fi endmenu +source drivers/message/fusion/Config.in + if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment comment 'Network device support' diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/defconfig linux.ac/arch/alpha/defconfig --- linux.vanilla/arch/alpha/defconfig Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/alpha/defconfig Thu Apr 12 17:50:05 2001 @@ -286,7 +286,7 @@ # CONFIG_SCSI_AHA1740 is not set CONFIG_SCSI_AIC7XXX=y CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 -CONFIG_AIC7XXX_RESET_DELAY=5000 +CONFIG_AIC7XXX_RESET_DELAY_MS=5000 # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/kernel/alpha_ksyms.c linux.ac/arch/alpha/kernel/alpha_ksyms.c --- linux.vanilla/arch/alpha/kernel/alpha_ksyms.c Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/alpha/kernel/alpha_ksyms.c Tue Apr 3 17:54:29 2001 @@ -190,7 +190,6 @@ EXPORT_SYMBOL(synchronize_irq); EXPORT_SYMBOL(flush_tlb_all); EXPORT_SYMBOL(flush_tlb_mm); -EXPORT_SYMBOL(flush_tlb_page); EXPORT_SYMBOL(flush_tlb_range); EXPORT_SYMBOL(smp_imb); EXPORT_SYMBOL(cpu_data); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/mm/fault.c linux.ac/arch/alpha/mm/fault.c --- linux.vanilla/arch/alpha/mm/fault.c Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/alpha/mm/fault.c Tue Apr 3 17:54:29 2001 @@ -24,10 +24,37 @@ #include <linux/smp.h> #include <linux/smp_lock.h> #include <linux/interrupt.h> +#include <linux/vt_kern.h> #include <asm/system.h> #include <asm/uaccess.h> +extern spinlock_t timerlist_lock; +void bust_spinlocks(int yes) +{ + spin_lock_init(&timerlist_lock); + if (yes) { + oops_in_progress = 1; +#ifdef CONFIG_SMP + spin_lock_init(&global_irq_lock); /* Many serial drivers do __global_cli() */ +#endif + } else { + int loglevel_save = console_loglevel; + unblank_screen(); + oops_in_progress = 0; + /* + * OK, the message is on the console. Now we call printk() + * without oops_in_progress set so that printk will give klogd + * a poke. Hold onto your hats... + */ + console_loglevel = 15; /* NMI oopser may have shut the console up */ + printk(" "); + console_loglevel = loglevel_save; + } +} + + + extern void die_if_kernel(char *,struct pt_regs *,long, unsigned long *); @@ -223,7 +250,7 @@ pgd = current->active_mm->pgd + offset; pgd_k = swapper_pg_dir + offset; - if (!pgd_present(*pgd) && pgd_present(*pgd_k)) { + if (pgd_present(*pgd_k)) { pgd_val(*pgd) = pgd_val(*pgd_k); return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/mm/init.c linux.ac/arch/alpha/mm/init.c --- linux.vanilla/arch/alpha/mm/init.c Wed Nov 29 06:43:39 2000 +++ linux.ac/arch/alpha/mm/init.c Wed Apr 4 13:31:54 2001 @@ -32,6 +32,9 @@ #include <asm/dma.h> #include <asm/mmu_context.h> #include <asm/console.h> +#include <asm/tlb.h> + +mmu_gather_t mmu_gathers[NR_CPUS]; static unsigned long totalram_pages; @@ -43,20 +46,6 @@ struct pgtable_cache_struct quicklists; #endif -void -__bad_pmd(pgd_t *pgd) -{ - printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd)); - pgd_set(pgd, BAD_PAGETABLE); -} - -void -__bad_pte(pmd_t *pmd) -{ - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - pmd_set(pmd, (pte_t *) BAD_PAGETABLE); -} - pgd_t * get_pgd_slow(void) { @@ -80,66 +69,26 @@ return ret; } -pmd_t * -get_pmd_slow(pgd_t *pgd, unsigned long offset) -{ - pmd_t *pmd; - - pmd = (pmd_t *) __get_free_page(GFP_KERNEL); - if (pgd_none(*pgd)) { - if (pmd) { - clear_page((void *)pmd); - pgd_set(pgd, pmd); - return pmd + offset; - } - pgd_set(pgd, BAD_PAGETABLE); - return NULL; - } - free_page((unsigned long)pmd); - if (pgd_bad(*pgd)) { - __bad_pmd(pgd); - return NULL; - } - return (pmd_t *) pgd_page(*pgd) + offset; -} - -pte_t * -get_pte_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - clear_page((void *)pte); - pmd_set(pmd, pte); - return pte + offset; - } - pmd_set(pmd, (pte_t *) BAD_PAGETABLE); - return NULL; - } - free_page((unsigned long)pte); - if (pmd_bad(*pmd)) { - __bad_pte(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - int do_check_pgt_cache(int low, int high) { int freed = 0; - if(pgtable_cache_size > high) { - do { - if(pgd_quicklist) - free_pgd_slow(get_pgd_fast()), freed++; - if(pmd_quicklist) - free_pmd_slow(get_pmd_fast()), freed++; - if(pte_quicklist) - free_pte_slow(get_pte_fast()), freed++; - } while(pgtable_cache_size > low); - } - return freed; + if(pgtable_cache_size > high) { + do { + if(pgd_quicklist) { + free_pgd_slow(get_pgd_fast()); + freed++; + } + if(pmd_quicklist) { + pmd_free_slow(pmd_alloc_one_fast(NULL, 0)); + freed++; + } + if(pte_quicklist) { + pte_free_slow(pte_alloc_one_fast(NULL, 0)); + freed++; + } + } while(pgtable_cache_size > low); + } + return freed; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/Makefile linux.ac/arch/arm/Makefile --- linux.vanilla/arch/arm/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/Makefile Sat Apr 14 01:15:10 2001 @@ -1,52 +1,36 @@ # # arch/arm/Makefile # -# This file is included by the global makefile so that you can add your own -# architecture-specific flags and dependencies. Remember to do have actions -# for "archclean" and "archdep" for cleaning up and making dependencies for -# this architecture -# # This file is subject to the terms and conditions of the GNU General Public # License. See the file "COPYING" in the main directory of this archive # for more details. # -# Copyright (C) 1995-2000 by Russell King +# Copyright (C) 1995-2001 by Russell King LINKFLAGS :=-p -X -T arch/arm/vmlinux.lds GZFLAGS :=-9 CFLAGS +=-fno-common -pipe -ifdef CONFIG_FRAME_POINTER +ifneq ($(CONFIG_NO_FRAME_POINTER),y) CFLAGS :=$(CFLAGS:-fomit-frame-pointer=) endif -ifdef CONFIG_DEBUG_INFO +ifeq ($(CONFIG_DEBUG_INFO),y) CFLAGS +=-g endif -# Ensure this is ld "2.9.4" or later -NEW_LINKER := $(shell $(LD) --gc-sections --version >/dev/null 2>&1; echo $$?) - -ifneq ($(NEW_LINKER),0) -dummy:; @echo '*** ${VERSION}.${PATCHLEVEL} kernels no longer build correctly with old versions of binutils.' - @echo '*** Please upgrade your binutils to 2.9.5.' - @false -endif - # Select CPU dependent flags. Note that order of declaration is important; # the options further down the list override previous items. # -apcs-$(CONFIG_CPU_26) :=-mapcs-26 -mcpu=arm3 -Os -apcs-$(CONFIG_CPU_32) :=-mapcs-32 +apcs-y := +apcs-$(CONFIG_CPU_26) :=-mcpu=arm3 -Os -arch-$(CONFIG_CPU_32v3) :=-march=armv3 +arch-y := +arch-$(CONFIG_CPU_32v3) :=-march=armv3m arch-$(CONFIG_CPU_32v4) :=-march=armv4 arch-$(CONFIG_CPU_32v5) :=-march=armv5 -proc-$(CONFIG_CPU_32v3) :=-marmv3m -proc-$(CONFIG_CPU_32v4) :=-marmv4 -proc-$(CONFIG_CPU_32v5) :=-marmv5 - +tune-y := tune-$(CONFIG_CPU_ARM610) :=-mtune=arm610 tune-$(CONFIG_CPU_ARM710) :=-mtune=arm710 tune-$(CONFIG_CPU_ARM720T) :=-mtune=arm7tdmi @@ -54,19 +38,27 @@ tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110 tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100 -CFLAGS += $(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -AFLAGS += $(apcs-y) $(proc-y) -mno-fpu +CFLAGS += -mapcs-32 $(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float +AFLAGS += -mapcs-32 $(apcs-y) $(arch-y) -mno-fpu LIBGCC := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name) ifeq ($(CONFIG_CPU_26),y) PROCESSOR = armo -TEXTADDR = 0x02080000 + ifeq ($(CONFIG_ROM_KERNEL),y) + DATAADDR = 0x02080000 + TEXTADDR = 0x03800000 + LDSCRIPT = arch/arm/vmlinux-armo-rom.lds.in + else + TEXTADDR = 0x02080000 + LDSCRIPT = arch/arm/vmlinux-armo.lds.in + endif endif ifeq ($(CONFIG_CPU_32),y) PROCESSOR = armv TEXTADDR = 0xC0008000 +LDSCRIPT = arch/arm/vmlinux-armv.lds.in endif ifeq ($(CONFIG_ARCH_ARCA5K),y) @@ -97,8 +89,13 @@ INCDIR = ebsa285 endif -ifeq ($(CONFIG_ARCH_NEXUSPCI),y) -MACHINE = nexuspci +ifeq ($(CONFIG_ARCH_FTVPCI),y) +MACHINE = ftvpci +INCDIR = nexuspci +endif + +ifeq ($(CONFIG_ARCH_TBOX),y) +MACHINE = tbox endif ifeq ($(CONFIG_ARCH_SHARK),y) @@ -134,6 +131,10 @@ INCDIR := $(MACHINE) endif +ifeq ($(origin DATAADDR), undefined) +DATAADDR := . +endif + # If we have a machine-specific directory, then include it in the build. MACHDIR := arch/arm/mach-$(MACHINE) ifeq ($(MACHDIR),$(wildcard $(MACHDIR))) @@ -143,13 +144,17 @@ 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/nwfpe +SUBDIRS += arch/arm/kernel arch/arm/mm arch/arm/lib arch/arm/nwfpe \ + arch/arm/fastfpe CORE_FILES := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES) -LIBS := arch/arm/lib/lib.o arch/arm/lib/lib.a $(LIBS) $(LIBGCC) +LIBS := arch/arm/lib/lib.a $(LIBS) $(LIBGCC) -ifeq ($(CONFIG_NWFPE),y) +ifeq ($(CONFIG_FPE_NWFPE),y) LIBS := arch/arm/nwfpe/math-emu.o $(LIBS) endif +ifeq ($(CONFIG_FPE_FASTFPE),y) +LIBS := arch/arm/fastfpe/fast-math-emu.o $(LIBS) +endif ifeq ($(CONFIG_ARCH_CLPS7500),y) SUBDIRS += drivers/acorn/char @@ -157,21 +162,13 @@ endif MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot +MAKETOOLS = $(MAKE) -C arch/$(ARCH)/tools # The following is a hack to get 'constants.h' up # to date before starting compilation -$(patsubst %, _dir_%, $(SUBDIRS)) init/main.o init/version.o : \ - include/asm-arm/mach-types.h - -$(patsubst %, _dir_%, $(SUBDIRS)) : constants - -include/asm-arm/mach-types.h: arch/arm/tools/mach-types \ - arch/arm/tools/gen-mach-types - @awk -f arch/arm/tools/gen-mach-types arch/arm/tools/mach-types > $@ - -constants: dummy - @$(MAKE) -C arch/arm/lib constants.h +$(patsubst %,_dir_%, $(SUBDIRS)): maketools +$(patsubst %,_modsubdir_%,$(MOD_DIRS)): maketools symlinks: archsymlinks @@ -181,8 +178,8 @@ vmlinux: arch/arm/vmlinux.lds -arch/arm/vmlinux.lds: arch/arm/vmlinux-$(PROCESSOR).lds.in dummy - @sed 's/TEXTADDR/$(TEXTADDR)/' <$< >$@ +arch/arm/vmlinux.lds: $(LDSCRIPT) dummy + @sed 's/TEXTADDR/$(TEXTADDR)/;s/DATAADDR/$(DATAADDR)/' $(LDSCRIPT) >$@ arch/arm/kernel arch/arm/mm arch/arm/lib: dummy $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@) @@ -190,17 +187,42 @@ bzImage zImage zinstall Image bootpImage install: vmlinux @$(MAKEBOOT) $@ +CLEAN_FILES += \ + arch/arm/vmlinux.lds + +MRPROPER_FILES += \ + include/asm-arm/arch \ + include/asm-arm/proc \ + include/asm-arm/constants.h* \ + include/asm-arm/mach-types.h + +# We use MRPROPER_FILES and CLEAN_FILES now archmrproper: - $(RM) include/asm-arm/arch include/asm-arm/proc + @/bin/true archclean: @$(MAKEBOOT) clean - $(RM) arch/arm/lib/constants.h arch/arm/vmlinux.lds - $(RM) include/asm-arm/mach-types.h -archdep: archsymlinks +archdep: scripts/mkdep archsymlinks + @$(MAKETOOLS) dep @$(MAKEBOOT) dep +maketools: checkbin + @$(MAKETOOLS) all + +# Ensure this is ld "2.9.4" or later +NEW_LINKER := $(shell $(LD) --gc-sections --version >/dev/null 2>&1; echo $$?) + +ifneq ($(NEW_LINKER),0) +checkbin: + @echo '*** ${VERSION}.${PATCHLEVEL} kernels no longer build correctly with old versions of binutils.' + @echo '*** Please upgrade your binutils to 2.9.5.' + @false +else +checkbin: + @true +endif + # My testing targets (that short circuit a few dependencies) zImg:; @$(MAKEBOOT) zImage Img:; @$(MAKEBOOT) Image @@ -211,15 +233,7 @@ # # Configuration targets. Use these to select a # configuration for your architecture -CFGS= a5k_config ebsa110_config \ - footbridge_config rpc_config \ - brutus_config victor_config \ - empeg_config graphicsclient_config \ - assabet_config lart_config \ - cerf_config lusl7200_config \ - sherman_config pangolin_config - -$(CFGS): +%_config: @( \ CFG=$(@:_config=); \ if [ -f arch/arm/def-configs/$$CFG ]; then \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/boot/Makefile linux.ac/arch/arm/boot/Makefile --- linux.vanilla/arch/arm/boot/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/boot/Makefile Sat Apr 14 01:15:10 2001 @@ -55,8 +55,7 @@ endif ifeq ($(CONFIG_ARCH_NEXUSPCI),y) -ZTEXTADDR = 0x40200000 -ZRELADDR = 0x40008000 +ZTEXTADDR = 0x40008000 endif ifeq ($(CONFIG_ARCH_L7200),y) @@ -72,7 +71,6 @@ ifeq ($(CONFIG_ARCH_P720T),y) ZTEXTADDR = 0xc0018000 -ZRELADDR = 0xc0018000 PARAMS_PHYS = 0xc0000100 INITRD_PHYS = 0xc0400000 INITRD_VIRT = 0xc0400000 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/boot/compressed/Makefile linux.ac/arch/arm/boot/compressed/Makefile --- linux.vanilla/arch/arm/boot/compressed/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/boot/compressed/Makefile Sat Apr 14 01:15:10 2001 @@ -9,7 +9,7 @@ HEAD = head.o OBJS = misc.o -CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS $(CFLAGS_PROC) +CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS $(CFLAGS_PROC) -msoft-float FONTC = $(TOPDIR)/drivers/video/font_acorn_8x8.c ZLDFLAGS = -p -X -T vmlinux.lds @@ -25,16 +25,24 @@ OBJS += head-netwinder.o endif +ifeq ($(CONFIG_ARCH_SHARK),y) +OBJS += head-shark.o ofw-shark.o +endif + ifeq ($(CONFIG_ARCH_INTEGRATOR),y) OBJS += head-netwinder.o endif -ifeq ($(CONFIG_ARCH_NEXUSPCI),y) -HEAD = head-nexuspci.o +ifeq ($(CONFIG_ARCH_FTVPCI),y) +OBJS += head-ftvpci.o endif ifeq ($(CONFIG_ARCH_L7200),y) OBJS += head-l7200.o +endif + +ifeq ($(CONFIG_ARCH_CLPS7500),y) +HEAD = head-clps7500.o endif ifeq ($(CONFIG_ARCH_P720T),y) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/boot/compressed/head-clps7500.S linux.ac/arch/arm/boot/compressed/head-clps7500.S --- linux.vanilla/arch/arm/boot/compressed/head-clps7500.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/boot/compressed/head-clps7500.S Sat Apr 14 01:15:10 2001 @@ -0,0 +1,87 @@ +/* + * linux/arch/arm/boot/compressed/head.S + * + * Copyright (C) 1999, 2000, 2001 Nexus Electronics Ltd + */ + +#include <linux/config.h> + + /* There are three different ways the kernel can be + booted on a 7500 system: from Angel (loaded in RAM), from + 16-bit ROM or from 32-bit Flash. Luckily, a single kernel + image does for them all. */ + /* This branch is taken if the CPU memory width matches the + actual device in use. The default at power on is 16 bits + so we must be prepared for a mismatch. */ + .section ".start", #alloc, #execinstr +2: + b 1f + .word 0xffff + .word 0xb632 @ mov r11, #0x03200000 + .word 0xe3a0 + .word 0x0000 @ mov r0, #0 + .word 0xe3a0 + .word 0x0080 @ strb r0, [r11, #0x80] + .word 0xe5cb + .word 0xf000 @ mov pc, #0 + .word 0xe3a0 +1: + adr r1, 2b + teq r1, #0 + bne .Langel + /* This is a direct-from-ROM boot. Copy the kernel into + RAM and run it there. */ + mov r0, #0x30 + mcr p15, 0, r0, c1, c0, 0 + mov r0, #0x13 + msr cpsr, r0 + mov r12, #0x03000000 @ point to LEDs + orr r12, r12, #0x00020000 + orr r12, r12, #0xba00 + mov r0, #0x5500 + str r0, [r12] + mov r0, #0x10000000 + orr r0, r0, #0x8000 + mov r4, r0 + ldr r2, =_end +2: + ldr r3, [r1], #4 + str r3, [r0], #4 + teq r0, r2 + bne 2b + mov r0, #0xff00 + str r0, [r12] +1: + mov r12, #0x03000000 @ point to LEDs + orr r12, r12, #0x00020000 + orr r12, r12, #0xba00 + mov r0, #0xfe00 + str r0, [r12] + + adr lr, 1f + mov r0, #0 + mov r1, #14 /* MACH_TYPE_CLPS7500 */ + mov pc, lr +.Langel: +#ifdef CONFIG_ANGELBOOT + /* Call Angel to switch into SVC mode. */ + mov r0, #0x17 + swi 0x123456 +#endif + /* Ensure all interrupts are off and MMU disabled */ + mrs r0, cpsr + orr r0, r0, #0xc0 + msr cpsr, r0 + + adr lr, 1b + orr lr, lr, #0x10000000 + mov r0, #0x30 @ MMU off + mcr p15, 0, r0, c1, c0, 0 + mov r0, r0 + mov pc, lr + + .ltorg + +1: +/* And the rest */ +#include "head.S" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/boot/compressed/head-shark.S linux.ac/arch/arm/boot/compressed/head-shark.S --- linux.vanilla/arch/arm/boot/compressed/head-shark.S Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/boot/compressed/head-shark.S Sat Apr 14 01:15:10 2001 @@ -1,5 +1,5 @@ /* The head-file for the Shark - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> * * Does the following: * - get the memory layout from firmware. This can only be done as long as the mmu @@ -20,8 +20,6 @@ b __beginning -__serial_addr: .long 0xf7eff3f8 - .long 0 @ space __ofw_data: .long 0 @ the number of memory blocks .space 128 @ (startaddr,size) ... .space 128 @ bootargs @@ -31,14 +29,10 @@ mov r0, #0xC0 @ disable irq and fiq mov r1, r0 - mrs r3, cpsr_all + mrs r3, cpsr bic r2, r3, r0 eor r2, r2, r1 - msr cpsr_all, r2 - - ldr r0, __serial_addr @ disable serial interrupt - mov r1, #0 @ hangs the machine, I don t know why. - strb r1, [r0, #0x01] + msr cpsr_c, r2 mov r0, r4 @ get the Memory layout from firmware adr r1, __ofw_data diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/boot/compressed/head.S linux.ac/arch/arm/boot/compressed/head.S --- linux.vanilla/arch/arm/boot/compressed/head.S Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/boot/compressed/head.S Sat Apr 14 01:15:10 2001 @@ -87,7 +87,8 @@ b 1f .word 0x016f2818 @ Magic numbers to help the loader - .word start + .word start @ absolute load/run zImage address + .word _edata @ zImage end address 1: mov r7, r1 @ save architecture ID mov r8, #0 @ save r0 #ifdef CONFIG_ANGELBOOT @@ -210,7 +211,7 @@ mov r0, r3 mov r8, r0, lsr #18 mov r8, r8, lsl #18 @ start of RAM - add r9, r8, #0x20000000 @ the maximum RAM size + add r9, r8, #0x10000000 @ a reasonable RAM size mov r1, #0x12 orr r1, r1, #3 << 10 add r2, r3, #16384 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/boot/compressed/ll_char_wr.S linux.ac/arch/arm/boot/compressed/ll_char_wr.S --- linux.vanilla/arch/arm/boot/compressed/ll_char_wr.S Mon Sep 18 23:15:24 2000 +++ linux.ac/arch/arm/boot/compressed/ll_char_wr.S Sat Apr 14 01:15:10 2001 @@ -16,7 +16,7 @@ @ Regs: [] = corruptible @ {} = used @ () = do not use -#define __ASSEMBLY__ + #include <linux/linkage.h> #include <asm/assembler.h> .text diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/boot/compressed/ofw-shark.c linux.ac/arch/arm/boot/compressed/ofw-shark.c --- linux.vanilla/arch/arm/boot/compressed/ofw-shark.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/boot/compressed/ofw-shark.c Sat Apr 14 01:15:10 2001 @@ -1,7 +1,7 @@ /* * linux/arch/arm/boot/compressed/ofw-shark.c * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> * * This file is used to get some basic information * about the memory layout of the shark we are running @@ -11,6 +11,7 @@ #include <linux/kernel.h> +#include <linux/types.h> #include <asm/setup.h> #include <asm/page.h> @@ -18,7 +19,7 @@ asmlinkage void create_params (unsigned long *buffer) { - /* Is there a better address? Also change in kernel/arch.c */ + /* Is there a better address? Also change in mach-shark/arch.c */ struct param_struct *params = (struct param_struct *) 0x08003000; int j,i,m,k,nr_banks,size; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/boot/compressed/setup-sa1100.S linux.ac/arch/arm/boot/compressed/setup-sa1100.S --- linux.vanilla/arch/arm/boot/compressed/setup-sa1100.S Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/boot/compressed/setup-sa1100.S Sat Apr 14 01:15:10 2001 @@ -24,6 +24,9 @@ PPC_BASE: .long 0x90060000 #define PPAR 0x08 +IC_BASE: .long 0x90050000 +#define ICMR 0x04 + UART1_BASE: .long 0x80010000 UART3_BASE: .long 0x80050000 #define UTCR0 0x00 @@ -52,6 +55,11 @@ ENTRY(sa1100_setup) mov r3, r0 @ keep machine type in r3 + @ Clear all interrupt sources + ldr r0, IC_BASE + mov r1, #0 + str r1, [r0, #ICMR] + @ Read System Configuration "Register" for Assabet. @ (taken from "Intel StrongARM SA-1110 Microprocessor Development Board @ User's Guide," p.4-9) @@ -87,6 +95,7 @@ @ Initialize UART (if bootloader has not done it yet)... teq r3, #MACH_TYPE_BRUTUS teqne r3, #MACH_TYPE_ASSABET + teqne r3, #MACH_TYPE_GRAPHICSCLIENT bne skip_uart @ UART3 if Assabet is used with Neponset @@ -95,6 +104,11 @@ ldreq r0, UART3_BASE beq uart_init + @ UART3 on GraphicsClient + teq r3, #MACH_TYPE_GRAPHICSCLIENT + ldreq r0, UART3_BASE + beq uart_init + @ At least for Brutus, the UART1 is used through @ the alternate GPIO function... teq r3, #MACH_TYPE_BRUTUS @@ -115,7 +129,8 @@ uart1: ldr r0, UART1_BASE -uart_init: ldr r1, [r0, #UTSR1] +uart_init: +1: ldr r1, [r0, #UTSR1] tst r1, #1<<0 @ TBY bne 1b mov r1, #0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/config.in linux.ac/arch/arm/config.in --- linux.vanilla/arch/arm/config.in Fri Feb 9 19:38:27 2001 +++ linux.ac/arch/arm/config.in Sat Apr 14 01:15:10 2001 @@ -21,10 +21,8 @@ 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 module symbols' CONFIG_MODVERSIONS - bool ' Kernel module loader' CONFIG_KMOD -fi +dep_bool ' Set version information on all module symbols' CONFIG_MODVERSIONS $CONFIG_MODULES +dep_bool ' Kernel module loader' CONFIG_KMOD $CONFIG_MODULES endmenu @@ -36,71 +34,62 @@ Cirrus-CL-PS7500FE CONFIG_ARCH_CLPS7500 \ Co-EBSA285 CONFIG_ARCH_CO285 \ EBSA-110 CONFIG_ARCH_EBSA110 \ + LinkUp-L7200 CONFIG_ARCH_L7200 \ FootBridge CONFIG_ARCH_FOOTBRIDGE \ Integrator CONFIG_ARCH_INTEGRATOR \ RiscPC CONFIG_ARCH_RPC \ - SA1100-based CONFIG_ARCH_SA1100" RiscPC - -# the following are placeholders for when they are fully integrated -# LinkUp-L7200 CONFIG_ARCH_L7200 + SA1100-based CONFIG_ARCH_SA1100 \ + CLPS711x/EP721x-based CONFIG_ARCH_CLPS711X" RiscPC mainmenu_option next_comment comment 'Archimedes/A5000 Implementations' -if [ "$CONFIG_ARCH_ARCA5K" = "y" ]; then - # These architectures will be combined. However, until this - # is complete... Note that the ARC will take precidence over - # A5K - comment 'Archimedes/A5000 Implementations (select only ONE)' - - bool ' Archimedes' CONFIG_ARCH_ARC - bool ' A5000' CONFIG_ARCH_A5K -fi +# These architectures will be combined. However, until this +# is complete... Note that the ARC will take precedence over +# A5K +comment 'Archimedes/A5000 Implementations (select only ONE)' +dep_bool ' Archimedes' CONFIG_ARCH_ARC $CONFIG_ARCH_ARCA5K +dep_bool ' A5000' CONFIG_ARCH_A5K $CONFIG_ARCH_ARCA5K endmenu mainmenu_option next_comment comment 'Footbridge Implementations' -if [ "$CONFIG_ARCH_FOOTBRIDGE" = "y" ]; then - bool ' CATS' CONFIG_ARCH_CATS - bool ' Compaq Personal Server' CONFIG_ARCH_PERSONAL_SERVER - bool ' EBSA285 (addin mode)' CONFIG_ARCH_EBSA285_ADDIN - bool ' EBSA285 (host mode)' CONFIG_ARCH_EBSA285_HOST - bool ' NetWinder' CONFIG_ARCH_NETWINDER -fi +dep_bool ' CATS' CONFIG_ARCH_CATS $CONFIG_ARCH_FOOTBRIDGE +dep_bool ' Compaq Personal Server' CONFIG_ARCH_PERSONAL_SERVER $CONFIG_ARCH_FOOTBRIDGE +dep_bool ' EBSA285 (addin mode)' CONFIG_ARCH_EBSA285_ADDIN $CONFIG_ARCH_FOOTBRIDGE +dep_bool ' EBSA285 (host mode)' CONFIG_ARCH_EBSA285_HOST $CONFIG_ARCH_FOOTBRIDGE +dep_bool ' NetWinder' CONFIG_ARCH_NETWINDER $CONFIG_ARCH_FOOTBRIDGE endmenu mainmenu_option next_comment comment 'SA11x0 Implementations' -if [ "$CONFIG_ARCH_SA1100" = "y" ]; then - - bool ' Assabet' CONFIG_SA1100_ASSABET - if [ "$CONFIG_SA1100_ASSABET" = "y" ]; then - bool ' Include support for Neponset' CONFIG_ASSABET_NEPONSET - fi - bool ' Brutus' CONFIG_SA1100_BRUTUS - bool ' CerfBoard' CONFIG_SA1100_CERF - bool ' Compaq iPAQ H3600 (Bitsy)' CONFIG_SA1100_BITSY -# bool ' Empeg' CONFIG_SA1100_EMPEG -# bool ' Itsy' CONFIG_SA1100_ITSY - bool ' LART' CONFIG_SA1100_LART -# bool ' PLEB' CONFIG_SA1100_PLEB - bool ' ThinClient' CONFIG_SA1100_THINCLIENT - bool ' GraphicsClient' CONFIG_SA1100_GRAPHICSCLIENT - bool ' nanoEngine' CONFIG_SA1100_NANOENGINE - bool ' Victor' CONFIG_SA1100_VICTOR -# bool ' Tifon' CONFIG_SA1100_TIFON - bool ' XP860' CONFIG_SA1100_XP860 - - # Someday, we'll support this as a general option. - bool ' Load kernel using Angel Debug Monitor' CONFIG_ANGELBOOT - - # Determine if SA1111 support is required - if [ "$CONFIG_ASSABET_NEPONSET" = "y" -o \ - "$CONFIG_SA1100_XP860" = "y" ]; then - define_bool CONFIG_SA1111 y - fi +dep_bool ' Assabet' CONFIG_SA1100_ASSABET $CONFIG_ARCH_SA1100 +dep_bool ' Include support for Neponset' CONFIG_ASSABET_NEPONSET $CONFIG_SA1100_ASSABET +dep_bool ' Brutus' CONFIG_SA1100_BRUTUS $CONFIG_ARCH_SA1100 +dep_bool ' CerfBoard' CONFIG_SA1100_CERF $CONFIG_ARCH_SA1100 +dep_bool ' Compaq iPAQ H3600 (Bitsy)' CONFIG_SA1100_BITSY $CONFIG_ARCH_SA1100 +#dep_bool ' Empeg' CONFIG_SA1100_EMPEG $CONFIG_ARCH_SA1100 +#dep_bool ' Itsy' CONFIG_SA1100_ITSY $CONFIG_ARCH_SA1100 +dep_bool ' LART' CONFIG_SA1100_LART $CONFIG_ARCH_SA1100 +#dep_bool ' PLEB' CONFIG_SA1100_PLEB $CONFIG_ARCH_SA1100 +dep_bool ' GraphicsClient' CONFIG_SA1100_GRAPHICSCLIENT $CONFIG_ARCH_SA1100 +dep_bool ' nanoEngine' CONFIG_SA1100_NANOENGINE $CONFIG_ARCH_SA1100 +dep_bool ' Victor' CONFIG_SA1100_VICTOR $CONFIG_ARCH_SA1100 +dep_bool ' Sherman' CONFIG_SA1100_SHERMAN $CONFIG_ARCH_SA1100 +dep_bool ' XP860' CONFIG_SA1100_XP860 $CONFIG_ARCH_SA1100 +dep_bool ' Pangolin' CONFIG_SA1100_PANGOLIN $CONFIG_ARCH_SA1100 + +# Determine if SA1111 support is required +if [ "$CONFIG_ASSABET_NEPONSET" = "y" -o \ + "$CONFIG_SA1100_XP860" = "y" ]; then + define_bool CONFIG_SA1111 y fi endmenu +mainmenu_option next_comment +comment 'CLPS711X/EP721X Implementations' +dep_bool ' P720T' CONFIG_ARCH_P720T $CONFIG_ARCH_CLPS711X +endmenu + # Definitions to make life easier if [ "$CONFIG_ARCH_ARCA5K" = "y" -o \ "$CONFIG_ARCH_RPC" = "y" ]; then @@ -147,49 +136,77 @@ comment 'Processor Type' -# Select CPU and optimisation dependent on architecture -if [ "$CONFIG_ARCH_RPC" = "y" ]; then +# Firstly, figure out what processor architecture version we should be using. +if [ "$CONFIG_ARCH_RPC" = "y" -o "$CONFIG_ARCH_CLPS7500" = "y" ]; then define_bool CONFIG_CPU_32v3 y - bool 'Support ARM610 processor' CONFIG_CPU_ARM6 - bool 'Support ARM710 processor' CONFIG_CPU_ARM7 - bool 'Support StrongARM(R) SA-110 processor' CONFIG_CPU_SA110 +else + define_bool CONFIG_CPU_32v3 n fi -if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ - "$CONFIG_FOOTBRIDGE" = "y" -o \ - "$CONFIG_ARCH_TBOX" = "y" -o \ - "$CONFIG_ARCH_SHARK" = "y" -o \ - "$CONFIG_ARCH_NEXUSPCI" = "y" ]; then +if [ "$CONFIG_ARCH_EBSA110" = "y" -o "$CONFIG_FOOTBRIDGE" = "y" -o \ + "$CONFIG_ARCH_TBOX" = "y" -o "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_ARCH_NEXUSPCI" = "y" -o "$CONFIG_ARCH_CLPS711X" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" -o "$CONFIG_ARCH_SA1100" = "y" -o \ + "$CONFIG_ARCH_L7200" = "y" ]; then define_bool CONFIG_CPU_32v4 y - define_bool CONFIG_CPU_SA110 y +else + define_bool CONFIG_CPU_32v4 n fi + +# Select CPU types depending on the architecture selected. +# We use this to select which CPUs are supported, and to select +# the compiler tuning options. + +# ARM610 +if [ "$CONFIG_ARCH_RPC" = "y" ]; then + bool 'Support ARM610 processor' CONFIG_CPU_ARM610 +else + define_bool CONFIG_CPU_ARM610 n +fi + +# ARM710 if [ "$CONFIG_ARCH_CLPS7500" = "y" ]; then - define_bool CONFIG_CPU_32v3 y - define_bool CONFIG_CPU_ARM7 y + define_bool CONFIG_CPU_ARM710 y +else + if [ "$CONFIG_ARCH_RPC" = "y" ]; then + bool 'Support ARM710 processor' CONFIG_CPU_ARM710 + else + define_bool CONFIG_CPU_ARM710 n + fi fi -if [ "$CONFIG_ARCH_L7200" = "y" ]; then - define_bool CONFIG_CPU_32v4 y - define_bool CONFIG_CPU_ARM720 y + +# ARM720T +if [ "$CONFIG_ARCH_CLPS711X" = "y" -o "$CONFIG_ARCH_L7200" = "y" ]; then + define_bool CONFIG_CPU_ARM720T y +else + if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then + bool 'Support ARM720T processor' CONFIG_CPU_ARM720T + else + define_bool CONFIG_CPU_ARM720T n + fi fi + +# ARM920T if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then - define_bool CONFIG_CPU_32v4 y - bool 'Support ARM720 processor' CONFIG_CPU_ARM720 - bool 'Support ARM920 processor' CONFIG_CPU_ARM920 -# bool 'Support ARM10 processor' CONFIG_CPU_ARM10 -fi -if [ "$CONFIG_ARCH_SA1100" = "y" ]; then - define_bool CONFIG_CPU_32v4 y - define_bool CONFIG_CPU_SA1100 y + bool 'Support ARM920T processor' CONFIG_CPU_ARM920T +else + define_bool CONFIG_CPU_ARM920T n fi - -if [ "$CONFIG_CPU_ARM920" = "y" ]; then - bool ' ARM920 CPU idle' CONFIG_CPU_ARM920_CPU_IDLE - bool ' ARM920 I-Cache on' CONFIG_CPU_ARM920_I_CACHE_ON - bool ' ARM920 D-Cache on' CONFIG_CPU_ARM920_D_CACHE_ON +if [ "$CONFIG_CPU_ARM920T" = "y" ]; then + bool ' ARM920T CPU idle' CONFIG_CPU_ARM920_CPU_IDLE + bool ' ARM920T I-Cache on' CONFIG_CPU_ARM920_I_CACHE_ON + bool ' ARM920T D-Cache on' CONFIG_CPU_ARM920_D_CACHE_ON if [ "$CONFIG_CPU_ARM920_D_CACHE_ON" = "y" ] ; then - bool ' Force write through caches on ARM920' CONFIG_CPU_ARM920_WRITETHROUGH + bool ' Force write through caches on ARM920T' CONFIG_CPU_ARM920_WRITETHROUGH fi fi -#if [ "$CONFIG_CPU_ARM10" = "y" ]; then + +# ARM1020 +#if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then +# bool 'Support ARM1020 processor' CONFIG_CPU_ARM1020 +#else + define_bool CONFIG_CPU_ARM1020 n +#fi +#if [ "$CONFIG_CPU_ARM1020" = "y" ]; then # bool ' ARM10 I-Cache on' CONFIG_CPU_ARM10_I_CACHE_ON # bool ' ARM10 D-Cache on' CONFIG_CPU_ARM10_D_CACHE_ON # if [ "$CONFIG_CPU_ARM10_D_CACHE_ON" = "y" ] ; then @@ -197,6 +214,30 @@ # fi #fi +# SA110 +if [ "$CONFIG_ARCH_EBSA110" = "y" -o "$CONFIG_FOOTBRIDGE" = "y" -o \ + "$CONFIG_ARCH_TBOX" = "y" -o "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_ARCH_NEXUSPCI" = "y" ]; then + define_bool CONFIG_CPU_SA110 y +else + if [ "$CONFIG_ARCH_RPC" = "y" ]; then + bool 'Support StrongARM(R) SA-110 processor' CONFIG_CPU_SA110 + else + define_bool CONFIG_CPU_SA110 n + fi +fi + +# SA1100 +if [ "$CONFIG_ARCH_SA1100" = "y" ]; then + define_bool CONFIG_CPU_SA1100 y +else + define_bool CONFIG_CPU_SA1100 n +fi + +#if [ "$CONFIG_CPU_32" = "y" ]; then +# bool 'Support Thumb instructions' CONFIG_ARM_THUMB +#fi + # Select various configuration options depending on the machine type if [ "$CONFIG_ARCH_SA1100" = "y" ]; then define_bool CONFIG_DISCONTIGMEM y @@ -209,8 +250,12 @@ mainmenu_option next_comment comment 'General setup' +comment 'Please ensure that you have read the help on the next option' +bool 'Load kernel using Angel Debug Monitor' CONFIG_ANGELBOOT + # Now handle the bus types -if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o \ +if [ "$CONFIG_ARCH_FTVPCI" = "y" -o \ + "$CONFIG_ARCH_SHARK" = "y" -o \ "$CONFIG_FOOTBRIDGE_HOST" = "y" ]; then define_bool CONFIG_PCI y else @@ -223,21 +268,19 @@ fi if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \ - "$CONFIG_ARCH_SHARK" = "y" ]; then + "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_ARCH_CLPS7500" = "y" -o \ + "$CONFIG_ARCH_EBSA110" = "y" ]; then define_bool CONFIG_ISA y - define_bool CONFIG_ISA_DMA y else define_bool CONFIG_ISA n - define_bool CONFIG_ISA_DMA n fi -# Do we have a PC-type keyboard in this architecture? -if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" ]; then - define_bool CONFIG_PC_KEYB y - define_bool CONFIG_PC_KEYMAP y -fi -if [ "$CONFIG_SA1100_ASSABET" = "y" ]; then - define_bool CONFIG_PC_KEYMAP y +if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \ + "$CONFIG_ARCH_SHARK" = "y" ]; then + define_bool CONFIG_ISA_DMA y +else + define_bool CONFIG_ISA_DMA n fi source drivers/pci/Config.in @@ -251,42 +294,44 @@ bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL -tristate 'NWFPE math emulation' CONFIG_NWFPE +tristate 'NWFPE math emulation' CONFIG_FPE_NWFPE +dep_tristate 'FastFPE math emulation (experimental)' CONFIG_FPE_FASTFPE $CONFIG_EXPERIMENTAL choice 'Kernel core (/proc/kcore) format' \ "ELF CONFIG_KCORE_ELF \ A.OUT CONFIG_KCORE_AOUT" ELF 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 +dep_bool 'Power Management support (experimental)' CONFIG_PM $CONFIG_EXPERIMENTAL +dep_tristate 'RISC OS personality' CONFIG_ARTHUR $CONFIG_CPU_32 -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'Power Management support' CONFIG_PM -fi - -if [ "$CONFIG_CPU_32" = "y" ]; then - tristate 'RISC OS personality' CONFIG_ARTHUR -fi -if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ - "$CONFIG_ARCH_SA1100" = "y" -o \ - "$CONFIG_ARCH_CLPS7500" = "y" -o \ +if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ + "$CONFIG_ARCH_SA1100" = "y" -o \ + "$CONFIG_ARCH_CLPS7500" = "y" -o \ "$CONFIG_ARCH_PERSONAL_SERVER" = "y" -o \ - "$CONFIG_ARCH_CATS" = "y" -o \ - "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then + "$CONFIG_ARCH_CATS" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" -o \ + "$CONFIG_ARCH_P720T" = "y" ]; then string 'Default 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" -o \ - "$CONFIG_ARCH_SA1100" = "y" -o \ - "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then +if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ + "$CONFIG_ARCH_EBSA110" = "y" -o \ + "$CONFIG_ARCH_EBSA285" = "y" -o \ + "$CONFIG_ARCH_FTVPCI" = "y" -o \ + "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_ARCH_CO285" = "y" -o \ + "$CONFIG_ARCH_SA1100" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" -o \ + "$CONFIG_ARCH_P720T" = "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" -o \ - "$CONFIG_ARCH_SA1100" = "y" -o \ - "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then + if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ + "$CONFIG_ARCH_EBSA285" = "y" -o \ + "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_ARCH_CO285" = "y" -o \ + "$CONFIG_ARCH_SA1100" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" -o \ + "$CONFIG_ARCH_P720T" = "y" ]; then bool ' Timer LED' CONFIG_LEDS_TIMER bool ' CPU usage LED' CONFIG_LEDS_CPU fi @@ -350,9 +395,13 @@ fi endmenu +if [ "$CONFIG_ARCH_CLPS711X" = "y" ]; then + source drivers/ssi/Config.in +fi + source drivers/ieee1394/Config.in -source drivers/i2o/Config.in +source drivers/message/i2o/Config.in mainmenu_option next_comment comment 'ISDN subsystem' @@ -363,6 +412,11 @@ fi endmenu +# +# input before char - char/joystick depends on it. As does USB. +# +source drivers/input/Config.in + source drivers/char/Config.in if [ "$CONFIG_ARCH_ACORN" = "y" -a \ "$CONFIG_BUSMOUSE" = "y" ]; then @@ -373,11 +427,34 @@ fi fi +source drivers/media/Config.in + source fs/Config.in if [ "$CONFIG_VT" = "y" ]; then mainmenu_option next_comment comment 'Console drivers' + # Select the keyboard type for this architecture. + if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \ + "$CONFIG_ARCH_CLPS7500" = "y" -o \ + "$CONFIG_ARCH_SHARK" = "y" ]; then + define_bool CONFIG_PC_KEYB y + fi + if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then + define_bool CONFIG_KMI_KEYB y + define_bool CONFIG_KMI_MOUSE y + fi + + # Do we use the PC-type keyboard map? + if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \ + "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_ARCH_SA1100" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" -o \ + "$CONFIG_ARCH_TBOX" = "y" -o \ + "$CONFIG_ARCH_CLPS7500" = "y" -o \ + "$CONFIG_ARCH_P720T" = "y" ]; then + define_bool CONFIG_PC_KEYMAP y + fi if [ "$CONFIG_ARCH_ACORN" != "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then bool 'VGA text console' CONFIG_VGA_CONSOLE fi @@ -388,6 +465,7 @@ if [ "$CONFIG_ARCH_ACORN" = "y" -o \ "$CONFIG_ARCH_CLPS7500" = "y" -o \ + "$CONFIG_ARCH_TBOX" = "y" -o \ "$CONFIG_ARCH_SHARK" = "y" -o \ "$CONFIG_PCI" = "y" ]; then mainmenu_option next_comment @@ -408,23 +486,14 @@ # Always compile kernel with framepointer (until 2.4 real comes out) # Bug reports aren't much use without this. -#bool 'Compile kernel with frame pointer (for useful debugging)' CONFIG_FRAME_POINTER -define_bool CONFIG_FRAME_POINTER y +bool 'Compile kernel without frame pointer' CONFIG_NO_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 '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 footbridge serial port' CONFIG_DEBUG_DC21285_PORT - fi - fi -fi +dep_bool 'Disable pgtable cache' CONFIG_NO_PGT_CACHE $CONFIG_CPU_26 +# These options are only for real kernel hackers who want to get their hands dirty. +dep_bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL $CONFIG_EXPERIMENTAL +dep_bool ' Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT $CONFIG_DEBUG_LL $CONFIG_FOOTBRIDGE +dep_bool ' kernel low-level debugging messages via UART2' CONFIG_DEBUG_CLPS711X_UART2 $CONFIG_DEBUG_LL $CONFIG_ARCH_CLPS711X endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/Makefile linux.ac/arch/arm/kernel/Makefile --- linux.vanilla/arch/arm/kernel/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/kernel/Makefile Sat Apr 14 01:15:10 2001 @@ -13,16 +13,18 @@ AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) +# This is depreciated. O_OBJS_arc = dma-arc.o oldlatches.o O_OBJS_rpc = dma-rpc.o O_OBJS_footbridge = dma-footbridge.o isa.o O_OBJS_l7200 = fiq.o -pci-nexuspci = plx90x0.o +pci-ftvpci = plx90x0.o pci-footbridge = dec21285.o pci-shark = via82c505.o -pci-$(CONFIG_ARCH_NEXUSPCI) += ftv-pci.o +# this is here to allow us to eventually move it out to mach-ftvpci +pci-$(CONFIG_ARCH_FTVPCI) += ftv-pci.o O_TARGET := kernel.o @@ -36,7 +38,7 @@ obj-n := obj- := -export-objs := armksyms.o dma.o ecard.o fiq.o oldlatches.o time.o +export-objs := armksyms.o dma.o ecard.o fiq.o io.o oldlatches.o time.o no-irq-arch := $(CONFIG_ARCH_INTEGRATOR) $(CONFIG_ARCH_CLPS711X) \ $(CONFIG_ARCH_FOOTBRIDGE) $(CONFIG_ARCH_EBSA110) @@ -46,16 +48,21 @@ endif obj-$(CONFIG_ARCH_ACORN) += ecard.o fiq.o time-acorn.o +obj-$(CONFIG_ARCH_CLPS7500) += time-acorn.o obj-$(CONFIG_DEBUG_LL) += debug-$(PROCESSOR).o obj-$(CONFIG_MODULES) += armksyms.o obj-$(CONFIG_ARTHUR) += arthur.o obj-$(CONFIG_ISA_DMA) += dma-isa.o obj-$(CONFIG_PCI) += bios32.o $(pci-$(MACHINE)) $(pci-y) +ifneq ($(MACHINE),ebsa110) + obj-y += io.o +endif + all: kernel.o $(HEAD_OBJ) init_task.o include $(TOPDIR)/Rules.make # 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 +entry-armv.o: calls.S $(TOPDIR)/include/asm-arm/constants.h +entry-armo.o: calls.S $(TOPDIR)/include/asm-arm/constants.h diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/arch.c linux.ac/arch/arm/kernel/arch.c --- linux.vanilla/arch/arm/kernel/arch.c Mon Sep 18 23:15:24 2000 +++ linux.ac/arch/arm/kernel/arch.c Sat Apr 14 01:15:10 2001 @@ -19,10 +19,9 @@ #include <asm/mach/arch.h> #include <asm/hardware/dec21285.h> -unsigned int vram_size; +extern void genarch_init_irq(void); -extern void setup_initrd(unsigned int start, unsigned int size); -extern void setup_ramdisk(int doload, int prompt, int start, unsigned int rd_sz); +unsigned int vram_size; #ifdef CONFIG_ARCH_ACORN @@ -79,6 +78,7 @@ DISABLE_PARPORT(1) FIXUP(fixup_acorn) MAPIO(rpc_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_ARCH_ARC @@ -86,6 +86,7 @@ MAINTAINER("Dave Gilbert") BOOT_PARAMS(0x0207c000) FIXUP(fixup_acorn) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_ARCH_A5K @@ -93,11 +94,13 @@ MAINTAINER("Russell King") BOOT_PARAMS(0x0207c000) FIXUP(fixup_acorn) + INITIRQ(genarch_init_irq) MACHINE_END #endif #endif #ifdef CONFIG_ARCH_L7200 +extern void __init l7200_map_io(void); static void __init fixup_l7200(struct machine_desc *desc, struct param_struct *params, @@ -109,34 +112,28 @@ mi->bank[0].node = 0; ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); - setup_ramdisk( 1, 0, 0, 8192 ); - setup_initrd( __phys_to_virt(0xf1000000), 0x00162b0d); -} + setup_ramdisk( 1, 0, 0, CONFIG_BLK_DEV_RAM_SIZE); + setup_initrd( __phys_to_virt(0xf1000000), 0x005dac7b); -extern void __init l7200_map_io(void); + /* Serial Console COM2 and LCD */ + strcpy( *cmdline, "console=tty0 console=ttyLU1,115200"); + + /* Serial Console COM1 and LCD */ + //strcpy( *cmdline, "console=tty0 console=ttyLU0,115200"); + + /* Console on LCD */ + //strcpy( *cmdline, "console=tty0"); +} -MACHINE_START(L7200, "LinkUp Systems L7200SDB") - MAINTAINER("Steve Hill") +MACHINE_START(L7200, "LinkUp Systems L7200") + MAINTAINER("Steve Hill / Scott McConnell") BOOT_MEM(0xf0000000, 0x80040000, 0xd0000000) FIXUP(fixup_l7200) MAPIO(l7200_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif -#ifdef CONFIG_ARCH_EBSA110 - -extern void __init ebsa110_map_io(void); - -MACHINE_START(EBSA110, "EBSA110") - MAINTAINER("Russell King") - BOOT_MEM(0x00000000, 0xe0000000, 0xe0000000) - BOOT_PARAMS(0x00000400) - DISABLE_PARPORT(0) - DISABLE_PARPORT(2) - SOFT_REBOOT - MAPIO(ebsa110_map_io) -MACHINE_END -#endif #ifdef CONFIG_ARCH_NEXUSPCI extern void __init nexuspci_map_io(void); @@ -145,6 +142,7 @@ MAINTAINER("Philip Blundell") BOOT_MEM(0x40000000, 0x10000000, 0xe0000000) MAPIO(nexuspci_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_ARCH_TBOX @@ -155,21 +153,25 @@ MAINTAINER("Philip Blundell") BOOT_MEM(0x80000000, 0x00400000, 0xe0000000) MAPIO(tbox_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_ARCH_CLPS7110 MACHINE_START(CLPS7110, "CL-PS7110") MAINTAINER("Werner Almesberger") + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_ARCH_ETOILE MACHINE_START(ETOILE, "Etoile") MAINTAINER("Alex de Vries") + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_ARCH_LACIE_NAS MACHINE_START(LACIE_NAS, "LaCie_NAS") MAINTAINER("Benjamin Herrenschmidt") + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_ARCH_CLPS7500 @@ -180,5 +182,6 @@ MAINTAINER("Philip Blundell") BOOT_MEM(0x10000000, 0x03000000, 0xe0000000) MAPIO(clps7500_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/armksyms.c linux.ac/arch/arm/kernel/armksyms.c --- linux.vanilla/arch/arm/kernel/armksyms.c Mon Sep 18 23:15:24 2000 +++ linux.ac/arch/arm/kernel/armksyms.c Sat Apr 14 01:15:10 2001 @@ -48,7 +48,6 @@ 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 @@ -77,15 +76,18 @@ extern void fpundefinstr(void); extern void fp_enter(void); -#define EXPORT_SYMBOL_ALIAS(sym,orig) \ - const char __kstrtab_##sym##[] __attribute__((section(".kstrtab"))) = \ - __MODULE_STRING(##sym##); \ - const struct module_symbol __ksymtab_##sym __attribute__((section("__ksymtab"))) = \ +#define EXPORT_SYMBOL_ALIAS(sym,orig) \ + const char __kstrtab_##sym##[] \ + __attribute__((section(".kstrtab"))) = \ + __MODULE_STRING(sym); \ + const struct module_symbol __ksymtab_##sym \ + __attribute__((section("__ksymtab"))) = \ { (unsigned long)&##orig, __kstrtab_##sym }; - /* - * floating point math emulator support. - * These symbols will never change their calling convention... - */ + +/* + * floating point math emulator support. + * These symbols will never change their calling convention... + */ EXPORT_SYMBOL_ALIAS(kern_fp_enter,fp_enter); EXPORT_SYMBOL_ALIAS(fp_printk,printk); EXPORT_SYMBOL_ALIAS(fp_send_sig,send_sig); @@ -95,7 +97,9 @@ EXPORT_SYMBOL(ret_from_exception); #endif +#ifdef CONFIG_VT EXPORT_SYMBOL(kd_mksound); +#endif /* platform dependent support */ EXPORT_SYMBOL(dump_thread); @@ -150,8 +154,6 @@ #ifndef CONFIG_NO_PGT_CACHE EXPORT_SYMBOL(quicklists); #endif -EXPORT_SYMBOL(__handle_bad_pmd); -EXPORT_SYMBOL(__handle_bad_pmd_kernel); /* string / mem functions */ EXPORT_SYMBOL_NOVERS(strcpy); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/arthur.c linux.ac/arch/arm/kernel/arthur.c --- linux.vanilla/arch/arm/kernel/arthur.c Mon Sep 18 23:15:24 2000 +++ linux.ac/arch/arm/kernel/arthur.c Sat Apr 14 01:15:10 2001 @@ -1,7 +1,9 @@ /* - * Arthur personality + * linux/arch/arm/kernel/arthur.c + * + * Copyright (C) 1998, 1999, 2000 Philip Blundell * - * Copyright (C) 1998, 1999, 2000 Philip Blundell + * Arthur personality */ /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/bios32.c linux.ac/arch/arm/kernel/bios32.c --- linux.vanilla/arch/arm/kernel/bios32.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/kernel/bios32.c Sat Apr 14 01:15:10 2001 @@ -307,7 +307,8 @@ * parity line correctly. */ if (dev->vendor == PCI_VENDOR_ID_INTERG && - dev->device == PCI_DEVICE_ID_INTERG_2000) + (dev->device == PCI_DEVICE_ID_INTERG_2000 || + dev->device == PCI_DEVICE_ID_INTERG_2010)) busdata->features &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY); @@ -394,6 +395,7 @@ extern struct hw_pci netwinder_pci; extern struct hw_pci personal_server_pci; extern struct hw_pci ftv_pci; +extern struct hw_pci shark_pci; extern struct hw_pci integrator_pci; void __init pcibios_init(void) @@ -409,6 +411,12 @@ break; } #endif +#ifdef CONFIG_ARCH_SHARK + if (machine_is_shark()) { + hw_pci = &shark_pci; + break; + } +#endif #ifdef CONFIG_ARCH_CATS if (machine_is_cats()) { hw_pci = &cats_pci; @@ -427,8 +435,8 @@ break; } #endif -#ifdef CONFIG_ARCH_NEXUSPCI - if (machine_is_nexuspci()) { +#ifdef CONFIG_ARCH_FTVPCI + if (machine_is_ftvpci()) { hw_pci = &ftv_pci; break; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/debug-armv.S linux.ac/arch/arm/kernel/debug-armv.S --- linux.vanilla/arch/arm/kernel/debug-armv.S Mon Sep 18 23:15:24 2000 +++ linux.ac/arch/arm/kernel/debug-armv.S Sat Apr 14 01:16:23 2001 @@ -12,7 +12,6 @@ #include <linux/config.h> #include <linux/linkage.h> #include <asm/hardware.h> -#include <asm/hardware/dec21285.h> .text @@ -67,8 +66,31 @@ tst \rd, #0x10 beq 1001b .endm + +#elif defined(CONFIG_ARCH_SHARK) + .macro addruart,rx + mov \rx, #0xe0000000 + orr \rx, \rx, #0x000003f8 + .endm + + .macro senduart,rd,rx + strb \rd, [\rx] + .endm + + .macro busyuart,rd,rx + mov \rd, #0 +1001: add \rd, \rd, #1 + teq \rd, #0x10000 + bne 1001b + .endm + + .macro waituart,rd,rx + .endm #elif defined(CONFIG_FOOTBRIDGE) + +#include <asm/hardware/dec21285.h> + #ifndef CONFIG_DEBUG_DC21285_PORT /* For NetWinder debugging */ .macro addruart,rx @@ -120,9 +142,12 @@ .macro waituart,rd,rx .endm #endif -#elif defined(CONFIG_ARCH_NEXUSPCI) +#elif defined(CONFIG_ARCH_FTVPCI) .macro addruart,rx - ldr \rx, =0xfff00000 + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + movne \rx, #0xe0000000 + moveq \rx, #0x10000000 .endm .macro senduart,rd,rx @@ -131,8 +156,8 @@ .macro busyuart,rd,rx 1001: ldr \rd, [\rx, #0x4] - tst \rd, #1 << 0 - bne 1001b + tst \rd, #1 << 2 + beq 1001b .endm .macro waituart,rd,rx @@ -164,6 +189,26 @@ bne 1001b .endm +#elif defined(CONFIG_ARCH_CLPS7500) + .macro addruart,rx + mov \rx, #0xe0000000 + orr \rx, \rx, #0x00010000 + orr \rx, \rx, #0x00000be0 + .endm + + .macro senduart,rd,rx + strb \rd, [\rx] + .endm + + .macro busyuart,rd,rx + .endm + + .macro waituart,rd,rx +1001: ldrb \rd, [\rx, #0x14] + tst \rd, #0x20 + beq 1001b + .endm + #elif defined(CONFIG_ARCH_L7200) .equ io_virt, IO_BASE @@ -174,12 +219,12 @@ tst \rx, #1 @ MMU enabled? moveq \rx, #io_phys @ physical base address movne \rx, #io_virt @ virtual address - add \rx, \rx, #0x00044000 @ Ser1 -@ add \rx, \rx, #0x00045000 @ Ser2 + add \rx, \rx, #0x00044000 @ UART1 +@ add \rx, \rx, #0x00045000 @ UART2 .endm .macro senduart,rd,rx - str \rd, [\rx, #0x0] @ UARTDR1 + str \rd, [\rx, #0x0] @ UARTDR .endm .macro waituart,rd,rx @@ -198,9 +243,6 @@ #include <asm/hardware/serial_amba.h> - .equ io_virt, 0xf0000000 + (0x16000000 >> 4) - .equ io_phys, 0x16000000 - .macro addruart,rx mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? @@ -223,6 +265,41 @@ 1001: ldr \rd, [\rx, #0x18] @ UARTFLG tst \rd, #1 << 3 @ UARTFLGUBUSY - 1 when busy bne 1001b + .endm + +#elif defined(CONFIG_ARCH_CLPS711X) + +#include <asm/hardware/clps7111.h> + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #CLPS7111_PHYS_BASE + movne \rx, #CLPS7111_VIRT_BASE +#ifndef CONFIG_DEBUG_CLPS711X_UART2 + add \rx, \rx, #0x0000 @ UART1 +#else + add \rx, \rx, #0x1000 @ UART2 +#endif + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #0x0480] @ UARTDR + .endm + + .macro waituart,rd,rx +1001: ldr \rd, [\rx, #0x0140] @ SYSFLGx + tst \rd, #1 << 11 @ UBUSYx + bne 1001b + .endm + + .macro busyuart,rd,rx + tst \rx, #0x1000 @ UART2 does not have CTS here + bne 1002f +1001: ldr \rd, [\rx, #0x0140] @ SYSFLGx + tst \rd, #1 << 8 @ CTS + bne 1001b +1002: .endm #else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/ecard.c linux.ac/arch/arm/kernel/ecard.c --- linux.vanilla/arch/arm/kernel/ecard.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/arm/kernel/ecard.c Sat Apr 14 01:16:23 2001 @@ -37,6 +37,7 @@ #include <linux/mm.h> #include <linux/slab.h> #include <linux/proc_fs.h> +#include <linux/notifier.h> #include <linux/init.h> #include <asm/dma.h> @@ -46,6 +47,7 @@ #include <asm/irq.h> #include <asm/pgalloc.h> #include <asm/mmu_context.h> +#include <asm/mach/irq.h> #ifndef CONFIG_ARCH_RPC #define HAVE_EXPMASK @@ -53,7 +55,7 @@ enum req { req_readbytes, - req_reset + req_reset_all }; struct ecard_request { @@ -134,19 +136,14 @@ #define POD_INT_ADDR(x) ((volatile unsigned char *)\ ((BUS_ADDR((x)) - IO_BASE) + IO_START)) -static void -ecard_task_reset(struct ecard_request *req) +static inline void ecard_task_reset(void) { - if (req->ec == NULL) { - ecard_t *ec; + 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); + for (ec = cards; ec; ec = ec->next) + if (ec->loader) + ecard_loader_reset(POD_INT_ADDR(ec->podaddr), + ec->loader); } static void @@ -156,48 +153,47 @@ volatile unsigned char *base_addr = (volatile unsigned char *)POD_INT_ADDR(req->ec->podaddr); unsigned int len = req->length; + unsigned int off = req->address; 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 + * 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; + unsigned int page; - if (page > 256) + page = (off >> 12) * 4; + if (page > 256 * 4) return; - page *= 4; + off &= 4095; - if (offset == 0 || index > offset) { - /* - * We need to reset the index counter. - */ + /* + * If we are reading offset 0, or our current index is + * greater than the offset, reset the hardware index counter. + */ + if (off == 0 || index > off) { *base_addr = 0; index = 0; } - while (index <= offset) { + /* + * Increment the hardware index counter until we get to the + * required offset. The read bytes are discarded. + */ + while (index < off) { + unsigned char byte; byte = base_addr[page]; index += 1; } while (len--) { - *buf++ = byte; - if (len) { - byte = base_addr[page]; - index += 1; - } + *buf++ = base_addr[page]; + index += 1; } } else { - unsigned int off = req->address; if (!req->use_loader || !req->ec->loader) { off *= 4; @@ -220,50 +216,30 @@ } +static void ecard_do_request(struct ecard_request *req) +{ + switch (req->req) { + case req_readbytes: + ecard_task_readbytes(req); + break; + + case req_reset_all: + ecard_task_reset(); + break; + } +} + #ifdef CONFIG_CPU_32 static pid_t ecard_pid; static wait_queue_head_t ecard_wait; -static wait_queue_head_t ecard_done; static struct ecard_request *ecard_req; -/* to be removed when exec_mmap becomes extern */ -static int exec_mmap(void) -{ - struct mm_struct * mm, * old_mm; - - old_mm = current->mm; - if (old_mm && atomic_read(&old_mm->mm_users) == 1) { - flush_cache_mm(old_mm); - mm_release(); - exit_mmap(old_mm); - flush_tlb_mm(old_mm); - return 0; - } - - mm = mm_alloc(); - if (mm) { - struct mm_struct *active_mm = current->active_mm; - - current->mm = mm; - current->active_mm = mm; - activate_mm(active_mm, mm); - mm_release(); - if (old_mm) { - if (active_mm != old_mm) BUG(); - mmput(old_mm); - return 0; - } - mmdrop(active_mm); - return 0; - } - return -ENOMEM; -} +static DECLARE_MUTEX_LOCKED(ecard_done_sem); /* - * Set up the expansion card - * daemon's environment. + * Set up the expansion card daemon's page tables. */ -static void ecard_init_task(int force) +static void ecard_init_pgtables(struct mm_struct *mm) { /* We want to set up the page tables for the following mapping: * Virtual Physical @@ -279,29 +255,41 @@ pgd_t *src_pgd, *dst_pgd; unsigned int dst_addr = IO_START; - if (!force) - exec_mmap(); - - src_pgd = pgd_offset(current->mm, IO_BASE); - dst_pgd = pgd_offset(current->mm, dst_addr); + src_pgd = pgd_offset(mm, IO_BASE); + dst_pgd = pgd_offset(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); + src_pgd = pgd_offset(mm, EASI_BASE); + dst_pgd = pgd_offset(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); + flush_tlb_range(mm, IO_START, IO_START + IO_SIZE); + flush_tlb_range(mm, EASI_START, EASI_START + EASI_SIZE); +} + +static int ecard_init_mm(void) +{ + struct mm_struct * mm = mm_alloc(); + struct mm_struct *active_mm = current->active_mm; + + if (!mm) + return -ENOMEM; + + current->mm = mm; + current->active_mm = mm; + activate_mm(active_mm, mm); + mmdrop(active_mm); + ecard_init_pgtables(mm); + return 0; } static int @@ -309,22 +297,23 @@ { struct task_struct *tsk = current; - tsk->session = 1; - tsk->pgrp = 1; - /* * We don't want /any/ signals, not even SIGKILL */ sigfillset(&tsk->blocked); sigemptyset(&tsk->pending.signal); recalc_sigpending(tsk); - strcpy(tsk->comm, "kecardd"); + daemonize(); /* - * Set up the environment + * Allocate a mm. We're not a lazy-TLB kernel task since we need + * to set page table entries where the user space would be. Note + * that this also creates the page tables. Failure is not an + * option here. */ - ecard_init_task(0); + if (ecard_init_mm()) + panic("kecardd: unable to alloc mm\n"); while (1) { struct ecard_request *req; @@ -338,16 +327,8 @@ } } 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); + ecard_do_request(req); + up(&ecard_done_sem); } } @@ -357,76 +338,90 @@ * FIXME: The test here is not sufficient to detect if the * kcardd is running. */ -static inline void +static 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. + * Make sure we have a context that is able to sleep. */ - if ((current == &init_task || in_interrupt()) && - req->req == req_reset && req->ec == NULL) { - ecard_init_task(1); - ecard_task_reset(req); - } else { - if (ecard_pid <= 0) - ecard_pid = kernel_thread(ecard_task, NULL, - CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + if (current == &init_task || in_interrupt()) + BUG(); - ecard_req = req; + if (ecard_pid <= 0) + ecard_pid = kernel_thread(ecard_task, NULL, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND); - wake_up(&ecard_wait); + ecard_req = req; + wake_up(&ecard_wait); - sleep_on(&ecard_done); - } + /* + * Now wait for kecardd to run. + */ + down(&ecard_done_sem); } #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); -} +#define ecard_call(req) ecard_do_request(req) #endif /* ======================= Mid-level card control ===================== */ + /* - * This is called to reset the loaders for each expansion card on reboot. + * This function is responsible for resetting the expansion cards to a + * sensible state immediately prior to rebooting the system. This function + * has process state (keventd), so we can sleep. + * + * Possible "val" values here: + * SYS_RESTART - restarting system + * SYS_HALT - halting system + * SYS_POWER_OFF - powering down system * - * This is required to make sure that the card is in the correct state - * that RiscOS expects it to be. + * We ignore all calls, unless it is a SYS_RESTART call - power down/halts + * will be followed by a SYS_RESTART if ctrl-alt-del is pressed again. */ -void -ecard_reset(int slot) +static void ecard_reboot(struct notifier_block *me, unsigned long val, void *v) { struct ecard_request req; - req.req = req_reset; + if (val != SYS_RESTART) + return; - if (slot < 0) - req.ec = NULL; - else - req.ec = slot_to_ecard(slot); + /* + * Disable the expansion card interrupt + */ + disable_irq(IRQ_EXPANSIONCARD); + /* + * If we have any expansion card loader code which will handle + * the reset for us, call it now. + */ + req.req = req_reset_all; ecard_call(&req); + /* + * Disable the expansion card interrupt again, just to be sure. + */ + disable_irq(IRQ_EXPANSIONCARD); + + /* + * Finally, reset the expansion card interrupt mask to + * all enable (RISC OS doesn't set this) + */ #ifdef HAS_EXPMASK - if (have_expmask && slot < 0) { - have_expmask |= ~0; - EXPMASK_ENABLE = have_expmask; - } + have_expmask = ~0; + __raw_writeb(have_expmask, EXPMASK_ENABLE); #endif } +static struct notifier_block ecard_reboot_notifier = { + notifier_call: ecard_reboot, +}; + + + static void ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld) { @@ -506,7 +501,7 @@ #ifdef HAS_EXPMASK if (irqnr < 4 && have_expmask) { have_expmask |= 1 << irqnr; - EXPMASK_ENABLE = have_expmask; + __raw_writeb(have_expmask, EXPMASK_ENABLE); } #endif } @@ -516,7 +511,7 @@ #ifdef HAS_EXPMASK if (irqnr < 4 && have_expmask) { have_expmask &= ~(1 << irqnr); - EXPMASK_ENABLE = have_expmask; + __raw_writeb(have_expmask, EXPMASK_ENABLE); } #endif } @@ -556,7 +551,7 @@ * * They are not meant to be called directly, but via enable/disable_irq. */ -void ecard_enableirq(unsigned int irqnr) +static void ecard_enableirq(unsigned int irqnr) { ecard_t *ec = slot_to_ecard(irqnr - 32); @@ -572,7 +567,7 @@ } } -void ecard_disableirq(unsigned int irqnr) +static void ecard_disableirq(unsigned int irqnr) { ecard_t *ec = slot_to_ecard(irqnr - 32); @@ -717,7 +712,7 @@ const unsigned int statusmask = 15; unsigned int status; - status = EXPMASK_STATUS & statusmask; + status = __raw_readb(EXPMASK_STATUS) & statusmask; if (status) { unsigned int slot; ecard_t *ec; @@ -739,18 +734,21 @@ * otherwise you will lose serial data at high speeds! */ oldexpmask = have_expmask; - EXPMASK_ENABLE = (have_expmask &= priority_masks[slot]); + have_expmask &= priority_masks[slot]; + __raw_writeb(have_expmask, EXPMASK_ENABLE); sti(); do_ecard_IRQ(ec->irq, regs); cli(); - EXPMASK_ENABLE = have_expmask = oldexpmask; - status = EXPMASK_STATUS & statusmask; + have_expmask = oldexpmask; + __raw_writeb(have_expmask, EXPMASK_ENABLE); + status = __raw_readb(EXPMASK_STATUS) & statusmask; if (status) goto again; } else { printk(KERN_WARNING "card%d: interrupt from unclaimed " "card???\n", slot); - EXPMASK_ENABLE = (have_expmask &= ~(1 << slot)); + have_expmask &= ~(1 << slot); + __raw_writeb(have_expmask, EXPMASK_ENABLE); } } else printk(KERN_WARNING "Wild interrupt from backplane (masks)\n"); @@ -762,10 +760,10 @@ ecard_t *ec; int found; - EXPMASK_ENABLE = 0x00; - EXPMASK_STATUS = 0xff; - found = ((EXPMASK_STATUS & 15) == 0); - EXPMASK_ENABLE = 0xff; + __raw_writeb(0x00, EXPMASK_ENABLE); + __raw_writeb(0xff, EXPMASK_STATUS); + found = (__raw_readb(EXPMASK_STATUS) & 15) == 0; + __raw_writeb(0xff, EXPMASK_ENABLE); if (!found) return; @@ -781,7 +779,7 @@ for (ec = cards; ec; ec = ec->next) have_expmask |= 1 << ec->slot_no; - EXPMASK_ENABLE = have_expmask; + __raw_writeb(have_expmask, EXPMASK_ENABLE); } #else #define ecard_probeirqhw() @@ -830,7 +828,7 @@ } #ifdef IOMD_ECTCR - outb(ectcr, IOMD_ECTCR); + iomd_writeb(ectcr, IOMD_ECTCR); #endif return address; } @@ -910,9 +908,8 @@ int i, rc = -ENOMEM; ec = kmalloc(sizeof(ecard_t), GFP_KERNEL); - if (!ec) - goto nodev; + goto nomem; memset(ec, 0, sizeof(ecard_t)); @@ -969,27 +966,31 @@ if (slot == 8) ec->irq = 11; #endif + /* + * hook the interrupt handlers + */ + if (ec->irq != 0 && ec->irq >= 32) { + irq_desc[ec->irq].mask_ack = ecard_disableirq; + irq_desc[ec->irq].mask = ecard_disableirq; + irq_desc[ec->irq].unmask = ecard_enableirq; + irq_desc[ec->irq].valid = 1; + } + #ifdef CONFIG_ARCH_RPC /* On RiscPC, only first two slots have DMA capability */ if (slot < 2) ec->dma = 2 + slot; #endif -#if 0 /* We don't support FIQs on expansion cards at the moment */ - ec->fiq = 96 + slot; -#endif - - rc = 0; for (ecp = &cards; *ecp; ecp = &(*ecp)->next); *ecp = ec; + slot_to_expcard[slot] = ec; + return 0; nodev: - if (rc && ec) - kfree(ec); - else - slot_to_expcard[slot] = ec; - + kfree(ec); +nomem: return rc; } @@ -1058,9 +1059,13 @@ { int slot; + /* + * Register our reboot notifier + */ + register_reboot_notifier(&ecard_reboot_notifier); + #ifdef CONFIG_CPU_32 init_waitqueue_head(&ecard_wait); - init_waitqueue_head(&ecard_done); #endif printk("Probing expansion cards\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/entry-armv.S linux.ac/arch/arm/kernel/entry-armv.S --- linux.vanilla/arch/arm/kernel/entry-armv.S Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/arm/kernel/entry-armv.S Sat Apr 14 01:16:23 2001 @@ -89,41 +89,52 @@ .if ioc_base_low orr r4, r4, #ioc_base_low .endif - ldrb \irqstat, [r4, #0x24] @ get high priority first - adr \base, irq_prio_h + ldrb \irqstat, [r4, #IOMD_IRQREQB] @ get high priority first + ldr \base, =irq_prio_h teq \irqstat, #0 #ifdef IOMD_BASE - ldreqb \irqstat, [r4, #0x1f4] @ get dma - adreq \base, irq_prio_d + ldreqb \irqstat, [r4, #IOMD_DMAREQ] @ get dma + addeq \base, \base, #256 @ irq_prio_h table size teqeq \irqstat, #0 + bne 2406f #endif - ldreqb \irqstat, [r4, #0x14] @ get low priority - adreq \base, irq_prio_l - - teq \irqstat, #0 - ldrneb \irqnr, [\base, \irqstat] @ get IRQ number + ldreqb \irqstat, [r4, #IOMD_IRQREQA] @ get low priority + addeq \base, \base, #256 @ irq_prio_d table size + teqeq \irqstat, #0 +#ifdef IOMD_IRQREQC + ldreqb \irqstat, [r4, #IOMD_IRQREQC] + addeq \base, \base, #256 @ irq_prio_l table size + teqeq \irqstat, #0 +#endif +#ifdef IOMD_IRQREQD + ldreqb \irqstat, [r4, #IOMD_IRQREQD] + addeq \base, \base, #256 @ irq_prio_lc table size + teqeq \irqstat, #0 +#endif +2406: ldrneb \irqnr, [\base, \irqstat] @ get IRQ number .endm /* - * Interrupt table (incorporates priority) + * Interrupt table (incorporates priority). Please note that we + * rely on the order of these tables (see above code). */ .macro irq_prio_table -irq_prio_l: .byte 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 - .byte 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 - .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 - .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 - .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3 - .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3 - .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 - .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +irq_prio_h: .byte 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 #ifdef IOMD_BASE irq_prio_d: .byte 0,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 .byte 20,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 @@ -142,26 +153,64 @@ .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 #endif -irq_prio_h: .byte 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 +irq_prio_l: .byte 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 + .byte 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 + .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3 + .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3 + .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +#ifdef IOMD_IRQREQC +irq_prio_lc: .byte 24,24,25,24,26,26,26,26,27,27,27,27,27,27,27,27 + .byte 28,24,25,24,26,26,26,26,27,27,27,27,27,27,27,27 + .byte 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 + .byte 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 + .byte 30,30,30,30,30,30,30,30,27,27,27,27,27,27,27,27 + .byte 30,30,30,30,30,30,30,30,27,27,27,27,27,27,27,27 + .byte 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 + .byte 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 + .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 + .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 + .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 + .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 + .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 + .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 + .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 + .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 +#endif +#ifdef IOMD_IRQREQD +irq_prio_ld: .byte 40,40,41,40,42,42,42,42,43,43,43,43,43,43,43,43 + .byte 44,40,41,40,42,42,42,42,43,43,43,43,43,43,43,43 + .byte 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45 + .byte 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45 + .byte 46,46,46,46,46,46,46,46,43,43,43,43,43,43,43,43 + .byte 46,46,46,46,46,46,46,46,43,43,43,43,43,43,43,43 + .byte 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45 + .byte 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45 + .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 + .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 + .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 + .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 + .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 + .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 + .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 + .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 +#endif .endm #elif defined(CONFIG_ARCH_EBSA110) +#define IRQ_STAT 0xff000000 /* read */ + .macro disable_fiq .endm @@ -457,7 +506,9 @@ .macro irq_prio_table .endm -#elif defined(CONFIG_ARCH_P720T) +#elif defined(CONFIG_ARCH_CLPS711X) + +#include <asm/hardware/clps7111.h> .macro disable_fiq .endm diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/entry-common.S linux.ac/arch/arm/kernel/entry-common.S --- linux.vanilla/arch/arm/kernel/entry-common.S Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/arm/kernel/entry-common.S Sat Apr 14 01:16:23 2001 @@ -35,9 +35,7 @@ .align 5 fast_syscall_return: - str r0, [sp, #S_R0 + S_OFF] @ returned r0 -slow_syscall_return: - add sp, sp, #S_OFF + str r0, [sp, #S_R0+S_OFF]! @ returned r0 ret_from_sys_call: @ external entry get_softirq r0 get_current_task r5 @@ -52,6 +50,7 @@ bne ret_reschedule teq r1, #0 @ check for signals blne ret_signal + ret_from_all: restore_user_regs @ internal ret_signal: mov r1, sp @ internal @@ -132,7 +131,8 @@ str ip, [sp, #S_IP + S_OFF] @ trace exit [IP = 1] bl SYMBOL_NAME(syscall_trace) str tip, [sp, #S_IP + S_OFF] - b slow_syscall_return + add sp, sp, #S_OFF + b ret_from_sys_call 2: add r1, sp, #S_OFF tst scno, #0x00f00000 @ is it a Unix SWI? @@ -142,8 +142,9 @@ b SYMBOL_NAME(sys_ni_syscall) @ not private func 3: eor r0, scno, #OS_NUMBER <<20 @ Put OS number back - adrsvc al, lr, slow_syscall_return - b SYMBOL_NAME(deferred) + bl SYMBOL_NAME(deferred) + add sp, sp, #S_OFF + b ret_from_sys_call .align 5 .type __irq_stat, #object diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/fiq.c linux.ac/arch/arm/kernel/fiq.c --- linux.vanilla/arch/arm/kernel/fiq.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/kernel/fiq.c Sat Apr 14 01:16:23 2001 @@ -124,7 +124,7 @@ #ifdef CONFIG_CPU_26 "mov %0, pc bic %1, %0, #0x3 - orr %1, %1, #0x0c000001 + orr %1, %1, %3 teqp %1, #0 @ select FIQ mode mov r0, r0 ldmia %2, {r8 - r14} @@ -133,7 +133,7 @@ #endif #ifdef CONFIG_CPU_32 "mrs %0, cpsr - mov %1, #0xc1 + mov %1, %3 msr cpsr_c, %1 @ select FIQ mode mov r0, r0 ldmia %2, {r8 - r14} @@ -141,7 +141,7 @@ mov r0, r0" #endif : "=&r" (tmp), "=&r" (tmp2) - : "r" (®s->ARM_r8) + : "r" (®s->ARM_r8), "I" (I_BIT | F_BIT | FIQ_MODE) /* 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 @@ -156,7 +156,7 @@ #ifdef CONFIG_CPU_26 "mov %0, pc bic %1, %0, #0x3 - orr %1, %1, #0x0c000001 + orr %1, %1, %3 teqp %1, #0 @ select FIQ mode mov r0, r0 stmia %2, {r8 - r14} @@ -165,7 +165,7 @@ #endif #ifdef CONFIG_CPU_32 "mrs %0, cpsr - mov %1, #0xc1 + mov %1, %3 msr cpsr_c, %1 @ select FIQ mode mov r0, r0 stmia %2, {r8 - r14} @@ -173,7 +173,7 @@ mov r0, r0" #endif : "=&r" (tmp), "=&r" (tmp2) - : "r" (®s->ARM_r8) + : "r" (®s->ARM_r8), "I" (I_BIT | F_BIT | FIQ_MODE) /* 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 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/head-armo.S linux.ac/arch/arm/kernel/head-armo.S --- linux.vanilla/arch/arm/kernel/head-armo.S Tue Nov 28 01:07:59 2000 +++ linux.ac/arch/arm/kernel/head-armo.S Sat Apr 14 01:16:23 2001 @@ -82,9 +82,9 @@ mov r1, #0 str r0, [r1, #4] ldr r0, arm2_id - swp r2, r2, [r1] @ check for swp (ARM2 can't) + swp r2, r2, [r1] @ check for swp (ARM2 cant) ldr r0, arm250_id - mrc 15, 0, r3, c0, c0 @ check for CP#15 (ARM250 can't) + mrc 15, 0, r3, c0, c0 @ check for CP#15 (ARM250 cant) mov r0, r3 continue: mov r2, #0xeb000000 @ Make undef vector loop sub r2, r2, #2 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/head-armv.S linux.ac/arch/arm/kernel/head-armv.S --- linux.vanilla/arch/arm/kernel/head-armv.S Tue Nov 28 01:07:59 2000 +++ linux.ac/arch/arm/kernel/head-armv.S Sat Apr 14 01:16:23 2001 @@ -26,7 +26,9 @@ * * Note that swapper_pg_dir is the virtual address of the page tables, and * pgtbl gives us a position-independent reference to these tables. We can - * do this because stext == TEXT_ADDR + * do this because stext == TEXTADDR + * + * swapper_pg_dir, pgtbl and krnladr are all closely related. */ #if (TEXTADDR & 0xffff) != 0x8000 #error TEXTADDR must start at 0xXXXX8000 @@ -35,24 +37,36 @@ .globl SYMBOL_NAME(swapper_pg_dir) .equ SYMBOL_NAME(swapper_pg_dir), TEXTADDR - 0x4000 - .macro pgtbl, reg + .macro pgtbl, reg, rambase adr \reg, stext sub \reg, \reg, #0x4000 .endm +/* + * Since the page table is closely related to the kernel start address, we + * can convert the page table base address to the base address of the section + * containing both. + */ + .macro krnladr, rd, pgtable, rambase + bic \rd, \pgtable, #0x000ff000 + .endm + +/* + * Kernel startup entry point. + * + * The rules are: + * r0 - should be 0 + * r1 - unique architecture number + * MMU - off + * I-cache - on or off + * D-cache - off + * + * See linux/arch/arm/tools/mach-types for the complete list of numbers + * for r1. + */ .section ".text.init",#alloc,#execinstr .type stext, #function ENTRY(stext) -/* - * Entry point. The general rules are: - * should be called with r0 == 0 - * r1 contains the unique architecture number - * with MMU is off, I-cache may be on or off, D-cache should be off. - * See linux/arch/arm/kernel/arch.c and linux/include/asm-arm/system.h - * for the complete list of numbers for r1. If you require a new number, - * please follow the instructions given towards the end of - * linux/Documentation/arm/README. - */ mov r12, r0 /* * NOTE! Any code which is placed here should be done for one of @@ -115,7 +129,7 @@ #endif mov r0, #F_BIT | I_BIT | MODE_SVC @ make sure svc mode - msr cpsr_c, r0 @ and all irqs diabled + msr cpsr_c, r0 @ and all irqs disabled bl __lookup_processor_type teq r10, #0 @ invalid processor? moveq r0, #'p' @ yes, error 'p' @@ -129,6 +143,7 @@ add pc, r10, #12 @ initialise processor @ (return control reg) + .type __switch_data, %object __switch_data: .long __mmap_switched .long SYMBOL_NAME(compat) .long SYMBOL_NAME(__bss_start) @@ -138,6 +153,7 @@ .long SYMBOL_NAME(cr_alignment) .long SYMBOL_NAME(init_task_union)+8192 + .type __ret, %function __ret: ldr lr, __switch_data mcr p15, 0, r0, c1, c0 mov r0, r0 @@ -190,31 +206,37 @@ * r8 = page table flags */ __create_page_tables: - pgtbl r4 + pgtbl r4, r5 @ page table address + + /* + * Clear the 16K level 1 swapper page table + */ mov r0, r4 mov r3, #0 - add r2, r0, #0x4000 @ 16k of page table -1: str r3, [r0], #4 @ Clear page table + add r2, r0, #0x4000 +1: str r3, [r0], #4 str r3, [r0], #4 str r3, [r0], #4 str r3, [r0], #4 teq r0, r2 bne 1b + /* - * Create identity mapping for first MB of kernel. - * This is marked cacheable and bufferable. - * - * The identity mapping will be removed by paging_init() + * Create identity mapping for first MB of kernel to + * cater for the MMU enable. This identity mapping + * will be removed by paging_init() */ - add r3, r8, r5 @ mmuflags + start of RAM - add r0, r4, r5, lsr #18 - str r3, [r0] @ identity mapping + krnladr r2, r4, r5 @ start of kernel + add r3, r8, r2 @ flags + kernel base + str r3, [r4, r2, lsr #18] @ identity mapping + /* * Now setup the pagetables for our kernel direct * mapped region. We round TEXTADDR down to the * nearest megabyte boundary. */ - add r0, r4, #(TEXTADDR & 0xfff00000) >> 18 @ start of kernel + add r0, r4, #(TEXTADDR & 0xff000000) >> 18 @ start of kernel + add r0, r0, #(TEXTADDR & 0x00f00000) >> 18 str r3, [r0], #4 @ PAGE_OFFSET + 0MB add r3, r3, #1 << 20 str r3, [r0], #4 @ PAGE_OFFSET + 1MB @@ -223,13 +245,25 @@ add r3, r3, #1 << 20 str r3, [r0], #4 @ PAGE_OFFSET + 3MB + /* + * Ensure that the first section of RAM is present. + * we assume that: + * 1. the RAM is aligned to a 256MB boundary + * 2. the kernel is executing in the same 256MB chunk + * as the start of RAM. + */ + bic r0, r0, #0x0ff00000 >> 18 @ round down + and r2, r5, #0xf0000000 @ round down + add r3, r8, r2 @ flags + rambase + str r3, [r0] + bic r8, r8, #0x0c @ turn off cacheable @ and bufferable bits #ifdef CONFIG_DEBUG_LL /* * Map in IO space for serial debugging. * This allows debug messages to be output - * via a serial before paging_init. + * via a serial console before paging_init. */ add r0, r4, r7 rsb r3, r7, #0x4000 @ PTRS_PER_PGD*sizeof(long) @@ -241,12 +275,13 @@ add r3, r3, #1 << 20 teq r0, r2 bne 1b -#ifdef CONFIG_ARCH_NETWINDER +#if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS) /* * If we're using the NetWinder, we need to map in * the 16550-type serial port for the debug messages */ - teq r1, #5 + teq r1, #MACH_TYPE_NETWINDER + teqne r1, #MACH_TYPE_CATS bne 1f add r0, r4, #0x3fc0 mov r3, #0x7c000000 @@ -263,13 +298,12 @@ * Similar reasons here - for debug. This is * only for Acorn RiscPC architectures. */ - teq r5, #0 - addne r0, r4, #0x80 @ 02000000 - movne r3, #0x02000000 - orrne r3, r3, r8 - strne r3, [r0] - addne r0, r4, #0x3600 @ d8000000 - strne r3, [r0] + add r0, r4, #0x80 @ 02000000 + mov r3, #0x02000000 + orr r3, r3, r8 + str r3, [r0] + add r0, r4, #0x3600 @ d8000000 + str r3, [r0] #endif mov pc, lr diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/io.c linux.ac/arch/arm/kernel/io.c --- linux.vanilla/arch/arm/kernel/io.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/kernel/io.c Sat Apr 14 01:16:23 2001 @@ -0,0 +1,49 @@ +#include <linux/module.h> +#include <linux/types.h> + +#include <asm/io.h> + +/* + * Copy data from IO memory space to "real" memory space. + * This needs to be optimized. + */ +void _memcpy_fromio(void * to, unsigned long from, size_t count) +{ + while (count) { + count--; + *(char *) to = readb(from); + ((char *) to)++; + from++; + } +} + +/* + * Copy data from "real" memory space to IO memory space. + * This needs to be optimized. + */ +void _memcpy_toio(unsigned long to, const void * from, size_t count) +{ + while (count) { + count--; + writeb(*(char *) from, to); + ((char *) from)++; + to++; + } +} + +/* + * "memset" on IO memory space. + * This needs to be optimized. + */ +void _memset_io(unsigned long dst, int c, size_t count) +{ + while (count) { + count--; + writeb(c, dst); + dst++; + } +} + +EXPORT_SYMBOL(_memcpy_fromio); +EXPORT_SYMBOL(_memcpy_toio); +EXPORT_SYMBOL(_memset_io); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/irq-arch.c linux.ac/arch/arm/kernel/irq-arch.c --- linux.vanilla/arch/arm/kernel/irq-arch.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/kernel/irq-arch.c Sat Apr 14 01:16:23 2001 @@ -0,0 +1,41 @@ +/* + * linux/arch/arm/kernel/irq-arch.c + * + * 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. + * + * We contain the architecture-specific parts of interrupt handling + * in this file. In 2.5, it will move into the various arch/arm/mach-* + * directories. + */ +#include <linux/ptrace.h> +#include <linux/kernel_stat.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/malloc.h> +#include <linux/random.h> +#include <linux/smp.h> +#include <linux/init.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/system.h> + +#include <asm/mach/irq.h> + +/* + * Get architecture specific interrupt handlers + * and interrupt initialisation. + */ +#include <asm/arch/irq.h> + +void __init genarch_init_irq(void) +{ + irq_init_irq(); +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/irq.c linux.ac/arch/arm/kernel/irq.c --- linux.vanilla/arch/arm/kernel/irq.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/arm/kernel/irq.c Sat Apr 14 01:16:23 2001 @@ -2,7 +2,7 @@ * linux/arch/arm/kernel/irq.c * * Copyright (C) 1992 Linus Torvalds - * Modifications for ARM processor Copyright (C) 1995-1998 Russell King. + * Modifications for ARM processor 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 @@ -29,9 +29,11 @@ #include <linux/smp.h> #include <linux/init.h> -#include <asm/hardware.h> -#include <asm/io.h> +#include <asm/irq.h> #include <asm/system.h> +#include <asm/mach/irq.h> + +#include <asm/arch/irq.h> /* pick up fixup_irq definition */ /* * Maximum IRQ count. Currently, this is arbitary. However, it should @@ -42,41 +44,11 @@ */ #define MAX_IRQ_CNT 100000 -spinlock_t irq_controller_lock; - -int setup_arm_irq(int, struct irqaction *); -extern int get_fiq_list(char *); -extern void init_FIQ(void); - -struct irqdesc { - unsigned int nomask : 1; /* IRQ does not mask in IRQ */ - unsigned int enabled : 1; /* IRQ is currently enabled */ - unsigned int triggered: 1; /* IRQ has occurred */ - 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 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; - /* - * IRQ lock detection - */ - unsigned int lck_cnt; - unsigned int lck_pc; - unsigned int lck_jif; -}; - -static struct irqdesc irq_desc[NR_IRQS]; static volatile unsigned long irq_err_count; +static spinlock_t irq_controller_lock; -/* - * Get architecture specific interrupt handlers - * and interrupt initialisation. - */ -#include <asm/arch/irq.h> +struct irqdesc irq_desc[NR_IRQS]; +void (*init_arch_irq)(void) __initdata = NULL; /* * Dummy mask/unmask handler @@ -85,6 +57,14 @@ { } +/** + * disable_irq - disable an irq and wait for completion + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. + * + * This function may be called - with care - from IRQ context. + */ void disable_irq(unsigned int irq) { unsigned long flags; @@ -95,6 +75,14 @@ spin_unlock_irqrestore(&irq_controller_lock, flags); } +/** + * enable_irq - enable interrupt handling on an irq + * @irq: Interrupt to enable + * + * Re-enables the processing of interrupts on this IRQ line + * + * This function may be called from IRQ context. + */ void enable_irq(unsigned int irq) { unsigned long flags; @@ -271,6 +259,7 @@ int shared = 0; struct irqaction *old, **p; unsigned long flags; + struct irqdesc *desc; /* * Some drivers like serial.c use request_irq() heavily, @@ -292,8 +281,9 @@ /* * The following block of code has to be executed atomically */ + desc = irq_desc + irq; spin_lock_irqsave(&irq_controller_lock, flags); - p = &irq_desc[irq].action; + p = &desc->action; if ((old = *p) != NULL) { /* Can't share interrupts unless both agree to */ if (!(old->flags & new->flags & SA_SHIRQ)) { @@ -312,11 +302,11 @@ *p = new; if (!shared) { - irq_desc[irq].nomask = (new->flags & SA_IRQNOMASK) ? 1 : 0; - irq_desc[irq].probing = 0; - if (!irq_desc[irq].noautoenable) { - irq_desc[irq].enabled = 1; - irq_desc[irq].unmask(irq); + desc->nomask = (new->flags & SA_IRQNOMASK) ? 1 : 0; + desc->probing = 0; + if (!desc->noautoenable) { + desc->enabled = 1; + desc->unmask(irq); } } @@ -324,13 +314,45 @@ return 0; } +/** + * request_irq - allocate an interrupt line + * @irq: Interrupt line to allocate + * @handler: Function to be called when the IRQ occurs + * @irqflags: Interrupt type flags + * @devname: An ascii name for the claiming device + * @dev_id: A cookie passed back to the handler function + * + * This call allocates interrupt resources and enables the + * interrupt line and IRQ handling. From the point this + * call is made your handler function may be invoked. Since + * your handler function must clear any interrupt the board + * raises, you must take care both to initialise your hardware + * and to set up the interrupt handler in the right order. + * + * Dev_id must be globally unique. Normally the address of the + * device data structure is used as the cookie. Since the handler + * receives this value it makes sense to use it. + * + * If your interrupt is shared you must pass a non NULL dev_id + * as this is required when freeing the interrupt. + * + * Flags: + * + * SA_SHIRQ Interrupt is shared + * + * SA_INTERRUPT Disable local interrupts while processing + * + * SA_SAMPLE_RANDOM The interrupt can be used for entropy + * + */ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irq_flags, const char * devname, void *dev_id) { unsigned long retval; struct irqaction *action; - if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler) + if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler || + (irq_flags & SA_SHIRQ && !dev_id)) return -EINVAL; action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); @@ -351,6 +373,18 @@ return retval; } +/** + * free_irq - free an interrupt + * @irq: Interrupt line to free + * @dev_id: Device identity to free + * + * Remove an interrupt handler. The handler is removed and if the + * interrupt line is no longer in use by any driver it is disabled. + * On a shared IRQ the caller must ensure the interrupt is disabled + * on the card it drives before calling this function. + * + * This function may be called from interrupt context. + */ void free_irq(unsigned int irq, void *dev_id) { struct irqaction * action, **p; @@ -486,6 +520,6 @@ irq_desc[irq].unmask = dummy_mask_unmask_irq; } - irq_init_irq(); + init_arch_irq(); init_dma(); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/leds-ebsa110.c linux.ac/arch/arm/kernel/leds-ebsa110.c --- linux.vanilla/arch/arm/kernel/leds-ebsa110.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/kernel/leds-ebsa110.c Thu Jan 1 01:00:00 1970 @@ -1,51 +0,0 @@ -/* - * linux/arch/arm/kernel/leds-ebsa110.c - * - * Copyright (C) 1998 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. - * - * EBSA-110 LED control routines. We use the led as follows: - * - * - Red - toggles state every 50 timer interrupts - */ -#include <linux/module.h> -#include <linux/spinlock.h> -#include <linux/init.h> - -#include <asm/hardware.h> -#include <asm/leds.h> -#include <asm/system.h> -#include <asm/mach-types.h> - -static spinlock_t leds_lock; - -static void ebsa110_leds_event(led_event_t ledevt) -{ - unsigned long flags; - - spin_lock_irqsave(&leds_lock, flags); - - switch(ledevt) { - case led_timer: - *(volatile unsigned char *)0xf2400000 ^= 128; - break; - - default: - break; - } - - spin_unlock_irqrestore(&leds_lock, flags); -} - -static int __init leds_init(void) -{ - if (machine_is_ebsa110()) - leds_event = ebsa110_leds_event; - - return 0; -} - -__initcall(leds_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/oldlatches.c linux.ac/arch/arm/kernel/oldlatches.c --- linux.vanilla/arch/arm/kernel/oldlatches.c Tue Nov 28 01:07:59 2000 +++ linux.ac/arch/arm/kernel/oldlatches.c Sat Apr 14 01:16:23 2001 @@ -59,7 +59,7 @@ } } -initcall(oldlatch_init); +__initcall(oldlatch_init); EXPORT_SYMBOL(oldlatch_aupdate); EXPORT_SYMBOL(oldlatch_bupdate); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/setup.c linux.ac/arch/arm/kernel/setup.c --- linux.vanilla/arch/arm/kernel/setup.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/kernel/setup.c Sat Apr 14 01:16:23 2001 @@ -26,6 +26,7 @@ #include <asm/mach-types.h> #include <asm/mach/arch.h> +#include <asm/mach/irq.h> #ifndef MEM_SIZE #define MEM_SIZE (16*1024*1024) @@ -35,10 +36,21 @@ #define CONFIG_CMDLINE "" #endif +#if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE) +char fpe_type[8]; + +static int __init fpe_setup(char *line) +{ + memcpy(fpe_type, line, 8); + return 1; +} + +__setup("fpe=", fpe_setup); +#endif + extern void paging_init(struct meminfo *, struct machine_desc *desc); extern void bootmem_init(struct meminfo *); extern void reboot_setup(char *str); -extern void disable_hlt(void); extern unsigned long memparse(char *ptr, char **retptr); extern int root_mountflags; extern int _stext, _text, _etext, _edata, _end; @@ -71,9 +83,10 @@ char elf_platform[ELF_PLATFORM_SIZE]; char saved_command_line[COMMAND_LINE_SIZE]; +static struct meminfo meminfo __initdata = { 0, }; static struct proc_info_item proc_info; static const char *machine_name; -static char command_line[COMMAND_LINE_SIZE] = { 0, }; +static char command_line[COMMAND_LINE_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' } }; @@ -306,71 +319,222 @@ request_resource(&ioport_resource, &lp2); } +/* + * Tag parsing. + * + * This is the new way of passing data to the kernel at boot time. Rather + * than passing a fixed inflexible structure to the kernel, we pass a list + * of variable-sized tags to the kernel. The first tag must be a ATAG_CORE + * tag for the list to be recognised (to distinguish the tagged list from + * a param_struct). The list is terminated with a zero-length tag (this tag + * is not parsed in any way). + */ +static int __init parse_tag_core(const struct tag *tag) +{ + if ((tag->u.core.flags & 1) == 0) + root_mountflags &= ~MS_RDONLY; + ROOT_DEV = to_kdev_t(tag->u.core.rootdev); + return 0; +} + +static int __init parse_tag_mem32(const struct tag *tag) +{ + if (meminfo.nr_banks >= NR_BANKS) { + printk(KERN_WARNING + "Ignoring memory bank 0x%08x size %dKB\n", + tag->u.mem.start, tag->u.mem.size / 1024); + return -EINVAL; + } + meminfo.bank[meminfo.nr_banks].start = tag->u.mem.start; + meminfo.bank[meminfo.nr_banks].size = tag->u.mem.size; + meminfo.bank[meminfo.nr_banks].node = 0; + meminfo.nr_banks += 1; + + return 0; +} + +static int __init parse_tag_videotext(const struct tag *tag) +{ + screen_info.orig_x = tag->u.videotext.x; + screen_info.orig_y = tag->u.videotext.y; + screen_info.orig_video_page = tag->u.videotext.video_page; + screen_info.orig_video_mode = tag->u.videotext.video_mode; + screen_info.orig_video_cols = tag->u.videotext.video_cols; + screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx; + screen_info.orig_video_lines = tag->u.videotext.video_lines; + screen_info.orig_video_isVGA = tag->u.videotext.video_isvga; + screen_info.orig_video_points = tag->u.videotext.video_points; + return 0; +} + +static int __init parse_tag_ramdisk(const struct tag *tag) +{ + setup_ramdisk((tag->u.ramdisk.flags & 1) == 0, + (tag->u.ramdisk.flags & 2) == 0, + tag->u.ramdisk.start, tag->u.ramdisk.size); + return 0; +} + +static int __init parse_tag_initrd(const struct tag *tag) +{ + setup_initrd(tag->u.initrd.start, tag->u.initrd.size); + return 0; +} + +static int __init parse_tag_serialnr(const struct tag *tag) +{ + system_serial_low = tag->u.serialnr.low; + system_serial_high = tag->u.serialnr.high; + return 0; +} + +static int __init parse_tag_revision(const struct tag *tag) +{ + system_rev = tag->u.revision.rev; + return 0; +} + +static int __init parse_tag_cmdline(const struct tag *tag) +{ + strncpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE); + default_command_line[COMMAND_LINE_SIZE - 1] = '\0'; + return 0; +} + +/* + * This is the core tag table; these are the tags + * that we recognise for any machine type. + */ +static const struct tagtable core_tagtable[] __init = { + { ATAG_CORE, parse_tag_core }, + { ATAG_MEM, parse_tag_mem32 }, + { ATAG_VIDEOTEXT, parse_tag_videotext }, + { ATAG_RAMDISK, parse_tag_ramdisk }, + { ATAG_INITRD, parse_tag_initrd }, + { ATAG_SERIAL, parse_tag_serialnr }, + { ATAG_REVISION, parse_tag_revision }, + { ATAG_CMDLINE, parse_tag_cmdline } +}; + +/* + * Scan one tag table for this tag, and call its parse function. + */ +static int __init +parse_tag(const struct tagtable *tbl, int size, const struct tag *t) +{ + int i; + + for (i = 0; i < size; i++, tbl++) + if (t->hdr.tag == tbl->tag) { + tbl->parse(t); + break; + } + + return i < size; +} + +/* + * Parse all tags in the list, checking both the global and architecture + * specific tag tables. + */ +static void __init +parse_tags(const struct tagtable *tbl, int size, const struct tag *t) +{ + /* + * The tag list is terminated with a zero-sized tag. Size is + * defined to be in units of 32-bit quantities. + */ + for (; t->hdr.size; t = (struct tag *)((u32 *)t + t->hdr.size)) { + if (parse_tag(core_tagtable, ARRAY_SIZE(core_tagtable), t)) + continue; + + if (tbl && parse_tag(tbl, size, t)) + continue; + + printk(KERN_WARNING + "Ignoring unrecognised tag 0x%08x\n", t->hdr.tag); + } +} + +static void __init parse_params(struct param_struct *params) +{ + if (params->u1.s.page_size != PAGE_SIZE) { + printk(KERN_WARNING "Warning: bad configuration page, " + "trying to continue\n"); + return; + } + + 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; + + if (params->u1.s.mem_fclk_21285 > 0) + mem_fclk_21285 = params->u1.s.mem_fclk_21285; + + 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); + + setup_initrd(params->u1.s.initrd_start, + params->u1.s.initrd_size); + + if (!(params->u1.s.flags & FLAG_READONLY)) + root_mountflags &= ~MS_RDONLY; + + strncpy(default_command_line, params->commandline, COMMAND_LINE_SIZE); + default_command_line[COMMAND_LINE_SIZE - 1] = '\0'; + + if (meminfo.nr_banks == 0) { + meminfo.nr_banks = 1; + meminfo.bank[0].start = PHYS_OFFSET; + meminfo.bank[0].size = params->u1.s.nr_pages << PAGE_SHIFT; + } +} + void __init setup_arch(char **cmdline_p) { struct param_struct *params = NULL; struct machine_desc *mdesc; - struct meminfo meminfo; char *from = default_command_line; - memset(&meminfo, 0, sizeof(meminfo)); - - setup_processor(); - ROOT_DEV = MKDEV(0, 255); + setup_processor(); mdesc = setup_architecture(machine_arch_type); machine_name = mdesc->name; - if (mdesc->broken_hlt) - disable_hlt(); - if (mdesc->soft_reboot) reboot_setup("s"); if (mdesc->param_offset) params = phys_to_virt(mdesc->param_offset); + /* + * Do the machine-specific fixups before we parse the + * parameters or tags. + */ if (mdesc->fixup) mdesc->fixup(mdesc, params, &from, &meminfo); - if (params && params->u1.s.page_size != PAGE_SIZE) { - printk(KERN_WARNING "Warning: bad configuration page, " - "trying to continue\n"); - params = NULL; - } - if (params) { - 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; - - if (params->u1.s.mem_fclk_21285 > 0) - mem_fclk_21285 = params->u1.s.mem_fclk_21285; - - 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); - - setup_initrd(params->u1.s.initrd_start, - params->u1.s.initrd_size); - - if (!(params->u1.s.flags & FLAG_READONLY)) - root_mountflags &= ~MS_RDONLY; + struct tag *tag = (struct tag *)params; - from = params->commandline; + /* + * Is the first tag the CORE tag? This differentiates + * between the tag list and the parameter table. + */ + if (tag->hdr.tag == ATAG_CORE) + parse_tags(mdesc->tagtable, mdesc->tagsize, tag); + else + parse_params(params); } if (meminfo.nr_banks == 0) { meminfo.nr_banks = 1; meminfo.bank[0].start = PHYS_OFFSET; - meminfo.bank[0].node = 0; - if (params) - meminfo.bank[0].size = params->u1.s.nr_pages << PAGE_SHIFT; - else - meminfo.bank[0].size = MEM_SIZE; + meminfo.bank[0].size = MEM_SIZE; } init_mm.start_code = (unsigned long) &_text; @@ -385,6 +549,11 @@ paging_init(&meminfo, mdesc); request_standard_resources(&meminfo, mdesc); + /* + * Set up various architecture-specific pointers + */ + init_arch_irq = mdesc->init_irq; + #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) conswitchp = &vga_con; @@ -403,8 +572,8 @@ (int)processor_id & 15, elf_platform); p += sprintf(p, "BogoMIPS\t: %lu.%02lu\n", - (loops_per_sec+2500) / 500000, - ((loops_per_sec+2500) / 5000) % 100); + loops_per_jiffy / (500000/HZ), + (loops_per_jiffy / (5000/HZ)) % 100); p += sprintf(p, "Hardware\t: %s\n", machine_name); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/time-acorn.c linux.ac/arch/arm/kernel/time-acorn.c --- linux.vanilla/arch/arm/kernel/time-acorn.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/kernel/time-acorn.c Sat Apr 14 01:16:23 2001 @@ -28,17 +28,17 @@ unsigned int count1, count2, status1, status2; unsigned long offset = 0; - status1 = inb(IOC_IRQREQA); + status1 = ioc_readb(IOC_IRQREQA); barrier (); - outb (0, IOC_T0LATCH); + ioc_writeb (0, IOC_T0LATCH); barrier (); - count1 = inb(IOC_T0CNTL) | (inb(IOC_T0CNTH) << 8); + count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8); barrier (); - status2 = inb(IOC_IRQREQA); + status2 = ioc_readb(IOC_IRQREQA); barrier (); - outb (0, IOC_T0LATCH); + ioc_writeb (0, IOC_T0LATCH); barrier (); - count2 = inb(IOC_T0CNTL) | (inb(IOC_T0CNTH) << 8); + count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8); if (count2 < count1) { /* @@ -67,9 +67,9 @@ void __init ioctime_init(void) { - outb(LATCH & 255, IOC_T0LTCHL); - outb(LATCH >> 8, IOC_T0LTCHH); - outb(0, IOC_T0GO); + ioc_writeb(LATCH & 255, IOC_T0LTCHL); + ioc_writeb(LATCH >> 8, IOC_T0LTCHH); + ioc_writeb(0, IOC_T0GO); gettimeoffset = ioctime_gettimeoffset; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/via82c505.c linux.ac/arch/arm/kernel/via82c505.c --- linux.vanilla/arch/arm/kernel/via82c505.c Tue Nov 28 01:07:59 2000 +++ linux.ac/arch/arm/kernel/via82c505.c Sat Apr 14 01:16:23 2001 @@ -106,8 +106,8 @@ break; case PCI_BASE_ADDRESS_0: if (size_wanted) { - /* 0x00900000 bytes long */ - *value = 0xff700000; + /* 0x00900000 bytes long (0xff700000) */ + *value = 0xff000000; size_wanted = 0; } else { *value = FB_START; @@ -117,7 +117,7 @@ *value = 6; break; default: - *value=0; + *value = 0; } return PCIBIOS_SUCCESSFUL; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/lib/Makefile linux.ac/arch/arm/lib/Makefile --- linux.vanilla/arch/arm/lib/Makefile Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/arm/lib/Makefile Sat Apr 14 01:16:23 2001 @@ -17,8 +17,6 @@ obj-m := obj-n := -export-objs := io.o - obj-arc := ecard.o io-acorn.o floppydma.o obj-rpc := ecard.o io-acorn.o floppydma.o obj-clps7500 := io-acorn.o @@ -47,10 +45,6 @@ ifeq ($(PROCESSOR),armo) obj-y += uaccess-armo.o -endif - -ifneq ($(MACHINE),ebsa110) - obj-y += io.o endif include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/lib/backtrace.S linux.ac/arch/arm/lib/backtrace.S --- linux.vanilla/arch/arm/lib/backtrace.S Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/lib/backtrace.S Sat Apr 14 01:16:23 2001 @@ -26,7 +26,7 @@ ENTRY(c_backtrace) -#ifndef CONFIG_FRAME_POINTER +#ifdef CONFIG_NO_FRAME_POINTER mov pc, lr #else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/lib/delay.S linux.ac/arch/arm/lib/delay.S --- linux.vanilla/arch/arm/lib/delay.S Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/lib/delay.S Sat Apr 14 01:16:23 2001 @@ -11,19 +11,26 @@ #include <asm/assembler.h> .text -LC0: .word SYMBOL_NAME(loops_per_sec) +LC0: .word SYMBOL_NAME(loops_per_jiffy) +/* + * 0 <= r0 <= 2000 + */ ENTRY(udelay) - mov r2, #0x1000 - orr r2, r2, #0x00c6 + mov r2, #0x6800 + orr r2, r2, #0x00db mul r1, r0, r2 ldr r2, LC0 ldr r2, [r2] mov r1, r1, lsr #11 mov r2, r2, lsr #11 mul r0, r1, r2 - movs r0, r0, lsr #10 + movs r0, r0, lsr #6 RETINSTR(moveq,pc,lr) + +/* + * loops = (r0 * 0x10c6 * 100 * loops_per_jiffie) / 2^32 + */ @ Delay routine ENTRY(__delay) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/lib/io-shark.c linux.ac/arch/arm/lib/io-shark.c --- linux.vanilla/arch/arm/lib/io-shark.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/lib/io-shark.c Sat Apr 14 01:16:23 2001 @@ -1,7 +1,7 @@ /* * linux/arch/arm/lib/io-shark.c * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> * * derived from: * linux/arch/arm/lib/io-ebsa.S diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/lib/io.c linux.ac/arch/arm/lib/io.c --- linux.vanilla/arch/arm/lib/io.c Mon Feb 7 01:45:25 2000 +++ linux.ac/arch/arm/lib/io.c Thu Jan 1 01:00:00 1970 @@ -1,50 +0,0 @@ -#include <linux/module.h> -#include <linux/types.h> - -#include <asm/io.h> - -/* - * Copy data from IO memory space to "real" memory space. - * This needs to be optimized. - */ -void _memcpy_fromio(void * to, unsigned long from, size_t count) -{ - while (count) { - count--; - *(char *) to = readb(from); - ((char *) to)++; - from++; - } -} - -/* - * Copy data from "real" memory space to IO memory space. - * This needs to be optimized. - */ -void _memcpy_toio(unsigned long to, const void * from, size_t count) -{ - while (count) { - count--; - writeb(*(char *) from, to); - ((char *) from)++; - to++; - } -} - -/* - * "memset" on IO memory space. - * This needs to be optimized. - */ -void _memset_io(unsigned long dst, int c, size_t count) -{ - while (count) { - count--; - writeb(c, dst); - dst++; - } -} - -EXPORT_SYMBOL(_memcpy_fromio); -EXPORT_SYMBOL(_memcpy_toio); -EXPORT_SYMBOL(_memset_io); - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-ebsa110/Makefile linux.ac/arch/arm/mach-ebsa110/Makefile --- linux.vanilla/arch/arm/mach-ebsa110/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-ebsa110/Makefile Sat Apr 14 01:16:46 2001 @@ -0,0 +1,23 @@ +# +# 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). + +USE_STANDARD_AS_RULE := true + +O_TARGET := ebsa110.o + +# Object file lists. + +obj-y := arch.o io.o irq.o mm.o time.o +obj-m := +obj-n := +obj- := + +export-objs := io.o + +obj-$(CONFIG_LEDS) += leds.o + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-ebsa110/arch.c linux.ac/arch/arm/mach-ebsa110/arch.c --- linux.vanilla/arch/arm/mach-ebsa110/arch.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-ebsa110/arch.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,33 @@ +/* + * linux/arch/arm/mach-ebsa110/arch.c + * + * 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. + */ +#include <linux/tty.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/init.h> + +#include <asm/elf.h> +#include <asm/setup.h> +#include <asm/mach-types.h> + +#include <asm/mach/arch.h> +#include <asm/hardware/dec21285.h> + +extern void ebsa110_map_io(void); +extern void ebsa110_init_irq(void); + +MACHINE_START(EBSA110, "EBSA110") + MAINTAINER("Russell King") + BOOT_MEM(0x00000000, 0xe0000000, 0xe0000000) + BOOT_PARAMS(0x00000400) + DISABLE_PARPORT(0) + DISABLE_PARPORT(2) + SOFT_REBOOT + MAPIO(ebsa110_map_io) + INITIRQ(ebsa110_init_irq) +MACHINE_END diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-ebsa110/io.c linux.ac/arch/arm/mach-ebsa110/io.c --- linux.vanilla/arch/arm/mach-ebsa110/io.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-ebsa110/io.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,320 @@ +/* + * linux/arch/arm/mach-ebsa110/isamem.c + * + * Copyright (C) 2001 Russell King + * + * Perform "ISA" memory and IO accesses. The EBSA110 has some "peculiarities" + * in the way it handles accesses to odd IO ports on 16-bit devices. These + * devices have their D0-D15 lines connected to the processors D0-D15 lines. + * Since they expect all byte IO operations to be performed on D0-D7, and the + * StrongARM expects to transfer the byte to these odd addresses on D8-D15, + * we must use a trick to get the required behaviour. + * + * The trick employed here is to use long word stores to odd address -1. The + * glue logic picks this up as a "trick" access, and asserts the LSB of the + * peripherals address bus, thereby accessing the odd IO port. Meanwhile, the + * StrongARM transfers its data on D0-D7 as expected. + * + * Things get more interesting on the pass-1 EBSA110 - the PCMCIA controller + * wiring was screwed in such a way that it had limited memory space access. + * Luckily, the work-around for this is not too horrible. See + * __isamem_convert_addr for the details. + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> + +#include <asm/io.h> +#include <asm/page.h> + +static u32 __isamem_convert_addr(void *addr) +{ + u32 ret, a = (u32) addr; + + /* + * The PCMCIA controller is wired up as follows: + * +---------+---------+---------+---------+---------+---------+ + * PCMCIA | 2 2 2 2 | 1 1 1 1 | 1 1 1 1 | 1 1 | | | + * | 3 2 1 0 | 9 8 7 6 | 5 4 3 2 | 1 0 9 8 | 7 6 5 4 | 3 2 1 0 | + * +---------+---------+---------+---------+---------+---------+ + * CPU | 2 2 2 2 | 2 1 1 1 | 1 1 1 1 | 1 1 1 | | | + * | 4 3 2 1 | 0 9 9 8 | 7 6 5 4 | 3 2 0 9 | 8 7 6 5 | 4 3 2 x | + * +---------+---------+---------+---------+---------+---------+ + * + * This means that we can access PCMCIA regions as follows: + * 0x*10000 -> 0x*1ffff + * 0x*70000 -> 0x*7ffff + * 0x*90000 -> 0x*9ffff + * 0x*f0000 -> 0x*fffff + */ + ret = (a & 0xf803fe) << 1; + ret |= (a & 0x03fc00) << 2; + + ret += 0xe8000000; + + if ((a & 0x20000) == (a & 0x40000) >> 1) + return ret; + + BUG(); + return 0; +} + +/* + * read[bwl] and write[bwl] + */ +u8 __readb(void *addr) +{ + u32 ret, a = __isamem_convert_addr(addr); + + if ((int)addr & 1) + ret = __arch_getl(a); + else + ret = __arch_getb(a); + return ret; +} + +u16 __readw(void *addr) +{ + u32 a = __isamem_convert_addr(addr); + + if ((int)addr & 1) + BUG(); + + return __arch_getw(a); +} + +u32 __readl(void *addr) +{ + u32 ret, a = __isamem_convert_addr(addr); + + if ((int)addr & 3) + BUG(); + + ret = __arch_getw(a); + ret |= __arch_getw(a + 4) << 16; + return ret; +} + +EXPORT_SYMBOL(__readb); +EXPORT_SYMBOL(__readw); +EXPORT_SYMBOL(__readl); + +void __writeb(u8 val, void *addr) +{ + u32 a = __isamem_convert_addr(addr); + + if ((int)addr & 1) + __arch_putl(val, a); + else + __arch_putb(val, a); +} + +void __writew(u16 val, void *addr) +{ + u32 a = __isamem_convert_addr(addr); + + if ((int)addr & 1) + BUG(); + + __arch_putw(val, a); +} + +void __writel(u32 val, void *addr) +{ + u32 a = __isamem_convert_addr(addr); + + if ((int)addr & 3) + BUG(); + + __arch_putw(val, a); + __arch_putw(val >> 16, a + 4); +} + +EXPORT_SYMBOL(__writeb); +EXPORT_SYMBOL(__writew); +EXPORT_SYMBOL(__writel); + +#define SUPERIO_PORT(p) \ + (((p) >> 3) == (0x3f8 >> 3) || \ + ((p) >> 3) == (0x2f8 >> 3) || \ + ((p) >> 3) == (0x378 >> 3)) + +u8 __inb(int port) +{ + u32 ret; + + /* + * The SuperIO registers use sane addressing techniques... + */ + if (SUPERIO_PORT(port)) + ret = __arch_getb(ISAIO_BASE + (port << 2)); + else { + u32 a = ISAIO_BASE + ((port & ~1) << 1); + + /* + * Shame nothing else does + */ + if (port & 1) + ret = __arch_getl(a); + else + ret = __arch_getb(a); + } + return ret; +} + +u16 __inw(int port) +{ + u32 ret; + + /* + * The SuperIO registers use sane addressing techniques... + */ + if (SUPERIO_PORT(port)) + ret = __arch_getw(ISAIO_BASE + (port << 2)); + else { + u32 a = ISAIO_BASE + ((port & ~1) << 1); + + /* + * Shame nothing else does + */ + if (port & 1) + BUG(); + + ret = __arch_getw(a); + } + return ret; +} + +u32 __inl(int port) +{ + BUG(); +} + +EXPORT_SYMBOL(__inb); +EXPORT_SYMBOL(__inw); +EXPORT_SYMBOL(__inl); + +void __outb(u8 val, int port) +{ + /* + * The SuperIO registers use sane addressing techniques... + */ + if (SUPERIO_PORT(port)) + __arch_putb(val, ISAIO_BASE + (port << 2)); + else { + u32 a = ISAIO_BASE + ((port & ~1) << 1); + + /* + * Shame nothing else does + */ + if (port & 1) + __arch_putl(val, a); + else + __arch_putb(val, a); + } +} + +void __outw(u16 val, int port) +{ + u32 off; + + /* + * The SuperIO registers use sane addressing techniques... + */ + if (SUPERIO_PORT(port)) + off = port << 2; + else { + off = (port & ~1) << 1; + if (port & 1) + BUG(); + + } + __arch_putw(val, ISAIO_BASE + off); +} + +void __outl(u32 val, int port) +{ + BUG(); +} + +EXPORT_SYMBOL(__outb); +EXPORT_SYMBOL(__outw); +EXPORT_SYMBOL(__outl); + +extern void __arch_writesb(unsigned long virt, const void *from, int len); +extern void __arch_writesw(unsigned long virt, const void *from, int len); +extern void __arch_writesl(unsigned long virt, const void *from, int len); +extern void __arch_readsb(unsigned long virt, void *from, int len); +extern void __arch_readsw(unsigned long virt, void *from, int len); +extern void __arch_readsl(unsigned long virt, void *from, int len); + +void outsb(unsigned int port, const void *from, int len) +{ + u32 off; + + if (SUPERIO_PORT(port)) + off = port << 2; + else { + off = (port & ~1) << 1; + if (port & 1) + BUG(); + } + + __arch_writesb(ISAIO_BASE + off, from, len); +} + +void insb(unsigned int port, void *from, int len) +{ + u32 off; + + if (SUPERIO_PORT(port)) + off = port << 2; + else { + off = (port & ~1) << 1; + if (port & 1) + BUG(); + } + + __arch_readsb(ISAIO_BASE + off, from, len); +} + +void outsw(unsigned int port, const void *from, int len) +{ + u32 off; + + if (SUPERIO_PORT(port)) + off = port << 2; + else { + off = (port & ~1) << 1; + if (port & 1) + BUG(); + } + + __arch_writesw(ISAIO_BASE + off, from, len); +} + +void insw(unsigned int port, void *from, int len) +{ + u32 off; + + if (SUPERIO_PORT(port)) + off = port << 2; + else { + off = (port & ~1) << 1; + if (port & 1) + BUG(); + } + + __arch_readsw(ISAIO_BASE + off, from, len); +} + +void outsl(unsigned int port, const void *from, int len) +{ + panic("outsl not supported on this architecture"); +} + +void insl(unsigned int port, void *from, int len) +{ + panic("insl not supported on this architecture"); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-ebsa110/irq.c linux.ac/arch/arm/mach-ebsa110/irq.c --- linux.vanilla/arch/arm/mach-ebsa110/irq.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-ebsa110/irq.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,55 @@ +/* + * linux/arch/arm/mach-ebsa110/irq.c + * + * Copyright (C) 1996-1998 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. + * + * Changelog: + * 22-08-1998 RMK Restructured IRQ routines + */ +#include <linux/init.h> + +#include <asm/mach/irq.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> + +#include "hardware.h" + +static void ebsa110_mask_irq(unsigned int irq) +{ + __raw_writeb(1 << irq, IRQ_MCLR); +} + +static void ebsa110_unmask_irq(unsigned int irq) +{ + __raw_writeb(1 << irq, IRQ_MSET); +} + +void __init ebsa110_init_irq(void) +{ + unsigned long flags; + int irq; + + save_flags_cli (flags); + __raw_writeb(0xff, IRQ_MCLR); + __raw_writeb(0x55, IRQ_MSET); + __raw_writeb(0x00, IRQ_MSET); + if (__raw_readb(IRQ_MASK) != 0x55) + while (1); + __raw_writeb(0xff, IRQ_MCLR); /* clear all interrupt enables */ + restore_flags (flags); + + for (irq = 0; irq < NR_IRQS; irq++) { + irq_desc[irq].valid = 1; + irq_desc[irq].probe_ok = 1; + irq_desc[irq].mask_ack = ebsa110_mask_irq; + irq_desc[irq].mask = ebsa110_mask_irq; + irq_desc[irq].unmask = ebsa110_unmask_irq; + } +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-ebsa110/leds.c linux.ac/arch/arm/mach-ebsa110/leds.c --- linux.vanilla/arch/arm/mach-ebsa110/leds.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-ebsa110/leds.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,51 @@ +/* + * linux/arch/arm/mach-ebsa110/leds.c + * + * Copyright (C) 1998 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. + * + * EBSA-110 LED control routines. We use the led as follows: + * + * - Red - toggles state every 50 timer interrupts + */ +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/init.h> + +#include <asm/hardware.h> +#include <asm/leds.h> +#include <asm/system.h> +#include <asm/mach-types.h> + +static spinlock_t leds_lock; + +static void ebsa110_leds_event(led_event_t ledevt) +{ + unsigned long flags; + + spin_lock_irqsave(&leds_lock, flags); + + switch(ledevt) { + case led_timer: + *(volatile unsigned char *)SOFT_BASE ^= 128; + break; + + default: + break; + } + + spin_unlock_irqrestore(&leds_lock, flags); +} + +static int __init leds_init(void) +{ + if (machine_is_ebsa110()) + leds_event = ebsa110_leds_event; + + return 0; +} + +__initcall(leds_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-ebsa110/mm.c linux.ac/arch/arm/mach-ebsa110/mm.c --- linux.vanilla/arch/arm/mach-ebsa110/mm.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-ebsa110/mm.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,43 @@ +/* + * linux/arch/arm/mach-ebsa110/mm.c + * + * Copyright (C) 1998-1999 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. + * + * Extra MM routines for the EBSA-110 architecture + */ +#include <linux/mm.h> +#include <linux/init.h> + +#include <asm/hardware.h> +#include <asm/pgtable.h> +#include <asm/page.h> + +#include <asm/mach/map.h> + +#include "hardware.h" + +static struct map_desc ebsa110_io_desc[] __initdata = { + /* + * sparse external-decode ISAIO space + */ + { IRQ_STAT, TRICK4_PHYS, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, /* IRQ_STAT/IRQ_MCLR */ + { IRQ_MASK, TRICK3_PHYS, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, /* IRQ_MASK/IRQ_MSET */ + { SOFT_BASE, TRICK1_PHYS, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, /* SOFT_BASE */ + { PIT_BASE, TRICK0_PHYS, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, /* PIT_BASE */ + + /* + * self-decode ISAIO space + */ + { ISAIO_BASE, ISAIO_PHYS, ISAIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { ISAMEM_BASE, ISAMEM_PHYS, ISAMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC +}; + +void __init ebsa110_map_io(void) +{ + iotable_init(ebsa110_io_desc); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-ebsa110/time.c linux.ac/arch/arm/mach-ebsa110/time.c --- linux.vanilla/arch/arm/mach-ebsa110/time.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-ebsa110/time.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,113 @@ +/* + * linux/arch/arm/mach-ebsa110/time.c + * + * Copyright (C) 2001 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 <linux/sched.h> +#include <linux/init.h> + +#include <asm/io.h> + +#define PIT_CTRL (PIT_BASE + 0x0d) +#define PIT_T2 (PIT_BASE + 0x09) +#define PIT_T1 (PIT_BASE + 0x05) +#define PIT_T0 (PIT_BASE + 0x01) + +/* + * This is the rate at which your MCLK signal toggles (in Hz) + * This was measured on a 10 digit frequency counter sampling + * over 1 second. + */ +#define MCLK 47894000 + +/* + * This is the rate at which the PIT timers get clocked + */ +#define CLKBY7 (MCLK / 7) + +/* + * If CLKBY7 is larger than this, then we must do software + * division of the timer interrupt. + */ +#if CLKBY7 > 6553500 +#define DIVISOR 2 +#else +#define DIVISOR 1 +#endif + +/* + * This is the counter value + */ +#define COUNT ((CLKBY7 + (DIVISOR * HZ / 2)) / (DIVISOR * HZ)) + +extern unsigned long (*gettimeoffset)(void); + +static unsigned long divisor; + +/* + * Get the time offset from the system PIT. Note that if we have missed an + * interrupt, then the PIT counter will roll over (ie, be negative). + * This actually works out to be convenient. + */ +static unsigned long ebsa110_gettimeoffset(void) +{ + unsigned long offset, count; + + __raw_writeb(0x40, PIT_CTRL); + count = __raw_readb(PIT_T1); + count |= __raw_readb(PIT_T1) << 8; + + /* + * If count > COUNT, make the number negative. + */ + if (count > COUNT) + count |= 0xffff0000; + + offset = COUNT * (DIVISOR - divisor); + offset -= count; + + /* + * `offset' is in units of timer counts. Convert + * offset to units of microseconds. + */ + offset = offset * (1000000 / HZ) / (COUNT * DIVISOR); + + return offset; +} + +int ebsa110_reset_timer(void) +{ + u32 count; + + /* latch and read timer 1 */ + __raw_writeb(0x40, PIT_CTRL); + count = __raw_readb(PIT_T1); + count |= __raw_readb(PIT_T1) << 8; + + count += COUNT; + + __raw_writeb(count & 0xff, PIT_T1); + __raw_writeb(count >> 8, PIT_T1); + + if (divisor == 0) + divisor = DIVISOR; + divisor -= 1; + return divisor; +} + +void __init ebsa110_setup_timer(void) +{ + /* + * Timer 1, mode 2, LSB/MSB + */ + __raw_writeb(0x70, PIT_CTRL); + __raw_writeb(COUNT & 0xff, PIT_T1); + __raw_writeb(COUNT >> 8, PIT_T1); + divisor = DIVISOR - 1; + + gettimeoffset = ebsa110_gettimeoffset; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-footbridge/Makefile linux.ac/arch/arm/mach-footbridge/Makefile --- linux.vanilla/arch/arm/mach-footbridge/Makefile Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mach-footbridge/Makefile Sat Apr 14 01:16:46 2001 @@ -5,42 +5,32 @@ # removes any old dependencies. DON'T put your own dependencies here # unless it's something special (ie not a .c file). +USE_STANDARD_AS_RULE := true + O_TARGET := footbridge.o # Object file lists. -obj-y := arch.o #dma.o mm.o +obj-y := arch.o irq.o mm.o #dma.o obj-m := obj-n := obj- := export-objs := netwinder-hw.o -ifeq ($(CONFIG_PCI),y) -obj-$(CONFIG_ARCH_CATS) += cats-pci.o -obj-$(CONFIG_ARCH_EBSA285) += ebsa285-pci.o -obj-$(CONFIG_ARCH_NETWINDER) += netwinder-pci.o -obj-$(CONFIG_ARCH_PERSONAL_SERVER) += personal-pci.o -endif - -ifeq ($(CONFIG_LEDS),y) -obj-$(CONFIG_ARCH_CO285) += ebsa285-leds.o -obj-$(CONFIG_ARCH_EBSA285) += ebsa285-leds.o -obj-$(CONFIG_ARCH_NETWINDER) += netwinder-leds.o -endif +pci-$(CONFIG_ARCH_CATS) += cats-pci.o +pci-$(CONFIG_ARCH_EBSA285) += ebsa285-pci.o +pci-$(CONFIG_ARCH_NETWINDER) += netwinder-pci.o +pci-$(CONFIG_ARCH_PERSONAL_SERVER) += personal-pci.o + +leds-$(CONFIG_ARCH_CO285) += ebsa285-leds.o +leds-$(CONFIG_ARCH_EBSA285) += ebsa285-leds.o +leds-$(CONFIG_ARCH_NETWINDER) += netwinder-leds.o obj-$(CONFIG_ARCH_CATS) += cats-hw.o obj-$(CONFIG_ARCH_NETWINDER) += netwinder-hw.o -# Files that are both resident and modular; remove from modular. - -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-out $(export-objs), $(obj-m))) -MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) +obj-$(CONFIG_PCI) +=$(pci-y) +obj-$(CONFIG_LEDS) +=$(leds-y) include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-footbridge/arch.c linux.ac/arch/arm/mach-footbridge/arch.c --- linux.vanilla/arch/arm/mach-footbridge/arch.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mach-footbridge/arch.c Sat Apr 14 01:16:46 2001 @@ -19,9 +19,8 @@ #include <asm/mach/arch.h> -extern void setup_initrd(unsigned int start, unsigned int size); -extern void setup_ramdisk(int doload, int prompt, int start, unsigned int rd_sz); -extern void __init footbridge_map_io(void); +extern void footbridge_map_io(void); +extern void footbridge_init_irq(void); #ifdef CONFIG_ARCH_EBSA285 @@ -42,6 +41,7 @@ VIDEO(0x000a0000, 0x000bffff) FIXUP(fixup_ebsa285) MAPIO(footbridge_map_io) + INITIRQ(footbridge_init_irq) MACHINE_END #endif @@ -91,6 +91,7 @@ DISABLE_PARPORT(2) FIXUP(fixup_netwinder) MAPIO(footbridge_map_io) + INITIRQ(footbridge_init_irq) MACHINE_END #endif @@ -111,9 +112,11 @@ MACHINE_START(CATS, "Chalice-CATS") MAINTAINER("Philip Blundell") BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) + BOOT_PARAMS(0x00000100) SOFT_REBOOT FIXUP(fixup_cats) MAPIO(footbridge_map_io) + INITIRQ(footbridge_init_irq) MACHINE_END #endif @@ -139,6 +142,7 @@ BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0x7cf00000) FIXUP(fixup_coebsa285) MAPIO(footbridge_map_io) + INITIRQ(footbridge_init_irq) MACHINE_END #endif @@ -148,5 +152,6 @@ BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) BOOT_PARAMS(0x00000100) MAPIO(footbridge_map_io) + INITIRQ(footbridge_init_irq) MACHINE_END #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-footbridge/irq.c linux.ac/arch/arm/mach-footbridge/irq.c --- linux.vanilla/arch/arm/mach-footbridge/irq.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-footbridge/irq.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,223 @@ +/* + * linux/arch/arm/mach-footbridge/irq.c + * + * Copyright (C) 1996-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. + * + * Changelog: + * 22-Aug-1998 RMK Restructured IRQ routines + * 03-Sep-1998 PJB Merged CATS support + * 20-Jan-1998 RMK Started merge of EBSA286, CATS and NetWinder + * 26-Jan-1999 PJB Don't use IACK on CATS + * 16-Mar-1999 RMK Added autodetect of ISA PICs + */ +#include <linux/sched.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/init.h> + +#include <asm/mach/irq.h> + +#include <asm/hardware.h> +#include <asm/hardware/dec21285.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <asm/mach-types.h> + +/* + * Footbridge IRQ translation table + * Converts from our IRQ numbers into FootBridge masks + */ +static const int fb_irq_mask[] = { + IRQ_MASK_UART_RX, /* 0 */ + IRQ_MASK_UART_TX, /* 1 */ + IRQ_MASK_TIMER1, /* 2 */ + IRQ_MASK_TIMER2, /* 3 */ + IRQ_MASK_TIMER3, /* 4 */ + IRQ_MASK_IN0, /* 5 */ + IRQ_MASK_IN1, /* 6 */ + IRQ_MASK_IN2, /* 7 */ + IRQ_MASK_IN3, /* 8 */ + IRQ_MASK_DOORBELLHOST, /* 9 */ + IRQ_MASK_DMA1, /* 10 */ + IRQ_MASK_DMA2, /* 11 */ + IRQ_MASK_PCI, /* 12 */ + IRQ_MASK_SDRAMPARITY, /* 13 */ + IRQ_MASK_I2OINPOST, /* 14 */ + IRQ_MASK_PCI_ABORT, /* 15 */ + IRQ_MASK_PCI_SERR, /* 16 */ + IRQ_MASK_DISCARD_TIMER, /* 17 */ + IRQ_MASK_PCI_DPERR, /* 18 */ + IRQ_MASK_PCI_PERR, /* 19 */ +}; + +static void fb_mask_irq(unsigned int irq) +{ + *CSR_IRQ_DISABLE = fb_irq_mask[_DC21285_INR(irq)]; +} + +static void fb_unmask_irq(unsigned int irq) +{ + *CSR_IRQ_ENABLE = fb_irq_mask[_DC21285_INR(irq)]; +} + +static void __init __fb_init_irq(void) +{ + int irq; + + /* + * setup DC21285 IRQs + */ + *CSR_IRQ_DISABLE = -1; + *CSR_FIQ_DISABLE = -1; + + for (irq = _DC21285_IRQ(0); irq < _DC21285_IRQ(20); irq++) { + irq_desc[irq].valid = 1; + irq_desc[irq].probe_ok = 1; + irq_desc[irq].mask_ack = fb_mask_irq; + irq_desc[irq].mask = fb_mask_irq; + irq_desc[irq].unmask = fb_unmask_irq; + } +} + +extern int isa_irq; + +static void isa_mask_pic_lo_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO); +} + +static void isa_mask_ack_pic_lo_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO); + outb(0x20, PIC_LO); +} + +static void isa_unmask_pic_lo_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_LO) & ~mask, PIC_MASK_LO); +} + +static void isa_mask_pic_hi_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI); +} + +static void isa_mask_ack_pic_hi_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI); + outb(0x62, PIC_LO); + outb(0x20, PIC_HI); +} + +static void isa_unmask_pic_hi_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI); +} + +static void no_action(int irq, void *dev_id, struct pt_regs *regs) +{ +} + +static struct irqaction irq_cascade = { handler: no_action, name: "cascade", }; +static struct resource pic1_resource = { "pic1", 0x20, 0x3f }; +static struct resource pic2_resource = { "pic2", 0xa0, 0xbf }; + +static void __init isa_init_irq(int irq) +{ + /* + * Setup, and then probe for an ISA PIC + * If the PIC is not there, then we + * ignore the PIC. + */ + outb(0x11, PIC_LO); + outb(_ISA_IRQ(0), PIC_MASK_LO); /* IRQ number */ + outb(0x04, PIC_MASK_LO); /* Slave on Ch2 */ + outb(0x01, PIC_MASK_LO); /* x86 */ + outb(0xf5, PIC_MASK_LO); /* pattern: 11110101 */ + + outb(0x11, PIC_HI); + outb(_ISA_IRQ(8), PIC_MASK_HI); /* IRQ number */ + outb(0x02, PIC_MASK_HI); /* Slave on Ch1 */ + outb(0x01, PIC_MASK_HI); /* x86 */ + outb(0xfa, PIC_MASK_HI); /* pattern: 11111010 */ + + outb(0x0b, PIC_LO); + outb(0x0b, PIC_HI); + + if (inb(PIC_MASK_LO) == 0xf5 && inb(PIC_MASK_HI) == 0xfa) { + outb(0xff, PIC_MASK_LO);/* mask all IRQs */ + outb(0xff, PIC_MASK_HI);/* mask all IRQs */ + isa_irq = irq; + } else + isa_irq = -1; + + if (isa_irq != -1) { + for (irq = _ISA_IRQ(0); irq < _ISA_IRQ(8); irq++) { + irq_desc[irq].valid = 1; + irq_desc[irq].probe_ok = 1; + irq_desc[irq].mask_ack = isa_mask_ack_pic_lo_irq; + irq_desc[irq].mask = isa_mask_pic_lo_irq; + irq_desc[irq].unmask = isa_unmask_pic_lo_irq; + } + + for (irq = _ISA_IRQ(8); irq < _ISA_IRQ(16); irq++) { + irq_desc[irq].valid = 1; + irq_desc[irq].probe_ok = 1; + irq_desc[irq].mask_ack = isa_mask_ack_pic_hi_irq; + irq_desc[irq].mask = isa_mask_pic_hi_irq; + irq_desc[irq].unmask = isa_unmask_pic_hi_irq; + } + + request_resource(&ioport_resource, &pic1_resource); + request_resource(&ioport_resource, &pic2_resource); + setup_arm_irq(IRQ_ISA_CASCADE, &irq_cascade); + setup_arm_irq(isa_irq, &irq_cascade); + + /* + * On the NetWinder, don't automatically + * enable ISA IRQ11 when it is requested. + * There appears to be a missing pull-up + * resistor on this line. + */ + if (machine_is_netwinder()) + irq_desc[_ISA_IRQ(11)].noautoenable = 1; + } +} + +void __init footbridge_init_irq(void) +{ + __fb_init_irq(); + + if (!footbridge_cfn_mode()) + return; + + if (machine_is_ebsa285()) + /* The following is dependent on which slot + * you plug the Southbridge card into. We + * currently assume that you plug it into + * the right-hand most slot. + */ + isa_init_irq(IRQ_PCI); + + if (machine_is_cats()) + isa_init_irq(IRQ_IN2); + + if (machine_is_netwinder()) + isa_init_irq(IRQ_IN3); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-footbridge/mm.c linux.ac/arch/arm/mach-footbridge/mm.c --- linux.vanilla/arch/arm/mach-footbridge/mm.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-footbridge/mm.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,117 @@ +/* + * linux/arch/arm/mach-footbridge/mm.c + * + * Copyright (C) 1998-2000 Russell King, Dave Gilbert. + * + * 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. + * + * Extra MM routines for the EBSA285 architecture + */ +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/init.h> + +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/io.h> +#include <asm/hardware/dec21285.h> +#include <asm/mach-types.h> + +#include <asm/mach/map.h> + +/* + * Common mapping for all systems. Note that the outbound write flush is + * commented out since there is a "No Fix" problem with it. Not mapping + * it means that we have extra bullet protection on our feet. + */ +static struct map_desc fb_common_io_desc[] __initdata = { + { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC +}; + +/* + * The mapping when the footbridge is in host mode. We don't map any of + * this when we are in add-in mode. + */ +static struct map_desc ebsa285_host_io_desc[] __initdata = { +#if defined(CONFIG_ARCH_FOOTBRIDGE) && defined(CONFIG_FOOTBRIDGE_HOST) + { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG, PCICFG0_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG, PCICFG1_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { PCIIACK_BASE, DC21285_PCI_IACK, PCIIACK_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, +#endif + LAST_DESC +}; + +/* + * The CO-ebsa285 mapping. + */ +static struct map_desc co285_io_desc[] __initdata = { +#ifdef CONFIG_ARCH_CO285 + { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, +#endif + LAST_DESC +}; + +void __init footbridge_map_io(void) +{ + struct map_desc *desc = NULL; + + /* + * Set up the common mapping first; we need this to + * determine whether we're in host mode or not. + */ + iotable_init(fb_common_io_desc); + + /* + * Now, work out what we've got to map in addition on this + * platform. + */ + if (machine_is_co285()) + desc = co285_io_desc; + else if (footbridge_cfn_mode()) + desc = ebsa285_host_io_desc; + + if (desc) + iotable_init(desc); +} + +#ifdef CONFIG_FOOTBRIDGE_ADDIN + +/* + * These two functions convert virtual addresses to PCI addresses and PCI + * addresses to virtual addresses. Note that it is only legal to use these + * on memory obtained via get_free_page or kmalloc. + */ +unsigned long __virt_to_bus(unsigned long res) +{ +#ifdef CONFIG_DEBUG_ERRORS + if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) { + printk("__virt_to_bus: invalid virtual address 0x%08lx\n", res); + __backtrace(); + } +#endif + return (res - PAGE_OFFSET) + (*CSR_PCISDRAMBASE & 0xfffffff0); +} + +unsigned long __bus_to_virt(unsigned long res) +{ + res -= (*CSR_PCISDRAMBASE & 0xfffffff0); + res += PAGE_OFFSET; + +#ifdef CONFIG_DEBUG_ERRORS + if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) { + printk("__bus_to_virt: invalid virtual address 0x%08lx\n", res); + __backtrace(); + } +#endif + return res; +} + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-sa1100/Makefile linux.ac/arch/arm/mach-sa1100/Makefile --- linux.vanilla/arch/arm/mach-sa1100/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/mach-sa1100/Makefile Sat Apr 14 01:16:46 2001 @@ -11,13 +11,14 @@ # Object file lists. -obj-y := arch.o hw.o #dma.o mm.o +obj-y := arch.o hw.o dma-sa1100.o # mm.o obj-m := obj-n := obj- := -export-objs := hw.o leds.o +export-objs := dma-sa1100.o dma-sa1111.o hw.o leds.o obj-$(CONFIG_LEDS) += leds.o +obj-$(CONFIG_SA1111) += dma-sa1111.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-sa1100/arch.c linux.ac/arch/arm/mach-sa1100/arch.c --- linux.vanilla/arch/arm/mach-sa1100/arch.c Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/arm/mach-sa1100/arch.c Sat Apr 14 01:16:46 2001 @@ -19,8 +19,23 @@ #include <asm/mach/arch.h> -extern void setup_initrd(unsigned int start, unsigned int size); -extern void setup_ramdisk(int doload, int prompt, int start, unsigned int rd_sz); +extern void genarch_init_irq(void); + + +static void sa1100_power_off(void) +{ + mdelay(100); + cli(); + /* disable internal oscillator, float CS lines */ + PCFR = (PCFR_OPDE | PCFR_FP | PCFR_FS); + /* set lowest clock */ + PPCR = 0; + /* set all GPIOs to input mode */ + GPDR = 0; + /* enter sleep mode */ + PMCR = PMCR_SF; +} + static void victor_power_off(void) { @@ -47,10 +62,13 @@ mi->bank[__nr].start = (__start), \ mi->bank[__nr].size = (__size), \ mi->bank[__nr].node = (((unsigned)(__start) - PHYS_OFFSET) >> 27) + static void __init fixup_sa1100(struct machine_desc *desc, struct param_struct *params, char **cmdline, struct meminfo *mi) { + pm_power_off = sa1100_power_off; + if (machine_is_assabet()) { /* * On Assabet, we must probe for the Neponset board *before* @@ -82,6 +100,16 @@ setup_initrd( 0xc0800000, 3*1024*1024 ); } + else if (machine_is_pangolin()) { + SET_BANK( 0, 0xc0000000, 32*1024*1024 ); + SET_BANK( 1, 0xc8000000, 32*1024*1024 ); + mi->nr_banks = 2; + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk( 1, 0, 0, 16384 ); + setup_initrd( 0xc0800000, 9*1024*1024 ); + } + else if (machine_is_brutus()) { SET_BANK( 0, 0xc0000000, 4*1024*1024 ); SET_BANK( 1, 0xc8000000, 4*1024*1024 ); @@ -133,7 +161,7 @@ setup_initrd(0xc0400000, 4*1024*1024); } - else if (machine_is_thinclient() || machine_is_graphicsclient()) { + else if (machine_is_graphicsclient()) { SET_BANK( 0, 0xc0000000, 16*1024*1024 ); mi->nr_banks = 1; @@ -154,15 +182,6 @@ if( *((char*)0xc0000100) ) *cmdline = ((char *)0xc0000100); } - else if (machine_is_tifon()) { - SET_BANK( 0, 0xc0000000, 16*1024*1024 ); - SET_BANK( 1, 0xc8000000, 16*1024*1024 ); - mi->nr_banks = 2; - - ROOT_DEV = MKDEV(UNNAMED_MAJOR, 0); - setup_ramdisk(1, 0, 0, 4096); - setup_initrd( 0xd0000000 + 0x1100004, 0x140000 ); - } else if (machine_is_victor()) { SET_BANK( 0, 0xc0000000, 4*1024*1024 ); @@ -180,6 +199,16 @@ pm_power_off = victor_power_off; } + else if (machine_is_sherman()) { + SET_BANK( 0, 0xc0000000, 64*1024*1024 ); + SET_BANK( 1, 0xc8000000, 64*1024*1024 ); + mi->nr_banks = 2; + + ROOT_DEV = MKDEV( 60, 2 ); + setup_ramdisk( 1, 0, 0, 8192 ); +// setup_initrd( 0xc0400000, 8*1024*1024 ); +} + else if (machine_is_xp860()) { SET_BANK( 0, 0xc0000000, 32*1024*1024 ); mi->nr_banks = 1; @@ -193,6 +222,15 @@ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_PANGOLIN +MACHINE_START(PANGOLIN, "Dialogue-Pangolin") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) + MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_BITSY @@ -201,6 +239,7 @@ BOOT_PARAMS(0xc0000100) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_BRUTUS @@ -208,6 +247,7 @@ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_CERF @@ -216,6 +256,7 @@ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_EMPEG @@ -223,6 +264,7 @@ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_GRAPHICSCLIENT @@ -230,14 +272,16 @@ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_ITSY MACHINE_START(ITSY, "Compaq Itsy") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) - BOOT_PARAMS(0xc0000100 + BOOT_PARAMS(0xc0000100) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_LART @@ -245,6 +289,7 @@ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_NANOENGINE @@ -252,6 +297,7 @@ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_PLEB @@ -259,20 +305,7 @@ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) -MACHINE_END -#endif -#ifdef CONFIG_SA1100_THINCLIENT -MACHINE_START(THINCLIENT, "ADS ThinClient") - BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) - FIXUP(fixup_sa1100) - MAPIO(sa1100_map_io) -MACHINE_END -#endif -#ifdef CONFIG_SA1100_TIFON -MACHINE_START(TIFON, "Tifon") - BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) - FIXUP(fixup_sa1100) - MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_VICTOR @@ -280,6 +313,15 @@ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_SHERMAN +MACHINE_START(SHERMAN, "Blazie Engineering Sherman") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) + MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_XP860 @@ -287,5 +329,6 @@ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-sa1100/dma-sa1100.c linux.ac/arch/arm/mach-sa1100/dma-sa1100.c --- linux.vanilla/arch/arm/mach-sa1100/dma-sa1100.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-sa1100/dma-sa1100.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,538 @@ +/* + * arch/arm/kernel/dma-sa1100.c + * + * Support functions for the SA11x0 internal DMA channels. + * (see also Documentation/arm/SA1100/DMA) + * + * Copyright (C) 2000 Nicolas Pitre + * + * 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 <linux/module.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/malloc.h> +#include <linux/errno.h> + +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/dma.h> +#include <asm/mach/dma.h> + + +#undef DEBUG +#ifdef DEBUG +#define DPRINTK( s, arg... ) printk( "dma<%s>: " s, dma->device_id , ##arg ) +#else +#define DPRINTK( x... ) +#endif + + +/* + * Maximum physical DMA buffer size + */ +#define MAX_DMA_SIZE 0x1fff +#define MAX_DMA_ORDER 12 + + +/* + * DMA control register structure + */ +typedef struct { + volatile u_long DDAR; + volatile u_long SetDCSR; + volatile u_long ClrDCSR; + volatile u_long RdDCSR; + volatile dma_addr_t DBSA; + volatile u_long DBTA; + volatile dma_addr_t DBSB; + volatile u_long DBTB; +} dma_regs_t; + + +/* + * DMA buffer structure + */ +struct dma_buf_s { + int size; /* buffer size */ + dma_addr_t dma_start; /* starting DMA address */ + dma_addr_t dma_ptr; /* current DMA pointer position */ + int ref; /* number of DMA references */ + void *id; /* to identify buffer from outside */ + struct dma_buf_s *next; /* next buffer to process */ +}; + + +#include "dma.h" + +sa1100_dma_t dma_chan[MAX_SA1100_DMA_CHANNELS]; + + +/* + * DMA processing... + */ + +static inline int start_sa1100_dma(sa1100_dma_t * dma, dma_addr_t dma_ptr, int size) +{ + dma_regs_t *regs = dma->regs; + int status; + int use_bufa; + + status = regs->RdDCSR; + + /* If both DMA buffers are started, there's nothing else we can do. */ + if ((status & DCSR_STRTA) && (status & DCSR_STRTB)) { + DPRINTK("start: st %#x busy\n", status); + return -EBUSY; + } + + use_bufa = (((status & DCSR_BIU) && (status & DCSR_STRTB)) || + (!(status & DCSR_BIU) && !(status & DCSR_STRTA))); + if (use_bufa) { + regs->ClrDCSR = DCSR_DONEA | DCSR_STRTA; + regs->DBSA = dma_ptr; + regs->DBTA = size; + regs->SetDCSR = DCSR_STRTA | DCSR_IE | DCSR_RUN; + DPRINTK("start a=%#x s=%d on A\n", dma_ptr, size); + } else { + regs->ClrDCSR = DCSR_DONEB | DCSR_STRTB; + regs->DBSB = dma_ptr; + regs->DBTB = size; + regs->SetDCSR = DCSR_STRTB | DCSR_IE | DCSR_RUN; + DPRINTK("start a=%#x s=%d on B\n", dma_ptr, size); + } + + return 0; +} + + +static int start_dma(sa1100_dma_t *dma, dma_addr_t dma_ptr, int size) +{ + if (channel_is_sa1111_sac(dma - dma_chan)) + return start_sa1111_sac_dma(dma, dma_ptr, size); + return start_sa1100_dma(dma, dma_ptr, size); +} + + +/* This must be called with IRQ disabled */ +static void process_dma(sa1100_dma_t * dma) +{ + dma_buf_t *buf; + int chunksize; + + for (;;) { + buf = dma->tail; + + if (!buf) { + /* no more data available */ + DPRINTK("process: no more buf (dma %s)\n", + dma->curr ? "active" : "inactive"); + /* + * Some devices may require DMA still sending data + * at any time for clock reference, etc. + * Note: if there is still a data buffer being + * processed then the ref count is negative. This + * allows for the DMA termination to be accounted in + * the proper order. + */ + if (dma->spin_size && dma->spin_ref >= 0) { + chunksize = dma->spin_size; + if (chunksize > MAX_DMA_SIZE) + chunksize = (1 << MAX_DMA_ORDER); + while (start_dma(dma, dma->spin_addr, chunksize) == 0) + dma->spin_ref++; + if (dma->curr != NULL) + dma->spin_ref = -dma->spin_ref; + } + break; + } + + /* + * Let's try to start DMA on the current buffer. + * If DMA is busy then we break here. + */ + chunksize = buf->size; + if (chunksize > MAX_DMA_SIZE) + chunksize = (1 << MAX_DMA_ORDER); + DPRINTK("process: b=%#x s=%d\n", (int) buf->id, buf->size); + if (start_dma(dma, buf->dma_ptr, chunksize) != 0) + break; + dma->active = 1; + if (!dma->curr) + dma->curr = buf; + buf->ref++; + buf->dma_ptr += chunksize; + buf->size -= chunksize; + if (buf->size == 0) { + /* current buffer is done: move tail to the next one */ + dma->tail = buf->next; + DPRINTK("process: next b=%#x\n", (int) dma->tail); + } + } +} + + +/* This must be called with IRQ disabled */ +void sa1100_dma_done (sa1100_dma_t *dma) +{ + dma_buf_t *buf = dma->curr; + + if (dma->spin_ref > 0) { + dma->spin_ref--; + } else if (buf) { + buf->ref--; + if (buf->ref == 0 && buf->size == 0) { + /* + * Current buffer is done. + * Move current reference to the next one and send + * the processed buffer to the callback function, + * then discard it. + */ + DPRINTK("IRQ: buf done\n"); + dma->curr = buf->next; + if (dma->curr == NULL) + dma->spin_ref = -dma->spin_ref; + if (dma->head == buf) + dma->head = NULL; + buf->size = buf->dma_ptr - buf->dma_start; + if (dma->callback) + dma->callback(buf->id, buf->size); + kfree(buf); + } + } + + process_dma(dma); +} + + +static void dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + sa1100_dma_t *dma = (sa1100_dma_t *) dev_id; + int status = dma->regs->RdDCSR; + + DPRINTK("IRQ: b=%#x st=%#x\n", (int) dma->curr->id, status); + + dma->regs->ClrDCSR = DCSR_ERROR | DCSR_DONEA | DCSR_DONEB; + if (!(status & (DCSR_DONEA | DCSR_DONEB))) + return; + + sa1100_dma_done (dma); +} + + +/* + * DMA interface functions + */ + +/* + * Get dma list + * for /proc/dma + */ +int sa1100_get_dma_list(char *buf) +{ + int i, len = 0; + + for (i = 0; i < MAX_SA1100_DMA_CHANNELS; i++) { + if (dma_chan[i].lock) + len += sprintf(buf + len, "%2d: %s\n", + i, dma_chan[i].device_id); + } + return len; +} + +int sa1100_request_dma(dmach_t * channel, const char *device_id) +{ + sa1100_dma_t *dma = NULL; + dma_regs_t *regs; + int ch, err; + + *channel = -1; /* to be sure we catch the freeing of a misregistered channel */ + + for (ch = 0; ch < SA1100_DMA_CHANNELS; ch++) { + dma = &dma_chan[ch]; + if (xchg(&dma->lock, 1) == 0) + break; + } + if (ch >= SA1100_DMA_CHANNELS) { + printk(KERN_ERR "%s: no free DMA channel available\n", + device_id); + return -EBUSY; + } + + err = request_irq(dma->irq, dma_irq_handler, SA_INTERRUPT, + device_id, (void *) dma); + if (err) { + printk(KERN_ERR + "%s: unable to request IRQ %d for DMA channel %d\n", + device_id, dma->irq, ch); + dma->lock = 0; + return err; + } + + *channel = ch; + dma->device_id = device_id; + dma->callback = NULL; + dma->spin_size = 0; + + regs = dma->regs; + regs->ClrDCSR = + (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB | + DCSR_IE | DCSR_ERROR | DCSR_RUN); + regs->DDAR = 0; + + DPRINTK("requested\n"); + return 0; +} + + +int sa1100_dma_set_callback(dmach_t channel, dma_callback_t cb) +{ + sa1100_dma_t *dma = &dma_chan[channel]; + + dma->callback = cb; + DPRINTK("cb = %p\n", cb); + return 0; +} + + +int sa1100_dma_set_device(dmach_t channel, dma_device_t device) +{ + sa1100_dma_t *dma = &dma_chan[channel]; + dma_regs_t *regs = dma->regs; + + if (dma->ready) + return -EINVAL; + + regs->ClrDCSR = DCSR_STRTA | DCSR_STRTB | DCSR_IE | DCSR_RUN; + regs->DDAR = device; + DPRINTK("DDAR = %#x\n", device); + dma->ready = 1; + return 0; +} + + +int sa1100_dma_set_spin(dmach_t channel, dma_addr_t addr, int size) +{ + sa1100_dma_t *dma = &dma_chan[channel]; + int flags; + + if (channel >= SA1100_DMA_CHANNELS) + return -EINVAL; + + DPRINTK("set spin %d at %#x\n", size, addr); + local_irq_save(flags); + dma->spin_addr = addr; + dma->spin_size = size; + if (size) + process_dma(dma); + local_irq_restore(flags); + return 0; +} + + +int sa1100_dma_queue_buffer(dmach_t channel, void *buf_id, + dma_addr_t data, int size) +{ + sa1100_dma_t *dma; + dma_buf_t *buf; + int flags; + + dma = &dma_chan[channel]; + if (!dma->ready) + return -EINVAL; + + buf = kmalloc(sizeof(*buf), GFP_ATOMIC); + if (!buf) + return -ENOMEM; + + buf->next = NULL; + buf->ref = 0; + buf->dma_ptr = buf->dma_start = data; + buf->size = size; + buf->id = buf_id; + DPRINTK("queueing b=%#x a=%#x s=%d\n", (int) buf_id, data, size); + + local_irq_save(flags); + if (dma->head) + dma->head->next = buf; + dma->head = buf; + if (!dma->tail) + dma->tail = buf; + process_dma(dma); + local_irq_restore(flags); + + return 0; +} + + +int sa1100_dma_get_current(dmach_t channel, void **buf_id, dma_addr_t *addr) +{ + sa1100_dma_t *dma = &dma_chan[channel]; + dma_regs_t *regs = dma->regs; + int flags, ret; + + if (channel_is_sa1111_sac(channel)) + return sa1111_dma_get_current(channel, buf_id, addr); + + local_irq_save(flags); + if (dma->curr && dma->spin_ref <= 0) { + dma_buf_t *buf = dma->curr; + int status, using_bufa; + + status = regs->RdDCSR; + /* + * If we got here, that's because there is, or recently was, a + * buffer being processed. We must determine whether buffer + * A or B is active. Two possibilities: either we are + * in the middle of a buffer, or the DMA controller just + * switched to the next toggle but the interrupt hasn't been + * serviced yet. The former case is straight forward. In + * the later case, we'll do like if DMA is just at the end + * of the previous toggle since all registers haven't been + * reset yet. This goes around the edge case and since we're + * always a little behind anyways it shouldn't make a big + * difference. If DMA has been stopped prior calling this + * then the position is always exact. + */ + using_bufa = ((!(status & DCSR_BIU) && (status & DCSR_STRTA)) || + ( (status & DCSR_BIU) && !(status & DCSR_STRTB))); + if (buf_id) + *buf_id = buf->id; + *addr = (using_bufa) ? regs->DBSA : regs->DBSB; + /* + * Clamp funky pointers sometimes returned by the hardware + * on completed DMA transfers + */ + if (*addr < buf->dma_start || + *addr > buf->dma_ptr) + *addr = buf->dma_ptr; + DPRINTK("curr_pos: b=%#x a=%#x\n", (int)dma->curr->id, *addr); + ret = 0; + } else { + if (buf_id) + *buf_id = NULL; + *addr = 0; + DPRINTK("curr_pos: spinning\n"); + ret = -ENXIO; + } + local_irq_restore(flags); + return ret; +} + + +int sa1100_dma_stop(dmach_t channel) +{ + sa1100_dma_t *dma = &dma_chan[channel]; + dma_regs_t *regs = dma->regs; + + if (channel_is_sa1111_sac(channel)) + return sa1111_dma_stop(channel); + + regs->ClrDCSR = DCSR_RUN | DCSR_IE; + return 0; +} + + +int sa1100_dma_resume(dmach_t channel) +{ + sa1100_dma_t *dma = &dma_chan[channel]; + dma_regs_t *regs = dma->regs; + + if (channel_is_sa1111_sac(channel)) + return sa1111_dma_resume(channel); + + regs->SetDCSR = DCSR_RUN | DCSR_IE; + return 0; +} + + +int sa1100_dma_flush_all(dmach_t channel) +{ + sa1100_dma_t *dma; + dma_buf_t *buf, *next_buf; + int flags; + + dma = &dma_chan[channel]; + local_irq_save(flags); + if (channel_is_sa1111_sac(channel)) + sa1111_reset_sac_dma(channel); + else + dma->regs->ClrDCSR = DCSR_STRTA|DCSR_STRTB|DCSR_RUN|DCSR_IE; + buf = dma->curr; + if (!buf) + buf = dma->tail; + dma->head = dma->tail = dma->curr = NULL; + dma->active = 0; + dma->spin_ref = 0; + if (dma->spin_size) + process_dma(dma); + local_irq_restore(flags); + while (buf) { + next_buf = buf->next; + kfree(buf); + buf = next_buf; + } + DPRINTK("flushed\n"); + return 0; +} + + +void sa1100_free_dma(dmach_t channel) +{ + sa1100_dma_t *dma; + + if ((unsigned) channel >= MAX_SA1100_DMA_CHANNELS) + return; + + dma = &dma_chan[channel]; + if (!dma->lock) { + printk(KERN_ERR "Trying to free free DMA%d\n", channel); + return; + } + + sa1100_dma_set_spin(channel, 0, 0); + sa1100_dma_flush_all(channel); + dma->ready = 0; + + if (channel_is_sa1111_sac(channel)) { + sa1111_cleanup_sac_dma(channel); + } else { + free_irq(IRQ_DMA0 + channel, (void *) dma); + } + dma->lock = 0; + + DPRINTK("freed\n"); +} + + +EXPORT_SYMBOL(sa1100_request_dma); +EXPORT_SYMBOL(sa1100_dma_set_callback); +EXPORT_SYMBOL(sa1100_dma_set_device); +EXPORT_SYMBOL(sa1100_dma_set_spin); +EXPORT_SYMBOL(sa1100_dma_queue_buffer); +EXPORT_SYMBOL(sa1100_dma_get_current); +EXPORT_SYMBOL(sa1100_dma_stop); +EXPORT_SYMBOL(sa1100_dma_resume); +EXPORT_SYMBOL(sa1100_dma_flush_all); +EXPORT_SYMBOL(sa1100_free_dma); + + +static int __init sa1100_init_dma(void) +{ + int channel; + for (channel = 0; channel < SA1100_DMA_CHANNELS; channel++) { + dma_chan[channel].regs = + (dma_regs_t *) io_p2v(_DDAR(channel)); + dma_chan[channel].irq = IRQ_DMA0 + channel; + } + return 0; +} + +__initcall(sa1100_init_dma); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-sa1100/dma-sa1111.c linux.ac/arch/arm/mach-sa1100/dma-sa1111.c --- linux.vanilla/arch/arm/mach-sa1100/dma-sa1111.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-sa1100/dma-sa1111.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,346 @@ +/* + * linux/arch/arm/mach-sa1100/dma-sa1111.c + * + * Copyright (C) 2000 John Dorsey + * + * 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. + * + * 4 September 2000 - created. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/errno.h> + +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/dma.h> + + +// #define DEBUG +#ifdef DEBUG +#define DPRINTK( s, arg... ) printk( "dma<%s>: " s, dma->device_id , ##arg ) +#else +#define DPRINTK( x... ) +#endif + + +/* + * Control register structure for the SA1111 SAC DMA + */ + +typedef struct { + volatile u_long SAD_CS; + volatile dma_addr_t SAD_SA; + volatile u_long SAD_CA; + volatile dma_addr_t SAD_SB; + volatile u_long SAD_CB; +} dma_regs_t; + +#include "dma.h" + + +void sa1111_reset_sac_dma(dmach_t channel) +{ + sa1100_dma_t *dma = &dma_chan[channel]; + dma->regs->SAD_CS = 0; + mdelay(1); + dma->dma_a = dma->dma_b = 0; +} + + +int start_sa1111_sac_dma(sa1100_dma_t *dma, dma_addr_t dma_ptr, size_t size) +{ + dma_regs_t *sac_regs = dma->regs; + + DPRINTK(" SAC DMA %cCS %02x at %08x (%d)\n", + (sac_regs==&SADTCS)?'T':'R', sac_regs->SAD_CS, dma_ptr, size); + + /* The minimum transfer length requirement has not yet been + * verified: + */ + if( size < SA1111_SAC_DMA_MIN_XFER ) + printk(KERN_WARNING "Warning: SAC xfers below %u bytes may be buggy!" + " (%u bytes)\n", SA1111_SAC_DMA_MIN_XFER, size); + + if( dma->dma_a && dma->dma_b ){ + DPRINTK(" neither engine available! (A %d, B %d)\n", + dma->dma_a, dma->dma_b); + return -1; + } + + if( sa1111_check_dma_bug(dma_ptr) ) + printk(KERN_WARNING "Warning: DMA address %08x is buggy!\n", + dma_ptr); + + if( (dma->last_dma || dma->dma_b) && dma->dma_a == 0 ){ + if( sac_regs->SAD_CS & SAD_CS_DBDB ){ + DPRINTK(" awaiting \"done B\" interrupt, not starting\n"); + return -1; + } + sac_regs->SAD_SA = SA1111_DMA_ADDR((u_int)dma_ptr); + sac_regs->SAD_CA = size; + sac_regs->SAD_CS = SAD_CS_DSTA | SAD_CS_DEN; + ++dma->dma_a; + DPRINTK(" with A [%02lx %08lx %04lx]\n", sac_regs->SAD_CS, + sac_regs->SAD_SA, sac_regs->SAD_CA); + } else { + if( sac_regs->SAD_CS & SAD_CS_DBDA ){ + DPRINTK(" awaiting \"done A\" interrupt, not starting\n"); + return -1; + } + sac_regs->SAD_SB = SA1111_DMA_ADDR((u_int)dma_ptr); + sac_regs->SAD_CB = size; + sac_regs->SAD_CS = SAD_CS_DSTB | SAD_CS_DEN; + ++dma->dma_b; + DPRINTK(" with B [%02lx %08lx %04lx]\n", sac_regs->SAD_CS, + sac_regs->SAD_SB, sac_regs->SAD_CB); + } + + /* Additional delay to avoid DMA engine lockup during record: */ + if( sac_regs == (dma_regs_t*)&SADRCS ) + mdelay(1); /* NP : wouuuh! ugly... */ + + return 0; +} + + +static void sa1111_sac_dma_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + sa1100_dma_t *dma = (sa1100_dma_t *) dev_id; + + DPRINTK("irq %d, last DMA serviced was %c, CS %02x\n", irq, + dma->last_dma?'B':'A', dma->regs->SAD_CS); + + /* Occasionally, one of the DMA engines (A or B) will + * lock up. We try to deal with this by quietly kicking + * the control register for the afflicted transfer + * direction. + * + * Note for the debugging-inclined: we currently aren't + * properly flushing the DMA engines during channel + * shutdown. A slight hiccup at the beginning of playback + * after a channel has been stopped can be heard as + * evidence of this. Programmatically, this shows up + * as either a locked engine, or a spurious interrupt. -jd + */ + + if(irq==AUDXMTDMADONEA || irq==AUDRCVDMADONEA){ + + if(dma->last_dma == 0){ + DPRINTK("DMA B has locked up!\n"); + dma->regs->SAD_CS = 0; + mdelay(1); + dma->dma_a = dma->dma_b = 0; + } else { + if(dma->dma_a == 0) + DPRINTK("spurious SAC IRQ %d\n", irq); + else { + --dma->dma_a; + + /* Servicing the SAC DMA engines too quickly + * after they issue a DONE interrupt causes + * them to lock up. + */ + if(irq==AUDRCVDMADONEA || irq==AUDRCVDMADONEB) + mdelay(1); + } + } + + dma->regs->SAD_CS = SAD_CS_DBDA | SAD_CS_DEN; /* w1c */ + dma->last_dma = 0; + + } else { + + if(dma->last_dma == 1){ + DPRINTK("DMA A has locked up!\n"); + dma->regs->SAD_CS = 0; + mdelay(1); + dma->dma_a = dma->dma_b = 0; + } else { + if(dma->dma_b == 0) + DPRINTK("spurious SAC IRQ %d\n", irq); + else { + --dma->dma_b; + + /* See lock-up note above. */ + if(irq==AUDRCVDMADONEA || irq==AUDRCVDMADONEB) + mdelay(1); + } + } + + dma->regs->SAD_CS = SAD_CS_DBDB | SAD_CS_DEN; /* w1c */ + dma->last_dma = 1; + + } + + /* NP: maybe this shouldn't be called in all cases? */ + sa1100_dma_done (dma); +} + + +int sa1111_sac_request_dma(dmach_t *channel, const char *device_id, + unsigned int direction) +{ + sa1100_dma_t *dma = NULL; + int ch, irq, err; + + *channel = -1; /* to be sure we catch the freeing of a misregistered channel */ + + ch = SA1111_SAC_DMA_BASE + direction; + + if (!channel_is_sa1111_sac(ch)) { + printk(KERN_ERR "%s: invalid SA-1111 SAC DMA channel (%d)\n", + device_id, ch); + return -1; + } + + dma = &dma_chan[ch]; + + if (xchg(&dma->lock, 1) == 1) { + printk(KERN_ERR "%s: SA-1111 SAC DMA channel %d in use\n", + device_id, ch); + return -EBUSY; + } + + irq = AUDXMTDMADONEA + direction; + err = request_irq(irq, sa1111_sac_dma_irq, SA_INTERRUPT, + device_id, (void *) dma); + if (err) { + printk(KERN_ERR + "%s: unable to request IRQ %d for DMA channel %d (A)\n", + device_id, irq, ch); + dma->lock = 0; + return err; + } + + irq = AUDXMTDMADONEB + direction; + err = request_irq(irq, sa1111_sac_dma_irq, SA_INTERRUPT, + device_id, (void *) dma); + if (err) { + printk(KERN_ERR + "%s: unable to request IRQ %d for DMA channel %d (B)\n", + device_id, irq, ch); + dma->lock = 0; + return err; + } + + *channel = ch; + dma->device_id = device_id; + dma->callback = NULL; + dma->spin_size = 0; + dma->ready = 1; + + return 0; +} + + +/* FIXME: need to complete the three following functions */ + +int sa1111_dma_get_current(dmach_t channel, void **buf_id, dma_addr_t *addr) +{ + return -ENOSYS; +} + +int sa1111_dma_stop(dmach_t channel) +{ + return 0; +} + +int sa1111_dma_resume(dmach_t channel) +{ + return 0; +} + + +void sa1111_cleanup_sac_dma(dmach_t channel) +{ + sa1100_dma_t *dma = &dma_chan[channel]; + free_irq(AUDXMTDMADONEA + (channel - SA1111_SAC_DMA_BASE), (void*) dma); + free_irq(AUDXMTDMADONEB + (channel - SA1111_SAC_DMA_BASE), (void*) dma); +} + + +/* According to the "Intel StrongARM SA-1111 Microprocessor Companion + * Chip Specification Update" (June 2000), errata #7, there is a + * significant bug in Serial Audio Controller DMA. If the SAC is + * accessing a region of memory above 1MB relative to the bank base, + * it is important that address bit 10 _NOT_ be asserted. Depending + * on the configuration of the RAM, bit 10 may correspond to one + * of several different (processor-relative) address bits. + * + * This routine only identifies whether or not a given DMA address + * is susceptible to the bug. + */ +int sa1111_check_dma_bug(dma_addr_t addr){ + unsigned int physaddr=SA1111_DMA_ADDR((unsigned int)addr); + + /* Section 4.6 of the "Intel StrongARM SA-1111 Development Module + * User's Guide" mentions that jumpers R51 and R52 control the + * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or + * SDRAM bank 1 on Neponset). The default configuration selects + * Assabet, so any address in bank 1 is necessarily invalid. + */ + if(machine_is_assabet() && addr >= _DRAMBnk1) + return -1; + + /* The bug only applies to buffers located more than one megabyte + * above the start of the target bank: + */ + if(physaddr<(1<<20)) + return 0; + + switch(FExtr(SMCR, SMCR_DRAC)){ + case 01: /* 10 row + bank address bits, A<20> must not be set */ + if(physaddr & (1<<20)) + return -1; + break; + case 02: /* 11 row + bank address bits, A<23> must not be set */ + if(physaddr & (1<<23)) + return -1; + break; + case 03: /* 12 row + bank address bits, A<24> must not be set */ + if(physaddr & (1<<24)) + return -1; + break; + case 04: /* 13 row + bank address bits, A<25> must not be set */ + if(physaddr & (1<<25)) + return -1; + break; + case 05: /* 14 row + bank address bits, A<20> must not be set */ + if(physaddr & (1<<20)) + return -1; + break; + case 06: /* 15 row + bank address bits, A<20> must not be set */ + if(physaddr & (1<<20)) + return -1; + break; + default: + printk(KERN_ERR "%s(): invalid SMCR DRAC value 0%o\n", + __FUNCTION__, FExtr(SMCR, SMCR_DRAC)); + return -1; + } + + return 0; +} + + +EXPORT_SYMBOL(sa1111_sac_request_dma); +EXPORT_SYMBOL(sa1111_check_dma_bug); + + +static void __init sa1111_init_sac_dma(void) +{ + int channel = SA1111_SAC_DMA_BASE; + dma_chan[channel++].regs = (dma_regs_t *) &SADTCS; + dma_chan[channel++].regs = (dma_regs_t *) &SADRCS; +} + +__initcall(sa1111_init_sac_dma); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-sa1100/dma.h linux.ac/arch/arm/mach-sa1100/dma.h --- linux.vanilla/arch/arm/mach-sa1100/dma.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-sa1100/dma.h Sat Apr 14 01:16:46 2001 @@ -0,0 +1,56 @@ +/* + * Definitions shared between dma-sa1100.c and dma-sa1111.c + * (C) 2000 Nicolas Pitre <nico@cam.org> + * + * 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. + */ + + +/* + * DMA channel structure. + */ + +typedef struct dma_buf_s dma_buf_t; + +typedef struct { + unsigned int lock; /* Device is allocated */ + const char *device_id; /* Device name */ + dma_buf_t *head; /* where to insert buffers */ + dma_buf_t *tail; /* where to remove buffers */ + dma_buf_t *curr; /* buffer currently DMA'ed */ + int ready; /* 1 if DMA can occur */ + int active; /* 1 if DMA is actually processing data */ + dma_regs_t *regs; /* points to appropriate DMA registers */ + int irq; /* IRQ used by the channel */ + dma_callback_t callback; /* ... to call when buffers are done */ + int spin_size; /* > 0 when DMA should spin when no more buffer */ + dma_addr_t spin_addr; /* DMA address to spin onto */ + int spin_ref; /* number of spinning references */ +#ifdef CONFIG_SA1111 + int dma_a, dma_b, last_dma; /* SA-1111 specific */ +#endif +} sa1100_dma_t; + +extern sa1100_dma_t dma_chan[MAX_SA1100_DMA_CHANNELS]; + + +int start_sa1111_sac_dma(sa1100_dma_t *dma, dma_addr_t dma_ptr, size_t size); +int sa1111_dma_get_current(dmach_t channel, void **buf_id, dma_addr_t *addr); +int sa1111_dma_stop(dmach_t channel); +int sa1111_dma_resume(dmach_t channel); +void sa1111_reset_sac_dma(dmach_t channel); +void sa1111_cleanup_sac_dma(dmach_t channel); + +void sa1100_dma_done (sa1100_dma_t *dma); + + +#ifdef CONFIG_SA1111 +#define channel_is_sa1111_sac(ch) \ + ((ch) >= SA1111_SAC_DMA_BASE && \ + (ch) < SA1111_SAC_DMA_BASE + SA1111_SAC_DMA_CHANNELS) +#else +#define channel_is_sa1111_sac(ch) (0) +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-shark/Makefile linux.ac/arch/arm/mach-shark/Makefile --- linux.vanilla/arch/arm/mach-shark/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/mach-shark/Makefile Sat Apr 14 01:16:46 2001 @@ -18,6 +18,6 @@ export-objs := -#obj-$(CONFIG_LEDS) += leds.o +obj-$(CONFIG_LEDS) += leds.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-shark/arch.c linux.ac/arch/arm/mach-shark/arch.c --- linux.vanilla/arch/arm/mach-shark/arch.c Tue Sep 19 16:31:53 2000 +++ linux.ac/arch/arm/mach-shark/arch.c Sat Apr 14 01:16:46 2001 @@ -18,14 +18,31 @@ #include <asm/mach/arch.h> -extern void setup_initrd(unsigned int start, unsigned int size); -extern void setup_ramdisk(int doload, int prompt, int start, unsigned int rd_sz); -extern void __init footbridge_map_io(void); -extern void __init shark_map_io(void); +static void __init +fixup_shark(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) { + int i; + + mi->nr_banks=0; + for (i=0;i<NR_BANKS;i++) { + if (params->u1.s.pages_in_bank[i] != 0) { + mi->nr_banks++; + mi->bank[i].node = 0; + mi->bank[i].start = params->u1.s.pages_in_bank[i] & 0xffff0000; + mi->bank[i].size = (params->u1.s.pages_in_bank[i] & 0xffff)*PAGE_SIZE; + params->u1.s.pages_in_bank[i] &= 0xffff; + } + } +} + +extern void shark_map_io(void); +extern void genarch_init_irq(void); MACHINE_START(SHARK, "Shark") MAINTAINER("Alexander Schulz") BOOT_MEM(0x08000000, 0x40000000, 0xe0000000) - VIDEO(0x06000000, 0x061fffff) + BOOT_PARAMS(0x08003000) + FIXUP(fixup_shark) MAPIO(shark_map_io) + INITIRQ(genarch_init_irq) MACHINE_END diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-shark/dma.c linux.ac/arch/arm/mach-shark/dma.c --- linux.vanilla/arch/arm/mach-shark/dma.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mach-shark/dma.c Sat Apr 14 01:16:46 2001 @@ -1,7 +1,7 @@ /* * linux/arch/arm/mach-shark/dma.c * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> * * derived from: * arch/arm/kernel/dma-ebsa285.c diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-shark/leds.c linux.ac/arch/arm/mach-shark/leds.c --- linux.vanilla/arch/arm/mach-shark/leds.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-shark/leds.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,163 @@ +/* + * arch/arm/kernel/leds-shark.c + * by Alexander Schulz <aschulz@netwinder.org> + * + * derived from: + * arch/arm/kernel/leds-footbridge.c + * Copyright (C) 1998-1999 Russell King + * + * DIGITAL Shark LED control routines. + * + * The leds use is as follows: + * - Green front - toggles state every 50 timer interrupts + * - Amber front - Unused, this is a dual color led (Amber/Green) + * - Amber back - On if system is not idle + * + * Changelog: + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/ioport.h> + +#include <asm/hardware.h> +#include <asm/leds.h> +#include <asm/io.h> +#include <asm/system.h> + +#define LED_STATE_ENABLED 1 +#define LED_STATE_CLAIMED 2 +static char led_state; +static short hw_led_state; +static short saved_state; + +static spinlock_t leds_lock = SPIN_LOCK_UNLOCKED; + +short sequoia_read(int addr) { + outw(addr,0x24); + return inw(0x26); +} + +void sequoia_write(short value,short addr) { + outw(addr,0x24); + outw(value,0x26); +} + +static void sequoia_leds_event(led_event_t evt) +{ + unsigned long flags; + + spin_lock_irqsave(&leds_lock, flags); + + hw_led_state = sequoia_read(0x09); + + switch (evt) { + case led_start: + hw_led_state |= SEQUOIA_LED_GREEN; + hw_led_state |= SEQUOIA_LED_AMBER; +#ifdef CONFIG_LEDS_CPU + hw_led_state |= SEQUOIA_LED_BACK; +#else + hw_led_state &= ~SEQUOIA_LED_BACK; +#endif + led_state |= LED_STATE_ENABLED; + break; + + case led_stop: + hw_led_state &= ~SEQUOIA_LED_BACK; + hw_led_state |= SEQUOIA_LED_GREEN; + hw_led_state |= SEQUOIA_LED_AMBER; + led_state &= ~LED_STATE_ENABLED; + break; + + case led_claim: + led_state |= LED_STATE_CLAIMED; + saved_state = hw_led_state; + hw_led_state &= ~SEQUOIA_LED_BACK; + hw_led_state |= SEQUOIA_LED_GREEN; + hw_led_state |= SEQUOIA_LED_AMBER; + break; + + case led_release: + led_state &= ~LED_STATE_CLAIMED; + hw_led_state = saved_state; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state ^= SEQUOIA_LED_GREEN; + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~SEQUOIA_LED_BACK; + break; + + case led_idle_end: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= SEQUOIA_LED_BACK; + break; +#endif + + case led_green_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~SEQUOIA_LED_GREEN; + break; + + case led_green_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= SEQUOIA_LED_GREEN; + break; + + case led_amber_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~SEQUOIA_LED_AMBER; + break; + + case led_amber_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= SEQUOIA_LED_AMBER; + break; + + case led_red_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= SEQUOIA_LED_BACK; + break; + + case led_red_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~SEQUOIA_LED_BACK; + break; + + default: + break; + } + + if (led_state & LED_STATE_ENABLED) + sequoia_write(hw_led_state,0x09); + + spin_unlock_irqrestore(&leds_lock, flags); +} + +static int __init leds_init(void) +{ + extern void (*leds_event)(led_event_t); + short temp; + + leds_event = sequoia_leds_event; + + /* Make LEDs independent of power-state */ + request_region(0x24,4,"sequoia"); + temp = sequoia_read(0x09); + temp |= 1<<10; + sequoia_write(temp,0x09); + leds_event(led_start); + return 0; +} + +__initcall(leds_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-shark/mm.c linux.ac/arch/arm/mach-shark/mm.c --- linux.vanilla/arch/arm/mach-shark/mm.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mach-shark/mm.c Sat Apr 14 01:16:46 2001 @@ -1,7 +1,7 @@ /* * linux/arch/arm/mach-shark/mm.c * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> * * 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 @@ -19,8 +19,6 @@ static struct map_desc shark_io_desc[] __initdata = { { IO_BASE , IO_START , IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, - { FB_BASE , FB_START , FB_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, - { FBREG_BASE , FBREG_START , FBREG_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, LAST_DESC }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/Makefile linux.ac/arch/arm/mm/Makefile --- linux.vanilla/arch/arm/mm/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/mm/Makefile Sat Apr 14 01:16:46 2001 @@ -13,13 +13,22 @@ # Object file lists. -obj-y := extable.o fault-common.o fault-$(PROCESSOR).o init.o \ - mm-$(PROCESSOR).o small_page.o +obj-y := init.o obj-m := obj-n := obj- := export-objs := proc-syms.o +cpu32-y := consistent.o fault-armv.o ioremap.o mm-armv.o +cpu32-$(CONFIG_MODULES) += proc-syms.o + +obj-y += extable.o fault-common.o +obj-$(CONFIG_CPU_26) += fault-armo.o mm-armo.o small_page.o +obj-$(CONFIG_CPU_32) += $(cpu32-y) + +obj-$(CONFIG_DISCONTIGMEM) += discontig.o + +# Select the processor-specific files p-$(CONFIG_CPU_26) += proc-arm2,3.o p-$(CONFIG_CPU_ARM610) += proc-arm6,7.o p-$(CONFIG_CPU_ARM710) += proc-arm6,7.o @@ -29,11 +38,6 @@ p-$(CONFIG_CPU_SA110) += proc-sa110.o p-$(CONFIG_CPU_SA1100) += proc-sa110.o -obj-$(CONFIG_CPU_32) += consistent.o ioremap.o -ifeq ($(CONFIG_CPU_32),y) -obj-$(CONFIG_MODULES) += proc-syms.o -endif - # Integrator follows "new style" # Soon, others will do too, and we can get rid of this MMMACH := mm-$(MACHINE).c @@ -46,10 +50,4 @@ include $(TOPDIR)/Rules.make # Special dependencies -proc-arm2,3.o: ../lib/constants.h -proc-arm6,7.o: ../lib/constants.h -proc-arm720.o: ../lib/constants.h -proc-arm920.o: ../lib/constants.h -proc-arm10.o: ../lib/constants.h -proc-sa110.o: ../lib/constants.h - +$(p-y): $(TOPDIR)/include/asm-arm/constants.h diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/consistent.c linux.ac/arch/arm/mm/consistent.c --- linux.vanilla/arch/arm/mm/consistent.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mm/consistent.c Sat Apr 14 01:16:46 2001 @@ -34,9 +34,9 @@ */ void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle) { - int order; - unsigned long page; - void *ret; + struct page *page, *end, *free; + unsigned long order; + void *ret, *virt; if (in_interrupt()) BUG(); @@ -44,37 +44,47 @@ size = PAGE_ALIGN(size); order = get_order(size); - page = __get_free_pages(gfp, order); + page = alloc_pages(gfp, order); if (!page) goto no_page; - ret = __ioremap(virt_to_phys((void *)page), size, 0); - if (ret) { - /* free wasted pages */ - unsigned long end; - - /* - * we need to ensure that there are no - * cachelines in use, or worse dirty in - * this area. - */ - invalidate_dcache_range(page, page + size); - invalidate_dcache_range((unsigned long)ret, (unsigned long)ret + size); - - *dma_handle = __virt_to_bus(page); - - end = page + (PAGE_SIZE << order); - page += size; - while (page < end) { - free_page(page); - page += PAGE_SIZE; - } - return ret; + /* + * We could do with a page_to_phys and page_to_bus here. + */ + virt = page_address(page); + *dma_handle = virt_to_bus(virt); + ret = __ioremap(virt_to_phys(virt), size, 0); + if (!ret) + goto no_remap; + +#if 0 /* ioremap_does_flush_cache_all */ + /* + * we need to ensure that there are no cachelines in use, or + * worse dirty in this area. Really, we don't need to do + * this since __ioremap does a flush_cache_all() anyway. --rmk + */ + invalidate_dcache_range(virt, virt + size); +#endif + + /* + * free wasted pages. We skip the first page since + * we know that it will have count = 1 and won't + * require freeing. + */ + page = virt_to_page(virt); + free = page + (size >> PAGE_SHIFT); + end = page + (1 << order); + + while (++page < end) { + set_page_count(page, 1); + if (page >= free) + __free_page(page); } + return ret; - free_pages(page, order); +no_remap: + __free_pages(page, order); no_page: - BUG(); return NULL; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/fault-armv.c linux.ac/arch/arm/mm/fault-armv.c --- linux.vanilla/arch/arm/mm/fault-armv.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/mm/fault-armv.c Sat Apr 14 01:16:46 2001 @@ -2,7 +2,7 @@ * linux/arch/arm/mm/fault-armv.c * * Copyright (C) 1995 Linus Torvalds - * Modifications for ARM processor (c) 1995-1999 Russell King + * Modifications for ARM processor (c) 1995-2001 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 @@ -29,7 +29,13 @@ extern void die_if_kernel(const char *str, struct pt_regs *regs, int err); extern void show_pte(struct mm_struct *mm, unsigned long addr); -extern int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs); +extern int do_page_fault(unsigned long addr, int error_code, + struct pt_regs *regs); +extern int do_translation_fault(unsigned long addr, int error_code, + struct pt_regs *regs); +extern void do_bad_area(struct task_struct *tsk, struct mm_struct *mm, + unsigned long addr, int error_code, + struct pt_regs *regs); #ifdef CONFIG_ALIGNMENT_TRAP /* @@ -37,12 +43,11 @@ * /proc/sys/debug/alignment, modified and integrated into * Linux 2.1 by Russell King * + * Speed optimisations and better fault handling by Russell King. + * * NOTE!!! This is not portable onto the ARM6/ARM7 processors yet. Also, * it seems to give a severe performance impact (1 abort/ms - NW runs at * ARM6 speeds) with GCC 2.7.2.2 - needs checking with a later GCC/EGCS. - * - * IMHO, I don't think that the trap handler is advantageous on ARM6,7 - * processors (they'll run like an ARM3). We'll see. */ #define CODING_BITS(i) (i & 0x0e000000) @@ -115,91 +120,323 @@ __initcall(alignment_init); #endif /* CONFIG_SYSCTL */ +union offset_union { + unsigned long un; + signed long sn; +}; + +#define TYPE_ERROR 0 +#define TYPE_FAULT 1 +#define TYPE_LDST 2 +#define TYPE_DONE 3 + +#define get8_unaligned_check(val,addr,err) \ + __asm__( \ + "1: ldrb %1, [%2]\n" \ + "2:\n" \ + " .section .fixup,\"ax\"\n" \ + " .align 2\n" \ + "3: mov %0, #1\n" \ + " b 2b\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 3\n" \ + " .long 1b, 3b\n" \ + " .previous\n" \ + : "=r" (err), "=&r" (val), "=r" (addr) \ + : "0" (err), "2" (addr)) + +#define get8t_unaligned_check(val,addr,err) \ + __asm__( \ + "1: ldrbt %1, [%2]\n" \ + "2:\n" \ + " .section .fixup,\"ax\"\n" \ + " .align 2\n" \ + "3: mov %0, #1\n" \ + " b 2b\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 3\n" \ + " .long 1b, 3b\n" \ + " .previous\n" \ + : "=r" (err), "=&r" (val), "=r" (addr) \ + : "0" (err), "2" (addr)) + +#define get16_unaligned_check(val,addr) \ + do { \ + unsigned int err = 0, v, a = addr; \ + get8_unaligned_check(val,a,err); \ + get8_unaligned_check(v,a,err); \ + val |= v << 8; \ + if (err) \ + goto fault; \ + } while (0) + +#define put16_unaligned_check(val,addr) \ + do { \ + unsigned int err = 0, v = val, a = addr; \ + __asm__( \ + "1: strb %1, [%2], #1\n" \ + " mov %1, %1, lsr #8\n" \ + "2: strb %1, [%2]\n" \ + "3:\n" \ + " .section .fixup,\"ax\"\n" \ + " .align 2\n" \ + "4: mov %0, #1\n" \ + " b 3b\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 3\n" \ + " .long 1b, 4b\n" \ + " .long 2b, 4b\n" \ + " .previous\n" \ + : "=r" (err), "=&r" (v), "=&r" (a) \ + : "0" (err), "1" (v), "2" (a)); \ + if (err) \ + goto fault; \ + } while (0) + +#define __put32_unaligned_check(ins,val,addr) \ + do { \ + unsigned int err = 0, v = val, a = addr; \ + __asm__( \ + "1: "ins" %1, [%2], #1\n" \ + " mov %1, %1, lsr #8\n" \ + "2: "ins" %1, [%2], #1\n" \ + " mov %1, %1, lsr #8\n" \ + "3: "ins" %1, [%2], #1\n" \ + " mov %1, %1, lsr #8\n" \ + "4: "ins" %1, [%2]\n" \ + "5:\n" \ + " .section .fixup,\"ax\"\n" \ + " .align 2\n" \ + "6: mov %0, #1\n" \ + " b 5b\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 3\n" \ + " .long 1b, 6b\n" \ + " .long 2b, 6b\n" \ + " .long 3b, 6b\n" \ + " .long 4b, 6b\n" \ + " .previous\n" \ + : "=r" (err), "=&r" (v), "=&r" (a) \ + : "0" (err), "1" (v), "2" (a)); \ + if (err) \ + goto fault; \ + } while (0) + +#define get32_unaligned_check(val,addr) \ + do { \ + unsigned int err = 0, v, a = addr; \ + get8_unaligned_check(val,a,err); \ + get8_unaligned_check(v,a,err); \ + val |= v << 8; \ + get8_unaligned_check(v,a,err); \ + val |= v << 16; \ + get8_unaligned_check(v,a,err); \ + val |= v << 24; \ + if (err) \ + goto fault; \ + } while (0) + +#define put32_unaligned_check(val,addr) \ + __put32_unaligned_check("strb", val, addr) + +#define get32t_unaligned_check(val,addr) \ + do { \ + unsigned int err = 0, v, a = addr; \ + get8t_unaligned_check(val,a,err); \ + get8t_unaligned_check(v,a,err); \ + val |= v << 8; \ + get8t_unaligned_check(v,a,err); \ + val |= v << 16; \ + get8t_unaligned_check(v,a,err); \ + val |= v << 24; \ + if (err) \ + goto fault; \ + } while (0) + +#define put32t_unaligned_check(val,addr) \ + __put32_unaligned_check("strbt", val, addr) + +static void +do_alignment_finish_ldst(unsigned long addr, unsigned long instr, struct pt_regs *regs, union offset_union offset) +{ + if (!LDST_U_BIT(instr)) + offset.un = -offset.un; + + if (!LDST_P_BIT(instr)) + addr += offset.un; + + if (!LDST_P_BIT(instr) || LDST_W_BIT(instr)) + regs->uregs[RN_BITS(instr)] = addr; +} + static int -do_alignment(unsigned long addr, int error_code, struct pt_regs *regs) +do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *regs) { - unsigned int instr, rd, rn, correction, nr_regs, regbits; - unsigned long eaddr; - union { unsigned long un; signed long sn; } offset; + unsigned int rd = RD_BITS(instr); - if (user_mode(regs)) { - set_cr(cr_no_alignment); - ai_user += 1; - return 0; - } + if ((instr & 0x01f00ff0) == 0x01000090) + goto swp; - ai_sys += 1; + if ((instr & 0x90) != 0x90 || (instr & 0x60) == 0) + goto bad; + + ai_half += 1; + + if (LDST_L_BIT(instr)) { + unsigned long val; + get16_unaligned_check(val, addr); + + /* signed half-word? */ + if (instr & 0x40) + val = (signed long)((signed short) val); + + regs->uregs[rd] = val; + } else + put16_unaligned_check(regs->uregs[rd], addr); + + return TYPE_LDST; + +swp: + printk(KERN_ERR "Alignment trap: not handling swp instruction\n"); +bad: + return TYPE_ERROR; + +fault: + return TYPE_FAULT; +} + +static int +do_alignment_ldrstr(unsigned long addr, unsigned long instr, struct pt_regs *regs) +{ + unsigned int rd = RD_BITS(instr); + + ai_word += 1; + + if (!LDST_P_BIT(instr) && LDST_W_BIT(instr)) + goto trans; + + if (LDST_L_BIT(instr)) + get32_unaligned_check(regs->uregs[rd], addr); + else + put32_unaligned_check(regs->uregs[rd], addr); + return TYPE_LDST; + +trans: + if (LDST_L_BIT(instr)) + get32t_unaligned_check(regs->uregs[rd], addr); + else + put32t_unaligned_check(regs->uregs[rd], addr); + return TYPE_LDST; + +fault: + return TYPE_FAULT; +} + +static int +do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *regs) +{ + unsigned int rd, rn, correction, nr_regs, regbits; + unsigned long eaddr; - instr = *(unsigned long *)instruction_pointer(regs); correction = 4; /* sometimes 8 on ARMv3 */ - regs->ARM_pc += correction + 4; + regs->ARM_pc += correction; rd = RD_BITS(instr); rn = RN_BITS(instr); eaddr = regs->uregs[rn]; - switch(CODING_BITS(instr)) { - case 0x00000000: - if ((instr & 0x0ff00ff0) == 0x01000090) { - ai_skipped += 1; - printk(KERN_ERR "Unaligned trap: not handling swp instruction\n"); - return 1; - } + if (LDM_S_BIT(instr)) + goto bad; - if (((instr & 0x0e000090) == 0x00000090) && (instr & 0x60) != 0) { - ai_half += 1; - if (LDSTH_I_BIT(instr)) - offset.un = (instr & 0xf00) >> 4 | (instr & 15); - else - offset.un = regs->uregs[RM_BITS(instr)]; - - if (LDST_P_BIT(instr)) { - if (LDST_U_BIT(instr)) - eaddr += offset.un; - else - eaddr -= offset.un; - } + ai_multi += 1; + + for (regbits = REGMASK_BITS(instr), nr_regs = 0; regbits; regbits >>= 1) + nr_regs += 4; - /* - * This is a "hint" - we already have eaddr worked out by the - * processor for us. - */ - if (addr != eaddr) - printk(KERN_ERR "LDRHSTRH: PC = %08lx, instr = %08x, " - "addr = %08lx, eaddr = %08lx\n", - instruction_pointer(regs), instr, addr, eaddr); - - if (LDST_L_BIT(instr)) - regs->uregs[rd] = get_unaligned((unsigned short *)eaddr); - else - put_unaligned(regs->uregs[rd], (unsigned short *)eaddr); - - /* signed half-word? */ - if (instr & 0x40) - regs->uregs[rd] = (long)((short) regs->uregs[rd]); - - if (!LDST_P_BIT(instr)) { - if (LDST_U_BIT(instr)) - eaddr += offset.un; - else - eaddr -= offset.un; - regs->uregs[rn] = eaddr; - } else if (LDST_W_BIT(instr)) - regs->uregs[rn] = eaddr; - break; + if (!LDST_U_BIT(instr)) + eaddr -= nr_regs; + + /* + * This is a "hint" - we already have eaddr worked out by the + * processor for us. + */ + if (addr != eaddr) + printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08lx, " + "addr = %08lx, eaddr = %08lx\n", + instruction_pointer(regs), instr, addr, eaddr); + + if ((LDST_U_BIT(instr) == 0 && LDST_P_BIT(instr) == 0) || + (LDST_U_BIT(instr) && LDST_P_BIT(instr))) + eaddr += 4; + + for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1) + if (regbits & 1) { + if (LDST_L_BIT(instr)) { + get32_unaligned_check(regs->uregs[rd], eaddr); + if (rd == 15) + correction = 0; + } else + put32_unaligned_check(regs->uregs[rd], eaddr); + eaddr += 4; } - default: - ai_skipped += 1; - panic("Alignment trap: not handling instruction %08X at %08lX", - instr, regs->ARM_pc - correction - 4); + if (LDST_W_BIT(instr)) { + if (LDST_P_BIT(instr) && !LDST_U_BIT(instr)) + eaddr -= nr_regs; + else if (LDST_P_BIT(instr)) + eaddr -= 4; + else if (!LDST_U_BIT(instr)) + eaddr -= 4 + nr_regs; + regs->uregs[rn] = eaddr; + } + regs->ARM_pc -= correction; + return TYPE_DONE; + +fault: + return TYPE_FAULT; + +bad: + printk(KERN_ERR "Alignment trap: not handling ldm with s-bit set\n"); + return TYPE_ERROR; +} + +static int +do_alignment(unsigned long addr, int error_code, struct pt_regs *regs) +{ + union offset_union offset; + unsigned long instr, instrptr; + int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs); + unsigned int type; + + if (user_mode(regs)) + goto user; + + ai_sys += 1; + + instrptr = instruction_pointer(regs); + instr = *(unsigned long *)instrptr; + + regs->ARM_pc += 4; + + switch (CODING_BITS(instr)) { + case 0x00000000: /* ldrh or strh */ + if (LDSTH_I_BIT(instr)) + offset.un = (instr & 0xf00) >> 4 | (instr & 15); + else + offset.un = regs->uregs[RM_BITS(instr)]; + handler = do_alignment_ldrhstrh; break; - case 0x04000000: + case 0x04000000: /* ldr or str immediate */ offset.un = OFFSET_BITS(instr); - goto ldr_str; + handler = do_alignment_ldrstr; + break; - case 0x06000000: + case 0x06000000: /* ldr or str register */ offset.un = regs->uregs[RM_BITS(instr)]; if (IS_SHIFT(instr)) { @@ -229,97 +466,49 @@ break; } } - - ldr_str: - ai_word += 1; - if (LDST_P_BIT(instr)) { - if (LDST_U_BIT(instr)) - eaddr += offset.un; - else - eaddr -= offset.un; - } else { - if (LDST_W_BIT(instr)) { - printk(KERN_ERR "Not handling ldrt/strt correctly\n"); - return 1; - } - } - - /* - * This is a "hint" - we already have eaddr worked out by the - * processor for us. - */ - if (addr != eaddr) - printk(KERN_ERR "LDRSTR: PC = %08lx, instr = %08x, " - "addr = %08lx, eaddr = %08lx\n", - instruction_pointer(regs), instr, addr, eaddr); - - if (LDST_L_BIT(instr)) { - regs->uregs[rd] = get_unaligned((unsigned long *)eaddr); - if (rd == 15) - correction = 0; - } else - put_unaligned(regs->uregs[rd], (unsigned long *)eaddr); - - if (!LDST_P_BIT(instr)) { - if (LDST_U_BIT(instr)) - eaddr += offset.un; - else - eaddr -= offset.un; - - regs->uregs[rn] = eaddr; - } else if (LDST_W_BIT(instr)) - regs->uregs[rn] = eaddr; + handler = do_alignment_ldrstr; break; - case 0x08000000: - if (LDM_S_BIT(instr)) - panic("Alignment trap: not handling LDM with s-bit\n"); - ai_multi += 1; - - for (regbits = REGMASK_BITS(instr), nr_regs = 0; regbits; regbits >>= 1) - nr_regs += 4; + case 0x08000000: /* ldm or stm */ + handler = do_alignment_ldmstm; + break; - if (!LDST_U_BIT(instr)) - eaddr -= nr_regs; + default: + goto bad; + } - /* - * This is a "hint" - we already have eaddr worked out by the - * processor for us. - */ - if (addr != eaddr) - printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08x, " - "addr = %08lx, eaddr = %08lx\n", - instruction_pointer(regs), instr, addr, eaddr); + type = handler(addr, instr, regs); - if ((LDST_U_BIT(instr) == 0 && LDST_P_BIT(instr) == 0) || - (LDST_U_BIT(instr) && LDST_P_BIT(instr))) - eaddr += 4; + if (type == TYPE_ERROR || type == TYPE_FAULT) + goto bad_or_fault; - for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1) - if (regbits & 1) { - if (LDST_L_BIT(instr)) { - regs->uregs[rd] = get_unaligned((unsigned long *)eaddr); - if (rd == 15) - correction = 0; - } else - put_unaligned(regs->uregs[rd], (unsigned long *)eaddr); - eaddr += 4; - } + if (type == TYPE_LDST) + do_alignment_finish_ldst(addr, instr, regs, offset); - if (LDST_W_BIT(instr)) { - if (LDST_P_BIT(instr) && !LDST_U_BIT(instr)) - eaddr -= nr_regs; - else if (LDST_P_BIT(instr)) - eaddr -= 4; - else if (!LDST_U_BIT(instr)) - eaddr -= 4 + nr_regs; - regs->uregs[rn] = eaddr; - } - break; - } + return 0; - regs->ARM_pc -= correction; +bad_or_fault: + if (type == TYPE_ERROR) + goto bad; + regs->ARM_pc -= 4; + /* + * We got a fault - fix it up, or die. + */ + do_bad_area(current, current->mm, addr, error_code, regs); + return 0; +bad: + /* + * Oops, we didn't handle the instruction. + */ + printk(KERN_ERR "Alignment trap: not handling instruction " + "%08lx at [<%08lx>]", instr, instrptr); + ai_skipped += 1; + return 1; + +user: + set_cr(cr_no_alignment); + ai_user += 1; return 0; } @@ -332,35 +521,13 @@ /* * Some section permission faults need to be handled gracefully, for * instance, when they happen due to a __{get,put}_user during an oops). - * In this case, we should return an error to the __{get,put}_user caller - * instead of causing another oops. We should also fixup this fault as - * the user could pass a pointer to a section to the kernel. */ static int do_sect_fault(unsigned long addr, int error_code, struct pt_regs *regs) { - unsigned long fixup; - - if (user_mode(regs)) { -#ifdef CONFIG_DEBUG_USER - printk("%s: permission fault on section, " - "address=0x%08lx, code %d\n", - current->comm, addr, error_code); -#endif - goto fail; - } - - fixup = search_exception_table(instruction_pointer(regs)); - if (fixup != 0) { -#ifdef DEBUG - printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n", - tsk->comm, regs->ARM_pc, addr, fixup); -#endif - regs->ARM_pc = fixup; - return 0; - } -fail: - return 1; /* not fixed up */ + struct task_struct *tsk = current; + do_bad_area(tsk, tsk->active_mm, addr, error_code, regs); + return 0; } static const struct fsr_info { @@ -369,17 +536,17 @@ char *name; } fsr_info[] = { { NULL, SIGSEGV, "vector exception" }, - { do_alignment, SIGBUS, "alignment exception" }, + { do_alignment, SIGILL, "alignment exception" }, { NULL, SIGKILL, "terminal exception" }, - { do_alignment, SIGBUS, "alignment exception" }, + { do_alignment, SIGILL, "alignment exception" }, { NULL, SIGBUS, "external abort on linefetch" }, - { do_page_fault, SIGSEGV, "page fault" }, + { do_translation_fault, SIGSEGV, "section translation fault" }, { NULL, SIGBUS, "external abort on linefetch" }, - { do_page_fault, SIGSEGV, "page fault" }, + { do_page_fault, SIGSEGV, "page translation fault" }, { NULL, SIGBUS, "external abort on non-linefetch" }, - { NULL, SIGSEGV, "domain fault" }, + { NULL, SIGSEGV, "section domain fault" }, { NULL, SIGBUS, "external abort on non-linefetch" }, - { NULL, SIGSEGV, "domain fault" }, + { NULL, SIGSEGV, "page domain fault" }, { NULL, SIGBUS, "external abort on translation" }, { do_sect_fault, SIGSEGV, "section permission fault" }, { NULL, SIGBUS, "external abort on translation" }, @@ -398,7 +565,7 @@ if (addr == regs->ARM_pc) goto sa1_weirdness; #endif -#if defined(CONFIG_CPU_ARM720T) && defined(CONFIG_ALIGNMENT_TRAP) +#if defined(CONFIG_CPU_ARM720) && defined(CONFIG_ALIGNMENT_TRAP) if (addr & 3 && (fsr & 13) != 1) goto arm720_weirdness; #endif @@ -410,7 +577,6 @@ return; bad: force_sig(inf->sig, current); - printk(KERN_ALERT "Unhandled fault: %s (%X) at 0x%08lx\n", inf->name, fsr, addr); show_pte(current->mm, addr); @@ -431,7 +597,7 @@ goto bad; return; #endif -#if defined(CONFIG_CPU_ARM720T) && defined(CONFIG_ALIGNMENT_TRAP) +#if defined(CONFIG_CPU_ARM720) && defined(CONFIG_ALIGNMENT_TRAP) arm720_weirdness: if (!user_mode(regs)) { unsigned long instr; @@ -462,6 +628,6 @@ asmlinkage int do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) { - do_page_fault(addr, 0, regs); + do_translation_fault(addr, 0, regs); return 1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/fault-common.c linux.ac/arch/arm/mm/fault-common.c --- linux.vanilla/arch/arm/mm/fault-common.c Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/arm/mm/fault-common.c Sat Apr 14 01:16:46 2001 @@ -2,7 +2,7 @@ * linux/arch/arm/mm/fault-common.c * * Copyright (C) 1995 Linus Torvalds - * Modifications for ARM processor (c) 1995-1999 Russell King + * Modifications for ARM processor (c) 1995-2001 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 @@ -93,8 +93,82 @@ printk("\n"); } +/* + * Oops. The kernel tried to access some page that wasn't present. + */ +static void +__do_kernel_fault(struct mm_struct *mm, unsigned long addr, int error_code, + struct pt_regs *regs) +{ + unsigned long fixup; + + /* + * Are we prepared to handle this kernel fault? + */ + if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) { +#ifdef DEBUG + printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n", + tsk->comm, regs->ARM_pc, addr, fixup); +#endif + regs->ARM_pc = fixup; + return; + } + + /* + * No handler, we'll have to terminate things with extreme prejudice. + */ + printk(KERN_ALERT + "Unable to handle kernel %s at virtual address %08lx\n", + (addr < PAGE_SIZE) ? "NULL pointer dereference" : + "paging request", addr); + + show_pte(mm, addr); + die("Oops", regs, error_code); + do_exit(SIGKILL); +} + +/* + * Something tried to access memory that isn't in our memory map.. + * User mode accesses just cause a SIGSEGV + */ +static void +__do_user_fault(struct task_struct *tsk, unsigned long addr, int error_code, + int code, struct pt_regs *regs) +{ + struct siginfo si; + +#ifdef CONFIG_DEBUG_USER + printk(KERN_DEBUG "%s: unhandled page fault at pc=0x%08lx, " + "lr=0x%08lx (bad address=0x%08lx, code %d)\n", + tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, error_code); +#endif + + tsk->thread.address = addr; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = 14; + si.si_signo = SIGSEGV; + si.si_errno = 0; + si.si_code = code; + si.si_addr = (void *)addr; + force_sig_info(SIGSEGV, &si, tsk); +} + +void +do_bad_area(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr, + int error_code, struct pt_regs *regs) +{ + /* + * If we are in kernel mode at this point, we + * have no context to handle this fault with. + */ + if (user_mode(regs)) + __do_user_fault(tsk, addr, error_code, SEGV_MAPERR, regs); + else + __do_kernel_fault(mm, addr, error_code, regs); +} + static int -__do_page_fault(struct mm_struct *mm, unsigned long addr, int mode, +__do_page_fault(struct mm_struct *mm, unsigned long addr, int error_code, struct task_struct *tsk) { struct vm_area_struct *vma; @@ -112,7 +186,7 @@ * memory access, so we can handle it. */ good_area: - if (READ_FAULT(mode)) /* read? */ + if (READ_FAULT(error_code)) /* read? */ mask = VM_READ|VM_EXEC; else mask = VM_WRITE; @@ -127,7 +201,7 @@ * than endlessly redo the fault. */ survive: - fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, DO_COW(mode)); + fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, DO_COW(error_code)); /* * Handle the "normal" cases first - successful and sigbus @@ -161,62 +235,16 @@ return fault; } -static int __do_vmalloc_fault(unsigned long addr, struct mm_struct *mm) -{ - /* Synchronise this task's top level page-table - * with the 'reference' page table. - */ - int offset = __pgd_offset(addr); - pgd_t *pgd, *pgd_k; - pmd_t *pmd, *pmd_k; - - pgd_k = init_mm.pgd + offset; - if (!pgd_present(*pgd_k)) - goto bad_area; - - pgd = mm->pgd + offset; -#if 0 /* note that we are two-level */ - if (!pgd_present(*pgd)) - set_pgd(pgd, *pgd_k); -#endif - - pmd_k = pmd_offset(pgd_k, addr); - if (pmd_none(*pmd_k)) - goto bad_area; - - pmd = pmd_offset(pgd, addr); - if (!pmd_none(*pmd)) - goto bad_area; - set_pmd(pmd, *pmd_k); - return 1; - -bad_area: - return -2; -} - -int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs) +int do_page_fault(unsigned long addr, int error_code, struct pt_regs *regs) { struct task_struct *tsk; struct mm_struct *mm; - unsigned long fixup; int fault; tsk = current; mm = tsk->mm; /* - * We fault-in kernel-space virtual memory on-demand. The - * 'reference' page table is init_mm.pgd. - * - * NOTE! We MUST NOT take any locks for this case. We may - * be in an interrupt or a critical region, and should - * only copy the information from the master page table, - * nothing more. - */ - if (addr >= TASK_SIZE) - goto vmalloc_fault; - - /* * If we're in an interrupt or have no user * context, we must not take the fault.. */ @@ -224,10 +252,9 @@ goto no_context; down_read(&mm->mmap_sem); - fault = __do_page_fault(mm, addr, mode, tsk); + fault = __do_page_fault(mm, addr, error_code, tsk); up_read(&mm->mmap_sem); -ret: /* * Handle the "normal" case first */ @@ -255,28 +282,9 @@ */ printk("VM: killing process %s\n", tsk->comm); do_exit(SIGKILL); - } else { - /* - * Something tried to access memory that isn't in our memory map.. - * User mode accesses just cause a SIGSEGV - */ - struct siginfo si; - -#ifdef CONFIG_DEBUG_USER - printk(KERN_DEBUG "%s: unhandled page fault at pc=0x%08lx, " - "lr=0x%08lx (bad address=0x%08lx, code %d)\n", - tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode); -#endif - - tsk->thread.address = addr; - tsk->thread.error_code = mode; - tsk->thread.trap_no = 14; - si.si_signo = SIGSEGV; - si.si_errno = 0; - si.si_code = fault == -1 ? SEGV_ACCERR : SEGV_MAPERR; - si.si_addr = (void *)addr; - force_sig_info(SIGSEGV, &si, tsk); - } + } else + __do_user_fault(tsk, addr, error_code, fault == -1 ? + SEGV_ACCERR : SEGV_MAPERR, regs); return 0; @@ -290,7 +298,7 @@ * or user mode. */ tsk->thread.address = addr; - tsk->thread.error_code = mode; + tsk->thread.error_code = error_code; tsk->thread.trap_no = 14; force_sig(SIGBUS, tsk); @@ -299,32 +307,64 @@ return 0; no_context: - /* Are we prepared to handle this kernel fault? */ - if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) { -#ifdef DEBUG - printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n", - tsk->comm, regs->ARM_pc, addr, fixup); + __do_kernel_fault(mm, addr, error_code, regs); + return 0; +} + +/* + * First Level Translation Fault Handler + * + * We enter here because the first level page table doesn't contain + * a valid entry for the address. + * + * If the address is in kernel space (>= TASK_SIZE), then we are + * probably faulting in the vmalloc() area. + * + * If the init_task's first level page tables contains the relevant + * entry, we copy the it to this task. If not, we send the process + * a signal, fixup the exception, or oops the kernel. + * + * NOTE! We MUST NOT take any locks for this case. We may be in an + * interrupt or a critical region, and should only copy the information + * from the master page table, nothing more. + */ +int do_translation_fault(unsigned long addr, int error_code, struct pt_regs *regs) +{ + struct task_struct *tsk; + struct mm_struct *mm; + int offset; + pgd_t *pgd, *pgd_k; + pmd_t *pmd, *pmd_k; + + if (addr < TASK_SIZE) + return do_page_fault(addr, error_code, regs); + + tsk = current; + mm = tsk->active_mm; + + offset = __pgd_offset(addr); + + pgd_k = init_mm.pgd + offset; + pgd = mm->pgd + offset; + + if (pgd_none(*pgd_k)) + goto bad_area; + +#if 0 /* note that we are two-level */ + if (!pgd_present(*pgd)) + set_pgd(pgd, *pgd_k); #endif - regs->ARM_pc = fixup; - return 0; - } - /* - * Oops. The kernel tried to access some bad page. We'll have to - * terminate things with extreme prejudice. - */ - printk(KERN_ALERT - "Unable to handle kernel %s at virtual address %08lx\n", - (addr < PAGE_SIZE) ? "NULL pointer dereference" : - "paging request", addr); + pmd_k = pmd_offset(pgd_k, addr); + pmd = pmd_offset(pgd, addr); - show_pte(mm, addr); - die("Oops", regs, mode); - do_exit(SIGKILL); + if (pmd_none(*pmd_k)) + goto bad_area; + set_pmd(pmd, *pmd_k); return 0; -vmalloc_fault: - fault = __do_vmalloc_fault(addr, mm); - goto ret; +bad_area: + do_bad_area(tsk, mm, addr, error_code, regs); + return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/init.c linux.ac/arch/arm/mm/init.c --- linux.vanilla/arch/arm/mm/init.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/mm/init.c Sat Apr 14 01:16:46 2001 @@ -33,6 +33,9 @@ #include <asm/mach/arch.h> #include <asm/mach/map.h> +#include <asm/tlb.h> + +mmu_gather_t mmu_gathers[NR_CPUS]; #ifndef CONFIG_DISCONTIGMEM #define NR_NODES 1 @@ -59,52 +62,10 @@ static struct meminfo meminfo __initdata = { 0, }; /* - * empty_bad_page is the page that is used for page faults when - * linux is out-of-memory. Older versions of linux just did a - * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving a inode - * unused etc.. - * - * empty_bad_pte_table is the accompanying page-table: it is - * initialized to point to BAD_PAGE entries. - * * empty_zero_page is a special page that is used for * zero-initialized data and COW. */ struct page *empty_zero_page; -struct page *empty_bad_page; -pte_t *empty_bad_pte_table; - -pte_t *get_bad_pte_table(void) -{ - pte_t v; - int i; - - v = pte_mkdirty(mk_pte(empty_bad_page, PAGE_SHARED)); - - for (i = 0; i < PTRS_PER_PTE; i++) - set_pte(empty_bad_pte_table + i, v); - - return empty_bad_pte_table; -} - -void __handle_bad_pmd(pmd_t *pmd) -{ - pmd_ERROR(*pmd); -#ifdef CONFIG_DEBUG_ERRORS - __backtrace(); -#endif - set_pmd(pmd, mk_user_pmd(get_bad_pte_table())); -} - -void __handle_bad_pmd_kernel(pmd_t *pmd) -{ - pmd_ERROR(*pmd); -#ifdef CONFIG_DEBUG_ERRORS - __backtrace(); -#endif - set_pmd(pmd, mk_kernel_pmd(get_bad_pte_table())); -} #ifndef CONFIG_NO_PGT_CACHE struct pgtable_cache_struct quicklists; @@ -120,12 +81,12 @@ freed++; } if(pmd_quicklist) { - free_pmd_slow(get_pmd_fast()); + pmd_free_slow(pmd_alloc_one_fast(NULL, 0)); freed++; } if(pte_quicklist) { - free_pte_slow(get_pte_fast()); - freed++; + pte_free_slow(pte_alloc_one_fast(NULL, 0)); + freed++; } } while(pgtable_cache_size > low); } @@ -514,18 +475,15 @@ */ void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc) { - void *zero_page, *bad_page, *bad_table; + void *zero_page; int node; memcpy(&meminfo, mi, sizeof(meminfo)); /* - * allocate what we need for the bad pages. - * note that we count on this going ok. + * allocate the zero page. Note that we count on this going ok. */ zero_page = alloc_bootmem_low_pages(PAGE_SIZE); - bad_page = alloc_bootmem_low_pages(PAGE_SIZE); - bad_table = alloc_bootmem_low_pages(TABLE_SIZE); /* * initialise the page tables. @@ -586,11 +544,7 @@ * the mem_map is initialised */ memzero(zero_page, PAGE_SIZE); - memzero(bad_page, PAGE_SIZE); - empty_zero_page = virt_to_page(zero_page); - empty_bad_page = virt_to_page(bad_page); - empty_bad_pte_table = ((pte_t *)bad_table) + TABLE_OFFSET; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/ioremap.c linux.ac/arch/arm/mm/ioremap.c --- linux.vanilla/arch/arm/mm/ioremap.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mm/ioremap.c Sat Apr 14 01:16:46 2001 @@ -44,14 +44,18 @@ end = address + size; if (end > PMD_SIZE) end = PMD_SIZE; + if (address >= end) + BUG(); do { - if (!pte_none(*pte)) + if (!pte_none(*pte)) { printk("remap_area_pte: page already exists\n"); + BUG(); + } set_pte(pte, mk_pte_phys(phys_addr, pgprot)); address += PAGE_SIZE; phys_addr += PAGE_SIZE; pte++; - } while (address < end); + } while (address && (address < end)); } static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, @@ -67,40 +71,50 @@ end = PGDIR_SIZE; phys_addr -= address; + if (address >= end) + BUG(); + pgprot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE | flags); do { - pte_t * pte = pte_alloc_kernel(pmd, address); + pte_t * pte = pte_alloc(&init_mm, pmd, address); if (!pte) return -ENOMEM; remap_area_pte(pte, address, end - address, address + phys_addr, pgprot); address = (address + PMD_SIZE) & PMD_MASK; pmd++; - } while (address < end); + } while (address && (address < end)); return 0; } static int remap_area_pages(unsigned long address, unsigned long phys_addr, unsigned long size, unsigned long flags) { + int error; pgd_t * dir; unsigned long end = address + size; phys_addr -= address; dir = pgd_offset(&init_mm, address); flush_cache_all(); - while (address < end) { - pmd_t *pmd = pmd_alloc_kernel(dir, address); + if (address >= end) + BUG(); + spin_lock(&init_mm.page_table_lock); + do { + pmd_t *pmd; + pmd = pmd_alloc(&init_mm, dir, address); + error = -ENOMEM; if (!pmd) - return -ENOMEM; + break; if (remap_area_pmd(pmd, address, end - address, phys_addr + address, flags)) - return -ENOMEM; - set_pgdir(address, *dir); + break; + error = 0; address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; - } + } while (address && (address < end)); + spin_unlock(&init_mm.page_table_lock); flush_tlb_all(); - return 0; + return error; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/mm-armo.c linux.ac/arch/arm/mm/mm-armo.c --- linux.vanilla/arch/arm/mm/mm-armo.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mm/mm-armo.c Sat Apr 14 01:16:46 2001 @@ -22,120 +22,98 @@ #include <asm/mach/map.h> #define MEMC_TABLE_SIZE (256*sizeof(unsigned long)) -#define PGD_TABLE_SIZE (PTRS_PER_PGD * BYTES_PER_PTR) +kmem_cache_t *pte_cache, *pgd_cache; int page_nr; -extern unsigned long get_page_2k(int prio); -extern void free_page_2k(unsigned long); -extern pte_t *get_bad_pte_table(void); - /* * Allocate a page table. Note that we place the MEMC * table before the page directory. This means we can * easily get to both tightly-associated data structures * with a single pointer. - * - * We actually only need 1152 bytes, 896 bytes is wasted. - * We could try to fit 7 PTEs into that slot somehow. */ -static inline void *alloc_pgd_table(int priority) +static inline pgd_t *alloc_pgd_table(int priority) { - unsigned long pg2k; + void *pg2k = kmem_cache_alloc(pgd_cache, GFP_KERNEL); - pg2k = get_page_2k(priority); if (pg2k) pg2k += MEMC_TABLE_SIZE; - return (void *)pg2k; + return (pgd_t *)pg2k; } void free_pgd_slow(pgd_t *pgd) { unsigned long tbl = (unsigned long)pgd; + /* + * CHECKME: are we leaking pte tables here??? + */ + tbl -= MEMC_TABLE_SIZE; - free_page_2k(tbl); + + kmem_cache_free(pgd_cache, (void *)tbl); } -/* - * FIXME: the following over-allocates by 1600% - */ -static inline void *alloc_pte_table(int size, int prio) +pgd_t *get_pgd_slow(struct mm_struct *mm) { - if (size != 128) - printk("invalid table size\n"); - return (void *)get_page_2k(prio); -} - -void free_pte_slow(pte_t *pte) -{ - unsigned long tbl = (unsigned long)pte; - free_page_2k(tbl); -} - -pgd_t *get_pgd_slow(void) -{ - pgd_t *pgd = (pgd_t *)alloc_pgd_table(GFP_KERNEL); - pmd_t *new_pmd; - - if (pgd) { - pgd_t *init = pgd_offset(&init_mm, 0); - - memzero(pgd, USER_PTRS_PER_PGD * sizeof(pgd_t)); - memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); - - /* - * On ARM, first page must always be allocated - */ - if (!pmd_alloc(pgd, 0)) - goto nomem; - else { - pmd_t *old_pmd = pmd_offset(init, 0); - new_pmd = pmd_offset(pgd, 0); - - if (!pte_alloc(new_pmd, 0)) - goto nomem_pmd; - else { - pte_t *new_pte = pte_offset(new_pmd, 0); - pte_t *old_pte = pte_offset(old_pmd, 0); - - set_pte (new_pte, *old_pte); - } - } - /* update MEMC tables */ - cpu_memc_update_all(pgd); - } - return pgd; + pgd_t *new_pgd, *init_pgd; + pmd_t *new_pmd, *init_pmd; + pte_t *new_pte, *init_pte; + + new_pgd = alloc_pgd_table(GFP_KERNEL); + if (!new_pgd) + goto no_pgd; + + /* + * This lock is here just to satisfy pmd_alloc and pte_lock + */ + spin_lock(&mm->page_table_lock); + + /* + * On ARM, first page must always be allocated since it contains + * the machine vectors. + */ + new_pmd = pmd_alloc(mm, new_pgd, 0); + if (!new_pmd) + goto no_pmd; -nomem_pmd: + new_pte = pte_alloc(mm, new_pmd, 0); + if (!new_pte) + goto no_pte; + + init_pgd = pgd_offset_k(0); + init_pmd = pmd_offset(init_pgd, 0); + init_pte = pte_offset(init_pmd, 0); + + set_pte(new_pte, *init_pte); + + /* + * most of the page table entries are zeroed + * wne the table is created. + */ + memcpy(new_pgd + USER_PTRS_PER_PGD, init_pgd + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + + spin_unlock(&mm->page_table_lock); + + /* update MEMC tables */ + cpu_memc_update_all(new_pgd); + return new_pgd; + +no_pte: + spin_unlock(&mm->page_table_lock); pmd_free(new_pmd); -nomem: - free_pgd_slow(pgd); + free_pgd_slow(new_pgd); return NULL; -} -pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; +no_pmd: + spin_unlock(&mm->page_table_lock); + free_pgd_slow(new_pgd); + return NULL; - pte = (pte_t *)alloc_pte_table(PTRS_PER_PTE * sizeof(pte_t), GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - memzero(pte, PTRS_PER_PTE * sizeof(pte_t)); - set_pmd(pmd, mk_user_pmd(pte)); - return pte + offset; - } - set_pmd(pmd, mk_user_pmd(get_bad_pte_table())); - return NULL; - } - free_pte_slow(pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; +no_pgd: + return NULL; } /* @@ -160,7 +138,7 @@ pte = alloc_bootmem_low_pages(PTRS_PER_PTE * sizeof(pte_t)); pte[0] = mk_pte_phys(PAGE_OFFSET + 491520, PAGE_READONLY); - set_pmd(pmd_offset(swapper_pg_dir, 0), mk_kernel_pmd(pte)); + pmd_populate(&init_mm, pmd_offset(swapper_pg_dir, 0), pte); for (i = 1; i < PTRS_PER_PGD; i++) pgd_val(swapper_pg_dir[i]) = 0; @@ -176,4 +154,31 @@ */ void __init create_memmap_holes(struct meminfo *mi) { +} + +static void pte_cache_ctor(void *pte, kmem_cache_t *cache, unsigned long flags) +{ + memzero(pte, sizeof(pte_t) * PTRS_PER_PTE); +} + +static void pgd_cache_ctor(void *pte, kmem_cache_t *cache, unsigned long flags) +{ + pgd_t *pgd = (pte + MEMC_TABLE_SIZE); + + memzero(pgd, USER_PTRS_PER_PGD * sizeof(pgd_t)); +} + +void __init pgtable_cache_init(void) +{ + pte_cache = kmem_cache_create("pte-cache", + sizeof(pte_t) * PTRS_PER_PTE, + 0, 0, pte_cache_ctor, NULL); + if (!pte_cache) + BUG(); + + pgd_cache = kmem_cache_create("pgd-cache", MEMC_TABLE_SIZE + + sizeof(pgd_t) * PTRS_PER_PGD, + 0, 0, pgd_cache_ctor, NULL); + if (!pgd_cache) + BUG(); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/mm-armv.c linux.ac/arch/arm/mm/mm-armv.c --- linux.vanilla/arch/arm/mm/mm-armv.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/mm/mm-armv.c Sat Apr 14 01:16:46 2001 @@ -22,12 +22,6 @@ #include <asm/mach/map.h> -unsigned long *valid_addr_bitmap; - -extern unsigned long get_page_2k(int priority); -extern void free_page_2k(unsigned long page); -extern pte_t *get_bad_pte_table(void); - /* * These are useful for identifing cache coherency * problems by allowing the cache or the cache and @@ -73,47 +67,68 @@ /* * need to get a 16k page for level 1 */ -pgd_t *get_pgd_slow(void) +pgd_t *get_pgd_slow(struct mm_struct *mm) { - pgd_t *pgd = (pgd_t *)__get_free_pages(GFP_KERNEL,2); - pmd_t *new_pmd; + pgd_t *new_pgd, *init_pgd; + pmd_t *new_pmd, *init_pmd; + pte_t *new_pte, *init_pte; + + new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 2); + if (!new_pgd) + goto no_pgd; + + memzero(new_pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t)); + + /* + * This lock is here just to satisfy pmd_alloc and pte_lock + */ + spin_lock(&mm->page_table_lock); - if (pgd) { - pgd_t *init = pgd_offset_k(0); + /* + * On ARM, first page must always be allocated since it contains + * the machine vectors. + */ + new_pmd = pmd_alloc(mm, new_pgd, 0); + if (!new_pmd) + goto no_pmd; + + new_pte = pte_alloc(mm, new_pmd, 0); + if (!new_pte) + goto no_pte; + + init_pgd = pgd_offset_k(0); + init_pmd = pmd_offset(init_pgd, 0); + init_pte = pte_offset(init_pmd, 0); - memzero(pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t)); - memcpy(pgd + FIRST_KERNEL_PGD_NR, init + FIRST_KERNEL_PGD_NR, + set_pte(new_pte, *init_pte); + + /* + * Copy over the kernel and IO PGD entries + */ + memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR, (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t)); - /* - * FIXME: this should not be necessary - */ - clean_cache_area(pgd, PTRS_PER_PGD * sizeof(pgd_t)); - /* - * On ARM, first page must always be allocated - */ - if (!pmd_alloc(pgd, 0)) - goto nomem; - else { - pmd_t *old_pmd = pmd_offset(init, 0); - new_pmd = pmd_offset(pgd, 0); - - if (!pte_alloc(new_pmd, 0)) - goto nomem_pmd; - else { - pte_t *new_pte = pte_offset(new_pmd, 0); - pte_t *old_pte = pte_offset(old_pmd, 0); + spin_unlock(&mm->page_table_lock); - set_pte(new_pte, *old_pte); - } - } - } - return pgd; + /* + * FIXME: this should not be necessary + */ + clean_cache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t)); + + return new_pgd; -nomem_pmd: +no_pte: + spin_unlock(&mm->page_table_lock); pmd_free(new_pmd); -nomem: - free_pages((unsigned long)pgd, 2); + free_pages((unsigned long)new_pgd, 2); + return NULL; + +no_pmd: + spin_unlock(&mm->page_table_lock); + free_pages((unsigned long)new_pgd, 2); + return NULL; + +no_pgd: return NULL; } @@ -142,59 +157,6 @@ free_pages((unsigned long) pgd, 2); } -pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *)get_page_2k(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - memzero(pte, 2 * PTRS_PER_PTE * sizeof(pte_t)); - clean_cache_area(pte, PTRS_PER_PTE * sizeof(pte_t)); - pte += PTRS_PER_PTE; - set_pmd(pmd, mk_user_pmd(pte)); - return pte + offset; - } - set_pmd(pmd, mk_user_pmd(get_bad_pte_table())); - return NULL; - } - free_page_2k((unsigned long)pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - -pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *)get_page_2k(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - memzero(pte, 2 * PTRS_PER_PTE * sizeof(pte_t)); - clean_cache_area(pte, PTRS_PER_PTE * sizeof(pte_t)); - pte += PTRS_PER_PTE; - set_pmd(pmd, mk_kernel_pmd(pte)); - return pte + offset; - } - set_pmd(pmd, mk_kernel_pmd(get_bad_pte_table())); - return NULL; - } - free_page_2k((unsigned long)pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - -void free_pte_slow(pte_t *pte) -{ - free_page_2k((unsigned long)(pte - PTRS_PER_PTE)); -} - /* * Create a SECTION PGD between VIRT and PHYS in domain * DOMAIN with protection PROT @@ -481,4 +443,42 @@ for (node = 0; node < numnodes; node++) free_unused_memmap_node(node, mi); +} + +/* + * PTE table allocation cache. + * + * This is a move away from our custom 2K page allocator. We now use the + * slab cache to keep track of these objects. + * + * With this, it is questionable as to whether the PGT cache gains us + * anything. We may be better off dropping the PTE stuff from our PGT + * cache implementation. + */ +kmem_cache_t *pte_cache; + +/* + * The constructor gets called for each object within the cache when the + * cache page is created. Note that if slab tries to misalign the blocks, + * we BUG() loudly. + */ +static void pte_cache_ctor(void *pte, kmem_cache_t *cache, unsigned long flags) +{ + unsigned long block = (unsigned long)pte; + + if (block & 2047) + BUG(); + + memzero(pte, 2 * PTRS_PER_PTE * sizeof(pte_t)); + cpu_cache_clean_invalidate_range(block, block + + PTRS_PER_PTE * sizeof(pte_t), 0); +} + +void __init pgtable_cache_init(void) +{ + pte_cache = kmem_cache_create("pte-cache", + 2 * PTRS_PER_PTE * sizeof(pte_t), 0, 0, + pte_cache_ctor, NULL); + if (!pte_cache) + BUG(); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/mm-clps7500.c linux.ac/arch/arm/mm/mm-clps7500.c --- linux.vanilla/arch/arm/mm/mm-clps7500.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mm/mm-clps7500.c Sat Apr 14 01:16:46 2001 @@ -6,6 +6,7 @@ * * Extra MM routines for CL7500 architecture */ +#include <linux/types.h> #include <linux/init.h> #include <asm/hardware.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/mm-ebsa110.c linux.ac/arch/arm/mm/mm-ebsa110.c --- linux.vanilla/arch/arm/mm/mm-ebsa110.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mm/mm-ebsa110.c Thu Jan 1 01:00:00 1970 @@ -1,30 +0,0 @@ -/* - * linux/arch/arm/mm/mm-ebsa110.c - * - * Copyright (C) 1998-1999 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. - * - * Extra MM routines for the EBSA-110 architecture - */ -#include <linux/mm.h> -#include <linux/init.h> - -#include <asm/hardware.h> -#include <asm/pgtable.h> -#include <asm/page.h> - -#include <asm/mach/map.h> - -static struct map_desc ebsa110_io_desc[] __initdata = { - { IO_BASE - PGDIR_SIZE, 0xc0000000, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, - { IO_BASE , IO_START , IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, - LAST_DESC -}; - -void __init ebsa110_map_io(void) -{ - iotable_init(ebsa110_io_desc); -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/mm-footbridge.c linux.ac/arch/arm/mm/mm-footbridge.c --- linux.vanilla/arch/arm/mm/mm-footbridge.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mm/mm-footbridge.c Thu Jan 1 01:00:00 1970 @@ -1,117 +0,0 @@ -/* - * linux/arch/arm/mm/mm-footbridge.c - * - * Copyright (C) 1998-2000 Russell King, Dave Gilbert. - * - * 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. - * - * Extra MM routines for the EBSA285 architecture - */ -#include <linux/config.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/init.h> - -#include <asm/pgtable.h> -#include <asm/page.h> -#include <asm/io.h> -#include <asm/hardware/dec21285.h> -#include <asm/mach-types.h> - -#include <asm/mach/map.h> - -/* - * Common mapping for all systems. Note that the outbound write flush is - * commented out since there is a "No Fix" problem with it. Not mapping - * it means that we have extra bullet protection on our feet. - */ -static struct map_desc fb_common_io_desc[] __initdata = { - { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, - { XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, - LAST_DESC -}; - -/* - * The mapping when the footbridge is in host mode. We don't map any of - * this when we are in add-in mode. - */ -static struct map_desc ebsa285_host_io_desc[] __initdata = { -#if defined(CONFIG_ARCH_FOOTBRIDGE) && defined(CONFIG_FOOTBRIDGE_HOST) - { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, - { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG, PCICFG0_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, - { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG, PCICFG1_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, - { PCIIACK_BASE, DC21285_PCI_IACK, PCIIACK_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, - { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, -#endif - LAST_DESC -}; - -/* - * The CO-ebsa285 mapping. - */ -static struct map_desc co285_io_desc[] __initdata = { -#ifdef CONFIG_ARCH_CO285 - { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, - { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, -#endif - LAST_DESC -}; - -void __init footbridge_map_io(void) -{ - struct map_desc *desc = NULL; - - /* - * Set up the common mapping first; we need this to - * determine whether we're in host mode or not. - */ - iotable_init(fb_common_io_desc); - - /* - * Now, work out what we've got to map in addition on this - * platform. - */ - if (machine_is_co285()) - desc = co285_io_desc; - else if (footbridge_cfn_mode()) - desc = ebsa285_host_io_desc; - - if (desc) - iotable_init(desc); -} - -#ifdef CONFIG_FOOTBRIDGE_ADDIN - -/* - * These two functions convert virtual addresses to PCI addresses and PCI - * addresses to virtual addresses. Note that it is only legal to use these - * on memory obtained via get_free_page or kmalloc. - */ -unsigned long __virt_to_bus(unsigned long res) -{ -#ifdef CONFIG_DEBUG_ERRORS - if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) { - printk("__virt_to_bus: invalid virtual address 0x%08lx\n", res); - __backtrace(); - } -#endif - return (res - PAGE_OFFSET) + (*CSR_PCISDRAMBASE & 0xfffffff0); -} - -unsigned long __bus_to_virt(unsigned long res) -{ - res -= (*CSR_PCISDRAMBASE & 0xfffffff0); - res += PAGE_OFFSET; - -#ifdef CONFIG_DEBUG_ERRORS - if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) { - printk("__bus_to_virt: invalid virtual address 0x%08lx\n", res); - __backtrace(); - } -#endif - return res; -} - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/mm-l7200.c linux.ac/arch/arm/mm/mm-l7200.c --- linux.vanilla/arch/arm/mm/mm-l7200.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mm/mm-l7200.c Sat Apr 14 01:16:46 2001 @@ -17,6 +17,9 @@ static struct map_desc l7200_io_desc[] __initdata = { { IO_BASE, IO_START, IO_SIZE, DOMAIN_IO, 0, 1 ,0 ,0}, { IO_BASE_2, IO_START_2, IO_SIZE_2, DOMAIN_IO, 0, 1 ,0 ,0}, + { AUX_BASE, AUX_START, AUX_SIZE, DOMAIN_IO, 0, 1 ,0 ,0}, + { FLASH1_BASE, FLASH1_START, FLASH1_SIZE, DOMAIN_IO, 0, 1 ,0 ,0}, + { FLASH2_BASE, FLASH2_START, FLASH2_SIZE, DOMAIN_IO, 0, 1 ,0 ,0}, LAST_DESC }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/mm-sa1100.c linux.ac/arch/arm/mm/mm-sa1100.c --- linux.vanilla/arch/arm/mm/mm-sa1100.c Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/arm/mm/mm-sa1100.c Sat Apr 14 01:16:46 2001 @@ -15,9 +15,8 @@ * */ #include <linux/config.h> -#include <linux/mm.h> +#include <linux/sched.h> #include <linux/init.h> -#include <linux/bootmem.h> #include <asm/hardware.h> #include <asm/pgtable.h> @@ -109,22 +108,9 @@ LAST_DESC }; -static struct map_desc thinclient_io_desc[] __initdata = { -#ifdef CONFIG_SA1100_THINCLIENT -#if 0 - { 0xe8000000, 0x00000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 when JP1 2-4 */ -#else - { 0xe8000000, 0x08000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 when JP1 3-4 */ -#endif - { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */ -#endif - LAST_DESC -}; - -static struct map_desc tifon_io_desc[] __initdata = { -#ifdef CONFIG_SA1100_TIFON - { 0xe8000000, 0x00000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */ - { 0xe8800000, 0x08000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 2 */ +static struct map_desc sherman_io_desc[] __initdata = { +#ifdef CONFIG_SA1100_SHERMAN + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash*/ #endif LAST_DESC }; @@ -138,9 +124,16 @@ static struct map_desc xp860_io_desc[] __initdata = { #ifdef CONFIG_SA1100_XP860 - { 0xf4000000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SCSI */ { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* LAN */ + { 0xf4000000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ +#endif + LAST_DESC +}; + +static struct map_desc pangolin_io_desc[] __initdata = { +#ifdef CONFIG_SA1100_PANGOLIN + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ #endif LAST_DESC }; @@ -153,8 +146,6 @@ if (machine_is_assabet()) desc = assabet_io_desc; - else if (machine_is_nanoengine()) - desc = nanoengine_io_desc; else if (machine_is_bitsy()) desc = bitsy_io_desc; else if (machine_is_cerf()) @@ -165,38 +156,21 @@ desc = graphicsclient_io_desc; else if (machine_is_lart()) desc = lart_io_desc; - else if (machine_is_thinclient()) - desc = thinclient_io_desc; - else if (machine_is_tifon()) - desc = tifon_io_desc; + else if (machine_is_nanoengine()) + desc = nanoengine_io_desc; + else if (machine_is_sherman()) + desc = sherman_io_desc; else if (machine_is_victor()) desc = victor_io_desc; else if (machine_is_xp860()) desc = xp860_io_desc; + else if (machine_is_pangolin()) + desc = pangolin_io_desc; if (desc) iotable_init(desc); } - -#ifdef CONFIG_DISCONTIGMEM - -/* - * Our node_data structure for discontigous memory. - * There is 4 possible nodes i.e. the 4 SA1100 RAM banks. - */ - -static bootmem_data_t node_bootmem_data[4]; - -pg_data_t sa1100_node_data[4] = -{ { bdata: &node_bootmem_data[0] }, - { bdata: &node_bootmem_data[1] }, - { bdata: &node_bootmem_data[2] }, - { bdata: &node_bootmem_data[3] } }; - -#endif - - /* * On Assabet, we must probe for the Neponset board *before* paging_init() * has occurred to actually determine the amount of RAM available. To do so, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/proc-sa110.S linux.ac/arch/arm/mm/proc-sa110.S --- linux.vanilla/arch/arm/mm/proc-sa110.S Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/arm/mm/proc-sa110.S Sat Apr 14 01:16:46 2001 @@ -556,7 +556,7 @@ mov pc, lr /* - * cpu_sa110_arm920_set_pte(ptep, pte) + * cpu_sa110_set_pte(ptep, pte) * * Set a PTE and flush it out */ @@ -737,7 +737,7 @@ b __sa110_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT .long cpu_sa110_info .long sa110_processor_functions .size __sa110_proc_info, . - __sa110_proc_info @@ -750,7 +750,7 @@ b __sa1100_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT .long cpu_sa1100_info .long sa1100_processor_functions .size __sa1100_proc_info, . - __sa1100_proc_info @@ -763,7 +763,7 @@ b __sa1100_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT .long cpu_sa1110_info .long sa1100_processor_functions .size __sa1110_proc_info, . - __sa1110_proc_info diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/small_page.c linux.ac/arch/arm/mm/small_page.c --- linux.vanilla/arch/arm/mm/small_page.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mm/small_page.c Sat Apr 14 01:16:46 2001 @@ -202,17 +202,6 @@ printk("Trying to free free small page from %p\n", __builtin_return_address(0)); } -unsigned long get_page_2k(int priority) -{ - return __get_small_page(priority, orders+0); -} - -void free_page_2k(unsigned long spage) -{ - __free_small_page(spage, orders+0); -} - -#if PAGE_SIZE > 8192 unsigned long get_page_8k(int priority) { return __get_small_page(priority, orders+1); @@ -222,4 +211,3 @@ { __free_small_page(spage, orders+1); } -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/Makefile linux.ac/arch/arm/nwfpe/Makefile --- linux.vanilla/arch/arm/nwfpe/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/nwfpe/Makefile Thu Apr 12 11:48:52 2001 @@ -1,7 +1,7 @@ # # linux/arch/arm/nwfpe/Makefile # -# Copyright (C) 1998, 1999 Philip Blundell +# Copyright (C) 1998, 1999, 2001 Philip Blundell # USE_STANDARD_AS_RULE := true @@ -14,7 +14,7 @@ list-multi := nwfpe.o -obj-$(CONFIG_NWFPE) += nwfpe.o +obj-$(CONFIG_FPE_NWFPE) += nwfpe.o nwfpe-objs := fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o \ fpmodule.o fpopcode.o softfloat.o \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/config.h linux.ac/arch/arm/nwfpe/config.h --- linux.vanilla/arch/arm/nwfpe/config.h Tue Aug 31 02:15:19 1999 +++ linux.ac/arch/arm/nwfpe/config.h Thu Jan 1 01:00:00 1970 @@ -1,31 +0,0 @@ -/* - NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 - - Direct questions, comments to Scott Bambrough <scottb@netwinder.org> - - 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 linux.vanilla/arch/arm/nwfpe/double_cpdo.c linux.ac/arch/arm/nwfpe/double_cpdo.c --- linux.vanilla/arch/arm/nwfpe/double_cpdo.c Tue Nov 28 01:07:59 2000 +++ linux.ac/arch/arm/nwfpe/double_cpdo.c Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 + (c) Rebel.COM, 1998,1999 Direct questions, comments to Scott Bambrough <scottb@netwinder.org> @@ -22,10 +22,6 @@ #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); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/entry.S linux.ac/arch/arm/nwfpe/entry.S --- linux.vanilla/arch/arm/nwfpe/entry.S Thu Oct 21 00:29:08 1999 +++ linux.ac/arch/arm/nwfpe/entry.S Thu Apr 12 11:48:52 2001 @@ -1,7 +1,7 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 - (c) Philip Blundell 1998-1999 + (c) Rebel.COM, 1998 + (c) 1998, 1999 Philip Blundell Direct questions, comments to Scott Bambrough <scottb@netwinder.org> @@ -86,7 +86,7 @@ ldr r5, [r4, #60] @ get contents of PC; sub r8, r5, #4 -.Lx2: ldrt r0, [r8], #0 @ get actual instruction into r0 +.Lx2: ldrt r0, [r8] @ get actual instruction into r0 emulate: bl EmulateAll @ emulate the instruction cmp r0, #0 @ was emulation successful @@ -115,15 +115,17 @@ mov r0, r6 @ prepare for EmulateAll() b emulate @ if r0 != 0, goto EmulateAll - @ We need to be prepared for the instruction at .Lx1 or .Lx2 - @ to fault. + @ We need to be prepared for the instructions at .Lx1 and .Lx2 + @ to fault. Emit the appropriate exception gunk to fix things up. + @ ??? For some reason, faults can happen at .Lx2 even with a + @ plain LDR instruction. Weird, but it seems harmless. .section .fixup,"ax" - .align -.Lfix: mov pc, r9 + .align 2 +.Lfix: mov pc, r9 @ let the user eat segfaults .previous .section __ex_table,"a" - .align 3 - .long .Lx2, .Lfix + .align 3 .long .Lx1, .Lfix + .long .Lx2, .Lfix .previous diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/entry26.S linux.ac/arch/arm/nwfpe/entry26.S --- linux.vanilla/arch/arm/nwfpe/entry26.S Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/arm/nwfpe/entry26.S Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 + (c) Rebel.COM, 1998 (c) Philip Blundell 1998-1999 Direct questions, comments to Scott Bambrough <scottb@netwinder.org> @@ -84,7 +84,7 @@ beq fpundefinstr @ no, return failure next: - ldrt r6, [r5], #4 @ get the next instruction and +.Lx1: ldrt r6, [r5], #4 @ get the next instruction and @ increment PC and r2, r6, #0x0F000000 @ test for FP insns @@ -110,3 +110,13 @@ adr lr, 1b orr lr, lr, #3 b EmulateAll @ if r0 != 0, goto EmulateAll + +.Lret: b ret_from_exception @ let the user eat segfaults + + @ We need to be prepared for the instruction at .Lx1 to fault. + @ Emit the appropriate exception gunk to fix things up. + .section __ex_table,"a" + .align 3 + .long .Lx1 + ldr lr, [lr, $(.Lret - .Lx1)/4] + .previous diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/extended_cpdo.c linux.ac/arch/arm/nwfpe/extended_cpdo.c --- linux.vanilla/arch/arm/nwfpe/extended_cpdo.c Tue Nov 28 01:07:59 2000 +++ linux.ac/arch/arm/nwfpe/extended_cpdo.c Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 + (c) Rebel.COM, 1998,1999 Direct questions, comments to Scott Bambrough <scottb@netwinder.org> @@ -22,8 +22,6 @@ #include "softfloat.h" #include "fpopcode.h" #include "fpa11.h" - -floatx80 getExtendedConstant(unsigned int); floatx80 floatx80_exp(floatx80 Fm); floatx80 floatx80_ln(floatx80 Fm); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/fpa11.c linux.ac/arch/arm/nwfpe/fpa11.c --- linux.vanilla/arch/arm/nwfpe/fpa11.c Thu Oct 21 00:29:08 1999 +++ linux.ac/arch/arm/nwfpe/fpa11.c Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 + (c) Rebel.COM, 1998,1999 Direct questions, comments to Scott Bambrough <scottb@netwinder.org> @@ -46,8 +46,8 @@ fpa11->fType[i] = typeNone; } - /* FPSR: set system id to FP_EMULATOR, clear all other bits */ - fpa11->fpsr = FP_EMULATOR; + /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ + fpa11->fpsr = FP_EMULATOR | BIT_AC; /* FPCR: set SB, AB and DA bits, clear all others */ #if MAINTAIN_FPCR diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/fpa11.inl linux.ac/arch/arm/nwfpe/fpa11.inl --- linux.vanilla/arch/arm/nwfpe/fpa11.inl Thu Oct 21 00:29:08 1999 +++ linux.ac/arch/arm/nwfpe/fpa11.inl Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 + (c) Rebel.COM, 1998,1999 Direct questions, comments to Scott Bambrough <scottb@netwinder.org> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/fpa11_cpdo.c linux.ac/arch/arm/nwfpe/fpa11_cpdo.c --- linux.vanilla/arch/arm/nwfpe/fpa11_cpdo.c Tue Nov 28 01:07:59 2000 +++ linux.ac/arch/arm/nwfpe/fpa11_cpdo.c Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 + (c) Rebel.COM, 1998,1999 Direct questions, comments to Scott Bambrough <scottb@netwinder.org> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/fpa11_cprt.c linux.ac/arch/arm/nwfpe/fpa11_cprt.c --- linux.vanilla/arch/arm/nwfpe/fpa11_cprt.c Tue Nov 28 01:07:59 2000 +++ linux.ac/arch/arm/nwfpe/fpa11_cprt.c Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 + (c) Rebel.COM, 1998,1999 (c) Philip Blundell, 1999 Direct questions, comments to Scott Bambrough <scottb@netwinder.org> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/fpmodule.c linux.ac/arch/arm/nwfpe/fpmodule.c --- linux.vanilla/arch/arm/nwfpe/fpmodule.c Tue Nov 28 01:07:59 2000 +++ linux.ac/arch/arm/nwfpe/fpmodule.c Thu Apr 12 11:48:52 2001 @@ -55,6 +55,8 @@ #else #define fp_send_sig send_sig #define kern_fp_enter fp_enter + +extern char fpe_type[]; #endif /* kernel function prototypes required */ @@ -72,24 +74,45 @@ /* Address of user registers on the kernel stack. */ unsigned int *userRegisters; -int __init fpe_init(void) +#ifdef MODULE +/* + * Return 0 if we can be unloaded. This can only happen if + * kern_fp_enter is still pointing at nwfpe_enter + */ +static int fpe_unload(void) +{ + return (kern_fp_enter == nwfpe_enter) ? 0 : 1; +} +#endif + +static int __init fpe_init(void) { - if (sizeof(FPA11) > sizeof(union fp_state)) + if (sizeof(FPA11) > sizeof(union fp_state)) { printk(KERN_ERR "nwfpe: bad structure size\n"); - else { - /* Display title, version and copyright information. */ - printk(KERN_WARNING "NetWinder Floating Point Emulator V0.95 " - "(c) 1998-1999 Rebel.com\n"); - - /* Save pointer to the old FP handler and then patch ourselves in */ - orig_fp_enter = kern_fp_enter; - kern_fp_enter = nwfpe_enter; + return -EINVAL; } +#ifdef MODULE + if (!mod_member_present(&__this_module, can_unload)) + return -EINVAL; + __this_module.can_unload = fpe_unload; +#else + if (fpe_type[0] && strcmp(fpe_type, "nwfpe")) + return 0; +#endif + + /* Display title, version and copyright information. */ + printk(KERN_WARNING "NetWinder Floating Point Emulator V0.95 " + "(c) 1998-1999 Rebel.com\n"); + + /* Save pointer to the old FP handler and then patch ourselves in */ + orig_fp_enter = kern_fp_enter; + kern_fp_enter = nwfpe_enter; + return 0; } -void __exit fpe_exit(void) +static void __exit fpe_exit(void) { /* Restore the values we saved earlier. */ kern_fp_enter = orig_fp_enter; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/fpmodule.inl linux.ac/arch/arm/nwfpe/fpmodule.inl --- linux.vanilla/arch/arm/nwfpe/fpmodule.inl Thu Oct 21 00:29:08 1999 +++ linux.ac/arch/arm/nwfpe/fpmodule.inl Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* - NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 Direct questions, comments to Scott Bambrough <scottb@netwinder.org> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/fpopcode.c linux.ac/arch/arm/nwfpe/fpopcode.c --- linux.vanilla/arch/arm/nwfpe/fpopcode.c Thu Oct 21 00:29:08 1999 +++ linux.ac/arch/arm/nwfpe/fpopcode.c Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 + (c) Rebel.COM, 1998,1999 Direct questions, comments to Scott Bambrough <scottb@netwinder.org> @@ -26,7 +26,7 @@ #include "fpmodule.h" #include "fpmodule.inl" -static floatx80 floatx80Constant[] = { +const floatx80 floatx80Constant[] = { { 0x0000, 0x0000000000000000ULL}, /* extended 0.0 */ { 0x3fff, 0x8000000000000000ULL}, /* extended 1.0 */ { 0x4000, 0x8000000000000000ULL}, /* extended 2.0 */ @@ -37,7 +37,7 @@ { 0x4002, 0xa000000000000000ULL} /* extended 10.0 */ }; -static float64 float64Constant[] = { +const float64 float64Constant[] = { 0x0000000000000000ULL, /* double 0.0 */ 0x3ff0000000000000ULL, /* double 1.0 */ 0x4000000000000000ULL, /* double 2.0 */ @@ -48,7 +48,7 @@ 0x4024000000000000ULL /* double 10.0 */ }; -static float32 float32Constant[] = { +const float32 float32Constant[] = { 0x00000000, /* single 0.0 */ 0x3f800000, /* single 1.0 */ 0x40000000, /* single 2.0 */ @@ -59,21 +59,6 @@ 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; @@ -135,10 +120,10 @@ return(nRc); } -/* contition code lookup table +/* condition 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] = { +static const unsigned short aCC[16] = { 0xF0F0, // EQ == Z set 0x0F0F, // NE 0xCCCC, // CS == C set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/fpopcode.h linux.ac/arch/arm/nwfpe/fpopcode.h --- linux.vanilla/arch/arm/nwfpe/fpopcode.h Tue Aug 31 02:15:19 1999 +++ linux.ac/arch/arm/nwfpe/fpopcode.h Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 + (c) Rebel.COM, 1998,1999 Direct questions, comments to Scott Bambrough <scottb@netwinder.org> @@ -366,11 +366,25 @@ /* 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); +static inline const floatx80 getExtendedConstant(const unsigned int nIndex) +{ + extern const floatx80 floatx80Constant[]; + return floatx80Constant[nIndex]; +} + +static inline const float64 getDoubleConstant(const unsigned int nIndex) +{ + extern const float64 float64Constant[]; + return float64Constant[nIndex]; +} + +static inline const float32 getSingleConstant(const unsigned int nIndex) +{ + extern const float32 float32Constant[]; + return float32Constant[nIndex]; +} -unsigned int getRegisterCount(const unsigned int opcode); -unsigned int getDestinationSize(const unsigned int opcode); +extern unsigned int getRegisterCount(const unsigned int opcode); +extern unsigned int getDestinationSize(const unsigned int opcode); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/single_cpdo.c linux.ac/arch/arm/nwfpe/single_cpdo.c --- linux.vanilla/arch/arm/nwfpe/single_cpdo.c Thu Oct 21 00:29:08 1999 +++ linux.ac/arch/arm/nwfpe/single_cpdo.c Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 + (c) Rebel.COM, 1998,1999 Direct questions, comments to Scott Bambrough <scottb@netwinder.org> @@ -22,8 +22,6 @@ #include "softfloat.h" #include "fpopcode.h" #include "fpa11.h" - -float32 getSingleConstant(unsigned int); float32 float32_exp(float32 Fm); float32 float32_ln(float32 Fm); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/tools/getconstants.c linux.ac/arch/arm/tools/getconstants.c --- linux.vanilla/arch/arm/tools/getconstants.c Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/arm/tools/getconstants.c Thu Apr 12 11:48:52 2001 @@ -14,14 +14,8 @@ #include <asm/pgtable.h> #include <asm/uaccess.h> -/* - * 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. +#ifndef __APCS_32__ +#error APCS-32 required #endif #define OFF_TSK(n) (unsigned long)&(((struct task_struct *)0)->n) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/tools/mach-types linux.ac/arch/arm/tools/mach-types --- linux.vanilla/arch/arm/tools/mach-types Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/arm/tools/mach-types Thu Apr 12 11:48:52 2001 @@ -1,10 +1,12 @@ # Database of machine macros and numbers # +# This file is linux/arch/arm/tools/mach-types +# # Please do not send patches to this file; it is automatically generated! # To add an entry into this database, please see Documentation/arm/README, # or contact rmk@arm.linux.org.uk # -# Last update: Fri Feb 9 22:27:32 2001 +# Last update: Sat Apr 7 09:45:09 2001 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -35,7 +37,7 @@ assabet SA1100_ASSABET ASSABET 25 victor SA1100_VICTOR VICTOR 26 lart SA1100_LART LART 27 -ranger ARCH_RANGER RANGER 28 +ranger SA1100_RANGER RANGER 28 graphicsclient SA1100_GRAPHICSCLIENT GRAPHICSCLIENT 29 xp860 SA1100_XP860 XP860 30 cerf SA1100_CERF CERF 31 @@ -48,7 +50,7 @@ netport SA1100_NETPORT NETPORT 38 pangolin SA1100_PANGOLIN PANGOLIN 39 yopy SA1100_YOPY YOPY 40 -coolidge SA1100_COOLIDGE coolidge 41 +coolidge SA1100_COOLIDGE COOLIDGE 41 huw_webpanel SA1100_HUW_WEBPANEL HUW_WEBPANEL 42 spotme ARCH_SPOTME SPOTME 43 freebird ARCH_FREEBIRD FREEBIRD 44 @@ -65,6 +67,16 @@ webpal ARCH_WEBPAL WEBPAL 55 linpda SA1100_LINPDA LINPDA 56 anakin ARCH_ANAKIN ANAKIN 57 +mvi SA1100_MVI MVI 58 +jupiter SA1100_JUPITER JUPITER 59 +psionw ARCH_PSIONW PSIONW 60 +aln SA1100_ALN ALN 61 +camelot ARCH_CAMELOT CAMELOT 62 +gds2200 SA1100_GDS2200 GDS2200 63 +psion_series7 SA1100_PSION_SERIES7 PSION_SERIES7 64 +xfile SA1100_XFILE XFILE 65 +accelent_ep9312 ARCH_ACCELENT_EP9312 ACCELENT_EP9312 66 +ic200 ARCH_IC200 IC200 67 # The following are unallocated empeg SA1100_EMPEG EMPEG diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/Makefile linux.ac/arch/cris/Makefile --- linux.vanilla/arch/cris/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/Makefile Tue Apr 10 18:04:53 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.11 2000/11/27 17:58:30 bjornw Exp $ +# $Id: Makefile,v 1.15 2001/02/16 17:50:04 larsv Exp $ # cris/Makefile # # This file is included by the global makefile so that you can add your own @@ -25,7 +25,7 @@ # regenerating stuff (even for incremental linking of subsystems!) is # even more nauseating. LD = if [ ! -e $(LD_SCRIPT).tmp -o $(LD_SCRIPT) -nt $(LD_SCRIPT).tmp ]; then \ - sed -e s/@ETRAX_DRAM_BASE@/0x$(ETRAX_DRAM_BASE)/ \ + sed -e s/@ETRAX_DRAM_VIRTUAL_BASE@/0x$(ETRAX_DRAM_VIRTUAL_BASE)/ \ -e s/@ETRAX_DRAM_SIZE_M@/$(ETRAX_DRAM_SIZE)/ \ < $(LD_SCRIPT) > $(LD_SCRIPT).tmp; \ else true; \ @@ -49,7 +49,7 @@ HEAD := arch/cris/kernel/head.o -SUBDIRS += arch/cris/kernel arch/cris/mm arch/cris/lib arch/cris/drivers +SUBDIRS += arch/cris/kernel arch/cris/mm arch/cris/lib arch/cris/drivers arch/cris/boot/rescue CORE_FILES += arch/cris/kernel/kernel.o arch/cris/mm/mm.o arch/cris/drivers/drivers.o LIBGCC = $(shell $(CC) $(CFLAGS) -print-file-name=libgcc.a) LIBS := $(TOPDIR)/arch/cris/lib/lib.a $(LIBS) $(TOPDIR)/arch/cris/lib/lib.a $(LIBGCC) @@ -76,10 +76,18 @@ cramfs: ## cramfs - Creates a cramfs image - mkcramfs -p 8192 root cramfs.img + mkcramfs -b 8192 root cramfs.img cat vmlinux.bin cramfs.img >timage -zImage: vmlinux +clinux: vmlinux.bin decompress.bin rescue.bin + +decompress.bin: dummy + @make -C arch/cris/boot/compressed decompress.bin + +rescue.bin: dummy + @make -C arch/cris/boot/rescue rescue.bin + +zImage: vmlinux.bin ## zImage - Compressed kernel (gzip) @$(MAKEBOOT) zImage diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/boot/compressed/Makefile linux.ac/arch/cris/boot/compressed/Makefile --- linux.vanilla/arch/cris/boot/compressed/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/boot/compressed/Makefile Tue Apr 10 18:04:53 2001 @@ -16,11 +16,14 @@ all: vmlinuz -vmlinuz: piggy.img $(OBJECTS) - $(LD) -mcriself -T decompress.ld -o decompress.o $(OBJECTS) +decompress.bin: $(OBJECTS) + $(LD) -T decompress.ld -o decompress.o $(OBJECTS) $(OBJCOPY) -O binary --remove-section=.bss decompress.o decompress.bin # save it for mkprod in the topdir. cp decompress.bin $(TOPDIR) + + +vmlinuz: piggy.img decompress.bin cat decompress.bin piggy.img $(TOPDIR)/cramfs.img > vmlinuz rm -f piggy.img diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/boot/compressed/decompress.ld linux.ac/arch/cris/boot/compressed/decompress.ld --- linux.vanilla/arch/cris/boot/compressed/decompress.ld Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/boot/compressed/decompress.ld Tue Apr 10 18:04:53 2001 @@ -1,3 +1,5 @@ +OUTPUT_FORMAT(elf32-us-cris) + MEMORY { dram : ORIGIN = 0x40700000, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/boot/compressed/head.S linux.ac/arch/cris/boot/compressed/head.S --- linux.vanilla/arch/cris/boot/compressed/head.S Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/boot/compressed/head.S Tue Apr 10 18:04:53 2001 @@ -8,7 +8,6 @@ * */ -#include <linux/config.h> #define ASSEMBLER_MACROS_ONLY #include <asm/sv_addr_ag.h> @@ -22,23 +21,24 @@ nop di -#ifndef CONFIG_SVINTO_SIM - - ;; We need to setup the bus registers before we start using the DRAM + ;; We need to initialze DRAM registers before we start using the DRAM +#include "../../lib/dram_init.S" + +dram_init_finished: + + ;; Initiate the PA and PB ports - move.d DEF_R_WAITSTATES, r0 - move.d r0, [R_WAITSTATES] + move.b DEF_R_PORT_PA_DATA, r0 + move.b r0, [R_PORT_PA_DATA] - move.d DEF_R_BUS_CONFIG, r0 - move.d r0, [R_BUS_CONFIG] - - move.d DEF_R_DRAM_CONFIG, r0 - move.d r0, [R_DRAM_CONFIG] + move.b DEF_R_PORT_PA_DIR, r0 + move.b r0, [R_PORT_PA_DIR] - move.d DEF_R_DRAM_TIMING, r0 - move.d r0, [R_DRAM_TIMING] + move.b DEF_R_PORT_PB_DATA, r0 + move.b r0, [R_PORT_PB_DATA] -#endif + move.b DEF_R_PORT_PB_DIR, r0 + move.b r0, [R_PORT_PB_DIR] ;; Setup the stack to a suitably high address. ;; We assume 8 MB is the minimum DRAM in an eLinux @@ -83,7 +83,7 @@ ;; Do the decompression and save compressed size in _inptr jsr _decompress_kernel - + ;; Put start address of cramfs in r9 so the kernel can use it ;; when mounting from flash @@ -91,7 +91,6 @@ add.d [_inptr], r9 ; size of compressed kernel ;; Enter the decompressed kernel - jump 0x40004000 ; kernel is linked to this address .data diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/boot/compressed/misc.c linux.ac/arch/cris/boot/compressed/misc.c --- linux.vanilla/arch/cris/boot/compressed/misc.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/cris/boot/compressed/misc.c Tue Apr 10 18:04:53 2001 @@ -13,7 +13,7 @@ */ /* where the piggybacked kernel image expects itself to live. - * it is the same address we use when we network load an uncompressed + * it is the same adress we use when we network load an uncompressed * image into DRAM, and it is the address the kernel is linked to live * at by etrax100.ld. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/boot/rescue/Makefile linux.ac/arch/cris/boot/rescue/Makefile --- linux.vanilla/arch/cris/boot/rescue/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/boot/rescue/Makefile Tue Apr 10 18:04:53 2001 @@ -0,0 +1,50 @@ +# +# Makefile for rescue code +# +ifndef TOPDIR +TOPDIR = ../../../.. +endif +CC = gcc-cris -I $(TOPDIR)/include +CFLAGS = -O2 +LD = ld-cris +OBJCOPY = objcopy-cris + +all: rescue.bin testrescue.bin kimagerescue.bin + +rescue: rescue.bin + # do nothing + +rescue.bin: head.o + $(LD) -T rescue.ld -o rescue.o head.o + $(OBJCOPY) -O binary --remove-section=.bss rescue.o rescue.bin + cp rescue.bin $(TOPDIR) + +testrescue.bin: testrescue.o + $(OBJCOPY) -O binary --remove-section=.bss testrescue.o tr.bin +# Pad it to 784 bytes + dd if=/dev/zero of=tmp2423 bs=1 count=784 + cat tr.bin tmp2423 >testrescue_tmp.bin + dd if=testrescue_tmp.bin of=testrescue.bin bs=1 count=784 + rm tr.bin tmp2423 testrescue_tmp.bin + +kimagerescue.bin: kimagerescue.o + $(OBJCOPY) -O binary --remove-section=.bss kimagerescue.o ktr.bin +# Pad it to 784 bytes, that's what the rescue loader expects + dd if=/dev/zero of=tmp2423 bs=1 count=784 + cat ktr.bin tmp2423 >kimagerescue_tmp.bin + dd if=kimagerescue_tmp.bin of=kimagerescue.bin bs=1 count=784 + rm ktr.bin tmp2423 kimagerescue_tmp.bin + +head.o: head.S + $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o + +testrescue.o: testrescue.S + $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o + +kimagerescue.o: kimagerescue.S + $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o + +clean: + rm -f *.o *.bin + +fastdep: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/boot/rescue/head.S linux.ac/arch/cris/boot/rescue/head.S --- linux.vanilla/arch/cris/boot/rescue/head.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/boot/rescue/head.S Tue Apr 10 18:04:53 2001 @@ -0,0 +1,323 @@ + ;; $Id: head.S,v 1.3 2001/02/14 16:57:25 larsv Exp $ + ;; + ;; Rescue code, made to reside at the beginning of the + ;; flash-memory. when it starts, it checks a partition + ;; table at the first sector after the rescue sector. + ;; the partition table was generated by the product builder + ;; script and contains offsets, lengths, types and checksums + ;; for each partition that this code should check. + ;; + ;; If any of the checksums fail, we assume the flash is so + ;; corrupt that we cant use it to boot into the ftp flash + ;; loader, and instead we initialize the serial port to + ;; receive a flash-loader and new flash image. we dont include + ;; any flash code here, but just accept a certain amount of + ;; bytes from the serial port and jump into it. the downloaded + ;; code is put in the cache. + ;; + ;; The partitiontable is designed so that it is transparent to + ;; code execution - it has a relative branch opcode in the + ;; beginning that jumps over it. each entry contains extra + ;; data so we can add stuff later. + ;; + ;; Partition table format: + ;; + ;; Code transparency: + ;; + ;; 2 bytes [opcode 'nop'] + ;; 2 bytes [opcode 'di'] + ;; 4 bytes [opcode 'ba <offset>', 8-bit or 16-bit version] + ;; 2 bytes [opcode 'nop', delay slot] + ;; + ;; Table validation (at +10): + ;; + ;; 2 bytes [magic/version word for partitiontable - 0xef, 0xbe] + ;; 2 bytes [length of all entries plus the end marker] + ;; 4 bytes [checksum for the partitiontable itself] + ;; + ;; Entries, each with the following format, last has offset -1: + ;; + ;; 4 bytes [offset in bytes, from start of flash] + ;; 4 bytes [length in bytes of partition] + ;; 4 bytes [checksum, simple longword sum] + ;; 2 bytes [partition type] + ;; 2 bytes [flags, only bit 0 used, ro/rw = 1/0] + ;; 16 bytes [reserved for future use] + ;; + ;; End marker + ;; + ;; 4 bytes [-1] + ;; + ;; 10 bytes [0, padding] + ;; + ;; Bit 0 in flags signifies RW or RO. The rescue code only bothers + ;; to check the checksum for RO partitions, since the others will + ;; change its data without updating the checksums. A 1 in bit 0 + ;; means RO, 0 means RW. That way, it is possible to set a partition + ;; in RO mode initially, and later mark it as RW, since you can always + ;; write 0's to the flash. + ;; + ;; During the wait for serial input, the status LED will flash so the + ;; user knows something went wrong. + ;; + ;; Copyright (C) 1999 Axis Communications AB + +#include <linux/config.h> +#define ASSEMBLER_MACROS_ONLY +#include <asm/sv_addr_ag.h> + + ;; The partitiontable is looked for at the first sector after the boot + ;; sector. Sector size is 65536 bytes in all flashes we use. + +#define PTABLE_START 0x10000 +#define PTABLE_MAGIC 0xbeef + + ;; The normal Etrax100 on-chip boot ROM does serial boot at 0x380000f0. + ;; That is not where we put our downloaded serial boot-code. The length is + ;; enough for downloading code that loads the rest of itself (after + ;; having setup the DRAM etc). It is the same length as the on-chip + ;; ROM loads, so the same host loader can be used to load a rescued + ;; product as well as one booted through the Etrax serial boot code. + +#define CODE_START 0x40000000 +#define CODE_LENGTH 784 + +#ifdef CONFIG_RESCUE_SER0 +#define SERXOFF R_SERIAL0_XOFF +#define SERBAUD R_SERIAL0_BAUD +#define SERRECC R_SERIAL0_REC_CTRL +#define SERRDAT R_SERIAL0_REC_DATA +#define SERSTAT R_SERIAL0_STATUS +#endif +#ifdef CONFIG_RESCUE_SER1 +#define SERXOFF R_SERIAL1_XOFF +#define SERBAUD R_SERIAL1_BAUD +#define SERRECC R_SERIAL1_REC_CTRL +#define SERRDAT R_SERIAL1_REC_DATA +#define SERSTAT R_SERIAL1_STATUS +#endif +#ifdef CONFIG_RESCUE_SER2 +#define SERXOFF R_SERIAL2_XOFF +#define SERBAUD R_SERIAL2_BAUD +#define SERRECC R_SERIAL2_REC_CTRL +#define SERRDAT R_SERIAL2_REC_DATA +#define SERSTAT R_SERIAL2_STATUS +#endif +#ifdef CONFIG_RESCUE_SER3 +#define SERXOFF R_SERIAL3_XOFF +#define SERBAUD R_SERIAL3_BAUD +#define SERRECC R_SERIAL3_REC_CTRL +#define SERRDAT R_SERIAL3_REC_DATA +#define SERSTAT R_SERIAL3_STATUS +#endif + +#define NOP_DI 0xf025050f + + .text + + ;; This is the entry point of the rescue code + ;; 0x80000000 if loaded in flash (as it should be) + ;; since etrax actually starts at address 2 when booting from flash, we + ;; put a nop (2 bytes) here first so we dont accidentally skip the di + + nop + di + + jump in_cache ; enter cached area instead +in_cache: + + ;; first put a jump test to give a possibility of upgrading the rescue code + ;; without erasing/reflashing the sector. we put a longword of -1 here and if + ;; its not -1, we jump using the value as jump target. since we can always + ;; change 1's to 0's without erasing the sector, it is possible to add new + ;; code after this and altering the jumptarget in an upgrade. + +jtcd: move.d [jumptarget], r0 + cmp.d 0xffffffff, r0 + beq no_newjump + nop + + jump [r0] + +jumptarget: + .dword 0xffffffff ; can be overwritten later to insert new code + +no_newjump: + ;; We need to setup the bus registers before we start using the DRAM +#include "../../lib/dram_init.S" + + ;; we now should go through the checksum-table and check the listed + ;; partitions for errors. + + move.d PTABLE_START, r3 + move.d [r3], r0 + cmp.d NOP_DI, r0 ; make sure the nop/di is there... + bne do_rescue + nop + + ;; skip the code transparency block (10 bytes). + + addq 10, r3 + + ;; check for correct magic + + move.w [r3+], r0 + cmp.w PTABLE_MAGIC, r0 + bne do_rescue ; didn't recognize - trig rescue + nop + + ;; check for correct ptable checksum + + movu.w [r3+], r2 ; ptable length + move.d r2, r8 ; save for later, length of total ptable + addq 28, r8 ; account for the rest + move.d [r3+], r4 ; ptable checksum + move.d r3, r1 + jsr checksum ; r1 source, r2 length, returns in r0 + + cmp.d r0, r4 + bne do_rescue ; didn't match - trig rescue + nop + + ;; ptable is ok. validate each entry. + + moveq -1, r7 + +ploop: move.d [r3+], r1 ; partition offset (from ptable start) + bne notfirst ; check if its the partition containing ptable + nop ; yes.. + move.d r8, r1 ; for its checksum check, skip the ptable + move.d [r3+], r2 ; partition length + sub.d r8, r2 ; minus the ptable length + ba bosse + nop +notfirst: + cmp.d -1, r1 ; the end of the ptable ? + beq flash_ok ; if so, the flash is validated + move.d [r3+], r2 ; partition length +bosse: move.d [r3+], r5 ; checksum + move.d [r3+], r4 ; type and flags + addq 16, r3 ; skip the reserved bytes + btstq 16, r4 ; check ro flag + bpl ploop ; rw partition, skip validation + nop + btstq 17, r4 ; check bootable flag + bpl 1f + nop + move.d r1, r7 ; remember boot partition offset +1: + + add.d PTABLE_START, r1 + + jsr checksum ; checksum the partition + + cmp.d r0, r5 + beq ploop ; checksums matched, go to next entry + nop + + ;; otherwise fall through to the rescue code. + +do_rescue: + ;; setup port PA and PB default initial directions and data + ;; (so we can flash LEDs, and so that DTR and others are set) + + move.b DEF_R_PORT_PA_DIR, r0 + move.b r0, [R_PORT_PA_DIR] + move.b DEF_R_PORT_PA_DATA, r0 + move.b r0, [R_PORT_PA_DATA] + + move.b DEF_R_PORT_PB_DIR, r0 + move.b r0, [R_PORT_PB_DIR] + move.b DEF_R_PORT_PB_DATA, r0 + move.b r0, [R_PORT_PB_DATA] + + ;; setup the serial port at 115200 baud + + moveq 0, r0 + move.d r0, [SERXOFF] + + move.b 0x99, r0 + move.b r0, [SERBAUD] ; 115.2kbaud for both transmit and receive + + move.b 0x40, r0 ; rec enable + move.b r0, [SERRECC] + + moveq 0, r1 ; "timer" to clock out a LED red flash + move.d CODE_START, r3 ; destination counter + movu.w CODE_LENGTH, r4 ; length + +wait_ser: + addq 1, r1 +#ifndef CONFIG_ETRAX_NO_LEDS +#ifdef CONFIG_ETRAX_PA_LEDS + move.b DEF_R_PORT_PA_DATA, r2 +#endif +#ifdef CONFIG_ETRAX_PB_LEDS + move.b DEF_R_PORT_PB_DATA, r2 +#endif + move.d (1 << CONFIG_ETRAX_LED1R) | (1 << CONFIG_ETRAX_LED2R), r0 + btstq 16, r1 + bpl 1f + nop + or.d r0, r2 ; set bit + ba 2f + nop +1: not r0 ; clear bit + and.d r0, r2 +2: +#ifdef CONFIG_ETRAX_PA_LEDS + move.b r2, [R_PORT_PA_DATA] +#endif +#ifdef CONFIG_ETRAX_PB_LEDS + move.b r2, [R_PORT_PB_DATA] +#endif +#ifdef CONFIG_ETRAX_90000000_LEDS + move.b r2, [0x90000000] +#endif +#endif + + ;; check if we got something on the serial port + + move.b [SERSTAT], r0 + btstq 0, r0 ; data_avail + bpl wait_ser + nop + + ;; got something - copy the byte and loop + + move.b [SERRDAT], r0 + move.b r0, [r3+] + + subq 1, r4 ; decrease length + bne wait_ser + nop + + ;; jump into downloaded code + + jump CODE_START + +flash_ok: + ;; check r7, which contains either -1 or the partition to boot from + + cmp.d -1, r7 + bne 1f + nop + move.d PTABLE_START, r7; otherwise use the ptable start +1: + jump r7 ; boot! + + + ;; Helper subroutines + + ;; Will checksum by simple addition + ;; r1 - source + ;; r2 - length in bytes + ;; result will be in r0 +checksum: + moveq 0, r0 +1: addu.b [r1+], r0 + subq 1, r2 + bne 1b + nop + ret + nop diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/boot/rescue/kimagerescue.S linux.ac/arch/cris/boot/rescue/kimagerescue.S --- linux.vanilla/arch/cris/boot/rescue/kimagerescue.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/boot/rescue/kimagerescue.S Tue Apr 10 18:04:53 2001 @@ -0,0 +1,143 @@ + ;; $Id: kimagerescue.S,v 1.2 2001/02/14 16:57:25 larsv Exp $ + ;; + ;; Rescue code to be prepended on a kimage and copied to the + ;; rescue serial port. + ;; This is called from the rescue code, it will copy received data to + ;; 4000500 and after a timeout jump to it. + +#include <linux/config.h> +#define ASSEMBLER_MACROS_ONLY +#include <asm/sv_addr_ag.h> + +#define CODE_START 0x40000500 +#define CODE_LENGTH 784 +#define TIMEOUT_VALUE 1000 + + +#ifdef CONFIG_RESCUE_SER0 +#define SERXOFF R_SERIAL0_XOFF +#define SERBAUD R_SERIAL0_BAUD +#define SERRECC R_SERIAL0_REC_CTRL +#define SERRDAT R_SERIAL0_REC_DATA +#define SERSTAT R_SERIAL0_STATUS +#endif +#ifdef CONFIG_RESCUE_SER1 +#define SERXOFF R_SERIAL1_XOFF +#define SERBAUD R_SERIAL1_BAUD +#define SERRECC R_SERIAL1_REC_CTRL +#define SERRDAT R_SERIAL1_REC_DATA +#define SERSTAT R_SERIAL1_STATUS +#endif +#ifdef CONFIG_RESCUE_SER2 +#define SERXOFF R_SERIAL2_XOFF +#define SERBAUD R_SERIAL2_BAUD +#define SERRECC R_SERIAL2_REC_CTRL +#define SERRDAT R_SERIAL2_REC_DATA +#define SERSTAT R_SERIAL2_STATUS +#endif +#ifdef CONFIG_RESCUE_SER3 +#define SERXOFF R_SERIAL3_XOFF +#define SERBAUD R_SERIAL3_BAUD +#define SERRECC R_SERIAL3_REC_CTRL +#define SERRDAT R_SERIAL3_REC_DATA +#define SERSTAT R_SERIAL3_STATUS +#endif + + .text + ;; This is the entry point of the rescue code + ;; 0x80000000 if loaded in flash (as it should be) + ;; since etrax actually starts at address 2 when booting from flash, we + ;; put a nop (2 bytes) here first so we dont accidentally skip the di + + nop + di +#ifndef CONFIG_SVINTO_SIM + ;; setup port PA and PB default initial directions and data + ;; (so we can flash LEDs, and so that DTR and others are set) + + move.b DEF_R_PORT_PA_DIR, r0 + move.b r0, [R_PORT_PA_DIR] + move.b DEF_R_PORT_PA_DATA, r0 + move.b r0, [R_PORT_PA_DATA] + + move.b DEF_R_PORT_PB_DIR, r0 + move.b r0, [R_PORT_PB_DIR] + move.b DEF_R_PORT_PB_DATA, r0 + move.b r0, [R_PORT_PB_DATA] + + ;; We need to setup the bus registers before we start using the DRAM +#include "../../lib/dram_init.S" + +#endif + ;; Setup the stack to a suitably high address. + ;; We assume 8 MB is the minimum DRAM in an eLinux + ;; product and put the sp at the top for now. + + move.d 0x40800000, sp + + ;; setup the serial port at 115200 baud + + moveq 0, r0 + move.d r0, [SERXOFF] + + move.b 0x99, r0 + move.b r0, [SERBAUD] ; 115.2kbaud for both transmit and receive + + move.b 0x40, r0 ; rec enable + move.b r0, [SERRECC] + + + moveq 0, r1 ; "timer" to clock out a LED red flash + move.d CODE_START, r3 ; destination counter + move.d CODE_LENGTH, r4 ; length + move.d TIMEOUT_VALUE, r5 ; "timeout" until jump + +wait_ser: + addq 1, r1 + subq 1, r5 ; decrease timeout + beq jump_start ; timed out + nop +#ifndef CONFIG_ETRAX_NO_LEDS +#ifdef CONFIG_ETRAX_PA_LEDS + move.b DEF_R_PORT_PA_DATA, r2 +#endif +#ifdef CONFIG_ETRAX_PB_LEDS + move.b DEF_R_PORT_PB_DATA, r2 +#endif + move.d (1 << CONFIG_ETRAX_LED1R) | (1 << CONFIG_ETRAX_LED2R), r0 + btstq 16, r1 + bpl 1f + nop + or.d r0, r2 ; set bit + ba 2f + nop +1: not r0 ; clear bit + and.d r0, r2 +2: +#ifdef CONFIG_ETRAX_PA_LEDS + move.b r2, [R_PORT_PA_DATA] +#endif +#ifdef CONFIG_ETRAX_PB_LEDS + move.b r2, [R_PORT_PB_DATA] +#endif +#endif + + ;; check if we got something on the serial port + + move.b [SERSTAT], r0 + btstq 0, r0 ; data_avail + bpl wait_ser + nop + + ;; got something - copy the byte and loop + + move.b [SERRDAT], r0 + move.b r0, [r3+] + move.d TIMEOUT_VALUE, r5 ; reset "timeout" + subq 1, r4 ; decrease length + bne wait_ser + nop +jump_start: + ;; jump into downloaded code + + jump CODE_START diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/boot/rescue/rescue.ld linux.ac/arch/cris/boot/rescue/rescue.ld --- linux.vanilla/arch/cris/boot/rescue/rescue.ld Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/boot/rescue/rescue.ld Tue Apr 10 18:04:53 2001 @@ -0,0 +1,20 @@ +MEMORY + { + flash : ORIGIN = 0x00000000, + LENGTH = 0x00100000 + } + +SECTIONS +{ + .text : + { + _stext = . ; + *(.text) + _etext = . ; + } > flash + .data : + { + *(.data) + _edata = . ; + } > flash +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/boot/rescue/testrescue.S linux.ac/arch/cris/boot/rescue/testrescue.S --- linux.vanilla/arch/cris/boot/rescue/testrescue.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/boot/rescue/testrescue.S Tue Apr 10 18:04:53 2001 @@ -0,0 +1,25 @@ + ;; $Id: testrescue.S,v 1.1 2001/01/31 15:32:09 johana Exp $ + ;; + ;; Simple testcode to download by the rescue block. + ;; Just lits some LEDs to show it was downloaded correctly. + ;; + ;; Copyright (C) 1999 Axis Communications AB + +#define ASSEMBLER_MACROS_ONLY +#include <asm/sv_addr_ag.h> + + .text + + nop + nop + moveq -1, r2 + move.b r2, [R_PORT_PA_DIR] + moveq 0, r2 + move.b r2, [R_PORT_PA_DATA] + +endless: + nop + ba endless + nop + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/boot/tools/build.c linux.ac/arch/cris/boot/tools/build.c --- linux.vanilla/arch/cris/boot/tools/build.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/boot/tools/build.c Tue Apr 10 18:04:53 2001 @@ -0,0 +1,288 @@ +/* + * linux/tools/build.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * This file builds a disk-image from three different files: + * + * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest + * - setup: 8086 machine code, sets up system parm + * - system: 80386 code for actual system + * + * It does some checking that all files are of the correct type, and + * just writes the result to stdout, removing headers and padding to + * the right amount. It also writes some system data to stderr. + */ + +/* + * Changes by tytso to allow root device specification + * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 + * Cross compiling fixes by Gertjan van Wingerde, July 1996 + */ + +#include <stdio.h> /* fprintf */ +#include <string.h> +#include <stdlib.h> /* contains exit */ +#include <sys/types.h> /* unistd.h needs this */ +#include <sys/stat.h> +#include <sys/sysmacros.h> +#include <unistd.h> /* contains read/write */ +#include <fcntl.h> +#include <linux/a.out.h> +#include <errno.h> + +#define MINIX_HEADER 32 + +#define N_MAGIC_OFFSET 1024 +#ifndef __BFD__ +static int GCC_HEADER = sizeof(struct exec); +#endif + +#ifdef __BIG_KERNEL__ +#define SYS_SIZE 0xffff +#else +#define SYS_SIZE DEF_SYSSIZE +#endif + +#define DEFAULT_MAJOR_ROOT 0 +#define DEFAULT_MINOR_ROOT 0 + +/* max nr of sectors of setup: don't change unless you also change + * bootsect etc */ +#define SETUP_SECTS 4 + +#define STRINGIFY(x) #x + +typedef union { + int i; + long l; + short s[2]; + char b[4]; +} conv; + +long intel_long(long l) +{ + conv t; + + t.b[0] = l & 0xff; l >>= 8; + t.b[1] = l & 0xff; l >>= 8; + t.b[2] = l & 0xff; l >>= 8; + t.b[3] = l & 0xff; l >>= 8; + return t.l; +} + +int intel_int(int i) +{ + conv t; + + t.b[0] = i & 0xff; i >>= 8; + t.b[1] = i & 0xff; i >>= 8; + t.b[2] = i & 0xff; i >>= 8; + t.b[3] = i & 0xff; i >>= 8; + return t.i; +} + +short intel_short(short l) +{ + conv t; + + t.b[0] = l & 0xff; l >>= 8; + t.b[1] = l & 0xff; l >>= 8; + return t.s[0]; +} + +void die(const char * str) +{ + fprintf(stderr,"%s\n",str); + exit(1); +} + +void usage(void) +{ + die("Usage: build bootsect setup system [rootdev] [> image]"); +} + +int main(int argc, char ** argv) +{ + int i,c,id,sz,tmp_int; + unsigned long sys_size, tmp_long; + char buf[1024]; +#ifndef __BFD__ + struct exec *ex = (struct exec *)buf; +#endif + char major_root, minor_root; + struct stat sb; + unsigned char setup_sectors; + + if ((argc < 4) || (argc > 5)) + usage(); + if (argc > 4) { + if (!strcmp(argv[4], "CURRENT")) { + if (stat("/", &sb)) { + perror("/"); + die("Couldn't stat /"); + } + major_root = major(sb.st_dev); + minor_root = minor(sb.st_dev); + } else if (strcmp(argv[4], "FLOPPY")) { + if (stat(argv[4], &sb)) { + perror(argv[4]); + die("Couldn't stat root device."); + } + major_root = major(sb.st_rdev); + minor_root = minor(sb.st_rdev); + } else { + major_root = 0; + minor_root = 0; + } + } else { + major_root = DEFAULT_MAJOR_ROOT; + minor_root = DEFAULT_MINOR_ROOT; + } + fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root); + for (i=0;i<sizeof buf; i++) buf[i]=0; + if ((id=open(argv[1],O_RDONLY,0))<0) + die("Unable to open 'boot'"); + if (read(id,buf,MINIX_HEADER) != MINIX_HEADER) + die("Unable to read header of 'boot'"); + if (((long *) buf)[0]!=intel_long(0x04100301)) + die("Non-Minix header of 'boot'"); + if (((long *) buf)[1]!=intel_long(MINIX_HEADER)) + die("Non-Minix header of 'boot'"); + if (((long *) buf)[3] != 0) + die("Illegal data segment in 'boot'"); + if (((long *) buf)[4] != 0) + die("Illegal bss in 'boot'"); + if (((long *) buf)[5] != 0) + die("Non-Minix header of 'boot'"); + if (((long *) buf)[7] != 0) + die("Illegal symbol table in 'boot'"); + i=read(id,buf,sizeof buf); + fprintf(stderr,"Boot sector %d bytes.\n",i); + if (i != 512) + die("Boot block must be exactly 512 bytes"); + if ((*(unsigned short *)(buf+510)) != (unsigned short)intel_short(0xAA55)) + die("Boot block hasn't got boot flag (0xAA55)"); + buf[508] = (char) minor_root; + buf[509] = (char) major_root; + i=write(1,buf,512); + if (i!=512) + die("Write call failed"); + close (id); + + if ((id=open(argv[2],O_RDONLY,0))<0) + die("Unable to open 'setup'"); + if (read(id,buf,MINIX_HEADER) != MINIX_HEADER) + die("Unable to read header of 'setup'"); + if (((long *) buf)[0]!=intel_long(0x04100301)) + die("Non-Minix header of 'setup'"); + if (((long *) buf)[1]!=intel_long(MINIX_HEADER)) + die("Non-Minix header of 'setup'"); + if (((long *) buf)[3] != 0) + die("Illegal data segment in 'setup'"); + if (((long *) buf)[4] != 0) + die("Illegal bss in 'setup'"); + if (((long *) buf)[5] != 0) + die("Non-Minix header of 'setup'"); + if (((long *) buf)[7] != 0) + die("Illegal symbol table in 'setup'"); + for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c ) +#ifdef __BIG_KERNEL__ + { + if (!i) { + /* Working with memcpy because of alignment constraints + on Sparc - Gertjan */ + memcpy(&tmp_long, &buf[2], sizeof(long)); + if (tmp_long != intel_long(0x53726448) ) + die("Wrong magic in loader header of 'setup'"); + memcpy(&tmp_int, &buf[6], sizeof(int)); + if (tmp_int < intel_int(0x200)) + die("Wrong version of loader header of 'setup'"); + buf[0x11] = 1; /* LOADED_HIGH */ + tmp_long = intel_long(0x100000); + memcpy(&buf[0x14], &tmp_long, sizeof(long)); /* code32_start */ + } +#endif + if (write(1,buf,c)!=c) + die("Write call failed"); +#ifdef __BIG_KERNEL__ + } +#endif + if (c != 0) + die("read-error on 'setup'"); + close (id); + setup_sectors = (unsigned char)((i + 511) / 512); + /* for compatibility with LILO */ + if (setup_sectors < SETUP_SECTS) + setup_sectors = SETUP_SECTS; + fprintf(stderr,"Setup is %d bytes.\n",i); + for (c=0 ; c<sizeof(buf) ; c++) + buf[c] = '\0'; + while (i < setup_sectors * 512) { + c = setup_sectors * 512 - i; + if (c > sizeof(buf)) + c = sizeof(buf); + if (write(1,buf,c) != c) + die("Write call failed"); + i += c; + } + + if ((id=open(argv[3],O_RDONLY,0))<0) + die("Unable to open 'system'"); +#ifndef __BFD__ + if (read(id,buf,GCC_HEADER) != GCC_HEADER) + die("Unable to read header of 'system'"); + if (N_MAGIC(*ex) == ZMAGIC) { + GCC_HEADER = N_MAGIC_OFFSET; + lseek(id, GCC_HEADER, SEEK_SET); + } else if (N_MAGIC(*ex) != QMAGIC) + die("Non-GCC header of 'system'"); + fprintf(stderr,"System is %d kB (%d kB code, %d kB data and %d kB bss)\n", + (ex->a_text+ex->a_data+ex->a_bss)/1024, + ex->a_text /1024, + ex->a_data /1024, + ex->a_bss /1024); + sz = N_SYMOFF(*ex) - GCC_HEADER + 4; +#else + if (fstat (id, &sb)) { + perror ("fstat"); + die ("Unable to stat 'system'"); + } + sz = sb.st_size; + fprintf (stderr, "System is %d kB\n", sz/1024); +#endif + sys_size = (sz + 15) / 16; + if (sys_size > SYS_SIZE) + die("System is too big"); + while (sz > 0) { + int l, n; + + l = sz; + if (l > sizeof(buf)) + l = sizeof(buf); + if ((n=read(id, buf, l)) != l) { + if (n == -1) + perror(argv[1]); + else + fprintf(stderr, "Unexpected EOF\n"); + die("Can't read 'system'"); + } + if (write(1, buf, l) != l) + die("Write failed"); + sz -= l; + } + close(id); + if (lseek(1, 497, 0) == 497) { + if (write(1, &setup_sectors, 1) != 1) + die("Write of setup sectors failed"); + } + if (lseek(1,500,0) == 500) { + buf[0] = (sys_size & 0xff); + buf[1] = ((sys_size >> 8) & 0xff); + if (write(1, buf, 2) != 2) + die("Write failed"); + } + return(0); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/config.in linux.ac/arch/cris/config.in --- linux.vanilla/arch/cris/config.in Fri Feb 16 23:53:08 2001 +++ linux.ac/arch/cris/config.in Tue Apr 10 18:05:08 2001 @@ -36,15 +36,19 @@ comment 'Hardware setup' choice 'Processor type' \ - "Etrax-100-LX CONFIG_ETRAX100LX \ - Etrax-100-LX-for-xsim-simulator CONFIG_SVINTO_SIM" Etrax-100-LX + "Etrax-100-LX-v1 CONFIG_ETRAX100LX \ + Etrax-100-LX-v2 CONFIG_ETRAX100LX_V2 \ + Etrax-100-LX-for-xsim-simulator CONFIG_SVINTO_SIM" Etrax-100-LX-v1 # For both LX version 1 and the current simulator we enable the low VM mapping -# Later when LX version 2 and above exist, this should be done with an if -define_bool CONFIG_CRIS_LOW_MAP y +if [ "$CONFIG_ETRAX100LX" = "y" -o "$CONFIG_SVINTO_SIM" = "y" ]; then + define_bool CONFIG_CRIS_LOW_MAP y + define_hex ETRAX_DRAM_VIRTUAL_BASE 60000000 +else + define_hex ETRAX_DRAM_VIRTUAL_BASE c0000000 +fi -hex 'DRAM base (hex)' ETRAX_DRAM_BASE 40000000 int 'DRAM size (dec, in MB)' ETRAX_DRAM_SIZE 8 int 'Max possible flash size (dec, in MB)' CONFIG_ETRAX_FLASH_LENGTH 2 @@ -69,12 +73,29 @@ "Serial-0 CONFIG_DEBUG_PORT0 \ Serial-1 CONFIG_DEBUG_PORT1 \ Serial-2 CONFIG_DEBUG_PORT2 \ - Serial-3 CONFIG_DEBUG_PORT3" Serial-0 + Serial-3 CONFIG_DEBUG_PORT3 \ + disabled CONFIG_DEBUG_PORT_NULL" Serial-0 + +choice 'Product rescue-port' \ + "Serial-0 CONFIG_RESCUE_SER0 \ + Serial-1 CONFIG_RESCUE_SER1 \ + Serial-2 CONFIG_RESCUE_SER2 \ + Serial-3 CONFIG_RESCUE_SER3" Serial-0 hex 'R_WAITSTATES' DEF_R_WAITSTATES 95a6 hex 'R_BUS_CONFIG' DEF_R_BUS_CONFIG 104 -hex 'R_DRAM_CONFIG' DEF_R_DRAM_CONFIG 1a200040 -hex 'R_DRAM_TIMING' DEF_R_DRAM_TIMING 5611 + +bool 'SDRAM support' CONFIG_SDRAM n +if [ "$CONFIG_SDRAM" = "n" ]; then + hex 'R_DRAM_CONFIG' DEF_R_DRAM_CONFIG 1a200040 + hex 'R_DRAM_TIMING' DEF_R_DRAM_TIMING 5611 +fi + +if [ "$CONFIG_SDRAM" = "y" ]; then + hex 'R_SDRAM_CONFIG' DEF_R_SDRAM_CONFIG d2fa7878 + hex 'R_SDRAM_TIMING' DEF_R_SDRAM_TIMING 80004801 +fi + hex 'R_PORT_PA_DIR' DEF_R_PORT_PA_DIR 1c hex 'R_PORT_PA_DATA' DEF_R_PORT_PA_DATA 00 hex 'R_PORT_PB_CONFIG' DEF_R_PORT_PB_CONFIG 00 @@ -82,24 +103,6 @@ hex 'R_PORT_PB_DATA' DEF_R_PORT_PB_DATA ff endmenu - -# only configure IP numbers if the kernel ifconfig/route setup is enabled - -if [ "$CONFIG_KERNEL_IFCONFIG" = "y" ]; then - mainmenu_option next_comment - comment 'IP address selection' - - comment 'All addresses are in hexadecimal form without 0x prefix' - - hex 'IP address' ELTEST_IPADR ab1005af - hex 'Network' ELTEST_NETWORK ab100000 - hex 'Netmask' ELTEST_NETMASK ffff0000 - hex 'Broadcast' ELTEST_BROADCAST ab10ffff - hex 'Gateway' ELTEST_GATEWAY ab100101 - hwaddr 'Ethernet address' ELTEST_ETHADR 00408ccd0000 - - endmenu -fi # bring in Etrax built-in drivers diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/cris.ld linux.ac/arch/cris/cris.ld --- linux.vanilla/arch/cris/cris.ld Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/cris/cris.ld Tue Apr 10 18:05:08 2001 @@ -1,13 +1,10 @@ /* ld script to make the Linux/CRIS kernel * Authors: Bjorn Wesen (bjornw@axis.com) - * - * For now, on Etrax-100 LX, the DRAM starts virtually at 0x6. Normally - * it should be at 0xc. */ SECTIONS { - . = 0x60000000; /* DRAM starts virtually at 0x60000000 */ + . = @ETRAX_DRAM_VIRTUAL_BASE@; _dram_start = .; _ibr_start = .; . = . + 0x4000; /* see head.S and pages reserved at the start */ @@ -21,6 +18,7 @@ *(.fixup) *(.text.__*) *(.rodata) + *(.rodata.__*) } . = ALIGN(4); /* Exception table */ @@ -77,5 +75,5 @@ *(.exitcall.exit) } - _dram_end = 0x60000000 + @ETRAX_DRAM_SIZE_M@*1024*1024; + _dram_end = _dram_start + @ETRAX_DRAM_SIZE_M@*1024*1024; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/defconfig linux.ac/arch/cris/defconfig --- linux.vanilla/arch/cris/defconfig Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/defconfig Tue Apr 10 18:05:08 2001 @@ -24,10 +24,13 @@ # Hardware setup # CONFIG_ETRAX100LX=y +# CONFIG_ETRAX100LX_V2 is not set # CONFIG_SVINTO_SIM is not set CONFIG_CRIS_LOW_MAP=y -ETRAX_DRAM_BASE=40000000 +ETRAX_DRAM_VIRTUAL_BASE=60000000 ETRAX_DRAM_SIZE=8 +CONFIG_ETRAX_FLASH_LENGTH=2 +CONFIG_ETRAX_FLASH_BUSWIDTH=2 CONFIG_ETRAX_PA_LEDS=y # CONFIG_ETRAX_PB_LEDS is not set # CONFIG_ETRAX_90000000_LEDS is not set @@ -40,8 +43,13 @@ # CONFIG_DEBUG_PORT1 is not set # CONFIG_DEBUG_PORT2 is not set # CONFIG_DEBUG_PORT3 is not set +CONFIG_RESCUE_SER0=y +# CONFIG_RESCUE_SER1 is not set +# CONFIG_RESCUE_SER2 is not set +# CONFIG_RESCUE_SER3 is not set DEF_R_WAITSTATES=95a6 DEF_R_BUS_CONFIG=104 +# CONFIG_SDRAM is not set DEF_R_DRAM_CONFIG=1a200040 DEF_R_DRAM_TIMING=5611 DEF_R_PORT_PA_DIR=1d @@ -56,6 +64,87 @@ CONFIG_ETRAX_ETHERNET=y CONFIG_NET_ETHERNET=y CONFIG_ETRAX_SERIAL=y +# CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB is not set +CONFIG_ETRAX_SERIAL_PORT1=y +# CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB is not set +# CONFIG_ETRAX_SERIAL_PORT2 is not set +# CONFIG_ETRAX_SERIAL_PORT3 is not set +# CONFIG_RS485 is not set +# CONFIG_ETRAX_SYNCHRONOUS_SERIAL is not set +# CONFIG_ETRAX_IDE is not set +CONFIG_ETRAX_AXISFLASHMAP=y +CONFIG_MTD=y +CONFIG_MTD_CFI=y +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_AMDSTD=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_ETRAX_I2C=y +CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C=y +CONFIG_ETRAX_GPIO=y +CONFIG_ETRAX_PA_BUTTON_BITMASK=02 +CONFIG_PA_CHANGEABLE_DIR=00 +CONFIG_PA_CHANGEABLE_BITS=FF +CONFIG_PB_CHANGEABLE_DIR=00 +CONFIG_PB_CHANGEABLE_BITS=FF +# CONFIG_JULIETTE is not set +# CONFIG_JULIETTE_VIDEO is not set +# CONFIG_JULIETTE_CCD is not set +# CONFIG_JULIETTE_SS1M is not set +# CONFIG_JULIETTE_MEGCCD is not set +# CONFIG_ETRAX_USB_HOST is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_MTDRAM is not set +CONFIG_MTD_CFI=y +# CONFIG_MTD_CFI_GEOMETRY is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_AMDSTD=y +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_PNC2000 is not set +# CONFIG_MTD_RPXLITE is not set +# CONFIG_MTD_SBC_MEDIAGX is not set +# CONFIG_MTD_ELAN_104NC is not set +# CONFIG_MTD_SA1100 is not set +# CONFIG_MTD_DC21285 is not set +# CONFIG_MTD_CSTM_CFI_JEDEC is not set +# CONFIG_MTD_JEDEC is not set +# CONFIG_MTD_MIXMEM is not set +# CONFIG_MTD_OCTAGON is not set +# CONFIG_MTD_VMAX is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_NAND_SPIA is not set +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set # # Block devices @@ -90,10 +179,6 @@ # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set - -# -# -# # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set @@ -101,6 +186,7 @@ # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set @@ -112,11 +198,61 @@ # CONFIG_NET_SCHED is not set # +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# IDE, ATA and ATAPI Block devices +# +# CONFIG_BLK_DEV_IDE is not set +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +# CONFIG_BLK_DEV_IDEDISK is not set +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set + +# # SCSI support # # CONFIG_SCSI is not set # +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# # Network device support # CONFIG_NETDEVICES=y @@ -177,6 +313,16 @@ # CONFIG_WAN is not set # +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# # ISDN subsystem # # CONFIG_ISDN is not set @@ -187,6 +333,60 @@ # CONFIG_CD_NO_IDESCSI is not set # +# Input core support +# +# CONFIG_INPUT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# # File systems # # CONFIG_QUOTA is not set @@ -259,59 +459,14 @@ # CONFIG_NLS is not set # -# Character devices -# -# CONFIG_VT is not set -# CONFIG_SERIAL is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_UNIX98_PTYS is not set -# CONFIG_PRINTER is not set -# CONFIG_PPDEV is not set - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_JOYSTICK is not set - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver +# Sound # -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set +# CONFIG_SOUND is not set # -# Sound +# USB support # -# CONFIG_SOUND is not set +# CONFIG_USB is not set # # Kernel hacking diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/Config.in linux.ac/arch/cris/drivers/Config.in --- linux.vanilla/arch/cris/drivers/Config.in Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/drivers/Config.in Tue Apr 10 18:05:08 2001 @@ -1,16 +1,74 @@ mainmenu_option next_comment comment 'Drivers for Etrax built-in interfaces' -bool 'Ethernet support' CONFIG_ETRAX_ETHERNET y +bool 'Ethernet support' CONFIG_ETRAX_ETHERNET if [ "$CONFIG_ETRAX_ETHERNET" = "y" ]; then # this is just so that the user does not have to go into the # normal ethernet driver section just to enable ethernetworking define_bool CONFIG_NET_ETHERNET y +else + define_bool CONFIG_NET_ETHERNET n fi -bool 'Serial-port support' CONFIG_ETRAX_SERIAL y +bool 'Serial-port support' CONFIG_ETRAX_SERIAL +if [ "$CONFIG_ETRAX_SERIAL" = "y" ]; then + comment ' Port 0 is always enabled' + bool ' Ser0 DTR, RI, DSR, CD on PB' CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB + if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB" = "y" ]; then + int ' Ser0 DTR on PB bit' CONFIG_ETRAX_SER0_DTR_ON_PB_BIT 4 + int ' Ser0 RI on PB bit' CONFIG_ETRAX_SER0_RI_ON_PB_BIT 5 + int ' Ser0 DSR on PB bit' CONFIG_ETRAX_SER0_DSR_ON_PB_BIT 6 + int ' Ser0 CD on PB bit' CONFIG_ETRAX_SER0_CD_ON_PB_BIT 7 + fi + + bool ' Serial port 1 enabled' CONFIG_ETRAX_SERIAL_PORT1 + if [ "$CONFIG_ETRAX_SERIAL_PORT1" = "y" ]; then + bool ' Ser1 DTR, RI, DSR, CD on PB' CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB + if [ "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB" = "y" ]; then + int ' Ser1 DTR on PB bit' CONFIG_ETRAX_SER1_DTR_ON_PB_BIT 4 + int ' Ser1 RI on PB bit' CONFIG_ETRAX_SER1_RI_ON_PB_BIT 5 + int ' Ser1 DSR on PB bit' CONFIG_ETRAX_SER1_DSR_ON_PB_BIT 6 + int ' Ser1 CD on PB bit' CONFIG_ETRAX_SER1_CD_ON_PB_BIT 7 + fi + fi + if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB" = "y" -a \ + "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB" = "y" ]; then + comment 'Make sure you dont have the same PB bits more than once!' + fi + bool ' Serial port 2 enabled' CONFIG_ETRAX_SERIAL_PORT2 + if [ "$CONFIG_ETRAX_SERIAL_PORT2" = "y" ]; then + bool ' Ser2 DTR, RI, DSR, CD on PA' CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA + if [ "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA" = "y" ]; then + int ' Ser2 DTR on PA bit' CONFIG_ETRAX_SER2_DTR_ON_PA_BIT 4 + int ' Ser2 RI on PA bit' CONFIG_ETRAX_SER2_RI_ON_PA_BIT 5 + int ' Ser2 DSR on PA bit' CONFIG_ETRAX_SER2_DSR_ON_PA_BIT 6 + int ' Ser2 CD on PA bit' CONFIG_ETRAX_SER2_CD_ON_PA_BIT 7 + fi + fi + bool ' Serial port 3 enabled' CONFIG_ETRAX_SERIAL_PORT3 + bool ' RS-485 support' CONFIG_RS485 + if [ "$CONFIG_RS485" = "y" ]; then + bool ' RS-485 mode on PA' CONFIG_RS485_ON_PA + if [ "$CONFIG_RS485_ON_PA" = "y" ]; then + int ' RS-485 mode on PA bit' CONFIG_RS485_ON_PA_BIT 3 + fi + bool ' Disable serial receiver' CONFIG_RS485_DISABLE_RECEIVER + fi +fi + +bool 'Synchronous serial port support' CONFIG_ETRAX_SYNCHRONOUS_SERIAL +if [ "$CONFIG_ETRAX_SYNCHRONOUS_SERIAL" = "y" ]; then + bool ' Synchronous serial port 0 enabled' CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0 + if [ "$CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0" = "y" ]; then + bool ' Synchronous serial port 0 uses DMA' CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA y + fi + bool ' Synchronous serial port 1 enabled' CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1 + if [ "$CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1" = "y" ]; then + bool ' Synchronous serial port 1 uses DMA' CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA y + fi +fi -bool 'ATA/IDE support' CONFIG_ETRAX_IDE n +bool 'ATA/IDE support' CONFIG_ETRAX_IDE if [ "$CONFIG_ETRAX_IDE" = "y" ]; then # here we should add the CONFIG_'s necessary to enable the basic @@ -25,14 +83,18 @@ define_bool CONFIG_BLK_DEV_IDEDMA y define_bool CONFIG_DMA_NONPCI y - + + int 'Delay for drives to regain consciousness' CONFIG_IDE_DELAY 15 + choice 'IDE reset pin' \ "Port_PB_Bit_7 CONFIG_ETRAX_IDE_PB7_RESET\ Port_G_Bit_27 CONFIG_ETRAX_IDE_G27_RESET\ Port_CSE1_Bit_16 CONFIG_ETRAX_IDE_CSE1_16_RESET" Port_PB_Bit_7 +else + define_bool CONFIG_IDE n fi -bool 'Axis flash-map support' CONFIG_ETRAX_AXISFLASHMAP n +bool 'Axis flash-map support' CONFIG_ETRAX_AXISFLASHMAP if [ "$CONFIG_ETRAX_AXISFLASHMAP" = "y" ]; then # here we define the CONFIG_'s necessary to enable MTD support @@ -43,7 +105,39 @@ define_bool CONFIG_MTD_CFI_INTELEXT n define_bool CONFIG_MTD_CFI_AMDSTD y + define_bool CONFIG_MTD_AMDSTD y + define_bool CONFIG_MTD_CHAR y + define_bool CONFIG_MTD_BLOCK y +fi + +bool 'I2C support' CONFIG_ETRAX_I2C +if [ "$CONFIG_ETRAX_I2C" = "y" ]; then +# this is true for most products since PB-I2C seems to be somewhat +# flawed.. + bool 'I2C uses PB not PB-I2C' CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C +fi + +bool 'GPIO support' CONFIG_ETRAX_GPIO +if [ "$CONFIG_ETRAX_GPIO" = "y" ]; then + hex ' PA-buttons bitmask' CONFIG_ETRAX_PA_BUTTON_BITMASK 02 + hex ' PA user changeable dir mask' CONFIG_PA_CHANGEABLE_DIR 00 + hex ' PA user changeable bits mask' CONFIG_PA_CHANGEABLE_BITS FF + hex ' PB user changeable dir mask' CONFIG_PB_CHANGEABLE_DIR 00 + hex ' PB user changeable bits mask' CONFIG_PB_CHANGEABLE_BITS FF +fi + +bool 'Juliette support' CONFIG_JULIETTE n + +if [ "$CONFIG_JULIETTE" = "y" ]; then + source arch/cris/drivers/juliette/Config.in +fi + +bool 'USB host' CONFIG_ETRAX_USB_HOST +if [ "$CONFIG_ETRAX_USB_HOST" = "y" ]; then + define_bool CONFIG_USB y + bool ' USB port 1 enabled' CONFIG_ETRAX_USB_HOST_PORT1 n + bool ' USB port 2 enabled' CONFIG_ETRAX_USB_HOST_PORT2 n fi endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/Makefile linux.ac/arch/cris/drivers/Makefile --- linux.vanilla/arch/cris/drivers/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/drivers/Makefile Tue Apr 10 18:05:08 2001 @@ -6,9 +6,16 @@ obj-y := -obj-$(CONFIG_ETRAX_ETHERNET) += ethernet.o -obj-$(CONFIG_ETRAX_SERIAL) += serial.o -obj-$(CONFIG_ETRAX_IDE) += ide.o -obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o + +obj-$(CONFIG_ETRAX_ETHERNET) += ethernet.o +obj-$(CONFIG_ETRAX_SERIAL) += serial.o +obj-$(CONFIG_ETRAX_IDE) += ide.o +obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o +obj-$(CONFIG_ETRAX_I2C) += i2c.o +obj-$(CONFIG_ETRAX_GPIO) += gpio.o +obj-$(CONFIG_ETRAX_USB_HOST) += usb-host.o +obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o +obj-$(CONFIG_JULIETTE) += juliette/juliette.o +subdir-$(CONFIG_JULIETTE) += juliette include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/axisflashmap.c linux.ac/arch/cris/drivers/axisflashmap.c --- linux.vanilla/arch/cris/drivers/axisflashmap.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/drivers/axisflashmap.c Tue Apr 10 18:05:08 2001 @@ -11,6 +11,17 @@ * partition split defined below. * * $Log: axisflashmap.c,v $ + * Revision 1.4 2001/02/23 12:47:15 bjornw + * Uncached flash in LOW_MAP moved from 0xe to 0x8 + * + * Revision 1.3 2001/02/16 12:11:45 jonashg + * MTD driver amd_flash is now included in MTD CVS repository. + * (It's now in drivers/mtd). + * + * Revision 1.2 2001/02/09 11:12:22 jonashg + * Support for AMD compatible non-CFI flash chips. + * Only tested with Toshiba TC58FVT160 so far. + * * Revision 1.1 2001/01/12 17:01:18 bjornw * * Added axisflashmap.c, a physical mapping for MTD that reads and understands * Axis partition-table format. @@ -31,7 +42,7 @@ #include <asm/mmu.h> #ifdef CONFIG_CRIS_LOW_MAP -#define FLASH_UNCACHED_ADDR KSEG_E +#define FLASH_UNCACHED_ADDR KSEG_8 #define FLASH_CACHED_ADDR KSEG_5 #else #define FLASH_UNCACHED_ADDR KSEG_E @@ -205,8 +216,14 @@ mymtd = do_cfi_probe(&axis_map); +#ifdef CONFIG_MTD_AMDSTD + if (!mymtd) { + mymtd = do_amd_flash_probe(&axis_map); + } +#endif + if(!mymtd) { - printk("cfi_probe erred %d\n", mymtd); + printk("%s: No flash chip found!\n", axis_map.name); return -ENXIO; } @@ -218,7 +235,8 @@ * now at least. */ - ptable_head = FLASH_CACHED_ADDR + PTABLE_SECTOR + PARTITION_TABLE_OFFSET; + ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR + + PTABLE_SECTOR + PARTITION_TABLE_OFFSET); pidx++; /* first partition is always set to the default */ if ((ptable_head->magic == PARTITION_TABLE_MAGIC) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/ethernet.c linux.ac/arch/cris/drivers/ethernet.c --- linux.vanilla/arch/cris/drivers/ethernet.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/cris/drivers/ethernet.c Tue Apr 10 18:05:08 2001 @@ -1,12 +1,23 @@ -/* $Id: ethernet.c,v 1.5 2000/11/29 17:22:22 bjornw Exp $ +/* $Id: ethernet.c,v 1.8 2001/02/27 13:52:48 bjornw Exp $ * * e100net.c: A network driver for the ETRAX 100LX network controller. * - * Copyright (c) 1998-2000 Axis Communications AB. + * Copyright (c) 1998-2001 Axis Communications AB. * * The outline of this driver comes from skeleton.c. * * $Log: ethernet.c,v $ + * Revision 1.8 2001/02/27 13:52:48 bjornw + * malloc.h -> slab.h + * + * Revision 1.7 2001/02/23 13:46:38 bjornw + * Spellling check + * + * Revision 1.6 2001/01/26 15:21:04 starvik + * Don't disable interrupts while reading MDIO registers (MDIO is slow) + * Corrected promiscuous mode + * Improved deallocation of IRQs ("ifconfig eth0 down" now works) + * * Revision 1.5 2000/11/29 17:22:22 bjornw * Get rid of the udword types legacy stuff * @@ -39,7 +50,7 @@ #include <linux/ptrace.h> #include <linux/ioport.h> #include <linux/in.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/string.h> #include <asm/system.h> #include <asm/bitops.h> @@ -53,7 +64,7 @@ #include <linux/etherdevice.h> #include <linux/skbuff.h> -#include <asm/svinto.h> +#include <asm/svinto.h> /* DMA and register descriptions */ //#define ETHDEBUG @@ -483,9 +494,6 @@ unsigned short data; /* Data read from MDIO */ int bitCounter; - save_flags(flags); - cli(); - /* Start of frame, OP Code, Physical Address, Register Address */ cmd = (MDIO_START << 14) | (MDIO_READ << 12) | (MDIO_PHYS_ADDR << 7) | (reg_num << 2); @@ -498,8 +506,7 @@ for(bitCounter=15; bitCounter>=0 ; bitCounter--) { data |= (e100_receive_mdio_bit() << bitCounter); } - - restore_flags(flags); + return data; } @@ -555,9 +562,6 @@ unsigned short data; int bitCounter; - save_flags(flags); - cli(); - data = e100_get_mdio_reg(MDIO_BASE_CONTROL_REG); cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) | (MDIO_BASE_CONTROL_REG << 2); @@ -569,8 +573,6 @@ for(bitCounter = 15; bitCounter >= 0 ; bitCounter--) { e100_send_mdio_bit(GET_BIT(bitCounter, data)); } - - restore_flags(flags); } /* Called by upper layers if they decide it took too long to complete @@ -858,9 +860,9 @@ /* Flush the Tx and disable Rx here. */ - free_irq(NETWORK_DMARX_IRQ, NULL); - free_irq(NETWORK_DMATX_IRQ, NULL); - free_irq(NETWORK_STATUS_IRQ, NULL); + free_irq(NETWORK_DMARX_IRQ, (void *)dev); + free_irq(NETWORK_DMATX_IRQ, (void *)dev); + free_irq(NETWORK_STATUS_IRQ, (void *)dev); free_dma(0); free_dma(1); @@ -926,10 +928,21 @@ /* promiscuous mode */ lo_bits = 0xfffffffful; hi_bits = 0xfffffffful; + + /* Enable individual receive */ + *R_NETWORK_REC_CONFIG = + IO_STATE(R_NETWORK_REC_CONFIG, broadcast, receive) | + IO_STATE(R_NETWORK_REC_CONFIG, ma0, enable) | + IO_STATE(R_NETWORK_REC_CONFIG, individual, receive); } else if (num_addr == 0) { /* Normal, clear the mc list */ lo_bits = 0x00000000ul; hi_bits = 0x00000000ul; + + /* Disable individual receive */ + *R_NETWORK_REC_CONFIG = + IO_STATE(R_NETWORK_REC_CONFIG, broadcast, receive) | + IO_STATE(R_NETWORK_REC_CONFIG, ma0, enable); } else { /* MC mode, receive normal and MC packets */ char hash_ix; @@ -971,6 +984,10 @@ } dmi = dmi->next; } + /* Disable individual receive */ + *R_NETWORK_REC_CONFIG = + IO_STATE(R_NETWORK_REC_CONFIG, broadcast, receive) | + IO_STATE(R_NETWORK_REC_CONFIG, ma0, enable); } *R_NETWORK_GA_0 = lo_bits; *R_NETWORK_GA_1 = hi_bits; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/examples/kiobuftest.c linux.ac/arch/cris/drivers/examples/kiobuftest.c --- linux.vanilla/arch/cris/drivers/examples/kiobuftest.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/drivers/examples/kiobuftest.c Tue Apr 10 18:05:08 2001 @@ -0,0 +1,108 @@ +/* + * Example showing how to pin down a range of virtual pages from user-space + * to be able to do for example DMA directly into them. + * + * It is necessary because the pages the virtual pointers reference, might + * not exist in memory (could be mapped to the zero-page, filemapped etc) + * and DMA cannot trigger the MMU to force them in (and would have time + * contraints making it impossible to wait for it anyway). + * + * Author: Bjorn Wesen + * + * $Log: kiobuftest.c,v $ + * Revision 1.2 2001/02/27 13:52:50 bjornw + * malloc.h -> slab.h + * + * Revision 1.1 2001/01/19 15:57:49 bjornw + * Example of how to do direct HW -> user-mode DMA + * + * + */ + +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/iobuf.h> + +#define KIOBUFTEST_MAJOR 124 /* in the local range, experimental */ + + +static ssize_t +kiobuf_read(struct file *filp, char *buf, size_t len, loff_t *ppos) +{ + + struct kiobuf *iobuf; + int res, i; + + /* Make a kiobuf that maps the entire length the reader has given + * us + */ + + res = alloc_kiovec(1, &iobuf); + if (res) + return res; + + if((res = map_user_kiobuf(READ, iobuf, (unsigned long)buf, len))) { + printk("map_user_kiobuf failed, return %d\n", res); + return res; + } + + /* At this point, the virtual area buf[0] -> buf[len-1] will + * have corresponding pages mapped in physical memory and locked + * until we unmap the kiobuf. They cannot be swapped out or moved + * around. + */ + + printk("nr_pages == %d\noffset == %d\nlength == %d\n", + iobuf->nr_pages, iobuf->offset, iobuf->length); + + for(i = 0; i < iobuf->nr_pages; i++) { + printk("page_add(maplist[%d]) == 0x%x\n", i, + page_address(iobuf->maplist[i])); + } + + /* This is the place to create the necessary scatter-gather vector + * for the DMA using the iobuf->maplist array and page_address + * (don't forget __pa if the DMA needs the actual physical DRAM address) + * and run it. + */ + + + + + /* Release the mapping and exit */ + + unmap_kiobuf(iobuf); /* The unlock_kiobuf is implicit here */ + + return len; +} + + +static struct file_operations kiobuf_fops = { + owner: THIS_MODULE, + read: kiobuf_read +}; + +static int __init +kiobuftest_init(void) +{ + int res; + + /* register char device */ + + res = register_chrdev(KIOBUFTEST_MAJOR, "kiobuftest", &kiobuf_fops); + if(res < 0) { + printk(KERN_ERR "kiobuftest: couldn't get a major number.\n"); + return res; + } + + printk("Initializing kiobuf-test device\n"); +} + +module_init(kiobuftest_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/gpio.c linux.ac/arch/cris/drivers/gpio.c --- linux.vanilla/arch/cris/drivers/gpio.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/drivers/gpio.c Tue Apr 10 18:05:08 2001 @@ -0,0 +1,298 @@ +/* $Id: gpio.c,v 1.4 2001/02/27 13:52:48 bjornw Exp $ + * + * Etrax general port I/O device + * + * Copyright (c) 1999, 2000, 2001 Axis Communications AB + * + * Authors: Bjorn Wesen (initial version) + * Ola Knutsson (LED handling) + * Johan Adolfsson (read/set directions) + * + * $Log: gpio.c,v $ + * Revision 1.4 2001/02/27 13:52:48 bjornw + * malloc.h -> slab.h + * + * Revision 1.3 2001/01/24 15:06:48 bjornw + * gpio_wq correct type + * + * Revision 1.2 2001/01/18 16:07:30 bjornw + * 2.4 port + * + * Revision 1.1 2001/01/18 15:55:16 bjornw + * Verbatim copy of etraxgpio.c from elinux 2.0 added + * + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/ioport.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/poll.h> +#include <linux/init.h> + +#include <asm/etraxgpio.h> +#include <asm/svinto.h> +#include <asm/io.h> +#include <asm/system.h> + +#define GPIO_MAJOR 120 /* experimental MAJOR number */ + +#define D(x) + +static char gpio_name[] = "etrax gpio"; + +static wait_queue_head_t *gpio_wq; + +static int gpio_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +static int gpio_open(struct inode *inode, struct file *filp); +static int gpio_release(struct inode *inode, struct file *filp); +static unsigned int gpio_poll(struct file *filp, struct poll_table_struct *wait); + +/* private data per open() of this driver */ + +struct gpio_private { + struct gpio_private *next; + volatile unsigned char *port, *shadow; + volatile unsigned char *dir, *dir_shadow; + unsigned char changeable_dir; + unsigned char changeable_bits; + unsigned char highalarm, lowalarm; + wait_queue_head_t alarm_wq; + int minor; +}; + +/* linked list of alarms to check for */ + +static struct gpio_private *alarmlist = 0; + +#define NUM_PORTS 2 +static volatile unsigned char *ports[2] = { R_PORT_PA_DATA, R_PORT_PB_DATA }; +static volatile unsigned char *shads[2] = { + &port_pa_data_shadow, &port_pb_data_shadow }; + +/* What direction bits that are user changeable 1=changeable*/ +#ifndef CONFIG_PA_CHANGEABLE_DIR +#define CONFIG_PA_CHANGEABLE_DIR 0x00 +#endif +#ifndef CONFIG_PB_CHANGEABLE_DIR +#define CONFIG_PB_CHANGEABLE_DIR 0x00 +#endif + +#ifndef CONFIG_PA_CHANGEABLE_BITS +#define CONFIG_PA_CHANGEABLE_BITS 0xFF +#endif +#ifndef CONFIG_PB_CHANGEABLE_BITS +#define CONFIG_PB_CHANGEABLE_BITS 0xFF +#endif + + +static unsigned char changeable_dir[2] = { CONFIG_PA_CHANGEABLE_DIR, + CONFIG_PB_CHANGEABLE_DIR }; +static unsigned char changeable_bits[2] = { CONFIG_PA_CHANGEABLE_BITS, + CONFIG_PB_CHANGEABLE_BITS }; + +static volatile unsigned char *dir[2] = { R_PORT_PA_DIR, R_PORT_PB_DIR }; + +static volatile unsigned char *dir_shadow[2] = { + &port_pa_dir_shadow, &port_pb_dir_shadow }; + +#define LEDS 2 + +static unsigned int +gpio_poll(struct file *filp, + struct poll_table_struct *wait) +{ + /* TODO poll on alarms! */ +#if 0 + if(!ANYTHING_WANTED) { + D(printk("gpio_select sleeping task\n")); + select_wait(&gpio_wq, table); + return 0; + } + D(printk("gpio_select ready\n")); +#endif + return 1; +} + +static int +gpio_open(struct inode *inode, struct file *filp) +{ + struct gpio_private *priv; + int p = MINOR(inode->i_rdev); + + if(p >= NUM_PORTS && p != LEDS) + return -EINVAL; + + priv = (struct gpio_private *)kmalloc(sizeof(struct gpio_private), + GFP_KERNEL); + + if(!priv) + return -ENOMEM; + + priv->minor = p; + + /* initialize the io/alarm struct and link it into our alarmlist */ + + priv->next = alarmlist; + alarmlist = priv; + priv->port = ports[p]; + priv->shadow = shads[p]; + + priv->changeable_dir = changeable_dir[p]; + priv->changeable_bits = changeable_bits[p]; + priv->dir = dir[p]; + priv->dir_shadow = dir_shadow[p]; + + priv->highalarm = 0; + priv->lowalarm = 0; + init_waitqueue_head(&priv->alarm_wq); + + filp->private_data = (void *)priv; + + return 0; +} + +static int +gpio_release(struct inode *inode, struct file *filp) +{ + struct gpio_private *p = alarmlist; + struct gpio_private *todel = (struct gpio_private *)filp->private_data; + + /* unlink from alarmlist and free the private structure */ + + if(p == todel) { + alarmlist = todel->next; + } else { + while(p->next != todel) + p = p->next; + p->next = todel->next; + } + + kfree(todel); + + return 0; +} + +/* Main device API. ioctl's to read/set/clear bits, as well as to + * set alarms to wait for using a subsequent select(). + */ + +static int +gpio_leds_ioctl(unsigned int cmd, unsigned long arg); + +static int +gpio_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct gpio_private *priv = (struct gpio_private *)file->private_data; + + if(_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) { + return -EINVAL; + } + + switch (_IOC_NR(cmd)) { + case IO_READBITS: + // read the port + return *priv->port; + case IO_SETBITS: + // set changeable bits with a 1 in arg + *priv->port = *priv->shadow |= + ((unsigned char)arg & priv->changeable_bits); + break; + case IO_CLRBITS: + // clear changeable bits with a 1 in arg + *priv->port = *priv->shadow &= + ~((unsigned char)arg & priv->changeable_bits); + break; + case IO_HIGHALARM: + // set alarm when bits with 1 in arg go high + priv->highalarm |= (unsigned char)arg; + break; + case IO_LOWALARM: + // set alarm when bits with 1 in arg go low + priv->lowalarm |= (unsigned char)arg; + break; + case IO_CLRALARM: + // clear alarm for bits with 1 in arg + priv->highalarm &= ~(unsigned char)arg; + priv->lowalarm &= ~(unsigned char)arg; + break; + case IO_READDIR: + /* Read direction 0=input 1=output */ + return *priv->dir_shadow; + case IO_SETINPUT: + /* Set direction 0=unchanged 1=input */ + *priv->dir = *priv->dir_shadow &= + ~((unsigned char)arg & priv->changeable_dir); + return *priv->dir_shadow; + case IO_SETOUTPUT: + /* Set direction 0=unchanged 1=output */ + *priv->dir = *priv->dir_shadow |= + ((unsigned char)arg & priv->changeable_dir); + return *priv->dir_shadow; + default: + if(priv->minor == LEDS) + return gpio_leds_ioctl(cmd, arg); + else + return -EINVAL; + } + + return 0; +} + +static int +gpio_leds_ioctl(unsigned int cmd, unsigned long arg) +{ + unsigned char green; + unsigned char red; + + switch (_IOC_NR(cmd)) { + case IO_LEDACTIVE_SET: + green = ((unsigned char) arg) & 1; + red = (((unsigned char) arg) >> 1) & 1; + LED_ACTIVE_SET_G(green); + LED_ACTIVE_SET_R(red); + break; + default: + return -EINVAL; + } +} + +struct file_operations gpio_fops = { + owner: THIS_MODULE, + poll: gpio_poll, + ioctl: gpio_ioctl, + open: gpio_open, + release: gpio_release, +}; + +/* main driver initialization routine, called from mem.c */ + +static __init int +gpio_init(void) +{ + int res; + + /* do the formalities */ + + res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops); + if(res < 0) { + printk(KERN_ERR "gpio: couldn't get a major number.\n"); + return res; + } + + printk("ETRAX 100LX GPIO driver v2.1, (c) 2001 Axis Communications AB\n"); + + return res; +} + +/* this makes sure that gpio_init is called during kernel boot */ + +module_init(gpio_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/i2c.c linux.ac/arch/cris/drivers/i2c.c --- linux.vanilla/arch/cris/drivers/i2c.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/drivers/i2c.c Tue Apr 10 18:05:08 2001 @@ -0,0 +1,691 @@ +/*!*************************************************************************** +*! +*! FILE NAME : i2c.c +*! +*! DESCRIPTION: implements an interface for IIC/I2C, both directly from other +*! kernel modules (i2c_writereg/readreg) and from userspace using +*! ioctl()'s +*! +*! Nov 30 1998 Torbjorn Eliasson Initial version. +*! Bjorn Wesen Elinux kernel version. +*! Jan 14 2000 Johan Adolfsson Fixed PB shadow register stuff - +*! don't use PB_I2C if DS1302 uses same bits, +*! use PB. +*! $Log: i2c.c,v $ +*! Revision 1.5 2001/02/27 13:52:48 bjornw +*! malloc.h -> slab.h +*! +*! Revision 1.4 2001/02/15 07:17:40 starvik +*! Corrected usage if port_pb_i2c_shadow +*! +*! Revision 1.3 2001/01/26 17:55:13 bjornw +*! * Made I2C_USES_PB_NOT_PB_I2C a CONFIG option instead of assigning it +*! magically. Config.in needs to set it for the options that need it, like +*! Dallas 1302 support. Actually, it should be default since it screws up +*! the PB bits even if you don't use I2C.. +*! * Include linux/config.h to get the above +*! +*! Revision 1.2 2001/01/18 15:49:30 bjornw +*! 2.4 port of I2C including some cleanups (untested of course) +*! +*! Revision 1.1 2001/01/18 15:35:25 bjornw +*! Verbatim copy of the Etrax i2c driver, 2.0 elinux version +*! +*! +*! --------------------------------------------------------------------------- +*! +*! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN +*! +*!***************************************************************************/ +/* $Id: i2c.c,v 1.5 2001/02/27 13:52:48 bjornw Exp $ */ +/****************** INCLUDE FILES SECTION ***********************************/ + +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/config.h> + +#include <asm/etraxi2c.h> + +#include <asm/system.h> +#include <asm/svinto.h> +#include <asm/io.h> +#include <asm/delay.h> + +#include "i2c.h" + +/****************** I2C DEFINITION SECTION *************************/ + +#define D(x) + +#define I2C_MAJOR 123 /* LOCAL/EXPERIMENTAL */ +static const char i2c_name[] = "i2c"; + +#define CLOCK_LOW_TIME 8 +#define CLOCK_HIGH_TIME 8 +#define START_CONDITION_HOLD_TIME 8 +#define STOP_CONDITION_HOLD_TIME 8 +#define ENABLE_OUTPUT 0x01 +#define ENABLE_INPUT 0x00 +#define I2C_CLOCK_HIGH 1 +#define I2C_CLOCK_LOW 0 +#define I2C_DATA_HIGH 1 +#define I2C_DATA_LOW 0 + +#if 0 +/* TODO: fix this so the CONFIG_ETRAX_I2C_USES... is set in Config.in instead */ +#if defined(CONFIG_DS1302) && (CONFIG_DS1302_SDABIT==0) && \ + (CONFIG_DS1302_SCLBIT == 1) +#define CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C +#endif +#endif + +#ifdef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C +/* Use PB and not PB_I2C */ +#define SDABIT 0 +#define SCLBIT 1 +#define i2c_enable() +#define i2c_disable() + +/* enable or disable output-enable, to select output or input on the i2c bus */ + +#define i2c_dir_out() \ + REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, SDABIT, 1) +#define i2c_dir_in() \ + REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, SDABIT, 0) + +/* control the i2c clock and data signals */ + +#define i2c_clk(x) \ + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, SCLBIT, x) +#define i2c_data(x) \ + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, SDABIT, x) + +/* read a bit from the i2c interface */ + +#define i2c_getbit() (*R_PORT_PB_READ & (1 << SDABIT)) + +#else +/* enable or disable the i2c interface */ + +#define i2c_enable() *R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_en)) +#define i2c_disable() *R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_en)) + +/* enable or disable output-enable, to select output or input on the i2c bus */ + +#define i2c_dir_out() *R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_oe_)) +#define i2c_dir_in() *R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_oe_)) + +/* control the i2c clock and data signals */ + +#define i2c_clk(x) *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \ + ~IO_MASK(R_PORT_PB_I2C, i2c_clk)) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, (x))) + +#define i2c_data(x) *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \ + ~IO_MASK(R_PORT_PB_I2C, i2c_d)) | IO_FIELD(R_PORT_PB_I2C, i2c_d, (x))) + +/* read a bit from the i2c interface */ + +#define i2c_getbit() (*R_PORT_PB_READ & 0x1) +#endif + +/* use the kernels delay routine */ + +#define i2c_delay(usecs) udelay(usecs) + + +/****************** FUNCTION DEFINITION SECTION *************************/ + + +/* generate i2c start condition */ + +static void +i2c_start(void) +{ + // + // SCL=1 SDA=1 + // + i2c_dir_out(); + i2c_delay(CLOCK_HIGH_TIME/6); + i2c_data(I2C_DATA_HIGH); + i2c_clk(I2C_CLOCK_HIGH); + i2c_delay(CLOCK_HIGH_TIME); + // + // SCL=1 SDA=0 + // + i2c_data(I2C_DATA_LOW); + i2c_delay(START_CONDITION_HOLD_TIME); + // + // SCL=0 SDA=0 + // + i2c_clk(I2C_CLOCK_LOW); + i2c_delay(CLOCK_LOW_TIME); +} + +/* generate i2c stop condition */ + +static void +i2c_stop(void) +{ + i2c_dir_out(); + + // + // SCL=0 SDA=0 + // + i2c_clk(I2C_CLOCK_LOW); + i2c_data(I2C_DATA_LOW); + i2c_delay(CLOCK_LOW_TIME*2); + // + // SCL=1 SDA=0 + // + i2c_clk(I2C_CLOCK_HIGH); + i2c_delay(CLOCK_HIGH_TIME*2); + // + // SCL=1 SDA=1 + // + i2c_data(I2C_DATA_HIGH); + i2c_delay(STOP_CONDITION_HOLD_TIME); + + i2c_dir_in(); +} + +/* write a byte to the i2c interface */ + +static void +i2c_outbyte(unsigned char x) +{ + int i; + + i2c_dir_out(); + + for (i = 0; i < 8; i++) { + if (x & 0x80) + i2c_data(I2C_DATA_HIGH); + else + i2c_data(I2C_DATA_LOW); + + i2c_delay(CLOCK_LOW_TIME/2); + i2c_clk(I2C_CLOCK_HIGH); + i2c_delay(CLOCK_HIGH_TIME); + i2c_clk(I2C_CLOCK_LOW); + i2c_delay(CLOCK_LOW_TIME/2); + x <<= 1; + } + i2c_data(I2C_DATA_LOW); + i2c_delay(CLOCK_LOW_TIME/2); + + // + // enable input + // + i2c_dir_in(); +} + +/* read a byte from the i2c interface */ + +static unsigned char +i2c_inbyte(void) +{ + unsigned char aBitByte = 0; + int i; + int iaa; + //int dd= 0; + + // + // enable output + // + i2c_dir_out(); + // + // Release data bus by setting + // data high + // + i2c_data(I2C_DATA_HIGH); + // + // enable input + // + i2c_dir_in(); + // + // Use PORT PB instead of I2C + // for input. (I2C not working) + // + i2c_clk(1); + i2c_data(1); +/* *R_PORT_PB_DATA = *R_PORT_PB_READ | 0x03;*/ + // + // get bits + // + for (i = 0; i < 8; i++) { + i2c_delay(CLOCK_LOW_TIME/2); + // + // low clock period + // + i2c_clk(I2C_CLOCK_HIGH); + // + // switch off I2C + // + i2c_data(1); + i2c_disable(); + i2c_dir_in(); + // + // wait before getting bit + // + i2c_delay(CLOCK_HIGH_TIME/2); + aBitByte = (aBitByte << 1); + iaa = i2c_getbit(); + aBitByte = aBitByte | iaa ; + //if (iaa > 0) dd++; + // + // wait + // + i2c_delay(CLOCK_HIGH_TIME/2); + // + // end clock puls + // + i2c_enable(); + i2c_dir_out(); + i2c_clk(I2C_CLOCK_LOW); + // + // low clock period + // + i2c_delay(CLOCK_LOW_TIME/2); + } + i2c_dir_out(); + return aBitByte; +} + +/*#--------------------------------------------------------------------------- +*# +*# FUNCTION NAME: i2c_getack +*# +*# DESCRIPTION : checks if ack was received from ic2 +*# +*#--------------------------------------------------------------------------*/ + +static int +i2c_getack(void) +{ + int ack = 1; + // + // enable output + // + i2c_dir_out(); + // + // Release data bus by setting + // data high + // + i2c_data(I2C_DATA_HIGH); + // + // enable input + // + i2c_dir_in(); + i2c_delay(CLOCK_HIGH_TIME/4); + // + // generate ACK clock pulse + // + i2c_clk(I2C_CLOCK_HIGH); + // + // Use PORT PB instead of I2C + // for input. (I2C not working) + // + i2c_clk(1); + i2c_data(1); + +/* *R_PORT_PB_DATA = *R_PORT_PB_READ | 0x03;*/ + // + // switch off I2C + // + i2c_data(1); + i2c_disable(); + i2c_dir_in(); + // + // now wait for ack + // + i2c_delay(CLOCK_HIGH_TIME/2); + // + // check for ack + // + if(i2c_getbit()) + ack = 0; + i2c_delay(CLOCK_HIGH_TIME/2); + if(!ack){ + if(!i2c_getbit()) /* receiver pulld SDA low */ + ack = 1; + i2c_delay(CLOCK_HIGH_TIME/2); + } + + // + // end clock pulse + // + i2c_enable(); + i2c_dir_out(); + i2c_clk(I2C_CLOCK_LOW); + i2c_delay(CLOCK_HIGH_TIME/4); + // + // enable output + // + i2c_dir_out(); + // + // remove ACK clock pulse + // + i2c_data(I2C_DATA_HIGH); + i2c_delay(CLOCK_LOW_TIME/2); + return ack; +} + +/*#--------------------------------------------------------------------------- +*# +*# FUNCTION NAME: I2C::sendAck +*# +*# DESCRIPTION : Send ACK on received data +*# +*#--------------------------------------------------------------------------*/ +static void +i2c_sendack(void) +{ + // + // enable output + // + i2c_delay(CLOCK_LOW_TIME); + i2c_dir_out(); + // + // set ack pulse high + // + i2c_data(I2C_DATA_LOW); + // + // generate clock pulse + // + i2c_delay(CLOCK_HIGH_TIME/6); + i2c_clk(I2C_CLOCK_HIGH); + i2c_delay(CLOCK_HIGH_TIME); + i2c_clk(I2C_CLOCK_LOW); + i2c_delay(CLOCK_LOW_TIME/6); + // + // reset data out + // + i2c_data(I2C_DATA_HIGH); + i2c_delay(CLOCK_LOW_TIME); + // + i2c_dir_in(); +} + +/*#--------------------------------------------------------------------------- +*# +*# FUNCTION NAME: i2c_writereg +*# +*# DESCRIPTION : Writes a value to an I2C device +*# +*#--------------------------------------------------------------------------*/ +int +i2c_writereg(unsigned char theSlave, unsigned char theReg, + unsigned char theValue) +{ + int error, cntr = 3; + + do { + error = 0; + // + // we don't like to be interrupted + // + cli(); + // + // generate start condition + // + i2c_start(); + // + // dummy preamble + // + i2c_outbyte(0x01); + i2c_data(I2C_DATA_HIGH); + i2c_clk(I2C_CLOCK_HIGH); + i2c_delay(CLOCK_HIGH_TIME); /* Dummy Acknowledge */ + i2c_clk(I2C_CLOCK_LOW); + i2c_delay(CLOCK_LOW_TIME); + i2c_clk(I2C_CLOCK_HIGH); + i2c_delay(CLOCK_LOW_TIME); /* Repeated Start Condition */ + i2c_data(I2C_DATA_LOW); + i2c_delay(CLOCK_HIGH_TIME); + i2c_clk(I2C_CLOCK_LOW); + i2c_delay(CLOCK_LOW_TIME); + + i2c_start(); + // + // send slave address + // + i2c_outbyte(theSlave); + // + // wait for ack + // + if(!i2c_getack()) + error = 1; + // + // now select register + // + i2c_dir_out(); + i2c_outbyte(theReg); + // + // now it's time to wait for ack + // + if(!i2c_getack()) + error |= 2; + // + // send register register data + // + i2c_outbyte(theValue); + // + // now it's time to wait for ack + // + if(!i2c_getack()) + error |= 4; + // + // end byte stream + // + i2c_stop(); + // + // enable interrupt again + // + sti(); + + } while(error && cntr--); + + i2c_delay(CLOCK_LOW_TIME); + + return -error; +} + +/*#--------------------------------------------------------------------------- +*# +*# FUNCTION NAME: i2c_readreg +*# +*# DESCRIPTION : Reads a value from the decoder registers. +*# +*#--------------------------------------------------------------------------*/ +unsigned char +i2c_readreg(unsigned char theSlave, unsigned char theReg) +{ + unsigned char b = 0; + int error, cntr = 3; + + do { + error = 0; + // + // we don't like to be interrupted + // + cli(); + // + // generate start condition + // + i2c_start(); + // + // dummy preamble + // + i2c_outbyte(0x01); + i2c_data(I2C_DATA_HIGH); + i2c_clk(I2C_CLOCK_HIGH); + i2c_delay(CLOCK_HIGH_TIME); /* Dummy Acknowledge */ + i2c_clk(I2C_CLOCK_LOW); + i2c_delay(CLOCK_LOW_TIME); + i2c_clk(I2C_CLOCK_HIGH); + i2c_delay(CLOCK_LOW_TIME); /* Repeated Start Condition */ + i2c_data(I2C_DATA_LOW); + i2c_delay(CLOCK_HIGH_TIME); + i2c_clk(I2C_CLOCK_LOW); + i2c_delay(CLOCK_LOW_TIME); + + i2c_start(); + + // + // send slave address + // + i2c_outbyte(theSlave); + // + // wait for ack + // + if(!i2c_getack()) + error = 1; + // + // now select register + // + i2c_dir_out(); + i2c_outbyte(theReg); + // + // now it's time to wait for ack + // + if(!i2c_getack()) + error = 1; + // + // repeat start condition + // + i2c_delay(CLOCK_LOW_TIME); + i2c_start(); + // + // send slave address + // + i2c_outbyte(theSlave | 0x01); + // + // wait for ack + // + if(!i2c_getack()) + error = 1; + // + // fetch register + // + b = i2c_inbyte(); + // + // send Ack + // + i2c_sendack(); + // + // end sequence + // + i2c_stop(); + // + // enable interrupt again + // + sti(); + } while(error && cntr--); + + return b; +} + +static int +i2c_open(struct inode *inode, struct file *filp) +{ + return 0; +} + +static int +i2c_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +/* Main device API. ioctl's to write or read to/from i2c registers. + */ + +static int +i2c_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + if(_IOC_TYPE(cmd) != ETRAXI2C_IOCTYPE) { + return -EINVAL; + } + + switch (_IOC_NR(cmd)) { + case I2C_WRITEREG: + // write to an i2c slave + D(printk("i2cw %d %d %d\n", + I2C_ARGSLAVE(arg), + I2C_ARGREG(arg), + I2C_ARGVALUE(arg))); + + return i2c_writereg(I2C_ARGSLAVE(arg), + I2C_ARGREG(arg), + I2C_ARGVALUE(arg)); + case I2C_READREG: + { + unsigned char val; + // read from an i2c slave + D(printk("i2cr %d %d ", + I2C_ARGSLAVE(arg), + I2C_ARGREG(arg))); + val = i2c_readreg(I2C_ARGSLAVE(arg), I2C_ARGREG(arg)); + D(printk("= %d\n", val)); + return val; + } + default: + return -EINVAL; + + } + + return 0; +} + +static struct file_operations i2c_fops = { + owner: THIS_MODULE, + ioctl: i2c_ioctl, + open: i2c_open, + release: i2c_release, +}; + +static int __init +i2c_init(void) +{ + int res; + + /* Setup and enable the Port B I2C interface */ + +#ifndef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C + *R_PORT_PB_I2C = port_pb_i2c_shadow |= + IO_STATE(R_PORT_PB_I2C, i2c_en, on) | + IO_FIELD(R_PORT_PB_I2C, i2c_d, 1) | + IO_FIELD(R_PORT_PB_I2C, i2c_clk, 1) | + IO_STATE(R_PORT_PB_I2C, i2c_oe_, enable); +#endif + + port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir0); + port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir1); + + *R_PORT_PB_DIR = (port_pb_dir_shadow |= + IO_STATE(R_PORT_PB_DIR, dir0, input) | + IO_STATE(R_PORT_PB_DIR, dir1, output)); + + /* register char device */ + + res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops); + if(res < 0) { + printk(KERN_ERR "i2c: couldn't get a major number.\n"); + return res; + } + + printk("I2C driver v2.2, (c) 1999-2001 Axis Communications AB\n"); +} + +/* this makes sure that i2c_init is called during boot */ + +module_init(i2c_init); + +/****************** END OF FILE i2c.c ********************************/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/i2c.h linux.ac/arch/cris/drivers/i2c.h --- linux.vanilla/arch/cris/drivers/i2c.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/drivers/i2c.h Tue Apr 10 18:05:08 2001 @@ -0,0 +1,16 @@ +/* $Id: i2c.h,v 1.2 2001/01/18 15:49:30 bjornw Exp $ */ + +/* High level I2C actions */ +int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue); +unsigned char i2c_readreg(unsigned char theSlave, unsigned char theReg); + +/* Low level I2C */ +static void i2c_start(void); +static void i2c_stop(void); +static void i2c_outbyte(unsigned char x); +static unsigned char i2c_inbyte(void); +static int i2c_getack(void); +static void i2c_sendack(void); + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/ide.c linux.ac/arch/cris/drivers/ide.c --- linux.vanilla/arch/cris/drivers/ide.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/cris/drivers/ide.c Tue Apr 10 18:05:08 2001 @@ -1,4 +1,4 @@ -/* $Id: ide.c,v 1.4 2001/01/10 21:14:32 bjornw Exp $ +/* $Id: ide.c,v 1.9 2001/03/01 13:11:18 bjornw Exp $ * * Etrax specific IDE functions, like init and PIO-mode setting etc. * Almost the entire ide.c is used for the rest of the Etrax ATA driver. @@ -8,6 +8,23 @@ * Mikael Starvik (pio setup stuff) * * $Log: ide.c,v $ + * Revision 1.9 2001/03/01 13:11:18 bjornw + * 100 -> HZ + * + * Revision 1.8 2001/03/01 09:32:56 matsfg + * Moved IDE delay to a CONFIG-parameter instead + * + * Revision 1.7 2001/02/23 13:46:38 bjornw + * Spellling check + * + * Revision 1.6 2001/02/22 15:44:30 bjornw + * * Use ioremap when mapping the CSE1 memory-mapped reset-line for LX v2 + * * sw_len for a 65536 descriptor is 0, not 65536 + * * Express concern for G27 reset code + * + * Revision 1.5 2001/02/16 07:35:38 matsfg + * Now handles DMA request blocks between 64k and 128k by split into two descriptors. + * * Revision 1.4 2001/01/10 21:14:32 bjornw * Initialize hwif->ideproc, for the new way of handling ide_xxx_data * @@ -63,8 +80,13 @@ /* number of Etrax DMA descriptors */ #define MAX_DMA_DESCRS 64 +#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET +/* address where the memory-mapped IDE reset bit lives, if used */ +static volatile unsigned long *reset_addr; +#endif + #define LOWDB(x) -#define D(x) +#define D(x) void OUT_BYTE(unsigned char data, ide_ioreg_t reg) { LOWDB(printk("ob: data 0x%x, reg 0x%x\n", data, reg)); @@ -208,7 +230,8 @@ static void e100_ideproc (ide_ide_action_t func, ide_drive_t *drive, void *buffer, unsigned int length); /* defined below */ -void __init init_e100_ide (void) +void __init +init_e100_ide (void) { volatile unsigned int dummy; int h; @@ -226,6 +249,8 @@ } /* actually reset and configure the etrax100 ide/ata interface */ + /* This is mystifying; why is not G27 SET anywhere ? It's just reset here twice. */ + /* de-assert bus-reset */ #ifdef CONFIG_ETRAX_IDE_PB7_RESET port_pb_dir_shadow = port_pb_dir_shadow | @@ -252,7 +277,16 @@ *R_GEN_CONFIG = genconfig_shadow; #ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET - *(volatile long *)(MEM_CSE1_START | MEM_NON_CACHEABLE) = 0; +#ifndef CONFIG_CRIS_LOW_MAP + /* remap the I/O-mapped reset-bit from CSE1 to something inside our kernel space */ + reset_addr = (unsigned long *)ioremap((unsigned long)(MEM_CSE1_START | + MEM_NON_CACHEABLE), 16); + *reset_addr = 0; +#else + /* LOW_MAP, can't do the ioremap, but it's already mapped straight over */ + reset_addr = (unsigned long *)(MEM_CSE1_START | MEM_NON_CACHEABLE); + *reset_addr = 0; +#endif #endif /* wait some */ @@ -262,9 +296,11 @@ dummy = 3; #ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET - *(volatile long *)(MEM_CSE1_START | MEM_NON_CACHEABLE) = 1 << 16; - *R_PORT_G_DATA = 0; /* de-assert bus-reset */ + *reset_addr = 1 << 16; #endif +#ifdef CONFIG_ETRAX_IDE_G27_RESET + *R_PORT_G_DATA = 0; /* de-assert bus-reset */ +#endif /* make a dummy read to set the ata controller in a proper state */ dummy = *R_ATA_STATUS_DATA; @@ -286,9 +322,9 @@ IO_STATE( R_IRQ_MASK0_SET, ata_irq2, set ) | IO_STATE( R_IRQ_MASK0_SET, ata_irq3, set ) ); - printk("ide: waiting 10 seconds for drives to regain consciousness\n"); + printk("ide: waiting %d seconds for drives to regain consciousness\n", CONFIG_IDE_DELAY); - h = jiffies + 1000; + h = jiffies + (CONFIG_IDE_DELAY * HZ); while(jiffies < h) ; /* reset the dma channels we will use */ @@ -560,14 +596,6 @@ return 1; } - /* uh.. I'm lazy.. if size >= 65536, it should loop below and split it in - more than one descriptor */ - - if(size >= 65536) { - printk("too large ATA DMA request block, size = %d!\n", size); - return 1; - } - /* however, this case is more difficult - R_ATA_TRANSFER_CNT cannot be more than 65536 words per transfer, so in that case we need to either 1) use a DMA interrupt to re-trigger R_ATA_TRANSFER_CNT and continue with @@ -581,8 +609,22 @@ return 1; } - /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */ + /* If size > 65536 it has to be splitted into new descriptors. Since we don't handle + size > 131072 only one split is necessary */ + if(size > 65536) { + /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */ + ata_descrs[count].sw_len = 0; /* 0 means 65536, this is a 16-bit field */ + ata_descrs[count].ctrl = 0; + ata_descrs[count].buf = addr; + ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]); + count++; + ata_tot_size += 65536; + /* size and addr should refere to not handled data */ + size -= 65536; + addr += 65536; + } + /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */ ata_descrs[count].sw_len = size; ata_descrs[count].ctrl = 0; ata_descrs[count].buf = addr; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/serial.c linux.ac/arch/cris/drivers/serial.c --- linux.vanilla/arch/cris/drivers/serial.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/cris/drivers/serial.c Tue Apr 10 18:05:08 2001 @@ -1,12 +1,26 @@ -/* $Id: serial.c,v 1.6 2000/11/22 16:36:09 bjornw Exp $ +/* $Id: serial.c,v 1.10 2001/03/05 13:14:07 bjornw Exp $ * * Serial port driver for the ETRAX 100LX chip * - * Copyright (C) 1998, 1999, 2000 Axis Communications AB + * Copyright (C) 1998, 1999, 2000, 2001 Axis Communications AB * * Many, many authors. Based once upon a time on serial.c for 16x50. * * $Log: serial.c,v $ + * Revision 1.10 2001/03/05 13:14:07 bjornw + * Another spelling fix + * + * Revision 1.9 2001/02/23 13:46:38 bjornw + * Spellling check + * + * Revision 1.8 2001/01/23 14:56:35 markusl + * Made use of ser1 optional + * Needed by USB + * + * Revision 1.7 2001/01/19 16:14:48 perf + * Added kernel options for serial ports 234. + * Changed option names from CONFIG_ETRAX100_XYZ to CONFIG_ETRAX_XYZ. + * * Revision 1.6 2000/11/22 16:36:09 bjornw * Please marketing by using the correct case when spelling Etrax. * @@ -176,7 +190,7 @@ * */ -static char *serial_version = "$Revision: 1.6 $"; +static char *serial_version = "$Revision: 1.10 $"; #include <linux/config.h> #include <linux/version.h> @@ -252,12 +266,12 @@ //#define SERIAL_HANDLE_EARLY_ERRORS -#ifndef CONFIG_ETRAX100_SERIAL_RX_TIMEOUT_TICKS +#ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS /* Default number of timer ticks before flushing rx fifo * When using "little data, low latency applications: use 0 * When using "much data applications (PPP)" use ~5 */ -#define CONFIG_ETRAX100_SERIAL_RX_TIMEOUT_TICKS 5 +#define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5 #endif #define MAX_FLUSH_TIME 8 @@ -367,36 +381,36 @@ { /* Ser 0 */ { -#if defined(CONFIG_ETRAX100_SER0_DTR_RI_DSR_CD_ON_PB) +#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB) R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow, - CONFIG_ETRAX100_SER0_DTR_ON_PB_BIT, - CONFIG_ETRAX100_SER0_RI_ON_PB_BIT, - CONFIG_ETRAX100_SER0_DSR_ON_PB_BIT, - CONFIG_ETRAX100_SER0_CD_ON_PB_BIT + CONFIG_ETRAX_SER0_DTR_ON_PB_BIT, + CONFIG_ETRAX_SER0_RI_ON_PB_BIT, + CONFIG_ETRAX_SER0_DSR_ON_PB_BIT, + CONFIG_ETRAX_SER0_CD_ON_PB_BIT #else &dummy_ser0, &dummy_ser0, &dummy_dir_ser0, 0, 1, 2, 3 #endif }, /* Ser 1 */ { -#if defined(CONFIG_ETRAX100_SER1_DTR_RI_DSR_CD_ON_PB) +#if defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB) R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow, - CONFIG_ETRAX100_SER1_DTR_ON_PB_BIT, - CONFIG_ETRAX100_SER1_RI_ON_PB_BIT, - CONFIG_ETRAX100_SER1_DSR_ON_PB_BIT, - CONFIG_ETRAX100_SER1_CD_ON_PB_BIT + CONFIG_ETRAX_SER1_DTR_ON_PB_BIT, + CONFIG_ETRAX_SER1_RI_ON_PB_BIT, + CONFIG_ETRAX_SER1_DSR_ON_PB_BIT, + CONFIG_ETRAX_SER1_CD_ON_PB_BIT #else &dummy_ser1, &dummy_ser1, &dummy_dir_ser1, 0, 1, 2, 3 #endif }, /* Ser 2 */ { -#if defined(CONFIG_ETRAX100_SER2_DTR_RI_DSR_CD_ON_PA) +#if defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA) R_PORT_PA_DATA, &port_pa_data_shadow, &port_pa_dir_shadow, - CONFIG_ETRAX100_SER2_DTR_ON_PA_BIT, - CONFIG_ETRAX100_SER2_RI_ON_PA_BIT, - CONFIG_ETRAX100_SER2_DSR_ON_PA_BIT, - CONFIG_ETRAX100_SER2_CD_ON_PA_BIT + CONFIG_ETRAX_SER2_DTR_ON_PA_BIT, + CONFIG_ETRAX_SER2_RI_ON_PA_BIT, + CONFIG_ETRAX_SER2_DSR_ON_PA_BIT, + CONFIG_ETRAX_SER2_CD_ON_PA_BIT #else &dummy_ser2, &dummy_ser2, &dummy_dir_ser2, 0, 1, 2, 3 #endif @@ -459,7 +473,7 @@ static struct semaphore tmp_buf_sem = MUTEX; #endif -#ifdef CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST +#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST #define TIMER1_IRQ_NBR 3 /* clock select 10 for timer 1 gives 230400 Hz */ @@ -494,7 +508,7 @@ *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer1, set); fast_timer_started = 1; } -#endif /* CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST */ +#endif /* CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST */ /* * This function maps from the Bxxxx defines in asm/termbits.h into real @@ -1267,12 +1281,12 @@ /* dma fifo/buffer timeout handler forces an end-of-packet for the dma input channel if no chars - have been received for CONFIG_ETRAX100_RX_TIMEOUT_TICKS/100 s. - If CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST is configured then this + have been received for CONFIG_ETRAX_RX_TIMEOUT_TICKS/100 s. + If CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST is configured then this handler is instead run at 15360 Hz. */ -#ifndef CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST +#ifndef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST static int timeout_divider = 0; #endif @@ -1467,7 +1481,7 @@ info->xmit.buf = (unsigned char *) page; #ifdef SERIAL_DEBUG_OPEN - printk("starting up ttyS%d (xmit_buf 0x%x)...\n", info->line, info->xmit_buf); + printk("starting up ttyS%d (xmit_buf 0x%x)...\n", info->line, info->xmit.buf); #endif if(info->tty) { @@ -2688,12 +2702,15 @@ return -ENODEV; /* dont allow opening ports that are not enabled in the HW config */ - -#ifndef CONFIG_ETRAX100_SERIAL_PORT2 +#ifndef CONFIG_ETRAX_SERIAL_PORT1 + if (line == 1) + return -ENODEV; +#endif +#ifndef CONFIG_ETRAX_SERIAL_PORT2 if (line == 2) return -ENODEV; #endif -#ifndef CONFIG_ETRAX100_SERIAL_PORT3 +#ifndef CONFIG_ETRAX_SERIAL_PORT3 if (line == 3) return -ENODEV; #endif @@ -2955,7 +2972,7 @@ for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) { info->line = i; info->tty = 0; - info->type = PORT_ETRAX100; + info->type = PORT_ETRAX; info->tr_running = 0; info->fifo_magic = 0; info->fifo_didmagic = 0; @@ -2990,25 +3007,27 @@ if(request_irq(8, ser_interrupt, SA_INTERRUPT, "serial ", NULL)) panic("irq8"); #endif +#ifdef CONFIG_ETRAX_SERIAL_PORT1 if(request_irq(24, tr_interrupt, SA_INTERRUPT, "serial 1 dma tr", NULL)) panic("irq24"); if(request_irq(25, rec_interrupt, SA_INTERRUPT, "serial 1 dma rec", NULL)) panic("irq25"); -#ifdef CONFIG_ETRAX100_SERIAL_PORT2 +#endif +#ifdef CONFIG_ETRAX_SERIAL_PORT2 /* DMA Shared with par0 (and SCSI0 and ATA) */ if(request_irq(18, tr_interrupt, SA_SHIRQ, "serial 2 dma tr", NULL)) panic("irq18"); if(request_irq(19, rec_interrupt, SA_SHIRQ, "serial 2 dma rec", NULL)) panic("irq19"); #endif -#ifdef CONFIG_ETRAX100_SERIAL_PORT3 +#ifdef CONFIG_ETRAX_SERIAL_PORT3 /* DMA Shared with par1 (and SCSI1 and Extern DMA 0) */ if(request_irq(20, tr_interrupt, SA_SHIRQ, "serial 3 dma tr", NULL)) panic("irq20"); if(request_irq(21, rec_interrupt, SA_SHIRQ, "serial 3 dma rec", NULL)) panic("irq21"); #endif -#ifdef CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST +#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST /* TODO: a timeout_interrupt needs to be written that calls timeout_handler */ if(request_irq(TIMER1_IRQ_NBR, timeout_interrupt, SA_SHIRQ, "fast serial dma timeout", NULL)) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/serial.h linux.ac/arch/cris/drivers/serial.h --- linux.vanilla/arch/cris/drivers/serial.h Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/drivers/serial.h Tue Apr 10 18:05:08 2001 @@ -4,8 +4,8 @@ * Copyright (C) 1998, 1999, 2000 Axis Communications AB */ -#ifndef _ETRAX100_SERIAL_H -#define _ETRAX100_SERIAL_H +#ifndef _ETRAX_SERIAL_H +#define _ETRAX_SERIAL_H #include <linux/config.h> #include <linux/circ_buf.h> @@ -64,7 +64,7 @@ unsigned long event; unsigned long last_active; int line; - int type; /* PORT_ETRAX100 */ + int type; /* PORT_ETRAX */ int count; /* # of fd on device */ int blocked_open; /* # of blocked opens */ long session; /* Session of opening process */ @@ -93,7 +93,7 @@ * system. */ -#define PORT_ETRAX100 1 +#define PORT_ETRAX 1 /* * Events are used to schedule things to happen at timer-interrupt @@ -103,4 +103,4 @@ #endif /* __KERNEL__ */ -#endif /* !(_ETRAX100_SERIAL_H) */ +#endif /* !(_ETRAX_SERIAL_H) */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/sync_serial.c linux.ac/arch/cris/drivers/sync_serial.c --- linux.vanilla/arch/cris/drivers/sync_serial.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/drivers/sync_serial.c Tue Apr 10 18:05:08 2001 @@ -0,0 +1,873 @@ +/* + * Simple synchronous serial port driver for ETRAX 100LX. + * + * Synchronous serial ports are used for continous streamed data like audio. + * The deault setting for this driver is compatible with the STA 013 MP3 decoder + * The driver can easily be tuned to fit other audio encoder/decoders and SPI + * + * Copyright (c) 2001 Axis Communications AB + * + * Author: Mikael Starvik + * + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/config.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/major.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <asm/svinto.h> +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/sync_serial.h> + +/* The receiver is a bit tricky beacuse of the continous stream of data. */ +/* */ +/* Two DMA descriptors are linked together. Each DMA descriptor is */ +/* responsible for one half of a common buffer. */ +/* */ +/* ------------------------------ */ +/* | ---------- ---------- | */ +/* --> | Descr1 |-->| Descr2 |--- */ +/* ---------- ---------- */ +/* | | */ +/* v v */ +/* ----------------------------- */ +/*  | BUFFER | */ +/* ----------------------------- */ +/* | | */ +/* readp writep */ +/* */ +/* If the application keeps up the pace readp will be right after writep.*/ +/* If the application can't keep the pace we have to throw away data. */ +/* The idea is that readp should be ready with the data pointed out by */ +/* Descr1 when the DMA has filled in Descr2. Otherwise we will discard */ +/* the rest of the data pointed out by Descr1 and set readp to the start */ +/* of Descr2 */ + +#define SYNC_SERIAL_MAJOR 125 + +#define IN_BUFFER_SIZE 8192 +#define OUT_BUFFER_SIZE 4096 + +#define DEBUG(x) + +/* Define some macros to access Etrax 100 registers */ +#define SETF(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \ + IO_FIELD(##reg##, field, val) +#define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \ + IO_STATE(##reg##, field, val) + +typedef struct sync_port +{ + /* Etrax registers and bits*/ + volatile unsigned * const status; + volatile unsigned * const ctrl_data; + volatile unsigned * const output_dma_first; + volatile unsigned char * const output_dma_cmd; + volatile unsigned char * const output_dma_clr_irq; + volatile unsigned * const input_dma_first; + volatile unsigned char * const input_dma_cmd; + volatile unsigned char * const input_dma_clr_irq; + volatile unsigned * const data_out; + volatile unsigned * const data_in; + char data_avail_bit; /* In R_IRQ_MASK1_RD */ + char transmitter_ready_bit; /* In R_IRQ_MASK1_RD */ + char ready_irq_bit; /* In R_IRQ_MASK1_SET and R_IRQ_MASK1_CLR */ + char input_dma_eop_bit; /* In R_IRQ_MASK2_RD */ + char input_dma_descr_bit; /* In R_IRQ_MASK2_RD */ + char output_dma_bit; /* In R_IRQ_MASK2_RD */ + char eop_bit; /* In R_SET_EOP */ + + int enabled; /* 1 if port is enabled */ + int use_dma; /* 1 if port uses dma */ + int port_nbr; /* Port 0 or 1 */ + unsigned ctrl_data_shadow; /* Register shadow */ + char busy; /* 1 if port is busy */ + wait_queue_head_t out_wait_q; + wait_queue_head_t in_wait_q; + struct etrax_dma_descr out_descr; + struct etrax_dma_descr in_descr1; + struct etrax_dma_descr in_descr2; + char out_buffer[OUT_BUFFER_SIZE]; + int out_count; /* Remaining bytes for current transfer */ + char* outp; /* Current position in out_buffer */ + char in_buffer[IN_BUFFER_SIZE]; + volatile char* readp; /* Next byte to be read by application */ + volatile char* writep; /* Next byte to be written by etrax */ + int odd_output; /* 1 if writing odd nible in 12 bit mode */ + int odd_input; /* 1 if reading odd nible in 12 bit mode */ +} sync_port; + + +static int etrax_sync_serial_init(void); +static void initialize_port(int portnbr); +static int sync_serial_open(struct inode *, struct file*); +static int sync_serial_release(struct inode*, struct file*); +static int sync_serial_ioctl(struct inode*, struct file*, + unsigned int cmd, unsigned long arg); +static ssize_t sync_serial_write(struct file * file, const char * buf, + size_t count, loff_t *ppos); +static ssize_t sync_serial_manual_write(struct file * file, const char * buf, + size_t count, loff_t *ppos); +static ssize_t sync_serial_read(struct file *file, char *buf, + size_t count, loff_t *ppos); +static void send_word(sync_port* port); +static void start_dma(struct sync_port *port, const char* data, int count); +static void start_dma_in(sync_port* port); +static void tr_interrupt(int irq, void *dev_id, struct pt_regs * regs); +static void rx_interrupt(int irq, void *dev_id, struct pt_regs * regs); +static void manual_interrupt(int irq, void *dev_id, struct pt_regs * regs); +static void flush_handler(void); + +/* The ports */ +static struct sync_port ports[]= +{ + { + R_SYNC_SERIAL1_STATUS, /* status */ + R_SYNC_SERIAL1_CTRL, /* ctrl_data */ + R_DMA_CH8_FIRST, /* output_dma_first */ + R_DMA_CH8_CMD, /* output_dma_cmd */ + R_DMA_CH8_CLR_INTR, /* output_dma_clr_irq */ + R_DMA_CH9_FIRST, /* input_dma_first */ + R_DMA_CH9_CMD, /* input_dma_cmd */ + R_DMA_CH9_CLR_INTR, /* input_dma_clr_irq */ + R_SYNC_SERIAL1_TR_DATA, /* data_out */ + R_SYNC_SERIAL1_REC_DATA,/* data in */ + IO_BITNR(R_IRQ_MASK1_RD, ser1_data), /* data_avail_bit */ + IO_BITNR(R_IRQ_MASK1_RD, ser1_ready), /* transmitter_ready_bit */ + IO_BITNR(R_IRQ_MASK1_SET, ser1_ready), /* ready_irq_bit */ + IO_BITNR(R_IRQ_MASK2_RD, dma9_eop), /* input_dma_eop_bit */ + IO_BITNR(R_IRQ_MASK2_RD, dma9_descr), /* input_dma_descr_bit */ + IO_BITNR(R_IRQ_MASK2_RD, dma8_eop), /* output_dma_bit */ + IO_BITNR(R_SET_EOP, ch9_eop) /* eop_bit */ + }, + { + R_SYNC_SERIAL3_STATUS, /* status */ + R_SYNC_SERIAL3_CTRL, /* ctrl_data */ + R_DMA_CH4_FIRST, /* output_dma_first */ + R_DMA_CH4_CMD, /* output_dma_cmd */ + R_DMA_CH4_CLR_INTR, /* output_dma_clr_irq */ + R_DMA_CH5_FIRST, /* input_dma_first */ + R_DMA_CH5_CMD, /* input_dma_cmd */ + R_DMA_CH5_CLR_INTR, /* input_dma_clr_irq */ + R_SYNC_SERIAL3_TR_DATA, /* data_out */ + R_SYNC_SERIAL3_REC_DATA,/* data in */ + IO_BITNR(R_IRQ_MASK1_RD, ser3_data), /* data_avail_bit */ + IO_BITNR(R_IRQ_MASK1_RD, ser3_ready), /* transmitter_ready_bit */ + IO_BITNR(R_IRQ_MASK1_SET, ser3_ready), /* ready_irq_bit */ + IO_BITNR(R_IRQ_MASK2_RD, dma5_eop), /* input_dma_eop_bit */ + IO_BITNR(R_IRQ_MASK2_RD, dma5_descr), /* input_dma_eop_bit */ + IO_BITNR(R_IRQ_MASK2_RD, dma4_eop), /* output_dma_bit */ + IO_BITNR(R_SET_EOP, ch5_eop) /* eop_bit */ + } +}; + +/* Register shadows */ +static unsigned sync_serial_prescale_shadow = 0; +static unsigned gen_config_ii_shadow = 0; + +/* Timer used to flush data from the DMA */ +static struct timer_list flush_timer; + +#define NUMBER_OF_PORTS (sizeof(ports)/sizeof(sync_port)) + +static struct file_operations sync_serial_fops = { + owner: THIS_MODULE, + write: sync_serial_write, + read: sync_serial_read, + ioctl: sync_serial_ioctl, + open: sync_serial_open, + release: sync_serial_release +}; + +static int __init etrax_sync_serial_init(void) +{ + ports[0].enabled = 0; + ports[1].enabled = 0; + + if (register_chrdev(SYNC_SERIAL_MAJOR,"sync serial", &sync_serial_fops) <0 ) + { + printk("unable to get major for synchronous serial port\n"); + return -EBUSY; + } + + /* Deselect synchronous serial ports */ + SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, async); + SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, async); + SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, ser3, select); + *R_GEN_CONFIG_II = gen_config_ii_shadow; + + /* Initialize Ports */ +#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) + ports[0].enabled = 1; + SETS(port_pb_i2c_shadow, R_PORT_PB_I2C, syncser1, ss1extra); + SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, sync); +#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA) + ports[0].use_dma = 1; + initialize_port(0); + if(request_irq(24, tr_interrupt, 0, "synchronous serial 1 dma tr", NULL)) + panic("Can't allocate sync serial port 1 IRQ"); + if(request_irq(25, rx_interrupt, 0, "synchronous serial 1 dma rx", NULL)) + panic("Can't allocate sync serial port 1 IRQ"); + RESET_DMA(8); WAIT_DMA(8); + RESET_DMA(9); WAIT_DMA(9); + *R_DMA_CH8_CLR_INTR = 3; /* Clear IRQ */ + *R_DMA_CH9_CLR_INTR = 3; /* Clear IRQ */ + *R_IRQ_MASK2_SET = + IO_STATE(R_IRQ_MASK2_SET, dma8_eop, set) | + IO_STATE(R_IRQ_MASK2_SET, dma8_descr, set) | + IO_STATE(R_IRQ_MASK2_SET, dma9_eop, set) | + IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set); + start_dma_in(&ports[0]); +#else + ports[0].use_dma = 0; + initialize_port(0); + if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", NULL)) + panic("Can't allocate sync serial manual irq"); + *R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser1_data, set); +#endif +#endif + +#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) + ports[1].enabled = 1; + SETS(port_pb_i2c_shadow, R_PORT_PB_I2C, syncser3, ss3extra); + SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, sync); +#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA) + ports[1].use_dma = 1; + initialize_port(1); + if(request_irq(20, tr_interrupt, 0, "synchronous serial 3 dma tr", NULL)) + panic("Can't allocate sync serial port 1 IRQ"); + if(request_irq(21, rx_interrupt, 0, "synchronous serial 3 dma rx", NULL)) + panic("Can't allocate sync serial port 1 IRQ"); + RESET_DMA(4); WAIT_DMA(4); + RESET_DMA(5); WAIT_DMA(5); + *R_DMA_CH4_CLR_INTR = 3; /* Clear IRQ */ + *R_DMA_CH5_CLR_INTR = 3; /* Clear IRQ */ + *R_IRQ_MASK2_SET = + IO_STATE(R_IRQ_MASK2_SET, dma4_eop, set) | + IO_STATE(R_IRQ_MASK2_SET, dma4_descr, set) | + IO_STATE(R_IRQ_MASK2_SET, dma5_eop, set) | + IO_STATE(R_IRQ_MASK2_SET, dma5_descr, set); + start_dma_in(&ports[1]); +#else + ports[1].use_dma = 0; + initialize_port(1); + if (port[0].use_dma) /* Port 0 uses dma, we must manual allocate IRQ */ + { + if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", NULL)) + panic("Can't allocate sync serial manual irq"); + } + *R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser3_data, set); +#endif +#endif + + *R_PORT_PB_I2C = port_pb_i2c_shadow; /* Use PB4/PB7 */ + + /* Set up timing */ + *R_SYNC_SERIAL_PRESCALE = sync_serial_prescale_shadow = ( + IO_STATE(R_SYNC_SERIAL_PRESCALE, clk_sel_u1, codec) | + IO_STATE(R_SYNC_SERIAL_PRESCALE, word_stb_sel_u1, external) | + IO_STATE(R_SYNC_SERIAL_PRESCALE, clk_sel_u3, codec) | + IO_STATE(R_SYNC_SERIAL_PRESCALE, word_stb_sel_u3, external) | + IO_STATE(R_SYNC_SERIAL_PRESCALE, prescaler, div4) | + IO_FIELD(R_SYNC_SERIAL_PRESCALE, frame_rate, 0) | + IO_FIELD(R_SYNC_SERIAL_PRESCALE, word_rate, 7) | + IO_STATE(R_SYNC_SERIAL_PRESCALE, warp_mode, normal)); + + /* Select synchronous ports */ + *R_GEN_CONFIG_II = gen_config_ii_shadow; + + /*Initialize DMA flush timer if dma is used */ + if (ports[0].use_dma || ports[1].use_dma) + { + init_timer(&flush_timer); + flush_timer.function = flush_handler; + mod_timer(&flush_timer, jiffies + 10); + } + + printk("Etrax100LX synchronous serial port driver\n"); + return 0; +} + +static void initialize_port(int portnbr) +{ + struct sync_port* port = &ports[portnbr]; + + DEBUG(printk("Init sync serial port %d\n", portnbr)); + + port->port_nbr = portnbr; + port->busy = 0; + port->readp = port->in_buffer; + port->writep = port->in_buffer + IN_BUFFER_SIZE/2; + port->odd_input = 0; + + init_waitqueue_head(&port->out_wait_q); + init_waitqueue_head(&port->in_wait_q); + + port->ctrl_data_shadow = + IO_STATE(R_SYNC_SERIAL1_CTRL, tr_baud, c115k2Hz) | + IO_STATE(R_SYNC_SERIAL1_CTRL, mode, master_output) | + IO_STATE(R_SYNC_SERIAL1_CTRL, error, ignore) | + IO_STATE(R_SYNC_SERIAL1_CTRL, rec_enable, disable) | + IO_STATE(R_SYNC_SERIAL1_CTRL, f_synctype, normal) | + IO_STATE(R_SYNC_SERIAL1_CTRL, f_syncsize, word) | + IO_STATE(R_SYNC_SERIAL1_CTRL, f_sync, on) | + IO_STATE(R_SYNC_SERIAL1_CTRL, clk_mode, normal) | + IO_STATE(R_SYNC_SERIAL1_CTRL, clk_halt, running) | + IO_STATE(R_SYNC_SERIAL1_CTRL, bitorder, msb) | + IO_STATE(R_SYNC_SERIAL1_CTRL, tr_enable, enable) | + IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit) | + IO_STATE(R_SYNC_SERIAL1_CTRL, buf_empty, lmt_8) | + IO_STATE(R_SYNC_SERIAL1_CTRL, buf_full, lmt_8) | + IO_STATE(R_SYNC_SERIAL1_CTRL, flow_ctrl, enabled) | + IO_STATE(R_SYNC_SERIAL1_CTRL, clk_polarity, neg) | + IO_STATE(R_SYNC_SERIAL1_CTRL, frame_polarity, normal)| + IO_STATE(R_SYNC_SERIAL1_CTRL, status_polarity, inverted)| + IO_STATE(R_SYNC_SERIAL1_CTRL, clk_driver, normal) | + IO_STATE(R_SYNC_SERIAL1_CTRL, frame_driver, normal) | + IO_STATE(R_SYNC_SERIAL1_CTRL, status_driver, normal)| + IO_STATE(R_SYNC_SERIAL1_CTRL, def_out0, high); + + if (port->use_dma) + port->ctrl_data_shadow |= IO_STATE(R_SYNC_SERIAL1_CTRL, dma_enable, on); + else + port->ctrl_data_shadow |= IO_STATE(R_SYNC_SERIAL1_CTRL, dma_enable, off); + + *port->ctrl_data = port->ctrl_data_shadow; +} + +static int sync_serial_open(struct inode *inode, struct file *file) +{ + int dev = MINOR(inode->i_rdev); + DEBUG(printk("Open sync serial port %d\n", dev)); + + if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) + { + DEBUG(printk("Invalid minor %d\n", dev)); + return -ENODEV; + } + if (ports[dev].busy) + { + DEBUG(printk("Device is busy.. \n")); + return -EBUSY; + } + ports[dev].busy = 1; + return 0; +} + +static int sync_serial_release(struct inode *inode, struct file *file) +{ + ports[MINOR(inode->i_rdev)].busy = 0; + return 0; +} + +static int sync_serial_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int dev = MINOR(file->f_dentry->d_inode->i_rdev); + sync_port* port = &ports[dev]; + + /* Disable port while changing config */ + if (dev) + { + RESET_DMA(4); WAIT_DMA(4); + *R_DMA_CH4_CLR_INTR = 3; + SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, async); + } + else + { + RESET_DMA(8); WAIT_DMA(8); + *R_DMA_CH8_CLR_INTR = 3; + SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, async); + } + *R_GEN_CONFIG_II = gen_config_ii_shadow; + + switch(cmd) + { + case SSP_SPEED: + if (GET_SPEED(arg) == CODEC) + { + if (dev) + SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u3, codec); + else + SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u1, codec); + + SETF(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, prescaler, GET_FREQ(arg)); + SETF(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, frame_rate, GET_FRAME_RATE(arg)); + SETF(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, word_rate, GET_WORD_RATE(arg)); + } + else + { + SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_baud, GET_SPEED(arg)); + if (dev) + SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u3, baudrate); + else + SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u1, baudrate); + } + break; + case SSP_MODE: + if (arg > 5) + return -EINVAL; + SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, arg); + break; + case SSP_FRAME_SYNC: + if (arg & NORMAL_SYNC) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_synctype, normal); + else if (arg & EARLY_SYNC) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_synctype, early); + + if (arg & BIT_SYNC) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, bit); + else if (arg & WORD_SYNC) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, word); + else if (arg & EXTENDED_SYNC) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, extended); + + if (arg & SYNC_ON) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_sync, on); + else if (arg & SYNC_OFF) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_sync, off); + + if (arg & WORD_SIZE_8) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size8bit); + else if (arg & WORD_SIZE_12) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size12bit); + else if (arg & WORD_SIZE_16) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size16bit); + else if (arg & WORD_SIZE_24) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size24bit); + else if (arg & WORD_SIZE_32) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size32bit); + + if (arg & BIT_ORDER_MSB) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, bitorder, msb); + else if (arg & BIT_ORDER_LSB) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, bitorder, lsb); + + if (arg & FLOW_CONTROL_ENABLE) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, flow_ctrl, enabled); + else if (arg & FLOW_CONTROL_DISABLE) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, flow_ctrl, disabled); + + if (arg & CLOCK_NOT_GATED) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, normal); + else if (arg & CLOCK_GATED) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, gated); + + break; + case SSP_IPOLARITY: + if (arg & CLOCK_NORMAL) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_polarity, neg); + else if (arg & CLOCK_INVERT) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_polarity, pos); + + if (arg & FRAME_NORMAL) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_polarity, normal); + else if (arg & FRAME_INVERT) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_polarity, inverted); + + if (arg & STATUS_NORMAL) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_polarity, normal); + else if (arg & STATUS_INVERT) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_polarity, inverted); + break; + case SSP_OPOLARITY: + if (arg & CLOCK_NORMAL) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_driver, normal); + else if (arg & CLOCK_INVERT) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_driver, inverted); + + if (arg & FRAME_NORMAL) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_driver, normal); + else if (arg & FRAME_INVERT) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_driver, inverted); + + if (arg & STATUS_NORMAL) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_driver, normal); + else if (arg & STATUS_INVERT) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_driver, inverted); + break; + case SSP_SPI: + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, flow_ctrl, disabled); + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, bitorder, msb); + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size8bit); + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_sync, on); + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, word); + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_synctype, normal); + if (arg & SPI_SLAVE) + { + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_polarity, inverted); + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_polarity, neg); + SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, SLAVE_INPUT); + } + else + { + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_driver, inverted); + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_driver, inverted); + SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, MASTER_OUTPUT); + } + break; + default: + return -EINVAL; + } + /* Set config and enable port */ + *port->ctrl_data = port->ctrl_data_shadow; + *R_SYNC_SERIAL_PRESCALE = sync_serial_prescale_shadow; + if (dev) + SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, sync); + else + SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, sync); + + *R_GEN_CONFIG_II = gen_config_ii_shadow; + return 0; +} + +static ssize_t sync_serial_manual_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + sync_port* port = &ports[MINOR(file->f_dentry->d_inode->i_rdev)]; + + copy_from_user(port->out_buffer, buf, count); + port->outp = port->out_buffer; + port->out_count = count; + port->odd_output = 1; + add_wait_queue(&port->out_wait_q, &wait); + set_current_state(TASK_INTERRUPTIBLE); + *R_IRQ_MASK1_SET = 1 << port->ready_irq_bit; /* transmitter ready IRQ on */ + send_word(port); /* Start sender by sending first word */ + schedule(); + set_current_state(TASK_RUNNING); + remove_wait_queue(&port->out_wait_q, &wait); + return count; +} + +static ssize_t sync_serial_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + sync_port *port = &ports[MINOR(file->f_dentry->d_inode->i_rdev)]; + + DEBUG(printk("Write dev %d count %d\n", port->port_nbr, count)); + + if (!port->use_dma) + { + return sync_serial_manual_write(file, buf, count, ppos); + } + + copy_from_user(port->out_buffer, buf, count); + add_wait_queue(&port->out_wait_q, &wait); + set_current_state(TASK_INTERRUPTIBLE); + start_dma(port, buf, count); + schedule(); + set_current_state(TASK_RUNNING); + remove_wait_queue(&port->out_wait_q, &wait); + return count; +} + +static ssize_t sync_serial_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + int avail; + sync_port *port = &ports[MINOR(file->f_dentry->d_inode->i_rdev)]; + char* start; + char* end; + unsigned long flags; + + DEBUG(printk("Read dev %d count\n")); + + /* Calculate number of available bytes */ + while (port->readp == port->writep) /* No data */ + { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + interruptible_sleep_on(&port->in_wait_q); + } + + /* Save pointers to avoid that they are modified by interrupt */ + start = port->readp; + end = port->writep; + + /* Lazy read, never return wrapped data. */ + if (end > start) + avail = end - start; + else + avail = port->in_buffer + IN_BUFFER_SIZE - start; + + count = count > avail ? avail : count; + copy_to_user(buf, start, count); + + /* Disable interrupts while updating readp */ + save_flags(flags); + cli(); + port->readp += count; + if (port->readp == port->in_buffer + IN_BUFFER_SIZE) /* Wrap? */ + port->readp = port->in_buffer; + restore_flags(flags); + + DEBUG(printk("%d bytes read\n", count)); + return count; +} + +static void send_word(sync_port* port) +{ + switch(port->ctrl_data_shadow & IO_MASK(R_SYNC_SERIAL1_CTRL, wordsize)) + { + case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit): + port->out_count--; + *port->data_out = *port->outp++; + break; + case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size12bit): + port->out_count--; + if (port->odd_output) + *port->data_out = ((*port->outp) << 16) | (*(unsigned short *)(port->outp + 1)); + else + *port->data_out = ((*(unsigned short *)port->outp) << 8) | (*(port->outp + 1)); + port->odd_output = !port->odd_output; + port->outp++; + break; + case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size16bit): + port->out_count-=2; + *port->data_out = *(unsigned short *)port->outp; + port->outp+=2; + break; + case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size24bit): + port->out_count-=3; + *port->data_out = *(unsigned int *)port->outp; + port->outp+=3; + break; + case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size32bit): + port->out_count-=4; + *port->data_out = *(unsigned int *)port->outp; + port->outp+=4; + break; + } +} + +static void start_dma(struct sync_port* port, const char* data, int count) +{ + port->out_descr.hw_len = 0; + port->out_descr.next = 0; + port->out_descr.ctrl = d_int | d_eol | d_eop; + port->out_descr.sw_len = count; + port->out_descr.buf = virt_to_phys(port->out_buffer); + port->out_descr.status = 0; + + *port->output_dma_first = virt_to_phys(&port->out_descr); + *port->output_dma_cmd = IO_STATE(R_DMA_CH0_CMD, cmd, start); +} + +static void start_dma_in(sync_port* port) +{ + if (port->writep > port->in_buffer + IN_BUFFER_SIZE) + { + panic("Offset too large in sync serial driver\n"); + return; + } + port->in_descr1.hw_len = 0; + port->in_descr1.ctrl = d_eop | d_int; + port->in_descr1.status = 0; + port->in_descr1.next = virt_to_phys(&port->in_descr2); + port->in_descr2.hw_len = 0; + port->in_descr2.next = virt_to_phys(&port->in_descr1); + port->in_descr2.ctrl = d_eop | d_int; + port->in_descr2.status = 0; + + /* Find out which descriptor to start */ + if (port->writep >= port->in_buffer + IN_BUFFER_SIZE/2) + { + /* Start descriptor 2 */ + port->in_descr1.sw_len = IN_BUFFER_SIZE/2; /* All data available in 1 */ + port->in_descr1.buf = virt_to_phys(port->in_buffer); + port->in_descr2.sw_len = port->in_buffer + IN_BUFFER_SIZE - port->writep; + port->in_descr2.buf = virt_to_phys(port->writep); + *port->input_dma_first = virt_to_phys(&port->in_descr2); + } + else + { + /* Start descriptor 1 */ + port->in_descr1.sw_len = port->in_buffer + IN_BUFFER_SIZE/2 - port->writep; + port->in_descr1.buf = virt_to_phys(port->writep); + port->in_descr2.sw_len = IN_BUFFER_SIZE/2; + port->in_descr2.buf = virt_to_phys(port->in_buffer + IN_BUFFER_SIZE / 2); + *port->input_dma_first = virt_to_phys(&port->in_descr1); + } + *port->input_dma_cmd = IO_STATE(R_DMA_CH0_CMD, cmd, start); +} + +static void tr_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + unsigned long ireg = *R_IRQ_MASK2_RD; + int i; + + for (i = 0; i < NUMBER_OF_PORTS; i++) + { + sync_port *port = &ports[i]; + if (ireg & (1 << port->output_dma_bit)) /* IRQ active for the port? */ + { + /* Clear IRQ */ + *port->output_dma_clr_irq = + IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH0_CLR_INTR, clr_descr, do); + wake_up_interruptible(&port->out_wait_q); /* wake up the waiting process */ + } + } +} + +static void rx_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + unsigned long ireg = *R_IRQ_MASK2_RD; + int i; + + for (i = 0; i < NUMBER_OF_PORTS; i++) + { + int update = 0; + sync_port *port = &ports[i]; + + if (!port->enabled) + { + continue; + } + + if (ireg & (1 << port->input_dma_descr_bit)) /* Descriptor interrupt */ + { + /* DMA has reached end of descriptor */ + *port->input_dma_clr_irq = + IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH0_CLR_INTR, clr_descr, do); + + /* Find out which descriptor that is ready */ + if (port->writep >= port->in_buffer + IN_BUFFER_SIZE/2) + { + /* Descr 2 was ready. Restart DMA at descriptor 1 */ + port->writep = port->in_buffer; + + /* Throw away data? */ + if (port->readp < port->in_buffer + IN_BUFFER_SIZE/2) + port->readp = port->in_buffer + IN_BUFFER_SIZE/2; + } + else + { + /* Descr 1 was ready. Restart DMA at descriptor 2 */ + port->writep = port->in_buffer + IN_BUFFER_SIZE/2; + + /* Throw away data? */ + if (port->readp >= port->in_buffer + IN_BUFFER_SIZE/2) + port->readp = port->in_buffer; + } + start_dma_in(port); + wake_up_interruptible(&port->in_wait_q); /* wake up the waiting process */ + } + else if (ireg & (1 << port->input_dma_eop_bit)) /* EOP interrupt */ + { + /* EOP interrupt means that DMA has not reached end of descriptor */ + *port->input_dma_clr_irq = + IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH0_CLR_INTR, clr_descr, do); + + /* Find out the current descriptor */ + if (port->writep >= port->in_buffer + IN_BUFFER_SIZE/2) + port->writep += port->in_descr2.hw_len; + else + port->writep += port->in_descr1.hw_len; + + start_dma_in(port); + wake_up_interruptible(&port->in_wait_q); /* wake up the waiting process */ + } + } +} + +static void manual_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + int i; + + for (i = 0; i < NUMBER_OF_PORTS; i++) + { + sync_port* port = &ports[i]; + + if (!port->enabled) + { + continue; + } + + if (*R_IRQ_MASK1_RD & (1 << port->data_avail_bit)) /* Data received? */ + { + /* Read data */ + switch(port->ctrl_data_shadow & IO_MASK(R_SYNC_SERIAL1_CTRL, wordsize)) + { + case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit): + *port->writep++ = *(volatile char *)port->data_in; + break; + case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size12bit): + { + int data = *(unsigned short *)port->data_in; + if (port->odd_input) + { + *port->writep |= (data & 0x0f00) >> 8; + *(port->writep + 1) = data & 0xff; + } + else + { + *port->writep = (data & 0x0ff0) >> 4; + *(port->writep + 1) = (data & 0x0f) << 4; + } + port->odd_input = !port->odd_input; + port->writep+=1; + } + break; + case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size16bit): + *(unsigned short*)port->writep = *(volatile unsigned short *)port->data_in; + port->writep+=2; + break; + case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size24bit): + *(unsigned int*)port->writep = *port->data_in; + port->writep+=3; + break; + case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size32bit): + *(unsigned int*)port->writep = *port->data_in; + port->writep+=4; + break; + } + + if (port->writep > port->in_buffer + IN_BUFFER_SIZE) /* Wrap? */ + port->writep = port->in_buffer; + wake_up_interruptible(&port->in_wait_q); /* Wake up application */ + } + + if (*R_IRQ_MASK1_RD & (1 << port->transmitter_ready_bit)) /* Transmitter ready? */ + { + if (port->out_count) /* More data to send */ + send_word(port); + else /* transmission finished */ + { + *R_IRQ_MASK1_CLR = 1 << port->ready_irq_bit; /* Turn off IRQ */ + wake_up_interruptible(&port->out_wait_q); /* Wake up application */ + } + } + } +} + +static void flush_handler(void) +{ + int i; + + for (i = 0; i < NUMBER_OF_PORTS; i++) + { + if (ports[i].enabled) + { + *R_SET_EOP = 1 << ports[i].eop_bit; + } + } + /* restart flush timer */ + mod_timer(&flush_timer, jiffies + 10); +} + +module_init(etrax_sync_serial_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/usb-host.c linux.ac/arch/cris/drivers/usb-host.c --- linux.vanilla/arch/cris/drivers/usb-host.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/drivers/usb-host.c Tue Apr 10 18:05:08 2001 @@ -0,0 +1,2501 @@ +/* + * usb-host.c: ETRAX 100LX USB Host Controller Driver (HCD) + * + * Copyright (c) 2001 Axis Communications AB. + * + * $Id: usb-host.c,v 1.8 2001/02/27 13:52:48 bjornw Exp $ + * + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/version.h> +#include <linux/list.h> + +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/svinto.h> + +#include <linux/usb.h> +#include "usb-host.h" + +#define ETRAX_USB_HC_IRQ 31 +#define ETRAX_USB_RX_IRQ 25 +#define ETRAX_USB_TX_IRQ 24 + +static const char *usb_hcd_version = "$Revision: 1.8 $"; + +#undef KERN_DEBUG +#define KERN_DEBUG "" + +#undef USB_DEBUG_RH +#undef USB_DEBUG_EP +#undef USB_DEBUG_DESC +#undef USB_DEBUG_TRACE +#undef USB_DEBUG_CTRL +#undef USB_DEBUG_BULK +#undef USB_DEBUG_INTR + +#ifdef USB_DEBUG_RH +#define dbg_rh(format, arg...) printk(KERN_DEBUG __FILE__ ": (RH) " format "\n" , ## arg) +#else +#define dbg_rh(format, arg...) do {} while (0) +#endif + +#ifdef USB_DEBUG_EP +#define dbg_ep(format, arg...) printk(KERN_DEBUG __FILE__ ": (EP) " format "\n" , ## arg) +#else +#define dbg_ep(format, arg...) do {} while (0) +#endif + +#ifdef USB_DEBUG_CTRL +#define dbg_ctrl(format, arg...) printk(KERN_DEBUG __FILE__ ": (CTRL) " format "\n" , ## arg) +#else +#define dbg_ctrl(format, arg...) do {} while (0) +#endif + +#ifdef USB_DEBUG_BULK +#define dbg_bulk(format, arg...) printk(KERN_DEBUG __FILE__ ": (BULK) " format "\n" , ## arg) +#else +#define dbg_bulk(format, arg...) do {} while (0) +#endif + +#ifdef USB_DEBUG_INTR +#define dbg_intr(format, arg...) printk(KERN_DEBUG __FILE__ ": (INTR) " format "\n" , ## arg) +#else +#define dbg_intr(format, arg...) do {} while (0) +#endif + +#ifdef USB_DEBUG_TRACE +#define DBFENTER (printk(KERN_DEBUG __FILE__ ": Entering : " __FUNCTION__ "\n")) +#define DBFEXIT (printk(KERN_DEBUG __FILE__ ": Exiting : " __FUNCTION__ "\n")) +#else +#define DBFENTER (NULL) +#define DBFEXIT (NULL) +#endif + +/*------------------------------------------------------------------- + Virtual Root Hub + -------------------------------------------------------------------*/ + +static __u8 root_hub_dev_des[] = +{ + 0x12, /* __u8 bLength; */ + 0x01, /* __u8 bDescriptorType; Device */ + 0x00, /* __u16 bcdUSB; v1.0 */ + 0x01, + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x00, /* __u8 bDeviceProtocol; */ + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + 0x00, /* __u16 idVendor; */ + 0x00, + 0x00, /* __u16 idProduct; */ + 0x00, + 0x00, /* __u16 bcdDevice; */ + 0x00, + 0x00, /* __u8 iManufacturer; */ + 0x02, /* __u8 iProduct; */ + 0x01, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + +/* Configuration descriptor */ +static __u8 root_hub_config_des[] = +{ + 0x09, /* __u8 bLength; */ + 0x02, /* __u8 bDescriptorType; Configuration */ + 0x19, /* __u16 wTotalLength; */ + 0x00, + 0x01, /* __u8 bNumInterfaces; */ + 0x01, /* __u8 bConfigurationValue; */ + 0x00, /* __u8 iConfiguration; */ + 0x40, /* __u8 bmAttributes; Bit 7: Bus-powered */ + 0x00, /* __u8 MaxPower; */ + + /* interface */ + 0x09, /* __u8 if_bLength; */ + 0x04, /* __u8 if_bDescriptorType; Interface */ + 0x00, /* __u8 if_bInterfaceNumber; */ + 0x00, /* __u8 if_bAlternateSetting; */ + 0x01, /* __u8 if_bNumEndpoints; */ + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ + 0x00, /* __u8 if_bInterfaceSubClass; */ + 0x00, /* __u8 if_bInterfaceProtocol; */ + 0x00, /* __u8 if_iInterface; */ + + /* endpoint */ + 0x07, /* __u8 ep_bLength; */ + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x08, /* __u16 ep_wMaxPacketSize; 8 Bytes */ + 0x00, + 0xff /* __u8 ep_bInterval; 255 ms */ +}; + +static __u8 root_hub_hub_des[] = +{ + 0x09, /* __u8 bLength; */ + 0x29, /* __u8 bDescriptorType; Hub-descriptor */ + 0x02, /* __u8 bNbrPorts; */ + 0x00, /* __u16 wHubCharacteristics; */ + 0x00, + 0x01, /* __u8 bPwrOn2pwrGood; 2ms */ + 0x00, /* __u8 bHubContrCurrent; 0 mA */ + 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */ + 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */ +}; + + +#define OK(x) len = (x); dbg_rh("OK(%d): line: %d", x, __LINE__); break +#define CHECK_ALIGN(x) if (((__u32)(x)) & 0x00000003) \ +{panic("Alignment check (DWORD) failed at %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);} + +static submit_urb_count = 0; + +//#define ETRAX_USB_INTR_IRQ +//#define ETRAX_USB_INTR_ERROR_FATAL + +#define RX_BUF_SIZE 32768 +#define RX_DESC_BUF_SIZE 64 +#define NBR_OF_RX_DESC (RX_BUF_SIZE / RX_DESC_BUF_SIZE) + +#define NBR_OF_EP_DESC 32 + +#define MAX_INTR_INTERVAL 128 + +static __u32 ep_usage_bitmask; +static __u32 ep_really_active; + +static unsigned char RxBuf[RX_BUF_SIZE]; +static USB_IN_Desc_t RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned (4))); + +static volatile USB_IN_Desc_t *myNextRxDesc; +static volatile USB_IN_Desc_t *myLastRxDesc; +static volatile USB_IN_Desc_t *myPrevRxDesc; + +static USB_EP_Desc_t TxCtrlEPList[NBR_OF_EP_DESC] __attribute__ ((aligned (4))); +static USB_EP_Desc_t TxBulkEPList[NBR_OF_EP_DESC] __attribute__ ((aligned (4))); + +static USB_EP_Desc_t TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4))); +static USB_SB_Desc_t TxIntrSB_zout __attribute__ ((aligned (4))); + +static urb_t *URB_List[NBR_OF_EP_DESC]; +static kmem_cache_t *usb_desc_cache; +static struct usb_bus *etrax_usb_bus; + +static void dump_urb (purb_t purb); +static void init_rx_buffers(void); +static int etrax_rh_unlink_urb (urb_t *urb); +static void etrax_rh_send_irq(urb_t *urb); +static void etrax_rh_init_int_timer(urb_t *urb); +static void etrax_rh_int_timer_do(unsigned long ptr); + +static void etrax_usb_setup_epid(char epid, char devnum, char endpoint, + char packsize, char slow); +static int etrax_usb_lookup_epid(unsigned char devnum, char endpoint, char slow, int maxp); +static int etrax_usb_allocate_epid(void); +static void etrax_usb_free_epid(char epid); +static void cleanup_sb(USB_SB_Desc_t *sb); + +static int etrax_usb_do_ctrl_hw_add(urb_t *urb, char epid, char maxlen); +static int etrax_usb_do_bulk_hw_add(urb_t *urb, char epid, char maxlen); + +static int etrax_usb_submit_ctrl_urb(urb_t *urb); + +static int etrax_usb_submit_urb(urb_t *urb); +static int etrax_usb_unlink_urb(urb_t *urb); +static int etrax_usb_get_frame_number(struct usb_device *usb_dev); +static int etrax_usb_allocate_dev(struct usb_device *usb_dev); +static int etrax_usb_deallocate_dev(struct usb_device *usb_dev); + +static void etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs); +static void etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs); +static void etrax_usb_hc_intr_top_half(int irq, void *vhc, struct pt_regs *regs); + +static int etrax_rh_submit_urb (urb_t *urb); + +static int etrax_usb_hc_init(void); +static void etrax_usb_hc_cleanup(void); + +static struct usb_operations etrax_usb_device_operations = +{ + etrax_usb_allocate_dev, + etrax_usb_deallocate_dev, + etrax_usb_get_frame_number, + etrax_usb_submit_urb, + etrax_usb_unlink_urb +}; + +#ifdef USB_DEBUG_DESC +static void dump_urb(purb_t purb) +{ + printk("\nurb :0x%08X\n", purb); + printk("next :0x%08X\n", purb->next); + printk("dev :0x%08X\n", purb->dev); + printk("pipe :0x%08X\n", purb->pipe); + printk("status :%d\n", purb->status); + printk("transfer_flags :0x%08X\n", purb->transfer_flags); + printk("transfer_buffer :0x%08X\n", purb->transfer_buffer); + printk("transfer_buffer_length:%d\n", purb->transfer_buffer_length); + printk("actual_length :%d\n", purb->actual_length); + printk("setup_packet :0x%08X\n", purb->setup_packet); + printk("start_frame :%d\n", purb->start_frame); + printk("number_of_packets :%d\n", purb->number_of_packets); + printk("interval :%d\n", purb->interval); + printk("error_count :%d\n", purb->error_count); + printk("context :0x%08X\n", purb->context); + printk("complete :0x%08X\n\n", purb->complete); +} + +static void dump_in_desc(USB_IN_Desc_t *in) +{ + printk("\nUSB_IN_Desc at 0x%08X\n", in); + printk(" sw_len : 0x%04X (%d)\n", in->sw_len, in->sw_len); + printk(" command : 0x%04X\n", in->command); + printk(" next : 0x%08X\n", in->next); + printk(" buf : 0x%08X\n", in->buf); + printk(" hw_len : 0x%04X (%d)\n", in->hw_len, in->hw_len); + printk(" status : 0x%04X\n\n", in->status); +} + +static void dump_sb_desc(USB_SB_Desc_t *sb) +{ + printk("\nUSB_SB_Desc at 0x%08X\n", sb); + printk(" sw_len : 0x%04X (%d)\n", sb->sw_len, sb->sw_len); + printk(" command : 0x%04X\n", sb->command); + printk(" next : 0x%08X\n", sb->next); + printk(" buf : 0x%08X\n\n", sb->buf); +} + + +static void dump_ep_desc(USB_EP_Desc_t *ep) +{ + printk("\nUSB_EP_Desc at 0x%08X\n", ep); + printk(" hw_len : 0x%04X (%d)\n", ep->hw_len, ep->hw_len); + printk(" command : 0x%08X\n", ep->command); + printk(" sub : 0x%08X\n", ep->sub); + printk(" nep : 0x%08X\n\n", ep->nep); +} + + +#else +#define dump_urb(...) (NULL) +#define dump_ep_desc(...) (NULL) +#define dump_sb_desc(...) (NULL) +#define dump_in_desc(...) (NULL) +#endif + +static void init_rx_buffers(void) +{ + int i; + + DBFENTER; + + for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) { + RxDescList[i].sw_len = RX_DESC_BUF_SIZE; + RxDescList[i].command = 0; + RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]); + RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE)); + RxDescList[i].hw_len = 0; + RxDescList[i].status = 0; + } + + RxDescList[i].sw_len = RX_DESC_BUF_SIZE; + RxDescList[i].command = IO_STATE(USB_IN_command, eol, yes); + RxDescList[i].next = virt_to_phys(&RxDescList[0]); + RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE)); + RxDescList[i].hw_len = 0; + RxDescList[i].status = 0; + + myNextRxDesc = &RxDescList[0]; + myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; + myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; + + *R_DMA_CH9_FIRST = virt_to_phys(myNextRxDesc); + *R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, start); + + DBFEXIT; +} + +static void init_tx_ctrl_ep(void) +{ + int i; + + DBFENTER; + + for (i = 0; i < (NBR_OF_EP_DESC - 1); i++) { + TxCtrlEPList[i].hw_len = 0; + TxCtrlEPList[i].command = IO_FIELD(USB_EP_command, epid, i); + TxCtrlEPList[i].sub = 0; + TxCtrlEPList[i].nep = virt_to_phys(&TxCtrlEPList[i + 1]); + } + + TxCtrlEPList[i].hw_len = 0; + TxCtrlEPList[i].command = IO_STATE(USB_EP_command, eol, yes) | + IO_FIELD(USB_EP_command, epid, i); + + TxCtrlEPList[i].sub = 0; + TxCtrlEPList[i].nep = virt_to_phys(&TxCtrlEPList[0]); + + *R_DMA_CH8_SUB1_EP = virt_to_phys(&TxCtrlEPList[0]); + *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start); + + DBFEXIT; +} + +static void init_tx_bulk_ep(void) +{ + int i; + + DBFENTER; + + for (i = 0; i < (NBR_OF_EP_DESC - 1); i++) { + TxBulkEPList[i].hw_len = 0; + TxBulkEPList[i].command = IO_FIELD(USB_EP_command, epid, i); + TxBulkEPList[i].sub = 0; + TxBulkEPList[i].nep = virt_to_phys(&TxBulkEPList[i + 1]); + } + + TxBulkEPList[i].hw_len = 0; + TxBulkEPList[i].command = IO_STATE(USB_EP_command, eol, yes) | + IO_FIELD(USB_EP_command, epid, i); + + TxBulkEPList[i].sub = 0; + TxBulkEPList[i].nep = virt_to_phys(&TxBulkEPList[0]); + + *R_DMA_CH8_SUB0_EP = virt_to_phys(&TxBulkEPList[0]); + *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); + + DBFEXIT; +} + +static void init_tx_intr_ep(void) +{ + int i; + + DBFENTER; + + TxIntrSB_zout.sw_len = 0; + TxIntrSB_zout.next = 0; + TxIntrSB_zout.buf = 0; + TxIntrSB_zout.command = IO_FIELD(USB_SB_command, rem, 0) | + IO_STATE(USB_SB_command, tt, zout) | + IO_STATE(USB_SB_command, full, yes) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, eol, yes); + + for (i = 0; i < (MAX_INTR_INTERVAL - 1); i++) { + TxIntrEPList[i].hw_len = 0; + TxIntrEPList[i].command = IO_STATE(USB_EP_command, eof, yes) | + IO_STATE(USB_EP_command, enable, yes) | + IO_FIELD(USB_EP_command, epid, 0); + TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout); + TxIntrEPList[i].nep = virt_to_phys(&TxIntrEPList[i + 1]); + } + + TxIntrEPList[i].hw_len = 0; + TxIntrEPList[i].command = + IO_STATE(USB_EP_command, eof, yes) | + IO_STATE(USB_EP_command, enable, yes) | + IO_FIELD(USB_EP_command, epid, 0); + TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout); + TxIntrEPList[i].nep = virt_to_phys(&TxIntrEPList[0]); + + *R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]); + *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start); + + DBFEXIT; +} + + +static int etrax_usb_unlink_intr_urb(urb_t *urb) +{ + struct usb_device *usb_dev = urb->dev; + etrax_hc_t *hc = usb_dev->bus->hcpriv; + + USB_EP_Desc_t *tmp_ep; + USB_EP_Desc_t *first_ep; + + USB_EP_Desc_t *ep_desc; + USB_SB_Desc_t *sb_desc; + + char epid; + char devnum; + char endpoint; + char slow; + int maxlen; + int i; + + etrax_urb_priv_t *urb_priv; + unsigned long flags; + + DBFENTER; + + devnum = usb_pipedevice(urb->pipe); + endpoint = usb_pipeendpoint(urb->pipe); + slow = usb_pipeslow(urb->pipe); + maxlen = usb_maxpacket(urb->dev, urb->pipe, + usb_pipeout(urb->pipe)); + + epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); + if (epid == -1) { + err("Trying to unlink urb that is not in traffic queue!!"); + return -1; /* fix this */ + } + + *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, stop); + /* Somehow wait for the DMA to finish current activities */ + i = jiffies + 100; + while (jiffies < i); + + first_ep = &TxIntrEPList[0]; + tmp_ep = first_ep; + + do { + if (IO_EXTRACT(USB_EP_command, epid, ((USB_EP_Desc_t *)phys_to_virt(tmp_ep->nep))->command) + == epid) { + /* Unlink it !!! */ + dbg_intr("Found urb to unlink for epid %d", epid); + + ep_desc = phys_to_virt(tmp_ep->nep); + tmp_ep->nep = ep_desc->nep; + kmem_cache_free(usb_desc_cache, phys_to_virt(ep_desc->sub)); + kmem_cache_free(usb_desc_cache, ep_desc); + } + + tmp_ep = phys_to_virt(tmp_ep->nep); + + } while (tmp_ep != first_ep); + + /* We should really try to move the EP register to an EP that is not removed + instead of restarting, but this will work too */ + *R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]); + *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start); + + clear_bit(epid, (void *)&ep_really_active); + URB_List[epid] = NULL; + etrax_usb_free_epid(epid); + + DBFEXIT; + + return 0; +} + +void etrax_usb_do_intr_recover(int epid) +{ + USB_EP_Desc_t *first_ep, *tmp_ep; + + first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP); + tmp_ep = first_ep; + + do { + if (IO_EXTRACT(USB_EP_command, epid, tmp_ep->command) == epid && + !(tmp_ep->command & IO_MASK(USB_EP_command, enable))) { + tmp_ep->command |= IO_STATE(USB_EP_command, enable, yes); + } + + tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->nep); + + } while (tmp_ep != first_ep); +} + +static int etrax_usb_submit_intr_urb(urb_t *urb) +{ + USB_EP_Desc_t *tmp_ep; + USB_EP_Desc_t *first_ep; + + USB_SB_Desc_t *sb_desc; + + char epid; + char devnum; + char endpoint; + char maxlen; + char slow; + int interval; + int i; + + etrax_urb_priv_t *urb_priv; + unsigned long flags; + + DBFENTER; + + devnum = usb_pipedevice(urb->pipe); + endpoint = usb_pipeendpoint(urb->pipe); + maxlen = usb_maxpacket(urb->dev, urb->pipe, + usb_pipeout(urb->pipe)); + + slow = usb_pipeslow(urb->pipe); + interval = urb->interval; + + dbg_intr("Intr traffic for dev %d, endpoint %d, maxlen %d, slow %d", + devnum, endpoint, maxlen, slow); + + epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); + if (epid == -1) { + epid = etrax_usb_allocate_epid(); + if (epid == -1) { + /* We're out of endpoints, return some error */ + err("We're out of endpoints"); + return -ENOMEM; + } + /* Now we have to fill in this ep */ + etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow); + } + /* Ok, now we got valid endpoint, lets insert some traffic */ + + urb_priv = (etrax_urb_priv_t *)kmalloc(sizeof(etrax_urb_priv_t), GFP_KERNEL); + urb_priv->first_sb = 0; + urb_priv->rx_offset = 0; + urb_priv->eot = 0; + INIT_LIST_HEAD(&urb_priv->ep_in_list); + urb->hcpriv = urb_priv; + + /* This is safe since there cannot be any other URB's for this epid */ + URB_List[epid] = urb; +#if 0 + first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP); +#else + first_ep = &TxIntrEPList[0]; +#endif + + /* Round of the interval to 2^n, it is obvious that this code favours + smaller numbers, but that is actually a good thing */ + for (i = 0; interval; i++) { + interval = interval >> 1; + } + + urb->interval = interval = 1 << (i - 1); + + dbg_intr("Interval rounded to %d", interval); + + tmp_ep = first_ep; + i = 0; + do { + if (tmp_ep->command & IO_MASK(USB_EP_command, eof)) { + if ((i % interval) == 0) { + /* Insert the traffic ep after tmp_ep */ + USB_EP_Desc_t *traffic_ep; + USB_SB_Desc_t *traffic_sb; + + traffic_ep = (USB_EP_Desc_t *) + kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); + traffic_sb = (USB_SB_Desc_t *) + kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); + + traffic_ep->hw_len = 0; + traffic_ep->command = IO_FIELD(USB_EP_command, epid, epid) | + IO_STATE(USB_EP_command, enable, yes); + traffic_ep->sub = virt_to_phys(traffic_sb); + + if (usb_pipein(urb->pipe)) { + traffic_sb->sw_len = urb->transfer_buffer_length ? + (urb->transfer_buffer_length - 1) / maxlen + 1 : 0; + traffic_sb->next = 0; + traffic_sb->buf = 0; + traffic_sb->command = IO_FIELD(USB_SB_command, rem, + urb->transfer_buffer_length % maxlen) | + IO_STATE(USB_SB_command, tt, in) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, eol, yes); + + } else if (usb_pipeout(urb->pipe)) { + traffic_sb->sw_len = urb->transfer_buffer_length; + traffic_sb->next = 0; + traffic_sb->buf = virt_to_phys(urb->transfer_buffer); + traffic_sb->command = IO_FIELD(USB_SB_command, rem, 0) | + IO_STATE(USB_SB_command, tt, out) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, eol, yes) | + IO_STATE(USB_SB_command, full, yes); + } + + traffic_ep->nep = tmp_ep->nep; + tmp_ep->nep = virt_to_phys(traffic_ep); + dbg_intr("One ep successfully inserted"); + } + i++; + } + tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->nep); + } while (tmp_ep != first_ep); + + set_bit(epid, (void *)&ep_really_active); + + *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start); + + DBFEXIT; + + return 0; +} + + +static int handle_intr_transfer_attn(char epid, int status) +{ + urb_t *old_urb; + + DBFENTER; + + old_urb = URB_List[epid]; + + /* if (status == 0 && IN) find data and copy to urb */ + if (status == 0 && usb_pipein(old_urb->pipe)) { + unsigned long flags; + etrax_urb_priv_t *urb_priv; + struct list_head *entry; + struct in_chunk *in; + + urb_priv = (etrax_urb_priv_t *)old_urb->hcpriv; + + save_flags(flags); + cli(); + + list_for_each(entry, &urb_priv->ep_in_list) { + in = list_entry(entry, struct in_chunk, list); + memcpy(old_urb->transfer_buffer, in->data, in->length); + old_urb->actual_length = in->length; + old_urb->status = status; + + if (old_urb->complete) { + old_urb->complete(old_urb); + } + + list_del(entry); + kfree(in->data); + kfree(in); + } + + restore_flags(flags); + + } else if (status != 0) { + warn("Some sort of error for INTR EP !!!!"); +#ifdef ETRAX_USB_INTR_ERROR_FATAL + /* This means that an INTR error is fatal for that endpoint */ + etrax_usb_unlink_intr_urb(old_urb); + old_urb->status = status; + if (old_urb->complete) { + old_urb->complete(old_urb); + } +#else + /* In this case we reenable the disabled endpoint(s) */ + etrax_usb_do_intr_recover(epid); +#endif + } + + DBFEXIT; +} + +static int etrax_rh_unlink_urb (urb_t *urb) +{ + etrax_hc_t *hc; + + DBFENTER; + + hc = urb->dev->bus->hcpriv; + + if (hc->rh.urb == urb) { + hc->rh.send = 0; + del_timer(&hc->rh.rh_int_timer); + } + + DBFEXIT; + return 0; +} + +static void etrax_rh_send_irq(urb_t *urb) +{ + __u16 data = 0; + etrax_hc_t *hc = urb->dev->bus->hcpriv; +// static prev_wPortStatus_1 = 0; +// static prev_wPortStatus_2 = 0; + +/* DBFENTER; */ + + +/* + dbg_rh("R_USB_FM_NUMBER : 0x%08X", *R_USB_FM_NUMBER); + dbg_rh("R_USB_FM_REMAINING: 0x%08X", *R_USB_FM_REMAINING); +*/ + + data |= (hc->rh.wPortChange_1) ? (1 << 1) : 0; + data |= (hc->rh.wPortChange_2) ? (1 << 2) : 0; + + *((__u16 *)urb->transfer_buffer) = cpu_to_le16(data); + urb->actual_length = 1; + urb->status = 0; + + + if (data && hc->rh.send && urb->complete) { + dbg_rh("wPortChange_1: 0x%04X", hc->rh.wPortChange_1); + dbg_rh("wPortChange_2: 0x%04X", hc->rh.wPortChange_2); + + urb->complete(urb); + } + +/* DBFEXIT; */ +} + +static void etrax_rh_init_int_timer(urb_t *urb) +{ + etrax_hc_t *hc; + +/* DBFENTER; */ + + hc = urb->dev->bus->hcpriv; + hc->rh.interval = urb->interval; + init_timer(&hc->rh.rh_int_timer); + hc->rh.rh_int_timer.function = etrax_rh_int_timer_do; + hc->rh.rh_int_timer.data = (unsigned long)urb; + hc->rh.rh_int_timer.expires = jiffies + ((HZ * hc->rh.interval) / 1000); + add_timer(&hc->rh.rh_int_timer); + +/* DBFEXIT; */ +} + +static void etrax_rh_int_timer_do(unsigned long ptr) +{ + urb_t *urb; + etrax_hc_t *hc; + +/* DBFENTER; */ + + urb = (urb_t*)ptr; + hc = urb->dev->bus->hcpriv; + + if (hc->rh.send) { + etrax_rh_send_irq(urb); + } + + etrax_rh_init_int_timer(urb); + +/* DBFEXIT; */ +} + +static void etrax_usb_setup_epid(char epid, char devnum, char endpoint, char packsize, char slow) +{ + unsigned long flags; + + DBFENTER; + + save_flags(flags); + cli(); + + if (test_bit(epid, (void *)&ep_usage_bitmask)) { + warn("Trying to setup used epid %d", epid); + DBFEXIT; + return; + } + + set_bit(epid, (void *)&ep_usage_bitmask); + dbg_ep("Setting up ep_id %d with devnum %d, endpoint %d and max_len %d", + epid, devnum, endpoint, packsize); + + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); + nop(); + *R_USB_EPT_DATA = IO_STATE(R_USB_EPT_DATA, valid, yes) | + IO_FIELD(R_USB_EPT_DATA, ep, endpoint) | + IO_FIELD(R_USB_EPT_DATA, dev, devnum) | + IO_FIELD(R_USB_EPT_DATA, max_len, packsize) | + IO_FIELD(R_USB_EPT_DATA, low_speed, slow); + + restore_flags(flags); + + DBFEXIT; +} + +static void etrax_usb_free_epid(char epid) +{ + unsigned long flags; + + DBFENTER; + + if (!test_bit(epid, (void *)&ep_usage_bitmask)) { + warn("Trying to free unused epid %d", epid); + DBFEXIT; + return; + } + + save_flags(flags); + cli(); + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); + nop(); + while (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold))printk("+"); + *R_USB_EPT_DATA = 0; + clear_bit(epid, (void *)&ep_usage_bitmask); + restore_flags(flags); + dbg_ep("epid: %d freed", epid); + + DBFEXIT; +} + + +static int etrax_usb_lookup_epid(unsigned char devnum, char endpoint, char slow, int maxp) +{ + int i; + unsigned long flags; + __u32 data; + + DBFENTER; + + save_flags(flags); + + /* Skip first ep_id since it is reserved when intr. or iso traffic is used */ + for (i = 0; i < NBR_OF_EP_DESC; i++) { + if (test_bit(i, (void *)&ep_usage_bitmask)) { + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, i); + nop(); + data = *R_USB_EPT_DATA; + if ((IO_MASK(R_USB_EPT_DATA, valid) & data) && + (IO_EXTRACT(R_USB_EPT_DATA, dev, data) == devnum) && + (IO_EXTRACT(R_USB_EPT_DATA, ep, data) == endpoint) && + (IO_EXTRACT(R_USB_EPT_DATA, low_speed, data) == slow) && + (IO_EXTRACT(R_USB_EPT_DATA, max_len, data) == maxp)) { + dbg_ep("Found ep_id %d for devnum %d, endpoint %d", + i, devnum, endpoint); + DBFEXIT; + return i; + } + } + } + + restore_flags(flags); + + dbg_ep("Found no ep_id for devnum %d, endpoint %d", + devnum, endpoint); + DBFEXIT; + return -1; +} + +static int etrax_usb_allocate_epid(void) +{ + int i; + + DBFENTER; + + for (i = 0; i < NBR_OF_EP_DESC; i++) { + if (!test_bit(i, (void *)&ep_usage_bitmask)) { + dbg_ep("Found free ep_id at %d", i); + DBFEXIT; + return i; + } + } + + dbg_ep("Found no free ep_id's"); + DBFEXIT; + return -1; +} + +static int etrax_usb_submit_bulk_urb(urb_t *urb) +{ + char epid; + char devnum; + char endpoint; + char maxlen; + char slow; + + urb_t *tmp_urb; + + etrax_urb_priv_t *urb_priv; + unsigned long flags; + + DBFENTER; + + devnum = usb_pipedevice(urb->pipe); + endpoint = usb_pipeendpoint(urb->pipe); + maxlen = usb_maxpacket(urb->dev, urb->pipe, + usb_pipeout(urb->pipe)); + slow = usb_pipeslow(urb->pipe); + + epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); + if (epid == -1) { + epid = etrax_usb_allocate_epid(); + if (epid == -1) { + /* We're out of endpoints, return some error */ + err("We're out of endpoints"); + return -ENOMEM; + } + /* Now we have to fill in this ep */ + etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow); + } + /* Ok, now we got valid endpoint, lets insert some traffic */ + + urb->status = -EINPROGRESS; + + save_flags(flags); + cli(); + + if (URB_List[epid]) { + /* Find end of list and add */ + for (tmp_urb = URB_List[epid]; tmp_urb->next; tmp_urb = tmp_urb->next) + dump_urb(tmp_urb); + + tmp_urb->next = urb; + restore_flags(flags); + } else { + /* If this is the first URB, add the URB and do HW add */ + URB_List[epid] = urb; + restore_flags(flags); + etrax_usb_do_bulk_hw_add(urb, epid, maxlen); + } + + DBFEXIT; + + return 0; +} + +static int etrax_usb_do_bulk_hw_add(urb_t *urb, char epid, char maxlen) +{ + USB_SB_Desc_t *sb_desc_1; + + etrax_urb_priv_t *urb_priv; + + unsigned long flags; + __u32 r_usb_ept_data; + + DBFENTER; + + urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_KERNEL); + sb_desc_1 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); + + if (usb_pipeout(urb->pipe)) { + + dbg_bulk("Bulk transfer for epid %d is OUT", epid); + dbg_bulk("transfer_buffer_length == %d", urb->transfer_buffer_length); + dbg_bulk("actual_length == %d", urb->actual_length); + + if (urb->transfer_buffer_length > 0xffff) { + panic(__FILE__ __FUNCTION__ ":urb->transfer_buffer_length > 0xffff\n"); + } + + sb_desc_1->sw_len = urb->transfer_buffer_length; /* was actual_length */ + sb_desc_1->command = IO_FIELD(USB_SB_command, rem, 0) | + IO_STATE(USB_SB_command, tt, out) | + +#if 0 + IO_STATE(USB_SB_command, full, no) | +#else + IO_STATE(USB_SB_command, full, yes) | +#endif + + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, eol, yes); + + dbg_bulk("transfer_buffer is at 0x%08X", urb->transfer_buffer); + + sb_desc_1->buf = virt_to_phys(urb->transfer_buffer); + sb_desc_1->next = 0; + + } else if (usb_pipein(urb->pipe)) { + + dbg_bulk("Transfer for epid %d is IN", epid); + dbg_bulk("transfer_buffer_length = %d", urb->transfer_buffer_length); + dbg_bulk("rem is calculated to %d", urb->transfer_buffer_length % maxlen); + + sb_desc_1->sw_len = urb->transfer_buffer_length ? + (urb->transfer_buffer_length - 1) / maxlen + 1 : 0; + dbg_bulk("sw_len got %d", sb_desc_1->sw_len); + dbg_bulk("transfer_buffer is at 0x%08X", urb->transfer_buffer); + + sb_desc_1->command = + IO_FIELD(USB_SB_command, rem, + urb->transfer_buffer_length % maxlen) | + IO_STATE(USB_SB_command, tt, in) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, eol, yes); + + sb_desc_1->buf = 0; + sb_desc_1->next = 0; + + urb_priv->rx_offset = 0; + urb_priv->eot = 0; + } + + urb_priv->first_sb = sb_desc_1; + + urb->hcpriv = (void *)urb_priv; + + /* Reset toggle bits and reset error count, remeber to di and ei */ + /* Warning: it is possible that this locking doesn't work with bottom-halves */ + + save_flags(flags); + cli(); + + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); + if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) { + panic("Hold was set in %s\n", __FUNCTION__); + } + + *R_USB_EPT_DATA &= + ~(IO_MASK(R_USB_EPT_DATA, error_count_in) | + IO_MASK(R_USB_EPT_DATA, error_count_out)); + + if (usb_pipeout(urb->pipe)) { + char toggle = + usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); + *R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_out); + *R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_out, toggle); + } else { + char toggle = + usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); + *R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_in); + *R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_in, toggle); + } + + /* Enable the EP descr. */ + + set_bit(epid, (void *)&ep_really_active); + + TxBulkEPList[epid].sub = virt_to_phys(sb_desc_1); + TxBulkEPList[epid].hw_len = 0; + TxBulkEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes); + + restore_flags(flags); + + if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) { + *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); + + } + + DBFEXIT; +} + +static int handle_bulk_transfer_attn(char epid, int status) +{ + urb_t *old_urb; + etrax_urb_priv_t *hc_priv; + unsigned long flags; + + DBFENTER; + + clear_bit(epid, (void *)&ep_really_active); + + old_urb = URB_List[epid]; + URB_List[epid] = old_urb->next; + + /* if (status == 0 && IN) find data and copy to urb */ + if (status == 0 && usb_pipein(old_urb->pipe)) { + etrax_urb_priv_t *urb_priv; + + urb_priv = (etrax_urb_priv_t *)old_urb->hcpriv; + save_flags(flags); + cli(); + if (urb_priv->eot == 1) { + old_urb->actual_length = urb_priv->rx_offset; + } else { + if (urb_priv->rx_offset == 0) { + status = 0; + } else { + status = -EPROTO; + } + + old_urb->actual_length = 0; + err("(BULK) No eot set in IN data!!! rx_offset is: %d", urb_priv->rx_offset); + } + + restore_flags(flags); + } + + save_flags(flags); + cli(); + + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); + if (usb_pipeout(old_urb->pipe)) { + char toggle = + IO_EXTRACT(R_USB_EPT_DATA, t_out, *R_USB_EPT_DATA); + usb_settoggle(old_urb->dev, usb_pipeendpoint(old_urb->pipe), + usb_pipeout(old_urb->pipe), toggle); + } else { + char toggle = + IO_EXTRACT(R_USB_EPT_DATA, t_in, *R_USB_EPT_DATA); + usb_settoggle(old_urb->dev, usb_pipeendpoint(old_urb->pipe), + usb_pipeout(old_urb->pipe), toggle); + } + restore_flags(flags); + + /* If there are any more URB's in the list we'd better start sending */ + if (URB_List[epid]) { + etrax_usb_do_bulk_hw_add(URB_List[epid], epid, + usb_maxpacket(URB_List[epid]->dev, URB_List[epid]->pipe, + usb_pipeout(URB_List[epid]->pipe))); + } +#if 1 + else { + /* This means that this EP is now free, deconfigure it */ + etrax_usb_free_epid(epid); + } +#endif + + /* Remember to free the SB's */ + hc_priv = (etrax_urb_priv_t *)old_urb->hcpriv; + cleanup_sb(hc_priv->first_sb); + kfree(hc_priv); + + old_urb->status = status; + if (old_urb->complete) { + old_urb->complete(old_urb); + } + + DBFEXIT; +} + +/* ---------------------------------------------------------------------------- */ + +static int etrax_usb_submit_ctrl_urb(urb_t *urb) +{ + char epid; + char devnum; + char endpoint; + char maxlen; + char slow; + + urb_t *tmp_urb; + + etrax_urb_priv_t *urb_priv; + unsigned long flags; + + DBFENTER; + + devnum = usb_pipedevice(urb->pipe); + endpoint = usb_pipeendpoint(urb->pipe); + maxlen = usb_maxpacket(urb->dev, urb->pipe, + usb_pipeout(urb->pipe)); + slow = usb_pipeslow(urb->pipe); + + epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); + if (epid == -1) { + epid = etrax_usb_allocate_epid(); + if (epid == -1) { + /* We're out of endpoints, return some error */ + err("We're out of endpoints"); + return -ENOMEM; + } + /* Now we have to fill in this ep */ + etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow); + } + /* Ok, now we got valid endpoint, lets insert some traffic */ + + urb->status = -EINPROGRESS; + + save_flags(flags); + cli(); + + if (URB_List[epid]) { + /* Find end of list and add */ + for (tmp_urb = URB_List[epid]; tmp_urb->next; tmp_urb = tmp_urb->next) + dump_urb(tmp_urb); + + tmp_urb->next = urb; + restore_flags(flags); + } else { + /* If this is the first URB, add the URB and do HW add */ + URB_List[epid] = urb; + restore_flags(flags); + etrax_usb_do_ctrl_hw_add(urb, epid, maxlen); + } + + DBFEXIT; + + return 0; +} + +static int etrax_usb_do_ctrl_hw_add(urb_t *urb, char epid, char maxlen) +{ + USB_SB_Desc_t *sb_desc_1; + USB_SB_Desc_t *sb_desc_2; + USB_SB_Desc_t *sb_desc_3; + + etrax_urb_priv_t *urb_priv; + + unsigned long flags; + __u32 r_usb_ept_data; + + + DBFENTER; + + urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_KERNEL); + sb_desc_1 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); + sb_desc_2 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); + + if (!(sb_desc_1 && sb_desc_2)) { + panic("kmem_cache_alloc in ctrl_hw_add gave NULL pointers !!!\n"); + } + + sb_desc_1->sw_len = 8; + sb_desc_1->command = IO_FIELD(USB_SB_command, rem, 0) | + IO_STATE(USB_SB_command, tt, setup) | + IO_STATE(USB_SB_command, full, yes) | + IO_STATE(USB_SB_command, eot, yes); + + sb_desc_1->buf = virt_to_phys(urb->setup_packet); + sb_desc_1->next = virt_to_phys(sb_desc_2); + dump_sb_desc(sb_desc_1); + + if (usb_pipeout(urb->pipe)) { + dbg_ctrl("Transfer for epid %d is OUT", epid); + + /* If this Control OUT transfer has an optional data stage we add an OUT token + before the mandatory IN (status) token, hence the reordered SB list */ + + if (urb->transfer_buffer) { + dbg_ctrl("This OUT transfer has an extra data stage"); + sb_desc_3 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); + + sb_desc_1->next = virt_to_phys(sb_desc_3); + + sb_desc_3->sw_len = urb->transfer_buffer_length; + sb_desc_3->command = IO_STATE(USB_SB_command, tt, out) | + IO_STATE(USB_SB_command, full, yes) | + IO_STATE(USB_SB_command, eot, yes); + sb_desc_3->buf = virt_to_phys(urb->transfer_buffer); + sb_desc_3->next = virt_to_phys(sb_desc_2); + } + + sb_desc_2->sw_len = 1; + sb_desc_2->command = IO_FIELD(USB_SB_command, rem, 0) | + IO_STATE(USB_SB_command, tt, in) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, eol, yes); + + sb_desc_2->buf = 0; + sb_desc_2->next = 0; + dump_sb_desc(sb_desc_2); + + } else if (usb_pipein(urb->pipe)) { + + dbg_ctrl("Transfer for epid %d is IN", epid); + dbg_ctrl("transfer_buffer_length = %d", urb->transfer_buffer_length); + dbg_ctrl("rem is calculated to %d", urb->transfer_buffer_length % maxlen); + + sb_desc_3 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); + + sb_desc_2->sw_len = urb->transfer_buffer_length ? + (urb->transfer_buffer_length - 1) / maxlen + 1 : 0; + dbg_ctrl("sw_len got %d", sb_desc_2->sw_len); + + sb_desc_2->command = + IO_FIELD(USB_SB_command, rem, + urb->transfer_buffer_length % maxlen) | + IO_STATE(USB_SB_command, tt, in) | + IO_STATE(USB_SB_command, eot, yes); + + sb_desc_2->buf = 0; + sb_desc_2->next = virt_to_phys(sb_desc_3); + dump_sb_desc(sb_desc_2); + + sb_desc_3->sw_len = 1; + sb_desc_3->command = IO_FIELD(USB_SB_command, rem, 0) | + IO_STATE(USB_SB_command, tt, zout) | + IO_STATE(USB_SB_command, full, yes) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, eol, yes); + + sb_desc_3->buf = 0; + sb_desc_3->next = 0; + dump_sb_desc(sb_desc_3); + + urb_priv->rx_offset = 0; + urb_priv->eot = 0; + } + + urb_priv->first_sb = sb_desc_1; + + urb->hcpriv = (void *)urb_priv; + + /* Reset toggle bits and reset error count, remeber to di and ei */ + /* Warning: it is possible that this locking doesn't work with bottom-halves */ + + save_flags(flags); + cli(); + + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); + if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) { + panic("Hold was set in %s\n", __FUNCTION__); + } + + + *R_USB_EPT_DATA &= + ~(IO_MASK(R_USB_EPT_DATA, error_count_in) | + IO_MASK(R_USB_EPT_DATA, error_count_out) | + IO_MASK(R_USB_EPT_DATA, t_in) | + IO_MASK(R_USB_EPT_DATA, t_out)); + + /* Enable the EP descr. */ + + set_bit(epid, (void *)&ep_really_active); + + TxCtrlEPList[epid].sub = virt_to_phys(sb_desc_1); + TxCtrlEPList[epid].hw_len = 0; + TxCtrlEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes); + restore_flags(flags); + + dump_ep_desc(&TxCtrlEPList[epid]); + + if (!(*R_DMA_CH8_SUB1_CMD & IO_MASK(R_DMA_CH8_SUB1_CMD, cmd))) { + *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start); + + } + + DBFEXIT; +} + +static int etrax_usb_submit_urb(urb_t *urb) +{ + etrax_hc_t *hc; + int rval = -EINVAL; + + DBFENTER; + + dump_urb(urb); + submit_urb_count++; + + hc = (etrax_hc_t*) urb->dev->bus->hcpriv; + + if (usb_pipedevice(urb->pipe) == hc->rh.devnum) { + /* This request if for the Virtual Root Hub */ + rval = etrax_rh_submit_urb(urb); + + } else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) { + rval = etrax_usb_submit_ctrl_urb(urb); + + } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { + rval = etrax_usb_submit_bulk_urb(urb); + + } else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { + int bustime; + + if (urb->bandwidth == 0) { + bustime = usb_check_bandwidth(urb->dev, urb); + if (bustime < 0) { + rval = bustime; + } else { + usb_claim_bandwidth(urb->dev, urb, bustime, 0); + rval = etrax_usb_submit_intr_urb(urb); + } + + } + } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + warn("Isochronous traffic is not supported !!!"); + rval = -EINVAL; + } + + DBFEXIT; + + return rval; +} + +static int etrax_usb_unlink_urb(urb_t *urb) +{ + etrax_hc_t *hc = urb->dev->bus->hcpriv; + int epid; + int pos; + int devnum, endpoint, slow, maxlen; + etrax_urb_priv_t *hc_priv; + unsigned long flags; + + DBFENTER; + dump_urb(urb); + devnum = usb_pipedevice(urb->pipe); + endpoint = usb_pipeendpoint(urb->pipe); + slow = usb_pipeslow(urb->pipe); + maxlen = usb_maxpacket(urb->dev, urb->pipe, + usb_pipeout(urb->pipe)); + + epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); + + if (epid == -1) + return 0; + + + if (usb_pipedevice(urb->pipe) == hc->rh.devnum) { + int ret; + ret = etrax_rh_unlink_urb(urb); + DBFEXIT; + return ret; + } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { + int ret; + ret = etrax_usb_unlink_intr_urb(urb); + urb->status = -ENOENT; + if (urb->complete) { + urb->complete(urb); + } + DBFEXIT; + return ret; + } + + info("Unlink of BULK or CTRL"); + + save_flags(flags); + cli(); + + for (epid = 0; epid < 32; epid++) { + urb_t *u = URB_List[epid]; + pos = 0; + + for (; u; u = u->next) { + pos++; + if (u == urb) { + info("Found urb at epid %d, pos %d", epid, pos); + + if (pos == 1) { + if (usb_pipetype(u->pipe) == PIPE_CONTROL) { + if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) { + /* The EP was enabled, disable it and wait */ + TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable); + while (*R_DMA_CH8_SUB1_EP == virt_to_phys(&TxCtrlEPList[epid])); + } + + } else if (usb_pipetype(u->pipe) == PIPE_BULK) { + if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) { + TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable); + while (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[epid])); + } + } + + URB_List[epid] = u->next; + + } else { + urb_t *up; + for (up = URB_List[epid]; up->next != u; up = up->next); + up->next = u->next; + } + u->status = -ENOENT; + if (u->complete) { + u->complete(u); + } + + hc_priv = (etrax_urb_priv_t *)u->hcpriv; + cleanup_sb(hc_priv->first_sb); + kfree(hc_priv); + } + } + } + + restore_flags(flags); + + DBFEXIT; + return 0; +} + +static int etrax_usb_get_frame_number(struct usb_device *usb_dev) +{ + DBFENTER; + DBFEXIT; + return (*R_USB_FM_NUMBER); +} + +static int etrax_usb_allocate_dev(struct usb_device *usb_dev) +{ + DBFENTER; + DBFEXIT; + return 0; +} + +static int etrax_usb_deallocate_dev(struct usb_device *usb_dev) +{ + DBFENTER; + DBFEXIT; + return 0; +} + +static void etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs) +{ + etrax_hc_t *hc = (etrax_hc_t *)vhc; + int epid; + char eol; + urb_t *urb; + USB_EP_Desc_t *tmp_ep; + USB_SB_Desc_t *tmp_sb; + + DBFENTER; + + if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub0_descr)) { + info("dma8_sub0_descr (BULK) intr."); + *R_DMA_CH8_SUB0_CLR_INTR = IO_STATE(R_DMA_CH8_SUB0_CLR_INTR, clr_descr, do); + } + if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub1_descr)) { + info("dma8_sub1_descr (CTRL) intr."); + *R_DMA_CH8_SUB1_CLR_INTR = IO_STATE(R_DMA_CH8_SUB1_CLR_INTR, clr_descr, do); + } + if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub2_descr)) { + info("dma8_sub2_descr (INT) intr."); + *R_DMA_CH8_SUB2_CLR_INTR = IO_STATE(R_DMA_CH8_SUB2_CLR_INTR, clr_descr, do); + } + if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub3_descr)) { + info("dma8_sub3_descr (ISO) intr."); + *R_DMA_CH8_SUB3_CLR_INTR = IO_STATE(R_DMA_CH8_SUB3_CLR_INTR, clr_descr, do); + } + + DBFEXIT; +} + +static void etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs) +{ + int epid = 0; + urb_t *urb; + etrax_urb_priv_t *urb_priv; + + *R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do); + + while (myNextRxDesc->status & IO_MASK(USB_IN_status, eop)) { + if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) { + + goto skip_out; + } + + if (myNextRxDesc->status & IO_MASK(USB_IN_status, error)) { + + goto skip_out; + } + + epid = IO_EXTRACT(USB_IN_status, epid, myNextRxDesc->status); + + urb = URB_List[epid]; + + if (urb && usb_pipein(urb->pipe)) { + urb_priv = (etrax_urb_priv_t *)urb->hcpriv; + + if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { + struct in_chunk *in; + dbg_intr("Packet for epid %d in rx buffers", epid); + in = kmalloc(sizeof(struct in_chunk), GFP_ATOMIC); + in->length = myNextRxDesc->hw_len; + in->data = kmalloc(in->length, GFP_ATOMIC); + memcpy(in->data, phys_to_virt(myNextRxDesc->buf), in->length); + list_add_tail(&in->list, &urb_priv->ep_in_list); +#ifndef ETRAX_USB_INTR_IRQ + etrax_usb_hc_intr_top_half(irq, vhc, regs); +#endif + + } else { + if ((urb_priv->rx_offset + myNextRxDesc->hw_len) > + urb->transfer_buffer_length) { + err("Packet (epid: %d) in RX buffer was bigger " + "than the URB has room for !!!", epid); + goto skip_out; + } + + memcpy(urb->transfer_buffer + urb_priv->rx_offset, + phys_to_virt(myNextRxDesc->buf), myNextRxDesc->hw_len); + + urb_priv->rx_offset += myNextRxDesc->hw_len; + } + + if (myNextRxDesc->status & IO_MASK(USB_IN_status, eot)) { + urb_priv->eot = 1; + } + + } else { + err("This is almost fatal, inpacket for epid %d which does not exist " + " or is out !!!\nURB was at 0x%08X", epid, urb); + + goto skip_out; + } + + skip_out: + myPrevRxDesc = myNextRxDesc; + myPrevRxDesc->command |= IO_MASK(USB_IN_command, eol); + myLastRxDesc->command &= ~IO_MASK(USB_IN_command, eol); + myLastRxDesc = myPrevRxDesc; + + myNextRxDesc->status = 0; + myNextRxDesc = phys_to_virt(myNextRxDesc->next); + } +} + + + +static void cleanup_sb(USB_SB_Desc_t *sb) +{ + USB_SB_Desc_t *next_sb; + + DBFENTER; + + if (sb == NULL) { + err("cleanup_sb was given a NULL pointer"); + return; + } + + while (!(sb->command & IO_MASK(USB_SB_command, eol))) { + next_sb = (USB_SB_Desc_t *)phys_to_virt(sb->next); + kmem_cache_free(usb_desc_cache, sb); + sb = next_sb; + } + + kmem_cache_free(usb_desc_cache, sb); + + DBFEXIT; + +} + +static int handle_control_transfer_attn(char epid, int status) +{ + urb_t *old_urb; + etrax_urb_priv_t *hc_priv; + + DBFENTER; + + clear_bit(epid, (void *)&ep_really_active); + + old_urb = URB_List[epid]; + URB_List[epid] = old_urb->next; + + /* if (status == 0 && IN) find data and copy to urb */ + if (status == 0 && usb_pipein(old_urb->pipe)) { + unsigned long flags; + etrax_urb_priv_t *urb_priv; + + urb_priv = (etrax_urb_priv_t *)old_urb->hcpriv; + save_flags(flags); + cli(); + if (urb_priv->eot == 1) { + old_urb->actual_length = urb_priv->rx_offset; + dbg_ctrl("urb_priv->rx_offset: %d in handle_control_attn", urb_priv->rx_offset); + } else { + status = -EPROTO; + old_urb->actual_length = 0; + err("(CTRL) No eot set in IN data!!! rx_offset: %d", urb_priv->rx_offset); + } + + restore_flags(flags); + } + + /* If there are any more URB's in the list we'd better start sending */ + if (URB_List[epid]) { + etrax_usb_do_ctrl_hw_add(URB_List[epid], epid, + usb_maxpacket(URB_List[epid]->dev, URB_List[epid]->pipe, + usb_pipeout(URB_List[epid]->pipe))); + } +#if 1 + else { + /* This means that this EP is now free, deconfigure it */ + etrax_usb_free_epid(epid); + } +#endif + + /* Remember to free the SB's */ + hc_priv = (etrax_urb_priv_t *)old_urb->hcpriv; + cleanup_sb(hc_priv->first_sb); + kfree(hc_priv); + + old_urb->status = status; + if (old_urb->complete) { + old_urb->complete(old_urb); + } + + DBFEXIT; +} + + + +static void etrax_usb_hc_intr_bottom_half(void *data) +{ + struct usb_reg_context *reg = (struct usb_reg_context *)data; + urb_t *old_urb; + + int error_code; + int epid; + + __u32 r_usb_ept_data; + + etrax_hc_t *hc = reg->hc; + __u16 r_usb_rh_port_status_1; + __u16 r_usb_rh_port_status_2; + + DBFENTER; + + if (reg->r_usb_irq_mask_read & IO_MASK(R_USB_IRQ_MASK_READ, port_status)) { + + /* + The Etrax RH does not include a wPortChange register, so this has + to be handled in software. See section 11.16.2.6.2 in USB 1.1 spec + for details. + */ + + r_usb_rh_port_status_1 = reg->r_usb_rh_port_status_1; + r_usb_rh_port_status_2 = reg->r_usb_rh_port_status_2; + + dbg_rh("port_status pending"); + dbg_rh("r_usb_rh_port_status_1: 0x%04X", r_usb_rh_port_status_1); + dbg_rh("r_usb_rh_port_status_2: 0x%04X", r_usb_rh_port_status_2); + + /* C_PORT_CONNECTION is set on any transition */ + hc->rh.wPortChange_1 |= + ((r_usb_rh_port_status_1 & (1 << RH_PORT_CONNECTION)) != + (hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_CONNECTION))) ? + (1 << RH_PORT_CONNECTION) : 0; + + hc->rh.wPortChange_2 |= + ((r_usb_rh_port_status_2 & (1 << RH_PORT_CONNECTION)) != + (hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_CONNECTION))) ? + (1 << RH_PORT_CONNECTION) : 0; + + /* C_PORT_ENABLE is _only_ set on a one to zero transition */ + hc->rh.wPortChange_1 |= + ((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_ENABLE)) + && !(r_usb_rh_port_status_1 & (1 << RH_PORT_ENABLE))) ? + (1 << RH_PORT_ENABLE) : 0; + + hc->rh.wPortChange_2 |= + ((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_ENABLE)) + && !(r_usb_rh_port_status_2 & (1 << RH_PORT_ENABLE))) ? + (1 << RH_PORT_ENABLE) : 0; + + /* C_PORT_SUSPEND seems difficult, lets ignore it.. (for now) */ + + /* C_PORT_RESET is _only_ set on a transition from the resetting state + to the enabled state */ + hc->rh.wPortChange_1 |= + ((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_RESET)) + && (r_usb_rh_port_status_1 & (1 << RH_PORT_ENABLE))) ? + (1 << RH_PORT_RESET) : 0; + + hc->rh.wPortChange_2 |= + ((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_RESET)) + && (r_usb_rh_port_status_2 & (1 << RH_PORT_ENABLE))) ? + (1 << RH_PORT_RESET) : 0; + + hc->rh.prev_wPortStatus_1 = r_usb_rh_port_status_1; + hc->rh.prev_wPortStatus_2 = r_usb_rh_port_status_2; + } + + for (epid = 0; epid < 32; epid++) { + + unsigned long flags; + + save_flags(flags); + cli(); + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); + r_usb_ept_data = *R_USB_EPT_DATA; + restore_flags(flags); + + if (r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, hold)) { + warn("Was hold for epid %d", epid); + continue; + } + + if (!(r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, valid))) { + continue; + } + + + if (test_bit(epid, (void *)®->r_usb_epid_attn)) { + + if (URB_List[epid] == NULL) { + err("R_USB_EPT_DATA is 0x%08X", r_usb_ept_data); + err("submit urb has been called %d times..", submit_urb_count); + err("EPID_ATTN for epid %d, with NULL entry in list", epid); + return; + } + + dbg_ep("r_usb_ept_data [%d] == 0x%08X", epid, + r_usb_ept_data); + + error_code = IO_EXTRACT(R_USB_EPT_DATA, error_code, + r_usb_ept_data); + + if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) { + /* no_error means that this urb was successfully sent or that we have + some undefinde error*/ + + if (IO_EXTRACT(R_USB_EPT_DATA, error_count_out, r_usb_ept_data) == 3 || + IO_EXTRACT(R_USB_EPT_DATA, error_count_in, r_usb_ept_data) == 3) { + /* Actually there were transmission errors */ + warn("Undefined error for endpoint %d", epid); + if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { + handle_control_transfer_attn(epid, -EPROTO); + } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) { + handle_bulk_transfer_attn(epid, -EPROTO); + } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { + handle_intr_transfer_attn(epid, -EPROTO); + } + + } else { + + if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) { + if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { + etrax_usb_do_intr_recover(epid); + } else { + panic("Epid attention for epid %d (none INTR), with no errors and no " + "exessive retry r_usb_status is 0x%02X\n", + epid, reg->r_usb_status); + } + + } else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) { + panic("Epid attention for epid %d, with no errors and no " + "exessive retry r_usb_status is 0x%02X\n", + epid, reg->r_usb_status); + + } + + warn("Epid attention for epid %d, with no errors and no " + "exessive retry r_usb_status is 0x%02X", + epid, reg->r_usb_status); + warn("OUT error count: %d", IO_EXTRACT(R_USB_EPT_DATA, error_count_out, + r_usb_ept_data)); + warn("IN error count: %d", IO_EXTRACT(R_USB_EPT_DATA, error_count_in, + r_usb_ept_data)); + + + } + + } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, stall)) { + warn("Stall for endpoint %d", epid); + if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { + handle_control_transfer_attn(epid, -EPIPE); + } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) { + handle_bulk_transfer_attn(epid, -EPIPE); + } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { + handle_intr_transfer_attn(epid, -EPIPE); + } + + + } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, bus_error)) { + panic("USB bus error for endpoint %d\n", epid); + + } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, buffer_error)) { + warn("Buffer error for endpoint %d", epid); + + if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { + handle_control_transfer_attn(epid, -EPROTO); + } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) { + handle_bulk_transfer_attn(epid, -EPROTO); + } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { + handle_intr_transfer_attn(epid, -EPROTO); + } + + } + } else if (test_bit(epid, (void *)&ep_really_active)) { + /* Should really be else if (testbit(really active)) */ + + if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { + + if (!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable))) { + /* Now we have to verify that this CTRL endpoint got disabled + cause it reached end of list with no error */ + + if (IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data) == + IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) { + /* + This means that the endpoint has no error, is disabled + and had inserted traffic, + i.e. transfer successfully completed + */ + dbg_ctrl("Last SB for CTRL %d sent successfully", epid); + handle_control_transfer_attn(epid, 0); + } + } + + } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) { + if (!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable))) { + /* Now we have to verify that this BULK endpoint go disabled + cause it reached end of list with no error */ + + if (IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data) == + IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) { + /* + This means that the endpoint has no error, is disabled + and had inserted traffic, + i.e. transfer successfully completed + */ + dbg_bulk("Last SB for BULK %d sent successfully", epid); + handle_bulk_transfer_attn(epid, 0); + } + } + } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { + handle_intr_transfer_attn(epid, 0); + } + } + + } + + kfree(reg); + + DBFEXIT; +} + + +static void etrax_usb_hc_intr_top_half(int irq, void *vhc, struct pt_regs *regs) +{ + struct usb_reg_context *reg; + + DBFENTER; + + reg = (struct usb_reg_context *)kmalloc(sizeof(struct usb_reg_context), GFP_ATOMIC); + + if (!(reg)) { + panic("kmalloc failed in top_half\n"); + } + + reg->hc = (etrax_hc_t *)vhc; + reg->r_usb_irq_mask_read = *R_USB_IRQ_MASK_READ; + reg->r_usb_status = *R_USB_STATUS; + +#if 0 + if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) { + panic("r_usb_status said perror\n"); + } + if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) { + panic("r_usb_status said ourun !!!\n"); + } +#endif + + reg->r_usb_epid_attn = *R_USB_EPID_ATTN; + + reg->r_usb_rh_port_status_1 = *R_USB_RH_PORT_STATUS_1; + reg->r_usb_rh_port_status_2 = *R_USB_RH_PORT_STATUS_2; + + reg->usb_bh.sync = 0; + reg->usb_bh.routine = etrax_usb_hc_intr_bottom_half; + reg->usb_bh.data = reg; + + queue_task(®->usb_bh, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + DBFEXIT; +} + +static int etrax_rh_submit_urb(urb_t *urb) +{ + struct usb_device *usb_dev = urb->dev; + etrax_hc_t *hc = usb_dev->bus->hcpriv; + unsigned int pipe = urb->pipe; + devrequest *cmd = (devrequest *) urb->setup_packet; + void *data = urb->transfer_buffer; + int leni = urb->transfer_buffer_length; + int len = 0; + int status = 0; + int stat = 0; + int i; + + __u16 cstatus; + + __u16 bmRType_bReq; + __u16 wValue; + __u16 wIndex; + __u16 wLength; + + DBFENTER; + + if (usb_pipetype (pipe) == PIPE_INTERRUPT) { + dbg_rh("Root-Hub submit IRQ: every %d ms", urb->interval); + hc->rh.urb = urb; + hc->rh.send = 1; + hc->rh.interval = urb->interval; + etrax_rh_init_int_timer(urb); + DBFEXIT; + + return 0; + } + + bmRType_bReq = cmd->requesttype | cmd->request << 8; + wValue = le16_to_cpu(cmd->value); + wIndex = le16_to_cpu(cmd->index); + wLength = le16_to_cpu(cmd->length); + + dbg_rh("bmRType_bReq : 0x%04X (%d)", bmRType_bReq, bmRType_bReq); + dbg_rh("wValue : 0x%04X (%d)", wValue, wValue); + dbg_rh("wIndex : 0x%04X (%d)", wIndex, wIndex); + dbg_rh("wLength : 0x%04X (%d)", wLength, wLength); + + switch (bmRType_bReq) { + + /* Request Destination: + without flags: Device, + RH_INTERFACE: interface, + RH_ENDPOINT: endpoint, + RH_CLASS means HUB here, + RH_OTHER | RH_CLASS almost ever means HUB_PORT here + */ + + case RH_GET_STATUS: + *(__u16 *) data = cpu_to_le16 (1); + OK (2); + + case RH_GET_STATUS | RH_INTERFACE: + *(__u16 *) data = cpu_to_le16 (0); + OK (2); + + case RH_GET_STATUS | RH_ENDPOINT: + *(__u16 *) data = cpu_to_le16 (0); + OK (2); + + case RH_GET_STATUS | RH_CLASS: + *(__u32 *) data = cpu_to_le32 (0); + OK (4); /* hub power ** */ + + case RH_GET_STATUS | RH_OTHER | RH_CLASS: + if (wIndex == 1) { + *((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_1); + *((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_1); + } + else if (wIndex == 2) { + *((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_2); + *((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_2); + } + else { + dbg_rh("RH_GET_STATUS whith invalid wIndex !!"); + OK(0); + } + + OK(4); + + case RH_CLEAR_FEATURE | RH_ENDPOINT: + switch (wValue) { + case (RH_ENDPOINT_STALL): + OK (0); + } + break; + + case RH_CLEAR_FEATURE | RH_CLASS: + switch (wValue) { + case (RH_C_HUB_OVER_CURRENT): + OK (0); /* hub power over current ** */ + } + break; + + case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: + switch (wValue) { + case (RH_PORT_ENABLE): + if (wIndex == 1) { + + dbg_rh("trying to do disable of port 1"); + + *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, yes); + while (hc->rh.prev_wPortStatus_1 & + IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes)); + *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no); + dbg_rh("Port 1 is disabled"); + + } else if (wIndex == 2) { + + dbg_rh("trying to do disable of port 2"); + + *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, yes); + while (hc->rh.prev_wPortStatus_2 & + IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, yes)); + *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no); + dbg_rh("Port 2 is disabled"); + + } else { + dbg_rh("RH_CLEAR_FEATURE->RH_PORT_ENABLE " + "with invalid wIndex == %d!!", wIndex); + } + + OK (0); + case (RH_PORT_SUSPEND): + /* Opposite to suspend should be resume, so well do a resume */ + if (wIndex == 1) { + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_sel, port1) | + IO_STATE(R_USB_COMMAND, port_cmd, resume)| + IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); + } else if (wIndex == 2) { + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_sel, port2) | + IO_STATE(R_USB_COMMAND, port_cmd, resume)| + IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); + } else { + dbg_rh("RH_CLEAR_FEATURE->RH_PORT_SUSPEND " + "with invalid wIndex == %d!!", wIndex); + } + + OK (0); + case (RH_PORT_POWER): + OK (0); /* port power ** */ + case (RH_C_PORT_CONNECTION): + + if (wIndex == 1) { + hc->rh.wPortChange_1 &= ~(1 << RH_PORT_CONNECTION); + } + else if (wIndex == 2) { + hc->rh.wPortChange_2 &= ~(1 << RH_PORT_CONNECTION); + } + else { + dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_CONNECTION " + "with invalid wIndex == %d!!", wIndex); + } + + OK (0); + case (RH_C_PORT_ENABLE): + if (wIndex == 1) { + hc->rh.wPortChange_1 &= ~(1 << RH_PORT_ENABLE); + } + else if (wIndex == 2) { + hc->rh.wPortChange_2 &= ~(1 << RH_PORT_ENABLE); + } + else { + dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_ENABLE " + "with invalid wIndex == %d!!", wIndex); + } + OK (0); + case (RH_C_PORT_SUSPEND): +/*** WR_RH_PORTSTAT(RH_PS_PSSC); */ + OK (0); + case (RH_C_PORT_OVER_CURRENT): + OK (0); /* port power over current ** */ + case (RH_C_PORT_RESET): + if (wIndex == 1) { + hc->rh.wPortChange_1 &= ~(1 << RH_PORT_RESET); + } + else if (wIndex == 2) { + dbg_rh("This is wPortChange before clear: 0x%04X", hc->rh.wPortChange_2); + + hc->rh.wPortChange_2 &= ~(1 << RH_PORT_RESET); + dbg_rh("This is wPortChange after clear: 0x%04X", hc->rh.wPortChange_2); + } else { + dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_RESET " + "with invalid index == %d!!", wIndex); + } + + OK (0); + + } + break; + + case RH_SET_FEATURE | RH_OTHER | RH_CLASS: + switch (wValue) { + case (RH_PORT_SUSPEND): + if (wIndex == 1) { + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_sel, port1) | + IO_STATE(R_USB_COMMAND, port_cmd, suspend) | + IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); + } else if (wIndex == 2) { + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_sel, port2) | + IO_STATE(R_USB_COMMAND, port_cmd, suspend) | + IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); + } else { + dbg_rh("RH_SET_FEATURE->RH_C_PORT_SUSPEND " + "with invalid wIndex == %d!!", wIndex); + } + + OK (0); + case (RH_PORT_RESET): + if (wIndex == 1) { + int port1_retry; + + port1_redo: + dbg_rh("Doing reset of port 1"); + + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_cmd, reset) | + IO_STATE(R_USB_COMMAND, port_sel, port1); + + /* We must once again wait at least 10ms for the device to recover */ + + port1_retry = 0; + while (!((*((volatile __u16 *)&hc->rh.prev_wPortStatus_1)) & + IO_STATE(R_USB_RH_PORT_STATUS_1, + enabled, yes))) { + printk(""); if (port1_retry++ >= 10000) {goto port1_redo;} + } + + /* This only seems to work if we use printk, + not even schedule() works !!! WHY ?? */ + + udelay(15000); + } + else if (wIndex == 2) { + int port2_retry; + + port2_redo: + dbg_rh("Doing reset of port 2"); + + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_cmd, reset) | + IO_STATE(R_USB_COMMAND, port_sel, port2); + + /* We must once again wait at least 10ms for the device to recover */ + + port2_retry = 0; + while (!((*((volatile __u16 *)&hc->rh.prev_wPortStatus_2)) & + IO_STATE(R_USB_RH_PORT_STATUS_2, + enabled, yes))) { + printk(""); if (port2_retry++ >= 10000) {goto port2_redo;} + } + + /* This only seems to work if we use printk, + not even schedule() works !!! WHY ?? */ + + udelay(15000); + } + + /* Try to bring the HC into running state */ + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run); + + nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); + + dbg_rh("...Done"); + OK(0); + + case (RH_PORT_POWER): + OK (0); /* port power ** */ + case (RH_PORT_ENABLE): + /* There is no rh port enable command in the Etrax USB interface!!!! */ + OK (0); + + } + break; + + case RH_SET_ADDRESS: + hc->rh.devnum = wValue; + dbg_rh("RH address set to: %d", hc->rh.devnum); + OK (0); + + case RH_GET_DESCRIPTOR: + switch ((wValue & 0xff00) >> 8) { + case (0x01): /* device descriptor */ + len = min (leni, min (sizeof (root_hub_dev_des), wLength)); + memcpy (data, root_hub_dev_des, len); + OK (len); + case (0x02): /* configuration descriptor */ + len = min (leni, min (sizeof (root_hub_config_des), wLength)); + memcpy (data, root_hub_config_des, len); + OK (len); + case (0x03): /* string descriptors */ + len = usb_root_hub_string (wValue & 0xff, + 0xff, "ETRAX 100LX", + data, wLength); + if (len > 0) { + OK (min (leni, len)); + } else + stat = -EPIPE; + } + break; + + case RH_GET_DESCRIPTOR | RH_CLASS: + root_hub_hub_des[2] = hc->rh.numports; + len = min (leni, min (sizeof (root_hub_hub_des), wLength)); + memcpy (data, root_hub_hub_des, len); + OK (len); + + case RH_GET_CONFIGURATION: + *(__u8 *) data = 0x01; + OK (1); + + case RH_SET_CONFIGURATION: + OK (0); + + default: + stat = -EPIPE; + } + + urb->actual_length = len; + urb->status = stat; + urb->dev=NULL; + if (urb->complete) { + urb->complete (urb); + } + DBFEXIT; + + return 0; +} + +static int __init etrax_usb_hc_init(void) +{ + static etrax_hc_t *hc; + struct usb_bus *bus; + struct usb_device *usb_rh; + + DBFENTER; + + info("ETRAX 100LX USB-HCD %s (c) 2001 Axis Communications AB\n", usb_hcd_version); + + hc = kmalloc(sizeof(etrax_hc_t), GFP_KERNEL); + + /* We use kmem_cache_* to make sure that all DMA desc. are dword aligned */ + usb_desc_cache = kmem_cache_create("usb_desc_cache", sizeof(USB_EP_Desc_t), 0, 0, 0, 0); + if (!usb_desc_cache) { + panic("USB Desc Cache allocation failed !!!\n"); + } + + etrax_usb_bus = bus = usb_alloc_bus(&etrax_usb_device_operations); + hc->bus = bus; + bus->hcpriv = hc; + + /* Initalize RH to the default address. + And make sure that we have no status change indication */ + hc->rh.numports = 2; /* The RH has two ports */ + hc->rh.devnum = 0; + hc->rh.wPortChange_1 = 0; + hc->rh.wPortChange_2 = 0; + + /* Also initate the previous values to zero */ + hc->rh.prev_wPortStatus_1 = 0; + hc->rh.prev_wPortStatus_2 = 0; + + /* Initialize the intr-traffic flags */ + hc->intr.sleeping = 0; + hc->intr.wq = NULL; + + /* Initially all ep's are free except ep 0 */ + ep_usage_bitmask = 0; + set_bit(0, (void *)&ep_usage_bitmask); + ep_really_active = 0; + + memset(URB_List, 0, sizeof(URB_List)); + + /* This code should really be moved */ + + if (request_dma(8, "ETRAX 100LX built-in USB (Tx)")) { + err("Could not allocate DMA ch 8 for USB"); + etrax_usb_hc_cleanup(); + DBFEXIT; + return -1; + } + + if (request_dma(9, "ETRAX 100LX built-in USB (Rx)")) { + err("Could not allocate DMA ch 9 for USB"); + etrax_usb_hc_cleanup(); + DBFEXIT; + return -1; + } +#if 0 /* Moved to head.S */ + *R_GEN_CONFIG = genconfig_shadow = + (genconfig_shadow & ~(IO_MASK(R_GEN_CONFIG, usb1) | + IO_MASK(R_GEN_CONFIG, usb2) | + IO_MASK(R_GEN_CONFIG, dma8) | + IO_MASK(R_GEN_CONFIG, dma9))) | + IO_STATE(R_GEN_CONFIG, dma8, usb) | + IO_STATE(R_GEN_CONFIG, dma9, usb) +#ifdef CONFIG_ETRAX_USB_HOST_PORT1 + | IO_STATE(R_GEN_CONFIG, usb1, select) +#endif +#ifdef CONFIG_ETRAX_USB_HOST_PORT2 + | IO_STATE(R_GEN_CONFIG, usb2, select) +#endif + ; +#endif + + usb_register_bus(hc->bus); + + /* We may have to set more bits, but these are the obvious ones */ + *R_IRQ_MASK2_SET = + IO_STATE(R_IRQ_MASK2_SET, dma8_sub0_descr, set) | + IO_STATE(R_IRQ_MASK2_SET, dma8_sub1_descr, set) | + IO_STATE(R_IRQ_MASK2_SET, dma8_sub2_descr, set) | + IO_STATE(R_IRQ_MASK2_SET, dma8_sub3_descr, set); + + *R_IRQ_MASK2_SET = + IO_STATE(R_IRQ_MASK2_SET, dma9_eop, set) | + IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set); + + *R_USB_IRQ_MASK_SET = + IO_STATE(R_USB_IRQ_MASK_SET, ctl_status, set) | + IO_STATE(R_USB_IRQ_MASK_SET, ctl_eot, set) | + IO_STATE(R_USB_IRQ_MASK_SET, bulk_eot, set) | +#ifdef ETRAX_USB_INTR_IRQ + IO_STATE(R_USB_IRQ_MASK_SET, intr_eot, set) | +#endif + IO_STATE(R_USB_IRQ_MASK_SET, epid_attn, set) | + IO_STATE(R_USB_IRQ_MASK_SET, port_status, set); + + if (request_irq(ETRAX_USB_HC_IRQ, etrax_usb_hc_intr_top_half, 0, + "ETRAX 100LX built-in USB (HC)", hc)) { + err("Could not allocate IRQ %d for USB", ETRAX_USB_HC_IRQ); + etrax_usb_hc_cleanup(); + DBFEXIT; + return -1; + } + + if (request_irq(ETRAX_USB_RX_IRQ, etrax_usb_rx_interrupt, 0, + "ETRAX 100LX built-in USB (Rx)", hc)) { + err("Could not allocate IRQ %d for USB", ETRAX_USB_RX_IRQ); + etrax_usb_hc_cleanup(); + DBFEXIT; + return -1; + } + + if (request_irq(ETRAX_USB_TX_IRQ, etrax_usb_tx_interrupt, 0, + "ETRAX 100LX built-in USB (Tx)", hc)) { + err("Could not allocate IRQ %d for USB", ETRAX_USB_TX_IRQ); + etrax_usb_hc_cleanup(); + DBFEXIT; + return -1; + } + + /* Reset the USB interface (configures as HC) */ + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, ctrl_cmd, reset) | + IO_STATE(R_USB_COMMAND, port_cmd, reset); + + nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); +#if 1 + /* Initate PSTART to all unallocatable bit times */ + *R_USB_FM_PSTART = IO_FIELD(R_USB_FM_PSTART, value, 10000); +#endif + +#ifdef CONFIG_ETRAX_USB_HOST_PORT1 + *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no); +#endif + +#ifdef CONFIG_ETRAX_USB_HOST_PORT2 + *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no); +#endif + + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, ctrl_cmd, host_config) | + IO_STATE(R_USB_COMMAND, port_cmd, reset); + + nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); + + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_sel, port1) | + IO_STATE(R_USB_COMMAND, port_cmd, reset); + + nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); + + /* Here we must wait at least 10ms so the device has time to recover */ + udelay(15000); + + init_rx_buffers(); + init_tx_bulk_ep(); + init_tx_ctrl_ep(); + init_tx_intr_ep(); + + /* This works. It seems like the host_run command only has effect when a device is connected, + i.e. it has to be done when a interrup */ + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run); + + nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); + + usb_rh = usb_alloc_dev(NULL, hc->bus); + hc->bus->root_hub = usb_rh; + usb_connect(usb_rh); + usb_new_device(usb_rh); + + DBFEXIT; + + return 0; +} + +static void etrax_usb_hc_cleanup(void) +{ + DBFENTER; + + free_irq(ETRAX_USB_HC_IRQ, NULL); + free_irq(ETRAX_USB_RX_IRQ, NULL); + free_irq(ETRAX_USB_TX_IRQ, NULL); + + free_dma(8); + free_dma(9); + usb_deregister_bus(etrax_usb_bus); + + DBFEXIT; +} + +module_init(etrax_usb_hc_init); +module_exit(etrax_usb_hc_cleanup); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/usb-host.h linux.ac/arch/cris/drivers/usb-host.h --- linux.vanilla/arch/cris/drivers/usb-host.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/drivers/usb-host.h Tue Apr 10 18:05:08 2001 @@ -0,0 +1,245 @@ +#ifndef __LINUX_ETRAX_USB_H +#define __LINUX_ETRAX_USB_H + +#include <linux/types.h> +#include <linux/list.h> + +typedef struct USB_IN_Desc { + __u16 sw_len; + __u16 command; + unsigned long next; + unsigned long buf; + __u16 hw_len; + __u16 status; +} USB_IN_Desc_t; + +typedef struct USB_SB_Desc { + __u16 sw_len; + __u16 command; + unsigned long next; + unsigned long buf; + __u32 dummy; +} USB_SB_Desc_t; + +typedef struct USB_EP_Desc { + __u16 hw_len; + __u16 command; + unsigned long sub; + unsigned long nep; + __u32 dummy; +} USB_EP_Desc_t; + +struct virt_root_hub { + int devnum; + void *urb; + void *int_addr; + int send; + int interval; + int numports; + struct timer_list rh_int_timer; + __u16 wPortChange_1; + __u16 wPortChange_2; + __u16 prev_wPortStatus_1; + __u16 prev_wPortStatus_2; +}; + +struct etrax_usb_intr_traffic { + int sleeping; + int error; + struct wait_queue *wq; +}; + +typedef struct etrax_usb_hc { + struct usb_bus *bus; + struct virt_root_hub rh; + struct etrax_usb_intr_traffic intr; +} etrax_hc_t; + +typedef enum {idle, eot, nodata} etrax_usb_rx_state_t; + +typedef struct etrax_usb_urb_priv { + USB_SB_Desc_t *first_sb; + __u32 rx_offset; + etrax_usb_rx_state_t rx_state; + __u8 eot; + struct list_head ep_in_list; +} etrax_urb_priv_t; + + +struct usb_reg_context +{ + etrax_hc_t *hc; + __u32 r_usb_epid_attn; + __u8 r_usb_status; + __u32 r_usb_rh_port_status_1; + __u32 r_usb_rh_port_status_2; + __u32 r_usb_irq_mask_read; + struct tq_struct usb_bh; +#if 0 + __u32 r_usb_ept_data[32]; +#endif +}; + +struct in_chunk +{ + void *data; + int length; + char epid; + struct list_head list; +}; + + +/* --------------------------------------------------------------------------- + Virtual Root HUB + ------------------------------------------------------------------------- */ +/* destination of request */ +#define RH_INTERFACE 0x01 +#define RH_ENDPOINT 0x02 +#define RH_OTHER 0x03 + +#define RH_CLASS 0x20 +#define RH_VENDOR 0x40 + +/* Requests: bRequest << 8 | bmRequestType */ +#define RH_GET_STATUS 0x0080 +#define RH_CLEAR_FEATURE 0x0100 +#define RH_SET_FEATURE 0x0300 +#define RH_SET_ADDRESS 0x0500 +#define RH_GET_DESCRIPTOR 0x0680 +#define RH_SET_DESCRIPTOR 0x0700 +#define RH_GET_CONFIGURATION 0x0880 +#define RH_SET_CONFIGURATION 0x0900 +#define RH_GET_STATE 0x0280 +#define RH_GET_INTERFACE 0x0A80 +#define RH_SET_INTERFACE 0x0B00 +#define RH_SYNC_FRAME 0x0C80 +/* Our Vendor Specific Request */ +#define RH_SET_EP 0x2000 + + +/* Hub port features */ +#define RH_PORT_CONNECTION 0x00 +#define RH_PORT_ENABLE 0x01 +#define RH_PORT_SUSPEND 0x02 +#define RH_PORT_OVER_CURRENT 0x03 +#define RH_PORT_RESET 0x04 +#define RH_PORT_POWER 0x08 +#define RH_PORT_LOW_SPEED 0x09 +#define RH_C_PORT_CONNECTION 0x10 +#define RH_C_PORT_ENABLE 0x11 +#define RH_C_PORT_SUSPEND 0x12 +#define RH_C_PORT_OVER_CURRENT 0x13 +#define RH_C_PORT_RESET 0x14 + +/* Hub features */ +#define RH_C_HUB_LOCAL_POWER 0x00 +#define RH_C_HUB_OVER_CURRENT 0x01 + +#define RH_DEVICE_REMOTE_WAKEUP 0x00 +#define RH_ENDPOINT_STALL 0x01 + +/* Our Vendor Specific feature */ +#define RH_REMOVE_EP 0x00 + + +#define RH_ACK 0x01 +#define RH_REQ_ERR -1 +#define RH_NACK 0x00 + +#define min(a,b) (((a)<(b))?(a):(b)) + +/* Field definitions for */ + +#define USB_IN_command__eol__BITNR 0 /* command macros */ +#define USB_IN_command__eol__WIDTH 1 +#define USB_IN_command__eol__no 0 +#define USB_IN_command__eol__yes 1 + +#define USB_IN_command__intr__BITNR 3 +#define USB_IN_command__intr__WIDTH 1 +#define USB_IN_command__intr__no 0 +#define USB_IN_command__intr__yes 1 + +#define USB_IN_status__eop__BITNR 1 /* status macros. */ +#define USB_IN_status__eop__WIDTH 1 +#define USB_IN_status__eop__no 0 +#define USB_IN_status__eop__yes 1 + +#define USB_IN_status__eot__BITNR 5 +#define USB_IN_status__eot__WIDTH 1 +#define USB_IN_status__eot__no 0 +#define USB_IN_status__eot__yes 1 + +#define USB_IN_status__error__BITNR 6 +#define USB_IN_status__error__WIDTH 1 +#define USB_IN_status__error__no 0 +#define USB_IN_status__error__yes 1 + +#define USB_IN_status__nodata__BITNR 7 +#define USB_IN_status__nodata__WIDTH 1 +#define USB_IN_status__nodata__no 0 +#define USB_IN_status__nodata__yes 1 + +#define USB_IN_status__epid__BITNR 8 +#define USB_IN_status__epid__WIDTH 5 + +#define USB_EP_command__eol__BITNR 0 +#define USB_EP_command__eol__WIDTH 1 +#define USB_EP_command__eol__no 0 +#define USB_EP_command__eol__yes 1 + +#define USB_EP_command__eof__BITNR 1 +#define USB_EP_command__eof__WIDTH 1 +#define USB_EP_command__eof__no 0 +#define USB_EP_command__eof__yes 1 + +#define USB_EP_command__intr__BITNR 3 +#define USB_EP_command__intr__WIDTH 1 +#define USB_EP_command__intr__no 0 +#define USB_EP_command__intr__yes 1 + +#define USB_EP_command__enable__BITNR 4 +#define USB_EP_command__enable__WIDTH 1 +#define USB_EP_command__enable__no 0 +#define USB_EP_command__enable__yes 1 + +#define USB_EP_command__hw_valid__BITNR 5 +#define USB_EP_command__hw_valid__WIDTH 1 +#define USB_EP_command__hw_valid__no 0 +#define USB_EP_command__hw_valid__yes 1 + +#define USB_EP_command__epid__BITNR 8 +#define USB_EP_command__epid__WIDTH 5 + +#define USB_SB_command__eol__BITNR 0 /* command macros. */ +#define USB_SB_command__eol__WIDTH 1 +#define USB_SB_command__eol__no 0 +#define USB_SB_command__eol__yes 1 + +#define USB_SB_command__eot__BITNR 1 +#define USB_SB_command__eot__WIDTH 1 +#define USB_SB_command__eot__no 0 +#define USB_SB_command__eot__yes 1 + +#define USB_SB_command__intr__BITNR 3 +#define USB_SB_command__intr__WIDTH 1 +#define USB_SB_command__intr__no 0 +#define USB_SB_command__intr__yes 1 + +#define USB_SB_command__tt__BITNR 4 +#define USB_SB_command__tt__WIDTH 2 +#define USB_SB_command__tt__zout 0 +#define USB_SB_command__tt__in 1 +#define USB_SB_command__tt__out 2 +#define USB_SB_command__tt__setup 3 + + +#define USB_SB_command__rem__BITNR 8 +#define USB_SB_command__rem__WIDTH 6 + +#define USB_SB_command__full__BITNR 6 +#define USB_SB_command__full__WIDTH 1 +#define USB_SB_command__full__no 0 +#define USB_SB_command__full__yes 1 + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/entry.S linux.ac/arch/cris/kernel/entry.S --- linux.vanilla/arch/cris/kernel/entry.S Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/cris/kernel/entry.S Tue Apr 10 18:05:08 2001 @@ -1,12 +1,30 @@ -/* $Id: entry.S,v 1.11 2001/01/10 21:13:29 bjornw Exp $ +/* $Id: entry.S,v 1.15 2001/03/05 13:14:30 bjornw Exp $ * * linux/arch/cris/entry.S * - * Copyright (C) 2000 Axis Communications AB + * Copyright (C) 2000, 2001 Axis Communications AB * * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: entry.S,v $ + * Revision 1.15 2001/03/05 13:14:30 bjornw + * Spelling fix + * + * Revision 1.14 2001/02/23 08:36:36 perf + * New ABI; syscallnr=r9, arg5=mof, arg6=srp. + * Corrected tracesys call check. + * + * Revision 1.13 2001/02/15 08:40:55 perf + * H-P by way of perf; + * - (_system_call): Don't read system call function address into r1. + * - (RBFExit): There is no such thing as a null pop. Adjust sp by addq. + * - (_system_call): Don't use r10 and don't save and restore it. + * - (THREAD_ESP0): New constant. + * - (_system_call): Inline set_esp0. + * + * Revision 1.12 2001/01/31 17:56:25 orjanf + * Added definition of LTASK_PID and made it global. + * * Revision 1.11 2001/01/10 21:13:29 bjornw * SYMBOL_NAME is defined incorrectly for the compiler options we currently use * @@ -79,7 +97,8 @@ .globl _mmu_bus_fault .globl _sys_call_table - + + .globl LTASK_PID ;; syscall error codes LENOSYS = 38 @@ -90,7 +109,17 @@ LTASK_SIGPENDING = 8 LTASK_NEEDRESCHED = 20 LTASK_PTRACE = 24 +LTASK_PID = 105 + + ;; process bits for ptrace +PT_TRACESYS_BIT = 1 + + ;; Offset for esp0 into task_struct: current->thread.esp0. + ;; FIXME: In need of padding somewhere, to get dword-alignment. + +THREAD_ESP0 = 597 + ;; some pt_regs offsets (from ptrace.h) LORIG_R10 = 4 @@ -98,8 +127,8 @@ LR12 = 12 LR11 = 16 LR10 = 20 -LR1 = 56 -LR0 = 60 +LR9 = 24 +LMOF = 64 LDCCR = 68 LSRP = 72 LIRP = 76 @@ -124,7 +153,7 @@ nop ba ret_with_reschedule ; go back but check schedule and signals first nop - + reschedule: ;; keep r9 intact push r9 @@ -170,41 +199,38 @@ push r10 ; push orig_r10 clear.d [sp=sp-4] ; frametype == 0, normal stackframe - move.d r10,r2 ; save for later - - movs.w -LENOSYS,r10 - move.d r10,[sp+LR10] ; put the default return value in r10 in the frame - - move.d sp,r10 - jsr _set_esp0 ; save top of frame (clobbers r9...) + movs.w -LENOSYS,r0 + move.d r0,[sp+LR10] ; put the default return value in r10 in the frame + + ;; Perform "current->thread.esp0 = sp". + ;; This used to be a separate function; set_esp0(ssp). + movs.w -8192,r0 ; THREAD_SIZE == 8192 + and.d sp,r0 + + move.d sp,[r0+THREAD_ESP0] ;; check if this process is syscall-traced - move.d sp, r10 - and.d -8192, r10 ; THREAD_SIZE == 8192 - move.d [r10+LTASK_PTRACE],r10 - btstq 2, r10 ; PT_TRACESYS + move.d [r0+LTASK_PTRACE],r0 + btstq PT_TRACESYS_BIT, r0 bmi tracesys nop ;; check for sanity in the requested syscall number - cmpu.w NR_syscalls,r1 + cmpu.w NR_syscalls,r9 bcc _ret_from_sys_call - lslq 2,r1 ; multiply by 4, in the delay slot - - ;; read the system call vector into r1 - - move.d [r1+_sys_call_table],r1 + lslq 2,r9 ; multiply by 4, in the delay slot - ;; the parameter carrying registers r11, r12 and 13 are intact - restore r10. - ;; the fifth parameter (if any) was in r0, and we need to put it on the stack + ;; the parameter carrying registers r10, r11, r12 and 13 are intact. + ;; the fifth and sixth parameters (if any) was in mof and srp + ;; respectively, and we need to put them on the stack. - push r0 - move.d r2,r10 + push srp + push mof - jsr r1 ; actually call the corresponding system call - addq 4,sp ; pop the r0 parameter + jsr [r9+_sys_call_table] ; actually do the system call + addq 2*4,sp ; pop the mof and srp parameters move.d r10,[sp+LR10] ; save the return value moveq 1,r9 ; "parameter" to ret_from_sys_call to show it was a sys call @@ -269,10 +295,8 @@ ;; just get the PC value to restart it with, and skip the rest of ;; the frame. pop irp ; fixup location will be here - pop p8 ; null pop - pop p8 ; null pop reti ; return to IRP, taking U-flag into account - pop p8 ; null pop in delayslot + addq 12,sp ; Skip rest of SBFS frame. tracesys: @@ -289,30 +313,32 @@ ;; check for sanity in the requested syscall number - move.d [sp+LR1], r1 + move.d [sp+LR9], r9 movs.w -LENOSYS, r10 - cmpu.w NR_syscalls,r1 + cmpu.w NR_syscalls,r9 bcc 1f - lslq 2,r1 ; multiply by 4, in the delay slot + lslq 2,r9 ; multiply by 4, in the delay slot - ;; read the system call vector entry into r1 + ;; read the system call vector entry into r9 - move.d [r1+_sys_call_table],r1 + move.d [r9+_sys_call_table],r9 - ;; restore r10, r11, r12, r13 and r0 into the needed registers + ;; restore r10, r11, r12, r13, mof and srp into the needed registers move.d [sp+LORIG_R10], r10 ; LR10 is already filled with -LENOSYS move.d [sp+LR11], r11 move.d [sp+LR12], r12 move.d [sp+LR13], r13 - move.d [sp+LR0], r0 + move [sp+LMOF], mof + move [sp+LSRP], srp - ;; the fifth parameter needs to be put on the stack for the system - ;; call to find it + ;; the fifth and sixth parameters needs to be put on the stack for + ;; the system call to find them - push r0 - jsr r1 ; actually call the system-call - addq 4,sp ; pop the r0 parameter + push srp + push mof + jsr r9 ; actually call the system-call + addq 2*4,sp ; pop the r0 parameter 1: move.d r10,[sp+LR10] ; save the return value diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/head.S linux.ac/arch/cris/kernel/head.S --- linux.vanilla/arch/cris/kernel/head.S Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/kernel/head.S Tue Apr 10 18:05:08 2001 @@ -1,46 +1,75 @@ - ;; $Id: head.S,v 1.11 2001/01/16 16:31:38 bjornw Exp $ - ;; - ;; Head of the kernel - alter with care - ;; - ;; Copyright (C) 2000, 2001 Axis Communications AB - ;; - ;; Authors: Bjorn Wesen (bjornw@axis.com) - ;; - ;; $Log: head.S,v $ - ;; Revision 1.11 2001/01/16 16:31:38 bjornw - ;; * Changed name and semantics of running_from_flash to romfs_in_flash, - ;; set by head.S to indicate to setup.c whether there is a cramfs image - ;; after the kernels BSS or not. Should work for all three boot-cases - ;; (DRAM with cramfs in DRAM, DRAM with cramfs in flash (compressed boot), - ;; and flash with cramfs in flash) - ;; - ;; Revision 1.10 2001/01/16 14:12:21 bjornw - ;; * Check for cramfs start passed in r9 from the decompressor, if all other - ;; cramfs options fail (if we boot from DRAM but don't find a cramfs image - ;; after the kernel in DRAM, it is probably still in the flash) - ;; * Check magic in cramfs detection when booting from flash directly - ;; - ;; Revision 1.9 2001/01/15 17:17:02 bjornw - ;; * Corrected the code that detects the cramfs lengths - ;; * Added a comment saying that the above does not work due to other - ;; reasons.. - ;; - ;; Revision 1.8 2001/01/15 16:27:51 jonashg - ;; Made boot after flashing work. - ;; * end destination is __vmlinux_end in RAM. - ;; * _romfs_start moved because of virtual memory. - ;; - ;; Revision 1.7 2000/11/21 13:55:29 bjornw - ;; Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type - ;; - ;; Revision 1.6 2000/10/06 12:36:55 bjornw - ;; Forgot swapper_pg_dir when changing memory map.. - ;; - ;; Revision 1.5 2000/10/04 16:49:30 bjornw - ;; * Fixed memory mapping in LX - ;; * Check for cramfs instead of romfs - ;; - ;; +/* $Id: head.S,v 1.20 2001/02/23 12:47:56 bjornw Exp $ + * + * Head of the kernel - alter with care + * + * Copyright (C) 2000, 2001 Axis Communications AB + * + * Authors: Bjorn Wesen (bjornw@axis.com) + * + * $Log: head.S,v $ + * Revision 1.20 2001/02/23 12:47:56 bjornw + * MMU regs during LOW_MAP updated to reflect a newer reality + * + * Revision 1.19 2001/02/19 11:12:07 bjornw + * Changed comment header format + * + * Revision 1.18 2001/02/15 07:25:38 starvik + * Added support for synchronous serial ports + * + * Revision 1.17 2001/02/08 15:53:13 starvik + * Last commit removed some important ifdefs + * + * Revision 1.16 2001/02/08 15:20:38 starvik + * Include dram_init.S as inline + * + * Revision 1.15 2001/01/29 18:12:01 bjornw + * Corrected some comments + * + * Revision 1.14 2001/01/29 13:11:29 starvik + * Include dram_init.S (with DRAM/SDRAM initialization) + * + * Revision 1.13 2001/01/23 14:54:57 markusl + * Updated for USB + * i.e. added r_gen_config settings + * + * Revision 1.12 2001/01/19 16:16:29 perf + * Added temporary mapping of 0x0c->0x0c to avoid flash loading confusion. + * Renamed serial options from ETRAX100 to ETRAX. + * + * Revision 1.11 2001/01/16 16:31:38 bjornw + * * Changed name and semantics of running_from_flash to romfs_in_flash, + * set by head.S to indicate to setup.c whether there is a cramfs image + * after the kernels BSS or not. Should work for all three boot-cases + * (DRAM with cramfs in DRAM, DRAM with cramfs in flash (compressed boot), + * and flash with cramfs in flash) + * + * Revision 1.10 2001/01/16 14:12:21 bjornw + * * Check for cramfs start passed in r9 from the decompressor, if all other + * cramfs options fail (if we boot from DRAM but don't find a cramfs image + * after the kernel in DRAM, it is probably still in the flash) + * * Check magic in cramfs detection when booting from flash directly + * + * Revision 1.9 2001/01/15 17:17:02 bjornw + * * Corrected the code that detects the cramfs lengths + * * Added a comment saying that the above does not work due to other + * reasons.. + * + * Revision 1.8 2001/01/15 16:27:51 jonashg + * Made boot after flashing work. + * * end destination is __vmlinux_end in RAM. + * * _romfs_start moved because of virtual memory. + * + * Revision 1.7 2000/11/21 13:55:29 bjornw + * Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type + * + * Revision 1.6 2000/10/06 12:36:55 bjornw + * Forgot swapper_pg_dir when changing memory map.. + * + * Revision 1.5 2000/10/04 16:49:30 bjornw + * * Fixed memory mapping in LX + * * Check for cramfs instead of romfs + * + */ #include <linux/config.h> #define ASSEMBLER_MACROS_ONLY @@ -82,13 +111,13 @@ ;; slightly different. We also let the simulator get this mapping for now. #ifdef CONFIG_CRIS_LOW_MAP - move.d 0x0800b000, r0 ; kseg mappings + move.d 0x0004b098, r0 ; kseg mappings, temporary map of 0xc0->0x40 move.d r0, [R_MMU_KBASE_HI] move.d 0x04040000, r0 ; temporary map of 0x40->0x40 and 0x00->0x00 move.d r0, [R_MMU_KBASE_LO] - move.d 0x80074871, r0 ; mmu enable, segs e,b,6,5,4,0 segment mapped + move.d 0x80075c71, r0 ; mmu enable, segs c,b,9,8,6,5,4,0 segment mapped move.d r0, [R_MMU_CONFIG] #else move.d 0x0804b000, r0 ; kseg mappings @@ -131,24 +160,9 @@ jump inram ; enter cached ram inflash: + ;; We need to initialze DRAM registers before we start using the DRAM +#include "../lib/dram_init.S" -#ifndef CONFIG_SVINTO_SIM - - ;; We need to setup the bus registers before we start using the DRAM - - move.d DEF_R_WAITSTATES, r0 - move.d r0, [R_WAITSTATES] - - move.d DEF_R_BUS_CONFIG, r0 - move.d r0, [R_BUS_CONFIG] - - move.d DEF_R_DRAM_CONFIG, r0 - move.d r0, [R_DRAM_CONFIG] - - move.d DEF_R_DRAM_TIMING, r0 - move.d r0, [R_DRAM_TIMING] - -#endif ;; Copy text+data to DRAM ;; This is fragile - the calculation of r4 as the image size depends ;; on that the labels below actually are the first and last positions @@ -357,27 +371,38 @@ #if !defined(CONFIG_KGDB) && !defined(CONFIG_DMA_MEMCPY) or.d 0x140000,r0 ; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA #endif -#if !defined(CONFIG_KGDB) || !defined(CONFIG_DEBUG_PORT1) +#if !defined(CONFIG_KGDB) || !defined(CONFIG_DEBUG_PORT1) or.d 0xc00000,r0 ; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA -#endif +#endif #ifdef CONFIG_DMA_MEMCPY or.d 0x003c0000,r0 ; 6/7 memory-memory DMA #endif -#ifdef CONFIG_ETRAX100_SERIAL_PORT2 +#ifdef CONFIG_ETRAX_SERIAL_PORT2 or.d 0x2808,r0 ; DMA channels 2 and 3 to serport 2, port 2 enabled #endif -#ifdef CONFIG_ETRAX100_SERIAL_PORT3 +#if defined(CONFIG_ETRAX_SERIAL_PORT3) || defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) or.d 0x28100,r0 ; DMA channels 4 and 5 to serport 3, port 3 enabled -#endif -#if defined(CONFIG_ETRAX100_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) +#endif +#if defined(CONFIG_ETRAX_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) or.w 0x4,r0 ; parport 0 enabled using DMA 2/3 #endif -#if defined(CONFIG_ETRAX100_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) +#if defined(CONFIG_ETRAX_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) or.w 0x80,r0 ; parport 1 enabled using DMA 4/5 #endif #ifdef CONFIG_BLK_DEV_ETRAXIDE or.d 0x3c02,r0 ; DMA channels 2 and 3 to ATA, ATA enabled #endif + +#ifdef CONFIG_ETRAX_USB_HOST_PORT1 + or.d 0x20000000,r0 ; Set the USB port 1 enable bit +#endif +#ifdef CONFIG_ETRAX_USB_HOST_PORT2 + or.d 0x40000000,r0 ; Set the USB port 2 enable bit +#endif +#ifdef CONFIG_ETRAX_USB_HOST + and.d 0xff3fffff,r0 ; Connect DMA channels 8 and 9 to USB +#endif + #ifdef CONFIG_JULIETTE or.d 0x3c000,r0 ; DMA channels 4 and 5 to EXTDMA0, for Juliette #ifndef CONFIG_BLK_DEV_ETRAXIDE @@ -438,6 +463,9 @@ move.b DEF_R_PORT_PB_DATA,r0 move.b r0,[_port_pb_data_shadow] move.b r0,[R_PORT_PB_DATA] + move.d 0, r0 + move.d r0,[_port_pb_i2c_shadow] + move.d r0, [R_PORT_PB_I2C] moveq 0,r0 move.d r0,[_port_g_data_shadow] @@ -478,7 +506,7 @@ move.d r0,[0x90000000] #endif -#ifdef CONFIG_ETRAX100_SERIAL_PORT3 +#ifdef CONFIG_ETRAX_SERIAL_PORT3 ;; setup the serial port 3 at 115200 baud for debug purposes moveq 0,r0 @@ -497,8 +525,7 @@ #endif /* CONFIG_SVINTO_SIM */ jump _start_kernel ; jump into the C-function _start_kernel in init/main.c - - + .data _etrax_irv: .dword 0 @@ -508,7 +535,7 @@ .dword 0 _romfs_in_flash: .dword 0 - + ;; put some special pages at the beginning of the kernel aligned ;; to page boundaries - the kernel cannot start until after this diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/irq.c linux.ac/arch/cris/kernel/irq.c --- linux.vanilla/arch/cris/kernel/irq.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/kernel/irq.c Tue Apr 10 18:05:08 2001 @@ -1,8 +1,8 @@ -/* $Id: irq.c,v 1.5 2000/08/17 15:35:15 bjornw Exp $ +/* $Id: irq.c,v 1.11 2001/02/27 13:52:52 bjornw Exp $ * * linux/arch/cris/kernel/irq.c * - * Copyright (c) 2000 Axis Communications AB + * Copyright (c) 2000,2001 Axis Communications AB * * Authors: Bjorn Wesen (bjornw@axis.com) * @@ -30,7 +30,7 @@ #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/timex.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/random.h> #include <asm/system.h> @@ -160,6 +160,8 @@ BUILD_IRQ(23, 0x800000) BUILD_IRQ(24, 0x1000000) BUILD_IRQ(25, 0x2000000) +/* IRQ 26-30 are resereved */ +BUILD_IRQ(31, 0x80000000) /* * Pointers to the low-level handlers @@ -172,7 +174,8 @@ IRQ12_interrupt, IRQ13_interrupt, NULL, NULL, IRQ16_interrupt, IRQ17_interrupt, IRQ18_interrupt, IRQ19_interrupt, IRQ20_interrupt, IRQ21_interrupt, IRQ22_interrupt, IRQ23_interrupt, - IRQ24_interrupt, IRQ25_interrupt + IRQ24_interrupt, IRQ25_interrupt, NULL, NULL, NULL, NULL, NULL, + IRQ31_interrupt }; static void (*sinterrupt[NR_IRQS])(void) = { @@ -182,7 +185,8 @@ sIRQ12_interrupt, sIRQ13_interrupt, NULL, NULL, sIRQ16_interrupt, sIRQ17_interrupt, sIRQ18_interrupt, sIRQ19_interrupt, sIRQ20_interrupt, sIRQ21_interrupt, sIRQ22_interrupt, sIRQ23_interrupt, - sIRQ24_interrupt, sIRQ25_interrupt + sIRQ24_interrupt, sIRQ25_interrupt, NULL, NULL, NULL, NULL, NULL, + sIRQ31_interrupt }; static void (*bad_interrupt[NR_IRQS])(void) = { @@ -198,7 +202,9 @@ bad_IRQ18_interrupt, bad_IRQ19_interrupt, bad_IRQ20_interrupt, bad_IRQ21_interrupt, bad_IRQ22_interrupt, bad_IRQ23_interrupt, - bad_IRQ24_interrupt, bad_IRQ25_interrupt + bad_IRQ24_interrupt, bad_IRQ25_interrupt, + NULL, NULL, NULL, NULL, NULL, + bad_IRQ31_interrupt }; /* @@ -212,7 +218,8 @@ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL }; int get_irq_list(char *buf) @@ -412,6 +419,8 @@ */ void system_call(void); /* from entry.S */ +void gdb_handle_breakpoint(void); /* from traps.c */ +void do_sigtrap(void); /* also from traps.c */ void init_IRQ(void) { @@ -431,14 +440,22 @@ for(i = 0; i < NR_IRQS; i++) irq_shortcuts[i] = NULL; - - for (i = 0; i < 256; i++) - etrax_irv->v[i] = weird_irq; - + + for (i = 0; i < 256; i++) + etrax_irv->v[i] = weird_irq; + + /* the entries in the break vector contain actual code to be + executed by the associated break handler, rather than just a jump + address. therefore we need to setup a default breakpoint handler + for all breakpoints */ + + for (i = 0; i < 16; i++) + set_break_vector(i, do_sigtrap); + /* set all etrax irq's to the bad handlers */ for (i = 2; i < NR_IRQS; i++) set_int_vector(i, bad_interrupt[i], 0); - + /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */ set_int_vector(15, multiple_interrupt, 0); @@ -456,12 +473,15 @@ set_break_vector(13, system_call); + /* setup a breakpoint handler for debugging used for both user and + kernel mode debugging (which is why it is not inside an ifdef + CONFIG_KGDB) */ + set_break_vector(8, gdb_handle_breakpoint); + #ifdef CONFIG_KGDB /* setup kgdb if its enabled, and break into the debugger */ - kgdb_init(); - breakpoint(); #endif -} +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/kgdb.c linux.ac/arch/cris/kernel/kgdb.c --- linux.vanilla/arch/cris/kernel/kgdb.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/kernel/kgdb.c Tue Apr 10 18:05:08 2001 @@ -18,6 +18,12 @@ *! Jul 21 1999 Bjorn Wesen eLinux port *! *! $Log: kgdb.c,v $ +*! Revision 1.4 2001/02/23 13:45:19 bjornw +*! config.h check +*! +*! Revision 1.3 2001/01/31 18:08:23 orjanf +*! Removed kgdb_handle_breakpoint from being the break 8 handler. +*! *! Revision 1.2 2001/01/12 14:22:25 orjanf *! Updated kernel debugging support to work with ETRAX 100LX. *! @@ -43,7 +49,7 @@ *! *!--------------------------------------------------------------------------- *! -*! $Id: kgdb.c,v 1.2 2001/01/12 14:22:25 orjanf Exp $ +*! $Id: kgdb.c,v 1.4 2001/02/23 13:45:19 bjornw Exp $ *! *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN *! @@ -1531,7 +1537,7 @@ { /* could initialize debug port as well but it's done in head.S already... */ - set_break_vector(8, kgdb_handle_breakpoint); + /* breakpoint handler is now set in irq.c */ set_int_vector(8, kgdb_handle_serial, 0); enableDebugIRQ(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/process.c linux.ac/arch/cris/kernel/process.c --- linux.vanilla/arch/cris/kernel/process.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/kernel/process.c Mon Apr 16 12:37:03 2001 @@ -1,9 +1,9 @@ -/* $Id: process.c,v 1.8 2000/09/13 14:34:13 bjornw Exp $ +/* $Id: process.c,v 1.12 2001/02/27 13:52:52 bjornw Exp $ * * linux/arch/cris/kernel/process.c * * Copyright (C) 1995 Linus Torvalds - * Copyright (C) 2000 Axis Communications AB + * Copyright (C) 2000, 2001 Axis Communications AB * * Authors: Bjorn Wesen (bjornw@axis.com) * @@ -23,7 +23,7 @@ #include <linux/stddef.h> #include <linux/unistd.h> #include <linux/ptrace.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/user.h> #include <linux/a.out.h> #include <linux/interrupt.h> @@ -71,11 +71,6 @@ #define currentregs ((struct pt_regs *)current->thread.esp0) -asmlinkage void set_esp0(unsigned long ssp) -{ - current->thread.esp0 = ssp; -} - void disable_hlt(void) { hlt_counter++; @@ -134,7 +129,7 @@ register long __a __asm__ ("r10"); __asm__ __volatile__ - ("movu.w %1,r1\n\t" /* r1 contains syscall number, to sys_clone */ + ("movu.w %1,r9\n\t" /* r9 contains syscall number, to sys_clone */ "clear.d r10\n\t" /* r10 is argument 1 to clone */ "move.d %2,r11\n\t" /* r11 is argument 2 to clone, the flags */ "break 13\n\t" /* call sys_clone, this will fork */ @@ -143,14 +138,14 @@ "nop\n\t" /* delay slot */ "move.d %4,r10\n\t" /* set argument to function to call */ "jsr %5\n\t" /* call specified function */ - "movu.w %3,r1\n\t" /* r1 is sys_exit syscall number */ + "movu.w %3,r9\n\t" /* r9 is sys_exit syscall number */ "moveq -1,r10\n\t" /* Give a really bad exit-value */ "break 13\n\t" /* call sys_exit, killing the child */ "1:\n\t" : "=r" (__a) : "g" (__NR_clone), "r" (flags | CLONE_VM), "g" (__NR_exit), "r" (arg), "r" (fn) - : "r10", "r11", "r1"); + : "r10", "r11", "r9"); return __a; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/setup.c linux.ac/arch/cris/kernel/setup.c --- linux.vanilla/arch/cris/kernel/setup.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/kernel/setup.c Tue Apr 10 18:05:25 2001 @@ -1,9 +1,9 @@ -/* $Id: setup.c,v 1.8 2001/01/16 16:31:38 bjornw Exp $ +/* $Id: setup.c,v 1.11 2001/03/02 15:52:03 bjornw Exp $ * * linux/arch/cris/kernel/setup.c * * Copyright (C) 1995 Linus Torvalds - * Copyright (c) 2000 Axis Communications AB + * Copyright (c) 2001 Axis Communications AB */ /* @@ -17,7 +17,7 @@ #include <linux/stddef.h> #include <linux/unistd.h> #include <linux/ptrace.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/user.h> #include <linux/a.out.h> #include <linux/tty.h> @@ -75,7 +75,8 @@ * */ -void __init setup_arch(char **cmdline_p) +void __init +setup_arch(char **cmdline_p) { unsigned long bootmap_size; unsigned long start_pfn, max_pfn; @@ -179,7 +180,7 @@ /* give credit for the CRIS port */ - printk("Linux/CRIS port on ETRAX 100LX (c) 2000 Axis Communications AB\n"); + printk("Linux/CRIS port on ETRAX 100LX (c) 2001 Axis Communications AB\n"); } @@ -192,6 +193,7 @@ #define HAS_ATA 0x0020 #define HAS_USB 0x0040 #define HAS_IRQ_BUG 0x0080 +#define HAS_MMU_BUG 0x0100 static struct cpu_info { char *model; @@ -214,7 +216,8 @@ { "Simulator", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG }, { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, - { "ETRAX 100LX", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU }, + { "ETRAX 100LX", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU | HAS_MMU_BUG }, + { "ETRAX 100LX v2", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU }, { "Unknown", 0, 0 }, }; @@ -241,6 +244,7 @@ "cache size\t: %d kB\n" "fpu\t\t: %s\n" "mmu\t\t: %s\n" + "mmu DMA bug\t: %s\n" "ethernet\t: %s Mbps\n" "token ring\t: %s\n" "scsi\t\t: %s\n" @@ -253,6 +257,7 @@ cpu_info[revision].cache, cpu_info[revision].flags & HAS_FPU ? "yes" : "no", cpu_info[revision].flags & HAS_MMU ? "yes" : "no", + cpu_info[revision].flags & HAS_MMU_BUG ? "yes" : "no", cpu_info[revision].flags & HAS_ETHERNET100 ? "10/100" : "10", cpu_info[revision].flags & HAS_TOKENRING ? "4/16 Mbps" : "no", cpu_info[revision].flags & HAS_SCSI ? "yes" : "no", diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/signal.c linux.ac/arch/cris/kernel/signal.c --- linux.vanilla/arch/cris/kernel/signal.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/kernel/signal.c Tue Apr 10 18:05:25 2001 @@ -38,9 +38,6 @@ #define RESTART_CRIS_SYS(regs) regs->r10 = regs->orig_r10; regs->irp -= 2; -int sys_wait4(pid_t pid, unsigned long *stat_addr, - int options, unsigned long *ru); - int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs); int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) @@ -391,9 +388,9 @@ } else { /* trampoline - the desired return ip is the retcode itself */ return_ip = (unsigned long)&frame->retcode; - /* This is movu.w __NR_sigreturn, r1; break 13; */ + /* This is movu.w __NR_sigreturn, r9; break 13; */ /* TODO: check byteorder */ - err |= __put_user(0x1c5f, (short *)(frame->retcode+0)); + err |= __put_user(0x9c5f, (short *)(frame->retcode+0)); err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+2)); err |= __put_user(0xe93d, (short *)(frame->retcode+4)); } @@ -453,9 +450,9 @@ } else { /* trampoline - the desired return ip is the retcode itself */ return_ip = (unsigned long)&frame->retcode; - /* This is movu.w __NR_sigreturn, r1; break 13; */ + /* This is movu.w __NR_sigreturn, r9; break 13; */ /* TODO: check byteorder */ - err |= __put_user(0x1c5f, (short *)(frame->retcode+0)); + err |= __put_user(0x9c5f, (short *)(frame->retcode+0)); err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+2)); err |= __put_user(0xe93d, (short *)(frame->retcode+4)); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/sys_cris.c linux.ac/arch/cris/kernel/sys_cris.c --- linux.vanilla/arch/cris/kernel/sys_cris.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/cris/kernel/sys_cris.c Tue Apr 10 18:05:25 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_cris.c,v 1.3 2000/08/02 13:59:02 bjornw Exp $ +/* $Id: sys_cris.c,v 1.4 2001/01/31 14:55:58 perf Exp $ * * linux/arch/cris/kernel/sys_etrax.c * @@ -97,10 +97,22 @@ return error; } -asmlinkage unsigned long old_mmap(unsigned long addr, size_t len, int prot, - int flags, int fd, off_t offset) -{ - return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); +asmlinkage unsigned long old_mmap(unsigned long *args) +{ + unsigned long buffer[6]; + int err = -EFAULT; + + if (copy_from_user(&buffer, args, sizeof(buffer))) + goto out; + + err = -EINVAL; + if (buffer[5] & ~PAGE_MASK) /* verify that offset is on page boundary */ + goto out; + + err = do_mmap2(buffer[0], buffer[1], buffer[2], buffer[3], + buffer[4], buffer[5] >> PAGE_SHIFT); +out: + return err; } asmlinkage long diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/traps.c linux.ac/arch/cris/kernel/traps.c --- linux.vanilla/arch/cris/kernel/traps.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/kernel/traps.c Tue Apr 10 18:05:25 2001 @@ -1,16 +1,19 @@ -/* $Id: traps.c,v 1.3 2000/10/04 16:50:06 bjornw Exp $ +/* $Id: traps.c,v 1.8 2001/02/23 13:45:20 bjornw Exp $ * * linux/arch/cris/traps.c * - * Etrax100 does not have any hardware traps, only IRQ's, which we setup - * in irq.c instead. Here we just define the die_if_kernel Oops'er. - * - * Copyright (C) 2000 Axis Communications AB + * Here we handle the break vectors not used by the system call + * mechanism, as well as some general stack/register dumping + * things. + * + * Copyright (C) 2000,2001 Axis Communications AB * * Authors: Bjorn Wesen + * Orjan Friberg * */ +#include <linux/config.h> #include <linux/init.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -35,7 +38,8 @@ #define MODULE_RANGE (8*1024*1024) -void show_stack(unsigned long *sp) +void +show_stack(unsigned long *sp) { unsigned long *stack, addr, module_start, module_end; int i; @@ -86,7 +90,8 @@ #if 0 /* displays a short stack trace */ -int show_stack() +int +show_stack() { unsigned long *sp = (unsigned long *)rdusp(); int i; @@ -97,7 +102,8 @@ } #endif -void show_registers(struct pt_regs * regs) +void +show_registers(struct pt_regs * regs) { unsigned long usp = rdusp(); @@ -145,9 +151,8 @@ #endif } - - -void die_if_kernel(const char * str, struct pt_regs * regs, long err) +void +die_if_kernel(const char * str, struct pt_regs * regs, long err) { if(user_mode(regs)) return; @@ -160,8 +165,68 @@ do_exit(SIGSEGV); } -void __init trap_init(void) +void __init +trap_init(void) { - } + +/* Use static variables instead of the stack for temporary storage. */ +static int saved_r0 = 0; +static int saved_dccr = 0; + +asm (" + .global _gdb_handle_breakpoint + .global _do_sigtrap +_gdb_handle_breakpoint: +;; +;; This handles a break instruction for entering a debug session. +;; + move dccr,[_saved_dccr] ; Save dccr. + move.d r0,[_saved_r0] ; Save r0. " +#ifdef CONFIG_KGDB +" + move ccr,r0 + btstq 8,r0 ; Test the U-flag. + bmi _ugdb_handle_breakpoint ; Go to user mode debugging. + nop ; Delay slot. + move.d [_saved_r0],r0 ; Restore r0. + move [_saved_dccr],dccr ; Restore dccr. + ba _kgdb_handle_breakpoint ; Go to kernel debugging. + nop ; Delay slot. " +#endif +" +_ugdb_handle_breakpoint: +;; +;; Yes, we could do a 'push brp' here and let gdb adjust the pc once it +;; starts talking to the target again, but this way we avoid a 'P' packet. +;; + move brp,r0 ; Use r0 temporarily for calculation. + subq 2,r0 ; Set to address of previous instruction. + move r0,brp ; Restore new brp. + move.d [_saved_r0],r0 ; Restore r0. + move [_saved_dccr],dccr ; Restore dccr. + +_do_sigtrap: +;; +;; SIGTRAP the process that executed the break instruction. +;; Make a frame that Rexit in entry.S expects. +;; + push brp ; Push breakpoint return pointer. + push srp ; Push subroutine return pointer. + push dccr ; Push condition codes. + push mof ; Push multiply overflow reg. + di ; Need to disable irq's at this point. + subq 14*4,sp ; Make room for r0-r13. + movem r13,[sp] ; Push the r0-r13 registers. + push r10 ; Push orig_r10. + clear.d [sp=sp-4] ; Frametype - this is a normal stackframe. + + movs.w -8192,r9 ; THREAD_SIZE == 8192 + and.d sp,r9 + move.d [r9+LTASK_PID],r10 ; current->pid as arg1. + moveq 5,r11 ; SIGTRAP as arg2. + jsr _sys_kill + + jump _ret_from_intr ; Use the return routine for interrupts. +"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/lib/checksum.S linux.ac/arch/cris/lib/checksum.S --- linux.vanilla/arch/cris/lib/checksum.S Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/lib/checksum.S Tue Apr 10 18:05:25 2001 @@ -1,16 +1,21 @@ - ;; $Id: checksum.S,v 1.1 2000/07/10 16:25:21 bjornw Exp $ - ;; A fast checksum routine using movem - ;; Copyright (c) 1998 Bjorn Wesen/Axis Communications AB +/* $Id: checksum.S,v 1.4 2001/02/19 11:11:33 bjornw Exp $ + * A fast checksum routine using movem + * Copyright (c) 1998-2001 Axis Communications AB + * + * csum_partial(const unsigned char * buff, int len, unsigned int sum) + */ - ;; csum_partial(const unsigned char * buff, int len, unsigned int sum) - .globl _csum_partial _csum_partial: + ;; r10 - src + ;; r11 - length + ;; r12 - checksum + ;; check for breakeven length between movem and normal word looping versions cmpu.w 80,r11 - bcs no_movem + blo word_loop nop ;; need to save the registers we use below in the movem loop @@ -21,10 +26,6 @@ ;; do a movem checksum - ;; r10 - src - ;; r11 - length - ;; r12 - checksum - subq 10*4,r11 ; update length for the first loop mloop: movem [r10+],r9 ; read 10 longwords @@ -65,23 +66,30 @@ addq 10*4,r11 ; compensate for last loop underflowing length - ;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below - - moveq -1,r1 ; put 0xffff in r1, faster than move.d 0xffff,r1 - lsrq 16,r1 - - move.d r12,r0 - lsrq 16,r0 ; r0 = checksum >> 16 - and.d r1,r12 ; checksum = checksum & 0xffff - add.d r0,r12 ; checksum += r0 - move.d r12,r0 ; do the same again, maybe we got a carry last add - lsrq 16,r0 - and.d r1,r12 - add.d r0,r12 - movem [sp+],r8 ; restore regs -no_movem: +word_loop: + ;; only fold if there is anything to fold. + + cmpq 0,r12 + beq no_fold + + ;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below. + ;; r9 and r13 can be used as temporaries. + + moveq -1,r9 ; put 0xffff in r9, faster than move.d 0xffff,r9 + lsrq 16,r9 + + move.d r12,r13 + lsrq 16,r13 ; r13 = checksum >> 16 + and.d r9,r12 ; checksum = checksum & 0xffff + add.d r13,r12 ; checksum += r13 + move.d r12,r13 ; do the same again, maybe we got a carry last add + lsrq 16,r13 + and.d r9,r12 + add.d r13,r12 + +no_fold: cmpq 2,r11 blt no_words nop @@ -110,4 +118,3 @@ ret move.d r12, r10 - \ No newline at end of file diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/lib/checksumcopy.S linux.ac/arch/cris/lib/checksumcopy.S --- linux.vanilla/arch/cris/lib/checksumcopy.S Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/lib/checksumcopy.S Tue Apr 10 18:05:25 2001 @@ -1,19 +1,25 @@ - ;; $Id: checksumcopy.S,v 1.2 2000/08/08 16:57:31 bjornw Exp $ - ;; A fast checksum+copy routine using movem - ;; Copyright (c) 1998, 2000 Axis Communications AB - ;; - ;; Authors: Bjorn Wesen - ;; - ;; csum_partial_copy_nocheck(const char *src, char *dst, - ;; int len, unsigned int sum) +/* $Id: checksumcopy.S,v 1.4 2001/02/19 11:11:34 bjornw Exp $ + * A fast checksum+copy routine using movem + * Copyright (c) 1998, 2001 Axis Communications AB + * + * Authors: Bjorn Wesen + * + * csum_partial_copy_nocheck(const char *src, char *dst, + * int len, unsigned int sum) + */ .globl _csum_partial_copy_nocheck _csum_partial_copy_nocheck: + ;; r10 - src + ;; r11 - dst + ;; r12 - length + ;; r13 - checksum + ;; check for breakeven length between movem and normal word looping versions cmpu.w 80,r12 - bcs no_movem + blo word_loop nop ;; need to save the registers we use below in the movem loop @@ -24,11 +30,6 @@ ;; do a movem copy and checksum - ;; r10 - src - ;; r11 - dst - ;; r12 - length - ;; r13 - checksum - subq 10*4,r12 ; update length for the first loop mloop: movem [r10+],r9 ; read 10 longwords @@ -61,6 +62,8 @@ ax addq 0,r13 + ax ; do it again, since we might have generated a carry + addq 0,r13 subq 10*4,r12 bge mloop @@ -68,23 +71,27 @@ addq 10*4,r12 ; compensate for last loop underflowing length + movem [sp+],r8 ; restore regs + +word_loop: + ;; only fold if there is anything to fold. + + cmpq 0,r13 + beq no_fold + ;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below + ;; r9 can be used as temporary. - moveq -1,r1 ; put 0xffff in r1, faster than move.d 0xffff,r1 - lsrq 16,r1 - - move.d r13,r0 - lsrq 16,r0 ; r0 = checksum >> 16 - and.d r1,r13 ; checksum = checksum & 0xffff - add.d r0,r13 ; checksum += r0 - move.d r13,r0 ; do the same again, maybe we got a carry last add - lsrq 16,r0 - and.d r1,r13 - add.d r0,r13 + move.d r13,r9 + lsrq 16,r9 ; r0 = checksum >> 16 + and.d 0xffff,r13 ; checksum = checksum & 0xffff + add.d r9,r13 ; checksum += r0 + move.d r13,r9 ; do the same again, maybe we got a carry last add + lsrq 16,r9 + and.d 0xffff,r13 + add.d r9,r13 - movem [sp+],r8 ; restore regs - -no_movem: +no_fold: cmpq 2,r12 blt no_words nop @@ -117,4 +124,4 @@ ret move.d r13, r10 - \ No newline at end of file + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/lib/dram_init.S linux.ac/arch/cris/lib/dram_init.S --- linux.vanilla/arch/cris/lib/dram_init.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/lib/dram_init.S Tue Apr 10 18:05:25 2001 @@ -0,0 +1,123 @@ + ;; $Id: dram_init.S,v 1.2 2001/02/08 15:20:00 starvik Exp $ + ;; + ;; DRAM/SDRAM initialization - alter with care + ;; This file is intended to be included from other assembler files + ;; + ;; Copyright (C) 2000 Axis Communications AB + ;; + ;; Authors: Mikael Starvik (starvik@axis.com) + ;; Bjorn Wesen (bjornw@axis.com) + ;; + ;; $Log: dram_init.S,v $ + ;; Revision 1.2 2001/02/08 15:20:00 starvik + ;; Corrected SDRAM initialization + ;; Should now be included as inline + ;; + ;; Revision 1.1 2001/01/29 13:08:02 starvik + ;; Initial version + ;; This file should be included from all assembler files that needs to + ;; initialize DRAM/SDRAM. + ;; + ;; + ;; + +#include <linux/config.h> + +#ifndef CONFIG_SVINTO_SIM + move.d DEF_R_WAITSTATES, r0 + move.d r0, [R_WAITSTATES] + + move.d DEF_R_BUS_CONFIG, r0 + move.d r0, [R_BUS_CONFIG] + +#ifndef CONFIG_SDRAM + move.d DEF_R_DRAM_CONFIG, r0 + move.d r0, [R_DRAM_CONFIG] + + move.d DEF_R_DRAM_TIMING, r0 + move.d r0, [R_DRAM_TIMING] +#else + ; Refer to ETRAX 100LX Designers Reference for a description of SDRAM initialization + + ; Bank configuration + move.d DEF_R_SDRAM_CONFIG, r0 + move.d r0, [R_SDRAM_CONFIG] + + ; Calculate value of mrs_data + ; cas_delay = 2 && bus_width = 32 => 0x40 + ; cas_delay = 3 && bus_width = 32 => 0x60 + ; cas_delay = 2 && bus_width = 16 => 0x20 + ; cas_delay = 3 && bus_width = 16 => 0x30 + + move.d 0x40, r2 ; Assume 32 bits and cas_delay = 2 + move.d DEF_R_SDRAM_TIMING, r1 + and.d 0x0c, r1 ; Get cas delay + cmp.d 0x08, r1 ; cas_delay = 2? + beq bw_check + nop + or.d 0x20, r2 ; cas_delay = 3 +bw_check: + move.d DEF_R_SDRAM_CONFIG, r1 + and.d 0x800000, r1 ; DRAM width is bit 23 + bne set_timing + nop + lsrq 1, r2 ; 16 bits. Shift down value. + + ; Set timing parameters. Starts master clock +set_timing: + move.d DEF_R_SDRAM_TIMING, r1 + or.d 0x80000000, r1 ; Make sure sdram enable bit is set + lslq 16, r2 ; mrs data starts at bit 16 + or.d r2, r1 + move.d r1, [R_SDRAM_TIMING] + + ; Wait 200ns + move.d 10, r2 +sdram_loop: + bne sdram_loop + subq 1, r2 + + ; Issue initialization command sequence + move.d sdram_commands_start, r2 + move.d sdram_commands_end, r3 +command_loop: + clear.d r4 + move.b [r2+], r4 + lslq 9, r4 ; Command starts at bit 9 + or.d r1, r4 + move.d r4, [R_SDRAM_TIMING] + nop ; Wait five nop cycles between each command + nop + nop + nop + nop + cmp.d r2, r3 + bne command_loop + nop + ba sdram_commands_end + nop + +sdram_commands_start: + .byte 3 ; Precharge + .byte 0 ; nop + .byte 2 ; refresh + .byte 0 ; nop + .byte 2 ; refresh + .byte 0 ; nop + .byte 2 ; refresh + .byte 0 ; nop + .byte 2 ; refresh + .byte 0 ; nop + .byte 2 ; refresh + .byte 0 ; nop + .byte 2 ; refresh + .byte 0 ; nop + .byte 2 ; refresh + .byte 0 ; nop + .byte 2 ; refresh + .byte 0 ; nop + .byte 1 ; mrs + .byte 0 ; nop +sdram_commands_end: +#endif +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/mm/Makefile linux.ac/arch/cris/mm/Makefile --- linux.vanilla/arch/cris/mm/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/mm/Makefile Tue Apr 10 18:05:25 2001 @@ -8,6 +8,6 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := mm.o -obj-y := init.o fault.o tlb.o extable.o +obj-y := init.o fault.o tlb.o extable.o ioremap.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/mm/fault.c linux.ac/arch/cris/mm/fault.c --- linux.vanilla/arch/cris/mm/fault.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/cris/mm/fault.c Tue Apr 10 18:05:25 2001 @@ -6,6 +6,9 @@ * Authors: Bjorn Wesen * * $Log: fault.c,v $ + * Revision 1.9 2001/03/05 13:22:20 bjornw + * Spell-fix and fix in vmalloc_fault handling + * * Revision 1.8 2000/11/22 14:45:31 bjornw * * 2.4.0-test10 removed the set_pgdir instantaneous kernel global mapping * into all processes. Instead we fill in the missing PTE entries on demand. @@ -301,7 +304,7 @@ /* Are we prepared to handle this kernel fault? * * (The kernel has valid exception-points in the source - * when it acesses user-memory. When it fails in one + * when it accesses user-memory. When it fails in one * of those points, we find it in a table and do a jump * to some fixup code that loads an appropriate error * code) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/mm/init.c linux.ac/arch/cris/mm/init.c --- linux.vanilla/arch/cris/mm/init.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/mm/init.c Tue Apr 10 18:05:25 2001 @@ -2,11 +2,22 @@ * linux/arch/cris/mm/init.c * * Copyright (C) 1995 Linus Torvalds - * Copyright (C) 2000 Axis Communications AB + * Copyright (C) 2000,2001 Axis Communications AB * * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: init.c,v $ + * Revision 1.18 2001/02/23 12:46:44 bjornw + * * 0xc was not CSE1; 0x8 is, same as uncached flash, so we move the uncached + * flash during CRIS_LOW_MAP from 0xe to 0x8 so both the flash and the I/O + * is mapped straight over (for !CRIS_LOW_MAP the uncached flash is still 0xe) + * + * Revision 1.17 2001/02/22 15:05:21 bjornw + * Map 0x9 straight over during LOW_MAP to allow for memory mapped LEDs + * + * Revision 1.16 2001/02/22 15:02:35 bjornw + * Map 0xc straight over during LOW_MAP to allow for memory mapped I/O + * * Revision 1.15 2001/01/10 21:12:10 bjornw * loops_per_sec -> loops_per_jiffy * @@ -57,6 +68,9 @@ #include <asm/pgtable.h> #include <asm/dma.h> #include <asm/svinto.h> +#include <asm/tlb.h> + +mmu_gather_t mmu_gathers[NR_CPUS]; static unsigned long totalram_pages; @@ -287,16 +301,19 @@ * The Juliette chip is mapped at 0xa so we pass that segment straight * through. We cannot vremap it because the vmalloc area is below 0x8 * and Juliette needs an uncached area above 0x8. + * + * Same thing with 0xc and 0x9, which is memory-mapped I/O on some boards. + * We map them straight over in LOW_MAP, but use vremap in LX version 2. */ *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, page ) | - IO_STATE(R_MMU_KSEG, seg_e, seg ) | /* uncached flash */ + IO_STATE(R_MMU_KSEG, seg_e, page ) | IO_STATE(R_MMU_KSEG, seg_d, page ) | - IO_STATE(R_MMU_KSEG, seg_c, page ) | + IO_STATE(R_MMU_KSEG, seg_c, page ) | IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ IO_STATE(R_MMU_KSEG, seg_a, seg ) | /* Juliette etc. */ - IO_STATE(R_MMU_KSEG, seg_9, page ) | - IO_STATE(R_MMU_KSEG, seg_8, page ) | + IO_STATE(R_MMU_KSEG, seg_9, seg ) | /* LED's on some boards */ + IO_STATE(R_MMU_KSEG, seg_8, seg ) | /* CSE0/1, flash and I/O */ IO_STATE(R_MMU_KSEG, seg_7, page ) | /* kernel vmalloc area */ IO_STATE(R_MMU_KSEG, seg_6, seg ) | /* kernel DRAM area */ IO_STATE(R_MMU_KSEG, seg_5, seg ) | /* cached flash */ @@ -307,13 +324,13 @@ IO_STATE(R_MMU_KSEG, seg_0, page ) ); /* user area */ *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) | + IO_FIELD(R_MMU_KBASE_HI, base_e, 0x0 ) | IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | IO_FIELD(R_MMU_KBASE_HI, base_c, 0x0 ) | IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | IO_FIELD(R_MMU_KBASE_HI, base_a, 0xa ) | - IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) ); + IO_FIELD(R_MMU_KBASE_HI, base_9, 0x9 ) | + IO_FIELD(R_MMU_KBASE_HI, base_8, 0x8 ) ); *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | IO_FIELD(R_MMU_KBASE_LO, base_6, 0x4 ) | diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/mm/ioremap.c linux.ac/arch/cris/mm/ioremap.c --- linux.vanilla/arch/cris/mm/ioremap.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/mm/ioremap.c Tue Apr 10 18:05:25 2001 @@ -0,0 +1,164 @@ +/* + * arch/cris/mm/ioremap.c + * + * Re-map IO memory to kernel address space so that we can access it. + * Needed for memory-mapped I/O devices mapped outside our normal DRAM + * window (that is, all memory-mapped I/O devices). + * + * (C) Copyright 1995 1996 Linus Torvalds + * CRIS-port by Axis Communications AB + */ + +#include <linux/vmalloc.h> +#include <asm/io.h> +#include <asm/pgalloc.h> + +static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, + unsigned long phys_addr, unsigned long flags) +{ + unsigned long end; + + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + if (address >= end) + BUG(); + do { + if (!pte_none(*pte)) { + printk("remap_area_pte: page already exists\n"); + BUG(); + } + set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT | __READABLE | + __WRITEABLE | _PAGE_GLOBAL | + _PAGE_KERNEL | flags))); + address += PAGE_SIZE; + phys_addr += PAGE_SIZE; + pte++; + } while (address && (address < end)); +} + +static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, + unsigned long phys_addr, unsigned long flags) +{ + unsigned long end; + + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + phys_addr -= address; + if (address >= end) + BUG(); + do { + pte_t * pte = pte_alloc_kernel(pmd, address); + if (!pte) + return -ENOMEM; + remap_area_pte(pte, address, end - address, address + phys_addr, flags); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address && (address < end)); + return 0; +} + +static int remap_area_pages(unsigned long address, unsigned long phys_addr, + unsigned long size, unsigned long flags) +{ + pgd_t * dir; + unsigned long end = address + size; + + phys_addr -= address; + dir = pgd_offset(&init_mm, address); + flush_cache_all(); + if (address >= end) + BUG(); + do { + pmd_t *pmd; + pmd = pmd_alloc_kernel(dir, address); + if (!pmd) + return -ENOMEM; + if (remap_area_pmd(pmd, address, end - address, + phys_addr + address, flags)) + return -ENOMEM; + address = (address + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } while (address && (address < end)); + flush_tlb_all(); + return 0; +} + +/* + * Generic mapping function (not visible outside): + */ + +/* + * Remap an arbitrary physical address space into the kernel virtual + * address space. Needed when the kernel wants to access high addresses + * directly. + * + * NOTE! We need to allow non-page-aligned mappings too: we will obviously + * have to convert them into an offset in a page-aligned mapping, but the + * caller shouldn't need to know that small detail. + */ +void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) +{ + void * addr; + struct vm_struct * area; + 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; + +#if 0 + /* TODO: Here we can put checks for driver-writer abuse... */ + + /* + * Don't remap the low PCI/ISA area, it's always mapped.. + */ + if (phys_addr >= 0xA0000 && last_addr < 0x100000) + return phys_to_virt(phys_addr); + + /* + * Don't allow anybody to remap normal RAM that we're using.. + */ + if (phys_addr < virt_to_phys(high_memory)) { + char *t_addr, *t_end; + struct page *page; + + t_addr = __va(phys_addr); + t_end = t_addr + (size - 1); + + for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++) + if(!PageReserved(page)) + return NULL; + } +#endif + + /* + * Mappings have to be page-aligned + */ + offset = phys_addr & ~PAGE_MASK; + phys_addr &= PAGE_MASK; + size = PAGE_ALIGN(last_addr) - phys_addr; + + /* + * Ok, go for it.. + */ + area = get_vm_area(size, VM_IOREMAP); + if (!area) + return NULL; + addr = area->addr; + if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) { + vfree(addr); + return NULL; + } + return (void *) (offset + (char *)addr); +} + +void iounmap(void *addr) +{ + if (addr > high_memory) + return vfree((void *) (PAGE_MASK & (unsigned long) addr)); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/Makefile linux.ac/arch/i386/Makefile --- linux.vanilla/arch/i386/Makefile Wed Jan 10 23:06:14 2001 +++ linux.ac/arch/i386/Makefile Sat Apr 14 02:08:52 2001 @@ -82,6 +82,10 @@ CFLAGS += -march=i586 endif +ifdef CONFIG_MCYRIXIII +CFLAGS += -march=i586 +endif + HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o SUBDIRS += arch/i386/kernel arch/i386/mm arch/i386/lib diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/boot/install.sh linux.ac/arch/i386/boot/install.sh --- linux.vanilla/arch/i386/boot/install.sh Tue Jan 3 11:57:26 1995 +++ linux.ac/arch/i386/boot/install.sh Tue Apr 3 17:54:29 2001 @@ -21,6 +21,7 @@ # User may have a custom install script +if [ -x ~/bin/installkernel ]; then exec ~/bin/installkernel "$@"; fi if [ -x /sbin/installkernel ]; then exec /sbin/installkernel "$@"; fi # Default install - same as make zlilo diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/boot/setup.S linux.ac/arch/i386/boot/setup.S --- linux.vanilla/arch/i386/boot/setup.S Sat Jan 27 18:51:35 2001 +++ linux.ac/arch/i386/boot/setup.S Thu Apr 12 11:48:59 2001 @@ -18,7 +18,7 @@ * March 1993/June 1994 (Christoph.Niemann@linux.org) * * add APM BIOS checking by Stephen Rothwell, May 1994 - * (Stephen.Rothwell@canb.auug.org.au) + * (sfr@canb.auug.org.au) * * High load stuff, initrd support and position independency * by Hans Lermen & Werner Almesberger, February 1996 @@ -81,14 +81,9 @@ type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin, # Bootlin, SYSLX, bootsect...) - # Else it is set by the loader: - # 0xTV: T=0 for LILO - # T=1 for Loadlin - # T=2 for bootsect-loader - # T=3 for SYSLX - # T=4 for ETHERBOOT - # V = version - + # See Documentation/i386/boot.txt for + # assigned ids + # flags, unused bits must be zero (RFU) bit within loadflags loadflags: LOADED_HIGH = 1 # If set, the kernel is loaded high @@ -228,8 +223,8 @@ # Move rest of setup code/data to here movw $2048, %di # four sectors loaded by LILO subw %si, %si - movw %cs, %ax # aka SETUPSEG - movw %ax, %es + pushw %cs + popw %es movw $SYSSEG, %ax movw %ax, %ds rep diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/config.in linux.ac/arch/i386/config.in --- linux.vanilla/arch/i386/config.in Mon Jan 8 21:27:56 2001 +++ linux.ac/arch/i386/config.in Tue Apr 17 16:37:18 2001 @@ -36,22 +36,25 @@ Pentium-III CONFIG_MPENTIUMIII \ Pentium-4 CONFIG_MPENTIUM4 \ K6/K6-II/K6-III CONFIG_MK6 \ - Athlon/K7 CONFIG_MK7 \ + Athlon/Duron/K7 CONFIG_MK7 \ Crusoe CONFIG_MCRUSOE \ Winchip-C6 CONFIG_MWINCHIPC6 \ Winchip-2 CONFIG_MWINCHIP2 \ - Winchip-2A/Winchip-3 CONFIG_MWINCHIP3D" Pentium-Pro + Winchip-2A/Winchip-3 CONFIG_MWINCHIP3D \ + CyrixIII/C3 CONFIG_MCYRIXIII" Pentium-Pro # # Define implied options from the CPU selection here # if [ "$CONFIG_M386" = "y" ]; then define_bool CONFIG_X86_CMPXCHG n + define_bool CONFIG_X86_XADD n define_int CONFIG_X86_L1_CACHE_SHIFT 4 else define_bool CONFIG_X86_WP_WORKS_OK y define_bool CONFIG_X86_INVLPG y define_bool CONFIG_X86_CMPXCHG y + define_bool CONFIG_X86_XADD y define_bool CONFIG_X86_BSWAP y define_bool CONFIG_X86_POPAD_OK y fi @@ -113,6 +116,13 @@ define_bool CONFIG_X86_PGE y define_bool CONFIG_X86_USE_PPRO_CHECKSUM y fi +if [ "$CONFIG_MCYRIXIII" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_SHIFT 5 + define_bool CONFIG_X86_TSC y + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_USE_3DNOW y + define_bool CONFIG_X86_USE_PPRO_CHECKSUM y +fi if [ "$CONFIG_MCRUSOE" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 5 define_bool CONFIG_X86_TSC y @@ -121,18 +131,21 @@ define_int CONFIG_X86_L1_CACHE_SHIFT 5 define_bool CONFIG_X86_ALIGNMENT_16 y define_bool CONFIG_X86_USE_PPRO_CHECKSUM y + define_bool CONFIG_X86_OOSTORE y fi if [ "$CONFIG_MWINCHIP2" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 5 define_bool CONFIG_X86_ALIGNMENT_16 y define_bool CONFIG_X86_TSC y define_bool CONFIG_X86_USE_PPRO_CHECKSUM y + define_bool CONFIG_X86_OOSTORE y fi if [ "$CONFIG_MWINCHIP3D" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 5 define_bool CONFIG_X86_ALIGNMENT_16 y define_bool CONFIG_X86_TSC y define_bool CONFIG_X86_USE_PPRO_CHECKSUM y + define_bool CONFIG_X86_OOSTORE y fi tristate 'Toshiba Laptop support' CONFIG_TOSHIBA @@ -156,10 +169,13 @@ bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR bool 'Symmetric multi-processing support' CONFIG_SMP if [ "$CONFIG_SMP" != "y" ]; then - bool 'APIC and IO-APIC support on uniprocessors' CONFIG_X86_UP_IOAPIC + bool 'APIC support on uniprocessors' CONFIG_X86_UP_APIC + dep_bool 'IO-APIC support on uniprocessors' CONFIG_X86_UP_IOAPIC $CONFIG_X86_UP_APIC + if [ "$CONFIG_X86_UP_APIC" = "y" ]; then + define_bool CONFIG_X86_LOCAL_APIC y + fi if [ "$CONFIG_X86_UP_IOAPIC" = "y" ]; then define_bool CONFIG_X86_IO_APIC y - define_bool CONFIG_X86_LOCAL_APIC y fi fi @@ -285,9 +301,11 @@ fi endmenu +source drivers/message/fusion/Config.in + source drivers/ieee1394/Config.in -source drivers/i2o/Config.in +source drivers/message/i2o/Config.in if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment @@ -364,6 +382,16 @@ mainmenu_option next_comment comment 'Kernel hacking' -#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC -bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +bool 'Kernel debugging' CONFIG_DEBUG_KERNEL + +if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then + + +bool ' Debug memory allocations' CONFIG_DEBUG_SLAB +bool ' Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT +bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ +bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK +bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE +fi + endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/defconfig linux.ac/arch/i386/defconfig --- linux.vanilla/arch/i386/defconfig Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/i386/defconfig Tue Apr 17 16:00:46 2001 @@ -35,9 +35,11 @@ # CONFIG_MWINCHIPC6 is not set # CONFIG_MWINCHIP2 is not set # CONFIG_MWINCHIP3D is not set +# CONFIG_MCYRIXIII is not set CONFIG_X86_WP_WORKS_OK=y CONFIG_X86_INVLPG=y CONFIG_X86_CMPXCHG=y +CONFIG_X86_XADD=y CONFIG_X86_BSWAP=y CONFIG_X86_POPAD_OK=y CONFIG_X86_L1_CACHE_SHIFT=5 @@ -108,6 +110,7 @@ # CONFIG_PNP=y CONFIG_ISAPNP=y +CONFIG_PNPBIOS=y # # Block devices @@ -383,6 +386,9 @@ # CONFIG_NE3210 is not set # CONFIG_ES3210 is not set # CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set @@ -561,6 +567,7 @@ # CONFIG_EFS_FS is not set # CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set +CONFIG_TMPFS=y # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set @@ -720,4 +727,5 @@ # # Kernel hacking # +CONFIG_DEBUG_IOVIRT=y # CONFIG_MAGIC_SYSRQ is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/Makefile linux.ac/arch/i386/kernel/Makefile --- linux.vanilla/arch/i386/kernel/Makefile Fri Dec 29 22:35:47 2000 +++ linux.ac/arch/i386/kernel/Makefile Tue Apr 3 17:54:29 2001 @@ -30,15 +30,20 @@ endif endif -obj-$(CONFIG_MCA) += mca.o -obj-$(CONFIG_MTRR) += mtrr.o -obj-$(CONFIG_X86_MSR) += msr.o -obj-$(CONFIG_X86_CPUID) += cpuid.o -obj-$(CONFIG_MICROCODE) += microcode.o -obj-$(CONFIG_APM) += apm.o -obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o -obj-$(CONFIG_X86_LOCAL_APIC) += apic.o -obj-$(CONFIG_X86_IO_APIC) += io_apic.o mpparse.o +obj-$(CONFIG_MCA) += mca.o +obj-$(CONFIG_MTRR) += mtrr.o +obj-$(CONFIG_X86_MSR) += msr.o +obj-$(CONFIG_X86_CPUID) += cpuid.o +obj-$(CONFIG_MICROCODE) += microcode.o +obj-$(CONFIG_APM) += apm.o +obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o +obj-$(CONFIG_X86_LOCAL_APIC) += mpparse.o apic.o nmi.o +obj-$(CONFIG_X86_IO_APIC) += io_apic.o obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o + +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/apic.c linux.ac/arch/i386/kernel/apic.c --- linux.vanilla/arch/i386/kernel/apic.c Tue Dec 5 20:43:48 2000 +++ linux.ac/arch/i386/kernel/apic.c Tue Apr 3 17:54:30 2001 @@ -9,6 +9,7 @@ * and Rolf G. Tews * for testing these extensively. * Maciej W. Rozycki : Various updates and fixes. + * Mikael Pettersson : Power Management for UP-APIC. */ #include <linux/config.h> @@ -23,11 +24,15 @@ #include <linux/mc146818rtc.h> #include <linux/kernel_stat.h> +#include <asm/atomic.h> #include <asm/smp.h> #include <asm/mtrr.h> #include <asm/mpspec.h> #include <asm/pgalloc.h> +/* Using APIC to generate smp_local_timer_interrupt? */ +int using_apic_timer = 0; + int prof_multiplier[NR_CPUS] = { 1, }; int prof_old_multiplier[NR_CPUS] = { 1, }; int prof_counter[NR_CPUS] = { 1, }; @@ -89,10 +94,10 @@ */ clear_local_APIC(); /* - * PIC mode, enable symmetric IO mode in the IMCR, - * i.e. connect BSP's local APIC to INT and NMI lines. + * PIC mode, enable APIC mode in the IMCR, i.e. + * connect BSP's local APIC to INT and NMI lines. */ - printk("leaving PIC mode, enabling symmetric IO mode.\n"); + printk("leaving PIC mode, enabling APIC mode.\n"); outb(0x70, 0x22); outb(0x01, 0x23); } @@ -107,7 +112,7 @@ * interrupts, including IPIs, won't work beyond * this point! The only exception are INIT IPIs. */ - printk("disabling symmetric IO mode, entering PIC mode.\n"); + printk("disabling APIC mode, entering PIC mode.\n"); outb(0x70, 0x22); outb(0x00, 0x23); } @@ -124,7 +129,7 @@ * for 82489DX!). */ value = apic_read(APIC_SPIV); - value &= ~(1<<8); + value &= ~APIC_SPIV_APIC_ENABLED; apic_write_around(APIC_SPIV, value); } @@ -203,6 +208,48 @@ extern void __error_in_apic_c (void); +/* + * An initial setup of the virtual wire mode. + */ +void __init init_bsp_APIC(void) +{ + unsigned long value, ver; + + /* + * Don't do the setup now if we have a SMP BIOS as the + * through-I/O-APIC virtual wire mode might be active. + */ + if (smp_found_config || !cpu_has_apic) + return; + + value = apic_read(APIC_LVR); + ver = GET_APIC_VERSION(value); + + /* + * Do not trust the local APIC being empty at bootup. + */ + clear_local_APIC(); + + /* + * Enable APIC. + */ + value = apic_read(APIC_SPIV); + value &= ~APIC_VECTOR_MASK; + value |= APIC_SPIV_APIC_ENABLED; + value |= APIC_SPIV_FOCUS_DISABLED; + value |= SPURIOUS_APIC_VECTOR; + apic_write_around(APIC_SPIV, value); + + /* + * Set up the virtual wire mode. + */ + apic_write_around(APIC_LVT0, APIC_DM_EXTINT); + value = APIC_DM_NMI; + if (!APIC_INTEGRATED(ver)) /* 82489DX */ + value |= APIC_LVT_LEVEL_TRIGGER; + apic_write_around(APIC_LVT1, value); +} + void __init setup_local_APIC (void) { unsigned long value, ver, maxlvt; @@ -255,7 +302,7 @@ /* * Enable APIC */ - value |= (1<<8); + value |= APIC_SPIV_APIC_ENABLED; /* * Some unknown Intel IO/APIC (or APIC) errata is biting us with @@ -270,12 +317,18 @@ * PCI Ne2000 networking cards and PII/PIII processors, dual * BX chipset. ] */ -#if 0 + /* + * Actually disabling the focus CPU check just makes the hang less + * frequent as it makes the interrupt distributon model be more + * like LRU than MRU (the short-term load is more even across CPUs). + * See also the comment in end_level_ioapic_irq(). --macro + */ +#if 1 /* Enable focus processor (bit==0) */ - value &= ~(1<<9); + value &= ~APIC_SPIV_FOCUS_DISABLED; #else /* Disable focus processor (bit==1) */ - value |= (1<<9); + value |= APIC_SPIV_FOCUS_DISABLED; #endif /* * Set spurious IRQ vector @@ -332,24 +385,250 @@ printk("ESR value after enabling vector: %08lx\n", value); } else printk("No ESR for 82489DX.\n"); + + if (nmi_watchdog == NMI_LOCAL_APIC) + setup_apic_nmi_watchdog(); } -void __init init_apic_mappings(void) +#ifdef CONFIG_PM + +#include <linux/slab.h> +#include <linux/pm.h> + +static struct { + /* 'active' is true if the local APIC was enabled by us and + not the BIOS; this signifies that we are also responsible + for disabling it before entering apm/acpi suspend */ + int active; + /* 'perfctr_pmdev' is here because the current (2.4.1) PM + callback system doesn't handle hierarchical dependencies */ + struct pm_dev *perfctr_pmdev; + /* r/w apic fields */ + unsigned int apic_id; + unsigned int apic_taskpri; + unsigned int apic_ldr; + unsigned int apic_dfr; + unsigned int apic_spiv; + unsigned int apic_lvtt; + unsigned int apic_lvtpc; + unsigned int apic_lvt0; + unsigned int apic_lvt1; + unsigned int apic_lvterr; + unsigned int apic_tmict; + unsigned int apic_tdcr; +} apic_pm_state; + +static void apic_pm_suspend(void *data) { - unsigned long apic_phys; + unsigned int l, h; + unsigned long flags; - if (smp_found_config) { - apic_phys = mp_lapic_addr; - } else { + if (apic_pm_state.perfctr_pmdev) + pm_send(apic_pm_state.perfctr_pmdev, PM_SUSPEND, data); + apic_pm_state.apic_id = apic_read(APIC_ID); + apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI); + apic_pm_state.apic_ldr = apic_read(APIC_LDR); + apic_pm_state.apic_dfr = apic_read(APIC_DFR); + apic_pm_state.apic_spiv = apic_read(APIC_SPIV); + apic_pm_state.apic_lvtt = apic_read(APIC_LVTT); + apic_pm_state.apic_lvtpc = apic_read(APIC_LVTPC); + apic_pm_state.apic_lvt0 = apic_read(APIC_LVT0); + apic_pm_state.apic_lvt1 = apic_read(APIC_LVT1); + apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR); + apic_pm_state.apic_tmict = apic_read(APIC_TMICT); + apic_pm_state.apic_tdcr = apic_read(APIC_TDCR); + __save_flags(flags); + __cli(); + disable_local_APIC(); + rdmsr(MSR_IA32_APICBASE, l, h); + l &= ~MSR_IA32_APICBASE_ENABLE; + wrmsr(MSR_IA32_APICBASE, l, h); + __restore_flags(flags); +} + +static void apic_pm_resume(void *data) +{ + unsigned int l, h; + unsigned long flags; + + __save_flags(flags); + __cli(); + rdmsr(MSR_IA32_APICBASE, l, h); + l &= ~MSR_IA32_APICBASE_BASE; + l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; + wrmsr(MSR_IA32_APICBASE, l, h); + apic_write(APIC_ID, apic_pm_state.apic_id); + apic_write(APIC_DFR, apic_pm_state.apic_dfr); + apic_write(APIC_LDR, apic_pm_state.apic_ldr); + apic_write(APIC_TASKPRI, apic_pm_state.apic_taskpri); + apic_write(APIC_SPIV, apic_pm_state.apic_spiv); + apic_write(APIC_LVT0, apic_pm_state.apic_lvt0); + apic_write(APIC_LVT1, apic_pm_state.apic_lvt1); + apic_write(APIC_ESR, 0); + apic_read(APIC_ESR); + apic_write(APIC_LVTERR, apic_pm_state.apic_lvterr); + apic_write(APIC_ESR, 0); + apic_read(APIC_ESR); + apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc); + apic_write(APIC_LVTT, apic_pm_state.apic_lvtt); + apic_write(APIC_TDCR, apic_pm_state.apic_tdcr); + apic_write(APIC_TMICT, apic_pm_state.apic_tmict); + __restore_flags(flags); + if (apic_pm_state.perfctr_pmdev) + pm_send(apic_pm_state.perfctr_pmdev, PM_RESUME, data); +} + +static int apic_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + switch (rqst) { + case PM_SUSPEND: + apic_pm_suspend(data); + break; + case PM_RESUME: + apic_pm_resume(data); + break; + } + return 0; +} + +/* perfctr driver should call this instead of pm_register() */ +struct pm_dev *apic_pm_register(pm_dev_t type, + unsigned long id, + pm_callback callback) +{ + struct pm_dev *dev; + + if (!apic_pm_state.active) + return pm_register(type, id, callback); + if (apic_pm_state.perfctr_pmdev) + return NULL; /* we're busy */ + dev = kmalloc(sizeof(struct pm_dev), GFP_KERNEL); + if (dev) { + memset(dev, 0, sizeof(*dev)); + dev->type = type; + dev->id = id; + dev->callback = callback; + apic_pm_state.perfctr_pmdev = dev; + } + return dev; +} + +/* perfctr driver should call this instead of pm_unregister() */ +void apic_pm_unregister(struct pm_dev *dev) +{ + if (!apic_pm_state.active) { + pm_unregister(dev); + } else if (dev == apic_pm_state.perfctr_pmdev) { + apic_pm_state.perfctr_pmdev = NULL; + kfree(dev); + } +} + +static void __init apic_pm_init1(void) +{ + /* can't pm_register() at this early stage in the boot process + (causes an immediate reboot), so just set the flag */ + apic_pm_state.active = 1; +} + +static void __init apic_pm_init2(void) +{ + if (apic_pm_state.active) + pm_register(PM_SYS_DEV, 0, apic_pm_callback); +} + +#else /* CONFIG_PM */ + +static inline void apic_pm_init1(void) { } +static inline void apic_pm_init2(void) { } + +#endif /* CONFIG_PM */ + +/* + * Detect and enable local APICs on non-SMP boards. + * Original code written by Keir Fraser. + */ + +static int __init detect_init_APIC (void) +{ + u32 h, l, features; + int needs_pm = 0; + extern void get_cpu_vendor(struct cpuinfo_x86*); + + /* Workaround for us being called before identify_cpu(). */ + get_cpu_vendor(&boot_cpu_data); + + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model > 1) + break; + goto no_apic; + case X86_VENDOR_INTEL: + if (boot_cpu_data.x86 == 6 || + (boot_cpu_data.x86 == 5 && cpu_has_apic)) + break; + goto no_apic; + default: + goto no_apic; + } + + if (!cpu_has_apic) { /* - * set up a fake all zeroes page to simulate the - * local APIC and another one for the IO-APIC. We - * could use the real zero-page, but it's safer - * this way if some buggy code writes to this page ... + * Some BIOSes disable the local APIC in the + * APIC_BASE MSR. This can only be done in + * software for Intel P6 and AMD K7 (Model > 1). */ + rdmsr(MSR_IA32_APICBASE, l, h); + if (!(l & MSR_IA32_APICBASE_ENABLE)) { + printk("Local APIC disabled by BIOS -- reenabling.\n"); + l &= ~MSR_IA32_APICBASE_BASE; + l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; + wrmsr(MSR_IA32_APICBASE, l, h); + needs_pm = 1; + } + } + /* + * The APIC feature bit should now be enabled + * in `cpuid' + */ + features = cpuid_edx(1); + if (!(features & (1 << X86_FEATURE_APIC))) { + printk("Could not enable APIC!\n"); + return -1; + } + set_bit(X86_FEATURE_APIC, &boot_cpu_data.x86_capability); + mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; + boot_cpu_id = 0; + if (nmi_watchdog != NMI_NONE) + nmi_watchdog = NMI_LOCAL_APIC; + + printk("Found and enabled local APIC!\n"); + + if (needs_pm) + apic_pm_init1(); + + return 0; + +no_apic: + printk("No local APIC present or hardware disabled\n"); + return -1; +} + +void __init init_apic_mappings(void) +{ + unsigned long apic_phys; + + /* + * If no local APIC can be found then set up a fake all + * zeroes page to simulate the local APIC and another + * one for the IO-APIC. + */ + if (!smp_found_config && detect_init_APIC()) { apic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE); apic_phys = __pa(apic_phys); - } + } else + apic_phys = mp_lapic_addr; + set_fixmap_nocache(FIX_APIC_BASE, apic_phys); Dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys); @@ -596,6 +875,9 @@ void __init setup_APIC_clocks (void) { + printk("Using local APIC timer interrupts.\n"); + using_apic_timer = 1; + __cli(); calibration_result = calibrate_APIC_clock(); @@ -764,7 +1046,7 @@ apic_write(APIC_ESR, 0); v1 = apic_read(APIC_ESR); ack_APIC_irq(); - irq_err_count++; + atomic_inc(&irq_err_count); /* Here is what the APIC error bits mean: 0: Send CS error @@ -780,3 +1062,43 @@ smp_processor_id(), v , v1); } +/* + * This initializes the IO-APIC and APIC hardware if this is + * a UP kernel. + */ +int __init APIC_init_uniprocessor (void) +{ + if (!smp_found_config && !cpu_has_apic) + return -1; + + /* + * Complain if the BIOS pretends there is one. + */ + if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_id])) { + printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", + boot_cpu_id); + return -1; + } + + verify_local_APIC(); + + connect_bsp_APIC(); + + phys_cpu_present_map = 1; + apic_write_around(APIC_ID, boot_cpu_id); + + apic_pm_init2(); + + setup_local_APIC(); + + if (nmi_watchdog == NMI_LOCAL_APIC) + check_nmi_watchdog(); +#ifdef CONFIG_X86_IO_APIC + if (smp_found_config) + if (!skip_ioapic_setup && nr_ioapics) + setup_IO_APIC(); +#endif + setup_APIC_clocks(); + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/apm.c linux.ac/arch/i386/kernel/apm.c --- linux.vanilla/arch/i386/kernel/apm.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/i386/kernel/apm.c Tue Apr 17 15:46:40 2001 @@ -1,6 +1,6 @@ /* -*- linux-c -*- * APM BIOS driver for Linux - * Copyright 1994-2000 Stephen Rothwell (sfr@linuxcare.com) + * Copyright 1994-2001 Stephen Rothwell (sfr@canb.auug.org.au) * * Initial development of this driver was funded by NEC Australia P/L * and NEC Corporation @@ -23,7 +23,7 @@ * March 1996, Rik Faith (faith@cs.unc.edu): * Prohibit APM BIOS calls unless apm_enabled. * (Thanks to Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de>) - * April 1996, Stephen Rothwell (Stephen.Rothwell@canb.auug.org.au) + * April 1996, Stephen Rothwell (sfr@canb.auug.org.au) * Version 1.0 and 1.1 * May 1996, Version 1.2 * Feb 1998, Version 1.3 @@ -119,7 +119,7 @@ * Make power off under SMP work again. * Fix thinko with initial engaging of BIOS. * Make sure power off only happens on CPU 0 - * (Paul "Rusty" Russell <rusty@linuxcare.com>). + * (Paul "Rusty" Russell <rusty@rustcorp.com.au>). * Do error notification to user mode if BIOS calls fail. * Move entrypoint offset fix to ...boot/setup.S * where it belongs (Cosmos <gis88564@cis.nctu.edu.tw>). @@ -166,6 +166,11 @@ * * [This document is available from Microsoft at: * http://www.microsoft.com/hwdev/busbios/amp_12.htm] + * + * (c) 2000 Crutcher Dunnavant <crutcher@redhat.com> + * changed to use the sysrq-register hack for registering + * the power off function called by magic sysrq + * based upon discusions in irc://irc.openprojects.net/#kernelnewbies */ #include <linux/config.h> @@ -191,12 +196,11 @@ #include <asm/uaccess.h> #include <asm/desc.h> +#include <linux/sysrq.h> + extern unsigned long get_cmos_time(void); extern void machine_real_restart(unsigned char *, int); -#ifdef CONFIG_MAGIC_SYSRQ -extern void (*sysrq_power_off)(void); -#endif #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) extern int (*console_blank_hook)(int); #endif @@ -227,6 +231,8 @@ * P: Toshiba 1950S: battery life information only gets updated after resume * P: Midwest Micro Soundbook Elite DX2/66 monochrome: screen blanking * broken in BIOS [Reported by Garst R. Reese <reese@isn.net>] + * ?: AcerNote-950: oops on reading /proc/apm - workaround is a WIP + * Neale Banks <neale@lowendale.com.au> December 2000 * * Legend: U = unusable with APM patches * P = partially usable with APM patches @@ -669,6 +675,23 @@ #endif } +#ifdef CONFIG_MAGIC_SYSRQ +/* + * Magic sysrq key and handler for the power off function + */ + +void handle_poweroff (int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) { + apm_power_off(); +} +struct sysrq_key_op sysrq_poweroff_op = { + handler: handle_poweroff, + help_msg: "Off", + action_msg: "Power Off\n" +}; +#endif + + #ifdef CONFIG_APM_DO_ENABLE static int apm_enable_power_management(int enable) { @@ -1523,9 +1546,8 @@ /* Install our power off handler.. */ if (power_off) pm_power_off = apm_power_off; -#ifdef CONFIG_MAGIC_SYSRQ - sysrq_power_off = apm_power_off; -#endif + register_sysrq_key('o',&sysrq_poweroff_op); + if (smp_num_cpus == 1) { #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) console_blank_hook = apm_console_blank; @@ -1550,6 +1572,9 @@ apm_disabled = 1; if (strncmp(str, "on", 2) == 0) apm_disabled = 0; + if ((strncmp(str, "broken-psr", 10) == 0) || + (strncmp(str, "broken_psr", 10) == 0)) + apm_info.get_power_status_broken = 1; invert = (strncmp(str, "no-", 3) == 0); if (invert) str += 3; @@ -1720,9 +1745,7 @@ } misc_deregister(&apm_device); remove_proc_entry("apm", NULL); -#ifdef CONFIG_MAGIC_SYSRQ - sysrq_power_off = NULL; -#endif + unregister_sysrq_key('o',&sysrq_poweroff_op); if (power_off) pm_power_off = NULL; exit_kapmd = 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/bluesmoke.c linux.ac/arch/i386/kernel/bluesmoke.c --- linux.vanilla/arch/i386/kernel/bluesmoke.c Fri Dec 29 22:07:20 2000 +++ linux.ac/arch/i386/kernel/bluesmoke.c Sat Apr 14 19:23:52 2001 @@ -1,6 +1,3 @@ -/* - * Machine Check Handler For PII/PIII - */ #include <linux/types.h> #include <linux/kernel.h> @@ -8,9 +5,13 @@ #include <asm/processor.h> #include <asm/msr.h> +/* + * Machine Check Handler For PII/PIII + */ + static int banks; -void do_machine_check(struct pt_regs * regs, long error_code) +static void intel_machine_check(struct pt_regs * regs, long error_code) { int recover=1; u32 alow, ahigh, high, low; @@ -45,6 +46,7 @@ printk(" at %08x%08x", high, low); } + printk("\n"); /* Clear it */ wrmsr(0x401+i*4, 0UL, 0UL); /* Serialize */ @@ -61,28 +63,101 @@ wrmsr(0x17a,mcgstl, mcgsth); } +/* + * Machine check handler for Pentium class Intel + */ + +static void pentium_machine_check(struct pt_regs * regs, long error_code) +{ + u32 loaddr, hi, lotype; + rdmsr(0x0, loaddr, hi); + rdmsr(0x1, lotype, hi); + printk(KERN_EMERG "CPU#%d: Machine Check Exception: 0x%8X (type 0x%8X).\n", smp_processor_id(), loaddr, lotype); + if(lotype&(1<<5)) + printk(KERN_EMERG "CPU#%d: Possible thermal failure (CPU on fire ?).\n", smp_processor_id()); +} /* - * This has to be run for each processor + * Machine check handler for WinChip C6 */ -void mcheck_init(struct cpuinfo_x86 *c) +static void winchip_machine_check(struct pt_regs * regs, long error_code) +{ + printk(KERN_EMERG "CPU#%d: Machine Check Exception.\n", smp_processor_id()); +} + +/* + * Handle unconfigured int18 (should never happen) + */ + +static void unexpected_machine_check(struct pt_regs * regs, long error_code) +{ + printk(KERN_ERR "CPU#%d: Unexpected int18 (Machine Check).\n", smp_processor_id()); +} + +/* + * Call the installed machine check handler for this CPU setup. + */ + +static void (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check; + +void do_machine_check(struct pt_regs * regs, long error_code) +{ + machine_check_vector(regs, error_code); +} + +/* + * Set up machine check reporting for Intel processors + */ + +void intel_mcheck_init(struct cpuinfo_x86 *c) { u32 l, h; int i; static int done; - - if( c->x86_vendor != X86_VENDOR_INTEL ) - return; + /* + * Check for MCE support + */ + if( !test_bit(X86_FEATURE_MCE, &c->x86_capability) ) + return; + + /* + * Pentium machine check + */ + + if(c->x86 == 5) + { + machine_check_vector = pentium_machine_check; + wmb(); + /* Read registers before enabling */ + rdmsr(0x0, l, h); + rdmsr(0x1, l, h); + if(done==0) + printk(KERN_INFO "Intel old style machine check architecture supported.\n"); + /* Enable MCE */ + __asm__ __volatile__ ( + "movl %%cr4, %%eax\n\t" + "orl $0x40, %%eax\n\t" + "movl %%eax, %%cr4\n\t" : : : "eax"); + printk(KERN_INFO "Intel old style machine check reporting enabled on CPU#%d.\n", smp_processor_id()); return; - + } + + + /* + * Check for PPro style MCA + */ + if( !test_bit(X86_FEATURE_MCA, &c->x86_capability) ) return; /* Ok machine check is available */ + machine_check_vector = intel_machine_check; + wmb(); + if(done==0) printk(KERN_INFO "Intel machine check architecture supported.\n"); rdmsr(0x179, l, h); @@ -103,4 +178,46 @@ "movl %%eax, %%cr4\n\t" : : : "eax"); printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n", smp_processor_id()); done=1; +} + +/* + * Set up machine check reporting on the Winchip C6 series + */ + +static void winchip_mcheck_init(struct cpuinfo_x86 *c) +{ + u32 lo, hi; + /* Not supported on C3 */ + if(c->x86 != 5) + return; + /* Winchip C6 */ + machine_check_vector = winchip_machine_check; + wmb(); + rdmsr(0x107, lo, hi); + lo|= (1<<2); /* Enable EIERRINT (int 18 MCE) */ + lo&= ~(1<<4); /* Enable MCE */ + wrmsr(0x107, lo, hi); + __asm__ __volatile__ ( + "movl %%cr4, %%eax\n\t" + "orl $0x40, %%eax\n\t" + "movl %%eax, %%cr4\n\t" : : : "eax"); + printk(KERN_INFO "Winchip machine check reporting enabled on CPU#%d.\n", smp_processor_id()); +} + + +/* + * This has to be run for each processor + */ + +void mcheck_init(struct cpuinfo_x86 *c) +{ + switch(c->x86_vendor) + { + case X86_VENDOR_INTEL: + intel_mcheck_init(c); + break; + case X86_VENDOR_CENTAUR: + winchip_mcheck_init(c); + break; + } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/dmi_scan.c linux.ac/arch/i386/kernel/dmi_scan.c --- linux.vanilla/arch/i386/kernel/dmi_scan.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/i386/kernel/dmi_scan.c Sun Apr 15 22:50:01 2001 @@ -1,8 +1,10 @@ +#include <linux/config.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/init.h> #include <linux/apm_bios.h> +#include <linux/slab.h> #include <asm/io.h> struct dmi_header @@ -13,6 +15,7 @@ }; #define dmi_printk(x) +//#define dmi_printk(x) printk(x) static char * __init dmi_string(struct dmi_header *dm, u8 s) { @@ -90,9 +93,163 @@ } +enum +{ + DMI_BIOS_VENDOR, + DMI_BIOS_VERSION, + DMI_BIOS_DATE, + DMI_SYS_VENDOR, + DMI_PRODUCT_NAME, + DMI_PRODUCT_VERSION, + DMI_BOARD_VENDOR, + DMI_BOARD_NAME, + DMI_BOARD_VERSION, + DMI_STRING_MAX +}; + +static char *dmi_ident[DMI_STRING_MAX]; + +/* + * Save a DMI string + */ + +static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string) +{ + char *p = dmi_string(dm, string); + if(p==NULL || *p == 0) + return; + dmi_ident[slot] = kmalloc(strlen(p)+1, GFP_KERNEL); + if(dmi_ident[slot]) + strcpy(dmi_ident[slot], p); + else + printk(KERN_ERR "dmi_save_ident: out of memory.\n"); +} + +/* + * DMI callbacks for problem boards + */ + +struct dmi_strmatch +{ + u8 slot; + char *substr; +}; + +#define NONE 255 + +struct dmi_blacklist +{ + int (*callback)(struct dmi_blacklist *); + char *ident; + struct dmi_strmatch matches[4]; +}; + +#define NO_MATCH { NONE, NULL} +#define MATCH(a,b) { a, b } + +/* + * We have problems with IDE DMA on some platforms. In paticular the + * KT7 series. On these it seems the newer BIOS has fixed them. The + * rule needs to be improved to match specific BIOS revisions with + * corruption problems + */ + +static __init int disable_ide_dma(struct dmi_blacklist *d) +{ +#ifdef CONFIG_BLK_DEV_IDE + extern int noautodma; + if(noautodma == 0) + { + noautodma = 1; + printk(KERN_INFO "%s series board detected. Disabling IDE DMA.\n", d->ident); + } +#endif + return 0; +} + +/* + * 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] + * + * Phoenix A04 08/24/2000 is known bad (Dell Inspiron 5000e) + * Phoenix A07 09/29/2000 is known good (Dell Inspiron 5000) + */ + +static __init int broken_apm_power(struct dmi_blacklist *d) +{ + apm_info.get_power_status_broken = 1; + printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n"); +} + +/* + * Process the DMI blacklists + */ + + +/* + * This will be expanded over time to force things like the APM + * interrupt mask settings according to the laptop + */ + +static __initdata struct dmi_blacklist dmi_blacklist[]={ +#if 0 + { disable_ide_dma, "KT7", { /* Overbroad right now - kill DMA on problem KT7 boards */ + MATCH(DMI_PRODUCT_NAME, "KT7-RAID"), + NO_MATCH, NO_MATCH, NO_MATCH + } }, +#endif + { broken_apm_power, "Dell Inspiron 5000e", { /* Handle problems with APM on Inspiron 5000e */ + MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), + MATCH(DMI_BIOS_VERSION, "A04"), + MATCH(DMI_BIOS_DATE, "08/24/2000"), NO_MATCH + } }, + { NULL, } +}; + + +/* + * Walk the blacklist table running matching functions until someone + * returns 1 or we hit the end. + */ + +static __init void dmi_check_blacklist(void) +{ + struct dmi_blacklist *d; + int i; + + d=&dmi_blacklist[0]; + while(d->callback) + { + for(i=0;i<4;i++) + { + int s = d->matches[i].slot; + if(s==NONE) + continue; + if(dmi_ident[s] && strstr(dmi_ident[s], d->matches[i].substr)) + continue; + /* No match */ + goto fail; + } + if(d->callback(d)) + return; +fail: + d++; + } +} + + + /* * 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 + * and machine entries. For 2.5 we should pull the smbus controller info * out of here. */ @@ -105,66 +262,47 @@ { case 0: p=dmi_string(dm,data[4]); - - if(*p && *p!=' ') + if(*p) { dmi_printk(("BIOS Vendor: %s\n", p)); + dmi_save_ident(dm, DMI_BIOS_VENDOR, 4); dmi_printk(("BIOS Version: %s\n", dmi_string(dm, data[5]))); + dmi_save_ident(dm, DMI_BIOS_VERSION, 5); dmi_printk(("BIOS Release: %s\n", dmi_string(dm, data[8]))); - } - - /* - * 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] - * - * Phoenix A04 08/24/2000 is known bad (Dell Inspiron 5000e) - * Phoenix A07 09/29/2000 is known good (Dell Inspiron 5000) - */ - - if(strcmp(dmi_string(dm, data[4]), "Phoenix Technologies LTD")==0) - { - if(strcmp(dmi_string(dm, data[5]), "A04")==0 - && strcmp(dmi_string(dm, data[8]), "08/24/2000")==0) - { - apm_info.get_power_status_broken = 1; - printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n"); - } + dmi_save_ident(dm, DMI_BIOS_DATE, 8); } break; + case 1: p=dmi_string(dm,data[4]); - - if(*p && *p!=' ') + if(*p) { dmi_printk(("System Vendor: %s.\n",p)); + dmi_save_ident(dm, DMI_SYS_VENDOR, 4); dmi_printk(("Product Name: %s.\n", dmi_string(dm, data[5]))); + dmi_save_ident(dm, DMI_PRODUCT_NAME, 5); dmi_printk(("Version %s.\n", dmi_string(dm, data[6]))); + dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6); dmi_printk(("Serial Number %s.\n", dmi_string(dm, data[7]))); } break; case 2: p=dmi_string(dm,data[4]); - - if(*p && *p!=' ') + if(*p) { dmi_printk(("Board Vendor: %s.\n",p)); + dmi_save_ident(dm, DMI_BOARD_VENDOR, 4); dmi_printk(("Board Name: %s.\n", dmi_string(dm, data[5]))); + dmi_save_ident(dm, DMI_BOARD_NAME, 5); dmi_printk(("Board Version: %s.\n", dmi_string(dm, data[6]))); + dmi_save_ident(dm, DMI_BOARD_VERSION, 6); } break; case 3: @@ -177,7 +315,10 @@ static int __init dmi_scan_machine(void) { - return dmi_iterate(dmi_decode); + int err = dmi_iterate(dmi_decode); + if(err == 0) + dmi_check_blacklist(); + return err; } module_init(dmi_scan_machine); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/head.S linux.ac/arch/i386/kernel/head.S --- linux.vanilla/arch/i386/kernel/head.S Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/i386/kernel/head.S Tue Apr 17 16:00:54 2001 @@ -447,6 +447,13 @@ .quad 0x00409a0000000000 /* 0x48 APM CS code */ .quad 0x00009a0000000000 /* 0x50 APM CS 16 code (16 bit) */ .quad 0x0040920000000000 /* 0x58 APM DS data */ + + /* PNPBIOS segments */ + .quad 0x00c09a0000000000 /* 0x60 32-bit code */ + .quad 0x00809a0000000000 /* 16-bit code */ + .quad 0x0080920000000000 /* 16-bit data */ + .quad 0x0080920000000000 /* 16-bit data */ + .quad 0x0080920000000000 /* 0x80 16-bit data */ .fill NR_CPUS*4,8,0 /* space for TSS's and LDT's */ /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/i386_ksyms.c linux.ac/arch/i386/kernel/i386_ksyms.c --- linux.vanilla/arch/i386/kernel/i386_ksyms.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/i386/kernel/i386_ksyms.c Sun Apr 15 23:03:32 2001 @@ -28,6 +28,7 @@ #include <asm/desc.h> #include <asm/pgtable.h> #include <asm/pgalloc.h> +#include <asm/page.h> extern void dump_thread(struct pt_regs *, struct user *); extern spinlock_t rtc_lock; @@ -61,7 +62,6 @@ EXPORT_SYMBOL(dump_extended_fpu); EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); -EXPORT_SYMBOL(__io_virt_debug); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(disable_irq_nosync); @@ -73,12 +73,16 @@ EXPORT_SYMBOL(apm_info); EXPORT_SYMBOL(gdt); +#ifdef CONFIG_DEBUG_IOVIRT +EXPORT_SYMBOL(__io_virt_debug); +#endif + EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); EXPORT_SYMBOL_NOVERS(__down_failed_trylock); EXPORT_SYMBOL_NOVERS(__up_wakeup); -EXPORT_SYMBOL_NOVERS(__down_write_failed); -EXPORT_SYMBOL_NOVERS(__down_read_failed); +EXPORT_SYMBOL_NOVERS(__rwsem_down_write_failed); +EXPORT_SYMBOL_NOVERS(__rwsem_down_read_failed); EXPORT_SYMBOL_NOVERS(__rwsem_wake); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy_generic); @@ -97,6 +101,7 @@ EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(simple_strtol); +EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strncpy_from_user); EXPORT_SYMBOL(__strncpy_from_user); @@ -162,3 +167,9 @@ #ifdef CONFIG_X86_PAE EXPORT_SYMBOL(empty_zero_page); #endif + +#ifdef CONFIG_DEBUG_BUGVERBOSE +EXPORT_SYMBOL(do_BUG); +#endif + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/i8259.c linux.ac/arch/i386/kernel/i8259.c --- linux.vanilla/arch/i386/kernel/i8259.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/i386/kernel/i8259.c Tue Apr 3 17:54:30 2001 @@ -12,6 +12,7 @@ #include <linux/init.h> #include <linux/kernel_stat.h> +#include <asm/atomic.h> #include <asm/system.h> #include <asm/io.h> #include <asm/irq.h> @@ -19,6 +20,7 @@ #include <asm/pgtable.h> #include <asm/delay.h> #include <asm/desc.h> +#include <asm/apic.h> #include <linux/irq.h> @@ -321,7 +323,7 @@ printk("spurious 8259A interrupt: IRQ%d.\n", irq); spurious_irq_mask |= irqmask; } - irq_err_count++; + atomic_inc(&irq_err_count); /* * Theoretically we do not have to handle this IRQ, * but in Linux this does not cause problems and is @@ -414,6 +416,9 @@ { int i; +#ifdef CONFIG_X86_LOCAL_APIC + init_bsp_APIC(); +#endif init_8259A(0); for (i = 0; i < NR_IRQS; i++) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/io_apic.c linux.ac/arch/i386/kernel/io_apic.c --- linux.vanilla/arch/i386/kernel/io_apic.c Fri Feb 9 19:28:31 2001 +++ linux.ac/arch/i386/kernel/io_apic.c Tue Apr 3 17:54:30 2001 @@ -33,23 +33,15 @@ #include <asm/smp.h> #include <asm/desc.h> +#undef APIC_LOCKUP_DEBUG + static spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED; /* - * # of IO-APICs and # of IRQ routing registers + * # of IRQ routing registers */ -int nr_ioapics; int nr_ioapic_registers[MAX_IO_APICS]; -/* I/O APIC entries */ -struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS]; - -/* # of MP IRQ source entries */ -struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; - -/* MP IRQ source entries */ -int mp_irq_entries; - #if CONFIG_SMP # define TARGET_CPUS cpu_online_map #else @@ -122,8 +114,14 @@ static void name##_IO_APIC_irq (unsigned int irq) \ __DO_ACTION(R, ACTION, FINAL) -DO_ACTION( __mask, 0, |= 0x00010000, io_apic_sync(entry->apic))/* mask = 1 */ -DO_ACTION( __unmask, 0, &= 0xfffeffff, ) /* mask = 0 */ +DO_ACTION( __mask, 0, |= 0x00010000, io_apic_sync(entry->apic) ) + /* mask = 1 */ +DO_ACTION( __unmask, 0, &= 0xfffeffff, ) + /* mask = 0 */ +DO_ACTION( __mask_and_edge, 0, = (reg & 0xffff7fff) | 0x00010000, ) + /* mask = 1, trigger = 0 */ +DO_ACTION( __unmask_and_level, 0, = (reg & 0xfffeffff) | 0x00008000, ) + /* mask = 0, trigger = 1 */ static void mask_IO_APIC_irq (unsigned int irq) { @@ -146,14 +144,17 @@ void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) { struct IO_APIC_route_entry entry; + unsigned long flags; /* * Disable it in the IO-APIC irq-routing table: */ memset(&entry, 0, sizeof(entry)); entry.mask = 1; + spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0)); io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1)); + spin_unlock_irqrestore(&ioapic_lock, flags); } static void clear_IO_APIC (void) @@ -581,6 +582,7 @@ { struct IO_APIC_route_entry entry; int apic, pin, idx, irq, first_notcon = 1, vector; + unsigned long flags; printk(KERN_DEBUG "init IO_APIC IRQs\n"); @@ -636,8 +638,10 @@ if (!apic && (irq < 16)) disable_8259A_irq(irq); } + spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1)); io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0)); + spin_unlock_irqrestore(&ioapic_lock, flags); } } @@ -652,6 +656,7 @@ void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector) { struct IO_APIC_route_entry entry; + unsigned long flags; memset(&entry,0,sizeof(entry)); @@ -681,8 +686,10 @@ /* * Add it to the IO-APIC irq-routing table: */ + spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1)); io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0)); + spin_unlock_irqrestore(&ioapic_lock, flags); enable_8259A_irq(0); } @@ -699,6 +706,7 @@ struct IO_APIC_reg_00 reg_00; struct IO_APIC_reg_01 reg_01; struct IO_APIC_reg_02 reg_02; + unsigned long flags; printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); for (i = 0; i < nr_ioapics; i++) @@ -713,10 +721,12 @@ for (apic = 0; apic < nr_ioapics; apic++) { + spin_lock_irqsave(&ioapic_lock, flags); *(int *)®_00 = io_apic_read(apic, 0); *(int *)®_01 = io_apic_read(apic, 1); if (reg_01.version >= 0x10) *(int *)®_02 = io_apic_read(apic, 2); + spin_unlock_irqrestore(&ioapic_lock, flags); printk("\n"); printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid); @@ -762,8 +772,10 @@ for (i = 0; i <= reg_01.entries; i++) { struct IO_APIC_route_entry entry; + spin_lock_irqsave(&ioapic_lock, flags); *(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2); *(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2); + spin_unlock_irqrestore(&ioapic_lock, flags); printk(KERN_DEBUG " %02x %03X %02X ", i, @@ -790,7 +802,7 @@ continue; printk(KERN_DEBUG "IRQ%d ", i); for (;;) { - printk("-> %d", entry->pin); + printk("-> %d:%d", entry->apic, entry->pin); if (!entry->next) break; entry = irq_2_pin + entry->next; @@ -847,6 +859,8 @@ v = apic_read(APIC_EOI); printk(KERN_DEBUG "... APIC EOI: %08x\n", v); + v = apic_read(APIC_RRR); + printk(KERN_DEBUG "... APIC RRR: %08x\n", v); v = apic_read(APIC_LDR); printk(KERN_DEBUG "... APIC LDR: %08x\n", v); v = apic_read(APIC_DFR); @@ -938,6 +952,7 @@ { struct IO_APIC_reg_01 reg_01; int i; + unsigned long flags; for (i = 0; i < PIN_MAP_SIZE; i++) { irq_2_pin[i].pin = -1; @@ -951,7 +966,9 @@ * The number of IO-APIC IRQ registers (== #pins): */ for (i = 0; i < nr_ioapics; i++) { + spin_lock_irqsave(&ioapic_lock, flags); *(int *)®_01 = io_apic_read(i, 1); + spin_unlock_irqrestore(&ioapic_lock, flags); nr_ioapic_registers[i] = reg_01.entries+1; } @@ -988,6 +1005,7 @@ int apic; int i; unsigned char old_id; + unsigned long flags; /* * Set the IOAPIC ID to the value stored in the MPC table. @@ -995,7 +1013,9 @@ for (apic = 0; apic < nr_ioapics; apic++) { /* Read the register 0 value */ + spin_lock_irqsave(&ioapic_lock, flags); *(int *)®_00 = io_apic_read(apic, 0); + spin_unlock_irqrestore(&ioapic_lock, flags); old_id = mp_ioapics[apic].mpc_apicid; @@ -1044,12 +1064,16 @@ mp_ioapics[apic].mpc_apicid); reg_00.ID = mp_ioapics[apic].mpc_apicid; + spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(apic, 0, *(int *)®_00); + spin_unlock_irqrestore(&ioapic_lock, flags); /* * Sanity check */ + spin_lock_irqsave(&ioapic_lock, flags); *(int *)®_00 = io_apic_read(apic, 0); + spin_unlock_irqrestore(&ioapic_lock, flags); if (reg_00.ID != mp_ioapics[apic].mpc_apicid) panic("could not set ID!\n"); else @@ -1086,25 +1110,6 @@ return 0; } -static int __init nmi_irq_works(void) -{ - irq_cpustat_t tmp[NR_CPUS]; - int j, cpu; - - memcpy(tmp, irq_stat, sizeof(tmp)); - sti(); - mdelay(50); - - for (j = 0; j < smp_num_cpus; j++) { - cpu = cpu_logical_map(j); - if (nmi_count(cpu) - tmp[cpu].__nmi_count <= 3) { - printk(KERN_WARNING "CPU#%d NMI appears to be stuck.\n", cpu); - return 0; - } - } - return 1; -} - /* * In the SMP+IOAPIC case it might happen that there are an unspecified * number of pending IRQ events unhandled. These cases are very rare, @@ -1191,12 +1196,63 @@ #define enable_level_ioapic_irq unmask_IO_APIC_irq #define disable_level_ioapic_irq mask_IO_APIC_irq -static void end_level_ioapic_irq (unsigned int i) +static void end_level_ioapic_irq (unsigned int irq) { + unsigned long v; + int i; + +/* + * It appears there is an erratum which affects at least version 0x11 + * of I/O APIC (that's the 82093AA and cores integrated into various + * chipsets). Under certain conditions a level-triggered interrupt is + * erroneously delivered as edge-triggered one but the respective IRR + * bit gets set nevertheless. As a result the I/O unit expects an EOI + * message but it will never arrive and further interrupts are blocked + * from the source. The exact reason is so far unknown, but the + * phenomenon was observed when two consecutive interrupt requests + * from a given source get delivered to the same CPU and the source is + * temporarily disabled in between. + * + * A workaround is to simulate an EOI message manually. We achieve it + * by setting the trigger mode to edge and then to level when the edge + * trigger mode gets detected in the TMR of a local APIC for a + * level-triggered interrupt. We mask the source for the time of the + * operation to prevent an edge-triggered interrupt escaping meanwhile. + * The idea is from Manfred Spraul. --macro + */ + i = IO_APIC_VECTOR(irq); + v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1)); + ack_APIC_irq(); + + if (!(v & (1 << (i & 0x1f)))) { +#ifdef APIC_MISMATCH_DEBUG + atomic_inc(&irq_mis_count); +#endif + spin_lock(&ioapic_lock); + __mask_and_edge_IO_APIC_irq(irq); +#ifdef APIC_LOCKUP_DEBUG + for (;;) { + struct irq_pin_list *entry = irq_2_pin + irq; + unsigned int reg; + + if (entry->pin == -1) + break; + reg = io_apic_read(entry->apic, 0x10 + entry->pin * 2); + if (reg & 0x00004000) + printk(KERN_CRIT "Aieee!!! Remote IRR" + " still set after unlock!\n"); + if (!entry->next) + break; + entry = irq_2_pin + entry->next; + } +#endif + __unmask_and_level_IO_APIC_irq(irq); + spin_unlock(&ioapic_lock); + } } -static void mask_and_ack_level_ioapic_irq (unsigned int i) { /* nothing */ } +static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ } static void set_ioapic_affinity (unsigned int irq, unsigned long mask) { @@ -1349,13 +1405,16 @@ int pin, i; struct IO_APIC_route_entry entry0, entry1; unsigned char save_control, save_freq_select; + unsigned long flags; pin = find_isa_irq_pin(8, mp_INT); if (pin == -1) return; + spin_lock_irqsave(&ioapic_lock, flags); *(((int *)&entry0) + 1) = io_apic_read(0, 0x11 + 2 * pin); *(((int *)&entry0) + 0) = io_apic_read(0, 0x10 + 2 * pin); + spin_unlock_irqrestore(&ioapic_lock, flags); clear_IO_APIC_pin(0, pin); memset(&entry1, 0, sizeof(entry1)); @@ -1368,8 +1427,10 @@ entry1.trigger = 0; entry1.vector = 0; + spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(0, 0x11 + 2 * pin, *(((int *)&entry1) + 1)); io_apic_write(0, 0x10 + 2 * pin, *(((int *)&entry1) + 0)); + spin_unlock_irqrestore(&ioapic_lock, flags); save_control = CMOS_READ(RTC_CONTROL); save_freq_select = CMOS_READ(RTC_FREQ_SELECT); @@ -1388,8 +1449,10 @@ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); clear_IO_APIC_pin(0, pin); + spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(0, 0x11 + 2 * pin, *(((int *)&entry0) + 1)); io_apic_write(0, 0x10 + 2 * pin, *(((int *)&entry0) + 0)); + spin_unlock_irqrestore(&ioapic_lock, flags); } /* @@ -1434,11 +1497,11 @@ */ unmask_IO_APIC_irq(0); if (timer_irq_works()) { - if (nmi_watchdog) { + if (nmi_watchdog == NMI_IO_APIC) { disable_8259A_irq(0); setup_nmi(); enable_8259A_irq(0); - nmi_irq_works(); + check_nmi_watchdog(); } return; } @@ -1455,9 +1518,9 @@ setup_ExtINT_IRQ0_pin(pin2, vector); if (timer_irq_works()) { printk("works.\n"); - if (nmi_watchdog) { + if (nmi_watchdog == NMI_IO_APIC) { setup_nmi(); - nmi_irq_works(); + check_nmi_watchdog(); } return; } @@ -1538,19 +1601,3 @@ check_timer(); print_IO_APIC(); } - -#ifndef CONFIG_SMP -/* - * This initializes the IO-APIC and APIC hardware if this is - * a UP kernel. - */ -void IO_APIC_init_uniprocessor (void) -{ - if (!smp_found_config) - return; - connect_bsp_APIC(); - setup_local_APIC(); - setup_IO_APIC(); - setup_APIC_clocks(); -} -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/irq.c linux.ac/arch/i386/kernel/irq.c --- linux.vanilla/arch/i386/kernel/irq.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/i386/kernel/irq.c Tue Apr 3 17:54:30 2001 @@ -33,6 +33,7 @@ #include <linux/irq.h> #include <linux/proc_fs.h> +#include <asm/atomic.h> #include <asm/io.h> #include <asm/smp.h> #include <asm/system.h> @@ -119,7 +120,12 @@ end_none }; -volatile unsigned long irq_err_count; +atomic_t irq_err_count; +#ifdef CONFIG_X86_IO_APIC +#ifdef APIC_MISMATCH_DEBUG +atomic_t irq_mis_count; +#endif +#endif /* * Generic, controller-independent functions: @@ -160,14 +166,19 @@ p += sprintf(p, "%10u ", nmi_count(cpu_logical_map(j))); p += sprintf(p, "\n"); -#if CONFIG_SMP +#if CONFIG_X86_LOCAL_APIC p += sprintf(p, "LOC: "); for (j = 0; j < smp_num_cpus; j++) p += sprintf(p, "%10u ", apic_timer_irqs[cpu_logical_map(j)]); p += sprintf(p, "\n"); #endif - p += sprintf(p, "ERR: %10lu\n", irq_err_count); + p += sprintf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); +#ifdef CONFIG_X86_IO_APIC +#ifdef APIC_MISMATCH_DEBUG + p += sprintf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); +#endif +#endif return p - buf; } @@ -460,14 +471,15 @@ * disable_irq_nosync - disable an irq without waiting * @irq: Interrupt to disable * - * Disable the selected interrupt line. Disables of an interrupt - * stack. Unlike disable_irq(), this function does not ensure existing + * Disable the selected interrupt line. Disables and Enables are + * nested. + * Unlike disable_irq(), this function does not ensure existing * instances of the IRQ handler have completed before returning. * * This function may be called from IRQ context. */ -void inline disable_irq_nosync(unsigned int irq) +inline void disable_irq_nosync(unsigned int irq) { irq_desc_t *desc = irq_desc + irq; unsigned long flags; @@ -484,9 +496,9 @@ * disable_irq - disable an irq and wait for completion * @irq: Interrupt to disable * - * Disable the selected interrupt line. Disables of an interrupt - * stack. That is for two disables you need two enables. This - * function waits for any pending IRQ handlers for this interrupt + * Disable the selected interrupt line. Enables and Disables are + * nested. + * This function waits for any pending IRQ handlers for this interrupt * to complete before returning. If you use this function while * holding a resource the IRQ handler may need you will deadlock. * @@ -505,11 +517,12 @@ } /** - * enable_irq - enable interrupt handling on an irq + * enable_irq - enable handling of an irq * @irq: Interrupt to enable * - * Re-enables the processing of interrupts on this IRQ line - * providing no disable_irq calls are now in effect. + * Undoes the effect of one call to disable_irq(). If this + * matches the last disable, processing of interrupts on this + * IRQ line is re-enabled. * * This function may be called from IRQ context. */ @@ -1016,20 +1029,9 @@ static struct proc_dir_entry * root_irq_dir; static struct proc_dir_entry * irq_dir [NR_IRQS]; -static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; - -static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; #define HEX_DIGITS 8 -static int irq_affinity_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - if (count < HEX_DIGITS+1) - return -EINVAL; - return sprintf (page, "%08lx\n", irq_affinity[(long)data]); -} - static unsigned int parse_hex_value (const char *buffer, unsigned long count, unsigned long *ret) { @@ -1067,6 +1069,19 @@ return 0; } +#if CONFIG_SMP + +static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; + +static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; +static int irq_affinity_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08lx\n", irq_affinity[(long)data]); +} + static int irq_affinity_write_proc (struct file *file, const char *buffer, unsigned long count, void *data) { @@ -1078,7 +1093,6 @@ err = parse_hex_value(buffer, count, &new_value); -#if CONFIG_SMP /* * Do not allow disabling IRQs completely - it's a too easy * way to make the system unusable accidentally :-) At least @@ -1086,7 +1100,6 @@ */ if (!(new_value & cpu_online_map)) return -EINVAL; -#endif irq_affinity[irq] = new_value; irq_desc[irq].handler->set_affinity(irq, new_value); @@ -1094,6 +1107,8 @@ return full_count; } +#endif + static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -1121,7 +1136,6 @@ static void register_irq_proc (unsigned int irq) { - struct proc_dir_entry *entry; char name [MAX_NAMELEN]; if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) || @@ -1134,15 +1148,23 @@ /* create /proc/irq/1234 */ irq_dir[irq] = proc_mkdir(name, root_irq_dir); - /* create /proc/irq/1234/smp_affinity */ - entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); +#if CONFIG_SMP + { + struct proc_dir_entry *entry; - entry->nlink = 1; - entry->data = (void *)(long)irq; - entry->read_proc = irq_affinity_read_proc; - entry->write_proc = irq_affinity_write_proc; + /* create /proc/irq/1234/smp_affinity */ + entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); - smp_affinity_entry[irq] = entry; + if (entry) { + entry->nlink = 1; + entry->data = (void *)(long)irq; + entry->read_proc = irq_affinity_read_proc; + entry->write_proc = irq_affinity_write_proc; + } + + smp_affinity_entry[irq] = entry; + } +#endif } unsigned long prof_cpu_mask = -1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/ldt.c linux.ac/arch/i386/kernel/ldt.c --- linux.vanilla/arch/i386/kernel/ldt.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/i386/kernel/ldt.c Thu Apr 12 11:49:12 2001 @@ -94,8 +94,6 @@ goto out_unlock; memset(mm->context.segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE); - if (atomic_read(&mm->mm_users) > 1) - printk(KERN_WARNING "LDT allocated for cloned task!\n"); /* * Possibly do an SMP cross-call to other CPUs to reload * their LDTs? diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/microcode.c linux.ac/arch/i386/kernel/microcode.c --- linux.vanilla/arch/i386/kernel/microcode.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/i386/kernel/microcode.c Tue Apr 3 17:54:30 2001 @@ -126,6 +126,7 @@ printk(KERN_ERR "microcode: failed to devfs_register()\n"); goto out; } + error = 0; printk(KERN_INFO "IA-32 Microcode Update Driver: v%s <tigran@veritas.com>\n", MICROCODE_VERSION); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/mpparse.c linux.ac/arch/i386/kernel/mpparse.c --- linux.vanilla/arch/i386/kernel/mpparse.c Wed Nov 15 05:25:34 2000 +++ linux.ac/arch/i386/kernel/mpparse.c Tue Apr 3 17:54:30 2001 @@ -38,6 +38,18 @@ int mp_bus_id_to_type [MAX_MP_BUSSES]; int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { -1, }; int mp_current_pci_id; + +/* I/O APIC entries */ +struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS]; + +/* # of MP IRQ source entries */ +struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; + +/* MP IRQ source entries */ +int mp_irq_entries; + +int nr_ioapics; + int pic_mode; unsigned long mp_lapic_addr; @@ -225,6 +237,11 @@ MAX_IO_APICS, nr_ioapics); panic("Recompile kernel with bigger MAX_IO_APICS!.\n"); } + if (!m->mpc_apicaddr) { + printk(KERN_ERR "WARNING: bogus zero I/O APIC address" + " found in MP table, skipping!\n"); + return; + } mp_ioapics[nr_ioapics] = *m; nr_ioapics++; } @@ -361,10 +378,19 @@ return num_processors; } +static int __init ELCR_trigger(unsigned int irq) +{ + unsigned int port; + + port = 0x4d0 + (irq >> 3); + return (inb(port) >> (irq & 7)) & 1; +} + static void __init construct_default_ioirq_mptable(int mpc_default_type) { struct mpc_config_intsrc intsrc; int i; + int ELCR_fallback = 0; intsrc.mpc_type = MP_INTSRC; intsrc.mpc_irqflag = 0; /* conforming */ @@ -372,6 +398,26 @@ intsrc.mpc_dstapic = mp_ioapics[0].mpc_apicid; intsrc.mpc_irqtype = mp_INT; + + /* + * If true, we have an ISA/PCI system with no IRQ entries + * in the MP table. To prevent the PCI interrupts from being set up + * incorrectly, we try to use the ELCR. The sanity check to see if + * there is good ELCR data is very simple - IRQ0, 1, 2 and 13 can + * never be level sensitive, so we simply see if the ELCR agrees. + * If it does, we assume it's valid. + */ + if (mpc_default_type == 5) { + printk("ISA/PCI bus type with no IRQ information... falling back to ELCR\n"); + + if (ELCR_trigger(0) || ELCR_trigger(1) || ELCR_trigger(2) || ELCR_trigger(13)) + printk("ELCR contains invalid data... not using ELCR\n"); + else { + printk("Using ELCR to identify PCI interrupts\n"); + ELCR_fallback = 1; + } + } + for (i = 0; i < 16; i++) { switch (mpc_default_type) { case 2: @@ -383,6 +429,18 @@ continue; /* IRQ2 is never connected */ } + if (ELCR_fallback) { + /* + * If the ELCR indicates a level-sensitive interrupt, we + * copy that information over to the MP table in the + * irqflag field (level sensitive, active high polarity). + */ + if (ELCR_trigger(i)) + intsrc.mpc_irqflag = 13; + else + intsrc.mpc_irqflag = 0; + } + intsrc.mpc_srcbusirq = i; intsrc.mpc_dstirq = i ? i : 2; /* IRQ0 to INTIN2 */ MP_intsrc_info(&intsrc); @@ -633,7 +691,7 @@ */ void __init find_smp_config (void) { -#ifdef CONFIG_X86_IO_APIC +#ifdef CONFIG_X86_LOCAL_APIC find_intel_smp(); #endif #ifdef CONFIG_VISWS diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/mtrr.c linux.ac/arch/i386/kernel/mtrr.c --- linux.vanilla/arch/i386/kernel/mtrr.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/i386/kernel/mtrr.c Sat Apr 14 22:37:46 2001 @@ -231,6 +231,20 @@ v1.37 20001109 H. Peter Anvin <hpa@zytor.com> Use the new centralized CPU feature detects. + + v1.38 + 20010309 Dave Jones <davej@suse.de> + Add support for Cyrix III. + + v1.39 + 20010312 Dave Jones <davej@suse.de> + Ugh, I broke AMD support. + Reworked fix by Troels Walsted Hansen <troels@thule.no> + + v1.40 + 20010327 Dave Jones <davej@suse.de> + Adapted Cyrix III support to include VIA C3. + */ #include <linux/types.h> #include <linux/errno.h> @@ -250,6 +264,7 @@ #include <linux/devfs_fs_kernel.h> #include <linux/mm.h> #include <linux/module.h> +#include <linux/pci.h> #define MTRR_NEED_STRINGS #include <asm/mtrr.h> #include <linux/init.h> @@ -269,7 +284,7 @@ #include <asm/hardirq.h> #include <linux/irq.h> -#define MTRR_VERSION "1.37 (20001109)" +#define MTRR_VERSION "1.40 (20010327)" #define TRUE 1 #define FALSE 0 @@ -464,6 +479,27 @@ static int have_wrcomb (void) { unsigned long config, dummy; + struct pci_dev *dev = NULL; + + /* ServerWorks LE chipsets have problems with write-combining + Don't allow it and leave room for other chipsets to be tagged */ + + if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) { + switch(dev->vendor) { + case PCI_VENDOR_ID_SERVERWORKS: + switch (dev->device) { + case PCI_DEVICE_ID_SERVERWORKS_LE: + return 0; + break; + default: + break; + } + break; + default: + break; + } + } + switch ( mtrr_if ) { @@ -538,7 +574,7 @@ * Note: shift==0xf means 4G, this is unsupported. */ if (shift) - *size = (reg < 7 ? 0x1UL : 0x40UL) << shift; + *size = (reg < 7 ? 0x1UL : 0x40UL) << (shift - 1); else *size = 0; @@ -610,12 +646,32 @@ unsigned long low; } centaur_mcr[8]; +static u8 centaur_mcr_reserved; +static u8 centaur_mcr_type; /* 0 for winchip, 1 for winchip2 */ + +/* + * Report boot time MCR setups + */ + +void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) +{ + centaur_mcr[mcr].low = lo; + centaur_mcr[mcr].high = hi; +} + static void centaur_get_mcr (unsigned int reg, unsigned long *base, unsigned long *size, mtrr_type *type) { *base = centaur_mcr[reg].high >> PAGE_SHIFT; *size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT; *type = MTRR_TYPE_WRCOMB; /* If it is there, it is write-combining */ + if(centaur_mcr_type==1 && ((centaur_mcr[reg].low&31)&2)) + *type = MTRR_TYPE_UNCACHABLE; + if(centaur_mcr_type==1 && (centaur_mcr[reg].low&31)==25) + *type = MTRR_TYPE_WRBACK; + if(centaur_mcr_type==0 && (centaur_mcr[reg].low&31)==31) + *type = MTRR_TYPE_WRBACK; + } /* End Function centaur_get_mcr */ static void (*get_mtrr) (unsigned int reg, unsigned long *base, @@ -758,7 +814,15 @@ else { high = base << PAGE_SHIFT; - low = -size << PAGE_SHIFT | 0x1f; /* only support write-combining... */ + if(centaur_mcr_type == 0) + low = -size << PAGE_SHIFT | 0x1f; /* only support write-combining... */ + else + { + if(type == MTRR_TYPE_UNCACHABLE) + low = -size << PAGE_SHIFT | 0x02; /* NC */ + else + low = -size << PAGE_SHIFT | 0x09; /* WWO,WC */ + } } centaur_mcr[reg].high = high; centaur_mcr[reg].low = low; @@ -1068,6 +1132,28 @@ return -ENOSPC; } /* End Function generic_get_free_region */ +static int centaur_get_free_region (unsigned long base, unsigned long size) +/* [SUMMARY] Get a free MTRR. + <base> The starting (base) address of the region. + <size> The size (in bytes) of the region. + [RETURNS] The index of the region on success, else -1 on error. +*/ +{ + int i, max; + mtrr_type ltype; + unsigned long lbase, lsize; + + max = get_num_var_ranges (); + for (i = 0; i < max; ++i) + { + if(centaur_mcr_reserved & (1<<i)) + continue; + (*get_mtrr) (i, &lbase, &lsize, <ype); + if (lsize == 0) return i; + } + return -ENOSPC; +} /* End Function generic_get_free_region */ + static int cyrix_get_free_region (unsigned long base, unsigned long size) /* [SUMMARY] Get a free ARR. <base> The starting (base) address of the region. @@ -1128,9 +1214,9 @@ * * The available types are * - * %MTRR_TYPE_UNCACHEABLE - No caching + * %MTRR_TYPE_UNCACHABLE - No caching * - * %MTRR_TYPE_WRITEBACK - Write data back in bursts whenever + * %MTRR_TYPE_WRBACK - Write data back in bursts whenever * * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts * @@ -1193,9 +1279,13 @@ case MTRR_IF_CENTAUR_MCR: if ( mtrr_if == MTRR_IF_CENTAUR_MCR ) { - if (type != MTRR_TYPE_WRCOMB) + /* + * FIXME: Winchip2 supports uncached + */ + if (type != MTRR_TYPE_WRCOMB && (centaur_mcr_type == 0 || type != MTRR_TYPE_UNCACHABLE)) { - printk (KERN_WARNING "mtrr: only write-combining is supported\n"); + printk (KERN_WARNING "mtrr: only write-combining%s supported\n", + centaur_mcr_type?" and uncacheable are":" is"); return -EINVAL; } } @@ -1312,9 +1402,9 @@ * * The available types are * - * %MTRR_TYPE_UNCACHEABLE - No caching + * %MTRR_TYPE_UNCACHABLE - No caching * - * %MTRR_TYPE_WRITEBACK - Write data back in bursts whenever + * %MTRR_TYPE_WRBACK - Write data back in bursts whenever * * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts * @@ -1777,7 +1867,8 @@ } devfs_set_file_size (devfs_handle, ascii_buf_bytes); # ifdef CONFIG_PROC_FS - proc_root_mtrr->size = ascii_buf_bytes; + if (proc_root_mtrr) + proc_root_mtrr->size = ascii_buf_bytes; # endif /* CONFIG_PROC_FS */ } /* End Function compute_ascii */ @@ -1910,23 +2001,64 @@ { unsigned i; struct set_mtrr_context ctxt; + u32 lo, hi; + int wc2 = -1; set_mtrr_prepare (&ctxt); /* Unfortunately, MCR's are read-only, so there is no way to * find out what the bios might have done. */ - /* Clear all MCR's. + + /* + * Enable MCR key if we are using a winchip2 + */ + + if(boot_cpu_data.x86_model==4) + wc2 = 0; + + if(boot_cpu_data.x86_model==8 || boot_cpu_data.x86_model == 9) + { + rdmsr(0x120, lo, hi); + if(((lo>>17)&7)==1) /* Type 1 Winchip2 MCR */ + { + lo&= ~0x1C0; /* clear key */ + lo|= 0x040; /* set key to 1 */ + wrmsr(0x120, lo, hi); /* unlock MCR */ + wc2 = 1; + centaur_mcr_type = 1; + } + } + /* Clear any unconfigured MCR's. * This way we are sure that the centaur_mcr array contains the actual * values. The disadvantage is that any BIOS tweaks are thus undone. + * */ for (i = 0; i < 8; ++i) { - centaur_mcr[i].high = 0; - centaur_mcr[i].low = 0; - wrmsr (0x110 + i , 0, 0); + if(centaur_mcr[i]. high == 0 && centaur_mcr[i].low == 0) + { + if(wc2==0 || !(lo & (1<<(9+i)))) + wrmsr (0x110 + i , 0, 0); + else + /* + * If the BIOS set up an MCR we cannot see it + * but we don't wish to obliterate it + */ + centaur_mcr_reserved |= (1<<i); + } + } + /* Throw the main write-combining switch... + However if OOSTORE is enabled then people have already done far + cleverer things and we should behave. + */ + + if(wc2 == 1) + { + lo |= 15; /* Write combine enables */ + wrmsr(0x120, lo, hi); } - /* Throw the main write-combining switch... */ - wrmsr (0x120, 0x01f0001f, 0); + else if(wc2 == 0) + wrmsr(0x120, 0x01F0001F, 0); set_mtrr_done (&ctxt); } /* End Function centaur_mcr_init */ @@ -1938,6 +2070,7 @@ get_mtrr = intel_get_mtrr; set_mtrr_up = intel_set_mtrr_up; switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: /* The original Athlon docs said that total addressable memory is 44 bits wide. @@ -1956,12 +2089,27 @@ size_and_mask = ~size_or_mask & 0xfff00000; break; } + size_or_mask = 0xff000000; /* 36 bits */ + size_and_mask = 0x00f00000; + break; + + case X86_VENDOR_CENTAUR: + /* Cyrix III has Intel style MTRRs, but doesn't support PAE */ + if (boot_cpu_data.x86 == 6 && + (boot_cpu_data.x86_model == 6 || + boot_cpu_data.x86_model == 7)) { + size_or_mask = 0xfff00000; /* 32 bits */ + size_and_mask = 0; + } + break; + default: /* Intel, etc. */ size_or_mask = 0xff000000; /* 36 bits */ size_and_mask = 0x00f00000; break; } + } else if ( test_bit(X86_FEATURE_K6_MTRR, &boot_cpu_data.x86_capability) ) { /* Pre-Athlon (K6) AMD CPU MTRRs */ mtrr_if = MTRR_IF_AMD_K6; @@ -1983,6 +2131,7 @@ mtrr_if = MTRR_IF_CENTAUR_MCR; get_mtrr = centaur_get_mcr; set_mtrr_up = centaur_set_mcr_up; + get_free_region = centaur_get_free_region; centaur_mcr_init(); size_or_mask = 0xfff00000; /* 32 bits */ size_and_mask = 0; @@ -2072,8 +2221,10 @@ #ifdef CONFIG_PROC_FS proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root); - proc_root_mtrr->owner = THIS_MODULE; - proc_root_mtrr->proc_fops = &mtrr_fops; + if (proc_root_mtrr) { + proc_root_mtrr->owner = THIS_MODULE; + proc_root_mtrr->proc_fops = &mtrr_fops; + } #endif #ifdef CONFIG_DEVFS_FS devfs_handle = devfs_register (NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/nmi.c linux.ac/arch/i386/kernel/nmi.c --- linux.vanilla/arch/i386/kernel/nmi.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/i386/kernel/nmi.c Tue Apr 3 17:54:30 2001 @@ -0,0 +1,299 @@ +/* + * linux/arch/i386/nmi.c + * + * NMI watchdog support on APIC systems + * + * Started by Ingo Molnar <mingo@redhat.com> + * + * Fixes: + * Mikael Pettersson : AMD K7 support for local APIC NMI watchdog. + * Mikael Pettersson : Power Management for local APIC NMI watchdog. + */ + +#include <linux/config.h> +#include <linux/mm.h> +#include <linux/irq.h> +#include <linux/delay.h> +#include <linux/bootmem.h> +#include <linux/smp_lock.h> +#include <linux/interrupt.h> +#include <linux/mc146818rtc.h> +#include <linux/kernel_stat.h> + +#include <asm/smp.h> +#include <asm/mtrr.h> +#include <asm/mpspec.h> + +unsigned int nmi_watchdog = NMI_NONE; +static unsigned int nmi_hz = HZ; +unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */ + +#define K7_EVNTSEL_ENABLE (1 << 22) +#define K7_EVNTSEL_INT (1 << 20) +#define K7_EVNTSEL_OS (1 << 17) +#define K7_EVNTSEL_USR (1 << 16) +#define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING 0x76 +#define K7_NMI_EVENT K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING + +#define P6_EVNTSEL0_ENABLE (1 << 22) +#define P6_EVNTSEL_INT (1 << 20) +#define P6_EVNTSEL_OS (1 << 17) +#define P6_EVNTSEL_USR (1 << 16) +#define P6_EVENT_CPU_CLOCKS_NOT_HALTED 0x79 +#define P6_NMI_EVENT P6_EVENT_CPU_CLOCKS_NOT_HALTED + +int __init check_nmi_watchdog (void) +{ + irq_cpustat_t tmp[NR_CPUS]; + int j, cpu; + + printk(KERN_INFO "testing NMI watchdog ... "); + + memcpy(tmp, irq_stat, sizeof(tmp)); + sti(); + mdelay((10*1000)/nmi_hz); // wait 10 ticks + + for (j = 0; j < smp_num_cpus; j++) { + cpu = cpu_logical_map(j); + if (nmi_count(cpu) - tmp[cpu].__nmi_count <= 5) { + printk("CPU#%d: NMI appears to be stuck!\n", cpu); + return -1; + } + } + printk("OK.\n"); + + /* now that we know it works we can reduce NMI frequency to + something more reasonable; makes a difference in some configs */ + if (nmi_watchdog == NMI_LOCAL_APIC) + nmi_hz = 1; + + return 0; +} + +static int __init setup_nmi_watchdog(char *str) +{ + int nmi; + + get_option(&str, &nmi); + + if (nmi >= NMI_INVALID) + return 0; + if (nmi == NMI_NONE) + nmi_watchdog = nmi; + /* + * If any other x86 CPU has a local APIC, then + * please test the NMI stuff there and send me the + * missing bits. Right now Intel P6 and AMD K7 only. + */ + if ((nmi == NMI_LOCAL_APIC) && + (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && + (boot_cpu_data.x86 == 6)) + nmi_watchdog = nmi; + if ((nmi == NMI_LOCAL_APIC) && + (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && + (boot_cpu_data.x86 == 6)) + nmi_watchdog = nmi; + /* + * We can enable the IO-APIC watchdog + * unconditionally. + */ + if (nmi == NMI_IO_APIC) + nmi_watchdog = nmi; + return 1; +} + +__setup("nmi_watchdog=", setup_nmi_watchdog); + +#ifdef CONFIG_PM + +#include <linux/pm.h> + +struct pm_dev *nmi_pmdev; + +static void disable_apic_nmi_watchdog(void) +{ + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + wrmsr(MSR_K7_EVNTSEL0, 0, 0); + break; + case X86_VENDOR_INTEL: + wrmsr(MSR_IA32_EVNTSEL0, 0, 0); + break; + } +} + +static int nmi_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + switch (rqst) { + case PM_SUSPEND: + disable_apic_nmi_watchdog(); + break; + case PM_RESUME: + setup_apic_nmi_watchdog(); + break; + } + return 0; +} + +static void nmi_pm_init(void) +{ + if (!nmi_pmdev) + nmi_pmdev = apic_pm_register(PM_SYS_DEV, 0, nmi_pm_callback); +} + +#define __pminit /*empty*/ + +#else /* CONFIG_PM */ + +static inline void nmi_pm_init(void) { } + +#define __pminit __init + +#endif /* CONFIG_PM */ + +/* + * Activate the NMI watchdog via the local APIC. + * Original code written by Keith Owens. + */ + +static void __pminit setup_k7_watchdog(void) +{ + int i; + unsigned int evntsel; + + nmi_perfctr_msr = MSR_K7_PERFCTR0; + + for(i = 0; i < 4; ++i) { + wrmsr(MSR_K7_EVNTSEL0+i, 0, 0); + wrmsr(MSR_K7_PERFCTR0+i, 0, 0); + } + + evntsel = K7_EVNTSEL_INT + | K7_EVNTSEL_OS + | K7_EVNTSEL_USR + | K7_NMI_EVENT; + + wrmsr(MSR_K7_EVNTSEL0, evntsel, 0); + Dprintk("setting K7_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000)); + wrmsr(MSR_K7_PERFCTR0, -(cpu_khz/nmi_hz*1000), -1); + apic_write(APIC_LVTPC, APIC_DM_NMI); + evntsel |= K7_EVNTSEL_ENABLE; + wrmsr(MSR_K7_EVNTSEL0, evntsel, 0); +} + +static void __pminit setup_p6_watchdog(void) +{ + int i; + unsigned int evntsel; + + nmi_perfctr_msr = MSR_IA32_PERFCTR0; + + for(i = 0; i < 2; ++i) { + wrmsr(MSR_IA32_EVNTSEL0+i, 0, 0); + wrmsr(MSR_IA32_PERFCTR0+i, 0, 0); + } + + evntsel = P6_EVNTSEL_INT + | P6_EVNTSEL_OS + | P6_EVNTSEL_USR + | P6_NMI_EVENT; + + wrmsr(MSR_IA32_EVNTSEL0, evntsel, 0); + Dprintk("setting IA32_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000)); + wrmsr(MSR_IA32_PERFCTR0, -(cpu_khz/nmi_hz*1000), 0); + apic_write(APIC_LVTPC, APIC_DM_NMI); + evntsel |= P6_EVNTSEL0_ENABLE; + wrmsr(MSR_IA32_EVNTSEL0, evntsel, 0); +} + +void __pminit setup_apic_nmi_watchdog (void) +{ + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + if (boot_cpu_data.x86 != 6) + return; + setup_k7_watchdog(); + break; + case X86_VENDOR_INTEL: + if (boot_cpu_data.x86 != 6) + return; + setup_p6_watchdog(); + break; + default: + return; + } + nmi_pm_init(); +} + +static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED; + +/* + * the best way to detect whether a CPU has a 'hard lockup' problem + * is to check it's local APIC timer IRQ counts. If they are not + * changing then that CPU has some problem. + * + * as these watchdog NMI IRQs are generated on every CPU, we only + * have to check the current processor. + * + * since NMIs dont listen to _any_ locks, we have to be extremely + * careful not to rely on unsafe variables. The printk might lock + * up though, so we have to break up any console locks first ... + * [when there will be more tty-related locks, break them up + * here too!] + */ + +static unsigned int + last_irq_sums [NR_CPUS], + alert_counter [NR_CPUS]; + +void touch_nmi_watchdog (void) +{ + int i; + + /* + * Just reset the alert counters, (other CPUs might be + * spinning on locks we hold): + */ + for (i = 0; i < smp_num_cpus; i++) + alert_counter[i] = 0; +} + +void nmi_watchdog_tick (struct pt_regs * regs) +{ + + /* + * Since current-> is always on the stack, and we always switch + * the stack NMI-atomically, it's safe to use smp_processor_id(). + */ + int sum, cpu = smp_processor_id(); + + sum = apic_timer_irqs[cpu]; + + if (last_irq_sums[cpu] == sum) { + /* + * Ayiee, looks like this CPU is stuck ... + * wait a few IRQs (5 seconds) before doing the oops ... + */ + alert_counter[cpu]++; + if (alert_counter[cpu] == 5*nmi_hz) { + spin_lock(&nmi_print_lock); + /* + * We are in trouble anyway, lets at least try + * to get a message out. + */ + bust_spinlocks(1); + printk("NMI Watchdog detected LOCKUP on CPU%d, registers:\n", cpu); + show_registers(regs); + printk("console shuts up ...\n"); + console_silent(); + spin_unlock(&nmi_print_lock); + bust_spinlocks(0); + do_exit(SIGSEGV); + } + } else { + last_irq_sums[cpu] = sum; + alert_counter[cpu] = 0; + } + if (nmi_perfctr_msr) + wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/pci-irq.c linux.ac/arch/i386/kernel/pci-irq.c --- linux.vanilla/arch/i386/kernel/pci-irq.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/i386/kernel/pci-irq.c Tue Apr 3 17:54:30 2001 @@ -222,15 +222,18 @@ /* * Cyrix: nibble offset 0x5C + * 0x5C bits 7:4 is INTB bits 3:0 is INTA + * 0x5D bits 7:4 is INTD bits 3:0 is INTC */ + static int pirq_cyrix_get(struct pci_dev *router, struct pci_dev *dev, int pirq) { - return read_config_nybble(router, 0x5C, pirq-1); + return read_config_nybble(router, 0x5C, pirq^1); } static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) { - write_config_nybble(router, 0x5C, pirq-1, irq); + write_config_nybble(router, 0x5C, pirq^1, irq); return 1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/pci-pc.c linux.ac/arch/i386/kernel/pci-pc.c --- linux.vanilla/arch/i386/kernel/pci-pc.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/i386/kernel/pci-pc.c Sun Apr 15 22:49:03 2001 @@ -843,6 +843,8 @@ pcibios_last_bus = -1; } +#if 0 +/* Until we get proper handling pray the BIOS gets it right */ /* * ServerWorks host bridges -- Find and scan all secondary buses. * Register 0x44 contains first, 0x45 last bus number routed there. @@ -860,6 +862,7 @@ printk("PCI: ServerWorks host bridge: last bus %02x\n", pcibios_last_bus); } } +#endif #if 0 /* Our bus code shouldnt need this fixup any more. Delete once verified */ @@ -957,34 +960,6 @@ d->irq = 9; } -static void __init pci_fixup_vt8363(struct pci_dev *d) -{ - /* - * The VIA bridge will corrupt disks without these settings. - */ - u8 tmp; - pci_read_config_byte(d, 0x54, &tmp); - if(tmp & (1<<2)) { - printk("PCI: Bus master Pipeline request disabled\n"); - pci_write_config_byte(d, 0x54, tmp & ~(1<<2)); - } - pci_read_config_byte(d, 0x70, &tmp); - if(tmp & (1<<3)) { - printk("PCI: Disabled enhanced CPU to PCI writes\n"); - pci_write_config_byte(d, 0x70, tmp & ~(1<<3)); - } - pci_read_config_byte(d, 0x71, &tmp); - if((tmp & (1<<3)) == 0) { - printk("PCI: Bursting cornercase bug worked around\n"); - pci_write_config_byte(d, 0x71, tmp | (1<<3)); - } - pci_read_config_byte(d, 0x76, &tmp); - if(tmp & (1<<7)) { - printk("PCI: Post Write Fail set to Retry\n"); - pci_write_config_byte(d, 0x76, tmp & ~(1<<7)); - } -} - static void __init pci_fixup_via691(struct pci_dev *d) { /* @@ -1033,7 +1008,6 @@ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5598, pci_fixup_latency }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, pci_fixup_via_acpi }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, pci_fixup_via_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_vt8363 }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C691, pci_fixup_via691 }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C598_1, pci_fixup_via691_2 }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, pci_fixup_piix4_acpi }, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/semaphore.c linux.ac/arch/i386/kernel/semaphore.c --- linux.vanilla/arch/i386/kernel/semaphore.c Sun Nov 19 01:31:25 2000 +++ linux.ac/arch/i386/kernel/semaphore.c Sat Apr 14 01:17:30 2001 @@ -14,7 +14,6 @@ */ #include <linux/config.h> #include <linux/sched.h> - #include <asm/semaphore.h> /* @@ -179,6 +178,7 @@ * value.. */ asm( +".text\n" ".align 4\n" ".globl __down_failed\n" "__down_failed:\n\t" @@ -193,6 +193,7 @@ ); asm( +".text\n" ".align 4\n" ".globl __down_failed_interruptible\n" "__down_failed_interruptible:\n\t" @@ -205,6 +206,7 @@ ); asm( +".text\n" ".align 4\n" ".globl __down_failed_trylock\n" "__down_failed_trylock:\n\t" @@ -217,6 +219,7 @@ ); asm( +".text\n" ".align 4\n" ".globl __up_wakeup\n" "__up_wakeup:\n\t" @@ -230,199 +233,9 @@ "ret" ); -asm( -" -.align 4 -.globl __down_read_failed -__down_read_failed: - pushl %edx - pushl %ecx - jnc 2f - -3: call down_read_failed_biased - -1: popl %ecx - popl %edx - ret - -2: call down_read_failed - " LOCK "subl $1,(%eax) - jns 1b - jnc 2b - jmp 3b -" -); - -asm( -" -.align 4 -.globl __down_write_failed -__down_write_failed: - pushl %edx - pushl %ecx - jnc 2f - -3: call down_write_failed_biased - -1: popl %ecx - popl %edx - ret - -2: call down_write_failed - " LOCK "subl $" RW_LOCK_BIAS_STR ",(%eax) - jz 1b - jnc 2b - jmp 3b -" -); - -struct rw_semaphore *FASTCALL(rwsem_wake_readers(struct rw_semaphore *sem)); -struct rw_semaphore *FASTCALL(rwsem_wake_writer(struct rw_semaphore *sem)); - -struct rw_semaphore *FASTCALL(down_read_failed_biased(struct rw_semaphore *sem)); -struct rw_semaphore *FASTCALL(down_write_failed_biased(struct rw_semaphore *sem)); -struct rw_semaphore *FASTCALL(down_read_failed(struct rw_semaphore *sem)); -struct rw_semaphore *FASTCALL(down_write_failed(struct rw_semaphore *sem)); - -struct rw_semaphore *down_read_failed_biased(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ - - for (;;) { - if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (!sem->read_bias_granted) - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - return sem; -} - -struct rw_semaphore *down_write_failed_biased(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */ - - for (;;) { - if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (!sem->write_bias_granted) - schedule(); - } - - remove_wait_queue(&sem->write_bias_wait, &wait); - tsk->state = TASK_RUNNING; - - /* if the lock is currently unbiased, awaken the sleepers - * FIXME: this wakes up the readers early in a bit of a - * stampede -> bad! - */ - if (atomic_read(&sem->count) >= 0) - wake_up(&sem->wait); - - return sem; -} - -/* Wait for the lock to become unbiased. Readers - * are non-exclusive. =) - */ -struct rw_semaphore *down_read_failed(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - __up_read(sem); /* this takes care of granting the lock */ - - add_wait_queue(&sem->wait, &wait); - - while (atomic_read(&sem->count) < 0) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (atomic_read(&sem->count) >= 0) - break; - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - return sem; -} - -/* Wait for the lock to become unbiased. Since we're - * a writer, we'll make ourselves exclusive. - */ -struct rw_semaphore *down_write_failed(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - __up_write(sem); /* this takes care of granting the lock */ - - add_wait_queue_exclusive(&sem->wait, &wait); - - while (atomic_read(&sem->count) < 0) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (atomic_read(&sem->count) >= 0) - break; /* we must attempt to acquire or bias the lock */ - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - return sem; -} - -asm( -" -.align 4 -.globl __rwsem_wake -__rwsem_wake: - pushl %edx - pushl %ecx - - jz 1f - call rwsem_wake_readers - jmp 2f - -1: call rwsem_wake_writer - -2: popl %ecx - popl %edx - ret -" -); - -/* Called when someone has done an up that transitioned from - * negative to non-negative, meaning that the lock has been - * granted to whomever owned the bias. +/* + * rw spinlock fallbacks */ -struct rw_semaphore *rwsem_wake_readers(struct rw_semaphore *sem) -{ - if (xchg(&sem->read_bias_granted, 1)) - BUG(); - wake_up(&sem->wait); - return sem; -} - -struct rw_semaphore *rwsem_wake_writer(struct rw_semaphore *sem) -{ - if (xchg(&sem->write_bias_granted, 1)) - BUG(); - wake_up(&sem->write_bias_wait); - return sem; -} - #if defined(CONFIG_SMP) asm( " @@ -451,4 +264,3 @@ " ); #endif - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/setup.c linux.ac/arch/i386/kernel/setup.c --- linux.vanilla/arch/i386/kernel/setup.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/i386/kernel/setup.c Tue Apr 17 15:30:08 2001 @@ -58,6 +58,12 @@ * Massive cleanup of CPU detection and bug handling; * Transmeta CPU detection, * H. Peter Anvin <hpa@zytor.com>, November 2000 + * + * Added E820 sanitization routine (removes overlapping memory regions); + * Brian Moyle <bmoyle@mvista.com>, February 2001 + * + * VIA C3 Support. + * Dave Jones <davej@suse.de>, March 2001 */ /* @@ -142,9 +148,9 @@ extern int rd_image_start; /* starting block # of image */ #endif +extern void mcheck_init(struct cpuinfo_x86 *c); extern int root_mountflags; extern char _text, _etext, _edata, _end; -extern unsigned long cpu_khz; static int disable_x86_serial_nr __initdata = 1; static int disable_x86_fxsr __initdata = 0; @@ -440,6 +446,170 @@ } /* + * Sanitize the BIOS e820 map. + * + * Some e820 responses include overlapping entries. The following + * replaces the original e820 map with a new one, removing overlaps. + * + */ +static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map) +{ + struct change_member { + struct e820entry *pbios; /* pointer to original bios entry */ + unsigned long long addr; /* address for this change point */ + }; + struct change_member change_point_list[2*E820MAX]; + struct change_member *change_point[2*E820MAX]; + struct e820entry *overlap_list[E820MAX]; + struct e820entry new_bios[E820MAX]; + struct change_member *change_tmp; + unsigned long current_type, last_type; + unsigned long long last_addr; + int chgidx, still_changing; + int overlap_entries; + int new_bios_entry; + int old_nr, new_nr; + int i; + + /* + Visually we're performing the following (1,2,3,4 = memory types)... + + Sample memory map (w/overlaps): + ____22__________________ + ______________________4_ + ____1111________________ + _44_____________________ + 11111111________________ + ____________________33__ + ___________44___________ + __________33333_________ + ______________22________ + ___________________2222_ + _________111111111______ + _____________________11_ + _________________4______ + + Sanitized equivalent (no overlap): + 1_______________________ + _44_____________________ + ___1____________________ + ____22__________________ + ______11________________ + _________1______________ + __________3_____________ + ___________44___________ + _____________33_________ + _______________2________ + ________________1_______ + _________________4______ + ___________________2____ + ____________________33__ + ______________________4_ + */ + + /* if there's only one memory region, don't bother */ + if (*pnr_map < 2) + return -1; + + old_nr = *pnr_map; + + /* bail out if we find any unreasonable addresses in bios map */ + for (i=0; i<old_nr; i++) + if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr) + return -1; + + /* create pointers for initial change-point information (for sorting) */ + for (i=0; i < 2*old_nr; i++) + change_point[i] = &change_point_list[i]; + + /* record all known change-points (starting and ending addresses) */ + chgidx = 0; + for (i=0; i < old_nr; i++) { + change_point[chgidx]->addr = biosmap[i].addr; + change_point[chgidx++]->pbios = &biosmap[i]; + change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size; + change_point[chgidx++]->pbios = &biosmap[i]; + } + + /* sort change-point list by memory addresses (low -> high) */ + still_changing = 1; + while (still_changing) { + still_changing = 0; + for (i=1; i < 2*old_nr; i++) { + /* if <current_addr> > <last_addr>, swap */ + /* or, if current=<start_addr> & last=<end_addr>, swap */ + if ((change_point[i]->addr < change_point[i-1]->addr) || + ((change_point[i]->addr == change_point[i-1]->addr) && + (change_point[i]->addr == change_point[i]->pbios->addr) && + (change_point[i-1]->addr != change_point[i-1]->pbios->addr)) + ) + { + change_tmp = change_point[i]; + change_point[i] = change_point[i-1]; + change_point[i-1] = change_tmp; + still_changing=1; + } + } + } + + /* create a new bios memory map, removing overlaps */ + overlap_entries=0; /* number of entries in the overlap table */ + new_bios_entry=0; /* index for creating new bios map entries */ + last_type = 0; /* start with undefined memory type */ + last_addr = 0; /* start with 0 as last starting address */ + /* loop through change-points, determining affect on the new bios map */ + for (chgidx=0; chgidx < 2*old_nr; chgidx++) + { + /* keep track of all overlapping bios entries */ + if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr) + { + /* add map entry to overlap list (> 1 entry implies an overlap) */ + overlap_list[overlap_entries++]=change_point[chgidx]->pbios; + } + else + { + /* remove entry from list (order independent, so swap with last) */ + for (i=0; i<overlap_entries; i++) + { + if (overlap_list[i] == change_point[chgidx]->pbios) + overlap_list[i] = overlap_list[overlap_entries-1]; + } + overlap_entries--; + } + /* if there are overlapping entries, decide which "type" to use */ + /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */ + current_type = 0; + for (i=0; i<overlap_entries; i++) + if (overlap_list[i]->type > current_type) + current_type = overlap_list[i]->type; + /* continue building up new bios map based on this information */ + if (current_type != last_type) { + if (last_type != 0) { + new_bios[new_bios_entry].size = + change_point[chgidx]->addr - last_addr; + /* move forward only if the new size was non-zero */ + if (new_bios[new_bios_entry].size != 0) + if (++new_bios_entry >= E820MAX) + break; /* no more space left for new bios entries */ + } + if (current_type != 0) { + new_bios[new_bios_entry].addr = change_point[chgidx]->addr; + new_bios[new_bios_entry].type = current_type; + last_addr=change_point[chgidx]->addr; + } + last_type = current_type; + } + } + new_nr = new_bios_entry; /* retain count for new bios entries */ + + /* copy new bios mapping into original location */ + memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry)); + *pnr_map = new_nr; + + return 0; +} + +/* * Copy the BIOS e820 map into a safe place. * * Sanity-check it while we're at it.. @@ -506,6 +676,7 @@ * Otherwise fake a memory map; one section from 0k->640k, * the next section from 1mb->appropriate_mem_k */ + sanitize_e820_map(E820_MAP, &E820_MAP_NR); if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) { unsigned long mem_size; @@ -560,7 +731,7 @@ * blow away any automatically generated * size */ - unsigned long start_at, mem_size; + unsigned long long start_at, mem_size; if (usermem == 0) { /* first time in: zap the whitelist @@ -772,21 +943,19 @@ smp_alloc_memory(); /* AP processor realmode stacks in low memory*/ #endif -#ifdef CONFIG_X86_IO_APIC +#ifdef CONFIG_X86_LOCAL_APIC /* * Find and reserve possible boot-time SMP configuration: */ find_smp_config(); #endif paging_init(); -#ifdef CONFIG_X86_IO_APIC +#ifdef CONFIG_X86_LOCAL_APIC /* * get boot-time SMP configuration: */ if (smp_found_config) get_smp_config(); -#endif -#ifdef CONFIG_X86_LOCAL_APIC init_apic_mappings(); #endif @@ -865,6 +1034,32 @@ __setup("notsc", tsc_setup); #endif + +static void __init interpret_eblcr(struct cpuinfo_x86 *c, u32 lo, int coding) +{ + static unsigned int __initdata mult[32] = { 10, 6, 8, 0, 11, 7, 9, 0, + 10, 14, 16, 12, 0, 15, 0, 13 , + 0, 0, 0, 0, 0, 0, 17, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; + int mul = (lo>>22)&15; + + /* The mobile pIII added bit 27. This is zero on other intel and + on the cyrix III */ + + if(lo&(1>>27)) + mul+=16; + + c->clockmul = mult[mul]; + + if (mult[mul]==0) + { + printk(KERN_INFO "Unknown CPU/BUS multiplier (%d, %x).\n", + mul, lo); + return; + } +} + + static int __init get_model_name(struct cpuinfo_x86 *c) { unsigned int *v; @@ -1299,6 +1494,248 @@ return; } +#ifdef CONFIG_X86_OOSTORE + +static u32 __init power2(u32 x) +{ + u32 s=1; + while(s<=x) + s<<=1; + return s>>=1; +} + +/* + * Set up an actual MCR + */ + +static void __init winchip_mcr_insert(int reg, u32 base, u32 size, int key) +{ + u32 lo, hi; + + hi = base & ~0xFFF; + lo = ~(size-1); /* Size is a power of 2 so this makes a mask */ + lo &= ~0xFFF; /* Remove the ctrl value bits */ + lo |= key; /* Attribute we wish to set */ + wrmsr(reg+0x110, lo, hi); + mtrr_centaur_report_mcr(reg, lo, hi); /* Tell the mtrr driver */ +} + +/* + * Figure what we can cover with MCR's + * + * Shortcut: We know you can't put 4Gig of RAM on a winchip + */ + +static u32 __init ramtop(void) /* 16388 */ +{ + int i; + u32 top = 0; + u32 clip = 0xFFFFFFFFUL; + + for (i = 0; i < e820.nr_map; i++) { + unsigned long start, end; + + if (e820.map[i].addr > 0xFFFFFFFFUL) + continue; + /* + * Don't MCR over reserved space. Ignore the ISA hole + * we frob around that catastrophy already + */ + + if (e820.map[i].type == E820_RESERVED) + { + if(e820.map[i].addr >= 0x100000UL && e820.map[i].addr < clip) + clip = e820.map[i].addr; + continue; + } + start = e820.map[i].addr; + end = e820.map[i].addr + e820.map[i].size; + if (start >= end) + continue; + if (end > top) + top = end; + } + /* Everything below 'top' should be RAM except for the ISA hole. + Because of the limited MCR's we want to map NV/ACPI into our + MCR range for gunk in RAM + + Clip might cause us to MCR insufficient RAM but that is an + acceptable failure mode and should only bite obscure boxes with + a VESA hole at 15Mb + + The second case Clip sometimes kicks in is when the EBDA is marked + as reserved. Again we fail safe with reasonable results + */ + + if(top>clip) + top=clip; + + return top; +} + +/* + * Compute a set of MCR's to give maximum coverage + */ + +static int __init winchip_mcr_compute(int nr, int key) +{ + u32 mem = ramtop(); + u32 root = power2(mem); + u32 base = root; + u32 top = root; + u32 floor = 0; + int ct = 0; + + while(ct<nr) + { + u32 fspace = 0; + + /* + * Find the largest block we will fill going upwards + */ + + u32 high = power2(mem-top); + + /* + * Find the largest block we will fill going downwards + */ + + u32 low = base/2; + + /* + * Don't fill below 1Mb going downwards as there + * is an ISA hole in the way. + */ + + if(base <= 1024*1024) + low = 0; + + /* + * See how much space we could cover by filling below + * the ISA hole + */ + + if(floor == 0) + fspace = 512*1024; + else if(floor ==512*1024) + fspace = 128*1024; + + /* And forget ROM space */ + + /* + * Now install the largest coverage we get + */ + + if(fspace > high && fspace > low) + { + winchip_mcr_insert(ct, floor, fspace, key); + floor += fspace; + } + else if(high > low) + { + winchip_mcr_insert(ct, top, high, key); + top += high; + } + else if(low > 0) + { + base -= low; + winchip_mcr_insert(ct, base, low, key); + } + else break; + ct++; + } + /* + * We loaded ct values. We now need to set the mask. The caller + * must do this bit. + */ + + return ct; +} + +static void __init winchip_create_optimal_mcr(void) +{ + int i; + /* + * Allocate up to 6 mcrs to mark as much of ram as possible + * as write combining and weak write ordered. + * + * To experiment with: Linux never uses stack operations for + * mmio spaces so we could globally enable stack operation wc + * + * Load the registers with type 31 - full write combining, all + * writes weakly ordered. + */ + int used = winchip_mcr_compute(6, 31); + + /* + * Wipe unused MCRs + */ + + for(i=used;i<8;i++) + wrmsr(0x110+i, 0, 0); +} + +static void __init winchip2_create_optimal_mcr(void) +{ + u32 lo, hi; + int i; + + /* + * Allocate up to 6 mcrs to mark as much of ram as possible + * as write combining, weak store ordered. + * + * Load the registers with type 25 + * 8 - weak write ordering + * 16 - weak read ordering + * 1 - write combining + */ + + int used = winchip_mcr_compute(6, 25); + + /* + * Mark the registers we are using. + */ + + rdmsr(0x120, lo, hi); + for(i=0;i<used;i++) + lo|=1<<(9+i); + wrmsr(0x120, lo, hi); + + /* + * Wipe unused MCRs + */ + + for(i=used;i<8;i++) + wrmsr(0x110+i, 0, 0); +} + +/* + * Handle the MCR key on the Winchip 2. + */ + +static void __init winchip2_unprotect_mcr(void) +{ + u32 lo, hi; + u32 key; + + rdmsr(0x120, lo, hi); + lo&=~0x1C0; /* blank bits 8-6 */ + key = (lo>>17) & 7; + lo |= key<<6; /* replace with unlock key */ + wrmsr(0x120, lo, hi); +} + +static void __init winchip2_protect_mcr(void) +{ + u32 lo, hi; + + rdmsr(0x120, lo, hi); + lo&=~0x1C0; /* blank bits 8-6 */ + wrmsr(0x120, lo, hi); +} + +#endif + static void __init init_centaur(struct cpuinfo_x86 *c) { enum { @@ -1342,6 +1779,19 @@ fcr_clr=DPDC; printk(KERN_NOTICE "Disabling bugged TSC.\n"); clear_bit(X86_FEATURE_TSC, &c->x86_capability); +#ifdef CONFIG_X86_OOSTORE + winchip_create_optimal_mcr(); + /* Enable + write combining on non-stack, non-string + write combining on string, all types + weak write ordering + + The C6 original lacks weak read order + + Note 0x120 is write only on Winchip 1 */ + + wrmsr(0x120, 0x01F0001F, 0); +#endif break; case 8: switch(c->x86_mask) { @@ -1357,11 +1807,37 @@ } fcr_set=ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|E2MMX|EAMD3D; fcr_clr=DPDC; +#ifdef CONFIG_X86_OOSTORE + winchip2_unprotect_mcr(); + winchip2_create_optimal_mcr(); + rdmsr(0x120, lo, hi); + /* Enable + write combining on non-stack, non-string + write combining on string, all types + weak write ordering + */ + lo|=31; + wrmsr(0x120, lo, hi); + winchip2_protect_mcr(); +#endif break; case 9: name="3"; fcr_set=ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|E2MMX|EAMD3D; fcr_clr=DPDC; +#ifdef CONFIG_X86_OOSTORE + winchip2_unprotect_mcr(); + winchip2_create_optimal_mcr(); + rdmsr(0x120, lo, hi); + /* Enable + write combining on non-stack, non-string + write combining on string, all types + weak write ordering + */ + lo|=31; + wrmsr(0x120, lo, hi); + winchip2_protect_mcr(); +#endif break; case 10: name="4"; @@ -1397,11 +1873,12 @@ c->x86_cache_size = (cc>>24)+(dd>>24); } sprintf( c->x86_model_id, "WinChip %s", name ); + mcheck_init(c); break; case 6: switch (c->x86_model) { - case 6: /* Cyrix III */ + case 6 ... 7: /* Cyrix III or C3 */ rdmsr (0x1107, lo, hi); lo |= (1<<1 | 1<<7); /* Report CX8 & enable PGE */ wrmsr (0x1107, lo, hi); @@ -1411,11 +1888,13 @@ get_model_name(c); display_cacheinfo(c); + + rdmsr(0x2A, lo, hi); + interpret_eblcr(c, lo, 0); break; } break; } - } @@ -1481,6 +1960,32 @@ wrmsr(0x80860004, cap_mask, uk); } + +static void __init init_rise(struct cpuinfo_x86 *c) +{ + printk("CPU: Rise iDragon"); + if (c->x86_model > 2) + printk(" II"); + printk("\n"); + printk("If you have one of these please email davej@suse.de\n"); + + /* Unhide possibly hidden capability flags + The mp6 iDragon family don't have MSRs. + We switch on extra features with this cpuid wierdness: */ + __asm__ ( + "movl $0x6363452a, %%eax\n\t" + "movl $0x3231206c, %%ecx\n\t" + "movl $0x2a32313a, %%edx\n\t" + "cpuid\n\t" + "movl $0x63634523, %%eax\n\t" + "movl $0x32315f6c, %%ecx\n\t" + "movl $0x2333313a, %%edx\n\t" + "cpuid\n\t" : : : "eax", "ebx", "ecx", "edx" + ); + set_bit(X86_FEATURE_CX8, &c->x86_capability); +} + + extern void trap_init_f00f_bug(void); static void __init init_intel(struct cpuinfo_x86 *c) @@ -1488,7 +1993,6 @@ #ifndef CONFIG_M686 static int f00f_workaround_enabled = 0; #endif - extern void mcheck_init(struct cpuinfo_x86 *c); char *p = NULL; unsigned int l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */ @@ -1631,6 +2135,13 @@ if ( c->x86 == 6 && c->x86_model < 3 && c->x86_mask < 3 ) clear_bit(X86_FEATURE_SEP, &c->x86_capability); + if ( c->x86 == 6 && c->x86_model >= 3) + { + u32 lo, hi; + rdmsr(0x2A, lo, hi); + interpret_eblcr(c, lo, (c->x86_model >= 7) ? 1: 0); + } + /* Names for the Pentium II/Celeron processors detectable only by also checking the cache size. Dixon is NOT a Celeron. */ @@ -1732,8 +2243,8 @@ { "Nx586", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_RISE, 5, - { "mP6", "mP6", NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, + { "iDragon", NULL, "iDragon", NULL, NULL, NULL, NULL, + NULL, "iDragon II", "iDragon II", NULL, NULL, NULL, NULL, NULL, NULL }}, }; /* Look up CPU names by table lookup. */ @@ -1997,6 +2508,15 @@ case X86_VENDOR_UNKNOWN: default: /* Not much we can do here... */ + /* Check if at least it has cpuid */ + if (c->cpuid_level == -1) + { + /* No cpuid. It must be an ancient CPU */ + if (c->x86 == 4) + strcpy(c->x86_model_id, "486"); + else if (c->x86 == 3) + strcpy(c->x86_model_id, "386"); + } break; case X86_VENDOR_CYRIX: @@ -2022,6 +2542,10 @@ case X86_VENDOR_TRANSMETA: init_transmeta(c); break; + + case X86_VENDOR_RISE: + init_rise(c); + break; } printk(KERN_DEBUG "CPU: After vendor init, caps: %08x %08x %08x %08x\n", @@ -2064,7 +2588,7 @@ /* Now the feature flags better reflect actual CPU features! */ - printk(KERN_DEBUG "CPU: After generic, caps: %08x %08x %08x %08x\n", + printk(KERN_DEBUG "CPU: After generic, caps: %08x %08x %08x %08x\n", c->x86_capability[0], c->x86_capability[1], c->x86_capability[2], @@ -2082,7 +2606,7 @@ boot_cpu_data.x86_capability[i] &= c->x86_capability[i]; } - printk(KERN_DEBUG "CPU: Common caps: %08x %08x %08x %08x\n", + printk(KERN_DEBUG "CPU: Common caps: %08x %08x %08x %08x\n", boot_cpu_data.x86_capability[0], boot_cpu_data.x86_capability[1], boot_cpu_data.x86_capability[2], @@ -2135,6 +2659,7 @@ int get_cpuinfo(char * buffer) { + extern int x86_udelay_tsc; /* For 2.5 we need to push this int c-> */ char *p = buffer; /* @@ -2189,7 +2714,7 @@ c->x86, c->x86_model, c->x86_model_id[0] ? c->x86_model_id : "unknown"); - + if (c->x86_mask || c->cpuid_level >= 0) p += sprintf(p, "stepping\t: %d\n", c->x86_mask); else @@ -2232,6 +2757,7 @@ p += sprintf(p, "\nbogomips\t: %lu.%02lu\n\n", 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 linux.vanilla/arch/i386/kernel/smp.c linux.ac/arch/i386/kernel/smp.c --- linux.vanilla/arch/i386/kernel/smp.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/i386/kernel/smp.c Tue Apr 3 17:54:30 2001 @@ -429,9 +429,10 @@ atomic_t started; atomic_t finished; int wait; -}; +} __attribute__ ((__aligned__(SMP_CACHE_BYTES))); static struct call_data_struct * call_data; +static struct call_data_struct call_data_array[NR_CPUS]; /* * this function sends a 'generic call function' IPI to all other CPUs @@ -453,32 +454,45 @@ * hardware interrupt handler, you may call it from a bottom half handler. */ { - struct call_data_struct data; - int cpus = smp_num_cpus-1; + struct call_data_struct *data; + int cpus = (cpu_online_map & ~(1 << smp_processor_id())); if (!cpus) return 0; - data.func = func; - data.info = info; - atomic_set(&data.started, 0); - data.wait = wait; + data = &call_data_array[smp_processor_id()]; + + data->func = func; + data->info = info; + data->wait = wait; if (wait) - atomic_set(&data.finished, 0); - - spin_lock_bh(&call_lock); - call_data = &data; + atomic_set(&data->finished, 0); + /* We have do to this one last to make sure that the IPI service + * code desn't get confused if it gets an unexpected repeat + * trigger of an old IPI while we're still setting up the new + * one. */ + atomic_set(&data->started, 0); + + local_bh_disable(); + spin_lock(&call_lock); + call_data = data; /* Send a message to all other CPUs and wait for them to respond */ send_IPI_allbutself(CALL_FUNCTION_VECTOR); /* Wait for response */ - while (atomic_read(&data.started) != cpus) + while (atomic_read(&data->started) != cpus) barrier(); + /* It is now safe to reuse the "call_data" global, but we need + * to keep local bottom-halves disabled until after waiters have + * been acknowledged to prevent reuse of the per-cpu call data + * entry. */ + spin_unlock(&call_lock); + if (wait) - while (atomic_read(&data.finished) != cpus) + while (atomic_read(&data->finished) != cpus) barrier(); - spin_unlock_bh(&call_lock); + local_bh_enable(); return 0; } @@ -528,15 +542,17 @@ ack_APIC_irq(); /* - * Notify initiating CPU that I've grabbed the data and am - * about to execute the function + * Notify initiating CPU that I've grabbed the data and am about + * to execute the function (and avoid servicing any single IPI + * twice) */ - atomic_inc(&call_data->started); + if (test_and_set_bit(smp_processor_id(), &call_data->started)) + return; /* * At this point the info structure may be out of scope unless wait==1 */ (*func)(info); if (wait) - atomic_inc(&call_data->finished); + set_bit(smp_processor_id(), &call_data->finished); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/smpboot.c linux.ac/arch/i386/kernel/smpboot.c --- linux.vanilla/arch/i386/kernel/smpboot.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/i386/kernel/smpboot.c Tue Apr 3 17:54:30 2001 @@ -780,7 +780,6 @@ } cycles_t cacheflush_time; -extern unsigned long cpu_khz; static void smp_tune_scheduling (void) { @@ -870,12 +869,15 @@ * get out of here now! */ if (!smp_found_config) { - printk(KERN_NOTICE "SMP motherboard not detected. Using dummy APIC emulation.\n"); + printk(KERN_NOTICE "SMP motherboard not detected.\n"); #ifndef CONFIG_VISWS io_apic_irqs = 0; #endif cpu_online_map = phys_cpu_present_map = 1; smp_num_cpus = 1; + if (APIC_init_uniprocessor()) + printk(KERN_NOTICE "Local APIC not detected." + " Using dummy APIC emulation.\n"); goto smp_done; } @@ -1003,7 +1005,7 @@ * Here we can be sure that there is an IO-APIC in the system. Let's * go and set it up: */ - if (!skip_ioapic_setup) + if (!skip_ioapic_setup && nr_ioapics) setup_IO_APIC(); #endif @@ -1021,4 +1023,3 @@ smp_done: zap_low_mappings(); } - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/time.c linux.ac/arch/i386/kernel/time.c --- linux.vanilla/arch/i386/kernel/time.c Fri Dec 29 22:07:57 2000 +++ linux.ac/arch/i386/kernel/time.c Tue Apr 3 17:54:30 2001 @@ -178,6 +178,15 @@ jiffies_t = jiffies; count |= inb_p(0x40) << 8; + + /* VIA686a test code... reset the latch if count > max */ + if (count > LATCH-1) { + outb_p(0x34, 0x43); + outb_p(LATCH & 0xff, 0x40); + outb(LATCH >> 8, 0x40); + count = LATCH - 1; + } + spin_unlock(&i8253_lock); /* @@ -413,7 +422,7 @@ if (!user_mode(regs)) x86_do_profile(regs->eip); #else - if (!smp_found_config) + if (!using_apic_timer) smp_local_timer_interrupt(regs); #endif @@ -492,6 +501,24 @@ count = inb_p(0x40); /* read the latched count */ count |= inb(0x40) << 8; + + + /* VIA686a test code... reset the latch if count > max */ + if (count > LATCH-1) { + static int last_whine; + outb_p(0x34, 0x43); + outb_p(LATCH & 0xff, 0x40); + outb(LATCH >> 8, 0x40); + count = LATCH - 1; + if(time_after(jiffies, last_whine)) + { + printk(KERN_WARNING "probable hardware bug: clock timer configuration lost - probably a VIA686a motherboard.\n"); + printk(KERN_WARNING "probable hardware bug: restoring chip configuration.\n"); + last_whine = jiffies + HZ; + } + } + + spin_unlock(&i8253_lock); count = ((LATCH-1) - count) * TICK_SIZE; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/traps.c linux.ac/arch/i386/kernel/traps.c --- linux.vanilla/arch/i386/kernel/traps.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/i386/kernel/traps.c Tue Apr 3 17:54:30 2001 @@ -63,8 +63,6 @@ */ struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, }; -extern void bust_spinlocks(void); - asmlinkage void divide_error(void); asmlinkage void debug(void); asmlinkage void nmi(void); @@ -129,7 +127,7 @@ void show_trace_task(struct task_struct *tsk) { - show_trace(&tsk->thread.esp); + show_trace((unsigned long *)(tsk->thread.esp)); } void show_stack(unsigned long * esp) @@ -155,7 +153,7 @@ show_trace(esp); } -static void show_registers(struct pt_regs *regs) +void show_registers(struct pt_regs *regs) { int i; int in_kernel = 1; @@ -212,9 +210,10 @@ { console_verbose(); spin_lock_irq(&die_lock); + bust_spinlocks(1); printk("%s: %04lx\n", str, err & 0xffff); show_registers(regs); - + bust_spinlocks(0); spin_unlock_irq(&die_lock); do_exit(SIGSEGV); } @@ -234,7 +233,7 @@ return address; } -static void inline do_trap(int trapnr, int signr, char *str, int vm86, +static inline void do_trap(int trapnr, int signr, char *str, int vm86, struct pt_regs * regs, long error_code, siginfo_t *info) { if (vm86 && regs->eflags & VM_MASK) @@ -386,83 +385,14 @@ printk("Do you have a strange power saving mode enabled?\n"); } -#if CONFIG_X86_IO_APIC - -int nmi_watchdog = 0; - -static int __init setup_nmi_watchdog(char *str) -{ - get_option(&str, &nmi_watchdog); - return 1; -} - -__setup("nmi_watchdog=", setup_nmi_watchdog); - -static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED; - -inline void nmi_watchdog_tick(struct pt_regs * regs) -{ - /* - * the best way to detect wether a CPU has a 'hard lockup' problem - * is to check it's local APIC timer IRQ counts. If they are not - * changing then that CPU has some problem. - * - * as these watchdog NMI IRQs are broadcasted to every CPU, here - * we only have to check the current processor. - * - * since NMIs dont listen to _any_ locks, we have to be extremely - * careful not to rely on unsafe variables. The printk might lock - * up though, so we have to break up console_lock first ... - * [when there will be more tty-related locks, break them up - * here too!] - */ - - static unsigned int last_irq_sums [NR_CPUS], - alert_counter [NR_CPUS]; - - /* - * Since current-> is always on the stack, and we always switch - * the stack NMI-atomically, it's safe to use smp_processor_id(). - */ - int sum, cpu = smp_processor_id(); - - sum = apic_timer_irqs[cpu]; - - if (last_irq_sums[cpu] == sum) { - /* - * Ayiee, looks like this CPU is stuck ... - * wait a few IRQs (5 seconds) before doing the oops ... - */ - alert_counter[cpu]++; - if (alert_counter[cpu] == 5*HZ) { - spin_lock(&nmi_print_lock); - /* - * We are in trouble anyway, lets at least try - * to get a message out. - */ - bust_spinlocks(); - printk("NMI Watchdog detected LOCKUP on CPU%d, registers:\n", cpu); - show_registers(regs); - printk("console shuts up ...\n"); - console_silent(); - spin_unlock(&nmi_print_lock); - do_exit(SIGSEGV); - } - } else { - last_irq_sums[cpu] = sum; - alert_counter[cpu] = 0; - } -} -#endif - asmlinkage void do_nmi(struct pt_regs * regs, long error_code) { unsigned char reason = inb(0x61); - ++nmi_count(smp_processor_id()); + if (!(reason & 0xc0)) { -#if CONFIG_X86_IO_APIC +#if CONFIG_X86_LOCAL_APIC /* * Ok, so this is none of the documented NMI sources, * so it must be the NMI watchdog. @@ -470,11 +400,9 @@ if (nmi_watchdog) { nmi_watchdog_tick(regs); return; - } else - unknown_nmi_error(reason, regs); -#else - unknown_nmi_error(reason, regs); + } #endif + unknown_nmi_error(reason, regs); return; } if (reason & 0x80) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/lib/Makefile linux.ac/arch/i386/lib/Makefile --- linux.vanilla/arch/i386/lib/Makefile Fri Dec 29 22:07:20 2000 +++ linux.ac/arch/i386/lib/Makefile Sat Apr 14 01:17:45 2001 @@ -8,10 +8,11 @@ L_TARGET = lib.a obj-y = checksum.o old-checksum.o delay.o \ - usercopy.o getuser.o putuser.o iodebug.o \ - memcpy.o + usercopy.o getuser.o putuser.o \ + memcpy.o strstr.o rwsem.o obj-$(CONFIG_X86_USE_3DNOW) += mmx.o obj-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o +obj-$(CONFIG_DEBUG_IOVIRT) += iodebug.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/lib/mmx.c linux.ac/arch/i386/lib/mmx.c --- linux.vanilla/arch/i386/lib/mmx.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/i386/lib/mmx.c Sun Apr 15 16:49:54 2001 @@ -1,3 +1,4 @@ +#include <linux/config.h> #include <linux/types.h> #include <linux/string.h> #include <linux/sched.h> @@ -5,6 +6,7 @@ #include <asm/i387.h> #include <asm/hardirq.h> + /* * MMX 3DNow! library helper functions * @@ -95,6 +97,13 @@ return p; } +#ifdef CONFIG_MK7 + +/* + * The K7 has streaming cache bypass load/store. The Cyrix III, K6 and + * other MMX using processors do not. + */ + static void fast_clear_page(void *page) { int i; @@ -194,6 +203,110 @@ ); kernel_fpu_end(); } + +#else + +/* + * Generic MMX implementation without K7 specific streaming + */ + +static void fast_clear_page(void *page) +{ + int i; + + kernel_fpu_begin(); + + __asm__ __volatile__ ( + " pxor %%mm0, %%mm0\n" : : + ); + + for(i=0;i<4096/128;i++) + { + __asm__ __volatile__ ( + " movq %%mm0, (%0)\n" + " movq %%mm0, 8(%0)\n" + " movq %%mm0, 16(%0)\n" + " movq %%mm0, 24(%0)\n" + " movq %%mm0, 32(%0)\n" + " movq %%mm0, 40(%0)\n" + " movq %%mm0, 48(%0)\n" + " movq %%mm0, 56(%0)\n" + " movq %%mm0, 64(%0)\n" + " movq %%mm0, 72(%0)\n" + " movq %%mm0, 80(%0)\n" + " movq %%mm0, 88(%0)\n" + " movq %%mm0, 96(%0)\n" + " movq %%mm0, 104(%0)\n" + " movq %%mm0, 112(%0)\n" + " movq %%mm0, 120(%0)\n" + : : "r" (page) : "memory"); + page+=128; + } + + kernel_fpu_end(); +} + +static void fast_copy_page(void *to, void *from) +{ + int i; + + + kernel_fpu_begin(); + + __asm__ __volatile__ ( + "1: prefetch (%0)\n" + " prefetch 64(%0)\n" + " prefetch 128(%0)\n" + " prefetch 192(%0)\n" + " prefetch 256(%0)\n" + "2: \n" + ".section .fixup, \"ax\"\n" + "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b, 3b\n" + ".previous" + : : "r" (from) ); + + for(i=0; i<4096/64; i++) + { + __asm__ __volatile__ ( + "1: prefetch 320(%0)\n" + "2: movq (%0), %%mm0\n" + " movq 8(%0), %%mm1\n" + " movq 16(%0), %%mm2\n" + " movq 24(%0), %%mm3\n" + " movq %%mm0, (%1)\n" + " movq %%mm1, 8(%1)\n" + " movq %%mm2, 16(%1)\n" + " movq %%mm3, 24(%1)\n" + " movq 32(%0), %%mm0\n" + " movq 40(%0), %%mm1\n" + " movq 48(%0), %%mm2\n" + " movq 56(%0), %%mm3\n" + " movq %%mm0, 32(%1)\n" + " movq %%mm1, 40(%1)\n" + " movq %%mm2, 48(%1)\n" + " movq %%mm3, 56(%1)\n" + ".section .fixup, \"ax\"\n" + "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b, 3b\n" + ".previous" + : : "r" (from), "r" (to) : "memory"); + from+=64; + to+=64; + } + kernel_fpu_end(); +} + + +#endif /* * Favour MMX for page clear and copy. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/lib/rwsem.S linux.ac/arch/i386/lib/rwsem.S --- linux.vanilla/arch/i386/lib/rwsem.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/i386/lib/rwsem.S Sat Apr 14 01:17:45 2001 @@ -0,0 +1,36 @@ +/* rwsem.S: R/W semaphores, register saving wrapper function stubs + * + * Written by David Howells (dhowells@redhat.com). + * Derived from arch/i386/kernel/semaphore.c + */ + +.text +.align 4 +.globl __rwsem_down_read_failed +__rwsem_down_read_failed: + pushl %edx + pushl %ecx + call rwsem_down_read_failed + popl %ecx + popl %edx + ret + +.align 4 +.globl __rwsem_down_write_failed +__rwsem_down_write_failed: + pushl %edx + pushl %ecx + call rwsem_down_write_failed + popl %ecx + popl %edx + ret + +.align 4 +.globl __rwsem_wake +__rwsem_wake: + pushl %edx + pushl %ecx + call rwsem_wake + popl %ecx + popl %edx + ret diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/lib/strstr.c linux.ac/arch/i386/lib/strstr.c --- linux.vanilla/arch/i386/lib/strstr.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/i386/lib/strstr.c Tue Apr 10 18:07:22 2001 @@ -0,0 +1,31 @@ +#include <linux/string.h> + +char * strstr(const char * cs,const char * ct) +{ +int d0, d1; +register char * __res; +__asm__ __volatile__( + "movl %6,%%edi\n\t" + "repne\n\t" + "scasb\n\t" + "notl %%ecx\n\t" + "decl %%ecx\n\t" /* NOTE! This also sets Z if searchstring='' */ + "movl %%ecx,%%edx\n" + "1:\tmovl %6,%%edi\n\t" + "movl %%esi,%%eax\n\t" + "movl %%edx,%%ecx\n\t" + "repe\n\t" + "cmpsb\n\t" + "je 2f\n\t" /* also works for empty string, see above */ + "xchgl %%eax,%%esi\n\t" + "incl %%esi\n\t" + "cmpb $0,-1(%%eax)\n\t" + "jne 1b\n\t" + "xorl %%eax,%%eax\n\t" + "2:" + :"=a" (__res), "=&c" (d0), "=&S" (d1) + :"0" (0), "1" (0xffffffff), "2" (cs), "g" (ct) + :"dx", "di"); +return __res; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/lib/usercopy.c linux.ac/arch/i386/lib/usercopy.c --- linux.vanilla/arch/i386/lib/usercopy.c Fri Nov 12 12:29:47 1999 +++ linux.ac/arch/i386/lib/usercopy.c Thu Apr 12 12:11:35 2001 @@ -34,6 +34,8 @@ else mmx_copy_user_zeroing(to, from, n); } + else + memset(to, 0, n); return n; } @@ -52,6 +54,8 @@ { if (access_ok(VERIFY_READ, from, n)) __copy_user_zeroing(to,from,n); + else + memset(to, 0, n); return n; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/control_w.h linux.ac/arch/i386/math-emu/control_w.h --- linux.vanilla/arch/i386/math-emu/control_w.h Thu Jun 29 16:25:27 1995 +++ linux.ac/arch/i386/math-emu/control_w.h Tue Apr 10 18:07:47 2001 @@ -42,4 +42,4 @@ /* FULL_PRECISION simulates all exceptions masked */ #define FULL_PRECISION (PR_64_BITS | RC_RND | 0x3f) -#endif _CONTROLW_H_ +#endif /* _CONTROLW_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/div_Xsig.S linux.ac/arch/i386/math-emu/div_Xsig.S --- linux.vanilla/arch/i386/math-emu/div_Xsig.S Fri Aug 27 18:18:17 1999 +++ linux.ac/arch/i386/math-emu/div_Xsig.S Tue Apr 10 18:07:47 2001 @@ -70,7 +70,7 @@ .long 0 FPU_result_1: .long 0 -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ .text @@ -79,7 +79,7 @@ movl %esp,%ebp #ifndef NON_REENTRANT_FPU subl $28,%esp -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ pushl %esi pushl %edi @@ -91,7 +91,7 @@ #ifdef PARANOID testl $0x80000000, XsigH(%ebx) /* Divisor */ je L_bugged -#endif PARANOID +#endif /* PARANOID */ /*---------------------------------------------------------------------------+ @@ -164,7 +164,7 @@ #ifdef PARANOID jb L_bugged_1 -#endif PARANOID +#endif /* PARANOID */ /* need to subtract another once of the denom */ incl FPU_result_3 /* Correct the answer */ @@ -177,7 +177,7 @@ #ifdef PARANOID sbbl $0,FPU_accum_3 jne L_bugged_1 /* Must check for non-zero result here */ -#endif PARANOID +#endif /* PARANOID */ /*----------------------------------------------------------------------*/ /* Half of the main problem is done, there is just a reduced numerator @@ -207,7 +207,7 @@ #ifdef PARANOID je L_bugged_2 /* Can't bump the result to 1.0 */ -#endif PARANOID +#endif /* PARANOID */ LDo_2nd_div: cmpl $0,%ecx /* augmented denom msw */ @@ -230,7 +230,7 @@ #ifdef PARANOID jc L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ movl FPU_result_2,%eax /* Get the result back */ mull XsigL(%ebx) /* now mul the ls dw of the denom */ @@ -241,14 +241,14 @@ #ifdef PARANOID jc L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ jz LDo_3rd_32_bits #ifdef PARANOID cmpl $1,FPU_accum_2 jne L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ /* need to subtract another once of the denom */ movl XsigL(%ebx),%eax @@ -260,14 +260,14 @@ #ifdef PARANOID jc L_bugged_2 jne L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ addl $1,FPU_result_2 /* Correct the answer */ adcl $0,FPU_result_3 #ifdef PARANOID jc L_bugged_2 /* Must check for non-zero result here */ -#endif PARANOID +#endif /* PARANOID */ /*----------------------------------------------------------------------*/ /* The division is essentially finished here, we just need to perform @@ -362,4 +362,4 @@ call EXCEPTION pop %ebx jmp L_exit -#endif PARANOID +#endif /* PARANOID */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/errors.c linux.ac/arch/i386/math-emu/errors.c --- linux.vanilla/arch/i386/math-emu/errors.c Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/errors.c Tue Apr 10 18:07:47 2001 @@ -141,7 +141,7 @@ if ( partial_status & SW_Zero_Div ) printk("SW: divide by zero\n"); if ( partial_status & SW_Denorm_Op ) printk("SW: denormalized operand\n"); if ( partial_status & SW_Invalid ) printk("SW: invalid operation\n"); -#endif DEBUGGING +#endif /* DEBUGGING */ printk(" SW: b=%d st=%ld es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n", partial_status & 0x8000 ? 1 : 0, /* busy */ @@ -327,7 +327,7 @@ #ifdef PRINT_MESSAGES /* My message from the sponsor */ printk(FPU_VERSION" "__DATE__" (C) W. Metzenthen.\n"); -#endif PRINT_MESSAGES +#endif /* PRINT_MESSAGES */ /* Get a name string for error reporting */ for (i=0; exception_names[i].type; i++) @@ -338,7 +338,7 @@ { #ifdef PRINT_MESSAGES printk("FP Exception: %s!\n", exception_names[i].name); -#endif PRINT_MESSAGES +#endif /* PRINT_MESSAGES */ } else printk("FPU emulator: Unknown Exception: 0x%04x!\n", n); @@ -351,7 +351,7 @@ #ifdef PRINT_MESSAGES else FPU_printall(); -#endif PRINT_MESSAGES +#endif /* PRINT_MESSAGES */ /* * The 80486 generates an interrupt on the next non-control FPU @@ -363,7 +363,7 @@ #ifdef __DEBUG__ math_abort(FPU_info,SIGFPE); -#endif __DEBUG__ +#endif /* __DEBUG__ */ } @@ -469,7 +469,7 @@ else #ifdef PARANOID if (tagb == TW_NaN) -#endif PARANOID +#endif /* PARANOID */ { signalling = !(b->sigh & 0x40000000); x = b; @@ -481,7 +481,7 @@ EXCEPTION(EX_INTERNAL|0x113); x = &CONST_QNaN; } -#endif PARANOID +#endif /* PARANOID */ if ( (!signalling) || (control_word & CW_Invalid) ) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/exception.h linux.ac/arch/i386/math-emu/exception.h --- linux.vanilla/arch/i386/math-emu/exception.h Mon Dec 11 21:34:33 2000 +++ linux.ac/arch/i386/math-emu/exception.h Tue Apr 10 18:07:47 2001 @@ -18,7 +18,7 @@ #ifndef SW_C1 #include "fpu_emu.h" -#endif SW_C1 +#endif /* SW_C1 */ #define FPU_BUSY Const_(0x8000) /* FPU busy bit (8087 compatibility) */ #define EX_ErrorSummary Const_(0x0080) /* Error summary status */ @@ -48,6 +48,6 @@ #define EXCEPTION(x) FPU_exception(x) #endif -#endif __ASSEMBLY__ +#endif /* __ASSEMBLY__ */ -#endif _EXCEPTION_H_ +#endif /* _EXCEPTION_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/fpu_asm.h linux.ac/arch/i386/math-emu/fpu_asm.h --- linux.vanilla/arch/i386/math-emu/fpu_asm.h Mon Dec 11 21:34:33 2000 +++ linux.ac/arch/i386/math-emu/fpu_asm.h Tue Apr 10 18:07:47 2001 @@ -29,4 +29,4 @@ #define SIGL(x) SIGL_OFFSET##(x) #define SIGH(x) 4(x) -#endif _FPU_ASM_H_ +#endif /* _FPU_ASM_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/fpu_emu.h linux.ac/arch/i386/math-emu/fpu_emu.h --- linux.vanilla/arch/i386/math-emu/fpu_emu.h Mon Dec 11 21:34:33 2000 +++ linux.ac/arch/i386/math-emu/fpu_emu.h Tue Apr 10 18:07:47 2001 @@ -88,7 +88,7 @@ #else # define RE_ENTRANT_CHECK_OFF # define RE_ENTRANT_CHECK_ON -#endif RE_ENTRANT_CHECKING +#endif /* RE_ENTRANT_CHECKING */ #define FWAIT_OPCODE 0x9b #define OP_SIZE_PREFIX 0x66 @@ -212,6 +212,6 @@ #include "fpu_proto.h" #endif -#endif __ASSEMBLY__ +#endif /* __ASSEMBLY__ */ -#endif _FPU_EMU_H_ +#endif /* _FPU_EMU_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/fpu_entry.c linux.ac/arch/i386/math-emu/fpu_entry.c --- linux.vanilla/arch/i386/math-emu/fpu_entry.c Tue Jun 20 02:10:44 2000 +++ linux.ac/arch/i386/math-emu/fpu_entry.c Tue Apr 10 18:07:47 2001 @@ -78,7 +78,7 @@ fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__, }; -#endif NO_UNDOC_CODE +#endif /* NO_UNDOC_CODE */ #define _NONE_ 0 /* Take no special action */ @@ -120,12 +120,12 @@ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_ }; -#endif NO_UNDOC_CODE +#endif /* NO_UNDOC_CODE */ #ifdef RE_ENTRANT_CHECKING u_char emulating=0; -#endif RE_ENTRANT_CHECKING +#endif /* RE_ENTRANT_CHECKING */ static int valid_prefix(u_char *Byte, u_char **fpu_eip, overrides *override); @@ -152,7 +152,7 @@ printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n"); } RE_ENTRANT_CHECK_ON; -#endif RE_ENTRANT_CHECKING +#endif /* RE_ENTRANT_CHECKING */ if (!current->used_math) { @@ -251,7 +251,7 @@ #ifdef PARANOID EXCEPTION(EX_INTERNAL|0x128); math_abort(FPU_info,SIGILL); -#endif PARANOID +#endif /* PARANOID */ } RE_ENTRANT_CHECK_OFF; @@ -386,7 +386,7 @@ /* fdiv or fsub */ real_2op_NaN(&loaded_data, loaded_tag, 0, &loaded_data); else -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ /* fadd, fdivr, fmul, or fsubr */ real_2op_NaN(&loaded_data, loaded_tag, 0, st0_ptr); } @@ -497,7 +497,7 @@ to do this: */ operand_address.offset = 0; operand_address.selector = FPU_DS; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ st0_ptr = &st(0); st0_tag = FPU_gettag0(); @@ -557,7 +557,7 @@ RE_ENTRANT_CHECK_OFF; FPU_printall(); RE_ENTRANT_CHECK_ON; -#endif DEBUG +#endif /* DEBUG */ if (FPU_lookahead && !current->need_resched) { @@ -669,7 +669,7 @@ __asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4)); #ifdef PARANOID printk("ERROR: wm-FPU-emu math_abort failed!\n"); -#endif PARANOID +#endif /* PARANOID */ } @@ -739,7 +739,7 @@ S387->twd |= 0xffff0000; S387->fcs &= ~0xf8000000; S387->fos |= 0xffff0000; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ __copy_to_user(d, &S387->cwd, 7*4); RE_ENTRANT_CHECK_ON; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/fpu_etc.c linux.ac/arch/i386/math-emu/fpu_etc.c --- linux.vanilla/arch/i386/math-emu/fpu_etc.c Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/fpu_etc.c Tue Apr 10 18:07:47 2001 @@ -68,7 +68,7 @@ /* This is weird! */ if (getsign(st0_ptr) == SIGN_POS) setcc(SW_C3); -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ return; } break; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/fpu_trig.c linux.ac/arch/i386/math-emu/fpu_trig.c --- linux.vanilla/arch/i386/math-emu/fpu_trig.c Thu Nov 4 17:10:22 1999 +++ linux.ac/arch/i386/math-emu/fpu_trig.c Tue Apr 10 18:07:47 2001 @@ -98,7 +98,7 @@ q++; } } -#endif BETTER_THAN_486 +#endif /* BETTER_THAN_486 */ } #ifdef BETTER_THAN_486 else @@ -138,7 +138,7 @@ } } } -#endif BETTER_THAN_486 +#endif /* BETTER_THAN_486 */ FPU_settag0(st0_tag); control_word = old_cw; @@ -186,7 +186,7 @@ #ifdef PARANOID else EXCEPTION(EX_INTERNAL|0x0112); -#endif PARANOID +#endif /* PARANOID */ } @@ -232,7 +232,7 @@ #ifdef PARANOID default: EXCEPTION(EX_INTERNAL|0x0112); -#endif PARANOID +#endif /* PARANOID */ } } @@ -463,7 +463,7 @@ #ifdef PARANOID else EXCEPTION(EX_INTERNAL | 0x119); -#endif PARANOID +#endif /* PARANOID */ } @@ -716,7 +716,7 @@ set_precision_flag_down(); /* 80486 appears to do this. */ #else set_precision_flag_up(); /* Must be up. */ -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ return 0; } } @@ -1008,7 +1008,7 @@ setcc(SW_C2); #else setcc(0); -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ return; } cc = SW_C2; @@ -1114,7 +1114,7 @@ #ifdef PARANOID if ( (st0_tag != TW_NaN) && (st1_tag != TW_NaN) ) EXCEPTION(EX_INTERNAL | 0x118); -#endif PARANOID +#endif /* PARANOID */ real_2op_NaN(st1_ptr, st1_tag, 0, st1_ptr); @@ -1315,7 +1315,7 @@ sign = getsign(st1_ptr); if ( FPU_divide_by_zero(1, sign) < 0 ) return; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ changesign(st1_ptr); } @@ -1451,7 +1451,7 @@ #ifdef PARANOID else EXCEPTION(EX_INTERNAL | 0x125); -#endif PARANOID +#endif /* PARANOID */ FPU_pop(); set_precision_flag_up(); /* We do not really know if up or down */ @@ -1542,7 +1542,7 @@ #ifdef PARANOID EXCEPTION(EX_INTERNAL | 0x116); return; -#endif PARANOID +#endif /* PARANOID */ } } else if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) ) @@ -1560,7 +1560,7 @@ #else if ( arith_invalid(1) < 0 ) return; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ } else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; @@ -1583,7 +1583,7 @@ changesign(st1_ptr); #else if ( arith_invalid(1) < 0 ) return; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ } else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; @@ -1618,14 +1618,14 @@ /* This should have higher priority than denormals, but... */ if ( arith_invalid(1) < 0 ) /* log(-infinity) */ return; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) ) return; #ifdef PECULIAR_486 /* Denormal operands actually get higher priority */ if ( arith_invalid(1) < 0 ) /* log(-infinity) */ return; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ } else if ( st1_tag == TAG_Zero ) { @@ -1654,7 +1654,7 @@ EXCEPTION(EX_INTERNAL | 0x117); return; } -#endif PARANOID +#endif /* PARANOID */ FPU_pop(); return; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/get_address.c linux.ac/arch/i386/math-emu/get_address.c --- linux.vanilla/arch/i386/math-emu/get_address.c Mon Jun 19 20:56:08 2000 +++ linux.ac/arch/i386/math-emu/get_address.c Tue Apr 10 18:07:47 2001 @@ -143,7 +143,7 @@ EXCEPTION(EX_INTERNAL|0x130); math_abort(FPU_info,SIGSEGV); } -#endif PARANOID +#endif /* PARANOID */ addr->selector = VM86_REG_(segment); return (unsigned long)VM86_REG_(segment) << 4; } @@ -166,7 +166,7 @@ EXCEPTION(EX_INTERNAL|0x132); math_abort(FPU_info,SIGSEGV); } -#endif PARANOID +#endif /* PARANOID */ switch ( segment ) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/load_store.c linux.ac/arch/i386/math-emu/load_store.c --- linux.vanilla/arch/i386/math-emu/load_store.c Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/load_store.c Tue Apr 10 18:07:47 2001 @@ -85,7 +85,7 @@ #ifdef PARANOID else EXCEPTION(EX_INTERNAL|0x140); -#endif PARANOID +#endif /* PARANOID */ } switch ( type_table[type] ) @@ -112,7 +112,7 @@ default: EXCEPTION(EX_INTERNAL|0x141); return 0; -#endif PARANOID +#endif /* PARANOID */ } switch ( type ) @@ -217,7 +217,7 @@ partial_status &= ~(SW_Summary | SW_Backward); #ifdef PECULIAR_486 control_word |= 0x40; /* An 80486 appears to always set this bit */ -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ return 1; case 025: /* fld m80real */ clear_C1(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/poly.h linux.ac/arch/i386/math-emu/poly.h --- linux.vanilla/arch/i386/math-emu/poly.h Thu Nov 4 17:10:22 1999 +++ linux.ac/arch/i386/math-emu/poly.h Tue Apr 10 18:07:47 2001 @@ -118,4 +118,4 @@ :"=g" (*x):"g" (x):"si","ax","cx"); } -#endif _POLY_H +#endif /* _POLY_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/poly_2xm1.c linux.ac/arch/i386/math-emu/poly_2xm1.c --- linux.vanilla/arch/i386/math-emu/poly_2xm1.c Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/poly_2xm1.c Tue Apr 10 18:07:47 2001 @@ -67,7 +67,7 @@ EXCEPTION(EX_INTERNAL|0x127); return 1; } -#endif PARANOID +#endif /* PARANOID */ argSignif.lsw = 0; XSIG_LL(argSignif) = Xll = significand(arg); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/poly_atan.c linux.ac/arch/i386/math-emu/poly_atan.c --- linux.vanilla/arch/i386/math-emu/poly_atan.c Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/poly_atan.c Tue Apr 10 18:07:47 2001 @@ -124,7 +124,7 @@ EXCEPTION(EX_INTERNAL|0x104); /* There must be a logic error */ return; } -#endif PARANOID +#endif /* PARANOID */ argSignif.msw = 0; /* Make the transformed arg -> 0.0 */ } else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/poly_l2.c linux.ac/arch/i386/math-emu/poly_l2.c --- linux.vanilla/arch/i386/math-emu/poly_l2.c Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/poly_l2.c Tue Apr 10 18:07:47 2001 @@ -157,7 +157,7 @@ #else if ( arith_invalid(1) < 0 ) return 1; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ } /* 80486 appears to do this */ @@ -243,7 +243,7 @@ /* The argument is too large */ } } -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ arg_signif.lsw = argSignif.lsw; XSIG_LL(arg_signif) = XSIG_LL(argSignif); adj = norm_Xsig(&argSignif); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/poly_sin.c linux.ac/arch/i386/math-emu/poly_sin.c --- linux.vanilla/arch/i386/math-emu/poly_sin.c Thu Nov 4 17:10:22 1999 +++ linux.ac/arch/i386/math-emu/poly_sin.c Tue Apr 10 18:07:47 2001 @@ -199,7 +199,7 @@ { EXCEPTION(EX_INTERNAL|0x150); } -#endif PARANOID +#endif /* PARANOID */ } @@ -224,7 +224,7 @@ FPU_copy_to_reg0(&CONST_QNaN, TAG_Special); return; } -#endif PARANOID +#endif /* PARANOID */ exponent = exponent(st0_ptr); @@ -392,6 +392,6 @@ { EXCEPTION(EX_INTERNAL|0x151); } -#endif PARANOID +#endif /* PARANOID */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/poly_tan.c linux.ac/arch/i386/math-emu/poly_tan.c --- linux.vanilla/arch/i386/math-emu/poly_tan.c Wed Jul 5 18:56:13 2000 +++ linux.ac/arch/i386/math-emu/poly_tan.c Tue Apr 10 18:07:47 2001 @@ -66,7 +66,7 @@ #ifdef PARANOID if ( signnegative(st0_ptr) ) /* Can't hack a number < 0.0 */ { arith_invalid(0); return; } /* Need a positive number */ -#endif PARANOID +#endif /* PARANOID */ /* Split the problem into two domains, smaller and larger than pi/4 */ if ( (exponent == 0) || ((exponent == -1) && (st0_ptr->sigh > 0xc90fdaa2)) ) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/reg_compare.c linux.ac/arch/i386/math-emu/reg_compare.c --- linux.vanilla/arch/i386/math-emu/reg_compare.c Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/reg_compare.c Tue Apr 10 18:07:47 2001 @@ -136,7 +136,7 @@ #ifdef PARANOID if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid); if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid); -#endif PARANOID +#endif /* PARANOID */ diff = exp0 - expb; if ( diff == 0 ) @@ -203,7 +203,7 @@ EXCEPTION(EX_INTERNAL|0x121); f = SW_C3 | SW_C2 | SW_C0; break; -#endif PARANOID +#endif /* PARANOID */ } setcc(f); if (c & COMP_Denormal) @@ -255,7 +255,7 @@ EXCEPTION(EX_INTERNAL|0x122); f = SW_C3 | SW_C2 | SW_C0; break; -#endif PARANOID +#endif /* PARANOID */ } setcc(f); if (c & COMP_Denormal) @@ -312,7 +312,7 @@ EXCEPTION(EX_INTERNAL|0x123); f = SW_C3 | SW_C2 | SW_C0; break; -#endif PARANOID +#endif /* PARANOID */ } setcc(f); if (c & COMP_Denormal) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/reg_constant.h linux.ac/arch/i386/math-emu/reg_constant.h --- linux.vanilla/arch/i386/math-emu/reg_constant.h Mon Dec 11 21:34:34 2000 +++ linux.ac/arch/i386/math-emu/reg_constant.h Tue Apr 10 18:07:47 2001 @@ -28,4 +28,4 @@ extern FPU_REG const CONST_MINF; extern FPU_REG const CONST_QNaN; -#endif _REG_CONSTANT_H_ +#endif /* _REG_CONSTANT_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/reg_divide.c linux.ac/arch/i386/math-emu/reg_divide.c --- linux.vanilla/arch/i386/math-emu/reg_divide.c Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/reg_divide.c Tue Apr 10 18:07:47 2001 @@ -201,6 +201,6 @@ EXCEPTION(EX_INTERNAL|0x102); return FPU_Exception; } -#endif PARANOID +#endif /* PARANOID */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/reg_ld_str.c linux.ac/arch/i386/math-emu/reg_ld_str.c --- linux.vanilla/arch/i386/math-emu/reg_ld_str.c Sun Jan 25 19:01:48 1998 +++ linux.ac/arch/i386/math-emu/reg_ld_str.c Tue Apr 10 18:07:47 2001 @@ -439,7 +439,7 @@ converts to decide underflow. */ if ( !((tmp.sigh == 0x00100000) && (tmp.sigl == 0) && (st0_ptr->sigl & 0x000007ff)) ) -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ { EXCEPTION(EX_Underflow); /* This is a special case: see sec 16.2.5.1 of @@ -559,7 +559,7 @@ /* Underflow has priority. */ if ( control_word & CW_Underflow ) denormal_operand(); -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ reg_copy(st0_ptr, &tmp); goto denormal_arg; } @@ -659,7 +659,7 @@ converts to decide underflow. */ if ( !((tmp.sigl == 0x00800000) && ((st0_ptr->sigh & 0x000000ff) || st0_ptr->sigl)) ) -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ { EXCEPTION(EX_Underflow); /* This is a special case: see sec 16.2.5.1 of @@ -776,7 +776,7 @@ /* Underflow has priority. */ if ( control_word & CW_Underflow ) denormal_operand(); -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ goto denormal_arg; } else if (st0_tag == TW_Infinity) @@ -1221,7 +1221,7 @@ #ifdef PECULIAR_486 control_word &= ~0xe080; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ top = (partial_status >> SW_Top_Shift) & 7; @@ -1303,7 +1303,7 @@ FPU_put_user(control_word & ~0xe080, (unsigned long *) d); #else FPU_put_user(control_word, (unsigned short *) d); -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ FPU_put_user(status_word(), (unsigned short *) (d+2)); FPU_put_user(fpu_tag_word, (unsigned short *) (d+4)); FPU_put_user(instruction_address.offset, (unsigned short *) (d+6)); @@ -1335,7 +1335,7 @@ fpu_tag_word |= 0xffff0000; I387.soft.fcs &= ~0xf8000000; I387.soft.fos |= 0xffff0000; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ __copy_to_user(d, &control_word, 7*4); RE_ENTRANT_CHECK_ON; d += 0x1c; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/reg_mul.c linux.ac/arch/i386/math-emu/reg_mul.c --- linux.vanilla/arch/i386/math-emu/reg_mul.c Wed Jun 24 22:30:08 1998 +++ linux.ac/arch/i386/math-emu/reg_mul.c Tue Apr 10 18:07:47 2001 @@ -126,6 +126,6 @@ EXCEPTION(EX_INTERNAL|0x102); return FPU_Exception; } -#endif PARANOID +#endif /* PARANOID */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/reg_round.S linux.ac/arch/i386/math-emu/reg_round.S --- linux.vanilla/arch/i386/math-emu/reg_round.S Thu Nov 4 17:10:22 1999 +++ linux.ac/arch/i386/math-emu/reg_round.S Tue Apr 10 18:07:47 2001 @@ -100,7 +100,7 @@ .byte 0 FPU_denormal: .byte 0 -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ .text @@ -126,13 +126,13 @@ #ifndef NON_REENTRANT_FPU pushl %ebx /* adjust the stack pointer */ -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ #ifdef PARANOID /* Cannot use this here yet */ /* orl %eax,%eax */ /* jns L_entry_bugged */ -#endif PARANOID +#endif /* PARANOID */ cmpw EXP_UNDER,EXP(%edi) jle L_Make_denorm /* The number is a de-normal */ @@ -160,12 +160,12 @@ je LRound_To_64 #ifdef PARANOID jmp L_bugged_denorm_486 -#endif PARANOID +#endif /* PARANOID */ #else #ifdef PARANOID jmp L_bugged_denorm /* There is no bug, just a bad control word */ -#endif PARANOID -#endif PECULIAR_486 +#endif /* PARANOID */ +#endif /* PECULIAR_486 */ /* Round etc to 24 bit precision */ @@ -186,7 +186,7 @@ #ifdef PARANOID jmp L_bugged_round24 -#endif PARANOID +#endif /* PARANOID */ LUp_24: cmpb SIGN_POS,PARAM5 @@ -266,7 +266,7 @@ #ifdef PARANOID jmp L_bugged_round53 -#endif PARANOID +#endif /* PARANOID */ LUp_53: cmpb SIGN_POS,PARAM5 @@ -340,7 +340,7 @@ #ifdef PARANOID jmp L_bugged_round64 -#endif PARANOID +#endif /* PARANOID */ LUp_64: cmpb SIGN_POS,PARAM5 @@ -430,7 +430,7 @@ #ifndef NON_REENTRANT_FPU popl %ebx /* adjust the stack pointer */ -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ fpu_Arith_exit: popl %ebx @@ -570,7 +570,7 @@ /* But check it... just in case. */ cmpw EXP_UNDER+1,EXP(%edi) jne L_norm_bugged -#endif PARANOID +#endif /* PARANOID */ #ifdef PECULIAR_486 /* @@ -586,7 +586,7 @@ #else orl %eax,%eax /* ms bits */ js L_Normalised /* No longer a denormal */ -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ jnz LDenormal_adj_exponent @@ -673,7 +673,7 @@ call EXCEPTION popl %ebx jmp L_exception_exit -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ L_bugged_round24: pushl EX_INTERNAL|0x231 @@ -706,4 +706,4 @@ L_exception_exit: mov $-1,%eax jmp fpu_reg_round_special_exit -#endif PARANOID +#endif /* PARANOID */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/reg_u_add.S linux.ac/arch/i386/math-emu/reg_u_add.S --- linux.vanilla/arch/i386/math-emu/reg_u_add.S Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/reg_u_add.S Tue Apr 10 18:07:47 2001 @@ -72,7 +72,7 @@ testl $0x80000000,SIGH(%esi) je L_bugged -#endif PARANOID +#endif /* PARANOID */ /* The number to be shifted is in %eax:%ebx:%edx */ cmpw $32,%cx /* shrd only works for 0..31 bits */ @@ -164,4 +164,4 @@ popl %esi leave ret -#endif PARANOID +#endif /* PARANOID */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/reg_u_div.S linux.ac/arch/i386/math-emu/reg_u_div.S --- linux.vanilla/arch/i386/math-emu/reg_u_div.S Fri Aug 27 18:18:17 1999 +++ linux.ac/arch/i386/math-emu/reg_u_div.S Tue Apr 10 18:07:47 2001 @@ -67,7 +67,7 @@ .long 0 FPU_ovfl_flag: .byte 0 -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ #define REGA PARAM1 #define REGB PARAM2 @@ -79,7 +79,7 @@ movl %esp,%ebp #ifndef NON_REENTRANT_FPU subl $28,%esp -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ pushl %esi pushl %edi @@ -112,7 +112,7 @@ /* je L_bugged */ testl $0x80000000, SIGH(%ebx) /* Divisor */ je L_bugged -#endif PARANOID +#endif /* PARANOID */ /* Check if the divisor can be treated as having just 32 bits */ cmpl $0,SIGL(%ebx) @@ -248,7 +248,7 @@ #ifdef PARANOID jb L_bugged_1 -#endif PARANOID +#endif /* PARANOID */ /* need to subtract another once of the denom */ incl FPU_result_2 /* Correct the answer */ @@ -261,7 +261,7 @@ #ifdef PARANOID sbbl $0,FPU_accum_3 jne L_bugged_1 /* Must check for non-zero result here */ -#endif PARANOID +#endif /* PARANOID */ /*----------------------------------------------------------------------*/ /* Half of the main problem is done, there is just a reduced numerator @@ -291,7 +291,7 @@ #ifdef PARANOID je L_bugged_2 /* Can't bump the result to 1.0 */ -#endif PARANOID +#endif /* PARANOID */ LDo_2nd_div: cmpl $0,%ecx /* augmented denom msw */ @@ -314,7 +314,7 @@ #ifdef PARANOID jc L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ movl FPU_result_1,%eax /* Get the result back */ mull SIGL(%ebx) /* now mul the ls dw of the denom */ @@ -325,14 +325,14 @@ #ifdef PARANOID jc L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ jz LDo_3rd_32_bits #ifdef PARANOID cmpl $1,FPU_accum_2 jne L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ /* need to subtract another once of the denom */ movl SIGL(%ebx),%eax @@ -344,14 +344,14 @@ #ifdef PARANOID jc L_bugged_2 jne L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ addl $1,FPU_result_1 /* Correct the answer */ adcl $0,FPU_result_2 #ifdef PARANOID jc L_bugged_2 /* Must check for non-zero result here */ -#endif PARANOID +#endif /* PARANOID */ /*----------------------------------------------------------------------*/ /* The division is essentially finished here, we just need to perform @@ -470,4 +470,4 @@ leave ret -#endif PARANOID +#endif /* PARANOID */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/reg_u_mul.S linux.ac/arch/i386/math-emu/reg_u_mul.S --- linux.vanilla/arch/i386/math-emu/reg_u_mul.S Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/reg_u_mul.S Tue Apr 10 18:07:47 2001 @@ -40,7 +40,7 @@ .long 0 FPU_accum_1: .long 0 -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ .text @@ -49,7 +49,7 @@ movl %esp,%ebp #ifndef NON_REENTRANT_FPU subl $8,%esp -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ pushl %esi pushl %edi @@ -63,7 +63,7 @@ jz L_bugged testl $0x80000000,SIGH(%edi) jz L_bugged -#endif PARANOID +#endif /* PARANOID */ xorl %ecx,%ecx xorl %ebx,%ebx @@ -144,5 +144,5 @@ popl %esi leave ret -#endif PARANOID +#endif /* PARANOID */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/reg_u_sub.S linux.ac/arch/i386/math-emu/reg_u_sub.S --- linux.vanilla/arch/i386/math-emu/reg_u_sub.S Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/reg_u_sub.S Tue Apr 10 18:07:47 2001 @@ -54,7 +54,7 @@ testl $0x80000000,SIGH(%esi) je L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ /*--------------------------------------+ | Form a register holding the | @@ -165,7 +165,7 @@ #ifdef PARANOID /* We can never get a borrow */ jc L_bugged -#endif PARANOID +#endif /* PARANOID */ /*--------------------------------------+ | Normalize the result | @@ -199,7 +199,7 @@ #ifdef PARANOID orl %edx,%edx jnz L_bugged_3 -#endif PARANOID +#endif /* PARANOID */ /* The result is zero */ movw $0,EXP(%edi) /* exponent */ @@ -262,7 +262,7 @@ L_error_exit: movl $-1,%eax -#endif PARANOID +#endif /* PARANOID */ L_exit: popl %ebx diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/status_w.h linux.ac/arch/i386/math-emu/status_w.h --- linux.vanilla/arch/i386/math-emu/status_w.h Mon Dec 11 21:34:33 2000 +++ linux.ac/arch/i386/math-emu/status_w.h Tue Apr 10 18:07:47 2001 @@ -58,8 +58,8 @@ # define clear_C1() { partial_status &= ~SW_C1; } # else # define clear_C1() -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ -#endif __ASSEMBLY__ +#endif /* __ASSEMBLY__ */ -#endif _STATUS_H_ +#endif /* _STATUS_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/wm_sqrt.S linux.ac/arch/i386/math-emu/wm_sqrt.S --- linux.vanilla/arch/i386/math-emu/wm_sqrt.S Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/wm_sqrt.S Tue Apr 10 18:07:47 2001 @@ -70,7 +70,7 @@ .long 0 FPU_fsqrt_arg_0: .long 0 /* ls word, at most the ms bit is set */ -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ .text @@ -79,7 +79,7 @@ movl %esp,%ebp #ifndef NON_REENTRANT_FPU subl $28,%esp -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ pushl %esi pushl %edi pushl %ebx @@ -210,7 +210,7 @@ /* It should be possible to get here only if the arg is ffff....ffff */ cmp $0xffffffff,FPU_fsqrt_arg_1 jnz sqrt_stage_2_error -#endif PARANOID +#endif /* PARANOID */ /* The best rounded result. */ xorl %eax,%eax @@ -224,7 +224,7 @@ sqrt_stage_2_error: pushl EX_INTERNAL|0x213 call EXCEPTION -#endif PARANOID +#endif /* PARANOID */ sqrt_stage_2_done: @@ -279,7 +279,7 @@ call EXCEPTION sqrt_stage_3_no_error: -#endif PARANOID +#endif /* PARANOID */ movl FPU_accum_2,%edx movl FPU_accum_1,%eax @@ -385,7 +385,7 @@ call EXCEPTION sqrt_near_exact_ok: -#endif PARANOID +#endif /* PARANOID */ or %ebx,%ebx js sqrt_near_exact_small @@ -445,7 +445,7 @@ call EXCEPTION sqrt_more_prec_ok: -#endif PARANOID +#endif /* PARANOID */ or %ebx,%ebx js sqrt_more_prec_small diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/mm/fault.c linux.ac/arch/i386/mm/fault.c --- linux.vanilla/arch/i386/mm/fault.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/i386/mm/fault.c Wed Apr 4 13:37:37 2001 @@ -4,6 +4,7 @@ * Copyright (C) 1995 Linus Torvalds */ +#include <linux/config.h> #include <linux/signal.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -17,6 +18,7 @@ #include <linux/smp_lock.h> #include <linux/interrupt.h> #include <linux/init.h> +#include <linux/vt_kern.h> /* For unblank_screen() */ #include <asm/system.h> #include <asm/uaccess.h> @@ -25,6 +27,8 @@ extern void die(const char *,struct pt_regs *,long); +extern int console_loglevel; + /* * Ugly, ugly, but the goto's result in better assembly.. */ @@ -77,17 +81,69 @@ return 0; } -extern spinlock_t console_lock, timerlist_lock; +extern spinlock_t timerlist_lock; /* * Unlock any spinlocks which will prevent us from getting the * message out (timerlist_lock is acquired through the * console unblank code) */ -void bust_spinlocks(void) +void bust_spinlocks(int yes) { - spin_lock_init(&console_lock); spin_lock_init(&timerlist_lock); + if (yes) { + oops_in_progress = 1; +#ifdef CONFIG_SMP + global_irq_lock = 0; /* Many serial drivers do __global_cli() */ +#endif + } else { + int loglevel_save = console_loglevel; +#ifdef CONFIG_VT + unblank_screen(); +#endif + oops_in_progress = 0; + /* + * OK, the message is on the console. Now we call printk() + * without oops_in_progress set so that printk will give klogd + * a poke. Hold onto your hats... + */ + console_loglevel = 15; /* NMI oopser may have shut the console up */ + printk(" "); + console_loglevel = loglevel_save; + } +} + +void do_BUG(const char *file, int line) +{ + bust_spinlocks(1); + printk("kernel BUG at %s:%d!\n", file, line); +} + +static void print_pagetable_entries (pgd_t *pgdir, unsigned long address) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + pgd = pgdir + __pgd_offset(address); + printk("pgd entry %p: %016Lx\n", pgd, (long long)pgd_val(*pgd)); + + if (!pgd_present(*pgd)) { + printk("... pgd not present!\n"); + return; + } + pmd = pmd_offset(pgd, address); + printk("pmd entry %p: %016Lx\n", pmd, (long long)pmd_val(*pmd)); + + if (!pmd_present(*pmd)) { + printk("... pmd not present!\n"); + return; + } + pte = pte_offset(pmd, address); + printk("pte entry %p: %016Lx\n", pte, (long long)pte_val(*pte)); + + if (!pte_present(*pte)) + printk("... pte not present!\n"); } asmlinkage void do_invalid_op(struct pt_regs *, unsigned long); @@ -264,7 +320,7 @@ * terminate things with extreme prejudice. */ - bust_spinlocks(); + bust_spinlocks(1); if (address < PAGE_SIZE) printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); @@ -274,15 +330,9 @@ printk(" printing eip:\n"); printk("%08lx\n", regs->eip); asm("movl %%cr3,%0":"=r" (page)); - page = ((unsigned long *) __va(page))[address >> 22]; - printk(KERN_ALERT "*pde = %08lx\n", page); - if (page & 1) { - page &= PAGE_MASK; - address &= 0x003ff000; - page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT]; - printk(KERN_ALERT "*pte = %08lx\n", page); - } + print_pagetable_entries((pgd_t *)__va(page), address); die("Oops", regs, error_code); + bust_spinlocks(0); do_exit(SIGKILL); /* @@ -322,7 +372,11 @@ /* * Synchronize this task's top level page-table * with the 'reference' page table. + * + * Note. There is 1 gotcha here. We may be doing the WP + * test. If so then fixing the pgd/pmd won't help. */ + int offset = __pgd_offset(address); pgd_t *pgd, *pgd_k; pmd_t *pmd, *pmd_k; @@ -340,7 +394,29 @@ pmd = pmd_offset(pgd, address); pmd_k = pmd_offset(pgd_k, address); - if (pmd_present(*pmd) || !pmd_present(*pmd_k)) + /* If the pmd is present then we either have two cpus trying + * to fill in the vmalloc entries at once, or we have an + * exception. We can treat the collision as a slow path without + * worry. Its incredibly incredibly rare + * + * If the pte is read only then we know its a fault and we must + * exception or Oops as it would loop forever otherwise + */ + + if (pmd_present(*pmd)) + { + pte_t *ptep = pte_offset(pmd, address); + if ((error_code & 2) && !pte_write(*ptep)) + { + if ((fixup = search_exception_table(regs->eip)) != 0) { + regs->eip = fixup; + return; + } + goto bad_area_nosemaphore; + } + /* SMP race.. continue */ + } + if (!pmd_present(*pmd_k)) goto bad_area_nosemaphore; set_pmd(pmd, *pmd_k); return; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/mm/init.c linux.ac/arch/i386/mm/init.c --- linux.vanilla/arch/i386/mm/init.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/i386/mm/init.c Tue Apr 3 22:43:57 2001 @@ -15,6 +15,9 @@ #include <linux/types.h> #include <linux/ptrace.h> #include <linux/mman.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/fs.h> #include <linux/mm.h> #include <linux/swap.h> #include <linux/smp.h> @@ -35,7 +38,9 @@ #include <asm/fixmap.h> #include <asm/e820.h> #include <asm/apic.h> +#include <asm/tlb.h> +mmu_gather_t mmu_gathers[NR_CPUS]; unsigned long highstart_pfn, highend_pfn; static unsigned long totalram_pages; static unsigned long totalhigh_pages; @@ -131,15 +136,11 @@ pte_t *pte; pgd = swapper_pg_dir + __pgd_offset(vaddr); - if (pgd_none(*pgd)) { - printk("PAE BUG #00!\n"); - return; - } + if (pgd_none(*pgd)) + BUG(); pmd = pmd_offset(pgd, vaddr); - if (pmd_none(*pmd)) { - printk("PAE BUG #01!\n"); - return; - } + if (pmd_none(*pmd)) + BUG(); pte = pte_offset(pmd, vaddr); if (pte_val(*pte)) pte_ERROR(*pte); @@ -183,7 +184,7 @@ pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); set_pgd(pgd, __pgd(__pa(pmd) + 0x1)); if (pmd != pmd_offset(pgd, 0)) - printk("PAE BUG #02!\n"); + BUG(); } pmd = pmd_offset(pgd, vaddr); #else @@ -309,14 +310,11 @@ * Zap initial low-memory mappings. * * Note that "pgd_clear()" doesn't do it for - * us in this case, because pgd_clear() is a - * no-op in the 2-level case (pmd_clear() is - * the thing that clears the page-tables in - * that case). + * us, because pgd_clear() is a no-op on i386. */ for (i = 0; i < USER_PTRS_PER_PGD; i++) #if CONFIG_X86_PAE - pgd_clear(swapper_pg_dir+i); + set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page))); #else set_pgd(swapper_pg_dir+i, __pgd(0)); #endif @@ -581,3 +579,23 @@ val->mem_unit = PAGE_SIZE; return; } + +#if CONFIG_X86_PAE + +#include <linux/slab.h> + +struct kmem_cache_s *pae_pgd_cachep; + +void __init init_pae_pgd_cache(void) +{ + /* + * PAE pgds must be 16-byte aligned: + */ + pae_pgd_cachep = kmem_cache_create("pae_pgd", 32, 0, + SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN, NULL, NULL); + if (!pae_pgd_cachep) + panic("init_pae(): Cannot alloc pae_pgd SLAB cache"); +} + +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/Makefile linux.ac/arch/ia64/Makefile --- linux.vanilla/arch/ia64/Makefile Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/Makefile Tue Apr 10 18:07:54 2001 @@ -5,7 +5,7 @@ # License. See the file "COPYING" in the main directory of this archive # for more details. # -# Copyright (C) 1998-2000 by David Mosberger-Tang <davidm@hpl.hp.com> +# Copyright (C) 1998-2001 by David Mosberger-Tang <davidm@hpl.hp.com> # NM := $(CROSS_COMPILE)nm -B @@ -14,13 +14,13 @@ export AWK LINKFLAGS = -static -T arch/$(ARCH)/vmlinux.lds -AFLAGS += -Wa,-x +AFLAGS += -Wa,-x AFLAGS_KERNEL := -mconstant-gp EXTRA = CFLAGS := $(CFLAGS) -pipe $(EXTRA) -Wa,-x -ffixed-r13 -mfixed-range=f10-f15,f32-f127 \ -funwind-tables -falign-functions=32 -# -frename-registers +# -frename-registers (this crashes the Nov 17 compiler...) CFLAGS_KERNEL := -mconstant-gp ifeq ($(CONFIG_ITANIUM_ASTEP_SPECIFIC),y) @@ -53,7 +53,7 @@ endif ifdef CONFIG_IA64_SGI_SN1 -CFLAGS += -DBRINGUP + CFLAGS += -DBRINGUP SUBDIRS := arch/$(ARCH)/sn/sn1 \ arch/$(ARCH)/sn \ arch/$(ARCH)/sn/io \ @@ -103,6 +103,11 @@ FORCE: ; +compressed: vmlinux + $(OBJCOPY) --strip-all vmlinux vmlinux-tmp + gzip -9 vmlinux-tmp + mv vmlinux-tmp.gz vmlinux.gz + rawboot: @$(MAKEBOOT) rawboot @@ -120,8 +125,6 @@ @$(MAKEBOOT) srmboot archclean: - @$(MAKE) -C arch/$(ARCH)/kernel clean - @$(MAKE) -C arch/$(ARCH)/tools clean @$(MAKEBOOT) clean archmrproper: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/boot/bootloader.c linux.ac/arch/ia64/boot/bootloader.c --- linux.vanilla/arch/ia64/boot/bootloader.c Tue Oct 10 01:54:53 2000 +++ linux.ac/arch/ia64/boot/bootloader.c Tue Apr 10 18:08:40 2001 @@ -3,8 +3,8 @@ * * Loads an ELF kernel. * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co + * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com> * * 01/07/99 S.Eranian modified to pass command line arguments to kernel @@ -65,35 +65,22 @@ } } -void -enter_virtual_mode (unsigned long new_psr) -{ - long tmp; - - asm volatile ("movl %0=1f" : "=r"(tmp)); - asm volatile ("mov cr.ipsr=%0" :: "r"(new_psr)); - asm volatile ("mov cr.iip=%0" :: "r"(tmp)); - asm volatile ("mov cr.ifs=r0"); - asm volatile ("rfi;;"); - asm volatile ("1:"); -} - #define MAX_ARGS 32 void _start (void) { - register long sp asm ("sp"); static char stack[16384] __attribute__ ((aligned (16))); static char mem[4096]; static char buffer[1024]; - unsigned long flags, off; + unsigned long off; int fd, i; struct disk_req req; struct disk_stat stat; struct elfhdr *elf; struct elf_phdr *elf_phdr; /* program header */ unsigned long e_entry, e_phoff, e_phnum; + register struct ia64_boot_param *bp; char *kpath, *args; long arglen = 0; @@ -107,15 +94,13 @@ ssc(0, 0, 0, 0, SSC_CONSOLE_INIT); /* - * S.Eranian: extract the commandline argument from the - * simulator + * S.Eranian: extract the commandline argument from the simulator * * The expected format is as follows: * * kernelname args... * - * Both are optional but you can't have the second one without the - * first. + * Both are optional but you can't have the second one without the first. */ arglen = ssc((long) buffer, 0, 0, 0, SSC_GET_ARGS); @@ -183,6 +168,10 @@ e_phoff += sizeof(*elf_phdr); elf_phdr = (struct elf_phdr *) mem; + + if (elf_phdr->p_type != PT_LOAD) + continue; + req.len = elf_phdr->p_filesz; req.addr = __pa(elf_phdr->p_vaddr); ssc(fd, 1, (long) &req, elf_phdr->p_offset, SSC_READ); @@ -197,38 +186,12 @@ /* fake an I/O base address: */ asm volatile ("mov ar.k0=%0" :: "r"(0xffffc000000UL)); - /* - * Install a translation register that identity maps the - * kernel's 256MB page. - */ - ia64_clear_ic(flags); - ia64_set_rr( 0, (0x1000 << 8) | (_PAGE_SIZE_1M << 2)); - ia64_set_rr(PAGE_OFFSET, (ia64_rid(0, PAGE_OFFSET) << 8) | (_PAGE_SIZE_256M << 2)); - ia64_srlz_d(); - ia64_itr(0x3, 0, 1024*1024, - pte_val(mk_pte_phys(1024*1024, __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX))), - _PAGE_SIZE_1M); - ia64_itr(0x3, 1, PAGE_OFFSET, - pte_val(mk_pte_phys(0, __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX))), - _PAGE_SIZE_256M); - ia64_srlz_i(); - - enter_virtual_mode(flags | IA64_PSR_IT | IA64_PSR_IC | IA64_PSR_DT | IA64_PSR_RT - | IA64_PSR_DFH | IA64_PSR_BN); - - sys_fw_init(args, arglen); + bp = sys_fw_init(args, arglen); ssc(0, (long) kpath, 0, 0, SSC_LOAD_SYMBOLS); - /* - * Install the kernel's command line argument on ZERO_PAGE - * just after the botoparam structure. - * In case we don't have any argument just put \0 - */ - memcpy(((struct ia64_boot_param *)ZERO_PAGE_ADDR) + 1, args, arglen); - sp = __pa(&stack); - - asm volatile ("br.sptk.few %0" :: "b"(e_entry)); + asm volatile ("mov sp=%2; mov r28=%1; br.sptk.few %0" + :: "b"(e_entry), "r"(bp), "r"(__pa(&stack))); cons_write("kernel returned!\n"); ssc(-1, 0, 0, 0, SSC_EXIT); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/config.in linux.ac/arch/ia64/config.in --- linux.vanilla/arch/ia64/config.in Fri Feb 16 23:53:08 2001 +++ linux.ac/arch/ia64/config.in Tue Apr 10 18:08:40 2001 @@ -24,6 +24,10 @@ define_bool CONFIG_MCA n define_bool CONFIG_SBUS n +choice 'IA-64 processor type' \ + "Itanium CONFIG_ITANIUM \ + McKinley CONFIG_MCKINLEY" Itanium + choice 'IA-64 system type' \ "generic CONFIG_IA64_GENERIC \ DIG-compliant CONFIG_IA64_DIG \ @@ -36,24 +40,47 @@ 16KB CONFIG_IA64_PAGE_SIZE_16KB \ 64KB CONFIG_IA64_PAGE_SIZE_64KB" 16KB -if [ "$CONFIG_IA64_DIG" = "y" ]; then - define_bool CONFIG_ITANIUM y +if [ "$CONFIG_ITANIUM" = "y" ]; then define_bool CONFIG_IA64_BRL_EMU y bool ' Enable Itanium A-step specific code' CONFIG_ITANIUM_ASTEP_SPECIFIC bool ' Enable Itanium B-step specific code' CONFIG_ITANIUM_BSTEP_SPECIFIC if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then bool ' Enable Itanium B0-step specific code' CONFIG_ITANIUM_B0_SPECIFIC + fi + if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then bool ' Enable Itanium B1-step specific code' CONFIG_ITANIUM_B1_SPECIFIC + fi + if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then bool ' Enable Itanium B2-step specific code' CONFIG_ITANIUM_B2_SPECIFIC fi bool ' Enable Itanium C-step specific code' CONFIG_ITANIUM_CSTEP_SPECIFIC if [ "$CONFIG_ITANIUM_CSTEP_SPECIFIC" = "y" ]; then bool ' Enable Itanium C0-step specific code' CONFIG_ITANIUM_C0_SPECIFIC fi + if [ "$CONFIG_ITANIUM_ASTEP_SPECIFIC" = "y" -o "$CONFIG_ITANIUM_B0_SPECIFIC" = "y" \ + -o "$CONFIG_ITANIUM_B1_SPECIFIC" = "y" -o "$CONFIG_ITANIUM_B2_SPECIFIC" = "y" ]; then + define_bool CONFIG_ITANIUM_PTCG n + else + define_bool CONFIG_ITANIUM_PTCG y + fi + if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then + define_int CONFIG_IA64_L1_CACHE_SHIFT 7 # align cache-sensitive data to 128 bytes + else + define_int CONFIG_IA64_L1_CACHE_SHIFT 6 # align cache-sensitive data to 64 bytes + fi +fi + +if [ "$CONFIG_MCKINLEY" = "y" ]; then + define_bool CONFIG_ITANIUM_PTCG y + define_int CONFIG_IA64_L1_CACHE_SHIFT 7 + bool ' Enable McKinley A-step specific code' CONFIG_MCKINLEY_ASTEP_SPECIFIC + if [ "$CONFIG_MCKINLEY_ASTEP_SPECIFIC" = "y" ]; then + bool ' Enable McKinley A0/A1-step specific code' CONFIG_MCKINLEY_A0_SPECIFIC + fi +fi + +if [ "$CONFIG_IA64_DIG" = "y" ]; then bool ' Force interrupt redirection' CONFIG_IA64_HAVE_IRQREDIR - bool ' Enable use of global TLB purge instruction (ptc.g)' CONFIG_ITANIUM_PTCG - bool ' Enable SoftSDV hacks' CONFIG_IA64_SOFTSDV_HACKS - bool ' Enable AzusA hacks' CONFIG_IA64_AZUSA_HACKS bool ' Enable IA-64 Machine Check Abort' CONFIG_IA64_MCA bool ' Enable ACPI 2.0 with errata 1.3' CONFIG_ACPI20 bool ' ACPI kernel configuration manager (EXPERIMENTAL)' CONFIG_ACPI_KERNEL_CONFIG @@ -65,11 +92,6 @@ fi if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then - bool ' Enable use of global TLB purge instruction (ptc.g)' CONFIG_ITANIUM_PTCG - bool ' Enable Itanium B-step specific code' CONFIG_ITANIUM_BSTEP_SPECIFIC - if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then - bool ' Enable Itanium B0-step specific code' CONFIG_ITANIUM_B0_SPECIFIC - fi bool ' Enable SGI Medusa Simulator Support' CONFIG_IA64_SGI_SN1_SIM define_bool CONFIG_DEVFS_DEBUG y define_bool CONFIG_DEVFS_FS y @@ -87,7 +109,8 @@ bool 'SMP support' CONFIG_SMP bool 'Performance monitor support' CONFIG_PERFMON -bool '/proc/pal support' CONFIG_IA64_PALINFO +tristate '/proc/pal support' CONFIG_IA64_PALINFO +tristate '/proc/efi support' CONFIG_IA64_EFIVARS bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC @@ -123,7 +146,7 @@ source drivers/mtd/Config.in source drivers/pnp/Config.in source drivers/block/Config.in -source drivers/i2o/Config.in +source drivers/message/i2o/Config.in source drivers/md/Config.in mainmenu_option next_comment @@ -253,7 +276,6 @@ bool 'Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG bool 'Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ bool 'Print possible IA64 hazards to console' CONFIG_IA64_PRINT_HAZARDS -bool 'Enable new unwind support' CONFIG_IA64_NEW_UNWIND bool 'Disable VHPT' CONFIG_DISABLE_VHPT endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/dig/setup.c linux.ac/arch/ia64/dig/setup.c --- linux.vanilla/arch/ia64/dig/setup.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/dig/setup.c Tue Apr 10 18:08:40 2001 @@ -1,9 +1,9 @@ /* - * Platform dependent support for Intel SoftSDV simulator. + * Platform dependent support for DIG64 platforms. * * Copyright (C) 1999 Intel Corp. - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1999, 2001 Hewlett-Packard Co + * Copyright (C) 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> * Copyright (C) 1999 Vijay Chander <vijay@engr.sgi.com> @@ -48,18 +48,14 @@ */ ROOT_DEV = to_kdev_t(0x0802); /* default to second partition on first drive */ -#ifdef CONFIG_IA64_SOFTSDV_HACKS - ROOT_DEV = to_kdev_t(0x0302); /* 2nd partion on 1st IDE */ -#endif /* CONFIG_IA64_SOFTSDV_HACKS */ - #ifdef CONFIG_SMP init_smp_config(); #endif memset(&screen_info, 0, sizeof(screen_info)); - if (!ia64_boot_param.console_info.num_rows - || !ia64_boot_param.console_info.num_cols) + if (!ia64_boot_param->console_info.num_rows + || !ia64_boot_param->console_info.num_cols) { printk("dig_setup: warning: invalid screen-info, guessing 80x25\n"); orig_x = 0; @@ -68,10 +64,10 @@ num_rows = 25; font_height = 16; } else { - orig_x = ia64_boot_param.console_info.orig_x; - orig_y = ia64_boot_param.console_info.orig_y; - num_cols = ia64_boot_param.console_info.num_cols; - num_rows = ia64_boot_param.console_info.num_rows; + orig_x = ia64_boot_param->console_info.orig_x; + orig_y = ia64_boot_param->console_info.orig_y; + num_cols = ia64_boot_param->console_info.num_cols; + num_rows = ia64_boot_param->console_info.num_rows; font_height = 400 / num_rows; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/hp/hpsim_irq.c linux.ac/arch/ia64/hp/hpsim_irq.c --- linux.vanilla/arch/ia64/hp/hpsim_irq.c Thu Jun 22 15:09:44 2000 +++ linux.ac/arch/ia64/hp/hpsim_irq.c Tue Apr 10 18:08:40 2001 @@ -1,8 +1,8 @@ /* * Platform dependent support for HP simulator. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/init.h> @@ -35,10 +35,12 @@ void __init hpsim_irq_init (void) { + irq_desc_t *idesc; int i; - for (i = IA64_MIN_VECTORED_IRQ; i <= IA64_MAX_VECTORED_IRQ; ++i) { - if (irq_desc[i].handler == &no_irq_type) - irq_desc[i].handler = &irq_type_hp_sim; + for (i = 0; i < NR_IRQS; ++i) { + idesc = irq_desc(i); + if (idesc->handler == &no_irq_type) + idesc->handler = &irq_type_hp_sim; } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/ia32/binfmt_elf32.c linux.ac/arch/ia64/ia32/binfmt_elf32.c --- linux.vanilla/arch/ia64/ia32/binfmt_elf32.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/ia64/ia32/binfmt_elf32.c Tue Apr 10 18:08:40 2001 @@ -57,28 +57,30 @@ if (page_count(page) != 1) printk("mem_map disagrees with %p at %08lx\n", (void *) page, address); + pgd = pgd_offset(tsk->mm, address); - pmd = pmd_alloc(pgd, address); - if (!pmd) { - __free_page(page); - force_sig(SIGKILL, tsk); - return 0; - } - pte = pte_alloc(pmd, address); - if (!pte) { - __free_page(page); - force_sig(SIGKILL, tsk); - return 0; - } - if (!pte_none(*pte)) { - pte_ERROR(*pte); - __free_page(page); - return 0; + + spin_lock(&tsk->mm->page_table_lock); + { + pmd = pmd_alloc(tsk->mm, pgd, address); + if (!pmd) + goto out; + pte = pte_alloc(tsk->mm, pmd, address); + if (!pte) + goto out; + if (!pte_none(*pte)) + goto out; + flush_page_to_ram(page); + set_pte(pte, pte_mkwrite(mk_pte(page, PAGE_SHARED))); } - flush_page_to_ram(page); - set_pte(pte, pte_mkwrite(mk_pte(page, PAGE_SHARED))); + spin_unlock(&tsk->mm->page_table_lock); /* no need for flush_tlb */ return page; + + out: + spin_unlock(&tsk->mm->page_table_lock); + __free_page(page); + return 0; } void ia64_elf32_init(struct pt_regs *regs) @@ -90,12 +92,13 @@ put_shared_page(current, virt_to_page(ia32_tss), IA32_PAGE_OFFSET + PAGE_SIZE); nr = smp_processor_id(); - + /* Do all the IA-32 setup here */ - current->thread.map_base = 0x40000000; - current->thread.task_size = 0xc0000000; /* use what Linux/x86 uses... */ - + current->thread.map_base = 0x40000000; + current->thread.task_size = 0xc0000000; /* use what Linux/x86 uses... */ + set_fs(USER_DS); /* set addr limit for new TASK_SIZE */ + /* setup ia32 state for ia32_load_state */ current->thread.eflag = IA32_EFLAG; @@ -124,14 +127,8 @@ : "r" ((ulong)IA32_FCR_DEFAULT)); __asm__("mov ar.fir = r0"); __asm__("mov ar.fdr = r0"); - __asm__("mov %0=ar.k0 ;;" : "=r" (current->thread.old_iob)); - __asm__("mov ar.k0=%0 ;;" :: "r"(IA32_IOBASE)); - /* TSS */ - __asm__("mov ar.k1 = %0" - : /* no outputs */ - : "r" IA64_SEG_DESCRIPTOR(IA32_PAGE_OFFSET + PAGE_SIZE, - 0x1FFFL, 0xBL, 1L, - 3L, 1L, 1L, 1L)); + current->thread.old_iob = ia64_get_kr(IA64_KR_IO_BASE); + ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE); /* Get the segment selectors right */ regs->r16 = (__USER_DS << 16) | (__USER_DS); /* ES == DS, GS, FS are zero */ @@ -149,23 +146,10 @@ regs->r31 = IA64_SEG_DESCRIPTOR(0xc0000000L, 0x400L, 0x3L, 1L, 3L, 1L, 1L, 1L); - /* Clear psr.ac */ + /* Clear psr.ac */ regs->cr_ipsr &= ~IA64_PSR_AC; regs->loadrs = 0; - /* - * According to the ABI %edx points to an `atexit' handler. - * Since we don't have one we'll set it to 0 and initialize - * all the other registers just to make things more deterministic, - * ala the i386 implementation. - */ - regs->r8 = 0; /* %eax */ - regs->r11 = 0; /* %ebx */ - regs->r9 = 0; /* %ecx */ - regs->r10 = 0; /* %edx */ - regs->r13 = 0; /* %ebp */ - regs->r14 = 0; /* %esi */ - regs->r15 = 0; /* %edi */ } #undef STACK_TOP @@ -185,9 +169,9 @@ bprm->exec += stack_base; mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (!mpnt) - return -ENOMEM; - + if (!mpnt) + return -ENOMEM; + { mpnt->vm_mm = current->mm; mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; @@ -200,7 +184,7 @@ mpnt->vm_private_data = 0; insert_vm_struct(current->mm, mpnt); current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; - } + } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { if (bprm->page[i]) { @@ -208,7 +192,7 @@ } stack_base += PAGE_SIZE; } - + return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/ia32/ia32_entry.S linux.ac/arch/ia64/ia32/ia32_entry.S --- linux.vanilla/arch/ia64/ia32/ia32_entry.S Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/ia32/ia32_entry.S Tue Apr 10 18:08:40 2001 @@ -4,11 +4,34 @@ #include "../kernel/entry.h" + /* + * execve() is special because in case of success, we need to + * setup a null register window frame (in case an IA-32 process + * is exec'ing an IA-64 program). + */ +ENTRY(ia32_execve) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(3) + alloc loc1=ar.pfs,3,2,4,0 + mov loc0=rp + .body + mov out0=in0 // filename + ;; // stop bit between alloc and call + mov out1=in1 // argv + mov out2=in2 // envp + add out3=16,sp // regs + br.call.sptk.few rp=sys32_execve +1: cmp4.ge p6,p0=r8,r0 + mov ar.pfs=loc1 // restore ar.pfs + ;; +(p6) mov ar.pfs=r0 // clear ar.pfs in case of success + sxt4 r8=r8 // return 64-bit result + mov rp=loc0 + br.ret.sptk.few rp +END(ia32_execve) + // // Get possibly unaligned sigmask argument into an aligned // kernel buffer - .text - GLOBAL_ENTRY(ia32_rt_sigsuspend) // We'll cheat and not do an alloc here since we are ultimately // going to do a simple branch to the IA64 sys_rt_sigsuspend. @@ -16,38 +39,30 @@ // We copy this 4-byte aligned value to an 8-byte aligned buffer // in the task structure and then jump to the IA64 code. - mov r8=r0 // no memory access errors yet - add r10=4,r32 - ;; -1: - ld4 r2=[r32] // get first half of sigmask - ld4 r3=[r10] // get second half of sigmask -2: - cmp.lt p6,p0=r8,r0 // check memory access + EX(.Lfail, ld4 r2=[r32],4) // load low part of sigmask ;; -(p6) br.ret.sptk.many rp // it failed - + EX(.Lfail, ld4 r3=[r32]) // load high part of sigmask adds r32=IA64_TASK_THREAD_SIGMASK_OFFSET,r13 + ;; + st8 [r32]=r2 adds r10=IA64_TASK_THREAD_SIGMASK_OFFSET+4,r13 ;; - st4 [r32]=r2 + st4 [r10]=r3 br.cond.sptk.many sys_rt_sigsuspend -END(ia32_rt_sigsuspend) - .section __ex_table,"a" - data4 @gprel(1b) - data4 (2b-1b)|1 - .previous +.Lfail: br.ret.sptk.many rp // failed to read sigmask +END(ia32_rt_sigsuspend) GLOBAL_ENTRY(ia32_ret_from_syscall) PT_REGS_UNWIND_INFO(0) cmp.ge p6,p7=r8,r0 // syscall executed successfully? adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 - ;; + ;; + alloc r3=ar.pfs,0,0,0,0 // drop the syscall argument frame st8 [r2]=r8 // store return value in slot for r8 - br.cond.sptk.few ia64_leave_kernel + br.cond.sptk.many ia64_leave_kernel END(ia32_ret_from_syscall) // @@ -69,7 +84,8 @@ ;; st8.spill [r2]=r8 // store return value in slot for r8 br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch return value -.ret2: br.cond.sptk.many ia64_leave_kernel // rp MUST be != ia64_leave_kernel! +.ret2: alloc r2=ar.pfs,0,0,0,0 // drop the syscall argument frame + br.cond.sptk.many ia64_leave_kernel // rp MUST be != ia64_leave_kernel! END(ia32_trace_syscall) GLOBAL_ENTRY(sys32_vfork) @@ -79,7 +95,7 @@ END(sys32_vfork) GLOBAL_ENTRY(sys32_fork) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2) alloc r16=ar.pfs,2,2,4,0 mov out0=SIGCHLD // out0 = clone_flags ;; @@ -88,14 +104,14 @@ mov loc1=r16 // save ar.pfs across do_fork DO_SAVE_SWITCH_STACK - UNW(.body) + .body mov out1=0 mov out3=0 adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s br.call.sptk.few rp=do_fork .ret3: mov ar.pfs=loc1 - UNW(.restore sp) + .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack mov rp=loc0 br.ret.sptk.many rp @@ -104,7 +120,7 @@ .rodata .align 8 .globl ia32_syscall_table -ia32_syscall_table: +ia32_syscall_table: data8 sys32_ni_syscall /* 0 - old "setup(" system call*/ data8 sys_exit data8 sys32_fork @@ -116,7 +132,7 @@ data8 sys_creat data8 sys_link data8 sys_unlink /* 10 */ - data8 sys32_execve + data8 ia32_execve data8 sys_chdir data8 sys32_time data8 sys_mknod @@ -133,8 +149,8 @@ data8 sys32_ni_syscall /* sys_stime is not supported on IA64 */ /* 25 */ data8 sys32_ptrace data8 sys32_alarm - data8 sys_pause data8 sys32_ni_syscall + data8 sys_pause data8 ia32_utime /* 30 */ data8 sys32_ni_syscall /* old stty syscall holder */ data8 sys32_ni_syscall /* old gtty syscall holder */ @@ -153,7 +169,7 @@ data8 sys_brk /* 45 */ data8 sys_setgid data8 sys_getgid - data8 sys32_ni_syscall + data8 sys32_signal data8 sys_geteuid data8 sys_getegid /* 50 */ data8 sys_acct @@ -227,7 +243,7 @@ data8 sys32_sigreturn data8 sys_clone /* 120 */ data8 sys_setdomainname - data8 sys_newuname + data8 sys32_newuname data8 sys_modify_ldt data8 sys_adjtimex data8 sys32_mprotect /* 125 */ @@ -249,12 +265,12 @@ data8 sys32_getdents data8 sys32_select data8 sys_flock - data8 sys_msync + data8 sys32_msync data8 sys32_readv /* 145 */ data8 sys32_writev data8 sys_getsid data8 sys_fdatasync - data8 sys_sysctl + data8 sys32_sysctl data8 sys_mlock /* 150 */ data8 sys_munlock data8 sys_mlockall diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/ia32/ia32_support.c linux.ac/arch/ia64/ia32/ia32_support.c --- linux.vanilla/arch/ia64/ia32/ia32_support.c Tue Oct 10 01:54:53 2000 +++ linux.ac/arch/ia64/ia32/ia32_support.c Tue Apr 10 18:08:40 2001 @@ -2,6 +2,7 @@ * IA32 helper functions * * 06/16/00 A. Mallick added csd/ssd/tssd for ia32 thread context + * 02/19/01 D. Mosberger dropped tssd; it's not needed */ #include <linux/kernel.h> @@ -22,7 +23,7 @@ void ia32_save_state (struct thread_struct *thread) { - unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd, tssd; + unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd; asm ("mov %0=ar.eflag;" "mov %1=ar.fsr;" @@ -31,9 +32,7 @@ "mov %4=ar.fdr;" "mov %5=ar.csd;" "mov %6=ar.ssd;" - "mov %7=ar.k1" - : "=r"(eflag), "=r"(fsr), "=r"(fcr), "=r"(fir), "=r"(fdr), - "=r"(csd), "=r"(ssd), "=r"(tssd)); + : "=r"(eflag), "=r"(fsr), "=r"(fcr), "=r"(fir), "=r"(fdr), "=r"(csd), "=r"(ssd)); thread->eflag = eflag; thread->fsr = fsr; thread->fcr = fcr; @@ -41,14 +40,13 @@ thread->fdr = fdr; thread->csd = csd; thread->ssd = ssd; - thread->tssd = tssd; asm ("mov ar.k0=%0 ;;" :: "r"(thread->old_iob)); } void ia32_load_state (struct thread_struct *thread) { - unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd, tssd; + unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd; eflag = thread->eflag; fsr = thread->fsr; @@ -57,7 +55,6 @@ fdr = thread->fdr; csd = thread->csd; ssd = thread->ssd; - tssd = thread->tssd; asm volatile ("mov ar.eflag=%0;" "mov ar.fsr=%1;" @@ -66,9 +63,7 @@ "mov ar.fdr=%4;" "mov ar.csd=%5;" "mov ar.ssd=%6;" - "mov ar.k1=%7" - :: "r"(eflag), "r"(fsr), "r"(fcr), "r"(fir), "r"(fdr), - "r"(csd), "r"(ssd), "r"(tssd)); + :: "r"(eflag), "r"(fsr), "r"(fcr), "r"(fir), "r"(fdr), "r"(csd), "r"(ssd)); asm ("mov %0=ar.k0 ;;" : "=r"(thread->old_iob)); asm ("mov ar.k0=%0 ;;" :: "r"(IA32_IOBASE)); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/ia32/sys_ia32.c linux.ac/arch/ia64/ia32/sys_ia32.c --- linux.vanilla/arch/ia64/ia32/sys_ia32.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/ia64/ia32/sys_ia32.c Tue Apr 10 18:08:40 2001 @@ -1,12 +1,12 @@ /* * sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Based on - * sys_sparc32 + * sys_sparc32 * * Copyright (C) 2000 VA Linux Co * Copyright (C) 2000 Don Dugger <n0ano@valinux.com> - * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com> - * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com> + * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 2000 Hewlett-Packard Co. * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com> * @@ -16,9 +16,10 @@ #include <linux/config.h> #include <linux/kernel.h> +#include <linux/sysctl.h> #include <linux/sched.h> -#include <linux/fs.h> -#include <linux/file.h> +#include <linux/fs.h> +#include <linux/file.h> #include <linux/signal.h> #include <linux/utime.h> #include <linux/resource.h> @@ -64,96 +65,87 @@ #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) extern asmlinkage long sys_execve (char *, char **, char **, struct pt_regs *); -extern asmlinkage long sys_munmap (unsigned long, size_t len); extern asmlinkage long sys_mprotect (unsigned long, size_t, unsigned long); static int -nargs(unsigned int arg, char **ap) +nargs (unsigned int arg, char **ap) { int n, err, addr; + if (!arg) + return 0; + n = 0; do { err = get_user(addr, (int *)A(arg)); if (err) return err; - if (ap) { /* no access_ok needed, we allocated */ - err = __put_user((char *)A(addr), ap++); - if (err) - return err; - } + if (ap) + *ap++ = (char *) A(addr); arg += sizeof(unsigned int); n++; } while (addr); - return(n - 1); + return n - 1; } asmlinkage long -sys32_execve( -char *filename, -unsigned int argv, -unsigned int envp, -int dummy3, -int dummy4, -int dummy5, -int dummy6, -int dummy7, -int stack) +sys32_execve (char *filename, unsigned int argv, unsigned int envp, + int dummy3, int dummy4, int dummy5, int dummy6, int dummy7, + int stack) { struct pt_regs *regs = (struct pt_regs *)&stack; + unsigned long old_map_base, old_task_size; char **av, **ae; int na, ne, len; long r; na = nargs(argv, NULL); if (na < 0) - return(na); + return na; ne = nargs(envp, NULL); if (ne < 0) - return(ne); + return ne; len = (na + ne + 2) * sizeof(*av); - /* - * kmalloc won't work because the `sys_exec' code will attempt - * to do a `get_user' on the arg list and `get_user' will fail - * on a kernel address (simplifies `get_user'). Instead we - * do an mmap to get a user address. Note that since a successful - * `execve' frees all current memory we only have to do an - * `munmap' if the `execve' failes. - */ - down_write(¤t->mm->mmap_sem); - - av = (char **) do_mmap_pgoff(0, 0UL, len, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, 0); - - up_write(¤t->mm->mmap_sem); + av = kmalloc(len, GFP_KERNEL); + if (!av) + return -ENOMEM; - if (IS_ERR(av)) - return (long)av; ae = av + na + 1; - r = __put_user(0, (av + na)); - if (r) - goto out; - r = __put_user(0, (ae + ne)); - if (r) - goto out; + av[na] = NULL; + ae[ne] = NULL; + r = nargs(argv, av); if (r < 0) goto out; r = nargs(envp, ae); if (r < 0) goto out; + + old_map_base = current->thread.map_base; + old_task_size = current->thread.task_size; + + /* we may be exec'ing a 64-bit process: reset map base & task-size: */ + current->thread.map_base = DEFAULT_MAP_BASE; + current->thread.task_size = DEFAULT_TASK_SIZE; + + set_fs(KERNEL_DS); r = sys_execve(filename, av, ae, regs); - if (r < 0) -out: - sys_munmap((unsigned long) av, len); - return(r); + if (r < 0) { + /* oops, execve failed, switch back to old map base & task-size: */ + current->thread.map_base = old_map_base; + current->thread.task_size = old_task_size; + set_fs(USER_DS); /* establish new task-size as the address-limit */ + out: + kfree(av); + } + return r; } static inline int putstat(struct stat32 *ubuf, struct stat *kbuf) { int err; - + err = put_user (kbuf->st_dev, &ubuf->st_dev); err |= __put_user (kbuf->st_ino, &ubuf->st_ino); err |= __put_user (kbuf->st_mode, &ubuf->st_mode); @@ -178,8 +170,8 @@ int ret; struct stat s; mm_segment_t old_fs = get_fs(); - - set_fs (KERNEL_DS); + + set_fs(KERNEL_DS); ret = sys_newstat(filename, &s); set_fs (old_fs); if (putstat (statbuf, &s)) @@ -195,7 +187,7 @@ int ret; struct stat s; mm_segment_t old_fs = get_fs(); - + set_fs (KERNEL_DS); ret = sys_newlstat(filename, &s); set_fs (old_fs); @@ -212,7 +204,7 @@ int ret; struct stat s; mm_segment_t old_fs = get_fs(); - + set_fs (KERNEL_DS); ret = sys_newfstat(fd, &s); set_fs (old_fs); @@ -221,7 +213,6 @@ return ret; } -#define ALIGN4K(a) (((a) + 0xfff) & ~0xfff) #define OFFSET4K(a) ((a) & 0xfff) unsigned long @@ -287,19 +278,19 @@ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); prot |= PROT_EXEC; - if ((flags & MAP_FIXED) && ((addr & ~PAGE_MASK) || (offset & ~PAGE_MASK))) - error = do_mmap_fake(file, addr, len, prot, flags, (loff_t)offset); + if ((flags & MAP_FIXED) && ((addr & ~PAGE_MASK) || (offset & ~PAGE_MASK))) + error = do_mmap_fake(file, addr, len, prot, flags, (loff_t)offset); else { - poff = offset & PAGE_MASK; - len += offset - poff; + poff = offset & PAGE_MASK; + len += offset - poff; + + down_write(¤t->mm->mmap_sem); + error = do_mmap_pgoff(file, addr, len, prot, flags, poff >> PAGE_SHIFT); + up_write(¤t->mm->mmap_sem); - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, poff >> PAGE_SHIFT); - up_write(¤t->mm->mmap_sem); - - if (!IS_ERR((void *) error)) - error += offset - poff; - } + if (!IS_ERR((void *) error)) + error += offset - poff; + } return error; } @@ -328,18 +319,46 @@ if (copy_from_user(&a, arg, sizeof(a))) return -EFAULT; + if (PAGE_ALIGN(a.len) == 0) + return a.addr; + if (!(a.flags & MAP_ANONYMOUS)) { file = fget(a.fd); if (!file) return -EBADF; } +#ifdef CONFIG_IA64_PAGE_SIZE_4KB + if ((a.offset & ~PAGE_MASK) != 0) + return -EINVAL; + + down_write(¤t->mm->mmap_sem); + retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, a.offset >> PAGE_SHIFT); + up_write(¤t->mm->mmap_sem); +#else // CONFIG_IA64_PAGE_SIZE_4KB retval = ia32_do_mmap(file, a.addr, a.len, a.prot, a.flags, a.fd, a.offset); +#endif // CONFIG_IA64_PAGE_SIZE_4KB if (file) fput(file); return retval; } asmlinkage long +sys32_mprotect(unsigned long start, size_t len, unsigned long prot) +{ + +#ifdef CONFIG_IA64_PAGE_SIZE_4KB + return(sys_mprotect(start, len, prot)); +#else // CONFIG_IA64_PAGE_SIZE_4KB + if (prot == 0) + return(0); + len += start & ~PAGE_MASK; + if ((start & ~PAGE_MASK) && (prot & PROT_WRITE)) + prot |= PROT_EXEC; + return(sys_mprotect(start & PAGE_MASK, len & PAGE_MASK, prot)); +#endif // CONFIG_IA64_PAGE_SIZE_4KB +} + +asmlinkage long sys32_pipe(int *fd) { int retval; @@ -355,15 +374,17 @@ } asmlinkage long -sys32_mprotect(unsigned long start, size_t len, unsigned long prot) +sys32_signal (int sig, unsigned int handler) { + struct k_sigaction new_sa, old_sa; + int ret; - if (prot == 0) - return(0); - len += start & ~PAGE_MASK; - if ((start & ~PAGE_MASK) && (prot & PROT_WRITE)) - prot |= PROT_EXEC; - return(sys_mprotect(start & PAGE_MASK, len & PAGE_MASK, prot)); + new_sa.sa.sa_handler = (__sighandler_t) A(handler); + new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK; + + ret = do_sigaction(sig, &new_sa, &old_sa); + + return ret ? ret : (unsigned long)old_sa.sa.sa_handler; } asmlinkage long @@ -393,7 +414,7 @@ | (((long)set32.sig[1]) << 32); } ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); - + if (ret) return -EFAULT; } @@ -436,7 +457,7 @@ sigset32_t s32; int ret; mm_segment_t old_fs = get_fs(); - + if (set) { if (copy_from_user (&s32, set, sizeof(sigset32_t))) return -EFAULT; @@ -449,7 +470,7 @@ } set_fs (KERNEL_DS); ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL, - sigsetsize); + sigsetsize); set_fs (old_fs); if (ret) return ret; if (oset) { @@ -469,7 +490,7 @@ put_statfs (struct statfs32 *ubuf, struct statfs *kbuf) { int err; - + err = put_user (kbuf->f_type, &ubuf->f_type); err |= __put_user (kbuf->f_bsize, &ubuf->f_bsize); err |= __put_user (kbuf->f_blocks, &ubuf->f_blocks); @@ -491,7 +512,7 @@ int ret; struct statfs s; mm_segment_t old_fs = get_fs(); - + set_fs (KERNEL_DS); ret = sys_statfs((const char *)path, &s); set_fs (old_fs); @@ -508,7 +529,7 @@ int ret; struct statfs s; mm_segment_t old_fs = get_fs(); - + set_fs (KERNEL_DS); ret = sys_fstatfs(fd, &s); set_fs (old_fs); @@ -534,7 +555,6 @@ return (!access_ok(VERIFY_READ, i, sizeof(*i)) || (__get_user(o->tv_sec, &i->tv_sec) | __get_user(o->tv_usec, &i->tv_usec))); - return ENOSYS; } static inline long @@ -553,18 +573,16 @@ __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) | __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) | __get_user(o->it_value.tv_usec, &i->it_value.tv_usec))); - return ENOSYS; } static inline long put_it32(struct itimerval32 *o, struct itimerval *i) { - return (!access_ok(VERIFY_WRITE, i, sizeof(*i)) || + return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) | __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) | __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) | __put_user(i->it_value.tv_usec, &o->it_value.tv_usec))); - return ENOSYS; } extern int do_getitimer(int which, struct itimerval *value); @@ -605,7 +623,7 @@ return 0; } -asmlinkage unsigned long +asmlinkage unsigned long sys32_alarm(unsigned int seconds) { struct itimerval it_new, it_old; @@ -638,7 +656,7 @@ ia32_utime(char * filename, struct utimbuf_32 *times32) { mm_segment_t old_fs = get_fs(); - struct timeval tv[2]; + struct timeval tv[2], *tvp; long ret; if (times32) { @@ -647,15 +665,10 @@ get_user(tv[1].tv_sec, ×32->mtime); tv[1].tv_usec = 0; set_fs (KERNEL_DS); - } else { - set_fs (KERNEL_DS); - ret = sys_gettimeofday(&tv[0], 0); - if (ret < 0) - goto out; - tv[1] = tv[0]; - } - ret = sys_utimes(filename, tv); - out: + tvp = tv; + } else + tvp = NULL; + ret = sys_utimes(filename, tvp); set_fs (old_fs); return ret; } @@ -685,7 +698,7 @@ struct timeval ktv; struct timezone ktz; - if (tv) { + if (tv) { if (get_tv32(&ktv, tv)) return -EFAULT; } @@ -872,7 +885,7 @@ /* * We need 6 bitmaps (in/out/ex for both incoming and outgoing), * since we used fdset we need to allocate memory in units of - * long-words. + * long-words. */ ret = -ENOMEM; size = FDS_BYTES(n); @@ -946,11 +959,11 @@ } struct timespec32 { - int tv_sec; + int tv_sec; int tv_nsec; }; -extern asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp); +extern asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp); asmlinkage long sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp) @@ -958,7 +971,7 @@ struct timespec t; int ret; mm_segment_t old_fs = get_fs (); - + if (get_user (t.tv_sec, &rqtp->tv_sec) || __get_user (t.tv_nsec, &rqtp->tv_nsec)) return -EFAULT; @@ -967,7 +980,7 @@ set_fs (old_fs); if (rmtp && ret == -EINTR) { if (__put_user (t.tv_sec, &rmtp->tv_sec) || - __put_user (t.tv_nsec, &rmtp->tv_nsec)) + __put_user (t.tv_nsec, &rmtp->tv_nsec)) return -EFAULT; } return ret; @@ -1072,7 +1085,7 @@ struct rlimit r; int ret; mm_segment_t old_fs = get_fs (); - + set_fs (KERNEL_DS); ret = sys_getrlimit(resource, &r); set_fs (old_fs); @@ -1092,7 +1105,7 @@ int ret; mm_segment_t old_fs = get_fs (); - if (resource >= RLIM_NLIMITS) return -EINVAL; + if (resource >= RLIM_NLIMITS) return -EINVAL; if (get_user (r.rlim_cur, &rlim->rlim_cur) || __get_user (r.rlim_max, &rlim->rlim_max)) return -EFAULT; @@ -1109,7 +1122,7 @@ /* * Declare the IA32 version of the msghdr */ - + struct msghdr32 { unsigned int msg_name; /* Socket name */ int msg_namelen; /* Length of name */ @@ -1157,7 +1170,7 @@ { int size, err, ct; struct iovec32 *iov32; - + if(m->msg_namelen) { if(mode==VERIFY_READ) @@ -1166,7 +1179,7 @@ if(err<0) goto out; } - + m->msg_name = address; } else m->msg_name = NULL; @@ -1195,7 +1208,7 @@ } /* XXX This really belongs in some header file... -DaveM */ -#define MAX_SOCK_ADDR 128 /* 108 for Unix domain - +#define MAX_SOCK_ADDR 128 /* 108 for Unix domain - 16 for IP, 16 for IPX, 24 for IPv6, about 80 for AX.25 */ @@ -1215,13 +1228,13 @@ unsigned char *ctl_buf = ctl; struct msghdr msg_sys; int err, ctl_len, iov_size, total_len; - + err = -EFAULT; if (shape_msg(&msg_sys, msg)) - goto out; + goto out; sock = sockfd_lookup(fd, &err); - if (!sock) + if (!sock) goto out; /* do not move before msg_sys is valid */ @@ -1240,7 +1253,7 @@ /* This will also move the address data into kernel space */ err = verify_iovec32(&msg_sys, iov, address, VERIFY_READ); - if (err < 0) + if (err < 0) goto out_freeiov; total_len = err; @@ -1248,14 +1261,14 @@ if (msg_sys.msg_controllen > INT_MAX) goto out_freeiov; - ctl_len = msg_sys.msg_controllen; - if (ctl_len) + ctl_len = msg_sys.msg_controllen; + if (ctl_len) { if (ctl_len > sizeof(ctl)) { err = -ENOBUFS; ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); - if (ctl_buf == NULL) + if (ctl_buf == NULL) goto out_freeiov; } err = -EFAULT; @@ -1270,14 +1283,14 @@ err = sock_sendmsg(sock, &msg_sys, total_len); out_freectl: - if (ctl_buf != ctl) + if (ctl_buf != ctl) sock_kfree_s(sock->sk, ctl_buf, ctl_len); out_freeiov: if (iov != iovstack) sock_kfree_s(sock->sk, iov, iov_size); out_put: sockfd_put(sock); -out: +out: return err; } @@ -1301,7 +1314,7 @@ /* user mode address pointers */ struct sockaddr *uaddr; int *uaddr_len; - + err=-EFAULT; if (shape_msg(&msg_sys, msg)) goto out; @@ -1313,7 +1326,7 @@ err = -EINVAL; if (msg_sys.msg_iovlen > UIO_MAXIOV) goto out_put; - + /* Check whether to allocate the iovec area*/ err = -ENOMEM; iov_size = msg_sys.msg_iovlen * sizeof(struct iovec); @@ -1327,7 +1340,7 @@ * Save the user-mode address (verify_iovec will change the * kernel msghdr to use the kernel address space) */ - + uaddr = msg_sys.msg_name; uaddr_len = &msg->msg_namelen; err = verify_iovec32(&msg_sys, iov, addr, VERIFY_WRITE); @@ -1337,7 +1350,7 @@ cmsg_ptr = (unsigned long)msg_sys.msg_control; msg_sys.msg_flags = 0; - + if (sock->file->f_flags & O_NONBLOCK) flags |= MSG_DONTWAIT; err = sock_recvmsg(sock, &msg_sys, total_len, flags); @@ -1353,7 +1366,7 @@ err = __put_user(msg_sys.msg_flags, &msg->msg_flags); if (err) goto out_freeiov; - err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, + err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, &msg->msg_controllen); if (err) goto out_freeiov; @@ -1371,15 +1384,15 @@ /* Argument list sizes for sys_socketcall */ #define AL(x) ((x) * sizeof(u32)) static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), - AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), - AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; + AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), + AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; #undef AL extern asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen); extern asmlinkage long sys_connect(int fd, struct sockaddr *uservaddr, int addrlen); extern asmlinkage long sys_accept(int fd, struct sockaddr *upeer_sockaddr, - int *upeer_addrlen); + int *upeer_addrlen); extern asmlinkage long sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len); extern asmlinkage long sys_getpeername(int fd, struct sockaddr *usockaddr, @@ -1406,15 +1419,15 @@ int ret; u32 a[6]; u32 a0,a1; - + if (call<SYS_SOCKET||call>SYS_RECVMSG) return -EINVAL; if (copy_from_user(a, args, nas[call])) return -EFAULT; a0=a[0]; a1=a[1]; - - switch(call) + + switch(call) { case SYS_SOCKET: ret = sys_socket(a0, a1, a[2]); @@ -1490,52 +1503,52 @@ struct ipc_perm32 { - key_t key; - __kernel_uid_t32 uid; - __kernel_gid_t32 gid; - __kernel_uid_t32 cuid; - __kernel_gid_t32 cgid; - __kernel_mode_t32 mode; - unsigned short seq; + key_t key; + __kernel_uid_t32 uid; + __kernel_gid_t32 gid; + __kernel_uid_t32 cuid; + __kernel_gid_t32 cgid; + __kernel_mode_t32 mode; + unsigned short seq; }; struct semid_ds32 { - struct ipc_perm32 sem_perm; /* permissions .. see ipc.h */ - __kernel_time_t32 sem_otime; /* last semop time */ - __kernel_time_t32 sem_ctime; /* last change time */ - u32 sem_base; /* ptr to first semaphore in array */ - u32 sem_pending; /* pending operations to be processed */ - u32 sem_pending_last; /* last pending operation */ - u32 undo; /* undo requests on this array */ - unsigned short sem_nsems; /* no. of semaphores in array */ + struct ipc_perm32 sem_perm; /* permissions .. see ipc.h */ + __kernel_time_t32 sem_otime; /* last semop time */ + __kernel_time_t32 sem_ctime; /* last change time */ + u32 sem_base; /* ptr to first semaphore in array */ + u32 sem_pending; /* pending operations to be processed */ + u32 sem_pending_last; /* last pending operation */ + u32 undo; /* undo requests on this array */ + unsigned short sem_nsems; /* no. of semaphores in array */ }; struct msqid_ds32 { - struct ipc_perm32 msg_perm; - u32 msg_first; - u32 msg_last; - __kernel_time_t32 msg_stime; - __kernel_time_t32 msg_rtime; - __kernel_time_t32 msg_ctime; - u32 wwait; - u32 rwait; - unsigned short msg_cbytes; - unsigned short msg_qnum; - unsigned short msg_qbytes; - __kernel_ipc_pid_t32 msg_lspid; - __kernel_ipc_pid_t32 msg_lrpid; + struct ipc_perm32 msg_perm; + u32 msg_first; + u32 msg_last; + __kernel_time_t32 msg_stime; + __kernel_time_t32 msg_rtime; + __kernel_time_t32 msg_ctime; + u32 wwait; + u32 rwait; + unsigned short msg_cbytes; + unsigned short msg_qnum; + unsigned short msg_qbytes; + __kernel_ipc_pid_t32 msg_lspid; + __kernel_ipc_pid_t32 msg_lrpid; }; struct shmid_ds32 { - struct ipc_perm32 shm_perm; - int shm_segsz; - __kernel_time_t32 shm_atime; - __kernel_time_t32 shm_dtime; - __kernel_time_t32 shm_ctime; - __kernel_ipc_pid_t32 shm_cpid; - __kernel_ipc_pid_t32 shm_lpid; - unsigned short shm_nattch; + struct ipc_perm32 shm_perm; + int shm_segsz; + __kernel_time_t32 shm_atime; + __kernel_time_t32 shm_dtime; + __kernel_time_t32 shm_ctime; + __kernel_ipc_pid_t32 shm_cpid; + __kernel_ipc_pid_t32 shm_lpid; + unsigned short shm_nattch; }; #define IPCOP_MASK(__x) (1UL << (__x)) @@ -1876,7 +1889,7 @@ err = do_sys32_shmat (first, second, third, version, (void *)AA(ptr)); break; - case SHMDT: + case SHMDT: err = sys_shmdt ((char *)AA(ptr)); break; case SHMGET: @@ -1902,7 +1915,7 @@ { int i; - /* SMP: This is fairly trivial. We grab CURRENT_TIME and + /* SMP: This is fairly trivial. We grab CURRENT_TIME and stuff it to user space. No side effects */ i = CURRENT_TIME; if (tloc) { @@ -1913,29 +1926,29 @@ } struct rusage32 { - struct timeval32 ru_utime; - struct timeval32 ru_stime; - int ru_maxrss; - int ru_ixrss; - int ru_idrss; - int ru_isrss; - int ru_minflt; - int ru_majflt; - int ru_nswap; - int ru_inblock; - int ru_oublock; - int ru_msgsnd; - int ru_msgrcv; - int ru_nsignals; - int ru_nvcsw; - int ru_nivcsw; + struct timeval32 ru_utime; + struct timeval32 ru_stime; + int ru_maxrss; + int ru_ixrss; + int ru_idrss; + int ru_isrss; + int ru_minflt; + int ru_majflt; + int ru_nswap; + int ru_inblock; + int ru_oublock; + int ru_msgsnd; + int ru_msgrcv; + int ru_nsignals; + int ru_nvcsw; + int ru_nivcsw; }; static int put_rusage (struct rusage32 *ru, struct rusage *r) { int err; - + err = put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec); err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec); err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec); @@ -1968,7 +1981,7 @@ int ret; unsigned int status; mm_segment_t old_fs = get_fs(); - + set_fs (KERNEL_DS); ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r); set_fs (old_fs); @@ -1995,7 +2008,7 @@ struct rusage r; int ret; mm_segment_t old_fs = get_fs(); - + set_fs (KERNEL_DS); ret = sys_getrusage(who, &r); set_fs (old_fs); @@ -2009,7 +2022,7 @@ __kernel_clock_t32 tms_cutime; __kernel_clock_t32 tms_cstime; }; - + extern asmlinkage long sys_times(struct tms * tbuf); asmlinkage long @@ -2019,7 +2032,7 @@ long ret; mm_segment_t old_fs = get_fs (); int err; - + set_fs (KERNEL_DS); ret = sys_times(tbuf ? &t : NULL); set_fs (old_fs); @@ -2069,7 +2082,7 @@ #define PT_GS 10 #define PT_ORIG_EAX 11 #define PT_EIP 12 -#define PT_CS 13 +#define PT_CS 13 #define PT_EFL 14 #define PT_UESP 15 #define PT_SS 16 @@ -2385,7 +2398,7 @@ break; case IA32_PTRACE_GETREGS: - if (!access_ok(VERIFY_WRITE, (int *)data, 17*sizeof(int))) { + if (!access_ok(VERIFY_WRITE, (int *)data, 17*sizeof(int))) { ret = -EIO; break; } @@ -2399,7 +2412,7 @@ case IA32_PTRACE_SETREGS: { unsigned int tmp; - if (!access_ok(VERIFY_READ, (int *)data, 17*sizeof(int))) { + if (!access_ok(VERIFY_READ, (int *)data, 17*sizeof(int))) { ret = -EIO; break; } @@ -2444,7 +2457,7 @@ get_flock32(struct flock *kfl, struct flock32 *ufl) { int err; - + err = get_user(kfl->l_type, &ufl->l_type); err |= __get_user(kfl->l_whence, &ufl->l_whence); err |= __get_user(kfl->l_start, &ufl->l_start); @@ -2457,7 +2470,7 @@ put_flock32(struct flock *kfl, struct flock32 *ufl) { int err; - + err = __put_user(kfl->l_type, &ufl->l_type); err |= __put_user(kfl->l_whence, &ufl->l_whence); err |= __put_user(kfl->l_start, &ufl->l_start); @@ -2480,7 +2493,7 @@ case F_GETLK: case F_SETLK: case F_SETLKW: - if(cmd != F_GETLK && get_flock32(&f, (struct flock32 *)((long)arg))) + if(get_flock32(&f, (struct flock32 *)((long)arg))) return -EFAULT; old_fs = get_fs(); set_fs(KERNEL_DS); @@ -2501,27 +2514,27 @@ asmlinkage long sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact) { - struct k_sigaction new_ka, old_ka; - int ret; + struct k_sigaction new_ka, old_ka; + int ret; - if (act) { + if (act) { old_sigset32_t mask; - + ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler); ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); ret |= __get_user(mask, &act->sa_mask); if (ret) return ret; siginitset(&new_ka.sa.sa_mask, mask); - } + } - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler); ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); - } + } return ret; } @@ -2658,6 +2671,85 @@ return -ERESTARTNOHAND; } +asmlinkage long sys_msync(unsigned long start, size_t len, int flags); + +asmlinkage int +sys32_msync(unsigned int start, unsigned int len, int flags) +{ + unsigned int addr; + + if (OFFSET4K(start)) + return -EINVAL; + addr = start & PAGE_MASK; + return(sys_msync(addr, len + (start - addr), flags)); +} + +struct sysctl_ia32 { + unsigned int name; + int nlen; + unsigned int oldval; + unsigned int oldlenp; + unsigned int newval; + unsigned int newlen; + unsigned int __unused[4]; +}; + +extern asmlinkage long sys_sysctl(struct __sysctl_args *args); + +asmlinkage long +sys32_sysctl(struct sysctl_ia32 *args32) +{ + struct sysctl_ia32 a32; + mm_segment_t old_fs = get_fs (); + void *oldvalp, *newvalp; + size_t oldlen; + int *namep; + long ret; + + if (copy_from_user(&a32, args32, sizeof (a32))) + return -EFAULT; + + /* + * We need to pre-validate these because we have to disable address checking + * before calling do_sysctl() because of OLDLEN but we can't run the risk of the + * user specifying bad addresses here. Well, since we're dealing with 32 bit + * addresses, we KNOW that access_ok() will always succeed, so this is an + * expensive NOP, but so what... + */ + namep = (int *) A(a32.name); + oldvalp = (void *) A(a32.oldval); + newvalp = (void *) A(a32.newval); + + if ((oldvalp && get_user(oldlen, (int *) A(a32.oldlenp))) + || !access_ok(VERIFY_WRITE, namep, 0) + || !access_ok(VERIFY_WRITE, oldvalp, 0) + || !access_ok(VERIFY_WRITE, newvalp, 0)) + return -EFAULT; + + set_fs(KERNEL_DS); + lock_kernel(); + ret = do_sysctl(namep, a32.nlen, oldvalp, &oldlen, newvalp, (size_t) a32.newlen); + unlock_kernel(); + set_fs(old_fs); + + if (oldvalp && put_user (oldlen, (int *) A(a32.oldlenp))) + return -EFAULT; + + return ret; +} + +asmlinkage long +sys32_newuname(struct new_utsname * name) +{ + extern asmlinkage long sys_newuname(struct new_utsname * name); + int ret = sys_newuname(name); + + if (!ret) + if (copy_to_user(name->machine, "i686\0\0\0", 8)) + ret = -EFAULT; + return ret; +} + #ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */ /* In order to reduce some races, while at the same time doing additional @@ -2721,7 +2813,7 @@ __kernel_time_t32 dqb_btime; __kernel_time_t32 dqb_itime; }; - + extern asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr); @@ -2733,7 +2825,7 @@ struct dqblk d; mm_segment_t old_fs; char *spec; - + switch (cmds) { case Q_GETQUOTA: break; @@ -2782,7 +2874,7 @@ mm_segment_t old_fs; int ret; char *filenam; - + if (!times) return sys_utime(filename, NULL); if (get_user (t.actime, ×->actime) || @@ -2792,7 +2884,7 @@ ret = PTR_ERR(filenam); if (!IS_ERR(filenam)) { old_fs = get_fs(); - set_fs (KERNEL_DS); + set_fs (KERNEL_DS); ret = sys_utime(filenam, &t); set_fs (old_fs); putname (filenam); @@ -2869,18 +2961,18 @@ } struct ncp_mount_data32 { - int version; - unsigned int ncp_fd; - __kernel_uid_t32 mounted_uid; - __kernel_pid_t32 wdog_pid; - unsigned char mounted_vol[NCP_VOLNAME_LEN + 1]; - unsigned int time_out; - unsigned int retry_count; - unsigned int flags; - __kernel_uid_t32 uid; - __kernel_gid_t32 gid; - __kernel_mode_t32 file_mode; - __kernel_mode_t32 dir_mode; + int version; + unsigned int ncp_fd; + __kernel_uid_t32 mounted_uid; + __kernel_pid_t32 wdog_pid; + unsigned char mounted_vol[NCP_VOLNAME_LEN + 1]; + unsigned int time_out; + unsigned int retry_count; + unsigned int flags; + __kernel_uid_t32 uid; + __kernel_gid_t32 gid; + __kernel_mode_t32 file_mode; + __kernel_mode_t32 dir_mode; }; static void * @@ -2901,12 +2993,12 @@ } struct smb_mount_data32 { - int version; - __kernel_uid_t32 mounted_uid; - __kernel_uid_t32 uid; - __kernel_gid_t32 gid; - __kernel_mode_t32 file_mode; - __kernel_mode_t32 dir_mode; + int version; + __kernel_uid_t32 mounted_uid; + __kernel_uid_t32 uid; + __kernel_gid_t32 gid; + __kernel_mode_t32 file_mode; + __kernel_mode_t32 dir_mode; }; static void * @@ -3020,16 +3112,16 @@ } struct sysinfo32 { - s32 uptime; - u32 loads[3]; - u32 totalram; - u32 freeram; - u32 sharedram; - u32 bufferram; - u32 totalswap; - u32 freeswap; - unsigned short procs; - char _f[22]; + s32 uptime; + u32 loads[3]; + u32 totalram; + u32 freeram; + u32 sharedram; + u32 bufferram; + u32 totalswap; + u32 freeswap; + unsigned short procs; + char _f[22]; }; extern asmlinkage long sys_sysinfo(struct sysinfo *info); @@ -3040,7 +3132,7 @@ struct sysinfo s; int ret, err; mm_segment_t old_fs = get_fs (); - + set_fs (KERNEL_DS); ret = sys_sysinfo(&s); set_fs (old_fs); @@ -3059,7 +3151,7 @@ return -EFAULT; return ret; } - + extern asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval); @@ -3069,7 +3161,7 @@ struct timespec t; int ret; mm_segment_t old_fs = get_fs (); - + set_fs (KERNEL_DS); ret = sys_sched_rr_get_interval(pid, &t); set_fs (old_fs); @@ -3088,7 +3180,7 @@ old_sigset_t s; int ret; mm_segment_t old_fs = get_fs(); - + if (set && get_user (s, set)) return -EFAULT; set_fs (KERNEL_DS); ret = sys_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL); @@ -3106,7 +3198,7 @@ old_sigset_t s; int ret; mm_segment_t old_fs = get_fs(); - + set_fs (KERNEL_DS); ret = sys_sigpending(&s); set_fs (old_fs); @@ -3123,7 +3215,7 @@ sigset_t32 s32; int ret; mm_segment_t old_fs = get_fs(); - + set_fs (KERNEL_DS); ret = sys_rt_sigpending(&s, sigsetsize); set_fs (old_fs); @@ -3234,7 +3326,7 @@ mm_segment_t old_fs = get_fs(); siginfo_t info; siginfo_t32 info32; - + if (copy_from_user (&s32, uthese, sizeof(sigset_t32))) return -EFAULT; switch (_NSIG_WORDS) { @@ -3270,7 +3362,7 @@ siginfo_t32 info32; int ret; mm_segment_t old_fs = get_fs(); - + if (copy_from_user (&info32, uinfo, sizeof(siginfo_t32))) return -EFAULT; /* XXX: Is this correct? */ @@ -3315,7 +3407,7 @@ uid_t a, b, c; int ret; mm_segment_t old_fs = get_fs(); - + set_fs (KERNEL_DS); ret = sys_getresuid(&a, &b, &c); set_fs (old_fs); @@ -3354,12 +3446,12 @@ asmlinkage long sys32_getresgid(__kernel_gid_t32 *rgid, __kernel_gid_t32 *egid, - __kernel_gid_t32 *sgid) + __kernel_gid_t32 *sgid) { gid_t a, b, c; int ret; mm_segment_t old_fs = get_fs(); - + set_fs (KERNEL_DS); ret = sys_getresgid(&a, &b, &c); set_fs (old_fs); @@ -3379,7 +3471,7 @@ gid_t gl[NGROUPS]; int ret, i; mm_segment_t old_fs = get_fs (); - + set_fs (KERNEL_DS); ret = sys_getgroups(gidsetsize, gl); set_fs (old_fs); @@ -3398,13 +3490,13 @@ gid_t gl[NGROUPS]; int ret, i; mm_segment_t old_fs = get_fs (); - + if ((unsigned) gidsetsize > NGROUPS) return -EINVAL; for (i = 0; i < gidsetsize; i++, grouplist++) if (__get_user (gl[i], grouplist)) return -EFAULT; - set_fs (KERNEL_DS); + set_fs (KERNEL_DS); ret = sys_setgroups(gidsetsize, gl); set_fs (old_fs); return ret; @@ -3442,26 +3534,26 @@ } struct msghdr32 { - u32 msg_name; - int msg_namelen; - u32 msg_iov; - __kernel_size_t32 msg_iovlen; - u32 msg_control; - __kernel_size_t32 msg_controllen; - unsigned msg_flags; + u32 msg_name; + int msg_namelen; + u32 msg_iov; + __kernel_size_t32 msg_iovlen; + u32 msg_control; + __kernel_size_t32 msg_controllen; + unsigned msg_flags; }; struct cmsghdr32 { - __kernel_size_t32 cmsg_len; - int cmsg_level; - int cmsg_type; + __kernel_size_t32 cmsg_len; + int cmsg_level; + int cmsg_type; }; /* Bleech... */ #define __CMSG32_NXTHDR(ctl, len, cmsg, cmsglen) \ - __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen)) + __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen)) #define CMSG32_NXTHDR(mhdr, cmsg, cmsglen) \ - cmsg32_nxthdr((mhdr), (cmsg), (cmsglen)) + cmsg32_nxthdr((mhdr), (cmsg), (cmsglen)) #define CMSG32_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) ) @@ -3479,7 +3571,7 @@ __inline__ struct cmsghdr32 * __cmsg32_nxthdr(void *__ctl, __kernel_size_t __size, - struct cmsghdr32 *__cmsg, int __cmsg_len) + struct cmsghdr32 *__cmsg, int __cmsg_len) { struct cmsghdr32 * __ptr; @@ -3541,7 +3633,7 @@ err |= get_user(kmsg->msg_iovlen, &umsg->msg_iovlen); err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen); err |= get_user(kmsg->msg_flags, &umsg->msg_flags); - + return err; } @@ -3588,7 +3680,7 @@ */ static int cmsghdr_from_user32_to_kern(struct msghdr *kmsg, unsigned char *stackbuf, - int stackbuf_size) + int stackbuf_size) { struct cmsghdr32 *ucmsg; struct cmsghdr *kcmsg, *kcmsg_base; @@ -3812,7 +3904,7 @@ kcmsg32->cmsg_len = clen32; ucmsg = (struct cmsghdr *) (((char *)ucmsg) + - CMSG_ALIGN(clen64)); + CMSG_ALIGN(clen64)); wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32)); } @@ -3985,7 +4077,7 @@ } extern asmlinkage long sys_init_module(const char *name_user, - struct module *mod_user); + struct module *mod_user); /* Hey, when you're trying to init module, take time and prepare us a nice 64bit * module structure, even if from 32bit modutils... Why to pollute kernel... :)) @@ -4275,7 +4367,7 @@ asmlinkage long sys32_query_module(char *name_user, int which, char *buf, - __kernel_size_t32 bufsize, u32 ret) + __kernel_size_t32 bufsize, u32 ret) { struct module *mod; int err; @@ -4340,7 +4432,7 @@ u32 value; char name[60]; }; - + extern asmlinkage long sys_get_kernel_syms(struct kernel_sym *table); asmlinkage long @@ -4349,7 +4441,7 @@ int len, i; struct kernel_sym *tbl; mm_segment_t old_fs; - + len = sys_get_kernel_syms(NULL); if (!table) return len; tbl = kmalloc (len * sizeof (struct kernel_sym), GFP_KERNEL); @@ -4477,7 +4569,7 @@ nfs_svc32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) { int err; - + err = __get_user(karg->ca_version, &arg32->ca32_version); err |= __get_user(karg->ca_svc.svc_port, &arg32->ca32_svc.svc32_port); err |= __get_user(karg->ca_svc.svc_nthreads, @@ -4489,7 +4581,7 @@ nfs_clnt32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) { int err; - + err = __get_user(karg->ca_version, &arg32->ca32_version); err |= copy_from_user(&karg->ca_client.cl_ident[0], &arg32->ca32_client.cl32_ident[0], @@ -4513,7 +4605,7 @@ nfs_exp32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) { int err; - + err = __get_user(karg->ca_version, &arg32->ca32_version); err |= copy_from_user(&karg->ca_export.ex_client[0], &arg32->ca32_export.ex32_client[0], @@ -4589,7 +4681,7 @@ nfs_getfh32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) { int err; - + err = __get_user(karg->ca_version, &arg32->ca32_version); err |= copy_from_user(&karg->ca_getfh.gf_addr, &arg32->ca32_getfh.gf32_addr, @@ -4607,7 +4699,7 @@ nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32) { int err; - + err = copy_to_user(&res32->cr32_getfh, &kres->cr_getfh, sizeof(res32->cr32_getfh)); @@ -4772,19 +4864,6 @@ } -extern asmlinkage long sys_newuname(struct new_utsname * name); - -asmlinkage long -sys32_newuname(struct new_utsname * name) -{ - int ret = sys_newuname(name); - - if (current->personality == PER_LINUX32 && !ret) { - ret = copy_to_user(name->machine, "sparc\0\0", 8); - } - return ret; -} - extern asmlinkage ssize_t sys_pread(unsigned int fd, char * buf, size_t count, loff_t pos); @@ -4825,7 +4904,7 @@ } extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, - size_t count); + size_t count); asmlinkage long sys32_sendfile(int out_fd, int in_fd, __kernel_off_t32 *offset, s32 count) @@ -4833,17 +4912,17 @@ mm_segment_t old_fs = get_fs(); int ret; off_t of; - + if (offset && get_user(of, offset)) return -EFAULT; - + set_fs(KERNEL_DS); ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count); set_fs(old_fs); - + if (!ret && offset && put_user(of, offset)) return -EFAULT; - + return ret; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/Makefile linux.ac/arch/ia64/kernel/Makefile --- linux.vanilla/arch/ia64/kernel/Makefile Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/Makefile Tue Apr 10 18:08:40 2001 @@ -11,19 +11,18 @@ O_TARGET := kernel.o -obj-y := acpi.o entry.o gate.o efi.o efi_stub.o irq.o irq_ia64.o irq_sapic.o ivt.o \ +export-objs := ia64_ksyms.o + +obj-y := acpi.o entry.o gate.o efi.o efi_stub.o ia64_ksyms.o irq.o irq_ia64.o irq_sapic.o ivt.o \ machvec.o pal.o process.o perfmon.o ptrace.o sal.o semaphore.o setup.o \ signal.o sys_ia64.o traps.o time.o unaligned.o unwind.o obj-$(CONFIG_IA64_GENERIC) += machvec.o iosapic.o obj-$(CONFIG_IA64_DIG) += iosapic.o obj-$(CONFIG_IA64_PALINFO) += palinfo.o +obj-$(CONFIG_IA64_EFIVARS) += efivars.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_SMP) += smp.o smpboot.o obj-$(CONFIG_IA64_MCA) += mca.o mca_asm.o obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o - -export-objs := ia64_ksyms.o - -clean:: include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/acpi.c linux.ac/arch/ia64/kernel/acpi.c --- linux.vanilla/arch/ia64/kernel/acpi.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/acpi.c Tue Apr 10 18:08:40 2001 @@ -1,9 +1,9 @@ /* - * Advanced Configuration and Power Interface + * Advanced Configuration and Power Interface * - * Based on 'ACPI Specification 1.0b' February 2, 1999 and + * Based on 'ACPI Specification 1.0b' February 2, 1999 and * 'IA-64 Extensions to ACPI Specification' Revision 0.6 - * + * * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com> * Copyright (C) 2000 Hewlett-Packard Co. @@ -111,15 +111,15 @@ * Identify usable CPU's and remember them for SMP bringup later. */ static void __init -acpi20_lsapic (char *p) +acpi20_lsapic (char *p) { int add = 1; acpi20_entry_lsapic_t *lsapic = (acpi20_entry_lsapic_t *) p; - printk(" CPU %d (%.04x:%.04x): ", total_cpus, lsapic->eid, lsapic->id); + printk(" CPU %.04x:%.04x: ", lsapic->eid, lsapic->id); if ((lsapic->flags & LSAPIC_ENABLED) == 0) { - printk("Disabled.\n"); + printk("disabled.\n"); add = 0; } @@ -127,11 +127,14 @@ smp_boot_data.cpu_phys_id[total_cpus] = -1; #endif if (add) { - printk("Available.\n"); available_cpus++; + printk("available"); #ifdef CONFIG_SMP smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid; -#endif /* CONFIG_SMP */ + if (hard_smp_processor_id() == smp_boot_data.cpu_phys_id[total_cpus]) + printk(" (BSP)"); +#endif + printk(".\n"); } total_cpus++; } @@ -199,7 +202,7 @@ printk("ACPI 2.0 MADT: LOCAL SAPIC\n"); acpi20_lsapic(p); break; - + case ACPI20_ENTRY_IO_SAPIC: iosapic = (acpi_entry_iosapic_t *) p; if (iosapic_init) @@ -233,7 +236,7 @@ end = p + (madt->header.length - sizeof(acpi_madt_t)); while (p < end) { - + switch (*p) { case ACPI20_ENTRY_INT_SRC_OVERRIDE: printk("ACPI 2.0 MADT: INT SOURCE Override\n"); @@ -251,7 +254,7 @@ available_cpus, total_cpus); } -int __init +int __init acpi20_parse (acpi20_rsdp_t *rsdp20) { acpi_xsdt_t *xsdt; @@ -311,12 +314,12 @@ printk("ACPI: Found 0 CPUS; assuming 1\n"); available_cpus = 1; /* We've got at least one of these, no? */ } - smp_boot_data.cpu_count = available_cpus; + smp_boot_data.cpu_count = total_cpus; #endif return 1; } /* - * ACPI 1.0b with 0.71 IA64 extensions functions; should be removed once all + * ACPI 1.0b with 0.71 IA64 extensions functions; should be removed once all * platforms start supporting ACPI 2.0 */ @@ -324,13 +327,13 @@ * Identify usable CPU's and remember them for SMP bringup later. */ static void __init -acpi_lsapic (char *p) +acpi_lsapic (char *p) { int add = 1; acpi_entry_lsapic_t *lsapic = (acpi_entry_lsapic_t *) p; - if ((lsapic->flags & LSAPIC_PRESENT) == 0) + if ((lsapic->flags & LSAPIC_PRESENT) == 0) return; printk(" CPU %d (%.04x:%.04x): ", total_cpus, lsapic->eid, lsapic->id); @@ -388,7 +391,7 @@ case ACPI_ENTRY_LOCAL_SAPIC: acpi_lsapic(p); break; - + case ACPI_ENTRY_IO_SAPIC: iosapic = (acpi_entry_iosapic_t *) p; if (iosapic_init) @@ -415,7 +418,7 @@ printk(" %d CPUs available, %d CPUs total\n", available_cpus, total_cpus); } -int __init +int __init acpi_parse (acpi_rsdp_t *rsdp) { acpi_rsdt_t *rsdt; @@ -433,9 +436,9 @@ return 0; } - printk("ACPI: %.6s %.8s %d.%d\n", rsdt->header.oem_id, rsdt->header.oem_table_id, + printk("ACPI: %.6s %.8s %d.%d\n", rsdt->header.oem_id, rsdt->header.oem_table_id, rsdt->header.oem_revision >> 16, rsdt->header.oem_revision & 0xffff); - + #ifdef CONFIG_ACPI_KERNEL_CONFIG acpi_cf_init(rsdp); #endif @@ -460,7 +463,7 @@ printk("ACPI: Found 0 CPUS; assuming 1\n"); available_cpus = 1; /* We've got at least one of these, no? */ } - smp_boot_data.cpu_count = available_cpus; + smp_boot_data.cpu_count = total_cpus; #endif return 1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/brl_emu.c linux.ac/arch/ia64/kernel/brl_emu.c --- linux.vanilla/arch/ia64/kernel/brl_emu.c Thu Jun 22 15:09:44 2000 +++ linux.ac/arch/ia64/kernel/brl_emu.c Tue Apr 10 18:08:40 2001 @@ -1,6 +1,6 @@ /* * Emulation of the "brl" instruction for IA64 processors that - * don't support it in hardware. + * don't support it in hardware. * Author: Stephan Zeisset, Intel Corp. <Stephan.Zeisset@intel.com> */ @@ -23,9 +23,9 @@ * of an and operation with the mask must be all 0's * or all 1's for the address to be valid. */ -#define unimplemented_virtual_address(va) ( \ - ((va) & my_cpu_data.unimpl_va_mask) != 0 && \ - ((va) & my_cpu_data.unimpl_va_mask) != my_cpu_data.unimpl_va_mask \ +#define unimplemented_virtual_address(va) ( \ + ((va) & local_cpu_data->unimpl_va_mask) != 0 && \ + ((va) & local_cpu_data->unimpl_va_mask) != local_cpu_data->unimpl_va_mask \ ) /* @@ -35,13 +35,13 @@ * address to be valid. */ #define unimplemented_physical_address(pa) ( \ - ((pa) & my_cpu_data.unimpl_pa_mask) != 0 \ + ((pa) & local_cpu_data->unimpl_pa_mask) != 0 \ ) /* - * Handle an illegal operation fault that was caused by an + * Handle an illegal operation fault that was caused by an * unimplemented "brl" instruction. - * If we are not successful (e.g because the illegal operation + * If we are not successful (e.g because the illegal operation * wasn't caused by a "brl" after all), we return -1. * If we are successful, we return either 0 or the address * of a "fixup" function for manipulating preserved register @@ -64,8 +64,8 @@ * Decode the instruction bundle. */ - if (copy_from_user(bundle, (void *) (regs->cr_iip), sizeof(bundle))) - return rv; + if (copy_from_user(bundle, (void *) (regs->cr_iip), sizeof(bundle))) + return rv; next_ip = (unsigned long) regs->cr_iip + 16; @@ -79,14 +79,14 @@ btype = ((bundle[1] >> 29) & 0x7); qp = ((bundle[1] >> 23) & 0x3f); offset = ((bundle[1] & 0x0800000000000000L) << 4) - | ((bundle[1] & 0x00fffff000000000L) >> 32) + | ((bundle[1] & 0x00fffff000000000L) >> 32) | ((bundle[1] & 0x00000000007fffffL) << 40) | ((bundle[0] & 0xffff000000000000L) >> 24); tmp_taken = regs->pr & (1L << qp); switch(opcode) { - + case 0xC: /* * Long Branch. @@ -169,7 +169,7 @@ */ regs->cr_ifs = ((regs->cr_ifs & 0xffffffc00000007f) - ((regs->cr_ifs >> 7) & 0x7f)); - + break; default: @@ -180,7 +180,7 @@ } - regs->cr_iip += offset; + regs->cr_iip += offset; ia64_psr(regs)->ri = 0; if (ia64_psr(regs)->it == 0) @@ -188,7 +188,7 @@ else unimplemented_address = unimplemented_virtual_address(regs->cr_iip); - if (unimplemented_address) { + if (unimplemented_address) { /* * The target address contains unimplemented bits. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/efi.c linux.ac/arch/ia64/kernel/efi.c --- linux.vanilla/arch/ia64/kernel/efi.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/kernel/efi.c Sat Apr 14 01:18:00 2001 @@ -5,9 +5,9 @@ * * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> - * Copyright (C) 1999-2000 Hewlett-Packard Co. + * Copyright (C) 1999-2001 Hewlett-Packard Co. * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com> - * Copyright (C) 1999-2000 Stephane Eranian <eranian@hpl.hp.com> + * Copyright (C) 1999-2001 Stephane Eranian <eranian@hpl.hp.com> * * All EFI Runtime Services are not implemented yet as EFI only * supports physical mode addressing on SoftSDV. This is to be fixed @@ -16,9 +16,8 @@ * Implemented EFI runtime services and virtual mode calls. --davidm * * Goutham Rao: <goutham.rao@intel.com> - * Skip non-WB memory and ignore empty memory ranges. + * Skip non-WB memory and ignore empty memory ranges. */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/types.h> @@ -26,6 +25,7 @@ #include <asm/efi.h> #include <asm/io.h> +#include <asm/kregs.h> #include <asm/pgtable.h> #include <asm/processor.h> @@ -128,9 +128,9 @@ efi_memory_desc_t *md; u64 efi_desc_size, start, end; - efi_map_start = __va(ia64_boot_param.efi_memmap); - efi_map_end = efi_map_start + ia64_boot_param.efi_memmap_size; - efi_desc_size = ia64_boot_param.efi_memdesc_size; + efi_map_start = __va(ia64_boot_param->efi_memmap); + efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; + efi_desc_size = ia64_boot_param->efi_memdesc_size; for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { md = p; @@ -203,9 +203,9 @@ u64 mask, flags; u64 vaddr; - efi_map_start = __va(ia64_boot_param.efi_memmap); - efi_map_end = efi_map_start + ia64_boot_param.efi_memmap_size; - efi_desc_size = ia64_boot_param.efi_memdesc_size; + efi_map_start = __va(ia64_boot_param->efi_memmap); + efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; + efi_desc_size = ia64_boot_param->efi_memdesc_size; for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { md = p; @@ -218,61 +218,48 @@ continue; } /* - * We must use the same page size as the one used - * for the kernel region when we map the PAL code. - * This way, we avoid overlapping TRs if code is - * executed nearby. The Alt I-TLB installs 256MB - * page sizes as defined for region 7. + * The only ITLB entry in region 7 that is used is the one installed by + * __start(). That entry covers a 64MB range. * * XXX Fixme: should be dynamic here (for page size) */ - mask = ~((1 << _PAGE_SIZE_256M)-1); + mask = ~((1 << _PAGE_SIZE_64M) - 1); vaddr = PAGE_OFFSET + md->phys_addr; /* - * We must check that the PAL mapping won't overlap - * with the kernel mapping on ITR1. + * We must check that the PAL mapping won't overlap with the kernel + * mapping. * - * PAL code is guaranteed to be aligned on a power of 2 - * between 4k and 256KB. - * Also from the documentation, it seems like there is an - * implicit guarantee that you will need only ONE ITR to - * map it. This implies that the PAL code is always aligned - * on its size, i.e., the closest matching page size supported - * by the TLB. Therefore PAL code is guaranteed never to cross - * a 256MB unless it is bigger than 256MB (very unlikely!). - * So for now the following test is enough to determine whether - * or not we need a dedicated ITR for the PAL code. + * PAL code is guaranteed to be aligned on a power of 2 between 4k and + * 256KB. Also from the documentation, it seems like there is an implicit + * guarantee that you will need only ONE ITR to map it. This implies that + * the PAL code is always aligned on its size, i.e., the closest matching + * page size supported by the TLB. Therefore PAL code is guaranteed never + * to cross a 64MB unless it is bigger than 64MB (very unlikely!). So for + * now the following test is enough to determine whether or not we need a + * dedicated ITR for the PAL code. */ - if ((vaddr & mask) == (PAGE_OFFSET & mask)) { - printk(__FUNCTION__ " : no need to install ITR for PAL Code\n"); + if ((vaddr & mask) == (KERNEL_START & mask)) { + printk(__FUNCTION__ " : no need to install ITR for PAL code\n"); continue; } - printk("CPU %d: mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n", + printk("CPU %d: mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n", smp_processor_id(), md->phys_addr, md->phys_addr + (md->num_pages << 12), - vaddr & mask, (vaddr & mask) + 256*1024*1024); + vaddr & mask, (vaddr & mask) + 64*1024*1024); /* * Cannot write to CRx with PSR.ic=1 */ ia64_clear_ic(flags); - - /* - * ITR0/DTR0: used for kernel code/data - * ITR1/DTR1: used by HP simulator - * ITR2/DTR2: map PAL code - */ - ia64_itr(0x1, 2, vaddr & mask, - pte_val(mk_pte_phys(md->phys_addr, - __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RX))), - _PAGE_SIZE_256M); + ia64_itr(0x1, IA64_TR_PALCODE, vaddr & mask, + pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL)), _PAGE_SIZE_64M); local_irq_restore(flags); - ia64_srlz_i (); + ia64_srlz_i(); } } -void __init +void __init efi_init (void) { void *efi_map_start, *efi_map_end; @@ -301,14 +288,14 @@ if (mem_limit != ~0UL) printk("Ignoring memory above %luMB\n", mem_limit >> 20); - efi.systab = __va(ia64_boot_param.efi_systab); + efi.systab = __va(ia64_boot_param->efi_systab); /* * Verify the EFI Table - */ - if (efi.systab == NULL) + */ + if (efi.systab == NULL) panic("Woah! Can't find EFI system table.\n"); - if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) + if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) panic("Woah! EFI system table signature incorrect\n"); if ((efi.systab->hdr.revision ^ EFI_SYSTEM_TABLE_REVISION) >> 16 != 0) printk("Warning: EFI system table major version mismatch: " @@ -360,9 +347,9 @@ efi.get_next_high_mono_count = phys_get_next_high_mono_count; efi.reset_system = phys_reset_system; - efi_map_start = __va(ia64_boot_param.efi_memmap); - efi_map_end = efi_map_start + ia64_boot_param.efi_memmap_size; - efi_desc_size = ia64_boot_param.efi_memdesc_size; + efi_map_start = __va(ia64_boot_param->efi_memmap); + efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; + efi_desc_size = ia64_boot_param->efi_memdesc_size; #if EFI_DEBUG /* print EFI memory map: */ @@ -380,16 +367,7 @@ #endif efi_map_pal_code(); - -#ifndef CONFIG_IA64_SOFTSDV_HACKS - /* - * (Some) SoftSDVs seem to have a problem with this call. - * Since it's mostly a performance optimization, just don't do - * it for now... --davidm 99/12/6 - */ efi_enter_virtual_mode(); -#endif - } void @@ -400,9 +378,9 @@ efi_status_t status; u64 efi_desc_size; - efi_map_start = __va(ia64_boot_param.efi_memmap); - efi_map_end = efi_map_start + ia64_boot_param.efi_memmap_size; - efi_desc_size = ia64_boot_param.efi_memdesc_size; + efi_map_start = __va(ia64_boot_param->efi_memmap); + efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; + efi_desc_size = ia64_boot_param->efi_memdesc_size; for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { md = p; @@ -441,9 +419,9 @@ } status = efi_call_phys(__va(runtime->set_virtual_address_map), - ia64_boot_param.efi_memmap_size, - efi_desc_size, ia64_boot_param.efi_memdesc_version, - ia64_boot_param.efi_memmap); + ia64_boot_param->efi_memmap_size, + efi_desc_size, ia64_boot_param->efi_memdesc_version, + ia64_boot_param->efi_memmap); if (status != EFI_SUCCESS) { printk("Warning: unable to switch EFI into virtual mode (status=%lu)\n", status); return; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/efi_stub.S linux.ac/arch/ia64/kernel/efi_stub.S --- linux.vanilla/arch/ia64/kernel/efi_stub.S Sat Jul 15 00:08:11 2000 +++ linux.ac/arch/ia64/kernel/efi_stub.S Tue Apr 10 18:08:40 2001 @@ -33,13 +33,6 @@ #include <asm/processor.h> #include <asm/asmmacro.h> - .text - .psr abi64 - .psr lsb - .lsb - - .text - /* * Inputs: * in0 = address of function descriptor of EFI routine to call @@ -50,15 +43,15 @@ */ GLOBAL_ENTRY(efi_call_phys) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) alloc loc1=ar.pfs,8,5,7,0 ld8 r2=[in0],8 // load EFI function's entry point mov loc0=rp - UNW(.body) + .body ;; mov loc2=gp // save global pointer mov loc4=ar.rsc // save RSE configuration - mov ar.rsc=r0 // put RSE in enforced lazy, LE mode + mov ar.rsc=0 // put RSE in enforced lazy, LE mode ;; ld8 gp=[in0] // load EFI function's global pointer @@ -80,7 +73,7 @@ mov out5=in6 mov out6=in7 br.call.sptk.few rp=b6 // call the EFI function -.ret1: mov ar.rsc=r0 // put RSE in enforced lazy, LE mode +.ret1: mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 br.call.sptk.few rp=ia64_switch_mode // return to virtual mode .ret2: mov ar.rsc=loc4 // restore RSE configuration diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/efivars.c linux.ac/arch/ia64/kernel/efivars.c --- linux.vanilla/arch/ia64/kernel/efivars.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ia64/kernel/efivars.c Tue Apr 10 18:08:40 2001 @@ -0,0 +1,433 @@ +/* + * EFI Variables - efivars.c + * + * Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com> + * + * This code takes all variables accessible from EFI runtime and + * exports them via /proc + * + * Reads to /proc/efi/varname return an efi_variable_t structure. + * Writes to /proc/efi/varname must be an efi_variable_t structure. + * Writes with DataSize = 0 or Attributes = 0 deletes the variable. + * Writes with a new value in VariableName+VendorGuid creates + * a new variable. + * + * + * 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 + * + * Changelog: + * + * 12 March 2001 - Matt Domsch <Matt_Domsch@dell.com> + * Feedback received from Stephane Eranian incorporated. + * efivar_write() checks copy_from_user() return value. + * efivar_read/write() returns proper errno. + * v0.02 release to linux-ia64@linuxia64.org + * + * 26 February 2001 - Matt Domsch <Matt_Domsch@dell.com> + * v0.01 release to linux-ia64@linuxia64.org + */ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/proc_fs.h> +#include <linux/sched.h> /* for capable() */ +#include <linux/mm.h> +#include <linux/module.h> + +#include <asm/efi.h> +#include <asm/uaccess.h> +#ifdef CONFIG_SMP +#include <linux/smp.h> +#endif + +MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>"); +MODULE_DESCRIPTION("/proc interface to EFI Variables"); + +#define EFIVARS_VERSION "0.02 2001-Mar-12" + +static int +efivar_read(char *page, char **start, off_t off, + int count, int *eof, void *data); +static int +efivar_write(struct file *file, const char *buffer, + unsigned long count, void *data); + + +/* + * The maximum size of VariableName + Data = 1024 + * Therefore, it's reasonable to save that much + * space in each part of the structure, + * and we use a page for reading/writing. + */ + +typedef struct _efi_variable_t { + efi_char16_t VariableName[1024/sizeof(efi_char16_t)]; + efi_guid_t VendorGuid; + unsigned long DataSize; + __u8 Data[1024]; + efi_status_t Status; + __u32 Attributes; +} __attribute__((packed)) efi_variable_t; + + +typedef struct _efivar_entry_t { + efi_variable_t var; + struct proc_dir_entry *entry; + struct list_head list; +} efivar_entry_t; + +spinlock_t efivars_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(efivar_list); +static struct proc_dir_entry *efi_dir = NULL; + +#define efivar_entry(n) list_entry(n, efivar_entry_t, list) + +/* Return the number of unicode characters in data */ +static unsigned long +utf8_strlen(efi_char16_t *data, unsigned long maxlength) +{ + unsigned long length = 0; + while (*data++ != 0 && length < maxlength) + length++; + return length; +} + +/* Return the number of bytes is the length of this string */ +/* Note: this is NOT the same as the number of unicode characters */ +static inline unsigned long +utf8_strsize(efi_char16_t *data, unsigned long maxlength) +{ + return utf8_strlen(data, maxlength/sizeof(efi_char16_t)) * + sizeof(efi_char16_t); +} + + +static int +proc_calc_metrics(char *page, char **start, off_t off, + int count, int *eof, int len) +{ + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + + +static void +uuid_unparse(efi_guid_t *guid, char *out) +{ + sprintf(out, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + guid->data1, guid->data2, guid->data3, + guid->data4[0], guid->data4[1], guid->data4[2], guid->data4[3], + guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]); +} + + + + + +/* + * efivar_create_proc_entry() + * Requires: + * variable_name_size = number of bytes required to hold + * variable_name (not counting the NULL + * character at the end. + * Returns 1 on failure, 0 on success + */ +static int +efivar_create_proc_entry(unsigned long variable_name_size, + efi_char16_t *variable_name, + efi_guid_t *vendor_guid) +{ + + int i, short_name_size = variable_name_size / + sizeof(efi_char16_t) + 38; + char *short_name = kmalloc(short_name_size+1, + GFP_KERNEL); + efivar_entry_t *new_efivar = kmalloc(sizeof(efivar_entry_t), + GFP_KERNEL); + if (!short_name || !new_efivar) { + if (short_name) kfree(short_name); + if (new_efivar) kfree(new_efivar); + return 1; + } + memset(short_name, 0, short_name_size+1); + memset(new_efivar, 0, sizeof(efivar_entry_t)); + + memcpy(new_efivar->var.VariableName, variable_name, + variable_name_size); + memcpy(&(new_efivar->var.VendorGuid), vendor_guid, sizeof(efi_guid_t)); + + /* Convert Unicode to normal chars (assume top bits are 0), + ala UTF-8 */ + for (i=0; i<variable_name_size / sizeof(efi_char16_t); i++) { + short_name[i] = variable_name[i] & 0xFF; + } + + /* This is ugly, but necessary to separate one vendor's + private variables from another's. */ + + *(short_name + strlen(short_name)) = '-'; + uuid_unparse(vendor_guid, short_name + strlen(short_name)); + + + /* Create the entry in proc */ + new_efivar->entry = create_proc_entry(short_name, 0600, efi_dir); + kfree(short_name); short_name = NULL; + if (!new_efivar->entry) return 1; + + + new_efivar->entry->data = new_efivar; + new_efivar->entry->read_proc = efivar_read; + new_efivar->entry->write_proc = efivar_write; + + list_add(&new_efivar->list, &efivar_list); + + + return 0; +} + + + +/*********************************************************** + * efivar_read() + * Requires: + * Modifies: page + * Returns: number of bytes written, or -EINVAL on failure + ***********************************************************/ + +static int +efivar_read(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len = sizeof(efi_variable_t); + efivar_entry_t *efi_var = data; + efi_variable_t *var_data = (efi_variable_t *)page; + + if (!page || !data) return -EINVAL; + + spin_lock(&efivars_lock); + MOD_INC_USE_COUNT; + + memcpy(var_data, &efi_var->var, len); + + var_data->DataSize = 1024; + var_data->Status = efi.get_variable(var_data->VariableName, + &var_data->VendorGuid, + &var_data->Attributes, + &var_data->DataSize, + var_data->Data); + + MOD_DEC_USE_COUNT; + spin_unlock(&efivars_lock); + + return proc_calc_metrics(page, start, off, count, eof, len); +} + +/*********************************************************** + * efivar_write() + * Requires: data is an efi_setvariable_t data type, + * properly filled in, possibly by a call + * first to efivar_read(). + * Caller must have CAP_SYS_ADMIN + * Modifies: NVRAM + * Returns: var_data->DataSize on success, errno on failure + * + ***********************************************************/ +static int +efivar_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + unsigned long strsize1, strsize2; + int found=0; + struct list_head *pos; + unsigned long size = sizeof(efi_variable_t); + efi_status_t status; + efivar_entry_t *efivar = data, *search_efivar = NULL; + efi_variable_t *var_data; + if (!data || count != size) { + printk(KERN_WARNING "efivars: improper struct of size 0x%lx passed.\n", count); + return -EINVAL; + } + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + spin_lock(&efivars_lock); + MOD_INC_USE_COUNT; + + var_data = kmalloc(size, GFP_KERNEL); + if (!var_data) { + MOD_DEC_USE_COUNT; + spin_unlock(&efivars_lock); + return -ENOMEM; + } + if (copy_from_user(var_data, buffer, size)) { + MOD_DEC_USE_COUNT; + spin_unlock(&efivars_lock); + return -EFAULT; + } + + + /* Since the data ptr we've currently got is probably for + a different variable find the right variable. + This allows any properly formatted data structure to + be written to any of the files in /proc/efi and it will work. + */ + list_for_each(pos, &efivar_list) { + search_efivar = efivar_entry(pos); + strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024); + strsize2 = utf8_strsize(var_data->VariableName, 1024); + if ( strsize1 == strsize2 && + !memcmp(&(search_efivar->var.VariableName), + var_data->VariableName, strsize1) && + !efi_guidcmp(search_efivar->var.VendorGuid, + var_data->VendorGuid)) { + found = 1; + break; + } + } + if (found) efivar = search_efivar; + + status = efi.set_variable(var_data->VariableName, + &var_data->VendorGuid, + var_data->Attributes, + var_data->DataSize, + var_data->Data); + + if (status != EFI_SUCCESS) { + printk(KERN_WARNING "set_variable() failed: status=%lx\n", status); + kfree(var_data); + MOD_DEC_USE_COUNT; + spin_unlock(&efivars_lock); + return -EIO; + } + + + if (!var_data->DataSize || !var_data->Attributes) { + /* We just deleted the NVRAM variable */ + remove_proc_entry(efivar->entry->name, efi_dir); + list_del(&efivar->list); + kfree(efivar); + } + + /* If this is a new variable, set up the proc entry for it. */ + if (!found) { + efivar_create_proc_entry(utf8_strsize(var_data->VariableName, + 1024), + var_data->VariableName, + &var_data->VendorGuid); + } + + kfree(var_data); + MOD_DEC_USE_COUNT; + spin_unlock(&efivars_lock); + return size; +} + + + +static int __init +efivars_init(void) +{ + + efi_status_t status; + efi_guid_t vendor_guid; + efi_char16_t *variable_name = kmalloc(1024, GFP_KERNEL); + unsigned long variable_name_size = 1024; + + spin_lock(&efivars_lock); + + printk(KERN_INFO "EFI Variables Facility v%s\n", EFIVARS_VERSION); + + /* Per EFI spec, the maximum storage allocated for both + the variable name and variable data is 1024 bytes. + */ + + efi_dir = proc_mkdir("efi", NULL); + + memset(variable_name, 0, 1024); + + do { + variable_name_size=1024; + + status = efi.get_next_variable(&variable_name_size, + variable_name, + &vendor_guid); + + + switch (status) { + case EFI_SUCCESS: + efivar_create_proc_entry(variable_name_size, + variable_name, + &vendor_guid); + break; + case EFI_NOT_FOUND: + break; + default: + printk(KERN_WARNING "get_next_variable: status=%lx\n", status); + status = EFI_NOT_FOUND; + break; + } + + } while (status != EFI_NOT_FOUND); + + kfree(variable_name); + spin_unlock(&efivars_lock); + return 0; +} + +static void __exit +efivars_exit(void) +{ + struct list_head *pos; + efivar_entry_t *efivar; + + spin_lock(&efivars_lock); + + list_for_each(pos, &efivar_list) { + efivar = efivar_entry(pos); + remove_proc_entry(efivar->entry->name, efi_dir); + list_del(&efivar->list); + kfree(efivar); + } + remove_proc_entry(efi_dir->name, NULL); + spin_unlock(&efivars_lock); + +} + +module_init(efivars_init); +module_exit(efivars_exit); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 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 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/entry.S linux.ac/arch/ia64/kernel/entry.S --- linux.vanilla/arch/ia64/kernel/entry.S Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/entry.S Tue Apr 10 18:08:40 2001 @@ -3,8 +3,8 @@ * * Kernel entry points. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> * Copyright (C) 1999 Asit Mallick <Asit.K.Mallick@intel.com> @@ -15,8 +15,6 @@ * kernel stack. This allows us to handle interrupts without changing * to physical mode. * - * ar.k4 is now used to hold last virtual map address - * * Jonathan Nickin <nicklin@missioncriticallinux.com> * Patrick O'Rourke <orourke@missioncriticallinux.com> * 11/07/2000 @@ -25,66 +23,84 @@ * Global (preserved) predicate usage on syscall entry/exit path: * * pKern: See entry.h. + * pUser: See entry.h. * pSys: See entry.h. * pNonSys: !pSys - * p2: (Alias of pKern!) True if any signals are pending. */ #include <linux/config.h> #include <asm/cache.h> #include <asm/errno.h> +#include <asm/kregs.h> #include <asm/offsets.h> #include <asm/processor.h> #include <asm/unistd.h> #include <asm/asmmacro.h> #include <asm/pgtable.h> - -#include "entry.h" - .text - .psr abi64 - .psr lsb - .lsb +#include "minstate.h" /* * execve() is special because in case of success, we need to * setup a null register window frame. */ ENTRY(ia64_execve) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(3)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(3) alloc loc1=ar.pfs,3,2,4,0 mov loc0=rp - UNW(.body) + .body mov out0=in0 // filename ;; // stop bit between alloc and call mov out1=in1 // argv mov out2=in2 // envp add out3=16,sp // regs br.call.sptk.few rp=sys_execve -.ret0: cmp4.ge p6,p0=r8,r0 +.ret0: cmp4.ge p6,p7=r8,r0 mov ar.pfs=loc1 // restore ar.pfs - ;; -(p6) mov ar.pfs=r0 // clear ar.pfs in case of success sxt4 r8=r8 // return 64-bit result + ;; + stf.spill [sp]=f0 +(p6) cmp.ne pKern,pUser=r0,r0 // a successful execve() lands us in user-mode... mov rp=loc0 +(p6) mov ar.pfs=r0 // clear ar.pfs on success +(p7) br.ret.sptk.few rp + /* + * In theory, we'd have to zap this state only to prevent leaking of + * security sensitive state (e.g., if current->dumpable is zero). However, + * this executes in less than 20 cycles even on Itanium, so it's not worth + * optimizing for...). + */ + mov r4=0; mov f2=f0; mov b1=r0 + mov r5=0; mov f3=f0; mov b2=r0 + mov r6=0; mov f4=f0; mov b3=r0 + mov r7=0; mov f5=f0; mov b4=r0 + mov ar.unat=0; mov f10=f0; mov b5=r0 + ldf.fill f11=[sp]; ldf.fill f12=[sp]; mov f13=f0 + ldf.fill f14=[sp]; ldf.fill f15=[sp]; mov f16=f0 + ldf.fill f17=[sp]; ldf.fill f18=[sp]; mov f19=f0 + ldf.fill f20=[sp]; ldf.fill f21=[sp]; mov f22=f0 + ldf.fill f23=[sp]; ldf.fill f24=[sp]; mov f25=f0 + ldf.fill f26=[sp]; ldf.fill f27=[sp]; mov f28=f0 + ldf.fill f29=[sp]; ldf.fill f30=[sp]; mov f31=f0 + mov ar.lc=0 br.ret.sptk.few rp END(ia64_execve) GLOBAL_ENTRY(sys_clone2) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2) alloc r16=ar.pfs,3,2,4,0 DO_SAVE_SWITCH_STACK mov loc0=rp mov loc1=r16 // save ar.pfs across do_fork - UNW(.body) + .body mov out1=in1 mov out3=in2 adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s mov out0=in0 // out0 = clone_flags br.call.sptk.few rp=do_fork -.ret1: UNW(.restore sp) +.ret1: .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack mov ar.pfs=loc1 mov rp=loc0 @@ -92,43 +108,42 @@ END(sys_clone2) GLOBAL_ENTRY(sys_clone) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2) alloc r16=ar.pfs,2,2,4,0 DO_SAVE_SWITCH_STACK mov loc0=rp mov loc1=r16 // save ar.pfs across do_fork - UNW(.body) + .body mov out1=in1 mov out3=0 adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s mov out0=in0 // out0 = clone_flags br.call.sptk.few rp=do_fork -.ret2: UNW(.restore sp) +.ret2: .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack mov ar.pfs=loc1 mov rp=loc0 br.ret.sptk.many rp END(sys_clone) -#define KSTACK_TR 2 - /* * prev_task <- ia64_switch_to(struct task_struct *next) */ GLOBAL_ENTRY(ia64_switch_to) - UNW(.prologue) + .prologue alloc r16=ar.pfs,1,0,0,0 DO_SAVE_SWITCH_STACK - UNW(.body) + .body adds r22=IA64_TASK_THREAD_KSP_OFFSET,r13 - mov r27=ar.k4 + mov r27=IA64_KR(CURRENT_STACK) dep r20=0,in0,61,3 // physical address of "current" ;; st8 [r22]=sp // save kernel stack pointer of old task - shr.u r26=r20,_PAGE_SIZE_256M + shr.u r26=r20,_PAGE_SIZE_64M + mov r16=1 ;; - cmp.eq p7,p6=r26,r0 // check < 256M + cmp.ne p6,p7=r26,r16 // check >= 64M && < 128M adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0 ;; /* @@ -142,50 +157,36 @@ (p6) ssm psr.ic // if we we had to map, renable the psr.ic bit FIRST!!! ;; (p6) srlz.d - mov ar.k6=r20 // copy "current" into ar.k6 + mov IA64_KR(CURRENT)=r20 // update "current" application register mov r8=r13 // return pointer to previously running task mov r13=in0 // set "current" pointer ;; (p6) ssm psr.i // renable psr.i AFTER the ic bit is serialized - DO_LOAD_SWITCH_STACK( ) + DO_LOAD_SWITCH_STACK #ifdef CONFIG_SMP sync.i // ensure "fc"s done by this CPU are visible on other CPUs -#endif +#endif br.ret.sptk.few rp // boogie on out in new context .map: rsm psr.i | psr.ic - movl r25=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX + movl r25=PAGE_KERNEL ;; srlz.d or r23=r25,r20 // construct PA | page properties - mov r25=_PAGE_SIZE_256M<<2 + mov r25=_PAGE_SIZE_64M<<2 ;; mov cr.itir=r25 mov cr.ifa=in0 // VA of next task... ;; - mov r25=KSTACK_TR // use tr entry #2... - mov ar.k4=r26 // remember last page we mapped... + mov r25=IA64_TR_CURRENT_STACK + mov IA64_KR(CURRENT_STACK)=r26 // remember last page we mapped... ;; itr.d dtr[r25]=r23 // wire in new mapping... br.cond.sptk.many .done - ;; END(ia64_switch_to) -#ifndef CONFIG_IA64_NEW_UNWIND - /* - * Like save_switch_stack, but also save the stack frame that is active - * at the time this function is called. - */ -ENTRY(save_switch_stack_with_current_frame) - UNW(.prologue) - alloc r16=ar.pfs,0,0,0,0 // pass ar.pfs to save_switch_stack - DO_SAVE_SWITCH_STACK - br.ret.sptk.few rp -END(save_switch_stack_with_current_frame) -#endif /* !CONFIG_IA64_NEW_UNWIND */ - /* * Note that interrupts are enabled during save_switch_stack and * load_switch_stack. This means that we may get an interrupt with @@ -205,95 +206,108 @@ * - rp (b0) holds return address to save */ GLOBAL_ENTRY(save_switch_stack) - UNW(.prologue) - UNW(.altrp b7) + .prologue + .altrp b7 flushrs // flush dirty regs to backing store (must be first in insn group) + .save @priunat,r17 mov r17=ar.unat // preserve caller's - adds r2=16,sp // r2 = &sw->caller_unat + .body +#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \ + || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) + adds r3=80,sp ;; - mov r18=ar.fpsr // preserve fpsr - mov ar.rsc=r0 // put RSE in mode: enforced lazy, little endian, pl 0 + lfetch.fault.excl.nt1 [r3],128 +#endif + mov ar.rsc=0 // put RSE in mode: enforced lazy, little endian, pl 0 +#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \ + || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) + adds r2=16+128,sp ;; - mov r19=ar.rnat - adds r3=24,sp // r3 = &sw->ar_fpsr + lfetch.fault.excl.nt1 [r2],128 + lfetch.fault.excl.nt1 [r3],128 +#endif + adds r14=SW(R4)+16,sp +#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \ + || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) + ;; + lfetch.fault.excl [r2] + lfetch.fault.excl [r3] +#endif + adds r15=SW(R5)+16,sp ;; - .savesp ar.unat,SW(CALLER_UNAT) - st8 [r2]=r17,16 - .savesp ar.fpsr,SW(AR_FPSR) - st8 [r3]=r18,24 + mov r18=ar.fpsr // preserve fpsr + mov r19=ar.rnat + add r2=SW(F2)+16,sp // r2 = &sw->f2 +.mem.offset 0,0; st8.spill [r14]=r4,16 // spill r4 +.mem.offset 8,0; st8.spill [r15]=r5,16 // spill r5 + add r3=SW(F3)+16,sp // r3 = &sw->f3 ;; - UNW(.body) stf.spill [r2]=f2,32 stf.spill [r3]=f3,32 mov r21=b0 +.mem.offset 0,0; st8.spill [r14]=r6,16 // spill r6 +.mem.offset 8,0; st8.spill [r15]=r7,16 // spill r7 + mov r22=b1 ;; + // since we're done with the spills, read and save ar.unat: + mov r29=ar.unat // M-unit + mov r20=ar.bspstore // M-unit + mov r23=b2 stf.spill [r2]=f4,32 stf.spill [r3]=f5,32 + mov r24=b3 ;; + st8 [r14]=r21,16 // save b0 + st8 [r15]=r22,16 // save b1 + mov r25=b4 stf.spill [r2]=f10,32 stf.spill [r3]=f11,32 - mov r22=b1 + mov r26=b5 ;; + st8 [r14]=r23,16 // save b2 + st8 [r15]=r24,16 // save b3 + mov r21=ar.lc // I-unit stf.spill [r2]=f12,32 stf.spill [r3]=f13,32 - mov r23=b2 ;; + st8 [r14]=r25,16 // save b4 + st8 [r15]=r26,16 // save b5 stf.spill [r2]=f14,32 stf.spill [r3]=f15,32 - mov r24=b3 ;; + st8 [r14]=r16 // save ar.pfs + st8 [r15]=r21 // save ar.lc stf.spill [r2]=f16,32 stf.spill [r3]=f17,32 - mov r25=b4 ;; stf.spill [r2]=f18,32 stf.spill [r3]=f19,32 - mov r26=b5 ;; stf.spill [r2]=f20,32 stf.spill [r3]=f21,32 - mov r17=ar.lc // I-unit ;; stf.spill [r2]=f22,32 stf.spill [r3]=f23,32 ;; stf.spill [r2]=f24,32 stf.spill [r3]=f25,32 + add r14=SW(CALLER_UNAT)+16,sp ;; stf.spill [r2]=f26,32 stf.spill [r3]=f27,32 + add r15=SW(AR_FPSR)+16,sp ;; stf.spill [r2]=f28,32 stf.spill [r3]=f29,32 - ;; - stf.spill [r2]=f30,32 - stf.spill [r3]=f31,24 - ;; -.mem.offset 0,0; st8.spill [r2]=r4,16 -.mem.offset 8,0; st8.spill [r3]=r5,16 - ;; -.mem.offset 0,0; st8.spill [r2]=r6,16 -.mem.offset 8,0; st8.spill [r3]=r7,16 - ;; - st8 [r2]=r21,16 // save b0 - st8 [r3]=r22,16 // save b1 - /* since we're done with the spills, read and save ar.unat: */ - mov r18=ar.unat // M-unit - mov r20=ar.bspstore // M-unit - ;; - st8 [r2]=r23,16 // save b2 - st8 [r3]=r24,16 // save b3 - ;; - st8 [r2]=r25,16 // save b4 - st8 [r3]=r26,16 // save b5 - ;; - st8 [r2]=r16,16 // save ar.pfs - st8 [r3]=r17,16 // save ar.lc + st8 [r14]=r17 // save caller_unat + st8 [r15]=r18 // save fpsr mov r21=pr ;; - st8 [r2]=r18,16 // save ar.unat + stf.spill [r2]=f30,(SW(AR_UNAT)-SW(F30)) + stf.spill [r3]=f31,(SW(AR_RNAT)-SW(F31)) + ;; + st8 [r2]=r29,16 // save ar.unat st8 [r3]=r19,16 // save ar.rnat - mov b7=r28 ;; st8 [r2]=r20 // save ar.bspstore st8 [r3]=r21 // save predicate registers @@ -303,16 +317,27 @@ /* * load_switch_stack: + * - "invala" MUST be done at call site (normally in DO_LOAD_SWITCH_STACK) * - b7 holds address to return to + * - must not touch r8-r11 */ ENTRY(load_switch_stack) - UNW(.prologue) - UNW(.altrp b7) - invala // invalidate ALAT - UNW(.body) - adds r2=IA64_SWITCH_STACK_B0_OFFSET+16,sp // get pointer to switch_stack.b0 - mov ar.rsc=r0 // put RSE into enforced lazy mode - adds r3=IA64_SWITCH_STACK_B0_OFFSET+24,sp // get pointer to switch_stack.b1 + .prologue + .altrp b7 + .body +#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \ + || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) + + lfetch.fault.nt1 [sp] +#endif + adds r2=SW(AR_BSPSTORE)+16,sp + adds r3=SW(AR_UNAT)+16,sp + mov ar.rsc=0 // put RSE into enforced lazy mode + adds r14=SW(CALLER_UNAT)+16,sp + adds r15=SW(AR_FPSR)+16,sp + ;; + ld8 r27=[r2],(SW(B0)-SW(AR_BSPSTORE)) // bspstore + ld8 r29=[r3],(SW(B1)-SW(AR_UNAT)) // unat ;; ld8 r21=[r2],16 // restore b0 ld8 r22=[r3],16 // restore b1 @@ -323,84 +348,77 @@ ld8 r25=[r2],16 // restore b4 ld8 r26=[r3],16 // restore b5 ;; - ld8 r16=[r2],16 // restore ar.pfs - ld8 r17=[r3],16 // restore ar.lc + ld8 r16=[r2],(SW(PR)-SW(AR_PFS)) // ar.pfs + ld8 r17=[r3],(SW(AR_RNAT)-SW(AR_LC)) // ar.lc ;; - ld8 r18=[r2],16 // restore ar.unat - ld8 r19=[r3],16 // restore ar.rnat - mov b0=r21 + ld8 r28=[r2] // restore pr + ld8 r30=[r3] // restore rnat ;; - ld8 r20=[r2] // restore ar.bspstore - ld8 r21=[r3] // restore predicate registers - mov ar.pfs=r16 + ld8 r18=[r14],16 // restore caller's unat + ld8 r19=[r15],24 // restore fpsr ;; - mov ar.bspstore=r20 + ldf.fill f2=[r14],32 + ldf.fill f3=[r15],32 ;; - loadrs // invalidate stacked regs outside current frame - adds r2=16-IA64_SWITCH_STACK_SIZE,r2 // get pointer to switch_stack.caller_unat - ;; // stop bit for rnat dependency - mov ar.rnat=r19 - mov ar.unat=r18 // establish unat holding the NaT bits for r4-r7 - adds r3=16-IA64_SWITCH_STACK_SIZE,r3 // get pointer to switch_stack.ar_fpsr + ldf.fill f4=[r14],32 + ldf.fill f5=[r15],32 ;; - ld8 r18=[r2],16 // restore caller's unat - ld8 r19=[r3],24 // restore fpsr - mov ar.lc=r17 + ldf.fill f10=[r14],32 + ldf.fill f11=[r15],32 + ;; + ldf.fill f12=[r14],32 + ldf.fill f13=[r15],32 ;; - ldf.fill f2=[r2],32 - ldf.fill f3=[r3],32 - mov pr=r21,-1 + ldf.fill f14=[r14],32 + ldf.fill f15=[r15],32 ;; - ldf.fill f4=[r2],32 - ldf.fill f5=[r3],32 + ldf.fill f16=[r14],32 + ldf.fill f17=[r15],32 ;; - ldf.fill f10=[r2],32 - ldf.fill f11=[r3],32 + ldf.fill f18=[r14],32 + ldf.fill f19=[r15],32 + mov b0=r21 + ;; + ldf.fill f20=[r14],32 + ldf.fill f21=[r15],32 mov b1=r22 ;; - ldf.fill f12=[r2],32 - ldf.fill f13=[r3],32 + ldf.fill f22=[r14],32 + ldf.fill f23=[r15],32 mov b2=r23 ;; - ldf.fill f14=[r2],32 - ldf.fill f15=[r3],32 + mov ar.bspstore=r27 + mov ar.unat=r29 // establish unat holding the NaT bits for r4-r7 mov b3=r24 ;; - ldf.fill f16=[r2],32 - ldf.fill f17=[r3],32 + ldf.fill f24=[r14],32 + ldf.fill f25=[r15],32 mov b4=r25 ;; - ldf.fill f18=[r2],32 - ldf.fill f19=[r3],32 + ldf.fill f26=[r14],32 + ldf.fill f27=[r15],32 mov b5=r26 ;; - ldf.fill f20=[r2],32 - ldf.fill f21=[r3],32 - ;; - ldf.fill f22=[r2],32 - ldf.fill f23=[r3],32 - ;; - ldf.fill f24=[r2],32 - ldf.fill f25=[r3],32 - ;; - ldf.fill f26=[r2],32 - ldf.fill f27=[r3],32 - ;; - ldf.fill f28=[r2],32 - ldf.fill f29=[r3],32 + ldf.fill f28=[r14],32 + ldf.fill f29=[r15],32 + mov ar.pfs=r16 ;; - ldf.fill f30=[r2],32 - ldf.fill f31=[r3],24 + ldf.fill f30=[r14],32 + ldf.fill f31=[r15],24 + mov ar.lc=r17 ;; - ld8.fill r4=[r2],16 - ld8.fill r5=[r3],16 + ld8.fill r4=[r14],16 + ld8.fill r5=[r15],16 + mov pr=r28,-1 ;; - ld8.fill r6=[r2],16 - ld8.fill r7=[r3],16 + ld8.fill r6=[r14],16 + ld8.fill r7=[r15],16 + mov ar.unat=r18 // restore caller's unat + mov ar.rnat=r30 // must restore after bspstore but before rsc! mov ar.fpsr=r19 // restore fpsr mov ar.rsc=3 // put RSE back into eager mode, pl 0 - br.cond.sptk.few b7 + br.cond.sptk.many b7 END(load_switch_stack) GLOBAL_ENTRY(__ia64_syscall) @@ -415,17 +433,16 @@ br.ret.sptk.few rp END(__ia64_syscall) - // - // We invoke syscall_trace through this intermediate function to - // ensure that the syscall input arguments are not clobbered. We - // also use it to preserve b6, which contains the syscall entry point. - // + /* + * We invoke syscall_trace through this intermediate function to + * ensure that the syscall input arguments are not clobbered. We + * also use it to preserve b6, which contains the syscall entry point. + */ GLOBAL_ENTRY(invoke_syscall_trace) -#ifdef CONFIG_IA64_NEW_UNWIND - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) alloc loc1=ar.pfs,8,3,0,0 mov loc0=rp - UNW(.body) + .body mov loc2=b6 ;; br.call.sptk.few rp=syscall_trace @@ -433,33 +450,18 @@ mov ar.pfs=loc1 mov b6=loc2 br.ret.sptk.few rp -#else /* !CONFIG_IA64_NEW_SYSCALL */ - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) - alloc loc1=ar.pfs,8,3,0,0 - ;; // WAW on CFM at the br.call - mov loc0=rp - br.call.sptk.many rp=save_switch_stack_with_current_frame // must preserve b6!! -.ret4: mov loc2=b6 - br.call.sptk.few rp=syscall_trace -.ret5: adds sp=IA64_SWITCH_STACK_SIZE,sp // drop switch_stack frame - mov rp=loc0 - mov ar.pfs=loc1 - mov b6=loc2 - ;; - br.ret.sptk.few rp -#endif /* !CONFIG_IA64_NEW_SYSCALL */ END(invoke_syscall_trace) - // - // Invoke a system call, but do some tracing before and after the call. - // We MUST preserve the current register frame throughout this routine - // because some system calls (such as ia64_execve) directly - // manipulate ar.pfs. - // - // Input: - // r15 = syscall number - // b6 = syscall entry point - // + /* + * Invoke a system call, but do some tracing before and after the call. + * We MUST preserve the current register frame throughout this routine + * because some system calls (such as ia64_execve) directly + * manipulate ar.pfs. + * + * Input: + * r15 = syscall number + * b6 = syscall entry point + */ .global ia64_strace_leave_kernel GLOBAL_ENTRY(ia64_trace_syscall) @@ -468,8 +470,8 @@ .ret6: br.call.sptk.few rp=b6 // do the syscall strace_check_retval: cmp.lt p6,p0=r8,r0 // syscall failed? - adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 - adds r3=IA64_PT_REGS_R8_OFFSET+32,sp // r3 = &pt_regs.r10 + adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8 + adds r3=PT(R10)+16,sp // r3 = &pt_regs.r10 mov r10=0 (p6) br.cond.sptk.few strace_error // syscall failed -> ;; // avoid RAW on r10 @@ -492,28 +494,14 @@ br.cond.sptk.few strace_save_retval END(ia64_trace_syscall) -/* - * A couple of convenience macros to help implement/understand the state - * restoration that happens at the end of ia64_ret_from_syscall. - */ -#define rARPR r31 -#define rCRIFS r30 -#define rCRIPSR r29 -#define rCRIIP r28 -#define rARRSC r27 -#define rARPFS r26 -#define rARUNAT r25 -#define rARRNAT r24 -#define rARBSPSTORE r23 -#define rKRBS r22 -#define rB6 r21 - GLOBAL_ENTRY(ia64_ret_from_clone) PT_REGS_UNWIND_INFO(0) #ifdef CONFIG_SMP - // In SMP mode, we need to call schedule_tail to complete the scheduling process. - // Called by ia64_switch_to after do_fork()->copy_thread(). r8 contains the - // address of the previously executing task. + /* + * In SMP mode, we need to call invoke_schedule_tail to complete the scheduling process. + * Called by ia64_switch_to after do_fork()->copy_thread(). r8 contains the + * address of the previously executing task. + */ br.call.sptk.few rp=invoke_schedule_tail .ret8: #endif @@ -530,8 +518,8 @@ GLOBAL_ENTRY(ia64_ret_from_syscall) PT_REGS_UNWIND_INFO(0) cmp.ge p6,p7=r8,r0 // syscall executed successfully? - adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 - adds r3=IA64_PT_REGS_R8_OFFSET+32,sp // r3 = &pt_regs.r10 + adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8 + adds r3=PT(R10)+16,sp // r3 = &pt_regs.r10 ;; .mem.offset 0,0 (p6) st8.spill [r2]=r8 // store return value in slot for r8 and set unat bit @@ -541,78 +529,57 @@ END(ia64_ret_from_syscall) // fall through GLOBAL_ENTRY(ia64_leave_kernel) - // check & deliver software interrupts: - PT_REGS_UNWIND_INFO(0) -#ifdef CONFIG_SMP - adds r2=IA64_TASK_PROCESSOR_OFFSET,r13 - movl r3=irq_stat // softirq_active - ;; - ld4 r2=[r2] + cmp.eq p16,p0=r0,r0 // set the "first_time" flag + movl r15=PERCPU_ADDR+IA64_CPU_SOFTIRQ_ACTIVE_OFFSET // r15 = &cpu_data.softirq.active ;; - shl r2=r2,SMP_CACHE_SHIFT // can't use shladd here... + ld8 r2=[r15] + movl r14=.restart ;; - add r3=r2,r3 -#else - movl r3=irq_stat // softirq_active + lfetch.fault [sp] + shr.u r3=r2,32 // r3 = cpu_data.softirq.mask + MOVBR(.ret.sptk,rp,r14,.restart) +.restart: + adds r17=IA64_TASK_NEED_RESCHED_OFFSET,r13 + adds r18=IA64_TASK_SIGPENDING_OFFSET,r13 +#ifdef CONFIG_PERFMON + adds r19=IA64_TASK_PFM_NOTIFY_OFFSET,r13 #endif ;; - ld8 r2=[r3] // r3 (softirq_active+softirq_mask) is guaranteed to be 8-byte aligned! - ;; - shr r3=r2,32 + ld8 r17=[r17] // load current->need_resched + ld4 r18=[r18] // load current->sigpending +(p16) and r2=r2,r3 // r2 <- (softirq.active & softirq.mask) ;; - and r2=r2,r3 +#ifdef CONFIG_PERFMON + ld8 r19=[r19] // load current->task.pfm_notify +#endif +(p16) cmp4.ne.unc p6,p0=r2,r0 // p6 <- (softirq.active & softirq.mask) != 0 +(pUser) cmp.ne.unc p7,p0=r17,r0 // current->need_resched != 0? ;; - cmp4.ne p6,p7=r2,r0 -(p6) br.call.spnt.many rp=invoke_do_softirq -1: -(pKern) br.cond.dpnt.many restore_all // yup -> skip check for rescheduling & signal delivery - - // call schedule() until we find a task that doesn't have need_resched set: - -back_from_resched: - { .mii - adds r2=IA64_TASK_NEED_RESCHED_OFFSET,r13 - mov r3=ip - adds r14=IA64_TASK_SIGPENDING_OFFSET,r13 - } +(pUser) cmp.ne.unc p8,p0=r18,r0 // current->sigpending != 0? +#ifdef CONFIG_PERFMON + cmp.ne p9,p0=r19,r0 // current->task.pfm_notify != 0? +#endif + cmp.ne p16,p0=r0,r0 // clear the "first_time" flag ;; - ld8 r2=[r2] - ld4 r14=[r14] - mov rp=r3 // arrange for schedule() to return to back_from_resched +# if __GNUC__ < 3 +(p6) br.call.spnt.many b7=invoke_do_softirq +# else +(p6) br.call.spnt.many b7=do_softirq +# endif +#ifdef CONFIG_PERFMON +(p9) br.call.spnt.many b7=pfm_overflow_notify +#endif +# if __GNUC__ < 3 +(p7) br.call.spnt.many b7=invoke_schedule +#else +(p7) br.call.spnt.many b7=schedule +#endif + adds r2=PT(R8)+16,r12 + adds r3=PT(R9)+16,r12 +(p8) br.call.spnt.many b7=handle_signal_delivery // check & deliver pending signals ;; - cmp.ne p6,p0=r2,r0 - cmp.ne p2,p0=r14,r0 // NOTE: pKern is an alias for p2!! - srlz.d -(p6) br.call.spnt.many b6=invoke_schedule // ignore return value -2: - // check & deliver pending signals: -(p2) br.call.spnt.few rp=handle_signal_delivery -.ret9: -#ifdef CONFIG_IA64_SOFTSDV_HACKS - // Check for lost ticks - rsm psr.i - mov r2 = ar.itc - movl r14 = 1000 // latency tolerance - mov r3 = cr.itm - ;; - sub r2 = r2, r3 - ;; - sub r2 = r2, r14 - ;; - cmp.ge p6,p7 = r2, r0 -(p6) br.call.spnt.few rp=invoke_ia64_reset_itm -.ret10: - ;; - ssm psr.i -#endif -restore_all: - // start restoring the state saved on the kernel stack (struct pt_regs): - - adds r2=IA64_PT_REGS_R8_OFFSET+16,r12 - adds r3=IA64_PT_REGS_R8_OFFSET+24,r12 - ;; ld8.fill r8=[r2],16 ld8.fill r9=[r3],16 ;; @@ -643,6 +610,9 @@ ld8.fill r30=[r2],16 ld8.fill r31=[r3],16 ;; + rsm psr.i | psr.ic // initiate turning off of interrupts & interruption collection + invala // invalidate ALAT + ;; ld8 r1=[r2],16 // ar.ccv ld8 r13=[r3],16 // ar.fpsr ;; @@ -658,14 +628,11 @@ mov ar.ccv=r1 mov ar.fpsr=r13 mov b0=r14 - // turn off interrupts, interrupt collection - rsm psr.i | psr.ic ;; - srlz.i // EAS 2.5 + srlz.i // ensure interrupts & interruption collection are off mov b7=r15 ;; - invala // invalidate ALAT - bsw.0;; // switch back to bank 0 (must be last in insn group) + bsw.0 // switch back to bank 0 ;; #ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC nop.i 0x0 @@ -683,17 +650,18 @@ ;; ld8 rCRIFS=[r16],16 // load cr.ifs ld8 rARUNAT=[r17],16 // load ar.unat + cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs ;; ld8 rARPFS=[r16],16 // load ar.pfs ld8 rARRSC=[r17],16 // load ar.rsc ;; ld8 rARRNAT=[r16],16 // load ar.rnat (may be garbage) - ld8 rARBSPSTORE=[r17],16 // load ar.bspstore (may be garbage) + ld8 rARBSPSTORE=[r17],16 // load ar.bspstore (may be garbage) ;; ld8 rARPR=[r16],16 // load predicates ld8 rB6=[r17],16 // load b6 ;; - ld8 r18=[r16],16 // load ar.rsc value for "loadrs" + ld8 r19=[r16],16 // load ar.rsc value for "loadrs" ld8.fill r1=[r17],16 // load r1 ;; ld8.fill r2=[r16],16 @@ -701,62 +669,102 @@ ;; ld8.fill r12=[r16],16 ld8.fill r13=[r17],16 - extr.u r19=rCRIPSR,32,2 // extract ps.cpl ;; - ld8.fill r14=[r16],16 - ld8.fill r15=[r17],16 - cmp.eq p6,p7=r0,r19 // are we returning to kernel mode? (psr.cpl==0) + ld8.fill r14=[r16] + ld8.fill r15=[r17] + shr.u r18=r19,16 // get byte size of existing "dirty" partition ;; - mov b6=rB6 - mov ar.pfs=rARPFS -(p6) br.cond.dpnt.few skip_rbs_switch - + mov r16=ar.bsp // get existing backing store pointer + movl r17=PERCPU_ADDR+IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET + ;; + ld4 r17=[r17] // r17 = cpu_data->phys_stacked_size_p8 +(pKern) br.cond.dpnt.few skip_rbs_switch /* * Restore user backing store. * * NOTE: alloc, loadrs, and cover can't be predicated. - * - * XXX This needs some scheduling/tuning once we believe it - * really does work as intended. */ - mov r16=ar.bsp // get existing backing store pointer (pNonSys) br.cond.dpnt.few dont_preserve_current_frame cover // add current frame into dirty partition ;; - mov rCRIFS=cr.ifs // fetch the cr.ifs value that "cover" produced - mov r17=ar.bsp // get new backing store pointer - ;; - sub r16=r17,r16 // calculate number of bytes that were added to rbs + mov r19=ar.bsp // get new backing store pointer + sub r16=r16,r18 // krbs = old bsp - size of dirty partition + cmp.ne p9,p0=r0,r0 // clear p9 to skip restore of cr.ifs ;; - shl r16=r16,16 // shift additional frame size into position for loadrs + sub r19=r19,r16 // calculate total byte size of dirty partition + add r18=64,r18 // don't force in0-in7 into memory... ;; - add r18=r16,r18 // adjust the loadrs value + shl r19=r19,16 // shift size of dirty partition into loadrs position ;; dont_preserve_current_frame: - alloc r16=ar.pfs,0,0,0,0 // drop the current call frame (noop for syscalls) - ;; - mov ar.rsc=r18 // load ar.rsc to be used for "loadrs" -#ifdef CONFIG_IA32_SUPPORT - tbit.nz p6,p0=rCRIPSR,IA64_PSR_IS_BIT + /* + * To prevent leaking bits between the kernel and user-space, + * we must clear the stacked registers in the "invalid" partition here. + * Not pretty, but at least it's fast (3.34 registers/cycle). + * Architecturally, this loop could go at 4.67 registers/cycle, but that would + * oversubscribe Itanium. + */ +# define pRecurse p6 +# define pReturn p7 +# define Nregs 10 + alloc loc0=ar.pfs,2,Nregs-2,2,0 + shr.u loc1=r18,9 // RNaTslots <= dirtySize / (64*8) + 1 + sub r17=r17,r18 // r17 = (physStackedSize + 8) - dirtySize + ;; + mov ar.rsc=r19 // load ar.rsc to be used for "loadrs" + shladd in0=loc1,3,r17 + mov in1=0 + ;; + .align 32 +rse_clear_invalid: + // cycle 0 + { .mii + alloc loc0=ar.pfs,2,Nregs-2,2,0 + cmp.lt pRecurse,p0=Nregs*8,in0 // if more than Nregs regs left to clear, (re)curse + add out0=-Nregs*8,in0 +}{ .mfb + add out1=1,in1 // increment recursion count + nop.f 0 + nop.b 0 // can't do br.call here because of alloc (WAW on CFM) + ;; +}{ .mfi // cycle 1 + mov loc1=0 + nop.f 0 + mov loc2=0 +}{ .mib + mov loc3=0 + mov loc4=0 +(pRecurse) br.call.sptk.few b6=rse_clear_invalid + +}{ .mfi // cycle 2 + mov loc5=0 + nop.f 0 + cmp.ne pReturn,p0=r0,in1 // if recursion count != 0, we need to do a br.ret +}{ .mib + mov loc6=0 + mov loc7=0 +(pReturn) br.ret.sptk.few b6 +} +# undef pRecurse +# undef pReturn + + alloc r17=ar.pfs,0,0,0,0 // drop current register frame ;; -(p6) mov ar.rsc=r0 // returning to IA32 mode -#endif - ;; loadrs ;; - mov ar.bspstore=rARBSPSTORE - ;; - mov ar.rnat=rARRNAT // must happen with RSE in lazy mode - skip_rbs_switch: + mov b6=rB6 + mov ar.pfs=rARPFS +(pUser) mov ar.bspstore=rARBSPSTORE +(p9) mov cr.ifs=rCRIFS + mov cr.ipsr=rCRIPSR + mov cr.iip=rCRIIP + ;; +(pUser) mov ar.rnat=rARRNAT // must happen with RSE in lazy mode mov ar.rsc=rARRSC mov ar.unat=rARUNAT - mov cr.ifs=rCRIFS // restore cr.ifs only if not a (synchronous) syscall mov pr=rARPR,-1 - mov cr.iip=rCRIIP - mov cr.ipsr=rCRIPSR - ;; - rfi;; // must be last instruction in an insn group + rfi END(ia64_leave_kernel) ENTRY(handle_syscall_error) @@ -784,13 +792,13 @@ br.cond.sptk.many ia64_leave_kernel END(handle_syscall_error) -#ifdef CONFIG_SMP +# ifdef CONFIG_SMP /* * Invoke schedule_tail(task) while preserving in0-in7, which may be needed * in case a system call gets restarted. */ ENTRY(invoke_schedule_tail) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) alloc loc1=ar.pfs,8,2,1,0 mov loc0=rp mov out0=r8 // Address of previous task @@ -801,35 +809,24 @@ br.ret.sptk.many rp END(invoke_schedule_tail) -#endif /* CONFIG_SMP */ - -#ifdef CONFIG_IA64_SOFTSDV_HACKS - -ENTRY(invoke_ia64_reset_itm) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) - alloc loc1=ar.pfs,8,2,0,0 - mov loc0=rp - ;; - UNW(.body) - br.call.sptk.many rp=ia64_reset_itm -.ret12: ;; - mov ar.pfs=loc1 - mov rp=loc0 - br.ret.sptk.many rp -END(invoke_ia64_reset_itm) - -#endif /* CONFIG_IA64_SOFTSDV_HACKS */ +# endif /* CONFIG_SMP */ +#if __GNUC__ < 3 /* * Invoke do_softirq() while preserving in0-in7, which may be needed - * in case a system call gets restarted. + * in case a system call gets restarted. Note that declaring do_softirq() + * with asmlinkage() is NOT enough because that will only preserve as many + * registers as there are formal arguments. + * + * XXX fix me: with gcc 3.0, we won't need this anymore because syscall_linkage + * renders all eight input registers (in0-in7) as "untouchable". */ ENTRY(invoke_do_softirq) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) alloc loc1=ar.pfs,8,2,0,0 mov loc0=rp ;; - UNW(.body) + .body br.call.sptk.few rp=do_softirq .ret13: mov ar.pfs=loc1 mov rp=loc0 @@ -838,27 +835,33 @@ /* * Invoke schedule() while preserving in0-in7, which may be needed - * in case a system call gets restarted. + * in case a system call gets restarted. Note that declaring schedule() + * with asmlinkage() is NOT enough because that will only preserve as many + * registers as there are formal arguments. + * + * XXX fix me: with gcc 3.0, we won't need this anymore because syscall_linkage + * renders all eight input registers (in0-in7) as "untouchable". */ ENTRY(invoke_schedule) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) alloc loc1=ar.pfs,8,2,0,0 mov loc0=rp ;; - UNW(.body) + .body br.call.sptk.few rp=schedule .ret14: mov ar.pfs=loc1 mov rp=loc0 br.ret.sptk.many rp END(invoke_schedule) - // - // Setup stack and call ia64_do_signal. Note that pSys and pNonSys need to - // be set up by the caller. We declare 8 input registers so the system call - // args get preserved, in case we need to restart a system call. - // +#endif /* __GNUC__ < 3 */ + + /* + * Setup stack and call ia64_do_signal. Note that pSys and pNonSys need to + * be set up by the caller. We declare 8 input registers so the system call + * args get preserved, in case we need to restart a system call. + */ ENTRY(handle_signal_delivery) -#ifdef CONFIG_IA64_NEW_UNWIND .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart! mov r9=ar.unat @@ -882,26 +885,9 @@ mov ar.unat=r9 mov ar.pfs=loc1 br.ret.sptk.many rp -#else /* !CONFIG_IA64_NEW_UNWIND */ - .prologue - alloc r16=ar.pfs,8,0,3,0 // preserve all eight input regs in case of syscall restart! - DO_SAVE_SWITCH_STACK - UNW(.body) - - mov out0=0 // there is no "oldset" - adds out1=16,sp // out1=&sigscratch - .pred.rel.mutex pSys, pNonSys -(pSys) mov out2=1 // out2==1 => we're in a syscall -(pNonSys) mov out2=0 // out2==0 => not a syscall - br.call.sptk.few rp=ia64_do_signal -.ret16: // restore the switch stack (ptrace may have modified it) - DO_LOAD_SWITCH_STACK( ) - br.ret.sptk.many rp -#endif /* !CONFIG_IA64_NEW_UNWIND */ END(handle_signal_delivery) GLOBAL_ENTRY(sys_rt_sigsuspend) -#ifdef CONFIG_IA64_NEW_UNWIND .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart! mov r9=ar.unat @@ -924,87 +910,43 @@ mov ar.unat=r9 mov ar.pfs=loc1 br.ret.sptk.many rp -#else /* !CONFIG_IA64_NEW_UNWIND */ - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)) - alloc r16=ar.pfs,2,0,3,0 - DO_SAVE_SWITCH_STACK - UNW(.body) - - mov out0=in0 // mask - mov out1=in1 // sigsetsize - adds out2=16,sp // out1=&sigscratch - br.call.sptk.many rp=ia64_rt_sigsuspend -.ret18: // restore the switch stack (ptrace may have modified it) - DO_LOAD_SWITCH_STACK( ) - br.ret.sptk.many rp -#endif /* !CONFIG_IA64_NEW_UNWIND */ END(sys_rt_sigsuspend) ENTRY(sys_rt_sigreturn) -#ifdef CONFIG_IA64_NEW_UNWIND - .regstk 0,0,3,0 // inherited from gate.s:invoke_sighandler() PT_REGS_UNWIND_INFO(0) + alloc r2=ar.pfs,0,0,1,0 .prologue PT_REGS_SAVES(16) adds sp=-16,sp .body - cmp.eq pNonSys,p0=r0,r0 // sigreturn isn't a normal syscall... + cmp.eq pNonSys,pSys=r0,r0 // sigreturn isn't a normal syscall... ;; adds out0=16,sp // out0 = &sigscratch br.call.sptk.few rp=ia64_rt_sigreturn -.ret19: adds sp=16,sp // doesn't drop pt_regs, so don't mark it as restoring sp! - PT_REGS_UNWIND_INFO(0) // instead, create a new body section with the smaller frame +.ret19: .restore sp 0 + adds sp=16,sp ;; ld8 r9=[sp] // load new ar.unat - mov b7=r8 + MOVBR(.sptk,b7,r8,ia64_leave_kernel) ;; mov ar.unat=r9 br b7 -#else /* !CONFIG_IA64_NEW_UNWIND */ - .regstk 0,0,3,0 // inherited from gate.s:invoke_sighandler() - PT_REGS_UNWIND_INFO(0) - UNW(.prologue) - UNW(.fframe IA64_PT_REGS_SIZE+IA64_SWITCH_STACK_SIZE) - UNW(.spillsp rp, PT(CR_IIP)+IA64_SWITCH_STACK_SIZE) - UNW(.spillsp ar.pfs, PT(CR_IFS)+IA64_SWITCH_STACK_SIZE) - UNW(.spillsp ar.unat, PT(AR_UNAT)+IA64_SWITCH_STACK_SIZE) - UNW(.spillsp pr, PT(PR)+IA64_SWITCH_STACK_SIZE) - adds sp=-IA64_SWITCH_STACK_SIZE,sp - cmp.eq pNonSys,p0=r0,r0 // sigreturn isn't a normal syscall... - ;; - UNW(.body) - - adds out0=16,sp // out0 = &sigscratch - br.call.sptk.few rp=ia64_rt_sigreturn -.ret20: adds r3=IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp - ;; - ld8 r9=[r3] // load new ar.unat - mov b7=r8 - ;; - PT_REGS_UNWIND_INFO(0) - adds sp=IA64_SWITCH_STACK_SIZE,sp // drop (dummy) switch-stack frame - mov ar.unat=r9 - br b7 -#endif /* !CONFIG_IA64_NEW_UNWIND */ END(sys_rt_sigreturn) GLOBAL_ENTRY(ia64_prepare_handle_unaligned) // - // r16 = fake ar.pfs, we simply need to make sure + // r16 = fake ar.pfs, we simply need to make sure // privilege is still 0 // - PT_REGS_UNWIND_INFO(0) - mov r16=r0 - UNW(.prologue) + mov r16=r0 + .prologue DO_SAVE_SWITCH_STACK br.call.sptk.few rp=ia64_handle_unaligned // stack frame setup in ivt .ret21: .body - DO_LOAD_SWITCH_STACK(PT_REGS_UNWIND_INFO(0)) + DO_LOAD_SWITCH_STACK br.cond.sptk.many rp // goes to ia64_leave_kernel END(ia64_prepare_handle_unaligned) -#ifdef CONFIG_IA64_NEW_UNWIND - // // unw_init_running(void (*callback)(info, arg), void *arg) // @@ -1050,8 +992,6 @@ br.ret.sptk.many rp END(unw_init_running) -#endif - .rodata .align 8 .globl sys_call_table @@ -1229,7 +1169,7 @@ data8 sys_accept data8 sys_getsockname // 1195 data8 sys_getpeername - data8 sys_socketpair + data8 sys_socketpair data8 sys_send data8 sys_sendto data8 sys_recv // 1200 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/entry.h linux.ac/arch/ia64/kernel/entry.h --- linux.vanilla/arch/ia64/kernel/entry.h Thu Jun 22 15:09:44 2000 +++ linux.ac/arch/ia64/kernel/entry.h Tue Apr 10 18:08:40 2001 @@ -1,65 +1,77 @@ +#include <linux/config.h> + +/* XXX fixme */ +#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC) +# define MOVBR(type,br,gr,lbl) mov br=gr +#else +# define MOVBR(type,br,gr,lbl) mov##type br=gr,lbl +#endif + /* * Preserved registers that are shared between code in ivt.S and entry.S. Be * careful not to step on these! */ #define pKern p2 /* will leave_kernel return to kernel-mode? */ +#define pUser p3 /* will leave_kernel return to user-mode? */ #define pSys p4 /* are we processing a (synchronous) system call? */ #define pNonSys p5 /* complement of pSys */ -#define PT(f) (IA64_PT_REGS_##f##_OFFSET + 16) -#define SW(f) (IA64_SWITCH_STACK_##f##_OFFSET + 16) +#define PT(f) (IA64_PT_REGS_##f##_OFFSET) +#define SW(f) (IA64_SWITCH_STACK_##f##_OFFSET) -#define PT_REGS_SAVES(off) \ - UNW(.unwabi @svr4, 'i'); \ - UNW(.fframe IA64_PT_REGS_SIZE+16+(off)); \ - UNW(.spillsp rp, PT(CR_IIP)+(off)); \ - UNW(.spillsp ar.pfs, PT(CR_IFS)+(off)); \ - UNW(.spillsp ar.unat, PT(AR_UNAT)+(off)); \ - UNW(.spillsp ar.fpsr, PT(AR_FPSR)+(off)); \ - UNW(.spillsp pr, PT(PR)+(off)); +#define PT_REGS_SAVES(off) \ + .unwabi @svr4, 'i'; \ + .fframe IA64_PT_REGS_SIZE+16+(off); \ + .spillsp rp, PT(CR_IIP)+16+(off); \ + .spillsp ar.pfs, PT(CR_IFS)+16+(off); \ + .spillsp ar.unat, PT(AR_UNAT)+16+(off); \ + .spillsp ar.fpsr, PT(AR_FPSR)+16+(off); \ + .spillsp pr, PT(PR)+16+(off); #define PT_REGS_UNWIND_INFO(off) \ - UNW(.prologue); \ + .prologue; \ PT_REGS_SAVES(off); \ - UNW(.body) + .body -#define SWITCH_STACK_SAVES(off) \ - UNW(.savesp ar.unat,SW(CALLER_UNAT)+(off)); UNW(.savesp ar.fpsr,SW(AR_FPSR)+(off)); \ - UNW(.spillsp f2,SW(F2)+(off)); UNW(.spillsp f3,SW(F3)+(off)); \ - UNW(.spillsp f4,SW(F4)+(off)); UNW(.spillsp f5,SW(F5)+(off)); \ - UNW(.spillsp f16,SW(F16)+(off)); UNW(.spillsp f17,SW(F17)+(off)); \ - UNW(.spillsp f18,SW(F18)+(off)); UNW(.spillsp f19,SW(F19)+(off)); \ - UNW(.spillsp f20,SW(F20)+(off)); UNW(.spillsp f21,SW(F21)+(off)); \ - UNW(.spillsp f22,SW(F22)+(off)); UNW(.spillsp f23,SW(F23)+(off)); \ - UNW(.spillsp f24,SW(F24)+(off)); UNW(.spillsp f25,SW(F25)+(off)); \ - UNW(.spillsp f26,SW(F26)+(off)); UNW(.spillsp f27,SW(F27)+(off)); \ - UNW(.spillsp f28,SW(F28)+(off)); UNW(.spillsp f29,SW(F29)+(off)); \ - UNW(.spillsp f30,SW(F30)+(off)); UNW(.spillsp f31,SW(F31)+(off)); \ - UNW(.spillsp r4,SW(R4)+(off)); UNW(.spillsp r5,SW(R5)+(off)); \ - UNW(.spillsp r6,SW(R6)+(off)); UNW(.spillsp r7,SW(R7)+(off)); \ - UNW(.spillsp b0,SW(B0)+(off)); UNW(.spillsp b1,SW(B1)+(off)); \ - UNW(.spillsp b2,SW(B2)+(off)); UNW(.spillsp b3,SW(B3)+(off)); \ - UNW(.spillsp b4,SW(B4)+(off)); UNW(.spillsp b5,SW(B5)+(off)); \ - UNW(.spillsp ar.pfs,SW(AR_PFS)+(off)); UNW(.spillsp ar.lc,SW(AR_LC)+(off)); \ - UNW(.spillsp @priunat,SW(AR_UNAT)+(off)); \ - UNW(.spillsp ar.rnat,SW(AR_RNAT)+(off)); UNW(.spillsp ar.bspstore,SW(AR_BSPSTORE)+(off)); \ - UNW(.spillsp pr,SW(PR)+(off)) +#define SWITCH_STACK_SAVES(off) \ + .savesp ar.unat,SW(CALLER_UNAT)+16+(off); \ + .savesp ar.fpsr,SW(AR_FPSR)+16+(off); \ + .spillsp f2,SW(F2)+16+(off); .spillsp f3,SW(F3)+16+(off); \ + .spillsp f4,SW(F4)+16+(off); .spillsp f5,SW(F5)+16+(off); \ + .spillsp f16,SW(F16)+16+(off); .spillsp f17,SW(F17)+16+(off); \ + .spillsp f18,SW(F18)+16+(off); .spillsp f19,SW(F19)+16+(off); \ + .spillsp f20,SW(F20)+16+(off); .spillsp f21,SW(F21)+16+(off); \ + .spillsp f22,SW(F22)+16+(off); .spillsp f23,SW(F23)+16+(off); \ + .spillsp f24,SW(F24)+16+(off); .spillsp f25,SW(F25)+16+(off); \ + .spillsp f26,SW(F26)+16+(off); .spillsp f27,SW(F27)+16+(off); \ + .spillsp f28,SW(F28)+16+(off); .spillsp f29,SW(F29)+16+(off); \ + .spillsp f30,SW(F30)+16+(off); .spillsp f31,SW(F31)+16+(off); \ + .spillsp r4,SW(R4)+16+(off); .spillsp r5,SW(R5)+16+(off); \ + .spillsp r6,SW(R6)+16+(off); .spillsp r7,SW(R7)+16+(off); \ + .spillsp b0,SW(B0)+16+(off); .spillsp b1,SW(B1)+16+(off); \ + .spillsp b2,SW(B2)+16+(off); .spillsp b3,SW(B3)+16+(off); \ + .spillsp b4,SW(B4)+16+(off); .spillsp b5,SW(B5)+16+(off); \ + .spillsp ar.pfs,SW(AR_PFS)+16+(off); .spillsp ar.lc,SW(AR_LC)+16+(off); \ + .spillsp @priunat,SW(AR_UNAT)+16+(off); \ + .spillsp ar.rnat,SW(AR_RNAT)+16+(off); \ + .spillsp ar.bspstore,SW(AR_BSPSTORE)+16+(off); \ + .spillsp pr,SW(PR)+16+(off)) #define DO_SAVE_SWITCH_STACK \ movl r28=1f; \ ;; \ .fframe IA64_SWITCH_STACK_SIZE; \ adds sp=-IA64_SWITCH_STACK_SIZE,sp; \ - mov b7=r28; \ + MOVBR(.ret.sptk,b7,r28,1f); \ SWITCH_STACK_SAVES(0); \ br.cond.sptk.many save_switch_stack; \ 1: -#define DO_LOAD_SWITCH_STACK(extra) \ +#define DO_LOAD_SWITCH_STACK \ movl r28=1f; \ ;; \ - mov b7=r28; \ + invala; \ + MOVBR(.ret.sptk,b7,r28,1f); \ br.cond.sptk.many load_switch_stack; \ -1: UNW(.restore sp); \ - extra; \ +1: .restore sp; \ adds sp=IA64_SWITCH_STACK_SIZE,sp diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/fw-emu.c linux.ac/arch/ia64/kernel/fw-emu.c --- linux.vanilla/arch/ia64/kernel/fw-emu.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/fw-emu.c Tue Apr 10 18:08:40 2001 @@ -1,8 +1,8 @@ /* * PAL & SAL emulation. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * * For the HP simulator, this file gets include in boot/bootloader.c. * For SoftSDV, this file gets included in sys_softsdv.c. @@ -22,7 +22,8 @@ #define NUM_MEM_DESCS 2 -static char fw_mem[( sizeof(efi_system_table_t) +static char fw_mem[( sizeof(struct ia64_boot_param) + + sizeof(efi_system_table_t) + sizeof(efi_runtime_services_t) + 1*sizeof(efi_config_table_t) + sizeof(struct ia64_sal_systab) @@ -151,6 +152,14 @@ movl r10=0x100000100 /* bus_ratio<<32 (1/256) */ movl r11=0x100000064 /* itc_ratio<<32 (1/100) */ ;; +1: cmp.eq p6,p7=19,r28 /* PAL_RSE_INFO */ +(p7) br.cond.sptk.few 1f + mov r8=0 /* status = 0 */ + mov r9=96 /* num phys stacked */ + mov r10=0 /* hints */ + mov r11=0 + br.cond.sptk.few rp + 1: cmp.eq p6,p7=1,r28 /* PAL_CACHE_FLUSH */ (p7) br.cond.sptk.few 1f mov r9=ar.lc @@ -168,8 +177,7 @@ ;; mov ar.lc=r9 mov r8=r0 -1: - br.cond.sptk.few rp +1: br.cond.sptk.few rp stacked: br.ret.sptk.few rp @@ -249,13 +257,7 @@ * or something platform specific? The SAL * doc ain't exactly clear on this... */ -#if defined(CONFIG_IA64_SOFTSDV_HACKS) - r9 = 4000000; -#elif defined(CONFIG_IA64_SDV) - r9 = 300000000; -#else r9 = 700000000; -#endif break; case SAL_FREQ_BASE_REALTIME_CLOCK: @@ -332,7 +334,7 @@ return (void *) addr; } -void +struct ia64_boot_param * sys_fw_init (const char *args, int arglen) { efi_system_table_t *efi_systab; @@ -358,6 +360,7 @@ sal_systab = (void *) cp; cp += sizeof(*sal_systab); sal_ed = (void *) cp; cp += sizeof(*sal_ed); efi_memmap = (void *) cp; cp += NUM_MEM_DESCS*sizeof(*efi_memmap); + bp = (void *) cp; cp += sizeof(*bp); cmd_line = (void *) cp; if (args) { @@ -423,7 +426,7 @@ strcpy(sal_systab->product_id, "SN1"); #endif - /* fill in an entry point: */ + /* fill in an entry point: */ sal_ed->type = SAL_DESC_ENTRY_POINT; sal_ed->pal_proc = __pa(pal_desc[0]); sal_ed->sal_proc = __pa(sal_desc[0]); @@ -440,15 +443,15 @@ md->pad = 0; md->phys_addr = 2*MB; md->virt_addr = 0; - md->num_pages = (64*MB) >> 12; /* 64MB (in 4KB pages) */ + md->num_pages = (128*MB) >> 12; /* 128MB (in 4KB pages) */ md->attribute = EFI_MEMORY_WB; /* descriptor for firmware emulator: */ md = &efi_memmap[1]; - md->type = EFI_RUNTIME_SERVICES_DATA; + md->type = EFI_PAL_CODE; md->pad = 0; md->phys_addr = 1*MB; - md->virt_addr = 0; + md->virt_addr = 1*MB; md->num_pages = (1*MB) >> 12; /* 1MB (in 4KB pages) */ md->attribute = EFI_MEMORY_WB; @@ -468,7 +471,6 @@ md->attribute = EFI_MEMORY_WB; #endif - bp = id(ZERO_PAGE_ADDR); bp->efi_systab = __pa(&fw_mem); bp->efi_memmap = __pa(efi_memmap); bp->efi_memmap_size = NUM_MEM_DESCS*sizeof(efi_memory_desc_t); @@ -479,6 +481,7 @@ bp->console_info.num_rows = 25; bp->console_info.orig_x = 0; bp->console_info.orig_y = 24; - bp->num_pci_vectors = 0; bp->fpswa = 0; + + return bp; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/gate.S linux.ac/arch/ia64/kernel/gate.S --- linux.vanilla/arch/ia64/kernel/gate.S Sat Jul 15 00:08:11 2000 +++ linux.ac/arch/ia64/kernel/gate.S Tue Apr 10 18:08:40 2001 @@ -1,10 +1,9 @@ /* - * This file contains the code that gets mapped at the upper end of - * each task's text region. For now, it contains the signal - * trampoline code only. + * This file contains the code that gets mapped at the upper end of each task's text + * region. For now, it contains the signal trampoline code only. * - * Copyright (C) 1999-2000 Hewlett-Packard Co - * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <asm/asmmacro.h> @@ -14,11 +13,7 @@ #include <asm/unistd.h> #include <asm/page.h> - .psr abi64 - .psr lsb - .lsb - - .section __gate_section,"ax" + .section .text.gate,"ax" .align PAGE_SIZE @@ -51,28 +46,24 @@ * | space | * +-------------------------------+ <-- sp * - * The register stack looks _exactly_ the way it looked at the - * time the signal occurred. In other words, we're treading - * on a potential mine-field: each incoming general register - * may be a NaT value (includeing sp, in which case the process - * ends up dying with a SIGSEGV). + * The register stack looks _exactly_ the way it looked at the time the signal + * occurred. In other words, we're treading on a potential mine-field: each + * incoming general register may be a NaT value (including sp, in which case the + * process ends up dying with a SIGSEGV). * - * The first need to do is a cover to get the registers onto - * the backing store. Once that is done, we invoke the signal - * handler which may modify some of the machine state. After - * returning from the signal handler, we return control to the - * previous context by executing a sigreturn system call. A - * signal handler may call the rt_sigreturn() function to - * directly return to a given sigcontext. However, the - * user-level sigreturn() needs to do much more than calling - * the rt_sigreturn() system call as it needs to unwind the - * stack to restore preserved registers that may have been - * saved on the signal handler's call stack. + * The first need to do is a cover to get the registers onto the backing store. + * Once that is done, we invoke the signal handler which may modify some of the + * machine state. After returning from the signal handler, we return control to + * the previous context by executing a sigreturn system call. A signal handler + * may call the rt_sigreturn() function to directly return to a given sigcontext. + * However, the user-level sigreturn() needs to do much more than calling the + * rt_sigreturn() system call as it needs to unwind the stack to restore preserved + * registers that may have been saved on the signal handler's call stack. * * On entry: * r2 = signal number * r3 = plabel of signal handler - * r15 = new register backing store (ignored) + * r15 = new register backing store * [sp+16] = sigframe */ @@ -153,7 +144,7 @@ ENTRY(setup_rbs) flushrs // must be first in insn - mov ar.rsc=r0 // put RSE into enforced lazy mode + mov ar.rsc=0 // put RSE into enforced lazy mode adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp ;; mov r14=ar.rnat // get rnat as updated by flushrs @@ -167,7 +158,7 @@ ENTRY(restore_rbs) flushrs - mov ar.rsc=r0 // put RSE into enforced lazy mode + mov ar.rsc=0 // put RSE into enforced lazy mode adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp ;; ld8 r14=[r16] // get new rnat diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/head.S linux.ac/arch/ia64/kernel/head.S --- linux.vanilla/arch/ia64/kernel/head.S Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/head.S Tue Apr 10 18:08:40 2001 @@ -5,8 +5,9 @@ * to set up the kernel's global pointer and jump to the kernel * entry point. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 2001 Stephane Eranian <eranian@hpl.hp.com> * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> * Copyright (C) 1999 Intel Corp. @@ -18,16 +19,15 @@ #include <asm/asmmacro.h> #include <asm/fpu.h> -#include <asm/pal.h> +#include <asm/kregs.h> +#include <asm/mmu_context.h> #include <asm/offsets.h> +#include <asm/pal.h> +#include <asm/pgtable.h> #include <asm/processor.h> #include <asm/ptrace.h> #include <asm/system.h> - .psr abi64 - .psr lsb - .lsb - .section __special_page_section,"ax" .global empty_zero_page @@ -38,29 +38,66 @@ swapper_pg_dir: .skip PAGE_SIZE - .global empty_bad_page -empty_bad_page: - .skip PAGE_SIZE - - .global empty_bad_pte_table -empty_bad_pte_table: - .skip PAGE_SIZE - - .global empty_bad_pmd_table -empty_bad_pmd_table: - .skip PAGE_SIZE - .rodata halt_msg: stringz "Halting kernel\n" .text + .global start_ap + + /* + * Start the kernel. When the bootloader passes control to _start(), r28 + * points to the address of the boot parameter area. Execution reaches + * here in physical mode. + */ GLOBAL_ENTRY(_start) - UNW(.prologue) - UNW(.save rp, r4) // terminate unwind chain with a NULL rp - UNW(mov r4=r0) - UNW(.body) +start_ap: + .prologue + .save rp, r4 // terminate unwind chain with a NULL rp + mov r4=r0 + .body + + /* + * Initialize the region register for region 7 and install a translation register + * that maps the kernel's text and data: + */ + rsm psr.i | psr.ic + mov r16=((ia64_rid(IA64_REGION_ID_KERNEL, PAGE_OFFSET) << 8) | (_PAGE_SIZE_64M << 2)) + ;; + srlz.i + mov r18=_PAGE_SIZE_64M<<2 + movl r17=PAGE_OFFSET + 64*1024*1024 + ;; + mov rr[r17]=r16 + mov cr.itir=r18 + mov cr.ifa=r17 + mov r16=IA64_TR_KERNEL + movl r18=(64*1024*1024 | PAGE_KERNEL) + ;; + srlz.i + ;; + itr.i itr[r16]=r18 + ;; + itr.d dtr[r16]=r18 + ;; + srlz.i + + /* + * Switch into virtual mode: + */ + movl r16=(IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN) + ;; + mov cr.ipsr=r16 + movl r17=1f + ;; + mov cr.iip=r17 + mov cr.ifs=r0 + ;; + rfi + ;; +1: // now we are in virtual mode + // set IVT entry point---can't access I/O ports without it movl r3=ia64_ivt ;; @@ -74,7 +111,7 @@ ;; #ifdef CONFIG_IA64_EARLY_PRINTK - mov r3=(6<<8) | (28<<2) + mov r3=(6<<8) | (_PAGE_SIZE_64M<<2) movl r2=6<<61 ;; mov rr[r2]=r3 @@ -83,27 +120,32 @@ ;; #endif -#define isAP p2 // are we booting an Application Processor (not the BSP)? +#define isAP p2 // are we an Application Processor? +#define isBP p3 // are we the Bootstrap Processor? - // Find the init_task for the currently booting CPU. At poweron, and in - // UP mode, cpu_now_booting is 0 + /* + * Find the init_task for the currently booting CPU. At poweron, and in + * UP mode, cpu_now_booting is 0. + */ movl r3=cpu_now_booting ;; - ld4 r3=[r3] + ld4 r3=[r3] // r3 <- smp_processor_id() movl r2=init_tasks - ;; + ;; shladd r2=r3,3,r2 ;; ld8 r2=[r2] - cmp4.ne isAP,p0=r3,r0 // p9 == true if this is an application processor (ap) + cmp4.ne isAP,isBP=r3,r0 ;; // RAW on r2 extr r3=r2,0,61 // r3 == phys addr of task struct ;; - // load the "current" pointer (r13) and ar.k6 with the current task + // load the "current" pointer (r13) and ar.k6 with the current task mov r13=r2 - mov ar.k6=r3 // Physical address - ;; + mov IA64_KR(CURRENT)=r3 // Physical address + + // initialize k4 to a safe value (64-128MB is mapped by TR_KERNEL) + mov IA64_KR(CURRENT_STACK)=1 /* * Reserve space at the top of the stack for "struct pt_regs". Kernel threads * don't store interesting values in that structure, but the space still needs @@ -113,14 +155,18 @@ */ addl r12=IA64_STK_OFFSET-IA64_PT_REGS_SIZE-16,r2 addl r2=IA64_RBS_OFFSET,r2 // initialize the RSE - mov ar.rsc=r0 // place RSE in enforced lazy mode + mov ar.rsc=0 // place RSE in enforced lazy mode ;; - mov ar.bspstore=r2 // establish the new RSE stack + loadrs // clear the dirty partition ;; - loadrs // load zero bytes from the register stack + mov ar.bspstore=r2 // establish the new RSE stack ;; mov ar.rsc=0x3 // place RSE in eager mode + +(isBP) dep r28=-1,r28,61,3 // make address virtual +(isBP) movl r2=ia64_boot_param ;; +(isBP) st8 [r2]=r28 // save the address of the boot param area passed by the bootloader #ifdef CONFIG_IA64_EARLY_PRINTK .rodata @@ -135,16 +181,12 @@ 1: // force new bundle #endif /* CONFIG_IA64_EARLY_PRINTK */ - alloc r2=ar.pfs,8,0,2,0 - ;; #ifdef CONFIG_SMP (isAP) br.call.sptk.few rp=smp_callin .ret0: (isAP) br.cond.sptk.few self #endif -#undef isAP - // This is executed by the bootstrap processor (bsp) only: #ifdef CONFIG_IA64_FW_EMU @@ -153,9 +195,11 @@ .ret1: #endif br.call.sptk.few rp=start_kernel -.ret2: addl r2=@ltoff(halt_msg),gp +.ret2: addl r3=@ltoff(halt_msg),gp + ;; + alloc r2=ar.pfs,8,0,2,0 ;; - ld8 out0=[r2] + ld8 out0=[r3] br.call.sptk.few b0=console_print self: br.sptk.few self // endless loop END(_start) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/ia64_ksyms.c linux.ac/arch/ia64/kernel/ia64_ksyms.c --- linux.vanilla/arch/ia64/kernel/ia64_ksyms.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/ia64_ksyms.c Tue Apr 10 18:08:40 2001 @@ -24,8 +24,11 @@ EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strtok); -#include <asm/hw_irq.h> +#include <linux/irq.h> EXPORT_SYMBOL(isa_irq_to_vector_map); +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(disable_irq_nosync); #include <linux/in6.h> #include <asm/checksum.h> @@ -40,10 +43,14 @@ EXPORT_SYMBOL(__ia64_memcpy_toio); EXPORT_SYMBOL(__ia64_memset_c_io); -#include <asm/irq.h> -EXPORT_SYMBOL(enable_irq); -EXPORT_SYMBOL(disable_irq); -EXPORT_SYMBOL(disable_irq_nosync); +#include <asm/semaphore.h> +EXPORT_SYMBOL_NOVERS(__down); +EXPORT_SYMBOL_NOVERS(__down_interruptible); +EXPORT_SYMBOL_NOVERS(__down_trylock); +EXPORT_SYMBOL_NOVERS(__up); +EXPORT_SYMBOL_NOVERS(__down_read_failed); +EXPORT_SYMBOL_NOVERS(__down_write_failed); +EXPORT_SYMBOL_NOVERS(__rwsem_wake); #include <asm/page.h> EXPORT_SYMBOL(clear_page); @@ -57,14 +64,20 @@ EXPORT_SYMBOL(last_cli_ip); #endif +#include <asm/pgalloc.h> + #ifdef CONFIG_SMP +EXPORT_SYMBOL(smp_flush_tlb_all); + #include <asm/current.h> #include <asm/hardirq.h> EXPORT_SYMBOL(synchronize_irq); #include <asm/smp.h> EXPORT_SYMBOL(smp_call_function); +EXPORT_SYMBOL(smp_call_function_single); +EXPORT_SYMBOL(cpu_online_map); #include <linux/smp.h> EXPORT_SYMBOL(smp_num_cpus); @@ -78,7 +91,11 @@ EXPORT_SYMBOL(__global_save_flags); EXPORT_SYMBOL(__global_restore_flags); -#endif +#else /* !CONFIG_SMP */ + +EXPORT_SYMBOL(__flush_tlb_all); + +#endif /* !CONFIG_SMP */ #include <asm/uaccess.h> EXPORT_SYMBOL(__copy_user); @@ -111,3 +128,12 @@ extern unsigned long ia64_iobase; EXPORT_SYMBOL(ia64_iobase); + +#include <asm/pal.h> +EXPORT_SYMBOL(ia64_pal_call_phys_stacked); +EXPORT_SYMBOL(ia64_pal_call_phys_static); +EXPORT_SYMBOL(ia64_pal_call_stacked); +EXPORT_SYMBOL(ia64_pal_call_static); + +extern struct efi efi; +EXPORT_SYMBOL(efi); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/iosapic.c linux.ac/arch/ia64/kernel/iosapic.c --- linux.vanilla/arch/ia64/kernel/iosapic.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/iosapic.c Tue Apr 10 18:08:40 2001 @@ -11,7 +11,7 @@ * 00/04/19 D. Mosberger Rewritten to mirror more closely the x86 I/O APIC code. * In particular, we now have separate handlers for edge * and level triggered interrupts. - * 00/10/27 Asit Mallick, Goutham Rao <goutham.rao@intel.com> IRQ vector allocation + * 00/10/27 Asit Mallick, Goutham Rao <goutham.rao@intel.com> IRQ vector allocation * PCI to vector mapping, shared PCI interrupts. * 00/10/27 D. Mosberger Document things a bit more to make them more understandable. * Clean up much of the old IOSAPIC cruft. @@ -79,27 +79,27 @@ static struct iosapic_irq { char *addr; /* base address of IOSAPIC */ unsigned char base_irq; /* first irq assigned to this IOSAPIC */ - char pin; /* IOSAPIC pin (-1 => not an IOSAPIC irq) */ - unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ + char pin; /* IOSAPIC pin (-1 => not an IOSAPIC irq) */ + unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ unsigned char polarity : 1; /* interrupt polarity (see iosapic.h) */ unsigned char trigger : 1; /* trigger mode (see iosapic.h) */ -} iosapic_irq[NR_IRQS]; +} iosapic_irq[IA64_NUM_VECTORS]; /* * Translate IOSAPIC irq number to the corresponding IA-64 interrupt vector. If no * entry exists, return -1. */ -static int +static int iosapic_irq_to_vector (int irq) { int vector; - for (vector = 0; vector < NR_IRQS; ++vector) + for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) if (iosapic_irq[vector].base_irq + iosapic_irq[vector].pin == irq) return vector; return -1; } - + /* * Map PCI pin to the corresponding IA-64 interrupt vector. If no such mapping exists, * return -1. @@ -137,14 +137,8 @@ (dmode << IOSAPIC_DELIVERY_SHIFT) | vector); -#ifdef CONFIG_IA64_AZUSA_HACKS - /* set Flush Disable bit */ - if (addr != (char *) 0xc0000000fec00000) - low32 |= (1 << 17); -#endif - /* dest contains both id and eid */ - high32 = (dest << IOSAPIC_DEST_SHIFT); + high32 = (dest << IOSAPIC_DEST_SHIFT); writel(IOSAPIC_RTE_HIGH(pin), addr + IOSAPIC_REG_SELECT); writel(high32, addr + IOSAPIC_WINDOW); @@ -158,16 +152,17 @@ /* do nothing... */ } -static void -mask_irq (unsigned int vector) +static void +mask_irq (unsigned int irq) { unsigned long flags; char *addr; u32 low32; int pin; + ia64_vector vec = irq_to_vector(irq); - addr = iosapic_irq[vector].addr; - pin = iosapic_irq[vector].pin; + addr = iosapic_irq[vec].addr; + pin = iosapic_irq[vec].pin; if (pin < 0) return; /* not an IOSAPIC interrupt! */ @@ -183,16 +178,17 @@ spin_unlock_irqrestore(&iosapic_lock, flags); } -static void -unmask_irq (unsigned int vector) +static void +unmask_irq (unsigned int irq) { unsigned long flags; char *addr; u32 low32; int pin; + ia64_vector vec = irq_to_vector(irq); - addr = iosapic_irq[vector].addr; - pin = iosapic_irq[vector].pin; + addr = iosapic_irq[vec].addr; + pin = iosapic_irq[vec].pin; if (pin < 0) return; /* not an IOSAPIC interrupt! */ @@ -209,7 +205,7 @@ static void -iosapic_set_affinity (unsigned int vector, unsigned long mask) +iosapic_set_affinity (unsigned int irq, unsigned long mask) { printk("iosapic_set_affinity: not implemented yet\n"); } @@ -219,16 +215,18 @@ */ static unsigned int -iosapic_startup_level_irq (unsigned int vector) +iosapic_startup_level_irq (unsigned int irq) { - unmask_irq(vector); + unmask_irq(irq); return 0; } static void -iosapic_end_level_irq (unsigned int vector) +iosapic_end_level_irq (unsigned int irq) { - writel(vector, iosapic_irq[vector].addr + IOSAPIC_EOI); + ia64_vector vec = irq_to_vector(irq); + + writel(vec, iosapic_irq[vec].addr + IOSAPIC_EOI); } #define iosapic_shutdown_level_irq mask_irq @@ -252,9 +250,9 @@ */ static unsigned int -iosapic_startup_edge_irq (unsigned int vector) +iosapic_startup_edge_irq (unsigned int irq) { - unmask_irq(vector); + unmask_irq(irq); /* * IOSAPIC simply drops interrupts pended while the * corresponding pin was masked, so we can't know if an @@ -264,15 +262,16 @@ } static void -iosapic_ack_edge_irq (unsigned int vector) +iosapic_ack_edge_irq (unsigned int irq) { + irq_desc_t *idesc = irq_desc(irq); /* * Once we have recorded IRQ_PENDING already, we can mask the * interrupt for real. This prevents IRQ storms from unhandled * devices. */ - if ((irq_desc[vector].status & (IRQ_PENDING|IRQ_DISABLED)) == (IRQ_PENDING|IRQ_DISABLED)) - mask_irq(vector); + if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) == (IRQ_PENDING|IRQ_DISABLED)) + mask_irq(irq); } #define iosapic_enable_edge_irq unmask_irq @@ -291,7 +290,7 @@ }; static unsigned int -iosapic_version (char *addr) +iosapic_version (char *addr) { /* * IOSAPIC Version Register return 32 bit structure like: @@ -335,6 +334,7 @@ { struct hw_interrupt_type *irq_type; int i, irq, max_pin, vector; + irq_desc_t *idesc; unsigned int ver; char *addr; static int first_time = 1; @@ -342,18 +342,18 @@ if (first_time) { first_time = 0; - for (vector = 0; vector < NR_IRQS; ++vector) + for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) iosapic_irq[vector].pin = -1; /* mark as unused */ - /* + /* * Fetch the PCI interrupt routing table: */ #ifdef CONFIG_ACPI_KERNEL_CONFIG acpi_cf_get_pci_vectors(&pci_irq.route, &pci_irq.num_routes); #else pci_irq.route = - (struct pci_vector_struct *) __va(ia64_boot_param.pci_vectors); - pci_irq.num_routes = ia64_boot_param.num_pci_vectors; + (struct pci_vector_struct *) __va(ia64_boot_param->pci_vectors); + pci_irq.num_routes = ia64_boot_param->num_pci_vectors; #endif } @@ -361,8 +361,8 @@ ver = iosapic_version(addr); max_pin = (ver >> 16) & 0xff; - - printk("IOSAPIC: version %x.%x, address 0x%lx, IRQs 0x%02x-0x%02x\n", + + printk("IOSAPIC: version %x.%x, address 0x%lx, IRQs 0x%02x-0x%02x\n", (ver & 0xf0) >> 4, (ver & 0x0f), phys_addr, base_irq, base_irq + max_pin); if (base_irq == 0) @@ -385,20 +385,20 @@ irq, iosapic_irq[vector].base_irq + iosapic_irq[vector].pin, vector); #endif - irq_type = &irq_type_iosapic_edge; - if (irq_desc[vector].handler != irq_type) { - if (irq_desc[vector].handler != &no_irq_type) + irq_type = &irq_type_iosapic_edge; + idesc = irq_desc(vector); + if (idesc->handler != irq_type) { + if (idesc->handler != &no_irq_type) printk("iosapic_init: changing vector 0x%02x from %s to " - "%s\n", irq, irq_desc[vector].handler->typename, + "%s\n", irq, idesc->handler->typename, irq_type->typename); - irq_desc[vector].handler = irq_type; + idesc->handler = irq_type; } /* program the IOSAPIC routing table: */ set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); } -#ifndef CONFIG_IA64_SOFTSDV_HACKS for (i = 0; i < pci_irq.num_routes; i++) { irq = pci_irq.route[i].irq; @@ -428,18 +428,17 @@ iosapic_irq[vector].base_irq + iosapic_irq[vector].pin, vector); # endif irq_type = &irq_type_iosapic_level; - if (irq_desc[vector].handler != irq_type){ - if (irq_desc[vector].handler != &no_irq_type) + idesc = irq_desc(vector); + if (idesc->handler != irq_type){ + if (idesc->handler != &no_irq_type) printk("iosapic_init: changing vector 0x%02x from %s to %s\n", - vector, irq_desc[vector].handler->typename, - irq_type->typename); - irq_desc[vector].handler = irq_type; + vector, idesc->handler->typename, irq_type->typename); + idesc->handler = irq_type; } /* program the IOSAPIC routing table: */ set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); } -#endif /* !CONFIG_IA64_SOFTSDV_HACKS */ } void @@ -492,7 +491,7 @@ * Nothing to fixup * Fix out-of-range IRQ numbers */ - if (dev->irq >= NR_IRQS) + if (dev->irq >= IA64_NUM_VECTORS) dev->irq = 15; /* Spurious interrupts */ } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/irq.c linux.ac/arch/ia64/kernel/irq.c --- linux.vanilla/arch/ia64/kernel/irq.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/ia64/kernel/irq.c Tue Apr 10 18:08:40 2001 @@ -63,7 +63,7 @@ /* * Controller mappings for all interrupt sources: */ -irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = +irq_desc_t _irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = { IRQ_DISABLED, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}}; static void register_irq_proc (unsigned int irq); @@ -131,6 +131,7 @@ { int i, j; struct irqaction * action; + irq_desc_t *idesc; char *p = buf; p += sprintf(p, " "); @@ -139,8 +140,9 @@ *p++ = '\n'; for (i = 0 ; i < NR_IRQS ; i++) { - action = irq_desc[i].action; - if (!action) + idesc = irq_desc(i); + action = idesc->action; + if (!action) continue; p += sprintf(p, "%3d: ",i); #ifndef CONFIG_SMP @@ -150,7 +152,7 @@ p += sprintf(p, "%10u ", kstat.irqs[cpu_logical_map(j)][i]); #endif - p += sprintf(p, " %14s", irq_desc[i].handler->typename); + p += sprintf(p, " %14s", idesc->handler->typename); p += sprintf(p, " %s", action->name); for (action=action->next; action; action = action->next) @@ -193,10 +195,10 @@ printk("\n%s, CPU %d:\n", str, cpu); printk("irq: %d [",irqs_running()); for(i=0;i < smp_num_cpus;i++) - printk(" %d",local_irq_count(i)); + printk(" %d",irq_count(i)); printk(" ]\nbh: %d [",spin_is_locked(&global_bh_lock) ? 1 : 0); for(i=0;i < smp_num_cpus;i++) - printk(" %d",local_bh_count(i)); + printk(" %d",bh_count(i)); printk(" ]\nStack dumps:"); #if defined(__ia64__) @@ -224,7 +226,7 @@ esp &= ~(THREAD_SIZE-1); esp += sizeof(struct task_struct); show_stack((void*)esp); - } + } #else You lose... #endif @@ -232,7 +234,7 @@ show_stack(NULL); printk("\n"); } - + #define MAXCOUNT 100000000 /* @@ -266,7 +268,7 @@ # endif #endif -static inline void wait_on_irq(int cpu) +static inline void wait_on_irq(void) { int count = MAXCOUNT; @@ -278,7 +280,7 @@ * already executing in one.. */ if (!irqs_running()) - if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock)) + if (local_bh_count() || !spin_is_locked(&global_bh_lock)) break; /* Duh, we have to loop. Release the lock to avoid deadlocks */ @@ -290,13 +292,13 @@ count = ~0; } __sti(); - SYNC_OTHER_CORES(cpu); + SYNC_OTHER_CORES(smp_processor_id()); __cli(); if (irqs_running()) continue; if (global_irq_lock) continue; - if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock)) + if (!local_bh_count() && spin_is_locked(&global_bh_lock)) continue; if (!test_and_set_bit(0,&global_irq_lock)) break; @@ -320,28 +322,28 @@ } } -static inline void get_irqlock(int cpu) +static inline void get_irqlock(void) { if (test_and_set_bit(0,&global_irq_lock)) { /* do we already hold the lock? */ - if (cpu == global_irq_holder) + if (smp_processor_id() == global_irq_holder) return; /* Uhhuh.. Somebody else got it. Wait.. */ do { do { } while (test_bit(0,&global_irq_lock)); - } while (test_and_set_bit(0,&global_irq_lock)); + } while (test_and_set_bit(0,&global_irq_lock)); } - /* + /* * We also to make sure that nobody else is running - * in an interrupt context. + * in an interrupt context. */ - wait_on_irq(cpu); + wait_on_irq(); /* * Ok, finally.. */ - global_irq_holder = cpu; + global_irq_holder = smp_processor_id(); } #define EFLAGS_IF_SHIFT 9 @@ -365,28 +367,24 @@ #ifdef __ia64__ __save_flags(flags); if (flags & IA64_PSR_I) { - int cpu = smp_processor_id(); __cli(); - if (!local_irq_count(cpu)) - get_irqlock(cpu); + if (!local_irq_count()) + get_irqlock(); } #else __save_flags(flags); if (flags & (1 << EFLAGS_IF_SHIFT)) { - int cpu = smp_processor_id(); __cli(); - if (!local_irq_count(cpu)) - get_irqlock(cpu); + if (!local_irq_count()) + get_irqlock(); } #endif } void __global_sti(void) { - int cpu = smp_processor_id(); - - if (!local_irq_count(cpu)) - release_irqlock(cpu); + if (!local_irq_count()) + release_irqlock(smp_processor_id()); __sti(); } @@ -414,7 +412,7 @@ retval = 2 + local_enabled; /* check for global flags if we're not in an interrupt */ - if (!local_irq_count(cpu)) { + if (!local_irq_count()) { if (local_enabled) retval = 1; if (global_irq_holder == cpu) @@ -456,9 +454,8 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) { int status; - int cpu = smp_processor_id(); - irq_enter(cpu, irq); + local_irq_enter(irq); status = 1; /* Force the "do bottom halves" bit */ @@ -474,7 +471,7 @@ add_interrupt_randomness(irq); __cli(); - irq_exit(cpu, irq); + local_irq_exit(irq); return status; } @@ -483,11 +480,11 @@ * Generic enable/disable code: this just calls * down into the PIC-specific version for the actual * hardware disable after having gotten the irq - * controller lock. + * controller lock. */ void inline disable_irq_nosync(unsigned int irq) { - irq_desc_t *desc = irq_desc + irq; + irq_desc_t *desc = irq_desc(irq); unsigned long flags; spin_lock_irqsave(&desc->lock, flags); @@ -507,17 +504,17 @@ disable_irq_nosync(irq); #ifdef CONFIG_SMP - if (!local_irq_count(smp_processor_id())) { + if (!local_irq_count()) { do { barrier(); - } while (irq_desc[irq].status & IRQ_INPROGRESS); + } while (irq_desc(irq)->status & IRQ_INPROGRESS); } #endif } void enable_irq(unsigned int irq) { - irq_desc_t *desc = irq_desc + irq; + irq_desc_t *desc = irq_desc(irq); unsigned long flags; spin_lock_irqsave(&desc->lock, flags); @@ -541,26 +538,14 @@ spin_unlock_irqrestore(&desc->lock, flags); } -void do_IRQ_per_cpu(unsigned long irq, struct pt_regs *regs) -{ - irq_desc_t *desc = irq_desc + irq; - int cpu = smp_processor_id(); - - kstat.irqs[cpu][irq]++; - - desc->handler->ack(irq); - handle_IRQ_event(irq, regs, desc->action); - desc->handler->end(irq); -} - /* * do_IRQ handles all normal device IRQ's (the special * SMP cross-CPU interrupts have their own specific * handlers). */ unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs) -{ - /* +{ + /* * We ack quickly, we don't want the irq controller * thinking we're snobs just because some other CPU has * disabled global interrupts (we have already done the @@ -571,75 +556,82 @@ * handled by some other CPU. (or is disabled) */ int cpu = smp_processor_id(); - irq_desc_t *desc = irq_desc + irq; + irq_desc_t *desc = irq_desc(irq); struct irqaction * action; unsigned int status; kstat.irqs[cpu][irq]++; - spin_lock(&desc->lock); - desc->handler->ack(irq); - /* - REPLAY is when Linux resends an IRQ that was dropped earlier - WAITING is used by probe to mark irqs that are being tested - */ - status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); - status |= IRQ_PENDING; /* we _want_ to handle it */ - /* - * If the IRQ is disabled for whatever reason, we cannot - * use the action we have. - */ - action = NULL; - if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { - action = desc->action; - status &= ~IRQ_PENDING; /* we commit to handling */ - status |= IRQ_INPROGRESS; /* we are handling it */ - } - desc->status = status; + if (desc->status & IRQ_PER_CPU) { + /* no locking required for CPU-local interrupts: */ + desc->handler->ack(irq); + handle_IRQ_event(irq, regs, desc->action); + desc->handler->end(irq); + } else { + spin_lock(&desc->lock); + desc->handler->ack(irq); + /* + * REPLAY is when Linux resends an IRQ that was dropped earlier + * WAITING is used by probe to mark irqs that are being tested + */ + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); + status |= IRQ_PENDING; /* we _want_ to handle it */ - /* - * If there is no IRQ handler or it was disabled, exit early. - * Since we set PENDING, if another processor is handling - * a different instance of this same irq, the other processor - * will take care of it. - */ - if (!action) - goto out; + /* + * If the IRQ is disabled for whatever reason, we cannot + * use the action we have. + */ + action = NULL; + if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { + action = desc->action; + status &= ~IRQ_PENDING; /* we commit to handling */ + status |= IRQ_INPROGRESS; /* we are handling it */ + } + desc->status = status; - /* - * Edge triggered interrupts need to remember - * pending events. - * This applies to any hw interrupts that allow a second - * instance of the same irq to arrive while we are in do_IRQ - * or in the handler. But the code here only handles the _second_ - * instance of the irq, not the third or fourth. So it is mostly - * useful for irq hardware that does not mask cleanly in an - * SMP environment. - */ - for (;;) { + /* + * If there is no IRQ handler or it was disabled, exit early. + * Since we set PENDING, if another processor is handling + * a different instance of this same irq, the other processor + * will take care of it. + */ + if (!action) + goto out; + + /* + * Edge triggered interrupts need to remember + * pending events. + * This applies to any hw interrupts that allow a second + * instance of the same irq to arrive while we are in do_IRQ + * or in the handler. But the code here only handles the _second_ + * instance of the irq, not the third or fourth. So it is mostly + * useful for irq hardware that does not mask cleanly in an + * SMP environment. + */ + for (;;) { + spin_unlock(&desc->lock); + handle_IRQ_event(irq, regs, action); + spin_lock(&desc->lock); + + if (!(desc->status & IRQ_PENDING)) + break; + desc->status &= ~IRQ_PENDING; + } + desc->status &= ~IRQ_INPROGRESS; + out: + /* + * The ->end() handler has to deal with interrupts which got + * disabled while the handler was running. + */ + desc->handler->end(irq); spin_unlock(&desc->lock); - handle_IRQ_event(irq, regs, action); - spin_lock(&desc->lock); - - if (!(desc->status & IRQ_PENDING)) - break; - desc->status &= ~IRQ_PENDING; } - desc->status &= ~IRQ_INPROGRESS; -out: - /* - * The ->end() handler has to deal with interrupts which got - * disabled while the handler was running. - */ - desc->handler->end(irq); - spin_unlock(&desc->lock); - return 1; } -int request_irq(unsigned int irq, +int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, + unsigned long irqflags, const char * devname, void *dev_id) { @@ -655,7 +647,7 @@ */ if (irqflags & SA_SHIRQ) { if (!dev_id) - printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]); + printk("Bad boy: %s called us without a dev_id!\n", devname); } #endif @@ -681,7 +673,7 @@ kfree(action); return retval; } - + void free_irq(unsigned int irq, void *dev_id) { irq_desc_t *desc; @@ -691,7 +683,7 @@ if (irq >= NR_IRQS) return; - desc = irq_desc + irq; + desc = irq_desc(irq); spin_lock_irqsave(&desc->lock,flags); p = &desc->action; for (;;) { @@ -739,16 +731,16 @@ unsigned long val; unsigned long delay; - /* + /* * something may have generated an irq long ago and we want to - * flush such a longstanding irq before considering it as spurious. + * flush such a longstanding irq before considering it as spurious. */ for (i = NR_IRQS-1; i > 0; i--) { - desc = irq_desc + i; + desc = irq_desc(i); spin_lock_irq(&desc->lock); - if (!irq_desc[i].action) - irq_desc[i].handler->startup(i); + if (!desc->action) + desc->handler->startup(i); spin_unlock_irq(&desc->lock); } @@ -762,7 +754,7 @@ * happened in the previous stage, it may have masked itself) */ for (i = NR_IRQS-1; i > 0; i--) { - desc = irq_desc + i; + desc = irq_desc(i); spin_lock_irq(&desc->lock); if (!desc->action) { @@ -784,7 +776,7 @@ */ val = 0; for (i = 0; i < NR_IRQS; i++) { - irq_desc_t *desc = irq_desc + i; + irq_desc_t *desc = irq_desc(i); unsigned int status; spin_lock_irq(&desc->lock); @@ -816,7 +808,7 @@ mask = 0; for (i = 0; i < 16; i++) { - irq_desc_t *desc = irq_desc + i; + irq_desc_t *desc = irq_desc(i); unsigned int status; spin_lock_irq(&desc->lock); @@ -846,7 +838,7 @@ nr_irqs = 0; irq_found = 0; for (i = 0; i < NR_IRQS; i++) { - irq_desc_t *desc = irq_desc + i; + irq_desc_t *desc = irq_desc(i); unsigned int status; spin_lock_irq(&desc->lock); @@ -869,13 +861,12 @@ return irq_found; } -/* this was setup_x86_irq but it seems pretty generic */ int setup_irq(unsigned int irq, struct irqaction * new) { int shared = 0; unsigned long flags; struct irqaction *old, **p; - irq_desc_t *desc = irq_desc + irq; + irq_desc_t *desc = irq_desc(irq); /* * Some drivers like serial.c use request_irq() heavily, @@ -986,7 +977,7 @@ int irq = (long) data, full_count = count, err; unsigned long new_value; - if (!irq_desc[irq].handler->set_affinity) + if (!irq_desc(irq)->handler->set_affinity) return -EIO; err = parse_hex_value(buffer, count, &new_value); @@ -1002,7 +993,7 @@ #endif irq_affinity[irq] = new_value; - irq_desc[irq].handler->set_affinity(irq, new_value); + irq_desc(irq)->handler->set_affinity(irq, new_value); return full_count; } @@ -1037,7 +1028,7 @@ struct proc_dir_entry *entry; char name [MAX_NAMELEN]; - if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type)) + if (!root_irq_dir || (irq_desc(irq)->handler == &no_irq_type)) return; memset(name, 0, MAX_NAMELEN); @@ -1079,9 +1070,8 @@ * Create entries for all existing IRQs. */ for (i = 0; i < NR_IRQS; i++) { - if (irq_desc[i].handler == &no_irq_type) + if (irq_desc(i)->handler == &no_irq_type) continue; register_irq_proc(i); } } - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/irq_ia64.c linux.ac/arch/ia64/kernel/irq_ia64.c --- linux.vanilla/arch/ia64/kernel/irq_ia64.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/ia64/kernel/irq_ia64.c Tue Apr 10 18:08:40 2001 @@ -39,7 +39,7 @@ #define IRQ_DEBUG 0 /* default base addr of IPI table */ -unsigned long ipi_base_addr = (__IA64_UNCACHED_OFFSET | IPI_DEFAULT_BASE_ADDR); +unsigned long ipi_base_addr = (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR); /* * Legacy IRQ to IA-64 vector translation table. @@ -53,21 +53,23 @@ int ia64_alloc_irq (void) { - static int next_irq = FIRST_DEVICE_IRQ; + static int next_irq = IA64_FIRST_DEVICE_VECTOR; - if (next_irq > LAST_DEVICE_IRQ) + if (next_irq > IA64_LAST_DEVICE_VECTOR) /* XXX could look for sharable vectors instead of panic'ing... */ panic("ia64_alloc_irq: out of interrupt vectors!"); return next_irq++; } +extern unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs); + /* * That's where the IVT branches when we get an external * interrupt. This branches to the correct hardware IRQ handler via * function ptr. */ void -ia64_handle_irq (unsigned long vector, struct pt_regs *regs) +ia64_handle_irq (ia64_vector vector, struct pt_regs *regs) { unsigned long saved_tpr; @@ -89,7 +91,7 @@ static unsigned char count; static long last_time; - if (count > 5 && jiffies - last_time > 5*HZ) + if (jiffies - last_time > 5*HZ) count = 0; if (++count < 5) { last_time = jiffies; @@ -109,19 +111,10 @@ saved_tpr = ia64_get_tpr(); ia64_srlz_d(); do { - if (vector >= NR_IRQS) { - printk("handle_irq: invalid vector %lu\n", vector); - ia64_set_tpr(saved_tpr); - ia64_srlz_d(); - return; - } ia64_set_tpr(vector); ia64_srlz_d(); - if ((irq_desc[vector].status & IRQ_PER_CPU) != 0) - do_IRQ_per_cpu(vector, regs); - else - do_IRQ(vector, regs); + do_IRQ(local_vector_to_irq(vector), regs); /* * Disable interrupts and send EOI: @@ -130,7 +123,7 @@ ia64_set_tpr(saved_tpr); ia64_eoi(); vector = ia64_get_ivr(); - } while (vector != IA64_SPURIOUS_INT); + } while (vector != IA64_SPURIOUS_INT_VECTOR); } #ifdef CONFIG_SMP @@ -144,33 +137,30 @@ }; #endif +void +register_percpu_irq (ia64_vector vec, struct irqaction *action) +{ + irq_desc_t *desc; + unsigned int irq; + + for (irq = 0; irq < NR_IRQS; ++irq) + if (irq_to_vector(irq) == vec) { + desc = irq_desc(irq); + desc->status |= IRQ_PER_CPU; + desc->handler = &irq_type_ia64_sapic; + if (action) + setup_irq(irq, action); + } +} + void __init init_IRQ (void) { - /* - * Disable all local interrupts - */ - ia64_set_itv(0, 1); - ia64_set_lrr0(0, 1); - ia64_set_lrr1(0, 1); - - irq_desc[IA64_SPURIOUS_INT].handler = &irq_type_ia64_sapic; + register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL); #ifdef CONFIG_SMP - /* - * Configure the IPI vector and handler - */ - irq_desc[IPI_IRQ].status |= IRQ_PER_CPU; - irq_desc[IPI_IRQ].handler = &irq_type_ia64_sapic; - setup_irq(IPI_IRQ, &ipi_irqaction); + register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction); #endif - - ia64_set_pmv(1 << 16); - ia64_set_cmcv(CMC_IRQ); /* XXX fix me */ - platform_irq_init(); - - /* clear TPR to enable all interrupt classes: */ - ia64_set_tpr(0); } void diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/ivt.S linux.ac/arch/ia64/kernel/ivt.S --- linux.vanilla/arch/ia64/kernel/ivt.S Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/ivt.S Tue Apr 10 18:08:40 2001 @@ -1,9 +1,9 @@ /* * arch/ia64/kernel/ivt.S * - * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998-2001 Hewlett-Packard Co * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com> - * Copyright (C) 1998-2000 David Mosberger <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 David Mosberger <davidm@hpl.hp.com> * * 00/08/23 Asit Mallick <asit.k.mallick@intel.com> TLB handling for SMP * 00/12/20 David Mosberger-Tang <davidm@hpl.hp.com> DTLB/ITLB handler now uses virtual PT. @@ -14,7 +14,7 @@ * * External interrupts only use 1 entry. All others are internal interrupts * - * The first 20 entries of the table contain 64 bundles each while the + * The first 20 entries of the table contain 64 bundles each while the * remaining 48 entries contain only 16 bundles each. * * The 64 bundles are used to allow inlining the whole handler for critical @@ -22,7 +22,7 @@ * * For each entry, the comment is as follows: * - * // 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51) + * // 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51) * entry offset ----/ / / / / * entry number ---------/ / / / * size of the entry -------------/ / / @@ -37,7 +37,9 @@ #include <linux/config.h> +#include <asm/asmmacro.h> #include <asm/break.h> +#include <asm/kregs.h> #include <asm/offsets.h> #include <asm/pgtable.h> #include <asm/processor.h> @@ -45,6 +47,22 @@ #include <asm/system.h> #include <asm/unistd.h> +#if 1 +# define PSR_DEFAULT_BITS psr.ac +#else +# define PSR_DEFAULT_BITS 0 +#endif + +#if 0 + /* + * This lets you track the last eight faults that occurred on the CPU. Make sure ar.k2 isn't + * needed for something else before enabling this... + */ +# define DBG_FAULT(i) mov r16=ar.k2;; shl r16=r16,8;; add r16=(i),r16;;mov ar.k2=r16 +#else +# define DBG_FAULT(i) +#endif + #define MINSTATE_VIRT /* needed by minstate.h */ #include "minstate.h" @@ -57,8 +75,8 @@ * As we don't (hopefully) use the space available, we need to fill it with * nops. the parameter may be used for debugging and is representing the entry * number - */ -#define BREAK_BUNDLE(a) break.m (a); \ + */ +#define BREAK_BUNDLE(a) break.m (a); \ break.i (a); \ break.i (a) /* @@ -71,17 +89,15 @@ */ #define BREAK_BUNDLE8(a); BREAK_BUNDLE4(a); BREAK_BUNDLE4(a) - .psr abi64 - .psr lsb - .lsb - - .section __ivt_section,"ax" + .section .text.ivt,"ax" .align 32768 // align on 32KB boundary .global ia64_ivt ia64_ivt: ///////////////////////////////////////////////////////////////////////////////////////// // 0x0000 Entry 0 (size 64 bundles) VHPT Translation (8,20,47) +ENTRY(vhpt_miss) + DBG_FAULT(0) /* * The VHPT vector is invoked when the TLB entry for the virtual page table * is missing. This happens only as a result of a previous @@ -103,7 +119,7 @@ ;; rsm psr.dt // use physical addressing for data mov r31=pr // save the predicate registers - mov r19=ar.k7 // get page table base address + mov r19=IA64_KR(PT_BASE) // get page table base address shl r21=r16,3 // shift bit 60 into sign bit shr.u r17=r16,61 // get the region number into r17 ;; @@ -146,19 +162,21 @@ (p6) br.spnt.many page_fault // handle bad address/page not present (page fault) mov cr.ifa=r22 - // Now compute and insert the TLB entry for the virtual page table. - // We never execute in a page table page so there is no need to set - // the exception deferral bit. + /* + * Now compute and insert the TLB entry for the virtual page table. We never + * execute in a page table page so there is no need to set the exception deferral + * bit. + */ adds r24=__DIRTY_BITS_NO_ED|_PAGE_PL_0|_PAGE_AR_RW,r23 ;; (p7) itc.d r24 ;; #ifdef CONFIG_SMP - // - // Re-check L2 and L3 pagetable. If they changed, we may have received - // a ptc.g between reading the pagetable and the "itc". If so, - // flush the entry we inserted and retry. - // + /* + * Re-check L2 and L3 pagetable. If they changed, we may have received a ptc.g + * between reading the pagetable and the "itc". If so, flush the entry we + * inserted and retry. + */ ld8 r25=[r21] // read L3 PTE again ld8 r26=[r17] // read L2 entry again ;; @@ -173,26 +191,29 @@ mov pr=r31,-1 // restore predicate registers rfi - ;; +END(vhpt_miss) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x0400 Entry 1 (size 64 bundles) ITLB (21) +ENTRY(itlb_miss) + DBG_FAULT(1) /* * The ITLB handler accesses the L3 PTE via the virtually mapped linear * page table. If a nested TLB miss occurs, we switch into physical * mode, walk the page table, and then re-execute the L3 PTE read * and go on normally after that. */ -itlb_fault: mov r16=cr.ifa // get virtual address mov r29=b0 // save b0 mov r31=pr // save predicates +itlb_fault: mov r17=cr.iha // get virtual address of L3 PTE movl r30=1f // load nested fault continuation point ;; 1: ld8 r18=[r17] // read L3 PTE ;; + mov b0=r29 tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? (p6) br.cond.spnt.many page_fault ;; @@ -208,26 +229,29 @@ #endif mov pr=r31,-1 rfi - ;; +END(itlb_miss) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x0800 Entry 2 (size 64 bundles) DTLB (9,48) +ENTRY(dtlb_miss) + DBG_FAULT(2) /* * The DTLB handler accesses the L3 PTE via the virtually mapped linear * page table. If a nested TLB miss occurs, we switch into physical * mode, walk the page table, and then re-execute the L3 PTE read * and go on normally after that. */ -dtlb_fault: mov r16=cr.ifa // get virtual address mov r29=b0 // save b0 mov r31=pr // save predicates +dtlb_fault: mov r17=cr.iha // get virtual address of L3 PTE movl r30=1f // load nested fault continuation point ;; 1: ld8 r18=[r17] // read L3 PTE ;; + mov b0=r29 tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? (p6) br.cond.spnt.many page_fault ;; @@ -243,24 +267,27 @@ #endif mov pr=r31,-1 rfi - ;; +END(dtlb_miss) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x0c00 Entry 3 (size 64 bundles) Alt ITLB (19) +ENTRY(alt_itlb_miss) + DBG_FAULT(3) mov r16=cr.ifa // get address that caused the TLB miss - movl r17=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX + movl r17=PAGE_KERNEL mov r21=cr.ipsr mov r31=pr ;; #ifdef CONFIG_DISABLE_VHPT shr.u r22=r16,61 // get the region number into r21 ;; - cmp.gt p8,p0=6,r22 // user mode + cmp.gt p8,p0=6,r22 // user mode ;; (p8) thash r17=r16 ;; (p8) mov cr.iha=r17 +(p8) mov r29=b0 // save b0 (p8) br.cond.dptk.many itlb_fault #endif extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl @@ -277,13 +304,15 @@ itc.i r19 // insert the TLB entry mov pr=r31,-1 rfi - ;; +END(alt_itlb_miss) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x1000 Entry 4 (size 64 bundles) Alt DTLB (7,46) +ENTRY(alt_dtlb_miss) + DBG_FAULT(4) mov r16=cr.ifa // get address that caused the TLB miss - movl r17=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX + movl r17=PAGE_KERNEL mov r20=cr.isr mov r21=cr.ipsr mov r31=pr @@ -296,6 +325,7 @@ (p8) thash r17=r16 ;; (p8) mov cr.iha=r17 +(p8) mov r29=b0 // save b0 (p8) br.cond.dptk.many dtlb_fault #endif extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl @@ -316,70 +346,63 @@ (p7) itc.d r19 // insert the TLB entry mov pr=r31,-1 rfi - ;; +END(alt_dtlb_miss) //----------------------------------------------------------------------------------- // call do_page_fault (predicates are in r31, psr.dt may be off, r16 is faulting address) -page_fault: +ENTRY(page_fault) ssm psr.dt ;; srlz.i ;; SAVE_MIN_WITH_COVER - // - // Copy control registers to temporary registers, then turn on psr bits, - // then copy the temporary regs to the output regs. We have to do this - // because the "alloc" can cause a mandatory store which could lead to - // an "Alt DTLB" fault which we can handle only if psr.ic is on. - // - mov r8=cr.ifa - mov r9=cr.isr + alloc r15=ar.pfs,0,0,3,0 + mov out0=cr.ifa + mov out1=cr.isr adds r3=8,r2 // set up second base pointer ;; - ssm psr.ic + ssm psr.ic | PSR_DEFAULT_BITS ;; srlz.i // guarantee that interrupt collection is enabled ;; (p15) ssm psr.i // restore psr.i movl r14=ia64_leave_kernel ;; - alloc r15=ar.pfs,0,0,3,0 // must be first in insn group - mov out0=r8 - mov out1=r9 - ;; SAVE_REST mov rp=r14 ;; adds out2=16,r12 // out2 = pointer to pt_regs br.call.sptk.many b6=ia64_do_page_fault // ignore return address - ;; +END(page_fault) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x1400 Entry 5 (size 64 bundles) Data nested TLB (6,45) - // - // In the absence of kernel bugs, we get here when the virtually mapped linear page - // table is accessed non-speculatively (e.g., in the Dirty-bit, Instruction - // Access-bit, or Data Access-bit faults). If the DTLB entry for the virtual page - // table is missing, a nested TLB miss fault is triggered and control is transferred - // to this point. When this happens, we lookup the pte for the faulting address - // by walking the page table in physical mode and return to the continuation point - // passed in register r30 (or call page_fault if the address is not mapped). - // - // Input: r16: faulting address - // r29: saved b0 - // r30: continuation address - // r31: saved pr - // - // Output: r17: physical address of L3 PTE of faulting address - // r29: saved b0 - // r30: continuation address - // r31: saved pr - // - // Clobbered: b0, r18, r19, r21, psr.dt (cleared) - // +ENTRY(nested_dtlb_miss) + /* + * In the absence of kernel bugs, we get here when the virtually mapped linear + * page table is accessed non-speculatively (e.g., in the Dirty-bit, Instruction + * Access-bit, or Data Access-bit faults). If the DTLB entry for the virtual page + * table is missing, a nested TLB miss fault is triggered and control is + * transferred to this point. When this happens, we lookup the pte for the + * faulting address by walking the page table in physical mode and return to the + * continuation point passed in register r30 (or call page_fault if the address is + * not mapped). + * + * Input: r16: faulting address + * r29: saved b0 + * r30: continuation address + * r31: saved pr + * + * Output: r17: physical address of L3 PTE of faulting address + * r29: saved b0 + * r30: continuation address + * r31: saved pr + * + * Clobbered: b0, r18, r19, r21, psr.dt (cleared) + */ rsm psr.dt // switch to using physical data addressing - mov r19=ar.k7 // get the page table base address + mov r19=IA64_KR(PT_BASE) // get the page table base address shl r21=r16,3 // shift bit 60 into sign bit ;; shr.u r17=r16,61 // get the region number into r17 @@ -399,7 +422,6 @@ shr.u r18=r16,PMD_SHIFT // shift L2 index into position ;; ld8 r17=[r17] // fetch the L1 entry (may be 0) - mov b0=r30 ;; (p7) cmp.eq p6,p7=r17,r0 // was L1 entry NULL? dep r17=r18,r17,3,(PAGE_SHIFT-3) // compute address of L2 page table entry @@ -409,34 +431,41 @@ ;; (p7) cmp.eq.or.andcm p6,p7=r17,r0 // was L2 entry NULL? dep r17=r19,r17,3,(PAGE_SHIFT-3) // compute address of L3 page table entry - ;; (p6) br.cond.spnt.many page_fault + mov b0=r30 br.sptk.many b0 // return to continuation point - ;; +END(nested_dtlb_miss) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x1800 Entry 6 (size 64 bundles) Instruction Key Miss (24) +ENTRY(ikey_miss) + DBG_FAULT(6) FAULT(6) +END(ikey_miss) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51) +ENTRY(dkey_miss) + DBG_FAULT(7) FAULT(7) +END(dkey_miss) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x2000 Entry 8 (size 64 bundles) Dirty-bit (54) - // - // What we do here is to simply turn on the dirty bit in the PTE. We need - // to update both the page-table and the TLB entry. To efficiently access - // the PTE, we address it through the virtual page table. Most likely, the - // TLB entry for the relevant virtual page table page is still present in - // the TLB so we can normally do this without additional TLB misses. - // In case the necessary virtual page table TLB entry isn't present, we take - // a nested TLB miss hit where we look up the physical address of the L3 PTE - // and then continue at label 1 below. - // +ENTRY(dirty_bit) + DBG_FAULT(8) + /* + * What we do here is to simply turn on the dirty bit in the PTE. We need to + * update both the page-table and the TLB entry. To efficiently access the PTE, + * we address it through the virtual page table. Most likely, the TLB entry for + * the relevant virtual page table page is still present in the TLB so we can + * normally do this without additional TLB misses. In case the necessary virtual + * page table TLB entry isn't present, we take a nested TLB miss hit where we look + * up the physical address of the L3 PTE and then continue at label 1 below. + */ mov r16=cr.ifa // get the address that caused the fault movl r30=1f // load continuation point in case of nested fault ;; @@ -477,11 +506,13 @@ #endif mov pr=r31,-1 // restore pr rfi - ;; +END(idirty_bit) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x2400 Entry 9 (size 64 bundles) Instruction Access-bit (27) +ENTRY(iaccess_bit) + DBG_FAULT(9) // Like Entry 8, except for instruction access mov r16=cr.ifa // get the address that caused the fault movl r30=1f // load continuation point in case of nested fault @@ -504,14 +535,14 @@ mov r28=ar.ccv // save ar.ccv ;; 1: ld8 r18=[r17] + ;; # if defined(CONFIG_IA32_SUPPORT) && \ (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_B0_SPECIFIC)) - // - // Erratum 85 (Access bit fault could be reported before page not present fault) - // If the PTE is indicates the page is not present, then just turn this into a - // page fault. - // - ;; + /* + * Erratum 85 (Access bit fault could be reported before page not present fault) + * If the PTE is indicates the page is not present, then just turn this into a + * page fault. + */ tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? (p6) br.sptk page_fault // page wasn't present # endif @@ -538,11 +569,11 @@ ;; # if defined(CONFIG_IA32_SUPPORT) && \ (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_B0_SPECIFIC)) - // - // Erratum 85 (Access bit fault could be reported before page not present fault) - // If the PTE is indicates the page is not present, then just turn this into a - // page fault. - // + /* + * Erratum 85 (Access bit fault could be reported before page not present fault) + * If the PTE is indicates the page is not present, then just turn this into a + * page fault. + */ tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? (p6) br.sptk page_fault // page wasn't present # endif @@ -554,11 +585,13 @@ #endif /* !CONFIG_SMP */ mov pr=r31,-1 rfi - ;; +END(iaccess_bit) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x2800 Entry 10 (size 64 bundles) Data Access-bit (15,55) +ENTRY(daccess_bit) + DBG_FAULT(10) // Like Entry 8, except for data access mov r16=cr.ifa // get the address that caused the fault movl r30=1f // load continuation point in case of nested fault @@ -599,11 +632,13 @@ mov b0=r29 // restore b0 mov pr=r31,-1 rfi - ;; +END(daccess_bit) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x2c00 Entry 11 (size 64 bundles) Break instruction (33) +ENTRY(break_fault) + DBG_FAULT(11) mov r16=cr.iim mov r17=__IA64_BREAK_SYSCALL mov r31=pr // prepare to save predicates @@ -613,8 +648,7 @@ SAVE_MIN // uses r31; defines r2: - // turn interrupt collection back on: - ssm psr.ic + ssm psr.ic | PSR_DEFAULT_BITS ;; srlz.i // guarantee that interrupt collection is enabled cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 @@ -667,12 +701,12 @@ ;; st8 [r16]=r18 // store new value for cr.isr -(p8) br.call.sptk.many b6=b6 // ignore this return addr +(p8) br.call.sptk.many b6=b6 // ignore this return addr br.call.sptk.many rp=ia64_trace_syscall // rp will be overwritten (ignored) // NOT REACHED +END(break_fault) - .proc demine_args -demine_args: +ENTRY(demine_args) alloc r2=ar.pfs,8,0,0,0 tnat.nz p8,p0=in0 tnat.nz p9,p0=in1 @@ -696,16 +730,18 @@ (p14) mov in6=-1 (p15) mov in7=-1 br.ret.sptk.many rp - .endp demine_args +END(demine_args) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x3000 Entry 12 (size 64 bundles) External Interrupt (4) +ENTRY(interrupt) + DBG_FAULT(12) mov r31=pr // prepare to save predicates ;; SAVE_MIN_WITH_COVER // uses r31; defines r2 and r3 - ssm psr.ic // turn interrupt collection + ssm psr.ic | PSR_DEFAULT_BITS ;; adds r3=8,r2 // set up second base pointer for SAVE_REST srlz.i // ensure everybody knows psr.ic is back on @@ -721,41 +757,38 @@ ;; mov rp=r14 br.call.sptk.many b6=ia64_handle_irq - ;; +END(interrupt) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x3400 Entry 13 (size 64 bundles) Reserved + DBG_FAULT(13) FAULT(13) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x3800 Entry 14 (size 64 bundles) Reserved + DBG_FAULT(14) FAULT(14) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x3c00 Entry 15 (size 64 bundles) Reserved + DBG_FAULT(15) FAULT(15) -// -// Squatting in this space ... -// -// This special case dispatcher for illegal operation faults -// allows preserved registers to be modified through a -// callback function (asm only) that is handed back from -// the fault handler in r8. Up to three arguments can be -// passed to the callback function by returning an aggregate -// with the callback as its first element, followed by the -// arguments. -// -dispatch_illegal_op_fault: + /* + * Squatting in this space ... + * + * This special case dispatcher for illegal operation faults allows preserved + * registers to be modified through a callback function (asm only) that is handed + * back from the fault handler in r8. Up to three arguments can be passed to the + * callback function by returning an aggregate with the callback as its first + * element, followed by the arguments. + */ +ENTRY(dispatch_illegal_op_fault) SAVE_MIN_WITH_COVER - // - // The "alloc" can cause a mandatory store which could lead to - // an "Alt DTLB" fault which we can handle only if psr.ic is on. - // - ssm psr.ic + ssm psr.ic | PSR_DEFAULT_BITS ;; srlz.i // guarantee that interrupt collection is enabled ;; @@ -781,27 +814,30 @@ cmp.ne p6,p0=0,r8 (p6) br.call.dpnt b6=b6 // call returns to ia64_leave_kernel br.sptk ia64_leave_kernel - ;; +END(dispatch_illegal_op_fault) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x4000 Entry 16 (size 64 bundles) Reserved + DBG_FAULT(16) FAULT(16) #ifdef CONFIG_IA32_SUPPORT - // There is no particular reason for this code to be here, other than that - // there happens to be space here that would go unused otherwise. If this - // fault ever gets "unreserved", simply moved the following code to a more - // suitable spot... + /* + * There is no particular reason for this code to be here, other than that + * there happens to be space here that would go unused otherwise. If this + * fault ever gets "unreserved", simply moved the following code to a more + * suitable spot... + */ // IA32 interrupt entry point -dispatch_to_ia32_handler: +ENTRY(dispatch_to_ia32_handler) SAVE_MIN ;; mov r14=cr.isr - ssm psr.ic + ssm psr.ic | PSR_DEFAULT_BITS ;; srlz.i // guarantee that interrupt collection is enabled ;; @@ -812,7 +848,7 @@ ;; mov r15=0x80 shr r14=r14,16 // Get interrupt number - ;; + ;; cmp.ne p6,p0=r14,r15 (p6) br.call.dpnt.many b6=non_ia32_syscall @@ -823,7 +859,7 @@ st8 [r15]=r8 // save orignal EAX in r1 (IA32 procs don't use the GP) ;; alloc r15=ar.pfs,0,0,6,0 // must first in an insn group - ;; + ;; ld4 r8=[r14],8 // r8 == EAX (syscall number) mov r15=222 // sys_vfork - last implemented system call ;; @@ -842,10 +878,10 @@ ;; ld4 out4=[r14] // R15 == edi movl r16=ia32_syscall_table - ;; + ;; (p6) shladd r16=r8,3,r16 // Force ni_syscall if not valid syscall number ld8 r2=[r2] // r2 = current->ptrace - ;; + ;; ld8 r16=[r16] tbit.z p8,p0=r2,PT_TRACESYS_BIT // (current->ptrace & PT_TRACESYS) == 0? ;; @@ -857,7 +893,7 @@ ;; br.call.sptk.many rp=ia32_trace_syscall // rp will be overwritten (ignored) -non_ia32_syscall: +non_ia32_syscall: alloc r15=ar.pfs,0,0,2,0 mov out0=r14 // interrupt # add out1=16,sp // pointer to pt_regs @@ -867,16 +903,17 @@ ;; mov rp=r15 br.ret.sptk.many rp - ;; +END(dispatch_to_ia32_handler) #endif /* CONFIG_IA32_SUPPORT */ .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x4400 Entry 17 (size 64 bundles) Reserved + DBG_FAULT(17) FAULT(17) -non_syscall: +ENTRY(non_syscall) SAVE_MIN_WITH_COVER // There is no particular reason for this code to be here, other than that @@ -884,49 +921,45 @@ // fault ever gets "unreserved", simply moved the following code to a more // suitable spot... - mov r8=cr.iim // get break immediate (must be done while psr.ic is off) + alloc r14=ar.pfs,0,0,2,0 + mov out0=cr.iim + add out1=16,sp adds r3=8,r2 // set up second base pointer for SAVE_REST - // turn interrupt collection back on: - ssm psr.ic + ssm psr.ic | PSR_DEFAULT_BITS ;; srlz.i // guarantee that interrupt collection is enabled ;; (p15) ssm psr.i // restore psr.i movl r15=ia64_leave_kernel ;; - alloc r14=ar.pfs,0,0,2,0 - mov out0=r8 // break number - add out1=16,sp // pointer to pt_regs - ;; SAVE_REST mov rp=r15 ;; br.call.sptk.many b6=ia64_bad_break // avoid WAW on CFM and ignore return addr - ;; +END(non_syscall) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x4800 Entry 18 (size 64 bundles) Reserved + DBG_FAULT(18) FAULT(18) - // There is no particular reason for this code to be here, other than that - // there happens to be space here that would go unused otherwise. If this - // fault ever gets "unreserved", simply moved the following code to a more - // suitable spot... + /* + * There is no particular reason for this code to be here, other than that + * there happens to be space here that would go unused otherwise. If this + * fault ever gets "unreserved", simply moved the following code to a more + * suitable spot... + */ -dispatch_unaligned_handler: +ENTRY(dispatch_unaligned_handler) SAVE_MIN_WITH_COVER ;; - // - // we can't have the alloc while psr.ic is cleared because - // we might get a mandatory RSE (when you reach the end of the - // rotating partition when doing the alloc) spill which could cause - // a page fault on the kernel virtual address and the handler - // wouldn't get the state to recover. - // - mov r15=cr.ifa - ssm psr.ic + alloc r14=ar.pfs,0,0,2,0 // now it's safe (must be first in insn group!) + mov out0=cr.ifa + adds out1=16,sp + + ssm psr.ic | PSR_DEFAULT_BITS ;; srlz.i // guarantee that interrupt collection is enabled ;; @@ -934,66 +967,53 @@ adds r3=8,r2 // set up second base pointer ;; SAVE_REST - ;; - alloc r14=ar.pfs,0,0,2,0 // now it's safe (must be first in insn group!) - ;; // avoid WAW on r14 movl r14=ia64_leave_kernel - mov out0=r15 // out0 = faulting address - adds out1=16,sp // out1 = pointer to pt_regs ;; mov rp=r14 br.sptk.many ia64_prepare_handle_unaligned - ;; +END(dispatch_unaligned_handler) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x4c00 Entry 19 (size 64 bundles) Reserved + DBG_FAULT(19) FAULT(19) - // There is no particular reason for this code to be here, other than that - // there happens to be space here that would go unused otherwise. If this - // fault ever gets "unreserved", simply moved the following code to a more - // suitable spot... + /* + * There is no particular reason for this code to be here, other than that + * there happens to be space here that would go unused otherwise. If this + * fault ever gets "unreserved", simply moved the following code to a more + * suitable spot... + */ -dispatch_to_fault_handler: - // - // Input: - // psr.ic: off - // r19: fault vector number (e.g., 24 for General Exception) - // r31: contains saved predicates (pr) - // +ENTRY(dispatch_to_fault_handler) + /* + * Input: + * psr.ic: off + * r19: fault vector number (e.g., 24 for General Exception) + * r31: contains saved predicates (pr) + */ SAVE_MIN_WITH_COVER_R19 - // - // Copy control registers to temporary registers, then turn on psr bits, - // then copy the temporary regs to the output regs. We have to do this - // because the "alloc" can cause a mandatory store which could lead to - // an "Alt DTLB" fault which we can handle only if psr.ic is on. - // - mov r8=cr.isr - mov r9=cr.ifa - mov r10=cr.iim - mov r11=cr.itir + alloc r14=ar.pfs,0,0,5,0 + mov out0=r15 + mov out1=cr.isr + mov out2=cr.ifa + mov out3=cr.iim + mov out4=cr.itir ;; - ssm psr.ic + ssm psr.ic | PSR_DEFAULT_BITS ;; srlz.i // guarantee that interrupt collection is enabled ;; (p15) ssm psr.i // restore psr.i adds r3=8,r2 // set up second base pointer for SAVE_REST ;; - alloc r14=ar.pfs,0,0,5,0 // must be first in insn group - mov out0=r15 - mov out1=r8 - mov out2=r9 - mov out3=r10 - mov out4=r11 - ;; SAVE_REST movl r14=ia64_leave_kernel ;; mov rp=r14 br.call.sptk.many b6=ia64_fault - ;; +END(dispatch_to_fault_handler) // // --- End of long entries, Beginning of short entries @@ -1002,55 +1022,67 @@ .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5000 Entry 20 (size 16 bundles) Page Not Present (10,22,49) +ENTRY(page_not_present) + DBG_FAULT(20) mov r16=cr.ifa rsm psr.dt - // The Linux page fault handler doesn't expect non-present pages to be in - // the TLB. Flush the existing entry now, so we meet that expectation. - mov r17=_PAGE_SIZE_4K<<2 + /* + * The Linux page fault handler doesn't expect non-present pages to be in + * the TLB. Flush the existing entry now, so we meet that expectation. + */ + mov r17=PAGE_SHIFT<<2 ;; ptc.l r16,r17 ;; mov r31=pr srlz.d br.sptk.many page_fault - ;; +END(page_not_present) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5100 Entry 21 (size 16 bundles) Key Permission (13,25,52) +ENTRY(key_permission) + DBG_FAULT(21) mov r16=cr.ifa rsm psr.dt mov r31=pr ;; srlz.d br.sptk.many page_fault - ;; +END(key_permission) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5200 Entry 22 (size 16 bundles) Instruction Access Rights (26) +ENTRY(iaccess_rights) + DBG_FAULT(22) mov r16=cr.ifa rsm psr.dt mov r31=pr ;; srlz.d br.sptk.many page_fault - ;; +END(iaccess_rights) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5300 Entry 23 (size 16 bundles) Data Access Rights (14,53) +ENTRY(daccess_rights) + DBG_FAULT(23) mov r16=cr.ifa rsm psr.dt mov r31=pr ;; srlz.d br.sptk.many page_fault - ;; +END(daccess_rights) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5400 Entry 24 (size 16 bundles) General Exception (5,32,34,36,38,39) +ENTRY(general_exception) + DBG_FAULT(24) mov r16=cr.isr mov r31=pr ;; @@ -1059,39 +1091,44 @@ ;; mov r19=24 // fault number br.sptk.many dispatch_to_fault_handler - ;; +END(general_exception) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5500 Entry 25 (size 16 bundles) Disabled FP-Register (35) +ENTRY(disabled_fp_reg) + DBG_FAULT(25) rsm psr.dfh // ensure we can access fph ;; srlz.d mov r31=pr mov r19=25 br.sptk.many dispatch_to_fault_handler - ;; +END(disabled_fp_reg) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5600 Entry 26 (size 16 bundles) Nat Consumption (11,23,37,50) +ENTRY(nat_consumption) + DBG_FAULT(26) FAULT(26) +END(nat_consumption) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5700 Entry 27 (size 16 bundles) Speculation (40) - // - // A [f]chk.[as] instruction needs to take the branch to - // the recovery code but this part of the architecture is - // not implemented in hardware on some CPUs, such as Itanium. - // Thus, in general we need to emulate the behavior. - // IIM contains the relative target (not yet sign extended). - // So after sign extending it we simply add it to IIP. - // We also need to reset the EI field of the IPSR to zero, - // i.e., the slot to restart into. - // - // cr.imm contains zero_ext(imm21) - // +ENTRY(speculation_vector) + DBG_FAULT(27) + /* + * A [f]chk.[as] instruction needs to take the branch to the recovery code but + * this part of the architecture is not implemented in hardware on some CPUs, such + * as Itanium. Thus, in general we need to emulate the behavior. IIM contains + * the relative target (not yet sign extended). So after sign extending it we + * simply add it to IIP. We also need to reset the EI field of the IPSR to zero, + * i.e., the slot to restart into. + * + * cr.imm contains zero_ext(imm21) + */ mov r18=cr.iim ;; mov r17=cr.iip @@ -1112,105 +1149,130 @@ ;; rfi // and go back - ;; +END(speculation_vector) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5800 Entry 28 (size 16 bundles) Reserved + DBG_FAULT(28) FAULT(28) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5900 Entry 29 (size 16 bundles) Debug (16,28,56) +ENTRY(debug_vector) + DBG_FAULT(29) FAULT(29) +END(debug_vector) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5a00 Entry 30 (size 16 bundles) Unaligned Reference (57) +ENTRY(unaligned_access) + DBG_FAULT(30) mov r16=cr.ipsr mov r31=pr // prepare to save predicates - ;; - br.sptk.many dispatch_unaligned_handler ;; + br.sptk.many dispatch_unaligned_handler +END(unaligned_access) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5b00 Entry 31 (size 16 bundles) Unsupported Data Reference (57) + DBG_FAULT(31) FAULT(31) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5c00 Entry 32 (size 16 bundles) Floating-Point Fault (64) + DBG_FAULT(32) FAULT(32) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5d00 Entry 33 (size 16 bundles) Floating Point Trap (66) + DBG_FAULT(33) FAULT(33) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5e00 Entry 34 (size 16 bundles) Lower Privilege Tranfer Trap (66) + DBG_FAULT(34) FAULT(34) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5f00 Entry 35 (size 16 bundles) Taken Branch Trap (68) + DBG_FAULT(35) FAULT(35) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6000 Entry 36 (size 16 bundles) Single Step Trap (69) + DBG_FAULT(36) FAULT(36) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6100 Entry 37 (size 16 bundles) Reserved + DBG_FAULT(37) FAULT(37) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6200 Entry 38 (size 16 bundles) Reserved + DBG_FAULT(38) FAULT(38) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6300 Entry 39 (size 16 bundles) Reserved + DBG_FAULT(39) FAULT(39) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6400 Entry 40 (size 16 bundles) Reserved + DBG_FAULT(40) FAULT(40) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6500 Entry 41 (size 16 bundles) Reserved + DBG_FAULT(41) FAULT(41) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6600 Entry 42 (size 16 bundles) Reserved + DBG_FAULT(42) FAULT(42) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6700 Entry 43 (size 16 bundles) Reserved + DBG_FAULT(43) FAULT(43) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6800 Entry 44 (size 16 bundles) Reserved + DBG_FAULT(44) FAULT(44) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6900 Entry 45 (size 16 bundles) IA-32 Exeception (17,18,29,41,42,43,44,58,60,61,62,72,73,75,76,77) +ENTRY(ia32_exception) + DBG_FAULT(45) FAULT(45) +END(ia32_exception) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6a00 Entry 46 (size 16 bundles) IA-32 Intercept (30,31,59,70,71) +ENTRY(ia32_intercept) + DBG_FAULT(46) #ifdef CONFIG_IA32_SUPPORT mov r31=pr mov r16=cr.isr @@ -1219,129 +1281,152 @@ mov r18=ar.eflag mov r19=cr.iim // old eflag value ;; - cmp.ne p2,p0=2,r17 -(p2) br.cond.spnt 1f // not a system flag fault + cmp.ne p6,p0=2,r17 +(p6) br.cond.spnt 1f // not a system flag fault xor r16=r18,r19 ;; extr.u r17=r16,18,1 // get the eflags.ac bit ;; - cmp.eq p2,p0=0,r17 -(p2) br.cond.spnt 1f // eflags.ac bit didn't change + cmp.eq p6,p0=0,r17 +(p6) br.cond.spnt 1f // eflags.ac bit didn't change ;; mov pr=r31,-1 // restore predicate registers rfi - ;; + 1: #endif // CONFIG_IA32_SUPPORT FAULT(46) +END(ia32_intercept) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6b00 Entry 47 (size 16 bundles) IA-32 Interrupt (74) +ENTRY(ia32_interrupt) + DBG_FAULT(47) #ifdef CONFIG_IA32_SUPPORT mov r31=pr br.sptk.many dispatch_to_ia32_handler - ;; #else FAULT(47) #endif +END(ia32_interrupt) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6c00 Entry 48 (size 16 bundles) Reserved + DBG_FAULT(48) FAULT(48) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6d00 Entry 49 (size 16 bundles) Reserved + DBG_FAULT(49) FAULT(49) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6e00 Entry 50 (size 16 bundles) Reserved + DBG_FAULT(50) FAULT(50) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6f00 Entry 51 (size 16 bundles) Reserved + DBG_FAULT(51) FAULT(51) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7000 Entry 52 (size 16 bundles) Reserved + DBG_FAULT(52) FAULT(52) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7100 Entry 53 (size 16 bundles) Reserved + DBG_FAULT(53) FAULT(53) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7200 Entry 54 (size 16 bundles) Reserved + DBG_FAULT(54) FAULT(54) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7300 Entry 55 (size 16 bundles) Reserved + DBG_FAULT(55) FAULT(55) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7400 Entry 56 (size 16 bundles) Reserved + DBG_FAULT(56) FAULT(56) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7500 Entry 57 (size 16 bundles) Reserved + DBG_FAULT(57) FAULT(57) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7600 Entry 58 (size 16 bundles) Reserved + DBG_FAULT(58) FAULT(58) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7700 Entry 59 (size 16 bundles) Reserved + DBG_FAULT(59) FAULT(59) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7800 Entry 60 (size 16 bundles) Reserved + DBG_FAULT(60) FAULT(60) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7900 Entry 61 (size 16 bundles) Reserved + DBG_FAULT(61) FAULT(61) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7a00 Entry 62 (size 16 bundles) Reserved + DBG_FAULT(62) FAULT(62) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7b00 Entry 63 (size 16 bundles) Reserved + DBG_FAULT(63) FAULT(63) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7c00 Entry 64 (size 16 bundles) Reserved + DBG_FAULT(64) FAULT(64) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7d00 Entry 65 (size 16 bundles) Reserved + DBG_FAULT(65) FAULT(65) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7e00 Entry 66 (size 16 bundles) Reserved + DBG_FAULT(66) FAULT(66) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7f00 Entry 67 (size 16 bundles) Reserved + DBG_FAULT(67) FAULT(67) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/mca.c linux.ac/arch/ia64/kernel/mca.c --- linux.vanilla/arch/ia64/kernel/mca.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/kernel/mca.c Sat Apr 14 01:18:00 2001 @@ -1,16 +1,16 @@ /* - * File: mca.c - * Purpose: Generic MCA handling layer + * File: mca.c + * Purpose: Generic MCA handling layer * * Updated for latest kernel * Copyright (C) 2000 Intel * Copyright (C) Chuck Fleckenstein (cfleck@co.intel.com) - * + * * Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) Vijay Chander(vijay@engr.sgi.com) * - * 00/03/29 C. Fleckenstein Fixed PAL/SAL update issues, began MCA bug fixes, logging issues, - * added min save state dump, added INIT handler. + * 00/03/29 C. Fleckenstein Fixed PAL/SAL update issues, began MCA bug fixes, logging issues, + * added min save state dump, added INIT handler. */ #include <linux/config.h> #include <linux/types.h> @@ -28,7 +28,7 @@ #include <asm/irq.h> - + typedef struct ia64_fptr { unsigned long fp; unsigned long gp; @@ -43,8 +43,8 @@ u64 ia64_mca_bspstore[1024]; u64 ia64_init_stack[INIT_TASK_SIZE] __attribute__((aligned(16))); -static void ia64_mca_cmc_vector_setup(int enable, - int_vector_t cmc_vector); +static void ia64_mca_cmc_vector_setup(int enable, + int_vector_t cmc_vector); static void ia64_mca_wakeup_ipi_wait(void); static void ia64_mca_wakeup(int cpu); static void ia64_mca_wakeup_all(void); @@ -77,7 +77,7 @@ * console, then we would call the appropriate debug hooks here. */ void -init_handler_platform (struct pt_regs *regs) +init_handler_platform (struct pt_regs *regs) { /* if a kernel debugger is available call it here else just dump the registers */ show_regs(regs); /* dump the state info */ @@ -87,7 +87,7 @@ log_print_platform ( void *cur_buff_ptr, prfunc_t prfunc) { } - + void ia64_mca_init_platform (void) { @@ -131,7 +131,7 @@ tpmss_ptr++; /* skip to next entry */ continue; } - } + } printk("%5s=0x%16.16lx ",min_state_labels[i],*tpmss_ptr++); @@ -142,7 +142,7 @@ /* hang city for now, until we include debugger or copy to ptregs to show: */ while (1); } - + /* * ia64_mca_cmc_vector_setup * Setup the correctable machine check vector register in the processor @@ -154,14 +154,14 @@ * None */ static void -ia64_mca_cmc_vector_setup(int enable, - int_vector_t cmc_vector) +ia64_mca_cmc_vector_setup(int enable, + int_vector_t cmc_vector) { cmcv_reg_t cmcv; - cmcv.cmcv_regval = 0; - cmcv.cmcv_mask = enable; - cmcv.cmcv_vector = cmc_vector; + cmcv.cmcv_regval = 0; + cmcv.cmcv_mask = enable; + cmcv.cmcv_vector = cmc_vector; ia64_set_cmcv(cmcv.cmcv_regval); } @@ -223,25 +223,27 @@ for(i = 0 ; i < IA64_MAXCPUS; i++) ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; - /* NOTE : The actual irqs for the rendez, wakeup and + /* NOTE : The actual irqs for the rendez, wakeup and * cmc interrupts are requested in the platform-specific * mca initialization code. */ - /* + /* * Register the rendezvous spinloop and wakeup mechanism with SAL */ /* Register the rendezvous interrupt vector with SAL */ if (ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT, SAL_MC_PARAM_MECHANISM_INT, - IA64_MCA_RENDEZ_INT_VECTOR, - IA64_MCA_RENDEZ_TIMEOUT)) + IA64_MCA_RENDEZ_VECTOR, + IA64_MCA_RENDEZ_TIMEOUT, + 0)) return; /* Register the wakeup interrupt vector with SAL */ if (ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP, SAL_MC_PARAM_MECHANISM_INT, - IA64_MCA_WAKEUP_INT_VECTOR, + IA64_MCA_WAKEUP_VECTOR, + 0, 0)) return; @@ -249,17 +251,16 @@ /* * Setup the correctable machine check vector */ - ia64_mca_cmc_vector_setup(IA64_CMC_INT_ENABLE, - IA64_MCA_CMC_INT_VECTOR); + ia64_mca_cmc_vector_setup(IA64_CMC_INT_ENABLE, IA64_CMC_VECTOR); IA64_MCA_DEBUG("ia64_mca_init : correctable mca vector setup done\n"); - ia64_mc_info.imi_mca_handler = __pa(ia64_os_mca_dispatch); + ia64_mc_info.imi_mca_handler = __pa(ia64_os_mca_dispatch); /* * XXX - disable SAL checksum by setting size to 0; should be * __pa(ia64_os_mca_dispatch_end) - __pa(ia64_os_mca_dispatch); */ - ia64_mc_info.imi_mca_handler_size = 0; + ia64_mc_info.imi_mca_handler_size = 0; /* Register the os mca handler with SAL */ if (ia64_sal_set_vectors(SAL_VECTOR_OS_MCA, ia64_mc_info.imi_mca_handler, @@ -271,13 +272,13 @@ IA64_MCA_DEBUG("ia64_mca_init : registered os mca handler with SAL\n"); - /* + /* * XXX - disable SAL checksum by setting size to 0, should be - * IA64_INIT_HANDLER_SIZE + * IA64_INIT_HANDLER_SIZE */ - ia64_mc_info.imi_monarch_init_handler = __pa(mon_init_ptr->fp); + ia64_mc_info.imi_monarch_init_handler = __pa(mon_init_ptr->fp); ia64_mc_info.imi_monarch_init_handler_size = 0; - ia64_mc_info.imi_slave_init_handler = __pa(slave_init_ptr->fp); + ia64_mc_info.imi_slave_init_handler = __pa(slave_init_ptr->fp); ia64_mc_info.imi_slave_init_handler_size = 0; IA64_MCA_DEBUG("ia64_mca_init : os init handler at %lx\n",ia64_mc_info.imi_monarch_init_handler); @@ -296,7 +297,7 @@ IA64_MCA_DEBUG("ia64_mca_init : registered os init handler with SAL\n"); - /* Initialize the areas set aside by the OS to buffer the + /* Initialize the areas set aside by the OS to buffer the * platform/processor error states for MCA/INIT/CMC * handling. */ @@ -308,7 +309,7 @@ ia64_log_init(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PLATFORM); ia64_mca_init_platform(); - + IA64_MCA_DEBUG("ia64_mca_init : platform-specific mca handling setup done\n"); #if defined(MCA_TEST) @@ -321,9 +322,9 @@ /* * ia64_mca_wakeup_ipi_wait * Wait for the inter-cpu interrupt to be sent by the - * monarch processor once it is done with handling the + * monarch processor once it is done with handling the * MCA. - * Inputs + * Inputs * None * Outputs * None @@ -331,8 +332,8 @@ void ia64_mca_wakeup_ipi_wait(void) { - int irr_num = (IA64_MCA_WAKEUP_INT_VECTOR >> 6); - int irr_bit = (IA64_MCA_WAKEUP_INT_VECTOR & 0x3f); + int irr_num = (IA64_MCA_WAKEUP_VECTOR >> 6); + int irr_bit = (IA64_MCA_WAKEUP_VECTOR & 0x3f); u64 irr = 0; do { @@ -356,7 +357,7 @@ /* * ia64_mca_wakeup * Send an inter-cpu interrupt to wake-up a particular cpu - * and mark that cpu to be out of rendez. + * and mark that cpu to be out of rendez. * Inputs * cpuid * Outputs @@ -365,9 +366,8 @@ void ia64_mca_wakeup(int cpu) { - platform_send_ipi(cpu, IA64_MCA_WAKEUP_INT_VECTOR, IA64_IPI_DM_INT, 0); + platform_send_ipi(cpu, IA64_MCA_WAKEUP_VECTOR, IA64_IPI_DM_INT, 0); ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; - } /* * ia64_mca_wakeup_all @@ -390,10 +390,10 @@ } /* * ia64_mca_rendez_interrupt_handler - * This is handler used to put slave processors into spinloop + * This is handler used to put slave processors into spinloop * while the monarch processor does the mca handling and later * wake each slave up once the monarch is done. - * Inputs + * Inputs * None * Outputs * None @@ -403,7 +403,7 @@ { int flags, cpu = 0; /* Mask all interrupts */ - save_and_cli(flags); + save_and_cli(flags); #ifdef CONFIG_SMP cpu = cpu_logical_id(hard_smp_processor_id()); @@ -414,7 +414,7 @@ */ ia64_sal_mc_rendez(); - /* Wait for the wakeup IPI from the monarch + /* Wait for the wakeup IPI from the monarch * This waiting is done by polling on the wakeup-interrupt * vector bit in the processor's IRRs */ @@ -430,30 +430,30 @@ /* * ia64_mca_wakeup_int_handler * The interrupt handler for processing the inter-cpu interrupt to the - * slave cpu which was spinning in the rendez loop. + * slave cpu which was spinning in the rendez loop. * Since this spinning is done by turning off the interrupts and - * polling on the wakeup-interrupt bit in the IRR, there is + * polling on the wakeup-interrupt bit in the IRR, there is * nothing useful to be done in the handler. * Inputs * wakeup_irq (Wakeup-interrupt bit) * arg (Interrupt handler specific argument) * ptregs (Exception frame at the time of the interrupt) * Outputs - * + * */ void ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg, struct pt_regs *ptregs) { - + } /* * ia64_return_to_sal_check * This is function called before going back from the OS_MCA handler - * to the OS_MCA dispatch code which finally takes the control back - * to the SAL. + * to the OS_MCA dispatch code which finally takes the control back + * to the SAL. * The main purpose of this routine is to setup the OS_MCA to SAL - * return state which can be used by the OS_MCA dispatch code + * return state which can be used by the OS_MCA dispatch code * just before going back to SAL. * Inputs * None @@ -467,16 +467,16 @@ /* Copy over some relevant stuff from the sal_to_os_mca_handoff * so that it can be used at the time of os_mca_to_sal_handoff */ - ia64_os_to_sal_handoff_state.imots_sal_gp = + ia64_os_to_sal_handoff_state.imots_sal_gp = ia64_sal_to_os_handoff_state.imsto_sal_gp; - ia64_os_to_sal_handoff_state.imots_sal_check_ra = + ia64_os_to_sal_handoff_state.imots_sal_check_ra = ia64_sal_to_os_handoff_state.imsto_sal_check_ra; /* For now ignore the MCA */ ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_CORRECTED; } -/* +/* * ia64_mca_ucmc_handler * This is uncorrectable machine check handler called from OS_MCA * dispatch code which is in turn called from SAL_CHECK(). @@ -503,7 +503,7 @@ ia64_log_print(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); - /* + /* * Do some error handling - Platform-specific mca handler is called at this point */ @@ -520,11 +520,11 @@ ia64_return_to_sal_check(); } -/* +/* * ia64_mca_cmc_int_handler * This is correctable machine check interrupt handler. * Right now the logs are extracted and displayed in a well-defined - * format. + * format. * Inputs * None * Outputs @@ -532,7 +532,7 @@ */ void ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs) -{ +{ /* Get the CMC processor log */ ia64_log_get(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); /* Get the CMC platform log */ @@ -543,8 +543,7 @@ cmci_handler_platform(cmc_irq, arg, ptregs); /* Clear the CMC SAL logs now that they have been saved in the OS buffer */ - ia64_sal_clear_state_info(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR); - ia64_sal_clear_state_info(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PLATFORM); + ia64_sal_clear_state_info(SAL_INFO_TYPE_CMC); } /* @@ -563,17 +562,17 @@ static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES][IA64_MAX_LOG_SUBTYPES]; #define IA64_LOG_LOCK_INIT(it, sit) spin_lock_init(&ia64_state_log[it][sit].isl_lock) -#define IA64_LOG_LOCK(it, sit) spin_lock_irqsave(&ia64_state_log[it][sit].isl_lock, s) -#define IA64_LOG_UNLOCK(it, sit) spin_unlock_irqrestore(&ia64_state_log[it][sit].isl_lock,\ +#define IA64_LOG_LOCK(it, sit) spin_lock_irqsave(&ia64_state_log[it][sit].isl_lock, s) +#define IA64_LOG_UNLOCK(it, sit) spin_unlock_irqrestore(&ia64_state_log[it][sit].isl_lock,\ s) #define IA64_LOG_NEXT_INDEX(it, sit) ia64_state_log[it][sit].isl_index -#define IA64_LOG_CURR_INDEX(it, sit) 1 - ia64_state_log[it][sit].isl_index +#define IA64_LOG_CURR_INDEX(it, sit) 1 - ia64_state_log[it][sit].isl_index #define IA64_LOG_INDEX_INC(it, sit) \ ia64_state_log[it][sit].isl_index = 1 - ia64_state_log[it][sit].isl_index #define IA64_LOG_INDEX_DEC(it, sit) \ ia64_state_log[it][sit].isl_index = 1 - ia64_state_log[it][sit].isl_index -#define IA64_LOG_NEXT_BUFFER(it, sit) (void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_NEXT_INDEX(it,sit)])) -#define IA64_LOG_CURR_BUFFER(it, sit) (void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_CURR_INDEX(it,sit)])) +#define IA64_LOG_NEXT_BUFFER(it, sit) (void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_NEXT_INDEX(it,sit)])) +#define IA64_LOG_CURR_BUFFER(it, sit) (void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_CURR_INDEX(it,sit)])) /* * C portion of the OS INIT handler @@ -582,7 +581,7 @@ * * Inputs: pointer to pt_regs where processor info was saved. * - * Returns: + * Returns: * 0 if SAL must warm boot the System * 1 if SAL must retrun to interrupted context using PAL_MC_RESUME * @@ -601,49 +600,48 @@ /* Get the INIT platform log */ ia64_log_get(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PLATFORM, (prfunc_t)printk); -#ifdef IA64_DUMP_ALL_PROC_INFO +#ifdef IA64_DUMP_ALL_PROC_INFO ia64_log_print(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); -#endif +#endif - /* + /* * get pointer to min state save area * */ plog_ptr=(ia64_psilog_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR); proc_ptr = &plog_ptr->devlog.proclog; - + ia64_process_min_state_save(&proc_ptr->slpi_min_state_area,regs); init_handler_platform(regs); /* call platform specific routines */ /* Clear the INIT SAL logs now that they have been saved in the OS buffer */ - ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR); - ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PLATFORM); + ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT); } /* * ia64_log_init - * Reset the OS ia64 log buffer - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) + * Reset the OS ia64 log buffer + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM}) - * Outputs : None + * Outputs : None */ void ia64_log_init(int sal_info_type, int sal_sub_info_type) { IA64_LOG_LOCK_INIT(sal_info_type, sal_sub_info_type); IA64_LOG_NEXT_INDEX(sal_info_type, sal_sub_info_type) = 0; - memset(IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type), 0, + memset(IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type), 0, sizeof(ia64_psilog_t) * IA64_MAX_LOGS); } -/* +/* * ia64_log_get - * Get the current MCA log from SAL and copy it into the OS log buffer. - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) + * Get the current MCA log from SAL and copy it into the OS log buffer. + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM}) - * Outputs : None + * Outputs : None * */ void @@ -658,7 +656,7 @@ /* Get the process state information */ log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type); - if (!(total_len=ia64_sal_get_state_info(sal_info_type, sal_sub_info_type ,(u64 *)log_buffer))) + if (!(total_len=ia64_sal_get_state_info(sal_info_type,(u64 *)log_buffer))) prfunc("ia64_mca_log_get : Getting processor log failed\n"); IA64_MCA_DEBUG("ia64_log_get: retrieved %d bytes of error information\n",total_len); @@ -669,21 +667,21 @@ } -/* +/* * ia64_log_clear - * Clear the current MCA log from SAL and dpending on the clear_os_buffer flags + * Clear the current MCA log from SAL and dpending on the clear_os_buffer flags * clear the OS log buffer also - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM}) - * clear_os_buffer + * clear_os_buffer * prfunc (print function) - * Outputs : None + * Outputs : None * */ void ia64_log_clear(int sal_info_type, int sal_sub_info_type, int clear_os_buffer, prfunc_t prfunc) { - if (ia64_sal_clear_state_info(sal_info_type, sal_sub_info_type)) + if (ia64_sal_clear_state_info(sal_info_type)) prfunc("ia64_mca_log_get : Clearing processor log failed\n"); if (clear_os_buffer) { @@ -698,7 +696,7 @@ memset(log_buffer, 0, sizeof(ia64_psilog_t)); IA64_LOG_INDEX_DEC(sal_info_type, sal_sub_info_type); - + IA64_LOG_UNLOCK(sal_info_type, sal_sub_info_type); } @@ -708,19 +706,19 @@ * ia64_log_processor_regs_print * Print the contents of the saved processor register(s) in the format * <reg_prefix>[<index>] <value> - * - * Inputs : regs (Register save buffer) - * reg_num (# of registers) + * + * Inputs : regs (Register save buffer) + * reg_num (# of registers) * reg_class (application/banked/control/bank1_general) * reg_prefix (ar/br/cr/b1_gr) - * Outputs : None + * Outputs : None * */ void -ia64_log_processor_regs_print(u64 *regs, - int reg_num, - char *reg_class, - char *reg_prefix, +ia64_log_processor_regs_print(u64 *regs, + int reg_num, + char *reg_class, + char *reg_prefix, prfunc_t prfunc) { int i; @@ -756,14 +754,14 @@ * ia64_log_cache_check_info_print * Display the machine check information related to cache error(s). * Inputs : i (Multiple errors are logged, i - index of logged error) - * info (Machine check info logged by the PAL and later + * info (Machine check info logged by the PAL and later * captured by the SAL) * target_addr (Address which caused the cache error) - * Outputs : None + * Outputs : None */ -void -ia64_log_cache_check_info_print(int i, - pal_cache_check_info_t info, +void +ia64_log_cache_check_info_print(int i, + pal_cache_check_info_t info, u64 target_addr, prfunc_t prfunc) { @@ -794,13 +792,13 @@ * ia64_log_tlb_check_info_print * Display the machine check information related to tlb error(s). * Inputs : i (Multiple errors are logged, i - index of logged error) - * info (Machine check info logged by the PAL and later + * info (Machine check info logged by the PAL and later * captured by the SAL) - * Outputs : None + * Outputs : None */ void -ia64_log_tlb_check_info_print(int i, +ia64_log_tlb_check_info_print(int i, pal_tlb_check_info_t info, prfunc_t prfunc) { @@ -826,16 +824,16 @@ * ia64_log_bus_check_info_print * Display the machine check information related to bus error(s). * Inputs : i (Multiple errors are logged, i - index of logged error) - * info (Machine check info logged by the PAL and later + * info (Machine check info logged by the PAL and later * captured by the SAL) * req_addr (Address of the requestor of the transaction) * resp_addr (Address of the responder of the transaction) * target_addr (Address where the data was to be delivered to or * obtained from) - * Outputs : None + * Outputs : None */ void -ia64_log_bus_check_info_print(int i, +ia64_log_bus_check_info_print(int i, pal_bus_check_info_t info, u64 req_addr, u64 resp_addr, @@ -868,9 +866,9 @@ * ia64_log_processor_info_print * Display the processor-specific information logged by PAL as a part * of MCA or INIT or CMC. - * Inputs : lh (Pointer of the sal log header which specifies the format + * Inputs : lh (Pointer of the sal log header which specifies the format * of SAL state info as specified by the SAL spec). - * Outputs : None + * Outputs : None */ void ia64_log_processor_info_print(sal_log_header_t *lh, prfunc_t prfunc) @@ -892,29 +890,29 @@ } /* Print branch register contents if valid */ - if (slpi->slpi_valid.slpi_br) + if (slpi->slpi_valid.slpi_br) ia64_log_processor_regs_print(slpi->slpi_br, 8, "Branch", "br", prfunc); /* Print control register contents if valid */ - if (slpi->slpi_valid.slpi_cr) + if (slpi->slpi_valid.slpi_cr) ia64_log_processor_regs_print(slpi->slpi_cr, 128, "Control", "cr", prfunc); /* Print application register contents if valid */ - if (slpi->slpi_valid.slpi_ar) + if (slpi->slpi_valid.slpi_ar) ia64_log_processor_regs_print(slpi->slpi_br, 128, "Application", "ar", prfunc); /* Print region register contents if valid */ - if (slpi->slpi_valid.slpi_rr) + if (slpi->slpi_valid.slpi_rr) ia64_log_processor_regs_print(slpi->slpi_rr, 8, "Region", "rr", prfunc); /* Print floating-point register contents if valid */ - if (slpi->slpi_valid.slpi_fr) - ia64_log_processor_regs_print(slpi->slpi_fr, 128, "Floating-point", "fr", + if (slpi->slpi_valid.slpi_fr) + ia64_log_processor_regs_print(slpi->slpi_fr, 128, "Floating-point", "fr", prfunc); /* Print the cache check information if any*/ for (i = 0 ; i < MAX_CACHE_ERRORS; i++) - ia64_log_cache_check_info_print(i, + ia64_log_cache_check_info_print(i, slpi->slpi_cache_check_info[i].slpi_cache_check, slpi->slpi_cache_check_info[i].slpi_target_address, prfunc); @@ -924,7 +922,7 @@ /* Print the bus check information if any*/ for (i = 0 ; i < MAX_BUS_ERRORS; i++) - ia64_log_bus_check_info_print(i, + ia64_log_bus_check_info_print(i, slpi->slpi_bus_check_info[i].slpi_bus_check, slpi->slpi_bus_check_info[i].slpi_requestor_addr, slpi->slpi_bus_check_info[i].slpi_responder_addr, @@ -935,15 +933,15 @@ /* * ia64_log_print - * Display the contents of the OS error log information - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) + * Display the contents of the OS error log information + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM}) - * Outputs : None + * Outputs : None */ void ia64_log_print(int sal_info_type, int sal_sub_info_type, prfunc_t prfunc) { - char *info_type, *sub_info_type; + char *info_type, *sub_info_type; switch(sal_info_type) { case SAL_INFO_TYPE_MCA: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/mca_asm.S linux.ac/arch/ia64/kernel/mca_asm.S --- linux.vanilla/arch/ia64/kernel/mca_asm.S Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/kernel/mca_asm.S Tue Apr 10 18:08:40 2001 @@ -1,4 +1,4 @@ -// +// // assembly portion of the IA64 MCA handling // // Mods by cfleck to integrate into kernel build @@ -8,6 +8,7 @@ // kstack, switch modes, jump to C INIT handler // #include <linux/config.h> + #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/mca_asm.h> @@ -17,13 +18,9 @@ * When we get an machine check, the kernel stack pointer is no longer * valid, so we need to set a new stack pointer. */ -#define MINSTATE_PHYS /* Make sure stack access is physical for MINSTATE */ +#define MINSTATE_PHYS /* Make sure stack access is physical for MINSTATE */ #include "minstate.h" - - .psr abi64 - .psr lsb - .lsb /* * SAL_TO_OS_MCA_HANDOFF_STATE @@ -35,26 +32,26 @@ * 6. GR12 = Return address to location within SAL_CHECK */ #define SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(_tmp) \ - movl _tmp=ia64_sal_to_os_handoff_state;; \ - st8 [_tmp]=r1,0x08;; \ - st8 [_tmp]=r8,0x08;; \ - st8 [_tmp]=r9,0x08;; \ - st8 [_tmp]=r10,0x08;; \ - st8 [_tmp]=r11,0x08;; \ - st8 [_tmp]=r12,0x08;; + movl _tmp=ia64_sal_to_os_handoff_state;; \ + st8 [_tmp]=r1,0x08;; \ + st8 [_tmp]=r8,0x08;; \ + st8 [_tmp]=r9,0x08;; \ + st8 [_tmp]=r10,0x08;; \ + st8 [_tmp]=r11,0x08;; \ + st8 [_tmp]=r12,0x08;; /* * OS_MCA_TO_SAL_HANDOFF_STATE * 1. GR8 = OS_MCA status * 2. GR9 = SAL GP (physical) * 3. GR22 = New min state save area pointer - */ + */ #define OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(_tmp) \ - movl _tmp=ia64_os_to_sal_handoff_state;; \ + movl _tmp=ia64_os_to_sal_handoff_state;; \ DATA_VA_TO_PA(_tmp);; \ - ld8 r8=[_tmp],0x08;; \ - ld8 r9=[_tmp],0x08;; \ - ld8 r22=[_tmp],0x08;; + ld8 r8=[_tmp],0x08;; \ + ld8 r9=[_tmp],0x08;; \ + ld8 r22=[_tmp],0x08;; /* * BRANCH @@ -65,9 +62,9 @@ * "ip" is the address of the instruction * located at "from_label". * "temp" is a scratch register like r2 - * "adjust" needed for HP compiler. + * "adjust" needed for HP compiler. * A screwup somewhere with constant arithmetic. - */ + */ #define BRANCH(to_label, temp, p, adjust) \ 100: (p) mov temp=ip; \ ;; \ @@ -76,7 +73,7 @@ (p) adds temp=adjust,temp; \ ;; \ (p) mov b1=temp ; \ - (p) br b1 + (p) br b1 .global ia64_os_mca_dispatch .global ia64_os_mca_dispatch_end @@ -88,11 +85,11 @@ .global ia64_mca_stack .global ia64_mca_stackframe .global ia64_mca_bspstore - .global ia64_init_stack - + .global ia64_init_stack + .text .align 16 - + ia64_os_mca_dispatch: #if defined(MCA_TEST) @@ -114,23 +111,23 @@ ;; begin_os_mca_dump: BRANCH(ia64_os_mca_proc_state_dump, r2, p0, 0x0) - ;; + ;; ia64_os_mca_done_dump: - // Setup new stack frame for OS_MCA handling - movl r2=ia64_mca_bspstore // local bspstore area location in r2 - movl r3=ia64_mca_stackframe // save stack frame to memory in r3 - rse_switch_context(r6,r3,r2);; // RSC management in this new context - movl r12=ia64_mca_stack;; + // Setup new stack frame for OS_MCA handling + movl r2=ia64_mca_bspstore // local bspstore area location in r2 + movl r3=ia64_mca_stackframe // save stack frame to memory in r3 + rse_switch_context(r6,r3,r2);; // RSC management in this new context + movl r12=ia64_mca_stack;; // Enter virtual mode from physical mode VIRTUAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_begin, r4) ia64_os_mca_virtual_begin: // call our handler - movl r2=ia64_mca_ucmc_handler;; - mov b6=r2;; - br.call.sptk.few b0=b6 + movl r2=ia64_mca_ucmc_handler;; + mov b6=r2;; + br.call.sptk.few b0=b6 .ret0: // Revert back to physical mode before going back to SAL PHYSICAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_end, r4) @@ -144,42 +141,36 @@ #endif /* #if defined(MCA_TEST) */ // restore the original stack frame here - movl r2=ia64_mca_stackframe // restore stack frame from memory at r2 + movl r2=ia64_mca_stackframe // restore stack frame from memory at r2 ;; DATA_VA_TO_PA(r2) - movl r4=IA64_PSR_MC + movl r4=IA64_PSR_MC ;; - rse_return_context(r4,r3,r2) // switch from interrupt context for RSE - + rse_return_context(r4,r3,r2) // switch from interrupt context for RSE + // let us restore all the registers from our PSI structure - mov r8=gp + mov r8=gp ;; begin_os_mca_restore: BRANCH(ia64_os_mca_proc_state_restore, r2, p0, 0x0) - ;; + ;; ia64_os_mca_done_restore: ;; -#ifdef SOFTSDV - VIRTUAL_MODE_ENTER(r2,r3, vmode_enter, r4) -vmode_enter: - br.ret.sptk.few b0 -#else // branch back to SALE_CHECK OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(r2) - ld8 r3=[r2];; - mov b0=r3 // SAL_CHECK return address - br b0 - ;; -#endif /* #ifdef SOFTSDV */ -ia64_os_mca_dispatch_end: + ld8 r3=[r2];; + mov b0=r3 // SAL_CHECK return address + br b0 + ;; +ia64_os_mca_dispatch_end: //EndMain////////////////////////////////////////////////////////////////////// //++ // Name: // ia64_os_mca_proc_state_dump() -// +// // Stub Description: // // This stub dumps the processor state during MCHK to a data area @@ -188,223 +179,223 @@ ia64_os_mca_proc_state_dump: // Get and save GR0-31 from Proc. Min. State Save Area to SAL PSI - movl r2=ia64_mca_proc_state_dump;; // Os state dump area + movl r2=ia64_mca_proc_state_dump;; // Os state dump area -// save ar.NaT - mov r5=ar.unat // ar.unat +// save ar.NaT + mov r5=ar.unat // ar.unat // save banked GRs 16-31 along with NaT bits - bsw.1;; - st8.spill [r2]=r16,8;; - st8.spill [r2]=r17,8;; - st8.spill [r2]=r18,8;; - st8.spill [r2]=r19,8;; - st8.spill [r2]=r20,8;; - st8.spill [r2]=r21,8;; - st8.spill [r2]=r22,8;; - st8.spill [r2]=r23,8;; - st8.spill [r2]=r24,8;; - st8.spill [r2]=r25,8;; - st8.spill [r2]=r26,8;; - st8.spill [r2]=r27,8;; - st8.spill [r2]=r28,8;; - st8.spill [r2]=r29,8;; - st8.spill [r2]=r30,8;; - st8.spill [r2]=r31,8;; - - mov r4=ar.unat;; - st8 [r2]=r4,8 // save User NaT bits for r16-r31 - mov ar.unat=r5 // restore original unat - bsw.0;; + bsw.1;; + st8.spill [r2]=r16,8;; + st8.spill [r2]=r17,8;; + st8.spill [r2]=r18,8;; + st8.spill [r2]=r19,8;; + st8.spill [r2]=r20,8;; + st8.spill [r2]=r21,8;; + st8.spill [r2]=r22,8;; + st8.spill [r2]=r23,8;; + st8.spill [r2]=r24,8;; + st8.spill [r2]=r25,8;; + st8.spill [r2]=r26,8;; + st8.spill [r2]=r27,8;; + st8.spill [r2]=r28,8;; + st8.spill [r2]=r29,8;; + st8.spill [r2]=r30,8;; + st8.spill [r2]=r31,8;; + + mov r4=ar.unat;; + st8 [r2]=r4,8 // save User NaT bits for r16-r31 + mov ar.unat=r5 // restore original unat + bsw.0;; //save BRs - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2 // duplicate r2 in r4 + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2 // duplicate r2 in r4 - mov r3=b0 - mov r5=b1 - mov r7=b2;; - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=b3 - mov r5=b4 - mov r7=b5;; - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=b6 - mov r5=b7;; - st8 [r2]=r3,2*8 - st8 [r4]=r5,2*8;; + mov r3=b0 + mov r5=b1 + mov r7=b2;; + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=b3 + mov r5=b4 + mov r7=b5;; + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=b6 + mov r5=b7;; + st8 [r2]=r3,2*8 + st8 [r4]=r5,2*8;; cSaveCRs: // save CRs - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2 // duplicate r2 in r4 + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2 // duplicate r2 in r4 - mov r3=cr0 // cr.dcr - mov r5=cr1 // cr.itm - mov r7=cr2;; // cr.iva - - st8 [r2]=r3,8*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; // 48 byte rements + mov r3=cr0 // cr.dcr + mov r5=cr1 // cr.itm + mov r7=cr2;; // cr.iva + + st8 [r2]=r3,8*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; // 48 byte rements - mov r3=cr8;; // cr.pta - st8 [r2]=r3,8*8;; // 64 byte rements + mov r3=cr8;; // cr.pta + st8 [r2]=r3,8*8;; // 64 byte rements // if PSR.ic=0, reading interruption registers causes an illegal operation fault - mov r3=psr;; - tbit.nz.unc p2,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test -(p2) st8 [r2]=r0,9*8+160 // increment by 168 byte inc. -begin_skip_intr_regs: - BRANCH(SkipIntrRegs, r9, p2, 0x0) - ;; - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2 // duplicate r2 in r6 - - mov r3=cr16 // cr.ipsr - mov r5=cr17 // cr.isr - mov r7=r0;; // cr.ida => cr18 - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=cr19 // cr.iip - mov r5=cr20 // cr.idtr - mov r7=cr21;; // cr.iitr - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=cr22 // cr.iipa - mov r5=cr23 // cr.ifs - mov r7=cr24;; // cr.iim - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=cr25;; // cr.iha - st8 [r2]=r3,160;; // 160 byte rement + mov r3=psr;; + tbit.nz.unc p6,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test +(p6) st8 [r2]=r0,9*8+160 // increment by 168 byte inc. +begin_skip_intr_regs: + BRANCH(SkipIntrRegs, r9, p6, 0x0) + ;; + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2 // duplicate r2 in r6 + + mov r3=cr16 // cr.ipsr + mov r5=cr17 // cr.isr + mov r7=r0;; // cr.ida => cr18 + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=cr19 // cr.iip + mov r5=cr20 // cr.idtr + mov r7=cr21;; // cr.iitr + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=cr22 // cr.iipa + mov r5=cr23 // cr.ifs + mov r7=cr24;; // cr.iim + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=cr25;; // cr.iha + st8 [r2]=r3,160;; // 160 byte rement SkipIntrRegs: - st8 [r2]=r0,168 // another 168 byte . + st8 [r2]=r0,168 // another 168 byte . - mov r3=cr66;; // cr.lid - st8 [r2]=r3,40 // 40 byte rement + mov r3=cr66;; // cr.lid + st8 [r2]=r3,40 // 40 byte rement - mov r3=cr71;; // cr.ivr - st8 [r2]=r3,8 + mov r3=cr71;; // cr.ivr + st8 [r2]=r3,8 - mov r3=cr72;; // cr.tpr - st8 [r2]=r3,24 // 24 byte increment - - mov r3=r0;; // cr.eoi => cr75 - st8 [r2]=r3,168 // 168 byte inc. - - mov r3=r0;; // cr.irr0 => cr96 - st8 [r2]=r3,16 // 16 byte inc. + mov r3=cr72;; // cr.tpr + st8 [r2]=r3,24 // 24 byte increment - mov r3=r0;; // cr.irr1 => cr98 - st8 [r2]=r3,16 // 16 byte inc. + mov r3=r0;; // cr.eoi => cr75 + st8 [r2]=r3,168 // 168 byte inc. - mov r3=r0;; // cr.irr2 => cr100 - st8 [r2]=r3,16 // 16 byte inc + mov r3=r0;; // cr.irr0 => cr96 + st8 [r2]=r3,16 // 16 byte inc. - mov r3=r0;; // cr.irr3 => cr100 - st8 [r2]=r3,16 // 16b inc. + mov r3=r0;; // cr.irr1 => cr98 + st8 [r2]=r3,16 // 16 byte inc. - mov r3=r0;; // cr.itv => cr114 - st8 [r2]=r3,16 // 16 byte inc. + mov r3=r0;; // cr.irr2 => cr100 + st8 [r2]=r3,16 // 16 byte inc - mov r3=r0;; // cr.pmv => cr116 - st8 [r2]=r3,8 + mov r3=r0;; // cr.irr3 => cr100 + st8 [r2]=r3,16 // 16b inc. - mov r3=r0;; // cr.lrr0 => cr117 - st8 [r2]=r3,8 + mov r3=r0;; // cr.itv => cr114 + st8 [r2]=r3,16 // 16 byte inc. - mov r3=r0;; // cr.lrr1 => cr118 - st8 [r2]=r3,8 + mov r3=r0;; // cr.pmv => cr116 + st8 [r2]=r3,8 - mov r3=r0;; // cr.cmcv => cr119 - st8 [r2]=r3,8*10;; + mov r3=r0;; // cr.lrr0 => cr117 + st8 [r2]=r3,8 + + mov r3=r0;; // cr.lrr1 => cr118 + st8 [r2]=r3,8 + + mov r3=r0;; // cr.cmcv => cr119 + st8 [r2]=r3,8*10;; cSaveARs: // save ARs - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2 // duplicate r2 in r6 + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2 // duplicate r2 in r6 - mov r3=ar0 // ar.kro - mov r5=ar1 // ar.kr1 - mov r7=ar2;; // ar.kr2 - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=ar3 // ar.kr3 - mov r5=ar4 // ar.kr4 - mov r7=ar5;; // ar.kr5 - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=ar6 // ar.kr6 - mov r5=ar7 // ar.kr7 - mov r7=r0;; // ar.kr8 - st8 [r2]=r3,10*8 - st8 [r4]=r5,10*8 - st8 [r6]=r7,10*8;; // rement by 72 bytes + mov r3=ar0 // ar.kro + mov r5=ar1 // ar.kr1 + mov r7=ar2;; // ar.kr2 + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=ar3 // ar.kr3 + mov r5=ar4 // ar.kr4 + mov r7=ar5;; // ar.kr5 + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=ar6 // ar.kr6 + mov r5=ar7 // ar.kr7 + mov r7=r0;; // ar.kr8 + st8 [r2]=r3,10*8 + st8 [r4]=r5,10*8 + st8 [r6]=r7,10*8;; // rement by 72 bytes - mov r3=ar16 // ar.rsc + mov r3=ar16 // ar.rsc mov ar16=r0 // put RSE in enforced lazy mode - mov r5=ar17 // ar.bsp + mov r5=ar17 // ar.bsp ;; - mov r7=ar18;; // ar.bspstore - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; + mov r7=ar18;; // ar.bspstore + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; - mov r3=ar19;; // ar.rnat - st8 [r2]=r3,8*13 // increment by 13x8 bytes + mov r3=ar19;; // ar.rnat + st8 [r2]=r3,8*13 // increment by 13x8 bytes - mov r3=ar32;; // ar.ccv - st8 [r2]=r3,8*4 + mov r3=ar32;; // ar.ccv + st8 [r2]=r3,8*4 - mov r3=ar36;; // ar.unat - st8 [r2]=r3,8*4 + mov r3=ar36;; // ar.unat + st8 [r2]=r3,8*4 - mov r3=ar40;; // ar.fpsr - st8 [r2]=r3,8*4 + mov r3=ar40;; // ar.fpsr + st8 [r2]=r3,8*4 - mov r3=ar44;; // ar.itc - st8 [r2]=r3,160 // 160 + mov r3=ar44;; // ar.itc + st8 [r2]=r3,160 // 160 - mov r3=ar64;; // ar.pfs - st8 [r2]=r3,8 + mov r3=ar64;; // ar.pfs + st8 [r2]=r3,8 - mov r3=ar65;; // ar.lc - st8 [r2]=r3,8 + mov r3=ar65;; // ar.lc + st8 [r2]=r3,8 + + mov r3=ar66;; // ar.ec + st8 [r2]=r3 + add r2=8*62,r2 //padding - mov r3=ar66;; // ar.ec - st8 [r2]=r3 - add r2=8*62,r2 //padding - // save RRs - mov ar.lc=0x08-1 - movl r4=0x00;; + mov ar.lc=0x08-1 + movl r4=0x00;; cStRR: - mov r3=rr[r4];; - st8 [r2]=r3,8 - add r4=1,r4 - br.cloop.sptk.few cStRR - ;; + mov r3=rr[r4];; + st8 [r2]=r3,8 + add r4=1,r4 + br.cloop.sptk.few cStRR + ;; end_os_mca_dump: BRANCH(ia64_os_mca_done_dump, r2, p0, -0x10) - ;; + ;; //EndStub////////////////////////////////////////////////////////////////////// @@ -412,7 +403,7 @@ //++ // Name: // ia64_os_mca_proc_state_restore() -// +// // Stub Description: // // This is a stub to restore the saved processor state during MCHK @@ -421,225 +412,225 @@ ia64_os_mca_proc_state_restore: -// Restore bank1 GR16-31 +// Restore bank1 GR16-31 movl r2=ia64_mca_proc_state_dump // Convert virtual address ;; // of OS state dump area DATA_VA_TO_PA(r2) // to physical address ;; restore_GRs: // restore bank-1 GRs 16-31 - bsw.1;; - add r3=16*8,r2;; // to get to NaT of GR 16-31 - ld8 r3=[r3];; - mov ar.unat=r3;; // first restore NaT - - ld8.fill r16=[r2],8;; - ld8.fill r17=[r2],8;; - ld8.fill r18=[r2],8;; - ld8.fill r19=[r2],8;; - ld8.fill r20=[r2],8;; - ld8.fill r21=[r2],8;; - ld8.fill r22=[r2],8;; - ld8.fill r23=[r2],8;; - ld8.fill r24=[r2],8;; - ld8.fill r25=[r2],8;; - ld8.fill r26=[r2],8;; - ld8.fill r27=[r2],8;; - ld8.fill r28=[r2],8;; - ld8.fill r29=[r2],8;; - ld8.fill r30=[r2],8;; - ld8.fill r31=[r2],8;; + bsw.1;; + add r3=16*8,r2;; // to get to NaT of GR 16-31 + ld8 r3=[r3];; + mov ar.unat=r3;; // first restore NaT + + ld8.fill r16=[r2],8;; + ld8.fill r17=[r2],8;; + ld8.fill r18=[r2],8;; + ld8.fill r19=[r2],8;; + ld8.fill r20=[r2],8;; + ld8.fill r21=[r2],8;; + ld8.fill r22=[r2],8;; + ld8.fill r23=[r2],8;; + ld8.fill r24=[r2],8;; + ld8.fill r25=[r2],8;; + ld8.fill r26=[r2],8;; + ld8.fill r27=[r2],8;; + ld8.fill r28=[r2],8;; + ld8.fill r29=[r2],8;; + ld8.fill r30=[r2],8;; + ld8.fill r31=[r2],8;; - ld8 r3=[r2],8;; // increment to skip NaT - bsw.0;; + ld8 r3=[r2],8;; // increment to skip NaT + bsw.0;; restore_BRs: - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2;; // duplicate r2 in r4 + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2;; // duplicate r2 in r4 - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov b0=r3 - mov b1=r5 - mov b2=r7;; - - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov b3=r3 - mov b4=r5 - mov b5=r7;; - - ld8 r3=[r2],2*8 - ld8 r5=[r4],2*8;; - mov b6=r3 - mov b7=r5;; + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov b0=r3 + mov b1=r5 + mov b2=r7;; + + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov b3=r3 + mov b4=r5 + mov b5=r7;; + + ld8 r3=[r2],2*8 + ld8 r5=[r4],2*8;; + mov b6=r3 + mov b7=r5;; restore_CRs: - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2;; // duplicate r2 in r4 + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2;; // duplicate r2 in r4 - ld8 r3=[r2],8*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; // 48 byte increments - mov cr0=r3 // cr.dcr - mov cr1=r5 // cr.itm - mov cr2=r7;; // cr.iva + ld8 r3=[r2],8*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; // 48 byte increments + mov cr0=r3 // cr.dcr + mov cr1=r5 // cr.itm + mov cr2=r7;; // cr.iva - ld8 r3=[r2],8*8;; // 64 byte increments + ld8 r3=[r2],8*8;; // 64 byte increments // mov cr8=r3 // cr.pta // if PSR.ic=1, reading interruption registers causes an illegal operation fault - mov r3=psr;; - tbit.nz.unc p2,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test -(p2) st8 [r2]=r0,9*8+160 // increment by 160 byte inc. - -begin_rskip_intr_regs: - BRANCH(rSkipIntrRegs, r9, p2, 0x0) - ;; - - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2;; // duplicate r2 in r4 - - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov cr16=r3 // cr.ipsr - mov cr17=r5 // cr.isr is read only + mov r3=psr;; + tbit.nz.unc p6,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test +(p6) st8 [r2]=r0,9*8+160 // increment by 160 byte inc. + +begin_rskip_intr_regs: + BRANCH(rSkipIntrRegs, r9, p6, 0x0) + ;; + + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2;; // duplicate r2 in r4 + + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov cr16=r3 // cr.ipsr + mov cr17=r5 // cr.isr is read only // mov cr18=r7;; // cr.ida - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov cr19=r3 // cr.iip - mov cr20=r5 // cr.idtr - mov cr21=r7;; // cr.iitr - - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov cr22=r3 // cr.iipa - mov cr23=r5 // cr.ifs - mov cr24=r7 // cr.iim + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov cr19=r3 // cr.iip + mov cr20=r5 // cr.idtr + mov cr21=r7;; // cr.iitr + + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov cr22=r3 // cr.iipa + mov cr23=r5 // cr.ifs + mov cr24=r7 // cr.iim - ld8 r3=[r2],160;; // 160 byte increment - mov cr25=r3 // cr.iha + ld8 r3=[r2],160;; // 160 byte increment + mov cr25=r3 // cr.iha rSkipIntrRegs: - ld8 r3=[r2],168;; // another 168 byte inc. + ld8 r3=[r2],168;; // another 168 byte inc. - ld8 r3=[r2],40;; // 40 byte increment - mov cr66=r3 // cr.lid + ld8 r3=[r2],40;; // 40 byte increment + mov cr66=r3 // cr.lid - ld8 r3=[r2],8;; + ld8 r3=[r2],8;; // mov cr71=r3 // cr.ivr is read only - ld8 r3=[r2],24;; // 24 byte increment - mov cr72=r3 // cr.tpr - - ld8 r3=[r2],168;; // 168 byte inc. + ld8 r3=[r2],24;; // 24 byte increment + mov cr72=r3 // cr.tpr + + ld8 r3=[r2],168;; // 168 byte inc. // mov cr75=r3 // cr.eoi - - ld8 r3=[r2],16;; // 16 byte inc. + + ld8 r3=[r2],16;; // 16 byte inc. // mov cr96=r3 // cr.irr0 is read only - ld8 r3=[r2],16;; // 16 byte inc. + ld8 r3=[r2],16;; // 16 byte inc. // mov cr98=r3 // cr.irr1 is read only - ld8 r3=[r2],16;; // 16 byte inc + ld8 r3=[r2],16;; // 16 byte inc // mov cr100=r3 // cr.irr2 is read only - ld8 r3=[r2],16;; // 16b inc. + ld8 r3=[r2],16;; // 16b inc. // mov cr102=r3 // cr.irr3 is read only - ld8 r3=[r2],16;; // 16 byte inc. + ld8 r3=[r2],16;; // 16 byte inc. // mov cr114=r3 // cr.itv - ld8 r3=[r2],8;; + ld8 r3=[r2],8;; // mov cr116=r3 // cr.pmv - ld8 r3=[r2],8;; + ld8 r3=[r2],8;; // mov cr117=r3 // cr.lrr0 - ld8 r3=[r2],8;; + ld8 r3=[r2],8;; // mov cr118=r3 // cr.lrr1 - ld8 r3=[r2],8*10;; + ld8 r3=[r2],8*10;; // mov cr119=r3 // cr.cmcv restore_ARs: - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2;; // duplicate r2 in r4 + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2;; // duplicate r2 in r4 - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov ar0=r3 // ar.kro - mov ar1=r5 // ar.kr1 - mov ar2=r7;; // ar.kr2 - - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov ar3=r3 // ar.kr3 - mov ar4=r5 // ar.kr4 - mov ar5=r7;; // ar.kr5 - - ld8 r3=[r2],10*8 - ld8 r5=[r4],10*8 - ld8 r7=[r6],10*8;; - mov ar6=r3 // ar.kr6 - mov ar7=r5 // ar.kr7 + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov ar0=r3 // ar.kro + mov ar1=r5 // ar.kr1 + mov ar2=r7;; // ar.kr2 + + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov ar3=r3 // ar.kr3 + mov ar4=r5 // ar.kr4 + mov ar5=r7;; // ar.kr5 + + ld8 r3=[r2],10*8 + ld8 r5=[r4],10*8 + ld8 r7=[r6],10*8;; + mov ar6=r3 // ar.kr6 + mov ar7=r5 // ar.kr7 // mov ar8=r6 // ar.kr8 - ;; + ;; - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; // mov ar16=r3 // ar.rsc // mov ar17=r5 // ar.bsp is read only mov ar16=r0 // make sure that RSE is in enforced lazy mode ;; - mov ar18=r7;; // ar.bspstore + mov ar18=r7;; // ar.bspstore - ld8 r9=[r2],8*13;; - mov ar19=r9 // ar.rnat + ld8 r9=[r2],8*13;; + mov ar19=r9 // ar.rnat mov ar16=r3 // ar.rsc - ld8 r3=[r2],8*4;; - mov ar32=r3 // ar.ccv + ld8 r3=[r2],8*4;; + mov ar32=r3 // ar.ccv - ld8 r3=[r2],8*4;; - mov ar36=r3 // ar.unat + ld8 r3=[r2],8*4;; + mov ar36=r3 // ar.unat - ld8 r3=[r2],8*4;; - mov ar40=r3 // ar.fpsr + ld8 r3=[r2],8*4;; + mov ar40=r3 // ar.fpsr - ld8 r3=[r2],160;; // 160 + ld8 r3=[r2],160;; // 160 // mov ar44=r3 // ar.itc - ld8 r3=[r2],8;; - mov ar64=r3 // ar.pfs + ld8 r3=[r2],8;; + mov ar64=r3 // ar.pfs + + ld8 r3=[r2],8;; + mov ar65=r3 // ar.lc - ld8 r3=[r2],8;; - mov ar65=r3 // ar.lc + ld8 r3=[r2];; + mov ar66=r3 // ar.ec + add r2=8*62,r2;; // padding - ld8 r3=[r2];; - mov ar66=r3 // ar.ec - add r2=8*62,r2;; // padding - restore_RRs: - mov r5=ar.lc - mov ar.lc=0x08-1 - movl r4=0x00 + mov r5=ar.lc + mov ar.lc=0x08-1 + movl r4=0x00 cStRRr: - ld8 r3=[r2],8;; + ld8 r3=[r2],8;; // mov rr[r4]=r3 // what are its access previledges? - add r4=1,r4 - br.cloop.sptk.few cStRRr - ;; - mov ar.lc=r5 + add r4=1,r4 + br.cloop.sptk.few cStRRr + ;; + mov ar.lc=r5 ;; end_os_mca_restore: BRANCH(ia64_os_mca_done_restore, r2, p0, -0x20) - ;; + ;; //EndStub////////////////////////////////////////////////////////////////////// // ok, the issue here is that we need to save state information so @@ -647,16 +638,16 @@ // In order to do this, our best bet is save the current state (plus // the state information obtain from the MIN_STATE_AREA) into a pt_regs // format. This way we can pass it on in a useable format. -// +// // // SAL to OS entry point for INIT on the monarch processor -// This has been defined for registration purposes with SAL +// This has been defined for registration purposes with SAL // as a part of ia64_mca_init. // // When we get here, the follow registers have been // set by the SAL for our use -// +// // 1. GR1 = OS INIT GP // 2. GR8 = PAL_PROC physical address // 3. GR9 = SAL_PROC physical address @@ -665,14 +656,14 @@ // 0 = Received INIT for event other than crash dump switch // 1 = Received wakeup at the end of an OS_MCA corrected machine check // 2 = Received INIT dude to CrashDump switch assertion -// +// // 6. GR12 = Return address to location within SAL_INIT procedure - + .text .align 16 -.global ia64_monarch_init_handler -.proc ia64_monarch_init_handler +.global ia64_monarch_init_handler +.proc ia64_monarch_init_handler ia64_monarch_init_handler: #if defined(CONFIG_SMP) && defined(SAL_MPINIT_WORKAROUND) @@ -680,6 +671,7 @@ // work around SAL bug that sends all processors to monarch entry // mov r17=cr.lid + // XXX fix me: this is wrong: hard_smp_processor_id() is a pair of lid/eid movl r18=__cpu_physical_id ;; dep r18=0,r18,61,3 // convert to physical address @@ -694,7 +686,7 @@ ;; #endif - + // // ok, the first thing we do is stash the information // the SAL passed to os @@ -706,8 +698,8 @@ ;; st8 [_tmp]=r1,0x08;; st8 [_tmp]=r8,0x08;; - st8 [_tmp]=r9,0x08;; - st8 [_tmp]=r10,0x08;; + st8 [_tmp]=r9,0x08;; + st8 [_tmp]=r10,0x08;; st8 [_tmp]=r11,0x08;; st8 [_tmp]=r12,0x08;; @@ -719,12 +711,12 @@ adds r3=8,r2 // set up second base pointer ;; SAVE_REST - + // ok, enough should be saved at this point to be dangerous, and supply // information for a dump // We need to switch to Virtual mode before hitting the C functions. // -// +// // movl r2=IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN mov r3=psr // get the current psr, minimum enabled at this point @@ -739,7 +731,7 @@ rfi ;; IVirtual_Switch: - // + // // We should now be running virtual // // Lets call the C handler to get the rest of the state info @@ -759,7 +751,7 @@ // // SAL to OS entry point for INIT on the slave processor -// This has been defined for registration purposes with SAL +// This has been defined for registration purposes with SAL // as a part of ia64_mca_init. // @@ -767,10 +759,10 @@ .align 16 .global ia64_slave_init_handler .proc ia64_slave_init_handler -ia64_slave_init_handler: +ia64_slave_init_handler: -slave_init_spin_me: +slave_init_spin_me: br.sptk slave_init_spin_me ;; .endp diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/minstate.h linux.ac/arch/ia64/kernel/minstate.h --- linux.vanilla/arch/ia64/kernel/minstate.h Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/minstate.h Tue Apr 10 18:08:40 2001 @@ -29,20 +29,20 @@ */ #define MINSTATE_START_SAVE_MIN_VIRT \ dep r1=-1,r1,61,3; /* r1 = current (virtual) */ \ -(p7) mov ar.rsc=r0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ +(pUser) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ ;; \ -(p7) addl rKRBS=IA64_RBS_OFFSET,r1; /* compute base of RBS */ \ -(p7) mov rARRNAT=ar.rnat; \ +(pUser) addl rKRBS=IA64_RBS_OFFSET,r1; /* compute base of RBS */ \ +(pUser) mov rARRNAT=ar.rnat; \ (pKern) mov r1=sp; /* get sp */ \ ;; \ -(p7) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ -(p7) mov rARBSPSTORE=ar.bspstore; /* save ar.bspstore */ \ +(pUser) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ +(pUser) mov rARBSPSTORE=ar.bspstore; /* save ar.bspstore */ \ ;; \ (pKern) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \ -(p7) mov ar.bspstore=rKRBS; /* switch to kernel RBS */ \ +(pUser) mov ar.bspstore=rKRBS; /* switch to kernel RBS */ \ ;; \ -(p7) mov r18=ar.bsp; \ -(p7) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ +(pUser) mov r18=ar.bsp; \ +(pUser) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ #define MINSTATE_END_SAVE_MIN_VIRT \ or r13=r13,r14; /* make `current' a kernel virtual address */ \ @@ -55,20 +55,20 @@ */ #define MINSTATE_START_SAVE_MIN_PHYS \ (pKern) movl sp=ia64_init_stack+IA64_STK_OFFSET-IA64_PT_REGS_SIZE; \ -(p7) mov ar.rsc=r0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ -(p7) addl rKRBS=IA64_RBS_OFFSET,r1; /* compute base of register backing store */ \ +(pUser) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ +(pUser) addl rKRBS=IA64_RBS_OFFSET,r1; /* compute base of register backing store */ \ ;; \ -(p7) mov rARRNAT=ar.rnat; \ +(pUser) mov rARRNAT=ar.rnat; \ (pKern) dep r1=0,sp,61,3; /* compute physical addr of sp */ \ -(p7) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ -(p7) mov rARBSPSTORE=ar.bspstore; /* save ar.bspstore */ \ -(p7) dep rKRBS=-1,rKRBS,61,3; /* compute kernel virtual addr of RBS */\ +(pUser) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ +(pUser) mov rARBSPSTORE=ar.bspstore; /* save ar.bspstore */ \ +(pUser) dep rKRBS=-1,rKRBS,61,3; /* compute kernel virtual addr of RBS */\ ;; \ (pKern) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \ -(p7) mov ar.bspstore=rKRBS; /* switch to kernel RBS */ \ +(pUser) mov ar.bspstore=rKRBS; /* switch to kernel RBS */ \ ;; \ -(p7) mov r18=ar.bsp; \ -(p7) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ +(pUser) mov r18=ar.bsp; \ +(pUser) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ #define MINSTATE_END_SAVE_MIN_PHYS \ or r12=r12,r14; /* make sp a kernel virtual address */ \ @@ -101,29 +101,30 @@ * r12 = kernel sp (kernel virtual address) * r13 = points to current task_struct (kernel virtual address) * p15 = TRUE if psr.i is set in cr.ipsr - * predicate registers (other than p6, p7, and p15), b6, r3, r8, r9, r10, r11, r14, r15: + * predicate registers (other than p2, p3, and p15), b6, r3, r8, r9, r10, r11, r14, r15: * preserved * * Note that psr.ic is NOT turned on by this macro. This is so that * we can pass interruption state as arguments to a handler. */ -#define DO_SAVE_MIN(COVER,EXTRA) \ +#define DO_SAVE_MIN(COVER,SAVE_IFS,EXTRA) \ mov rARRSC=ar.rsc; \ mov rARPFS=ar.pfs; \ mov rR1=r1; \ mov rARUNAT=ar.unat; \ mov rCRIPSR=cr.ipsr; \ - mov rB6=b6; /* rB6 = branch reg 6 */ \ + mov rB6=b6; /* rB6 = branch reg 6 */ \ mov rCRIIP=cr.iip; \ - mov r1=ar.k6; /* r1 = current (physical) */ \ + mov r1=IA64_KR(CURRENT); /* r1 = current (physical) */ \ + COVER; \ ;; \ invala; \ extr.u r16=rCRIPSR,32,2; /* extract psr.cpl */ \ ;; \ - cmp.eq pKern,p7=r0,r16; /* are we in kernel mode already? (psr.cpl==0) */ \ + cmp.eq pKern,pUser=r0,r16; /* are we in kernel mode already? (psr.cpl==0) */ \ /* switch from user to kernel RBS: */ \ - COVER; \ ;; \ + SAVE_IFS; \ MINSTATE_START_SAVE_MIN \ ;; \ mov r16=r1; /* initialize first base pointer */ \ @@ -135,7 +136,7 @@ ;; \ st8 [r16]=rCRIFS,16; /* save cr.ifs */ \ st8 [r17]=rARUNAT,16; /* save ar.unat */ \ -(p7) sub r18=r18,rKRBS; /* r18=RSE.ndirty*8 */ \ +(pUser) sub r18=r18,rKRBS; /* r18=RSE.ndirty*8 */ \ ;; \ st8 [r16]=rARPFS,16; /* save ar.pfs */ \ st8 [r17]=rARRSC,16; /* save ar.rsc */ \ @@ -143,8 +144,8 @@ ;; /* avoid RAW on r16 & r17 */ \ (pKern) adds r16=16,r16; /* skip over ar_rnat field */ \ (pKern) adds r17=16,r17; /* skip over ar_bspstore field */ \ -(p7) st8 [r16]=rARRNAT,16; /* save ar.rnat */ \ -(p7) st8 [r17]=rARBSPSTORE,16; /* save ar.bspstore */ \ +(pUser) st8 [r16]=rARRNAT,16; /* save ar.rnat */ \ +(pUser) st8 [r17]=rARBSPSTORE,16; /* save ar.bspstore */ \ ;; \ st8 [r16]=rARPR,16; /* save predicates */ \ st8 [r17]=rB6,16; /* save b6 */ \ @@ -171,7 +172,7 @@ ;; \ .mem.offset 0,0; st8.spill [r16]=r10,16; \ .mem.offset 8,0; st8.spill [r17]=r11,16; \ - mov r13=ar.k6; /* establish `current' */ \ + mov r13=IA64_KR(CURRENT); /* establish `current' */ \ ;; \ EXTRA; \ movl r1=__gp; /* establish kernel global pointer */ \ @@ -240,6 +241,6 @@ # define STOPS #endif -#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs,) STOPS -#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs, mov r15=r19) STOPS -#define SAVE_MIN DO_SAVE_MIN(mov rCRIFS=r0,) STOPS +#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs,) STOPS +#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs, mov r15=r19) STOPS +#define SAVE_MIN DO_SAVE_MIN( , mov rCRIFS=r0, ) STOPS diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/pal.S linux.ac/arch/ia64/kernel/pal.S --- linux.vanilla/arch/ia64/kernel/pal.S Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/pal.S Tue Apr 10 18:08:40 2001 @@ -14,11 +14,6 @@ #include <asm/asmmacro.h> #include <asm/processor.h> - .text - .psr abi64 - .psr lsb - .lsb - .data pal_entry_point: data8 ia64_pal_default_handler @@ -58,7 +53,7 @@ * */ GLOBAL_ENTRY(ia64_pal_call_static) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6) alloc loc1 = ar.pfs,6,90,0,0 movl loc2 = pal_entry_point 1: { @@ -73,7 +68,7 @@ ;; mov loc3 = psr mov loc0 = rp - UNW(.body) + .body mov r30 = in2 (p6) rsm psr.i | psr.ic @@ -101,14 +96,14 @@ * in2 - in3 Remaning PAL arguments */ GLOBAL_ENTRY(ia64_pal_call_stacked) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5) alloc loc1 = ar.pfs,5,4,87,0 movl loc2 = pal_entry_point mov r28 = in0 // Index MUST be copied to r28 mov out0 = in0 // AND in0 of PAL function mov loc0 = rp - UNW(.body) + .body ;; ld8 loc2 = [loc2] // loc2 <- entry point mov out1 = in1 @@ -148,7 +143,7 @@ GLOBAL_ENTRY(ia64_pal_call_phys_static) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6) alloc loc1 = ar.pfs,6,90,0,0 movl loc2 = pal_entry_point 1: { @@ -156,7 +151,7 @@ mov r8 = ip // save ip to compute branch mov loc0 = rp // save rp } - UNW(.body) + .body ;; ld8 loc2 = [loc2] // loc2 <- entry point mov r29 = in1 // first argument @@ -171,7 +166,7 @@ dep.z r8=r8,0,61 // convert rp to physical ;; mov b7 = loc2 // install target to branch reg - mov ar.rsc=r0 // put RSE in enforced lazy, LE mode + mov ar.rsc=0 // put RSE in enforced lazy, LE mode movl r16=PAL_PSR_BITS_TO_CLEAR movl r17=PAL_PSR_BITS_TO_SET ;; @@ -182,7 +177,7 @@ .ret1: mov rp = r8 // install return address (physical) br.cond.sptk.few b7 1: - mov ar.rsc=r0 // put RSE in enforced lazy, LE mode + mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 // r16= original psr br.call.sptk.few rp=ia64_switch_mode // return to virtual mode .ret2: @@ -204,7 +199,7 @@ * in2 - in3 Remaning PAL arguments */ GLOBAL_ENTRY(ia64_pal_call_phys_stacked) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5) alloc loc1 = ar.pfs,5,5,86,0 movl loc2 = pal_entry_point 1: { @@ -224,7 +219,7 @@ mov loc4=ar.rsc // save RSE configuration dep.z loc2=loc2,0,61 // convert pal entry point to physical ;; - mov ar.rsc=r0 // put RSE in enforced lazy, LE mode + mov ar.rsc=0 // put RSE in enforced lazy, LE mode movl r16=PAL_PSR_BITS_TO_CLEAR movl r17=PAL_PSR_BITS_TO_SET ;; @@ -236,7 +231,7 @@ .ret6: br.call.sptk.many rp=b7 // now make the call .ret7: - mov ar.rsc=r0 // put RSE in enforced lazy, LE mode + mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 // r16= original psr br.call.sptk.few rp=ia64_switch_mode // return to virtual mode diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/palinfo.c linux.ac/arch/ia64/kernel/palinfo.c --- linux.vanilla/arch/ia64/kernel/palinfo.c Fri Feb 16 23:53:08 2001 +++ linux.ac/arch/ia64/kernel/palinfo.c Tue Apr 10 18:08:40 2001 @@ -5,16 +5,13 @@ * This code is based on specification of PAL as of the * Intel IA-64 Architecture Software Developer's Manual v1.0. * - * + * * Copyright (C) 2000 Hewlett-Packard Co * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com> - * + * * 05/26/2000 S.Eranian initial release * 08/21/2000 S.Eranian updated to July 2000 PAL specs - * - * ISSUES: - * - as of 2.2.9/2.2.12, the following values are still wrong - * PAL_VM_SUMMARY: key & rid sizes + * 02/05/2001 S.Eranian fixed module support */ #include <linux/config.h> #include <linux/types.h> @@ -36,12 +33,7 @@ MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>"); MODULE_DESCRIPTION("/proc interface to IA-64 PAL"); -/* - * Hope to get rid of this one in a near future -*/ -#define IA64_PAL_VERSION_BUG 1 - -#define PALINFO_VERSION "0.3" +#define PALINFO_VERSION "0.4" #ifdef CONFIG_SMP #define cpu_is_online(i) (cpu_online_map & (1UL << i)) @@ -83,7 +75,7 @@ "Non-temporal, all levels", "Reserved", "Reserved", - "Reserved", + "Reserved", "Reserved" }; @@ -94,7 +86,7 @@ "Non-temporal, all levels", "Reserved", "Reserved", - "Reserved", + "Reserved", "Reserved" }; @@ -108,7 +100,7 @@ #define RSE_HINTS_COUNT (sizeof(rse_hints)/sizeof(const char *)) /* - * The current revision of the Volume 2 (July 2000) of + * The current revision of the Volume 2 (July 2000) of * IA-64 Architecture Software Developer's Manual is wrong. * Table 4-10 has invalid information concerning the ma field: * Correct table is: @@ -116,7 +108,7 @@ * bit 4 - 100 - UC * bit 5 - 101 - UCE * bit 6 - 110 - WC - * bit 7 - 111 - NatPage + * bit 7 - 111 - NatPage */ static const char *mem_attrib[]={ "Write Back (WB)", /* 000 */ @@ -136,7 +128,7 @@ * * Input: * - a pointer to a buffer to hold the string - * - a 64-bit vector + * - a 64-bit vector * Ouput: * - a pointer to the end of the buffer * @@ -163,7 +155,7 @@ * * Input: * - a pointer to a buffer to hold the string - * - a 64-bit vector + * - a 64-bit vector * Ouput: * - a pointer to the end of the buffer * @@ -181,7 +173,7 @@ if (i != 0 && (i%64) == 0) value = *++reg_info; if ((value & 0x1) == 0 && skip == 0) { - if (begin <= i - 2) + if (begin <= i - 2) p += sprintf(p, "%d-%d ", begin, i-1); else p += sprintf(p, "%d ", i-1); @@ -194,7 +186,7 @@ value >>=1; } if (begin > -1) { - if (begin < 127) + if (begin < 127) p += sprintf(p, "%d-127", begin); else p += sprintf(p, "127"); @@ -219,7 +211,7 @@ if (halt_info[i].pal_power_mgmt_info_s.im == 1) { p += sprintf(p, "Power level %d:\n" \ "\tentry_latency : %d cycles\n" \ - "\texit_latency : %d cycles\n" \ + "\texit_latency : %d cycles\n" \ "\tpower consumption : %d mW\n" \ "\tCache+TLB coherency : %s\n", i, halt_info[i].pal_power_mgmt_info_s.entry_latency, @@ -233,7 +225,7 @@ return p - page; } -static int +static int cache_info(char *page) { char *p = page; @@ -288,13 +280,13 @@ for(k=0; k < 8; k++ ) { if ( cci.pcci_st_hints & 0x1) p += sprintf(p, "[%s]", cache_st_hints[k]); - cci.pcci_st_hints >>=1; + cci.pcci_st_hints >>=1; } p += sprintf(p, "\n\tLoad hints : "); for(k=0; k < 8; k++ ) { if ( cci.pcci_ld_hints & 0x1) p += sprintf(p, "[%s]", cache_ld_hints[k]); - cci.pcci_ld_hints >>=1; + cci.pcci_ld_hints >>=1; } p += sprintf(p, "\n\tAlias boundary : %d byte(s)\n" \ "\tTag LSB : %d\n" \ @@ -384,7 +376,7 @@ ptce.stride[1]); p += sprintf(p, "TC Levels : %d\n" \ - "Unique TC(s) : %d\n", + "Unique TC(s) : %d\n", vm_info_1.pal_vm_info_1_s.num_tc_levels, vm_info_1.pal_vm_info_1_s.max_unique_tcs); @@ -392,7 +384,7 @@ for (j=2; j>0 ; j--) { tc_pages = 0; /* just in case */ - + /* even without unification, some levels may not be present */ if ((status=ia64_pal_vm_info(i,j, &tc_info, &tc_pages)) != 0) { continue; @@ -422,7 +414,7 @@ } p += sprintf(p, "\n"); - return p - page; + return p - page; } @@ -446,7 +438,7 @@ if (ia64_pal_register_info(info, ®_info[0], ®_info[1]) != 0) return 0; - p += sprintf(p, "%-32s : ", info_type[info]); + p += sprintf(p, "%-32s : ", info_type[info]); p = bitregister_process(p, reg_info, 128); @@ -458,8 +450,8 @@ p += sprintf(p, "RSE stacked physical registers : %ld\n" \ "RSE load/store hints : %ld (%s)\n", phys_stacked, - hints.ph_data, - hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(\?\?)"); + hints.ph_data, + hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(\?\?)"); if (ia64_pal_debug_info(&iregs, &dregs)) return 0; @@ -486,15 +478,15 @@ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Disable BINIT on processor time-out", "Disable dynamic power management (DPM)", - "Disable coherency", - "Disable cache", + "Disable coherency", + "Disable cache", "Enable CMCI promotion", "Enable MCA to BINIT promotion", "Enable MCA promotion", "Enable BEER promotion" }; - + static int processor_info(char *page) { @@ -508,7 +500,7 @@ for(i=0; i < 64; i++, v++,avail >>=1, status >>=1, control >>=1) { if ( ! *v ) continue; - p += sprintf(p, "%-40s : %s%s %s\n", *v, + p += sprintf(p, "%-40s : %s%s %s\n", *v, avail & 0x1 ? "" : "NotImpl", avail & 0x1 ? (status & 0x1 ? "On" : "Off"): "", avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): ""); @@ -526,9 +518,9 @@ "Enable Half Transfer", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - "Enable Cache Line Repl. Exclusive", - "Enable Cache Line Repl. Shared", + NULL, NULL, NULL, NULL, + "Enable Cache Line Repl. Exclusive", + "Enable Cache Line Repl. Shared", "Disable Transaction Queuing", "Disable Reponse Error Checking", "Disable Bus Error Checking", @@ -541,7 +533,7 @@ "Disable Bus Data Error Checking" }; - + static int bus_info(char *page) { @@ -560,7 +552,7 @@ for(i=0; i < 64; i++, v++, avail >>=1, status >>=1, control >>=1) { if ( ! *v ) continue; - p += sprintf(p, "%-48s : %s%s %s\n", *v, + p += sprintf(p, "%-48s : %s%s %s\n", *v, avail & 0x1 ? "" : "NotImpl", avail & 0x1 ? (status & 0x1 ? "On" : "Off"): "", avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): ""); @@ -568,62 +560,39 @@ return p - page; } - -/* - * physical mode call for PAL_VERSION is working fine. - * This function is meant to go away once PAL get fixed. - */ -static inline s64 -ia64_pal_version_phys(pal_version_u_t *pal_min_version, pal_version_u_t *pal_cur_version) -{ - struct ia64_pal_retval iprv; - PAL_CALL_PHYS(iprv, PAL_VERSION, 0, 0, 0); - if (pal_min_version) - pal_min_version->pal_version_val = iprv.v0; - if (pal_cur_version) - pal_cur_version->pal_version_val = iprv.v1; - return iprv.status; -} - static int version_info(char *page) { - s64 status; pal_version_u_t min_ver, cur_ver; char *p = page; -#ifdef IA64_PAL_VERSION_BUG - /* The virtual mode call is buggy. But the physical mode call seems - * to be ok. Until they fix virtual mode, we do physical. - */ - status = ia64_pal_version_phys(&min_ver, &cur_ver); -#else - /* The system crashes if you enable this code with the wrong PAL - * code + /* The PAL_VERSION call is advertised as being able to support + * both physical and virtual mode calls. This seems to be a documentation + * bug rather than firmware bug. In fact, it does only support physical mode. + * So now the code reflects this fact and the pal_version() has been updated + * accordingly. */ - status = ia64_pal_version(&min_ver, &cur_ver); -#endif - if (status != 0) return 0; + if (ia64_pal_version(&min_ver, &cur_ver) != 0) return 0; p += sprintf(p, "PAL_vendor : 0x%02x (min=0x%02x)\n" \ "PAL_A : %x.%x.%x (min=%x.%x.%x)\n" \ "PAL_B : %x.%x.%x (min=%x.%x.%x)\n", - cur_ver.pal_version_s.pv_pal_vendor, - min_ver.pal_version_s.pv_pal_vendor, + cur_ver.pal_version_s.pv_pal_vendor, + min_ver.pal_version_s.pv_pal_vendor, - cur_ver.pal_version_s.pv_pal_a_model>>4, - cur_ver.pal_version_s.pv_pal_a_model&0xf, - cur_ver.pal_version_s.pv_pal_a_rev, - min_ver.pal_version_s.pv_pal_a_model>>4, - min_ver.pal_version_s.pv_pal_a_model&0xf, - min_ver.pal_version_s.pv_pal_a_rev, - - cur_ver.pal_version_s.pv_pal_b_model>>4, - cur_ver.pal_version_s.pv_pal_b_model&0xf, - cur_ver.pal_version_s.pv_pal_b_rev, - min_ver.pal_version_s.pv_pal_b_model>>4, - min_ver.pal_version_s.pv_pal_b_model&0xf, - min_ver.pal_version_s.pv_pal_b_rev); + cur_ver.pal_version_s.pv_pal_a_model>>4, + cur_ver.pal_version_s.pv_pal_a_model&0xf, + cur_ver.pal_version_s.pv_pal_a_rev, + min_ver.pal_version_s.pv_pal_a_model>>4, + min_ver.pal_version_s.pv_pal_a_model&0xf, + min_ver.pal_version_s.pv_pal_a_rev, + + cur_ver.pal_version_s.pv_pal_b_model>>4, + cur_ver.pal_version_s.pv_pal_b_model&0xf, + cur_ver.pal_version_s.pv_pal_b_rev, + min_ver.pal_version_s.pv_pal_b_model>>4, + min_ver.pal_version_s.pv_pal_b_model&0xf, + min_ver.pal_version_s.pv_pal_b_rev); return p - page; } @@ -650,7 +619,7 @@ "Counter width : %d bits\n" \ "Cycle event number : %d\n" \ "Retired event number : %d\n" \ - "Implemented PMC : ", + "Implemented PMC : ", pm_info.pal_perf_mon_info_s.generic, pm_info.pal_perf_mon_info_s.width, pm_info.pal_perf_mon_info_s.cycles, @@ -659,15 +628,15 @@ p = bitregister_process(p, pm_buffer, 256); p += sprintf(p, "\nImplemented PMD : "); - + p = bitregister_process(p, pm_buffer+4, 256); p += sprintf(p, "\nCycles count capable : "); - + p = bitregister_process(p, pm_buffer+8, 256); p += sprintf(p, "\nRetired bundles count capable : "); - + p = bitregister_process(p, pm_buffer+12, 256); p += sprintf(p, "\n"); @@ -683,7 +652,7 @@ u64 base; if (ia64_pal_freq_base(&base) == -1) - p += sprintf(p, "Output clock : not implemented\n"); + p += sprintf(p, "Output clock : not implemented\n"); else p += sprintf(p, "Output clock : %ld ticks/s\n", base); @@ -762,7 +731,7 @@ if (ifa_reg->valid == 0) continue; - gr_reg = (struct gr_reg *)tr_buffer; + gr_reg = (struct gr_reg *)tr_buffer; itir_reg = (struct itir_reg *)&tr_buffer[1]; rid_reg = (struct rid_reg *)&tr_buffer[3]; @@ -788,7 +757,7 @@ "\trid : %x\n" \ "\tp : %d\n" \ "\tma : %d\n" \ - "\td : %d\n", + "\td : %d\n", gr_reg->pl, gr_reg->ar, rid_reg->rid, @@ -807,7 +776,7 @@ */ static palinfo_entry_t palinfo_entries[]={ { "version_info", version_info, }, - { "vm_info", vm_info, }, + { "vm_info", vm_info, }, { "cache_info", cache_info, }, { "power_info", power_info, }, { "register_info", register_info, }, @@ -821,14 +790,14 @@ #define NR_PALINFO_ENTRIES (sizeof(palinfo_entries)/sizeof(palinfo_entry_t)) /* - * this array is used to keep track of the proc entries we create. This is + * this array is used to keep track of the proc entries we create. This is * required in the module mode when we need to remove all entries. The procfs code * does not do recursion of deletion * * Notes: * - first +1 accounts for the cpuN entry * - second +1 account for toplevel palinfo - * + * */ #define NR_PALINFO_PROC_ENTRIES (NR_CPUS*(NR_PALINFO_ENTRIES+1)+1) @@ -855,7 +824,7 @@ #ifdef CONFIG_SMP /* - * used to hold information about final function to call + * used to hold information about final function to call */ typedef struct { palinfo_func_t func; /* pointer to function to call */ @@ -888,7 +857,7 @@ * 0 : error or nothing to output * otherwise how many bytes in the "page" buffer were written */ -static +static int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page) { palinfo_smp_data_t ptr; @@ -908,7 +877,7 @@ return ptr.ret; } #else /* ! CONFIG_SMP */ -static +static int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page) { printk(__FUNCTION__" should not be called with non SMP kernel\n"); @@ -930,25 +899,25 @@ * in SMP mode, we may need to call another CPU to get correct * information. PAL, by definition, is processor specific */ - if (f->req_cpu == smp_processor_id()) + if (f->req_cpu == smp_processor_id()) len = (*palinfo_entries[f->func_id].proc_read)(page); else len = palinfo_handle_smp(f, page); - if (len <= off+count) *eof = 1; + if (len <= off+count) *eof = 1; - *start = page + off; - len -= off; + *start = page + off; + len -= off; - if (len>count) len = count; - if (len<0) len = 0; + if (len>count) len = count; + if (len<0) len = 0; MOD_DEC_USE_COUNT; - return len; + return len; } -static int __init +static int __init palinfo_init(void) { # define CPUSTR "cpu%d" @@ -979,7 +948,7 @@ for (j=0; j < NR_PALINFO_ENTRIES; j++) { f.func_id = j; - *pdir++ = create_proc_read_entry (palinfo_entries[j].name, 0, cpu_dir, + *pdir++ = create_proc_read_entry (palinfo_entries[j].name, 0, cpu_dir, palinfo_read_entry, (void *)f.value); } *pdir++ = cpu_dir; @@ -994,9 +963,10 @@ { int i = 0; - /* remove all nodes: depth first pass */ + /* remove all nodes: depth first pass. Could optimize this */ for (i=0; i< NR_PALINFO_PROC_ENTRIES ; i++) { - remove_proc_entry (palinfo_proc_entries[i]->name, NULL); + if (palinfo_proc_entries[i]) + remove_proc_entry (palinfo_proc_entries[i]->name, NULL); } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/perfmon.c linux.ac/arch/ia64/kernel/perfmon.c --- linux.vanilla/arch/ia64/kernel/perfmon.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/perfmon.c Sat Apr 14 01:18:00 2001 @@ -7,57 +7,39 @@ * Modifications by Stephane Eranian, Hewlett-Packard Co. * Copyright (C) 1999 Ganesh Venkitachalam <venkitac@us.ibm.com> * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com> - * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com> + * Copyright (C) 2000-2001 Stephane Eranian <eranian@hpl.hp.com> */ #include <linux/config.h> - #include <linux/kernel.h> -#include <linux/init.h> #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/smp_lock.h> #include <linux/proc_fs.h> +#include <linux/init.h> +#include <linux/vmalloc.h> +#include <linux/wrapper.h> +#include <linux/mm.h> +#include <asm/bitops.h> +#include <asm/efi.h> #include <asm/errno.h> #include <asm/hw_irq.h> +#include <asm/page.h> +#include <asm/pal.h> +#include <asm/perfmon.h> +#include <asm/pgtable.h> #include <asm/processor.h> +#include <asm/signal.h> #include <asm/system.h> #include <asm/uaccess.h> -#include <asm/pal.h> - -/* Long blurb on how this works: - * We set dcr.pp, psr.pp, and the appropriate pmc control values with - * this. Notice that we go about modifying _each_ task's pt_regs to - * set cr_ipsr.pp. This will start counting when "current" does an - * _rfi_. Also, since each task's cr_ipsr.pp, and cr_ipsr is inherited - * across forks, we do _not_ need additional code on context - * switches. On stopping of the counters we dont need to go about - * changing every task's cr_ipsr back to where it wuz, because we can - * just set pmc[0]=1. But we do it anyways becuase we will probably - * add thread specific accounting later. - * - * The obvious problem with this is that on SMP systems, it is a bit - * of work (when someone wants to do it:-)) - it would be easier if we - * just added code to the context-switch path, but if we wanted to support - * per-thread accounting, the context-switch path might be long unless - * we introduce a flag in the task_struct. Right now, the following code - * will NOT work correctly on MP (for more than one reason:-)). - * - * The short answer is that to make this work on SMP, we would need - * to lock the run queue to ensure no context switches, send - * an IPI to each processor, and in that IPI handler, set processor regs, - * and just modify the psr bit of only the _current_ thread, since we have - * modified the psr bit correctly in the kernel stack for every process - * which is not running. Also, we need pmd arrays per-processor, and - * the READ_PMD command will need to get values off of other processors. - * IPIs are the answer, irrespective of what the question is. Might - * crash on SMP systems without the lock_kernel(). - */ +#include <asm/delay.h> /* for ia64_get_itc() */ #ifdef CONFIG_PERFMON -#define MAX_PERF_COUNTER 4 /* true for Itanium, at least */ +#define PFM_VERSION "0.2" +#define PFM_SMPL_HDR_VERSION 1 + #define PMU_FIRST_COUNTER 4 /* first generic counter */ #define PFM_WRITE_PMCS 0xa0 @@ -67,293 +49,1019 @@ #define PFM_START 0xa4 #define PFM_ENABLE 0xa5 /* unfreeze only */ #define PFM_DISABLE 0xa6 /* freeze only */ -/* +#define PFM_RESTART 0xcf +#define PFM_CREATE_CONTEXT 0xa7 +/* * Those 2 are just meant for debugging. I considered using sysctl() for * that but it is a little bit too pervasive. This solution is at least * self-contained. */ -#define PFM_DEBUG_ON 0xe0 +#define PFM_DEBUG_ON 0xe0 #define PFM_DEBUG_OFF 0xe1 + +/* + * perfmon API flags + */ +#define PFM_FL_INHERIT_NONE 0x00 /* never inherit a context across fork (default) */ +#define PFM_FL_INHERIT_ONCE 0x01 /* clone pfm_context only once across fork() */ +#define PFM_FL_INHERIT_ALL 0x02 /* always clone pfm_context across fork() */ +#define PFM_FL_SMPL_OVFL_NOBLOCK 0x04 /* do not block on sampling buffer overflow */ +#define PFM_FL_SYSTEMWIDE 0x08 /* create a systemwide context */ + +/* + * PMC API flags + */ +#define PFM_REGFL_OVFL_NOTIFY 1 /* send notification on overflow */ + +/* + * Private flags and masks + */ +#define PFM_FL_INHERIT_MASK (PFM_FL_INHERIT_NONE|PFM_FL_INHERIT_ONCE|PFM_FL_INHERIT_ALL) + #ifdef CONFIG_SMP #define cpu_is_online(i) (cpu_online_map & (1UL << i)) #else #define cpu_is_online(i) 1 #endif -#define PMC_IS_IMPL(i) (pmu_conf.impl_regs[i>>6] & (1<< (i&~(64-1)))) -#define PMD_IS_IMPL(i) (pmu_conf.impl_regs[4+(i>>6)] & (1<< (i&~(64-1)))) +#define PMC_IS_IMPL(i) (i < pmu_conf.num_pmcs && pmu_conf.impl_regs[i>>6] & (1<< (i&~(64-1)))) +#define PMD_IS_IMPL(i) (i < pmu_conf.num_pmds && pmu_conf.impl_regs[4+(i>>6)] & (1<< (i&~(64-1)))) #define PMD_IS_COUNTER(i) (i>=PMU_FIRST_COUNTER && i < (PMU_FIRST_COUNTER+pmu_conf.max_counters)) #define PMC_IS_COUNTER(i) (i>=PMU_FIRST_COUNTER && i < (PMU_FIRST_COUNTER+pmu_conf.max_counters)) +/* This is the Itanium-specific PMC layout for counter config */ +typedef struct { + unsigned long pmc_plm:4; /* privilege level mask */ + unsigned long pmc_ev:1; /* external visibility */ + unsigned long pmc_oi:1; /* overflow interrupt */ + unsigned long pmc_pm:1; /* privileged monitor */ + unsigned long pmc_ig1:1; /* reserved */ + unsigned long pmc_es:7; /* event select */ + unsigned long pmc_ig2:1; /* reserved */ + unsigned long pmc_umask:4; /* unit mask */ + unsigned long pmc_thres:3; /* threshold */ + unsigned long pmc_ig3:1; /* reserved (missing from table on p6-17) */ + unsigned long pmc_ism:2; /* instruction set mask */ + unsigned long pmc_ig4:38; /* reserved */ +} pmc_counter_reg_t; + +/* test for EAR/BTB configuration */ +#define PMU_DEAR_EVENT 0x67 +#define PMU_IEAR_EVENT 0x23 +#define PMU_BTB_EVENT 0x11 + +#define PMC_IS_DEAR(a) (((pmc_counter_reg_t *)(a))->pmc_es == PMU_DEAR_EVENT) +#define PMC_IS_IEAR(a) (((pmc_counter_reg_t *)(a))->pmc_es == PMU_IEAR_EVENT) +#define PMC_IS_BTB(a) (((pmc_counter_reg_t *)(a))->pmc_es == PMU_BTB_EVENT) + /* - * this structure needs to be enhanced + * This header is at the beginning of the sampling buffer returned to the user. + * It is exported as Read-Only at this point. It is directly followed with the + * first record. */ typedef struct { - unsigned long pfr_reg_num; /* which register */ - unsigned long pfr_reg_value; /* configuration (PMC) or initial value (PMD) */ - unsigned long pfr_reg_reset; /* reset value on overflow (PMD) */ - void *pfr_smpl_buf; /* pointer to user buffer for EAR/BTB */ - unsigned long pfr_smpl_size; /* size of user buffer for EAR/BTB */ - pid_t pfr_notify_pid; /* process to notify */ - int pfr_notify_sig; /* signal for notification, 0=no notification */ -} perfmon_req_t; + int hdr_version; /* could be used to differentiate formats */ + int hdr_reserved; + unsigned long hdr_entry_size; /* size of one entry in bytes */ + unsigned long hdr_count; /* how many valid entries */ + unsigned long hdr_pmds; /* which pmds are recorded */ +} perfmon_smpl_hdr_t; -#if 0 +/* + * Header entry in the buffer as a header as follows. + * The header is directly followed with the PMDS to saved in increasing index order: + * PMD4, PMD5, .... How many PMDs are present is determined by the tool which must + * keep track of it when generating the final trace file. + */ typedef struct { - unsigned long pmu_reg_data; /* generic PMD register */ - unsigned long pmu_reg_num; /* which register number */ -} perfmon_reg_t; -#endif + int pid; /* identification of process */ + int cpu; /* which cpu was used */ + unsigned long rate; /* initial value of this counter */ + unsigned long stamp; /* timestamp */ + unsigned long ip; /* where did the overflow interrupt happened */ + unsigned long regs; /* which registers overflowed (up to 64)*/ +} perfmon_smpl_entry_t; /* - * This structure is initialize at boot time and contains + * There is one such data structure per perfmon context. It is used to describe the + * sampling buffer. It is to be shared among siblings whereas the pfm_context isn't. + * Therefore we maintain a refcnt which is incremented on fork(). + * This buffer is private to the kernel only the actual sampling buffer including its + * header are exposed to the user. This construct allows us to export the buffer read-write, + * if needed, without worrying about security problems. + */ +typedef struct { + atomic_t psb_refcnt; /* how many users for the buffer */ + int reserved; + void *psb_addr; /* points to location of first entry */ + unsigned long psb_entries; /* maximum number of entries */ + unsigned long psb_size; /* aligned size of buffer */ + unsigned long psb_index; /* next free entry slot */ + unsigned long psb_entry_size; /* size of each entry including entry header */ + perfmon_smpl_hdr_t *psb_hdr; /* points to sampling buffer header */ +} pfm_smpl_buffer_desc_t; + + +/* + * This structure is initialized at boot time and contains * a description of the PMU main characteristic as indicated * by PAL */ typedef struct { + unsigned long pfm_is_disabled; /* indicates if perfmon is working properly */ unsigned long perf_ovfl_val; /* overflow value for generic counters */ unsigned long max_counters; /* upper limit on counter pair (PMC/PMD) */ + unsigned long num_pmcs ; /* highest PMC implemented (may have holes) */ + unsigned long num_pmds; /* highest PMD implemented (may have holes) */ unsigned long impl_regs[16]; /* buffer used to hold implememted PMC/PMD mask */ } pmu_config_t; +#define PERFMON_IS_DISABLED() pmu_conf.pfm_is_disabled + +typedef struct { + __u64 val; /* virtual 64bit counter value */ + __u64 ival; /* initial value from user */ + __u64 smpl_rval; /* reset value on sampling overflow */ + __u64 ovfl_rval; /* reset value on overflow */ + int flags; /* notify/do not notify */ +} pfm_counter_t; +#define PMD_OVFL_NOTIFY(ctx, i) ((ctx)->ctx_pmds[i].flags & PFM_REGFL_OVFL_NOTIFY) + +/* + * perfmon context. One per process, is cloned on fork() depending on inheritance flags + */ +typedef struct { + unsigned int inherit:2; /* inherit mode */ + unsigned int noblock:1; /* block/don't block on overflow with notification */ + unsigned int system:1; /* do system wide monitoring */ + unsigned int frozen:1; /* pmu must be kept frozen on ctxsw in */ + unsigned int reserved:27; +} pfm_context_flags_t; + +typedef struct pfm_context { + + pfm_smpl_buffer_desc_t *ctx_smpl_buf; /* sampling buffer descriptor, if any */ + unsigned long ctx_dear_counter; /* which PMD holds D-EAR */ + unsigned long ctx_iear_counter; /* which PMD holds I-EAR */ + unsigned long ctx_btb_counter; /* which PMD holds BTB */ + + pid_t ctx_notify_pid; /* who to notify on overflow */ + int ctx_notify_sig; /* XXX: SIGPROF or other */ + pfm_context_flags_t ctx_flags; /* block/noblock */ + pid_t ctx_creator; /* pid of creator (debug) */ + unsigned long ctx_ovfl_regs; /* which registers just overflowed (notification) */ + unsigned long ctx_smpl_regs; /* which registers to record on overflow */ + + struct semaphore ctx_restart_sem; /* use for blocking notification mode */ + + pfm_counter_t ctx_pmds[IA64_NUM_PMD_COUNTERS]; /* XXX: size should be dynamic */ +} pfm_context_t; + +#define ctx_fl_inherit ctx_flags.inherit +#define ctx_fl_noblock ctx_flags.noblock +#define ctx_fl_system ctx_flags.system +#define ctx_fl_frozen ctx_flags.frozen + +#define CTX_IS_DEAR(c,n) ((c)->ctx_dear_counter == (n)) +#define CTX_IS_IEAR(c,n) ((c)->ctx_iear_counter == (n)) +#define CTX_IS_BTB(c,n) ((c)->ctx_btb_counter == (n)) +#define CTX_OVFL_NOBLOCK(c) ((c)->ctx_fl_noblock == 1) +#define CTX_INHERIT_MODE(c) ((c)->ctx_fl_inherit) +#define CTX_HAS_SMPL(c) ((c)->ctx_smpl_buf != NULL) + static pmu_config_t pmu_conf; /* for debug only */ -static unsigned long pfm_debug=1; /* 0= nodebug, >0= debug output on */ -#define DBprintk(a) {\ - if (pfm_debug >0) { printk a; } \ +static unsigned long pfm_debug=0; /* 0= nodebug, >0= debug output on */ +#define DBprintk(a) \ + do { \ + if (pfm_debug >0) { printk(__FUNCTION__" "); printk a; } \ + } while (0); + +static void perfmon_softint(unsigned long ignored); +static void ia64_reset_pmu(void); + +DECLARE_TASKLET(pfm_tasklet, perfmon_softint, 0); + +/* + * structure used to pass information between the interrupt handler + * and the tasklet. + */ +typedef struct { + pid_t to_pid; /* which process to notify */ + pid_t from_pid; /* which process is source of overflow */ + int sig; /* with which signal */ + unsigned long bitvect; /* which counters have overflowed */ +} notification_info_t; + +#define notification_is_invalid(i) (i->to_pid < 2) + +/* will need to be cache line padded */ +static notification_info_t notify_info[NR_CPUS]; + +/* + * We force cache line alignment to avoid false sharing + * given that we have one entry per CPU. + */ +static struct { + struct task_struct *owner; +} ____cacheline_aligned pmu_owners[NR_CPUS]; +/* helper macros */ +#define SET_PMU_OWNER(t) do { pmu_owners[smp_processor_id()].owner = (t); } while(0); +#define PMU_OWNER() pmu_owners[smp_processor_id()].owner + +/* for debug only */ +static struct proc_dir_entry *perfmon_dir; + +/* + * finds the number of PM(C|D) registers given + * the bitvector returned by PAL + */ +static unsigned long __init +find_num_pm_regs(long *buffer) +{ + int i=3; /* 4 words/per bitvector */ + + /* start from the most significant word */ + while (i>=0 && buffer[i] == 0 ) i--; + if (i< 0) { + printk(KERN_ERR "perfmon: No bit set in pm_buffer\n"); + return 0; + } + return 1+ ia64_fls(buffer[i]) + 64 * i; } + /* - * could optimize to avoid cache line conflicts in SMP + * Generates a unique (per CPU) timestamp + */ +static inline unsigned long +perfmon_get_stamp(void) +{ + /* + * XXX: maybe find something more efficient + */ + return ia64_get_itc(); +} + +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. */ -static struct task_struct *pmu_owners[NR_CPUS]; +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 = (unsigned long) page_address(pte_page(pte)); + ret |= (adr & (PAGE_SIZE - 1)); + } + } + } + DBprintk(("uv2kva(%lx-->%lx)\n", adr, ret)); + 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) +{ + __u64 pa; + __asm__ __volatile__ ("tpa %0 = %1" : "=r"(pa) : "r"(adr) : "memory"); + DBprintk(("kv2pa(%lx-->%lx)\n", adr, pa)); + return pa; +} + +static void * +rvmalloc(unsigned long size) +{ + void *mem; + unsigned long adr, page; + + /* XXX: may have to revisit this part because + * vmalloc() does not necessarily return a page-aligned buffer. + * This maybe a security problem when mapped at user level + */ + mem=vmalloc(size); + if (mem) { + 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); + mem_map_reserve(virt_to_page(__va(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + } + return mem; +} + +static void +rvfree(void *mem, unsigned long size) +{ + unsigned long adr, page; + + if (mem) { + adr=(unsigned long) mem; + while (size > 0) { + page = kvirt_to_pa(adr); + mem_map_unreserve(virt_to_page(__va(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + vfree(mem); + } +} + +static pfm_context_t * +pfm_context_alloc(void) +{ + pfm_context_t *pfc; + + /* allocate context descriptor */ + pfc = vmalloc(sizeof(*pfc)); + if (pfc) memset(pfc, 0, sizeof(*pfc)); + + return pfc; +} + +static void +pfm_context_free(pfm_context_t *pfc) +{ + if (pfc) vfree(pfc); +} static int -do_perfmonctl (struct task_struct *task, int cmd, int flags, perfmon_req_t *req, int count, struct pt_regs *regs) +pfm_remap_buffer(unsigned long buf, unsigned long addr, unsigned long size) { - perfmon_req_t tmp; - int i; + unsigned long page; - switch (cmd) { - case PFM_WRITE_PMCS: - /* we don't quite support this right now */ - if (task != current) return -EINVAL; + while (size > 0) { + page = kvirt_to_pa(buf); - if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; + if (remap_page_range(addr, page, PAGE_SIZE, PAGE_SHARED)) return -ENOMEM; + + addr += PAGE_SIZE; + buf += PAGE_SIZE; + size -= PAGE_SIZE; + } + return 0; +} + +/* + * counts the number of PMDS to save per entry. + * This code is generic enough to accomodate more than 64 PMDS when they become available + */ +static unsigned long +pfm_smpl_entry_size(unsigned long *which, unsigned long size) +{ + unsigned long res = 0; + int i; + + for (i=0; i < size; i++, which++) res += hweight64(*which); + + DBprintk((" res=%ld\n", res)); + + return res; +} + +/* + * Allocates the sampling buffer and remaps it into caller's address space + */ +static int +pfm_smpl_buffer_alloc(pfm_context_t *ctx, unsigned long which_pmds, unsigned long entries, void **user_addr) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + unsigned long addr, size, regcount; + void *smpl_buf; + pfm_smpl_buffer_desc_t *psb; + + regcount = pfm_smpl_entry_size(&which_pmds, 1); + + /* note that regcount might be 0, in this case only the header for each + * entry will be recorded. + */ + + /* + * 1 buffer hdr and for each entry a header + regcount PMDs to save + */ + size = PAGE_ALIGN( sizeof(perfmon_smpl_hdr_t) + + entries * (sizeof(perfmon_smpl_entry_t) + regcount*sizeof(u64))); + /* + * check requested size to avoid Denial-of-service attacks + * XXX: may have to refine this test + */ + if (size > current->rlim[RLIMIT_MEMLOCK].rlim_cur) return -EAGAIN; + + /* find some free area in address space */ + addr = get_unmapped_area(NULL, 0, size, 0, 0); + if (!addr) goto no_addr; + + DBprintk((" entries=%ld aligned size=%ld, unmapped @0x%lx\n", entries, size, addr)); + + /* allocate vma */ + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (!vma) goto no_vma; + + /* XXX: see rvmalloc() for page alignment problem */ + smpl_buf = rvmalloc(size); + if (smpl_buf == NULL) goto no_buffer; + + DBprintk((" smpl_buf @%p\n", smpl_buf)); + + if (pfm_remap_buffer((unsigned long)smpl_buf, addr, size)) goto cant_remap; + + /* allocate sampling buffer descriptor now */ + psb = vmalloc(sizeof(*psb)); + if (psb == NULL) goto no_buffer_desc; + + /* start with something clean */ + memset(smpl_buf, 0x0, size); + + psb->psb_hdr = smpl_buf; + psb->psb_addr = (char *)smpl_buf+sizeof(perfmon_smpl_hdr_t); /* first entry */ + psb->psb_size = size; /* aligned size */ + psb->psb_index = 0; + psb->psb_entries = entries; + + atomic_set(&psb->psb_refcnt, 1); + + psb->psb_entry_size = sizeof(perfmon_smpl_entry_t) + regcount*sizeof(u64); + + DBprintk((" psb @%p entry_size=%ld hdr=%p addr=%p\n", (void *)psb,psb->psb_entry_size, (void *)psb->psb_hdr, (void *)psb->psb_addr)); + + /* initialize some of the fields of header */ + psb->psb_hdr->hdr_version = PFM_SMPL_HDR_VERSION; + psb->psb_hdr->hdr_entry_size = sizeof(perfmon_smpl_entry_t)+regcount*sizeof(u64); + psb->psb_hdr->hdr_pmds = which_pmds; + + /* store which PMDS to record */ + ctx->ctx_smpl_regs = which_pmds; + + /* link to perfmon context */ + ctx->ctx_smpl_buf = psb; + + /* + * initialize the vma for the sampling buffer + */ + vma->vm_mm = mm; + vma->vm_start = addr; + vma->vm_end = addr + size; + vma->vm_flags = VM_READ|VM_MAYREAD; + vma->vm_page_prot = PAGE_READONLY; /* XXX may need to change */ + vma->vm_ops = NULL; + vma->vm_pgoff = 0; + vma->vm_file = NULL; + vma->vm_raend = 0; + + vma->vm_private_data = ctx; /* link to pfm_context(not yet used) */ + + /* + * now insert the vma in the vm list for the process + */ + insert_vm_struct(mm, vma); + + mm->total_vm += size >> PAGE_SHIFT; + + /* + * that's the address returned to the user + */ + *user_addr = (void *)addr; + + return 0; + + /* outlined error handling */ +no_addr: + DBprintk(("Cannot find unmapped area for size %ld\n", size)); + return -ENOMEM; +no_vma: + DBprintk(("Cannot allocate vma\n")); + return -ENOMEM; +cant_remap: + DBprintk(("Can't remap buffer\n")); + rvfree(smpl_buf, size); +no_buffer: + DBprintk(("Can't allocate sampling buffer\n")); + kmem_cache_free(vm_area_cachep, vma); + return -ENOMEM; +no_buffer_desc: + DBprintk(("Can't allocate sampling buffer descriptor\n")); + kmem_cache_free(vm_area_cachep, vma); + rvfree(smpl_buf, size); + return -ENOMEM; +} + +static int +pfx_is_sane(pfreq_context_t *pfx) +{ + /* valid signal */ + if (pfx->notify_sig < 1 || pfx->notify_sig >= _NSIG) return 0; + + /* cannot send to process 1, 0 means do not notify */ + if (pfx->notify_pid < 0 || pfx->notify_pid == 1) return 0; + + /* asked for sampling, but nothing to record ! */ + if (pfx->smpl_entries > 0 && pfm_smpl_entry_size(&pfx->smpl_regs, 1) == 0) return 0; + + /* probably more to add here */ + + + return 1; +} + +static int +pfm_context_create(struct task_struct *task, int flags, perfmon_req_t *req) +{ + pfm_context_t *ctx; + perfmon_req_t tmp; + void *uaddr = NULL; + int ret = -EFAULT; + int ctx_flags; + + /* to go away */ + if (flags) { + printk("perfmon: use context flags instead of perfmon() flags. Obsoleted API\n"); + } + + if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; + + ctx_flags = tmp.pfr_ctx.flags; + + /* not yet supported */ + if (ctx_flags & PFM_FL_SYSTEMWIDE) return -EINVAL; + + if (!pfx_is_sane(&tmp.pfr_ctx)) return -EINVAL; + + ctx = pfm_context_alloc(); + if (!ctx) return -ENOMEM; + + /* record who the creator is (for debug) */ + ctx->ctx_creator = task->pid; + + ctx->ctx_notify_pid = tmp.pfr_ctx.notify_pid; + ctx->ctx_notify_sig = SIGPROF; /* siginfo imposes a fixed signal */ + + if (tmp.pfr_ctx.smpl_entries) { + DBprintk((" sampling entries=%ld\n",tmp.pfr_ctx.smpl_entries)); + if ((ret=pfm_smpl_buffer_alloc(ctx, tmp.pfr_ctx.smpl_regs, tmp.pfr_ctx.smpl_entries, &uaddr)) ) goto buffer_error; + tmp.pfr_ctx.smpl_vaddr = uaddr; + } + /* initialization of context's flags */ + ctx->ctx_fl_inherit = ctx_flags & PFM_FL_INHERIT_MASK; + ctx->ctx_fl_noblock = (ctx_flags & PFM_FL_SMPL_OVFL_NOBLOCK) ? 1 : 0; + ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEMWIDE) ? 1: 0; + ctx->ctx_fl_frozen = 0; + + sema_init(&ctx->ctx_restart_sem, 0); /* init this semaphore to locked */ + + if (copy_to_user(req, &tmp, sizeof(tmp))) goto buffer_error; + + DBprintk((" context=%p, pid=%d notify_sig %d notify_pid=%d\n",(void *)ctx, task->pid, ctx->ctx_notify_sig, ctx->ctx_notify_pid)); + DBprintk((" context=%p, pid=%d flags=0x%x inherit=%d noblock=%d system=%d\n",(void *)ctx, task->pid, ctx_flags, ctx->ctx_fl_inherit, ctx->ctx_fl_noblock, ctx->ctx_fl_system)); + + /* link with task */ + task->thread.pfm_context = ctx; + + return 0; + +buffer_error: + vfree(ctx); + + return ret; +} + +static void +pfm_reset_regs(pfm_context_t *ctx) +{ + unsigned long mask = ctx->ctx_ovfl_regs; + int i, cnum; + + DBprintk((" ovfl_regs=0x%lx\n", mask)); + /* + * now restore reset value on sampling overflowed counters + */ + for(i=0, cnum=PMU_FIRST_COUNTER; i < pmu_conf.max_counters; i++, cnum++, mask >>= 1) { + if (mask & 0x1) { + DBprintk((" reseting PMD[%d]=%lx\n", cnum, ctx->ctx_pmds[i].smpl_rval & pmu_conf.perf_ovfl_val)); + + /* upper part is ignored on rval */ + ia64_set_pmd(cnum, ctx->ctx_pmds[i].smpl_rval); + } + } +} + +static int +pfm_write_pmcs(struct task_struct *ta, perfmon_req_t *req, int count) +{ + struct thread_struct *th = &ta->thread; + pfm_context_t *ctx = th->pfm_context; + perfmon_req_t tmp; + unsigned long cnum; + int i; + + /* XXX: ctx locking may be required here */ + + for (i = 0; i < count; i++, req++) { + + if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; + + cnum = tmp.pfr_reg.reg_num; + + /* XXX needs to check validity of the data maybe */ + if (!PMC_IS_IMPL(cnum)) { + DBprintk((" invalid pmc[%ld]\n", cnum)); + return -EINVAL; + } + + if (PMC_IS_COUNTER(cnum)) { + + /* + * we keep track of EARS/BTB to speed up sampling later + */ + if (PMC_IS_DEAR(&tmp.pfr_reg.reg_value)) { + ctx->ctx_dear_counter = cnum; + } else if (PMC_IS_IEAR(&tmp.pfr_reg.reg_value)) { + ctx->ctx_iear_counter = cnum; + } else if (PMC_IS_BTB(&tmp.pfr_reg.reg_value)) { + ctx->ctx_btb_counter = cnum; + } + + if (tmp.pfr_reg.reg_flags & PFM_REGFL_OVFL_NOTIFY) + ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags |= PFM_REGFL_OVFL_NOTIFY; + } + + ia64_set_pmc(cnum, tmp.pfr_reg.reg_value); + DBprintk((" setting PMC[%ld]=0x%lx flags=0x%x\n", cnum, tmp.pfr_reg.reg_value, ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags)); + + } + /* + * we have to set this here event hough we haven't necessarily started monitoring + * because we may be context switched out + */ + th->flags |= IA64_THREAD_PM_VALID; + + return 0; +} + +static int +pfm_write_pmds(struct task_struct *ta, perfmon_req_t *req, int count) +{ + struct thread_struct *th = &ta->thread; + pfm_context_t *ctx = th->pfm_context; + perfmon_req_t tmp; + unsigned long cnum; + int i; + + /* XXX: ctx locking may be required here */ + + for (i = 0; i < count; i++, req++) { + int k; + + if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; - for (i = 0; i < count; i++, req++) { - copy_from_user(&tmp, req, sizeof(tmp)); + cnum = tmp.pfr_reg.reg_num; - /* XXX needs to check validity of the data maybe */ + k = cnum - PMU_FIRST_COUNTER; - if (!PMC_IS_IMPL(tmp.pfr_reg_num)) { - DBprintk((__FUNCTION__ " invalid pmc[%ld]\n", tmp.pfr_reg_num)); - return -EINVAL; - } - - /* XXX: for counters, need to some checks */ - if (PMC_IS_COUNTER(tmp.pfr_reg_num)) { - current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].sig = tmp.pfr_notify_sig; - current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].pid = tmp.pfr_notify_pid; - - DBprintk((__FUNCTION__" setting PMC[%ld] send sig %d to %d\n",tmp.pfr_reg_num, tmp.pfr_notify_sig, tmp.pfr_notify_pid)); - } - ia64_set_pmc(tmp.pfr_reg_num, tmp.pfr_reg_value); + if (!PMD_IS_IMPL(cnum)) return -EINVAL; - DBprintk((__FUNCTION__" setting PMC[%ld]=0x%lx\n", tmp.pfr_reg_num, tmp.pfr_reg_value)); + /* update virtualized (64bits) counter */ + if (PMD_IS_COUNTER(cnum)) { + ctx->ctx_pmds[k].ival = tmp.pfr_reg.reg_value; + ctx->ctx_pmds[k].val = tmp.pfr_reg.reg_value & ~pmu_conf.perf_ovfl_val; + ctx->ctx_pmds[k].smpl_rval = tmp.pfr_reg.reg_smpl_reset; + ctx->ctx_pmds[k].ovfl_rval = tmp.pfr_reg.reg_ovfl_reset; + } + + /* writes to unimplemented part is ignored, so this is safe */ + ia64_set_pmd(cnum, tmp.pfr_reg.reg_value); + + /* to go away */ + ia64_srlz_d(); + DBprintk((" setting PMD[%ld]: pmd.val=0x%lx pmd.ovfl_rval=0x%lx pmd.smpl_rval=0x%lx pmd=%lx\n", + cnum, + ctx->ctx_pmds[k].val, + ctx->ctx_pmds[k].ovfl_rval, + ctx->ctx_pmds[k].smpl_rval, + ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val)); + } + /* + * we have to set this here event hough we haven't necessarily started monitoring + * because we may be context switched out + */ + th->flags |= IA64_THREAD_PM_VALID; + + return 0; +} + +static int +pfm_read_pmds(struct task_struct *ta, perfmon_req_t *req, int count) +{ + struct thread_struct *th = &ta->thread; + pfm_context_t *ctx = th->pfm_context; + unsigned long val=0; + perfmon_req_t tmp; + int i; + + /* + * XXX: MUST MAKE SURE WE DON"T HAVE ANY PENDING OVERFLOW BEFORE READING + * This is required when the monitoring has been stoppped by user of kernel. + * If ity is still going on, then that's fine because we a re not gauranteed + * to return an accurate value in this case + */ + + /* XXX: ctx locking may be required here */ + + for (i = 0; i < count; i++, req++) { + int k; + + if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; + + if (!PMD_IS_IMPL(tmp.pfr_reg.reg_num)) return -EINVAL; + + k = tmp.pfr_reg.reg_num - PMU_FIRST_COUNTER; + + if (PMD_IS_COUNTER(tmp.pfr_reg.reg_num)) { + if (ta == current){ + val = ia64_get_pmd(tmp.pfr_reg.reg_num); + } else { + val = th->pmd[k]; } + val &= pmu_conf.perf_ovfl_val; /* - * we have to set this here event hough we haven't necessarily started monitoring - * because we may be context switched out + * lower part of .val may not be zero, so we must be an addition because of + * residual count (see update_counters). */ - current->thread.flags |= IA64_THREAD_PM_VALID; - break; + val += ctx->ctx_pmds[k].val; + } else { + /* for now */ + if (ta != current) return -EINVAL; - case PFM_WRITE_PMDS: + val = ia64_get_pmd(tmp.pfr_reg.reg_num); + } + tmp.pfr_reg.reg_value = val; + + DBprintk((" reading PMD[%ld]=0x%lx\n", tmp.pfr_reg.reg_num, val)); + + if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT; + } + return 0; +} + +static int +pfm_do_restart(struct task_struct *task) +{ + struct thread_struct *th = &task->thread; + pfm_context_t *ctx = th->pfm_context; + void *sem = &ctx->ctx_restart_sem; + + if (task == current) { + DBprintk((" restartig self %d frozen=%d \n", current->pid, ctx->ctx_fl_frozen)); + + pfm_reset_regs(ctx); + + /* + * We ignore block/don't block because we never block + * for a self-monitoring process. + */ + ctx->ctx_fl_frozen = 0; + + if (CTX_HAS_SMPL(ctx)) { + ctx->ctx_smpl_buf->psb_hdr->hdr_count = 0; + ctx->ctx_smpl_buf->psb_index = 0; + } + + /* pfm_reset_smpl_buffers(ctx,th->pfm_ovfl_regs);*/ + + /* simply unfreeze */ + ia64_set_pmc(0, 0); + ia64_srlz_d(); + + return 0; + } + + /* check if blocking */ + if (CTX_OVFL_NOBLOCK(ctx) == 0) { + DBprintk((" unblocking %d \n", task->pid)); + up(sem); + return 0; + } + + /* + * in case of non blocking mode, then it's just a matter of + * of reseting the sampling buffer (if any) index. The PMU + * is already active. + */ + + /* + * must reset the header count first + */ + if (CTX_HAS_SMPL(ctx)) { + DBprintk((" resetting sampling indexes for %d \n", task->pid)); + ctx->ctx_smpl_buf->psb_hdr->hdr_count = 0; + ctx->ctx_smpl_buf->psb_index = 0; + } + + return 0; +} + + +static int +do_perfmonctl (struct task_struct *task, int cmd, int flags, perfmon_req_t *req, int count, struct pt_regs *regs) +{ + perfmon_req_t tmp; + struct thread_struct *th = &task->thread; + pfm_context_t *ctx = th->pfm_context; + + memset(&tmp, 0, sizeof(tmp)); + + switch (cmd) { + case PFM_CREATE_CONTEXT: + /* a context has already been defined */ + if (ctx) return -EBUSY; + + /* may be a temporary limitation */ + if (task != current) return -EINVAL; + + if (req == NULL || count != 1) return -EINVAL; + + if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; + + return pfm_context_create(task, flags, req); + + case PFM_WRITE_PMCS: /* we don't quite support this right now */ if (task != current) return -EINVAL; if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; - for (i = 0; i < count; i++, req++) { - copy_from_user(&tmp, req, sizeof(tmp)); + if (!ctx) { + DBprintk((" PFM_WRITE_PMCS: no context for task %d\n", task->pid)); + return -EINVAL; + } + return pfm_write_pmcs(task, req, count); + + case PFM_WRITE_PMDS: + /* we don't quite support this right now */ + if (task != current) return -EINVAL; - if (!PMD_IS_IMPL(tmp.pfr_reg_num)) return -EINVAL; + if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; - /* update virtualized (64bits) counter */ - if (PMD_IS_COUNTER(tmp.pfr_reg_num)) { - current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].val = tmp.pfr_reg_value & ~pmu_conf.perf_ovfl_val; - current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].rval = tmp.pfr_reg_reset; - } - /* writes to unimplemented part is ignored, so this is safe */ - ia64_set_pmd(tmp.pfr_reg_num, tmp.pfr_reg_value); - /* to go away */ - ia64_srlz_d(); - DBprintk((__FUNCTION__" setting PMD[%ld]: pmod.val=0x%lx pmd=0x%lx rval=0x%lx\n", tmp.pfr_reg_num, current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].val, ia64_get_pmd(tmp.pfr_reg_num),current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].rval)); + if (!ctx) { + DBprintk((" PFM_WRITE_PMDS: no context for task %d\n", task->pid)); + return -EINVAL; } - /* - * we have to set this here event hough we haven't necessarily started monitoring - * because we may be context switched out - */ - current->thread.flags |= IA64_THREAD_PM_VALID; - break; + return pfm_write_pmds(task, req, count); case PFM_START: /* we don't quite support this right now */ if (task != current) return -EINVAL; - pmu_owners[smp_processor_id()] = current; + if (!ctx) { + DBprintk((" PFM_START: no context for task %d\n", task->pid)); + return -EINVAL; + } + + SET_PMU_OWNER(current); /* will start monitoring right after rfi */ ia64_psr(regs)->up = 1; - /* - * mark the state as valid. - * this will trigger save/restore at context switch - */ - current->thread.flags |= IA64_THREAD_PM_VALID; + /* + * mark the state as valid. + * this will trigger save/restore at context switch + */ + th->flags |= IA64_THREAD_PM_VALID; ia64_set_pmc(0, 0); + ia64_srlz_d(); - break; + break; case PFM_ENABLE: /* we don't quite support this right now */ if (task != current) return -EINVAL; - pmu_owners[smp_processor_id()] = current; + if (!ctx) { + DBprintk((" PFM_ENABLE: no context for task %d\n", task->pid)); + return -EINVAL; + } + + /* reset all registers to stable quiet state */ + ia64_reset_pmu(); + + /* make sure nothing starts */ + ia64_psr(regs)->up = 0; + ia64_psr(regs)->pp = 0; + + /* do it on the live register as well */ + __asm__ __volatile__ ("rsm psr.pp|psr.pp;;"::: "memory"); + + SET_PMU_OWNER(current); - /* - * mark the state as valid. - * this will trigger save/restore at context switch - */ - current->thread.flags |= IA64_THREAD_PM_VALID; + /* + * mark the state as valid. + * this will trigger save/restore at context switch + */ + th->flags |= IA64_THREAD_PM_VALID; /* simply unfreeze */ ia64_set_pmc(0, 0); + ia64_srlz_d(); break; case PFM_DISABLE: /* we don't quite support this right now */ if (task != current) return -EINVAL; - /* simply unfreeze */ + /* simply freeze */ ia64_set_pmc(0, 1); ia64_srlz_d(); break; - case PFM_READ_PMDS: + case PFM_READ_PMDS: if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; if (!access_ok(VERIFY_WRITE, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; - /* This looks shady, but IMHO this will work fine. This is - * the sequence that I could come up with to avoid races - * with the interrupt handler. See explanation in the - * following comment. - */ -#if 0 -/* irrelevant with user monitors */ - local_irq_save(flags); - __asm__ __volatile__("rsm psr.pp\n"); - dcr = ia64_get_dcr(); - dcr &= ~IA64_DCR_PP; - ia64_set_dcr(dcr); - local_irq_restore(flags); -#endif - /* - * We cannot write to pmc[0] to stop counting here, as - * that particular instruction might cause an overflow - * and the mask in pmc[0] might get lost. I'm _not_ - * sure of the hardware behavior here. So we stop - * counting by psr.pp = 0. And we reset dcr.pp to - * prevent an interrupt from mucking up psr.pp in the - * meanwhile. Perfmon interrupts are pended, hence the - * above code should be ok if one of the above instructions - * caused overflows, i.e the interrupt should get serviced - * when we re-enabled interrupts. When I muck with dcr, - * is the irq_save/restore needed? - */ - - for (i = 0; i < count; i++, req++) { - unsigned long val=0; - - copy_from_user(&tmp, req, sizeof(tmp)); - - if (!PMD_IS_IMPL(tmp.pfr_reg_num)) return -EINVAL; - - if (PMD_IS_COUNTER(tmp.pfr_reg_num)) { - if (task == current){ - val = ia64_get_pmd(tmp.pfr_reg_num) & pmu_conf.perf_ovfl_val; - } else { - val = task->thread.pmd[tmp.pfr_reg_num - PMU_FIRST_COUNTER] & pmu_conf.perf_ovfl_val; - } - val += task->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].val; - } else { - /* for now */ - if (task != current) return -EINVAL; - - val = ia64_get_pmd(tmp.pfr_reg_num); + if (!ctx) { + DBprintk((" PFM_READ_PMDS: no context for task %d\n", task->pid)); + return -EINVAL; } - tmp.pfr_reg_value = val; - -DBprintk((__FUNCTION__" reading PMD[%ld]=0x%lx\n", tmp.pfr_reg_num, val)); - - if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT; - } -#if 0 -/* irrelevant with user monitors */ - local_irq_save(flags); - __asm__ __volatile__("ssm psr.pp"); - dcr = ia64_get_dcr(); - dcr |= IA64_DCR_PP; - ia64_set_dcr(dcr); - local_irq_restore(flags); -#endif - break; + return pfm_read_pmds(task, req, count); case PFM_STOP: - /* we don't quite support this right now */ - if (task != current) return -EINVAL; + /* we don't quite support this right now */ + if (task != current) return -EINVAL; - ia64_set_pmc(0, 1); - ia64_srlz_d(); + ia64_set_pmc(0, 1); + ia64_srlz_d(); - ia64_psr(regs)->up = 0; + ia64_psr(regs)->up = 0; - current->thread.flags &= ~IA64_THREAD_PM_VALID; + th->flags &= ~IA64_THREAD_PM_VALID; - pmu_owners[smp_processor_id()] = NULL; + SET_PMU_OWNER(NULL); -#if 0 -/* irrelevant with user monitors */ - local_irq_save(flags); - dcr = ia64_get_dcr(); - dcr &= ~IA64_DCR_PP; - ia64_set_dcr(dcr); - local_irq_restore(flags); - ia64_psr(regs)->up = 0; -#endif - - break; + /* we probably will need some more cleanup here */ + break; case PFM_DEBUG_ON: - printk(__FUNCTION__" debuggin on\n"); + printk(" debugging on\n"); pfm_debug = 1; break; case PFM_DEBUG_OFF: - printk(__FUNCTION__" debuggin off\n"); + printk(" debugging off\n"); pfm_debug = 0; break; + case PFM_RESTART: /* temporary, will most likely end up as a PFM_ENABLE */ + + if ((th->flags & IA64_THREAD_PM_VALID) == 0) { + printk(" PFM_RESTART not monitoring\n"); + return -EINVAL; + } + if (!ctx) { + printk(" PFM_RESTART no ctx for %d\n", task->pid); + return -EINVAL; + } + if (CTX_OVFL_NOBLOCK(ctx) == 0 && ctx->ctx_fl_frozen==0) { + printk("task %d without pmu_frozen set\n", task->pid); + return -EINVAL; + } + + return pfm_do_restart(task); /* we only look at first entry */ + default: - DBprintk((__FUNCTION__" UNknown command 0x%x\n", cmd)); - return -EINVAL; - break; - } - return 0; + DBprintk((" UNknown command 0x%x\n", cmd)); + return -EINVAL; + } + return 0; +} + +/* + * XXX: do something better here + */ +static int +perfmon_bad_permissions(struct task_struct *task) +{ + /* stolen from bad_signal() */ + return (current->session != task->session) + && (current->euid ^ task->suid) && (current->euid ^ task->uid) + && (current->uid ^ task->suid) && (current->uid ^ task->uid); } asmlinkage int @@ -361,8 +1069,16 @@ { struct pt_regs *regs = (struct pt_regs *) &stack; struct task_struct *child = current; - int ret; + int ret = -ESRCH; + + /* sanity check: + * + * ensures that we don't do bad things in case the OS + * does not have enough storage to save/restore PMC/PMD + */ + if (PERFMON_IS_DISABLED()) return -ENOSYS; + /* XXX: pid interface is going away in favor of pfm context */ if (pid != current->pid) { read_lock(&tasklist_lock); { @@ -370,37 +1086,245 @@ if (child) get_task_struct(child); } - if (!child) { - read_unlock(&tasklist_lock); - return -ESRCH; - } + + if (!child) goto abort_call; + + ret = -EPERM; + + if (perfmon_bad_permissions(child)) goto abort_call; + /* * XXX: need to do more checking here */ - if (child->state != TASK_ZOMBIE) { - DBprintk((__FUNCTION__" warning process %d not in stable state %ld\n", pid, child->state)); + if (child->state != TASK_ZOMBIE && child->state != TASK_STOPPED) { + DBprintk((" warning process %d not in stable state %ld\n", pid, child->state)); } - } + } ret = do_perfmonctl(child, cmd, flags, req, count, regs); +abort_call: if (child != current) read_unlock(&tasklist_lock); return ret; } -static inline int -update_counters (u64 pmc0) +/* + * This function is invoked on the exit path of the kernel. Therefore it must make sure + * it does does modify the caller's input registers (in0-in7) in case of entry by system call + * which can be restarted. That's why it's declared as a system call and all 8 possible args + * are declared even though not used. + */ +#if __GNUC__ >= 3 +void asmlinkage +pfm_overflow_notify(void) +#else +void asmlinkage +pfm_overflow_notify(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7) +#endif { - unsigned long mask, i, cnum; - struct thread_struct *th; - struct task_struct *ta; + struct task_struct *task; + struct thread_struct *th = ¤t->thread; + pfm_context_t *ctx = current->thread.pfm_context; + struct siginfo si; + int ret; - if (pmu_owners[smp_processor_id()] == NULL) { - DBprintk((__FUNCTION__" Spurious overflow interrupt: PMU not owned\n")); - return 0; + /* + * do some sanity checks first + */ + if (!ctx) { + printk("perfmon: process %d has no PFM context\n", current->pid); + return; + } + if (ctx->ctx_notify_pid < 2) { + printk("perfmon: process %d invalid notify_pid=%d\n", current->pid, ctx->ctx_notify_pid); + return; + } + + DBprintk((" current=%d ctx=%p bv=0%lx\n", current->pid, (void *)ctx, ctx->ctx_ovfl_regs)); + /* + * NO matter what notify_pid is, + * we clear overflow, won't notify again + */ + th->pfm_pend_notify = 0; + + /* + * When measuring in kernel mode and non-blocking fashion, it is possible to + * get an overflow while executing this code. Therefore the state of pend_notify + * and ovfl_regs can be altered. The important point is not to loose any notification. + * It is fine to get called for nothing. To make sure we do collect as much state as + * possible, update_counters() always uses |= to add bit to the ovfl_regs field. + * + * In certain cases, it is possible to come here, with ovfl_regs == 0; + * + * XXX: pend_notify and ovfl_regs could be merged maybe ! + */ + if (ctx->ctx_ovfl_regs == 0) { + printk("perfmon: spurious overflow notification from pid %d\n", current->pid); + return; } - + read_lock(&tasklist_lock); + + task = find_task_by_pid(ctx->ctx_notify_pid); + + if (task) { + si.si_signo = ctx->ctx_notify_sig; + si.si_errno = 0; + si.si_code = PROF_OVFL; /* goes to user */ + si.si_addr = NULL; + si.si_pid = current->pid; /* who is sending */ + si.si_pfm_ovfl = ctx->ctx_ovfl_regs; + + DBprintk((" SIGPROF to %d @ %p\n", task->pid, (void *)task)); + + /* must be done with tasklist_lock locked */ + ret = send_sig_info(ctx->ctx_notify_sig, &si, task); + if (ret != 0) { + DBprintk((" send_sig_info(process %d, SIGPROF)=%d\n", ctx->ctx_notify_pid, ret)); + task = NULL; /* will cause return */ + } + } else { + printk("perfmon: notify_pid %d not found\n", ctx->ctx_notify_pid); + } + + read_unlock(&tasklist_lock); + + /* now that we have released the lock handle error condition */ + if (!task || CTX_OVFL_NOBLOCK(ctx)) { + /* we clear all pending overflow bits in noblock mode */ + ctx->ctx_ovfl_regs = 0; + return; + } + DBprintk((" CPU%d %d before sleep\n", smp_processor_id(), current->pid)); + + /* + * may go through without blocking on SMP systems + * if restart has been received already by the time we call down() + */ + ret = down_interruptible(&ctx->ctx_restart_sem); + + DBprintk((" CPU%d %d after sleep ret=%d\n", smp_processor_id(), current->pid, ret)); + + /* + * in case of interruption of down() we don't restart anything + */ + if (ret >= 0) { + /* we reactivate on context switch */ + ctx->ctx_fl_frozen = 0; + /* + * the ovfl_sem is cleared by the restart task and this is safe because we always + * use the local reference + */ + + pfm_reset_regs(ctx); + + /* now we can clear this mask */ + ctx->ctx_ovfl_regs = 0; + + /* + * Unlock sampling buffer and reset index atomically + * XXX: not really needed when blocking + */ + if (CTX_HAS_SMPL(ctx)) { + ctx->ctx_smpl_buf->psb_hdr->hdr_count = 0; + ctx->ctx_smpl_buf->psb_index = 0; + } + + DBprintk((" CPU%d %d unfreeze PMU\n", smp_processor_id(), current->pid)); + + ia64_set_pmc(0, 0); + ia64_srlz_d(); + + /* state restored, can go back to work (user mode) */ + } +} + +static void +perfmon_softint(unsigned long ignored) +{ + notification_info_t *info; + int my_cpu = smp_processor_id(); + struct task_struct *task; + struct siginfo si; + + info = notify_info+my_cpu; + + DBprintk((" CPU%d current=%d to_pid=%d from_pid=%d bv=0x%lx\n", \ + smp_processor_id(), current->pid, info->to_pid, info->from_pid, info->bitvect)); + + /* assumption check */ + if (info->from_pid == info->to_pid) { + DBprintk((" Tasklet assumption error: from=%d tor=%d\n", info->from_pid, info->to_pid)); + return; + } + + if (notification_is_invalid(info)) { + DBprintk((" invalid notification information\n")); + return; + } + + /* sanity check */ + if (info->to_pid == 1) { + DBprintk((" cannot notify init\n")); + return; + } + /* + * XXX: needs way more checks here to make sure we send to a task we have control over + */ + read_lock(&tasklist_lock); + + task = find_task_by_pid(info->to_pid); + + DBprintk((" after find %p\n", (void *)task)); + + if (task) { + int ret; + + si.si_signo = SIGPROF; + si.si_errno = 0; + si.si_code = PROF_OVFL; /* goes to user */ + si.si_addr = NULL; + si.si_pid = info->from_pid; /* who is sending */ + si.si_pfm_ovfl = info->bitvect; + + DBprintk((" SIGPROF to %d @ %p\n", task->pid, (void *)task)); + + /* must be done with tasklist_lock locked */ + ret = send_sig_info(SIGPROF, &si, task); + if (ret != 0) + DBprintk((" send_sig_info(process %d, SIGPROF)=%d\n", info->to_pid, ret)); + + /* invalidate notification */ + info->to_pid = info->from_pid = 0; + info->bitvect = 0; + } + + read_unlock(&tasklist_lock); + + DBprintk((" after unlock %p\n", (void *)task)); + + if (!task) { + printk("perfmon: CPU%d cannot find process %d\n", smp_processor_id(), info->to_pid); + } +} + +/* + * main overflow processing routine. + * it can be called from the interrupt path or explicitely during the context switch code + * Return: + * 0 : do not unfreeze the PMU + * 1 : PMU can be unfrozen + */ +static unsigned long +update_counters (struct task_struct *ta, u64 pmc0, struct pt_regs *regs) +{ + unsigned long mask, i, cnum; + struct thread_struct *th; + pfm_context_t *ctx; + unsigned long bv = 0; + int my_cpu = smp_processor_id(); + int ret = 1, buffer_is_full = 0; + int ovfl_is_smpl, can_notify, need_reset_pmd16=0; /* * It is never safe to access the task for which the overflow interrupt is destinated * using the current variable as the interrupt may occur in the middle of a context switch @@ -408,76 +1332,269 @@ * * For monitoring, however, we do need to get access to the task which caused the overflow * to account for overflow on the counters. + * * We accomplish this by maintaining a current owner of the PMU per CPU. During context - * switch the ownership is changed in a way such that the reflected owner is always the + * switch the ownership is changed in a way such that the reflected owner is always the * valid one, i.e. the one that caused the interrupt. */ - ta = pmu_owners[smp_processor_id()]; - th = &pmu_owners[smp_processor_id()]->thread; + + if (ta == NULL) { + DBprintk((" owners[%d]=NULL\n", my_cpu)); + return 0x1; + } + th = &ta->thread; + ctx = th->pfm_context; /* - * Don't think this could happen given first test. Keep as sanity check + * XXX: debug test + * Don't think this could happen given upfront tests */ if ((th->flags & IA64_THREAD_PM_VALID) == 0) { - DBprintk((__FUNCTION__" Spurious overflow interrupt: process %d not using perfmon\n", ta->pid)); + printk("perfmon: Spurious overflow interrupt: process %d not using perfmon\n", ta->pid); + return 0x1; + } + if (!ctx) { + printk("perfmon: Spurious overflow interrupt: process %d has no PFM context\n", ta->pid); return 0; } /* - * if PMU not frozen: spurious from previous context - * if PMC[0] = 0x1 : frozen but no overflow reported: leftover from previous context - * - * in either case we don't touch the state upon return from handler + * sanity test. Should never happen */ - if ((pmc0 & 0x1) == 0 || pmc0 == 0x1) { - DBprintk((__FUNCTION__" Spurious overflow interrupt: process %d freeze=0\n",ta->pid)); - return 0; + if ((pmc0 & 0x1 )== 0) { + printk("perfmon: pid %d pmc0=0x%lx assumption error for freeze bit\n", ta->pid, pmc0); + return 0x0; } - mask = pmc0 >> 4; + mask = pmc0 >> PMU_FIRST_COUNTER; - for (i = 0, cnum = PMU_FIRST_COUNTER; i < pmu_conf.max_counters; cnum++, i++, mask >>= 1) { + DBprintk(("pmc0=0x%lx pid=%d\n", pmc0, ta->pid)); - if (mask & 0x1) { - DBprintk((__FUNCTION__ " PMD[%ld] overflowed pmd=0x%lx pmod.val=0x%lx\n", cnum, ia64_get_pmd(cnum), th->pmu_counters[i].val)); - + DBprintk(("ctx is in %s mode\n", CTX_OVFL_NOBLOCK(ctx) ? "NO-BLOCK" : "BLOCK")); + + if (CTX_HAS_SMPL(ctx)) { + pfm_smpl_buffer_desc_t *psb = ctx->ctx_smpl_buf; + unsigned long *e, m, idx=0; + perfmon_smpl_entry_t *h; + int j; + + idx = ia64_fetch_and_add(1, &psb->psb_index); + DBprintk((" trying to record index=%ld entries=%ld\n", idx, psb->psb_entries)); + + /* + * XXX: there is a small chance that we could run out on index before resetting + * but index is unsigned long, so it will take some time..... + */ + if (idx > psb->psb_entries) { + buffer_is_full = 1; + goto reload_pmds; + } + + /* first entry is really entry 0, not 1 caused by fetch_and_add */ + idx--; + + h = (perfmon_smpl_entry_t *)(((char *)psb->psb_addr) + idx*(psb->psb_entry_size)); + + h->pid = ta->pid; + h->cpu = my_cpu; + h->rate = 0; + h->ip = regs ? regs->cr_iip : 0x0; /* where did the fault happened */ + h->regs = mask; /* which registers overflowed */ + + /* guaranteed to monotonically increase on each cpu */ + h->stamp = perfmon_get_stamp(); + + e = (unsigned long *)(h+1); + /* + * selectively store PMDs in increasing index number + */ + for (j=0, m = ctx->ctx_smpl_regs; m; m >>=1, j++) { + if (m & 0x1) { + if (PMD_IS_COUNTER(j)) + *e = ctx->ctx_pmds[j-PMU_FIRST_COUNTER].val + + (ia64_get_pmd(j) & pmu_conf.perf_ovfl_val); + else + *e = ia64_get_pmd(j); /* slow */ + DBprintk((" e=%p pmd%d =0x%lx\n", (void *)e, j, *e)); + e++; + } + } + /* make the new entry visible to user, needs to be atomic */ + ia64_fetch_and_add(1, &psb->psb_hdr->hdr_count); + + DBprintk((" index=%ld entries=%ld hdr_count=%ld\n", idx, psb->psb_entries, psb->psb_hdr->hdr_count)); + + /* sampling buffer full ? */ + if (idx == (psb->psb_entries-1)) { + bv = mask; + buffer_is_full = 1; + + DBprintk((" sampling buffer full must notify bv=0x%lx\n", bv)); + + if (!CTX_OVFL_NOBLOCK(ctx)) goto buffer_full; /* - * Because we somtimes (EARS/BTB) reset to a specific value, we cannot simply use - * val to count the number of times we overflowed. Otherwise we would loose the value - * current in the PMD (which can be >0). So to make sure we don't loose - * the residual counts we set val to contain full 64bits value of the counter. + * here, we have a full buffer but we are in non-blocking mode + * so we need to reloads overflowed PMDs with sampling reset values + * and restart */ - th->pmu_counters[i].val += 1+pmu_conf.perf_ovfl_val+(ia64_get_pmd(cnum) &pmu_conf.perf_ovfl_val); + } + } +reload_pmds: + ovfl_is_smpl = CTX_OVFL_NOBLOCK(ctx) && buffer_is_full; + can_notify = CTX_HAS_SMPL(ctx) == 0 && ctx->ctx_notify_pid; - /* writes to upper part are ignored, so this is safe */ - ia64_set_pmd(cnum, th->pmu_counters[i].rval); + for (i = 0, cnum = PMU_FIRST_COUNTER; mask ; cnum++, i++, mask >>= 1) { + + if ((mask & 0x1) == 0) continue; + + DBprintk((" PMD[%ld] overflowed pmd=0x%lx pmod.val=0x%lx\n", cnum, ia64_get_pmd(cnum), ctx->ctx_pmds[i].val)); - DBprintk((__FUNCTION__ " pmod[%ld].val=0x%lx pmd=0x%lx\n", i, th->pmu_counters[i].val, ia64_get_pmd(cnum)&pmu_conf.perf_ovfl_val)); + /* + * Because we sometimes (EARS/BTB) reset to a specific value, we cannot simply use + * val to count the number of times we overflowed. Otherwise we would loose the current value + * in the PMD (which can be >0). So to make sure we don't loose + * the residual counts we set val to contain full 64bits value of the counter. + * + * XXX: is this needed for EARS/BTB ? + */ + ctx->ctx_pmds[i].val += 1 + pmu_conf.perf_ovfl_val + + (ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val); /* slow */ + + DBprintk((" pmod[%ld].val=0x%lx pmd=0x%lx\n", i, ctx->ctx_pmds[i].val, ia64_get_pmd(cnum)&pmu_conf.perf_ovfl_val)); + + if (can_notify && PMD_OVFL_NOTIFY(ctx, i)) { + DBprintk((" CPU%d should notify process %d with signal %d\n", my_cpu, ctx->ctx_notify_pid, ctx->ctx_notify_sig)); + bv |= 1 << i; + } else { + DBprintk((" CPU%d PMD[%ld] overflow, no notification\n", my_cpu, cnum)); + /* + * In case no notification is requested, we reload the reset value right away + * otherwise we wait until the notify_pid process has been called and has + * has finished processing data. Check out pfm_overflow_notify() + */ - if (th->pmu_counters[i].pid != 0 && th->pmu_counters[i].sig>0) { - DBprintk((__FUNCTION__ " shouild notify process %d with signal %d\n",th->pmu_counters[i].pid, th->pmu_counters[i].sig)); + /* writes to upper part are ignored, so this is safe */ + if (ovfl_is_smpl) { + DBprintk((" CPU%d PMD[%ld] reloaded with smpl_val=%lx\n", my_cpu, cnum,ctx->ctx_pmds[i].smpl_rval)); + ia64_set_pmd(cnum, ctx->ctx_pmds[i].smpl_rval); + } else { + DBprintk((" CPU%d PMD[%ld] reloaded with ovfl_val=%lx\n", my_cpu, cnum,ctx->ctx_pmds[i].smpl_rval)); + ia64_set_pmd(cnum, ctx->ctx_pmds[i].ovfl_rval); } } + if (cnum == ctx->ctx_btb_counter) need_reset_pmd16=1; } - return 1; + /* + * In case of BTB, overflow + * we need to reset the BTB index. + */ + if (need_reset_pmd16) { + DBprintk(("reset PMD16\n")); + ia64_set_pmd(16, 0); + } +buffer_full: + /* see pfm_overflow_notify() on details for why we use |= here */ + ctx->ctx_ovfl_regs |= bv; + + /* nobody to notify, return and unfreeze */ + if (!bv) return 0x0; + + + if (ctx->ctx_notify_pid == ta->pid) { + struct siginfo si; + + si.si_errno = 0; + si.si_addr = NULL; + si.si_pid = ta->pid; /* who is sending */ + + + si.si_signo = ctx->ctx_notify_sig; /* is SIGPROF */ + si.si_code = PROF_OVFL; /* goes to user */ + si.si_pfm_ovfl = bv; + + + /* + * in this case, we don't stop the task, we let it go on. It will + * necessarily go to the signal handler (if any) when it goes back to + * user mode. + */ + DBprintk((" sending %d notification to self %d\n", si.si_signo, ta->pid)); + + + /* this call is safe in an interrupt handler */ + ret = send_sig_info(ctx->ctx_notify_sig, &si, ta); + if (ret != 0) + printk(" send_sig_info(process %d, SIGPROF)=%d\n", ta->pid, ret); + /* + * no matter if we block or not, we keep PMU frozen and do not unfreeze on ctxsw + */ + ctx->ctx_fl_frozen = 1; + + } else { +#if 0 + /* + * The tasklet is guaranteed to be scheduled for this CPU only + */ + notify_info[my_cpu].to_pid = ctx->notify_pid; + notify_info[my_cpu].from_pid = ta->pid; /* for debug only */ + notify_info[my_cpu].bitvect = bv; + /* tasklet is inserted and active */ + tasklet_schedule(&pfm_tasklet); +#endif + /* + * stored the vector of overflowed registers for use in notification + * mark that a notification/blocking is pending (arm the trap) + */ + th->pfm_pend_notify = 1; + + /* + * if we do block, then keep PMU frozen until restart + */ + if (!CTX_OVFL_NOBLOCK(ctx)) ctx->ctx_fl_frozen = 1; + + DBprintk((" process %d notify ovfl_regs=0x%lx\n", ta->pid, bv)); + } + /* + * keep PMU frozen (and overflowed bits cleared) when we have to stop, + * otherwise return a resume 'value' for PMC[0] + * + * XXX: maybe that's enough to get rid of ctx_fl_frozen ? + */ + DBprintk((" will return pmc0=0x%x\n",ctx->ctx_fl_frozen ? 0x1 : 0x0)); + return ctx->ctx_fl_frozen ? 0x1 : 0x0; } static void perfmon_interrupt (int irq, void *arg, struct pt_regs *regs) { - /* unfreeze if not spurious */ - if ( update_counters(ia64_get_pmc(0)) ) { - ia64_set_pmc(0, 0); + u64 pmc0; + struct task_struct *ta; + + pmc0 = ia64_get_pmc(0); /* slow */ + + /* + * if we have some pending bits set + * assumes : if any PM[0].bit[63-1] is set, then PMC[0].fr = 1 + */ + if ((pmc0 & ~0x1) && (ta=PMU_OWNER())) { + + /* assumes, PMC[0].fr = 1 at this point */ + pmc0 = update_counters(ta, pmc0, regs); + + /* + * if pmu_frozen = 0 + * pmc0 = 0 and we resume monitoring right away + * else + * pmc0 = 0x1 frozen but all pending bits are cleared + */ + ia64_set_pmc(0, pmc0); ia64_srlz_d(); + } else { + printk("perfmon: Spurious PMU overflow interrupt: pmc0=0x%lx owner=%p\n", pmc0, (void *)PMU_OWNER()); } } -static struct irqaction perfmon_irqaction = { - handler: perfmon_interrupt, - flags: SA_INTERRUPT, - name: "perfmon" -}; - +/* for debug only */ static int perfmon_proc_info(char *page) { @@ -487,56 +1604,79 @@ p += sprintf(p, "PMC[0]=%lx\nPerfmon debug: %s\n", pmc0, pfm_debug ? "On" : "Off"); for(i=0; i < NR_CPUS; i++) { - if (cpu_is_online(i)) - p += sprintf(p, "CPU%d.PMU %d\n", i, pmu_owners[i] ? pmu_owners[i]->pid: -1); + if (cpu_is_online(i)) + p += sprintf(p, "CPU%d.PMU %d\n", i, pmu_owners[i].owner ? pmu_owners[i].owner->pid: 0); } return p - page; } +/* for debug only */ static int perfmon_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = perfmon_proc_info(page); - if (len <= off+count) *eof = 1; + if (len <= off+count) *eof = 1; - *start = page + off; - len -= off; + *start = page + off; + len -= off; - if (len>count) len = count; - if (len<0) len = 0; + if (len>count) len = count; + if (len<0) len = 0; - return len; + return len; } -static struct proc_dir_entry *perfmon_dir; +static struct irqaction perfmon_irqaction = { + handler: perfmon_interrupt, + flags: SA_INTERRUPT, + name: "perfmon" +}; void __init perfmon_init (void) { pal_perf_mon_info_u_t pm_info; s64 status; - - irq_desc[PERFMON_IRQ].status |= IRQ_PER_CPU; - irq_desc[PERFMON_IRQ].handler = &irq_type_ia64_sapic; - setup_irq(PERFMON_IRQ, &perfmon_irqaction); - ia64_set_pmv(PERFMON_IRQ); + register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction); + + ia64_set_pmv(IA64_PERFMON_VECTOR); ia64_srlz_d(); - printk("perfmon: Initialized vector to %u\n",PERFMON_IRQ); + pmu_conf.pfm_is_disabled = 1; + + printk("perfmon: version %s\n", PFM_VERSION); + printk("perfmon: Interrupt vectored to %u\n", IA64_PERFMON_VECTOR); if ((status=ia64_pal_perf_mon_info(pmu_conf.impl_regs, &pm_info)) != 0) { - printk(__FUNCTION__ " pal call failed (%ld)\n", status); + printk("perfmon: PAL call failed (%ld)\n", status); return; - } - pmu_conf.perf_ovfl_val = (1L << pm_info.pal_perf_mon_info_s.width) - 1; - - /* XXX need to use PAL instead */ + } + pmu_conf.perf_ovfl_val = (1L << pm_info.pal_perf_mon_info_s.width) - 1; pmu_conf.max_counters = pm_info.pal_perf_mon_info_s.generic; + pmu_conf.num_pmds = find_num_pm_regs(pmu_conf.impl_regs); + pmu_conf.num_pmcs = find_num_pm_regs(&pmu_conf.impl_regs[4]); printk("perfmon: Counters are %d bits\n", pm_info.pal_perf_mon_info_s.width); printk("perfmon: Maximum counter value 0x%lx\n", pmu_conf.perf_ovfl_val); + printk("perfmon: %ld PMC/PMD pairs\n", pmu_conf.max_counters); + printk("perfmon: %ld PMCs, %ld PMDs\n", pmu_conf.num_pmcs, pmu_conf.num_pmds); + printk("perfmon: Sampling format v%d\n", PFM_SMPL_HDR_VERSION); + + /* sanity check */ + if (pmu_conf.num_pmds >= IA64_NUM_PMD_REGS || pmu_conf.num_pmcs >= IA64_NUM_PMC_REGS) { + printk(KERN_ERR "perfmon: ERROR not enough PMC/PMD storage in kernel, perfmon is DISABLED\n"); + return; /* no need to continue anyway */ + } + /* we are all set */ + pmu_conf.pfm_is_disabled = 0; + + /* + * Insert the tasklet in the list. + * It is still disabled at this point, so it won't run + printk(__FUNCTION__" tasklet is %p state=%d, count=%d\n", &perfmon_tasklet, perfmon_tasklet.state, perfmon_tasklet.count); + */ /* * for now here for debug purposes @@ -547,7 +1687,7 @@ void perfmon_init_percpu (void) { - ia64_set_pmv(PERFMON_IRQ); + ia64_set_pmv(IA64_PERFMON_VECTOR); ia64_srlz_d(); } @@ -555,14 +1695,19 @@ * XXX: for system wide this function MUST never be called */ void -ia64_save_pm_regs (struct task_struct *ta) +pfm_save_regs (struct task_struct *ta) { - struct thread_struct *t = &ta->thread; + struct task_struct *owner; + struct thread_struct *t; u64 pmc0, psr; - int i,j; + int i; + if (ta == NULL) { + panic(__FUNCTION__" task is NULL\n"); + } + t = &ta->thread; /* - * We must maek sure that we don't loose any potential overflow + * We must make sure that we don't loose any potential overflow * interrupt while saving PMU context. In this code, external * interrupts are always enabled. */ @@ -575,94 +1720,102 @@ /* * stop monitoring: * This is the only way to stop monitoring without destroying overflow - * information in PMC[0..3]. + * information in PMC[0]. * This is the last instruction which can cause overflow when monitoring * in kernel. - * By now, we could still have an overflow interrupt in flight. + * By now, we could still have an overflow interrupt in-flight. */ - __asm__ __volatile__ ("rsm psr.up;;"::: "memory"); - + __asm__ __volatile__ ("rum psr.up;;"::: "memory"); + + /* + * Mark the PMU as not owned + * This will cause the interrupt handler to do nothing in case an overflow + * interrupt was in-flight + * This also guarantees that pmc0 will contain the final state + * It virtually gives us full control over overflow processing from that point + * on. + * It must be an atomic operation. + */ + owner = PMU_OWNER(); + SET_PMU_OWNER(NULL); + /* * read current overflow status: * - * We may be reading stale information at this point, if we got interrupt - * just before the read(pmc0) but that's all right. However, if we did - * not get the interrupt before, this read reflects LAST state. - * + * we are guaranteed to read the final stable state */ - pmc0 = ia64_get_pmc(0); + ia64_srlz_d(); + pmc0 = ia64_get_pmc(0); /* slow */ /* * freeze PMU: * * This destroys the overflow information. This is required to make sure * next process does not start with monitoring on if not requested - * (PSR.up may not be enough). - * - * We could still get an overflow interrupt by now. However the handler - * will not do anything if is sees PMC[0].fr=1 but no overflow bits - * are set. So PMU will stay in frozen state. This implies that pmc0 - * will still be holding the correct unprocessed information. - * */ ia64_set_pmc(0, 1); ia64_srlz_d(); /* - * check for overflow bits set: + * Check for overflow bits and proceed manually if needed * - * If pmc0 reports PMU frozen, this means we have a pending overflow, - * therefore we invoke the handler. Handler is reentrant with regards - * to PMC[0] so it is safe to call it twice. - * - * IF pmc0 reports overflow, we need to reread current PMC[0] value - * in case the handler was invoked right after the first pmc0 read. - * it is was not invoked then pmc0==PMC[0], otherwise it's been invoked - * and overflow information has been processed, so we don't need to call. - * - * Test breakdown: - * - pmc0 & ~0x1: test if overflow happened - * - second part: check if current register reflects this as well. - * - * NOTE: testing for pmc0 & 0x1 is not enough has it would trigger call - * when PM_VALID and PMU.fr which is common when setting up registers - * just before actually starting monitors. - * - */ - if ((pmc0 & ~0x1) && ((pmc0=ia64_get_pmc(0)) &~0x1) ) { - printk(__FUNCTION__" Warning: pmc[0]=0x%lx\n", pmc0); - update_counters(pmc0); - /* - * XXX: not sure that's enough. the next task may still get the - * interrupt. - */ + * It is safe to call the interrupt handler now because it does + * not try to block the task right away. Instead it will set a + * flag and let the task proceed. The blocking will only occur + * next time the task exits from the kernel. + */ + if (pmc0 & ~0x1) { + if (owner != ta) printk(__FUNCTION__" owner=%p task=%p\n", (void *)owner, (void *)ta); + printk(__FUNCTION__" Warning: pmc[0]=0x%lx explicit call\n", pmc0); + + pmc0 = update_counters(owner, pmc0, NULL); + /* we will save the updated version of pmc0 */ } /* * restore PSR for context switch to save */ - __asm__ __volatile__ ("mov psr.l=%0;;"::"r"(psr): "memory"); + __asm__ __volatile__ ("mov psr.l=%0;; srlz.i;;"::"r"(psr): "memory"); + /* - * XXX: this will need to be extended beyong just counters + * XXX needs further optimization. + * Also must take holes into account */ - for (i=0,j=4; i< IA64_NUM_PMD_COUNTERS; i++,j++) { - t->pmd[i] = ia64_get_pmd(j); - t->pmc[i] = ia64_get_pmc(j); + for (i=0; i< pmu_conf.num_pmds; i++) { + t->pmd[i] = ia64_get_pmd(i); + } + + /* skip PMC[0], we handle it separately */ + for (i=1; i< pmu_conf.num_pmcs; i++) { + t->pmc[i] = ia64_get_pmc(i); } + /* - * PMU is frozen, PMU context is saved: nobody owns the PMU on this CPU - * At this point, we should not receive any pending interrupt from the - * 'switched out' task + * Throughout this code we could have gotten an overflow interrupt. It is transformed + * into a spurious interrupt as soon as we give up pmu ownership. */ - pmu_owners[smp_processor_id()] = NULL; } void -ia64_load_pm_regs (struct task_struct *ta) +pfm_load_regs (struct task_struct *ta) { struct thread_struct *t = &ta->thread; - int i,j; + pfm_context_t *ctx = ta->thread.pfm_context; + int i; + + /* + * XXX needs further optimization. + * Also must take holes into account + */ + for (i=0; i< pmu_conf.num_pmds; i++) { + ia64_set_pmd(i, t->pmd[i]); + } + + /* skip PMC[0] to avoid side effects */ + for (i=1; i< pmu_conf.num_pmcs; i++) { + ia64_set_pmc(i, t->pmc[i]); + } /* * we first restore ownership of the PMU to the 'soon to be current' @@ -670,26 +1823,277 @@ * of this function, we get an interrupt, we attribute it to the correct * task */ - pmu_owners[smp_processor_id()] = ta; + SET_PMU_OWNER(ta); + +#if 0 + /* + * check if we had pending overflow before context switching out + * If so, we invoke the handler manually, i.e. simulate interrupt. + * + * XXX: given that we do not use the tasklet anymore to stop, we can + * move this back to the pfm_save_regs() routine. + */ + if (t->pmc[0] & ~0x1) { + /* freeze set in pfm_save_regs() */ + DBprintk((" pmc[0]=0x%lx manual interrupt\n",t->pmc[0])); + update_counters(ta, t->pmc[0], NULL); + } +#endif /* - * XXX: this will need to be extended beyong just counters + * unfreeze only when possible */ - for (i=0,j=4; i< IA64_NUM_PMD_COUNTERS; i++,j++) { - ia64_set_pmd(j, t->pmd[i]); - ia64_set_pmc(j, t->pmc[i]); + if (ctx->ctx_fl_frozen == 0) { + ia64_set_pmc(0, 0); + ia64_srlz_d(); + } +} + + +/* + * This function is called when a thread exits (from exit_thread()). + * This is a simplified pfm_save_regs() that simply flushes hthe current + * register state into the save area taking into account any pending + * overflow. This time no notification is sent because the taks is dying + * anyway. The inline processing of overflows avoids loosing some counts. + * The PMU is frozen on exit from this call and is to never be reenabled + * again for this task. + */ +void +pfm_flush_regs (struct task_struct *ta) +{ + pfm_context_t *ctx; + u64 pmc0, psr, mask; + int i,j; + + if (ta == NULL) { + panic(__FUNCTION__" task is NULL\n"); } + ctx = ta->thread.pfm_context; + if (ctx == NULL) { + panic(__FUNCTION__" no PFM ctx is NULL\n"); + } + /* + * We must make sure that we don't loose any potential overflow + * interrupt while saving PMU context. In this code, external + * interrupts are always enabled. + */ + + /* + * save current PSR: needed because we modify it + */ + __asm__ __volatile__ ("mov %0=psr;;": "=r"(psr) :: "memory"); + + /* + * stop monitoring: + * This is the only way to stop monitoring without destroying overflow + * information in PMC[0]. + * This is the last instruction which can cause overflow when monitoring + * in kernel. + * By now, we could still have an overflow interrupt in-flight. + */ + __asm__ __volatile__ ("rsm psr.up;;"::: "memory"); + + /* + * Mark the PMU as not owned + * This will cause the interrupt handler to do nothing in case an overflow + * interrupt was in-flight + * This also guarantees that pmc0 will contain the final state + * It virtually gives us full control on overflow processing from that point + * on. + * It must be an atomic operation. + */ + SET_PMU_OWNER(NULL); + + /* + * read current overflow status: + * + * we are guaranteed to read the final stable state + */ + ia64_srlz_d(); + pmc0 = ia64_get_pmc(0); /* slow */ + + /* + * freeze PMU: + * + * This destroys the overflow information. This is required to make sure + * next process does not start with monitoring on if not requested + */ + ia64_set_pmc(0, 1); + ia64_srlz_d(); + + /* + * restore PSR for context switch to save + */ + __asm__ __volatile__ ("mov psr.l=%0;;srlz.i;"::"r"(psr): "memory"); + /* - * unfreeze PMU + * This loop flushes the PMD into the PFM context. + * IT also processes overflow inline. + * + * IMPORTANT: No notification is sent at this point as the process is dying. + * The implicit notification will come from a SIGCHILD or a return from a + * waitpid(). + * + * XXX: must take holes into account */ - ia64_set_pmc(0, 0); + mask = pmc0 >> PMU_FIRST_COUNTER; + for (i=0,j=PMU_FIRST_COUNTER; i< pmu_conf.max_counters; i++,j++) { + + /* collect latest results */ + ctx->ctx_pmds[i].val += ia64_get_pmd(j) & pmu_conf.perf_ovfl_val; + + /* take care of overflow inline */ + if (mask & 0x1) { + ctx->ctx_pmds[i].val += 1 + pmu_conf.perf_ovfl_val; + DBprintk((" PMD[%d] overflowed pmd=0x%lx pmds.val=0x%lx\n", + j, ia64_get_pmd(j), ctx->ctx_pmds[i].val)); + } + } +} + +/* + * XXX: this routine is not very portable for PMCs + * XXX: make this routine able to work with non current context + */ +static void +ia64_reset_pmu(void) +{ + int i; + + /* PMU is frozen, no pending overflow bits */ + ia64_set_pmc(0,1); + + /* extra overflow bits + counter configs cleared */ + for(i=1; i< PMU_FIRST_COUNTER + pmu_conf.max_counters ; i++) { + ia64_set_pmc(i,0); + } + + /* opcode matcher set to all 1s */ + ia64_set_pmc(8,~0); + ia64_set_pmc(9,~0); + + /* I-EAR config cleared, plm=0 */ + ia64_set_pmc(10,0); + + /* D-EAR config cleared, PMC[11].pt must be 1 */ + ia64_set_pmc(11,1 << 28); + + /* BTB config. plm=0 */ + ia64_set_pmc(12,0); + + /* Instruction address range, PMC[13].ta must be 1 */ + ia64_set_pmc(13,1); + + /* clears all PMD registers */ + for(i=0;i< pmu_conf.num_pmds; i++) { + if (PMD_IS_IMPL(i)) ia64_set_pmd(i,0); + } ia64_srlz_d(); } +/* + * task is the newly created task + */ +int +pfm_inherit(struct task_struct *task) +{ + pfm_context_t *ctx = current->thread.pfm_context; + pfm_context_t *nctx; + struct thread_struct *th = &task->thread; + int i, cnum; + + /* + * takes care of easiest case first + */ + if (CTX_INHERIT_MODE(ctx) == PFM_FL_INHERIT_NONE) { + DBprintk((" removing PFM context for %d\n", task->pid)); + task->thread.pfm_context = NULL; + task->thread.pfm_pend_notify = 0; + /* copy_thread() clears IA64_THREAD_PM_VALID */ + return 0; + } + nctx = pfm_context_alloc(); + if (nctx == NULL) return -ENOMEM; + + /* copy content */ + *nctx = *ctx; + + if (ctx->ctx_fl_inherit == PFM_FL_INHERIT_ONCE) { + nctx->ctx_fl_inherit = PFM_FL_INHERIT_NONE; + DBprintk((" downgrading to INHERIT_NONE for %d\n", task->pid)); + } + + /* initialize counters in new context */ + for(i=0, cnum= PMU_FIRST_COUNTER; i < pmu_conf.max_counters; cnum++, i++) { + nctx->ctx_pmds[i].val = nctx->ctx_pmds[i].ival & ~pmu_conf.perf_ovfl_val; + th->pmd[cnum] = nctx->ctx_pmds[i].ival & pmu_conf.perf_ovfl_val; + + } + /* clear BTB index register */ + th->pmd[16] = 0; + + /* if sampling then increment number of users of buffer */ + if (nctx->ctx_smpl_buf) { + atomic_inc(&nctx->ctx_smpl_buf->psb_refcnt); + } + + nctx->ctx_fl_frozen = 0; + nctx->ctx_ovfl_regs = 0; + sema_init(&nctx->ctx_restart_sem, 0); /* reset this semaphore to locked */ + + /* clear pending notification */ + th->pfm_pend_notify = 0; + + /* link with new task */ + th->pfm_context = nctx; + + DBprintk((" nctx=%p for process %d\n", (void *)nctx, task->pid)); + + /* + * the copy_thread routine automatically clears + * IA64_THREAD_PM_VALID, so we need to reenable it, if it was used by the caller + */ + if (current->thread.flags & IA64_THREAD_PM_VALID) { + DBprintk((" setting PM_VALID for %d\n", task->pid)); + th->flags |= IA64_THREAD_PM_VALID; + } + + return 0; +} + +/* called from exit_thread() */ +void +pfm_context_exit(struct task_struct *task) +{ + pfm_context_t *ctx = task->thread.pfm_context; + + if (!ctx) { + DBprintk((" invalid context for %d\n", task->pid)); + return; + } + + /* check is we have a sampling buffer attached */ + if (ctx->ctx_smpl_buf) { + pfm_smpl_buffer_desc_t *psb = ctx->ctx_smpl_buf; + + /* if only user left, then remove */ + DBprintk((" pid %d: task %d sampling psb->refcnt=%d\n", current->pid, task->pid, psb->psb_refcnt.counter)); + + if (atomic_dec_and_test(&psb->psb_refcnt) ) { + rvfree(psb->psb_hdr, psb->psb_size); + vfree(psb); + DBprintk((" pid %d: cleaning task %d sampling buffer\n", current->pid, task->pid )); + } + } + DBprintk((" pid %d: task %d pfm_context is freed @%p\n", current->pid, task->pid, (void *)ctx)); + pfm_context_free(ctx); +} + #else /* !CONFIG_PERFMON */ -asmlinkage unsigned long -sys_perfmonctl (int cmd, int count, void *ptr) +asmlinkage int +sys_perfmonctl (int pid, int cmd, int flags, perfmon_req_t *req, int count, long arg6, long arg7, long arg8, long stack) { return -ENOSYS; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/process.c linux.ac/arch/ia64/kernel/process.c --- linux.vanilla/arch/ia64/kernel/process.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/process.c Mon Apr 16 12:37:03 2001 @@ -1,8 +1,8 @@ /* * Architecture-specific setup. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #define __KERNEL_SYSCALLS__ /* see <asm/unistd.h> */ #include <linux/config.h> @@ -20,6 +20,7 @@ #include <asm/delay.h> #include <asm/efi.h> +#include <asm/perfmon.h> #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/sal.h> @@ -27,8 +28,6 @@ #include <asm/unwind.h> #include <asm/user.h> -#ifdef CONFIG_IA64_NEW_UNWIND - static void do_show_stack (struct unw_frame_info *info, void *arg) { @@ -46,12 +45,9 @@ } while (unw_unwind(info) >= 0); } -#endif - void show_stack (struct task_struct *task) { -#ifdef CONFIG_IA64_NEW_UNWIND if (!task) unw_init_running(do_show_stack, 0); else { @@ -60,7 +56,6 @@ unw_init_from_blocked_task(&info, task); do_show_stack(&info, 0); } -#endif } void @@ -108,10 +103,8 @@ ((i == sof - 1) || (i % 3) == 2) ? "\n" : " "); } } -#ifdef CONFIG_IA64_NEW_UNWIND if (!user_mode(regs)) show_stack(0); -#endif } void __attribute__((noreturn)) @@ -147,7 +140,7 @@ ia64_save_debug_regs(&task->thread.dbr[0]); #ifdef CONFIG_PERFMON if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0) - ia64_save_pm_regs(task); + pfm_save_regs(task); #endif if (IS_IA32_PROCESS(ia64_task_regs(task))) ia32_save_state(&task->thread); @@ -160,7 +153,7 @@ ia64_load_debug_regs(&task->thread.dbr[0]); #ifdef CONFIG_PERFMON if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0) - ia64_load_pm_regs(task); + pfm_load_regs(task); #endif if (IS_IA32_PROCESS(ia64_task_regs(task))) ia32_load_state(&task->thread); @@ -210,6 +203,7 @@ struct switch_stack *child_stack, *stack; extern char ia64_ret_from_clone; struct pt_regs *child_ptregs; + int retval = 0; #ifdef CONFIG_SMP /* @@ -290,15 +284,17 @@ if (IS_IA32_PROCESS(ia64_task_regs(current))) ia32_save_state(&p->thread); #endif - return 0; +#ifdef CONFIG_PERFMON + if (current->thread.pfm_context) + retval = pfm_inherit(p); +#endif + return retval; } -#ifdef CONFIG_IA64_NEW_UNWIND - void do_copy_regs (struct unw_frame_info *info, void *arg) { - unsigned long ar_bsp, ndirty, *krbs, addr, mask, sp, nat_bits = 0, ip; + unsigned long ar_bsp, addr, mask, sp, nat_bits = 0, ip, ar_rnat; elf_greg_t *dst = arg; struct pt_regs *pt; char nat; @@ -313,18 +309,18 @@ unw_get_sp(info, &sp); pt = (struct pt_regs *) (sp + 16); - krbs = (unsigned long *) current + IA64_RBS_OFFSET/8; - ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19)); - ar_bsp = (unsigned long) ia64_rse_skip_regs((long *) pt->ar_bspstore, ndirty); + ar_bsp = ia64_get_user_bsp(current, pt); /* - * Write portion of RSE backing store living on the kernel - * stack to the VM of the process. + * Write portion of RSE backing store living on the kernel stack to the VM of the + * process. */ for (addr = pt->ar_bspstore; addr < ar_bsp; addr += 8) - if (ia64_peek(pt, current, addr, &val) == 0) + if (ia64_peek(current, ar_bsp, addr, &val) == 0) access_process_vm(current, addr, &val, sizeof(val), 1); + ia64_peek(current, ar_bsp, (long) ia64_rse_rnat_addr((long *) addr - 1), &ar_rnat); + /* * coredump format: * r0-r31 @@ -361,7 +357,7 @@ */ dst[46] = ar_bsp; dst[47] = pt->ar_bspstore; - unw_get_ar(info, UNW_AR_RNAT, &dst[48]); + dst[48] = ar_rnat; unw_get_ar(info, UNW_AR_CCV, &dst[49]); unw_get_ar(info, UNW_AR_UNAT, &dst[50]); unw_get_ar(info, UNW_AR_FPSR, &dst[51]); @@ -391,91 +387,16 @@ memcpy(dst + 32, current->thread.fph, 96*16); } -#endif /* CONFIG_IA64_NEW_UNWIND */ - void ia64_elf_core_copy_regs (struct pt_regs *pt, elf_gregset_t dst) { -#ifdef CONFIG_IA64_NEW_UNWIND unw_init_running(do_copy_regs, dst); -#else - struct switch_stack *sw = ((struct switch_stack *) pt) - 1; - unsigned long ar_ec, cfm, ar_bsp, ndirty, *krbs, addr; - - ar_ec = (sw->ar_pfs >> 52) & 0x3f; - - cfm = pt->cr_ifs & ((1UL << 63) - 1); - if ((pt->cr_ifs & (1UL << 63)) == 0) { - /* if cr_ifs isn't valid, we got here through a syscall or a break */ - cfm = sw->ar_pfs & ((1UL << 38) - 1); - } - - krbs = (unsigned long *) current + IA64_RBS_OFFSET/8; - ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19)); - ar_bsp = (unsigned long) ia64_rse_skip_regs((long *) pt->ar_bspstore, ndirty); - - /* - * Write portion of RSE backing store living on the kernel - * stack to the VM of the process. - */ - for (addr = pt->ar_bspstore; addr < ar_bsp; addr += 8) { - long val; - if (ia64_peek(pt, current, addr, &val) == 0) - access_process_vm(current, addr, &val, sizeof(val), 1); - } - - /* r0-r31 - * NaT bits (for r0-r31; bit N == 1 iff rN is a NaT) - * predicate registers (p0-p63) - * b0-b7 - * ip cfm user-mask - * ar.rsc ar.bsp ar.bspstore ar.rnat - * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec - */ - memset(dst, 0, sizeof(dst)); /* don't leak any "random" bits */ - - /* r0 is zero */ dst[ 1] = pt->r1; dst[ 2] = pt->r2; dst[ 3] = pt->r3; - dst[ 4] = sw->r4; dst[ 5] = sw->r5; dst[ 6] = sw->r6; dst[ 7] = sw->r7; - dst[ 8] = pt->r8; dst[ 9] = pt->r9; dst[10] = pt->r10; dst[11] = pt->r11; - dst[12] = pt->r12; dst[13] = pt->r13; dst[14] = pt->r14; dst[15] = pt->r15; - memcpy(dst + 16, &pt->r16, 16*8); /* r16-r31 are contiguous */ - - dst[32] = ia64_get_nat_bits(pt, sw); - dst[33] = pt->pr; - - /* branch regs: */ - dst[34] = pt->b0; dst[35] = sw->b1; dst[36] = sw->b2; dst[37] = sw->b3; - dst[38] = sw->b4; dst[39] = sw->b5; dst[40] = pt->b6; dst[41] = pt->b7; - - dst[42] = pt->cr_iip + ia64_psr(pt)->ri; - dst[43] = pt->cr_ifs; - dst[44] = pt->cr_ipsr & IA64_PSR_UM; - - dst[45] = pt->ar_rsc; dst[46] = ar_bsp; dst[47] = pt->ar_bspstore; dst[48] = pt->ar_rnat; - dst[49] = pt->ar_ccv; dst[50] = pt->ar_unat; dst[51] = sw->ar_fpsr; dst[52] = pt->ar_pfs; - dst[53] = sw->ar_lc; dst[54] = (sw->ar_pfs >> 52) & 0x3f; -#endif /* !CONFIG_IA64_NEW_UNWIND */ } int dump_fpu (struct pt_regs *pt, elf_fpregset_t dst) { -#ifdef CONFIG_IA64_NEW_UNWIND unw_init_running(do_dump_fpu, dst); -#else - struct switch_stack *sw = ((struct switch_stack *) pt) - 1; - - memset(dst, 0, sizeof (dst)); /* don't leak any "random" bits */ - - /* f0 is 0.0 */ /* f1 is 1.0 */ dst[2] = sw->f2; dst[3] = sw->f3; - dst[4] = sw->f4; dst[5] = sw->f5; dst[6] = pt->f6; dst[7] = pt->f7; - dst[8] = pt->f8; dst[9] = pt->f9; - memcpy(dst + 10, &sw->f10, 22*16); /* f10-f31 are contiguous */ - - ia64_flush_fph(current); - if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0) - memcpy(dst + 32, current->thread.fph, 96*16); -#endif return 1; /* f0-f31 are always valid so we always return 1 */ } @@ -523,6 +444,15 @@ #endif } +#ifdef CONFIG_PERFMON +void +release_thread (struct task_struct *task) +{ + if (task->thread.pfm_context) + pfm_context_exit(task); +} +#endif + /* * Clean up state associated with current thread. This is called when * the thread calls exit(). @@ -545,7 +475,7 @@ * we garantee no race. this call we also stop * monitoring */ - ia64_save_pm_regs(current); + pfm_flush_regs(current); /* * make sure that switch_to() will not save context again */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/ptrace.c linux.ac/arch/ia64/kernel/ptrace.c --- linux.vanilla/arch/ia64/kernel/ptrace.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/ia64/kernel/ptrace.c Tue Apr 10 18:08:40 2001 @@ -1,8 +1,8 @@ /* * Kernel support for the ptrace() and syscall tracing interfaces. * - * Copyright (C) 1999-2000 Hewlett-Packard Co - * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> * * Derived from the x86 and Alpha versions. Most of the code in here * could actually be factored into a common set of routines. @@ -22,6 +22,7 @@ #include <asm/rse.h> #include <asm/system.h> #include <asm/uaccess.h> +#include <asm/unwind.h> /* * Bits in the PSR that we allow ptrace() to change: @@ -36,8 +37,6 @@ (IA64_PSR_UM | IA64_PSR_DB | IA64_PSR_IS | IA64_PSR_ID | IA64_PSR_DD | IA64_PSR_RI) #define IPSR_READ_MASK IPSR_WRITE_MASK -#ifdef CONFIG_IA64_NEW_UNWIND - #define PTRACE_DEBUG 1 #if PTRACE_DEBUG @@ -97,57 +96,6 @@ # undef PUT_BITS } -#else /* !CONFIG_IA64_NEW_UNWIND */ - -/* - * Collect the NaT bits for r1-r31 from sw->caller_unat and - * sw->ar_unat and return a NaT bitset where bit i is set iff the NaT - * bit of register i is set. - */ -long -ia64_get_nat_bits (struct pt_regs *pt, struct switch_stack *sw) -{ -# define GET_BITS(str, first, last, unat) \ - ({ \ - unsigned long bit = ia64_unat_pos(&str->r##first); \ - unsigned long mask = ((1UL << (last - first + 1)) - 1) << first; \ - (ia64_rotl(unat, first) >> bit) & mask; \ - }) - unsigned long val; - - val = GET_BITS(pt, 1, 3, sw->caller_unat); - val |= GET_BITS(pt, 12, 15, sw->caller_unat); - val |= GET_BITS(pt, 8, 11, sw->caller_unat); - val |= GET_BITS(pt, 16, 31, sw->caller_unat); - val |= GET_BITS(sw, 4, 7, sw->ar_unat); - return val; - -# undef GET_BITS -} - -/* - * Store the NaT bitset NAT in pt->caller_unat and sw->ar_unat. - */ -void -ia64_put_nat_bits (struct pt_regs *pt, struct switch_stack *sw, unsigned long nat) -{ -# define PUT_BITS(str, first, last, nat) \ - ({ \ - unsigned long bit = ia64_unat_pos(&str->r##first); \ - unsigned long mask = ((1UL << (last - first + 1)) - 1) << bit; \ - (ia64_rotr(nat, first) << bit) & mask; \ - }) - sw->caller_unat = PUT_BITS(pt, 1, 3, nat); - sw->caller_unat |= PUT_BITS(pt, 12, 15, nat); - sw->caller_unat |= PUT_BITS(pt, 8, 11, nat); - sw->caller_unat |= PUT_BITS(pt, 16, 31, nat); - sw->ar_unat = PUT_BITS(sw, 4, 7, nat); - -# undef PUT_BITS -} - -#endif /* !CONFIG_IA64_NEW_UNWIND */ - #define IA64_MLX_TEMPLATE 0x2 #define IA64_MOVL_OPCODE 6 @@ -215,7 +163,7 @@ * | slot01 | > child_regs->ar_rnat * +--------+ | * | slot02 | / kernel rbs - * +--------+ +--------+ + * +--------+ +--------+ * <- child_regs->ar_bspstore | slot61 | <-- krbs * +- - - - + +--------+ * | slot62 | @@ -275,7 +223,7 @@ /* some bits need to be merged in from pt->ar_rnat */ kmask = ~((1UL << ia64_rse_slot_num(ubspstore)) - 1); urnat = (pt->ar_rnat & ~kmask); - } + } if (rnat0_kaddr >= kbsp) { rnat0 = sw->ar_rnat; } else if (rnat0_kaddr > krbs) { @@ -319,7 +267,7 @@ /* some bits need to be place in pt->ar_rnat: */ kmask = ~((1UL << ia64_rse_slot_num(ubspstore)) - 1); pt->ar_rnat = (pt->ar_rnat & kmask) | (rnat & ~kmask); - } + } /* * Note: Section 11.1 of the EAS guarantees that bit 63 of an * rnat slot is ignored. so we don't have to clear it here. @@ -342,9 +290,9 @@ } long -ia64_peek (struct pt_regs *regs, struct task_struct *child, unsigned long addr, long *val) +ia64_peek (struct task_struct *child, unsigned long user_bsp, unsigned long addr, long *val) { - unsigned long *bspstore, *krbs, krbs_num_regs, regnum, *rbs_end, *laddr; + unsigned long *bspstore, *krbs, regnum, *laddr, *ubsp = (long *) user_bsp; struct switch_stack *child_stack; struct pt_regs *child_regs; size_t copied; @@ -352,35 +300,22 @@ laddr = (unsigned long *) addr; child_regs = ia64_task_regs(child); -#ifdef CONFIG_IA64_NEW_UNWIND child_stack = (struct switch_stack *) (child->thread.ksp + 16); -#else - child_stack = (struct switch_stack *) child_regs - 1; -#endif bspstore = (unsigned long *) child_regs->ar_bspstore; krbs = (unsigned long *) child + IA64_RBS_OFFSET/8; - krbs_num_regs = ia64_rse_num_regs(krbs, (unsigned long *) child_stack->ar_bspstore); - rbs_end = ia64_rse_skip_regs(bspstore, krbs_num_regs); - if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(rbs_end)) { + if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(ubsp)) { /* - * Attempt to read the RBS in an area that's actually - * on the kernel RBS => read the corresponding bits in - * the kernel RBS. + * Attempt to read the RBS in an area that's actually on the kernel RBS => + * read the corresponding bits in the kernel RBS. */ if (ia64_rse_is_rnat_slot(laddr)) ret = get_rnat(child_regs, child_stack, krbs, laddr); else { - regnum = ia64_rse_num_regs(bspstore, laddr); - laddr = ia64_rse_skip_regs(krbs, regnum); - if (regnum >= krbs_num_regs) { + if (laddr >= ubsp) ret = 0; - } else { - if ((unsigned long) laddr >= (unsigned long) high_memory) { - printk("yikes: trying to access long at %p\n", - (void *) laddr); - return -EIO; - } - ret = *laddr; + else { + regnum = ia64_rse_num_regs(bspstore, laddr); + ret = *ia64_rse_skip_regs(krbs, regnum); } } } else { @@ -393,36 +328,28 @@ } long -ia64_poke (struct pt_regs *regs, struct task_struct *child, unsigned long addr, long val) +ia64_poke (struct task_struct *child, unsigned long user_bsp, unsigned long addr, long val) { - unsigned long *bspstore, *krbs, krbs_num_regs, regnum, *rbs_end, *laddr; + unsigned long *bspstore, *krbs, regnum, *laddr, *ubsp = (long *) user_bsp; struct switch_stack *child_stack; struct pt_regs *child_regs; laddr = (unsigned long *) addr; child_regs = ia64_task_regs(child); -#ifdef CONFIG_IA64_NEW_UNWIND child_stack = (struct switch_stack *) (child->thread.ksp + 16); -#else - child_stack = (struct switch_stack *) child_regs - 1; -#endif bspstore = (unsigned long *) child_regs->ar_bspstore; krbs = (unsigned long *) child + IA64_RBS_OFFSET/8; - krbs_num_regs = ia64_rse_num_regs(krbs, (unsigned long *) child_stack->ar_bspstore); - rbs_end = ia64_rse_skip_regs(bspstore, krbs_num_regs); - if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(rbs_end)) { + if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(ubsp)) { /* - * Attempt to write the RBS in an area that's actually - * on the kernel RBS => write the corresponding bits - * in the kernel RBS. + * Attempt to write the RBS in an area that's actually on the kernel RBS + * => write the corresponding bits in the kernel RBS. */ if (ia64_rse_is_rnat_slot(laddr)) put_rnat(child_regs, child_stack, krbs, laddr, val); else { - regnum = ia64_rse_num_regs(bspstore, laddr); - laddr = ia64_rse_skip_regs(krbs, regnum); - if (regnum < krbs_num_regs) { - *laddr = val; + if (laddr < ubsp) { + regnum = ia64_rse_num_regs(bspstore, laddr); + *ia64_rse_skip_regs(krbs, regnum) = val; } } } else if (access_process_vm(child, addr, &val, sizeof(val), 1) != sizeof(val)) { @@ -432,83 +359,76 @@ } /* - * Synchronize (i.e, write) the RSE backing store living in kernel - * space to the VM of the indicated child process. - * - * If new_bsp is non-zero, the bsp will (effectively) be updated to - * the new value upon resumption of the child process. This is - * accomplished by setting the loadrs value to zero and the bspstore - * value to the new bsp value. - * - * When new_bsp and force_loadrs_to_zero are both 0, the register - * backing store in kernel space is written to user space and the - * loadrs and bspstore values are left alone. - * - * When new_bsp is zero and force_loadrs_to_zero is 1 (non-zero), - * loadrs is set to 0, and the bspstore value is set to the old bsp - * value. This will cause the stacked registers (r32 and up) to be - * obtained entirely from the child's memory space rather than - * from the kernel. (This makes it easier to write code for - * modifying the stacked registers in multi-threaded programs.) - * - * Note: I had originally written this function without the - * force_loadrs_to_zero parameter; it was written so that loadrs would - * always be set to zero. But I had problems with certain system - * calls apparently causing a portion of the RBS to be zeroed. (I - * still don't understand why this was happening.) Anyway, it'd - * definitely less intrusive to leave loadrs and bspstore alone if - * possible. + * Calculate the user-level address that would have been in ar.bsp had the user executed a + * "cover" instruction right before entering the kernel. */ -static long -sync_kernel_register_backing_store (struct task_struct *child, - long new_bsp, - int force_loadrs_to_zero) +unsigned long +ia64_get_user_bsp (struct task_struct *child, struct pt_regs *pt) { - unsigned long *krbs, bspstore, *kbspstore, bsp, rbs_end, addr, val; - long ndirty, ret = 0; - struct pt_regs *child_regs = ia64_task_regs(child); - -#ifdef CONFIG_IA64_NEW_UNWIND + unsigned long *krbs, *bspstore, cfm; struct unw_frame_info info; - unsigned long cfm, sof; - - unw_init_from_blocked_task(&info, child); - if (unw_unwind_to_user(&info) < 0) - return -1; - - unw_get_bsp(&info, (unsigned long *) &kbspstore); + long ndirty; krbs = (unsigned long *) child + IA64_RBS_OFFSET/8; - ndirty = ia64_rse_num_regs(krbs, krbs + (child_regs->loadrs >> 19)); - bspstore = child_regs->ar_bspstore; - bsp = (long) ia64_rse_skip_regs((long *)bspstore, ndirty); - - cfm = child_regs->cr_ifs; - if (!(cfm & (1UL << 63))) - unw_get_cfm(&info, &cfm); - sof = (cfm & 0x7f); - rbs_end = (long) ia64_rse_skip_regs((long *)bspstore, sof); -#else - struct switch_stack *child_stack; - unsigned long krbs_num_regs; + bspstore = (unsigned long *) pt->ar_bspstore; + ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19)); - child_stack = (struct switch_stack *) child_regs - 1; - kbspstore = (unsigned long *) child_stack->ar_bspstore; - krbs = (unsigned long *) child + IA64_RBS_OFFSET/8; - ndirty = ia64_rse_num_regs(krbs, krbs + (child_regs->loadrs >> 19)); - bspstore = child_regs->ar_bspstore; - bsp = (long) ia64_rse_skip_regs((long *)bspstore, ndirty); - krbs_num_regs = ia64_rse_num_regs(krbs, kbspstore); - rbs_end = (long) ia64_rse_skip_regs((long *)bspstore, krbs_num_regs); -#endif + if ((long) pt->cr_ifs >= 0) { + /* + * If bit 63 of cr.ifs is cleared, the kernel was entered via a system + * call and we need to recover the CFM that existed on entry to the + * kernel by unwinding the kernel stack. + */ + unw_init_from_blocked_task(&info, child); + if (unw_unwind_to_user(&info) == 0) { + unw_get_cfm(&info, &cfm); + ndirty += (cfm & 0x7f); + } + } + return (unsigned long) ia64_rse_skip_regs(bspstore, ndirty); +} - /* Return early if nothing to do */ - if (bsp == new_bsp) +/* + * Synchronize (i.e, write) the RSE backing store living in kernel space to the VM of the + * indicated child process. + * + * If new_bsp is non-zero, the bsp will (effectively) be updated to the new value upon + * resumption of the child process. This is accomplished by setting the loadrs value to + * zero and the bspstore value to the new bsp value. + * + * When new_bsp and flush_user_rbs are both 0, the register backing store in kernel space + * is written to user space and the loadrs and bspstore values are left alone. + * + * When new_bsp is zero and flush_user_rbs is 1 (non-zero), loadrs is set to 0, and the + * bspstore value is set to the old bsp value. This will cause the stacked registers (r32 + * and up) to be obtained entirely from the child's memory space rather than from the + * kernel. (This makes it easier to write code for modifying the stacked registers in + * multi-threaded programs.) + * + * Note: I had originally written this function without the flush_user_rbs parameter; it + * was written so that loadrs would always be set to zero. But I had problems with + * certain system calls apparently causing a portion of the RBS to be zeroed. (I still + * don't understand why this was happening.) Anyway, it'd definitely less intrusive to + * leave loadrs and bspstore alone if possible. + */ +static long +sync_kernel_register_backing_store (struct task_struct *child, long user_bsp, long new_bsp, + int flush_user_rbs) +{ + struct pt_regs *child_regs = ia64_task_regs(child); + unsigned long addr, val; + long ret; + + /* + * Return early if nothing to do. Note that new_bsp will be zero if the caller + * wants to force synchronization without changing bsp. + */ + if (user_bsp == new_bsp) return 0; /* Write portion of backing store living on kernel stack to the child's VM. */ - for (addr = bspstore; addr < rbs_end; addr += 8) { - ret = ia64_peek(child_regs, child, addr, &val); + for (addr = child_regs->ar_bspstore; addr < user_bsp; addr += 8) { + ret = ia64_peek(child, user_bsp, addr, &val); if (ret != 0) return ret; if (access_process_vm(child, addr, &val, sizeof(val), 1) != sizeof(val)) @@ -516,27 +436,26 @@ } if (new_bsp != 0) { - force_loadrs_to_zero = 1; - bsp = new_bsp; + flush_user_rbs = 1; + user_bsp = new_bsp; } - if (force_loadrs_to_zero) { + if (flush_user_rbs) { child_regs->loadrs = 0; - child_regs->ar_bspstore = bsp; + child_regs->ar_bspstore = user_bsp; } - - return ret; + return 0; } static void -sync_thread_rbs (struct task_struct *child, struct mm_struct *mm, int make_writable) +sync_thread_rbs (struct task_struct *child, long bsp, struct mm_struct *mm, int make_writable) { struct task_struct *p; read_lock(&tasklist_lock); { for_each_task(p) { if (p->mm == mm && p->state != TASK_RUNNING) - sync_kernel_register_backing_store(p, 0, make_writable); + sync_kernel_register_backing_store(p, bsp, 0, make_writable); } } read_unlock(&tasklist_lock); @@ -588,10 +507,6 @@ psr->dfh = 1; } -#ifdef CONFIG_IA64_NEW_UNWIND - -#include <asm/unwind.h> - static int access_fr (struct unw_frame_info *info, int regnum, int hi, unsigned long *data, int write_access) { @@ -613,7 +528,7 @@ static int access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data, int write_access) { - unsigned long *ptr, *rbs, *bspstore, ndirty, regnum; + unsigned long *ptr, regnum, bsp, rnat_addr; struct switch_stack *sw; struct unw_frame_info info; struct pt_regs *pt; @@ -710,36 +625,16 @@ /* scratch state */ switch (addr) { case PT_AR_BSP: + bsp = ia64_get_user_bsp(child, pt); if (write_access) - /* FIXME? Account for lack of ``cover'' in the syscall case */ - return sync_kernel_register_backing_store(child, *data, 1); + return sync_kernel_register_backing_store(child, bsp, *data, 1); else { - rbs = (unsigned long *) child + IA64_RBS_OFFSET/8; - bspstore = (unsigned long *) pt->ar_bspstore; - ndirty = ia64_rse_num_regs(rbs, rbs + (pt->loadrs >> 19)); - - /* - * If we're in a system call, no ``cover'' was done. So to - * make things uniform, we'll add the appropriate displacement - * onto bsp if we're in a system call. - */ - if (!(pt->cr_ifs & (1UL << 63))) { - struct unw_frame_info info; - unsigned long cfm; - - unw_init_from_blocked_task(&info, child); - if (unw_unwind_to_user(&info) < 0) - return -1; - - unw_get_cfm(&info, &cfm); - ndirty += cfm & 0x7f; - } - *data = (unsigned long) ia64_rse_skip_regs(bspstore, ndirty); + *data = bsp; return 0; } case PT_CFM: - if (pt->cr_ifs & (1UL << 63)) { + if ((long) pt->cr_ifs < 0) { if (write_access) pt->cr_ifs = ((pt->cr_ifs & ~0x3fffffffffUL) | (*data & 0x3fffffffffUL)); @@ -770,7 +665,15 @@ *data = (pt->cr_ipsr & IPSR_READ_MASK); return 0; - case PT_R1: case PT_R2: case PT_R3: + case PT_AR_RNAT: + bsp = ia64_get_user_bsp(child, pt); + rnat_addr = (long) ia64_rse_rnat_addr((long *) bsp - 1); + if (write_access) + return ia64_poke(child, bsp, rnat_addr, *data); + else + return ia64_peek(child, bsp, rnat_addr, data); + + case PT_R1: case PT_R2: case PT_R3: case PT_R8: case PT_R9: case PT_R10: case PT_R11: case PT_R12: case PT_R13: case PT_R14: case PT_R15: case PT_R16: case PT_R17: case PT_R18: case PT_R19: @@ -781,7 +684,7 @@ case PT_F6: case PT_F6+8: case PT_F7: case PT_F7+8: case PT_F8: case PT_F8+8: case PT_F9: case PT_F9+8: case PT_AR_BSPSTORE: - case PT_AR_RSC: case PT_AR_UNAT: case PT_AR_PFS: case PT_AR_RNAT: + case PT_AR_RSC: case PT_AR_UNAT: case PT_AR_PFS: case PT_AR_CCV: case PT_AR_FPSR: case PT_CR_IIP: case PT_PR: /* scratch register */ ptr = (unsigned long *) ((long) pt + addr - PT_CR_IPSR); @@ -799,7 +702,7 @@ if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) { child->thread.flags |= IA64_THREAD_DBG_VALID; memset(child->thread.dbr, 0, sizeof(child->thread.dbr)); - memset(child->thread.ibr, 0, sizeof( child->thread.ibr)); + memset(child->thread.ibr, 0, sizeof(child->thread.ibr)); } if (addr >= PT_IBR) { regnum = (addr - PT_IBR) >> 3; @@ -830,173 +733,13 @@ return 0; } -#else /* !CONFIG_IA64_NEW_UNWIND */ - -static int -access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data, int write_access) -{ - unsigned long *ptr = NULL, *rbs, *bspstore, ndirty, regnum; - struct switch_stack *sw; - struct pt_regs *pt; - - if ((addr & 0x7) != 0) - return -1; - - if (addr < PT_F127+16) { - /* accessing fph */ - if (write_access) - ia64_sync_fph(child); - else - ia64_flush_fph(child); - ptr = (unsigned long *) ((unsigned long) &child->thread.fph + addr); - } else if (addr < PT_F9+16) { - /* accessing switch_stack or pt_regs: */ - pt = ia64_task_regs(child); - sw = (struct switch_stack *) pt - 1; - - switch (addr) { - case PT_NAT_BITS: - if (write_access) - ia64_put_nat_bits(pt, sw, *data); - else - *data = ia64_get_nat_bits(pt, sw); - return 0; - - case PT_AR_BSP: - if (write_access) - /* FIXME? Account for lack of ``cover'' in the syscall case */ - return sync_kernel_register_backing_store(child, *data, 1); - else { - rbs = (unsigned long *) child + IA64_RBS_OFFSET/8; - bspstore = (unsigned long *) pt->ar_bspstore; - ndirty = ia64_rse_num_regs(rbs, rbs + (pt->loadrs >> 19)); - - /* - * If we're in a system call, no ``cover'' was done. So to - * make things uniform, we'll add the appropriate displacement - * onto bsp if we're in a system call. - */ - if (!(pt->cr_ifs & (1UL << 63))) - ndirty += sw->ar_pfs & 0x7f; - *data = (unsigned long) ia64_rse_skip_regs(bspstore, ndirty); - return 0; - } - - case PT_CFM: - if (write_access) { - if (pt->cr_ifs & (1UL << 63)) - pt->cr_ifs = ((pt->cr_ifs & ~0x3fffffffffUL) - | (*data & 0x3fffffffffUL)); - else - sw->ar_pfs = ((sw->ar_pfs & ~0x3fffffffffUL) - | (*data & 0x3fffffffffUL)); - return 0; - } else { - if ((pt->cr_ifs & (1UL << 63)) == 0) - *data = sw->ar_pfs; - else - /* return only the CFM */ - *data = pt->cr_ifs & 0x3fffffffffUL; - return 0; - } - - case PT_CR_IPSR: - if (write_access) - pt->cr_ipsr = ((*data & IPSR_WRITE_MASK) - | (pt->cr_ipsr & ~IPSR_WRITE_MASK)); - else - *data = (pt->cr_ipsr & IPSR_READ_MASK); - return 0; - - case PT_AR_EC: - if (write_access) - sw->ar_pfs = (((*data & 0x3f) << 52) - | (sw->ar_pfs & ~(0x3fUL << 52))); - else - *data = (sw->ar_pfs >> 52) & 0x3f; - break; - - case PT_R1: case PT_R2: case PT_R3: - case PT_R4: case PT_R5: case PT_R6: case PT_R7: - case PT_R8: case PT_R9: case PT_R10: case PT_R11: - case PT_R12: case PT_R13: case PT_R14: case PT_R15: - case PT_R16: case PT_R17: case PT_R18: case PT_R19: - case PT_R20: case PT_R21: case PT_R22: case PT_R23: - case PT_R24: case PT_R25: case PT_R26: case PT_R27: - case PT_R28: case PT_R29: case PT_R30: case PT_R31: - case PT_B0: case PT_B1: case PT_B2: case PT_B3: - case PT_B4: case PT_B5: case PT_B6: case PT_B7: - case PT_F2: case PT_F2+8: case PT_F3: case PT_F3+8: - case PT_F4: case PT_F4+8: case PT_F5: case PT_F5+8: - case PT_F6: case PT_F6+8: case PT_F7: case PT_F7+8: - case PT_F8: case PT_F8+8: case PT_F9: case PT_F9+8: - case PT_F10: case PT_F10+8: case PT_F11: case PT_F11+8: - case PT_F12: case PT_F12+8: case PT_F13: case PT_F13+8: - case PT_F14: case PT_F14+8: case PT_F15: case PT_F15+8: - case PT_F16: case PT_F16+8: case PT_F17: case PT_F17+8: - case PT_F18: case PT_F18+8: case PT_F19: case PT_F19+8: - case PT_F20: case PT_F20+8: case PT_F21: case PT_F21+8: - case PT_F22: case PT_F22+8: case PT_F23: case PT_F23+8: - case PT_F24: case PT_F24+8: case PT_F25: case PT_F25+8: - case PT_F26: case PT_F26+8: case PT_F27: case PT_F27+8: - case PT_F28: case PT_F28+8: case PT_F29: case PT_F29+8: - case PT_F30: case PT_F30+8: case PT_F31: case PT_F31+8: - case PT_AR_BSPSTORE: - case PT_AR_RSC: case PT_AR_UNAT: case PT_AR_PFS: case PT_AR_RNAT: - case PT_AR_CCV: case PT_AR_FPSR: case PT_CR_IIP: case PT_PR: - case PT_AR_LC: - ptr = (unsigned long *) ((long) sw + addr - PT_NAT_BITS); - break; - - default: - /* disallow accessing anything else... */ - return -1; - } - } else { - - /* access debug registers */ - - if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) { - child->thread.flags |= IA64_THREAD_DBG_VALID; - memset(child->thread.dbr, 0, sizeof child->thread.dbr); - memset(child->thread.ibr, 0, sizeof child->thread.ibr); - } - if (addr >= PT_IBR) { - regnum = (addr - PT_IBR) >> 3; - ptr = &child->thread.ibr[0]; - } else { - regnum = (addr - PT_DBR) >> 3; - ptr = &child->thread.dbr[0]; - } - - if (regnum >= 8) - return -1; - - ptr += regnum; - - if (write_access) - /* don't let the user set kernel-level breakpoints... */ - *ptr = *data & ~(7UL << 56); - else - *data = *ptr; - return 0; - } - if (write_access) - *ptr = *data; - else - *data = *ptr; - return 0; -} - -#endif /* !CONFIG_IA64_NEW_UNWIND */ - asmlinkage long sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data, long arg4, long arg5, long arg6, long arg7, long stack) { - struct pt_regs *regs = (struct pt_regs *) &stack; + struct pt_regs *pt, *regs = (struct pt_regs *) &stack; struct task_struct *child; - unsigned long flags; + unsigned long flags, bsp; long ret; lock_kernel(); @@ -1031,10 +774,10 @@ (current->uid != child->euid) || (current->uid != child->suid) || (current->uid != child->uid) || - (current->gid != child->egid) || - (current->gid != child->sgid) || - (!cap_issubset(child->cap_permitted, current->cap_permitted)) || - (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) + (current->gid != child->egid) || + (current->gid != child->sgid) || + (!cap_issubset(child->cap_permitted, current->cap_permitted)) || + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) goto out_tsk; /* the same process cannot be attached many times */ if (child->ptrace & PT_PTRACED) @@ -1065,10 +808,13 @@ if (child->p_pptr != current) goto out_tsk; + pt = ia64_task_regs(child); + switch (request) { case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: /* read word at location addr */ - if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) { + bsp = ia64_get_user_bsp(child, pt); + if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) { struct mm_struct *mm; long do_sync; @@ -1079,9 +825,9 @@ } task_unlock(child); if (do_sync) - sync_thread_rbs(child, mm, 0); + sync_thread_rbs(child, bsp, mm, 0); } - ret = ia64_peek(regs, child, addr, &data); + ret = ia64_peek(child, bsp, addr, &data); if (ret == 0) { ret = data; regs->r8 = 0; /* ensure "ret" is not mistaken as an error code */ @@ -1090,7 +836,8 @@ case PTRACE_POKETEXT: case PTRACE_POKEDATA: /* write the word at location addr */ - if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) { + bsp = ia64_get_user_bsp(child, pt); + if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) { struct mm_struct *mm; long do_sync; @@ -1101,9 +848,9 @@ } task_unlock(child); if (do_sync) - sync_thread_rbs(child, mm, 1); + sync_thread_rbs(child, bsp, mm, 1); } - ret = ia64_poke(regs, child, addr, data); + ret = ia64_poke(child, bsp, addr, data); goto out_tsk; case PTRACE_PEEKUSR: /* read the word at addr in the USER area */ @@ -1125,21 +872,19 @@ case PTRACE_GETSIGINFO: ret = -EIO; - if (!access_ok(VERIFY_WRITE, data, sizeof (siginfo_t)) - || child->thread.siginfo == 0) + if (!access_ok(VERIFY_WRITE, data, sizeof (siginfo_t)) || !child->thread.siginfo) goto out_tsk; - copy_to_user((siginfo_t *) data, child->thread.siginfo, sizeof (siginfo_t)); - ret = 0; + ret = copy_siginfo_to_user((siginfo_t *) data, child->thread.siginfo); goto out_tsk; - break; + case PTRACE_SETSIGINFO: ret = -EIO; if (!access_ok(VERIFY_READ, data, sizeof (siginfo_t)) || child->thread.siginfo == 0) goto out_tsk; - copy_from_user(child->thread.siginfo, (siginfo_t *) data, sizeof (siginfo_t)); - ret = 0; + ret = copy_siginfo_from_user(child->thread.siginfo, (siginfo_t *) data); goto out_tsk; + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: /* restart after signal. */ ret = -EIO; @@ -1152,8 +897,8 @@ child->exit_code = data; /* make sure the single step/take-branch tra bits are not set: */ - ia64_psr(ia64_task_regs(child))->ss = 0; - ia64_psr(ia64_task_regs(child))->tb = 0; + ia64_psr(pt)->ss = 0; + ia64_psr(pt)->tb = 0; /* Turn off flag indicating that the KRBS is sync'd with child's VM: */ child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED; @@ -1173,8 +918,8 @@ child->exit_code = SIGKILL; /* make sure the single step/take-branch tra bits are not set: */ - ia64_psr(ia64_task_regs(child))->ss = 0; - ia64_psr(ia64_task_regs(child))->tb = 0; + ia64_psr(pt)->ss = 0; + ia64_psr(pt)->tb = 0; /* Turn off flag indicating that the KRBS is sync'd with child's VM: */ child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED; @@ -1191,9 +936,9 @@ child->ptrace &= ~PT_TRACESYS; if (request == PTRACE_SINGLESTEP) { - ia64_psr(ia64_task_regs(child))->ss = 1; + ia64_psr(pt)->ss = 1; } else { - ia64_psr(ia64_task_regs(child))->tb = 1; + ia64_psr(pt)->tb = 1; } child->exit_code = data; @@ -1219,8 +964,8 @@ write_unlock_irqrestore(&tasklist_lock, flags); /* make sure the single step/take-branch tra bits are not set: */ - ia64_psr(ia64_task_regs(child))->ss = 0; - ia64_psr(ia64_task_regs(child))->tb = 0; + ia64_psr(pt)->ss = 0; + ia64_psr(pt)->tb = 0; /* Turn off flag indicating that the KRBS is sync'd with child's VM: */ child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/setup.c linux.ac/arch/ia64/kernel/setup.c --- linux.vanilla/arch/ia64/kernel/setup.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/setup.c Tue Apr 10 18:08:40 2001 @@ -1,8 +1,8 @@ /* * Architecture-specific setup. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com> * Copyright (C) 2000, Rohit Seth <rohit.seth@intel.com> * Copyright (C) 1999 VA Linux Systems @@ -42,16 +42,20 @@ # include <linux/blk.h> #endif +#if defined(CONFIG_SMP) && (IA64_CPU_SIZE > PAGE_SIZE) +# error "struct cpuinfo_ia64 too big!" +#endif + extern char _end; /* cpu_data[0] is data for the bootstrap processor: */ -struct cpuinfo_ia64 cpu_data[NR_CPUS]; +struct cpuinfo_ia64 cpu_data[NR_CPUS] __attribute__ ((section ("__special_page_section"))); unsigned long ia64_cycles_per_usec; -struct ia64_boot_param ia64_boot_param; +struct ia64_boot_param *ia64_boot_param; struct screen_info screen_info; /* This tells _start which CPU is booting. */ -int cpu_now_booting = 0; +int cpu_now_booting; #ifdef CONFIG_SMP volatile unsigned long cpu_online_map; @@ -119,14 +123,7 @@ unw_init(); - /* - * The secondary bootstrap loader passes us the boot - * parameters at the beginning of the ZERO_PAGE, so let's - * stash away those values before ZERO_PAGE gets cleared out. - */ - memcpy(&ia64_boot_param, (void *) ZERO_PAGE_ADDR, sizeof(ia64_boot_param)); - - *cmdline_p = __va(ia64_boot_param.command_line); + *cmdline_p = __va(ia64_boot_param->command_line); strncpy(saved_command_line, *cmdline_p, sizeof(saved_command_line)); saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; /* for safety */ @@ -140,9 +137,8 @@ * change APIs, they'd do things for the better. Grumble... */ bootmap_start = PAGE_ALIGN(__pa(&_end)); - if (ia64_boot_param.initrd_size) - bootmap_start = PAGE_ALIGN(bootmap_start - + ia64_boot_param.initrd_size); + if (ia64_boot_param->initrd_size) + bootmap_start = PAGE_ALIGN(bootmap_start + ia64_boot_param->initrd_size); bootmap_size = init_bootmem(bootmap_start >> PAGE_SHIFT, max_pfn); efi_memmap_walk(free_available_memory, 0); @@ -150,7 +146,7 @@ reserve_bootmem(bootmap_start, bootmap_size); #ifdef CONFIG_BLK_DEV_INITRD - initrd_start = ia64_boot_param.initrd_start; + initrd_start = ia64_boot_param->initrd_start; if (initrd_start) { u64 start, size; @@ -163,16 +159,16 @@ "for initrd, please upgrade the loader\n"); else #endif - /* + /* * The loader ONLY passes physical addresses */ initrd_start = (unsigned long)__va(initrd_start); - initrd_end = initrd_start+ia64_boot_param.initrd_size; + initrd_end = initrd_start+ia64_boot_param->initrd_size; start = initrd_start; - size = ia64_boot_param.initrd_size; + size = ia64_boot_param->initrd_size; printk("Initial ramdisk at: 0x%p (%lu bytes)\n", - (void *) initrd_start, ia64_boot_param.initrd_size); + (void *) initrd_start, ia64_boot_param->initrd_size); /* * The kernel end and the beginning of initrd can be @@ -218,19 +214,19 @@ /* process SAL system table: */ ia64_sal_init(efi.sal_systab); -#ifdef CONFIG_SMP - current->processor = 0; - cpu_physical_id(0) = hard_smp_processor_id(); -#endif /* * Set `iobase' to the appropriate address in region 6 * (uncached access range) */ - __asm__ ("mov %0=ar.k0;;" : "=r"(ia64_iobase)); + ia64_iobase = ia64_get_kr(IA64_KR_IO_BASE); ia64_iobase = __IA64_UNCACHED_OFFSET | (ia64_iobase & ~PAGE_OFFSET); cpu_init(); /* initialize the bootstrap CPU */ +#ifdef CONFIG_SMP + cpu_physical_id(0) = hard_smp_processor_id(); +#endif + #ifdef CONFIG_IA64_GENERIC machvec_init(acpi_get_sysname()); #endif @@ -239,7 +235,7 @@ if (efi.acpi20) { /* Parse the ACPI 2.0 tables */ acpi20_parse(efi.acpi20); - } else + } else #endif if (efi.acpi) { /* Parse the ACPI tables */ @@ -259,8 +255,8 @@ ia64_mca_init(); #endif - paging_init(); platform_setup(cmdline_p); + paging_init(); } /* @@ -325,7 +321,7 @@ c->ppn, c->number, c->proc_freq / 1000000, c->proc_freq % 1000000, c->itc_freq / 1000000, c->itc_freq % 1000000, lpj*HZ/500000, (lpj*HZ/5000) % 100); - } + } return p - buffer; } @@ -362,8 +358,6 @@ for (i = 0; i < 5; ++i) cpuid.bits[i] = ia64_get_cpuid(i); - memset(c, 0, sizeof(struct cpuinfo_ia64)); - memcpy(c->vendor, cpuid.field.vendor, 16); c->ppn = cpuid.field.ppn; c->number = cpuid.field.number; @@ -382,12 +376,6 @@ smp_processor_id(), impl_va_msb + 1, phys_addr_size); c->unimpl_va_mask = ~((7L<<61) | ((1L << (impl_va_msb + 1)) - 1)); c->unimpl_pa_mask = ~((1L<<63) | ((1L << phys_addr_size) - 1)); - -#ifdef CONFIG_IA64_SOFTSDV_HACKS - /* BUG: SoftSDV doesn't support the cpuid registers. */ - if (c->vendor[0] == '\0') - memcpy(c->vendor, "Intel", 6); -#endif } /* @@ -397,12 +385,18 @@ void cpu_init (void) { - extern void __init ia64_rid_init (void); - extern void __init ia64_tlb_init (void); + extern void __init ia64_mmu_init (void); + unsigned long num_phys_stacked; pal_vm_info_2_u_t vmi; unsigned int max_ctx; - identify_cpu(&my_cpu_data); + /* + * We can't pass "local_cpu_data" do identify_cpu() because we haven't called + * ia64_mmu_init() yet. And we can't call ia64_mmu_init() first because it + * depends on the data returned by identify_cpu(). We break the dependency by + * accessing cpu_data[] the old way, through identity mapped space. + */ + identify_cpu(&cpu_data[smp_processor_id()]); /* Clear the stack memory reserved for pt_regs: */ memset(ia64_task_regs(current), 0, sizeof(struct pt_regs)); @@ -415,22 +409,30 @@ ia64_set_dcr( IA64_DCR_DM | IA64_DCR_DP | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_DR | IA64_DCR_DA | IA64_DCR_DD); #ifndef CONFIG_SMP - ia64_set_fpu_owner(0); /* initialize ar.k5 */ + ia64_set_fpu_owner(0); #endif atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; - ia64_rid_init(); - ia64_tlb_init(); + ia64_mmu_init(); -#ifdef CONFIG_IA32_SUPPORT +#ifdef CONFIG_IA32_SUPPORT /* initialize global ia32 state - CR0 and CR4 */ __asm__("mov ar.cflg = %0" : /* no outputs */ : "r" (((ulong) IA32_CR4 << 32) | IA32_CR0)); #endif + /* disable all local interrupt sources: */ + ia64_set_itv(1 << 16); + ia64_set_lrr0(1 << 16); + ia64_set_lrr1(1 << 16); + ia64_set_pmv(1 << 16); + ia64_set_cmcv(1 << 16); + + /* clear TPR & XTP to enable all interrupt classes: */ + ia64_set_tpr(0); #ifdef CONFIG_SMP normal_xtp(); #endif @@ -439,7 +441,7 @@ if (ia64_pal_vm_summary(NULL, &vmi) == 0) max_ctx = (1U << (vmi.pal_vm_info_2_s.rid_size - 3)) - 1; else { - printk("ia64_rid_init: PAL VM summary failed, assuming 18 RID bits\n"); + printk("cpu_init: PAL VM summary failed, assuming 18 RID bits\n"); max_ctx = (1U << 15) - 1; /* use architected minimum */ } while (max_ctx < ia64_ctx.max_ctx) { @@ -447,4 +449,10 @@ if (cmpxchg(&ia64_ctx.max_ctx, old, max_ctx) == old) break; } + + if (ia64_pal_rse_info(&num_phys_stacked, 0) != 0) { + printk ("cpu_init: PAL RSE info failed, assuming 96 physical stacked regs\n"); + num_phys_stacked = 96; + } + local_cpu_data->phys_stacked_size_p8 = num_phys_stacked*8 + 8; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/signal.c linux.ac/arch/ia64/kernel/signal.c --- linux.vanilla/arch/ia64/kernel/signal.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/signal.c Tue Apr 10 18:08:40 2001 @@ -1,8 +1,8 @@ /* * Architecture-specific signal handling support. * - * Copyright (C) 1999-2000 Hewlett-Packard Co - * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> * * Derived from i386 and Alpha versions. */ @@ -38,12 +38,8 @@ #endif struct sigscratch { -#ifdef CONFIG_IA64_NEW_UNWIND unsigned long scratch_unat; /* ar.unat for the general registers saved in pt */ unsigned long pad; -#else - struct switch_stack sw; -#endif struct pt_regs pt; }; @@ -52,7 +48,6 @@ struct sigcontext sc; }; -extern long sys_wait4 (int, int *, int, struct rusage *); extern long ia64_do_signal (sigset_t *, struct sigscratch *, long); /* forward decl */ long @@ -141,11 +136,7 @@ ia64_psr(&scr->pt)->ri = ip & 0x3; scr->pt.cr_ipsr = (scr->pt.cr_ipsr & ~IA64_PSR_UM) | (um & IA64_PSR_UM); -#ifdef CONFIG_IA64_NEW_UNWIND scr->scratch_unat = ia64_put_scratch_nat_bits(&scr->pt, nat); -#else - ia64_put_nat_bits(&scr->pt, &scr->sw, nat); /* restore the original scratch NaT bits */ -#endif if ((flags & IA64_SC_FLAG_FPH_VALID) != 0) { struct ia64_psr *psr = ia64_psr(&scr->pt); @@ -162,7 +153,7 @@ int copy_siginfo_to_user (siginfo_t *to, siginfo_t *from) { - if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t))) return -EFAULT; if (from->si_code < 0) return __copy_to_user(to, from, sizeof(siginfo_t)); @@ -190,6 +181,11 @@ err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); err |= __put_user(from->si_status, &to->si_status); + case __SI_PROF >> 16: + err |= __put_user(from->si_uid, &to->si_uid); + err |= __put_user(from->si_pid, &to->si_pid); + err |= __put_user(from->si_pfm_ovfl, &to->si_pfm_ovfl); + break; default: err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_pid, &to->si_pid); @@ -200,6 +196,43 @@ } } +int +copy_siginfo_from_user (siginfo_t *to, siginfo_t *from) +{ + if (!access_ok(VERIFY_READ, from, sizeof(siginfo_t))) + return -EFAULT; + if (__copy_from_user(to, from, sizeof(siginfo_t)) != 0) + return -EFAULT; + + if (SI_FROMUSER(to)) + return 0; + + to->si_code &= ~__SI_MASK; + if (to->si_code != 0) { + switch (to->si_signo) { + case SIGILL: case SIGFPE: case SIGSEGV: case SIGBUS: case SIGTRAP: + to->si_code |= __SI_FAULT; + break; + + case SIGCHLD: + to->si_code |= __SI_CHLD; + break; + + case SIGPOLL: + to->si_code |= __SI_POLL; + break; + + case SIGPROF: + to->si_code |= __SI_PROF; + break; + + default: + break; + } + } + return 0; +} + long ia64_rt_sigreturn (struct sigscratch *scr) { @@ -212,19 +245,17 @@ sc = &((struct sigframe *) (scr->pt.r12 + 16))->sc; /* - * When we return to the previously executing context, r8 and - * r10 have already been setup the way we want them. Indeed, - * if the signal wasn't delivered while in a system call, we - * must not touch r8 or r10 as otherwise user-level stat could - * be corrupted. + * When we return to the previously executing context, r8 and r10 have already + * been setup the way we want them. Indeed, if the signal wasn't delivered while + * in a system call, we must not touch r8 or r10 as otherwise user-level state + * could be corrupted. */ retval = (long) &ia64_leave_kernel; if (current->ptrace & PT_TRACESYS) /* - * strace expects to be notified after sigreturn - * returns even though the context to which we return - * may not be in the middle of a syscall. Thus, the - * return-value that strace displays for sigreturn is + * strace expects to be notified after sigreturn returns even though the + * context to which we return may not be in the middle of a syscall. + * Thus, the return-value that strace displays for sigreturn is * meaningless. */ retval = (long) &ia64_strace_leave_kernel; @@ -301,11 +332,7 @@ * preserved registers (r4-r7) are never being looked at by * the signal handler (registers r4-r7 are used instead). */ -#ifdef CONFIG_IA64_NEW_UNWIND nat = ia64_get_scratch_nat_bits(&scr->pt, scr->scratch_unat); -#else - nat = ia64_get_nat_bits(&scr->pt, &scr->sw); -#endif err = __put_user(flags, &sc->sc_flags); @@ -371,21 +398,11 @@ scr->pt.cr_iip = tramp_addr; ia64_psr(&scr->pt)->ri = 0; /* start executing in first slot */ -#ifdef CONFIG_IA64_NEW_UNWIND /* * Note: this affects only the NaT bits of the scratch regs * (the ones saved in pt_regs), which is exactly what we want. */ scr->scratch_unat = 0; /* ensure NaT bits of at least r2, r3, r12, and r15 are clear */ -#else - /* - * Note: this affects only the NaT bits of the scratch regs - * (the ones saved in pt_regs), which is exactly what we want. - * The NaT bits for the preserved regs (r4-r7) are in - * sw->ar_unat iff this process is being PTRACED. - */ - scr->sw.caller_unat = 0; /* ensure NaT bits of at least r2, r3, r12, and r15 are clear */ -#endif #if DEBUG_SIG printk("SIG deliver (%s:%d): sig=%d sp=%lx ip=%lx handler=%lx\n", @@ -437,13 +454,8 @@ } /* - * Note that `init' is a special process: it doesn't get signals it - * doesn't want to handle. Thus you cannot kill init even with a - * SIGKILL even by mistake. - * - * Note that we go through the signals twice: once to check the - * signals that the kernel can handle, and then we build all the - * user-level signal handling stack-frames in one go after that. + * Note that `init' is a special process: it doesn't get signals it doesn't want to + * handle. Thus you cannot kill init even with a SIGKILL even by mistake. */ long ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall) @@ -454,9 +466,9 @@ long errno = scr->pt.r8; /* - * In the ia64_leave_kernel code path, 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. + * In the ia64_leave_kernel code path, 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(&scr->pt)) return 0; @@ -476,11 +488,10 @@ #endif if (scr->pt.r10 != -1) { /* - * A system calls has to be restarted only if one of - * the error codes ERESTARTNOHAND, ERESTARTSYS, or - * ERESTARTNOINTR is returned. If r10 isn't -1 then - * r8 doesn't hold an error code and we don't need to - * restart the syscall, so we set in_syscall to zero. + * A system calls has to be restarted only if one of the error codes + * ERESTARTNOHAND, ERESTARTSYS, or ERESTARTNOINTR is returned. If r10 + * isn't -1 then r8 doesn't hold an error code and we don't need to + * restart the syscall, so we can clear the "restart" flag here. */ restart = 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/smp.c linux.ac/arch/ia64/kernel/smp.c --- linux.vanilla/arch/ia64/kernel/smp.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/smp.c Tue Apr 10 18:08:40 2001 @@ -2,8 +2,8 @@ * SMP Support * * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> - * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com> - * + * Copyright (C) 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com> + * * Lots of stuff stolen from arch/alpha/kernel/smp.c * * 00/09/11 David Mosberger <davidm@hpl.hp.com> Do loops_per_jiffy calibration on each CPU. @@ -37,8 +37,8 @@ #include <asm/io.h> #include <asm/irq.h> #include <asm/page.h> -#include <asm/pgtable.h> #include <asm/pgalloc.h> +#include <asm/pgtable.h> #include <asm/processor.h> #include <asm/ptrace.h> #include <asm/sal.h> @@ -50,9 +50,8 @@ extern void machine_halt(void); extern void start_ap(void); -extern int cpu_now_booting; /* Used by head.S to find idle task */ -extern volatile unsigned long cpu_online_map; /* Bitmap of available cpu's */ -extern struct cpuinfo_ia64 cpu_data[NR_CPUS]; /* Duh... */ +extern int cpu_now_booting; /* used by head.S to find idle task */ +extern volatile unsigned long cpu_online_map; /* bitmap of available cpu's */ struct smp_boot_data smp_boot_data __initdata; @@ -60,18 +59,19 @@ char __initdata no_int_routing; +/* don't make this a CPU-local variable: it's used for IPIs, mostly... */ +int __cpu_physical_id[NR_CPUS]; /* logical ID -> physical CPU ID map */ + unsigned char smp_int_redirect; /* are INT and IPI redirectable by the chipset? */ -volatile int __cpu_physical_id[NR_CPUS] = { -1, }; /* Logical ID -> SAPIC ID */ -int smp_num_cpus = 1; -volatile int smp_threads_ready; /* Set when the idlers are all forked */ -cycles_t cacheflush_time; -unsigned long ap_wakeup_vector = -1; /* External Int to use to wakeup AP's */ +int smp_num_cpus = 1; +volatile int smp_threads_ready; /* set when the idlers are all forked */ +unsigned long ap_wakeup_vector; /* external Int to use to wakeup AP's */ static volatile unsigned long cpu_callin_map; static volatile int smp_commenced; -static int max_cpus = -1; /* Command line */ -static unsigned long ipi_op[NR_CPUS]; +static int max_cpus = -1; /* command line */ + struct smp_call_struct { void (*func) (void *info); void *info; @@ -99,7 +99,8 @@ * SMP mode to <NUM>. */ -static int __init nosmp(char *str) +static int __init +nosmp (char *str) { max_cpus = 0; return 1; @@ -107,7 +108,8 @@ __setup("nosmp", nosmp); -static int __init maxcpus(char *str) +static int __init +maxcpus (char *str) { get_option(&str, &max_cpus); return 1; @@ -116,7 +118,7 @@ __setup("maxcpus=", maxcpus); static int __init -nointroute(char *str) +nointroute (char *str) { no_int_routing = 1; return 1; @@ -125,21 +127,20 @@ __setup("nointroute", nointroute); /* - * Yoink this CPU from the runnable list... + * Yoink this CPU from the runnable list... */ void -halt_processor(void) +halt_processor (void) { - clear_bit(smp_processor_id(), &cpu_online_map); + clear_bit(smp_processor_id(), &cpu_online_map); max_xtp(); __cli(); - for (;;) + for (;;) ; - } static inline int -pointer_lock(void *lock, void *data, int retry) +pointer_lock (void *lock, void *data, int retry) { volatile long *ptr = lock; again: @@ -156,14 +157,13 @@ } void -handle_IPI(int irq, void *dev_id, struct pt_regs *regs) +handle_IPI (int irq, void *dev_id, struct pt_regs *regs) { - int this_cpu = smp_processor_id(); - unsigned long *pending_ipis = &ipi_op[this_cpu]; + unsigned long *pending_ipis = &local_cpu_data->ipi_operation; unsigned long ops; /* Count this now; we may make a call that never returns. */ - cpu_data[this_cpu].ipi_count++; + local_cpu_data->ipi_count++; mb(); /* Order interrupt and bit testing. */ while ((ops = xchg(pending_ipis, 0)) != 0) { @@ -173,16 +173,16 @@ which = ffz(~ops); ops &= ~(1 << which); - + switch (which) { case IPI_RESCHEDULE: - /* - * Reschedule callback. Everything to be done is done by the - * interrupt return path. + /* + * Reschedule callback. Everything to be done is done by the + * interrupt return path. */ break; - - case IPI_CALL_FUNC: + + case IPI_CALL_FUNC: { struct smp_call_struct *data; void (*func)(void *info); @@ -203,7 +203,7 @@ /* Notify the sending CPU that the task is done. */ mb(); - if (wait) + if (wait) atomic_dec(&data->unfinished_count); } break; @@ -214,7 +214,7 @@ #ifndef CONFIG_ITANIUM_PTCG case IPI_FLUSH_TLB: - { + { extern unsigned long flush_start, flush_end, flush_nbits, flush_rid; extern atomic_t flush_cpu_count; unsigned long saved_rid = ia64_get_rr(flush_start); @@ -223,6 +223,8 @@ unsigned long nbits = flush_nbits; /* + * Current CPU may be running with different RID so we need to + * reload the RID of flushed address. * Current CPU may be running with different * RID so we need to reload the RID of flushed * address. Purging the translation also @@ -235,7 +237,7 @@ ia64_set_rr(flush_start, flush_rid); ia64_srlz_d(); } - + do { /* * Purge local TLB entries. @@ -258,7 +260,8 @@ #endif /* !CONFIG_ITANIUM_PTCG */ default: - printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which); + printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", + smp_processor_id(), which); break; } /* Switch */ } while (ops); @@ -268,21 +271,21 @@ } static inline void -send_IPI_single (int dest_cpu, int op) +send_IPI_single (int dest_cpu, int op) { - - if (dest_cpu == -1) - return; - - set_bit(op, &ipi_op[dest_cpu]); - platform_send_ipi(dest_cpu, IPI_IRQ, IA64_IPI_DM_INT, 0); + + if (dest_cpu == -1) + return; + + set_bit(op, &cpu_data[dest_cpu].ipi_operation); + platform_send_ipi(dest_cpu, IA64_IPI_VECTOR, IA64_IPI_DM_INT, 0); } static inline void -send_IPI_allbutself(int op) +send_IPI_allbutself (int op) { int i; - + for (i = 0; i < smp_num_cpus; i++) { if (i != smp_processor_id()) send_IPI_single(i, op); @@ -290,7 +293,7 @@ } static inline void -send_IPI_all(int op) +send_IPI_all (int op) { int i; @@ -299,30 +302,42 @@ } static inline void -send_IPI_self(int op) +send_IPI_self (int op) { send_IPI_single(smp_processor_id(), op); } void -smp_send_reschedule(int cpu) +smp_send_reschedule (int cpu) { send_IPI_single(cpu, IPI_RESCHEDULE); } void -smp_send_stop(void) +smp_send_stop (void) { send_IPI_allbutself(IPI_CPU_STOP); } #ifndef CONFIG_ITANIUM_PTCG + void -smp_send_flush_tlb(void) +smp_send_flush_tlb (void) { send_IPI_allbutself(IPI_FLUSH_TLB); } -#endif /* !CONFIG_ITANIUM_PTCG */ + +void +smp_resend_flush_tlb(void) +{ + /* + * Really need a null IPI but since this rarely should happen & since this code + * will go away, lets not add one. + */ + send_IPI_allbutself(IPI_RESCHEDULE); +} + +#endif /* !CONFIG_ITANIUM_PTCG */ /* * Run a function on another CPU @@ -347,7 +362,7 @@ printk(__FUNCTION__" trying to call self\n"); return -EBUSY; } - + data.func = func; data.info = info; data.wait = wait; @@ -392,7 +407,6 @@ * Does not return until remote CPUs are nearly ready to execute <func> * or are or have executed. */ - int smp_call_function (void (*func) (void *info), void *info, int retry, int wait) { @@ -402,7 +416,7 @@ if (cpus == 0) return 0; - + data.func = func; data.info = info; data.wait = wait; @@ -425,7 +439,7 @@ int i; for (i = 0; i < smp_num_cpus; i++) { if (i != smp_processor_id()) - platform_send_ipi(i, IPI_IRQ, IA64_IPI_DM_INT, 0); + platform_send_ipi(i, IA64_IPI_VECTOR, IA64_IPI_DM_INT, 0); } goto retry; #else @@ -446,7 +460,7 @@ * want to ensure all TLB's flushed before proceeding. */ void -smp_flush_tlb_all(void) +smp_flush_tlb_all (void) { smp_call_function((void (*)(void *))__flush_tlb_all, NULL, 1, 1); __flush_tlb_all(); @@ -456,21 +470,19 @@ * Ideally sets up per-cpu profiling hooks. Doesn't do much now... */ static inline void __init -smp_setup_percpu_timer(int cpuid) +smp_setup_percpu_timer(void) { - cpu_data[cpuid].prof_counter = 1; - cpu_data[cpuid].prof_multiplier = 1; + local_cpu_data->prof_counter = 1; + local_cpu_data->prof_multiplier = 1; } -void -smp_do_timer(struct pt_regs *regs) +void +smp_do_timer (struct pt_regs *regs) { - int cpu = smp_processor_id(); - int user = user_mode(regs); - struct cpuinfo_ia64 *data = &cpu_data[cpu]; + int user = user_mode(regs); - if (--data->prof_counter <= 0) { - data->prof_counter = data->prof_multiplier; + if (--local_cpu_data->prof_counter <= 0) { + local_cpu_data->prof_counter = local_cpu_data->prof_multiplier; update_process_times(user); } } @@ -480,7 +492,7 @@ * AP's start using C here. */ void __init -smp_callin (void) +smp_callin (void) { extern void ia64_rid_init(void); extern void ia64_init_itm(void); @@ -493,12 +505,12 @@ if (test_and_set_bit(cpu, &cpu_online_map)) { printk("CPU#%d already initialized!\n", cpu); machine_halt(); - } + } efi_map_pal_code(); cpu_init(); - smp_setup_percpu_timer(cpu); + smp_setup_percpu_timer(); /* setup the CPU local timer tick */ ia64_init_itm(); @@ -506,15 +518,10 @@ #ifdef CONFIG_PERFMON perfmon_init_percpu(); #endif - - /* Disable all local interrupts */ - ia64_set_lrr0(0, 1); - ia64_set_lrr1(0, 1); - local_irq_enable(); /* Interrupts have been off until now */ calibrate_delay(); - my_cpu_data.loops_per_jiffy = loops_per_jiffy; + local_cpu_data->loops_per_jiffy = loops_per_jiffy; /* allow the master to continue */ set_bit(cpu, &cpu_callin_map); @@ -531,8 +538,8 @@ * path in which case the new idle task could get scheduled before we * had a chance to remove it from the run-queue... */ -static int __init -fork_by_hand(void) +static int __init +fork_by_hand (void) { /* * Don't care about the usp and regs settings since we'll never @@ -545,22 +552,22 @@ * Bring one cpu online. Return 0 if this fails for any reason. */ static int __init -smp_boot_one_cpu(int cpu) +smp_boot_one_cpu (int cpu) { struct task_struct *idle; int cpu_phys_id = cpu_physical_id(cpu); long timeout; - /* + /* * Create an idle task for this CPU. Note that the address we * give to kernel_thread is irrelevant -- it's going to start * where OS_BOOT_RENDEVZ vector in SAL says to start. But * this gets all the other task-y sort of data structures set - * up like we wish. We need to pull the just created idle task - * off the run queue and stuff it into the init_tasks[] array. + * up like we wish. We need to pull the just created idle task + * off the run queue and stuff it into the init_tasks[] array. * Sheesh . . . */ - if (fork_by_hand() < 0) + if (fork_by_hand() < 0) panic("failed fork for CPU 0x%x", cpu_phys_id); /* * We remove it from the pidhash and the runqueue @@ -571,7 +578,7 @@ panic("No idle process for CPU 0x%x", cpu_phys_id); init_tasks[cpu] = idle; del_from_runqueue(idle); - unhash_process(idle); + unhash_process(idle); /* Schedule the first task manually. */ idle->processor = cpu; @@ -590,50 +597,41 @@ udelay(100); } - printk(KERN_ERR "SMP: Processor 0x%x is stuck.\n", cpu_phys_id); + printk(KERN_ERR "SMP: CPU 0x%x is stuck\n", cpu_phys_id); return 0; } /* - * Called by smp_init bring all the secondaries online and hold them. - * XXX: this is ACPI specific; it uses "magic" variables exported from acpi.c - * to 'discover' the AP's. Blech. + * Called by smp_init bring all the secondaries online and hold them. */ void __init -smp_boot_cpus(void) +smp_boot_cpus (void) { int i, cpu_count = 1; unsigned long bogosum; - /* Take care of some initial bookkeeping. */ - memset(&__cpu_physical_id, -1, sizeof(__cpu_physical_id)); - memset(&ipi_op, 0, sizeof(ipi_op)); - - /* Setup BP mappings */ - __cpu_physical_id[0] = hard_smp_processor_id(); - /* on the BP, the kernel already called calibrate_delay_loop() in init/main.c */ - my_cpu_data.loops_per_jiffy = loops_per_jiffy; + local_cpu_data->loops_per_jiffy = loops_per_jiffy; #if 0 smp_tune_scheduling(); #endif - smp_setup_percpu_timer(0); + smp_setup_percpu_timer(); if (test_and_set_bit(0, &cpu_online_map)) { printk("CPU#%d already initialized!\n", smp_processor_id()); machine_halt(); - } + } init_idle(); /* Nothing to do when told not to. */ if (max_cpus == 0) { - printk(KERN_INFO "SMP mode deactivated.\n"); + printk(KERN_INFO "SMP mode deactivated.\n"); return; } - if (max_cpus != -1) + if (max_cpus != -1) printk("Limiting CPUs to %d\n", max_cpus); if (smp_boot_data.cpu_count > 1) { @@ -650,7 +648,7 @@ continue; /* failed */ cpu_count++; /* Count good CPUs only... */ - /* + /* * Bail if we've started as many CPUS as we've been told to. */ if (cpu_count == max_cpus) @@ -663,10 +661,10 @@ } bogosum = 0; - for (i = 0; i < NR_CPUS; i++) { + for (i = 0; i < NR_CPUS; i++) { if (cpu_online_map & (1L << i)) bogosum += cpu_data[i].loops_per_jiffy; - } + } printk(KERN_INFO "SMP: Total of %d processors activated (%lu.%02lu BogoMIPS).\n", cpu_count, bogosum*HZ/500000, (bogosum*HZ/5000) % 100); @@ -674,31 +672,31 @@ smp_num_cpus = cpu_count; } -/* +/* * Called when the BP is just about to fire off init. */ -void __init -smp_commence(void) +void __init +smp_commence (void) { smp_commenced = 1; } int __init -setup_profiling_timer(unsigned int multiplier) +setup_profiling_timer (unsigned int multiplier) { - return -EINVAL; + return -EINVAL; } /* * Assume that CPU's have been discovered by some platform-dependant * interface. For SoftSDV/Lion, that would be ACPI. * - * Setup of the IPI irq handler is done in irq.c:init_IRQ_SMP(). + * Setup of the IPI irq handler is done in irq.c:init_IRQ(). * * This also registers the AP OS_MC_REDVEZ address with SAL. */ void __init -init_smp_config(void) +init_smp_config (void) { struct fptr { unsigned long fp; @@ -708,14 +706,13 @@ /* Tell SAL where to drop the AP's. */ ap_startup = (struct fptr *) start_ap; - sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ, - __pa(ap_startup->fp), __pa(ap_startup->gp), 0, - 0, 0, 0); + sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ, __pa(ap_startup->fp), + __pa(ap_startup->gp), 0, 0, 0, 0); if (sal_ret < 0) { printk("SMP: Can't set SAL AP Boot Rendezvous: %s\n", ia64_sal_strerror(sal_ret)); printk(" Forcing UP mode\n"); max_cpus = 0; - smp_num_cpus = 1; + smp_num_cpus = 1; } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/smpboot.c linux.ac/arch/ia64/kernel/smpboot.c --- linux.vanilla/arch/ia64/kernel/smpboot.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/kernel/smpboot.c Tue Apr 10 18:08:40 2001 @@ -1,74 +1,4 @@ /* - * SMP Support - * - * Application processor startup code, moved from smp.c to better support kernel profile */ -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/smp.h> -#include <linux/kernel_stat.h> -#include <linux/mm.h> -#include <linux/delay.h> - -#include <asm/atomic.h> -#include <asm/bitops.h> -#include <asm/current.h> -#include <asm/delay.h> -#include <asm/efi.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/pgalloc.h> -#include <asm/processor.h> -#include <asm/ptrace.h> -#include <asm/sal.h> -#include <asm/system.h> -#include <asm/unistd.h> - -/* - * SAL shoves the AP's here when we start them. Physical mode, no kernel TR, - * no RRs set, better than even chance that psr is bogus. Fix all that and - * call _start. In effect, pretend to be lilo. - * - * Stolen from lilo_start.c. Thanks David! - */ -void -start_ap(void) -{ - extern void _start (void); - unsigned long flags; - - /* - * Install a translation register that identity maps the - * kernel's 256MB page(s). - */ - ia64_clear_ic(flags); - ia64_set_rr( 0, (0x1000 << 8) | (_PAGE_SIZE_1M << 2)); - ia64_set_rr(PAGE_OFFSET, (ia64_rid(0, PAGE_OFFSET) << 8) | (_PAGE_SIZE_256M << 2)); - ia64_srlz_d(); - ia64_itr(0x3, 1, PAGE_OFFSET, - pte_val(mk_pte_phys(0, __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX))), - _PAGE_SIZE_256M); - ia64_srlz_i(); - - flags = (IA64_PSR_IT | IA64_PSR_IC | IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_DFH | - IA64_PSR_BN); - - asm volatile ("movl r8 = 1f\n" - ";;\n" - "mov cr.ipsr=%0\n" - "mov cr.iip=r8\n" - "mov cr.ifs=r0\n" - ";;\n" - "rfi;;" - "1:\n" - "movl r1 = __gp" :: "r"(flags) : "r8"); - _start(); -} - - +/* place holder... */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/sys_ia64.c linux.ac/arch/ia64/kernel/sys_ia64.c --- linux.vanilla/arch/ia64/kernel/sys_ia64.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/ia64/kernel/sys_ia64.c Sat Apr 14 01:18:00 2001 @@ -22,16 +22,16 @@ #define COLOR_ALIGN(addr) (((addr) + SHMLBA - 1) & ~(SHMLBA - 1)) unsigned long -get_unmapped_area (unsigned long addr, unsigned long len) +arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { struct vm_area_struct * vmm; if (len > RGN_MAP_LIMIT) - return 0; + return -ENOMEM; if (!addr) addr = TASK_UNMAPPED_BASE; - if (current->thread.flags & IA64_THREAD_MAP_SHARED) + if (flags & MAP_SHARED) addr = COLOR_ALIGN(addr); else addr = PAGE_ALIGN(addr); @@ -39,17 +39,19 @@ for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { /* At this point: (!vmm || addr < vmm->vm_end). */ if (TASK_SIZE - len < addr) - return 0; + return -ENOMEM; if (rgn_offset(addr) + len > RGN_MAP_LIMIT) /* no risk of overflow here... */ - return 0; + return -ENOMEM; if (!vmm || addr + len <= vmm->vm_start) return addr; addr = vmm->vm_end; + if (flags & MAP_SHARED) + addr = COLOR_ALIGN(addr); } } asmlinkage long -ia64_getpriority (int which, int who, long arg2, long arg3, long arg4, long arg5, long arg6, +ia64_getpriority (int which, int who, long arg2, long arg3, long arg4, long arg5, long arg6, long arg7, long stack) { struct pt_regs *regs = (struct pt_regs *) &stack; @@ -197,15 +199,10 @@ return -EBADF; } - if (flags & MAP_SHARED) - current->thread.flags |= IA64_THREAD_MAP_SHARED; - down_write(¤t->mm->mmap_sem); addr = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); up_write(¤t->mm->mmap_sem); - current->thread.flags &= ~IA64_THREAD_MAP_SHARED; - if (file) fput(file); return addr; @@ -246,15 +243,15 @@ asmlinkage long sys_vm86 (long arg0, long arg1, long arg2, long arg3) { - printk(KERN_ERR "sys_vm86(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3); - return -ENOSYS; + printk(KERN_ERR "sys_vm86(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3); + return -ENOSYS; } asmlinkage long sys_modify_ldt (long arg0, long arg1, long arg2, long arg3) { - printk(KERN_ERR "sys_modify_ldt(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3); - return -ENOSYS; + printk(KERN_ERR "sys_modify_ldt(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3); + return -ENOSYS; } asmlinkage unsigned long @@ -392,7 +389,7 @@ } return err; } - + #endif #ifndef CONFIG_PCI diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/time.c linux.ac/arch/ia64/kernel/time.c --- linux.vanilla/arch/ia64/kernel/time.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/time.c Tue Apr 10 18:08:40 2001 @@ -1,9 +1,9 @@ /* * linux/arch/ia64/kernel/time.c * - * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998-2001 Hewlett-Packard Co * Copyright (C) 1998-2000 Stephane Eranian <eranian@hpl.hp.com> - * Copyright (C) 1999-2000 David Mosberger <davidm@hpl.hp.com> + * Copyright (C) 1999-2001 David Mosberger <davidm@hpl.hp.com> * Copyright (C) 1999 Don Dugger <don.dugger@intel.com> * Copyright (C) 1999-2000 VA Linux Systems * Copyright (C) 1999-2000 Walt Drummond <drummond@valinux.com> @@ -32,14 +32,6 @@ #endif -static struct { - unsigned long delta; - union { - unsigned long count; - unsigned char pad[SMP_CACHE_BYTES]; - } next[NR_CPUS]; -} itm; - static void do_profile (unsigned long ip) { @@ -61,7 +53,7 @@ ip = prof_len - 1; atomic_inc((atomic_t *) &prof_buffer[ip]); - } + } } /* @@ -82,7 +74,7 @@ unsigned long now = ia64_get_itc(), last_tick; unsigned long elapsed_cycles, lost = jiffies - wall_jiffies; - last_tick = (itm.next[smp_processor_id()].count - (lost+1)*itm.delta); + last_tick = (local_cpu_data->itm_next - (lost+1)*local_cpu_data->itm_delta); # if 1 if ((long) (now - last_tick) < 0) { printk("Yikes: now < last_tick (now=0x%lx,last_tick=%lx)! No can do.\n", @@ -91,7 +83,7 @@ } # endif elapsed_cycles = now - last_tick; - return (elapsed_cycles*my_cpu_data.usec_per_cyc) >> IA64_USEC_PER_CYC_SHIFT; + return (elapsed_cycles*local_cpu_data->usec_per_cyc) >> IA64_USEC_PER_CYC_SHIFT; #endif } @@ -132,7 +124,7 @@ read_lock_irqsave(&xtime_lock, flags); { usec = gettimeoffset(); - + sec = xtime.tv_sec; usec += xtime.tv_usec; } @@ -150,10 +142,9 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - int cpu = smp_processor_id(); unsigned long new_itm; - new_itm = itm.next[cpu].count; + new_itm = local_cpu_data->itm_next; if (!time_after(ia64_get_itc(), new_itm)) printk("Oops: timer tick before it's due (itc=%lx,itm=%lx)\n", @@ -165,7 +156,7 @@ * four so that we can use a prof_shift of 2 to get instruction-level * instead of just bundle-level accuracy. */ - if (!user_mode(regs)) + if (!user_mode(regs)) do_profile(regs->cr_iip + 4*ia64_psr(regs)->ri); #ifdef CONFIG_SMP @@ -183,52 +174,50 @@ write_unlock(&xtime_lock); } - new_itm += itm.delta; - itm.next[cpu].count = new_itm; + new_itm += local_cpu_data->itm_delta; + local_cpu_data->itm_next = new_itm; if (time_after(new_itm, ia64_get_itc())) break; } - /* - * If we're too close to the next clock tick for comfort, we - * increase the saftey margin by intentionally dropping the - * next tick(s). We do NOT update itm.next accordingly - * because that would force us to call do_timer() which in - * turn would let our clock run too fast (with the potentially - * devastating effect of losing monotony of time). - */ - while (!time_after(new_itm, ia64_get_itc() + itm.delta/2)) - new_itm += itm.delta; - ia64_set_itm(new_itm); -} - -#ifdef CONFIG_IA64_SOFTSDV_HACKS - -/* - * Interrupts must be disabled before calling this routine. - */ -void -ia64_reset_itm (void) -{ - timer_interrupt(0, 0, ia64_task_regs(current)); + do { + /* + * If we're too close to the next clock tick for comfort, we increase the + * saftey margin by intentionally dropping the next tick(s). We do NOT update + * itm.next because that would force us to call do_timer() which in turn would + * let our clock run too fast (with the potentially devastating effect of + * losing monotony of time). + */ + while (!time_after(new_itm, ia64_get_itc() + local_cpu_data->itm_delta/2)) + new_itm += local_cpu_data->itm_delta; + ia64_set_itm(new_itm); + /* double check, in case we got hit by a (slow) PMI: */ + } while (time_after_eq(ia64_get_itc(), new_itm)); } -#endif - /* * Encapsulate access to the itm structure for SMP. */ void __init -ia64_cpu_local_tick(void) +ia64_cpu_local_tick (void) { -#ifdef CONFIG_IA64_SOFTSDV_HACKS - ia64_set_itc(0); -#endif + int cpu = smp_processor_id(); + unsigned long shift = 0, delta; /* arrange for the cycle counter to generate a timer interrupt: */ - ia64_set_itv(TIMER_IRQ, 0); - itm.next[smp_processor_id()].count = ia64_get_itc() + itm.delta; - ia64_set_itm(itm.next[smp_processor_id()].count); + ia64_set_itv(IA64_TIMER_VECTOR); + + delta = local_cpu_data->itm_delta; + /* + * Stagger the timer tick for each CPU so they don't occur all at (almost) the + * same time: + */ + if (cpu) { + unsigned long hi = 1UL << ia64_fls(cpu); + shift = (2*(cpu - hi) + 1) * delta/hi/2; + } + local_cpu_data->itm_next = ia64_get_itc() + delta + shift; + ia64_set_itm(local_cpu_data->itm_next); } void __init @@ -258,33 +247,28 @@ itc_ratio.num = 3; itc_ratio.den = 1; } -#ifdef CONFIG_IA64_SOFTSDV_HACKS - platform_base_freq = 10000000; - proc_ratio.num = 4; proc_ratio.den = 1; - itc_ratio.num = 4; itc_ratio.den = 1; -#else if (platform_base_freq < 40000000) { printk("Platform base frequency %lu bogus---resetting to 75MHz!\n", platform_base_freq); platform_base_freq = 75000000; } -#endif if (!proc_ratio.den) - proc_ratio.num = 1; /* avoid division by zero */ + proc_ratio.den = 1; /* avoid division by zero */ if (!itc_ratio.den) - itc_ratio.num = 1; /* avoid division by zero */ + itc_ratio.den = 1; /* avoid division by zero */ - itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den; - itm.delta = itc_freq / HZ; - printk("CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, ITC freq=%lu.%03luMHz\n", + itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den; + local_cpu_data->itm_delta = (itc_freq + HZ/2) / HZ; + printk("CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, ITC freq=%lu.%03luMHz\n", smp_processor_id(), platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000, - itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000); + itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000); - my_cpu_data.proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den; - my_cpu_data.itc_freq = itc_freq; - my_cpu_data.cyc_per_usec = itc_freq / 1000000; - my_cpu_data.usec_per_cyc = (1000000UL << IA64_USEC_PER_CYC_SHIFT) / itc_freq; + local_cpu_data->proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den; + local_cpu_data->itc_freq = itc_freq; + local_cpu_data->cyc_per_usec = (itc_freq + 500000) / 1000000; + local_cpu_data->usec_per_cyc = ((1000000UL<<IA64_USEC_PER_CYC_SHIFT) + + itc_freq/2)/itc_freq; /* Setup the CPU local timer tick */ ia64_cpu_local_tick(); @@ -299,11 +283,7 @@ void __init time_init (void) { - /* we can't do request_irq() here because the kmalloc() would fail... */ - irq_desc[TIMER_IRQ].status |= IRQ_PER_CPU; - irq_desc[TIMER_IRQ].handler = &irq_type_ia64_sapic; - setup_irq(TIMER_IRQ, &timer_irqaction); - + register_percpu_irq(IA64_TIMER_VECTOR, &timer_irqaction); efi_gettimeofday(&xtime); ia64_init_itm(); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/traps.c linux.ac/arch/ia64/kernel/traps.c --- linux.vanilla/arch/ia64/kernel/traps.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/traps.c Tue Apr 10 18:08:40 2001 @@ -7,8 +7,6 @@ * 05/12/00 grao <goutham.rao@intel.com> : added isr in siginfo for SIGFPE */ -#define FPSWA_DEBUG 1 - /* * The fpu_fault() handler needs to be able to access and update all * floating point registers. Those saved in pt_regs can be accessed @@ -47,31 +45,10 @@ void __init trap_init (void) { - printk("fpswa interface at %lx\n", ia64_boot_param.fpswa); - if (ia64_boot_param.fpswa) { -#define OLD_FIRMWARE -#ifdef OLD_FIRMWARE - /* - * HACK to work around broken firmware. This code - * applies the label fixup to the FPSWA interface and - * works both with old and new (fixed) firmware. - */ - unsigned long addr = (unsigned long) __va(ia64_boot_param.fpswa); - unsigned long gp_val = *(unsigned long *)(addr + 8); - - /* go indirect and indexed to get table address */ - addr = gp_val; - gp_val = *(unsigned long *)(addr + 8); - - while (gp_val == *(unsigned long *)(addr + 8)) { - *(unsigned long *)addr |= PAGE_OFFSET; - *(unsigned long *)(addr + 8) |= PAGE_OFFSET; - addr += 16; - } -#endif + printk("fpswa interface at %lx\n", ia64_boot_param->fpswa); + if (ia64_boot_param->fpswa) /* FPSWA fixup: make the interface pointer a kernel virtual address: */ - fpswa_interface = __va(ia64_boot_param.fpswa); - } + fpswa_interface = __va(ia64_boot_param->fpswa); } void @@ -240,6 +217,7 @@ { fp_state_t fp_state; fpswa_ret_t ret; +#define FPSWA_BUG #ifdef FPSWA_BUG struct ia64_fpreg f6_15[10]; #endif @@ -250,7 +228,7 @@ memset(&fp_state, 0, sizeof(fp_state_t)); /* - * compute fp_state. only FP registers f6 - f11 are used by the + * compute fp_state. only FP registers f6 - f11 are used by the * kernel, so set those bits in the mask and set the low volatile * pointer to point to these registers. */ @@ -263,15 +241,15 @@ f6_15[1] = regs->f7; f6_15[2] = regs->f8; f6_15[3] = regs->f9; - __asm__ ("stf.spill %0=f10%P0" : "=m"(f6_15[4])); - __asm__ ("stf.spill %0=f11%P0" : "=m"(f6_15[5])); - __asm__ ("stf.spill %0=f12%P0" : "=m"(f6_15[6])); - __asm__ ("stf.spill %0=f13%P0" : "=m"(f6_15[7])); - __asm__ ("stf.spill %0=f14%P0" : "=m"(f6_15[8])); - __asm__ ("stf.spill %0=f15%P0" : "=m"(f6_15[9])); + __asm__ ("stf.spill %0=f10%P0" : "=m"(f6_15[4])); + __asm__ ("stf.spill %0=f11%P0" : "=m"(f6_15[5])); + __asm__ ("stf.spill %0=f12%P0" : "=m"(f6_15[6])); + __asm__ ("stf.spill %0=f13%P0" : "=m"(f6_15[7])); + __asm__ ("stf.spill %0=f14%P0" : "=m"(f6_15[8])); + __asm__ ("stf.spill %0=f15%P0" : "=m"(f6_15[9])); fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) f6_15; #endif - /* + /* * unsigned long (*EFI_FPSWA) ( * unsigned long trap_type, * void *Bundle, @@ -287,12 +265,12 @@ (unsigned long *) isr, (unsigned long *) pr, (unsigned long *) ifs, &fp_state); #ifdef FPSWA_BUG - __asm__ ("ldf.fill f10=%0%P0" :: "m"(f6_15[4])); - __asm__ ("ldf.fill f11=%0%P0" :: "m"(f6_15[5])); - __asm__ ("ldf.fill f12=%0%P0" :: "m"(f6_15[6])); - __asm__ ("ldf.fill f13=%0%P0" :: "m"(f6_15[7])); - __asm__ ("ldf.fill f14=%0%P0" :: "m"(f6_15[8])); - __asm__ ("ldf.fill f15=%0%P0" :: "m"(f6_15[9])); + __asm__ ("ldf.fill f10=%0%P0" :: "m"(f6_15[4])); + __asm__ ("ldf.fill f11=%0%P0" :: "m"(f6_15[5])); + __asm__ ("ldf.fill f12=%0%P0" :: "m"(f6_15[6])); + __asm__ ("ldf.fill f13=%0%P0" :: "m"(f6_15[7])); + __asm__ ("ldf.fill f14=%0%P0" :: "m"(f6_15[8])); + __asm__ ("ldf.fill f15=%0%P0" :: "m"(f6_15[9])); regs->f6 = f6_15[0]; regs->f7 = f6_15[1]; regs->f8 = f6_15[2]; @@ -319,21 +297,20 @@ if (copy_from_user(bundle, (void *) fault_ip, sizeof(bundle))) return -1; -#ifdef FPSWA_DEBUG - if (fpu_swa_count > 5 && jiffies - last_time > 5*HZ) + if (jiffies - last_time > 5*HZ) fpu_swa_count = 0; if (++fpu_swa_count < 5) { last_time = jiffies; - printk("%s(%d): floating-point assist fault at ip %016lx\n", + printk(KERN_WARNING "%s(%d): floating-point assist fault at ip %016lx\n", current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri); } -#endif + exception = fp_emulate(fp_fault, bundle, ®s->cr_ipsr, ®s->ar_fpsr, &isr, ®s->pr, - ®s->cr_ifs, regs); + ®s->cr_ifs, regs); if (fp_fault) { if (exception == 0) { /* emulation was successful */ - ia64_increment_ip(regs); + ia64_increment_ip(regs); } else if (exception == -1) { printk("handle_fpu_swa: fp_emulate() returned -1\n"); return -1; @@ -392,7 +369,7 @@ struct siginfo si; char buf[128]; -#ifdef CONFIG_IA64_BRL_EMU +#ifdef CONFIG_IA64_BRL_EMU { extern struct illegal_op_return ia64_emulate_brl (struct pt_regs *, unsigned long); @@ -431,7 +408,7 @@ "IA-64 Reserved Register/Field fault", "Disabled Instruction Set Transition fault", "Unknown fault 5", "Unknown fault 6", "Unknown fault 7", "Illegal Hazard fault", - "Unknown fault 9", "Unknown fault 10", "Unknown fault 11", "Unknown fault 12", + "Unknown fault 9", "Unknown fault 10", "Unknown fault 11", "Unknown fault 12", "Unknown fault 13", "Unknown fault 14", "Unknown fault 15" }; @@ -444,7 +421,7 @@ unsigned long n = vector; char buf[32], *cp; - if (count > 5 && jiffies - last_time > 5*HZ) + if (jiffies - last_time > 5*HZ) count = 0; if (count++ < 5) { @@ -502,7 +479,7 @@ case 35: /* Taken Branch Trap */ case 36: /* Single Step Trap */ switch (vector) { - case 29: + case 29: siginfo.si_code = TRAP_HWBKPT; #ifdef CONFIG_ITANIUM /* @@ -513,7 +490,7 @@ ifa = regs->cr_iip; #endif siginfo.si_addr = (void *) ifa; - break; + break; case 35: siginfo.si_code = TRAP_BRANCH; break; case 36: siginfo.si_code = TRAP_TRACE; break; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/unaligned.c linux.ac/arch/ia64/kernel/unaligned.c --- linux.vanilla/arch/ia64/kernel/unaligned.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/unaligned.c Tue Apr 10 18:08:40 2001 @@ -1,12 +1,16 @@ /* * Architecture-specific unaligned trap handling. * - * Copyright (C) 1999-2000 Hewlett-Packard Co + * Copyright (C) 1999-2001 Hewlett-Packard Co * Copyright (C) 1999-2000 Stephane Eranian <eranian@hpl.hp.com> + * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com> + * + * 2001/01/17 Add support emulation of unaligned kernel accesses. */ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/smp_lock.h> + #include <asm/uaccess.h> #include <asm/rse.h> #include <asm/processor.h> @@ -17,14 +21,28 @@ #undef DEBUG_UNALIGNED_TRAP #ifdef DEBUG_UNALIGNED_TRAP -#define DPRINT(a) { printk("%s, line %d: ", __FUNCTION__, __LINE__); printk a;} +# define DPRINT(a...) do { printk("%s.%u: ", __FUNCTION__, __LINE__); printk (a); } while (0) +# define DDUMP(str,vp,len) dump(str, vp, len) + +static void +dump (const char *str, void *vp, size_t len) +{ + unsigned char *cp = vp; + int i; + + printk("%s", str); + for (i = 0; i < len; ++i) + printk (" %02x", *cp++); + printk("\n"); +} #else -#define DPRINT(a) +# define DPRINT(a...) +# define DDUMP(str,vp,len) #endif #define IA64_FIRST_STACKED_GR 32 #define IA64_FIRST_ROTATING_FR 32 -#define SIGN_EXT9 __IA64_UL(0xffffffffffffff00) +#define SIGN_EXT9 0xffffffffffffff00ul /* * For M-unit: @@ -35,33 +53,34 @@ * --------|------|---------| * 4 | 1 | 6 | = 11 bits * -------------------------- - * However bits [31:30] are not directly useful to distinguish between - * load/store so we can use [35:32] instead, which gives the following + * However bits [31:30] are not directly useful to distinguish between + * load/store so we can use [35:32] instead, which gives the following * mask ([40:32]) using 9 bits. The 'e' comes from the fact that we defer * checking the m-bit until later in the load/store emulation. */ -#define IA64_OPCODE_MASK 0x1ef00000000 +#define IA64_OPCODE_MASK 0x1ef +#define IA64_OPCODE_SHIFT 32 /* * Table C-28 Integer Load/Store - * + * * We ignore [35:32]= 0x6, 0x7, 0xE, 0xF * - * ld8.fill, st8.fill MUST be aligned because the RNATs are based on + * ld8.fill, st8.fill MUST be aligned because the RNATs are based on * the address (bits [8:3]), so we must failed. */ -#define LD_OP 0x08000000000 -#define LDS_OP 0x08100000000 -#define LDA_OP 0x08200000000 -#define LDSA_OP 0x08300000000 -#define LDBIAS_OP 0x08400000000 -#define LDACQ_OP 0x08500000000 +#define LD_OP 0x080 +#define LDS_OP 0x081 +#define LDA_OP 0x082 +#define LDSA_OP 0x083 +#define LDBIAS_OP 0x084 +#define LDACQ_OP 0x085 /* 0x086, 0x087 are not relevant */ -#define LDCCLR_OP 0x08800000000 -#define LDCNC_OP 0x08900000000 -#define LDCCLRACQ_OP 0x08a00000000 -#define ST_OP 0x08c00000000 -#define STREL_OP 0x08d00000000 +#define LDCCLR_OP 0x088 +#define LDCNC_OP 0x089 +#define LDCCLRACQ_OP 0x08a +#define ST_OP 0x08c +#define STREL_OP 0x08d /* 0x08e,0x8f are not relevant */ /* @@ -73,38 +92,38 @@ /* * Table C-30 Integer Load/Store +Imm - * + * * We ignore [35:32]= 0x6, 0x7, 0xE, 0xF * - * ld8.fill, st8.fill must be aligned because the Nat register are based on + * ld8.fill, st8.fill must be aligned because the Nat register are based on * the address, so we must fail and the program must be fixed. */ -#define LD_IMM_OP 0x0a000000000 -#define LDS_IMM_OP 0x0a100000000 -#define LDA_IMM_OP 0x0a200000000 -#define LDSA_IMM_OP 0x0a300000000 -#define LDBIAS_IMM_OP 0x0a400000000 -#define LDACQ_IMM_OP 0x0a500000000 +#define LD_IMM_OP 0x0a0 +#define LDS_IMM_OP 0x0a1 +#define LDA_IMM_OP 0x0a2 +#define LDSA_IMM_OP 0x0a3 +#define LDBIAS_IMM_OP 0x0a4 +#define LDACQ_IMM_OP 0x0a5 /* 0x0a6, 0xa7 are not relevant */ -#define LDCCLR_IMM_OP 0x0a800000000 -#define LDCNC_IMM_OP 0x0a900000000 -#define LDCCLRACQ_IMM_OP 0x0aa00000000 -#define ST_IMM_OP 0x0ac00000000 -#define STREL_IMM_OP 0x0ad00000000 +#define LDCCLR_IMM_OP 0x0a8 +#define LDCNC_IMM_OP 0x0a9 +#define LDCCLRACQ_IMM_OP 0x0aa +#define ST_IMM_OP 0x0ac +#define STREL_IMM_OP 0x0ad /* 0x0ae,0xaf are not relevant */ /* * Table C-32 Floating-point Load/Store */ -#define LDF_OP 0x0c000000000 -#define LDFS_OP 0x0c100000000 -#define LDFA_OP 0x0c200000000 -#define LDFSA_OP 0x0c300000000 +#define LDF_OP 0x0c0 +#define LDFS_OP 0x0c1 +#define LDFA_OP 0x0c2 +#define LDFSA_OP 0x0c3 /* 0x0c6 is irrelevant */ -#define LDFCCLR_OP 0x0c800000000 -#define LDFCNC_OP 0x0c900000000 +#define LDFCCLR_OP 0x0c8 +#define LDFCNC_OP 0x0c9 /* 0x0cb is irrelevant */ -#define STF_OP 0x0cc00000000 +#define STF_OP 0x0cc /* * Table C-33 Floating-point Load +Reg @@ -116,17 +135,17 @@ /* * Table C-34 Floating-point Load/Store +Imm */ -#define LDF_IMM_OP 0x0e000000000 -#define LDFS_IMM_OP 0x0e100000000 -#define LDFA_IMM_OP 0x0e200000000 -#define LDFSA_IMM_OP 0x0e300000000 +#define LDF_IMM_OP 0x0e0 +#define LDFS_IMM_OP 0x0e1 +#define LDFA_IMM_OP 0x0e2 +#define LDFSA_IMM_OP 0x0e3 /* 0x0e6 is irrelevant */ -#define LDFCCLR_IMM_OP 0x0e800000000 -#define LDFCNC_IMM_OP 0x0e900000000 -#define STF_IMM_OP 0x0ec00000000 +#define LDFCCLR_IMM_OP 0x0e8 +#define LDFCNC_IMM_OP 0x0e9 +#define STF_IMM_OP 0x0ec typedef struct { - unsigned long qp:6; /* [0:5] */ + unsigned long qp:6; /* [0:5] */ unsigned long r1:7; /* [6:12] */ unsigned long imm:7; /* [13:19] */ unsigned long r3:7; /* [20:26] */ @@ -170,7 +189,7 @@ #define FR_IN_SW(x) (fr_info[x] & 0x1) static u16 gr_info[32]={ - 0, /* r0 is read-only : WE SHOULD NEVER GET THIS */ + 0, /* r0 is read-only : WE SHOULD NEVER GET THIS */ RPT(r1), RPT(r2), RPT(r3), @@ -186,7 +205,7 @@ }; static u16 fr_info[32]={ - 0, /* constant : WE SHOULD NEVER GET THIS */ + 0, /* constant : WE SHOULD NEVER GET THIS */ 0, /* constant : WE SHOULD NEVER GET THIS */ RSW(f2), RSW(f3), RSW(f4), RSW(f5), @@ -255,162 +274,160 @@ } static void -set_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long val, int nat) +set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, int nat) { - struct switch_stack *sw = (struct switch_stack *)regs - 1; - unsigned long *kbs = ((unsigned long *)current) + IA64_RBS_OFFSET/8; + struct switch_stack *sw = (struct switch_stack *) regs - 1; + unsigned long *bsp, *bspstore, *addr, *rnat_addr, *ubs_end; + unsigned long *kbs = (void *) current + IA64_RBS_OFFSET; + unsigned long rnats, nat_mask; unsigned long on_kbs; - unsigned long *bsp, *bspstore, *addr, *ubs_end, *slot; - unsigned long rnats; - long nlocals; + long sof = (regs->cr_ifs) & 0x7f; - /* - * cr_ifs=[rv:ifm], ifm=[....:sof(6)] - * nlocal=number of locals (in+loc) register of the faulting function - */ - nlocals = (regs->cr_ifs) & 0x7f; + DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld\n", + r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f); - DPRINT(("sw.bsptore=%lx pt.bspstore=%lx\n", sw->ar_bspstore, regs->ar_bspstore)); - DPRINT(("cr.ifs=%lx sof=%ld sol=%ld\n", - regs->cr_ifs, regs->cr_ifs &0x7f, (regs->cr_ifs>>7)&0x7f)); + if ((r1 - 32) >= sof) { + /* this should never happen, as the "rsvd register fault" has higher priority */ + DPRINT("ignoring write to r%lu; only %lu registers are allocated!\n", r1, sof); + return; + } - on_kbs = ia64_rse_num_regs(kbs, (unsigned long *)sw->ar_bspstore); - bspstore = (unsigned long *)regs->ar_bspstore; + on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore); + addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + (r1 - 32)); + if (addr >= kbs) { + /* the register is on the kernel backing store: easy... */ + rnat_addr = ia64_rse_rnat_addr(addr); + if ((unsigned long) rnat_addr >= sw->ar_bspstore) + rnat_addr = &sw->ar_rnat; + nat_mask = 1UL << ia64_rse_slot_num(addr); - DPRINT(("rse_slot_num=0x%lx\n",ia64_rse_slot_num((unsigned long *)sw->ar_bspstore))); - DPRINT(("kbs=%p nlocals=%ld\n", (void *) kbs, nlocals)); - DPRINT(("bspstore next rnat slot %p\n", - (void *) ia64_rse_rnat_addr((unsigned long *)sw->ar_bspstore))); - DPRINT(("on_kbs=%ld rnats=%ld\n", - on_kbs, ((sw->ar_bspstore-(unsigned long)kbs)>>3) - on_kbs)); + *addr = val; + if (nat) + *rnat_addr |= nat_mask; + else + *rnat_addr &= ~nat_mask; + return; + } /* - * See get_rse_reg() for an explanation on the following instructions + * Avoid using user_mode() here: with "epc", we cannot use the privilege level to + * infer whether the interrupt task was running on the kernel backing store. */ + if (regs->r12 >= TASK_SIZE) { + DPRINT("ignoring kernel write to r%lu; register isn't on the RBS!", r1); + return; + } + + bspstore = (unsigned long *) regs->ar_bspstore; ubs_end = ia64_rse_skip_regs(bspstore, on_kbs); - bsp = ia64_rse_skip_regs(ubs_end, -nlocals); - addr = slot = ia64_rse_skip_regs(bsp, r1 - 32); + bsp = ia64_rse_skip_regs(ubs_end, -sof); + addr = ia64_rse_skip_regs(bsp, r1 - 32); - DPRINT(("ubs_end=%p bsp=%p addr=%p slot=0x%lx\n", - (void *) ubs_end, (void *) bsp, (void *) addr, ia64_rse_slot_num(addr))); + DPRINT("ubs_end=%p bsp=%p addr=%px\n", (void *) ubs_end, (void *) bsp, (void *) addr); - ia64_poke(regs, current, (unsigned long)addr, val); + ia64_poke(current, (unsigned long) ubs_end, (unsigned long) addr, val); - /* - * addr will now contain the address of the RNAT for the register - */ - addr = ia64_rse_rnat_addr(addr); + rnat_addr = ia64_rse_rnat_addr(addr); - ia64_peek(regs, current, (unsigned long)addr, &rnats); - DPRINT(("rnat @%p = 0x%lx nat=%d rnatval=%lx\n", - (void *) addr, rnats, nat, rnats &ia64_rse_slot_num(slot))); - - if (nat) { - rnats |= __IA64_UL(1) << ia64_rse_slot_num(slot); - } else { - rnats &= ~(__IA64_UL(1) << ia64_rse_slot_num(slot)); - } - ia64_poke(regs, current, (unsigned long)addr, rnats); + ia64_peek(current, (unsigned long) ubs_end, (unsigned long) rnat_addr, &rnats); + DPRINT("rnat @%p = 0x%lx nat=%d old nat=%ld\n", + (void *) rnat_addr, rnats, nat, (rnats >> ia64_rse_slot_num(addr)) & 1); - DPRINT(("rnat changed to @%p = 0x%lx\n", (void *) addr, rnats)); + nat_mask = 1UL << ia64_rse_slot_num(addr); + if (nat) + rnats |= nat_mask; + else + rnats &= ~nat_mask; + ia64_poke(current, (unsigned long) ubs_end, (unsigned long) rnat_addr, rnats); + + DPRINT("rnat changed to @%p = 0x%lx\n", (void *) rnat_addr, rnats); } static void -get_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long *val, int *nat) +get_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long *val, int *nat) { - struct switch_stack *sw = (struct switch_stack *)regs - 1; - unsigned long *kbs = (unsigned long *)current + IA64_RBS_OFFSET/8; + struct switch_stack *sw = (struct switch_stack *) regs - 1; + unsigned long *bsp, *addr, *rnat_addr, *ubs_end, *bspstore; + unsigned long *kbs = (void *) current + IA64_RBS_OFFSET; + unsigned long rnats, nat_mask; unsigned long on_kbs; - long nlocals; - unsigned long *bsp, *addr, *ubs_end, *slot, *bspstore; - unsigned long rnats; + long sof = (regs->cr_ifs) & 0x7f; - /* - * cr_ifs=[rv:ifm], ifm=[....:sof(6)] - * nlocals=number of local registers in the faulting function - */ - nlocals = (regs->cr_ifs) & 0x7f; + DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld\n", + r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f); - /* - * save_switch_stack does a flushrs and saves bspstore. - * on_kbs = actual number of registers saved on kernel backing store - * (taking into accound potential RNATs) - * - * Note that this number can be greater than nlocals if the dirty - * parititions included more than one stack frame at the time we - * switched to KBS - */ - on_kbs = ia64_rse_num_regs(kbs, (unsigned long *)sw->ar_bspstore); - bspstore = (unsigned long *)regs->ar_bspstore; + if ((r1 - 32) >= sof) { + /* this should never happen, as the "rsvd register fault" has higher priority */ + DPRINT("ignoring read from r%lu; only %lu registers are allocated!\n", r1, sof); + return; + } + + on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore); + addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + (r1 - 32)); + if (addr >= kbs) { + /* the register is on the kernel backing store: easy... */ + *val = *addr; + if (nat) { + rnat_addr = ia64_rse_rnat_addr(addr); + if ((unsigned long) rnat_addr >= sw->ar_bspstore) + rnat_addr = &sw->ar_rnat; + nat_mask = 1UL << ia64_rse_slot_num(addr); + *nat = (*rnat_addr & nat_mask) != 0; + } + return; + } /* - * To simplify the logic, we calculate everything as if there was only - * one backing store i.e., the user one (UBS). We let it to peek/poke - * to figure out whether the register we're looking for really is - * on the UBS or on KBS. - * - * regs->ar_bsptore = address of last register saved on UBS (before switch) - * - * ubs_end = virtual end of the UBS (if everything had been spilled there) - * - * We know that ubs_end is the point where the last register on the - * stack frame we're interested in as been saved. So we need to walk - * our way backward to figure out what the BSP "was" for that frame, - * this will give us the location of r32. - * - * bsp = "virtual UBS" address of r32 for our frame - * - * Finally, get compute the address of the register we're looking for - * using bsp as our base (move up again). - * - * Please note that in our case, we know that the register is necessarily - * on the KBS because we are only interested in the current frame at the moment - * we got the exception i.e., bsp is not changed until we switch to KBS. + * Avoid using user_mode() here: with "epc", we cannot use the privilege level to + * infer whether the interrupt task was running on the kernel backing store. */ + if (regs->r12 >= TASK_SIZE) { + DPRINT("ignoring kernel read of r%lu; register isn't on the RBS!", r1); + return; + } + + bspstore = (unsigned long *)regs->ar_bspstore; ubs_end = ia64_rse_skip_regs(bspstore, on_kbs); - bsp = ia64_rse_skip_regs(ubs_end, -nlocals); - addr = slot = ia64_rse_skip_regs(bsp, r1 - 32); + bsp = ia64_rse_skip_regs(ubs_end, -sof); + addr = ia64_rse_skip_regs(bsp, r1 - 32); - DPRINT(("ubs_end=%p bsp=%p addr=%p slot=0x%lx\n", - (void *) ubs_end, (void *) bsp, (void *) addr, ia64_rse_slot_num(addr))); - - ia64_peek(regs, current, (unsigned long)addr, val); + DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr); - /* - * addr will now contain the address of the RNAT for the register - */ - addr = ia64_rse_rnat_addr(addr); + ia64_peek(current, (unsigned long) ubs_end, (unsigned long) addr, val); - ia64_peek(regs, current, (unsigned long)addr, &rnats); - DPRINT(("rnat @%p = 0x%lx\n", (void *) addr, rnats)); - - if (nat) - *nat = rnats >> ia64_rse_slot_num(slot) & 0x1; + if (nat) { + rnat_addr = ia64_rse_rnat_addr(addr); + nat_mask = 1UL << ia64_rse_slot_num(addr); + + DPRINT("rnat @%p = 0x%lx\n", (void *) rnat_addr, rnats); + + ia64_peek(current, (unsigned long) ubs_end, (unsigned long) rnat_addr, &rnats); + *nat = (rnats & nat_mask) != 0; + } } static void -setreg(unsigned long regnum, unsigned long val, int nat, struct pt_regs *regs) +setreg (unsigned long regnum, unsigned long val, int nat, struct pt_regs *regs) { - struct switch_stack *sw = (struct switch_stack *)regs -1; + struct switch_stack *sw = (struct switch_stack *) regs - 1; unsigned long addr; unsigned long bitmask; unsigned long *unat; - /* * First takes care of stacked registers */ - if (regnum >= IA64_FIRST_STACKED_GR) { + if (regnum >= IA64_FIRST_STACKED_GR) { set_rse_reg(regs, regnum, val, nat); return; } /* - * Using r0 as a target raises a General Exception fault which has - * higher priority than the Unaligned Reference fault. - */ + * Using r0 as a target raises a General Exception fault which has higher priority + * than the Unaligned Reference fault. + */ /* * Now look at registers in [0-31] range and init correct UNAT @@ -422,8 +439,8 @@ addr = (unsigned long)regs; unat = &sw->caller_unat; } - DPRINT(("tmp_base=%lx switch_stack=%s offset=%d\n", - addr, unat==&sw->ar_unat ? "yes":"no", GR_OFFS(regnum))); + DPRINT("tmp_base=%lx switch_stack=%s offset=%d\n", + addr, unat==&sw->ar_unat ? "yes":"no", GR_OFFS(regnum)); /* * add offset from base of struct * and do it ! @@ -436,20 +453,20 @@ * We need to clear the corresponding UNAT bit to fully emulate the load * UNAT bit_pos = GR[r3]{8:3} form EAS-2.4 */ - bitmask = __IA64_UL(1) << (addr >> 3 & 0x3f); - DPRINT(("*0x%lx=0x%lx NaT=%d prev_unat @%p=%lx\n", addr, val, nat, (void *) unat, *unat)); + bitmask = 1UL << (addr >> 3 & 0x3f); + DPRINT("*0x%lx=0x%lx NaT=%d prev_unat @%p=%lx\n", addr, val, nat, (void *) unat, *unat); if (nat) { *unat |= bitmask; } else { *unat &= ~bitmask; } - DPRINT(("*0x%lx=0x%lx NaT=%d new unat: %p=%lx\n", addr, val, nat, (void *) unat,*unat)); + DPRINT("*0x%lx=0x%lx NaT=%d new unat: %p=%lx\n", addr, val, nat, (void *) unat,*unat); } #define IA64_FPH_OFFS(r) (r - IA64_FIRST_ROTATING_FR) static void -setfpreg(unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs) +setfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs) { struct switch_stack *sw = (struct switch_stack *)regs - 1; unsigned long addr; @@ -465,7 +482,7 @@ * * For now, we are using approach (1). */ - if (regnum >= IA64_FIRST_ROTATING_FR) { + if (regnum >= IA64_FIRST_ROTATING_FR) { ia64_sync_fph(current); current->thread.fph[IA64_FPH_OFFS(regnum)] = *fpval; } else { @@ -477,18 +494,18 @@ } else { addr = (unsigned long)regs; } - - DPRINT(("tmp_base=%lx offset=%d\n", addr, FR_OFFS(regnum))); + + DPRINT("tmp_base=%lx offset=%d\n", addr, FR_OFFS(regnum)); addr += FR_OFFS(regnum); *(struct ia64_fpreg *)addr = *fpval; /* - * mark the low partition as being used now + * mark the low partition as being used now * * It is highly unlikely that this bit is not already set, but * let's do it for safety. - */ + */ regs->cr_ipsr |= IA64_PSR_MFL; } } @@ -497,40 +514,40 @@ * Those 2 inline functions generate the spilled versions of the constant floating point * registers which can be used with stfX */ -static inline void -float_spill_f0(struct ia64_fpreg *final) +static inline void +float_spill_f0 (struct ia64_fpreg *final) { __asm__ __volatile__ ("stf.spill [%0]=f0" :: "r"(final) : "memory"); } -static inline void -float_spill_f1(struct ia64_fpreg *final) +static inline void +float_spill_f1 (struct ia64_fpreg *final) { __asm__ __volatile__ ("stf.spill [%0]=f1" :: "r"(final) : "memory"); } static void -getfpreg(unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs) +getfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs) { - struct switch_stack *sw = (struct switch_stack *)regs -1; + struct switch_stack *sw = (struct switch_stack *) regs - 1; unsigned long addr; /* - * From EAS-2.5: FPDisableFault has higher priority than - * Unaligned Fault. Thus, when we get here, we know the partition is + * From EAS-2.5: FPDisableFault has higher priority than + * Unaligned Fault. Thus, when we get here, we know the partition is * enabled. * * When regnum > 31, the register is still live and we need to force a save * to current->thread.fph to get access to it. See discussion in setfpreg() * for reasons and other ways of doing this. */ - if (regnum >= IA64_FIRST_ROTATING_FR) { + if (regnum >= IA64_FIRST_ROTATING_FR) { ia64_flush_fph(current); *fpval = current->thread.fph[IA64_FPH_OFFS(regnum)]; } else { /* * f0 = 0.0, f1= 1.0. Those registers are constant and are thus - * not saved, we must generate their spilled form on the fly + * not saved, we must generate their spilled form on the fly */ switch(regnum) { case 0: @@ -546,8 +563,8 @@ addr = FR_IN_SW(regnum) ? (unsigned long)sw : (unsigned long)regs; - DPRINT(("is_sw=%d tmp_base=%lx offset=0x%x\n", - FR_IN_SW(regnum), addr, FR_OFFS(regnum))); + DPRINT("is_sw=%d tmp_base=%lx offset=0x%x\n", + FR_IN_SW(regnum), addr, FR_OFFS(regnum)); addr += FR_OFFS(regnum); *fpval = *(struct ia64_fpreg *)addr; @@ -557,12 +574,12 @@ static void -getreg(unsigned long regnum, unsigned long *val, int *nat, struct pt_regs *regs) +getreg (unsigned long regnum, unsigned long *val, int *nat, struct pt_regs *regs) { - struct switch_stack *sw = (struct switch_stack *)regs -1; + struct switch_stack *sw = (struct switch_stack *) regs - 1; unsigned long addr, *unat; - if (regnum >= IA64_FIRST_STACKED_GR) { + if (regnum >= IA64_FIRST_STACKED_GR) { get_rse_reg(regs, regnum, val, nat); return; } @@ -588,7 +605,7 @@ unat = &sw->caller_unat; } - DPRINT(("addr_base=%lx offset=0x%x\n", addr, GR_OFFS(regnum))); + DPRINT("addr_base=%lx offset=0x%x\n", addr, GR_OFFS(regnum)); addr += GR_OFFS(regnum); @@ -602,16 +619,16 @@ } static void -emulate_load_updates(update_t type, load_store_t *ld, struct pt_regs *regs, unsigned long ifa) -{ +emulate_load_updates (update_t type, load_store_t ld, struct pt_regs *regs, unsigned long ifa) +{ /* - * IMPORTANT: + * IMPORTANT: * Given the way we handle unaligned speculative loads, we should * not get to this point in the code but we keep this sanity check, * just in case. */ - if (ld->x6_op == 1 || ld->x6_op == 3) { - printk(KERN_ERR __FUNCTION__": register update on speculative load, error\n"); + if (ld.x6_op == 1 || ld.x6_op == 3) { + printk(KERN_ERR __FUNCTION__": register update on speculative load, error\n"); die_if_kernel("unaligned reference on specualtive load with register update\n", regs, 30); } @@ -624,18 +641,18 @@ if (type == UPD_IMMEDIATE) { unsigned long imm; - /* - * Load +Imm: ldXZ r1=[r3],imm(9) - * + /* + * Load +Imm: ldXZ r1=[r3],imm(9) + * * - * form imm9: [13:19] contain the first 7 bits - */ - imm = ld->x << 7 | ld->imm; + * form imm9: [13:19] contain the first 7 bits + */ + imm = ld.x << 7 | ld.imm; /* * sign extend (1+8bits) if m set */ - if (ld->m) imm |= SIGN_EXT9; + if (ld.m) imm |= SIGN_EXT9; /* * ifa == r3 and we know that the NaT bit on r3 was clear so @@ -643,109 +660,79 @@ */ ifa += imm; - setreg(ld->r3, ifa, 0, regs); + setreg(ld.r3, ifa, 0, regs); - DPRINT(("ld.x=%d ld.m=%d imm=%ld r3=0x%lx\n", ld->x, ld->m, imm, ifa)); + DPRINT("ld.x=%d ld.m=%d imm=%ld r3=0x%lx\n", ld.x, ld.m, imm, ifa); - } else if (ld->m) { + } else if (ld.m) { unsigned long r2; int nat_r2; /* * Load +Reg Opcode: ldXZ r1=[r3],r2 * - * Note: that we update r3 even in the case of ldfX.a + * Note: that we update r3 even in the case of ldfX.a * (where the load does not happen) * * The way the load algorithm works, we know that r3 does not * have its NaT bit set (would have gotten NaT consumption - * before getting the unaligned fault). So we can use ifa + * before getting the unaligned fault). So we can use ifa * which equals r3 at this point. * * IMPORTANT: - * The above statement holds ONLY because we know that we + * The above statement holds ONLY because we know that we * never reach this code when trying to do a ldX.s. - * If we ever make it to here on an ldfX.s then + * If we ever make it to here on an ldfX.s then */ - getreg(ld->imm, &r2, &nat_r2, regs); - + getreg(ld.imm, &r2, &nat_r2, regs); + ifa += r2; - + /* * propagate Nat r2 -> r3 */ - setreg(ld->r3, ifa, nat_r2, regs); + setreg(ld.r3, ifa, nat_r2, regs); - DPRINT(("imm=%d r2=%ld r3=0x%lx nat_r2=%d\n",ld->imm, r2, ifa, nat_r2)); + DPRINT("imm=%d r2=%ld r3=0x%lx nat_r2=%d\n",ld.imm, r2, ifa, nat_r2); } } static int -emulate_load_int(unsigned long ifa, load_store_t *ld, struct pt_regs *regs) +emulate_load_int (unsigned long ifa, load_store_t ld, struct pt_regs *regs) { - unsigned long val; - unsigned int len = 1<< ld->x6_sz; - - /* - * the macro supposes sequential access (which is the case) - * if the first byte is an invalid address we return here. Otherwise - * there is a guard page at the top of the user's address page and - * the first access would generate a NaT consumption fault and return - * with a SIGSEGV, which is what we want. - * - * Note: the first argument is ignored - */ - if (access_ok(VERIFY_READ, (void *)ifa, len) < 0) { - DPRINT(("verify area failed on %lx\n", ifa)); - return -1; - } + unsigned int len = 1 << ld.x6_sz; /* * r0, as target, doesn't need to be checked because Illegal Instruction * faults have higher priority than unaligned faults. * - * r0 cannot be found as the base as it would never generate an + * r0 cannot be found as the base as it would never generate an * unaligned reference. */ /* - * ldX.a we don't try to emulate anything but we must - * invalidate the ALAT entry. + * ldX.a we don't try to emulate anything but we must invalidate the ALAT entry. * See comment below for explanation on how we handle ldX.a */ - if (ld->x6_op != 0x2) { - /* - * we rely on the macros in unaligned.h for now i.e., - * we let the compiler figure out how to read memory gracefully. - * - * We need this switch/case because the way the inline function - * works. The code is optimized by the compiler and looks like - * a single switch/case. - */ - switch(len) { - case 2: - val = ia64_get_unaligned((void *)ifa, 2); - break; - case 4: - val = ia64_get_unaligned((void *)ifa, 4); - break; - case 8: - val = ia64_get_unaligned((void *)ifa, 8); - break; - default: - DPRINT(("unknown size: x6=%d\n", ld->x6_sz)); - return -1; - } + if (ld.x6_op != 0x2) { + unsigned long val = 0; - setreg(ld->r1, val, 0, regs); + if (len != 2 && len != 4 && len != 8) { + DPRINT("unknown size: x6=%d\n", ld.x6_sz); + return -1; + } + /* this assumes little-endian byte-order: */ + if (copy_from_user(&val, (void *) ifa, len)) + return -1; + setreg(ld.r1, val, 0, regs); } /* * check for updates on any kind of loads */ - if (ld->op == 0x5 || ld->m) - emulate_load_updates(ld->op == 0x5 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa); + if (ld.op == 0x5 || ld.m) + emulate_load_updates(ld.op == 0x5 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa); /* * handling of various loads (based on EAS2.4): @@ -753,7 +740,6 @@ * ldX.acq (ordered load): * - acquire semantics would have been used, so force fence instead. * - * * ldX.c.clr (check load and clear): * - if we get to this handler, it's because the entry was not in the ALAT. * Therefore the operation reverts to a normal load @@ -764,15 +750,15 @@ * ldX.c.clr.acq (ordered check load and clear): * - same as above for c.clr part. The load needs to have acquire semantics. So * we use the fence semantics which is stronger and thus ensures correctness. - * + * * ldX.a (advanced load): - * - suppose ldX.a r1=[r3]. If we get to the unaligned trap it's because the - * address doesn't match requested size alignement. This means that we would + * - suppose ldX.a r1=[r3]. If we get to the unaligned trap it's because the + * address doesn't match requested size alignement. This means that we would * possibly need more than one load to get the result. * * The load part can be handled just like a normal load, however the difficult * part is to get the right thing into the ALAT. The critical piece of information - * in the base address of the load & size. To do that, a ld.a must be executed, + * in the base address of the load & size. To do that, a ld.a must be executed, * clearly any address can be pushed into the table by using ld1.a r1=[r3]. Now * if we use the same target register, we will be okay for the check.a instruction. * If we look at the store, basically a stX [r3]=r1 checks the ALAT for any entry @@ -791,7 +777,7 @@ * store & shift to temporary; * ld1.a r1=[r3] * store & shift to temporary; - * r1=temporary + * r1=temporary * * So int this case, you would get the right value is r1 but the wrong info in * the ALAT. Notice that you could do it in reverse to finish with address 3 @@ -815,7 +801,7 @@ * So it's okay NOT to do any actual load on an unaligned ld.a. However the ALAT * must be invalidated for the register (so that's chck.a.*,ld.c.* don't pick up * a stale entry later) The register base update MUST also be performed. - * + * * Now what is the content of the register and its NaT bit in the case we don't * do the load ? EAS2.4, says (in case an actual load is needed) * @@ -828,40 +814,26 @@ */ /* - * when the load has the .acq completer then + * when the load has the .acq completer then * use ordering fence. */ - if (ld->x6_op == 0x5 || ld->x6_op == 0xa) + if (ld.x6_op == 0x5 || ld.x6_op == 0xa) mb(); /* * invalidate ALAT entry in case of advanced load */ - if (ld->x6_op == 0x2) - invala_gr(ld->r1); + if (ld.x6_op == 0x2) + invala_gr(ld.r1); return 0; } static int -emulate_store_int(unsigned long ifa, load_store_t *ld, struct pt_regs *regs) +emulate_store_int (unsigned long ifa, load_store_t ld, struct pt_regs *regs) { unsigned long r2; - unsigned int len = 1<< ld->x6_sz; - - /* - * the macro supposes sequential access (which is the case) - * if the first byte is an invalid address we return here. Otherwise - * there is a guard page at the top of the user's address page and - * the first access would generate a NaT consumption fault and return - * with a SIGSEGV, which is what we want. - * - * Note: the first argument is ignored - */ - if (access_ok(VERIFY_WRITE, (void *)ifa, len) < 0) { - DPRINT(("verify area failed on %lx\n",ifa)); - return -1; - } + unsigned int len = 1 << ld.x6_sz; /* * if we get to this handler, Nat bits on both r3 and r2 have already @@ -869,7 +841,7 @@ * * extract the value to be stored */ - getreg(ld->imm, &r2, 0, regs); + getreg(ld.imm, &r2, 0, regs); /* * we rely on the macros in unaligned.h for now i.e., @@ -879,48 +851,43 @@ * works. The code is optimized by the compiler and looks like * a single switch/case. */ - DPRINT(("st%d [%lx]=%lx\n", len, ifa, r2)); + DPRINT("st%d [%lx]=%lx\n", len, ifa, r2); - switch(len) { - case 2: - ia64_put_unaligned(r2, (void *)ifa, 2); - break; - case 4: - ia64_put_unaligned(r2, (void *)ifa, 4); - break; - case 8: - ia64_put_unaligned(r2, (void *)ifa, 8); - break; - default: - DPRINT(("unknown size: x6=%d\n", ld->x6_sz)); - return -1; + if (len != 2 && len != 4 && len != 8) { + DPRINT("unknown size: x6=%d\n", ld.x6_sz); + return -1; } + + /* this assumes little-endian byte-order: */ + if (copy_to_user((void *) ifa, &r2, len)) + return -1; + /* * stX [r3]=r2,imm(9) * * NOTE: - * ld->r3 can never be r0, because r0 would not generate an + * ld.r3 can never be r0, because r0 would not generate an * unaligned access. */ - if (ld->op == 0x5) { + if (ld.op == 0x5) { unsigned long imm; /* * form imm9: [12:6] contain first 7bits */ - imm = ld->x << 7 | ld->r1; + imm = ld.x << 7 | ld.r1; /* * sign extend (8bits) if m set */ - if (ld->m) imm |= SIGN_EXT9; + if (ld.m) imm |= SIGN_EXT9; /* * ifa == r3 (NaT is necessarily cleared) */ ifa += imm; - DPRINT(("imm=%lx r3=%lx\n", imm, ifa)); - - setreg(ld->r3, ifa, 0, regs); + DPRINT("imm=%lx r3=%lx\n", imm, ifa); + + setreg(ld.r3, ifa, 0, regs); } /* * we don't have alat_invalidate_multiple() so we need @@ -931,7 +898,7 @@ /* * stX.rel: use fence instead of release */ - if (ld->x6_op == 0xd) + if (ld.x6_op == 0xd) mb(); return 0; @@ -940,120 +907,108 @@ /* * floating point operations sizes in bytes */ -static const unsigned short float_fsz[4]={ +static const unsigned char float_fsz[4]={ 16, /* extended precision (e) */ 8, /* integer (8) */ 4, /* single precision (s) */ 8 /* double precision (d) */ }; -static inline void -mem2float_extended(struct ia64_fpreg *init, struct ia64_fpreg *final) +static inline void +mem2float_extended (struct ia64_fpreg *init, struct ia64_fpreg *final) { __asm__ __volatile__ ("ldfe f6=[%0];; stf.spill [%1]=f6" :: "r"(init), "r"(final) : "f6","memory"); } -static inline void -mem2float_integer(struct ia64_fpreg *init, struct ia64_fpreg *final) +static inline void +mem2float_integer (struct ia64_fpreg *init, struct ia64_fpreg *final) { __asm__ __volatile__ ("ldf8 f6=[%0];; stf.spill [%1]=f6" :: "r"(init), "r"(final) : "f6","memory"); } -static inline void -mem2float_single(struct ia64_fpreg *init, struct ia64_fpreg *final) +static inline void +mem2float_single (struct ia64_fpreg *init, struct ia64_fpreg *final) { __asm__ __volatile__ ("ldfs f6=[%0];; stf.spill [%1]=f6" :: "r"(init), "r"(final) : "f6","memory"); } -static inline void -mem2float_double(struct ia64_fpreg *init, struct ia64_fpreg *final) +static inline void +mem2float_double (struct ia64_fpreg *init, struct ia64_fpreg *final) { __asm__ __volatile__ ("ldfd f6=[%0];; stf.spill [%1]=f6" :: "r"(init), "r"(final) : "f6","memory"); } -static inline void -float2mem_extended(struct ia64_fpreg *init, struct ia64_fpreg *final) +static inline void +float2mem_extended (struct ia64_fpreg *init, struct ia64_fpreg *final) { __asm__ __volatile__ ("ldf.fill f6=[%0];; stfe [%1]=f6" :: "r"(init), "r"(final) : "f6","memory"); } -static inline void -float2mem_integer(struct ia64_fpreg *init, struct ia64_fpreg *final) +static inline void +float2mem_integer (struct ia64_fpreg *init, struct ia64_fpreg *final) { __asm__ __volatile__ ("ldf.fill f6=[%0];; stf8 [%1]=f6" :: "r"(init), "r"(final) : "f6","memory"); } -static inline void -float2mem_single(struct ia64_fpreg *init, struct ia64_fpreg *final) +static inline void +float2mem_single (struct ia64_fpreg *init, struct ia64_fpreg *final) { __asm__ __volatile__ ("ldf.fill f6=[%0];; stfs [%1]=f6" :: "r"(init), "r"(final) : "f6","memory"); } -static inline void -float2mem_double(struct ia64_fpreg *init, struct ia64_fpreg *final) +static inline void +float2mem_double (struct ia64_fpreg *init, struct ia64_fpreg *final) { __asm__ __volatile__ ("ldf.fill f6=[%0];; stfd [%1]=f6" :: "r"(init), "r"(final) : "f6","memory"); } static int -emulate_load_floatpair(unsigned long ifa, load_store_t *ld, struct pt_regs *regs) +emulate_load_floatpair (unsigned long ifa, load_store_t ld, struct pt_regs *regs) { struct ia64_fpreg fpr_init[2]; struct ia64_fpreg fpr_final[2]; - unsigned long len = float_fsz[ld->x6_sz]; + unsigned long len = float_fsz[ld.x6_sz]; - if (access_ok(VERIFY_READ, (void *)ifa, len<<1) < 0) { - DPRINT(("verify area failed on %lx\n", ifa)); - return -1; - } /* * fr0 & fr1 don't need to be checked because Illegal Instruction * faults have higher priority than unaligned faults. * - * r0 cannot be found as the base as it would never generate an + * r0 cannot be found as the base as it would never generate an * unaligned reference. */ - /* + /* * make sure we get clean buffers */ - memset(&fpr_init,0, sizeof(fpr_init)); - memset(&fpr_final,0, sizeof(fpr_final)); + memset(&fpr_init, 0, sizeof(fpr_init)); + memset(&fpr_final, 0, sizeof(fpr_final)); /* * ldfpX.a: we don't try to emulate anything but we must * invalidate the ALAT entry and execute updates, if any. */ - if (ld->x6_op != 0x2) { - /* - * does the unaligned access - */ - memcpy(&fpr_init[0], (void *)ifa, len); - memcpy(&fpr_init[1], (void *)(ifa+len), len); + if (ld.x6_op != 0x2) { + /* this assumes little-endian byte-order: */ - DPRINT(("ld.r1=%d ld.imm=%d x6_sz=%d\n", ld->r1, ld->imm, ld->x6_sz)); -#ifdef DEBUG_UNALIGNED_TRAP - { int i; char *c = (char *)&fpr_init; - printk("fpr_init= "); - for(i=0; i < len<<1; i++ ) { - printk("%02x ", c[i]&0xff); - } - printk("\n"); - } -#endif + if (copy_from_user(&fpr_init[0], (void *) ifa, len) + || copy_from_user(&fpr_init[1], (void *) (ifa + len), len)) + return -1; + + DPRINT("ld.r1=%d ld.imm=%d x6_sz=%d\n", ld.r1, ld.imm, ld.x6_sz); + DDUMP("frp_init =", &fpr_init, 2*len); /* * XXX fixme - * Could optimize inlines by using ldfpX & 2 spills + * Could optimize inlines by using ldfpX & 2 spills */ - switch( ld->x6_sz ) { + switch( ld.x6_sz ) { case 0: mem2float_extended(&fpr_init[0], &fpr_final[0]); mem2float_extended(&fpr_init[1], &fpr_final[1]); @@ -1071,15 +1026,7 @@ mem2float_double(&fpr_init[1], &fpr_final[1]); break; } -#ifdef DEBUG_UNALIGNED_TRAP - { int i; char *c = (char *)&fpr_final; - printk("fpr_final= "); - for(i=0; i < len<<1; i++ ) { - printk("%02x ", c[i]&0xff); - } - printk("\n"); - } -#endif + DDUMP("fpr_final =", &fpr_final, 2*len); /* * XXX fixme * @@ -1087,16 +1034,15 @@ * use the storage from the saved context i.e., the actual final * destination (pt_regs, switch_stack or thread structure). */ - setfpreg(ld->r1, &fpr_final[0], regs); - setfpreg(ld->imm, &fpr_final[1], regs); + setfpreg(ld.r1, &fpr_final[0], regs); + setfpreg(ld.imm, &fpr_final[1], regs); } /* * Check for updates: only immediate updates are available for this * instruction. */ - if (ld->m) { - + if (ld.m) { /* * the immediate is implicit given the ldsz of the operation: * single: 8 (2x4) and for all others it's 16 (2x8) @@ -1104,57 +1050,45 @@ ifa += len<<1; /* - * IMPORTANT: + * IMPORTANT: * the fact that we force the NaT of r3 to zero is ONLY valid * as long as we don't come here with a ldfpX.s. * For this reason we keep this sanity check */ - if (ld->x6_op == 1 || ld->x6_op == 3) { - printk(KERN_ERR "%s: register update on speculative load pair, error\n", - __FUNCTION__); - } - + if (ld.x6_op == 1 || ld.x6_op == 3) + printk(KERN_ERR __FUNCTION__": register update on speculative load pair, " + "error\n"); - setreg(ld->r3, ifa, 0, regs); + setreg(ld.r3, ifa, 0, regs); } /* * Invalidate ALAT entries, if any, for both registers. */ - if (ld->x6_op == 0x2) { - invala_fr(ld->r1); - invala_fr(ld->imm); + if (ld.x6_op == 0x2) { + invala_fr(ld.r1); + invala_fr(ld.imm); } return 0; } static int -emulate_load_float(unsigned long ifa, load_store_t *ld, struct pt_regs *regs) +emulate_load_float (unsigned long ifa, load_store_t ld, struct pt_regs *regs) { struct ia64_fpreg fpr_init; struct ia64_fpreg fpr_final; - unsigned long len = float_fsz[ld->x6_sz]; + unsigned long len = float_fsz[ld.x6_sz]; /* - * check for load pair because our masking scheme is not fine grain enough - if (ld->x == 1) return emulate_load_floatpair(ifa,ld,regs); - */ - - if (access_ok(VERIFY_READ, (void *)ifa, len) < 0) { - DPRINT(("verify area failed on %lx\n", ifa)); - return -1; - } - /* * fr0 & fr1 don't need to be checked because Illegal Instruction * faults have higher priority than unaligned faults. * - * r0 cannot be found as the base as it would never generate an + * r0 cannot be found as the base as it would never generate an * unaligned reference. */ - - /* + /* * make sure we get clean buffers */ memset(&fpr_init,0, sizeof(fpr_init)); @@ -1165,27 +1099,16 @@ * invalidate the ALAT entry. * See comments in ldX for descriptions on how the various loads are handled. */ - if (ld->x6_op != 0x2) { - - /* - * does the unaligned access - */ - memcpy(&fpr_init, (void *)ifa, len); + if (ld.x6_op != 0x2) { + if (copy_from_user(&fpr_init, (void *) ifa, len)) + return -1; - DPRINT(("ld.r1=%d x6_sz=%d\n", ld->r1, ld->x6_sz)); -#ifdef DEBUG_UNALIGNED_TRAP - { int i; char *c = (char *)&fpr_init; - printk("fpr_init= "); - for(i=0; i < len; i++ ) { - printk("%02x ", c[i]&0xff); - } - printk("\n"); - } -#endif + DPRINT("ld.r1=%d x6_sz=%d\n", ld.r1, ld.x6_sz); + DDUMP("fpr_init =", &fpr_init, len); /* * we only do something for x6_op={0,8,9} */ - switch( ld->x6_sz ) { + switch( ld.x6_sz ) { case 0: mem2float_extended(&fpr_init, &fpr_final); break; @@ -1199,15 +1122,7 @@ mem2float_double(&fpr_init, &fpr_final); break; } -#ifdef DEBUG_UNALIGNED_TRAP - { int i; char *c = (char *)&fpr_final; - printk("fpr_final= "); - for(i=0; i < len; i++ ) { - printk("%02x ", c[i]&0xff); - } - printk("\n"); - } -#endif + DDUMP("fpr_final =", &fpr_final, len); /* * XXX fixme * @@ -1215,66 +1130,51 @@ * use the storage from the saved context i.e., the actual final * destination (pt_regs, switch_stack or thread structure). */ - setfpreg(ld->r1, &fpr_final, regs); + setfpreg(ld.r1, &fpr_final, regs); } /* * check for updates on any loads */ - if (ld->op == 0x7 || ld->m) - emulate_load_updates(ld->op == 0x7 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa); + if (ld.op == 0x7 || ld.m) + emulate_load_updates(ld.op == 0x7 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa); /* * invalidate ALAT entry in case of advanced floating point loads */ - if (ld->x6_op == 0x2) - invala_fr(ld->r1); + if (ld.x6_op == 0x2) + invala_fr(ld.r1); return 0; } static int -emulate_store_float(unsigned long ifa, load_store_t *ld, struct pt_regs *regs) +emulate_store_float (unsigned long ifa, load_store_t ld, struct pt_regs *regs) { struct ia64_fpreg fpr_init; struct ia64_fpreg fpr_final; - unsigned long len = float_fsz[ld->x6_sz]; - - /* - * the macro supposes sequential access (which is the case) - * if the first byte is an invalid address we return here. Otherwise - * there is a guard page at the top of the user's address page and - * the first access would generate a NaT consumption fault and return - * with a SIGSEGV, which is what we want. - * - * Note: the first argument is ignored - */ - if (access_ok(VERIFY_WRITE, (void *)ifa, len) < 0) { - DPRINT(("verify area failed on %lx\n",ifa)); - return -1; - } + unsigned long len = float_fsz[ld.x6_sz]; - /* + /* * make sure we get clean buffers */ memset(&fpr_init,0, sizeof(fpr_init)); memset(&fpr_final,0, sizeof(fpr_final)); - /* * if we get to this handler, Nat bits on both r3 and r2 have already * been checked. so we don't need to do it * * extract the value to be stored */ - getfpreg(ld->imm, &fpr_init, regs); + getfpreg(ld.imm, &fpr_init, regs); /* * during this step, we extract the spilled registers from the saved * context i.e., we refill. Then we store (no spill) to temporary * aligned location */ - switch( ld->x6_sz ) { + switch( ld.x6_sz ) { case 0: float2mem_extended(&fpr_init, &fpr_final); break; @@ -1288,56 +1188,40 @@ float2mem_double(&fpr_init, &fpr_final); break; } - DPRINT(("ld.r1=%d x6_sz=%d\n", ld->r1, ld->x6_sz)); -#ifdef DEBUG_UNALIGNED_TRAP - { int i; char *c = (char *)&fpr_init; - printk("fpr_init= "); - for(i=0; i < len; i++ ) { - printk("%02x ", c[i]&0xff); - } - printk("\n"); - } - { int i; char *c = (char *)&fpr_final; - printk("fpr_final= "); - for(i=0; i < len; i++ ) { - printk("%02x ", c[i]&0xff); - } - printk("\n"); - } -#endif + DPRINT("ld.r1=%d x6_sz=%d\n", ld.r1, ld.x6_sz); + DDUMP("fpr_init =", &fpr_init, len); + DDUMP("fpr_final =", &fpr_final, len); - /* - * does the unaligned store - */ - memcpy((void *)ifa, &fpr_final, len); + if (copy_to_user((void *) ifa, &fpr_final, len)) + return -1; /* * stfX [r3]=r2,imm(9) * * NOTE: - * ld->r3 can never be r0, because r0 would not generate an + * ld.r3 can never be r0, because r0 would not generate an * unaligned access. */ - if (ld->op == 0x7) { + if (ld.op == 0x7) { unsigned long imm; /* * form imm9: [12:6] contain first 7bits */ - imm = ld->x << 7 | ld->r1; + imm = ld.x << 7 | ld.r1; /* * sign extend (8bits) if m set */ - if (ld->m) - imm |= SIGN_EXT9; + if (ld.m) + imm |= SIGN_EXT9; /* * ifa == r3 (NaT is necessarily cleared) */ ifa += imm; - DPRINT(("imm=%lx r3=%lx\n", imm, ifa)); - - setreg(ld->r3, ifa, 0, regs); + DPRINT("imm=%lx r3=%lx\n", imm, ifa); + + setreg(ld.r3, ifa, 0, regs); } /* * we don't have alat_invalidate_multiple() so we need @@ -1348,132 +1232,106 @@ return 0; } -void -ia64_handle_unaligned(unsigned long ifa, struct pt_regs *regs) +/* + * Make sure we log the unaligned access, so that user/sysadmin can notice it and + * eventually fix the program. However, we don't want to do that for every access so we + * pace it with jiffies. This isn't really MP-safe, but it doesn't really have to be + * either... + */ +static int +within_logging_rate_limit (void) { - static unsigned long unalign_count; - static long last_time; + static unsigned long count, last_time; + if (jiffies - last_time > 5*HZ) + count = 0; + if (++count < 5) { + last_time = jiffies; + return 1; + } + return 0; + +} + +void +ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs) +{ + struct exception_fixup fix = { 0 }; struct ia64_psr *ipsr = ia64_psr(regs); - unsigned long *bundle_addr; + mm_segment_t old_fs = get_fs(); + unsigned long bundle[2]; unsigned long opcode; - unsigned long op; - load_store_t *insn; + struct siginfo si; + union { + unsigned long l; + load_store_t insn; + } u; int ret = -1; + if (ia64_psr(regs)->be) { + /* we don't support big-endian accesses */ + die_if_kernel("big-endian unaligned accesses are not supported", regs, 0); + goto force_sigbus; + } + /* - * Unaligned references in the kernel could come from unaligned - * arguments to system calls. We fault the user process in - * these cases and panic the kernel otherwise (the kernel should - * be fixed to not make unaligned accesses). + * Treat kernel accesses for which there is an exception handler entry the same as + * user-level unaligned accesses. Otherwise, a clever program could trick this + * handler into reading an arbitrary kernel addresses... */ if (!user_mode(regs)) { - const struct exception_table_entry *fix; - +#ifdef GAS_HAS_LOCAL_TAGS + fix = search_exception_table(regs->cr_iip + ia64_psr(regs)->ri); +#else fix = search_exception_table(regs->cr_iip); - if (fix) { - regs->r8 = -EFAULT; - if (fix->skip & 1) { - regs->r9 = 0; - } - regs->cr_iip += ((long) fix->skip) & ~15; - regs->cr_ipsr &= ~IA64_PSR_RI; /* clear exception slot number */ - return; - } - die_if_kernel("Unaligned reference while in kernel\n", regs, 30); - /* NOT_REACHED */ - } - /* - * For now, we don't support user processes running big-endian - * which do unaligned accesses - */ - if (ia64_psr(regs)->be) { - struct siginfo si; - - printk(KERN_ERR "%s(%d): big-endian unaligned access %016lx (ip=%016lx) not " - "yet supported\n", - current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri); - - si.si_signo = SIGBUS; - si.si_errno = 0; - si.si_code = BUS_ADRALN; - si.si_addr = (void *) ifa; - force_sig_info(SIGBUS, &si, current); - return; - } - - if (current->thread.flags & IA64_THREAD_UAC_SIGBUS) { - struct siginfo si; - - si.si_signo = SIGBUS; - si.si_errno = 0; - si.si_code = BUS_ADRALN; - si.si_addr = (void *) ifa; - force_sig_info(SIGBUS, &si, current); - return; +#endif } - - if (!(current->thread.flags & IA64_THREAD_UAC_NOPRINT)) { - /* - * Make sure we log the unaligned access, so that - * user/sysadmin can notice it and eventually fix the - * program. - * - * We don't want to do that for every access so we - * pace it with jiffies. - */ - if (unalign_count > 5 && jiffies - last_time > 5*HZ) - unalign_count = 0; - if (++unalign_count < 5) { + if (user_mode(regs) || fix.cont) { + if ((current->thread.flags & IA64_THREAD_UAC_SIGBUS) != 0) + goto force_sigbus; + + if (!(current->thread.flags & IA64_THREAD_UAC_NOPRINT) + && within_logging_rate_limit()) + { char buf[200]; /* comm[] is at most 16 bytes... */ size_t len; - last_time = jiffies; - len = sprintf(buf, "%s(%d): unaligned access to 0x%016lx, ip=0x%016lx\n\r", - current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri); + len = sprintf(buf, "%s(%d): unaligned access to 0x%016lx, " + "ip=0x%016lx\n\r", current->comm, current->pid, + ifa, regs->cr_iip + ipsr->ri); tty_write_message(current->tty, buf); buf[len-1] = '\0'; /* drop '\r' */ - printk("%s", buf); /* guard against command names containing %s!! */ + printk(KERN_WARNING "%s", buf); /* watch for command names containing %s */ } + } else { + if (within_logging_rate_limit()) + printk(KERN_WARNING "kernel unaligned access to 0x%016lx, ip=0x%016lx\n", + ifa, regs->cr_iip + ipsr->ri); + set_fs(KERNEL_DS); } - DPRINT(("iip=%lx ifa=%lx isr=%lx\n", regs->cr_iip, ifa, regs->cr_ipsr)); - DPRINT(("ISR.ei=%d ISR.sp=%d\n", ipsr->ri, ipsr->it)); + DPRINT("iip=%lx ifa=%lx isr=%lx (ei=%d, sp=%d)\n", + regs->cr_iip, ifa, regs->cr_ipsr, ipsr->ri, ipsr->it); - bundle_addr = (unsigned long *)(regs->cr_iip); + if (__copy_from_user(bundle, (void *) regs->cr_iip, 16)) + goto failure; /* * extract the instruction from the bundle given the slot number */ - switch ( ipsr->ri ) { - case 0: op = *bundle_addr >> 5; - break; - - case 1: op = *bundle_addr >> 46 | (*(bundle_addr+1) & 0x7fffff)<<18; - break; - - case 2: op = *(bundle_addr+1) >> 23; - break; + switch (ipsr->ri) { + case 0: u.l = (bundle[0] >> 5); break; + case 1: u.l = (bundle[0] >> 46) | (bundle[1] << 18); break; + case 2: u.l = (bundle[1] >> 23); break; } + opcode = (u.l >> IA64_OPCODE_SHIFT) & IA64_OPCODE_MASK; - insn = (load_store_t *)&op; - opcode = op & IA64_OPCODE_MASK; - - DPRINT(("opcode=%lx ld.qp=%d ld.r1=%d ld.imm=%d ld.r3=%d ld.x=%d ld.hint=%d " - "ld.x6=0x%x ld.m=%d ld.op=%d\n", - opcode, - insn->qp, - insn->r1, - insn->imm, - insn->r3, - insn->x, - insn->hint, - insn->x6_sz, - insn->m, - insn->op)); + DPRINT("opcode=%lx ld.qp=%d ld.r1=%d ld.imm=%d ld.r3=%d ld.x=%d ld.hint=%d " + "ld.x6=0x%x ld.m=%d ld.op=%d\n", opcode, u.insn.qp, u.insn.r1, u.insn.imm, + u.insn.r3, u.insn.x, u.insn.hint, u.insn.x6_sz, u.insn.m, u.insn.op); /* - * IMPORTANT: + * IMPORTANT: * Notice that the swictch statement DOES not cover all possible instructions * that DO generate unaligned references. This is made on purpose because for some * instructions it DOES NOT make sense to try and emulate the access. Sometimes it @@ -1483,104 +1341,124 @@ * load/store: * - ldX.spill * - stX.spill - * Reason: RNATs are based on addresses + * Reason: RNATs are based on addresses * * synchronization: * - cmpxchg * - fetchadd * - xchg - * Reason: ATOMIC operations cannot be emulated properly using multiple - * instructions. + * Reason: ATOMIC operations cannot be emulated properly using multiple + * instructions. * * speculative loads: * - ldX.sZ - * Reason: side effects, code must be ready to deal with failure so simpler - * to let the load fail. + * Reason: side effects, code must be ready to deal with failure so simpler + * to let the load fail. * --------------------------------------------------------------------------------- * XXX fixme * * I would like to get rid of this switch case and do something * more elegant. */ - switch(opcode) { - case LDS_OP: - case LDSA_OP: - case LDS_IMM_OP: - case LDSA_IMM_OP: - case LDFS_OP: - case LDFSA_OP: - case LDFS_IMM_OP: - /* - * The instruction will be retried with defered exceptions - * turned on, and we should get Nat bit installed - * - * IMPORTANT: - * When PSR_ED is set, the register & immediate update - * forms are actually executed even though the operation - * failed. So we don't need to take care of this. - */ - DPRINT(("forcing PSR_ED\n")); - regs->cr_ipsr |= IA64_PSR_ED; - return; - - case LD_OP: - case LDA_OP: - case LDBIAS_OP: - case LDACQ_OP: - case LDCCLR_OP: - case LDCNC_OP: - case LDCCLRACQ_OP: - case LD_IMM_OP: - case LDA_IMM_OP: - case LDBIAS_IMM_OP: - case LDACQ_IMM_OP: - case LDCCLR_IMM_OP: - case LDCNC_IMM_OP: - case LDCCLRACQ_IMM_OP: - ret = emulate_load_int(ifa, insn, regs); - break; - case ST_OP: - case STREL_OP: - case ST_IMM_OP: - case STREL_IMM_OP: - ret = emulate_store_int(ifa, insn, regs); - break; - case LDF_OP: - case LDFA_OP: - case LDFCCLR_OP: - case LDFCNC_OP: - case LDF_IMM_OP: - case LDFA_IMM_OP: - case LDFCCLR_IMM_OP: - case LDFCNC_IMM_OP: - ret = insn->x ? - emulate_load_floatpair(ifa, insn, regs): - emulate_load_float(ifa, insn, regs); - break; - case STF_OP: - case STF_IMM_OP: - ret = emulate_store_float(ifa, insn, regs); - } - - DPRINT(("ret=%d\n", ret)); - if (ret) { - struct siginfo si; - - si.si_signo = SIGBUS; - si.si_errno = 0; - si.si_code = BUS_ADRALN; - si.si_addr = (void *) ifa; - force_sig_info(SIGBUS, &si, current); - } else { + switch (opcode) { + case LDS_OP: + case LDSA_OP: + case LDS_IMM_OP: + case LDSA_IMM_OP: + case LDFS_OP: + case LDFSA_OP: + case LDFS_IMM_OP: /* - * given today's architecture this case is not likely to happen - * because a memory access instruction (M) can never be in the - * last slot of a bundle. But let's keep it for now. - */ - if (ipsr->ri == 2) - regs->cr_iip += 16; - ipsr->ri = ++ipsr->ri & 3; - } + * The instruction will be retried with deferred exceptions turned on, and + * we should get Nat bit installed + * + * IMPORTANT: When PSR_ED is set, the register & immediate update forms + * are actually executed even though the operation failed. So we don't + * need to take care of this. + */ + DPRINT("forcing PSR_ED\n"); + regs->cr_ipsr |= IA64_PSR_ED; + goto done; + + case LD_OP: + case LDA_OP: + case LDBIAS_OP: + case LDACQ_OP: + case LDCCLR_OP: + case LDCNC_OP: + case LDCCLRACQ_OP: + case LD_IMM_OP: + case LDA_IMM_OP: + case LDBIAS_IMM_OP: + case LDACQ_IMM_OP: + case LDCCLR_IMM_OP: + case LDCNC_IMM_OP: + case LDCCLRACQ_IMM_OP: + ret = emulate_load_int(ifa, u.insn, regs); + break; + + case ST_OP: + case STREL_OP: + case ST_IMM_OP: + case STREL_IMM_OP: + ret = emulate_store_int(ifa, u.insn, regs); + break; + + case LDF_OP: + case LDFA_OP: + case LDFCCLR_OP: + case LDFCNC_OP: + case LDF_IMM_OP: + case LDFA_IMM_OP: + case LDFCCLR_IMM_OP: + case LDFCNC_IMM_OP: + if (u.insn.x) + ret = emulate_load_floatpair(ifa, u.insn, regs); + else + ret = emulate_load_float(ifa, u.insn, regs); + break; + + case STF_OP: + case STF_IMM_OP: + ret = emulate_store_float(ifa, u.insn, regs); + break; + + default: + goto failure; + } + DPRINT("ret=%d\n", ret); + if (ret) + goto failure; + + if (ipsr->ri == 2) + /* + * given today's architecture this case is not likely to happen because a + * memory access instruction (M) can never be in the last slot of a + * bundle. But let's keep it for now. + */ + regs->cr_iip += 16; + ipsr->ri = (ipsr->ri + 1) & 0x3; + + DPRINT("ipsr->ri=%d iip=%lx\n", ipsr->ri, regs->cr_iip); + done: + set_fs(old_fs); /* restore original address limit */ + return; - DPRINT(("ipsr->ri=%d iip=%lx\n", ipsr->ri, regs->cr_iip)); + failure: + /* something went wrong... */ + if (!user_mode(regs)) { + if (fix.cont) { + handle_exception(regs, fix); + goto done; + } + die_if_kernel("error during unaligned kernel access\n", regs, ret); + /* NOT_REACHED */ + } + force_sigbus: + si.si_signo = SIGBUS; + si.si_errno = 0; + si.si_code = BUS_ADRALN; + si.si_addr = (void *) ifa; + force_sig_info(SIGBUS, &si, current); + goto done; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/unwind.c linux.ac/arch/ia64/kernel/unwind.c --- linux.vanilla/arch/ia64/kernel/unwind.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/ia64/kernel/unwind.c Sat Apr 14 01:18:00 2001 @@ -1,6 +1,6 @@ /* - * Copyright (C) 1999-2000 Hewlett-Packard Co - * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ /* * This file implements call frame unwind support for the Linux @@ -24,15 +24,12 @@ * o if both the unw.lock spinlock and a script's read-write lock must be * acquired, then the read-write lock must be acquired first. */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/slab.h> #include <asm/unwind.h> -#ifdef CONFIG_IA64_NEW_UNWIND - #include <asm/delay.h> #include <asm/page.h> #include <asm/ptrace.h> @@ -306,7 +303,7 @@ } } else { /* access a stacked register */ - addr = ia64_rse_skip_regs((unsigned long *) info->bsp, regnum); + addr = ia64_rse_skip_regs((unsigned long *) info->bsp, regnum - 32); nat_addr = ia64_rse_rnat_addr(addr); if ((unsigned long) addr < info->regstk.limit || (unsigned long) addr >= info->regstk.top) @@ -660,7 +657,7 @@ */ if (sr->any_spills) { off = sr->spill_offset; - alloc_spill_area(&off, 16, sr->curr.reg + UNW_REG_F2, sr->curr.reg + UNW_REG_F31); + alloc_spill_area(&off, 16, sr->curr.reg + UNW_REG_F2, sr->curr.reg + UNW_REG_F31); alloc_spill_area(&off, 8, sr->curr.reg + UNW_REG_B1, sr->curr.reg + UNW_REG_B5); alloc_spill_area(&off, 8, sr->curr.reg + UNW_REG_R4, sr->curr.reg + UNW_REG_R7); } @@ -911,6 +908,10 @@ struct unw_reg_state *rs; rs = alloc_reg_state(); + if (!rs) { + printk("unwind: cannot stack!\n"); + return; + } memcpy(rs, &sr->curr, sizeof(*rs)); rs->label = label; rs->next = sr->reg_state_list; @@ -927,7 +928,7 @@ if (sr->when_target <= sr->region_start + MIN((int)t, sr->region_len - 1)) return 0; if (qp > 0) { - if ((sr->pr_val & (1UL << qp)) == 0) + if ((sr->pr_val & (1UL << qp)) == 0) return 0; sr->pr_mask |= (1UL << qp); } @@ -944,7 +945,7 @@ r = sr->curr.reg + decode_abreg(abreg, 0); r->where = UNW_WHERE_NONE; - r->when = sr->region_start + MIN((int)t, sr->region_len - 1); + r->when = UNW_WHEN_NEVER; r->val = 0; } @@ -1443,12 +1444,17 @@ * sp has been restored and all values on the memory stack below * psp also have been restored. */ - sr.curr.reg[UNW_REG_PSP].where = UNW_WHERE_NONE; sr.curr.reg[UNW_REG_PSP].val = 0; + sr.curr.reg[UNW_REG_PSP].where = UNW_WHERE_NONE; + sr.curr.reg[UNW_REG_PSP].when = UNW_WHEN_NEVER; for (r = sr.curr.reg; r < sr.curr.reg + UNW_NUM_REGS; ++r) if ((r->where == UNW_WHERE_PSPREL && r->val <= 0x10) || r->where == UNW_WHERE_SPREL) + { + r->val = 0; r->where = UNW_WHERE_NONE; + r->when = UNW_WHEN_NEVER; + } } script->flags = sr.flags; @@ -1477,7 +1483,7 @@ case UNW_WHERE_PSPREL: printk("[psp+0x%lx]", r->val); break; case UNW_WHERE_NONE: printk("%s+0x%lx", unw.preg_name[r - sr.curr.reg], r->val); - break; + break; default: printk("BADWHERE(%d)", r->where); break; } printk("\t\t%d\n", r->when); @@ -1604,7 +1610,9 @@ case UNW_INSN_LOAD: #if UNW_DEBUG - if ((s[val] & (my_cpu_data.unimpl_va_mask | 0x7)) || s[val] < TASK_SIZE) { + if ((s[val] & (local_cpu_data->unimpl_va_mask | 0x7)) != 0 + || s[val] < TASK_SIZE) + { debug(1, "unwind: rejecting bad psp=0x%lx\n", s[val]); break; } @@ -1636,7 +1644,7 @@ int have_write_lock = 0; struct unw_script *scr; - if ((info->ip & (my_cpu_data.unimpl_va_mask | 0xf)) || info->ip < TASK_SIZE) { + if ((info->ip & (local_cpu_data->unimpl_va_mask | 0xf)) || info->ip < TASK_SIZE) { /* don't let obviously bad addresses pollute the cache */ debug(1, "unwind: rejecting bad ip=0x%lx\n", info->ip); info->rp_loc = 0; @@ -1672,7 +1680,7 @@ unsigned long ip, pr, num_regs; STAT(unsigned long start, flags;) int retval; - + STAT(local_irq_save(flags); ++unw.stat.api.unwinds; start = ia64_get_itc()); prev_ip = info->ip; @@ -1818,140 +1826,14 @@ STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags)); } -#endif /* CONFIG_IA64_NEW_UNWIND */ - void unw_init_from_blocked_task (struct unw_frame_info *info, struct task_struct *t) { struct switch_stack *sw = (struct switch_stack *) (t->thread.ksp + 16); -#ifdef CONFIG_IA64_NEW_UNWIND unw_init_frame_info(info, t, sw); -#else - unsigned long sol, limit, top; - - memset(info, 0, sizeof(*info)); - - sol = (sw->ar_pfs >> 7) & 0x7f; /* size of locals */ - - limit = (unsigned long) t + IA64_RBS_OFFSET; - top = sw->ar_bspstore; - if (top - (unsigned long) t >= IA64_STK_OFFSET) - top = limit; - - info->regstk.limit = limit; - info->regstk.top = top; - info->sw = sw; - info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sol); - info->cfm_loc = &sw->ar_pfs; - info->ip = sw->b0; -#endif } -void -unw_init_from_current (struct unw_frame_info *info, struct pt_regs *regs) -{ -#ifdef CONFIG_IA64_NEW_UNWIND - struct switch_stack *sw = (struct switch_stack *) regs - 1; - - unw_init_frame_info(info, current, sw); - /* skip over interrupt frame: */ - unw_unwind(info); -#else - struct switch_stack *sw = (struct switch_stack *) regs - 1; - unsigned long sol, sof, *bsp, limit, top; - - limit = (unsigned long) current + IA64_RBS_OFFSET; - top = sw->ar_bspstore; - if (top - (unsigned long) current >= IA64_STK_OFFSET) - top = limit; - - memset(info, 0, sizeof(*info)); - - sol = (sw->ar_pfs >> 7) & 0x7f; /* size of frame */ - - /* this gives us the bsp top level frame (kdb interrupt frame): */ - bsp = ia64_rse_skip_regs((unsigned long *) top, -sol); - - /* now skip past the interrupt frame: */ - sof = regs->cr_ifs & 0x7f; /* size of frame */ - - info->regstk.limit = limit; - info->regstk.top = top; - info->sw = sw; - info->bsp = (unsigned long) ia64_rse_skip_regs(bsp, -sof); - info->cfm_loc = ®s->cr_ifs; - info->ip = regs->cr_iip; -#endif -} - -#ifndef CONFIG_IA64_NEW_UNWIND - -static unsigned long -read_reg (struct unw_frame_info *info, int regnum, int *is_nat) -{ - unsigned long *addr, *rnat_addr, rnat; - - addr = ia64_rse_skip_regs((unsigned long *) info->bsp, regnum); - if ((unsigned long) addr < info->regstk.limit - || (unsigned long) addr >= info->regstk.top || ((long) addr & 0x7) != 0) - { - *is_nat = 1; - return 0xdeadbeefdeadbeef; - } - rnat_addr = ia64_rse_rnat_addr(addr); - - if ((unsigned long) rnat_addr >= info->regstk.top) - rnat = info->sw->ar_rnat; - else - rnat = *rnat_addr; - *is_nat = (rnat & (1UL << ia64_rse_slot_num(addr))) != 0; - return *addr; -} - -/* - * On entry, info->regstk.top should point to the register backing - * store for r32. - */ -int -unw_unwind (struct unw_frame_info *info) -{ - unsigned long sol, cfm = *info->cfm_loc; - int is_nat; - - sol = (cfm >> 7) & 0x7f; /* size of locals */ - - /* - * In general, we would have to make use of unwind info to - * unwind an IA-64 stack, but for now gcc uses a special - * convention that makes this possible without full-fledged - * unwindo info. Specifically, we expect "rp" in the second - * last, and "ar.pfs" in the last local register, so the - * number of locals in a frame must be at least two. If it's - * less than that, we reached the end of the C call stack. - */ - if (sol < 2) - return -1; - - info->ip = read_reg(info, sol - 2, &is_nat); - if (is_nat || (info->ip & (my_cpu_data.unimpl_va_mask | 0xf))) - /* reject let obviously bad addresses */ - return -1; - - info->cfm_loc = ia64_rse_skip_regs((unsigned long *) info->bsp, sol - 1); - cfm = read_reg(info, sol - 1, &is_nat); - if (is_nat) - return -1; - - sol = (cfm >> 7) & 0x7f; - - info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->bsp, -sol); - return 0; -} -#endif /* !CONFIG_IA64_NEW_UNWIND */ - -#ifdef CONFIG_IA64_NEW_UNWIND - static void init_unwind_table (struct unw_table *table, const char *name, unsigned long segment_base, unsigned long gp, void *table_start, void *table_end) @@ -1979,7 +1861,7 @@ dprintk("unwind: ignoring attempt to insert empty unwind table\n"); return 0; } - + table = kmalloc(sizeof(*table), GFP_USER); if (!table) return 0; @@ -2052,12 +1934,10 @@ kfree(table); } -#endif /* CONFIG_IA64_NEW_UNWIND */ void unw_init (void) { -#ifdef CONFIG_IA64_NEW_UNWIND extern int ia64_unw_start, ia64_unw_end, __gp; extern void unw_hash_index_t_is_too_narrow (void); long i, off; @@ -2093,5 +1973,4 @@ init_unwind_table(&unw.kernel_table, "kernel", KERNEL_START, (unsigned long) &__gp, &ia64_unw_start, &ia64_unw_end); -#endif /* CONFIG_IA64_NEW_UNWIND */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/Makefile linux.ac/arch/ia64/lib/Makefile --- linux.vanilla/arch/ia64/lib/Makefile Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/lib/Makefile Tue Apr 10 18:08:40 2001 @@ -7,18 +7,18 @@ L_TARGET = lib.a +export-objs := io.o swiotlb.o + obj-y := __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o \ checksum.o clear_page.o csum_partial_copy.o copy_page.o \ copy_user.o clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o \ - flush.o do_csum.o \ + flush.o io.o do_csum.o \ swiotlb.o ifneq ($(CONFIG_ITANIUM_ASTEP_SPECIFIC),y) obj-y += memcpy.o memset.o strlen.o endif - -export-objs += io.o IGNORE_FLAGS_OBJS = __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/clear_page.S linux.ac/arch/ia64/lib/clear_page.S --- linux.vanilla/arch/ia64/lib/clear_page.S Thu Jun 22 15:09:44 2000 +++ linux.ac/arch/ia64/lib/clear_page.S Tue Apr 10 18:09:55 2001 @@ -6,29 +6,24 @@ * * Inputs: * in0: address of page - * + * * Output: * none * - * Copyright (C) 1999-2000 Hewlett-Packard Co + * Copyright (C) 1999-2001 Hewlett-Packard Co * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com> - * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <asm/asmmacro.h> #include <asm/page.h> - .text - .psr abi64 - .psr lsb - .lsb - GLOBAL_ENTRY(clear_page) - UNW(.prologue) + .prologue alloc r11=ar.pfs,1,0,0,0 - UNW(.save ar.lc, r16) + .save ar.lc, r16 mov r16=ar.lc // slow - UNW(.body) + .body mov r17=PAGE_SIZE/32-1 // -1 = repeat/until ;; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/clear_user.S linux.ac/arch/ia64/lib/clear_user.S --- linux.vanilla/arch/ia64/lib/clear_user.S Thu Jun 22 15:09:44 2000 +++ linux.ac/arch/ia64/lib/clear_user.S Tue Apr 10 18:09:55 2001 @@ -6,8 +6,8 @@ * in1: length of buffer in bytes * Outputs: * r8: number of bytes that didn't get cleared due to a fault - * - * Copyright (C) 1998, 1999 Hewlett-Packard Co + * + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com> */ @@ -51,27 +51,12 @@ // have side effects (same thing for writing). // -// The label comes first because our store instruction contains a comma -// and confuse the preprocessor otherwise -// -#define EX(y,x...) \ - .section __ex_table,"a"; \ - data4 @gprel(99f); \ - data4 y-99f; \ - .previous; \ -99: x - - .text - .psr abi64 - .psr lsb - .lsb - GLOBAL_ENTRY(__do_clear_user) - UNW(.prologue) - UNW(.save ar.pfs, saved_pfs) - alloc saved_pfs=ar.pfs,2,0,0,0 + .prologue + .save ar.pfs, saved_pfs + alloc saved_pfs=ar.pfs,2,0,0,0 cmp.eq p6,p0=r0,len // check for zero length - UNW(.save ar.lc, saved_lc) + .save ar.lc, saved_lc mov saved_lc=ar.lc // preserve ar.lc (slow) .body ;; // avoid WAW on CFM @@ -80,7 +65,7 @@ (p6) br.ret.spnt.few rp ;; cmp.lt p6,p0=16,len // if len > 16 then long memset - mov ar.lc=tmp // initialize lc for small count + mov ar.lc=tmp // initialize lc for small count (p6) br.cond.dptk.few long_do_clear ;; // WAR on ar.lc // @@ -91,7 +76,7 @@ // the various counters compared to how long the loop is supposed // to last on average does not make this solution viable. // -1: +1: EX( .Lexit1, st1 [buf]=r0,1 ) adds len=-1,len // countdown length using len br.cloop.dptk.few 1b @@ -99,7 +84,7 @@ // // .Lexit4: comes from byte by byte loop // len contains bytes left -.Lexit1: +.Lexit1: mov ret0=len // faster than using ar.lc mov ar.lc=saved_lc br.ret.sptk.few rp // end of short clear_user @@ -110,7 +95,7 @@ // so we focus on alignment (no branches required) // // The use of len/len2 for countdown of the number of bytes left - // instead of ret0 is due to the fact that the exception code + // instead of ret0 is due to the fact that the exception code // changes the values of r8. // long_do_clear: @@ -131,10 +116,10 @@ EX( .Lexit3, (p6) st8 [buf]=r0,8 ) // 8-byte aligned (p6) adds len=-8,len;; shr.u cnt=len,4 // number of 128-bit (2x64bit) words - ;; + ;; cmp.eq p6,p0=r0,cnt adds tmp=-1,cnt -(p6) br.cond.dpnt.few .dotail // we have less than 16 bytes left +(p6) br.cond.dpnt.few .dotail // we have less than 16 bytes left ;; adds buf2=8,buf // setup second base pointer mov ar.lc=tmp @@ -143,32 +128,30 @@ // // 16bytes/iteration core loop // - // The second store can never generate a fault because + // The second store can never generate a fault because // we come into the loop only when we are 16-byte aligned. // This means that if we cross a page then it will always be // in the first store and never in the second. // - // + // // We need to keep track of the remaining length. A possible (optimistic) - // way would be to ue ar.lc and derive how many byte were left by + // way would be to use ar.lc and derive how many byte were left by // doing : left= 16*ar.lc + 16. this would avoid the addition at - // every iteration. + // every iteration. // However we need to keep the synchronization point. A template // M;;MB does not exist and thus we can keep the addition at no // extra cycle cost (use a nop slot anyway). It also simplifies the // (unlikely) error recovery code // -2: - - EX(.Lexit3, st8 [buf]=r0,16 ) +2: EX(.Lexit3, st8 [buf]=r0,16 ) ;; // needed to get len correct when error st8 [buf2]=r0,16 - adds len=-16,len + adds len=-16,len br.cloop.dptk.few 2b ;; mov ar.lc=saved_lc - // + // // tail correction based on len only // // We alternate the use of len3,len2 to allow parallelism and correct @@ -176,14 +159,14 @@ // The addition of len2/len3 does not cost anything more compared to // the regular memset as we had empty slots. // -.dotail: +.dotail: mov len2=len // for parallelization of error handling mov len3=len - tbit.nz p6,p0=len,3 + tbit.nz p6,p0=len,3 ;; EX( .Lexit2, (p6) st8 [buf]=r0,8 ) // at least 8 bytes (p6) adds len3=-8,len2 - tbit.nz p7,p6=len,2 + tbit.nz p7,p6=len,2 ;; EX( .Lexit2, (p7) st4 [buf]=r0,4 ) // at least 4 bytes (p7) adds len2=-4,len3 @@ -207,8 +190,8 @@ // // // .Lexit2: - // if p6 -> coming from st8 or st2 : len2 contains what's left - // if p7 -> coming from st4 or st1 : len3 contains what's left + // if p6 -> coming from st8 or st2 : len2 contains what's left + // if p7 -> coming from st4 or st1 : len3 contains what's left // We must restore lc/pr even though might not have been used. .Lexit2: .pred.rel "mutex", p6, p7 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/copy_page.S linux.ac/arch/ia64/lib/copy_page.S --- linux.vanilla/arch/ia64/lib/copy_page.S Thu Jun 22 15:09:44 2000 +++ linux.ac/arch/ia64/lib/copy_page.S Tue Apr 10 18:09:55 2001 @@ -3,14 +3,14 @@ * Optimized version of the standard copy_page() function * * Based on comments from ddd. Try not to overflow write buffer. - * + * * Inputs: - * in0: address of target page + * in0: address of target page * in1: address of source page * Output: - * no return value + * no return value * - * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999, 2001 Hewlett-Packard Co * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com> */ #include <asm/asmmacro.h> @@ -28,28 +28,23 @@ #define tgt1 r22 #define tgt2 r23 - .text - .psr abi64 - .psr lsb - .lsb - GLOBAL_ENTRY(copy_page) - UNW(.prologue) - UNW(.save ar.pfs, saved_pfs) + .prologue + .save ar.pfs, saved_pfs alloc saved_pfs=ar.pfs,3,((2*PIPE_DEPTH+7)&~7),0,((2*PIPE_DEPTH+7)&~7) .rotr t1[PIPE_DEPTH], t2[PIPE_DEPTH] .rotp p[PIPE_DEPTH] - UNW(.save ar.lc, saved_lc) + .save ar.lc, saved_lc mov saved_lc=ar.lc // save ar.lc ahead of time - UNW(.save pr, saved_pr) + .save pr, saved_pr mov saved_pr=pr // rotating predicates are preserved // resgisters we must save. - UNW(.body) + .body - mov src1=in1 // initialize 1st stream source - adds src2=8,in1 // initialize 2nd stream source + mov src1=in1 // initialize 1st stream source + adds src2=8,in1 // initialize 2nd stream source mov lcount=PAGE_SIZE/16-1 // as many 16bytes as there are on a page // -1 is because br.ctop is repeat/until @@ -72,7 +67,7 @@ // // The initialization of the prolog is done via the predicate registers: // the choice of EPI DEPENDS on the depth of the pipeline (n). - // When lc > 0 pr63=1 and it is fed back into pr16 and pr16-pr62 + // When lc > 0 pr63=1 and it is fed back into pr16 and pr16-pr62 // are then shifted right at every iteration, // Thus by initializing pr16=1 and the rest to 0 before the loop // we get EPI=1 after n iterations. @@ -87,7 +82,7 @@ // stores but no loads anymore ;; mov pr=saved_pr,0xffffffffffff0000 // restore predicates - mov ar.pfs=saved_pfs // restore ar.ec + mov ar.pfs=saved_pfs // restore ar.ec mov ar.lc=saved_lc // restore saved lc br.ret.sptk.few rp // bye... END(copy_page) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/copy_user.S linux.ac/arch/ia64/lib/copy_user.S --- linux.vanilla/arch/ia64/lib/copy_user.S Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/ia64/lib/copy_user.S Tue Apr 10 18:09:55 2001 @@ -12,41 +12,25 @@ * * Inputs: * in0 address of source buffer - * in1 address of destination buffer + * in1 address of destination buffer * in2 number of bytes to copy * - * Outputs: - * ret0 0 in case of success. The number of bytes NOT copied in - * case of error. + * Outputs: + * ret0 0 in case of success. The number of bytes NOT copied in + * case of error. * * Copyright (C) 2000 Hewlett-Packard Co * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com> * * Fixme: * - handle the case where we have more than 16 bytes and the alignment - * are different. + * are different. * - more benchmarking - * - fix extraneous stop bit introduced by the EX() macro. + * - fix extraneous stop bit introduced by the EX() macro. */ #include <asm/asmmacro.h> -// The label comes first because our store instruction contains a comma -// and confuse the preprocessor otherwise -// -#undef DEBUG -#ifdef DEBUG -#define EX(y,x...) \ -99: x -#else -#define EX(y,x...) \ - .section __ex_table,"a"; \ - data4 @gprel(99f); \ - data4 y-99f; \ - .previous; \ -99: x -#endif - // // Tuneable parameters // @@ -85,13 +69,10 @@ #define enddst r29 #define endsrc r30 #define saved_pfs r31 - .text - .psr abi64 - .psr lsb GLOBAL_ENTRY(__copy_user) - UNW(.prologue) - UNW(.save ar.pfs, saved_pfs) + .prologue + .save ar.pfs, saved_pfs alloc saved_pfs=ar.pfs,3,((2*PIPE_DEPTH+7)&~7),0,((2*PIPE_DEPTH+7)&~7) .rotr val1[PIPE_DEPTH],val2[PIPE_DEPTH] @@ -102,16 +83,16 @@ ;; // RAW of cfm when len=0 cmp.eq p8,p0=r0,len // check for zero length - UNW(.save ar.lc, saved_lc) + .save ar.lc, saved_lc mov saved_lc=ar.lc // preserve ar.lc (slow) (p8) br.ret.spnt.few rp // empty mempcy() ;; add enddst=dst,len // first byte after end of source add endsrc=src,len // first byte after end of destination - UNW(.save pr, saved_pr) + .save pr, saved_pr mov saved_pr=pr // preserve predicates - UNW(.body) + .body mov dst1=dst // copy because of rotation mov ar.ec=PIPE_DEPTH @@ -119,7 +100,7 @@ mov src1=src // copy because of rotation mov ar.lc=len2 // initialize lc for small count - cmp.lt p10,p7=COPY_BREAK,len // if len > COPY_BREAK then long copy + cmp.lt p10,p7=COPY_BREAK,len // if len > COPY_BREAK then long copy xor tmp=src,dst // same alignment test prepare (p10) br.cond.dptk.few long_copy_user @@ -128,9 +109,8 @@ // Now we do the byte by byte loop with software pipeline // // p7 is necessarily false by now -1: +1: EX(failure_in_pipe1,(p16) ld1 val1[0]=[src1],1) - EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) br.ctop.dptk.few 1b ;; @@ -148,10 +128,10 @@ and src2=0x7,src1 // src offset and dst2=0x7,dst1 // dst offset ;; - // The basic idea is that we copy byte-by-byte at the head so - // that we can reach 8-byte alignment for both src1 and dst1. - // Then copy the body using software pipelined 8-byte copy, - // shifting the two back-to-back words right and left, then copy + // The basic idea is that we copy byte-by-byte at the head so + // that we can reach 8-byte alignment for both src1 and dst1. + // Then copy the body using software pipelined 8-byte copy, + // shifting the two back-to-back words right and left, then copy // the tail by copying byte-by-byte. // // Fault handling. If the byte-by-byte at the head fails on the @@ -162,18 +142,18 @@ // handled simply by failure_in_pipe1. // // The case p14 represents the source has more bytes in the - // the first word (by the shifted part), whereas the p15 needs to - // copy some bytes from the 2nd word of the source that has the + // the first word (by the shifted part), whereas the p15 needs to + // copy some bytes from the 2nd word of the source that has the // tail of the 1st of the destination. // // - // Optimization. If dst1 is 8-byte aligned (not rarely), we don't need - // to copy the head to dst1, to start 8-byte copy software pipleline. + // Optimization. If dst1 is 8-byte aligned (not rarely), we don't need + // to copy the head to dst1, to start 8-byte copy software pipleline. // We know src1 is not 8-byte aligned in this case. // cmp.eq p14,p15=r0,dst2 -(p15) br.cond.spnt.few 1f +(p15) br.cond.spnt.few 1f ;; sub t1=8,src2 mov t2=src2 @@ -182,10 +162,10 @@ sub len1=len,t1 // set len1 ;; sub lshift=64,rshift - ;; + ;; br.cond.spnt.few word_copy_user - ;; -1: + ;; +1: cmp.leu p14,p15=src2,dst2 sub t1=dst2,src2 ;; @@ -196,30 +176,29 @@ ;; // For the case p14, we don't need to copy the shifted part to // the 1st word of destination. - sub t2=8,t1 + sub t2=8,t1 (p14) sub word1=word1,t1 ;; sub len1=len,word1 // resulting len (p15) shl rshift=t1,3 // in bits (p14) shl rshift=t2,3 - ;; + ;; (p14) sub len1=len1,t1 adds cnt=-1,word1 - ;; + ;; sub lshift=64,rshift mov ar.ec=PIPE_DEPTH mov pr.rot=1<<16 // p16=true all others are false mov ar.lc=cnt - ;; -2: + ;; +2: EX(failure_in_pipe2,(p16) ld1 val1[0]=[src1],1) - ;; EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) br.ctop.dptk.few 2b ;; - clrrrb - ;; -word_copy_user: + clrrrb + ;; +word_copy_user: cmp.gtu p9,p0=16,len1 (p9) br.cond.spnt.few 4f // if (16 > len1) skip 8-byte copy ;; @@ -227,7 +206,7 @@ ;; adds cnt=-1,cnt ;; - .pred.rel "mutex", p14, p15 + .pred.rel "mutex", p14, p15 (p14) sub src1=src1,t2 (p15) sub src1=src1,t1 // @@ -237,23 +216,23 @@ mov ar.lc=cnt mov ar.ec=PIPE_DEPTH mov pr.rot=1<<16 // p16=true all others are false - ;; + ;; 3: // - // The pipleline consists of 3 stages: + // The pipleline consists of 3 stages: // 1 (p16): Load a word from src1 // 2 (EPI_1): Shift right pair, saving to tmp // 3 (EPI): Store tmp to dst1 // - // To make it simple, use at least 2 (p16) loops to set up val1[n] + // To make it simple, use at least 2 (p16) loops to set up val1[n] // because we need 2 back-to-back val1[] to get tmp. // Note that this implies EPI_2 must be p18 or greater. - // + // #define EPI_1 p[PIPE_DEPTH-2] #define SWITCH(pred, shift) cmp.eq pred,p0=shift,rshift #define CASE(pred, shift) \ - (pred) br.cond.spnt.few copy_user_bit##shift + (pred) br.cond.spnt.few copy_user_bit##shift #define BODY(rshift) \ copy_user_bit##rshift: \ 1: \ @@ -267,11 +246,11 @@ // // Since the instruction 'shrp' requires a fixed 128-bit value // specifying the bits to shift, we need to provide 7 cases - // below. + // below. // SWITCH(p6, 8) SWITCH(p7, 16) - SWITCH(p8, 24) + SWITCH(p8, 24) SWITCH(p9, 32) SWITCH(p10, 40) SWITCH(p11, 48) @@ -289,40 +268,40 @@ BODY(16) BODY(24) BODY(32) - BODY(40) + BODY(40) BODY(48) BODY(56) - ;; -.diff_align_do_tail: - .pred.rel "mutex", p14, p15 + ;; +.diff_align_do_tail: + .pred.rel "mutex", p14, p15 (p14) sub src1=src1,t1 -(p14) adds dst1=-8,dst1 +(p14) adds dst1=-8,dst1 (p15) sub dst1=dst1,t1 - ;; -4: + ;; +4: // Tail correction. // // The problem with this piplelined loop is that the last word is not - // loaded and thus parf of the last word written is not correct. + // loaded and thus parf of the last word written is not correct. // To fix that, we simply copy the tail byte by byte. - + sub len1=endsrc,src1,1 clrrrb - ;; + ;; mov ar.ec=PIPE_DEPTH mov pr.rot=1<<16 // p16=true all others are false mov ar.lc=len1 ;; -5: +5: EX(failure_in_pipe1,(p16) ld1 val1[0]=[src1],1) - EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) br.ctop.dptk.few 5b ;; + mov ar.lc=saved_lc mov pr=saved_pr,0xffffffffffff0000 mov ar.pfs=saved_pfs br.ret.dptk.few rp - + // // Beginning of long mempcy (i.e. > 16 bytes) // @@ -353,6 +332,7 @@ // we have never executed the ld1, therefore st1 is not executed. // EX(failure_in1,(p8) ld4 val2[0]=[src1],4) // 4-byte aligned + ;; EX(failure_out,(p6) st1 [dst1]=val1[0],1) tbit.nz p9,p0=src1,3 ;; @@ -369,12 +349,12 @@ shr.u cnt=len1,4 // number of 128-bit (2x64bit) words ;; EX(failure_out, (p9) st8 [dst1]=val2[1],8) - tbit.nz p6,p0=len1,3 + tbit.nz p6,p0=len1,3 cmp.eq p7,p0=r0,cnt adds tmp=-1,cnt // br.ctop is repeat/until (p7) br.cond.dpnt.few .dotail // we have less than 16 bytes left ;; - adds src2=8,src1 + adds src2=8,src1 adds dst2=8,dst1 mov ar.lc=tmp ;; @@ -395,12 +375,12 @@ // No matter where we come from (loop or test) the src1 pointer // is 16 byte aligned AND we have less than 16 bytes to copy. // -.dotail: +.dotail: EX(failure_in1,(p6) ld8 val1[0]=[src1],8) // at least 8 bytes tbit.nz p7,p0=len1,2 ;; EX(failure_in1,(p7) ld4 val1[1]=[src1],4) // at least 4 bytes - tbit.nz p8,p0=len1,1 + tbit.nz p8,p0=len1,1 ;; EX(failure_in1,(p8) ld2 val2[0]=[src1],2) // at least 2 bytes tbit.nz p9,p0=len1,0 @@ -430,7 +410,7 @@ // // In the same loop iteration, the dst1 pointer does not directly // reflect where the faulty load was. - // + // // - pipeline effect // When you get a fault on load, you may have valid data from // previous loads not yet store in transit. Such data must be @@ -442,7 +422,7 @@ // - we don't disrupt the pipeline, i.e. data in transit in // the software pipeline will be eventually move to memory. // We simply replace the load with a simple mov and keep the - // pipeline going. We can't really do this inline because + // pipeline going. We can't really do this inline because // p16 is always reset to 1 when lc > 0. // failure_in_pipe1: @@ -459,7 +439,7 @@ // // This is the case where the byte by byte copy fails on the load - // when we copy the head. We need to finish the pipeline and copy + // when we copy the head. We need to finish the pipeline and copy // zeros for the rest of the destination. Since this happens // at the top we still need to fill the body and tail. failure_in_pipe2: @@ -471,7 +451,7 @@ ;; sub len=enddst,dst1,1 // precompute len br.cond.dptk.few failure_in1bis - ;; + ;; // // Here we handle the head & tail part when we check for alignment. @@ -482,7 +462,7 @@ // // However some simplifications are possible given the way // things work. - // + // // 1) HEAD // Theory of operation: // @@ -506,23 +486,23 @@ // // Key point: // - if you fail on 1, 2, 4 then you have never executed any smaller - // size loads, e.g. failing ld4 means no ld1 nor ld2 executed + // size loads, e.g. failing ld4 means no ld1 nor ld2 executed // before. // // This allows us to simplify the cleanup code, because basically you // only have to worry about "pending" stores in the case of a failing - // ld8(). Given the way the code is written today, this means only + // ld8(). Given the way the code is written today, this means only // worry about st2, st4. There we can use the information encapsulated // into the predicates. - // + // // Other key point: - // - if you fail on the ld8 in the head, it means you went straight + // - if you fail on the ld8 in the head, it means you went straight // to it, i.e. 8byte alignment within an unexisting page. // Again this comes from the fact that if you crossed just for the ld8 then // you are 8byte aligned but also 16byte align, therefore you would // either go for the 16byte copy loop OR the ld8 in the tail part. // The combination ld1, ld2, ld4, ld8 where you fail on ld8 is impossible - // because it would mean you had 15bytes to copy in which case you + // because it would mean you had 15bytes to copy in which case you // would have defaulted to the byte by byte copy. // // @@ -533,18 +513,18 @@ // Key point: // This means that we either: // - are right on a page boundary - // OR - // - are at more than 16 bytes from a page boundary with + // OR + // - are at more than 16 bytes from a page boundary with // at most 15 bytes to copy: no chance of crossing. // // This allows us to assume that if we fail on a load we haven't possibly - // executed any of the previous (tail) ones, so we don't need to do - // any stores. For instance, if we fail on ld2, this means we had + // executed any of the previous (tail) ones, so we don't need to do + // any stores. For instance, if we fail on ld2, this means we had // 2 or 3 bytes left to copy and we did not execute the ld8 nor ld4. // - // This means that we are in a situation similar the a fault in the - // head part. That's nice! - // + // This means that we are in a situation similar the a fault in the + // head part. That's nice! + // failure_in1: // sub ret0=enddst,dst1 // number of bytes to zero, i.e. not copied // sub len=enddst,dst1,1 @@ -563,7 +543,7 @@ ;; 5: st1 [dst1]=r0,1 - br.cloop.dptk.few 5b + br.cloop.dptk.few 5b ;; skip_loop: mov pr=saved_pr,0xffffffffffff0000 @@ -574,7 +554,7 @@ // // Here we simply restart the loop but instead // of doing loads we fill the pipeline with zeroes - // We can't simply store r0 because we may have valid + // We can't simply store r0 because we may have valid // data in transit in the pipeline. // ar.lc and ar.ec are setup correctly at this point // @@ -593,7 +573,7 @@ ;; cmp.ne p6,p0=dst1,enddst // Do we need to finish the tail ? sub len=enddst,dst1,1 // precompute len -(p6) br.cond.dptk.few failure_in1bis +(p6) br.cond.dptk.few failure_in1bis ;; mov pr=saved_pr,0xffffffffffff0000 mov ar.lc=saved_lc @@ -610,13 +590,13 @@ ;; cmp.ne p6,p0=dst1,enddst // Do we need to finish the tail ? sub len=enddst,dst1,1 // precompute len -(p6) br.cond.dptk.few failure_in1bis +(p6) br.cond.dptk.few failure_in1bis ;; mov pr=saved_pr,0xffffffffffff0000 mov ar.lc=saved_lc mov ar.pfs=saved_pfs br.ret.dptk.few rp - + // // handling of failures on stores: that's the easy part // diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/csum_partial_copy.c linux.ac/arch/ia64/lib/csum_partial_copy.c --- linux.vanilla/arch/ia64/lib/csum_partial_copy.c Mon Feb 7 02:42:40 2000 +++ linux.ac/arch/ia64/lib/csum_partial_copy.c Tue Apr 10 18:09:55 2001 @@ -1,6 +1,6 @@ /* * Network Checksum & Copy routine - * + * * Copyright (C) 1999 Hewlett-Packard Co * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com> * @@ -107,22 +107,18 @@ do_csum_partial_copy_from_user (const char *src, char *dst, int len, unsigned int psum, int *errp) { - const unsigned char *psrc = src; unsigned long result; - int cplen = len; - int r = 0; /* XXX Fixme - * for now we separate the copy from checksum for obvious + * for now we separate the copy from checksum for obvious * alignment difficulties. Look at the Alpha code and you'll be * scared. */ - while ( cplen-- ) r |=__get_user(*dst++,psrc++); - - if ( r && errp ) *errp = r; + if (__copy_from_user(dst, src, len) != 0 && errp) + *errp = -EFAULT; - result = do_csum(src, len); + result = do_csum(dst, len); /* add in old sum, and carry.. */ result += psum; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/do_csum.S linux.ac/arch/ia64/lib/do_csum.S --- linux.vanilla/arch/ia64/lib/do_csum.S Thu Jun 22 15:09:44 2000 +++ linux.ac/arch/ia64/lib/do_csum.S Tue Apr 10 18:09:55 2001 @@ -7,8 +7,8 @@ * Inputs: * in0: address of buffer to checksum (char *) * in1: length of the buffer (int) - * - * Copyright (C) 1999 Hewlett-Packard Co + * + * Copyright (C) 1999, 2001 Hewlett-Packard Co * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com> * */ @@ -39,7 +39,7 @@ // This version avoids synchronization in the core loop by also using a // pipeline for the accumulation of the checksum in result[]. // -// p[] +// p[] // |---| // 0| | r32 : new value loaded in pipeline // |---| @@ -50,7 +50,7 @@ // 3| | r35 : previous value added to checksum (previous iteration) // |---| // -// result[] +// result[] // |---| // 0| | r36 : new checksum // |---| @@ -68,7 +68,7 @@ // - Maybe another algorithm which would take care of the folding at the // end in a different manner // - Work with people more knowledgeable than me on the network stack -// to figure out if we could not split the function depending on the +// to figure out if we could not split the function depending on the // type of packet or alignment we get. Like the ip_fast_csum() routine // where we know we have at least 20bytes worth of data to checksum. // - Look at RFCs about checksums to see whether or not we can do better @@ -94,17 +94,11 @@ #define buf in0 #define len in1 - - .text - .psr abi64 - .psr lsb - .lsb - // unsigned long do_csum(unsigned char *buf,int len) GLOBAL_ENTRY(do_csum) - UNW(.prologue) - UNW(.save ar.pfs, saved_pfs) + .prologue + .save ar.pfs, saved_pfs alloc saved_pfs=ar.pfs,2,8,0,8 .rotr p[4], result[3] @@ -126,7 +120,7 @@ ;; and lastoff=7,tmp1 // how many bytes off for last element andcm last=tmp2,tmp3 // address of word containing last byte - UNW(.save pr, saved_pr) + .save pr, saved_pr mov saved_pr=pr // preserve predicates (rotation) ;; sub tmp3=last,first // tmp3=distance from first to last @@ -144,14 +138,14 @@ ;; shl tmp1=tmp1,3 // number of bits - shl hmask=hmask,tmp2 // build head mask, mask off [0,firstoff[ + shl hmask=hmask,tmp2 // build head mask, mask off [0,firstoff[ ;; shr.u tmask=tmask,tmp1 // build tail mask, mask off ]8,lastoff] - UNW(.save ar.lc, saved_lc) + .save ar.lc, saved_lc mov saved_lc=ar.lc // save lc ;; - UNW(.body) + .body (p8) and hmask=hmask,tmask // apply tail mask to head mask if 1 word only (p9) and p[1]=lastval,tmask // mask last it as appropriate @@ -163,7 +157,7 @@ ;; // XXX Fixme: not very nice initialization here // - // Setup loop control registers: + // Setup loop control registers: // // tmp3=0 (1 word) : lc=0, ec=2, p16=F // tmp3=1 (2 words) : lc=0, ec=3, p16=F @@ -227,7 +221,7 @@ add ret0=tmp1,tmp2 mov pr=saved_pr,0xffffffffffff0000 ;; - // if buf was odd then swap bytes + // if buf was odd then swap bytes mov ar.pfs=saved_pfs // restore ar.ec (p10) mux1 ret0=ret0,@rev // reverse word ;; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/flush.S linux.ac/arch/ia64/lib/flush.S --- linux.vanilla/arch/ia64/lib/flush.S Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/lib/flush.S Tue Apr 10 18:09:55 2001 @@ -1,30 +1,25 @@ /* * Cache flushing routines. * - * Copyright (C) 1999-2000 Hewlett-Packard Co - * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <asm/asmmacro.h> #include <asm/page.h> - .text - .psr abi64 - .psr lsb - .lsb - /* * flush_icache_range(start,end) * Must flush range from start to end-1 but nothing else (need to * be careful not to touch addresses that may be unmapped). */ GLOBAL_ENTRY(flush_icache_range) - UNW(.prologue) + .prologue alloc r2=ar.pfs,2,0,0,0 sub r8=in1,in0,1 ;; shr.u r8=r8,5 // we flush 32 bytes per iteration - UNW(.save ar.lc, r3) - mov r3=ar.lc // save ar.lc + .save ar.lc, r3 + mov r3=ar.lc // save ar.lc ;; .body @@ -38,7 +33,7 @@ sync.i ;; srlz.i - ;; + ;; mov ar.lc=r3 // restore ar.lc br.ret.sptk.many rp END(flush_icache_range) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/idiv64.S linux.ac/arch/ia64/lib/idiv64.S --- linux.vanilla/arch/ia64/lib/idiv64.S Tue Oct 10 01:54:56 2000 +++ linux.ac/arch/ia64/lib/idiv64.S Tue Apr 10 18:09:55 2001 @@ -37,28 +37,29 @@ #define NAME PASTE(PASTE(__,SGN),PASTE(OP,di3)) GLOBAL_ENTRY(NAME) - UNW(.prologue) + .prologue .regstk 2,0,0,0 // Transfer inputs to FP registers. setf.sig f8 = in0 setf.sig f9 = in1 - UNW(.fframe 16) - UNW(.save.f 0x20) + ;; + .fframe 16 + .save.f 0x20 stf.spill [sp] = f17,-16 // Convert the inputs to FP, to avoid FP software-assist faults. INT_TO_FP(f8, f8) ;; - UNW(.save.f 0x10) + .save.f 0x10 stf.spill [sp] = f16 - UNW(.body) + .body INT_TO_FP(f9, f9) ;; frcpa.s1 f17, p6 = f8, f9 // y0 = frcpa(b) ;; (p6) fmpy.s1 f7 = f8, f17 // q0 = a*y0 -(p6) fnma.s1 f6 = f9, f17, f1 // e0 = -b*y0 + 1 +(p6) fnma.s1 f6 = f9, f17, f1 // e0 = -b*y0 + 1 ;; (p6) fma.s1 f16 = f7, f6, f7 // q1 = q0*e0 + q0 (p6) fmpy.s1 f7 = f6, f6 // e1 = e0*e0 @@ -70,7 +71,7 @@ (p6) fma.s1 f6 = f17, f6, f17 // y1 = y0*e0 + y0 ;; (p6) fma.s1 f6 = f6, f7, f6 // y2 = y1*e1 + y1 -(p6) fnma.s1 f7 = f9, f16, f8 // r = -b*q2 + a +(p6) fnma.s1 f7 = f9, f16, f8 // r = -b*q2 + a ;; #ifdef MODULO setf.sig f8 = in0 // f8 = a @@ -78,7 +79,7 @@ #endif (p6) fma.s1 f17 = f7, f6, f16 // q3 = r*y2 + q2 ;; - UNW(.restore sp) + .restore sp ldf.fill f16 = [sp], 16 FP_TO_INT(f17, f17) // q = trunc(q3) ;; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/memcpy.S linux.ac/arch/ia64/lib/memcpy.S --- linux.vanilla/arch/ia64/lib/memcpy.S Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/lib/memcpy.S Tue Apr 10 18:09:55 2001 @@ -68,19 +68,19 @@ * the more general copy routine handling arbitrary * sizes/alignment etc. */ - UNW(.prologue) - UNW(.save ar.pfs, saved_pfs) + .prologue + .save ar.pfs, saved_pfs alloc saved_pfs=ar.pfs,3,Nrot,0,Nrot - UNW(.save ar.lc, saved_lc) + .save ar.lc, saved_lc mov saved_lc=ar.lc or t0=in0,in1 ;; or t0=t0,in2 - UNW(.save pr, saved_pr) + .save pr, saved_pr mov saved_pr=pr - UNW(.body) + .body cmp.eq p6,p0=in2,r0 // zero length? mov retval=in0 // return dst diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/memset.S linux.ac/arch/ia64/lib/memset.S --- linux.vanilla/arch/ia64/lib/memset.S Thu Jun 22 15:09:44 2000 +++ linux.ac/arch/ia64/lib/memset.S Tue Apr 10 18:09:55 2001 @@ -3,14 +3,13 @@ * Optimized version of the standard memset() function * * Return: none - * * * Inputs: * in0: address of buffer * in1: byte value to use for storing * in2: length of the buffer * - * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999, 2001 Hewlett-Packard Co * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com> */ @@ -31,20 +30,16 @@ #define saved_lc r20 #define tmp r21 - .text - .psr abi64 - .psr lsb - GLOBAL_ENTRY(memset) - UNW(.prologue) - UNW(.save ar.pfs, saved_pfs) - alloc saved_pfs=ar.pfs,3,0,0,0 // cnt is sink here + .prologue + .save ar.pfs, saved_pfs + alloc saved_pfs=ar.pfs,3,0,0,0 // cnt is sink here cmp.eq p8,p0=r0,len // check for zero length - UNW(.save ar.lc, saved_lc) + .save ar.lc, saved_lc mov saved_lc=ar.lc // preserve ar.lc (slow) - ;; + ;; - UNW(.body) + .body adds tmp=-1,len // br.ctop is repeat/until tbit.nz p6,p0=buf,0 // odd alignment @@ -82,7 +77,7 @@ (p6) st8 [buf]=val,8 // 8-byte aligned (p6) adds len=-8,len;; shr.u cnt=len,4 // number of 128-bit (2x64bit) words - ;; + ;; cmp.eq p6,p0=r0,cnt adds tmp=-1,cnt (p6) br.cond.dpnt.few .dotail // we have less than 16 bytes left @@ -96,10 +91,10 @@ br.cloop.dptk.few 2b ;; .dotail: // tail correction based on len only - tbit.nz p6,p0=len,3 + tbit.nz p6,p0=len,3 ;; (p6) st8 [buf]=val,8 // at least 8 bytes - tbit.nz p6,p0=len,2 + tbit.nz p6,p0=len,2 ;; (p6) st4 [buf]=val,4 // at least 4 bytes tbit.nz p6,p0=len,1 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/strlen.S linux.ac/arch/ia64/lib/strlen.S --- linux.vanilla/arch/ia64/lib/strlen.S Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/ia64/lib/strlen.S Tue Apr 10 18:09:55 2001 @@ -5,12 +5,12 @@ * * Inputs: * in0 address of string - * - * Outputs: - * ret0 the number of characters in the string (0 if empty string) - * does not count the \0 * - * Copyright (C) 1999 Hewlett-Packard Co + * Outputs: + * ret0 the number of characters in the string (0 if empty string) + * does not count the \0 + * + * Copyright (C) 1999, 2001 Hewlett-Packard Co * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com> * * 09/24/99 S.Eranian add speculation recovery code @@ -30,7 +30,7 @@ // string may not be 8-byte aligned. In this case we load the 8byte // quantity which includes the start of the string and mask the unused // bytes with 0xff to avoid confusing czx. -// We use speculative loads and software pipelining to hide memory +// We use speculative loads and software pipelining to hide memory // latency and do read ahead safely. This way we defer any exception. // // Because we don't want the kernel to be relying on particular @@ -42,7 +42,7 @@ // The fact that speculation may fail can be caused, for instance, by // the DCR.dm bit being set. In this case TLB misses are deferred, i.e., // a NaT bit will be set if the translation is not present. The normal -// load, on the other hand, will cause the translation to be inserted +// load, on the other hand, will cause the translation to be inserted // if the mapping exists. // // It should be noted that we execute recovery code only when we need @@ -50,22 +50,22 @@ // recovery code on pure read ahead data. // // Remarks: -// - the cmp r0,r0 is used as a fast way to initialize a predicate +// - the cmp r0,r0 is used as a fast way to initialize a predicate // register to 1. This is required to make sure that we get the parallel // compare correct. // // - we don't use the epilogue counter to exit the loop but we need to set // it to zero beforehand. // -// - after the loop we must test for Nat values because neither the +// - after the loop we must test for Nat values because neither the // czx nor cmp instruction raise a NaT consumption fault. We must be -// careful not to look too far for a Nat for which we don't care. +// careful not to look too far for a Nat for which we don't care. // For instance we don't need to look at a NaT in val2 if the zero byte // was in val1. // // - Clearly performance tuning is required. // -// +// // #define saved_pfs r11 #define tmp r10 @@ -78,15 +78,9 @@ #define val1 r22 #define val2 r23 - - .text - .psr abi64 - .psr lsb - .lsb - GLOBAL_ENTRY(strlen) - UNW(.prologue) - UNW(.save ar.pfs, saved_pfs) + .prologue + .save ar.pfs, saved_pfs alloc saved_pfs=ar.pfs,11,0,0,8 // rotating must be multiple of 8 .rotr v[2], w[2] // declares our 4 aliases @@ -94,11 +88,11 @@ extr.u tmp=in0,0,3 // tmp=least significant 3 bits mov orig=in0 // keep trackof initial byte address dep src=0,in0,0,3 // src=8byte-aligned in0 address - UNW(.save pr, saved_pr) + .save pr, saved_pr mov saved_pr=pr // preserve predicates (rotation) ;; - UNW(.body) + .body ld8 v[1]=[src],8 // must not speculate: can fail here shl tmp=tmp,3 // multiply by 8bits/byte @@ -115,8 +109,8 @@ or v[1]=v[1],mask // now we have a safe initial byte pattern ;; 1: - ld8.s v[0]=[src],8 // speculatively load next - czx1.r val1=v[1] // search 0 byte from right + ld8.s v[0]=[src],8 // speculatively load next + czx1.r val1=v[1] // search 0 byte from right czx1.r val2=w[1] // search 0 byte from right following 8bytes ;; ld8.s w[0]=[src],8 // speculatively load next to next @@ -132,11 +126,7 @@ // - there must be a better way of doing the test // cmp.eq p8,p9=8,val1 // p6 = val1 had zero (disambiguate) -#ifdef notyet tnat.nz p6,p7=val1 // test NaT on val1 -#else - tnat.z p7,p6=val1 // test NaT on val1 -#endif (p6) br.cond.spnt.few recover// jump to recovery if val1 is NaT ;; // @@ -154,7 +144,7 @@ sub tmp=8,val1 // which byte in word mov pr=saved_pr,0xffffffffffff0000 ;; - sub ret0=ret0,tmp // adjust + sub ret0=ret0,tmp // adjust mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what br.ret.sptk.few rp // end of normal execution @@ -167,8 +157,8 @@ // // IMPORTANT: // Please note that in the case of strlen() as opposed to strlen_user() - // we don't use the exception mechanism, as this function is not - // supposed to fail. If that happens it means we have a bug and the + // we don't use the exception mechanism, as this function is not + // supposed to fail. If that happens it means we have a bug and the // code will cause of kernel fault. // // XXX Fixme @@ -187,7 +177,7 @@ 2: (p6) ld8 val=[base],8 // will fail if unrecoverable fault ;; - czx1.r val1=val // search 0 byte from right + czx1.r val1=val // search 0 byte from right ;; cmp.eq p6,p0=8,val1 // val1==8 ? (p6) br.wtop.dptk.few 2b // loop until p6 == 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/strlen_user.S linux.ac/arch/ia64/lib/strlen_user.S --- linux.vanilla/arch/ia64/lib/strlen_user.S Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/ia64/lib/strlen_user.S Tue Apr 10 18:09:55 2001 @@ -6,9 +6,9 @@ * * Outputs: * ret0 0 in case of fault, strlen(buffer)+1 otherwise - * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co + * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com> * * 01/19/99 S.Eranian heavily enhanced version (see details below) @@ -24,8 +24,8 @@ // - length of string + 1 // - 0 in case an exception is raised // -// This is an enhanced version of the basic strlen_user. it includes a -// combination of compute zero index (czx), parallel comparisons, speculative +// This is an enhanced version of the basic strlen_user. it includes a +// combination of compute zero index (czx), parallel comparisons, speculative // loads and loop unroll using rotating registers. // // General Ideas about the algorithm: @@ -34,7 +34,7 @@ // string may not be 8-byte aligned. In this case we load the 8byte // quantity which includes the start of the string and mask the unused // bytes with 0xff to avoid confusing czx. -// We use speculative loads and software pipelining to hide memory +// We use speculative loads and software pipelining to hide memory // latency and do read ahead safely. This way we defer any exception. // // Because we don't want the kernel to be relying on particular @@ -45,7 +45,7 @@ // The fact that speculation may fail can be caused, for instance, by // the DCR.dm bit being set. In this case TLB misses are deferred, i.e., // a NaT bit will be set if the translation is not present. The normal -// load, on the other hand, will cause the translation to be inserted +// load, on the other hand, will cause the translation to be inserted // if the mapping exists. // // It should be noted that we execute recovery code only when we need @@ -53,30 +53,21 @@ // recovery code on pure read ahead data. // // Remarks: -// - the cmp r0,r0 is used as a fast way to initialize a predicate +// - the cmp r0,r0 is used as a fast way to initialize a predicate // register to 1. This is required to make sure that we get the parallel // compare correct. // // - we don't use the epilogue counter to exit the loop but we need to set // it to zero beforehand. // -// - after the loop we must test for Nat values because neither the +// - after the loop we must test for Nat values because neither the // czx nor cmp instruction raise a NaT consumption fault. We must be -// careful not to look too far for a Nat for which we don't care. +// careful not to look too far for a Nat for which we don't care. // For instance we don't need to look at a NaT in val2 if the zero byte // was in val1. // // - Clearly performance tuning is required. // -// -// - -#define EX(y,x...) \ - .section __ex_table,"a"; \ - data4 @gprel(99f); \ - data4 y-99f; \ - .previous; \ -99: x #define saved_pfs r11 #define tmp r10 @@ -89,15 +80,9 @@ #define val1 r22 #define val2 r23 - - .text - .psr abi64 - .psr lsb - .lsb - GLOBAL_ENTRY(__strlen_user) - UNW(.prologue) - UNW(.save ar.pfs, saved_pfs) + .prologue + .save ar.pfs, saved_pfs alloc saved_pfs=ar.pfs,11,0,0,8 .rotr v[2], w[2] // declares our 4 aliases @@ -105,7 +90,7 @@ extr.u tmp=in0,0,3 // tmp=least significant 3 bits mov orig=in0 // keep trackof initial byte address dep src=0,in0,0,3 // src=8byte-aligned in0 address - UNW(.save pr, saved_pr) + .save pr, saved_pr mov saved_pr=pr // preserve predicates (rotation) ;; @@ -127,8 +112,8 @@ or v[1]=v[1],mask // now we have a safe initial byte pattern ;; 1: - ld8.s v[0]=[src],8 // speculatively load next - czx1.r val1=v[1] // search 0 byte from right + ld8.s v[0]=[src],8 // speculatively load next + czx1.r val1=v[1] // search 0 byte from right czx1.r val2=w[1] // search 0 byte from right following 8bytes ;; ld8.s w[0]=[src],8 // speculatively load next to next @@ -144,11 +129,7 @@ // - there must be a better way of doing the test // cmp.eq p8,p9=8,val1 // p6 = val1 had zero (disambiguate) -#ifdef notyet tnat.nz p6,p7=val1 // test NaT on val1 -#else - tnat.z p7,p6=val1 // test NaT on val1 -#endif (p6) br.cond.spnt.few recover// jump to recovery if val1 is NaT ;; // @@ -193,7 +174,7 @@ 2: EX(.Lexit1, (p6) ld8 val=[base],8) ;; - czx1.r val1=val // search 0 byte from right + czx1.r val1=val // search 0 byte from right ;; cmp.eq p6,p0=8,val1 // val1==8 ? (p6) br.wtop.dptk.few 2b // loop until p6 == 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/strncpy_from_user.S linux.ac/arch/ia64/lib/strncpy_from_user.S --- linux.vanilla/arch/ia64/lib/strncpy_from_user.S Thu Jun 22 15:09:44 2000 +++ linux.ac/arch/ia64/lib/strncpy_from_user.S Tue Apr 10 18:09:55 2001 @@ -8,9 +8,9 @@ * in2: length of buffer in bytes * Outputs: * r8: -EFAULT in case of fault or number of bytes copied if no fault - * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * * 00/03/06 D. Mosberger Fixed to return proper return value (bug found by * by Andreas Schwab <schwab@suse.de>). @@ -18,18 +18,6 @@ #include <asm/asmmacro.h> -#define EX(x...) \ -99: x; \ - .section __ex_table,"a"; \ - data4 @gprel(99b); \ - data4 .Lexit-99b; \ - .previous - - .text - .psr abi64 - .psr lsb - .lsb - GLOBAL_ENTRY(__strncpy_from_user) alloc r2=ar.pfs,3,0,0,0 mov r8=0 @@ -41,15 +29,16 @@ // XXX braindead copy loop---this needs to be optimized .Loop1: - EX(ld1 r8=[in1],1;; st1 [in0]=r8,1; cmp.ne p6,p7=r8,r0) + EX(.Lexit, ld1 r8=[in1],1) + ;; + EX(.Lexit, st1 [in0]=r8,1) + cmp.ne p6,p7=r8,r0 ;; (p6) cmp.ne.unc p8,p0=in1,r10 (p8) br.cond.dpnt.few .Loop1 ;; (p6) mov r8=in2 // buffer filled up---return buffer length (p7) sub r8=in1,r9,1 // return string length (excluding NUL character) - br.ret.sptk.few rp - -.Lexit: +[.Lexit:] br.ret.sptk.few rp END(__strncpy_from_user) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/strnlen_user.S linux.ac/arch/ia64/lib/strnlen_user.S --- linux.vanilla/arch/ia64/lib/strnlen_user.S Thu Jun 22 15:09:44 2000 +++ linux.ac/arch/ia64/lib/strnlen_user.S Tue Apr 10 18:09:55 2001 @@ -8,41 +8,28 @@ * in1: string length limit N * Outputs: * r8: 0 in case of fault, strlen(buffer)+1 otherwise - * - * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * + * Copyright (C) 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <asm/asmmacro.h> -/* If a fault occurs, r8 gets set to -EFAULT and r9 gets cleared. */ -#define EX(x...) \ - .section __ex_table,"a"; \ - data4 @gprel(99f); \ - data4 (.Lexit-99f)|1; \ - .previous \ -99: x; - - .text - .psr abi64 - .psr lsb - .lsb - GLOBAL_ENTRY(__strnlen_user) - UNW(.prologue) + .prologue alloc r2=ar.pfs,2,0,0,0 - UNW(.save ar.lc, r16) + .save ar.lc, r16 mov r16=ar.lc // preserve ar.lc - UNW(.body) + .body add r3=-1,in1 ;; mov ar.lc=r3 mov r9=0 - + ;; // XXX braindead strlen loop---this needs to be optimized .Loop1: - EX(ld1 r8=[in0],1) + EXCLR(.Lexit, ld1 r8=[in0],1) add r9=1,r9 ;; cmp.eq p6,p0=r8,r0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/swiotlb.c linux.ac/arch/ia64/lib/swiotlb.c --- linux.vanilla/arch/ia64/lib/swiotlb.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/lib/swiotlb.c Tue Apr 10 18:09:55 2001 @@ -11,6 +11,7 @@ */ #include <linux/mm.h> +#include <linux/module.h> #include <linux/pci.h> #include <linux/spinlock.h> #include <linux/string.h> @@ -50,14 +51,14 @@ static unsigned int io_tlb_index; /* - * We need to save away the original address corresponding to a mapped entry for the sync + * We need to save away the original address corresponding to a mapped entry for the sync * operations. */ static unsigned char **io_tlb_orig_addr; /* * Protect the above data structures in the map and unmap calls - */ + */ static spinlock_t io_tlb_lock = SPIN_LOCK_UNLOCKED; static int __init @@ -132,7 +133,7 @@ { wrap = index = ALIGN(io_tlb_index, stride); - if (index >= io_tlb_nslabs) + if (index >= io_tlb_nslabs) wrap = index = 0; do { @@ -164,12 +165,12 @@ } while (index != wrap); /* - * XXX What is a suitable recovery mechanism here? We cannot + * XXX What is a suitable recovery mechanism here? We cannot * sleep because we are called from with in interrupts! */ panic("map_single: could not allocate software IO TLB (%ld bytes)", size); -found: } + found: spin_unlock_irqrestore(&io_tlb_lock, flags); /* @@ -199,9 +200,9 @@ */ if ((direction == PCI_DMA_FROMDEVICE) || (direction == PCI_DMA_BIDIRECTIONAL)) /* - * bounce... copy the data back into the original buffer * and delete the - * bounce buffer. - */ + * bounce... copy the data back into the original buffer * and delete the + * bounce buffer. + */ memcpy(buffer, dma_addr, size); /* @@ -236,9 +237,9 @@ char *buffer = io_tlb_orig_addr[index]; /* - * bounce... copy the data back into/from the original buffer + * bounce... copy the data back into/from the original buffer * XXX How do you handle PCI_DMA_BIDIRECTIONAL here ? - */ + */ if (direction == PCI_DMA_FROMDEVICE) memcpy(buffer, dma_addr, size); else if (direction == PCI_DMA_TODEVICE) @@ -298,8 +299,8 @@ */ return pci_addr; - /* - * get a bounce buffer: + /* + * get a bounce buffer: */ pci_addr = virt_to_phys(map_single(hwdev, ptr, size, direction)); @@ -325,12 +326,8 @@ pg_addr = PAGE_ALIGN((unsigned long) addr); end = (unsigned long) addr + size; while (pg_addr + PAGE_SIZE <= end) { -#if 0 - set_bit(PG_arch_1, virt_to_page(pg_addr)); -#else - if (!VALID_PAGE(virt_to_page(pg_addr))) - printk("Invalid addr %lx!!!\n", pg_addr); -#endif + struct page *page = virt_to_page(pg_addr); + set_bit(PG_arch_1, &page->flags); pg_addr += PAGE_SIZE; } } @@ -454,3 +451,14 @@ { return virt_to_phys(sg->address); } + +EXPORT_SYMBOL(swiotlb_init); +EXPORT_SYMBOL(swiotlb_map_single); +EXPORT_SYMBOL(swiotlb_unmap_single); +EXPORT_SYMBOL(swiotlb_map_sg); +EXPORT_SYMBOL(swiotlb_unmap_sg); +EXPORT_SYMBOL(swiotlb_sync_single); +EXPORT_SYMBOL(swiotlb_sync_sg); +EXPORT_SYMBOL(swiotlb_dma_address); +EXPORT_SYMBOL(swiotlb_alloc_consistent); +EXPORT_SYMBOL(swiotlb_free_consistent); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/mm/extable.c linux.ac/arch/ia64/mm/extable.c --- linux.vanilla/arch/ia64/mm/extable.c Mon Feb 7 02:42:40 2000 +++ linux.ac/arch/ia64/mm/extable.c Tue Apr 10 18:09:55 2001 @@ -1,8 +1,8 @@ /* * Kernel exception handling table support. Derived from arch/alpha/mm/extable.c. * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co + * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/config.h> @@ -43,14 +43,22 @@ return 0; } -register unsigned long gp __asm__("gp"); +#ifndef CONFIG_MODULE +register unsigned long main_gp __asm__("gp"); +#endif -const struct exception_table_entry * +struct exception_fixup search_exception_table (unsigned long addr) { + const struct exception_table_entry *entry; + struct exception_fixup fix = { 0 }; + #ifndef CONFIG_MODULE /* There is only the kernel to search. */ - return search_one_table(__start___ex_table, __stop___ex_table - 1, addr - gp); + entry = search_one_table(__start___ex_table, __stop___ex_table - 1, addr - main_gp); + if (entry) + fix.cont = entry->cont + main_gp; + return fix; #else struct exception_table_entry *ret; /* The kernel is the last "module" -- no need to treat it special. */ @@ -59,10 +67,22 @@ for (mp = module_list; mp ; mp = mp->next) { if (!mp->ex_table_start) continue; - ret = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr - mp->gp); - if (ret) - return ret; + entry = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr - mp->gp); + if (entry) { + fix.cont = entry->cont + mp->gp; + return fix; + } } - return 0; #endif + return fix; +} + +void +handle_exception (struct pt_regs *regs, struct exception_fixup fix) +{ + regs->r8 = -EFAULT; + if (fix.cont & 4) + regs->r9 = 0; + regs->cr_iip = (long) fix.cont & ~0xf; + ia64_psr(regs)->ri = fix.cont & 0x3; /* set continuation slot number */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/mm/fault.c linux.ac/arch/ia64/mm/fault.c --- linux.vanilla/arch/ia64/mm/fault.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/ia64/mm/fault.c Tue Apr 10 18:09:55 2001 @@ -47,7 +47,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs) { struct mm_struct *mm = current->mm; - const struct exception_table_entry *fix; + struct exception_fixup fix; struct vm_area_struct *vma, *prev_vma; struct siginfo si; int signal = SIGSEGV; @@ -163,14 +163,13 @@ return; } +#ifdef GAS_HAS_LOCAL_TAGS + fix = search_exception_table(regs->cr_iip + ia64_psr(regs)->ri); +#else fix = search_exception_table(regs->cr_iip); - if (fix) { - regs->r8 = -EFAULT; - if (fix->skip & 1) { - regs->r9 = 0; - } - regs->cr_iip += ((long) fix->skip) & ~15; - regs->cr_ipsr &= ~IA64_PSR_RI; /* clear exception slot number */ +#endif + if (fix.cont) { + handle_exception(regs, fix); return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/mm/init.c linux.ac/arch/ia64/mm/init.c --- linux.vanilla/arch/ia64/mm/init.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/mm/init.c Tue Apr 10 18:11:49 2001 @@ -1,8 +1,8 @@ /* * Initialize MMU support. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/config.h> #include <linux/kernel.h> @@ -23,116 +23,36 @@ #include <asm/pgalloc.h> #include <asm/sal.h> #include <asm/system.h> +#include <asm/uaccess.h> +#include <asm/tlb.h> + +mmu_gather_t mmu_gathers[NR_CPUS]; /* References to section boundaries: */ extern char _stext, _etext, _edata, __init_begin, __init_end; -/* - * These are allocated in head.S so that we get proper page alignment. - * If you change the size of these then change head.S as well. - */ -extern char empty_bad_page[PAGE_SIZE]; -extern pmd_t empty_bad_pmd_table[PTRS_PER_PMD]; -extern pte_t empty_bad_pte_table[PTRS_PER_PTE]; - extern void ia64_tlb_init (void); +unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL; + static unsigned long totalram_pages; -/* - * Fill in empty_bad_pmd_table with entries pointing to - * empty_bad_pte_table and return the address of this PMD table. - */ -static pmd_t * -get_bad_pmd_table (void) -{ - pmd_t v; - int i; - - pmd_set(&v, empty_bad_pte_table); - - for (i = 0; i < PTRS_PER_PMD; ++i) - empty_bad_pmd_table[i] = v; - - return empty_bad_pmd_table; -} - -/* - * Fill in empty_bad_pte_table with PTEs pointing to empty_bad_page - * and return the address of this PTE table. - */ -static pte_t * -get_bad_pte_table (void) -{ - pte_t v; - int i; - - set_pte(&v, pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED))); - - for (i = 0; i < PTRS_PER_PTE; ++i) - empty_bad_pte_table[i] = v; - - return empty_bad_pte_table; -} - -void -__handle_bad_pgd (pgd_t *pgd) -{ - pgd_ERROR(*pgd); - pgd_set(pgd, get_bad_pmd_table()); -} - -void -__handle_bad_pmd (pmd_t *pmd) -{ - pmd_ERROR(*pmd); - pmd_set(pmd, get_bad_pte_table()); -} - -/* - * Allocate and initialize an L3 directory page and set - * the L2 directory entry PMD to the newly allocated page. - */ -pte_t* -get_pte_slow (pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - /* everything A-OK */ - clear_page(pte); - pmd_set(pmd, pte); - return pte + offset; - } - pmd_set(pmd, get_bad_pte_table()); - return NULL; - } - free_page((unsigned long) pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - int do_check_pgt_cache (int low, int high) { int freed = 0; - if (pgtable_cache_size > high) { - do { - if (pgd_quicklist) - free_page((unsigned long)get_pgd_fast()), ++freed; - if (pmd_quicklist) - free_page((unsigned long)get_pmd_fast()), ++freed; - if (pte_quicklist) - free_page((unsigned long)get_pte_fast()), ++freed; - } while (pgtable_cache_size > low); - } - return freed; + if (pgtable_cache_size > high) { + do { + if (pgd_quicklist) + free_page((unsigned long)pgd_alloc_one_fast()), ++freed; + if (pmd_quicklist) + free_page((unsigned long)pmd_alloc_one_fast(0, 0)), ++freed; + if (pte_quicklist) + free_page((unsigned long)pte_alloc_one_fast(0, 0)), ++freed; + } while (pgtable_cache_size > low); + } + return freed; } /* @@ -188,12 +108,12 @@ { /* * EFI uses 4KB pages while the kernel can use 4KB or bigger. - * Thus EFI and the kernel may have different page sizes. It is - * therefore possible to have the initrd share the same page as - * the end of the kernel (given current setup). + * Thus EFI and the kernel may have different page sizes. It is + * therefore possible to have the initrd share the same page as + * the end of the kernel (given current setup). * * To avoid freeing/using the wrong page (kernel sized) we: - * - align up the beginning of initrd + * - align up the beginning of initrd * - keep the end untouched * * | | @@ -201,8 +121,8 @@ * | | * | | * | | 9000 - * |/////////////| - * |/////////////| + * |/////////////| + * |/////////////| * |=============| 8000 * |///INITRD////| * |/////////////| @@ -211,9 +131,9 @@ * |KKKKKKKKKKKKK| * |=============| 6000 * |KKKKKKKKKKKKK| - * |KKKKKKKKKKKKK| + * |KKKKKKKKKKKKK| * K=kernel using 8KB pages - * + * * In this example, we must free page 8000 ONLY. So we must align up * initrd_start and keep initrd_end as is. */ @@ -286,52 +206,59 @@ page_address(page)); pgd = pgd_offset_k(address); /* note: this is NOT pgd_offset()! */ - pmd = pmd_alloc(pgd, address); - if (!pmd) { - __free_page(page); - panic("Out of memory."); - return 0; - } - pte = pte_alloc(pmd, address); - if (!pte) { - __free_page(page); - panic("Out of memory."); - return 0; - } - if (!pte_none(*pte)) { - pte_ERROR(*pte); - __free_page(page); - return 0; + + spin_lock(&init_mm.page_table_lock); + { + pmd = pmd_alloc(&init_mm, pgd, address); + if (!pmd) + goto out; + pte = pte_alloc(&init_mm, pmd, address); + if (!pte) + goto out; + if (!pte_none(*pte)) { + pte_ERROR(*pte); + goto out; + } + flush_page_to_ram(page); + set_pte(pte, mk_pte(page, PAGE_GATE)); } - flush_page_to_ram(page); - set_pte(pte, mk_pte(page, PAGE_GATE)); + out: spin_unlock(&init_mm.page_table_lock); /* no need for flush_tlb */ return page; } void __init -ia64_rid_init (void) +ia64_mmu_init (void) { unsigned long flags, rid, pta, impl_va_bits; + extern void __init tlb_init (void); #ifdef CONFIG_DISABLE_VHPT # define VHPT_ENABLE_BIT 0 #else # define VHPT_ENABLE_BIT 1 #endif - /* Set up the kernel identity mappings (regions 6 & 7) and the vmalloc area (region 5): */ + /* + * Set up the kernel identity mapping for regions 6 and 5. The mapping for region + * 7 is setup up in _start(). + */ ia64_clear_ic(flags); rid = ia64_rid(IA64_REGION_ID_KERNEL, __IA64_UNCACHED_OFFSET); - ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (_PAGE_SIZE_256M << 2)); - - rid = ia64_rid(IA64_REGION_ID_KERNEL, PAGE_OFFSET); - ia64_set_rr(PAGE_OFFSET, (rid << 8) | (_PAGE_SIZE_256M << 2)); + ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (_PAGE_SIZE_64M << 2)); rid = ia64_rid(IA64_REGION_ID_KERNEL, VMALLOC_START); ia64_set_rr(VMALLOC_START, (rid << 8) | (PAGE_SHIFT << 2) | 1); + /* ensure rr6 is up-to-date before inserting the PERCPU_ADDR translation: */ + ia64_srlz_d(); + + ia64_itr(0x2, IA64_TR_PERCPU_DATA, PERCPU_ADDR, + pte_val(mk_pte_phys(__pa(&cpu_data[smp_processor_id()]), PAGE_KERNEL)), + PAGE_SHIFT); + __restore_flags(flags); + ia64_srlz_i(); /* * Check if the virtually mapped linear page table (VMLPT) overlaps with a mapped @@ -356,7 +283,7 @@ # define vmlpt_bits (impl_va_bits - PAGE_SHIFT + pte_bits) # define POW2(n) (1ULL << (n)) - impl_va_bits = ffz(~my_cpu_data.unimpl_va_mask); + impl_va_bits = ffz(~(local_cpu_data->unimpl_va_mask | (7UL << 61))); if (impl_va_bits < 51 || impl_va_bits > 61) panic("CPU has bogus IMPL_VA_MSB value of %lu!\n", impl_va_bits - 1); @@ -374,6 +301,8 @@ * enabled. */ ia64_set_pta(pta | (0 << 8) | (vmlpt_bits << 2) | VHPT_ENABLE_BIT); + + ia64_tlb_init(); } /* @@ -390,7 +319,7 @@ memset(zones_size, 0, sizeof(zones_size)); - max_dma = (PAGE_ALIGN(MAX_DMA_ADDRESS) >> PAGE_SHIFT); + max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; if (max_low_pfn < max_dma) zones_size[ZONE_DMA] = max_low_pfn; else { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/mm/tlb.c linux.ac/arch/ia64/mm/tlb.c --- linux.vanilla/arch/ia64/mm/tlb.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/mm/tlb.c Tue Apr 10 18:09:55 2001 @@ -1,11 +1,11 @@ /* * TLB support routines. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * - * 08/02/00 A. Mallick <asit.k.mallick@intel.com> - * Modified RID allocation for SMP + * 08/02/00 A. Mallick <asit.k.mallick@intel.com> + * Modified RID allocation for SMP * Goutham Rao <goutham.rao@intel.com> * IPI based ptc implementation and A-step IPI implementation. */ @@ -41,7 +41,7 @@ }; /* - * Seralize usage of ptc.g + * Seralize usage of ptc.g */ spinlock_t ptcg_lock = SPIN_LOCK_UNLOCKED; /* see <asm/pgtable.h> */ @@ -49,7 +49,7 @@ #include <linux/irq.h> -unsigned long flush_end, flush_start, flush_nbits, flush_rid; +unsigned long flush_end, flush_start, flush_nbits, flush_rid; atomic_t flush_cpu_count; /* @@ -71,7 +71,7 @@ if (!(flags & IA64_PSR_I)) { saved_tpr = ia64_get_tpr(); ia64_srlz_d(); - ia64_set_tpr(IPI_IRQ - 16); + ia64_set_tpr(IA64_IPI_VECTOR - 16); ia64_srlz_d(); local_irq_enable(); } @@ -97,13 +97,14 @@ /* * Wait for other CPUs to finish purging entries. */ -#if (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC)) +#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC) { + extern void smp_resend_flush_tlb (void); unsigned long start = ia64_get_itc(); + while (atomic_read(&flush_cpu_count) > 0) { - if ((ia64_get_itc() - start) > 40000UL) { - atomic_set(&flush_cpu_count, smp_num_cpus - 1); - smp_send_flush_tlb(); + if ((ia64_get_itc() - start) > 400000UL) { + smp_resend_flush_tlb(); start = ia64_get_itc(); } } @@ -148,7 +149,7 @@ if (tsk_context == ia64_ctx.next) { if (++ia64_ctx.next >= ia64_ctx.limit) { /* empty range: reset the range limit and start over */ - if (ia64_ctx.next > max_ctx) + if (ia64_ctx.next > max_ctx) ia64_ctx.next = 300; ia64_ctx.limit = max_ctx + 1; goto repeat; @@ -166,11 +167,11 @@ { unsigned long i, j, flags, count0, count1, stride0, stride1, addr; - addr = my_cpu_data.ptce_base; - count0 = my_cpu_data.ptce_count[0]; - count1 = my_cpu_data.ptce_count[1]; - stride0 = my_cpu_data.ptce_stride[0]; - stride1 = my_cpu_data.ptce_stride[1]; + addr = local_cpu_data->ptce_base; + count0 = local_cpu_data->ptce_count[0]; + count1 = local_cpu_data->ptce_count[1]; + stride0 = local_cpu_data->ptce_stride[0]; + stride1 = local_cpu_data->ptce_stride[1]; local_irq_save(flags); for (i = 0; i < count0; ++i) { @@ -249,11 +250,11 @@ ia64_ptce_info_t ptce_info; ia64_get_ptce(&ptce_info); - my_cpu_data.ptce_base = ptce_info.base; - my_cpu_data.ptce_count[0] = ptce_info.count[0]; - my_cpu_data.ptce_count[1] = ptce_info.count[1]; - my_cpu_data.ptce_stride[0] = ptce_info.stride[0]; - my_cpu_data.ptce_stride[1] = ptce_info.stride[1]; + local_cpu_data->ptce_base = ptce_info.base; + local_cpu_data->ptce_count[0] = ptce_info.count[0]; + local_cpu_data->ptce_count[1] = ptce_info.count[1]; + local_cpu_data->ptce_stride[0] = ptce_info.stride[0]; + local_cpu_data->ptce_stride[1] = ptce_info.stride[1]; __flush_tlb_all(); /* nuke left overs from bootstrapping... */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/Makefile linux.ac/arch/ia64/sn/Makefile --- linux.vanilla/arch/ia64/sn/Makefile Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/Makefile Tue Apr 10 18:09:55 2001 @@ -8,12 +8,11 @@ EXTRA_CFLAGS := -DSN -DLANGUAGE_C=1 -D_LANGUAGE_C=1 -I. -DBRINGUP \ -DDIRECT_L1_CONSOLE -DNUMA_BASE -DSIMULATED_KLGRAPH \ -DNUMA_MIGR_CONTROL -DLITTLE_ENDIAN -DREAL_HARDWARE \ - -DNEW_INTERRUPTS -DCONFIG_IA64_SGI_IO + -DNEW_INTERRUPTS all: sn.a O_TARGET = sn.a -O_HEADERS = -O_OBJS = sn1/sn1.a +obj-y = sn1/sn1.a clean:: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/fprom/Makefile linux.ac/arch/ia64/sn/fprom/Makefile --- linux.vanilla/arch/ia64/sn/fprom/Makefile Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/fprom/Makefile Tue Apr 10 18:09:55 2001 @@ -13,6 +13,7 @@ LIB = ../../lib/lib.a OBJ=fpromasm.o main.o fw-emu.o fpmem.o +obj-y=fprom fprom: $(OBJ) $(LD) -static -Tfprom.lds -o fprom $(OBJ) $(LIB) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/fprom/fw-emu.c linux.ac/arch/ia64/sn/fprom/fw-emu.c --- linux.vanilla/arch/ia64/sn/fprom/fw-emu.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/fprom/fw-emu.c Sat Apr 14 01:18:00 2001 @@ -8,6 +8,7 @@ * Copyright (C) 2000 Silicon Graphics, Inc. * Copyright (C) 2000 by Jack Steiner (steiner@sgi.com) */ + #include <asm/efi.h> #include <asm/pal.h> #include <asm/sal.h> @@ -62,6 +63,7 @@ func_ptr_t ap_entry; +static efi_runtime_services_t *efi_runtime_p; static char fw_mem[( sizeof(efi_system_table_t) + sizeof(efi_runtime_services_t) + NUM_EFI_DESCS*sizeof(efi_config_table_t) @@ -88,8 +90,8 @@ .text .proc pal_emulator_static pal_emulator_static: - mov r8=-1 - cmp.eq p6,p7=6,r28 /* PAL_PTCE_INFO */ + mov r8=-1;; + cmp.eq p6,p7=6,r28;; /* PAL_PTCE_INFO */ (p7) br.cond.sptk.few 1f ;; mov r8=0 /* status = 0 */ @@ -98,20 +100,20 @@ movl r11=0x1000000000002000 /* stride[0], stride[1] */ br.cond.sptk.few rp -1: cmp.eq p6,p7=14,r28 /* PAL_FREQ_RATIOS */ -(p7) br.cond.sptk.few 1f +1: cmp.eq p6,p7=14,r28;; /* PAL_FREQ_RATIOS */ +(p7) br.cond.sptk.few 1f;; mov r8=0 /* status = 0 */ movl r9 =0x100000064 /* proc_ratio (1/100) */ movl r10=0x100000100 /* bus_ratio<<32 (1/256) */ movl r11=0x10000000a /* itc_ratio<<32 (1/100) */ -1: cmp.eq p6,p7=22,r28 /* PAL_MC_DRAIN */ -(p7) br.cond.sptk.few 1f +1: cmp.eq p6,p7=22,r28;; /* PAL_MC_DRAIN */ +(p7) br.cond.sptk.few 1f;; mov r8=0 br.cond.sptk.few rp -1: cmp.eq p6,p7=23,r28 /* PAL_MC_EXPECTED */ -(p7) br.cond.sptk.few 1f +1: cmp.eq p6,p7=23,r28;; /* PAL_MC_EXPECTED */ +(p7) br.cond.sptk.few 1f;; mov r8=0 br.cond.sptk.few rp @@ -256,6 +258,36 @@ _fp->gp = __fwtab_pa(base_nasid, _fp->gp); } +void +fix_virt_function_pointer(void *fptr) +{ + func_ptr_t *fp; + + fp = fptr; + fp->pc = fp->pc | PAGE_OFFSET; + fp->gp = fp->gp | PAGE_OFFSET; +} + + +int +efi_set_virtual_address_map(void) +{ + efi_runtime_services_t *runtime; + + runtime = efi_runtime_p; + fix_virt_function_pointer((void*)runtime->get_time); + fix_virt_function_pointer((void*)runtime->set_time); + fix_virt_function_pointer((void*)runtime->get_wakeup_time); + fix_virt_function_pointer((void*)runtime->set_wakeup_time); + fix_virt_function_pointer((void*)runtime->set_virtual_address_map); + fix_virt_function_pointer((void*)runtime->get_variable); + fix_virt_function_pointer((void*)runtime->get_next_variable); + fix_virt_function_pointer((void*)runtime->set_variable); + fix_virt_function_pointer((void*)runtime->get_next_high_mono_count); + fix_virt_function_pointer((void*)runtime->reset_system); + return EFI_SUCCESS;; +} + void sys_fw_init (const char *args, int arglen, int bsp) @@ -305,7 +337,7 @@ cp = fw_mem; efi_systab = (void *) cp; cp += sizeof(*efi_systab); - efi_runtime = (void *) cp; cp += sizeof(*efi_runtime); + efi_runtime_p = efi_runtime = (void *) cp; cp += sizeof(*efi_runtime); efi_tables = (void *) cp; cp += NUM_EFI_DESCS*sizeof(*efi_tables); sal_systab = (void *) cp; cp += sizeof(*sal_systab); sal_ed = (void *) cp; cp += sizeof(*sal_ed); @@ -354,7 +386,7 @@ efi_runtime->set_time = __fwtab_pa(base_nasid, &efi_unimplemented); efi_runtime->get_wakeup_time = __fwtab_pa(base_nasid, &efi_unimplemented); efi_runtime->set_wakeup_time = __fwtab_pa(base_nasid, &efi_unimplemented); - efi_runtime->set_virtual_address_map = __fwtab_pa(base_nasid, &efi_success); + efi_runtime->set_virtual_address_map = __fwtab_pa(base_nasid, &efi_set_virtual_address_map); efi_runtime->get_variable = __fwtab_pa(base_nasid, &efi_unimplemented); efi_runtime->get_next_variable = __fwtab_pa(base_nasid, &efi_unimplemented); efi_runtime->set_variable = __fwtab_pa(base_nasid, &efi_unimplemented); @@ -370,10 +402,11 @@ fix_function_pointer(&efi_get_time); fix_function_pointer(&efi_success); fix_function_pointer(&efi_reset_system); + fix_function_pointer(&efi_set_virtual_address_map); /* fill in the ACPI system table: */ memcpy(acpi_systab->signature, "RSD PTR ", 8); - acpi_systab->rsdt = (acpi_rsdt_t*)__fwtab_pa(base_nasid, acpi_rsdt); + acpi_systab->rsdt = (struct acpi_rsdt*)__fwtab_pa(base_nasid, acpi_rsdt); memcpy(acpi_rsdt->header.signature, "RSDT",4); acpi_rsdt->header.length = sizeof(acpi_rsdt_t); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/Makefile linux.ac/arch/ia64/sn/io/Makefile --- linux.vanilla/arch/ia64/sn/io/Makefile Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/io/Makefile Tue Apr 10 18:09:55 2001 @@ -18,15 +18,15 @@ EXTRA_CFLAGS := -DSN -DLANGUAGE_C=1 -D_LANGUAGE_C=1 -I. -DBRINGUP \ -DDIRECT_L1_CONSOLE -DNUMA_BASE -DSIMULATED_KLGRAPH \ -DNUMA_MIGR_CONTROL -DLITTLE_ENDIAN -DREAL_HARDWARE \ - -DNEW_INTERRUPTS -DCONFIG_IA64_SGI_IO + -DNEW_INTERRUPTS O_TARGET := sgiio.o -O_OBJS := stubs.o sgi_if.o pciio.o pcibr.o xtalk.o xbow.o xswitch.o hubspc.o \ - klgraph_hack.o io.o hubdev.o \ +obj-y := stubs.o sgi_if.o pciio.o pcibr.o xtalk.o xbow.o xswitch.o hubspc.o \ + klgraph_hack.o io.o hubdev.o huberror.o \ hcl.o labelcl.o invent.o klgraph.o klconflib.o sgi_io_sim.o \ module.o sgi_io_init.o klgraph_hack.o ml_SN_init.o \ - ml_SN_intr.o ip37.o \ + ml_SN_intr.o ip37.o pciba.o \ ml_iograph.o hcl_util.o cdl.o \ mem_refcnt.o devsupport.o alenlist.o pci_bus_cvlink.o \ - eeprom.o pci.o pci_dma.o l1.o l1_command.o + eeprom.o pci.o pci_dma.o l1.o l1_command.o ate_utils.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/alenlist.c linux.ac/arch/ia64/sn/io/alenlist.c --- linux.vanilla/arch/ia64/sn/io/alenlist.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/alenlist.c Tue Apr 10 18:09:55 2001 @@ -201,8 +201,8 @@ int alenlist_count=0; /* Currently allocated Lists */ int alenlist_chunk_count = 0; /* Currently allocated chunks */ int alenlist_cursor_count = 0; /* Currently allocate cursors */ -#define INCR_COUNT(ptr) atomicAddInt((ptr), 1); -#define DECR_COUNT(ptr) atomicAddInt((ptr), -1); +#define INCR_COUNT(ptr) atomic_inc((ptr)); +#define DECR_COUNT(ptr) atomic_dec((ptr)); #else #define INCR_COUNT(ptr) #define DECR_COUNT(ptr) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/cdl.c linux.ac/arch/ia64/sn/io/cdl.c --- linux.vanilla/arch/ia64/sn/io/cdl.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/cdl.c Tue Apr 10 18:09:55 2001 @@ -67,7 +67,7 @@ void cdl_del(cdl_p reg) { - printk("SGI IO INFRASTRUCTURE - cdl_del not supported.\n"); + return; } /* @@ -77,7 +77,7 @@ Do nothing. */ int -cdl_add_driver(cdl_p reg, int key1, int key2, char *prefix, int flags) +cdl_add_driver(cdl_p reg, int key1, int key2, char *prefix, int flags, cdl_drv_f *func) { return 0; } @@ -86,11 +86,9 @@ * cdl_del_driver: Not supported. */ void -cdl_del_driver(cdl_p reg, - char *prefix) +cdl_del_driver(cdl_p reg, char *prefix, cdl_drv_f *func) { - - printk("SGI IO INFRASTRUCTURE - cdl_del_driver not supported.\n"); + return; } /* @@ -106,7 +104,7 @@ */ int cdl_add_connpt(cdl_p reg, int part_num, int mfg_num, - devfs_handle_t connpt) + devfs_handle_t connpt, int drv_flags) { int i; @@ -123,27 +121,12 @@ if (sgi_infrastructure_drivers[i].attach) { return(sgi_infrastructure_drivers[i].attach(connpt)); } -#ifdef BRINGUP - /* - * XXX HACK ALERT bypassing fops for now.. - */ - else { - printk("cdl_add_connpt: NEED FOPS FOR OUR DRIVERS!!\n"); - printk("cdl_add_connpt: part_num= 0x%x mfg_num= 0x%x\n", - part_num, mfg_num); - return(-1); - } -#endif /* BRINGUP */ } else { continue; } - - printk("**** cdl_add_connpt: driver not found for part_num %d mfg_num %d ****\n", part_num, mfg_num); - - return(-1); } - if ( (i == MAX_SGI_IO_INFRA_DRVR) ) - printk("**** cdl_add_connpt: Driver not found for part_num 0x%x mfg_num 0x%x ****\n", part_num, mfg_num); + + /* printk("WARNING: cdl_add_connpt: Driver not found for part_num 0x%x mfg_num 0x%x\n", part_num, mfg_num); */ return (0); } @@ -151,11 +134,11 @@ /* * cdl_del_connpt: Not implemented. */ -void -cdl_del_connpt(cdl_p reg, int key1, int key2, devfs_handle_t connpt) +int +cdl_del_connpt(cdl_p reg, int key1, int key2, devfs_handle_t connpt, int drv_flags) { - printk("SGI IO INFRASTRUCTURE - cdl_del_cdl_del_connpt not supported.\n"); + return(0); } /* @@ -166,65 +149,54 @@ char *prefix, cdl_iter_f * func) { - - printk("SGI IO INFRASTRUCTURE - cdl_iterate not supported.\n"); + return; } async_attach_t async_attach_new(void) { - printk("SGI IO INFRASTRUCTURE - async_attach_new not supported.\n"); return(0); } void async_attach_free(async_attach_t aa) { - printk("SGI IO INFRASTRUCTURE - async_attach_free not supported.\n"); + return; } async_attach_t async_attach_get_info(devfs_handle_t vhdl) { - printk("SGI IO INFRASTRUCTURE - async_attach_get_info not supported.\n"); return(0); } void async_attach_add_info(devfs_handle_t vhdl, async_attach_t aa) { - printk("SGI IO INFRASTRUCTURE - async_attach_add_info not supported.\n"); + return; } void async_attach_del_info(devfs_handle_t vhdl) { - - printk("SGI IO INFRASTRUCTURE - async_attach_del_info not supported.\n"); - + return; } void async_attach_signal_start(async_attach_t aa) { - - printk("SGI IO INFRASTRUCTURE - async_attach_signal_start not supported.\n"); - + return; } void async_attach_signal_done(async_attach_t aa) { - - printk("SGI IO INFRASTRUCTURE - async_attach_signal_done not supported.\n"); - + return; } void async_attach_waitall(async_attach_t aa) { - - printk("SGI IO INFRASTRUCTURE - async_attach_waitall not supported.\n"); - + return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/devsupport.c linux.ac/arch/ia64/sn/io/devsupport.c --- linux.vanilla/arch/ia64/sn/io/devsupport.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/devsupport.c Tue Apr 10 18:09:55 2001 @@ -1,5 +1,3 @@ -#define ilvt_t int - /* $Id$ * * This file is subject to the terms and conditions of the GNU General Public @@ -28,7 +26,7 @@ /* =====Generic iobus support===== */ /* String table to hold names of interrupts. */ -#ifdef notyet +#ifdef LATER static struct string_table device_desc_string_table; #endif @@ -36,7 +34,7 @@ static void device_desc_init(void) { -#ifdef notyet +#ifdef LATER string_table_init(&device_desc_string_table); #endif FIXME("device_desc_init"); @@ -47,7 +45,7 @@ static device_desc_t device_desc_alloc(void) { -#ifdef notyet +#ifdef LATER device_desc_t device_desc; device_desc = (device_desc_t)kmem_zalloc(sizeof(struct device_desc_s), 0); @@ -69,7 +67,7 @@ void device_desc_free(device_desc_t device_desc) { -#ifdef notyet +#ifdef LATER if (!(device_desc->flags & D_IS_ASSOC)) /* sanity */ kfree(device_desc); #endif @@ -79,7 +77,7 @@ device_desc_t device_desc_dup(devfs_handle_t dev) { -#ifdef notyet +#ifdef LATER device_desc_t orig_device_desc, new_device_desc; @@ -111,7 +109,7 @@ device_desc_t device_desc_default_get(devfs_handle_t dev) { -#ifdef notyet +#ifdef LATER graph_error_t rc; device_desc_t device_desc; @@ -130,7 +128,7 @@ void device_desc_default_set(devfs_handle_t dev, device_desc_t new_device_desc) { -#ifdef notyet +#ifdef LATER graph_error_t rc; device_desc_t old_device_desc = NULL; @@ -164,7 +162,7 @@ devfs_handle_t device_desc_intr_target_get(device_desc_t device_desc) { -#ifdef notyet +#ifdef LATER return(device_desc->intr_target); #else FIXME("device_desc_intr_target_get"); @@ -175,7 +173,7 @@ int device_desc_intr_policy_get(device_desc_t device_desc) { -#ifdef notyet +#ifdef LATER return(device_desc->intr_policy); #else FIXME("device_desc_intr_policy_get"); @@ -186,7 +184,7 @@ ilvl_t device_desc_intr_swlevel_get(device_desc_t device_desc) { -#ifdef notyet +#ifdef LATER return(device_desc->intr_swlevel); #else FIXME("device_desc_intr_swlevel_get"); @@ -197,7 +195,7 @@ char * device_desc_intr_name_get(device_desc_t device_desc) { -#ifdef notyet +#ifdef LATER return(device_desc->intr_name); #else FIXME("device_desc_intr_name_get"); @@ -208,7 +206,7 @@ int device_desc_flags_get(device_desc_t device_desc) { -#ifdef notyet +#ifdef LATER return(device_desc->flags); #else FIXME("device_desc_flags_get"); @@ -240,7 +238,7 @@ void device_desc_intr_name_set(device_desc_t device_desc, char *name) { -#ifdef notyet +#ifdef LATER if ( device_desc != (device_desc_t)0 ) device_desc->intr_name = string_table_insert(&device_desc_string_table, name); #else @@ -325,7 +323,7 @@ static void dev_admin_registry_init(dev_admin_registry_t *registry) { -#ifdef notyet +#ifdef LATER if ( registry != (dev_admin_registry_t *)0 ) DEV_ADMIN_REGISTRY_INITLOCK(®istry->reg_lock, "dev_admin_registry_lock"); @@ -349,7 +347,7 @@ char *name, char *val) { -#ifdef notyet +#ifdef LATER dev_admin_list_t *reg_entry; dev_admin_list_t *scan = 0; @@ -404,7 +402,7 @@ static char * dev_admin_registry_find(dev_admin_registry_t *registry,char *name) { -#ifdef notyet +#ifdef LATER dev_admin_list_t *scan = 0; DEV_ADMIN_REGISTRY_RDLOCK(®istry->reg_lock); @@ -433,7 +431,7 @@ device_admin_info_get(devfs_handle_t dev_vhdl, char *info_lbl) { -#ifdef notyet +#ifdef LATER char *info = 0; /* return value need not be GRAPH_SUCCESS as the labelled @@ -460,7 +458,7 @@ char *dev_info_lbl, char *dev_info_val) { -#ifdef notyet +#ifdef LATER graph_error_t rv; arbitrary_info_t old_info; @@ -570,7 +568,7 @@ device_driver_admin_info_get(char *driver_prefix, char *driver_info_lbl) { -#ifdef notyet +#ifdef LATER device_driver_t driver; driver = device_driver_get(driver_prefix); @@ -592,7 +590,7 @@ char *driver_info_lbl, char *driver_info_val) { -#ifdef notyet +#ifdef LATER device_driver_t driver; driver = device_driver_get(driver_prefix); @@ -623,7 +621,7 @@ void device_admin_table_init(void) { -#ifdef notyet +#ifdef LATER extended_dev_admin_table_size = 0; mrinit(&extended_dev_admin_table_lock, "extended_dev_admin_table_lock"); @@ -638,7 +636,7 @@ void device_admin_table_update(char *name,char *label,char *value) { -#ifdef notyet +#ifdef LATER dev_admin_info_t *p; mrupdate(&extended_dev_admin_table_lock); @@ -678,7 +676,7 @@ void device_driver_admin_table_init(void) { -#ifdef notyet +#ifdef LATER extended_drv_admin_table_size = 0; mrinit(&extended_drv_admin_table_lock, "extended_drv_admin_table_lock"); @@ -693,7 +691,7 @@ void device_driver_admin_table_update(char *name,char *label,char *value) { -#ifdef notyet +#ifdef LATER dev_admin_info_t *p; mrupdate(&extended_dev_admin_table_lock); @@ -730,7 +728,7 @@ void device_admin_info_update(devfs_handle_t dev_vhdl) { -#ifdef notyet +#ifdef LATER int i = 0; dev_admin_info_t *scan; devfs_handle_t scan_vhdl; @@ -779,7 +777,7 @@ void device_driver_admin_info_update(device_driver_t driver) { -#ifdef notyet +#ifdef LATER int i = 0; dev_admin_info_t *scan; @@ -823,7 +821,7 @@ */ #define DEVICE_DRIVER_HASH_SIZE 32 -#ifdef notyet +#ifdef LATER lock_t device_driver_lock[DEVICE_DRIVER_HASH_SIZE]; device_driver_t device_driver_hash[DEVICE_DRIVER_HASH_SIZE]; static struct string_table driver_prefix_string_table; @@ -835,7 +833,7 @@ void device_driver_init(void) { -#ifdef notyet +#ifdef LATER int i; extern void alenlist_init(void); extern void hwgraph_init(void); @@ -849,7 +847,7 @@ string_table_init(&driver_prefix_string_table); for (i=0; i<DEVICE_DRIVER_HASH_SIZE; i++) { - spinlock_init(&device_driver_lock[i], "devdrv"); + spin_lock_init(&device_driver_lock[i]); device_driver_hash[i] = NULL; } @@ -877,7 +875,7 @@ static int driver_prefix_hash(char *prefix) { -#ifdef notyet +#ifdef LATER int accum = 0; char nextchar; @@ -903,10 +901,10 @@ device_driver_t device_driver_alloc(char *prefix) { -#ifdef notyet +#ifdef LATER int which_hash; device_driver_t new_driver; - int s; + unsigned long s; which_hash = driver_prefix_hash(prefix); @@ -964,9 +962,9 @@ void device_driver_free(device_driver_t driver) { -#ifdef notyet +#ifdef LATER int which_hash; - int s; + unsigned long s; if (!driver) return; @@ -1027,10 +1025,10 @@ device_driver_t device_driver_get(char *prefix) { -#ifdef notyet +#ifdef LATER int which_hash; device_driver_t drvscan; - int s; + unsigned long s; if (prefix == NULL) return(NULL); @@ -1060,7 +1058,7 @@ device_driver_t device_driver_getbydev(devfs_handle_t device) { -#ifdef notyet +#ifdef LATER struct bdevsw *my_bdevsw; struct cdevsw *my_cdevsw; @@ -1093,7 +1091,7 @@ struct bdevsw *my_bdevsw, struct cdevsw *my_cdevsw) { -#ifdef notyet +#ifdef LATER int i; if (!driver) @@ -1194,7 +1192,7 @@ void device_info_set(devfs_handle_t device, void *info) { -#ifdef notyet +#ifdef LATER hwgraph_fastinfo_set(device, (arbitrary_info_t)info); #endif FIXME("device_info_set"); @@ -1207,7 +1205,7 @@ void * device_info_get(devfs_handle_t device) { -#ifdef notyet +#ifdef LATER return((void *)hwgraph_fastinfo_get(device)); #else FIXME("device_info_get"); @@ -1222,7 +1220,7 @@ int device_driver_sysgen_thread_pri_get(char *dev_prefix) { -#ifdef notyet +#ifdef LATER int pri; char *pri_s; char *class; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/eeprom.c linux.ac/arch/ia64/sn/io/eeprom.c --- linux.vanilla/arch/ia64/sn/io/eeprom.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/io/eeprom.c Tue Apr 10 18:09:55 2001 @@ -53,7 +53,6 @@ #include <asm/sn/labelcl.h> #include <asm/sn/eeprom.h> #include <asm/sn/ksys/i2c.h> -#include <asm/sn/cmn_err.h> /* #include <sys/SN/SN1/ip27log.h> */ #include <asm/sn/router.h> #include <asm/sn/module.h> @@ -949,6 +948,7 @@ #else char msg[BRL1_QSIZE]; /* message buffer */ int len; /* number of bytes used in message buffer */ + int resp; /* l1 response code */ int spd_len = EEPROM_CHUNKSIZE; /* remaining bytes in spd record */ int offset = 0; /* current offset into spd record */ char *spd_p = spd->bytes; /* "thumb" for writing to spd */ @@ -981,11 +981,26 @@ } /* check response */ - if( sc_interpret_resp( msg, 5, + if( (resp = sc_interpret_resp( msg, 5, L1_ARG_INT, &spd_len, - L1_ARG_UNKNOWN, &len, spd_p ) < 0 ) + L1_ARG_UNKNOWN, &len, spd_p )) < 0 ) { - return( EEP_L1 ); + /* + * translate l1 response code to eeprom.c error codes: + * The L1 response will be L1_RESP_NAVAIL if the spd + * can't be read (i.e. the spd isn't physically there). It will + * return L1_RESP_INVAL if the spd exists, but fails the checksum + * test because the eeprom wasn't programmed, programmed incorrectly, + * or corrupted. L1_RESP_NAVAIL indicates the eeprom is likely not present, + * whereas L1_RESP_INVAL indicates the eeprom is present, but the data is + * invalid. + */ + if(resp == L1_RESP_INVAL) { + resp = EEP_BAD_CHECKSUM; + } else { + resp = EEP_L1; + } + return( resp ); } if( spd_len > EEPROM_CHUNKSIZE ) @@ -1201,7 +1216,9 @@ #else int r; uint64_t uid = 0; +#ifdef LOG_GETENV char uid_str[32]; +#endif int l1_compt, subch; if ( IS_RUNNING_ON_SIMULATOR() ) @@ -1228,6 +1245,13 @@ if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 ) return EEP_L1; + if((component & C_DIMM) == C_DIMM) { + l1_compt = L1_EEP_DIMM(component & COMPT_MASK); + r = read_spd(scp,subch,l1_compt, buf->spd); + sc_close(scp,subch); + return(r); + } + switch( component ) { case C_BRICK: @@ -1252,13 +1276,6 @@ l1_compt = L1_EEP_PIMM( component & COMPT_MASK ); break; - case C_DIMM: - /* one of the DIMMs */ - l1_compt = L1_EEP_DIMM( component & COMPT_MASK ); - r = read_spd( scp, subch, l1_compt, buf->spd ); - sc_close( scp, subch ); - return r; - default: /* unsupported board type */ sc_close( scp, subch ); @@ -1297,8 +1314,7 @@ scp = get_l1sc(); } else { - elsc_t *get_elsc(void); - scp = get_elsc(); + scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; } return _cbrick_eeprom_read( buf, scp, component ); @@ -1333,8 +1349,7 @@ scp = get_l1sc(); } else { - elsc_t *get_elsc(void); - scp = get_elsc(); + scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; } if( (subch = sc_open( scp, L1_ADDR_LOCALIO )) < 0 ) @@ -1350,9 +1365,11 @@ if( r != EEP_OK ) { sc_close( scp, subch ); -#ifdef BRINGUP /* Once EEPROMs are universally available, remove this */ + /* + * Whenever we no longer need to test on hardware + * that does not have EEPROMS, then this can be removed. + */ r = fake_an_eeprom_record( buf, component, rtc_time() ); -#endif /* BRINGUP */ return r; } break; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/hcl.c linux.ac/arch/ia64/sn/io/hcl.c --- linux.vanilla/arch/ia64/sn/io/hcl.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/io/hcl.c Tue Apr 10 18:09:55 2001 @@ -30,6 +30,7 @@ #define HCL_TEMP_NAME_LEN 44 #define HCL_VERSION "1.0" devfs_handle_t hwgraph_root = NULL; +devfs_handle_t linux_busnum = NULL; /* * Debug flag definition. @@ -41,7 +42,9 @@ static unsigned int hcl_debug_init __initdata = HCL_DEBUG_NONE; #endif static unsigned int hcl_debug = HCL_DEBUG_NONE; +#if defined(CONFIG_HCL_DEBUG) && !defined(MODULE) static unsigned int boot_options = OPTION_NONE; +#endif /* * Some Global definitions. @@ -49,6 +52,12 @@ spinlock_t hcl_spinlock; devfs_handle_t hcl_handle = NULL; +invplace_t invplace_none = { + GRAPH_VERTEX_NONE, + GRAPH_VERTEX_PLACE_NONE, + NULL +}; + /* * HCL device driver. * The purpose of this device driver is to provide a facility @@ -98,6 +107,7 @@ } struct file_operations hcl_fops = { + (struct module *)0, NULL, /* lseek - default */ NULL, /* read - general block-dev read */ NULL, /* write - general block-dev write */ @@ -110,9 +120,9 @@ hcl_close, /* release */ NULL, /* fsync */ NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ - NULL /* lock */ + NULL, /* lock */ + NULL, /* readv */ + NULL, /* writev */ }; @@ -134,13 +144,15 @@ extern struct string_table label_string_table; int rv = 0; +#if defined(CONFIG_HCL_DEBUG) && !defined(MODULE) printk ("\n%s: v%s Colin Ngam (cngam@sgi.com)\n", HCL_NAME, HCL_VERSION); -#if defined(CONFIG_HCL_DEBUG) && !defined(MODULE) + hcl_debug = hcl_debug_init; printk ("%s: hcl_debug: 0x%0x\n", HCL_NAME, hcl_debug); -#endif printk ("\n%s: boot_options: 0x%0x\n", HCL_NAME, boot_options); +#endif + spin_lock_init(&hcl_spinlock); /* @@ -148,7 +160,7 @@ */ rv = hwgraph_path_add(NULL, "hw", &hwgraph_root); if (rv) - printk ("init_hcl: Failed to create hwgraph_root. Error = %d.\n", rv); + printk ("WARNING: init_hcl: Failed to create hwgraph_root. Error = %d.\n", rv); /* * Create the hcl driver to support inventory entry manipulations. @@ -171,6 +183,15 @@ */ string_table_init(&label_string_table); + /* + * Create the directory that links Linux bus numbers to our Xwidget. + */ + rv = hwgraph_path_add(hwgraph_root, "linux/busnum", &linux_busnum); + if (linux_busnum == NULL) { + panic("HCL: Unable to create hw/linux/busnum\n"); + return(0); + } + return(0); } @@ -190,7 +211,6 @@ { while ( (*str != '\0') && !isspace (*str) ) { - printk("HCL: Boot time parameter %s\n", str); #ifdef CONFIG_HCL_DEBUG if (strncmp (str, "all", 3) == 0) { hcl_debug_init |= HCL_DEBUG_ALL; @@ -445,7 +465,7 @@ /* * We need to clean up! */ - printk("HCL: Unable to set the connect point to it's parent 0x%p\n", + printk(KERN_WARNING "HCL: Unable to set the connect point to it's parent 0x%p\n", new_devfs_handle); } @@ -561,19 +581,44 @@ { char *path; + char *s1; + char *index; int name_start; devfs_handle_t handle = NULL; int rv; + int i, count; path = kmalloc(1024, GFP_KERNEL); + memset(path, 0x0, 1024); + name_start = devfs_generate_path (from, path, 1024); + s1 = &path[name_start]; + count = 0; + while (1) { + index = strstr (s1, "/"); + if (index) { + count++; + s1 = ++index; + } else { + count++; + break; + } + } + + memset(path, 0x0, 1024); name_start = devfs_generate_path (to, path, 1024); + for (i = 0; i < count; i++) { + strcat(path,"../"); + } + + strcat(path, &path[name_start]); + /* * Otherwise, just create a symlink to the vertex. * In this case the vertex was previous created with a REAL pathname. */ rv = devfs_mk_symlink (from, (const char *)name, - DEVFS_FL_DEFAULT, (const char *)&path[name_start], + DEVFS_FL_DEFAULT, path, &handle, NULL); name_start = devfs_generate_path (handle, path, 1024); @@ -744,7 +789,6 @@ *placeptr = which_place + 1; if (curr && name) { tempname = devfs_get_name(*target, &namelen); - printk("hwgraph_edge_get_next: Component name = %s, length = %d\n", tempname, namelen); if (tempname && namelen) strcpy(name, tempname); } @@ -1335,7 +1379,7 @@ return(DEVNAME_UNKNOWN); } -#ifdef IRIX +#ifdef LATER /* ** Return the compact node id of the node that ultimately "owns" the specified ** vertex. In order to do this, we walk back through masters and connect points @@ -1440,7 +1484,7 @@ return (mem_vhdl); } -#endif /* IRIX */ +#endif /* LATER */ /* @@ -1454,7 +1498,7 @@ { devfs_handle_t xx = NULL; - printk("FIXME: hwgraph_char_device_add() called. Use hwgraph_register.\n"); + printk("WARNING: hwgraph_char_device_add() not supported .. use hwgraph_register.\n"); *devhdl = xx; // Must set devhdl return(GRAPH_SUCCESS); } @@ -1462,14 +1506,13 @@ graph_error_t hwgraph_edge_remove(devfs_handle_t from, char *name, devfs_handle_t *toptr) { - printk("FIXME: hwgraph_edge_remove\n"); + printk("WARNING: hwgraph_edge_remove NOT supported.\n"); return(GRAPH_ILLEGAL_REQUEST); } graph_error_t hwgraph_vertex_unref(devfs_handle_t vhdl) { - printk("FIXME: hwgraph_vertex_unref\n"); return(GRAPH_ILLEGAL_REQUEST); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/hcl_util.c linux.ac/arch/ia64/sn/io/hcl_util.c --- linux.vanilla/arch/ia64/sn/io/hcl_util.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/hcl_util.c Tue Apr 10 18:09:55 2001 @@ -137,6 +137,20 @@ } } +/* +** If the specified device represents a CPU, return its cpuid; +** otherwise, return CPU_NONE. +*/ +cpuid_t +cpuvertex_to_cpuid(devfs_handle_t vhdl) +{ + arbitrary_info_t cpuid = CPU_NONE; + + (void)labelcl_info_get_LBL(vhdl, INFO_LBL_CPUID, NULL, &cpuid); + + return((cpuid_t)cpuid); +} + /* ** dev_to_name converts a devfs_handle_t into a canonical name. If the devfs_handle_t diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/hubdev.c linux.ac/arch/ia64/sn/io/hubdev.c --- linux.vanilla/arch/ia64/sn/io/hubdev.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/hubdev.c Tue Apr 10 18:09:55 2001 @@ -31,7 +31,7 @@ void hubdev_init(void) { - mutex_init(&hubdev_callout_mutex, MUTEX_DEFAULT, "hubdev"); + mutex_init(&hubdev_callout_mutex); hubdev_callout_list = NULL; } @@ -45,9 +45,9 @@ callout = (hubdev_callout_t *)kmem_zalloc(sizeof(hubdev_callout_t), KM_SLEEP); ASSERT(callout); - mutex_lock(&hubdev_callout_mutex, PZERO); + mutex_lock(&hubdev_callout_mutex); /* - * Insert at the front of the list + * Insert at the end of the list */ callout->fp = hubdev_callout_list; hubdev_callout_list = callout; @@ -62,7 +62,7 @@ ASSERT(attach_method); - mutex_lock(&hubdev_callout_mutex, PZERO); + mutex_lock(&hubdev_callout_mutex); /* * Remove registry element containing attach_method */ @@ -86,7 +86,7 @@ hubdev_callout_t *p; int errcode; - mutex_lock(&hubdev_callout_mutex, PZERO); + mutex_lock(&hubdev_callout_mutex); for (p = hubdev_callout_list; p != NULL; p = p->fp) { ASSERT(p->attach_method); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/huberror.c linux.ac/arch/ia64/sn/io/huberror.c --- linux.vanilla/arch/ia64/sn/io/huberror.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ia64/sn/io/huberror.c Tue Apr 10 18:09:55 2001 @@ -0,0 +1,475 @@ +/* $Id$ + * + * 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) 1992 - 1997, 2000 Silicon Graphics, Inc. + * Copyright (C) 2000 by Alan Mayer + */ + + +#include <linux/types.h> +#include <linux/slab.h> +#include <asm/smp.h> +#include <asm/sn/sgi.h> +#include <asm/sn/iograph.h> +#include <asm/sn/invent.h> +#include <asm/sn/hcl.h> +#include <asm/sn/labelcl.h> +#include <asm/sn/nodemask.h> +#include <asm/sn/sn_private.h> +#include <asm/sn/klconfig.h> +#include <asm/sn/synergy.h> +#include <asm/sn/sn_cpuid.h> +#include <asm/sn/pci/pciio.h> +#include <asm/sn/pci/pcibr.h> +#include <asm/sn/xtalk/xtalk.h> +#include <asm/sn/pci/pcibr_private.h> +#include <asm/sn/intr.h> + +extern void hubni_eint_init(cnodeid_t cnode); +extern void hubii_eint_init(cnodeid_t cnode); +extern void hubii_eint_handler (int irq, void *arg, struct pt_regs *ep); +extern void snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs); + +extern int maxcpus; + +#define HUB_ERROR_PERIOD (120 * HZ) /* 2 minutes */ + + +void +hub_error_clear(nasid_t nasid) +{ + int i; + hubreg_t idsr; + int sn; + + for(sn=0; sn<NUM_SUBNODES; sn++) { + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_PEND, -1); + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_STATUS0_A_CLR, -1); + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_STATUS0_B_CLR, -1); + REMOTE_HUB_PI_S(nasid, sn, PI_SPURIOUS_HDR_0, 0); + REMOTE_HUB_PI_S(nasid, sn, PI_SPURIOUS_HDR_1, 0); + } + + REMOTE_HUB_L(nasid, MD_DIR_ERROR_CLR); + REMOTE_HUB_L(nasid, MD_MEM_ERROR_CLR); + REMOTE_HUB_L(nasid, MD_MISC1_ERROR_CLR); + REMOTE_HUB_L(nasid, MD_PROTOCOL_ERR_CLR); + + /* + * Make sure spurious write response errors are cleared + * (values are from hub_set_prb()) + */ + for (i = 0; i <= HUB_WIDGET_ID_MAX - HUB_WIDGET_ID_MIN + 1; i++) { + iprb_t prb; + + prb.iprb_regval = REMOTE_HUB_L(nasid, IIO_IOPRB_0 + (i * sizeof(hubreg_t))); + + /* Clear out some fields */ + prb.iprb_ovflow = 1; + prb.iprb_bnakctr = 0; + prb.iprb_anakctr = 0; + + /* + * PIO reads in fire-and-forget mode on bedrock 1.0 don't + * frob the credit count properly, making the responses appear + * spurious. So don't use fire-and-forget mode. Bug 761802. + */ + prb.iprb_ff = 0; /* disable fire-and-forget mode by default */ + + prb.iprb_xtalkctr = 3; /* approx. PIO credits for the widget */ + + REMOTE_HUB_S(nasid, IIO_IOPRB_0 + (i * sizeof(hubreg_t)), prb.iprb_regval); + } + + REMOTE_HUB_S(nasid, IIO_IO_ERR_CLR, -1); + idsr = REMOTE_HUB_L(nasid, IIO_IIDSR); + REMOTE_HUB_S(nasid, IIO_IIDSR, (idsr & ~(IIO_IIDSR_SENT_MASK))); + + REMOTE_HUB_L(nasid, NI_PORT_ERROR_CLEAR); + /* No need to clear NI_PORT_HEADER regs; they are continually overwritten*/ + + REMOTE_HUB_S(nasid, LB_ERROR_MASK_CLR, -1); + REMOTE_HUB_S(nasid, LB_ERROR_HDR1, 0); + + /* Clear XB error regs, in order */ + for (i = 0; + i <= XB_FIRST_ERROR_CLEAR - XB_POQ0_ERROR_CLEAR; + i += sizeof(hubreg_t)) { + REMOTE_HUB_S(nasid, XB_POQ0_ERROR_CLEAR + i, 0); + } +} + + +/* + * Function : hub_error_init + * Purpose : initialize the error handling requirements for a given hub. + * Parameters : cnode, the compact nodeid. + * Assumptions : Called only once per hub, either by a local cpu. Or by a + * remote cpu, when this hub is headless.(cpuless) + * Returns : None + */ + +void +hub_error_init(cnodeid_t cnode) +{ + nasid_t nasid; + + nasid = cnodeid_to_nasid(cnode); + hub_error_clear(nasid); + +#ifdef ajm + if (cnode == 0) { + /* + * Allocate log for storing the node specific error info + */ + for (i = 0; i < numnodes; i++) { + kl_error_log[i] = kmem_zalloc_node(sizeof(sn0_error_log_t), + KM_NOSLEEP, i); + hub_err_count[i] = kmem_zalloc_node(sizeof(hub_errcnt_t), + VM_DIRECT | KM_NOSLEEP, i); + ASSERT_ALWAYS(kl_error_log[i] && hub_err_count[i]); + } + } + + /* + * Assumption: There will be only one cpu who will initialize + * a hub. we need to setup the ii and each pi error interrupts. + * The SN1 hub (bedrock) has two PI, one for up to two processors. + */ + + if (cpuid_to_cnodeid(smp_processor_id()) == cnode) { + int generic_intr_mask = PI_ERR_GENERIC; /* These interrupts are sent to only 1 CPU per NODE */ + + ASSERT_ALWAYS(kl_error_log[cnode]); + ASSERT_ALWAYS(hub_err_count[cnode]); + MD_ERR_LOG_INIT(kl_error_log[cnode]); + + /* One for each CPU */ + recover_error_init(RECOVER_ERROR_TABLE(cnode, 0)); + recover_error_init(RECOVER_ERROR_TABLE(cnode, 1)); + recover_error_init(RECOVER_ERROR_TABLE(cnode, 2)); + recover_error_init(RECOVER_ERROR_TABLE(cnode, 3)); + + /* + * Setup error intr masks. + */ + for(sn=0; sn<NUM_SUBNODES; sn++) { + int cpuA_present = REMOTE_HUB_PI_L(nasid, sn, PI_CPU_ENABLE_A); + int cpuB_present = REMOTE_HUB_PI_L(nasid, sn, PI_CPU_ENABLE_B); + + if (cpuA_present) { + if (cpuB_present) { /* A && B */ + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_A, + (PI_FATAL_ERR_CPU_B | PI_MISC_ERR_CPU_A|generic_intr_mask)); + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_B, + (PI_FATAL_ERR_CPU_A | PI_MISC_ERR_CPU_B)); + + } else { /* A && !B */ + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_A, + (PI_FATAL_ERR_CPU_A | PI_MISC_ERR_CPU_A|generic_intr_mask)); + } + generic_intr_mask = 0; + } else { + if (cpuB_present) { /* !A && B */ + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_B, + (PI_FATAL_ERR_CPU_B | PI_MISC_ERR_CPU_B|generic_intr_mask)); + generic_intr_mask = 0; + + } else { /* !A && !B */ + /* nothing to set up */ + } + } + } + + /* + * Turn off UNCAC_UNCORR interrupt in the masks. Anyone interested + * in these errors will peek at the int pend register to see if its + * set. + */ + for(sn=0; sn<NUM_SUBNODES; sn++) { + misc = REMOTE_HUB_PI_L(nasid, sn, PI_ERR_INT_MASK_A); + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_A, (misc & ~PI_ERR_UNCAC_UNCORR_A)); + misc = REMOTE_HUB_PI_L(nasid, sn, PI_ERR_INT_MASK_B); + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_B, (misc & ~PI_ERR_UNCAC_UNCORR_B)); + } + + /* + * enable all error indicators to turn on, in case of errors. + * + * This is not good on single cpu node boards. + **** LOCAL_HUB_S(PI_SYSAD_ERRCHK_EN, PI_SYSAD_CHECK_ALL); + */ + for(sn=0; sn<NUM_SUBNODES; sn++) { + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_STATUS1_A_CLR, 0); + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_STATUS1_B_CLR, 0); + } + + /* Set up stack for each present processor */ + for(sn=0; sn<NUM_SUBNODES; sn++) { + if (REMOTE_HUB_PI_L(nasid, sn, PI_CPU_PRESENT_A)) { + SN0_ERROR_LOG(cnode)->el_spool_cur_addr[0] = + SN0_ERROR_LOG(cnode)->el_spool_last_addr[0] = + REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_A); + } + + if (REMOTE_HUB_PI_L(nasid, sn, PI_CPU_PRESENT_B)) { + SN0_ERROR_LOG(cnode)->el_spool_cur_addr[1] = + SN0_ERROR_LOG(cnode)->el_spool_last_addr[1] = + REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_B); + } + } + + + PI_SPOOL_SIZE_BYTES = + ERR_STACK_SIZE_BYTES(REMOTE_HUB_L(nasid, PI_ERR_STACK_SIZE)); + +#ifdef BRINGUP +/* BRINGUP: The following code looks like a check to make sure +the prom set up the error spool correctly for 2 processors. I +don't think it is needed. */ + for(sn=0; sn<NUM_SUBNODES; sn++) { + if (REMOTE_HUB_PI_L(nasid, sn, PI_CPU_PRESENT_B)) { + __psunsigned_t addr_a = REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_A); + __psunsigned_t addr_b = REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_B); + if ((addr_a & ~0xff) == (addr_b & ~0xff)) { + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_STACK_ADDR_B, + addr_b + PI_SPOOL_SIZE_BYTES); + + SN0_ERROR_LOG(cnode)->el_spool_cur_addr[1] = + SN0_ERROR_LOG(cnode)->el_spool_last_addr[1] = + REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_B); + + } + } + } +#endif /* BRINGUP */ + + /* programming our own hub. Enable error_int_pend intr. + * If both present, CPU A takes CPU b's error interrupts and any + * generic ones. CPU B takes CPU A error ints. + */ + if (cause_intr_connect (SRB_ERR_IDX, + (intr_func_t)(hubpi_eint_handler), + SR_ALL_MASK|SR_IE)) { + cmn_err(ERR_WARN, + "hub_error_init: cause_intr_connect failed on %d", cnode); + } + } + else { + /* programming remote hub. The only valid reason that this + * is called will be on headless hubs. No interrupts + */ + for(sn=0; sn<NUM_SUBNODES; sn++) { + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_A, 0); /* not necessary */ + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_B, 0); /* not necessary */ + } + } +#endif /* ajm */ + /* + * Now setup the hub ii and ni error interrupt handler. + */ + + hubii_eint_init(cnode); + hubni_eint_init(cnode); + +#ifdef ajm + /*** XXX FIXME XXX resolve the following***/ + /* INT_PEND1 bits set up for one hub only: + * SHUTDOWN_INTR + * MD_COR_ERR_INTR + * COR_ERR_INTR_A and COR_ERR_INTR_B should be sent to the + * appropriate CPU only. + */ + + if (cnode == 0) { + error_consistency_check.eps_state = 0; + error_consistency_check.eps_cpuid = -1; + spinlock_init(&error_consistency_check.eps_lock, "error_dump_lock"); + } +#endif + + nodepda->huberror_ticks = HUB_ERROR_PERIOD; + return; +} + +/* + * Function : hubii_eint_init + * Parameters : cnode + * Purpose : to initialize the hub iio error interrupt. + * Assumptions : Called once per hub, by the cpu which will ultimately + * handle this interrupt. + * Returns : None. + */ + + +void +hubii_eint_init(cnodeid_t cnode) +{ + int bit, rv; + ii_iidsr_u_t hubio_eint; + hubinfo_t hinfo; + cpuid_t intr_cpu; + devfs_handle_t hub_v; + ii_ilcsr_u_t ilcsr; + + hub_v = (devfs_handle_t)cnodeid_to_vertex(cnode); + ASSERT_ALWAYS(hub_v); + hubinfo_get(hub_v, &hinfo); + + ASSERT(hinfo); + ASSERT(hinfo->h_cnodeid == cnode); + + ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR); + + if ((ilcsr.ii_ilcsr_fld_s.i_llp_stat & 0x2) == 0) { + /* + * HUB II link is not up. + * Just disable LLP, and don't connect any interrupts. + */ + ilcsr.ii_ilcsr_fld_s.i_llp_en = 0; + REMOTE_HUB_S(hinfo->h_nasid, IIO_ILCSR, ilcsr.ii_ilcsr_regval); + return; + } + /* Select a possible interrupt target where there is a free interrupt + * bit and also reserve the interrupt bit for this IO error interrupt + */ + intr_cpu = intr_heuristic(hub_v,0,INTRCONNECT_ANYBIT,II_ERRORINT,hub_v, + "HUB IO error interrupt",&bit); + if (intr_cpu == CPU_NONE) { + printk("hubii_eint_init: intr_reserve_level failed, cnode %d", cnode); + return; + } + + rv = intr_connect_level(intr_cpu, bit, 0,(intr_func_t)(NULL), + (void *)(long)hub_v, NULL); + synergy_intr_connect(bit, intr_cpu); + request_irq(bit_pos_to_irq(bit) + (intr_cpu << 8), hubii_eint_handler, 0, NULL, (void *)hub_v); + ASSERT_ALWAYS(rv >= 0); + hubio_eint.ii_iidsr_regval = 0; + hubio_eint.ii_iidsr_fld_s.i_enable = 1; + hubio_eint.ii_iidsr_fld_s.i_level = bit;/* Take the least significant bits*/ + hubio_eint.ii_iidsr_fld_s.i_node = COMPACT_TO_NASID_NODEID(cnode); + hubio_eint.ii_iidsr_fld_s.i_pi_id = cpuid_to_subnode(intr_cpu); + REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, hubio_eint.ii_iidsr_regval); + +} + +void +hubni_eint_init(cnodeid_t cnode) +{ + int intr_bit; + cpuid_t targ; + + + if ((targ = cnodeid_to_cpuid(cnode)) == CPU_NONE) + return; + + /* The prom chooses which cpu gets these interrupts, but we + * don't know which one it chose. We will register all of the + * cpus to be sure. This only costs us an irqaction per cpu. + */ + for (; targ < CPUS_PER_NODE; targ++) { + if (!cpu_enabled(targ) ) continue; + /* connect the INTEND1 bits. */ + for (intr_bit = XB_ERROR; intr_bit <= MSC_PANIC_INTR; intr_bit++) { + intr_connect_level(targ, intr_bit, II_ERRORINT, NULL, NULL, NULL); + } + request_irq(SGI_HUB_ERROR_IRQ + (targ << 8), snia_error_intr_handler, 0, NULL, NULL); + /* synergy masks are initialized in the prom to enable all interrupts. */ + /* We'll just leave them that way, here, for these interrupts. */ + } +} + + +/*ARGSUSED*/ +void +hubii_eint_handler (int irq, void *arg, struct pt_regs *ep) +{ + devfs_handle_t hub_v; + hubinfo_t hinfo; + ii_wstat_u_t wstat; + hubreg_t idsr; + + panic("Hubii interrupt\n"); +#ifdef ajm + /* + * If the NI has a problem, everyone has a problem. We shouldn't + * even attempt to handle other errors when an NI error is present. + */ + if (check_ni_errors()) { + hubni_error_handler("II interrupt", 1); + /* NOTREACHED */ + } + + /* two levels of casting avoids compiler warning.!! */ + hub_v = (devfs_handle_t)(long)(arg); + ASSERT(hub_v); + + hubinfo_get(hub_v, &hinfo); + + /* + * Identify the reason for error. + */ + wstat.ii_wstat_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_WSTAT); + + if (wstat.ii_wstat_fld_s.w_crazy) { + char *reason; + /* + * We can do a couple of things here. + * Look at the fields TX_MX_RTY/XT_TAIL_TO/XT_CRD_TO to check + * which of these caused the CRAZY bit to be set. + * You may be able to check if the Link is up really. + */ + if (wstat.ii_wstat_fld_s.w_tx_mx_rty) + reason = "Micro Packet Retry Timeout"; + else if (wstat.ii_wstat_fld_s.w_xt_tail_to) + reason = "Crosstalk Tail Timeout"; + else if (wstat.ii_wstat_fld_s.w_xt_crd_to) + reason = "Crosstalk Credit Timeout"; + else { + hubreg_t hubii_imem; + /* + * Check if widget 0 has been marked as shutdown, or + * if BTE 0/1 has been marked. + */ + hubii_imem = REMOTE_HUB_L(hinfo->h_nasid, IIO_IMEM); + if (hubii_imem & IIO_IMEM_W0ESD) + reason = "Hub Widget 0 has been Shutdown"; + else if (hubii_imem & IIO_IMEM_B0ESD) + reason = "BTE 0 has been shutdown"; + else if (hubii_imem & IIO_IMEM_B1ESD) + reason = "BTE 1 has been shutdown"; + else reason = "Unknown"; + + } + /* + * Note: we may never be able to print this, if the II talking + * to Xbow which hosts the console is dead. + */ + printk("Hub %d to Xtalk Link failed (II_ECRAZY) Reason: %s", + hinfo->h_cnodeid, reason); + } + + /* + * It's a toss as to which one among PRB/CRB to check first. + * Current decision is based on the severity of the errors. + * IO CRB errors tend to be more severe than PRB errors. + * + * It is possible for BTE errors to have been handled already, so we + * may not see any errors handled here. + */ + (void)hubiio_crb_error_handler(hub_v, hinfo); + (void)hubiio_prb_error_handler(hub_v, hinfo); + /* + * If we reach here, it indicates crb/prb handlers successfully + * handled the error. So, re-enable II to send more interrupt + * and return. + */ + REMOTE_HUB_S(hinfo->h_nasid, IIO_IECLR, 0xffffff); + idsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_IIDSR) & ~IIO_IIDSR_SENT_MASK; + REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, idsr); +#endif /* ajm */ +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/hubspc.c linux.ac/arch/ia64/sn/io/hubspc.c --- linux.vanilla/arch/ia64/sn/io/hubspc.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/io/hubspc.c Tue Apr 10 18:09:55 2001 @@ -61,7 +61,7 @@ }cpuprom_info_t; static cpuprom_info_t *cpuprom_head; -lock_t cpuprom_spinlock; +spinlock_t cpuprom_spinlock; #define PROM_LOCK() mutex_spinlock(&cpuprom_spinlock) #define PROM_UNLOCK(s) mutex_spinunlock(&cpuprom_spinlock, (s)) @@ -72,7 +72,7 @@ prominfo_add(devfs_handle_t hub, devfs_handle_t prom) { cpuprom_info_t *info; - int s; + unsigned long s; info = kmalloc(sizeof(cpuprom_info_t), GFP_KERNEL); ASSERT(info); @@ -89,7 +89,7 @@ void prominfo_del(devfs_handle_t prom) { - int s; + unsigned long s; cpuprom_info_t *info; cpuprom_info_t **prev; @@ -111,7 +111,7 @@ devfs_handle_t prominfo_nodeget(devfs_handle_t prom) { - int s; + unsigned long s; cpuprom_info_t *info; s = PROM_LOCK(); @@ -297,7 +297,7 @@ printf("hubspc_init: Completed\n"); #endif /* HUBSPC_DEBUG */ /* Initialize spinlocks */ - spinlock_init(&cpuprom_spinlock, "promlist"); + mutex_spinlock_init(&cpuprom_spinlock); } /* ARGSUSED */ @@ -312,12 +312,6 @@ break; case HUBSPC_PROM: - /* Check if the user has proper access rights to - * read/write the prom space. - */ - if (!cap_able(CAP_DEVICE_MGT)) { - errcode = EPERM; - } break; default: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/invent.c linux.ac/arch/ia64/sn/io/invent.c --- linux.vanilla/arch/ia64/sn/io/invent.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/invent.c Tue Apr 10 18:09:55 2001 @@ -61,6 +61,9 @@ * These two routines are intended to prevent the caller from having to know * the internal structure of the inventory table. * + * The caller of get_next_inventory is supposed to call start_scan_invent + * before the irst call to get_next_inventory, and the caller is required + * to call end_scan_invent after the last call to get_next_inventory. */ inventory_t * get_next_inventory(invplace_t *place) @@ -74,11 +77,15 @@ * We've exhausted inventory items on the last device. * Advance to next device. */ + place->invplace_inv = NULL; /* Start from beginning invent on this device */ rv = hwgraph_vertex_get_next(&device, &place->invplace_vplace); - if (rv != LABELCL_SUCCESS) + if (rv == LABELCL_SUCCESS) { + place->invplace_vhdl = device; + } + else { + place->invplace_vhdl = GRAPH_VERTEX_NONE; return(NULL); - place->invplace_vhdl = device; - place->invplace_inv = NULL; /* Start from beginning invent on this device */ + } } return(pinv); @@ -91,6 +98,23 @@ return sizeof(inventory_t); } +/* Must be called prior to first call to get_next_inventory */ +void +start_scan_inventory(invplace_t *iplace) +{ + *iplace = INVPLACE_NONE; +} + +/* Must be called after last call to get_next_inventory */ +void +end_scan_inventory(invplace_t *iplace) +{ + devfs_handle_t vhdl = iplace->invplace_vhdl; + if (vhdl != GRAPH_VERTEX_NONE) + hwgraph_vertex_unref(vhdl); + *iplace = INVPLACE_NONE; /* paranoia */ +} + /* * Hardware inventory scanner. * @@ -106,11 +130,13 @@ ie = 0; rc = 0; - while ( (ie = (inventory_t *)get_next_inventory(&iplace)) ) { + start_scan_inventory(&iplace); + while ((ie = (inventory_t *)get_next_inventory(&iplace))) { rc = (*fun)(ie, arg); if (rc) break; } + end_scan_inventory(&iplace); return rc; } @@ -127,6 +153,7 @@ { invplace_t iplace = { NULL,NULL, NULL }; + start_scan_inventory(&iplace); while ((pinv = (inventory_t *)get_next_inventory(&iplace)) != NULL) { if (class != -1 && pinv->inv_class != class) continue; @@ -146,6 +173,7 @@ continue; break; } + end_scan_inventory(&iplace); return(pinv); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/io.c linux.ac/arch/ia64/sn/io/io.c --- linux.vanilla/arch/ia64/sn/io/io.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/io.c Sat Apr 14 01:18:00 2001 @@ -13,7 +13,6 @@ #include <linux/slab.h> #include <asm/sn/types.h> #include <asm/sn/sgi.h> -#include <asm/sn/cmn_err.h> #include <asm/sn/iobus.h> #include <asm/sn/iograph.h> #include <asm/param.h> @@ -33,11 +32,6 @@ extern xtalk_provider_t hub_provider; -#ifndef CONFIG_IA64_SGI_IO -/* Global variables */ -extern pdaindr_t pdaindr[MAXCPUS]; -#endif - /* * Perform any initializations needed to support hub-based I/O. * Called once during startup. @@ -45,7 +39,7 @@ void hubio_init(void) { -#if 0 +#ifdef LATER /* This isn't needed unless we port the entire sio driver ... */ extern void early_brl1_port_init( void ); early_brl1_port_init(); @@ -101,17 +95,14 @@ hub_piomap->hpio_flags = HUB_PIOMAP_IS_BIGWINDOW; IIO_ITTE_DISABLE(nasid, bigwin); } -#ifdef BRINGUP hub_set_piomode(nasid, HUB_PIO_CONVEYOR); -#else - /* Set all the xwidgets in fire-and-forget mode - * by default - */ - hub_set_piomode(nasid, HUB_PIO_FIRE_N_FORGET); -#endif /* BRINGUP */ - sv_init(&hubinfo->h_bwwait, SV_FIFO, "bigwin"); - spinlock_init(&hubinfo->h_bwlock, "bigwin"); + mutex_spinlock_init(&hubinfo->h_bwlock); +/* + * If this lock can be acquired from interrupts or bh's, add SV_INTS or SV_BHS, + * respectively, to the flags here. + */ + sv_init(&hubinfo->h_bwwait, &hubinfo->h_bwlock, SV_ORDER_FIFO | SV_MON_SPIN); } /* @@ -143,7 +134,7 @@ int bigwin, free_bw_index; nasid_t nasid; volatile hubreg_t junk; - int s; + unsigned long s; /* sanity check */ if (byte_count_max > byte_count) @@ -222,7 +213,7 @@ goto done; } - sv_wait(&hubinfo->h_bwwait, PZERO, &hubinfo->h_bwlock, s); + sv_wait(&hubinfo->h_bwwait, 0, 0); goto tryagain; } } @@ -282,7 +273,7 @@ devfs_handle_t hubv; hubinfo_t hubinfo; nasid_t nasid; - int s; + unsigned long s; /* * Small windows are permanently mapped to corresponding widgets, @@ -463,9 +454,9 @@ if (!(dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) { vhdl = dmamap->hdma_xtalk_info.xd_dev; #if defined(SUPPORT_PRINTING_V_FORMAT) - cmn_err(CE_WARN, "%v: hub_dmamap_addr re-uses dmamap.\n",vhdl); + PRINT_WARNING("%v: hub_dmamap_addr re-uses dmamap.\n",vhdl); #else - cmn_err(CE_WARN, "0x%p: hub_dmamap_addr re-uses dmamap.\n", &vhdl); + PRINT_WARNING("0x%x: hub_dmamap_addr re-uses dmamap.\n", vhdl); #endif } } else { @@ -496,9 +487,9 @@ if (!(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) { vhdl = hub_dmamap->hdma_xtalk_info.xd_dev; #if defined(SUPPORT_PRINTING_V_FORMAT) - cmn_err(CE_WARN,"%v: hub_dmamap_list re-uses dmamap\n",vhdl); + PRINT_WARNING("%v: hub_dmamap_list re-uses dmamap\n",vhdl); #else - cmn_err(CE_WARN,"0x%p: hub_dmamap_list re-uses dmamap\n", &vhdl); + PRINT_WARNING("0x%x: hub_dmamap_list re-uses dmamap\n", vhdl); #endif } } else { @@ -525,9 +516,9 @@ if (!(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) { vhdl = hub_dmamap->hdma_xtalk_info.xd_dev; #if defined(SUPPORT_PRINTING_V_FORMAT) - cmn_err(CE_WARN, "%v: hub_dmamap_done already done with dmamap\n",vhdl); + PRINT_WARNING("%v: hub_dmamap_done already done with dmamap\n",vhdl); #else - cmn_err(CE_WARN, "0x%p: hub_dmamap_done already done with dmamap\n", &vhdl); + PRINT_WARNING("0x%x: hub_dmamap_done already done with dmamap\n", vhdl); #endif } } @@ -629,16 +620,17 @@ * Allocate resources required for an interrupt as specified in dev_desc. * Returns a hub interrupt handle on success, or 0 on failure. */ -hub_intr_t -hub_intr_alloc( devfs_handle_t dev, /* which crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev) /* owner of this interrupt, if known */ +static hub_intr_t +do_hub_intr_alloc(devfs_handle_t dev, /* which crosstalk device */ + device_desc_t dev_desc, /* device descriptor */ + devfs_handle_t owner_dev, /* owner of this interrupt, if known */ + int uncond_nothread) /* unconditionally non-threaded */ { - cpuid_t cpu; /* cpu to receive interrupt */ + cpuid_t cpu = (cpuid_t)0; /* cpu to receive interrupt */ int cpupicked = 0; int bit; /* interrupt vector */ /*REFERENCED*/ - int intr_resflags; + int intr_resflags = 0; hub_intr_t intr_hdl; cnodeid_t nodeid; /* node to receive interrupt */ /*REFERENCED*/ @@ -665,7 +657,7 @@ intr_swlevel = device_desc_intr_swlevel_get(dev_desc); if (dev_desc->flags & D_INTR_ISERR) { intr_resflags = II_ERRORINT; - } else if (!(dev_desc->flags & D_INTR_NOTHREAD)) { + } else if (!uncond_nothread && !(dev_desc->flags & D_INTR_NOTHREAD)) { intr_resflags = II_THREADED; } else { /* Neither an error nor a thread. */ @@ -673,7 +665,8 @@ } } else { intr_swlevel = default_intr_pri; - intr_resflags = II_THREADED; + if (!uncond_nothread) + intr_resflags = II_THREADED; } /* XXX - Need to determine if the interrupt should be threaded. */ @@ -692,13 +685,11 @@ /* At this point we SHOULD have a valid cpu */ if (cpu == CPU_NONE) { #if defined(SUPPORT_PRINTING_V_FORMAT) - cmn_err(CE_WARN, - "%v hub_intr_alloc could not allocate interrupt\n", + PRINT_WARNING("%v hub_intr_alloc could not allocate interrupt\n", owner_dev); #else - cmn_err(CE_WARN, - "0x%p hub_intr_alloc could not allocate interrupt\n", - &owner_dev); + PRINT_WARNING("0x%x hub_intr_alloc could not allocate interrupt\n", + owner_dev); #endif return(0); @@ -714,15 +705,13 @@ owner_dev, intr_name); if (bit < 0) { #if defined(SUPPORT_PRINTING_V_FORMAT) - cmn_err(CE_WARN, - "Could not reserve an interrupt bit for cpu " + PRINT_WARNING("Could not reserve an interrupt bit for cpu " " %d and dev %v\n", cpu,owner_dev); #else - cmn_err(CE_WARN, - "Could not reserve an interrupt bit for cpu " + PRINT_WARNING("Could not reserve an interrupt bit for cpu " " %d and dev 0x%x\n", - cpu, &owner_dev); + cpu, owner_dev); #endif return(0); @@ -751,8 +740,6 @@ xtalk_info->xi_dev = dev; xtalk_info->xi_vector = bit; xtalk_info->xi_addr = xtalk_addr; - xtalk_info->xi_flags = (intr_resflags == II_THREADED) ? - 0 : XTALK_INTR_NOTHREAD; /* * Regardless of which CPU we ultimately interrupt, a given crosstalk @@ -779,6 +766,31 @@ return(intr_hdl); } +/* + * Allocate resources required for an interrupt as specified in dev_desc. + * Returns a hub interrupt handle on success, or 0 on failure. + */ +hub_intr_t +hub_intr_alloc( devfs_handle_t dev, /* which crosstalk device */ + device_desc_t dev_desc, /* device descriptor */ + devfs_handle_t owner_dev) /* owner of this interrupt, if known */ +{ + return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 0)); +} + +/* + * Allocate resources required for an interrupt as specified in dev_desc. + * Uncondtionally request non-threaded, regardless of what the device + * descriptor might say. + * Returns a hub interrupt handle on success, or 0 on failure. + */ +hub_intr_t +hub_intr_alloc_nothd(devfs_handle_t dev, /* which crosstalk device */ + device_desc_t dev_desc, /* device descriptor */ + devfs_handle_t owner_dev) /* owner of this interrupt, if known */ +{ + return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 1)); +} /* * Free resources consumed by intr_alloc. @@ -1001,7 +1013,7 @@ { iprb_t prb; int prb_offset; -#ifdef IRIX +#ifdef LATER extern int force_fire_and_forget; extern volatile int ignore_conveyor_override; @@ -1063,7 +1075,7 @@ int direct_connect; hubii_wcr_t ii_wcr; int prbnum; - int s, cons_lock = 0; + int cons_lock = 0; ASSERT(NASID_TO_COMPACT_NODEID(nasid) != INVALID_CNODEID); if (nasid == get_console_nasid()) { @@ -1098,15 +1110,6 @@ hub_setup_prb(nasid, prbnum, 3, conveyor); } -#ifdef IRIX - /* - * In direct connect mode, disable access to all widgets but 0. - * Later, the prom will do this for us. - */ - if (direct_connect) - ii_iowa = 1; -#endif - REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, ii_iowa); if (cons_lock) @@ -1151,7 +1154,8 @@ devfs_handle_t hub_vhdl = xwidget_info_master_get(widget_info); hubinfo_t hub_info = 0; nasid_t nasid; - int s,rv; + unsigned long s; + int rv; /* Use the nasid from the hub info hanging off the hub vertex * and widget number from the widget vertex @@ -1178,7 +1182,7 @@ devfs_handle_t hub_vhdl = xwidget_info_master_get(widget_info); hubinfo_t hub_info = 0; nasid_t nasid; - int s; + unsigned long s; /* Use the nasid from the hub info hanging off the hub vertex * and widget number from the widget vertex @@ -1201,7 +1205,7 @@ devfs_handle_t hub_vhdl = xwidget_info_master_get(widget_info); hubinfo_t hub_info = 0; nasid_t nasid; - int s; + unsigned long s; /* Use the nasid from the hub info hanging off the hub vertex * and widget number from the widget vertex @@ -1253,25 +1257,23 @@ ii_iowa = REMOTE_HUB_L(nasid, IIO_IOWA); #if defined(SUPPORT_PRINTING_V_FORMAT) - cmn_err(CE_CONT, "Inquiry Info for %v\n", xconn); + printk("Inquiry Info for %v\n", xconn); #else - cmn_err(CE_CONT, "Inquiry Info for 0x%p\n", &xconn); + printk("Inquiry Info for 0x%x\n", xconn); #endif - cmn_err(CE_CONT,"\tDevices shutdown [ "); + printk("\tDevices shutdown [ "); for (d = 0 ; d <= 7 ; d++) if (!(ii_iidem & (IIO_IIDEM_WIDGETDEV_MASK(widget,d)))) - cmn_err(CE_CONT, " %d", d); + printk(" %d", d); - cmn_err(CE_CONT,"]\n"); + printk("]\n"); - cmn_err(CE_CONT, - "\tInbound access ? %s\n", + printk("\tInbound access ? %s\n", ii_iiwa & IIO_IIWA_WIDGET(widget) ? "yes" : "no"); - cmn_err(CE_CONT, - "\tOutbound access ? %s\n", + printk("\tOutbound access ? %s\n", ii_iowa & IIO_IOWA_WIDGET(widget) ? "yes" : "no"); } @@ -1300,6 +1302,7 @@ (xtalk_dmalist_drain_f *) hub_dmalist_drain, (xtalk_intr_alloc_f *) hub_intr_alloc, + (xtalk_intr_alloc_f *) hub_intr_alloc_nothd, (xtalk_intr_free_f *) hub_intr_free, (xtalk_intr_connect_f *) hub_intr_connect, (xtalk_intr_disconnect_f *) hub_intr_disconnect, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/ip37.c linux.ac/arch/ia64/sn/io/ip37.c --- linux.vanilla/arch/ia64/sn/io/ip37.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/io/ip37.c Tue Apr 10 18:09:55 2001 @@ -30,10 +30,6 @@ ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid,IIO_WCR); - printk("hub_widget_id: Found Hub Widget ID 0x%x from Register 0x%p\n", ii_wcr.wcr_fields_s.wcr_widget_id, REMOTE_HUB_ADDR(nasid, IIO_WCR)); - - printk("hub_widget_id: Found Hub Widget 0x%lx wcr_reg_value 0x%lx\n", REMOTE_HUB_L(nasid,IIO_WCR), ii_wcr.wcr_reg_value); - return ii_wcr.wcr_fields_s.wcr_widget_id; } @@ -64,8 +60,6 @@ get_hub_chiprev(nasid_t nasid) { - printk("get_hub_chiprev: Hub Chip Rev 0x%lx\n", - (REMOTE_HUB_L(nasid, LB_REV_ID) & LRI_REV_MASK) >> LRI_REV_SHFT); return ((REMOTE_HUB_L(nasid, LB_REV_ID) & LRI_REV_MASK) >> LRI_REV_SHFT); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/klconflib.c linux.ac/arch/ia64/sn/io/klconflib.c --- linux.vanilla/arch/ia64/sn/io/klconflib.c Sat Feb 17 00:02:34 2001 +++ linux.ac/arch/ia64/sn/io/klconflib.c Tue Apr 10 18:09:55 2001 @@ -82,7 +82,7 @@ } index = j; if (index == KLCF_NUM_COMPS(brd)) { - printf("find_component: Bad pointer: 0x%p\n", kli); + DBG("find_component: Bad pointer: 0x%p\n", kli); return (klinfo_t *)NULL; } index++; /* next component */ @@ -152,11 +152,6 @@ return (lboard_t *)NULL; } -#ifndef CONFIG_IA64_SGI_IO -#define tolower(c) (isupper(c) ? (c) - 'A' + 'a' : (c)) -#define toupper(c) (islower(c) ? (c) - 'a' + 'A' : (c)) -#endif - /* * Convert a NIC name to a name for use in the hardware graph. @@ -205,10 +200,6 @@ !strncmp(new_name, "mio", 3) || !strncmp(new_name, "media_io", 8)) strcpy(new_name, "baseio"); -#if !defined(CONFIG_SGI_IP35) && !defined(CONFIG_IA64_SGI_SN1) && !defined(CONFIG_IA64_GENERIC) - else if (!strncmp(new_name, "ip29", 4)) - strcpy(new_name,SN00_MOTHERBOARD); -#endif else if (!strncmp(new_name, "divo", 4)) strcpy(new_name, "divo") ; @@ -284,11 +275,11 @@ /* * PV # 540860 - * If the name is not 'baseio' or SN00 MOTHERBOARD + * If the name is not 'baseio' * get the lowest of all the names in the nic string. * This is needed for boards like divo, which can have * a bunch of daughter cards, but would like to be called - * divo. We could do this for baseio and SN00 MOTHERBOARD + * divo. We could do this for baseio * but it has some special case names that we would not * like to disturb at this point. */ @@ -355,11 +346,7 @@ /* * look for boards that might contain an xbow or xbridge */ -#if SN0 - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_MIDPLANE8); -#else - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_PBRICK_XBOW); -#endif + brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW); if (brd == NULL) return 0; if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW)) @@ -369,7 +356,7 @@ if (!XBOW_PORT_TYPE_IO(xbow_p, link) || !XBOW_PORT_IS_ENABLED(xbow_p, link)) return 0; - printf("xbow_port_io_enabled: brd 0x%p xbow_p 0x%p \n", brd, xbow_p); + DBG("xbow_port_io_enabled: brd 0x%p xbow_p 0x%p \n", brd, xbow_p); return 1; } @@ -395,6 +382,9 @@ if (brd->brd_type == KLTYPE_META_ROUTER) { board_name = EDGE_LBL_META_ROUTER; hasmetarouter++; + } else if (brd->brd_type == KLTYPE_REPEATER_ROUTER) { + board_name = EDGE_LBL_REPEATER_ROUTER; + hasmetarouter++; } else board_name = EDGE_LBL_ROUTER; break; @@ -420,22 +410,17 @@ modnum = brd->brd_module; -#if defined(SN0) - slot = brd->brd_slot; - get_slotname(slot, slot_name); - - ASSERT(modnum >= 0); - - sprintf(path, "%H/" EDGE_LBL_SLOT "/%s/%s", - modnum, slot_name, board_name); -#else ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE); -#ifdef BRINGUP /* fix IP35 hwgraph */ - sprintf(path, EDGE_LBL_MODULE "/%x/%s", modnum, board_name); +#ifdef __ia64 + { + char buffer[16]; + memset(buffer, 0, 16); + format_module_id(buffer, modnum, MODULE_FORMAT_BRIEF); + sprintf(path, EDGE_LBL_MODULE "/%s/%s", buffer, board_name); + } #else sprintf(path, "%H/%s", modnum, board_name); #endif -#endif } /* @@ -455,172 +440,8 @@ } -#ifndef CONFIG_IA64_SGI_IO -#if 1 -/* - * find_gfxpipe(#) - * - * XXXmacko - * This is only used by graphics drivers, and should be moved - * over to gfx/kern/graphics/SN0 as soon as it's convenient. - */ -static klgfx_t *graphics_pipe_list = NULL; -static devfs_handle_t hwgraph_all_gfxids = GRAPH_VERTEX_NONE; - -void -setup_gfxpipe_link(devfs_handle_t vhdl,int pipenum) -{ - char idbuf[8]; - extern graph_hdl_t hwgraph; - - graph_info_add_LBL(hwgraph, vhdl, INFO_LBL_GFXID, INFO_DESC_EXPORT, - (arbitrary_info_t)pipenum); - if (hwgraph_all_gfxids == GRAPH_VERTEX_NONE) - hwgraph_path_add(hwgraph_root, EDGE_LBL_GFX, &hwgraph_all_gfxids); - sprintf(idbuf, "%d", pipenum); - hwgraph_edge_add(hwgraph_all_gfxids, vhdl, idbuf); - -} -#endif - -/* - * find the pipenum'th logical graphics pipe (KLCLASS_GFX) - */ -lboard_t * -find_gfxpipe(int pipenum) -{ - gda_t *gdap; - cnodeid_t cnode; - nasid_t nasid; - lboard_t *lb; - klgfx_t *kg,**pkg; - int i; - - gdap = (gda_t *)GDA_ADDR(get_nasid()); - if (gdap->g_magic != GDA_MAGIC) - return NULL; - - if (!graphics_pipe_list) { - /* for all nodes */ - for (cnode = 0; cnode < MAX_COMPACT_NODES; cnode ++) { - nasid = gdap->g_nasidtable[cnode]; - if (nasid == INVALID_NASID) - continue; - lb = KL_CONFIG_INFO(nasid) ; - while (lb = find_lboard_class(lb, KLCLASS_GFX)) { - moduleid_t kgm, pkgm; - int kgs, pkgs; - -#if defined(DEBUG) && (defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)) && defined(BRINGUP) - printf("find_gfxpipe(): PIPE: %s mod %M slot %d\n",lb?lb->brd_name:"!LBRD", - lb->brd_module,lb->brd_slot); -#endif - /* insert lb into list */ - if (!(kg = (klgfx_t*)find_first_component(lb,KLSTRUCT_GFX))) { - lb = KLCF_NEXT(lb); - continue; - } - /* set moduleslot now that we have brd_module set */ - kg->moduleslot = (lb->brd_module << 8) | SLOTNUM_GETSLOT(lb->brd_slot); - /* make sure board has device flag set */ - kg->gfx_info.flags |= KLINFO_DEVICE; - if (kg->cookie < KLGFX_COOKIE) { - kg->gfx_next_pipe = NULL; - kg->cookie = KLGFX_COOKIE; - } - - kgm = kg->moduleslot>>8; - kgs = kg->moduleslot&0xff; - pkg = &graphics_pipe_list; - while (*pkg) { - pkgm = (*pkg)->moduleslot>>8; - pkgs = (*pkg)->moduleslot&0xff; - - if (!(MODULE_CMP(kgm, pkgm) > 0 || - (MODULE_CMP(kgm, pkgm) == 0 && - kgs > pkgs))) - break; - - pkg = &(*pkg)->gfx_next_pipe; - } - kg->gfx_next_pipe = *pkg; - *pkg = kg; - lb = KLCF_NEXT(lb); - } - } -#ifdef FIND_GFXPIPE_DEBUG - i = 0; - kg = graphics_pipe_list; - while (kg) { - lboard_t *lb; -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - lb = find_lboard_class(KL_CONFIG_INFO(kg->gfx_info.nasid), KLCLASS_GFX); -#else -#error Need to figure out how to find graphics boards ... -#endif -#if defined(SUPPORT_PRINTING_M_FORMAT) - printf("find_gfxpipe(): %s pipe %d mod %M slot %d\n",lb?lb->brd_name:"!LBRD",i, - (kg->moduleslot>>8),(kg->moduleslot&0xff)); -#else - printf("find_gfxpipe(): %s pipe %d mod 0x%x slot %d\n",lb?lb->brd_name:"!LBRD",i, - (kg->moduleslot>>8),(kg->moduleslot&0xff)); -#endif - kg = kg->gfx_next_pipe; - i++; - } -#endif - } - - i = 0; - kg = graphics_pipe_list; - while (kg && (i < pipenum)) { - kg = kg->gfx_next_pipe; - i++; - } - - if (!kg) return NULL; - -#if defined(SN0) - return find_lboard_modslot(KL_CONFIG_INFO(kg->gfx_info.nasid), - (kg->moduleslot>>8), - SLOTNUM_XTALK_CLASS|(kg->moduleslot&0xff)); -#elif defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - return find_lboard_class(KL_CONFIG_INFO(kg->gfx_info.nasid), KLCLASS_GFX); -#else -#error Need to figure out how to find graphics boards ... -#endif -} -#endif - - #define MHZ 1000000 -#ifndef CONFIG_IA64_SGI_IO -uint -cpu_cycles_adjust(uint orig_cycles) -{ - klcpu_t *acpu; - uint speed; - - acpu = nasid_slice_to_cpuinfo(get_nasid(), get_slice()); - - if (acpu == NULL) return orig_cycles; - - /* - * cpu cycles seem to be half of the real value, hack and mult by 2 - * for now. - */ - speed = (orig_cycles * 2) / MHZ; - - /* - * if the cpu thinks its running at some random speed nowhere close - * the programmed speed, do nothing. - */ - if ((speed < (acpu->cpu_speed - 2)) || (speed > (acpu->cpu_speed + 2))) - return orig_cycles; - return (acpu->cpu_speed * MHZ/2); -} -#endif /* CONFIG_IA64_SGI_IO */ /* Get the canonical hardware graph name for the given pci component * on the given io board. @@ -633,9 +454,6 @@ moduleid_t modnum; slotid_t slot; char board_name[20]; -#ifdef SN0 - char slot_name[SLOTNUM_MAXLENGTH]; -#endif ASSERT(brd); @@ -646,13 +464,7 @@ * into a string */ slot = brd->brd_slot; -#ifdef SN0 - get_slotname(slot, slot_name); - - ASSERT(modnum >= 0); -#else ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE); -#endif /* Get the io board name */ if (!brd || (brd->brd_sversion < 2)) { @@ -662,18 +474,10 @@ } /* Give out the canonical name of the pci device*/ -#ifdef SN0 - sprintf(name, - "/hw/"EDGE_LBL_MODULE "/%M/"EDGE_LBL_SLOT"/%s/%s/" - EDGE_LBL_PCI"/%d", - modnum, slot_name, board_name,KLCF_BRIDGE_W_ID(component)); -#elif defined (CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) sprintf(name, "/dev/hw/"EDGE_LBL_MODULE "/%x/"EDGE_LBL_SLOT"/%s/" EDGE_LBL_PCI"/%d", modnum, board_name,KLCF_BRIDGE_W_ID(component)); -#endif - } /* @@ -894,90 +698,6 @@ } #include "asm/sn/sn_private.h" -#ifndef CONFIG_IA64_SGI_IO -/* - * Given a physical address get the name of memory dimm bank - * in a hwgraph name format. - */ -void -membank_pathname_get(paddr_t paddr,char *name) -{ - cnodeid_t cnode; - char slotname[SLOTNUM_MAXLENGTH]; - - cnode = paddr_cnode(paddr); - /* Make sure that we have a valid name buffer */ - if (!name) - return; - - name[0] = 0; - /* Make sure that the cnode is valid */ - if ((cnode == CNODEID_NONE) || (cnode > numnodes)) - return; - /* Given a slotid(class:type) get the slotname */ -#if defined (SN0) - get_slotname(NODE_SLOTID(cnode),slotname); - sprintf(name, - "/hw/"EDGE_LBL_MODULE"/%M/"EDGE_LBL_SLOT"/%s/"EDGE_LBL_NODE - "/"EDGE_LBL_MEMORY"/dimm_bank/%d", - NODE_MODULEID(cnode),slotname,paddr_dimm(paddr)); -#elif defined (CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - sprintf(name, - "/dev/hw/"EDGE_LBL_MODULE"/%M/"EDGE_LBL_NODE - "/"EDGE_LBL_MEMORY"/dimm_bank/%d", - NODE_MODULEID(cnode),paddr_dimm(paddr)); -#endif -} - - - -int -membank_check_mixed_hidensity(nasid_t nasid) -{ - lboard_t *brd; - klmembnk_t *mem; - int min_size = 1024, max_size = 0; - int bank, mem_size; - - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27); - ASSERT(brd); - - mem = (klmembnk_t *)find_first_component(brd, KLSTRUCT_MEMBNK); - ASSERT(mem); - - - for (mem_size = 0, bank = 0; bank < MD_MEM_BANKS; bank++) { - mem_size = KLCONFIG_MEMBNK_SIZE(mem, bank); - if (mem_size < min_size) - min_size = mem_size; - if (mem_size > max_size) - max_size = mem_size; - } - - if ((max_size == 512) && (max_size != min_size)) - return 1; - - return 0; -} - - -int -mem_mixed_hidensity_banks(void) -{ - cnodeid_t cnode; - nasid_t nasid; - - for (cnode = 0; cnode < maxnodes; cnode++) { - nasid = COMPACT_TO_NASID_NODEID(cnode); - if (nasid == INVALID_NASID) - continue; - if (membank_check_mixed_hidensity(nasid)) - return 1; - } - return 0; - -} -#endif /* CONFIG_IA64_SGI_IO */ xwidgetnum_t nodevertex_widgetnum_get(devfs_handle_t node_vtx) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/klgraph.c linux.ac/arch/ia64/sn/io/klgraph.c --- linux.vanilla/arch/ia64/sn/io/klgraph.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/io/klgraph.c Tue Apr 10 18:09:55 2001 @@ -23,18 +23,15 @@ #include <asm/sn/hcl.h> #include <asm/sn/labelcl.h> -#include <asm/sn/cmn_err.h> #include <asm/sn/agent.h> -#ifdef CONFIG_IA64_SGI_IO #include <asm/sn/kldir.h> -#endif #include <asm/sn/gda.h> #include <asm/sn/klconfig.h> #include <asm/sn/router.h> #include <asm/sn/xtalk/xbow.h> #include <asm/sn/hcl_util.h> -#define KLGRAPH_DEBUG 1 +/* #define KLGRAPH_DEBUG 1 */ #ifdef KLGRAPH_DEBUG #define GRPRINTF(x) printk x #define CE_GRPANIC CE_PANIC @@ -48,25 +45,6 @@ extern char arg_maxnodes[]; extern int maxnodes; -#ifndef BRINGUP -/* - * Gets reason for diagval using table lookup. - */ -static char* -get_diag_string(uint diagcode) -{ - int num_entries; - int i; - num_entries = sizeof(diagval_map) / sizeof(diagval_t); - for (i = 0; i < num_entries; i++){ - if ((unchar)diagval_map[i].dv_code == (unchar)diagcode) - return diagval_map[i].dv_msg; - } - return "Unknown"; -} - -#endif /* ndef BRINGUP */ - /* * Support for verbose inventory via hardware graph. @@ -105,7 +83,7 @@ klhwg_invent_alloc(cnode, INV_PROM, sizeof(invent_miscinfo_t)); baseio_inventory->im_type = INV_IO6PROM; /* Read the io6prom revision from the nvram */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER nvram_prom_version_get(&version,&revision); #endif /* Store the revision info in the inventory */ @@ -169,7 +147,7 @@ (void) hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv); rc = device_master_set(myhubv, node_vertex); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* * Activate when we support hub stats. */ @@ -178,8 +156,7 @@ #endif if (rc != GRAPH_SUCCESS) { - cmn_err(CE_WARN, - "klhwg_add_hub: Can't add hub info label 0x%p, code %d", + PRINT_WARNING("klhwg_add_hub: Can't add hub info label 0x%p, code %d", myhubv, rc); } @@ -187,15 +164,12 @@ #ifndef BRINGUP init_hub_stats(cnode, NODEPDA(cnode)); -#endif /* ndef BRINGUP */ - -#ifndef CONFIG_IA64_SGI_IO sndrv_attach(myhubv); #else /* * Need to call our driver to do the attach? */ - printk("klhwg_add_hub: Need to add code to do the attach.\n"); + FIXME("klhwg_add_hub: Need to add code to do the attach.\n"); #endif } @@ -350,7 +324,7 @@ rps_invent->ir_gen.ig_flag = INVENT_ENABLED; } -#endif /* ndef BRINGUP */ +#endif /* BRINGUP */ void klhwg_add_xbow(cnodeid_t cnode, nasid_t nasid) @@ -366,7 +340,7 @@ #if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || defined(CONFIG_IA64_GENERIC) if ((brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), - KLTYPE_PBRICK_XBOW)) == NULL) + KLTYPE_IOBRICK_XBOW)) == NULL) return; #endif @@ -380,7 +354,7 @@ == NULL) return; -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* * We cannot support this function in devfs .. see below where * we use hwgraph_path_add() to create this vertex with a known @@ -390,21 +364,19 @@ ASSERT(err == GRAPH_SUCCESS); xswitch_vertex_init(xbow_v); -#endif /* !CONFIG_IA64_SGI_IO */ +#endif /* LATER */ for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { if (!XBOW_PORT_TYPE_HUB(xbow_p, widgetnum)) continue; hub_nasid = XBOW_PORT_NASID(xbow_p, widgetnum); - printk("klhwg_add_xbow: Found xbow port type hub hub_nasid %d widgetnum %d\n", hub_nasid, widgetnum); if (hub_nasid == INVALID_NASID) { - cmn_err(CE_WARN, "hub widget %d, skipping xbow graph\n", widgetnum); + PRINT_WARNING("hub widget %d, skipping xbow graph\n", widgetnum); continue; } hub_cnode = NASID_TO_COMPACT_NODEID(hub_nasid); - printk("klhwg_add_xbow: cnode %d cnode %d\n", nasid_to_compact_node[0], nasid_to_compact_node[1]); if (is_specified(arg_maxnodes) && hub_cnode == INVALID_CNODEID) { continue; @@ -412,21 +384,18 @@ hubv = cnodeid_to_vertex(hub_cnode); -#ifdef CONFIG_IA64_SGI_IO - printk("klhwg_add_xbow: Hub Vertex found = %p hub_cnode %d\n", hubv, hub_cnode); err = hwgraph_path_add(hubv, EDGE_LBL_XTALK, &xbow_v); if (err != GRAPH_SUCCESS) { if (err == GRAPH_DUP) - cmn_err(CE_WARN, "klhwg_add_xbow: Check for " + PRINT_WARNING("klhwg_add_xbow: Check for " "working routers and router links!"); - cmn_err(CE_GRPANIC, "klhwg_add_xbow: Failed to add " + PRINT_PANIC("klhwg_add_xbow: Failed to add " "edge: vertex 0x%p (0x%p) to vertex 0x%p (0x%p)," "error %d\n", hubv, hubv, xbow_v, xbow_v, err); } xswitch_vertex_init(xbow_v); -#endif NODEPDA(hub_cnode)->xbow_vhdl = xbow_v; @@ -443,14 +412,14 @@ GRPRINTF(("klhwg_add_xbow: adding port nasid %d %s to vertex 0x%p\n", hub_nasid, EDGE_LBL_XTALK, hubv)); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER err = hwgraph_edge_add(hubv, xbow_v, EDGE_LBL_XTALK); if (err != GRAPH_SUCCESS) { if (err == GRAPH_DUP) - cmn_err(CE_WARN, "klhwg_add_xbow: Check for " + PRINT_WARNING("klhwg_add_xbow: Check for " "working routers and router links!"); - cmn_err(CE_GRPANIC, "klhwg_add_xbow: Failed to add " + PRINT_PANIC("klhwg_add_xbow: Failed to add " "edge: vertex 0x%p (0x%p) to vertex 0x%p (0x%p), " "error %d\n", hubv, hubv, xbow_v, xbow_v, err); @@ -488,9 +457,8 @@ path_buffer, hwgraph_root)); rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex); - printk("klhwg_add_node: rv = %d graph success %d node_vertex 0x%p\n", rv, GRAPH_SUCCESS, node_vertex); if (rv != GRAPH_SUCCESS) - cmn_err(CE_PANIC, "Node vertex creation failed. " + PRINT_PANIC("Node vertex creation failed. " "Path == %s", path_buffer); @@ -504,11 +472,8 @@ if(!board_disabled) { mark_nodevertex_as_node(node_vertex, cnode + board_disabled * numnodes); - printk("klhwg_add_node: node_vertex %p, cnode %d numnodes %d\n", node_vertex, cnode, numnodes); s = dev_to_name(node_vertex, path_buffer, sizeof(path_buffer)); - printk("klhwg_add_node: s %s\n", s); - NODEPDA(cnode)->hwg_node_name = kmalloc(strlen(s) + 1, GFP_KERNEL); @@ -581,7 +546,7 @@ rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex); if (rv != GRAPH_SUCCESS) - cmn_err(CE_PANIC, "Router vertex creation " + PRINT_PANIC("Router vertex creation " "failed. Path == %s", path_buffer); @@ -629,12 +594,11 @@ return; if (rc != GRAPH_SUCCESS) - cmn_err(CE_WARN, "Can't find router: %s", path_buffer); + PRINT_WARNING("Can't find router: %s", path_buffer); /* We don't know what to do with multiple router components */ if (brd->brd_numcompts != 1) { - cmn_err(CE_PANIC, - "klhwg_connect_one_router: %d cmpts on router\n", + PRINT_PANIC("klhwg_connect_one_router: %d cmpts on router\n", brd->brd_numcompts); return; } @@ -668,7 +632,7 @@ if (rc != GRAPH_SUCCESS) { if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd)) continue; - cmn_err(CE_PANIC, "Can't find router: %s", dest_path); + PRINT_PANIC("Can't find router: %s", dest_path); } GRPRINTF(("klhwg_connect_one_router: Link from %s/%d to %s\n", path_buffer, port, dest_path)); @@ -685,7 +649,7 @@ } if (rc != GRAPH_SUCCESS && !is_specified(arg_maxnodes)) - cmn_err(CE_GRPANIC, "Can't create edge: %s/%s to vertex 0x%p error 0x%x\n", + PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p error 0x%x\n", path_buffer, dest_path, dest_hndl, rc); } @@ -768,7 +732,7 @@ rc = hwgraph_traverse(hwgraph_root, path_buffer, &hub_hndl); if (rc != GRAPH_SUCCESS) - cmn_err(CE_WARN, "Can't find hub: %s", path_buffer); + PRINT_WARNING("Can't find hub: %s", path_buffer); dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( hub->hub_port.port_nasid, @@ -782,7 +746,7 @@ if (rc != GRAPH_SUCCESS) { if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd)) continue; - cmn_err(CE_PANIC, "Can't find board: %s", dest_path); + PRINT_PANIC("Can't find board: %s", dest_path); } else { @@ -792,7 +756,7 @@ rc = hwgraph_edge_add(hub_hndl, dest_hndl, EDGE_LBL_INTERCONNECT); if (rc != GRAPH_SUCCESS) - cmn_err(CE_GRPANIC, "Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n", + PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n", path_buffer, dest_path, dest_hndl, rc); } @@ -815,7 +779,7 @@ */ char device_name[MAXDEVNAME]; -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER device_admin_table_init(); #endif for(cnode = 0; cnode < numnodes; cnode++) { @@ -853,7 +817,7 @@ device_component_canonical_name_get(board, component, device_name); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER device_admin_table_update(device_name, ADMIN_LBL_DISABLED, "yes"); @@ -877,13 +841,20 @@ char name[128]; devfs_handle_t vhdl; int rc; + char buffer[16]; /* Add devices under each module */ for (cm = 0; cm < nummodules; cm++) { /* Use module as module vertex fastinfo */ +#ifdef __ia64 + memset(buffer, 0, 16); + format_module_id(buffer, modules[cm]->id, MODULE_FORMAT_BRIEF); + sprintf(name, EDGE_LBL_MODULE "/%s", buffer); +#else sprintf(name, EDGE_LBL_MODULE "/%x", modules[cm]->id); +#endif rc = hwgraph_path_add(hwgraph_root, name, &vhdl); ASSERT(rc == GRAPH_SUCCESS); @@ -893,9 +864,15 @@ /* Add system controller */ +#ifdef __ia64 + sprintf(name, + EDGE_LBL_MODULE "/%s/" EDGE_LBL_L1, + buffer); +#else sprintf(name, EDGE_LBL_MODULE "/%x/" EDGE_LBL_L1, modules[cm]->id); +#endif rc = hwgraph_path_add(hwgraph_root, name, &vhdl); ASSERT_ALWAYS(rc == GRAPH_SUCCESS); @@ -905,7 +882,7 @@ INFO_LBL_ELSC, (arbitrary_info_t) (__psint_t) 1); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER sndrv_attach(vhdl); #else /* @@ -923,13 +900,10 @@ gda_t *gdap; cnodeid_t cnode; -#ifdef SIMULATED_KLGRAPH - //gdap = 0xa800000000011000; - gdap = (gda_t *)0xe000000000011000; - printk("klhwg_add_all_nodes: SIMULATED_KLGRAPH FIXME: gdap= 0x%p\n", gdap); -#else - gdap = GDA; -#endif /* SIMULATED_KLGRAPH */ + gdap = (gda_t *)0xe000000000002400; + + FIXME("klhwg_add_all_nodes: FIX GDA\n"); + for (cnode = 0; cnode < numnodes; cnode++) { ASSERT(gdap->g_nasidtable[cnode] != INVALID_NASID); klhwg_add_node(hwgraph_root, cnode, gdap); @@ -938,12 +912,7 @@ for (cnode = 0; cnode < numnodes; cnode++) { ASSERT(gdap->g_nasidtable[cnode] != INVALID_NASID); -#ifndef CONFIG_IA64_SGI_IO klhwg_add_xbow(cnode, gdap->g_nasidtable[cnode]); -#else - printk("klhwg_add_all_nodes: Fix me by getting real nasid\n"); - klhwg_add_xbow(cnode, 0); -#endif } /* @@ -959,7 +928,7 @@ * routers in the system. */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER router_guardians_set(hwgraph_root); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/klgraph_hack.c linux.ac/arch/ia64/sn/io/klgraph_hack.c --- linux.vanilla/arch/ia64/sn/io/klgraph_hack.c Sat Feb 17 00:02:34 2001 +++ linux.ac/arch/ia64/sn/io/klgraph_hack.c Sat Apr 14 01:18:00 2001 @@ -15,7 +15,6 @@ */ #include <linux/types.h> -#include <linux/config.h> #include <linux/slab.h> #include <linux/vmalloc.h> #include <asm/sn/sgi.h> @@ -35,55 +34,6 @@ extern void clear_ii_error(void); #endif /* BRINGUP */ -void -simulated_BW0_init(void) -{ - - unsigned long *cnode0_hub; - unsigned long hub_widget = 0x1000000; - unsigned long hub_offset = 0x800000; - unsigned long hub_reg_base = 0; - extern void * vmalloc(unsigned long); - - memset(&nasid_to_compact_node[0], 0, sizeof(cnodeid_t) * MAX_NASIDS); - - BW0 = vmalloc(0x10000000); - if (BW0 == NULL) { - printk("Darn it .. cannot create space for Big Window 0\n"); - } - printk("BW0: Start Address %p\n", BW0); - - memset(BW0+(0x10000000 - 8), 0xf, 0x8); - - printk("BW0: Last WORD address %p has value 0x%lx\n", (char *)(BW0 +(0x10000000 - 8)), *(long *)(BW0 +(0x10000000 - 8))); - - printk("XWIDGET 8 Address = 0x%p\n", (unsigned long *)(NODE_SWIN_BASE(0, 8)) ); - - /* - * Do some HUB Register Hack .. - */ - hub_reg_base = (unsigned long)BW0 + hub_widget + hub_offset; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_WID); *cnode0_hub = 0x1c110049; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_WSTAT); *cnode0_hub = 0x0; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_WCR); *cnode0_hub = 0x401b; - printk("IIO_WCR address = 0x%p\n", cnode0_hub); - - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_ILAPR); *cnode0_hub = 0xffffffffffffffff; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_ILAPO); *cnode0_hub = 0x0; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_IOWA); *cnode0_hub = 0xff01; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_IIWA); *cnode0_hub = 0xff01; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_IIDEM); *cnode0_hub = 0xffffffffffffffff; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_ILCSR); *cnode0_hub = 0x3fc03ff640a; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_ILLR); *cnode0_hub = 0x0; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_IIDSR); *cnode0_hub = 0x1000040; -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_IGFX0); *cnode0_hub = 0x0; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_IGFX1); *cnode0_hub = 0x0; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_ISCR0); *cnode0_hub = 0x23d; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_ISCR1); *cnode0_hub = 0x0; -#endif /* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 */ -} - #define SYNERGY_WIDGET ((char *)0xc0000e0000000000) #define SYNERGY_SWIZZLE ((char *)0xc0000e0000000400) #define HUBREG ((char *)0xc0000a0001e00000) @@ -136,10 +86,10 @@ klxbow_t *klxbow_ptr; klinfo_t *klinfo_ptr; klcomp_t *klcomp_ptr; +#if 0 uint64_t *tmp; volatile u32 *tmp32; -#if 0 /* Preset some values */ /* Write IOERR clear to clear the CRAZY bit in the status */ tmp = (uint64_t *)0xc0000a0001c001f8; *tmp = (uint64_t)0xffffffff; @@ -164,7 +114,6 @@ *tmp32 = 0xba98; tmp32 = (volatile u32 *)0xc0000a000f000288L; *tmp32 = 0xba98; -#endif printk("Widget ID Address 0x%p Value 0x%lx\n", (uint64_t *)0xc0000a0001e00000, *( (volatile uint64_t *)0xc0000a0001e00000) ); @@ -181,6 +130,7 @@ printk("Xbow ID Address 0x%p Value 0x%x\n", (uint64_t *)0xc000020000000004, *( (volatile uint32_t *)0xc000020000000004) ); +#endif if ( test ) test_io_regs(); @@ -210,9 +160,8 @@ */ linux_klcfg = (kl_config_hdr_t *)0xe000000000030000; if (linux_klcfg->ch_magic == 0xbeedbabe) { - printk("Linux Kernel Booted from Disk\n"); + return; } else { - printk("Linux Kernel Booted from PROM\n"); linux_klcfg = kl_hdr_ptr; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/l1.c linux.ac/arch/ia64/sn/io/l1.c --- linux.vanilla/arch/ia64/sn/io/l1.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/ia64/sn/io/l1.c Tue Apr 10 18:09:55 2001 @@ -34,6 +34,7 @@ #include <linux/types.h> #include <linux/config.h> #include <linux/slab.h> +#include <linux/spinlock.h> #include <asm/sn/sgi.h> #include <asm/sn/iograph.h> #include <asm/sn/invent.h> @@ -42,7 +43,6 @@ #include <asm/sn/labelcl.h> #include <asm/sn/eeprom.h> #include <asm/sn/ksys/i2c.h> -#include <asm/sn/cmn_err.h> #include <asm/sn/router.h> #include <asm/sn/module.h> #include <asm/sn/ksys/l1.h> @@ -51,6 +51,20 @@ #include <asm/sn/sn1/uart16550.h> +/* + * Delete this when atomic_clear is part of atomic.h. + */ +static __inline__ int +atomic_clear (int i, atomic_t *v) +{ + __s32 old, new; + + do { + old = atomic_read(v); + new = old & ~i; + } while (ia64_cmpxchg("acq", v, old, new, sizeof(atomic_t)) != old); + return new; +} #if defined(EEPROM_DEBUG) #define db_printf(x) printk x @@ -73,6 +87,7 @@ /* location of uart receive/xmit data register */ #define L1_UART_BASE(n) ((ulong)REMOTE_HSPEC_ADDR((n), HSPEC_UART_0)) #define LOCAL_HUB LOCAL_HUB_ADDR +#define LOCK_HUB REMOTE_HUB_ADDR #define ADDR_L1_REG(n, r) \ (L1_UART_BASE(n) | ( (r) << 3 )) @@ -84,21 +99,10 @@ ( SD(ADDR_L1_REG((n), (r)), (v)) ) -/* Avoid conflicts with symmon...*/ -#define CONS_HW_LOCK(x) -#define CONS_HW_UNLOCK(x) - -#define L1_CONS_HW_LOCK(sc) CONS_HW_LOCK(sc->uart == BRL1_LOCALUART) -#define L1_CONS_HW_UNLOCK(sc) CONS_HW_UNLOCK(sc->uart == BRL1_LOCALUART) - -#if DEBUG -static int debuglock_ospl; /* For CONS_HW_LOCK macro */ -#endif - /* UART-related #defines */ #define UART_BAUD_RATE 57600 -#define UART_FIFO_DEPTH 16 +#define UART_FIFO_DEPTH 0xf0 #define UART_DELAY_SPAN 10 #define UART_PUTC_TIMEOUT 50000 #define UART_INIT_TIMEOUT 100000 @@ -146,6 +150,9 @@ _xyz[0] = _b[_i++]; \ } #else /* BIG_ENDIAN */ + +extern char *bcopy(const char * src, char * dest, int count); + #define COPY_INT_TO_BUFFER(_b, _i, _n) \ { \ bcopy((char *)&_n, _b, sizeof(_n)); \ @@ -165,13 +172,148 @@ } #endif /* LITTLE_ENDIAN */ -int atomicAddInt(int *int_ptr, int value); -int atomicClearInt(int *int_ptr, int value); void kmem_free(void *where, int size); #define BCOPY(x,y,z) memcpy(y,x,z) -extern char *bcopy(const char * src, char * dest, int count); +/* + * Console locking defines and functions. + * + */ + +#ifdef BRINGUP +#define FORCE_CONSOLE_NASID +#endif + +#define HUB_LOCK 16 + +#define PRIMARY_LOCK_TIMEOUT 10000000 +#define HUB_LOCK_REG(n) LOCK_HUB(n, MD_PERF_CNT0) + +#define SET_BITS(reg, bits) SD(reg, LD(reg) | (bits)) +#define CLR_BITS(reg, bits) SD(reg, LD(reg) & ~(bits)) +#define TST_BITS(reg, bits) ((LD(reg) & (bits)) != 0) + +#define HUB_TEST_AND_SET(n) LD(LOCK_HUB(n,LB_SCRATCH_REG3_RZ)) +#define HUB_CLEAR(n) SD(LOCK_HUB(n,LB_SCRATCH_REG3),0) + +#define RTC_TIME_MAX ((rtc_time_t) ~0ULL) + + +/* + * primary_lock + * + * Allows CPU's 0-3 to mutually exclude the hub from one another by + * obtaining a blocking lock. Does nothing if only one CPU is active. + * + * This lock should be held just long enough to set or clear a global + * lock bit. After a relatively short timeout period, this routine + * figures something is wrong, and steals the lock. It does not set + * any other CPU to "dead". + */ +inline void +primary_lock(nasid_t nasid) +{ + rtc_time_t expire; + + expire = rtc_time() + PRIMARY_LOCK_TIMEOUT; + + while (HUB_TEST_AND_SET(nasid)) { + if (rtc_time() > expire) { + HUB_CLEAR(nasid); + } + } +} + +/* + * primary_unlock (internal) + * + * Counterpart to primary_lock + */ + +inline void +primary_unlock(nasid_t nasid) +{ + HUB_CLEAR(nasid); +} + +/* + * hub_unlock + * + * Counterpart to hub_lock_timeout and hub_lock + */ + +inline void +hub_unlock(nasid_t nasid, int level) +{ + uint64_t mask = 1ULL << level; + + primary_lock(nasid); + CLR_BITS(HUB_LOCK_REG(nasid), mask); + primary_unlock(nasid); +} + +/* + * hub_lock_timeout + * + * Uses primary_lock to implement multiple lock levels. + * + * There are 20 lock levels from 0 to 19 (limited by the number of bits + * in HUB_LOCK_REG). To prevent deadlock, multiple locks should be + * obtained in order of increasingly higher level, and released in the + * reverse order. + * + * A timeout value of 0 may be used for no timeout. + * + * Returns 0 if successful, -1 if lock times out. + */ + +inline int +hub_lock_timeout(nasid_t nasid, int level, rtc_time_t timeout) +{ + uint64_t mask = 1ULL << level; + rtc_time_t expire = (timeout ? rtc_time() + timeout : RTC_TIME_MAX); + int done = 0; + + while (! done) { + while (TST_BITS(HUB_LOCK_REG(nasid), mask)) { + if (rtc_time() > expire) + return -1; + } + + primary_lock(nasid); + + if (! TST_BITS(HUB_LOCK_REG(nasid), mask)) { + SET_BITS(HUB_LOCK_REG(nasid), mask); + done = 1; + } + primary_unlock(nasid); + } + return 0; +} + + +#define LOCK_TIMEOUT (0x1500000 * 1) /* 0x1500000 is ~30 sec */ + +inline void +lock_console(nasid_t nasid) +{ + int ret; + + ret = hub_lock_timeout(nasid, HUB_LOCK, (rtc_time_t)LOCK_TIMEOUT); + if ( ret != 0 ) { + /* timeout */ + hub_unlock(nasid, HUB_LOCK); + /* If the 2nd lock fails, just pile ahead.... */ + hub_lock_timeout(nasid, HUB_LOCK, (rtc_time_t)LOCK_TIMEOUT); + } +} + +inline void +unlock_console(nasid_t nasid) +{ + hub_unlock(nasid, HUB_LOCK); +} int @@ -189,7 +331,7 @@ UART_DELAY( delay_span ); } -#define UART_PUTC_READY(n) (READ_L1_UART_REG((n), REG_LSR) & LSR_XHRE) +#define UART_PUTC_READY(n) ( (READ_L1_UART_REG((n), REG_LSR) & LSR_XHRE) && (READ_L1_UART_REG((n), REG_MSR) & MSR_CTS) ) static int uart_putc( l1sc_t *sc ) @@ -198,6 +340,10 @@ /* need a delay to avoid dropping chars */ UART_DELAY(57); #endif +#ifdef FORCE_CONSOLE_NASID + /* We need this for the console write path _elscuart_flush() -> brl1_send() */ + sc->nasid = 0; +#endif WRITE_L1_UART_REG( sc->nasid, REG_DAT, sc->send[sc->sent] ); return UART_SUCCESS; @@ -210,6 +356,10 @@ u_char lsr_reg = 0; nasid_t nasid = sc->nasid; +#ifdef FORCE_CONSOLE_NASID + nasid = sc->nasid = 0; +#endif + if( (lsr_reg = READ_L1_UART_REG( nasid, REG_LSR )) & (LSR_RCA | LSR_PARERR | LSR_FRMERR) ) { @@ -246,7 +396,8 @@ } } - L1_CONS_HW_LOCK( sc ); + if ( sc->uart == BRL1_LOCALUART ) + lock_console(nasid); WRITE_L1_UART_REG( nasid, REG_LCR, LCR_DLAB ); uart_delay( UART_DELAY_SPAN ); @@ -271,17 +422,17 @@ WRITE_L1_UART_REG( nasid, REG_FCR, FCR_FIFOEN | FCR_RxFIFO | FCR_TxFIFO ); - L1_CONS_HW_UNLOCK( sc ); + if ( sc->uart == BRL1_LOCALUART ) + unlock_console(nasid); } +/* This requires the console lock */ static void uart_intr_enable( l1sc_t *sc, u_char mask ) { u_char lcr_reg, icr_reg; nasid_t nasid = sc->nasid; - L1_CONS_HW_LOCK(sc); - /* make sure that the DLAB bit in the LCR register is 0 */ lcr_reg = READ_L1_UART_REG( nasid, REG_LCR ); @@ -293,18 +444,15 @@ icr_reg = READ_L1_UART_REG( nasid, REG_ICR ); icr_reg |= mask; WRITE_L1_UART_REG( nasid, REG_ICR, icr_reg /*(ICR_RIEN | ICR_TIEN)*/ ); - - L1_CONS_HW_UNLOCK(sc); } +/* This requires the console lock */ static void uart_intr_disable( l1sc_t *sc, u_char mask ) { u_char lcr_reg, icr_reg; nasid_t nasid = sc->nasid; - L1_CONS_HW_LOCK(sc); - /* make sure that the DLAB bit in the LCR register is 0 */ lcr_reg = READ_L1_UART_REG( nasid, REG_LCR ); @@ -316,8 +464,6 @@ icr_reg = READ_L1_UART_REG( nasid, REG_ICR ); icr_reg &= mask; WRITE_L1_UART_REG( nasid, REG_ICR, icr_reg /*(ICR_RIEN | ICR_TIEN)*/ ); - - L1_CONS_HW_UNLOCK(sc); } #define uart_enable_xmit_intr(sc) \ @@ -353,15 +499,9 @@ } \ } -#ifdef SABLE -#define RTR_UART_PUTC_TIMEOUT 0 -#define RTR_UART_DELAY_SPAN 0 -#define RTR_UART_INIT_TIMEOUT 0 -#else #define RTR_UART_PUTC_TIMEOUT UART_PUTC_TIMEOUT*10 #define RTR_UART_DELAY_SPAN UART_DELAY_SPAN #define RTR_UART_INIT_TIMEOUT UART_INIT_TIMEOUT*10 -#endif static int rtr_uart_putc( l1sc_t *sc ) @@ -370,7 +510,11 @@ nasid_t nasid = sc->nasid; net_vec_t path = sc->uart; rtc_time_t expire = rtc_time() + RTR_UART_PUTC_TIMEOUT; - + +#ifdef FORCE_CONSOLE_NASID + /* We need this for the console write path _elscuart_flush() -> brl1_send() */ + nasid = sc->nasid = 0; +#endif c = (sc->send[sc->sent] & 0xffULL); while( 1 ) @@ -399,6 +543,10 @@ nasid_t nasid = sc->nasid; net_vec_t path = sc->uart; +#ifdef FORCE_CONSOLE_NASID + nasid = sc->nasid = 0; +#endif + READ_RTR_L1_UART_REG( path, nasid, REG_LSR, ®val ); if( regval & (LSR_RCA | LSR_PARERR | LSR_FRMERR) ) { @@ -468,28 +616,6 @@ return 0; } - - - -/********************************************************************* - * locking macros - */ - -#define L1SC_SEND_LOCK(l,pl) \ - { if( (l)->uart == BRL1_LOCALUART ) \ - (pl) = mutex_spinlock_spl( &((l)->send_lock), spl7 ); } - -#define L1SC_SEND_UNLOCK(l,pl) \ - { if( (l)->uart == BRL1_LOCALUART ) \ - mutex_spinunlock( &((l)->send_lock), (pl)); } - -#define L1SC_RECV_LOCK(l,pl) \ - { if( (l)->uart == BRL1_LOCALUART ) \ - (pl) = mutex_spinlock_spl( &((l)->recv_lock), spl7 ); } - -#define L1SC_RECV_UNLOCK(l,pl) \ - { if( (l)->uart == BRL1_LOCALUART ) \ - mutex_spinunlock( &((l)->recv_lock), (pl)); } /********************************************************************* @@ -501,60 +627,17 @@ * */ - #ifdef SPINLOCKS_WORK -#define SUBCH_LOCK(sc,pl) \ - (pl) = mutex_spinlock_spl( &((sc)->subch_lock), spl7 ) -#define SUBCH_UNLOCK(sc,pl) \ - mutex_spinunlock( &((sc)->subch_lock), (pl) ) - -#define SUBCH_DATA_LOCK(sbch,pl) \ - (pl) = mutex_spinlock_spl( &((sbch)->data_lock), spl7 ) -#define SUBCH_DATA_UNLOCK(sbch,pl) \ - mutex_spinunlock( &((sbch)->data_lock), (pl) ) +#define SUBCH_LOCK(sc) spin_lock_irq( &((sc)->subch_lock) ) +#define SUBCH_UNLOCK(sc) spin_unlock_irq( &((sc)->subch_lock) ) +#define SUBCH_DATA_LOCK(sbch) spin_lock_irq( &((sbch)->data_lock) ) +#define SUBCH_DATA_UNLOCK(sbch) spin_unlock_irq( &((sbch)->data_lock) ) #else -#define SUBCH_LOCK(sc,pl) -#define SUBCH_UNLOCK(sc,pl) -#define SUBCH_DATA_LOCK(sbch,pl) -#define SUBCH_DATA_UNLOCK(sbch,pl) -#endif /* SPINLOCKS_WORK */ - -/* - * set a function to be called for subchannel ch in the event of - * a transmission low-water interrupt from the uart - */ -void -subch_set_tx_notify( l1sc_t *sc, int ch, brl1_notif_t func ) -{ - int pl; - L1SC_SEND_LOCK( sc, pl ); - sc->subch[ch].tx_notify = func; - - /* some upper layer is asking to be notified of low-water, but if the - * send buffer isn't already in use, we're going to need to get the - * interrupts going on the uart... - */ - if( func && !sc->send_in_use ) - uart_enable_xmit_intr( sc ); - L1SC_SEND_UNLOCK(sc, pl ); -} - -/* - * set a function to be called for subchannel ch when data is received - */ -void -subch_set_rx_notify( l1sc_t *sc, int ch, brl1_notif_t func ) -{ -#ifdef SPINLOCKS_WORK - int pl; +#define SUBCH_LOCK(sc) +#define SUBCH_UNLOCK(sc) +#define SUBCH_DATA_LOCK(sbch) +#define SUBCH_DATA_UNLOCK(sbch) #endif - brl1_sch_t *subch = &(sc->subch[ch]); - - SUBCH_DATA_LOCK( subch, pl ); - sc->subch[ch].rx_notify = func; - SUBCH_DATA_UNLOCK( subch, pl ); -} - /* get_myid is an internal function that reads the PI_CPU_NUM @@ -680,21 +763,18 @@ /* timeouts */ #define BRL1_INIT_TIMEOUT 500000 -extern l1sc_t * get_elsc( void ); - /* * brl1_discard_packet is a dummy "receive callback" used to get rid * of packets we don't want */ void brl1_discard_packet( l1sc_t *sc, int ch ) { - int pl; brl1_sch_t *subch = &sc->subch[ch]; sc_cq_t *q = subch->iqp; - SUBCH_DATA_LOCK( subch, pl ); + SUBCH_DATA_LOCK( subch ); q->opos = q->ipos; - atomicClearInt( &(subch->packet_arrived), ~((unsigned)0) ); - SUBCH_DATA_UNLOCK( subch, pl ); + atomic_clear( &(subch->packet_arrived), ~((unsigned)0) ); + SUBCH_DATA_UNLOCK( subch ); } @@ -720,18 +800,14 @@ */ if( sc->uart == BRL1_LOCALUART ) { - CONS_HW_LOCK(1); if( !(sc->fifo_space) && UART_PUTC_READY( sc->nasid ) ) -// sc->fifo_space = UART_FIFO_DEPTH; - sc->fifo_space = 1000; + sc->fifo_space = UART_FIFO_DEPTH; while( (sc->sent < sc->send_len) && (sc->fifo_space) ) { uart_putc( sc ); sc->fifo_space--; sc->sent++; } - - CONS_HW_UNLOCK(1); } else @@ -770,7 +846,6 @@ } } } - return sc->sent; } @@ -786,20 +861,25 @@ * until our message has been completely transmitted. */ -int +static int brl1_send( l1sc_t *sc, char *msg, int len, u_char type_and_subch, int wait ) { - int pl; int index; int pkt_len = 0; unsigned short crc = INIT_CRC; char *send_ptr = sc->send; - L1SC_SEND_LOCK(sc, pl); +#ifdef BRINGUP + /* We want to be sure that we are sending the entire packet before returning */ + wait = 1; +#endif + if ( sc->uart == BRL1_LOCALUART ) + lock_console(sc->nasid); if( sc->send_in_use ) { if( !wait ) { - L1SC_SEND_UNLOCK(sc, pl); + if ( sc->uart == BRL1_LOCALUART ) + unlock_console(sc->nasid); return 0; /* couldn't send anything; wait for buffer to drain */ } else { @@ -880,61 +960,12 @@ /* enable low-water interrupts so buffer will be drained */ uart_enable_xmit_intr(sc); } - L1SC_SEND_UNLOCK(sc, pl); + if ( sc->uart == BRL1_LOCALUART ) + unlock_console(sc->nasid); return len; } -/* brl1_send_cont is intended to be called as an interrupt service - * routine. It sends until the UART won't accept any more characters, - * or until an error is encountered (in which case we surrender the - * send buffer and give up trying to send the packet). Once the - * last character in the packet has been sent, this routine releases - * the send buffer and calls any previously-registered "low-water" - * output routines. - */ -int -brl1_send_cont( l1sc_t *sc ) -{ - int pl; - int done = 0; - brl1_notif_t callups[BRL1_NUM_SUBCHANS]; - brl1_notif_t *callup; - brl1_sch_t *subch; - int index; - - L1SC_SEND_LOCK(sc, pl); - brl1_send_chars( sc ); - done = (sc->sent == sc->send_len); - if( done ) { - - sc->send_in_use = 0; - uart_disable_xmit_intr(sc); - - /* collect pointers to callups *before* unlocking */ - subch = sc->subch; - callup = callups; - for( index = 0; index < BRL1_NUM_SUBCHANS; index++ ) { - *callup = subch->tx_notify; - subch++; - callup++; - } - } - L1SC_SEND_UNLOCK(sc, pl); - - if( done ) { - /* call any upper layer that's asked for low-water notification */ - callup = callups; - for( index = 0; index < BRL1_NUM_SUBCHANS; index++ ) { - if( *callup ) - (*(*callup))( sc, index ); - callup++; - } - } - return 0; -} - - /* internal function -- used by brl1_receive to read a character * from the uart and check whether errors occurred in the process. */ @@ -1039,14 +1070,16 @@ { int result; /* value to be returned by brl1_receive */ int c; /* most-recently-read character */ - int pl; /* priority level for UART receive lock */ int done; /* set done to break out of recv loop */ sc_cq_t *q; /* pointer to queue we're working with */ result = BRL1_NO_MESSAGE; - L1SC_RECV_LOCK( sc, pl ); - L1_CONS_HW_LOCK( sc ); +#ifdef FORCE_CONSOLE_NASID + sc->nasid = 0; +#endif + if ( sc->uart == BRL1_LOCALUART ) + lock_console(sc->nasid); done = 0; while( !done ) @@ -1171,7 +1204,6 @@ unsigned short crc; /* holds the crc as we calculate it */ int i; /* index variable */ brl1_sch_t *subch; /* subchannel for received packet */ - int sch_pl; /* cookie for subchannel lock */ brl1_notif_t callup; /* "data ready" callup */ /* whatever else may happen, we've seen a flag and we're @@ -1226,7 +1258,7 @@ /* get the subchannel and lock it */ subch = &(sc->subch[SUBCH( LAST_HDR_GET(sc) )]); - SUBCH_DATA_LOCK( subch, sch_pl ); + SUBCH_DATA_LOCK( subch ); /* if this isn't a console packet, we need to record * a length byte @@ -1242,16 +1274,16 @@ /* notify subchannel owner that there's something * on the queue for them */ - atomicAddInt( &(subch->packet_arrived), 1); + atomic_inc(&(subch->packet_arrived)); callup = subch->rx_notify; - SUBCH_DATA_UNLOCK( subch, sch_pl ); + SUBCH_DATA_UNLOCK( subch ); if( callup ) { - L1_CONS_HW_UNLOCK( sc ); - L1SC_RECV_UNLOCK( sc, pl ); + if ( sc->uart == BRL1_LOCALUART ) + unlock_console(sc->nasid); (*callup)( sc, SUBCH(LAST_HDR_GET(sc)) ); - L1SC_RECV_LOCK( sc, pl ); - L1_CONS_HW_LOCK( sc ); + if ( sc->uart == BRL1_LOCALUART ) + lock_console(sc->nasid); } continue; /* go back for more! */ } @@ -1320,8 +1352,8 @@ } /* end of switch( STATE_GET(sc) ) */ } /* end of while(!done) */ - L1_CONS_HW_UNLOCK( sc ); - L1SC_RECV_UNLOCK(sc, pl); + if ( sc->uart == BRL1_LOCALUART ) + unlock_console(sc->nasid); return result; } @@ -1338,6 +1370,9 @@ brl1_sch_t *subch; bzero( sc, sizeof( *sc ) ); +#ifdef FORCE_CONSOLE_NASID + nasid = (nasid_t)0; +#endif sc->nasid = nasid; sc->uart = uart; sc->getc_f = (uart == BRL1_LOCALUART ? uart_getc : rtr_uart_getc); @@ -1351,9 +1386,9 @@ /* assign processor TTY channels */ for( i = 0; i < CPUS_PER_NODE; i++, subch++ ) { subch->use = BRL1_SUBCH_RSVD; - subch->packet_arrived = 0; - spinlock_init( &(subch->data_lock), NULL ); - sv_init( &(subch->arrive_sv), SV_FIFO, NULL ); + subch->packet_arrived = ATOMIC_INIT(0); + spin_lock_init( &(subch->data_lock) ); + sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */ ); subch->tx_notify = NULL; /* (for now, drop elscuart packets in the kernel) */ subch->rx_notify = brl1_discard_packet; @@ -1364,9 +1399,9 @@ * processor's individual TTY channel has been assigned) */ subch->use = BRL1_SUBCH_RSVD; - subch->packet_arrived = 0; - spinlock_init( &(subch->data_lock), NULL ); - sv_init( &(subch->arrive_sv), SV_FIFO, NULL ); + subch->packet_arrived = ATOMIC_INIT(0); + spin_lock_init( &(subch->data_lock) ); + sv_init( &(subch->arrive_sv), &subch->data_lock, SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */ ); subch->tx_notify = NULL; if( sc->uart == BRL1_LOCALUART ) { subch->iqp = kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, @@ -1387,7 +1422,7 @@ */ for( ; i < 0x10; i++, subch++ ) { subch->use = BRL1_SUBCH_FREE; - subch->packet_arrived = 0; + subch->packet_arrived = ATOMIC_INIT(0); subch->tx_notify = NULL; subch->rx_notify = brl1_discard_packet; subch->iqp = &sc->garbage_q; @@ -1396,7 +1431,7 @@ /* remaining subchannels are free */ for( ; i < BRL1_NUM_SUBCHANS; i++, subch++ ) { subch->use = BRL1_SUBCH_FREE; - subch->packet_arrived = 0; + subch->packet_arrived = ATOMIC_INIT(0); subch->tx_notify = NULL; subch->rx_notify = brl1_discard_packet; subch->iqp = &sc->garbage_q; @@ -1404,9 +1439,7 @@ /* initialize synchronization structures */ - spinlock_init( &(sc->send_lock), NULL ); - spinlock_init( &(sc->recv_lock), NULL ); - spinlock_init( &(sc->subch_lock), NULL ); + spin_lock_init( &(sc->subch_lock) ); if( sc->uart == BRL1_LOCALUART ) { uart_init( sc, UART_BAUD_RATE ); @@ -1423,146 +1456,46 @@ extern int elsc_module_get(l1sc_t *); sc->modid = elsc_module_get( sc ); - sc->modid = - (sc->modid < 0 ? INVALID_MODULE : sc->modid); - + sc->modid = (sc->modid < 0 ? INVALID_MODULE : sc->modid); sc->verbose = 1; } } -/********************************************************************* - * These are interrupt-related functions used in the kernel to service - * the L1. - */ - -/* - * brl1_intrd is the function which is called in a loop by the - * xthread that services L1 interrupts. - */ -#ifdef IRIX -void -brl1_intrd( struct eframe_s *ep ) -{ - u_char isr_reg; - l1sc_t *sc = get_elsc(); - - isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR); - - while( isr_reg & (ISR_RxRDY | ISR_TxRDY) ) { - - if( isr_reg & ISR_RxRDY ) { - brl1_receive(sc); - } - if( (isr_reg & ISR_TxRDY) || - (sc->send_in_use && UART_PUTC_READY(sc->nasid)) ) - { - brl1_send_cont(sc); - } - isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR); - } - - /* uart interrupts were blocked at bedrock when the interrupt - * was initially answered; reenable them now - */ - intr_unblock_bit( sc->intr_cpu, UART_INTR ); - ep = ep; /* placate the compiler */ -} -#endif - - - -/* brl1_intr is called directly from the uart interrupt; after it runs, the - * interrupt "daemon" xthread is signalled to continue. - */ -#ifdef IRIX -void -brl1_intr( struct eframe_s *ep ) -{ - /* Disable the UART interrupt, giving the xthread time to respond. - * When the daemon (xthread) finishes doing its thing, it will - * unblock the interrupt. - */ - intr_block_bit( get_elsc()->intr_cpu, UART_INTR ); - ep = ep; /* placate the compiler */ -} - - -/* set up uart interrupt handling for this node's uart - */ -void -brl1_connect_intr( l1sc_t *sc ) -{ - cpuid_t last_cpu; - - sc->intr_cpu = nodepda->node_first_cpu; - - if( intr_connect_level(sc->intr_cpu, UART_INTR, INTPEND0_MAXMASK, - (intr_func_t)brl1_intrd, 0, - (intr_func_t)brl1_intr) ) - cmn_err(CE_PANIC, "brl1_connect_intr: Can't connect UART interrupt."); - - uart_enable_recv_intr( sc ); -} -#endif /* IRIX */ - -#ifdef SABLE -/* this function is called periodically to generate fake interrupts - * and allow brl1_intrd to send/receive characters - */ -void -hubuart_service( void ) -{ - l1sc_t *sc = get_elsc(); - /* note that we'll lose error state by reading the lsr_reg. - * This is probably ok in the frictionless domain of sable. - */ - int lsr_reg; - nasid_t nasid = sc->nasid; - lsr_reg = READ_L1_UART_REG( nasid, REG_LSR ); - if( lsr_reg & (LSR_RCA | LSR_XSRE) ) { - REMOTE_HUB_PI_SEND_INTR(0, 0, UART_INTR); - } -} -#endif /* SABLE */ - - -/********************************************************************* - * The following function allows the kernel to "go around" the - * uninitialized l1sc structure to allow console output during - * early system startup. - */ - /* These are functions to use from serial_in/out when in protocol - * mode to send and receive uart control regs. + * mode to send and receive uart control regs. These are external + * interfaces into the protocol driver. */ void -brl1_send_control(int offset, int value) +l1_control_out(int offset, int value) { - nasid_t nasid = get_nasid(); + nasid_t nasid = 0; //(get_elsc())->nasid; WRITE_L1_UART_REG(nasid, offset, value); } int -brl1_get_control(int offset) +l1_control_in(int offset) { - nasid_t nasid = get_nasid(); + nasid_t nasid = 0; //(get_elsc())->nasid; return(READ_L1_UART_REG(nasid, offset)); } #define PUTCHAR(ch) \ { \ - while( !(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XHRE) ); \ + while( (!(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XHRE)) || \ + (!(READ_L1_UART_REG( nasid, REG_MSR ) & MSR_CTS)) ); \ WRITE_L1_UART_REG( nasid, REG_DAT, (ch) ); \ } int -brl1_send_console_packet( char *str, int len ) +l1_serial_out( char *str, int len ) { int sent = len; char crc_char; unsigned short crc = INIT_CRC; - nasid_t nasid = get_nasid(); + nasid_t nasid = 0; //(get_elsc())->nasid; + + lock_console(nasid); PUTCHAR( BRL1_FLAG_CH ); PUTCHAR( BRL1_EVENT | SC_CONS_SYSTEM ); @@ -1598,9 +1531,18 @@ PUTCHAR( crc_char ); PUTCHAR( BRL1_FLAG_CH ); + unlock_console(nasid); return sent - len; } +int +l1_serial_in(void) +{ + static int l1_cons_getc( l1sc_t *sc ); + + return(l1_cons_getc(get_elsc())); +} + /********************************************************************* * l1_cons functions @@ -1612,7 +1554,7 @@ * */ -int +static int l1_cons_poll( l1sc_t *sc ) { /* in case this gets called before the l1sc_t structure for the module_t @@ -1623,13 +1565,13 @@ return 0; } - if( sc->subch[SC_CONS_SYSTEM].packet_arrived ) { + if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) { return 1; } brl1_receive( sc ); - if( sc->subch[SC_CONS_SYSTEM].packet_arrived ) { + if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) { return 1; } return 0; @@ -1638,13 +1580,11 @@ /* pull a character off of the system console queue (if one is available) */ -int +static int l1_cons_getc( l1sc_t *sc ) { int c; -#ifdef SPINLOCKS_WORK - int pl; -#endif + brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]); sc_cq_t *q = subch->iqp; @@ -1652,16 +1592,16 @@ return 0; } - SUBCH_DATA_LOCK( subch, pl ); + SUBCH_DATA_LOCK( subch ); if( cq_empty( q ) ) { - subch->packet_arrived = 0; - SUBCH_DATA_UNLOCK( subch, pl ); + atomic_set(&subch->packet_arrived, 0); + SUBCH_DATA_UNLOCK( subch ); return 0; } cq_rem( q, c ); if( cq_empty( q ) ) - subch->packet_arrived = 0; - SUBCH_DATA_UNLOCK( subch, pl ); + atomic_set(&subch->packet_arrived, 0); + SUBCH_DATA_UNLOCK( subch ); return c; } @@ -1672,106 +1612,15 @@ void l1_cons_init( l1sc_t *sc ) { -#ifdef SPINLOCKS_WORK - int pl; -#endif brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]); - SUBCH_DATA_LOCK( subch, pl ); - subch->packet_arrived = 0; + SUBCH_DATA_LOCK( subch ); + atomic_set(&subch->packet_arrived, 0); cq_init( subch->iqp ); - SUBCH_DATA_UNLOCK( subch, pl ); -} - - -/* - * Write a message to the L1 on the system console subchannel. - * - * Danger: don't use a non-zero value for the wait parameter unless you're - * someone important (like a kernel error message). - */ -int -l1_cons_write( l1sc_t *sc, char *msg, int len, int wait ) -{ - return( brl1_send( sc, msg, len, (SC_CONS_SYSTEM | BRL1_EVENT), wait ) ); -} - - -/* - * Read as many characters from the system console receive queue as are - * available there (up to avail bytes). - */ -int -l1_cons_read( l1sc_t *sc, char *buf, int avail ) -{ - int pl; - int before_wrap, after_wrap; - brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]); - sc_cq_t *q = subch->iqp; - - if( !(subch->packet_arrived) ) - return 0; - - SUBCH_DATA_LOCK( subch, pl ); - if( q->opos > q->ipos ) { - before_wrap = BRL1_QSIZE - q->opos; - if( before_wrap >= avail ) { - before_wrap = avail; - after_wrap = 0; - } - else { - avail -= before_wrap; - after_wrap = q->ipos; - if( after_wrap > avail ) - after_wrap = avail; - } - } - else { - before_wrap = q->ipos - q->opos; - if( before_wrap > avail ) - before_wrap = avail; - after_wrap = 0; - } - - - BCOPY( q->buf + q->opos, buf, before_wrap ); - if( after_wrap ) - BCOPY( q->buf, buf + before_wrap, after_wrap ); - q->opos = ((q->opos + before_wrap + after_wrap) % BRL1_QSIZE); - - subch->packet_arrived = 0; - SUBCH_DATA_UNLOCK( subch, pl ); - - return( before_wrap + after_wrap ); -} - - -/* - * Install a callback function for the system console subchannel - * to allow an upper layer to be notified when the send buffer - * has been emptied. - */ -void -l1_cons_tx_notif( l1sc_t *sc, brl1_notif_t func ) -{ - subch_set_tx_notify( sc, SC_CONS_SYSTEM, func ); -} - - -/* - * Install a callback function for the system console subchannel - * to allow an upper layer to be notified when a packet has been - * received. - */ -void -l1_cons_rx_notif( l1sc_t *sc, brl1_notif_t func ) -{ - subch_set_rx_notify( sc, SC_CONS_SYSTEM, func ); + SUBCH_DATA_UNLOCK( subch ); } - - /********************************************************************* * The following functions and definitions implement the "message"- * style interface to the L1 system controller. @@ -1795,7 +1644,9 @@ sc_data_ready( l1sc_t *sc, int ch ) { brl1_sch_t *subch = &(sc->subch[ch]); + SUBCH_DATA_LOCK( subch ); sv_signal( &(subch->arrive_sv) ); + SUBCH_DATA_UNLOCK( subch ); } /* sc_open reserves a subchannel to send a request to the L1 (the @@ -1810,10 +1661,9 @@ * subchannel assignment. */ int ch; - int pl; brl1_sch_t *subch; - SUBCH_LOCK( sc, pl ); + SUBCH_LOCK( sc ); /* Look for a free subchannel. Subchannels 0-15 are reserved * for other purposes. @@ -1826,17 +1676,17 @@ if( ch == BRL1_NUM_SUBCHANS ) { /* there were no subchannels available! */ - SUBCH_UNLOCK( sc, pl ); + SUBCH_UNLOCK( sc ); return SC_NSUBCH; } subch->use = BRL1_SUBCH_RSVD; - SUBCH_UNLOCK( sc, pl ); + SUBCH_UNLOCK( sc ); - subch->packet_arrived = 0; + atomic_set(&subch->packet_arrived, 0); subch->target = target; - sv_init( &(subch->arrive_sv), SV_FIFO, NULL ); - spinlock_init( &(subch->data_lock), NULL ); + spin_lock_init( &(subch->data_lock) ); + sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */); subch->tx_notify = NULL; subch->rx_notify = sc_data_ready; subch->iqp = kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, @@ -1854,27 +1704,28 @@ sc_close( l1sc_t *sc, int ch ) { brl1_sch_t *subch; - int pl; - SUBCH_LOCK( sc, pl ); + SUBCH_LOCK( sc ); subch = &(sc->subch[ch]); if( subch->use != BRL1_SUBCH_RSVD ) { /* we're trying to close a subchannel that's not open */ return SC_NOPEN; } - subch->packet_arrived = 0; + atomic_set(&subch->packet_arrived, 0); subch->use = BRL1_SUBCH_FREE; + SUBCH_DATA_LOCK( subch ); sv_broadcast( &(subch->arrive_sv) ); sv_destroy( &(subch->arrive_sv) ); - spinlock_destroy( &(subch->data_lock) ); + SUBCH_DATA_UNLOCK( subch ); + spin_lock_destroy( &(subch->data_lock) ); ASSERT( subch->iqp && (subch->iqp != &sc->garbage_q) ); kmem_free( subch->iqp, sizeof(sc_cq_t) ); subch->iqp = &sc->garbage_q; - SUBCH_UNLOCK( sc, pl ); + SUBCH_UNLOCK( sc ); return SC_SUCCESS; } @@ -2248,7 +2099,7 @@ else { q->opos = ((q->opos + before_wrap) & (BRL1_QSIZE - 1)); } - atomicAddInt( &(subch->packet_arrived), -1 ); + atomic_dec(&(subch->packet_arrived)); } @@ -2263,7 +2114,6 @@ int sc_recv_poll( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block ) { - int pl; /* lock cookie */ int is_msg = 0; brl1_sch_t *subch = &(sc->subch[ch]); @@ -2278,7 +2128,7 @@ /* kick the next lower layer and see if it pulls anything in */ brl1_receive( sc ); - is_msg = subch->packet_arrived; + is_msg = atomic_read(&subch->packet_arrived); } while( block && !is_msg && (rtc_time() < exp_time) ); @@ -2287,9 +2137,9 @@ return( SC_NMSG ); } - SUBCH_DATA_LOCK( subch, pl ); + SUBCH_DATA_LOCK( subch ); subch_pull_msg( subch, msg, len ); - SUBCH_DATA_UNLOCK( subch, pl ); + SUBCH_DATA_UNLOCK( subch ); return( SC_SUCCESS ); } @@ -2305,17 +2155,16 @@ int sc_recv_intr( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block ) { - int pl; /* lock cookie */ int is_msg = 0; brl1_sch_t *subch = &(sc->subch[ch]); do { - SUBCH_DATA_LOCK(subch, pl); - is_msg = subch->packet_arrived; + SUBCH_DATA_LOCK(subch); + is_msg = atomic_read(&subch->packet_arrived); if( !is_msg && block ) { /* wake me when you've got something */ subch->rx_notify = sc_data_ready; - sv_wait( &(subch->arrive_sv), 0, &(subch->data_lock), pl ); + sv_wait( &(subch->arrive_sv), 0, 0); if( subch->use == BRL1_SUBCH_FREE ) { /* oops-- somebody closed our subchannel while we were * sleeping! @@ -2329,12 +2178,12 @@ if( !is_msg ) { /* no message and we didn't care to wait for one */ - SUBCH_DATA_UNLOCK( subch, pl ); + SUBCH_DATA_UNLOCK( subch ); return( SC_NMSG ); } subch_pull_msg( subch, msg, len ); - SUBCH_DATA_UNLOCK( subch, pl ); + SUBCH_DATA_UNLOCK( subch ); return( SC_SUCCESS ); } @@ -2388,12 +2237,12 @@ } /* block on sc_recv_* */ -#ifdef notyet +#ifdef LATER if( sc->uart == BRL1_LOCALUART ) { return( sc_recv_intr( sc, ch, resp, len, __WAIT_RECV ) ); } else -#endif +#endif /* LATER */ { return( sc_recv_poll( sc, ch, resp, len, __WAIT_RECV ) ); } @@ -2438,12 +2287,12 @@ { brl1_sch_t *subch = &(sc->subch[ch]); - if( subch->packet_arrived ) + if( atomic_read(&subch->packet_arrived) ) return 1; brl1_receive( sc ); - if( subch->packet_arrived ) + if( atomic_read(&subch->packet_arrived) ) return 1; return 0; @@ -2461,6 +2310,9 @@ /* sc_dispatch_env_event handles events sent from the system control * network's environmental monitor tasks. */ + +#ifdef LINUX_KERNEL_THREADS + static void sc_dispatch_env_event( uint code, int argc, char *args, int maxlen ) { @@ -2512,18 +2364,16 @@ for( ; i < j && ((args[i] == 0xd) || (args[i] == 0xa)); i++ ); - - /* write the event to syslog */ -#ifdef IRIX - cmn_err_tag( ESPcode, CE_WARN, &(args[i]) ); -#endif } } +#endif /* LINUX_KERNEL_THREADS */ /* sc_event waits for events to arrive from the system controller, and * prints appropriate messages to the syslog. */ + +#ifdef LINUX_KERNEL_THREADS static void sc_event( l1sc_t *sc, int ch ) { @@ -2544,7 +2394,7 @@ */ result = sc_recv_intr( sc, ch, event, &event_len, 1 ); if( result != SC_SUCCESS ) { - cmn_err( CE_WARN, "Error receiving sysctl event on nasid %d\n", + PRINT_WARNING("Error receiving sysctl event on nasid %d\n", sc->nasid ); } else { @@ -2588,13 +2438,13 @@ } } +#endif /* LINUX_KERNEL_THREADS */ /* sc_listen sets up a service thread to listen for incoming events. */ void sc_listen( l1sc_t *sc ) { - int pl; int result; brl1_sch_t *subch; @@ -2602,24 +2452,26 @@ int len; /* length of message being sent */ int ch; /* system controller subchannel used */ +#ifdef LINUX_KERNEL_THREADS extern int msc_shutdown_pri; +#endif /* grab the designated "event subchannel" */ - SUBCH_LOCK( sc, pl ); + SUBCH_LOCK( sc ); subch = &(sc->subch[BRL1_EVENT_SUBCH]); if( subch->use != BRL1_SUBCH_FREE ) { - SUBCH_UNLOCK( sc, pl ); - cmn_err( CE_WARN, "sysctl event subchannel in use! " + SUBCH_UNLOCK( sc ); + PRINT_WARNING("sysctl event subchannel in use! " "Not monitoring sysctl events.\n" ); return; } subch->use = BRL1_SUBCH_RSVD; - SUBCH_UNLOCK( sc, pl ); + SUBCH_UNLOCK( sc ); - subch->packet_arrived = 0; + atomic_set(&subch->packet_arrived, 0); subch->target = BRL1_LOCALUART; - sv_init( &(subch->arrive_sv), SV_FIFO, NULL ); - spinlock_init( &(subch->data_lock), NULL ); + spin_lock_init( &(subch->data_lock) ); + sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */); subch->tx_notify = NULL; subch->rx_notify = sc_data_ready; subch->iqp = kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, @@ -2670,7 +2522,7 @@ err_return: /* there was a problem; complain */ - cmn_err( CE_WARN, "failed to set sysctl event-monitoring subchannel. " + PRINT_WARNING("failed to set sysctl event-monitoring subchannel. " "Sysctl events will not be monitored.\n" ); } @@ -2825,7 +2677,7 @@ int _elscuart_readc( l1sc_t *sc ) { - int c, pl; + int c; sc_cq_t *q; brl1_sch_t *subch; @@ -2833,32 +2685,32 @@ subch = &(sc->subch[ SC_CONS_SYSTEM ]); q = subch->iqp; - SUBCH_DATA_LOCK( subch, pl ); + SUBCH_DATA_LOCK( subch ); if( !cq_empty( q ) ) { cq_rem( q, c ); if( cq_empty( q ) ) { - subch->packet_arrived = 0; + atomic_set(&subch->packet_arrived, 0); } - SUBCH_DATA_UNLOCK( subch, pl ); + SUBCH_DATA_UNLOCK( subch ); return c; } - SUBCH_DATA_UNLOCK( subch, pl ); + SUBCH_DATA_UNLOCK( subch ); } subch = &(sc->subch[ L1_ELSCUART_SUBCH(get_myid()) ]); q = subch->iqp; - SUBCH_DATA_LOCK( subch, pl ); + SUBCH_DATA_LOCK( subch ); if( cq_empty( q ) ) { - SUBCH_DATA_UNLOCK( subch, pl ); + SUBCH_DATA_UNLOCK( subch ); return -1; } cq_rem( q, c ); if( cq_empty ( q ) ) { - subch->packet_arrived = 0; + atomic_set(&subch->packet_arrived, 0); } - SUBCH_DATA_UNLOCK( subch, pl ); + SUBCH_DATA_UNLOCK( subch ); return c; } @@ -2918,6 +2770,7 @@ #else char ver[BRL1_QSIZE]; extern int elsc_version( l1sc_t *, char * ); + if ( IS_RUNNING_ON_SIMULATOR() ) return 0; return( elsc_version(sc, ver) >= 0 ); @@ -2932,43 +2785,13 @@ void _elscuart_init( l1sc_t *sc ) { - int pl; brl1_sch_t *subch = &sc->subch[L1_ELSCUART_SUBCH(get_myid())]; - SUBCH_DATA_LOCK(subch, pl); + SUBCH_DATA_LOCK(subch); - subch->packet_arrived = 0; + atomic_set(&subch->packet_arrived, 0); cq_init( subch->iqp ); cq_init( &sc->oq[MAP_OQ(L1_ELSCUART_SUBCH(get_myid()))] ); - SUBCH_DATA_UNLOCK(subch, pl); -} - - -#ifdef IRIX - -/* elscuart_syscon_listen causes the processor on which it's - * invoked to "listen" to the system console subchannel (that - * is, subchannel 4) for console input. - */ -void -elscuart_syscon_listen( l1sc_t *sc ) -{ - int pl; - brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]); - - /* if we're already listening, don't bother */ - if( sc->cons_listen ) - return; - - SUBCH_DATA_LOCK( subch, pl ); - - subch->use = BRL1_SUBCH_RSVD; - subch->packet_arrived = 0; - - SUBCH_DATA_UNLOCK( subch, pl ); - - - sc->cons_listen = 1; + SUBCH_DATA_UNLOCK(subch); } -#endif /* IRIX */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/l1_command.c linux.ac/arch/ia64/sn/io/l1_command.c --- linux.vanilla/arch/ia64/sn/io/l1_command.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/l1_command.c Tue Apr 10 18:09:55 2001 @@ -18,7 +18,6 @@ #include <asm/sn/labelcl.h> #include <asm/sn/eeprom.h> #include <asm/sn/ksys/i2c.h> -#include <asm/sn/cmn_err.h> #include <asm/sn/router.h> #include <asm/sn/module.h> #include <asm/sn/ksys/l1.h> @@ -68,7 +67,6 @@ #define SC_COMMAND sc_command - /* * elsc_init * @@ -206,6 +204,7 @@ return -1; } + /* * Command Set */ @@ -312,6 +311,7 @@ return 0; } + /* * elsc_rack_bay_get fills in the two int * arguments with the * rack number and bay number of the L1 being addressed @@ -447,8 +447,9 @@ /* construct module ID from rack and slot info */ - if ((ret = elsc_rack_bay_type_get(e, &rnum, &bay, &bricktype)) < 0) + if ((ret = elsc_rack_bay_type_get(e, &rnum, &bay, &bricktype)) < 0) { return ret; + } /* report unset location info. with a special, otherwise invalid modid */ if (rnum == 0 && bay == 0) @@ -935,6 +936,7 @@ return cbrick_uid_get( e->nasid, nic ); } + int _elsc_hbt(elsc_t *e, int ival, int rdly) { e = e; @@ -958,11 +960,12 @@ /* fill in msg with the opcode & params */ bzero( msg, BRL1_QSIZE ); - subch = sc_open( sc, L1_ADDR_LOCAL ); - L1_BUILD_ADDR( &target, compt, rack, bay, L1_ADDR_TASK_CMD ); + L1_BUILD_ADDR( &target, compt, rack, bay, 0 ); + subch = sc_open( sc, target ); + if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - target, L1_REQ_EXEC_CMD, 2, + L1_ADDR_TASK_CMD, L1_REQ_EXEC_CMD, 2, L1_ARG_ASCII, cmd )) < 0 ) { sc_close( sc, subch ); @@ -970,7 +973,7 @@ } /* send the request to the L1 */ - if( sc_command( sc, subch, msg, msg, &len ) < 0 ) + if( SC_COMMAND( sc, subch, msg, msg, &len ) < 0 ) { sc_close( sc, subch ); return( ELSC_ERROR_CMD_SEND ); @@ -988,6 +991,38 @@ return 0; } +/* + * sc_power_down + * + * Shuts down the c-brick associated with sc, and any attached I/O bricks + * or other c-bricks (won't go through r-bricks). + */ + +int sc_power_down(l1sc_t *sc) +{ + return sc_command_interp( sc, L1_ADDR_TYPE_L1, L1_ADDR_RACK_LOCAL, + L1_ADDR_BAY_LOCAL, "* pwr d" ); +} + + +/* + * sc_power_down_all + * + * Works similarly to sc_power_down, except that the request is sent to the + * closest L2 and EVERYBODY gets turned off. + */ + +int sc_power_down_all(l1sc_t *sc) +{ + if( nodepda->num_routers > 0 ) { + return sc_command_interp( sc, L1_ADDR_TYPE_L2, L1_ADDR_RACK_LOCAL, + L1_ADDR_BAY_LOCAL, "* pwr d" ); + } + else { + return sc_power_down( sc ); + } +} + /* * Routines for reading the R-brick's L1 @@ -1115,10 +1150,6 @@ if ((ret = iobrick_rack_bay_type_get(sc, &rnum, &bay, &brick_type)) < 0) return ret; - /* report unset location info. with a special, otherwise invalid modid */ - if (rnum == 0 && bay == 0) - return MODULE_NOT_SET; - if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) return ELSC_ERROR_MODULE; @@ -1203,28 +1234,101 @@ */ int -iobrick_pci_slot_pwr( l1sc_t *sc, int bus, int slot, int up ) +iobrick_pci_pwr( l1sc_t *sc, int bus, int slot, int req_code ) { - char cmd[BRL1_QSIZE]; - unsigned rack, bay, brick_type; - if( iobrick_rack_bay_type_get( sc, &rack, &bay, &brick_type ) < 0 ) +#if 0 /* The "bedrock request" method of performing this function + * seems to be broken in the L1, so for now use the command- + * interpreter method + */ + + char msg[BRL1_QSIZE]; + int len; /* length of message being sent */ + int subch; /* system controller subchannel used */ + + /* fill in msg with the opcode & params */ + bzero( msg, BRL1_QSIZE ); + subch = sc_open( sc, L1_ADDR_LOCALIO ); + + if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + req_code, 4, + L1_ARG_INT, bus, + L1_ARG_INT, slot )) < 0 ) + { + sc_close( sc, subch ); + return( ELSC_ERROR_CMD_ARGS ); + } + + /* send the request to the L1 */ + if( SC_COMMAND(sc, subch, msg, msg, &len ) < 0 ) + { + sc_close( sc, subch ); return( ELSC_ERROR_CMD_SEND ); - sprintf( cmd, "pci %d %d %s", bus, slot, - (up ? "u" : "d") ); - return( sc_command_interp - ( sc, L1_ADDR_TYPE_L1, rack, bay, cmd ) ); + } + + /* free up subchannel */ + sc_close( sc, subch ); + + /* check response */ + if( sc_interpret_resp( msg, 0 ) < 0 ) + { + return( ELSC_ERROR_RESP_FORMAT ); + } + + return 0; + +#else + char cmd[64]; + char *fxn; + + switch( req_code ) + { + case L1_REQ_PCI_UP: + fxn = "u"; + break; + case L1_REQ_PCI_DOWN: + fxn = "d"; + break; + case L1_REQ_PCI_RESET: + fxn = "rst"; + break; + default: + return( ELSC_ERROR_CMD_ARGS ); + } + + if( slot == -1 ) + sprintf( cmd, "pci %d %s", bus, fxn ); + else + sprintf( cmd, "pci %d %d %s", bus, slot, fxn ); + + return sc_command_interp( sc, L1_ADDR_TYPE_IOBRICK, + L1_ADDR_RACK_LOCAL, L1_ADDR_BAY_LOCAL, cmd ); +#endif +} + +int +iobrick_pci_slot_pwr( l1sc_t *sc, int bus, int slot, int up ) +{ + return iobrick_pci_pwr( sc, bus, slot, up ); } int iobrick_pci_bus_pwr( l1sc_t *sc, int bus, int up ) { - char cmd[BRL1_QSIZE]; - unsigned rack, bay, brick_type; - if( iobrick_rack_bay_type_get( sc, &rack, &bay, &brick_type ) < 0 ) - return( ELSC_ERROR_CMD_SEND ); - sprintf( cmd, "pci %d %s", bus, (up ? "u" : "d") ); - return( sc_command_interp - ( sc, L1_ADDR_TYPE_L1, rack, bay, cmd ) ); + return iobrick_pci_pwr( sc, bus, -1, up ); +} + + +int +iobrick_pci_slot_rst( l1sc_t *sc, int bus, int slot ) +{ + return iobrick_pci_pwr( sc, bus, slot, L1_REQ_PCI_RESET ); +} + +int +iobrick_pci_bus_rst( l1sc_t *sc, int bus ) +{ + return iobrick_pci_pwr( sc, bus, -1, L1_REQ_PCI_RESET ); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/labelcl.c linux.ac/arch/ia64/sn/io/labelcl.c --- linux.vanilla/arch/ia64/sn/io/labelcl.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/labelcl.c Tue Apr 10 18:09:55 2001 @@ -286,7 +286,7 @@ if (!strcmp(info_name, old_label_list[i].name)) { /* Not allowed to add duplicate labelled info names. */ kfree(new_label_list); - printk("labelcl_info_add_LBL: Duplicate label name %s for vertex 0x%p\n", info_name, de); + printk(KERN_WARNING "labelcl_info_add_LBL: Duplicate label name %s for vertex 0x%p\n", info_name, de); return(-1); } new_label_list[i] = old_label_list[i]; /* structure copy */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/mem_refcnt.c linux.ac/arch/ia64/sn/io/mem_refcnt.c --- linux.vanilla/arch/ia64/sn/io/mem_refcnt.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/mem_refcnt.c Sat Apr 14 01:18:00 2001 @@ -9,7 +9,6 @@ */ #include <linux/types.h> -#include <linux/config.h> #include <asm/sn/sgi.h> #include <asm/sn/invent.h> #include <asm/sn/hcl.h> @@ -58,15 +57,8 @@ mem_refcnt_open(devfs_handle_t *devp, mode_t oflag, int otyp, cred_t *crp) { cnodeid_t node; -#ifndef CONFIG_IA64_SGI_SN1 - extern int numnodes; -#endif - - ASSERT( (hubspc_subdevice_t)(ulong)device_info_get(*devp) == HUBSPC_REFCOUNTERS ); - if (!cap_able(CAP_MEMORY_MGT)) { - return (EPERM); - } + ASSERT( (hubspc_subdevice_t)(ulong)device_info_get(*devp) == HUBSPC_REFCOUNTERS ); node = master_node_get(*devp); @@ -97,9 +89,6 @@ int errcode; char* buffer; size_t blen; -#ifndef CONFIG_IA64_SGI_SN1 - extern int numnodes; -#endif ASSERT( (hubspc_subdevice_t)(ulong)device_info_get(dev) == HUBSPC_REFCOUNTERS ); @@ -186,7 +175,7 @@ rcb.rcb_cnodeid = node; rcb.rcb_granularity = MD_PAGE_SIZE; -#ifdef notyet +#ifdef LATER rcb.rcb_hw_counter_max = MIGR_COUNTER_MAX_GET(node); rcb.rcb_diff_threshold = MIGR_THRESHOLD_DIFF_GET(node); #endif @@ -209,7 +198,7 @@ ASSERT(nslots <= MAX_MEM_SLOTS); for (s = 0; s < nslots; s++) { slot[s].base = (uint64_t)ctob(slot_getbasepfn(node, s)); -#ifdef notyet +#ifdef LATER slot[s].size = (uint64_t)ctob(slot_getsize(node, s)); #else slot[s].size = (uint64_t)1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/ml_SN_init.c linux.ac/arch/ia64/sn/io/ml_SN_init.c --- linux.vanilla/arch/ia64/sn/io/ml_SN_init.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/io/ml_SN_init.c Tue Apr 10 18:09:55 2001 @@ -45,25 +45,8 @@ extern xwidgetnum_t hub_widget_id(nasid_t); -#ifndef CONFIG_IA64_SGI_IO -#if defined (IP27) -short cputype = CPU_IP27; -#elif defined (IP33) -short cputype = CPU_IP33; -#elif defined (IP35) -short cputype = CPU_IP35; -#else -#error <BOMB! define new cputype here > -#endif -#endif /* CONFIG_IA64_SGI_IO */ - static int fine_mode = 0; -#ifndef CONFIG_IA64_SGI_IO -/* Global variables */ -pdaindr_t pdaindr[MAXCPUS]; -#endif - static cnodemask_t hub_init_mask; /* Mask of cpu in a node doing init */ static volatile cnodemask_t hub_init_done_mask; /* Node mask where we wait for @@ -101,7 +84,7 @@ master_nasid = get_nasid(); set_master_bridge_base(); FIXME("mlreset: Enable when we support ioc3 .."); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER if (get_console_nasid() == master_nasid) /* Set up the IOC3 */ ioc3_mlreset((ioc3_cfg_t *)KL_CONFIG_CH_CONS_INFO(master_nasid)->config_base, @@ -113,7 +96,7 @@ nvram_baseinit(); fine_mode = is_fine_dirmode(); -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ /* We're the master processor */ master_procid = smp_processor_id(); @@ -125,7 +108,7 @@ */ ASSERT_ALWAYS(master_nasid == get_nasid()); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* * Activate when calias is implemented. @@ -155,7 +138,7 @@ ((HUB_PIO_MAP_TO_MEM << IIO_ITTE_IOSP_SHIFT) | (0 << IIO_ITTE_WIDGET_SHIFT))); } -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ /* Set up the hub initialization mask and init the lock */ CNODEMASK_CLRALL(hub_init_mask); @@ -169,7 +152,7 @@ /* Initialize Hub Pseudodriver Management */ hubdev_init(); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* * Our IO system doesn't require cache writebacks. Set some * variables appropriately. @@ -192,7 +175,7 @@ * keep redundant PROM code in memory. */ he_arcs_set_vectors(); -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ } else { /* slave != 0 */ /* @@ -216,8 +199,10 @@ extern void router_map_init(nodepda_t *); extern void router_queue_init(nodepda_t *,cnodeid_t); + extern void intr_init_vecblk(nodepda_t *, cnodeid_t, int); + #if defined(DEBUG) - extern lock_t intr_dev_targ_map_lock; + extern spinlock_t intr_dev_targ_map_lock; extern uint64_t intr_dev_targ_map_size; /* Initialize the lock to access the device - target cpu mapping @@ -229,7 +214,7 @@ * There is always a cnode 0 present. */ intr_dev_targ_map_size = 0; - init_spinlock(&intr_dev_targ_map_lock,"dtmap_lock",0); + spin_lock_init(&intr_dev_targ_map_lock); } #endif /* DEBUG */ /* Allocate per-node platform-dependent data */ @@ -241,8 +226,6 @@ hubinfo->h_cnodeid = node; hubinfo->h_nasid = COMPACT_TO_NASID_NODEID(node); - printk("init_platform_nodepda: hubinfo 0x%p, &hubinfo->h_crblock 0x%p\n", hubinfo, &hubinfo->h_crblock); - spin_lock_init(&hubinfo->h_crblock); hubinfo->h_widgetid = hub_widget_id(hubinfo->h_nasid); @@ -265,21 +248,18 @@ for (sn=0; sn<NUM_SUBNODES; sn++) { SNPDA(npda,sn)->prof_count = 0; SNPDA(npda,sn)->next_prof_timeout = 0; -// ajm -#ifndef CONFIG_IA64_SGI_IO intr_init_vecblk(npda, node, sn); -#endif } npda->vector_unit_busy = 0; spin_lock_init(&npda->vector_lock); - init_MUTEX_LOCKED(&npda->xbow_sema); /* init it locked? */ + mutex_init_locked(&npda->xbow_sema); /* init it locked? */ spin_lock_init(&npda->fprom_lock); spin_lock_init(&npda->node_utlbswitchlock); npda->ni_error_print = 0; -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER if (need_utlbmiss_patch) { npda->node_need_utlbmiss_patch = 1; npda->node_utlbmiss_patched = 1; @@ -299,7 +279,7 @@ npda->nasid_mask[nasid / 8] |= (1 << nasid % 8); } -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER npda->node_first_cpu = get_cnode_cpu(node); #endif @@ -324,7 +304,7 @@ * may not be guaranteed shared memory at that time * which precludes depending on a global dump stack */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER npda->dump_stack = (uint64_t *)kmem_zalloc_node(DUMP_STACK_SIZE,VM_NOSLEEP, node); ASSERT_ALWAYS(npda->dump_stack); @@ -334,7 +314,7 @@ * both the cpus on a node to proceed with nmi * handling. */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER npda->dump_count = 0; /* Setup the (module,slot) --> nic mapping for all the routers @@ -356,7 +336,7 @@ npda->node_bte_info[i] = (bteinfo_t *)NULL; } #endif -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ } /* XXX - Move the interrupt stuff to intr.c ? */ @@ -369,13 +349,15 @@ void init_platform_pda(cpuid_t cpu) { hub_intmasks_t *intmasks; +#ifdef LATER cpuinfo_t cpuinfo; +#endif int i; cnodeid_t cnode; synergy_da_t *sda; int which_synergy; -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* Allocate per-cpu platform-dependent data */ cpuinfo = (cpuinfo_t)kmem_alloc_node(sizeof(struct cpuinfo_s), GFP_ATOMIC, cputocnode(cpu)); ASSERT_ALWAYS(cpuinfo); @@ -390,7 +372,7 @@ // intmasks = &ppda->p_intmasks; intmasks = &sda->s_intmasks; -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER ASSERT_ALWAYS(&ppda->p_nodepda); #endif @@ -400,15 +382,15 @@ /* Set up pointer to the vector block in the nodepda. */ /* (Cant use SUBNODEPDA - not working yet) */ - intmasks->dispatch0 = &Nodepdaindr[cnode]->snpda[cputosubnode(cpu)].intr_dispatch0; - intmasks->dispatch1 = &Nodepdaindr[cnode]->snpda[cputosubnode(cpu)].intr_dispatch1; + intmasks->dispatch0 = &Nodepdaindr[cnode]->snpda[cpuid_to_subnode(cpu)].intr_dispatch0; + intmasks->dispatch1 = &Nodepdaindr[cnode]->snpda[cpuid_to_subnode(cpu)].intr_dispatch1; /* Clear INT_PEND1 masks. */ for (i = 0; i < N_INTPEND1_MASKS; i++) intmasks->intpend1_masks[i] = 0; -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* Don't read the routers unless we're the master. */ ppda->p_routertick = 0; #endif @@ -419,7 +401,7 @@ #error "need protect_hub_calias, protect_nmi_handler_data" #endif -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* * For now, just protect the first page (exception handlers). We * may want to protect more stuff later. @@ -433,13 +415,6 @@ for (i = 0; i < MAX_REGIONS; i++) { if (i == nasid_to_region(nasid)) continue; -#ifndef BRINGUP - /* Protect the exception handlers. */ - *(__psunsigned_t *)BDPRT_ENTRY(pa, i) = MD_PROT_NO; - - /* Protect the ARCS SPB. */ - *(__psunsigned_t *)BDPRT_ENTRY(pa + 4096, i) = MD_PROT_NO; -#endif } } @@ -455,15 +430,12 @@ for (i = 0; i < MAX_REGIONS; i++) { if (i == nasid_to_region(nasid)) continue; -#ifndef BRINGUP - *(__psunsigned_t *)BDPRT_ENTRY(pa, i) = MD_PROT_NO; -#endif } } -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ -#ifdef IRIX +#ifdef LATER /* * Protect areas of memory that we access uncached by marking them as * poisoned so the T5 can't read them speculatively and erroneously @@ -492,7 +464,7 @@ CACHE_ERR_AREA_SIZE, 1); #error "SN1 not handled correctly" } -#endif /* IRIX */ +#endif /* LATER */ /* * per_hub_init @@ -509,15 +481,10 @@ ii_icmr_u_t ii_icmr; ii_ibcr_u_t ii_ibcr; #endif -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER int i; #endif -#ifdef SIMULATED_KLGRAPH - compact_to_nasid_node[0] = 0; - nasid_to_compact_node[0] = 0; - FIXME("per_hub_init: SIMULATED_KLCONFIG: compact_to_nasid_node[0] = 0\n"); -#endif /* SIMULATED_KLGRAPH */ nasid = COMPACT_TO_NASID_NODEID(cnode); ASSERT(nasid != INVALID_NASID); @@ -546,15 +513,26 @@ if (!done) { npdap = NODEPDA(cnode); +#if defined(CONFIG_IA64_SGI_SYNERGY_PERF) + /* initialize per-node synergy perf instrumentation */ + npdap->synergy_perf_enabled = 0; /* off by default */ + npdap->synergy_perf_lock = SPIN_LOCK_UNLOCKED; + npdap->synergy_perf_freq = SYNERGY_PERF_FREQ_DEFAULT; + npdap->synergy_inactive_intervals = 0; + npdap->synergy_active_intervals = 0; + npdap->synergy_perf_data = NULL; + npdap->synergy_perf_first = NULL; +#endif /* CONFIG_IA64_SGI_SYNERGY_PERF */ + npdap->hub_chip_rev = get_hub_chiprev(nasid); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER for (i = 0; i < CPUS_PER_NODE; i++) { cpu = cnode_slice_to_cpuid(cnode, i); if (!cpu_enabled(cpu)) SET_CPU_LEDS(nasid, i, 0xf); } -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) /* SN1 specific */ @@ -582,7 +560,6 @@ #endif /* SN0_HWDEBUG */ -#ifndef CONFIG_IA64_SGI_IO /* Reserve all of the hardwired interrupt levels. */ intr_reserve_hardwired(cnode); @@ -590,6 +567,7 @@ /* Initialize error interrupts for this hub. */ hub_error_init(cnode); +#ifdef LATER /* Set up correctable memory/directory ECC error interrupt. */ install_eccintr(cnode); @@ -599,7 +577,7 @@ /* Enable RT clock interrupts */ hub_rtc_init(cnode); hub_migrintr_init(cnode); /* Enable migration interrupt */ -#endif +#endif /* LATER */ spin_lock(&hub_mask_lock); CNODEMASK_SETB(hub_init_done_mask, cnode); @@ -609,9 +587,14 @@ /* * Wait for the other CPU to complete the initialization. */ - while (CNODEMASK_TSTB(hub_init_done_mask, cnode) == 0) + while (CNODEMASK_TSTB(hub_init_done_mask, cnode) == 0) { + /* + * On SNIA64 we should never get here .. + */ + printk("WARNING: per_hub_init: Should NEVER get here!\n"); /* LOOP */ ; + } } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/ml_SN_intr.c linux.ac/arch/ia64/sn/io/ml_SN_intr.c --- linux.vanilla/arch/ia64/sn/io/ml_SN_intr.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/ml_SN_intr.c Sat Apr 14 01:18:00 2001 @@ -34,6 +34,8 @@ #include <asm/sn/pci/pcibr.h> #include <asm/sn/xtalk/xtalk.h> #include <asm/sn/pci/pcibr_private.h> +#include <asm/sn/intr.h> + #if DEBUG_INTR_TSTAMP_DEBUG #include <sys/debug.h> @@ -65,6 +67,8 @@ extern cnodeid_t master_node_get(devfs_handle_t vhdl); +extern snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs); + #define INTR_LOCK(vecblk) \ (s = mutex_spinlock(&(vecblk)->vector_lock)) @@ -99,7 +103,7 @@ void intr_stray(void *lvl) { - printk("Stray Interrupt - level %ld to cpu %d", (long)lvl, cpuid()); + PRINT_WARNING("Stray Interrupt - level %ld to cpu %d", (long)lvl, cpuid()); } #if defined(DEBUG) @@ -119,7 +123,7 @@ intr_dev_targ_map_t intr_dev_targ_map[MAX_DEVICES]; uint64_t intr_dev_targ_map_size; -lock_t intr_dev_targ_map_lock; +spinlock_t intr_dev_targ_map_lock; /* Print out the device - target cpu mapping. * This routine is used only in the idbg command @@ -220,7 +224,7 @@ } - spinlock_init(&vecblk->vector_lock, "ivecb"); + mutex_spinlock_init(&vecblk->vector_lock); vecblk->vector_count = 0; for (i = 0; i < CPUS_PER_SUBNODE; i++) @@ -254,7 +258,7 @@ { intr_vecblk_t *vecblk; hub_intmasks_t *hub_intmasks; - int s; + unsigned long s; int rv = 0; int ip; synergy_da_t *sda; @@ -283,8 +287,7 @@ INTR_LOCK(vecblk); if (bit <= -1) { - // bit = 0; - bit = 7; /* First available on SNIA */ + bit = 0; ASSERT(reserve == II_RESERVE); /* Choose any available level */ for (; bit < N_INTPEND_BITS; bit++) { @@ -449,9 +452,9 @@ { intr_vecblk_t *vecblk; hubreg_t *intpend_masks; - int s; int rv = 0; int ip; + unsigned long s; ASSERT(bit < N_INTPEND_BITS * 2); @@ -530,7 +533,7 @@ { intr_vecblk_t *vecblk; hubreg_t *intpend_masks; - int s; + unsigned long s; int rv = 0; int ip; @@ -582,8 +585,8 @@ do_intr_block_bit(cpuid_t cpu, int bit, int block) { intr_vecblk_t *vecblk; - int s; int ip; + unsigned long s; hubreg_t *intpend_masks; volatile hubreg_t mask_value; volatile hubreg_t *mask_reg; @@ -671,7 +674,6 @@ int local_cpu_num; cpu = cnode_slice_to_cpuid(cnode, slice); - cpu = cpu_logical_id(cpu); if (cpu == CPU_NONE) continue; @@ -711,7 +713,7 @@ } -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* * Convert a subnode vertex into a (cnodeid, which_subnode) pair. * Return 0 on success, non-zero on failure. @@ -736,7 +738,7 @@ return(0); /* success */ } -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ /* Make it easy to identify subnode vertices in the hwgraph */ void @@ -755,13 +757,14 @@ } -#ifndef CONFIG_IA64_SGI_IO /* * Given a device descriptor, extract interrupt target information and * choose an appropriate CPU. Return CPU_NONE if we can't make sense * out of the target information. * TBD: Should this be considered platform-independent code? */ + +#ifdef LATER static cpuid_t intr_target_from_desc(device_desc_t dev_desc, int favor_subnode) { @@ -799,10 +802,10 @@ cpuchosen: return(cpuid); } -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* * Check if we had already visited this candidate cnode */ @@ -824,7 +827,7 @@ return(visited_cnodes); } -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ @@ -915,7 +918,7 @@ { cpuid_t cpuid; /* possible intr targ*/ cnodeid_t candidate; /* possible canidate */ -#ifndef BRINGUP +#ifdef LATER cnodeid_t visited_cnodes[MAX_NASIDS], /* nodes seen so far */ center, /* node we are on */ candidate; /* possible canidate */ @@ -926,10 +929,10 @@ */ maxradius = physmem_maxradius(); void *rv; -#endif /* BRINGUP */ +#endif /* LATER */ int which_subnode = SUBNODE_ANY; -#if CONFIG_IA64_SGI_IO /* SN1 + pcibr Addressing Limitation */ +/* SN1 + pcibr Addressing Limitation */ { devfs_handle_t pconn_vhdl; pcibr_soft_t pcibr_soft; @@ -962,9 +965,8 @@ } } } -#endif /* CONFIG_IA64_SGI_IO */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* * If an interrupt target was specified for this * interrupt allocation, try to use it. @@ -998,7 +1000,7 @@ */ } -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ /* Check if we can find a valid interrupt target candidate on * the master node for the device. @@ -1019,7 +1021,7 @@ intr_unreserve_level(cpuid, *resp_bit); } - printk("Cannot target interrupts to closest node(%d): %ld (0x%lx)\n", + PRINT_WARNING("Cannot target interrupts to closest node(%d): %ld (0x%lx)\n", master_node_get(dev),(long) owner_dev, (unsigned long)owner_dev); /* Fall through into the default algorithm @@ -1076,10 +1078,11 @@ #else /* BRINGUP */ { // Do a stupid round-robin assignment of the node. - static cnodeid_t last_node = 0; + static cnodeid_t last_node = -1; - if (last_node > numnodes) last_node = 0; - for (candidate = last_node; candidate <= numnodes; candidate++) { + if (last_node >= numnodes) last_node = 0; + for (candidate = last_node + 1; candidate != last_node; candidate++) { + if (candidate == numnodes) candidate = 0; cpuid = intr_bit_reserve_test(CPU_NONE, which_subnode, candidate, @@ -1091,18 +1094,18 @@ if (cpuid != CPU_NONE) { if (cpu_on_subnode(cpuid, which_subnode)) { - last_node++; + last_node = candidate; return(cpuid); /* got a valid interrupt target */ } else intr_unreserve_level(cpuid, *resp_bit); } - last_node++; } + last_node = candidate; } #endif - printk("Cannot target interrupts to any close node: %ld (0x%lx)\n", + PRINT_WARNING("Cannot target interrupts to any close node: %ld (0x%lx)\n", (long)owner_dev, (unsigned long)owner_dev); /* In the worst case try to allocate interrupt bits on the @@ -1127,7 +1130,7 @@ intr_unreserve_level(cpuid, *resp_bit); } - printk("Cannot target interrupts: %ld (0x%lx)\n", + PRINT_WARNING("Cannot target interrupts: %ld (0x%lx)\n", (long)owner_dev, (unsigned long)owner_dev); return(CPU_NONE); /* Should never get here */ @@ -1515,6 +1518,7 @@ } } +#endif /* BRINGUP */ struct hardwired_intr_s { signed char level; @@ -1525,17 +1529,9 @@ { INT_PEND0_BASELVL + GFX_INTR_A, 0, "Gfx A" }, { INT_PEND0_BASELVL + GFX_INTR_B, 0, "Gfx B" }, { INT_PEND0_BASELVL + PG_MIG_INTR, II_THREADED, "Migration" }, -#if defined(SN1) && !defined(DIRECT_L1_CONSOLE) { INT_PEND0_BASELVL + UART_INTR, II_THREADED, "Bedrock/L1" }, -#else - { INT_PEND0_BASELVL + UART_INTR, 0, "Hub I2C" }, -#endif { INT_PEND0_BASELVL + CC_PEND_A, 0, "Crosscall A" }, { INT_PEND0_BASELVL + CC_PEND_B, 0, "Crosscall B" }, - { INT_PEND0_BASELVL + MSC_MESG_INTR, II_THREADED, "MSC Message" }, - { INT_PEND0_BASELVL + CPU_ACTION_A, 0, "CPU Action A" }, - { INT_PEND0_BASELVL + CPU_ACTION_B, 0, "CPU Action B" }, - { INT_PEND1_BASELVL + IO_ERROR_INTR, II_ERRORINT, "IO Error" }, { INT_PEND1_BASELVL + CLK_ERR_INTR, II_ERRORINT, "Clock Error" }, { INT_PEND1_BASELVL + COR_ERR_INTR_A, II_ERRORINT, "Correctable Error A" }, { INT_PEND1_BASELVL + COR_ERR_INTR_B, II_ERRORINT, "Correctable Error B" }, @@ -1546,13 +1542,11 @@ { INT_PEND1_BASELVL + MSC_PANIC_INTR, II_ERRORINT, "MSC Panic" }, { INT_PEND1_BASELVL + LLP_PFAIL_INTR_A, II_ERRORINT, "LLP Pfail WAR" }, { INT_PEND1_BASELVL + LLP_PFAIL_INTR_B, II_ERRORINT, "LLP Pfail WAR" }, -#ifdef SN1 { INT_PEND1_BASELVL + NACK_INT_A, 0, "CPU A Nack count == NACK_CMP" }, { INT_PEND1_BASELVL + NACK_INT_B, 0, "CPU B Nack count == NACK_CMP" }, { INT_PEND1_BASELVL + LB_ERROR, 0, "Local Block Error" }, { INT_PEND1_BASELVL + XB_ERROR, 0, "Local XBar Error" }, -#endif /* SN1 */ - { -1, 0, (char *)NULL} + { -1, 0, (char *)NULL}, }; /* @@ -1567,7 +1561,13 @@ int i; char subnode_done[NUM_SUBNODES]; - cpu = cnodetocpu(cnode); + // cpu = cnodetocpu(cnode); + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + if (cpuid_to_cnodeid(cpu) == cnode) { + break; + } + } + if (cpu == smp_num_cpus) cpu = CPU_NONE; if (cpu == CPU_NONE) { printk("Node %d has no CPUs", cnode); return; @@ -1576,7 +1576,7 @@ for (i=0; i<NUM_SUBNODES; i++) subnode_done[i] = 0; - for (; cpu<maxcpus && cpu_enabled(cpu) && cputocnode(cpu) == cnode; cpu++) { + for (; cpu<smp_num_cpus && cpu_enabled(cpu) && cpuid_to_cnodeid(cpu) == cnode; cpu++) { int which_subnode = cpuid_to_subnode(cpu); if (subnode_done[which_subnode]) continue; @@ -1594,7 +1594,6 @@ } } -#endif /* BRINGUP */ /* * Check and clear interrupts. @@ -1612,7 +1611,7 @@ for (i = 0; i < N_INTPEND_BITS; i++) { if (bits & (1 << i)) { #ifdef INTRDEBUG - printk( "Nasid %d interrupt bit %d set in %s", + PRINT_WARNING("Nasid %d interrupt bit %d set in %s", nasid, i, name); #endif LOCAL_HUB_CLR_INTR(base_level + i); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/ml_iograph.c linux.ac/arch/ia64/sn/io/ml_iograph.c --- linux.vanilla/arch/ia64/sn/io/ml_iograph.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/ml_iograph.c Sat Apr 14 01:18:00 2001 @@ -32,6 +32,13 @@ extern int maxnodes; +/* #define IOGRAPH_DEBUG */ +#ifdef IOGRAPH_DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* IOGRAPH_DEBUG */ + /* #define PROBE_TEST */ /* At most 2 hubs can be connected to an xswitch */ @@ -44,7 +51,7 @@ * xswitch vertex is created. */ typedef struct xswitch_vol_s { - struct semaphore xswitch_volunteer_mutex; + mutex_t xswitch_volunteer_mutex; int xswitch_volunteer_count; devfs_handle_t xswitch_volunteer[NUM_XSWITCH_VOLUNTEER]; } *xswitch_vol_t; @@ -56,7 +63,7 @@ int rc; xvolinfo = kmalloc(sizeof(struct xswitch_vol_s), GFP_KERNEL); - init_MUTEX(&xvolinfo->xswitch_volunteer_mutex); + mutex_init(&xvolinfo->xswitch_volunteer_mutex); xvolinfo->xswitch_volunteer_count = 0; rc = hwgraph_info_add_LBL(xswitch, INFO_LBL_XSWITCH_VOL, @@ -78,7 +85,7 @@ rc = hwgraph_info_remove_LBL(xswitch, INFO_LBL_XSWITCH_VOL, (arbitrary_info_t *)&xvolinfo); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER ASSERT(rc == GRAPH_SUCCESS); rc = rc; #endif @@ -97,64 +104,26 @@ INFO_LBL_XSWITCH_VOL, (arbitrary_info_t *)&xvolinfo); if (xvolinfo == NULL) { -#ifndef CONFIG_IA64_SGI_IO - if (!is_headless_node_vertex(master)) - cmn_err(CE_WARN, - "volunteer for widgets: vertex %v has no info label", +#ifdef LATER + if (!is_headless_node_vertex(master)) { +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_WARNING("volunteer for widgets: vertex %v has no info label", + xswitch); +#else + PRINT_WARNING("volunteer for widgets: vertex 0x%x has no info label", xswitch); #endif + } +#endif /* LATER */ return; } -#ifndef CONFIG_IA64_SGI_IO - mutex_lock(&xvolinfo->xswitch_volunteer_mutex, PZERO); -#endif + mutex_lock(&xvolinfo->xswitch_volunteer_mutex); ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER); xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master; xvolinfo->xswitch_volunteer_count++; -#ifndef CONFIG_IA64_SGI_IO mutex_unlock(&xvolinfo->xswitch_volunteer_mutex); -#endif -} - -#ifndef BRINGUP -/* - * The "ideal fixed assignment" of 12 IO slots to 4 node slots. - * At index N is the node slot number of the node board that should - * ideally control the widget in IO slot N. Note that if there is - * only one node board on a given xbow, it will control all of the - * devices on that xbow regardless of these defaults. - * - * N1 controls IO slots IO1, IO3, IO5 (upper left) - * N3 controls IO slots IO2, IO4, IO6 (upper right) - * N2 controls IO slots IO7, IO9, IO11 (lower left) - * N4 controls IO slots IO8, IO10, IO12 (lower right) - * - * This makes assignments predictable and easily controllable. - * TBD: Allow administrator to override these defaults. - */ -static slotid_t ideal_assignment[] = { - -1, /* IO0 -->non-existent */ - 1, /* IO1 -->N1 */ - 3, /* IO2 -->N3 */ - 1, /* IO3 -->N1 */ - 3, /* IO4 -->N3 */ - 1, /* IO5 -->N1 */ - 3, /* IO6 -->N3 */ - 2, /* IO7 -->N2 */ - 4, /* IO8 -->N4 */ - 2, /* IO9 -->N2 */ - 4, /* IO10-->N4 */ - 2, /* IO11-->N2 */ - 4 /* IO12-->N4 */ -}; - -static int -is_ideal_assignment(slotid_t hubslot, slotid_t ioslot) -{ - return(ideal_assignment[ioslot] == hubslot); } -#endif /* ifndef BRINGUP */ extern int xbow_port_io_enabled(nasid_t nasid, int widgetnum); @@ -166,15 +135,12 @@ static void assign_widgets_to_volunteers(devfs_handle_t xswitch, devfs_handle_t hubv) { + int curr_volunteer, num_volunteer; + xwidgetnum_t widgetnum; xswitch_info_t xswitch_info; xswitch_vol_t xvolinfo = NULL; - xwidgetnum_t widgetnum; - int curr_volunteer, num_volunteer; nasid_t nasid; hubinfo_t hubinfo; -#ifndef BRINGUP - int xbownum; -#endif hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; @@ -186,13 +152,19 @@ INFO_LBL_XSWITCH_VOL, (arbitrary_info_t *)&xvolinfo); if (xvolinfo == NULL) { -#ifndef CONFIG_IA64_SGI_IO - if (!is_headless_node_vertex(hubv)) - cmn_err(CE_WARN, - "assign_widgets_to_volunteers:vertex %v has " +#ifdef LATER + if (!is_headless_node_vertex(hubv)) { +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_WARNING("assign_widgets_to_volunteers:vertex %v has " + " no info label", + xswitch); +#else + PRINT_WARNING("assign_widgets_to_volunteers:vertex 0x%x has " " no info label", xswitch); #endif + } +#endif /* LATER */ return; } @@ -206,10 +178,6 @@ xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv); } -#ifndef BRINGUP - xbownum = get_node_crossbow(nasid); -#endif /* ifndef BRINGUP */ - /* * TBD: Use administrative information to alter assignment of * widgets to hubs. @@ -239,29 +207,12 @@ if (nasid == get_console_nasid()) goto do_assignment; } -#ifndef CONFIG_IA64_SGI_IO - cmn_err(CE_PANIC, - "Nasid == %d, console nasid == %d", +#ifdef LATER + PRINT_PANIC("Nasid == %d, console nasid == %d", nasid, get_console_nasid()); #endif } -#ifndef BRINGUP - /* - * Try to do the "ideal" assignment if IO slots to nodes. - */ - for (i=0; i<num_volunteer; i++) { - hubv = xvolinfo->xswitch_volunteer[i]; - hubinfo_get(hubv, &hubinfo); - nasid = hubinfo->h_nasid; - if (is_ideal_assignment(SLOTNUM_GETSLOT(get_node_slotid(nasid)), - SLOTNUM_GETSLOT(get_widget_slotnum(xbownum, widgetnum)))) { - - goto do_assignment; - - } - } -#endif /* ifndef BRINGUP */ /* * Do a round-robin assignment among the volunteer nodes. @@ -301,13 +252,13 @@ for(cnode = 0; cnode < numnodes; cnode++) { nasid = COMPACT_TO_NASID_NODEID(cnode); board = (lboard_t *)KL_CONFIG_INFO(nasid); - printk("iograph_early_init: Found board 0x%p\n", board); + DBG("iograph_early_init: Found board 0x%p\n", board); /* Check out all the board info stored on a node */ while(board) { board->brd_graph_link = GRAPH_VERTEX_NONE; board = KLCF_NEXT(board); - printk("iograph_early_init: Found board 0x%p\n", board); + DBG("iograph_early_init: Found board 0x%p\n", board); } @@ -316,7 +267,7 @@ hubio_init(); } -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* There is an identical definition of this in os/scheduler/runq.c */ #define INIT_COOKIE(cookie) cookie.must_run = 0; cookie.cpu = PDA_RUNANYWHERE /* @@ -363,12 +314,11 @@ { restoremustrun(cookie); } -static sema_t io_init_sema; - -#endif /* !CONFIG_IA64_SGI_IO */ - -struct semaphore io_init_sema; +#endif /* LATER */ +#ifdef LINUX_KERNEL_THREADS +static struct semaphore io_init_sema; +#endif /* * Let boot processor know that we're done initializing our node's IO @@ -378,9 +328,11 @@ static void io_init_done(cnodeid_t cnodeid,cpu_cookie_t c) { -#ifndef CONFIG_IA64_SGI_IO /* Let boot processor know that we're done. */ +#ifdef LINUX_KERNEL_THREADS up(&io_init_sema); +#endif +#ifdef LATER /* This is for the setnoderun done when the io_init thread * started */ @@ -420,17 +372,12 @@ * We're able to read from a widget because our hub's * WIDGET_ID was set up earlier. */ -#ifdef BRINGUP widgetreg_t widget_id = *(volatile widgetreg_t *) (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID); - printk("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id, + DBG("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id, (volatile widgetreg_t *)(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID) ); -#else /* !BRINGUP */ - widgetreg_t widget_id = XWIDGET_ID_READ(nasid, 0); -#endif /* BRINGUP */ - hwid->part_num = XWIDGET_PART_NUM(widget_id); hwid->rev_num = XWIDGET_REV_NUM(widget_id); hwid->mfg_num = XWIDGET_MFG_NUM(widget_id); @@ -438,8 +385,6 @@ /* TBD: link reset */ } else { - panic("\n\n**** early_probe_for_widget: Hub Vertex 0x%p is DOWN llp_csr_reg 0x%x ****\n\n", hubv, llp_csr_reg); - hwid->part_num = XWIDGET_PART_NUM_NONE; hwid->rev_num = XWIDGET_REV_NUM_NONE; hwid->mfg_num = XWIDGET_MFG_NUM_NONE; @@ -499,8 +444,9 @@ moduleid_t module; slotid_t slot; lboard_t *board = NULL; + char buffer[16]; - printk("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum); + DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum); /* * Verify that xswitchv is indeed an attached xswitch. */ @@ -546,8 +492,8 @@ * but I don't feel like figuring out vhdl right now.. * and I know for a fact the answer is 0x2d000049 */ - printk("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n"); - printk("XWIDGET_PART_NUM(0x2d000049)= 0x%x\n", XWIDGET_PART_NUM(0x2d000049)); + DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n"); + DBG("XWIDGET_PART_NUM(0x2d000049)= 0x%x\n", XWIDGET_PART_NUM(0x2d000049)); if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM) { #else if (nasid_has_xbridge(nasid)) { @@ -557,8 +503,18 @@ module, KLTYPE_IOBRICK); - if (board) - printk("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type); +DBG("io_xswitch_widget_init: Board 0x%p\n", board); +{ + lboard_t dummy; + + if (board) { + DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type); + } else { + DBG("io_xswitch_widget_init: FIXME did not find IOBOARD\n"); + board = &dummy; + } + +} /* * BRINGUP @@ -568,11 +524,16 @@ #ifdef SUPPORT_PRINTING_M_FORMAT sprintf(pathname, EDGE_LBL_MODULE "/%M/" -#else - sprintf(pathname, EDGE_LBL_MODULE "/%x/" -#endif "%cbrick" "/%s/%d", NODEPDA(cnode)->module_id, + +#else + memset(buffer, 0, 16); + format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF); + sprintf(pathname, EDGE_LBL_MODULE "/%s/" + "%cbrick" "/%s/%d", + buffer, +#endif #ifdef BRINGUP (board->brd_type == KLTYPE_IBRICK) ? 'I' : @@ -584,7 +545,7 @@ EDGE_LBL_XTALK, widgetnum); } - printk("io_xswitch_widget_init: path= %s\n", pathname); + DBG("io_xswitch_widget_init: path= %s\n", pathname); rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv); ASSERT(rc == GRAPH_SUCCESS); @@ -612,7 +573,7 @@ module = NODEPDA(cnode)->module_id; #ifdef XBRIDGE_REGS_SIM - printk("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n"); + DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n"); if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM) { #else if (nasid_has_xbridge(nasid)) { @@ -647,16 +608,21 @@ */ #ifdef SUPPORT_PRINTING_M_FORMAT sprintf(pathname, EDGE_LBL_MODULE "/%M/" + EDGE_LBL_SLOT "/%s/%s", + NODEPDA(cnode)->module_id, + slotname, new_name); #else - sprintf(pathname, EDGE_LBL_MODULE "/%x/" -#endif + memset(buffer, 0, 16); + format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF); + sprintf(pathname, EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLOT "/%s/%s", - NODEPDA(cnode)->module_id, + buffer, slotname, new_name); +#endif } rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv); - printk("io_xswitch_widget_init: (2) path= %s\n", pathname); + DBG("io_xswitch_widget_init: (2) path= %s\n", pathname); /* * This is a weird ass code needed for error injection * purposes. @@ -666,7 +632,7 @@ klhwg_baseio_inventory_add(widgetv,cnode); } sprintf(name, "%d", widgetnum); - printk("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv); + DBG("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv); rc = hwgraph_edge_add(xswitchv, widgetv, name); /* @@ -683,7 +649,7 @@ */ #ifdef XBRIDGE_REGS_SIM widget_id = 0x2d000049; - printk("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: id hardwired to widget_id\n"); + DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: id hardwired to widget_id\n"); #else widget_id = XWIDGET_ID_READ(nasid, widgetnum); #endif /* XBRIDGE_REGS_SIM */ @@ -715,21 +681,13 @@ aa = async_attach_new(); - printk("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode); + DBG("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode); for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { -#ifdef BRINGUP - if (widgetnum != 0xe) - io_xswitch_widget_init(xswitchv, - cnodeid_to_vertex(cnode), - widgetnum, aa); - -#else io_xswitch_widget_init(xswitchv, cnodeid_to_vertex(cnode), widgetnum, aa); -#endif /* BRINGUP */ } /* * Wait for parallel attach threads, if any, to complete. @@ -798,9 +756,12 @@ #endif /* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 */ } if (board == NULL) { -#ifndef CONFIG_IA64_SGI_IO - cmn_err(CE_WARN, - "Could not find PROM info for vertex %v, " +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_WARNING("Could not find PROM info for vertex %v, " + "FRU analyzer may fail", + vhdl); +#else + PRINT_WARNING("Could not find PROM info for vertex 0x%x, " "FRU analyzer may fail", vhdl); #endif @@ -828,16 +789,13 @@ hubinfo_t hubinfo; int is_xswitch; nodepda_t *npdap; -#ifndef CONFIG_IA64_SGI_IO - sema_t *peer_sema = 0; -#else struct semaphore *peer_sema = 0; -#endif uint32_t widget_partnum; nodepda_router_info_t *npda_rip; cpu_cookie_t c = 0; + extern int hubdev_docallouts(devfs_handle_t); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* Try to execute on the node that we're initializing. */ c = setnoderun(cnodeid); #endif @@ -851,13 +809,11 @@ * form /hw/module/%M/slot/%d/node */ hubv = cnodeid_to_vertex(cnodeid); - printk("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap); + DBG("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap); ASSERT(hubv != GRAPH_VERTEX_NONE); -#if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC hubdev_docallouts(hubv); -#endif /* * Set up the dependent routers if we have any. @@ -877,10 +833,10 @@ /* * Read mfg info on this hub */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER printk("io_init_node: FIXME need to implement HUB_VERTEX_MFG_INFO\n"); HUB_VERTEX_MFG_INFO(hubv); -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ /* * If nothing connected to this hub's xtalk port, we're done. @@ -892,7 +848,7 @@ int index; for (index = 0; index < 600; index++) - printk("Interfering with device probing!!!\n"); + DBG("Interfering with device probing!!!\n"); } #endif /* io_init_done takes cpu cookie as 2nd argument @@ -900,8 +856,8 @@ * at the start of this thread */ - printk("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv); - io_init_done(cnodeid,c); + DBG("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv); + return; /* NOTREACHED */ } @@ -931,13 +887,13 @@ (void)hwgraph_path_add(hubv, EDGE_LBL_XTALK, &switchv); - printk("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv); + DBG("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv); ASSERT(switchv != GRAPH_VERTEX_NONE); (void)hwgraph_edge_add(hubv, switchv, EDGE_LBL_IO); - printk("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n"); + DBG("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n"); /* * We need to find the widget id and update the basew_id field @@ -951,7 +907,7 @@ widget_partnum == XBRIDGE_WIDGET_PART_NUM){ npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID); - printk("io_init_node: Found XBRIDGE widget_partnum= 0x%x\n", widget_partnum); + DBG("io_init_node: Found XBRIDGE widget_partnum= 0x%x\n", widget_partnum); } else if (widget_partnum == XBOW_WIDGET_PART_NUM || widget_partnum == XXBOW_WIDGET_PART_NUM) { @@ -959,7 +915,7 @@ * Xbow control register does not have the widget ID field. * So, hard code the widget ID to be zero. */ - printk("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum); + DBG("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum); npdap->basew_id = 0; #if defined(BRINGUP) @@ -982,7 +938,7 @@ char widname[10]; sprintf(widname, "%x", npdap->basew_id); (void)hwgraph_path_add(switchv, widname, &widgetv); - printk("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv); + DBG("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv); ASSERT(widgetv != GRAPH_VERTEX_NONE); } @@ -1043,13 +999,13 @@ /* Signal that we're done */ if (peer_sema) { - up(peer_sema); + mutex_unlock(peer_sema); } } else { /* Wait 'til master is done assigning widgets. */ - down(&npdap->xbow_sema); + mutex_lock(&npdap->xbow_sema); } #ifdef PROBE_TEST @@ -1057,7 +1013,7 @@ int index; for (index = 0; index < 500; index++) - printk("Interfering with device probing!!!\n"); + DBG("Interfering with device probing!!!\n"); } #endif /* Now both nodes can safely inititialize widgets */ @@ -1070,15 +1026,12 @@ */ io_init_done(cnodeid,c); - printk("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid); + DBG("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid); } #define IOINIT_STKSZ (16 * 1024) -#ifndef CONFIG_IA64_SGI_IO -#include <sys/sn/iograph.h> -#endif #define __DEVSTR1 "/../.master/" #define __DEVSTR2 "/target/" #define __DEVSTR3 "/lun/0/disk/partition/" @@ -1145,6 +1098,7 @@ {"15/" EDGE_LBL_PCI "/3/" EDGE_LBL_SCSI_CTLR "/0", 2}, {"14/" EDGE_LBL_PCI "/1/" EDGE_LBL_SCSI_CTLR "/0", 3}, {"14/" EDGE_LBL_PCI "/2/" EDGE_LBL_SCSI_CTLR "/0", 4}, + {"15/" EDGE_LBL_PCI "/6/ohci/0/" EDGE_LBL_SCSI_CTLR "/0", 5}, {NULL, -1} /* must be last */ }; @@ -1181,11 +1135,7 @@ } -#ifndef CONFIG_IA64_SGI_IO -#include <sys/asm/sn/ioerror_handling.h> -#else #include <asm/sn/ioerror_handling.h> -#endif extern devfs_handle_t ioc3_console_vhdl_get(void); devfs_handle_t sys_critical_graph_root = GRAPH_VERTEX_NONE; @@ -1203,7 +1153,7 @@ int slot; devfs_handle_t baseio_console_conn; - printk("sys_critical_graph_init: FIXME.\n"); + DBG("sys_critical_graph_init: FIXME.\n"); baseio_console_conn = hwgraph_connectpt_get(baseio_console_vhdl); if (baseio_console_conn == NULL) { @@ -1303,7 +1253,7 @@ devfs_handle_t console_vhdl, pci_vhdl, enet_vhdl; - printk("baseio_ctlr_num_set; FIXME\n"); + DBG("baseio_ctlr_num_set; FIXME\n"); console_vhdl = ioc3_console_vhdl_get(); if (console_vhdl == GRAPH_VERTEX_NONE) return; @@ -1384,10 +1334,8 @@ else { rtn_val = pcibr_alloc_all_rrbs(vhdl, 0, 4,1, 4,0, 0,0, 0,0); } -#ifndef CONFIG_IA64_SGI_IO if (rtn_val) - cmn_err(CE_WARN, "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed"); -#endif + PRINT_WARNING("sn00_rrb_alloc: pcibr_alloc_all_rrbs failed"); if ((vendor_list[5] != PCIIO_VENDOR_ID_NONE) && (vendor_list[7] != PCIIO_VENDOR_ID_NONE)) { @@ -1406,10 +1354,8 @@ /* nothing in slot 5 or 7 */ rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 4,1, 4,0, 0,0, 0,0); } -#ifndef CONFIG_IA64_SGI_IO if (rtn_val) - cmn_err(CE_WARN, "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed"); -#endif + PRINT_WARNING("sn00_rrb_alloc: pcibr_alloc_all_rrbs failed"); } @@ -1423,17 +1369,18 @@ /* Governor on init threads..bump up when safe * (beware many devfs races) */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER int io_init_node_threads = 2; #endif cnodeid_t cnodeid, active; - init_MUTEX(&io_init_sema); - +#ifdef LINUX_KERNEL_THREADS + sema_init(&io_init_sema, 0); +#endif active = 0; for (cnodeid = 0; cnodeid < maxnodes; cnodeid++) { -#ifndef CONFIG_IA64_SGI_IO +#ifdef LINUX_KERNEL_THREADS char thread_name[16]; extern int io_init_pri; @@ -1448,20 +1395,17 @@ io_init_pri, KT_PS, (st_func_t *)io_init_node, (void *)(long)cnodeid, 0, 0, 0); #else - printk("init_all_devices: Calling io_init_node() for cnode %d\n", cnodeid); + DBG("init_all_devices: Calling io_init_node() for cnode %d\n", cnodeid); io_init_node(cnodeid); - printk("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid); - -#endif /* !CONFIG_IA64_SGI_IO */ + DBG("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid); +#endif /* LINUX_KERNEL_THREADS */ +#ifdef LINUX_KERNEL_THREADS /* Limit how many nodes go at once, to not overload hwgraph */ /* TBD: Should timeout */ -#ifdef AA_DEBUG - printk("started thread for cnode %d\n", cnodeid); -#endif -#ifdef LINUX_KERNEL_THREADS + DBG("started thread for cnode %d\n", cnodeid); active++; if (io_init_node_threads && active >= io_init_node_threads) { @@ -1476,9 +1420,9 @@ while (active > 0) { #ifdef AA_DEBUG - printk("waiting, %d still active\n", active); + DBG("waiting, %d still active\n", active); #endif - sema(&io_init_sema); + down(&io_init_sema); active--; } @@ -1534,22 +1478,22 @@ int i; int viable_found = 0; - printk("Only controller numbers 0..%d are supported for\n", NUM_BASE_IO_SCSI_CTLR-1); - printk("prom \"root\" variables of the form dksXdXsX.\n"); - printk("To use another disk you must use the full hardware graph path\n\n"); - printk("Possible controller numbers for use in 'dksXdXsX' on this system: "); + DBG("Only controller numbers 0..%d are supported for\n", NUM_BASE_IO_SCSI_CTLR-1); + DBG("prom \"root\" variables of the form dksXdXsX.\n"); + DBG("To use another disk you must use the full hardware graph path\n\n"); + DBG("Possible controller numbers for use in 'dksXdXsX' on this system: "); for (i=0; i<NUM_BASE_IO_SCSI_CTLR; i++) { if (base_io_scsi_ctlr_vhdl[i] != GRAPH_VERTEX_NONE) { - printk("%d ", i); + DBG("%d ", i); viable_found=1; } } if (viable_found) - printk("\n"); + DBG("\n"); else - printk("none found!\n"); + DBG("none found!\n"); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER if (kdebug) debug("ring"); #endif @@ -1579,4 +1523,132 @@ *tmp2++ = '/'; strcpy(tmp2, EDGE_LBL_BLOCK); strcpy(devnm,tmpnm); +} + +static +struct io_brick_map_s io_brick_tab[] = { + +/* Ibrick widget number to PCI bus number map */ + { + 'I', /* Ibrick type */ + /* PCI Bus # Widget # */ + { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ + 0, /* 0x8 */ + 0, /* 0x9 */ + 0, 0, /* 0xa - 0xb */ + 0, /* 0xc */ + 0, /* 0xd */ + 2, /* 0xe */ + 1 /* 0xf */ + } + }, + +/* Pbrick widget number to PCI bus number map */ + { + 'P', /* Pbrick type */ + /* PCI Bus # Widget # */ + { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ + 2, /* 0x8 */ + 1, /* 0x9 */ + 0, 0, /* 0xa - 0xb */ + 5, /* 0xc */ + 6, /* 0xd */ + 4, /* 0xe */ + 3 /* 0xf */ + } + }, + +/* Xbrick widget to XIO slot map */ + { + 'X', /* Xbrick type */ + /* XIO Slot # Widget # */ + { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ + 1, /* 0x8 */ + 2, /* 0x9 */ + 0, 0, /* 0xa - 0xb */ + 3, /* 0xc */ + 4, /* 0xd */ + 0, /* 0xe */ + 0 /* 0xf */ + } + } +}; + +/* + * Use the brick's type to map a widget number to a meaningful int + */ +int +io_brick_map_widget(char brick_type, int widget_num) +{ + int num_bricks, i; + + /* Calculate number of bricks in table */ + num_bricks = sizeof(io_brick_tab)/sizeof(io_brick_tab[0]); + + /* Look for brick prefix in table */ + for (i = 0; i < num_bricks; i++) { + if (brick_type == io_brick_tab[i].ibm_type) + return(io_brick_tab[i].ibm_map_wid[widget_num]); + } + + return 0; + +} + +/* + * Use the device's vertex to map the device's widget to a meaningful int + */ +int +io_path_map_widget(devfs_handle_t vertex) +{ + char hw_path_name[MAXDEVNAME]; + char *wp, *bp, *sp = NULL; + int widget_num; + long atoi(char *); + int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen); + + + /* Get the full path name of the vertex */ + if (GRAPH_SUCCESS != hwgraph_vertex_name_get(vertex, hw_path_name, + MAXDEVNAME)) + return 0; + + /* Find the widget number in the path name */ + wp = strstr(hw_path_name, "/"EDGE_LBL_XTALK"/"); + if (wp == NULL) + return 0; + widget_num = atoi(wp+7); + if (widget_num < XBOW_PORT_8 || widget_num > XBOW_PORT_F) + return 0; + + /* Find "brick" in the path name */ + bp = strstr(hw_path_name, "brick"); + if (bp == NULL) + return 0; + + /* Find preceding slash */ + sp = bp; + while (sp > hw_path_name) { + sp--; + if (*sp == '/') + break; + } + + /* Invalid if no preceding slash */ + if (!sp) + return 0; + + /* Bump slash pointer to "brick" prefix */ + sp++; + /* + * Verify "brick" prefix length; valid exaples: + * 'I' from "/Ibrick" + * 'P' from "/Pbrick" + * 'X' from "/Xbrick" + */ + if ((bp - sp) != 1) + return 0; + + return (io_brick_map_widget(*sp, widget_num)); + } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/module.c linux.ac/arch/ia64/sn/io/module.c --- linux.vanilla/arch/ia64/sn/io/module.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/module.c Sat Apr 14 01:18:00 2001 @@ -9,13 +9,11 @@ */ #include <linux/types.h> -#include <linux/config.h> #include <linux/slab.h> #include <asm/sn/sgi.h> #include <asm/sn/invent.h> #include <asm/sn/hcl.h> #include <asm/sn/labelcl.h> -#include <asm/sn/cmn_err.h> #include <asm/sn/xtalk/xbow.h> #include <asm/sn/pci/bridge.h> #include <asm/sn/klconfig.h> @@ -24,12 +22,17 @@ #include <asm/sn/pci/pcibr.h> #include <asm/sn/xtalk/xswitch.h> #include <asm/sn/nodepda.h> +#include <asm/sn/sn_cpuid.h> -#define LDEBUG 1 +/* #define LDEBUG 1 */ -#define DPRINTF if (LDEBUG) printk +#ifdef LDEBUG +#define DPRINTF printk #define printf printk +#else +#define DPRINTF(x...) +#endif module_t *modules[MODULE_MAX]; int nummodules; @@ -100,8 +103,6 @@ { int i; - DPRINTF("module_lookup: id=%d\n", id); - for (i = 0; i < nummodules; i++) if (modules[i]->id == id) { DPRINTF("module_lookup: found m=0x%p\n", modules[i]); @@ -125,29 +126,29 @@ { module_t *m; int i; + char buffer[16]; - DPRINTF("module_add_node: id=%x node=%d\n", id, n); +#ifdef __ia64 + memset(buffer, 0, 16); + format_module_id(buffer, id, MODULE_FORMAT_BRIEF); + DPRINTF("module_add_node: id=%s node=%d\n", buffer, n); +#endif if ((m = module_lookup(id)) == 0) { -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER m = kmem_zalloc_node(sizeof (module_t), KM_NOSLEEP, n); #else m = kmalloc(sizeof (module_t), GFP_KERNEL); memset(m, 0 , sizeof(module_t)); - printk("Module nodecnt = %d\n", m->nodecnt); #endif ASSERT_ALWAYS(m); - DPRINTF("module_add_node: m=0x%p\n", m); - m->id = id; spin_lock_init(&m->lock); - init_MUTEX_LOCKED(&m->thdcnt); + mutex_init_locked(&m->thdcnt); -printk("Set elsc to 0x%p on node %d\n", &m->elsc, get_nasid()); - -set_elsc(&m->elsc); +// set_elsc(&m->elsc); elsc_init(&m->elsc, COMPACT_TO_NASID_NODEID(n)); spin_lock_init(&m->elsclock); @@ -162,8 +163,7 @@ m->nodes[m->nodecnt++] = n; -printk("module_add_node: module %x now has %d nodes\n", id, m->nodecnt); - DPRINTF("module_add_node: module %x now has %d nodes\n", id, m->nodecnt); + DPRINTF("module_add_node: module %s now has %d nodes\n", buffer, m->nodecnt); return m; } @@ -172,6 +172,7 @@ { lboard_t *board; klmod_serial_num_t *comp; + char * bcopy(const char * src, char * dest, int count); board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_MIDPLANE8); @@ -204,14 +205,8 @@ if (m->snum_valid) return 1; else { -#ifndef CONFIG_IA64_SGI_IO - cmn_err(CE_WARN | CE_MAINTENANCE, - "Invalid serial number for module %d, " - "possible missing or invalid NIC.", m->id); -#else - printk("Invalid serial number for module %d, " + DPRINTF("Invalid serial number for module %d, " "possible missing or invalid NIC.", m->id); -#endif return 0; } } @@ -246,32 +241,12 @@ nserial); if (nserial == 0) - cmn_err(CE_WARN, "No serial number found."); + PRINT_WARNING("io_module_init: No serial number found.\n"); } -#ifdef BRINGUP -elsc_t *Elsc[100]; - -void -set_elsc(elsc_t *p) -{ - Elsc[get_nasid()] = p; -} -#endif - elsc_t *get_elsc(void) { -#ifdef BRINGUP -return(Elsc[get_nasid()]); -#else - if ( NODEPDA(get_nasid())->module == (module_t *)0 ) { - printf("get_elsc() for nasd %d fails\n", get_nasid()); -// return((elsc_t *)0); - } - return &NODEPDA(get_nasid())->module->elsc; - -// return &NODEPDA(NASID_TO_COMPACT_NODEID(0))->module->elsc; -#endif + return &NODEPDA(cpuid_to_cnodeid(smp_processor_id()))->module->elsc; } int diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/pci.c linux.ac/arch/ia64/sn/io/pci.c --- linux.vanilla/arch/ia64/sn/io/pci.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/io/pci.c Tue Apr 10 18:09:55 2001 @@ -14,7 +14,6 @@ #include <linux/pci.h> #include <asm/sn/types.h> #include <asm/sn/sgi.h> -#include <asm/sn/cmn_err.h> #include <asm/sn/iobus.h> #include <asm/sn/iograph.h> #include <asm/param.h> @@ -250,18 +249,9 @@ pci_fixup_ioc3(struct pci_dev *d) { int i; - int slot; - unsigned long res = 0; - unsigned int val, size; - int ret; - u_short command; + unsigned int size; - devfs_handle_t device_vertex; devfs_handle_t bridge_vhdl = pci_bus_to_vertex(d->bus->number); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) hwgraph_fastinfo_get(bridge_vhdl); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - bridge_t *bridge = pcibr_soft->bs_base; - bridgereg_t devreg; /* IOC3 only decodes 0x20 bytes of the config space, reading * beyond that is relatively benign but writing beyond that @@ -271,7 +261,7 @@ * currently we hack this with special code in * sgi_pci_intr_support() */ - printk("pci_fixup_ioc3: Fixing base addresses for ioc3 device %s\n", d->slot_name); + DBG("pci_fixup_ioc3: Fixing base addresses for ioc3 device %s\n", d->slot_name); /* I happen to know from the spec that the ioc3 needs only 0xfffff * The standard pci trick of writing ~0 to the baddr and seeing @@ -296,7 +286,9 @@ * DEV_DIRECT bit. This will not work if IOC3 is not on Slot * 4. */ - *(volatile u32 *)0xc0000a000f000220 |= 0x90000; + DBG("pci_fixup_ioc3: FIXME .. need to take NASID into account when setting IOC3 devreg 0x%x\n", *(volatile u32 *)0xc0000a000f000220); + + *(volatile u32 *)0xc0000a000f000220 |= 0x90000; d->subsystem_vendor = 0; d->subsystem_device = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/pci_bus_cvlink.c linux.ac/arch/ia64/sn/io/pci_bus_cvlink.c --- linux.vanilla/arch/ia64/sn/io/pci_bus_cvlink.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/pci_bus_cvlink.c Sat Apr 14 01:18:00 2001 @@ -16,7 +16,6 @@ #include <asm/sn/types.h> #include <asm/sn/hack.h> #include <asm/sn/sgi.h> -#include <asm/sn/cmn_err.h> #include <asm/sn/iobus.h> #include <asm/sn/iograph.h> #include <asm/param.h> @@ -32,23 +31,32 @@ #include <asm/sn/xtalk/xtalkaddrs.h> #include <asm/sn/klconfig.h> #include <asm/sn/io.h> -#include <asm/sn/pci/pci_bus_cvlink.h> #include <asm/sn/pci/pciio.h> // #include <sys/ql.h> #include <asm/sn/pci/pcibr.h> #include <asm/sn/pci/pcibr_private.h> extern int bridge_rev_b_data_check_disable; +#include <asm/sn/pci/pci_bus_cvlink.h> #define MAX_PCI_XWIDGET 256 -devfs_handle_t busnum_to_xwidget[MAX_PCI_XWIDGET]; +devfs_handle_t busnum_to_pcibr_vhdl[MAX_PCI_XWIDGET]; nasid_t busnum_to_nid[MAX_PCI_XWIDGET]; +void * busnum_to_atedmamaps[MAX_PCI_XWIDGET]; unsigned char num_bridges; static int done_probing = 0; static int pci_bus_map_create(devfs_handle_t xtalk); devfs_handle_t devfn_to_vertex(unsigned char busnum, unsigned int devfn); +#define SN1_IOPORTS_UNIT 256 +#define MAX_IOPORTS 0xffff +#define MAX_IOPORTS_CHUNKS (MAX_IOPORTS / SN1_IOPORTS_UNIT) +struct ioports_to_tlbs_s ioports_to_tlbs[MAX_IOPORTS_CHUNKS]; +unsigned long sn1_allocate_ioports(unsigned long pci_address); + + + /* * pci_bus_cvlink_init() - To be called once during initialization before * SGI IO Infrastructure init is called. @@ -56,9 +64,13 @@ void pci_bus_cvlink_init(void) { - - memset(busnum_to_xwidget, 0x0, sizeof(devfs_handle_t) * MAX_PCI_XWIDGET); + memset(busnum_to_pcibr_vhdl, 0x0, sizeof(devfs_handle_t) * MAX_PCI_XWIDGET); memset(busnum_to_nid, 0x0, sizeof(nasid_t) * MAX_PCI_XWIDGET); + + memset(busnum_to_atedmamaps, 0x0, sizeof(void *) * MAX_PCI_XWIDGET); + + memset(ioports_to_tlbs, 0x0, sizeof(ioports_to_tlbs)); + num_bridges = 0; } @@ -70,27 +82,13 @@ pci_bus_to_vertex(unsigned char busnum) { - devfs_handle_t xwidget; devfs_handle_t pci_bus = NULL; /* * First get the xwidget vertex. */ - xwidget = busnum_to_xwidget[busnum]; - if (!xwidget) - return (NULL); - - /* - * Use devfs to get the pci vertex from xwidget. - */ - if (hwgraph_traverse(xwidget, EDGE_LBL_PCI, &pci_bus) != GRAPH_SUCCESS) { - if (!pci_bus) { - printk("pci_bus_to_vertex: Cannot find pci bus for given bus number %d\n", busnum); - return (NULL); - } - } - + pci_bus = busnum_to_pcibr_vhdl[busnum]; return(pci_bus); } @@ -138,7 +136,6 @@ if (hwgraph_traverse(pci_bus, name, &device_vertex) != GRAPH_SUCCESS) { if (!device_vertex) { - printk("devfn_to_vertex: Unable to get slot&func %s from pci vertex 0x%p\n", name, pci_bus); return(NULL); } } @@ -175,6 +172,61 @@ } /* + * sn1_allocate_ioports() - This routine provides the allocation and + * mappings between Linux style IOPORTs management. + * + * For simplicity sake, SN1 will allocate IOPORTs in chunks of + * 256bytes .. irrespective of what the card desires. This may + * have to change when we understand how to deal with legacy ioports + * which are hardcoded in some drivers e.g. SVGA. + * + * Ofcourse, the SN1 IO Infrastructure has no concept of IOPORT numbers. + * It will remain so. The IO Infrastructure will continue to map + * IO Resource just like IRIX. When this is done, we map IOPORT + * chunks to these resources. The Linux drivers will see and use real + * IOPORT numbers. The various IOPORT access macros e.g. inb/outb etc. + * does the munging of these IOPORT numbers to make a Uncache Virtual + * Address. This address via the tlb entries generates the PCI Address + * allocated by the SN1 IO Infrastructure Layer. + */ +static unsigned long sn1_ioport_num = 0x100; /* Reserve room for Legacy stuff */ +unsigned long +sn1_allocate_ioports(unsigned long pci_address) +{ + + unsigned long ioport_index; + + /* + * Just some idiot checking .. + */ + if ( sn1_ioport_num > 0xffff ) { + printk("sn1_allocate_ioports: No more IO PORTS available\n"); + return(-1); + } + + /* + * See Section 4.1.1.5 of Intel IA-64 Acrchitecture Software Developer's + * Manual for details. + */ + ioport_index = sn1_ioport_num / SN1_IOPORTS_UNIT; + ioports_to_tlbs[ioport_index].ppn = pci_address; + ioports_to_tlbs[ioport_index].p = 1; /* Present Bit */ + ioports_to_tlbs[ioport_index].ma = 5; /* Memory Attributes */ + ioports_to_tlbs[ioport_index].a = 0; /* Set Data Access Bit Fault */ + ioports_to_tlbs[ioport_index].d = 0; /* Dirty Bit */ + ioports_to_tlbs[ioport_index].pl = 3;/* Privilege Level - All levels can R/W*/ + ioports_to_tlbs[ioport_index].ar = 2; /* Access Rights - R/W only*/ + ioports_to_tlbs[ioport_index].ed = 0; /* Exception Deferral Bit */ + ioports_to_tlbs[ioport_index].ig = 0; /* Ignored */ + + printk("sn1_allocate_ioports: ioport_index 0x%x ioports_to_tlbs 0x%p\n", ioport_index, ioports_to_tlbs[ioport_index].ppn); + + sn1_ioport_num += SN1_IOPORTS_UNIT; + + return(sn1_ioport_num - SN1_IOPORTS_UNIT); +} + +/* * sn1_pci_fixup() - This routine is called when platform_pci_fixup() is * invoked at the end of pcibios_init() to link the Linux pci * infrastructure to SGI IO Infrasturcture - ia64/kernel/pci.c @@ -189,6 +241,11 @@ struct pci_dev *device_dev = NULL; struct sn1_widget_sysdata *widget_sysdata; struct sn1_device_sysdata *device_sysdata; + unsigned long ioport; + pciio_intr_t intr_handle; + int cpuid, bit; + devfs_handle_t *device_vertex; + pciio_intr_line_t lines; extern void sn1_pci_find_bios(void); @@ -204,7 +261,6 @@ devfs_handle_t bridge_vhdl = pci_bus_to_vertex(0); pcibr_soft_t pcibr_soft = (pcibr_soft_t) hwgraph_fastinfo_get(bridge_vhdl); bridge_t *bridge = pcibr_soft->bs_base; -printk("Before Changing PIO Map Address:\n"); printk("pci_fixup_ioc3: Before devreg fixup\n"); printk("pci_fixup_ioc3: Devreg 0 0x%x\n", bridge->b_device[0].reg); printk("pci_fixup_ioc3: Devreg 1 0x%x\n", bridge->b_device[1].reg); @@ -280,16 +336,11 @@ size = device_dev->resource[idx].end - device_dev->resource[idx].start; if (size) { -res = 0; -res = pciio_config_get(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + idx, 4); -printk("Before pciio_pio_addr Base address %d = 0x%lx\n", idx, res); - - printk(" Changing device %d:%d resource start address from 0x%lx", - PCI_SLOT(device_dev->devfn),PCI_FUNC(device_dev->devfn), - device_dev->resource[idx].start); - device_dev->resource[idx].start = - (unsigned long)pciio_pio_addr(vhdl, 0, - PCIIO_SPACE_WIN(idx), 0, size, 0, PCIIO_BYTE_STREAM); + res = 0; + res = pciio_config_get(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + idx, 4); + device_dev->resource[idx].start = (unsigned long)pciio_pio_addr(vhdl, 0, PCIIO_SPACE_WIN(idx), 0, size, 0, PCIIO_BYTE_STREAM); + +/* printk("sn1_pci_fixup: Mapped Address = 0x%p size = 0x%x\n", device_dev->resource[idx].start, size); */ } else continue; @@ -304,13 +355,14 @@ device_dev->resource[idx].start & 0xfffff7ffffffffff; device_dev->resource[idx].end = device_dev->resource[idx].end & 0xfffff7ffffffffff; - printk(" to 0x%lx\n", device_dev->resource[idx].start); -res = 0; -res = pciio_config_get(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + idx, 4); -printk("After pciio_pio_addr Base address %d = 0x%lx\n", idx, res); - - if (device_dev->resource[idx].flags & IORESOURCE_IO) + res = 0; + res = pciio_config_get(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + idx, 4); + if (device_dev->resource[idx].flags & IORESOURCE_IO) { cmd |= PCI_COMMAND_IO; + ioport = sn1_allocate_ioports(device_dev->resource[idx].start); + /* device_dev->resource[idx].start = ioport; */ + /* device_dev->resource[idx].end = ioport + SN1_IOPORTS_UNIT */ + } else if (device_dev->resource[idx].flags & IORESOURCE_MEM) cmd |= PCI_COMMAND_MEMORY; } @@ -319,9 +371,6 @@ */ size = device_dev->resource[PCI_ROM_RESOURCE].end - device_dev->resource[PCI_ROM_RESOURCE].start; - printk(" Changing device %d:%d ROM resource start address from 0x%lx", - PCI_SLOT(device_dev->devfn),PCI_FUNC(device_dev->devfn), - device_dev->resource[PCI_ROM_RESOURCE].start); device_dev->resource[PCI_ROM_RESOURCE].start = (unsigned long) pciio_pio_addr(vhdl, 0, PCIIO_SPACE_ROM, 0, size, 0, PCIIO_BYTE_STREAM); @@ -341,24 +390,26 @@ /* bit gets dropped .. no harm */ pci_write_config_word(device_dev, PCI_COMMAND, cmd); - printk(" to 0x%lx\n", device_dev->resource[PCI_ROM_RESOURCE].start); + pci_read_config_byte(device_dev, PCI_INTERRUPT_PIN, &lines); +#ifdef BRINGUP + if (device_dev->vendor == PCI_VENDOR_ID_SGI && + device_dev->device == PCI_DEVICE_ID_SGI_IOC3 ) { + lines = 1; + } - /* - * Set the irq correctly. - * Bits 7:3 = slot - * Bits 2:0 = function - * - * In the IRQ we will have: - * Bits 24:16 = bus number - * Bits 15:8 = slot|func number - */ - irq = 0; - irq = (irq | (device_dev->devfn << 8)); - irq = (irq | ( (device_dev->bus->number & 0xff) << 16) ); +#endif + + device_sysdata = (struct sn1_device_sysdata *)device_dev->sysdata; + device_vertex = device_sysdata->vhdl; + + intr_handle = pciio_intr_alloc(device_vertex, NULL, lines, device_vertex); + + bit = intr_handle->pi_irq; + cpuid = intr_handle->pi_cpu; + irq = bit_pos_to_irq(bit); + irq = irq + (cpuid << 8); + pciio_intr_connect(intr_handle, NULL, NULL, NULL); device_dev->irq = irq; -printk("sn1_pci_fixup: slot= %d fn= %d vendor= 0x%x device= 0x%x irq= 0x%x\n", -PCI_SLOT(device_dev->devfn),PCI_FUNC(device_dev->devfn),device_dev->vendor, -device_dev->device, device_dev->irq); } #endif /* REAL_HARDWARE */ @@ -369,7 +420,6 @@ pcibr_soft_t pcibr_soft = (pcibr_soft_t) hwgraph_fastinfo_get(bridge_vhdl); bridge_t *bridge = pcibr_soft->bs_base; -printk("After Changing PIO Map Address:\n"); printk("pci_fixup_ioc3: Before devreg fixup\n"); printk("pci_fixup_ioc3: Devreg 0 0x%x\n", bridge->b_device[0].reg); printk("pci_fixup_ioc3: Devreg 1 0x%x\n", bridge->b_device[1].reg); @@ -386,6 +436,25 @@ /* * pci_bus_map_create() - Called by pci_bus_to_hcl_cvlink() to finish the job. + * + * Linux PCI Bus numbers are assigned from lowest module_id numbers + * (rack/slot etc.) starting from HUB_WIDGET_ID_MAX down to + * HUB_WIDGET_ID_MIN: + * widgetnum 15 gets lower Bus Number than widgetnum 14 etc. + * + * Given 2 modules 001c01 and 001c02 we get the following mappings: + * 001c01, widgetnum 15 = Bus number 0 + * 001c01, widgetnum 14 = Bus number 1 + * 001c02, widgetnum 15 = Bus number 3 + * 001c02, widgetnum 14 = Bus number 4 + * etc. + * + * The rational for starting Bus Number 0 with Widget number 15 is because + * the system boot disks are always connected via Widget 15 Slot 0 of the + * I-brick. Linux creates /dev/sd* devices(naming) strating from Bus Number 0 + * Therefore, /dev/sda1 will be the first disk, on Widget 15 of the lowest + * module id(Master Cnode) of the system. + * */ static int pci_bus_map_create(devfs_handle_t xtalk) @@ -402,10 +471,21 @@ /* * Loop throught this vertex and get the Xwidgets .. */ - for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { + for (widgetnum = HUB_WIDGET_ID_MAX; widgetnum >= HUB_WIDGET_ID_MIN; widgetnum--) { + { + int pos; + char dname[256]; + pos = devfs_generate_path(xtalk, dname, 256); + printk("%s : path= %s\n", __FUNCTION__, &dname[pos]); + } + sprintf(pathname, "%d", widgetnum); xwidget = NULL; + /* + * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget + * /hw/module/001c16/Pbrick/xtalk/8/pci/1 is device + */ rv = hwgraph_traverse(xtalk, pathname, &xwidget); if ( (rv != GRAPH_SUCCESS) ) { if (!xwidget) @@ -425,25 +505,35 @@ * Should not be any race here ... */ num_bridges++; - busnum_to_xwidget[num_bridges - 1] = xwidget; + busnum_to_pcibr_vhdl[num_bridges - 1] = pci_bus; /* * Get the master node and from there get the NASID. */ master_node_vertex = device_master_get(xwidget); if (!master_node_vertex) { - printk(" **** pci_bus_map_create: Unable to get .master for vertex 0x%p **** \n", xwidget); + printk("WARNING: pci_bus_map_create: Unable to get .master for vertex 0x%p\n", xwidget); } hubinfo_get(master_node_vertex, &hubinfo); if (!hubinfo) { - printk(" **** pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p ****\n", master_node_vertex); + printk("WARNING: pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p\n", master_node_vertex); return(1); } else { busnum_to_nid[num_bridges - 1] = hubinfo->h_nasid; } - printk("pci_bus_map_create: Found Hub nasid %d PCI Xwidget 0x%p widgetnum= %d\n", hubinfo->h_nasid, xwidget, widgetnum); + /* + * Pre assign DMA maps needed for 32 Bits Page Map DMA. + */ + busnum_to_atedmamaps[num_bridges - 1] = (void *) kmalloc( + sizeof(struct sn1_dma_maps_s) * 512, GFP_KERNEL); + if (!busnum_to_atedmamaps[num_bridges - 1]) + printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, xwidget); + + memset(busnum_to_atedmamaps[num_bridges - 1], 0x0, + sizeof(struct sn1_dma_maps_s) * 512); + } return(0); @@ -468,6 +558,9 @@ graph_vertex_place_t placeptr = EDGE_PLACE_WANT_REAL_EDGES; int rv = 0; char name[256]; + int master_iobrick; + moduleid_t iobrick_id; + int i; /* * Iterate throught each xtalk links in the system .. @@ -480,42 +573,48 @@ devfs_hdl = hwgraph_path_to_vertex("/dev/hw/module"); /* - * Loop throught this directory "/devfs/hw/module/" and get each - * of it's entry. - */ - while (1) { - - /* Get vertex of component /dev/hw/<module_number> */ - memset((char *)name, '0', 256); - module_comp = NULL; - rv = hwgraph_edge_get_next(devfs_hdl, (char *)name, &module_comp, (uint *)&placeptr); - if ((rv == 0) && (module_comp)) { - /* Found a valid entry */ - node = NULL; - rv = hwgraph_edge_get(module_comp, "node", &node); - - } else { - printk("pci_bus_to_hcl_cvlink: No more Module Component.\n"); - return(0); + * To provide consistent(not persistent) device naming, we need to start + * bus number allocation from the C-Brick with the lowest module id e.g. 001c01 + * with an attached I-Brick. Find the master_iobrick. + */ + master_iobrick = -1; + for (i = 0; i < nummodules; i++) { + moduleid_t iobrick_id; + iobrick_id = iobrick_module_get(&modules[i]->elsc); + if (iobrick_id > 0) { /* Valid module id */ + if (MODULE_GET_BTYPE(iobrick_id) == MODULE_IBRICK) { + master_iobrick = i; + break; + } } + } - if ( (rv != 0) || (!node) ){ - printk("pci_bus_to_hcl_cvlink: Module Component does not have node vertex.\n"); - continue; - } else { - xtalk = NULL; - rv = hwgraph_edge_get(node, "xtalk", &xtalk); - if ( (rv != 0) || (xtalk == NULL) ){ - printk("pci_bus_to_hcl_cvlink: Node has no xtalk vertex.\n"); - continue; - } + /* + * The master_iobrick gets bus 0 and 1. + */ + if (master_iobrick >= 0) { + memset(name, 0, 256); + format_module_id(name, modules[master_iobrick]->id, MODULE_FORMAT_BRIEF); + strcat(name, "/node/xtalk"); + xtalk = NULL; + rv = hwgraph_edge_get(devfs_hdl, name, &xtalk); + pci_bus_map_create(xtalk); + } + + /* + * Now go do the rest of the modules, starting from the C-Brick with the lowest + * module id, remembering to skip the master_iobrick, which was done above. + */ + for (i = 0; i < nummodules; i++) { + if (i == master_iobrick) { + continue; /* Did the master_iobrick already. */ } - printk("pci_bus_to_hcl_cvlink: Found Module %s node vertex = 0x%p xtalk vertex = 0x%p\n", name, node, xtalk); - /* - * Call routine to get the existing PCI Xwidget and create - * the convenience link from "/devfs/hw/pci_bus/.." - */ + memset(name, 0, 256); + format_module_id(name, modules[i]->id, MODULE_FORMAT_BRIEF); + strcat(name, "/node/xtalk"); + xtalk = NULL; + rv = hwgraph_edge_get(devfs_hdl, name, &xtalk); pci_bus_map_create(xtalk); } @@ -539,10 +638,8 @@ struct sn1_widget_sysdata *widget_sysdata; struct sn1_device_sysdata *device_sysdata; - printk("sgi_pci_intr_support: Called with requested_irq 0x%x\n", requested_irq); - if (!dev_desc || !bus_vertex || !device_vertex) { - printk("sgi_pci_intr_support: Invalid parameter dev_desc 0x%p, bus_vertex 0x%p, device_vertex 0x%p\n", dev_desc, bus_vertex, device_vertex); + printk("WARNING: sgi_pci_intr_support: Invalid parameter dev_desc 0x%p, bus_vertex 0x%p, device_vertex 0x%p\n", dev_desc, bus_vertex, device_vertex); return(-1); } @@ -577,15 +674,11 @@ if (pci_dev->vendor == PCI_VENDOR_ID_SGI && pci_dev->device == PCI_DEVICE_ID_SGI_IOC3 ) { *lines = 1; - printk("%s : IOC3 HACK: lines= %d\n", __FUNCTION__, *lines); } #endif /* BRINGUP */ /* Not supported currently */ *dev_desc = NULL; - - printk("sgi_pci_intr_support: Device Descriptor 0x%p, Bus Vertex 0x%p, Interrupt Pins 0x%x, Device Vertex 0x%p\n", *dev_desc, *bus_vertex, *lines, *device_vertex); - return(0); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/pci_dma.c linux.ac/arch/ia64/sn/io/pci_dma.c --- linux.vanilla/arch/ia64/sn/io/pci_dma.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/pci_dma.c Sat Apr 14 01:18:00 2001 @@ -21,9 +21,6 @@ #ifndef _LANGUAGE_C #define _LANGUAGE_C 99 #endif -#ifndef CONFIG_IA64_SGI_IO -#define CONFIG_IA64_SGI_IO 99 -#endif #include <asm/io.h> #include <asm/sn/sgi.h> @@ -32,9 +29,9 @@ #include <asm/sn/pci/pcibr.h> #include <asm/sn/pci/pcibr_private.h> #include <asm/sn/iobus.h> -#include <asm/sn/pci/pci_bus_cvlink.h> #include <asm/sn/types.h> #include <asm/sn/alenlist.h> +#include <asm/sn/pci/pci_bus_cvlink.h> /* * this is REALLY ugly, blame it on gcc's lame inlining that we @@ -43,13 +40,69 @@ #if LANGUAGE_C == 99 #undef LANGUAGE_C #endif -#if _LANGUAGE_C == 99 -#undef _LANGUAGE_C -#endif #if CONFIG_IA64_SGI_IO == 99 #undef CONFIG_IA64_SGI_IO #endif +pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t); +struct sn1_dma_maps_s *find_sn1_dma_map(dma_addr_t, unsigned char); +extern devfs_handle_t busnum_to_pcibr_vhdl[]; +extern nasid_t busnum_to_nid[]; +extern void * busnum_to_atedmamaps[]; + +/* + * Get a free pciio_dmamap_t entry. + */ +pciio_dmamap_t +get_free_pciio_dmamap(devfs_handle_t pci_bus) +{ + int i; + struct sn1_dma_maps_s *sn1_dma_map = NULL; + + /* + * Darn, we need to get the maps allocated for this bus. + */ + for (i=0; i<512; i++) { + if (busnum_to_pcibr_vhdl[i] == pci_bus) { + sn1_dma_map = busnum_to_atedmamaps[i]; + } + } + + /* + * Now get a free dmamap entry from this list. + */ + for (i=0; i<512; i++, sn1_dma_map++) { + if (!sn1_dma_map->dma_addr) { + sn1_dma_map->dma_addr = -1; + return( (pciio_dmamap_t) sn1_dma_map ); + } + } + +printk("get_pciio_dmamap: Unable to find a free dmamap\n"); + return(NULL); + +} + +struct sn1_dma_maps_s * +find_sn1_dma_map(dma_addr_t dma_addr, unsigned char busnum) +{ + + struct sn1_dma_maps_s *sn1_dma_map = NULL; + int i; + + sn1_dma_map = busnum_to_atedmamaps[busnum]; + + for (i=0; i<512; i++, sn1_dma_map++) { + if (sn1_dma_map->dma_addr == dma_addr) { + return( sn1_dma_map ); + } + } + +printk("find_pciio_dmamap: Unable find the corresponding dma map\n"); + return(NULL); + +} + /* * sn1 platform specific pci_alloc_consistent() * @@ -74,7 +127,7 @@ device_sysdata = (struct sn1_device_sysdata *) hwdev->sysdata; vhdl = device_sysdata->vhdl; - if ( ret = (void *)__get_free_pages(gfp, get_order(size)) ) { + if ( (ret = (void *)__get_free_pages(gfp, get_order(size))) ) { memset(ret, 0, size); } else { return(NULL); @@ -142,6 +195,8 @@ dma_addr_t dma_addr; paddr_t temp_ptr; struct sn1_device_sysdata *device_sysdata; + pciio_dmamap_t dma_map; + if (direction == PCI_DMA_NONE) @@ -153,7 +208,7 @@ device_sysdata = (struct sn1_device_sysdata *) hwdev->sysdata; vhdl = device_sysdata->vhdl; for (i = 0; i < nents; i++, sg++) { - sg->orig_address = sg->address; + sg->orig_address = (char *)NULL; dma_addr = 0; temp_ptr = (paddr_t) __pa(sg->address); @@ -166,7 +221,6 @@ PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD | PCIIO_DMA_A64 ); sg->address = (char *)dma_addr; -/* printk("pci_map_sg: 64Bits hwdev %p DMA Address 0x%p alt_address 0x%p orig_address 0x%p length 0x%x\n", hwdev, sg->address, sg->alt_address, sg->orig_address, sg->length); */ continue; } @@ -180,17 +234,28 @@ PCIIO_DMA_CMD); if (dma_addr) { sg->address = (char *)dma_addr; -/* printk("pci_map_single: 32Bit direct pciio_dmatrans_addr pcidev %p returns dma_addr 0x%lx\n", hwdev, dma_addr); */ continue; - } else { - /* - * We need to map this request by using ATEs. - */ - printk("pci_map_single: 32Bits DMA Page Map support not available yet!"); - BUG(); - } + } + + /* + * It is a 32bit card and we cannot do Direct mapping. + * Let's 32Bit Page map the request. + */ + dma_map = NULL; + dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length, + PCIBR_BARRIER | PCIIO_BYTE_STREAM | + PCIIO_DMA_CMD); + if (!dma_map) { + printk("pci_map_sg: Unable to allocate anymore 32Bits Page Map entries.\n"); + BUG(); + } + dma_addr = (dma_addr_t)pciio_dmamap_addr(dma_map, temp_ptr, sg->length); + /* printk("pci_map_sg: dma_map 0x%p Phys Addr 0x%p dma_addr 0x%p\n", dma_map, temp_ptr, dma_addr); */ + sg->address = (char *)dma_addr; + sg->orig_address = (char *)dma_map; + } return nents; @@ -206,13 +271,25 @@ sn1_pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) { int i; + struct sn1_dma_maps_s *sn1_dma_map; + if (direction == PCI_DMA_NONE) BUG(); + for (i = 0; i < nelems; i++, sg++) - if (sg->orig_address != sg->address) { + if (sg->orig_address) { + /* + * We maintain the DMA Map pointer in sg->orig_address if + * it is ever allocated. + */ /* phys_to_virt((dma_addr_t)sg->address | ~0x80000000); */ - sg->address = sg->orig_address; + /* sg->address = sg->orig_address; */ + sg->address = (char *)-1; + sn1_dma_map = (struct sn1_dma_maps_s *)sg->orig_address; + pciio_dmamap_done((pciio_dmamap_t)sn1_dma_map); + pciio_dmamap_free((pciio_dmamap_t)sn1_dma_map); + sn1_dma_map->dma_addr = 0; sg->orig_address = 0; } } @@ -234,24 +311,20 @@ dma_addr_t dma_addr; paddr_t temp_ptr; struct sn1_device_sysdata *device_sysdata; + pciio_dmamap_t dma_map = NULL; + struct sn1_dma_maps_s *sn1_dma_map; if (direction == PCI_DMA_NONE) BUG(); - if (IS_PCI32L(hwdev)) { - /* - * SNIA64 cannot support DMA Addresses smaller than 32 bits. - */ - return ((dma_addr_t) NULL); - } /* * find vertex for the device */ device_sysdata = (struct sn1_device_sysdata *)hwdev->sysdata; vhdl = device_sysdata->vhdl; -/* printk("pci_map_single: Called vhdl = 0x%p ptr = 0x%p size = %d\n", vhdl, ptr, size); */ + /* * Call our dmamap interface */ @@ -266,7 +339,6 @@ temp_ptr, size, PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD | PCIIO_DMA_A64 ); -/* printk("pci_map_single: 64Bit pciio_dmatrans_addr pcidev %p returns dma_addr 0x%lx\n", hwdev, dma_addr); */ return (dma_addr); } @@ -281,14 +353,7 @@ temp_ptr, size, PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD); if (dma_addr) { -/* printk("pci_map_single: 32Bit direct pciio_dmatrans_addr pcidev %p returns dma_addr 0x%lx\n", hwdev, dma_addr); */ return (dma_addr); - } else { - /* - * We need to map this request by using ATEs. - */ - printk("pci_map_single: 32Bits DMA Page Map support not available yet!"); - BUG(); } } @@ -297,23 +362,56 @@ * SNIA64 cannot support DMA Addresses smaller than 32 bits. */ return ((dma_addr_t) NULL); + } + + /* + * It is a 32bit card and we cannot do Direct mapping. + * Let's 32Bit Page map the request. + */ + dma_map = NULL; + dma_map = pciio_dmamap_alloc(vhdl, NULL, size, PCIBR_BARRIER | + PCIIO_BYTE_STREAM | PCIIO_DMA_CMD); + if (!dma_map) { + printk("pci_map_single: Unable to allocate anymore 32Bits Page Map entries.\n"); + BUG(); } - return ((dma_addr_t) NULL); + dma_addr = (dma_addr_t) pciio_dmamap_addr(dma_map, temp_ptr, size); + /* printk("pci_map_single: dma_map 0x%p Phys Addr 0x%p dma_addr 0x%p\n", dma_map, + temp_ptr, dma_addr); */ + sn1_dma_map = (struct sn1_dma_maps_s *)dma_map; + sn1_dma_map->dma_addr = dma_addr; + return ((dma_addr_t)dma_addr); } void sn1_pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) { + + struct sn1_dma_maps_s *sn1_dma_map = NULL; + if (direction == PCI_DMA_NONE) - BUG(); - /* Nothing to do */ + BUG(); + + /* + * Get the sn1_dma_map entry. + */ + if (IS_PCI32_MAPPED(dma_addr)) + sn1_dma_map = find_sn1_dma_map(dma_addr, hwdev->bus->number); + + if (sn1_dma_map) { + pciio_dmamap_done((pciio_dmamap_t)sn1_dma_map); + pciio_dmamap_free((pciio_dmamap_t)sn1_dma_map); + sn1_dma_map->dma_addr = (dma_addr_t)NULL; + } + } void sn1_pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) { + if (direction == PCI_DMA_NONE) BUG(); /* Nothing to do */ @@ -330,5 +428,5 @@ unsigned long sn1_dma_address (struct scatterlist *sg) { - return (sg->address); + return ((unsigned long)sg->address); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/pciba.c linux.ac/arch/ia64/sn/io/pciba.c --- linux.vanilla/arch/ia64/sn/io/pciba.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ia64/sn/io/pciba.c Sat Apr 14 01:18:00 2001 @@ -0,0 +1,1716 @@ +/* $Id$ + * + * 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) 1992 - 1997, 2000 Silicon Graphics, Inc. + * Copyright (C) 2000 by Colin Ngam + */ + +#include <linux/types.h> +#include <linux/config.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <asm/sn/sgi.h> +#include <asm/sn/addrs.h> +#include <asm/sn/arch.h> +#include <asm/sn/iograph.h> +#include <asm/sn/invent.h> +#include <asm/sn/hcl.h> +#include <asm/sn/labelcl.h> +#include <asm/sn/xtalk/xwidget.h> +#include <asm/sn/pci/bridge.h> +#include <asm/sn/pci/pciio.h> +#include <asm/sn/pci/pcibr.h> +#include <asm/sn/pci/pcibr_private.h> +#include <asm/sn/pci/pci_defs.h> +#include <asm/sn/prio.h> +#include <asm/sn/ioerror_handling.h> +#include <asm/sn/xtalk/xbow.h> +#include <asm/sn/ioc3.h> +#include <asm/sn/eeprom.h> +#include <asm/sn/sn1/bedrock.h> +#include <asm/sn/sn_private.h> +#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) +#include <asm/sn/sn1/hubio.h> +#include <asm/sn/sn1/hubio_next.h> +#endif + +#define copyin(_a, _b, _c) copy_from_user(_b, _a, _c) + +#ifndef DEBUG_PCIBA +#define DEBUG_PCIBA 0 +#endif + +/* v_mapphys does not percolate page offset back. */ +#define PCIBA_ALIGN_CHECK 1 + +#include <asm/sn/pci/pciba.h> + +/* grab an unused space code for "User DMA" space */ +#ifndef PCIBA_SPACE_UDMA +#define PCIBA_SPACE_UDMA (14) +#endif + +#if DEBUG_REFCT +extern int hwgraph_vertex_refct(vertex_hdl_t); +#endif +extern int pci_user_dma_max_pages; + +#define NEW(ptr) (ptr = kmem_zalloc(sizeof (*(ptr)), KM_SLEEP)) +#define DEL(ptr) (kfree(ptr)) + +/* Oops -- no standard "pci address" type! */ +typedef uint64_t pciaddr_t; + +/* ================================================================ + * driver types + */ +typedef struct pciba_slot_s *pciba_slot_t; +typedef struct pciba_comm_s *pciba_comm_t; +typedef struct pciba_soft_s *pciba_soft_t; +typedef struct pciba_map_s *pciba_map_t, **pciba_map_h; +typedef struct pciba_dma_s *pciba_dma_t, **pciba_dma_h; +typedef struct pciba_bus_s *pciba_bus_t; + +#define TRACKED_SPACES 16 +struct pciba_comm_s { + devfs_handle_t conn; + pciba_bus_t bus; + int refct; + pciba_soft_t soft[TRACKED_SPACES][2]; + struct semaphore lock; + pciba_dma_t dmap; +}; + +/* pciba_soft: device_info() for all openables */ +struct pciba_soft_s { + pciba_comm_t comm; + devfs_handle_t vhdl; + int refct; + pciio_space_t space; + size_t size; + pciio_space_t iomem; + pciaddr_t base; + unsigned flags; +}; + +#define pciba_soft_get(v) (pciba_soft_t)hwgraph_fastinfo_get(v) +#define pciba_soft_set(v,i) hwgraph_fastinfo_set(v,(arbitrary_info_t)(i)) + +#define pciba_soft_lock(soft) down(&soft->comm->lock) +#define pciba_soft_unlock(soft) up(&soft->comm->lock) + +/* pciba_map: data describing a mapping. + * (ie. a user mmap request) + */ +struct pciba_map_s { + pciba_map_t next; +#ifdef LATER + uthread_t *uthread; +#endif + __psunsigned_t handle; + uvaddr_t uvaddr; + size_t size; + pciio_piomap_t map; + pciio_space_t space; + pciaddr_t base; + unsigned flags; +}; + +/* pciba_dma: data describing a DMA mapping. + */ +struct pciba_dma_s { + pciba_dma_t next; + iopaddr_t paddr; /* starting phys addr */ + caddr_t kaddr; /* starting kern addr */ + pciio_dmamap_t map; /* mapping resources (ugh!) */ + pciaddr_t daddr; /* starting pci addr */ + size_t pages; /* size of block in pages */ + size_t bytes; /* size of block in bytes */ + __psunsigned_t handle; /* mapping handle */ +}; + +/* pciba_bus: common bus info for all openables + * descended from the same master vertex. + */ +struct pciba_bus_s { + struct semaphore lock; + pciba_map_t maps; /* stack of mappings */ + int refct; +}; + +#define pciba_bus_lock(bus) down(&bus->lock) +#define pciba_bus_unlock(bus) up(&bus->lock) + +typedef union ioctl_arg_buffer_u { + char data[IOCPARM_MASK + 1]; + uint8_t uc; + uint16_t us; + uint32_t ui; + uint64_t ud; + caddr_t ca; +#if ULI + struct uliargs uli; + struct uliargs32 uli32; +#endif +} ioctl_arg_buffer_t; + +/* ================================================================ + * driver variables + */ +char *pciba_mversion = "mload version 7.0"; +int pciba_devflag = 0x1 | + 0x200 | + 0x400; + +/* this counts the reasons why we can not + * currently unload this driver. + */ +atomic_t pciba_prevent_unload = ATOMIC_INIT(0); + +#if DEBUG_PCIBA +static struct reg_values space_v[] = +{ + {PCIIO_SPACE_NONE, "none"}, + {PCIIO_SPACE_ROM, "ROM"}, + {PCIIO_SPACE_IO, "I/O"}, + {PCIIO_SPACE_MEM, "MEM"}, + {PCIIO_SPACE_MEM32, "MEM(32)"}, + {PCIIO_SPACE_MEM64, "MEM(64)"}, + {PCIIO_SPACE_CFG, "CFG"}, + {PCIIO_SPACE_WIN(0), "WIN(0)"}, + {PCIIO_SPACE_WIN(1), "WIN(1)"}, + {PCIIO_SPACE_WIN(2), "WIN(2)"}, + {PCIIO_SPACE_WIN(3), "WIN(3)"}, + {PCIIO_SPACE_WIN(4), "WIN(4)"}, + {PCIIO_SPACE_WIN(5), "WIN(5)"}, + {PCIBA_SPACE_UDMA, "UDMA"}, + {PCIIO_SPACE_BAD, "BAD"}, + {0} +}; + +static struct reg_desc space_desc[] = +{ + {0xFF, 0, "space", 0, space_v}, + {0} +}; +#endif + +char pciba_edge_lbl_base[] = "base"; +char pciba_edge_lbl_cfg[] = "config"; +char pciba_edge_lbl_dma[] = "dma"; +char pciba_edge_lbl_intr[] = "intr"; +char pciba_edge_lbl_io[] = "io"; +char pciba_edge_lbl_mem[] = "mem"; +char pciba_edge_lbl_rom[] = "rom"; +char *pciba_edge_lbl_win[6] = +{"0", "1", "2", "3", "4", "5"}; + +#define PCIBA_EDGE_LBL_BASE pciba_edge_lbl_base +#define PCIBA_EDGE_LBL_CFG pciba_edge_lbl_cfg +#define PCIBA_EDGE_LBL_DMA pciba_edge_lbl_dma +#define PCIBA_EDGE_LBL_INTR pciba_edge_lbl_intr +#define PCIBA_EDGE_LBL_IO pciba_edge_lbl_io +#define PCIBA_EDGE_LBL_MEM pciba_edge_lbl_mem +#define PCIBA_EDGE_LBL_ROM pciba_edge_lbl_rom +#define PCIBA_EDGE_LBL_WIN(n) pciba_edge_lbl_win[n] + +#define PCIBA_EDGE_LBL_FLIP pciba_edge_lbl_flip + +static char pciba_info_lbl_bus[] = "pciba_bus"; + +#define PCIBA_INFO_LBL_BUS pciba_info_lbl_bus + +struct file_operations pciba_fops = { + owner: THIS_MODULE, + llseek: NULL, + read: NULL, + write: NULL, + readdir: NULL, + poll: NULL, + ioctl: NULL, + mmap: NULL, + open: NULL, + flush: NULL, + release: NULL, + fsync: NULL, + fasync: NULL, + lock: NULL, + readv: NULL, + writev: NULL +}; + +/* ================================================================ + * function table of contents + */ + +void pciba_init(void); +int pciba_attach(devfs_handle_t); + +static void pciba_sub_attach(pciba_comm_t, + pciio_space_t, pciio_space_t, pciaddr_t, + devfs_handle_t, devfs_handle_t, char *); + +static pciba_bus_t pciba_find_bus(devfs_handle_t, int); +#ifdef LATER +static void pciba_map_push(pciba_bus_t, pciba_map_t); +static pciba_map_t pciba_map_pop_hdl(pciba_bus_t, __psunsigned_t); +static void pciba_sub_detach(devfs_handle_t, char *); +static pciio_iter_f pciba_unload_me; +#endif + +int pciba_unload(void); +int pciba_unreg(void); +int pciba_detach(devfs_handle_t); + +int pciba_open(dev_t *, int, int, struct cred *); +int pciba_close(dev_t); +int pciba_read(dev_t, cred_t *); +int pciba_write(dev_t, cred_t *); +int pciba_ioctl(dev_t, int, void *, int, cred_t *, int *); + +int pciba_map(dev_t, vhandl_t *, off_t, size_t, uint32_t); +int pciba_unmap(dev_t, vhandl_t *); + +#if ULI +void pciba_clearuli(struct uli *); +static intr_func_f pciba_intr; +#endif /* Undef as it gets implemented */ + +/* ================================================================ + * driver load, register, and setup + */ +void +pciba_init(void) +{ + + /* + * What do we need to do here? + */ +#if DEBUG_PCIBA + printk("pciba_init()\n"); +#endif +} + +#ifdef LATER +#if HWG_PERF_CHECK && IP30 && !DEBUG +void +pciba_timeout(void *arg1, void *arg2) +{ + struct semaphore *semap = (sema_t *) arg1; + unsigned long *cvalp = (unsigned long *) arg2; + + if (cvalp) + cvalp[0] = RAW_COUNT(); + if (semap) + up(semap); +} + +volatile unsigned long cNval[1]; +struct semaphore tsema; + +void +pciba_timeout_test(void) +{ + unsigned long c0val, cval; + toid_t tid; + + extern void hwg_hprint(unsigned long, char *); + + sema_init(&tsema, 0); + + cNval[0] = 0; + c0val = RAW_COUNT(); + tid = timeout((void (*)()) pciba_timeout, (void *) 0, 1, (void *) cNval); + DELAY(1000000); + cval = cNval[0]; + if (cval == 0) { + untimeout(tid); + PRINT_ALERT("pciba: one-tick timeout did not happen in a second\n"); + return; + } + cval = cval - c0val; + hwg_hprint(cval, "timeout(1)"); + + cNval[0] = 0; + c0val = RAW_COUNT(); + tid = timeout((void (*)()) pciba_timeout, (void *) &tsema, 2, (void *) cNval); + + /* FIXME : this probably needs to be down_interruptible() */ + + if (down(&tsema) < 0) { /* wait for the pciba_timeout */ + untimeout(tid); + PRINT_WARNING("pciba: timeout(2) time check aborted\n"); + return; + } + cval = cNval[0]; + if (cval == 0) { + untimeout(tid); + PRINT_WARNING("pciba: timeout(2) time not logged\n"); + return; + } + cval = cval - c0val; + hwg_hprint(cval, "timeout(2)"); + + cNval[0] = 0; + c0val = RAW_COUNT(); + tid = timeout((void (*)()) pciba_timeout, (void *) &tsema, HZ, (void *) cNval); + + /* FIXME : this probably needs to be down_interruptible() */ + + if (down(&tsema) < 0) { /* wait for the pciba_timeout */ + untimeout(tid); + PRINT_WARNING("pciba: timeout(HZ) time check aborted\n"); + return; + } + cval = cNval[0]; + if (cval == 0) { + untimeout(tid); + PRINT_WARNING("pciba: timeout(HZ) time not logged\n"); + return; + } + cval = cval - c0val; + hwg_hprint(cval, "timeout(HZ)"); + + printk("verifying untimeout() cancells ...\n"); + cNval[0] = 0; + tid = timeout((void (*)()) pciba_timeout, (void *) 0, 2, (void *) cNval); + untimeout(tid); + DELAY(1000000); + cval = cNval[0]; + if (cval != 0) { + PRINT_ALERT("pciba: unable to cancel two-tick timeout\n"); + cval -= c0val; + hwg_hprint(cval, "CANCELLED timeout(2)"); + } +} +#endif + +int +pciba_reg(void) +{ +#if DEBUG_PCIBA + printk("pciba_reg()\n"); +#endif + pciio_driver_register(-1, -1, "pciba_", 0); + +#if HWG_PERF_CHECK && IP30 && !DEBUG + printk("%s %d\n", __FUNCTION__, __LINE__); +pciba_timeout_test(); +#endif + +#if DEBUG_REFCT + { + char *cname = "pciba"; + char *dname = "ptv"; + char *cpath0 = "node/xtalk/15"; + char *uname0 = "0"; + char *cpath1 = "node/xtalk/13"; + char *uname1 = "1"; + devfs_handle_t conn; + devfs_handle_t conv; + devfs_handle_t vhdl; + int ret; + + printk("pciba refct tests:\n"); + +#define SHOWREF(vhdl,func) printk("ref=%d\t%s\t(%d) %v\n", hwgraph_vertex_refct(vhdl), #func, vhdl, vhdl); + + if (GRAPH_SUCCESS != (ret = hwgraph_path_add(hwgraph_root, cname, &conv))) + printk("\tunable to create conv (ret=%d)\n", ret); + else { SHOWREF(conv, hwgraph_path_add); + if (GRAPH_SUCCESS != (ret = hwgraph_traverse(hwgraph_root, cpath0, &conn))) + printk("\tunable to find %s (ret=%d)\n", cpath0, ret); + else { SHOWREF(conn, hwgraph_traverse); + if (GRAPH_SUCCESS != (ret = hwgraph_char_device_add(conn, dname, "pciba_", &vhdl))) + printk("unable to create %v/%s (ret=%d)\n", conn, dname, ret); + else { SHOWREF(vhdl, hwgraph_char_device_add); + hwgraph_chmod(vhdl, 0666); SHOWREF(vhdl, hwgraph_chmod); + if (GRAPH_SUCCESS != (ret = hwgraph_edge_add(conv, vhdl, uname0))) + printk("unable to create %v/%s (ret=%d)\n", conn, uname0, vhdl, ret); + else SHOWREF(vhdl, hwgraph_edge_add); + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(vhdl))) + printk("unable to unref %v\n", vhdl); + else SHOWREF(vhdl, hwgraph_vertex_unref); + } + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(conn))) + printk("unable to unref %v\n", conn); + else SHOWREF(conn, hwgraph_vertex_unref); + } + + if (GRAPH_SUCCESS != (ret = hwgraph_traverse(hwgraph_root, cpath1, &conn))) + printk("\tunable to find %s (ret=%d)\n", cpath1, ret); + else { SHOWREF(conn, hwgraph_traverse); + if (GRAPH_SUCCESS != (ret = hwgraph_char_device_add(conn, dname, "pciba_", &vhdl))) + printk("unable to create %v/%s (ret=%d)\n", conn, dname, ret); + else { SHOWREF(vhdl, hwgraph_char_device_add); + hwgraph_chmod(vhdl, 0666); SHOWREF(vhdl, hwgraph_chmod); + if (GRAPH_SUCCESS != (ret = hwgraph_edge_add(conv, vhdl, uname1))) + printk("unable to create %v/%s (ret=%d)\n", conn, uname1, vhdl, ret); + else SHOWREF(vhdl, hwgraph_edge_add); + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(vhdl))) + printk("unable to unref %v\n", vhdl); + else SHOWREF(vhdl, hwgraph_vertex_unref); + } + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(conn))) + printk("unable to unref %v\n", conn); + else SHOWREF(conn, hwgraph_vertex_unref); + } + + if (GRAPH_SUCCESS != (ret = hwgraph_traverse(hwgraph_root, cpath0, &conn))) + printk("\tunable to find %s (ret=%d)\n", cpath0, ret); + else { SHOWREF(conn, hwgraph_traverse); + if (GRAPH_SUCCESS != (ret = hwgraph_traverse(conn, dname, &vhdl))) + printk("\tunable to find %v/%s (ret=%d)\n", conn, dname, ret); + else { SHOWREF(vhdl, hwgraph_traverse); + if (GRAPH_SUCCESS != (ret = hwgraph_edge_remove(conv, uname0, NULL))) + printk("\tunable to remove edge %v/%s (ret=%d)\n", conv, uname0, ret); + else SHOWREF(vhdl, hwgraph_edge_remove); + if (GRAPH_SUCCESS != (ret = hwgraph_edge_remove(conn, dname, NULL))) + printk("\tunable to remove edge %v/%s (ret=%d)\n", conn, dname, ret); + else SHOWREF(vhdl, hwgraph_edge_remove); + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(vhdl))) + printk("unable to unref %v\n", vhdl); + else SHOWREF(vhdl, hwgraph_vertex_unref); + if (GRAPH_SUCCESS == (ret = hwgraph_vertex_destroy(vhdl))) + printk("\tvertex %d destroyed OK\n", vhdl); + else SHOWREF(vhdl, hwgraph_vertex_destroy); + } + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(conn))) + printk("unable to unref %v\n", conn); + else SHOWREF(conn, hwgraph_vertex_unref); + } + + if (GRAPH_SUCCESS != (ret = hwgraph_traverse(hwgraph_root, cpath1, &conn))) + printk("\tunable to find %s (ret=%d)\n", cpath1, ret); + else { SHOWREF(conn, hwgraph_traverse); + if (GRAPH_SUCCESS != (ret = hwgraph_traverse(conn, dname, &vhdl))) + printk("\tunable to find %v/%s (ret=%d)\n", conn, dname, ret); + else { SHOWREF(vhdl, hwgraph_traverse); + if (GRAPH_SUCCESS != (ret = hwgraph_edge_remove(conv, uname1, NULL))) + printk("\tunable to remove edge %v/%s (ret=%d)\n", conv, uname1, ret); + else SHOWREF(vhdl, hwgraph_edge_remove); + if (GRAPH_SUCCESS != (ret = hwgraph_edge_remove(conn, dname, NULL))) + printk("\tunable to remove edge %v/%s (ret=%d)\n", conn, dname, ret); + else SHOWREF(vhdl, hwgraph_edge_remove); + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(vhdl))) + printk("unable to unref %v\n", vhdl); + else SHOWREF(vhdl, hwgraph_vertex_unref); + if (GRAPH_SUCCESS == (ret = hwgraph_vertex_destroy(vhdl))) + printk("\tvertex %d destroyed OK\n", vhdl); + else SHOWREF(vhdl, hwgraph_vertex_destroy); + } + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(conn))) + printk("unable to unref %v\n", conn); + else SHOWREF(conn, hwgraph_vertex_unref); + } + + if (GRAPH_SUCCESS != (ret = hwgraph_edge_remove(hwgraph_root, cname, NULL))) + printk("\tunable to remove edge %v/%s (ret=%d)\n", hwgraph_root, cname, ret); + else SHOWREF(conv, hwgraph_edge_remove); + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(conv))) + printk("unable to unref %v\n", conv); + else SHOWREF(conv, hwgraph_vertex_unref); + if (GRAPH_SUCCESS == (ret = hwgraph_vertex_destroy(conv))) + printk("\tvertex %d destroyed OK\n", conv); + else SHOWREF(conv, hwgraph_vertex_destroy); + } + } +#endif + + return 0; +} + +#endif +int +pciba_attach(devfs_handle_t hconn) +{ +#if defined(PCIIO_SLOT_NONE) + pciio_info_t info = pciio_info_get(hconn); + pciio_slot_t slot = pciio_info_slot_get(info); +#endif + pciba_comm_t comm; + pciba_bus_t bus; + int ht; + devfs_handle_t hbase; + devfs_handle_t gconn; + devfs_handle_t gbase; + int win; + int wins; + pciio_space_t space; + pciaddr_t base; + + int iwins; + int mwins; + +#if DEBUG_PCIBA + printk("pciba_attach(%p)\n", hconn); +#endif + + /* Pick up "dualslot guest" vertex, + * which gets all functionality except + * config space access. + */ + if ((GRAPH_SUCCESS != + hwgraph_traverse(hconn, ".guest", &gconn)) || + (hconn == gconn)) + gconn = GRAPH_VERTEX_NONE; + + bus = pciba_find_bus(hconn, 1); + bus->refct ++; + + /* set up data common to all pciba openables + * on this connection point. + */ + NEW(comm); + comm->conn = hconn; + comm->bus = bus; + comm->refct = 0; + sema_init(&comm->lock, 1); + +#if !defined(PCIIO_SLOT_NONE) + if (bus->refct == 1) +#else + if (slot == PCIIO_SLOT_NONE) +#endif + { + pciio_info_t pciio_info; + devfs_handle_t master; + + pciio_info = pciio_info_get(hconn); + master = pciio_info_master_get(pciio_info); + + pciba_sub_attach(comm, PCIIO_SPACE_IO, PCIIO_SPACE_IO, 0, master, master, PCIBA_EDGE_LBL_IO); + pciba_sub_attach(comm, PCIIO_SPACE_MEM, PCIIO_SPACE_MEM, 0, master, master, PCIBA_EDGE_LBL_MEM); +#if defined(PCIIO_SLOT_NONE) + return 0; +#endif + } + + ht = 0x7F & pciio_config_get(hconn, PCI_CFG_HEADER_TYPE, 1); + + wins = ((ht == 0x00) ? 6 : + (ht == 0x01) ? 2 : + 0); + + mwins = iwins = 0; + + hbase = GRAPH_VERTEX_NONE; + gbase = GRAPH_VERTEX_NONE; + + for (win = 0; win < wins; win++) { + + base = pciio_config_get(hconn, PCI_CFG_BASE_ADDR(win), 4); + if (base & 1) { + space = PCIIO_SPACE_IO; + base &= 0xFFFFFFFC; + } else if ((base & 7) == 4) { + space = PCIIO_SPACE_MEM; + base &= 0xFFFFFFF0; + base |= ((pciaddr_t) pciio_config_get(hconn, PCI_CFG_BASE_ADDR(win + 1), 4)) << 32; + } else { + space = PCIIO_SPACE_MEM; + base &= 0xFFFFFFF0; + } + + if (!base) + break; + +#if PCIBA_ALIGN_CHECK + if (base & (_PAGESZ - 1)) { +#if DEBUG_PCIBA + PRINT_WARNING("%p pciba: BASE%d not page aligned!\n" + "\tmmap this window at offset 0x%x via \".../pci/%s\"\n", + hconn, win, base, + (space == PCIIO_SPACE_IO) ? "io" : "mem"); +#endif + continue; /* next window */ + } +#endif + + if ((hbase == GRAPH_VERTEX_NONE) && + ((GRAPH_SUCCESS != + hwgraph_path_add(hconn, PCIBA_EDGE_LBL_BASE, &hbase)) || + (hbase == GRAPH_VERTEX_NONE))) + break; /* no base vertex, no more windows. */ + + if ((gconn != GRAPH_VERTEX_NONE) && + (gbase == GRAPH_VERTEX_NONE) && + ((GRAPH_SUCCESS != + hwgraph_path_add(gconn, PCIBA_EDGE_LBL_BASE, &gbase)) || + (gbase == GRAPH_VERTEX_NONE))) + break; /* no base vertex, no more windows. */ + + pciba_sub_attach(comm, PCIIO_SPACE_WIN(win), space, base, hbase, gbase, PCIBA_EDGE_LBL_WIN(win)); + + if (space == PCIIO_SPACE_IO) { + if (!iwins++) { + pciba_sub_attach(comm, PCIIO_SPACE_WIN(win), space, base, hconn, gconn, PCIBA_EDGE_LBL_IO); + } + } else { + if (!mwins++) { + pciba_sub_attach(comm, PCIIO_SPACE_WIN(win), space, base, hconn, gconn, PCIBA_EDGE_LBL_MEM); + } + } + + if ((base & 7) == 4) + win++; + } + + pciba_sub_attach(comm, PCIIO_SPACE_CFG, PCIIO_SPACE_NONE, 0, hconn, gconn, PCIBA_EDGE_LBL_CFG); + pciba_sub_attach(comm, PCIBA_SPACE_UDMA, PCIIO_SPACE_NONE, 0, hconn, gconn, PCIBA_EDGE_LBL_DMA); +#if ULI + pciba_sub_attach(comm, PCIIO_SPACE_NONE, PCIIO_SPACE_NONE, 0, hconn, gconn, PCIBA_EDGE_LBL_INTR); +#endif + + /* XXX should ignore if device is an IOC3 */ + if (ht == 0x01) + base = pciio_config_get(hconn, PCI_EXPANSION_ROM+8, 4); + else + base = pciio_config_get(hconn, PCI_EXPANSION_ROM, 4); + + base &= 0xFFFFF000; + + if (base) { + if (base & (_PAGESZ - 1)) +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_WARNING("%v pciba: ROM is 0x%x\n" + "\tnot page aligned, mmap will be difficult\n", + hconn, base); +#else + PRINT_WARNING("0x%x pciba: ROM is 0x%x\n" + "\tnot page aligned, mmap will be difficult\n", + hconn, base); +#endif + pciba_sub_attach(comm, PCIIO_SPACE_ROM, PCIIO_SPACE_MEM, base, hconn, gconn, PCIBA_EDGE_LBL_ROM); + } + +#if !FICUS /* FICUS shorts the refct by one on path_add */ + if (hbase != GRAPH_VERTEX_NONE) + hwgraph_vertex_unref(hbase); + + if (gbase != GRAPH_VERTEX_NONE) + hwgraph_vertex_unref(gbase); +#endif + + return 0; +} + +static void +pciba_sub_attach2(pciba_comm_t comm, + pciio_space_t space, + pciio_space_t iomem, + pciaddr_t base, + devfs_handle_t from, + char *name, + char *suf, + unsigned bigend) +{ + char nbuf[128]; + pciba_soft_t soft; + devfs_handle_t handle = NULL; + + if (suf && *suf) { + strcpy(nbuf, name); + name = nbuf; + strcat(name, suf); + } + +#if DEBUG_PCIBA + printk("pciba_sub_attach2 %p/%s %p at %p[%x]\n", + from, name, space, space_desc, iomem, space_desc, base, from, name); +#endif + + if (space < TRACKED_SPACES) + if ((soft = comm->soft[space][bigend]) != NULL) { + soft->refct ++; + hwgraph_edge_add(from, soft->vhdl, name); + return; + } + + NEW(soft); + if (!soft) + return; + + soft->comm = comm; + soft->space = space; + soft->size = 0; + soft->iomem = iomem; + soft->base = base; + soft->refct = 1; + + if (space == PCIIO_SPACE_NONE) + soft->flags = 0; + else if (bigend) + soft->flags = PCIIO_BYTE_STREAM; + else + soft->flags = PCIIO_WORD_VALUES; + + handle = hwgraph_register(from, name, + 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &pciba_fops, NULL); + soft->vhdl = handle; + pciba_soft_set(soft->vhdl, soft); + if (space < TRACKED_SPACES) + comm->soft[space][bigend] = soft; + comm->refct ++; +} + +static void +pciba_sub_attach1(pciba_comm_t comm, + pciio_space_t space, + pciio_space_t iomem, + pciaddr_t base, + devfs_handle_t hfrom, + devfs_handle_t gfrom, + char *name, + char *suf, + unsigned bigend) +{ + pciba_sub_attach2(comm, space, iomem, base, hfrom, name, suf, bigend); + if ((gfrom != GRAPH_VERTEX_NONE) && (gfrom != hfrom)) + pciba_sub_attach2(comm, space, iomem, base, gfrom, name, suf, bigend); +} + +static void +pciba_sub_attach(pciba_comm_t comm, + pciio_space_t space, + pciio_space_t iomem, + pciaddr_t base, + devfs_handle_t hfrom, + devfs_handle_t gfrom, + char *name) +{ + pciba_sub_attach1(comm, space, iomem, base, hfrom, gfrom, name, NULL, 0); + if (iomem != PCIIO_SPACE_NONE) { + pciba_sub_attach1(comm, space, iomem, base, hfrom, gfrom, name, "_le", 0); + pciba_sub_attach1(comm, space, iomem, base, hfrom, gfrom, name, "_be", 1); + } +} + +#ifdef LATER +static void +pciba_reload_me(devfs_handle_t pconn_vhdl) +{ + devfs_handle_t vhdl; + +#if DEBUG_PCIBA + printf("pciba_reload_me(%v)\n", pconn_vhdl); +#endif + + if (GRAPH_SUCCESS != + hwgraph_traverse(pconn_vhdl, PCIBA_EDGE_LBL_CFG, &vhdl)) + return; + + hwgraph_vertex_unref(vhdl); +} +#endif /* LATER */ + +static pciba_bus_t +pciba_find_bus(devfs_handle_t pconn, int cflag) +{ + pciio_info_t pciio_info; + devfs_handle_t master; + arbitrary_info_t ainfo; + pciba_bus_t bus; + + pciio_info = pciio_info_get(pconn); + master = pciio_info_master_get(pciio_info); + + if (GRAPH_SUCCESS == + hwgraph_info_get_LBL(master, PCIBA_INFO_LBL_BUS, &ainfo)) + return (pciba_bus_t) ainfo; + + if (!cflag) + return 0; + + NEW(bus); + if (!bus) + return 0; + + sema_init(&bus->lock, 1); + + ainfo = (arbitrary_info_t) bus; + hwgraph_info_add_LBL(master, PCIBA_INFO_LBL_BUS, ainfo); + hwgraph_info_get_LBL(master, PCIBA_INFO_LBL_BUS, &ainfo); + if ((pciba_bus_t) ainfo != bus) + DEL(bus); +#if DEBUG_PCIBA + else + printk("pcbia_find_bus: new bus at %p\n", master); +#endif + + return (pciba_bus_t) ainfo; +} + +#ifdef LATER +static void +pciba_map_push(pciba_bus_t bus, pciba_map_t map) +{ +#if DEBUG_PCIBA + printk("pciba_map_push(bus=0x%x, map=0x%x, hdl=0x%x\n", + bus, map, map->handle); +#endif + pciba_bus_lock(bus); + map->next = bus->maps; + bus->maps = map; + pciba_bus_unlock(bus); +} + +static pciba_map_t +pciba_map_pop_hdl(pciba_bus_t bus, __psunsigned_t handle) +{ + pciba_map_h hdl; + pciba_map_t map; + + pciba_bus_lock(bus); + for (hdl = &bus->maps; map = *hdl; hdl = &map->next) + if (map->handle == handle) { + *hdl = map->next; + break; + } + pciba_bus_unlock(bus); +#if DEBUG_PCIBA + printk("pciba_map_pop_va(bus=0x%x, handle=0x%x) returns map=0x%x\n", + bus, handle, map); +#endif + return map; +} + +/* ================================================================ + * driver teardown, unregister and unload + */ +int +pciba_unload(void) +{ +#if DEBUG_PCIBA + printk("pciba_unload()\n"); +#endif + + if (atomic_read(&pciba_prevent_unload)) + return -1; + + pciio_iterate("pciba_", pciba_unload_me); + + return 0; +} + +int +pciba_unreg(void) +{ + +#if DEBUG_PCIBA + printf("pciba_unreg()\n"); +#endif + + if (atomic_read(&pciba_prevent_unload)) + return -1; + + pciio_driver_unregister("pciba_"); + return 0; +} + +int +pciba_detach(devfs_handle_t conn) +{ + devfs_handle_t base; + pciba_bus_t bus; + devfs_handle_t gconn; + devfs_handle_t gbase; + + pciio_info_t pciio_info; + devfs_handle_t master; + arbitrary_info_t ainfo; + int ret; + +#if DEBUG_PCIBA + printf("pciba_detach(%v)\n", conn); +#endif + + if ((GRAPH_SUCCESS != + hwgraph_traverse(conn, ".guest", &gconn)) || + (conn == gconn)) + gconn = GRAPH_VERTEX_NONE; + + if (gconn != GRAPH_VERTEX_NONE) { + pciba_sub_detach(gconn, PCIBA_EDGE_LBL_CFG); + pciba_sub_detach(gconn, PCIBA_EDGE_LBL_DMA); + pciba_sub_detach(gconn, PCIBA_EDGE_LBL_ROM); +#if ULI + pciba_sub_detach(gconn, PCIBA_EDGE_LBL_INTR); +#endif + if (GRAPH_SUCCESS == hwgraph_edge_remove(conn, PCIBA_EDGE_LBL_BASE, &gbase)) { + pciba_sub_detach(gconn, PCIBA_EDGE_LBL_MEM); + pciba_sub_detach(gconn, PCIBA_EDGE_LBL_IO); + pciba_sub_detach(gbase, "0"); + pciba_sub_detach(gbase, "1"); + pciba_sub_detach(gbase, "2"); + pciba_sub_detach(gbase, "3"); + pciba_sub_detach(gbase, "4"); + pciba_sub_detach(gbase, "5"); + hwgraph_vertex_unref(gbase); + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_destroy(gbase))) { +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_WARNING("pciba: hwgraph_vertex_destroy(%v/base) failed (%d)", + conn, ret); +#else + PRINT_WARNING("pciba: hwgraph_vertex_destroy(0x%x/base) failed (%d)", + conn, ret); +#endif +#if DEBUG_REFCT + printk("\tretained refct %d\n", hwgraph_vertex_refct(gbase)); +#endif + } + } + } + + pciba_sub_detach(conn, PCIBA_EDGE_LBL_CFG); + pciba_sub_detach(conn, PCIBA_EDGE_LBL_DMA); + pciba_sub_detach(conn, PCIBA_EDGE_LBL_ROM); +#if ULI + pciba_sub_detach(conn, PCIBA_EDGE_LBL_INTR); +#endif + + if (GRAPH_SUCCESS == hwgraph_edge_remove(conn, PCIBA_EDGE_LBL_BASE, &base)) { + pciba_sub_detach(conn, PCIBA_EDGE_LBL_MEM); + pciba_sub_detach(conn, PCIBA_EDGE_LBL_IO); + pciba_sub_detach(base, "0"); + pciba_sub_detach(base, "1"); + pciba_sub_detach(base, "2"); + pciba_sub_detach(base, "3"); + pciba_sub_detach(base, "4"); + pciba_sub_detach(base, "5"); + hwgraph_vertex_unref(base); + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_destroy(base))) { +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_WARNING(CE_WARN, "pciba: hwgraph_vertex_destroy(%v/base) failed (%d)", + conn, ret); +#else + PRINT_WARNING(CE_WARN, "pciba: hwgraph_vertex_destroy(0x%x/base) failed (%d)", + conn, ret); +#endif +#if DEBUG_REFCT + printk("\tretained refct %d\n", hwgraph_vertex_refct(base)); +#endif + } + } + + bus = pciba_find_bus(conn, 0); + if (bus && !--(bus->refct)) { + + pciio_info = pciio_info_get(conn); + + master = pciio_info_master_get(pciio_info); + + pciba_sub_detach(master, PCIBA_EDGE_LBL_IO); + pciba_sub_detach(master, PCIBA_EDGE_LBL_MEM); + pciba_sub_detach(master, PCIBA_EDGE_LBL_CFG); + hwgraph_info_remove_LBL(master, PCIBA_INFO_LBL_BUS, &ainfo); + +#if DEBUG_PCIBA + printf("pcbia_detach: DEL(bus) at %v\n", master); +#endif + DEL(bus); + } + + return 0; +} + +static void +pciba_sub_detach1(devfs_handle_t conn, + char *name, + char *suf) +{ + devfs_handle_t vhdl; + pciba_soft_t soft; + pciba_comm_t comm; + int ret; + char nbuf[128]; + + if (suf && *suf) { + strcpy(nbuf, name); + name = nbuf; + strcat(name, suf); + } + + if ((GRAPH_SUCCESS == hwgraph_edge_remove(conn, name, &vhdl)) && + ((soft = pciba_soft_get(vhdl)) != NULL)) { +#if DEBUG_PCIBA +#if defined(SUPPORT_PRINTING_V_FORMAT) + prink("pciba_sub_detach(%v,%s)\n", conn, name); +#else + prink("pciba_sub_detach(0x%x,%s)\n", conn, name); +#endif +#endif + + hwgraph_vertex_unref(soft->vhdl); +#if DEBUG_REFCT + printk("\tadjusted refct %d (soft ref: %d)\n", + hwgraph_vertex_refct(vhdl), + soft->refct); +#endif + if (!--(soft->refct)) { + comm = soft->comm; + if (!--(comm->refct)) { + DEL(comm); + } + pciba_soft_set(vhdl, 0); + DEL(soft); + + hwgraph_vertex_unref(vhdl); + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_destroy(vhdl))) { +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_WARNING("pciba: hwgraph_vertex_destroy(0x%x/%s) failed (%d)", + conn, name, ret); +#else + PRINT_WARNING("pciba: hwgraph_vertex_destroy(%v/%s) failed (%d)", + conn, name, ret); +#endif +#if DEBUG_REFCT + printk("\tretained refct %d\n", hwgraph_vertex_refct(vhdl)); +#endif + } + } + } +} + +static void +pciba_sub_detach(devfs_handle_t conn, + char *name) +{ + pciba_sub_detach1(conn, name, ""); + pciba_sub_detach1(conn, name, "_le"); + pciba_sub_detach1(conn, name, "_be"); +} + +static void +pciba_unload_me(devfs_handle_t pconn_vhdl) +{ + devfs_handle_t c_vhdl; + +#if DEBUG_PCIBA + printf("pciba_unload_me(%v)\n", pconn_vhdl); +#endif + + if (GRAPH_SUCCESS != + hwgraph_traverse(pconn_vhdl, PCIBA_EDGE_LBL_CFG, &c_vhdl)) + return; + + hwgraph_vertex_unref(c_vhdl); +} + +/* ================================================================ + * standard unix entry points + */ + +/*ARGSUSED */ +int +pciba_open(dev_t *devp, int flag, int otyp, struct cred *crp) +{ + +#if DEBUG_PCIBA + printf("pciba_open(%V)\n", *devp); +#endif + return 0; +} + +/*ARGSUSED */ +int +pciba_close(dev_t dev) +{ + devfs_handle_t vhdl = dev_to_vhdl(dev); + pciba_soft_t soft = pciba_soft_get(vhdl); + +#if DEBUG_PCIBA + printf("pciba_close(%V)\n", dev); +#endif + + /* if there is pending DMA for this device, hit the + * device over the head with a baseball bat and + * release the system memory resources. + */ + if (soft && soft->comm->dmap) { + pciba_dma_t next; + pciba_dma_t dmap; + + pciba_soft_lock(soft); + if (dmap = soft->comm->dmap) { + soft->comm->dmap = 0; + + pciio_reset(soft->comm->conn); + + do { + if (!dmap->kaddr) + break; + if (!dmap->paddr) + break; + if (dmap->bytes < NBPP) + break; + next = dmap->next; + kvpfree(dmap->kaddr, dmap->bytes / NBPP); + dmap->paddr = 0; + dmap->bytes = 0; + DEL(dmap); + } while (dmap = next); + } + pciba_soft_unlock(soft); + } + return 0; +} + +/* ARGSUSED */ +int +pciba_read(dev_t dev, cred_t *crp) +{ +#if DEBUG_PCIBA + printf("pciba_read(%V)\n", dev); +#endif + + return EINVAL; +} + +/* ARGSUSED */ +int +pciba_write(dev_t dev, cred_t *crp) +{ +#if DEBUG_PCIBA + printf("pciba_write(%V)\n", dev); +#endif + + return EINVAL; +} + +/*ARGSUSED */ +int +pciba_ioctl(dev_t dev, int cmd, void *uarg, int mode, cred_t *crp, int *rvalp) +{ + devfs_handle_t vhdl; + pciba_soft_t soft; + pciio_space_t space; + ioctl_arg_buffer_t arg; + int psize; + int err = 0; + +#if ULI + char abi = get_current_abi(); + pciio_intr_t intr=0; + device_desc_t desc; + cpuid_t intrcpu; + unsigned lines; + struct uli *uli = 0; +#endif + unsigned flags; + void *kaddr = 0; + iopaddr_t paddr; + pciba_dma_h dmah; + pciba_dma_t dmap = 0; + pciio_dmamap_t dmamap = 0; + size_t bytes; + int pages; + pciaddr_t daddr; + +#if DEBUG_PCIBA + printf("pciba_ioctl(%V,0x%x)\n", dev, cmd); +#endif + + psize = (cmd >> 16) & IOCPARM_MASK; + +#if ULI + ASSERT(sizeof(struct uliargs) > 8); /* prevent CFG access conflict */ + ASSERT(sizeof(struct uliargs) <= IOCPARM_MASK); +#endif + + arg.ca = uarg; + + if ((psize > 0) && (cmd & (IOC_OUT | IOC_IN))) { + if (psize > sizeof(arg)) + err = EINVAL; /* "bad parameter size */ + else { + if (cmd & IOC_OUT) + bzero(arg.data, psize); + if ((cmd & IOC_IN) && + (copyin(uarg, arg.data, psize) < 0)) + err = EFAULT; /* "parameter copyin failed" */ + } + } + vhdl = dev_to_vhdl(dev); + soft = pciba_soft_get(vhdl); + space = soft->space; + + if (err == 0) { + err = EINVAL; /* "invalid ioctl for this vertex" */ + switch (space) { +#if ULI + case PCIIO_SPACE_NONE: /* the "intr" vertex */ + /* PCIIOCSETULI: set up user interrupts. + */ + lines = cmd & 15; + if (ABI_IS_64BIT(abi)) { + if (cmd != PCIIOCSETULI(lines)) { + err = EINVAL; /* "invalid ioctl for this vertex" */ + break; + } + } + else { + struct uliargs uliargs; + + if (cmd != PCIIOCSETULI32(lines)) { + err = EINVAL; /* "invalid ioctl for this vertex" */ + break; + } + + uliargs32_to_uliargs(&arg.uli32, &uliargs); + arg.uli = uliargs; + } + desc = device_desc_dup(soft->comm->conn); + device_desc_flags_set(desc, (device_desc_flags_get(desc) | + D_INTR_NOTHREAD)); + device_desc_intr_swlevel_set(desc, INTR_SWLEVEL_NOTHREAD_DEFAULT); + device_desc_intr_name_set(desc, "PCIBA"); + device_desc_default_set(soft->comm->conn, desc); + + /* When designating interrupts, the slot number + * is taken from the connection point. + * Bits 0..3 are used to select INTA..INTD; more + * than one bit can be specified. These should + * be constructed using PCIIO_INTR_LINE_[ABCD]. + */ + intr = pciio_intr_alloc + (soft->comm->conn, desc, lines, soft->vhdl); + if (intr == 0) { + err = ENOMEM; /* "insufficient resources" */ + break; + } + intrcpu = cpuvertex_to_cpuid(pciio_intr_cpu_get(intr)); + + if (err = new_uli(&arg.uli, &uli, intrcpu)) { + break; /* "unable to set up ULI" */ + } + atomic_inc(&pciba_prevent_unload); + + pciio_intr_connect(intr, pciba_intr, uli, (void *) 0); + + /* NOTE: don't set the teardown function + * until the interrupt is connected. + */ + uli->teardownarg1 = (__psint_t) intr; + uli->teardown = pciba_clearuli; + + arg.uli.id = uli->index; + + if (!ABI_IS_64BIT(abi)) { + struct uliargs32 uliargs32; + uliargs_to_uliargs32(&arg.uli, &uliargs32); + arg.uli32 = uliargs32; + } + + err = 0; + break; +#endif + + case PCIBA_SPACE_UDMA: /* the "dma" vertex */ + + switch (cmd) { + + case PCIIOCDMAALLOC: + /* PCIIOCDMAALLOC: allocate a chunk of physical + * memory and set it up for DMA. Return the + * PCI address that gets to it. + * NOTE: this allocates memory local to the + * CPU doing the ioctl, not local to the + * device that will be doing the DMA. + */ + + if (!_CAP_ABLE(CAP_DEVICE_MGT)) { + err = EPERM; + break; + } + /* separate the halves of the incoming parameter */ + flags = arg.ud >> 32; + bytes = arg.ud & 0xFFFFFFFF; + +#if DEBUG_PCIBA + printf("pciba: user wants 0x%x bytes of DMA, flags 0x%x\n", + bytes, flags); +#endif + + /* round up the requested size to the next highest page */ + pages = (bytes + NBPP - 1) / NBPP; + + /* make sure the requested size is something reasonable */ + if (pages > pci_user_dma_max_pages) { +#if DEBUG_PCIBA + printf("pciba: request for too much buffer space\n"); +#endif + err = EINVAL; + break; /* "request for too much buffer space" */ + } + /* "correct" number of bytes */ + bytes = pages * NBPP; + + /* allocate the space */ + /* XXX- force to same node as the device? */ + /* XXX- someday, we want to handle user buffers, + * and noncontiguous pages, but this will + * require either fancy mapping or handing + * a list of blocks back to the user. For + * now, just tell users to allocate a lot of + * individual single-pages and manage their + * scatter-gather manually. + */ + kaddr = kvpalloc(pages, VM_DIRECT | KM_NOSLEEP, 0); + if (kaddr == 0) { +#if DEBUG_PCIBA + printf("pciba: unable to get %d contiguous pages\n", pages); +#endif + err = EAGAIN; /* "insufficient resources, try again later" */ + break; + } +#if DEBUG_PCIBA + printf("pciba: kaddr is 0x%x\n", kaddr); +#endif + paddr = kvtophys(kaddr); + + daddr = pciio_dmatrans_addr + (soft->comm->conn, 0, paddr, bytes, flags); + if (daddr == 0) { /* "no direct path available" */ +#if DEBUG_PCIBA + printf("pciba: dmatrans failed, trying dmamap\n"); +#endif + dmamap = pciio_dmamap_alloc + (soft->comm->conn, 0, bytes, flags); + if (dmamap == 0) { +#if DEBUG_PCIBA + printf("pciba: unable to allocate dmamap\n"); +#endif + err = ENOMEM; + break; /* "out of mapping resources" */ + } + daddr = pciio_dmamap_addr + (dmamap, paddr, bytes); + if (daddr == 0) { +#if DEBUG_PCIBA + printf("pciba: dmamap_addr failed\n"); +#endif + err = EINVAL; + break; /* "can't get there from here" */ + } + } +#if DEBUG_PCIBA + printf("pciba: daddr is 0x%x\n", daddr); +#endif + NEW(dmap); + if (!dmap) { + err = ENOMEM; + break; /* "no memory available" */ + } + dmap->bytes = bytes; + dmap->pages = pages; + dmap->paddr = paddr; + dmap->kaddr = kaddr; + dmap->map = dmamap; + dmap->daddr = daddr; + dmap->handle = 0; + +#if DEBUG_PCIBA + printf("pciba: dmap 0x%x contains va 0x%x bytes 0x%x pa 0x%x pages 0x%x daddr 0x%x\n", + dmap, kaddr, bytes, paddr, pages, daddr); +#endif + + arg.ud = dmap->daddr; + + err = 0; + break; + + case PCIIOCDMAFREE: + /* PCIIOCDMAFREE: Find the chunk of + * User DMA memory, and release its + * resources back to the system. + */ + + if (!_CAP_ABLE(CAP_DEVICE_MGT)) { + err = EPERM; /* "you can't do that" */ + break; + } + if (soft->comm->dmap == NULL) { + err = EINVAL; /* "no User DMA to free" */ + break; + } + /* find the request. */ + daddr = arg.ud; + err = EINVAL; /* "block not found" */ + pciba_soft_lock(soft); + for (dmah = &soft->comm->dmap; dmap = *dmah; dmah = &dmap->next) { + if (dmap->daddr == daddr) { + if (dmap->handle != 0) { + dmap = 0; /* don't DEL this dmap! */ + err = EINVAL; /* "please unmap first" */ + break; /* break outa for loop. */ + } + *dmah = dmap->next; + + if (dmamap = dmap->map) { + pciio_dmamap_free(dmamap); + dmamap = 0; /* don't free it twice! */ + } + kvpfree(dmap->kaddr, dmap->bytes / NBPP); + DEL(dmap); + dmap = 0; /* don't link this back into the list! */ + err = 0; /* "all done" */ + break; /* break outa for loop. */ + } + } + pciba_soft_unlock(soft); + break; /* break outa case PCIIOCDMAFREE: */ + } + break; /* break outa case PCIBA_SPACE_UDMA: */ + + case PCIIO_SPACE_CFG: + + /* PCIIOCCFG{RD,WR}: read and/or write + * PCI configuration space. If both, + * the read happens first (this becomes + * a swap operation, atomic with respect + * to other updates through this path). + * + * Should be *last* IOCTl command checked, + * so other patterns can nip useless codes + * out of the space this decodes. + */ + err = EINVAL; + if ((psize > 0) || (psize <= 8) && + (((cmd & 0xFF) + psize) <= 256) && + (cmd & (IOC_IN | IOC_OUT))) { + + uint64_t rdata; + uint64_t wdata; + int shft; + + shft = 64 - (8 * psize); + + wdata = arg.ud >> shft; + + pciba_soft_lock(soft); + + if (cmd & IOC_OUT) + rdata = pciio_config_get(soft->comm->conn, cmd & 0xFFFF, psize); + if (cmd & IOC_IN) + pciio_config_set(soft->comm->conn, cmd & 0xFFFF, psize, wdata); + + pciba_soft_unlock(soft); + + arg.ud = rdata << shft; + err = 0; + break; + } + break; + } + } + /* done: come here if all went OK. + */ + if ((err == 0) && + ((cmd & IOC_OUT) && (psize > 0)) && + copyout(arg.data, uarg, psize)) + err = EFAULT; + + /* This gets delayed until after the copyout so we + * do not free the dmap on a copyout error, or + * alternately end up with a dangling allocated + * buffer that the user never got back. + */ + if ((err == 0) && dmap) { + pciba_soft_lock(soft); + dmap->next = soft->comm->dmap; + soft->comm->dmap = dmap; + pciba_soft_unlock(soft); + } + if (err) { + /* Things went badly. Clean up. + */ +#if ULI + if (intr) { + pciio_intr_disconnect(intr); + pciio_intr_free(intr); + } + if (uli) + free_uli(uli); +#endif + if (dmap) { + if (dmap->map && (dmap->map != dmamap)) + pciio_dmamap_free(dmap->map); + DEL(dmap); + } + if (dmamap) + pciio_dmamap_free(dmamap); + if (kaddr) + kvpfree(kaddr, pages); + } + return *rvalp = err; +} + +/* ================================================================ + * mapping support + */ + +/*ARGSUSED */ +int +pciba_map(dev_t dev, vhandl_t *vt, + off_t off, size_t len, uint32_t prot) +{ + devfs_handle_t vhdl = dev_to_vhdl(dev); + pciba_soft_t soft = pciba_soft_get(vhdl); + devfs_handle_t conn = soft->comm->conn; + pciio_space_t space = soft->space; + size_t pages = (len + NBPP - 1) / NBPP; + pciio_piomap_t pciio_piomap = 0; + caddr_t kaddr; + pciba_map_t map; + pciba_dma_t dmap; + +#if DEBUG_PCIBA + printf("pciba_map(%V,vt=0x%x)\n", dev, vt); +#endif + + if (space == PCIBA_SPACE_UDMA) { + pciba_soft_lock(soft); + + for (dmap = soft->comm->dmap; dmap != NULL; dmap = dmap->next) { + if (off == dmap->daddr) { + if (pages != dmap->pages) { + pciba_soft_unlock(soft); + return EINVAL; /* "size mismatch" */ + } + v_mapphys(vt, dmap->kaddr, dmap->bytes); + dmap->handle = v_gethandle(vt); + pciba_soft_unlock(soft); +#if DEBUG_PCIBA + printf("pciba: mapped dma at kaddr 0x%x via handle 0x%x\n", + dmap->kaddr, dmap->handle); +#endif + return 0; + } + } + pciba_soft_unlock(soft); + return EINVAL; /* "block not found" */ + } + if (soft->iomem == PCIIO_SPACE_NONE) + return EINVAL; /* "mmap not supported" */ + + kaddr = (caddr_t) pciio_pio_addr + (conn, 0, space, off, len, &pciio_piomap, soft->flags | PCIIO_FIXED ); + +#if DEBUG_PCIBA + printf("pciba: mapped %R[0x%x..0x%x] via map 0x%x to kaddr 0x%x\n", + space, space_desc, off, off + len - 1, pciio_piomap, kaddr); +#endif + + if (kaddr == NULL) + return EINVAL; /* "you can't get there from here" */ + + NEW(map); + if (map == NULL) { + if (pciio_piomap) + pciio_piomap_free(pciio_piomap); + return ENOMEM; /* "unable to get memory resources */ + } +#ifdef LATER + map->uthread = curuthread; +#endif + map->handle = v_gethandle(vt); + map->uvaddr = v_getaddr(vt); + map->map = pciio_piomap; + map->space = soft->iomem; + map->base = soft->base + off; + map->size = len; + pciba_map_push(soft->comm->bus, map); + + /* Inform the system of the correct + * kvaddr corresponding to the thing + * that is being mapped. + */ + v_mapphys(vt, kaddr, len); + + return 0; +} + +/*ARGSUSED */ +int +pciba_unmap(dev_t dev, vhandl_t *vt) +{ + devfs_handle_t vhdl = dev_to_vhdl(dev); + pciba_soft_t soft = pciba_soft_get(vhdl); + pciba_bus_t bus = soft->comm->bus; + pciba_map_t map; + __psunsigned_t handle = v_gethandle(vt); + +#if DEBUG_PCIBA + printf("pciba_unmap(%V,vt=%x)\n", dev, vt); +#endif + + /* If this is a userDMA buffer, + * make a note that it has been unmapped + * so it can be released. + */ + if (soft->comm->dmap) { + pciba_dma_t dmap; + + pciba_soft_lock(soft); + for (dmap = soft->comm->dmap; dmap != NULL; dmap = dmap->next) + if (handle == dmap->handle) { + dmap->handle = 0; + pciba_soft_unlock(soft); +#if DEBUG_PCIBA + printf("pciba: unmapped dma at kaddr 0x%x via handle 0x%x\n", + dmap->kaddr, handle); +#endif + return 0; /* found userPCI */ + } + pciba_soft_unlock(soft); + } + map = pciba_map_pop_hdl(bus, handle); + if (map == NULL) + return EINVAL; /* no match */ + + if (map->map) + pciio_piomap_free(map->map); + DEL(map); + + return (0); /* all done OK */ +} + +#if ULI +void +pciba_clearuli(struct uli *uli) +{ + pciio_intr_t intr = (pciio_intr_t) uli->teardownarg1; + +#if DEBUG_PCIBA + printf("pciba_clearuli(0x%x)\n", uli); +#endif + + pciio_intr_disconnect(intr); + pciio_intr_free(intr); + atomic_dec(&pciba_prevent_unload); +} + +void +pciba_intr(intr_arg_t arg) +{ + struct uli *uli = (struct uli *) arg; + int ulinum = uli->index; + + extern void frs_handle_uli(void); + + if (ulinum >= 0 && ulinum < MAX_ULIS) { + uli_callup(ulinum); + + if (private.p_frs_flags) + frs_handle_uli(); + } +} +#endif +#endif /* LATER - undef as we implement each routine */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/pcibr.c linux.ac/arch/ia64/sn/io/pcibr.c --- linux.vanilla/arch/ia64/sn/io/pcibr.c Tue Apr 3 17:31:54 2001 +++ linux.ac/arch/ia64/sn/io/pcibr.c Sat Apr 14 01:18:00 2001 @@ -15,6 +15,7 @@ #include <linux/types.h> #include <linux/config.h> #include <linux/slab.h> +#include <linux/module.h> #include <asm/sn/sgi.h> #include <asm/sn/addrs.h> #include <asm/sn/arch.h> @@ -22,7 +23,6 @@ #include <asm/sn/invent.h> #include <asm/sn/hcl.h> #include <asm/sn/labelcl.h> -#include <asm/sn/cmn_err.h> #include <asm/sn/xtalk/xwidget.h> #include <asm/sn/pci/bridge.h> #include <asm/sn/pci/pciio.h> @@ -41,6 +41,14 @@ #include <asm/sn/sn1/hubio_next.h> #endif +#ifdef __ia64 +#define rmallocmap atemapalloc +#define rmfreemap atemapfree +#define rmfree atefree +#define rmalloc atealloc +#endif + +#undef PCIBR_ATE_DEBUG #if defined(BRINGUP) #if 0 #define DEBUG 1 /* To avoid lots of bad printk() formats leave off */ @@ -54,6 +62,24 @@ #define LOCAL static #endif +/* + * Macros related to the Lucent USS 302/312 usb timeout workaround. It + * appears that if the lucent part can get into a retry loop if it sees a + * DAC on the bus during a pio read retry. The loop is broken after about + * 1ms, so we need to set up bridges holding this part to allow at least + * 1ms for pio. + */ + +#define USS302_TIMEOUT_WAR + +#ifdef USS302_TIMEOUT_WAR +#include <asm/sn/io.h> +#define LUCENT_USBHC_VENDOR_ID_NUM 0x11c1 +#define LUCENT_USBHC302_DEVICE_ID_NUM 0x5801 +#define LUCENT_USBHC312_DEVICE_ID_NUM 0x5802 +#define USS302_BRIDGE_TIMEOUT_HLD 4 +#endif + #define PCIBR_LLP_CONTROL_WAR #if defined (PCIBR_LLP_CONTROL_WAR) int pcibr_llp_control_war_cnt; @@ -69,6 +95,7 @@ int pcibr_devflag = D_MP; +#ifdef LATER #define F(s,n) { 1l<<(s),-(s), n } struct reg_desc bridge_int_status_desc[] = @@ -246,6 +273,7 @@ {0} }; #endif +#endif /* LATER */ /* kbrick widgetnum-to-bus layout */ int p_busnum[MAX_PORT_NUM] = { /* widget# */ @@ -275,8 +303,8 @@ * CPU to a particular IO device are synched before the start of the next * set of PIO operations to the same device. */ -#define pcibr_lock(pcibr_soft) io_splock(pcibr_soft->bs_lock) -#define pcibr_unlock(pcibr_soft, s) io_spunlock(pcibr_soft->bs_lock,s) +#define pcibr_lock(pcibr_soft) io_splock(&pcibr_soft->bs_lock) +#define pcibr_unlock(pcibr_soft,s) io_spunlock(&pcibr_soft->bs_lock,s) #if PCIBR_SOFT_LIST typedef struct pcibr_list_s *pcibr_list_p; @@ -302,6 +330,31 @@ extern int hub_device_flags_set(devfs_handle_t widget_dev, hub_widget_flags_t flags); #endif +extern pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t); + +/* + * This is the file operation table for the pcibr driver. + * As each of the functions are implemented, put the + * appropriate function name below. + */ +struct file_operations pcibr_fops = { + owner: THIS_MODULE, + llseek: NULL, + read: NULL, + write: NULL, + readdir: NULL, + poll: NULL, + ioctl: NULL, + mmap: NULL, + open: NULL, + flush: NULL, + release: NULL, + fsync: NULL, + fasync: NULL, + lock: NULL, + readv: NULL, + writev: NULL +}; extern devfs_handle_t hwgraph_root; extern graph_error_t hwgraph_vertex_unref(devfs_handle_t vhdl); @@ -317,7 +370,7 @@ extern struct map *rmallocmap(uint64_t mapsiz); extern void rmfreemap(struct map *mp); extern int compare_and_swap_ptr(void **location, void *old_ptr, void *new_ptr); -extern void cmn_err_tag(int seqnumber, register int level, char *fmt, ...); +extern int io_path_map_widget(devfs_handle_t vertex); @@ -363,17 +416,13 @@ void pcibr_freeblock_sub(iopaddr_t *, iopaddr_t *, iopaddr_t, size_t); -#ifndef BRINGUP LOCAL int pcibr_init_ext_ate_ram(bridge_t *); -#endif LOCAL int pcibr_ate_alloc(pcibr_soft_t, int); LOCAL void pcibr_ate_free(pcibr_soft_t, int, int); LOCAL pcibr_info_t pcibr_info_get(devfs_handle_t); LOCAL pcibr_info_t pcibr_device_info_new(pcibr_soft_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); LOCAL void pcibr_device_info_free(devfs_handle_t, pciio_slot_t); -LOCAL int pcibr_device_attach(devfs_handle_t,pciio_slot_t); -LOCAL int pcibr_device_detach(devfs_handle_t,pciio_slot_t); LOCAL iopaddr_t pcibr_addr_pci_to_xio(devfs_handle_t, pciio_slot_t, pciio_space_t, iopaddr_t, size_t, unsigned); pcibr_piomap_t pcibr_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); @@ -411,7 +460,7 @@ devfs_handle_t pcibr_intr_cpu_get(pcibr_intr_t); void pcibr_xintr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); -void pcibr_intr_list_func(intr_arg_t); +void pcibr_intr_func(intr_arg_t); LOCAL void print_bridge_errcmd(uint32_t, char *); @@ -450,21 +499,32 @@ void pcibr_hints_intr_bits(devfs_handle_t, pcibr_intr_bits_f *); void pcibr_set_rrb_callback(devfs_handle_t, rrb_alloc_funct_t); void pcibr_hints_handsoff(devfs_handle_t); -void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, uint64_t); +void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, ulong); -LOCAL int pcibr_slot_reset(devfs_handle_t,pciio_slot_t); LOCAL int pcibr_slot_info_init(devfs_handle_t,pciio_slot_t); LOCAL int pcibr_slot_info_free(devfs_handle_t,pciio_slot_t); + +#ifdef LATER +LOCAL int pcibr_slot_info_return(pcibr_soft_t, pciio_slot_t, + pcibr_slot_info_resp_t); +LOCAL void pcibr_slot_func_info_return(pcibr_info_h, int, + pcibr_slot_func_info_resp_t); +#endif /* LATER */ + LOCAL int pcibr_slot_addr_space_init(devfs_handle_t,pciio_slot_t); LOCAL int pcibr_slot_device_init(devfs_handle_t, pciio_slot_t); LOCAL int pcibr_slot_guest_info_init(devfs_handle_t,pciio_slot_t); LOCAL int pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t); -LOCAL int pcibr_slot_call_device_attach(devfs_handle_t,pciio_slot_t); -LOCAL int pcibr_slot_call_device_detach(devfs_handle_t,pciio_slot_t); +LOCAL int pcibr_slot_call_device_attach(devfs_handle_t, + pciio_slot_t, int); +LOCAL int pcibr_slot_call_device_detach(devfs_handle_t, + pciio_slot_t, int); -int pcibr_slot_powerup(devfs_handle_t,pciio_slot_t); -int pcibr_slot_shutdown(devfs_handle_t,pciio_slot_t); -int pcibr_slot_inquiry(devfs_handle_t,pciio_slot_t); +LOCAL int pcibr_slot_detach(devfs_handle_t, pciio_slot_t, int); +LOCAL int pcibr_is_slot_sys_critical(devfs_handle_t, pciio_slot_t); +#ifdef LATER +LOCAL int pcibr_slot_query(devfs_handle_t, pcibr_slot_info_req_t); +#endif /* ===================================================================== * RRB management @@ -754,7 +814,7 @@ int final_vchan0; int final_vchan1; int avail_rrbs; - unsigned s; + unsigned long s; int error; /* @@ -930,7 +990,7 @@ pciio_info_t pciio_info; pciio_slot_t pciio_slot; pcibr_soft_t pcibr_soft; - unsigned s; + unsigned long s; int error = -1; if ((pciio_info = pciio_info_get(pconn_vhdl)) && @@ -978,11 +1038,7 @@ int dev_3_rrbs, int virt3, int dev_4_rrbs, int virt4) { devfs_handle_t pcibr_vhdl; -#ifdef colin - pcibr_soft_t pcibr_soft; -#else - pcibr_soft_t pcibr_soft = NULL; -#endif + pcibr_soft_t pcibr_soft = NULL; bridge_t *bridge = NULL; uint32_t rrb_setting = 0; @@ -991,7 +1047,7 @@ int dev_rrbs[4]; int virt[4]; int i, j; - unsigned s; + unsigned long s; if (GRAPH_SUCCESS == hwgraph_traverse(vhdl, EDGE_LBL_PCI, &pcibr_vhdl)) { @@ -1089,7 +1145,7 @@ pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); bridge_t *bridge = pcibr_soft->bs_base; - unsigned s; + unsigned long s; reg_p rrbp; unsigned rrbm; int i; @@ -1141,7 +1197,7 @@ bridgereg_t badd32; bridgereg_t badd64; bridgereg_t fix; - unsigned s; + unsigned long s; bridgereg_t xmask; xmask = mask; @@ -1203,29 +1259,16 @@ /* Generic macro flags */ if (flags & PCIIO_DMA_DATA) { -#ifdef colin - new = new - & ~BRIDGE_DEV_BARRIER /* barrier off */ - | BRIDGE_DEV_PREF; /* prefetch on */ -#else new = (new & ~BRIDGE_DEV_BARRIER) /* barrier off */ | BRIDGE_DEV_PREF; /* prefetch on */ -#endif } if (flags & PCIIO_DMA_CMD) { -#ifdef colin - new = new - & ~BRIDGE_DEV_PREF /* prefetch off */ - & ~BRIDGE_DEV_WRGA_BITS /* write gather off */ - | BRIDGE_DEV_BARRIER; /* barrier on */ -#else new = ((new & ~BRIDGE_DEV_PREF) /* prefetch off */ & ~BRIDGE_DEV_WRGA_BITS) /* write gather off */ | BRIDGE_DEV_BARRIER; /* barrier on */ -#endif } /* Generic detail flags */ @@ -1297,13 +1340,8 @@ * but the alternative is not allowing * the new stream at all. */ -#ifdef colin - if (fix = bad & (BRIDGE_DEV_PRECISE | - BRIDGE_DEV_BARRIER)) { -#else if ( (fix = bad & (BRIDGE_DEV_PRECISE | BRIDGE_DEV_BARRIER)) ){ -#endif bad &= ~fix; /* don't change these bits if * they are already set in "old" @@ -1317,13 +1355,8 @@ * but the alternative is not allowing * the new stream at all. */ -#ifdef colin - if (fix = bad & (BRIDGE_DEV_WRGA_BITS | - BRIDGE_DEV_PREF)) { -#else if ( (fix = bad & (BRIDGE_DEV_WRGA_BITS | - BRIDGE_DEV_PREF)) ){ -#endif + BRIDGE_DEV_PREF)) ) { bad &= ~fix; /* don't change these bits if * we wanted to turn them on. @@ -1379,7 +1412,7 @@ bridgereg_t mask) { pcibr_soft_slot_t slotp; - unsigned s; + unsigned long s; slotp = &pcibr_soft->bs_slot[slot]; @@ -1403,7 +1436,7 @@ pciio_slot_t slot) { bridge_t *bridge; - unsigned s; + unsigned long s; volatile uint32_t wrf; s = pcibr_lock(pcibr_soft); bridge = pcibr_soft->bs_base; @@ -1429,14 +1462,14 @@ { int rv; bridgereg_t old_enable, new_enable; + int badaddr_val(volatile void *, int, volatile void *); + old_enable = bridge->b_int_enable; new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; bridge->b_int_enable = new_enable; -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) -#if defined(BRINGUP) /* * The xbridge doesn't clear b_err_int_view unless * multi-err is cleared... @@ -1445,8 +1478,6 @@ if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) { bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR; } -#endif /* BRINGUP */ -#endif /* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 */ if (bridge->b_int_status & BRIDGE_IRR_PCI_GRP) { bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR; @@ -1454,8 +1485,6 @@ } rv = badaddr_val((void *) cfg, 4, valp); -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) -#if defined(BRINGUP) /* * The xbridge doesn't set master timeout in b_int_status * here. Fortunately it's in error_interrupt_view. @@ -1465,8 +1494,6 @@ bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR; rv = 1; /* unoccupied slot */ } -#endif /* BRINGUP */ -#endif /* CONFIG_SGI_IP35 */ bridge->b_int_enable = old_enable; bridge->b_wid_tflush; /* wait until Bridge PIO complete */ @@ -1514,10 +1541,6 @@ int pcibr_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp) { -#ifndef CONFIG_IA64_SGI_IO - if (!_CAP_CRABLE((uint64_t)credp, (uint64_t)CAP_DEVICE_MGT)) - return EPERM; -#endif return 0; } @@ -1630,42 +1653,10 @@ return slot; } + /*========================================================================== * BRIDGE PCI SLOT RELATED IOCTLs */ -/* - * pcibr_slot_powerup - * Software initialize the pci slot. - */ -int -pcibr_slot_powerup(devfs_handle_t pcibr_vhdl,pciio_slot_t slot) -{ - /* Check for the valid slot */ - if (!PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - if (pcibr_device_attach(pcibr_vhdl,slot)) - return(EINVAL); - - return(0); -} -/* - * pcibr_slot_shutdown - * Software shutdown the pci slot - */ -int -pcibr_slot_shutdown(devfs_handle_t pcibr_vhdl,pciio_slot_t slot) -{ - /* Check for valid slot */ - if (!PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - if (pcibr_device_detach(pcibr_vhdl,slot)) - return(EINVAL); - - return(0); -} - char *pci_space_name[] = {"NONE", "ROM", "IO", @@ -1683,177 +1674,163 @@ "", "BAD"}; + +#ifdef LATER + void -pcibr_slot_func_info_print(pcibr_info_h pcibr_infoh, int func, int verbose) +pcibr_slot_func_info_return(pcibr_info_h pcibr_infoh, + int func, + pcibr_slot_func_info_resp_t funcp) { - pcibr_info_t pcibr_info = pcibr_infoh[func]; - char name[MAXDEVNAME]; - int win; - - if (!pcibr_info) - return; + pcibr_info_t pcibr_info = pcibr_infoh[func]; + int win; + funcp->resp_f_status = 0; + + if (!pcibr_info) { + return; + } + + funcp->resp_f_status |= FUNC_IS_VALID; #ifdef SUPPORT_PRINTING_V_FORMAT - sprintf(name, "%v", pcibr_info->f_vertex); -#endif - if (!verbose) { - printk("\tSlot Name : %s\n",name); - } else { - printk("\tPER-SLOT FUNCTION INFO\n"); -#ifdef SUPPORT_PRINTING_V_FORMAT - sprintf(name, "%v", pcibr_info->f_vertex); + sprintf(funcp->resp_f_slot_name, "%v", pcibr_info->f_vertex); +#else + sprintf(funcp->resp_f_slot_name, "%x", pcibr_info->f_vertex); #endif - printk("\tSlot Name : %s\n",name); - printk("\tPCI Bus : %d ",pcibr_info->f_bus); - printk("Slot : %d ", pcibr_info->f_slot); - printk("Function : %d\n", pcibr_info->f_func); + + if(is_sys_critical_vertex(pcibr_info->f_vertex)) { + funcp->resp_f_status |= FUNC_IS_SYS_CRITICAL; + } + + funcp->resp_f_bus = pcibr_info->f_bus; + funcp->resp_f_slot = pcibr_info->f_slot; + funcp->resp_f_func = pcibr_info->f_func; #ifdef SUPPORT_PRINTING_V_FORMAT - sprintf(name, "%v", pcibr_info->f_master); + sprintf(funcp->resp_f_master_name, "%v", pcibr_info->f_master); +#else + sprintf(funcp->resp_f_master_name, "%x", pcibr_info->f_master); #endif - printk("\tBus provider : %s\n",name); - printk("\tProvider Fns : 0x%p ", pcibr_info->f_pops); - printk("Error Handler : 0x%p Arg 0x%p\n", - pcibr_info->f_efunc,pcibr_info->f_einfo); + funcp->resp_f_pops = pcibr_info->f_pops; + funcp->resp_f_efunc = pcibr_info->f_efunc; + funcp->resp_f_einfo = pcibr_info->f_einfo; + + funcp->resp_f_vendor = pcibr_info->f_vendor; + funcp->resp_f_device = pcibr_info->f_device; + + for(win = 0 ; win < 6 ; win++) { + funcp->resp_f_window[win].resp_w_base = + pcibr_info->f_window[win].w_base; + funcp->resp_f_window[win].resp_w_size = + pcibr_info->f_window[win].w_size; + sprintf(funcp->resp_f_window[win].resp_w_space, + "%s", + pci_space_name[pcibr_info->f_window[win].w_space]); } - printk("\tVendorId : 0x%x " , pcibr_info->f_vendor); - printk("DeviceId : 0x%x\n", pcibr_info->f_device); - printk("\n\tBase Register Info\n"); - printk("\t\tReg#\tBase\t\tSize\t\tSpace\n"); - for(win = 0 ; win < 6 ; win++) - printk("\t\t%d\t0x%lx\t%s0x%lx\t%s%s\n", - win, - pcibr_info->f_window[win].w_base, - pcibr_info->f_window[win].w_base >= 0x100000 ? "": "\t", - pcibr_info->f_window[win].w_size, - pcibr_info->f_window[win].w_size >= 0x100000 ? "": "\t", - pci_space_name[pcibr_info->f_window[win].w_space]); - - printk("\t\t7\t0x%x\t%s0x%x\t%sROM\n", - pcibr_info->f_rbase, - pcibr_info->f_rbase > 0x100000 ? "" : "\t", - pcibr_info->f_rsize, - pcibr_info->f_rsize > 0x100000 ? "" : "\t"); + funcp->resp_f_rbase = pcibr_info->f_rbase; + funcp->resp_f_rsize = pcibr_info->f_rsize; - printk("\n\tInterrupt Bit Map\n"); - printk("\t\tPCI Int#\tBridge Pin#\n"); - for (win = 0 ; win < 4; win++) - printk("\t\tINT%c\t\t%d\n",win+'A',pcibr_info->f_ibit[win]); - printk("\n"); -} + for (win = 0 ; win < 4; win++) { + funcp->resp_f_ibit[win] = pcibr_info->f_ibit[win]; + } + funcp->resp_f_att_det_error = pcibr_info->f_att_det_error; -void -pcibr_slot_info_print(pcibr_soft_t pcibr_soft, - pciio_slot_t slot, - int verbose) -{ - pcibr_soft_slot_t pss; - char slot_conn_name[MAXDEVNAME]; - int func; - bridge_t *bridge = pcibr_soft->bs_base; - bridgereg_t b_resp; - reg_p b_respp; - int dev; - bridgereg_t b_int_device; - bridgereg_t b_int_host; - bridgereg_t b_int_enable; - int pin = 0; - int int_bits = 0; +} + +int +pcibr_slot_info_return(pcibr_soft_t pcibr_soft, + pciio_slot_t slot, + pcibr_slot_info_resp_t respp) +{ + pcibr_soft_slot_t pss; + int func; + bridge_t *bridge = pcibr_soft->bs_base; + reg_p b_respp; + pcibr_slot_info_resp_t slotp; + pcibr_slot_func_info_resp_t funcp; + + slotp = kmem_zalloc(sizeof(*slotp), KM_SLEEP); + if (slotp == NULL) { + return(ENOMEM); + } pss = &pcibr_soft->bs_slot[slot]; printk("\nPCI INFRASTRUCTURAL INFO FOR SLOT %d\n\n", slot); - if (verbose) { - printk("\tHost Present ? %s ", pss->has_host ? "yes" : "no"); - printk("\tHost Slot : %d\n",pss->host_slot); + slotp->resp_has_host = pss->has_host; + slotp->resp_host_slot = pss->host_slot; #ifdef SUPPORT_PRINTING_V_FORMAT - sprintf(slot_conn_name, "%v", pss->slot_conn); + sprintf(slotp->resp_slot_conn_name, "%v", pss->slot_conn); +#else + sprintf(slotp->resp_slot_conn_name, "%x", pss->slot_conn); #endif - printk("\tSlot Conn : %s\n",slot_conn_name); - printk("\t#Functions : %d\n",pss->bss_ninfo); + slotp->resp_slot_status = pss->slot_status; + slotp->resp_l1_bus_num = io_path_map_widget(pcibr_soft->bs_vhdl); + + if (is_sys_critical_vertex(pss->slot_conn)) { + slotp->resp_slot_status |= SLOT_IS_SYS_CRITICAL; } - for (func = 0; func < pss->bss_ninfo; func++) - pcibr_slot_func_info_print(pss->bss_infos,func, verbose); - printk("\tDevio[Space:%s,Base:0x%lx,Shadow:0x%x]\n", - pci_space_name[pss->bss_devio.bssd_space], - pss->bss_devio.bssd_base, - pss->bss_device); - - if (verbose) { - printk("\tUsage counts : pmu %d d32 %d d64 %d\n", - pss->bss_pmu_uctr,pss->bss_d32_uctr,pss->bss_d64_uctr); - - printk("\tDirect Trans Info : d64_base 0x%x d64_flags 0x%x" - "d32_base 0x%x d32_flags 0x%x\n", - (unsigned int)pss->bss_d64_base, pss->bss_d64_flags, - (unsigned int)pss->bss_d32_base, pss->bss_d32_flags); - - printk("\tExt ATEs active ? %s", - pss->bss_ext_ates_active ? "yes" : "no"); - printk(" Command register : 0x%p ", pss->bss_cmd_pointer); - printk(" Shadow command val : 0x%x\n", pss->bss_cmd_shadow); + + slotp->resp_bss_ninfo = pss->bss_ninfo; + + for (func = 0; func < pss->bss_ninfo; func++) { + funcp = &(slotp->resp_func[func]); + pcibr_slot_func_info_return(pss->bss_infos, func, funcp); } - printk("\tSoft RRB Info[Valid %d+%d, Reserved %d]\n", - pcibr_soft->bs_rrb_valid[slot], - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); + sprintf(slotp->resp_bss_devio_bssd_space, "%s", + pci_space_name[pss->bss_devio.bssd_space]); + slotp->resp_bss_devio_bssd_base = pss->bss_devio.bssd_base; + slotp->resp_bss_device = pss->bss_device; + slotp->resp_bss_pmu_uctr = pss->bss_pmu_uctr; + slotp->resp_bss_d32_uctr = pss->bss_d32_uctr; + slotp->resp_bss_d64_uctr = pss->bss_d64_uctr; - if (slot & 1) - b_respp = &bridge->b_odd_resp; - else - b_respp = &bridge->b_even_resp; + slotp->resp_bss_d64_base = pss->bss_d64_base; + slotp->resp_bss_d64_flags = pss->bss_d64_flags; + slotp->resp_bss_d32_base = pss->bss_d32_base; + slotp->resp_bss_d32_flags = pss->bss_d32_flags; - b_resp = *b_respp; + slotp->resp_bss_ext_ates_active = atomic_read(&pss->bss_ext_ates_active); - printk("\n\tBridge RRB Info\n"); - printk("\t\tRRB#\tVirtual\n"); - for (dev = 0; dev < 8; dev++) { - if ((b_resp & BRIDGE_RRB_EN) && - (b_resp & BRIDGE_RRB_PDEV) == (slot >> 1)) - printk( "\t\t%d\t%s\n", - dev, - (b_resp & BRIDGE_RRB_VDEV) ? "yes" : "no"); - b_resp >>= 4; - - } - b_int_device = bridge->b_int_device; - b_int_enable = bridge->b_int_enable; + slotp->resp_bss_cmd_pointer = pss->bss_cmd_pointer; + slotp->resp_bss_cmd_shadow = pss->bss_cmd_shadow; - printk("\n\tBridge Interrupt Info\n" - "\t\tInt_device 0x%x\n\t\tInt_enable 0x%x " - "\n\t\tEnabled pin#s for this slot: ", - b_int_device, - b_int_enable); + slotp->resp_bs_rrb_valid = pcibr_soft->bs_rrb_valid[slot]; + slotp->resp_bs_rrb_valid_v = pcibr_soft->bs_rrb_valid[slot + + PCIBR_RRB_SLOT_VIRTUAL]; + slotp->resp_bs_rrb_res = pcibr_soft->bs_rrb_res[slot]; - while (b_int_device) { - if (((b_int_device & 7) == slot) && - (b_int_enable & (1 << pin))) { - int_bits |= (1 << pin); - printk("%d ", pin); - } - pin++; - b_int_device >>= 3; + if (slot & 1) { + b_respp = &bridge->b_odd_resp; + } else { + b_respp = &bridge->b_even_resp; } - if (!int_bits) - printk("NONE "); + slotp->resp_b_resp = *b_respp; - b_int_host = bridge->b_int_addr[slot].addr; + slotp->resp_b_int_device = bridge->b_int_device; + slotp->resp_b_int_enable = bridge->b_int_enable; + slotp->resp_b_int_host = bridge->b_int_addr[slot].addr; - printk("\n\t\tInt_host_addr 0x%x\n", - b_int_host); - + if (COPYOUT(slotp, respp, sizeof(*respp))) { + return(EFAULT); + } + + kmem_free(slotp, sizeof(*slotp)); + + return(0); } -int verbose = 0; /* - * pcibr_slot_inquiry - * Print information about the pci slot maintained by the infrastructure. - * Current information displayed + * pcibr_slot_query + * Return information about the PCI slot maintained by the infrastructure. + * Information is requested in the request structure. + * + * Information returned in the response structure: * Slot hwgraph name * Vendor/Device info * Base register info @@ -1861,7 +1838,6 @@ * Devio register * Software RRB info * RRB register info - * In verbose mode following additional info is displayed * Host/Gues info * PCI Bus #,slot #, function # * Slot provider hwgraph name @@ -1872,28 +1848,76 @@ * External SSRAM workaround info */ int -pcibr_slot_inquiry(devfs_handle_t pcibr_vhdl, pciio_slot_t slot) +pcibr_slot_query(devfs_handle_t pcibr_vhdl, pcibr_slot_info_req_t reqp) { - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); + pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); + pciio_slot_t slot = reqp->req_slot; + pciio_slot_t tmp_slot; + pcibr_slot_info_resp_t respp = (pcibr_slot_info_resp_t) reqp->req_respp; + int size = reqp->req_size; + int error; /* Make sure that we are dealing with a bridge device vertex */ - if (!pcibr_soft) - return(EINVAL); + if (!pcibr_soft) { + return(EINVAL); + } - /* Make sure that we have a valid pci slot number or PCIIO_SLOT_NONE */ - if ((!PCIBR_VALID_SLOT(slot)) && (slot != PCIIO_SLOT_NONE)) - return(EINVAL); + /* Make sure that we have a valid PCI slot number or PCIIO_SLOT_NONE */ + if ((!PCIBR_VALID_SLOT(slot)) && (slot != PCIIO_SLOT_NONE)) { + return(EINVAL); + } - /* Print information for the requested pci slot */ +#ifdef LATER + /* Do not allow a query of a slot in a shoehorn */ + if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) { + return(EPERM); + } +#endif + + /* Return information for the requested PCI slot */ if (slot != PCIIO_SLOT_NONE) { - pcibr_slot_info_print(pcibr_soft,slot,verbose); - return(0); + if (size < sizeof(*respp)) { + return(EINVAL); + } + + /* Acquire read access to the slot */ + mrlock(pcibr_soft->bs_slot[slot].slot_lock, MR_ACCESS, PZERO); + + error = pcibr_slot_info_return(pcibr_soft, slot, respp); + + /* Release the slot lock */ + mrunlock(pcibr_soft->bs_slot[slot].slot_lock); + + return(error); } - /* Print information for all the slots */ - for (slot = 0; slot < 8; slot++) - pcibr_slot_info_print(pcibr_soft, slot,verbose); - return(0); + + /* Return information for all the slots */ + for (tmp_slot = 0; tmp_slot < 8; tmp_slot++) { + + if (size < sizeof(*respp)) { + return(EINVAL); + } + + /* Acquire read access to the slot */ + mrlock(pcibr_soft->bs_slot[tmp_slot].slot_lock, MR_ACCESS, PZERO); + + error = pcibr_slot_info_return(pcibr_soft, tmp_slot, respp); + + /* Release the slot lock */ + mrunlock(pcibr_soft->bs_slot[tmp_slot].slot_lock); + + if (error) { + return(error); + } + + ++respp; + size -= sizeof(*respp); + } + + return(error); } +#endif /* LATER */ + /*ARGSUSED */ int @@ -1905,7 +1929,7 @@ int *rvalp) { devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get((devfs_handle_t)dev); -#ifdef colin +#ifdef LATER pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); #endif int error = 0; @@ -1913,7 +1937,7 @@ hwgraph_vertex_unref(pcibr_vhdl); switch (cmd) { -#ifdef colin +#ifdef LATER case GIOCSETBW: { grio_ioctl_info_t info; @@ -1969,7 +1993,6 @@ pcibr_priority_bits_set(pcibr_soft, slot, PCI_PRIO_LOW); break; } -#endif /* colin */ case PCIBR_SLOT_POWERUP: { @@ -1985,31 +2008,33 @@ break; } case PCIBR_SLOT_SHUTDOWN: - { - pciio_slot_t slot; - if (!cap_able(CAP_DEVICE_MGT)) { error = EPERM; break; } slot = (pciio_slot_t)(uint64_t)arg; - error = pcibr_slot_shutdown(pcibr_vhdl,slot); + error = pcibr_slot_powerup(pcibr_vhdl,slot); break; } - case PCIBR_SLOT_INQUIRY: + case PCIBR_SLOT_QUERY: { - pciio_slot_t slot; + struct pcibr_slot_info_req_s req; if (!cap_able(CAP_DEVICE_MGT)) { error = EPERM; break; } - slot = (pciio_slot_t)(uint64_t)arg; - error = pcibr_slot_inquiry(pcibr_vhdl,slot); + if (COPYIN(arg, &req, sizeof(req))) { + error = EFAULT; + break; + } + + error = pcibr_slot_query(pcibr_vhdl, &req); break; } +#endif /* LATER */ default: break; @@ -2055,7 +2080,6 @@ *free_basep = last + 1; /* keep upper chunk */ } -#ifdef IRIX /* Convert from ssram_bits in control register to number of SSRAM entries */ #define ATE_NUM_ENTRIES(n) _ate_info[n] @@ -2070,14 +2094,12 @@ #define ATE_NUM_SIZES (sizeof(_ate_info) / sizeof(int)) #define ATE_PROBE_VALUE 0x0123456789abcdefULL -#endif /* IRIX */ /* * Determine the size of this bridge's external mapping SSRAM, and set * the control register appropriately to reflect this size, and initialize * the external SSRAM. */ -#ifndef BRINGUP LOCAL int pcibr_init_ext_ate_ram(bridge_t *bridge) { @@ -2087,9 +2109,6 @@ bridgereg_t old_enable, new_enable; int s; - if (is_xbridge(bridge)) - return 0; - /* Probe SSRAM to determine its size. */ old_enable = bridge->b_int_enable; new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; @@ -2116,11 +2135,9 @@ */ s = splhi(); -#ifdef colin bridge->b_wid_control = (bridge->b_wid_control & ~BRIDGE_CTRL_SSRAM_SIZE_MASK) | BRIDGE_CTRL_SSRAM_SIZE(largest_working_size); -#endif bridge->b_wid_control; /* inval addr bug war */ splx(s); @@ -2139,7 +2156,6 @@ return (num_entries); } -#endif /* !BRINGUP */ /* * Allocate "count" contiguous Bridge Address Translation Entries @@ -2155,6 +2171,7 @@ int index = 0; index = (int) rmalloc(pcibr_soft->bs_int_ate_map, (size_t) count); +/* printk("Colin: pcibr_ate_alloc - index %d count %d \n", index, count); */ if (!index && pcibr_soft->bs_ext_ate_map) index = (int) rmalloc(pcibr_soft->bs_ext_ate_map, (size_t) count); @@ -2174,6 +2191,8 @@ /* note the "+1" since rmalloc handles 1..n but * we start counting ATEs at zero. */ +/* printk("Colin: pcibr_ate_free - index %d count %d\n", index, count); */ + rmfree((index < pcibr_soft->bs_int_ate_size) ? pcibr_soft->bs_int_ate_map : pcibr_soft->bs_ext_ate_map, @@ -2233,8 +2252,6 @@ /* * Record the info in the sparse func info space. */ -printk("pcibr_device_info_new: slot= %d func= %d bss_ninfo= %d pcibr_info= 0x%p\n", slot, func, pcibr_soft->bs_slot[slot].bss_ninfo, pcibr_info); - if (func < pcibr_soft->bs_slot[slot].bss_ninfo) pcibr_soft->bs_slot[slot].bss_infos[func] = pcibr_info; } @@ -2281,7 +2298,7 @@ slotp->bss_d32_flags = 0; /* Clear out shadow info necessary for the external SSRAM workaround */ - slotp->bss_ext_ates_active = 0; + slotp->bss_ext_ates_active = ATOMIC_INIT(0); slotp->bss_cmd_pointer = 0; slotp->bss_cmd_shadow = 0; @@ -2336,55 +2353,10 @@ pcibr_soft->bs_spinfo.pci_mem_last); /* - * pcibr_slot_reset - * Reset the pci device in the particular slot . - */ -int -pcibr_slot_reset(devfs_handle_t pcibr_vhdl,pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge_t *bridge; - bridgereg_t ctrlreg,tmp; - volatile bridgereg_t *wrb_flush; - - if (!PCIBR_VALID_SLOT(slot)) - return(1); - - if (!pcibr_soft) - return(1); - - /* Enable the DMA operations from this device of the xtalk widget - * (PCI host bridge in this case). - */ - xtalk_widgetdev_enable(pcibr_soft->bs_conn, slot); - /* Set the reset slot bit in the bridge's wid control register - * to reset the pci slot - */ - bridge = pcibr_soft->bs_base; - /* Read the bridge widget control and clear out the reset pin - * bit for the corresponding slot. - */ - tmp = ctrlreg = bridge->b_wid_control; - tmp &= ~BRIDGE_CTRL_RST_PIN(slot); - bridge->b_wid_control = tmp; - tmp = bridge->b_wid_control; - /* Restore the old control register back. - * NOTE : pci card gets reset when the reset pin bit - * changes from 0 (set above) to 1 (going to be set now). - */ - bridge->b_wid_control = ctrlreg; - - /* Flush the write buffers if any !! */ - wrb_flush = &(bridge->b_wr_req_buf[slot].reg); - while (*wrb_flush); - - return(0); -} -/* * pcibr_slot_info_init * Probe for this slot and see if it is populated. - * If it is populated initialize the generic pci infrastructural - * information associated with this particular pci device. + * If it is populated initialize the generic PCI infrastructural + * information associated with this particular PCI device. */ int pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, @@ -2401,6 +2373,9 @@ pciio_vendor_id_t vendor; pciio_device_id_t device; unsigned htype; +#if !defined(CONFIG_IA64_SGI_SN1) + int nbars; +#endif cfg_p wptr; int win; pciio_space_t space; @@ -2416,40 +2391,41 @@ /* Get the basic software information required to proceed */ pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft) - return(1); + return(EINVAL); bridge = pcibr_soft->bs_base; if (!PCIBR_VALID_SLOT(slot)) - return(1); - - slotp = &pcibr_soft->bs_slot[slot]; - - /* Load the current values of allocated pci address spaces */ - PCI_ADDR_SPACE_LIMITS_LOAD(); + return(EINVAL); - /* If we have a host slot (eg:- IOC3 has 2 pci slots and the initialization + /* If we have a host slot (eg:- IOC3 has 2 PCI slots and the initialization * is done by the host slot then we are done. */ - if (pcibr_soft->bs_slot[slot].has_host) - return(0); + if (pcibr_soft->bs_slot[slot].has_host) { + return(0); + } + + /* Check for a slot with any system critical functions */ + if (pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) + return(EPERM); + + /* Load the current values of allocated PCI address spaces */ + PCI_ADDR_SPACE_LIMITS_LOAD(); /* Try to read the device-id/vendor-id from the config space */ cfgw = bridge->b_type0_cfg_dev[slot].l; -#ifdef BRINGUP - if (slot < 3 || slot == 7) - return (0); - else -#endif /* BRINGUP */ - if (pcibr_probe_slot(bridge, cfgw, &idword)) - return(0); + if (pcibr_probe_slot(bridge, cfgw, &idword)) + return(ENODEV); + + slotp = &pcibr_soft->bs_slot[slot]; + slotp->slot_status |= SLOT_POWER_UP; vendor = 0xFFFF & idword; /* If the vendor id is not valid then the slot is not populated * and we are done. */ - if (vendor == 0xFFFF) - return(0); /* next slot */ + if (vendor == 0xFFFF) + return(ENODEV); device = 0xFFFF & (idword >> 16); htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); @@ -2503,7 +2479,13 @@ if (htype != 0x00) { PRINT_WARNING("%s pcibr: pci slot %d func %d has strange header type 0x%x\n", pcibr_soft->bs_name, slot, func, htype); +#if defined(CONFIG_IA64_SGI_SN1) continue; +#else + nbars = 2; + } else { + nbars = PCI_CFG_BASE_ADDRS; +#endif } #if DEBUG && ATTACH_DEBUG PRINT_NOTICE( @@ -2516,13 +2498,17 @@ conn_vhdl = pciio_device_info_register(pcibr_vhdl, &pcibr_info->f_c); if (func == 0) slotp->slot_conn = conn_vhdl; - + cmd_reg = cfgw[PCI_CFG_COMMAND / 4]; wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; - - for (win = 0; win < PCI_CFG_BASE_ADDRS; ++win) { +#if defined(CONFIG_IA64_SGI_SN1) + for (win = 0; win < PCI_CFG_BASE_ADDRS; ++win) +#else + for (win = 0; win < nbars; ++win) +#endif + { iopaddr_t base, mask, code; size_t size; @@ -2573,9 +2559,9 @@ base = wptr[((win*4)^4)/4]; #else base = wptr[win]; -#endif /* LITTLE_ENDIAN */ +#endif - if (base & 1) { + if (base & PCI_BA_IO_SPACE) { /* BASE is in I/O space. */ space = PCIIO_SPACE_IO; mask = -4; @@ -2590,7 +2576,7 @@ /* BASE is in MEM space. */ space = PCIIO_SPACE_MEM; mask = -16; - code = base & 15; + code = base & PCI_BA_MEM_LOCATION; /* extract BAR type */ base = base & mask; if (base == 0) { ; /* not assigned */ @@ -2697,37 +2683,30 @@ } /* next win */ } /* next func */ - /* Store back the values for allocated pci address spaces */ + /* Store back the values for allocated PCI address spaces */ PCI_ADDR_SPACE_LIMITS_STORE(); return(0); } /* * pcibr_slot_info_free - * Remove all the pci infrastructural information associated - * with a particular pci device. + * Remove all the PCI infrastructural information associated + * with a particular PCI device. */ int -pcibr_slot_info_free(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) +pcibr_slot_info_free(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) { pcibr_soft_t pcibr_soft; pcibr_info_h pcibr_infoh; int nfunc; -#if defined(PCI_HOTSWAP_DEBUG) - cfg_p cfgw; - bridge_t *bridge; - int win; - cfg_p wptr; -#endif /* PCI_HOTSWAP_DEBUG */ - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(1); + return(EINVAL); -#if defined(PCI_HOTSWAP_DEBUG) +#if !defined(CONFIG_IA64_SGI_SN1) /* Clean out all the base registers */ bridge = pcibr_soft->bs_base; cfgw = bridge->b_type0_cfg_dev[slot].l; @@ -2739,7 +2718,7 @@ #else wptr[win] = 0; #endif /* LITTLE_ENDIAN */ -#endif /* PCI_HOTSWAP_DEBUG */ +#endif /* !CONFIG_IA64_SGI_SN1 */ nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; @@ -2750,13 +2729,12 @@ pcibr_soft->bs_slot[slot].bss_ninfo = 0; return(0); - - } + int as_debug = 0; /* * pcibr_slot_addr_space_init - * Reserve chunks of pci address space as required by + * Reserve chunks of PCI address space as required by * the base registers in the card. */ int @@ -2772,38 +2750,40 @@ iopaddr_t pci_hi_fb, pci_hi_fl; size_t align; iopaddr_t mask; + int nbars; int nfunc; int func; int win; pcibr_soft = pcibr_soft_get(pcibr_vhdl); + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(1); + return(EINVAL); bridge = pcibr_soft->bs_base; - /* Get the current values for the allocated pci address spaces */ + /* Get the current values for the allocated PCI address spaces */ PCI_ADDR_SPACE_LIMITS_LOAD(); if (as_debug) -#ifdef colin +#ifdef LATER PCI_ADDR_SPACE_LIMITS_PRINT(); #endif /* allocate address space, * for windows that have not been * previously assigned. */ - - if (pcibr_soft->bs_slot[slot].has_host) + if (pcibr_soft->bs_slot[slot].has_host) { return(0); + } nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; if (nfunc < 1) - return(0); + return(EINVAL); pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; if (!pcibr_infoh) - return(0); + return(EINVAL); /* * Try to make the DevIO windows not @@ -2842,7 +2822,16 @@ cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; - for (win = 0; win < PCI_CFG_BASE_ADDRS; ++win) { +#if defined(CONFIG_IA64_SGI_SN1) + nbars = PCI_CFG_BASE_ADDRS; +#else + if ((do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1) & 0x7f) != 0) + nbars = 2; + else + nbars = PCI_CFG_BASE_ADDRS; +#endif + + for (win = 0; win < nbars; ++win) { space = pcibr_info->f_window[win].w_space; base = pcibr_info->f_window[win].w_base; @@ -2908,7 +2897,9 @@ pcibr_info->f_window[win].w_base = base; #ifdef LITTLE_ENDIAN wptr[((win*4)^4)/4] = base; +#if DEBUG && PCI_DEBUG printk("Setting base address 0x%p base 0x%x\n", &(wptr[((win*4)^4)/4]), base); +#endif #else wptr[win] = base; #endif /* LITTLE_ENDIAN */ @@ -2976,7 +2967,22 @@ * be sure are set. */ pci_cfg_cmd_reg_add |= PCI_CMD_IO_SPACE; - pci_cfg_cmd_reg_add |= PCI_CMD_MEM_SPACE; + + /* + * The Adaptec 1160 FC Controller WAR #767995: + * The part incorrectly ignores the upper 32 bits of a 64 bit + * address when decoding references to it's registers so to + * keep it from responding to a bus cycle that it shouldn't + * we only use I/O space to get at it's registers. Don't + * enable memory space accesses on that PCI device. + */ + #define FCADP_VENDID 0x9004 /* Adaptec Vendor ID from fcadp.h */ + #define FCADP_DEVID 0x1160 /* Adaptec 1160 Device ID from fcadp.h */ + + if ((pcibr_info->f_vendor != FCADP_VENDID) || + (pcibr_info->f_device != FCADP_DEVID)) + pci_cfg_cmd_reg_add |= PCI_CMD_MEM_SPACE; + pci_cfg_cmd_reg_add |= PCI_CMD_BUS_MASTER; pci_cfg_cmd_reg_p = cfgw + PCI_CFG_COMMAND / 4; @@ -2991,28 +2997,30 @@ } /* next func */ - /* Now that we have allocated new chunks of pci address spaces to this + /* Now that we have allocated new chunks of PCI address spaces to this * card we need to update the bookkeeping values which indicate - * the current pci address space allocations. + * the current PCI address space allocations. */ PCI_ADDR_SPACE_LIMITS_STORE(); return(0); } + /* * pcibr_slot_device_init - * Setup the device register in the bridge for this pci slot. + * Setup the device register in the bridge for this PCI slot. */ int -pcibr_slot_device_init(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) +pcibr_slot_device_init(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) { - pcibr_soft_t pcibr_soft; + pcibr_soft_t pcibr_soft; bridge_t *bridge; - bridgereg_t devreg; + bridgereg_t devreg; pcibr_soft = pcibr_soft_get(pcibr_vhdl); + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(1); + return(EINVAL); bridge = pcibr_soft->bs_base; @@ -3036,13 +3044,13 @@ #if DEBUG && PCI_DEBUG printk("pcibr: PCI space allocation done.\n"); #endif - + return(0); } /* * pcibr_slot_guest_info_init - * Setup the host/guest relations for a pci slot. + * Setup the host/guest relations for a PCI slot. */ int pcibr_slot_guest_info_init(devfs_handle_t pcibr_vhdl, @@ -3056,7 +3064,7 @@ pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(1); + return(EINVAL); slotp = &pcibr_soft->bs_slot[slot]; @@ -3103,17 +3111,17 @@ return(0); } + /* * pcibr_slot_initial_rrb_alloc * Allocate a default number of rrbs for this slot on - * the two channels. This is dictated by the rrb allocation + * the two channels. This is dictated by the rrb allocation * strategy routine defined per platform. */ int -pcibr_slot_initial_rrb_alloc(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) - +pcibr_slot_initial_rrb_alloc(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) { pcibr_soft_t pcibr_soft; pcibr_info_h pcibr_infoh; @@ -3123,16 +3131,17 @@ int r; pcibr_soft = pcibr_soft_get(pcibr_vhdl); + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(1); + return(EINVAL); bridge = pcibr_soft->bs_base; - /* How may RRBs are on this slot? */ c0 = do_pcibr_rrb_count_valid(bridge, slot); c1 = do_pcibr_rrb_count_valid(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL); + #if PCIBR_RRB_DEBUG printk("pcibr_attach: slot %d started with %d+%d\n", slot, c0, c1); #endif @@ -3149,7 +3158,7 @@ do_pcibr_rrb_free(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL, c1); pcibr_soft->bs_rrb_valid[slot] = 0x1000; pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = 0x1000; - return(0); + return(ENODEV); } pcibr_soft->bs_rrb_avail[slot & 1] -= c0 + c1; @@ -3173,17 +3182,19 @@ pcibr_soft->bs_rrb_res[slot]); printk("\n"); #endif + return(0); } /* * pcibr_slot_call_device_attach - * This calls the associated driver attach routine for the pci + * This calls the associated driver attach routine for the PCI * card in this slot. */ int -pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) +pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot, + int drv_flags) { pcibr_soft_t pcibr_soft; pcibr_info_h pcibr_infoh; @@ -3192,14 +3203,19 @@ int func; devfs_handle_t xconn_vhdl,conn_vhdl; int nfunc; + int error_func; + int error_slot = 0; + int error = ENODEV; pcibr_soft = pcibr_soft_get(pcibr_vhdl); + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(1); + return(EINVAL); - if (pcibr_soft->bs_slot[slot].has_host) - return(0); + if (pcibr_soft->bs_slot[slot].has_host) { + return(EPERM); + } xconn_vhdl = pcibr_soft->bs_conn; aa = async_attach_get_info(xconn_vhdl); @@ -3207,8 +3223,6 @@ nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - printk("\npcibr_slot_call_device_attach: link 0x%p pci bus 0x%p slot %d\n", xconn_vhdl, pcibr_vhdl, slot); - for (func = 0; func < nfunc; ++func) { pcibr_info = pcibr_infoh[func]; @@ -3221,51 +3235,77 @@ conn_vhdl = pcibr_info->f_vertex; - /* If the pci device has been disabled in the prom, + /* If the PCI device has been disabled in the prom, * do not set it up for driver attach. NOTE: usrpci * and pciba will not "see" this connection point! */ if (device_admin_info_get(conn_vhdl, ADMIN_LBL_DISABLED)) { #ifdef SUPPORT_PRINTING_V_FORMAT - PRINT_WARNING( "pcibr_slot_call_device_attach: %v disabled\n", + PRINT_WARNING("pcibr_slot_call_device_attach: %v disabled\n", conn_vhdl); #endif continue; } +#ifdef LATER + /* + * Activate if and when we support cdl. + */ if (aa) async_attach_add_info(conn_vhdl, aa); - pciio_device_attach(conn_vhdl); - } /* next func */ +#endif /* LATER */ - printk("\npcibr_slot_call_device_attach: DONE\n"); + error_func = pciio_device_attach(conn_vhdl, drv_flags); - return(0); + pcibr_info->f_att_det_error = error_func; + + if (error_func) + error_slot = error_func; + + error = error_slot; + + } /* next func */ + + if (error) { + if ((error != ENODEV) && (error != EUNATCH)) + pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_INCMPLT; + } else { + pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT; + } + + return(error); } + /* * pcibr_slot_call_device_detach - * This calls the associated driver detach routine for the pci + * This calls the associated driver detach routine for the PCI * card in this slot. */ int -pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) +pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot, + int drv_flags) { pcibr_soft_t pcibr_soft; pcibr_info_h pcibr_infoh; pcibr_info_t pcibr_info; int func; - devfs_handle_t conn_vhdl; + devfs_handle_t conn_vhdl = GRAPH_VERTEX_NONE; int nfunc; - int ndetach = 1; + int error_func; + int error_slot = 0; + int error = ENODEV; pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(1); + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + return(EINVAL); if (pcibr_soft->bs_slot[slot].has_host) - return(0); - + return(EPERM); + + /* Make sure that we do not detach a system critical function vertex */ + if(pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) + return(EPERM); nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; @@ -3281,94 +3321,120 @@ continue; conn_vhdl = pcibr_info->f_vertex; - - /* Make sure that we do not detach a system critical device - * vertex. - */ - if (is_sys_critical_vertex(conn_vhdl)) { -#ifdef SUPPORT_PRINTING_V_FORMAT - PRINT_WARNING( "%v is a system critical device vertex\n", - conn_vhdl); -#endif - continue; - } - - ndetach = 0; - pciio_device_detach(conn_vhdl); + + error_func = pciio_device_detach(conn_vhdl, drv_flags); + + pcibr_info->f_att_det_error = error_func; + + if (error_func) + error_slot = error_func; + + error = error_slot; + } /* next func */ + pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; - return(ndetach); + if (error) { + if ((error != ENODEV) && (error != EUNATCH)) + pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_INCMPLT; + } else { + if (conn_vhdl != GRAPH_VERTEX_NONE) + pcibr_device_unregister(conn_vhdl); + pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT; + } + + return(error); } /* - * pcibr_device_attach + * pcibr_slot_detach * This is a place holder routine to keep track of all the - * slot-specific initialization that needs to be done. - * This is usually called when we want to initialize a new - * pci card on the bus. + * slot-specific freeing that needs to be done. */ int -pcibr_device_attach(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) +pcibr_slot_detach(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot, + int drv_flags) { - return ( - /* Reset the slot */ - pcibr_slot_reset(pcibr_vhdl,slot) || - /* FInd out what is out there */ - pcibr_slot_info_init(pcibr_vhdl,slot) || - - /* Set up the address space for this slot in the pci land */ - pcibr_slot_addr_space_init(pcibr_vhdl,slot) || - - /* Setup the device register */ - pcibr_slot_device_init(pcibr_vhdl, slot) || - - /* Setup host/guest relations */ - pcibr_slot_guest_info_init(pcibr_vhdl,slot) || - - /* Initial RRB management */ - pcibr_slot_initial_rrb_alloc(pcibr_vhdl,slot) || - - /* Call the device attach */ - pcibr_slot_call_device_attach(pcibr_vhdl,slot) - ); + int error; + + /* Call the device detach function */ + error = (pcibr_slot_call_device_detach(pcibr_vhdl, slot, drv_flags)); + return (error); } + /* - * pcibr_device_detach - * This is a place holder routine to keep track of all the - * slot-specific freeing that needs to be done. + * pcibr_is_slot_sys_critical + * Check slot for any functions that are system critical. + * Return 1 if any are system critical or 0 otherwise. + * + * This function will always return 0 when called by + * pcibr_attach() because the system critical vertices + * have not yet been set in the hwgraph. */ int -pcibr_device_detach(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) +pcibr_is_slot_sys_critical(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) { - - /* Call the device detach */ - return (pcibr_slot_call_device_detach(pcibr_vhdl,slot)); + pcibr_soft_t pcibr_soft; + pcibr_info_h pcibr_infoh; + pcibr_info_t pcibr_info; + devfs_handle_t conn_vhdl = GRAPH_VERTEX_NONE; + int nfunc; + int func; + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + return(0); + + nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; + pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; + + for (func = 0; func < nfunc; ++func) { + + pcibr_info = pcibr_infoh[func]; + if (!pcibr_info) + continue; + + if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) + continue; + + conn_vhdl = pcibr_info->f_vertex; + if (is_sys_critical_vertex(conn_vhdl)) { +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_WARNING("%v is a system critical device vertex\n", conn_vhdl); +#else + PRINT_WARNING("%p is a system critical device vertex\n", conn_vhdl); +#endif + return(1); + } + + } + return(0); } + /* * pcibr_device_unregister - * This frees up any hardware resources reserved for this pci device - * and removes any pci infrastructural information setup for it. - * This is usually used at the time of shutting down of the pci card. + * This frees up any hardware resources reserved for this PCI device + * and removes any PCI infrastructural information setup for it. + * This is usually used at the time of shutting down of the PCI card. */ -void +int pcibr_device_unregister(devfs_handle_t pconn_vhdl) { - pciio_info_t pciio_info; - devfs_handle_t pcibr_vhdl; - pciio_slot_t slot; - pcibr_soft_t pcibr_soft; + pciio_info_t pciio_info; + devfs_handle_t pcibr_vhdl; + pciio_slot_t slot; + pcibr_soft_t pcibr_soft; bridge_t *bridge; + int error_call; + int error = 0; pciio_info = pciio_info_get(pconn_vhdl); - /* Detach the pciba name space */ - pciio_device_detach(pconn_vhdl); - pcibr_vhdl = pciio_info_master_get(pciio_info); slot = pciio_info_slot_get(pciio_info); @@ -3382,19 +3448,31 @@ pcibr_rrb_flush(pconn_vhdl); /* Free the rrbs allocated to this slot */ - do_pcibr_rrb_free(bridge, slot, - pcibr_soft->bs_rrb_valid[slot] + - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL]); + error_call = do_pcibr_rrb_free(bridge, slot, + pcibr_soft->bs_rrb_valid[slot] + + pcibr_soft->bs_rrb_valid[slot + + PCIBR_RRB_SLOT_VIRTUAL]); + if (error_call) + error = ERANGE; pcibr_soft->bs_rrb_valid[slot] = 0; pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = 0; pcibr_soft->bs_rrb_res[slot] = 0; /* Flush the write buffers !! */ - (void)pcibr_wrb_flush(pconn_vhdl); + error_call = pcibr_wrb_flush(pconn_vhdl); + + if (error_call) + error = error_call; + /* Clear the information specific to the slot */ - (void)pcibr_slot_info_free(pcibr_vhdl, slot); + error_call = pcibr_slot_info_free(pcibr_vhdl, slot); + + if (error_call) + error = error_call; + + return(error); } @@ -3467,6 +3545,7 @@ return (rv == GRAPH_SUCCESS); } + /* * pcibr_attach: called every time the crosstalk * infrastructure is asked to initialize a widget @@ -3502,11 +3581,15 @@ iopaddr_t pci_hi_fb, pci_hi_fl; int spl_level; +#ifdef LATER char *nicinfo = (char *)0; +#endif #if PCI_FBBE int fast_back_to_back_enable; #endif + l1sc_t *scp; + nasid_t nasid; async_attach_t aa = NULL; @@ -3542,8 +3625,6 @@ NeedXbridgeSwap = 1; #endif - printk("pcibr_attach: Called with vertex 0x%p, b_wid_stat 0x%x, gio 0x%x\n",xconn_vhdl, bridge->b_wid_stat, BRIDGE_STAT_PCI_GIO_N); - /* * Create the vertex for the PCI bus, which we * will also use to hold the pcibr_soft and @@ -3558,8 +3639,14 @@ rc = hwgraph_path_add(xconn_vhdl, EDGE_LBL_PCI, &pcibr_vhdl); ASSERT(rc == GRAPH_SUCCESS); - rc = hwgraph_char_device_add(pcibr_vhdl, EDGE_LBL_CONTROLLER, "pcibr_", &ctlr_vhdl); - ASSERT(rc == GRAPH_SUCCESS); + ctlr_vhdl = NULL; + ctlr_vhdl = hwgraph_register(pcibr_vhdl, EDGE_LBL_CONTROLLER, + 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &pcibr_fops, NULL); + + ASSERT(ctlr_vhdl != NULL); /* * decode the nic, and hang its stuff off our @@ -3606,6 +3693,10 @@ pcibr_soft->bs_xbridge = 0; } + nasid = NASID_GET(bridge); + scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; + pcibr_soft->bs_l1sc = scp; + pcibr_soft->bs_moduleid = iobrick_module_get(scp); pcibr_soft->bsi_err_intr = 0; /* Bridges up through REV C @@ -3660,7 +3751,7 @@ /* * Init bridge lock. */ - spinlock_init(&pcibr_soft->bs_lock, "pcibr_loc"); + spin_lock_init(&pcibr_soft->bs_lock); /* * If we have one, process the hints structure. @@ -3691,12 +3782,18 @@ pcibr_soft->bs_slot[slot].bss_devio.bssd_space = PCIIO_SPACE_NONE; pcibr_soft->bs_slot[slot].bss_d64_base = PCIBR_D64_BASE_UNSET; pcibr_soft->bs_slot[slot].bss_d32_base = PCIBR_D32_BASE_UNSET; - pcibr_soft->bs_slot[slot].bss_ext_ates_active = 0; + pcibr_soft->bs_slot[slot].bss_ext_ates_active = ATOMIC_INIT(0); } for (ibit = 0; ibit < 8; ++ibit) { pcibr_soft->bs_intr[ibit].bsi_xtalk_intr = 0; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_list = 0; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_soft = pcibr_soft; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_list = NULL; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_stat = + &(bridge->b_int_status); + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_hdlrcnt = 0; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_shared = 0; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_connected = 0; } /* @@ -3733,7 +3830,7 @@ iopaddr_t xbase; xwidgetnum_t xport; iopaddr_t offset; - int num_entries; + int num_entries = 0; int entry; cnodeid_t cnodeid; nasid_t nasid; @@ -3801,10 +3898,6 @@ dirmap = xport << BRIDGE_DIRMAP_W_ID_SHFT; -#ifdef IRIX - dirmap |= BRIDGE_DIRMAP_RMF_64; -#endif - if (xbase) dirmap |= BRIDGE_DIRMAP_OFF & xbase; else if (offset >= (512 << 20)) @@ -3855,15 +3948,10 @@ * recomparing against BRIDGE_INTERNAL_ATES every * time. */ -#ifdef BRINGUP - /* - * 082799: for some reason pcibr_init_ext_ate_ram is causing - * a Data Bus Error. It should be zero anyway so just force it. - */ - num_entries = 0; -#else - num_entries = pcibr_init_ext_ate_ram(bridge); -#endif + if (is_xbridge(bridge)) + num_entries = 0; + else + num_entries = pcibr_init_ext_ate_ram(bridge); /* we always have 128 ATEs (512 for Xbridge) inside the chip * even if disabled for debugging. @@ -3947,7 +4035,6 @@ pcibr_soft->bsi_err_intr = xtalk_intr; -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) /* * On IP35 with XBridge, we do some extra checks in pcibr_setwidint * in order to work around some addressing limitations. In order @@ -3955,9 +4042,6 @@ * start from a known clean state. */ pcibr_clearwidint(bridge); -#endif - - printk("pribr_attach: FIXME Error Interrupt not registered\n"); xtalk_intr_connect(xtalk_intr, (intr_func_t) pcibr_error_intr_handler, @@ -4054,13 +4138,13 @@ } #endif -#ifdef IRIX +#ifdef LATER /* If the bridge has been reset then there is no need to reset * the individual PCI slots. */ for (slot = 0; slot < 8; ++slot) /* Reset all the slots */ - (void)pcibr_slot_reset(pcibr_vhdl,slot); + (void)pcibr_slot_reset(pcibr_vhdl, slot); #endif for (slot = 0; slot < 8; ++slot) @@ -4075,6 +4159,7 @@ /* Setup the device register */ (void)pcibr_slot_device_init(pcibr_vhdl, slot); +#ifndef __ia64 #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) for (slot = 0; slot < 8; ++slot) /* Set up convenience links */ @@ -4082,6 +4167,7 @@ if (pcibr_soft->bs_slot[slot].bss_ninfo > 0) /* if occupied */ pcibr_bus_cnvlink(pcibr_info->f_vertex, slot); #endif +#endif for (slot = 0; slot < 8; ++slot) /* Setup host/guest relations */ @@ -4091,12 +4177,34 @@ /* Initial RRB management */ (void)pcibr_slot_initial_rrb_alloc(pcibr_vhdl,slot); -#ifdef dagum /* driver attach routines should be called out from generic linux code */ for (slot = 0; slot < 8; ++slot) /* Call the device attach */ - (void)pcibr_slot_call_device_attach(pcibr_vhdl,slot); -#endif /* dagum */ + (void)pcibr_slot_call_device_attach(pcibr_vhdl, slot, 0); + + /* + * Each Pbrick PCI bus only has slots 1 and 2. Similarly for + * widget 0xe on Ibricks. Allocate RRB's accordingly. + */ + if (pcibr_soft->bs_moduleid > 0) { + switch (MODULE_GET_BTCHAR(pcibr_soft->bs_moduleid)) { + case 'p': /* Pbrick */ + do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); + do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8); + break; + case 'i': /* Ibrick */ + /* port 0xe on the Ibrick only has slots 1 and 2 */ + if (pcibr_soft->bs_xid == 0xe) { + do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); + do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8); + } + else { + /* allocate one RRB for the serial port */ + do_pcibr_rrb_autoalloc(pcibr_soft, 0, 1); + } + break; + } /* switch */ + } #ifdef LATER if (strstr(nicinfo, XTALK_PCI_PART_NUM)) { @@ -4119,13 +4227,13 @@ #endif } #else - printk("pcibr_attach: FIXME to call do_pcibr_rrb_autoalloc nicinfo 0x%p\n", nicinfo); + FIXME("pcibr_attach: Call do_pcibr_rrb_autoalloc nicinfo\n"); #endif if (aa) async_attach_add_info(noslot_conn, aa); - pciio_device_attach(noslot_conn); + pciio_device_attach(noslot_conn, 0); /* @@ -4166,14 +4274,14 @@ printk("pcibr_device_detach called for %p/%d\n", pcibr_vhdl,slot); #endif - pcibr_device_detach(pcibr_vhdl, slot); + pcibr_slot_detach(pcibr_vhdl, slot, 0); } /* Unregister the no-slot connection point */ pciio_device_info_unregister(pcibr_vhdl, &(pcibr_soft->bs_noslot_info->f_c)); - spinlock_destroy(&pcibr_soft->bs_lock); + spin_lock_destroy(&pcibr_soft->bs_lock); kfree(pcibr_soft->bs_name); /* Error handler gets unregistered when the widget info is @@ -4264,7 +4372,7 @@ size_t msize; /* size of devio(x) mapped area on PCI */ size_t mmask; /* addr bits stored in Device(x) */ - unsigned s; + unsigned long s; s = pcibr_lock(pcibr_soft); @@ -4327,7 +4435,7 @@ if (wspace == PCIIO_SPACE_NONE) goto done; - /* get pci base and size */ + /* get PCI base and size */ wbase = pcibr_info->f_window[bar].w_base; wsize = pcibr_info->f_window[bar].w_size; @@ -4587,7 +4695,7 @@ pcibr_piomap_t pcibr_piomap; iopaddr_t xio_addr; xtalk_piomap_t xtalk_piomap; - unsigned s; + unsigned long s; /* Make sure that the req sizes are non-zero */ if ((req_size < 1) || (req_size_max < 1)) @@ -4631,7 +4739,7 @@ pcibr_piomap->bp_pciaddr = pci_addr; pcibr_piomap->bp_mapsz = req_size; pcibr_piomap->bp_soft = pcibr_soft; - pcibr_piomap->bp_toc[0] = 0; + pcibr_piomap->bp_toc[0] = ATOMIC_INIT(0); if (mapptr) { s = pcibr_lock(pcibr_soft); @@ -4733,7 +4841,7 @@ pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); pciio_piospace_t piosp; - int s; + unsigned long s; iopaddr_t *pciaddr, *pcilast; iopaddr_t start_addr; @@ -4751,7 +4859,7 @@ /* * First look if a previously allocated chunk exists. */ - if ((piosp = pcibr_info->f_piospace) != (pciio_piospace_t)0) { + if ((piosp = pcibr_info->f_piospace)) { /* * Look through the list for a right sized free chunk. */ @@ -4825,7 +4933,7 @@ pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; pciio_piospace_t piosp; - int s; + unsigned long s; char name[1024]; /* @@ -4901,7 +5009,7 @@ iopaddr_t attributes = 0; /* Sanity check: Bridge only allows use of VCHAN1 via 64-bit addrs */ -#ifdef IRIX +#ifdef LATER ASSERT_ALWAYS(!(flags & PCIBR_VCHAN1) || (flags & PCIIO_DMA_A64)); #endif @@ -5031,7 +5139,16 @@ /* merge in forced flags */ flags |= pcibr_soft->bs_dma_flags; +#ifdef IRIX NEWf(pcibr_dmamap, flags); +#else + /* + * On SNIA64, these maps are pre-allocated because pcibr_dmamap_alloc() + * can be called within an interrupt thread. + */ + pcibr_dmamap = (pcibr_dmamap_t)get_free_pciio_dmamap(pcibr_soft->bs_vhdl); +#endif + if (!pcibr_dmamap) return 0; @@ -5162,7 +5279,7 @@ pcibr_dmamap->bd_pci_addr = PCI32_MAPPED_BASE + IOPGSIZE * ate_index; /* - * for xbridge the byte-swap bit == bit 29 of pci address + * for xbridge the byte-swap bit == bit 29 of PCI address */ if (pcibr_soft->bs_xbridge) { if (flags & PCIIO_BYTE_STREAM) @@ -5201,7 +5318,7 @@ bridge_t *bridge = pcibr_soft->bs_base; volatile unsigned *cmd_regp; unsigned cmd_reg; - unsigned s; + unsigned long s; pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_SSRAM; @@ -5239,20 +5356,15 @@ pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; pciio_slot_t slot = pcibr_dmamap->bd_slot; -#ifdef IRIX unsigned flags = pcibr_dmamap->bd_flags; -#endif /* Make sure that bss_ext_ates_active * is properly kept up to date. */ -#ifdef IRIX + if (PCIBR_DMAMAP_BUSY & flags) if (PCIBR_DMAMAP_SSRAM & flags) - atomicAddInt(&(pcibr_soft-> - bs_slot[slot]. - bss_ext_ates_active), -1); -#endif + atomic_dec(&(pcibr_soft->bs_slot[slot]. bss_ext_ates_active)); xtalk_dmamap_free(pcibr_dmamap->bd_xtalk); @@ -5265,7 +5377,9 @@ pcibr_dmamap->bd_ate_count); pcibr_release_device(pcibr_soft, slot, BRIDGE_DEV_PMU_BITS); } +#ifdef IRIX DEL(pcibr_dmamap); +#endif } /* @@ -5325,7 +5439,6 @@ /* We are starting to get more complexity * surrounding writing ATEs, so pull * the writing code into this new function. - * XXX mail ranga@engr for IP27 prom! */ #if PCIBR_FREEZE_TIME @@ -5342,13 +5455,13 @@ unsigned *cmd_regs) { pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; -#ifdef IRIX +#ifdef LATER int dma_slot = pcibr_dmamap->bd_slot; #endif int ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM; int slot; - unsigned s; + unsigned long s; unsigned cmd_reg; volatile unsigned *cmd_lwa; unsigned cmd_lwd; @@ -5371,27 +5484,22 @@ */ s = pcibr_lock(pcibr_soft); -#ifdef IRIX +#ifdef LATER /* just in case pcibr_dmamap_done was not called */ if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_BUSY) { pcibr_dmamap->bd_flags &= ~PCIBR_DMAMAP_BUSY; if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM) - atomicAddInt(&(pcibr_soft-> - bs_slot[dma_slot]. - bss_ext_ates_active), -1); + atomic_dec(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active)); xtalk_dmamap_done(pcibr_dmamap->bd_xtalk); } -#endif +#endif /* LATER */ #if PCIBR_FREEZE_TIME *freeze_time_ptr = get_timestamp(); #endif cmd_lwa = 0; for (slot = 0; slot < 8; ++slot) - if (pcibr_soft-> - bs_slot[slot]. - bss_ext_ates_active) { - + if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) { cmd_reg = pcibr_soft-> bs_slot[slot]. bss_cmd_shadow; @@ -5418,9 +5526,7 @@ /* Flush all the write buffers in the bridge */ for (slot = 0; slot < 8; ++slot) - if (pcibr_soft-> - bs_slot[slot]. - bss_ext_ates_active) { + if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) { /* Flush the write buffer associated with this * PCI device which might be using dma map RAM. */ @@ -5462,9 +5568,7 @@ unsigned s) { pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; -#ifdef IRIX int dma_slot = pcibr_dmamap->bd_slot; -#endif int slot; bridge_t *bridge = pcibr_soft->bs_base; int ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM; @@ -5486,11 +5590,7 @@ bridge->b_type0_cfg_dev[slot].l[PCI_CFG_COMMAND / 4] = cmd_reg; pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_BUSY; -#ifdef IRIX - atomicAddInt(&(pcibr_soft-> - bs_slot[dma_slot]. - bss_ext_ates_active), 1); -#endif + atomic_inc(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active)); #if PCIBR_FREEZE_TIME freeze_time = get_timestamp() - freeze_time_start; @@ -5685,11 +5785,7 @@ unsigned flags) { pcibr_soft_t pcibr_soft; -#ifdef IRIX - bridge_t *bridge; -#else bridge_t *bridge=NULL; -#endif unsigned al_flags = (flags & PCIIO_NOSLEEP) ? AL_NOSLEEP : 0; int inplace = flags & PCIIO_INPLACE; @@ -5699,19 +5795,11 @@ size_t length; iopaddr_t offset; unsigned direct64; -#ifdef IRIX - int ate_index; - int ate_count; - int ate_total = 0; - bridge_ate_p ate_ptr; - bridge_ate_t ate_proto; -#else int ate_index = 0; int ate_count = 0; int ate_total = 0; bridge_ate_p ate_ptr = (bridge_ate_p)0; bridge_ate_t ate_proto = (bridge_ate_t)0; -#endif bridge_ate_t ate_prev; bridge_ate_t ate; alenaddr_t xio_addr; @@ -5899,16 +5987,12 @@ * between _addr/_list and _done, but Hub does. */ -#ifdef IRIX if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_BUSY) { pcibr_dmamap->bd_flags &= ~PCIBR_DMAMAP_BUSY; if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM) - atomicAddInt(&(pcibr_dmamap->bd_soft-> - bs_slot[pcibr_dmamap->bd_slot]. - bss_ext_ates_active), -1); + atomic_dec(&(pcibr_dmamap->bd_soft->bs_slot[pcibr_dmamap->bd_slot]. bss_ext_ates_active)); } -#endif xtalk_dmamap_done(pcibr_dmamap->bd_xtalk); } @@ -6332,11 +6416,7 @@ */ if (xio_port == pcibr_soft->bs_xid) { pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, xio_size); -#ifdef IRIX - if (pci_addr == NULL) -#else if ( (pci_addr == (alenaddr_t)NULL) ) -#endif goto fail; } else if (direct64) { ASSERT(xio_port != 0); @@ -6371,11 +6451,7 @@ } } -#ifdef IRIX - if (relbits) -#else if (relbits) { -#endif if (direct64) { slotp->bss_d64_flags = flags; slotp->bss_d64_base = pci_base; @@ -6383,9 +6459,7 @@ slotp->bss_d32_flags = flags; slotp->bss_d32_base = pci_base; } -#ifndef IRIX } -#endif if (!inplace) alenlist_done(xtalk_alenlist); @@ -6480,26 +6554,155 @@ return bbits; } -#ifdef IRIX + +/* + * Get the next wrapper pointer queued in the interrupt circular buffer. + */ +#ifdef KERNEL_THREADS +pcibr_intr_wrap_t +pcibr_wrap_get(pcibr_intr_cbuf_t cbuf) +{ + pcibr_intr_wrap_t wrap; + + if (cbuf->ib_in == cbuf->ib_out) + PRINT_PANIC("pcibr intr circular buffer empty, cbuf=0x%x, ib_in=ib_out=%d\n", + cbuf, cbuf->ib_out); + + wrap = cbuf->ib_cbuf[cbuf->ib_out++]; + cbuf->ib_out = cbuf->ib_out % IBUFSIZE; + return(wrap); +} + +/* + * Queue a wrapper pointer in the interrupt circular buffer. + */ +void +pcibr_wrap_put(pcibr_intr_wrap_t wrap, pcibr_intr_cbuf_t cbuf) +{ + int in; + unsigned long s; + + /* + * Multiple CPUs could be executing this code simultaneously + * if a handler has registered multiple interrupt lines and + * the interrupts are directed to different CPUs. + */ + s = mutex_spinlock(&cbuf->ib_lock); + in = (cbuf->ib_in + 1) % IBUFSIZE; + if (in == cbuf->ib_out) + PRINT_PANIC("pcibr intr circular buffer full, cbuf=0x%x, ib_in=%d\n", + cbuf, cbuf->ib_in); + + cbuf->ib_cbuf[cbuf->ib_in] = wrap; + cbuf->ib_in = in; + mutex_spinunlock(&cbuf->ib_lock, s); + return; +} +#endif /* KERNEL_THREADS */ + +/* + * There are end cases where a deadlock can occur if interrupt + * processing completes and the Bridge b_int_status bit is still set. + * + * One scenerio is if a second PCI interrupt occurs within 60ns of + * the previous interrupt being cleared. In this case the Bridge + * does not detect the transition, the Bridge b_int_status bit + * remains set, and because no transition was detected no interrupt + * packet is sent to the Hub/Heart. + * + * A second scenerio is possible when a b_int_status bit is being + * shared by multiple devices: + * Device #1 generates interrupt + * Bridge b_int_status bit set + * Device #2 generates interrupt + * interrupt processing begins + * ISR for device #1 runs and + * clears interrupt + * Device #1 generates interrupt + * ISR for device #2 runs and + * clears interrupt + * (b_int_status bit still set) + * interrupt processing completes + * + * Interrupt processing is now complete, but an interrupt is still + * outstanding for Device #1. But because there was no transition of + * the b_int_status bit, no interrupt packet will be generated and + * a deadlock will occur. + * + * To avoid these deadlock situations, this function is used + * to check if a specific Bridge b_int_status bit is set, and if so, + * cause the setting of the corresponding interrupt bit. + * + * On a XBridge (IP35), we do this by writing the appropriate Bridge Force + * Interrupt register. + */ +void +pcibr_force_interrupt(pcibr_intr_wrap_t wrap) +{ + unsigned bit; + pcibr_soft_t pcibr_soft = wrap->iw_soft; + bridge_t *bridge = pcibr_soft->bs_base; + cpuid_t cpuvertex_to_cpuid(devfs_handle_t vhdl); + + bit = wrap->iw_intr; + + if (pcibr_soft->bs_xbridge) { + bridge->b_force_pin[bit].intr = 1; + } else if ((1 << bit) & *wrap->iw_stat) { + cpuid_t cpu; + unsigned intr_bit; + xtalk_intr_t xtalk_intr = + pcibr_soft->bs_intr[bit].bsi_xtalk_intr; + + intr_bit = (short) xtalk_intr_vector_get(xtalk_intr); + cpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr)); + REMOTE_CPU_SEND_INTR(cpu, intr_bit); + } +} + /* Wrapper for pcibr interrupt threads. */ +#ifdef KERNEL_THREADS static void pcibr_intrd(pcibr_intr_t intr) { + pcibr_intr_wrap_t wrap; + /* Called on each restart */ ASSERT(cpuid() == intr->bi_mustruncpu); #ifdef ITHREAD_LATENCY - xthread_update_latstats(intr->bi_tinfo->thd_latstats); + xthread_update_latstats(intr->bi_tinfo.thd_latstats); #endif /* ITHREAD_LATENCY */ ASSERT(intr->bi_func != NULL); intr->bi_func(intr->bi_arg); /* Invoke the interrupt handler */ + /* + * The pcibr_intrd thread needs access to the wrapper struct + * specific to the current interrupt it is processing. Because + * multiple calls/wakeups to the thread could be queued, each + * potentially from a different interrupt line (PCIIO_INTR_LINE_A, + * etc), multiple wrapper struct pointers need to be queued. This + * is done via a circular buffer of wrapper struct pointers. + */ + wrap = pcibr_wrap_get(&intr->bi_ibuf); + + /* + * The interrupt handler has completed. Now decrement the running + * count tracking the number of handlers still running for this line. + * If this was the last handler to complete (i.e., iw_hdlrcnt == 0), + * avoid a potential deadlock condition and ensure that another + * interrupt will occur if the Bridge b_int_status bit is still + * set. + */ + atomicAddInt(&(wrap->iw_hdlrcnt), -1); + if (wrap->iw_hdlrcnt == 0) + pcibr_force_interrupt(wrap); + ipsema(&intr->bi_tinfo.thd_isync); /* Sleep 'till next interrupt */ /* NOTREACHED */ } - static void pcibr_intrd_start(pcibr_intr_t intr) { @@ -6519,14 +6722,16 @@ char thread_name[32]; sprintf(thread_name, "pcibr_intrd[0x%x]", bridge_levels); + thread_name[IT_NAMELEN-1] = '\0'; /* XXX need to adjust priority whenever an interrupt is connected */ + intr->bi_tinfo.thd_pri = intr_swlevel; atomicSetInt(&intr->bi_tinfo.thd_flags, THD_ISTHREAD | THD_REG); xthread_setup(thread_name, intr_swlevel, &intr->bi_tinfo, (xt_func_t *)pcibr_intrd_start, (void *)intr); } -#endif /* IRIX */ +#endif /* KERNEL_THREADS */ @@ -6542,13 +6747,16 @@ pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; bridge_t *bridge = pcibr_soft->bs_base; - int is_threaded; + int is_threaded = 0; +#ifdef KERNEL_THREADS + cpuid_t mustruncpu = CPU_NONE; + cpuid_t old_intrcpu = CPU_NONE; +#endif int thread_swlevel; xtalk_intr_t *xtalk_intr_p; pcibr_intr_t *pcibr_intr_p; pcibr_intr_list_t *intr_list_p; - pcibr_intr_wrap_t *intr_wrap_p; unsigned pcibr_int_bits; unsigned pcibr_int_bit; @@ -6557,7 +6765,6 @@ pcibr_intr_t pcibr_intr; pcibr_intr_list_t intr_entry; pcibr_intr_list_t intr_list; - pcibr_intr_wrap_t intr_wrap; bridgereg_t int_dev; #if DEBUG && INTR_DEBUG @@ -6576,9 +6783,29 @@ return NULL; if (dev_desc) { + cpuid_t intr_target_from_desc(device_desc_t, int); + +#ifdef KERNEL_THREADS is_threaded = !(device_desc_flags_get(dev_desc) & D_INTR_NOTHREAD); - if (is_threaded) + if (is_threaded) { + /* + * If the device descriptor contains interrupt target info, + * save the CPU requested. This is the CPU the pcibr_intrd + * thread will be set to run on. + * + * We need to get the interrupt target info at this time, because + * the original intr_target value can be overwritten, as part of + * the xtalk_intr_alloc_nothd() call, with the actual interrupt CPU. + * This can be different than the requested CPU if the lower layers + * could not direct the hardware interrupt to the requested CPU. + * Regardless of which CPU processes the hardware interrupt, the + * ISR thread will still be setup to run on the CPU originally + * requested. + */ + mustruncpu = intr_target_from_desc(dev_desc, SUBNODE_ANY); thread_swlevel = device_desc_intr_swlevel_get(dev_desc); + } +#endif /* KERNEL_THREADS */ } else { extern int default_intr_pri; @@ -6594,6 +6821,11 @@ pcibr_intr->bi_arg = 0; /* unset until connect */ pcibr_intr->bi_flags = is_threaded ? 0 : PCIIO_INTR_NOTHREAD; pcibr_intr->bi_mustruncpu = CPU_NONE; +#ifdef KERNEL_THREADS + pcibr_intr->bi_ibuf.ib_in = 0; + pcibr_intr->bi_ibuf.ib_out = 0; +#endif + mutex_spinlock_init(&pcibr_intr->bi_ibuf.ib_lock); pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info, lines); @@ -6626,7 +6858,17 @@ * single Bridge. (IP35-specific code forces this, and we * verify in pcibr_setwidint.) */ - xtalk_intr = xtalk_intr_alloc(xconn_vhdl, dev_desc, owner_dev); + + /* + * All code dealing with threaded PCI interrupt handlers + * is located at the pcibr level. Because of this, + * we always want the lower layers (hub/heart_intr_alloc, + * intr_level_connect) to treat us as non-threaded so we + * don't set up a duplicate threaded environment. We make + * this happen by calling a special xtalk interface. + */ + xtalk_intr = xtalk_intr_alloc_nothd(xconn_vhdl, dev_desc, + owner_dev); #if DEBUG && INTR_DEBUG printk("%v: xtalk_intr=0x%X\n", xconn_vhdl, xtalk_intr); #endif @@ -6690,32 +6932,64 @@ } } - /* - * For threaded drivers, set the interrupt thread to run wherever - * the interrupt is targeted. - */ -#ifdef notyet +#ifdef KERNEL_THREADS if (is_threaded) { - cpuid_t old_mustrun = pcibr_intr->bi_mustruncpu; - pcibr_intr->bi_mustruncpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr)); - ASSERT(pcibr_intr->bi_mustruncpu >= 0); + cpuid_t intrcpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr)); /* - * This is possible, but very unlikely: It means that 2 (or more) interrupts - * originating on a single Bridge and used by a single device were unable to - * find sufficient xtalk interrupt resources that would allow them all to be - * handled by the same CPU. If someone tries to target lots of interrupts to - * a single CPU, we might hit this case. Things should still operate correctly, - * but it's a sub-optimal configuration. + * It is possible that 2 (or more) interrupts originating on a + * single Bridge and used by a single device were assigned to + * different CPUs. If this occurs issue a warning message for + * this sub-optimal configuration. There are two ways this + * could happen: + * + * - There were insufficient xtalk interrupt resources to + * allow all interrupts to be assigned to the same CPU. + * This is an unlikely case, but could happen if someone + * tries to target a lot of interrupts to a single CPU. + * + * - If there is no device descriptor associated with this + * device, the xtalk/hub/heart layers will not know to + * assign the same CPU to any additional interrupts this + * driver has specified, and will perform the normal load + * leveling of interrupts across CPUs. + * (The lower layers store the CPU assigned to the first + * interrupt in the device desc, if present, and then when + * called again for additional interrupts for the same device, + * use this information to assign the same CPU to these + * interrupts.) */ - if ((old_mustrun != CPU_NONE) && (old_mustrun != pcibr_intr->bi_mustruncpu)) { -#ifdef SUPPORT_PRINTING_V_FORMAT - PRINT_WARNING( "Conflict on where to schedule interrupts for %v\n", pconn_vhdl); + if ((old_intrcpu != CPU_NONE) && (old_intrcpu != intrcpu)) { +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_WARNING("Conflict on where to schedule interrupts for %v\n", pconn_vhdl); +#else + PRINT_WARNING("Conflict on where to schedule interrupts for 0x%x\n", pconn_vhdl); #endif - PRINT_WARNING( "(on cpu %d or on cpu %d)\n", old_mustrun, pcibr_intr->bi_mustruncpu); + PRINT_WARNING("(on cpu %d or on cpu %d), cpu %d used\n", old_intrcpu, intrcpu, intrcpu); + } + if (old_intrcpu == CPU_NONE) + old_intrcpu = intrcpu; + /* + * For threaded drivers, set the interrupt thread to run wherever + * the interrupt is targeted, or where requested in the dev_desc. + */ + if (mustruncpu != CPU_NONE) { + pcibr_intr->bi_mustruncpu = mustruncpu; + if (mustruncpu != intrcpu) { + PRINT_WARNING("Request to target PCI interrupts to CPU %d could not\n" + " be satisfied, CPU %d used. However, interrupt thread\n" + " pcibr_intrd will run on CPU %d as requested.\n" + " %v (0x%x)\n", + mustruncpu, intrcpu, mustruncpu, owner_dev, + owner_dev); + } + } else { + pcibr_intr->bi_mustruncpu = intrcpu; } + ASSERT(pcibr_intr->bi_mustruncpu >= 0); + } -#endif +#endif /* KERNEL_THREADS */ pcibr_intr->bi_ibits |= 1 << pcibr_int_bit; @@ -6723,8 +6997,20 @@ intr_entry->il_next = NULL; intr_entry->il_intr = pcibr_intr; intr_entry->il_wrbf = &(bridge->b_wr_req_buf[pciio_slot].reg); + intr_list_p = + &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list; +#if DEBUG && INTR_DEBUG +#if defined(SUPPORT_PRINTING_V_FORMAT) + printk("0x%x: Bridge bit %d wrap=0x%x\n", + pconn_vhdl, pcibr_int_bit, + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap); +#else + printk("%v: Bridge bit %d wrap=0x%x\n", + pconn_vhdl, pcibr_int_bit, + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap); +#endif +#endif - intr_list_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_list; if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { /* we are the first interrupt on this bridge bit. */ @@ -6751,29 +7037,12 @@ intr_list_p = &intr_list->il_next; if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { /* we are the new second interrupt on this bit. - * switch to local wrapper. */ + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared = 1; #if DEBUG && INTR_DEBUG printk("%v INT 0x%x (bridge bit %d) is new SECOND\n", pconn_vhdl, pcibr_int_bits, pcibr_int_bit); #endif - NEW(intr_wrap); - intr_wrap->iw_soft = pcibr_soft; - intr_wrap->iw_stat = &(bridge->b_int_status); - intr_wrap->iw_intr = 1 << pcibr_int_bit; - intr_wrap->iw_list = intr_list; - intr_wrap_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; - if (!compare_and_swap_ptr((void **) intr_wrap_p, NULL, intr_wrap)) { - /* someone else set up the wrapper. - */ - DEL(intr_wrap); - continue; -#if DEBUG && INTR_DEBUG - } else { - printk("%v bridge bit %d wrapper state created\n", - pconn_vhdl, pcibr_int_bit); -#endif - } continue; } while (1) { @@ -6807,13 +7076,13 @@ } } -#ifdef IRIX +#ifdef KERNEL_THREADS if (is_threaded) { /* Set pcibr_intr->bi_tinfo */ pcibr_thread_setup(pcibr_intr, pcibr_int_bits, thread_swlevel); ASSERT(!(pcibr_intr->bi_flags & PCIIO_INTR_CONNECTED)); } -#endif +#endif /* KERNEL_THREADS */ #if DEBUG && INTR_DEBUG printk("%v pcibr_intr_alloc complete\n", pconn_vhdl); @@ -6832,13 +7101,13 @@ pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; unsigned pcibr_int_bit; pcibr_intr_list_t intr_list; - pcibr_intr_wrap_t intr_wrap; + int intr_shared; xtalk_intr_t *xtalk_intrp; for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) { if (pcibr_int_bits & (1 << pcibr_int_bit)) { for (intr_list = - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_list; + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list; intr_list != NULL; intr_list = intr_list->il_next) if (compare_and_swap_ptr((void **) &intr_list->il_intr, @@ -6852,10 +7121,11 @@ /* If this interrupt line is not being shared between multiple * devices release the xtalk interrupt resources. */ - intr_wrap = - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; + intr_shared = + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared; xtalk_intrp = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; - if ((intr_wrap == NULL) && (*xtalk_intrp)) { + + if ((!intr_shared) && (*xtalk_intrp)) { bridge_t *bridge = pcibr_soft->bs_base; bridgereg_t int_dev; @@ -6900,7 +7170,7 @@ unsigned pcibr_int_bits = pcibr_intr->bi_ibits; unsigned pcibr_int_bit; bridgereg_t b_int_enable; - unsigned s; + unsigned long s; if (pcibr_intr == NULL) return -1; @@ -6924,59 +7194,29 @@ if (pcibr_int_bits & (1 << pcibr_int_bit)) { pcibr_intr_wrap_t intr_wrap; xtalk_intr_t xtalk_intr; - int *setptr; xtalk_intr = pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; - /* if we have no wrap structure, - * tell xtalk to deliver the interrupt - * directly to the client. + intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; + /* + * If this interrupt line is being shared and the connect has + * already been done, no need to do it again. */ - intr_wrap = pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; - if (intr_wrap == NULL) { - xtalk_intr_connect(xtalk_intr, - (intr_func_t) intr_func, - (intr_arg_t) intr_arg, - (xtalk_intr_setfunc_t) pcibr_setpciint, - (void *) &(bridge->b_int_addr[pcibr_int_bit].addr), - thread); -#if DEBUG && INTR_DEBUG - printk("%v bridge bit %d routed by xtalk\n", - pcibr_intr->bi_dev, pcibr_int_bit); -#endif + if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected) continue; - } - - setptr = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_wrap_set; - if (*setptr) - continue; - - /* We have a wrap structure, so we're sharing a Bridge interrupt level */ - - xtalk_intr_disconnect(xtalk_intr); /* Disconnect old interrupt */ /* - If the existing xtalk_intr was allocated without the NOTHREAD flag, - we need to allocate a new one that's NOTHREAD, and connect to the - new one. pcibr_intr_list_func expects to run at interrupt level - rather than in a thread. With today's devices, this can't happen, - so let's punt on writing the code till we need it (probably never). - Instead, just ASSERT that we're a NOTHREAD xtalk_intr. - */ -#ifdef IRIX - ASSERT_ALWAYS(!(pcibr_intr->bi_flags & PCIIO_INTR_NOTHREAD) || - xtalk_intr_flags_get(xtalk_intr) & XTALK_INTR_NOTHREAD); -#endif - - /* Use the wrapper dispatch function to handle shared Bridge interrupts */ + * Use the pcibr wrapper function to handle all Bridge interrupts + * regardless of whether the interrupt line is shared or not. + */ xtalk_intr_connect(xtalk_intr, - pcibr_intr_list_func, + pcibr_intr_func, (intr_arg_t) intr_wrap, (xtalk_intr_setfunc_t) pcibr_setpciint, (void *) &(bridge->b_int_addr[pcibr_int_bit].addr), 0); - *setptr = 1; + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 1; #if DEBUG && INTR_DEBUG printk("%v bridge bit %d wrapper connected\n", @@ -7001,9 +7241,9 @@ bridge_t *bridge = pcibr_soft->bs_base; unsigned pcibr_int_bits = pcibr_intr->bi_ibits; unsigned pcibr_int_bit; - pcibr_intr_wrap_t intr_wrap; + pcibr_intr_wrap_t intr_wrap; bridgereg_t b_int_enable; - unsigned s; + unsigned long s; /* Stop calling the function. Now. */ @@ -7021,7 +7261,7 @@ */ for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) if ((pcibr_int_bits & (1 << pcibr_int_bit)) && - (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_wrap_set)) + (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared)) pcibr_int_bits &= ~(1 << pcibr_int_bit); if (!pcibr_int_bits) return; @@ -7035,26 +7275,32 @@ for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) if (pcibr_int_bits & (1 << pcibr_int_bit)) { - /* if we have set up the share wrapper, + /* if the interrupt line is now shared, * do not disconnect it. */ - if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_wrap_set) + if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) continue; xtalk_intr_disconnect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr); + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 0; + +#if DEBUG && INTR_DEBUG + printk("%s: xtalk disconnect done for Bridge bit %d\n", + pcibr_soft->bs_name, pcibr_int_bit); +#endif - /* if we have a share wrapper state, + /* if we are sharing the interrupt line, * connect us up; this closes the hole - * where the connection of the wrapper + * where the another pcibr_intr_alloc() * was in progress as we disconnected. */ - intr_wrap = pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; - if (intr_wrap == NULL) + intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; + if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) continue; xtalk_intr_connect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr, - pcibr_intr_list_func, + pcibr_intr_func, (intr_arg_t) intr_wrap, (xtalk_intr_setfunc_t) pcibr_setpciint, (void *) &(bridge->b_int_addr[pcibr_int_bit].addr), @@ -7168,7 +7414,7 @@ bridge->b_int_enable |= ~BRIDGE_IMR_INT_MSK; } else { - /* routing a pci device interrupt. + /* routing a PCI device interrupt. * targ and low 38 bits of addr must * be the same as the already set * value for the widget error interrupt. @@ -7187,46 +7433,71 @@ bridge->b_wid_tflush; /* wait until Bridge PIO complete */ } + +/* + * pcibr_intr_func() + * + * This is the pcibr interrupt "wrapper" function that is called, + * in interrupt context, to initiate the interrupt handler(s) registered + * (via pcibr_intr_alloc/connect) for the occuring interrupt. Non-threaded + * handlers will be called directly, and threaded handlers will have their + * thread woken up. + */ void -pcibr_intr_list_func(intr_arg_t arg) +pcibr_intr_func(intr_arg_t arg) { pcibr_intr_wrap_t wrap = (pcibr_intr_wrap_t) arg; - reg_p statp = wrap->iw_stat; - bridgereg_t mask = wrap->iw_intr; reg_p wrbf; - pcibr_intr_list_t list; - pcibr_intr_t intr; intr_func_t func; + pcibr_intr_t intr; + pcibr_intr_list_t list; int clearit; - int thread_count = 0; +#ifdef KERNEL_THREADS + int do_nonthreaded = 0; + int do_threaded = 1; + int is_threaded = 0; +#else + int do_nonthreaded = 1; + int do_threaded = 0; + int is_threaded = 0; +#endif + int nonthreaded_count = 0; + int x = 0; + + /* + * If any handler is still running from a previous interrupt + * just return. If there's a need to call the handler(s) again, + * another interrupt will be generated either by the device or by + * pcibr_force_interrupt(). + */ + + if (wrap->iw_hdlrcnt) { + return; + } /* - * Loop until either - * 1) All interrupts have been removed by direct-called interrupt handlers OR - * 2) We've woken up at least one interrupt thread that will presumably clear - * Bridge interrupt bits + * Call all interrupt handlers registered. + * First, the pcibr_intrd threads for any threaded handlers will be + * awoken, then any non-threaded handlers will be called sequentially. */ - while ((!thread_count) && (mask & *statp)) { clearit = 1; - for (list = wrap->iw_list; - list != NULL; - list = list->il_next) { - if ((intr = list->il_intr) && - (intr->bi_flags & PCIIO_INTR_CONNECTED)) { - int is_threaded; + while (do_threaded || do_nonthreaded) { + for (list = wrap->iw_list; list != NULL; list = list->il_next) { + if ((intr = list->il_intr) && + (intr->bi_flags & PCIIO_INTR_CONNECTED)) { - ASSERT(intr->bi_func); + ASSERT(intr->bi_func); /* * This device may have initiated write * requests since the bridge last saw * an edge on this interrupt input; flushing - * the buffer here should help but may not - * be sufficient if we get more requests after - * the flush, followed by the card deciding - * it wants service, before the interrupt - * handler checks to see if things need + * the buffer prior to invoking the handler + * should help but may not be sufficient if we + * get more requests after the flush, followed + * by the card deciding it wants service, before + * the interrupt handler checks to see if things need * to be done. * * There is a similar race condition if @@ -7238,28 +7509,96 @@ * has completed, but before observing the * contents of memory? */ -#ifdef IRIX - if (wrbf = list->il_wrbf) + +#ifdef KERNEL_THREADS + is_threaded = !(intr->bi_flags & PCIIO_INTR_NOTHREAD); + if (!is_threaded) { + nonthreaded_count++; + } + + if ((do_threaded) && (is_threaded)) { + /* Only need to flush write buffers if sharing */ + + if ((wrap->iw_shared) && (wrbf = list->il_wrbf)) { + if (x = *wrbf) /* write request buffer flush */ +#ifdef SUPPORT_PRINTING_V_FORMAT + PRINT_ALERT("pcibr_intr_func %v: \n" + "write buffer flush failed, wrbf=0x%x\n", + list->il_intr->bi_dev, wrbf); #else - if ((wrbf = list->il_wrbf)) + PRINT_ALERT("pcibr_intr_func 0x%x: \n" + "write buffer flush failed, wrbf=0x%x\n", + list->il_intr->bi_dev, wrbf); #endif - (void) *wrbf; /* write request buffer flush */ + } + + /* + * Keep a running count of the number of interrupt + * handlers that have yet to complete. + */ + atomicAddInt(&(wrap->iw_hdlrcnt), 1); + + /* + * Prior to waking up pcibr_intrd, a pointer to the + * wrapper struct corresponding to the interrupt taken + * needs to be queued in the interrupt circular buffer. + * The pcibr_intrd thread needs the wrapper pointer in + * order to decrement the handler count (iw_hdlrcnt). + */ + pcibr_wrap_put(wrap, &intr->bi_ibuf); +#ifdef ITHREAD_LATENCY + xthread_set_istamp(intr->bi_tinfo.thd_latstats); +#endif /* ITHREAD_LATENCY */ + up(&intr->bi_tinfo.thd_isync); + } else +#endif /* KERNEL_THREADS */ + if ((do_nonthreaded) && (!is_threaded)) { + /* Non-threaded. + * Call the interrupt handler at interrupt level + */ - is_threaded = !(intr->bi_flags & PCIIO_INTR_NOTHREAD); + /* Only need to flush write buffers if sharing */ - if (is_threaded) { - thread_count++; -#ifdef IRIX - icvsema(&intr->bi_tinfo.thd_isync, intr->bi_tinfo.thd_pri, - NULL, NULL, NULL); + if ((wrap->iw_shared) && (wrbf = list->il_wrbf)) { + if ((x = *wrbf)) /* write request buffer flush */ +#ifdef SUPPORT_PRINTING_V_FORMAT + PRINT_ALERT("pcibr_intr_func %v: \n" + "write buffer flush failed, wrbf=0x%x\n", + list->il_intr->bi_dev, wrbf); +#else + PRINT_ALERT("pcibr_intr_func %p: \n" + "write buffer flush failed, wrbf=0x%x\n", + list->il_intr->bi_dev, wrbf); #endif - } else { - /* Non-threaded. Call the interrupt handler at interrupt level */ + } + func = intr->bi_func; func(intr->bi_arg); + } + + clearit = 0; } + } + + if (do_threaded) { + /* + * All threaded handlers have been called; + * next do non-threaded, if any. + */ + do_threaded = 0; - clearit = 0; + if (nonthreaded_count) + do_nonthreaded = 1; + } else { + do_nonthreaded = 0; + /* + * If the non-threaded handler was the last to complete, + * (i.e., no threaded handlers still running) force an + * interrupt to avoid a potential deadlock situation. + */ + if (wrap->iw_hdlrcnt == 0) { + pcibr_force_interrupt(wrap); + } } } @@ -7275,7 +7614,8 @@ pcibr_soft_t pcibr_soft = wrap->iw_soft; bridge_t *bridge = pcibr_soft->bs_base; bridgereg_t b_int_enable; - unsigned s; + bridgereg_t mask = 1 << wrap->iw_intr; + unsigned long s; s = pcibr_lock(pcibr_soft); b_int_enable = bridge->b_int_enable; @@ -7285,7 +7625,6 @@ pcibr_unlock(pcibr_soft, s); return; } - } } /* ===================================================================== @@ -7403,7 +7742,7 @@ bridge->b_pci_err_lower); } if (int_status & BRIDGE_ISR_ERROR_FATAL) { - cmn_err_tag(14, (int)CE_PANIC, "PCI Bridge Error interrupt killed the system"); + PRINT_PANIC("PCI Bridge Error interrupt killed the system"); /*NOTREACHED */ } else { PRINT_ALERT( "Non-fatal Error in Bridge.."); @@ -7491,10 +7830,8 @@ soft->bs_slot[slot].bss_window[win].bssw_base; else if (map->bp_space == PCIIO_SPACE_ROM) base += pcibr_info->f_rbase; -#ifdef IRIX if ((pci_addr >= base) && (pci_addr < (base + size))) - atomicAddInt(map->bp_toc, 1); -#endif + atomic_inc(map->bp_toc); } } } @@ -7532,34 +7869,8 @@ bridgereg_t err_status; int i; -#if defined(SN0_HWDEBUG) - extern int la_trigger_nasid1; - extern int la_trigger_nasid2; - extern long la_trigger_val; -#endif - /* REFERENCED */ bridgereg_t disable_errintr_mask = 0; -#ifdef IRIX - int rv; -#else - int rv = 0; -#endif - int error_code = IOECODE_DMA | IOECODE_READ; - ioerror_mode_t mode = MODE_DEVERROR; - ioerror_t ioe; - -#if defined(SN0_HWDEBUG) - /* - * trigger points for logic analyzer. Used to debug the DMA timeout - * note that 0xcafe is added to the trigger values to avoid false - * triggers when la_trigger_val shows up in a cacheline as data - */ - if (la_trigger_nasid1 != -1) - REMOTE_HUB_PI_S(la_trigger_nasid1, 0, PI_CPU_NUM, la_trigger_val + 0xcafe); - if (la_trigger_nasid2 != -1) - REMOTE_HUB_PI_S(la_trigger_nasid2, 0, PI_CPU_NUM, la_trigger_val + 0xcafe); -#endif #if PCIBR_SOFT_LIST /* IP27 seems to be handing us junk. @@ -7635,7 +7946,7 @@ bs_estat->bs_errcount_total++; -#ifdef IRIX +#ifdef LATER current_tick = lbolt; #else current_tick = 0; @@ -7777,7 +8088,7 @@ if ((err_status & BRIDGE_ISR_INVLD_ADDR) && ((((uint64_t) bridge->b_wid_err_upper << 32) | (bridge->b_wid_err_lower)) == (BRIDGE_INT_RST_STAT & 0xff0))) { -#ifdef IRIX +#ifdef LATER if (kdebug) PRINT_NOTICE( "%s bridge: ignoring llp/control address interrupt", pcibr_soft->bs_name); @@ -7787,32 +8098,6 @@ } #endif /* PCIBR_LLP_CONTROL_WAR */ - /* Check if this is the RESP_XTALK_ERROR interrupt. - * This can happen due to a failed DMA READ operation. - */ - if (err_status & BRIDGE_ISR_RESP_XTLK_ERR) { - /* Phase 1 : Look at the error state in the bridge and further - * down in the device layers. - */ -#if defined(CONFIG_SGI_IO_ERROR_HANDLING) - (void)error_state_set(pcibr_soft->bs_conn, ERROR_STATE_LOOKUP); -#endif - IOERROR_SETVALUE(&ioe, widgetnum, pcibr_soft->bs_xid); - (void)pcibr_error_handler((error_handler_arg_t)pcibr_soft, - error_code, - mode, - &ioe); - /* Phase 2 : Perform the action agreed upon in phase 1. - */ -#if defined(CONFIG_SGI_IO_ERROR_HANDLING) - (void)error_state_set(pcibr_soft->bs_conn, ERROR_STATE_ACTION); -#endif - rv = pcibr_error_handler((error_handler_arg_t)pcibr_soft, - error_code, - mode, - &ioe); - } - if (rv != IOERROR_HANDLED) { #ifdef DEBUG if (err_status & BRIDGE_ISR_ERROR_DUMP) pcibr_error_dump(pcibr_soft); @@ -7822,7 +8107,7 @@ pcibr_error_dump(pcibr_soft); } #endif - } + /* * We can't return without re-enabling the interrupt, since * it would cause problems for devices like IOC3 (Lost @@ -7853,11 +8138,7 @@ iopaddr_t *offsetp, pciio_function_t *funcp) { -#ifdef IRIX - int s, f, w; -#else int s, f=0, w; -#endif iopaddr_t base; size_t size; pciio_piospace_t piosp; @@ -8082,7 +8363,7 @@ * decodes the PCI specific portions -- we count on our * callers to dump the raw IOE data. */ -#ifdef colin +#ifdef LATER #define BEM_ADD_IOE(ioe) \ do { \ if (IOERROR_FIELDVALID(ioe, busspace)) { \ @@ -8165,7 +8446,7 @@ * and need to construct the slot/space/offset. */ -#ifdef colin +#ifdef LATER bad_xaddr = IOERROR_GETVALUE(ioe, xtalkaddr); #else bad_xaddr = -1; @@ -8207,7 +8488,7 @@ if (x > 1) x--; /* x is which devio reg; no guarantee - * pci slot x will be responding. + * PCI slot x will be responding. * still need to figure out who decodes * space/offset on the bus. */ @@ -8253,7 +8534,7 @@ if ((slot == PCIIO_SLOT_NONE) && (space != PCIIO_SPACE_NONE)) { /* we've got a space/offset but not which - * pci slot decodes it. Check through our + * PCI slot decodes it. Check through our * notions of which devices decode where. * * Yes, this "duplicates" some logic in @@ -8353,9 +8634,7 @@ wx = PCIIO_SPACE_MEM; wl = wb + ws; if ((wx == raw_space) && (raw_paddr >= wb) && (raw_paddr < wl)) { -#ifdef IRIX - atomicAddInt(map->bp_toc, 1); -#endif + atomic_inc(map->bp_toc); if (slot == PCIIO_SLOT_NONE) { slot = cs; space = map->bp_space; @@ -8369,7 +8648,7 @@ if (space != PCIIO_SPACE_NONE) { if (slot != PCIIO_SLOT_NONE) { -#ifdef IRIX +#ifdef LATER if (func != PCIIO_FUNC_NONE) IOERROR_SETVALUE(ioe, widgetdev, pciio_widgetdev_create(slot,func)); @@ -8451,10 +8730,10 @@ * error interrupt is due to read/write error.. */ - /* We know the xtalk addr, the raw pci bus space, - * the raw pci bus address, the decoded pci bus + /* We know the xtalk addr, the raw PCI bus space, + * the raw PCI bus address, the decoded PCI bus * space, the offset within that space, and the - * decoded pci slot (which may be "PCIIO_SLOT_NONE" if no slot + * decoded PCI slot (which may be "PCIIO_SLOT_NONE" if no slot * is known to be involved). */ @@ -8506,7 +8785,7 @@ BEM_ADD_VAR(raw_paddr); if (IOERROR_FIELDVALID(ioe, widgetdev)) { -#ifdef colin +#ifdef LATER slot = pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, widgetdev)); func = pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, @@ -8545,7 +8824,7 @@ * Need a way to ensure we don't inadvertently clear some * other errors. */ -#ifdef IRIX +#ifdef LATER if (IOERROR_FIELDVALID(ioe, widgetdev)) pcibr_device_disable(pcibr_soft, pciio_widgetdev_slot_get( @@ -8586,7 +8865,7 @@ * Look up the address, in the bridge error registers, and * take appropriate action */ -#ifdef colin +#ifdef LATER ASSERT(IOERROR_GETVALUE(ioe, widgetnum) == pcibr_soft->bs_xid); ASSERT(bridge); #endif @@ -8618,7 +8897,7 @@ retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); if (retval != IOERROR_HANDLED) -#ifdef colin +#ifdef LATER pcibr_device_disable(pcibr_soft, pciio_widgetdev_slot_get( IOERROR_GETVALUE(ioe,widgetdev))); @@ -8690,7 +8969,7 @@ retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); -#ifdef IRIX +#ifdef LATER if (retval != IOERROR_HANDLED) { pcibr_device_disable(pcibr_soft, pciio_widgetdev_slot_get( @@ -8722,22 +9001,8 @@ { pcibr_soft_t pcibr_soft; int retval = IOERROR_BADERRORCODE; - devfs_handle_t xconn_vhdl,pcibr_vhdl; -#if defined(CONFIG_SGI_IO_ERROR_HANDLING) - error_state_t e_state; -#endif - pcibr_soft = (pcibr_soft_t) einfo; - - xconn_vhdl = pcibr_soft->bs_conn; - pcibr_vhdl = pcibr_soft->bs_vhdl; -#if defined(CONFIG_SGI_IO_ERROR_HANDLING) - e_state = error_state_get(xconn_vhdl); - - if (error_state_set(pcibr_vhdl, e_state) == - ERROR_RETURN_CODE_CANNOT_SET_STATE) - return(IOERROR_UNHANDLED); -#endif + pcibr_soft = (pcibr_soft_t) einfo; /* If we are in the action handling phase clean out the error state * on the xswitch. @@ -8844,7 +9109,7 @@ bridge_t *bridge = pcibr_soft->bs_base; bridgereg_t ctlreg; unsigned cfgctl[8]; - unsigned s; + unsigned long s; int f, nf; pcibr_info_h pcibr_infoh; pcibr_info_t pcibr_info; @@ -8869,11 +9134,7 @@ /* XXX delay? */ for (f = 0; f < nf; ++f) -#ifdef IRIX - if (pcibr_info = pcibr_infoh[f]) -#else if ((pcibr_info = pcibr_infoh[f])) -#endif for (win = 0; win < 6; ++win) if (pcibr_info->f_window[win].w_base != 0) bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_BASE_ADDR(win) / 4] = @@ -8901,7 +9162,7 @@ pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); bridgereg_t devreg; - unsigned s; + unsigned long s; /* * Bridge supports hardware swapping; so we can always @@ -8944,7 +9205,7 @@ pciio_slot_t pciio_slot, pciio_priority_t device_prio) { - int s; + unsigned long s; int *counter; bridgereg_t rtbits = 0; bridgereg_t devreg; @@ -8966,9 +9227,9 @@ * XXX- Bug in Rev B Bridge Si: * Symptom: Prefetcher starts operating incorrectly. This happens * due to corruption of the address storage ram in the prefetcher - * when a non-real time pci request is pulled and a real-time one is + * when a non-real time PCI request is pulled and a real-time one is * put in it's place. Workaround: Use only a single arbitration ring - * on pci bus. GBR and RR can still be uniquely used per + * on PCI bus. GBR and RR can still be uniquely used per * device. NETLIST MERGE DONE, WILL BE FIXED IN REV C. */ @@ -8983,18 +9244,12 @@ s = pcibr_lock(pcibr_soft); devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; if (device_prio == PCI_PRIO_HIGH) { -#ifdef IRIX - if (++*counter == 1) -#else if ((++*counter == 1)) { -#endif if (rtbits) devreg |= rtbits; else rc = PRIO_FAIL; -#ifndef IRIX } -#endif } else if (device_prio == PCI_PRIO_LOW) { if (*counter <= 0) rc = PRIO_FAIL; @@ -9082,15 +9337,11 @@ if (set || clr) { bridgereg_t devreg; - unsigned s; + unsigned long s; s = pcibr_lock(pcibr_soft); devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; -#ifdef IRIX - devreg = devreg & ~clr | set; -#else devreg = (devreg & ~clr) | set; -#endif if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { bridge_t *bridge = pcibr_soft->bs_base; @@ -9146,13 +9397,9 @@ pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; - if ( (pcibr_soft_t)0 != pcibr_soft ) { - bridge = pcibr_soft->bs_base; - if ( (bridge_t *)0 != bridge ) { - cfgbase = bridge->b_type0_cfg_dev[pciio_slot].f[pciio_func].l; - } - } + bridge = pcibr_soft->bs_base; + cfgbase = bridge->b_type0_cfg_dev[pciio_slot].f[pciio_func].l; return cfgbase; } @@ -9215,7 +9462,7 @@ case 3: if (reg & 1) { CB(cfgbase, reg) = value; - CS(cfgbase, reg + 1) = value >> 8; + CS(cfgbase, (reg + 1)) = value >> 8; } else { CS(cfgbase, reg) = value; CB(cfgbase, reg + 2) = value >> 16; @@ -9266,6 +9513,16 @@ (pciio_error_devenable_f *) pcibr_error_devenable, (pciio_error_extract_f *) pcibr_error_extract, + +#ifdef LATER + (pciio_driver_reg_callback_f *) pcibr_driver_reg_callback, + (pciio_driver_unreg_callback_f *) pcibr_driver_unreg_callback, +#else + (pciio_driver_reg_callback_f *) 0, + (pciio_driver_unreg_callback_f *) 0, +#endif + (pciio_device_unregister_f *) pcibr_device_unregister, + (pciio_dma_enabled_f *) pcibr_dma_enabled, }; LOCAL pcibr_hints_t @@ -9299,7 +9556,7 @@ return (pcibr_hints_t) ainfo; abnormal_exit: -#ifdef IRIX +#ifdef LATER printf("SHOULD NOT BE HERE\n"); #endif DEL(hint); @@ -9417,12 +9674,7 @@ if (ainfo == (arbitrary_info_t) subdevp) return; DEL(subdevp); -#ifdef IRIX - if (ainfo == NULL) -#else - if (ainfo == (arbitrary_info_t) NULL) -#endif - { + if (ainfo == (arbitrary_info_t) NULL) { #if DEBUG printk("pcibr_hints_subdevs: null subdevs ptr at\n" "\t%p\n", pconn_vhdl); @@ -9438,7 +9690,7 @@ } -#ifdef colin +#ifdef LATER #include <sys/idbg.h> #include <sys/idbgentry.h> @@ -9531,7 +9783,7 @@ pss->bss_d32_base, pss->bss_d32_flags); qprintf("\tExt ATEs active ? %s", - pss->bss_ext_ates_active ? "yes" : "no"); + atomic_read(&pss->bss_ext_ates_active) ? "yes" : "no"); qprintf(" Command register : 0x%x ", pss->bss_cmd_pointer); qprintf(" Shadow command val : 0x%x\n", pss->bss_cmd_shadow); @@ -9559,7 +9811,7 @@ qprintf("Invalid ips %d\n",ips); } -#endif /* colin */ +#endif /* LATER */ int pcibr_dma_enabled(devfs_handle_t pconn_vhdl) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/pciio.c linux.ac/arch/ia64/sn/io/pciio.c --- linux.vanilla/arch/ia64/sn/io/pciio.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/io/pciio.c Tue Apr 10 18:09:56 2001 @@ -14,6 +14,7 @@ #include <linux/config.h> #include <linux/slab.h> #include <asm/sn/sgi.h> +#include <asm/sn/xtalk/xbow.h> /* Must be before iograph.h to get MAX_PORT_NUM */ #include <asm/sn/iograph.h> #include <asm/sn/invent.h> #include <asm/sn/hcl.h> @@ -23,6 +24,7 @@ #include <asm/sn/ioerror_handling.h> #include <asm/sn/pci/pciio.h> #include <asm/sn/pci/pciio_private.h> +#include <asm/sn/sn_sal.h> #define DEBUG_PCIIO #undef DEBUG_PCIIO /* turn this on for yet more console output */ @@ -38,28 +40,30 @@ int badaddr_val(volatile void *addr, int len, volatile void *ptr) { + int ret = 0; + volatile void *new_addr; + switch (len) { - case 4: *(volatile u32*)ptr = *(((volatile u32*)(((u64) addr)^4))); - default: printk("FIXME: argh fix badaddr_val\n"); + case 4: + new_addr = (void *)(((u64) addr)^4); + ret = ia64_sn_probe_io_slot((long)new_addr, len, (void *)ptr); + break; + default: + printk(KERN_WARNING "badaddr_val given len %x but supports len of 4 only\n", len); } - /* no such thing as a bad addr .... */ - return(0); -} + if (ret < 0) + panic("badaddr_val: unexpected status (%d) in probing", ret); + return(ret); -void -cmn_err_tag(int seqnumber, register int level, char *fmt, ...) -{ } + nasid_t get_console_nasid(void) { -#ifdef IRIX + extern nasid_t console_nasid; return console_nasid; -#else - return 0; -#endif } int @@ -208,8 +212,8 @@ void pciio_device_info_free(pciio_info_t); devfs_handle_t pciio_device_info_register(devfs_handle_t, pciio_info_t); void pciio_device_info_unregister(devfs_handle_t, pciio_info_t); -int pciio_device_attach(devfs_handle_t); -int pciio_device_detach(devfs_handle_t); +int pciio_device_attach(devfs_handle_t, int); +int pciio_device_detach(devfs_handle_t, int); void pciio_error_register(devfs_handle_t, error_handler_f *, error_handler_arg_t); int pciio_reset(devfs_handle_t); @@ -234,13 +238,30 @@ pciio_info_t card_info; pciio_provider_t *provider_fns; - card_info = pciio_info_get(dev); - ASSERT(card_info != NULL); + /* + * We're called with two types of vertices, one is + * the bridge vertex (ends with "pci") and the other is the + * pci slot vertex (ends with "pci/[0-8]"). For the first type + * we need to get the provider from the PFUNCS label. For + * the second we get it from fastinfo/c_pops. + */ + provider_fns = pciio_provider_fns_get(dev); + if (provider_fns == NULL) { + card_info = pciio_info_get(dev); + if (card_info != NULL) { + provider_fns = pciio_info_pops_get(card_info); + } + } + + if (provider_fns == NULL) +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_PANIC("%v: provider_fns == NULL", dev); +#else + PRINT_PANIC("0x%x: provider_fns == NULL", dev); +#endif - provider_fns = pciio_info_pops_get(card_info); - ASSERT(provider_fns != NULL); + return provider_fns; - return (provider_fns); } #define DEV_FUNC(dev,func) pciio_to_provider_fns(dev)->func @@ -672,15 +693,21 @@ error_state_t e_state; #endif -#ifdef IRIX #if DEBUG && ERROR_DEBUG - cmn_err(CE_CONT, "%v: pciio_error_handler\n", pciio_vhdl); +#if defined(SUPPORT_PRINTING_V_FORMAT) + printk("%v: pciio_error_handler\n", pciio_vhdl); +#else + printk("0x%x: pciio_error_handler\n", pciio_vhdl); #endif #endif - IOERR_PRINTF(cmn_err(CE_NOTE, - "%v: PCI Bus Error: Error code: %d Error mode: %d\n", +#if defined(SUPPORT_PRINTING_V_FORMAT) + IOERR_PRINTF(printk("%v: PCI Bus Error: Error code: %d Error mode: %d\n", pciio_vhdl, error_code, mode)); +#else + IOERR_PRINTF(printk("0x%x: PCI Bus Error: Error code: %d Error mode: %d\n", + pciio_vhdl, error_code, mode)); +#endif /* If there is an error handler sitting on * the "no-slot" connection point, give it @@ -715,7 +742,7 @@ * widgetdev is a 4byte value encoded as slot in the higher order * 2 bytes and function in the lower order 2 bytes. */ -#ifdef IRIX +#ifdef LATER slot = pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioerror, widgetdev)); #else slot = 0; @@ -732,9 +759,12 @@ #if defined(CONFIG_SGI_IO_ERROR_HANDLING) e_state = error_state_get(pciio_vhdl); + if (e_state == ERROR_STATE_ACTION) (void)error_state_set(pciio_vhdl, ERROR_STATE_NONE); + + if (error_state_set(pconn_vhdl,e_state) == ERROR_RETURN_CODE_CANNOT_SET_STATE) return(IOERROR_UNHANDLED); @@ -825,12 +855,18 @@ ASSERT((desired_end == PCIDMA_ENDIAN_BIG) || (desired_end == PCIDMA_ENDIAN_LITTLE)); #if DEBUG - cmn_err(CE_ALERT, - "%v: pciio_endian_set is going away.\n" +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_ALERT("%v: pciio_endian_set is going away.\n" + "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n" + "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n", + dev); +#else + PRINT_ALERT("0x%x: pciio_endian_set is going away.\n" "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n" "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n", dev); #endif +#endif return DEV_FUNC(dev, endian_set) (dev, device_end, desired_end); @@ -1027,8 +1063,6 @@ (pciio_info->c_fingerprint != pciio_info_fingerprint)) { #endif /* BRINGUP */ - printk("pciio_info_get: Found fastinfo 0x%p but wrong fingerprint %s\n", pciio_info, - pciio_info->c_fingerprint); return((pciio_info_t)-1); /* Should panic .. */ } @@ -1198,7 +1232,11 @@ pciio_attach(devfs_handle_t pciio) { #if DEBUG && ATTACH_DEBUG - cmn_err(CE_CONT, "%v: pciio_attach\n", pciio); +#if defined(SUPPORT_PRINTING_V_FORMAT) + printk("%v: pciio_attach\n", pciio); +#else + printk("0x%x: pciio_attach\n", pciio); +#endif #endif return 0; } @@ -1220,11 +1258,7 @@ { arbitrary_info_t ainfo; -#ifdef IRIX - hwgraph_info_remove_LBL(provider, INFO_LBL_PFUNCS, &ainfo); -#else hwgraph_info_remove_LBL(provider, INFO_LBL_PFUNCS, (long *) &ainfo); -#endif } /* @@ -1258,7 +1292,7 @@ return cdl_add_driver(pciio_registry, vendor_id, device_id, - driver_prefix, flags); + driver_prefix, flags, NULL); } /* @@ -1274,7 +1308,33 @@ */ ASSERT(pciio_registry != NULL); - cdl_del_driver(pciio_registry, driver_prefix); + cdl_del_driver(pciio_registry, driver_prefix, NULL); +} + +/* + * Set the slot status for a device supported by the + * driver being registered. + */ +void +pciio_driver_reg_callback( + devfs_handle_t pconn_vhdl, + int key1, + int key2, + int error) +{ +} + +/* + * Set the slot status for a device supported by the + * driver being unregistered. + */ +void +pciio_driver_unreg_callback( + devfs_handle_t pconn_vhdl, + int key1, + int key2, + int error) +{ } /* @@ -1307,7 +1367,6 @@ pciio_vendor_id_t vendor_id, pciio_device_id_t device_id) { - return pciio_device_info_register (connectpt, pciio_device_info_new (NULL, master, slot, func, vendor_id, device_id)); @@ -1366,8 +1425,6 @@ pciio_info->c_slot, pciio_info->c_func); - printk("pciio_device_info_register: connectpt 0x%p, pciio_info 0x%p\n", connectpt, pciio_info); - if (GRAPH_SUCCESS != hwgraph_path_add(connectpt, name, &pconn)) return pconn; @@ -1379,7 +1436,9 @@ int pos; char dname[256]; pos = devfs_generate_path(pconn, dname, 256); +#ifdef DEBUG_PCIIO printk("%s : pconn path= %s \n", __FUNCTION__, &dname[pos]); +#endif } #endif /* BRINGUP */ @@ -1421,6 +1480,7 @@ /* Remove the link to our pci provider */ hwgraph_edge_remove(pconn, EDGE_LBL_MASTER, NULL); + hwgraph_vertex_unref(pconn); hwgraph_vertex_destroy(pconn); @@ -1447,18 +1507,21 @@ static void pciio_device_inventory_remove(devfs_handle_t pconn_vhdl) { -#ifdef IRIX +#ifdef LATER hwgraph_inventory_remove(pconn_vhdl,-1,-1,-1,-1,-1); #endif } /*ARGSUSED */ int -pciio_device_attach(devfs_handle_t pconn) +pciio_device_attach(devfs_handle_t pconn, + int drv_flags) { pciio_info_t pciio_info; pciio_vendor_id_t vendor_id; pciio_device_id_t device_id; + int pciba_attach(devfs_handle_t); + pciio_device_inventory_add(pconn); pciio_info = pciio_info_get(pconn); @@ -1466,8 +1529,6 @@ vendor_id = pciio_info->c_vendor; device_id = pciio_info->c_device; - printk("pciio_device_attach: Function 0x%p, vendor 0x%x, device_id %x\n", pconn, vendor_id, device_id); - /* we don't start attaching things until * all the driver init routines (including * pciio_init) have been called; so we @@ -1475,12 +1536,17 @@ */ ASSERT(pciio_registry != NULL); - return(cdl_add_connpt(pciio_registry, vendor_id, device_id, pconn)); + /* + * Since pciba is not called from cdl routines .. call it here. + */ + pciba_attach(pconn); + return(cdl_add_connpt(pciio_registry, vendor_id, device_id, pconn, drv_flags)); } int -pciio_device_detach(devfs_handle_t pconn) +pciio_device_detach(devfs_handle_t pconn, + int drv_flags) { pciio_info_t pciio_info; pciio_vendor_id_t vendor_id; @@ -1499,10 +1565,9 @@ */ ASSERT(pciio_registry != NULL); - cdl_del_connpt(pciio_registry, vendor_id, device_id, pconn); + return(cdl_del_connpt(pciio_registry, vendor_id, device_id, + pconn, drv_flags)); - return(0); - } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/sgi_if.c linux.ac/arch/ia64/sn/io/sgi_if.c --- linux.vanilla/arch/ia64/sn/io/sgi_if.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/sgi_if.c Tue Apr 10 18:09:56 2001 @@ -21,8 +21,6 @@ #include <asm/sn/pci/pciio.h> #include <asm/sn/slotnum.h> -#define spinlock_init(x,name) mutex_init(x, MUTEX_DEFAULT, name); - void * kmem_zalloc(size_t size, int flag) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/sgi_io_init.c linux.ac/arch/ia64/sn/io/sgi_io_init.c --- linux.vanilla/arch/ia64/sn/io/sgi_io_init.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/io/sgi_io_init.c Tue Apr 10 18:12:08 2001 @@ -79,13 +79,8 @@ void sgi_master_io_infr_init(void) { -#ifdef Colin - /* - * Simulate Big Window 0. - * Only when we build for lutsen etc. .. - */ - simulated_BW0_init(); -#endif + int cnode; + extern int maxnodes; /* * Do any early init stuff .. einit_tbl[] etc. @@ -122,7 +117,9 @@ sn_mp_setup(); DBG("--> sgi_master_io_infr_init: calling per_hub_init(0).\n"); - per_hub_init(0); /* Need to get and send in actual cnode number */ + for (cnode = 0; cnode < maxnodes; cnode++) { + per_hub_init(cnode); + } /* We can do headless hub cnodes here .. */ @@ -188,7 +185,7 @@ /* Emulate cboot() .. */ mlreset(1); /* This is a slave cpu */ - per_hub_init(0); /* Need to get and send in actual cnode number */ + // per_hub_init(0); /* Need to get and send in actual cnode number */ /* Done */ } @@ -212,12 +209,8 @@ * do not currently support yet .. just a hack for now. */ #ifdef NUMA_BASE - DBG("sn_mp_setup(): maxnodes= %d numnodes= %d\n", maxnodes,numnodes); maxnodes = numnodes; -#ifdef SIMULATED_KLGRAPH - maxnodes = 1; - numnodes = 1; -#endif /* SIMULATED_KLGRAPH */ + DBG("sn_mp_setup(): maxnodes= %d numnodes= %d\n", maxnodes,numnodes); printk("sn_mp_setup(): Allocating backing store for *Nodepdaindr[%2d] \n", maxnodes); @@ -259,6 +252,14 @@ * ml/SN/promif.c */ +#ifdef CONFIG_IA64_SGI_SN1 + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + /* Skip holes in CPU space */ + if (cpu_enabled(cpu)) { + init_platform_pda(cpu); + } + } +#endif for (cnode = 0; cnode < maxnodes; cnode++) { /* * Set up platform-dependent nodepda fields. @@ -267,29 +268,7 @@ */ DBG("sn_mp_io_setup: calling init_platform_nodepda(%2d)\n",cnode); init_platform_nodepda(Nodepdaindr[cnode], cnode); - - /* - * This routine clears the Hub's Interrupt registers. - */ -#ifndef CONFIG_IA64_SGI_IO - /* - * We need to move this intr_clear_all() routine - * from SN/intr.c to a more appropriate file. - * Talk to Al Mayer. - */ - intr_clear_all(COMPACT_TO_NASID_NODEID(cnode)); -#endif } - -#ifdef CONFIG_IA64_SGI_IO - for (cpu = 0; cpu < smp_num_cpus; cpu++) { - /* Skip holes in CPU space */ - if (cpu_enabled(cpu)) { - init_platform_pda(cpu); - } - } -#endif - /* * Initialize platform-dependent vertices in the hwgraph: * module @@ -309,4 +288,26 @@ klhwg_add_all_modules(hwgraph_root); DBG("sn_mp_setup: calling klhwg_add_all_nodes()\n"); klhwg_add_all_nodes(hwgraph_root); + + + for (cnode = 0; cnode < maxnodes; cnode++) { + + /* + * This routine clears the Hub's Interrupt registers. + */ +#ifdef CONFIG_IA64_SGI_SN1 + /* + * We need to move this intr_clear_all() routine + * from SN/intr.c to a more appropriate file. + * Talk to Al Mayer. + */ + intr_clear_all(COMPACT_TO_NASID_NODEID(cnode)); + /* now init the hub */ + // per_hub_init(cnode); +#endif + } + +#if defined(CONFIG_IA64_SGI_SYNERGY_PERF) + synergy_perf_init(); +#endif /* CONFIG_IA64_SGI_SYNERGY_PERF */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/sgi_io_sim.c linux.ac/arch/ia64/sn/io/sgi_io_sim.c --- linux.vanilla/arch/ia64/sn/io/sgi_io_sim.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/sgi_io_sim.c Tue Apr 10 18:12:08 2001 @@ -17,9 +17,6 @@ #include <asm/sn/sn_private.h> #include <asm/sn/synergy.h> -cnodeid_t nasid_to_compact_node[MAX_NASIDS]; -nasid_t compact_to_nasid_node[MAX_COMPACT_NODES]; -cnodeid_t cpuid_to_compact_node[MAXCPUS]; cpuid_t master_procid = 0; int maxnodes; char arg_maxnodes[4]; @@ -42,12 +39,6 @@ return (strlen(s) != 0); } - -void pciba_init(void) -{ - FIXME("pciba_init : no-op\n"); -} - void xbmon_init(void) { FIXME("xbmon_init : no-op\n"); @@ -82,7 +73,7 @@ * Routines provided by ml/SN/promif.c. */ static __psunsigned_t master_bridge_base = (__psunsigned_t)NULL; -static nasid_t console_nasid; +nasid_t console_nasid; static char console_wid; static char console_pcislot; @@ -90,19 +81,12 @@ set_master_bridge_base(void) { -#ifdef SIMULATED_KLGRAPH - printk("set_master_bridge_base: SIMULATED_KLGRAPH FIXME hardwired master.\n"); - console_nasid = 0; - console_wid = 0x8; - console_pcislot = 0x2; -#else console_nasid = KL_CONFIG_CH_CONS_INFO(master_nasid)->nasid; console_wid = WIDGETID_GET(KL_CONFIG_CH_CONS_INFO(master_nasid)->memory_base); console_pcislot = KL_CONFIG_CH_CONS_INFO(master_nasid)->npci; -#endif /* SIMULATED_KLGRAPH */ - master_bridge_base = (__psunsigned_t)NODE_SWIN_BASE(console_nasid, console_wid); + FIXME("WARNING: set_master_bridge_base: NON NASID 0 DOES NOT WORK\n"); } int @@ -133,21 +117,6 @@ } else { return 0; } -} - -cnodeid_t -nasid_to_compact_nodeid(nasid_t nasid) -{ - ASSERT(nasid >= 0 && nasid < MAX_NASIDS); - return nasid_to_compact_node[nasid]; -} - -nasid_t -compact_to_nasid_nodeid(cnodeid_t cnode) -{ - ASSERT(cnode >= 0 && cnode <= MAX_COMPACT_NODES); - ASSERT(compact_to_nasid_node[cnode] >= 0); - return compact_to_nasid_node[cnode]; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/stubs.c linux.ac/arch/ia64/sn/io/stubs.c --- linux.vanilla/arch/ia64/sn/io/stubs.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/stubs.c Tue Apr 10 18:12:08 2001 @@ -31,8 +31,6 @@ int force_fire_and_forget; int ignore_conveyor_override; -#define spinlock_init(x,name) mutex_init(x, MUTEX_DEFAULT, name); - devfs_handle_t dummy_vrtx; /* Needed for cpuid_to_vertex() in hack.h */ @@ -105,32 +103,6 @@ return((zone_t *)0); } -uint64_t -rmalloc(struct map *mp, size_t size) -{ - FIXME("rmalloc : returns NULL"); - return((uint64_t)0); -} - -void -rmfree(struct map *mp, size_t size, uint64_t a) -{ - FIXME("rmfree : no-op"); -} - -struct map * -rmallocmap(uint64_t mapsiz) -{ - FIXME("rmallocmap : returns NULL"); - return((struct map *)0); -} - -void -rmfreemap(struct map *mp) -{ - FIXME("rmfreemap : no-op"); -} - int compare_and_swap_ptr(void **location, void *old_ptr, void *new_ptr) { @@ -170,40 +142,6 @@ ioc3_console_vhdl_get(void) {FIXME("ioc3_console_vhdl_get"); return( (devfs_handle_t)-1);} - -#if 0 -#define io_splock(l) 1 -#define io_spunlock(l,s) - -#define spinlock_destroy(a) /* needed by pcibr_detach() */ -#define mutex_spinlock(a) 0 -#define mutex_spinunlock(a,b) -#define mutex_init(a,b,c) ; -#define mutex_lock(a,b) ; -#define mutex_unlock(a) ; -#define dev_to_vhdl(dev) 0 -#define get_timestamp() 0 -#define us_delay(a) -#define v_mapphys(a,b,c) 0 -#define splhi() 0 -#define splx(s) -#define spinlock_init(x,name) mutex_init(x, MUTEX_DEFAULT, name); -#endif /* 0 */ - -int -cap_able(uint64_t x) -{ - FIXME("cap_able : returns 1"); - return(1); -} - -int -cap_able_cred(uint64_t a, uint64_t b) -{ - FIXME("cap_able_cred : returns 1"); - return(1); -} - void nic_vmc_check(devfs_handle_t vhdl, char *nicinfo) { @@ -236,21 +174,5 @@ uint64_t value) { FIXME("vector_write_node\n"); - return(0); -} - -int -atomicAddInt(int *int_ptr, int value) -{ -// FIXME("atomicAddInt : simple add\n"); - *int_ptr += value; - return(0); -} - -int -atomicClearInt(int *int_ptr, int value) -{ - FIXME("atomicClearInt : simple clear\n"); - *int_ptr &= ~value; return(0); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/xbow.c linux.ac/arch/ia64/sn/io/xbow.c --- linux.vanilla/arch/ia64/sn/io/xbow.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/ia64/sn/io/xbow.c Sat Apr 14 01:18:00 2001 @@ -9,7 +9,6 @@ */ #include <linux/types.h> -#include <linux/config.h> #include <linux/slab.h> #include <linux/sched.h> #include <asm/sn/sgi.h> @@ -17,19 +16,18 @@ #include <asm/sn/invent.h> #include <asm/sn/hcl.h> #include <asm/sn/labelcl.h> +#include <asm/sn/hack.h> #include <asm/sn/pci/bridge.h> #include <asm/sn/xtalk/xtalk_private.h> -#define DEBUG 1 -#define XBOW_DEBUG 1 +/* #define DEBUG 1 */ +/* #define XBOW_DEBUG 1 */ /* * Files needed to get the device driver entry points */ -/* #include <asm/cred.h> */ - #include <asm/sn/xtalk/xbow.h> #include <asm/sn/xtalk/xtalk.h> #include <asm/sn/xtalk/xswitch.h> @@ -66,7 +64,7 @@ xbow_perf_t xbow_perfcnt[XBOW_PERF_COUNTERS]; xbow_perf_link_t xbow_perflink[MAX_XBOW_PORTS]; xbow_link_status_t xbow_link_status[MAX_XBOW_PORTS]; - lock_t xbow_perf_lock; + spinlock_t xbow_perf_lock; int link_monitor; widget_cfg_t *wpio[MAX_XBOW_PORTS]; /* cached PIO pointer */ @@ -74,7 +72,7 @@ * destination port since contention happens there. * Implicit mapping from xbow ports (8..f) -> (0..7) array indices. */ - lock_t xbow_bw_alloc_lock; /* bw allocation lock */ + spinlock_t xbow_bw_alloc_lock; /* bw allocation lock */ unsigned long long bw_hiwm[MAX_XBOW_PORTS]; /* hiwater mark values */ unsigned long long bw_cur_used[MAX_XBOW_PORTS]; /* bw used currently */ }; @@ -118,15 +116,8 @@ int xbow_disable_llp_monitor(devfs_handle_t); int xbow_enable_llp_monitor(devfs_handle_t); - -#ifdef IRIX -int xbow_prio_bw_alloc(devfs_handle_t, xwidgetnum_t, xwidgetnum_t, - unsigned long long, unsigned long long); -#else int xbow_prio_bw_alloc(devfs_handle_t, xwidgetnum_t, xwidgetnum_t, unsigned long long, unsigned long long); -#endif - xswitch_reset_link_f xbow_reset_link; @@ -237,7 +228,11 @@ int xbow_num; #if DEBUG && ATTACH_DEBUG - cmn_err(CE_CONT, "%v: xbow_attach\n", conn); +#if defined(SUPPORT_PRINTING_V_FORMAT + printk("%v: xbow_attach\n", conn); +#else + printk("0x%x: xbow_attach\n", conn); +#endif #endif /* @@ -261,7 +256,9 @@ * of our connection point. */ busv = hwgraph_connectpt_get(conn); +#if DEBUG && ATTACH_DEBUG printk("xbow_attach: Bus Vertex 0x%p, conn 0x%p, xbow register 0x%p wid= 0x%x\n", busv, conn, xbow, *(volatile u32 *)xbow); +#endif ASSERT(busv != GRAPH_VERTEX_NONE); @@ -283,8 +280,7 @@ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, /* &hcl_fops */ (void *)&vhdl, NULL); if (!vhdl) { - printk("xbow_attach: Unable to create char device for xbow conn -0x%p\n", + printk(KERN_WARNING "xbow_attach: Unable to create char device for xbow conn %p\n", conn); } @@ -306,11 +302,7 @@ /* Add xbow number as a suffix to the hwgraph name of the xbow. * This is helpful while looking at the error/warning messages. */ -#if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC xbow_num = 0; -#else - xbow_num = xswitch_id_get(busv); -#endif /* * get the name of this xbow vertex and keep the info. @@ -341,7 +333,7 @@ * Crossbow is DOWNREV: these chips are not good * to have around, and the operator should be told. */ -#ifdef IRIX +#ifdef LATER #if !DEBUG if ( #if SHOW_REVS @@ -349,8 +341,7 @@ #endif /* SHOW_REVS */ (rev < XBOW_REV_1_1)) #endif /* !DEBUG */ - cmn_err((rev < XBOW_REV_1_1) ? CE_WARN : CE_CONT, - "%sCrossbow ASIC: rev %s (code=%d) at %s%s", + printk("%sCrossbow ASIC: rev %s (code=%d) at %s%s", (rev < XBOW_REV_1_1) ? "DOWNREV " : "", (rev == XBOW_REV_1_0) ? "1.0" : (rev == XBOW_REV_1_1) ? "1.1" : @@ -362,14 +353,13 @@ "unknown", rev, soft->name, (rev < XBOW_REV_1_1) ? "" : "\n"); -#endif /* IRIX */ - - spinlock_init(&soft->xbow_perf_lock, "xbow_perf_lock"); +#endif /* LATER */ + mutex_spinlock_init(&soft->xbow_perf_lock); soft->xbow_perfcnt[0].xp_perf_reg = &xbow->xb_perf_ctr_a; soft->xbow_perfcnt[1].xp_perf_reg = &xbow->xb_perf_ctr_b; /* Initialization for GBR bw allocation */ - spinlock_init(&soft->xbow_bw_alloc_lock, "xbow_bw_alloc_lock"); + mutex_spinlock_init(&soft->xbow_bw_alloc_lock); #define XBOW_8_BIT_PORT_BW_MAX (400 * 1000 * 1000) /* 400 MB/s */ #define XBOW_16_BIT_PORT_BW_MAX (800 * 1000 * 1000) /* 800 MB/s */ @@ -403,7 +393,7 @@ xwidget_error_register(conn, xbow_error_handler, soft); #else - printk("xbow_attach: Fixme: we bypassed attaching xbow error interrupt.\n"); + FIXME("xbow_attach: Fixme: we bypassed attaching xbow error interrupt.\n"); #endif /* LATER */ /* @@ -479,8 +469,6 @@ int xbow_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp) { - if (!_CAP_CRABLE((uint64_t)credp, CAP_DEVICE_MGT)) - return EPERM; return 0; } @@ -525,28 +513,9 @@ char devname[MAXDEVNAME]; xwidget_info_t xwidget_info; int i; -#if IP27 - cnodeid_t cnodeid = CNODEID_NONE; -#endif vertex_to_name(dev, devname, MAXDEVNAME); -#if IP30 - /* If there is a ".connection" edge from this vertex, - * then it must be "/hw/node" vertex. Return the widget - * number for heart: 8. - */ - if (hwgraph_edge_get(dev, EDGE_LBL_CONN, &tdev) == - GRAPH_SUCCESS) { - return ((xwidgetnum_t) 8); - } -#elif IP27 - if ((cnodeid = nodevertex_to_cnodeid(dev)) != CNODEID_NONE) { - ASSERT(cnodeid < maxnodes); - return(hub_widget_id(COMPACT_TO_NASID_NODEID(cnodeid))); - } -#endif - /* If this is a pci controller vertex, traverse up using * the ".." links to get to the widget. */ @@ -601,7 +570,7 @@ ASSERT_ALWAYS(rc != 0); #endif switch (cmd) { -#ifdef IRIX +#ifdef LATER case XBOWIOC_PERF_ENABLE: case XBOWIOC_PERF_DISABLE: { @@ -630,7 +599,7 @@ } #endif -#ifdef IRIX +#ifdef LATER case XBOWIOC_PERF_GET: { xbow_perf_link_t *xbow_perf_cnt; @@ -652,10 +621,6 @@ #endif case XBOWIOC_LLP_ERROR_ENABLE: - if (!_CAP_CRABLE((uint64_t)cr, CAP_DEVICE_MGT)) { - error = EPERM; - break; - } if ((error = xbow_enable_llp_monitor(vhdl)) != 0) error = EINVAL; @@ -663,16 +628,12 @@ case XBOWIOC_LLP_ERROR_DISABLE: - if (!_CAP_CRABLE((uint64_t)cr, CAP_DEVICE_MGT)) { - error = EPERM; - break; - } if ((error = xbow_disable_llp_monitor(vhdl)) != 0) error = EINVAL; break; -#ifdef IRIX +#ifdef LATER case XBOWIOC_LLP_ERROR_GET: { xbow_link_status_t *xbow_llp_status; @@ -693,17 +654,12 @@ } #endif -#ifdef IRIX +#ifdef LATER case GIOCSETBW: { grio_ioctl_info_t info; xwidgetnum_t src_widgetnum, dest_widgetnum; - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) { error = EFAULT; break; @@ -863,14 +819,14 @@ xbow->xb_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); } -#define XEM_ADD_STR(s) cmn_err(CE_CONT, "%s", (s)) -#define XEM_ADD_NVAR(n,v) cmn_err(CE_CONT, "\t%20s: 0x%x\n", (n), (v)) +#define XEM_ADD_STR(s) printk("%s", (s)) +#define XEM_ADD_NVAR(n,v) printk("\t%20s: 0x%x\n", (n), (v)) #define XEM_ADD_VAR(v) XEM_ADD_NVAR(#v,(v)) #define XEM_ADD_IOEF(n) if (IOERROR_FIELDVALID(ioe,n)) \ XEM_ADD_NVAR("ioe." #n, \ IOERROR_GETVALUE(ioe,n)) -#ifdef IRIX +#ifdef LATER static void xem_add_ioe(ioerror_t *ioe) { @@ -891,7 +847,7 @@ } #define XEM_ADD_IOE() (xem_add_ioe(ioe)) -#endif /* IRIX */ +#endif /* LATER */ int xbow_xmit_retry_errors = 0; @@ -971,7 +927,6 @@ static void xbow_errintr_handler(intr_arg_t arg) { -#ifdef IRIX ioerror_t ioe[1]; xbow_soft_t soft = (xbow_soft_t) arg; xbow_t *xbow = soft->base; @@ -1065,9 +1020,8 @@ xwidget_vhdl = xbow_widget_lookup(soft->busv,port); xwidget_name = xwidget_name_get(xwidget_vhdl); -#ifdef IRIX - cmn_err(CE_CONT, - "%s port %X[%s] XIO Bus Error", +#ifdef LATER + printk("%s port %X[%s] XIO Bus Error", soft->name, port, xwidget_name); if (link_status & XB_STAT_MULTI_ERR) XEM_ADD_STR("\tMultiple Errors\n"); @@ -1089,8 +1043,7 @@ XEM_ADD_STR("\tMaximum Request Timeout\n"); if (link_status & XB_STAT_SRC_TOUT_ERR) XEM_ADD_STR("\tSource Timeout Error\n"); -#endif - +#endif /* LATER */ { int other_port; @@ -1130,8 +1083,7 @@ | XB_WID_STAT_XTALK_ERR | XB_WID_STAT_REG_ACC_ERR)) { - cmn_err(CE_CONT, - "%s Port 0 XIO Bus Error", + printk("%s Port 0 XIO Bus Error", soft->name); if (wid_stat & XB_WID_STAT_MULTI_ERR) XEM_ADD_STR("\tMultiple Error\n"); @@ -1150,9 +1102,8 @@ XEM_ADD_VAR(wid_err_upper); XEM_ADD_VAR(wid_err_lower); XEM_ADD_VAR(wid_err_addr); - cmn_err_tag(8, CE_PANIC, "XIO Bus Error"); + PRINT_PANIC("XIO Bus Error"); } -#endif } #endif /* LATER */ @@ -1180,7 +1131,6 @@ ioerror_mode_t mode, ioerror_t *ioerror) { -#ifdef IRIX int retval = IOERROR_WIDGETLEVEL; xbow_soft_t soft = (xbow_soft_t) einfo; @@ -1204,7 +1154,7 @@ busv = soft->busv; #if DEBUG && ERROR_DEBUG - cmn_err(CE_CONT, "%s: xbow_error_handler\n", soft->name, busv); + printk("%s: xbow_error_handler\n", soft->name, busv); #endif port = IOERROR_GETVALUE(ioerror, widgetnum); @@ -1217,14 +1167,12 @@ return IOERROR_HANDLED; if (error_code & IOECODE_DMA) { - cmn_err(CE_ALERT, - "DMA error blamed on Crossbow at %s\n" + PRINT_ALERT("DMA error blamed on Crossbow at %s\n" "\tbut Crosbow never initiates DMA!", soft->name); } if (error_code & IOECODE_PIO) { - cmn_err(CE_ALERT, - "PIO Error on XIO Bus %s\n" + PRINT_ALERt("PIO Error on XIO Bus %s\n" "\tattempting to access XIO controller\n" "\twith offset 0x%X", soft->name, @@ -1258,14 +1206,12 @@ return IOERROR_HANDLED; if (error_code & IOECODE_DMA) { - cmn_err(CE_ALERT, - "DMA error blamed on XIO port at %s/%d\n" + PRINT_ALERT("DMA error blamed on XIO port at %s/%d\n" "\tbut Crossbow does not support that port", soft->name, port); } if (error_code & IOECODE_PIO) { - cmn_err(CE_ALERT, - "PIO Error on XIO Bus %s\n" + PRINT_ALERT("PIO Error on XIO Bus %s\n" "\tattempting to access XIO port %d\n" "\t(which Crossbow does not support)" "\twith offset 0x%X", @@ -1309,14 +1255,12 @@ return IOERROR_HANDLED; if (error_code & IOECODE_DMA) { - cmn_err(CE_ALERT, - "DMA error blamed on XIO port at %s/%d\n" + PRINT_ALERT("DMA error blamed on XIO port at %s/%d\n" "\tbut there is no device connected there.", soft->name, port); } if (error_code & IOECODE_PIO) { - cmn_err(CE_ALERT, - "PIO Error on XIO Bus %s\n" + PRINT_ALERT("PIO Error on XIO Bus %s\n" "\tattempting to access XIO port %d\n" "\t(which has no device connected)" "\twith offset 0x%X", @@ -1349,16 +1293,14 @@ if (mode == MODE_DEVPROBE) return IOERROR_HANDLED; - cmn_err(CE_ALERT, - "%s%sError on XIO Bus %s port %d", + PRINT_ALERT("%s%sError on XIO Bus %s port %d", (error_code & IOECODE_DMA) ? "DMA " : "", (error_code & IOECODE_PIO) ? "PIO " : "", soft->name, port); if ((error_code & IOECODE_PIO) && (IOERROR_FIELDVALID(ioerror, xtalkaddr))) { - cmn_err(CE_CONT, - "\tAccess attempted to offset 0x%X\n", + printk("\tAccess attempted to offset 0x%X\n", IOERROR_GETVALUE(ioerror, xtalkaddr)); } if (link_aux_status & XB_AUX_LINKFAIL_RST_BAD) @@ -1393,16 +1335,14 @@ if (retval == IOERROR_UNHANDLED) { retval = IOERROR_PANIC; - cmn_err(CE_ALERT, - "%s%sError on XIO Bus %s port %d", + PRINT_ALERT("%s%sError on XIO Bus %s port %d", (error_code & IOECODE_DMA) ? "DMA " : "", (error_code & IOECODE_PIO) ? "PIO " : "", soft->name, port); if ((error_code & IOECODE_PIO) && (IOERROR_FIELDVALID(ioerror, xtalkaddr))) { - cmn_err(CE_CONT, - "\tAccess attempted to offset 0x%X\n", + printk("\tAccess attempted to offset 0x%X\n", IOERROR_GETVALUE(ioerror, xtalkaddr)); } } @@ -1428,7 +1368,6 @@ */ return retval; -#endif /* IRIX */ } #endif /* LATER */ @@ -1440,7 +1379,8 @@ xbow_perf_t *xbow_perf = xbow_soft->xbow_perfcnt; xbow_perf_link_t *xbow_plink = xbow_soft->xbow_perflink; xbow_perfcount_t perf_reg; - int link, s, i; + unsigned long s; + int link, i; for (i = 0; i < XBOW_PERF_COUNTERS; i++, xbow_perf++) { if (xbow_perf->xp_mode == XBOW_MONITOR_NONE) @@ -1460,7 +1400,7 @@ } /* Do port /mode multiplexing here */ -#ifdef IRIX +#ifdef LATER (void) timeout(xbow_update_perf_counters, (void *) (__psunsigned_t) vhdl, XBOW_PERF_TIMEOUT); #endif @@ -1484,7 +1424,8 @@ xbow_linkctrl_t xbow_link_ctrl; xbow_t *xbow = xbow_soft->base; xbow_perfcount_t perf_reg; - int s, i; + unsigned long s; + int i; link -= BASE_XBOW_PORT; if ((link < 0) || (link >= MAX_XBOW_PORTS)) @@ -1525,7 +1466,7 @@ *(xbowreg_t *) xbow_perf->xp_perf_reg = perf_reg.xb_counter_val; xbow_perf->xp_current = perf_reg.xb_perf.count; -#ifdef IRIX +#ifdef LATER (void) timeout(xbow_update_perf_counters, (void *) (__psunsigned_t) vhdl, XBOW_PERF_TIMEOUT); #endif @@ -1578,13 +1519,13 @@ aux_sts.xb_aux_linkstatus.tx_retry_cnt; if (lnk_sts.linkstatus & ~(XB_STAT_RCV_ERR | XB_STAT_XMT_RTRY_ERR | XB_STAT_LINKALIVE)) { -#ifdef IRIX - cmn_err(CE_WARN, "link %d[%s]: bad status 0x%x\n", +#ifdef LATER + PRINT_WARNING("link %d[%s]: bad status 0x%x\n", link, xwidget_name, lnk_sts.linkstatus); #endif } } -#ifdef IRIX +#ifdef LATER if (xbow_soft->link_monitor) (void) timeout(xbow_update_llp_status, (void *) (__psunsigned_t) vhdl, XBOW_STATS_TIMEOUT); @@ -1611,7 +1552,7 @@ { xbow_soft_t xbow_soft = xbow_soft_get(vhdl); -#ifdef IRIX +#ifdef LATER (void) timeout(xbow_update_llp_status, (void *) (__psunsigned_t) vhdl, XBOW_STATS_TIMEOUT); #endif @@ -1690,7 +1631,7 @@ int i; xb_linkregs_t *link; -#ifdef IRIX +#ifdef LATER if (dev_is_vertex((devfs_handle_t) regs)) { devfs_handle_t vhdl = (devfs_handle_t) regs; xbow_soft_t soft = xbow_soft_get(vhdl); @@ -1702,7 +1643,7 @@ xbow = (xbow_t *) regs; } -#ifdef IRIX +#ifdef LATER qprintf("Printing xbow registers starting at 0x%x\n", xbow); qprintf("wid %x status %x erruppr %x errlower %x control %x timeout %x\n", xbow->xb_wid_id, xbow->xb_wid_stat, xbow->xb_wid_err_upper, @@ -1716,7 +1657,7 @@ for (i = 8; i <= 0xf; i++) { link = &xbow->xb_link(i); -#ifdef IRIX +#ifdef LATER qprintf("Link %d registers\n", i); qprintf("\tctrl %x stat %x arbuppr %x arblowr %x auxstat %x\n", link->link_control, link->link_status, @@ -1795,7 +1736,7 @@ xbow_soft_t soft = xbow_soft_get(vhdl); volatile xbowreg_t *xreg; xbowreg_t mask; - int s; + unsigned long s; int error = 0; bandwidth_t old_bw_BYTES, req_bw_BYTES; xbowreg_t old_xreg; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/xswitch.c linux.ac/arch/ia64/sn/io/xswitch.c --- linux.vanilla/arch/ia64/sn/io/xswitch.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/xswitch.c Tue Apr 10 18:12:08 2001 @@ -88,13 +88,15 @@ xswitch_info = (xswitch_info_t) hwgraph_fastinfo_get(xwidget); -#ifdef IRIX +#ifdef LATER if ((xswitch_info != NULL) && (xswitch_info->fingerprint != xswitch_info_fingerprint)) - cmn_err(CE_PANIC, "%v xswitch_info_get bad fingerprint", xwidget); +#ifdef SUPPORT_PRINTING_V_FORMAT + PRINT_PANIC("%v xswitch_info_get bad fingerprint", xwidget); +#else + PRINT_PANIC("%x xswitch_info_get bad fingerprint", xwidget); #endif - - printk("xswitch_info_get: xwidget 0x%p xswitch_info 0x%p\n", xwidget, xswitch_info); +#endif /* LATER */ return (xswitch_info); } @@ -118,9 +120,9 @@ xswitch_info_vhdl_get(xswitch_info_t xswitch_info, xwidgetnum_t port) { -#ifdef IRIX +#ifdef LATER if (xswitch_info == NULL) - cmn_err(CE_PANIC, "xswitch_info_vhdl_get: null xswitch_info"); + PRINT_PANIC("xswitch_info_vhdl_get: null xswitch_info"); #endif #if XSWITCH_CENSUS_PORT_MIN @@ -196,8 +198,6 @@ GRAPH_VERTEX_NONE); } xswitch_info_set(xwidget, xswitch_info); - printk("xswitch_info_new: xswitch_info_set xwidget 0x%p, xswitch_info 0x%p\n", - xwidget, xswitch_info); } return xswitch_info; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/xtalk.c linux.ac/arch/ia64/sn/io/xtalk.c --- linux.vanilla/arch/ia64/sn/io/xtalk.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/ia64/sn/io/xtalk.c Sat Apr 14 01:18:00 2001 @@ -9,7 +9,6 @@ */ #include <linux/types.h> -#include <linux/config.h> #include <linux/slab.h> #include <asm/sn/sgi.h> #include <asm/sn/iobus.h> @@ -71,6 +70,7 @@ void xtalk_dmaaddr_drain(devfs_handle_t, iopaddr_t, size_t); void xtalk_dmalist_drain(devfs_handle_t, alenlist_t); xtalk_intr_t xtalk_intr_alloc(devfs_handle_t, device_desc_t, devfs_handle_t); +xtalk_intr_t xtalk_intr_alloc_nothd(devfs_handle_t, device_desc_t, devfs_handle_t); void xtalk_intr_free(xtalk_intr_t); int xtalk_intr_connect(xtalk_intr_t, intr_func_t, intr_arg_t, xtalk_intr_setfunc_t, void *, void *); void xtalk_intr_disconnect(xtalk_intr_t); @@ -318,7 +318,7 @@ unsigned flags) { #if DEBUG - cmn_err(CE_PANIC, "null_xtalk_early_piotrans_addr"); + PRINT_PANIC("null_xtalk_early_piotrans_addr"); #endif return NULL; } @@ -439,6 +439,19 @@ (dev, dev_desc, owner_dev); } +/* + * Allocate resources required for an interrupt as specified in dev_desc. + * Unconditionally setup resources to be non-threaded. + * Return resource handle in intr_hdl. + */ +xtalk_intr_t +xtalk_intr_alloc_nothd(devfs_handle_t dev, /* which Crosstalk device */ + device_desc_t dev_desc, /* device descriptor */ + devfs_handle_t owner_dev) /* owner of this interrupt */ +{ + return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc_nothd) + (dev, dev_desc, owner_dev); +} /* * Free resources consumed by intr_alloc. @@ -527,7 +540,11 @@ xwidget_info_t xwidget_info; #if DEBUG && ERROR_DEBUG - cmn_err(CE_CONT, "%v: xtalk_error_handler\n", xconn); +#ifdef SUPPORT_PRINTING_V_FORMAT + printk("%v: xtalk_error_handler\n", xconn); +#else + printk("%x: xtalk_error_handler\n", xconn); +#endif #endif xwidget_info = xwidget_info_get(xconn); @@ -549,9 +566,13 @@ (mode == MODE_DEVREENABLE)) return IOERROR_HANDLED; -#ifdef IRIX - cmn_err(CE_WARN, "Xbow at %v encountered Fatal error", xconn); +#ifdef LATER +#ifdef SUPPORT_PRINTING_V_FORMAT + PRINT_WARNING("Xbow at %v encountered Fatal error", xconn); +#else + PRINT_WARNING("Xbow at %x encountered Fatal error", xconn); #endif +#endif /* LATER */ ioerror_dump("xtalk", error_code, mode, ioerror); return IOERROR_UNHANDLED; @@ -648,13 +669,6 @@ return (xtalk_intr->xi_sfarg); } - -int -xtalk_intr_flags_get(xtalk_intr_t xtalk_intr) -{ - return(xtalk_intr->xi_flags); -} - /****** Generic crosstalk pio interfaces ******/ devfs_handle_t xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap) @@ -726,11 +740,15 @@ widget_info = (xwidget_info_t) hwgraph_fastinfo_get(xwidget); -#ifdef IRIX +#ifdef LATER if ((widget_info != NULL) && (widget_info->w_fingerprint != widget_info_fingerprint)) - cmn_err(CE_PANIC, "%v bad xwidget_info", xwidget); +#ifdef SUPPORT_PRINTING_V_FORMAT + PRINT_PANIC("%v bad xwidget_info", xwidget); +#else + PRINT_PANIC("%x bad xwidget_info", xwidget); #endif +#endif /* LATER */ return (widget_info); } @@ -894,7 +912,7 @@ return cdl_add_driver(xtalk_registry, part_num, mfg_num, - driver_prefix, flags); + driver_prefix, flags, NULL); } /* @@ -910,7 +928,7 @@ */ ASSERT(xtalk_registry != NULL); - cdl_del_driver(xtalk_registry, driver_prefix); + cdl_del_driver(xtalk_registry, driver_prefix, NULL); } /* @@ -963,7 +981,6 @@ * long as we have it, we can use it elsewhere. */ s = dev_to_name(widget,devnm,MAXDEVNAME); - printk("xwidget_register: dev_to_name widget id 0x%p, s = %s\n", widget, s); widget_info->w_name = kmalloc(strlen(s) + 1, GFP_KERNEL); strcpy(widget_info->w_name,s); @@ -985,7 +1002,8 @@ if (aa) async_attach_add_info(widget, aa); - return cdl_add_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, widget); + return cdl_add_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, + widget, 0); } /* @@ -1009,8 +1027,8 @@ hwid = &(widget_info->w_hwid); - cdl_del_connpt(xtalk_registry, hwid->part_num, - hwid->mfg_num, widget); + cdl_del_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, + widget, 0); /* Clean out the xwidget information */ (void)kfree(widget_info->w_name); @@ -1051,7 +1069,7 @@ xswitch_reset_link(xwidget); info = xwidget_info_get(xwidget); -#ifdef IRIX +#ifdef LATER ASSERT_ALWAYS(info != NULL); #endif @@ -1083,26 +1101,7 @@ ASSERT(info != NULL); return(xwidget_info_name_get(info)); } -/* - * xtalk_device_powerup - * Reset and initialize the specified xtalk widget - */ -int -xtalk_device_powerup(devfs_handle_t xbus_vhdl, xwidgetnum_t widget) -{ -#ifndef CONFIG_IA64_SGI_IO - extern void io_xswitch_widget_init(devfs_handle_t, - devfs_handle_t, - xwidgetnum_t, - async_attach_t); - io_xswitch_widget_init(xbus_vhdl, - hwgraph_connectpt_get(xbus_vhdl), - widget, - NULL); -#endif /* CONFIG_IA64_SGI_IO */ - - return(0); -} + /* * xtalk_device_shutdown * Disable the specified xtalk widget and clean out all the software diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/Makefile linux.ac/arch/ia64/sn/sn1/Makefile --- linux.vanilla/arch/ia64/sn/sn1/Makefile Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/sn1/Makefile Tue Apr 10 18:12:08 2001 @@ -8,7 +8,7 @@ EXTRA_CFLAGS := -DSN -DLANGUAGE_C=1 -D_LANGUAGE_C=1 -I. -DBRINGUP \ -DDIRECT_L1_CONSOLE -DNUMA_BASE -DSIMULATED_KLGRAPH \ -DNUMA_MIGR_CONTROL -DLITTLE_ENDIAN -DREAL_HARDWARE \ - -DNEW_INTERRUPTS -DCONFIG_IA64_SGI_IO + -DNEW_INTERRUPTS .S.s: $(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -o $*.s $< @@ -18,18 +18,13 @@ all: sn1.a O_TARGET = sn1.a -O_HEADERS = -O_OBJS = irq.o setup.o iomv.o mm.o smp.o synergy.o sn1_asm.o \ - discontig.o -ifeq ($(CONFIG_IA64_SGI_AUTOTEST),y) -O_OBJS += llsc4.o -endif +obj-y = irq.o setup.o iomv.o mm.o smp.o synergy.o sn1_asm.o \ + discontig.o probe.o error.o sv.o - -ifeq ($(CONFIG_IA64_GENERIC),y) -O_OBJS += machvec.o -endif +obj-$(CONFIG_IA64_SGI_AUTOTEST) += llsc4.o +obj-$(CONFIG_IA64_GENERIC) += machvec.o +obj-$(CONFIG_MODULES) += sn1_ksyms.o clean:: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/discontig.c linux.ac/arch/ia64/sn/sn1/discontig.c --- linux.vanilla/arch/ia64/sn/sn1/discontig.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/sn1/discontig.c Tue Apr 10 18:12:08 2001 @@ -139,35 +139,6 @@ dump_bootmem_info() ; } -void __init -discontig_paging_init(void) -{ - int i; - unsigned long max_dma, zones_size[MAX_NR_ZONES]; - void dump_node_data(void); - - max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; - for (i = 0; i < numnodes; i++) { - extern void free_unused_memmap_node(int); - unsigned long startpfn = __pa((void *)NODE_START(i)) >> PAGE_SHIFT; - unsigned long numpfn = NODE_SIZE(i) >> PAGE_SHIFT; - memset(zones_size, 0, sizeof(zones_size)); - - if ((startpfn + numpfn) < max_dma) { - zones_size[ZONE_DMA] = numpfn; - } else if (startpfn > max_dma) { - zones_size[ZONE_NORMAL] = numpfn; - } else { - zones_size[ZONE_DMA] = (max_dma - startpfn); - zones_size[ZONE_NORMAL] = numpfn - zones_size[ZONE_DMA]; - } - free_area_init_node(i, NODE_DATA(i), NULL, zones_size, startpfn<<PAGE_SHIFT, 0); - free_unused_memmap_node(i); - } - dump_node_data(); -} - - void dump_node_data(void) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/error.c linux.ac/arch/ia64/sn/sn1/error.c --- linux.vanilla/arch/ia64/sn/sn1/error.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ia64/sn/sn1/error.c Tue Apr 10 18:12:08 2001 @@ -0,0 +1,149 @@ + + +/* + * SN1 Platform specific error Support + * + * Copyright (C) 2001 Silicon Graphics, Inc. + * Copyright (C) 2001 Alan Mayer (ajm@sgi.com) + */ + + + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> + +#include <asm/ptrace.h> +#include <linux/devfs_fs_kernel.h> +#include <asm/smp.h> +#include <asm/sn/sn_cpuid.h> +#include <asm/sn/sn1/bedrock.h> +#include <asm/sn/intr.h> +#include <asm/sn/addrs.h> + +void +snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs) { + unsigned long long intpend_val; + unsigned long long bit; + + switch (irq) { + case SGI_UART_IRQ: + // This isn't really an error interrupt. We're just + // here because we have to do something with them. + // This is probably wrong, and this code will be + // removed. + intpend_val = LOCAL_HUB_L(PI_INT_PEND0); + if ( (bit = ~(1L<<GFX_INTR_A)) == + (intpend_val & ~(1L<<GFX_INTR_A)) ) { + LOCAL_HUB_CLR_INTR(bit); + return; + } + if ( (bit = ~(1L<<GFX_INTR_B)) == + (intpend_val & ~(1L<<GFX_INTR_B)) ) { + LOCAL_HUB_CLR_INTR(bit); + return; + } + if ( (bit = ~(1L<<PG_MIG_INTR)) == + (intpend_val & ~(1L<<PG_MIG_INTR)) ) { + LOCAL_HUB_CLR_INTR(bit); + return; + } + if ( (bit = ~(1L<<UART_INTR)) == + (intpend_val & ~(1L<<UART_INTR)) ) { + LOCAL_HUB_CLR_INTR(bit); + return; + } + if ( (bit = ~(1L<<CC_PEND_A)) == + (intpend_val & ~(1L<<CC_PEND_A)) ) { + LOCAL_HUB_CLR_INTR(bit); + return; + } + if ( (bit = ~(1L<<CC_PEND_B)) == + (intpend_val & ~(1L<<CC_PEND_B)) ) { + LOCAL_HUB_CLR_INTR(bit); + return; + } + printk("Received SGI_UART_IRQ (65), but no intpend0 bits were set???\n"); + return; + case SGI_HUB_ERROR_IRQ: + // These are mostly error interrupts of various + // sorts. We need to do more than panic here, but + // what the heck, this is bring up. + intpend_val = LOCAL_HUB_L(PI_INT_PEND1); + + if ( (bit = ~(1L<<XB_ERROR)) == + (intpend_val & ~(1L<<XB_ERROR)) ) { + LOCAL_HUB_CLR_INTR(bit); + panic("RECEIVED XB_ERROR on cpu %d, cnode %d\n", + smp_processor_id(), + cpuid_to_cnodeid(smp_processor_id())); + } + if ( (bit = ~(1L<<LB_ERROR)) == + (intpend_val & ~(1L<<LB_ERROR)) ) { + LOCAL_HUB_CLR_INTR(bit); + panic("RECEIVED LB_ERROR on cpu %d, cnode %d\n", + smp_processor_id(), + cpuid_to_cnodeid(smp_processor_id())); + } + if ( (bit = ~(1L<<NACK_INT_A)) == + (intpend_val & ~(1L<<NACK_INT_A)) ) { + LOCAL_HUB_CLR_INTR(bit); + panic("RECEIVED NACK_INT_A on cpu %d, cnode %d\n", + smp_processor_id(), + cpuid_to_cnodeid(smp_processor_id())); + } + if ( (bit = ~(1L<<NACK_INT_B)) == + (intpend_val & ~(1L<<NACK_INT_B)) ) { + LOCAL_HUB_CLR_INTR(bit); + panic("RECEIVED NACK_INT_B on cpu %d, cnode %d\n", + smp_processor_id(), + cpuid_to_cnodeid(smp_processor_id())); + } + if ( (bit = ~(1L<<CLK_ERR_INTR)) == + (intpend_val & ~(1L<<CLK_ERR_INTR)) ) { + LOCAL_HUB_CLR_INTR(bit); + panic("RECEIVED CLK_ERR_INTR on cpu %d, cnode %d\n", + smp_processor_id(), + cpuid_to_cnodeid(smp_processor_id())); + } + if ( (bit = ~(1L<<COR_ERR_INTR_A)) == + (intpend_val & ~(1L<<COR_ERR_INTR_A)) ) { + LOCAL_HUB_CLR_INTR(bit); + panic("RECEIVED COR_ERR_INTR_A on cpu %d, cnode %d\n", + smp_processor_id(), + cpuid_to_cnodeid(smp_processor_id())); + } + if ( (bit = ~(1L<<COR_ERR_INTR_B)) == + (intpend_val & ~(1L<<COR_ERR_INTR_B)) ) { + LOCAL_HUB_CLR_INTR(bit); + panic("RECEIVED COR_ERR_INTR_B on cpu %d, cnode %d\n", + smp_processor_id(), + cpuid_to_cnodeid(smp_processor_id())); + } + if ( (bit = ~(1L<<MD_COR_ERR_INTR)) == + (intpend_val & ~(1L<<MD_COR_ERR_INTR)) ) { + LOCAL_HUB_CLR_INTR(bit); + panic("RECEIVED MD_COR_ERR_INTR on cpu %d, cnode %d\n", + smp_processor_id(), + cpuid_to_cnodeid(smp_processor_id())); + } + if ( (bit = ~(1L<<NI_ERROR_INTR)) == + (intpend_val & ~(1L<<NI_ERROR_INTR)) ) { + LOCAL_HUB_CLR_INTR(bit); + panic("RECEIVED NI_ERROR_INTR on cpu %d, cnode %d\n", + smp_processor_id(), + cpuid_to_cnodeid(smp_processor_id())); + } + if ( (bit = ~(1L<<MSC_PANIC_INTR)) == + (intpend_val & ~(1L<<MSC_PANIC_INTR)) ) { + LOCAL_HUB_CLR_INTR(bit); + panic("RECEIVED MSC_PANIC_INTR on cpu %d, cnode %d\n", + smp_processor_id(), + cpuid_to_cnodeid(smp_processor_id())); + } + printk("Received SGI_XB_ERROR_IRQ (182) but no intpend1 bits are set???\n"); + return; + default: + printk("Received invalid irq in snia_error_intr_handler()/n"); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/iomv.c linux.ac/arch/ia64/sn/sn1/iomv.c --- linux.vanilla/arch/ia64/sn/sn1/iomv.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/sn1/iomv.c Tue Apr 10 18:12:08 2001 @@ -25,11 +25,8 @@ * for accessing registers in bedrock local block * (so we don't do port&0xfff) */ - if (port == 0x1f6 || port == 0x1f7 - || port == 0x3f6 || port == 0x3f7 - || port == 0x1f0 || port == 0x1f1 - || port == 0x1f3 || port == 0x1f4 - || port == 0x1f2 || port == 0x1f5) { + if (port >= 0x1f0 && port <= 0x1f7 || + port == 0x3f6 || port == 0x3f7) { io_base = __IA64_UNCACHED_OFFSET | 0x00000FFFFC000000; addr = io_base | ((port >> 2) << 12) | (port & 0xfff); } else { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/irq.c linux.ac/arch/ia64/sn/sn1/irq.c --- linux.vanilla/arch/ia64/sn/sn1/irq.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/sn1/irq.c Tue Apr 10 18:12:08 2001 @@ -4,11 +4,13 @@ * Copyright (C) 2000 Silicon Graphics * Copyright (C) 2000 Jack Steiner (steiner@sgi.com) * Copyright (C) 2000 Alan Mayer (ajm@sgi.com) + * Copyright (C) 2000 Kanoj Sarcar (kanoj@sgi.com) */ #include <linux/config.h> #include <linux/init.h> #include <linux/sched.h> +#include <linux/slab.h> #include <asm/current.h> #include <linux/irq.h> #include <linux/interrupt.h> @@ -30,28 +32,23 @@ #include <asm/sn/sn1/arch.h> #include <asm/sn/synergy.h> +#define IRQ_BIT_OFFSET 64 -int bit_pos_to_irq(int bit); -int irq_to_bit_pos(int irq); -void add_interrupt_randomness(int irq); -void * kmalloc(size_t size, int flags); -void kfree(const void *); -int sgi_pci_intr_support (unsigned int, device_desc_t *, devfs_handle_t *, pciio_intr_line_t *, devfs_handle_t *); -pciio_intr_t pciio_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); -int request_irq(unsigned int, void (*)(int, void *, struct pt_regs *), unsigned long, const char *, void *); - -/* This should be dynamically allocated, at least part of it. */ -/* For the time being, though, we'll statically allocate it */ -/* because kmalloc hasn't been initiallized at the time this */ -/* array is initiallized. One way to do it would be to statically */ -/* allocate the data for node 0, then let other nodes, as they */ -/* need it, dynamically allocate their own data space. */ - -struct sn1_cnode_action_list *sn1_node_actions[MAX_COMPACT_NODES]; -struct sn1_cnode_action_list sn1_actions[MAX_COMPACT_NODES][256]; +int bit_pos_to_irq(int bit) +{ + if (bit > 118) + bit = 118; + return (bit + IRQ_BIT_OFFSET); +} +static inline int irq_to_bit_pos(int irq) +{ + int bit = irq - IRQ_BIT_OFFSET; -extern int numnodes; + if (bit > 63) + bit -= 64; + return bit; +} static unsigned int sn1_startup_irq(unsigned int irq) @@ -82,6 +79,10 @@ static void sn1_end_irq(unsigned int irq) { + int bit; + + bit = irq_to_bit_pos(irq); + LOCAL_HUB_CLR_INTR(bit); } static void @@ -89,38 +90,6 @@ { } - -static void -sn1_handle_irq(int irq, void *dummy, struct pt_regs *regs) -{ - int bit, cnode; - struct sn1_cnode_action_list *alp; - struct sn1_intr_action *ap; - void (*handler)(int, void *, struct pt_regs *); - unsigned long flags = 0; - int cpuid = smp_processor_id(); - - - bit = irq_to_bit_pos(irq); - LOCAL_HUB_CLR_INTR(bit); - cnode = cpuid_to_cnodeid(cpuid); - alp = sn1_node_actions[cnode]; - ap = alp[irq].action_list; - if (ap == NULL) { - return; - } - while (ap) { - flags |= ap->flags; - handler = ap->handler; - (*handler)(irq,ap->intr_arg,regs); - ap = ap->next; - } - if ((flags & SA_SAMPLE_RANDOM) != 0) - add_interrupt_randomness(irq); - - return; -} - struct hw_interrupt_type irq_type_sn1 = { "sn1_irq", sn1_startup_irq, @@ -132,134 +101,83 @@ sn1_set_affinity_irq }; -struct irqaction sn1_irqaction = { - sn1_handle_irq, - 0, - 0, - NULL, - NULL, - NULL, -}; void sn1_irq_init (void) { - int i,j; + int i; for (i = 0; i <= NR_IRQS; ++i) { - if (irq_desc[i].handler == &no_irq_type) { - irq_desc[i].handler = &irq_type_sn1; - if (i >=71 && i <= 181) { - irq_desc[i].action = &sn1_irqaction; - } - } - } - - for (i = 0; i < numnodes; i++) { - sn1_node_actions[i] = sn1_actions[i]; - memset(sn1_node_actions[i], 0, - sizeof(struct sn1_cnode_action_list) * - (IA64_MAX_VECTORED_IRQ + 1)); - for (j=0; j<IA64_MAX_VECTORED_IRQ+1; j++) { - spin_lock_init(&sn1_node_actions[i][j].action_list_lock); + if (idesc_from_vector(i)->handler == &no_irq_type) { + idesc_from_vector(i)->handler = &irq_type_sn1; } } } -int -sn1_request_irq (unsigned int requested_irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, const char * devname, void *dev_id) -{ - devfs_handle_t curr_dev; - devfs_handle_t dev; - pciio_intr_t intr_handle; - pciio_intr_line_t line; - device_desc_t dev_desc; - int cpuid, bit, cnode; - struct sn1_intr_action *ap, *new_ap; - struct sn1_cnode_action_list *alp; - int irq; - - if ( (requested_irq & 0xff) == 0 ) { - int ret; - - sgi_pci_intr_support(requested_irq, - &dev_desc, &dev, &line, &curr_dev); - intr_handle = pciio_intr_alloc(curr_dev, NULL, line, curr_dev); - bit = intr_handle->pi_irq; - cpuid = intr_handle->pi_cpu; - irq = bit_pos_to_irq(bit); - cnode = cpuid_to_cnodeid(cpuid); - new_ap = (struct sn1_intr_action *)kmalloc( - sizeof(struct sn1_intr_action), GFP_KERNEL); - irq_desc[irq].status = 0; - new_ap->handler = handler; - new_ap->intr_arg = dev_id; - new_ap->flags = irqflags; - new_ap->next = NULL; - alp = sn1_node_actions[cnode]; - - spin_lock(&alp[irq].action_list_lock); - ap = alp[irq].action_list; - /* check action list for "share" consistency */ - while (ap){ - if (!(ap->flags & irqflags & SA_SHIRQ) ) { - return(-EBUSY); - spin_unlock(&alp[irq].action_list_lock); - } - ap = ap->next; - } - ap = alp[irq].action_list; - if (ap) { - while (ap->next) { - ap = ap->next; - } - ap->next = new_ap; - } else { - alp[irq].action_list = new_ap; - } - ret = pciio_intr_connect(intr_handle, (intr_func_t)handler, dev_id, NULL); - if (ret) { /* connect failed, undo what we did. */ - new_ap = alp[irq].action_list; - if (new_ap == ap) { - alp[irq].action_list = NULL; - kfree(ap); - } else { - while (new_ap->next && new_ap->next != ap) { - new_ap = new_ap->next; - } - if (new_ap->next == ap) { - new_ap->next = ap->next; - kfree(ap); - } - } - } - - spin_unlock(&alp[irq].action_list_lock); - return(ret); - } else { - return(request_irq(requested_irq, handler, irqflags, devname, dev_id)); - } -} -#if !defined(CONFIG_IA64_SGI_IO) +#if !defined(CONFIG_IA64_SGI_SN1) void sn1_pci_fixup(int arg) { } #endif -int -bit_pos_to_irq(int bit) { -#define BIT_TO_IRQ 64 +#ifdef CONFIG_PERCPU_IRQ + +extern irq_desc_t irq_descX[NR_IRQS]; +irq_desc_t *irq_desc_ptr[NR_CPUS] = { irq_descX }; + +/* + * Each slave AP allocates its own irq table. + */ +int __init cpu_irq_init(void) +{ + irq_desc_ptr[smp_processor_id()] = (irq_desc_t *)kmalloc(sizeof(irq_descX), GFP_KERNEL); + if (irq_desc_ptr[smp_processor_id()] == 0) + return(-1); + memcpy(irq_desc_ptr[smp_processor_id()], irq_desc_ptr[0], + sizeof(irq_descX)); + return(0); +} + +/* + * This can also allocate the irq tables for the other cpus, specifically + * on their nodes. + */ +int __init master_irq_init(void) +{ + return(0); +} + +/* + * The input is an ivt level. + */ +irq_desc_t *idesc_from_vector(unsigned int ivnum) +{ + return(irq_desc_ptr[smp_processor_id()] + ivnum); +} - return bit + BIT_TO_IRQ; +/* + * The input is a "soft" level, that we encoded in. + */ +irq_desc_t *idesc_from_irq(unsigned int irq) +{ + return(irq_desc_ptr[irq >> 8] + (irq & 0xff)); } -int -irq_to_bit_pos(int irq) { -#define IRQ_TO_BIT 64 +unsigned int ivector_from_irq(unsigned int irq) +{ + return(irq & 0xff); +} - return irq - IRQ_TO_BIT; +/* + * This should return the Linux irq # for the i/p vector on the + * i/p cpu. We currently do not track this. + */ +unsigned int irq_from_cpuvector(int cpunum, unsigned int vector) +{ + return (vector); } + +#endif /* CONFIG_PERCPU_IRQ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/llsc4.c linux.ac/arch/ia64/sn/sn1/llsc4.c --- linux.vanilla/arch/ia64/sn/sn1/llsc4.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/sn1/llsc4.c Tue Apr 10 18:12:08 2001 @@ -35,6 +35,15 @@ static int inttest=0; #endif +#ifdef IA64_SEMFIX_INSN +#undef IA64_SEMFIX_INSN +#endif +#ifdef IA64_SEMFIX +#undef IA64_SEMFIX +#endif +# define IA64_SEMFIX_INSN +# define IA64_SEMFIX "" + /* * Test parameter table for AUTOTEST @@ -46,22 +55,22 @@ } autotest_table_t; autotest_table_t autotest_table[] = { - {1000000, 2, 0x2b4 }, - {1000000, 16, 0, }, - {1000000, 16, 4, }, - {1000000, 128, 0x44 }, - {1000000, 128, 0x84 }, - {1000000, 128, 0x200 }, - {1000000, 128, 0x204 }, - {1000000, 128, 0x2b4 }, - {1000000, 2, 8*MB+0x2b4 }, - {1000000, 16, 8*MB+0 }, - {1000000, 16, 8*MB+4 }, - {1000000, 128, 8*MB+0x44 }, - {1000000, 128, 8*MB+0x84 }, - {1000000, 128, 8*MB+0x200 }, - {1000000, 128, 8*MB+0x204 }, - {1000000, 128, 8*MB+0x2b4 }, + {5000000, 2, 0x2b4 }, + {5000000, 16, 0, }, + {5000000, 16, 4, }, + {5000000, 128, 0x44 }, + {5000000, 128, 0x84 }, + {5000000, 128, 0x200 }, + {5000000, 128, 0x204 }, + {5000000, 128, 0x2b4 }, + {5000000, 2, 8*MB+0x2b4 }, + {5000000, 16, 8*MB+0 }, + {5000000, 16, 8*MB+4 }, + {5000000, 128, 8*MB+0x44 }, + {5000000, 128, 8*MB+0x84 }, + {5000000, 128, 8*MB+0x200 }, + {5000000, 128, 8*MB+0x204 }, + {5000000, 128, 8*MB+0x2b4 }, {0}}; /* @@ -134,20 +143,21 @@ static void Speedo(void); int autotest_enabled=0; -static int autotest_explicit_flush=0; static int llsctest_number=-1; static int errstop_enabled=0; static int fail_enabled=0; static int selective_trigger=0; +static int dump_block_addrs_opt=0; +static uint errlock=0; static int __init autotest_enable(char *str) { autotest_enabled = 1; return 1; } -static int __init set_llscxflush(char *str) +static int __init set_llscblkadr(char *str) { - autotest_explicit_flush = 1; + dump_block_addrs_opt = 1; return 1; } static int __init set_llscselt(char *str) @@ -179,55 +189,39 @@ printk (" Test options:\n"); printk (" llsctest=<n>\t%d\tTest number to run (all = -1)\n", llsctest_number); printk (" llscerrstop \t%s\tStop on error\n", errstop_enabled ? "on" : "off"); - printk (" llscxflush \t%s\tEnable explicit FC in test\n", autotest_explicit_flush ? "on" : "off"); printk (" llscfail \t%s\tForce a failure to test the trigger & error messages\n", fail_enabled ? "on" : "off"); printk (" llscselt \t%s\tSelective triger on failures\n", selective_trigger ? "on" : "off"); + printk (" llscblkadr \t%s\tDump data block addresses\n", dump_block_addrs_opt ? "on" : "off"); + printk (" SEMFIX: %s\n", IA64_SEMFIX); printk ("\n"); } __setup("autotest", autotest_enable); __setup("llsctest=", set_llsctest); __setup("llscerrstop", set_llscerrstop); -__setup("llscxflush", set_llscxflush); __setup("llscfail", set_llscfail); __setup("llscselt", set_llscselt); +__setup("llscblkadr", set_llscblkadr); -extern inline void -flush_buddy(void *p) -{ - long lp; - - if (autotest_explicit_flush) { - lp = (long)p; - lp ^= 0x40; - asm volatile ("fc %0" :: "r"(lp) : "memory"); - ia64_sync_i(); - ia64_srlz_d(); - } -} - -static int +extern inline int set_lock(uint *lock, uint id) { uint old; - flush_buddy(lock); old = cmpxchg_acq(lock, 0, id); return (old == 0); } -static int +extern inline int clr_lock(uint *lock, uint id) { uint old; - flush_buddy(lock); old = cmpxchg_rel(lock, id, 0); return (old == id); } -static void +extern inline void zero_lock(uint *lock) { - flush_buddy(lock); *lock = 0; } @@ -322,7 +316,6 @@ return 1; } if (correct_errors) { - flush_buddy(privp); tp->private[linei] = *privp; } errs++; @@ -343,7 +336,6 @@ errs++; } pval++; - flush_buddy(privp); *privp = pval; tp->private[linei] = pval; break; @@ -425,9 +417,7 @@ errs++; } - flush_buddy(sharep); *sharep = lockpat; - flush_buddy(sharecopy); *sharecopy = lockpat; @@ -471,7 +461,7 @@ static int rerr(capture_t *cap, char *msg, void *lp, void *slp, int thread, int pass, int linei, int exp, int found, int stillbad) { - int cpu; + int cpu, i; long synerr; int selt; @@ -487,6 +477,11 @@ } spin(1); + i = 100; + while (i && set_lock(&errlock, 1) != 1) { + spin(1); + i--; + } printk ("\nDataError!: %-20s, test %ld, thread %d, line:%d, pass %d (0x%x), time %ld expected:%x, found:%x\n", msg, k_testnumber, thread, linei, pass, pass, jiffies, exp, found); @@ -512,6 +507,7 @@ printk("SYNERR: Thread %d, Synerr: 0x%lx\n", thread, synerr); spin(2); printk("\n\n"); + clr_lock(&errlock, 1); if (errstop_enabled) { local_irq_disable(); @@ -639,8 +635,10 @@ testnumber = llsctest_number; } else { testnumber++; - if (autotest_table[testnumber].passes == 0) + if (autotest_table[testnumber].passes == 0) { testnumber = 0; + dump_block_addrs_opt = 0; + } } k_passes = autotest_table[testnumber].passes; k_linepad = autotest_table[testnumber].linepad; @@ -704,6 +702,22 @@ } static void +dump_block_addrs(void) +{ + int i; + + printk("LLSC TestNumber %ld\n", k_testnumber); + + for (i=0; i<k_linecount; i++) { + printk(" %lx", blocks[i]); + if (i%4 == 3) + printk("\n"); + } + printk("\n"); +} + + +static void set_thread_state(int cpuid, int state) { if (k_threadprivate[cpuid]->threadstate == TS_KILLED) { @@ -717,6 +731,7 @@ build_mem_map(unsigned long start, unsigned long end, void *arg) { long lstart; + long align = 8*MB; /* * HACK - skip the kernel on the first node */ @@ -731,9 +746,11 @@ while (lstart > start && (!PageReserved(virt_to_page(lstart-PAGE_SIZE)) && virt_to_page(lstart-PAGE_SIZE)->count.counter == 0)) lstart -= PAGE_SIZE; - printk (" memmap: start 0x%lx, end 0x%lx\n", lstart, end); + lstart = (lstart + align -1) /align * align; + end = end / align * align; if (lstart >= end) return 0; + printk (" memmap: start 0x%lx, end 0x%lx\n", lstart, end); memmap[memmapx].vstart = lstart; memmap[memmapx].vend = end; @@ -812,6 +829,8 @@ if (k_linecount > MAX_LINECOUNT) k_linecount = MAX_LINECOUNT; k_linecount = k_linecount & ~1; setup_block_addresses(); + if (dump_block_addrs_opt) + dump_block_addrs(); k_currentpass = pass++; k_go = ST_RUN; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/machvec.c linux.ac/arch/ia64/sn/sn1/machvec.c --- linux.vanilla/arch/ia64/sn/sn1/machvec.c Sat Aug 12 03:09:06 2000 +++ linux.ac/arch/ia64/sn/sn1/machvec.c Tue Apr 10 18:12:08 2001 @@ -1,2 +1,18 @@ #define MACHVEC_PLATFORM_NAME sn1 #include <asm/machvec_init.h> +#include <asm/io.h> +#include <linux/pci.h> +void* +sn1_mk_io_addr_MACRO + +dma_addr_t +sn1_pci_map_single_MACRO + +int +sn1_pci_map_sg_MACRO + +unsigned long +sn1_virt_to_phys_MACRO + +void * +sn1_phys_to_virt_MACRO diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/mm.c linux.ac/arch/ia64/sn/sn1/mm.c --- linux.vanilla/arch/ia64/sn/sn1/mm.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/sn1/mm.c Tue Apr 10 18:12:08 2001 @@ -1,7 +1,7 @@ /* - * Copyright, 2000, Silicon Graphics. + * Copyright, 2000-2001, Silicon Graphics. * Copyright Srinivasa Thirumalachar (sprasad@engr.sgi.com) - * Copyright 2000 Kanoj Sarcar (kanoj@sgi.com) + * Copyright 2000-2001 Kanoj Sarcar (kanoj@sgi.com) */ #include <linux/config.h> @@ -11,32 +11,23 @@ #include <asm/efi.h> #include <asm/sn/mmzone_sn1.h> -# define MIN(a,b) ((a) < (b) ? (a) : (b)) -# define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +#define DONE_NOTHING 0 +#define DONE_FINDING 1 +#define DONE_BUILDING 2 -/* - * Note that the nodemem[] data structure does not support arbitrary - * memory types and memory descriptors inside the node. For example, - * you can not have multiple efi-mem-type segments in the node and - * expect the OS not to use specific mem-types. Currently, the - * assumption is that "start" is the start of virtual/physical memory - * on the node. PROM can reserve some memory _only_ at the beginning. - * This is tracked via the "usable" field, that maintains where the - * os can start using memory from on a node (ie end of PROM memory). - * setup_node_bootmem() is passed the above "usable" value, and is - * expected to make bootmem calls that ensure lower memory is not used. - * Note that the bootmem for a node is initialized on the entire node, - * without regards to any holes - then we reserve the holes in - * setup_sn1_bootmem(), to make sure the holes are not handed out by - * alloc_bootmem, as well as the corresponding mem_map entries are not - * considered allocatable by the page_alloc routines. - */ struct nodemem_s { - u64 start ; - u64 end ; - u64 hole[SN1_MAX_BANK_PER_NODE] ; - u64 usable; -} nodemem[MAXNODES] ; + u64 start; /* start of kernel usable memory */ + u64 end; /* end of kernel usable memory */ + u64 mtot; /* total kernel usable memory */ + u64 done; /* state of bootmem initialization */ + u64 bstart; /* where should the bootmem area be */ + u64 bsize; /* bootmap size */ + u64 hole[SN1_MAX_BANK_PER_NODE]; +} nodemem[MAXNODES]; + static int nodemem_valid = 0; static int __init @@ -46,7 +37,7 @@ unsigned long count = 0; if (start >= end) - return 0 ; + return 0; /* * Get the memmap ptrs to the start and end of the holes. @@ -54,31 +45,33 @@ * Can we do virt_to_page(end), if end is on the next node? */ - page = virt_to_page(start-1); - page++ ; - pageend = virt_to_page(end) ; + page = virt_to_page(start - 1); + page++; + pageend = virt_to_page(end); printk("hpage=0x%lx, hpageend=0x%lx\n", (u64)page, (u64)pageend) ; free_bootmem_node(NODE_DATA(nid), __pa(page), (u64)pageend - (u64)page); - return count ; + return count; } -void +static void __init free_unused_memmap_node(int nid) { - u64 i = 0 ; - u64 holestart = -1 ; + u64 i = 0; + u64 holestart = -1; + u64 start = nodemem[nid].start; + start = ((start >> SN1_NODE_ADDR_SHIFT) << SN1_NODE_ADDR_SHIFT); do { - holestart = nodemem[nid].hole[i] ; - i++ ; + holestart = nodemem[nid].hole[i]; + i++; while ((i < SN1_MAX_BANK_PER_NODE) && - (nodemem[nid].hole[i] == (u64)-1)) - i++ ; + (nodemem[nid].hole[i] == (u64)-1)) + i++; if (i < SN1_MAX_BANK_PER_NODE) free_unused_memmap_hole(nid, holestart, - nodemem[nid].start + (i<<SN1_BANK_ADDR_SHIFT)); + start + (i<<SN1_BANK_ADDR_SHIFT)); } while (i<SN1_MAX_BANK_PER_NODE); } @@ -98,7 +91,6 @@ cnodeid = NASID_TO_CNODEID(nasid); bankid = GetBankId(__pa(vaddr)); nodemem[cnodeid].start = MIN(nodemem[cnodeid].start, vaddr); - nodemem[cnodeid].usable = MIN(nodemem[cnodeid].usable, vaddr); nvaddr = (unsigned long)__va((unsigned long)(++nasid) << SN1_NODE_ADDR_SHIFT); nodemem[cnodeid].end = MAX(nodemem[cnodeid].end, MIN(end, nvaddr)); @@ -118,11 +110,14 @@ pgtbl_size_ok(int nid) { unsigned long numpfn, bank0size, nodesize ; + unsigned long start = nodemem[nid].start; + + start = ((start >> SN1_NODE_ADDR_SHIFT) << SN1_NODE_ADDR_SHIFT); - nodesize = nodemem[nid].end - nodemem[nid].start ; + nodesize = nodemem[nid].end - start ; numpfn = nodesize >> PAGE_SHIFT; - bank0size = nodemem[nid].hole[0] - nodemem[nid].start ; + bank0size = nodemem[nid].hole[0] - start ; /* If nid == master node && no kernel text replication */ bank0size -= 0xA00000 ; /* Kernel text + stuff */ bank0size -= ((numpfn + 7) >> 3); @@ -163,198 +158,198 @@ #ifdef CONFIG_DISCONTIGMEM -extern bootmem_data_t bdata[] ; -static int curnodeid ; +extern bootmem_data_t bdata[]; +/* + * This assumes there will be a hole in kernel-usable memory between nodes + * (due to prom). The memory descriptors invoked via efi_memmap_walk are + * in increasing order. It tries to identify first suitable free area to + * put the bootmem for the node in. When presented with the md holding + * the kernel, it only searches at the end of the kernel area. + */ static int __init -setup_node_bootmem(unsigned long start, unsigned long end, unsigned long nodefree) +find_node_bootmem(unsigned long start, unsigned long end, void *arg) { + int nasid = GetNasId(__pa(start)); + int cnodeid = NASID_TO_CNODEID(nasid); + unsigned long nodesize; extern char _end; - int i; - unsigned long kernelend = PAGE_ALIGN((unsigned long)(&_end)); - unsigned long pkernelend = __pa(kernelend); - unsigned long bootmap_start, bootmap_size; - unsigned long pstart, pend; - - pstart = __pa(start) ; - pend = __pa(end) ; - - /* If we are past a node mem boundary, on simulated dig numa - * increment current node id. */ - - curnodeid = NASID_TO_CNODEID(GetNasId(pstart)) ; - - /* - * Make sure we are being passed page aligned addresses. - */ - if ((start & (PAGE_SIZE - 1)) || (end & (PAGE_SIZE - 1))) - panic("setup_node_bootmem:align"); + unsigned long kaddr = (unsigned long)&_end; - - /* For now, just go to the lower CHUNK alignment so that - * chunktonid of 0-8MB and other lower mem pages get initted. */ - - pstart &= CHUNKMASK ; - pend = (pend+CHUNKSZ-1) & CHUNKMASK; - - /* If pend == 0, both addrs below 8 MB, special case it - * FIX: CHUNKNUM(pend-1) broken if pend == 0 - * both addrs within 8MB */ - - if (pend == 0) { - chunktonid[0] = 0; - return 0; - } - - /* Fill up the chunktonid array first. */ - - for (i = PCHUNKNUM(pstart); i <= PCHUNKNUM(pend-1); i++) - chunktonid[i] = curnodeid; - - /* This check is bogus for now till MAXCHUNKS is properly - * defined to say if it includes holes or not. */ - - if ((CHUNKTONID(PCHUNKNUM(pend)) > MAXCHUNKS) || - (PCHUNKNUM(pstart) >= PCHUNKNUM(pend))) { - printk("Ign 0x%lx-0x%lx, ", __pa(start), __pa(end)); + /* + * Track memory available to kernel. + */ + nodemem[cnodeid].mtot += ((end - start) >> PAGE_SHIFT); + if (nodemem[cnodeid].done != DONE_NOTHING) return(0); - } + nodesize = nodemem[cnodeid].end - ((nodemem[cnodeid].start >> + SN1_NODE_ADDR_SHIFT) << SN1_NODE_ADDR_SHIFT); + nodesize >>= PAGE_SHIFT; - /* This routine gets called many times in node 0. - * The first one to reach here would be the one after - * kernelend to end of first node. */ - - NODE_DATA(curnodeid)->bdata = &(bdata[curnodeid]); - - if (curnodeid == 0) { - /* for master node, forcibly assign these values - * This gets called many times on dig but we - * want these exact values - * Also on softsdv, the memdesc for 0 is missing */ - NODE_START(curnodeid) = PAGE_OFFSET; - NODE_SIZE(curnodeid) = (end - PAGE_OFFSET); - } else { - /* This gets called only once for non zero nodes - * If it does not, then NODE_STARt should be - * LOCAL_BASE(nid) */ + /* + * Adjust limits for the md holding the kernel. + */ + if ((start < kaddr) && (end > kaddr)) + start = PAGE_ALIGN(kaddr); - NODE_START(curnodeid) = start; - NODE_SIZE(curnodeid) = (end - start); + /* + * We need space for mem_map, bootmem map plus a few more pages + * to satisfy alloc_bootmems out of node 0. + */ + if ((end - start) > ((nodesize * sizeof(struct page)) + (nodesize/8) + + (10 * PAGE_SIZE))) { + nodemem[cnodeid].bstart = start; + nodemem[cnodeid].done = DONE_FINDING; } + return(0); +} - /* if end < kernelend do not do anything below this */ - if (pend < pkernelend) - return 0 ; +/* + * This assumes there will be a hole in kernel-usable memory between nodes + * (due to prom). The memory descriptors invoked via efi_memmap_walk are + * in increasing order. + */ +static int __init +build_node_bootmem(unsigned long start, unsigned long end, void *arg) +{ + int nasid = GetNasId(__pa(start)); + int curnodeid = NASID_TO_CNODEID(nasid); + int i; + unsigned long pstart, pend; + extern char _end, _stext; + unsigned long kaddr = (unsigned long)&_end; - /* - * Handle the node that contains kernel text/data. It would - * be nice if the loader loads the kernel at a "chunk", ie - * not in memory that the kernel will ignore (else free_initmem - * has to worry about not freeing memory that the kernel ignores). - * Note that we assume the space from the node start to - * KERNEL_START can not hold all the bootmem data, but from kernel - * end to node end can. - */ - - /* TBD: This may be bogus in light of the above check. */ - - if ((pstart < pkernelend) && (pend >= pkernelend)) { - bootmap_start = pkernelend; - } else { - bootmap_start = __pa(start); /* chunk & page aligned */ + if (nodemem[curnodeid].done == DONE_FINDING) { + /* + * This is where we come to know the node is present. + * Do node wide tasks. + */ + nodemem[curnodeid].done = DONE_BUILDING; + NODE_DATA(curnodeid)->bdata = &(bdata[curnodeid]); + + /* + * Update the chunktonid array as a node wide task. There + * are too many smalls mds on first node to do this per md. + */ + pstart = __pa(nodemem[curnodeid].start); + pend = __pa(nodemem[curnodeid].end); + pstart &= CHUNKMASK; + pend = (pend + CHUNKSZ - 1) & CHUNKMASK; + /* Possible check point to enforce minimum node size */ + if (nodemem[curnodeid].bstart == -1) { + printk("No valid bootmem area on node %d\n", curnodeid); + while(1); + } + for (i = PCHUNKNUM(pstart); i <= PCHUNKNUM(pend - 1); i++) + chunktonid[i] = curnodeid; + if ((CHUNKTONID(PCHUNKNUM(pend)) > MAXCHUNKS) || + (PCHUNKNUM(pstart) >= PCHUNKNUM(pend))) { + printk("Ign 0x%lx-0x%lx, ", __pa(start), __pa(end)); + return(0); + } + + /* + * NODE_START and NODE_SIZE determine the physical range + * on the node that mem_map array needs to be set up for. + */ + NODE_START(curnodeid) = ((nodemem[curnodeid].start >> + SN1_NODE_ADDR_SHIFT) << SN1_NODE_ADDR_SHIFT); + NODE_SIZE(curnodeid) = (nodemem[curnodeid].end - + NODE_START(curnodeid)); + + nodemem[curnodeid].bsize = + init_bootmem_node(NODE_DATA(curnodeid), + (__pa(nodemem[curnodeid].bstart) >> PAGE_SHIFT), + (__pa((nodemem[curnodeid].start >> SN1_NODE_ADDR_SHIFT) + << SN1_NODE_ADDR_SHIFT) >> PAGE_SHIFT), + (__pa(nodemem[curnodeid].end) >> PAGE_SHIFT)); + + } else if (nodemem[curnodeid].done == DONE_NOTHING) { + printk("build_node_bootmem: node %d weirdness\n", curnodeid); + while(1); /* Paranoia */ } /* - * Low memory is reserved for PROM use on SN1. The current node - * memory model is [PROM mem ... kernel ... free], where the - * first two components are optional on a node. + * Free the entire md. */ - if (bootmap_start < __pa(nodefree)) - bootmap_start = __pa(nodefree); - -/* XXX TBD */ -/* For curnodeid of 0, this gets called many times because of many - * < 8MB segments. start gets bumped each time. We want to fix it - * to 0 now. - */ - if (curnodeid == 0) - start=PAGE_OFFSET; -/* - * This makes sure that in free_area_init_core - paging_init - * idx is the entire node page range and for loop goes thro - * all pages. test_bit for kernel pages should remain reserved - * because free available mem takes care of kernel_start and end - */ - - bootmap_size = init_bootmem_node(NODE_DATA(curnodeid), - (bootmap_start >> PAGE_SHIFT), - (__pa(start) >> PAGE_SHIFT), (__pa(end) >> PAGE_SHIFT)); + free_bootmem_node(NODE_DATA(curnodeid), __pa(start), (end - start)); - free_bootmem_node(NODE_DATA(curnodeid), bootmap_start + bootmap_size, - __pa(end) - (bootmap_start + bootmap_size)); + /* + * Reclaim back the bootmap and kernel areas. + */ + if ((start <= nodemem[curnodeid].bstart) && (end > + nodemem[curnodeid].bstart)) + reserve_bootmem_node(NODE_DATA(curnodeid), + __pa(nodemem[curnodeid].bstart), nodemem[curnodeid].bsize); + if ((start <= kaddr) && (end > kaddr)) + reserve_bootmem_node(NODE_DATA(curnodeid), + __pa(&_stext), (&_end - &_stext)); return(0); } -void +void __init setup_sn1_bootmem(int maxnodes) { int i; - for (i=0;i<MAXNODES;i++) { - nodemem[i].usable = nodemem[i].start = -1 ; - nodemem[i].end = 0 ; - memset(&nodemem[i].hole, -1, sizeof(nodemem[i].hole)) ; + for (i = 0; i < MAXNODES; i++) { + nodemem[i].start = nodemem[i].bstart = -1; + nodemem[i].end = nodemem[i].bsize = nodemem[i].mtot = 0; + nodemem[i].done = DONE_NOTHING; + memset(&nodemem[i].hole, -1, sizeof(nodemem[i].hole)); } - efi_memmap_walk(build_nodemem_map, 0) ; + efi_memmap_walk(build_nodemem_map, 0); - /* - * Run thru all the nodes, adjusting their starts. This is needed - * because efi_memmap_walk() might not process certain mds that - * are marked reserved for PROM at node low memory. - */ - for (i = 0; i < maxnodes; i++) - nodemem[i].start = ((nodemem[i].start >> SN1_NODE_ADDR_SHIFT) << - SN1_NODE_ADDR_SHIFT); - nodemem_valid = 1 ; + nodemem_valid = 1; - /* After building the nodemem map, check if the page table + /* + * After building the nodemem map, check if the node memmap * will fit in the first bank of each node. If not change - * the node end addr till it fits. We dont want to do this - * in mm/page_alloc.c + * the node end addr till it fits. */ - for (i=0;i<maxnodes;i++) - check_pgtbl_size(i) ; - - for (i=0;i<maxnodes;i++) - setup_node_bootmem(nodemem[i].start, nodemem[i].end, nodemem[i].usable); + for (i = 0; i < maxnodes; i++) + check_pgtbl_size(i); - /* - * Mark the holes as reserved, so the corresponding mem_map - * entries will not be marked allocatable in free_all_bootmem*(). - */ - for (i = 0; i < maxnodes; i++) { - int j = 0 ; - u64 holestart = -1 ; - - do { - holestart = nodemem[i].hole[j++]; - while ((j < SN1_MAX_BANK_PER_NODE) && - (nodemem[i].hole[j] == (u64)-1)) - j++; - if (j < SN1_MAX_BANK_PER_NODE) - reserve_bootmem_node(NODE_DATA(i), - __pa(holestart), (nodemem[i].start + - ((long)j << SN1_BANK_ADDR_SHIFT) - - holestart)); - } while (j < SN1_MAX_BANK_PER_NODE); - } + dump_nodemem_map(maxnodes); - dump_nodemem_map(maxnodes) ; + efi_memmap_walk(find_node_bootmem, 0); + efi_memmap_walk(build_node_bootmem, 0); } #endif +void __init +discontig_paging_init(void) +{ + int i; + unsigned long max_dma, zones_size[MAX_NR_ZONES], holes_size[MAX_NR_ZONES]; + extern void dump_node_data(void); + + max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; + for (i = 0; i < numnodes; i++) { + unsigned long startpfn = __pa((void *)NODE_START(i)) >> PAGE_SHIFT; + unsigned long numpfn = NODE_SIZE(i) >> PAGE_SHIFT; + memset(zones_size, 0, sizeof(zones_size)); + memset(holes_size, 0, sizeof(holes_size)); + holes_size[ZONE_DMA] = numpfn - nodemem[i].mtot; + + if ((startpfn + numpfn) < max_dma) { + zones_size[ZONE_DMA] = numpfn; + } else if (startpfn > max_dma) { + zones_size[ZONE_NORMAL] = numpfn; + panic("discontig_paging_init: %d\n", i); + } else { + zones_size[ZONE_DMA] = (max_dma - startpfn); + zones_size[ZONE_NORMAL] = numpfn - zones_size[ZONE_DMA]; + panic("discontig_paging_init: %d\n", i); + } + free_area_init_node(i, NODE_DATA(i), NULL, zones_size, startpfn<<PAGE_SHIFT, holes_size); + free_unused_memmap_node(i); + } + dump_node_data(); +} + /* * This used to be invoked from an SN1 specific hack in efi_memmap_walk. * It tries to ignore banks which the kernel is ignoring because bank 0 @@ -386,10 +381,10 @@ int i,j; printk("NODEMEM_S info ....\n") ; - printk("Node start end usable\n"); + printk("Node start end\n"); for (i=0;i<maxnodes;i++) { - printk("%d 0x%lx 0x%lx 0x%lx\n", - i, nodemem[i].start, nodemem[i].end, nodemem[i].usable); + printk("%d 0x%lx 0x%lx\n", + i, nodemem[i].start, nodemem[i].end); printk("Holes -> ") ; for (j=0;j<SN1_MAX_BANK_PER_NODE;j++) printk("0x%lx ", nodemem[i].hole[j]) ; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/probe.c linux.ac/arch/ia64/sn/sn1/probe.c --- linux.vanilla/arch/ia64/sn/sn1/probe.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ia64/sn/sn1/probe.c Tue Apr 10 18:12:08 2001 @@ -0,0 +1,62 @@ +/* + * Platform dependent support for IO probing. + * + * Copyright (C) 2000 Silicon Graphics + * Copyright (C) 2000 Jack Steiner (steiner@sgi.com) + */ + +#include <asm/sn/sn_sal.h> + +/* + * ia64_sn_probe_io_slot + * This function will probe a physical address to determine if + * the address can be read. If reading the address causes a BUS + * error, an error is returned. If the probe succeeds, the contents + * of the memory location is returned. + * + * Calling sequence: + * ia64_probe_io_slot(paddr, size, data_ptr) + * + * Input: + * paddr Physical address to probe + * size Number bytes to read (1,2,4,8) + * data_ptr Address to store value read by probe + * (-1 returned if probe fails) + * + * Output: + * Status + * 0 - probe successful + * 1 - probe failed (generated MCA) + * 2 - Bad arg + * <0 - PAL error + */ + + +u64 +ia64_sn_probe_io_slot(long paddr, long size, void *data_ptr) +{ + struct ia64_sal_retval isrv; + + SAL_CALL(isrv, SN_SAL_PROBE, paddr, size, 0, 0, 0, 0, 0); + + if (data_ptr) { + switch (size) { + case 1: + *((u8*)data_ptr) = (u8)isrv.v0; + break; + case 2: + *((u16*)data_ptr) = (u16)isrv.v0; + break; + case 4: + *((u32*)data_ptr) = (u32)isrv.v0; + break; + case 8: + *((u64*)data_ptr) = (u64)isrv.v0; + break; + default: + isrv.status = 2; + } + } + + return isrv.status; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/setup.c linux.ac/arch/ia64/sn/sn1/setup.c --- linux.vanilla/arch/ia64/sn/sn1/setup.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/sn1/setup.c Tue Apr 10 18:12:08 2001 @@ -15,12 +15,30 @@ #include <linux/sched.h> #include <linux/ioport.h> #include <linux/mm.h> +#include <linux/serial.h> #include <asm/sn/mmzone_sn1.h> #include <asm/io.h> +#include <asm/dma.h> #include <asm/machvec.h> #include <asm/system.h> #include <asm/processor.h> +#include <asm-ia64/sn/arch.h> +#include <asm-ia64/sn/addrs.h> + + +/* + * This is the address of the RRegs in the HSpace of the global + * master. It is used by a hack in serial.c (serial_[in|out], + * printk.c (early_printk), and kdb_io.c to put console output on that + * node's Bedrock UART. It is initialized here to 0, so that + * early_printk won't try to access the UART before + * master_node_bedrock_address is properly calculated. + */ +u64 master_node_bedrock_address = 0UL; + +static void sn_fix_ivt_for_partitioned_system(void); + /* * The format of "screen_info" is strange, and due to early i386-setup @@ -58,31 +76,169 @@ #endif } +#if defined(BRINGUP) && defined(CONFIG_IA64_EARLY_PRINTK) +void __init +early_sn1_setup(void) +{ + master_node_bedrock_address = + (u64)REMOTE_HSPEC_ADDR(get_nasid(), 0); + printk("early_sn1_setup: setting master_node_bedrock_address to 0x%lx\n", master_node_bedrock_address); +} +#endif /* BRINGUP && CONFIG_IA64_EARLY_PRINTK */ + void __init sn1_setup(char **cmdline_p) { - extern void init_sn1_smp_config(void); +#if defined(CONFIG_SERIAL) && !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) + struct serial_struct req; +#endif + + MAX_DMA_ADDRESS = PAGE_OFFSET + 0x10000000000UL; + master_node_bedrock_address = + (u64)REMOTE_HSPEC_ADDR(get_nasid(), 0); + printk("sn1_setup: setting master_node_bedrock_address to 0x%lx\n", + master_node_bedrock_address); + +#if defined(CONFIG_SERIAL) && !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) + /* + * We do early_serial_setup() to clean out the rs-table[] from the + * statically compiled in version. + */ + memset(&req, 0, sizeof(struct serial_struct)); + req.line = 0; + req.baud_base = 124800; + req.port = 0; + req.port_high = 0; + req.irq = 0; + req.flags = (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST); + req.io_type = SERIAL_IO_MEM; + req.hub6 = 0; + req.iomem_base = (u8 *)(master_node_bedrock_address + 0x80); + req.iomem_reg_shift = 3; + req.type = 0; + req.xmit_fifo_size = 0; + req.custom_divisor = 0; + req.closing_wait = 0; + early_serial_setup(&req); +#endif /* CONFIG_SERIAL && !CONFIG_SERIAL_SGI_L1_PROTOCOL */ + ROOT_DEV = to_kdev_t(0x0301); /* default to first IDE drive */ + sn_fix_ivt_for_partitioned_system(); - init_sn1_smp_config(); -#ifdef ZZZ -#if !defined (CONFIG_IA64_SOFTSDV_HACKS) - /* - * Program the timer to deliver timer ticks. 0x40 is the I/O port - * address of PIT counter 0, 0x43 is the I/O port address of the - * PIT control word. - */ - request_region(0x40,0x20,"timer"); - outb(0x34, 0x43); /* Control word */ - outb(LATCH & 0xff , 0x40); /* LSB */ - outb(LATCH >> 8, 0x40); /* MSB */ - printk("PIT: LATCH at 0x%x%x for %d HZ\n", LATCH >> 8, LATCH & 0xff, HZ); -#endif -#endif #ifdef CONFIG_SMP init_smp_config(); #endif screen_info = sn1_screen_info; +} + + +/* + * sn_fix_ivt_for_partitioned_system + * + * This is an ugly hack that is needed for partitioned systems. + * + * On a partitioned system, most partitions do NOT have a physical address 0. + * Unfortunately, the exception handling code in ivt.S has a couple of physical + * addresses of kernel structures hardcoded into "movl" instructions. + * These addresses are correct on partition 0 only. On all other partitions, + * the addresses must be changed to reference the correct address. + * + * This routine scans the ivt code and replaces the hardcoded addresses with + * the correct address. + * + * Note that we could have made the ivt.S code dynamically determine the correct + * address but this would add code to performance critical pathes. This option + * was rejected. + */ + +#define TEMP_mlx 4 /* template type that contains movl instruction */ +#define TEMP_mlX 5 /* template type that contains movl instruction */ + +typedef union { /* Instruction encoding for movl instruction */ + struct { + unsigned long qp:6; + unsigned long r1:7; + unsigned long imm7b:7; + unsigned long vc:1; + unsigned long ic:1; + unsigned long imm5c:5; + unsigned long imm9d:9; + unsigned long i:1; + unsigned long op:4; + unsigned long fill:23; + } b; + unsigned long l; +} movl_instruction_t; + +#define MOVL_OPCODE 6 +#define MOVL_ARG(a,b) (((long)a.i<<63) | ((long)b<<22) | ((long)a.ic<<21) | \ + ((long)a.imm5c<<16) | ((long)a.imm9d<<7) | ((long)a.imm7b)) + +typedef struct { /* Instruction bundle */ + unsigned long template:5; + unsigned long ins2:41; + unsigned long ins1l:18; + unsigned long ins1u:23; + unsigned long ins0:41; +} instruction_bundle_t; + + +static void __init +sn_fix_ivt_for_partitioned_system(void) +{ + extern int ia64_ivt; + instruction_bundle_t *p, *pend; + movl_instruction_t ins0, ins1, ins2; + long new_ins1, phys_offset; + unsigned long val; + + /* + * Setup to scan the ivt code. + */ + p = (instruction_bundle_t*)&ia64_ivt; + pend = p + 0x8000/sizeof(instruction_bundle_t); + phys_offset = __pa(p) & ~0x1ffffffffUL; + + /* + * Hunt for movl instructions that contain the node 0 physical address + * of "SWAPPER_PGD_ADDR". These addresses must be relocated to reference the + * actual node that the kernel is loaded on. + */ + for (; p < pend; p++) { + if (p->template != TEMP_mlx && p->template != TEMP_mlX) + continue; + ins0.l = p->ins0; + if (ins0.b.op != MOVL_OPCODE) + continue; + ins1.l = ((long)p->ins1u<<18) | p->ins1l; + ins2.l = p->ins2; + val = MOVL_ARG(ins0.b, ins1.l); + + /* + * Test for correct address. SWAPPER_PGD_ADDR will + * always be a node 0 virtual address. Note that we cant + * use the __pa or __va macros here since they may contain + * debug code that gets fooled here. + */ + if ((PAGE_OFFSET | val) != SWAPPER_PGD_ADDR) + continue; + + /* + * We found an instruction that needs to be fixed. The following + * inserts the NASID of the ivt into the movl instruction. + */ + new_ins1 = ins1.l | (phys_offset>>22); + p->ins1l = new_ins1 & 0x3ffff; + p->ins1u = (new_ins1>>18) & 0x7fffff; + ia64_fc(p); + } + + /* + * Do necessary serialization. + */ + ia64_sync_i(); + ia64_srlz_i(); + } int diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/smp.c linux.ac/arch/ia64/sn/sn1/smp.c --- linux.vanilla/arch/ia64/sn/sn1/smp.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/sn1/smp.c Tue Apr 10 18:12:08 2001 @@ -124,10 +124,10 @@ #ifdef CONFIG_SMP +#ifdef PTC_NOTYET static void __init process_sal_ptc_domain_info(ia64_sal_ptc_domain_info_t *di, int domain) { -#ifdef PTC_NOTYET ia64_sal_ptc_domain_proc_entry_t *pe; int i, sapicid, cpuid; @@ -138,7 +138,6 @@ sn_sapicid_info[cpuid].domain = domain; sn_sapicid_info[cpuid].sapicid = sapicid; } -#endif } @@ -153,6 +152,7 @@ process_sal_ptc_domain_info(di, i); } } +#endif void __init @@ -179,7 +179,7 @@ { #ifdef PTC_NOTYET - sn_sapicid_info[0].sapicid = hard_processor_sapicid(); + sn_sapicid_info[0].sapicid = hard_smp_processor_id(); #endif } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/sn1_asm.S linux.ac/arch/ia64/sn/sn1/sn1_asm.S --- linux.vanilla/arch/ia64/sn/sn1/sn1_asm.S Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/sn1/sn1_asm.S Tue Apr 10 18:12:08 2001 @@ -4,3 +4,146 @@ * Copyright (C) 2000 Jack Steiner (steiner@sgi.com) */ +#include <linux/config.h> +#ifdef CONFIG_IA64_SGI_AUTOTEST + +// Testing only. +// Routine will cause MCAs +// zzzmsa(n) +// n=0 MCA via duplicate TLB dropin +// n=0 MCA via read of garbage address +// + +#define ITIR(key, ps) ((key<<8) | (ps<<2)) +#define TLB_PAGESIZE 28 // Use 256MB pages for now. + + .global zzzmca + .proc zzzmca +zzzmca: + alloc loc4 = ar.pfs,2,8,1,0;; + cmp.ne p6,p0=r32,r0;; + movl r2=0x2dead + movl r3=0x3dead + movl r15=0x15dead + movl r16=0x16dead + movl r31=0x31dead + movl loc0=0x34beef + movl loc1=0x35beef + movl loc2=0x36beef + movl loc3=0x37beef + movl out0=0x42beef + + movl r20=0x32feed;; + mov ar32=r20 + movl r20=0x36feed;; + mov ar36=r20 + movl r20=0x65feed;; + mov ar65=r20 + movl r20=0x66feed;; + mov ar66=r20 + +(p6) br.cond.sptk 1f + + rsm 0x2000;; + srlz.d; + mov r11 = 1 + mov r3 = ITIR(0,TLB_PAGESIZE);; + mov cr.itir = r3 + mov r10 = 0;; + itr.d dtr[r11] = r10;; + mov r11 = 2 + + itr.d dtr[r11] = r10;; + br 9f + +1: movl r8=0xfe00000048;; + ld8 r9=[r8];; + mf + mf.a + srlz.d + +9: mov ar.pfs=loc4 + br.ret.sptk rp + + .endp zzzmca + + .global zzzspec + .proc zzzspec +zzzspec: + mov r8=r32 + movl r9=0xe000000000000000 + movl r10=0x4000;; + ld8.s r16=[r8];; + ld8.s r17=[r9];; + add r8=r8,r10;; + ld8.s r18=[r8];; + add r8=r8,r10;; + ld8.s r19=[r8];; + add r8=r8,r10;; + ld8.s r20=[r8];; + mov r8=r0 + tnat.nz p6,p0=r16 + tnat.nz p7,p0=r17 + tnat.nz p8,p0=r18 + tnat.nz p9,p0=r19 + tnat.nz p10,p0=r20;; + (p6) dep r8=-1,r8,0,1;; + (p7) dep r8=-1,r8,1,1;; + (p8) dep r8=-1,r8,2,1;; + (p9) dep r8=-1,r8,3,1;; + (p10) dep r8=-1,r8,4,1;; + br.ret.sptk rp + .endp zzzspec + + .global zzzspec2 + .proc zzzspec2 +zzzspec2: + cmp.eq p6,p7=r2,r2 + movl r16=0xc0000a0001000020 + ;; + mf + ;; + ld8 r9=[r16] + (p6) br.spnt 1f + ld8 r10=[r32] + ;; + 1: mf.a + mf + + ld8 r9=[r16];; + cmp.ne p6,p7=r9,r16 + (p6) br.spnt 1f + ld8 r10=[r32] + ;; + 1: mf.a + mf + + ld8 r9=[r33];; + cmp.ne p6,p7=r9,r33 + (p6) br.spnt 1f + ld8 r10=[r32] + ;; + 1: mf.a + mf + + tpa r23=r32 + add r20=512,r33 + add r21=1024,r33;; + ld8 r9=[r20] + ld8 r10=[r21];; + nop.i 0 + { .mib + nop.m 0 + cmp.ne p6,p7=r10,r33 + (p6) br.spnt 1f + } + ld8 r10=[r32] + ;; + 1: mf.a + mf + br.ret.sptk rp + + .endp zzzspec + +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/sn1_ksyms.c linux.ac/arch/ia64/sn/sn1/sn1_ksyms.c --- linux.vanilla/arch/ia64/sn/sn1/sn1_ksyms.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ia64/sn/sn1/sn1_ksyms.c Tue Apr 10 18:12:08 2001 @@ -0,0 +1,39 @@ +/* + * 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) 2000 Silicon Graphics, Inc. + * Copyright (C) 2000 Jesse Barnes (jbarnes@sgi.com) + */ + + +/* + * Architecture-specific kernel symbols + */ + +#include <linux/module.h> + +#include <asm/machvec.h> + +/* + * I/O routines + */ +EXPORT_SYMBOL(sn1_outb); +EXPORT_SYMBOL(sn1_outl); +EXPORT_SYMBOL(sn1_outw); +EXPORT_SYMBOL(sn1_inw); +EXPORT_SYMBOL(sn1_inb); +EXPORT_SYMBOL(sn1_inl); + +/* + * other stuff (more to be added later, cleanup then) + */ +EXPORT_SYMBOL(sn1_pci_map_sg); +EXPORT_SYMBOL(sn1_pci_unmap_sg); +EXPORT_SYMBOL(sn1_pci_alloc_consistent); +EXPORT_SYMBOL(sn1_pci_free_consistent); +EXPORT_SYMBOL(sn1_dma_address); + +#include <linux/mm.h> +EXPORT_SYMBOL(alloc_pages); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/sv.c linux.ac/arch/ia64/sn/sn1/sv.c --- linux.vanilla/arch/ia64/sn/sn1/sv.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ia64/sn/sn1/sv.c Tue Apr 10 18:12:08 2001 @@ -0,0 +1,551 @@ +/* + * 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) 2000 Silicon Graphics, Inc. All rights reserved + * + * This implemenation of synchronization variables is heavily based on + * one done by Steve Lord <lord@sgi.com> + * + * Paul Cassella <pwc@sgi.com> + */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/init.h> + +#include <asm/semaphore.h> +#include <asm/hardirq.h> +#include <asm/softirq.h> +#include <asm/current.h> + +#include <asm/sn/sv.h> + +/* Define this to have sv_test() run some simple tests. + kernel_thread() must behave as expected when this is called. */ +#undef RUN_SV_TEST + +#define DEBUG + +/* Set up some macros so sv_wait(), sv_signal(), and sv_broadcast() + can sanity check interrupt state on architectures where we know + how. */ +#ifdef DEBUG + #define SV_DEBUG_INTERRUPT_STATE + #ifdef __mips64 + #define SV_TEST_INTERRUPTS_ENABLED(flags) ((flags & 0x1) != 0) + #define SV_TEST_INTERRUPTS_DISABLED(flags) ((flags & 0x1) == 0) + #define SV_INTERRUPT_TEST_WORKERS 31 + #elif defined(__ia64) + #define SV_TEST_INTERRUPTS_ENABLED(flags) ((flags & 0x4000) != 0) + #define SV_TEST_INTERRUPTS_DISABLED(flags) ((flags & 0x4000) == 0) + #define SV_INTERRUPT_TEST_WORKERS 4 /* simulator's slow */ + #else + #undef SV_DEBUG_INTERRUPT_STATE + #define SV_INTERRUPT_TEST_WORKERS 4 /* reasonable? default. */ + #endif /* __mips64 */ +#endif /* DEBUG */ + + +/* XXX FIXME hack hack hack. Our mips64 tree is from before the + switch to WQ_FLAG_EXCLUSIVE, and our ia64 tree is from after it. */ +#ifdef TASK_EXCLUSIVE + #undef EXCLUSIVE_IN_QUEUE +#else + #define EXCLUSIVE_IN_QUEUE + #define TASK_EXCLUSIVE 0 /* for the set_current_state() in sv_wait() */ +#endif + + +static inline void sv_lock(sv_t *sv) { + spin_lock(&sv->sv_lock); +} + +static inline void sv_unlock(sv_t *sv) { + spin_unlock(&sv->sv_lock); +} + +/* up() is "extern inline", so we can't pass its address to sv_wait. + Use this function's address instead. */ +static void up_wrapper(struct semaphore *sem) { + up(sem); +} + +/* spin_unlock() is sometimes a macro. */ +static void spin_unlock_wrapper(spinlock_t *s) { + spin_unlock(s); +} + +/* XXX Perhaps sv_wait() should do the switch() each time and avoid + the extra indirection and the need for the _wrapper functions? */ + +static inline void sv_set_mon_type(sv_t *sv, int type) { + switch (type) { + case SV_MON_SPIN: + sv->sv_mon_unlock_func = + (sv_mon_unlock_func_t)spin_unlock_wrapper; + break; + case SV_MON_SEMA: + sv->sv_mon_unlock_func = + (sv_mon_unlock_func_t)up_wrapper; + if(sv->sv_flags & SV_INTS) { + printk(KERN_ERR "sv_set_mon_type: The monitor lock " + "cannot be shared with interrupts if it is a " + "semaphore!\n"); + BUG(); + } + if(sv->sv_flags & SV_BHS) { + printk(KERN_ERR "sv_set_mon_type: The monitor lock " + "cannot be shared with bottom-halves if it is " + "a semaphore!\n"); + BUG(); + } + break; +#if 0 + /* + * If needed, and will need to think about interrupts. This + * may be needed, for example, if someone wants to use sv's + * with something like dev_base; writers need to hold two + * locks. + */ + case SV_MON_CUSTOM: + { + struct sv_mon_custom *c = lock; + sv->sv_mon_unlock_func = c->sv_mon_unlock_func; + sv->sv_mon_lock = c->sv_mon_lock; + break; + } +#endif + + default: + printk(KERN_ERR "sv_set_mon_type: unknown type %d (0x%x)! " + "(flags 0x%x)\n", type, type, sv->sv_flags); + BUG(); + break; + } + sv->sv_flags |= type; +} + +static inline void sv_set_ord(sv_t *sv, int ord) { + if (!ord) + ord = SV_ORDER_DEFAULT; + + if (ord != SV_ORDER_FIFO && ord != SV_ORDER_LIFO) { + printk(KERN_EMERG "sv_set_ord: unknown order %d (0x%x)! ", + ord, ord); + BUG(); + } + + sv->sv_flags |= ord; +} + +void sv_init(sv_t *sv, sv_mon_lock_t *lock, int flags) +{ + int ord = flags & SV_ORDER_MASK; + int type = flags & SV_MON_MASK; + + /* Copy all non-order, non-type flags */ + sv->sv_flags = (flags & ~(SV_ORDER_MASK | SV_MON_MASK)); + + if((sv->sv_flags & (SV_INTS | SV_BHS)) == (SV_INTS | SV_BHS)) { + printk(KERN_ERR "sv_init: do not set both SV_INTS and SV_BHS, only SV_INTS.\n"); + BUG(); + } + + sv_set_ord(sv, ord); + sv_set_mon_type(sv, type); + + /* If lock is NULL, we'll get it from sv_wait_compat() (and + ignore it in sv_signal() and sv_broadcast()). */ + sv->sv_mon_lock = lock; + + spin_lock_init(&sv->sv_lock); + init_waitqueue_head(&sv->sv_waiters); +} + +/* + * The associated lock must be locked on entry. It is unlocked on return. + * + * Return values: + * + * n < 0 : interrupted, -n jiffies remaining on timeout, or -1 if timeout == 0 + * n = 0 : timeout expired + * n > 0 : sv_signal()'d, n jiffies remaining on timeout, or 1 if timeout == 0 + */ +signed long sv_wait(sv_t *sv, int sv_wait_flags, unsigned long timeout) +{ + DECLARE_WAITQUEUE( wait, current ); + unsigned long flags; + signed long ret = 0; + +#ifdef SV_DEBUG_INTERRUPT_STATE + { + unsigned long flags; + __save_flags(flags); + + if(sv->sv_flags & SV_INTS) { + if(SV_TEST_INTERRUPTS_ENABLED(flags)) { + printk(KERN_ERR "sv_wait: SV_INTS and interrupts " + "enabled (flags: 0x%lx)\n", flags); + BUG(); + } + } else { + if (SV_TEST_INTERRUPTS_DISABLED(flags)) { + printk(KERN_WARNING "sv_wait: !SV_INTS and interrupts " + "disabled! (flags: 0x%lx)\n", flags); + } + } + } +#endif /* SV_DEBUG_INTERRUPT_STATE */ + + sv_lock(sv); + + sv->sv_mon_unlock_func(sv->sv_mon_lock); + + /* Add ourselves to the wait queue and set the state before + * releasing the sv_lock so as to avoid racing with the + * wake_up() in sv_signal() and sv_broadcast(). + */ + + /* don't need the _irqsave part, but there is no wq_write_lock() */ + wq_write_lock_irqsave(&sv->sv_waiters.lock, flags); + +#ifdef EXCLUSIVE_IN_QUEUE + wait.flags |= WQ_FLAG_EXCLUSIVE; +#endif + + switch(sv->sv_flags & SV_ORDER_MASK) { + case SV_ORDER_FIFO: + __add_wait_queue_tail(&sv->sv_waiters, &wait); + break; + case SV_ORDER_FILO: + __add_wait_queue(&sv->sv_waiters, &wait); + break; + default: + printk(KERN_ERR "sv_wait: unknown order! (sv: 0x%p, flags: 0x%x)\n", + sv, sv->sv_flags); + BUG(); + } + wq_write_unlock_irqrestore(&sv->sv_waiters.lock, flags); + + if(sv_wait_flags & SV_WAIT_SIG) + set_current_state(TASK_EXCLUSIVE | TASK_INTERRUPTIBLE ); + else + set_current_state(TASK_EXCLUSIVE | TASK_UNINTERRUPTIBLE); + + spin_unlock(&sv->sv_lock); + + if(sv->sv_flags & SV_INTS) + local_irq_enable(); + else if(sv->sv_flags & SV_BHS) + local_bh_enable(); + + if (timeout) + ret = schedule_timeout(timeout); + else + schedule(); + + if(current->state != TASK_RUNNING) /* XXX Is this possible? */ { + printk(KERN_ERR "sv_wait: state not TASK_RUNNING after " + "schedule().\n"); + set_current_state(TASK_RUNNING); + } + + remove_wait_queue(&sv->sv_waiters, &wait); + + /* Return cases: + - woken by a sv_signal/sv_broadcast + - woken by a signal + - woken by timeout expiring + */ + + /* XXX This isn't really accurate; we may have been woken + before the signal anyway.... */ + if(signal_pending(current)) + return timeout ? -ret : -1; + return timeout ? ret : 1; +} + + +void sv_signal(sv_t *sv) +{ + /* If interrupts can acquire this lock, they can also acquire the + sv_mon_lock, which we must already have to have called this, so + interrupts must be disabled already. If interrupts cannot + contend for this lock, we don't have to worry about it. */ + +#ifdef SV_DEBUG_INTERRUPT_STATE + if(sv->sv_flags & SV_INTS) { + unsigned long flags; + __save_flags(flags); + if(SV_TEST_INTERRUPTS_ENABLED(flags)) + printk(KERN_ERR "sv_signal: SV_INTS and " + "interrupts enabled! (flags: 0x%lx)\n", flags); + } +#endif /* SV_DEBUG_INTERRUPT_STATE */ + + sv_lock(sv); + wake_up(&sv->sv_waiters); + sv_unlock(sv); +} + +void sv_broadcast(sv_t *sv) +{ +#ifdef SV_DEBUG_INTERRUPT_STATE + if(sv->sv_flags & SV_INTS) { + unsigned long flags; + __save_flags(flags); + if(SV_TEST_INTERRUPTS_ENABLED(flags)) + printk(KERN_ERR "sv_broadcast: SV_INTS and " + "interrupts enabled! (flags: 0x%lx)\n", flags); + } +#endif /* SV_DEBUG_INTERRUPT_STATE */ + + sv_lock(sv); + wake_up_all(&sv->sv_waiters); + sv_unlock(sv); +} + +void sv_destroy(sv_t *sv) +{ + if(!spin_trylock(&sv->sv_lock)) { + printk(KERN_ERR "sv_destroy: someone else has sv 0x%p locked!\n", sv); + BUG(); + } + + /* XXX Check that the waitqueue is empty? + Mark the sv destroyed? + */ +} + + +#ifdef RUN_SV_TEST + +static DECLARE_MUTEX_LOCKED(talkback); +static DECLARE_MUTEX_LOCKED(sem); +sv_t sv; +sv_t sv_filo; + +static int sv_test_1_w(void *arg) +{ + printk("sv_test_1_w: acquiring spinlock 0x%p...\n", arg); + + spin_lock((spinlock_t*)arg); + printk("sv_test_1_w: spinlock acquired, waking sv_test_1_s.\n"); + + up(&sem); + + printk("sv_test_1_w: sv_spin_wait()'ing.\n"); + + sv_spin_wait(&sv, arg); + + printk("sv_test_1_w: talkback.\n"); + up(&talkback); + + printk("sv_test_1_w: exiting.\n"); + return 0; +} + +static int sv_test_1_s(void *arg) +{ + printk("sv_test_1_s: waiting for semaphore.\n"); + down(&sem); + printk("sv_test_1_s: semaphore acquired. Acquiring spinlock.\n"); + spin_lock((spinlock_t*)arg); + printk("sv_test_1_s: spinlock acquired. sv_signaling.\n"); + sv_signal(&sv); + printk("sv_test_1_s: talkback.\n"); + up(&talkback); + printk("sv_test_1_s: exiting.\n"); + return 0; + +} + +static int count; +static DECLARE_MUTEX(monitor); + +static int sv_test_2_w(void *arg) +{ + int dummy = count++; + sv_t *sv = (sv_t *)arg; + + down(&monitor); + up(&talkback); + printk("sv_test_2_w: thread %d started, sv_waiting.\n", dummy); + sv_sema_wait(sv, &monitor); + printk("sv_test_2_w: thread %d woken, exiting.\n", dummy); + up(&sem); + return 0; +} + +static int sv_test_2_s_1(void *arg) +{ + int i; + sv_t *sv = (sv_t *)arg; + + down(&monitor); + for(i = 0; i < 3; i++) { + printk("sv_test_2_s_1: waking one thread.\n"); + sv_signal(sv); + down(&sem); + } + + printk("sv_test_2_s_1: signaling and broadcasting again. Nothing should happen.\n"); + sv_signal(sv); + sv_broadcast(sv); + sv_signal(sv); + sv_broadcast(sv); + + printk("sv_test_2_s_1: talkbacking.\n"); + up(&talkback); + up(&monitor); + return 0; +} + +static int sv_test_2_s(void *arg) +{ + int i; + sv_t *sv = (sv_t *)arg; + + down(&monitor); + for(i = 0; i < 3; i++) { + printk("sv_test_2_s: waking one thread (should be %d.)\n", i); + sv_signal(sv); + down(&sem); + } + + printk("sv_test_3_s: waking remaining threads with broadcast.\n"); + sv_broadcast(sv); + for(; i < 10; i++) + down(&sem); + + printk("sv_test_3_s: sending talkback.\n"); + up(&talkback); + + printk("sv_test_3_s: exiting.\n"); + up(&monitor); + return 0; +} + + +static void big_test(sv_t *sv) +{ + int i; + + count = 0; + + for(i = 0; i < 3; i++) { + printk("big_test: spawning thread %d.\n", i); + kernel_thread(sv_test_2_w, sv, 0); + down(&talkback); + } + + printk("big_test: spawning first wake-up thread.\n"); + kernel_thread(sv_test_2_s_1, sv, 0); + + down(&talkback); + printk("big_test: talkback happened.\n"); + + + for(i = 3; i < 13; i++) { + printk("big_test: spawning thread %d.\n", i); + kernel_thread(sv_test_2_w, sv, 0); + down(&talkback); + } + + printk("big_test: spawning wake-up thread.\n"); + kernel_thread(sv_test_2_s, sv, 0); + + down(&talkback); +} + +sv_t int_test_sv; +spinlock_t int_test_spin = SPIN_LOCK_UNLOCKED; +int int_test_ready; +static int irqtestcount; + +static int interrupt_test_worker(void *unused) +{ + int id = ++irqtestcount; + int it = 0; + unsigned long flags, flags2; + + printk("ITW: thread %d started.\n", id); + + while(1) { + __save_flags(flags2); + if(jiffies % 3) { + printk("ITW %2d %5d: irqsaving (%lx)\n", id, it, flags2); + spin_lock_irqsave(&int_test_spin, flags); + } else { + printk("ITW %2d %5d: spin_lock_irqing (%lx)\n", id, it, flags2); + spin_lock_irq(&int_test_spin); + } + + __save_flags(flags2); + printk("ITW %2d %5d: locked, sv_waiting (%lx).\n", id, it, flags2); + sv_wait(&int_test_sv, 0, 0); + + __save_flags(flags2); + printk("ITW %2d %5d: wait finished (%lx), pausing\n", id, it, flags2); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(jiffies & 0xf); + if(current->state != TASK_RUNNING) + printk("ITW: current->state isn't RUNNING after schedule!\n"); + it++; + } +} + +static void interrupt_test(void) +{ + int i; + + printk("interrupt_test: initing sv.\n"); + sv_init(&int_test_sv, &int_test_spin, SV_MON_SPIN | SV_INTS); + + for(i = 0; i < SV_INTERRUPT_TEST_WORKERS; i++) { + printk("interrupt_test: starting test thread %d.\n", i); + kernel_thread(interrupt_test_worker, 0, 0); + } + printk("interrupt_test: done with init part.\n"); + int_test_ready = 1; +} + +int sv_test(void) +{ + spinlock_t s = SPIN_LOCK_UNLOCKED; + + sv_init(&sv, &s, SV_MON_SPIN); + printk("sv_test: starting sv_test_1_w.\n"); + kernel_thread(sv_test_1_w, &s, 0); + printk("sv_test: starting sv_test_1_s.\n"); + kernel_thread(sv_test_1_s, &s, 0); + + printk("sv_test: waiting for talkback.\n"); + down(&talkback); down(&talkback); + printk("sv_test: talkback happened, sv_destroying.\n"); + sv_destroy(&sv); + + count = 0; + + printk("sv_test: beginning big_test on sv.\n"); + + sv_init(&sv, &monitor, SV_MON_SEMA); + big_test(&sv); + sv_destroy(&sv); + + printk("sv_test: beginning big_test on sv_filo.\n"); + sv_init(&sv_filo, &monitor, SV_MON_SEMA | SV_ORDER_FILO); + big_test(&sv_filo); + sv_destroy(&sv_filo); + + interrupt_test(); + + printk("sv_test: done.\n"); + return 0; +} + +__initcall(sv_test); + +#endif /* RUN_SV_TEST */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/synergy.c linux.ac/arch/ia64/sn/sn1/synergy.c --- linux.vanilla/arch/ia64/sn/sn1/synergy.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/sn1/synergy.c Tue Apr 10 18:12:08 2001 @@ -8,9 +8,12 @@ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/spinlock.h> +#include <linux/proc_fs.h> #include <asm/ptrace.h> #include <linux/devfs_fs_kernel.h> @@ -26,8 +29,6 @@ void setclear_mask_a(int irq, int cpuid, int set); void * kmalloc(size_t size, int flags); -extern struct sn1_cnode_action_list *sn1_node_actions[]; - void synergy_intr_alloc(int bit, int cpuid) { @@ -40,9 +41,7 @@ { int irq; unsigned is_b; -int nasid; -nasid = cpuid_to_nasid(cpuid); irq = bit_pos_to_irq(bit); is_b = (cpuid_to_slice(cpuid)) & 1; @@ -202,3 +201,229 @@ REMOTE_SYNERGY_STORE(nasid, synergy, reg, val); } } + +#if defined(CONFIG_IA64_SGI_SYNERGY_PERF) + +/* + * Synergy perf registers. Multiplexed via timer_interrupt + */ +static struct proc_dir_entry *synergy_perf_proc = NULL; + +/* + * read handler for /proc/synergy + */ +static int +synergy_perf_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + cnodeid_t cnode; + nodepda_t *npdap; + synergy_perf_t *p; + int len = 0; + + len += sprintf(page+len, "# cnode module slot event synergy-A synergy-B\n"); + + /* walk the event list for each node */ + for (cnode=0; cnode < numnodes; cnode++) { + npdap = NODEPDA(cnode); + if (npdap->synergy_perf_enabled == 0) { + len += sprintf(page+len, "# DISABLED\n"); + break; + } + + spin_lock_irq(&npdap->synergy_perf_lock); + for (p = npdap->synergy_perf_first; p;) { + uint64_t cnt_a=0, cnt_b=0; + + if (p->intervals > 0) { + cnt_a = p->counts[0] * npdap->synergy_active_intervals / p->intervals; + cnt_b = p->counts[1] * npdap->synergy_active_intervals / p->intervals; + } + + len += sprintf(page+len, "%d %d %d %12lx %lu %lu\n", + (int)cnode, (int)npdap->module_id, (int)npdap->slotdesc, + p->modesel, cnt_a, cnt_b); + + p = p->next; + if (p == npdap->synergy_perf_first) + break; + } + spin_unlock_irq(&npdap->synergy_perf_lock); + } + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + + return len; +} + +static int +synergy_perf_append(uint64_t modesel) +{ + int cnode; + nodepda_t *npdap; + synergy_perf_t *p; + int err = 0; + + /* bit 45 is enable */ + modesel |= (1UL << 45); + + for (cnode=0; cnode < numnodes; cnode++) { + /* for each node, insert a new synergy_perf entry */ + if ((npdap = NODEPDA(cnode)) == NULL) { + printk("synergy_perf_append: cnode=%d NODEPDA(cnode)==NULL, nodepda=%p\n", cnode, nodepda); + continue; + } + + /* XX use kmem_alloc_node() when it is implemented */ + p = (synergy_perf_t *)kmalloc(sizeof(synergy_perf_t), GFP_KERNEL); + if (p == NULL) + err = -ENOMEM; + else { + memset(p, 0, sizeof(synergy_perf_t)); + p->modesel = modesel; + if (npdap->synergy_perf_data == NULL) { + /* circular list */ + p->next = p; + npdap->synergy_perf_data = p; + npdap->synergy_perf_first = p; + } + else { + /* + * Jumble up the insertion order so we get better sampling. + * Once the list is complete, "first" stays the same so the + * reporting order is consistent. + */ + p->next = npdap->synergy_perf_first->next; + npdap->synergy_perf_first->next = p; + npdap->synergy_perf_first = p->next; + } + } + } + + return err; +} + +static int +synergy_perf_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int cnode; + nodepda_t *npdap; + uint64_t modesel; + char cmd[64]; + extern long atoi(char *); + + if (count == sizeof(uint64_t)) { + if (copy_from_user(&modesel, buffer, sizeof(uint64_t))) + return -EFAULT; + synergy_perf_append(modesel); + } + else { + if (copy_from_user(cmd, buffer, count < sizeof(cmd) ? count : sizeof(cmd))) + return -EFAULT; + if (strncmp(cmd, "enable", 6) == 0) { + /* enable counting */ + for (cnode=0; cnode < numnodes; cnode++) { + npdap = NODEPDA(cnode); + npdap->synergy_perf_enabled = 1; + } + printk("NOTICE: synergy perf counting enabled\n"); + } + else + if (strncmp(cmd, "disable", 7) == 0) { + /* disable counting */ + for (cnode=0; cnode < numnodes; cnode++) { + npdap = NODEPDA(cnode); + npdap->synergy_perf_enabled = 0; + } + printk("NOTICE: synergy perf counting disabled\n"); + } + else + if (strncmp(cmd, "frequency", 9) == 0) { + /* set the update frequency (timer-interrupts per update) */ + int freq; + + if (count < 12) + return -EINVAL; + freq = atoi(cmd + 10); + if (freq <= 0 || freq > 100) + return -EINVAL; + for (cnode=0; cnode < numnodes; cnode++) { + npdap = NODEPDA(cnode); + npdap->synergy_perf_freq = (uint64_t)freq; + } + printk("NOTICE: synergy perf freq set to %d\n", freq); + } + else + return -EINVAL; + } + + return count; +} + +void +synergy_perf_update(int cpu) +{ + nasid_t nasid; + cnodeid_t cnode = cpuid_to_cnodeid(cpu); + struct nodepda_s *npdap; + extern struct nodepda_s *nodepda; + + if (nodepda == NULL || (npdap=NODEPDA(cnode)) == NULL || npdap->synergy_perf_enabled == 0 || + npdap->synergy_perf_data == NULL) { + /* I/O not initialized, or not enabled, or no events to monitor */ + return; + } + + if (npdap->synergy_inactive_intervals++ % npdap->synergy_perf_freq != 0) { + /* don't multiplex on every timer interrupt */ + return; + } + + /* + * Read registers for last interval and increment counters. + * Hold the per-node synergy_perf_lock so concurrent readers get + * consistent values. + */ + spin_lock_irq(&npdap->synergy_perf_lock); + + nasid = cpuid_to_nasid(cpu); + npdap->synergy_active_intervals++; + npdap->synergy_perf_data->intervals++; + + npdap->synergy_perf_data->counts[0] += 0xffffffffffUL & + REMOTE_SYNERGY_LOAD(nasid, 0, PERF_CNTR0_A); + + npdap->synergy_perf_data->counts[1] += 0xffffffffffUL & + REMOTE_SYNERGY_LOAD(nasid, 1, PERF_CNTR0_B); + + /* skip to next in circular list */ + npdap->synergy_perf_data = npdap->synergy_perf_data->next; + + spin_unlock_irq(&npdap->synergy_perf_lock); + + /* set the counter 0 selection modes for both A and B */ + REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTL0_A, npdap->synergy_perf_data->modesel); + REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTL0_B, npdap->synergy_perf_data->modesel); + + /* and reset the counter registers to zero */ + REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTR0_A, 0UL); + REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTR0_B, 0UL); +} + +void +synergy_perf_init(void) +{ + if ((synergy_perf_proc = create_proc_entry("synergy", 0644, NULL)) != NULL) { + synergy_perf_proc->read_proc = synergy_perf_read_proc; + synergy_perf_proc->write_proc = synergy_perf_write_proc; + printk("markgw: synergy_perf_init()\n"); + } +} + +#endif /* CONFIG_IA64_SGI_SYNERGY_PERF */ + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/tools/print_offsets.awk linux.ac/arch/ia64/tools/print_offsets.awk --- linux.vanilla/arch/ia64/tools/print_offsets.awk Sat Jul 15 00:08:12 2000 +++ linux.ac/arch/ia64/tools/print_offsets.awk Tue Apr 10 18:12:08 2001 @@ -28,6 +28,10 @@ inside_table = 0 } +/.*[.]rodata/ { + inside_table = 0 +} + { if (inside_table) { if ($1 == "//") getline; @@ -61,7 +65,7 @@ inside_table = 1 } -/tab#:/ { +/tab\#:/ { inside_table = 1 } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/tools/print_offsets.c linux.ac/arch/ia64/tools/print_offsets.c --- linux.vanilla/arch/ia64/tools/print_offsets.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/tools/print_offsets.c Tue Apr 10 18:12:15 2001 @@ -1,8 +1,8 @@ /* * Utility to generate asm-ia64/offsets.h. * - * Copyright (C) 1999-2000 Hewlett-Packard Co - * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> * * Note that this file has dual use: when building the kernel * natively, the file is translated into a binary and executed. When @@ -45,9 +45,8 @@ { "IA64_PT_REGS_SIZE", sizeof (struct pt_regs) }, { "IA64_SWITCH_STACK_SIZE", sizeof (struct switch_stack) }, { "IA64_SIGINFO_SIZE", sizeof (struct siginfo) }, -#ifdef CONFIG_IA64_NEW_UNWIND + { "IA64_CPU_SIZE", sizeof (struct cpuinfo_ia64) }, { "UNW_FRAME_INFO_SIZE", sizeof (struct unw_frame_info) }, -#endif { "", 0 }, /* spacer */ { "IA64_TASK_PTRACE_OFFSET", offsetof (struct task_struct, ptrace) }, { "IA64_TASK_SIGPENDING_OFFSET", offsetof (struct task_struct, sigpending) }, @@ -58,6 +57,9 @@ #ifdef CONFIG_IA32_SUPPORT { "IA64_TASK_THREAD_SIGMASK_OFFSET",offsetof (struct task_struct, thread.un.sigmask) }, #endif +#ifdef CONFIG_PERFMON + { "IA64_TASK_PFM_NOTIFY_OFFSET", offsetof(struct task_struct, thread.pfm_pend_notify) }, +#endif { "IA64_TASK_PID_OFFSET", offsetof (struct task_struct, pid) }, { "IA64_TASK_MM_OFFSET", offsetof (struct task_struct, mm) }, { "IA64_PT_REGS_CR_IPSR_OFFSET", offsetof (struct pt_regs, cr_ipsr) }, @@ -157,6 +159,11 @@ { "IA64_SIGCONTEXT_FR6_OFFSET", offsetof (struct sigcontext, sc_fr[6]) }, { "IA64_CLONE_VFORK", CLONE_VFORK }, { "IA64_CLONE_VM", CLONE_VM }, + { "IA64_CPU_IRQ_COUNT_OFFSET", offsetof (struct cpuinfo_ia64, irq_stat.f.irq_count) }, + { "IA64_CPU_BH_COUNT_OFFSET", offsetof (struct cpuinfo_ia64, irq_stat.f.bh_count) }, + { "IA64_CPU_SOFTIRQ_ACTIVE_OFFSET", offsetof (struct cpuinfo_ia64, softirq.active) }, + { "IA64_CPU_SOFTIRQ_MASK_OFFSET", offsetof (struct cpuinfo_ia64, softirq.mask) }, + { "IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET", offsetof (struct cpuinfo_ia64, phys_stacked_size_p8) }, }; static const char *tabs = "\t\t\t\t\t\t\t\t\t\t"; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/vmlinux.lds.S linux.ac/arch/ia64/vmlinux.lds.S --- linux.vanilla/arch/ia64/vmlinux.lds.S Sat Aug 12 03:09:06 2000 +++ linux.ac/arch/ia64/vmlinux.lds.S Tue Apr 10 18:12:15 2001 @@ -5,10 +5,18 @@ OUTPUT_FORMAT("elf64-ia64-little") OUTPUT_ARCH(ia64) -ENTRY(_start) +ENTRY(phys_start) SECTIONS { + /* Sections to be discarded */ + /DISCARD/ : { + *(.text.exit) + *(.data.exit) + *(.exitcall.exit) + } + v = PAGE_OFFSET; /* this symbol is here to make debugging easier... */ + phys_start = _start - PAGE_OFFSET; . = KERNEL_START; @@ -16,11 +24,11 @@ _stext = .; .text : AT(ADDR(.text) - PAGE_OFFSET) { - *(__ivt_section) + *(.text.ivt) /* these are not really text pages, but the zero page needs to be in a fixed location: */ *(__special_page_section) __start_gate_section = .; - *(__gate_section) + *(.text.gate) __stop_gate_section = .; *(.text) } @@ -34,7 +42,7 @@ /* Read-only data */ - __gp = ALIGN(8) + 0x200000; + __gp = ALIGN(16) + 0x200000; /* gp must be 16-byte aligned for exc. table */ /* Global data */ _data = .; @@ -60,13 +68,19 @@ { *(__ksymtab) } __stop___ksymtab = .; - /* Unwind table */ + __start___kallsyms = .; /* All kernel symbols for debugging */ + __kallsyms : AT(ADDR(__kallsyms) - PAGE_OFFSET) + { *(__kallsyms) } + __stop___kallsyms = .; + + /* Unwind info & table: */ + .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - PAGE_OFFSET) + { *(.IA_64.unwind_info*) } + . = ALIGN(8); ia64_unw_start = .; .IA_64.unwind : AT(ADDR(.IA_64.unwind) - PAGE_OFFSET) - { *(.IA_64.unwind) } + { *(.IA_64.unwind*) } ia64_unw_end = .; - .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - PAGE_OFFSET) - { *(.IA_64.unwind_info) } .rodata : AT(ADDR(.rodata) - PAGE_OFFSET) { *(.rodata) } @@ -129,13 +143,6 @@ { *(.bss) *(COMMON) } . = ALIGN(64 / 8); _end = .; - - /* Sections to be discarded */ - /DISCARD/ : { - *(.text.exit) - *(.data.exit) - *(.exitcall.exit) - } /* Stabs debugging sections. */ .stab 0 : { *(.stab) } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/m68k/amiga/config.c linux.ac/arch/m68k/amiga/config.c --- linux.vanilla/arch/m68k/amiga/config.c Thu Jan 4 21:00:55 2001 +++ linux.ac/arch/m68k/amiga/config.c Tue Apr 3 17:54:31 2001 @@ -769,20 +769,6 @@ return 0; } -void dbprintf(const char *fmt , ...) -{ - static char buf[1024]; - va_list args; - extern void console_print (const char *str); - extern int vsprintf(char * buf, const char * fmt, va_list args); - - va_start(args, fmt); - vsprintf(buf, fmt, args); - va_end(args); - - console_print (buf); -} - static NORET_TYPE void amiga_reset( void ) ATTRIB_NORET; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/m68k/config.in linux.ac/arch/m68k/config.in --- linux.vanilla/arch/m68k/config.in Thu Jan 4 21:00:55 2001 +++ linux.ac/arch/m68k/config.in Tue Apr 10 18:12:27 2001 @@ -487,8 +487,10 @@ fi fi if [ "$CONFIG_APOLLO" = "y" ]; then - bool 'Support for DN serial port (dummy)' CONFIG_SERIAL + bool 'Support for DN serial port (dummy)' CONFIG_DN_SERIAL bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE + + define_tristate CONFIG_SERIAL $CONFIG_DN_SERIAL fi bool 'Support for user serial device modules' CONFIG_USERIAL bool 'Watchdog Timer Support' CONFIG_WATCHDOG diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/m68k/ifpsp060/src/fpsp.S linux.ac/arch/m68k/ifpsp060/src/fpsp.S --- linux.vanilla/arch/m68k/ifpsp060/src/fpsp.S Tue Apr 3 17:31:54 2001 +++ linux.ac/arch/m68k/ifpsp060/src/fpsp.S Tue Apr 10 18:12:27 2001 @@ -19594,7 +19594,7 @@ # in the data register file. If it's actually out in memory, use one of # # the mem_read() routines to fetch it. If the mem_read() access returns # # a failing value, exit through the special facc_in() routine which # -# will create an acess error exception frame from the current exception # +# will create an access error exception frame from the current exception # # frame. # # Immediate data and regular data accesses are separated because # # if an immediate data access fails, the resulting fault status # @@ -24608,7 +24608,7 @@ # made out of the current exception stack frame. # # So, we first call restore() which makes sure that any updated # # -(an)+ register gets returned to its pre-exception value and then # -# we change the stack to an acess error stack frame. # +# we change the stack to an access error stack frame. # # # ######################################################################### diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/m68k/ifpsp060/src/pfpsp.S linux.ac/arch/m68k/ifpsp060/src/pfpsp.S --- linux.vanilla/arch/m68k/ifpsp060/src/pfpsp.S Tue Apr 3 17:31:54 2001 +++ linux.ac/arch/m68k/ifpsp060/src/pfpsp.S Tue Apr 10 18:12:39 2001 @@ -14568,7 +14568,7 @@ # made out of the current exception stack frame. # # So, we first call restore() which makes sure that any updated # # -(an)+ register gets returned to its pre-exception value and then # -# we change the stack to an acess error stack frame. # +# we change the stack to an access error stack frame. # # # ######################################################################### diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/m68k/kernel/setup.c linux.ac/arch/m68k/kernel/setup.c --- linux.vanilla/arch/m68k/kernel/setup.c Thu Jan 4 21:00:55 2001 +++ linux.ac/arch/m68k/kernel/setup.c Tue Apr 3 17:54:32 2001 @@ -39,10 +39,6 @@ #include <linux/blk.h> #endif -#ifndef CONFIG_AMIGA -#define dbprintf printk -#endif - unsigned long m68k_machtype; unsigned long m68k_cputype; unsigned long m68k_fputype; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/m68k/mm/init.c linux.ac/arch/m68k/mm/init.c --- linux.vanilla/arch/m68k/mm/init.c Mon Oct 16 20:58:51 2000 +++ linux.ac/arch/m68k/mm/init.c Tue Apr 3 17:54:32 2001 @@ -31,12 +31,11 @@ #ifdef CONFIG_ATARI #include <asm/atari_stram.h> #endif +#include <asm/tlb.h> -static unsigned long totalram_pages; +mmu_gather_t mmu_gathers[NR_CPUS]; -#ifdef CONFIG_SUN3 -void mmu_emu_reserve_pages(unsigned long max_page); -#endif +unsigned long totalram_pages = 0; int do_check_pgt_cache(int low, int high) { @@ -86,7 +85,7 @@ void show_mem(void) { unsigned long i; - int free = 0, total = 0, reserved = 0, nonshared = 0, shared = 0; + int free = 0, total = 0, reserved = 0, shared = 0; int cached = 0; printk("\nMem-info:\n"); @@ -101,15 +100,12 @@ cached++; else if (!page_count(mem_map+i)) free++; - else if (page_count(mem_map+i) == 1) - nonshared++; else shared += page_count(mem_map+i) - 1; } printk("%d pages of RAM\n",total); printk("%d free pages\n",free); printk("%d reserved pages\n",reserved); - printk("%d pages nonshared\n",nonshared); printk("%d pages shared\n",shared); printk("%d pages swap cached\n",cached); printk("%ld pages in page table cache\n",pgtable_cache_size); @@ -137,17 +133,11 @@ #ifdef CONFIG_ATARI if (MACH_IS_ATARI) - atari_stram_reserve_pages( start_mem ); -#endif - -#ifdef CONFIG_SUN3 - /* reserve rom pages */ - mmu_emu_reserve_pages(max_mapnr); + atari_stram_mem_init_hook(); #endif /* this will put all memory onto the freelists */ totalram_pages = free_all_bootmem(); - printk("tp:%ld\n", totalram_pages); for (tmp = PAGE_OFFSET ; tmp < (unsigned long)high_memory; tmp += PAGE_SIZE) { #if 0 @@ -201,13 +191,15 @@ #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { + int pages = 0; for (; start < end; start += PAGE_SIZE) { ClearPageReserved(virt_to_page(start)); set_page_count(virt_to_page(start), 1); free_page(start); totalram_pages++; + pages++; } - printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); + printk ("Freeing initrd memory: %dk freed\n", pages); } #endif @@ -220,15 +212,8 @@ val->sharedram = 0; val->freeram = nr_free_pages(); val->bufferram = atomic_read(&buffermem_pages); - while (i-- > 0) { - if (PageReserved(mem_map+i)) - continue; - val->totalram++; - if (!page_count(mem_map+i)) - continue; - val->sharedram += page_count(mem_map+i) - 1; - } val->totalhigh = 0; val->freehigh = 0; + val->mem_unit = PAGE_SIZE; return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/m68k/mm/memory.c linux.ac/arch/m68k/mm/memory.c --- linux.vanilla/arch/m68k/mm/memory.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/m68k/mm/memory.c Tue Apr 3 17:54:32 2001 @@ -246,6 +246,10 @@ voff -= m68k_memory[i].size; } while (++i < m68k_num_memory); + /* As a special case allow `__pa(high_memory)'. */ + if (voff == 0) + return m68k_memory[i-1].addr + m68k_memory[i-1].size; + return mm_vtop_fallback(vaddr); } #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/m68k/mm/motorola.c linux.ac/arch/m68k/mm/motorola.c --- linux.vanilla/arch/m68k/mm/motorola.c Tue Aug 8 05:02:27 2000 +++ linux.ac/arch/m68k/mm/motorola.c Tue Apr 10 18:12:39 2001 @@ -286,6 +286,7 @@ } extern char __init_begin, __init_end; +extern unsigned long totalram_pages; void free_initmem(void) { @@ -296,6 +297,7 @@ virt_to_page(addr)->flags &= ~(1 << PG_reserved); set_page_count(virt_to_page(addr), 1); free_page(addr); + totalram_pages++; } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/m68k/q40/config.c linux.ac/arch/m68k/q40/config.c --- linux.vanilla/arch/m68k/q40/config.c Tue Apr 3 17:31:55 2001 +++ linux.ac/arch/m68k/q40/config.c Tue Apr 3 17:54:32 2001 @@ -238,7 +238,7 @@ mach_max_dma_address = 32*1024*1024; /* no DMA at all, but ide-scsi requires it.. */ -/* userfull for early debugging stages writes kernel messages into SRAM */ +/* useful for early debugging stages - writes kernel messages into SRAM */ if (!strncmp( m68k_debug_device,"mem",3 )) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/Makefile linux.ac/arch/mips/Makefile --- linux.vanilla/arch/mips/Makefile Fri Jul 28 02:36:54 2000 +++ linux.ac/arch/mips/Makefile Tue Apr 3 17:54:32 2001 @@ -17,8 +17,10 @@ # ifdef CONFIG_CPU_LITTLE_ENDIAN tool-prefix = mipsel-linux- +output-format = elf32-littlemips else tool-prefix = mips-linux- +output-format = elf32-bigmips endif ifdef CONFIG_CROSSCOMPILE @@ -26,16 +28,16 @@ endif # -# The ELF GCC uses -G0 -mabicalls -fpic as default. We don't need PIC -# code in the kernel since it only slows down the whole thing. For the -# old GCC these options are just the defaults. At some point we might -# make use of global pointer optimizations. +# GCC uses -G0 -mabicalls -fpic as default. We don't want PIC in the kernel +# code since it only slows down the whole thing. At some point we might make +# use of global pointer optimizations but their use of $28 conflicts with +# the current pointer optimization. # # The DECStation requires an ECOFF kernel for remote booting, other MIPS # machines may also. Since BFD is incredibly buggy with respect to # crossformat linking we rely on the elf2ecoff tool for format conversion. # -CFLAGS += -G 0 -mno-abicalls -fno-pic +GCCFLAGS := -G 0 -mno-abicalls -fno-pic LINKFLAGS += -static -G 0 MODFLAGS += -mlong-calls @@ -47,37 +49,63 @@ # CPU-dependent compiler/assembler options for optimization. # ifdef CONFIG_CPU_R3000 -CFLAGS := $(CFLAGS) -mcpu=r3000 -mips1 +GCCFLAGS += -mcpu=r3000 -mips1 +endif +ifdef CONFIG_CPU_R3912 +GCCFLAGS += -mcpu=r3000 -mips1 endif ifdef CONFIG_CPU_R6000 -CFLAGS := $(CFLAGS) -mcpu=r6000 -mips2 -Wa,--trap +GCCFLAGS += -mcpu=r6000 -mips2 -Wa,--trap endif ifdef CONFIG_CPU_R4300 -CFLAGS := $(CFLAGS) -mcpu=r4300 -mips2 -Wa,--trap +GCCFLAGS += -mcpu=r4300 -mips2 -Wa,--trap endif ifdef CONFIG_CPU_R4X00 -CFLAGS := $(CFLAGS) -mcpu=r4600 -mips2 -Wa,--trap +GCCFLAGS += -mcpu=r4600 -mips2 -Wa,--trap +endif +ifdef CONFIG_CPU_MIPS32 +GCCFLAGS += -mcpu=r4600 -mips2 -Wa,--trap endif ifdef CONFIG_CPU_R5000 -CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap +GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap +endif +ifdef CONFIG_CPU_R5432 +GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap endif ifdef CONFIG_CPU_NEVADA -CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap -mmad +GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap -mmad +endif +ifdef CONFIG_CPU_RM7000 +GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap endif ifdef CONFIG_CPU_R8000 -CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap +GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap endif ifdef CONFIG_CPU_R10000 -CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap +GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap endif +ifdef CONFIG_MIPS_FPU_EMULATOR +CORE_FILES +=arch/mips/math-emu/fpu_emulator.o +SUBDIRS +=arch/mips/math-emu +endif + +# +# The pipe options is bad for my low-mem machine +# Uncomment this if you want this. +# +GCCFLAGS += -pipe + +CFLAGS := -I $(TOPDIR)/include/asm/gcc $(CFLAGS) $(GCCFLAGS) +AFLAGS += $(GCCFLAGS) + # # Board-dependent options and extra files # ifdef CONFIG_ALGOR_P4032 CORE_FILES += arch/mips/algor/algor.o SUBDIRS += arch/mips/algor -#LOADADDR += 0x80000000 +LOADADDR += 0x80000000 endif # @@ -90,6 +118,18 @@ LOADADDR += 0x80040000 endif +ifdef CONFIG_MIPS_ATLAS +LIBS += arch/mips/mips-boards/atlas/atlas.o arch/mips/mips-boards/generic/mipsboards.o +SUBDIRS += arch/mips/mips-boards/generic arch/mips/mips-boards/atlas +LOADADDR += 0x80100000 +endif + +ifdef CONFIG_MIPS_MALTA +LIBS += arch/mips/mips-boards/malta/malta.o arch/mips/mips-boards/generic/mipsboards.o +SUBDIRS += arch/mips/mips-boards/malta arch/mips/mips-boards/generic +LOADADDR += 0x80100000 +endif + # # Acer PICA 61, Mips Magnum 4000 and Olivetti M700. # @@ -100,12 +140,6 @@ LOADADDR += 0x80080000 endif -ifdef CONFIG_COBALT_MICRO_SERVER -ARCHIVES += arch/mips/cobalt/cobalt.o -SUBDIRS += arch/mips/cobalt -LOADADDR += 0x80000000 -endif - ifdef CONFIG_SNI_RM200_PCI CORE_FILES += arch/mips/sni/sni.o SUBDIRS += arch/mips/sni arch/mips/arc @@ -114,7 +148,8 @@ endif ifdef CONFIG_SGI_IP22 -LIBS += arch/mips/sgi/kernel/sgikern.a arch/mips/arc/arclib.a +CORE_FILES += arch/mips/sgi/kernel/ip22-kern.o +LIBS += arch/mips/arc/arclib.a SUBDIRS += arch/mips/sgi/kernel arch/mips/arc # # Set LOADADDR to >= 0x88069000 if you want to leave space for symmon, @@ -152,28 +187,74 @@ endif # -# Choosing incompatible machines durings configuration will result in -# error messages during linking. Select a default linkscript if -# none has been choosen above. # -ifndef LINKSCRIPT -ifndef CONFIG_CPU_LITTLE_ENDIAN -LINKSCRIPT = arch/mips/ld.script.big -else -LINKSCRIPT = arch/mips/ld.script.little +# NEC DDB Vrc-5476 +# +ifdef CONFIG_DDB5476 +SUBDIRS += arch/mips/ddb5476 +LIBS += arch/mips/ddb5476/ddb5476.a +LOADADDR += 0x80080000 endif + +# +# Galileo EV64120 Board +# +ifdef CONFIG_MIPS_EV64120 +LIBS += arch/mips/galileo-boards/ev64120/ev64120.o +SUBDIRS += arch/mips/galileo-boards/ev64120 +LOADADDR += 0x80100000 endif -LINKFLAGS += -T $(word 1,$(LINKSCRIPT)) -ifdef LOADADDR -LINKFLAGS += -Ttext $(word 1,$(LOADADDR)) +# +# Galileo EV96100 Board +# +ifdef CONFIG_MIPS_EV96100 +LIBS += arch/mips/galileo-boards/ev96100/ev96100.o arch/mips/galileo-boards/generic/galboards.o +SUBDIRS += arch/mips/galileo-boards/generic arch/mips/galileo-boards/ev96100 +LOADADDR += 0x80100000 endif # -# The pipe options is bad for my low-mem machine -# Uncomment this if you want this. +# Momentum Ocelot board +# +ifdef CONFIG_MOMENCO_OCELOT +LIBS += arch/mips/gt64120/common/gt64120.o arch/mips/gt64120/momenco_ocelot/momenco_ocelot.o +SUBDIRS += arch/mips/gt64120/common arch/mips/gt64120/momenco_ocelot +LOADADDR += 0x80100000 +endif + # -CFLAGS += -pipe +# Philips Nino +# +ifdef CONFIG_NINO +CORE_FILES += arch/mips/philips/nino/nino.o \ + arch/mips/philips/drivers/drivers.o +SUBDIRS += arch/mips/philips/nino arch/mips/philips/drivers +LOADADDR += 0x80000000 +endif + +# +# ITE 8172 eval board with QED 5231 CPU +# +ifdef CONFIG_MIPS_ITE8172 +LIBS += arch/mips/ite-boards/qed-4n-s01b/ite.o \ + arch/mips/ite-boards/generic/it8172.o +SUBDIRS += arch/mips/ite-boards/generic \ + arch/mips/ite-boards/qed-4n-s01b +LOADADDR += 0x80100000 +endif + +# +# Choosing incompatible machines durings configuration will result in +# error messages during linking. Select a default linkscript if +# none has been choosen above. +# +vmlinux: arch/$(ARCH)/ld.script + +arch/$(ARCH)/ld.script: arch/$(ARCH)/ld.script.in arch/$(ARCH)/Makefile + sed -e 's/@@OUTPUT_FORMAT@@/$(output-format)/' \ + -e 's/@@LOADADDR@@/$(LOADADDR)/' <$< >$@ +LINKFLAGS += -T arch/$(ARCH)/ld.script HEAD := arch/mips/kernel/head.o arch/mips/kernel/init_task.o @@ -197,8 +278,18 @@ $(ORIONBOOT) orionboot endif +ifdef CONFIG_MIPS_EV64120 +GALILEOBOOT = $(MAKE) -C arch/$(ARCH)/galileo-boards/ev64120 + +gboot: vmlinux + $(MAKE) -C arch/$(ARCH)/galileo-boards/ev64120/compressed +endif + MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot +vmlinux.ecoff: vmlinux + @$(MAKEBOOT) $@ + zImage: vmlinux @$(MAKEBOOT) zImage @@ -209,7 +300,7 @@ archclean: @$(MAKEBOOT) clean - $(MAKE) -C arch/$(ARCH)/kernel clean + rm -f arch/$(ARCH)/ld.script $(MAKE) -C arch/$(ARCH)/tools clean $(MAKE) -C arch/mips/baget clean diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/arc/Makefile linux.ac/arch/mips/arc/Makefile --- linux.vanilla/arch/mips/arc/Makefile Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/arc/Makefile Tue Apr 3 17:54:32 2001 @@ -1,4 +1,3 @@ -# $Id: Makefile,v 1.1 1998/10/18 13:32:08 tsbogend Exp $ # # Makefile for the SGI arcs prom monitor library routines # under Linux. @@ -10,7 +9,10 @@ # Note 2! The CFLAGS definitions are now in the main makefile... L_TARGET = arclib.a -L_OBJS = console.o init.o printf.o memory.o tree.o env.o cmdline.o misc.o \ - time.o file.o identify.o + +obj-y += console.o init.o memory.o tree.o env.o cmdline.o misc.o \ + time.o file.o identify.o + +obj-$(CONFIG_ARC_CONSOLE) += arc_con.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/arc/arc_con.c linux.ac/arch/mips/arc/arc_con.c --- linux.vanilla/arch/mips/arc/arc_con.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/arc/arc_con.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,69 @@ +/* + * Wrap-around code for a console using the + * ARC io-routines. + * + * Copyright (c) 1998 Harald Koerfgen + */ + +#include <linux/tty.h> +#include <linux/major.h> +#include <linux/ptrace.h> +#include <linux/init.h> +#include <linux/console.h> +#include <linux/fs.h> + +extern char prom_getchar (void); +extern void prom_printf (char *, ...); + +static void prom_console_write(struct console *co, const char *s, + unsigned count) +{ + unsigned i; + + /* + * Now, do each character + */ + for (i = 0; i < count; i++) { + if (*s == 10) + prom_printf("%c", 13); + prom_printf("%c", *s++); + } +} + +static int prom_console_wait_key(struct console *co) +{ + return prom_getchar(); +} + +static int __init prom_console_setup(struct console *co, char *options) +{ + return 0; +} + +static kdev_t prom_console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +static struct console arc_cons = { + "ttyS", + prom_console_write, + NULL, + prom_console_device, + prom_console_wait_key, + NULL, + prom_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +/* + * Register console. + */ + +void __init arc_console_init(void) +{ + register_console(&arc_cons); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/arc/cmdline.c linux.ac/arch/mips/arc/cmdline.c --- linux.vanilla/arch/mips/arc/cmdline.c Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/arc/cmdline.c Tue Apr 3 17:54:32 2001 @@ -2,8 +2,6 @@ * cmdline.c: Kernel command line creation using ARCS argc/argv. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: cmdline.c,v 1.1 1998/10/18 13:32:08 tsbogend Exp $ */ #include <linux/init.h> #include <linux/kernel.h> @@ -12,9 +10,9 @@ #include <asm/sgialib.h> #include <asm/bootinfo.h> -/* #define DEBUG_CMDLINE */ +#undef DEBUG_CMDLINE -char arcs_cmdline[CL_SIZE]; +char arcs_cmdline[COMMAND_LINE_SIZE]; char * __init prom_getcmdline(void) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/arc/console.c linux.ac/arch/mips/arc/console.c --- linux.vanilla/arch/mips/arc/console.c Mon Feb 28 15:18:20 2000 +++ linux.ac/arch/mips/arc/console.c Tue Apr 3 17:54:32 2001 @@ -1,50 +1,99 @@ /* - * console.c: SGI arcs console code. + * 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) 1996 David S. Miller (dm@sgi.com) * Compability with board caches, Ulf Carlsson - * - * $Id: console.c,v 1.3 1999/10/09 00:00:57 ralf Exp $ */ #include <linux/config.h> #include <linux/init.h> +#include <linux/kernel.h> #include <asm/sgialib.h> #include <asm/bcache.h> +#include <linux/console.h> +#include <linux/kdev_t.h> +#include <linux/major.h> + +#ifdef CONFIG_ARC_CONSOLE +#define __init +#endif -/* The romvec is not compatible with board caches. Thus we disable it during - * romvec action. Since r4xx0.c is always compiled and linked with your kernel, - * this shouldn't cause any harm regardless what MIPS processor you have. +/* + * IP22 boardcache is not compatible with board caches. Thus we disable it + * during romvec action. Since r4xx0.c is always compiled and linked with your + * kernel, this shouldn't cause any harm regardless what MIPS processor you + * have. * - * The romvec write and read functions seem to interfere with the serial lines + * The ARC write and read functions seem to interfere with the serial lines * in some way. You should be careful with them. */ -extern struct bcache_ops *bcops; -#ifdef CONFIG_SGI_PROM_CONSOLE -void prom_putchar(char c) -#else void __init prom_putchar(char c) -#endif { long cnt; char it = c; - bcops->bc_disable(); + bc_disable(); romvec->write(1, &it, 1, &cnt); - bcops->bc_enable(); + bc_enable(); } -#ifdef CONFIG_SGI_PROM_CONSOLE -char prom_getchar(void) -#else char __init prom_getchar(void) -#endif { long cnt; char c; - bcops->bc_disable(); + bc_disable(); romvec->read(0, &c, 1, &cnt); - bcops->bc_enable(); + bc_enable(); + return c; +} + +static char ppbuf[1024]; + +void __init prom_printf(char *fmt, ...) +{ + va_list args; + char ch, *bptr; + int i; + + va_start(args, fmt); + i = vsprintf(ppbuf, fmt, args); + + bptr = ppbuf; + + while ((ch = *(bptr++)) != 0) { + if (ch == '\n') + prom_putchar('\r'); + + prom_putchar(ch); + } + va_end(args); +} + +static void +arc_console_write(struct console *con, const char *s, unsigned n) +{ + prom_printf("%s", s); +} + +static kdev_t +arc_console_dev(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +static struct console arc_prom_console = { + name: "prom", + write: arc_console_write, + device: arc_console_dev, + flags: CON_PRINTBUFFER, + index: -1, +}; + +__init void arc_setup_console(void) +{ + register_console(&arc_prom_console); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/arc/identify.c linux.ac/arch/mips/arc/identify.c --- linux.vanilla/arch/mips/arc/identify.c Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/arc/identify.c Tue Apr 3 17:54:32 2001 @@ -6,8 +6,6 @@ * This code is based on arch/mips/sgi/kernel/system.c, which is * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: identify.c,v 1.2 1999/02/25 21:04:13 tsbogend Exp $ */ #include <linux/init.h> #include <linux/kernel.h> @@ -19,50 +17,51 @@ #include <asm/bootinfo.h> struct smatch { - char *name; - int group; - int type; - int flags; + char *name; + int group; + int type; + int flags; }; static struct smatch mach_table[] = { - { "SGI-IP22", MACH_GROUP_SGI, MACH_SGI_INDY, PROM_FLAG_ARCS }, - { "Microsoft-Jazz", MACH_GROUP_JAZZ, MACH_MIPS_MAGNUM_4000, 0 }, - { "PICA-61", MACH_GROUP_JAZZ, MACH_ACER_PICA_61, 0 }, - { "RM200PCI", MACH_GROUP_SNI_RM, MACH_SNI_RM200_PCI, 0 } + {"SGI-IP22", MACH_GROUP_SGI, MACH_SGI_INDY, PROM_FLAG_ARCS}, + {"Microsoft-Jazz", MACH_GROUP_JAZZ, MACH_MIPS_MAGNUM_4000, 0}, + {"PICA-61", MACH_GROUP_JAZZ, MACH_ACER_PICA_61, 0}, + {"RM200PCI", MACH_GROUP_SNI_RM, MACH_SNI_RM200_PCI, 0} }; int prom_flags; -static struct smatch * __init string_to_mach(char *s) +static struct smatch *__init string_to_mach(char *s) { - int i; - - for (i = 0; i < sizeof (mach_table); i++) { - if(!strcmp(s, mach_table[i].name)) - return &mach_table[i]; - } - prom_printf("\nYeee, could not determine architecture type <%s>\n", s); - prom_printf("press a key to reboot\n"); - prom_getchar(); - romvec->imode(); - return NULL; + int i; + + for (i = 0; i < sizeof(mach_table); i++) { + if (!strcmp(s, mach_table[i].name)) + return &mach_table[i]; + } + prom_printf("\nYeee, could not determine architecture type <%s>\n", + s); + prom_printf("press a key to reboot\n"); + prom_getchar(); + romvec->imode(); + return NULL; } void __init prom_identify_arch(void) { - pcomponent *p; - struct smatch *mach; - - /* The root component tells us what machine architecture we - * have here. - */ - p = prom_getchild(PROM_NULL_COMPONENT); - printk("ARCH: %s\n", p->iname); - mach = string_to_mach(p->iname); - - mips_machgroup = mach->group; - mips_machtype = mach->type; - prom_flags = mach->flags; -} + pcomponent *p; + struct smatch *mach; + /* + * The root component tells us what machine architecture we + * have here. + */ + p = prom_getchild(PROM_NULL_COMPONENT); + printk("ARCH: %s\n", p->iname); + mach = string_to_mach(p->iname); + + mips_machgroup = mach->group; + mips_machtype = mach->type; + prom_flags = mach->flags; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/arc/init.c linux.ac/arch/mips/arc/init.c --- linux.vanilla/arch/mips/arc/init.c Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/arc/init.c Tue Apr 3 17:54:32 2001 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.5 2000/03/07 15:45:27 ralf Exp $ +/* * 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. @@ -23,7 +23,9 @@ extern void prom_testtree(void); -int __init prom_init(int argc, char **argv, char **envp, int *prom_vec) +extern void arc_setup_console(void); + +void __init prom_init(int argc, char **argv, char **envp, int *prom_vec) { struct linux_promblock *pb; @@ -33,7 +35,20 @@ prom_argv = argv; prom_envp = envp; - if(pb->magic != 0x53435241) { +#if 0 + /* arc_printf should not use prom_printf as soon as we free + * the prom buffers - This horribly breaks on Indys with framebuffer + * as it simply stops after initialising swap - On the Indigo2 serial + * console you will get A LOT illegal instructions - Only enable + * this for early init crashes - This also brings up artefacts of + * printing everything twice on serial console and on GFX Console + * this has the effect of having the prom printing everything + * in the small rectangle and the kernel printing around. + */ + + arc_setup_console(); +#endif + if (pb->magic != 0x53435241) { prom_printf("Aieee, bad prom vector magic %08lx\n", pb->magic); while(1) ; @@ -55,5 +70,4 @@ romvec->imode(); } #endif - return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/arc/memory.c linux.ac/arch/mips/arc/memory.c --- linux.vanilla/arch/mips/arc/memory.c Tue Aug 8 05:02:27 2000 +++ linux.ac/arch/mips/arc/memory.c Tue Apr 3 17:54:32 2001 @@ -3,8 +3,6 @@ * given to us from the ARCS firmware. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: memory.c,v 1.10 2000/01/27 23:21:57 ralf Exp $ */ #include <linux/init.h> #include <linux/kernel.h> @@ -47,31 +45,25 @@ "LoadedProgram", "FirmwareTemporary", "FirmwarePermanent", - "FreeContigiuous" + "FreeContiguous" }; #define mtypes(a) (prom_flags & PROM_FLAG_ARCS) ? arcs_mtypes[a.arcs] : arc_mtypes[a.arc] #endif -static struct prom_pmemblock pblocks[PROM_MAX_PMEMBLOCKS]; - -#define MEMTYPE_DONTUSE 0 -#define MEMTYPE_PROM 1 -#define MEMTYPE_FREE 2 - static inline int memtype_classify_arcs (union linux_memtypes type) { switch (type.arcs) { case arcs_fcontig: case arcs_free: - return MEMTYPE_FREE; + return BOOT_MEM_RAM; case arcs_atmp: - return MEMTYPE_PROM; + return BOOT_MEM_ROM_DATA; case arcs_eblock: case arcs_rvpage: case arcs_bmem: case arcs_prog: case arcs_aperm: - return MEMTYPE_DONTUSE; + return BOOT_MEM_RESERVED; default: BUG(); } @@ -83,15 +75,15 @@ switch (type.arc) { case arc_free: case arc_fcontig: - return MEMTYPE_FREE; + return BOOT_MEM_RAM; case arc_atmp: - return MEMTYPE_PROM; + return BOOT_MEM_ROM_DATA; case arc_eblock: case arc_rvpage: case arc_bmem: case arc_prog: case arc_aperm: - return MEMTYPE_DONTUSE; + return BOOT_MEM_RESERVED; default: BUG(); } @@ -106,50 +98,13 @@ return memtype_classify_arc(type); } -static inline unsigned long find_max_low_pfn(void) -{ - struct prom_pmemblock *p, *highest; - unsigned long pfn; - - p = pblocks; - highest = 0; - while (p->size != 0) { - if (!highest || p->base > highest->base) - highest = p; - p++; - } - - pfn = (highest->base + highest->size) >> PAGE_SHIFT; -#ifdef DEBUG - prom_printf("find_max_low_pfn: 0x%lx pfns.\n", pfn); -#endif - return pfn; -} - -static inline struct prom_pmemblock *find_largest_memblock(void) -{ - struct prom_pmemblock *p, *largest; - - p = pblocks; - largest = 0; - while (p->size != 0) { - if (!largest || p->size > largest->size) - largest = p; - p++; - } - - return largest; -} - void __init prom_meminit(void) { - struct prom_pmemblock *largest; - unsigned long bootmap_size; struct linux_mdesc *p; - int totram; - int i = 0; #ifdef DEBUG + int i = 0; + prom_printf("ARCS MEMORY DESCRIPTOR dump:\n"); p = ArcGetMemoryDescriptor(PROM_NULL_MDESC); while(p) { @@ -160,77 +115,36 @@ } #endif - totram = 0; - i = 0; p = PROM_NULL_MDESC; while ((p = ArcGetMemoryDescriptor(p))) { - pblocks[i].type = prom_memtype_classify(p->type); - pblocks[i].base = p->base << PAGE_SHIFT; - pblocks[i].size = p->pages << PAGE_SHIFT; - - switch (pblocks[i].type) { - case MEMTYPE_FREE: - totram += pblocks[i].size; -#ifdef DEBUG - prom_printf("free_chunk[%d]: base=%08lx size=%x\n", - i, pblocks[i].base, - pblocks[i].size); -#endif - i++; - break; - case MEMTYPE_PROM: -#ifdef DEBUG - prom_printf("prom_chunk[%d]: base=%08lx size=%x\n", - i, pblocks[i].base, - pblocks[i].size); -#endif - i++; - break; - default: - break; - } - } - pblocks[i].size = 0; - - max_low_pfn = find_max_low_pfn(); - - largest = find_largest_memblock(); - bootmap_size = init_bootmem(largest->base >> PAGE_SHIFT, max_low_pfn); + unsigned long base, size; + long type; - for (i = 0; pblocks[i].size; i++) - if (pblocks[i].type == MEMTYPE_FREE) - free_bootmem(pblocks[i].base, pblocks[i].size); + base = p->base << PAGE_SHIFT; + size = p->pages << PAGE_SHIFT; + type = prom_memtype_classify(p->type); - /* This test is simpleminded. It will fail if the bootmem bitmap - falls into multiple adjacent ARC memory areas. */ - if (bootmap_size > largest->size) { - prom_printf("CRITIAL: overwriting PROM data.\n"); - BUG(); + add_memory_region(base, size, type); } - - /* Reserve the memory bootmap itself */ - reserve_bootmem(largest->base, bootmap_size); - - printk("PROMLIB: Total free ram %dK / %dMB.\n", - totram >> 10, totram >> 20); } void __init prom_free_prom_memory (void) { - struct prom_pmemblock *p; unsigned long freed = 0; unsigned long addr; + int i; - for (p = pblocks; p->size != 0; p++) { - if (p->type != MEMTYPE_PROM) + for (i = 0; i < boot_mem_map.nr_map; i++) { + if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA) continue; - addr = PAGE_OFFSET + p->base; - while (addr < p->base + p->size) { - ClearPageReserved(virt_to_page(addr)); - set_page_count(virt_to_page(addr), 1); - free_page(addr); + addr = boot_mem_map.map[i].addr; + while (addr < boot_mem_map.map[i].addr + + boot_mem_map.map[i].size) { + ClearPageReserved(virt_to_page(__va(addr))); + set_page_count(virt_to_page(__va(addr)), 1); + free_page((unsigned long)__va(addr)); addr += PAGE_SIZE; freed += PAGE_SIZE; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/arc/misc.c linux.ac/arch/mips/arc/misc.c --- linux.vanilla/arch/mips/arc/misc.c Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/arc/misc.c Tue Apr 3 17:54:32 2001 @@ -1,5 +1,4 @@ -/* $Id: misc.c,v 1.1 1998/10/18 13:32:09 tsbogend Exp $ - * +/* * misc.c: Miscellaneous ARCS PROM routines. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) @@ -13,13 +12,12 @@ #include <asm/bootinfo.h> #include <asm/system.h> -extern unsigned long mips_cputype; extern void *sgiwd93_host; extern void reset_wd33c93(void *instance); void prom_halt(void) { - bcops->bc_disable(); + bc_disable(); cli(); #if CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); @@ -29,7 +27,7 @@ void prom_powerdown(void) { - bcops->bc_disable(); + bc_disable(); cli(); #if CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); @@ -40,7 +38,7 @@ /* XXX is this a soft reset basically? XXX */ void prom_restart(void) { - bcops->bc_disable(); + bc_disable(); cli(); #if CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); @@ -50,7 +48,7 @@ void prom_reboot(void) { - bcops->bc_disable(); + bc_disable(); cli(); #if CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); @@ -60,7 +58,7 @@ void prom_imode(void) { - bcops->bc_disable(); + bc_disable(); cli(); #if CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/arc/printf.c linux.ac/arch/mips/arc/printf.c --- linux.vanilla/arch/mips/arc/printf.c Mon Feb 28 15:18:20 2000 +++ linux.ac/arch/mips/arc/printf.c Thu Jan 1 01:00:00 1970 @@ -1,40 +0,0 @@ -/* - * printf.c: Putting things on the screen using SGI arcs - * PROM facilities. - * - * Copyright (C) 1996 David S. Miller (dm@sgi.com) - * - * $Id: printf.c,v 1.3 1999/10/09 00:00:57 ralf Exp $ - */ -#include <linux/config.h> -#include <linux/init.h> -#include <linux/kernel.h> - -#include <asm/sgialib.h> - -static char ppbuf[1024]; - -#ifdef CONFIG_SGI_PROM_CONSOLE -void prom_printf(char *fmt, ...) -#else -void __init prom_printf(char *fmt, ...) -#endif -{ - va_list args; - char ch, *bptr; - int i; - - va_start(args, fmt); - i = vsprintf(ppbuf, fmt, args); - - bptr = ppbuf; - - while((ch = *(bptr++)) != 0) { - if(ch == '\n') - prom_putchar('\r'); - - prom_putchar(ch); - } - va_end(args); - return; -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/baget/Makefile linux.ac/arch/mips/baget/Makefile --- linux.vanilla/arch/mips/baget/Makefile Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/baget/Makefile Tue Apr 3 17:54:32 2001 @@ -1,4 +1,3 @@ -# $Id: Makefile,v 1.3 1999/08/13 17:07:26 harald Exp $ # # Makefile for the Baget specific kernel interface routines # under Linux. @@ -12,22 +11,12 @@ all: baget.a O_TARGET := baget.a -O_OBJS := baget.o print.o setup.o time.o irq.o bagetIRQ.o reset.o wbflush.o -ifeq ($(CONFIG_SERIAL),y) - OX_OBJS += vacserial.o -else - ifeq ($(CONFIG_SERIAL),m) - MX_OBJS += vacserial.o - endif -endif -ifeq ($(CONFIG_VAC_RTC),y) - OX_OBJS += vacrtc.o -else - ifeq ($(CONFIG_VAC_RTC),m) - MX_OBJS += vacrtc.o - endif -endif +export-objs := vacserial.o vacrtc.o +obj-y := baget.o print.o setup.o time.o irq.o bagetIRQ.o \ + reset.o wbflush.o +obj-$(CONFIG_SERIAL) += vacserial.o +obj-$(CONFIG_VAC_RTC) += vacrtc.o bagetIRQ.o : bagetIRQ.S $(CC) $(CFLAGS) -c -o $@ $< diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/baget/prom/Makefile linux.ac/arch/mips/baget/prom/Makefile --- linux.vanilla/arch/mips/baget/prom/Makefile Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/baget/prom/Makefile Tue Apr 3 17:54:32 2001 @@ -1,4 +1,4 @@ -# $Id$ +# # Makefile for the Baget/MIPS prom emulator library routines. # # Note! Dependencies are done automagically by 'make dep', which also @@ -7,9 +7,8 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -O_TARGET := bagetlib.a -O_OBJS := init.o +L_TARGET := bagetlib.a -all: $(O_TARGET) +obj-y := init.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/config.in linux.ac/arch/mips/config.in --- linux.vanilla/arch/mips/config.in Thu Nov 16 20:51:28 2000 +++ linux.ac/arch/mips/config.in Tue Apr 3 17:54:32 2001 @@ -233,7 +233,7 @@ if [ "$CONFIG_DECSTATION" != "y" -a \ "$CONFIG_SGI_IP22" != "y" ]; then - source drivers/i2o/Config.in + source drivers/message/i2o/Config.in fi if [ "$CONFIG_NET" = "y" ]; then @@ -329,7 +329,10 @@ # if [ "$CONFIG_ACCESSBUS" = "y" ]; then # bool 'MAXINE Access.Bus mouse (VSXXX-BB/GB) support' CONFIG_DTOP_MOUSE # fi - bool 'Enhanced Real Time Clock Support' CONFIG_RTC + bool 'Enhanced Real Time Clock Support' CONFIG_MIPS_RTC + + define_tristate CONFIG_RTC $CONFIG_MIPS_RTC + endmenu fi diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5074/Makefile linux.ac/arch/mips/ddb5074/Makefile --- linux.vanilla/arch/mips/ddb5074/Makefile Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/ddb5074/Makefile Tue Apr 3 17:54:32 2001 @@ -8,8 +8,6 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... # -# $Id$ -# .S.s: $(CPP) $(CFLAGS) $< -o $*.s @@ -17,6 +15,7 @@ $(CC) $(CFLAGS) -c $< -o $*.o O_TARGET = ddb5074.a -O_OBJS = setup.o irq.o time.o prom.o pci.o pci-dma.o int-handler.o nile4.o + +obj-y := setup.o irq.o time.o prom.o pci.o int-handler.o nile4.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5074/int-handler.S linux.ac/arch/mips/ddb5074/int-handler.S --- linux.vanilla/arch/mips/ddb5074/int-handler.S Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/ddb5074/int-handler.S Tue Apr 3 17:54:32 2001 @@ -7,54 +7,50 @@ * * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id: int-handler.S,v 1.1 2000/01/26 00:07:44 ralf Exp $ */ - #include <asm/asm.h> #include <asm/mipsregs.h> #include <asm/regdef.h> #include <asm/stackframe.h> - /* A lot of complication here is taken away because: - * - * 1) We handle one interrupt and return, sitting in a loop - * and moving across all the pending IRQ bits in the cause - * register is _NOT_ the answer, the common case is one - * pending IRQ so optimize in that direction. - * - * 2) We need not check against bits in the status register - * IRQ mask, that would make this routine slow as hell. - * - * 3) Linux only thinks in terms of all IRQs on or all IRQs - * off, nothing in between like BSD spl() brain-damage. - * - * Furthermore, the IRQs on the INDY look basically (barring - * software IRQs which we don't use at all) like: - * - * MIPS IRQ Source - * -------- ------ - * 0 Software (ignored) - * 1 Software (ignored) - * 2 Local IRQ level zero - * 3 Local IRQ level one - * 4 8254 Timer zero - * 5 8254 Timer one - * 6 Bus Error - * 7 R4k timer (what we use) - * - * We handle the IRQ according to _our_ priority which is: - * - * Highest ---- R4k Timer - * Local IRQ zero - * Local IRQ one - * Bus Error - * 8254 Timer zero - * Lowest ---- 8254 Timer one - * - * then we just return, if multiple IRQs are pending then - * we will just take another exception, big deal. - */ +/* A lot of complication here is taken away because: + * + * 1) We handle one interrupt and return, sitting in a loop and moving across + * all the pending IRQ bits in the cause register is _NOT_ the answer, the + * common case is one pending IRQ so optimize in that direction. + * + * 2) We need not check against bits in the status register IRQ mask, that + * would make this routine slow as hell. + * + * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in + * between like BSD spl() brain-damage. + * + * Furthermore, the IRQs on the INDY look basically (barring software IRQs + * which we don't use at all) like: + * + * MIPS IRQ Source + * -------- ------ + * 0 Software (ignored) + * 1 Software (ignored) + * 2 Local IRQ level zero + * 3 Local IRQ level one + * 4 8254 Timer zero + * 5 8254 Timer one + * 6 Bus Error + * 7 R4k timer (what we use) + * + * We handle the IRQ according to _our_ priority which is: + * + * Highest ---- R4k Timer + * Local IRQ zero + * Local IRQ one + * Bus Error + * 8254 Timer zero + * Lowest ---- 8254 Timer one + * + * then we just return, if multiple IRQs are pending then we will just take + * another exception, big deal. + */ .text .set noreorder diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5074/irq.c linux.ac/arch/mips/ddb5074/irq.c --- linux.vanilla/arch/mips/ddb5074/irq.c Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/ddb5074/irq.c Tue Apr 3 17:54:32 2001 @@ -3,10 +3,7 @@ * * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id: irq.c,v 1.1 2000/01/26 00:07:44 ralf Exp $ */ - #include <linux/config.h> #include <linux/init.h> #include <linux/signal.h> @@ -14,6 +11,7 @@ #include <linux/types.h> #include <linux/interrupt.h> #include <linux/ioport.h> + #include <asm/io.h> #include <asm/irq.h> #include <asm/ptrace.h> @@ -27,7 +25,7 @@ extern asmlinkage void ddbIRQ(void); extern asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs); -extern asmlinkage void do_IRQ(int irq, struct pt_regs * regs); +extern asmlinkage void do_IRQ(int irq, struct pt_regs *regs); void no_action(int cpl, void *dev_id, struct pt_regs *regs) @@ -55,177 +53,174 @@ static void m1543_irq_setup(void) { - /* - * The ALI M1543 has 13 interrupt inputs, IRQ1..IRQ13. Not all - * the possible IO sources in the M1543 are in use by us. We will - * use the following mapping: - * - * IRQ1 - keyboard (default set by M1543) - * IRQ3 - reserved for UART B (default set by M1543) (note that - * the schematics for the DDB Vrc-5074 board seem to - * indicate that IRQ3 is connected to the DS1386 - * watchdog timer interrupt output so we might have - * a conflict) - * IRQ4 - reserved for UART A (default set by M1543) - * IRQ5 - parallel (default set by M1543) - * IRQ8 - DS1386 time of day (RTC) interrupt - * IRQ12 - mouse - */ - - /* - * Assing mouse interrupt to IRQ12 - */ - - /* Enter configuration mode */ - outb(0x51, M1543_PNP_CONFIG); - outb(0x23, M1543_PNP_CONFIG); - - /* Select logical device 7 (Keyboard) */ - outb(0x07, M1543_PNP_INDEX); - outb(0x07, M1543_PNP_DATA); - - /* Select IRQ12 */ - outb(0x72, M1543_PNP_INDEX); - outb(0x0c, M1543_PNP_DATA); - - /* Leave configration mode */ - outb(0xbb, M1543_PNP_CONFIG); + /* + * The ALI M1543 has 13 interrupt inputs, IRQ1..IRQ13. Not all + * the possible IO sources in the M1543 are in use by us. We will + * use the following mapping: + * + * IRQ1 - keyboard (default set by M1543) + * IRQ3 - reserved for UART B (default set by M1543) (note that + * the schematics for the DDB Vrc-5074 board seem to + * indicate that IRQ3 is connected to the DS1386 + * watchdog timer interrupt output so we might have + * a conflict) + * IRQ4 - reserved for UART A (default set by M1543) + * IRQ5 - parallel (default set by M1543) + * IRQ8 - DS1386 time of day (RTC) interrupt + * IRQ12 - mouse + */ + + /* + * Assing mouse interrupt to IRQ12 + */ + + /* Enter configuration mode */ + outb(0x51, M1543_PNP_CONFIG); + outb(0x23, M1543_PNP_CONFIG); + + /* Select logical device 7 (Keyboard) */ + outb(0x07, M1543_PNP_INDEX); + outb(0x07, M1543_PNP_DATA); + + /* Select IRQ12 */ + outb(0x72, M1543_PNP_INDEX); + outb(0x0c, M1543_PNP_DATA); + + /* Leave configration mode */ + outb(0xbb, M1543_PNP_CONFIG); - /* Initialize the 8259 PIC in the M1543 */ - i8259_init(); + /* Initialize the 8259 PIC in the M1543 */ + i8259_init(); - /* Enable the interrupt cascade */ - nile4_enable_irq(NILE4_INT_INTE); + /* Enable the interrupt cascade */ + nile4_enable_irq(NILE4_INT_INTE); - request_region(M1543_PNP_CONFIG, 2, "M1543 config"); - request_region(M1543_INT1_MASTER_ELCR, 2, "pic ELCR"); + request_region(M1543_PNP_CONFIG, 2, "M1543 config"); + request_region(M1543_INT1_MASTER_ELCR, 2, "pic ELCR"); } static void nile4_irq_setup(void) { - int i; + int i; - /* Map all interrupts to CPU int #0 */ - nile4_map_irq_all(0); + /* Map all interrupts to CPU int #0 */ + nile4_map_irq_all(0); - /* PCI INTA#-E# must be level triggered */ - nile4_set_pci_irq_level_or_edge(0, 1); - nile4_set_pci_irq_level_or_edge(1, 1); - nile4_set_pci_irq_level_or_edge(2, 1); - nile4_set_pci_irq_level_or_edge(3, 1); - nile4_set_pci_irq_level_or_edge(4, 1); - - /* PCI INTA#-D# must be active low, INTE# must be active high */ - nile4_set_pci_irq_polarity(0, 0); - nile4_set_pci_irq_polarity(1, 0); - nile4_set_pci_irq_polarity(2, 0); - nile4_set_pci_irq_polarity(3, 0); - nile4_set_pci_irq_polarity(4, 1); + /* PCI INTA#-E# must be level triggered */ + nile4_set_pci_irq_level_or_edge(0, 1); + nile4_set_pci_irq_level_or_edge(1, 1); + nile4_set_pci_irq_level_or_edge(2, 1); + nile4_set_pci_irq_level_or_edge(3, 1); + nile4_set_pci_irq_level_or_edge(4, 1); + + /* PCI INTA#-D# must be active low, INTE# must be active high */ + nile4_set_pci_irq_polarity(0, 0); + nile4_set_pci_irq_polarity(1, 0); + nile4_set_pci_irq_polarity(2, 0); + nile4_set_pci_irq_polarity(3, 0); + nile4_set_pci_irq_polarity(4, 1); - for (i = 0; i < 16; i++) - nile4_clear_irq(i); + for (i = 0; i < 16; i++) + nile4_clear_irq(i); - /* Enable CPU int #0 */ - nile4_enable_irq_output(0); + /* Enable CPU int #0 */ + nile4_enable_irq_output(0); - request_mem_region(NILE4_BASE, NILE4_SIZE, "Nile 4"); + request_mem_region(NILE4_BASE, NILE4_SIZE, "Nile 4"); } /* * IRQ2 is cascade interrupt to second interrupt controller */ - -static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL }; +static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL }; void disable_irq(unsigned int irq_nr) { - if (is_i8259_irq(irq_nr)) - i8259_disable_irq(irq_nr); - else - nile4_disable_irq(irq_to_nile4(irq_nr)); + if (is_i8259_irq(irq_nr)) + i8259_disable_irq(irq_nr); + else + nile4_disable_irq(irq_to_nile4(irq_nr)); } void enable_irq(unsigned int irq_nr) { - if (is_i8259_irq(irq_nr)) - i8259_enable_irq(irq_nr); - else - nile4_enable_irq(irq_to_nile4(irq_nr)); + if (is_i8259_irq(irq_nr)) + i8259_enable_irq(irq_nr); + else + nile4_enable_irq(irq_to_nile4(irq_nr)); } int table[16] = { 0, }; void ddb_local0_irqdispatch(struct pt_regs *regs) { - u32 mask; - int nile4_irq; + u32 mask; + int nile4_irq; #if 1 - volatile static int nesting = 0; - if (nesting++ == 0) - ddb5074_led_d3(1); - ddb5074_led_hex(nesting < 16 ? nesting : 15); + volatile static int nesting = 0; + if (nesting++ == 0) + ddb5074_led_d3(1); + ddb5074_led_hex(nesting < 16 ? nesting : 15); #endif - mask = nile4_get_irq_stat(0); - nile4_clear_irq_mask(mask); + mask = nile4_get_irq_stat(0); + nile4_clear_irq_mask(mask); - /* Handle the timer interrupt first */ - if (mask & (1<<NILE4_INT_GPT)) { - nile4_disable_irq(NILE4_INT_GPT); - do_IRQ(nile4_to_irq(NILE4_INT_GPT), regs); - nile4_enable_irq(NILE4_INT_GPT); - mask &= ~(1<<NILE4_INT_GPT); - } - for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1) - if (mask & 1) { - nile4_disable_irq(nile4_irq); - if (nile4_irq == NILE4_INT_INTE) { - int i8259_irq = nile4_i8259_iack(); - i8259_do_irq(i8259_irq, regs); - } else - do_IRQ(nile4_to_irq(nile4_irq), regs); - nile4_enable_irq(nile4_irq); + /* Handle the timer interrupt first */ + if (mask & (1 << NILE4_INT_GPT)) { + nile4_disable_irq(NILE4_INT_GPT); + do_IRQ(nile4_to_irq(NILE4_INT_GPT), regs); + nile4_enable_irq(NILE4_INT_GPT); + mask &= ~(1 << NILE4_INT_GPT); } - + for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1) + if (mask & 1) { + nile4_disable_irq(nile4_irq); + if (nile4_irq == NILE4_INT_INTE) { + int i8259_irq = nile4_i8259_iack(); + i8259_do_irq(i8259_irq, regs); + } else + do_IRQ(nile4_to_irq(nile4_irq), regs); + nile4_enable_irq(nile4_irq); + } #if 1 - if (--nesting == 0) - ddb5074_led_d3(0); - ddb5074_led_hex(nesting < 16 ? nesting : 15); + if (--nesting == 0) + ddb5074_led_d3(0); + ddb5074_led_hex(nesting < 16 ? nesting : 15); #endif } void ddb_local1_irqdispatch(void) { - printk("ddb_local1_irqdispatch called\n"); + printk("ddb_local1_irqdispatch called\n"); } void ddb_buserror_irq(void) { - printk("ddb_buserror_irq called\n"); + printk("ddb_buserror_irq called\n"); } void ddb_8254timer_irq(void) { - printk("ddb_8254timer_irq called\n"); + printk("ddb_8254timer_irq called\n"); } void __init ddb_irq_setup(void) { #ifdef CONFIG_REMOTE_DEBUG - if (remote_debug) - set_debug_traps(); - breakpoint(); /* you may move this line to whereever you want :-) */ + if (remote_debug) + set_debug_traps(); + breakpoint(); /* you may move this line to whereever you want :-) */ #endif - request_region(0x20, 0x20, "pic1"); - request_region(0xa0, 0x20, "pic2"); - i8259_setup_irq(2, &irq2); + request_region(0x20, 0x20, "pic1"); + request_region(0xa0, 0x20, "pic2"); + i8259_setup_irq(2, &irq2); - nile4_irq_setup(); - m1543_irq_setup(); + nile4_irq_setup(); + m1543_irq_setup(); - set_except_vector(0, ddbIRQ); + set_except_vector(0, ddbIRQ); } - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5074/nile4.c linux.ac/arch/mips/ddb5074/nile4.c --- linux.vanilla/arch/mips/ddb5074/nile4.c Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/ddb5074/nile4.c Tue Apr 3 17:54:32 2001 @@ -3,292 +3,290 @@ * * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id$ */ - #include <linux/kernel.h> #include <linux/types.h> + #include <asm/nile4.h> - /* - * Physical Device Address Registers - * - * Note: 32 bit addressing only! - */ - -void nile4_set_pdar(u32 pdar, u32 phys, u32 size, int width, int on_memory_bus, - int visible) -{ - u32 maskbits; - u32 widthbits; - - if (pdar > NILE4_BOOTCS || (pdar & 7)) { - printk("nile4_set_pdar: invalid pdar %d\n", pdar); - return; - } - if (pdar == NILE4_INTCS && size != 0x00200000) { - printk("nile4_set_pdar: INTCS size must be 2 MB\n"); - return; - } - switch (size) { -#if 0 /* We don't support 4 GB yet */ +/* + * Physical Device Address Registers + * + * Note: 32 bit addressing only! + */ +void nile4_set_pdar(u32 pdar, u32 phys, u32 size, int width, + int on_memory_bus, int visible) +{ + u32 maskbits; + u32 widthbits; + + if (pdar > NILE4_BOOTCS || (pdar & 7)) { + printk("nile4_set_pdar: invalid pdar %d\n", pdar); + return; + } + if (pdar == NILE4_INTCS && size != 0x00200000) { + printk("nile4_set_pdar: INTCS size must be 2 MB\n"); + return; + } + switch (size) { +#if 0 /* We don't support 4 GB yet */ case 0x100000000: /* 4 GB */ - maskbits = 4; - break; + maskbits = 4; + break; #endif case 0x80000000: /* 2 GB */ - maskbits = 5; - break; + maskbits = 5; + break; case 0x40000000: /* 1 GB */ - maskbits = 6; - break; + maskbits = 6; + break; case 0x20000000: /* 512 MB */ - maskbits = 7; - break; + maskbits = 7; + break; case 0x10000000: /* 256 MB */ - maskbits = 8; - break; + maskbits = 8; + break; case 0x08000000: /* 128 MB */ - maskbits = 9; - break; + maskbits = 9; + break; case 0x04000000: /* 64 MB */ - maskbits = 10; - break; + maskbits = 10; + break; case 0x02000000: /* 32 MB */ - maskbits = 11; - break; + maskbits = 11; + break; case 0x01000000: /* 16 MB */ - maskbits = 12; - break; + maskbits = 12; + break; case 0x00800000: /* 8 MB */ - maskbits = 13; - break; + maskbits = 13; + break; case 0x00400000: /* 4 MB */ - maskbits = 14; - break; + maskbits = 14; + break; case 0x00200000: /* 2 MB */ - maskbits = 15; - break; - case 0: /* OFF */ - maskbits = 0; - break; + maskbits = 15; + break; + case 0: /* OFF */ + maskbits = 0; + break; default: - printk("nile4_set_pdar: unsupported size %p\n", (void *)size); - return; - } - switch (width) { + printk("nile4_set_pdar: unsupported size %p\n", (void *) size); + return; + } + switch (width) { case 8: - widthbits = 0; - break; + widthbits = 0; + break; case 16: - widthbits = 1; - break; + widthbits = 1; + break; case 32: - widthbits = 2; - break; + widthbits = 2; + break; case 64: - widthbits = 3; - break; + widthbits = 3; + break; default: - printk("nile4_set_pdar: unsupported width %d\n", width); - return; - } - nile4_out32(pdar, maskbits | (on_memory_bus ? 0x10 : 0) | - (visible ? 0x20 : 0) | (widthbits << 6) | - (phys & 0xffe00000)); - nile4_out32(pdar+4, 0); - /* - * When programming a PDAR, the register should be read immediately after - * writing it. This ensures that address decoders are properly configured. - */ - (void)nile4_in32(pdar); - (void)nile4_in32(pdar+4); + printk("nile4_set_pdar: unsupported width %d\n", width); + return; + } + nile4_out32(pdar, maskbits | (on_memory_bus ? 0x10 : 0) | + (visible ? 0x20 : 0) | (widthbits << 6) | + (phys & 0xffe00000)); + nile4_out32(pdar + 4, 0); + /* + * When programming a PDAR, the register should be read immediately + * after writing it. This ensures that address decoders are properly + * configured. + */ + nile4_in32(pdar); + nile4_in32(pdar + 4); } - /* - * PCI Master Registers - * - * Note: 32 bit addressing only! - */ - +/* + * PCI Master Registers + * + * Note: 32 bit addressing only! + */ void nile4_set_pmr(u32 pmr, u32 type, u32 addr) { - if (pmr != NILE4_PCIINIT0 && pmr != NILE4_PCIINIT1) { - printk("nile4_set_pmr: invalid pmr %d\n", pmr); - return; - } - switch (type) { + if (pmr != NILE4_PCIINIT0 && pmr != NILE4_PCIINIT1) { + printk("nile4_set_pmr: invalid pmr %d\n", pmr); + return; + } + switch (type) { case NILE4_PCICMD_IACK: /* PCI Interrupt Acknowledge */ case NILE4_PCICMD_IO: /* PCI I/O Space */ case NILE4_PCICMD_MEM: /* PCI Memory Space */ case NILE4_PCICMD_CFG: /* PCI Configuration Space */ - break; + break; default: - printk("nile4_set_pmr: invalid type %d\n", type); - return; - } - nile4_out32(pmr, (type << 1) | 0x10 | (addr & 0xffe00000)); - nile4_out32(pmr+4, 0); + printk("nile4_set_pmr: invalid type %d\n", type); + return; + } + nile4_out32(pmr, (type << 1) | 0x10 | (addr & 0xffe00000)); + nile4_out32(pmr + 4, 0); } - /* - * Interrupt Programming - */ - +/* + * Interrupt Programming + */ void nile4_map_irq(int nile4_irq, int cpu_irq) { - u32 offset, t; + u32 offset, t; - offset = NILE4_INTCTRL; - if (nile4_irq >= 8) { - offset += 4; - nile4_irq -= 8; - } - t = nile4_in32(offset); - t &= ~(7 << (nile4_irq*4)); - t |= cpu_irq << (nile4_irq*4); - nile4_out32(offset, t); + offset = NILE4_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + t = nile4_in32(offset); + t &= ~(7 << (nile4_irq * 4)); + t |= cpu_irq << (nile4_irq * 4); + nile4_out32(offset, t); } void nile4_map_irq_all(int cpu_irq) { - u32 all, t; - - all = cpu_irq; - all |= all << 4; - all |= all << 8; - all |= all << 16; - t = nile4_in32(NILE4_INTCTRL); - t &= 0x88888888; - t |= all; - nile4_out32(NILE4_INTCTRL, t); - t = nile4_in32(NILE4_INTCTRL+4); - t &= 0x88888888; - t |= all; - nile4_out32(NILE4_INTCTRL+4, t); + u32 all, t; + + all = cpu_irq; + all |= all << 4; + all |= all << 8; + all |= all << 16; + t = nile4_in32(NILE4_INTCTRL); + t &= 0x88888888; + t |= all; + nile4_out32(NILE4_INTCTRL, t); + t = nile4_in32(NILE4_INTCTRL + 4); + t &= 0x88888888; + t |= all; + nile4_out32(NILE4_INTCTRL + 4, t); } void nile4_enable_irq(int nile4_irq) { - u32 offset, t; + u32 offset, t; - offset = NILE4_INTCTRL; - if (nile4_irq >= 8) { - offset += 4; - nile4_irq -= 8; - } - t = nile4_in32(offset); - t |= 8 << (nile4_irq*4); - nile4_out32(offset, t); + offset = NILE4_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + t = nile4_in32(offset); + t |= 8 << (nile4_irq * 4); + nile4_out32(offset, t); } void nile4_disable_irq(int nile4_irq) { - u32 offset, t; + u32 offset, t; - offset = NILE4_INTCTRL; - if (nile4_irq >= 8) { - offset += 4; - nile4_irq -= 8; - } - t = nile4_in32(offset); - t &= ~(8 << (nile4_irq*4)); - nile4_out32(offset, t); + offset = NILE4_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + t = nile4_in32(offset); + t &= ~(8 << (nile4_irq * 4)); + nile4_out32(offset, t); } void nile4_disable_irq_all(void) { - nile4_out32(NILE4_INTCTRL, 0); - nile4_out32(NILE4_INTCTRL+4, 0); + nile4_out32(NILE4_INTCTRL, 0); + nile4_out32(NILE4_INTCTRL + 4, 0); } u16 nile4_get_irq_stat(int cpu_irq) { - return nile4_in16(NILE4_INTSTAT0+cpu_irq*2); + return nile4_in16(NILE4_INTSTAT0 + cpu_irq * 2); } void nile4_enable_irq_output(int cpu_irq) { - u32 t; + u32 t; - t = nile4_in32(NILE4_INTSTAT1+4); - t |= 1 << (16+cpu_irq); - nile4_out32(NILE4_INTSTAT1, t); + t = nile4_in32(NILE4_INTSTAT1 + 4); + t |= 1 << (16 + cpu_irq); + nile4_out32(NILE4_INTSTAT1, t); } void nile4_disable_irq_output(int cpu_irq) { - u32 t; + u32 t; - t = nile4_in32(NILE4_INTSTAT1+4); - t &= ~(1 << (16+cpu_irq)); - nile4_out32(NILE4_INTSTAT1, t); + t = nile4_in32(NILE4_INTSTAT1 + 4); + t &= ~(1 << (16 + cpu_irq)); + nile4_out32(NILE4_INTSTAT1, t); } void nile4_set_pci_irq_polarity(int pci_irq, int high) { - u32 t; + u32 t; - t = nile4_in32(NILE4_INTPPES); - if (high) - t &= ~(1 << (pci_irq*2)); - else - t |= 1 << (pci_irq*2); - nile4_out32(NILE4_INTPPES, t); + t = nile4_in32(NILE4_INTPPES); + if (high) + t &= ~(1 << (pci_irq * 2)); + else + t |= 1 << (pci_irq * 2); + nile4_out32(NILE4_INTPPES, t); } void nile4_set_pci_irq_level_or_edge(int pci_irq, int level) { - u32 t; + u32 t; - t = nile4_in32(NILE4_INTPPES); - if (level) - t |= 2 << (pci_irq*2); - else - t &= ~(2 << (pci_irq*2)); - nile4_out32(NILE4_INTPPES, t); + t = nile4_in32(NILE4_INTPPES); + if (level) + t |= 2 << (pci_irq * 2); + else + t &= ~(2 << (pci_irq * 2)); + nile4_out32(NILE4_INTPPES, t); } void nile4_clear_irq(int nile4_irq) { - nile4_out32(NILE4_INTCLR, 1 << nile4_irq); + nile4_out32(NILE4_INTCLR, 1 << nile4_irq); } void nile4_clear_irq_mask(u32 mask) { - nile4_out32(NILE4_INTCLR, mask); + nile4_out32(NILE4_INTCLR, mask); } u8 nile4_i8259_iack(void) { - u8 irq; + u8 irq; - /* Set window 0 for interrupt acknowledge */ - nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IACK, 0); - irq = *(volatile u8 *)NILE4_PCI_IACK_BASE; - /* Set window 0 for PCI I/O space */ - nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0); - return irq; + /* Set window 0 for interrupt acknowledge */ + nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IACK, 0); + irq = *(volatile u8 *) NILE4_PCI_IACK_BASE; + /* Set window 0 for PCI I/O space */ + nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0); + return irq; } #if 0 void nile4_dump_irq_status(void) { - printk("CPUSTAT = %p:%p\n", (void *)nile4_in32(NILE4_CPUSTAT+4), - (void *)nile4_in32(NILE4_CPUSTAT)); - printk("INTCTRL = %p:%p\n", (void *)nile4_in32(NILE4_INTCTRL+4), - (void *)nile4_in32(NILE4_INTCTRL)); - printk("INTSTAT0 = %p:%p\n", (void *)nile4_in32(NILE4_INTSTAT0+4), - (void *)nile4_in32(NILE4_INTSTAT0)); - printk("INTSTAT1 = %p:%p\n", (void *)nile4_in32(NILE4_INTSTAT1+4), - (void *)nile4_in32(NILE4_INTSTAT1)); - printk("INTCLR = %p:%p\n", (void *)nile4_in32(NILE4_INTCLR+4), - (void *)nile4_in32(NILE4_INTCLR)); - printk("INTPPES = %p:%p\n", (void *)nile4_in32(NILE4_INTPPES+4), - (void *)nile4_in32(NILE4_INTPPES)); + printk("CPUSTAT = %p:%p\n", (void *) nile4_in32(NILE4_CPUSTAT + 4), + (void *) nile4_in32(NILE4_CPUSTAT)); + printk("INTCTRL = %p:%p\n", (void *) nile4_in32(NILE4_INTCTRL + 4), + (void *) nile4_in32(NILE4_INTCTRL)); + printk("INTSTAT0 = %p:%p\n", + (void *) nile4_in32(NILE4_INTSTAT0 + 4), + (void *) nile4_in32(NILE4_INTSTAT0)); + printk("INTSTAT1 = %p:%p\n", + (void *) nile4_in32(NILE4_INTSTAT1 + 4), + (void *) nile4_in32(NILE4_INTSTAT1)); + printk("INTCLR = %p:%p\n", (void *) nile4_in32(NILE4_INTCLR + 4), + (void *) nile4_in32(NILE4_INTCLR)); + printk("INTPPES = %p:%p\n", (void *) nile4_in32(NILE4_INTPPES + 4), + (void *) nile4_in32(NILE4_INTPPES)); } #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5074/pci-dma.c linux.ac/arch/mips/ddb5074/pci-dma.c --- linux.vanilla/arch/mips/ddb5074/pci-dma.c Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/ddb5074/pci-dma.c Thu Jan 1 01:00:00 1970 @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com> - * - * - * Dynamic DMA mapping support. - * - * swiped from i386, and cloned for MIPS by Geert. - * - */ - -#include <linux/types.h> -#include <linux/mm.h> -#include <linux/string.h> -#include <linux/pci.h> -#include <asm/io.h> - -void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, - dma_addr_t *dma_handle) -{ - void *ret; - int gfp = GFP_ATOMIC; - - if (hwdev == NULL || hwdev->dma_mask != 0xffffffff) - gfp |= GFP_DMA; - ret = (void *)__get_free_pages(gfp, get_order(size)); - - if (ret != NULL) { - memset(ret, 0, size); - *dma_handle = virt_to_bus(ret); - } - return ret; -} - -void pci_free_consistent(struct pci_dev *hwdev, size_t size, - void *vaddr, dma_addr_t dma_handle) -{ - free_pages((unsigned long)vaddr, get_order(size)); -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5074/pci.c linux.ac/arch/mips/ddb5074/pci.c --- linux.vanilla/arch/mips/ddb5074/pci.c Tue Nov 28 01:51:34 2000 +++ linux.ac/arch/mips/ddb5074/pci.c Tue Apr 3 17:54:32 2001 @@ -4,313 +4,325 @@ * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> * Albert Dorofeev <albert@sonycom.com> * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id: pci.c,v 1.4 2000/02/18 00:02:17 ralf Exp $ */ - #include <linux/init.h> #include <linux/kernel.h> #include <linux/pci.h> #include <linux/types.h> #include <linux/sched.h> #include <linux/ioport.h> -#include <asm-mips/nile4.h> + +#include <asm/nile4.h> static u32 nile4_pre_pci_access0(int slot_num) { - u32 pci_addr = 0; - u32 virt_addr = NILE4_PCI_CFG_BASE; + u32 pci_addr = 0; + u32 virt_addr = NILE4_PCI_CFG_BASE; - /* Set window 1 address 8000000 - 64 bit - 2 MB (PCI config space) */ - nile4_set_pdar(NILE4_PCIW1, PHYSADDR(virt_addr), 0x00200000, 64, 0, 0); - if (slot_num > 2) - pci_addr = 0x00040000 << slot_num; - else - virt_addr += 0x00040000 << slot_num; - nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, pci_addr); - return virt_addr; + /* Set window 1 address 8000000 - 64 bit - 2 MB (PCI config space) */ + nile4_set_pdar(NILE4_PCIW1, PHYSADDR(virt_addr), 0x00200000, 64, 0, + 0); + if (slot_num > 2) + pci_addr = 0x00040000 << slot_num; + else + virt_addr += 0x00040000 << slot_num; + nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, pci_addr); + return virt_addr; } static void nile4_post_pci_access0(void) { - /* Set window 1 back to address 8000000 - 64 bit - 128 MB (PCI IO space) */ - nile4_set_pdar(NILE4_PCIW1, PHYSADDR(NILE4_PCI_MEM_BASE), 0x08000000, 64, - 1, 1); - nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0); + /* + * Set window 1 back to address 8000000 - 64 bit - 128 MB + * (PCI IO space) + */ + nile4_set_pdar(NILE4_PCIW1, PHYSADDR(NILE4_PCI_MEM_BASE), + 0x08000000, 64, 1, 1); + nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0); } -static int nile4_pci_read_config_dword( struct pci_dev *dev, - int where, u32 *val) +static int nile4_pci_read_config_dword(struct pci_dev *dev, + int where, u32 * val) { - int slot_num, func_num; - u32 base; - - /* - * For starters let's do configuration cycle 0 only (one bus only) - */ - if (dev->bus->number) - return PCIBIOS_FUNC_NOT_SUPPORTED; + int slot_num, func_num; + u32 base; - slot_num = PCI_SLOT(dev->devfn); - func_num = PCI_FUNC(dev->devfn); - if (slot_num == 5) { /* - * This is Nile 4 and it will crash if we access it like other - * devices + * For starters let's do configuration cycle 0 only (one bus only) */ - *val = nile4_in32(NILE4_PCI_BASE + where); + if (dev->bus->number) + return PCIBIOS_FUNC_NOT_SUPPORTED; + + slot_num = PCI_SLOT(dev->devfn); + func_num = PCI_FUNC(dev->devfn); + if (slot_num == 5) { + /* + * This is Nile 4 and it will crash if we access it like other + * devices + */ + *val = nile4_in32(NILE4_PCI_BASE + where); + return PCIBIOS_SUCCESSFUL; + } + base = nile4_pre_pci_access0(slot_num); + *val = + *((volatile u32 *) (base + (func_num << 8) + (where & 0xfc))); + nile4_post_pci_access0(); return PCIBIOS_SUCCESSFUL; - } - base = nile4_pre_pci_access0(slot_num); - *val = *((volatile u32 *)(base + (func_num << 8) + (where & 0xfc))); - nile4_post_pci_access0(); - return PCIBIOS_SUCCESSFUL; } static int nile4_pci_write_config_dword(struct pci_dev *dev, int where, u32 val) { - int slot_num, func_num; - u32 base; + int slot_num, func_num; + u32 base; - /* - * For starters let's do configuration cycle 0 only (one bus only) - */ - if (dev->bus->number) - return PCIBIOS_FUNC_NOT_SUPPORTED; - - slot_num = PCI_SLOT(dev->devfn); - func_num = PCI_FUNC(dev->devfn); - if (slot_num == 5) { /* - * This is Nile 4 and it will crash if we access it like other - * devices + * For starters let's do configuration cycle 0 only (one bus only) */ - nile4_out32(NILE4_PCI_BASE + where, val); + if (dev->bus->number) + return PCIBIOS_FUNC_NOT_SUPPORTED; + + slot_num = PCI_SLOT(dev->devfn); + func_num = PCI_FUNC(dev->devfn); + if (slot_num == 5) { + /* + * This is Nile 4 and it will crash if we access it like other + * devices + */ + nile4_out32(NILE4_PCI_BASE + where, val); + return PCIBIOS_SUCCESSFUL; + } + base = nile4_pre_pci_access0(slot_num); + *((volatile u32 *) (base + (func_num << 8) + (where & 0xfc))) = + val; + nile4_post_pci_access0(); + return PCIBIOS_SUCCESSFUL; +} + +static int nile4_pci_read_config_word(struct pci_dev *dev, int where, + u16 * val) +{ + int status; + u32 result; + + status = nile4_pci_read_config_dword(dev, where, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 2) + result >>= 16; + *val = result & 0xffff; return PCIBIOS_SUCCESSFUL; - } - base = nile4_pre_pci_access0(slot_num); - *((volatile u32 *)(base + (func_num << 8) + (where & 0xfc))) = val; - nile4_post_pci_access0(); - return PCIBIOS_SUCCESSFUL; -} - -static int nile4_pci_read_config_word(struct pci_dev *dev, int where, u16 *val) -{ - int status; - u32 result; - - status = nile4_pci_read_config_dword(dev, where, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - if (where & 2) - result >>= 16; - *val = result & 0xffff; - return PCIBIOS_SUCCESSFUL; -} - -static int nile4_pci_read_config_byte(struct pci_dev *dev, int where, u8 *val) -{ - int status; - u32 result; - - status = nile4_pci_read_config_dword(dev, where, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - if (where & 1) - result >>= 8; - if (where & 2) - result >>= 16; - *val = result & 0xff; - return PCIBIOS_SUCCESSFUL; -} - -static int nile4_pci_write_config_word(struct pci_dev *dev, int where, u16 val) -{ - int status, shift = 0; - u32 result; - - status = nile4_pci_read_config_dword(dev, where, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - if (where & 2) - shift += 16; - result &= ~(0xffff << shift); - result |= val << shift; - return nile4_pci_write_config_dword(dev, where, result); -} - -static int nile4_pci_write_config_byte( struct pci_dev *dev, int where, u8 val) -{ - int status, shift = 0; - u32 result; - - status = nile4_pci_read_config_dword(dev, where, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - if (where & 2) - shift += 16; - if (where & 1) - shift += 8; - result &= ~(0xff << shift); - result |= val << shift; - return nile4_pci_write_config_dword(dev, where, result); +} + +static int nile4_pci_read_config_byte(struct pci_dev *dev, int where, + u8 * val) +{ + int status; + u32 result; + + status = nile4_pci_read_config_dword(dev, where, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 1) + result >>= 8; + if (where & 2) + result >>= 16; + *val = result & 0xff; + return PCIBIOS_SUCCESSFUL; +} + +static int nile4_pci_write_config_word(struct pci_dev *dev, int where, + u16 val) +{ + int status, shift = 0; + u32 result; + + status = nile4_pci_read_config_dword(dev, where, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 2) + shift += 16; + result &= ~(0xffff << shift); + result |= val << shift; + return nile4_pci_write_config_dword(dev, where, result); +} + +static int nile4_pci_write_config_byte(struct pci_dev *dev, int where, + u8 val) +{ + int status, shift = 0; + u32 result; + + status = nile4_pci_read_config_dword(dev, where, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 2) + shift += 16; + if (where & 1) + shift += 8; + result &= ~(0xff << shift); + result |= val << shift; + return nile4_pci_write_config_dword(dev, where, result); } struct pci_ops nile4_pci_ops = { - nile4_pci_read_config_byte, - nile4_pci_read_config_word, - nile4_pci_read_config_dword, - nile4_pci_write_config_byte, - nile4_pci_write_config_word, - nile4_pci_write_config_dword + nile4_pci_read_config_byte, + nile4_pci_read_config_word, + nile4_pci_read_config_dword, + nile4_pci_write_config_byte, + nile4_pci_write_config_word, + nile4_pci_write_config_dword }; struct { - struct resource ram; - struct resource flash; - struct resource isa_io; - struct resource pci_io; - struct resource isa_mem; - struct resource pci_mem; - struct resource nile4; - struct resource boot; + struct resource ram; + struct resource flash; + struct resource isa_io; + struct resource pci_io; + struct resource isa_mem; + struct resource pci_mem; + struct resource nile4; + struct resource boot; } ddb5074_resources = { - { "RAM", 0x00000000, 0x03ffffff, - IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 }, - { "Flash ROM", 0x04000000, 0x043fffff }, - { "Nile4 ISA I/O", 0x06000000, 0x060fffff }, - { "Nile4 PCI I/O", 0x06100000, 0x07ffffff }, - { "Nile4 ISA mem", 0x08000000, 0x08ffffff, IORESOURCE_MEM }, - { "Nile4 PCI mem", 0x09000000, 0x0fffffff, IORESOURCE_MEM }, - { "Nile4 ctrl", 0x1fa00000, 0x1fbfffff, - IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 }, - { "Boot ROM", 0x1fc00000, 0x1fffffff } + { "RAM", 0x00000000, 0x03ffffff, + IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64}, + { "Flash ROM", 0x04000000, 0x043fffff}, + { "Nile4 ISA I/O", 0x06000000, 0x060fffff}, + { "Nile4 PCI I/O", 0x06100000, 0x07ffffff}, + { "Nile4 ISA mem", 0x08000000, 0x08ffffff, IORESOURCE_MEM}, + { "Nile4 PCI mem", 0x09000000, 0x0fffffff, IORESOURCE_MEM}, + { "Nile4 ctrl", 0x1fa00000, 0x1fbfffff, + IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64}, + { "Boot ROM", 0x1fc00000, 0x1fffffff} }; static void __init ddb5074_pci_fixup(void) { - struct pci_dev *dev; + struct pci_dev *dev; - pci_for_each_dev(dev) { - if (dev->vendor == PCI_VENDOR_ID_NEC && - dev->device == PCI_DEVICE_ID_NEC_NILE4) { - /* - * The first 64-bit PCI base register should point to the Nile4 - * control registers. Unfortunately this isn't the case, so we fix - * it ourselves. This allows the serial driver to find the UART. - */ - dev->resource[0] = ddb5074_resources.nile4; - request_resource(&iomem_resource, &dev->resource[0]); - /* - * The second 64-bit PCI base register points to the first memory - * bank. Unfortunately the address is wrong, so we fix it (again). - */ - dev->resource[2] = ddb5074_resources.ram; - request_resource(&iomem_resource, &dev->resource[2]); - } else if (dev->vendor == PCI_VENDOR_ID_AL && - dev->device == PCI_DEVICE_ID_AL_M7101) { - /* - * It's nice to have the LEDs on the GPIO pins available for - * debugging - */ - extern struct pci_dev *pci_pmu; - u8 t8; - - pci_pmu = dev; /* for LEDs D2 and D3 */ - /* Program the lines for LEDs D2 and D3 to output */ - nile4_pci_read_config_byte(dev, 0x7d, &t8); - t8 |= 0xc0; - nile4_pci_write_config_byte(dev, 0x7d, t8); - /* Turn LEDs D2 and D3 off */ - nile4_pci_read_config_byte(dev, 0x7e, &t8); - t8 |= 0xc0; - nile4_pci_write_config_byte(dev, 0x7e, t8); + pci_for_each_dev(dev) { + if (dev->vendor == PCI_VENDOR_ID_NEC && + dev->device == PCI_DEVICE_ID_NEC_NILE4) { + /* + * The first 64-bit PCI base register should point to + * the Nile4 control registers. Unfortunately this + * isn't the case, so we fix it ourselves. This allows + * the serial driver to find the UART. + */ + dev->resource[0] = ddb5074_resources.nile4; + request_resource(&iomem_resource, + &dev->resource[0]); + /* + * The second 64-bit PCI base register points to the + * first memory bank. Unfortunately the address is + * wrong, so we fix it (again). + */ + dev->resource[2] = ddb5074_resources.ram; + request_resource(&iomem_resource, + &dev->resource[2]); + } else if (dev->vendor == PCI_VENDOR_ID_AL + && dev->device == PCI_DEVICE_ID_AL_M7101) { + /* + * It's nice to have the LEDs on the GPIO pins + * available for debugging + */ + extern struct pci_dev *pci_pmu; + u8 t8; + + pci_pmu = dev; /* for LEDs D2 and D3 */ + /* Program the lines for LEDs D2 and D3 to output */ + nile4_pci_read_config_byte(dev, 0x7d, &t8); + t8 |= 0xc0; + nile4_pci_write_config_byte(dev, 0x7d, t8); + /* Turn LEDs D2 and D3 off */ + nile4_pci_read_config_byte(dev, 0x7e, &t8); + t8 |= 0xc0; + nile4_pci_write_config_byte(dev, 0x7e, t8); + } } - } } static void __init pcibios_fixup_irqs(void) { - struct pci_dev *dev; - int slot_num; + struct pci_dev *dev; + int slot_num; - pci_for_each_dev(dev) { - slot_num = PCI_SLOT(dev->devfn); - switch (slot_num) { - case 0: - dev->irq = nile4_to_irq(NILE4_INT_INTE); - break; - case 1: - dev->irq = nile4_to_irq(NILE4_INT_INTA); - break; - case 2: /* slot 1 */ - dev->irq = nile4_to_irq(NILE4_INT_INTA); - break; - case 3: /* slot 2 */ - dev->irq = nile4_to_irq(NILE4_INT_INTB); - break; - case 4: /* slot 3 */ - dev->irq = nile4_to_irq(NILE4_INT_INTC); - break; - case 5: - /* - * Fixup so the serial driver can use the UART - */ - dev->irq = nile4_to_irq(NILE4_INT_UART); - break; - case 13: - dev->irq = nile4_to_irq(NILE4_INT_INTE); - break; - default: - break; + pci_for_each_dev(dev) { + slot_num = PCI_SLOT(dev->devfn); + switch (slot_num) { + case 0: + dev->irq = nile4_to_irq(NILE4_INT_INTE); + break; + case 1: + dev->irq = nile4_to_irq(NILE4_INT_INTA); + break; + case 2: /* slot 1 */ + dev->irq = nile4_to_irq(NILE4_INT_INTA); + break; + case 3: /* slot 2 */ + dev->irq = nile4_to_irq(NILE4_INT_INTB); + break; + case 4: /* slot 3 */ + dev->irq = nile4_to_irq(NILE4_INT_INTC); + break; + case 5: + /* + * Fixup so the serial driver can use the UART + */ + dev->irq = nile4_to_irq(NILE4_INT_UART); + break; + case 13: + dev->irq = nile4_to_irq(NILE4_INT_INTE); + break; + default: + break; + } } - } } void __init pcibios_init(void) { - printk("PCI: Probing PCI hardware\n"); - ioport_resource.end = 0x1ffffff; /* 32 MB */ - iomem_resource.end = 0x1fffffff; /* 512 MB */ - /* `ram' and `nile4' are requested through the Nile4 pci_dev */ - request_resource(&iomem_resource, &ddb5074_resources.flash); - request_resource(&iomem_resource, &ddb5074_resources.isa_io); - request_resource(&iomem_resource, &ddb5074_resources.pci_io); - request_resource(&iomem_resource, &ddb5074_resources.isa_mem); - request_resource(&iomem_resource, &ddb5074_resources.pci_mem); - request_resource(&iomem_resource, &ddb5074_resources.boot); - - pci_scan_bus(0, &nile4_pci_ops, NULL); - ddb5074_pci_fixup(); - pci_assign_unassigned_resources(); - pcibios_fixup_irqs(); + printk("PCI: Probing PCI hardware\n"); + ioport_resource.end = 0x1ffffff; /* 32 MB */ + iomem_resource.end = 0x1fffffff; /* 512 MB */ + /* `ram' and `nile4' are requested through the Nile4 pci_dev */ + request_resource(&iomem_resource, &ddb5074_resources.flash); + request_resource(&iomem_resource, &ddb5074_resources.isa_io); + request_resource(&iomem_resource, &ddb5074_resources.pci_io); + request_resource(&iomem_resource, &ddb5074_resources.isa_mem); + request_resource(&iomem_resource, &ddb5074_resources.pci_mem); + request_resource(&iomem_resource, &ddb5074_resources.boot); + + pci_scan_bus(0, &nile4_pci_ops, NULL); + ddb5074_pci_fixup(); + pci_assign_unassigned_resources(); + pcibios_fixup_irqs(); } void __init pcibios_fixup_bus(struct pci_bus *bus) { - bus->resource[1] = &ddb5074_resources.pci_mem; + bus->resource[1] = &ddb5074_resources.pci_mem; } -char *pcibios_setup (char *str) +char *pcibios_setup(char *str) { - return str; + return str; } void __init pcibios_update_irq(struct pci_dev *dev, int irq) { - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); } void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges) { - ranges->io_start -= bus->resource[0]->start; - ranges->io_end -= bus->resource[0]->start; - ranges->mem_start -= bus->resource[1]->start; - ranges->mem_end -= bus->resource[1]->start; + ranges->io_start -= bus->resource[0]->start; + ranges->io_end -= bus->resource[0]->start; + ranges->mem_start -= bus->resource[1]->start; + ranges->mem_end -= bus->resource[1]->start; } int pcibios_enable_resources(struct pci_dev *dev) @@ -323,15 +335,15 @@ * Don't touch the Nile 4 */ if (dev->vendor == PCI_VENDOR_ID_NEC && - dev->device == PCI_DEVICE_ID_NEC_NILE4) - return 0; + dev->device == PCI_DEVICE_ID_NEC_NILE4) return 0; pci_read_config_word(dev, PCI_COMMAND, &cmd); old_cmd = cmd; - for(idx=0; idx<6; idx++) { + for (idx = 0; idx < 6; idx++) { r = &dev->resource[idx]; if (!r->start && r->end) { - printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); + printk(KERN_ERR "PCI: Device %s not available because " + "of resource collisions\n", dev->slot_name); return -EINVAL; } if (r->flags & IORESOURCE_IO) @@ -340,7 +352,8 @@ cmd |= PCI_COMMAND_MEMORY; } if (cmd != old_cmd) { - printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd); + printk("PCI: Enabling device %s (%04x -> %04x)\n", + dev->slot_name, old_cmd, cmd); pci_write_config_word(dev, PCI_COMMAND, cmd); } return 0; @@ -348,7 +361,7 @@ int pcibios_enable_device(struct pci_dev *dev) { - return pcibios_enable_resources(dev); + return pcibios_enable_resources(dev); } void pcibios_update_resource(struct pci_dev *dev, struct resource *root, @@ -359,18 +372,23 @@ new = res->start | (res->flags & PCI_REGION_FLAG_MASK); if (resource < 6) { - reg = PCI_BASE_ADDRESS_0 + 4*resource; + reg = PCI_BASE_ADDRESS_0 + 4 * resource; } else if (resource == PCI_ROM_RESOURCE) { res->flags |= PCI_ROM_ADDRESS_ENABLE; reg = dev->rom_base_reg; } else { - /* Somebody might have asked allocation of a non-standard resource */ + /* + * Somebody might have asked allocation of a non-standard + * resource + */ return; } - + pci_write_config_dword(dev, reg, new); pci_read_config_dword(dev, reg, &check); - if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) { + if ((new ^ check) & + ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : + PCI_BASE_ADDRESS_MEM_MASK)) { printk(KERN_ERR "PCI: Error while updating region " "%s/%d (%08x != %08x)\n", dev->slot_name, resource, new, check); @@ -400,5 +418,4 @@ } -struct pci_fixup pcibios_fixups[] = {}; - +struct pci_fixup pcibios_fixups[] = { }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5074/prom.c linux.ac/arch/mips/ddb5074/prom.c --- linux.vanilla/arch/mips/ddb5074/prom.c Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/ddb5074/prom.c Tue Apr 3 17:54:32 2001 @@ -3,58 +3,32 @@ * * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id: prom.c,v 1.1 2000/01/26 00:07:44 ralf Exp $ */ - #include <linux/init.h> #include <linux/mm.h> #include <linux/sched.h> #include <linux/bootmem.h> + #include <asm/addrspace.h> #include <asm/bootinfo.h> -char arcs_cmdline[CL_SIZE]; - -extern char _end; - -#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) -#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) - +char arcs_cmdline[COMMAND_LINE_SIZE]; void __init prom_init(const char *s) { - int i = 0; - unsigned long mem_size, free_start, free_end, start_pfn, bootmap_size; + int i = 0; -// _serinit(); + if (s != (void *) -1) + while (*s && i < sizeof(arcs_cmdline) - 1) + arcs_cmdline[i++] = *s++; + arcs_cmdline[i] = '\0'; - if (s != (void *)-1) - while (*s && i < sizeof(arcs_cmdline)-1) - arcs_cmdline[i++] = *s++; - arcs_cmdline[i] = '\0'; - - mips_machgroup = MACH_GROUP_NEC_DDB; - mips_machtype = MACH_NEC_DDB5074; - /* 64 MB non-upgradable */ - mem_size = 64 << 20; - - free_start = PHYSADDR(PFN_ALIGN(&_end)); - free_end = mem_size; - start_pfn = PFN_UP((unsigned long)&_end); - - /* Register all the contiguous memory with the bootmem allocator - and free it. Be careful about the bootmem freemap. */ - bootmap_size = init_bootmem(start_pfn, mem_size >> PAGE_SHIFT); - - /* Free the entire available memory after the _end symbol. */ - free_start += bootmap_size; - free_bootmem(free_start, free_end-free_start); -} + mips_machgroup = MACH_GROUP_NEC_DDB; + mips_machtype = MACH_NEC_DDB5074; -void __init prom_fixup_mem_map(unsigned long start, unsigned long end) -{ + /* 64 MB non-upgradable */ + add_memory_region(0, 64 << 20, BOOT_MEM_RAM); } void __init prom_free_prom_memory(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5074/setup.c linux.ac/arch/mips/ddb5074/setup.c --- linux.vanilla/arch/mips/ddb5074/setup.c Mon Jul 10 06:18:15 2000 +++ linux.ac/arch/mips/ddb5074/setup.c Tue Apr 3 17:54:32 2001 @@ -3,10 +3,7 @@ * * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id: setup.c,v 1.1 2000/01/26 00:07:44 ralf Exp $ */ - #include <linux/config.h> #include <linux/init.h> #include <linux/kbd_ll.h> @@ -42,85 +39,83 @@ extern struct ide_ops std_ide_ops; extern struct rtc_ops ddb_rtc_ops; -static void (*back_to_prom)(void) = (void (*)(void))0xbfc00000; +static void (*back_to_prom) (void) = (void (*)(void)) 0xbfc00000; static void ddb_machine_restart(char *command) { - u32 t; + u32 t; - /* PCI cold reset */ - t = nile4_in32(NILE4_PCICTRL+4); - t |= 0x40000000; - nile4_out32(NILE4_PCICTRL+4, t); - /* CPU cold reset */ - t = nile4_in32(NILE4_CPUSTAT); - t |= 1; - nile4_out32(NILE4_CPUSTAT, t); - /* Call the PROM */ - back_to_prom(); + /* PCI cold reset */ + t = nile4_in32(NILE4_PCICTRL + 4); + t |= 0x40000000; + nile4_out32(NILE4_PCICTRL + 4, t); + /* CPU cold reset */ + t = nile4_in32(NILE4_CPUSTAT); + t |= 1; + nile4_out32(NILE4_CPUSTAT, t); + /* Call the PROM */ + back_to_prom(); } static void ddb_machine_halt(void) { - printk("DDB Vrc-5074 halted.\n"); - do {} while (1); + printk("DDB Vrc-5074 halted.\n"); + do { + } while (1); } static void ddb_machine_power_off(void) { - printk("DDB Vrc-5074 halted. Please turn off the power.\n"); - do {} while (1); + printk("DDB Vrc-5074 halted. Please turn off the power.\n"); + do { + } while (1); } extern void ddb_irq_setup(void); -void (*board_time_init)(struct irqaction *irq); +void (*board_time_init) (struct irqaction * irq); static void __init ddb_time_init(struct irqaction *irq) { - /* set the clock to 1 Hz */ - nile4_out32(NILE4_T2CTRL, 1000000); - /* enable the General-Purpose Timer */ - nile4_out32(NILE4_T2CTRL+4, 0x00000001); - /* reset timer */ - nile4_out32(NILE4_T2CNTR, 0); - /* enable interrupt */ - nile4_enable_irq(NILE4_INT_GPT); - i8259_setup_irq(nile4_to_irq(NILE4_INT_GPT), irq); - set_cp0_status(ST0_IM, IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4); + /* set the clock to 1 Hz */ + nile4_out32(NILE4_T2CTRL, 1000000); + /* enable the General-Purpose Timer */ + nile4_out32(NILE4_T2CTRL + 4, 0x00000001); + /* reset timer */ + nile4_out32(NILE4_T2CNTR, 0); + /* enable interrupt */ + nile4_enable_irq(NILE4_INT_GPT); + i8259_setup_irq(nile4_to_irq(NILE4_INT_GPT), irq); + change_cp0_status(ST0_IM, + IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4); } void __init ddb_setup(void) { - extern int panic_timeout; + extern int panic_timeout; - irq_setup = ddb_irq_setup; - mips_io_port_base = NILE4_PCI_IO_BASE; - isa_slot_offset = NILE4_PCI_MEM_BASE; - request_region(0x00, 0x20, "dma1"); - request_region(0x40, 0x20, "timer"); - request_region(0x70, 0x10, "rtc"); - request_region(0x80, 0x10, "dma page reg"); - request_region(0xc0, 0x20, "dma2"); - board_time_init = ddb_time_init; - - _machine_restart = ddb_machine_restart; - _machine_halt = ddb_machine_halt; - _machine_power_off = ddb_machine_power_off; + irq_setup = ddb_irq_setup; + mips_io_port_base = NILE4_PCI_IO_BASE; + isa_slot_offset = NILE4_PCI_MEM_BASE; + request_region(0x00, 0x20, "dma1"); + request_region(0x40, 0x20, "timer"); + request_region(0x70, 0x10, "rtc"); + request_region(0x80, 0x10, "dma page reg"); + request_region(0xc0, 0x20, "dma2"); + board_time_init = ddb_time_init; + + _machine_restart = ddb_machine_restart; + _machine_halt = ddb_machine_halt; + _machine_power_off = ddb_machine_power_off; #ifdef CONFIG_BLK_DEV_IDE - ide_ops = &std_ide_ops; + ide_ops = &std_ide_ops; #endif - rtc_ops = &ddb_rtc_ops; + rtc_ops = &ddb_rtc_ops; - /* Reboot on panic */ - panic_timeout = 180; -} - -int __init page_is_ram(unsigned long pagenr) -{ - return 1; + /* Reboot on panic */ + panic_timeout = 180; } @@ -133,12 +128,12 @@ #define NS16550_BASE (NILE4_PCI_IO_BASE+0x03f8) static inline u8 ns16550_in(u32 reg) { - return *(volatile u8 *)(NS16550_BASE+reg); + return *(volatile u8 *) (NS16550_BASE + reg); } static inline void ns16550_out(u32 reg, u8 val) { - *(volatile u8 *)(NS16550_BASE+reg) = val; + *(volatile u8 *) (NS16550_BASE + reg) = val; } #endif @@ -168,87 +163,84 @@ void _serinit(void) { #if USE_NILE4_SERIAL - ns16550_out(NS16550_LCR, 0x80); - ns16550_out(NS16550_DLM, 0x00); - ns16550_out(NS16550_DLL, 0x36); /* 9600 baud */ - ns16550_out(NS16550_LCR, 0x00); - ns16550_out(NS16550_LCR, 0x03); - ns16550_out(NS16550_FCR, 0x47); + ns16550_out(NS16550_LCR, 0x80); + ns16550_out(NS16550_DLM, 0x00); + ns16550_out(NS16550_DLL, 0x36); /* 9600 baud */ + ns16550_out(NS16550_LCR, 0x00); + ns16550_out(NS16550_LCR, 0x03); + ns16550_out(NS16550_FCR, 0x47); #else - /* done by PMON */ + /* done by PMON */ #endif } void _putc(char c) { - while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE)); - ns16550_out(NS16550_THR, c); - if (c == '\n') { while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE)); - ns16550_out(NS16550_THR, '\r'); - } + ns16550_out(NS16550_THR, c); + if (c == '\n') { + while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE)); + ns16550_out(NS16550_THR, '\r'); + } } void _puts(const char *s) { - char c; - while ((c = *s++)) - _putc(c); + char c; + while ((c = *s++)) + _putc(c); } char _getc(void) { - while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_DR)); - return ns16550_in(NS16550_RBR); + while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_DR)); + return ns16550_in(NS16550_RBR); } int _testc(void) { - return (ns16550_in(NS16550_LSR) & NS16550_LSR_DR) != 0; + return (ns16550_in(NS16550_LSR) & NS16550_LSR_DR) != 0; } - /* - * Hexadecimal 7-segment LED - */ - +/* + * Hexadecimal 7-segment LED + */ void ddb5074_led_hex(int hex) { - outb(hex, 0x80); + outb(hex, 0x80); } - /* - * LEDs D2 and D3, connected to the GPIO pins of the PMU in the ALi M1543 - */ - +/* + * LEDs D2 and D3, connected to the GPIO pins of the PMU in the ALi M1543 + */ struct pci_dev *pci_pmu = NULL; void ddb5074_led_d2(int on) { - u8 t; + u8 t; - if (pci_pmu) { - pci_read_config_byte(pci_pmu, 0x7e, &t); - if (on) - t &= 0x7f; - else - t |= 0x80; - pci_write_config_byte(pci_pmu, 0x7e, t); - } + if (pci_pmu) { + pci_read_config_byte(pci_pmu, 0x7e, &t); + if (on) + t &= 0x7f; + else + t |= 0x80; + pci_write_config_byte(pci_pmu, 0x7e, t); + } } void ddb5074_led_d3(int on) { - u8 t; + u8 t; - if (pci_pmu) { - pci_read_config_byte(pci_pmu, 0x7e, &t); - if (on) - t &= 0xbf; - else - t |= 0x40; - pci_write_config_byte(pci_pmu, 0x7e, t); - } + if (pci_pmu) { + pci_read_config_byte(pci_pmu, 0x7e, &t); + if (on) + t &= 0xbf; + else + t |= 0x40; + pci_write_config_byte(pci_pmu, 0x7e, t); + } } - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5074/time.c linux.ac/arch/mips/ddb5074/time.c --- linux.vanilla/arch/mips/ddb5074/time.c Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/ddb5074/time.c Tue Apr 3 17:54:32 2001 @@ -3,33 +3,30 @@ * * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id* */ - #include <linux/init.h> #include <asm/mc146818rtc.h> static unsigned char ddb_rtc_read_data(unsigned long addr) { - outb_p(addr, RTC_PORT(0)); - return inb_p(RTC_PORT(1)); + outb_p(addr, RTC_PORT(0)); + + return inb_p(RTC_PORT(1)); } static void ddb_rtc_write_data(unsigned char data, unsigned long addr) { - outb_p(addr, RTC_PORT(0)); - outb_p(data, RTC_PORT(1)); + outb_p(addr, RTC_PORT(0)); + outb_p(data, RTC_PORT(1)); } static int ddb_rtc_bcd_mode(void) { - return 1; + return 1; } struct rtc_ops ddb_rtc_ops = { - ddb_rtc_read_data, - ddb_rtc_write_data, - ddb_rtc_bcd_mode + ddb_rtc_read_data, + ddb_rtc_write_data, + ddb_rtc_bcd_mode }; - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5476/Makefile linux.ac/arch/mips/ddb5476/Makefile --- linux.vanilla/arch/mips/ddb5476/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ddb5476/Makefile Tue Apr 3 17:54:32 2001 @@ -0,0 +1,23 @@ +# +# Makefile for the NEC DDB Vrc-5074 specific kernel interface routines +# under Linux. +# +# 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.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +O_TARGET = ddb5476.a + +obj-y += setup.o irq.o time.o prom.o pci.o \ + int-handler.o nile4.o +obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5476/dbg_io.c linux.ac/arch/mips/ddb5476/dbg_io.c --- linux.vanilla/arch/mips/ddb5476/dbg_io.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ddb5476/dbg_io.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,125 @@ + +#include <linux/config.h> + +#if (defined(CONFIG_DDB5476) && defined(CONFIG_REMOTE_DEBUG)) + +/* --- CONFIG --- */ + +/* we need uint32 uint8 */ +/* #include "types.h" */ +typedef unsigned char uint8; +typedef unsigned int uint32; + +/* --- END OF CONFIG --- */ + +#define UART16550_BAUD_2400 2400 +#define UART16550_BAUD_4800 4800 +#define UART16550_BAUD_9600 9600 +#define UART16550_BAUD_19200 19200 +#define UART16550_BAUD_38400 38400 +#define UART16550_BAUD_57600 57600 +#define UART16550_BAUD_115200 115200 + +#define UART16550_PARITY_NONE 0 +#define UART16550_PARITY_ODD 0x08 +#define UART16550_PARITY_EVEN 0x18 +#define UART16550_PARITY_MARK 0x28 +#define UART16550_PARITY_SPACE 0x38 + +#define UART16550_DATA_5BIT 0x0 +#define UART16550_DATA_6BIT 0x1 +#define UART16550_DATA_7BIT 0x2 +#define UART16550_DATA_8BIT 0x3 + +#define UART16550_STOP_1BIT 0x0 +#define UART16550_STOP_2BIT 0x4 + +/* ----------------------------------------------------- */ + +/* === CONFIG === */ + +/* [jsun] we use the second serial port for kdb */ +#define BASE 0xa60002f8 +#define MAX_BAUD 115200 + +/* === END OF CONFIG === */ + +/* register offset */ +#define OFS_RCV_BUFFER 0 +#define OFS_TRANS_HOLD 0 +#define OFS_SEND_BUFFER 0 +#define OFS_INTR_ENABLE 1 +#define OFS_INTR_ID 2 +#define OFS_DATA_FORMAT 3 +#define OFS_LINE_CONTROL 3 +#define OFS_MODEM_CONTROL 4 +#define OFS_RS232_OUTPUT 4 +#define OFS_LINE_STATUS 5 +#define OFS_MODEM_STATUS 6 +#define OFS_RS232_INPUT 6 +#define OFS_SCRATCH_PAD 7 + +#define OFS_DIVISOR_LSB 0 +#define OFS_DIVISOR_MSB 1 + + +/* memory-mapped read/write of the port */ +#define UART16550_READ(y) (*((volatile uint8*)(BASE + y))) +#define UART16550_WRITE(y, z) ((*((volatile uint8*)(BASE + y))) = z) + +void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop) +{ + /* disable interrupts */ + UART16550_WRITE(OFS_INTR_ENABLE, 0); + + /* set up buad rate */ + { + uint32 divisor; + + /* set DIAB bit */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x80); + + /* set divisor */ + divisor = MAX_BAUD / baud; + UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff); + UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8); + + /* clear DIAB bit */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x0); + } + + /* set data format */ + UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop); +} + +static int remoteDebugInitialized = 0; + +uint8 getDebugChar(void) +{ + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(UART16550_BAUD_38400, + UART16550_DATA_8BIT, + UART16550_PARITY_NONE, UART16550_STOP_1BIT); + } + + while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0); + return UART16550_READ(OFS_RCV_BUFFER); +} + + +int putDebugChar(uint8 byte) +{ + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(UART16550_BAUD_9600, + UART16550_DATA_8BIT, + UART16550_PARITY_NONE, UART16550_STOP_1BIT); + } + + while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0); + UART16550_WRITE(OFS_SEND_BUFFER, byte); + return 1; +} + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5476/int-handler.S linux.ac/arch/mips/ddb5476/int-handler.S --- linux.vanilla/arch/mips/ddb5476/int-handler.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ddb5476/int-handler.S Tue Apr 3 17:54:32 2001 @@ -0,0 +1,125 @@ +/* + * arch/mips/ddb5074/int-handler.S -- NEC DDB Vrc-5074 interrupt handler + * + * Based on arch/mips/sgi/kernel/indyIRQ.S + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include <asm/asm.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> + +/* + * A lot of complication here is taken away because: + * + * 1) We handle one interrupt and return, sitting in a loop and moving across + * all the pending IRQ bits in the cause register is _NOT_ the answer, the + * common case is one pending IRQ so optimize in that direction. + * + * 2) We need not check against bits in the status register IRQ mask, that + * would make this routine slow as hell. + * + * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in + * between like BSD spl() brain-damage. + * + * Furthermore, the IRQs on the INDY look basically (barring software IRQs + * which we don't use at all) like: + * + * MIPS IRQ Source + * -------- ------ + * 0 Software (ignored) + * 1 Software (ignored) + * 2 Local IRQ level zero + * 3 Local IRQ level one + * 4 8254 Timer zero + * 5 8254 Timer one + * 6 Bus Error + * 7 R4k timer (what we use) + * + * We handle the IRQ according to _our_ priority which is: + * + * Highest ---- R4k Timer + * Local IRQ zero + * Local IRQ one + * Bus Error + * 8254 Timer zero + * Lowest ---- 8254 Timer one + * + * then we just return, if multiple IRQs are pending then we will just take + * another exception, big deal. + */ + + .text + .set noreorder + .set noat + .align 5 + NESTED(ddbIRQ, PT_SIZE, sp) + SAVE_ALL + CLI + .set at + mfc0 s1, CP0_CAUSE # get irq mask + +#if 1 + mfc0 t2,CP0_STATUS # get enabled interrupts + and s0, s1, t2 # isolate allowed ones +#endif + /* First we check for r4k counter/timer IRQ. */ + andi a0, s0, CAUSEF_IP2 # delay slot, check local level zero + beq a0, zero, 1f + andi a0, s0, CAUSEF_IP3 # delay slot, check local level one + + /* Wheee, local level zero interrupt. */ + jal ddb_local0_irqdispatch + move a0, sp # delay slot + + j ret_from_irq + nop # delay slot + +1: + beq a0, zero, 1f + andi a0, s0, CAUSEF_IP6 # delay slot, check bus error + + /* Wheee, local level one interrupt. */ + move a0, sp + jal ddb_local1_irqdispatch + nop + + j ret_from_irq + nop + +1: + beq a0, zero, 1f + nop + + /* Wheee, an asynchronous bus error... */ + move a0, sp + jal ddb_buserror_irq + nop + + j ret_from_irq + nop + +1: + /* Here by mistake? This is possible, what can happen + * is that by the time we take the exception the IRQ + * pin goes low, so just leave if this is the case. + */ + andi a0, s0, (CAUSEF_IP4 | CAUSEF_IP5) + beq a0, zero, 1f + + /* Must be one of the 8254 timers... */ + move a0, sp + jal ddb_8254timer_irq + nop +1: + /* phamtom interrupt */ + move a0, s1 + jal ddb_phantom_irq + nop + j ret_from_irq + nop + END(ddbIRQ) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5476/irq.c linux.ac/arch/mips/ddb5476/irq.c --- linux.vanilla/arch/mips/ddb5476/irq.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ddb5476/irq.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,251 @@ +/* + * arch/mips/ddb5476/irq.c -- NEC DDB Vrc-5476 interrupt routines + * + * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/ptrace.h> +#include <asm/nile4.h> + +extern void __init i8259_init(void); +extern void i8259_disable_irq(unsigned int irq_nr); +extern void i8259_enable_irq(unsigned int irq_nr); + +extern asmlinkage void ddbIRQ(void); +extern asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs); +extern asmlinkage void do_IRQ(int irq, struct pt_regs *regs); + + +void no_action(int cpl, void *dev_id, struct pt_regs *regs) +{ +} + + +#define M1543_PNP_CONFIG 0x03f0 /* PnP Config Port */ +#define M1543_PNP_INDEX 0x03f0 /* PnP Index Port */ +#define M1543_PNP_DATA 0x03f1 /* PnP Data Port */ + +#define M1543_PNP_ALT_CONFIG 0x0370 /* Alternative PnP Config Port */ +#define M1543_PNP_ALT_INDEX 0x0370 /* Alternative PnP Index Port */ +#define M1543_PNP_ALT_DATA 0x0371 /* Alternative PnP Data Port */ + +#define M1543_INT1_MASTER_CTRL 0x0020 /* INT_1 (master) Control Register */ +#define M1543_INT1_MASTER_MASK 0x0021 /* INT_1 (master) Mask Register */ + +#define M1543_INT1_SLAVE_CTRL 0x00a0 /* INT_1 (slave) Control Register */ +#define M1543_INT1_SLAVE_MASK 0x00a1 /* INT_1 (slave) Mask Register */ + +#define M1543_INT1_MASTER_ELCR 0x04d0 /* INT_1 (master) Edge/Level Control */ +#define M1543_INT1_SLAVE_ELCR 0x04d1 /* INT_1 (slave) Edge/Level Control */ + +static struct { + struct resource m1543_config; + struct resource pic_elcr; +} m1543_ioport = { + { "M1543 config", M1543_PNP_CONFIG, M1543_PNP_CONFIG + 1, + IORESOURCE_BUSY}, + { "pic ELCR", M1543_INT1_MASTER_ELCR, M1543_INT1_MASTER_ELCR + 1, + IORESOURCE_BUSY} +}; + +static void m1543_irq_setup(void) +{ + /* + * The ALI M1543 has 13 interrupt inputs, IRQ1..IRQ13. Not all + * the possible IO sources in the M1543 are in use by us. We will + * use the following mapping: + * + * IRQ1 - keyboard (default set by M1543) + * IRQ3 - reserved for UART B (default set by M1543) (note that + * the schematics for the DDB Vrc-5476 board seem to + * indicate that IRQ3 is connected to the DS1386 + * watchdog timer interrupt output so we might have + * a conflict) + * IRQ4 - reserved for UART A (default set by M1543) + * IRQ5 - parallel (default set by M1543) + * IRQ8 - DS1386 time of day (RTC) interrupt + * IRQ9 - USB (hardwired in ddb_setup) + * IRQ10 - PMU (hardwired in ddb_setup) + * IRQ12 - mouse + * IRQ14,15 - IDE controller (need to be confirmed, jsun) + */ + + /* + * Assing mouse interrupt to IRQ12 + */ + + /* Enter configuration mode */ + outb(0x51, M1543_PNP_CONFIG); + outb(0x23, M1543_PNP_CONFIG); + + /* Select logical device 7 (Keyboard) */ + outb(0x07, M1543_PNP_INDEX); + outb(0x07, M1543_PNP_DATA); + + /* Select IRQ12 */ + outb(0x72, M1543_PNP_INDEX); + outb(0x0c, M1543_PNP_DATA); + + /* Leave configration mode */ + outb(0xbb, M1543_PNP_CONFIG); + + + /* Initialize the 8259 PIC in the M1543 */ + i8259_init(); + + /* Enable the interrupt cascade from M1543 */ + nile4_enable_irq(NILE4_INT_INTC); + + /* request io ports */ + if (request_resource(&ioport_resource, &m1543_ioport.m1543_config) + || request_resource(&ioport_resource, &m1543_ioport.pic_elcr)) { + printk("m1543_irq_setup : requesting io ports failed.\n"); + for (;;); + } +} + +static void nile4_irq_setup(void) +{ + int i; + + /* Map all interrupts to CPU int #0 */ + nile4_map_irq_all(0); + + /* PCI INTA#-E# must be level triggered */ + nile4_set_pci_irq_level_or_edge(0, 1); + nile4_set_pci_irq_level_or_edge(1, 1); + nile4_set_pci_irq_level_or_edge(2, 1); + nile4_set_pci_irq_level_or_edge(3, 1); + + /* PCI INTA#, B#, D# must be active low, INTC# must be active high */ + nile4_set_pci_irq_polarity(0, 0); + nile4_set_pci_irq_polarity(1, 0); + nile4_set_pci_irq_polarity(2, 1); + nile4_set_pci_irq_polarity(3, 0); + + for (i = 0; i < 16; i++) + nile4_clear_irq(i); + + /* Enable CPU int #0 */ + nile4_enable_irq_output(0); + + /* memory resource acquire in ddb_setup */ +} + + +/* + * IRQ2 is cascade interrupt to second interrupt controller + */ +static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL }; + + +void disable_irq(unsigned int irq_nr) +{ + if (is_i8259_irq(irq_nr)) + i8259_disable_irq(irq_nr); + else + nile4_disable_irq(irq_to_nile4(irq_nr)); +} + +void enable_irq(unsigned int irq_nr) +{ + if (is_i8259_irq(irq_nr)) + i8259_enable_irq(irq_nr); + else + nile4_enable_irq(irq_to_nile4(irq_nr)); +} + +int table[16] = { 0, }; + +void ddb_local0_irqdispatch(struct pt_regs *regs) +{ + u32 mask; + int nile4_irq; +#if 0 + volatile static int nesting = 0; + if (nesting++ == 0) + ddb5476_led_d3(1); + ddb5476_led_hex(nesting < 16 ? nesting : 15); +#endif + + mask = nile4_get_irq_stat(0); + nile4_clear_irq_mask(mask); + + /* Handle the timer interrupt first */ + if (mask & (1 << NILE4_INT_GPT)) { + nile4_disable_irq(NILE4_INT_GPT); + do_IRQ(nile4_to_irq(NILE4_INT_GPT), regs); + nile4_enable_irq(NILE4_INT_GPT); + mask &= ~(1 << NILE4_INT_GPT); + } + for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1) + if (mask & 1) { + nile4_disable_irq(nile4_irq); + if (nile4_irq == NILE4_INT_INTC) { + int i8259_irq = nile4_i8259_iack(); + i8259_do_irq(i8259_irq, regs); + } else { + do_IRQ(nile4_to_irq(nile4_irq), regs); + } + nile4_enable_irq(nile4_irq); + } +#if 0 + if (--nesting == 0) + ddb5476_led_d3(0); + ddb5476_led_hex(nesting < 16 ? nesting : 15); +#endif +} + +void ddb_local1_irqdispatch(void) +{ + printk("ddb_local1_irqdispatch called\n"); +} + +void ddb_buserror_irq(void) +{ + printk("ddb_buserror_irq called\n"); +} + +void ddb_8254timer_irq(void) +{ + printk("ddb_8254timer_irq called\n"); +} + +void ddb_phantom_irq(unsigned long cause) +{ + printk("phantom interrupts detected : \n"); + printk("\tcause \t\t0x%08x\n", cause); + printk("\tcause reg\t0x%08x\n", + read_32bit_cp0_register(CP0_CAUSE)); + printk("\tstatus reg\t0x%08x\n", + read_32bit_cp0_register(CP0_STATUS)); +} + +void __init ddb_irq_setup(void) +{ +#ifdef CONFIG_REMOTE_DEBUG + printk("Wait for gdb client connection ...\n"); + set_debug_traps(); + breakpoint(); /* you may move this line to whereever you want :-) */ +#endif + i8259_setup_irq(2, &irq2); + + nile4_irq_setup(); + m1543_irq_setup(); + + /* we pin #0 - #4 (no internal timer) */ + change_cp0_status(ST0_IM, + IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4); + + set_except_vector(0, ddbIRQ); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5476/nile4.c linux.ac/arch/mips/ddb5476/nile4.c --- linux.vanilla/arch/mips/ddb5476/nile4.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ddb5476/nile4.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,293 @@ +/* + * arch/mips/ddb5074/nile4.c -- NEC Vrc-5074 Nile 4 support routines + * + * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include <linux/kernel.h> +#include <linux/types.h> + +#include <asm/nile4.h> + + +/* + * Physical Device Address Registers + * + * Note: 32 bit addressing only! + */ +void nile4_set_pdar(u32 pdar, u32 phys, u32 size, int width, + int on_memory_bus, int visible) +{ + u32 maskbits; + u32 widthbits; + + if (pdar > NILE4_BOOTCS || (pdar & 7)) { + printk("nile4_set_pdar: invalid pdar %d\n", pdar); + return; + } + if (pdar == NILE4_INTCS && size != 0x00200000) { + printk("nile4_set_pdar: INTCS size must be 2 MB\n"); + return; + } + switch (size) { +#if 0 /* We don't support 4 GB yet */ + case 0x100000000: /* 4 GB */ + maskbits = 4; + break; +#endif + case 0x80000000: /* 2 GB */ + maskbits = 5; + break; + case 0x40000000: /* 1 GB */ + maskbits = 6; + break; + case 0x20000000: /* 512 MB */ + maskbits = 7; + break; + case 0x10000000: /* 256 MB */ + maskbits = 8; + break; + case 0x08000000: /* 128 MB */ + maskbits = 9; + break; + case 0x04000000: /* 64 MB */ + maskbits = 10; + break; + case 0x02000000: /* 32 MB */ + maskbits = 11; + break; + case 0x01000000: /* 16 MB */ + maskbits = 12; + break; + case 0x00800000: /* 8 MB */ + maskbits = 13; + break; + case 0x00400000: /* 4 MB */ + maskbits = 14; + break; + case 0x00200000: /* 2 MB */ + maskbits = 15; + break; + case 0: /* OFF */ + maskbits = 0; + break; + default: + printk("nile4_set_pdar: unsupported size %p\n", + (void *) size); + return; + } + switch (width) { + case 8: + widthbits = 0; + break; + case 16: + widthbits = 1; + break; + case 32: + widthbits = 2; + break; + case 64: + widthbits = 3; + break; + default: + printk("nile4_set_pdar: unsupported width %d\n", width); + return; + } + nile4_out32(pdar, maskbits | (on_memory_bus ? 0x10 : 0) | + (visible ? 0x20 : 0) | (widthbits << 6) | + (phys & 0xffe00000)); + nile4_out32(pdar + 4, 0); + /* + * When programming a PDAR, the register should be read immediately + * after writing it. This ensures that address decoders are properly + * configured. + */ + nile4_in32(pdar); + nile4_in32(pdar + 4); +} + + +/* + * PCI Master Registers + * + * Note: 32 bit addressing only! + */ +void nile4_set_pmr(u32 pmr, u32 type, u32 addr) +{ + if (pmr != NILE4_PCIINIT0 && pmr != NILE4_PCIINIT1) { + printk("nile4_set_pmr: invalid pmr %d\n", pmr); + return; + } + switch (type) { + case NILE4_PCICMD_IACK: /* PCI Interrupt Acknowledge */ + case NILE4_PCICMD_IO: /* PCI I/O Space */ + case NILE4_PCICMD_MEM: /* PCI Memory Space */ + case NILE4_PCICMD_CFG: /* PCI Configuration Space */ + break; + default: + printk("nile4_set_pmr: invalid type %d\n", type); + return; + } + nile4_out32(pmr, (type << 1) | 0x10 | (addr & 0xffe00000)); + nile4_out32(pmr + 4, 0); +} + + +/* + * Interrupt Programming + */ +void nile4_map_irq(int nile4_irq, int cpu_irq) +{ + u32 offset, t; + + offset = NILE4_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + t = nile4_in32(offset); + t &= ~(7 << (nile4_irq * 4)); + t |= cpu_irq << (nile4_irq * 4); + nile4_out32(offset, t); +} + +void nile4_map_irq_all(int cpu_irq) +{ + u32 all, t; + + all = cpu_irq; + all |= all << 4; + all |= all << 8; + all |= all << 16; + t = nile4_in32(NILE4_INTCTRL); + t &= 0x88888888; + t |= all; + nile4_out32(NILE4_INTCTRL, t); + t = nile4_in32(NILE4_INTCTRL + 4); + t &= 0x88888888; + t |= all; + nile4_out32(NILE4_INTCTRL + 4, t); +} + +void nile4_enable_irq(int nile4_irq) +{ + u32 offset, t; + + offset = NILE4_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + t = nile4_in32(offset); + t |= 8 << (nile4_irq * 4); + nile4_out32(offset, t); +} + +void nile4_disable_irq(int nile4_irq) +{ + u32 offset, t; + + offset = NILE4_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + t = nile4_in32(offset); + t &= ~(8 << (nile4_irq * 4)); + nile4_out32(offset, t); +} + +void nile4_disable_irq_all(void) +{ + nile4_out32(NILE4_INTCTRL, 0); + nile4_out32(NILE4_INTCTRL + 4, 0); +} + +u16 nile4_get_irq_stat(int cpu_irq) +{ + return nile4_in16(NILE4_INTSTAT0 + cpu_irq * 2); +} + +void nile4_enable_irq_output(int cpu_irq) +{ + u32 t; + + t = nile4_in32(NILE4_INTSTAT1 + 4); + t |= 1 << (16 + cpu_irq); + nile4_out32(NILE4_INTSTAT1, t); +} + +void nile4_disable_irq_output(int cpu_irq) +{ + u32 t; + + t = nile4_in32(NILE4_INTSTAT1 + 4); + t &= ~(1 << (16 + cpu_irq)); + nile4_out32(NILE4_INTSTAT1, t); +} + +void nile4_set_pci_irq_polarity(int pci_irq, int high) +{ + u32 t; + + t = nile4_in32(NILE4_INTPPES); + if (high) + t &= ~(1 << (pci_irq * 2)); + else + t |= 1 << (pci_irq * 2); + nile4_out32(NILE4_INTPPES, t); +} + +void nile4_set_pci_irq_level_or_edge(int pci_irq, int level) +{ + u32 t; + + t = nile4_in32(NILE4_INTPPES); + if (level) + t |= 2 << (pci_irq * 2); + else + t &= ~(2 << (pci_irq * 2)); + nile4_out32(NILE4_INTPPES, t); +} + +void nile4_clear_irq(int nile4_irq) +{ + nile4_out32(NILE4_INTCLR, 1 << nile4_irq); +} + +void nile4_clear_irq_mask(u32 mask) +{ + nile4_out32(NILE4_INTCLR, mask); +} + +u8 nile4_i8259_iack(void) +{ + u8 irq; + + /* Set window 0 for interrupt acknowledge */ + nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IACK, 0); + irq = *(volatile u8 *) NILE4_PCI_IACK_BASE; + /* Set window 0 for PCI I/O space */ + nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0); + return irq; +} + +#if 0 +void nile4_dump_irq_status(void) +{ + printk("CPUSTAT = %p:%p\n", (void *) nile4_in32(NILE4_CPUSTAT + 4), + (void *) nile4_in32(NILE4_CPUSTAT)); + printk("INTCTRL = %p:%p\n", (void *) nile4_in32(NILE4_INTCTRL + 4), + (void *) nile4_in32(NILE4_INTCTRL)); + printk("INTSTAT0 = %p:%p\n", + (void *) nile4_in32(NILE4_INTSTAT0 + 4), + (void *) nile4_in32(NILE4_INTSTAT0)); + printk("INTSTAT1 = %p:%p\n", + (void *) nile4_in32(NILE4_INTSTAT1 + 4), + (void *) nile4_in32(NILE4_INTSTAT1)); + printk("INTCLR = %p:%p\n", (void *) nile4_in32(NILE4_INTCLR + 4), + (void *) nile4_in32(NILE4_INTCLR)); + printk("INTPPES = %p:%p\n", (void *) nile4_in32(NILE4_INTPPES + 4), + (void *) nile4_in32(NILE4_INTPPES)); +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5476/pci.c linux.ac/arch/mips/ddb5476/pci.c --- linux.vanilla/arch/mips/ddb5476/pci.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ddb5476/pci.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,495 @@ +/* + * arch/mips/ddb5476/pci.c -- NEC DDB Vrc-5074 PCI access routines + * + * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> + * Albert Dorofeev <albert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/ioport.h> + +#include <asm-mips/nile4.h> + + +static u32 nile4_pre_pci_access0(int slot_num) +{ + u32 pci_addr = 0; + u32 virt_addr = NILE4_PCI_CFG_BASE; + + /* work around the bug for Vrc5476 */ + if (slot_num == 13) + return NILE4_BASE + NILE4_PCI_BASE; + + /* Set window 1 address 08000000 - 32 bit - 128 MB (PCI config space) */ + nile4_set_pdar(NILE4_PCIW1, PHYSADDR(virt_addr), 0x08000000, 32, 0, + 0); + + // [jsun] we start scanning from addr:10, + // with 128M we can go up to addr:26 (slot 16) + if (slot_num <= 16) { + virt_addr += 0x00000400 << slot_num; + } else { + /* for high slot, we have to set higher PCI base addr */ + pci_addr = 0x00000400 << slot_num; + } + nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, pci_addr); + return virt_addr; +} + +static void nile4_post_pci_access0(void) +{ + /* + * Set window 1 back to address 08000000 - 32 bit - 128 MB + * (PCI IO space) + */ + nile4_set_pdar(NILE4_PCIW1, PHYSADDR(NILE4_PCI_MEM_BASE), + 0x08000000, 32, 1, 1); + // nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0); + nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0x08000000); +} + + +static int nile4_pci_read_config_dword(struct pci_dev *dev, + int where, u32 * val) +{ + int slot_num, func_num; + u32 base; + u32 addr; + + /* + * Do we need to generate type 1 configure transaction? + */ + if (dev->bus->number) { + /* FIXME - not working yet */ + return PCIBIOS_FUNC_NOT_SUPPORTED; + + /* + * the largest type 1 configuration addr is 16M, < 256M + * config space + */ + slot_num = 0; + addr = + (dev->bus->number << 16) | (dev->devfn < + 8) | where | 1; + } else { + slot_num = PCI_SLOT(dev->devfn); + func_num = PCI_FUNC(dev->devfn); + addr = (func_num << 8) + where; + } + + base = nile4_pre_pci_access0(slot_num); + *val = *(volatile u32 *) (base + addr); + nile4_post_pci_access0(); + return PCIBIOS_SUCCESSFUL; +} + +static int nile4_pci_write_config_dword(struct pci_dev *dev, int where, + u32 val) +{ + int slot_num, func_num; + u32 base; + u32 addr; + + /* + * Do we need to generate type 1 configure transaction? + */ + if (dev->bus->number) { + /* FIXME - not working yet */ + return PCIBIOS_FUNC_NOT_SUPPORTED; + + /* the largest type 1 configuration addr is 16M, < 256M config space */ + slot_num = 0; + addr = + (dev->bus->number << 16) | (dev->devfn < + 8) | where | 1; + } else { + slot_num = PCI_SLOT(dev->devfn); + func_num = PCI_FUNC(dev->devfn); + addr = (func_num << 8) + where; + } + + base = nile4_pre_pci_access0(slot_num); + *(volatile u32 *) (base + addr) = val; + nile4_post_pci_access0(); + return PCIBIOS_SUCCESSFUL; +} + +static int nile4_pci_read_config_word(struct pci_dev *dev, int where, + u16 * val) +{ + int status; + u32 result; + + status = nile4_pci_read_config_dword(dev, where & ~3, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 2) + result >>= 16; + *val = result & 0xffff; + return PCIBIOS_SUCCESSFUL; +} + +static int nile4_pci_read_config_byte(struct pci_dev *dev, int where, + u8 * val) +{ + int status; + u32 result; + + status = nile4_pci_read_config_dword(dev, where & ~3, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 1) + result >>= 8; + if (where & 2) + result >>= 16; + *val = result & 0xff; + return PCIBIOS_SUCCESSFUL; +} + +static int nile4_pci_write_config_word(struct pci_dev *dev, int where, + u16 val) +{ + int status, shift = 0; + u32 result; + + status = nile4_pci_read_config_dword(dev, where & ~3, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 2) + shift += 16; + result &= ~(0xffff << shift); + result |= val << shift; + return nile4_pci_write_config_dword(dev, where & ~3, result); +} + +static int nile4_pci_write_config_byte(struct pci_dev *dev, int where, + u8 val) +{ + int status, shift = 0; + u32 result; + + status = nile4_pci_read_config_dword(dev, where & ~3, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 2) + shift += 16; + if (where & 1) + shift += 8; + result &= ~(0xff << shift); + result |= val << shift; + return nile4_pci_write_config_dword(dev, where & ~3, result); +} + +struct pci_ops nile4_pci_ops = { + nile4_pci_read_config_byte, + nile4_pci_read_config_word, + nile4_pci_read_config_dword, + nile4_pci_write_config_byte, + nile4_pci_write_config_word, + nile4_pci_write_config_dword +}; + +struct { + struct resource ram; + struct resource flash; + struct resource isa_io; + struct resource pci_io; + struct resource isa_mem; + struct resource pci_mem; + struct resource nile4; + struct resource boot; +} ddb5476_resources = { + // { "RAM", 0x00000000, 0x03ffffff, IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 }, + { + "RAM", 0x00000000, 0x03ffffff, IORESOURCE_MEM}, { + "Flash ROM", 0x04000000, 0x043fffff}, { + "Nile4 ISA I/O", 0x06000000, 0x060fffff}, { + "Nile4 PCI I/O", 0x06100000, 0x07ffffff}, { + "Nile4 ISA mem", 0x08000000, 0x08ffffff, IORESOURCE_MEM}, { + "Nile4 PCI mem", 0x09000000, 0x0fffffff, IORESOURCE_MEM}, + // { "Nile4 ctrl", 0x1fa00000, 0x1fbfffff, IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 }, + { + "Nile4 ctrl", 0x1fa00000, 0x1fbfffff, IORESOURCE_MEM}, { + "Boot ROM", 0x1fc00000, 0x1fffffff} +}; + +struct resource M5229_resources[5] = { + {"M5229 BAR0", 0x1f0, 0x1f3, IORESOURCE_IO}, + {"M5229 BAR1", 0x3f4, 0x3f7, IORESOURCE_IO}, + {"M5229 BAR2", 0x170, 0x173, IORESOURCE_IO}, + {"M5229 BAR3", 0x374, 0x377, IORESOURCE_IO}, + {"M5229 BAR4", 0xf000, 0xf00f, IORESOURCE_IO} +}; + +static void __init ddb5476_pci_fixup(void) +{ + struct pci_dev *dev; + + pci_for_each_dev(dev) { + if (dev->vendor == PCI_VENDOR_ID_NEC && + dev->device == PCI_DEVICE_ID_NEC_VRC5476) { + /* + * The first 64-bit PCI base register should point to + * the Nile4 control registers. Unfortunately this + * isn't the case, so we fix it ourselves. This allows + * the serial driver to find the UART. + */ + dev->resource[0] = ddb5476_resources.nile4; + request_resource(&iomem_resource, + &dev->resource[0]); + /* + * The second 64-bit PCI base register points to the + * first memory bank. Unfortunately the address is + * wrong, so we fix it (again). + */ + + /* [jsun] We cannot request the resource anymore, + * because kernel/setup.c has already reserved "System + * RAM" resource at the same spot. + * The fundamental problem here is that PCI host + * controller should not put system RAM mapping in BAR + * and make subject to PCI resource assignement. + * Current fix is a total hack. We set parent to 1 so + * so that PCI resource assignement code is fooled to + * think the resource is assigned, and will not attempt + * to mess with it. + */ + dev->resource[2] = ddb5476_resources.ram; + if (request_resource(&iomem_resource, + &dev->resource[2]) ) { + dev->resource[2].parent = 0x1; + } + + } else if (dev->vendor == PCI_VENDOR_ID_AL + && dev->device == PCI_DEVICE_ID_AL_M7101) { + /* + * It's nice to have the LEDs on the GPIO pins + * available for debugging + */ + extern struct pci_dev *pci_pmu; + u8 t8; + + pci_pmu = dev; /* for LEDs D2 and D3 */ + /* Program the lines for LEDs D2 and D3 to output */ + nile4_pci_read_config_byte(dev, 0x7d, &t8); + t8 |= 0xc0; + nile4_pci_write_config_byte(dev, 0x7d, t8); + /* Turn LEDs D2 and D3 off */ + nile4_pci_read_config_byte(dev, 0x7e, &t8); + t8 |= 0xc0; + nile4_pci_write_config_byte(dev, 0x7e, t8); + } else if (dev->vendor == PCI_VENDOR_ID_AL && + dev->device == 0x5229) { + int i; + for (i = 0; i < 5; i++) { + dev->resource[i] = M5229_resources[i]; + request_resource(&ioport_resource, + &dev->resource[i]); + } + } + } +} + +static void __init pcibios_fixup_irqs(void) +{ + struct pci_dev *dev; + int slot_num; + + pci_for_each_dev(dev) { + slot_num = PCI_SLOT(dev->devfn); + switch (slot_num) { + case 3: /* re-programmed to USB */ + dev->irq = 9; /* hard-coded; see irq.c */ + break; + case 4: /* re-programmed to PMU */ + dev->irq = 10; /* hard-coded; see irq.c */ + break; + case 6: /* on-board pci-pci bridge */ + dev->irq = 0xff; + break; + case 7: /* on-board ether */ + dev->irq = nile4_to_irq(NILE4_INT_INTB); + break; + case 8: /* ISA-PCI bridge */ + dev->irq = nile4_to_irq(NILE4_INT_INTC); + break; + case 9: /* ext slot #3 */ + dev->irq = nile4_to_irq(NILE4_INT_INTD); + break; + case 10: /* ext slot #4 */ + dev->irq = nile4_to_irq(NILE4_INT_INTA); + break; + case 13: /* Vrc5476 */ + dev->irq = 0xff; + break; + case 14: /* HD controller, M5229 */ + dev->irq = 14; + break; + default: + printk + ("JSUN : in pcibios_fixup_irqs - unkown slot %d\n", + slot_num); + panic + ("JSUN : in pcibios_fixup_irqs - unkown slot.\n"); + } + } +} + +void __init pcibios_init(void) +{ + printk("PCI: Emulate bios initialization \n"); + /* [jsun] we need to set BAR0 so that SDRAM 0 appears at 0x0 in PCI */ + *(long *) (NILE4_BASE + NILE4_BAR0) = 0x8; + + printk("PCI: Probing PCI hardware\n"); + ioport_resource.end = 0x1ffffff; /* 32 MB */ + iomem_resource.end = 0x1fffffff; /* 512 MB */ + + /* `ram' and `nile4' are requested through the Nile4 pci_dev */ + request_resource(&iomem_resource, &ddb5476_resources.flash); + request_resource(&iomem_resource, &ddb5476_resources.isa_io); + request_resource(&iomem_resource, &ddb5476_resources.pci_io); + request_resource(&iomem_resource, &ddb5476_resources.isa_mem); + request_resource(&iomem_resource, &ddb5476_resources.pci_mem); + request_resource(&iomem_resource, &ddb5476_resources.boot); + + pci_scan_bus(0, &nile4_pci_ops, NULL); + ddb5476_pci_fixup(); + pci_assign_unassigned_resources(); + pcibios_fixup_irqs(); +} + +void __init pcibios_fixup_bus(struct pci_bus *bus) +{ + /* [jsun] we don't know how to fix sub-buses yet */ + if (bus->number == 0) { + bus->resource[1] = &ddb5476_resources.pci_mem; + } +} + +char *pcibios_setup(char *str) +{ + return str; +} + +void __init pcibios_update_irq(struct pci_dev *dev, int irq) +{ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); +} + +void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus, + struct pbus_set_ranges_data *ranges) +{ + /* + * our caller figure out range by going through the dev structures. + * I guess this is the place to fix things up if the bus is using a + * different view of the addressing space. + */ + +#if 0 /* original DDB5074 code */ + if (bus->number == 0) { + ranges->io_start -= bus->resource[0]->start; + ranges->io_end -= bus->resource[0]->start; + ranges->mem_start -= bus->resource[1]->start; + ranges->mem_end -= bus->resource[1]->start; + } +#endif +} + +int pcibios_enable_resources(struct pci_dev *dev) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + /* + * Don't touch the Nile 4 + */ + if (dev->vendor == PCI_VENDOR_ID_NEC && + dev->device == PCI_DEVICE_ID_NEC_VRC5476) return 0; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for (idx = 0; idx < 6; idx++) { + r = &dev->resource[idx]; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because " + "of resource collisions\n", dev->slot_name); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (cmd != old_cmd) { + printk("PCI: Enabling device %s (%04x -> %04x)\n", + dev->slot_name, old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + +int pcibios_enable_device(struct pci_dev *dev) +{ + return pcibios_enable_resources(dev); +} + +void pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) +{ + u32 new, check; + int reg; + + new = res->start | (res->flags & PCI_REGION_FLAG_MASK); + if (resource < 6) { + reg = PCI_BASE_ADDRESS_0 + 4 * resource; + } else if (resource == PCI_ROM_RESOURCE) { + res->flags |= PCI_ROM_ADDRESS_ENABLE; + reg = dev->rom_base_reg; + } else { + /* + * Somebody might have asked allocation of a non-standard + * resource + */ + return; + } + + pci_write_config_dword(dev, reg, new); + pci_read_config_dword(dev, reg, &check); + if ((new ^ check) & + ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : + PCI_BASE_ADDRESS_MEM_MASK)) { + printk(KERN_ERR "PCI: Error while updating region " + "%s/%d (%08x != %08x)\n", dev->slot_name, resource, + new, check); + } +} + +void pcibios_align_resource(void *data, struct resource *res, + unsigned long size) +{ + struct pci_dev *dev = data; + + if (res->flags & IORESOURCE_IO) { + unsigned long start = res->start; + + /* We need to avoid collisions with `mirrored' VGA ports + and other strange ISA hardware, so we always want the + addresses kilobyte aligned. */ + if (size > 0x100) { + printk(KERN_ERR "PCI: I/O Region %s/%d too large" + " (%ld bytes)\n", dev->slot_name, + dev->resource - res, size); + } + + start = (start + 1024 - 1) & ~(1024 - 1); + res->start = start; + } +} + +struct pci_fixup pcibios_fixups[] = { {0} }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5476/prom.c linux.ac/arch/mips/ddb5476/prom.c --- linux.vanilla/arch/mips/ddb5476/prom.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ddb5476/prom.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,43 @@ +/* + * arch/mips/ddb5476/prom.c -- NEC DDB Vrc-5476 PROM routines + * + * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + * + * Jun Sun - modified for DDB5476. + */ +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/bootmem.h> + +#include <asm/addrspace.h> +#include <asm/bootinfo.h> + + +char arcs_cmdline[COMMAND_LINE_SIZE]; + +/* [jsun@junsun.net] PMON passes arguments in C main() style */ +void __init prom_init(int argc, const char **arg) +{ + int i; + + /* arg[0] is "g", the rest is boot parameters */ + arcs_cmdline[0] = '\0'; + for (i = 1; i < argc; i++) { + if (strlen(arcs_cmdline) + strlen(arg[i] + 1) + >= sizeof(arcs_cmdline)) + break; + strcat(arcs_cmdline, arg[i]); + strcat(arcs_cmdline, " "); + } + + mips_machgroup = MACH_GROUP_NEC_DDB; + mips_machtype = MACH_NEC_DDB5476; + /* 64 MB non-upgradable */ + add_memory_region(0, 64 << 20, BOOT_MEM_RAM); +} + +void __init prom_free_prom_memory(void) +{ +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5476/setup.c linux.ac/arch/mips/ddb5476/setup.c --- linux.vanilla/arch/mips/ddb5476/setup.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ddb5476/setup.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,375 @@ +/* + * arch/mips/ddb5476/setup.c -- NEC DDB Vrc-5476 setup routines + * + * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/kbd_ll.h> +#include <linux/kernel.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/console.h> +#include <linux/sched.h> +#include <linux/mc146818rtc.h> +#include <linux/pc_keyb.h> +#include <linux/pci.h> +#include <linux/ide.h> + +#include <asm/addrspace.h> +#include <asm/bcache.h> +#include <asm/keyboard.h> +#include <asm/irq.h> +#include <asm/reboot.h> +#include <asm/gdb-stub.h> +#include <asm/nile4.h> + + +#ifdef CONFIG_REMOTE_DEBUG +extern void rs_kgdb_hook(int); +extern void breakpoint(void); +#endif + +#if defined(CONFIG_SERIAL_CONSOLE) +extern void console_setup(char *); +#endif + +extern struct ide_ops std_ide_ops; +extern struct rtc_ops ddb_rtc_ops; +extern struct kbd_ops std_kbd_ops; + +static void (*back_to_prom) (void) = (void (*)(void)) 0xbfc00000; + +static void ddb_machine_restart(char *command) +{ + u32 t; + + /* PCI cold reset */ + t = nile4_in32(NILE4_PCICTRL + 4); + t |= 0x40000000; + nile4_out32(NILE4_PCICTRL + 4, t); + /* CPU cold reset */ + t = nile4_in32(NILE4_CPUSTAT); + t |= 1; + nile4_out32(NILE4_CPUSTAT, t); + /* Call the PROM */ + back_to_prom(); +} + +static void ddb_machine_halt(void) +{ + printk("DDB Vrc-5476 halted.\n"); + while (1); +} + +static void ddb_machine_power_off(void) +{ + printk("DDB Vrc-5476 halted. Please turn off the power.\n"); + while (1); +} + +extern void ddb_irq_setup(void); + +void (*board_time_init) (struct irqaction * irq); + + +static void __init ddb_time_init(struct irqaction *irq) +{ + /* set the clock to 1 Hz */ + nile4_out32(NILE4_T2CTRL, 1000000); + /* enable the General-Purpose Timer */ + nile4_out32(NILE4_T2CTRL + 4, 0x00000001); + /* reset timer */ + nile4_out32(NILE4_T2CNTR, 0); + /* enable interrupt */ + nile4_enable_irq(NILE4_INT_GPT); + i8259_setup_irq(nile4_to_irq(NILE4_INT_GPT), irq); +} + +static struct { + struct resource dma1; + struct resource pic1; + struct resource timer; + struct resource rtc; + struct resource dma_page_reg; + struct resource pic2; + struct resource dma2; +} ddb5476_ioport = { + { + "dma1", 0x00, 0x1f, IORESOURCE_BUSY}, { + "pic1", 0x20, 0x3f, IORESOURCE_BUSY}, { + "timer", 0x40, 0x5f, IORESOURCE_BUSY}, { + "rtc", 0x70, 0x7f, IORESOURCE_BUSY}, { + "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY}, { + "pic2", 0xa0, 0xbf, IORESOURCE_BUSY}, { + "dma2", 0xc0, 0xdf, IORESOURCE_BUSY} +}; + +static struct { + struct resource nile4; +} ddb5476_iomem = { + { "Nile 4", NILE4_BASE, NILE4_BASE + NILE4_SIZE - 1, IORESOURCE_BUSY} +}; + +void __init ddb_setup(void) +{ + extern int panic_timeout; + + irq_setup = ddb_irq_setup; + mips_io_port_base = NILE4_PCI_IO_BASE; + isa_slot_offset = NILE4_PCI_MEM_BASE; + board_time_init = ddb_time_init; + + _machine_restart = ddb_machine_restart; + _machine_halt = ddb_machine_halt; + _machine_power_off = ddb_machine_power_off; + + /* request io port/mem resources */ + if (request_resource(&ioport_resource, &ddb5476_ioport.dma1) || + request_resource(&ioport_resource, &ddb5476_ioport.pic1) || + request_resource(&ioport_resource, &ddb5476_ioport.timer) || + request_resource(&ioport_resource, &ddb5476_ioport.rtc) || + request_resource(&ioport_resource, + &ddb5476_ioport.dma_page_reg) + || request_resource(&ioport_resource, &ddb5476_ioport.pic2) + || request_resource(&ioport_resource, &ddb5476_ioport.dma2) + || request_resource(&iomem_resource, &ddb5476_iomem.nile4)) { + printk + ("ddb_setup - requesting oo port resources failed.\n"); + for (;;); + } +#ifdef CONFIG_BLK_DEV_IDE + ide_ops = &std_ide_ops; +#endif + rtc_ops = &ddb_rtc_ops; + +#ifdef CONFIG_PC_KEYB + kbd_ops = &std_kbd_ops; +#endif + + /* Reboot on panic */ + panic_timeout = 180; + + /* [jsun] we need to set BAR0 so that SDRAM 0 appears at 0x0 in PCI */ + /* *(long*)0xbfa00218 = 0x8; */ + +#ifdef CONFIG_FB + conswitchp = &dummy_con; +#endif + + + /* board initialization stuff - non-fundamental, but need to be set + * before kernel runs */ + + /* setup I/O space */ + nile4_set_pdar(NILE4_PCIW0, + PHYSADDR(NILE4_PCI_IO_BASE), 0x02000000, 32, 0, 0); + nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0); + + /* map config space to 0xa8000000, 128MB */ + nile4_set_pdar(NILE4_PCIW1, + PHYSADDR(NILE4_PCI_CFG_BASE), 0x08000000, 32, 0, 0); + nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, 0x0); + + /* ----- M1543 PCI setup ------ */ + + /* we know M1543 PCI-ISA controller is at addr:18 */ + /* xxxx1010 makes USB at addr:13 and PMU at addr:14 */ + *(volatile unsigned char *) 0xa8040072 &= 0xf0; + *(volatile unsigned char *) 0xa8040072 |= 0xa; + + /* setup USB interrupt to IRQ 9, (bit 0:3 - 0001) + * no IOCHRDY signal, (bit 7 - 1) + * M1543C & M7101 VID and Subsys Device ID are read-only (bit 6 - 1) + * Bypass USB Master INTAJ level to edge conversion (bit 4 - 0) + */ + *(unsigned char *) 0xa8040074 = 0xc1; + + /* setup PMU(SCI to IRQ 10 (bit 0:3 - 0011) + * SCI routing to IRQ 13 disabled (bit 7 - 1) + * SCI interrupt level to edge conversion bypassed (bit 4 - 0) + */ + *(unsigned char *) 0xa8040076 = 0x83; + + /* setup IDE controller + * enable IDE controller (bit 6 - 1) + * IDE IDSEL to be addr:24 (bit 4:5 - 11) + * no IDE ATA Secondary Bus Signal Pad Control (bit 3 - 0) + * no IDE ATA Primary Bus Signal Pad Control (bit 2 - 0) + * primary IRQ is 14, secondary is 15 (bit 1:0 - 01 + */ + // *(unsigned char*)0xa8040058 = 0x71; + // *(unsigned char*)0xa8040058 = 0x79; + // *(unsigned char*)0xa8040058 = 0x74; // use SIRQ, primary tri-state + *(unsigned char *) 0xa8040058 = 0x75; // primary tri-state + +#if 0 + /* this is not necessary if M5229 does not use SIRQ */ + *(unsigned char *) 0xa8040044 = 0x0d; // primary to IRQ 14 + *(unsigned char *) 0xa8040075 = 0x0d; // secondary to IRQ 14 +#endif + + /* enable IDE in the M5229 config register 0x50 (bit 0 - 1) */ + /* M5229 IDSEL is addr:24; see above setting */ + *(unsigned char *) 0xa9000050 |= 0x1; + + /* enable bus master (bit 2) and IO decoding (bit 0) */ + *(unsigned char *) 0xa9000004 |= 0x5; + + /* enable native, copied from arch/ppc/k2boot/head.S */ + /* TODO - need volatile, need to be portable */ + *(unsigned char *) 0xa9000009 = 0xff; + + /* ----- end of M1543 PCI setup ------ */ + + /* ----- reset on-board ether chip ------ */ + *((volatile u32 *) 0xa8020004) |= 1; /* decode I/O */ + *((volatile u32 *) 0xa8020010) = 0; /* set BAR address */ + + /* send reset command */ + *((volatile u32 *) 0xa6000000) = 1; /* do a soft reset */ + + /* disable ether chip */ + *((volatile u32 *) 0xa8020004) = 0; /* disable any decoding */ + + /* put it into sleep */ + *((volatile u32 *) 0xa8020040) = 0x80000000; + + /* ----- end of reset on-board ether chip ------ */ + + /* ----- set pci window 1 to pci memory space -------- */ + nile4_set_pdar(NILE4_PCIW1, + PHYSADDR(NILE4_PCI_MEM_BASE), 0x08000000, 32, 0, 0); + // nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0); + nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0x08000000); + +} + +#define USE_NILE4_SERIAL 0 + +#if USE_NILE4_SERIAL +#define ns16550_in(reg) nile4_in8((reg)*8) +#define ns16550_out(reg, val) nile4_out8((reg)*8, (val)) +#else +#define NS16550_BASE (NILE4_PCI_IO_BASE+0x03f8) +static inline u8 ns16550_in(u32 reg) +{ + return *(volatile u8 *) (NS16550_BASE + reg); +} + +static inline void ns16550_out(u32 reg, u8 val) +{ + *(volatile u8 *) (NS16550_BASE + reg) = val; +} +#endif + +#define NS16550_RBR 0 +#define NS16550_THR 0 +#define NS16550_DLL 0 +#define NS16550_IER 1 +#define NS16550_DLM 1 +#define NS16550_FCR 2 +#define NS16550_IIR 2 +#define NS16550_LCR 3 +#define NS16550_MCR 4 +#define NS16550_LSR 5 +#define NS16550_MSR 6 +#define NS16550_SCR 7 + +#define NS16550_LSR_DR 0x01 /* Data ready */ +#define NS16550_LSR_OE 0x02 /* Overrun */ +#define NS16550_LSR_PE 0x04 /* Parity error */ +#define NS16550_LSR_FE 0x08 /* Framing error */ +#define NS16550_LSR_BI 0x10 /* Break */ +#define NS16550_LSR_THRE 0x20 /* Xmit holding register empty */ +#define NS16550_LSR_TEMT 0x40 /* Xmitter empty */ +#define NS16550_LSR_ERR 0x80 /* Error */ + + +void _serinit(void) +{ +#if USE_NILE4_SERIAL + ns16550_out(NS16550_LCR, 0x80); + ns16550_out(NS16550_DLM, 0x00); + ns16550_out(NS16550_DLL, 0x36); /* 9600 baud */ + ns16550_out(NS16550_LCR, 0x00); + ns16550_out(NS16550_LCR, 0x03); + ns16550_out(NS16550_FCR, 0x47); +#else + /* done by PMON */ +#endif +} + +void _putc(char c) +{ + while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE)); + ns16550_out(NS16550_THR, c); + if (c == '\n') { + while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE)); + ns16550_out(NS16550_THR, '\r'); + } +} + +void _puts(const char *s) +{ + char c; + + while ((c = *s++)) + _putc(c); +} + +char _getc(void) +{ + while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_DR)); + + return ns16550_in(NS16550_RBR); +} + +int _testc(void) +{ + return (ns16550_in(NS16550_LSR) & NS16550_LSR_DR) != 0; +} + + +/* + * Hexadecimal 7-segment LED + */ +void ddb5476_led_hex(int hex) +{ + outb(hex, 0x80); +} + + +/* + * LEDs D2 and D3, connected to the GPIO pins of the PMU in the ALi M1543 + */ +struct pci_dev *pci_pmu = NULL; + +void ddb5476_led_d2(int on) +{ + u8 t; + + if (pci_pmu) { + pci_read_config_byte(pci_pmu, 0x7e, &t); + if (on) + t &= 0x7f; + else + t |= 0x80; + pci_write_config_byte(pci_pmu, 0x7e, t); + } +} + +void ddb5476_led_d3(int on) +{ + u8 t; + + if (pci_pmu) { + pci_read_config_byte(pci_pmu, 0x7e, &t); + if (on) + t &= 0xbf; + else + t |= 0x40; + pci_write_config_byte(pci_pmu, 0x7e, t); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5476/time.c linux.ac/arch/mips/ddb5476/time.c --- linux.vanilla/arch/mips/ddb5476/time.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ddb5476/time.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,32 @@ +/* + * arch/mips/ddb5074/time.c -- Timer routines + * + * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include <linux/init.h> + +#include <asm/mc146818rtc.h> + +static unsigned char ddb_rtc_read_data(unsigned long addr) +{ + outb_p(addr, RTC_PORT(0)); + return inb_p(RTC_PORT(1)); +} + +static void ddb_rtc_write_data(unsigned char data, unsigned long addr) +{ + outb_p(addr, RTC_PORT(0)); + outb_p(data, RTC_PORT(1)); +} + +static int ddb_rtc_bcd_mode(void) +{ + return 1; +} + +struct rtc_ops ddb_rtc_ops = { + ddb_rtc_read_data, + ddb_rtc_write_data, + ddb_rtc_bcd_mode +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/dec/Makefile linux.ac/arch/mips/dec/Makefile --- linux.vanilla/arch/mips/dec/Makefile Fri Feb 25 06:52:30 2000 +++ linux.ac/arch/mips/dec/Makefile Tue Apr 3 17:54:32 2001 @@ -7,30 +7,20 @@ # .S.s: - $(CPP) $(CFLAGS) $< -o $*.s + $(CPP) $(AFLAGS) $< -o $@ .S.o: - $(CC) $(CFLAGS) -c $< -o $*.o + $(CC) $(AFLAGS) -c $< -o $@ -all: dec.o O_TARGET := dec.o -O_OBJS := int-handler.o setup.o irq.o time.o reset.o rtc-dec.o -ifdef CONFIG_PROM_CONSOLE -O_OBJS += promcon.o -endif +all: dec.o -ifdef CONFIG_SERIAL -O_OBJS += serial.o -endif +export-objs := wbflush.o +obj-y := int-handler.o setup.o irq.o time.o reset.o rtc-dec.o wbflush.o -ifeq ($(CONFIG_MODULES),y) - OX_OBJS = wbflush.o -else - O_OBJS += wbflush.o -endif +obj-$(CONFIG_PROM_CONSOLE) += promcon.o +obj-$(CONFIG_SERIAL) += serial.o int-handler.o: int-handler.S - -clean: include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/dec/boot/Makefile linux.ac/arch/mips/dec/boot/Makefile --- linux.vanilla/arch/mips/dec/boot/Makefile Sat Jun 26 01:40:12 1999 +++ linux.ac/arch/mips/dec/boot/Makefile Tue Apr 3 17:54:32 2001 @@ -18,7 +18,8 @@ all: dec_boot.o O_TARGET := dec_boot.o -O_OBJS := decstation.o + +obj-y := decstation.o clean: rm -f nbImage diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/defconfig linux.ac/arch/mips/defconfig --- linux.vanilla/arch/mips/defconfig Tue Apr 3 17:31:55 2001 +++ linux.ac/arch/mips/defconfig Tue Apr 3 17:54:32 2001 @@ -16,16 +16,17 @@ # CONFIG_COBALT_MICRO_SERVER is not set # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -# CONFIG_ORION is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_OLIVETTI_M700 is not set CONFIG_SGI_IP22=y # CONFIG_SNI_RM200_PCI is not set +# CONFIG_MCA is not set # CONFIG_SBUS is not set CONFIG_ARC32=y CONFIG_PC_KEYB=y CONFIG_SGI=y # CONFIG_ISA is not set +# CONFIG_EISA is not set # CONFIG_PCI is not set # @@ -84,17 +85,23 @@ # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BLK_DEV_LVM is not set # # Networking options @@ -111,10 +118,8 @@ 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_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set @@ -131,6 +136,7 @@ # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set @@ -152,6 +158,7 @@ CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y +# CONFIG_CHR_DEV_OSST is not set CONFIG_BLK_DEV_SR=y # CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_SR_EXTRA_DEVS=2 @@ -192,14 +199,14 @@ # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_SIM710 is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_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_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_DEBUG is not set @@ -229,6 +236,8 @@ # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -283,8 +292,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -299,11 +306,13 @@ # CONFIG_MAC_PARTITION is not set CONFIG_MSDOS_PARTITION=y # CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set CONFIG_SGI_PARTITION=y # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # @@ -334,6 +343,11 @@ # USB support # # CONFIG_USB is not set + +# +# Input core support +# +# CONFIG_INPUT is not set # # Kernel hacking diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/defconfig-cobalt linux.ac/arch/mips/defconfig-cobalt --- linux.vanilla/arch/mips/defconfig-cobalt Fri Jul 28 02:36:54 2000 +++ linux.ac/arch/mips/defconfig-cobalt Tue Apr 3 17:54:32 2001 @@ -17,18 +17,18 @@ CONFIG_COBALT_28=y # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -# CONFIG_ORION is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_OLIVETTI_M700 is not set # CONFIG_SGI_IP22 is not set # CONFIG_SNI_RM200_PCI is not set +# CONFIG_MCA is not set # CONFIG_SBUS is not set -# CONFIG_ISA is not set CONFIG_COBALT_27=y CONFIG_COBALT_LCD=y CONFIG_COBALT_SERIAL=y CONFIG_PCI=y # CONFIG_ISA is not set +# CONFIG_EISA is not set # # Loadable module support @@ -85,22 +85,26 @@ # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set CONFIG_BLK_DEV_LOOP=m # CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_LVM is not set -CONFIG_BLK_DEV_MD=y -CONFIG_MD_LINEAR=y -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_BOOT is not set -# CONFIG_AUTODETECT_RAID is not set CONFIG_BLK_DEV_RAM=m CONFIG_BLK_DEV_RAM_SIZE=4096 # CONFIG_BLK_DEV_INITRD is not set # +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_BLK_DEV_LVM is not set + +# # Networking options # # CONFIG_PACKET is not set @@ -112,13 +116,11 @@ CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set CONFIG_IP_MROUTE=y # CONFIG_IP_PIMSM_V1 is not set # CONFIG_IP_PIMSM_V2 is not set -CONFIG_IP_ALIAS=y # CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set @@ -130,13 +132,13 @@ # CONFIG_IPX=m # CONFIG_IPX_INTERN is not set -# CONFIG_SPX is not set CONFIG_ATALK=m # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set @@ -171,6 +173,7 @@ CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=m +# CONFIG_CHR_DEV_OSST is not set CONFIG_BLK_DEV_SR=m # CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_SR_EXTRA_DEVS=2 @@ -194,15 +197,14 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set CONFIG_SCSI_AIC7XXX=y -# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 -# CONFIG_AIC7XXX_PROC_STATS is not set CONFIG_AIC7XXX_RESET_DELAY=5 # 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_CPQFCTS is not set # CONFIG_SCSI_DMX3191D is not set # CONFIG_SCSI_DTC3280 is not set # CONFIG_SCSI_EATA is not set @@ -214,8 +216,6 @@ # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_SIM710 is not set # CONFIG_SCSI_NCR53C7xx is not set CONFIG_SCSI_NCR53C8XX=y # CONFIG_SCSI_SYM53C8XX is not set @@ -233,6 +233,8 @@ # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set @@ -265,6 +267,7 @@ CONFIG_DUMMY=m # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_NET_SB1000 is not set # @@ -277,6 +280,7 @@ # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set +# CONFIG_HP100 is not set # CONFIG_NET_ISA is not set # CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set @@ -284,8 +288,9 @@ # # Ethernet (1000 Mbit) # -# CONFIG_YELLOWFIN is not set # CONFIG_ACENIC is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set @@ -326,6 +331,7 @@ CONFIG_ISDN_PPP=y CONFIG_ISDN_PPP_VJ=y CONFIG_ISDN_MPP=y +# CONFIG_ISDN_PPP_BSDCOMP is not set CONFIG_ISDN_AUDIO=y # CONFIG_ISDN_TTY_FAX is not set @@ -353,6 +359,7 @@ # CONFIG_HISAX_NO_LLC is not set # CONFIG_HISAX_NO_KEYPAD is not set CONFIG_HISAX_1TR6=y +# CONFIG_HISAX_NI1 is not set # # HiSax supported cards @@ -374,6 +381,7 @@ # CONFIG_HISAX_SPORTSTER is not set # CONFIG_HISAX_MIC is not set # CONFIG_HISAX_NETJET is not set +# CONFIG_HISAX_NETJET_U is not set # CONFIG_HISAX_NICCY is not set # CONFIG_HISAX_ISURF is not set # CONFIG_HISAX_HSTSAPHIR is not set @@ -383,6 +391,7 @@ # CONFIG_HISAX_HFC_PCI is not set # CONFIG_HISAX_W6692 is not set # CONFIG_HISAX_HFC_SX is not set +# CONFIG_HISAX_SEDLBAUER_CS is not set # # Active ISDN cards @@ -393,8 +402,8 @@ # CONFIG_ISDN_DRV_ACT2000 is not set # CONFIG_ISDN_DRV_EICON is not set # CONFIG_ISDN_CAPI is not set -# CONFIG_ISDN_CAPI_MIDDLEWARE is not set # CONFIG_HYSDN is not set +# CONFIG_HYSDN_CAPI is not set # # Old CD-ROM drivers (not SCSI, not IDE) @@ -425,6 +434,10 @@ # Joysticks # # CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# # CONFIG_QIC02_TAPE is not set # @@ -434,11 +447,6 @@ # CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set CONFIG_RTC=y - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -447,8 +455,13 @@ # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set # CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems @@ -456,6 +469,8 @@ CONFIG_QUOTA=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -503,6 +518,7 @@ CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set # CONFIG_NCP_FS is not set # CONFIG_NCPFS_PACKET_SIGNING is not set # CONFIG_NCPFS_IOCTL_LOCKING is not set @@ -510,8 +526,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -520,6 +534,7 @@ # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y +CONFIG_SMB_NLS=y CONFIG_NLS=y # @@ -569,6 +584,11 @@ # USB support # # CONFIG_USB is not set + +# +# Input core support +# +# CONFIG_INPUT is not set # # Kernel hacking diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/defconfig-ddb5476 linux.ac/arch/mips/defconfig-ddb5476 --- linux.vanilla/arch/mips/defconfig-ddb5476 Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/defconfig-ddb5476 Tue Apr 3 17:54:32 2001 @@ -0,0 +1,541 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_MIPS=y +# CONFIG_SMP is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Machine selection +# +# CONFIG_ACER_PICA_61 is not set +# CONFIG_ALGOR_P4032 is not set +# CONFIG_BAGET_MIPS is not set +# CONFIG_DECSTATION is not set +# CONFIG_DDB5074 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_NINO is not set +# CONFIG_MIPS_MAGNUM_4000 is not set +# CONFIG_MOMENCO_OCELOT is not set +CONFIG_DDB5476=y +# CONFIG_OLIVETTI_M700 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SNI_RM200_PCI is not set +# CONFIG_MIPS_ITE8172 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_I8259=y +CONFIG_ISA=y +CONFIG_PCI=y +CONFIG_PC_KEYB=y +CONFIG_ROTTEN_IRQ=y +CONFIG_EISA=y + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# CPU selection +# +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_R3912 is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_R5000 is not set +CONFIG_CPU_R5432=y +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_MIPS32 is not set +# CONFIG_CPU_ADVANCED is not set +CONFIG_CPU_HAS_LLSC=y +# CONFIG_CPU_HAS_WB is not set + +# +# General setup +# +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_MIPS_FPU_EMULATOR=y +CONFIG_KCORE_ELF=y +CONFIG_ELF_KERNEL=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_NET=y +# CONFIG_PCI_NAMES is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set +# CONFIG_PCMCIA is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST 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_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +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_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +# CONFIG_BLK_DEV_IDEDMA_PCI is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_IDEDMA_PCI_AUTO is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD7409 is not set +# CONFIG_AMD7409_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_BLK_DEV_OSB4 is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=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_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_TULIP=y +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_EEPRO100_PM is not set +# CONFIG_LNE390 is not set +# CONFIG_NATSEMI is not set +CONFIG_NE2K_PCI=y +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139TOO is not set +# CONFIG_RTL8129 is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_LAN_SAA9730 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring 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_WAN is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Character devices +# +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_RAMFS 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_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_FB=y + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_RIVA is not set +# CONFIG_FB_CLGEN is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_ATY128 is not set +CONFIG_FB_3DFX=y +# CONFIG_FB_SIS is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB32=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +# CONFIG_FBCON_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Input core support +# +# CONFIG_INPUT is not set + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_REMOTE_DEBUG is not set +# CONFIG_LL_DEBUG is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_MIPS_UNCACHED is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/defconfig-decstation linux.ac/arch/mips/defconfig-decstation --- linux.vanilla/arch/mips/defconfig-decstation Fri Jul 28 02:36:54 2000 +++ linux.ac/arch/mips/defconfig-decstation Tue Apr 3 17:54:32 2001 @@ -16,13 +16,14 @@ # CONFIG_COBALT_MICRO_SERVER is not set CONFIG_DECSTATION=y # CONFIG_DDB5074 is not set -# CONFIG_ORION is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_OLIVETTI_M700 is not set # CONFIG_SGI_IP22 is not set # CONFIG_SNI_RM200_PCI is not set +# CONFIG_MCA is not set # CONFIG_SBUS is not set # CONFIG_ISA is not set +# CONFIG_EISA is not set # CONFIG_PCI is not set # @@ -80,17 +81,23 @@ # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BLK_DEV_LVM is not set # # Networking options @@ -107,10 +114,8 @@ 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_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set @@ -127,6 +132,7 @@ # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set @@ -148,6 +154,7 @@ CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 # CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set # CONFIG_BLK_DEV_SR is not set # CONFIG_CHR_DEV_SG is not set @@ -170,6 +177,7 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set @@ -186,14 +194,14 @@ # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_SIM710 is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_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_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_DEBUG is not set @@ -224,6 +232,8 @@ # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -278,8 +288,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -294,17 +302,24 @@ # CONFIG_MAC_PARTITION is not set CONFIG_MSDOS_PARTITION=y # CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_SGI_PARTITION is not set CONFIG_ULTRIX_PARTITION=y # CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # # USB support # # CONFIG_USB is not set + +# +# Input core support +# +# CONFIG_INPUT is not set # # Kernel hacking diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/defconfig-ip22 linux.ac/arch/mips/defconfig-ip22 --- linux.vanilla/arch/mips/defconfig-ip22 Fri Jul 28 02:36:54 2000 +++ linux.ac/arch/mips/defconfig-ip22 Tue Apr 3 17:54:32 2001 @@ -16,16 +16,17 @@ # CONFIG_COBALT_MICRO_SERVER is not set # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -# CONFIG_ORION is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_OLIVETTI_M700 is not set CONFIG_SGI_IP22=y # CONFIG_SNI_RM200_PCI is not set +# CONFIG_MCA is not set # CONFIG_SBUS is not set CONFIG_ARC32=y CONFIG_PC_KEYB=y CONFIG_SGI=y # CONFIG_ISA is not set +# CONFIG_EISA is not set # CONFIG_PCI is not set # @@ -84,17 +85,23 @@ # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BLK_DEV_LVM is not set # # Networking options @@ -111,10 +118,8 @@ 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_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set @@ -131,6 +136,7 @@ # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set @@ -152,6 +158,7 @@ CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y +# CONFIG_CHR_DEV_OSST is not set CONFIG_BLK_DEV_SR=y # CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_SR_EXTRA_DEVS=2 @@ -175,6 +182,7 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set @@ -191,14 +199,14 @@ # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_SIM710 is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_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_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_DEBUG is not set @@ -228,6 +236,8 @@ # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -282,8 +292,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -298,11 +306,13 @@ # CONFIG_MAC_PARTITION is not set CONFIG_MSDOS_PARTITION=y # CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set CONFIG_SGI_PARTITION=y # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # @@ -333,6 +343,11 @@ # USB support # # CONFIG_USB is not set + +# +# Input core support +# +# CONFIG_INPUT is not set # # Kernel hacking diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/defconfig-it8172 linux.ac/arch/mips/defconfig-it8172 --- linux.vanilla/arch/mips/defconfig-it8172 Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/defconfig-it8172 Tue Apr 3 17:54:32 2001 @@ -0,0 +1,569 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_MIPS=y +# CONFIG_SMP is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Machine selection +# +# CONFIG_ACER_PICA_61 is not set +# CONFIG_ALGOR_P4032 is not set +# CONFIG_BAGET_MIPS is not set +# CONFIG_DECSTATION is not set +# CONFIG_DDB5074 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_NINO is not set +# CONFIG_MIPS_MAGNUM_4000 is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_DDB5476 is not set +# CONFIG_OLIVETTI_M700 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SNI_RM200_PCI is not set +CONFIG_MIPS_ITE8172=y +# CONFIG_IT8172_REVC is not set +CONFIG_QTRONIX_KEYBOARD=y +CONFIG_IT8172_CIR=y +# CONFIG_IT8172_SCR0 is not set +# CONFIG_IT8172_SCR1 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_PCI=y +CONFIG_IT8712=y +CONFIG_PC_KEYB=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_I8259 is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# CPU selection +# +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_R3912 is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_RM7000 is not set +CONFIG_CPU_NEVADA=y +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_MIPS32 is not set +# CONFIG_CPU_ADVANCED is not set +CONFIG_CPU_HAS_LLSC=y +# CONFIG_CPU_HAS_WB is not set + +# +# General setup +# +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_MIPS_FPU_EMULATOR=y +CONFIG_KCORE_ELF=y +CONFIG_ELF_KERNEL=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_NET=y +CONFIG_PCI_NAMES=y +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set +# CONFIG_PCMCIA is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# RAM/ROM Device Drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_MTDRAM is not set + +# +# Linearly Mapped Flash Device Drivers +# +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_JEDEC is not set +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_START=8000000 +CONFIG_MTD_PHYSMAP_LEN=2000000 +CONFIG_MTD_PHYSMAP_BUSWIDTH=4 + +# +# Drivers for chip mappings +# +# CONFIG_MTD_MIXMEM is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_OCTAGON is not set +# CONFIG_MTD_PNC2000 is not set +# CONFIG_MTD_RPXLITE is not set +# CONFIG_MTD_VMAX is not set + +# +# User modules and translation layers for MTD devices +# +CONFIG_MTD_CHAR=y +# CONFIG_MTD_BLOCK is not set +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +# CONFIG_UNIX is not set +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_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +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_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_IDEDMA_PCI_AUTO=y +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD7409 is not set +# CONFIG_AMD7409_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +CONFIG_BLK_DEV_IT8172=y +CONFIG_IT8172_TUNING=y +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_BLK_DEV_OSB4 is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +CONFIG_IDE_CHIPSETS=y + +# +# Note: most of these also require special kernel boot parameters +# +# CONFIG_BLK_DEV_4DRIVES is not set +# CONFIG_BLK_DEV_ALI14XX is not set +# CONFIG_BLK_DEV_DTC2278 is not set +# CONFIG_BLK_DEV_HT6560B is not set +# CONFIG_BLK_DEV_PDC4030 is not set +# CONFIG_BLK_DEV_QD6580 is not set +# CONFIG_BLK_DEV_UMC8672 is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=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_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_TULIP=y +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set +# CONFIG_EEPRO100_PM is not set +# CONFIG_LNE390 is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +CONFIG_8139TOO=y +# CONFIG_RTL8129 is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_LAN_SAA9730 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring 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_WAN is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_RAMFS 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_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Input core support +# +# CONFIG_INPUT is not set + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_MIPS_FPE_MODULE is not set +# CONFIG_REMOTE_DEBUG is not set +# CONFIG_LL_DEBUG is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_MIPS_UNCACHED is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/defconfig-orion linux.ac/arch/mips/defconfig-orion --- linux.vanilla/arch/mips/defconfig-orion Fri Jul 28 02:36:54 2000 +++ linux.ac/arch/mips/defconfig-orion Tue Apr 3 17:54:32 2001 @@ -16,13 +16,14 @@ # CONFIG_COBALT_MICRO_SERVER is not set # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -CONFIG_ORION=y # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_OLIVETTI_M700 is not set # CONFIG_SGI_IP22 is not set # CONFIG_SNI_RM200_PCI is not set +# CONFIG_MCA is not set # CONFIG_SBUS is not set # CONFIG_ISA is not set +# CONFIG_EISA is not set # CONFIG_PCI is not set # @@ -79,18 +80,24 @@ # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_LVM is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_LVM is not set # # Networking options @@ -113,6 +120,7 @@ # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set # CONFIG_ECONET_AUNUDP is not set # CONFIG_ECONET_NATIVE is not set # CONFIG_WAN_ROUTER is not set @@ -180,6 +188,10 @@ # Joysticks # # CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# # CONFIG_QIC02_TAPE is not set # @@ -189,11 +201,6 @@ # CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -202,8 +209,13 @@ # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set # CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems @@ -211,6 +223,8 @@ # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -265,6 +279,7 @@ # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # @@ -276,6 +291,11 @@ # USB support # # CONFIG_USB is not set + +# +# Input core support +# +# CONFIG_INPUT is not set # # Kernel hacking diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/defconfig-rm200 linux.ac/arch/mips/defconfig-rm200 --- linux.vanilla/arch/mips/defconfig-rm200 Fri Jul 28 02:36:54 2000 +++ linux.ac/arch/mips/defconfig-rm200 Tue Apr 3 17:54:32 2001 @@ -16,16 +16,17 @@ # CONFIG_COBALT_MICRO_SERVER is not set # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -# CONFIG_ORION is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_OLIVETTI_M700 is not set # CONFIG_SGI_IP22 is not set CONFIG_SNI_RM200_PCI=y +# CONFIG_MCA is not set # CONFIG_SBUS is not set CONFIG_ARC32=y CONFIG_PCI=y CONFIG_ISA=y CONFIG_PC_KEYB=y +CONFIG_EISA=y # # Loadable module support @@ -88,17 +89,23 @@ # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BLK_DEV_LVM is not set # # Networking options @@ -113,10 +120,8 @@ # 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_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set @@ -133,6 +138,7 @@ # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set @@ -211,6 +217,10 @@ # Joysticks # # CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# # CONFIG_QIC02_TAPE is not set # @@ -220,11 +230,6 @@ # CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set CONFIG_RTC=y - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -233,8 +238,13 @@ # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set # CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems @@ -242,6 +252,8 @@ # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -296,8 +308,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -312,11 +322,13 @@ # CONFIG_MAC_PARTITION is not set CONFIG_MSDOS_PARTITION=y # CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set CONFIG_SGI_PARTITION=y # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # @@ -339,6 +351,11 @@ # USB support # # CONFIG_USB is not set + +# +# Input core support +# +# CONFIG_INPUT is not set # # Kernel hacking diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/Makefile linux.ac/arch/mips/ite-boards/generic/Makefile --- linux.vanilla/arch/mips/ite-boards/generic/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/Makefile Tue Apr 3 17:54:32 2001 @@ -0,0 +1,36 @@ +# +# Copyright 2000 MontaVista Software Inc. +# Author: MontaVista Software, Inc. +# ppopov@mvista.com or support@mvista.com +# +# Makefile for the ITE 8172 (qed-4n-s01b) board, generic files. +# +# 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). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: it8172.o + +O_TARGET := it8172.o + +obj-y := it8172_rtc.o it8172_setup.o irq.o int-handler.o pmon_prom.o time.o lpc.o puts.o reset.o + +ifdef CONFIG_PCI +obj-y += it8172_pci.o +endif + +ifdef CONFIG_IT8172_CIR +obj-y += it8172_cir.o +endif + +ifdef CONFIG_REMOTE_DEBUG + obj-y += dbg_io.o +endif + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/dbg_io.c linux.ac/arch/mips/ite-boards/generic/dbg_io.c --- linux.vanilla/arch/mips/ite-boards/generic/dbg_io.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/dbg_io.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,127 @@ + +#include <linux/config.h> + +#ifdef CONFIG_REMOTE_DEBUG + +/* --- CONFIG --- */ + +/* we need uint32 uint8 */ +/* #include "types.h" */ +typedef unsigned char uint8; +typedef unsigned int uint32; + +/* --- END OF CONFIG --- */ + +#define UART16550_BAUD_2400 2400 +#define UART16550_BAUD_4800 4800 +#define UART16550_BAUD_9600 9600 +#define UART16550_BAUD_19200 19200 +#define UART16550_BAUD_38400 38400 +#define UART16550_BAUD_57600 57600 +#define UART16550_BAUD_115200 115200 + +#define UART16550_PARITY_NONE 0 +#define UART16550_PARITY_ODD 0x08 +#define UART16550_PARITY_EVEN 0x18 +#define UART16550_PARITY_MARK 0x28 +#define UART16550_PARITY_SPACE 0x38 + +#define UART16550_DATA_5BIT 0x0 +#define UART16550_DATA_6BIT 0x1 +#define UART16550_DATA_7BIT 0x2 +#define UART16550_DATA_8BIT 0x3 + +#define UART16550_STOP_1BIT 0x0 +#define UART16550_STOP_2BIT 0x4 + +/* ----------------------------------------------------- */ + +/* === CONFIG === */ + +/* [stevel] we use the IT8712 serial port for kgdb */ +#define DEBUG_BASE 0xB40003F8 /* 8712 serial port 1 base address */ +#define MAX_BAUD 115200 + +/* === END OF CONFIG === */ + +/* register offset */ +#define OFS_RCV_BUFFER 0 +#define OFS_TRANS_HOLD 0 +#define OFS_SEND_BUFFER 0 +#define OFS_INTR_ENABLE 1 +#define OFS_INTR_ID 2 +#define OFS_DATA_FORMAT 3 +#define OFS_LINE_CONTROL 3 +#define OFS_MODEM_CONTROL 4 +#define OFS_RS232_OUTPUT 4 +#define OFS_LINE_STATUS 5 +#define OFS_MODEM_STATUS 6 +#define OFS_RS232_INPUT 6 +#define OFS_SCRATCH_PAD 7 + +#define OFS_DIVISOR_LSB 0 +#define OFS_DIVISOR_MSB 1 + + +/* memory-mapped read/write of the port */ +#define UART16550_READ(y) (*((volatile uint8*)(DEBUG_BASE + y))) +#define UART16550_WRITE(y,z) ((*((volatile uint8*)(DEBUG_BASE + y))) = z) + +void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop) +{ + /* disable interrupts */ + UART16550_WRITE(OFS_INTR_ENABLE, 0); + + /* set up buad rate */ + { + uint32 divisor; + + /* set DIAB bit */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x80); + + /* set divisor */ + divisor = MAX_BAUD / baud; + UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff); + UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00)>>8); + + /* clear DIAB bit */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x0); + } + + /* set data format */ + UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop); +} + +static int remoteDebugInitialized = 0; + +uint8 getDebugChar(void) +{ + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(UART16550_BAUD_115200, + UART16550_DATA_8BIT, + UART16550_PARITY_NONE, + UART16550_STOP_1BIT); + } + + while((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0); + return UART16550_READ(OFS_RCV_BUFFER); +} + + +int putDebugChar(uint8 byte) +{ + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(UART16550_BAUD_115200, + UART16550_DATA_8BIT, + UART16550_PARITY_NONE, + UART16550_STOP_1BIT); + } + + while ((UART16550_READ(OFS_LINE_STATUS) &0x20) == 0); + UART16550_WRITE(OFS_SEND_BUFFER, byte); + return 1; +} + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/int-handler.S linux.ac/arch/mips/ite-boards/generic/int-handler.S --- linux.vanilla/arch/mips/ite-boards/generic/int-handler.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/int-handler.S Tue Apr 3 17:54:32 2001 @@ -0,0 +1,61 @@ +#include <asm/asm.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> + + .text + .set macro + .set noat + .align 5 + +NESTED(it8172_IRQ, PT_SIZE, sp) + SAVE_ALL + CLI # Important: mark KERNEL mode ! + + /* We're working with 'reorder' set at this point. */ + /* + * Get pending interrupts + */ + + mfc0 t0,CP0_CAUSE # get pending interrupts + mfc0 t1,CP0_STATUS # get enabled interrupts + and t0,t1 # isolate allowed ones + + andi t0,0xff00 # isolate pending bits + beqz t0, 3f # spurious interrupt + + andi a0, t0, CAUSEF_IP7 + beq a0, zero, 1f + move a0, sp + jal mips_timer_interrupt + j ret_from_irq + nop + +1: + andi a0, t0, CAUSEF_IP2 # the only int we expect at this time + beq a0, zero, 3f + move a0,sp + jal it8172_hw0_irqdispatch + + mfc0 t0,CP0_STATUS # disable interrupts + ori t0,1 + xori t0,1 + mtc0 t0,CP0_STATUS + nop + nop + nop + + la a1, ret_from_irq + jr a1 + nop + +3: + move a0, sp + jal mips_spurious_interrupt + nop + la a1, ret_from_irq + jr a1 + nop + +END(it8172_IRQ) + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/irq.c linux.ac/arch/mips/ite-boards/generic/irq.c --- linux.vanilla/arch/mips/ite-boards/generic/irq.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/irq.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,540 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * ITE 8172G interrupt/setup routines. + * + * Copyright 2000,2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.com + * + * Part of this file was derived from Carsten Langgaard's + * arch/mips/mips-boards/atlas/atlas_int.c. + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS 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. + * + * 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 <linux/config.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/module.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/timex.h> +#include <linux/malloc.h> +#include <linux/random.h> +#include <linux/serial_reg.h> + +#include <asm/bitops.h> +#include <asm/bootinfo.h> +#include <asm/io.h> +#include <asm/mipsregs.h> +#include <asm/system.h> +#include <asm/it8172/it8172.h> +#include <asm/it8172/it8172_int.h> +#include <asm/it8172/it8172_dbg.h> + +#undef DEBUG_IRQ +#ifdef DEBUG_IRQ +/* note: prints function name for you */ +#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#ifdef CONFIG_REMOTE_DEBUG +extern void breakpoint(void); +#endif + +/* revisit */ +#define EXT_IRQ0_TO_IP 2 /* IP 2 */ +#define EXT_IRQ5_TO_IP 7 /* IP 7 */ + +extern void set_debug_traps(void); +extern void mips_timer_interrupt(int irq, struct pt_regs *regs); +extern asmlinkage void it8172_IRQ(void); +irq_cpustat_t irq_stat [NR_CPUS]; +unsigned int local_bh_count[NR_CPUS]; +unsigned int local_irq_count[NR_CPUS]; +unsigned long spurious_count = 0; +irq_desc_t irq_desc[NR_IRQS]; +irq_desc_t *irq_desc_base=&irq_desc[0]; + +struct it8172_intc_regs volatile *it8172_hw0_icregs + = (struct it8172_intc_regs volatile *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_INTC_BASE)); + +/* Function for careful CP0 interrupt mask access */ +static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask) +{ + unsigned long status = read_32bit_cp0_register(CP0_STATUS); + status &= ~((clr_mask & 0xFF) << 8); + status |= (set_mask & 0xFF) << 8; + write_32bit_cp0_register(CP0_STATUS, status); +} + +static inline void mask_irq(unsigned int irq_nr) +{ + modify_cp0_intmask(irq_nr, 0); +} + +static inline void unmask_irq(unsigned int irq_nr) +{ + modify_cp0_intmask(0, irq_nr); +} + +void disable_irq(unsigned int irq_nr) +{ + unsigned long flags; + + save_and_cli(flags); + mask_irq(irq_nr); + restore_flags(flags); +} + +void enable_irq(unsigned int irq_nr) +{ + unsigned long flags; + + save_and_cli(flags); + unmask_irq(irq_nr); + restore_flags(flags); +} + + +void disable_it8172_irq(unsigned int irq_nr) +{ + unsigned short mask; + + DPRINTK("disable_it8172_irq %d\n", irq_nr); + + if ( (irq_nr >= IT8172_LPC_IRQ_BASE) && (irq_nr <= IT8172_SERIRQ_15)) { + /* LPC interrupt */ + DPRINTK("disable, before lpc_mask %x\n", it8172_hw0_icregs->lpc_mask); + it8172_hw0_icregs->lpc_mask |= (1 << (irq_nr - IT8172_LPC_IRQ_BASE)); + DPRINTK("disable, after lpc_mask %x\n", it8172_hw0_icregs->lpc_mask); + } + else if ( (irq_nr >= IT8172_LB_IRQ_BASE) && (irq_nr <= IT8172_IOCHK_IRQ)) { + /* Local Bus interrupt */ + DPRINTK("before lb_mask %x\n", it8172_hw0_icregs->lb_mask); + it8172_hw0_icregs->lb_mask |= (1 << (irq_nr - IT8172_LB_IRQ_BASE)); + DPRINTK("after lb_mask %x\n", it8172_hw0_icregs->lb_mask); + } + else if ( (irq_nr >= IT8172_PCI_DEV_IRQ_BASE) && (irq_nr <= IT8172_DMA_IRQ)) { + /* PCI and other interrupts */ + DPRINTK("before pci_mask %x\n", it8172_hw0_icregs->pci_mask); + it8172_hw0_icregs->pci_mask |= (1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE)); + DPRINTK("after pci_mask %x\n", it8172_hw0_icregs->pci_mask); + } + else if ( (irq_nr >= IT8172_NMI_IRQ_BASE) && (irq_nr <= IT8172_POWER_NMI_IRQ)) { + /* NMI interrupts */ + DPRINTK("before nmi_mask %x\n", it8172_hw0_icregs->nmi_mask); + it8172_hw0_icregs->nmi_mask |= (1 << (irq_nr - IT8172_NMI_IRQ_BASE)); + DPRINTK("after nmi_mask %x\n", it8172_hw0_icregs->nmi_mask); + } + else { + panic("disable_it8172_irq: bad irq %d\n", irq_nr); + } +} + + +void enable_it8172_irq(unsigned int irq_nr) +{ + DPRINTK("enable_it8172_irq %d\n", irq_nr); + if ( (irq_nr >= IT8172_LPC_IRQ_BASE) && (irq_nr <= IT8172_SERIRQ_15)) { + /* LPC interrupt */ + DPRINTK("enable, before lpc_mask %x\n", it8172_hw0_icregs->lpc_mask); + it8172_hw0_icregs->lpc_mask &= ~(1 << (irq_nr - IT8172_LPC_IRQ_BASE)); + DPRINTK("enable, after lpc_mask %x\n", it8172_hw0_icregs->lpc_mask); + } + else if ( (irq_nr >= IT8172_LB_IRQ_BASE) && (irq_nr <= IT8172_IOCHK_IRQ)) { + /* Local Bus interrupt */ + DPRINTK("before lb_mask %x\n", it8172_hw0_icregs->lb_mask); + it8172_hw0_icregs->lb_mask &= ~(1 << (irq_nr - IT8172_LB_IRQ_BASE)); + DPRINTK("after lb_mask %x\n", it8172_hw0_icregs->lb_mask); + } + else if ( (irq_nr >= IT8172_PCI_DEV_IRQ_BASE) && (irq_nr <= IT8172_DMA_IRQ)) { + /* PCI and other interrupts */ + DPRINTK("before pci_mask %x\n", it8172_hw0_icregs->pci_mask); + it8172_hw0_icregs->pci_mask &= ~(1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE)); + DPRINTK("after pci_mask %x\n", it8172_hw0_icregs->pci_mask); + } + else if ( (irq_nr >= IT8172_NMI_IRQ_BASE) && (irq_nr <= IT8172_POWER_NMI_IRQ)) { + /* NMI interrupts */ + DPRINTK("before nmi_mask %x\n", it8172_hw0_icregs->nmi_mask); + it8172_hw0_icregs->nmi_mask &= ~(1 << (irq_nr - IT8172_NMI_IRQ_BASE)); + DPRINTK("after nmi_mask %x\n", it8172_hw0_icregs->nmi_mask); + } + else { + panic("enable_it8172_irq: bad irq %d\n", irq_nr); + } +} + +static unsigned int startup_ite_irq(unsigned int irq) +{ + enable_it8172_irq(irq); + return 0; +} + +#define shutdown_ite_irq disable_it8172_irq +#define mask_and_ack_ite_irq disable_it8172_irq + +static void end_ite_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_it8172_irq(irq); +} + +static struct hw_interrupt_type it8172_irq_type = { + "ITE8172", + startup_ite_irq, + shutdown_ite_irq, + enable_it8172_irq, + disable_it8172_irq, + mask_and_ack_ite_irq, + end_ite_irq, + NULL +}; + + +int get_irq_list(char *buf) +{ + int i, len = 0, j; + struct irqaction * action; + + len += sprintf(buf+len, " "); + for (j=0; j<smp_num_cpus; j++) + len += sprintf(buf+len, "CPU%d ",j); + *(char *)(buf+len++) = '\n'; + + for (i = 0 ; i < NR_IRQS ; i++) { + action = irq_desc[i].action; + if ( !action || !action->handler ) + continue; + len += sprintf(buf+len, "%3d: ", i); + len += sprintf(buf+len, "%10u ", kstat_irqs(i)); + if ( irq_desc[i].handler ) + len += sprintf(buf+len, " %s ", irq_desc[i].handler->typename ); + else + len += sprintf(buf+len, " None "); + len += sprintf(buf+len, " %s",action->name); + for (action=action->next; action; action = action->next) { + len += sprintf(buf+len, ", %s", action->name); + } + len += sprintf(buf+len, "\n"); + } + len += sprintf(buf+len, "BAD: %10lu\n", spurious_count); + return len; +} + +asmlinkage void do_IRQ(int irq, struct pt_regs *regs) +{ + struct irqaction *action; + int cpu; + + cpu = smp_processor_id(); + irq_enter(cpu, irq); + + kstat.irqs[cpu][irq]++; +#if 0 + if (irq_desc[irq].handler && irq_desc[irq].handler->ack) { + // printk("invoking ack handler\n"); + irq_desc[irq].handler->ack(irq); + } +#endif + + action = irq_desc[irq].action; + + if (action && action->handler) + { + //mask_irq(1<<irq); + //printk("action->handler %x\n", action->handler); + disable_it8172_irq(irq); + //if (!(action->flags & SA_INTERRUPT)) __sti(); /* reenable ints */ + do { + action->handler(irq, action->dev_id, regs); + action = action->next; + } while ( action ); + //__cli(); /* disable ints */ + if (irq_desc[irq].handler) + { + } + //unmask_irq(1<<irq); + enable_it8172_irq(irq); + } + else + { + spurious_count++; + printk("Unhandled interrupt %d, cause %x, disabled\n", + (unsigned)irq, (unsigned)regs->cp0_cause); + disable_it8172_irq(irq); + //disable_irq(1<<irq); + } + irq_exit(cpu, irq); +} + +int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, const char * devname, void *dev_id) +{ + struct irqaction *old, **p, *action; + unsigned long flags; + + /* + * IP0 and IP1 are software interrupts. IP7 is typically the timer interrupt. + * + * The ITE QED-4N-S01B board has one single interrupt line going from + * the system controller to the CPU. It's connected to the CPU external + * irq pin 1, which is IP2. The interrupt numbers are listed in it8172_int.h; + * the ISA interrupts are numbered from 0 to 15, and the rest go from + * there. + */ + + //printk("request_irq: %d handler %x\n", irq, handler); + if (irq >= NR_IRQS) + return -EINVAL; + + if (!handler) + { + /* Free */ + for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) + { + /* Found it - now free it */ + save_flags(flags); + cli(); + *p = action->next; + disable_it8172_irq(irq); + //disable_irq(1<<irq); + restore_flags(flags); + kfree(action); + return 0; + } + return -ENOENT; + } + + action = (struct irqaction *) + kmalloc(sizeof(struct irqaction), GFP_KERNEL); + if (!action) + return -ENOMEM; + memset(action, 0, sizeof(struct irqaction)); + + save_flags(flags); + cli(); + + action->handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + action->dev_id = dev_id; + action->next = NULL; + + p = &irq_desc[irq].action; + + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & action->flags & SA_SHIRQ)) + return -EBUSY; + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + } + *p = action; + enable_it8172_irq(irq); + restore_flags(flags); +#if 0 + printk("request_irq: status %x cause %x\n", + read_32bit_cp0_register(CP0_STATUS), read_32bit_cp0_register(CP0_CAUSE)); +#endif + return 0; +} + +void free_irq(unsigned int irq, void *dev_id) +{ + request_irq(irq, NULL, 0, NULL, dev_id); +} + +void enable_cpu_timer(void) +{ + enable_irq(1<<EXT_IRQ5_TO_IP); /* timer interrupt */ +} + +unsigned long probe_irq_on (void) +{ + return 0; +} + +int probe_irq_off (unsigned long irqs) +{ + return 0; +} + + +void __init init_IRQ(void) +{ + int i; + + memset(irq_desc, 0, sizeof(irq_desc)); + set_except_vector(0, it8172_IRQ); + + /* mask all interrupts */ + it8172_hw0_icregs->lb_mask = 0xffff; + it8172_hw0_icregs->lpc_mask = 0xffff; + it8172_hw0_icregs->pci_mask = 0xffff; + it8172_hw0_icregs->nmi_mask = 0xffff; + + /* make all interrupts level triggered */ + it8172_hw0_icregs->lb_trigger = 0; + it8172_hw0_icregs->lpc_trigger = 0; + it8172_hw0_icregs->pci_trigger = 0; + it8172_hw0_icregs->nmi_trigger = 0; + + /* active level setting */ + /* uart, keyboard, and mouse are active high */ + it8172_hw0_icregs->lpc_level = (0x10 | 0x2 | 0x1000); + it8172_hw0_icregs->lb_level |= 0x20; + + /* keyboard and mouse are edge triggered */ + it8172_hw0_icregs->lpc_trigger |= (0x2 | 0x1000); + + +#if 0 + // Enable this piece of code to make internal USB interrupt + // edge triggered. + it8172_hw0_icregs->pci_trigger |= + (1 << (IT8172_USB_IRQ - IT8172_PCI_DEV_IRQ_BASE)); + it8172_hw0_icregs->pci_level &= + ~(1 << (IT8172_USB_IRQ - IT8172_PCI_DEV_IRQ_BASE)); +#endif + + for (i = 0; i <= IT8172_INT_END; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = 0; + irq_desc[i].depth = 1; + irq_desc[i].handler = &it8172_irq_type; + } + + /* + * Enable external int line 2 + * All ITE interrupts are masked for now. + */ + enable_irq(1<<EXT_IRQ0_TO_IP); + //change_cp0_status(ST0_IM, IE_IRQ2); + +#ifdef CONFIG_REMOTE_DEBUG + /* If local serial I/O used for debug port, enter kgdb at once */ + puts("Waiting for kgdb to connect..."); + set_debug_traps(); + breakpoint(); +#endif +} + +void mips_spurious_interrupt(struct pt_regs *regs) +{ +#if 1 + return; +#else + unsigned long status, cause; + + printk("got spurious interrupt\n"); + status = read_32bit_cp0_register(CP0_STATUS); + cause = read_32bit_cp0_register(CP0_CAUSE); + printk("status %x cause %x\n", status, cause); + printk("epc %x badvaddr %x \n", regs->cp0_epc, regs->cp0_badvaddr); +// while(1); +#endif +} + +void it8172_hw0_irqdispatch(struct pt_regs *regs) +{ + int irq; + unsigned short intstatus, status; + + intstatus = it8172_hw0_icregs->intstatus; + if (intstatus & 0x8) { + panic("Got NMI interrupt\n"); + } + else if (intstatus & 0x4) { + /* PCI interrupt */ + irq = 0; + status = it8172_hw0_icregs->pci_req; + while (!(status & 0x1)) { + irq++; + status >>= 1; + } + irq += IT8172_PCI_DEV_IRQ_BASE; + //printk("pci int %d\n", irq); + } + else if (intstatus & 0x1) { + /* Local Bus interrupt */ + irq = 0; + status = it8172_hw0_icregs->lb_req; + while (!(status & 0x1)) { + irq++; + status >>= 1; + } + irq += IT8172_LB_IRQ_BASE; + //printk("lb int %d\n", irq); + } + else if (intstatus & 0x2) { + /* LPC interrupt */ + /* Since some lpc interrupts are edge triggered, + * we could lose an interrupt this way because + * we acknowledge all ints at onces. Revisit. + */ + status = it8172_hw0_icregs->lpc_req; + it8172_hw0_icregs->lpc_req = 0; /* acknowledge ints */ + irq = 0; + while (!(status & 0x1)) { + irq++; + status >>= 1; + } + irq += IT8172_LPC_IRQ_BASE; + //printk("LPC int %d\n", irq); + } + else { + return; + } + do_IRQ(irq, regs); +} + +void show_pending_irqs(void) +{ + fputs("intstatus: "); + put32(it8172_hw0_icregs->intstatus); + puts(""); + + fputs("pci_req: "); + put32(it8172_hw0_icregs->pci_req); + puts(""); + + fputs("lb_req: "); + put32(it8172_hw0_icregs->lb_req); + puts(""); + + fputs("lpc_req: "); + put32(it8172_hw0_icregs->lpc_req); + puts(""); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/it8172_cir.c linux.ac/arch/mips/ite-boards/generic/it8172_cir.c --- linux.vanilla/arch/mips/ite-boards/generic/it8172_cir.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/it8172_cir.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,171 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * IT8172 Consumer IR port generic routines. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.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. + * + * 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. + * + * 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 <linux/config.h> + +#ifdef CONFIG_IT8172_CIR + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> + +#include <asm/it8172/it8172.h> +#include <asm/it8172/it8172_cir.h> + + +volatile struct it8172_cir_regs *cir_regs[NUM_CIR_PORTS] = { + (volatile struct it8172_cir_regs *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_CIR0_BASE)), + (volatile struct it8172_cir_regs *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_CIR1_BASE))}; + + +/* + * Initialize Consumer IR Port. + */ +int cir_port_init(struct cir_port *cir) +{ + int port = cir->port; + unsigned char data; + + /* set baud rate */ + cir_regs[port]->bdlr = cir->baud_rate & 0xff; + cir_regs[port]->bdhr = (cir->baud_rate >> 8) & 0xff; + + /* set receiver control register */ + cir_regs[port]->rcr = (CIR_SET_RDWOS(cir->rdwos) | CIR_SET_RXDCR(cir->rxdcr)); + + /* set carrier frequency register */ + cir_regs[port]->cfr = (CIR_SET_CF(cir->cfq) | CIR_SET_HS(cir->hcfs)); + + /* set fifo threshold */ + data = cir_regs[port]->mstcr & 0xf3; + data |= CIR_SET_FIFO_TL(cir->fifo_tl); + cir_regs[port]->mstcr = data; + + clear_fifo(cir); + enable_receiver(cir); + disable_rx_demodulation(cir); + + set_rx_active(cir); + int_enable(cir); + rx_int_enable(cir); + + return 0; +} + + +void clear_fifo(struct cir_port *cir) +{ + cir_regs[cir->port]->mstcr |= CIR_FIFO_CLEAR; +} + +void enable_receiver(struct cir_port *cir) +{ + cir_regs[cir->port]->rcr |= CIR_RXEN; +} + +void disable_receiver(struct cir_port *cir) +{ + cir_regs[cir->port]->rcr &= ~CIR_RXEN; +} + +void enable_rx_demodulation(struct cir_port *cir) +{ + cir_regs[cir->port]->rcr |= CIR_RXEND; +} + +void disable_rx_demodulation(struct cir_port *cir) +{ + cir_regs[cir->port]->rcr &= ~CIR_RXEND; +} + +void set_rx_active(struct cir_port *cir) +{ + cir_regs[cir->port]->rcr |= CIR_RXACT; +} + +void int_enable(struct cir_port *cir) +{ + cir_regs[cir->port]->ier |= CIR_IEC; +} + +void rx_int_enable(struct cir_port *cir) +{ + cir_regs[cir->port]->ier |= CIR_RDAIE; +} + +void dump_regs(struct cir_port *cir) +{ + printk("mstcr %x ier %x iir %x cfr %x rcr %x tcr %x tfsr %x rfsr %x\n", + cir_regs[cir->port]->mstcr, + cir_regs[cir->port]->ier, + cir_regs[cir->port]->iir, + cir_regs[cir->port]->cfr, + cir_regs[cir->port]->rcr, + cir_regs[cir->port]->tcr, + cir_regs[cir->port]->tfsr, + cir_regs[cir->port]->rfsr); + + while (cir_regs[cir->port]->iir & CIR_RDAI) { + printk("data %x\n", cir_regs[cir->port]->dr); + } +} + +void dump_reg_addr(struct cir_port *cir) +{ + printk("dr %x mstcr %x ier %x iir %x cfr %x rcr %x tcr %x bdlr %x bdhr %x tfsr %x rfsr %x\n", + (unsigned)&cir_regs[cir->port]->dr, + (unsigned)&cir_regs[cir->port]->mstcr, + (unsigned)&cir_regs[cir->port]->ier, + (unsigned)&cir_regs[cir->port]->iir, + (unsigned)&cir_regs[cir->port]->cfr, + (unsigned)&cir_regs[cir->port]->rcr, + (unsigned)&cir_regs[cir->port]->tcr, + (unsigned)&cir_regs[cir->port]->bdlr, + (unsigned)&cir_regs[cir->port]->bdhr, + (unsigned)&cir_regs[cir->port]->tfsr, + (unsigned)&cir_regs[cir->port]->rfsr); +} + +int cir_get_rx_count(struct cir_port *cir) +{ + return cir_regs[cir->port]->rfsr & CIR_RXFBC_MASK; +} + +char cir_read_data(struct cir_port *cir) +{ + return cir_regs[cir->port]->dr; +} + +char get_int_status(struct cir_port *cir) +{ + return cir_regs[cir->port]->iir; +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/it8172_pci.c linux.ac/arch/mips/ite-boards/generic/it8172_pci.c --- linux.vanilla/arch/mips/ite-boards/generic/it8172_pci.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/it8172_pci.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,276 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * IT8172 system controller specific pci support. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.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. + * + * 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. + * + * 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 <linux/config.h> + +#ifdef CONFIG_PCI + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> + +#include <asm/it8172/it8172.h> +#include <asm/it8172/it8172_pci.h> + +#define PCI_ACCESS_READ 0 +#define PCI_ACCESS_WRITE 1 + +#undef DEBUG +#undef DEBUG_CONFIG_CYCLES + +static int +it8172_pcibios_config_access(unsigned char access_type, struct pci_dev *dev, + unsigned char where, u32 *data) +{ + /* + * config cycles are on 4 byte boundary only + */ + unsigned char bus = dev->bus->number; + unsigned char dev_fn = dev->devfn; + +#ifdef DEBUG_CONFIG_CYCLES + printk("it config: type %d dev %x bus %d dev_fn %x data %x\n", + access_type, dev, bus, dev_fn, *data); + +#endif + + /* Setup address */ + IT_WRITE(IT_CONFADDR, (bus << IT_BUSNUM_SHF) | + (dev_fn << IT_FUNCNUM_SHF) | (where & ~0x3)); + + + if (access_type == PCI_ACCESS_WRITE) { + IT_WRITE(IT_CONFDATA, *data); + } + else { + IT_READ(IT_CONFDATA, *data); + } + + /* + * Revisit: check for master or target abort. + */ + return 0; + + +} + + +/* + * We can't address 8 and 16 bit words directly. Instead we have to + * read/write a 32bit word and mask/modify the data we actually want. + */ +static int +it8172_pcibios_read_config_byte (struct pci_dev *dev, int where, u8 *val) +{ + u32 data = 0; + + if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + *val = (data >> ((where & 3) << 3)) & 0xff; +#ifdef DEBUG + printk("cfg read byte: bus %d dev_fn %x where %x: val %x\n", + dev->bus->number, dev->devfn, where, *val); +#endif + + return PCIBIOS_SUCCESSFUL; +} + + +static int +it8172_pcibios_read_config_word (struct pci_dev *dev, int where, u16 *val) +{ + u32 data = 0; + + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + *val = (data >> ((where & 3) << 3)) & 0xffff; +#ifdef DEBUG + printk("cfg read word: bus %d dev_fn %x where %x: val %x\n", + dev->bus->number, dev->devfn, where, *val); +#endif + + return PCIBIOS_SUCCESSFUL; +} + +static int +it8172_pcibios_read_config_dword (struct pci_dev *dev, int where, u32 *val) +{ + u32 data = 0; + + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + *val = data; +#ifdef DEBUG + printk("cfg read dword: bus %d dev_fn %x where %x: val %x\n", + dev->bus->number, dev->devfn, where, *val); +#endif + + return PCIBIOS_SUCCESSFUL; +} + + +static int +it8172_pcibios_write_config_byte (struct pci_dev *dev, int where, u8 val) +{ + u32 data = 0; + + if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + + if (it8172_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data)) + return -1; + + return PCIBIOS_SUCCESSFUL; +} + +static int +it8172_pcibios_write_config_word (struct pci_dev *dev, int where, u16 val) +{ + u32 data = 0; + + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + + if (it8172_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data)) + return -1; + + + return PCIBIOS_SUCCESSFUL; +} + +static int +it8172_pcibios_write_config_dword(struct pci_dev *dev, int where, u32 val) +{ + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (it8172_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &val)) + return -1; + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops it8172_pci_ops = { + it8172_pcibios_read_config_byte, + it8172_pcibios_read_config_word, + it8172_pcibios_read_config_dword, + it8172_pcibios_write_config_byte, + it8172_pcibios_write_config_word, + it8172_pcibios_write_config_dword +}; + +void __init pcibios_init(void) +{ + + printk("PCI: Probing PCI hardware on host bus 0.\n"); + pci_scan_bus(0, &it8172_pci_ops, NULL); +} + +int __init +pcibios_enable_device(struct pci_dev *dev) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for(idx=0; idx<6; idx++) { + r = &dev->resource[idx]; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (dev->resource[PCI_ROM_RESOURCE].start) + cmd |= PCI_COMMAND_MEMORY; + if (cmd != old_cmd) { + printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + + +void __init +pcibios_align_resource(void *data, struct resource *res, unsigned long size) +{ + printk("pcibios_align_resource\n"); +} + +char * __init +pcibios_setup(char *str) +{ + /* Nothing to do for now. */ + + return str; +} + +void __init +pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) +{ + unsigned long where, size; + u32 reg; + + where = PCI_BASE_ADDRESS_0 + (resource * 4); + size = res->end - res->start; + pci_read_config_dword(dev, where, ®); + reg = (reg & size) | (((u32)(res->start - root->start)) & ~size); + pci_write_config_dword(dev, where, reg); +} + +void __init pcibios_fixup_bus(struct pci_bus *b) +{ + printk("pcibios_fixup_bus\n"); +} +#endif /* CONFIG_PCI */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/it8172_rtc.c linux.ac/arch/mips/ite-boards/generic/it8172_rtc.c --- linux.vanilla/arch/mips/ite-boards/generic/it8172_rtc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/it8172_rtc.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,63 @@ +/* + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.com + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + * + * RTC routines for ITE8172 MC146818-compatible rtc chip. + * + */ +#include <asm/spinlock.h> +#include <linux/mc146818rtc.h> +#include <asm/it8172/it8172.h> + +#define IT8172_RTC_ADR_REG (IT8172_PCI_IO_BASE + IT_RTC_BASE) +#define IT8172_RTC_DAT_REG (IT8172_RTC_ADR_REG + 1) + +static volatile char *rtc_adr_reg = KSEG1ADDR((volatile char *)IT8172_RTC_ADR_REG); +static volatile char *rtc_dat_reg = KSEG1ADDR((volatile char *)IT8172_RTC_DAT_REG); + +unsigned char it8172_rtc_read_data(unsigned long addr) +{ + unsigned char retval; + + *rtc_adr_reg = addr; + retval = *rtc_dat_reg; + return retval; +} + +void it8172_rtc_write_data(unsigned char data, unsigned long addr) +{ + *rtc_adr_reg = addr; + *rtc_dat_reg = data; +} + +static int it8172_rtc_bcd_mode(void) +{ + return 0; +} + +struct rtc_ops it8172_rtc_ops = { + &it8172_rtc_read_data, + &it8172_rtc_write_data, + &it8172_rtc_bcd_mode +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/it8172_setup.c linux.ac/arch/mips/ite-boards/generic/it8172_setup.c --- linux.vanilla/arch/mips/ite-boards/generic/it8172_setup.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/it8172_setup.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,310 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * IT8172/QED5231 board setup. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.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. + * + * 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. + * + * 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 <linux/config.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/ioport.h> +#include <linux/console.h> +#include <linux/mc146818rtc.h> +#include <linux/serial_reg.h> + +#include <asm/cpu.h> +#include <asm/bootinfo.h> +#include <asm/irq.h> +#include <asm/mipsregs.h> +#include <asm/reboot.h> +#include <asm/it8172/it8172.h> +#include <asm/it8712.h> +#ifdef CONFIG_PC_KEYB +#include <asm/keyboard.h> +#endif + +#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE) +extern void console_setup(char *, int *); +char serial_console[20]; +#endif + +extern struct rtc_ops it8172_rtc_ops; +extern struct resource ioport_resource; +extern unsigned long mips_io_port_base; +#ifdef CONFIG_BLK_DEV_IDE +extern struct ide_ops std_ide_ops; +extern struct ide_ops *ide_ops; +#endif +#ifdef CONFIG_PC_KEYB +extern struct kbd_ops std_kbd_ops; +int init_8712_keyboard(void); +#endif + +extern int SearchIT8712(void); +extern void InitLPCInterface(void); +extern char * __init prom_getcmdline(void); +extern void it8172_restart(void); +extern void it8172_halt(void); +extern void it8172_power_off(void); + +#ifdef CONFIG_IT8172_REVC +struct { + struct resource ram; + struct resource pci_mem; + struct resource pci_io; + struct resource flash; + struct resource boot; +} it8172_resources = { + { "RAM", 0, 0, IORESOURCE_MEM }, /* to be initted */ + { "PCI Mem", 0x10000000, 0x13FFFFFF, IORESOURCE_MEM }, + { "PCI I/O", 0x14000000, 0x17FFFFFF }, + { "Flash", 0x08000000, 0x0CFFFFFF }, + { "Boot ROM", 0x1FC00000, 0x1FFFFFFF } +}; +#else +struct { + struct resource ram; + struct resource pci_mem0; + struct resource pci_mem1; + struct resource pci_io; + struct resource pci_mem2; + struct resource pci_mem3; + struct resource flash; + struct resource boot; +} it8172_resources = { + { "RAM", 0, 0, IORESOURCE_MEM }, /* to be initted */ + { "PCI Mem0", 0x0C000000, 0x0FFFFFFF, IORESOURCE_MEM }, + { "PCI Mem1", 0x10000000, 0x13FFFFFF, IORESOURCE_MEM }, + { "PCI I/O", 0x14000000, 0x17FFFFFF }, + { "PCI Mem2", 0x1A000000, 0x1BFFFFFF, IORESOURCE_MEM }, + { "PCI Mem3", 0x1C000000, 0x1FBFFFFF, IORESOURCE_MEM }, + { "Flash", 0x08000000, 0x0CFFFFFF }, + { "Boot ROM", 0x1FC00000, 0x1FFFFFFF } +}; +#endif + + +void __init it8172_init_ram_resource(unsigned long memsize) +{ + it8172_resources.ram.end = memsize; +} + +void __init it8172_setup(void) +{ +#ifdef CONFIG_BLK_DEV_IT8172 + unsigned short dsr; +#endif + char *argptr; + + argptr = prom_getcmdline(); +#ifdef CONFIG_SERIAL_CONSOLE + if ((argptr = strstr(argptr, "console=ttyS0")) == NULL) { + strcpy(serial_console, "ttyS0,115200"); + console_setup(serial_console, NULL); + } +#endif + + rtc_ops = &it8172_rtc_ops; + + _machine_restart = it8172_restart; + _machine_halt = it8172_halt; + _machine_power_off = it8172_power_off; + + /* + * IO/MEM resources. + * + * revisit this area. + */ + mips_io_port_base = KSEG1; + ioport_resource.start = it8172_resources.pci_io.start; + ioport_resource.end = it8172_resources.pci_io.end; +#ifdef CONFIG_IT8172_REVC + iomem_resource.start = it8172_resources.pci_mem.start; + iomem_resource.end = it8172_resources.pci_mem.end; +#else + iomem_resource.start = it8172_resources.pci_mem0.start; + iomem_resource.end = it8172_resources.pci_mem3.end; +#endif + +#ifdef CONFIG_BLK_DEV_INITRD + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); +#endif + +#ifdef CONFIG_BLK_DEV_IT8172 + /* + * Pull IDE device out of standby mode. + */ + IT_IO_READ16(IT_PM_DSR, dsr); + dsr &= ~IT_PM_DSR_IDESB; + IT_IO_WRITE16(IT_PM_DSR, dsr); + + ide_ops = &std_ide_ops; +#endif + +#ifdef CONFIG_FB + conswitchp = &dummy_con; +#endif + + InitLPCInterface(); + +#ifdef CONFIG_MIPS_ITE8172 + if (SearchIT8712()) { + printk("Found IT8712 Super IO\n"); + // enable IT8712 serial port + LPCSetConfig(LDN_SERIAL1, 0x30, 0x01); /* enable */ + LPCSetConfig(LDN_SERIAL1, 0x23, 0x01); /* clock selection */ +#ifdef CONFIG_PC_KEYB + if (init_8712_keyboard()) { + printk("Unable to initialize keyboard\n"); + LPCSetConfig(LDN_KEYBOARD, 0x30, 0x0); /* disable keyboard */ + } + else { + LPCSetConfig(LDN_KEYBOARD, 0x30, 0x1); /* enable keyboard */ + LPCSetConfig(LDN_KEYBOARD, 0xf0, 0x2); + LPCSetConfig(LDN_KEYBOARD, 0x71, 0x3); + + LPCSetConfig(LDN_MOUSE, 0x30, 0x1); /* enable mouse */ + + LPCSetConfig(0x4, 0x30, 0x1); + LPCSetConfig(0x4, 0xf4, LPCGetConfig(0x4, 0xf4) | 0x80); + + if ((LPCGetConfig(LDN_KEYBOARD, 0x30) == 0) || + (LPCGetConfig(LDN_MOUSE, 0x30) == 0)) + printk("Error: keyboard or mouse not enabled\n"); + + kbd_ops = &std_kbd_ops; + } +#endif + } + else { + printk("IT8712 Super IO not found\n"); + } +#endif + +#ifdef CONFIG_IT8172_CIR + { + unsigned long data; + //printk("Enabling CIR0\n"); + IT_IO_READ16(IT_PM_DSR, data); + data &= ~IT_PM_DSR_CIR0SB; + IT_IO_WRITE16(IT_PM_DSR, data); + //printk("DSR register: %x\n", (unsigned)IT_IO_READ16(IT_PM_DSR, data)); + } +#endif +#ifdef CONFIG_IT8172_SCR0 + { + unsigned i; + /* Enable Smart Card Reader 0 */ + /* First power it up */ + IT_IO_READ16(IT_PM_DSR, i); + i &= ~IT_PM_DSR_SCR0SB; + IT_IO_WRITE16(IT_PM_DSR, i); + /* Then initialize its registers */ + outb(( IT_SCR_SFR_GATE_UART_OFF << IT_SCR_SFR_GATE_UART_BIT + |IT_SCR_SFR_FET_CHARGE_213_US << IT_SCR_SFR_FET_CHARGE_BIT + |IT_SCR_SFR_CARD_FREQ_3_5_MHZ << IT_SCR_SFR_CARD_FREQ_BIT + |IT_SCR_SFR_FET_ACTIVE_INVERT << IT_SCR_SFR_FET_ACTIVE_BIT + |IT_SCR_SFR_ENABLE_ON << IT_SCR_SFR_ENABLE_BIT), + IT8172_PCI_IO_BASE + IT_SCR0_BASE + IT_SCR_SFR); + outb(IT_SCR_SCDR_RESET_MODE_ASYNC << IT_SCR_SCDR_RESET_MODE_BIT, + IT8172_PCI_IO_BASE + IT_SCR0_BASE + IT_SCR_SCDR); + } +#endif /* CONFIG_IT8172_SCR0 */ +#ifdef CONFIG_IT8172_SCR1 + { + unsigned i; + /* Enable Smart Card Reader 1 */ + /* First power it up */ + IT_IO_READ16(IT_PM_DSR, i); + i &= ~IT_PM_DSR_SCR1SB; + IT_IO_WRITE16(IT_PM_DSR, i); + /* Then initialize its registers */ + outb(( IT_SCR_SFR_GATE_UART_OFF << IT_SCR_SFR_GATE_UART_BIT + |IT_SCR_SFR_FET_CHARGE_213_US << IT_SCR_SFR_FET_CHARGE_BIT + |IT_SCR_SFR_CARD_FREQ_3_5_MHZ << IT_SCR_SFR_CARD_FREQ_BIT + |IT_SCR_SFR_FET_ACTIVE_INVERT << IT_SCR_SFR_FET_ACTIVE_BIT + |IT_SCR_SFR_ENABLE_ON << IT_SCR_SFR_ENABLE_BIT), + IT8172_PCI_IO_BASE + IT_SCR1_BASE + IT_SCR_SFR); + outb(IT_SCR_SCDR_RESET_MODE_ASYNC << IT_SCR_SCDR_RESET_MODE_BIT, + IT8172_PCI_IO_BASE + IT_SCR1_BASE + IT_SCR_SCDR); + } +#endif /* CONFIG_IT8172_SCR1 */ +} + + +#ifdef CONFIG_PC_KEYB +/* + * According to the ITE Special BIOS Note for waking up the + * keyboard controller... + */ +int init_8712_keyboard() +{ + unsigned int cmd_port = 0x14000064; + unsigned int data_port = 0x14000060; + unsigned char data; + int i; + + printk("8712 keyboard init"); + + outb(0xaa, cmd_port); /* send self-test cmd */ + i = 0; + while (!(inb(cmd_port) & 0x1)) { /* wait output buffer full */ + i++; + if (i > 0xffffff) + return 1; + } + + data = inb(data_port); + outb(0xcb, cmd_port); /* set ps2 mode */ + while (inb(cmd_port) & 0x2) { /* wait while input buffer full */ + i++; + if (i > 0xffffff) + return 1; + } + outb(0x01, data_port); + while (inb(cmd_port) & 0x2) { /* wait while input buffer full */ + i++; + if (i > 0xffffff) + return 1; + } + + outb(0x60, cmd_port); /* write 8042 command byte */ + while (inb(cmd_port) & 0x2) { /* wait while input buffer full */ + i++; + if (i > 0xffffff) + return 1; + } + outb(0x45, data_port); /* at interface, keyboard enabled, system flag */ + while (inb(cmd_port) & 0x2) { /* wait while input buffer full */ + i++; + if (i > 0xffffff) + return 1; + } + + outb(0xae, cmd_port); /* enable interface */ + return 0; +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/lpc.c linux.ac/arch/mips/ite-boards/generic/lpc.c --- linux.vanilla/arch/mips/ite-boards/generic/lpc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/lpc.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,144 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * ITE Semi IT8712 Super I/O functions. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.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. + * + * 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. + * + * 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 <asm/io.h> +#include <asm/types.h> +#include <asm/it8712.h> +#include <asm/it8172/it8172.h> + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +void LPCEnterMBPnP() +{ + int i; + unsigned char key[4] = {0x87, 0x01, 0x55, 0x55}; + + for (i = 0; i<4; i++) + outb(key[i], LPC_KEY_ADDR); + +} + +void LPCExitMBPnP() +{ + outb(0x02, LPC_KEY_ADDR); + outb(0x02, LPC_DATA_ADDR); +} + +void LPCSetConfig(char LdnNumber, char Index, char data) +{ + LPCEnterMBPnP(); // Enter IT8712 MB PnP mode + outb(0x07, LPC_KEY_ADDR); + outb(LdnNumber, LPC_DATA_ADDR); + outb(Index, LPC_KEY_ADDR); + outb(data, LPC_DATA_ADDR); + LPCExitMBPnP(); +} + +char LPCGetConfig(char LdnNumber, char Index) +{ + char rtn; + + LPCEnterMBPnP(); // Enter IT8712 MB PnP mode + outb(0x07, LPC_KEY_ADDR); + outb(LdnNumber, LPC_DATA_ADDR); + outb(Index, LPC_KEY_ADDR); + rtn = inb(LPC_DATA_ADDR); + LPCExitMBPnP(); + return rtn; +} + +int SearchIT8712() +{ + unsigned char Id1, Id2; + unsigned short Id; + + LPCEnterMBPnP(); + outb(0x20, LPC_KEY_ADDR); /* chip id byte 1 */ + Id1 = inb(LPC_DATA_ADDR); + outb(0x21, LPC_KEY_ADDR); /* chip id byte 2 */ + Id2 = inb(LPC_DATA_ADDR); + Id = (Id1 << 8) | Id2; + LPCExitMBPnP(); + if (Id == 0x8712) + return TRUE; + else + return FALSE; +} + +void InitLPCInterface() +{ + unsigned char bus, dev_fn; + unsigned long data; + + bus = 0; + dev_fn = 1<<3 | 4; + + + /* pci cmd, SERR# Enable */ + IT_WRITE(IT_CONFADDR, + (bus << IT_BUSNUM_SHF) | + (dev_fn << IT_FUNCNUM_SHF) | + ((0x4 / 4) << IT_REGNUM_SHF)); + IT_READ(IT_CONFDATA, data); + data |= 0x0100; + IT_WRITE(IT_CONFADDR, + (bus << IT_BUSNUM_SHF) | + (dev_fn << IT_FUNCNUM_SHF) | + ((0x4 / 4) << IT_REGNUM_SHF)); + IT_WRITE(IT_CONFDATA, data); + + /* setup serial irq control register */ + IT_WRITE(IT_CONFADDR, + (bus << IT_BUSNUM_SHF) | + (dev_fn << IT_FUNCNUM_SHF) | + ((0x48 / 4) << IT_REGNUM_SHF)); + IT_READ(IT_CONFDATA, data); + data = (data & 0xffff00ff) | 0xc400; + IT_WRITE(IT_CONFADDR, + (bus << IT_BUSNUM_SHF) | + (dev_fn << IT_FUNCNUM_SHF) | + ((0x48 / 4) << IT_REGNUM_SHF)); + IT_WRITE(IT_CONFDATA, data); + + + /* Enable I/O Space Subtractive Decode */ + /* default 0x4C is 0x3f220000 */ + IT_WRITE(IT_CONFADDR, + (bus << IT_BUSNUM_SHF) | + (dev_fn << IT_FUNCNUM_SHF) | + ((0x4C / 4) << IT_REGNUM_SHF)); + IT_WRITE(IT_CONFDATA, 0x3f2200f3); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/pmon_prom.c linux.ac/arch/mips/ite-boards/generic/pmon_prom.c --- linux.vanilla/arch/mips/ite-boards/generic/pmon_prom.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/pmon_prom.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,138 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * PROM library initialisation code, assuming a version of + * pmon is the boot code. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.com + * + * This file was derived from Carsten Langgaard's + * arch/mips/mips-boards/xx files. + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS 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. + * + * 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 <linux/kernel.h> +#include <linux/init.h> +#include <linux/string.h> + +#include <asm/bootinfo.h> + +/* #define DEBUG_CMDLINE */ + +char arcs_cmdline[COMMAND_LINE_SIZE]; +int prom_argc; +char **prom_argv, **prom_envp; + +typedef struct +{ + char *name; +/* char *val; */ +}t_env_var; + + +char * __init prom_getcmdline(void) +{ + return &(arcs_cmdline[0]); +} + +void __init prom_init_cmdline(void) +{ + char *cp; + int actr; + + actr = 1; /* Always ignore argv[0] */ + + cp = &(arcs_cmdline[0]); + while(actr < prom_argc) { + strcpy(cp, prom_argv[actr]); + cp += strlen(prom_argv[actr]); + *cp++ = ' '; + actr++; + } + if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ + --cp; + *cp = '\0'; + +} + + +char *prom_getenv(char *envname) +{ + /* + * Return a pointer to the given environment variable. + * Environment variables are stored in the form of "memsize=64". + */ + + t_env_var *env = (t_env_var *)prom_envp; + int i; + + i = strlen(envname); + + while(env->name) { + if(strncmp(envname, env->name, i) == 0) { + return(env->name + strlen(envname) + 1); + } + env++; + } + return(NULL); +} + +static inline unsigned char str2hexnum(unsigned char c) +{ + if(c >= '0' && c <= '9') + return c - '0'; + if(c >= 'a' && c <= 'f') + return c - 'a' + 10; + return 0; /* foo */ +} + +int __init page_is_ram(unsigned long pagenr) +{ + return 1; +} + +void prom_free_prom_memory (void) +{ +} + +unsigned long __init prom_get_memsize(void) +{ + char *memsize_str; + unsigned int memsize; + + memsize_str = prom_getenv("memsize"); + if (!memsize_str) { + printk("memsize unknown: setting to 32MB\n"); + memsize = 32; + } else { +#ifdef DEBUG + printk("prom_memsize: %s\n", memsize_str); +#endif + memsize = simple_strtol(memsize_str, NULL, 0); + } + return memsize; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/puts.c linux.ac/arch/mips/ite-boards/generic/puts.c --- linux.vanilla/arch/mips/ite-boards/generic/puts.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/puts.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,144 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Low level uart routines to directly access a 16550 uart. + * + * Copyright 2000,2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.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. + * + * 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. + * + * 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 <linux/types.h> + +#define SERIAL_BASE 0xB4011800 /* it8172 */ +#define SER_CMD 5 +#define SER_DATA 0x00 +#define TX_BUSY 0x20 + +#define TIMEOUT 0xffff +#undef SLOW_DOWN + +static const char digits[16] = "0123456789abcdef"; +static volatile unsigned char * const com1 = (unsigned char *)SERIAL_BASE; + + +#ifdef SLOW_DOWN +static inline void slow_down() +{ + int k; + for (k=0; k<10000; k++); +} +#else +#define slow_down() +#endif + +void +putch(const unsigned char c) +{ + unsigned char ch; + int i = 0; + + do { + ch = com1[SER_CMD]; + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (0 == (ch & TX_BUSY)); + com1[SER_DATA] = c; +} + +void +puts(unsigned char *cp) +{ + unsigned char ch; + int i = 0; + + while (*cp) { + do { + ch = com1[SER_CMD]; + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (0 == (ch & TX_BUSY)); + com1[SER_DATA] = *cp++; + } + putch('\r'); + putch('\n'); +} + +void +fputs(unsigned char *cp) +{ + unsigned char ch; + int i = 0; + + while (*cp) { + + do { + ch = com1[SER_CMD]; + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (0 == (ch & TX_BUSY)); + com1[SER_DATA] = *cp++; + } +} + + +void +put64(uint64_t ul) +{ + int cnt; + unsigned ch; + + cnt = 16; /* 16 nibbles in a 64 bit long */ + putch('0'); + putch('x'); + do { + cnt--; + ch = (unsigned char)(ul >> cnt * 4) & 0x0F; + putch(digits[ch]); + } while (cnt > 0); +} + +void +put32(unsigned u) +{ + int cnt; + unsigned ch; + + cnt = 8; /* 8 nibbles in a 32 bit long */ + putch('0'); + putch('x'); + do { + cnt--; + ch = (unsigned char)(u >> cnt * 4) & 0x0F; + putch(digits[ch]); + } while (cnt > 0); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/reset.c linux.ac/arch/mips/ite-boards/generic/reset.c --- linux.vanilla/arch/mips/ite-boards/generic/reset.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/reset.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,61 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * ITE 8172 reset routines. + * + * Copyright (C) 1997, 2001 Ralf Baechle + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.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. + * + * 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. + * + * 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 <linux/sched.h> +#include <linux/mm.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/processor.h> +#include <asm/reboot.h> +#include <asm/system.h> + +void it8172_restart(char *command) +{ + set_cp0_status(ST0_BEV | ST0_ERL); + change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); + flush_cache_all(); + write_32bit_cp0_register(CP0_WIRED, 0); + __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000)); +} + +void it8172_halt(void) +{ + printk(KERN_NOTICE "\n** You can safely turn off the power\n"); + while (1) + __asm__(".set\tmips3\n\t" + "wait\n\t" + ".set\tmips0"); +} + +void it8172_power_off(void) +{ + it8172_halt(); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/time.c linux.ac/arch/mips/ite-boards/generic/time.c --- linux.vanilla/arch/mips/ite-boards/generic/time.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/time.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,378 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + * + * Setting up the clock on the MIPS boards. + * + */ + +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/sched.h> +#include <linux/spinlock.h> + +#include <asm/mipsregs.h> +#include <asm/ptrace.h> +#include <asm/it8172/it8172_int.h> + +#include <linux/mc146818rtc.h> +#include <linux/timex.h> + +extern void enable_cpu_timer(void); +extern volatile unsigned long wall_jiffies; +extern rwlock_t xtime_lock; + +unsigned long missed_heart_beats = 0; +static long last_rtc_update = 0; +static unsigned long r4k_offset; /* Amount to increment compare reg each time */ +static unsigned long r4k_cur; /* What counter should be at next timer irq */ +static unsigned int timer_tick_count=0; + +static inline void ack_r4ktimer(unsigned long newval) +{ + write_32bit_cp0_register(CP0_COMPARE, newval); +} + + +/* + * In order to set the CMOS clock precisely, set_rtc_mmss has to be + * called 500 ms after the second nowtime has started, because when + * nowtime is written into the registers of the CMOS clock, it will + * jump to the next second precisely 500 ms later. Check the Motorola + * MC146818A or Dallas DS12887 data sheet for details. + * + * BUG: This routine does not handle hour overflow properly; it just + * sets the minutes. Usually you won't notice until after reboot! + */ +static int set_rtc_mmss(unsigned long nowtime) +{ + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + unsigned char save_control, save_freq_select; + + save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + cmos_minutes = CMOS_READ(RTC_MINUTES); + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - cmos_minutes) < 30) { + CMOS_WRITE(real_seconds,RTC_SECONDS); + CMOS_WRITE(real_minutes,RTC_MINUTES); + } else { + printk(KERN_WARNING + "set_rtc_mmss: can't update from %d to %d\n", + cmos_minutes, real_minutes); + retval = -1; + } + + /* The following flags have to be released exactly in this order, + * otherwise the DS12887 (popular MC146818A clone with integrated + * battery and quartz) will not reset the oscillator and will not + * update precisely 500 ms later. You won't find this mentioned in + * the Dallas Semiconductor data sheets, but who believes data + * sheets anyway ... -- Markus Kuhn + */ + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + + return retval; +} + + +/* + * There are a lot of conceptually broken versions of the MIPS timer interrupt + * handler floating around. This one is rather different, but the algorithm + * is provably more robust. + */ +void mips_timer_interrupt(struct pt_regs *regs) +{ + if (r4k_offset == 0) + goto null; + + do { + kstat.irqs[0][MIPS_CPU_TIMER_IRQ]++; + do_timer(regs); + + /* Historical comment/code: + * RTC time of day s updated approx. every 11 + * minutes. Because of how the numbers work out + * we need to make absolutely sure we do this update + * within 500ms before the * next second starts, + * thus the following code. + */ + read_lock(&xtime_lock); + if ((time_status & STA_UNSYNC) == 0 + && xtime.tv_sec > last_rtc_update + 660 + && xtime.tv_usec >= 500000 - (tick >> 1) + && xtime.tv_usec <= 500000 + (tick >> 1)) + if (set_rtc_mmss(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else { + /* do it again in 60 s */ + last_rtc_update = xtime.tv_sec - 600; + } + read_unlock(&xtime_lock); + + r4k_cur += r4k_offset; + ack_r4ktimer(r4k_cur); + + } while (((unsigned long)read_32bit_cp0_register(CP0_COUNT) + - r4k_cur) < 0x7fffffff); + + return; + +null: + ack_r4ktimer(0); +} + +/* + * Figure out the r4k offset, the amount to increment the compare + * register for each time tick. + * Use the RTC to calculate offset. + */ +static unsigned long __init cal_r4koff(void) +{ + unsigned long count; + unsigned int flags; + + __save_and_cli(flags); + + /* Start counter exactly on falling edge of update flag */ + while (CMOS_READ(RTC_REG_A) & RTC_UIP); + while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); + + /* Start r4k counter. */ + write_32bit_cp0_register(CP0_COUNT, 0); + + /* Read counter exactly on falling edge of update flag */ + while (CMOS_READ(RTC_REG_A) & RTC_UIP); + while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); + + count = read_32bit_cp0_register(CP0_COUNT); + + /* restore interrupts */ + __restore_flags(flags); + + return (count / HZ); +} + +static unsigned long __init get_mips_time(void) +{ + unsigned int year, mon, day, hour, min, sec; + unsigned char save_control; + + save_control = CMOS_READ(RTC_CONTROL); + + /* Freeze it. */ + CMOS_WRITE(save_control | RTC_SET, RTC_CONTROL); + + /* Read regs. */ + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + + if (!(save_control & RTC_24H)) + { + if ((hour & 0xf) == 0xc) + hour &= 0x80; + if (hour & 0x80) + hour = (hour & 0xf) + 12; + } + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR); + + /* Unfreeze clock. */ + CMOS_WRITE(save_control, RTC_CONTROL); + + if ((year += 1900) < 1970) + year += 100; + + return mktime(year, mon, day, hour, min, sec); +} + +void __init time_init(void) +{ + unsigned int est_freq, flags; + + /* Set Data mode - binary. */ + CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL); + + printk("calculating r4koff... "); + r4k_offset = cal_r4koff(); + printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset); + + est_freq = 2*r4k_offset*HZ; + est_freq += 5000; /* round */ + est_freq -= est_freq%10000; + printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, + (est_freq%1000000)*100/1000000); + r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset); + + write_32bit_cp0_register(CP0_COMPARE, r4k_cur); + + enable_cpu_timer(); + + /* Read time from the RTC chipset. */ + write_lock_irqsave (&xtime_lock, flags); + xtime.tv_sec = get_mips_time(); + xtime.tv_usec = 0; + write_unlock_irqrestore(&xtime_lock, flags); +} + +/* This is for machines which generate the exact clock. */ +#define USECS_PER_JIFFY (1000000/HZ) + +/* Cycle counter value at the previous timer interrupt.. */ + +static unsigned int timerhi = 0, timerlo = 0; + +/* + * FIXME: Does playing with the RP bit in c0_status interfere with this code? + */ +static unsigned long do_fast_gettimeoffset(void) +{ + u32 count; + unsigned long res, tmp; + + /* Last jiffy when do_fast_gettimeoffset() was called. */ + static unsigned long last_jiffies=0; + unsigned long quotient; + + /* + * Cached "1/(clocks per usec)*2^32" value. + * It has to be recalculated once each jiffy. + */ + static unsigned long cached_quotient=0; + + tmp = jiffies; + + quotient = cached_quotient; + + if (tmp && last_jiffies != tmp) { + last_jiffies = tmp; + __asm__(".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "lwu\t%0,%2\n\t" + "dsll32\t$1,%1,0\n\t" + "or\t$1,$1,%0\n\t" + "ddivu\t$0,$1,%3\n\t" + "mflo\t$1\n\t" + "dsll32\t%0,%4,0\n\t" + "nop\n\t" + "ddivu\t$0,%0,$1\n\t" + "mflo\t%0\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=&r" (quotient) + :"r" (timerhi), + "m" (timerlo), + "r" (tmp), + "r" (USECS_PER_JIFFY) + :"$1"); + cached_quotient = quotient; + } + + /* Get last timer tick in absolute kernel time */ + count = read_32bit_cp0_register(CP0_COUNT); + + /* .. relative to previous jiffy (32 bits is enough) */ + count -= timerlo; + + __asm__("multu\t%1,%2\n\t" + "mfhi\t%0" + :"=r" (res) + :"r" (count), + "r" (quotient)); + + /* + * Due to possible jiffies inconsistencies, we need to check + * the result so that we'll get a timer that is monotonic. + */ + if (res >= USECS_PER_JIFFY) + res = USECS_PER_JIFFY-1; + + return res; +} + +void do_gettimeofday(struct timeval *tv) +{ + unsigned int flags; + + read_lock_irqsave (&xtime_lock, flags); + *tv = xtime; + tv->tv_usec += do_fast_gettimeoffset(); + + /* + * xtime is atomically updated in timer_bh. jiffies - wall_jiffies + * is nonzero if the timer bottom half hasnt executed yet. + */ + if (jiffies - wall_jiffies) + tv->tv_usec += USECS_PER_JIFFY; + + read_unlock_irqrestore (&xtime_lock, flags); + + if (tv->tv_usec >= 1000000) { + tv->tv_usec -= 1000000; + tv->tv_sec++; + } +} + +void do_settimeofday(struct timeval *tv) +{ + write_lock_irq (&xtime_lock); + + /* This is revolting. We need to set the xtime.tv_usec correctly. + * However, the value in this location is is value at the last tick. + * Discover what correction gettimeofday would have done, and then + * undo it! + */ + tv->tv_usec -= do_fast_gettimeoffset(); + + if (tv->tv_usec < 0) { + tv->tv_usec += 1000000; + tv->tv_sec--; + } + + xtime = *tv; + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + + write_unlock_irq (&xtime_lock); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/qed-4n-s01b/Makefile linux.ac/arch/mips/ite-boards/qed-4n-s01b/Makefile --- linux.vanilla/arch/mips/ite-boards/qed-4n-s01b/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/qed-4n-s01b/Makefile Tue Apr 3 17:54:32 2001 @@ -0,0 +1,37 @@ +# +# Copyright 2000 MontaVista Software Inc. +# Author: MontaVista Software, Inc. +# ppopov@mvista.com or support@mvista.com +# +# Makefile for the ITE 8172 (qed-4n-s01b) board, board +# specific files. +# +# 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). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: ite.o + +O_TARGET := ite.o + +obj-y := init.o + +ifdef CONFIG_PCI +obj-y += pci_fixup.o +endif + +ifdef CONFIG_BLK_DEV_INITRD +obj-y += le_ramdisk.o +endif + + +dep: + $(CPP) -M *.c > .depend + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/qed-4n-s01b/README linux.ac/arch/mips/ite-boards/qed-4n-s01b/README --- linux.vanilla/arch/mips/ite-boards/qed-4n-s01b/README Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/qed-4n-s01b/README Tue Apr 3 17:54:32 2001 @@ -0,0 +1,2 @@ +This is an ITE (www.iteusa.com) eval board for the ITE 8172G +system controller, with a QED 5231 CPU. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/qed-4n-s01b/init.c linux.ac/arch/mips/ite-boards/qed-4n-s01b/init.c --- linux.vanilla/arch/mips/ite-boards/qed-4n-s01b/init.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/qed-4n-s01b/init.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,87 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * IT8172/QED5231 board setup. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.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. + * + * 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. + * + * 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 <linux/init.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/bootmem.h> +#include <asm/addrspace.h> +#include <asm/bootinfo.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <asm/it8172/it8172.h> +#include <asm/it8172/it8172_dbg.h> + +int prom_argc; +char **prom_argv, **prom_envp; + +extern char _end; +extern void __init prom_init_cmdline(void); +extern unsigned long __init prom_get_memsize(void); +extern void __init it8172_init_ram_resource(unsigned long memsize); + +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) +#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) + + +int __init prom_init(int argc, char **argv, char **envp, int *prom_vec) +{ + unsigned long mem_size, free_start, free_end, bootmap_size; + unsigned long pcicr; + + prom_argc = argc; + prom_argv = argv; + prom_envp = envp; + + puts("ITE board running..."); + + mips_machgroup = MACH_GROUP_ITE; + mips_machtype = MACH_QED_4N_S01B; /* ITE board name/number */ + + prom_init_cmdline(); + mem_size = prom_get_memsize(); + + printk("Memory size: %dMB\n", (unsigned)mem_size); + + mem_size <<= 20; /* MB */ + + /* + * make the entire physical memory visible to pci bus masters + */ + IT_READ(IT_MC_PCICR, pcicr); + pcicr &= ~0x1f; + pcicr |= (mem_size - 1) >> 22; + IT_WRITE(IT_MC_PCICR, pcicr); + + it8172_init_ram_resource(mem_size); + add_memory_region(0, 20 << 20, BOOT_MEM_RAM); + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/qed-4n-s01b/pci_fixup.c linux.ac/arch/mips/ite-boards/qed-4n-s01b/pci_fixup.c --- linux.vanilla/arch/mips/ite-boards/qed-4n-s01b/pci_fixup.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/qed-4n-s01b/pci_fixup.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,197 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Board specific pci fixups. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.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. + * + * 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. + * + * 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 <linux/config.h> + +#ifdef CONFIG_PCI + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> + +#include <asm/it8172/it8172.h> +#include <asm/it8172/it8172_pci.h> +#include <asm/it8172/it8172_int.h> + +void __init board_int_line_fixup(struct pci_dev *dev) +{ + unsigned int slot, func; + unsigned char pin; + const int internal_func_irqs[7] = { + IT8172_AC97_IRQ, + IT8172_DMA_IRQ, + IT8172_CDMA_IRQ, + IT8172_USB_IRQ, + IT8172_BRIDGE_MASTER_IRQ, + IT8172_IDE_IRQ, + IT8172_MC68K_IRQ + }; + +#ifdef DEBUG + printk("board_int_line_fixup bus %d\n", dev->bus->number); +#endif + if (dev->bus->number != 0) + return; + + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + +#ifdef DEBUG + pci_read_config_dword(dev, PCI_SUBSYSTEM_VENDOR_ID, &vendor); +#endif + + slot = PCI_SLOT(dev->devfn); + func = PCI_FUNC(dev->devfn); + + switch (slot) { + case 0x01: + /* + * Internal device 1 is actually 7 different internal + * devices on the IT8172G (a multi-function device). + */ + if (func < 7) + dev->irq = internal_func_irqs[func]; + break; + case 0x10: + switch (pin) { + case 1: /* pin A */ + dev->irq = IT8172_PCI_INTA_IRQ; + break; + case 2: /* pin B */ + dev->irq = IT8172_PCI_INTB_IRQ; + break; + case 3: /* pin C */ + dev->irq = IT8172_PCI_INTC_IRQ; + break; + case 4: /* pin D */ + dev->irq = IT8172_PCI_INTD_IRQ; + break; + default: + dev->irq = 0xff; + break; + + } + break; + case 0x11: + switch (pin) { + case 1: /* pin A */ + dev->irq = IT8172_PCI_INTA_IRQ; + break; + case 2: /* pin B */ + dev->irq = IT8172_PCI_INTB_IRQ; + break; + case 3: /* pin C */ + dev->irq = IT8172_PCI_INTC_IRQ; + break; + case 4: /* pin D */ + dev->irq = IT8172_PCI_INTD_IRQ; + break; + default: + dev->irq = 0xff; + break; + + } + break; + case 0x12: + switch (pin) { + case 1: /* pin A */ + dev->irq = IT8172_PCI_INTB_IRQ; + break; + case 2: /* pin B */ + dev->irq = IT8172_PCI_INTC_IRQ; + break; + case 3: /* pin C */ + dev->irq = IT8172_PCI_INTD_IRQ; + break; + case 4: /* pin D */ + dev->irq = IT8172_PCI_INTA_IRQ; + break; + default: + dev->irq = 0xff; + break; + + } + break; + case 0x13: + switch (pin) { + case 1: /* pin A */ + dev->irq = IT8172_PCI_INTC_IRQ; + break; + case 2: /* pin B */ + dev->irq = IT8172_PCI_INTD_IRQ; + break; + case 3: /* pin C */ + dev->irq = IT8172_PCI_INTA_IRQ; + break; + case 4: /* pin D */ + dev->irq = IT8172_PCI_INTB_IRQ; + break; + default: + dev->irq = 0xff; + break; + + } + break; + case 0x14: + switch (pin) { + case 1: /* pin A */ + dev->irq = IT8172_PCI_INTD_IRQ; + break; + case 2: /* pin B */ + dev->irq = IT8172_PCI_INTA_IRQ; + break; + case 3: /* pin C */ + dev->irq = IT8172_PCI_INTB_IRQ; + break; + case 4: /* pin D */ + dev->irq = IT8172_PCI_INTC_IRQ; + break; + default: + dev->irq = 0xff; + break; + + } + break; + default: + return; + } + +#ifdef DEBUG + printk("irq fixup: slot %d, vendor %x, int line %d, int number %d\n", + slot, vendor, pin, dev->irq); +#endif + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + +} + +struct pci_fixup pcibios_fixups[] = { + { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, board_int_line_fixup }, + { 0 } +}; +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/jazz/Makefile linux.ac/arch/mips/jazz/Makefile --- linux.vanilla/arch/mips/jazz/Makefile Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/jazz/Makefile Tue Apr 3 17:54:32 2001 @@ -1,4 +1,3 @@ -# $Id: Makefile,v 1.5 1999/01/03 17:50:47 ralf Exp $ # # Makefile for the Jazz family specific parts of the kernel # @@ -8,17 +7,17 @@ # .S.s: - $(CPP) $(CFLAGS) $< -o $*.s + $(CPP) $(CFLAGS) $< -o $@ .S.o: - $(CC) $(CFLAGS) -c $< -o $*.o + $(CC) $(CFLAGS) -c $< -o $@ all: jazz.o + O_TARGET := jazz.o -O_OBJS := int-handler.o jazzdma.o reset.o rtc-jazz.o setup.o floppy-jazz.o \ - kbd-jazz.o -int-handler.o: int-handler.S +obj-y := int-handler.o irq.o jazzdma.o reset.o rtc-jazz.o setup.o \ + floppy-jazz.o kbd-jazz.o -clean: +int-handler.o: int-handler.S include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/branch.c linux.ac/arch/mips/kernel/branch.c --- linux.vanilla/arch/mips/kernel/branch.c Wed Dec 10 18:31:09 1997 +++ linux.ac/arch/mips/kernel/branch.c Tue Apr 3 17:54:32 2001 @@ -5,15 +5,19 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1996, 1997 by Ralf Baechle + * Copyright (C) 1996, 97, 2000 by Ralf Baechle */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/signal.h> #include <asm/branch.h> +#include <asm/cpu.h> #include <asm/inst.h> #include <asm/ptrace.h> #include <asm/uaccess.h> +#include <asm/bootinfo.h> +#include <asm/processor.h> /* * Compute the return address and do emulate branch simulation, if required. @@ -65,7 +69,7 @@ switch (insn.i_format.rt) { case bltz_op: case bltzl_op: - if (regs->regs[insn.i_format.rs] < 0) + if ((long)regs->regs[insn.i_format.rs] < 0) epc = epc + 4 + (insn.i_format.simmediate << 2); else epc += 8; @@ -74,7 +78,7 @@ case bgez_op: case bgezl_op: - if (regs->regs[insn.i_format.rs] >= 0) + if ((long)regs->regs[insn.i_format.rs] >= 0) epc = epc + 4 + (insn.i_format.simmediate << 2); else epc += 8; @@ -84,7 +88,7 @@ case bltzal_op: case bltzall_op: regs->regs[31] = epc + 8; - if (regs->regs[insn.i_format.rs] < 0) + if ((long)regs->regs[insn.i_format.rs] < 0) epc = epc + 4 + (insn.i_format.simmediate << 2); else epc += 8; @@ -94,7 +98,7 @@ case bgezal_op: case bgezall_op: regs->regs[31] = epc + 8; - if (regs->regs[insn.i_format.rs] >= 0) + if ((long)regs->regs[insn.i_format.rs] >= 0) epc = epc + 4 + (insn.i_format.simmediate << 2); else epc += 8; @@ -142,7 +146,7 @@ case blez_op: /* not really i_format */ case blezl_op: /* rt field assumed to be zero */ - if (regs->regs[insn.i_format.rs] <= 0) + if ((long)regs->regs[insn.i_format.rs] <= 0) epc = epc + 4 + (insn.i_format.simmediate << 2); else epc += 8; @@ -152,7 +156,7 @@ case bgtz_op: case bgtzl_op: /* rt field assumed to be zero */ - if (regs->regs[insn.i_format.rs] > 0) + if ((long)regs->regs[insn.i_format.rs] > 0) epc = epc + 4 + (insn.i_format.simmediate << 2); else epc += 8; @@ -163,6 +167,11 @@ * And now the FPA/cp1 branch instructions. */ case cop1_op: +#ifdef CONFIG_MIPS_FPU_EMULATOR + if(!(mips_cpu.options & MIPS_CPU_FPU)) + fcr31 = current->thread.fpu.soft.sr; + else +#endif asm ("cfc1\t%0,$31":"=r" (fcr31)); bit = (insn.i_format.rt >> 2); bit += (bit != 0); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/process.c linux.ac/arch/mips/kernel/process.c --- linux.vanilla/arch/mips/kernel/process.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/mips/kernel/process.c Mon Apr 16 12:37:03 2001 @@ -1,12 +1,12 @@ -/* $Id: process.c,v 1.18 2000/01/29 01:41:59 ralf Exp $ - * +/* * 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) 1994 - 1999 by Ralf Baechle and others. + * Copyright (C) 1994 - 2000 by Ralf Baechle and others. * Copyright (C) 1999 Silicon Graphics, Inc. */ +#include <linux/config.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -21,6 +21,7 @@ #include <linux/a.out.h> #include <asm/bootinfo.h> +#include <asm/cpu.h> #include <asm/pgtable.h> #include <asm/system.h> #include <asm/mipsregs.h> @@ -55,7 +56,7 @@ { /* Forget lazy fpu state */ if (last_task_used_math == current) { - set_cp0_status(ST0_CU1, ST0_CU1); + set_cp0_status(ST0_CU1); __asm__ __volatile__("cfc1\t$0,$31"); last_task_used_math = NULL; } @@ -65,7 +66,7 @@ { /* Forget lazy fpu state */ if (last_task_used_math == current) { - set_cp0_status(ST0_CU1, ST0_CU1); + set_cp0_status(ST0_CU1); __asm__ __volatile__("cfc1\t$0,$31"); last_task_used_math = NULL; } @@ -81,9 +82,13 @@ childksp = (unsigned long)p + KERNEL_STACK_SIZE - 32; - if (last_task_used_math == current) { - set_cp0_status(ST0_CU1, ST0_CU1); - save_fp(p); + if (last_task_used_math == current) +#ifdef CONFIG_MIPS_FPU_EMULATOR + if (mips_cpu.options & MIPS_CPU_FPU) +#endif + { + set_cp0_status(ST0_CU1); + save_fp(p); } /* set up new TSS. */ childregs = (struct pt_regs *) childksp - 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/ptrace.c linux.ac/arch/mips/kernel/ptrace.c --- linux.vanilla/arch/mips/kernel/ptrace.c Mon Jul 10 06:18:15 2000 +++ linux.ac/arch/mips/kernel/ptrace.c Tue Apr 3 17:54:32 2001 @@ -1,14 +1,16 @@ -/* $Id: ptrace.c,v 1.17 1999/09/28 22:25:47 ralf Exp $ - * +/* * 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) 1992 Ross Biro * Copyright (C) Linus Torvalds - * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle + * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle * Copyright (C) 1996 David S. Miller + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999 MIPS Technologies, Inc. */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> @@ -24,6 +26,8 @@ #include <asm/page.h> #include <asm/system.h> #include <asm/uaccess.h> +#include <asm/bootinfo.h> +#include <asm/cpu.h> asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { @@ -131,13 +135,22 @@ break; case FPR_BASE ... FPR_BASE + 31: if (child->used_math) { + unsigned long long *fregs + = (unsigned long long *) + &child->thread.fpu.hard.fp_regs[0]; +#ifdef CONFIG_MIPS_FPU_EMULATOR + if(!(mips_cpu.options & MIPS_CPU_FPU)) { + fregs = (unsigned long long *) + &child->thread.fpu.soft.regs[0]; + } else +#endif if (last_task_used_math == child) { enable_cp1(); save_fp(child); disable_cp1(); last_task_used_math = NULL; } - tmp = child->thread.fpu.hard.fp_regs[addr - 32]; + tmp = (unsigned long) fregs[(addr - 32)]; } else { tmp = -1; /* FP not yet used */ } @@ -158,6 +171,11 @@ tmp = regs->lo; break; case FPC_CSR: +#ifdef CONFIG_MIPS_FPU_EMULATOR + if(!(mips_cpu.options & MIPS_CPU_FPU)) + tmp = child->thread.fpu.soft.sr; + else +#endif tmp = child->thread.fpu.hard.control; break; case FPC_EIR: { /* implementation / version register */ @@ -198,9 +216,17 @@ regs->regs[addr] = data; break; case FPR_BASE ... FPR_BASE + 31: { - unsigned int *fregs; + unsigned long long *fregs; + fregs = (unsigned long long *)&child->thread.fpu.hard.fp_regs[0]; if (child->used_math) { - if (last_task_used_math == child) { + if (last_task_used_math == child) +#ifdef CONFIG_MIPS_FPU_EMULATOR + if(!(mips_cpu.options & MIPS_CPU_FPU)) { + fregs = (unsigned long long *) + &child->thread.fpu.soft.regs[0]; + } else +#endif + { enable_cp1(); save_fp(child); disable_cp1(); @@ -213,7 +239,6 @@ sizeof(child->thread.fpu.hard)); child->thread.fpu.hard.control = 0; } - fregs = child->thread.fpu.hard.fp_regs; fregs[addr - FPR_BASE] = data; break; } @@ -227,6 +252,11 @@ regs->lo = data; break; case FPC_CSR: +#ifdef CONFIG_MIPS_FPU_EMULATOR + if(!(mips_cpu.options & MIPS_CPU_FPU)) + child->thread.fpu.soft.sr = data; + else +#endif child->thread.fpu.hard.control = data; break; default: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/r2300_fpu.S linux.ac/arch/mips/kernel/r2300_fpu.S --- linux.vanilla/arch/mips/kernel/r2300_fpu.S Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/kernel/r2300_fpu.S Tue Apr 3 17:54:32 2001 @@ -1,7 +1,4 @@ -/* $Id: r2300_fpu.S,v 1.6 1999/08/09 19:43:14 harald Exp $ - * - * r2300_fpu.S: Save/restore floating point context for signal handlers. - * +/* * 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. @@ -30,7 +27,7 @@ .set noreorder .set mips1 /* Save floating point context */ -LEAF(save_fp_context) +LEAF(_save_fp_context) li v0, 0 # assume success cfc1 t1,fcr31 EX(swc1 $f0,(SC_FPREGS+0)(a0)) @@ -65,13 +62,13 @@ EX(swc1 $f29,(SC_FPREGS+232)(a0)) EX(swc1 $f30,(SC_FPREGS+240)(a0)) EX(swc1 $f31,(SC_FPREGS+248)(a0)) - EX(sw t1,SC_FPC_CSR(a0)) + EX(sw t1,(SC_FPC_CSR)(a0)) cfc1 t0,$0 # implementation/version jr ra .set nomacro - EX(sw t0,SC_FPC_EIR(a0)) + EX(sw t0,(SC_FPC_EIR)(a0)) .set macro - END(save_fp_context) + END(_save_fp_context) /* * Restore FPU state: @@ -82,9 +79,9 @@ * frame on the current content of c0_status, not on the content of the * stack frame which might have been changed by the user. */ -LEAF(restore_fp_context) +LEAF(_restore_fp_context) li v0, 0 # assume success - EX(lw t0,SC_FPC_CSR(a0)) + EX(lw t0,(SC_FPC_CSR)(a0)) EX(lwc1 $f0,(SC_FPREGS+0)(a0)) EX(lwc1 $f1,(SC_FPREGS+8)(a0)) EX(lwc1 $f2,(SC_FPREGS+16)(a0)) @@ -119,7 +116,7 @@ EX(lwc1 $f31,(SC_FPREGS+248)(a0)) jr ra ctc1 t0,fcr31 - END(restore_fp_context) + END(_restore_fp_context) .type fault@function .ent fault diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/r2300_switch.S linux.ac/arch/mips/kernel/r2300_switch.S --- linux.vanilla/arch/mips/kernel/r2300_switch.S Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/kernel/r2300_switch.S Tue Apr 3 17:54:32 2001 @@ -9,7 +9,7 @@ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * * Further modifications to make this work: - * Copyright (c) 1998 Harald Koerfgen + * Copyright (c) 1998-2000 Harald Koerfgen */ #include <asm/asm.h> #include <asm/bootinfo.h> @@ -30,13 +30,11 @@ .align 5 /* - * task_struct *r4xx0_resume(task_struct *prev, - * task_struct *next) + * task_struct *resume(task_struct *prev, + * task_struct *next) */ LEAF(resume) - .set reorder mfc0 t1, CP0_STATUS - .set noreorder sw t1, THREAD_STATUS(a0) CPU_SAVE_NONSCRATCH(a0) sw ra, THREAD_REG31(a0) @@ -57,8 +55,10 @@ and a2, a3 or a2, t1 mtc0 a2, CP0_STATUS + .set noreorder jr ra move v0, a0 + .set reorder END(resume) /* @@ -74,19 +74,16 @@ or t0, t3 mtc0 t0, CP0_STATUS + .set noreorder beqz a0, 2f # Save floating point state nor t3, zero, t3 .set reorder lw t1, ST_OFF(a0) # last thread looses fpu - .set noreorder and t1, t3 sw t1, ST_OFF(a0) - swc1 $f0, (THREAD_FPU + 0x00)(a0) FPU_SAVE_SINGLE(a0, t1) # clobbers t1 2: - lwc1 $f0, (THREAD_FPU + 0x00)($28) - .set reorder FPU_RESTORE_SINGLE($28, t0) # clobbers t0 jr ra END(lazy_fpu_switch) @@ -94,14 +91,20 @@ /* * Save a thread's fp context. */ - .set noreorder LEAF(save_fp) FPU_SAVE_SINGLE(a0, t1) # clobbers t1 jr ra - swc1 $f0, (THREAD_FPU + 0x00)(a0) END(save_fp) /* + * Restore a thread's fp context. + */ +LEAF(restore_fp) + FPU_RESTORE_SINGLE(a0, t1) # clobbers t1 + jr ra + END(restore_fp) + +/* * Load the FPU with signalling NANS. This bit pattern we're using has * the property that no matter wether considered as single or as double * precission represents signaling NANS. @@ -153,6 +156,8 @@ mtc1 t0, $f28 mtc1 t0, $f29 mtc1 t0, $f30 + .set noreorder jr ra mtc1 t0, $f31 + .set reorder END(init_fpu) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/r4k_fpu.S linux.ac/arch/mips/kernel/r4k_fpu.S --- linux.vanilla/arch/mips/kernel/r4k_fpu.S Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/kernel/r4k_fpu.S Tue Apr 3 17:54:32 2001 @@ -1,15 +1,15 @@ -/* $Id: r4k_fpu.S,v 1.8 1999/09/28 22:25:47 ralf Exp $ - * - * r4k_fpu.S: Save/restore floating point context for signal handlers. - * +/* * 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) 1996, 1998 by Ralf Baechle + * Copyright (C) 1996, 1998, 2000 by Ralf Baechle * * Multi-arch abstraction and asm macros for easier reading: * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. */ #include <asm/asm.h> #include <asm/errno.h> @@ -19,7 +19,7 @@ #include <asm/regdef.h> #define EX(a,b) \ -9: a,##b; \ +9: a,b; \ .section __ex_table,"a"; \ PTR 9b, fault; \ .previous @@ -27,7 +27,7 @@ .set noreorder .set mips3 /* Save floating point context */ -LEAF(save_fp_context) +LEAF(_save_fp_context) li v0, 0 # assume success cfc1 t1,fcr31 @@ -55,7 +55,7 @@ .set nomacro EX(sw t0,SC_FPC_EIR(a0)) .set macro - END(save_fp_context) + END(_save_fp_context) /* * Restore FPU state: @@ -66,7 +66,7 @@ * frame on the current content of c0_status, not on the content of the * stack frame which might have been changed by the user. */ -LEAF(restore_fp_context) +LEAF(_restore_fp_context) li v0, 0 # assume success EX(lw t0,SC_FPC_CSR(a0)) @@ -92,7 +92,7 @@ EX(ldc1 $f30,(SC_FPREGS+240)(a0)) jr ra ctc1 t0,fcr31 - END(restore_fp_context) + END(_restore_fp_context) .type fault@function .ent fault diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/r4k_misc.S linux.ac/arch/mips/kernel/r4k_misc.S --- linux.vanilla/arch/mips/kernel/r4k_misc.S Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/kernel/r4k_misc.S Tue Apr 3 17:54:32 2001 @@ -7,6 +7,13 @@ * Multi-cpu abstraction and reworking: * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) */ +/************************************************************************** + * 14 Nov, 2000. + * Made support for MIPS32 CPUs. + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + *************************************************************************/ #include <asm/asm.h> #include <asm/current.h> #include <asm/offset.h> @@ -102,7 +109,6 @@ sw pte, (ptr); .set noreorder - .set mips3 /* * From the IDT errata for the QED RM5230 (Nevada), processor revision 1.0: @@ -147,7 +153,9 @@ tlbwi 1: nop + .set mips3 eret + .set mips0 #endif nopage_tlbl: @@ -169,7 +177,9 @@ tlbwi 1: nop + .set mips3 eret + .set mips0 #endif nopage_tlbs: @@ -201,7 +211,9 @@ tlbwi 1: nop + .set mips3 eret + .set mips0 #endif nowrite_mod: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/r4k_switch.S linux.ac/arch/mips/kernel/r4k_switch.S --- linux.vanilla/arch/mips/kernel/r4k_switch.S Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/kernel/r4k_switch.S Tue Apr 3 17:54:32 2001 @@ -9,6 +9,14 @@ * Copyright (C) 1994, 1995, 1996, by Andreas Busse * Copyright (C) 1999 Silicon Graphics, Inc. */ +/************************************************************************** + * 13 Nov, 2000. + * Made support for MIPS32 CPUs and restoring of fp registers. + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + *************************************************************************/ + #include <asm/asm.h> #include <asm/bootinfo.h> #include <asm/cachectl.h> @@ -24,8 +32,6 @@ #include <asm/asmmacro.h> - .set mips3 - /* * task_struct *r4xx0_resume(task_struct *prev, task_struct *next) */ @@ -95,6 +101,14 @@ END(save_fp) /* + * Restore a thread's fp context. + */ +LEAF(restore_fp) + FPU_RESTORE_DOUBLE(a0, t1) # clobbers t1 + jr ra + END(restore_fp) + +/* * Load the FPU with signalling NANS. This bit pattern we're using has * the property that no matter whether considered as single or as double * precision represents signaling NANS. @@ -105,6 +119,7 @@ #define FPU_DEFAULT 0x00000000 LEAF(init_fpu) + .set mips3 mfc0 t0, CP0_STATUS li t1, 0x20000000 or t0, t1 @@ -135,3 +150,4 @@ dmtc1 t0, $f30 .set reorder END(init_fpu) + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/r6000_fpu.S linux.ac/arch/mips/kernel/r6000_fpu.S --- linux.vanilla/arch/mips/kernel/r6000_fpu.S Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/kernel/r6000_fpu.S Tue Apr 3 17:54:32 2001 @@ -9,8 +9,6 @@ * * Multi-arch abstraction and asm macros for easier reading: * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: r6000_fpu.S,v 1.5 1999/05/01 22:40:37 ralf Exp $ */ #include <asm/asm.h> #include <asm/fpregdef.h> @@ -21,7 +19,7 @@ .set noreorder .set mips2 /* Save floating point context */ - LEAF(save_fp_context) + LEAF(_save_fp_context) mfc0 t0,CP0_STATUS sll t0,t0,2 bgez t0,1f @@ -49,7 +47,7 @@ sw t0,SC_FPC_CSR(a0) 1: jr ra nop - END(save_fp_context) + END(_save_fp_context) /* Restore FPU state: * - fp gp registers @@ -59,7 +57,7 @@ * frame on the current content of c0_status, not on the content of the * stack frame which might have been changed by the user. */ - LEAF(restore_fp_context) + LEAF(_restore_fp_context) mfc0 t0,CP0_STATUS sll t0,t0,2 @@ -86,4 +84,4 @@ ctc1 t0,fcr31 1: jr ra nop - END(restore_fp_context) + END(_restore_fp_context) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/setup.c linux.ac/arch/mips/kernel/setup.c --- linux.vanilla/arch/mips/kernel/setup.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/mips/kernel/setup.c Tue Apr 3 17:54:32 2001 @@ -4,8 +4,9 @@ * for more details. * * Copyright (C) 1995 Linus Torvalds - * Copyright (C) 1995, 1996, 1997, 1998 Ralf Baechle + * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000 Ralf Baechle * Copyright (C) 1996 Stoned Elipot + * Copyright (C) 2000 Maciej W. Rozycki */ #include <linux/config.h> #include <linux/errno.h> @@ -36,10 +37,10 @@ #include <asm/asm.h> #include <asm/bootinfo.h> #include <asm/cachectl.h> +#include <asm/cpu.h> #include <asm/io.h> #include <asm/stackframe.h> #include <asm/system.h> -#include <asm/cpu.h> #ifdef CONFIG_SGI_IP22 #include <asm/sgialib.h> #endif @@ -152,64 +153,171 @@ #endif } +/* declaration of the global struct */ +struct mips_cpu mips_cpu = {PRID_IMP_UNKNOWN, CPU_UNKNOWN, 0, 0, 0, + {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}}; + +/* Shortcut for assembler access to mips_cpu.options */ +int *cpuoptions = &mips_cpu.options; + +#define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4KTLB \ + | MIPS_CPU_COUNTER | MIPS_CPU_CACHE_CDEX) + static inline void cpu_probe(void) { - unsigned int prid = read_32bit_cp0_register(CP0_PRID); - switch(prid & 0xff00) { + unsigned long config1; + + mips_cpu.processor_id = read_32bit_cp0_register(CP0_PRID); + switch (mips_cpu.processor_id & 0xff00) { case PRID_IMP_R2000: - mips_cputype = CPU_R2000; + mips_cpu.cputype = CPU_R2000; + mips_cpu.isa_level = MIPS_CPU_ISA_I; + mips_cpu.options = MIPS_CPU_TLB; + mips_cpu.tlbsize = 64; break; case PRID_IMP_R3000: - if((prid & 0xff) == PRID_REV_R3000A) - if(cpu_has_confreg()) - mips_cputype = CPU_R3081E; + if ((mips_cpu.processor_id & 0xff) == PRID_REV_R3000A) + if (cpu_has_confreg()) + mips_cpu.cputype = CPU_R3081E; else - mips_cputype = CPU_R3000A; + mips_cpu.cputype = CPU_R3000A; else - mips_cputype = CPU_R3000; + mips_cpu.cputype = CPU_R3000; + mips_cpu.isa_level = MIPS_CPU_ISA_I; + mips_cpu.options = MIPS_CPU_TLB; + mips_cpu.tlbsize = 64; break; case PRID_IMP_R4000: - if((prid & 0xff) == PRID_REV_R4400) - mips_cputype = CPU_R4400SC; + if ((mips_cpu.processor_id & 0xff) == PRID_REV_R4400) + mips_cpu.cputype = CPU_R4400SC; else - mips_cputype = CPU_R4000SC; + mips_cpu.cputype = CPU_R4000SC; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | + MIPS_CPU_WATCH | MIPS_CPU_VCE; + mips_cpu.tlbsize = 48; break; case PRID_IMP_R4600: - mips_cputype = CPU_R4600; + mips_cpu.cputype = CPU_R4600; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU; + mips_cpu.tlbsize = 48; break; +/* + * This processor doesn't have an MMU, so it's not "real easy" to + * run Linux on it. It is left purely for documentation. + * case PRID_IMP_R4650: - mips_cputype = CPU_R4650; + mips_cpu.cputype = CPU_R4650; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU; + mips_cpu.tlbsize = 48; + break; + */ + case PRID_IMP_R3912: + mips_cpu.cputype = CPU_R3912; + mips_cpu.isa_level = MIPS_CPU_ISA_I; + mips_cpu.options = MIPS_CPU_TLB; + mips_cpu.tlbsize = 32; break; case PRID_IMP_R4700: - mips_cputype = CPU_R4700; + mips_cpu.cputype = CPU_R4700; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; + mips_cpu.tlbsize = 48; break; case PRID_IMP_R5000: - mips_cputype = CPU_R5000; + mips_cpu.cputype = CPU_R5000; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; + mips_cpu.tlbsize = 48; + break; + case PRID_IMP_R5432: + mips_cpu.cputype = CPU_R5432; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; + mips_cpu.tlbsize = 48; break; case PRID_IMP_NEVADA: - mips_cputype = CPU_NEVADA; + mips_cpu.cputype = CPU_NEVADA; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | + MIPS_CPU_DIVEC; + mips_cpu.tlbsize = 48; + mips_cpu.icache.ways = 2; + mips_cpu.dcache.ways = 2; break; case PRID_IMP_R6000: - mips_cputype = CPU_R6000; + mips_cpu.cputype = CPU_R6000; + mips_cpu.isa_level = MIPS_CPU_ISA_II; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU; + mips_cpu.tlbsize = 32; break; case PRID_IMP_R6000A: - mips_cputype = CPU_R6000A; + mips_cpu.cputype = CPU_R6000A; + mips_cpu.isa_level = MIPS_CPU_ISA_II; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU; + mips_cpu.tlbsize = 32; + break; + case PRID_IMP_RM7000: + mips_cpu.cputype = CPU_RM7000; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; break; case PRID_IMP_R8000: - mips_cputype = CPU_R8000; + mips_cpu.cputype = CPU_R8000; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_FPU | MIPS_CPU_32FPR; + mips_cpu.tlbsize = 384; /* has wierd TLB: 3-way x 128 */ break; case PRID_IMP_R10000: - mips_cputype = CPU_R10000; - break; - case PRID_IMP_RM7000: - mips_cputype = CPU_R5000; + mips_cpu.cputype = CPU_R10000; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_FPU | MIPS_CPU_32FPR | + MIPS_CPU_COUNTER | MIPS_CPU_WATCH; + mips_cpu.tlbsize = 64; + break; +#ifdef CONFIG_CPU_MIPS32 + case PRID_IMP_4KC: + mips_cpu.cputype = CPU_4KC; + mips_cpu.isa_level = MIPS_CPU_ISA_M32; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | + MIPS_CPU_DIVEC | MIPS_CPU_WATCH; + config1 = read_mips32_cp0_config1(); + if (config1 & (1 << 3)) + mips_cpu.options |= MIPS_CPU_WATCH; + if (config1 & (1 << 2)) + mips_cpu.options |= MIPS_CPU_MIPS16; + if (config1 & 1) + mips_cpu.options |= MIPS_CPU_FPU; + mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT; + break; + case PRID_IMP_5KC: + mips_cpu.cputype = CPU_5KC; + mips_cpu.isa_level = MIPS_CPU_ISA_M64; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | + MIPS_CPU_DIVEC | MIPS_CPU_WATCH; + config1 = read_mips32_cp0_config1(); + if (config1 & (1 << 3)) + mips_cpu.options |= MIPS_CPU_WATCH; + if (config1 & (1 << 2)) + mips_cpu.options |= MIPS_CPU_MIPS16; + if (config1 & 1) + mips_cpu.options |= MIPS_CPU_FPU; + mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT; break; +#endif default: - mips_cputype = CPU_UNKNOWN; + mips_cpu.cputype = CPU_UNKNOWN; } } -asmlinkage void __init init_arch(int argc, char **argv, char **envp, int *prom_vec) +asmlinkage void __init +init_arch(int argc, char **argv, char **envp, int *prom_vec) { unsigned int s; @@ -232,18 +340,13 @@ */ loadmmu(); - /* Disable coprocessors */ + /* Disable coprocessors and set FPU for 16 FPRs */ s = read_32bit_cp0_register(CP0_STATUS); - s &= ~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_KX|ST0_SX); + s &= ~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_KX|ST0_SX|ST0_FR); s |= ST0_CU0; write_32bit_cp0_register(CP0_STATUS, s); - /* - * Main should never return here, but - * just in case, we know what happens. - */ - for(;;) - start_kernel(); + start_kernel(); } static void __init default_irq_setup(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/signal.c linux.ac/arch/mips/kernel/signal.c --- linux.vanilla/arch/mips/kernel/signal.c Wed Jan 24 23:20:59 2001 +++ linux.ac/arch/mips/kernel/signal.c Tue Apr 3 17:54:32 2001 @@ -31,8 +31,9 @@ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) extern asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); -extern asmlinkage int save_fp_context(struct sigcontext *sc); -extern asmlinkage int restore_fp_context(struct sigcontext *sc); + +extern asmlinkage int (*save_fp_context)(struct sigcontext *sc); +extern asmlinkage int (*restore_fp_context)(struct sigcontext *sc); extern asmlinkage void syscall_trace(void); @@ -74,12 +75,12 @@ /* * Atomically swap in the new signal mask, and wait for a signal. */ -asmlinkage inline int -sys_sigsuspend(struct pt_regs regs) +save_static_function(sys_sigsuspend); +static_unused int +_sys_sigsuspend(struct pt_regs regs) { sigset_t *uset, saveset, newset; - save_static(®s); uset = (sigset_t *) regs.regs[4]; if (copy_from_user(&newset, uset, sizeof(sigset_t))) return -EFAULT; @@ -101,14 +102,14 @@ } } -asmlinkage int -sys_rt_sigsuspend(struct pt_regs regs) + +save_static_function(sys_rt_sigsuspend); +static_unused int +_sys_rt_sigsuspend(struct pt_regs regs) { sigset_t *unewset, saveset, newset; size_t sigsetsize; - save_static(®s); - /* XXX Don't preclude handling different sized sigset_t's. */ sigsetsize = regs.regs[5]; if (sigsetsize != sizeof(sigset_t)) @@ -353,7 +354,7 @@ err |= __put_user(owned_fp, &sc->sc_ownedfp); if (current->used_math) { /* fp is active. */ - set_cp0_status(ST0_CU1, ST0_CU1); + set_cp0_status(ST0_CU1); err |= save_fp_context(sc); last_task_used_math = NULL; regs->cp0_status &= ~ST0_CU1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/traps.c linux.ac/arch/mips/kernel/traps.c --- linux.vanilla/arch/mips/kernel/traps.c Mon Dec 4 01:48:19 2000 +++ linux.ac/arch/mips/kernel/traps.c Tue Apr 3 17:54:32 2001 @@ -7,6 +7,9 @@ * Modified for R3000 by Paul M. Antoine, 1995, 1996 * Complete output from die() by Ulf Carlsson, 1998 * Copyright (C) 1999 Silicon Graphics, Inc. + * + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. */ #include <linux/config.h> #include <linux/init.h> @@ -16,12 +19,15 @@ #include <linux/smp_lock.h> #include <linux/spinlock.h> +#include <asm/bootinfo.h> #include <asm/branch.h> +#include <asm/cpu.h> #include <asm/cachectl.h> +#include <asm/inst.h> #include <asm/jazz.h> #include <asm/pgtable.h> #include <asm/io.h> -#include <asm/bootinfo.h> +#include <asm/siginfo.h> #include <asm/watch.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -51,13 +57,15 @@ extern asmlinkage void handle_tr(void); extern asmlinkage void handle_fpe(void); extern asmlinkage void handle_watch(void); +extern asmlinkage void handle_mcheck(void); extern asmlinkage void handle_reserved(void); +extern int fpu_emulator_cop1Handler(int, struct pt_regs *); + static char *cpu_names[] = CPU_NAMES; char watch_available = 0; char dedicated_iv_available = 0; -char vce_available = 0; void (*ibe_board_handler)(struct pt_regs *regs); void (*dbe_board_handler)(struct pt_regs *regs); @@ -308,9 +316,11 @@ */ void do_fpe(struct pt_regs *regs, unsigned long fcr31) { - unsigned long pc; - unsigned int insn; - extern void simfp(unsigned int); + +#ifdef CONFIG_MIPS_FPU_EMULATOR + if(!(mips_cpu.options & MIPS_CPU_FPU)) + panic("Floating Point Exception with No FPU"); +#endif #ifdef CONFIG_MIPS_FPE_MODULE if (fpe_handler != NULL) { @@ -318,12 +328,52 @@ return; } #endif - if (fcr31 & 0x20000) { + + if (fcr31 & FPU_CSR_UNI_X) { +#ifdef CONFIG_MIPS_FPU_EMULATOR + extern void save_fp(struct task_struct *); + extern void restore_fp(struct task_struct *); + int sig; + /* + * Unimplemented operation exception. If we've got the + * Full software emulator on-board, let's use it... + * + * Force FPU to dump state into task/thread context. + * We're moving a lot of data here for what is probably + * a single instruction, but the alternative is to + * pre-decode the FP register operands before invoking + * the emulator, which seems a bit extreme for what + * should be an infrequent event. + */ + save_fp(current); + + /* Run the emulator */ + sig = fpu_emulator_cop1Handler(0, regs); + + /* + * We can't allow the emulated instruction to leave the + * Unimplemented Operation bit set in the FCR31 fp-register. + */ + current->thread.fpu.soft.sr &= ~FPU_CSR_UNI_X; + + /* Restore the hardware register state */ + restore_fp(current); + + /* If something went wrong, signal */ + if (sig) + force_sig(sig, current); +#else + /* Else use mini-emulator */ + + extern void simfp(int); + unsigned long pc; + unsigned int insn; + /* Retry instruction with flush to zero ... */ if (!(fcr31 & (1<<24))) { printk("Setting flush to zero for %s.\n", current->comm); - fcr31 &= ~0x20000; + fcr31 &= ~FPU_CSR_UNI_X; fcr31 |= (1<<24); __asm__ __volatile__( "ctc1\t%0,$31" @@ -332,20 +382,26 @@ return; } pc = regs->cp0_epc + ((regs->cp0_cause & CAUSEF_BD) ? 4 : 0); - if (get_user(insn, (unsigned int *)pc)) { + if(pc & 0x80000000) insn = *(unsigned int *)pc; + else if (get_user(insn, (unsigned int *)pc)) { /* XXX Can this happen? */ force_sig(SIGSEGV, current); } printk(KERN_DEBUG "Unimplemented exception for insn %08x at 0x%08lx in %s.\n", insn, regs->cp0_epc, current->comm); - simfp(insn); + simfp(MIPSInst(insn)); + compute_return_epc(regs); +#endif /* CONFIG_MIPS_FPU_EMULATOR */ + + return; } if (compute_return_epc(regs)) return; - //force_sig(SIGFPE, current); - printk(KERN_DEBUG "Should send SIGFPE to %s\n", current->comm); + + force_sig(SIGFPE, current); + printk(KERN_DEBUG "Sent send SIGFPE to %s\n", current->comm); } static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode) @@ -382,12 +438,28 @@ * (A short test says that IRIX 5.3 sends SIGTRAP for all break * insns, even for break codes that indicate arithmetic failures. * Weird ...) + * But should we continue the brokenness??? --macro */ - force_sig(SIGTRAP, current); + switch (bcode) { + case 6: + case 7: + if (bcode == 7) + info.si_code = FPE_INTDIV; + else + info.si_code = FPE_INTOVF; + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_addr = (void *)compute_return_epc(regs); + force_sig_info(SIGFPE, &info, current); + break; + default: + force_sig(SIGTRAP, current); + } } void do_tr(struct pt_regs *regs) { + siginfo_t info; unsigned int opcode, bcode; if (get_insn_opcode(regs, &opcode)) @@ -398,8 +470,23 @@ * (A short test says that IRIX 5.3 sends SIGTRAP for all break * insns, even for break codes that indicate arithmetic failures. * Weird ...) + * But should we continue the brokenness??? --macro */ - force_sig(SIGTRAP, current); + switch (bcode) { + case 6: + case 7: + if (bcode == 7) + info.si_code = FPE_INTDIV; + else + info.si_code = FPE_INTOVF; + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_addr = (void *)compute_return_epc(regs); + force_sig_info(SIGFPE, &info, current); + break; + default: + force_sig(SIGTRAP, current); + } } #if !defined(CONFIG_CPU_HAS_LLSC) @@ -520,10 +607,32 @@ unsigned int cpid; extern void lazy_fpu_switch(void*); extern void init_fpu(void); - +#ifdef CONFIG_MIPS_FPU_EMULATOR + void fpu_emulator_init_fpu(void); + int sig; +#endif cpid = (regs->cp0_cause >> CAUSEB_CE) & 3; if (cpid != 1) goto bad_cid; + +#ifdef CONFIG_MIPS_FPU_EMULATOR + if(!(mips_cpu.options & MIPS_CPU_FPU)) { + if (last_task_used_math != current) { + if(!current->used_math) { + fpu_emulator_init_fpu(); + current->used_math = 1; + } + } + sig = fpu_emulator_cop1Handler(0, regs); + last_task_used_math = current; + if(sig) { + force_sig(sig, current); + } + return; + } +#else + if(!(mips_cpu.options & MIPS_CPU_FPU)) goto bad_cid; +#endif regs->cp0_status |= ST0_CU1; if (last_task_used_math == current) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/lib/Makefile linux.ac/arch/mips/lib/Makefile --- linux.vanilla/arch/mips/lib/Makefile Wed Dec 6 07:15:12 2000 +++ linux.ac/arch/mips/lib/Makefile Tue Apr 3 17:54:32 2001 @@ -9,26 +9,23 @@ L_TARGET = lib.a -L_OBJS = csum_partial.o csum_partial_copy.o \ - rtc-std.o rtc-no.o memcpy.o memset.o watch.o\ - strlen_user.o strncpy_user.o strnlen_user.o +obj-y += csum_partial.o csum_partial_copy.o \ + rtc-std.o rtc-no.o memcpy.o memset.o \ + watch.o strlen_user.o strncpy_user.o \ + strnlen_user.o ifdef CONFIG_CPU_R3000 - L_OBJS += r3k_dump_tlb.o + obj-y += r3k_dump_tlb.o else - L_OBJS += dump_tlb.o + ifdef CONFIG_CPU_R3912 + obj-y += r3k_dump_tlb.o + else + obj-y += dump_tlb.o + endif endif -ifdef CONFIG_BLK_DEV_FD - L_OBJS += floppy-no.o floppy-std.o -endif - -ifdef CONFIG_IDE - L_OBJS += ide-std.o ide-no.o -endif - -ifdef CONFIG_PC_KEYB - L_OBJS += kbd-std.o kbd-no.o -endif +obj-$(CONFIG_BLK_DEV_FD) += floppy-no.o floppy-std.o +obj-$(CONFIG_IDE) += ide-std.o ide-no.o +obj-$(CONFIG_PC_KEYB) += kbd-std.o kbd-no.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/lib/kbd-std.c linux.ac/arch/mips/lib/kbd-std.c --- linux.vanilla/arch/mips/lib/kbd-std.c Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/lib/kbd-std.c Tue Apr 3 17:54:32 2001 @@ -8,6 +8,7 @@ * * Copyright (C) 1998, 1999 by Ralf Baechle */ +#include <linux/config.h> #include <linux/ioport.h> #include <linux/sched.h> #include <linux/pc_keyb.h> @@ -19,11 +20,17 @@ static void std_kbd_request_region(void) { +#ifdef CONFIG_MIPS_ITE8172 + printk("std_kbd_request_region\n"); + request_region(0x14000060, 16, "keyboard"); +#else request_region(0x60, 16, "keyboard"); +#endif } static int std_kbd_request_irq(void (*handler)(int, void *, struct pt_regs *)) { + printk("std_kbd_request_irq\n"); return request_irq(KEYBOARD_IRQ, handler, 0, "keyboard", NULL); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/Makefile linux.ac/arch/mips/math-emu/Makefile --- linux.vanilla/arch/mips/math-emu/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/Makefile Tue Apr 3 17:54:32 2001 @@ -0,0 +1,24 @@ +# +# Makefile for the Linux/MIPS kernel FPU emulation. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +EXTRA_ASFLAGS = -mips2 -mcpu=r4000 + +O_TARGET:= fpu_emulator.o + +obj-y := cp1emu.o ieee754m.o ieee754d.o ieee754dp.o ieee754sp.o ieee754.o \ + ieee754xcpt.o dp_frexp.o dp_modf.o dp_div.o dp_mul.o dp_sub.o \ + dp_add.o dp_fsp.o dp_cmp.o dp_logb.o dp_scalb.o dp_simple.o \ + dp_tint.o dp_fint.o dp_tlong.o dp_flong.o sp_frexp.o sp_modf.o \ + sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_logb.o \ + sp_scalb.o sp_simple.o sp_tint.o sp_fint.o sp_tlong.o sp_flong.o \ + dp_sqrt.o sp_sqrt.o kernel_linkage.o + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/cp1emu.c linux.ac/arch/mips/math-emu/cp1emu.c --- linux.vanilla/arch/mips/math-emu/cp1emu.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/cp1emu.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,1811 @@ +/* + * cp1emu.c: a MIPS coprocessor 1 (fpu) instruction emulator + * + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + * + * A complete emulator for MIPS coprocessor 1 instructions. This is + * required for #float(switch) or #float(trap), where it catches all + * COP1 instructions via the "CoProcessor Unusable" exception. + * + * More surprisingly it is also required for #float(ieee), to help out + * the hardware fpu at the boundaries of the IEEE-754 representation + * (denormalised values, infinities, underflow, etc). It is made + * quite nasty because emulation of some non-COP1 instructions is + * required, e.g. in branch delay slots. + * + * Notes: + * 1) the IEEE754 library (-le) performs the actual arithmetic; + * 2) if you know that you won't have an fpu, then you'll get much + * better performance by compiling with -msoft-float! */ + +/************************************************************************** + * Nov 7, 2000 + * Massive changes to integrate with Linux kernel. + * + * Replace use of kernel data area with use of user stack + * for execution of instructions in branch delay slots. + * + * Replace use of static kernel variables with thread_struct elements. + * + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + *************************************************************************/ +#include <linux/mm.h> +#include <linux/signal.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> + +#include <asm/asm.h> +#include <asm/branch.h> +#include <asm/byteorder.h> +#include <asm/inst.h> +#include <asm/uaccess.h> +#include <asm/processor.h> +#include <asm/mipsregs.h> +#include <asm/system.h> +#include <asm/pgtable.h> + +#include <asm/fpu_emulator.h> + +#include "ieee754.h" + +/* Strap kernel emulator for full MIPS IV emulation */ + +#ifdef __mips +#undef __mips +#endif +#define __mips 4 + +typedef void *vaddr_t; + +/* Function which emulates the instruction in a branch delay slot. */ + +static int mips_dsemul(struct pt_regs *, mips_instruction, vaddr_t); + +/* Function which emulates a floating point instruction. */ + +static int fpu_emu(struct pt_regs *, struct mips_fpu_soft_struct *, + mips_instruction); + +#if __mips >= 4 && __mips != 32 +static int fpux_emu(struct pt_regs *, + struct mips_fpu_soft_struct *, mips_instruction); +#endif + +/* Further private data for which no space exists in mips_fpu_soft_struct */ + +struct mips_fpu_emulator_private fpuemuprivate; + +/* Control registers */ + +#define FPCREG_RID 0 /* $0 = revision id */ +#define FPCREG_CSR 31 /* $31 = csr */ + +/* Convert Mips rounding mode (0..3) to IEEE library modes. */ +static const unsigned char ieee_rm[4] = { + IEEE754_RN, IEEE754_RZ, IEEE754_RU, IEEE754_RD +}; + +#if __mips >= 4 +/* convert condition code register number to csr bit */ +static const unsigned int fpucondbit[8] = { + FPU_CSR_COND0, + FPU_CSR_COND1, + FPU_CSR_COND2, + FPU_CSR_COND3, + FPU_CSR_COND4, + FPU_CSR_COND5, + FPU_CSR_COND6, + FPU_CSR_COND7 +}; +#endif + + + +/* + * Redundant with logic already in kernel/branch.c, + * embedded in compute_return_epc. At some point, + * a single subroutine should be used across both + * modules. + */ +static int isBranchInstr(mips_instruction * i) +{ + switch (MIPSInst_OPCODE(*i)) { + case spec_op: + switch (MIPSInst_FUNC(*i)) { + case jalr_op: + case jr_op: + return 1; + } + break; + + case bcond_op: + switch (MIPSInst_RT(*i)) { + case bltz_op: + case bgez_op: + case bltzl_op: + case bgezl_op: + case bltzal_op: + case bgezal_op: + case bltzall_op: + case bgezall_op: + return 1; + } + break; + + case j_op: + case jal_op: + case jalx_op: + case beq_op: + case bne_op: + case blez_op: + case bgtz_op: + case beql_op: + case bnel_op: + case blezl_op: + case bgtzl_op: + return 1; + + case cop0_op: + case cop1_op: + case cop2_op: + case cop1x_op: + if (MIPSInst_RS(*i) == bc_op) + return 1; + break; + } + + return 0; +} + +#define REG_TO_VA (vaddr_t) +#define VA_TO_REG (unsigned long) + +static unsigned long +mips_get_word(struct pt_regs *xcp, void *va, int *perr) +{ + unsigned long temp; + + if (!user_mode(xcp)) { + *perr = 0; + return (*(unsigned long *) va); + } else { + /* Use kernel get_user() macro */ + *perr = (int) get_user(temp, (unsigned long *) va); + return temp; + } +} + +static unsigned long long +mips_get_dword(struct pt_regs *xcp, void *va, int *perr) +{ + unsigned long long temp; + + if (!user_mode(xcp)) { + *perr = 0; + return (*(unsigned long long *) va); + } else { + /* Use kernel get_user() macro */ + *perr = (int) get_user(temp, (unsigned long long *) va); + return temp; + } +} + +static int mips_put_word(struct pt_regs *xcp, void *va, unsigned long val) +{ + if (!user_mode(xcp)) { + *(unsigned long *) va = val; + return 0; + } else { + /* Use kernel get_user() macro */ + return (int) put_user(val, (unsigned long *) va); + } +} + +static int mips_put_dword(struct pt_regs *xcp, void *va, long long val) +{ + if (!user_mode(xcp)) { + *(unsigned long long *) va = val; + return 0; + } else { + /* Use kernel get_user() macro */ + return (int) put_user(val, (unsigned long long *) va); + } +} + + +/* + * In the Linux kernel, we support selection of FPR format on the + * basis of the Status.FR bit. This does imply that, if a full 32 + * FPRs are desired, there needs to be a flip-flop that can be written + * to one at that bit position. In any case, normal MIPS ABI uses + * only the even FPRs (Status.FR = 0). + */ + +#define CP0_STATUS_FR_SUPPORT + +/* + * Emulate the single floating point instruction pointed at by EPC. + * Two instructions if the instruction is in a branch delay slot. + */ + +static int +cop1Emulate(int xcptno, struct pt_regs *xcp, + struct mips_fpu_soft_struct *ctx) +{ + mips_instruction ir; + vaddr_t emulpc; + vaddr_t contpc; + unsigned int cond; + int err = 0; + + + ir = mips_get_word(xcp, REG_TO_VA xcp->cp0_epc, &err); + if (err) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + + /* XXX NEC Vr54xx bug workaround */ + if ((xcp->cp0_cause & CAUSEF_BD) && !isBranchInstr(&ir)) + xcp->cp0_cause &= ~CAUSEF_BD; + + if (xcp->cp0_cause & CAUSEF_BD) { + /* + * The instruction to be emulated is in a branch delay slot + * which means that we have to emulate the branch instruction + * BEFORE we do the cop1 instruction. + * + * This branch could be a COP1 branch, but in that case we + * would have had a trap for that instruction, and would not + * come through this route. + * + * Linux MIPS branch emulator operates on context, updating the + * cp0_epc. + */ + emulpc = REG_TO_VA(xcp->cp0_epc + 4); /* Snapshot emulation target */ + + if (__compute_return_epc(xcp)) { +#ifdef CP1DBG + printk("failed to emulate branch at %p\n", + REG_TO_VA(xcp->cp0_epc)); +#endif + return SIGILL;; + } + ir = mips_get_word(xcp, emulpc, &err); + if (err) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + contpc = REG_TO_VA xcp->cp0_epc; + } else { + emulpc = REG_TO_VA xcp->cp0_epc; + contpc = REG_TO_VA xcp->cp0_epc + 4; + } + + emul: + fpuemuprivate.stats.emulated++; + switch (MIPSInst_OPCODE(ir)) { +#ifdef CP0_STATUS_FR_SUPPORT + /* R4000+ 64-bit fpu registers */ +#ifndef SINGLE_ONLY_FPU + case ldc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + int ft = MIPSInst_RT(ir); + if (!(xcp->cp0_status & ST0_FR)) + ft &= ~1; + ctx->regs[ft] = mips_get_dword(xcp, va, &err); + fpuemuprivate.stats.loads++; + if (err) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + } + break; + + case sdc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + int ft = MIPSInst_RT(ir); + if (!(xcp->cp0_status & ST0_FR)) + ft &= ~1; + fpuemuprivate.stats.stores++; + if (mips_put_dword(xcp, va, ctx->regs[ft])) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + } + break; +#endif + + case lwc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + fpureg_t val; + int ft = MIPSInst_RT(ir); + fpuemuprivate.stats.loads++; + val = mips_get_word(xcp, va, &err); + if (err) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + if (xcp->cp0_status & ST0_FR) { + /* load whole register */ + ctx->regs[ft] = val; + } else if (ft & 1) { + /* load to m.s. 32 bits */ +#ifdef SINGLE_ONLY_FPU + /* illegal register in single-float mode */ + return SIGILL; +#else + ctx->regs[(ft & ~1)] &= 0xffffffff; + ctx->regs[(ft & ~1)] |= val << 32; +#endif + } else { + /* load to l.s. 32 bits */ + ctx->regs[ft] &= ~0xffffffffLL; + ctx->regs[ft] |= val; + } + } + break; + + case swc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + unsigned int val; + int ft = MIPSInst_RT(ir); + fpuemuprivate.stats.stores++; + if (xcp->cp0_status & ST0_FR) { + /* store whole register */ + val = ctx->regs[ft]; + } else if (ft & 1) { +#ifdef SINGLE_ONLY_FPU + /* illegal register in single-float mode */ + return SIGILL; +#else + /* store from m.s. 32 bits */ + val = ctx->regs[(ft & ~1)] >> 32; +#endif + } else { + /* store from l.s. 32 bits */ + val = ctx->regs[ft]; + } + if (mips_put_word(xcp, va, val)) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + } + break; +#else /* old 32-bit fpu registers */ + case lwc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + ctx->regs[MIPSInst_RT(ir)] = + mips_get_word(xcp, va, &err); + fpuemuprivate.stats.loads++; + if (err) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + } + break; + + case swc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + fpuemuprivate.stats.stores++; + if (mips_put_word + (xcp, va, ctx->regs[MIPSInst_RT(ir)])) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + } + break; + case ldc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + unsigned int rt = MIPSInst_RT(ir) & ~1; + int errs = 0; + fpuemuprivate.stats.loads++; +#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__) + ctx->regs[rt + 1] = + mips_get_word(xcp, va + 0, &err); + errs += err; + ctx->regs[rt + 0] = + mips_get_word(xcp, va + 4, &err); + errs += err; +#else + ctx->regs[rt + 0] = + mips_get_word(xcp, va + 0, &err); + errs += err; + ctx->regs[rt + 1] = + mips_get_word(xcp, va + 4, &err); + errs += err; +#endif + if (err) + return SIGBUS; + } + break; + + case sdc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + unsigned int rt = MIPSInst_RT(ir) & ~1; + fpuemuprivate.stats.stores++; +#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__) + if (mips_put_word(xcp, va + 0, ctx->regs[rt + 1])) + return SIGBUS; + if (mips_put_word(xcp, va + 4, ctx->regs[rt + 0])) + return SIGBUS; +#else + if (mips_put_word(xcp, va + 0, ctx->regs[rt + 0])) + return SIGBUS; + if (mips_put_word(xcp, va + 4, ctx->regs[rt + 1])) + return SIGBUS; +#endif + } + break; +#endif + + case cop1_op: + switch (MIPSInst_RS(ir)) { + +#ifdef CP0_STATUS_FR_SUPPORT +#if __mips64 && !defined(SINGLE_ONLY_FPU) + case dmfc_op: + /* copregister fs -> gpr[rt] */ + if (MIPSInst_RT(ir) != 0) { + int fs = MIPSInst_RD(ir); + if (!(xcp->cp0_status & ST0_FR)) + fs &= ~1; + xcp->regs[MIPSInst_RT(ir)] = ctx->regs[fs]; + } + break; + + case dmtc_op: + /* copregister fs <- rt */ + { + fpureg_t value; + int fs = MIPSInst_RD(ir); + if (!(xcp->cp0_status & ST0_FR)) + fs &= ~1; + value = + (MIPSInst_RT(ir) == + 0) ? 0 : xcp->regs[MIPSInst_RT(ir)]; + ctx->regs[fs] = value; + } + break; +#endif + + case mfc_op: + /* copregister rd -> gpr[rt] */ + if (MIPSInst_RT(ir) != 0) { + /* default value from l.s. 32 bits */ + int value = ctx->regs[MIPSInst_RD(ir)]; + if (MIPSInst_RD(ir) & 1) { +#ifdef SINGLE_ONLY_FPU + /* illegal register in single-float mode */ + return SIGILL; +#else + if (!(xcp->cp0_status & ST0_FR)) { + /* move from m.s. 32 bits */ + value = + ctx-> + regs[MIPSInst_RD(ir) & + ~1] >> 32; + } +#endif + } + xcp->regs[MIPSInst_RT(ir)] = value; + } + break; + + case mtc_op: + /* copregister rd <- rt */ + { + fpureg_t value; + if (MIPSInst_RT(ir) == 0) + value = 0; + else + value = + (unsigned int) xcp-> + regs[MIPSInst_RT(ir)]; + if (MIPSInst_RD(ir) & 1) { +#ifdef SINGLE_ONLY_FPU + /* illegal register in single-float mode */ + return SIGILL; +#else + if (!(xcp->cp0_status & ST0_FR)) { + /* move to m.s. 32 bits */ + ctx-> + regs[ + (MIPSInst_RD(ir) & + ~1)] &= + 0xffffffff; + ctx-> + regs[ + (MIPSInst_RD(ir) & + ~1)] |= + value << 32; + break; + } +#endif + } + /* move to l.s. 32 bits */ + ctx->regs[MIPSInst_RD(ir)] &= + ~0xffffffffLL; + ctx->regs[MIPSInst_RD(ir)] |= value; + } + break; +#else + + case mfc_op: + /* copregister rd -> gpr[rt] */ + if (MIPSInst_RT(ir) != 0) { + unsigned value = + ctx->regs[MIPSInst_RD(ir)]; + xcp->regs[MIPSInst_RT(ir)] = value; + } + break; + + case mtc_op: + /* copregister rd <- rt */ + { + unsigned value; + value = + (MIPSInst_RT(ir) == + 0) ? 0 : xcp->regs[MIPSInst_RT(ir)]; + ctx->regs[MIPSInst_RD(ir)] = value; + } + break; +#endif + + case cfc_op: + /* cop control register rd -> gpr[rt] */ + { + unsigned value; + + if (MIPSInst_RD(ir) == FPCREG_CSR) { + value = ctx->sr; +#ifdef CSRTRACE + printk + ("%p gpr[%d]<-csr=%08x\n", + REG_TO_VA(xcp->cp0_epc), + MIPSInst_RT(ir), value); +#endif + } else if (MIPSInst_RD(ir) == FPCREG_RID) + value = 0; + else + value = 0; + if (MIPSInst_RT(ir)) + xcp->regs[MIPSInst_RT(ir)] = value; + } + break; + + case ctc_op: + /* copregister rd <- rt */ + { + unsigned value; + + if (MIPSInst_RT(ir) == 0) + value = 0; + else + value = xcp->regs[MIPSInst_RT(ir)]; + + /* we only have one writable control reg + */ + if (MIPSInst_RD(ir) == FPCREG_CSR) { +#ifdef CSRTRACE + printk + ("%p gpr[%d]->csr=%08x\n", + REG_TO_VA(xcp->cp0_epc), + MIPSInst_RT(ir), value); +#endif + ctx->sr = value; + /* copy new rounding mode to ieee library state! */ + ieee754_csr.rm = + ieee_rm[value & 0x3]; + } + } + break; + + case bc_op: + if (xcp->cp0_cause & CAUSEF_BD) { + return SIGILL; + } + { + int likely = 0; + +#if __mips >= 4 + cond = + ctx-> + sr & fpucondbit[MIPSInst_RT(ir) >> 2]; +#else + cond = ctx->sr & FPU_CSR_COND; +#endif + switch (MIPSInst_RT(ir) & 3) { + case bcfl_op: + likely = 1; + case bcf_op: + cond = !cond; + break; + case bctl_op: + likely = 1; + case bct_op: + break; + default: + /* thats an illegal instruction */ + return SIGILL; + } + + xcp->cp0_cause |= CAUSEF_BD; + if (cond) { + /* branch taken: emulate dslot instruction */ + xcp->cp0_epc += 4; + contpc = + REG_TO_VA xcp->cp0_epc + + (MIPSInst_SIMM(ir) << 2); + + ir = + mips_get_word(xcp, + REG_TO_VA(xcp-> + cp0_epc), + &err); + if (err) { + fpuemuprivate.stats. + errors++; + return SIGBUS; + } + + switch (MIPSInst_OPCODE(ir)) { + case lwc1_op: + case swc1_op: +#if (__mips >= 2 || __mips64) && !defined(SINGLE_ONLY_FPU) + case ldc1_op: + case sdc1_op: +#endif + case cop1_op: +#if __mips >= 4 && __mips != 32 + case cop1x_op: +#endif + /* its one of ours */ + goto emul; +#if __mips >= 4 + case spec_op: + if (MIPSInst_FUNC(ir) == + movc_op) goto emul; + break; +#endif + } + + /* single step the non-cp1 instruction in the dslot */ + return mips_dsemul(xcp, ir, + contpc); + } else { + /* branch not taken */ + if (likely) + /* branch likely nullifies dslot if not taken */ + xcp->cp0_epc += 4; + /* else continue & execute dslot as normal insn */ + } + } + break; + + default: + if (!(MIPSInst_RS(ir) & 0x10)) { + return SIGILL; + } + /* a real fpu computation instruction */ + { + int sig; + if ((sig = fpu_emu(xcp, ctx, ir))) + return sig; + } + } + break; + +#if __mips >= 4 && __mips != 32 + case cop1x_op: + { + int sig; + if ((sig = fpux_emu(xcp, ctx, ir))) + return sig; + } + break; +#endif + +#if __mips >= 4 + case spec_op: + if (MIPSInst_FUNC(ir) != movc_op) + return SIGILL; + cond = fpucondbit[MIPSInst_RT(ir) >> 2]; + if (((ctx->sr & cond) != 0) != + ((MIPSInst_RT(ir) & 1) != 0)) return 0; + xcp->regs[MIPSInst_RD(ir)] = xcp->regs[MIPSInst_RS(ir)]; + break; +#endif + + default: + return SIGILL; + } + + /* we did it !! */ + xcp->cp0_epc = VA_TO_REG(contpc); + xcp->cp0_cause &= ~CAUSEF_BD; + return 0; +} + +/* + * Emulate the arbritrary instruction ir at xcp->cp0_epc. Required when + * we have to emulate the instruction in a COP1 branch delay slot. Do + * not change cp0_epc due to the instruction + * + * According to the spec: + * 1) it shouldnt be a branch :-) + * 2) it can be a COP instruction :-( + * 3) if we are tring to run a protected memory space we must take + * special care on memory access instructions :-( + */ + +/* + * "Trampoline" return routine to catch exception following + * execution of delay-slot instruction execution. + */ + +int do_dsemulret(struct pt_regs *xcp) +{ +#ifdef DSEMUL_TRACE + printk("desemulret\n"); +#endif + /* Set EPC to return to post-branch instruction */ + xcp->cp0_epc = current->thread.dsemul_epc; + /* + * Clear the state that got us here. + */ + current->thread.dsemul_aerpc = (unsigned long) 0; + + return 0; +} + + +#define AdELOAD 0x8c000001 /* lw $0,1($0) */ + +static int +mips_dsemul(struct pt_regs *xcp, mips_instruction ir, vaddr_t cpc) +{ + mips_instruction *dsemul_insns; + mips_instruction forcetrap; + extern asmlinkage void handle_dsemulret(void); + + if (ir == 0) { /* a nop is easy */ + xcp->cp0_epc = VA_TO_REG(cpc); + return 0; + } +#ifdef DSEMUL_TRACE + printk("desemul %p %p\n", REG_TO_VA(xcp->cp0_epc), cpc); +#endif + + /* + * The strategy is to push the instruction onto the user stack + * and put a trap after it which we can catch and jump to + * the required address any alternative apart from full + * instruction emulation!!. + */ + dsemul_insns = (mips_instruction *) (xcp->regs[29] & ~3); + dsemul_insns -= 3; /* Two instructions, plus one for luck ;-) */ + /* Verify that the stack pointer is not competely insane */ + if (verify_area + (VERIFY_WRITE, dsemul_insns, sizeof(mips_instruction) * 2)) + return SIGBUS; + + if (mips_put_word(xcp, &dsemul_insns[0], ir)) { + fpuemuprivate.stats.errors++; + return (SIGBUS); + } + + /* + * Algorithmics used a system call instruction, and + * borrowed that vector. MIPS/Linux version is a bit + * more heavyweight in the interests of portability and + * multiprocessor support. We flag the thread for special + * handling in the unaligned access handler and force an + * address error excpetion. + */ + + /* If one is *really* paranoid, one tests for a bad stack pointer */ + if ((xcp->regs[29] & 0x3) == 0x3) + forcetrap = AdELOAD - 1; + else + forcetrap = AdELOAD; + + if (mips_put_word(xcp, &dsemul_insns[1], forcetrap)) { + fpuemuprivate.stats.errors++; + return (SIGBUS); + } + + /* Set thread state to catch and handle the exception */ + current->thread.dsemul_epc = (unsigned long) cpc; + current->thread.dsemul_aerpc = (unsigned long) &dsemul_insns[1]; + xcp->cp0_epc = VA_TO_REG & dsemul_insns[0]; + + /* What we'd really like to do is just flush the line(s) of the */ + /* icache containing the dsemulret instructions, but there's no */ + /* mechanism to do this yet... */ + flush_cache_all(); + return SIGILL; /* force out of emulation loop */ +} + +/* + * Conversion table from MIPS compare ops 48-63 + * cond = ieee754dp_cmp(x,y,IEEE754_UN); + */ +static const unsigned char cmptab[8] = { + 0, /* cmp_0 (sig) cmp_sf */ + IEEE754_CUN, /* cmp_un (sig) cmp_ngle */ + IEEE754_CEQ, /* cmp_eq (sig) cmp_seq */ + IEEE754_CEQ | IEEE754_CUN, /* cmp_ueq (sig) cmp_ngl */ + IEEE754_CLT, /* cmp_olt (sig) cmp_lt */ + IEEE754_CLT | IEEE754_CUN, /* cmp_ult (sig) cmp_nge */ + IEEE754_CLT | IEEE754_CEQ, /* cmp_ole (sig) cmp_le */ + IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN, /* cmp_ule (sig) cmp_ngt */ +}; + +#define SIFROMREG(si,x) ((si) = ctx->regs[x]) +#define SITOREG(si,x) (ctx->regs[x] = (int)(si)) + +#if __mips64 && !defined(SINGLE_ONLY_FPU) +#define DIFROMREG(di,x) ((di) = ctx->regs[x]) +#define DITOREG(di,x) (ctx->regs[x] = (di)) +#endif + +#define SPFROMREG(sp,x) ((sp).bits = ctx->regs[x]) +#define SPTOREG(sp,x) (ctx->regs[x] = (sp).bits) + +#ifdef CP0_STATUS_FR_SUPPORT +#define DPFROMREG(dp,x) ((dp).bits = \ + ctx->regs[(xcp->cp0_status & ST0_FR) ? x : (x & ~1)]) +#define DPTOREG(dp,x) (ctx->regs[(xcp->cp0_status & ST0_FR) ? x : (x & ~1)]\ + = (dp).bits) +#else +/* Beware: MIPS COP1 doubles are always little_word endian in registers */ +#define DPFROMREG(dp,x) \ + ((dp).bits = ((unsigned long long)ctx->regs[(x)+1] << 32) | ctx->regs[x]) +#define DPTOREG(dp,x) \ + (ctx->regs[x] = (dp).bits, ctx->regs[(x)+1] = (dp).bits >> 32) +#endif + +#if __mips >= 4 && __mips != 32 + +/* + * Additional MIPS4 instructions + */ + +static ieee754dp fpemu_dp_recip(ieee754dp d) +{ + return ieee754dp_div(ieee754dp_one(0), d); +} + +static ieee754dp fpemu_dp_rsqrt(ieee754dp d) +{ + return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d)); +} + +static ieee754sp fpemu_sp_recip(ieee754sp s) +{ + return ieee754sp_div(ieee754sp_one(0), s); +} + +static ieee754sp fpemu_sp_rsqrt(ieee754sp s) +{ + return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s)); +} + + +static ieee754dp fpemu_dp_madd(ieee754dp r, ieee754dp s, ieee754dp t) +{ + return ieee754dp_add(ieee754dp_mul(s, t), r); +} + +static ieee754dp fpemu_dp_msub(ieee754dp r, ieee754dp s, ieee754dp t) +{ + return ieee754dp_sub(ieee754dp_mul(s, t), r); +} + +static ieee754dp fpemu_dp_nmadd(ieee754dp r, ieee754dp s, ieee754dp t) +{ + return ieee754dp_neg(ieee754dp_add(ieee754dp_mul(s, t), r)); +} + +static ieee754dp fpemu_dp_nmsub(ieee754dp r, ieee754dp s, ieee754dp t) +{ + return ieee754dp_neg(ieee754dp_sub(ieee754dp_mul(s, t), r)); +} + + +static ieee754sp fpemu_sp_madd(ieee754sp r, ieee754sp s, ieee754sp t) +{ + return ieee754sp_add(ieee754sp_mul(s, t), r); +} + +static ieee754sp fpemu_sp_msub(ieee754sp r, ieee754sp s, ieee754sp t) +{ + return ieee754sp_sub(ieee754sp_mul(s, t), r); +} + +static ieee754sp fpemu_sp_nmadd(ieee754sp r, ieee754sp s, ieee754sp t) +{ + return ieee754sp_neg(ieee754sp_add(ieee754sp_mul(s, t), r)); +} + +static ieee754sp fpemu_sp_nmsub(ieee754sp r, ieee754sp s, ieee754sp t) +{ + return ieee754sp_neg(ieee754sp_sub(ieee754sp_mul(s, t), r)); +} + +static int +fpux_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx, + mips_instruction ir) +{ + unsigned rcsr = 0; /* resulting csr */ + + fpuemuprivate.stats.cp1xops++; + + switch (MIPSInst_FMA_FFMT(ir)) { + case s_fmt: /* 0 */ + { + ieee754sp(*handler) (ieee754sp, ieee754sp, + ieee754sp); + ieee754sp fd, fr, fs, ft; + + switch (MIPSInst_FUNC(ir)) { + case lwxc1_op: + { + void *va = + REG_TO_VA(xcp-> + regs[MIPSInst_FR(ir)] + + + xcp-> + regs[MIPSInst_FT + (ir)]); + fpureg_t val; + int err = 0; + val = mips_get_word(xcp, va, &err); + if (err) { + fpuemuprivate.stats. + errors++; + return SIGBUS; + } + if (xcp->cp0_status & ST0_FR) { + /* load whole register */ + ctx-> + regs[MIPSInst_FD(ir)] = + val; + } else if (MIPSInst_FD(ir) & 1) { + /* load to m.s. 32 bits */ +#if defined(SINGLE_ONLY_FPU) + /* illegal register in single-float mode */ + return SIGILL; +#else + ctx-> + regs[ + (MIPSInst_FD(ir) & + ~1)] &= + 0xffffffff; + ctx-> + regs[ + (MIPSInst_FD(ir) & + ~1)] |= + val << 32; +#endif + } else { + /* load to l.s. 32 bits */ + ctx-> + regs[MIPSInst_FD(ir)] + &= ~0xffffffffLL; + ctx-> + regs[MIPSInst_FD(ir)] + |= val; + } + } + break; + + case swxc1_op: + { + void *va = + REG_TO_VA(xcp-> + regs[MIPSInst_FR(ir)] + + + xcp-> + regs[MIPSInst_FT + (ir)]); + unsigned int val; + if (xcp->cp0_status & ST0_FR) { + /* store whole register */ + val = + ctx-> + regs[MIPSInst_FS(ir)]; + } else if (MIPSInst_FS(ir) & 1) { +#if defined(SINGLE_ONLY_FPU) + /* illegal register in single-float mode */ + return SIGILL; +#else + /* store from m.s. 32 bits */ + val = + ctx-> + regs[ + (MIPSInst_FS(ir) & + ~1)] >> 32; +#endif + } else { + /* store from l.s. 32 bits */ + val = + ctx-> + regs[MIPSInst_FS(ir)]; + } + if (mips_put_word(xcp, va, val)) { + fpuemuprivate.stats. + errors++; + return SIGBUS; + } + } + break; + + case madd_s_op: + handler = fpemu_sp_madd; + goto scoptop; + case msub_s_op: + handler = fpemu_sp_msub; + goto scoptop; + case nmadd_s_op: + handler = fpemu_sp_nmadd; + goto scoptop; + case nmsub_s_op: + handler = fpemu_sp_nmsub; + goto scoptop; + + scoptop: + SPFROMREG(fr, MIPSInst_FR(ir)); + SPFROMREG(fs, MIPSInst_FS(ir)); + SPFROMREG(ft, MIPSInst_FT(ir)); + fd = (*handler) (fr, fs, ft); + SPTOREG(fd, MIPSInst_FD(ir)); + + copcsr: + if (ieee754_cxtest(IEEE754_INEXACT)) + rcsr |= + FPU_CSR_INE_X | FPU_CSR_INE_S; + if (ieee754_cxtest(IEEE754_UNDERFLOW)) + rcsr |= + FPU_CSR_UDF_X | FPU_CSR_UDF_S; + if (ieee754_cxtest(IEEE754_OVERFLOW)) + rcsr |= + FPU_CSR_OVF_X | FPU_CSR_OVF_S; + if (ieee754_cxtest + (IEEE754_INVALID_OPERATION)) rcsr |= + FPU_CSR_INV_X | FPU_CSR_INV_S; + + ctx->sr = + (ctx->sr & ~FPU_CSR_ALL_X) | rcsr; + if ((ctx->sr >> 5) & ctx-> + sr & FPU_CSR_ALL_E) { + /*printk ("SIGFPE: fpu csr = %08x\n",ctx->sr); */ + return SIGFPE; + } + + break; + + default: + return SIGILL; + } + } + break; + +#if !defined(SINGLE_ONLY_FPU) + case d_fmt: /* 1 */ + { + ieee754dp(*handler) (ieee754dp, ieee754dp, + ieee754dp); + ieee754dp fd, fr, fs, ft; + + switch (MIPSInst_FUNC(ir)) { + case ldxc1_op: + { + void *va = + REG_TO_VA(xcp-> + regs[MIPSInst_FR(ir)] + + + xcp-> + regs[MIPSInst_FT + (ir)]); + int err = 0; + ctx->regs[MIPSInst_FD(ir)] = + mips_get_dword(xcp, va, &err); + if (err) { + fpuemuprivate.stats. + errors++; + return SIGBUS; + } + } + break; + + case sdxc1_op: + { + void *va = + REG_TO_VA(xcp-> + regs[MIPSInst_FR(ir)] + + + xcp-> + regs[MIPSInst_FT + (ir)]); + if (mips_put_dword + (xcp, va, + ctx->regs[MIPSInst_FS(ir)])) { + fpuemuprivate.stats. + errors++; + return SIGBUS; + } + } + break; + + case madd_d_op: + handler = fpemu_dp_madd; + goto dcoptop; + case msub_d_op: + handler = fpemu_dp_msub; + goto dcoptop; + case nmadd_d_op: + handler = fpemu_dp_nmadd; + goto dcoptop; + case nmsub_d_op: + handler = fpemu_dp_nmsub; + goto dcoptop; + + dcoptop: + DPFROMREG(fr, MIPSInst_FR(ir)); + DPFROMREG(fs, MIPSInst_FS(ir)); + DPFROMREG(ft, MIPSInst_FT(ir)); + fd = (*handler) (fr, fs, ft); + DPTOREG(fd, MIPSInst_FD(ir)); + goto copcsr; + + default: + return SIGILL; + } + } + break; +#endif + + case 0x7: /* 7 */ + { + if (MIPSInst_FUNC(ir) != pfetch_op) { + return SIGILL; + } + /* ignore prefx operation */ + } + break; + + default: + return SIGILL; + } + + return 0; +} +#endif + + + +/* + * Emulate a single COP1 arithmetic instruction. + */ +static int +fpu_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx, + mips_instruction ir) +{ + int rfmt; /* resulting format */ + unsigned rcsr = 0; /* resulting csr */ + unsigned cond; + union { + ieee754dp d; + ieee754sp s; + int w; +#if __mips64 + long long l; +#endif + } rv; /* resulting value */ + + fpuemuprivate.stats.cp1ops++; + switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) { + + case s_fmt:{ /* 0 */ + ieee754sp(*handler) (); + + switch (MIPSInst_FUNC(ir)) { + /* binary ops */ + case fadd_op: + handler = ieee754sp_add; + goto scopbop; + case fsub_op: + handler = ieee754sp_sub; + goto scopbop; + case fmul_op: + handler = ieee754sp_mul; + goto scopbop; + case fdiv_op: + handler = ieee754sp_div; + goto scopbop; + + /* unary ops */ +#if __mips >= 2 || __mips64 + case fsqrt_op: + handler = ieee754sp_sqrt; + goto scopuop; +#endif +#if __mips >= 4 && __mips != 32 + case frsqrt_op: + handler = fpemu_sp_rsqrt; + goto scopuop; + case frecip_op: + handler = fpemu_sp_recip; + goto scopuop; +#endif +#if __mips >= 4 + case fmovc_op: + cond = fpucondbit[MIPSInst_FT(ir) >> 2]; + if (((ctx->sr & cond) != 0) != + ((MIPSInst_FT(ir) & 1) != 0)) + return 0; + SPFROMREG(rv.s, MIPSInst_FS(ir)); + break; + case fmovz_op: + if (xcp->regs[MIPSInst_FT(ir)] != 0) + return 0; + SPFROMREG(rv.s, MIPSInst_FS(ir)); + break; + case fmovn_op: + if (xcp->regs[MIPSInst_FT(ir)] == 0) + return 0; + SPFROMREG(rv.s, MIPSInst_FS(ir)); + break; +#endif + case fabs_op: + handler = ieee754sp_abs; + goto scopuop; + case fneg_op: + handler = ieee754sp_neg; + goto scopuop; + case fmov_op: + /* an easy one */ + SPFROMREG(rv.s, MIPSInst_FS(ir)); + break; + /* binary op on handler */ +scopbop: + { + ieee754sp fs, ft; + + SPFROMREG(fs, MIPSInst_FS(ir)); + SPFROMREG(ft, MIPSInst_FT(ir)); + + rv.s = (*handler) (fs, ft); + goto copcsr; + } +scopuop: + { + ieee754sp fs; + + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.s = (*handler) (fs); + goto copcsr; + } +copcsr: + if (ieee754_cxtest(IEEE754_INEXACT)) + rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; + if (ieee754_cxtest(IEEE754_UNDERFLOW)) + rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; + if (ieee754_cxtest(IEEE754_OVERFLOW)) + rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; + if (ieee754_cxtest(IEEE754_ZERO_DIVIDE)) + rcsr |= FPU_CSR_DIV_X | FPU_CSR_DIV_S; + if (ieee754_cxtest + (IEEE754_INVALID_OPERATION)) rcsr |= + FPU_CSR_INV_X | FPU_CSR_INV_S; + break; + + /* unary conv ops */ + case fcvts_op: + return SIGILL; /* not defined */ + case fcvtd_op: +#if defined(SINGLE_ONLY_FPU) + return SIGILL; /* not defined */ +#else + { + ieee754sp fs; + + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.d = ieee754dp_fsp(fs); + rfmt = d_fmt; + goto copcsr; + } +#endif + case fcvtw_op: + { + ieee754sp fs; + + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.w = ieee754sp_tint(fs); + rfmt = w_fmt; + goto copcsr; + } + +#if __mips >= 2 || __mips64 + case fround_op: + case ftrunc_op: + case fceil_op: + case ffloor_op: + { + unsigned int oldrm = ieee754_csr.rm; + ieee754sp fs; + + SPFROMREG(fs, MIPSInst_FS(ir)); + ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3]; + rv.w = ieee754sp_tint(fs); + ieee754_csr.rm = oldrm; + rfmt = w_fmt; + goto copcsr; + } +#endif /* __mips >= 2 */ + +#if __mips64 && !defined(SINGLE_ONLY_FPU) + case fcvtl_op: + { + ieee754sp fs; + + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.l = ieee754sp_tlong(fs); + rfmt = l_fmt; + goto copcsr; + } + + case froundl_op: + case ftruncl_op: + case fceill_op: + case ffloorl_op: + { + unsigned int oldrm = ieee754_csr.rm; + ieee754sp fs; + + SPFROMREG(fs, MIPSInst_FS(ir)); + ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3]; + rv.l = ieee754sp_tlong(fs); + ieee754_csr.rm = oldrm; + rfmt = l_fmt; + goto copcsr; + } +#endif /* __mips64 && !fpu(single) */ + + default: + if (MIPSInst_FUNC(ir) >= fcmp_op) { + unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; + ieee754sp fs, ft; + + SPFROMREG(fs, MIPSInst_FS(ir)); + SPFROMREG(ft, MIPSInst_FT(ir)); + rv.w = ieee754sp_cmp(fs, ft, cmptab[cmpop & 0x7]); + rfmt = -1; + if ((cmpop & 0x8) && ieee754_cxtest(IEEE754_INVALID_OPERATION)) + rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; + } else { + return SIGILL; + } + break; + } + break; + } + +#if !defined(SINGLE_ONLY_FPU) + case d_fmt: { + ieee754dp(*handler) (); + + switch (MIPSInst_FUNC(ir)) { + /* binary ops */ + case fadd_op: + handler = ieee754dp_add; + goto dcopbop; + case fsub_op: + handler = ieee754dp_sub; + goto dcopbop; + case fmul_op: + handler = ieee754dp_mul; + goto dcopbop; + case fdiv_op: + handler = ieee754dp_div; + goto dcopbop; + + /* unary ops */ +#if __mips >= 2 || __mips64 + case fsqrt_op: + handler = ieee754dp_sqrt; + goto dcopuop; +#endif +#if __mips >= 4 && __mips != 32 + case frsqrt_op: + handler = fpemu_dp_rsqrt; + goto dcopuop; + case frecip_op: + handler = fpemu_dp_recip; + goto dcopuop; +#endif +#if __mips >= 4 + case fmovc_op: + cond = fpucondbit[MIPSInst_FT(ir) >> 2]; + if (((ctx->sr & cond) != 0) != ((MIPSInst_FT(ir) & 1) != 0)) + return 0; + DPFROMREG(rv.d, MIPSInst_FS(ir)); + break; + case fmovz_op: + if (xcp->regs[MIPSInst_FT(ir)] != 0) + return 0; + DPFROMREG(rv.d, MIPSInst_FS(ir)); + break; + case fmovn_op: + if (xcp->regs[MIPSInst_FT(ir)] == 0) + return 0; + DPFROMREG(rv.d, MIPSInst_FS(ir)); + break; +#endif + case fabs_op: + handler = ieee754dp_abs; + goto dcopuop; + case fneg_op: + handler = ieee754dp_neg; + goto dcopuop; + case fmov_op: + /* an easy one */ + DPFROMREG(rv.d, MIPSInst_FS(ir)); + break; + + /* binary op on handler */ +dcopbop: + { + ieee754dp fs, ft; + + DPFROMREG(fs, MIPSInst_FS(ir)); + DPFROMREG(ft, MIPSInst_FT(ir)); + + rv.d = (*handler) (fs, ft); + goto copcsr; + } +dcopuop: + { + ieee754dp fs; + + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.d = (*handler) (fs); + goto copcsr; + } + + /* unary conv ops */ + case fcvts_op: + { + ieee754dp fs; + + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.s = ieee754sp_fdp(fs); + rfmt = s_fmt; + goto copcsr; + } + case fcvtd_op: + return SIGILL; /* not defined */ + case fcvtw_op: + { + ieee754dp fs; + + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.w = ieee754dp_tint(fs); /* wrong */ + rfmt = w_fmt; + goto copcsr; + } + +#if __mips >= 2 || __mips64 + case fround_op: + case ftrunc_op: + case fceil_op: + case ffloor_op: + { + unsigned int oldrm = ieee754_csr.rm; + ieee754dp fs; + + DPFROMREG(fs, MIPSInst_FS(ir)); + ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3]; + rv.w = ieee754dp_tint(fs); + ieee754_csr.rm = oldrm; + rfmt = w_fmt; + goto copcsr; + } +#endif + +#if __mips64 && !defined(SINGLE_ONLY_FPU) + case fcvtl_op: + { + ieee754dp fs; + + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.l = ieee754dp_tlong(fs); + rfmt = l_fmt; + goto copcsr; + } + + case froundl_op: + case ftruncl_op: + case fceill_op: + case ffloorl_op: + { + unsigned int oldrm = ieee754_csr.rm; + ieee754dp fs; + + DPFROMREG(fs, MIPSInst_FS(ir)); + ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3]; + rv.l = ieee754dp_tlong(fs); + ieee754_csr.rm = oldrm; + rfmt = l_fmt; + goto copcsr; + } +#endif /* __mips >= 3 && !fpu(single) */ + + default: + if (MIPSInst_FUNC(ir) >= fcmp_op) { + unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; + ieee754dp fs, ft; + + DPFROMREG(fs, MIPSInst_FS(ir)); + DPFROMREG(ft, MIPSInst_FT(ir)); + rv.w = ieee754dp_cmp(fs, ft, cmptab[cmpop & 0x7]); + rfmt = -1; + if ((cmpop & 0x8) && ieee754_cxtest (IEEE754_INVALID_OPERATION)) + rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; + } else { + return SIGILL; + } + break; + } + break; + } +#endif /* !defined(SINGLE_ONLY_FPU) */ + + case w_fmt: { + switch (MIPSInst_FUNC(ir)) { + case fcvts_op: + /* convert word to single precision real */ + rv.s = ieee754sp_fint(ctx-> regs[MIPSInst_FS(ir)]); + rfmt = s_fmt; + goto copcsr; +#if !defined(SINGLE_ONLY_FPU) + case fcvtd_op: + /* convert word to double precision real */ + rv.d = ieee754dp_fint(ctx-> regs[MIPSInst_FS(ir)]); + rfmt = d_fmt; + goto copcsr; +#endif + default: + return SIGILL; + } + break; + } + +#if __mips64 && !defined(SINGLE_ONLY_FPU) + case l_fmt: { + switch (MIPSInst_FUNC(ir)) { + case fcvts_op: + /* convert long to single precision real */ + rv.s = ieee754sp_flong(ctx-> regs[MIPSInst_FS(ir)]); + rfmt = s_fmt; + goto copcsr; + case fcvtd_op: + /* convert long to double precision real */ + rv.d = ieee754dp_flong(ctx-> regs[MIPSInst_FS(ir)]); + rfmt = d_fmt; + goto copcsr; + default: + return SIGILL; + } + break; + } +#endif + + default: + return SIGILL; + } + + /* + * Update the fpu CSR register for this operation. + * If an exception is required, generate a tidy SIGFPE exception, + * without updating the result register. + * Note: cause exception bits do not accumulate, they are rewritten + * for each op; only the flag/sticky bits accumulate. + */ + ctx->sr = (ctx->sr & ~FPU_CSR_ALL_X) | rcsr; + if ((ctx->sr >> 5) & ctx->sr & FPU_CSR_ALL_E) { + /*printk ("SIGFPE: fpu csr = %08x\n",ctx->sr); */ + return SIGFPE; + } + + /* + * Now we can safely write the result back to the register file. + */ + switch (rfmt) { + case -1: { +#if __mips >= 4 + cond = fpucondbit[MIPSInst_FD(ir) >> 2]; +#else + cond = FPU_CSR_COND; +#endif + if (rv.w) + ctx->sr |= cond; + else + ctx->sr &= ~cond; + break; + } +#if !defined(SINGLE_ONLY_FPU) + case d_fmt: + DPTOREG(rv.d, MIPSInst_FD(ir)); + break; +#endif + case s_fmt: + SPTOREG(rv.s, MIPSInst_FD(ir)); + break; + case w_fmt: + SITOREG(rv.w, MIPSInst_FD(ir)); + break; +#if __mips64 && !defined(SINGLE_ONLY_FPU) + case l_fmt: + DITOREG(rv.l, MIPSInst_FD(ir)); + break; +#endif + default: + return SIGILL; + } + + return 0; +} + + +/* + * Emulate the floating point instruction at EPC, and continue + * to run until we hit a non-fp instruction, or a backward + * branch. This cuts down dramatically on the per instruction + * exception overhead. + */ +int fpu_emulator_cop1Handler(int xcptno, struct pt_regs *xcp) +{ + struct mips_fpu_soft_struct *ctx = ¤t->thread.fpu.soft; + unsigned long oldepc, prevepc; + unsigned int insn; + int sig = 0; + int err = 0; + + oldepc = xcp->cp0_epc; + do { + prevepc = xcp->cp0_epc; + insn = mips_get_word(xcp, REG_TO_VA(xcp->cp0_epc), &err); + if (err) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + if (insn != 0) + sig = cop1Emulate(xcptno, xcp, ctx); + else + xcp->cp0_epc += 4; /* skip nops */ + } while (xcp->cp0_epc > prevepc && sig == 0); + + /* SIGILL indicates a non-fpu instruction */ + if (sig == SIGILL && xcp->cp0_epc != oldepc) + /* but if epc has advanced, then ignore it */ + sig = 0; + + return sig; +} + + +#ifdef NOTDEF +/* + * Patch up the hardware fpu state when an f.p. exception occurs. + */ +static int cop1Patcher(int xcptno, struct pt_regs *xcp) +{ + struct mips_fpu_soft_struct *ctx = ¤t->thread.fpu.soft; + unsigned sr; + int sig; + + /* reenable Cp1, else fpe_save() will get nested exception */ + sr = mips_bissr(ST0_CU1); + + /* get fpu registers and status, then clear pending exceptions */ + fpe_save(ctx); + fpe_setsr(ctx->sr &= ~FPU_CSR_ALL_X); + + /* get current rounding mode for IEEE library, and emulate insn */ + ieee754_csr.rm = ieee_rm[ctx->sr & 0x3]; + sig = cop1Emulate(xcptno, xcp, ctx); + + /* don't return with f.p. exceptions pending */ + ctx->sr &= ~FPU_CSR_ALL_X; + fpe_restore(ctx); + + mips_setsr(sr); + return sig; +} + +void _cop1_init(int emulate) +{ + extern int _nofpu; + + if (emulate) { + /* + * Install cop1 emulator to handle "coprocessor unusable" exception + */ + xcption(XCPTCPU, cop1Handler); + fpuemuactive = 1; /* tell dbg.c that we are in charge */ + _nofpu = 0; /* tell setjmp() it "has" an fpu */ + } else { + /* + * Install cop1 emulator for floating point exceptions only, + * i.e. denormalised results, underflow, overflow etc, which + * must be emulated in s/w. + */ +#ifdef 1 + /* r4000 or above use dedicate exception */ + xcption(XCPTFPE, cop1Patcher); +#else + /* r3000 et al use interrupt */ + extern int _sbd_getfpuintr(void); + int intno = _sbd_getfpuintr(); + intrupt(intno, cop1Patcher, 0); + mips_bissr(SR_IM0 << intno); +#endif + +#if (#cpu(r4640) || #cpu(r4650)) && !defined(SINGLE_ONLY_FPU) + /* For R4640/R4650 compiled *without* the -msingle-float flag, + then we share responsibility: the h/w handles the single + precision operations, and the trap emulator handles the + double precision. We set fpuemuactive so that dbg.c first + fetches the s/w state before saving the h/w state. */ + fpuemuactive = 1; + { + int i; + /* initialise the unused d.p high order words to be NaN */ + for (i = 0; i < 32; i++) + current->thread.fpu.soft.regs[i] = + 0x7ff80bad00000000LL; + } +#endif /* (r4640 || r4650) && !fpu(single) */ + } +} +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_add.c linux.ac/arch/mips/math-emu/dp_add.c --- linux.vanilla/arch/mips/math-emu/dp_add.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_add.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,186 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) +{ + COMPXDP; + COMPYDP; + + EXPLODEXDP; + EXPLODEYDP; + + CLEARCX; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "add", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y, "add", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x, "add", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754dp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Inifity handeling + */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + if (xs == ys) + return x; + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_xcpt(ieee754dp_indef(), "add", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + return y; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + return x; + + /* Zero handeling + */ + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + else + return ieee754dp_zero(ieee754_csr.rm == + IEEE754_RD); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return x; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return y; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + /* FALL THROUGH */ + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + DPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + /* provide guard,round and stick bit space */ + xm <<= 3; + ym <<= 3; + + if (xe > ye) { + /* have to shift y fraction right to align + */ + int s = xe - ye; + ym = XDPSRS(ym, s); + ye += s; + } else if (ye > xe) { + /* have to shift x fraction right to align + */ + int s = ye - xe; + xm = XDPSRS(xm, s); + xe += s; + } + assert(xe == ye); + assert(xe <= DP_EMAX); + + if (xs == ys) { + /* generate 28 bit result of adding two 27 bit numbers + * leaving result in xm,xs,xe + */ + xm = xm + ym; + xe = xe; + xs = xs; + + if (xm >> (DP_MBITS + 1 + 3)) { /* carry out */ + xm = XDPSRS1(xm); + xe++; + } + } else { + if (xm >= ym) { + xm = xm - ym; + xe = xe; + xs = xs; + } else { + xm = ym - xm; + xe = xe; + xs = ys; + } + if (xm == 0) + return ieee754dp_zero(ieee754_csr.rm == + IEEE754_RD); + + /* normalize to rounding precision */ + while ((xm >> (DP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + + } + DPNORMRET2(xs, xe, xm, "add", x, y); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_cmp.c linux.ac/arch/mips/math-emu/dp_cmp.c --- linux.vanilla/arch/mips/math-emu/dp_cmp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_cmp.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,58 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cmp) +{ + CLEARCX; + + if (ieee754dp_isnan(x) || ieee754dp_isnan(y)) { + if (cmp & IEEE754_CUN) + return 1; + if (cmp & (IEEE754_CLT | IEEE754_CGT)) { + if (SETCX(IEEE754_INVALID_OPERATION)) + return ieee754si_xcpt(0, "fcmpf", x); + } + return 0; + } else { + long long int vx = x.bits; + long long int vy = y.bits; + + if (vx < 0) + vx = -vx ^ DP_SIGN_BIT; + if (vy < 0) + vy = -vy ^ DP_SIGN_BIT; + + if (vx < vy) + return (cmp & IEEE754_CLT) != 0; + else if (vx == vy) + return (cmp & IEEE754_CEQ) != 0; + else + return (cmp & IEEE754_CGT) != 0; + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_div.c linux.ac/arch/mips/math-emu/dp_div.c --- linux.vanilla/arch/mips/math-emu/dp_div.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_div.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,160 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y) +{ + COMPXDP; + COMPYDP; + + CLEARCX; + + EXPLODEXDP; + EXPLODEYDP; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "div", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y, "div", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x, "div", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754dp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Infinity handeling + */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + return ieee754dp_zero(xs ^ ys); + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + return ieee754dp_inf(xs ^ ys); + + /* Zero handeling + */ + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + SETCX(IEEE754_ZERO_DIVIDE); + return ieee754dp_xcpt(ieee754dp_inf(xs ^ ys), "div", x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return ieee754dp_zero(xs == ys ? 0 : 1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + DPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + /* provide rounding space */ + xm <<= 3; + ym <<= 3; + + { + /* now the dirty work */ + + unsigned long long rm = 0; + int re = xe - ye; + unsigned long long bm; + + for (bm = DP_MBIT(DP_MBITS + 2); bm; bm >>= 1) { + if (xm >= ym) { + xm -= ym; + rm |= bm; + if (xm == 0) + break; + } + xm <<= 1; + } + rm <<= 1; + if (xm) + rm |= 1; /* have remainder, set sticky */ + + assert(rm); + + /* normalise rm to rounding precision ? + */ + while ((rm >> (DP_MBITS + 3)) == 0) { + rm <<= 1; + re--; + } + + DPNORMRET2(xs == ys ? 0 : 1, re, rm, "div", x, y); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_fint.c linux.ac/arch/mips/math-emu/dp_fint.c --- linux.vanilla/arch/mips/math-emu/dp_fint.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_fint.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,78 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_fint(int x) +{ + COMPXDP; + + CLEARCX; + + if (x == 0) + return ieee754dp_zero(0); + if (x == 1 || x == -1) + return ieee754dp_one(x < 0); + if (x == 10 || x == -10) + return ieee754dp_ten(x < 0); + + xs = (x < 0); + if (xs) { + if (x == (1 << 31)) + xm = ((unsigned) 1 << 31); /* max neg can't be safely negated */ + else + xm = -x; + } else { + xm = x; + } + +#if 1 + /* normalize - result can never be inexact or overflow */ + xe = DP_MBITS; + while ((xm >> DP_MBITS) == 0) { + xm <<= 1; + xe--; + } + return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); +#else + /* normalize */ + xe = DP_MBITS + 3; + while ((xm >> (DP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + DPNORMRET1(xs, xe, xm, "fint", x); +#endif +} + +ieee754dp ieee754dp_funs(unsigned int u) +{ + if ((int) u < 0) + return ieee754dp_add(ieee754dp_1e31(), + ieee754dp_fint(u & ~(1 << 31))); + return ieee754dp_fint(u); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_flong.c linux.ac/arch/mips/math-emu/dp_flong.c --- linux.vanilla/arch/mips/math-emu/dp_flong.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_flong.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,76 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_flong(long long x) +{ + COMPXDP; + + CLEARCX; + + if (x == 0) + return ieee754dp_zero(0); + if (x == 1 || x == -1) + return ieee754dp_one(x < 0); + if (x == 10 || x == -10) + return ieee754dp_ten(x < 0); + + xs = (x < 0); + if (xs) { + if (x == (1ULL << 63)) + xm = (1ULL << 63); /* max neg can't be safely negated */ + else + xm = -x; + } else { + xm = x; + } + + /* normalize */ + xe = DP_MBITS + 3; + if (xm >> (DP_MBITS + 1 + 3)) { + /* shunt out overflow bits */ + while (xm >> (DP_MBITS + 1 + 3)) { + XDPSRSX1(); + } + } else { + /* normalize in grs extended double precision */ + while ((xm >> (DP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + } + DPNORMRET1(xs, xe, xm, "dp_flong", x); +} + +ieee754dp ieee754dp_fulong(unsigned long long u) +{ + if ((long long) u < 0) + return ieee754dp_add(ieee754dp_1e63(), + ieee754dp_flong(u & ~(1ULL << 63))); + return ieee754dp_flong(u); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_frexp.c linux.ac/arch/mips/math-emu/dp_frexp.c --- linux.vanilla/arch/mips/math-emu/dp_frexp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_frexp.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,53 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +/* close to ieeep754dp_logb +*/ +ieee754dp ieee754dp_frexp(ieee754dp x, int *eptr) +{ + COMPXDP; + CLEARCX; + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_INF: + case IEEE754_CLASS_ZERO: + *eptr = 0; + return x; + case IEEE754_CLASS_DNORM: + DPDNORMX; + break; + case IEEE754_CLASS_NORM: + break; + } + *eptr = xe + 1; + return builddp(xs, -1 + DP_EBIAS, xm & ~DP_HIDDEN_BIT); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_fsp.c linux.ac/arch/mips/math-emu/dp_fsp.c --- linux.vanilla/arch/mips/math-emu/dp_fsp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_fsp.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,70 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_fsp(ieee754sp x) +{ + COMPXSP; + + CLEARCX; + + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_SNAN: + return ieee754dp_nanxcpt(builddp(xs, + DP_EMAX + 1 + DP_EBIAS, + ((unsigned long long) xm + << (DP_MBITS - + SP_MBITS))), "fsp", + x); + case IEEE754_CLASS_INF: + return ieee754dp_inf(xs); + case IEEE754_CLASS_ZERO: + return ieee754dp_zero(xs); + case IEEE754_CLASS_DNORM: + /* normalize */ + while ((xm >> SP_MBITS) == 0) { + xm <<= 1; + xe--; + } + break; + case IEEE754_CLASS_NORM: + break; + } + + /* CANT possibly overflow,underflow, or need rounding + */ + + /* drop the hidden bit */ + xm &= ~SP_HIDDEN_BIT; + + return builddp(xs, xe + DP_EBIAS, + (unsigned long long) xm << (DP_MBITS - SP_MBITS)); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_logb.c linux.ac/arch/mips/math-emu/dp_logb.c --- linux.vanilla/arch/mips/math-emu/dp_logb.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_logb.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,54 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_logb(ieee754dp x) +{ + COMPXDP; + + CLEARCX; + + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + return ieee754dp_nanxcpt(x, "logb", x); + case IEEE754_CLASS_QNAN: + return x; + case IEEE754_CLASS_INF: + return ieee754dp_inf(0); + case IEEE754_CLASS_ZERO: + return ieee754dp_inf(1); + case IEEE754_CLASS_DNORM: + DPDNORMX; + break; + case IEEE754_CLASS_NORM: + break; + } + return ieee754dp_fint(xe); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_modf.c linux.ac/arch/mips/math-emu/dp_modf.c --- linux.vanilla/arch/mips/math-emu/dp_modf.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_modf.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,80 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +/* modf function is always exact for a finite number +*/ +ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp * ip) +{ + COMPXDP; + + CLEARCX; + + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_INF: + case IEEE754_CLASS_ZERO: + *ip = x; + return x; + case IEEE754_CLASS_DNORM: + /* far to small */ + *ip = ieee754dp_zero(xs); + return x; + case IEEE754_CLASS_NORM: + break; + } + if (xe < 0) { + *ip = ieee754dp_zero(xs); + return x; + } + if (xe >= DP_MBITS) { + *ip = x; + return ieee754dp_zero(xs); + } + /* generate ipart mantissa by clearing bottom bits + */ + *ip = builddp(xs, xe + DP_EBIAS, + ((xm >> (DP_MBITS - xe)) << (DP_MBITS - xe)) & + ~DP_HIDDEN_BIT); + + /* generate fpart mantissa by clearing top bits + * and normalizing (must be able to normalize) + */ + xm = (xm << (64 - (DP_MBITS - xe))) >> (64 - (DP_MBITS - xe)); + if (xm == 0) + return ieee754dp_zero(xs); + + while ((xm >> DP_MBITS) == 0) { + xm <<= 1; + xe--; + } + return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_mul.c linux.ac/arch/mips/math-emu/dp_mul.c --- linux.vanilla/arch/mips/math-emu/dp_mul.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_mul.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,180 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y) +{ + COMPXDP; + COMPYDP; + + CLEARCX; + + EXPLODEXDP; + EXPLODEYDP; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "mul", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y, "mul", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x, "mul", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754dp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Infinity handeling */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_xcpt(ieee754dp_indef(), "mul", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + return ieee754dp_inf(xs ^ ys); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return ieee754dp_zero(xs ^ ys); + + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + DPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + /* rm = xm * ym, re = xe+ye basicly */ + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + { + int re = xe + ye; + int rs = xs ^ ys; + unsigned long long rm; + + /* shunt to top of word */ + xm <<= 64 - (DP_MBITS + 1); + ym <<= 64 - (DP_MBITS + 1); + + /* multiply 32bits xm,ym to give high 32bits rm with stickness + */ + + /* 32 * 32 => 64 */ +#define DPXMULT(x,y) ((unsigned long long)(x) * (unsigned long long)y) + + { + unsigned lxm = xm; + unsigned hxm = xm >> 32; + unsigned lym = ym; + unsigned hym = ym >> 32; + unsigned long long lrm; + unsigned long long hrm; + + lrm = DPXMULT(lxm, lym); + hrm = DPXMULT(hxm, hym); + + { + unsigned long long t = DPXMULT(lxm, hym); + { + unsigned long long at = + lrm + (t << 32); + hrm += at < lrm; + lrm = at; + } + hrm = hrm + (t >> 32); + } + + { + unsigned long long t = DPXMULT(hxm, lym); + { + unsigned long long at = + lrm + (t << 32); + hrm += at < lrm; + lrm = at; + } + hrm = hrm + (t >> 32); + } + rm = hrm | (lrm != 0); + } + + /* + * sticky shift down to normal rounding precision + */ + if ((signed long long) rm < 0) { + rm = + (rm >> (64 - (DP_MBITS + 1 + 3))) | + ((rm << (DP_MBITS + 1 + 3)) != 0); + re++; + } else { + rm = + (rm >> (64 - (DP_MBITS + 1 + 3 + 1))) | + ((rm << (DP_MBITS + 1 + 3 + 1)) != 0); + } + assert(rm & (DP_HIDDEN_BIT << 3)); + DPNORMRET2(rs, re, rm, "mul", x, y); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_scalb.c linux.ac/arch/mips/math-emu/dp_scalb.c --- linux.vanilla/arch/mips/math-emu/dp_scalb.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_scalb.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,58 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_scalb(ieee754dp x, int n) +{ + COMPXDP; + + CLEARCX; + + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + return ieee754dp_nanxcpt(x, "scalb", x, n); + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_INF: + case IEEE754_CLASS_ZERO: + return x; + case IEEE754_CLASS_DNORM: + DPDNORMX; + break; + case IEEE754_CLASS_NORM: + break; + } + DPNORMRET2(xs, xe + n, xm << 3, "scalb", x, n); +} + + +ieee754dp ieee754dp_ldexp(ieee754dp x, int n) +{ + return ieee754dp_scalb(x, n); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_simple.c linux.ac/arch/mips/math-emu/dp_simple.c --- linux.vanilla/arch/mips/math-emu/dp_simple.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_simple.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,66 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +int ieee754dp_finite(ieee754dp x) +{ + return DPBEXP(x) != DP_EMAX + 1 + DP_EBIAS; +} + +ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y) +{ + CLEARCX; + DPSIGN(x) = DPSIGN(y); + return x; +} + + +ieee754dp ieee754dp_neg(ieee754dp x) +{ + CLEARCX; + + if (ieee754dp_isnan(x)) /* but not infinity */ + return ieee754dp_nanxcpt(x, "neg", x); + + /* quick fix up */ + DPSIGN(x) ^= 1; + return x; +} + + +ieee754dp ieee754dp_abs(ieee754dp x) +{ + CLEARCX; + + if (ieee754dp_isnan(x)) /* but not infinity */ + return ieee754dp_nanxcpt(x, "abs", x); + + /* quick fix up */ + DPSIGN(x) = 0; + return x; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_sqrt.c linux.ac/arch/mips/math-emu/dp_sqrt.c --- linux.vanilla/arch/mips/math-emu/dp_sqrt.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_sqrt.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,167 @@ +/* IEEE754 floating point arithmetic + * double precision square root + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +static const struct ieee754dp_konst knan = { +#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__) + 0, 0, DP_EBIAS + DP_EMAX + 1, 0 +#else + 0, DP_EBIAS + DP_EMAX + 1, 0, 0 +#endif +}; + +#define nan ((ieee754dp)knan) + +static const unsigned table[] = { + 0, 1204, 3062, 5746, 9193, 13348, 18162, 23592, + 29598, 36145, 43202, 50740, 58733, 67158, 75992, + 85215, 83599, 71378, 60428, 50647, 41945, 34246, + 27478, 21581, 16499, 12183, 8588, 5674, 3403, + 1742, 661, 130 +}; + +ieee754dp ieee754dp_sqrt(ieee754dp x) +{ + struct ieee754_csr oldcsr; + ieee754dp y, z, t; + unsigned scalx, yh; + COMPXDP; + + EXPLODEXDP; + + /* x == INF or NAN? */ + switch (xc) { + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_SNAN: + /* sqrt(Nan) = Nan */ + return ieee754dp_nanxcpt(x, "sqrt"); + case IEEE754_CLASS_ZERO: + /* sqrt(0) = 0 */ + return x; + case IEEE754_CLASS_INF: + if (xs) + /* sqrt(-Inf) = Nan */ + return ieee754dp_nanxcpt(nan, "sqrt"); + /* sqrt(+Inf) = Inf */ + return x; + case IEEE754_CLASS_DNORM: + DPDNORMX; + /* fall through */ + case IEEE754_CLASS_NORM: + if (xs) + /* sqrt(-x) = Nan */ + return ieee754dp_nanxcpt(nan, "sqrt"); + break; + } + + /* save old csr; switch off INX enable & flag; set RN rounding */ + oldcsr = ieee754_csr; + ieee754_csr.mx &= ~IEEE754_INEXACT; + ieee754_csr.sx &= ~IEEE754_INEXACT; + ieee754_csr.rm = IEEE754_RN; + + /* adjust exponent to prevent overflow */ + scalx = 0; + if (xe > 512) { /* x > 2**-512? */ + xe -= 512; /* x = x / 2**512 */ + scalx += 256; + } else if (xe < -512) { /* x < 2**-512? */ + xe += 512; /* x = x * 2**512 */ + scalx -= 256; + } + + y = x = builddp(0, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); + + /* magic initial approximation to almost 8 sig. bits */ + yh = y.bits >> 32; + yh = (yh >> 1) + 0x1ff80000; + yh = yh - table[(yh >> 15) & 31]; + y.bits = ((unsigned long long) yh << 32) | (y.bits & 0xffffffff); + + /* Heron's rule once with correction to improve to ~18 sig. bits */ + /* t=x/y; y=y+t; py[n0]=py[n0]-0x00100006; py[n1]=0; */ + t = ieee754dp_div(x, y); + y = ieee754dp_add(y, t); + y.bits -= 0x0010000600000000LL; + y.bits &= 0xffffffff00000000LL; + + /* triple to almost 56 sig. bits: y ~= sqrt(x) to within 1 ulp */ + /* t=y*y; z=t; pt[n0]+=0x00100000; t+=z; z=(x-z)*y; */ + z = t = ieee754dp_mul(y, y); + t.parts.bexp += 0x001; + t = ieee754dp_add(t, z); + z = ieee754dp_mul(ieee754dp_sub(x, z), y); + + /* t=z/(t+x) ; pt[n0]+=0x00100000; y+=t; */ + t = ieee754dp_div(z, ieee754dp_add(t, x)); + t.parts.bexp += 0x001; + y = ieee754dp_add(y, t); + + /* twiddle last bit to force y correctly rounded */ + + /* set RZ, clear INEX flag */ + ieee754_csr.rm = IEEE754_RZ; + ieee754_csr.sx &= ~IEEE754_INEXACT; + + /* t=x/y; ...chopped quotient, possibly inexact */ + t = ieee754dp_div(x, y); + + if (ieee754_csr.sx & IEEE754_INEXACT || t.bits != y.bits) { + + if (!(ieee754_csr.sx & IEEE754_INEXACT)) + /* t = t-ulp */ + t.bits -= 1; + + /* add inexact to result status */ + oldcsr.cx |= IEEE754_INEXACT; + oldcsr.sx |= IEEE754_INEXACT; + + switch (oldcsr.rm) { + case IEEE754_RP: + y.bits += 1; + /* drop through */ + case IEEE754_RN: + t.bits += 1; + break; + } + + /* y=y+t; ...chopped sum */ + y = ieee754dp_add(y, t); + + /* adjust scalx for correctly rounded sqrt(x) */ + scalx -= 1; + } + + /* py[n0]=py[n0]+scalx; ...scale back y */ + y.parts.bexp += scalx; + + /* restore rounding mode, possibly set inexact */ + ieee754_csr = oldcsr; + + return y; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_sub.c linux.ac/arch/mips/math-emu/dp_sub.c --- linux.vanilla/arch/mips/math-emu/dp_sub.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_sub.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,193 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) +{ + COMPXDP; + COMPYDP; + + CLEARCX; + + EXPLODEXDP; + EXPLODEYDP; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "sub", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y, "sub", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x, "sub", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754dp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Inifity handeling + */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + if (xs != ys) + return x; + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_xcpt(ieee754dp_indef(), "sub", x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + return ieee754dp_inf(ys ^ 1); + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + return x; + + /* Zero handeling + */ + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs != ys) + return x; + else + return ieee754dp_zero(ieee754_csr.rm == + IEEE754_RD); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return x; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + /* quick fix up */ + DPSIGN(y) ^= 1; + return y; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + /* FAAL THOROUGH */ + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + /* normalize ym,ye */ + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + /* normalize xm,xe */ + DPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + /* flip sign of y and handle as add */ + ys ^= 1; + + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + + /* provide guard,round and stick bit dpace */ + xm <<= 3; + ym <<= 3; + + if (xe > ye) { + /* have to shift y fraction right to align + */ + int s = xe - ye; + ym = XDPSRS(ym, s); + ye += s; + } else if (ye > xe) { + /* have to shift x fraction right to align + */ + int s = ye - xe; + xm = XDPSRS(xm, s); + xe += s; + } + assert(xe == ye); + assert(xe <= DP_EMAX); + + if (xs == ys) { + /* generate 28 bit result of adding two 27 bit numbers + */ + xm = xm + ym; + xe = xe; + xs = xs; + + if (xm >> (DP_MBITS + 1 + 3)) { /* carry out */ + xm = XDPSRS1(xm); /* shift preserving sticky */ + xe++; + } + } else { + if (xm >= ym) { + xm = xm - ym; + xe = xe; + xs = xs; + } else { + xm = ym - xm; + xe = xe; + xs = ys; + } + if (xm == 0) + if (ieee754_csr.rm == IEEE754_RD) + return ieee754dp_zero(1); /* round negative inf. => sign = -1 */ + else + return ieee754dp_zero(0); /* other round modes => sign = 1 */ + + /* normalize to rounding precision + */ + while ((xm >> (DP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + } + DPNORMRET2(xs, xe, xm, "sub", x, y); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_tint.c linux.ac/arch/mips/math-emu/dp_tint.c --- linux.vanilla/arch/mips/math-emu/dp_tint.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_tint.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,88 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include <linux/kernel.h> +#include "ieee754dp.h" + +int ieee754dp_tint(ieee754dp x) +{ + COMPXDP; + + CLEARCX; + + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + SETCX(IEEE754_INVALID_OPERATION); + return ieee754si_xcpt(ieee754si_indef(), "fixdp", x); + case IEEE754_CLASS_INF: + SETCX(IEEE754_OVERFLOW); + return ieee754si_xcpt(ieee754si_indef(), "fixdp", x); + case IEEE754_CLASS_ZERO: + return 0; + case IEEE754_CLASS_DNORM: /* much to small */ + SETCX(IEEE754_UNDERFLOW); + return ieee754si_xcpt(0, "fixdp", x); + case IEEE754_CLASS_NORM: + break; + } + if (xe >= 31) { + SETCX(IEEE754_OVERFLOW); + return ieee754si_xcpt(ieee754si_indef(), "fix", x); + } + if (xe < 0) { + SETCX(IEEE754_UNDERFLOW); + return ieee754si_xcpt(0, "fix", x); + } + /* oh gawd */ + if (xe > DP_MBITS) { + xm <<= xe - DP_MBITS; + } else if (xe < DP_MBITS) { + /* XXX no rounding + */ + xm >>= DP_MBITS - xe; + } + if (xs) + return -xm; + else + return xm; +} + + +unsigned int ieee754dp_tuns(ieee754dp x) +{ + ieee754dp hb = ieee754dp_1e31(); + + /* what if x < 0 ?? */ + if (ieee754dp_lt(x, hb)) + return (unsigned) ieee754dp_tint(x); + + return (unsigned) ieee754dp_tint(ieee754dp_sub(x, hb)) | + ((unsigned) 1 << 31); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_tlong.c linux.ac/arch/mips/math-emu/dp_tlong.c --- linux.vanilla/arch/mips/math-emu/dp_tlong.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_tlong.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,141 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +long long ieee754dp_tlong(ieee754dp x) +{ + COMPXDP; + + CLEARCX; + + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + SETCX(IEEE754_INVALID_OPERATION); + return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); + case IEEE754_CLASS_INF: + SETCX(IEEE754_OVERFLOW); + return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); + case IEEE754_CLASS_ZERO: + return 0; + case IEEE754_CLASS_DNORM: /* much too small */ + SETCX(IEEE754_UNDERFLOW); + return ieee754di_xcpt(0, "dp_tlong", x); + case IEEE754_CLASS_NORM: + break; + } + if (xe >= 63) { + SETCX(IEEE754_OVERFLOW); + return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); + } + if (xe < 0) { + if (ieee754_csr.rm == IEEE754_RU) { + if (xs) { /* Negative */ + return 0x0000000000000000LL; + } else { /* Positive */ + return 0x0000000000000001LL; + } + } else if (ieee754_csr.rm == IEEE754_RD) { + if (xs) { /* Negative , return -1 */ + return 0xffffffffffffffffLL; + } else { /* Positive */ + return 0x0000000000000000LL; + } + } else { + SETCX(IEEE754_UNDERFLOW); + return ieee754di_xcpt(0, "dp_tlong", x); + } + } + /* oh gawd */ + if (xe > DP_MBITS) { + xm <<= xe - DP_MBITS; + } else if (xe < DP_MBITS) { + unsigned long long residue; + unsigned long long mask = 0; + int i; + int round; + int sticky; + int odd; + + /* compute mask */ + for (i = 0; i < DP_MBITS - xe; i++) { + mask = mask << 1; + mask = mask | 0x1; + } + residue = (xm & mask) << (64 - (DP_MBITS - xe)); + round = + ((0x8000000000000000LL & residue) != + 0x0000000000000000LL); + sticky = + ((0x7fffffffffffffffLL & residue) != + 0x0000000000000000LL); + + xm >>= DP_MBITS - xe; + + odd = ((xm & 0x1) != 0x0000000000000000LL); + + /* Do the rounding */ + if (!round && sticky) { + if ((ieee754_csr.rm == IEEE754_RU && !xs) + || (ieee754_csr.rm == IEEE754_RD && xs)) { + xm++; + } + } else if (round && !sticky) { + if ((ieee754_csr.rm == IEEE754_RU && !xs) + || (ieee754_csr.rm == IEEE754_RD && xs) + || (ieee754_csr.rm == IEEE754_RN && odd)) { + xm++; + } + } else if (round && sticky) { + if ((ieee754_csr.rm == IEEE754_RU && !xs) + || (ieee754_csr.rm == IEEE754_RD && xs) + || (ieee754_csr.rm == IEEE754_RN)) { + xm++; + } + } + } + if (xs) + return -xm; + else + return xm; +} + + +unsigned long long ieee754dp_tulong(ieee754dp x) +{ + ieee754dp hb = ieee754dp_1e63(); + + /* what if x < 0 ?? */ + if (ieee754dp_lt(x, hb)) + return (unsigned long long) ieee754dp_tlong(x); + + return (unsigned long long) ieee754dp_tlong(ieee754dp_sub(x, hb)) | + (1ULL << 63); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/ieee754.c linux.ac/arch/mips/math-emu/ieee754.c --- linux.vanilla/arch/mips/math-emu/ieee754.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/ieee754.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,138 @@ +/* ieee754 floating point arithmetic + * single and double precision + * + * BUGS + * not much dp done + * doesnt generate IEEE754_INEXACT + * + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754int.h" + +#define DP_EBIAS 1023 +#define DP_EMIN (-1022) +#define DP_EMAX 1023 + +#define SP_EBIAS 127 +#define SP_EMIN (-126) +#define SP_EMAX 127 + +/* indexed by class */ +const char *const ieee754_cname[] = { + "Normal", + "Zero", + "Denormal", + "Infinity", + "QNaN", + "SNaN", +}; + +/* the control status register +*/ +struct ieee754_csr ieee754_csr; + +/* special constants +*/ + + +#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__) +#define SPSTR(s,b,m) {m,b,s} +#define DPSTR(s,b,mh,ml) {ml,mh,b,s} +#endif + +#ifdef __MIPSEB__ +#define SPSTR(s,b,m) {s,b,m} +#define DPSTR(s,b,mh,ml) {s,b,mh,ml} +#endif + +const struct ieee754dp_konst __ieee754dp_spcvals[] = { + DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 0), /* + zero */ + DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 0), /* - zero */ + DPSTR(0, DP_EBIAS, 0, 0), /* + 1.0 */ + DPSTR(1, DP_EBIAS, 0, 0), /* - 1.0 */ + DPSTR(0, 3 + DP_EBIAS, 0x40000, 0), /* + 10.0 */ + DPSTR(1, 3 + DP_EBIAS, 0x40000, 0), /* - 10.0 */ + DPSTR(0, DP_EMAX + 1 + DP_EBIAS, 0, 0), /* + infinity */ + DPSTR(1, DP_EMAX + 1 + DP_EBIAS, 0, 0), /* - infinity */ + DPSTR(0, DP_EMAX + 1 + DP_EBIAS, 0x40000, 0), /* + indef quiet Nan */ + DPSTR(0, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF), /* + max */ + DPSTR(1, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF), /* - max */ + DPSTR(0, DP_EMIN + DP_EBIAS, 0, 0), /* + min normal */ + DPSTR(1, DP_EMIN + DP_EBIAS, 0, 0), /* - min normal */ + DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 1), /* + min denormal */ + DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 1), /* - min denormal */ + DPSTR(0, 31 + DP_EBIAS, 0, 0), /* + 1.0e31 */ + DPSTR(0, 63 + DP_EBIAS, 0, 0), /* + 1.0e63 */ +}; + +const struct ieee754sp_konst __ieee754sp_spcvals[] = { + SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 0), /* + zero */ + SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 0), /* - zero */ + SPSTR(0, SP_EBIAS, 0), /* + 1.0 */ + SPSTR(1, SP_EBIAS, 0), /* - 1.0 */ + SPSTR(0, 3 + SP_EBIAS, 0x200000), /* + 10.0 */ + SPSTR(1, 3 + SP_EBIAS, 0x200000), /* - 10.0 */ + SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0), /* + infinity */ + SPSTR(1, SP_EMAX + 1 + SP_EBIAS, 0), /* - infinity */ + SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0x200000), /* + indef quiet Nan */ + SPSTR(0, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* + max normal */ + SPSTR(1, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* - max normal */ + SPSTR(0, SP_EMIN + SP_EBIAS, 0), /* + min normal */ + SPSTR(1, SP_EMIN + SP_EBIAS, 0), /* - min normal */ + SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 1), /* + min denormal */ + SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 1), /* - min denormal */ + SPSTR(0, 31 + SP_EBIAS, 0), /* + 1.0e31 */ + SPSTR(0, 63 + SP_EBIAS, 0), /* + 1.0e63 */ +}; + + +int ieee754si_xcpt(int r, const char *op, ...) +{ + struct ieee754xctx ax; + + if (!TSTX()) + return r; + ax.op = op; + ax.rt = IEEE754_RT_SI; + ax.rv.si = r; + va_start(ax.ap, op); + ieee754_xcpt(&ax); + return ax.rv.si; +} + +long long ieee754di_xcpt(long long r, const char *op, ...) +{ + struct ieee754xctx ax; + + if (!TSTX()) + return r; + ax.op = op; + ax.rt = IEEE754_RT_DI; + ax.rv.di = r; + va_start(ax.ap, op); + ieee754_xcpt(&ax); + return ax.rv.di; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/ieee754.h linux.ac/arch/mips/math-emu/ieee754.h --- linux.vanilla/arch/mips/math-emu/ieee754.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/ieee754.h Tue Apr 3 17:54:32 2001 @@ -0,0 +1,490 @@ +/* single and double precision fp ops + * missing extended precision. +*/ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + */ + +/************************************************************************** + * Nov 7, 2000 + * Modification to allow integration with Linux kernel + * + * Kevin D. Kissell, kevink@mips.com and Carsten Langgard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + *************************************************************************/ + +#ifdef __KERNEL__ +/* Going from Algorithmics to Linux native environment, add this */ +#include <linux/types.h> + +/* + * Not very pretty, but the Linux kernel's normal va_list definition + * does not allow it to be used as a structure element, as it is here. + */ +#ifndef _STDARG_H +#include <stdarg.h> +#endif + +#else + +/* Note that __KERNEL__ is taken to mean Linux kernel */ + +#if #system(OpenBSD) +#include <machine/types.h> +#endif +#include <machine/endian.h> + +#endif /* __KERNEL__ */ + +#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__) +struct ieee754dp_konst { + unsigned mantlo:32; + unsigned manthi:20; + unsigned bexp:11; + unsigned sign:1; +}; +struct ieee754sp_konst { + unsigned mant:23; + unsigned bexp:8; + unsigned sign:1; +}; + +typedef union _ieee754dp { + struct ieee754dp_konst oparts; + struct { + unsigned long long mant:52; + unsigned int bexp:11; + unsigned int sign:1; + } parts; + unsigned long long bits; + double d; +} ieee754dp; + +typedef union _ieee754sp { + struct ieee754sp_konst parts; + float f; + unsigned long bits; +} ieee754sp; +#endif + +#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__) +struct ieee754dp_konst { + unsigned sign:1; + unsigned bexp:11; + unsigned manthi:20; + unsigned mantlo:32; +}; +typedef union _ieee754dp { + struct ieee754dp_konst oparts; + struct { + unsigned int sign:1; + unsigned int bexp:11; + unsigned long long mant:52; + } parts; + double d; + unsigned long long bits; +} ieee754dp; + +struct ieee754sp_konst { + unsigned sign:1; + unsigned bexp:8; + unsigned mant:23; +}; + +typedef union _ieee754sp { + struct ieee754sp_konst parts; + float f; + unsigned long bits; +} ieee754sp; +#endif + +/* + * single precision (often aka float) +*/ +int ieee754sp_finite(ieee754sp x); +int ieee754sp_class(ieee754sp x); + +ieee754sp ieee754sp_abs(ieee754sp x); +ieee754sp ieee754sp_neg(ieee754sp x); +ieee754sp ieee754sp_scalb(ieee754sp x, int); +ieee754sp ieee754sp_logb(ieee754sp x); + +/* x with sign of y */ +ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y); + +ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y); +ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y); +ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y); +ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y); + +ieee754sp ieee754sp_fint(int x); +ieee754sp ieee754sp_funs(unsigned x); +ieee754sp ieee754sp_flong(long long x); +ieee754sp ieee754sp_fulong(unsigned long long x); +ieee754sp ieee754sp_fdp(ieee754dp x); + +int ieee754sp_tint(ieee754sp x); +unsigned int ieee754sp_tuns(ieee754sp x); +long long ieee754sp_tlong(ieee754sp x); +unsigned long long ieee754sp_tulong(ieee754sp x); + +int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cop); +/* + * basic sp math + */ +ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp * ip); +ieee754sp ieee754sp_frexp(ieee754sp x, int *exp); +ieee754sp ieee754sp_ldexp(ieee754sp x, int exp); + +ieee754sp ieee754sp_ceil(ieee754sp x); +ieee754sp ieee754sp_floor(ieee754sp x); +ieee754sp ieee754sp_trunc(ieee754sp x); + +ieee754sp ieee754sp_sqrt(ieee754sp x); + +/* + * double precision (often aka double) +*/ +int ieee754dp_finite(ieee754dp x); +int ieee754dp_class(ieee754dp x); + +/* x with sign of y */ +ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y); + +ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y); +ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y); +ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y); +ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y); + +ieee754dp ieee754dp_abs(ieee754dp x); +ieee754dp ieee754dp_neg(ieee754dp x); +ieee754dp ieee754dp_scalb(ieee754dp x, int); + +/* return exponent as integer in floating point format + */ +ieee754dp ieee754dp_logb(ieee754dp x); + +ieee754dp ieee754dp_fint(int x); +ieee754dp ieee754dp_funs(unsigned x); +ieee754dp ieee754dp_flong(long long x); +ieee754dp ieee754dp_fulong(unsigned long long x); +ieee754dp ieee754dp_fsp(ieee754sp x); + +ieee754dp ieee754dp_ceil(ieee754dp x); +ieee754dp ieee754dp_floor(ieee754dp x); +ieee754dp ieee754dp_trunc(ieee754dp x); + +int ieee754dp_tint(ieee754dp x); +unsigned int ieee754dp_tuns(ieee754dp x); +long long ieee754dp_tlong(ieee754dp x); +unsigned long long ieee754dp_tulong(ieee754dp x); + +int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cop); +/* + * basic sp math + */ +ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp * ip); +ieee754dp ieee754dp_frexp(ieee754dp x, int *exp); +ieee754dp ieee754dp_ldexp(ieee754dp x, int exp); + +ieee754dp ieee754dp_ceil(ieee754dp x); +ieee754dp ieee754dp_floor(ieee754dp x); +ieee754dp ieee754dp_trunc(ieee754dp x); + +ieee754dp ieee754dp_sqrt(ieee754dp x); + + + +/* 5 types of floating point number +*/ +#define IEEE754_CLASS_NORM 0x00 +#define IEEE754_CLASS_ZERO 0x01 +#define IEEE754_CLASS_DNORM 0x02 +#define IEEE754_CLASS_INF 0x03 +#define IEEE754_CLASS_SNAN 0x04 +#define IEEE754_CLASS_QNAN 0x05 +extern const char *const ieee754_cname[]; + +/* exception numbers */ +#define IEEE754_INEXACT 0x01 +#define IEEE754_UNDERFLOW 0x02 +#define IEEE754_OVERFLOW 0x04 +#define IEEE754_ZERO_DIVIDE 0x08 +#define IEEE754_INVALID_OPERATION 0x10 + +/* cmp operators +*/ +#define IEEE754_CLT 0x01 +#define IEEE754_CEQ 0x02 +#define IEEE754_CGT 0x04 +#define IEEE754_CUN 0x08 + +/* rounding mode +*/ +#define IEEE754_RN 0 /* round to nearest */ +#define IEEE754_RZ 1 /* round toward zero */ +#define IEEE754_RD 2 /* round toward -Infinity */ +#define IEEE754_RU 3 /* round toward +Infinity */ + +/* other naming */ +#define IEEE754_RM IEEE754_RD +#define IEEE754_RP IEEE754_RU + +/* "normal" comparisons +*/ +static __inline int ieee754sp_eq(ieee754sp x, ieee754sp y) +{ + return ieee754sp_cmp(x, y, IEEE754_CEQ); +} + +static __inline int ieee754sp_ne(ieee754sp x, ieee754sp y) +{ + return ieee754sp_cmp(x, y, + IEEE754_CLT | IEEE754_CGT | IEEE754_CUN); +} + +static __inline int ieee754sp_lt(ieee754sp x, ieee754sp y) +{ + return ieee754sp_cmp(x, y, IEEE754_CLT); +} + +static __inline int ieee754sp_le(ieee754sp x, ieee754sp y) +{ + return ieee754sp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ); +} + +static __inline int ieee754sp_gt(ieee754sp x, ieee754sp y) +{ + return ieee754sp_cmp(x, y, IEEE754_CGT); +} + + +static __inline int ieee754sp_ge(ieee754sp x, ieee754sp y) +{ + return ieee754sp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ); +} + +static __inline int ieee754dp_eq(ieee754dp x, ieee754dp y) +{ + return ieee754dp_cmp(x, y, IEEE754_CEQ); +} + +static __inline int ieee754dp_ne(ieee754dp x, ieee754dp y) +{ + return ieee754dp_cmp(x, y, + IEEE754_CLT | IEEE754_CGT | IEEE754_CUN); +} + +static __inline int ieee754dp_lt(ieee754dp x, ieee754dp y) +{ + return ieee754dp_cmp(x, y, IEEE754_CLT); +} + +static __inline int ieee754dp_le(ieee754dp x, ieee754dp y) +{ + return ieee754dp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ); +} + +static __inline int ieee754dp_gt(ieee754dp x, ieee754dp y) +{ + return ieee754dp_cmp(x, y, IEEE754_CGT); +} + +static __inline int ieee754dp_ge(ieee754dp x, ieee754dp y) +{ + return ieee754dp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ); +} + + +/* like strtod +*/ +ieee754dp ieee754dp_fstr(const char *s, char **endp); +char *ieee754dp_tstr(ieee754dp x, int prec, int fmt, int af); + + +/* the control status register +*/ +struct ieee754_csr { + unsigned pad:13; + unsigned noq:1; /* set 1 for no quiet NaN's */ + unsigned nod:1; /* set 1 for no denormalised numbers */ + unsigned cx:5; /* exceptions this operation */ + unsigned mx:5; /* exception enable mask */ + unsigned sx:5; /* exceptions total */ + unsigned rm:2; /* current rounding mode */ +}; +extern struct ieee754_csr ieee754_csr; + +static __inline unsigned ieee754_getrm(void) +{ + return (ieee754_csr.rm); +} +static __inline unsigned ieee754_setrm(unsigned rm) +{ + return (ieee754_csr.rm = rm); +} + +/* + * get current exceptions + */ +static __inline unsigned ieee754_getcx(void) +{ + return (ieee754_csr.cx); +} + +/* test for current exception condition + */ +static __inline int ieee754_cxtest(unsigned n) +{ + return (ieee754_csr.cx & n); +} + +/* + * get sticky exceptions + */ +static __inline unsigned ieee754_getsx(void) +{ + return (ieee754_csr.sx); +} + +/* clear sticky conditions +*/ +static __inline unsigned ieee754_clrsx(void) +{ + return (ieee754_csr.sx = 0); +} + +/* test for sticky exception condition + */ +static __inline int ieee754_sxtest(unsigned n) +{ + return (ieee754_csr.sx & n); +} + +/* debugging */ +ieee754sp ieee754sp_dump(char *s, ieee754sp x); +ieee754dp ieee754dp_dump(char *s, ieee754dp x); + +#define IEEE754_SPCVAL_PZERO 0 +#define IEEE754_SPCVAL_NZERO 1 +#define IEEE754_SPCVAL_PONE 2 +#define IEEE754_SPCVAL_NONE 3 +#define IEEE754_SPCVAL_PTEN 4 +#define IEEE754_SPCVAL_NTEN 5 +#define IEEE754_SPCVAL_PINFINITY 6 +#define IEEE754_SPCVAL_NINFINITY 7 +#define IEEE754_SPCVAL_INDEF 8 +#define IEEE754_SPCVAL_PMAX 9 /* +max norm */ +#define IEEE754_SPCVAL_NMAX 10 /* -max norm */ +#define IEEE754_SPCVAL_PMIN 11 /* +min norm */ +#define IEEE754_SPCVAL_NMIN 12 /* +min norm */ +#define IEEE754_SPCVAL_PMIND 13 /* +min denorm */ +#define IEEE754_SPCVAL_NMIND 14 /* +min denorm */ +#define IEEE754_SPCVAL_P1E31 15 /* + 1.0e31 */ +#define IEEE754_SPCVAL_P1E63 16 /* + 1.0e63 */ + +extern const struct ieee754dp_konst __ieee754dp_spcvals[]; +extern const struct ieee754sp_konst __ieee754sp_spcvals[]; +#define ieee754dp_spcvals ((const ieee754dp *)__ieee754dp_spcvals) +#define ieee754sp_spcvals ((const ieee754sp *)__ieee754sp_spcvals) + +/* return infinity with given sign +*/ +#define ieee754dp_inf(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)]) +#define ieee754dp_zero(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PZERO+(sn)]) +#define ieee754dp_one(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PONE+(sn)]) +#define ieee754dp_ten(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PTEN+(sn)]) +#define ieee754dp_indef() \ + (ieee754dp_spcvals[IEEE754_SPCVAL_INDEF]) +#define ieee754dp_max(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PMAX+(sn)]) +#define ieee754dp_min(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PMIN+(sn)]) +#define ieee754dp_mind(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PMIND+(sn)]) +#define ieee754dp_1e31() \ + (ieee754dp_spcvals[IEEE754_SPCVAL_P1E31]) +#define ieee754dp_1e63() \ + (ieee754dp_spcvals[IEEE754_SPCVAL_P1E63]) + +#define ieee754sp_inf(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)]) +#define ieee754sp_zero(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PZERO+(sn)]) +#define ieee754sp_one(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PONE+(sn)]) +#define ieee754sp_ten(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PTEN+(sn)]) +#define ieee754sp_indef() \ + (ieee754sp_spcvals[IEEE754_SPCVAL_INDEF]) +#define ieee754sp_max(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PMAX+(sn)]) +#define ieee754sp_min(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PMIN+(sn)]) +#define ieee754sp_mind(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PMIND+(sn)]) +#define ieee754sp_1e31() \ + (ieee754sp_spcvals[IEEE754_SPCVAL_P1E31]) +#define ieee754sp_1e63() \ + (ieee754sp_spcvals[IEEE754_SPCVAL_P1E63]) + +/* indefinite integer value +*/ +#define ieee754si_indef() INT_MIN +#ifdef LONG_LONG_MIN +#define ieee754di_indef() LONG_LONG_MIN +#else +#define ieee754di_indef() (-9223372036854775807LL-1) +#endif + +/* IEEE exception context, passed to handler */ +struct ieee754xctx { + const char *op; /* operation name */ + int rt; /* result type */ + union { + ieee754sp sp; /* single precision */ + ieee754dp dp; /* double precision */ +#ifdef IEEE854_XP + ieee754xp xp; /* extended precision */ +#endif + int si; /* standard signed integer (32bits) */ + long long di; /* extended signed integer (64bits) */ + } rv; /* default result format implied by op */ + va_list ap; +}; + +/* result types for xctx.rt */ +#define IEEE754_RT_SP 0 +#define IEEE754_RT_DP 1 +#define IEEE754_RT_XP 2 +#define IEEE754_RT_SI 3 +#define IEEE754_RT_DI 4 + +extern void ieee754_xcpt(struct ieee754xctx *xcp); + +/* compat */ +#define ieee754dp_fix(x) ieee754dp_tint(x) +#define ieee754sp_fix(x) ieee754sp_tint(x) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/ieee754d.c linux.ac/arch/mips/math-emu/ieee754d.c --- linux.vanilla/arch/mips/math-emu/ieee754d.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/ieee754d.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,142 @@ +/* some debug functions +*/ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + */ + +/************************************************************************** + * Nov 7, 2000 + * Modified to build and operate in Linux kernel environment. + * + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + *************************************************************************/ + +#include "ieee754.h" + +#define DP_EBIAS 1023 +#define DP_EMIN (-1022) +#define DP_EMAX 1023 +#define DP_FBITS 52 + +#define SP_EBIAS 127 +#define SP_EMIN (-126) +#define SP_EMAX 127 +#define SP_FBITS 23 + +#define DP_MBIT(x) ((unsigned long long)1 << (x)) +#define DP_HIDDEN_BIT DP_MBIT(DP_FBITS) +#define DP_SIGN_BIT DP_MBIT(63) + + +#define SP_MBIT(x) ((unsigned long)1 << (x)) +#define SP_HIDDEN_BIT SP_MBIT(SP_FBITS) +#define SP_SIGN_BIT SP_MBIT(31) + + +#define SPSIGN(sp) (sp.parts.sign) +#define SPBEXP(sp) (sp.parts.bexp) +#define SPMANT(sp) (sp.parts.mant) + +#define DPSIGN(dp) (dp.parts.sign) +#define DPBEXP(dp) (dp.parts.bexp) +#define DPMANT(dp) (dp.parts.mant) + +ieee754dp ieee754dp_dump(char *m, ieee754dp x) +{ + int i; + + printk("%s", m); + printk("<%08x,%08x>\n", (unsigned) (x.bits >> 32), + (unsigned) x.bits); + printk("\t="); + switch (ieee754dp_class(x)) { + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_SNAN: + printk("Nan %c", DPSIGN(x) ? '-' : '+'); + for (i = DP_FBITS - 1; i >= 0; i--) + printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0'); + break; + case IEEE754_CLASS_INF: + printk("%cInfinity", DPSIGN(x) ? '-' : '+'); + break; + case IEEE754_CLASS_ZERO: + printk("%cZero", DPSIGN(x) ? '-' : '+'); + break; + case IEEE754_CLASS_DNORM: + printk("%c0.", DPSIGN(x) ? '-' : '+'); + for (i = DP_FBITS - 1; i >= 0; i--) + printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0'); + printk("e%d", DPBEXP(x) - DP_EBIAS); + break; + case IEEE754_CLASS_NORM: + printk("%c1.", DPSIGN(x) ? '-' : '+'); + for (i = DP_FBITS - 1; i >= 0; i--) + printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0'); + printk("e%d", DPBEXP(x) - DP_EBIAS); + break; + default: + printk("Illegal/Unknown IEEE754 value class"); + } + printk("\n"); + return x; +} + +ieee754sp ieee754sp_dump(char *m, ieee754sp x) +{ + int i; + + printk("%s=", m); + printk("<%08x>\n", (unsigned) x.bits); + printk("\t="); + switch (ieee754sp_class(x)) { + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_SNAN: + printk("Nan %c", SPSIGN(x) ? '-' : '+'); + for (i = SP_FBITS - 1; i >= 0; i--) + printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0'); + break; + case IEEE754_CLASS_INF: + printk("%cInfinity", SPSIGN(x) ? '-' : '+'); + break; + case IEEE754_CLASS_ZERO: + printk("%cZero", SPSIGN(x) ? '-' : '+'); + break; + case IEEE754_CLASS_DNORM: + printk("%c0.", SPSIGN(x) ? '-' : '+'); + for (i = SP_FBITS - 1; i >= 0; i--) + printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0'); + printk("e%d", SPBEXP(x) - SP_EBIAS); + break; + case IEEE754_CLASS_NORM: + printk("%c1.", SPSIGN(x) ? '-' : '+'); + for (i = SP_FBITS - 1; i >= 0; i--) + printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0'); + printk("e%d", SPBEXP(x) - SP_EBIAS); + break; + default: + printk("Illegal/Unknown IEEE754 value class"); + } + printk("\n"); + return x; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/ieee754dp.c linux.ac/arch/mips/math-emu/ieee754dp.c --- linux.vanilla/arch/mips/math-emu/ieee754dp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/ieee754dp.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,197 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +int ieee754dp_class(ieee754dp x) +{ + COMPXDP; + EXPLODEXDP; + return xc; +} + +int ieee754dp_isnan(ieee754dp x) +{ + return ieee754dp_class(x) >= IEEE754_CLASS_SNAN; +} + +int ieee754dp_issnan(ieee754dp x) +{ + assert(ieee754dp_isnan(x)); + if (ieee754_csr.noq) + return 1; + return !(DPMANT(x) & DP_MBIT(DP_MBITS - 1)); +} + + +ieee754dp ieee754dp_xcpt(ieee754dp r, const char *op, ...) +{ + struct ieee754xctx ax; + if (!TSTX()) + return r; + + ax.op = op; + ax.rt = IEEE754_RT_DP; + ax.rv.dp = r; + va_start(ax.ap, op); + ieee754_xcpt(&ax); + return ax.rv.dp; +} + +ieee754dp ieee754dp_nanxcpt(ieee754dp r, const char *op, ...) +{ + struct ieee754xctx ax; + + assert(ieee754dp_isnan(r)); + + if (!ieee754dp_issnan(r)) /* QNAN does not cause invalid op !! */ + return r; + + if (!SETCX(IEEE754_INVALID_OPERATION)) { + /* not enabled convert to a quiet NaN */ + if (ieee754_csr.noq) + return r; + DPMANT(r) |= DP_MBIT(DP_MBITS - 1); + return r; + } + + ax.op = op; + ax.rt = 0; + ax.rv.dp = r; + va_start(ax.ap, op); + ieee754_xcpt(&ax); + return ax.rv.dp; +} + +ieee754dp ieee754dp_bestnan(ieee754dp x, ieee754dp y) +{ + assert(ieee754dp_isnan(x)); + assert(ieee754dp_isnan(y)); + + if (DPMANT(x) > DPMANT(y)) + return x; + else + return y; +} + + +/* generate a normal/denormal number with over,under handeling + * sn is sign + * xe is an unbiased exponent + * xm is 3bit extended precision value. + */ +ieee754dp ieee754dp_format(int sn, int xe, unsigned long long xm) +{ + assert(xm); /* we dont gen exact zeros (probably should) */ + + assert((xm >> (DP_MBITS + 1 + 3)) == 0); /* no execess */ + assert(xm & (DP_HIDDEN_BIT << 3)); + + if (xe < DP_EMIN) { + /* strip lower bits */ + int es = DP_EMIN - xe; + + if (ieee754_csr.nod) { + SETCX(IEEE754_UNDERFLOW); + return ieee754dp_zero(sn); + } + + /* sticky right shift es bits + */ + xm = XDPSRS(xm, es); + xe += es; + + assert((xm & (DP_HIDDEN_BIT << 3)) == 0); + assert(xe == DP_EMIN); + } + if (xm & (DP_MBIT(3) - 1)) { + SETCX(IEEE754_INEXACT); + /* inexact must round of 3 bits + */ + switch (ieee754_csr.rm) { + case IEEE754_RZ: + break; + case IEEE754_RN: + xm += 0x3 + ((xm >> 3) & 1); + /* xm += (xm&0x8)?0x4:0x3 */ + break; + case IEEE754_RU: /* toward +Infinity */ + if (!sn) /* ?? */ + xm += 0x8; + break; + case IEEE754_RD: /* toward -Infinity */ + if (sn) /* ?? */ + xm += 0x8; + break; + } + /* adjust exponent for rounding add overflowing + */ + if (xm >> (DP_MBITS + 3 + 1)) { /* add causes mantissa overflow */ + xm >>= 1; + xe++; + } + } + /* strip grs bits */ + xm >>= 3; + + assert((xm >> (DP_MBITS + 1)) == 0); /* no execess */ + assert(xe >= DP_EMIN); + + if (xe > DP_EMAX) { + SETCX(IEEE754_OVERFLOW); + /* -O can be table indexed by (rm,sn) */ + switch (ieee754_csr.rm) { + case IEEE754_RN: + return ieee754dp_inf(sn); + case IEEE754_RZ: + return ieee754dp_max(sn); + case IEEE754_RU: /* toward +Infinity */ + if (sn == 0) + return ieee754dp_inf(0); + else + return ieee754dp_max(1); + case IEEE754_RD: /* toward -Infinity */ + if (sn == 0) + return ieee754dp_max(0); + else + return ieee754dp_inf(1); + } + } + /* gen norm/denorm/zero */ + + if ((xm & DP_HIDDEN_BIT) == 0) { + /* we underflow (tiny/zero) */ + assert(xe == DP_EMIN); + SETCX(IEEE754_UNDERFLOW); + return builddp(sn, DP_EMIN - 1 + DP_EBIAS, xm); + } else { + assert((xm >> (DP_MBITS + 1)) == 0); /* no execess */ + assert(xm & DP_HIDDEN_BIT); + + return builddp(sn, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/ieee754dp.h linux.ac/arch/mips/math-emu/ieee754dp.h --- linux.vanilla/arch/mips/math-emu/ieee754dp.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/ieee754dp.h Tue Apr 3 17:54:32 2001 @@ -0,0 +1,83 @@ +/* + * IEEE754 floating point + * double precision internal header file + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754int.h" + +#define assert(expr) ((void)0) + +/* 3bit extended double precision sticky right shift */ +#define XDPSRS(v,rs) \ + ((rs > (DP_MBITS+3))?1:((v) >> (rs)) | ((v) << (64-(rs)) != 0)) + +#define XDPSRSX1() \ + (xe++, (xm = (xm >> 1) | (xm & 1))) + +#define XDPSRS1(v) \ + (((v) >> 1) | ((v) & 1)) + +/* convert denormal to normalized with extended exponent */ +#define DPDNORMx(m,e) \ + while( (m >> DP_MBITS) == 0) { m <<= 1; e--; } +#define DPDNORMX DPDNORMx(xm,xe) +#define DPDNORMY DPDNORMx(ym,ye) + +static __inline ieee754dp builddp(int s, int bx, unsigned long long m) +{ + ieee754dp r; + + assert((s) == 0 || (s) == 1); + assert((bx) >= DP_EMIN - 1 + DP_EBIAS + && (bx) <= DP_EMAX + 1 + DP_EBIAS); + assert(((m) >> DP_MBITS) == 0); + + r.parts.sign = s; + r.parts.bexp = bx; + r.parts.mant = m; + return r; +} + +extern int ieee754dp_isnan(ieee754dp); +extern int ieee754dp_issnan(ieee754dp); +extern int ieee754si_xcpt(int, const char *, ...); +extern long long ieee754di_xcpt(long long, const char *, ...); +extern ieee754dp ieee754dp_xcpt(ieee754dp, const char *, ...); +extern ieee754dp ieee754dp_nanxcpt(ieee754dp, const char *, ...); +extern ieee754dp ieee754dp_bestnan(ieee754dp, ieee754dp); +extern ieee754dp ieee754dp_format(int, int, unsigned long long); + + +#define DPNORMRET2(s,e,m,name,a0,a1) \ +{ \ + ieee754dp V = ieee754dp_format(s,e,m); \ + if(TSTX()) \ + return ieee754dp_xcpt(V,name,a0,a1); \ + else \ + return V; \ +} + +#define DPNORMRET1(s,e,m,name,a0) DPNORMRET2(s,e,m,name,a0,a0) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/ieee754int.h linux.ac/arch/mips/math-emu/ieee754int.h --- linux.vanilla/arch/mips/math-emu/ieee754int.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/ieee754int.h Tue Apr 3 17:54:32 2001 @@ -0,0 +1,135 @@ +/* + * IEEE754 floating point + * common internal header file + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754.h" + +#define DP_EBIAS 1023 +#define DP_EMIN (-1022) +#define DP_EMAX 1023 +#define DP_MBITS 52 + +#define SP_EBIAS 127 +#define SP_EMIN (-126) +#define SP_EMAX 127 +#define SP_MBITS 23 + +#define DP_MBIT(x) ((unsigned long long)1 << (x)) +#define DP_HIDDEN_BIT DP_MBIT(DP_MBITS) +#define DP_SIGN_BIT DP_MBIT(63) + +#define SP_MBIT(x) ((unsigned long)1 << (x)) +#define SP_HIDDEN_BIT SP_MBIT(SP_MBITS) +#define SP_SIGN_BIT SP_MBIT(31) + + +#define SPSIGN(sp) (sp.parts.sign) +#define SPBEXP(sp) (sp.parts.bexp) +#define SPMANT(sp) (sp.parts.mant) + +#define DPSIGN(dp) (dp.parts.sign) +#define DPBEXP(dp) (dp.parts.bexp) +#define DPMANT(dp) (dp.parts.mant) + +#define CLPAIR(x,y) ((x)*6+(y)) + +#define CLEARCX \ + (ieee754_csr.cx = 0) + +#define SETCX(x) \ + (ieee754_csr.cx |= (x),ieee754_csr.sx |= (x),ieee754_csr.mx & (x)) + +#define TSTX() \ + (ieee754_csr.cx & ieee754_csr.mx) + + +#define COMPXSP \ + unsigned xm; int xe; int xs; int xc + +#define COMPYSP \ + unsigned ym; int ye; int ys; int yc + +#define EXPLODESP(v,vc,vs,ve,vm) \ +{\ + vs = SPSIGN(v);\ + ve = SPBEXP(v);\ + vm = SPMANT(v);\ + if(ve == SP_EMAX+1+SP_EBIAS){\ + if(vm == 0)\ + vc = IEEE754_CLASS_INF;\ + else if(vm & SP_MBIT(SP_MBITS-1)) \ + vc = IEEE754_CLASS_QNAN;\ + else \ + vc = IEEE754_CLASS_SNAN;\ + } else if(ve == SP_EMIN-1+SP_EBIAS) {\ + if(vm) {\ + ve = SP_EMIN;\ + vc = IEEE754_CLASS_DNORM;\ + } else\ + vc = IEEE754_CLASS_ZERO;\ + } else {\ + ve -= SP_EBIAS;\ + vm |= SP_HIDDEN_BIT;\ + vc = IEEE754_CLASS_NORM;\ + }\ +} +#define EXPLODEXSP EXPLODESP(x,xc,xs,xe,xm) +#define EXPLODEYSP EXPLODESP(y,yc,ys,ye,ym) + + +#define COMPXDP \ +unsigned long long xm; int xe; int xs; int xc + +#define COMPYDP \ +unsigned long long ym; int ye; int ys; int yc + +#define EXPLODEDP(v,vc,vs,ve,vm) \ +{\ + vm = DPMANT(v);\ + vs = DPSIGN(v);\ + ve = DPBEXP(v);\ + if(ve == DP_EMAX+1+DP_EBIAS){\ + if(vm == 0)\ + vc = IEEE754_CLASS_INF;\ + else if(vm & DP_MBIT(DP_MBITS-1)) \ + vc = IEEE754_CLASS_QNAN;\ + else \ + vc = IEEE754_CLASS_SNAN;\ + } else if(ve == DP_EMIN-1+DP_EBIAS) {\ + if(vm) {\ + ve = DP_EMIN;\ + vc = IEEE754_CLASS_DNORM;\ + } else\ + vc = IEEE754_CLASS_ZERO;\ + } else {\ + ve -= DP_EBIAS;\ + vm |= DP_HIDDEN_BIT;\ + vc = IEEE754_CLASS_NORM;\ + }\ +} +#define EXPLODEXDP EXPLODEDP(x,xc,xs,xe,xm) +#define EXPLODEYDP EXPLODEDP(y,yc,ys,ye,ym) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/ieee754m.c linux.ac/arch/mips/math-emu/ieee754m.c --- linux.vanilla/arch/mips/math-emu/ieee754m.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/ieee754m.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,56 @@ +/* + * floor, trunc, ceil + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754.h" + +ieee754dp ieee754dp_floor(ieee754dp x) +{ + ieee754dp i; + + if (ieee754dp_lt(ieee754dp_modf(x, &i), ieee754dp_zero(0))) + return ieee754dp_sub(i, ieee754dp_one(0)); + else + return i; +} + +ieee754dp ieee754dp_ceil(ieee754dp x) +{ + ieee754dp i; + + if (ieee754dp_gt(ieee754dp_modf(x, &i), ieee754dp_zero(0))) + return ieee754dp_add(i, ieee754dp_one(0)); + else + return i; +} + +ieee754dp ieee754dp_trunc(ieee754dp x) +{ + ieee754dp i; + + (void) ieee754dp_modf(x, &i); + return i; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/ieee754sp.c linux.ac/arch/mips/math-emu/ieee754sp.c --- linux.vanilla/arch/mips/math-emu/ieee754sp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/ieee754sp.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,197 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +int ieee754sp_class(ieee754sp x) +{ + COMPXSP; + EXPLODEXSP; + return xc; +} + +int ieee754sp_isnan(ieee754sp x) +{ + return ieee754sp_class(x) >= IEEE754_CLASS_SNAN; +} + +int ieee754sp_issnan(ieee754sp x) +{ + assert(ieee754sp_isnan(x)); + if (ieee754_csr.noq) + return 1; + return !(SPMANT(x) & SP_MBIT(SP_MBITS - 1)); +} + + +ieee754sp ieee754sp_xcpt(ieee754sp r, const char *op, ...) +{ + struct ieee754xctx ax; + + if (!TSTX()) + return r; + + ax.op = op; + ax.rt = IEEE754_RT_SP; + ax.rv.sp = r; + va_start(ax.ap, op); + ieee754_xcpt(&ax); + return ax.rv.sp; +} + +ieee754sp ieee754sp_nanxcpt(ieee754sp r, const char *op, ...) +{ + struct ieee754xctx ax; + + assert(ieee754sp_isnan(r)); + + if (!ieee754sp_issnan(r)) /* QNAN does not cause invalid op !! */ + return r; + + if (!SETCX(IEEE754_INVALID_OPERATION)) { + /* not enabled convert to a quiet NaN */ + if (ieee754_csr.noq) + return r; + SPMANT(r) |= SP_MBIT(SP_MBITS - 1); + return r; + } + + ax.op = op; + ax.rt = 0; + ax.rv.sp = r; + va_start(ax.ap, op); + ieee754_xcpt(&ax); + return ax.rv.sp; +} + +ieee754sp ieee754sp_bestnan(ieee754sp x, ieee754sp y) +{ + assert(ieee754sp_isnan(x)); + assert(ieee754sp_isnan(y)); + + if (SPMANT(x) > SPMANT(y)) + return x; + else + return y; +} + + +/* generate a normal/denormal number with over,under handeling + * sn is sign + * xe is an unbiased exponent + * xm is 3bit extended precision value. + */ +ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) +{ + assert(xm); /* we dont gen exact zeros (probably should) */ + + assert((xm >> (SP_MBITS + 1 + 3)) == 0); /* no execess */ + assert(xm & (SP_HIDDEN_BIT << 3)); + + if (xe < SP_EMIN) { + /* strip lower bits */ + int es = SP_EMIN - xe; + + if (ieee754_csr.nod) { + SETCX(IEEE754_UNDERFLOW); + return ieee754sp_zero(sn); + } + + /* sticky right shift es bits + */ + SPXSRSXn(es); + + assert((xm & (SP_HIDDEN_BIT << 3)) == 0); + assert(xe == SP_EMIN); + } + if (xm & (SP_MBIT(3) - 1)) { + SETCX(IEEE754_INEXACT); + /* inexact must round of 3 bits + */ + switch (ieee754_csr.rm) { + case IEEE754_RZ: + break; + case IEEE754_RN: + xm += 0x3 + ((xm >> 3) & 1); + /* xm += (xm&0x8)?0x4:0x3 */ + break; + case IEEE754_RU: /* toward +Infinity */ + if (!sn) /* ?? */ + xm += 0x8; + break; + case IEEE754_RD: /* toward -Infinity */ + if (sn) /* ?? */ + xm += 0x8; + break; + } + /* adjust exponent for rounding add overflowing + */ + if (xm >> (SP_MBITS + 1 + 3)) { /* add causes mantissa overflow */ + xm >>= 1; + xe++; + } + } + /* strip grs bits */ + xm >>= 3; + + assert((xm >> (SP_MBITS + 1)) == 0); /* no execess */ + assert(xe >= SP_EMIN); + + if (xe > SP_EMAX) { + SETCX(IEEE754_OVERFLOW); + /* -O can be table indexed by (rm,sn) */ + switch (ieee754_csr.rm) { + case IEEE754_RN: + return ieee754sp_inf(sn); + case IEEE754_RZ: + return ieee754sp_max(sn); + case IEEE754_RU: /* toward +Infinity */ + if (sn == 0) + return ieee754sp_inf(0); + else + return ieee754sp_max(1); + case IEEE754_RD: /* toward -Infinity */ + if (sn == 0) + return ieee754sp_max(0); + else + return ieee754sp_inf(1); + } + } + /* gen norm/denorm/zero */ + + if ((xm & SP_HIDDEN_BIT) == 0) { + /* we underflow (tiny/zero) */ + assert(xe == SP_EMIN); + SETCX(IEEE754_UNDERFLOW); + return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm); + } else { + assert((xm >> (SP_MBITS + 1)) == 0); /* no execess */ + assert(xm & SP_HIDDEN_BIT); + + return buildsp(sn, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/ieee754sp.h linux.ac/arch/mips/math-emu/ieee754sp.h --- linux.vanilla/arch/mips/math-emu/ieee754sp.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/ieee754sp.h Tue Apr 3 17:54:32 2001 @@ -0,0 +1,89 @@ +/* + * IEEE754 floating point + * double precision internal header file + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754int.h" + +#define assert(expr) ((void)0) + +/* 3bit extended single precision sticky right shift */ +#define SPXSRSXn(rs) \ + (xe += rs, \ + xm = (rs > (SP_MBITS+3))?1:((xm) >> (rs)) | ((xm) << (32-(rs)) != 0)) + +#define SPXSRSX1() \ + (xe++, (xm = (xm >> 1) | (xm & 1))) + +#define SPXSRSYn(rs) \ + (ye+=rs, \ + ym = (rs > (SP_MBITS+3))?1:((ym) >> (rs)) | ((ym) << (32-(rs)) != 0)) + +#define SPXSRSY1() \ + (ye++, (ym = (ym >> 1) | (ym & 1))) + +/* convert denormal to normalized with extended exponent */ +#define SPDNORMx(m,e) \ + while( (m >> SP_MBITS) == 0) { m <<= 1; e--; } +#define SPDNORMX SPDNORMx(xm,xe) +#define SPDNORMY SPDNORMx(ym,ye) + +static __inline ieee754sp buildsp(int s, int bx, unsigned m) +{ + ieee754sp r; + + assert((s) == 0 || (s) == 1); + assert((bx) >= SP_EMIN - 1 + SP_EBIAS + && (bx) <= SP_EMAX + 1 + SP_EBIAS); + assert(((m) >> SP_MBITS) == 0); + + r.parts.sign = s; + r.parts.bexp = bx; + r.parts.mant = m; + + return r; +} + +extern int ieee754sp_isnan(ieee754sp); +extern int ieee754sp_issnan(ieee754sp); +extern int ieee754si_xcpt(int, const char *, ...); +extern long long ieee754di_xcpt(long long, const char *, ...); +extern ieee754sp ieee754sp_xcpt(ieee754sp, const char *, ...); +extern ieee754sp ieee754sp_nanxcpt(ieee754sp, const char *, ...); +extern ieee754sp ieee754sp_bestnan(ieee754sp, ieee754sp); +extern ieee754sp ieee754sp_format(int, int, unsigned); + + +#define SPNORMRET2(s,e,m,name,a0,a1) \ +{ \ + ieee754sp V = ieee754sp_format(s,e,m); \ + if(TSTX()) \ + return ieee754sp_xcpt(V,name,a0,a1); \ + else \ + return V; \ +} + +#define SPNORMRET1(s,e,m,name,a0) SPNORMRET2(s,e,m,name,a0,a0) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/ieee754xcpt.c linux.ac/arch/mips/math-emu/ieee754xcpt.c --- linux.vanilla/arch/mips/math-emu/ieee754xcpt.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/ieee754xcpt.c Tue Apr 3 17:54:32 2001 @@ -0,0 +1,48 @@ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + */ + +/************************************************************************** + * Nov 7, 2000 + * Added preprocessor hacks to map to Linux kernel diagnostics. + * + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + *************************************************************************/ + +#include "ieee754.h" + +/* + * Very naff exception handler (you can plug in your own and + * override this). + */ + +static const char *const rtnames[] = { + "sp", "dp", "xp", "si", "di" +}; + +void ieee754_xcpt(struct ieee754xctx *xcp) +{ + printk("floating point exception in \"%s\", type=%s\n", + xcp->op, rtnames[xcp->rt]); +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/kernel_linkage.c linux.ac/arch/mips/math-emu/kernel_linkage.c --- linux.vanilla/arch/mips/math-emu/kernel_linkage.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/kernel_linkage.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,95 @@ +/************************************************************************** + * + * arch/mips/math_emu/kernel_linkage.c + * + * Kevin D. Kissell, kevink@mips and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + *************************************************************************/ +/* + * Routines corresponding to Linux kernel FP context + * manipulation primitives for the Algorithmics MIPS + * FPU Emulator + */ + +#include <linux/sched.h> +#include <asm/processor.h> +#include <asm/signal.h> +#include <asm/uaccess.h> + +#include <asm/fpu_emulator.h> + +extern struct mips_fpu_emulator_private fpuemuprivate; + +#define SIGNALLING_NAN 0x7ff800007ff80000LL + +void fpu_emulator_init_fpu(void) +{ + static int first = 1; + int i; + + if (first) { + first = 0; + printk("Algorithmics/MIPS FPU Emulator v1.4\n"); + } + + current->thread.fpu.soft.sr = 0; + for (i = 0; i < 32; i++) { + current->thread.fpu.soft.regs[i] = SIGNALLING_NAN; + } +} + + +/* + * Emulator context save/restore to/from a signal context + * presumed to be on the user stack, and therefore accessed + * with appropriate macros from uaccess.h + */ + +int fpu_emulator_save_context(struct sigcontext *sc) +{ + int i; + int err = 0; + + for (i = 0; i < 32; i++) { + err |= + __put_user(current->thread.fpu.soft.regs[i], + &sc->sc_fpregs[i]); + } + err |= __put_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr); + err |= __put_user(fpuemuprivate.eir, &sc->sc_fpc_eir); + + return err; +} + +int fpu_emulator_restore_context(struct sigcontext *sc) +{ + int i; + int err = 0; + + for (i = 0; i < 32; i++) { + err |= + __get_user(current->thread.fpu.soft.regs[i], + &sc->sc_fpregs[i]); + } + err |= __get_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr); + err |= __get_user(fpuemuprivate.eir, &sc->sc_fpc_eir); + + return err; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_add.c linux.ac/arch/mips/math-emu/sp_add.c --- linux.vanilla/arch/mips/math-emu/sp_add.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_add.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,180 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) +{ + COMPXSP; + COMPYSP; + + EXPLODEXSP; + EXPLODEYSP; + + CLEARCX; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "add", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y, "add", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x, "add", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754sp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Inifity handeling + */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + if (xs == ys) + return x; + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_xcpt(ieee754sp_indef(), "add", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + return y; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + return x; + + /* Zero handeling + */ + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + else + return ieee754sp_zero(ieee754_csr.rm == + IEEE754_RD); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return x; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return y; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + SPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + /* provide guard,round and stick bit space */ + xm <<= 3; + ym <<= 3; + + if (xe > ye) { + /* have to shift y fraction right to align + */ + int s = xe - ye; + SPXSRSYn(s); + } else if (ye > xe) { + /* have to shift x fraction right to align + */ + int s = ye - xe; + SPXSRSXn(s); + } + assert(xe == ye); + assert(xe <= SP_EMAX); + + if (xs == ys) { + /* generate 28 bit result of adding two 27 bit numbers + * leaving result in xm,xs,xe + */ + xm = xm + ym; + xe = xe; + xs = xs; + + if (xm >> (SP_MBITS + 1 + 3)) { /* carry out */ + SPXSRSX1(); + } + } else { + if (xm >= ym) { + xm = xm - ym; + xe = xe; + xs = xs; + } else { + xm = ym - xm; + xe = xe; + xs = ys; + } + if (xm == 0) + return ieee754sp_zero(ieee754_csr.rm == + IEEE754_RD); + + /* normalize in extended single precision */ + while ((xm >> (SP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + + } + SPNORMRET2(xs, xe, xm, "add", x, y); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_cmp.c linux.ac/arch/mips/math-emu/sp_cmp.c --- linux.vanilla/arch/mips/math-emu/sp_cmp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_cmp.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,58 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cmp) +{ + CLEARCX; + + if (ieee754sp_isnan(x) || ieee754sp_isnan(y)) { + if (cmp & IEEE754_CUN) + return 1; + if (cmp & (IEEE754_CLT | IEEE754_CGT)) { + if (SETCX(IEEE754_INVALID_OPERATION)) + return ieee754si_xcpt(0, "fcmpf", x); + } + return 0; + } else { + int vx = x.bits; + int vy = y.bits; + + if (vx < 0) + vx = -vx ^ SP_SIGN_BIT; + if (vy < 0) + vy = -vy ^ SP_SIGN_BIT; + + if (vx < vy) + return (cmp & IEEE754_CLT) != 0; + else if (vx == vy) + return (cmp & IEEE754_CEQ) != 0; + else + return (cmp & IEEE754_CGT) != 0; + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_div.c linux.ac/arch/mips/math-emu/sp_div.c --- linux.vanilla/arch/mips/math-emu/sp_div.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_div.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,160 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y) +{ + COMPXSP; + COMPYSP; + + CLEARCX; + + EXPLODEXSP; + EXPLODEYSP; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "div", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y, "div", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x, "div", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754sp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Infinity handeling + */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + return ieee754sp_zero(xs ^ ys); + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + return ieee754sp_inf(xs ^ ys); + + /* Zero handeling + */ + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + SETCX(IEEE754_ZERO_DIVIDE); + return ieee754sp_xcpt(ieee754sp_inf(xs ^ ys), "div", x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return ieee754sp_zero(xs == ys ? 0 : 1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + SPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + /* provide rounding space */ + xm <<= 3; + ym <<= 3; + + { + /* now the dirty work */ + + unsigned rm = 0; + int re = xe - ye; + unsigned bm; + + for (bm = SP_MBIT(SP_MBITS + 2); bm; bm >>= 1) { + if (xm >= ym) { + xm -= ym; + rm |= bm; + if (xm == 0) + break; + } + xm <<= 1; + } + rm <<= 1; + if (xm) + rm |= 1; /* have remainder, set sticky */ + + assert(rm); + + /* normalise rm to rounding precision ? + */ + while ((rm >> (SP_MBITS + 3)) == 0) { + rm <<= 1; + re--; + } + + SPNORMRET2(xs == ys ? 0 : 1, re, rm, "div", x, y); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_fdp.c linux.ac/arch/mips/math-emu/sp_fdp.c --- linux.vanilla/arch/mips/math-emu/sp_fdp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_fdp.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,69 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_fdp(ieee754dp x) +{ + COMPXDP; + + CLEARCX; + + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_SNAN: + return ieee754sp_nanxcpt(buildsp(xs, + SP_EMAX + 1 + SP_EBIAS, + (unsigned long) + (xm >> + (DP_MBITS - SP_MBITS))), + "fdp", x); + case IEEE754_CLASS_INF: + return ieee754sp_inf(xs); + case IEEE754_CLASS_ZERO: + return ieee754sp_zero(xs); + case IEEE754_CLASS_DNORM: + /* cant possibly be sp representable */ + SETCX(IEEE754_UNDERFLOW); + return ieee754sp_xcpt(ieee754sp_zero(xs), "fdp", x); + case IEEE754_CLASS_NORM: + break; + } + + { + unsigned long rm; + + /* convert from DP_MBITS to SP_MBITS+3 with sticky right shift + */ + rm = (xm >> (DP_MBITS - (SP_MBITS + 3))) | + ((xm << (64 - (DP_MBITS - (SP_MBITS + 3)))) != 0); + + SPNORMRET1(xs, xe, rm, "fdp", x); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_fint.c linux.ac/arch/mips/math-emu/sp_fint.c --- linux.vanilla/arch/mips/math-emu/sp_fint.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_fint.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,78 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_fint(int x) +{ + COMPXSP; + + CLEARCX; + + if (x == 0) + return ieee754sp_zero(0); + if (x == 1 || x == -1) + return ieee754sp_one(x < 0); + if (x == 10 || x == -10) + return ieee754sp_ten(x < 0); + + xs = (x < 0); + if (xs) { + if (x == (1 << 31)) + xm = ((unsigned) 1 << 31); /* max neg can't be safely negated */ + else + xm = -x; + } else { + xm = x; + } + xe = SP_MBITS + 3; + + if (xm >> (SP_MBITS + 1 + 3)) { + /* shunt out overflow bits + */ + while (xm >> (SP_MBITS + 1 + 3)) { + SPXSRSX1(); + } + } else { + /* normalize in grs extended single precision + */ + while ((xm >> (SP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + } + SPNORMRET1(xs, xe, xm, "fint", x); +} + + +ieee754sp ieee754sp_funs(unsigned int u) +{ + if ((int) u < 0) + return ieee754sp_add(ieee754sp_1e31(), + ieee754sp_fint(u & ~(1 << 31))); + return ieee754sp_fint(u); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_flong.c linux.ac/arch/mips/math-emu/sp_flong.c --- linux.vanilla/arch/mips/math-emu/sp_flong.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_flong.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,77 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_flong(long long x) +{ + COMPXDP; /* <--- need 64-bit mantissa temp */ + + CLEARCX; + + if (x == 0) + return ieee754sp_zero(0); + if (x == 1 || x == -1) + return ieee754sp_one(x < 0); + if (x == 10 || x == -10) + return ieee754sp_ten(x < 0); + + xs = (x < 0); + if (xs) { + if (x == (1ULL << 63)) + xm = (1ULL << 63); /* max neg can't be safely negated */ + else + xm = -x; + } else { + xm = x; + } + xe = SP_MBITS + 3; + + if (xm >> (SP_MBITS + 1 + 3)) { + /* shunt out overflow bits + */ + while (xm >> (SP_MBITS + 1 + 3)) { + SPXSRSX1(); + } + } else { + /* normalize in grs extended single precision */ + while ((xm >> (SP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + } + SPNORMRET1(xs, xe, xm, "sp_flong", x); +} + + +ieee754sp ieee754sp_fulong(unsigned long long u) +{ + if ((long long) u < 0) + return ieee754sp_add(ieee754sp_1e63(), + ieee754sp_flong(u & ~(1ULL << 63))); + return ieee754sp_flong(u); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_frexp.c linux.ac/arch/mips/math-emu/sp_frexp.c --- linux.vanilla/arch/mips/math-emu/sp_frexp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_frexp.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,53 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +/* close to ieeep754sp_logb +*/ +ieee754sp ieee754sp_frexp(ieee754sp x, int *eptr) +{ + COMPXSP; + CLEARCX; + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_INF: + case IEEE754_CLASS_ZERO: + *eptr = 0; + return x; + case IEEE754_CLASS_DNORM: + SPDNORMX; + break; + case IEEE754_CLASS_NORM: + break; + } + *eptr = xe + 1; + return buildsp(xs, -1 + SP_EBIAS, xm & ~SP_HIDDEN_BIT); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_logb.c linux.ac/arch/mips/math-emu/sp_logb.c --- linux.vanilla/arch/mips/math-emu/sp_logb.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_logb.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,54 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_logb(ieee754sp x) +{ + COMPXSP; + + CLEARCX; + + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + return ieee754sp_nanxcpt(x, "logb", x); + case IEEE754_CLASS_QNAN: + return x; + case IEEE754_CLASS_INF: + return ieee754sp_inf(0); + case IEEE754_CLASS_ZERO: + return ieee754sp_inf(1); + case IEEE754_CLASS_DNORM: + SPDNORMX; + break; + case IEEE754_CLASS_NORM: + break; + } + return ieee754sp_fint(xe); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_modf.c linux.ac/arch/mips/math-emu/sp_modf.c --- linux.vanilla/arch/mips/math-emu/sp_modf.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_modf.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,80 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +/* modf function is always exact for a finite number +*/ +ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp * ip) +{ + COMPXSP; + + CLEARCX; + + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_INF: + case IEEE754_CLASS_ZERO: + *ip = x; + return x; + case IEEE754_CLASS_DNORM: + /* far to small */ + *ip = ieee754sp_zero(xs); + return x; + case IEEE754_CLASS_NORM: + break; + } + if (xe < 0) { + *ip = ieee754sp_zero(xs); + return x; + } + if (xe >= SP_MBITS) { + *ip = x; + return ieee754sp_zero(xs); + } + /* generate ipart mantissa by clearing bottom bits + */ + *ip = buildsp(xs, xe + SP_EBIAS, + ((xm >> (SP_MBITS - xe)) << (SP_MBITS - xe)) & + ~SP_HIDDEN_BIT); + + /* generate fpart mantissa by clearing top bits + * and normalizing (must be able to normalize) + */ + xm = (xm << (32 - (SP_MBITS - xe))) >> (32 - (SP_MBITS - xe)); + if (xm == 0) + return ieee754sp_zero(xs); + + while ((xm >> SP_MBITS) == 0) { + xm <<= 1; + xe--; + } + return buildsp(xs, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_mul.c linux.ac/arch/mips/math-emu/sp_mul.c --- linux.vanilla/arch/mips/math-emu/sp_mul.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_mul.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,174 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y) +{ + COMPXSP; + COMPYSP; + + CLEARCX; + + EXPLODEXSP; + EXPLODEYSP; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "mul", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y, "mul", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x, "mul", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754sp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Infinity handeling */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_xcpt(ieee754sp_indef(), "mul", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + return ieee754sp_inf(xs ^ ys); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return ieee754sp_zero(xs ^ ys); + + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + SPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + /* rm = xm * ym, re = xe+ye basicly */ + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + { + int re = xe + ye; + int rs = xs ^ ys; + unsigned rm; + + /* shunt to top of word */ + xm <<= 32 - (SP_MBITS + 1); + ym <<= 32 - (SP_MBITS + 1); + + /* multiply 32bits xm,ym to give high 32bits rm with stickness + */ + { + unsigned short lxm = xm & 0xffff; + unsigned short hxm = xm >> 16; + unsigned short lym = ym & 0xffff; + unsigned short hym = ym >> 16; + unsigned lrm; + unsigned hrm; + + lrm = lxm * lym; /* 16 * 16 => 32 */ + hrm = hxm * hym; /* 16 * 16 => 32 */ + + { + unsigned t = lxm * hym; /* 16 * 16 => 32 */ + { + unsigned at = lrm + (t << 16); + hrm += at < lrm; + lrm = at; + } + hrm = hrm + (t >> 16); + } + + { + unsigned t = hxm * lym; /* 16 * 16 => 32 */ + { + unsigned at = lrm + (t << 16); + hrm += at < lrm; + lrm = at; + } + hrm = hrm + (t >> 16); + } + rm = hrm | (lrm != 0); + } + + /* + * sticky shift down to normal rounding precision + */ + if ((int) rm < 0) { + rm = (rm >> (32 - (SP_MBITS + 1 + 3))) | + ((rm << (SP_MBITS + 1 + 3)) != 0); + re++; + } else { + rm = (rm >> (32 - (SP_MBITS + 1 + 3 + 1))) | + ((rm << (SP_MBITS + 1 + 3 + 1)) != 0); + } + assert(rm & (SP_HIDDEN_BIT << 3)); + + SPNORMRET2(rs, re, rm, "mul", x, y); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_scalb.c linux.ac/arch/mips/math-emu/sp_scalb.c --- linux.vanilla/arch/mips/math-emu/sp_scalb.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_scalb.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,58 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_scalb(ieee754sp x, int n) +{ + COMPXSP; + + CLEARCX; + + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + return ieee754sp_nanxcpt(x, "scalb", x, n); + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_INF: + case IEEE754_CLASS_ZERO: + return x; + case IEEE754_CLASS_DNORM: + SPDNORMX; + break; + case IEEE754_CLASS_NORM: + break; + } + SPNORMRET2(xs, xe + n, xm << 3, "scalb", x, n); +} + + +ieee754sp ieee754sp_ldexp(ieee754sp x, int n) +{ + return ieee754sp_scalb(x, n); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_simple.c linux.ac/arch/mips/math-emu/sp_simple.c --- linux.vanilla/arch/mips/math-emu/sp_simple.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_simple.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,66 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +int ieee754sp_finite(ieee754sp x) +{ + return SPBEXP(x) != SP_EMAX + 1 + SP_EBIAS; +} + +ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y) +{ + CLEARCX; + SPSIGN(x) = SPSIGN(y); + return x; +} + + +ieee754sp ieee754sp_neg(ieee754sp x) +{ + CLEARCX; + + if (ieee754sp_isnan(x)) /* but not infinity */ + return ieee754sp_nanxcpt(x, "neg", x); + + /* quick fix up */ + SPSIGN(x) ^= 1; + return x; +} + + +ieee754sp ieee754sp_abs(ieee754sp x) +{ + CLEARCX; + + if (ieee754sp_isnan(x)) /* but not infinity */ + return ieee754sp_nanxcpt(x, "abs", x); + + /* quick fix up */ + SPSIGN(x) = 0; + return x; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_sqrt.c linux.ac/arch/mips/math-emu/sp_sqrt.c --- linux.vanilla/arch/mips/math-emu/sp_sqrt.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_sqrt.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,115 @@ +/* IEEE754 floating point arithmetic + * single precision square root + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +static const struct ieee754sp_konst knan = { + 0, SP_EBIAS + SP_EMAX + 1, 0 +}; + +#define nan ((ieee754sp)knan) + +ieee754sp ieee754sp_sqrt(ieee754sp x) +{ + int sign = (int) 0x80000000; + int ix, s, q, m, t, i; + unsigned int r; + COMPXDP; + + /* take care of Inf and NaN */ + + EXPLODEXDP; + + /* x == INF or NAN? */ + switch (xc) { + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_SNAN: + /* sqrt(Nan) = Nan */ + return ieee754sp_nanxcpt(x, "sqrt"); + case IEEE754_CLASS_ZERO: + /* sqrt(0) = 0 */ + return x; + case IEEE754_CLASS_INF: + if (xs) + /* sqrt(-Inf) = Nan */ + return ieee754sp_nanxcpt(nan, "sqrt"); + /* sqrt(+Inf) = Inf */ + return x; + case IEEE754_CLASS_DNORM: + case IEEE754_CLASS_NORM: + if (xs) + /* sqrt(-x) = Nan */ + return ieee754sp_nanxcpt(nan, "sqrt"); + break; + } + + ix = x.bits; + + /* normalize x */ + m = (ix >> 23); + if (m == 0) { /* subnormal x */ + for (i = 0; (ix & 0x00800000) == 0; i++) + ix <<= 1; + m -= i - 1; + } + m -= 127; /* unbias exponent */ + ix = (ix & 0x007fffff) | 0x00800000; + if (m & 1) /* odd m, double x to make it even */ + ix += ix; + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix += ix; + q = s = 0; /* q = sqrt(x) */ + r = 0x01000000; /* r = moving bit from right to left */ + + while (r != 0) { + t = s + r; + if (t <= ix) { + s = t + r; + ix -= t; + q += r; + } + ix += ix; + r >>= 1; + } + + if (ix != 0) { + switch (ieee754_csr.rm) { + case IEEE754_RP: + q += 2; + break; + case IEEE754_RN: + q += (q & 1); + break; + } + } + ix = (q >> 1) + 0x3f000000; + ix += (m << 23); + x.bits = ix; + return x; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_sub.c linux.ac/arch/mips/math-emu/sp_sub.c --- linux.vanilla/arch/mips/math-emu/sp_sub.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_sub.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,187 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) +{ + COMPXSP; + COMPYSP; + + CLEARCX; + + EXPLODEXSP; + EXPLODEYSP; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "sub", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y, "sub", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x, "sub", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754sp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Inifity handeling + */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + if (xs != ys) + return x; + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_xcpt(ieee754sp_indef(), "sub", x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + return ieee754sp_inf(ys ^ 1); + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + return x; + + /* Zero handeling + */ + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs != ys) + return x; + else + return ieee754sp_zero(ieee754_csr.rm == + IEEE754_RD); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return x; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + /* quick fix up */ + DPSIGN(y) ^= 1; + return y; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + SPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + /* flip sign of y and handle as add */ + ys ^= 1; + + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + + /* provide guard,round and stick bit space */ + xm <<= 3; + ym <<= 3; + + if (xe > ye) { + /* have to shift y fraction right to align + */ + int s = xe - ye; + SPXSRSYn(s); + } else if (ye > xe) { + /* have to shift x fraction right to align + */ + int s = ye - xe; + SPXSRSXn(s); + } + assert(xe == ye); + assert(xe <= SP_EMAX); + + if (xs == ys) { + /* generate 28 bit result of adding two 27 bit numbers + */ + xm = xm + ym; + xe = xe; + xs = xs; + + if (xm >> (SP_MBITS + 1 + 3)) { /* carry out */ + SPXSRSX1(); /* shift preserving sticky */ + } + } else { + if (xm >= ym) { + xm = xm - ym; + xe = xe; + xs = xs; + } else { + xm = ym - xm; + xe = xe; + xs = ys; + } + if (xm == 0) + if (ieee754_csr.rm == IEEE754_RD) + return ieee754sp_zero(1); /* round negative inf. => sign = -1 */ + else + return ieee754sp_zero(0); /* other round modes => sign = 1 */ + + /* normalize to rounding precision + */ + while ((xm >> (SP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + } + SPNORMRET2(xs, xe, xm, "sub", x, y); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_tint.c linux.ac/arch/mips/math-emu/sp_tint.c --- linux.vanilla/arch/mips/math-emu/sp_tint.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_tint.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,88 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include <linux/kernel.h> +#include "ieee754sp.h" + +int ieee754sp_tint(ieee754sp x) +{ + COMPXSP; + + CLEARCX; + + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + SETCX(IEEE754_INVALID_OPERATION); + return ieee754si_xcpt(ieee754si_indef(), "fixsp", x); + case IEEE754_CLASS_INF: + SETCX(IEEE754_OVERFLOW); + return ieee754si_xcpt(ieee754si_indef(), "fixsp", x); + case IEEE754_CLASS_ZERO: + return 0; + case IEEE754_CLASS_DNORM: /* much to small */ + SETCX(IEEE754_UNDERFLOW); + return ieee754si_xcpt(0, "fixsp", x); + case IEEE754_CLASS_NORM: + break; + } + if (xe >= 31) { + SETCX(IEEE754_OVERFLOW); + return ieee754si_xcpt(ieee754si_indef(), "fix", x); + } + if (xe < 0) { + SETCX(IEEE754_UNDERFLOW); + return ieee754si_xcpt(0, "fix", x); + } + /* oh gawd */ + if (xe > SP_MBITS) { + xm <<= xe - SP_MBITS; + } else if (xe < SP_MBITS) { + /* XXX no rounding + */ + xm >>= SP_MBITS - xe; + } + if (xs) + return -xm; + else + return xm; +} + + +unsigned int ieee754sp_tuns(ieee754sp x) +{ + ieee754sp hb = ieee754sp_1e31(); + + /* what if x < 0 ?? */ + if (ieee754sp_lt(x, hb)) + return (unsigned) ieee754sp_tint(x); + + return (unsigned) ieee754sp_tint(ieee754sp_sub(x, hb)) | + ((unsigned) 1 << 31); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_tlong.c linux.ac/arch/mips/math-emu/sp_tlong.c --- linux.vanilla/arch/mips/math-emu/sp_tlong.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_tlong.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,87 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +long long ieee754sp_tlong(ieee754sp x) +{ + COMPXDP; /* <-- need 64-bit mantissa tmp */ + + CLEARCX; + + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + SETCX(IEEE754_INVALID_OPERATION); + return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); + case IEEE754_CLASS_INF: + SETCX(IEEE754_OVERFLOW); + return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); + case IEEE754_CLASS_ZERO: + return 0; + case IEEE754_CLASS_DNORM: /* much to small */ + SETCX(IEEE754_UNDERFLOW); + return ieee754di_xcpt(0, "sp_tlong", x); + case IEEE754_CLASS_NORM: + break; + } + if (xe >= 63) { + SETCX(IEEE754_OVERFLOW); + return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); + } + if (xe < 0) { + SETCX(IEEE754_UNDERFLOW); + return ieee754di_xcpt(0, "sp_tlong", x); + } + /* oh gawd */ + if (xe > SP_MBITS) { + xm <<= xe - SP_MBITS; + } else if (xe < SP_MBITS) { + /* XXX no rounding + */ + xm >>= SP_MBITS - xe; + } + if (xs) + return -xm; + else + return xm; +} + + +unsigned long long ieee754sp_tulong(ieee754sp x) +{ + ieee754sp hb = ieee754sp_1e63(); + + /* what if x < 0 ?? */ + if (ieee754sp_lt(x, hb)) + return (unsigned long long) ieee754sp_tlong(x); + + return (unsigned long long) ieee754sp_tlong(ieee754sp_sub(x, hb)) | + (1ULL << 63); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/atlas/Makefile linux.ac/arch/mips/mips-boards/atlas/Makefile --- linux.vanilla/arch/mips/mips-boards/atlas/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/atlas/Makefile Tue Apr 3 17:54:33 2001 @@ -0,0 +1,42 @@ +# +# Carsten Langgaard, carstenl@mips.com +# Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. +# +# ######################################################################## +# +# This program is free software; you can distribute it and/or modify it +# under the terms of the GNU General Public License (Version 2) as +# published by the Free Software Foundation. +# +# This program is distributed in the hope 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. +# +# ####################################################################### +# +# Makefile for the MIPS Atlas specific kernel interface routines +# under Linux. +# +# 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.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: atlas.o + +O_TARGET := atlas.o + +obj-y := atlas_int.o atlas_rtc.o atlas_setup.o + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/atlas/atlas_int.c linux.ac/arch/mips/mips-boards/atlas/atlas_int.c --- linux.vanilla/arch/mips/mips-boards/atlas/atlas_int.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/atlas/atlas_int.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,248 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + * + * Routines for generic manipulation of the interrupts found on the MIPS + * Atlas board. + * + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/kernel_stat.h> + +#include <asm/irq.h> +#include <asm/mips-boards/atlas.h> +#include <asm/mips-boards/atlasint.h> +#include <asm/gdb-stub.h> + + +struct atlas_ictrl_regs *atlas_hw0_icregs + = (struct atlas_ictrl_regs *)ATLAS_ICTRL_REGS_BASE; + +extern asmlinkage void mipsIRQ(void); +extern void do_IRQ(int irq, struct pt_regs *regs); + +unsigned long spurious_count = 0; +irq_desc_t irq_desc[NR_IRQS]; + +#if 0 +#define DEBUG_INT(x...) printk(x) +#else +#define DEBUG_INT(x...) +#endif + +void disable_atlas_irq(unsigned int irq_nr) +{ + atlas_hw0_icregs->intrsten = (1 << irq_nr); +} + +void enable_atlas_irq(unsigned int irq_nr) +{ + atlas_hw0_icregs->intseten = (1 << irq_nr); +} + +static unsigned int startup_atlas_irq(unsigned int irq) +{ + enable_atlas_irq(irq); + return 0; /* never anything pending */ +} + +#define shutdown_atlas_irq disable_atlas_irq + +#define mask_and_ack_atlas_irq disable_atlas_irq + +static void end_atlas_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_atlas_irq(irq); +} + +static struct hw_interrupt_type atlas_irq_type = { + "Atlas", + startup_atlas_irq, + shutdown_atlas_irq, + enable_atlas_irq, + disable_atlas_irq, + mask_and_ack_atlas_irq, + end_atlas_irq, + NULL +}; + +int get_irq_list(char *buf) +{ + int i, len = 0; + int num = 0; + struct irqaction *action; + + for (i = 0; i < ATLASINT_END; i++, num++) { + action = irq_desc[i].action; + if (!action) + continue; + len += sprintf(buf+len, "%2d: %8d %c %s", + num, kstat.irqs[0][num], + (action->flags & SA_INTERRUPT) ? '+' : ' ', + action->name); + for (action=action->next; action; action = action->next) { + len += sprintf(buf+len, ",%s %s", + (action->flags & SA_INTERRUPT) ? " +" : "", + action->name); + } + len += sprintf(buf+len, " [hw0]\n"); + } + return len; +} + +int request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char * devname, + void *dev_id) +{ + struct irqaction *action; + + DEBUG_INT("request_irq: irq=%d, devname = %s\n", irq, devname); + + if (irq >= ATLASINT_END) + return -EINVAL; + if (!handler) + return -EINVAL; + + action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); + if(!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + action->dev_id = dev_id; + action->next = 0; + irq_desc[irq].action = action; + enable_atlas_irq(irq); + + return 0; +} + +void free_irq(unsigned int irq, void *dev_id) +{ + struct irqaction *action; + + if (irq >= ATLASINT_END) { + printk("Trying to free IRQ%d\n",irq); + return; + } + + action = irq_desc[irq].action; + irq_desc[irq].action = NULL; + disable_atlas_irq(irq); + kfree(action); +} + +static inline int ls1bit32(unsigned int x) +{ + int b = 31, s; + + s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s; + s = 8; if (x << 8 == 0) s = 0; b -= s; x <<= s; + s = 4; if (x << 4 == 0) s = 0; b -= s; x <<= s; + s = 2; if (x << 2 == 0) s = 0; b -= s; x <<= s; + s = 1; if (x << 1 == 0) s = 0; b -= s; + + return b; +} + +void atlas_hw0_irqdispatch(struct pt_regs *regs) +{ + struct irqaction *action; + unsigned long int_status; + int irq, cpu = smp_processor_id(); + + int_status = atlas_hw0_icregs->intstatus; + + /* if int_status == 0, then the interrupt has already been cleared */ + if (int_status == 0) + return; + + irq = ls1bit32(int_status); + action = irq_desc[irq].action; + + DEBUG_INT("atlas_hw0_irqdispatch: irq=%d\n", irq); + + /* if action == NULL, then we don't have a handler for the irq */ + if ( action == NULL ) { + printk("No handler for hw0 irq: %i\n", irq); + spurious_count++; + return; + } + + irq_enter(cpu, irq); + kstat.irqs[0][irq]++; + action->handler(irq, action->dev_id, regs); + irq_exit(cpu, irq); + + return; +} + +unsigned long probe_irq_on (void) +{ + return 0; +} + + +int probe_irq_off (unsigned long irqs) +{ + return 0; +} + +#ifdef CONFIG_REMOTE_DEBUG +extern void breakpoint(void); +extern int remote_debug; +#endif + +void __init init_IRQ(void) +{ + int i; + + /* + * Mask out all interrupt by writing "1" to all bit position in + * the interrupt reset reg. + */ + atlas_hw0_icregs->intrsten = 0xffffffff; + + /* Now safe to set the exception vector. */ + set_except_vector(0, mipsIRQ); + + for (i = 0; i <= ATLASINT_END; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = 0; + irq_desc[i].depth = 1; + irq_desc[i].handler = &atlas_irq_type; + } + +#ifdef CONFIG_REMOTE_DEBUG + if (remote_debug) { + set_debug_traps(); + breakpoint(); + } +#endif +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/atlas/atlas_rtc.c linux.ac/arch/mips/mips-boards/atlas/atlas_rtc.c --- linux.vanilla/arch/mips/mips-boards/atlas/atlas_rtc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/atlas/atlas_rtc.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,58 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + * + * RTC routines for Atlas style attached Dallas chip. + * + */ +#include <linux/spinlock.h> +#include <linux/mc146818rtc.h> +#include <asm/mips-boards/atlas.h> + + +static unsigned char atlas_rtc_read_data(unsigned long addr) +{ + volatile unsigned int *rtc_adr_reg = (void *)ATLAS_RTC_ADR_REG; + volatile unsigned int *rtc_dat_reg = (void *)ATLAS_RTC_DAT_REG; + + *rtc_adr_reg = addr; + + return *rtc_dat_reg; +} + +static void atlas_rtc_write_data(unsigned char data, unsigned long addr) +{ + volatile unsigned int *rtc_adr_reg = (void *)ATLAS_RTC_ADR_REG; + volatile unsigned int *rtc_dat_reg = (void *)ATLAS_RTC_DAT_REG; + + *rtc_adr_reg = addr; + *rtc_dat_reg = data; +} + +static int atlas_rtc_bcd_mode(void) +{ + return 0; +} + +struct rtc_ops atlas_rtc_ops = { + &atlas_rtc_read_data, + &atlas_rtc_write_data, + &atlas_rtc_bcd_mode +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/atlas/atlas_setup.c linux.ac/arch/mips/mips-boards/atlas/atlas_setup.c --- linux.vanilla/arch/mips/mips-boards/atlas/atlas_setup.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/atlas/atlas_setup.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,115 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * Atlas specific setup. + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/mc146818rtc.h> +#include <linux/ioport.h> + +#include <asm/cpu.h> +#include <asm/bootinfo.h> +#include <asm/irq.h> +#include <asm/mips-boards/generic.h> +#include <asm/mips-boards/prom.h> +#include <asm/gt64120.h> +#include <asm/mips-boards/atlasint.h> + +#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE) +extern void console_setup(char *, int *); +char serial_console[20]; +#endif + +#ifdef CONFIG_REMOTE_DEBUG +extern void rs_kgdb_hook(int); +extern void saa9730_kgdb_hook(void); +extern void breakpoint(void); +int remote_debug = 0; +#endif + +extern struct rtc_ops atlas_rtc_ops; + +extern void mips_reboot_setup(void); + +void __init atlas_setup(void) +{ +#ifdef CONFIG_REMOTE_DEBUG + int rs_putDebugChar(char); + char rs_getDebugChar(void); + int saa9730_putDebugChar(char); + char saa9730_getDebugChar(void); + extern int (*putDebugChar)(char); + extern char (*getDebugChar)(void); +#endif + char *argptr; + + ioport_resource.end = 0x7fffffff; + +#ifdef CONFIG_SERIAL_CONSOLE + argptr = prom_getcmdline(); + if ((argptr = strstr(argptr, "console=ttyS0")) == NULL) { + int i = 0; + char *s = prom_getenv("modetty0"); + while(s[i] >= '0' && s[i] <= '9') + i++; + strcpy(serial_console, "ttyS0,"); + strncpy(serial_console + 6, s, i); + prom_printf("Config serial console: %s\n", serial_console); + console_setup(serial_console, NULL); + } +#endif + +#ifdef CONFIG_REMOTE_DEBUG + argptr = prom_getcmdline(); + if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) { + int line; + argptr += strlen("kgdb=ttyS"); + if (*argptr != '0' && *argptr != '1') + printk("KGDB: Uknown serial line /dev/ttyS%c, " + "falling back to /dev/ttyS1\n", *argptr); + line = *argptr == '0' ? 0 : 1; + printk("KGDB: Using serial line /dev/ttyS%d for session\n", + line ? 1 : 0); + + if(line == 0) { + rs_kgdb_hook(line); + putDebugChar = rs_putDebugChar; + getDebugChar = rs_getDebugChar; + } else { + saa9730_kgdb_hook(); + putDebugChar = saa9730_putDebugChar; + getDebugChar = saa9730_getDebugChar; + } + + prom_printf("KGDB: Using serial line /dev/ttyS%d for session, " + "please connect your debugger\n", line ? 1 : 0); + + remote_debug = 1; + /* Breakpoints and stuff are in atlas_irq_setup() */ + } +#endif + argptr = prom_getcmdline(); + + if ((argptr = strstr(argptr, "nofpu")) != NULL) + mips_cpu.options &= ~MIPS_CPU_FPU; + + rtc_ops = &atlas_rtc_ops; + + mips_reboot_setup(); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/Makefile linux.ac/arch/mips/mips-boards/generic/Makefile --- linux.vanilla/arch/mips/mips-boards/generic/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/Makefile Tue Apr 3 17:54:33 2001 @@ -0,0 +1,41 @@ +# +# Carsten Langgaard, carstenl@mips.com +# Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. +# +# ######################################################################## +# +# This program is free software; you can distribute it and/or modify it +# under the terms of the GNU General Public License (Version 2) as +# published by the Free Software Foundation. +# +# This program is distributed in the hope 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. +# +# ####################################################################### +# +# Makefile for the MIPS boards generic routines under Linux. +# +# 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.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +O_TARGET := mipsboards.o + +obj-y := mipsIRQ.o pci.o reset.o display.o init.o \ + memory.o printf.o cmdline.o time.o +obj-$(CONFIG_REMOTE_DEBUG) += gdb_hook.o + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/cmdline.c linux.ac/arch/mips/mips-boards/generic/cmdline.c --- linux.vanilla/arch/mips/mips-boards/generic/cmdline.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/cmdline.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,53 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * Kernel command line creation using the prom monitor (YAMON) argc/argv. + */ +#include <linux/init.h> +#include <linux/string.h> + +#include <asm/bootinfo.h> + +extern int prom_argc; +extern char **prom_argv; + +char arcs_cmdline[COMMAND_LINE_SIZE]; + +char * __init prom_getcmdline(void) +{ + return &(arcs_cmdline[0]); +} + + +void __init prom_init_cmdline(void) +{ + char *cp; + int actr; + + actr = 1; /* Always ignore argv[0] */ + + cp = &(arcs_cmdline[0]); + while(actr < prom_argc) { + strcpy(cp, prom_argv[actr]); + cp += strlen(prom_argv[actr]); + *cp++ = ' '; + actr++; + } + if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ + --cp; + *cp = '\0'; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/display.c linux.ac/arch/mips/mips-boards/generic/display.c --- linux.vanilla/arch/mips/mips-boards/generic/display.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/display.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,47 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + * + * Display routines for display messages in MIPS boards ascii display. + * + */ + +#include <asm/mips-boards/generic.h> + + +void mips_display_message(const char *str) +{ + volatile unsigned int *display = (void *)ASCII_DISPLAY_POS_BASE; + int i; + + for (i = 0; i <= 14; i=i+2) { + if (*str) + display[i] = *str++; + else + display[i] = ' '; + } +} + +void mips_display_word(unsigned int num) +{ + volatile unsigned int *display = (void *)ASCII_DISPLAY_WORD_BASE; + + *display = num; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/gdb_hook.c linux.ac/arch/mips/mips-boards/generic/gdb_hook.c --- linux.vanilla/arch/mips/mips-boards/generic/gdb_hook.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/gdb_hook.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,205 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + * + * This is the interface to the remote debugger stub. + * + */ + +#include <linux/config.h> +#include <linux/serialP.h> +#include <linux/serial_reg.h> + +#include <asm/serial.h> +#include <asm/io.h> + +static struct serial_state rs_table[RS_TABLE_SIZE] = { + SERIAL_PORT_DFNS /* Defined in serial.h */ +}; + +static struct async_struct kdb_port_info = {0}; + +int (*putDebugChar)(char); +char (*getDebugChar)(void); + +static __inline__ unsigned int serial_in(struct async_struct *info, int offset) +{ + return inb(info->port + offset); +} + +static __inline__ void serial_out(struct async_struct *info, int offset, + int value) +{ + outb(value, info->port+offset); +} + +void rs_kgdb_hook(int tty_no) { + int t; + struct serial_state *ser = &rs_table[tty_no]; + + kdb_port_info.state = ser; + kdb_port_info.magic = SERIAL_MAGIC; + kdb_port_info.port = ser->port; + kdb_port_info.flags = ser->flags; + + /* + * Clear all interrupts + */ + serial_in(&kdb_port_info, UART_LSR); + serial_in(&kdb_port_info, UART_RX); + serial_in(&kdb_port_info, UART_IIR); + serial_in(&kdb_port_info, UART_MSR); + + /* + * Now, initialize the UART + */ + serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ + if (kdb_port_info.flags & ASYNC_FOURPORT) { + kdb_port_info.MCR = UART_MCR_DTR | UART_MCR_RTS; + t = UART_MCR_DTR | UART_MCR_OUT1; + } else { + kdb_port_info.MCR + = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; + t = UART_MCR_DTR | UART_MCR_RTS; + } + + kdb_port_info.MCR = t; /* no interrupts, please */ + serial_out(&kdb_port_info, UART_MCR, kdb_port_info.MCR); + + /* + * and set the speed of the serial port + * (currently hardwired to 9600 8N1 + */ + + /* baud rate is fixed to 9600 (is this sufficient?)*/ + t = kdb_port_info.state->baud_base / 9600; + /* set DLAB */ + serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB); + serial_out(&kdb_port_info, UART_DLL, t & 0xff);/* LS of divisor */ + serial_out(&kdb_port_info, UART_DLM, t >> 8); /* MS of divisor */ + /* reset DLAB */ + serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8); +} + +int rs_putDebugChar(char c) +{ + + if (!kdb_port_info.state) { /* need to init device first */ + return 0; + } + + while ((serial_in(&kdb_port_info, UART_LSR) & UART_LSR_THRE) == 0) + ; + + serial_out(&kdb_port_info, UART_TX, c); + + return 1; +} + +char rs_getDebugChar(void) +{ + if (!kdb_port_info.state) { /* need to init device first */ + return 0; + } + + while (!(serial_in(&kdb_port_info, UART_LSR) & 1)) + ; + + return(serial_in(&kdb_port_info, UART_RX)); +} + + +#ifdef CONFIG_MIPS_ATLAS + +#include <asm/mips-boards/atlas.h> +#include <asm/mips-boards/saa9730_uart.h> + +#define INB(a) inb((unsigned long)a) +#define OUTB(x,a) outb(x,(unsigned long)a) + +/* + * This is the interface to the remote debugger stub + * if the Philips part is used for the debug port, + * called from the platform setup code. + * + * PCI init will not have been done yet, we make a + * universal assumption about the way the bootloader (YAMON) + * have located and set up the chip. + */ +static t_uart_saa9730_regmap *kgdb_uart = (void *)(ATLAS_SAA9730_REG + SAA9730_UART_REGS_ADDR); + +static int saa9730_kgdb_active = 0; + +void saa9730_kgdb_hook(void) +{ + volatile unsigned char t; + + /* + * Clear all interrupts + */ + t = INB(&kgdb_uart->Lsr); + t += INB(&kgdb_uart->Msr); + t += INB(&kgdb_uart->Thr_Rbr); + t += INB(&kgdb_uart->Iir_Fcr); + + /* + * Now, initialize the UART + */ + /* 8 data bits, one stop bit, no parity */ + OUTB(SAA9730_LCR_DATA8, &kgdb_uart->Lcr); + + /* baud rate is fixed to 9600 (is this sufficient?)*/ + OUTB(0, &kgdb_uart->BaudDivMsb); /* HACK - Assumes standard crystal */ + OUTB(23, &kgdb_uart->BaudDivLsb); /* HACK - known for MIPS Atlas */ + + /* Set RTS/DTR active */ + OUTB(SAA9730_MCR_DTR | SAA9730_MCR_RTS, &kgdb_uart->Mcr); + saa9730_kgdb_active = 1; +} + +int saa9730_putDebugChar(char c) +{ + + if (!saa9730_kgdb_active) { /* need to init device first */ + return 0; + } + + while (!(INB(&kgdb_uart->Lsr) & SAA9730_LSR_THRE)) + ; + OUTB(c, &kgdb_uart->Thr_Rbr); + + return 1; +} + +char saa9730_getDebugChar(void) +{ + char c; + + if (!saa9730_kgdb_active) { /* need to init device first */ + return 0; + } + while (!(INB(&kgdb_uart->Lsr) & SAA9730_LSR_DR)) + ; + + c = INB(&kgdb_uart->Thr_Rbr); + return(c); +} + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/init.c linux.ac/arch/mips/mips-boards/generic/init.c --- linux.vanilla/arch/mips/mips-boards/generic/init.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/init.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,139 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * PROM library initialisation code. + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/string.h> +#include <linux/kernel.h> + +#include <asm/io.h> +#include <asm/mips-boards/prom.h> +#include <asm/mips-boards/generic.h> +#include <asm/gt64120.h> +#include <asm/mips-boards/malta.h> + +/* Environment variable */ +typedef struct +{ + char *name; + char *val; +} t_env_var; + +int prom_argc; +char **prom_argv, **prom_envp; + +int init_debug = 0; + +char *prom_getenv(char *envname) +{ + /* + * Return a pointer to the given environment variable. + */ + + t_env_var *env = (t_env_var *)prom_envp; + int i; + + i = strlen(envname); + + while(env->name) { + if(strncmp(envname, env->name, i) == 0) { + return(env->val); + } + env++; + } + return(NULL); +} + +static inline unsigned char str2hexnum(unsigned char c) +{ + if(c >= '0' && c <= '9') + return c - '0'; + if(c >= 'a' && c <= 'f') + return c - 'a' + 10; + return 0; /* foo */ +} + +static inline void str2eaddr(unsigned char *ea, unsigned char *str) +{ + int i; + + for(i = 0; i < 6; i++) { + unsigned char num; + + if((*str == '.') || (*str == ':')) + str++; + num = str2hexnum(*str++) << 4; + num |= (str2hexnum(*str++)); + ea[i] = num; + } +} + +int get_ethernet_addr(char *ethernet_addr) +{ + char *ethaddr_str; + + ethaddr_str = prom_getenv("ethaddr"); + if (!ethaddr_str) { + printk("ethaddr not set in boot prom\n"); + return -1; + } + str2eaddr(ethernet_addr, ethaddr_str); + + if (init_debug > 1) { + int i; + printk("get_ethernet_addr: "); + for (i=0; i<5; i++) + printk("%02x:", (unsigned char)*(ethernet_addr+i)); + printk("%02x\n", *(ethernet_addr+i)); + } + + return 0; +} + +int __init prom_init(int argc, char **argv, char **envp) +{ + prom_argc = argc; + prom_argv = argv; + prom_envp = envp; + + mips_display_message("LINUX"); + + /* + * Setup the North bridge to do Master byte-lane swapping when + * running in bigendian. + */ +#if defined(__MIPSEL__) + GT_WRITE(GT_PCI0_CMD_OFS, GT_PCI0_CMD_MBYTESWAP_BIT | + GT_PCI0_CMD_SBYTESWAP_BIT); +#else + GT_WRITE(GT_PCI0_CMD_OFS, 0); +#endif + +#if defined(CONFIG_MIPS_MALTA) + mips_io_port_base = MALTA_PORT_BASE; +#else + mips_io_port_base = KSEG1; +#endif + setup_prom_printf(0); + prom_printf("\nLINUX started...\n"); + prom_init_cmdline(); + prom_meminit(); + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/memory.c linux.ac/arch/mips/mips-boards/generic/memory.c --- linux.vanilla/arch/mips/mips-boards/generic/memory.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/memory.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,169 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + * + * PROM library functions for acquiring/using memory descriptors given to + * us from the YAMON. + * + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/bootmem.h> + +#include <asm/bootinfo.h> +#include <asm/page.h> + +#include <asm/mips-boards/prom.h> + +/*#define DEBUG*/ + +enum yamon_memtypes { + yamon_dontuse, + yamon_prom, + yamon_free, +}; +struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS]; + +#ifdef DEBUG +static char *mtypes[3] = { + "Dont use memory", + "YAMON PROM memory", + "Free memmory", +}; +#endif + + +struct prom_pmemblock * __init prom_getmdesc(void) +{ + char *memsize_str; + unsigned int memsize; + + memsize_str = prom_getenv("memsize"); + if (!memsize_str) { + prom_printf("memsize not set in boot prom, set to default (32Mb)\n"); + memsize = 0x02000000; + } else { +#ifdef DEBUG + prom_printf("prom_memsize = %s\n", memsize_str); +#endif + memsize = simple_strtol(memsize_str, NULL, 0); + } + + memset(mdesc, 0, sizeof(mdesc)); + + mdesc[0].type = yamon_dontuse; + mdesc[0].base = 0x00000000; + mdesc[0].size = 0x00001000; + + mdesc[1].type = yamon_prom; + mdesc[1].base = 0x00001000; + mdesc[1].size = 0x000ef000; + +#if (CONFIG_MIPS_MALTA) + /* + * The area 0x000f0000-0x000fffff is allocated for BIOS memory by the + * south bridge and PCI access always forwarded to the ISA Bus and + * BIOSCS# is always generated. + * This mean that this area can't be used as DMA memory for PCI + * devices. + */ + mdesc[2].type = yamon_dontuse; + mdesc[2].base = 0x000f0000; + mdesc[2].size = 0x00010000; +#else + mdesc[2].type = yamon_prom; + mdesc[2].base = 0x000f0000; + mdesc[2].size = 0x00010000; +#endif + + mdesc[3].type = yamon_free; + mdesc[3].base = 0x00100000; + mdesc[3].size = memsize - mdesc[3].base; + + return &mdesc[0]; +} + +static int __init prom_memtype_classify (unsigned int type) +{ + switch (type) { + case yamon_free: + return BOOT_MEM_RAM; + case yamon_prom: + return BOOT_MEM_ROM_DATA; + default: + return BOOT_MEM_RESERVED; + } +} + +void __init prom_meminit(void) +{ + struct prom_pmemblock *p; + +#ifdef DEBUG + int i = 0; + + prom_printf("YAMON MEMORY DESCRIPTOR dump:\n"); + p = prom_getmdesc(); + while (p->size) { + prom_printf("[%d,%p]: base<%08lx> size<%08lx> type<%s>\n", + i, p, p->base, p->size, mtypes[p->type]); + p++; + i++; + } +#endif + p = prom_getmdesc(); + while (p->size) { + unsigned long base, size; + long type; + + type = prom_memtype_classify (p->type); + base = p->base; + size = p->size; + + add_memory_region(base, size, type); + + p++; + } +} + +void prom_free_prom_memory (void) +{ + int i; + struct prom_pmemblock *p; + unsigned long freed = 0; + unsigned long addr; + + for (i = 0; i < boot_mem_map.nr_map; i++) { + if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA) + continue; + + addr = boot_mem_map.map[i].addr; + while (addr < boot_mem_map.map[i].addr + + boot_mem_map.map[i].size) { + ClearPageReserved(virt_to_page(phys_to_virt(addr))); + set_page_count(virt_to_page(phys_to_virt(addr)), 1); + free_page(phys_to_virt(addr)); + addr += PAGE_SIZE; + freed += PAGE_SIZE; + } + } + printk("Freeing prom memory: %ldkb freed\n", freed >> 10); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/mipsIRQ.S linux.ac/arch/mips/mips-boards/generic/mipsIRQ.S --- linux.vanilla/arch/mips/mips-boards/generic/mipsIRQ.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/mipsIRQ.S Tue Apr 3 17:54:33 2001 @@ -0,0 +1,122 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + * + * Interrupt exception dispatch code. + * + */ +#include <linux/config.h> + +#include <asm/asm.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> + +/* A lot of complication here is taken away because: + * + * 1) We handle one interrupt and return, sitting in a loop and moving across + * all the pending IRQ bits in the cause register is _NOT_ the answer, the + * common case is one pending IRQ so optimize in that direction. + * + * 2) We need not check against bits in the status register IRQ mask, that + * would make this routine slow as hell. + * + * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in + * between like BSD spl() brain-damage. + * + * Furthermore, the IRQs on the MIPS board look basically (barring software + * IRQs which we don't use at all and all external interrupt sources are + * combined together on hardware interrupt 0 (MIPS IRQ 2)) like: + * + * MIPS IRQ Source + * -------- ------ + * 0 Software (ignored) + * 1 Software (ignored) + * 2 Combined hardware interrupt (hw0) + * 3 Hardware (ignored) + * 4 Hardware (ignored) + * 5 Hardware (ignored) + * 6 Hardware (ignored) + * 7 R4k timer (what we use) + * + * We handle the IRQ according to _our_ priority which is: + * + * Highest ---- R4k Timer + * Lowest ---- Combined hardware interrupt + * + * then we just return, if multiple IRQs are pending then we will just take + * another exception, big deal. + */ + + .text + .set noreorder + .set noat + .align 5 + NESTED(mipsIRQ, PT_SIZE, sp) + SAVE_ALL + CLI + .set at + + mfc0 s0, CP0_CAUSE # get irq mask + + /* First we check for r4k counter/timer IRQ. */ + andi a0, s0, CAUSEF_IP7 + beq a0, zero, 1f + andi a0, s0, CAUSEF_IP2 # delay slot, check hw0 interrupt + + /* Wheee, a timer interrupt. */ + move a0, sp + jal mips_timer_interrupt + nop + + j ret_from_irq + nop + +1: + beq a0, zero, 1f + nop + + /* Wheee, combined hardware level zero interrupt. */ +#if defined(CONFIG_MIPS_ATLAS) + jal atlas_hw0_irqdispatch +#elif defined(CONFIG_MIPS_MALTA) + jal malta_hw0_irqdispatch +#else +#error "MIPS board not supported\n" +#endif + move a0, sp # delay slot + + j ret_from_irq + nop # delay slot + +1: + /* + * Here by mistake? This is possible, what can happen is that by the + * time we take the exception the IRQ pin goes low, so just leave if + * this is the case. + */ + move a1,s0 + PRINT("Got interrupt: c0_cause = %08x\n") + mfc0 a1, CP0_EPC + PRINT("c0_epc = %08x\n") + + j ret_from_irq + nop + END(mipsIRQ) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/pci.c linux.ac/arch/mips/mips-boards/generic/pci.c --- linux.vanilla/arch/mips/mips-boards/generic/pci.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/pci.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,328 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * MIPS boards specific PCI support. + * + */ +#include <linux/config.h> + +#ifdef CONFIG_PCI + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> + +#include <asm/mips-boards/generic.h> +#include <asm/gt64120.h> +#ifdef CONFIG_MIPS_MALTA +#include <asm/mips-boards/malta.h> +#endif + +#define PCI_ACCESS_READ 0 +#define PCI_ACCESS_WRITE 1 + +static int +mips_pcibios_config_access(unsigned char access_type, struct pci_dev *dev, + unsigned char where, u32 *data) +{ + unsigned char bus = dev->bus->number; + unsigned char dev_fn = dev->devfn; + u32 intr; + + if ((bus == 0) && (dev_fn >= PCI_DEVFN(31,0))) + return -1; /* Because of a bug in the galileo (for slot 31). */ + + /* Clear cause register bits */ + GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | + GT_INTRCAUSE_TARABORT0_BIT)); + + /* Setup address */ + GT_WRITE(GT_PCI0_CFGADDR_OFS, + (bus << GT_PCI0_CFGADDR_BUSNUM_SHF) | + (dev_fn << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | + ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) | + GT_PCI0_CFGADDR_CONFIGEN_BIT); + + if (access_type == PCI_ACCESS_WRITE) { + if (bus == 0 && dev_fn == 0) { + /* + * Galileo is acting differently than other devices. + */ + GT_WRITE(GT_PCI0_CFGDATA_OFS, *data); + } else { + GT_PCI_WRITE(GT_PCI0_CFGDATA_OFS, *data); + } + } else { + if (bus == 0 && dev_fn == 0) { + /* + * Galileo is acting differently than other devices. + */ + GT_READ(GT_PCI0_CFGDATA_OFS, *data); + } else { + GT_PCI_READ(GT_PCI0_CFGDATA_OFS, *data); + } + } + + /* Check for master or target abort */ + GT_READ(GT_INTRCAUSE_OFS, intr); + + if (intr & (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)) + { + /* Error occured */ + + /* Clear bits */ + GT_WRITE( GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | + GT_INTRCAUSE_TARABORT0_BIT) ); + + return -1; + } + + return 0; +} + + +/* + * We can't address 8 and 16 bit words directly. Instead we have to + * read/write a 32bit word and mask/modify the data we actually want. + */ +static int +mips_pcibios_read_config_byte (struct pci_dev *dev, int where, u8 *val) +{ + u32 data = 0; + + if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + *val = (data >> ((where & 3) << 3)) & 0xff; + + return PCIBIOS_SUCCESSFUL; +} + + +static int +mips_pcibios_read_config_word (struct pci_dev *dev, int where, u16 *val) +{ + u32 data = 0; + + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + *val = (data >> ((where & 3) << 3)) & 0xffff; + + return PCIBIOS_SUCCESSFUL; +} + +static int +mips_pcibios_read_config_dword (struct pci_dev *dev, int where, u32 *val) +{ + u32 data = 0; + + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + *val = data; + + return PCIBIOS_SUCCESSFUL; +} + + +static int +mips_pcibios_write_config_byte (struct pci_dev *dev, int where, u8 val) +{ + u32 data = 0; + + if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + + if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data)) + return -1; + + return PCIBIOS_SUCCESSFUL; +} + +static int +mips_pcibios_write_config_word (struct pci_dev *dev, int where, u16 val) +{ + u32 data = 0; + + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + + if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data)) + return -1; + + + return PCIBIOS_SUCCESSFUL; +} + +static int +mips_pcibios_write_config_dword(struct pci_dev *dev, int where, u32 val) +{ + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &val)) + return -1; + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops mips_pci_ops = { + mips_pcibios_read_config_byte, + mips_pcibios_read_config_word, + mips_pcibios_read_config_dword, + mips_pcibios_write_config_byte, + mips_pcibios_write_config_word, + mips_pcibios_write_config_dword +}; + +void __init pcibios_init(void) +{ +#ifdef CONFIG_MIPS_MALTA + struct pci_dev *pdev; + unsigned char reg_val; +#endif + + printk("PCI: Probing PCI hardware on host bus 0.\n"); + pci_scan_bus(0, &mips_pci_ops, NULL); + + /* + * Due to a bug in the Galileo system controller, we need to setup + * the PCI BAR for the Galileo internal registers. + * This should be done in the bios/bootprom and will be fixed in + * a later revision of YAMON (the MIPS boards boot prom). + */ + GT_WRITE(GT_PCI0_CFGADDR_OFS, + (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | /* Local bus */ + (0 << GT_PCI0_CFGADDR_DEVNUM_SHF) | /* GT64120 device */ + (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | /* Function 0 */ + ((0x20/4) << GT_PCI0_CFGADDR_REGNUM_SHF) | /* BAR 4 */ + GT_PCI0_CFGADDR_CONFIGEN_BIT ); + + /* Perform the write */ + GT_WRITE( GT_PCI0_CFGDATA_OFS, PHYSADDR(MIPS_GT_BASE)); + +#ifdef CONFIG_MIPS_MALTA + pci_for_each_dev(pdev) { + if ((pdev->vendor == PCI_VENDOR_ID_INTEL) + && (pdev->device == PCI_DEVICE_ID_INTEL_82371AB) + && (PCI_SLOT(pdev->devfn) == 0x0a)) { + /* + * IDE Decode enable. + */ + pci_read_config_byte(pdev, 0x41, ®_val); + pci_write_config_byte(pdev, 0x41, reg_val | 0x80); + pci_read_config_byte(pdev, 0x43, ®_val); + pci_write_config_byte(pdev, 0x43, reg_val | 0x80); + } + + if ((pdev->vendor == PCI_VENDOR_ID_INTEL) + && (pdev->device == PCI_DEVICE_ID_INTEL_82371AB_0) + && (PCI_SLOT(pdev->devfn) == 0x0a)) { + /* + * Set top of main memory accessible by ISA or DMA + * devices to 16 Mb. + */ + pci_read_config_byte(pdev, 0x69, ®_val); + pci_write_config_byte(pdev, 0x69, reg_val | 0xf0); + } + } + + /* + * Activate Floppy Controller in the SMSC FDC37M817 Super I/O + * Controller. + * This should be done in the bios/bootprom and will be fixed in + * a later revision of YAMON (the MIPS boards boot prom). + */ + /* Entering config state. */ + SMSC_WRITE(SMSC_CONFIG_ENTER, SMSC_CONFIG_REG); + + /* Activate floppy controller. */ + SMSC_WRITE(SMSC_CONFIG_DEVNUM, SMSC_CONFIG_REG); + SMSC_WRITE(SMSC_CONFIG_DEVNUM_FLOPPY, SMSC_DATA_REG); + SMSC_WRITE(SMSC_CONFIG_ACTIVATE, SMSC_CONFIG_REG); + SMSC_WRITE(SMSC_CONFIG_ACTIVATE_ENABLE, SMSC_DATA_REG); + + /* Exit config state. */ + SMSC_WRITE(SMSC_CONFIG_EXIT, SMSC_CONFIG_REG); +#endif +} + +int __init +pcibios_enable_device(struct pci_dev *dev) +{ + /* Not needed, since we enable all devices at startup. */ + return 0; +} + +void __init +pcibios_align_resource(void *data, struct resource *res, unsigned long size) +{ +} + +char * __init +pcibios_setup(char *str) +{ + /* Nothing to do for now. */ + + return str; +} + +struct pci_fixup pcibios_fixups[] = { + { 0 } +}; + +void __init +pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) +{ + unsigned long where, size; + u32 reg; + + where = PCI_BASE_ADDRESS_0 + (resource * 4); + size = res->end - res->start; + pci_read_config_dword(dev, where, ®); + reg = (reg & size) | (((u32)(res->start - root->start)) & ~size); + pci_write_config_dword(dev, where, reg); +} + +/* + * Called after each bus is probed, but before its children + * are examined. + */ +void __init pcibios_fixup_bus(struct pci_bus *b) +{ + pci_read_bridge_bases(b); +} + +#endif /* CONFIG_PCI */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/printf.c linux.ac/arch/mips/mips-boards/generic/printf.c --- linux.vanilla/arch/mips/mips-boards/generic/printf.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/printf.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,140 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + * + * Putting things on the screen/serial line using YAMONs facilities. + * + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/serialP.h> +#include <linux/serial_reg.h> +#include <asm/system.h> +#include <asm/io.h> +#include <asm/serial.h> + + +#ifdef CONFIG_MIPS_ATLAS +/* + * Atlas registers are memory mapped on 64-bit aligned boundaries and + * only word access are allowed. + * When reading the UART 8 bit registers only the LSB are valid. + */ +unsigned int atlas_serial_in(struct async_struct *info, int offset) +{ + return (*(volatile unsigned int *)(info->port + mips_io_port_base + offset*8) & 0xff); +} + +void atlas_serial_out(struct async_struct *info, int offset, int value) +{ + *(volatile unsigned int *)(info->port + mips_io_port_base + offset*8) = value; +} + +#define serial_in atlas_serial_in +#define serial_out atlas_serial_out + +#else + +static unsigned int serial_in(struct async_struct *info, int offset) +{ + return inb(info->port + offset); +} + +static void serial_out(struct async_struct *info, int offset, + int value) +{ + outb(value, info->port + offset); +} +#endif + +static struct serial_state rs_table[] = { + SERIAL_PORT_DFNS /* Defined in serial.h */ +}; + +/* + * Hooks to fake "prom" console I/O before devices + * are fully initialized. + */ +static struct async_struct prom_port_info = {0}; + +void __init setup_prom_printf(int tty_no) { + struct serial_state *ser = &rs_table[tty_no]; + + prom_port_info.state = ser; + prom_port_info.magic = SERIAL_MAGIC; + prom_port_info.port = ser->port; + prom_port_info.flags = ser->flags; + + /* No setup of UART - assume YAMON left in sane state */ +} + +int putPromChar(char c) +{ + if (!prom_port_info.state) { /* need to init device first */ + return 0; + } + + while ((serial_in(&prom_port_info, UART_LSR) & UART_LSR_THRE) == 0) + ; + + serial_out(&prom_port_info, UART_TX, c); + + return 1; +} + +char getPromChar(void) +{ + if (!prom_port_info.state) { /* need to init device first */ + return 0; + } + + while (!(serial_in(&prom_port_info, UART_LSR) & 1)) + ; + + return(serial_in(&prom_port_info, UART_RX)); +} + +static char buf[1024]; + +void __init prom_printf(char *fmt, ...) +{ + va_list args; + int l; + char *p, *buf_end; + long flags; + + int putPromChar(char); + + /* Low level, brute force, not SMP safe... */ + save_and_cli(flags); + va_start(args, fmt); + l = vsprintf(buf, fmt, args); /* hopefully i < sizeof(buf) */ + va_end(args); + + buf_end = buf + l; + + for (p = buf; p < buf_end; p++) { + /* Crude cr/nl handling is better than none */ + if(*p == '\n')putPromChar('\r'); + putPromChar(*p); + } + restore_flags(flags); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/reset.c linux.ac/arch/mips/mips-boards/generic/reset.c --- linux.vanilla/arch/mips/mips-boards/generic/reset.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/reset.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,72 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + * + * Reset the MIPS boards. + * + */ +#include <linux/config.h> + +#include <asm/reboot.h> +#include <asm/mips-boards/generic.h> +#if defined(CONFIG_MIPS_ATLAS) +#include <asm/mips-boards/atlas.h> +#endif + +static void mips_machine_restart(char *command); +static void mips_machine_halt(void); +#if defined(CONFIG_MIPS_ATLAS) +static void atlas_machine_power_off(void); +#endif + +static void mips_machine_restart(char *command) +{ + volatile unsigned int *softres_reg = (void *)SOFTRES_REG; + + *softres_reg = GORESET; +} + +static void mips_machine_halt(void) +{ + volatile unsigned int *softres_reg = (void *)SOFTRES_REG; + + *softres_reg = GORESET; +} + +#if defined(CONFIG_MIPS_ATLAS) +static void atlas_machine_power_off(void) +{ + volatile unsigned int *psustby_reg = (void *)ATLAS_PSUSTBY_REG; + + *psustby_reg = ATLAS_GOSTBY; +} +#endif + +void mips_reboot_setup(void) +{ + _machine_restart = mips_machine_restart; + _machine_halt = mips_machine_halt; +#if defined(CONFIG_MIPS_ATLAS) + _machine_power_off = atlas_machine_power_off; +#endif +#if defined(CONFIG_MIPS_MALTA) + _machine_power_off = mips_machine_halt; +#endif +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/time.c linux.ac/arch/mips/mips-boards/generic/time.c --- linux.vanilla/arch/mips/mips-boards/generic/time.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/time.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,410 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + * + * Setting up the clock on the MIPS boards. + * + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/sched.h> +#include <linux/spinlock.h> + +#include <asm/mipsregs.h> +#include <asm/ptrace.h> +#include <asm/div64.h> + +#include <linux/mc146818rtc.h> +#include <linux/timex.h> + +#include <asm/mips-boards/generic.h> +#include <asm/mips-boards/prom.h> + +extern volatile unsigned long wall_jiffies; +static long last_rtc_update = 0; +unsigned long missed_heart_beats = 0; + +static unsigned long r4k_offset; /* Amount to increment compare reg each time */ +static unsigned long r4k_cur; /* What counter should be at next timer irq */ +extern rwlock_t xtime_lock; + +#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) + +#if defined(CONFIG_MIPS_ATLAS) +static char display_string[] = " LINUX ON ATLAS "; +#endif +#if defined(CONFIG_MIPS_MALTA) +static char display_string[] = " LINUX ON MALTA "; +#endif +static unsigned int display_count = 0; +#define MAX_DISPLAY_COUNT (sizeof(display_string) - 8) + +static unsigned int timer_tick_count=0; + + +static inline void ack_r4ktimer(unsigned long newval) +{ + write_32bit_cp0_register(CP0_COMPARE, newval); +} + + +/* + * In order to set the CMOS clock precisely, set_rtc_mmss has to be + * called 500 ms after the second nowtime has started, because when + * nowtime is written into the registers of the CMOS clock, it will + * jump to the next second precisely 500 ms later. Check the Motorola + * MC146818A or Dallas DS12887 data sheet for details. + * + * BUG: This routine does not handle hour overflow properly; it just + * sets the minutes. Usually you won't notice until after reboot! + */ +static int set_rtc_mmss(unsigned long nowtime) +{ + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + unsigned char save_control, save_freq_select; + + save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + cmos_minutes = CMOS_READ(RTC_MINUTES); + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - cmos_minutes) < 30) { + CMOS_WRITE(real_seconds,RTC_SECONDS); + CMOS_WRITE(real_minutes,RTC_MINUTES); + } else { + printk(KERN_WARNING + "set_rtc_mmss: can't update from %d to %d\n", + cmos_minutes, real_minutes); + retval = -1; + } + + /* The following flags have to be released exactly in this order, + * otherwise the DS12887 (popular MC146818A clone with integrated + * battery and quartz) will not reset the oscillator and will not + * update precisely 500 ms later. You won't find this mentioned in + * the Dallas Semiconductor data sheets, but who believes data + * sheets anyway ... -- Markus Kuhn + */ + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + + return retval; +} + +/* + * There are a lot of conceptually broken versions of the MIPS timer interrupt + * handler floating around. This one is rather different, but the algorithm + * is provably more robust. + */ +void mips_timer_interrupt(struct pt_regs *regs) +{ + int irq = 7; + + if (r4k_offset == 0) + goto null; + + do { + kstat.irqs[0][irq]++; + do_timer(regs); + + /* Historical comment/code: + * RTC time of day s updated approx. every 11 + * minutes. Because of how the numbers work out + * we need to make absolutely sure we do this update + * within 500ms before the * next second starts, + * thus the following code. + */ + read_lock(&xtime_lock); + if ((time_status & STA_UNSYNC) == 0 + && xtime.tv_sec > last_rtc_update + 660 + && xtime.tv_usec >= 500000 - (tick >> 1) + && xtime.tv_usec <= 500000 + (tick >> 1)) + if (set_rtc_mmss(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else + /* do it again in 60 s */ + last_rtc_update = xtime.tv_sec - 600; + read_unlock(&xtime_lock); + + if ((timer_tick_count++ % HZ) == 0) { + mips_display_message(&display_string[display_count++]); + if (display_count == MAX_DISPLAY_COUNT) + display_count = 0; + } + + r4k_cur += r4k_offset; + ack_r4ktimer(r4k_cur); + + } while (((unsigned long)read_32bit_cp0_register(CP0_COUNT) + - r4k_cur) < 0x7fffffff); + + return; + +null: + ack_r4ktimer(0); +} + +/* + * Figure out the r4k offset, the amount to increment the compare + * register for each time tick. + * Use the RTC to calculate offset. + */ +static unsigned long __init cal_r4koff(void) +{ + unsigned long count; + unsigned int flags; + + __save_and_cli(flags); + + /* Start counter exactly on falling edge of update flag */ + while (CMOS_READ(RTC_REG_A) & RTC_UIP); + while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); + + /* Start r4k counter. */ + write_32bit_cp0_register(CP0_COUNT, 0); + + /* Read counter exactly on falling edge of update flag */ + while (CMOS_READ(RTC_REG_A) & RTC_UIP); + while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); + + count = read_32bit_cp0_register(CP0_COUNT); + + /* restore interrupts */ + __restore_flags(flags); + + return (count / HZ); +} + +static unsigned long __init get_mips_time(void) +{ + unsigned int year, mon, day, hour, min, sec; + unsigned char save_control; + + save_control = CMOS_READ(RTC_CONTROL); + + /* Freeze it. */ + CMOS_WRITE(save_control | RTC_SET, RTC_CONTROL); + + /* Read regs. */ + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + + if (!(save_control & RTC_24H)) + { + if ((hour & 0xf) == 0xc) + hour &= 0x80; + if (hour & 0x80) + hour = (hour & 0xf) + 12; + } + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR); + + /* Unfreeze clock. */ + CMOS_WRITE(save_control, RTC_CONTROL); + + if ((year += 1900) < 1970) + year += 100; + + return mktime(year, mon, day, hour, min, sec); +} + +void __init time_init(void) +{ + unsigned int est_freq, flags; + + /* Set Data mode - binary. */ + CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL); + + printk("calculating r4koff... "); + r4k_offset = cal_r4koff(); + printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset); + + est_freq = 2*r4k_offset*HZ; + est_freq += 5000; /* round */ + est_freq -= est_freq%10000; + printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, + (est_freq%1000000)*100/1000000); + r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset); + + write_32bit_cp0_register(CP0_COMPARE, r4k_cur); + change_cp0_status(ST0_IM, ALLINTS); + + /* Read time from the RTC chipset. */ + write_lock_irqsave (&xtime_lock, flags); + xtime.tv_sec = get_mips_time(); + xtime.tv_usec = 0; + write_unlock_irqrestore(&xtime_lock, flags); +} + +/* This is for machines which generate the exact clock. */ +#define USECS_PER_JIFFY (1000000/HZ) +#define USECS_PER_JIFFY_FRAC (0x100000000*1000000/HZ&0xffffffff) + +/* Cycle counter value at the previous timer interrupt.. */ + +static unsigned int timerhi = 0, timerlo = 0; + +/* + * FIXME: Does playing with the RP bit in c0_status interfere with this code? + */ +static unsigned long do_fast_gettimeoffset(void) +{ + u32 count; + unsigned long res, tmp; + + /* Last jiffy when do_fast_gettimeoffset() was called. */ + static unsigned long last_jiffies=0; + unsigned long quotient; + + /* + * Cached "1/(clocks per usec)*2^32" value. + * It has to be recalculated once each jiffy. + */ + static unsigned long cached_quotient=0; + + tmp = jiffies; + + quotient = cached_quotient; + + if (tmp && last_jiffies != tmp) { + last_jiffies = tmp; +#ifdef CONFIG_CPU_MIPS32 + if (last_jiffies != 0) { + unsigned long r0; + do_div64_32(r0, timerhi, timerlo, tmp); + do_div64_32(quotient, USECS_PER_JIFFY, + USECS_PER_JIFFY_FRAC, r0); + cached_quotient = quotient; + } +#else + __asm__(".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "lwu\t%0,%2\n\t" + "dsll32\t$1,%1,0\n\t" + "or\t$1,$1,%0\n\t" + "ddivu\t$0,$1,%3\n\t" + "mflo\t$1\n\t" + "dsll32\t%0,%4,0\n\t" + "nop\n\t" + "ddivu\t$0,%0,$1\n\t" + "mflo\t%0\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=&r" (quotient) + :"r" (timerhi), + "m" (timerlo), + "r" (tmp), + "r" (USECS_PER_JIFFY) + :"$1"); + cached_quotient = quotient; +#endif + } + + /* Get last timer tick in absolute kernel time */ + count = read_32bit_cp0_register(CP0_COUNT); + + /* .. relative to previous jiffy (32 bits is enough) */ + count -= timerlo; + + __asm__("multu\t%1,%2\n\t" + "mfhi\t%0" + :"=r" (res) + :"r" (count), + "r" (quotient)); + + /* + * Due to possible jiffies inconsistencies, we need to check + * the result so that we'll get a timer that is monotonic. + */ + if (res >= USECS_PER_JIFFY) + res = USECS_PER_JIFFY-1; + + return res; +} + +void do_gettimeofday(struct timeval *tv) +{ + unsigned int flags; + + read_lock_irqsave (&xtime_lock, flags); + *tv = xtime; + tv->tv_usec += do_fast_gettimeoffset(); + + /* + * xtime is atomically updated in timer_bh. jiffies - wall_jiffies + * is nonzero if the timer bottom half hasnt executed yet. + */ + if (jiffies - wall_jiffies) + tv->tv_usec += USECS_PER_JIFFY; + + read_unlock_irqrestore (&xtime_lock, flags); + + if (tv->tv_usec >= 1000000) { + tv->tv_usec -= 1000000; + tv->tv_sec++; + } +} + +void do_settimeofday(struct timeval *tv) +{ + write_lock_irq (&xtime_lock); + + /* This is revolting. We need to set the xtime.tv_usec correctly. + * However, the value in this location is is value at the last tick. + * Discover what correction gettimeofday would have done, and then + * undo it! + */ + tv->tv_usec -= do_fast_gettimeoffset(); + + if (tv->tv_usec < 0) { + tv->tv_usec += 1000000; + tv->tv_sec--; + } + + xtime = *tv; + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + + write_unlock_irq (&xtime_lock); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/malta/Makefile linux.ac/arch/mips/mips-boards/malta/Makefile --- linux.vanilla/arch/mips/mips-boards/malta/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/malta/Makefile Tue Apr 3 17:54:33 2001 @@ -0,0 +1,40 @@ +# +# Carsten Langgaard, carstenl@mips.com +# Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. +# +# ######################################################################## +# +# This program is free software; you can distribute it and/or modify it +# under the terms of the GNU General Public License (Version 2) as +# published by the Free Software Foundation. +# +# This program is distributed in the hope 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. +# +# ####################################################################### +# +# Makefile for the MIPS Malta specific kernel interface routines +# under Linux. +# +# 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.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +O_TARGET := malta.o + +obj-y := malta_int.o malta_rtc.o malta_setup.o + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/malta/malta_int.c linux.ac/arch/mips/mips-boards/malta/malta_int.c --- linux.vanilla/arch/mips/mips-boards/malta/malta_int.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/malta/malta_int.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,378 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * Routines for generic manipulation of the interrupts found on the MIPS + * Malta board. + * The interrupt controller is located in the South Bridge a PIIX4 device + * with two internal 82C95 interrupt controllers. + */ +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/kernel_stat.h> +#include <linux/random.h> + +#include <asm/irq.h> +#include <asm/io.h> +#include <asm/mips-boards/malta.h> +#include <asm/mips-boards/maltaint.h> +#include <asm/mips-boards/piix4.h> +#include <asm/gt64120.h> +#include <asm/mips-boards/generic.h> + +extern asmlinkage void mipsIRQ(void); + +unsigned int local_bh_count[NR_CPUS]; +unsigned int local_irq_count[NR_CPUS]; +unsigned long spurious_count = 0; + +static struct irqaction *hw0_irq_action[MALTAINT_END] = { + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL +}; + +static struct irqaction r4ktimer_action = { + NULL, 0, 0, "R4000 timer/counter", NULL, NULL, +}; + +static struct irqaction *irq_action[8] = { + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, &r4ktimer_action +}; + +#if 0 +#define DEBUG_INT(x...) printk(x) +#else +#define DEBUG_INT(x...) +#endif + +/* + * This contains the interrupt mask for both 82C59 interrupt controllers. + */ +static unsigned int cached_int_mask = 0xffff; + + +void disable_irq(unsigned int irq_nr) +{ + unsigned long flags; + + if(irq_nr >= MALTAINT_END) { + printk("whee, invalid irq_nr %d\n", irq_nr); + panic("IRQ, you lose..."); + } + + save_and_cli(flags); + cached_int_mask |= (1 << irq_nr); + if (irq_nr & 8) { + outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1); + } else { + outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1); + } + restore_flags(flags); +} + + +void enable_irq(unsigned int irq_nr) +{ + unsigned long flags; + + if(irq_nr >= MALTAINT_END) { + printk("whee, invalid irq_nr %d\n", irq_nr); + panic("IRQ, you lose..."); + } + + save_and_cli(flags); + cached_int_mask &= ~(1 << irq_nr); + if (irq_nr & 8) { + outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1); + + /* Enable irq 2 (cascade interrupt). */ + cached_int_mask &= ~(1 << 2); + outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1); + } else { + outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1); + } + restore_flags(flags); +} + + +int get_irq_list(char *buf) +{ + int i, len = 0; + int num = 0; + struct irqaction *action; + + for (i = 0; i < 8; i++, num++) { + action = irq_action[i]; + if (!action) + continue; + len += sprintf(buf+len, "%2d: %8d %c %s", + num, kstat.irqs[0][num], + (action->flags & SA_INTERRUPT) ? '+' : ' ', + action->name); + for (action=action->next; action; action = action->next) { + len += sprintf(buf+len, ",%s %s", + (action->flags & SA_INTERRUPT) ? " +" : "", + action->name); + } + len += sprintf(buf+len, " [on-chip]\n"); + } + for (i = 0; i < MALTAINT_END; i++, num++) { + action = hw0_irq_action[i]; + if (!action) + continue; + len += sprintf(buf+len, "%2d: %8d %c %s", + num, kstat.irqs[0][num], + (action->flags & SA_INTERRUPT) ? '+' : ' ', + action->name); + for (action=action->next; action; action = action->next) { + len += sprintf(buf+len, ",%s %s", + (action->flags & SA_INTERRUPT) ? " +" : "", + action->name); + } + len += sprintf(buf+len, " [hw0]\n"); + } + return len; +} + + +static int setup_irq(unsigned int irq, struct irqaction * new) +{ + int shared = 0; + struct irqaction *old, **p; + + p = &hw0_irq_action[irq]; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) + return -EBUSY; + + /* Can't share interrupts unless both are same type */ + if ((old->flags ^ new->flags) & SA_INTERRUPT) + return -EBUSY; + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + if (new->flags & SA_SAMPLE_RANDOM) + rand_initialize_irq(irq); + + *p = new; + if (!shared) + enable_irq(irq); + + return 0; +} + +int request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char * devname, + void *dev_id) +{ + struct irqaction *action; + int retval; + + DEBUG_INT("request_irq: irq=%d, devname = %s\n", irq, devname); + + if (irq >= MALTAINT_END) + return -EINVAL; + if (!handler) + return -EINVAL; + + action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); + if(!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + action->dev_id = dev_id; + action->next = 0; + + retval = setup_irq(irq, action); + if (retval) + kfree(action); + + return retval; +} + + +void free_irq(unsigned int irq, void *dev_id) +{ + struct irqaction *action, **p; + + if (irq >= MALTAINT_END) { + printk("Trying to free IRQ%d\n",irq); + return; + } + + for (p = &hw0_irq_action[irq]; (action = *p) != NULL; + p = &action->next) + { + if (action->dev_id != dev_id) + continue; + + /* Found it - now free it */ + *p = action->next; + kfree(action); + if (!hw0_irq_action[irq]) + disable_irq(irq); + return; + } + printk("Trying to free IRQ%d\n",irq); +} + +void __init init_IRQ(void) +{ + irq_setup(); +} + +static inline int get_int(int *irq) +{ + /* + * Determine highest priority pending interrupt by performing + * a PCI Interrupt Acknowledge cycle. + */ + GT_READ(GT_PCI0_IACK_OFS, *irq); + *irq &= 0xFF; + + /* + * IRQ7 is used to detect spurious interrupts. + * The interrupt acknowledge cycle returns IRQ7, if no + * interrupts is requested. + * We can differentiate between this situation and a + * "Normal" IRQ7 by reading the ISR. + */ + if (*irq == 7) + { + outb(PIIX4_OCW3_SEL | PIIX4_OCW3_ISR, PIIX4_ICTLR1_OCW3); + if (!(inb(PIIX4_ICTLR1_OCW3) & (1 << 7))) + return -1; /* Spurious interrupt. */ + } + + return 0; +} + +static inline void ack_int(int irq) +{ + if (irq & 8) { + /* Specific EOI to cascade */ + outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI | PIIX4_OCW2_ILS_2, + PIIX4_ICTLR1_OCW2); + + /* Non specific EOI to cascade */ + outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI, PIIX4_ICTLR2_OCW2); + } else { + /* Non specific EOI to cascade */ + outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI, PIIX4_ICTLR1_OCW2); + } +} + +void malta_hw0_irqdispatch(struct pt_regs *regs) +{ + struct irqaction *action; + int irq=0, cpu = smp_processor_id(); + + DEBUG_INT("malta_hw0_irqdispatch\n"); + + if (get_int(&irq)) + return; /* interrupt has already been cleared */ + + disable_irq(irq); + ack_int(irq); + + DEBUG_INT("malta_hw0_irqdispatch: irq=%d\n", irq); + action = hw0_irq_action[irq]; + + /* + * if action == NULL, then we don't have a handler + * for the irq + */ + if ( action == NULL ) + return; + + irq_enter(cpu, irq); + kstat.irqs[0][irq + 8]++; + do { + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + + enable_irq(irq); + irq_exit(cpu, irq); +} + + +unsigned long probe_irq_on (void) +{ + unsigned int i, irqs = 0; + unsigned long delay; + + /* first, enable any unassigned irqs */ + for (i = MALTAINT_END-1; i > 0; i--) { + if (!hw0_irq_action[i]) { + enable_irq(i); + irqs |= (1 << i); + } + } + + /* wait for spurious interrupts to mask themselves out again */ + for (delay = jiffies + HZ/10; time_before(jiffies, delay); ) + /* about 100ms delay */; + + /* now filter out any obviously spurious interrupts */ + return irqs & ~cached_int_mask; +} + + +int probe_irq_off (unsigned long irqs) +{ + unsigned int i; + + irqs &= cached_int_mask; + if (!irqs) + return 0; + i = ffz(~irqs); + if (irqs != (irqs & (1 << i))) + i = -i; + + return i; +} + + +void __init maltaint_init(void) +{ + /* + * Mask out all interrupt by writing "1" to all bit position in + * the IMR register. + */ + outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1); + outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1); + + /* Now safe to set the exception vector. */ + set_except_vector(0, mipsIRQ); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/malta/malta_rtc.c linux.ac/arch/mips/mips-boards/malta/malta_rtc.c --- linux.vanilla/arch/mips/mips-boards/malta/malta_rtc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/malta/malta_rtc.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,51 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + * + * RTC routines for Malta style attached PIIX4 device, which contains a + * Motorola MC146818A-compatible Real Time Clock. + * + */ +#include <linux/spinlock.h> +#include <linux/mc146818rtc.h> +#include <asm/mips-boards/malta.h> + +static unsigned char malta_rtc_read_data(unsigned long addr) +{ + outb(addr, MALTA_RTC_ADR_REG); + return inb(MALTA_RTC_DAT_REG); +} + +static void malta_rtc_write_data(unsigned char data, unsigned long addr) +{ + outb(addr, MALTA_RTC_ADR_REG); + outb(data, MALTA_RTC_DAT_REG); +} + +static int malta_rtc_bcd_mode(void) +{ + return 0; +} + +struct rtc_ops malta_rtc_ops = { + &malta_rtc_read_data, + &malta_rtc_write_data, + &malta_rtc_bcd_mode +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/malta/malta_setup.c linux.ac/arch/mips/mips-boards/malta/malta_setup.c --- linux.vanilla/arch/mips/mips-boards/malta/malta_setup.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/malta/malta_setup.c Tue Apr 3 17:54:33 2001 @@ -0,0 +1,159 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + * + * Malta specific setup, including init of the feature struct. + * + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/mc146818rtc.h> +#include <linux/ioport.h> +#include <linux/pci.h> +#ifdef CONFIG_BLK_DEV_IDE +#include <linux/ide.h> +#endif + +#include <asm/cpu.h> +#include <asm/bootinfo.h> +#include <asm/irq.h> +#include <asm/mips-boards/generic.h> +#include <asm/mips-boards/prom.h> +#include <asm/mips-boards/malta.h> +#include <asm/mips-boards/maltaint.h> +#ifdef CONFIG_BLK_DEV_FD +#include <asm/floppy.h> +#endif +#include <asm/dma.h> + +#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE) +extern void console_setup(char *, int *); +char serial_console[20]; +#endif + +#ifdef CONFIG_REMOTE_DEBUG +extern void set_debug_traps(void); +extern void rs_kgdb_hook(int); +extern void breakpoint(void); +static int remote_debug = 0; +#endif + +#ifdef CONFIG_BLK_DEV_IDE +extern struct ide_ops std_ide_ops; +#endif +#ifdef CONFIG_BLK_DEV_FD +extern struct fd_ops std_fd_ops; +#endif +extern struct rtc_ops malta_rtc_ops; + +extern void mips_reboot_setup(void); + +struct resource standard_io_resources[] = { + { "dma1", 0x00, 0x1f, IORESOURCE_BUSY }, + { "pic1", 0x20, 0x3f, IORESOURCE_BUSY }, + { "timer", 0x40, 0x5f, IORESOURCE_BUSY }, + { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY }, + { "pic2", 0xa0, 0xbf, IORESOURCE_BUSY }, + { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY }, +}; + +#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource)) + +static void __init malta_irq_setup(void) +{ + maltaint_init(); + +#ifdef CONFIG_REMOTE_DEBUG + if (remote_debug) { + set_debug_traps(); + breakpoint(); + } +#endif +} + + +void __init malta_setup(void) +{ +#ifdef CONFIG_REMOTE_DEBUG + int rs_putDebugChar(char); + char rs_getDebugChar(void); + extern int (*putDebugChar)(char); + extern char (*getDebugChar)(void); +#endif + char *argptr; + int i; + + irq_setup = malta_irq_setup; + + /* Request I/O space for devices used on the Malta board. */ + for (i = 0; i < STANDARD_IO_RESOURCES; i++) + request_resource(&ioport_resource, standard_io_resources+i); + + /* + * Enable DMA channel 4 (cascade channel) in the PIIX4 south bridge. + */ + enable_dma(4); + +#ifdef CONFIG_SERIAL_CONSOLE + argptr = prom_getcmdline(); + if ((argptr = strstr(argptr, "console=")) == NULL) { + argptr = prom_getcmdline(); + strcat(argptr, " console=ttyS0,38400"); + } +#endif + +#ifdef CONFIG_REMOTE_DEBUG + argptr = prom_getcmdline(); + if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) { + int line; + argptr += strlen("kgdb=ttyS"); + if (*argptr != '0' && *argptr != '1') + printk("KGDB: Uknown serial line /dev/ttyS%c, " + "falling back to /dev/ttyS1\n", *argptr); + line = *argptr == '0' ? 0 : 1; + printk("KGDB: Using serial line /dev/ttyS%d for session\n", + line ? 1 : 0); + + rs_kgdb_hook(line); + putDebugChar = rs_putDebugChar; + getDebugChar = rs_getDebugChar; + + prom_printf("KGDB: Using serial line /dev/ttyS%d for session, " + "please connect your debugger\n", line ? 1 : 0); + + remote_debug = 1; + /* Breakpoints and stuff are in malta_irq_setup() */ + } +#endif + + argptr = prom_getcmdline(); + if ((argptr = strstr(argptr, "nofpu")) != NULL) + mips_cpu.options &= ~MIPS_CPU_FPU; + + rtc_ops = &malta_rtc_ops; +#ifdef CONFIG_BLK_DEV_IDE + ide_ops = &std_ide_ops; +#endif +#ifdef CONFIG_BLK_DEV_FD + fd_ops = &std_fd_ops; +#endif + mips_reboot_setup(); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mm/Makefile linux.ac/arch/mips/mm/Makefile --- linux.vanilla/arch/mips/mm/Makefile Fri Feb 25 06:52:30 2000 +++ linux.ac/arch/mips/mm/Makefile Tue Apr 3 17:54:33 2001 @@ -8,34 +8,20 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := mm.o -O_OBJS := extable.o init.o fault.o loadmmu.o -ifdef CONFIG_CPU_R3000 -O_OBJS += r2300.o -endif +export-objs += umap.o +obj-y += extable.o init.o fault.o loadmmu.o -ifdef CONFIG_CPU_R4300 -O_OBJS += r4xx0.o -endif - -ifdef CONFIG_CPU_R4X00 -O_OBJS += r4xx0.o -endif - -ifdef CONFIG_CPU_R5000 -O_OBJS += r4xx0.o -endif - -ifdef CONFIG_CPU_NEVADA -O_OBJS += r4xx0.o -endif - -ifdef CONFIG_SGI_IP22 -O_OBJS += umap.o -endif - -ifdef CONFIG_BAGET_MIPS -O_OBJS += umap.o -endif +obj-$(CONFIG_CPU_R3000) += r2300.o +obj-$(CONFIG_CPU_R3912) += r2300.o +obj-$(CONFIG_CPU_R4300) += r4xx0.o +obj-$(CONFIG_CPU_R4X00) += r4xx0.o +obj-$(CONFIG_CPU_R5000) += r4xx0.o +obj-$(CONFIG_CPU_NEVADA) += r4xx0.o +obj-$(CONFIG_CPU_R5432) += r5432.o +obj-$(CONFIG_CPU_RM7000) += rm7k.o +obj-$(CONFIG_CPU_MIPS32) += mips32.o +obj-$(CONFIG_SGI_IP22) += umap.o +obj-$(CONFIG_BAGET_MIPS) += umap.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mm/init.c linux.ac/arch/mips/mm/init.c --- linux.vanilla/arch/mips/mm/init.c Mon Oct 16 20:58:51 2000 +++ linux.ac/arch/mips/mm/init.c Tue Apr 3 17:54:33 2001 @@ -38,6 +38,9 @@ #include <asm/sgialib.h> #endif #include <asm/mmu_context.h> +#include <asm/tlb.h> + +mmu_gather_t mmu_gathers[NR_CPUS]; static unsigned long totalram_pages; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/orion/Makefile linux.ac/arch/mips/orion/Makefile --- linux.vanilla/arch/mips/orion/Makefile Tue Jul 11 19:14:48 2000 +++ linux.ac/arch/mips/orion/Makefile Thu Jan 1 01:00:00 1970 @@ -1,48 +0,0 @@ -# -# 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. -# -# -# Produce a bootimage for the IPSX -# Copyright (C) 2000 Cort Dougan <cort@fsmlabs.com> -# - -.S.s: - $(CPP) $(CFLAGS) $< -o $*.s -.S.o: - $(CC) $(CFLAGS) -c $< -o $*.o - -OBJS = promcon.o char.o serial.8530.o orion.hw.init.o setup.o irq.o int-handler.o - -all: orionkern.a - -orionkern.a: $(OBJS) initrd.o #no_initrd.o - $(AR) rcs orionkern.a $(OBJS) initrd.o #no_initrd.o - sync - -initrd.c: piggyback ramdisk.image.gz - ./piggyback initrd < ramdisk.image.gz > initrd.c - -piggyback: piggyback.c - $(HOSTCC) $(HOSTCFLAGS) -o piggyback piggyback.c - -orionboot: orion.ctl - -patchapp: patchapp.c - $(HOSTCC) -o $@ $^ - -orion.ctl: patchapp ../../../vmlinux - $(OBJCOPY) -Obinary ../../../vmlinux orion.nosym - ./patchapp orion.nosym orion - cp -f orion.bin orion.ctl - -# Don't build dependencies, this may die if $(CC) isn't gcc -dep: - -clean: - rm -f patchapp orion.bin orion.nosym orion.ctl initrd.c - -dummy: - -include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/orion/int-handler.S linux.ac/arch/mips/orion/int-handler.S --- linux.vanilla/arch/mips/orion/int-handler.S Tue Jul 11 19:14:48 2000 +++ linux.ac/arch/mips/orion/int-handler.S Thu Jan 1 01:00:00 1970 @@ -1,53 +0,0 @@ -#include <asm/asm.h> -#include <asm/mipsregs.h> -#include <asm/regdef.h> -#include <asm/stackframe.h> - - .text - .set mips1 - .set reorder - .set macro - .set noat - .align 5 - -NESTED(orionIRQ, PT_SIZE, sp) - SAVE_ALL - CLI # Important: mark KERNEL mode ! - /* - * Get pending interrupts - */ - mfc0 t0,CP0_CAUSE # get pending interrupts - mfc0 t1,CP0_STATUS # get enabled interrupts - and t0,t1 # isolate allowed ones - andi t0,0xff00 # isolate pending bits - sll t0,16 # shift the pending bits down - beqz t0,3f # no pending intrs, then spurious - nop # delay slot - - /* - * Find irq with highest priority - * FIXME: This is slow - use binary search - */ - la a0,7 -1: bltz t0,2f # found pending irq - subu a0,1 - sll t0,1 - b 1b - nop # delay slot - -call_do_IRQ: -2: move a1,sp - jal do_IRQ - nop # delay slot - - mfc0 t0,CP0_STATUS # disable interrupts - ori t0,1 - xori t0,1 - mtc0 t0,CP0_STATUS - - la a1, ret_from_irq - jr a1 - -3: j spurious_interrupt -END(orionIRQ) - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/orion/irq.c linux.ac/arch/mips/orion/irq.c --- linux.vanilla/arch/mips/orion/irq.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/mips/orion/irq.c Thu Jan 1 01:00:00 1970 @@ -1,281 +0,0 @@ -/* - * Code to handle irqs on Orion boards - * -- Cort <cort@fsmlabs.com> - */ -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/kernel_stat.h> -#include <linux/module.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/timex.h> -#include <linux/slab.h> -#include <linux/random.h> - -#include <asm/bitops.h> -#include <asm/bootinfo.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/mipsregs.h> -#include <asm/system.h> -#include <asm/orion.h> - -void (*board_time_init)(struct irqaction *irq); -extern asmlinkage void orionIRQ(void); -unsigned long spurious_count = 0; -irq_desc_t irq_desc[NR_IRQS]; - -static void galileo_ack(unsigned int irq_nr) -{ - *((unsigned long *) (((unsigned)( 0x14000000 )|0xA0000000) + 0xC18) ) = (((( 0 )&0xff)<<24)+ ((( 0 )&0xff00)<<8)+ ((( 0 )&0xff0000)>>8)+ ((( 0 )&0xff000000)>>24)) ; -} - -struct hw_interrupt_type galileo_pic = { - " Galileo ", - NULL, - NULL, - NULL, /* unmask_irq */ - NULL, /* mask_irq */ - galileo_ack, /* mask_and_ack */ - 0 -}; - -/* Function for careful CP0 interrupt mask access */ -static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask) -{ - unsigned long status = read_32bit_cp0_register(CP0_STATUS); - status &= ~((clr_mask & 0xFF) << 8); - status |= (set_mask & 0xFF) << 8; - write_32bit_cp0_register(CP0_STATUS, status); -} - -static inline void mask_irq(unsigned int irq_nr) -{ - modify_cp0_intmask(irq_nr, 0); -} - -static inline void unmask_irq(unsigned int irq_nr) -{ - modify_cp0_intmask(0, irq_nr); -} - -void disable_irq(unsigned int irq_nr) -{ - unsigned long flags; - - save_and_cli(flags); - mask_irq(irq_nr); - restore_flags(flags); -} - -void enable_irq(unsigned int irq_nr) -{ - unsigned long flags; - - save_and_cli(flags); - unmask_irq(irq_nr); - restore_flags(flags); -} - -/*static struct irqaction *irq_action[NR_IRQS] = { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; -*/ -void __init orion_time_init(struct irqaction *irq) -{ - __u32 timer_count; - - irq_desc[2].handler = &galileo_pic; - irq_desc[2].action = irq; - - /* This code was provided by the CoSine guys and despite its - * appearance init's the timer. - * -- Cort - */ - *((__u32 *) (((unsigned)( 0x14000000 )|0xA0000000) + 0x864) ) = (((( 0 )&0xff)<<24)+ ((( 0 )&0xff00)<<8)+ ((( 0 )&0xff0000)>>8)+ ((( 0 )&0xff000000)>>24)) ; - - *((__u32 *) (((unsigned)( 0x14000000 )|0xA0000000) + 0x850) ) = (((( 0 )&0xff)<<24)+ ((( 0 )&0xff00)<<8)+ ((( 0 )&0xff0000)>>8)+ ((( 0 )&0xff000000)>>24)) ; - - timer_count = 300000000/100; - - *((__u32 *) (((unsigned)( 0x14000000 )|0xA0000000) + 0x850) ) = (((( timer_count )&0xff)<<24)+ ((( timer_count )&0xff00)<<8)+ ((( timer_count )&0xff0000)>>8)+ ((( timer_count )&0xff000000)>>24)) ; - - *((__u32 *) (((unsigned)( 0x14000000 )|0xA0000000) + 0xC1C) ) = (((( 0x100 )&0xff)<<24)+ ((( 0x100 )&0xff00)<<8)+ ((( 0x100 )&0xff0000)>>8)+ ((( 0x100 )&0xff000000)>>24)) ; - - *((__u32 *) (((unsigned)( 0x14000000 )|0xA0000000) + 0x864) ) = (((( 0x03 )&0xff)<<24)+ ((( 0x03 )&0xff00)<<8)+ ((( 0x03 )&0xff0000)>>8)+ ((( 0x03 )&0xff000000)>>24)) ; - - *((__u32 *) (((unsigned)( 0x14000000 )|0xA0000000) + 0xC18) ) = (((( 0 )&0xff)<<24)+ ((( 0 )&0xff00)<<8)+ ((( 0 )&0xff0000)>>8)+ ((( 0 )&0xff000000)>>24)) ; -} - -int get_irq_list(char *buf) -{ - int i, len = 0, j; - struct irqaction * action; - - len += sprintf(buf+len, " "); - for (j=0; j<smp_num_cpus; j++) - len += sprintf(buf+len, "CPU%d ",j); - *(char *)(buf+len++) = '\n'; - - for (i = 0 ; i < NR_IRQS ; i++) { - action = irq_desc[i].action; - if ( !action || !action->handler ) - continue; - len += sprintf(buf+len, "%3d: ", i); - len += sprintf(buf+len, "%10u ", kstat_irqs(i)); - if ( irq_desc[i].handler ) - len += sprintf(buf+len, " %s ", irq_desc[i].handler->typename ); - else - len += sprintf(buf+len, " None "); - len += sprintf(buf+len, " %s",action->name); - for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ", %s", action->name); - } - len += sprintf(buf+len, "\n"); - } - len += sprintf(buf+len, "BAD: %10lu\n", spurious_count); - return len; -} - -asmlinkage void do_IRQ(int irq, struct pt_regs * regs) -{ - struct irqaction *action; - int do_random, cpu; - int status; - - cpu = smp_processor_id(); - irq_enter(cpu); - kstat.irqs[cpu][irq]++; - status = 0; - - if (irq_desc[irq].handler->ack) - irq_desc[irq].handler->ack(irq); - - action = irq_desc[irq].action; - if (action && action->handler) - { - if (!(action->flags & SA_INTERRUPT)) - __sti(); - do { - status |= action->flags; - action->handler(irq, action->dev_id, regs); - action = action->next; - } while ( action ); - __cli(); - if (irq_desc[irq].handler) - { - if (irq_desc[irq].handler->end) - irq_desc[irq].handler->end(irq); - else if (irq_desc[irq].handler->enable) - irq_desc[irq].handler->enable(irq); - } - } - - irq_exit(cpu); - - if (softirq_active(cpu)&softirq_mask(cpu)) - do_softirq(); - - /* unmasking and bottom half handling is done magically for us. */ -} - -int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, const char * devname, void *dev_id) -{ - struct irqaction *old, **p, *action; - unsigned long flags; - - if (irq >= NR_IRQS) - return -EINVAL; - if (!handler) - { - /* Free */ - for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) - { - /* Found it - now free it */ - save_flags(flags); - cli(); - *p = action->next; - restore_flags(flags); - kfree(action); - return 0; - } - return -ENOENT; - } - - action = (struct irqaction *) - kmalloc(sizeof(struct irqaction), GFP_KERNEL); - if (!action) - return -ENOMEM; - - save_flags(flags); - cli(); - - action->handler = handler; - action->flags = irqflags; - action->mask = 0; - action->name = devname; - action->dev_id = dev_id; - action->next = NULL; - enable_irq(irq); - - p = &irq_desc[irq].action; - - if ((old = *p) != NULL) { - /* Can't share interrupts unless both agree to */ - if (!(old->flags & action->flags & SA_SHIRQ)) - return -EBUSY; - /* add new interrupt at end of irq queue */ - do { - p = &old->next; - old = *p; - } while (old); - } - *p = action; - - restore_flags(flags); - return 0; -} - -void free_irq(unsigned int irq, void *dev_id) -{ - request_irq(irq, NULL, 0, NULL, dev_id); -} - - -unsigned long probe_irq_on (void) -{ - return 0; -} - -int probe_irq_off (unsigned long irqs) -{ - return 0; -} - -int (*irq_cannonicalize)(int irq); - -int orion_irq_cannonicalize(int i) -{ - return i; -} - -void __init init_IRQ(void) -{ - - irq_cannonicalize = orion_irq_cannonicalize; - set_except_vector(0, orionIRQ); -} - -EXPORT_SYMBOL(irq_cannonicalize); - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/orion/ld.script.orion linux.ac/arch/mips/orion/ld.script.orion --- linux.vanilla/arch/mips/orion/ld.script.orion Tue Jul 11 19:14:48 2000 +++ linux.ac/arch/mips/orion/ld.script.orion Thu Jan 1 01:00:00 1970 @@ -1,113 +0,0 @@ -OUTPUT_FORMAT("elf32-bigmips") -OUTPUT_ARCH(mips) -ENTRY(kernel_entry) -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = 0x80100000; - /* app_header is needed for the Orion bootloader -- Cort */ - .app_header : { *(.app_header) } - .init : { *(.init) } =0 - .text : - { - _ftext = . ; - *(.text) - *(.rodata) - *(.rodata1) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - } =0 - _etext = .; - PROVIDE (etext = .); - - . = ALIGN(8192); - .data.init_task : { *(.data.init_task) } - - /* Startup code */ - . = ALIGN(4096); - __init_begin = .; - .text.init : { *(.text.init) } - .data.init : { *(.data.init) } - . = ALIGN(16); - __setup_start = .; - .setup.init : { *(.setup.init) } - __setup_end = .; - __initcall_start = .; - .initcall.init : { *(.initcall.init) } - __initcall_end = .; - . = ALIGN(4096); /* Align double page for init_task_union */ - __init_end = .; - - . = ALIGN(4096); - .data.page_aligned : { *(.data.idt) } - - . = ALIGN(32); - .data.cacheline_aligned : { *(.data.cacheline_aligned) } - - .fini : { *(.fini) } =0 - .reginfo : { *(.reginfo) } - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. It would - be more correct to do this: - . = .; - The current expression does not correctly handle the case of a - text segment ending precisely at the end of a page; it causes the - data segment to skip a page. The above expression does not have - this problem, but it will currently (2/95) cause BFD to allocate - a single segment, combining both text and data, for this case. - This will prevent the text segment from being shared among - multiple executions of the program; I think that is more - important than losing a page of the virtual address space (note - that no actual memory is lost; the page which is skipped can not - be referenced). */ - . = .; - .data : - { - _fdata = . ; - *(.data) - CONSTRUCTORS - } - .data1 : { *(.data1) } - _gp = . + 0x8000; - .lit8 : { *(.lit8) } - .lit4 : { *(.lit4) } - .ctors : { *(.ctors) } - .dtors : { *(.dtors) } - .got : { *(.got.plt) *(.got) } - .dynamic : { *(.dynamic) } - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata : { *(.sdata) } - _edata = .; - PROVIDE (edata = .); - - __bss_start = .; - _fbss = .; - .sbss : { *(.sbss) *(.scommon) } - .bss : - { - *(.dynbss) - *(.bss) - *(COMMON) - _end = . ; - PROVIDE (end = .); - } - /* These are needed for ELF backends which have not yet been - converted to the new style linker. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - /* DWARF debug sections. - Symbols in the .debug DWARF section are relative to the beginning of the - section so we begin .debug at 0. It's not clear yet what needs to happen - for the others. */ - .debug 0 : { *(.debug) } - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - .debug_sfnames 0 : { *(.debug_sfnames) } - .line 0 : { *(.line) } - /* These must appear regardless of . */ - .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } - .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/orion/misc.c linux.ac/arch/mips/orion/misc.c --- linux.vanilla/arch/mips/orion/misc.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/mips/orion/misc.c Thu Jan 1 01:00:00 1970 @@ -1,100 +0,0 @@ -/* - * Catch-all for Orion-specify code that doesn't fit easily elsewhere. - * -- Cort - */ - -#include <linux/config.h> -#include <linux/errno.h> -#include <linux/hdreg.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/stddef.h> -#include <linux/string.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/user.h> -#include <linux/utsname.h> -#include <linux/a.out.h> -#include <linux/tty.h> -#ifdef CONFIG_BLK_DEV_RAM -#include <linux/blk.h> -#endif -#include <linux/ide.h> -#ifdef CONFIG_RTC -#include <linux/timex.h> -#endif - -#include <asm/asm.h> -#include <asm/bootinfo.h> -#include <asm/cachectl.h> -#include <asm/io.h> -#include <asm/stackframe.h> -#include <asm/system.h> -#include <asm/cpu.h> -#include <linux/bootmem.h> -#include <asm/addrspace.h> -#include <asm/mc146818rtc.h> - -char arcs_cmdline[CL_SIZE] = {0, }; -extern int _end; - -static unsigned char orion_rtc_read_data(unsigned long addr) -{ - return 0; -} - -static void orion_rtc_write_data(unsigned char data, unsigned long addr) -{ -} - -static int orion_rtc_bcd_mode(void) -{ - return 0; -} - -struct rtc_ops orion_rtc_ops = { - &orion_rtc_read_data, - &orion_rtc_write_data, - &orion_rtc_bcd_mode -}; - -extern void InitCIB(void); -extern void InitQpic(void); -extern void InitCupid(void); - -void __init orion_setup(void) -{ - InitCIB(); - InitQpic(); - InitCupid(); -} - -#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) -#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) - - - -int orion_sysinit(void) -{ - unsigned long mem_size, free_start, free_end, start_pfn, bootmap_size; - - mips_machgroup = MACH_GROUP_ORION; - /* 64 MB non-upgradable */ - mem_size = 32 << 20; - - free_start = PHYSADDR(PFN_ALIGN(&_end)); - free_end = mem_size; - start_pfn = PFN_UP((unsigned long)&_end); - - /* Register all the contiguous memory with the bootmem allocator - and free it. Be careful about the bootmem freemap. */ - bootmap_size = init_bootmem(start_pfn, mem_size >> PAGE_SHIFT); - - /* Free the entire available memory after the _end symbol. */ - free_start += bootmap_size; - free_bootmem(free_start, free_end-free_start); -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/orion/no_initrd.c linux.ac/arch/mips/orion/no_initrd.c --- linux.vanilla/arch/mips/orion/no_initrd.c Tue Jul 11 19:14:48 2000 +++ linux.ac/arch/mips/orion/no_initrd.c Thu Jan 1 01:00:00 1970 @@ -1,2 +0,0 @@ -unsigned long *orion_initrd_start = 0; -unsigned long orion_initrd_size = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/orion/piggyback.c linux.ac/arch/mips/orion/piggyback.c --- linux.vanilla/arch/mips/orion/piggyback.c Tue Jul 11 19:14:48 2000 +++ linux.ac/arch/mips/orion/piggyback.c Thu Jan 1 01:00:00 1970 @@ -1,59 +0,0 @@ -#include <stdio.h> -#include <unistd.h> - -extern long ce_exec_config[]; - -int main(int argc, char *argv[]) -{ - int i, cnt, pos, len; - unsigned int cksum, val; - unsigned char *lp; - unsigned char buf[8192]; - if (argc != 2) - { - fprintf(stderr, "usage: %s name <in-file >out-file\n", - argv[0]); - exit(1); - } - fprintf(stdout, "/*\n"); - fprintf(stdout, "* Miscellaneous data structures:\n"); - fprintf(stdout, "* WARNING - this file is automatically generated!\n"); - fprintf(stdout, "*/\n"); - fprintf(stdout, "\n"); - fprintf(stdout, "unsigned long orion_%s_start[] = {\n", argv[1]); - pos = 0; - cksum = 0; - while ((len = read(0, buf, sizeof(buf))) > 0) - { - cnt = 0; - lp = (unsigned char *)buf; - len = (len + 3) & ~3; /* Round up to longwords */ - for (i = 0; i < len; i += 4) - { - if (cnt == 0) - { - fprintf(stdout, "\t"); - } - fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]); - val = *(unsigned long *)lp; - cksum ^= val; - lp += 4; - if (++cnt == 4) - { - cnt = 0; - fprintf(stdout, ", /* %x */\n", pos+i-12); - fflush(stdout); - } else - { - fprintf(stdout, ","); - } - } - pos += len; - } - fprintf(stdout, "0 };\n"); - fprintf(stdout, "unsigned long orion_%s_size = 0x%x;\n", argv[1], pos); - fflush(stdout); - fclose(stdout); - fprintf(stderr, "cksum = %x\n", cksum); - exit(0); -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/orion/promcon.c linux.ac/arch/mips/orion/promcon.c --- linux.vanilla/arch/mips/orion/promcon.c Thu Oct 12 22:20:48 2000 +++ linux.ac/arch/mips/orion/promcon.c Thu Jan 1 01:00:00 1970 @@ -1,168 +0,0 @@ -/* - * Wrap-around code for a console using the - * SGI PROM io-routines. - * - * Copyright (c) 1999 Ulf Carlsson - * - * Derived from DECstation promcon.c - * Copyright (c) 1998 Harald Koerfgen - */ - -#include <linux/tty.h> -#include <linux/major.h> -#include <linux/ptrace.h> -#include <linux/init.h> -#include <linux/console.h> -#include <linux/fs.h> -/* -#include <asm/sgialib.h> -*/ -extern void prom_printf(char *fmt, ...); -unsigned long splx(unsigned long mask){return 0;} -#if 0 -unsigned long ramsize=0x100000; -unsigned long RamSize(){return ramsize;} -extern void prom_printf(char *fmt, ...); -unsigned long splx(unsigned long mask){return 0;} -long PssSetIntHandler(unsigned long intnum, void *handler){} -long PssEnableInt(unsigned long intnum){} -long PssDisableInt(unsigned long intnum){} -unsigned long t_ident(char name[4], unsigned long node, unsigned long *tid){} -#endif - -extern void SerialPollConout(unsigned char c); -static void prom_console_write(struct console *co, const char *s, - unsigned count) -{ - unsigned i; - - /* - * Now, do each character - */ - for (i = 0; i < count; i++) { - if (*s == 10) - SerialPollConout(13); - SerialPollConout(*s++); - } -} -extern int prom_getchar(void); -static int prom_console_wait_key(struct console *co) -{ - return prom_getchar(); -} - -extern void SerialPollInit(void); -extern void SerialSetup(unsigned long baud, unsigned long console, unsigned long host, unsigned long intr_desc); -static int __init prom_console_setup(struct console *co, char *options) -{ - SerialSetup(19200,1,1,3); - SerialPollInit(); - SerialPollOn(); - return 0; -} - -static kdev_t prom_console_device(struct console *c) -{ - return MKDEV(TTY_MAJOR, 64 + c->index); -} - -static struct console sercons = -{ - name: "ttyS", - write: prom_console_write, - device: prom_console_device, - wait_key: prom_console_wait_key, - setup: prom_console_setup, - flags: CON_PRINTBUFFER, - index: -1, -}; - -/* - * Register console. - */ - -void serial_console_init(void) -{ - register_console(&sercons); -} - -extern void prom_putchar(int mychar); - -static char ppbuf[1000]; - - -void prom_printf(char *fmt, ...) -{ - va_list args; - char ch, *bptr; - int i; - - va_start(args, fmt); - i = vsprintf(ppbuf, fmt, args); - - bptr = ppbuf; - - while((ch = *(bptr++)) != 0) { - if(ch == '\n') - prom_putchar('\r'); - - prom_putchar(ch); - } - va_end(args); - return; -} - - - -void prom_putchar(int mychar){} -int prom_getchar(void){return 0;} -struct app_header_s { - unsigned long MAGIC_JMP; - unsigned long MAGIC_NOP; - unsigned long header_tag; - unsigned long header_flags; - unsigned long header_length; - unsigned long header_cksum; - - void *load_addr; - void *end_addr; - void *start_addr; - char *app_name_p; - char *version_p; - char *date_p; - char *time_p; - unsigned long type; - unsigned long crc; - unsigned long reserved; -}; -typedef struct app_header_s app_header_t; -char linked_app_name[]="linux"; -char *linked_app_name_p=&linked_app_name[0]; - -char linked_app_ver[]="2.4 -test1"; -char *linked_app_ver_p=&linked_app_ver[0]; - -char linked_app_date[]="today"; -char *linked_app_date_p=&linked_app_date[0]; - -char linked_app_time[]="now"; -char *linked_app_time_p=&linked_app_time[0]; -extern void *__bss_start; -extern void *kernel_entry; - -app_header_t app_header __attribute__ ((section (".app_header"))) = { - (0x10000000 | (((sizeof(app_header_t)>>2)-1) & 0xffff)) , - 0 , - (((( 0x4321 ) & 0xFFFF) << 16) | (( 0x0100 ) & 0xFFFF)) , - 0x80000000 , - sizeof(app_header_t), - 0, - &app_header, - &__bss_start, - &kernel_entry, - linked_app_name, - linked_app_ver, - linked_app_date, - linked_app_time, - 0 -}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/orion/setup.c linux.ac/arch/mips/orion/setup.c --- linux.vanilla/arch/mips/orion/setup.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/mips/orion/setup.c Thu Jan 1 01:00:00 1970 @@ -1,125 +0,0 @@ -/* - * Catch-all for Orion-specific code that doesn't fit easily elsewhere. - * -- Cort - */ -#include <linux/config.h> -#include <linux/errno.h> -#include <linux/hdreg.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/stddef.h> -#include <linux/string.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/user.h> -#include <linux/utsname.h> -#include <linux/a.out.h> -#include <linux/tty.h> -#include <linux/interrupt.h> -#ifdef CONFIG_BLK_DEV_RAM -#include <linux/blk.h> -#endif -#include <linux/ide.h> -#ifdef CONFIG_RTC -#include <linux/timex.h> -#endif - -#include <asm/asm.h> -#include <asm/bootinfo.h> -#include <asm/cachectl.h> -#include <asm/io.h> -#include <asm/stackframe.h> -#include <asm/system.h> -#include <asm/cpu.h> -#include <linux/bootmem.h> -#include <asm/addrspace.h> -#include <asm/mc146818rtc.h> -#include <asm/orion.h> - -char arcs_cmdline[CL_SIZE] = { "console=ttyS0,19200" }; -extern int _end; - -static unsigned char orion_rtc_read_data(unsigned long addr) -{ - return 0; -} - -static void orion_rtc_write_data(unsigned char data, unsigned long addr) -{ -} - -static int orion_rtc_bcd_mode(void) -{ - return 0; -} - -struct rtc_ops orion_rtc_ops = { - &orion_rtc_read_data, - &orion_rtc_write_data, - &orion_rtc_bcd_mode -}; - -extern void InitCIB(void); -extern void InitQpic(void); -extern void InitCupid(void); - -void __init orion_setup(void) -{ - extern void (*board_time_init)(struct irqaction *irq); - void orion_time_init(struct irqaction *); - - rtc_ops = &orion_rtc_ops; - board_time_init = orion_time_init; - mips_io_port_base = GT64120_BASE; - - InitCIB(); - InitQpic(); - InitCupid(); -} - -#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) -#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) - -unsigned long mem_size; -int __init prom_init(int a, char **b, char **c, int *d) -{ - unsigned long free_start, free_end, start_pfn, bootmap_size; - extern unsigned long orion_initrd_start[], orion_initrd_size; - - mips_machgroup = MACH_GROUP_ORION; - /* 64 MB non-upgradable */ - mem_size = 64 << 20; - - free_start = PHYSADDR(PFN_ALIGN(&_end)); - free_end = mem_size; - start_pfn = PFN_UP((unsigned long)&_end); - - /* Register all the contiguous memory with the bootmem allocator - and free it. Be careful about the bootmem freemap. */ - bootmap_size = init_bootmem(start_pfn, mem_size >> PAGE_SHIFT); - - /* Free the entire available memory after the _end symbol. */ - free_start += bootmap_size; - free_bootmem(free_start, free_end-free_start); - - initrd_start = (ulong)orion_initrd_start; - initrd_end = (ulong)orion_initrd_start + (ulong)orion_initrd_size; - initrd_below_start_ok = 1; - - return 0; -} - -void prom_free_prom_memory (void) -{ -} - -int page_is_ram(unsigned long pagenr) -{ - if ( pagenr < (mem_size >> PAGE_SHIFT) ) - return 1; - return 0; -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/sgi/kernel/Makefile linux.ac/arch/mips/sgi/kernel/Makefile --- linux.vanilla/arch/mips/sgi/kernel/Makefile Mon Jul 10 06:18:15 2000 +++ linux.ac/arch/mips/sgi/kernel/Makefile Tue Apr 3 17:54:33 2001 @@ -13,21 +13,13 @@ .S.o: $(CC) $(CFLAGS) -c $< -o $*.o -OBJS = indy_mc.o indy_sc.o indy_hpc.o indy_int.o indy_rtc.o \ - system.o indyIRQ.o reset.o setup.o time.o -ifdef CONFIG_SGI_PROM_CONSOLE -OBJS += promcon.o -endif +O_TARGET := ip22-kern.o -all: sgikern.a +all: ip22-kern.o indyIRQ.o -sgikern.a: $(OBJS) - $(AR) rcs sgikern.a $(OBJS) - sync +obj-y += indy_mc.o indy_sc.o indy_hpc.o indy_int.o indy_rtc.o system.o \ + indyIRQ.o reset.o setup.o time.o indyIRQ.o: indyIRQ.S - -dep: - $(CPP) $(CPPFLAGS) -M *.c > .depend include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/sni/Makefile linux.ac/arch/mips/sni/Makefile --- linux.vanilla/arch/mips/sni/Makefile Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/sni/Makefile Tue Apr 3 17:54:33 2001 @@ -1,4 +1,3 @@ -# $Id: Makefile,v 1.3 1999/01/04 16:03:57 ralf Exp $ # # Makefile for the SNI specific part of the kernel # @@ -12,12 +11,12 @@ .S.o: $(CC) $(CFLAGS) -c $< -o $*.o -all: sni.o +all: sni.o int-handler.o + O_TARGET := sni.o -O_OBJS := dma.o int-handler.o io.o pci.o pcimt_scache.o reset.o setup.o -int-handler.o: int-handler.S +obj-y := int-handler.o io.o irq.o pci.o pcimt_scache.o reset.o setup.o -clean: +int-handler.o: int-handler.S include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips64/config.in linux.ac/arch/mips64/config.in --- linux.vanilla/arch/mips64/config.in Mon Feb 5 05:48:46 2001 +++ linux.ac/arch/mips64/config.in Tue Apr 3 17:54:33 2001 @@ -163,7 +163,7 @@ fi endmenu -source drivers/i2o/Config.in +source drivers/message/i2o/Config.in if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips64/defconfig linux.ac/arch/mips64/defconfig --- linux.vanilla/arch/mips64/defconfig Tue Apr 3 17:31:55 2001 +++ linux.ac/arch/mips64/defconfig Tue Apr 3 17:54:33 2001 @@ -120,6 +120,11 @@ # CONFIG_BRIDGE is not set # +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# # Telephony Support # # CONFIG_PHONE is not set @@ -422,6 +427,7 @@ # CONFIG_MAC_PARTITION is not set CONFIG_MSDOS_PARTITION=y # CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set CONFIG_SGI_PARTITION=y diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips64/defconfig-ip22 linux.ac/arch/mips64/defconfig-ip22 --- linux.vanilla/arch/mips64/defconfig-ip22 Mon Feb 5 05:48:46 2001 +++ linux.ac/arch/mips64/defconfig-ip22 Tue Apr 3 17:54:33 2001 @@ -110,6 +110,11 @@ # CONFIG_BRIDGE is not set # +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# # Telephony Support # # CONFIG_PHONE is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips64/defconfig-ip27 linux.ac/arch/mips64/defconfig-ip27 --- linux.vanilla/arch/mips64/defconfig-ip27 Mon Feb 5 05:48:46 2001 +++ linux.ac/arch/mips64/defconfig-ip27 Tue Apr 3 17:54:33 2001 @@ -120,6 +120,11 @@ # CONFIG_BRIDGE is not set # +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# # Telephony Support # # CONFIG_PHONE is not set @@ -165,6 +170,7 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set @@ -421,6 +427,7 @@ # CONFIG_MAC_PARTITION is not set CONFIG_MSDOS_PARTITION=y # CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set CONFIG_SGI_PARTITION=y diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips64/mm/Makefile linux.ac/arch/mips64/mm/Makefile --- linux.vanilla/arch/mips64/mm/Makefile Mon Feb 5 05:48:46 2001 +++ linux.ac/arch/mips64/mm/Makefile Tue Apr 3 17:54:33 2001 @@ -4,7 +4,8 @@ O_TARGET := mm.o -obj-y := extable.o init.o fault.o loadmmu.o +export-objs += umap.o +obj-y := extable.o init.o fault.o loadmmu.o obj-$(CONFIG_CPU_R4300) += r4xx0.o obj-$(CONFIG_CPU_R4X00) += r4xx0.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips64/mm/fault.c linux.ac/arch/mips64/mm/fault.c --- linux.vanilla/arch/mips64/mm/fault.c Tue Apr 3 17:31:55 2001 +++ linux.ac/arch/mips64/mm/fault.c Tue Apr 3 17:54:33 2001 @@ -6,6 +6,7 @@ * Copyright (C) 1995 - 2000 by Ralf Baechle * Copyright (C) 1999, 2000 by Silicon Graphics, Inc. */ +#include <linux/config.h> #include <linux/signal.h> #include <linux/sched.h> #include <linux/interrupt.h> @@ -31,6 +32,7 @@ #define development_version (LINUX_VERSION_CODE & 0x100) extern void die(char *, struct pt_regs *, unsigned long write); +extern int console_loglevel; /* * Macro for exception fixup code to access integer registers. @@ -57,17 +59,34 @@ printk("Got exception 0x%lx at 0x%lx\n", retaddr, regs.cp0_epc); } -extern spinlock_t console_lock, timerlist_lock; +extern spinlock_t timerlist_lock; /* * Unlock any spinlocks which will prevent us from getting the - * message out (timerlist_lock is acquired through the + * message out (timerlist_lock is aquired through the * console unblank code) */ -void bust_spinlocks(void) +void bust_spinlocks(int yes) { - spin_lock_init(&console_lock); spin_lock_init(&timerlist_lock); + if (yes) { + oops_in_progress = 1; +#ifdef CONFIG_SMP + global_irq_lock = 0; /* Many serial drivers do __global_cli() */ +#endif + } else { + int loglevel_save = console_loglevel; + unblank_screen(); + oops_in_progress = 0; + /* + * OK, the message is on the console. Now we call printk() + * without oops_in_progress set so that printk will give klogd + * a poke. Hold onto your hats... + */ + console_loglevel = 15; /* NMI oopser may have shut the console up */ + printk(" "); + console_loglevel = loglevel_save; + } } /* @@ -195,7 +214,7 @@ * terminate things with extreme prejudice. */ - bust_spinlocks(); + bust_spinlocks(1); printk(KERN_ALERT "Cpu %d Unable to handle kernel paging request at " "address %08lx, epc == %08x, ra == %08x\n", @@ -203,6 +222,7 @@ (unsigned int) regs->regs[31]); die("Oops", regs, write); do_exit(SIGKILL); + bust_spinlocks(0); /* * We ran out of memory, or some other thing happened to us that made diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips64/mm/init.c linux.ac/arch/mips64/mm/init.c --- linux.vanilla/arch/mips64/mm/init.c Mon Oct 16 20:58:51 2000 +++ linux.ac/arch/mips64/mm/init.c Tue Apr 3 17:54:33 2001 @@ -37,6 +37,9 @@ #include <asm/sgialib.h> #endif #include <asm/mmu_context.h> +#include <asm/tlb.h> + +mmu_gather_t mmu_gathers[NR_CPUS]; unsigned long totalram_pages; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips64/tools/Makefile linux.ac/arch/mips64/tools/Makefile --- linux.vanilla/arch/mips64/tools/Makefile Mon Jul 10 06:18:16 2000 +++ linux.ac/arch/mips64/tools/Makefile Tue Apr 3 17:54:33 2001 @@ -1,4 +1,3 @@ -# $Id: Makefile,v 1.1 1999/08/18 21:46:53 ralf Exp $ # # Makefile for MIPS kernel build tools. # diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/Makefile linux.ac/arch/parisc/Makefile --- linux.vanilla/arch/parisc/Makefile Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/Makefile Tue Apr 3 17:54:33 2001 @@ -39,6 +39,8 @@ # No fixed-point multiply CFLAGS += -mdisable-fpregs +ASFLAGS := -D__ASSEMBLY__ -traditional + HEAD = arch/parisc/kernel/head.o SUBDIRS := $(SUBDIRS) $(addprefix arch/parisc/, tools kernel mm lib hpux) @@ -85,6 +87,7 @@ install: archclean: + $(MAKE) -C arch/$(ARCH)/tools clean archmrproper: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/config.common linux.ac/arch/parisc/config.common --- linux.vanilla/arch/parisc/config.common Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/parisc/config.common Tue Apr 3 17:54:33 2001 @@ -0,0 +1,159 @@ +# +# For a description of the syntax of this configuration file, +# see the Configure script. +# + +mainmenu_name "Linux Kernel Configuration" + +define_bool CONFIG_PARISC y +define_bool CONFIG_UID16 n + +mainmenu_option next_comment +comment 'Code maturity level options' +bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL +endmenu + +mainmenu_option next_comment +comment 'Loadable module support' +bool 'Enable loadable module support' CONFIG_MODULES +if [ "$CONFIG_MODULES" = "y" ]; then + bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS + bool 'Kernel module loader' CONFIG_KMOD +fi +endmenu + +mainmenu_option next_comment +comment 'General options' + +bool 'Symmetric multi-processing support' CONFIG_SMP + +bool 'Kernel Debugger support' CONFIG_KWDB +# define_bool CONFIG_KWDB n + +bool 'GSC/Gecko bus support' CONFIG_GSC y + +bool 'U2/Uturn I/O MMU' CONFIG_IOMMU_CCIO y +bool 'LASI I/O support' CONFIG_GSC_LASI y +bool 'WAX support' CONFIG_GSC_WAX y + +bool 'PCI or EISA bus support' CONFIG_PCI y + +if [ "$CONFIG_PCI" = "y" ]; then + bool ' GSCtoPCI/DINO PCI support' CONFIG_GSC_DINO y + bool ' LBA/Elroy PCI support' CONFIG_PCI_LBA n +# bool ' EPIC PCI support' CONFIG_PCI_EPIC n + dep_bool ' WAX EISA support' CONFIG_WAX_EISA y $CONFIG_GSC_WAX + bool ' SuperIO support' CONFIG_SUPERIO n +fi + +if [ "$CONFIG_PCI_LBA" = "y" ]; then + define_bool CONFIG_IOSAPIC y + define_bool CONFIG_IOMMU_SBA y +fi + +source drivers/pci/Config.in + +bool 'Chassis LCD and LED support' CONFIG_CHASSIS_LCD_LED y + +endmenu + +mainmenu_option next_comment +comment 'General setup' + +bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG + +bool 'Networking support' CONFIG_NET + +bool 'System V IPC' CONFIG_SYSVIPC +bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT +bool 'Sysctl support' CONFIG_SYSCTL +define_bool CONFIG_KCORE_ELF y +tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +tristate 'Kernel support for SOM binaries' CONFIG_BINFMT_SOM +tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC + +# anyone want to get ACPI working on PA/RISC? +define_bool CONFIG_PM n + +endmenu + +source drivers/parport/Config.in + +source drivers/block/Config.in + +source drivers/md/Config.in + +if [ "$CONFIG_NET" = "y" ]; then + source net/Config.in +fi + +# when SuckyIO is working, put the IDE stuff in here. + +mainmenu_option next_comment +comment 'SCSI support' + +tristate 'SCSI support' CONFIG_SCSI + +if [ "$CONFIG_SCSI" != "n" ]; then + source drivers/scsi/Config.in +fi +endmenu + +if [ "$CONFIG_NET" = "y" ]; then + mainmenu_option next_comment + comment 'Network device support' + + bool 'Network device support' CONFIG_NETDEVICES + + if [ "$CONFIG_NETDEVICES" = "y" ]; then + source drivers/net/Config.in + if [ "$CONFIG_ATM" = "y" ]; then + source drivers/atm/Config.in + fi + fi + endmenu +fi + +# +# input before char - char/joystick depends on it. As does USB. +# +source drivers/input/Config.in +source drivers/char/Config.in + +source drivers/media/Config.in + +source fs/Config.in + +if [ "$CONFIG_VT" = "y" ]; then + mainmenu_option next_comment + comment 'Console drivers' + source drivers/video/Config.in + + bool 'STI console' CONFIG_STI_CONSOLE + if [ "$CONFIG_GSC_PS2" = "y" ]; then + define_bool CONFIG_DUMMY_CONSOLE y + fi + if [ "$CONFIG_STI_CONSOLE" = "y" ]; then + define_bool CONFIG_DUMMY_CONSOLE y + fi + endmenu +fi + +mainmenu_option next_comment +comment 'Sound' + +tristate 'Sound card support' CONFIG_SOUND +if [ "$CONFIG_SOUND" != "n" ]; then + source drivers/sound/Config.in +fi +endmenu + +# when SuckyIO is working +#source drivers/usb/Config.in + +mainmenu_option next_comment +comment 'Kernel hacking' + +#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC +bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/config.in linux.ac/arch/parisc/config.in --- linux.vanilla/arch/parisc/config.in Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/config.in Tue Apr 3 17:54:33 2001 @@ -3,206 +3,6 @@ # see the Configure script. # -mainmenu_name "Linux Kernel Configuration" - -define_bool CONFIG_PARISC y -define_bool CONFIG_UID16 n - -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 'General options' - -# bool 'Symmetric multi-processing support' CONFIG_SMP -define_bool CONFIG_SMP n - -bool 'Kernel Debugger support' CONFIG_KWDB -# define_bool CONFIG_KWDB n - -# bool 'GSC/Gecko bus support' CONFIG_GSC y -define_bool CONFIG_GSC y - -bool 'U2/Uturn I/O MMU' CONFIG_IOMMU_CCIO y -bool 'LASI I/O support' CONFIG_GSC_LASI y - -bool 'PCI bus support' CONFIG_PCI y - -if [ "$CONFIG_PCI" = "y" ]; then - bool 'GSCtoPCI/DINO PCI support' CONFIG_GSC_DINO y - bool 'LBA/Elroy PCI support' CONFIG_PCI_LBA n -fi - -if [ "$CONFIG_PCI_LBA" = "y" ]; then - define_bool CONFIG_IOSAPIC y - define_bool CONFIG_IOMMU_SBA y -fi - -# -# if [ "$CONFIG_PCI_EPIC" = "y" ]; then... -# - -endmenu - -mainmenu_option next_comment -comment 'Loadable module support' -bool 'Enable loadable module support' CONFIG_MODULES -if [ "$CONFIG_MODULES" = "y" ]; then - bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS - bool 'Kernel module loader' CONFIG_KMOD -fi -endmenu - -mainmenu_option next_comment -comment 'General setup' - -bool 'Networking support' CONFIG_NET - -bool 'System V IPC' CONFIG_SYSVIPC -bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT -bool 'Sysctl support' CONFIG_SYSCTL -tristate 'Kernel support for SOM binaries' CONFIG_BINFMT_SOM -tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF -tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA -fi - -endmenu - -##source drivers/parport/Config.in -mainmenu_option next_comment -comment 'Parallel port support' - -tristate 'Parallel port support' CONFIG_PARPORT -if [ "$CONFIG_PARPORT" != "n" ]; then - if [ "$CONFIG_PCI" = "y" ]; then - dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT - if [ "$CONFIG_PARPORT_PC" != "n" ]; then - bool ' Use FIFO/DMA if available' CONFIG_PARPORT_PC_FIFO - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' SuperIO chipset support (EXPERIMENTAL)' CONFIG_PARPORT_PC_SUPERIO - fi - fi - fi - if [ "$CONFIG_GSC_LASI" = "y" ]; then - dep_tristate ' LASI/ASP builtin parallel-port' CONFIG_PARPORT_GSC $CONFIG_PARPORT - else - define_tristate CONFIG_PARPORT_GSC n - fi - - # If exactly one hardware type is selected then parport will optimise away - # support for loading any others. Defeat this if the user is keen. - bool ' Support foreign hardware' CONFIG_PARPORT_OTHER - - bool ' IEEE 1284 transfer modes' CONFIG_PARPORT_1284 -fi -endmenu - - -source drivers/block/Config.in - -if [ "$CONFIG_NET" = "y" ]; then - source net/Config.in -fi - -mainmenu_option next_comment -comment 'SCSI support' - -tristate 'SCSI support' CONFIG_SCSI - -if [ "$CONFIG_SCSI" != "n" ]; then - comment 'SCSI support type (disk, tape, CDrom)' - - dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI - if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then - int 'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40 - fi - - dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI - dep_tristate 'SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI - if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then - bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR - int 'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2 - fi - dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI - - comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' - bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN - bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS - - mainmenu_option next_comment - comment 'SCSI low-level drivers' - if [ "$CONFIG_GSC_LASI" = "y" ]; then - dep_tristate 'Lasi SCSI support' CONFIG_SCSI_LASI $CONFIG_SCSI - dep_tristate 'Zalon SCSI support' CONFIG_SCSI_ZALON $CONFIG_SCSI - fi - if [ "$CONFIG_PCI" = "y" ]; then - dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI - fi - if [ "$CONFIG_SCSI_ZALON" != "n" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then - int ' default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8 - int ' maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32 - int ' synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 20 - bool ' enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE - bool ' use normal IO' CONFIG_SCSI_NCR53C8XX_IOMAPPED - fi - endmenu -fi -endmenu - -if [ "$CONFIG_NET" = "y" ]; then - mainmenu_option next_comment - comment 'Network device support' - - bool 'Network device support' CONFIG_NETDEVICES - - if [ "$CONFIG_NETDEVICES" = "y" ]; then - if [ "$CONFIG_GSC_LASI" = "y" ]; then - tristate 'Lasi ethernet' CONFIG_LASI_82596 - fi - source drivers/net/Config.in - fi - endmenu -fi - -source drivers/char/Config.in - -source fs/Config.in - -mainmenu_option next_comment -comment 'Sound Drivers' -tristate 'Sound card support' CONFIG_SOUND -if [ "$CONFIG_SOUND" != "n" ]; then - source drivers/sound/Config.in -fi -endmenu - -if [ "$CONFIG_VT" = "y" ]; then - mainmenu_option next_comment - comment 'Console drivers' - source drivers/video/Config.in - -# bool 'IODC console' CONFIG_IODC_CONSOLE - bool 'STI console' CONFIG_STI_CONSOLE - if [ "$CONFIG_IODC_CONSOLE" = "n" ]; then - if [ "$CONFIG_GSC_PS2" = "y" ]; then - define_bool CONFIG_DUMMY_CONSOLE y - fi - fi - if [ "$CONFIG_STI_CONSOLE" = "y" ]; then - define_bool CONFIG_DUMMY_CONSOLE y - fi - endmenu -fi -# endmenu - -mainmenu_option next_comment -comment 'Kernel hacking' - -#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC -bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ -endmenu +define_bool CONFIG_PARISC32 y +source arch/parisc/config.common diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/defconfig linux.ac/arch/parisc/defconfig --- linux.vanilla/arch/parisc/defconfig Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/defconfig Tue Apr 3 17:54:33 2001 @@ -1,6 +1,7 @@ # -# Automatically generated by make menuconfig: don't edit +# Automatically generated make config: don't edit # +CONFIG_PARISC32=y CONFIG_PARISC=y # CONFIG_UID16 is not set @@ -10,6 +11,11 @@ CONFIG_EXPERIMENTAL=y # +# Loadable module support +# +# CONFIG_MODULES is not set + +# # General options # # CONFIG_SMP is not set @@ -17,37 +23,41 @@ CONFIG_GSC=y CONFIG_IOMMU_CCIO=y CONFIG_GSC_LASI=y +CONFIG_GSC_WAX=y CONFIG_PCI=y CONFIG_GSC_DINO=y CONFIG_PCI_LBA=y +CONFIG_WAX_EISA=y +# CONFIG_SUPERIO is not set CONFIG_IOSAPIC=y CONFIG_IOMMU_SBA=y - -# -# Loadable module support -# -CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set -CONFIG_KMOD=y +CONFIG_PCI_NAMES=y +CONFIG_CHASSIS_LCD_LED=y # # General setup # +CONFIG_HOTPLUG=y CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y -CONFIG_BINFMT_SOM=y +CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_SOM=y # CONFIG_BINFMT_MISC is not set -# CONFIG_BINFMT_JAVA is not set +# CONFIG_PM is not set # # Parallel port support # CONFIG_PARPORT=y # CONFIG_PARPORT_PC is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set CONFIG_PARPORT_GSC=y +# CONFIG_PARPORT_SUNBPP is not set # CONFIG_PARPORT_OTHER is not set # CONFIG_PARPORT_1284 is not set @@ -67,6 +77,20 @@ CONFIG_BLK_DEV_INITRD=y # +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=y +CONFIG_MD_RAID0=y +CONFIG_MD_RAID1=y +CONFIG_MD_RAID5=y +# CONFIG_MD_BOOT is not set +# CONFIG_AUTODETECT_RAID is not set +# CONFIG_BLK_DEV_LVM is not set +# CONFIG_LVM_PROC_FS is not set + +# # Networking options # # CONFIG_PACKET is not set @@ -87,6 +111,10 @@ # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set + +# +# +# # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set @@ -109,33 +137,92 @@ # SCSI support # CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y +# CONFIG_CHR_DEV_OSST is not set CONFIG_BLK_DEV_SR=y # CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set # CONFIG_SCSI_MULTI_LUN is not set # CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set # # SCSI low-level drivers # +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# 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_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D 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_LASI=y CONFIG_SCSI_ZALON=y +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set CONFIG_SCSI_SYM53C8XX=y CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 CONFIG_SCSI_NCR53C8XX_SYNC=20 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set +# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set +# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_SCSI_PCMCIA is not set # # Network device support # CONFIG_NETDEVICES=y -CONFIG_LASI_82596=y # # ARCnet devices @@ -151,6 +238,7 @@ # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +CONFIG_LASI_82596=y # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set @@ -162,27 +250,28 @@ CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set # CONFIG_ADAPTEC_STARFIRE is not set -# CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set -# CONFIG_DE4X5 is not set CONFIG_TULIP=y +# CONFIG_DE4X5 is not set # CONFIG_DGRS is not set # CONFIG_DM9102 is not set # CONFIG_EEPRO100 is not set +# CONFIG_EEPRO100_PM is not set # CONFIG_LNE390 is not set # CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set # CONFIG_NE3210 is not set # CONFIG_ES3210 is not set -# CONFIG_RTL8129 is not set # CONFIG_8139TOO is not set +# CONFIG_RTL8129 is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set # CONFIG_WINBOND_840 is not set +# CONFIG_HAPPYMEAL is not set # CONFIG_NET_POCKET is not set # @@ -217,6 +306,16 @@ # CONFIG_WAN is not set # +# PCMCIA network device support +# +# CONFIG_NET_PCMCIA is not set + +# +# Input core support +# +# CONFIG_INPUT is not set + +# # Character devices # CONFIG_VT=y @@ -249,6 +348,10 @@ # Joysticks # # CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# # CONFIG_QIC02_TAPE is not set # @@ -269,6 +372,17 @@ # CONFIG_FTAPE is not set # CONFIG_AGP is not set # CONFIG_DRM is not set +CONFIG_PCMCIA_SERIAL=y + +# +# PCMCIA character device support +# +# CONFIG_PCMCIA_SERIAL_CS is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems @@ -330,8 +444,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -340,14 +452,10 @@ # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # -# Sound Drivers -# -# CONFIG_SOUND is not set - -# # Console drivers # @@ -356,6 +464,12 @@ # # CONFIG_FB is not set # CONFIG_STI_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set # # Kernel hacking diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/hpux/Makefile linux.ac/arch/parisc/hpux/Makefile --- linux.vanilla/arch/parisc/hpux/Makefile Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/hpux/Makefile Tue Apr 3 17:54:33 2001 @@ -7,10 +7,7 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -all: hpux.o O_TARGET = hpux.o -O_OBJS = entry_hpux.o gate.o wrappers.o fs.o ioctl.o sys_hpux.o - -.o.S: $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $*.S -o $*.o +obj-y := entry_hpux.o gate.o wrappers.o fs.o ioctl.o sys_hpux.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/hpux/fs.c linux.ac/arch/parisc/hpux/fs.c --- linux.vanilla/arch/parisc/hpux/fs.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/hpux/fs.c Tue Apr 3 17:54:33 2001 @@ -52,7 +52,8 @@ #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1)) -static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino) +static int filldir(void * __buf, const char * name, int namlen, off_t offset, + ino_t ino, unsigned int d_type) { struct hpux_dirent * dirent; struct getdents_callback * buf = (struct getdents_callback *) __buf; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/hpux/gate.S linux.ac/arch/parisc/hpux/gate.S --- linux.vanilla/arch/parisc/hpux/gate.S Wed Dec 6 19:46:39 2000 +++ linux.ac/arch/parisc/hpux/gate.S Tue Apr 3 17:54:33 2001 @@ -8,7 +8,6 @@ * sorry about the wall, puffin.. */ -#define __ASSEMBLY__ #include <asm/assembly.h> #include <asm/offset.h> #include <asm/unistd.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/hpux/ioctl.c linux.ac/arch/parisc/hpux/ioctl.c --- linux.vanilla/arch/parisc/hpux/ioctl.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/hpux/ioctl.c Tue Apr 3 17:54:33 2001 @@ -54,10 +54,6 @@ case 't': result = hpux_ioctl_t(fd, cmd, arg); break; - default: - /* If my mother ever sees this, I hope she disowns me. - * Take this out after NYLWE. */ - result = sys_ioctl(fd, cmd, arg); } return result; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/hpux/wrappers.S linux.ac/arch/parisc/hpux/wrappers.S --- linux.vanilla/arch/parisc/hpux/wrappers.S Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/hpux/wrappers.S Tue Apr 3 17:54:33 2001 @@ -29,7 +29,6 @@ .level 1.1 .text -#define __ASSEMBLY__ #include <asm/assembly.h> #include <asm/signal.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/Makefile linux.ac/arch/parisc/kernel/Makefile --- linux.vanilla/arch/parisc/kernel/Makefile Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/Makefile Tue Apr 3 17:54:33 2001 @@ -8,25 +8,23 @@ # Note 2! The CFLAGS definitions are now in the main makefile... all: kernel.o init_task.o pdc_cons.o process.o head.o -O_TARGET = kernel.o -O_OBJS = -# Object file lists. +O_TARGET = kernel.o obj-y := obj-m := obj-n := obj- := -obj-y += cache.o setup.o traps.o time.o irq.o \ +obj-y += cache.o pacache.o setup.o traps.o time.o irq.o \ syscall.o entry.o sys_parisc.o pdc.o ptrace.o hardware.o \ inventory.o drivers.o semaphore.o pa7300lc.o pci-dma.o \ - signal.o hpmc.o \ - real1.o real2.o led.o parisc_ksyms.o + signal.o hpmc.o real1.o real2.o parisc_ksyms.o export-objs := parisc_ksyms.o +obj-$(CONFIG_SMP) += smp.o irq_smp.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_VT) += keyboard.o obj-$(CONFIG_PCI_LBA) += lba_pci.o @@ -37,16 +35,7 @@ # Only use one of them: ccio-rm-dma is for PCX-W systems *only* # obj-$(CONFIG_IOMMU_CCIO) += ccio-rm-dma.o obj-$(CONFIG_IOMMU_CCIO) += ccio-dma.o - -.o.S: $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $*.S -o $*.o - -# Translate to Rules.make lists. - -O_OBJS := $(filter-out $(export-objs), $(obj-y)) -OX_OBJS := $(filter $(export-objs), $(obj-y)) -M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) -MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) -MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) -MIX_OBJS := $(sort $(filter $(export-objs), $(int-m))) +obj-$(CONFIG_CHASSIS_LCD_LED) += led.o +obj-$(CONFIG_SUPERIO) += superio.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/cache.c linux.ac/arch/parisc/kernel/cache.c --- linux.vanilla/arch/parisc/kernel/cache.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/cache.c Tue Apr 3 17:54:33 2001 @@ -21,170 +21,38 @@ #include <asm/system.h> #include <asm/page.h> #include <asm/pgalloc.h> +#include <asm/processor.h> + +int split_tlb; +int dcache_stride; +int icache_stride; struct pdc_cache_info cache_info; #ifndef __LP64__ static struct pdc_btlb_info btlb_info; #endif +/* flushes EVERYTHING (tlb & cache) */ -void __flush_page_to_ram(unsigned long address) +void +flush_all_caches(void) { - __flush_dcache_range(address, PAGE_SIZE); - __flush_icache_range(address, PAGE_SIZE); + flush_instruction_cache(); + flush_data_cache(); + flush_tlb_all(); } - - -void flush_data_cache(void) -{ - register unsigned long base = cache_info.dc_base; - register unsigned long count = cache_info.dc_count; - register unsigned long loop = cache_info.dc_loop; - register unsigned long stride = cache_info.dc_stride; - register unsigned long addr; - register long i, j; - - for(i=0,addr=base; i<count; i++,addr+=stride) - for(j=0; j<loop; j++) - fdce(addr); -} - -static inline void flush_data_tlb_space(void) +void +update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte) { - unsigned long base = cache_info.dt_off_base; - unsigned long count = cache_info.dt_off_count; - unsigned long stride = cache_info.dt_off_stride; - unsigned long loop = cache_info.dt_loop; - - unsigned long addr; - long i,j; - - for(i=0,addr=base; i<count; i++,addr+=stride) - for(j=0; j<loop; j++) - pdtlbe(addr); -} - + struct page *page = pte_page(pte); + if (VALID_PAGE(page) && page->mapping && + test_bit(PG_dcache_dirty, &page->flags)) { -void flush_data_tlb(void) -{ - unsigned long base = cache_info.dt_sp_base; - unsigned long count = cache_info.dt_sp_count; - unsigned long stride = cache_info.dt_sp_stride; - unsigned long space; - unsigned long old_sr1; - long i; - - old_sr1 = mfsp(1); - - for(i=0,space=base; i<count; i++, space+=stride) { - mtsp(space,1); - flush_data_tlb_space(); + flush_kernel_dcache_page(page_address(page)); + clear_bit(PG_dcache_dirty, &page->flags); } - - mtsp(old_sr1, 1); -} - -static inline void flush_instruction_tlb_space(void) -{ - unsigned long base = cache_info.it_off_base; - unsigned long count = cache_info.it_off_count; - unsigned long stride = cache_info.it_off_stride; - unsigned long loop = cache_info.it_loop; - - unsigned long addr; - long i,j; - - for(i=0,addr=base; i<count; i++,addr+=stride) - for(j=0; j<loop; j++) - pitlbe(addr); -} - -void flush_instruction_tlb(void) -{ - unsigned long base = cache_info.it_sp_base; - unsigned long count = cache_info.it_sp_count; - unsigned long stride = cache_info.it_sp_stride; - unsigned long space; - unsigned long old_sr1; - unsigned int i; - - old_sr1 = mfsp(1); - - for(i=0,space=base; i<count; i++, space+=stride) { - mtsp(space,1); - flush_instruction_tlb_space(); - } - - mtsp(old_sr1, 1); -} - - -void __flush_tlb_space(unsigned long space) -{ - unsigned long old_sr1; - - old_sr1 = mfsp(1); - mtsp(space, 1); - - flush_data_tlb_space(); - flush_instruction_tlb_space(); - - mtsp(old_sr1, 1); -} - - -void flush_instruction_cache(void) -{ - register unsigned long base = cache_info.ic_base; - register unsigned long count = cache_info.ic_count; - register unsigned long loop = cache_info.ic_loop; - register unsigned long stride = cache_info.ic_stride; - register unsigned long addr; - register long i, j; - unsigned long old_sr1; - - old_sr1 = mfsp(1); - mtsp(0,1); - - /* - * Note: fice instruction has 3 bit space field, so one must - * be specified (otherwise you are justing using whatever - * happens to be in sr0). - */ - - for(i=0,addr=base; i<count; i++,addr+=stride) - for(j=0; j<loop; j++) - fice(addr); - - mtsp(old_sr1, 1); -} - -/* not yet ... fdc() needs to be implemented in cache.h ! -void flush_datacache_range( unsigned int base, unsigned int end ) -{ - register long offset,offset_add; - offset_add = ( (1<<(cache_info.dc_conf.cc_block-1)) * - cache_info.dc_conf.cc_line ) << 4; - for (offset=base; offset<=end; offset+=offset_add) - fdc(space,offset); - fdc(space,end); -} -*/ - -/* flushes code and data-cache */ -void flush_all_caches(void) -{ - flush_instruction_cache(); - flush_data_cache(); - - flush_instruction_tlb(); - flush_data_tlb(); - - asm volatile("sync"); - asm volatile("syncdma"); - asm volatile("sync"); } int get_cache_info(char *buffer) @@ -229,7 +97,6 @@ return p - buffer; } - void __init cache_init(void) { @@ -244,10 +111,93 @@ sizeof (struct pdc_cache_info) / sizeof (long), sizeof (struct pdc_cache_cf) ); + + printk("dc base %x dc stride %x dc count %x dc loop %d\n", + cache_info.dc_base, + cache_info.dc_stride, + cache_info.dc_count, + cache_info.dc_loop); + + printk("dc conf: alias %d block %d line %d wt %d sh %d cst %d assoc %d\n", + cache_info.dc_conf.cc_alias, + cache_info.dc_conf.cc_block, + cache_info.dc_conf.cc_line, + cache_info.dc_conf.cc_wt, + cache_info.dc_conf.cc_sh, + cache_info.dc_conf.cc_cst, + cache_info.dc_conf.cc_assoc); + + printk("ic conf: alias %d block %d line %d wt %d sh %d cst %d assoc %d\n", + cache_info.ic_conf.cc_alias, + cache_info.ic_conf.cc_block, + cache_info.ic_conf.cc_line, + cache_info.ic_conf.cc_wt, + cache_info.ic_conf.cc_sh, + cache_info.ic_conf.cc_cst, + cache_info.ic_conf.cc_assoc); + + printk("dt conf: sh %d page %d cst %d aid %d pad1 %d \n", + cache_info.dt_conf.tc_sh, + cache_info.dt_conf.tc_page, + cache_info.dt_conf.tc_cst, + cache_info.dt_conf.tc_aid, + cache_info.dt_conf.tc_pad1); + + printk("it conf: sh %d page %d cst %d aid %d pad1 %d \n", + cache_info.it_conf.tc_sh, + cache_info.it_conf.tc_page, + cache_info.it_conf.tc_cst, + cache_info.it_conf.tc_aid, + cache_info.it_conf.tc_pad1); #endif + + split_tlb = 0; + if (cache_info.dt_conf.tc_sh == 0 || cache_info.dt_conf.tc_sh == 2) { + + if (cache_info.dt_conf.tc_sh == 2) + printk("Unexpected TLB configuration. Will flush I/D separately (could be optimized).\n"); + + split_tlb = 1; + } + + dcache_stride = ( (1<<(cache_info.dc_conf.cc_block+3)) * + cache_info.dc_conf.cc_line ); + icache_stride = ( (1<<(cache_info.ic_conf.cc_block+3)) * + cache_info.ic_conf.cc_line ); #ifndef __LP64__ if(pdc_btlb_info(&btlb_info)<0) { memset(&btlb_info, 0, sizeof btlb_info); } #endif +} + +void disable_sr_hashing(void) +{ + int srhash_type; + + if (boot_cpu_data.cpu_type == pcxl2) + return; /* pcxl2 doesn't support space register hashing */ + + switch (boot_cpu_data.cpu_type) { + + case pcx: + BUG(); /* We shouldn't get here. code in setup.c should prevent it */ + return; + + case pcxs: + case pcxt: + case pcxt_: + srhash_type = SRHASH_PCXST; + break; + + case pcxl: + srhash_type = SRHASH_PCXL; + break; + + default: /* Currently all PA2.0 machines use the same ins. sequence */ + srhash_type = SRHASH_PA20; + break; + } + + disable_sr_hashing_asm(srhash_type); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/ccio-dma.c linux.ac/arch/parisc/kernel/ccio-dma.c --- linux.vanilla/arch/parisc/kernel/ccio-dma.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/parisc/kernel/ccio-dma.c Tue Apr 3 17:54:33 2001 @@ -38,16 +38,19 @@ #include <linux/spinlock.h> #include <linux/slab.h> #include <linux/string.h> +#define PCI_DEBUG #include <linux/pci.h> +#undef PCI_DEBUG #include <asm/byteorder.h> #include <asm/cache.h> /* for L1_CACHE_BYTES */ #include <asm/uaccess.h> #include <asm/pgalloc.h> #include <asm/page.h> - +#include <asm/dma.h> #include <asm/io.h> #include <asm/gsc.h> /* for gsc_writeN()... */ +#include <asm/hardware.h> /* for register_module() */ /* ** Choose "ccio" since that's what HP-UX calls it. @@ -55,12 +58,11 @@ */ #define MODULE_NAME "ccio" -/* -#define DEBUG_CCIO_RES -#define DEBUG_CCIO_RUN -#define DEBUG_CCIO_INIT -#define DUMP_RESMAP -*/ +#undef DEBUG_CCIO_RES +#undef DEBUG_CCIO_RUN +#undef DEBUG_CCIO_INIT +#undef DEBUG_CCIO_RUN_SG +#undef ASSERT_PDIR_SANITY #include <linux/proc_fs.h> #include <asm/runway.h> /* for proc_runway_root */ @@ -83,8 +85,15 @@ #define DBG_RES(x...) #endif +#ifdef DEBUG_CCIO_RUN_SG +#define DBG_RUN_SG(x...) printk(x) +#else +#define DBG_RUN_SG(x...) +#endif + #define CCIO_INLINE /* inline */ -#define WRITE_U32(value, addr) gsc_writel(value, (u32 *) (addr)) +#define WRITE_U32(value, addr) gsc_writel(value, (u32 *)(addr)) +#define READ_U32(addr) gsc_readl((u32 *)(addr)) #define U2_IOA_RUNWAY 0x580 #define U2_BC_GSC 0x501 @@ -92,46 +101,22 @@ #define UTURN_BC_GSC 0x502 /* We *can't* support JAVA (T600). Venture there at your own risk. */ -static void dump_resmap(void); static int ccio_driver_callback(struct hp_device *, struct pa_iodc_driver *); static struct pa_iodc_driver ccio_drivers_for[] = { - - {HPHW_IOA, U2_IOA_RUNWAY, 0x0, 0xb, 0, 0x10, - DRIVER_CHECK_HVERSION + - DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, - MODULE_NAME, "U2 I/O MMU", (void *) ccio_driver_callback}, - - {HPHW_IOA, UTURN_IOA_RUNWAY, 0x0, 0xb, 0, 0x10, - DRIVER_CHECK_HVERSION + - DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, - MODULE_NAME, "Uturn I/O MMU", (void *) ccio_driver_callback}, - -/* -** FIXME: The following claims the GSC bus port, not the IOA. -** And there are two busses below a single I/O TLB. -** -** These should go away once we have a real PA bus walk. -** Firmware wants to tell the PA bus walk code about the GSC ports -** since they are not "architected" PA I/O devices. Ie a PA bus walk -** wouldn't discover them. But the PA bus walk code could check -** the "fixed module table" to add such devices to an I/O Tree -** and proceed with the recursive, depth first bus walk. -*/ - {HPHW_BCPORT, U2_BC_GSC, 0x0, 0xc, 0, 0x10, - DRIVER_CHECK_HVERSION + - DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, - MODULE_NAME, "U2 GSC+ BC", (void *) ccio_driver_callback}, - - {HPHW_BCPORT, UTURN_BC_GSC, 0x0, 0xc, 0, 0x10, - DRIVER_CHECK_HVERSION + - DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, - MODULE_NAME, "Uturn GSC+ BC", (void *) ccio_driver_callback}, - - {0,0,0,0,0,0, - 0, - (char *) NULL, (char *) NULL, (void *) NULL } + {HPHW_IOA, U2_IOA_RUNWAY, 0x0, 0xb, 0, 0x10, + DRIVER_CHECK_HVERSION + DRIVER_CHECK_SVERSION + + DRIVER_CHECK_HWTYPE, MODULE_NAME, "U2 I/O MMU", + (void *)ccio_driver_callback}, + + {HPHW_IOA, UTURN_IOA_RUNWAY, 0x0, 0xb, 0, 0x10, + DRIVER_CHECK_HVERSION + DRIVER_CHECK_SVERSION + + DRIVER_CHECK_HWTYPE, MODULE_NAME, "Uturn I/O MMU", + (void *)ccio_driver_callback}, + + {0,0,0,0,0,0,0, + (char *)NULL, (char *)NULL, (void *)NULL} }; @@ -176,41 +161,57 @@ volatile uint32_t io_io_high; /* Offset 15 */ }; +struct ioc { + struct ioa_registers *ioc_hpa; /* I/O MMU base address */ + u8 *res_map; /* resource map, bit == pdir entry */ + u64 *pdir_base; /* physical base address */ + + u32 res_hint; /* next available IOVP - + circular search */ + u32 res_size; /* size of resource map in bytes */ + spinlock_t res_lock; -struct ccio_device { - struct ccio_device *next; /* list of LBA's in system */ - struct hp_device *iodc; /* data about dev from firmware */ - spinlock_t ccio_lock; +#ifdef CONFIG_PROC_FS +#define CCIO_SEARCH_SAMPLE 0x100 + unsigned long avg_search[CCIO_SEARCH_SAMPLE]; + unsigned long avg_idx; /* current index into avg_search */ + unsigned long used_pages; + unsigned long msingle_calls; + unsigned long msingle_pages; + unsigned long msg_calls; + unsigned long msg_pages; + unsigned long usingle_calls; + unsigned long usingle_pages; + unsigned long usg_calls; + unsigned long usg_pages; - struct ioa_registers *ccio_hpa; /* base address */ - u64 *pdir_base; /* physical base address */ - char *res_map; /* resource map, bit == pdir entry */ - - int res_hint; /* next available IOVP - circular search */ - int res_size; /* size of resource map in bytes */ - int chainid_shift; /* specify bit location of chain_id */ - int flags; /* state/functionality enabled */ -#ifdef DELAYED_RESOURCE_CNT - dma_addr_t res_delay[DELAYED_RESOURCE_CNT]; + unsigned short cujo20_bug; #endif /* STUFF We don't need in performance path */ - int pdir_size; /* in bytes, determined by IOV Space size */ - int hw_rev; /* HW revision of chip */ + u32 pdir_size; /* in bytes, determined by IOV Space size */ + u32 chainid_shift; /* specify bit location of chain_id */ + struct ccio_device *ioa; + struct hp_device *iodc; /* data about dev from firmware */ }; +struct ccio_device { + struct ccio_device *next; /* list of LBA's in system */ + spinlock_t ccio_lock; -/* Ratio of Host MEM to IOV Space size */ -static unsigned long ccio_mem_ratio = 4; -static struct ccio_device *ccio_list = NULL; + /* STUFF We don't need in performance path */ + int hw_rev; /* HW revision of chip */ + int flags; /* state/functionality enabled */ + unsigned short num_ioc; /* number of on-board IOC's */ +#define MAX_IOC 2 + struct ioc ioc[MAX_IOC]; +}; -static int ccio_proc_info(char *buffer, char **start, off_t offset, int length); -static unsigned long ccio_used_bytes = 0; -static unsigned long ccio_used_pages = 0; -static int ccio_cujo_bug = 0; -static unsigned long ccio_alloc_size = 0; -static unsigned long ccio_free_size = 0; +/* Ratio of Host MEM to IOV Space size */ +static unsigned long ccio_mem_ratio = 32; +static struct ccio_device *ccio_list; +static int ccio_count; /************************************************************** * @@ -239,16 +240,78 @@ #define PDIR_INDEX(iovp) ((iovp)>>IOVP_SHIFT) #define MKIOVP(pdir_idx) ((long)(pdir_idx) << IOVP_SHIFT) #define MKIOVA(iovp,offset) (dma_addr_t)((long)iovp | (long)offset) +#define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1)) -/* CUJO20 KLUDGE start */ -#define CUJO_20_BITMASK 0x0ffff000 /* upper nibble is a don't care */ -#define CUJO_20_STEP 0x10000000 /* inc upper nibble */ -#define CUJO_20_BADPAGE1 0x01003000 /* pages that hpmc on raven U+ */ -#define CUJO_20_BADPAGE2 0x01607000 /* pages that hpmc on firehawk U+ */ -#define CUJO_20_BADHVERS 0x6821 /* low nibble 1 is cujo rev 2.0 */ -#define CUJO_RAVEN_LOC 0xf1000000UL /* cujo location on raven U+ */ -#define CUJO_FIREHAWK_LOC 0xf1604000UL /* cujo location on firehawk U+ */ -/* CUJO20 KLUDGE end */ +#ifdef ASSERT_PDIR_SANITY +static void +ccio_dump_pdir_entry(struct ioc *ioc, char *msg, uint pide) +{ + /* start printing from lowest pde in rval */ + u64 *ptr = &(ioc->pdir_base[pide & (~0UL * BITS_PER_LONG)]); + unsigned long *rptr = (unsigned long *) &(ioc->res_map[(pide >>3) & ~(sizeof(unsigned long) - 1)]); + uint rcnt; + + printk("ccio: %s rp %p bit %d rval 0x%lx\n", msg, + rptr, pide & (BITS_PER_LONG - 1), *rptr); + + rcnt = 0; + while(rcnt < BITS_PER_LONG) { + printk("%s %2d %p %016Lx\n", + (rcnt == (pide & (BITS_PER_LONG - 1))) + ? " -->" : " ", + rcnt, ptr, *ptr ); + rcnt++; + ptr++; + } + printk(msg); +} + +static int +ccio_check_pdir(struct ioc *ioc, char *msg) +{ + int i, j; + u32 *res_ptr = (u32 *)ioc->res_map; + u32 *pptr = (u32 *)ioc->pdir_base; + u32 pmap; + char buf1[512] = {0}; + char buf2[512] = {0}; + + ++pptr; + + printk(msg); + for(i = 0; i < (ioc->res_size / sizeof(u32)); ++i, ++res_ptr) { + if((i & 15) == 0) { + printk("%s\n", buf1); + buf1[0] = '\0'; + printk("%s\n", buf2); + buf2[0] = '\0'; + printk("\n"); + } + for(j = 0, pmap = 0; j < 32; ++j, ++pptr, ++pptr) { + pmap |= (*pptr & 0x1) << (31 - j); + } + sprintf(buf1, "%s %08x", buf1, *res_ptr); + sprintf(buf2, "%s %08x", buf2, pmap); + } + printk("%s\n", buf1); + printk("%s\n", buf2); + printk("\n"); + return 0; +} + +static void +ccio_dump_sg(struct ioc *ioc, struct scatterlist *startsg, int nents) +{ + while(nents-- > 0) { + printk(" %d : %08lx/%05x %p/%05x\n", nents, + (unsigned long)sg_dma_address(startsg), + sg_dma_len(startsg), + startsg->address, startsg->length); + startsg++; + } +} + +#endif /* ASSERT_PDIR_SANITY */ /* ** Don't worry about the 150% average search length on a miss. @@ -256,26 +319,24 @@ ** cause the kernel to panic anyhow. */ -/* ioa->res_hint = idx + (size >> 3); \ */ -#define CCIO_SEARCH_LOOP(ioa, idx, mask, size) \ - for(; res_ptr < res_end; ++res_ptr) \ - { \ - if(0 == ((*res_ptr) & mask)) { \ - *res_ptr |= mask; \ - idx = (int)((unsigned long)res_ptr - (unsigned long)ioa->res_map); \ - ioa->res_hint = 0;\ +#define CCIO_SEARCH_LOOP(ioc, res_idx, mask_ptr, size) \ + for(; res_ptr < res_end; ++res_ptr) { \ + if(0 == (*res_ptr & *mask_ptr)) { \ + *res_ptr |= *mask_ptr; \ + res_idx = (int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \ + ioc->res_hint = res_idx + (size >> 3); \ goto resource_found; \ } \ } -#define CCIO_FIND_FREE_MAPPING(ioa, idx, mask, size) { \ - u##size *res_ptr = (u##size *)&((ioa)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \ - u##size *res_end = (u##size *)&(ioa)->res_map[ioa->res_size]; \ - CCIO_SEARCH_LOOP(ioa, idx, mask, size); \ - res_ptr = (u##size *)&(ioa)->res_map[0]; \ - CCIO_SEARCH_LOOP(ioa, idx, mask, size); \ -} +#define CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, size) \ + u##size *res_ptr = (u##size *)&((ioc)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \ + u##size *res_end = (u##size *)&(ioc)->res_map[ioa->res_size]; \ + u##size *mask_ptr = (u##size *)&mask; \ + CCIO_SEARCH_LOOP(ioc, res_idx, mask_ptr, size); \ + res_ptr = (u##size *)&(ioc)->res_map[0]; \ + CCIO_SEARCH_LOOP(ioa, res_idx, mask_ptr, size); /* ** Find available bit in this ioa's resource map. @@ -291,23 +352,24 @@ ** (eg > 16 pages) mappings. */ static int -ccio_alloc_range(struct ccio_device *ioa, size_t size) +ccio_alloc_range(struct ioc *ioc, size_t size) { int res_idx; - unsigned long mask, flags; - unsigned int pages_needed = size >> PAGE_SHIFT; - + unsigned long pages_needed = (size >> IOVP_SHIFT); + unsigned long mask = ~0L; +#ifdef CONFIG_PROC_FS + unsigned long cr_start = mfctl(16); +#endif + ASSERT(pages_needed); ASSERT((pages_needed * IOVP_SIZE) < DMA_CHUNK_SIZE); - ASSERT(pages_needed < (BITS_PER_LONG - IOVP_SHIFT)); - - mask = (unsigned long) -1L; - mask >>= BITS_PER_LONG - pages_needed; + ASSERT(pages_needed < BITS_PER_LONG); + ASSERT(0 == (size & ~IOVP_MASK)); - DBG_RES(__FUNCTION__ " size: %d pages_needed %d pages_mask 0x%08lx\n", - size, pages_needed, mask); - - spin_lock_irqsave(&ioa->ccio_lock, flags); + mask = ~(mask >> pages_needed); + + DBG_RES("%s() size: %d pages_needed %d mask 0x%08lx\n", + __FUNCTION__, size, pages_needed, mask); /* ** "seek and ye shall find"...praying never hurts either... @@ -315,98 +377,93 @@ */ if(pages_needed <= 8) { - CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 8); + CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 8); } else if(pages_needed <= 16) { - CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 16); + CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 16); } else if(pages_needed <= 32) { - CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 32); + CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 32); #ifdef __LP64__ } else if(pages_needed <= 64) { - CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 64) + CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 64); #endif } else { - panic(__FILE__ ":" __FUNCTION__ "() Too many pages to map.\n"); + panic(__FILE__ ": %s() Too many pages to map. pages_needed: %ld\n", __FUNCTION__, pages_needed); } -#ifdef DUMP_RESMAP - dump_resmap(); +#ifdef ASSERT_PDIR_SANITY + ccio_check_pdir(ioc, "bummer"); #endif - panic(__FILE__ ":" __FUNCTION__ "() I/O MMU is out of mapping resources\n"); + panic(__FILE__ ": %s() I/O MMU is out of mapping resources.\n", __FUNCTION__); resource_found: - DBG_RES(__FUNCTION__ " res_idx %d mask 0x%08lx res_hint: %d\n", - res_idx, mask, ioa->res_hint); - - ccio_used_pages += pages_needed; - ccio_used_bytes += ((pages_needed >> 3) ? (pages_needed >> 3) : 1); + DBG_RES("%s() res_idx %d mask 0x%08lx res_hint: %d\n", + __FUNCTION__, res_idx, mask, ioc->res_hint); - spin_unlock_irqrestore(&ioa->ccio_lock, flags); +#ifdef CONFIG_PROC_FS + { + unsigned long cr_end = mfctl(16); + unsigned long tmp = cr_end - cr_start; + /* check for roll over */ + cr_start = (cr_end < cr_start) ? -(tmp) : (tmp); + } + ioc->avg_search[ioc->avg_idx++] = cr_start; + ioc->avg_idx &= CCIO_SEARCH_SAMPLE - 1; -#ifdef DUMP_RESMAP - dump_resmap(); + ioc->used_pages += pages_needed; #endif /* - ** return the bit address (convert from byte to bit). + ** return the bit address. */ - return (res_idx << 3); + return res_idx << 3; } - -#define CCIO_FREE_MAPPINGS(ioa, idx, mask, size) \ - u##size *res_ptr = (u##size *)&((ioa)->res_map[idx + (((size >> 3) - 1) & ~((size >> 3) - 1))]); \ - ASSERT((*res_ptr & mask) == mask); \ - *res_ptr &= ~mask; +#define CCIO_FREE_MAPPINGS(ioc, res_idx, mask, size) \ + u##size *res_ptr = (u##size *)&((ioc)->res_map[res_idx]); \ + u##size *mask_ptr = (u##size *)&mask; \ + ASSERT((*res_ptr & *mask_ptr) == *mask_ptr); \ + *res_ptr &= ~(*mask_ptr); /* ** clear bits in the ioa's resource map */ static void -ccio_free_range(struct ccio_device *ioa, dma_addr_t iova, size_t size) +ccio_free_range(struct ioc *ioc, dma_addr_t iova, size_t size) { - unsigned long mask, flags; + unsigned long mask = ~0L; unsigned long iovp = CCIO_IOVP(iova); - unsigned int res_idx = PDIR_INDEX(iovp)>>3; - unsigned int pages_mapped = (size >> IOVP_SHIFT) + !!(size & ~IOVP_MASK); + unsigned int res_idx = PDIR_INDEX(iovp) >> 3; + unsigned int pages_mapped = (size >> IOVP_SHIFT); - ASSERT(pages_needed); - ASSERT((pages_needed * IOVP_SIZE) < DMA_CHUNK_SIZE); - ASSERT(pages_needed < (BITS_PER_LONG - IOVP_SHIFT)); + ASSERT(pages_mapped); + ASSERT((pages_mapped * IOVP_SIZE) < DMA_CHUNK_SIZE); + ASSERT(pages_mapped < BITS_PER_LONG); - mask = (unsigned long) -1L; - mask >>= BITS_PER_LONG - pages_mapped; + mask = ~(mask >> pages_mapped); - DBG_RES(__FUNCTION__ " res_idx: %d size: %d pages_mapped %d mask 0x%08lx\n", - res_idx, size, pages_mapped, mask); + DBG_RES("%s(): res_idx: %d size: %d pages_mapped %d mask 0x%08lx\n", + __FUNCTION__, res_idx, size, pages_mapped, mask); - spin_lock_irqsave(&ioa->ccio_lock, flags); +#ifdef CONFIG_PROC_FS + ioc->used_pages -= pages_mapped; +#endif if(pages_mapped <= 8) { - CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 8); + CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 8); } else if(pages_mapped <= 16) { - CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 16); + CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 16); } else if(pages_mapped <= 32) { - CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 32); + CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 32); #ifdef __LP64__ } else if(pages_mapped <= 64) { - CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 64); + CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 64); #endif } else { - panic(__FILE__ ":" __FUNCTION__ "() Too many pages to unmap.\n"); + panic(__FILE__ ":%s() Too many pages to unmap.\n", __FUNCTION__); } - - ccio_used_pages -= (pages_mapped ? pages_mapped : 1); - ccio_used_bytes -= ((pages_mapped >> 3) ? (pages_mapped >> 3) : 1); - - spin_unlock_irqrestore(&ioa->ccio_lock, flags); - -#ifdef DUMP_RESMAP - dump_resmap(); -#endif } - /**************************************************************** ** ** CCIO dma_ops support routines @@ -500,7 +557,7 @@ /* We currently only support kernel addresses */ ASSERT(sid == 0); - ASSERT(((unsigned long) vba & 0xf0000000UL) == 0xc0000000UL); + ASSERT(((unsigned long) vba & 0xc0000000UL) == 0xc0000000UL); mtsp(sid,1); @@ -556,27 +613,25 @@ asm volatile("sync"); } - /* ** Remove stale entries from the I/O TLB. ** Need to do this whenever an entry in the PDIR is marked invalid. */ static CCIO_INLINE void -ccio_clear_io_tlb( struct ccio_device *d, dma_addr_t iovp, size_t byte_cnt) +ccio_clear_io_tlb(struct ioc *ioc, dma_addr_t iovp, size_t byte_cnt) { - u32 chain_size = 1 << d->chainid_shift; + u32 chain_size = 1 << ioc->chainid_shift; iovp &= ~(IOVP_SIZE-1); /* clear offset bits, just want pagenum */ byte_cnt += chain_size; - while (byte_cnt > chain_size) { - WRITE_U32(CMD_TLB_PURGE | iovp, &d->ccio_hpa->io_command); - iovp += chain_size; + while(byte_cnt > chain_size) { + WRITE_U32(CMD_TLB_PURGE | iovp, &ioc->ioc_hpa->io_command); + iovp += chain_size; byte_cnt -= chain_size; - } + } } - /*********************************************************** * * Mark the I/O Pdir entries invalid and blow away the @@ -590,23 +645,21 @@ * (We do need to maker I/O PDIR entries invalid regardless). ***********************************************************/ static CCIO_INLINE void -ccio_mark_invalid(struct ccio_device *d, dma_addr_t iova, size_t byte_cnt) +ccio_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) { - u32 iovp = (u32) CCIO_IOVP(iova); + u32 iovp = (u32)CCIO_IOVP(iova); size_t saved_byte_cnt; /* round up to nearest page size */ - saved_byte_cnt = byte_cnt = (byte_cnt + IOVP_SIZE - 1) & IOVP_MASK; + saved_byte_cnt = byte_cnt = (byte_cnt + ~IOVP_MASK) & IOVP_MASK; - while (byte_cnt > 0) { + while(byte_cnt > 0) { /* invalidate one page at a time */ unsigned int idx = PDIR_INDEX(iovp); - char *pdir_ptr = (char *) &(d->pdir_base[idx]); - - ASSERT( idx < (d->pdir_size/sizeof(u64))); - - pdir_ptr[7] = 0; /* clear only VALID bit */ + char *pdir_ptr = (char *) &(ioc->pdir_base[idx]); + ASSERT(idx < (ioc->pdir_size / sizeof(u64))); + pdir_ptr[7] = 0; /* clear only VALID bit */ /* ** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360) ** PCX-U/U+ do. (eg C200/C240) @@ -622,67 +675,44 @@ } asm volatile("sync"); - ccio_clear_io_tlb(d, CCIO_IOVP(iova), saved_byte_cnt); + ccio_clear_io_tlb(ioc, CCIO_IOVP(iova), saved_byte_cnt); } - /**************************************************************** ** ** CCIO dma_ops ** *****************************************************************/ -void __init ccio_init(void) -{ - register_driver(ccio_drivers_for); -} - - -static int ccio_dma_supported( struct pci_dev *dev, dma_addr_t mask) +static int +ccio_dma_supported(struct pci_dev *dev, dma_addr_t mask) { - if (dev == NULL) { + if(dev == NULL) { printk(MODULE_NAME ": EISA/ISA/et al not supported\n"); BUG(); - return(0); + return 0; } dev->dma_mask = mask; /* save it */ /* only support 32-bit devices (ie PCI/GSC) */ - return((int) (mask >= 0xffffffffUL)); -} - -/* -** Dump a hex representation of the resource map. -*/ - -#ifdef DUMP_RESMAP -static -void dump_resmap() -{ - struct ccio_device *ioa = ccio_list; - unsigned long *res_ptr = (unsigned long *)ioa->res_map; - unsigned long i = 0; - - printk("res_map: "); - for(; i < (ioa->res_size / sizeof(unsigned long)); ++i, ++res_ptr) - printk("%08lx ", *res_ptr); - - printk("\n"); + return (int)(mask >= 0xffffffffUL); } -#endif /* ** map_single returns a fully formed IOVA */ -static dma_addr_t ccio_map_single(struct pci_dev *dev, void *addr, size_t size, int direction) + +static dma_addr_t +ccio_map_single(struct pci_dev *dev, void *addr, size_t size, int direction) { - struct ccio_device *ioa = ccio_list; /* FIXME : see Multi-IOC below */ + int idx; + struct ioc *ioc = &ccio_list->ioc[0]; + unsigned long flags; dma_addr_t iovp; dma_addr_t offset; u64 *pdir_start; unsigned long hint = hint_lookup[direction]; - int idx; ASSERT(size > 0); @@ -690,41 +720,49 @@ offset = ((dma_addr_t) addr) & ~IOVP_MASK; /* round up to nearest IOVP_SIZE */ - size = (size + offset + IOVP_SIZE - 1) & IOVP_MASK; + size = (size + offset + ~IOVP_MASK) & IOVP_MASK; - idx = ccio_alloc_range(ioa, size); - iovp = (dma_addr_t) MKIOVP(idx); + spin_lock_irqsave(&ioc->res_lock, flags); - DBG_RUN(__FUNCTION__ " 0x%p -> 0x%lx", addr, (long) iovp | offset); +#ifdef CONFIG_PROC_FS + ioc->msingle_calls++; + ioc->msingle_pages += size >> IOVP_SHIFT; +#endif + + idx = ccio_alloc_range(ioc, size); + iovp = (dma_addr_t)MKIOVP(idx); - pdir_start = &(ioa->pdir_base[idx]); + pdir_start = &(ioc->pdir_base[idx]); + + DBG_RUN("%s() 0x%p -> 0x%lx", __FUNCTION__, addr, (long)iovp | offset); /* If not cacheline aligned, force SAFE_DMA on the whole mess */ - if ((size % L1_CACHE_BYTES) || ((unsigned long) addr % L1_CACHE_BYTES)) + if((size % L1_CACHE_BYTES) || ((unsigned long)addr % L1_CACHE_BYTES)) hint |= HINT_SAFE_DMA; /* round up to nearest IOVP_SIZE */ - size = (size + IOVP_SIZE - 1) & IOVP_MASK; - - while (size > 0) { + size = (size + ~IOVP_MASK) & IOVP_MASK; + while(size > 0) { ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, addr, hint); DBG_RUN(" pdir %p %08x%08x\n", pdir_start, (u32) (((u32 *) pdir_start)[0]), - (u32) (((u32 *) pdir_start)[1]) - ); + (u32) (((u32 *) pdir_start)[1])); + ++pdir_start; addr += IOVP_SIZE; size -= IOVP_SIZE; - pdir_start++; } + + spin_unlock_irqrestore(&ioc->res_lock, flags); + /* form complete address */ return CCIO_IOVA(iovp, offset); } - -static void ccio_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, int direction) +static void +ccio_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, int direction) { #ifdef FIXME /* Multi-IOC (ie N-class) : need to lookup IOC from dev @@ -737,117 +775,362 @@ #else struct ccio_device *ioa = ccio_list; #endif - dma_addr_t offset; + struct ioc *ioc = &ioa->ioc[0]; + unsigned long flags; + dma_addr_t offset = iova & ~IOVP_MASK; - offset = iova & ~IOVP_MASK; - - /* round up to nearest IOVP_SIZE */ - size = (size + offset + IOVP_SIZE - 1) & IOVP_MASK; + DBG_RUN("%s() iovp 0x%lx/%x\n", __FUNCTION__, (long)iova, size); - /* Mask off offset */ - iova &= IOVP_MASK; + iova ^= offset; /* clear offset bits */ + size += offset; + size = ROUNDUP(size, IOVP_SIZE); - DBG_RUN(__FUNCTION__ " iovp 0x%lx\n", (long) iova); + spin_lock_irqsave(&ioc->res_lock, flags); -#ifdef DELAYED_RESOURCE_CNT - if (ioa->saved_cnt < DELAYED_RESOURCE_CNT) { - ioa->saved_iova[ioa->saved_cnt] = iova; - ioa->saved_size[ioa->saved_cnt] = size; - ccio_saved_cnt++; - } else { - do { +#ifdef CONFIG_PROC_FS + ioc->usingle_calls++; + ioc->usingle_pages += size >> IOVP_SHIFT; #endif - ccio_mark_invalid(ioa, iova, size); - ccio_free_range(ioa, iova, size); -#ifdef DELAYED_RESOURCE_CNT - d->saved_cnt--; - iova = ioa->saved_iova[ioa->saved_cnt]; - size = ioa->saved_size[ioa->saved_cnt]; - } while (ioa->saved_cnt) - } -#endif + ccio_mark_invalid(ioc, iova, size); + ccio_free_range(ioc, iova, size); + spin_unlock_irqrestore(&ioc->res_lock, flags); } - -static void * ccio_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) +static void * +ccio_alloc_consistent(struct pci_dev *dev, size_t size, dma_addr_t *dma_handle) { - void *ret; - unsigned long flags; - struct ccio_device *ioa = ccio_list; - - DBG_RUN(__FUNCTION__ " size 0x%x\n", size); - + void *ret; #if 0 /* GRANT Need to establish hierarchy for non-PCI devs as well ** and then provide matching gsc_map_xxx() functions for them as well. */ - if (!hwdev) { + if(!hwdev) { /* only support PCI */ *dma_handle = 0; return 0; } #endif - spin_lock_irqsave(&ioa->ccio_lock, flags); - ccio_alloc_size += get_order(size); - spin_unlock_irqrestore(&ioa->ccio_lock, flags); - ret = (void *) __get_free_pages(GFP_ATOMIC, get_order(size)); if (ret) { memset(ret, 0, size); - *dma_handle = ccio_map_single(hwdev, ret, size, PCI_DMA_BIDIRECTIONAL); + *dma_handle = ccio_map_single(dev, ret, size, PCI_DMA_BIDIRECTIONAL); } - DBG_RUN(__FUNCTION__ " ret %p\n", ret); return ret; } +static void +ccio_free_consistent(struct pci_dev *dev, size_t size, void *vaddr, dma_addr_t dma_handle) +{ + ccio_unmap_single(dev, dma_handle, size, 0); + free_pages((unsigned long)vaddr, get_order(size)); +} + +/* +** Since 0 is a valid pdir_base index value, can't use that +** to determine if a value is valid or not. Use a flag to indicate +** the SG list entry contains a valid pdir index. +*/ +#define PIDE_FLAG 0x80000000UL -static void ccio_free_consistent (struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) +static CCIO_INLINE int +ccio_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents, unsigned long hint) { - unsigned long flags; - struct ccio_device *ioa = ccio_list; + struct scatterlist *dma_sg = startsg; /* pointer to current DMA */ + int n_mappings = 0; + u64 *pdirp = 0; + unsigned long dma_offset = 0; + + dma_sg--; + while (nents-- > 0) { + int cnt = sg_dma_len(startsg); + sg_dma_len(startsg) = 0; + + DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n", nents, + (unsigned long)sg_dma_address(startsg), cnt, + startsg->address, startsg->length + ); - spin_lock_irqsave(&ioa->ccio_lock, flags); - ccio_free_size += get_order(size); - spin_unlock_irqrestore(&ioa->ccio_lock, flags); + /* + ** Look for the start of a new DMA stream + */ + if(sg_dma_address(startsg) & PIDE_FLAG) { + u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG; + dma_offset = (unsigned long) pide & ~IOVP_MASK; + sg_dma_address(startsg) = 0; + dma_sg++; + sg_dma_address(dma_sg) = pide; + pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]); + n_mappings++; + } - ccio_unmap_single(hwdev, dma_handle, size, 0); - free_pages((unsigned long) vaddr, get_order(size)); + /* + ** Look for a VCONTIG chunk + */ + if (cnt) { + unsigned long vaddr = (unsigned long)startsg->address; + ASSERT(pdirp); + + /* Since multiple Vcontig blocks could make up + ** one DMA stream, *add* cnt to dma_len. + */ + sg_dma_len(dma_sg) += cnt; + cnt += dma_offset; + dma_offset=0; /* only want offset on first chunk */ + cnt = ROUNDUP(cnt, IOVP_SIZE); +#ifdef CONFIG_PROC_FS + ioc->msg_pages += cnt >> IOVP_SHIFT; +#endif + do { + ccio_io_pdir_entry(pdirp, KERNEL_SPACE, (void *)vaddr, hint); + vaddr += IOVP_SIZE; + cnt -= IOVP_SIZE; + pdirp++; + } while (cnt > 0); + } + startsg++; + } + return(n_mappings); } -static int ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) +/* +** Two address ranges are DMA contiguous *iff* "end of prev" and +** "start of next" are both on a page boundry. +** +** (shift left is a quick trick to mask off upper bits) +*/ +#define DMA_CONTIG(__X, __Y) \ + (((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL) + + +/* +** First pass is to walk the SG list and determine where the breaks are +** in the DMA stream. Allocates PDIR entries but does not fill them. +** Returns the number of DMA chunks. +** +** Doing the fill seperate from the coalescing/allocation keeps the +** code simpler. Future enhancement could make one pass through +** the sglist do both. +*/ + +static CCIO_INLINE int +ccio_coalesce_chunks(struct ioc *ioc, struct scatterlist *startsg, int nents) { - int tmp = nents; + struct scatterlist *vcontig_sg; /* VCONTIG chunk head */ + unsigned long vcontig_len; /* len of VCONTIG chunk */ + unsigned long vcontig_end; + struct scatterlist *dma_sg; /* next DMA stream head */ + unsigned long dma_offset, dma_len; /* start/len of DMA stream */ + int n_mappings = 0; + + while (nents > 0) { - DBG_RUN(KERN_WARNING __FUNCTION__ " START\n"); + /* + ** Prepare for first/next DMA stream + */ + dma_sg = vcontig_sg = startsg; + dma_len = vcontig_len = vcontig_end = startsg->length; + vcontig_end += (unsigned long) startsg->address; + dma_offset = (unsigned long) startsg->address & ~IOVP_MASK; + + /* PARANOID: clear entries */ + sg_dma_address(startsg) = 0; + sg_dma_len(startsg) = 0; - /* KISS: map each buffer seperately. */ - while (nents) { - sg_dma_address(sglist) = ccio_map_single(dev, sglist->address, sglist->length, direction); - sg_dma_len(sglist) = sglist->length; - nents--; - sglist++; + /* + ** This loop terminates one iteration "early" since + ** it's always looking one "ahead". + */ + while(--nents > 0) { + unsigned long startsg_end; + + startsg++; + startsg_end = (unsigned long)startsg->address + startsg->length; + + /* PARANOID: clear entries */ + sg_dma_address(startsg) = 0; + sg_dma_len(startsg) = 0; + + /* + ** First look for virtually contiguous blocks. + ** PARISC needs this since it's cache is virtually + ** indexed and we need the associated virtual + ** address for each I/O address we map. + ** + ** 1) Can we prepend the next transaction? + ** Only if they are on the same page. + ** And we don't mind DMA order wrong. NOT. + ** Feasible but requires substantial work. + */ + + /* + ** 2) or append the next transaction? + */ + if(vcontig_end == (unsigned long) startsg->address) { + vcontig_len += startsg->length; + vcontig_end += startsg->length; + dma_len += startsg->length; + continue; + } + + /* + ** Not virtually contigous. + ** Terminate prev chunk. + ** Start a new chunk. + ** + ** Once we start a new VCONTIG chunk, dma_offset + ** can't change. And we need the offset from the first + ** chunk - not the last one. Ergo Successive chunks + ** must start on page boundaries and dove tail + ** with it's predecessor. + */ + sg_dma_len(vcontig_sg) = vcontig_len; + + vcontig_sg = startsg; + vcontig_len = startsg->length; + + /* + ** 3) do the entries end/start on page boundaries? + ** Don't update vcontig_end until we've checked. + */ + if (DMA_CONTIG(vcontig_end, startsg->address)) { + vcontig_end = vcontig_len + (unsigned long)startsg->address; + dma_len += vcontig_len; + continue; + } else { + break; + } + } + + /* + ** End of DMA Stream + ** Terminate last VCONTIG block. + ** Allocate space for DMA stream. + */ + sg_dma_len(vcontig_sg) = vcontig_len; + dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK; + sg_dma_address(dma_sg) = + PIDE_FLAG + | (ccio_alloc_range(ioc, dma_len) << IOVP_SHIFT) + | dma_offset; + n_mappings++; } - DBG_RUN(KERN_WARNING __FUNCTION__ " DONE\n"); - return tmp; + return n_mappings; } -static void ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) +/* +** And this algorithm still generally only ends up coalescing entries +** that happens to be on the same page due to how sglists are assembled. +*/ +static int +ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) { - DBG_RUN(KERN_WARNING __FUNCTION__ " : unmapping %d entries\n", nents); - while (nents) { - ccio_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction); - nents--; - sglist++; + struct ioc *ioc = &ccio_list->ioc[0]; + int coalesced, filled = 0; + unsigned long flags; + unsigned long hint = hint_lookup[direction]; + + DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents); + + /* Fast path single entry scatterlists. */ + if(nents == 1) { + sg_dma_address(sglist)= ccio_map_single(dev, sglist->address, + sglist->length, direction); + sg_dma_len(sglist)= sglist->length; + return 1; + } + + spin_lock_irqsave(&ioc->res_lock, flags); + +#ifdef ASSERT_PDIR_SANITY + if(ccio_check_pdir(ioc, "Check before ccio_map_sg()")) { + ccio_dump_sg(ioc, sglist, nents); + panic("Check before ccio_map_sg()"); + } +#endif + +#ifdef CONFIG_PROC_FS + ioc->msg_calls++; +#endif + + /* + ** First coalesce the chunks and allocate I/O pdir space + ** + ** If this is one DMA stream, we can properly map using the + ** correct virtual address associated with each DMA page. + ** w/o this association, we wouldn't have coherent DMA! + ** Access to the virtual address is what forces a two pass algorithm. + */ + coalesced = ccio_coalesce_chunks(ioc, sglist, nents); + + /* + ** Program the I/O Pdir + ** + ** map the virtual addresses to the I/O Pdir + ** o dma_address will contain the pdir index + ** o dma_len will contain the number of bytes to map + ** o address contains the virtual address. + */ + filled = ccio_fill_pdir(ioc, sglist, nents, hint); + +#ifdef ASSERT_PDIR_SANITY + if(ccio_check_pdir(ioc, "Check after ccio_map_sg()")) { + ccio_dump_sg(ioc, sglist, nents); + panic("Check after ccio_map_sg()\n"); } - return; +#endif + + spin_unlock_irqrestore(&ioc->res_lock, flags); + + ASSERT(coalesced == filled); + DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled); + + return filled; } +static void +ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) +{ + struct ioc *ioc = &ccio_list->ioc[0]; /* FIXME : see Multi-IOC below */ +#ifdef ASSERT_PDIR_SANITY + unsigned long flags; +#endif + + DBG_RUN_SG("%s() START %d entries, %p,%x\n", + __FUNCTION__, nents, sglist->address, sglist->length); + +#ifdef CONFIG_PROC_FS + ioc->usg_calls++; +#endif + +#ifdef ASSERT_PDIR_SANITY + spin_lock_irqsave(&ioc->res_lock, flags); + ccio_check_pdir(ioc,"Check before ccio_unmap_sg()"); + spin_unlock_irqrestore(&ioc->res_lock, flags); +#endif + + while(sg_dma_len(sglist) && nents--) { + +#ifdef CONFIG_PROC_FS + ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT; +#endif + ccio_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction); + ++sglist; + } + + DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__, nents); + +#ifdef ASSERT_PDIR_SANITY + spin_lock_irqsave(&ioc->res_lock, flags); + ccio_check_pdir(ioc,"Check after ccio_unmap_sg()"); + spin_unlock_irqrestore(&ioc->res_lock, flags); +#endif +} static struct pci_dma_ops ccio_ops = { ccio_dma_supported, @@ -861,6 +1144,181 @@ NULL, /* dma_sync_sg : ditto */ }; +#ifdef CONFIG_PROC_FS +static int +ccio_proc_info(char *buf, char **start, off_t offset, int len) +{ + int i, j; + struct ccio_device *ioa = ccio_list; + unsigned long avg = 0, min, max; + + buf[0] = '\0'; + do { + for(i = 0; i < MAX_IOC; ++i) { + + struct ioc *ioc = &ioa->ioc[i]; + unsigned int total_pages = ioc->res_size << 3; + + sprintf(buf, "%s%s rev %d.%d\n", buf, + parisc_getHWdescription(ioc->iodc->hw_type, ioc->iodc->hversion, + ioc->iodc->sversion), + (ioc->ioa->hw_rev & 0x7) + 1, (ioc->ioa->hw_rev & 0x18) >> 3); + + sprintf(buf, "%sCujo 2.0 bug : %s\n", + buf, (ioc->cujo20_bug ? "yes" : "no")); + + sprintf(buf, "%sIO PDIR size : %d bytes (%d entries)\n", + buf, ((ioc->res_size << 3) * sizeof(u64)), total_pages); + + sprintf(buf, "%sIO PDIR size : %d bytes (%d entries)\n", + buf, ((ioc->res_size << 3) * sizeof(u64)), total_pages); + + sprintf(buf, "%sIO PDIR entries : %ld free %ld used (%d%%)\n", buf, + total_pages - ioc->used_pages, ioc->used_pages, + (int)(ioc->used_pages * 100 / total_pages)); + + sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", + buf, ioc->res_size, ioc->res_size << 3); + + min = max = ioc->avg_search[0]; + for(j = 0; j < CCIO_SEARCH_SAMPLE; ++j) { + avg += ioc->avg_search[j]; + if(ioc->avg_search[j] > max) + max = ioc->avg_search[j]; + if(ioc->avg_search[j] < min) + min = ioc->avg_search[j]; + } + avg /= CCIO_SEARCH_SAMPLE; + sprintf(buf, "%s Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n", + buf, min, avg, max); + + sprintf(buf, "%spci_map_single(): %8ld calls %8ld pages (avg %d/1000)\n", + buf, ioc->msingle_calls, ioc->msingle_pages, + (int)((ioc->msingle_pages * 1000)/ioc->msingle_calls)); + + /* KLUGE - unmap_sg calls unmap_single for each mapped page */ + min = ioc->usingle_calls - ioc->usg_calls; + max = ioc->usingle_pages - ioc->usg_pages; + sprintf(buf, "%spci_unmap_single: %8ld calls %8ld pages (avg %d/1000)\n", + buf, min, max, (int)((max * 1000)/min)); + + sprintf(buf, "%spci_map_sg() : %8ld calls %8ld pages (avg %d/1000)\n", + buf, ioc->msg_calls, ioc->msg_pages, + (int)((ioc->msg_pages * 1000)/ioc->msg_calls)); + + sprintf(buf, "%spci_unmap_sg() : %8ld calls %8ld pages (avg %d/1000)\n\n\n", + buf, ioc->usg_calls, ioc->usg_pages, + (int)((ioc->usg_pages * 1000)/ioc->usg_calls)); + } + ioa = ioa->next; + + } while(NULL != ioa); + + return strlen(buf); +} + +static int +ccio_resource_map(char *buf, char **start, off_t offset, int len) +{ + int i, j; + struct ccio_device *ioa = ccio_list; + + buf[0] = '\0'; + do { + for(i = 0; i < MAX_IOC; ++i) { + struct ioc *ioc = &ioa->ioc[i]; + u32 *res_ptr = (u32 *)ioc->res_map; + + for(j = 0; j < (ioc->res_size / sizeof(u32)); ++j, ++res_ptr) { + if((j & 7) == 0) + strcat(buf,"\n "); + sprintf(buf, "%s %08x", buf, *res_ptr); + } + strcat(buf, "\n\n"); + } + ioa = ioa->next; + + } while(NULL != ioa); + + return strlen(buf); +} +#endif + + +/* CUJO20 KLUDGE start */ +static struct { + u16 hversion; + u8 spa; + u8 type; + u32 foo[3]; /* 16 bytes total */ +} cujo_iodc __attribute__ ((aligned (64))); + +static unsigned long cujo_result[32] __attribute__ ((aligned (16))) = {0,0,0,0}; + +/* +** CUJO 2.0 incorrectly decodes a memory access for specific +** pages (every page at specific iotlb locations dependent +** upon where the cujo is flexed - diff on raven/firehawk. +** resulting in an hpmc and/or silent data corruption. +** Workaround is to prevent use of those I/O TLB entries +** by marking the suspect bitmap range entries as busy. +*/ + +/* CUJO20 KLUDGE start */ +#define CUJO_20_BITMASK 0x0ffff000 /* upper nibble is a don't care */ +#define CUJO_20_STEP 0x10000000 /* inc upper nibble */ +#define CUJO_20_BADPAGE1 0x01003000 /* pages that hpmc on raven U+ */ +#define CUJO_20_BADPAGE2 0x01607000 /* pages that hpmc on firehawk U+ */ +#define CUJO_20_BADHVERS 0x6821 /* low nibble 1 is cujo rev 2.0 */ +#define CUJO_RAVEN_LOC 0xf1000000UL /* cujo location on raven U+ */ +#define CUJO_FIREHAWK_LOC 0xf1604000UL /* cujo location on firehawk U+ */ +/* CUJO20 KLUDGE end */ + +static void +ccio_cujo20_hack(struct ioc *ioc) +{ + u32 iovp = 0, io_io_low; + unsigned int idx; + unsigned long status, mask; + u8 *res_ptr = ioc->res_map; + + /* only test IOC that have the potential to be bad. */ + io_io_low = READ_U32(&ioc->ioc_hpa->io_io_low) << 16; + if(!(CUJO_RAVEN_LOC == io_io_low || CUJO_FIREHAWK_LOC == io_io_low)) + return; + + status = pdc_iodc_read(&cujo_result, (void *)CUJO_RAVEN_LOC, 0, &cujo_iodc, 16); + if(0 == status) { + if(CUJO_20_BADHVERS == cujo_iodc.hversion) + iovp = CUJO_20_BADPAGE1; + } else { + status = pdc_iodc_read(&cujo_result, (void *)CUJO_FIREHAWK_LOC, 0, &cujo_iodc, 16); + if(0 == status) { + if(CUJO_20_BADHVERS == cujo_iodc.hversion) + iovp = CUJO_20_BADPAGE2; + } else { + /* not a defective system */ + return; + } + } + + printk(MODULE_NAME ": Cujo 2.0 bug needs a work around\n"); +#ifdef CONFIG_PROC_FS + ioc->cujo20_bug = 1; +#endif + /* + ** mark bit entries that match "bad page" + */ + idx = PDIR_INDEX(iovp)>>3; + mask = 0xff; + + while(idx * sizeof(u8) < ioc->res_size) { + res_ptr[idx] |= mask; + idx += (PDIR_INDEX(CUJO_20_STEP)>>3); + } +} +/* CUJO20 KLUDGE end */ + #if 0 /* GRANT - is this needed for U2 or not? */ @@ -878,7 +1336,7 @@ ccio_get_iotlb_size(struct hp_device *d) { if(d->spa_shift == 0) { - panic(__FUNCTION__ ": Can't determine I/O TLB size.\n"); + panic("%s() : Can't determine I/O TLB size.\n", __FUNCTION__); } return(1 << d->spa_shift); } @@ -887,22 +1345,14 @@ /* Uturn supports 256 TLB entries */ #define CCIO_CHAINID_SHIFT 8 #define CCIO_CHAINID_MASK 0xff - #endif /* 0 */ - -/* -** Figure out how big the I/O PDIR should be and alloc it. -** Also sets variables which depend on pdir size. -*/ static void -ccio_alloc_pdir(struct ccio_device *ioa) +ccio_ioc_init(struct ioc *ioc) { + int i, iov_order; extern unsigned long mem_max; /* arch.../setup.c */ - - u32 iova_space_size = 0; - void * pdir_base; - int pdir_size, iov_order; + u32 iova_space_size; /* ** Determine IOVA Space size from memory size. @@ -915,15 +1365,16 @@ ** methods still require some "extra" to support PCI ** Hot-Plug/Removal of PCI cards. (aka PCI OLARD). */ + /* limit IOVA space size to 1MB-1GB */ - if (mem_max < (ccio_mem_ratio*1024*1024)) { - iova_space_size = 1024*1024; + if(mem_max < (ccio_mem_ratio * 1024 * 1024)) { + iova_space_size = 1024 * 1024; #ifdef __LP64__ - } else if (mem_max > (ccio_mem_ratio*512*1024*1024)) { - iova_space_size = 512*1024*1024; + } else if(mem_max > (ccio_mem_ratio * 512 * 1024 * 1024)) { + iova_space_size = 512 * 1024 * 1024; #endif } else { - iova_space_size = (u32) (mem_max/ccio_mem_ratio); + iova_space_size = (u32)(mem_max / ccio_mem_ratio); } /* @@ -933,207 +1384,92 @@ /* We could use larger page sizes in order to *decrease* the number ** of mappings needed. (ie 8k pages means 1/2 the mappings). - ** + ** ** Note: Grant Grunder says "Using 8k I/O pages isn't trivial either ** since the pages must also be physically contiguous - typically ** this is the case under linux." */ - iov_order = get_order(iova_space_size); + iov_order = get_order(iova_space_size) >> (IOVP_SHIFT - PAGE_SHIFT); ASSERT(iov_order <= (30 - IOVP_SHIFT)); /* iova_space_size <= 1GB */ ASSERT(iov_order >= (20 - IOVP_SHIFT)); /* iova_space_size >= 1MB */ iova_space_size = 1 << (iov_order + IOVP_SHIFT); - ioa->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64); + ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64); - ASSERT(pdir_size < 4*1024*1024); /* max pdir size < 4MB */ + ASSERT(ioc->pdir_size < 4 * 1024 * 1024); /* max pdir size < 4MB */ /* Verify it's a power of two */ - ASSERT((1 << get_order(pdir_size)) == (pdir_size >> PAGE_SHIFT)); + ASSERT((1 << get_order(ioc->pdir_size)) == (ioc->pdir_size >> PAGE_SHIFT)); - DBG_INIT(__FUNCTION__ " hpa 0x%p mem %dMB IOV %dMB (%d bits)\n PDIR size 0x%0x", - ioa->ccio_hpa, (int) (mem_max>>20), iova_space_size>>20, - iov_order + PAGE_SHIFT, pdir_size); - - ioa->pdir_base = - pdir_base = (void *) __get_free_pages(GFP_KERNEL, get_order(pdir_size)); - if (NULL == pdir_base) - { - panic(__FILE__ ":" __FUNCTION__ "() could not allocate I/O Page Table\n"); + DBG_INIT("%s() hpa 0x%p mem %luMB IOV %dMB (%d bits) PDIR size 0x%0x", + __FUNCTION__, ioc->ioc_hpa, mem_max>>20, iova_space_size>>20, + iov_order + PAGE_SHIFT, ioc->pdir_size); + + ioc->pdir_base = (u64 *)__get_free_pages(GFP_KERNEL, get_order(ioc->pdir_size)); + if(NULL == ioc->pdir_base) { + panic(__FILE__ ":%s() could not allocate I/O Page Table\n", __FUNCTION__); + } + memset(ioc->pdir_base, 0, ioc->pdir_size); + + ASSERT((((unsigned long)ioc->pdir_base) & PAGE_MASK) == (unsigned long)ioc->pdir_base); + DBG_INIT(" base %p", ioc->pdir_base); + + /* resource map size dictated by pdir_size */ + ioc->res_size = (ioc->pdir_size / sizeof(u64)) >> 3; + DBG_INIT("%s() res_size 0x%x\n", __FUNCTION__, ioc->res_size); + + ioc->res_map = (u8 *)__get_free_pages(GFP_KERNEL, get_order(ioc->res_size)); + if(NULL == ioc->res_map) { + panic(__FILE__ ":%s() could not allocate resource map\n", __FUNCTION__); } - memset(pdir_base, 0, pdir_size); + memset(ioc->res_map, 0, ioc->res_size); - ASSERT((((unsigned long) pdir_base) & PAGE_MASK) == (unsigned long) pdir_base); + /* Initialize the res_hint to 16 */ + ioc->res_hint = 16; - DBG_INIT(" base %p", pdir_base); + /* Initialize the spinlock */ + spin_lock_init(&ioc->res_lock); /* ** Chainid is the upper most bits of an IOVP used to determine ** which TLB entry an IOVP will use. */ - ioa->chainid_shift = get_order(iova_space_size)+PAGE_SHIFT-CCIO_CHAINID_SHIFT; - - DBG_INIT(" chainid_shift 0x%x\n", ioa->chainid_shift); -} - - -static void -ccio_hw_init(struct ccio_device *ioa) -{ - int i; + ioc->chainid_shift = get_order(iova_space_size) + PAGE_SHIFT - CCIO_CHAINID_SHIFT; + DBG_INIT(" chainid_shift 0x%x\n", ioc->chainid_shift); /* ** Initialize IOA hardware */ - WRITE_U32(CCIO_CHAINID_MASK << ioa->chainid_shift, &ioa->ccio_hpa->io_chain_id_mask); - WRITE_U32(virt_to_phys(ioa->pdir_base), &ioa->ccio_hpa->io_pdir_base); + WRITE_U32(CCIO_CHAINID_MASK << ioc->chainid_shift, + &ioc->ioc_hpa->io_chain_id_mask); + WRITE_U32(virt_to_phys(ioc->pdir_base), + &ioc->ioc_hpa->io_pdir_base); /* ** Go to "Virtual Mode" */ - WRITE_U32(IOA_NORMAL_MODE, &ioa->ccio_hpa->io_control); + WRITE_U32(IOA_NORMAL_MODE, &ioc->ioc_hpa->io_control); /* ** Initialize all I/O TLB entries to 0 (Valid bit off). */ - WRITE_U32(0, &ioa->ccio_hpa->io_tlb_entry_m); - WRITE_U32(0, &ioa->ccio_hpa->io_tlb_entry_l); + WRITE_U32(0, &ioc->ioc_hpa->io_tlb_entry_m); + WRITE_U32(0, &ioc->ioc_hpa->io_tlb_entry_l); - for (i = 1 << CCIO_CHAINID_SHIFT; i ; i--) { - WRITE_U32((CMD_TLB_DIRECT_WRITE | (i << ioa->chainid_shift)), - &ioa->ccio_hpa->io_command); + for(i = 1 << CCIO_CHAINID_SHIFT; i ; i--) { + WRITE_U32((CMD_TLB_DIRECT_WRITE | (i << ioc->chainid_shift)), + &ioc->ioc_hpa->io_command); } -} - - -static void -ccio_resmap_init(struct ccio_device *ioa) -{ - u32 res_size; - /* - ** Ok...we do more than just init resource map + ** See if we need the cujo 2.0 work around. */ - ioa->ccio_lock = SPIN_LOCK_UNLOCKED; - - ioa->res_hint = 16; /* next available IOVP - circular search */ - - /* resource map size dictated by pdir_size */ - res_size = ioa->pdir_size/sizeof(u64); /* entries */ - res_size >>= 3; /* convert bit count to byte count */ - DBG_INIT(__FUNCTION__ "() res_size 0x%x\n", res_size); - - ioa->res_size = res_size; - ioa->res_map = (char *) __get_free_pages(GFP_KERNEL, get_order(res_size)); - if (NULL == ioa->res_map) - { - panic(__FILE__ ":" __FUNCTION__ "() could not allocate resource map\n"); - } - memset(ioa->res_map, 0, res_size); -} - -/* CUJO20 KLUDGE start */ -static struct { - u16 hversion; - u8 spa; - u8 type; - u32 foo[3]; /* 16 bytes total */ -} cujo_iodc __attribute__ ((aligned (64))); -static unsigned long cujo_result[32] __attribute__ ((aligned (16))) = {0,0,0,0}; - -/* -** CUJO 2.0 incorrectly decodes a memory access for specific -** pages (every page at specific iotlb locations dependent -** upon where the cujo is flexed - diff on raven/firehawk. -** resulting in an hpmc and/or silent data corruption. -** Workaround is to prevent use of those I/O TLB entries -** by marking the suspect bitmap range entries as busy. -*/ -static void -ccio_cujo20_hack(struct ccio_device *ioa) -{ - unsigned long status; - unsigned int idx; - u8 *res_ptr = ioa->res_map; - u32 iovp=0x0; - unsigned long mask; - - status = pdc_iodc_read( &cujo_result, (void *) CUJO_RAVEN_LOC, 0, &cujo_iodc, 16); - if (status == 0) { - if (cujo_iodc.hversion==CUJO_20_BADHVERS) - iovp = CUJO_20_BADPAGE1; - } else { - status = pdc_iodc_read( &cujo_result, (void *) CUJO_FIREHAWK_LOC, 0, &cujo_iodc, 16); - if (status == 0) { - if (cujo_iodc.hversion==CUJO_20_BADHVERS) - iovp = CUJO_20_BADPAGE2; - } else { - /* not a defective system */ - return; - } - } - - printk(MODULE_NAME ": Cujo 2.0 bug needs a work around\n"); - ccio_cujo_bug = 1; - - /* - ** mark bit entries that match "bad page" - */ - idx = PDIR_INDEX(iovp)>>3; - mask = 0xff; - - while(idx * sizeof(u8) < ioa->res_size) { - res_ptr[idx] |= mask; - idx += (PDIR_INDEX(CUJO_20_STEP)>>3); - ccio_used_pages += 8; - ccio_used_bytes += 1; - } -} -/* CUJO20 KLUDGE end */ - -#ifdef CONFIG_PROC_FS -static int ccio_proc_info(char *buf, char **start, off_t offset, int len) -{ - unsigned long i = 0; - struct ccio_device *ioa = ccio_list; - unsigned long *res_ptr = (unsigned long *)ioa->res_map; - unsigned long total_pages = ioa->res_size << 3; /* 8 bits per byte */ - - sprintf(buf, "%s\nCujo 2.0 bug : %s\n", - parisc_getHWdescription(ioa->iodc->hw_type, ioa->iodc->hversion, - ioa->iodc->sversion), - (ccio_cujo_bug ? "yes" : "no")); - - sprintf(buf, "%sIO pdir size : %d bytes (%d entries)\n", - buf, ((ioa->res_size << 3) * sizeof(u64)), /* 8 bits per byte */ - ioa->res_size << 3); /* 8 bits per byte */ - - sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", - buf, ioa->res_size, ioa->res_size << 3); /* 8 bits per byte */ - - strcat(buf, " total: free: used: % used:\n"); - sprintf(buf, "%sblocks %8d %8ld %8ld %8ld%%\n", buf, ioa->res_size, - ioa->res_size - ccio_used_bytes, ccio_used_bytes, - (ccio_used_bytes * 100) / ioa->res_size); - - sprintf(buf, "%spages %8ld %8ld %8ld %8ld%%\n", buf, total_pages, - total_pages - ccio_used_pages, ccio_used_pages, - (ccio_used_pages * 100 / total_pages)); - - sprintf(buf, "%sconsistent %8ld %8ld\n", buf, - ccio_alloc_size, ccio_free_size); - - strcat(buf, "\nResource bitmap:\n"); - - for(; i < (ioa->res_size / sizeof(unsigned long)); ++i, ++res_ptr) - len += sprintf(buf, "%s%08lx ", buf, *res_ptr); - - strcat(buf, "\n"); - return strlen(buf); + /* CUJO20 KLUDGE start */ + ccio_cujo20_hack(ioc); + /* CUJO20 KLUDGE end */ } -#endif /* ** Determine if ccio should claim this chip (return 0) or not (return 1). @@ -1143,67 +1479,64 @@ static int ccio_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri) { - struct ccio_device *ioa; + int i; + struct ccio_device *ioa = ccio_list; printk("%s found %s at 0x%p\n", dri->name, dri->version, d->hpa); - if (ccio_list) { - printk(MODULE_NAME ": already initialized one device\n"); - return(0); + if(NULL == ccio_list) { + create_proc_info_entry(MODULE_NAME, 0, proc_runway_root, ccio_proc_info); + create_proc_info_entry(MODULE_NAME"-bitmap", 0, proc_runway_root, + ccio_resource_map); + + ccio_list = kmalloc(sizeof(struct ccio_device), GFP_KERNEL); + if(NULL == ccio_list) { + printk(MODULE_NAME " - couldn't alloc ccio_device\n"); + return 1; + } + memset(ccio_list, 0, sizeof(struct ccio_device)); + ioa = ccio_list; + ++ccio_count; } - ioa = kmalloc(sizeof(struct ccio_device), GFP_KERNEL); - if (NULL == ioa) - { - printk(MODULE_NAME " - couldn't alloc ccio_device\n"); - return(1); + for(i = 0; i < (ccio_count - 1); ++i) { + ioa = ioa->next; } - memset(ioa, 0, sizeof(struct ccio_device)); - - /* - ** ccio list is used mainly as a kluge to support a single instance. - ** Eventually, with core dumps, it'll be useful for debugging. - */ - ccio_list = ioa; - ioa->iodc = d; -#if 1 -/* KLUGE: determine IOA hpa based on GSC port value. -** Needed until we have a PA bus walk. Can only discover IOA via -** walking the architected PA MMIO space as described by the I/O ACD. -** "Legacy" PA Firmware only tells us about unarchitected devices -** that can't be detected by PA/EISA/PCI bus walks. -*/ - switch((long) d->hpa) { - case 0xf3fbf000L: /* C110 IOA0 LBC (aka GSC port) */ - /* ccio_hpa same as C200 IOA0 */ - case 0xf203f000L: /* C180/C200/240/C360 IOA0 LBC (aka GSC port) */ - ioa->ccio_hpa = (struct ioa_registers *) 0xfff88000L; - break; - case 0xf103f000L: /* C180/C200/240/C360 IOA1 LBC (aka GSC port) */ - ioa->ccio_hpa = (struct ioa_registers *) 0xfff8A000L; - break; - default: - panic("ccio-dma.c doesn't know this GSC port Address!\n"); - break; - }; -#else - ioa->ccio_hpa = d->hpa; -#endif + for(i = 0; i < MAX_IOC; ++i) { + if(NULL == ioa->ioc[i].ioc_hpa) + break; + } - ccio_alloc_pdir(ioa); - ccio_hw_init(ioa); - ccio_resmap_init(ioa); + if(MAX_IOC == i) { + ioa->next = kmalloc(sizeof(struct ccio_device), GFP_KERNEL); + ioa = ioa->next; + if(NULL == ioa) { + printk(MODULE_NAME " - couldn't alloc ccio_device\n"); + return 1; + } + memset(ioa, 0, sizeof(struct ccio_device)); + ++ccio_count; + i = 0; + } - /* CUJO20 KLUDGE start */ - ccio_cujo20_hack(ioa); - /* CUJO20 KLUDGE end */ + ioa->ioc[i].iodc = d; + ioa->ioc[i].ioc_hpa = d->hpa; + ioa->ioc[i].ioa = ioa; + ccio_ioc_init(&ioa->ioc[i]); hppa_dma_ops = &ccio_ops; - create_proc_info_entry(MODULE_NAME, 0, proc_runway_root, ccio_proc_info); - return(0); + printk("io_io_high: 0x%08x io_io_low: 0x%08x\n", + READ_U32(&ioa->ioc[i].ioc_hpa->io_io_high) << 16, + READ_U32(&ioa->ioc[i].ioc_hpa->io_io_low) << 16); + return 0; } - - +void __init +ccio_init(void) +{ + ccio_list = (struct ccio_device *)NULL; + ccio_count = 0; + register_driver(ccio_drivers_for); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/drivers.c linux.ac/arch/parisc/kernel/drivers.c --- linux.vanilla/arch/parisc/kernel/drivers.c Wed Dec 6 19:46:39 2000 +++ linux.ac/arch/parisc/kernel/drivers.c Tue Apr 3 17:54:33 2001 @@ -1,12 +1,9 @@ -/* +/* drivers.c -drivers.c - -Copyright (c) 1999 The Puffin Group - -This is a collection of routines intended to register all the devices -in a system, and register device drivers. + Copyright (c) 1999 The Puffin Group + This is a collection of routines intended to register all the devices + in a system, and register device drivers. */ #include <linux/slab.h> @@ -17,57 +14,58 @@ #include <asm/pdc.h> -extern struct hp_hardware *parisc_get_reference( - unsigned short hw_type, unsigned long hversion, - unsigned long sversion ); - - -/* I'm assuming there'll never be 64 devices. We should probably make +/* I'm assuming there'll never be 64 devices. We should probably make this more flexible. */ #define MAX_DEVICES 64 -unsigned int num_devices = 0; +static int num_devices; +static struct hp_device pa_devices[MAX_DEVICES]; -struct hp_device devices[MAX_DEVICES]; +static struct pa_iodc_driver *pa_drivers = NULL; static unsigned long pdc_result[32] __attribute__ ((aligned (16))) = {0,0,0,0}; static u8 iodc_data[32] __attribute__ ((aligned (64))); -/* - * XXX should we be using a locked array ? - */ - + +static int compare_spec( struct hp_device * hp_dev, + struct pa_iodc_driver *driver) +{ + if ((driver->check & DRIVER_CHECK_HWTYPE) + && (driver->hw_type != hp_dev->hw_type)) return 0; + if ((driver->check & DRIVER_CHECK_HVERSION) + && (driver->hversion != hp_dev->hversion)) return 0; + if ((driver->check & DRIVER_CHECK_HVERSION_REV) + && (driver->hversion_rev != hp_dev->hversion_rev)) return 0; + if ((driver->check & DRIVER_CHECK_SVERSION) + && (driver->sversion != hp_dev->sversion)) return 0; + if ((driver->check & DRIVER_CHECK_SVERSION_REV) + && (driver->sversion_rev != hp_dev->sversion_rev)) return 0; + if ((driver->check & DRIVER_CHECK_OPT) + && (driver->opt != hp_dev->opt)) return 0; + + return 1; +} + int register_driver(struct pa_iodc_driver *driver) { - unsigned int i; + int i; struct hp_device * device; - for (;driver->check;driver++) { + for(;driver->check;driver++) { + /* link driver to the head of the global list. + ** The list gets built in reverse order...ideally, it shouldn't + ** matter but reality will eventually rear it's ugly head. + */ + driver->next = pa_drivers; + pa_drivers = driver; - for (i=0;i<num_devices;i++) { - device = &devices[i]; + for (i=0; i < num_devices; i++) { + device = &pa_devices[i]; - if (device->managed) continue; + if (device->managed) continue; + if (0 == compare_spec(device, driver)) continue; - if ((driver->check & DRIVER_CHECK_HWTYPE) && - (driver->hw_type != device->hw_type)) - continue; - if ((driver->check & DRIVER_CHECK_HVERSION) && - (driver->hversion != device->hversion)) - continue; - if ((driver->check & DRIVER_CHECK_HVERSION_REV) && - (driver->hversion_rev != device->hversion_rev)) - continue; - if ((driver->check & DRIVER_CHECK_SVERSION) && - (driver->sversion != device->sversion)) - continue; - if ((driver->check & DRIVER_CHECK_SVERSION_REV) && - (driver->sversion_rev != device->sversion_rev)) - continue; - if ((driver->check & DRIVER_CHECK_OPT) && - (driver->opt != device->opt)) - continue; if ( (*driver->callback)(device,driver) ==0) { device->managed=1; } else { @@ -83,52 +81,113 @@ } -struct hp_device * register_module(void *hpa) +/* this function adds an address to the list of additional addresses of a module */ +int add_pa_dev_addr(struct hp_device *hp_device, unsigned long addr) { + if (!hp_device || !addr) + return 0; + if (hp_device->num_addrs >= MAX_ADD_ADDRS) { + printk(KERN_ERR "%s: Too many additional addresses. " + "Increase the value of MAX_ADD_ADDRS in harware.h !\n", + __FUNCTION__ ); + return 0; + } + + hp_device->addr[hp_device->num_addrs] = addr; + hp_device->num_addrs++; + + return hp_device->num_addrs; +} + + +struct hp_device *alloc_pa_dev(unsigned long hpa) +{ + int i, status; struct hp_device * d; - int status; - d = &devices[num_devices]; - status = pdc_iodc_read(&pdc_result,hpa,0,&iodc_data,32 ); - if (status !=PDC_RET_OK) { + d = &pa_devices[num_devices]; + status = pdc_iodc_read(&pdc_result, (void *)hpa, 0, &iodc_data, 32); + if (status != PDC_RET_OK) { /* There is no device here, so we'll skip it */ - return 0; + return NULL; + } + + /* Check to make sure this device has not already been added -Ryan */ + for(i = 0; i < num_devices; ++i) { + if((unsigned long)pa_devices[i].hpa == hpa) + return NULL; } d->hw_type = iodc_data[3]&0x1f; d->hversion = (iodc_data[0]<<4)|((iodc_data[1]&0xf0)>>4); - d->sversion = + d->sversion = ((iodc_data[4]&0x0f)<<16)|(iodc_data[5]<<8)|(iodc_data[6]); d->hversion_rev = iodc_data[1]&0x0f; d->sversion_rev = iodc_data[4]>>4; d->opt = iodc_data[7]; - d->hpa = hpa; - d->managed=0; - d->reference = parisc_get_reference(d->hw_type, d->hversion, - d->sversion); - - num_devices++; + d->hpa = (void *) hpa; + d->managed = 0; + d->reference = parisc_get_reference(d->hw_type, + d->hversion, d->sversion); + + /* add the hpa of this module as the first additional address */ + add_pa_dev_addr(d, hpa); + + num_devices++; return d; -} +} -void print_devices(char * buf) { - int i; +/* Return status if device is managed */ +int register_pa_dev(struct hp_device *hp_dev) +{ + struct pa_iodc_driver *driver = pa_drivers; + + while ((0 == hp_dev->managed) && (NULL != driver)) { + + if (compare_spec(hp_dev,driver)) + hp_dev->managed = + ((*driver->callback)(hp_dev,driver) == 0); + + driver = driver->next; + } + + return hp_dev->managed; +} + +struct hp_device *get_pa_dev(unsigned int index) +{ + if (index >= num_devices) + return NULL; + + return &pa_devices[index]; +} + + +void print_pa_devices(char * buf) +{ + int i, k; struct hp_device *d; + printk("Found devices:\n"); - for (i=0;i<num_devices;i++) { - d = &devices[i]; - printk(KERN_INFO - "%d. %s (%d) at 0x%p, versions 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", + for (i=0; i<num_devices; i++) { + d = &pa_devices[i]; + printk(KERN_INFO + "%d. %s (%d) at 0x%p, versions 0x%x, 0x%x, 0x%x, 0x%x, 0x%x", i+1, (d->reference) ? d->reference->name : "Unknown device", - d->hw_type,d->hpa, d->hversion, d->hversion_rev, + d->hw_type, d->hpa, d->hversion, d->hversion_rev, d->sversion, d->sversion_rev, d->opt); + if (d->num_addrs>1) { + printk(", additional addresses: "); + for (k=1; k<d->num_addrs; k++) + printk("0x%lx ", d->addr[k]); + } + + printk("\n"); } - printk("That's a total of %d devices.\n",num_devices); + printk("That's a total of %d devices.\n", num_devices); } - - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/entry.S linux.ac/arch/parisc/kernel/entry.S --- linux.vanilla/arch/parisc/kernel/entry.S Wed Dec 6 19:46:39 2000 +++ linux.ac/arch/parisc/kernel/entry.S Mon Apr 16 12:37:04 2001 @@ -38,9 +38,10 @@ #ifdef __LP64__ .level 2.0w +#else + .level 2.0 #endif -#define __ASSEMBLY__ #include <asm/assembly.h> /* for LDREG/STREG defines */ #include <asm/pgtable.h> #include <asm/psw.h> @@ -69,14 +70,15 @@ mtctl %r1, %cr22 mtctl %r0, %cr17 mtctl %r0, %cr17 - ldil L%.+28, %r1 - ldo R%.+24(%r1), %r1 + ldil L%4f, %r1 + ldo R%4f(%r1), %r1 LDIL_FIXUP(%r1) mtctl %r1, %cr18 ldo 4(%r1), %r1 mtctl %r1, %cr18 \rfi_type nop +4: .endm .macro get_stack @@ -179,8 +181,8 @@ /* Register definitions for tlb miss handler macros */ - va = r8 /* virtual address for which the trap occured */ - spc = r24 /* space for which the trap occured */ + va = r8 /* virtual address for which the trap occurred */ + spc = r24 /* space for which the trap occurred */ #ifndef __LP64__ @@ -298,37 +300,27 @@ .endm #ifndef __LP64__ - /* nadtlb miss interruption handler (parisc 1.1 - 32 bit) - * - * Note: nadtlb misses will be treated - * as an ordinary dtlb miss for now. - * - */ + /* nadtlb miss interruption handler (parisc 1.1 - 32 bit) */ .macro nadtlb_11 code mfctl %isr,spc - b dtlb_miss_11 + b nadtlb_miss_11 mfctl %ior,va .align 32 .endm #endif - /* nadtlb miss interruption handler (parisc 2.0) - * - * Note: nadtlb misses will be treated - * as an ordinary dtlb miss for now. - * - */ + /* nadtlb miss interruption handler (parisc 2.0) */ .macro nadtlb_20 code mfctl %isr,spc #ifdef __LP64__ - b dtlb_miss_20w + b nadtlb_miss_20w #else - b dtlb_miss_20 + b nadtlb_miss_20 #endif mfctl %ior,va @@ -402,7 +394,11 @@ def 13 def 14 dtlb_20 15 +#if 0 naitlb_20 16 +#else + def 16 +#endif nadtlb_20 17 def 18 def 19 @@ -446,7 +442,11 @@ def 13 def 14 dtlb_11 15 +#if 0 naitlb_11 16 +#else + def 16 +#endif nadtlb_11 17 def 18 def 19 @@ -811,11 +811,11 @@ */ t0 = r1 /* temporary register 0 */ - va = r8 /* virtual address for which the trap occured */ + va = r8 /* virtual address for which the trap occurred */ t1 = r9 /* temporary register 1 */ pte = r16 /* pte/phys page # */ prot = r17 /* prot bits */ - spc = r24 /* space for which the trap occured */ + spc = r24 /* space for which the trap occurred */ ptp = r25 /* page directory/page table pointer */ #ifdef __LP64__ @@ -838,14 +838,101 @@ ldd,s t1(ptp),ptp extrd,u va,42,9,t0 /* get second-level index */ - bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_fault + bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20w + depdi 0,63,12,ptp /* clear prot bits */ + + /* Second level page table lookup */ + + ldd,s t0(ptp),ptp + extrd,u va,51,9,t0 /* get third-level index */ + bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20w + depdi 0,63,12,ptp /* clear prot bits */ + + /* Third level page table lookup */ + + shladd t0,3,ptp,ptp + ldi _PAGE_ACCESSED,t1 + ldd 0(ptp),pte + bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_check_alias_20w + + /* Check whether the "accessed" bit was set, otherwise do so */ + + or t1,pte,t0 /* t0 has R bit set */ + and,*<> t1,pte,%r0 /* test and nullify if already set */ + std t0,0(ptp) /* write back pte */ + + copy spc,prot /* init prot with faulting space */ + + depd pte,8,7,prot + extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0 + depdi 1,12,1,prot + extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0 + depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */ + extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0 + depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */ + + /* Get rid of prot bits and convert to page addr for idtlbt */ + + depdi 0,63,12,pte + extrd,u pte,56,32,pte + idtlbt pte,prot + + rfir + nop + +dtlb_check_alias_20w: + + /* Check to see if fault is in the temporary alias region */ + + cmpib,<>,n 0,spc,dtlb_fault /* forward */ + ldil L%(TMPALIAS_MAP_START),t0 + LDIL_FIXUP(t0) + copy va,t1 + depdi 0,63,23,t1 + cmpb,*<>,n t0,t1,dtlb_fault /* forward */ + ldi (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot + depd,z prot,8,7,prot + + /* + * OK, it is in the temp alias region, check whether "from" or "to". + * Check "subtle" note in pacache.S re: r23/r26. + */ + + extrd,u,*= va,41,1,r0 + or,*tr %r23,%r0,pte /* If "from" use "from" page */ + or,* %r26,%r0,pte /* else "to", use "to" page */ + + idtlbt pte,prot + + rfir + nop + +nadtlb_miss_20w: + + extrd,u spc,31,7,t1 /* adjust va */ + depd t1,31,7,va /* adjust va */ + depdi 0,31,7,spc /* adjust space */ + mfctl %cr25,ptp /* Assume user space miss */ + or,*<> %r0,spc,%r0 /* If it is user space, nullify */ + mfctl %cr24,ptp /* Load kernel pgd instead */ + extrd,u va,33,9,t1 /* Get pgd index */ + + mfsp %sr7,t0 /* Get current space */ + or,*= %r0,t0,%r0 /* If kernel, nullify following test */ + comb,<>,n t0,spc,nadtlb_fault /* forward */ + + /* First level page table lookup */ + + ldd,s t1(ptp),ptp + extrd,u va,42,9,t0 /* get second-level index */ + bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate depdi 0,63,12,ptp /* clear prot bits */ /* Second level page table lookup */ ldd,s t0(ptp),ptp extrd,u va,51,9,t0 /* get third-level index */ - bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_fault + bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate depdi 0,63,12,ptp /* clear prot bits */ /* Third level page table lookup */ @@ -853,7 +940,7 @@ shladd t0,3,ptp,ptp ldi _PAGE_ACCESSED,t1 ldd 0(ptp),pte - bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_fault + bb,>=,n pte,_PAGE_PRESENT_BIT,nadtlb_emulate /* Check whether the "accessed" bit was set, otherwise do so */ @@ -875,10 +962,11 @@ depdi 0,63,12,pte extrd,u pte,56,32,pte - idtlbt %r16,%r17 + idtlbt pte,prot rfir nop + #else dtlb_miss_11: @@ -895,7 +983,7 @@ ldwx,s t1(ptp),ptp extru va,19,10,t0 /* get second-level index */ - bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_fault + bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_11 depi 0,31,12,ptp /* clear prot bits */ /* Second level page table lookup */ @@ -903,7 +991,7 @@ sh2addl t0,ptp,ptp ldi _PAGE_ACCESSED,t1 ldw 0(ptp),pte - bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_fault + bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_check_alias_11 /* Check whether the "accessed" bit was set, otherwise do so */ @@ -937,9 +1025,90 @@ rfir nop -dtlb_miss_20: - .level 2.0 +dtlb_check_alias_11: + /* Check to see if fault is in the temporary alias region */ + + cmpib,<>,n 0,spc,dtlb_fault /* forward */ + ldil L%(TMPALIAS_MAP_START),t0 + copy va,t1 + depwi 0,31,23,t1 + cmpb,<>,n t0,t1,dtlb_fault /* forward */ + ldi (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot + depw,z prot,8,7,prot + + /* + * OK, it is in the temp alias region, check whether "from" or "to". + * Check "subtle" note in pacache.S re: r23/r26. + */ + + extrw,u,= va,9,1,r0 + or,tr %r23,%r0,pte /* If "from" use "from" page */ + or %r26,%r0,pte /* else "to", use "to" page */ + + idtlba pte,(va) + idtlbp prot,(va) + + rfir + nop + +nadtlb_miss_11: + mfctl %cr25,ptp /* Assume user space miss */ + or,<> %r0,spc,%r0 /* If it is user space, nullify */ + mfctl %cr24,ptp /* Load kernel pgd instead */ + extru va,9,10,t1 /* Get pgd index */ + + mfsp %sr7,t0 /* Get current space */ + or,= %r0,t0,%r0 /* If kernel, nullify following test */ + comb,<>,n t0,spc,nadtlb_fault /* forward */ + + /* First level page table lookup */ + + ldwx,s t1(ptp),ptp + extru va,19,10,t0 /* get second-level index */ + bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate + depi 0,31,12,ptp /* clear prot bits */ + + /* Second level page table lookup */ + + sh2addl t0,ptp,ptp + ldi _PAGE_ACCESSED,t1 + ldw 0(ptp),pte + bb,>=,n pte,_PAGE_PRESENT_BIT,nadtlb_emulate + + /* Check whether the "accessed" bit was set, otherwise do so */ + + or t1,pte,t0 /* t0 has R bit set */ + and,<> t1,pte,%r0 /* test and nullify if already set */ + stw t0,0(ptp) /* write back pte */ + + copy spc,prot /* init prot with faulting space */ + dep pte,8,7,prot + + extru,= pte,_PAGE_NO_CACHE_BIT,1,r0 + depi 1,12,1,prot + extru,= pte,_PAGE_USER_BIT,1,r0 + depi 7,11,3,prot /* Set for user space (1 rsvd for read) */ + extru,= pte,_PAGE_GATEWAY_BIT,1,r0 + depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */ + + /* Get rid of prot bits and convert to page addr for idtlba */ + + depi 0,31,12,pte + extru pte,24,25,pte + + mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */ + mtsp spc,%sr1 + + idtlba pte,(%sr1,va) + idtlbp prot,(%sr1,va) + + mtsp t0, %sr1 /* Restore sr1 */ + + rfir + nop + +dtlb_miss_20: mfctl %cr25,ptp /* Assume user space miss */ or,<> %r0,spc,%r0 /* If it is user space, nullify */ mfctl %cr24,ptp /* Load kernel pgd instead */ @@ -953,7 +1122,7 @@ ldwx,s t1(ptp),ptp extru va,19,10,t0 /* get second-level index */ - bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_fault + bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20 depi 0,31,12,ptp /* clear prot bits */ /* Second level page table lookup */ @@ -961,7 +1130,7 @@ sh2addl t0,ptp,ptp ldi _PAGE_ACCESSED,t1 ldw 0(ptp),pte - bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_fault + bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_check_alias_20 /* Check whether the "accessed" bit was set, otherwise do so */ @@ -983,14 +1152,128 @@ depdi 0,63,12,pte extrd,u pte,56,25,pte - idtlbt %r16,%r17 + idtlbt pte,prot + + rfir + nop + +dtlb_check_alias_20: - .level 1.1 + /* Check to see if fault is in the temporary alias region */ + + cmpib,<>,n 0,spc,dtlb_fault /* forward */ + ldil L%(TMPALIAS_MAP_START),t0 + copy va,t1 + depwi 0,31,23,t1 + cmpb,<>,n t0,t1,dtlb_fault /* forward */ + ldi (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot + depd,z prot,8,7,prot + + /* + * OK, it is in the temp alias region, check whether "from" or "to". + * Check "subtle" note in pacache.S re: r23/r26. + */ + + extrw,u,= va,9,1,r0 + or,tr %r23,%r0,pte /* If "from" use "from" page */ + or %r26,%r0,pte /* else "to", use "to" page */ + + idtlbt pte,prot + + rfir + nop + +nadtlb_miss_20: + mfctl %cr25,ptp /* Assume user space miss */ + or,<> %r0,spc,%r0 /* If it is user space, nullify */ + mfctl %cr24,ptp /* Load kernel pgd instead */ + extru va,9,10,t1 /* Get pgd index */ + + mfsp %sr7,t0 /* Get current space */ + or,= %r0,t0,%r0 /* If kernel, nullify following test */ + comb,<>,n t0,spc,nadtlb_fault /* forward */ + + /* First level page table lookup */ + + ldwx,s t1(ptp),ptp + extru va,19,10,t0 /* get second-level index */ + bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate + depi 0,31,12,ptp /* clear prot bits */ + + /* Second level page table lookup */ + + sh2addl t0,ptp,ptp + ldi _PAGE_ACCESSED,t1 + ldw 0(ptp),pte + bb,>=,n pte,_PAGE_PRESENT_BIT,nadtlb_emulate + + /* Check whether the "accessed" bit was set, otherwise do so */ + + or t1,pte,t0 /* t0 has R bit set */ + and,<> t1,pte,%r0 /* test and nullify if already set */ + stw t0,0(ptp) /* write back pte */ + + copy spc,prot /* init prot with faulting space */ + + depd pte,8,7,prot + extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0 + depdi 1,12,1,prot + extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0 + depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */ + extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0 + depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */ + + /* Get rid of prot bits and convert to page addr for idtlbt */ + + depdi 0,63,12,pte + extrd,u pte,56,25,pte + idtlbt pte,prot rfir nop #endif +nadtlb_emulate: + + /* + * Non access misses can be caused by fdc,fic,pdc,lpa,probe and + * probei instructions. We don't want to fault for these + * instructions (not only does it not make sense, it can cause + * deadlocks, since some flushes are done with the mmap + * semaphore held). If the translation doesn't exist, we can't + * insert a translation, so have to emulate the side effects + * of the instruction. Since we don't insert a translation + * we can get a lot of faults during a flush loop, so it makes + * sense to try to do it here with minimum overhead. We only + * emulate fdc,fic & pdc instructions whose base and index + * registers are not shadowed. We defer everything else to the + * "slow" path. + */ + + mfctl %cr19,%r9 /* Get iir */ + ldi 0x280,%r16 + and %r9,%r16,%r17 + cmpb,<>,n %r16,%r17,nadtlb_fault /* Not fdc,fic,pdc */ + bb,>=,n %r9,26,nadtlb_nullify /* m bit not set, just nullify */ + b,l get_register,%r25 + extrw,u %r9,15,5,%r8 /* Get index register # */ + cmpib,=,n -1,%r1,nadtlb_fault /* have to use slow path */ + copy %r1,%r24 + b,l get_register,%r25 + extrw,u %r9,10,5,%r8 /* Get base register # */ + cmpib,=,n -1,%r1,nadtlb_fault /* have to use slow path */ + b,l set_register,%r25 + add,l %r1,%r24,%r1 /* doesn't affect c/b bits */ + +nadtlb_nullify: + mfctl %cr22,%r8 /* Get ipsw */ + ldil L%PSW_N,%r9 + or %r8,%r9,%r8 /* Set PSW_N */ + mtctl %r8,%cr22 + + rfir + nop + #ifdef __LP64__ itlb_miss_20w: @@ -1053,7 +1336,7 @@ depdi 0,63,12,pte extrd,u pte,56,32,pte - iitlbt %r16,%r17 + iitlbt pte,prot rfir nop @@ -1169,8 +1452,6 @@ copy spc,prot /* init prot with faulting space */ - .level 2.0 - depd pte,8,7,prot extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0 depdi 1,12,1,prot @@ -1183,8 +1464,7 @@ depdi 0,63,12,pte extrd,u pte,56,25,pte - iitlbt %r16,%r17 - .level 1.1 + iitlbt pte,prot rfir nop @@ -1252,7 +1532,7 @@ depdi 0,63,12,pte extrd,u pte,56,32,pte - idtlbt %r16,%r17 + idtlbt pte,prot rfir nop @@ -1344,8 +1624,6 @@ copy spc,prot /* init prot with faulting space */ - .level 2.0 - depd pte,8,7,prot extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0 depdi 1,12,1,prot @@ -1358,9 +1636,7 @@ depdi 0,63,12,pte extrd,u pte,56,25,pte - idtlbt %r16,%r17 - - .level 1.1 + idtlbt pte,prot rfir nop @@ -1380,6 +1656,10 @@ b tlb_fault ldi 6,%r1 +nadtlb_fault: + b tlb_fault + ldi 17,%r1 + dtlb_fault: ldi 15,%r1 @@ -1666,6 +1946,11 @@ STREG %r28,TASK_PT_GR28-TASK_SZ_ALGN-FRAME_SIZE(%r30) + /* Seems to me that dp could be wrong here, if the syscall involved + * calling a module, and nothing got round to restoring dp on return. + */ + loadgp + syscall_check_bh: /* #ifdef NOTNOW */ @@ -1774,21 +2059,28 @@ syscall_restore_rfi: ldo -1(%r0),%r2 /* Set recovery cntr to -1 */ mtctl %r2,%cr0 /* for immediate trap */ - copy %r0,%r2 /* Create a reasonable PSW */ + LDREG TASK_PT_PSW(%r1),%r2 /* Get old PSW */ + ldi 0x0b,%r20 /* Create new PSW */ + depi -1,13,1,%r20 /* C, Q, D, and I bits */ + bb,>=,n %r19,15,try_tbit /* PT_SINGLESTEP */ + depi -1,27,1,%r20 /* R bit */ +try_tbit: + bb,>=,n %r19,14,psw_setup /* PT_BLOCKSTEP, see ptrace.c */ + depi -1,7,1,%r20 /* T bit */ +psw_setup: + STREG %r20,TASK_PT_PSW(%r1) /* XXX W bit??? */ - depi -1,13,1,%r2 - depi -1,28,1,%r2 - depi -1,30,1,%r2 - depi -1,31,1,%r2 - bb,<,n %r19,15,set_rbit /* PT_SINGLESTEP */ - bb,>=,n %r19,14,set_nobit /* PT_BLOCKSTEP, see ptrace.c */ -set_tbit: - depi -1,7,1,%r2 - b,n set_nobit -set_rbit: - depi -1,27,1,%r2 -set_nobit: - STREG %r2,TASK_PT_PSW(%r1) + /* Now if old D bit is clear, it means we didn't save all registers + * on syscall entry, so do that now. This only happens on TRACEME + * calls, or if someone attached to us while we were on a syscall. + * We could make this more efficient by not saving r3-r18, but + * then we wouldn't be able to use the common intr_restore path. + * It is only for traced processes anyway, so performance is not + * an issue. + */ + bb,< %r2,30,pt_regs_ok /* Branch if D set */ + ldo TASK_REGS(%r1),%r25 + reg_save %r25 /* Save r3 to r18 */ STREG %r1,TASK_PT_CR30(%r1) mfsp %sr0,%r2 STREG %r2,TASK_PT_SR0(%r1) @@ -1804,13 +2096,12 @@ STREG %r2,TASK_PT_SR7(%r1) STREG %r2,TASK_PT_IASQ0(%r1) STREG %r2,TASK_PT_IASQ1(%r1) +pt_regs_ok: LDREG TASK_PT_GR31(%r1),%r2 depi 3,31,2,%r2 /* ensure return to user mode. */ STREG %r2,TASK_PT_IAOQ0(%r1) ldo 4(%r2),%r2 STREG %r2,TASK_PT_IAOQ1(%r1) - ldo TASK_REGS(%r1),%r25 - reg_save %r25 /* Save r3 to r18 */ copy %r25,%r16 b intr_restore nop @@ -1849,6 +2140,160 @@ b,n syscall_restore + /* + * get_register is used by the non access tlb miss handlers to + * copy the value of the general register specified in r8 into + * r1. This routine can't be used for shadowed registers, since + * the rfir will restore the original value. So, for the shadowed + * registers we put a -1 into r1 to indicate that the register + * should not be used (the register being copied could also have + * a -1 in it, but that is OK, it just means that we will have + * to use the slow path instead). + */ + +get_register: + blr %r8,%r0 + nop + bv %r0(%r25) /* r0 */ + copy %r0,%r1 + bv %r0(%r25) /* r1 - shadowed */ + ldi -1,%r1 + bv %r0(%r25) /* r2 */ + copy %r2,%r1 + bv %r0(%r25) /* r3 */ + copy %r3,%r1 + bv %r0(%r25) /* r4 */ + copy %r4,%r1 + bv %r0(%r25) /* r5 */ + copy %r5,%r1 + bv %r0(%r25) /* r6 */ + copy %r6,%r1 + bv %r0(%r25) /* r7 */ + copy %r7,%r1 + bv %r0(%r25) /* r8 - shadowed */ + ldi -1,%r1 + bv %r0(%r25) /* r9 - shadowed */ + ldi -1,%r1 + bv %r0(%r25) /* r10 */ + copy %r10,%r1 + bv %r0(%r25) /* r11 */ + copy %r11,%r1 + bv %r0(%r25) /* r12 */ + copy %r12,%r1 + bv %r0(%r25) /* r13 */ + copy %r13,%r1 + bv %r0(%r25) /* r14 */ + copy %r14,%r1 + bv %r0(%r25) /* r15 */ + copy %r15,%r1 + bv %r0(%r25) /* r16 - shadowed */ + ldi -1,%r1 + bv %r0(%r25) /* r17 - shadowed */ + ldi -1,%r1 + bv %r0(%r25) /* r18 */ + copy %r18,%r1 + bv %r0(%r25) /* r19 */ + copy %r19,%r1 + bv %r0(%r25) /* r20 */ + copy %r20,%r1 + bv %r0(%r25) /* r21 */ + copy %r21,%r1 + bv %r0(%r25) /* r22 */ + copy %r22,%r1 + bv %r0(%r25) /* r23 */ + copy %r23,%r1 + bv %r0(%r25) /* r24 - shadowed */ + ldi -1,%r1 + bv %r0(%r25) /* r25 - shadowed */ + ldi -1,%r1 + bv %r0(%r25) /* r26 */ + copy %r26,%r1 + bv %r0(%r25) /* r27 */ + copy %r27,%r1 + bv %r0(%r25) /* r28 */ + copy %r28,%r1 + bv %r0(%r25) /* r29 */ + copy %r29,%r1 + bv %r0(%r25) /* r30 */ + copy %r30,%r1 + bv %r0(%r25) /* r31 */ + copy %r31,%r1 + + /* + * set_register is used by the non access tlb miss handlers to + * copy the value of r1 into the general register specified in + * r8. + */ + +set_register: + blr %r8,%r0 + nop + bv %r0(%r25) /* r0 (silly, but it is a place holder) */ + copy %r1,%r0 + bv %r0(%r25) /* r1 */ + copy %r1,%r1 + bv %r0(%r25) /* r2 */ + copy %r1,%r2 + bv %r0(%r25) /* r3 */ + copy %r1,%r3 + bv %r0(%r25) /* r4 */ + copy %r1,%r4 + bv %r0(%r25) /* r5 */ + copy %r1,%r5 + bv %r0(%r25) /* r6 */ + copy %r1,%r6 + bv %r0(%r25) /* r7 */ + copy %r1,%r7 + bv %r0(%r25) /* r8 */ + copy %r1,%r8 + bv %r0(%r25) /* r9 */ + copy %r1,%r9 + bv %r0(%r25) /* r10 */ + copy %r1,%r10 + bv %r0(%r25) /* r11 */ + copy %r1,%r11 + bv %r0(%r25) /* r12 */ + copy %r1,%r12 + bv %r0(%r25) /* r13 */ + copy %r1,%r13 + bv %r0(%r25) /* r14 */ + copy %r1,%r14 + bv %r0(%r25) /* r15 */ + copy %r1,%r15 + bv %r0(%r25) /* r16 */ + copy %r1,%r16 + bv %r0(%r25) /* r17 */ + copy %r1,%r17 + bv %r0(%r25) /* r18 */ + copy %r1,%r18 + bv %r0(%r25) /* r19 */ + copy %r1,%r19 + bv %r0(%r25) /* r20 */ + copy %r1,%r20 + bv %r0(%r25) /* r21 */ + copy %r1,%r21 + bv %r0(%r25) /* r22 */ + copy %r1,%r22 + bv %r0(%r25) /* r23 */ + copy %r1,%r23 + bv %r0(%r25) /* r24 */ + copy %r1,%r24 + bv %r0(%r25) /* r25 */ + copy %r1,%r25 + bv %r0(%r25) /* r26 */ + copy %r1,%r26 + bv %r0(%r25) /* r27 */ + copy %r1,%r27 + bv %r0(%r25) /* r28 */ + copy %r1,%r28 + bv %r0(%r25) /* r29 */ + copy %r1,%r29 + bv %r0(%r25) /* r30 */ + copy %r1,%r30 + bv %r0(%r25) /* r31 */ + copy %r1,%r31 + + #ifdef __LP64__ unimplemented_64bitirq: ssm PSW_SM_Q+PSW_SM_I, %r0 @@ -1865,3 +2310,4 @@ b,n . nop #endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/hardware.c linux.ac/arch/parisc/kernel/hardware.c --- linux.vanilla/arch/parisc/kernel/hardware.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/hardware.c Tue Apr 3 17:54:33 2001 @@ -218,6 +218,23 @@ {HPHW_NPROC,0x5C9,0x4,0x91,"Rhapsody DC- 440"}, {HPHW_NPROC,0x5CA,0x4,0x91,"Rhapsody DC- 360"}, {HPHW_NPROC,0x5CB,0x4,0x91,"Crescendo 440"}, + {HPHW_NPROC,0x5CC,0x4,0x91,"Prelude W 440"}, + {HPHW_NPROC,0x5CD,0x4,0x91,"SPP2600"}, + {HPHW_NPROC,0x5CE,0x4,0x91,"M2600"}, + {HPHW_NPROC,0x5CF,0x4,0x81,"Alegro W+"}, + {HPHW_NPROC,0x5D0,0x4,0x81,"Kazoo W+"}, + {HPHW_NPROC,0x5D1,0x4,0x91,"Forte W+ 2w"}, + {HPHW_NPROC,0x5D2,0x4,0x91,"Forte W+ 4w"}, + {HPHW_NPROC,0x5D3,0x4,0x91,"Prelude W+ 540"}, + {HPHW_NPROC,0x5D4,0x4,0x91,"Duet W+"}, + {HPHW_NPROC,0x5D5,0x4,0x91,"Crescendo 550"}, + {HPHW_NPROC,0x5D6,0x4,0x81,"Crescendo DC- 440"}, + {HPHW_NPROC,0x5D7,0x4,0x91,"Keystone W+"}, + {HPHW_NPROC,0x5D8,0x4,0x91,"Rhapsody wave 2 W+ DC-"}, + {HPHW_NPROC,0x5D9,0x4,0x91,"Rhapsody wave 2 W+"}, + {HPHW_NPROC,0x5DA,0x4,0x91,"Marcato W+ DC-"}, + {HPHW_NPROC,0x5DB,0x4,0x91,"Marcato W+"}, + {HPHW_NPROC,0x5DE,0x4,0x81,"Piccolo W+"}, {HPHW_NPROC,0x5FF,0x4,0x91,"Hitachi W"}, {HPHW_NPROC,0x600,0x4,0x81,"Gecko (712/60)"}, {HPHW_NPROC,0x601,0x4,0x81,"Gecko 80 (712/80)"}, @@ -694,8 +711,8 @@ {HPHW_FIO, 0x04D, 0x00074, 0x0, "Anole L2 165 Core Centronics"}, {HPHW_FIO, 0x050, 0x00074, 0x0, "Merlin Jr 132 Core Centronics"}, {HPHW_FIO, 0x051, 0x00074, 0x0, "Firehawk Core Centronics"}, - {HPHW_FIO, 0x056, 0x00074, 0x0, "Raven+ wSE FWSCSI Core Centronics"}, - {HPHW_FIO, 0x057, 0x00074, 0x0, "Raven+ wDiff FWSCSI Core Centronics"}, + {HPHW_FIO, 0x056, 0x00074, 0x0, "Raven+ w SE FWSCSI Core Centronics"}, + {HPHW_FIO, 0x057, 0x00074, 0x0, "Raven+ w Diff FWSCSI Core Centronics"}, {HPHW_FIO, 0x058, 0x00074, 0x0, "FireHawk 200 Core Centronics"}, {HPHW_FIO, 0x05C, 0x00074, 0x0, "SummitHawk 230 Core Centronics"}, {HPHW_FIO, 0x800, 0x00074, 0x0, "Hitachi Tiny 64 Core Centronics"}, @@ -1370,7 +1387,20 @@ { 0x05ba, 0x0fff, pcxu_ }, /* 0x05ba - 0x05ba */ { 0x05bb, 0x0fff, pcxw }, /* 0x05bb - 0x05bb */ { 0x05bc, 0x0ffc, pcxw }, /* 0x05bc - 0x05bf */ - { 0x05c0, 0x0fc0, pcxw }, /* 0x05c0 - 0x05ff */ + { 0x05c0, 0x0ffc, pcxw }, /* 0x05c0 - 0x05c3 */ + { 0x05c4, 0x0ffe, pcxw }, /* 0x05c4 - 0x05c5 */ + { 0x05c6, 0x0fff, pcxw }, /* 0x05c6 - 0x05c6 */ + { 0x05c7, 0x0fff, pcxw_ }, /* 0x05c7 - 0x05c7 */ + { 0x05c8, 0x0ffc, pcxw }, /* 0x05c8 - 0x05cb */ + { 0x05cc, 0x0ffe, pcxw }, /* 0x05cc - 0x05cd */ + { 0x05ce, 0x0ffe, pcxw_ }, /* 0x05ce - 0x05cf */ + { 0x05d0, 0x0ffc, pcxw_ }, /* 0x05d0 - 0x05d3 */ + { 0x05d4, 0x0ffe, pcxw_ }, /* 0x05d4 - 0x05d5 */ + { 0x05d6, 0x0fff, pcxw }, /* 0x05d6 - 0x05d6 */ + { 0x05d7, 0x0fff, pcxw_ }, /* 0x05d7 - 0x05d7 */ + { 0x05d8, 0x0ff8, pcxw_ }, /* 0x05d8 - 0x05df */ + { 0x05e0, 0x0ff0, pcxw_ }, /* 0x05e0 - 0x05ef */ + { 0x05f0, 0x0ff0, pcxw_ }, /* 0x05f0 - 0x05ff */ { 0x0600, 0x0ff0, pcxl }, /* 0x0600 - 0x060f */ { 0x0610, 0x0ff0, pcxl }, /* 0x0610 - 0x061f */ { 0x0000, 0x0000, pcx } /* terminate table */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/head.S linux.ac/arch/parisc/kernel/head.S --- linux.vanilla/arch/parisc/kernel/head.S Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/head.S Tue Apr 3 17:54:33 2001 @@ -8,17 +8,14 @@ * Copyright 1999 SuSE GmbH (Philipp Rumpf) * Copyright 1999 Philipp Rumpf (prumpf@tux.org) * - * Initial Version 04-23-1999 by Helge Deller (helge.deller@ruhr-uni-bochum.de) + * Initial Version 04-23-1999 by Helge Deller <deller@gmx.de> */ +#include <linux/config.h> /* for CONFIG_SMP */ #include <asm/offset.h> #include <asm/psw.h> -#define __ASSEMBLY__ -/********* -#include <asm/pdc.h> -*********/ #include <asm/assembly.h> #include <asm/pgtable.h> @@ -52,43 +49,97 @@ .callinfo /* Make sure sr4-sr7 are set to zero for the kernel address space */ - - mtsp %r0,%sr4 - mtsp %r0,%sr5 - mtsp %r0,%sr6 - mtsp %r0,%sr7 + mtsp %r0,%sr4 + mtsp %r0,%sr5 + mtsp %r0,%sr6 + mtsp %r0,%sr7 /* Initialize startup VM. Just map first 8 MB of memory */ - ldil L%PA(pg0),%r1 ldo R%PA(pg0)(%r1),%r1 ldo _PAGE_TABLE(%r1),%r3 + ldil L%PA(swapper_pg_dir),%r4 ldo R%PA(swapper_pg_dir)(%r4),%r4 mtctl %r4,%cr24 /* Initialize kernel root pointer */ mtctl %r4,%cr25 /* Initialize user root pointer */ - stw %r3,0xc00(%r4) /* Hardwired 0xc0000000 kernel vaddr start */ + + stw %r3,0xc00(%r4) /* Hardwired 0xc... kernel Vaddr start*/ ldo 0x1000(%r3),%r3 stw %r3,0xc04(%r4) - ldo _PAGE_KERNEL(%r0),%r3 /* Hardwired 0x0 phys addr start */ + ldo _PAGE_KERNEL(%r0),%r3 /* Hardwired 0 phys addr start */ $pgt_fill_loop: stwm %r3,4(%r1) ldo 0x1000(%r3),%r3 bb,>= %r3,8,$pgt_fill_loop nop + + /* Load the return address...er...crash 'n burn */ + copy %r0,%r2 + + /* And the RFI Target address too */ + ldil L%start_parisc,%r11 + ldo R%start_parisc(%r11),%r11 + + /* And the stack pointer too */ + ldil L%init_task_union+TASK_SZ_ALGN,%sp + ldo R%init_task_union+TASK_SZ_ALGN(%sp),%sp + +#ifdef CONFIG_SMP + /* Set the smp rendevous address into page zero. + ** It would be safer to do this in init_smp_config() but + ** it's just way easier to deal with here because + ** of 64-bit function ptrs and the address is local to this file. + */ + ldil L%PA(smp_slave_stext),%r10 + ldo R%PA(smp_slave_stext)(%r10),%r10 + stw %r10,0x10(%r0) /* MEM_RENDEZ */ + stw %r0,0x28(%r0) /* MEM_RENDEZ_HI - assume addr < 4GB */ + + /* FALLTHROUGH */ + .procend + + /* + ** Code Common to both Monarch and Slave processors. + ** Entry: + ** %r11 must contain RFI target address. + ** %r25/%r26 args to pass to target function + ** %r2 in case rfi target decides it didn't like something + ** + ** Caller must init: SR4-7, %sp, %r10, %cr24/25, + */ +common_stext: + .proc + .callinfo +#else + /* Clear PDC entry point - we won't use it */ + stw %r0,0x10(%r0) /* MEM_RENDEZ */ + stw %r0,0x28(%r0) /* MEM_RENDEZ_HI */ +#endif + + /* PARANOID: clear user scratch/user space SR's */ + mtsp %r0,%sr0 + mtsp %r0,%sr1 + mtsp %r0,%sr2 + mtsp %r0,%sr3 + + /* Initialize Protection Registers */ + mtctl %r0,%cr8 + mtctl %r0,%cr9 + mtctl %r0,%cr12 + mtctl %r0,%cr13 + /* Initialize the global data pointer */ ldil L%$global$,%dp ldo R%$global$(%dp),%dp - - /* And the stack pointer, physical too */ - ldil L%init_task_union+TASK_SZ_ALGN,%sp - ldo R%init_task_union+TASK_SZ_ALGN(%sp),%sp - /* we need this to take interruptions directly after the rfi below */ - /* (which we need for PA2.0 boxes) */ + /* Clear the current task register. + ** We need this to take interruptions directly after the rfi below + ** (required for PA2.0 boxes) + */ mtctl %r0, %cr30 - + /* * Set up our interrupt table. HPMCs might not work after this! * @@ -96,7 +147,6 @@ * following short sequence of instructions can determine this * (without being illegal on a PA1.1 machine). */ - ldi 32,%r10 mtctl %r10,%cr11 .level 2.0 @@ -116,34 +166,103 @@ /* Disable (most) interruptions */ mtsm %r0 - + /* kernel PSW: - * - no interruptions except for HPMC and TOC (which are handled by PDC) + * - no interruptions except HPMC and TOC (which are handled by PDC) * - Q bit set (IODC / PDC interruptions) * - big-endian * - virtually mapped */ - ldil L%KERNEL_PSW,%r10 ldo R%KERNEL_PSW(%r10),%r10 mtctl %r10,%ipsw - - /* Set the space pointers for the post-RFI world */ - mtctl %r0,%cr17 /* Clear two-level IIA Space Queue */ - mtctl %r0,%cr17 /* effectively setting kernel space. */ - - /* And the return address(es) too */ - ldil L%start_parisc,%r10 - ldo R%start_parisc(%r10),%r10 - mtctl %r10,%cr18 - ldo 4(%r10),%r10 - mtctl %r10,%cr18 + + /* Set the space pointers for the post-RFI world + ** Clear the two-level IIA Space Queue, effectively setting + ** Kernel space. + */ + mtctl %r0,%cr17 + mtctl %r0,%cr17 + + /* Load RFI target into PC queue */ + mtctl %r11,%cr18 + ldo 4(%r11),%r11 + mtctl %r11,%cr18 /* Jump to hyperspace */ rfi nop .procend + + +#ifdef CONFIG_SMP + + .import smp_init_current_idle_task,data + .import smp_callin,code + +smp_callin_rtn: + .proc + .callinfo + break 1,1 /* Break if returned from start_secondary */ + nop + nop + .procend + +/*************************************************************************** +* +* smp_slave_stext is executed by all non-monarch Processors when the Monarch +* pokes the slave CPUs in smp.c:smp_boot_cpus(). +* +* Once here, registers values are initialized in order to branch to virtual +* mode. Once all available/eligible CPUs are in virtual mode, all are +* released and start out by executing their own idle task. +*****************************************************************************/ + + +smp_slave_stext: + .proc + .callinfo + + /* + ** Initialize Space registers + */ + mtsp %r0,%sr4 + mtsp %r0,%sr5 + mtsp %r0,%sr6 + mtsp %r0,%sr7 + + /* Initialize the SP - monarch sets up smp_init_current_idle_task */ + ldil L%PA(smp_init_current_idle_task),%sp + ldo R%PA(smp_init_current_idle_task)(%sp),%sp +#ifdef __LP64__ + ldd 0(%sp),%sp /* load task address */ +#else + ldw 0(%sp),%sp /* load task address */ +#endif + addil L%TASK_SZ_ALGN,%sp /* stack is above task */ + ldo R%TASK_SZ_ALGN(%r1),%sp + + /* point CPU to kernel page tables */ + ldil L%PA(swapper_pg_dir),%r4 + ldo R%PA(swapper_pg_dir)(%r4),%r4 + mtctl %r4,%cr24 /* Initialize kernel root pointer */ + mtctl %r4,%cr25 /* Initialize user root pointer */ + + /* Load RFI *return* address in case smp_callin bails */ + ldil L%smp_callin_rtn,%r2 + ldo R%smp_callin_rtn(%r2),%r2 + + /* Load RFI target address. */ + ldil L%smp_callin,%r11 + ldo R%smp_callin(%r11),%r11 + + /* ok...common code can handle the rest */ + b common_stext + nop + + .procend +#endif /* CONFIG_SMP */ .data diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/hpmc.S linux.ac/arch/parisc/kernel/hpmc.S --- linux.vanilla/arch/parisc/kernel/hpmc.S Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/hpmc.S Tue Apr 3 17:54:34 2001 @@ -43,7 +43,6 @@ .level 1.1 .data -#define __ASSEMBLY__ #include <asm/assembly.h> #include <asm/pdc.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/inventory.c linux.ac/arch/parisc/kernel/inventory.c --- linux.vanilla/arch/parisc/kernel/inventory.c Wed Dec 6 19:46:39 2000 +++ linux.ac/arch/parisc/kernel/inventory.c Tue Apr 3 17:54:34 2001 @@ -1,40 +1,36 @@ - /* Copyright (c) 1999 The Puffin Group */ /* Written by David Kennedy and Alex deVries */ #include <linux/types.h> #include <linux/kernel.h> +#include <linux/mm.h> #include <asm/hardware.h> #include <asm/io.h> #include <asm/pdc.h> +#include <asm/processor.h> /* ** Debug options -** DEBUG_PAT Dump details which PDC PAT provides about ranges/devices. +** DEBUG_PAT Dump details which PDC PAT provides about ranges/devices. */ #undef DEBUG_PAT -extern char *parisc_getHWtype(unsigned short hw_type); - -extern struct hp_device * register_module(void *hpa); -extern void print_devices(char * buf); - - -int pdc_hpa_processor(void *address); -#ifndef __LP64__ -static u8 iodc_data[32] __attribute__ ((aligned (64))); -static struct pdc_model model __attribute__ ((aligned (8))); +#ifndef __LP64__ +static u8 iodc_data[32 * sizeof(long)] __attribute__ ((aligned(64))); +static struct pdc_memory_map r_addr __attribute__ ((aligned(8))); +static struct pdc_model model __attribute__ ((aligned(8))); #endif -static unsigned long pdc_result[32] __attribute__ ((aligned (8))) = {0,0,0,0}; -static struct pdc_hpa processor_hpa __attribute__ ((aligned (8))); -static struct pdc_system_map module_result __attribute__ ((aligned (8))); -static struct pdc_module_path module_path __attribute__ ((aligned (8))); +static unsigned long pdc_result[32] __attribute__ ((aligned(8))); +static struct pdc_hpa processor_hpa __attribute__ ((aligned(8))); +static struct pdc_system_map_mod_info module_result __attribute__ ((aligned(8))); +static struct pdc_system_map_addr_info addr_result __attribute__ ((aligned(8))); +static struct pdc_module_path module_path __attribute__ ((aligned(8))); #ifdef __LP64__ #include <asm/pdcpat.h> -int pdc_pat = 0; +int pdc_pat; /* ** The module object is filled via PDC_PAT_CELL[Return Cell Module]. @@ -47,26 +43,25 @@ ** */ -static int -pat_query_module( ulong pcell_loc, ulong mod_index) +static int pat_query_module(ulong pcell_loc, ulong mod_index) { - extern int num_devices; - extern struct hp_device devices[]; - pdc_pat_cell_mod_maddr_block_t pa_pdc_cell; - struct hp_device * dev = &devices[num_devices]; - uint64_t temp; /* 64-bit scratch value */ - long status; /* PDC return value status */ + unsigned long temp; /* 64-bit scratch value */ + long status; /* PDC return value status */ + struct hp_device *dev; /* return cell module (PA or Processor view) */ - status = pdc_pat_cell_module(& pdc_result, pcell_loc, mod_index, - PA_VIEW, & pa_pdc_cell); + status = pdc_pat_cell_module(&pdc_result, pcell_loc, mod_index, + PA_VIEW, &pa_pdc_cell); if (status != PDC_RET_OK) { /* no more cell modules or error */ return status; } + temp = pa_pdc_cell.cba; + dev = alloc_pa_dev(PAT_GET_CBA(temp)); /* sets dev->hpa */ + /* ** save parameters in the hp_device ** (The idea being the device driver will call pdc_pat_cell_module() @@ -81,8 +76,7 @@ dev->pmod_loc = pa_pdc_cell.mod_location; dev->mod_path = pa_pdc_cell.mod_path; - temp = pa_pdc_cell.cba; - register_module((void *) PAT_GET_CBA(temp)); /* fills in dev->hpa */ + register_pa_dev(dev); /* advertise device */ #ifdef DEBUG_PAT /* dump what we see so far... */ @@ -90,37 +84,36 @@ ulong i; case PAT_ENTITY_PROC: - printk ("PAT_ENTITY_PROC: id_eid 0x%lx\n", pa_pdc_cell.mod[0]); + printk("PAT_ENTITY_PROC: id_eid 0x%lx\n", + pa_pdc_cell.mod[0]); break; case PAT_ENTITY_MEM: - printk ("PAT_ENTITY_MEM: amount 0x%lx min_gni_base 0x%lx min_gni_len 0x%lx\n", - pa_pdc_cell.mod[0], - pa_pdc_cell.mod[1], - pa_pdc_cell.mod[2]); + printk("PAT_ENTITY_MEM: amount 0x%lx min_gni_base 0x%lx min_gni_len 0x%lx\n", + pa_pdc_cell.mod[0], pa_pdc_cell.mod[1], + pa_pdc_cell.mod[2]); break; case PAT_ENTITY_CA: - printk ("PAT_ENTITY_CA: %ld\n",pcell_loc); + printk("PAT_ENTITY_CA: %ld\n", pcell_loc); break; case PAT_ENTITY_PBC: - printk ("PAT_ENTITY_PBC: "); + printk("PAT_ENTITY_PBC: "); goto print_ranges; case PAT_ENTITY_SBA: - printk ("PAT_ENTITY_SBA: "); + printk("PAT_ENTITY_SBA: "); goto print_ranges; case PAT_ENTITY_LBA: - printk ("PAT_ENTITY_LBA: "); + printk("PAT_ENTITY_LBA: "); -print_ranges: - printk ("ranges %ld\n", pa_pdc_cell.mod[1]); + print_ranges: + printk("ranges %ld\n", pa_pdc_cell.mod[1]); for (i = 0; i < pa_pdc_cell.mod[1]; i++) { - printk (" %ld: 0x%016lx 0x%016lx 0x%016lx\n", i, - pa_pdc_cell.mod[2+i*3], /* type */ - pa_pdc_cell.mod[3+i*3], /* start */ - pa_pdc_cell.mod[4+i*3]); /* finish (ie end) */ + printk(" %ld: 0x%016lx 0x%016lx 0x%016lx\n", i, pa_pdc_cell.mod[2 + i * 3], /* type */ + pa_pdc_cell.mod[3 + i * 3], /* start */ + pa_pdc_cell.mod[4 + i * 3]); /* finish (ie end) */ } printk("\n"); break; @@ -132,14 +125,13 @@ static int do_pat_inventory(void) { - ulong mod_index=0; + ulong mod_index = 0; int status; ulong cell_num; ulong pcell_loc; pdc_pat = (pdc_pat_cell_get_number(&pdc_result) == PDC_OK); - if (!pdc_pat) - { + if (!pdc_pat) { return 0; } @@ -152,9 +144,8 @@ printk("CELL_GET_NUMBER: 0x%lx 0x%lx\n", cell_num, pcell_loc); #endif - status = pdc_pat_cell_num_to_loc(&pdc_result, cell_num); - if (status == PDC_BAD_OPTION) - { + status = pdc_pat_cell_num_to_loc(&pdc_result, cell_num); + if (status == PDC_BAD_OPTION) { /* Prelude (and it's successors: Lclass, A400/500) only ** implement PDC_PAT_CELL sub-options 0 and 2. ** "Home cook'n is best anyhow!" @@ -166,45 +157,134 @@ panic("WTF? CELL_GET_NUMBER give me invalid cell number?"); } - while (PDC_RET_OK == pat_query_module(pcell_loc, mod_index)) - { + while (PDC_RET_OK == pat_query_module(pcell_loc, mod_index)) { mod_index++; } return mod_index; } -#endif /* __LP64__ */ +#endif /* __LP64__ */ + +/* Fixed Physical Address - Location of the Central Bus */ +#define FPA (unsigned long)(signed int)0xFFF80000 + +/* The fixed portion is contained in hpa[14..19] for 32 bit and hpa[46..51] for 64 bit. +** The maximum number of native devices is 2^6 (64) and the offset between devices is +** 2^12 (0x1000). +** - Ryan +*/ +#define MAX_NATIVE_DEVICES 64 +#define NATIVE_DEVICE_OFFSET 0x1000 + +static int do_native_bus_walk(unsigned long hpa) +{ + int num = 0; + struct hp_device *hp_device; + unsigned long hpa_end = + hpa + (MAX_NATIVE_DEVICES * NATIVE_DEVICE_OFFSET); + + for (; hpa < hpa_end; hpa += NATIVE_DEVICE_OFFSET) { + hp_device = alloc_pa_dev(hpa); + if (!hp_device) + continue; + + register_pa_dev(hp_device); + ++num; + } + return num; +} static int do_newer_workstation_inventory(void) { + int i, j, num; long status; - int i, num = 0; + struct hp_device *hp_device; /* So the idea here is to simply try one SYSTEM_MAP call. If - that one works, great, otherwise do it another way */ - - status = pdc_system_map_find_mods(&module_result,&module_path,0); - - if (status == PDC_RET_OK) { - /* This is for newer non-PDC-PAT boxes */ + ** that one works, great, otherwise do it another way + */ + status = pdc_system_map_find_mods(&module_result, &module_path, 0); + if (status != PDC_RET_OK) + return 0; - printk("a newer box...\n"); - for(i=0, status=PDC_RET_OK; status != PDC_RET_NE_PROC && - status != PDC_RET_NE_MOD ;i++) { + /* This is for newer non-PDC-PAT boxes */ + printk("a newer box...\n"); + num = 0; + for (i = 0; status != PDC_RET_NE_PROC && status != PDC_RET_NE_MOD; ++i) { + + status = pdc_system_map_find_mods(&module_result, &module_path, i); + if (status != PDC_RET_OK) + continue; + + hp_device = alloc_pa_dev((unsigned long) module_result.mod_addr); + if (!hp_device) + continue; + + register_pa_dev(hp_device); + ++num; + + /* if available, get the additional addresses for a module */ + if (!module_result.add_addrs) + continue; - status = pdc_system_map_find_mods(&module_result,&module_path,i); + for (j = 1; j <= module_result.add_addrs; ++j) { + status = pdc_system_map_find_addrs(&addr_result, i, j); if (status == PDC_RET_OK) { - num++; - register_module(module_result.mod_addr); + add_pa_dev_addr(hp_device, (unsigned long) + addr_result.mod_addr); + } else { + printk("Bad PDC_FIND_ADDRESS status return (%ld) for index %d\n", + status, j); + status = PDC_RET_OK; /* reset status for outer loop */ } } - } + } /* end of main loop */ + /* Walk the system bus */ + num += do_native_bus_walk(FPA); return (num > 0); } + #ifndef __LP64__ -static struct pdc_memory_map r_addr __attribute__ ((aligned (8))); + +/* The following checks to see if the system is a 715/old. This might +** sound a bit unusual, but there are some workarounds required for these +** machines. These machines are the 715/33, 715/50 and 715/75. +** +** This function returns 1 if we are a 715/old, and 0 if we're not. +*/ +static int check_if_715old(void) +{ + /* To do this check, I'm going to look at the CPU's hversion and + ** and sversion. I'm taking the following from documentation. Here's + ** the table of machines to skip (CPU_HVERSIONs from hardware.c): + ** + ** Machine CPU_HVERSION real life verification + ** + ** Scorpio (715/50): 0x310 Yes + ** Scorpio Jr.(715/33) 0x311 Yes + ** Strider-50 (715S/50) 0x312 No + ** Strider-33 (715S/33) 0x313 No + ** Trailways-50 (715T/50) 0x314 No + ** Trailways-33 (715T/33) 0x315 No + ** Scorpio Sr.(715/75) 0x316 Yes + ** + */ + + switch (CPU_HVERSION) { + case 0x310: + case 0x311: + case 0x312: + case 0x313: + case 0x314: + case 0x315: + case 0x316: + return 1; + } + return 0; +} + static int really_do_oldhw_inventory(void) { @@ -214,184 +294,205 @@ unsigned int func; /* This is undocumented at the time of writing, but basically - we're setting up mod_path so that bc[0..4]=0xff, and step - through mod to get the "Path Structure for GSC Modules". If - it works, use the returned HPA and determine the hardware type. */ + ** we're setting up mod_path so that bc[0..4]=0xff, and step + ** through mod to get the "Path Structure for GSC Modules". If + ** it works, use the returned HPA and determine the hardware type. + */ - for (i=0;i<6;i++) module_path.bc[i]=0xff; + memset(module_path.bc, 0xff, sizeof(module_path.bc)); - for (mod=0;mod<16;mod++) { + for (mod = 0; mod < 16; mod++) { char *stype = NULL; - - module_path.mod=mod; + + module_path.mod = mod; + status = pdc_mem_map_hpa(&r_addr, &module_path); - if (status!=PDC_RET_OK) continue; - - status = pdc_iodc_read(&pdc_result,(void *) r_addr.hpa, - 0, &iodc_data,32 ); - if (status!=PDC_RET_OK) continue; - hw_type = iodc_data[3]&0x1f; - - switch (hw_type) - { - case HPHW_NPROC: /* 0 */ - stype="Processor"; break; - - case HPHW_MEMORY: /* 1 */ - stype="Memory"; break; - - case HPHW_B_DMA: /* 2 */ - stype="Type B DMA"; break; - - case HPHW_A_DMA: /* 4 */ - stype="Type A DMA"; break; - - case HPHW_A_DIRECT: /* 5 */ - stype="Type A Direct"; break; - - case HPHW_BCPORT: /* 7 */ - stype="Bus Converter Port"; break; - - case HPHW_CONSOLE: /* 9 */ - stype="Console"; break; - - case HPHW_FIO: /* 10 - Graphics */ - stype="Foreign I/O (Graphics)"; break; - - case HPHW_BA: /* 11 - Bus Adapter */ - stype="Bus Adapter"; break; - - case HPHW_IOA: /* 12 */ - stype="I/O Adapter"; break; - - case HPHW_BRIDGE: /* 13 */ - stype="Bridge"; break; - - case HPHW_FABRIC: /* 14 */ - stype="Fabric"; break; - - case HPHW_FAULTY: /* 31 */ - stype="Faulty HW"; break; + if (status != PDC_RET_OK) + continue; + + /* On 715/old systems, pdc_iodc_read() seems to fail + ** and simply hang the system when querying the onboard + ** graphics cards, which are at location 0xf800000. Because + ** of this, I'm going to skip them. We might have to rewrite + ** an exception to this so it ends up in the inventory table. + ** In any case, this is where the hook is. + */ + if (r_addr.hpa == 0xf8000000 && check_if_715old()) { + printk("Using Alex's odd 715/old exception, onboard graphics won't be inventoried!\n"); + continue; + } + status = pdc_iodc_read(&pdc_result, (void *) r_addr.hpa, 0, + &iodc_data, 32); + if (status != PDC_RET_OK) + continue; + + hw_type = iodc_data[3] & 0x1f; + switch (hw_type) { + case HPHW_NPROC: + stype = "Processor"; + break; /* 0 */ + case HPHW_MEMORY: + stype = "Memory"; + break; /* 1 */ + case HPHW_B_DMA: + stype = "Type B DMA"; + break; /* 2 */ + case HPHW_A_DMA: + stype = "Type A DMA"; + break; /* 4 */ + case HPHW_A_DIRECT: + stype = "Type A Direct"; + break; /* 5 */ + case HPHW_BCPORT: + stype = "Bus Converter Port"; + break; /* 7 */ + case HPHW_CONSOLE: + stype = "Console"; + break; /* 9 */ + case HPHW_FIO: + stype = "Foreign I/O (Graphics)"; + break; /* 10 */ + case HPHW_BA: + stype = "Bus Adapter"; + break; /* 11 */ + case HPHW_IOA: + stype = "I/O Adapter"; + break; /* 12 */ + case HPHW_BRIDGE: + stype = "Bridge"; + break; /* 13 */ + case HPHW_FABRIC: + stype = "Fabric"; + break; /* 14 */ + case HPHW_FAULTY: + stype = "Faulty HW"; + break; /* 31 */ case HPHW_OTHER: /* 42 */ - default: + default: printk("Don't know this hw_type: %d\n", hw_type); break; - } + } /* switch() */ - // This is kluged. But don't want to replicate code for - // most of the above cases. + /* This is kluged. But don't want to replicate code for + ** most of the above cases. + */ if (stype) { -#ifdef DBG_PDC_QUERY - // parisc/kernel/drivers.c - extern int num_devices; - extern struct hp_device devices[]; - struct hp_hardware *h; -#endif + struct hp_device *hp_dev; status = pdc_mem_map_hpa(&r_addr, &module_path); - if (status==PDC_RET_OK && register_module((void *) r_addr.hpa) != NULL) - num++; + if (status == PDC_RET_OK + && (hp_dev = alloc_pa_dev(r_addr.hpa))) { + + register_pa_dev(hp_dev); + ++num; + } + if (hw_type == HPHW_BA) { + /* Now, we're checking for devices for each + ** module. I seem to think that the + ** modules in question are Lasi (2), 2nd Lasi (6) + ** Wax (5). To do this, set bc[5]=0, and set + ** bc[4] to the module, and step through the + ** functions. + */ + + for (i = 0; i < 4; i++) { + module_path.bc[i] = 0xff; + } + + module_path.bc[4] = mod; + for (func = 0; func < 16; func++) { + module_path.mod = func; + module_path.bc[5] = 0; + + status = pdc_mem_map_hpa(&r_addr, + &module_path); + if (status != PDC_RET_OK) + continue; + + hp_dev = alloc_pa_dev(r_addr.hpa); + if (hp_dev) { + register_pa_dev(hp_dev); + ++num; + } + } - if (hw_type == HPHW_BA) { - /* Now, we're checking for devices for each - module. I seem to think that the - modules in question are Lasi (2), 2nd Lasi (6) - Wax (5). To do this, set bc[5]=0, and set - bc[4] to the module, and step through the - functions. */ - - for (i=0;i<4;i++) module_path.bc[i]=0xff; - module_path.bc[4]=mod; - for (func=0;func<16;func++) { - module_path.mod = func; - module_path.bc[5]=0; - status = pdc_mem_map_hpa(&r_addr, &module_path); - if (status!=PDC_RET_OK) continue; - if (register_module((void *) r_addr.hpa) != NULL) - num++; } - } - // reset module_path.bc[] - for (i=0;i<6;i++) module_path.bc[i]=0xff; + /* hw_type == HPHW_BA */ + /* reset module_path.bc[] */ + memset(module_path.bc, 0xff, + sizeof(module_path.bc)); -#ifdef DBG_PDC_QUERY -// -// Let print_devices() dump everything which is registered. -// - h = devices[num_devices-1].reference; + } /* if (stype) */ + } /* for() */ - if (h) stype = h->name; - printk("Found %s at %d\n", stype, module_path.mod); -#endif - } - } return num; } -static int -do_old_inventory(void) +static int do_old_inventory(void) { - unsigned int bus_id; + unsigned int bus_id; long status; - int ok = 0; printk(" an older box...\n"); /* Here, we're going to check the model, and decide - if we should even bother trying. */ + ** if we should even bother trying. + */ status = pdc_model_info(&model); - bus_id = (model.hversion >> (4+7) ) &0x1f; + bus_id = (model.hversion >> (4 + 7)) & 0x1f; /* Here, we're checking the HVERSION of the CPU. - We're only checking the 0th CPU, since it'll - be the same on an SMP box. */ + ** We're only checking the 0th CPU, since it'll + ** be the same on an SMP box. + */ switch (bus_id) { - case 0x4: /* 720, 730, 750, 735, 755 */ - case 0x6: /* 705, 710 */ - case 0x7: /* 715, 725 */ - case 0x8: /* 745, 747, 742 */ - case 0xA: /* 712 and similiar */ - case 0xC: /* 715/64, at least */ + case 0x4: /* 720, 730, 750, 735, 755 */ + case 0x6: /* 705, 710 */ + case 0x7: /* 715, 725 */ + case 0x8: /* 745, 747, 742 */ + case 0xA: /* 712 and similiar */ + case 0xC: /* 715/64, at least */ /* Do inventory using MEM_MAP */ - really_do_oldhw_inventory(); - ok = 1; - break; - default: /* Everything else */ - printk("This is a very very old machine, with a bus_id of 0x%x.\n",bus_id); + return really_do_oldhw_inventory(); + + default: /* Everything else */ + printk("This is a very very old machine, with a bus_id of 0x%x.\n", + bus_id); panic("This will probably never run Linux.\n"); } - return ok; + return 0; } #endif /* !__LP64__ */ -void do_inventory(void){ - if((pdc_hpa_processor(&processor_hpa))<0){ - printk(KERN_INFO "Couldn't get the HPA of the processor.\n" ); +void do_inventory(void) +{ + if (pdc_hpa_processor(&processor_hpa) < 0) { + printk(KERN_INFO + "Couldn't get the HPA of the processor.\n"); } printk("Searching for devices in PDC firmware... "); printk("processor hpa 0x%lx\n", processor_hpa.hpa); - if (!( - do_newer_workstation_inventory() + if (!(do_newer_workstation_inventory() #ifdef __LP64__ - || do_pat_inventory() -#else /* __LP64__ */ - || do_old_inventory() -#endif /* __LP64__ */ - )) - { - panic("I can't get the hardware inventory on this machine"); + || do_pat_inventory() +#else /* __LP64__ */ + || do_old_inventory() +#endif /* __LP64__ */ + )) { + panic("I can't get the hardware inventory on this machine"); } - print_devices(NULL); + + print_pa_devices(NULL); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/iosapic.c linux.ac/arch/parisc/kernel/iosapic.c --- linux.vanilla/arch/parisc/kernel/iosapic.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/parisc/kernel/iosapic.c Tue Apr 3 17:54:34 2001 @@ -714,7 +714,8 @@ vi->vi_txn_data = txn_alloc_data(vi->vi_txn_irq, 8); ASSERT(vi->vi_txn_data < 256); /* matches 8 above */ - tmp = request_irq(vi->vi_txn_irq, iosapic_interrupt, 0, "iosapic", vi); + tmp = request_irq(vi->vi_txn_irq, iosapic_interrupt, 0, + vi->vi_name, vi); ASSERT(tmp == 0); vi->vi_eoi_addr = ((void *) isi->isi_hpa) + IOSAPIC_REG_EOI; @@ -1034,6 +1035,7 @@ } memset(vip, 0, sizeof(struct vector_info) * isi->isi_num_vectors); + sprintf(isi->isi_name, "IO-SAPIC%02d", iosapic_count++); /* ** Initialize vector array @@ -1041,11 +1043,12 @@ for (cnt=0; cnt < isi->isi_num_vectors; cnt++, vip++) { vip->vi_irqline = (unsigned char) cnt; vip->vi_ios = isi; + sprintf(vip->vi_name, "%s-L%d", isi->isi_name, cnt); } isi->isi_region = alloc_irq_region(isi->isi_num_vectors, &iosapic_irq_ops, IRQ_REG_DIS|IRQ_REG_MASK, - "I/O Sapic", (void *) isi->isi_vector); + isi->isi_name, (void *) isi->isi_vector); ASSERT(NULL != isi->isi_region); return ((void *) isi); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/iosapic_private.h linux.ac/arch/parisc/kernel/iosapic_private.h --- linux.vanilla/arch/parisc/kernel/iosapic_private.h Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/iosapic_private.h Tue Apr 3 17:54:34 2001 @@ -111,11 +111,12 @@ struct irt_entry *vi_irte; /* IRT entry */ u32 *vi_eoi_addr; /* precalculate EOI reg address */ u32 vi_eoi_data; /* IA64: ? PA: swapped txn_data */ - u8 vi_status; /* status/flags */ - u8 vi_irqline; /* INTINn(IRQ) */ int vi_txn_irq; /* virtual IRQ number for processor */ ulong vi_txn_addr; /* IA64: id_eid PA: partial HPA */ ulong vi_txn_data; /* IA64: vector PA: EIR bit */ + u8 vi_status; /* status/flags */ + u8 vi_irqline; /* INTINn(IRQ) */ + char vi_name[32]; /* user visible identity */ }; @@ -127,6 +128,8 @@ int isi_num_vectors; /* size of IRdT array */ int isi_status; /* status/flags */ unsigned int isi_version; /* DEBUG: data fr version reg */ + /* round up to next cacheline */ + char isi_name[20]; /* identify region for users */ }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/irq.c linux.ac/arch/parisc/kernel/irq.c --- linux.vanilla/arch/parisc/kernel/irq.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/parisc/kernel/irq.c Tue Apr 3 17:54:34 2001 @@ -2,12 +2,10 @@ * * Code to handle x86 style IRQs plus some generic interrupt stuff. * - * This is not in any way SMP-clean. - * * Copyright (C) 1992 Linus Torvalds * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle - * Copyright (C) 1999 SuSE GmbH (Author: Philipp Rumpf, prumpf@tux.org) - * Copyright (C) 2000 Hewlett Packard Corp (Co-Author: Grant Grundler, grundler@cup.hp.com) + * Copyright (C) 1999 SuSE GmbH (Philipp Rumpf, prumpf@tux.org) + * Copyright (C) 1999-2000 Grant Grundler * * 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 @@ -23,9 +21,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/config.h> #include <linux/bitops.h> #include <asm/bitops.h> +#include <linux/config.h> #include <asm/pdc.h> #include <linux/errno.h> #include <linux/init.h> @@ -39,13 +37,16 @@ #include <linux/random.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/spinlock.h> #include <asm/cache.h> #undef DEBUG_IRQ extern void timer_interrupt(int, void *, struct pt_regs *); +#ifdef CONFIG_SMP extern void ipi_interrupt(int, void *, struct pt_regs *); +#endif #ifdef DEBUG_IRQ #define DBG_IRQ(x...) printk(x) @@ -53,9 +54,11 @@ #define DBG_IRQ(x...) #endif /* DEBUG_IRQ */ -#define EIEM_MASK(irq) (1L<<(MAX_CPU_IRQ-IRQ_OFFSET(irq))) -#define CLEAR_EIEM_BIT(irq) set_eiem(get_eiem() & ~EIEM_MASK(irq)) -#define SET_EIEM_BIT(irq) set_eiem(get_eiem() | EIEM_MASK(irq)) +#define EIEM_MASK(irq) (1UL<<(MAX_CPU_IRQ-IRQ_OFFSET(irq))) +#define CLEAR_EIEM_BIT(irq) set_eiem(get_eiem() & ~EIEM_MASK(irq)) +#define SET_EIEM_BIT(irq) set_eiem(get_eiem() | EIEM_MASK(irq)) + +static spinlock_t irq_lock = SPIN_LOCK_UNLOCKED; /* protect IRQ regions */ static void disable_cpu_irq(void *unused, int irq) { @@ -72,17 +75,19 @@ static struct irqaction cpu_irq_actions[IRQ_PER_REGION] = { [IRQ_OFFSET(TIMER_IRQ)] { timer_interrupt, 0, 0, "timer", NULL, NULL }, +#ifdef CONFIG_SMP [IRQ_OFFSET(IPI_IRQ)] { ipi_interrupt, 0, 0, "IPI", NULL, NULL }, +#endif }; struct irq_region cpu_irq_region = { { disable_cpu_irq, enable_cpu_irq, NULL, NULL }, - { &cpu_data[0], "PA-PIC", IRQ_REG_MASK|IRQ_REG_DIS, IRQ_FROM_REGION(CPU_IRQ_REGION)}, + { &cpu_data[0], "PA-CPU-00", IRQ_REG_MASK|IRQ_REG_DIS, IRQ_FROM_REGION(CPU_IRQ_REGION)}, cpu_irq_actions }; struct irq_region *irq_region[NR_IRQ_REGS] = { - [ 0 ] NULL, /* abuse will data page fault (aka code 15) */ + [ 0 ] NULL, /* abuse will data page fault (aka code 15) */ [ CPU_IRQ_REGION ] &cpu_irq_region, }; @@ -95,7 +100,7 @@ static inline void mask_irq(int irq) { struct irq_region *region; - + #ifdef DEBUG_IRQ if (irq != TIMER_IRQ) #endif @@ -144,7 +149,7 @@ BUG(); } -void enable_irq(int irq) +void enable_irq(int irq) { struct irq_region *region; @@ -164,30 +169,36 @@ { #ifdef CONFIG_PROC_FS char *p = buf; - int i, j; - int regnr, irq_no; + int i; + int regnr; struct irq_region *region; - struct irqaction *action, *mainaction; + struct irqaction *action; p += sprintf(p, " "); - for (j=0; j<smp_num_cpus; j++) - p += sprintf(p, "CPU%d ",j); + p += sprintf(p, " IRQ count "); *p++ = '\n'; + /* We don't need *irqsave lock variants since this is + ** only allowed to change while in the base context. + */ + spin_lock(&irq_lock); for (regnr = 0; regnr < NR_IRQ_REGS; regnr++) { region = irq_region[regnr]; - if (!region || !region->action) + + if (!region || !region->action) continue; - - mainaction = region->action; for (i = 0; i <= MAX_CPU_IRQ; i++) { - action = mainaction++; - if (!action || !action->name) + unsigned int irq_no; +#ifdef CONFIG_SMP + int j; +#endif + action = &(region->action[i]); + if (!action->handler) continue; - + irq_no = IRQ_FROM_REGION(regnr) + i; - + p += sprintf(p, "%3d: ", irq_no); #ifndef CONFIG_SMP p += sprintf(p, "%10u ", kstat_irqs(irq_no)); @@ -196,30 +207,20 @@ p += sprintf(p, "%10u ", kstat.irqs[cpu_logical_map(j)][irq_no]); #endif - p += sprintf(p, " %14s", + p += sprintf(p, " %14s", region->data.name ? region->data.name : "N/A"); p += sprintf(p, " %s", action->name); - - for (action=action->next; action; action = action->next) - p += sprintf(p, ", %s", action->name); *p++ = '\n'; - } - } + } + } + spin_unlock(&irq_lock); p += sprintf(p, "\n"); -#if CONFIG_SMP - p += sprintf(p, "LOC: "); - for (j = 0; j < smp_num_cpus; j++) - p += sprintf(p, "%10u ", - apic_timer_irqs[cpu_logical_map(j)]); - p += sprintf(p, "\n"); -#endif - return p - buf; #else /* CONFIG_PROC_FS */ - return 0; + return 0; #endif /* CONFIG_PROC_FS */ } @@ -283,7 +284,7 @@ ** V-class (EPIC): 6 bits ** N/L-class/A500: 8 bits (iosapic) ** PCI 2.2 MSI: 16 bits (I think) -** Existing PCI devices: 32-bits (NCR c720/ATM/GigE/HyperFabric) +** Existing PCI devices: 32-bits (all Symbios SCSI/ATM/HyperFabric) ** ** On the service provider side: ** o PA 1.1 (and PA2.0 narrow mode) 5-bits (width of EIR register) @@ -318,21 +319,23 @@ int cpu = smp_processor_id(); irq_enter(cpu, irq); + ++kstat.irqs[IRQ_REGION(irq)][IRQ_OFFSET(irq)]; #ifdef DEBUG_IRQ if (irq != TIMER_IRQ) #endif DBG_IRQ("do_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq)); + if (action->handler == NULL) - printk(KERN_ERR "No handler for interrupt %d !\n", irq); + printk(KERN_ERR "IRQ: CPU:%d No handler for IRQ %d !\n", cpu, irq); for(; action && action->handler; action = action->next) { action->handler(irq, action->dev_id, regs); } - + irq_exit(cpu, irq); - /* don't need to care about unmasking and stuff */ + /* do_irq_mask() deals with IRQ unmasking and stuff */ do_softirq(); } @@ -340,7 +343,6 @@ { unsigned long bit; int irq; - int cpu = smp_processor_id(); #ifdef DEBUG_IRQ if (mask != (1L << MAX_CPU_IRQ)) @@ -354,17 +356,13 @@ irq_num = region->data.irqbase + irq; - ++kstat.irqs[cpu][IRQ_FROM_REGION(CPU_IRQ_REGION) | irq]; - if (IRQ_REGION(irq_num) != CPU_IRQ_REGION) - ++kstat.irqs[cpu][irq_num]; - mask_irq(irq_num); do_irq(®ion->action[irq], irq_num, regs); unmask_irq(irq_num); } } -static inline int alloc_irqregion(void) +static inline int find_free_region(void) { int irqreg; @@ -383,13 +381,13 @@ struct irq_region *region; int index; - index = alloc_irqregion(); + index = find_free_region(); if((IRQ_REGION(count-1))) return NULL; - + if (count < IRQ_PER_REGION) { - DBG_IRQ("alloc_irq_region() using minimum of %d irq lines for %s (%d)\n", + DBG_IRQ("alloc_irq_region() using minimum of %d irq lines for %s (%d)\n", IRQ_PER_REGION, name, count); count = IRQ_PER_REGION; } @@ -397,7 +395,7 @@ if(flags & IRQ_REG_MASK) if(!(ops->mask_irq && ops->unmask_irq)) return NULL; - + if(flags & IRQ_REG_DIS) if(!(ops->disable_irq && ops->enable_irq)) return NULL; @@ -426,14 +424,14 @@ return irq_region[index]; } - - + + /* FIXME: SMP, flags, bottom halves, rest */ -int request_irq(unsigned int irq, +int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, + unsigned long irqflags, const char * devname, void *dev_id) { @@ -442,6 +440,7 @@ #if 0 printk(KERN_INFO "request_irq(%d, %p, 0x%lx, %s, %p)\n",irq, handler, irqflags, devname, dev_id); #endif + if(!handler) { printk(KERN_ERR "request_irq(%d,...): Augh! No handler for irq!\n", irq); @@ -459,16 +458,28 @@ return -EINVAL; } - action = &irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)]; + /* + ** We don't allow request_irq()/free_irq() called from an + ** interrupt context. We aren't aware of a need for it at + ** the moment. If that changes, replace all usage of irq_lock + ** with *irqsave locking variants. + ** - ggg + */ + if (in_interrupt()) BUG(); + spin_lock(&irq_lock); + action = &(irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)]); + + /* First one is preallocated. */ if(action->handler) { + /* But it's in use...find the tail and allocate a new one */ while(action->next) action = action->next; - action->next = kmalloc(sizeof *action, GFP_ATOMIC); + action->next = kmalloc(sizeof(*action), GFP_ATOMIC); action = action->next; - } + } if(!action) { printk(KERN_ERR "request_irq():Augh! No action!\n") ; @@ -481,6 +492,7 @@ action->name = devname; action->next = NULL; action->dev_id = dev_id; + spin_unlock(&irq_lock); enable_irq(irq); return 0; @@ -490,6 +502,10 @@ { struct irqaction *action, **p; + /* See comments in request_irq() about interrupt context */ + if (in_interrupt()) BUG(); + + spin_lock(&irq_lock); action = &irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)]; if(action->dev_id == dev_id) { @@ -498,6 +514,7 @@ else memcpy(action, action->next, sizeof *action); + spin_unlock(&irq_lock); return; } @@ -512,9 +529,11 @@ *p = action->next; kfree(action); + spin_unlock(&irq_lock); return; } + spin_unlock(&irq_lock); printk(KERN_ERR "Trying to free free IRQ%d\n",irq); } @@ -528,11 +547,16 @@ return 0; } - void __init init_IRQ(void) { + local_irq_disable(); /* PARANOID - should already be disabled */ + set_eiem(-1L); /* enable all EIR bits */ + mtctl(-1L, 23); /* EIRR : clear all pending interrupts */ } +#ifdef CONFIG_PROC_FS +/* called from kernel/sysctl.c:sysctl_init() */ void init_irq_proc(void) { } +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/irq_smp.c linux.ac/arch/parisc/kernel/irq_smp.c --- linux.vanilla/arch/parisc/kernel/irq_smp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/parisc/kernel/irq_smp.c Tue Apr 3 17:54:34 2001 @@ -0,0 +1,233 @@ +/* + * linux/arch/parisc/kernel/irq_smp.c + * (90% stolen from alpha port, 9% from ia64, rest is mine -ggg) + * + * Copyright (C) 2001 Hewlett-Packard Co + * Copyright (C) 2001 Grant Grundler <grundler@puffin.external.hp.com> + * + */ + +#include <linux/kernel.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/random.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/irq.h> + +#include <asm/system.h> +#include <asm/io.h> + + +int global_irq_holder = NO_PROC_ID; /* Who has global_irq_lock. */ +spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; /* protects IRQ's. */ +atomic_t global_irq_count; /* global count of IRQ active */ + + +/* Global IRQ locking depth. */ +static void *previous_irqholder = NULL; + +#define MAXCOUNT 100000000 + + +static void +show(char * str, void *where) +{ + int cpu = smp_processor_id(); + + printk("\n%s, CPU %d: %p\n", str, cpu, where); + printk("irq: %d [%d %d]\n", + irqs_running(), + local_irq_count(0), + local_irq_count(1)); + + printk("bh: %d [%d %d]\n", + spin_is_locked(&global_bh_lock) ? 1 : 0, + local_bh_count(0), + local_bh_count(1)); +} + +static inline void +wait_on_irq(int cpu, void *where) +{ + int count = MAXCOUNT; + + for (;;) { + + /* + * Wait until all interrupts are gone. Wait + * for bottom half handlers unless we're + * already executing in one.. + */ + if (!irqs_running()) { + if (local_bh_count(cpu) + || !spin_is_locked(&global_bh_lock)) + break; + } + + /* Duh, we have to loop. Release the lock to avoid deadlocks */ + spin_unlock(&global_irq_lock); + + for (;;) { + if (!--count) { + show("wait_on_irq", where); + count = MAXCOUNT; + } + __sti(); + udelay(1); /* make sure to run pending irqs */ + __cli(); + + if (irqs_running()) + continue; + if (spin_is_locked(&global_irq_lock)) + continue; + if (!local_bh_count(cpu) + && spin_is_locked(&global_bh_lock)) + continue; + if (spin_trylock(&global_irq_lock)) + break; + } + } +} + +static inline void +get_irqlock(int cpu, void* where) +{ + if (!spin_trylock(&global_irq_lock)) { + /* Do we already hold the lock? */ + if (cpu == global_irq_holder) + return; + /* Uhhuh.. Somebody else got it. Wait. */ + spin_lock(&global_irq_lock); + } + + /* + * Ok, we got the lock bit. + * But that's actually just the easy part.. Now + * we need to make sure that nobody else is running + * in an interrupt context. + */ + wait_on_irq(cpu, where); + + /* + * Finally. + */ +#if DEBUG_SPINLOCK + global_irq_lock.task = current; + global_irq_lock.previous = where; +#endif + global_irq_holder = cpu; + previous_irqholder = where; +} + + +/* +** A global "cli()" while in an interrupt context +** turns into just a local cli(). Interrupts +** should use spinlocks for the (very unlikely) +** case that they ever want to protect against +** each other. +** +** If we already have local interrupts disabled, +** this will not turn a local disable into a +** global one (problems with spinlocks: this makes +** save_flags+cli+sti usable inside a spinlock). +*/ +void +__global_cli(void) +{ + if (in_interrupt()) + { + int cpu = smp_processor_id(); + __cli(); + if (!local_irq_count(cpu)) + { + void *where = __builtin_return_address(0); + get_irqlock(cpu, where); + } + } +} + +void +__global_sti(void) +{ + int cpu = smp_processor_id(); + + if (!local_irq_count(cpu)) + release_irqlock(cpu); + __sti(); +} + +/* + * SMP flags value to restore to: + * 0 - global cli + * 1 - global sti + * 2 - local cli + * 3 - local sti + */ +unsigned long +__global_save_flags(void) +{ + int retval; + int local_enabled; + unsigned long flags; + int cpu = smp_processor_id(); + + __save_flags(flags); + local_enabled = (!(flags & 7)); + /* default to local */ + retval = 2 + local_enabled; + + /* Check for global flags if we're not in an interrupt. */ + if (!local_irq_count(cpu)) { + if (local_enabled) + retval = 1; + if (global_irq_holder == cpu) + retval = 0; + } + return retval; +} + +void +__global_restore_flags(unsigned long flags) +{ + switch (flags) { + case 0: + __global_cli(); + break; + case 1: + __global_sti(); + break; + case 2: + __cli(); + break; + case 3: + __sti(); + break; + default: + printk(KERN_ERR "global_restore_flags: %08lx (%p)\n", + flags, __builtin_return_address(0)); + } +} + +/* + * From its use, I infer that synchronize_irq() stalls a thread until + * the effects of a command to an external device are known to have + * taken hold. Typically, the command is to stop sending interrupts. + * The strategy here is wait until there is at most one processor + * (this one) in an irq. The memory barrier serializes the write to + * the device and the subsequent accesses of global_irq_count. + * --jmartin + */ +#define DEBUG_SYNCHRONIZE_IRQ 0 + +void +synchronize_irq(void) +{ + /* Jay's version. */ + if (irqs_running()) { + cli(); + sti(); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/lasimap.map linux.ac/arch/parisc/kernel/lasimap.map --- linux.vanilla/arch/parisc/kernel/lasimap.map Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/lasimap.map Thu Jan 1 01:00:00 1970 @@ -1,322 +0,0 @@ -# HP 712 kernel keymap. This uses 7 modifier combinations. - -keymaps 0-2,4-5,8,12 -# ie, plain, Shift, AltGr, Control, Control+Shift, Alt and Control+Alt - - -# Change the above line into -# keymaps 0-2,4-6,8,12 -# in case you want the entries -# altgr control keycode 83 = Boot -# altgr control keycode 111 = Boot -# below. -# -# In fact AltGr is used very little, and one more keymap can -# be saved by mapping AltGr to Alt (and adapting a few entries): -# keycode 100 = Alt -# -keycode 1 = F9 F19 Console_21 - control keycode 1 = F9 - alt keycode 1 = Console_9 - control alt keycode 1 = Console_9 -keycode 2 = -keycode 3 = F5 F15 Console_17 - control keycode 3 = F5 - alt keycode 3 = Console_5 - control alt keycode 3 = Console_5 -keycode 4 = F3 F13 Console_15 - control keycode 4 = F3 - alt keycode 4 = Console_3 - control alt keycode 4 = Console_3 -keycode 5 = F1 F11 Console_13 - control keycode 5 = F1 - alt keycode 5 = Console_1 - control alt keycode 5 = Console_1 -keycode 6 = F2 F12 Console_14 - control keycode 6 = F2 - alt keycode 6 = Console_2 - control alt keycode 6 = Console_2 -keycode 7 = F12 F12 Console_24 - control keycode 7 = F12 - alt keycode 7 = Console_12 - control alt keycode 7 = Console_12 -keycode 8 = -keycode 9 = F10 F20 Console_22 - control keycode 9 = F10 - alt keycode 9 = Console_10 - control alt keycode 9 = Console_10 -keycode 10 = F8 F18 Console_20 - control keycode 10 = F8 - alt keycode 10 = Console_8 - control alt keycode 10 = Console_8 -keycode 11 = F6 F16 Console_18 - control keycode 11 = F6 - alt keycode 11 = Console_6 - control alt keycode 11 = Console_6 -keycode 12 = F4 F14 Console_16 - control keycode 12 = F4 - alt keycode 12 = Console_4 - control alt keycode 12 = Console_4 -keycode 13 = Tab Tab - alt keycode 13 = Meta_Tab -keycode 14 = grave asciitilde - control keycode 14 = nul - alt keycode 14 = Meta_grave -keycode 15 = -keycode 16 = -keycode 17 = Alt -keycode 18 = Shift -keycode 19 = -keycode 20 = Control -keycode 21 = q -keycode 22 = one exclam exclam -keycode 23 = -keycode 24 = -keycode 25 = -keycode 26 = z -keycode 27 = s -keycode 28 = a - altgr keycode 28 = Hex_A -keycode 29 = w -keycode 30 = two at at -keycode 31 = -keycode 32 = -keycode 33 = c - altgr keycode 46 = Hex_C -keycode 34 = x -keycode 35 = d - altgr keycode 35 = Hex_D -keycode 36 = e - altgr keycode 36 = Hex_E -keycode 37 = four dollar -keycode 38 = three numbersign -keycode 39 = -keycode 40 = -keycode 41 = -keycode 42 = v -keycode 43 = f - altgr keycode 43 = Hex_F -keycode 44 = t -keycode 45 = r -keycode 46 = five percent -keycode 47 = -keycode 48 = -keycode 49 = n -keycode 50 = b - altgr keycode 50 = Hex_B -keycode 51 = h -keycode 52 = g -keycode 53 = y -keycode 54 = six asciicircum -keycode 55 = -keycode 56 = -keycode 57 = -keycode 58 = m -keycode 59 = j -keycode 60 = u -keycode 61 = seven ampersand -keycode 62 = eight asterisk asterisk -keycode 63 = -keycode 64 = -keycode 65 = comma less - alt keycode 65 = Meta_comma -keycode 66 = k -keycode 67 = i -keycode 68 = o -keycode 69 = zero parenright bracketright -keycode 70 = nine parenleft bracketleft -keycode 71 = -keycode 72 = -keycode 73 = period greater - control keycode 73 = Compose - alt keycode 73 = Meta_period -keycode 74 = slash question - control keycode 74 = Delete - alt keycode 53 = Meta_slash -keycode 75 = l -keycode 76 = semicolon colon - alt keycode 39 = Meta_semicolon -keycode 77 = p -keycode 78 = minus underscore -keycode 79 = -keycode 80 = -keycode 81 = -keycode 82 = apostrophe quotedbl - control keycode 82 = Control_g - alt keycode 40 = Meta_apostrophe -keycode 83 = -keycode 84 = bracketleft braceleft - control keycode 84 = Escape - alt keycode 26 = Meta_bracketleft -keycode 85 = equal plus -keycode 86 = -keycode 87 = -keycode 88 = Caps_Lock -keycode 88 = -keycode 89 = -keycode 89 = -keycode 89 = -keycode 90 = Return - alt keycode 90 = Meta_Control_m -keycode 91 = bracketright braceright asciitilde - control keycode 91 = Control_bracketright - alt keycode 91 = Meta_bracketright -keycode 92 = -keycode 93 = backslash bar - control keycode 43 = Control_backslash - alt keycode 43 = Meta_backslash -keycode 94 = -keycode 95 = -keycode 96 = -keycode 97 = -keycode 98 = -keycode 99 = -keycode 100 = -keycode 101 = -keycode 102 = BackSpace -keycode 103 = -keycode 104 = -keycode 105 = KP_1 - alt keycode 105 = Ascii_1 - altgr keycode 105 = Hex_1 -keycode 106 = -keycode 107 = KP_4 - alt keycode 107 = Ascii_4 - altgr keycode 107 = Hex_4 -keycode 108 = KP_7 - alt keycode 108 = Ascii_7 - altgr keycode 108 = Hex_7 -keycode 109 = -keycode 110 = -keycode 111 = -keycode 112 = KP_0 - alt keycode 82 = Ascii_0 - altgr keycode 82 = Hex_0 -keycode 113 = KP_Period -keycode 114 = KP_2 - alt keycode 114 = Ascii_2 - altgr keycode 114 = Hex_2 -keycode 115 = KP_5 - alt keycode 115 = Ascii_5 - altgr keycode 115 = Hex_5 -keycode 116 = KP_6 - alt keycode 116 = Ascii_6 - altgr keycode 116 = Hex_6 -keycode 117 = KP_8 - alt keycode 117 = Ascii_8 - altgr keycode 117 = Hex_8 -keycode 118 = Escape -keycode 119 = -keycode 120 = F11 -keycode 121 = KP_Add -keycode 122 = KP_3 - alt keycode 122 = Ascii_3 - altgr keycode 122 = Hex_3 -keycode 123 = KP_Subtract -keycode 124 = KP_Multiply -keycode 125 = KP_9 - alt keycode 125 = Ascii_9 - altgr keycode 125 = Hex_9 -keycode 126 = -# 131!! -keycode 127 = F7 F17 Console_19 - control keycode 127 = F7 - alt keycode 127 = Console_7 - control alt keycode 127 = Console_7 - -string F1 = "\033[[A" -string F2 = "\033[[B" -string F3 = "\033[[C" -string F4 = "\033[[D" -string F5 = "\033[[E" -string F6 = "\033[17~" -string F7 = "\033[18~" -string F8 = "\033[19~" -string F9 = "\033[20~" -string F10 = "\033[21~" -string F11 = "\033[23~" -string F12 = "\033[24~" -string F13 = "\033[25~" -string F14 = "\033[26~" -string F15 = "\033[28~" -string F16 = "\033[29~" -string F17 = "\033[31~" -string F18 = "\033[32~" -string F19 = "\033[33~" -string F20 = "\033[34~" -string Find = "\033[1~" -string Insert = "\033[2~" -string Remove = "\033[3~" -string Select = "\033[4~" -string Prior = "\033[5~" -string Next = "\033[6~" -string Macro = "\033[M" -string Pause = "\033[P" -compose '`' 'A' to 'Ŕ' -compose '`' 'a' to 'ŕ' -compose '\'' 'A' to 'Á' -compose '\'' 'a' to 'á' -compose '^' 'A' to 'Â' -compose '^' 'a' to 'â' -compose '~' 'A' to 'Ă' -compose '~' 'a' to 'ă' -compose '"' 'A' to 'Ä' -compose '"' 'a' to 'ä' -compose 'O' 'A' to 'Ĺ' -compose 'o' 'a' to 'ĺ' -compose '0' 'A' to 'Ĺ' -compose '0' 'a' to 'ĺ' -compose 'A' 'A' to 'Ĺ' -compose 'a' 'a' to 'ĺ' -compose 'A' 'E' to 'Ć' -compose 'a' 'e' to 'ć' -compose ',' 'C' to 'Ç' -compose ',' 'c' to 'ç' -compose '`' 'E' to 'Č' -compose '`' 'e' to 'č' -compose '\'' 'E' to 'É' -compose '\'' 'e' to 'é' -compose '^' 'E' to 'Ę' -compose '^' 'e' to 'ę' -compose '"' 'E' to 'Ë' -compose '"' 'e' to 'ë' -compose '`' 'I' to 'Ě' -compose '`' 'i' to 'ě' -compose '\'' 'I' to 'Í' -compose '\'' 'i' to 'í' -compose '^' 'I' to 'Î' -compose '^' 'i' to 'î' -compose '"' 'I' to 'Ď' -compose '"' 'i' to 'ď' -compose '-' 'D' to 'Đ' -compose '-' 'd' to 'đ' -compose '~' 'N' to 'Ń' -compose '~' 'n' to 'ń' -compose '`' 'O' to 'Ň' -compose '`' 'o' to 'ň' -compose '\'' 'O' to 'Ó' -compose '\'' 'o' to 'ó' -compose '^' 'O' to 'Ô' -compose '^' 'o' to 'ô' -compose '~' 'O' to 'Ő' -compose '~' 'o' to 'ő' -compose '"' 'O' to 'Ö' -compose '"' 'o' to 'ö' -compose '/' 'O' to 'Ř' -compose '/' 'o' to 'ř' -compose '`' 'U' to 'Ů' -compose '`' 'u' to 'ů' -compose '\'' 'U' to 'Ú' -compose '\'' 'u' to 'ú' -compose '^' 'U' to 'Ű' -compose '^' 'u' to 'ű' -compose '"' 'U' to 'Ü' -compose '"' 'u' to 'ü' -compose '\'' 'Y' to 'Ý' -compose '\'' 'y' to 'ý' -compose 'T' 'H' to 'Ţ' -compose 't' 'h' to 'ţ' -compose 's' 's' to 'ß' -compose '"' 'y' to '˙' -compose 's' 'z' to 'ß' -compose 'i' 'j' to '˙' diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/led.c linux.ac/arch/parisc/kernel/led.c --- linux.vanilla/arch/parisc/kernel/led.c Wed Dec 6 19:46:39 2000 +++ linux.ac/arch/parisc/kernel/led.c Tue Apr 3 17:54:34 2001 @@ -9,15 +9,25 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * + * TODO: + * - stop all LED activity at kernel shutdown/halt (add to notifier chain) + * - LCD functionality is completely untested (lack of hardware :-() + * - add procfs entry to (maybe partially) enable & disable LEDs + * - speed-up calculations with inlined assembler + * - modularization */ -#include <linux/config.h> +#define DEBUG 1 /* undefine for production */ + #include <linux/init.h> #include <linux/kernel_stat.h> #include <linux/types.h> #include <linux/interrupt.h> #include <linux/ioport.h> #include <linux/bitops.h> +#include <linux/version.h> +#include <linux/delay.h> +#include <linux/netdevice.h> #include <asm/io.h> #include <asm/gsc.h> #include <asm/processor.h> @@ -25,12 +35,17 @@ #include <asm/param.h> /* HZ */ #include <asm/led.h> - -/* define to disable all LED functions */ -#undef DISABLE_LEDS +/* The control of the LEDs and LCDs on PARISC-machines have to be done + completely in software. The necessary calculations are done during every + interrupt and since the calculations may consume relatively much CPU-time + some of the calculations can be turned off with the following defines */ +#undef NO_HEARTBEAT +#undef NO_DISKIO +#undef NO_LAN_RXTX -#define CPU_HVERSION ((boot_cpu_data.hversion >> 4) & 0x0FFF) +#define CALC_ADD(val, comp, add) \ + (val<=(comp/8) ? add/16 : val<=(comp/4) ? add/8 : val<=(comp/2) ? add/4 : add) struct lcd_block { @@ -40,8 +55,10 @@ }; /* Structure returned by PDC_RETURN_CHASSIS_INFO */ +/* NOTE: we use unsigned long:16 two times, since the following member + lcd_cmd_reg_addr needs to be 64bit aligned on 64bit PA2.0-machines */ struct pdc_chassis_lcd_info_ret_block { - unsigned long model:16; /* DISPLAY_MODEL_XXXX (see below) */ + unsigned long model:16; /* DISPLAY_MODEL_XXXX */ unsigned long lcd_width:16; /* width of the LCD in chars (DISPLAY_MODEL_LCD only) */ char *lcd_cmd_reg_addr; /* ptr to LCD cmd-register & data ptr for LED */ char *lcd_data_reg_addr; /* ptr to LCD data-register (LCD only) */ @@ -56,20 +73,10 @@ char _pad; }; -/* values for pdc_chassis_lcd_info_ret_block.model: */ -#define DISPLAY_MODEL_LCD 0 /* KittyHawk LED or LCD */ -#define DISPLAY_MODEL_NONE 1 /* no LED or LCD */ -#define DISPLAY_MODEL_LASI 2 /* LASI style 8 bit LED */ -#define DISPLAY_MODEL_OLD_ASP 0x7F /* faked: ASP style 8 x 1 bit LED (only very old ASP versions) */ - /* LCD_CMD and LCD_DATA for KittyHawk machines */ -#ifdef __LP64__ -#define KITTYHAWK_LCD_CMD 0xfffffffff0190000L -#else -#define KITTYHAWK_LCD_CMD 0xf0190000 -#endif -#define KITTYHAWK_LCD_DATA (KITTYHAWK_LCD_CMD + 1) +#define KITTYHAWK_LCD_CMD (0xfffffffff0190000UL) /* 64bit-ready */ +#define KITTYHAWK_LCD_DATA (KITTYHAWK_LCD_CMD+1) /* lcd_info is pre-initialized to the values needed to program KittyHawk LCD's */ @@ -92,6 +99,8 @@ #define LED_DATA_REG lcd_info.lcd_cmd_reg_addr /* LASI & ASP only */ +/* ptr to LCD/LED-specific function */ +static void (*led_func_ptr) (unsigned char); /* @@ -141,7 +150,6 @@ ** TODO: check the value of "min_cmd_delay" against the value of HZ. ** */ - static void led_LCD_driver(unsigned char leds) { static int last_index; /* 0:heartbeat, 1:disk, 2:lan_in, 3:lan_out */ @@ -178,179 +186,239 @@ } /* now update the vars for the next interrupt iteration */ - if (++last_was_cmd == 2) { + if (++last_was_cmd == 2) { /* switch between cmd & data */ last_was_cmd = 0; - if (++last_index == 4) - last_index = 0; + if (++last_index == 4) + last_index = 0; /* switch back to heartbeat index */ + } +} + + +/* + ** + ** led_get_net_stats() + ** + ** calculate the TX- & RX-troughput on the network interfaces in + ** the system for usage in the LED code + ** + */ +#ifndef NO_LAN_RXTX +static unsigned long led_net_rx_counter, led_net_tx_counter; + +static void led_get_net_stats(int addvalue) +{ + static unsigned long rx_total_last, tx_total_last; + unsigned long rx_total, tx_total; + struct net_device *dev; + struct net_device_stats *stats; + + rx_total = tx_total = 0; + + /* are we really allowed to lock dev during the interrupt this way ? */ + read_lock(&dev_base_lock); + for (dev = dev_base; dev != NULL; dev = dev->next) { + if (dev->get_stats) { /* && dev->if_port!=IF_PORT_UNKNOWN */ + stats = dev->get_stats(dev); + rx_total += stats->rx_packets; + tx_total += stats->tx_packets; + } } + read_unlock(&dev_base_lock); + + rx_total -= rx_total_last; + tx_total -= tx_total_last; + + if (rx_total) + led_net_rx_counter += CALC_ADD(rx_total, tx_total, addvalue); + + if (tx_total) + led_net_tx_counter += CALC_ADD(tx_total, rx_total, addvalue); + + rx_total_last += rx_total; + tx_total_last += tx_total; } +#endif /* NO_LAN_RXTX */ + +/* + ** + ** led_get_diskio_stats() + ** + ** calculate the disk-io througput in the system + ** (analog to linux/fs/proc/proc_misc.c) + ** + */ +#ifndef NO_DISKIO +static unsigned long led_diskio_counter; +static void led_get_diskio_stats(int addvalue) +{ + static unsigned int diskio_total_last, diskio_max; + int major, disk, total; + + total = 0; + for (major = 0; major < DK_MAX_MAJOR; major++) { + for (disk = 0; disk < DK_MAX_DISK; disk++) + total += kstat.dk_drive[major][disk]; + } + total -= diskio_total_last; + + if (total) { + if (total >= diskio_max) { + led_diskio_counter += addvalue; + diskio_max = total; /* new maximum value found */ + } else + led_diskio_counter += CALC_ADD(total, diskio_max, addvalue); + } + + diskio_total_last += total; +} +#endif /* NO_DISKIO */ -static char currentleds; /* stores current value of the LEDs */ -static void (*led_func_ptr) (unsigned char); /* ptr to LCD/LED-specific function */ /* ** led_interrupt_func() ** ** is called at every timer interrupt from time.c, ** updates the chassis LCD/LED + + TODO: + - display load average (older machines like 715/64 have 4 "free" LED's for that!) + - optimizations (we are still in an interrupt-function !!!) + */ -#define HEARTBEAT_LEN (HZ/16) +static unsigned char currentleds; /* stores current value of the LEDs */ + +#define HEARTBEAT_LEN (HZ*6/100) +#define HEARTBEAT_2ND_RANGE_START (HZ*22/100) +#define HEARTBEAT_2ND_RANGE_END (HEARTBEAT_2ND_RANGE_START + HEARTBEAT_LEN) void led_interrupt_func(void) { -#ifndef DISABLE_LEDS - static int count; - static int lastleds = -1; - static int nr; + static unsigned int count, count_HZ; + static unsigned char lastleds; /* exit, if not initialized */ if (!led_func_ptr) return; - /* increment the local counter */ - if (count == (HZ-1)) - count = 0; - else - count++; - - /* calculate the Heartbeat */ - if ((count % (HZ/2)) < HEARTBEAT_LEN) + /* increment the local counters */ + ++count; + if (++count_HZ == HZ) + count_HZ = 0; + +#ifndef NO_HEARTBEAT + /* flash heartbeat-LED like a real heart (2 x short then a long delay) */ + if (count_HZ<HEARTBEAT_LEN || + (count_HZ>=HEARTBEAT_2ND_RANGE_START && count_HZ<HEARTBEAT_2ND_RANGE_END)) currentleds |= LED_HEARTBEAT; else currentleds &= ~LED_HEARTBEAT; +#endif - /* roll LEDs 0..2 */ - if (count == 0) { - if (nr++ >= 2) - nr = 0; - currentleds &= ~7; - currentleds |= (1 << nr); + /* gather network and diskio statistics and flash LEDs respectively */ + +#ifndef NO_LAN_RXTX + if ((count & 31) == 0) + led_get_net_stats(30); + + if (led_net_rx_counter) { + led_net_rx_counter--; + currentleds |= LED_LAN_RCV; + } + else + currentleds &= ~LED_LAN_RCV; + + if (led_net_tx_counter) { + led_net_tx_counter--; + currentleds |= LED_LAN_TX; } + else + currentleds &= ~LED_LAN_TX; +#endif + +#ifndef NO_DISKIO + /* avoid to calculate diskio-stats at same irq as netio-stats ! */ + if ((count & 31) == 15) + led_get_diskio_stats(30); + + if (led_diskio_counter) { + led_diskio_counter--; + currentleds |= LED_DISK_IO; + } + else + currentleds &= ~LED_DISK_IO; +#endif - /* now update the LEDs */ + /* update the LCD/LEDs */ if (currentleds != lastleds) { led_func_ptr(currentleds); lastleds = currentleds; } -#endif } /* ** register_led_driver() ** - ** All information in lcd_info needs to be set up prior - ** calling this function. + ** registers an external LED or LCD for usage by this driver. + ** currently only LCD-, LASI- and ASP-style LCD/LED's are supported. + ** */ -static void __init register_led_driver(void) +int __init register_led_driver( int model, char *cmd_reg, char *data_reg ) { -#ifndef DISABLE_LEDS + static int initialized; + + if (initialized || !data_reg) + return 1; + + lcd_info.model = model; /* store the values */ + LCD_CMD_REG = (cmd_reg == LED_CMD_REG_NONE) ? NULL : cmd_reg; + switch (lcd_info.model) { case DISPLAY_MODEL_LCD: - printk(KERN_INFO "LCD display at (%p,%p)\n", - LCD_CMD_REG , LCD_DATA_REG); + LCD_DATA_REG = data_reg; led_func_ptr = led_LCD_driver; + printk(KERN_INFO "LCD display at %p,%p registered\n", + LCD_CMD_REG , LCD_DATA_REG); + lcd_print( "Linux " UTS_RELEASE ); break; case DISPLAY_MODEL_LASI: - printk(KERN_INFO "LED display at %p\n", - LED_DATA_REG); + LED_DATA_REG = data_reg; led_func_ptr = led_LASI_driver; + printk(KERN_INFO "LED display at %p registered\n", LED_DATA_REG); break; case DISPLAY_MODEL_OLD_ASP: - printk(KERN_INFO "LED (ASP-style) display at %p\n", - LED_DATA_REG); + LED_DATA_REG = data_reg; led_func_ptr = led_ASP_driver; + printk(KERN_INFO "LED (ASP-style) display at %p registered\n", + LED_DATA_REG); break; default: printk(KERN_ERR "%s: Wrong LCD/LED model %d !\n", __FUNCTION__, lcd_info.model); - return; + return 1; } -#endif -} - -/* - * XXX - could this move to lasi.c ?? - */ - -/* - ** lasi_led_init() - ** - ** lasi_led_init() is called from lasi.c with the base hpa - ** of the lasi controller chip. - ** Since Mirage and Electra machines use a different LED - ** address register, we need to check for these machines - ** explicitly. - */ - -#ifdef CONFIG_GSC_LASI -void __init lasi_led_init(unsigned long lasi_hpa) -{ - if (lcd_info.model != DISPLAY_MODEL_NONE || - lasi_hpa == 0) - return; - - printk("%s: CPU_HVERSION %x\n", __FUNCTION__, CPU_HVERSION); - - /* Mirage and Electra machines need special offsets */ - switch (CPU_HVERSION) { - case 0x60A: /* Mirage Jr (715/64) */ - case 0x60B: /* Mirage 100 */ - case 0x60C: /* Mirage 100+ */ - case 0x60D: /* Electra 100 */ - case 0x60E: /* Electra 120 */ - LED_DATA_REG = (char *) (lasi_hpa - 0x00020000); - break; - default: - LED_DATA_REG = (char *) (lasi_hpa + 0x0000C000); - break; - } /* switch() */ - - lcd_info.model = DISPLAY_MODEL_LASI; - register_led_driver(); -} -#endif - - -/* - ** asp_led_init() - ** - ** asp_led_init() is called from asp.c with the ptr - ** to the LED display. - */ - -#ifdef CONFIG_GSC_LASI -void __init asp_led_init(unsigned long led_ptr) -{ - if (lcd_info.model != DISPLAY_MODEL_NONE || - led_ptr == 0) - return; - - lcd_info.model = DISPLAY_MODEL_OLD_ASP; - LED_DATA_REG = (char *) led_ptr; - - register_led_driver(); + + initialized++; /* mark the LCD/LED driver now as initialized */ + + return 0; } -#endif - - - /* ** register_led_regions() ** - ** Simple function, which registers the LCD/LED regions for /procfs. + ** register_led_regions() registers the LCD/LED regions for /procfs. ** At bootup - where the initialisation of the LCD/LED normally happens - ** not all internal structures of request_region() are properly set up, - ** so that we delay the registration until busdevice.c is executed. + ** so that we delay the led-registration until after busdevices_init() + ** has been executed. ** */ @@ -369,6 +437,42 @@ } +/* + ** + ** lcd_print() + ** + ** Displays the given string on the LCD-Display of newer machines + ** + ** TODO: + ** + ** - _NEVER_ execute at the same time as led_LCD_driver() !!!! + ** - + */ +int lcd_print( char *str ) +{ + int i; + + if (lcd_info.model != DISPLAY_MODEL_LCD || !led_func_ptr) + return 0; + + /* Set LCD Cursor to 1st character */ + gsc_writeb(lcd_info.reset_cmd1, LCD_CMD_REG); + udelay(lcd_info.min_cmd_delay); + + /* Print the string */ + for (i=0; i < lcd_info.lcd_width; i++) { + if (str && *str) + gsc_writeb(*str++, LCD_DATA_REG); + else + gsc_writeb(' ', LCD_DATA_REG); + udelay(lcd_info.min_cmd_delay); + } + + return lcd_info.lcd_width; +} + + + /* ** led_init() @@ -384,11 +488,8 @@ int __init led_init(void) { -#ifndef DISABLE_LEDS long pdc_result[32]; - printk("%s: CPU_HVERSION %x\n", __FUNCTION__, CPU_HVERSION); - /* Work around the buggy PDC of KittyHawk-machines */ switch (CPU_HVERSION) { case 0x580: /* KittyHawk DC2-100 (K100) */ @@ -396,7 +497,8 @@ case 0x582: /* KittyHawk DC3 100 (K400) */ case 0x583: /* KittyHawk DC3 120 (K410) */ case 0x58B: /* KittyHawk DC2 100 (K200) */ - printk("%s: KittyHawk-Machine found !!\n", __FUNCTION__); + printk(KERN_INFO "%s: KittyHawk-Machine (hversion 0x%x) found, " + "LED detection skipped.\n", __FILE__, CPU_HVERSION); goto found; /* use the preinitialized values of lcd_info */ default: @@ -407,19 +509,25 @@ pdc_result[0] = pdc_result[1] = 0; if (pdc_chassis_info(&pdc_result, &lcd_info, sizeof(lcd_info)) == PDC_OK) { - printk("%s: chassis info: model %d, ret0=%d, ret1=%d\n", - __FUNCTION__, lcd_info.model, pdc_result[0], pdc_result[1]); + pr_debug("%s: chassis info: model=%d (%s), " + "lcd_width=%d, cmd_delay=%u, ret0=%ld, ret1=%ld\n", + __FUNCTION__, + lcd_info.model, + (lcd_info.model==DISPLAY_MODEL_LCD) ? "LCD" : + (lcd_info.model==DISPLAY_MODEL_LASI) ? "LED" : "unknown", + lcd_info.lcd_width, lcd_info.min_cmd_delay, + pdc_result[0], pdc_result[1]); /* check the results. Some machines have a buggy PDC */ if (pdc_result[0] <= 0 || pdc_result[0] != pdc_result[1]) goto not_found; switch (lcd_info.model) { - case DISPLAY_MODEL_LCD: /* LCD display */ + case DISPLAY_MODEL_LCD: /* LCD display */ if (pdc_result[0] != sizeof(struct pdc_chassis_lcd_info_ret_block) && pdc_result[0] != sizeof(struct pdc_chassis_lcd_info_ret_block) - 1) goto not_found; - printk("%s: min_cmd_delay = %d uS\n", + pr_debug("%s: min_cmd_delay = %d uS\n", __FUNCTION__, lcd_info.min_cmd_delay); break; @@ -435,17 +543,16 @@ printk(KERN_WARNING "Unknown LCD/LED model %d\n", lcd_info.model); goto not_found; - } /* switch() */ + } /* switch() */ found: /* register the LCD/LED driver */ - register_led_driver(); + register_led_driver(lcd_info.model, LCD_CMD_REG, LCD_DATA_REG); return 0; - } /* if() */ + } /* if() */ not_found: lcd_info.model = DISPLAY_MODEL_NONE; return 1; -#endif } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/pacache.S linux.ac/arch/parisc/kernel/pacache.S --- linux.vanilla/arch/parisc/kernel/pacache.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/parisc/kernel/pacache.S Tue Apr 3 17:54:34 2001 @@ -0,0 +1,799 @@ +/* + * Parisc tlb and cache flushing support + * Copyright (C) 2000 Hewlett-Packard (John Marvin) + * + * 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. + */ + +/* + * NOTE: fdc,fic, and pdc instructions that use base register modification + * should only use index and base registers that are not shadowed, + * so that the fast path emulation in the non access miss handler + * can be used. + */ + +#ifdef __LP64__ +#define ADDIB addib,* +#define ADDIBEQ addib,*= /* silly gnu cpp doesn't concatenate * and = */ +#define CMPB cmpb,* +#define ANDCM andcm,* + + .level 2.0w +#else +#define ADDIB addib, +#define ADDIBEQ addib,= /* silly gnu cpp doesn't concatenate * and = */ +#define CMPB cmpb, +#define ANDCM andcm + + .level 2.0 +#endif + +#include <asm/assembly.h> +#include <asm/psw.h> +#include <asm/pgtable.h> +#include <asm/cache.h> + + .text + .align 128 + + .export __flush_tlb_all,code + +__flush_tlb_all: + .proc + .callinfo NO_CALLS + .entry + + /* + * The pitlbe and pdtlbe instructions should only be used to + * flush the entire tlb. Also, there needs to be no intervening + * tlb operations, e.g. tlb misses, so the operation needs + * to happen in real mode with all interruptions disabled. + */ + + /* + * Once again, we do the rfi dance ... some day we need examine + * all of our uses of this type of code and see what can be + * consolidated. + */ + + ssm 0,%r0 /* relied upon translation! */ + nop + nop + nop + nop + nop + nop + nop + + mtsm %r0 /* disable interruptions */ + ldil L%REAL_MODE_PSW, %r1 + ldo R%REAL_MODE_PSW(%r1), %r1 + mtctl %r1, %cr22 + mtctl %r0, %cr17 + mtctl %r0, %cr17 + ldil L%PA(1f),%r1 + ldo R%PA(1f)(%r1),%r1 + mtctl %r1, %cr18 + ldo 4(%r1), %r1 + mtctl %r1, %cr18 + rfi + nop + +1: ldil L%PA(cache_info),%r1 + ldo R%PA(cache_info)(%r1),%r1 + + /* Flush Instruction Tlb */ + + LDREG ITLB_SID_BASE(%r1),%r20 + LDREG ITLB_SID_STRIDE(%r1),%r21 + LDREG ITLB_SID_COUNT(%r1),%r22 + LDREG ITLB_OFF_BASE(%r1),%arg0 + LDREG ITLB_OFF_STRIDE(%r1),%arg1 + LDREG ITLB_OFF_COUNT(%r1),%arg2 + LDREG ITLB_LOOP(%r1),%arg3 + + ADDIBEQ -1,%arg3,fitoneloop /* Preadjust and test */ + movb,<,n %arg3,%r31,fitdone /* If loop < 0, skip */ + copy %arg0,%r28 /* Init base addr */ + +fitmanyloop: /* Loop if LOOP >= 2 */ + mtsp %r20,%sr1 + add %r21,%r20,%r20 /* increment space */ + copy %arg2,%r29 /* Init middle loop count */ + +fitmanymiddle: /* Loop if LOOP >= 2 */ + ADDIB> -1,%r31,fitmanymiddle /* Adjusted inner loop decr */ + pitlbe 0(%sr1,%r28) + pitlbe,m %arg1(%sr1,%r28) /* Last pitlbe and addr adjust */ + ADDIB> -1,%r29,fitmanymiddle /* Middle loop decr */ + copy %arg3,%r31 /* Re-init inner loop count */ + + movb,tr %arg0,%r28,fitmanyloop /* Re-init base addr */ + ADDIB<=,n -1,%r22,fitdone /* Outer loop count decr */ + +fitoneloop: /* Loop if LOOP = 1 */ + mtsp %r20,%sr1 + copy %arg0,%r28 /* init base addr */ + copy %arg2,%r29 /* init middle loop count */ + +fitonemiddle: /* Loop if LOOP = 1 */ + ADDIB> -1,%r29,fitonemiddle /* Middle loop count decr */ + pitlbe,m %arg1(%sr1,%r28) /* pitlbe for one loop */ + + ADDIB> -1,%r22,fitoneloop /* Outer loop count decr */ + add %r21,%r20,%r20 /* increment space */ + +fitdone: + + /* Flush Data Tlb */ + + LDREG DTLB_SID_BASE(%r1),%r20 + LDREG DTLB_SID_STRIDE(%r1),%r21 + LDREG DTLB_SID_COUNT(%r1),%r22 + LDREG DTLB_OFF_BASE(%r1),%arg0 + LDREG DTLB_OFF_STRIDE(%r1),%arg1 + LDREG DTLB_OFF_COUNT(%r1),%arg2 + LDREG DTLB_LOOP(%r1),%arg3 + + ADDIBEQ -1,%arg3,fdtoneloop /* Preadjust and test */ + movb,<,n %arg3,%r31,fdtdone /* If loop < 0, skip */ + copy %arg0,%r28 /* Init base addr */ + +fdtmanyloop: /* Loop if LOOP >= 2 */ + mtsp %r20,%sr1 + add %r21,%r20,%r20 /* increment space */ + copy %arg2,%r29 /* Init middle loop count */ + +fdtmanymiddle: /* Loop if LOOP >= 2 */ + ADDIB> -1,%r31,fdtmanymiddle /* Adjusted inner loop decr */ + pdtlbe 0(%sr1,%r28) + pdtlbe,m %arg1(%sr1,%r28) /* Last pdtlbe and addr adjust */ + ADDIB> -1,%r29,fdtmanymiddle /* Middle loop decr */ + copy %arg3,%r31 /* Re-init inner loop count */ + + movb,tr %arg0,%r28,fdtmanyloop /* Re-init base addr */ + ADDIB<=,n -1,%r22,fdtdone /* Outer loop count decr */ + +fdtoneloop: /* Loop if LOOP = 1 */ + mtsp %r20,%sr1 + copy %arg0,%r28 /* init base addr */ + copy %arg2,%r29 /* init middle loop count */ + +fdtonemiddle: /* Loop if LOOP = 1 */ + ADDIB> -1,%r29,fdtonemiddle /* Middle loop count decr */ + pdtlbe,m %arg1(%sr1,%r28) /* pdtlbe for one loop */ + + ADDIB> -1,%r22,fdtoneloop /* Outer loop count decr */ + add %r21,%r20,%r20 /* increment space */ + +fdtdone: + + /* Switch back to virtual mode */ + + mtsm 0 /* clear Q bit */ + ldil L%KERNEL_PSW, %r1 + ldo R%KERNEL_PSW(%r1), %r1 + mtctl %r1, %cr22 + mtctl %r0, %cr17 + mtctl %r0, %cr17 + ldil L%(2f), %r1 + ldo R%(2f)(%r1), %r1 + LDIL_FIXUP(%r1) + mtctl %r1, %cr18 + ldo 4(%r1), %r1 + mtctl %r1, %cr18 + rfi + nop + +2: bv %r0(%r2) + nop + .exit + + .procend + + .export flush_instruction_cache,code + .import cache_info,data + +flush_instruction_cache: + .proc + .callinfo NO_CALLS + .entry + + mtsp %r0,%sr1 + ldil L%cache_info,%r1 + ldo R%cache_info(%r1),%r1 + LDIL_FIXUP(%r1) + + /* Flush Instruction Cache */ + + LDREG ICACHE_BASE(%r1),%arg0 + LDREG ICACHE_STRIDE(%r1),%arg1 + LDREG ICACHE_COUNT(%r1),%arg2 + LDREG ICACHE_LOOP(%r1),%arg3 + ADDIBEQ -1,%arg3,fioneloop /* Preadjust and test */ + movb,<,n %arg3,%r31,fisync /* If loop < 0, do sync */ + +fimanyloop: /* Loop if LOOP >= 2 */ + ADDIB> -1,%r31,fimanyloop /* Adjusted inner loop decr */ + fice 0(%sr1,%arg0) + fice,m %arg1(%sr1,%arg0) /* Last fice and addr adjust */ + movb,tr %arg3,%r31,fimanyloop /* Re-init inner loop count */ + ADDIB<=,n -1,%arg2,fisync /* Outer loop decr */ + +fioneloop: /* Loop if LOOP = 1 */ + ADDIB> -1,%arg2,fioneloop /* Outer loop count decr */ + fice,m %arg1(%sr1,%arg0) /* Fice for one loop */ + +fisync: + sync + bv %r0(%r2) + nop + .exit + + .procend + + .export flush_data_cache,code + .import cache_info,data + +flush_data_cache: + .proc + .callinfo NO_CALLS + .entry + + mtsp %r0,%sr1 + ldil L%cache_info,%r1 + ldo R%cache_info(%r1),%r1 + LDIL_FIXUP(%r1) + + /* Flush Data Cache */ + + LDREG DCACHE_BASE(%r1),%arg0 + LDREG DCACHE_STRIDE(%r1),%arg1 + LDREG DCACHE_COUNT(%r1),%arg2 + LDREG DCACHE_LOOP(%r1),%arg3 + ADDIBEQ -1,%arg3,fdoneloop /* Preadjust and test */ + movb,<,n %arg3,%r31,fdsync /* If loop < 0, do sync */ + +fdmanyloop: /* Loop if LOOP >= 2 */ + ADDIB> -1,%r31,fdmanyloop /* Adjusted inner loop decr */ + fdce 0(%sr1,%arg0) + fdce,m %arg1(%sr1,%arg0) /* Last fdce and addr adjust */ + movb,tr %arg3,%r31,fdmanyloop /* Re-init inner loop count */ + ADDIB<=,n -1,%arg2,fdsync /* Outer loop decr */ + +fdoneloop: /* Loop if LOOP = 1 */ + ADDIB> -1,%arg2,fdoneloop /* Outer loop count decr */ + fdce,m %arg1(%sr1,%arg0) /* Fdce for one loop */ + +fdsync: + syncdma + sync + bv %r0(%r2) + nop + .exit + + .procend + +#if (TMPALIAS_MAP_START != 0xff000000UL) +#warning TMPALIAS_MAP_START changed. If > 32 bit, code in pacache.S is bogus +#endif + +/* + * NOTE: Code in copy_user_page and clear_user_page have hard coded + * dependencies on the maximum alias boundary being 4 Mb. We've + * been assured by the parisc chip designers that there will not + * ever be a parisc chip with a larger alias boundary (Never say + * never :-) ). + * + * Subtle: the dtlb miss handlers support the temp alias region by + * "knowing" that if a dtlb miss happens within the temp alias + * region it must have occurred while in copy_user_page or + * clear_user_page. Since these routines make use of processor + * local translations, we don't want to insert them into the + * kernel page table. Instead, we load up some general registers + * (they need to be registers which aren't shadowed) + * with the physical page numbers (preshifted for tlb insertion) + * needed to insert the translations. When we miss on the + * translation, the dtlb miss handler inserts the translation + * into the tlb using these values: + * + * %r26 physical page (shifted for tlb insert) of "to" translation + * %r23 physical page (shifted for tlb insert) of "from" translation + */ + + .export copy_user_page_asm,code + +copy_user_page_asm: + .proc + .callinfo NO_CALLS + .entry + + tophys %r26 + tophys %r25 + copy %r25,%r23 /* move into non shadowed register */ + + ldil L%(TMPALIAS_MAP_START),%r28 + LDIL_FIXUP(%r28) +#ifdef __LP64__ + extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */ + extrd,u %r23,56,32,%r23 /* convert phys addr to tlb insert format */ + depd %r24,63,22,%r28 /* Form aliased virtual address 'to' */ + depdi 0,63,12,%r28 /* Clear any offset bits */ + copy %r28,%r29 + depdi 1,41,1,%r29 /* Form aliased virtual address 'from' */ +#else + extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */ + extrw,u %r23,24,25,%r23 /* convert phys addr to tlb insert format */ + depw %r24,31,22,%r28 /* Form aliased virtual address 'to' */ + depwi 0,31,12,%r28 /* Clear any offset bits */ + copy %r28,%r29 + depwi 1,9,1,%r29 /* Form aliased virtual address 'from' */ +#endif + + /* Purge any old translations */ + + pdtlb 0(%r28) + pdtlb 0(%r29) + + ldi 64,%r1 + + /* + * This loop is optimized for PCXL/PCXL2 ldw/ldw and stw/stw + * bundles (very restricted rules for bundling). It probably + * does OK on PCXU and better, but we could do better with + * ldd/std instructions. Note that until (if) we start saving + * the full 64 bit register values on interrupt, we can't + * use ldd/std on a 32 bit kernel. + */ + + +1: + ldw 0(%r29),%r19 + ldw 4(%r29),%r20 + ldw 8(%r29),%r21 + ldw 12(%r29),%r22 + stw %r19,0(%r28) + stw %r20,4(%r28) + stw %r21,8(%r28) + stw %r22,12(%r28) + ldw 16(%r29),%r19 + ldw 20(%r29),%r20 + ldw 24(%r29),%r21 + ldw 28(%r29),%r22 + stw %r19,16(%r28) + stw %r20,20(%r28) + stw %r21,24(%r28) + stw %r22,28(%r28) + ldw 32(%r29),%r19 + ldw 36(%r29),%r20 + ldw 40(%r29),%r21 + ldw 44(%r29),%r22 + stw %r19,32(%r28) + stw %r20,36(%r28) + stw %r21,40(%r28) + stw %r22,44(%r28) + ldw 48(%r29),%r19 + ldw 52(%r29),%r20 + ldw 56(%r29),%r21 + ldw 60(%r29),%r22 + stw %r19,48(%r28) + stw %r20,52(%r28) + stw %r21,56(%r28) + stw %r22,60(%r28) + ldo 64(%r28),%r28 + ADDIB> -1,%r1,1b + ldo 64(%r29),%r29 + + bv %r0(%r2) + nop + .exit + + .procend + + .export clear_user_page_asm,code + +clear_user_page_asm: + .proc + .callinfo NO_CALLS + .entry + + tophys %r26 + + ldil L%(TMPALIAS_MAP_START),%r28 + LDIL_FIXUP(%r28) +#ifdef __LP64__ + extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */ + depd %r25,63,22,%r28 /* Form aliased virtual address 'to' */ + depdi 0,63,12,%r28 /* Clear any offset bits */ +#else + extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */ + depw %r25,31,22,%r28 /* Form aliased virtual address 'to' */ + depwi 0,31,12,%r28 /* Clear any offset bits */ +#endif + + /* Purge any old translation */ + + pdtlb 0(%r28) + + ldi 64,%r1 + +1: + stw %r0,0(%r28) + stw %r0,4(%r28) + stw %r0,8(%r28) + stw %r0,12(%r28) + stw %r0,16(%r28) + stw %r0,20(%r28) + stw %r0,24(%r28) + stw %r0,28(%r28) + stw %r0,32(%r28) + stw %r0,36(%r28) + stw %r0,40(%r28) + stw %r0,44(%r28) + stw %r0,48(%r28) + stw %r0,52(%r28) + stw %r0,56(%r28) + stw %r0,60(%r28) + ADDIB> -1,%r1,1b + ldo 64(%r28),%r28 + + bv %r0(%r2) + nop + .exit + + .procend + + .export flush_kernel_dcache_page + +flush_kernel_dcache_page: + .proc + .callinfo NO_CALLS + .entry + + ldil L%dcache_stride,%r1 + LDIL_FIXUP(%r1) + ldw R%dcache_stride(%r1),%r23 + +#ifdef __LP64__ + depdi,z 1,63-PAGE_SHIFT,1,%r25 +#else + depwi,z 1,31-PAGE_SHIFT,1,%r25 +#endif + add %r26,%r25,%r25 + sub %r25,%r23,%r25 + + +1: fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + CMPB<< %r26,%r25,1b + fdc,m %r23(%r26) + + sync + bv %r0(%r2) + nop + .exit + + .procend + + .export purge_kernel_dcache_page + +purge_kernel_dcache_page: + .proc + .callinfo NO_CALLS + .entry + + ldil L%dcache_stride,%r1 + LDIL_FIXUP(%r1) + ldw R%dcache_stride(%r1),%r23 + +#ifdef __LP64__ + depdi,z 1,63-PAGE_SHIFT,1,%r25 +#else + depwi,z 1,31-PAGE_SHIFT,1,%r25 +#endif + add %r26,%r25,%r25 + sub %r25,%r23,%r25 + +1: pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + CMPB<< %r26,%r25,1b + pdc,m %r23(%r26) + + sync + bv %r0(%r2) + nop + .exit + + .procend + +#if 0 + /* Currently not used, but it still is a possible alternate + * solution. + */ + + .export flush_alias_page + +flush_alias_page: + .proc + .callinfo NO_CALLS + .entry + + tophys %r26 + + ldil L%(TMPALIAS_MAP_START),%r28 + LDIL_FIXUP(%r28) +#ifdef __LP64__ + extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */ + depd %r25,63,22,%r28 /* Form aliased virtual address 'to' */ + depdi 0,63,12,%r28 /* Clear any offset bits */ +#else + extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */ + depw %r25,31,22,%r28 /* Form aliased virtual address 'to' */ + depwi 0,31,12,%r28 /* Clear any offset bits */ +#endif + + /* Purge any old translation */ + + pdtlb 0(%r28) + + ldil L%dcache_stride,%r1 + LDIL_FIXUP(%r1) + ldw R%dcache_stride(%r1),%r23 + +#ifdef __LP64__ + depdi,z 1,63-PAGE_SHIFT,1,%r29 +#else + depwi,z 1,31-PAGE_SHIFT,1,%r29 +#endif + add %r28,%r29,%r29 + sub %r29,%r23,%r29 + +1: fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + CMPB<< %r28,%r29,1b + fdc,m %r23(%r28) + + sync + bv %r0(%r2) + nop + .exit + + .procend +#endif + + .export flush_user_dcache_range_asm + +flush_user_dcache_range_asm: + .proc + .callinfo NO_CALLS + .entry + + ldil L%dcache_stride,%r1 + LDIL_FIXUP(%r1) + ldw R%dcache_stride(%r1),%r23 + ldo -1(%r23),%r21 + ANDCM %r26,%r21,%r26 + +1: CMPB<<,n %r26,%r25,1b + fdc,m %r23(%sr3,%r26) + + sync + bv %r0(%r2) + nop + .exit + + .procend + + .export flush_kernel_dcache_range_asm + +flush_kernel_dcache_range_asm: + .proc + .callinfo NO_CALLS + .entry + + ldil L%dcache_stride,%r1 + LDIL_FIXUP(%r1) + ldw R%dcache_stride(%r1),%r23 + ldo -1(%r23),%r21 + ANDCM %r26,%r21,%r26 + +1: CMPB<<,n %r26,%r25,1b + fdc,m %r23(%r26) + + sync + syncdma + bv %r0(%r2) + nop + .exit + + .procend + + .export flush_user_icache_range_asm + +flush_user_icache_range_asm: + .proc + .callinfo NO_CALLS + .entry + + ldil L%icache_stride,%r1 + LDIL_FIXUP(%r1) + ldw R%icache_stride(%r1),%r23 + ldo -1(%r23),%r21 + ANDCM %r26,%r21,%r26 + +1: CMPB<<,n %r26,%r25,1b + fic,m %r23(%sr3,%r26) + + sync + bv %r0(%r2) + nop + .exit + + .procend + + .export flush_kernel_icache_range_asm + +flush_kernel_icache_range_asm: + .proc + .callinfo NO_CALLS + .entry + + ldil L%icache_stride,%r1 + LDIL_FIXUP(%r1) + ldw R%icache_stride(%r1),%r23 + ldo -1(%r23),%r21 + ANDCM %r26,%r21,%r26 + +1: CMPB<<,n %r26,%r25,1b + fic,m %r23(%r26) + + sync + bv %r0(%r2) + nop + .exit + + .procend + + .export disable_sr_hashing_asm,code + +disable_sr_hashing_asm: + .proc + .callinfo NO_CALLS + .entry + + /* Switch to real mode */ + + ssm 0,%r0 /* relied upon translation! */ + nop + nop + nop + nop + nop + nop + nop + + mtsm %r0 /* disable interruptions */ + ldil L%REAL_MODE_PSW, %r1 + ldo R%REAL_MODE_PSW(%r1), %r1 + mtctl %r1, %cr22 + mtctl %r0, %cr17 + mtctl %r0, %cr17 + ldil L%PA(1f),%r1 + ldo R%PA(1f)(%r1),%r1 + mtctl %r1, %cr18 + ldo 4(%r1), %r1 + mtctl %r1, %cr18 + rfi + nop + +1: cmpib,=,n SRHASH_PCXST,%r26,srdis_pcxs + cmpib,=,n SRHASH_PCXL,%r26,srdis_pcxl + cmpib,=,n SRHASH_PA20,%r26,srdis_pa20 + b,n srdis_done + +srdis_pcxs: + + /* Disable Space Register Hashing for PCXS,PCXT,PCXT' */ + + .word 0x14031a00 /* mfdiag %dr0,%r3 */ + .word 0x14031a00 /* must issue twice */ + depwi 0,18,1,%r3 /* Clear DHE (dcache hash enable) */ + depwi 0,20,1,%r3 /* Clear IHE (icache hash enable) */ + .word 0x14031600 /* mtdiag %r3,%dr0 */ + .word 0x14031600 /* must issue twice */ + b,n srdis_done + +srdis_pcxl: + + /* Disable Space Register Hashing for PCXL */ + + .word 0x14030600 /* mfdiag %dr0,%r3 */ + depwi 0,28,2,%r3 /* Clear DHASH_EN & IHASH_EN */ + .word 0x14030240 /* mtdiag %r3,%dr0 */ + b,n srdis_done + +srdis_pa20: + + /* Disable Space Register Hashing for PCXU,PCXU+,PCXW,PCXW+ */ + + .word 0x144008a3 /* mfdiag %dr2,%r3 */ + depdi 0,54,1,%r3 /* clear DIAG_SPHASH_ENAB (bit 54) */ + .word 0x14431840 /* mtdiag %r3,%dr2 */ + +srdis_done: + + /* Switch back to virtual mode */ + + mtsm 0 /* clear Q bit */ + ldil L%KERNEL_PSW, %r1 + ldo R%KERNEL_PSW(%r1), %r1 + mtctl %r1, %cr22 + mtctl %r0, %cr17 + mtctl %r0, %cr17 + ldil L%(2f), %r1 + ldo R%(2f)(%r1), %r1 + LDIL_FIXUP(%r1) + mtctl %r1, %cr18 + ldo 4(%r1), %r1 + mtctl %r1, %cr18 + rfi + nop + +2: bv %r0(%r2) + nop + .exit + + .procend + + .end diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/parisc_ksyms.c linux.ac/arch/parisc/kernel/parisc_ksyms.c --- linux.vanilla/arch/parisc/kernel/parisc_ksyms.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/parisc_ksyms.c Tue Apr 3 17:54:34 2001 @@ -22,8 +22,10 @@ EXPORT_SYMBOL(strncpy); EXPORT_SYMBOL(strtok); +#if defined(CONFIG_PCI) || defined(CONFIG_ISA) #include <linux/pci.h> EXPORT_SYMBOL(hppa_dma_ops); +#endif #include <asm/irq.h> EXPORT_SYMBOL(enable_irq); @@ -33,18 +35,30 @@ EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(boot_cpu_data); +#include <linux/pm.h> +EXPORT_SYMBOL(pm_power_off); + #ifdef CONFIG_SMP EXPORT_SYMBOL(synchronize_irq); #include <asm/smplock.h> EXPORT_SYMBOL(kernel_flag); +/* from asm/system.h */ #include <asm/system.h> EXPORT_SYMBOL(__global_sti); EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_save_flags); EXPORT_SYMBOL(__global_restore_flags); +#endif +#include <asm/atomic.h> +EXPORT_SYMBOL(__xchg8); +EXPORT_SYMBOL(__xchg32); +EXPORT_SYMBOL(__cmpxchg_u32); +#ifdef __LP64__ +EXPORT_SYMBOL(__xchg64); +EXPORT_SYMBOL(__cmpxchg_u64); #endif #include <asm/uaccess.h> @@ -69,12 +83,24 @@ EXPORT_SYMBOL(gsc_alloc_irq); EXPORT_SYMBOL(pdc_iodc_read); +#if defined(CONFIG_PCI) || defined(CONFIG_ISA) +#include <asm/io.h> +EXPORT_SYMBOL(inb); +EXPORT_SYMBOL(inw); +EXPORT_SYMBOL(inl); +EXPORT_SYMBOL(outb); +EXPORT_SYMBOL(outw); +EXPORT_SYMBOL(outl); +#endif + extern void $$divI(void); extern void $$divU(void); extern void $$remI(void); extern void $$remU(void); +#ifndef __LP64__ extern void $$mulI(void); extern void $$mulU(void); +#endif extern void $$divU_3(void); extern void $$divU_5(void); extern void $$divU_6(void); @@ -98,8 +124,10 @@ EXPORT_SYMBOL_NOVERS($$divU); EXPORT_SYMBOL_NOVERS($$remI); EXPORT_SYMBOL_NOVERS($$remU); +#ifndef __LP64__ EXPORT_SYMBOL_NOVERS($$mulI); EXPORT_SYMBOL_NOVERS($$mulU); +#endif EXPORT_SYMBOL_NOVERS($$divU_3); EXPORT_SYMBOL_NOVERS($$divU_5); EXPORT_SYMBOL_NOVERS($$divU_6); @@ -126,9 +154,11 @@ #ifdef __LP64__ extern void __divdi3(void); extern void __udivdi3(void); +extern void __umoddi3(void); EXPORT_SYMBOL_NOVERS(__divdi3); EXPORT_SYMBOL_NOVERS(__udivdi3); +EXPORT_SYMBOL_NOVERS(__umoddi3); #endif #ifndef __LP64__ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/pci.c linux.ac/arch/parisc/kernel/pci.c --- linux.vanilla/arch/parisc/kernel/pci.c Wed Dec 6 19:46:39 2000 +++ linux.ac/arch/parisc/kernel/pci.c Tue Apr 3 17:54:34 2001 @@ -75,7 +75,7 @@ ASSERT(pci_port); /* make sure services are defined */ \ ASSERT(parisc_pci_hba[b]); /* make sure ioaddr are "fixed up" */ \ if (parisc_pci_hba[b] == NULL) { \ - printk(KERN_WARNING "\nPCI Host Bus Adapter %d not registered. in" #size "(0x%x) returning -1\n", b, addr); \ + printk(KERN_WARNING "\nPCI or WAX Host Bus Adapter %d not registered. in" #size "(0x%x) returning -1\n", b, addr); \ } else { \ d = pci_port->in##type(parisc_pci_hba[b], PCI_PORT_ADDR(addr)); \ } \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/pdc.c linux.ac/arch/parisc/kernel/pdc.c --- linux.vanilla/arch/parisc/kernel/pdc.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/pdc.c Tue Apr 3 17:54:34 2001 @@ -99,6 +99,13 @@ } #endif +int pdc_coproc_cfg(void *address) +{ + ASSERT_ALIGN(address, 8); + return mem_pdc_call(PDC_COPROC, PDC_COPROC_CFG, __pa(address)); +} + + int pdc_iodc_read(void *address, void * hpa, unsigned int index, void * iodc_data, unsigned int iodc_data_size) { @@ -109,11 +116,35 @@ } -int pdc_system_map_find_mods(void *pdc_mod_info, - void *mod_path, int index) +int pdc_psw_get_mask(void *mask_ret) +{ + return mem_pdc_call(PDC_PSW, PDC_PSW_MASK, __pa(mask_ret)); +} + + +int pdc_psw_get_defaults(void *psw_ret) +{ + return mem_pdc_call(PDC_PSW, PDC_PSW_GET_DEFAULTS, __pa(psw_ret)); +} + + +int pdc_psw_set_defaults(unsigned long psw_val) +{ + return mem_pdc_call(PDC_PSW, PDC_PSW_SET_DEFAULTS, psw_val); +} + +int pdc_system_map_find_mods(void *pdc_mod_info, + void *mod_path, long mod_index) { return mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_MODULE, - __pa(pdc_mod_info), __pa(mod_path), (long)index); + __pa(pdc_mod_info), __pa(mod_path), mod_index); +} + +int pdc_system_map_find_addrs(void *pdc_addr_info, + long mod_index, long addr_index) +{ + return mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_ADDRESS, + __pa(pdc_addr_info), mod_index, addr_index); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/pdc_cons.c linux.ac/arch/parisc/kernel/pdc_cons.c --- linux.vanilla/arch/parisc/kernel/pdc_cons.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/pdc_cons.c Tue Apr 3 17:54:34 2001 @@ -31,7 +31,6 @@ void pdc_putc(unsigned char c) { unsigned int n; - unsigned long flags; switch (c) { case '\n': @@ -110,7 +109,7 @@ wait_key: pdc_console_wait_key, unblank: NULL, setup: pdc_console_setup, - flags: CON_PRINTBUFFER|CON_ENABLED, // |CON_CONSDEV, + flags: CON_BOOT|CON_PRINTBUFFER|CON_ENABLED, // |CON_CONSDEV, index: -1, }; @@ -135,16 +134,20 @@ /* Unregister the pdc console with the printk console layer */ void pdc_console_die(void) { + extern unsigned long log_size; /* kernel/printk.c */ + printk("Switching from PDC console\n"); if (!pdc_console_initialized) return; --pdc_console_initialized; - + + /* Don't repeat what we've already printed */ + log_size = 0; + #ifdef CONFIG_VT_CONSOLE { /* fixme (needed?): Wait for console-tasklet to finish !*/ - extern struct tasklet_struct console_tasklet; - tasklet_schedule(&console_tasklet); + schedule_console_callback(); } #endif @@ -163,7 +166,7 @@ void pdc_console_restart(void) { struct console *console; - extern int log_size; + extern unsigned long log_size; /* kernel/printk.c */ if (pdc_console_initialized) return; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/process.c linux.ac/arch/parisc/kernel/process.c --- linux.vanilla/arch/parisc/kernel/process.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/parisc/kernel/process.c Tue Apr 3 17:54:34 2001 @@ -50,6 +50,11 @@ int hlt_counter=0; +/* + * Power off function, if any + */ +void (*pm_power_off)(void); + void disable_hlt(void) { hlt_counter++; @@ -85,26 +90,74 @@ { } -struct notifier_block *mach_notifier; +#ifdef __LP64__ +#define COMMAND_GLOBAL 0xfffffffffffe0030UL +#else +#define COMMAND_GLOBAL 0xfffe0030 +#endif + +#define CMD_RESET 5 /* reset any module */ + +/* +** The Wright Brothers and Gecko systems have a H/W problem +** (Lasi...'nuf said) may cause a broadcast reset to lockup +** the system. An HVERSION dependent PDC call was developed +** to perform a "safe", platform specific broadcast reset instead +** of kludging up all the code. +** +** Older machines which do not implement PDC_BROADCAST_RESET will +** return (with an error) and the regular broadcast reset can be +** issued. Obviously, if the PDC does implement PDC_BROADCAST_RESET +** the PDC call will not return (the system will be reset). +*/ +void machine_restart(char *cmd) +{ +#ifdef FASTBOOT_SELFTEST_SUPPORT + /* + ** If user has modified the Firmware Selftest Bitmap, + ** run the tests specified in the bitmap after the + ** system is rebooted w/PDC_DO_RESET. + ** + ** ftc_bitmap = 0x1AUL "Skip destructive memory tests" + ** + ** Using "directed resets" at each processor with the MEM_TOC + ** vector cleared will also avoid running destructive + ** memory self tests. (Not implemented yet) + */ + if (ftc_bitmap) { + mem_pdc_call( PDC_BROADCAST_RESET, + PDC_DO_FIRM_TEST_RESET, PDC_FIRM_TEST_MAGIC, + ftc_bitmap); + } +#endif + + /* "Normal" system reset */ + (void) mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_RESET, + 0L, 0L, 0L); + + /* Nope...box should reset with just CMD_RESET now */ + gsc_writel(CMD_RESET, COMMAND_GLOBAL); + + /* Wait for RESET to lay us to rest. */ + while (1) ; -void machine_restart(char *ptr) -{ - notifier_call_chain(&mach_notifier, MACH_RESTART, ptr); } void machine_halt(void) { - notifier_call_chain(&mach_notifier, MACH_HALT, NULL); } void machine_power_on(void) { - notifier_call_chain(&mach_notifier, MACH_POWER_ON, NULL); } +/* This routine is called from sys_reboot to actually turn off the + * machine */ void machine_power_off(void) { - notifier_call_chain(&mach_notifier, MACH_POWER_OFF, NULL); + /* If there is a registered power off handler, call it. */ + if(pm_power_off) + pm_power_off(); } @@ -148,10 +201,54 @@ /* * Fill in the FPU structure for a core dump. */ + int dump_fpu (struct pt_regs * regs, elf_fpregset_t *r) { memcpy(r, regs->fr, sizeof *r); return 1; +} + +/* + * Fill in general registers in a core dump. This saves pretty + * much the same registers as hp-ux, although in a different order. + * Registers marked # below are not currently saved in pt_regs, so + * we use their current values here. + * + * gr0..gr31 + * sr0..sr7 + * iaoq0..iaoq1 + * iasq0..iasq1 + * cr11 (sar) + * cr19 (iir) + * cr20 (isr) + * cr21 (ior) + * # cr22 (ipsw) + * # cr0 (recovery counter) + * # cr24..cr31 (temporary registers) + * # cr8,9,12,13 (protection IDs) + * # cr10 (scr/ccr) + * # cr15 (ext int enable mask) + * + */ + +void +parisc_elf_core_copy_regs (struct pt_regs *pt, elf_gregset_t dst) +{ + memset(dst, 0, sizeof(dst)); /* don't leak any "random" bits */ + memcpy(dst + 0, pt->gr, 32 * sizeof(elf_greg_t)); + memcpy(dst + 32, pt->sr, 8 * sizeof(elf_greg_t)); + memcpy(dst + 40, pt->iaoq, 2 * sizeof(elf_greg_t)); + memcpy(dst + 42, pt->iasq, 2 * sizeof(elf_greg_t)); + dst[44] = pt->sar; dst[45] = pt->iir; + dst[46] = pt->isr; dst[47] = pt->ior; + dst[48] = mfctl(22); dst[49] = mfctl(0); + dst[50] = mfctl(24); dst[51] = mfctl(25); + dst[52] = mfctl(26); dst[53] = mfctl(27); + dst[54] = mfctl(28); dst[55] = mfctl(29); + dst[56] = mfctl(30); dst[57] = mfctl(31); + dst[58] = mfctl( 8); dst[59] = mfctl( 9); + dst[60] = mfctl(12); dst[61] = mfctl(13); + dst[62] = mfctl(10); dst[63] = mfctl(15); } /* Note that "fork()" is implemented in terms of clone, with diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/ptrace.c linux.ac/arch/parisc/kernel/ptrace.c --- linux.vanilla/arch/parisc/kernel/ptrace.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/ptrace.c Tue Apr 3 17:54:34 2001 @@ -31,6 +31,9 @@ #define PT_SINGLESTEP 0x10000 #define PT_BLOCKSTEP 0x20000 +/* PSW bits we allow the degubber to modify */ +#define USER_PSW_BITS (PSW_N | PSW_V | PSW_CB) + long sys_ptrace(long request, pid_t pid, long addr, long data) { struct task_struct *child; @@ -146,19 +149,32 @@ ret = -EIO; if ((addr & 3) || (unsigned long) addr >= sizeof(struct pt_regs)) goto out_tsk; - /* XXX This test probably needs adjusting. We probably want to - * allow writes to some bits of PSW, and may want to block writes - * to (some) space registers. Some register values written here - * may be ignored in entry.S:syscall_restore_rfi; e.g. iaoq is - * written with r31/r31+4, and not with the values in pt_regs. + /* Some register values written here may be ignored in + * entry.S:syscall_restore_rfi; e.g. iaoq is written with + * r31/r31+4, and not with the values in pt_regs. */ - /* Allow writing of gr1-gr31, fr*, sr*, iasq*, iaoq*, sar */ - if (addr == PT_PSW || (addr > PT_IAOQ1 && addr != PT_SAR)) + if (addr == PT_PSW) { + /* Allow writing to Nullify, Divide-step-correction, + * and carry/borrow bits. + * BEWARE, if you set N, and then single step, it wont + * stop on the nullified instruction. + */ + data &= USER_PSW_BITS; + task_regs(child)->gr[0] &= ~USER_PSW_BITS; + task_regs(child)->gr[0] |= data; + ret = 0; + goto out_tsk; + } + else if ((addr >= PT_GR1 && addr <= PT_GR31) || + addr == PT_IAOQ0 || addr == PT_IAOQ1 || + (addr >= PT_FR0 && addr <= PT_FR31) || + addr == PT_SAR) { + *(unsigned long *) ((char *) task_regs(child) + addr) = data; + ret = 0; + goto out_tsk; + } + else goto out_tsk; - - *(unsigned long *) ((char *) task_regs(child) + addr) = data; - ret = 0; - goto out_tsk; case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/real2.S linux.ac/arch/parisc/kernel/real2.S --- linux.vanilla/arch/parisc/kernel/real2.S Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/real2.S Tue Apr 3 17:54:34 2001 @@ -7,7 +7,6 @@ * Copyright (C) 2000 Hewlett Packard (Paul Bame bame@puffin.external.hp.com) * */ -#define __ASSEMBLY__ #include <asm/assembly.h> #include <asm/psw.h> @@ -157,7 +156,7 @@ mtctl %r1, %cr18 ldo 4(%r1), %r1 mtctl %r1, %cr18 - load32 PDC_PSW, %r1 + load32 REAL_MODE_PSW, %r1 mtctl %r1, %cr22 rfi diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/sba_iommu.c linux.ac/arch/parisc/kernel/sba_iommu.c --- linux.vanilla/arch/parisc/kernel/sba_iommu.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/parisc/kernel/sba_iommu.c Tue Apr 3 17:54:34 2001 @@ -237,14 +237,18 @@ char *res_map; /* resource map, bit == pdir entry */ u64 *pdir_base; /* physical base address */ - unsigned long *res_hint; /* next available IOVP - circular search */ + unsigned long *res_hint; /* next avail IOVP - circular search */ + spinlock_t res_lock; + unsigned long hint_mask_pdir; /* bits used for DMA hints */ unsigned int res_bitshift; /* from the LEFT! */ unsigned int res_size; /* size of resource map in bytes */ unsigned int hint_shift_pdir; - spinlock_t res_lock; - unsigned long hint_mask_pdir; /* bits used for DMA hints */ #ifdef DELAYED_RESOURCE_CNT - dma_addr_t res_delay[DELAYED_RESOURCE_CNT]; + int saved_cnt; + struct sba_dma_pair { + dma_addr_t iova; + size_t size; + } saved[DELAYED_RESOURCE_CNT]; #endif #ifdef CONFIG_PROC_FS @@ -546,7 +550,6 @@ pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map); pide <<= 3; /* convert to bit address */ pide += bitshiftcnt; - ASSERT(0 != pide); break; } mask >>= o; @@ -562,7 +565,7 @@ } /* wrapped ? */ - ioc->res_hint = (res_end == res_ptr) ? (unsigned long *) ioc->res_map : res_ptr; + ioc->res_hint = (res_end >= res_ptr) ? (unsigned long *) ioc->res_map : res_ptr; return (pide); } @@ -810,7 +813,7 @@ ASSERT(size > 0); /* save offset bits */ - offset = ((dma_addr_t) addr) & ~IOVP_MASK; + offset = ((dma_addr_t) (long) addr) & ~IOVP_MASK; /* round up to nearest IOVP_SIZE */ size = (size + offset + ~IOVP_MASK) & IOVP_MASK; @@ -880,7 +883,10 @@ #else struct ioc *ioc = &sba_list->ioc[0]; #endif - +#ifdef DELAYED_RESOURCE_CNT + struct sba_dma_pair *d = &(ioc->saved[ioc->saved_cnt]); +#endif + unsigned long flags; dma_addr_t offset; offset = iova & ~IOVP_MASK; @@ -891,38 +897,43 @@ size += offset; size = ROUNDUP(size, IOVP_SIZE); - ASSERT(0 != iova); - spin_lock_irqsave(&ioc->res_lock, flags); #ifdef CONFIG_PROC_FS ioc->usingle_calls++; ioc->usingle_pages += size >> IOVP_SHIFT; #endif -#ifdef DELAYED_RESOURCE_CNT - if (ioc->saved_cnt < DELAYED_RESOURCE_CNT) { - ioc->saved_iova[ioc->saved_cnt] = iova; - ioc->saved_size[ioc->saved_cnt] = size; - ioc_saved_cnt++; - } else { - do { -#endif - sba_mark_invalid(ioc, iova, size); - sba_free_range(ioc, iova, size); #ifdef DELAYED_RESOURCE_CNT - ioc->saved_cnt--; - iova = ioc->saved_iova[ioc->saved_cnt]; - size = ioc->saved_size[ioc->saved_cnt]; - } while (ioc->saved_cnt) - + d->iova = iova; + d->size = size; + if (++ioc->saved_cnt >= DELAYED_RESOURCE_CNT) { + int cnt = ioc->saved_cnt; + while (cnt) { + sba_mark_invalid(ioc, d->iova, d->size); + sba_free_range(ioc, d->iova, d->size); + d--; + cnt--; + } + ioc->saved_cnt = 0; /* flush purges */ - (void) (volatile) READ_REG32(ioc->ioc_hpa+IOC_PCOM); + READ_REG32(ioc->ioc_hpa+IOC_PCOM); } #else + sba_mark_invalid(ioc, iova, size); + sba_free_range(ioc, iova, size); /* flush purges */ READ_REG32(ioc->ioc_hpa+IOC_PCOM); #endif spin_unlock_irqrestore(&ioc->res_lock, flags); + + /* XXX REVISIT for 2.5 Linux - we need syncdma for kernel-user + ** space zero-copy support. For Astro based systems this isn't + ** a big deal WRT performance. + ** As long as 2.4 kernels copyin/copyout data from/to userspace, + ** we don't need the syncdma. The issue here is the cachelines + ** in the I/O MMU are *not* fully coherent - this is a bug. + asm volatile("syncdma"); + */ } @@ -955,27 +966,6 @@ free_pages((unsigned long) vaddr, get_order(size)); } -/* -** Two address ranges are "virtually contiguous" iff: -** 1) end of prev == start of next, or... append case -** 3) end of next == start of prev prepend case -** -** and they are DMA contiguous *iff*: -** 2) end of prev and start of next are both on a page boundry -** -** (shift left is a quick trick to mask off upper bits) -*/ -#define DMA_CONTIG(__X, __Y) \ - (((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL) - -/* -** Assumption is two transactions are mutually exclusive. -** ie both go to different parts of memory. -** If both are true, then both transaction are on the same page. -*/ -#define DMA_SAME_PAGE(s1,e1,s2,e2) \ - ( ((((s1) ^ (s2)) >> PAGE_SHIFT) == 0) \ - && ((((e1) ^ (e2)) >> PAGE_SHIFT) == 0) ) /* ** Since 0 is a valid pdir_base index value, can't use that @@ -1006,7 +996,7 @@ #ifdef DEBUG_LARGE_SG_ENTRIES if (dump_run_sg) - printk(" %d : %08lx/%05x %p/%05x\n", + printk(" %2d : %08lx/%05x %p/%05x\n", nents, (unsigned long) sg_dma_address(startsg), cnt, startsg->address, startsg->length @@ -1024,11 +1014,10 @@ if (sg_dma_address(startsg) & PIDE_FLAG) { u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG; dma_offset = (unsigned long) pide & ~IOVP_MASK; - pide >>= IOVP_SHIFT; - pdirp = &(ioc->pdir_base[pide]); sg_dma_address(startsg) = 0; - ++dma_sg; - sg_dma_address(dma_sg) = (pide << IOVP_SHIFT) + dma_offset; + dma_sg++; + sg_dma_address(dma_sg) = pide; + pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]); n_mappings++; } @@ -1039,6 +1028,9 @@ unsigned long vaddr = (unsigned long) startsg->address; ASSERT(pdirp); + /* Since multiple Vcontig blocks could make up + ** one DMA stream, *add* cnt to dma_len. + */ sg_dma_len(dma_sg) += cnt; cnt += dma_offset; dma_offset=0; /* only want offset on first chunk */ @@ -1062,6 +1054,15 @@ } +/* +** Two address ranges are DMA contiguous *iff* "end of prev" and +** "start of next" are both on a page boundry. +** +** (shift left is a quick trick to mask off upper bits) +*/ +#define DMA_CONTIG(__X, __Y) \ + (((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL) + /* ** First pass is to walk the SG list and determine where the breaks are @@ -1077,117 +1078,104 @@ struct scatterlist *startsg, int nents) { + struct scatterlist *vcontig_sg; /* VCONTIG chunk head */ + unsigned long vcontig_len; /* len of VCONTIG chunk */ + unsigned long vcontig_end; + struct scatterlist *dma_sg; /* next DMA stream head */ + unsigned long dma_offset, dma_len; /* start/len of DMA stream */ int n_mappings = 0; while (nents > 0) { - struct scatterlist *dma_sg; /* next DMA stream head */ - unsigned long dma_offset, dma_len; /* start/len of DMA stream */ - struct scatterlist *chunksg; /* virtually contig chunk head */ - unsigned long chunk_addr, chunk_len; /* start/len of VCONTIG chunk */ /* ** Prepare for first/next DMA stream */ - dma_sg = chunksg = startsg; - dma_len = chunk_len = startsg->length; - chunk_addr = (unsigned long) startsg->address; - dma_offset = 0UL; + dma_sg = vcontig_sg = startsg; + dma_len = vcontig_len = vcontig_end = startsg->length; + vcontig_end += (unsigned long) startsg->address; + dma_offset = (unsigned long) startsg->address & ~IOVP_MASK; + + /* PARANOID: clear entries */ + sg_dma_address(startsg) = 0; + sg_dma_len(startsg) = 0; /* ** This loop terminates one iteration "early" since ** it's always looking one "ahead". */ while (--nents > 0) { - /* ptr to coalesce prev and next */ - struct scatterlist *prev_sg = startsg; - unsigned long prev_end = (unsigned long) prev_sg->address + prev_sg->length; - unsigned long current_end; + unsigned long startsg_end; + + startsg++; + startsg_end = (unsigned long) startsg->address + startsg->length; /* PARANOID: clear entries */ sg_dma_address(startsg) = 0; sg_dma_len(startsg) = 0; - /* Now start looking ahead */ - startsg++; - current_end = (unsigned long) startsg->address + startsg->length; - /* ** First look for virtually contiguous blocks. ** PARISC needs this since it's cache is virtually ** indexed and we need the associated virtual ** address for each I/O address we map. ** - ** 1) can we *prepend* the next transaction? + ** 1) Can we prepend the next transaction? + ** Only if they are on the same page. + ** And we don't mind DMA order wrong. NOT. + ** Feasible but requires substantial work. */ - if (current_end == (unsigned long) prev_sg->address) - { - /* prepend : get new offset */ - chunksg = startsg; - chunk_addr = (unsigned long) prev_sg->address; - chunk_len += startsg->length; - dma_len += startsg->length; - continue; - } /* ** 2) or append the next transaction? */ - if (prev_end == (unsigned long) startsg->address) + if (vcontig_end == (unsigned long) startsg->address) { - chunk_len += startsg->length; - dma_len += startsg->length; + vcontig_len += startsg->length; + vcontig_end += startsg->length; + dma_len += startsg->length; continue; } #ifdef DEBUG_LARGE_SG_ENTRIES - dump_run_sg = (chunk_len > IOVP_SIZE); + dump_run_sg = (vcontig_len > IOVP_SIZE); #endif + /* ** Not virtually contigous. ** Terminate prev chunk. ** Start a new chunk. ** - ** Once we start a new VCONTIG chunk, the offset + ** Once we start a new VCONTIG chunk, dma_offset ** can't change. And we need the offset from the first ** chunk - not the last one. Ergo Successive chunks ** must start on page boundaries and dove tail ** with it's predecessor. */ - sg_dma_len(prev_sg) = chunk_len; + sg_dma_len(vcontig_sg) = vcontig_len; - chunk_len = startsg->length; - dma_offset |= (chunk_addr & ~IOVP_MASK); - ASSERT((0 == (chunk_addr & ~IOVP_MASK)) || - (dma_offset == (chunk_addr & ~IOVP_MASK))); + vcontig_sg = startsg; + vcontig_len = startsg->length; -#if 0 /* - ** 4) do the chunks end/start on page boundaries? - ** Easier than 3 since no offsets are involved. + ** 3) do the entries end/start on page boundaries? + ** Don't update vcontig_end until we've checked. */ - if (DMA_CONTIG(prev_end, startsg->address)) + if (DMA_CONTIG(vcontig_end, startsg->address)) { - /* - ** Yes. - ** Reset chunk ptr. - */ - chunksg = startsg; - chunk_addr = (unsigned long) startsg->address; - + vcontig_end = vcontig_len + (unsigned long) startsg->address; + dma_len += vcontig_len; continue; - } else -#endif - { + } else { break; } } /* ** End of DMA Stream - ** Terminate chunk. + ** Terminate last VCONTIG block. ** Allocate space for DMA stream. */ - sg_dma_len(startsg) = chunk_len; + sg_dma_len(vcontig_sg) = vcontig_len; dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK; sg_dma_address(dma_sg) = PIDE_FLAG @@ -1295,10 +1283,11 @@ while (sg_dma_len(sglist) && nents--) { + sba_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction); #ifdef CONFIG_PROC_FS - ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT; + ioc->usg_pages += ((sg_dma_address(sglist) & ~IOVP_MASK) + sg_dma_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT; + ioc->usingle_calls--; /* kluge since call is unmap_sg() */ #endif - sba_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction); ++sglist; } @@ -1625,8 +1614,8 @@ ); sprintf(buf, "%sIO PDIR size : %d bytes (%d entries)\n", buf, - ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits per byte */ - total_pages); /* 8 bits per byte */ + (int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */ + total_pages); sprintf(buf, "%sIO PDIR entries : %ld free %ld used (%d%%)\n", buf, total_pages - ioc->used_pages, ioc->used_pages, @@ -1645,22 +1634,22 @@ sprintf(buf, "%s Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n", buf, min, avg, max); - sprintf(buf, "%spci_map_single(): %8ld calls %8ld pages (avg %d/1000)\n", + sprintf(buf, "%spci_map_single(): %12ld calls %12ld pages (avg %d/1000)\n", buf, ioc->msingle_calls, ioc->msingle_pages, (int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls)); /* KLUGE - unmap_sg calls unmap_single for each mapped page */ - min = ioc->usingle_calls - ioc->usg_calls; + min = ioc->usingle_calls; max = ioc->usingle_pages - ioc->usg_pages; - sprintf(buf, "%spci_unmap_single: %8ld calls %8ld pages (avg %d/1000)\n", + sprintf(buf, "%spci_unmap_single: %12ld calls %12ld pages (avg %d/1000)\n", buf, min, max, (int) ((max * 1000)/min)); - sprintf(buf, "%spci_map_sg() : %8ld calls %8ld pages (avg %d/1000)\n", + sprintf(buf, "%spci_map_sg() : %12ld calls %12ld pages (avg %d/1000)\n", buf, ioc->msg_calls, ioc->msg_pages, (int) ((ioc->msg_pages * 1000)/ioc->msg_calls)); - sprintf(buf, "%spci_unmap_sg() : %8ld calls %8ld pages (avg %d/1000)\n", + sprintf(buf, "%spci_unmap_sg() : %12ld calls %12ld pages (avg %d/1000)\n", buf, ioc->usg_calls, ioc->usg_pages, (int) ((ioc->usg_pages * 1000)/ioc->usg_calls)); @@ -1672,13 +1661,14 @@ { struct sba_device *sba_dev = sba_list; struct ioc *ioc = &sba_dev->ioc[0]; - unsigned long *res_ptr = (unsigned long *)ioc->res_map; + unsigned int *res_ptr = (unsigned int *)ioc->res_map; int i; - for(i = 0; i < (ioc->res_size / sizeof(unsigned long)); ++i, ++res_ptr) { + buf[0] = '\0'; + for(i = 0; i < (ioc->res_size / sizeof(unsigned int)); ++i, ++res_ptr) { if ((i & 7) == 0) strcat(buf,"\n "); - sprintf(buf, "%s %08lx", buf, *res_ptr); + sprintf(buf, "%s %08x", buf, *res_ptr); } strcat(buf, "\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/semaphore.c linux.ac/arch/parisc/kernel/semaphore.c --- linux.vanilla/arch/parisc/kernel/semaphore.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/semaphore.c Tue Apr 3 17:54:34 2001 @@ -9,6 +9,7 @@ #include <linux/sched.h> #include <asm/semaphore-helper.h> +#include <asm/atomic.h> /* for xchg() definitions */ /* * Semaphores are implemented using a two-way counter: @@ -184,9 +185,9 @@ add_wait_queue_exclusive(&sem->wait, &wait); while (atomic_read(&sem->count) < 0) { - set_task_state(current, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + set_task_state(current, TASK_UNINTERRUPTIBLE); if (atomic_read(&sem->count) >= 0) - break; /* we must attempt to aquire or bias the lock */ + break; /* we must attempt to acquire or bias the lock */ schedule(); } @@ -203,7 +204,7 @@ for (;;) { if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0)) break; - set_task_state(current, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + set_task_state(current, TASK_UNINTERRUPTIBLE); if (!sem->write_bias_granted) schedule(); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/setup.c linux.ac/arch/parisc/kernel/setup.c --- linux.vanilla/arch/parisc/kernel/setup.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/parisc/kernel/setup.c Tue Apr 3 17:54:34 2001 @@ -1,9 +1,9 @@ /* $Id: setup.c,v 1.8 2000/02/02 04:42:38 prumpf Exp $ * * Initial setup-routines for HP 9000 based hardware. - * + * * Copyright (C) 1991, 1992, 1995 Linus Torvalds - * Modifications for PA-RISC (C) 1999 Helge Deller <helge.deller@ruhr-uni-bochum.de> + * Modifications for PA-RISC (C) 1999 Helge Deller <deller@gmx.de> * Modifications copyright 1999 SuSE GmbH (Philipp Rumpf) * Modifications copyright 2000 Martin K. Petersen <mkp@mkp.net> * Modifications copyright 2000 Philipp Rumpf <prumpf@tux.org> @@ -19,13 +19,14 @@ * 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 <linux/config.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -36,7 +37,6 @@ #include <linux/unistd.h> #include <linux/user.h> #include <linux/tty.h> -#include <linux/config.h> #include <linux/fs.h> #include <linux/kdev_t.h> #include <linux/major.h> @@ -92,7 +92,7 @@ parent: &iomem_resource, sibling: &sysrom_resource, child: &pdcdata_resource}; extern char _text; /* start of kernel code, defined by linker */ -extern int data_start; +extern int data_start; extern char _edata; /* end of data, begin BSS, defined by linker */ extern char _end; /* end of BSS, defined by linker */ @@ -117,10 +117,6 @@ struct system_cpuinfo_parisc boot_cpu_data; struct cpuinfo_parisc cpu_data[NR_CPUS]; -extern void do_inventory(void); -extern void cache_init(void); -extern struct hp_device * register_module(void *hpa); - static int cpu_driver_callback(struct hp_device *, struct pa_iodc_driver *); static struct pa_iodc_driver cpu_drivers_for[] = { @@ -134,6 +130,9 @@ static long fallback_cpu_hpa[] = { 0xfffa0000L, 0xfffbe000L, 0x0 }; +/* This has to go somewhere in architecture specific code. */ + +int EISA_bus; /* ** PARISC CPU driver - claim "device" and initialize CPU data structures. @@ -143,15 +142,14 @@ ** change once the system has booted. ** ** The callback *should* do per-instance initialization of -** everything including the monarch. Some of the code that's -** in setup.c:start_parisc() should migrate here and start_parisc() -** should "register_driver(cpu_driver_for)" before calling -** do_inventory(). +** everything including the monarch. "Per CPU" init code in +** setup.c:start_parisc() has migrated here and start_parisc() +** will "register_driver(cpu_driver_for)" before calling do_inventory(). ** ** The goal of consolidating CPU initialization into one place is ** to make sure all CPU's get initialized the same way. -** It would be nice if the even the manarch through the exact same code path. -** (up to rendevous at least). +** The code path not shared is how PDC hands control of the CPU to the OS. +** The initialization of OS data structures is the same (done below). */ #undef ASSERT #define ASSERT(expr) \ @@ -160,6 +158,7 @@ panic(#expr); \ } + static int cpu_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri) { @@ -167,6 +166,8 @@ extern int pdc_pat; /* arch/parisc/kernel/inventory.c */ static unsigned long pdc_result[32] __attribute__ ((aligned (8))) = {0,0,0,0}; #endif + unsigned long txn_addr; + unsigned long cpuid; struct cpuinfo_parisc *p; #ifndef CONFIG_SMP @@ -176,16 +177,6 @@ } #endif - p = &cpu_data[boot_cpu_data.cpu_count]; - boot_cpu_data.cpu_count++; - -/* TODO: Enable FP regs - done early in start_parisc() now */ - - /* initialize counters */ - memset(p, 0, sizeof(struct cpuinfo_parisc)); - - p->hpa = (unsigned long) d->hpa; /* save CPU hpa */ - #ifdef __LP64__ if (pdc_pat) { ulong status; @@ -201,7 +192,7 @@ ASSERT(d->pmod_loc == pa_pdc_cell.mod_location); ASSERT(d->mod_path == pa_pdc_cell.mod_path); - p->txn_addr = pa_pdc_cell.mod[0]; /* id_eid for IO sapic */ + txn_addr = pa_pdc_cell.mod[0]; /* id_eid for IO sapic */ /* get the cpu number */ status = mem_pdc_call( PDC_PAT_CPU, PDC_PAT_CPU_GET_NUMBER, @@ -209,20 +200,46 @@ ASSERT(PDC_RET_OK == status); - p->cpuid = pdc_result[0]; - + if(pdc_result[0] >= NR_CPUS) { + printk(KERN_WARNING "IGNORING CPU at 0x%p," + " cpu_slot_id > NR_CPUS" + " (%ld > %d)\n", + d->hpa, pdc_result[0], NR_CPUS); + /* Ignore CPU since it will only crash */ + boot_cpu_data.cpu_count--; + return(1); + } else { + cpuid = pdc_result[0]; + } } else #endif { - p->txn_addr = (unsigned long) d->hpa; /* for normal parisc */ + txn_addr = (unsigned long) d->hpa; /* for normal parisc */ /* logical CPU ID and update global counter */ - p->cpuid = boot_cpu_data.cpu_count - 1; + cpuid = boot_cpu_data.cpu_count; } + p = &cpu_data[cpuid]; + boot_cpu_data.cpu_count++; + + /* initialize counters */ + memset(p, 0, sizeof(struct cpuinfo_parisc)); + + p->dev = d; /* Save hp_device ref in case we want PDC data */ + p->hpa = (unsigned long) d->hpa; /* save CPU hpa */ + p->cpuid = cpuid; /* save CPU hpa */ + p->txn_addr = txn_addr; /* save CPU hpa */ + + /* + ** CONFIG_SMP: init_smp_config() will attempt to get CPU's into + ** OS control. RENDEZVOUS is the default state - see mem_set above. + ** p->state = STATE_RENDEZVOUS; + */ + /* ** itimer and ipi IRQ handlers are statically initialized in - ** arch/parisc/kernel/irq.c + ** arch/parisc/kernel/irq.c. ie Don't need to register them. */ p->region = irq_region[IRQ_FROM_REGION(CPU_IRQ_REGION)]; @@ -230,41 +247,32 @@ } -void __xchg_called_with_bad_pointer(void) -{ - printk(KERN_EMERG "xchg() called with bad pointer !\n"); -} - - /* Some versions of IODC don't list the CPU, and since we don't walk * the bus yet, we have to probe for processors at well known hpa - * addresses. + * addresses. */ void __init register_fallback_cpu (void) { struct hp_device *d = NULL; int i = 0; - -#ifdef CONFIG_SMP -#error "Revisit CPU fallback addresses for SMP (Assuming bus walk hasn't been implemented)" -#endif + printk ("No CPUs reported by firmware - probing...\n"); - + while (fallback_cpu_hpa[i]) { - - d = register_module ((void *) fallback_cpu_hpa[i]); - - if (d > 0) { + + d = alloc_pa_dev(fallback_cpu_hpa[i]); + + if (d && (HPHW_NPROC == d->hw_type)) { printk ("Found CPU at %lx\n", fallback_cpu_hpa[i]); - cpu_driver_callback (d, 0); + (void) register_pa_dev(d); return; } - + i++; } - - panic ("No CPUs found. System halted.\n"); + + panic ("Don't know where this CPU lives. System halted.\n"); return; } @@ -289,7 +297,7 @@ if(pdc_model_cpuid(&boot_cpu_data.pdc.cpuid)==0) printk("cpuid %08lx\n", boot_cpu_data.pdc.cpuid.cpuid); - + printk("CPUID vers %ld rev %ld\n", (boot_cpu_data.pdc.cpuid.cpuid >> 5) & 127, boot_cpu_data.pdc.cpuid.cpuid & 31); @@ -300,7 +308,7 @@ boot_cpu_data.model_name = parisc_getHWdescription(HPHW_NPROC, boot_cpu_data.pdc.model.hversion>>4, boot_cpu_data.pdc.model.sversion>>8); - + boot_cpu_data.hversion = boot_cpu_data.pdc.model.hversion; boot_cpu_data.sversion = boot_cpu_data.pdc.model.sversion; @@ -312,71 +320,71 @@ } -#ifdef __LP64__ -#define COMMAND_GLOBAL 0xfffffffffffe0030UL -#else -#define COMMAND_GLOBAL 0xfffe0030 -#endif - -#define CMD_RESET 5 /* reset any module */ - /* -** The Wright Brothers and Gecko systems have a H/W problem -** (Lasi...'nuf said) may cause a broadcast reset to lockup -** the system. An HVERSION dependent PDC call was developed -** to perform a "safe", platform specific broadcast reset instead -** of kludging up all the code. +** Set width/Enable FP coprocessor +** +** REVISIT: this could be done in the "code 22" trap handler. +** (frowands idea - that way we know which processes need FP +** registers saved on the interrupt stack.) ** -** Older machines which do not implement PDC_BROADCAST_RESET will -** return (with an error) and the regular broadcast reset can be -** issued. Obviously, if the PDC does implement PDC_BROADCAST_RESET -** the PDC call will not return (the system will be reset). +** NEWS FLASH: wide kernels need FP coprocessor enabled to handle +** formatted printing of %lx for example (double divides I think) */ -static int -reset_parisc(struct notifier_block *self, unsigned long command, void *ptr) +int +init_per_cpu(int cpuid) { - printk("%s: %s(cmd=%lu)\n", __FILE__, __FUNCTION__, command); + unsigned long pdc_result[32] __attribute__ ((aligned (8))); + unsigned long ccr; + int ret; - switch(command) { - case MACH_RESTART: -#ifdef FASTBOOT_SELFTEST_SUPPORT - /* - ** If user has modified the Firmware Selftest Bitmap, - ** run the tests specified in the bitmap after the - ** system is rebooted w/PDC_DO_RESET. - ** - ** ftc_bitmap = 0x1AUL "Skip destructive memory tests" - ** - ** Using "directed resets" at each processor with the MEM_TOC - ** vector cleared will also avoid running destructive - ** memory self tests. (Not implemented yet) - */ - if (ftc_bitmap) { - mem_pdc_call( PDC_BROADCAST_RESET, - PDC_DO_FIRM_TEST_RESET, PDC_FIRM_TEST_MAGIC, - ftc_bitmap); - } -#endif + /* + ** ret[0] == Functional Coprocessors + ** ret[1] == Coprocessors Present + ** ret[15] == FP test status + ** ret[17] == Revision + ** ret[18] == Model + */ + ret = pdc_coproc_cfg(&pdc_result); + ccr = pdc_result[0]; - /* "Normal" system reset */ - (void) mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_RESET, - 0L, 0L, 0L); + if(ret >= 0 && ccr) { + mtctl(ccr, 10); /* 10 == Coprocessor Control Reg */ - /* Nope...box should reset with just CMD_RESET now */ - gsc_writel(CMD_RESET, COMMAND_GLOBAL); + /* FWIW, FP rev/model is a more accurate way to determine + ** CPU type. CPU rev/model has some ambiguous cases. + */ + cpu_data[cpuid].fp_rev = pdc_result[17]; + cpu_data[cpuid].fp_model = pdc_result[18]; - /* Wait for RESET to lay us to rest. */ - while (1) ; + printk(KERN_INFO "FP[%d] enabled: Rev %ld Model %ld\n", + cpuid, pdc_result[17], pdc_result[18]); - break; + /* + ** store status register to stack (hopefully aligned) + ** and clear the T-bit. + */ + asm volatile ("fstd %fr0,8(%sp)"); + + } else { + printk(KERN_WARNING "WARNING: No FP CoProcessor?!" + " (pdc_result[0] == 0x%lx, expected 0xc0)\n" +#ifdef __LP64__ + "Halting Machine - FP required\n" +#endif + ,ccr); +#ifdef __LP64__ + mdelay(100); /* previous chars get pushed to console */ + panic("FP CoProc not reported"); +#endif } - return NOTIFY_DONE; -} -static struct notifier_block parisc_block = { reset_parisc, NULL, 0 }; + /* FUTURE: Enable Performance Monitor : ccr bit 0x20 */ + return(ret); +} -/* start_parisc() will be called from head.S to setup our new memory_start + +/* start_parisc() will be called from head.S to setup our new memory_start and actually start our kernel ! Memory-Layout is: - Kernel-Image (code+data+BSS) @@ -395,11 +403,9 @@ void __init start_parisc(unsigned arg0, unsigned arg1, unsigned arg2, unsigned arg3) { - register unsigned long ccr; unsigned long memory_start; /* Clear BSS */ - { char *p = &_edata, *q = &_end; @@ -408,43 +414,22 @@ } } - - pdc_console_init(); - + printk("The " #ifdef __LP64__ - printk("The 64-bit Kernel has started...\n"); + "64" #else - printk("The 32-bit Kernel has started...\n"); + "32" #endif + "-bit Kernel has started...\n"); - /* - ** Enable FP coprocessor - ** - ** REVISIT: ccr should be set by PDC_COPROC results to support PA1.0. - ** Hardcoding works for PA1.1 processors. - ** - ** REVISIT: this could be done in the "code 22" trap handler. - ** (frowands idea - that way we know which processes need FP - ** registers saved on the interrupt stack.) - ** - ** NEWS FLASH: wide kernels need FP coprocessor enabled to handle - ** formatted printing of %lx for example (double divides I think) - */ - ccr = 0xc0; - mtctl(ccr, 10); - printk("Enabled FP coprocessor\n"); - -#ifdef __LP64__ - printk( "If this is the LAST MESSAGE YOU SEE, you're probably using\n" - "32-bit millicode by mistake.\n"); -#endif + init_per_cpu(smp_processor_id()); /* Set Modes & Enable FP */ memory_start = (unsigned long) &_end; memory_start = (memory_start + PAGE_SIZE) & PAGE_MASK; printk("Free memory starts at: 0x%lx\n", memory_start); /* Collect stuff passed in from the boot loader */ - printk(KERN_WARNING "%s(0x%x,0x%x,0x%x,0x%x)\n", + printk(KERN_WARNING "%s(0x%x,0x%x,0x%x,0x%x)\n", __FUNCTION__, arg0, arg1, arg2, arg3); /* arg0 is free-mem start, arg1 is ptr to command line */ @@ -472,7 +457,9 @@ collect_boot_cpu_data(); /* initialize the LCD/LED after boot_cpu_data is available ! */ +#ifdef CONFIG_CHASSIS_LCD_LED led_init(); /* LCD/LED initialization */ +#endif do_inventory(); /* probe for hardware */ register_driver(cpu_drivers_for); /* claim all the CPUs */ @@ -480,14 +467,24 @@ if (boot_cpu_data.cpu_count == 0) register_fallback_cpu(); - printk("CPU(s): %d x %s at %d.%06d MHz\n", + printk("CPU(s): %d x %s at %d.%06d MHz\n", boot_cpu_data.cpu_count, boot_cpu_data.cpu_name, - boot_cpu_data.cpu_hz / 1000000, + boot_cpu_data.cpu_hz / 1000000, boot_cpu_data.cpu_hz % 1000000 ); switch (boot_cpu_data.cpu_type) { case pcx: + /* + * We've got way too many dependencies on 1.1 semantics + * to support 1.0 boxes at this point. + */ + printk("PA-RISC Linux currently only supports machines that conform to\n"); + printk("the PA-RISC 1.1 or 2.0 architecture specification.\n"); + for (;;) + ; + break; /* not reached */ + case pcxs: case pcxt: hppa_dma_ops = &pcx_dma_ops; @@ -501,12 +498,15 @@ break; } + /* Turn off space register hashing */ + + disable_sr_hashing(); + #if 1 /* KLUGE! this really belongs in kernel/resource.c! */ iomem_resource.end = ~0UL; #endif sysram_resource.end = mem_max - 1; - notifier_chain_register(&mach_notifier, &parisc_block); start_kernel(); /* now back to arch-generic code... */ } @@ -542,6 +542,8 @@ } #endif + EISA_bus = 0; + cache_init(); paging_init(); @@ -557,8 +559,6 @@ #elif CONFIG_VT #if defined(CONFIG_STI_CONSOLE) conswitchp = &dummy_con; /* we use take_over_console() later ! */ -#elif defined(CONFIG_IODC_CONSOLE) - conswitchp = &prom_con; /* it's currently really "prom_con" */ #elif defined(CONFIG_DUMMY_CONSOLE) conswitchp = &dummy_con; #endif @@ -578,18 +578,21 @@ for(n=0; n<boot_cpu_data.cpu_count; n++) { #ifdef CONFIG_SMP - if (!(cpu_online_map & (1<<n))) + if (0 == cpu_data[n].hpa) continue; +#ifdef ENTRY_SYS_CPUS +#error iCOD support wants to show CPU state here +#endif #endif p += sprintf(p, "processor\t: %d\n" "cpu family\t: PA-RISC %s\n", n, boot_cpu_data.family_name); p += sprintf(p, "cpu\t\t: %s\n", boot_cpu_data.cpu_name ); - + /* cpu MHz */ p += sprintf(p, "cpu MHz\t\t: %d.%06d\n", - boot_cpu_data.cpu_hz / 1000000, + boot_cpu_data.cpu_hz / 1000000, boot_cpu_data.cpu_hz % 1000000 ); p += sprintf(p, "model\t\t: %s\n" @@ -605,8 +608,8 @@ p += get_cache_info(p); /* print cachesize info ? */ p += sprintf(p, "bogomips\t: %lu.%02lu\n", - (loops_per_sec+2500)/500000, - ((loops_per_sec+2500)/5000) % 100); + loops_per_jiffy / (500000 / HZ), + (loops_per_jiffy / (5000 / HZ)) % 100); } return p - buffer; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/signal.c linux.ac/arch/parisc/kernel/signal.c --- linux.vanilla/arch/parisc/kernel/signal.c Wed Dec 6 19:46:39 2000 +++ linux.ac/arch/parisc/kernel/signal.c Tue Apr 3 17:54:34 2001 @@ -139,7 +139,7 @@ #define INSN_LDI_R25_1 0x34190002 /* ldi 1,%r25 (in_syscall=1) */ #define INSN_LDI_R20 0x3414015a /* ldi __NR_rt_sigreturn,%r20 */ #define INSN_BLE_SR2_R0 0xe4008200 /* be,l 0x100(%sr2,%r0),%sr0,%r31 */ -#define INSN_NOP 0x80000240 /* nop */ +#define INSN_NOP 0x08000240 /* nop */ /* For debugging */ #define INSN_DIE_HORRIBLY 0x68000ccc /* stw %r0,0x666(%sr0,%r0) */ @@ -226,7 +226,7 @@ give_sigsegv: #if DEBUG_SIG - printk("fuckup in sys_rt_sigreturn, sending SIGSEGV\n"); + printk("sys_rt_sigreturn sending SIGSEGV\n"); #endif si.si_signo = SIGSEGV; si.si_errno = 0; @@ -413,7 +413,7 @@ give_sigsegv: #if DEBUG_SIG - printk("fuckup in setup_rt_frame, sending SIGSEGV\n"); + printk("setup_rt_frame sending SIGSEGV\n"); #endif if (sig == SIGSEGV) ka->sa.sa_handler = SIG_DFL; @@ -539,7 +539,7 @@ #if DEBUG_SIG printk("sa_handler is %lx\n", ka->sa.sa_handler); #endif - if ((unsigned long) ka->sa.sa_handler == (unsigned long) SIG_IGN) { + if (ka->sa.sa_handler == SIG_IGN) { if (signr != SIGCHLD) continue; while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) @@ -547,7 +547,7 @@ continue; } - if ((unsigned long) ka->sa.sa_handler == (unsigned long) SIG_DFL) { + if (ka->sa.sa_handler == SIG_DFL) { int exit_code = signr; /* Init gets no signals it doesn't want. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/smp.c linux.ac/arch/parisc/kernel/smp.c --- linux.vanilla/arch/parisc/kernel/smp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/parisc/kernel/smp.c Tue Apr 3 17:54:34 2001 @@ -0,0 +1,885 @@ +/* +** SMP Support +** +** Copyright (C) 1999 Walt Drummond <drummond@valinux.com> +** Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com> +** Copyright (C) 2001 Grant Grundler <grundler@puffin.external.hp.com> +** +** Lots of stuff stolen from arch/alpha/kernel/smp.c +** ...and then parisc stole from arch/ia64/kernel/smp.c. Thanks David! :^) +** +** Thanks to John Curry and Ullas Ponnadi. I learned alot from their work. +** -grant (1/12/2001) +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +*/ +#define __KERNEL_SYSCALLS__ +#undef ENTRY_SYS_CPUS /* syscall support for iCOD-like functionality */ + +#include <linux/config.h> + +#include <linux/types.h> +#include <linux/spinlock.h> +#include <linux/malloc.h> + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/smp.h> +#include <linux/kernel_stat.h> +#include <linux/mm.h> +#include <linux/delay.h> + +#include <asm/system.h> +#include <asm/atomic.h> +#include <asm/bitops.h> +#include <asm/current.h> +#include <asm/delay.h> +#include <asm/pgalloc.h> /* for flush_tlb_all() proto/macro */ + +#include <asm/io.h> +#include <asm/irq.h> /* for CPU_IRQ_REGION and friends */ +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/processor.h> +#include <asm/ptrace.h> +#include <asm/unistd.h> + +/* Enable debug msgs for now */ +#define kDEBUG 100 +#define STATIC + +extern void _start(void); + +spinlock_t smp_lock = SPIN_LOCK_UNLOCKED; + +volatile struct task_struct *smp_init_current_idle_task; +spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; + +volatile int __cpu_number_map[NR_CPUS] = { -1, }; /* cpu # -> Logical cpu ID*/ +volatile int __cpu_logical_map[NR_CPUS] = { -1, }; /* logical ID -> cup # */ + +static volatile int smp_commenced = 0; /* Set when the idlers are all forked */ +static volatile int cpu_now_booting = 0; /* track which CPU is booting */ +static volatile unsigned long cpu_callin_map = 0; /* Bitmap of online CPUs */ +#define IS_LOGGED_IN(cpunum) (test_bit(cpunum, &cpu_callin_map)) + +int smp_num_cpus = 1; +int smp_threads_ready = 0; +static int max_cpus = -1; /* Command line */ +static unsigned long ipi_op[NR_CPUS]; +struct smp_call_struct { + void (*func) (void *info); + void *info; + long wait; + atomic_t unstarted_count; + atomic_t unfinished_count; +}; +static volatile struct smp_call_struct *smp_call_function_data; + +enum ipi_message_type { + IPI_RESCHEDULE, + IPI_CALL_FUNC, + IPI_CPU_START, + IPI_CPU_STOP, + IPI_CPU_TEST +}; + + +/********** SMP inter processor interrupt and communication routines */ + +#if 0 +/* XXX REVISIT Ignore for now. Need this to register IPI handler +** once we have perCPU ExtIntr switch tables. +*/ +static void +ipi_init(int cpuid) +{ + + /* If CPU is present ... */ +#ifdef ENTRY_SYS_CPUS + /* *and* running (not stopped) ... */ +#error iCOD support wants state checked here. +#endif + if(IS_LOGGED_IN(cpuid) ) + { + switch_to_idle_task(current); + } + + return; +} +#endif + + +/* +** Yoink this CPU from the runnable list... +** +*/ +static void +halt_processor(void) +{ +#ifdef ENTRY_SYS_CPUS +#error halt_processor() needs rework +/* +** o migrate I/O interrupts off this CPU. +** o leave IPI enabled - __cli() will disable IPI. +** o leave CPU in online map - just change the state +*/ + cpu_data[this_cpu].state = STATE_STOPPED; + mark_bh(IPI_BH); +#else + /* REVISIT : redirect I/O Interrupts to another CPU? */ + /* REVISIT : does PM *know* this CPU isn't available? */ + clear_bit(smp_processor_id(), &cpu_callin_map); + __cli(); + for (;;) + ; +#endif +} + + +void +ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + int this_cpu = smp_processor_id(); + unsigned long *pending_ipis = &ipi_op[this_cpu]; + unsigned long ops; + + /* Count this now; we may make a call that never returns. */ + cpu_data[this_cpu].ipi_count++; + + mb(); /* Order interrupt and bit testing. */ + while ((ops = xchg(pending_ipis, 0)) != 0) { + mb(); /* Order bit clearing and data access. */ + do { + unsigned long which; + +printk("ipi_interrupt(%d,...) on %d ops = 0x%lx ", irq, this_cpu, ops); + + which = ffz(~ops); + ops &= ~(1 << which); + +printk("(which = %ld)\n", which); + + switch (which) { + case IPI_RESCHEDULE: +#if (kDEBUG>=100) + printk("CPU:%d got reschedule interrupt\n",this_cpu); +#endif /* kDEBUG */ + /* + * Reschedule callback. Everything to be done is done by the + * interrupt return path. + */ + break; + + case IPI_CALL_FUNC: + { + volatile struct smp_call_struct *data; + void (*func)(void *info); + void *info; + int wait; + + data = smp_call_function_data; + func = data->func; + info = data->info; + wait = data->wait; + + mb(); + atomic_dec (&data->unstarted_count); + + /* At this point, *data may be gone unless wait is true. */ + (*func)(info); + + /* Notify the sending CPU that the task is done. */ + mb(); + if (wait) + atomic_dec (&data->unfinished_count); + } + break; + + case IPI_CPU_START: +#ifdef ENTRY_SYS_CPUS + cpu_data[this_cpu].state = STATE_RUNNING; +#endif + break; + + case IPI_CPU_STOP: +#ifdef ENTRY_SYS_CPUS +#else + halt_processor(); +#endif + break; + + case IPI_CPU_TEST: +#if (kDEBUG>=100) + printk("CPU:%d is alive\n",this_cpu); +#endif /* kDEBUG */ + break; + + default: + printk(KERN_CRIT "Unknown IPI num on CPU %d: %lu\n", this_cpu, which); + return; + } /* Switch */ + } while (ops); + + mb(); /* Order data access and bit testing. */ + } + return; +} + + +static inline void +ipi_send(int cpu, enum ipi_message_type op) +{ + set_bit(1<< op, &(cpu_data[cpu].pending_ipi)); + + /* + ** Just in case it's directed at ourselves, we want to make + ** sure the interrupt doesn't get delivered until we are out + ** of real mode again. I think it's cheaper to disable IRQ's + ** briefly than test for it. + */ + local_irq_disable(); + gsc_writel(IRQ_OFFSET(IPI_IRQ), cpu_data[cpu].hpa); + local_irq_enable(); +} + + +static inline void +send_IPI_single(int dest_cpu, enum ipi_message_type op) +{ + if (dest_cpu == NO_PROC_ID) + return; + + ipi_send(dest_cpu, op); +} + +static inline void +send_IPI_allbutself(enum ipi_message_type op) +{ + int i; + + for (i = 0; i < smp_num_cpus; i++) { + int cpu_id = __cpu_logical_map[i]; + if (cpu_id != smp_processor_id()) + send_IPI_single(cpu_id, op); + } +} + +static inline void +send_IPI_all(enum ipi_message_type op) +{ + int i; + + for (i = 0; i < smp_num_cpus; i++) + send_IPI_single(__cpu_logical_map[i], op); +} + +static inline void +send_IPI_self(enum ipi_message_type op) +{ + send_IPI_single(smp_processor_id(), op); +} + +inline void +smp_send_stop(void) { send_IPI_allbutself(IPI_CPU_STOP); } + +static inline void +smp_send_start(void) { send_IPI_allbutself(IPI_CPU_START); } + +void +smp_send_reschedule(int cpu) { send_IPI_single(cpu, IPI_RESCHEDULE); } + + +/* + * Run a function on all other CPUs. + * <func> The function to run. This must be fast and non-blocking. + * <info> An arbitrary pointer to pass to the function. + * <retry> If true, keep retrying until ready. + * <wait> If true, wait until function has completed on other CPUs. + * [RETURNS] 0 on success, else a negative status code. + * + * Does not return until remote CPUs are nearly ready to execute <func> + * or are or have executed. + */ + +int +smp_call_function (void (*func) (void *info), void *info, int retry, int wait) +{ + struct smp_call_struct data; + long timeout; + static spinlock_t lock = SPIN_LOCK_UNLOCKED; + + data.func = func; + data.info = info; + data.wait = wait; + atomic_set(&data.unstarted_count, smp_num_cpus - 1); + atomic_set(&data.unfinished_count, smp_num_cpus - 1); + + if (retry) { + while (1) { + if (smp_call_function_data) { + schedule (); /* Give a mate a go */ + continue; + } + spin_lock (&lock); + if (smp_call_function_data) { + spin_unlock (&lock); /* Bad luck */ + continue; + } + /* Mine, all mine! */ + break; + } + } + else { + spin_lock (&lock); + if (smp_call_function_data) { + spin_unlock (&lock); + return -EBUSY; + } + } + + smp_call_function_data = &data; + spin_unlock (&lock); + + /* Send a message to all other CPUs and wait for them to respond */ + send_IPI_allbutself(IPI_CALL_FUNC); + + /* Wait for response */ + timeout = jiffies + HZ; + while ( (atomic_read (&data.unstarted_count) > 0) && + time_before (jiffies, timeout) ) + barrier (); + + if (atomic_read (&data.unstarted_count) > 0) { + smp_call_function_data = NULL; + return -ETIMEDOUT; + } + + while (wait && atomic_read (&data.unfinished_count) > 0) + barrier (); + + smp_call_function_data = NULL; + return 0; +} + + + +/* + * Setup routine for controlling SMP activation + * + * Command-line option of "nosmp" or "maxcpus=0" will disable SMP + * activation entirely (the MPS table probe still happens, though). + * + * Command-line option of "maxcpus=<NUM>", where <NUM> is an integer + * greater than 0, limits the maximum number of CPUs activated in + * SMP mode to <NUM>. + */ + +static int __init nosmp(char *str) +{ + max_cpus = 0; + return 1; +} + +__setup("nosmp", nosmp); + +static int __init maxcpus(char *str) +{ + get_option(&str, &max_cpus); + return 1; +} + +__setup("maxcpus=", maxcpus); + + +void +proxy_flush_tlb_all(void) +{ + flush_tlb_all(); +} + +/* + * Flush all other CPU's tlb and then mine. Do this with smp_call_function() + * as we want to ensure all TLB's flushed before proceeding. + */ +void +smp_flush_tlb_all(void) +{ + smp_call_function((void (*)(void *))proxy_flush_tlb_all, NULL, 1, 1); + flush_tlb_all(); +} + + +/* + * Ideally sets up per-cpu profiling hooks. Doesn't do much now... + */ +static inline void __init +smp_setup_percpu_timer(int cpunum) +{ + cpu_data[cpunum].prof_counter = 1; + cpu_data[cpunum].prof_multiplier = 1; +} + + +void +smp_do_timer(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + struct cpuinfo_parisc *data = &cpu_data[cpu]; + + if (!--data->prof_counter) { + irq_enter(cpu, TIMER_IRQ); + update_process_times(user_mode(regs)); + data->prof_counter = data->prof_multiplier; + irq_exit(cpu, TIMER_IRQ); + } +} + + +/* + * Called by secondaries to update state and initialize CPU registers. + */ +STATIC void __init +smp_cpu_init(int cpunum) +{ + extern int init_per_cpu(int); /* arch/parisc/kernel/setup.c */ + extern void init_IRQ(void); /* arch/parisc/kernel/irq.c */ + + /* Set modes and Enable floating point coprocessor */ + (void) init_per_cpu(cpunum); + +#if 0 + flush_tlb_all(); + flush_cache_all(); +#endif + mb(); + + /* Well, support 2.4 linux scheme as well. */ + if (test_and_set_bit(cpunum, (unsigned long *) (&cpu_callin_map))) + { + extern void machine_halt(void); /* arch/parisc.../process.c */ + + printk("CPU#%d already initialized!\n", cpunum); + machine_halt(); + } + + init_IRQ(); /* make sure no IRQ's are enabled or pending */ +} + + +/* + * Slaves start using C here. Indirectly called from smp_slave_stext. + * Do what start_parisc() and main() do for boot strap processor (aka monarch) + */ +void __init smp_callin(unsigned long pdc_entry_point, long hpa) +{ + extern void cpu_idle(void); /* arch/parisc/kernel/process.c */ + int slave_id = cpu_now_booting; + + smp_cpu_init(slave_id); + + +printk("SMP: CPU:%d CR15 %lx CR22 %lx CR23 %lx\n", slave_id, + mfctl(15), mfctl(22), mfctl(23)); + + /* Slave's wait here until Big Poppa daddy say "jump" */ + mb(); /* PARANOID */ + while (!smp_commenced) ; + mb(); /* PARANOID */ + + local_irq_enable(); /* Interrupts have been off until now */ + +printk("SMP: CPU:%d CR15 %lx CR22 %lx CR23 %lx\n", slave_id, + mfctl(15), mfctl(22), mfctl(23)); + +mdelay(300); +/* spin_lock (&smp_lock); */ + +printk("SMP: CPU:%d calling cpu_idle()\n", slave_id); +mdelay(300); +/* spin_unlock (&smp_lock); */ + cpu_idle(); /* Wait for timer to schedule some work */ + /* NOTREACHED */ +panic("smp_callin() AAAAaaaaahhhh....\n"); +} + + + + +/* + * Create the idle task for a new Slave CPU. DO NOT use kernel_thread() + * because that could end up calling schedule(). If it did, the new idle + * task could get scheduled before we had a chance to remove it from the + * run-queue... + */ +#if 0 +STATIC struct task_struct *fork_by_hand(void) +{ + struct task_struct *p; + + /* Create the stack and task structure for this idle process */ + if(0 != (p = (struct task_struct *)alloc_task_struct())) + { + *p = init_task; + p->need_resched = 0; + p->thread.pg_tables = 0; /* REVISIT */ + return p; + } + return(NULL); +} +#else +STATIC int fork_by_hand(void) +{ + struct pt_regs regs; + + /* + * don't care about the regs settings since + * we'll never reschedule the forked task. + */ + return do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0); +} +#endif + + +/* + * Bring one cpu online. + */ +STATIC int smp_boot_one_cpu(int cpuid, int cpunum) +{ + struct task_struct *idle; + long timeout; + + /* + * Create an idle task for this CPU. Note the address wed* give + * to kernel_thread is irrelevant -- it's going to start + * where OS_BOOT_RENDEVZ vector in SAL says to start. But + * this gets all the other task-y sort of data structures set + * up like we wish. We need to pull the just created idle task + * off the run queue and stuff it into the init_tasks[] array. + * Sheesh . . . + */ + + if (fork_by_hand() < 0) + panic("SMP: fork failed for CPU:%d", cpuid); + + idle = init_task.prev_task; + if (!idle) + panic("SMP: No idle process for CPU:%d", cpuid); + +printk("sboc: task 0x%p for %d/%d\n", idle, cpuid, cpunum); + + __cpu_number_map[cpuid] = cpunum; + __cpu_logical_map[cpunum] = cpuid; + + init_tasks[cpunum] = idle; + del_from_runqueue(idle); + unhash_process(idle); + + idle->processor = cpunum; + idle->has_cpu = 1; /* Schedule the first task manually */ + +printk("sboc: CPU %d state 0x%lx flags 0x%lx\n", + cpunum, idle->state, idle->flags); + + /* Let _start know what logical CPU we're booting + ** (offset into init_tasks[],cpu_data[]) + */ + cpu_now_booting = cpunum; + + /* + ** boot strap code needs to know the task address since + ** it also contains the process stack. + */ + smp_init_current_idle_task = idle ; + mb(); + + /* + ** This gets PDC to release the CPU from a very tight loop. + ** See MEM_RENDEZ comments in head.S. + */ + gsc_writel(IRQ_OFFSET(TIMER_IRQ), cpu_data[cpunum].hpa); + mb(); + + /* + * OK, wait a bit for that CPU to finish staggering about. + * Slave will set a bit when it reaches smp_cpu_init() and then + * wait for smp_commenced to be 1. + * Once we see the bit change, we can move on. + */ + for (timeout = 0; timeout < 10000; timeout++) { + if(IS_LOGGED_IN(cpunum)) { + /* Which implies Slave has started up */ + cpu_now_booting = 0; + smp_init_current_idle_task = NULL; + goto alive ; + } + udelay(100); + barrier(); + } + + __cpu_logical_map[cpunum] = NO_PROC_ID; + __cpu_number_map[cpuid] = NO_PROC_ID; + init_tasks[cpunum] = NULL; + free_task_struct(idle); + + printk("SMP: CPU:%d is stuck.\n", cpuid); + return -1; + +alive: + /* Remember the Slave data */ +#if (kDEBUG>=100) + printk("SMP: CPU:%d (num %d) came alive after %ld _us\n", + cpuid, cpunum, timeout * 100); +#endif /* kDEBUG */ +#ifdef ENTRY_SYS_CPUS + cpu_data[cpunum].state = STATE_RUNNING; +#endif + return 0; +} + + + + +/* +** inventory.c:do_inventory() has already 'discovered' the additional CPU's. +** We are ready to wrest them from PDC's control now. +** Called by smp_init bring all the secondaries online and hold them. +** +** o Setup of the IPI irq handler is done in irq.c. +** o MEM_RENDEZ is initialzed in head.S:stext() +** +*/ +void __init smp_boot_cpus(void) +{ + int i, cpu_count = 1; + unsigned long bogosum = loops_per_jiffy; /* Count Monarch */ + + /* REVISIT - assumes first CPU reported by PAT PDC is BSP */ + int bootstrap_processor=cpu_data[0].cpuid; /* CPU ID of BSP */ + + /* Take care of some initial bookkeeping. */ + for(i=0;i<NR_CPUS;i++) { + __cpu_number_map[i] = NO_PROC_ID; + __cpu_logical_map[i] = NO_PROC_ID; + } + + /* Setup BSP mappings */ + __cpu_number_map[bootstrap_processor] = 0; + __cpu_logical_map[0] = bootstrap_processor; + printk("SMP: bootstrap CPU ID is %d\n",bootstrap_processor); + init_task.processor = 0; + current->processor = 0; /*These are set already*/ + cpu_callin_map = 1; /* Mark Boostrap processor as present */ + +#ifdef ENTRY_SYS_CPUS + cpu_data[0].state = STATE_RUNNING; +#endif + + init_idle(); + + /* Nothing to do when told not to. */ + if (max_cpus == 0) { + printk(KERN_INFO "SMP mode deactivated.\n"); + return; + } + + if (max_cpus != -1) + printk("Limiting CPUs to %d\n", max_cpus); + + /* We found more than one CPU.... */ + if (boot_cpu_data.cpu_count > 1) { + + for (i = 0; i < NR_CPUS; i++) { + if (cpu_data[i].cpuid == NO_PROC_ID || + cpu_data[i].cpuid == bootstrap_processor) + continue; + + if (smp_boot_one_cpu(cpu_data[i].cpuid, cpu_count) < 0) + continue; + + bogosum += loops_per_jiffy; + cpu_count++; /* Count good CPUs only... */ + + /* Bail when we've started as many CPUS as told to */ + if (cpu_count == max_cpus) + break; + } + } + if (cpu_count == 1) { + printk("SMP: Bootstrap processor only.\n"); + } + + printk(KERN_INFO "SMP: Total %d of %d processors activated " + "(%lu.%02lu BogoMIPS noticed).\n", + cpu_count, boot_cpu_data.cpu_count, (bogosum + 25) / 5000, + ((bogosum + 25) / 50) % 100); + + smp_num_cpus = cpu_count; +#if 0 + ipi_init(); +#endif + return; +} + +/* + * Called from main.c by each Monarch Processor. + * After this, any CPU can schedule any task. + */ +void smp_commence(void) +{ +printk("SMP: BSP before\n"); +mdelay(1000); + + smp_commenced = 1; + mb(); + +mdelay(10000); +printk("SMP: BSP proceeding\n"); +mdelay(300); + return; +} + +#ifdef ENTRY_SYS_CPUS +/* Code goes along with: +** entry.s: ENTRY_NAME(sys_cpus) / * 215, for cpu stat * / +*/ +int sys_cpus(int argc, char **argv) +{ + int i,j=0; + extern int current_pid(int cpu); + + if( argc > 2 ) { + printk("sys_cpus:Only one argument supported\n"); + return (-1); + } + if ( argc == 1 ){ + +#ifdef DUMP_MORE_STATE + for(i=0;i<NR_CPUS;i++){ + int cpus_per_line = 4; + if(IS_LOGGED_IN(i)){ + if(j++ % cpus_per_line) printk(" %3d",i); + else printk("\n %3d",i); + } + } + printk("\n"); +#else + printk("\n 0\n"); +#endif + } + else if((argc==2) && !(strcmp(argv[1],"-l"))){ + printk("\nCPUSTATE TASK CPUNUM CPUID HARDCPU(HPA)\n"); +#ifdef DUMP_MORE_STATE + for(i=0;i<NR_CPUS;i++){ + if(!IS_LOGGED_IN(i)) continue; + if(cpu_data[i].cpuid!=NO_PROC_ID){ + switch(cpu_data[i].state){ + case STATE_RENDEZVOUS:printk("RENDEZVS ");break; + case STATE_RUNNING: printk((current_pid(i)!=0) + ? "RUNNING " : "IDLING "); + break; + case STATE_STOPPED: printk("STOPPED ");break; + case STATE_HALTED: printk("HALTED ");break; + default: printk("%08x?", cpu_data[i].state); + break; + } + if(IS_LOGGED_IN(i)){ + printk(" %4d",current_pid(i)); + } + printk(" %6d",cpu_number_map(i)); + printk(" %5d",i); + printk(" 0x%lx\n",cpu_data[i].hpa); + } + } +#else + printk("\n%s %4d 0 0 --------",(current->pid)?"RUNNING ": + "IDLING ",current->pid); +#endif + } + else if((argc==2) && !(strcmp(argv[1],"-s"))){ +#ifdef DUMP_MORE_STATE + printk("\nCPUSTATE CPUID\n"); + for(i=0;i<NR_CPUS;i++){ + if(!IS_LOGGED_IN(i)) continue; + if(cpu_data[i].cpuid!=NO_PROC_ID){ + switch(cpu_data[i].state){ + case STATE_RENDEZVOUS:printk("RENDEZVS");break; + case STATE_RUNNING: printk((current_pid(i)!=0) + ? "RUNNING " : "IDLING"); + break; + case STATE_STOPPED: printk("STOPPED ");break; + case STATE_HALTED: printk("HALTED ");break; + default: + } + printk(" %5d\n",i); + } + } +#else + printk("\n%s CPU0",(current->pid==0)?"RUNNING ":"IDLING "); +#endif + } + else { + printk("sys_cpus:Unknown request\n"); + return (-1); + } + return (0); +} +#endif /* ENTRY_SYS_CPUS */ + + +int sys_get_cpu(void) +{ + return(smp_processor_id()); +} + + +int sys_ipi_send(int cpu,int op) +{ + if(cpu!=NO_PROC_ID){ + if(cpu<0) goto sys_ipi_error; + if(cpu<0 || cpu > NR_CPUS) goto sys_ipi_error; + if(__cpu_number_map[cpu]==NO_PROC_ID) goto sys_ipi_error; + } + switch(op){ + case IPI_CALL_FUNC: + if(cpu!=NO_PROC_ID){ + printk("Note:Ignoring cpuid:%d and calling function on all CPUS\n",cpu); + } + smp_flush_tlb_all(); + break; + case IPI_RESCHEDULE: + case IPI_CPU_TEST: + case IPI_CPU_START: + case IPI_CPU_STOP: + default: + if(cpu!=NO_PROC_ID){ + send_IPI_single(cpu,op);break; + } + else{ + if(op == IPI_CPU_STOP){ /* we don't want to down this cpu also */ + send_IPI_allbutself(op); + } + else{ + send_IPI_all(op); + } + } + break; + } + return (0); +sys_ipi_error: + printk("CPU:%d cann't send IPI to CPU:%d\n",smp_processor_id(),cpu); + return (-1); +} + +#ifdef CONFIG_PROC_FS +int __init +setup_profiling_timer(unsigned int multiplier) +{ + return -EINVAL; +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/superio.c linux.ac/arch/parisc/kernel/superio.c --- linux.vanilla/arch/parisc/kernel/superio.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/parisc/kernel/superio.c Tue Apr 3 17:54:34 2001 @@ -0,0 +1,394 @@ +/* National Semiconductor NS87560UBD Super I/O controller used in + * HP [BCJ]x000 workstations. + * + * This chip is a horrid piece of engineering, and National + * denies any knowledge of its existence. Thus no datasheet is + * available off www.national.com. + * + * (C) Copyright 2000 Linuxcare, Inc. + * (C) Copyright 2000 Linuxcare Canada, Inc. + * (C) Copyright 2000 Martin K. Petersen <mkp@linuxcare.com> + * (C) Copyright 2000 Alex deVries <alex@linuxcare.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. + * + * The initial version of this is by Martin Peterson. Alex deVries + * has spent a bit of time trying to coax it into working. + */ + + +/* NOTES: + * + * The following is what iostat reports on my J5000: + * + * 10/0/14/0 ext_bus IDE + * 10/0/14/0.0 target + * 10/0/14/0.0.0 disk TEAC CD-532E-B + * 10/0/14/0.7 target + * 10/0/14/0.7.0 ctl Initiator + * 10/0/14/1 ba PCI Core I/O Adapter + * 10/0/14/1/1 tty Built-in RS-232C + * 10/0/14/1/2 tty Built-in RS-232C + * 10/0/14/1/3 ext_bus Built-in Parallel Interface + * 10/0/14/2 usb Built-in USB Interface + * 10/0/14/2.1 usbhub USB Root Hub + * + * It appears IDE is on function 0, ttyS0, ttyS1 and the parallel port + * are on function 1, while USB is on function 2. + * + * PCI bus walk on my J5000: + * + * PCI: 00:60 [1011/0019] DEC 21142/21143 + * PCI: 00:68 [11d4/1889] Analog Devices 1889 Audio DAC + * PCI: 00:70 [100b/0002] National Semiconductor IDE + * PCI: 00:71 [100b/000e] National Semiconductor Legacy I/O + * PCI: 00:72 [100b/0012] National Semiconductor USB + * PCI: 00:78 [1000/000b] Symbios Logic 53c896 + * PCI: 00:79 [1000/000b] Symbios Logic 53c896 + * [...] + * + * It appears function 0 is identical to a PC87415 IDE controller + * cell. + * + * We must be incredibly careful during initialization. Since all + * interrupts are routed through function 1 (which is not allowed by + * the PCI spec), we need to program the PICs on the legacy I/O port + * *before* we attempt to set up IDE and USB. @#$!& + * + * According to HP, devices are only enabled by firmware if they have + * a physical device connected. + * + * Configuration register bits: + * 0x5A: FDC, SP1, IDE1, SP2, IDE2, PAR, Reserved, P92 + * 0x5B: RTC, 8259, 8254, DMA1, DMA2, KBC, P61, APM + * + */ + +#include <linux/config.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/timex.h> +#include <linux/malloc.h> +#include <linux/random.h> +#include <linux/serial.h> +#include <linux/pci.h> +#include <asm/serial.h> +#include <asm/io.h> +#include <asm/hardware.h> +#include <asm/gsc.h> + + +/* Local prototypes */ +__init void superio_probe (void); +static void superio_init (struct pci_dev *pdev,int interrupt); + +static int superio_serial_init (void); + + +/* Offsets to configuration and base address registers */ +#define IC_PIC1 0x20 /* PCI I/O address of master 8259 */ +#define IC_PIC2 0xA0 /* PCI I/O address of slave */ +#define SIO_CR 0x5A /* Configuration Register */ +#define SIO_FDCBAR 0x90 /* Floppy Disk Controller BAR */ +#define SIO_SP1BAR 0x94 /* Serial 1 BAR */ +#define SIO_SP2BAR 0x98 /* Serial 2 BAR */ +#define SIO_PPBAR 0x9C /* Parallel BAR */ + +/* Interrupt triggers and routing */ +#define TRIGGER_1 0x67 /* Edge/level trigger register 1 */ +#define TRIGGER_2 0x68 /* Edge/level trigger register 2 */ +#define IR_SER 0x69 /* Serial 1 [0:3] and Serial 2 [4:7] */ +#define IR_PFD 0x6a /* Parallel [0:3] and Floppy [4:7] */ +#define IR_IDE 0x6b /* IDE1 [0:3] and IDE2 [4:7] */ +#define IR_USB 0x70 /* USB [4:7] */ +#define IR_LOW 0x69 /* Lowest interrupt routing reg */ +#define IR_HIGH 0x71 /* Highest interrupt routing reg */ + +/* 8259 operational control words */ +#define OCW2_EOI 0x20 /* Non-specific EOI */ +#define OCW2_SEOI 0x60 /* Specific EOI */ +#define OCW3_IIR 0x0A /* Read request register */ +#define OCW3_ISR 0x0B /* Read service register */ +#define OCW3_POLL 0x0C /* Poll the PIC for an interrupt vector */ + +/* Interrupt lines. Only PIC1 is used */ +#define USB_IRQ 1 /* USB */ +#define SP1_IRQ 3 /* Serial port 1 */ +#define SP2_IRQ 4 /* Serial port 2 */ +#define PAR_IRQ 5 /* Parallel port */ +#define FDC_IRQ 6 /* Floppy controller */ +#define IDE_IRQ 7 /* IDE (pri+sec) */ + + +static struct superio_device { + u16 fdc_base; + u16 sp1_base; + u16 sp2_base; + u16 pp_base; +} sio; + + +/* There can be only one... */ +static int found = 0; + +static void superio_interrupt(int irq, void *devp, struct pt_regs *regs); + +/* Probe for a Super I/O device and print info */ +void __init +superio_probe (void) +{ + struct pci_dev *pdev = NULL; + u8 hdr_type, interrupt; + int ret; + + printk ("superio: Probe\n"); + + /* Check whether we have PCI */ + if (!pci_present) + return; + + /* Only probe once */ + if (found) + return; + found++; + + if ((pdev = pci_find_device (PCI_VENDOR_ID_NS, 0x0002, NULL))) { + u16 word; + int i; + + for (i = 0 ; i < 12 ; i++) + printk ("IDE: %lx\n", pci_resource_start (pdev, i)); + + pci_read_config_word (pdev, PCI_COMMAND, &word); + word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO; + pci_write_config_word (pdev, PCI_COMMAND, word); + ret = pci_read_config_byte(pdev,PCI_INTERRUPT_LINE,&interrupt); + printk ("Scanning: interrupt is %i ret is %i\n", interrupt,ret); + pci_set_master (pdev); + } + else + printk ("Could not find Superio IDE !\n"); + + if ((pdev = pci_find_device (PCI_VENDOR_ID_NS, 0x0012, NULL))) { + u16 word; + int i; + + for (i = 0 ; i < 12 ; i++) + printk ("USB: %lx\n", pci_resource_start (pdev, i)); + + pci_read_config_word (pdev, PCI_COMMAND, &word); + word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO; + pci_write_config_word (pdev, PCI_COMMAND, word); + ret = pci_read_config_byte(pdev,PCI_INTERRUPT_LINE,&interrupt); + printk ("Scanning: interrupt is %i ret is %i\n", interrupt,ret); + } + else + printk ("Could not find Superio USB!\n"); + + if ((pdev = pci_find_device (PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87560_LIO, NULL))) { + + /* I'm setting interrupt randomly here because dev->irq is + set to zero, and I can't figure out why this is. */ + + interrupt = 69; + + superio_init (pdev,interrupt); + } else + printk ("Bah!\n"); +} + + +/* Initialize Super I/O device */ +static void +superio_init (struct pci_dev *pdev,int interrupt) +{ + u8 i; + u16 word; + + printk ("superio: Found NS87560 legacy I/O device at %s with irq of %i \n", + pdev->slot_name,pdev->irq); + + /* What's enabled */ + pci_read_config_word (pdev, SIO_CR, &word); + printk ("superio: CR = %x\n", word); + + /* Find our I/O devices */ + pci_read_config_word (pdev, SIO_SP1BAR, &sio.sp1_base); + printk ("superio: Serial port 1 at 0x%x\n", sio.sp1_base); + + pci_read_config_word (pdev, SIO_SP2BAR, &sio.sp2_base); + printk ("superio: Serial port 2 at 0x%x\n", sio.sp2_base); + + pci_read_config_word (pdev, SIO_PPBAR, &sio.pp_base); + printk ("superio: Parallel port at 0x%x\n", sio.pp_base); + + pci_read_config_word (pdev, SIO_FDCBAR, &sio.sp1_base); + printk ("superio: Floppy controller at 0x%x\n", sio.fdc_base); + + request_region (IC_PIC1, 0x1f, "pic1"); + request_region (IC_PIC2, 0x1f, "pic2"); + request_region (SIO_SP1BAR, 0xf, "serial"); + + /* Enable the legacy I/O function */ + pci_read_config_word (pdev, PCI_COMMAND, &word); + word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO; + pci_write_config_word (pdev, PCI_COMMAND, word); + pci_set_master (pdev); + + /* Next project is programming the onboard interrupt + * controllers. PDC hasn't done this for us, since it's using + * polled I/O. + */ + + /* Set PIC interrupts to edge triggered */ + printk ("Set PIC interrupts to edge triggered\n"); + pci_write_config_byte (pdev, TRIGGER_1, 0x0); + pci_write_config_byte (pdev, TRIGGER_2, 0x0); + + /* Disable all interrupt routing */ + printk ("Disable all interrupt routing\n"); + for (i = IR_LOW ; i < IR_HIGH ; i++) + pci_write_config_byte (pdev, i, 0x0); + + /* PIC1 Initialization Command Word register programming */ + printk ("PIC1 Initialization Command Word register programming\n"); + outb (0x11,IC_PIC1+0); /* ICW1: ICW4 write req | ICW1 */ + outb (0x00,IC_PIC1+1); /* ICW2: N/A */ + outb (0x04,IC_PIC1+1); /* ICW3: Cascade */ + outb (0x01,IC_PIC1+1); /* ICW4: x86 mode */ + + /* PIC2 Initialization Command Word register programming */ + outb (0x11,IC_PIC2+0); /* ICW1: ICW4 write req | ICW1 */ + outb (0x00,IC_PIC2+1); /* ICW2: N/A */ + outb (0x02,IC_PIC2+1); /* ICW3: Slave ID code */ + outb (0x01,IC_PIC2+1); /* ICW4: x86 mode */ + + /* Program Operational Control Words */ + outb (0xff,IC_PIC1+1); /* OCW1: Mask all interrupts */ + outb (0x68,IC_PIC1+0); /* OCW3: OCW3 select | ESMM | SMM */ + + /* Set up interrupt routing */ + pci_write_config_byte (pdev, IR_USB, 0x10); /* USB on IRQ1 */ + pci_write_config_byte (pdev, IR_SER, 0x43); /* SP1 on IRQ3, SP2 on IRQ4 */ + pci_write_config_byte (pdev, IR_PFD, 0x65); /* PAR on IRQ5, FDC on IRQ6 */ + pci_write_config_byte (pdev, IR_IDE, 0x07); /* IDE 1 on IRQ7 */ + + /* Set USB and IDE to level triggered interrupts, rest to edge */ + pci_write_config_byte (pdev, TRIGGER_1, 0x81); /* IRQ 1 and 7 */ + + +#ifdef CONFIG_SERIAL +// hellow(); +// superio_serial_init(); +#endif +printk("superio: line %i\n",__LINE__); + + pci_enable_device(pdev); + + if (request_irq(interrupt,superio_interrupt,SA_INTERRUPT,"SuperIO",NULL)) { + printk("superio: could not get irq\n"); + return; + } +} + + +static void superio_interrupt(int irq, void *devp, struct pt_regs *regs) +{ + u8 results,isr,device_interrupting; + + printk("In superio interrupt!\n"); + + + /* Poll the 8259 to see if there's an interrupt. */ + outb (OCW3_POLL,IC_PIC1+0); /* ICW4: x86 mode */ + + results = inb(IC_PIC1+1); + + if ((results & 0x80) == 0) { + /* Not a real interrupt. */ + /* Check the In Service bit */ + } + + /* Check the last three three bits to check which device is prompting the interrupt */ + + device_interrupting = results & 0x7; + + if (device_interrupting ==2) { + /* Ah, it's the slave PIC that's interrupting */ + /* Figure out which one */ + + } + + /* Check the approprate ISR bit to see if the device is actually interrupting */ + + if (device_interrupting < 8) { + outb(OCW3_ISR,IC_PIC1); + isr = inb(IC_PIC1); + } else { + outb(OCW3_ISR,IC_PIC2); + isr = inb(IC_PIC2); + } + if ((isr & 0x80) == 0) { + return; + } + + /* Call the appropriate device's interrupt */ + + return; +} + +static int +superio_serial_init(void) +{ + struct serial_struct *serial; + int retval; + + serial = kmalloc (sizeof (struct serial_struct), GFP_KERNEL); + + if (!serial) + return -ENOMEM; + + memset (serial, 0, sizeof (struct serial_struct)); + + serial->type = PORT_16550A; + serial->line = 0; + serial->iomem_base = (unsigned char *) sio.sp1_base; + +#ifdef CONFIG_SERIAL_CONSOLE + serial->port = serial->iomem_base; +#endif + serial->irq = 0; + serial->io_type = 0; + serial->flags = 0; + serial->xmit_fifo_size = 16; + serial->custom_divisor = 0; + serial->baud_base = BASE_BAUD; + + retval = register_serial (serial); + + if (retval) { + kfree (serial); + return -ENODEV; + } + + return retval; +} + + + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * c-set-style: "K&R" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/syscall.S linux.ac/arch/parisc/kernel/syscall.S --- linux.vanilla/arch/parisc/kernel/syscall.S Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/syscall.S Tue Apr 3 17:54:34 2001 @@ -12,7 +12,6 @@ #include <asm/errno.h> #include <asm/psw.h> -#define __ASSEMBLY__ #include <asm/assembly.h> #include <asm/processor.h> #include <linux/version.h> @@ -66,7 +65,10 @@ /* Save some registers for sigcontext and potential task switch (see entry.S for the details of which ones are - saved/restored) */ + saved/restored). TASK_PT_PSW is zeroed so we can see whether + a process is on a syscall or not. For an interrupt the real + PSW value is stored. This is needed for gdb and sys_ptrace. */ + STREG %r0, TASK_PT_PSW(%r1) STREG %r2, TASK_PT_GR2(%r1) /* preserve rp */ STREG %r19, TASK_PT_GR19(%r1) STREG %r20, TASK_PT_GR20(%r1) @@ -159,11 +161,17 @@ .Ltracesys: tracesys: /* Need to save more registers so the debugger can see where we - * are. + * are. This saves only the lower 8 bits of PSW, so that the C + * bit is still clear on syscalls, and the D bit is set if this + * full register save path has been executed. We check the D + * bit on syscall_return_rfi to determine which registers to + * restore. An interrupt results in a full PSW saved with the + * C bit set, a non-straced syscall entry results in C and D clear + * in the saved PSW. */ ldo -TASK_SZ_ALGN-64(%r30),%r1 /* get task ptr */ - ssm 0,%r2 /* Lower 8 bits only!! */ - STREG %r2,TASK_PT_PSW(%r1) + ssm 0,%r2 + STREG %r2,TASK_PT_PSW(%r1) /* Lower 8 bits only!! */ STREG %r1,TASK_PT_CR30(%r1) mfsp %sr0,%r2 STREG %r2,TASK_PT_SR0(%r1) @@ -282,13 +290,13 @@ * narrow palinux. Use ENTRY_DIFF for those where a 32-bit specific * implementation is required on wide palinux. */ -#define ENTRY_SAME(_name_) .dword sys_##_name_ -#define ENTRY_DIFF(_name_) .dword sys32_##_name_ -#define ENTRY_UHOH(_name_) .dword sys32_unimplemented +#define ENTRY_SAME(_name_) .dword sys_/**/_name_ +#define ENTRY_DIFF(_name_) .dword sys32_/**/_name_ +#define ENTRY_UHOH(_name_) .dword sys32_/**/unimplemented #else -#define ENTRY_SAME(_name_) .word sys_##_name_ -#define ENTRY_DIFF(_name_) .word sys_##_name_ -#define ENTRY_UHOH(_name_) .word sys_##_name_ +#define ENTRY_SAME(_name_) .word sys_/**/_name_ +#define ENTRY_DIFF(_name_) .word sys_/**/_name_ +#define ENTRY_UHOH(_name_) .word sys_/**/_name_ #endif .align 8 @@ -391,8 +399,8 @@ ENTRY_DIFF(getrlimit) ENTRY_DIFF(getrusage) /* struct timeval and timezone are maybe?? consistent wide and narrow */ - ENTRY_SAME(gettimeofday) - ENTRY_SAME(settimeofday) + ENTRY_DIFF(gettimeofday) + ENTRY_DIFF(settimeofday) ENTRY_SAME(getgroups) /* 80 */ ENTRY_SAME(setgroups) /* struct socketaddr... */ @@ -402,11 +410,12 @@ ENTRY_DIFF(newlstat) ENTRY_SAME(readlink) /* 85 */ /* suspect we'll need some work for narrow shlibs on wide kernel */ + /* NOTE this doesn't get used when I boot 32-bit userspace */ + /* containing working shlib apps -- can this be nuked? */ ENTRY_UHOH(uselib) ENTRY_SAME(swapon) ENTRY_SAME(reboot) - /* argh! struct dirent contains a long */ - ENTRY_UHOH(old_readdir) + ENTRY_SAME(ni_syscall) /* I'm not certain about off_t... */ ENTRY_SAME(mmap) /* 90 */ ENTRY_SAME(munmap) @@ -461,12 +470,11 @@ ENTRY_SAME(delete_module) /* struct kernel_sym contains a long. Linus never heard of size_t? */ ENTRY_DIFF(get_kernel_syms) /* 130 */ - ENTRY_SAME(quotactl) + /* time_t inside struct dqblk */ + ENTRY_UHOH(quotactl) ENTRY_SAME(getpgid) ENTRY_SAME(fchdir) - /* bdflush(func, addr) where func has least-significant-bit set means - * addr is a pointer to long :-( */ - ENTRY_UHOH(bdflush) + ENTRY_SAME(bdflush) ENTRY_SAME(sysfs) /* 135 */ ENTRY_SAME(personality) ENTRY_SAME(ni_syscall) /* for afs_syscall */ @@ -479,12 +487,12 @@ ENTRY_DIFF(getdents) /* it is POSSIBLE that select will be OK because even though fd_set * contains longs, the macros and sizes are clever. */ - ENTRY_SAME(select) + ENTRY_DIFF(select) ENTRY_SAME(flock) ENTRY_SAME(msync) /* struct iovec contains pointers */ - ENTRY_UHOH(readv) /* 145 */ - ENTRY_UHOH(writev) + ENTRY_DIFF(readv) /* 145 */ + ENTRY_DIFF(writev) ENTRY_SAME(getsid) ENTRY_SAME(fdatasync) /* struct __sysctl_args is a mess */ @@ -532,8 +540,8 @@ ENTRY_SAME(setsockopt) ENTRY_SAME(getsockopt) /* struct msghdr contains pointers... */ - ENTRY_UHOH(sendmsg) - ENTRY_UHOH(recvmsg) + ENTRY_DIFF(sendmsg) + ENTRY_DIFF(recvmsg) ENTRY_SAME(semop) /* 185 */ ENTRY_SAME(semget) /* needs a more careful review */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/time.c linux.ac/arch/parisc/kernel/time.c --- linux.vanilla/arch/parisc/kernel/time.c Wed Dec 6 19:46:39 2000 +++ linux.ac/arch/parisc/kernel/time.c Tue Apr 3 17:54:34 2001 @@ -10,6 +10,7 @@ * 1998-12-20 Updated NTP code according to technical memorandum Jan '96 * "A Kernel Model for Precision Timekeeping" by Dave Mills */ +#include <linux/config.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -30,69 +31,160 @@ #include <linux/timex.h> +/* xtime and wall_jiffies keep wall-clock time */ +extern unsigned long wall_jiffies; extern rwlock_t xtime_lock; -static int timer_value; -static int timer_delta; +static long clocktick; /* timer cycles per tick */ +static long halftick; static struct pdc_tod tod_data __attribute__((aligned(8))); void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - int old; - int lost = 0; - int cr16; - - old = timer_value; + long now = mfctl(16); + long next_tick; - cr16 = mfctl(16); - while((timer_value - cr16) < (timer_delta / 2)) { - timer_value += timer_delta; - lost++; + /* initialize next_tick to time at last clocktick */ + next_tick = cpu_data[smp_processor_id()].it_value; + /* since time passes between the interrupt and the mfctl() + * above, it is never true that last_tick + clocktick == now. If we + * never miss a clocktick, we could set next_tick = last_tick + clocktick + * but maybe we'll miss ticks, hence the loop. + * + * Variables are *signed*. + */ + while((next_tick - now) < halftick) { + next_tick += clocktick; + /* supposedly (wall_jiffies - jiffies) = "lost" ticks */ + /* but haven't checked it works for parisc */ + /* lost++; */ } - - mtctl(timer_value ,16); + mtctl(next_tick, 16); + cpu_data[smp_processor_id()].it_value = next_tick; +#if 0 + unsigned long now = mfctl(16); + /* this code will lose time by delaying the next clocktick by the */ + /* amount of time between the interrupt and the mfctl(16) above */ + cpu_data[smp_processor_id()].it_value = now; + + now += clocktick; + mtctl(now ,16); +#endif do_timer(regs); +#ifdef CONFIG_CHASSIS_LCD_LED led_interrupt_func(); +#endif } -void do_gettimeofday(struct timeval *tv) +/*** converted from ia64 ***/ +/* + * Return the number of micro-seconds that elapsed since the last + * update to wall time (aka xtime aka wall_jiffies). The xtime_lock + * must be at least read-locked when calling this routine. + */ +static inline unsigned long +gettimeoffset (void) { - unsigned long flags; - +#ifndef CONFIG_SMP + /* this might work for SMP but probably not -- should be ok on */ + /* all CPUs running timer interrupts, which may only be monarch */ + long last_tick; + long elapsed_cycles; + + /* this is the intended time of the next tick */ + last_tick = cpu_data[smp_processor_id()].it_value; + /* so subtract one tick */ + /* and account for possible difference between wall and actual time */ + last_tick += clocktick * (jiffies - wall_jiffies - 1); + elapsed_cycles = mfctl(16) - last_tick; + + /* the precision of this math could be improved */ + return elapsed_cycles / (PAGE0->mem_10msec / 10000); +#else + return 0; +#endif +} + +void +do_gettimeofday (struct timeval *tv) +{ + unsigned long flags, usec, sec; + read_lock_irqsave(&xtime_lock, flags); - tv->tv_sec = xtime.tv_sec; - tv->tv_usec = xtime.tv_usec; + { + usec = gettimeoffset(); + + sec = xtime.tv_sec; + usec += xtime.tv_usec; + } read_unlock_irqrestore(&xtime_lock, flags); + while (usec >= 1000000) { + usec -= 1000000; + ++sec; + } + + tv->tv_sec = sec; + tv->tv_usec = usec; } -void do_settimeofday(struct timeval *tv) +void +do_settimeofday (struct timeval *tv) { write_lock_irq(&xtime_lock); - xtime.tv_sec = tv->tv_sec; - xtime.tv_usec = tv->tv_usec; + { + /* + * This is revolting. We need to set "xtime" + * correctly. However, the value in this location is + * the value at the most recent update of wall time. + * Discover what correction gettimeofday would have + * done, and then undo it! + */ + tv->tv_usec -= gettimeoffset(); + tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ); + + while (tv->tv_usec < 0) { + tv->tv_usec += 1000000; + tv->tv_sec--; + } + + xtime = *tv; + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + } write_unlock_irq(&xtime_lock); } + void __init time_init(void) { - timer_delta = (100 * PAGE0->mem_10msec) / HZ; + unsigned long next_tick; + + clocktick = (100 * PAGE0->mem_10msec) / HZ; + halftick = clocktick / 2; - /* make the first timer interrupt go off in one second */ - timer_value = mfctl(16) + (HZ * timer_delta); - mtctl(timer_value, 16); + /* make the first timer interrupt go off in one second + ** Used for bogomips calculation. + */ + cpu_data[smp_processor_id()].it_value = next_tick = mfctl(16); + next_tick += HZ * clocktick; + /* kick off Itimer (CR16) */ + mtctl(next_tick, 16); if(pdc_tod_read(&tod_data) == 0) { + write_lock_irq(&xtime_lock); xtime.tv_sec = tod_data.tod_sec; xtime.tv_usec = tod_data.tod_usec; + write_unlock_irq(&xtime_lock); } else { printk(KERN_ERR "Error reading tod clock\n"); xtime.tv_sec = 0; xtime.tv_usec = 0; } - } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/traps.c linux.ac/arch/parisc/kernel/traps.c --- linux.vanilla/arch/parisc/kernel/traps.c Wed Dec 6 19:46:39 2000 +++ linux.ac/arch/parisc/kernel/traps.c Tue Apr 3 17:54:34 2001 @@ -41,13 +41,6 @@ #endif /* CONFIG_KWDB */ -static inline void console_verbose(void) -{ - extern int console_loglevel; - console_loglevel = 15; -} - - void page_exception(void); /* @@ -95,7 +88,7 @@ for (i = 0; i < 8; i += 4) { int j; - printk("sr%d-%d\t", i, i + 4); + printk("sr%d-%d\t", i, i + 3); for (j = 0; j < 4; j++) { printk(RFMT, regs->sr[i + j]); } @@ -146,14 +139,6 @@ do_exit(SIGSEGV); } -asmlinkage void cache_flush_denied(struct pt_regs * regs, long error_code) -{ -} - -asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) -{ -} - #ifndef CONFIG_MATH_EMULATION asmlinkage void math_emulate(long arg) @@ -167,24 +152,6 @@ return syscall(regs); } -struct { - int retval; - - int (*func) (void *, struct pt_regs *); - void * data; -} ipi_action[NR_CPUS]; - -void ipi_interrupt(int irq, void *unused, struct pt_regs *regs) -{ - int cpu = smp_processor_id(); - - if(!ipi_action[cpu].func) - BUG(); - - ipi_action[cpu].retval = - ipi_action[cpu].func(ipi_action[cpu].data, regs); -} - /* gdb uses break 4,8 */ #define GDB_BREAK_INSN 0x10004 void handle_gdb_break(struct pt_regs *regs, int wot) @@ -205,7 +172,6 @@ struct save_state ssp; #endif /* CONFIG_KWDB */ - flush_all_caches(); switch(iir) { case 0x00: /* show registers, halt */ @@ -571,9 +537,14 @@ die_if_kernel("Floating point exception", regs, 0); /* quiet */ handle_fpe(regs); return; - case 15: - case 16: /* Non-Access TLB miss faulting address is in IOR */ + case 17: + /* TODO: Still need to add slow path emulation code here */ + + fault_address = regs->ior; + parisc_terminate("Non access data tlb fault!",regs,code,fault_address); + + case 15: case 26: fault_address = regs->ior; fault_space = regs->isr; @@ -684,27 +655,7 @@ do_page_fault(regs, code, fault_address); - /* - * This should not be necessary. - * However, we do not currently - * implement flush_page_to_ram. - * - * The problem is that if we just - * brought in some code through the - * D-cache, the I-cache may not see - * it since it hasn't been flushed - * to ram. - */ - -/* flush_all_caches(); */ - -#if 0 - printk("returning %p\n", regs); -/* show_regs(regs); */ -#endif - return; - } void show_stack(unsigned long sp) @@ -870,11 +821,8 @@ void __init trap_init(void) { - volatile long eiem; void *iva; - printk("trap_init\n"); - if (boot_cpu_data.cpu_type >= pcxu) iva = (void *) &fault_vector_20; else @@ -886,10 +834,4 @@ if(check_ivt(iva)) panic("IVT invalid"); - - mtctl(0, 30); - mtctl(90000000, 16); - set_eiem(-1L); - mtctl(-1L, 23); - asm volatile ("rsm 0,%0" : "=r" (eiem)); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/lib/Makefile linux.ac/arch/parisc/lib/Makefile --- linux.vanilla/arch/parisc/lib/Makefile Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/lib/Makefile Tue Apr 3 17:54:34 2001 @@ -4,10 +4,6 @@ L_TARGET = lib.a -L_OBJS = lusercopy.o bitops.o checksum.o - - -.S.o: - $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o +obj-y := lusercopy.o bitops.o checksum.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/lib/bitops.c linux.ac/arch/parisc/lib/bitops.c --- linux.vanilla/arch/parisc/lib/bitops.c Wed Dec 6 19:46:39 2000 +++ linux.ac/arch/parisc/lib/bitops.c Tue Apr 3 17:54:34 2001 @@ -1,7 +1,10 @@ -/* atomic.c: atomic operations which got too long to be inlined all over - * the place. +/* + * bitops.c: atomic operations which got too long to be inlined all over + * the place. * - * Copyright 1999 Philipp Rumpf (prumpf@tux.org */ + * Copyright 1999 Philipp Rumpf (prumpf@tux.org) + * Copyright 2000 Grant Grundler (grundler@cup.hp.com) + */ #include <linux/config.h> #include <linux/kernel.h> @@ -17,44 +20,65 @@ spinlock_t __atomic_lock = SPIN_LOCK_UNLOCKED; -#ifndef __LP64__ -unsigned long __xchg(unsigned long x, unsigned long *ptr, int size) +#ifdef __LP64__ +unsigned long __xchg64(unsigned long x, unsigned long *ptr) { unsigned long temp, flags; - if (size != sizeof x) { - printk("__xchg called with bad pointer\n"); - } - spin_lock_irqsave(&__atomic_lock, flags); + SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags); temp = *ptr; *ptr = x; - spin_unlock_irqrestore(&__atomic_lock, flags); + SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags); return temp; } -#else -unsigned long __xchg(unsigned long x, unsigned long *ptr, int size) +#endif + +unsigned long __xchg32(int x, int *ptr) { - unsigned long temp, flags; - unsigned int *ptr32; + unsigned long flags; + unsigned long temp; + + SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags); + (long) temp = (long) *ptr; /* XXX - sign extension wanted? */ + *ptr = x; + SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags); + return temp; +} + + +unsigned long __xchg8(char x, char *ptr) +{ + unsigned long flags; + unsigned long temp; - if (size == 8) { -try_long: - spin_lock_irqsave(&__atomic_lock, flags); - temp = *ptr; - *ptr = x; - spin_unlock_irqrestore(&__atomic_lock, flags); - return temp; - } - if (size == 4) { - ptr32 = (unsigned int *)ptr; - spin_lock_irqsave(&__atomic_lock, flags); - temp = (unsigned long)*ptr32; - *ptr32 = (unsigned int)x; - spin_unlock_irqrestore(&__atomic_lock, flags); - return temp; - } + SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags); + (long) temp = (long) *ptr; /* XXX - sign extension wanted? */ + *ptr = x; + SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags); + return temp; +} + + +#ifdef __LP64__ +unsigned long __cmpxchg_u64(volatile long *ptr, unsigned long old, unsigned long new) +{ + unsigned long flags; - printk("__xchg called with bad pointer\n"); - goto try_long; + SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags); + old = *ptr; + *ptr = new; + SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags); + return (old == new); } #endif + +unsigned long __cmpxchg_u32(volatile int *ptr, int old, int new) +{ + unsigned long flags; + + SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags); + old = *ptr; + *ptr = new; + SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags); + return (old == new); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/lib/lusercopy.S linux.ac/arch/parisc/lib/lusercopy.S --- linux.vanilla/arch/parisc/lib/lusercopy.S Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/lib/lusercopy.S Tue Apr 3 17:54:34 2001 @@ -82,7 +82,11 @@ ldo 1(%r24),%r24 .section __ex_table,"a" +#ifdef __LP64__ + .dword 1b,(2b-1b) +#else .word 1b,(2b-1b) +#endif .previous .procend @@ -123,7 +127,11 @@ nop .section __ex_table,"a" +#ifdef __LP64__ + .dword 1b,(2b-1b) +#else .word 1b,(2b-1b) +#endif .previous .procend @@ -161,8 +169,13 @@ ldi -EFAULT,%r28 .section __ex_table,"a" +#ifdef __LP64__ + .dword 1b,(3b-1b) + .dword 2b,(3b-2b) +#else .word 1b,(3b-1b) - .word 2b,(2b-1b) + .word 2b,(3b-2b) +#endif .previous .procend @@ -194,7 +207,11 @@ ldo 1(%r25),%r25 .section __ex_table,"a" +#ifdef __LP64__ + .dword 1b,(2b-1b) +#else .word 1b,(2b-1b) +#endif .previous .procend @@ -233,8 +250,13 @@ copy %r24,%r26 /* reset r26 so 0 is returned on fault */ .section __ex_table,"a" +#ifdef __LP64__ + .dword 1b,(3b-1b) + .dword 2b,(3b-2b) +#else .word 1b,(3b-1b) - .word 2b,(2b-1b) + .word 2b,(3b-2b) +#endif .previous .procend diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/mm/Makefile linux.ac/arch/parisc/mm/Makefile --- linux.vanilla/arch/parisc/mm/Makefile Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/mm/Makefile Tue Apr 3 17:54:34 2001 @@ -8,6 +8,6 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := mm.o -O_OBJS := init.o fault.o kmap.o extable.o +obj-y := init.o fault.o extable.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/mm/fault.c linux.ac/arch/parisc/mm/fault.c --- linux.vanilla/arch/parisc/mm/fault.c Tue Apr 3 17:31:55 2001 +++ linux.ac/arch/parisc/mm/fault.c Tue Apr 3 17:54:34 2001 @@ -114,48 +114,6 @@ #undef isGraphicsFlushRead #undef BITSSET -/* This is similar to expand_stack(), except that it is for stacks - * that grow upwards. - */ - -static inline int expand_stackup(struct vm_area_struct * vma, unsigned long address) -{ - unsigned long grow; - - address += 4 + PAGE_SIZE - 1; - address &= PAGE_MASK; - grow = (address - vma->vm_end) >> PAGE_SHIFT; - if (address - vma->vm_start > current->rlim[RLIMIT_STACK].rlim_cur || - ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) - return -ENOMEM; - vma->vm_end = address; - vma->vm_mm->total_vm += grow; - if (vma->vm_flags & VM_LOCKED) - vma->vm_mm->locked_vm += grow; - return 0; -} - - -/* This is similar to find_vma(), except that it understands that stacks - * grow up rather than down. - * XXX Optimise by making use of cache and avl tree as per find_vma(). - */ - -struct vm_area_struct * pa_find_vma(struct mm_struct * mm, unsigned long addr) -{ - struct vm_area_struct *vma = NULL; - - if (mm) { - vma = mm->mmap; - if (!vma || addr < vma->vm_start) - return NULL; - while (vma->vm_next && addr >= vma->vm_next->vm_start) - vma = vma->vm_next; - } - return vma; -} - - /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate @@ -163,10 +121,30 @@ */ extern void parisc_terminate(char *, struct pt_regs *, int, unsigned long); +#if 0 +/* This is the treewalk to find a vma which is the highest that has + * a start < addr. We're using find_vma_prev instead right now, but + * we might want to use this at some point in the future. Probably + * not, but I want it committed to CVS so I don't lose it :-) + */ + while (tree != vm_avl_empty) { + if (tree->vm_start > addr) { + tree = tree->vm_avl_left; + } else { + prev = tree; + if (prev->vm_next == NULL) + break; + if (prev->vm_next->vm_start > addr) + break; + tree = tree->vm_avl_right; + } + } +#endif + void do_page_fault(struct pt_regs *regs, unsigned long code, unsigned long address) { - struct vm_area_struct * vma; + struct vm_area_struct *vma, *prev_vma; struct task_struct *tsk = current; struct mm_struct *mm = tsk->mm; const struct exception_table_entry *fix; @@ -176,13 +154,9 @@ goto no_context; down_read(&mm->mmap_sem); - vma = pa_find_vma(mm, address); - if (!vma) - goto bad_area; - if (address < vma->vm_end) - goto good_area; - if (!(vma->vm_flags & VM_GROWSUP) || expand_stackup(vma, address)) - goto bad_area; + vma = find_vma_prev(mm, address, &prev_vma); + if (!vma || address < vma->vm_start) + goto check_expansion; /* * Ok, we have a good vm_area for this memory access. We still need to * check the access permissions. @@ -221,6 +195,11 @@ up_read(&mm->mmap_sem); return; +check_expansion: + vma = prev_vma; + if (vma && (expand_stack(vma, address) == 0)) + goto good_area; + /* * Something tried to access memory that isn't in our memory map.. */ @@ -230,8 +209,12 @@ if (user_mode(regs)) { struct siginfo si; - printk("\ndo_page_fault() pid=%d command='%s'\n", - tsk->pid, tsk->comm); + printk("\ndo_page_fault() pid=%d command='%s' type=%d address=0x%08lx\n", + tsk->pid, tsk->comm, code, address); + if (vma) { + printk("vm_start = 0x%08lx, vm_end = 0x%08lx\n", + vma->vm_start, vma->vm_end); + } show_regs(regs); /* FIXME: actually we need to get the signo and code correct */ si.si_signo = SIGSEGV; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/mm/init.c linux.ac/arch/parisc/mm/init.c --- linux.vanilla/arch/parisc/mm/init.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/mm/init.c Tue Apr 3 17:54:34 2001 @@ -19,6 +19,9 @@ #include <linux/unistd.h> #include <asm/pgalloc.h> +#include <asm/tlb.h> + +mmu_gather_t mmu_gathers[NR_CPUS]; static unsigned long totalram_pages; extern unsigned long max_pfn, mem_max; @@ -388,53 +391,97 @@ } } -#define NR_SPACE_IDS 8192 +/* + * Currently we have a one-to-one relationship between space id's and + * protection id's. Older parisc chips (PCXS, PCXT, PCXL, PCXL2) only + * support 15 bit protection id's, so that is the limiting factor. + * We could do some type of run time initialization here, but let's + * make sure there is a need first. + */ + +#define NR_SPACE_IDS 32768 +#define SID_ARRAY_SIZE (NR_SPACE_IDS / (8 * sizeof(long))) -static unsigned long space_id[NR_SPACE_IDS / (8 * sizeof(long))]; +static unsigned long space_id[SID_ARRAY_SIZE] = { 1 }; /* disallow space 0 */ +static unsigned long dirty_space_id[SID_ARRAY_SIZE]; static unsigned long space_id_index; -static unsigned long free_space_ids = NR_SPACE_IDS; +static unsigned long free_space_ids = NR_SPACE_IDS - 1; +static unsigned long dirty_space_ids = 0; -/* - * XXX: We should probably unfold the set_bit / test_bit / clear_bit - * locking out of these two functions and have a single spinlock on the - * space_id data structures. - * - * Don't bother. This is all going to be significantly changed in the - * very near future. - */ +static spinlock_t sid_lock = SPIN_LOCK_UNLOCKED; #define SPACEID_SHIFT (PAGE_SHIFT + (PT_NLEVELS)*(PAGE_SHIFT - PT_NLEVELS) - 32) unsigned long alloc_sid(void) { unsigned long index; + spin_lock(&sid_lock); - if (free_space_ids == 0) - BUG(); + if (free_space_ids == 0) { + if (dirty_space_ids != 0) { + spin_unlock(&sid_lock); + flush_tlb_all(); /* flush_tlb_all() calls recycle_sids() */ + spin_lock(&sid_lock); + } + if (free_space_ids == 0) + BUG(); + } free_space_ids--; - do { - index = find_next_zero_bit(space_id, NR_SPACE_IDS, space_id_index); - } while(test_and_set_bit(index, space_id)); - + index = find_next_zero_bit(space_id, NR_SPACE_IDS, space_id_index); + space_id[index >> SHIFT_PER_LONG] |= (1L << (index & (BITS_PER_LONG - 1))); space_id_index = index; + spin_unlock(&sid_lock); + return index << SPACEID_SHIFT; } void free_sid(unsigned long spaceid) { unsigned long index = spaceid >> SPACEID_SHIFT; - if (index < 0) - BUG(); - clear_bit(index, space_id); + spin_lock(&sid_lock); + + dirty_space_id[index >> SHIFT_PER_LONG] |= (1L << (index & (BITS_PER_LONG - 1))); + dirty_space_ids++; + + spin_unlock(&sid_lock); +} + +/* + * flush_tlb_all() calls recycle_sids(), since whenever the entire tlb is + * purged, we can safely reuse the space ids that were released but + * not flushed from the tlb. + */ + +static void recycle_sids(void) +{ + int i; + + /* NOTE: sid_lock must be held upon entry */ - if (space_id_index > index) { - space_id_index = index; + if (dirty_space_ids != 0) { + for (i = 0; i < SID_ARRAY_SIZE; i++) { + space_id[i] ^= dirty_space_id[i]; + dirty_space_id[i] = 0; + } + + free_space_ids += dirty_space_ids; + dirty_space_ids = 0; + space_id_index = 0; } - free_space_ids++; +} + +extern void __flush_tlb_all(void); + +void flush_tlb_all(void) +{ + spin_lock(&sid_lock); + __flush_tlb_all(); + recycle_sids(); + spin_unlock(&sid_lock); } #ifdef CONFIG_BLK_DEV_INITRD diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/mm/kmap.c linux.ac/arch/parisc/mm/kmap.c --- linux.vanilla/arch/parisc/mm/kmap.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/parisc/mm/kmap.c Thu Jan 1 01:00:00 1970 @@ -1,143 +0,0 @@ -/* -** Stolen mostly from arch/parisc/kernel/pci-dma.c -*/ - -#include <linux/types.h> -#include <linux/mm.h> -#include <linux/string.h> -#include <linux/pci.h> - -#include <linux/slab.h> -#include <linux/vmalloc.h> - -#include <asm/uaccess.h> -#include <asm/pgalloc.h> - -#include <asm/io.h> -#include <asm/page.h> /* get_order */ - -#undef flush_cache_all -#define flush_cache_all flush_all_caches - -typedef void (*pte_iterator_t) (pte_t * pte, unsigned long arg); - -#if 0 -/* XXX This routine could be used with iterate_page() to replace - * unmap_uncached_page() and save a little code space but I didn't - * do that since I'm not certain whether this is the right path. -PB - */ -static void unmap_cached_pte(pte_t * pte, unsigned long arg) -{ - pte_t page = *pte; - pte_clear(pte); - if (!pte_none(page)) { - if (pte_present(page)) { - unsigned long map_nr = pte_pagenr(page); - if (map_nr < max_mapnr) - __free_page(mem_map + map_nr); - } else { - printk(KERN_CRIT - "Whee.. Swapped out page in kernel page table\n"); - } - } -} -#endif - -/* These two routines should probably check a few things... */ -static void set_uncached(pte_t * pte, unsigned long arg) -{ - pte_val(*pte) |= _PAGE_NO_CACHE; -} - -static void set_cached(pte_t * pte, unsigned long arg) -{ - pte_val(*pte) &= ~_PAGE_NO_CACHE; -} - -static inline void iterate_pte(pmd_t * pmd, unsigned long address, - unsigned long size, pte_iterator_t op, - unsigned long arg) -{ - pte_t *pte; - unsigned long end; - - if (pmd_none(*pmd)) - return; - if (pmd_bad(*pmd)) { - pmd_ERROR(*pmd); - pmd_clear(pmd); - return; - } - pte = pte_offset(pmd, address); - address &= ~PMD_MASK; - end = address + size; - if (end > PMD_SIZE) - end = PMD_SIZE; - do { - op(pte, arg); - address += PAGE_SIZE; - pte++; - } while (address < end); -} - -static inline void iterate_pmd(pgd_t * dir, unsigned long address, - unsigned long size, pte_iterator_t op, - unsigned long arg) -{ - pmd_t *pmd; - unsigned long end; - - if (pgd_none(*dir)) - return; - if (pgd_bad(*dir)) { - pgd_ERROR(*dir); - pgd_clear(dir); - return; - } - pmd = pmd_offset(dir, address); - address &= ~PGDIR_MASK; - end = address + size; - if (end > PGDIR_SIZE) - end = PGDIR_SIZE; - do { - iterate_pte(pmd, address, end - address, op, arg); - address = (address + PMD_SIZE) & PMD_MASK; - pmd++; - } while (address < end); -} - -static void iterate_pages(unsigned long address, unsigned long size, - pte_iterator_t op, unsigned long arg) -{ - pgd_t *dir; - unsigned long end = address + size; - - dir = pgd_offset_k(address); - flush_cache_all(); - do { - iterate_pmd(dir, address, end - address, op, arg); - address = (address + PGDIR_SIZE) & PGDIR_MASK; - dir++; - } while (address && (address < end)); - flush_tlb_all(); -} - -void -kernel_set_cachemode(unsigned long vaddr, unsigned long size, int what) -{ - switch (what) { - case IOMAP_FULL_CACHING: - iterate_pages(vaddr, size, set_cached, 0); - flush_tlb_range(&init_mm, vaddr, size); - break; - case IOMAP_NOCACHE_SER: - iterate_pages(vaddr, size, set_uncached, 0); - flush_tlb_range(&init_mm, vaddr, size); - break; - default: - printk(KERN_CRIT - "kernel_set_cachemode mode %d not understood\n", - what); - break; - } -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/mm/pa11.c linux.ac/arch/parisc/mm/pa11.c --- linux.vanilla/arch/parisc/mm/pa11.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/mm/pa11.c Thu Jan 1 01:00:00 1970 @@ -1,170 +0,0 @@ -/* $Id: pa11.c,v 1.1 1999/03/17 01:05:41 pjlahaie Exp $ - * - * pa11.c: PA 1.1 specific mmu/cache code. - * - */ -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/mm.h> - -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/system.h> -#include <asm/sgialib.h> -#include <asm/mmu_context.h> - -extern unsigned long mips_tlb_entries; - -/* page functions */ -void pa11_clear_page(unsigned long page) -{ -} - -static void pa11_copy_page(unsigned long to, unsigned long from) -{ -} - -/* Cache operations. */ -static inline void pa11_flush_cache_all(void) { } -static void pa11_flush_cache_mm(struct mm_struct *mm) { } -static void pa11_flush_cache_range(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ -} - -static void pa11_flush_cache_page(struct vm_area_struct *vma, - unsigned long page) -{ -} - -static void pa11_flush_page_to_ram(unsigned long page) -{ -} - -static void pa11_flush_cache_sigtramp(unsigned long page) -{ -} - -/* TLB operations. */ -static inline void pa11_flush_tlb_all(void) -{ - unsigned long flags; - int entry; - - save_and_cli(flags); -/* Here we will need to flush all the TLBs */ - restore_flags(flags); -} - -static void pa11_flush_tlb_mm(struct mm_struct *mm) -{ -/* This is what the MIPS does.. Is it the right thing for PA-RISC? */ - if(mm == current->mm) - pa11_flush_tlb_all(); -} - -static void pa11_flush_tlb_range(struct mm_struct *mm, unsigned long start, - unsigned long end) -{ - if(mm == current->mm) - pa11_flush_tlb_all(); -} - -static void pa11_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) -{ - if(vma->vm_mm == current->mm) - pa11_flush_tlb_all(); -} - -static void pa11_load_pgd(unsigned long pg_dir) -{ - unsigned long flags; - /* We need to do the right thing here */ -} - -/* - * Initialize new page directory with pointers to invalid ptes - */ -static void pa11_pgd_init(unsigned long page) -{ - unsigned long dummy1, dummy2; - -} - -static void pa11_update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) -{ - pa11_flush_tlb_page(vma, address); -} - -static void pa11_show_regs(struct pt_regs * regs) -{ - /* - * Saved main processor registers - */ - printk("$0 : %08x %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - 0, (unsigned long) regs->regs[1], (unsigned long) regs->regs[2], - (unsigned long) regs->regs[3], (unsigned long) regs->regs[4], - (unsigned long) regs->regs[5], (unsigned long) regs->regs[6], - (unsigned long) regs->regs[7]); - printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - (unsigned long) regs->regs[8], (unsigned long) regs->regs[9], - (unsigned long) regs->regs[10], (unsigned long) regs->regs[11], - (unsigned long) regs->regs[12], (unsigned long) regs->regs[13], - (unsigned long) regs->regs[14], (unsigned long) regs->regs[15]); - printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - (unsigned long) regs->regs[16], (unsigned long) regs->regs[17], - (unsigned long) regs->regs[18], (unsigned long) regs->regs[19], - (unsigned long) regs->regs[20], (unsigned long) regs->regs[21], - (unsigned long) regs->regs[22], (unsigned long) regs->regs[23]); - printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx\n", - (unsigned long) regs->regs[24], (unsigned long) regs->regs[25], - (unsigned long) regs->regs[28], (unsigned long) regs->regs[29], - (unsigned long) regs->regs[30], (unsigned long) regs->regs[31]); - - /* - * Saved cp0 registers - */ - printk("epc : %08lx\nStatus: %08x\nCause : %08x\n", - (unsigned long) regs->cp0_epc, (unsigned int) regs->cp0_status, - (unsigned int) regs->cp0_cause); -} - -static int pa11_user_mode(struct pt_regs *regs) -{ - /* Return user mode stuff?? */ -} - -__initfunc(void ld_mmu_pa11(void)) -{ - - /* Taken directly from the MIPS arch.. Lots of bad things here */ - clear_page = pa11_clear_page; - copy_page = pa11_copy_page; - - flush_cache_all = pa11_flush_cache_all; - flush_cache_mm = pa11_flush_cache_mm; - flush_cache_range = pa11_flush_cache_range; - flush_cache_page = pa11_flush_cache_page; - flush_cache_sigtramp = pa11_flush_cache_sigtramp; - flush_page_to_ram = pa11_flush_page_to_ram; - - flush_tlb_all = pa11_flush_tlb_all; - flush_tlb_mm = pa11_flush_tlb_mm; - flush_tlb_range = pa11_flush_tlb_range; - flush_tlb_page = pa11_flush_tlb_page; - pa11_asid_setup(); - - load_pgd = pa11_load_pgd; - pgd_init = pa11_pgd_init; - update_mmu_cache = pa11_update_mmu_cache; - - show_regs = pa11_show_regs; - - add_wired_entry = pa11_add_wired_entry; - - user_mode = pa11_user_mode; - flush_tlb_all(); -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/mm/pa20.c linux.ac/arch/parisc/mm/pa20.c --- linux.vanilla/arch/parisc/mm/pa20.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/mm/pa20.c Thu Jan 1 01:00:00 1970 @@ -1,170 +0,0 @@ -/* $Id: pa20.c,v 1.1 1999/03/17 01:05:41 pjlahaie Exp $ - * - * pa20.c: PA 2.0 specific mmu/cache code. - * - */ -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/mm.h> - -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/system.h> -#include <asm/sgialib.h> -#include <asm/mmu_context.h> - -extern unsigned long mips_tlb_entries; - -/* page functions */ -void pa20_clear_page(unsigned long page) -{ -} - -static void pa20_copy_page(unsigned long to, unsigned long from) -{ -} - -/* Cache operations. */ -static inline void pa20_flush_cache_all(void) { } -static void pa20_flush_cache_mm(struct mm_struct *mm) { } -static void pa20_flush_cache_range(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ -} - -static void pa20_flush_cache_page(struct vm_area_struct *vma, - unsigned long page) -{ -} - -static void pa20_flush_page_to_ram(unsigned long page) -{ -} - -static void pa20_flush_cache_sigtramp(unsigned long page) -{ -} - -/* TLB operations. */ -static inline void pa20_flush_tlb_all(void) -{ - unsigned long flags; - int entry; - - save_and_cli(flags); -/* Here we will need to flush all the TLBs */ - restore_flags(flags); -} - -static void pa20_flush_tlb_mm(struct mm_struct *mm) -{ -/* This is what the MIPS does.. Is it the right thing for PA-RISC? */ - if(mm == current->mm) - pa20_flush_tlb_all(); -} - -static void pa20_flush_tlb_range(struct mm_struct *mm, unsigned long start, - unsigned long end) -{ - if(mm == current->mm) - pa20_flush_tlb_all(); -} - -static void pa20_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) -{ - if(vma->vm_mm == current->mm) - pa20_flush_tlb_all(); -} - -static void pa20_load_pgd(unsigned long pg_dir) -{ - unsigned long flags; - /* We need to do the right thing here */ -} - -/* - * Initialize new page directory with pointers to invalid ptes - */ -static void pa20_pgd_init(unsigned long page) -{ - unsigned long dummy1, dummy2; - -} - -static void pa20_update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) -{ - pa20_flush_tlb_page(vma, address); -} - -static void pa20_show_regs(struct pt_regs * regs) -{ - /* - * Saved main processor registers - */ - printk("$0 : %08x %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - 0, (unsigned long) regs->regs[1], (unsigned long) regs->regs[2], - (unsigned long) regs->regs[3], (unsigned long) regs->regs[4], - (unsigned long) regs->regs[5], (unsigned long) regs->regs[6], - (unsigned long) regs->regs[7]); - printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - (unsigned long) regs->regs[8], (unsigned long) regs->regs[9], - (unsigned long) regs->regs[10], (unsigned long) regs->regs[11], - (unsigned long) regs->regs[12], (unsigned long) regs->regs[13], - (unsigned long) regs->regs[14], (unsigned long) regs->regs[15]); - printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - (unsigned long) regs->regs[16], (unsigned long) regs->regs[17], - (unsigned long) regs->regs[18], (unsigned long) regs->regs[19], - (unsigned long) regs->regs[20], (unsigned long) regs->regs[21], - (unsigned long) regs->regs[22], (unsigned long) regs->regs[23]); - printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx\n", - (unsigned long) regs->regs[24], (unsigned long) regs->regs[25], - (unsigned long) regs->regs[28], (unsigned long) regs->regs[29], - (unsigned long) regs->regs[30], (unsigned long) regs->regs[31]); - - /* - * Saved cp0 registers - */ - printk("epc : %08lx\nStatus: %08x\nCause : %08x\n", - (unsigned long) regs->cp0_epc, (unsigned int) regs->cp0_status, - (unsigned int) regs->cp0_cause); -} - -static int pa20_user_mode(struct pt_regs *regs) -{ - /* Return user mode stuff?? */ -} - -__initfunc(void ld_mmu_pa20(void)) -{ - - /* Taken directly from the MIPS arch.. Lots of bad things here */ - clear_page = pa20_clear_page; - copy_page = pa20_copy_page; - - flush_cache_all = pa20_flush_cache_all; - flush_cache_mm = pa20_flush_cache_mm; - flush_cache_range = pa20_flush_cache_range; - flush_cache_page = pa20_flush_cache_page; - flush_cache_sigtramp = pa20_flush_cache_sigtramp; - flush_page_to_ram = pa20_flush_page_to_ram; - - flush_tlb_all = pa20_flush_tlb_all; - flush_tlb_mm = pa20_flush_tlb_mm; - flush_tlb_range = pa20_flush_tlb_range; - flush_tlb_page = pa20_flush_tlb_page; - pa20_asid_setup(); - - load_pgd = pa20_load_pgd; - pgd_init = pa20_pgd_init; - update_mmu_cache = pa20_update_mmu_cache; - - show_regs = pa20_show_regs; - - add_wired_entry = pa20_add_wired_entry; - - user_mode = pa20_user_mode; - flush_tlb_all(); -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/tools/Makefile linux.ac/arch/parisc/tools/Makefile --- linux.vanilla/arch/parisc/tools/Makefile Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/tools/Makefile Tue Apr 3 17:54:34 2001 @@ -22,7 +22,7 @@ offset.s: offset.c -clean: +distclean clean: rm -f offset.[hs] $(TARGET).new include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/tools/offset.c linux.ac/arch/parisc/tools/offset.c --- linux.vanilla/arch/parisc/tools/offset.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/tools/offset.c Tue Apr 3 17:54:34 2001 @@ -13,6 +13,7 @@ #include <asm/ptrace.h> #include <asm/processor.h> #include <asm/hardirq.h> +#include <asm/pdc.h> #define text(t) __asm__("\n@@@" t) #define _offset(type, member) (&(((type *)NULL)->member)) @@ -260,6 +261,34 @@ offset("#define IRQSTAT_SI_ACTIVE ", irq_cpustat_t, __softirq_active); offset("#define IRQSTAT_SI_MASK ", irq_cpustat_t, __softirq_mask); size ("#define IRQSTAT_SZ ", irq_cpustat_t); + linefeed; +} + +void output_cache_info_defines(void) +{ + text("/* PARISC pdc_cache_info offsets. */"); + offset("#define ICACHE_BASE ", struct pdc_cache_info, ic_base); + offset("#define ICACHE_STRIDE ", struct pdc_cache_info, ic_stride); + offset("#define ICACHE_COUNT ", struct pdc_cache_info, ic_count); + offset("#define ICACHE_LOOP ", struct pdc_cache_info, ic_loop); + offset("#define DCACHE_BASE ", struct pdc_cache_info, dc_base); + offset("#define DCACHE_STRIDE ", struct pdc_cache_info, dc_stride); + offset("#define DCACHE_COUNT ", struct pdc_cache_info, dc_count); + offset("#define DCACHE_LOOP ", struct pdc_cache_info, dc_loop); + offset("#define ITLB_SID_BASE ", struct pdc_cache_info, it_sp_base); + offset("#define ITLB_SID_STRIDE ", struct pdc_cache_info, it_sp_stride); + offset("#define ITLB_SID_COUNT ", struct pdc_cache_info, it_sp_count); + offset("#define ITLB_OFF_BASE ", struct pdc_cache_info, it_off_base); + offset("#define ITLB_OFF_STRIDE ", struct pdc_cache_info, it_off_stride); + offset("#define ITLB_OFF_COUNT ", struct pdc_cache_info, it_off_count); + offset("#define ITLB_LOOP ", struct pdc_cache_info, it_loop); + offset("#define DTLB_SID_BASE ", struct pdc_cache_info, dt_sp_base); + offset("#define DTLB_SID_STRIDE ", struct pdc_cache_info, dt_sp_stride); + offset("#define DTLB_SID_COUNT ", struct pdc_cache_info, dt_sp_count); + offset("#define DTLB_OFF_BASE ", struct pdc_cache_info, dt_off_base); + offset("#define DTLB_OFF_STRIDE ", struct pdc_cache_info, dt_off_stride); + offset("#define DTLB_OFF_COUNT ", struct pdc_cache_info, dt_off_count); + offset("#define DTLB_LOOP ", struct pdc_cache_info, dt_loop); linefeed; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/vmlinux.lds linux.ac/arch/parisc/vmlinux.lds --- linux.vanilla/arch/parisc/vmlinux.lds Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/vmlinux.lds Tue Apr 3 17:54:34 2001 @@ -1,5 +1,4 @@ /* ld script to make hppa Linux kernel */ -OUTPUT_FORMAT("elf32-hppa") OUTPUT_ARCH(hppa) ENTRY(_stext) SECTIONS @@ -15,7 +14,6 @@ _text = .; /* Text and read-only data */ .text BLOCK(16) : { *(.text*) - *(.PARISC.unwind) *(.fixup) *(.lock.text) /* out-of-line lock text */ *(.gnu.warning) @@ -63,6 +61,7 @@ .bss : { *(.bss) *(COMMON) } /* BSS */ + .PARISC.unwind : { *(.PARISC.unwind) } _end = . ; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/Makefile linux.ac/arch/ppc/Makefile --- linux.vanilla/arch/ppc/Makefile Mon Jan 22 23:41:14 2001 +++ linux.ac/arch/ppc/Makefile Tue Apr 3 23:32:42 2001 @@ -31,7 +31,7 @@ endif ifdef CONFIG_8xx -CFLAGS := $(CFLAGS) -mcpu=860 -I../8xx_io +CFLAGS := $(CFLAGS) -mcpu=860 endif ifdef CONFIG_PPC64BRIDGE @@ -144,6 +144,9 @@ .PHONY: clean_config clean_config: rm -f .config arch/ppc/defconfig + +gemini_config: clean_config + cp -f arch/ppc/configs/gemini_defconfig arch/ppc/defconfig pmac_config: clean_config cp -f arch/ppc/configs/pmac_defconfig arch/ppc/defconfig diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/amiga/config.c linux.ac/arch/ppc/amiga/config.c --- linux.vanilla/arch/ppc/amiga/config.c Tue Nov 28 01:57:34 2000 +++ linux.ac/arch/ppc/amiga/config.c Tue Apr 3 17:54:34 2001 @@ -743,20 +743,6 @@ return 0; } -void dbprintf(const char *fmt , ...) -{ - static char buf[1024]; - va_list args; - extern void console_print (const char *str); - extern int vsprintf(char * buf, const char * fmt, va_list args); - - va_start(args, fmt); - vsprintf(buf, fmt, args); - va_end(args); - - console_print (buf); -} - static NORET_TYPE void amiga_reset( void ) ATTRIB_NORET; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/boot/Makefile linux.ac/arch/ppc/boot/Makefile --- linux.vanilla/arch/ppc/boot/Makefile Mon Jan 22 23:41:14 2001 +++ linux.ac/arch/ppc/boot/Makefile Tue Apr 3 23:32:42 2001 @@ -31,6 +31,12 @@ TFTPIMAGE=/tftpboot/zImage.prep$(MSIZE) endif +ifeq ($(CONFIG_SMP),y) +TFTPSIMAGE=/tftpboot/sImage.smp +else +TFTPSIMAGE=/tftpboot/sImage +endif + ifeq ($(CONFIG_PPC64BRIDGE),y) MSIZE=.64 else @@ -70,8 +76,24 @@ --add-section=image=../coffboot/vmlinux.gz \ zvmlinux.initrd.tmp $@ rm zvmlinux.initrd.tmp +ifdef CONFIG_GEMINI + $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) + $(OBJCOPY) -I elf32-powerpc -O binary zvmlinux.initrd.tmp svmlinux.initrd.tmp + ./mksimage svmlinux.initrd.tmp ../coffboot/vmlinux.gz ramdisk.image.gz \ + -o svmlinux.initrd > sImage.map + $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh sioffset initrd` \ + -DINITRD_SIZE=`sh sisize initrd` \ + -DZIMAGE_OFFSET=`sh sioffset zimage` \ + -DZIMAGE_SIZE=`sh sisize zimage` \ + -c -o misc.o misc.c + $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) + $(OBJCOPY) -I elf32-powerpc -O binary zvmlinux.initrd.tmp svmlinux.initrd.tmp + ./mksimage svmlinux.initrd.tmp ../coffboot/vmlinux.gz ramdisk.image.gz \ + -o svmlinux.initrd > /dev/null + rm svmlinux.initrd.tmp zvmlinux.initrd.tmp sImage.map +endif -zImage: zvmlinux mkprep +zImage: zvmlinux mkprep sImage mksimage ifdef CONFIG_ALL_PPC ./mkprep -pbp zvmlinux zImage endif @@ -80,12 +102,17 @@ gzip $(GZIP_FLAGS) vmapus endif +sImage: ../../../vmlinux +ifdef CONFIG_GEMINI + $(OBJCOPY) -I elf32-powerpc -O binary ../../../vmlinux sImage +endif + zImage.initrd: zvmlinux.initrd mkprep ifdef CONFIG_ALL_PPC ./mkprep -pbp zvmlinux.initrd zImage.initrd endif -zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz +zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz mksimage # # build the boot loader image and then compute the offset into it # for the kernel image @@ -105,6 +132,19 @@ $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ zvmlinux.tmp $@ rm zvmlinux.tmp +ifdef CONFIG_GEMINI + $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) + $(OBJCOPY) -I elf32-powerpc -O binary zvmlinux.tmp svmlinux.tmp + ./mksimage svmlinux.tmp ../coffboot/vmlinux.gz -o svmlinux > sImage.map + $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ + -DZIMAGE_OFFSET=`sh sioffset zimage` \ + -DZIMAGE_SIZE=`sh sisize zimage` \ + -c -o misc.o misc.c + $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) + $(OBJCOPY) -I elf32-powerpc -O binary zvmlinux.tmp svmlinux.tmp + ./mksimage svmlinux.tmp ../coffboot/vmlinux.gz -o svmlinux > /dev/null + rm svmlinux.tmp sImage.map zvmlinux.tmp +endif floppy: $(TOPDIR)/vmlinux zImage dd if=zImage of=/dev/fd0H1440 bs=64b @@ -112,16 +152,22 @@ mkprep : mkprep.c $(HOSTCC) -o mkprep mkprep.c +mksimage: mksimage.c + $(HOSTCC) -o mksimage mksimage.c + znetboot : zImage ifdef CONFIG_ALL_PPC cp zImage $(TFTPIMAGE) endif +ifdef CONFIG_GEMINI + cp sImage $(TFTPSIMAGE) +endif znetboot.initrd : zImage.initrd cp zImage.initrd $(TFTPIMAGE) clean: - rm -f vmlinux* zvmlinux* mkprep zImage* + rm -f vmlinux* zvmlinux* mkprep zImage* sImage* fastdep: $(TOPDIR)/scripts/mkdep *.[Sch] > .depend diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/boot/mksimage.c linux.ac/arch/ppc/boot/mksimage.c --- linux.vanilla/arch/ppc/boot/mksimage.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ppc/boot/mksimage.c Tue Apr 3 23:32:42 2001 @@ -0,0 +1,124 @@ +/* + * + * + * + * + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> + + +#define SIZE 1024 +#define BLOCK_ALIGN(x) (((x)+SIZE-1)&(~(SIZE-1))) + +static void +die(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + exit(1); +} + +static void +usage(void) +{ + printf("Usage: mkbinimg <bootstrap> <kernel> <ramdisk> -o <binary>\n"); + exit(1); +} + +static int +copy_blocks(int ifd, int ofd, unsigned long *offset, unsigned long *size) +{ + off_t cur; + int amt; + unsigned long len = 0; + char buffer[SIZE]; + + cur = lseek(ofd, 0, SEEK_CUR); + + if (cur % SIZE) { + cur = BLOCK_ALIGN(cur); + cur = lseek(ofd, cur, SEEK_SET); + } + + *offset = (unsigned long) cur; + while((amt = read(ifd, buffer, SIZE)) > 0) { + write(ofd, buffer, amt); + len += amt; + } + *size = len; + return 0; +} + + +int +main(int argc, char *argv[]) +{ + char *kernel, *loader, *rdimage = NULL; + unsigned long ld_off, kern_off, rd_off; + unsigned long ld_size, kern_size, rd_size; + int fd, ofd, len; + char buffer[500]; + + if (argc < 5 && !strcmp(argv[argc-2], "-o")) + usage(); + + if (argc > 5) + rdimage = argv[3]; + + kernel = argv[2]; + loader = argv[1]; + + ofd = open(argv[argc-1], (O_RDWR|O_CREAT), 0755); + if (ofd < 0) { + die("can't open %s: %s", argv[5], strerror(errno)); + } + + ld_off = kern_off = rd_off = 0; + ld_size = kern_size = rd_size = 0; + memset(buffer, 0, 500); + len = 0; + + fd = open(loader, O_RDONLY); + if (fd < 0) + die("can't open loader: %s", strerror(errno)); + + copy_blocks(fd, ofd, &ld_off, &ld_size); + len = sprintf(buffer, "bootloader: %x %x\n", ld_off, ld_size); + close(fd); + + fd = open(kernel, O_RDONLY); + if (fd < 0) + die("can't open kernel: %s", strerror(errno)); + + copy_blocks(fd, ofd, &kern_off, &kern_size); + len += sprintf(buffer+len, "zimage: %x %x\n", kern_off, kern_size); + close(fd); + + if (rdimage) { + fd = open(rdimage, O_RDONLY); + if (fd < 0) + die("can't get ramdisk: %s", strerror(errno)); + + copy_blocks(fd, ofd, &rd_off, &rd_size); + close(fd); + } + + len += sprintf(buffer+len, "initrd: %x %x", rd_off, rd_size); + + close(ofd); + + printf("%s\n", buffer); + + return 0; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/boot/sioffset linux.ac/arch/ppc/boot/sioffset --- linux.vanilla/arch/ppc/boot/sioffset Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ppc/boot/sioffset Tue Apr 3 23:32:42 2001 @@ -0,0 +1,4 @@ +#!/bin/bash + +OFFSET=`grep $1 sImage.map | awk '{print $2}'` +echo "0x"$OFFSET diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/boot/sisize linux.ac/arch/ppc/boot/sisize --- linux.vanilla/arch/ppc/boot/sisize Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ppc/boot/sisize Tue Apr 3 23:32:42 2001 @@ -0,0 +1,4 @@ +#!/bin/bash + +OFFSET=`grep $1 sImage.map | awk '{print $3}'` +echo "0x"$OFFSET diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/coffboot/chrpmain.c linux.ac/arch/ppc/coffboot/chrpmain.c --- linux.vanilla/arch/ppc/coffboot/chrpmain.c Sun Sep 17 17:48:06 2000 +++ linux.ac/arch/ppc/coffboot/chrpmain.c Tue Apr 3 23:32:46 2001 @@ -14,6 +14,8 @@ extern void *finddevice(const char *); extern int getprop(void *, const char *, void *, int); +extern void *claim(unsigned int, unsigned int, unsigned int); +extern void release(void *ptr, unsigned int len); void make_bi_recs(unsigned long); void gunzip(void *, int, unsigned char *, int *); void stop_imac_ethernet(void); @@ -78,6 +80,7 @@ printf("done %u bytes\n", len); printf("%u bytes of heap consumed, max in use %u\n", avail_high - begin_avail, heap_max); + release(begin_avail, SCRATCH_SIZE); } else { memmove(dst, im, len); } @@ -98,8 +101,13 @@ void make_bi_recs(unsigned long addr) { struct bi_record *rec; - rec = (struct bi_record *)_ALIGN((unsigned long)addr+(1<<20)-1,(1<<20)); - + + /* leave a 1MB gap then align to the next 1MB boundary */ + addr = _ALIGN(addr+ (1<<20) - 1, (1<<20)); + if (addr >= PROG_START + PROG_SIZE) + claim(addr, 0x1000, 0); + + rec = (struct bi_record *)addr; rec->tag = BI_FIRST; rec->size = sizeof(struct bi_record); rec = (struct bi_record *)((unsigned long)rec + rec->size); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/coffboot/start.c linux.ac/arch/ppc/coffboot/start.c --- linux.vanilla/arch/ppc/coffboot/start.c Thu Dec 2 22:37:34 1999 +++ linux.ac/arch/ppc/coffboot/start.c Tue Apr 3 17:54:35 2001 @@ -172,6 +172,25 @@ return args.ret; } +void +release(void *virt, unsigned int size) +{ + struct prom_args { + char *service; + int nargs; + int nret; + void *virt; + unsigned int size; + } args; + + args.service = "release"; + args.nargs = 2; + args.nret = 0; + args.virt = virt; + args.size = size; + (*prom)(&args); +} + int getprop(void *phandle, const char *name, void *buf, int buflen) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/config.in linux.ac/arch/ppc/config.in --- linux.vanilla/arch/ppc/config.in Tue Apr 3 17:31:55 2001 +++ linux.ac/arch/ppc/config.in Tue Apr 3 23:32:48 2001 @@ -82,6 +82,7 @@ if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "n" ]; then choice 'Machine Type' \ "PowerMac/PReP/MTX/CHRP CONFIG_ALL_PPC \ + Gemini CONFIG_GEMINI \ APUS CONFIG_APUS" PowerMac/PReP/MTX/CHRP fi diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/defconfig linux.ac/arch/ppc/defconfig --- linux.vanilla/arch/ppc/defconfig Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/defconfig Thu Apr 12 17:50:05 2001 @@ -297,7 +297,7 @@ # CONFIG_SCSI_AHA1740 is not set CONFIG_SCSI_AIC7XXX=y CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 -CONFIG_AIC7XXX_RESET_DELAY=15000 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/Makefile linux.ac/arch/ppc/kernel/Makefile --- linux.vanilla/arch/ppc/kernel/Makefile Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/Makefile Tue Apr 3 23:32:48 2001 @@ -7,12 +7,10 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... +USE_STANDARD_AS_RULE := true + ifdef CONFIG_PPC64BRIDGE -.S.o: - $(CC) $(CFLAGS) -D__ASSEMBLY__ -mppc64bridge -c $< -o $*.o -else -.S.o: - $(CC) $(CFLAGS) -D__ASSEMBLY__ -c $< -o $*.o +EXTRA_AFLAGS := -Wa,-mppc64bridge endif ifeq ($(CONFIG_4xx),y) @@ -31,7 +29,7 @@ export-objs := ppc_ksyms.o prep_setup.o -obj-$(CONFIG_PPC) := entry.o traps.o irq.o idle.o time.o misc.o \ +obj-y := entry.o traps.o irq.o idle.o time.o misc.o \ process.o signal.o bitops.o ptrace.o \ ppc_htab.o semaphore.o syscalls.o \ align.o setup.o @@ -54,7 +52,7 @@ ifeq ($(CONFIG_8xx),y) obj-$(CONFIG_PCI) += qspan_pci.c else -obj-$(CONFIG_PPC) += hashtable.o +obj-y += hashtable.o endif obj-$(CONFIG_MATH_EMULATION) += softemu8xx.o obj-$(CONFIG_MBX) += i8259.o @@ -65,6 +63,8 @@ indirect_pci.o i8259.o prep_pci.o \ prep_time.o prep_nvram.o prep_setup.o obj-$(CONFIG_PMAC_BACKLIGHT) += pmac_backlight.o +obj-$(CONFIG_GEMINI) += gemini_prom.o gemini_pci.o gemini_setup.o \ + open_pic.o obj-$(CONFIG_8260) += m8260_setup.o ppc8260_pic.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/apus_setup.c linux.ac/arch/ppc/kernel/apus_setup.c --- linux.vanilla/arch/ppc/kernel/apus_setup.c Mon Jan 22 23:41:15 2001 +++ linux.ac/arch/ppc/kernel/apus_setup.c Tue Apr 3 23:32:48 2001 @@ -1017,6 +1017,59 @@ 0 }; +#define HARDWARE_MAPPED_SIZE (512*1024) +unsigned long __init apus_find_end_of_memory(void) +{ + int shadow = 0; + unsigned long total; + + /* The memory size reported by ADOS excludes the 512KB + reserved for PPC exception registers and possibly 512KB + containing a shadow of the ADOS ROM. */ + { + unsigned long size = memory[0].size; + + /* If 2MB aligned, size was probably user + specified. We can't tell anything about shadowing + in this case so skip shadow assignment. */ + if (0 != (size & 0x1fffff)){ + /* Align to 512KB to ensure correct handling + of both memfile and system specified + sizes. */ + size = ((size+0x0007ffff) & 0xfff80000); + /* If memory is 1MB aligned, assume + shadowing. */ + shadow = !(size & 0x80000); + } + + /* Add the chunk that ADOS does not see. by aligning + the size to the nearest 2MB limit upwards. */ + memory[0].size = ((size+0x001fffff) & 0xffe00000); + } + + total = memory[0].size; + + /* Remove the memory chunks that are controlled by special + Phase5 hardware. */ + + /* Remove the upper 512KB if it contains a shadow of + the ADOS ROM. FIXME: It might be possible to + disable this shadow HW. Check the booter + (ppc_boot.c) */ + if (shadow) + total -= HARDWARE_MAPPED_SIZE; + + /* Remove the upper 512KB where the PPC exception + vectors are mapped. */ + total -= HARDWARE_MAPPED_SIZE; + + /* Linux/APUS only handles one block of memory -- the one on + the PowerUP board. Other system memory is horrible slow in + comparison. The user can use other memory for swapping + using the z2ram device. */ + ram_phys_base = memory[0].addr; + return total; +} __init void apus_init_IRQ(void) @@ -1037,10 +1090,6 @@ amiga_init_IRQ(); - int_control.int_sti = __no_use_sti; - int_control.int_cli = __no_use_cli; - int_control.int_save_flags = __no_use_save_flags; - int_control.int_restore_flags = __no_use_restore_flags; } __init @@ -1072,7 +1121,10 @@ ppc_md.irq_cannonicalize = apus_irq_cannonicalize; ppc_md.init_IRQ = apus_init_IRQ; ppc_md.get_irq = apus_get_irq; - ppc_md.post_irq = apus_post_irq; + +#error Should use the ->end() member of irq_desc[x]. -- Cort + /*ppc_md.post_irq = apus_post_irq;*/ + #ifdef CONFIG_HEARTBEAT ppc_md.heartbeat = apus_heartbeat; ppc_md.heartbeat_count = 1; @@ -1091,6 +1143,8 @@ ppc_md.set_rtc_time = apus_set_rtc_time; ppc_md.get_rtc_time = apus_get_rtc_time; ppc_md.calibrate_decr = apus_calibrate_decr; + + ppc_md.find_end_of_memory = apus_find_end_of_memory; ppc_md.nvram_read_val = NULL; ppc_md.nvram_write_val = NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/chrp_pci.c linux.ac/arch/ppc/kernel/chrp_pci.c --- linux.vanilla/arch/ppc/kernel/chrp_pci.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/chrp_pci.c Tue Apr 3 23:32:48 2001 @@ -298,62 +298,6 @@ bus->resource[1] = &gg2_resources.pci_mem; } -/* this is used by the pmac_pci code too... - paulus */ -void process_bridge_ranges(struct pci_controller *hose, - struct device_node *dev, int primary) -{ - unsigned int *ranges; - int rlen = 0; - int memno = 0; - struct resource *res; - - hose->io_base_phys = 0; - ranges = (unsigned int *) get_property(dev, "ranges", &rlen); - while ((rlen -= 6 * sizeof(unsigned int)) >= 0) { - res = NULL; - switch (ranges[0] >> 24) { - case 1: /* I/O space */ - if (ranges[2] != 0) - break; - hose->io_base_phys = ranges[3]; - hose->io_base_virt = ioremap(ranges[3], ranges[5]); - if (primary) - isa_io_base = (unsigned long) hose->io_base_virt; - res = &hose->io_resource; - res->flags = IORESOURCE_IO; - res->start = ranges[2]; - break; - case 2: /* memory space */ - memno = 0; - if (ranges[1] == 0 && ranges[2] == 0 - && ranges[5] <= (16 << 20)) { - /* 1st 16MB, i.e. ISA memory area */ - if (primary) - isa_mem_base = ranges[3]; - memno = 1; - } - while (memno < 3 && hose->mem_resources[memno].flags) - ++memno; - if (memno == 0) - hose->pci_mem_offset = ranges[3] - ranges[2]; - if (memno < 3) { - res = &hose->mem_resources[memno]; - res->flags = IORESOURCE_MEM; - res->start = ranges[3]; - } - break; - } - if (res != NULL) { - res->name = dev->full_name; - res->end = res->start + ranges[5] - 1; - res->parent = NULL; - res->sibling = NULL; - res->child = NULL; - } - ranges += 6; - } -} - /* this is largely modeled and stolen after the pmac_pci code -- tgall */ @@ -405,7 +349,7 @@ hose->cfg_addr = (volatile unsigned int *) cfg; hose->cfg_data = cfg + 0x10; - process_bridge_ranges(hose, dev, index == 0); + pci_process_bridge_OF_ranges(hose, dev, index == 0); #ifdef CONFIG_POWER3 openpic_setup_ISU(index, opprop[index+1]); @@ -442,7 +386,7 @@ void __init chrp_find_bridges(void) { - struct device_node *py; + struct device_node *py, *dev; char *model, *name; struct pci_controller* hose; @@ -453,7 +397,7 @@ #else /* CONFIG_POWER4 */ model = get_property(find_path_device("/"), "model", NULL); if (!strncmp("MOT", model, 3)) { - struct pci_controller* hose; + struct pci_controller *hose; hose = pcibios_alloc_controller(); if (!hose) @@ -463,8 +407,9 @@ /* Check that please. This must be the root of the OF * PCI tree (the root host bridge */ - hose->arch_data = find_devices("pci"); + hose->arch_data = dev = find_devices("pci"); setup_grackle(hose, 0x20000); + process_bridge_ranges(hose, dev, 1); return; } @@ -485,13 +430,13 @@ /* Check that please. This must be the root of the OF * PCI tree (the root host bridge */ - hose->arch_data = find_devices("pci"); + hose->arch_data = dev = find_devices("pci"); name = get_property(find_path_device("/"), "name", NULL); if (!strncmp("IBM,7043-150", name, 12) || !strncmp("IBM,7046-155", name, 12) || !strncmp("IBM,7046-B50", name, 12) ) { setup_grackle(hose, 0x01000000); - isa_mem_base = 0x80000000; + process_bridge_ranges(hose, dev, 1); return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/chrp_setup.c linux.ac/arch/ppc/kernel/chrp_setup.c --- linux.vanilla/arch/ppc/kernel/chrp_setup.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/chrp_setup.c Tue Apr 3 23:32:48 2001 @@ -67,6 +67,7 @@ void rtas_indicator_progress(char *, unsigned short); void bootx_text_progress(char *, unsigned short); +extern unsigned long pmac_find_end_of_memory(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, @@ -559,11 +560,9 @@ #ifndef CONFIG_POWER4 ppc_md.init_IRQ = chrp_init_IRQ; ppc_md.get_irq = openpic_get_irq; - ppc_md.post_irq = NULL; #else ppc_md.init_IRQ = xics_init_IRQ; ppc_md.get_irq = xics_get_irq; - ppc_md.post_irq = NULL; #endif /* CONFIG_POWER4 */ ppc_md.init = chrp_init2; @@ -576,6 +575,8 @@ ppc_md.set_rtc_time = chrp_set_rtc_time; ppc_md.get_rtc_time = chrp_get_rtc_time; ppc_md.calibrate_decr = chrp_calibrate_decr; + + ppc_md.find_end_of_memory = pmac_find_end_of_memory; #ifdef CONFIG_VT /* these are adjusted in chrp_init2 if we have an ADB keyboard */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/gemini_pci.c linux.ac/arch/ppc/kernel/gemini_pci.c --- linux.vanilla/arch/ppc/kernel/gemini_pci.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ppc/kernel/gemini_pci.c Tue Apr 3 23:32:48 2001 @@ -0,0 +1,121 @@ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/malloc.h> + +#include <asm/machdep.h> +#include <asm/gemini.h> +#include <asm/byteorder.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/pci-bridge.h> + +#include "pci.h" + +#define pci_config_addr(bus,dev,offset) \ + (0x80000000 | (bus<<16) | (dev<<8) | offset) + + +int +gemini_pcibios_read_config_byte(struct pci_dev *dev, int offset, u8 *val) +{ + unsigned long reg; + reg = grackle_read(pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3)))); + *val = ((reg >> ((offset & 0x3) << 3)) & 0xff); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_read_config_word(struct pci_dev *dev, int offset, u16 *val) +{ + unsigned long reg; + reg = grackle_read(pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3)))); + *val = ((reg >> ((offset & 0x3) << 3)) & 0xffff); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_read_config_dword(struct pci_dev *dev, int offset, u32 *val) +{ + *val = grackle_read(pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3)))); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_write_config_byte(struct pci_dev *dev, int offset, u8 val) +{ + unsigned long reg; + int shifts = offset & 0x3; + unsigned int addr = pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3))); + + reg = grackle_read(addr); + reg = (reg & ~(0xff << (shifts << 3))) | (val << (shifts << 3)); + grackle_write(addr, reg ); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_write_config_word(struct pci_dev *dev, int offset, u16 val) +{ + unsigned long reg; + int shifts = offset & 0x3; + unsigned int addr = pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3))); + + reg = grackle_read(addr); + reg = (reg & ~(0xffff << (shifts << 3))) | (val << (shifts << 3)); + grackle_write(addr, reg ); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_write_config_dword(struct pci_dev *dev, int offset, u32 val) +{ + grackle_write(pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3))), val); + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops gemini_pci_ops = +{ + gemini_pcibios_read_config_byte, + gemini_pcibios_read_config_word, + gemini_pcibios_read_config_dword, + gemini_pcibios_write_config_byte, + gemini_pcibios_write_config_word, + gemini_pcibios_write_config_dword +}; + +void __init gemini_pcibios_fixup(void) +{ + int i; + struct pci_dev *dev; + + pci_for_each_dev(dev) { + for(i = 0; i < 6; i++) { + if (dev->resource[i].flags & IORESOURCE_IO) { + dev->resource[i].start |= (0xfe << 24); + dev->resource[i].end |= (0xfe << 24); + } + } + } +} + + +/* The "bootloader" for Synergy boards does none of this for us, so we need to + lay it all out ourselves... --Dan */ +void __init gemini_find_bridges(void) +{ + struct pci_controller* hose; + + ppc_md.pcibios_fixup = gemini_pcibios_fixup; + + hose = pcibios_alloc_controller(); + if (!hose) + return; + hose->ops = &gemini_pci_ops; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/gemini_prom.S linux.ac/arch/ppc/kernel/gemini_prom.S --- linux.vanilla/arch/ppc/kernel/gemini_prom.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ppc/kernel/gemini_prom.S Tue Apr 3 23:32:48 2001 @@ -0,0 +1,96 @@ +/* + * arch/ppc/kernel/gemini_prom.S + * + * Not really prom support code (yet), but sort of anti-prom code. The current + * bootloader does a number of things it shouldn't and doesn't do things that it + * should. The stuff in here is mainly a hodge-podge collection of setup code + * to get the board up and running. + * ---Dan + */ + +#include "ppc_asm.tmpl" +#include "ppc_defs.h" +#include <linux/config.h> +#include <asm/processor.h> +#include <asm/page.h> +#include <asm/gemini.h> + +#define HID0_ABE (1<<3) + +/* + * On 750's the MMU is on when Linux is booted, so we need to clear out the + * bootloader's BAT settings, make sure we're in supervisor state (gotcha!), + * and turn off the MMU. + * + */ + +_GLOBAL(gemini_prom_init) +#ifdef CONFIG_SMP + /* Since the MMU's on, get stuff in rom space that we'll need */ + lis r4,GEMINI_CPUSTAT@h + ori r4,r4,GEMINI_CPUSTAT@l + lbz r5,0(r4) + andi. r5,r5,3 + mr r24,r5 /* cpu # used later on */ +#endif + mfmsr r4 + li r3,MSR_PR /* ensure supervisor! */ + ori r3,r3,MSR_IR|MSR_DR + andc r4,r4,r3 + mtmsr r4 + isync +#if 0 + /* zero out the bats now that the MMU is off */ +prom_no_mmu: + li r3,0 + mtspr IBAT0U,r3 + mtspr IBAT0L,r3 + mtspr IBAT1U,r3 + mtspr IBAT1L,r3 + mtspr IBAT2U,r3 + mtspr IBAT2L,r3 + mtspr IBAT3U,r3 + mtspr IBAT3L,r3 + + mtspr DBAT0U,r3 + mtspr DBAT0L,r3 + mtspr DBAT1U,r3 + mtspr DBAT1L,r3 + mtspr DBAT2U,r3 + mtspr DBAT2L,r3 + mtspr DBAT3U,r3 + mtspr DBAT3L,r3 +#endif + + /* the bootloader (as far as I'm currently aware) doesn't mess with page + tables, but since we're already here, might as well zap these, too */ + li r4,0 + mtspr SDR1,r4 + + li r4,16 + mtctr r4 + li r3,0 + li r4,0 +3: mtsrin r3,r4 + addi r3,r3,1 + bdnz 3b + +#ifdef CONFIG_SMP + /* The 750 book (and Mot/IBM support) says that this will "assist" snooping + when in SMP. Not sure yet whether this should stay or leave... */ + mfspr r4,HID0 + ori r4,r4,HID0_ABE + mtspr HID0,r4 + sync +#endif /* CONFIG_SMP */ + blr + +/* apparently, SMon doesn't pay attention to HID0[SRST]. Disable the MMU and + branch to 0xfff00100 */ +_GLOBAL(_gemini_reboot) + lis r5,GEMINI_BOOT_INIT@h + ori r5,r5,GEMINI_BOOT_INIT@l + li r6,MSR_IP + mtspr SRR0,r5 + mtspr SRR1,r6 + rfi diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/gemini_setup.c linux.ac/arch/ppc/kernel/gemini_setup.c --- linux.vanilla/arch/ppc/kernel/gemini_setup.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ppc/kernel/gemini_setup.c Tue Apr 3 23:32:48 2001 @@ -0,0 +1,537 @@ +/* + * linux/arch/ppc/kernel/setup.c + * + * Copyright (C) 1995 Linus Torvalds + * Adapted from 'alpha' version by Gary Thomas + * Modified by Cort Dougan (cort@cs.nmt.edu) + * Synergy Microsystems board support by Dan Cox (dan@synergymicro.com) + * + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/time.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/blk.h> +#include <linux/console.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/m48t35.h> +#include <asm/gemini.h> +#include <asm/time.h> + +#include "local_irq.h" +#include "open_pic.h" + +void gemini_find_bridges(void); +static int gemini_get_clock_speed(void); +extern void gemini_pcibios_fixup(void); + +static char *gemini_board_families[] = { + "VGM", "VSS", "KGM", "VGR", "VCM", "VCS", "KCM", "VCR" +}; +static int gemini_board_count = sizeof(gemini_board_families) / + sizeof(gemini_board_families[0]); + +static unsigned int cpu_7xx[16] = { + 0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0 +}; +static unsigned int cpu_6xx[16] = { + 0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0 +}; + +int chrp_get_irq(struct pt_regs *); +void chrp_post_irq(struct pt_regs* regs, int); + +static inline unsigned long _get_HID1(void) +{ + unsigned long val; + + __asm__ __volatile__("mfspr %0,1009" : "=r" (val)); + return val; +} + +/* + * prom_init is the Gemini version of prom.c:prom_init. We only need + * the BSS clearing code, so I copied that out of prom.c. This is a + * lot simpler than hacking prom.c so it will build with Gemini. -VAL + */ + +#define PTRRELOC(x) ((typeof(x))((unsigned long)(x) + offset)) + +unsigned long +prom_init(void) +{ + unsigned long offset = reloc_offset(); + unsigned long phys; + extern char __bss_start, _end; + + /* First zero the BSS -- use memset, some arches don't have + * caches on yet */ + memset_io(PTRRELOC(&__bss_start),0 , &_end - &__bss_start); + + /* Default */ + phys = offset + KERNELBASE; + + gemini_prom_init(); + + return phys; +} + +int +gemini_get_cpuinfo(char *buffer) +{ + int len; + unsigned char reg, rev; + char *family; + unsigned int type; + + reg = readb(GEMINI_FEAT); + family = gemini_board_families[((reg>>4) & 0xf)]; + if (((reg>>4) & 0xf) > gemini_board_count) + printk(KERN_ERR "cpuinfo(): unable to determine board family\n"); + + reg = readb(GEMINI_BREV); + type = (reg>>4) & 0xf; + rev = reg & 0xf; + + reg = readb(GEMINI_BECO); + + len = sprintf( buffer, "machine\t\t: Gemini %s%d, rev %c, eco %d\n", + family, type, (rev + 'A'), (reg & 0xf)); + + len = sprintf(buffer, "board\t\t: Gemini %s", family); + if (type > 9) + len += sprintf(buffer+len, "%c", (type - 10) + 'A'); + else + len += sprintf(buffer+len, "%d", type); + + len += sprintf(buffer+len, ", rev %c, eco %d\n", + (rev + 'A'), (reg & 0xf)); + + len += sprintf(buffer+len, "clock\t\t: %dMhz\n", + gemini_get_clock_speed()); + + return len; +} + +static u_char gemini_openpic_initsenses[] = { + 1, + 1, + 1, + 1, + 0, + 0, + 1, /* remainder are level-triggered */ +}; + +#define GEMINI_MPIC_ADDR (0xfcfc0000) +#define GEMINI_MPIC_PCI_CFG (0x80005800) + +void __init gemini_openpic_init(void) +{ + + OpenPIC_Addr = (volatile struct OpenPIC *) + grackle_read(GEMINI_MPIC_PCI_CFG + 0x10); + OpenPIC_InitSenses = gemini_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof( gemini_openpic_initsenses ); + + ioremap( GEMINI_MPIC_ADDR, OPENPIC_SIZE); +} + + +extern unsigned long loops_per_jiffy; +extern int root_mountflags; +extern char cmd_line[]; + +void +gemini_heartbeat(void) +{ + static unsigned long led = GEMINI_LEDBASE+(4*8); + static char direction = 8; + *(char *)led = 0; + if ( (led + direction) > (GEMINI_LEDBASE+(7*8)) || + (led + direction) < (GEMINI_LEDBASE+(4*8)) ) + direction *= -1; + led += direction; + *(char *)led = 0xff; + ppc_md.heartbeat_count = ppc_md.heartbeat_reset; +} + +void __init gemini_setup_arch(void) +{ + extern char cmd_line[]; + + + loops_per_jiffy = 50000000/HZ; + +#ifdef CONFIG_BLK_DEV_INITRD + /* bootable off CDROM */ + if (initrd_start) + ROOT_DEV = MKDEV(SCSI_CDROM_MAJOR, 0); + else +#endif + ROOT_DEV = to_kdev_t(0x0801); + + /* nothing but serial consoles... */ + sprintf(cmd_line, "%s console=ttyS0", cmd_line); + + printk("Boot arguments: %s\n", cmd_line); + + ppc_md.heartbeat = gemini_heartbeat; + ppc_md.heartbeat_reset = HZ/8; + ppc_md.heartbeat_count = 1; + + /* Lookup PCI hosts */ + gemini_find_bridges(); + /* take special pains to map the MPIC, since it isn't mapped yet */ + gemini_openpic_init(); + /* start the L2 */ + gemini_init_l2(); +} + + +int +gemini_get_clock_speed(void) +{ + unsigned long hid1, pvr = _get_PVR(); + int clock; + + hid1 = (_get_HID1() >> 28) & 0xf; + if (PVR_VER(pvr) == 8 || + PVR_VER(pvr) == 12) + hid1 = cpu_7xx[hid1]; + else + hid1 = cpu_6xx[hid1]; + + switch((readb(GEMINI_BSTAT) & 0xc) >> 2) { + + case 0: + default: + clock = (hid1*100)/3; + break; + + case 1: + clock = (hid1*125)/3; + break; + + case 2: + clock = (hid1*50); + break; + } + + return clock; +} + +void __init gemini_init_l2(void) +{ + unsigned char reg, brev, fam, creg; + unsigned long cache; + unsigned long pvr = _get_PVR(); + + reg = readb(GEMINI_L2CFG); + brev = readb(GEMINI_BREV); + fam = readb(GEMINI_FEAT); + + switch(PVR_VER(pvr)) { + + case 8: + if (reg & 0xc0) + cache = (((reg >> 6) & 0x3) << 28); + else + cache = 0x3 << 28; + +#ifdef CONFIG_SMP + /* Pre-3.0 processor revs had snooping errata. Leave + their L2's disabled with SMP. -- Dan */ + if (PVR_CFG(pvr) < 3) { + printk("Pre-3.0 750; L2 left disabled!\n"); + return; + } +#endif /* CONFIG_SMP */ + + /* Special case: VGM5-B's came before L2 ratios were set on + the board. Processor speed shouldn't be too high, so + set L2 ratio to 1:1.5. */ + if ((brev == 0x51) && ((fam & 0xa0) >> 4) == 0) + reg |= 1; + + /* determine best cache ratio based upon what the board + tells us (which sometimes _may_ not be true) and + the processor speed. */ + else { + if (gemini_get_clock_speed() > 250) + reg = 2; + } + break; + case 12: + { + static unsigned long l2_size_val = 0; + + if (!l2_size_val) + l2_size_val = _get_L2CR(); + cache = l2_size_val; + break; + } + case 4: + case 9: + creg = readb(GEMINI_CPUSTAT); + if (((creg & 0xc) >> 2) != 1) + printk("Dual-604 boards don't support the use of L2\n"); + else + writeb(1, GEMINI_L2CFG); + return; + default: + printk("Unknown processor; L2 left disabled\n"); + return; + } + + cache |= ((1<<reg) << 25); + cache |= (L2CR_PIPE_LATEWR|L2CR_L2CTL|L2CR_INST_DISABLE); + _set_L2CR(0); + _set_L2CR(cache | L2CR_L2E); + +} + +void +gemini_restart(char *cmd) +{ + __cli(); + /* make a clean restart, not via the MPIC */ + _gemini_reboot(); + for(;;); +} + +void +gemini_power_off(void) +{ + for(;;); +} + +void +gemini_halt(void) +{ + gemini_restart(NULL); +} + +void __init gemini_init_IRQ(void) +{ + /* gemini has no 8259 */ + openpic_init(1, 0, 0, -1); +} + +#define gemini_rtc_read(x) (readb(GEMINI_RTC+(x))) +#define gemini_rtc_write(val,x) (writeb((val),(GEMINI_RTC+(x)))) + +/* ensure that the RTC is up and running */ +long __init gemini_time_init(void) +{ + unsigned char reg; + + reg = gemini_rtc_read(M48T35_RTC_CONTROL); + + if ( reg & M48T35_RTC_STOPPED ) { + printk(KERN_INFO "M48T35 real-time-clock was stopped. Now starting...\n"); + 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 + +unsigned long +gemini_get_rtc_time(void) +{ + unsigned int year, mon, day, hour, min, sec; + unsigned char reg; + + reg = gemini_rtc_read(M48T35_RTC_CONTROL); + gemini_rtc_write((reg|M48T35_RTC_READ), M48T35_RTC_CONTROL); +#ifdef DEBUG_RTC + printk("get rtc: reg = %x\n", reg); +#endif + + do { + sec = gemini_rtc_read(M48T35_RTC_SECONDS); + min = gemini_rtc_read(M48T35_RTC_MINUTES); + hour = gemini_rtc_read(M48T35_RTC_HOURS); + day = gemini_rtc_read(M48T35_RTC_DOM); + mon = gemini_rtc_read(M48T35_RTC_MONTH); + year = gemini_rtc_read(M48T35_RTC_YEAR); + } while( sec != gemini_rtc_read(M48T35_RTC_SECONDS)); +#ifdef DEBUG_RTC + printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", + sec, min, hour, day, mon, year); +#endif + + gemini_rtc_write(reg, M48T35_RTC_CONTROL); + + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + + if ((year += 1900) < 1970) + year += 100; +#ifdef DEBUG_RTC + printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", + sec, min, hour, day, mon, year); +#endif + + return mktime( year, mon, day, hour, min, sec ); +} + + +int +gemini_set_rtc_time( unsigned long now ) +{ + unsigned char reg; + struct rtc_time tm; + + to_tm( now, &tm ); + + reg = gemini_rtc_read(M48T35_RTC_CONTROL); +#if DEBUG_RTC + printk("set rtc: reg = %x\n", reg); +#endif + + gemini_rtc_write((reg|M48T35_RTC_SET), M48T35_RTC_CONTROL); +#if DEBUG_RTC + printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n", + tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year); +#endif + + tm.tm_year -= 1900; + BIN_TO_BCD(tm.tm_sec); + BIN_TO_BCD(tm.tm_min); + BIN_TO_BCD(tm.tm_hour); + BIN_TO_BCD(tm.tm_mon); + BIN_TO_BCD(tm.tm_mday); + BIN_TO_BCD(tm.tm_year); +#ifdef DEBUG_RTC + printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n", + tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year); +#endif + + gemini_rtc_write(tm.tm_sec, M48T35_RTC_SECONDS); + gemini_rtc_write(tm.tm_min, M48T35_RTC_MINUTES); + gemini_rtc_write(tm.tm_hour, M48T35_RTC_HOURS); + gemini_rtc_write(tm.tm_mday, M48T35_RTC_DOM); + gemini_rtc_write(tm.tm_mon, M48T35_RTC_MONTH); + gemini_rtc_write(tm.tm_year, M48T35_RTC_YEAR); + + /* done writing */ + gemini_rtc_write(reg, M48T35_RTC_CONTROL); + + if ((time_state == TIME_ERROR) || (time_state == TIME_BAD)) + time_state = TIME_OK; + + return 0; +} + +/* use the RTC to determine the decrementer count */ +void __init gemini_calibrate_decr(void) +{ + int freq, divisor; + unsigned char reg; + + /* determine processor bus speed */ + reg = readb(GEMINI_BSTAT); + + switch(((reg & 0x0c)>>2)&0x3) { + case 0: + default: + freq = 66667; + break; + case 1: + freq = 83000; + break; + case 2: + freq = 100000; + break; + } + + freq *= 1000; + divisor = 4; + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); +} + +unsigned long __init gemini_find_end_of_memory(void) +{ + unsigned long total; + unsigned char reg; + + reg = readb(GEMINI_MEMCFG); + total = ((1<<((reg & 0x7) - 1)) * + (8<<((reg >> 3) & 0x7))); + total *= (1024*1024); + return total; +} + +void __init gemini_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + int i; + int chrp_get_irq( struct pt_regs * ); + + for(i = 0; i < GEMINI_LEDS; i++) + gemini_led_off(i); + + ISA_DMA_THRESHOLD = 0; + DMA_MODE_READ = 0; + DMA_MODE_WRITE = 0; + +#ifdef CONFIG_BLK_DEV_INITRD + if ( r4 ) + { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif + + ppc_md.setup_arch = gemini_setup_arch; + ppc_md.setup_residual = NULL; + ppc_md.get_cpuinfo = gemini_get_cpuinfo; + ppc_md.irq_cannonicalize = NULL; + ppc_md.init_IRQ = gemini_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + ppc_md.init = NULL; + + ppc_md.restart = gemini_restart; + ppc_md.power_off = gemini_power_off; + ppc_md.halt = gemini_halt; + + ppc_md.time_init = gemini_time_init; + ppc_md.set_rtc_time = gemini_set_rtc_time; + ppc_md.get_rtc_time = gemini_get_rtc_time; + ppc_md.calibrate_decr = gemini_calibrate_decr; + + ppc_md.find_end_of_memory = gemini_find_end_of_memory; + + /* no keyboard/mouse/video stuff yet.. */ + ppc_md.kbd_setkeycode = NULL; + ppc_md.kbd_getkeycode = NULL; + ppc_md.kbd_translate = NULL; + ppc_md.kbd_unexpected_up = NULL; + ppc_md.kbd_leds = NULL; + ppc_md.kbd_init_hw = NULL; +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.ppc_kbd_sysrq_xlate = NULL; +#endif + ppc_md.pcibios_fixup_bus = gemini_pcibios_fixup; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/head.S linux.ac/arch/ppc/kernel/head.S --- linux.vanilla/arch/ppc/kernel/head.S Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/head.S Tue Apr 3 23:32:48 2001 @@ -161,6 +161,7 @@ bl fix_mem_constants #endif /* CONFIG_APUS */ +#ifndef CONFIG_GEMINI /* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains * the physical address we are running at, returned by prom_init() */ @@ -168,6 +169,7 @@ __after_mmu_off: bl clear_bats bl flush_tlbs +#endif #ifndef CONFIG_POWER4 /* POWER4 doesn't have BATs */ @@ -307,8 +309,13 @@ .long ret_from_except /* System reset */ -#ifdef CONFIG_SMP /* MVME/MTX start the secondary here */ +#ifdef CONFIG_SMP /* MVME/MTX and gemini start the secondary here */ +#ifdef CONFIG_GEMINI + . = 0x100 + b __secondary_start_gemini +#else /* CONFIG_GEMINI */ STD_EXCEPTION(0x100, Reset, __secondary_start_psurge) +#endif /* CONFIG_GEMINI */ #else STD_EXCEPTION(0x100, Reset, UnknownException) #endif @@ -1266,6 +1273,20 @@ #endif /* CONFIG_APUS */ #ifdef CONFIG_SMP +#ifdef CONFIG_GEMINI + .globl __secondary_start_gemini +__secondary_start_gemini: + mfspr r4,HID0 + ori r4,r4,HID0_ICFI + li r3,0 + ori r3,r3,HID0_ICE + andc r4,r4,r3 + mtspr HID0,r4 + sync + bl prom_init + b __secondary_start +#endif /* CONFIG_GEMINI */ + .globl __secondary_start_psurge __secondary_start_psurge: li r24,1 /* cpu # */ @@ -1536,6 +1557,7 @@ * -- Cort */ clear_bats: +#if !defined(CONFIG_GEMINI) li r20,0 mfspr r9,PVR rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ @@ -1559,8 +1581,10 @@ mtspr IBAT2L,r20 mtspr IBAT3U,r20 mtspr IBAT3L,r20 +#endif /* !defined(CONFIG_GEMINI) */ blr +#ifndef CONFIG_GEMINI flush_tlbs: lis r20, 0x40 1: addic. r20, r20, -0x1000 @@ -1579,6 +1603,7 @@ mtspr SRR1,r3 sync RFI +#endif #ifndef CONFIG_POWER4 /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/irq.c linux.ac/arch/ppc/kernel/irq.c --- linux.vanilla/arch/ppc/kernel/irq.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/irq.c Tue Apr 3 23:32:58 2001 @@ -176,9 +176,19 @@ return 0; } -/* This could be promoted to a real free_irq() ... */ -static int -do_free_irq(int irq, void* dev_id) +#if (defined(CONFIG_8xx) || defined(CONFIG_8260)) +/* Name change so we can catch standard drivers that potentially mess up + * the internal interrupt controller on 8xx and 8260. Just bear with me, + * I don't like this either and I am searching a better solution. For + * now, this is what I need. -- Dan + */ +#define request_irq request_8xxirq +#elif defined(CONFIG_APUS) +#define request_irq request_sysirq +#define free_irq sys_free_irq +#endif + +void free_irq(unsigned int irq, void* dev_id) { irq_desc_t *desc; struct irqaction **p; @@ -209,27 +219,15 @@ barrier(); #endif irq_kfree(action); - return 0; + return; } printk("Trying to free free IRQ%d\n",irq); spin_unlock_irqrestore(&desc->lock,flags); break; } - return -ENOENT; + return; } -#if (defined(CONFIG_8xx) || defined(CONFIG_8260)) -/* Name change so we can catch standard drivers that potentially mess up - * the internal interrupt controller on 8xx and 8260. Just bear with me, - * I don't like this either and I am searching a better solution. For - * now, this is what I need. -- Dan - */ -#define request_irq request_8xxirq -#elif defined(CONFIG_APUS) -#define request_irq request_sysirq -#define free_irq sys_free_irq -#endif - int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) { @@ -239,8 +237,17 @@ if (irq >= NR_IRQS) return -EINVAL; if (!handler) - /* We could implement really free_irq() instead of that... */ - return do_free_irq(irq, dev_id); + { + /* + * free_irq() used to be implemented as a call to + * request_irq() with handler being NULL. Now we have + * a real free_irq() but need to allow the old behavior + * for old code that hasn't caught up yet. + * -- Cort <cort@fsmlabs.com> + */ + free_irq(irq, dev_id); + return 0; + } action = (struct irqaction *) irq_kmalloc(sizeof(struct irqaction), GFP_KERNEL); @@ -266,11 +273,6 @@ return 0; } -void free_irq(unsigned int irq, void *dev_id) -{ - request_irq(irq, NULL, 0, NULL, dev_id); -} - /* * Generic enable/disable code: this just calls * down into the PIC-specific version for the actual @@ -546,10 +548,7 @@ goto out; } ppc_irq_dispatch_handler( regs, irq ); - if (ppc_md.post_irq) - ppc_md.post_irq( regs, irq ); - - out: +out: hardirq_exit( cpu ); return 1; /* lets ret_from_int know we can do checks */ } @@ -851,15 +850,18 @@ } #endif /* CONFIG_SMP */ -static struct proc_dir_entry * root_irq_dir; -static struct proc_dir_entry * irq_dir [NR_IRQS]; -static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; +static struct proc_dir_entry *root_irq_dir; +static struct proc_dir_entry *irq_dir[NR_IRQS]; +static struct proc_dir_entry *smp_affinity_entry[NR_IRQS]; #ifdef CONFIG_IRQ_ALL_CPUS -unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0xffffffff}; -#else /* CONFIG_IRQ_ALL_CPUS */ -unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0x00000000}; -#endif /* CONFIG_IRQ_ALL_CPUS */ +#define DEFAULT_CPU_AFFINITY 0xffffffff +#else +#define DEFAULT_CPU_AFFINITY 0x00000001 +#endif + +unsigned int irq_affinity [NR_IRQS] = + { [0 ... NR_IRQS-1] = DEFAULT_CPU_AFFINITY }; #define HEX_DIGITS 8 @@ -919,16 +921,18 @@ err = parse_hex_value(buffer, count, &new_value); -/* Why is this disabled ? --BenH */ -#if 0/*CONFIG_SMP*/ /* * Do not allow disabling IRQs completely - it's a too easy * way to make the system unusable accidentally :-) At least * one online CPU still has to be targeted. + * + * We assume a 1-1 logical<->physical cpu mapping here. If + * we assume that the cpu indices in /proc/irq/../smp_affinity + * are actually logical cpu #'s then we have no problem. + * -- Cort <cort@fsmlabs.com> */ if (!(new_value & cpu_online_map)) return -EINVAL; -#endif irq_affinity[irq] = new_value; irq_desc[irq].handler->set_affinity(irq, new_value); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/m8260_setup.c linux.ac/arch/ppc/kernel/m8260_setup.c --- linux.vanilla/arch/ppc/kernel/m8260_setup.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/m8260_setup.c Tue Apr 3 23:32:58 2001 @@ -212,6 +212,18 @@ } +/* + * Same hack as 8xx + */ +unsigned long __init m8260_find_end_of_memory(void) +{ + bd_t *binfo; + extern unsigned char __res[]; + + binfo = (bd_t *)__res; + + return binfo->bi_memsize; +} void __init m8260_init(unsigned long r3, unsigned long r4, unsigned long r5, @@ -254,18 +266,8 @@ ppc_md.get_rtc_time = m8260_get_rtc_time; ppc_md.calibrate_decr = m8260_calibrate_decr; -#if 0 - ppc_md.kbd_setkeycode = pckbd_setkeycode; - ppc_md.kbd_getkeycode = pckbd_getkeycode; - ppc_md.kbd_pretranslate = pckbd_pretranslate; - ppc_md.kbd_translate = pckbd_translate; - ppc_md.kbd_unexpected_up = pckbd_unexpected_up; - ppc_md.kbd_leds = pckbd_leds; - ppc_md.kbd_init_hw = pckbd_init_hw; -#ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate; -#endif -#else + ppc_md.find_end_of_memory = m8260_find_end_of_memory; + ppc_md.kbd_setkeycode = NULL; ppc_md.kbd_getkeycode = NULL; ppc_md.kbd_translate = NULL; @@ -274,7 +276,6 @@ ppc_md.kbd_init_hw = NULL; #ifdef CONFIG_MAGIC_SYSRQ ppc_md.kbd_sysrq_xlate = NULL; -#endif #endif #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/m8xx_setup.c linux.ac/arch/ppc/kernel/m8xx_setup.c --- linux.vanilla/arch/ppc/kernel/m8xx_setup.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/m8xx_setup.c Tue Apr 3 23:32:58 2001 @@ -590,6 +590,25 @@ /* -------------------------------------------------------------------- */ +/* + * This is a big hack right now, but it may turn into something real + * someday. + * + * For the 8xx boards (at this time anyway), there is nothing to initialize + * associated the PROM. Rather than include all of the prom.c + * functions in the image just to get prom_init, all we really need right + * now is the initialization of the physical memory region. + */ +unsigned long __init m8xx_find_end_of_memory(void) +{ + bd_t *binfo; + extern unsigned char __res[]; + + binfo = (bd_t *)__res; + + return binfo->bi_memsize; +} + void __init m8xx_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/misc.S linux.ac/arch/ppc/kernel/misc.S --- linux.vanilla/arch/ppc/kernel/misc.S Mon Jan 22 23:41:15 2001 +++ linux.ac/arch/ppc/kernel/misc.S Mon Apr 16 12:37:04 2001 @@ -44,7 +44,8 @@ beqlr 1: bdnz 1b blr - +_GLOBAL(__sti_check_lost_end) + /* * Returns (address we're running at) - (address we were linked at) * for use before the text and data are mapped to KERNELBASE. @@ -60,14 +61,29 @@ mtlr r0 blr -/* void __no_use_save_flags(unsigned long *flags) */ -_GLOBAL(__no_use_save_flags) +/* void __save_flags_ptr(unsigned long *flags) */ +_GLOBAL(__save_flags_ptr) mfmsr r4 stw r4,0(r3) blr + /* + * Need these nops here for taking over save/restore to + * handle lost intrs + * -- Cort + */ + nop + nop + nop + nop + nop + nop + nop + nop +_GLOBAL(__save_flags_ptr_end) + -/* void __no_use_restore_flags(unsigned long flags) */ -_GLOBAL(__no_use_restore_flags) +/* void __restore_flags(unsigned long flags) */ +_GLOBAL(__restore_flags) /* * Just set/clear the MSR_EE bit through restore/flags but do not * change anything else. This is needed by the RT system and makes @@ -94,16 +110,30 @@ mtmsr r3 SYNC blr +_GLOBAL(__restore_flags_end) -_GLOBAL(__no_use_cli) +_GLOBAL(__cli) mfmsr r0 /* Get current interrupt state */ rlwinm r3,r0,16+1,32-1,31 /* Extract old value of 'EE' */ rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */ SYNC /* Some chip revs have problems here... */ mtmsr r0 /* Update machine state */ blr /* Done */ + /* + * Need these nops here for taking over save/restore to + * handle lost intrs + * -- Cort + */ + nop + nop + nop + nop + nop + nop +_GLOBAL(__cli_end) -_GLOBAL(__no_use_sti) + +_GLOBAL(__sti) lis r4,ppc_n_lost_interrupts@ha lwz r4,ppc_n_lost_interrupts@l(r4) mfmsr r3 /* Get current state */ @@ -113,6 +143,15 @@ SYNC /* Some chip revs have problems here... */ mtmsr r3 /* Update machine state */ blr + /* + * Need these nops here for taking over save/restore to + * handle lost intrs + * -- Cort + */ + nop + nop + nop +_GLOBAL(__sti_end) /* * We were about to enable interrupts but we have to simulate @@ -141,7 +180,7 @@ * complement mask on the msr then "or" some values on. * _nmask_and_or_msr(nmask, value_to_or) */ - _GLOBAL(_nmask_and_or_msr) +_GLOBAL(_nmask_and_or_msr) mfmsr r0 /* Get current msr */ andc r0,r0,r3 /* And off the bits set in r3 (first parm) */ or r0,r0,r4 /* Or on the bits in r4 (second parm) */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/open_pic.c linux.ac/arch/ppc/kernel/open_pic.c --- linux.vanilla/arch/ppc/kernel/open_pic.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/open_pic.c Tue Apr 3 23:32:58 2001 @@ -775,11 +775,17 @@ int openpic_get_irq(struct pt_regs *regs) { +/* + * Clean up needed. -VAL + */ +#ifndef CONFIG_GEMINI extern int i8259_irq(int cpu); - +#endif int irq = openpic_irq(); /* Management of the cascade should be moved out of here */ + + /* Yep - because openpic !=> i8259, for one thing. -VAL */ if (open_pic_irq_offset && irq == open_pic_irq_offset) { /* @@ -787,8 +793,10 @@ */ if ( chrp_int_ack_special ) irq = *chrp_int_ack_special; +#ifndef CONFIG_GEMINI else irq = i8259_irq( smp_processor_id() ); +#endif openpic_eoi(); } if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/pci.c linux.ac/arch/ppc/kernel/pci.c --- linux.vanilla/arch/ppc/kernel/pci.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/pci.c Tue Apr 3 23:32:58 2001 @@ -399,6 +399,10 @@ return hose; } +#ifdef CONFIG_ALL_PPC +/* + * Functions below are used on OpenFirmware machines. + */ static void make_one_node_map(struct device_node* node, u8 pci_bus) { @@ -577,6 +581,85 @@ *devfn = ((reg[0] >> 8) & 0xff); return 0; } + +void __init +pci_process_bridge_OF_ranges(struct pci_controller *hose, + struct device_node *dev, int primary) +{ + unsigned int *ranges, *prev; + int rlen = 0; + int memno = 0; + struct resource *res; + + /* First we try to merge ranges to fix a problem with some pmacs + * that can have more than 3 ranges, fortunately using contiguous + * addresses -- BenH + */ + ranges = (unsigned int *) get_property(dev, "ranges", &rlen); + prev = NULL; + while ((rlen -= 6 * sizeof(unsigned int)) >= 0) { + if (prev) { + if (prev[0] == ranges[0] && prev[1] == ranges[1] && + (prev[2] + prev[5]) == ranges[2] && + (prev[3] + prev[5]) == ranges[3]) { + prev[5] += ranges[5]; + ranges[0] = 0; + ranges += 6; + continue; + } + } + prev = ranges; + ranges += 6; + } + + rlen = 0; + hose->io_base_phys = 0; + ranges = (unsigned int *) get_property(dev, "ranges", &rlen); + while ((rlen -= 6 * sizeof(unsigned int)) >= 0) { + res = NULL; + switch (ranges[0] >> 24) { + case 1: /* I/O space */ + if (ranges[2] != 0) + break; + hose->io_base_phys = ranges[3]; + hose->io_base_virt = ioremap(ranges[3], ranges[5]); + if (primary) + isa_io_base = (unsigned long) hose->io_base_virt; + res = &hose->io_resource; + res->flags = IORESOURCE_IO; + res->start = ranges[2]; + break; + case 2: /* memory space */ + memno = 0; + if (ranges[1] == 0 && ranges[2] == 0 + && ranges[5] <= (16 << 20)) { + /* 1st 16MB, i.e. ISA memory area */ + if (primary) + isa_mem_base = ranges[3]; + memno = 1; + } + while (memno < 3 && hose->mem_resources[memno].flags) + ++memno; + if (memno == 0) + hose->pci_mem_offset = ranges[3] - ranges[2]; + if (memno < 3) { + res = &hose->mem_resources[memno]; + res->flags = IORESOURCE_MEM; + res->start = ranges[3]; + } + break; + } + if (res != NULL) { + res->name = dev->full_name; + res->end = res->start + ranges[5] - 1; + res->parent = NULL; + res->sibling = NULL; + res->child = NULL; + } + ranges += 6; + } +} +#endif /* CONFIG_ALL_PPC */ void __init pcibios_init(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/pmac_pci.c linux.ac/arch/ppc/kernel/pmac_pci.c --- linux.vanilla/arch/ppc/kernel/pmac_pci.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/pmac_pci.c Tue Apr 3 23:32:58 2001 @@ -29,8 +29,6 @@ #undef DEBUG -extern void process_bridge_ranges(struct pci_controller *hose, - struct device_node *dev, int primary); static void add_bridges(struct device_node *dev); /* XXX Could be per-controller, but I don't think we risk anything by @@ -382,7 +380,7 @@ hose->ops = ¯isc_pci_ops; hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); -#if 0 /* done in process_bridge_ranges now - paulus */ +#if 0 /* done in pci_process_bridge_OF_ranges now - paulus */ hose->io_base_phys = addr->address; /* is 0x10000 enough for io space ? */ hose->io_base_virt = (void *)ioremap(addr->address, 0x10000); @@ -405,7 +403,7 @@ ioremap(addr->address + 0x800000, 0x1000); hose->cfg_data = (volatile unsigned char *) ioremap(addr->address + 0xc00000, 0x1000); -#if 0 /* done in process_bridge_ranges now - paulus */ +#if 0 /* done in pci_process_bridge_OF_ranges now - paulus */ hose->io_base_phys = addr->address; hose->io_base_virt = (void *) ioremap(addr->address, 0x10000); #endif @@ -505,7 +503,7 @@ /* Interpret the "ranges" property */ /* This also maps the I/O region and sets isa_io/mem_base */ - process_bridge_ranges(hose, dev, primary); + pci_process_bridge_OF_ranges(hose, dev, primary); /* Fixup "bus-range" OF property */ fixup_bus_range(dev); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/pmac_pic.c linux.ac/arch/ppc/kernel/pmac_pic.c --- linux.vanilla/arch/ppc/kernel/pmac_pic.c Sat Feb 17 00:02:34 2001 +++ linux.ac/arch/ppc/kernel/pmac_pic.c Tue Apr 3 23:32:58 2001 @@ -44,7 +44,7 @@ * since it can lose interrupts (see pmac_set_irq_mask). * -- Cort */ -void __pmac __no_use_set_lost(unsigned long irq_nr) +void __pmac __set_lost(unsigned long irq_nr) { if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) atomic_inc(&ppc_n_lost_interrupts); @@ -372,8 +372,37 @@ } irqctrler = NULL; } - - int_control.int_set_lost = __no_use_set_lost; + else + { + extern ulong __sti_check_lost, __sti_check_lost_end, + __restore_flags_check_lost, + __restore_flags_check_lost_end; + ulong flags; + + /* + * We need to check for lost intrs in sti, copy the + * checking version of __sti()/__restore_flags() over + * the non-lost intr check __sti()/__restore_flags(). + * + * Since this is only a problem with non-openpic PICs + * we only do it for non-openpic. + * -- Cort <cort@fsmlabs.com> + */ + + __save_flags(flags); + __cli(); + + memcpy( __sti, &__sti_check_lost, + &__sti_check_lost_end - &__sti_check_lost ); + flush_icache_range( (ulong)__sti, (ulong)&__sti_end ); + + memcpy( __restore_flags, &__restore_flags_check_lost, + &__restore_flags_check_lost_end - &__restore_flags_check_lost ); + flush_icache_range( (ulong)__restore_flags, (ulong)&__restore_flags_end ); + + __restore_flags(flags); + } + /* * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts, * 1998 G3 Series PowerBooks have 128, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/pmac_setup.c linux.ac/arch/ppc/kernel/pmac_setup.c --- linux.vanilla/arch/ppc/kernel/pmac_setup.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/pmac_setup.c Tue Apr 3 23:32:58 2001 @@ -66,6 +66,7 @@ #include <asm/time.h> #include "local_irq.h" #include "pmac_pic.h" +#include "../mm/mem_pieces.h" #undef SHOW_GATWICK_IRQS @@ -103,6 +104,8 @@ extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial); +struct device_node *memory_node; + unsigned char drive_info; int ppc_override_l2cr = 0; @@ -470,7 +473,7 @@ char *p; /* Do nothing if the root has been set already. */ - if ((goodness < current_root_goodness) && + if ((goodness <= current_root_goodness) && (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE))) return; p = strstr(saved_command_line, "root="); @@ -635,6 +638,74 @@ #endif #endif +/* + * Read in a property describing some pieces of memory. + */ + +static void __init get_mem_prop(char *name, struct mem_pieces *mp) +{ + struct reg_property *rp; + int s; + + rp = (struct reg_property *) get_property(memory_node, name, &s); + if (rp == NULL) { + printk(KERN_ERR "error: couldn't get %s property on /memory\n", + name); + abort(); + } + mp->n_regions = s / sizeof(mp->regions[0]); + memcpy(mp->regions, rp, s); + + /* Make sure the pieces are sorted. */ + mem_pieces_sort(mp); + mem_pieces_coalesce(mp); +} + +/* + * On systems with Open Firmware, collect information about + * physical RAM and which pieces are already in use. + * At this point, we have (at least) the first 8MB mapped with a BAT. + * Our text, data, bss use something over 1MB, starting at 0. + * Open Firmware may be using 1MB at the 4MB point. + */ +unsigned long __init pmac_find_end_of_memory(void) +{ + unsigned long a, total; + struct mem_pieces phys_mem; + + memory_node = find_devices("memory"); + if (memory_node == NULL) { + printk(KERN_ERR "can't find memory node\n"); + abort(); + } + + /* + * Find out where physical memory is, and check that it + * starts at 0 and is contiguous. It seems that RAM is + * always physically contiguous on Power Macintoshes. + * + * Supporting discontiguous physical memory isn't hard, + * it just makes the virtual <-> physical mapping functions + * more complicated (or else you end up wasting space + * in mem_map). + */ + get_mem_prop("reg", &phys_mem); + if (phys_mem.n_regions == 0) + panic("No RAM??"); + a = phys_mem.regions[0].address; + if (a != 0) + panic("RAM doesn't start at physical address 0"); + total = phys_mem.regions[0].size; + + if (phys_mem.n_regions > 1) { + printk("RAM starting at 0x%x is not contiguous\n", + phys_mem.regions[1].address); + printk("Using RAM from 0 to 0x%lx\n", total-1); + } + + return total; +} + void __init pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) @@ -665,6 +736,8 @@ ppc_md.set_rtc_time = pmac_set_rtc_time; ppc_md.get_rtc_time = pmac_get_rtc_time; ppc_md.calibrate_decr = pmac_calibrate_decr; + + ppc_md.find_end_of_memory = pmac_find_end_of_memory; #ifdef CONFIG_VT #ifdef CONFIG_INPUT diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/ppc8xx_pic.c linux.ac/arch/ppc/kernel/ppc8xx_pic.c --- linux.vanilla/arch/ppc/kernel/ppc8xx_pic.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/ppc8xx_pic.c Tue Apr 3 23:32:58 2001 @@ -158,13 +158,15 @@ */ switch (irq) { #ifdef IDE0_INTERRUPT - case IDE0_INTERRUPT: /* fall through */ + case IDE0_INTERRUPT: /* IDE0 */ + return (request_8xxirq(irq, handler, irqflags, devname, + dev_id)); #endif #ifdef IDE1_INTERRUPT - case IDE1_INTERRUPT: /* fall through */ + case IDE1_INTERRUPT: /* IDE1 */ + return (request_8xxirq(irq, handler, irqflags, devname, + dev_id)); #endif - return (request_8xxirq(irq, handler, irqflags, devname, dev_id)); - default: /* unknown IRQ -> panic */ panic("request_irq"); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/ppc_ksyms.c linux.ac/arch/ppc/kernel/ppc_ksyms.c --- linux.vanilla/arch/ppc/kernel/ppc_ksyms.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/ppc_ksyms.c Tue Apr 3 23:32:58 2001 @@ -315,6 +315,14 @@ EXPORT_SYMBOL(__delay); EXPORT_SYMBOL(int_control); +EXPORT_SYMBOL(__sti); +EXPORT_SYMBOL(__sti_end); +EXPORT_SYMBOL(__cli); +EXPORT_SYMBOL(__cli_end); +EXPORT_SYMBOL(__save_flags_ptr); +EXPORT_SYMBOL(__save_flags_ptr_end); +EXPORT_SYMBOL(__restore_flags); +EXPORT_SYMBOL(__restore_flags_end); EXPORT_SYMBOL(timer_interrupt_intercept); EXPORT_SYMBOL(timer_interrupt); EXPORT_SYMBOL(do_IRQ_intercept); @@ -324,7 +332,6 @@ EXPORT_SYMBOL(tb_ticks_per_jiffy); EXPORT_SYMBOL(get_wchan); EXPORT_SYMBOL(console_drivers); -EXPORT_SYMBOL(console_lock); #ifdef CONFIG_XMON EXPORT_SYMBOL(xmon); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/prep_pci.c linux.ac/arch/ppc/kernel/prep_pci.c --- linux.vanilla/arch/ppc/kernel/prep_pci.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/prep_pci.c Tue Apr 3 23:32:58 2001 @@ -437,8 +437,8 @@ static char ibm8xx_pci_IRQ_routes[] __prepdata = { 0, /* Line 0 - unused */ - 13, /* Line 1 */ - 10, /* Line 2 */ + 15, /* Line 1 */ + 15, /* Line 2 */ 15, /* Line 3 */ 15, /* Line 4 */ }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/prep_setup.c linux.ac/arch/ppc/kernel/prep_setup.c --- linux.vanilla/arch/ppc/kernel/prep_setup.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/prep_setup.c Tue Apr 3 23:32:58 2001 @@ -318,7 +318,9 @@ /* remap the VGA memory */ vgacon_remap_base = 0xf0000000; /*vgacon_remap_base = ioremap(0xc0000000, 0xba000);*/ - conswitchp = &vga_con; + conswitchp = &vga_con; +#else + conswitchp = &dummy_con; #endif } @@ -697,6 +699,35 @@ } #endif +/* + * This finds the amount of physical ram and does necessary + * setup for prep. This is pretty architecture specific so + * this will likely stay separate from the pmac. + * -- Cort + */ +unsigned long __init prep_find_end_of_memory(void) +{ + unsigned long total; +#ifdef CONFIG_PREP_RESIDUAL + total = res->TotalMemory; +#else + total = 0; +#endif + + if (total == 0 ) + { + /* + * I need a way to probe the amount of memory if the residual + * data doesn't contain it. -- Cort + */ + printk("Ramsize from residual data was 0 -- Probing for value\n"); + total = 0x02000000; + printk("Ramsize default to be %ldM\n", total>>20); + } + + return (total); +} + unsigned long *MotSave_SmpIar; unsigned char *MotSave_CpusState[2]; @@ -756,7 +787,8 @@ { if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) ) _prep_type = _PREP_IBM; - _prep_type = _PREP_Motorola; + else + _prep_type = _PREP_Motorola; } else /* assume motorola if no residual (netboot?) */ #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/process.c linux.ac/arch/ppc/kernel/process.c --- linux.vanilla/arch/ppc/kernel/process.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/ppc/kernel/process.c Tue Apr 17 15:38:29 2001 @@ -378,45 +378,6 @@ } /* - * XXX ld.so expects the auxiliary table to start on - * a 16-byte boundary, so we have to find it and - * move it up. :-( - */ -static inline void shove_aux_table(unsigned long sp) -{ - int argc; - char *p; - unsigned long e; - unsigned long aux_start, offset; - - if (__get_user(argc, (int *)sp)) - return; - sp += sizeof(int) + (argc + 1) * sizeof(char *); - /* skip over the environment pointers */ - do { - if (__get_user(p, (char **)sp)) - return; - sp += sizeof(char *); - } while (p != NULL); - aux_start = sp; - /* skip to the end of the auxiliary table */ - do { - if (__get_user(e, (unsigned long *)sp)) - return; - sp += 2 * sizeof(unsigned long); - } while (e != AT_NULL); - offset = ((aux_start + 15) & ~15) - aux_start; - if (offset != 0) { - do { - sp -= sizeof(unsigned long); - if (__get_user(e, (unsigned long *)sp) - || __put_user(e, (unsigned long *)(sp + offset))) - return; - } while (sp > aux_start); - } -} - -/* * Set up a thread for executing a new program */ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp) @@ -425,7 +386,6 @@ regs->nip = nip; regs->gpr[1] = sp; regs->msr = MSR_USER; - shove_aux_table(sp); if (last_task_used_math == current) last_task_used_math = 0; if (last_task_used_altivec == current) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/prom.c linux.ac/arch/ppc/kernel/prom.c --- linux.vanilla/arch/ppc/kernel/prom.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/prom.c Tue Apr 3 23:32:59 2001 @@ -1566,6 +1566,8 @@ } ip = (int *) get_property(np, "AAPL,interrupts", &l); + if (ip == 0 && np->parent) + ip = (int *) get_property(np->parent, "AAPL,interrupts", &l); if (ip == 0) ip = (int *) get_property(np, "interrupts", &l); if (ip != 0) { @@ -1619,6 +1621,8 @@ return mem_start; ip = (int *) get_property(np, "AAPL,interrupts", &l); + if (ip == 0 && np->parent) + ip = (int *) get_property(np->parent, "AAPL,interrupts", &l); if (ip == 0) ip = (int *) get_property(np, "interrupts", &l); if (ip != 0) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/ptrace.c linux.ac/arch/ppc/kernel/ptrace.c --- linux.vanilla/arch/ppc/kernel/ptrace.c Tue Jun 20 01:59:36 2000 +++ linux.ac/arch/ppc/kernel/ptrace.c Tue Apr 3 17:54:35 2001 @@ -10,7 +10,7 @@ * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds * * Modified by Cort Dougan (cort@hq.fsmlabs.com) - * and Paul Mackerras (paulus@linuxcare.com.au). + * and Paul Mackerras (paulus@samba.org). * * 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 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/setup.c linux.ac/arch/ppc/kernel/setup.c --- linux.vanilla/arch/ppc/kernel/setup.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/setup.c Tue Apr 3 23:32:59 2001 @@ -73,6 +73,12 @@ unsigned long r6, unsigned long r7); +extern void gemini_init(unsigned long r3, + unsigned long r4, + unsigned long r5, + unsigned long r6, + unsigned long r7); + #ifdef CONFIG_XMON extern void xmon_map_scc(void); #endif @@ -80,13 +86,7 @@ extern boot_infos_t *boot_infos; char saved_command_line[256]; unsigned char aux_device_present; -struct int_control_struct int_control = -{ - __no_use_cli, - __no_use_sti, - __no_use_restore_flags, - __no_use_save_flags -}; +struct int_control_struct int_control; struct ide_machdep_calls ppc_ide_md; int parse_bootinfo(void); @@ -547,6 +547,11 @@ #ifdef CONFIG_APUS case _MACH_apus: apus_init(r3, r4, r5, r6, r7); + break; +#endif +#ifdef CONFIG_GEMINI + case _MACH_gemini: + gemini_init(r3, r4, r5, r6, r7); break; #endif default: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/smp.c linux.ac/arch/ppc/kernel/smp.c --- linux.vanilla/arch/ppc/kernel/smp.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/smp.c Tue Apr 3 23:32:59 2001 @@ -40,6 +40,7 @@ #include <asm/residual.h> #include <asm/feature.h> #include <asm/time.h> +#include <asm/gemini.h> #include "open_pic.h" int smp_threads_ready; @@ -55,7 +56,7 @@ unsigned int prof_counter[NR_CPUS]; cycles_t cacheflush_time; static int max_cpus __initdata = NR_CPUS; - +unsigned long cpu_online_map; int smp_hw_index[NR_CPUS]; /* all cpu mappings are 1-1 -- Cort */ @@ -628,6 +629,43 @@ do_openpic_setup_cpu(); } +#ifdef CONFIG_GEMINI +static int +smp_gemini_probe(void) +{ + int i, nr; + + nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK) >> 2; + if (nr == 0) + nr = 4; + + if (nr > 1) { + openpic_request_IPIs(); + for (i = 1; i < nr; ++i) + smp_hw_index[i] = i; + } + + return nr; +} + +static void +smp_gemini_kick_cpu(int nr) +{ + openpic_init_processor( 1<<i ); + openpic_init_processor( 0 ); +} + +static void +smp_gemini_setup_cpu(void) +{ + if (OpenPIC_Addr) + do_openpic_setup_cpu(); + if (cpu_nr > 0) + gemini_init_l2(); +} +#endif /* CONFIG_GEMINI */ + + static struct smp_ops_t { void (*message_pass)(int target, int msg, unsigned long data, int wait); int (*probe)(void); @@ -685,6 +723,16 @@ smp_prep_setup_cpu, }; +#ifdef CONFIG_GEMINI +/* Gemini */ +static struct smp_ops_t gemini_smp_ops = { + smp_openpic_message_pass, + smp_gemini_probe, + smp_gemini_kick_cpu, + smp_gemini_setup_cpu, +}; +#endif /* CONFIG_GEMINI */ + /* * Common functions */ @@ -925,6 +973,11 @@ case _MACH_prep: smp_ops = &prep_smp_ops; break; +#ifdef CONFIG_GEMINI + case _MACH_gemini: + smp_ops = &gemini_smp_ops; + break; +#endif /* CONFIG_GEMINI */ default: printk("SMP not supported on this machine.\n"); return; @@ -1114,8 +1167,18 @@ init_idle(); + /* + * This cpu is now "online". Only set them online + * before they enter the loop below since write access + * to the below variable is _not_ guaranteed to be + * atomic. + * -- Cort <cort@fsmlabs.com> + */ + cpu_online_map |= 1UL << smp_processor_id(); + while(!smp_commenced) barrier(); + /* see smp_commence for more info */ if (!smp_tb_synchronized && smp_num_cpus == 2) { smp_software_tb_sync(cpu); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/lib/Makefile linux.ac/arch/ppc/lib/Makefile --- linux.vanilla/arch/ppc/lib/Makefile Mon Jan 22 23:41:15 2001 +++ linux.ac/arch/ppc/lib/Makefile Tue Apr 3 23:32:59 2001 @@ -2,8 +2,7 @@ # Makefile for ppc-specific library files.. # -.S.o: - $(CC) $(AFLAGS) -c $< -o $*.o +USE_STANDARD_AS_RULE := true O_TARGET := lib.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/mm/init.c linux.ac/arch/ppc/mm/init.c --- linux.vanilla/arch/ppc/mm/init.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/mm/init.c Tue Apr 3 23:32:59 2001 @@ -61,12 +61,16 @@ #include <asm/machdep.h> #include <asm/setup.h> #include <asm/amigahw.h> +#include <asm/gemini.h> #include "mem_pieces.h" #if defined(CONFIG_4xx) #include "4xx_tlb.h" #endif +#include <asm/tlb.h> + +mmu_gather_t mmu_gathers[NR_CPUS]; #define MAX_LOW_MEM (512 << 20) @@ -111,19 +115,6 @@ void MMU_init(void); void *early_get_page(void); -unsigned long prep_find_end_of_memory(void); -unsigned long pmac_find_end_of_memory(void); -unsigned long apus_find_end_of_memory(void); -extern unsigned long find_end_of_memory(void); -#ifdef CONFIG_8xx -unsigned long m8xx_find_end_of_memory(void); -#endif /* CONFIG_8xx */ -#ifdef CONFIG_4xx -unsigned long oak_find_end_of_memory(void); -#endif -#ifdef CONFIG_8260 -unsigned long m8260_find_end_of_memory(void); -#endif /* CONFIG_8260 */ static void mapin_ram(void); int map_page(unsigned long va, unsigned long pa, int flags); void set_phys_avail(unsigned long total_ram); @@ -668,33 +659,6 @@ } #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) -static void get_mem_prop(char *, struct mem_pieces *); - -#if defined(CONFIG_ALL_PPC) -/* - * Read in a property describing some pieces of memory. - */ - -static void __init get_mem_prop(char *name, struct mem_pieces *mp) -{ - struct reg_property *rp; - int s; - - rp = (struct reg_property *) get_property(memory_node, name, &s); - if (rp == NULL) { - printk(KERN_ERR "error: couldn't get %s property on /memory\n", - name); - abort(); - } - mp->n_regions = s / sizeof(mp->regions[0]); - memcpy(mp->regions, rp, s); - - /* Make sure the pieces are sorted. */ - mem_pieces_sort(mp); - mem_pieces_coalesce(mp); -} -#endif /* CONFIG_ALL_PPC */ - /* * Set up one of the I/D BAT (block address translation) register pairs. * The parameters are not checked; in particular size must be a power @@ -923,7 +887,7 @@ * at KERNELBASE. */ - total_memory = total_lowmem = oak_find_end_of_memory(); + total_memory = total_lowmem = ppc_md.find_end_of_memory(); end_of_DRAM = __va(total_memory); mapin_ram(); @@ -948,7 +912,7 @@ { if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111); - total_memory = total_lowmem = m8xx_find_end_of_memory(); + total_memory = total_lowmem = ppc_md.find_end_of_memory(); #ifdef CONFIG_HIGHMEM if (total_lowmem > MAX_LOW_MEM) { total_lowmem = MAX_LOW_MEM; @@ -994,19 +958,8 @@ { if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111); - if (have_of) - total_memory = pmac_find_end_of_memory(); -#ifdef CONFIG_APUS - else if (_machine == _MACH_apus ) - total_memory = apus_find_end_of_memory(); -#endif -#if defined(CONFIG_8260) - else - total_memory = m8260_find_end_of_memory(); -#else - else /* prep */ - total_memory = prep_find_end_of_memory(); -#endif + total_memory = ppc_md.find_end_of_memory(); + if (__max_memory && total_memory > __max_memory) total_memory = __max_memory; total_lowmem = total_memory; @@ -1069,6 +1022,10 @@ /* Map chip and ZorroII memory */ setbat(1, zTwoBase, 0x00000000, 0x01000000, IO_PAGE); break; + case _MACH_gemini: + setbat(0, 0xf0000000, 0xf0000000, 0x10000000, IO_PAGE); + setbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE); + break; case _MACH_8260: /* Map the IMMR, plus anything else we can cover * in that upper space according to the memory controller @@ -1257,155 +1214,6 @@ } #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) -#if defined(CONFIG_ALL_PPC) -/* - * On systems with Open Firmware, collect information about - * physical RAM and which pieces are already in use. - * At this point, we have (at least) the first 8MB mapped with a BAT. - * Our text, data, bss use something over 1MB, starting at 0. - * Open Firmware may be using 1MB at the 4MB point. - */ -unsigned long __init pmac_find_end_of_memory(void) -{ - unsigned long a, total; - struct mem_pieces phys_mem; - - memory_node = find_devices("memory"); - if (memory_node == NULL) { - printk(KERN_ERR "can't find memory node\n"); - abort(); - } - - /* - * Find out where physical memory is, and check that it - * starts at 0 and is contiguous. It seems that RAM is - * always physically contiguous on Power Macintoshes. - * - * Supporting discontiguous physical memory isn't hard, - * it just makes the virtual <-> physical mapping functions - * more complicated (or else you end up wasting space - * in mem_map). - */ - get_mem_prop("reg", &phys_mem); - if (phys_mem.n_regions == 0) - panic("No RAM??"); - a = phys_mem.regions[0].address; - if (a != 0) - panic("RAM doesn't start at physical address 0"); - total = phys_mem.regions[0].size; - - if (phys_mem.n_regions > 1) { - printk("RAM starting at 0x%x is not contiguous\n", - phys_mem.regions[1].address); - printk("Using RAM from 0 to 0x%lx\n", total-1); - } - - return total; -} -#endif /* CONFIG_ALL_PPC */ - -#if defined(CONFIG_ALL_PPC) -/* - * This finds the amount of physical ram and does necessary - * setup for prep. This is pretty architecture specific so - * this will likely stay separate from the pmac. - * -- Cort - */ -unsigned long __init prep_find_end_of_memory(void) -{ - unsigned long total; -#ifdef CONFIG_PREP_RESIDUAL - total = res->TotalMemory; -#else - total = 0; -#endif - - if (total == 0 ) - { - /* - * I need a way to probe the amount of memory if the residual - * data doesn't contain it. -- Cort - */ - printk("Ramsize from residual data was 0 -- Probing for value\n"); - total = 0x02000000; - printk("Ramsize default to be %ldM\n", total>>20); - } - - return (total); -} -#endif /* defined(CONFIG_ALL_PPC) */ - -#ifdef CONFIG_8260 -/* - * Same hack as 8xx. - */ -unsigned long __init m8260_find_end_of_memory(void) -{ - bd_t *binfo; - extern unsigned char __res[]; - - binfo = (bd_t *)__res; - - return binfo->bi_memsize; -} -#endif /* CONFIG_8260 */ - -#ifdef CONFIG_APUS -#define HARDWARE_MAPPED_SIZE (512*1024) -unsigned long __init apus_find_end_of_memory(void) -{ - int shadow = 0; - unsigned long total; - - /* The memory size reported by ADOS excludes the 512KB - reserved for PPC exception registers and possibly 512KB - containing a shadow of the ADOS ROM. */ - { - unsigned long size = memory[0].size; - - /* If 2MB aligned, size was probably user - specified. We can't tell anything about shadowing - in this case so skip shadow assignment. */ - if (0 != (size & 0x1fffff)){ - /* Align to 512KB to ensure correct handling - of both memfile and system specified - sizes. */ - size = ((size+0x0007ffff) & 0xfff80000); - /* If memory is 1MB aligned, assume - shadowing. */ - shadow = !(size & 0x80000); - } - - /* Add the chunk that ADOS does not see. by aligning - the size to the nearest 2MB limit upwards. */ - memory[0].size = ((size+0x001fffff) & 0xffe00000); - } - - total = memory[0].size; - - /* Remove the memory chunks that are controlled by special - Phase5 hardware. */ - - /* Remove the upper 512KB if it contains a shadow of - the ADOS ROM. FIXME: It might be possible to - disable this shadow HW. Check the booter - (ppc_boot.c) */ - if (shadow) - total -= HARDWARE_MAPPED_SIZE; - - /* Remove the upper 512KB where the PPC exception - vectors are mapped. */ - total -= HARDWARE_MAPPED_SIZE; - - /* Linux/APUS only handles one block of memory -- the one on - the PowerUP board. Other system memory is horrible slow in - comparison. The user can use other memory for swapping - using the z2ram device. */ - ram_phys_base = memory[0].addr; - return total; -} -#endif /* CONFIG_APUS */ - /* * Initialize the hash table and patch the instructions in head.S. */ @@ -1514,43 +1322,7 @@ } if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205); } -#elif defined(CONFIG_8xx) -/* - * This is a big hack right now, but it may turn into something real - * someday. - * - * For the 8xx boards (at this time anyway), there is nothing to initialize - * associated the PROM. Rather than include all of the prom.c - * functions in the image just to get prom_init, all we really need right - * now is the initialization of the physical memory region. - */ -unsigned long __init m8xx_find_end_of_memory(void) -{ - bd_t *binfo; - extern unsigned char __res[]; - - binfo = (bd_t *)__res; - - return binfo->bi_memsize; -} #endif /* !CONFIG_4xx && !CONFIG_8xx */ - -#ifdef CONFIG_OAK -/* - * Return the virtual address representing the top of physical RAM - * on the Oak board. - */ -unsigned long __init -oak_find_end_of_memory(void) -{ - extern unsigned char __res[]; - - unsigned long *ret; - bd_t *bip = (bd_t *)__res; - - return bip->bi_memsize; -} -#endif /* * Set phys_avail to the amount of physical memory, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/xmon/start.c linux.ac/arch/ppc/xmon/start.c --- linux.vanilla/arch/ppc/xmon/start.c Mon Jan 22 23:41:15 2001 +++ linux.ac/arch/ppc/xmon/start.c Tue Apr 3 23:32:59 2001 @@ -101,6 +101,15 @@ sccc = base + (addr & ~PAGE_MASK); sccd = sccc + 0x10; } + else if ( _machine & _MACH_gemini ) + { + /* should already be mapped by the kernel boot */ + sccc = (volatile unsigned char *) 0xffeffb0d; + sccd = (volatile unsigned char *) 0xffeffb08; + TXRDY = 0x20; + RXRDY = 1; + console = 1; + } else { /* should already be mapped by the kernel boot */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/xmon/start_8xx.c linux.ac/arch/ppc/xmon/start_8xx.c --- linux.vanilla/arch/ppc/xmon/start_8xx.c Wed May 3 09:47:57 2000 +++ linux.ac/arch/ppc/xmon/start_8xx.c Tue Apr 3 23:32:59 2001 @@ -15,7 +15,7 @@ #include <asm/processor.h> #include <asm/8xx_immap.h> #include <asm/mpc8xx.h> -#include "commproc.h" +#include "../8xx_io/commproc.h" extern void xmon_printf(const char *fmt, ...); extern int xmon_8xx_write(char *str, int nb); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/Makefile linux.ac/arch/s390/Makefile --- linux.vanilla/arch/s390/Makefile Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/Makefile Thu Apr 12 11:59:46 2001 @@ -26,10 +26,14 @@ HEAD := arch/s390/kernel/head.o arch/s390/kernel/init_task.o SUBDIRS := $(SUBDIRS) arch/s390/mm arch/s390/kernel arch/s390/lib \ - drivers/s390 + drivers/s390 arch/s390/math-emu CORE_FILES := arch/s390/mm/mm.o arch/s390/kernel/kernel.o $(CORE_FILES) \ drivers/s390/io.o LIBS := $(TOPDIR)/arch/s390/lib/lib.a $(LIBS) $(TOPDIR)/arch/s390/lib/lib.a + +ifeq ($(CONFIG_MATHEMU),y) + CORE_FILES := $(CORE_FILES) arch/s390/math-emu/math-emu.o +endif all: image listing diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/boot/Makefile linux.ac/arch/s390/boot/Makefile --- linux.vanilla/arch/s390/boot/Makefile Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/boot/Makefile Thu Apr 12 11:59:46 2001 @@ -25,7 +25,7 @@ image: $(CONFIGURE) $(TOPDIR)/vmlinux \ iplfba.boot ipleckd.boot ipldump.boot $(OBJCOPY) -O binary $(TOPDIR)/vmlinux image - $(NM) $(TOPDIR)/vmlinux | grep -v '\(compiled\)\|\( [aU] \)\|\(\.\)\|\(LASH[RL]DI\)' | sort > $(TOPDIR)/System.map + $(NM) $(TOPDIR)/vmlinux | grep -v '\(compiled\)\|\( [aUw] \)\|\(\.\)\|\(LASH[RL]DI\)' | sort > $(TOPDIR)/System.map listing: ../../../vmlinux $(OBJDUMP) --disassemble --disassemble-all --disassemble-zeroes --reloc $(TOPDIR)/vmlinux > listing diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/config.in linux.ac/arch/s390/config.in --- linux.vanilla/arch/s390/config.in Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/config.in Thu Apr 12 11:59:46 2001 @@ -28,7 +28,7 @@ mainmenu_option next_comment comment 'Processor type and features' bool 'Symmetric multi-processing support' CONFIG_SMP -bool 'IEEE FPU emulation' CONFIG_IEEEFPU_EMULATION +bool 'IEEE FPU emulation' CONFIG_MATHEMU endmenu mainmenu_option next_comment @@ -44,7 +44,7 @@ bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL -define CONFIG_KCORE ELF +define_bool CONFIG_KCORE_ELF y tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG @@ -65,6 +65,6 @@ if [ "$CONFIG_CTC" = "y" ]; then bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG fi -# this does not work. bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/defconfig linux.ac/arch/s390/defconfig --- linux.vanilla/arch/s390/defconfig Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/defconfig Thu Apr 12 11:59:46 2001 @@ -1,5 +1,5 @@ # -# Automatically generated by make menuconfig: don't edit +# Automatically generated make config: don't edit # # CONFIG_ISA is not set # CONFIG_EISA is not set @@ -13,12 +13,6 @@ CONFIG_EXPERIMENTAL=y # -# Processor type and features -# -CONFIG_SMP=y -CONFIG_IEEEFPU_EMULATION=y - -# # Loadable module support # CONFIG_MODULES=y @@ -26,6 +20,12 @@ CONFIG_KMOD=y # +# Processor type and features +# +CONFIG_SMP=y +CONFIG_MATHEMU=y + +# # General setup # CONFIG_FAST_IRQ=y @@ -36,6 +36,7 @@ CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y +CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set # CONFIG_PROCESS_DEBUG is not set @@ -49,9 +50,14 @@ CONFIG_BLK_DEV_RAM_SIZE=24576 CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_XPRAM=m + +# +# S/390 block device drivers +# CONFIG_DASD=y CONFIG_DASD_ECKD=y CONFIG_DASD_FBA=y +# CONFIG_DASD_DIAG is not set # # Multi-device support (RAID and LVM) @@ -63,20 +69,31 @@ CONFIG_MD_RAID1=m CONFIG_MD_RAID5=m CONFIG_BLK_DEV_LVM=m -CONFIG_LVM_PROC_FS=y # # Character device drivers # CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 + +# +# S/390 character device drivers +# CONFIG_3215=y CONFIG_3215_CONSOLE=y CONFIG_HWC=y CONFIG_HWC_CONSOLE=y CONFIG_S390_TAPE=m + +# +# S/390 tape interface support +# CONFIG_S390_TAPE_CHAR=y CONFIG_S390_TAPE_BLOCK=y + +# +# S/390 tape hardware support +# CONFIG_S390_TAPE_3490=y CONFIG_S390_TAPE_3480=y @@ -88,6 +105,10 @@ CONFIG_NET_ETHERNET=y CONFIG_TR=y # CONFIG_FDDI is not set + +# +# S/390 network device drivers +# # CONFIG_CHANDEV is not set CONFIG_CTC=m CONFIG_IUCV=m @@ -109,11 +130,16 @@ # CONFIG_IP_PNP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set + +# +# +# # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set @@ -138,6 +164,8 @@ # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -192,8 +220,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -211,8 +237,10 @@ # CONFIG_SGI_PARTITION is not set # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # # Kernel hacking # +# CONFIG_MAGIC_SYSRQ is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/Makefile linux.ac/arch/s390/kernel/Makefile --- linux.vanilla/arch/s390/kernel/Makefile Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/Makefile Thu Apr 12 11:59:46 2001 @@ -14,14 +14,13 @@ O_TARGET := kernel.o -export-objs := s390_ksyms.o +export-objs := debug.o ebcdic.o irq.o s390_ext.o smp.o s390_ksyms.o obj-y := lowcore.o entry.o bitmap.o traps.o time.o process.o irq.o \ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ semaphore.o s390fpu.o reipl.o s390_ext.o debug.o obj-$(CONFIG_MODULES) += s390_ksyms.o obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_IEEEFPU_EMULATION) += mathemu.o floatlib.o # # Kernel debugging diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/cpcmd.c linux.ac/arch/s390/kernel/cpcmd.c --- linux.vanilla/arch/s390/kernel/cpcmd.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/cpcmd.c Thu Apr 12 11:59:46 2001 @@ -10,6 +10,7 @@ #include <linux/kernel.h> #include <linux/string.h> #include <asm/ebcdic.h> +#include <asm/cpcmd.h> void cpcmd(char *cmd, char *response, int rlen) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/cpcmd.h linux.ac/arch/s390/kernel/cpcmd.h --- linux.vanilla/arch/s390/kernel/cpcmd.h Fri May 12 19:41:44 2000 +++ linux.ac/arch/s390/kernel/cpcmd.h Thu Jan 1 01:00:00 1970 @@ -1,14 +0,0 @@ -/* - * arch/s390/kernel/cpcmd.h - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), - */ - -#ifndef __CPCMD__ -#define __CPCMD__ - -extern void cpcmd(char *cmd, char *response, int rlen); - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/debug.c linux.ac/arch/s390/kernel/debug.c --- linux.vanilla/arch/s390/kernel/debug.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/debug.c Thu Apr 12 11:59:46 2001 @@ -15,45 +15,53 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/malloc.h> -#include <linux/vmalloc.h> #include <linux/ctype.h> #include <linux/version.h> #include <asm/uaccess.h> #include <asm/semaphore.h> -#ifdef MODULE #include <linux/module.h> -#endif #include <asm/debug.h> #define MIN(a,b) (((a)<(b))?(a):(b)) - -#if defined(CONFIG_ARCH_S390X) -#define DEBUG_PROC_HEADER_SIZE 46 -#else -#define DEBUG_PROC_HEADER_SIZE 38 -#endif - -#define ADD_BUFFER 1000 +#define DEBUG_PROLOG_ENTRY -1 /* 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 */ + loff_t offset; /* offset of last read in file */ + int act_area; /* number of last formated area */ + int act_entry; /* last formated entry (offset */ + /* relative to beginning of last */ + /* formated area) */ + size_t act_entry_offset; /* up to this offset we copied */ + /* in last read the last formated */ + /* entry to userland */ + char temp_buf[2048]; /* buffer for output */ + debug_info_t *debug_info_org; /* original debug information */ + debug_info_t *debug_info_snap; /* snapshot of debug information */ struct debug_view *view; /* used view of debug info */ } file_private_info_t; +typedef struct +{ + char *string; + /* + * This assumes that all args are converted into longs + * on L/390 this is the case for all types of parameter + * except of floats, and long long (32 bit) + * + */ + long args[0]; +} debug_sprintf_entry; + + 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, @@ -83,6 +91,9 @@ static int debug_raw_header_fn(debug_info_t * id, struct debug_view *view, int area, debug_entry_t * entry, char *out_buf); +static int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, debug_sprintf_entry *curr_event); + /* globals */ struct debug_view debug_raw_view = { @@ -90,6 +101,7 @@ NULL, &debug_raw_header_fn, &debug_raw_format_fn, + NULL, NULL }; @@ -98,6 +110,7 @@ NULL, &debug_dflt_header_fn, &debug_hex_ascii_format_fn, + NULL, NULL }; @@ -106,9 +119,22 @@ &debug_prolog_level_fn, NULL, NULL, - &debug_input_level_fn + &debug_input_level_fn, + NULL +}; + +struct debug_view debug_sprintf_view = { + "sprintf", + NULL, + &debug_dflt_header_fn, + (debug_format_proc_t*)&debug_sprintf_format_fn, + NULL, + NULL }; + +unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION; + /* static globals */ static debug_info_t *debug_area_first = NULL; @@ -137,64 +163,108 @@ static struct proc_dir_entry *debug_proc_root_entry; - /* functions */ /* - * debug_info_create - * - create new debug-info + * debug_info_alloc + * - alloc new debug-info */ -static debug_info_t* debug_info_create(char *name, int page_order, +static debug_info_t* debug_info_alloc(char *name, int page_order, int nr_areas, int buf_size) { debug_info_t* rc; int i; - /* alloc everything */ + /* alloc everything */ - rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC); - if(!rc) + rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC); + if(!rc) goto fail_malloc_rc; rc->active_entry = (int*)kmalloc(nr_areas * sizeof(int), GFP_ATOMIC); if(!rc->active_entry) goto fail_malloc_active_entry; memset(rc->active_entry, 0, nr_areas * sizeof(int)); - rc->areas = (debug_entry_t **) kmalloc(nr_areas * - sizeof(debug_entry_t *), - GFP_ATOMIC); - if (!rc->areas) - goto fail_malloc_areas; - 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); - } - goto fail_malloc_areas2; - } else { - memset(rc->areas[i], 0, PAGE_SIZE << page_order); - } - } + rc->areas = (debug_entry_t **) kmalloc(nr_areas * + sizeof(debug_entry_t *), + GFP_ATOMIC); + if (!rc->areas) + goto fail_malloc_areas; + 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); + } + goto fail_malloc_areas2; + } else { + memset(rc->areas[i], 0, PAGE_SIZE << page_order); + } + } + + /* initialize members */ - /* initialize members */ + spin_lock_init(&rc->lock); + 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; + 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->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *)); + memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS * + sizeof(struct proc_dir_entry*)); + atomic_set(&(rc->ref_count), 0); + + return rc; + +fail_malloc_areas2: + kfree(rc->areas); +fail_malloc_areas: + kfree(rc->active_entry); +fail_malloc_active_entry: + kfree(rc); +fail_malloc_rc: + return NULL; +} + +/* + * debug_info_free + * - free memory debug-info + */ + +static void debug_info_free(debug_info_t* db_info){ + int i; + 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); + kfree(db_info->active_entry); + kfree(db_info); +} + +/* + * debug_info_create + * - create new debug-info + */ + +static debug_info_t* debug_info_create(char *name, int page_order, + int nr_areas, int buf_size) +{ + debug_info_t* rc; + + rc = debug_info_alloc(name, page_order, nr_areas, buf_size); + if(!rc) + goto out; + + + /* create proc rood directory */ - spin_lock_init(&rc->lock); - 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; - 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->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *)); - memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS * - sizeof(struct proc_dir_entry*)); - 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 | @@ -216,16 +286,29 @@ rc->next = NULL; debug_info_get(rc); +out: return rc; +} -fail_malloc_areas2: - kfree(rc->areas); -fail_malloc_areas: - kfree(rc->active_entry); -fail_malloc_active_entry: - kfree(rc); -fail_malloc_rc: - return NULL; +/* + * debug_info_copy + * - copy debug-info + */ + +static debug_info_t* debug_info_copy(debug_info_t* in) +{ + int i; + debug_info_t* rc; + rc = debug_info_alloc(in->name, in->page_order, + in->nr_areas, in->buf_size); + if(!rc) + goto out; + + for(i = 0; i < in->nr_areas; i++){ + memcpy(rc->areas[i],in->areas[i], PAGE_SIZE << in->page_order); + } +out: + return rc; } /* @@ -261,49 +344,120 @@ } 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); - kfree(db_info->active_entry); if(db_info == debug_area_first) debug_area_first = db_info->next; if(db_info == debug_area_last) debug_area_last = db_info->prev; if(db_info->prev) db_info->prev->next = db_info->next; if(db_info->next) db_info->next->prev = db_info->prev; - kfree(db_info); + debug_info_free(db_info); } } +/* + * debug_format_entry: + * - format one debug entry and return size of formated data + */ + +static int debug_format_entry(file_private_info_t *p_info) +{ + debug_info_t *id_org = p_info->debug_info_org; + debug_info_t *id_snap = p_info->debug_info_snap; + struct debug_view *view = p_info->view; + debug_entry_t *act_entry; + size_t len = 0; + if(p_info->act_entry == DEBUG_PROLOG_ENTRY){ + /* print prolog */ + if (view->prolog_proc) + len += view->prolog_proc(id_org, view,p_info->temp_buf); + goto out; + } + + act_entry = (debug_entry_t *) ((char*)id_snap->areas[p_info->act_area] + + p_info->act_entry); + + if (act_entry->id.stck == 0LL) + goto out; /* empty entry */ + if (view->header_proc) + len += view->header_proc(id_org, view, p_info->act_area, + act_entry, p_info->temp_buf + len); + if (view->format_proc) + len += view->format_proc(id_org, view, p_info->temp_buf + len, + DEBUG_DATA(act_entry)); + out: + return len; +} + +/* + * debug_next_entry: + * - goto next entry in p_info + */ + +extern inline int debug_next_entry(file_private_info_t *p_info) +{ + debug_info_t *id = p_info->debug_info_snap; + if(p_info->act_entry == DEBUG_PROLOG_ENTRY){ + p_info->act_entry = 0; + goto out; + } + if ((p_info->act_entry += id->entry_size) + > ((PAGE_SIZE << (id->page_order)) + - id->entry_size)){ + + /* next area */ + p_info->act_entry = 0; + p_info->act_area++; + if(p_info->act_area >= id->nr_areas) + return 1; + } +out: + return 0; +} /* * debug_output: * - called for user read() - * - copies formated output form private_data of the file - * handle to the user buffer + * - copies formated debug entries 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 */ + size_t len, /* length of buffer */ loff_t *offset /* offset in the file */ ) { - loff_t len; + size_t count = 0; + size_t entry_offset, size = 0; 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" */ + if (*offset != p_info->offset) + return -EPIPE; + if(p_info->act_area >= p_info->debug_info_snap->nr_areas) + return 0; + + entry_offset = p_info->act_entry_offset; + + while(count < len){ + size = debug_format_entry(p_info); + size = MIN((len - count), (size - entry_offset)); + + if(size){ + if ((rc = copy_to_user(user_buf + count, + p_info->temp_buf + entry_offset, size))) + return rc; + } + count += size; + entry_offset = 0; + if(count != len) + if(debug_next_entry(p_info)) + goto out; } +out: + p_info->offset = *offset + count; + p_info->act_entry_offset = size; + *offset = p_info->offset; + return count; } /* @@ -322,68 +476,16 @@ 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, + rc = p_info->view->input_proc(p_info->debug_info_org, p_info->view, file, user_buf, length, offset); + else + rc = -EPERM; 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, - DEBUG_DATA(act_entry)); - 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 @@ -392,17 +494,14 @@ static int debug_open(struct inode *inode, struct file *file) { - int i = 0, size = 0, rc = 0, f_entry_size = 0; + int i = 0, rc = 0; file_private_info_t *p_info; - debug_info_t* debug_info; + debug_info_t *debug_info, *debug_info_snapshot; #ifdef DEBUG printk("debug_open\n"); #endif - -#ifdef MODULE MOD_INC_USE_COUNT; -#endif down(&debug_lock); /* find debug log and view */ @@ -422,87 +521,41 @@ /* 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"); + + /* make snapshot of current debug areas to get it consistent */ + + debug_info_snapshot = debug_info_copy(debug_info); + + if(!debug_info_snapshot){ + printk(KERN_ERR "debug_open: debug_info_copy failed (out of mem)\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_info->views[i]->prolog_proc) - size += - debug_info->views[i]->prolog_proc(debug_info, - debug_info-> - views[i], NULL); - - if (debug_info->views[i]->header_proc) - f_entry_size = - debug_info->views[i]->header_proc(debug_info, - debug_info-> - views[i], 0, NULL, - NULL); - if (debug_info->views[i]->format_proc) - f_entry_size += - debug_info->views[i]->format_proc(debug_info, - debug_info-> - views[i], NULL, - NULL); - - size += f_entry_size - * (PAGE_SIZE / debug_info->entry_size - << debug_info->page_order) - * debug_info->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); + if ((file->private_data = + kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) { + printk(KERN_ERR "debug_open: kmalloc failed\n"); + debug_info_free(debug_info_snapshot); rc = -ENOMEM; goto out; } - - p_info->size = size; - p_info->debug_info = debug_info; + p_info = (file_private_info_t *) file->private_data; + p_info->offset = 0; + p_info->debug_info_snap = debug_info_snapshot; + p_info->debug_info_org = debug_info; p_info->view = debug_info->views[i]; + p_info->act_area = 0; + p_info->act_entry = DEBUG_PROLOG_ENTRY; + p_info->act_entry_offset = 0; - spin_lock_irq(&debug_info->lock); - - p_info->len = - debug_format_output(debug_info, p_info->data, size, - debug_info->views[i]); -#ifdef DEBUG - { - int ilen = p_info->len; - printk("debug_open: len: %i\n", ilen); - } -#endif - - spin_unlock_irq(&debug_info->lock); debug_info_get(debug_info); out: up(&debug_lock); -#ifdef MODULE if (rc != 0) MOD_DEC_USE_COUNT; -#endif return rc; } @@ -518,18 +571,11 @@ #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 + debug_info_free(p_info->debug_info_snap); + debug_info_put(p_info->debug_info_org); + kfree(file->private_data); MOD_DEC_USE_COUNT; -#endif return 0; /* success */ } @@ -607,9 +653,7 @@ { debug_info_t *rc = NULL; -#ifdef MODULE MOD_INC_USE_COUNT; -#endif if (!initialized) debug_init(); down(&debug_lock); @@ -626,9 +670,7 @@ out: if (rc == NULL){ printk(KERN_ERR "debug: debug_register failed for %s\n",name); -#ifdef MODULE MOD_DEC_USE_COUNT; -#endif } up(&debug_lock); return rc; @@ -648,9 +690,7 @@ debug_info_put(id); up(&debug_lock); -#ifdef MODULE MOD_DEC_USE_COUNT; -#endif out: return; } @@ -662,7 +702,7 @@ void debug_set_level(debug_info_t* id, int new_level) { - long flags; + unsigned long flags; if(!id) return; spin_lock_irqsave(&id->lock,flags); @@ -687,7 +727,7 @@ * - set active entry to next in the ring buffer */ -static inline void proceed_active_entry(debug_info_t * id) +extern 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)) @@ -699,7 +739,7 @@ * - set active area to next in the ring buffer */ -static inline void proceed_active_area(debug_info_t * id) +extern inline void proceed_active_area(debug_info_t * id) { id->active_area++; id->active_area = id->active_area % id->nr_areas; @@ -709,7 +749,7 @@ * get_active_entry: */ -static inline debug_entry_t *get_active_entry(debug_info_t * id) +extern 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]); @@ -720,160 +760,126 @@ * - set timestamp, caller address, cpu number etc. */ -static inline debug_entry_t *debug_common(debug_info_t * id) +extern inline debug_entry_t *debug_common(debug_info_t * id, int level, + const void *buf, int len, int exception) { + unsigned long flags; debug_entry_t *active; + spin_lock_irqsave(&id->lock, flags); 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; + active->id.fields.exception = exception; + active->id.fields.level = level; memset(DEBUG_DATA(active), 0, id->buf_size); memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size)); proceed_active_entry(id); + if(exception) + proceed_active_area(id); spin_unlock_irqrestore(&id->lock, flags); - out: + return active; } /* - * debug_int_event: + * debug_event_common: + * - write debug entry with given size */ -debug_entry_t *debug_int_event(debug_info_t * id, int level, - unsigned int tag) +debug_entry_t *debug_event_common(debug_info_t * id, int level, const 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(DEBUG_DATA(active), 0, id->buf_size); - memcpy(DEBUG_DATA(active), &tag, MIN(sizeof(unsigned int), id->buf_size)); - proceed_active_entry(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; + return debug_common(id, level, buf, len, 0); } /* - * debug_text_event: + * debug_exception_common: + * - write debug entry with given size and switch to next debug area */ -debug_entry_t *debug_text_event(debug_info_t * id, int level, - const char *txt) +debug_entry_t *debug_exception_common(debug_info_t * id, int level, + const 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); - memset(DEBUG_DATA(active), 0, id->buf_size); - strncpy(DEBUG_DATA(active), txt, MIN(strlen(txt), id->buf_size)); - active->id.fields.exception = 0; - proceed_active_entry(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; - + return debug_common(id, level, buf, len, 1); } /* - * debug_exception: + * counts arguments in format string for sprintf view */ -debug_entry_t *debug_exception(debug_info_t * id, int level, void *buf, - int len) +extern inline int debug_count_numargs(char *string) { - long flags; - debug_entry_t *active = NULL; + int numargs=0; - if ((!id) || (level > id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - active->id.fields.exception = 1; - memset(DEBUG_DATA(active), 0, id->buf_size); - memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size)); - proceed_active_entry(id); - proceed_active_area(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; + while(*string) { + if(*string++=='%') + numargs++; + } + return(numargs); } /* - * debug_int_exception: + * debug_sprintf_event: */ -debug_entry_t *debug_int_exception(debug_info_t * id, int level, - unsigned int tag) +debug_entry_t *debug_sprintf_event(debug_info_t* id, + int level,char *string,...) { - long flags; - debug_entry_t *active = NULL; + va_list ap; + int numargs,alloc_size,idx; + debug_sprintf_entry *curr_event; + debug_entry_t *retval = NULL; - if ((!id) || (level > id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - active->id.fields.exception = 1; - memset(DEBUG_DATA(active), 0, id->buf_size); - memcpy(DEBUG_DATA(active), &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; + if((!id) || (level > id->level)) + return NULL; + else { + numargs=debug_count_numargs(string); + alloc_size=offsetof(debug_sprintf_entry,args[numargs]); + curr_event=alloca(alloc_size); + + if(curr_event){ + va_start(ap,string); + curr_event->string=string; + for(idx=0;idx<numargs;idx++) + curr_event->args[idx]=va_arg(ap,long); + retval=debug_common(id,level, curr_event,alloc_size,0); + va_end(ap); + } + return retval; + } } /* - * debug_text_exception: + * debug_sprintf_exception: */ -debug_entry_t *debug_text_exception(debug_info_t * id, int level, - const char *txt) +debug_entry_t *debug_sprintf_exception(debug_info_t* id, + int level,char *string,...) { - 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(DEBUG_DATA(active), 0, id->buf_size); - strncpy(DEBUG_DATA(active), txt, 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; + va_list ap; + int numargs,alloc_size,idx; + debug_sprintf_entry *curr_event; + debug_entry_t *retval = NULL; + if((!id) || (level > id->level)) + return NULL; + else { + numargs=debug_count_numargs(string); + alloc_size=offsetof(debug_sprintf_entry,args[numargs]); + curr_event=alloca(alloc_size); + + if(curr_event){ + va_start(ap,string); + curr_event->string=string; + for(idx=0;idx<numargs;idx++) + curr_event->args[idx]=va_arg(ap,long); + retval=debug_common(id,level, curr_event,alloc_size,1); + va_end(ap); + } + return retval; + } } /* @@ -908,7 +914,7 @@ { int rc = 0; int i; - long flags; + unsigned long flags; mode_t mode = S_IFREG; if (!id) @@ -951,7 +957,7 @@ { int rc = 0; int i; - long flags; + unsigned long flags; if (!id) goto out; @@ -987,13 +993,8 @@ { int rc = 0; - if (out_buf == NULL) { - rc = 2; - goto out; - } if(id->level == -1) rc = sprintf(out_buf,"-\n"); else rc = sprintf(out_buf, "%i\n", id->level); - out: return rc; } @@ -1010,8 +1011,10 @@ if (*offset != 0) goto out; - if ((rc = copy_from_user(input_buf, user_buf, 1))) + if (copy_from_user(input_buf, user_buf, 1)){ + rc = -EFAULT; goto out; + } if (isdigit(input_buf[0])) { int new_level = ((int) input_buf[0] - (int) '0'); debug_set_level(id, new_level); @@ -1036,10 +1039,7 @@ int rc; rc = sizeof(debug_entry_t); - if (out_buf == NULL) - goto out; memcpy(out_buf,entry,sizeof(debug_entry_t)); - out: return rc; } @@ -1053,10 +1053,7 @@ int rc; rc = id->buf_size; - if (out_buf == NULL || in_buf == NULL) - goto out; memcpy(out_buf, in_buf, id->buf_size); - out: return rc; } @@ -1069,10 +1066,6 @@ { int i, rc = 0; - if (out_buf == NULL || in_buf == NULL) { - rc = id->buf_size * 4 + 3; - goto out; - } for (i = 0; i < id->buf_size; i++) { rc += sprintf(out_buf + rc, "%02x ", ((unsigned char *) in_buf)[i]); @@ -1086,7 +1079,6 @@ rc += sprintf(out_buf + rc, "%c", c); } rc += sprintf(out_buf + rc, "\n"); - out: return rc; } @@ -1102,12 +1094,9 @@ char *except_str; unsigned long caller; int rc = 0; + unsigned int level; - if (out_buf == NULL) { - rc = DEBUG_PROC_HEADER_SIZE; - goto out; - } - + level = entry->id.fields.level; time = entry->id.stck; /* adjust todclock to 1970 */ time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096); @@ -1119,18 +1108,60 @@ except_str = "-"; caller = (unsigned long) entry->caller; #if defined(CONFIG_ARCH_S390X) - rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %016lx ", - area, time_val.tv_sec, - time_val.tv_usec, except_str, - entry->id.fields.cpuid, caller); + rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %016lx ", + area, time_val.tv_sec, time_val.tv_usec, level, + except_str, entry->id.fields.cpuid, caller); #else 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); + rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %08lx ", + area, time_val.tv_sec, time_val.tv_usec, level, + except_str, entry->id.fields.cpuid, caller); #endif - out: + return rc; +} + +/* + * prints debug data sprintf-formated: + * debug_sprinf_event/exception calls must be used together with this view + */ + +#define DEBUG_SPRINTF_MAX_ARGS 10 + +int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, debug_sprintf_entry *curr_event) +{ + int num_longs, num_used_args = 0,i, rc = 0; + int index[DEBUG_SPRINTF_MAX_ARGS]; + + /* count of longs fit into one entry */ + num_longs = id->buf_size / sizeof(long); + + if(num_longs < 1) + goto out; /* bufsize of entry too small */ + if(num_longs == 1) { + /* no args, we use only the string */ + strcpy(out_buf, curr_event->string); + rc = strlen(curr_event->string); + goto out; + } + + /* number of arguments used for sprintf (without the format string) */ + num_used_args = MIN(DEBUG_SPRINTF_MAX_ARGS, (num_longs - 1)); + + memset(index,0, DEBUG_SPRINTF_MAX_ARGS * sizeof(int)); + + for(i = 0; i < num_used_args; i++) + index[i] = i; + + rc = sprintf(out_buf, curr_event->string, curr_event->args[index[0]], + curr_event->args[index[1]], curr_event->args[index[2]], + curr_event->args[index[3]], curr_event->args[index[4]], + curr_event->args[index[5]], curr_event->args[index[6]], + curr_event->args[index[7]], curr_event->args[index[8]], + curr_event->args[index[9]]); + +out: + return rc; } @@ -1165,3 +1196,17 @@ } #endif /* MODULE */ + +EXPORT_SYMBOL(debug_register); +EXPORT_SYMBOL(debug_unregister); +EXPORT_SYMBOL(debug_set_level); +EXPORT_SYMBOL(debug_register_view); +EXPORT_SYMBOL(debug_unregister_view); +EXPORT_SYMBOL(debug_event_common); +EXPORT_SYMBOL(debug_exception_common); +EXPORT_SYMBOL(debug_hex_ascii_view); +EXPORT_SYMBOL(debug_raw_view); +EXPORT_SYMBOL(debug_dflt_header_fn); +EXPORT_SYMBOL(debug_sprintf_view); +EXPORT_SYMBOL(debug_sprintf_exception); +EXPORT_SYMBOL(debug_sprintf_event); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/ebcdic.c linux.ac/arch/s390/kernel/ebcdic.c --- linux.vanilla/arch/s390/kernel/ebcdic.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/ebcdic.c Thu Apr 12 11:59:46 2001 @@ -9,6 +9,7 @@ * Martin Peschke <peschke@fh-brandenburg.de> */ +#include <linux/module.h> #include <asm/types.h> /* @@ -389,3 +390,11 @@ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; + +EXPORT_SYMBOL_NOVERS(_ascebc_500); +EXPORT_SYMBOL_NOVERS(_ebcasc_500); +EXPORT_SYMBOL_NOVERS(_ascebc); +EXPORT_SYMBOL_NOVERS(_ebcasc); +EXPORT_SYMBOL_NOVERS(_ebc_tolower); +EXPORT_SYMBOL_NOVERS(_ebc_toupper); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/entry.S linux.ac/arch/s390/kernel/entry.S --- linux.vanilla/arch/s390/kernel/entry.S Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/s390/kernel/entry.S Thu Apr 12 11:59:46 2001 @@ -9,56 +9,52 @@ * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), */ +#define ASSEMBLY + #include <linux/sys.h> #include <linux/linkage.h> #include <linux/config.h> #include <asm/lowcore.h> #include <asm/errno.h> -#define ASSEMBLY #include <asm/smp.h> -#include <asm/s390-regs-common.h> - +#include <asm/ptrace.h> /* - * 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 - * me grief when I modify the pt_regs + * Stack layout for the system_call stack entry. + * The first few entries are identical to the user_regs_struct. */ 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) -SP_R2 = (SP_R1+GPR_SIZE) -SP_R3 = (SP_R2+GPR_SIZE) -SP_R4 = (SP_R3+GPR_SIZE) -SP_R5 = (SP_R4+GPR_SIZE) -SP_R6 = (SP_R5+GPR_SIZE) -SP_R7 = (SP_R6+GPR_SIZE) -SP_R8 = (SP_R7+GPR_SIZE) -SP_R9 = (SP_R8+GPR_SIZE) -SP_RA = (SP_R9+GPR_SIZE) -SP_RB = (SP_RA+GPR_SIZE) -SP_RC = (SP_RB+GPR_SIZE) -SP_RD = (SP_RC+GPR_SIZE) -SP_RE = (SP_RD+GPR_SIZE) -SP_RF = (SP_RE+GPR_SIZE) -SP_AREGS = (SP_RF+GPR_SIZE) -SP_ORIG_R2 = (SP_AREGS+(NUM_ACRS*ACR_SIZE)) +SP_PSW = STACK_FRAME_OVERHEAD + PT_PSWMASK +SP_R0 = STACK_FRAME_OVERHEAD + PT_GPR0 +SP_R1 = STACK_FRAME_OVERHEAD + PT_GPR1 +SP_R2 = STACK_FRAME_OVERHEAD + PT_GPR2 +SP_R3 = STACK_FRAME_OVERHEAD + PT_GPR3 +SP_R4 = STACK_FRAME_OVERHEAD + PT_GPR4 +SP_R5 = STACK_FRAME_OVERHEAD + PT_GPR5 +SP_R6 = STACK_FRAME_OVERHEAD + PT_GPR6 +SP_R7 = STACK_FRAME_OVERHEAD + PT_GPR7 +SP_R8 = STACK_FRAME_OVERHEAD + PT_GPR8 +SP_R9 = STACK_FRAME_OVERHEAD + PT_GPR9 +SP_R10 = STACK_FRAME_OVERHEAD + PT_GPR10 +SP_R11 = STACK_FRAME_OVERHEAD + PT_GPR11 +SP_R12 = STACK_FRAME_OVERHEAD + PT_GPR12 +SP_R13 = STACK_FRAME_OVERHEAD + PT_GPR13 +SP_R14 = STACK_FRAME_OVERHEAD + PT_GPR14 +SP_R15 = STACK_FRAME_OVERHEAD + PT_GPR15 +SP_AREGS = STACK_FRAME_OVERHEAD + PT_ACR0 +SP_ORIG_R2 = STACK_FRAME_OVERHEAD + PT_ORIGGPR2 +/* Now the additional entries */ SP_TRAP = (SP_ORIG_R2+GPR_SIZE) #if CONFIG_REMOTE_DEBUG SP_CRREGS = (SP_TRAP+4) /* 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 - 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_SIZE = (SP_SVC_STEP+4) +SP_SIZE = (SP_PGM_OLD_ILC+4) /* * these defines are offsets into the thread_struct */ @@ -73,6 +69,8 @@ _TSS_TRAP = (_TSS_PROT+4) _TSS_MM = (_TSS_TRAP+4) _TSS_PER = (_TSS_MM+8) +_TSS_IEEE = (_TSS_PER+36) +_TSS_FLAGS = (_TSS_IEEE+4) /* * these are offsets into the task-struct. @@ -84,11 +82,6 @@ tsk_ptrace = 28 processor = 60 -/* PSW related defines */ -disable = 0xFC -enable = 0x03 -daton = 0x04 - /* * Base Address of this Module --- saved in __LC_ENTRY_BASE */ @@ -97,26 +90,6 @@ #define BASED(name) name-entry_base(%r13) -#if 0 -/* some code left lying around in case we need a - * printk for debugging purposes - */ - sysc_printk: .long printk - sysc_msg: .string "<2>r15 %X\n" - .align 4 - -# basr %r13,0 - l %r0,SP_PSW+4(%r15) - sll %r0,1 - chi %r0,0 - jnz sysc_dn - l %r9,sysc_printk-sysc_lit(%r13) - la %r2,sysc_msg-sysc_lit(%r13) - lr %r3,%r15 - basr %r14,%r9 -sysc_dn: -#endif - /* * Register usage in interrupt handlers: * R9 - pointer to current task structure @@ -125,38 +98,41 @@ * R15 - kernel stack pointer */ -#define SAVE_ALL(psworg) \ - stm %r13,%r15,__LC_SAVE_AREA ; \ - stam %a2,%a4,__LC_SAVE_AREA+12 ; \ - basr %r13,0 ; /* temp base pointer */ \ - l %r13,.Lentry_base-.(%r13) ; /* load &entry_base to %r13 */ \ - tm psworg+1,0x01 ; /* test problem state bit */ \ - bz BASED(.+12) ; /* skip stack setup save */ \ - l %r15,__LC_KERNEL_STACK ; /* problem state -> load ksp */ \ - lam %a2,%a4,BASED(.Lc_ac) ; /* set ac.reg. 2 to primary space */ \ - /* and access reg. 4 to home space */ \ -0: s %r15,BASED(.Lc_spsize); /* make room for registers & psw */ \ - n %r15,BASED(.Lc0xfffffff8) ; /* align stack pointer to 8 */ \ - 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. */ \ - 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 */ \ - st %r0,SP_TRAP(%r15) ; \ - xc 0(4,%r15),0(%r15) ; /* clear back chain */ - -#define RESTORE_ALL \ - mvc __LC_RETURN_PSW(8),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 */ \ - ni __LC_RETURN_PSW+1,0xfd ; /* clear wait state bit */ \ - lpsw __LC_RETURN_PSW /* back to caller */ + .macro SAVE_ALL psworg # system entry macro + stm %r13,%r15,__LC_SAVE_AREA + stam %a2,%a4,__LC_SAVE_AREA+12 + basr %r13,0 # temp base pointer + l %r13,.Lentry_base-.(%r13) # load &entry_base to %r13 + tm \psworg+1,0x01 # test problem state bit + bz BASED(.+12) # skip stack setup save + l %r15,__LC_KERNEL_STACK # problem state -> load ksp + lam %a2,%a4,BASED(.Lc_ac) # set ac.reg. 2 to primary space + # and access reg. 4 to home space +0: s %r15,BASED(.Lc_spsize) # make room for registers & psw + n %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8 + 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_R13(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack + 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 + st %r0,SP_TRAP(%r15) + xc 0(4,%r15),0(%r15) # clear back chain + .endm + + .macro RESTORE_ALL # system exit macro + mvc __LC_RETURN_PSW(8),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 + ni __LC_RETURN_PSW+1,0xfd # clear wait state bit + lpsw __LC_RETURN_PSW # back to caller + .endm -#define GET_CURRENT /* load pointer to task_struct to R9 */ \ - lr %r9,%r15 ; \ + .macro GET_CURRENT + lr %r9,%r15 # load pointer to task_struct to %r9 n %r9,BASED(.Lc0xffffe000) + .endm /* @@ -173,7 +149,7 @@ l %r4,_TSS_PTREGS(%r3) 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 %c9,%c11,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 @@ -202,13 +178,13 @@ .globl system_call system_call: - SAVE_ALL(0x20) - xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15) + SAVE_ALL __LC_SVC_OLD_PSW + mvi SP_PGM_OLD_ILC(%r15),1 # mark PGM_OLD_ILC as invalid pgm_system_call: + GET_CURRENT # load pointer to task_struct to R9 slr %r8,%r8 # gpr 8 is call save (-> tracesys) ic %r8,0x8B # get svc number from lowcore stosm 24(%r15),0x03 # reenable interrupts - GET_CURRENT # load pointer to task_struct to R9 sll %r8,2 l %r8,sys_call_table-entry_base(8,%r13) # get address of system call tm tsk_ptrace+3(%r9),0x02 # PT_TRACESYS @@ -219,7 +195,6 @@ # changing anything here !! sysc_return: - GET_CURRENT # load pointer to task_struct to R9 tm SP_PSW+1(%r15),0x01 # returning to user ? bno BASED(sysc_leave) # no-> skip bottom half, resched & signal # @@ -237,9 +212,9 @@ icm %r0,15,sigpending(%r9) # get sigpending from task_struct bnz BASED(sysc_signal_return) sysc_leave: - icm %r0,15,SP_SVC_STEP(%r15) # get sigpending from task_struct - bnz BASED(pgm_svcret) - stnsm 24(%r15),disable # disable I/O and ext. interrupts + tm SP_PGM_OLD_ILC(%r15),0xff + bz BASED(pgm_svcret) + stnsm 24(%r15),0xfc # disable I/O and ext. interrupts RESTORE_ALL # @@ -371,7 +346,7 @@ br %r1 # branch to sys_rt_sigsuspend sys_sigaltstack_glue: - la %r2,SP_PTREGS(%r15) # load pt_regs as parameter + la %r4,SP_PTREGS(%r15) # load pt_regs as parameter l %r1,BASED(.Lsigaltstack) br %r1 # branch to sys_sigreturn @@ -647,20 +622,19 @@ n %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8 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 + mvc SP_R13(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack 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),0x20 # move user PSW to stack 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 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: mvi SP_TRAP+3(%r15),0x28 # set trap indication back to pgm_chk lh %r7,SP_PGM_OLD_ILC(%r15) # get ilc from stack - xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15) + mvi SP_PGM_OLD_ILC(%r15),1 # mark PGM_OLD_ILC as invalid b BASED(pgm_no_sv) pgm_sv: tm 0x29,0x01 # test problem state bit @@ -672,25 +646,25 @@ n %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8 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 + mvc SP_R13(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack 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),0x28 # move user PSW to stack la %r0,0x28 # store trap indication st %r0,SP_TRAP(%r15) xc 0(4,%r15),0(%r15) # clear back chain - xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15) - lh %r7,__LC_PGM_ILC # load instruction length + mvi SP_PGM_OLD_ILC(%r15),1 # mark PGM_OLD_ILC as invalid + lh %r7,__LC_PGM_ILC # load instruction length + GET_CURRENT pgm_no_sv: lh %r8,__LC_PGM_INT_CODE # N.B. saved int code used later KEEP it - stosm 24(%r15),0x03 # reenable interrupts lr %r3,%r8 la %r0,0x7f nr %r3,%r0 # clear per-event-bit be BASED(pgm_dn) # none of Martins exceptions occurred bypass - l %r9,BASED(.Ljump_table) + l %r1,BASED(.Ljump_table) sll %r3,2 - l %r9,0(%r3,%r9) # load address of handler routine + l %r1,0(%r3,%r1) # load address of handler routine la %r2,SP_PTREGS(%r15) # address of register-save area srl %r3,2 cl %r3,BASED(.Lc4) # protection-exception ? @@ -698,14 +672,17 @@ l %r5,SP_PSW+4(15) # load psw addr sr %r5,%r7 # substract ilc from psw st %r5,SP_PSW+4(15) # store corrected psw addr -pgm_go: basr %r14,%r9 # branch to interrupt-handler +pgm_per:cl %r3,BASED(.Lc20) # pseudo page fault ? + be BASED(pgm_go) # if yes then don't reenable interrupts + stosm 24(%r15),0x03 # reenable interrupts +pgm_go: basr %r14,%r1 # branch to interrupt-handler pgm_dn: la %r0,0x80 nr %r8,%r0 # check for per exception be BASED(pgm_return) la %r2,SP_PTREGS(15) # address of register-save area - l %r9,BASED(.Lhandle_per) # load adr. of per handler + l %r1,BASED(.Lhandle_per) # load adr. of per handler la %r14,BASED(sysc_return) # load adr. of system return - br %r9 # branch to handle_per_exception + br %r1 # branch to handle_per_exception # # the backend code is the same as for sys-call @@ -719,19 +696,19 @@ .globl io_int_handler io_int_handler: - SAVE_ALL(0x38) + SAVE_ALL __LC_IO_OLD_PSW + GET_CURRENT # load pointer to task_struct to R9 la %r2,SP_PTREGS(%r15) # address of register-save area sr %r3,%r3 icm %r3,%r3,__LC_SUBCHANNEL_NR # load subchannel nr & extend to int - l %r4,__LC_IO_INT_PARM # load interruption parm - l %r5,__LC_IO_INT_WORD # load interruption word - l %r9,BASED(.Ldo_IRQ) # load address of do_IRQ - basr %r14,%r9 # branch to standard irq handler + l %r4,__LC_IO_INT_PARM # load interuption parm + l %r5,__LC_IO_INT_WORD # load interuption word + l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ + basr %r14,%r1 # branch to standard irq handler io_return: - GET_CURRENT # load pointer to task_struct to R9 tm SP_PSW+1(%r15),0x01 # returning to user ? - bz BASED(io_leave) # no-> skip resched & signal + bno BASED(io_leave) # no-> skip resched & signal stosm 24(%r15),0x03 # reenable interrupts # # check, if bottom-half has to be done @@ -748,7 +725,7 @@ icm %r0,15,sigpending(%r9) # get sigpending from task_struct bnz BASED(io_signal_return) io_leave: - stnsm 24(%r15),disable # disable I/O and ext. interrupts + stnsm 24(%r15),0xfc # disable I/O and ext. interrupts RESTORE_ALL # @@ -784,26 +761,27 @@ .globl ext_int_handler ext_int_handler: - SAVE_ALL(0x18) + SAVE_ALL __LC_EXT_OLD_PSW + GET_CURRENT # load pointer to task_struct to R9 la %r2,SP_PTREGS(%r15) # address of register-save area lh %r3,__LC_EXT_INT_CODE # error code lr %r1,%r3 # calculate index = code & 0xff n %r1,BASED(.Lc0xff) sll %r1,2 - l %r9,BASED(.Lext_hash) - l %r9,0(%r1,%r9) # get first list entry for hash value - ltr %r9,%r9 # == NULL ? + l %r4,BASED(.Lext_hash) + l %r4,0(%r1,%r4) # get first list entry for hash value + ltr %r4,%r4 # == NULL ? bz BASED(io_return) # yes, nothing to do, exit ext_int_loop: - ch %r3,8(%r9) # compare external interrupt code + ch %r3,8(%r4) # compare external interrupt code be BASED(ext_int_found) - icm %r9,15,0(%r9) # next list entry + icm %r4,15,0(%r4) # next list entry bnz BASED(ext_int_loop) b BASED(io_return) ext_int_found: - l %r9,4(%r9) # get handler address + l %r4,4(%r4) # get handler address la %r14,BASED(io_return) - br %r9 # branch to ext call handler + br %r4 # branch to ext call handler /* * Machine check handler routines @@ -811,7 +789,7 @@ .globl mcck_int_handler mcck_int_handler: - SAVE_ALL(0x30) + SAVE_ALL __LC_MCK_OLD_PSW l %r1,BASED(.Ls390_mcck) basr %r14,%r1 # call machine check handler mcck_return: @@ -826,7 +804,7 @@ l %r15,__LC_KERNEL_STACK # load ksp lctl %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs lam %a0,%a15,__LC_AREGS_SAVE_AREA - stosm 0(%r15),daton # now we can turn dat on + stosm 0(%r15),0x04 # now we can turn dat on lm %r6,%r15,24(%r15) # load registers from clone basr %r14,0 l %r14,restart_addr-.(%r14) @@ -859,6 +837,7 @@ .Lc_ac: .long 0,0,1 .Lc_ENOSYS: .long -ENOSYS .Lc4: .long 4 +.Lc20: .long 20 .Lc0x1202: .long 0x1202 .Lc0x1004: .long 0x1004 .Lc0x2401: .long 0x2401 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/floatlib.c linux.ac/arch/s390/kernel/floatlib.c --- linux.vanilla/arch/s390/kernel/floatlib.c Fri May 12 19:41:44 2000 +++ linux.ac/arch/s390/kernel/floatlib.c Thu Jan 1 01:00:00 1970 @@ -1,1021 +0,0 @@ -/* -** libgcc support for software floating point. -** Copyright (C) 1991 by Pipeline Associates, Inc. All rights reserved. -** Permission is granted to do *anything* you want with this file, -** commercial or otherwise, provided this message remains intact. So there! -** I would appreciate receiving any updates/patches/changes that anyone -** makes, and am willing to be the repository for said changes (am I -** making a big mistake?). - -Warning! Only single-precision is actually implemented. This file -won't really be much use until double-precision is supported. - -However, once that is done, this file might eventually become a -replacement for libgcc1.c. It might also make possible -cross-compilation for an IEEE target machine from a non-IEEE -host such as a VAX. - -If you'd like to work on completing this, please talk to rms@gnu.ai.mit.edu. - ---> Double precision floating support added by James Carlson on 20 April 1998. - -** -** Pat Wood -** Pipeline Associates, Inc. -** pipeline!phw@motown.com or -** sun!pipeline!phw or -** uunet!motown!pipeline!phw -** -** 05/01/91 -- V1.0 -- first release to gcc mailing lists -** 05/04/91 -- V1.1 -- added float and double prototypes and return values -** -- fixed problems with adding and subtracting zero -** -- fixed rounding in truncdfsf2 -** -- fixed SWAP define and tested on 386 -*/ - -/* -** The following are routines that replace the libgcc soft floating point -** routines that are called automatically when -msoft-float is selected. -** The support single and double precision IEEE format, with provisions -** for byte-swapped machines (tested on 386). Some of the double-precision -** routines work at full precision, but most of the hard ones simply punt -** and call the single precision routines, producing a loss of accuracy. -** long long support is not assumed or included. -** Overall accuracy is close to IEEE (actually 68882) for single-precision -** arithmetic. I think there may still be a 1 in 1000 chance of a bit -** being rounded the wrong way during a multiply. I'm not fussy enough to -** bother with it, but if anyone is, knock yourself out. -** -** Efficiency has only been addressed where it was obvious that something -** would make a big difference. Anyone who wants to do this right for -** best speed should go in and rewrite in assembler. -** -** I have tested this only on a 68030 workstation and 386/ix integrated -** in with -msoft-float. -*/ - -#define float long -#define double long long - -/* the following deal with IEEE single-precision numbers */ -#define EXCESS 126 -#define SIGNBIT 0x80000000 -#define HIDDEN (1 << 23) -#define SIGN(fp) ((fp) & SIGNBIT) -#define EXP(fp) (((fp) >> 23) & 0xFF) -#define MANT(fp) (((fp) & 0x7FFFFF) | HIDDEN) -#define PACK(s,e,m) ((s) | ((e) << 23) | (m)) - -/* the following deal with IEEE double-precision numbers */ -#define EXCESSD 1022 -#define HIDDEND (1 << 20) -#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) -#define SIGND(fp) ((fp.l.upper) & SIGNBIT) -#define MANTD(fp) (((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) |(fp.l.lower >> 22)) -#define HIDDEND_LL ((long long)1 << 52) -#define MANTD_LL(fp) ((fp.ll & (HIDDEND_LL-1)) | HIDDEND_LL) -#define PACKD_LL(s,e,m) (((long long)((s)+((e)<<20))<<32)|(m)) - -/* define SWAP for 386/960 reverse-byte-order brain-damaged CPUs */ -union double_long { - double d; -#ifdef SWAP - struct { - unsigned long lower; - long upper; - } l; -#else - struct { - long upper; - unsigned long lower; - } l; -#endif - long long ll; -}; - -union float_long - { - float f; - long l; - }; - -long long -__negdi2 (long long u) -{ - - union lll { - long long ll; - long s[2]; - }; - - union lll w,uu; - - uu.ll = u; - - w.s[1] = -uu.s[1]; - w.s[0] = -uu.s[0] - ((int) w.s[1] != 0); - - return w.ll; -} - - - -/* add two floats */ -float -__addsf3 (float a1, float a2) -{ - register long mant1, mant2; - register union float_long fl1, fl2; - register int exp1, exp2; - int sign = 0; - - fl1.f = a1; - fl2.f = a2; - - /* check for zero args */ - if (!fl1.l) { - fl1.f = fl2.f; - goto test_done; - } - if (!fl2.l) - goto test_done; - - exp1 = EXP (fl1.l); - exp2 = EXP (fl2.l); - - if (exp1 > exp2 + 25) - goto test_done; - if (exp2 > exp1 + 25) { - fl1.f = fl2.f; - goto test_done; - } - - /* do everything in excess precision so's we can round later */ - mant1 = MANT (fl1.l) << 6; - mant2 = MANT (fl2.l) << 6; - - if (SIGN (fl1.l)) - mant1 = -mant1; - if (SIGN (fl2.l)) - mant2 = -mant2; - - if (exp1 > exp2) - { - mant2 >>= exp1 - exp2; - } - else - { - mant1 >>= exp2 - exp1; - exp1 = exp2; - } - mant1 += mant2; - - if (mant1 < 0) - { - mant1 = -mant1; - sign = SIGNBIT; - } - else if (!mant1) { - fl1.f = 0; - goto test_done; - } - - /* normalize up */ - while (!(mant1 & 0xE0000000)) - { - mant1 <<= 1; - exp1--; - } - - /* normalize down? */ - if (mant1 & (1 << 30)) - { - mant1 >>= 1; - exp1++; - } - - /* round to even */ - mant1 += (mant1 & 0x40) ? 0x20 : 0x1F; - - /* normalize down? */ - if (mant1 & (1 << 30)) - { - mant1 >>= 1; - exp1++; - } - - /* lose extra precision */ - mant1 >>= 6; - - /* turn off hidden bit */ - mant1 &= ~HIDDEN; - - /* pack up and go home */ - fl1.l = PACK (sign, exp1, mant1); -test_done: - return (fl1.f); -} - -/* subtract two floats */ -float -__subsf3 (float a1, float a2) -{ - register union float_long fl1, fl2; - - fl1.f = a1; - fl2.f = a2; - - /* check for second arg zero */ - if (!fl2.l) - return (fl1.f); - /* twiddle sign bit */ - fl2.l ^= SIGNBIT; - /* check for first arg zero */ - if (!fl1.l) - return (fl2.f); - /* add values */ - return __addsf3 (a1, fl2.f); -} - -/* compare two floats */ -long -__cmpsf2 (float a1, float a2) -{ - register union float_long fl1, fl2; - - fl1.f = a1; - fl2.f = a2; - - if (SIGN (fl1.l) && SIGN (fl2.l)) - { - fl1.l ^= SIGNBIT; - fl2.l ^= SIGNBIT; - if (fl1.l < fl2.l) - return (-1); - if (fl1.l > fl2.l) - return (1); - return 0; - } else { - if (fl1.l < fl2.l) - return (-1); - if (fl1.l > fl2.l) - return (1); - return (0); - } -} - -/* multiply two floats */ -float -__mulsf3 (float a1, float a2) -{ - register union float_long fl1, fl2; - register unsigned long result; - register int exp; - int sign; - - fl1.f = a1; - fl2.f = a2; - - if (!fl1.l || !fl2.l) { - fl1.f = 0; - goto test_done; - } - - /* compute sign and exponent */ - sign = SIGN (fl1.l) ^ SIGN (fl2.l); - exp = EXP (fl1.l) - EXCESS; - exp += EXP (fl2.l); - - fl1.l = MANT (fl1.l); - fl2.l = MANT (fl2.l); - - /* the multiply is done as one 16x16 multiply and two 16x8 multiples */ - result = (fl1.l >> 8) * (fl2.l >> 8); - result += ((fl1.l & 0xFF) * (fl2.l >> 8)) >> 8; - result += ((fl2.l & 0xFF) * (fl1.l >> 8)) >> 8; - - result >>= 2; - if (result & 0x20000000) - { - /* round */ - result += 0x20; - result >>= 6; - } - else - { - /* round */ - result += 0x10; - result >>= 5; - exp--; - } - if (result & (HIDDEN<<1)) { - result >>= 1; - exp++; - } - - result &= ~HIDDEN; - - /* pack up and go home */ - fl1.l = PACK (sign, exp, result); -test_done: - return (fl1.f); -} - -/* divide two floats */ -float -__divsf3 (float a1, float a2) -{ - register union float_long fl1, fl2; - register int result; - register int mask; - register int exp, sign; - - fl1.f = a1; - fl2.f = a2; - - /* subtract exponents */ - exp = EXP (fl1.l) - EXP (fl2.l) + EXCESS; - - /* compute sign */ - sign = SIGN (fl1.l) ^ SIGN (fl2.l); - - /* divide by zero??? */ - if (!fl2.l) - /* return NaN or -NaN */ - return (sign ? 0xFFFFFFFF : 0x7FFFFFFF); - - /* numerator zero??? */ - if (!fl1.l) - return (0); - - /* now get mantissas */ - fl1.l = MANT (fl1.l); - fl2.l = MANT (fl2.l); - - /* this assures we have 25 bits of precision in the end */ - if (fl1.l < fl2.l) - { - fl1.l <<= 1; - exp--; - } - - /* now we perform repeated subtraction of fl2.l from fl1.l */ - mask = 0x1000000; - result = 0; - while (mask) - { - if (fl1.l >= fl2.l) - { - result |= mask; - fl1.l -= fl2.l; - } - fl1.l <<= 1; - mask >>= 1; - } - - /* round */ - result += 1; - - /* normalize down */ - exp++; - result >>= 1; - - result &= ~HIDDEN; - - /* pack up and go home */ - fl1.l = PACK (sign, exp, result); - return (fl1.f); -} - -/* convert double to float */ -float -__truncdfsf2 (double a1) -{ - register int exp; - register long mant; - register union float_long fl; - register union double_long dl1; - - dl1.d = a1; - - if (!dl1.l.upper && !dl1.l.lower) - return (float)(0); - - exp = EXPD (dl1) - EXCESSD + EXCESS; - - /* shift double mantissa 6 bits so we can round */ - mant = MANTD (dl1) >> 6; - - /* now round and shift down */ - mant += 1; - mant >>= 1; - - /* did the round overflow? */ - if (mant & 0xFF000000) - { - mant >>= 1; - exp++; - } - - mant &= ~HIDDEN; - - /* pack up and go home */ - fl.l = PACK (SIGND (dl1), exp, mant); - return (fl.f); -} - -/* convert int to double */ -double -__floatsidf (register long a1) -{ - register int sign = 0, exp = 31 + EXCESSD; - union double_long dl; - - if (a1 == 0x80000000) - { - /* - * -a1 would be 0 ! - */ - dl.l.upper = 0xc1e00000; - dl.l.lower = 0x0; - return (dl.d); - } - - if (!a1) - { - dl.l.upper = dl.l.lower = 0; - return (dl.d); - } - - if (a1 < 0) - { - sign = SIGNBIT; - a1 = -a1; - } - - while (a1 < 0x1000000) - { - a1 <<= 4; - exp -= 4; - } - - while (a1 < 0x40000000) - { - a1 <<= 1; - exp--; - } - - /* pack up and go home */ - dl.l.upper = sign; - dl.l.upper |= exp << 20; - dl.l.upper |= (a1 >> 10) & ~HIDDEND; - dl.l.lower = a1 << 22; - - return (dl.d); -} - -double -__floatdidf (register long long a1) -{ - register int exp = 63 + EXCESSD; - union double_long dl; - - dl.l.upper = dl.l.lower = 0; - if (a1 == 0) - return (dl.d); - - if (a1 < 0) { - dl.l.upper = SIGNBIT; - a1 = -a1; - } - - while (a1 < (long long)1<<54) { - a1 <<= 8; - exp -= 8; - } - while (a1 < (long long)1<<62) { - a1 <<= 1; - exp -= 1; - } - /* pack up and go home */ - dl.ll |= (a1 >> 10) & ~HIDDEND_LL; - dl.l.upper |= exp << 20; - - return (dl.d); -} - -float -__floatsisf (register long a1) -{ - return __truncdfsf2(__floatsidf(a1)); -} - -float -__floatdisf (register long long a1) -{ - return (float)__floatdidf(a1); -} -/* negate a float */ -float -__negsf2 (float a1) -{ - register union float_long fl1; - - fl1.f = a1; - if (!fl1.l) - return (0); - - fl1.l ^= SIGNBIT; - return (fl1.f); -} - -/* negate a double */ -double -__negdf2 (double a1) -{ - register union double_long dl1; - - dl1.d = a1; - - if (!dl1.l.upper && !dl1.l.lower) - return (dl1.d); - - dl1.l.upper ^= SIGNBIT; - return (dl1.d); -} - -/* convert float to double */ -double -__extendsfdf2 (float a1) -{ - register union float_long fl1; - register union double_long dl; - register int exp; - - fl1.f = a1; - - if (!fl1.l) - { - dl.l.upper = dl.l.lower = 0; - return (dl.d); - } - - dl.l.upper = SIGN (fl1.l); - exp = EXP (fl1.l) - EXCESS + EXCESSD; - dl.l.upper |= exp << 20; - dl.l.upper |= (MANT (fl1.l) & ~HIDDEN) >> 3; - dl.l.lower = MANT (fl1.l) << 29; - - return (dl.d); -} - - -/* compare two doubles */ -long -__cmpdf2 (double a1, double a2) -{ - register union double_long dl1, dl2; - - dl1.d = a1; - dl2.d = a2; - - if (SIGND (dl1) && SIGND (dl2)) - { - dl1.l.upper ^= SIGNBIT; - dl2.l.upper ^= SIGNBIT; - if (dl1.l.upper < dl2.l.upper) - return (1); - if (dl1.l.upper > dl2.l.upper) - return (-1); - if (dl1.l.lower < dl2.l.lower) - return (1); - if (dl1.l.lower > dl2.l.lower) - return (-1); - return (0); - } else { - if (dl1.l.upper < dl2.l.upper) - return (-1); - if (dl1.l.upper > dl2.l.upper) - return (1); - if (dl1.l.lower < dl2.l.lower) - return (-1); - if (dl1.l.lower > dl2.l.lower) - return (1); - return (0); - } -} - -/* convert double to int */ -long -__fixdfsi (double a1) -{ - register union double_long dl1; - register int exp; - register long l; - - dl1.d = a1; - - if (!dl1.l.upper && !dl1.l.lower) - return (0); - - exp = EXPD (dl1) - EXCESSD - 31; - l = MANTD (dl1); - - if (exp > 0) - return SIGND(dl1) ? (1<<31) : ((1ul<<31)-1); - - /* shift down until exp = 0 or l = 0 */ - if (exp <= 0 && exp > -32 && l) - l >>= -exp; - else - return (0); - - return (SIGND (dl1) ? -l : l); -} - -/* convert float to int */ -long -__fixsfsi (float a1) -{ - return __fixdfsi(__extendsfdf2(a1)); -} - -/* convert double to int */ -long long -__fixdfdi (double a1) -{ - register union double_long dl1; - register int exp; - register long long l; - - dl1.d = a1; - - if (!dl1.l.upper && !dl1.l.lower) - return (0); - - exp = EXPD (dl1) - EXCESSD - 64; - l = MANTD_LL(dl1); - - if (exp > 0) { - l = (long long)1<<63; - if (!SIGND(dl1)) - l--; - return l; - } - - /* shift down until exp = 0 or l = 0 */ - if (exp <= 0 && exp > -64 && l) - l >>= -exp; - else - return (0); - - return (SIGND (dl1) ? -l : l); -} - -/* convert double to unsigned int */ -unsigned long -__fixunsdfsi (double a1) -{ - register union double_long dl1; - register int exp; - register unsigned long l; - - dl1.d = a1; - - if (!dl1.l.upper && !dl1.l.lower) - return (0); - - exp = EXPD (dl1) - EXCESSD - 32; - l = (((((dl1.l.upper) & 0xFFFFF) | HIDDEND) << 11) | (dl1.l.lower >> 21)); - - if (exp > 0) - return (0xFFFFFFFFul); /* largest integer */ - - /* shift down until exp = 0 or l = 0 */ - if (exp < 0 && exp > -32 && l) - l >>= -exp; - else - return (0); - - return (l); -} - -/* convert double to unsigned int */ -unsigned long long -__fixunsdfdi (double a1) -{ - register union double_long dl1; - register int exp; - register unsigned long long l; - - dl1.d = a1; - - if (dl1.ll == 0) - return (0); - - exp = EXPD (dl1) - EXCESSD - 64; - - l = dl1.ll; - - if (exp > 0) - return (unsigned long long)-1; - - /* shift down until exp = 0 or l = 0 */ - if (exp < 0 && exp > -64 && l) - l >>= -exp; - else - return (0); - - return (l); -} - -/* addtwo doubles */ -double -__adddf3 (double a1, double a2) -{ - register long long mant1, mant2; - register union double_long fl1, fl2; - register int exp1, exp2; - int sign = 0; - - fl1.d = a1; - fl2.d = a2; - - /* check for zero args */ - if (!fl2.ll) - goto test_done; - if (!fl1.ll) { - fl1.d = fl2.d; - goto test_done; - } - - exp1 = EXPD(fl1); - exp2 = EXPD(fl2); - - if (exp1 > exp2 + 54) - goto test_done; - if (exp2 > exp1 + 54) { - fl1.d = fl2.d; - goto test_done; - } - - /* do everything in excess precision so's we can round later */ - mant1 = MANTD_LL(fl1) << 9; - mant2 = MANTD_LL(fl2) << 9; - - if (SIGND(fl1)) - mant1 = -mant1; - if (SIGND(fl2)) - mant2 = -mant2; - - if (exp1 > exp2) - mant2 >>= exp1 - exp2; - else { - mant1 >>= exp2 - exp1; - exp1 = exp2; - } - mant1 += mant2; - - if (mant1 < 0) { - mant1 = -mant1; - sign = SIGNBIT; - } else if (!mant1) { - fl1.d = 0; - goto test_done; - } - - /* normalize up */ - while (!(mant1 & ((long long)7<<61))) { - mant1 <<= 1; - exp1--; - } - - /* normalize down? */ - if (mant1 & ((long long)3<<62)) { - mant1 >>= 1; - exp1++; - } - - /* round to even */ - mant1 += (mant1 & (1<<9)) ? (1<<8) : ((1<<8)-1); - - /* normalize down? */ - if (mant1 & ((long long)3<<62)) { - mant1 >>= 1; - exp1++; - } - - /* lose extra precision */ - mant1 >>= 9; - - /* turn off hidden bit */ - mant1 &= ~HIDDEND_LL; - - /* pack up and go home */ - fl1.ll = PACKD_LL(sign,exp1,mant1); - -test_done: - return (fl1.d); -} - -/* subtract two doubles */ -double -__subdf3 (double a1, double a2) -{ - register union double_long fl1, fl2; - - fl1.d = a1; - fl2.d = a2; - - /* check for zero args */ - if (!fl2.ll) - return (fl1.d); - /* twiddle sign bit and add */ - fl2.l.upper ^= SIGNBIT; - if (!fl1.ll) - return (fl2.d); - return __adddf3 (a1, fl2.d); -} - -/* multiply two doubles */ -double -__muldf3 (double a1, double a2) -{ - register union double_long fl1, fl2; - register unsigned long long result=0ULL; - register int exp; - int sign; - - fl1.d = a1; - fl2.d = a2; - - if (!fl1.ll || !fl2.ll) { - fl1.d = 0; - goto test_done; - } - - /* compute sign and exponent */ - sign = SIGND(fl1) ^ SIGND(fl2); - exp = EXPD(fl1) - EXCESSD; - exp += EXPD(fl2); - - fl1.ll = MANTD_LL(fl1); - fl2.ll = MANTD_LL(fl2); - - /* the multiply is done as one 31x31 multiply and two 31x21 multiples */ - result = (fl1.ll >> 21) * (fl2.ll >> 21); - result += ((fl1.ll & 0x1FFFFF) * (fl2.ll >> 21)) >> 21; - result += ((fl2.ll & 0x1FFFFF) * (fl1.ll >> 21)) >> 21; - - result >>= 2; - if (result & ((long long)1<<61)) { - /* round */ - result += 1<<8; - result >>= 9; - } else { - /* round */ - result += 1<<7; - result >>= 8; - exp--; - } - if (result & (HIDDEND_LL<<1)) { - result >>= 1; - exp++; - } - - result &= ~HIDDEND_LL; - - /* pack up and go home */ - fl1.ll = PACKD_LL(sign,exp,result); -test_done: - return (fl1.d); -} - -/* divide two doubles */ -double -__divdf3 (double a1, double a2) -{ - register union double_long fl1, fl2; - register long long mask,result; - register int exp, sign; - - fl1.d = a1; - fl2.d = a2; - - /* subtract exponents */ - exp = EXPD(fl1) - EXPD(fl2) + EXCESSD; - - /* compute sign */ - sign = SIGND(fl1) ^ SIGND(fl2); - - /* numerator zero??? */ - if (fl1.ll == 0) { - /* divide by zero??? */ - if (fl2.ll == 0) - fl1.ll = ((unsigned long long)1<<63)-1; /* NaN */ - else - fl1.ll = 0; - goto test_done; - } - - /* return +Inf or -Inf */ - if (fl2.ll == 0) { - fl1.ll = PACKD_LL(SIGND(fl1),2047,0); - goto test_done; - } - - - /* now get mantissas */ - fl1.ll = MANTD_LL(fl1); - fl2.ll = MANTD_LL(fl2); - - /* this assures we have 54 bits of precision in the end */ - if (fl1.ll < fl2.ll) { - fl1.ll <<= 1; - exp--; - } - - /* now we perform repeated subtraction of fl2.ll from fl1.ll */ - mask = (long long)1<<53; - result = 0; - while (mask) { - if (fl1.ll >= fl2.ll) - { - result |= mask; - fl1.ll -= fl2.ll; - } - fl1.ll <<= 1; - mask >>= 1; - } - - /* round */ - result += 1; - - /* normalize down */ - exp++; - result >>= 1; - - result &= ~HIDDEND_LL; - - /* pack up and go home */ - fl1.ll = PACKD_LL(sign, exp, result); - -test_done: - return (fl1.d); -} - -int -__gtdf2 (double a1, double a2) -{ - return __cmpdf2 ((float) a1, (float) a2) > 0; -} - -int -__gedf2 (double a1, double a2) -{ - return (__cmpdf2 ((float) a1, (float) a2) >= 0) - 1; -} - -int -__ltdf2 (double a1, double a2) -{ - return - (__cmpdf2 ((float) a1, (float) a2) < 0); -} - -int -__ledf2 (double a1, double a2) -{ - return __cmpdf2 ((float) a1, (float) a2) > 0; -} - -int -__eqdf2 (double a1, double a2) -{ - return *(long long *) &a1 == *(long long *) &a2; -} - -int -__nedf2 (double a1, double a2) -{ - return *(long long *) &a1 != *(long long *) &a2; -} - -/* absolute value of double */ -double -__absdf2(double a1) -{ - if (__cmpdf2(a1,0.0) < 0) - return __negdf2(a1); - else - return a1; -} - -/* absolute value of float */ -float -__abssf2(float a1) -{ - if (__cmpsf2(a1,0.0) < 0) - return __negsf2(a1); - else - return a1; -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/head.S linux.ac/arch/s390/kernel/head.S --- linux.vanilla/arch/s390/kernel/head.S Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/head.S Thu Apr 12 11:59:46 2001 @@ -261,8 +261,9 @@ l %r1,0xb8 # load ipl subchannel number la %r2,IPL_BS # load start address bas %r14,.Lloader # load rest of ipl image - st %r1,__LC_IPLDEV # store ipl device number l %r12,.Lparm # pointer to parameter area + st %r1,__LC_IPLDEV # store ipl device number + st %r1,IPL_DEVICE-PARMAREA(%r12) # # load parameter file from ipl device @@ -406,7 +407,8 @@ sr %r3,%r2 la %r3,1(%r3) .done: - st %r3,MEMORY_SIZE-PARMAREA(%r11) + l %r1,.memsize + st %r3,0(%r1) slr %r0,%r0 st %r0,INITRD_SIZE-PARMAREA(%r11) st %r0,INITRD_START-PARMAREA(%r11) @@ -414,6 +416,7 @@ .tbl: .long _ebcasc # translate table .cmd: .long COMMAND_LINE # address of command line buffer .parm: .long PARMAREA +.memsize: .long memory_size .fourmeg: .long 0x00400000 # 4M .pgmnw: .long 0x00080000,.pgmx .lowcase: @@ -464,7 +467,7 @@ # # find out memory size. # - mvc 104(8),.Lpcmem-.LPG1(%r13) # setup program check handler + mvc __LC_PGM_NEW_PSW(8),.Lpcmem-.LPG1(%r13) lhi %r2,1 sll %r2,17 # test in increments of 128KB lr %r1,%r2 @@ -476,78 +479,56 @@ bnm .Lloop-.LPG1(%r13) # r1 < 0x80000000 -> loop .Lchkmem: n %r1,.L4malign-.LPG1(%r13) # align to multiples of 4M - st %r1,MEMORY_SIZE-PARMAREA(%r12) # store memory size -.Lsizeok: - -# -# Now we have to move the ramdisk to a location approriate for the -# memory size. If we have more than 64 MB of memory we move it to 32MB -# to make room for the page tables set up by paging_init. -# - l %r1,MEMORY_SIZE-PARMAREA(%r12) - cl %r1,.Lbigmem-.LPG1(%r13) # memory < 64mb ? - bl .Lnomove-.LPG1(%r13) # if yes ramdisk @8MB is ok - icm %r4,15,INITRD_START-PARMAREA(%r12) - bz .Lnomove-.LPG1(%r13) - l %r2,.Lrdstart-.LPG1(%r13) # new address of ramdisk - st %r2,INITRD_START-PARMAREA(%r12) - l %r1,INITRD_SIZE-PARMAREA(%r12) - ar %r2,%r1 # we start moving at the end - ar %r4,%r1 # because new location > old location -.Lmove: lr %r0,%r2 # new - old is the maximum we can move - sr %r0,%r4 # because of overlapping - cr %r0,%r1 # we shouldn't move more than there is - bnh .Lnoend-.LPG1(%r13) - lr %r0,%r1 -.Lnoend:cl %r0,.Lmaxchunk-.LPG1(%r13) # mvcl can move 2^24-1 in one go - bnh .Lchunk-.LPG1(%r13) - l %r0,.Lmaxchunk-.LPG1(%r13) -.Lchunk:sr %r2,%r0 # make source & destination pointer - sr %r4,%r0 - lr %r3,%r0 # set source & destination length - lr %r5,%r0 - mvcl %r2,%r4 - sr %r2,%r0 # substract length again, since - sr %r4,%r0 # mvcl added it to the pointers - sr %r1,%r0 # substract chunk size from length - bnz .Lmove-.LPG1(%r13) -.Lnomove: + l %r2,.Lmemsize-.LPG1(%r13) # address of variable memory_size + st %r1,0(%r2) # store memory size + l %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags # # find out if we are running under VM # stidp __LC_CPUID # store cpuid tm __LC_CPUID,0xff # running under VM ? bno .Lnovm-.LPG1(%r13) - oi MACHINE_FLAGS+3-PARMAREA(%r12),1 # set VM flag + oi 3(%r12),1 # set VM flag .Lnovm: lh %r0,__LC_CPUID+4 # get cpu version chi %r0,0x7490 # running on a P/390 ? bne .Lnop390-.LPG1(%r13) - oi MACHINE_FLAGS+3-PARMAREA(%r12),4 # set P/390 flag + oi 3(%r12),4 # set P/390 flag .Lnop390: # # find out if we have an IEEE fpu # - mvc 104(8),.Lpcfpu-.LPG1(%r13) # setup program check handler + mvc __LC_PGM_NEW_PSW(8),.Lpcfpu-.LPG1(%r13) ld %f0,.Lflt0-.LPG1(%r13) # load (float) 0.0 ldr %f2,%f0 adbr %f0,%f2 # test IEEE add instruction - oi MACHINE_FLAGS+3-PARMAREA(%r12),2 # set IEEE fpu flag + oi 3(%r12),2 # set IEEE fpu flag .Lchkfpu: # # find out if we have the CSP instruction # - mvc 104(8),.Lpccsp-.LPG1(%r13) # setup program check handler + mvc __LC_PGM_NEW_PSW(8),.Lpccsp-.LPG1(%r13) la %r0,0 lr %r1,%r0 la %r2,.Lflt0-.LPG1(%r13) csp %r0,%r2 # Test CSP instruction - oi MACHINE_FLAGS+3-PARMAREA(%r12),8 # set CSP flag + oi 3(%r12),8 # set CSP flag .Lchkcsp: +# +# find out if we have the MVPG instruction +# + mvc __LC_PGM_NEW_PSW(8),.Lpcmvpg-.LPG1(%r13) + sr %r0,%r0 + la %r1,0 + la %r2,0 + mvpg %r1,%r2 # Test CSP instruction + oi 3(%r12),16 # set MVPG flag +.Lchkmvpg: + lpsw .Lentry-.LPG1(13) # jump to _stext in primary-space, # virtual and never return ... .align 8 @@ -571,24 +552,23 @@ .Lpcmem:.long 0x00080000,0x80000000 + .Lchkmem .Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu .Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp +.Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg .Lflt0: .double 0 .Lparm1:.long PARMAREA .L4malign:.long 0xffc00000 .Lbigmem:.long 0x04000000 .Lrdstart:.long 0x02000000 .Lmaxchunk:.long 0x00ffffff +.Lmemsize:.long memory_size +.Lmflags:.long machine_flags # # params at 10400 (setup.h) # .org PARMAREA - .long 0x0100 # ORIG_ROOT_DEV: ramdisk major/minor - .word 0 # MOUNT_ROOT_RDONLY: no - .long 0 # MEMORY_SIZE - .long 0 # MACHINE_FLAGS (bit 0:VM, bit 1:IEEE) - .long RAMDISK_ORIGIN # INITRD_START - .long 0x800000 # INITRD_SIZE - .word 0 # RAMDISK_FLAGS + .long 0,0 # IPL_DEVICE + .long 0,RAMDISK_ORIGIN # INITRD_START + .long 0,0x800000 # INITRD_SIZE .org COMMAND_LINE .byte "root=/dev/ram0 ro" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/irq.c linux.ac/arch/s390/kernel/irq.c --- linux.vanilla/arch/s390/kernel/irq.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/irq.c Thu Apr 12 11:59:46 2001 @@ -11,6 +11,7 @@ * S/390 I/O interrupt processing and I/O request processing is * implemented in arch/s390/kernel/s390io.c */ +#include <linux/module.h> #include <linux/config.h> #include <linux/ptrace.h> #include <linux/errno.h> @@ -20,7 +21,7 @@ #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/timex.h> -#include <linux/slab.h> +#include <linux/malloc.h> #include <linux/string.h> #include <linux/random.h> #include <linux/smp.h> @@ -286,7 +287,7 @@ */ void __global_cli(void) { - unsigned int flags; + unsigned long flags; __save_flags(flags); if (flags & (1 << EFLAGS_I_SHIFT)) { @@ -357,48 +358,6 @@ #endif -/* - * Note : This fuction should be eliminated as it doesn't comply with the - * S/390 irq scheme we have implemented ... - */ -int handle_IRQ_event( unsigned int irq, int cpu, struct pt_regs * regs) -{ - struct irqaction * action; - int status; - - status = 0; - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - return( -ENODEV); - - action = ioinfo[irq]->irq_desc.action; - - if (action) - { - status |= 1; - - if (!(action->flags & SA_INTERRUPT)) - __sti(); - - do - { - status |= action->flags; - action->handler(irq, action->dev_id, regs); - action = action->next; - } while (action); - - if (status & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); - __cli(); - - } /* endif */ - - return status; -} - -void enable_nop(int irq) -{ -} void __init init_IRQ(void) { @@ -427,3 +386,8 @@ /* For now, nothing... */ } +EXPORT_SYMBOL(__global_cli); +EXPORT_SYMBOL(__global_sti); +EXPORT_SYMBOL(__global_save_flags); +EXPORT_SYMBOL(__global_restore_flags); +EXPORT_SYMBOL(global_bh_lock); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/irqextras390.c linux.ac/arch/s390/kernel/irqextras390.c --- linux.vanilla/arch/s390/kernel/irqextras390.c Fri May 12 19:41:44 2000 +++ linux.ac/arch/s390/kernel/irqextras390.c Thu Jan 1 01:00:00 1970 @@ -1,35 +0,0 @@ -/* - * arch/s390/kernel/irqextras390.c - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), - * - * Some channel code by D.J. Barrow - */ - -/* - -*/ -#include<asm/irqextras390.h> -#include<asm/lowcore.h> - -#if 0 -// fixchannelprogram is now obselete -void fixchannelprogram(orb_bits_t *orbptr) -{ - __u32 newAddress=orbptr->ccw_program_address; - fixccws(orbptr->ccw_program_address); - orbptr->ccw_program_address=newAddress; - orbptr->ccw_program_address=(ccw1_t *)(((__u32)orbptr->ccw_program_address)); -} -#endif - -void fixccws(ccw1_bits_t *ccwptr) -{ - for(;;ccwptr++) - { // Just hope nobody starts doing prefixing - if(!ccwptr->cc) - break; - } -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/mathemu.c linux.ac/arch/s390/kernel/mathemu.c --- linux.vanilla/arch/s390/kernel/mathemu.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/mathemu.c Thu Jan 1 01:00:00 1970 @@ -1,1045 +0,0 @@ -/* - * arch/s390/kernel/mathemu.c - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), - * - * 'mathemu.c' handles IEEE instructions on a S390 processor - * that does not have the IEEE fpu - */ - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/ptrace.h> - -#include <asm/uaccess.h> -#include <asm/mathemu.h> - -#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; - __u16 *location; - -#if CONFIG_SYSCTL - if(sysctl_ieee_emulation_warnings) -#endif - { - regs=current->thread.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 int set_CC_df(__u64 val1,__u64 val2) { - int rc; - rc = __cmpdf2(val1,val2); - current->thread.regs->psw.mask &= 0xFFFFCFFF; - switch (rc) { - case -1: - current->thread.regs->psw.mask |= 0x00001000; - break; - case 1: - current->thread.regs->psw.mask |= 0x00002000; - break; - } - return 0; -} - -static int set_CC_sf(__u32 val1,__u32 val2) { - int rc; - rc = __cmpsf2(val1,val2); - current->thread.regs->psw.mask &= 0xFFFFCFFF; - switch (rc) { - case -1: - current->thread.regs->psw.mask |= 0x00001000; - break; - case 1: - current->thread.regs->psw.mask |= 0x00002000; - break; - } - return 0; -} - - -static int emu_adb (int rx, __u64 val) { - current->thread.fp_regs.fprs[rx].d = __adddf3(current->thread.fp_regs.fprs[rx].d,val); - set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); - return 0; -} - -static int emu_adbr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].d = __adddf3(current->thread.fp_regs.fprs[rx].d, - current->thread.fp_regs.fprs[ry].d); - set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); - return 0; -} - -static int emu_aeb (int rx, __u32 val) { - current->thread.fp_regs.fprs[rx].f = __addsf3(current->thread.fp_regs.fprs[rx].f,val); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_aebr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].f = __addsf3(current->thread.fp_regs.fprs[rx].f, - current->thread.fp_regs.fprs[ry].f); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_axbr (int rx, int ry) { - display_emulation_not_implemented("axbr"); - return 0; -} - -static int emu_cdb (int rx, __u64 val) { - set_CC_df(current->thread.fp_regs.fprs[rx].d,val); - return 0; -} - -static int emu_cdbr (int rx, int ry) { - set_CC_df(current->thread.fp_regs.fprs[rx].d,current->thread.fp_regs.fprs[ry].d); - return 0; -} - -static int emu_cdfbr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].d = - __floatsidf(current->thread.regs->gprs[ry]); - return 0; -} - -static int emu_ceb (int rx, __u32 val) { - set_CC_sf(current->thread.fp_regs.fprs[rx].f,val); - return 0; -} - -static int emu_cebr (int rx, int ry) { - set_CC_sf(current->thread.fp_regs.fprs[rx].f,current->thread.fp_regs.fprs[ry].f); - return 0; -} - -static int emu_cefbr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].f = - __floatsisf(current->thread.regs->gprs[ry]); - return 0; -} - -static int emu_cfdbr (int rx, int ry, int mask) { - current->thread.regs->gprs[rx] = - __fixdfsi(current->thread.fp_regs.fprs[ry].d); - return 0; -} - -static int emu_cfebr (int rx, int ry, int mask) { - current->thread.regs->gprs[rx] = - __fixsfsi(current->thread.fp_regs.fprs[ry].f); - return 0; -} - -static int emu_cfxbr (int rx, int ry, int mask) { - display_emulation_not_implemented("cfxbr"); - return 0; -} - -static int emu_cxbr (int rx, int ry) { - display_emulation_not_implemented("cxbr"); - return 0; -} - -static int emu_cxfbr (int rx, int ry) { - display_emulation_not_implemented("cxfbr"); - return 0; -} - -static int emu_ddb (int rx, __u64 val) { - current->thread.fp_regs.fprs[rx].d = __divdf3(current->thread.fp_regs.fprs[rx].d,val); - set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); - return 0; -} - -static int emu_ddbr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].d = __divdf3(current->thread.fp_regs.fprs[rx].d, - current->thread.fp_regs.fprs[ry].d); - set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); - return 0; -} - -static int emu_deb (int rx, __u32 val) { - current->thread.fp_regs.fprs[rx].f = __divsf3(current->thread.fp_regs.fprs[rx].f,val); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_debr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].f = __divsf3(current->thread.fp_regs.fprs[rx].f, - current->thread.fp_regs.fprs[ry].f); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_didbr (int rx, int ry, int mask) { - display_emulation_not_implemented("didbr"); - return 0; -} - -static int emu_diebr (int rx, int ry, int mask) { - display_emulation_not_implemented("diebr"); - return 0; -} - -static int emu_dxbr (int rx, int ry) { - display_emulation_not_implemented("dxbr"); - return 0; -} - -static int emu_efpc (int rx, int ry) { - current->thread.regs->gprs[rx]=current->thread.fp_regs.fpc; - return 0; -} - -static int emu_fidbr (int rx, int ry, int mask) { - display_emulation_not_implemented("fidbr"); - return 0; -} - -static int emu_fiebr (int rx, int ry, int mask) { - display_emulation_not_implemented("fiebr"); - return 0; -} - -static int emu_fixbr (int rx, int ry, int mask) { - display_emulation_not_implemented("fixbr"); - return 0; -} - -static int emu_kdb (int rx, __u64 val) { - display_emulation_not_implemented("kdb"); - return 0; -} - -static int emu_kdbr (int rx, int ry) { - display_emulation_not_implemented("kdbr"); - return 0; -} - -static int emu_keb (int rx, __u32 val) { - display_emulation_not_implemented("keb"); - return 0; -} - -static int emu_kebr (int rx, int ry) { - display_emulation_not_implemented("kebr"); - return 0; -} - -static int emu_kxbr (int rx, int ry) { - display_emulation_not_implemented("kxbr"); - return 0; -} - -static int emu_lcdbr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].d = - __negdf2(current->thread.fp_regs.fprs[ry].d); - set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); - return 0; -} - -static int emu_lcebr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].f = - __negsf2(current->thread.fp_regs.fprs[ry].f); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_lcxbr (int rx, int ry) { - display_emulation_not_implemented("lcxbr"); - return 0; -} - -static int emu_ldeb (int rx, __u32 val) { - current->thread.fp_regs.fprs[rx].d = __extendsfdf2(val); - return 0; -} - -static int emu_ldebr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].d = - __extendsfdf2(current->thread.fp_regs.fprs[ry].f); - return 0; -} - -static int emu_ldxbr (int rx, int ry) { - display_emulation_not_implemented("ldxbr"); - return 0; -} - -static int emu_ledbr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].f = __truncdfsf2(current->thread.fp_regs.fprs[ry].d); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_lexbr (int rx, int ry) { - display_emulation_not_implemented("lexbr"); - return 0; -} - -static int emu_lndbr (int rx, int ry) { - display_emulation_not_implemented("lndbr"); - return 0; -} - -static int emu_lnebr (int rx, int ry) { - display_emulation_not_implemented("lnebr"); - return 0; -} - -static int emu_lnxbr (int rx, int ry) { - display_emulation_not_implemented("lnxbr"); - return 0; -} - -static int emu_lpdbr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].d = __absdf2(current->thread.fp_regs.fprs[ry].d); - set_CC_df(current->thread.fp_regs.fprs[rx].d,0); - return 0; -} - -static int emu_lpebr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].f = __abssf2(current->thread.fp_regs.fprs[ry].f); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_lpxbr (int rx, int ry) { - display_emulation_not_implemented("lpxbr"); - return 0; -} - -static int emu_ltdbr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].d = current->thread.fp_regs.fprs[ry].d; - set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); - return 0; -} - -static int emu_ltebr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].f = current->thread.fp_regs.fprs[ry].f; - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_ltxbr (int rx, int ry) { - display_emulation_not_implemented("ltxbr"); - return 0; -} - -static int emu_lxdb (int rx, __u64 val) { - display_emulation_not_implemented("lxdb"); - return 0; -} - -static int emu_lxdbr (int rx, int ry) { - display_emulation_not_implemented("lxdbr"); - return 0; -} - -static int emu_lxeb (int rx, __u32 val) { - display_emulation_not_implemented("lxeb"); - return 0; -} - -static int emu_lxebr (int rx, int ry) { - display_emulation_not_implemented("lxebr"); - return 0; -} - -static int emu_madb (int rx, __u64 val, int mask) { - display_emulation_not_implemented("madb"); - return 0; -} - -static int emu_madbr (int rx, int ry, int mask) { - display_emulation_not_implemented("madbr"); - return 0; -} - -static int emu_maeb (int rx, __u32 val, int mask) { - display_emulation_not_implemented("maeb"); - return 0; -} - -static int emu_maebr (int rx, int ry, int mask) { - display_emulation_not_implemented("maebr"); - return 0; -} - -static int emu_mdb (int rx, __u64 val) { - current->thread.fp_regs.fprs[rx].d = __muldf3(current->thread.fp_regs.fprs[rx].d,val); - set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); - return 0; -} - -static int emu_mdbr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].d = __muldf3(current->thread.fp_regs.fprs[rx].d, - current->thread.fp_regs.fprs[ry].d); - set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); - return 0; -} - -static int emu_mdeb (int rx, __u32 val) { - display_emulation_not_implemented("mdeb"); - return 0; -} - -static int emu_mdebr (int rx, int ry) { - display_emulation_not_implemented("mdebr"); - return 0; -} - -static int emu_meeb (int rx, __u32 val) { - current->thread.fp_regs.fprs[rx].f = __mulsf3(current->thread.fp_regs.fprs[rx].f, - val); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_meebr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].f = __mulsf3(current->thread.fp_regs.fprs[rx].f, - current->thread.fp_regs.fprs[ry].f); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_msdb (int rx, __u64 val, int mask) { - display_emulation_not_implemented("msdb"); - return 0; -} - -static int emu_msdbr (int rx, int ry, int mask) { - display_emulation_not_implemented("msdbr"); - return 0; -} - -static int emu_mseb (int rx, __u32 val, int mask) { - display_emulation_not_implemented("mseb"); - return 0; -} - -static int emu_msebr (int rx, int ry, int mask) { - display_emulation_not_implemented("msebr"); - return 0; -} - -static int emu_mxbr (int rx, int ry) { - display_emulation_not_implemented("mxbr"); - return 0; -} - -static int emu_mxdb (int rx, __u64 val) { - display_emulation_not_implemented("mxdb"); - return 0; -} - -static int emu_mxdbr (int rx, int ry) { - display_emulation_not_implemented("mxdbr"); - return 0; -} - -static int emu_sdb (int rx, __u64 val) { - current->thread.fp_regs.fprs[rx].d = __subdf3(current->thread.fp_regs.fprs[rx].d, - val); - set_CC_sf(current->thread.fp_regs.fprs[rx].d,0ULL); - return 0; -} - -static int emu_sdbr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].d = __subdf3(current->thread.fp_regs.fprs[rx].d, - current->thread.fp_regs.fprs[ry].d); - set_CC_sf(current->thread.fp_regs.fprs[rx].d,0ULL); - return 0; -} - -static int emu_seb (int rx, __u32 val) { - current->thread.fp_regs.fprs[rx].f = __subsf3(current->thread.fp_regs.fprs[rx].f, - val); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_sebr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].f = __subsf3(current->thread.fp_regs.fprs[rx].f, - current->thread.fp_regs.fprs[ry].f); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_sfpc (int rx, int ry) { - __u32 val=current->thread.regs->gprs[rx]; - if(val==0) - current->thread.fp_regs.fpc=val; - else - display_emulation_not_implemented("sfpc"); - return 0; -} - -static int emu_sqdb (int rx, __u64 val) { - display_emulation_not_implemented("sqdb"); - return 0; -} - -static int emu_sqdbr (int rx, int ry) { - display_emulation_not_implemented("sqdbr"); - return 0; -} - -static int emu_sqeb (int rx, __u32 val) { - display_emulation_not_implemented("sqeb"); - return 0; -} - -static int emu_sqebr (int rx, int ry) { - display_emulation_not_implemented("sqebr"); - return 0; -} - -static int emu_sqxbr (int rx, int ry) { - display_emulation_not_implemented("sqxbr"); - return 0; -} - -static int emu_sxbr (int rx, int ry) { - display_emulation_not_implemented("sxbr"); - return 0; -} - -static int emu_tcdb (int rx, __u64 val) { - display_emulation_not_implemented("tcdb"); - return 0; -} - -static int emu_tceb (int rx, __u32 val) { - display_emulation_not_implemented("tceb"); - return 0; -} - -static int emu_tcxb (int rx, __u64 val) { - display_emulation_not_implemented("tcxb"); - return 0; -} - - -static inline void emu_load_regd(int reg) { - if ((reg&9) == 0) { /* test if reg in {0,2,4,6} */ - __asm__ __volatile ( /* load reg from fp_regs.fprs[reg] */ - " bras 1,0f\n" - " ld 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].d) - : "1" ); - } -} - -static inline void emu_load_rege(int reg) { - if ((reg&9) == 0) { /* test if reg in {0,2,4,6} */ - __asm__ __volatile ( /* load reg from fp_regs.fprs[reg] */ - " bras 1,0f\n" - " le 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].f) - : "1" ); - } -} - -static inline void emu_store_regd(int reg) { - if ((reg&9) == 0) { /* test if reg in {0,2,4,6} */ - __asm__ __volatile ( /* store reg to fp_regs.fprs[reg] */ - " bras 1,0f\n" - " std 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].d) - : "1" ); - } -} - - -static inline void emu_store_rege(int reg) { - if ((reg&9) == 0) { /* test if reg in {0,2,4,6} */ - __asm__ __volatile ( /* store reg to fp_regs.fprs[reg] */ - " bras 1,0f\n" - " ste 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].f) - : "1" ); - } -} - -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, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1,10, 1, 1, 3, 1, 1, 1, 1, 1, 1, 0, 0, - 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 3, 0, 0, 0, 3, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, - 0, 0, 0, 0, 5, 6, 6, 0, 7, 8, 8, 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 - }; - static const void *jump_table[]= { - emu_lpebr, emu_lnebr, emu_ltebr, emu_lcebr, - emu_ldebr, emu_lxdbr, emu_lxebr, emu_mxdbr, - emu_kebr, emu_cebr, emu_aebr, emu_sebr, - emu_mdebr, emu_debr, emu_maebr, emu_msebr, - emu_lpdbr, emu_lndbr, emu_ltdbr, emu_lcdbr, - emu_sqebr, emu_sqdbr, emu_sqxbr, emu_meebr, - emu_kdbr, emu_cdbr, emu_adbr, emu_sdbr, - emu_mdbr, emu_ddbr, emu_madbr, emu_msdbr, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - emu_lpxbr, emu_lnxbr, emu_ltxbr, emu_lcxbr, - emu_ledbr, emu_ldxbr, emu_lexbr, emu_fixbr, - emu_kxbr, emu_cxbr, emu_axbr, emu_sxbr, - emu_mxbr, emu_dxbr, NULL, NULL, - NULL, NULL, NULL, emu_diebr, - NULL, NULL, NULL, emu_fiebr, - NULL, NULL, NULL, emu_didbr, - NULL, NULL, NULL, emu_fidbr, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - emu_sfpc, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - emu_efpc, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - emu_cefbr, emu_cdfbr, emu_cxfbr, NULL, - emu_cfebr, emu_cfdbr, emu_cfxbr - }; - - switch (format_table[opcode[1]]) { - case 1: /* RRE format, double operation */ - emu_store_regd((opcode[3]>>4)&15); - emu_store_regd(opcode[3]&15); - /* call the emulation function */ - 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 rc; - case 2: /* RRE format, float operation */ - emu_store_rege((opcode[3]>>4)&15); - emu_store_rege(opcode[3]&15); - /* call the emulation function */ - 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 rc; - case 3: /* RRF format, double operation */ - emu_store_regd((opcode[3]>>4)&15); - emu_store_regd(opcode[3]&15); - /* call the emulation function */ - 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 rc; - case 4: /* RRF format, float operation */ - emu_store_rege((opcode[3]>>4)&15); - emu_store_rege(opcode[3]&15); - /* call the emulation function */ - 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 rc; - case 5: /* RRE format, cefbr instruction */ - emu_store_rege((opcode[3]>>4)&15); - /* call the emulation function */ - rc=((int (*)(int, int))jump_table[opcode[1]]) - (opcode[3]>>4,opcode[3]&15); - 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 */ - rc=((int (*)(int, int))jump_table[opcode[1]]) - (opcode[3]>>4,opcode[3]&15); - 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 */ - rc=((int (*)(int, int, int))jump_table[opcode[1]]) - (opcode[3]>>4,opcode[3]&15,opcode[2]>>4); - return rc; - case 8: /* RRF format, cfdbr & cfxbr instruction */ - emu_store_regd(opcode[3]&15); - /* call the emulation function */ - rc=((int (*)(int, int, int))jump_table[opcode[1]]) - (opcode[3]>>4,opcode[3]&15,opcode[2]>>4); - 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 */ - rc=((int (*)(int, int))jump_table[opcode[1]]) - (opcode[3]>>4,opcode[3]&15); - 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 */ - rc=((int (*)(int, int))jump_table[opcode[1]]) - (opcode[3]>>4,opcode[3]&15); - emu_load_rege((opcode[3]>>4)&15); - return rc; - default: - return 1; - } -} - -static void* calc_addr(struct pt_regs *regs,int rx,int rb,int disp) -{ - rx &= 0xf; - rb &= 0xf; - disp &= 0xfff; - return (void*) ((rx != 0 ? regs->gprs[rx] : 0) + /* index */ - (rb != 0 ? regs->gprs[rb] : 0) + /* base */ - disp); -} - -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, - 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, - 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 - }; - static const void *jump_table[]= { - NULL, NULL, NULL, NULL, - emu_ldeb, emu_lxdb, emu_lxeb, emu_mxdb, - emu_keb, emu_ceb, emu_aeb, emu_seb, - emu_mdeb, emu_deb, emu_maeb, emu_mseb, - emu_tceb, emu_tcdb, emu_tcxb, NULL, - emu_sqeb, emu_sqdb, NULL, emu_meeb, - emu_kdb, emu_cdb, emu_adb, emu_sdb, - emu_mdb, emu_ddb, emu_madb, emu_msdb - }; - - switch (format_table[opcode[5]]) { - case 1: /* RXE format, __u64 constant */ { - __u64 *dxb, temp; - __u32 opc; - - emu_store_regd((opcode[1]>>4)&15); - opc = *((__u32 *) opcode); - dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc); - mathemu_copy_from_user(&temp, dxb, 8); - /* call the emulation function */ - rc=((int (*)(int, __u64))jump_table[opcode[5]]) - (opcode[1]>>4,temp); - emu_load_regd((opcode[1]>>4)&15); - return rc; - } - case 2: /* RXE format, __u32 constant */ { - __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); - mathemu_get_user(temp, dxb); - /* call the emulation function */ - rc=((int (*)(int, __u32))jump_table[opcode[5]]) - (opcode[1]>>4,temp); - emu_load_rege((opcode[1]>>4)&15); - return rc; - } - case 3: /* RXF format, __u64 constant */ { - __u32 *dxb, temp; - __u32 opc; - - emu_store_regd((opcode[1]>>4)&15); - opc = *((__u32 *) opcode); - dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - mathemu_copy_from_user(&temp, dxb, 8); - /* call the emulation function */ - rc=((int (*)(int, __u32, int))jump_table[opcode[5]]) - (opcode[1]>>4,temp,opcode[4]>>4); - emu_load_regd((opcode[1]>>4)&15); - return rc; - } - case 4: /* RXF format, __u32 constant */ { - __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); - mathemu_get_user(temp, dxb); - /* call the emulation function */ - rc=((int (*)(int, __u32, int))jump_table[opcode[5]]) - (opcode[1]>>4,temp,opcode[4]>>4); - emu_load_rege((opcode[1]>>4)&15); - 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); - mathemu_get_user(temp, dxb); - /* call the emulation function */ - rc=((int (*)(int, __u32))jump_table[opcode[5]]) - (opcode[1]>>4,temp); - emu_load_regd((opcode[1]>>4)&15); - return rc; - } - default: - return 1; - } -} - -/* - * Emulate LDR Rx,Ry with Rx or Ry not in {0, 2, 4, 6} - */ -int math_emu_ldr(__u8 *opcode) { - __u16 opc = *((__u16 *) opcode); - - if ((opc & 0x0090) == 0) { /* test if rx in {0,2,4,6} */ - /* we got an exception therfore ry can't be in {0,2,4,6} */ - __asm__ __volatile ( /* load rx from fp_regs.fprs[ry] */ - " bras 1,0f\n" - " ld 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" (opc&0x00f0), - "a" (¤t->thread.fp_regs.fprs[opc&0x000f].d) - : "1" ); - } else if ((opc & 0x0009) == 0) { /* test if ry in {0,2,4,6} */ - __asm__ __volatile ( /* store ry to fp_regs.fprs[rx] */ - " bras 1,0f\n" - " std 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" ((opc&0x000f)<<4), - "a" (¤t->thread.fp_regs.fprs[(opc&0x00f0)>>4].d) - : "1" ); - } else { /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */ - current->thread.fp_regs.fprs[(opc&0x00f0)>>4] = - current->thread.fp_regs.fprs[opc&0x000f]; - } - return 0; -} - -/* - * Emulate LER Rx,Ry with Rx or Ry not in {0, 2, 4, 6} - */ -int math_emu_ler(__u8 *opcode) { - __u16 opc = *((__u16 *) opcode); - - if ((opc & 0x0090) == 0) { /* test if rx in {0,2,4,6} */ - /* we got an exception therfore ry can't be in {0,2,4,6} */ - __asm__ __volatile ( /* load rx from fp_regs.fprs[ry] */ - " bras 1,0f\n" - " le 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" (opc&0x00f0), - "a" (¤t->thread.fp_regs.fprs[opc&0x000f].f) - : "1" ); - } else if ((opc & 0x0009) == 0) { /* test if ry in {0,2,4,6} */ - __asm__ __volatile ( /* store ry to fp_regs.fprs[rx] */ - " bras 1,0f\n" - " ste 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" ((opc&0x000f)<<4), - "a" (¤t->thread.fp_regs.fprs[(opc&0x00f0)>>4].f) - : "1" ); - } else { /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */ - current->thread.fp_regs.fprs[(opc&0x00f0)>>4] = - current->thread.fp_regs.fprs[opc&0x000f]; - } - return 0; -} - -/* - * Emulate LD R,D(X,B) with R not in {0, 2, 4, 6} - */ -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); - mathemu_copy_from_user(¤t->thread.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} - */ -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); - mem = (__u32 *) (¤t->thread.fp_regs.fprs[(opc>>20)&15].f); - mathemu_get_user(mem[0], dxb); - return 0; -} - -/* - * Emulate STD R,D(X,B) with R not in {0, 2, 4, 6} - */ -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); - mathemu_copy_to_user(dxb, ¤t->thread.fp_regs.fprs[(opc>>20)&15].d, 8); - return 0; -} - -/* - * Emulate STE R,D(X,B) with R not in {0, 2, 4, 6} - */ -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 mathemu_put_user fails ? */ - mem = (__u32 *) (¤t->thread.fp_regs.fprs[(opc>>20)&15].f); - mathemu_put_user(mem[0], dxb); - return 0; -} - -/* - * Emulate LFPC D(B) - */ -int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) { - __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; -} - -/* - * Emulate STFPC D(B) - */ -int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) { - __u32 *dxb; - __u32 opc = *((__u32 *) opcode); - dxb= (__u32 *) calc_addr(regs,0,opc>>12,opc); - mathemu_put_user(current->thread.fp_regs.fpc, dxb); - return 0; -} - -/* - * Emulate SRNM D(B) - */ -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 linux.vanilla/arch/s390/kernel/process.c linux.ac/arch/s390/kernel/process.c --- linux.vanilla/arch/s390/kernel/process.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/process.c Mon Apr 16 12:37:04 2001 @@ -42,7 +42,6 @@ #include <asm/system.h> #include <asm/io.h> #include <asm/processor.h> -#include <asm/misc390.h> #include <asm/irq.h> spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED; @@ -300,12 +299,10 @@ unsigned long fprs[4]; /* fpr 4 and 6 */ unsigned long empty[4]; #if CONFIG_REMOTE_DEBUG - gdb_pt_regs childregs; + struct gdb_pt_regs childregs; #else - pt_regs childregs; + struct pt_regs childregs; #endif - __u32 pgm_old_ilc; /* single step magic from entry.S */ - __u32 pgm_svc_step; } *frame; frame = (struct stack_frame *) (2*PAGE_SIZE + (unsigned long) p) -1; @@ -321,7 +318,7 @@ /* fake return stack for resume(), don't go back to schedule */ frame->gprs[9] = (unsigned long) frame; - frame->pgm_svc_step = 0; /* Nope we aren't single stepping an svc */ + frame->childregs.old_ilc = -1; /* We are not single stepping an svc */ /* save fprs, if used in last task */ save_fp_regs(&p->thread.fp_regs); p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _SEGMENT_TABLE; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/ptrace.c linux.ac/arch/s390/kernel/ptrace.c --- linux.vanilla/arch/s390/kernel/ptrace.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/ptrace.c Thu Apr 12 11:59:46 2001 @@ -180,9 +180,9 @@ copymax=(PT_FPR15_LO+4); realuseraddr=(addr_t)&(((u8 *)&task->thread.fp_regs)[useraddr-PT_FPC]); } - else if(useraddr<sizeof(user_regs_struct)) + else if(useraddr<sizeof(struct user_regs_struct)) { - copymax=sizeof(user_regs_struct); + copymax=sizeof(struct user_regs_struct); realuseraddr=(addr_t)&(((u8 *)&task->thread.per_info)[useraddr-PT_CR_9]); } else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/s390_ext.c linux.ac/arch/s390/kernel/s390_ext.c --- linux.vanilla/arch/s390/kernel/s390_ext.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/s390_ext.c Thu Apr 12 11:59:46 2001 @@ -7,6 +7,7 @@ * Martin Schwidefsky (schwidefsky@de.ibm.com) */ +#include <linux/module.h> #include <linux/kernel.h> #include <linux/malloc.h> #include <asm/lowcore.h> @@ -74,4 +75,6 @@ return 0; } +EXPORT_SYMBOL(register_external_interrupt); +EXPORT_SYMBOL(unregister_external_interrupt); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/s390_ksyms.c linux.ac/arch/s390/kernel/s390_ksyms.c --- linux.vanilla/arch/s390/kernel/s390_ksyms.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/s390_ksyms.c Thu Apr 12 11:59:46 2001 @@ -5,67 +5,14 @@ */ #include <linux/config.h> #include <linux/module.h> -#include <linux/string.h> -#include <asm/ccwcache.h> -#include <asm/debug.h> -#include <asm/irq.h> -#include <asm/s390_ext.h> -#include <asm/s390dyn.h> -#include <asm/ebcdic.h> #include <asm/checksum.h> #include <asm/delay.h> -#if CONFIG_CHANDEV -#include <asm/chandev.h> -#endif +#include <asm/setup.h> #if CONFIG_IP_MULTICAST #include <net/arp.h> #endif /* - * I/O subsystem - */ -EXPORT_SYMBOL(halt_IO); -EXPORT_SYMBOL(clear_IO); -EXPORT_SYMBOL(do_IO); -EXPORT_SYMBOL(resume_IO); -EXPORT_SYMBOL(ioinfo); -EXPORT_SYMBOL(get_dev_info_by_irq); -EXPORT_SYMBOL(get_dev_info_by_devno); -EXPORT_SYMBOL(get_irq_by_devno); -EXPORT_SYMBOL(get_devno_by_irq); -EXPORT_SYMBOL(get_irq_first); -EXPORT_SYMBOL(get_irq_next); -EXPORT_SYMBOL(read_conf_data); -EXPORT_SYMBOL(read_dev_chars); -EXPORT_SYMBOL(s390_request_irq_special); -EXPORT_SYMBOL(s390_device_register); -EXPORT_SYMBOL(s390_device_unregister); - -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_set_level); -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_ascii_view); -EXPORT_SYMBOL(debug_raw_view); -EXPORT_SYMBOL(debug_dflt_header_fn); - -/* * memory management */ EXPORT_SYMBOL(_oi_bitmap); @@ -99,42 +46,17 @@ EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL_NOVERS(strpbrk); -EXPORT_SYMBOL_NOVERS(_ascebc_500); -EXPORT_SYMBOL_NOVERS(_ebcasc_500); -EXPORT_SYMBOL_NOVERS(_ascebc); -EXPORT_SYMBOL_NOVERS(_ebcasc); -EXPORT_SYMBOL_NOVERS(_ebc_tolower); -EXPORT_SYMBOL_NOVERS(_ebc_toupper); - /* * misc. */ -EXPORT_SYMBOL(module_list); +EXPORT_SYMBOL(machine_flags); EXPORT_SYMBOL(__udelay); -#ifdef CONFIG_SMP -#include <asm/smplock.h> -EXPORT_SYMBOL(__global_cli); -EXPORT_SYMBOL(__global_sti); -EXPORT_SYMBOL(__global_save_flags); -EXPORT_SYMBOL(__global_restore_flags); -EXPORT_SYMBOL(lowcore_ptr); -EXPORT_SYMBOL(global_bh_lock); -EXPORT_SYMBOL(kernel_flag); -EXPORT_SYMBOL(smp_ctl_set_bit); -EXPORT_SYMBOL(smp_ctl_clear_bit); -#endif EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(csum_fold); -#if CONFIG_CHANDEV -EXPORT_SYMBOL(chandev_register_and_probe); -EXPORT_SYMBOL(chandev_request_irq); -EXPORT_SYMBOL(chandev_unregister); -EXPORT_SYMBOL(chandev_initdevice); -EXPORT_SYMBOL(chandev_initnetdevice); -#endif + #if CONFIG_IP_MULTICAST /* Required for lcs gigabit ethernet multicast support */ EXPORT_SYMBOL(arp_mc_map); #endif -EXPORT_SYMBOL(s390_daemonize); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/s390fpu.c linux.ac/arch/s390/kernel/s390fpu.c --- linux.vanilla/arch/s390/kernel/s390fpu.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/s390fpu.c Thu Apr 12 11:59:46 2001 @@ -57,10 +57,9 @@ void save_fp_regs(s390_fp_regs *fpregs) { -#if CONFIG_IEEEFPU_EMULATION +#if CONFIG_MATHEMU s390_fp_regs *currentfprs; -#endif -#if CONFIG_IEEEFPU_EMULATION + if(!save_fp_regs1(fpregs)) { currentfprs=¤t->thread.fp_regs; @@ -119,11 +118,9 @@ void restore_fp_regs(s390_fp_regs *fpregs) { -#if CONFIG_IEEEFPU_EMULATION +#if CONFIG_MATHEMU s390_fp_regs *currentfprs; -#endif -#if CONFIG_IEEEFPU_EMULATION if(!restore_fp_regs1(fpregs)) { currentfprs=¤t->thread.fp_regs; @@ -138,15 +135,4 @@ restore_fp_regs1(fpregs); #endif } - - - - - - - - - - - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/setup.c linux.ac/arch/s390/kernel/setup.c --- linux.vanilla/arch/s390/kernel/setup.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390/kernel/setup.c Thu Apr 12 11:59:46 2001 @@ -38,10 +38,13 @@ #include <asm/system.h> #include <asm/smp.h> #include <asm/mmu_context.h> +#include <asm/cpcmd.h> /* * Machine setup.. */ +unsigned long memory_size = 0; +unsigned long machine_flags = 0; __u16 boot_cpu_addr; int cpus_initialized = 0; unsigned long cpu_initialized = 0; @@ -50,17 +53,8 @@ /* * Setup options */ - -#ifdef CONFIG_BLK_DEV_RAM -extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ -extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt*/ -extern int rd_image_start; /* starting block # of image */ -#endif - -extern int root_mountflags; extern int _text,_etext, _edata, _end; - /* * This is set up by the setup-routine at boot-time * for S390 need to find out, what we have to setup @@ -208,14 +202,9 @@ "This machine has an IEEE fpu\n" : "This machine has no IEEE fpu\n"); - ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV); -#ifdef CONFIG_BLK_DEV_RAM - rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; - rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); - rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); -#endif + ROOT_DEV = to_kdev_t(0x0100); memory_start = (unsigned long) &_end; /* fixit if use $CODELO etc*/ - memory_end = MEMORY_SIZE; + memory_end = memory_size; /* * We need some free virtual space to be able to do vmalloc. * On a machine with 2GB memory we make sure that we have at @@ -223,8 +212,6 @@ */ if (memory_end > 1920*1024*1024) memory_end = 1920*1024*1024; - memory_start = (unsigned long) &_end; /* fixit if use $CODELO etc*/ - memory_end = MEMORY_SIZE; /* detected in head.s */ init_mm.start_code = PAGE_OFFSET; init_mm.end_code = (unsigned long) &_etext; init_mm.end_data = (unsigned long) &_edata; @@ -311,7 +298,6 @@ */ reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size); - paging_init(); #ifdef CONFIG_BLK_DEV_INITRD if (INITRD_START) { if (INITRD_START + INITRD_SIZE <= memory_end) { @@ -326,6 +312,9 @@ } } #endif + + paging_init(); + res = alloc_bootmem_low(sizeof(struct resource)); res->start = 0; res->end = memory_end; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/signal.c linux.ac/arch/s390/kernel/signal.c --- linux.vanilla/arch/s390/kernel/signal.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390/kernel/signal.c Thu Apr 12 11:59:46 2001 @@ -187,7 +187,7 @@ int err; s390_fp_regs fpregs; - err = __copy_to_user(&sregs->regs,regs,sizeof(s390_regs_common)); + err = __copy_to_user(&sregs->regs,regs,sizeof(_s390_regs_common)); if(!err) { save_fp_regs(&fpregs); @@ -202,7 +202,7 @@ int err; s390_fp_regs fpregs; psw_t saved_psw=regs->psw; - err=__copy_from_user(regs,&sregs->regs,sizeof(s390_regs_common)); + err=__copy_from_user(regs,&sregs->regs,sizeof(_s390_regs_common)); if(!err) { regs->orig_gpr2 = -1; /* disable syscall checks */ @@ -218,7 +218,7 @@ } static int -restore_sigcontext(struct sigcontext *sc, pt_regs *regs, +restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs, _sigregs *sregs,sigset_t *set) { unsigned int err; @@ -555,6 +555,7 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: + case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (do_coredump(signr, regs)) exit_code |= 0x80; /* FALLTHRU */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/smp.c linux.ac/arch/s390/kernel/smp.c --- linux.vanilla/arch/s390/kernel/smp.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390/kernel/smp.c Thu Apr 12 11:59:46 2001 @@ -20,6 +20,7 @@ * cpu_number_map in other architectures. */ +#include <linux/module.h> #include <linux/init.h> #include <linux/mm.h> @@ -33,8 +34,7 @@ #include <asm/pgalloc.h> #include <asm/irq.h> #include <asm/s390_ext.h> - -#include "cpcmd.h" +#include <asm/cpcmd.h> /* prototypes */ extern int cpu_idle(void * unused); @@ -390,7 +390,7 @@ /* stop all processors */ - smp_signal_others(sigp_stop, 0, TRUE, NULL); + smp_signal_others(sigp_stop, 0, 1, NULL); /* store status of all processors in their lowcores (real 0) */ @@ -586,7 +586,7 @@ struct pt_regs regs; /* don't care about the psw and regs settings since we'll never reschedule the forked task. */ - memset(®s,0,sizeof(pt_regs)); + memset(®s,0,sizeof(struct pt_regs)); return do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0); } @@ -772,3 +772,7 @@ } } +EXPORT_SYMBOL(lowcore_ptr); +EXPORT_SYMBOL(kernel_flag); +EXPORT_SYMBOL(smp_ctl_set_bit); +EXPORT_SYMBOL(smp_ctl_clear_bit); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/traps.c linux.ac/arch/s390/kernel/traps.c --- linux.vanilla/arch/s390/kernel/traps.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390/kernel/traps.c Thu Apr 12 11:59:46 2001 @@ -35,6 +35,7 @@ #if CONFIG_REMOTE_DEBUG #include <asm/gdb-stub.h> #endif +#include <asm/cpcmd.h> /* Called from entry.S only */ extern void handle_per_exception(struct pt_regs *regs); @@ -51,6 +52,7 @@ #endif extern pgm_check_handler_t do_page_fault; +extern pgm_check_handler_t do_pseudo_page_fault; spinlock_t die_lock; @@ -140,7 +142,7 @@ 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, "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) @@ -149,7 +151,7 @@ { __u8 opcode[6]; __u16 *location; - int do_sig = 0; + int signal = 0; int problem_state=(regs->psw.mask & PSW_PROBLEM_STATE); lock_kernel(); @@ -161,82 +163,93 @@ if(*((__u16 *)opcode)==S390_BREAKPOINT_U16) { if(do_debugger_trap(regs,SIGTRAP)) - do_sig=1; + signal = SIGILL; } -#ifdef CONFIG_IEEEFPU_EMULATION - else if (problem_state ) +#ifdef CONFIG_MATHEMU + else if (problem_state) { if (opcode[0] == 0xb3) { get_user(*((__u16 *) (opcode+2)), location+1); - do_sig = math_emu_b3(opcode, regs); + signal = math_emu_b3(opcode, regs); } else if (opcode[0] == 0xed) { get_user(*((__u32 *) (opcode+2)), (__u32 *)(location+1)); - do_sig = math_emu_ed(opcode, regs); + signal = math_emu_ed(opcode, regs); } else if (*((__u16 *) opcode) == 0xb299) { get_user(*((__u16 *) (opcode+2)), location+1); - do_sig = math_emu_srnm(opcode, regs); + signal = math_emu_srnm(opcode, regs); } else if (*((__u16 *) opcode) == 0xb29c) { get_user(*((__u16 *) (opcode+2)), location+1); - do_sig = math_emu_stfpc(opcode, regs); + signal = math_emu_stfpc(opcode, regs); } else if (*((__u16 *) opcode) == 0xb29d) { get_user(*((__u16 *) (opcode+2)), location+1); - do_sig = math_emu_lfpc(opcode, regs); + signal = math_emu_lfpc(opcode, regs); } else - do_sig = 1; + signal = SIGILL; } #endif else - do_sig = 1; - if (do_sig) - do_trap(interruption_code, SIGILL, "illegal operation", regs, NULL); + signal = SIGILL; + if (signal == SIGFPE) { + current->thread.ieee_instruction_pointer = (addr_t) location; + do_trap(interruption_code, signal, + "floating point exception", regs, NULL); + } else if (signal) + do_trap(interruption_code, signal, + "illegal operation", regs, NULL); unlock_kernel(); } -#ifdef CONFIG_IEEEFPU_EMULATION -asmlinkage void specification_exception(struct pt_regs * regs, long interruption_code) +#ifdef CONFIG_MATHEMU +asmlinkage void +specification_exception(struct pt_regs * regs, long interruption_code) { __u8 opcode[6]; __u16 *location; - int do_sig = 0; + int signal = 0; lock_kernel(); - if (regs->psw.mask & 0x00010000L) { + if (regs->psw.mask & PSW_PROBLEM_STATE) { location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); get_user(*((__u16 *) opcode), location); switch (opcode[0]) { case 0x28: /* LDR Rx,Ry */ - do_sig=math_emu_ldr(opcode); + signal = math_emu_ldr(opcode); break; case 0x38: /* LER Rx,Ry */ - do_sig=math_emu_ler(opcode); + signal = math_emu_ler(opcode); break; case 0x60: /* STD R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - do_sig=math_emu_std(opcode, regs); + signal = math_emu_std(opcode, regs); break; case 0x68: /* LD R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - do_sig=math_emu_ld(opcode, regs); + signal = math_emu_ld(opcode, regs); break; case 0x70: /* STE R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - do_sig=math_emu_ste(opcode, regs); + signal = math_emu_ste(opcode, regs); break; case 0x78: /* LE R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - do_sig=math_emu_le(opcode, regs); + signal = math_emu_le(opcode, regs); break; default: - do_sig = 1; + signal = SIGILL; break; } } else - do_sig = 1; - if (do_sig) - do_trap(interruption_code, SIGILL, "specification exception", regs, NULL); + signal = SIGILL; + if (signal == SIGFPE) { + current->thread.ieee_instruction_pointer = (addr_t) location; + do_trap(interruption_code, signal, + "floating point exception", regs, NULL); + } else if (signal) + do_trap(interruption_code, signal, + "specification exception", regs, NULL); unlock_kernel(); } #else @@ -247,80 +260,79 @@ { __u8 opcode[6]; __u16 *location; - int do_sig = 0; + int signal = 0; lock_kernel(); location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); - if(MACHINE_HAS_IEEE) - { + if (MACHINE_HAS_IEEE) __asm__ volatile ("stfpc %0\n\t" : "=m" (current->thread.fp_regs.fpc)); - } - /* Same code should work when we implement fpu emulation */ - /* provided we call data exception from the fpu emulator */ - if(current->thread.fp_regs.fpc&FPC_DXC_MASK) - { - current->thread.ieee_instruction_pointer=(addr_t)location; - force_sig(SIGFPE, current); - } -#ifdef CONFIG_IEEEFPU_EMULATION - else if (regs->psw.mask & 0x00010000L) { + +#ifdef CONFIG_MATHEMU + else if (regs->psw.mask & PSW_PROBLEM_STATE) { get_user(*((__u16 *) opcode), location); switch (opcode[0]) { case 0x28: /* LDR Rx,Ry */ - do_sig=math_emu_ldr(opcode); + signal = math_emu_ldr(opcode); break; case 0x38: /* LER Rx,Ry */ - do_sig=math_emu_ler(opcode); + signal = math_emu_ler(opcode); break; case 0x60: /* STD R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - do_sig=math_emu_std(opcode, regs); + signal = math_emu_std(opcode, regs); break; case 0x68: /* LD R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - do_sig=math_emu_ld(opcode, regs); + signal = math_emu_ld(opcode, regs); break; case 0x70: /* STE R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - do_sig=math_emu_ste(opcode, regs); + signal = math_emu_ste(opcode, regs); break; case 0x78: /* LE R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - do_sig=math_emu_le(opcode, regs); + signal = math_emu_le(opcode, regs); break; case 0xb3: get_user(*((__u16 *) (opcode+2)), location+1); - do_sig = math_emu_b3(opcode, regs); + signal = math_emu_b3(opcode, regs); break; case 0xed: get_user(*((__u32 *) (opcode+2)), (__u32 *)(location+1)); - do_sig = math_emu_ed(opcode, regs); + signal = math_emu_ed(opcode, regs); break; case 0xb2: if (opcode[1] == 0x99) { get_user(*((__u16 *) (opcode+2)), location+1); - do_sig = math_emu_srnm(opcode, regs); + signal = math_emu_srnm(opcode, regs); } else if (opcode[1] == 0x9c) { get_user(*((__u16 *) (opcode+2)), location+1); - do_sig = math_emu_stfpc(opcode, regs); + signal = math_emu_stfpc(opcode, regs); } else if (opcode[1] == 0x9d) { get_user(*((__u16 *) (opcode+2)), location+1); - do_sig = math_emu_lfpc(opcode, regs); + signal = math_emu_lfpc(opcode, regs); } else - do_sig = 1; + signal = SIGILL; break; default: - do_sig = 1; + signal = SIGILL; break; } } #endif + if (current->thread.fp_regs.fpc & FPC_DXC_MASK) + signal = SIGFPE; else - do_sig = 1; - if (do_sig) - do_trap(interruption_code, SIGILL, "data exception", regs, NULL); + signal = SIGILL; + if (signal == SIGFPE) { + current->thread.ieee_instruction_pointer = (addr_t) location; + do_trap(interruption_code, signal, + "floating point exception", regs, NULL); + } else if (signal) + do_trap(interruption_code, signal, + "data exception", regs, NULL); unlock_kernel(); } @@ -337,17 +349,20 @@ pgm_check_table[1] = &illegal_op; pgm_check_table[2] = &privileged_op; pgm_check_table[3] = &execute_exception; + pgm_check_table[4] = &do_page_fault; pgm_check_table[5] = &addressing_exception; pgm_check_table[6] = &specification_exception; pgm_check_table[7] = &data_exception; pgm_check_table[9] = ÷_exception; + pgm_check_table[0x10] = &do_page_fault; + pgm_check_table[0x11] = &do_page_fault; pgm_check_table[0x12] = &translation_exception; pgm_check_table[0x13] = &special_op_exception; + pgm_check_table[0x14] = &do_pseudo_page_fault; pgm_check_table[0x15] = &operand_exception; - pgm_check_table[4] = &do_page_fault; - pgm_check_table[0x10] = &do_page_fault; - pgm_check_table[0x11] = &do_page_fault; pgm_check_table[0x1C] = &privileged_op; + if (MACHINE_IS_VM) + cpcmd("SET PAGEX ON", NULL, 0); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/lib/Makefile linux.ac/arch/s390/lib/Makefile --- linux.vanilla/arch/s390/lib/Makefile Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390/lib/Makefile Thu Apr 12 11:59:46 2001 @@ -12,7 +12,8 @@ L_TARGET = lib.a -obj-y = checksum.o delay.o memset.o strcmp.o strncpy.o uaccess.o +obj-y = checksum.o delay.o memset.o misaligned.o strcmp.o strncpy.o uaccess.o +export-objs += misaligned.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/lib/checksum.c linux.ac/arch/s390/lib/checksum.c --- linux.vanilla/arch/s390/lib/checksum.c Fri May 12 19:41:45 2000 +++ linux.ac/arch/s390/lib/checksum.c Thu Apr 12 11:59:46 2001 @@ -23,18 +23,17 @@ unsigned int csum_partial (const unsigned char *buff, int len, unsigned int sum) { + register_pair rp; /* * Experiments with ethernet and slip connections show that buff * is aligned on either a 2-byte or 4-byte boundary. */ + rp.subreg.even = (unsigned long) buff; + rp.subreg.odd = (unsigned long) len; __asm__ __volatile__ ( - " lr 2,%1\n" /* address in gpr 2 */ - " lr 3,%2\n" /* length in gpr 3 */ - "0: cksm %0,2\n" /* do checksum on longs */ + "0: cksm %0,%1\n" /* do checksum on longs */ " jo 0b\n" - : "+&d" (sum) - : "d" (buff), "d" (len) - : "cc", "2", "3" ); + : "+&d" (sum), "+&a" (rp) : : "cc" ); return sum; } @@ -43,14 +42,16 @@ */ unsigned short csum_fold(unsigned int sum) { - __asm__ __volatile__ ( - " sr 3,3\n" /* %0 = H*65536 + L */ - " lr 2,%0\n" /* %0 = H L, R2/R3 = H L / 0 0 */ - " srdl 2,16\n" /* %0 = H L, R2/R3 = 0 H / L 0 */ - " alr 2,3\n" /* %0 = H L, R2/R3 = L H / L 0 */ - " alr %0,2\n" /* %0 = H+L+C L+H */ - " srl %0,16\n" /* %0 = H+L+C */ - : "+d" (sum) : : "cc", "2", "3"); - return ((unsigned short) ~sum); + register_pair rp; + + __asm__ __volatile__ ( + " slr %N1,%N1\n" /* %0 = H L */ + " lr %1,%0\n" /* %0 = H L, %1 = H L 0 0 */ + " srdl %1,16\n" /* %0 = H L, %1 = 0 H L 0 */ + " alr %1,%N1\n" /* %0 = H L, %1 = L H L 0 */ + " alr %0,%1\n" /* %0 = H+L+C L+H */ + " srl %0,16\n" /* %0 = H+L+C */ + : "+&d" (sum), "=d" (rp) : : "cc" ); + return ((unsigned short) ~sum); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/lib/misaligned.c linux.ac/arch/s390/lib/misaligned.c --- linux.vanilla/arch/s390/lib/misaligned.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/s390/lib/misaligned.c Thu Apr 12 11:59:46 2001 @@ -0,0 +1,29 @@ +/* + * arch/s390/lib/misaligned.c + * S390 misalignment panic stubs + * + * S390 version + * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com). + * + * xchg wants to panic if the pointer is not aligned. To avoid multiplying + * the panic message over and over again, the panic is done in the helper + * functions __misaligned_u32 and __misaligned_u16. + */ + +#include <linux/module.h> +#include <linux/kernel.h> + +void __misaligned_u16(void) +{ + panic("misaligned (__u16 *) in __xchg\n"); +} + +void __misaligned_u32(void) +{ + panic("misaligned (__u32 *) in __xchg\n"); +} + +EXPORT_SYMBOL(__misaligned_u16); +EXPORT_SYMBOL(__misaligned_u32); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/math-emu/Makefile linux.ac/arch/s390/math-emu/Makefile --- linux.vanilla/arch/s390/math-emu/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/s390/math-emu/Makefile Thu Apr 12 11:59:46 2001 @@ -0,0 +1,12 @@ +# +# Makefile for the FPU instruction emulation. +# + +O_TARGET := math-emu.o +obj-$(CONFIG_MATHEMU) := math.o qrnnd.o + +EXTRA_CFLAGS = -I. -I$(TOPDIR)/include/math-emu -w + +include $(TOPDIR)/Rules.make + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/math-emu/math.c linux.ac/arch/s390/math-emu/math.c --- linux.vanilla/arch/s390/math-emu/math.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/s390/math-emu/math.c Sat Apr 14 01:18:00 2001 @@ -0,0 +1,2152 @@ +/* + * arch/s390/math-emu/math.c + * + * S390 version + * Copyright (C) 1999-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), + * + * 'math.c' emulates IEEE instructions on a S390 processor + * that does not have the IEEE fpu (all processors before G5). + */ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <asm/uaccess.h> + +#include "sfp-util.h" +#include <math-emu/soft-fp.h> +#include <math-emu/single.h> +#include <math-emu/double.h> +#include <math-emu/quad.h> + +/* + * I miss a macro to round a floating point number to the + * nearest integer in the same floating point format. + */ +#define _FP_TO_FPINT_ROUND(fs, wc, X) \ + do { \ + switch (X##_c) \ + { \ + case FP_CLS_NORMAL: \ + if (X##_e > _FP_FRACBITS_##fs + _FP_EXPBIAS_##fs) \ + { /* floating point number has no bits after the dot. */ \ + } \ + else if (X##_e <= _FP_FRACBITS_##fs + _FP_EXPBIAS_##fs && \ + X##_e > _FP_EXPBIAS_##fs) \ + { /* some bits before the dot, some after it. */ \ + _FP_FRAC_SRS_##wc(X, _FP_WFRACBITS_##fs, \ + X##_e - _FP_EXPBIAS_##fs \ + + _FP_FRACBITS_##fs); \ + _FP_ROUND(wc, X); \ + _FP_FRAC_SLL_##wc(X, X##_e - _FP_EXPBIAS_##fs \ + + _FP_FRACBITS_##fs); \ + } \ + else \ + { /* all bits after the dot. */ \ + FP_SET_EXCEPTION(FP_EX_INEXACT); \ + X##_c = FP_CLS_ZERO; \ + } \ + break; \ + case FP_CLS_NAN: \ + case FP_CLS_INF: \ + case FP_CLS_ZERO: \ + break; \ + } \ + } while (0) + +#define FP_TO_FPINT_ROUND_S(X) _FP_TO_FPINT_ROUND(S,1,X) +#define FP_TO_FPINT_ROUND_D(X) _FP_TO_FPINT_ROUND(D,2,X) +#define FP_TO_FPINT_ROUND_Q(X) _FP_TO_FPINT_ROUND(Q,4,X) + +typedef union { + long double ld; + struct { + __u64 high; + __u64 low; + } w; +} mathemu_ldcv; + +#ifdef CONFIG_SYSCTL +int sysctl_ieee_emulation_warnings=1; +#endif + +#define mathemu_put_user(x, p) \ + do { \ + if (put_user((x),(p))) \ + return SIGSEGV; \ + } while (0) + +#define mathemu_get_user(x, p) \ + do { \ + if (get_user((x),(p))) \ + return SIGSEGV; \ + } while (0) + +#define mathemu_copy_from_user(d, s, n)\ + do { \ + if (copy_from_user((d),(s),(n)) == -EFAULT) \ + return SIGSEGV; \ + } while (0) + +#define mathemu_copy_to_user(d, s, n) \ + do { \ + if (copy_to_user((d),(s),(n)) == -EFAULT) \ + return SIGSEGV; \ + } while (0) + +static void display_emulation_not_implemented(char *instr) +{ + struct pt_regs *regs; + __u16 *location; + +#if CONFIG_SYSCTL + if(sysctl_ieee_emulation_warnings) +#endif + { + regs = current->thread.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 inline void emu_set_CC (int cc) +{ + current->thread.regs->psw.mask = + (current->thread.regs->psw.mask & 0xFFFFCFFF) | ((cc&3) << 12); +} + +/* + * Set the condition code in the user psw. + * 0 : Result is zero + * 1 : Result is less than zero + * 2 : Result is greater than zero + * 3 : Result is NaN or INF + */ +static inline void emu_set_CC_cs(int class, int sign) +{ + switch (class) { + case FP_CLS_NORMAL: + case FP_CLS_INF: + emu_set_CC(sign ? 1 : 2); + break; + case FP_CLS_ZERO: + emu_set_CC(0); + break; + case FP_CLS_NAN: + emu_set_CC(3); + break; + } +} + +/* Add long double */ +static int emu_axbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[rx].ui; + cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QB, &cvt.ld); + FP_ADD_Q(QR, QA, QB); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + emu_set_CC_cs(QR_c, QR_s); + return _fex; +} + +/* Add double */ +static int emu_adbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, ¤t->thread.fp_regs.fprs[ry].d); + FP_ADD_D(DR, DA, DB); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + emu_set_CC_cs(DR_c, DR_s); + return _fex; +} + +/* Add double */ +static int emu_adb (int rx, double *val) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, val); + FP_ADD_D(DR, DA, DB); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + emu_set_CC_cs(DR_c, DR_s); + return _fex; +} + +/* Add float */ +static int emu_aebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, ¤t->thread.fp_regs.fprs[ry].f); + FP_ADD_S(SR, SA, SB); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + emu_set_CC_cs(SR_c, SR_s); + return _fex; +} + +/* Add float */ +static int emu_aeb (int rx, float *val) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, val); + FP_ADD_S(SR, SA, SB); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + emu_set_CC_cs(SR_c, SR_s); + return _fex; +} + +/* Compare long double */ +static int emu_cxbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_Q(QB); + mathemu_ldcv cvt; + int IR; + + cvt.w.high = current->thread.fp_regs.fprs[rx].ui; + cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui; + FP_UNPACK_RAW_QP(QA, &cvt.ld); + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_RAW_QP(QB, &cvt.ld); + FP_CMP_Q(IR, QA, QB, 3); + /* + * IR == -1 if DA < DB, IR == 0 if DA == DB, + * IR == 1 if DA > DB and IR == 3 if unorderded + */ + emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR); + return 0; +} + +/* Compare double */ +static int emu_cdbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_D(DB); + int IR; + + FP_UNPACK_RAW_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_RAW_DP(DB, ¤t->thread.fp_regs.fprs[ry].d); + FP_CMP_D(IR, DA, DB, 3); + /* + * IR == -1 if DA < DB, IR == 0 if DA == DB, + * IR == 1 if DA > DB and IR == 3 if unorderded + */ + emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR); + return 0; +} + +/* Compare double */ +static int emu_cdb (int rx, double *val) { + FP_DECL_D(DA); FP_DECL_D(DB); + int IR; + + FP_UNPACK_RAW_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_RAW_DP(DB, val); + FP_CMP_D(IR, DA, DB, 3); + /* + * IR == -1 if DA < DB, IR == 0 if DA == DB, + * IR == 1 if DA > DB and IR == 3 if unorderded + */ + emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR); + return 0; +} + +/* Compare float */ +static int emu_cebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_S(SB); + int IR; + + FP_UNPACK_RAW_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_RAW_SP(SB, ¤t->thread.fp_regs.fprs[ry].f); + FP_CMP_S(IR, SA, SB, 3); + /* + * IR == -1 if DA < DB, IR == 0 if DA == DB, + * IR == 1 if DA > DB and IR == 3 if unorderded + */ + emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR); + return 0; +} + +/* Compare float */ +static int emu_ceb (int rx, float *val) { + FP_DECL_S(SA); FP_DECL_S(SB); + int IR; + + FP_UNPACK_RAW_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_RAW_SP(SB, val); + FP_CMP_S(IR, SA, SB, 3); + /* + * IR == -1 if DA < DB, IR == 0 if DA == DB, + * IR == 1 if DA > DB and IR == 3 if unorderded + */ + emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR); + return 0; +} + +/* Compare and signal long double */ +static int emu_kxbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_Q(QB); + FP_DECL_EX; + mathemu_ldcv cvt; + int IR; + + cvt.w.high = current->thread.fp_regs.fprs[rx].ui; + cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui; + FP_UNPACK_RAW_QP(QA, &cvt.ld); + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QB, &cvt.ld); + FP_CMP_Q(IR, QA, QB, 3); + /* + * IR == -1 if DA < DB, IR == 0 if DA == DB, + * IR == 1 if DA > DB and IR == 3 if unorderded + */ + emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR); + if (IR == 3) + FP_SET_EXCEPTION (FP_EX_INVALID); + return _fex; +} + +/* Compare and signal double */ +static int emu_kdbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_D(DB); + FP_DECL_EX; + int IR; + + FP_UNPACK_RAW_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_RAW_DP(DB, ¤t->thread.fp_regs.fprs[ry].d); + FP_CMP_D(IR, DA, DB, 3); + /* + * IR == -1 if DA < DB, IR == 0 if DA == DB, + * IR == 1 if DA > DB and IR == 3 if unorderded + */ + emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR); + if (IR == 3) + FP_SET_EXCEPTION (FP_EX_INVALID); + return _fex; +} + +/* Compare and signal double */ +static int emu_kdb (int rx, double *val) { + FP_DECL_D(DA); FP_DECL_D(DB); + FP_DECL_EX; + int IR; + + FP_UNPACK_RAW_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_RAW_DP(DB, val); + FP_CMP_D(IR, DA, DB, 3); + /* + * IR == -1 if DA < DB, IR == 0 if DA == DB, + * IR == 1 if DA > DB and IR == 3 if unorderded + */ + emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR); + if (IR == 3) + FP_SET_EXCEPTION (FP_EX_INVALID); + return _fex; +} + +/* Compare and signal float */ +static int emu_kebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_S(SB); + FP_DECL_EX; + int IR; + + FP_UNPACK_RAW_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_RAW_SP(SB, ¤t->thread.fp_regs.fprs[ry].f); + FP_CMP_S(IR, SA, SB, 3); + /* + * IR == -1 if DA < DB, IR == 0 if DA == DB, + * IR == 1 if DA > DB and IR == 3 if unorderded + */ + emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR); + if (IR == 3) + FP_SET_EXCEPTION (FP_EX_INVALID); + return _fex; +} + +/* Compare and signal float */ +static int emu_keb (int rx, float *val) { + FP_DECL_S(SA); FP_DECL_S(SB); + FP_DECL_EX; + int IR; + + FP_UNPACK_RAW_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_RAW_SP(SB, val); + FP_CMP_S(IR, SA, SB, 3); + /* + * IR == -1 if DA < DB, IR == 0 if DA == DB, + * IR == 1 if DA > DB and IR == 3 if unorderded + */ + emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR); + if (IR == 3) + FP_SET_EXCEPTION (FP_EX_INVALID); + return _fex; +} + +/* Convert from fixed long double */ +static int emu_cxfbr (int rx, int ry) { + FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + __s32 si; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + si = current->thread.regs->gprs[ry]; + FP_FROM_INT_Q(QR, si, 32, int); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + return _fex; +} + +/* Convert from fixed double */ +static int emu_cdfbr (int rx, int ry) { + FP_DECL_D(DR); + FP_DECL_EX; + __s32 si; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + si = current->thread.regs->gprs[ry]; + FP_FROM_INT_D(DR, si, 32, int); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + return _fex; +} + +/* Convert from fixed float */ +static int emu_cefbr (int rx, int ry) { + FP_DECL_S(SR); + FP_DECL_EX; + __s32 si; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + si = current->thread.regs->gprs[ry]; + FP_FROM_INT_S(SR, si, 32, int); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + return _fex; +} + +/* Convert to fixed long double */ +static int emu_cfxbr (int rx, int ry, int mask) { + FP_DECL_Q(QA); + FP_DECL_EX; + mathemu_ldcv cvt; + __s32 si; + int mode; + + if (mask == 0) + mode = current->thread.fp_regs.fpc & 3; + else if (mask == 1) + mode = FP_RND_NEAREST; + else + mode = mask - 4; + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + FP_TO_INT_ROUND_Q(si, QA, 32, 1); + current->thread.regs->gprs[rx] = si; + emu_set_CC_cs(QA_c, QA_s); + return _fex; +} + +/* Convert to fixed double */ +static int emu_cfdbr (int rx, int ry, int mask) { + FP_DECL_D(DA); + FP_DECL_EX; + __s32 si; + int mode; + + if (mask == 0) + mode = current->thread.fp_regs.fpc & 3; + else if (mask == 1) + mode = FP_RND_NEAREST; + else + mode = mask - 4; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[ry].d); + FP_TO_INT_ROUND_D(si, DA, 32, 1); + current->thread.regs->gprs[rx] = si; + emu_set_CC_cs(DA_c, DA_s); + return _fex; +} + +/* Convert to fixed float */ +static int emu_cfebr (int rx, int ry, int mask) { + FP_DECL_S(SA); + FP_DECL_EX; + __s32 si; + int mode; + + if (mask == 0) + mode = current->thread.fp_regs.fpc & 3; + else if (mask == 1) + mode = FP_RND_NEAREST; + else + mode = mask - 4; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[ry].f); + FP_TO_INT_ROUND_S(si, SA, 32, 1); + current->thread.regs->gprs[rx] = si; + emu_set_CC_cs(SA_c, SA_s); + return _fex; +} + +/* Divide long double */ +static int emu_dxbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[rx].ui; + cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QB, &cvt.ld); + FP_DIV_Q(QR, QA, QB); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + return _fex; +} + +/* Divide double */ +static int emu_ddbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, ¤t->thread.fp_regs.fprs[ry].d); + FP_DIV_D(DR, DA, DB); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + return _fex; +} + +/* Divide double */ +static int emu_ddb (int rx, double *val) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, val); + FP_DIV_D(DR, DA, DB); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + return _fex; +} + +/* Divide float */ +static int emu_debr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, ¤t->thread.fp_regs.fprs[ry].f); + FP_DIV_S(SR, SA, SB); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + return _fex; +} + +/* Divide float */ +static int emu_deb (int rx, float *val) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, val); + FP_DIV_S(SR, SA, SB); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + return _fex; +} + +/* Divide to integer double */ +static int emu_didbr (int rx, int ry, int mask) { + display_emulation_not_implemented("didbr"); + return 0; +} + +/* Divide to integer float */ +static int emu_diebr (int rx, int ry, int mask) { + display_emulation_not_implemented("diebr"); + return 0; +} + +/* Extract fpc */ +static int emu_efpc (int rx, int ry) { + current->thread.regs->gprs[rx] = current->thread.fp_regs.fpc; + return 0; +} + +/* Load and test long double */ +static int emu_ltxbr (int rx, int ry) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + mathemu_ldcv cvt; + FP_DECL_Q(QA); + FP_DECL_EX; + + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui; + fp_regs->fprs[rx+2].ui = fp_regs->fprs[ry+2].ui; + emu_set_CC_cs(QA_c, QA_s); + return _fex; +} + +/* Load and test double */ +static int emu_ltdbr (int rx, int ry) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + FP_DECL_D(DA); + FP_DECL_EX; + + FP_UNPACK_DP(DA, &fp_regs->fprs[ry].d); + fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui; + emu_set_CC_cs(DA_c, DA_s); + return _fex; +} + +/* Load and test double */ +static int emu_ltebr (int rx, int ry) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + FP_DECL_S(SA); + FP_DECL_EX; + + FP_UNPACK_SP(SA, &fp_regs->fprs[ry].f); + fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui; + emu_set_CC_cs(SA_c, SA_s); + return _fex; +} + +/* Load complement long double */ +static int emu_lcxbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + FP_NEG_Q(QR, QA); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + emu_set_CC_cs(QR_c, QR_s); + return _fex; +} + +/* Load complement double */ +static int emu_lcdbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[ry].d); + FP_NEG_D(DR, DA); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + emu_set_CC_cs(DR_c, DR_s); + return _fex; +} + +/* Load complement float */ +static int emu_lcebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[ry].f); + FP_NEG_S(SR, SA); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + emu_set_CC_cs(SR_c, SR_s); + return _fex; +} + +/* Load floating point integer long double */ +static int emu_fixbr (int rx, int ry, int mask) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + FP_DECL_Q(QA); + FP_DECL_EX; + mathemu_ldcv cvt; + __s32 si; + int mode; + + if (mask == 0) + mode = fp_regs->fpc & 3; + else if (mask == 1) + mode = FP_RND_NEAREST; + else + mode = mask - 4; + cvt.w.high = fp_regs->fprs[ry].ui; + cvt.w.low = fp_regs->fprs[ry+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + FP_TO_FPINT_ROUND_Q(QA); + FP_PACK_QP(&cvt.ld, QA); + fp_regs->fprs[rx].ui = cvt.w.high; + fp_regs->fprs[rx+2].ui = cvt.w.low; + return _fex; +} + +/* Load floating point integer double */ +static int emu_fidbr (int rx, int ry, int mask) { + /* FIXME: rounding mode !! */ + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + FP_DECL_D(DA); + FP_DECL_EX; + __s32 si; + int mode; + + if (mask == 0) + mode = fp_regs->fpc & 3; + else if (mask == 1) + mode = FP_RND_NEAREST; + else + mode = mask - 4; + FP_UNPACK_DP(DA, &fp_regs->fprs[ry].d); + FP_TO_FPINT_ROUND_D(DA); + FP_PACK_DP(&fp_regs->fprs[rx].d, DA); + return _fex; +} + +/* Load floating point integer float */ +static int emu_fiebr (int rx, int ry, int mask) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + FP_DECL_S(SA); + FP_DECL_EX; + __s32 si; + int mode; + + if (mask == 0) + mode = fp_regs->fpc & 3; + else if (mask == 1) + mode = FP_RND_NEAREST; + else + mode = mask - 4; + FP_UNPACK_SP(SA, &fp_regs->fprs[ry].f); + FP_TO_FPINT_ROUND_S(SA); + FP_PACK_SP(&fp_regs->fprs[rx].f, SA); + return _fex; +} + +/* Load lengthened double to long double */ +static int emu_lxdbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[ry].d); + FP_CONV (Q, D, 4, 2, QR, DA); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + return _fex; +} + +/* Load lengthened double to long double */ +static int emu_lxdb (int rx, double *val) { + FP_DECL_D(DA); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, val); + FP_CONV (Q, D, 4, 2, QR, DA); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + return _fex; +} + +/* Load lengthened float to long double */ +static int emu_lxebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[ry].f); + FP_CONV (Q, S, 4, 1, QR, SA); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + return _fex; +} + +/* Load lengthened float to long double */ +static int emu_lxeb (int rx, float *val) { + FP_DECL_S(SA); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, val); + FP_CONV (Q, S, 4, 1, QR, SA); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + return _fex; +} + +/* Load lengthened float to double */ +static int emu_ldebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[ry].f); + FP_CONV (D, S, 2, 1, DR, SA); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + return _fex; +} + +/* Load lengthened float to double */ +static int emu_ldeb (int rx, float *val) { + FP_DECL_S(SA); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, val); + FP_CONV (D, S, 2, 1, DR, SA); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + return _fex; +} + +/* Load negative long double */ +static int emu_lnxbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + if (QA_s == 0) { + FP_NEG_Q(QR, QA); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + } else { + current->thread.fp_regs.fprs[rx].ui = + current->thread.fp_regs.fprs[ry].ui; + current->thread.fp_regs.fprs[rx+2].ui = + current->thread.fp_regs.fprs[ry+2].ui; + } + emu_set_CC_cs(QR_c, QR_s); + return _fex; +} + +/* Load negative double */ +static int emu_lndbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[ry].d); + if (DA_s == 0) { + FP_NEG_D(DR, DA); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + } else + current->thread.fp_regs.fprs[rx].ui = + current->thread.fp_regs.fprs[ry].ui; + emu_set_CC_cs(DR_c, DR_s); + return _fex; +} + +/* Load negative float */ +static int emu_lnebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[ry].f); + if (SA_s == 0) { + FP_NEG_S(SR, SA); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + } else + current->thread.fp_regs.fprs[rx].ui = + current->thread.fp_regs.fprs[ry].ui; + emu_set_CC_cs(SR_c, SR_s); + return _fex; +} + +/* Load positive long double */ +static int emu_lpxbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + if (QA_s != 0) { + FP_NEG_Q(QR, QA); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + } else{ + current->thread.fp_regs.fprs[rx].ui = + current->thread.fp_regs.fprs[ry].ui; + current->thread.fp_regs.fprs[rx+2].ui = + current->thread.fp_regs.fprs[ry+2].ui; + } + emu_set_CC_cs(QR_c, QR_s); + return _fex; +} + +/* Load positive double */ +static int emu_lpdbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[ry].d); + if (DA_s != 0) { + FP_NEG_D(DR, DA); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + } else + current->thread.fp_regs.fprs[rx].ui = + current->thread.fp_regs.fprs[ry].ui; + emu_set_CC_cs(DR_c, DR_s); + return _fex; +} + +/* Load positive float */ +static int emu_lpebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[ry].f); + if (SA_s != 0) { + FP_NEG_S(SR, SA); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + } else + current->thread.fp_regs.fprs[rx].ui = + current->thread.fp_regs.fprs[ry].ui; + emu_set_CC_cs(SR_c, SR_s); + return _fex; +} + +/* Load rounded long double to double */ +static int emu_ldxbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_D(DR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + FP_CONV (D, Q, 2, 4, DR, QA); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].f, DR); + return _fex; +} + +/* Load rounded long double to float */ +static int emu_lexbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_S(SR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + FP_CONV (S, Q, 1, 4, SR, QA); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + return _fex; +} + +/* Load rounded double to float */ +static int emu_ledbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[ry].d); + FP_CONV (S, D, 1, 2, SR, DA); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + return _fex; +} + +/* Multiply long double */ +static int emu_mxbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[rx].ui; + cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QB, &cvt.ld); + FP_MUL_Q(QR, QA, QB); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + return _fex; +} + +/* Multiply double */ +static int emu_mdbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, ¤t->thread.fp_regs.fprs[ry].d); + FP_MUL_D(DR, DA, DB); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + return _fex; +} + +/* Multiply double */ +static int emu_mdb (int rx, double *val) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, val); + FP_MUL_D(DR, DA, DB); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + return _fex; +} + +/* Multiply double to long double */ +static int emu_mxdbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_CONV (Q, D, 4, 2, QA, DA); + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[ry].d); + FP_CONV (Q, D, 4, 2, QB, DA); + FP_MUL_Q(QR, QA, QB); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + return _fex; +} + +/* Multiply double to long double */ +static int emu_mxdb (int rx, long double *val) { + FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[rx].ui; + cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + FP_UNPACK_QP(QB, val); + FP_MUL_Q(QR, QA, QB); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + return _fex; +} + +/* Multiply float */ +static int emu_meebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, ¤t->thread.fp_regs.fprs[ry].f); + FP_MUL_S(SR, SA, SB); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + return _fex; +} + +/* Multiply float */ +static int emu_meeb (int rx, float *val) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, val); + FP_MUL_S(SR, SA, SB); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + return _fex; +} + +/* Multiply float to double */ +static int emu_mdebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_CONV (D, S, 2, 1, DA, SA); + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[ry].f); + FP_CONV (D, S, 2, 1, DB, SA); + FP_MUL_D(DR, DA, DB); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + return _fex; +} + +/* Multiply float to double */ +static int emu_mdeb (int rx, float *val) { + FP_DECL_S(SA); FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_CONV (D, S, 2, 1, DA, SA); + FP_UNPACK_SP(SA, val); + FP_CONV (D, S, 2, 1, DB, SA); + FP_MUL_D(DR, DA, DB); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + return _fex; +} + +/* Multiply and add double */ +static int emu_madbr (int rx, int ry, int rz) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, ¤t->thread.fp_regs.fprs[ry].d); + FP_UNPACK_DP(DC, ¤t->thread.fp_regs.fprs[rz].d); + FP_MUL_D(DR, DA, DB); + FP_ADD_D(DR, DR, DC); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rz].d, DR); + return _fex; +} + +/* Multiply and add double */ +static int emu_madb (int rx, double *val, int rz) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, val); + FP_UNPACK_DP(DC, ¤t->thread.fp_regs.fprs[rz].d); + FP_MUL_D(DR, DA, DB); + FP_ADD_D(DR, DR, DC); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rz].d, DR); + return _fex; +} + +/* Multiply and add float */ +static int emu_maebr (int rx, int ry, int rz) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, ¤t->thread.fp_regs.fprs[ry].f); + FP_UNPACK_SP(SC, ¤t->thread.fp_regs.fprs[rz].f); + FP_MUL_S(SR, SA, SB); + FP_ADD_S(SR, SR, SC); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rz].f, SR); + return _fex; +} + +/* Multiply and add float */ +static int emu_maeb (int rx, float *val, int rz) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, val); + FP_UNPACK_SP(SC, ¤t->thread.fp_regs.fprs[rz].f); + FP_MUL_S(SR, SA, SB); + FP_ADD_S(SR, SR, SC); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rz].f, SR); + return _fex; +} + +/* Multiply and subtract double */ +static int emu_msdbr (int rx, int ry, int rz) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, ¤t->thread.fp_regs.fprs[ry].d); + FP_UNPACK_DP(DC, ¤t->thread.fp_regs.fprs[rz].d); + FP_MUL_D(DR, DA, DB); + FP_SUB_D(DR, DR, DC); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rz].d, DR); + return _fex; +} + +/* Multiply and subtract double */ +static int emu_msdb (int rx, double *val, int rz) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, val); + FP_UNPACK_DP(DC, ¤t->thread.fp_regs.fprs[rz].d); + FP_MUL_D(DR, DA, DB); + FP_SUB_D(DR, DR, DC); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rz].d, DR); + return _fex; +} + +/* Multiply and subtract float */ +static int emu_msebr (int rx, int ry, int rz) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, ¤t->thread.fp_regs.fprs[ry].f); + FP_UNPACK_SP(SC, ¤t->thread.fp_regs.fprs[rz].f); + FP_MUL_S(SR, SA, SB); + FP_SUB_S(SR, SR, SC); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rz].f, SR); + return _fex; +} + +/* Multiply and subtract float */ +static int emu_mseb (int rx, float *val, int rz) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, val); + FP_UNPACK_SP(SC, ¤t->thread.fp_regs.fprs[rz].f); + FP_MUL_S(SR, SA, SB); + FP_SUB_S(SR, SR, SC); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rz].f, SR); + return _fex; +} + +/* Set floating point control word */ +static int emu_sfpc (int rx, int ry) { + __u32 temp; + + temp = current->thread.regs->gprs[rx]; + if ((temp & ~FPC_VALID_MASK) != 0) + return SIGILL; + current->thread.fp_regs.fpc = temp; + return 0; +} + +/* Square root long double */ +static int emu_sqxbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + FP_SQRT_Q(QR, QA); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + emu_set_CC_cs(QR_c, QR_s); + return _fex; +} + +/* Square root double */ +static int emu_sqdbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[ry].d); + FP_SQRT_D(DR, DA); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + emu_set_CC_cs(DR_c, DR_s); + return _fex; +} + +/* Square root double */ +static int emu_sqdb (int rx, double *val) { + FP_DECL_D(DA); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, val); + FP_SQRT_D(DR, DA); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + emu_set_CC_cs(DR_c, DR_s); + return _fex; +} + +/* Square root float */ +static int emu_sqebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[ry].f); + FP_SQRT_S(SR, SA); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + emu_set_CC_cs(SR_c, SR_s); + return _fex; +} + +/* Square root float */ +static int emu_sqeb (int rx, float *val) { + FP_DECL_S(SA); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, val); + FP_SQRT_S(SR, SA); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + emu_set_CC_cs(SR_c, SR_s); + return _fex; +} + +/* Subtract long double */ +static int emu_sxbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[rx].ui; + cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QB, &cvt.ld); + FP_SUB_Q(QR, QA, QB); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + emu_set_CC_cs(QR_c, QR_s); + return _fex; +} + +/* Subtract double */ +static int emu_sdbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, ¤t->thread.fp_regs.fprs[ry].d); + FP_SUB_D(DR, DA, DB); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + emu_set_CC_cs(DR_c, DR_s); + return _fex; +} + +/* Subtract double */ +static int emu_sdb (int rx, double *val) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, val); + FP_SUB_D(DR, DA, DB); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + emu_set_CC_cs(DR_c, DR_s); + return _fex; +} + +/* Subtract float */ +static int emu_sebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, ¤t->thread.fp_regs.fprs[ry].f); + FP_SUB_S(SR, SA, SB); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + emu_set_CC_cs(SR_c, SR_s); + return _fex; +} + +/* Subtract float */ +static int emu_seb (int rx, float *val) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, val); + FP_SUB_S(SR, SA, SB); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + emu_set_CC_cs(SR_c, SR_s); + return _fex; +} + +/* Test data class long double */ +static int emu_tcxb (int rx, double *val) { + display_emulation_not_implemented("tcxb"); + return 0; +} + +/* Test data class double */ +static int emu_tcdb (int rx, double *val) { + display_emulation_not_implemented("tcdb"); + return 0; +} + +/* Test data class float */ +static int emu_tceb (int rx, __u32 val) { + display_emulation_not_implemented("tceb"); + return 0; +} + +static inline void emu_load_regd(int reg) { + if ((reg&9) != 0) /* test if reg in {0,2,4,6} */ + return; + asm volatile ( /* load reg from fp_regs.fprs[reg] */ + " bras 1,0f\n" + " ld 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" (reg<<4),"a" (¤t->thread.fp_regs.fprs[reg].d) + : "1" ); +} + +static inline void emu_load_rege(int reg) { + if ((reg&9) != 0) /* test if reg in {0,2,4,6} */ + return; + asm volatile ( /* load reg from fp_regs.fprs[reg] */ + " bras 1,0f\n" + " le 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].f) + : "1" ); +} + +static inline void emu_store_regd(int reg) { + if ((reg&9) != 0) /* test if reg in {0,2,4,6} */ + return; + asm volatile ( /* store reg to fp_regs.fprs[reg] */ + " bras 1,0f\n" + " std 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].d) + : "1" ); +} + + +static inline void emu_store_rege(int reg) { + if ((reg&9) != 0) /* test if reg in {0,2,4,6} */ + return; + asm volatile ( /* store reg to fp_regs.fprs[reg] */ + " bras 1,0f\n" + " ste 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].f) + : "1" ); +} + +int math_emu_b3(__u8 *opcode, struct pt_regs * regs) { + int _fex = 0; + static const __u8 format_table[256] = { + [0x00] = 0x03,[0x01] = 0x03,[0x02] = 0x03,[0x03] = 0x03, + [0x04] = 0x0f,[0x05] = 0x0d,[0x06] = 0x0e,[0x07] = 0x0d, + [0x08] = 0x03,[0x09] = 0x03,[0x0a] = 0x03,[0x0b] = 0x03, + [0x0c] = 0x0f,[0x0d] = 0x03,[0x0e] = 0x06,[0x0f] = 0x06, + [0x10] = 0x02,[0x11] = 0x02,[0x12] = 0x02,[0x13] = 0x02, + [0x14] = 0x03,[0x15] = 0x02,[0x16] = 0x01,[0x17] = 0x03, + [0x18] = 0x02,[0x19] = 0x02,[0x1a] = 0x02,[0x1b] = 0x02, + [0x1c] = 0x02,[0x1d] = 0x02,[0x1e] = 0x05,[0x1f] = 0x05, + [0x40] = 0x01,[0x41] = 0x01,[0x42] = 0x01,[0x43] = 0x01, + [0x44] = 0x12,[0x45] = 0x0d,[0x46] = 0x11,[0x47] = 0x04, + [0x48] = 0x01,[0x49] = 0x01,[0x4a] = 0x01,[0x4b] = 0x01, + [0x4c] = 0x01,[0x4d] = 0x01,[0x53] = 0x06,[0x57] = 0x06, + [0x5b] = 0x05,[0x5f] = 0x05,[0x84] = 0x13,[0x8c] = 0x13, + [0x94] = 0x09,[0x95] = 0x08,[0x96] = 0x07,[0x98] = 0x0c, + [0x99] = 0x0b,[0x9a] = 0x0a + }; + static const void *jump_table[256]= { + [0x00] = emu_lpebr,[0x01] = emu_lnebr,[0x02] = emu_ltebr, + [0x03] = emu_lcebr,[0x04] = emu_ldebr,[0x05] = emu_lxdbr, + [0x06] = emu_lxebr,[0x07] = emu_mxdbr,[0x08] = emu_kebr, + [0x09] = emu_cebr, [0x0a] = emu_aebr, [0x0b] = emu_sebr, + [0x0c] = emu_mdebr,[0x0d] = emu_debr, [0x0e] = emu_maebr, + [0x0f] = emu_msebr,[0x10] = emu_lpdbr,[0x11] = emu_lndbr, + [0x12] = emu_ltdbr,[0x13] = emu_lcdbr,[0x14] = emu_sqebr, + [0x15] = emu_sqdbr,[0x16] = emu_sqxbr,[0x17] = emu_meebr, + [0x18] = emu_kdbr, [0x19] = emu_cdbr, [0x1a] = emu_adbr, + [0x1b] = emu_sdbr, [0x1c] = emu_mdbr, [0x1d] = emu_ddbr, + [0x1e] = emu_madbr,[0x1f] = emu_msdbr,[0x40] = emu_lpxbr, + [0x41] = emu_lnxbr,[0x42] = emu_ltxbr,[0x43] = emu_lcxbr, + [0x44] = emu_ledbr,[0x45] = emu_ldxbr,[0x46] = emu_lexbr, + [0x47] = emu_fixbr,[0x48] = emu_kxbr, [0x49] = emu_cxbr, + [0x4a] = emu_axbr, [0x4b] = emu_sxbr, [0x4c] = emu_mxbr, + [0x4d] = emu_dxbr, [0x53] = emu_diebr,[0x57] = emu_fiebr, + [0x5b] = emu_didbr,[0x5f] = emu_fidbr,[0x84] = emu_sfpc, + [0x8c] = emu_efpc, [0x94] = emu_cefbr,[0x95] = emu_cdfbr, + [0x96] = emu_cxfbr,[0x98] = emu_cfebr,[0x99] = emu_cfdbr, + [0x9a] = emu_cfxbr + }; + + switch (format_table[opcode[1]]) { + case 1: /* RRE format, long double operation */ + if (opcode[3] & 0x22) + return SIGILL; + emu_store_regd((opcode[3] >> 4) & 15); + emu_store_regd(((opcode[3] >> 4) & 15) + 2); + emu_store_regd(opcode[3] & 15); + emu_store_regd((opcode[3] & 15) + 2); + /* call the emulation function */ + _fex = ((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] >> 4) & 15) + 2); + emu_load_regd(opcode[3] & 15); + emu_load_regd((opcode[3] & 15) + 2); + break; + case 2: /* RRE format, double operation */ + emu_store_regd((opcode[3] >> 4) & 15); + emu_store_regd(opcode[3] & 15); + /* call the emulation function */ + _fex = ((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); + break; + case 3: /* RRE format, float operation */ + emu_store_rege((opcode[3] >> 4) & 15); + emu_store_rege(opcode[3] & 15); + /* call the emulation function */ + _fex = ((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); + break; + case 4: /* RRF format, long double operation */ + if (opcode[3] & 0x22) + return SIGILL; + emu_store_regd((opcode[3] >> 4) & 15); + emu_store_regd(((opcode[3] >> 4) & 15) + 2); + emu_store_regd(opcode[3] & 15); + emu_store_regd((opcode[3] & 15) + 2); + /* call the emulation function */ + _fex = ((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] >> 4) & 15) + 2); + emu_load_regd(opcode[3] & 15); + emu_load_regd((opcode[3] & 15) + 2); + break; + case 5: /* RRF format, double operation */ + emu_store_regd((opcode[2] >> 4) & 15); + emu_store_regd((opcode[3] >> 4) & 15); + emu_store_regd(opcode[3] & 15); + /* call the emulation function */ + _fex = ((int (*)(int, int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4); + emu_load_regd((opcode[2] >> 4) & 15); + emu_load_regd((opcode[3] >> 4) & 15); + emu_load_regd(opcode[3] & 15); + break; + case 6: /* RRF format, float operation */ + emu_store_rege((opcode[2] >> 4) & 15); + emu_store_rege((opcode[3] >> 4) & 15); + emu_store_rege(opcode[3] & 15); + /* call the emulation function */ + _fex = ((int (*)(int, int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4); + emu_load_rege((opcode[2] >> 4) & 15); + emu_load_rege((opcode[3] >> 4) & 15); + emu_load_rege(opcode[3] & 15); + break; + case 7: /* RRE format, cxfbr instruction */ + /* call the emulation function */ + if (opcode[3] & 0x20) + return SIGILL; + _fex = ((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] >> 4) & 15) + 2); + break; + case 8: /* RRE format, cdfbr instruction */ + /* call the emulation function */ + _fex = ((int (*)(int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15); + emu_load_regd((opcode[3] >> 4) & 15); + break; + case 9: /* RRE format, cefbr instruction */ + /* call the emulation function */ + _fex = ((int (*)(int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15); + emu_load_rege((opcode[3] >> 4) & 15); + break; + case 10: /* RRF format, cfxbr instruction */ + if ((opcode[2] & 128) == 128 || (opcode[2] & 96) == 32) + /* mask of { 2,3,8-15 } is invalid */ + return SIGILL; + if (opcode[3] & 2) + return SIGILL; + emu_store_regd(opcode[3] & 15); + emu_store_regd((opcode[3] & 15) + 2); + /* call the emulation function */ + _fex = ((int (*)(int, int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4); + break; + case 11: /* RRF format, cfdbr instruction */ + if ((opcode[2] & 128) == 128 || (opcode[2] & 96) == 32) + /* mask of { 2,3,8-15 } is invalid */ + return SIGILL; + emu_store_regd(opcode[3] & 15); + /* call the emulation function */ + _fex = ((int (*)(int, int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4); + break; + case 12: /* RRF format, cfebr instruction */ + if ((opcode[2] & 128) == 128 || (opcode[2] & 96) == 32) + /* mask of { 2,3,8-15 } is invalid */ + return SIGILL; + emu_store_rege(opcode[3] & 15); + /* call the emulation function */ + _fex = ((int (*)(int, int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4); + break; + case 13: /* RRE format, ldxbr & mdxbr instruction */ + /* double store but long double load */ + if (opcode[3] & 0x20) + return SIGILL; + emu_store_regd((opcode[3] >> 4) & 15); + emu_store_regd(opcode[3] & 15); + /* call the emulation function */ + _fex = ((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] >> 4) & 15) + 2); + break; + case 14: /* RRE format, ldxbr & mdxbr instruction */ + /* float store but long double load */ + if (opcode[3] & 0x20) + return SIGILL; + emu_store_rege((opcode[3] >> 4) & 15); + emu_store_rege(opcode[3] & 15); + /* call the emulation function */ + _fex = ((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] >> 4) & 15) + 2); + break; + case 15: /* 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 */ + _fex = ((int (*)(int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15); + emu_load_regd((opcode[3] >> 4) & 15); + break; + case 16: /* RRE format, ldxbr instruction */ + /* long double store but double load */ + if (opcode[3] & 2) + return SIGILL; + emu_store_regd(opcode[3] & 15); + emu_store_regd((opcode[3] & 15) + 2); + /* call the emulation function */ + _fex = ((int (*)(int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15); + emu_load_regd((opcode[3] >> 4) & 15); + break; + case 17: /* RRE format, ldxbr instruction */ + /* long double store but float load */ + if (opcode[3] & 2) + return SIGILL; + emu_store_regd(opcode[3] & 15); + emu_store_regd((opcode[3] & 15) + 2); + /* call the emulation function */ + _fex = ((int (*)(int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15); + emu_load_rege((opcode[3] >> 4) & 15); + break; + case 18: /* RRE format, ledbr instruction */ + /* double store but float load */ + emu_store_regd(opcode[3] & 15); + /* call the emulation function */ + _fex = ((int (*)(int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15); + emu_load_rege((opcode[3] >> 4) & 15); + break; + case 19: /* RRE format, efpc & sfpc instruction */ + /* call the emulation function */ + _fex = ((int (*)(int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15); + break; + default: /* invalid operation */ + return SIGILL; + } + if (_fex != 0) { + current->thread.fp_regs.fpc |= _fex; + if (current->thread.fp_regs.fpc & (_fex << 8)) + return SIGFPE; + } + return 0; +} + +static void* calc_addr(struct pt_regs *regs, int rx, int rb, int disp) +{ + addr_t addr; + + rx &= 15; + rb &= 15; + addr = disp & 0xfff; + addr += (rx != 0) ? regs->gprs[rx] : 0; /* + index */ + addr += (rb != 0) ? regs->gprs[rb] : 0; /* + base */ + return (void*) addr; +} + +int math_emu_ed(__u8 *opcode, struct pt_regs * regs) { + int _fex = 0; + + static const __u8 format_table[256] = { + [0x04] = 0x08,[0x05] = 0x07,[0x06] = 0x09,[0x07] = 0x07, + [0x08] = 0x03,[0x09] = 0x03,[0x0a] = 0x03,[0x0b] = 0x03, + [0x0c] = 0x08,[0x0d] = 0x03,[0x0e] = 0x06,[0x0f] = 0x06, + [0x10] = 0x03,[0x11] = 0x02,[0x12] = 0x01,[0x14] = 0x03, + [0x15] = 0x02,[0x17] = 0x03,[0x18] = 0x02,[0x19] = 0x02, + [0x1a] = 0x02,[0x1b] = 0x02,[0x1c] = 0x02,[0x1d] = 0x02, + [0x1e] = 0x05,[0x1f] = 0x05, + }; + static const void *jump_table[]= { + [0x04] = emu_ldeb,[0x05] = emu_lxdb,[0x06] = emu_lxeb, + [0x07] = emu_mxdb,[0x08] = emu_keb, [0x09] = emu_ceb, + [0x0a] = emu_aeb, [0x0b] = emu_seb, [0x0c] = emu_mdeb, + [0x0d] = emu_deb, [0x0e] = emu_maeb,[0x0f] = emu_mseb, + [0x10] = emu_tceb,[0x11] = emu_tcdb,[0x12] = emu_tcxb, + [0x14] = emu_sqeb,[0x15] = emu_sqdb,[0x17] = emu_meeb, + [0x18] = emu_kdb, [0x19] = emu_cdb, [0x1a] = emu_adb, + [0x1b] = emu_sdb, [0x1c] = emu_mdb, [0x1d] = emu_ddb, + [0x1e] = emu_madb,[0x1f] = emu_msdb + }; + + switch (format_table[opcode[5]]) { + case 1: /* RXE format, long double constant */ { + __u64 *dxb, temp[2]; + __u32 opc; + + if ((opcode[1] >> 4) & 2) + return SIGILL; + emu_store_regd((opcode[1] >> 4) & 15); + emu_store_regd(((opcode[1] >> 4) & 15) + 2); + opc = *((__u32 *) opcode); + dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mathemu_copy_from_user(&temp, dxb, 16); + /* call the emulation function */ + _fex = ((int (*)(int, long double *)) jump_table[opcode[5]]) + (opcode[1] >> 4, (long double *) &temp); + emu_load_regd((opcode[1] >> 4) & 15); + emu_load_regd(((opcode[1] >> 4) & 15) + 2); + break; + } + case 2: /* RXE format, double constant */ { + __u64 *dxb, temp; + __u32 opc; + + emu_store_regd((opcode[1] >> 4) & 15); + opc = *((__u32 *) opcode); + dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mathemu_copy_from_user(&temp, dxb, 8); + /* call the emulation function */ + _fex = ((int (*)(int, double *)) jump_table[opcode[5]]) + (opcode[1] >> 4, (double *) &temp); + emu_load_regd((opcode[1] >> 4) & 15); + break; + } + case 3: /* RXE format, float constant */ { + __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); + mathemu_get_user(temp, dxb); + /* call the emulation function */ + _fex = ((int (*)(int, float *)) jump_table[opcode[5]]) + (opcode[1] >> 4, (float *) &temp); + emu_load_rege((opcode[1] >> 4) & 15); + break; + } + case 4: /* RXF format, long double constant */ { + __u64 *dxb, temp[2]; + __u32 opc; + + if (((opcode[1] >> 4) & 0x20) || ((opcode[4] >> 4) & 0x20)) + return SIGILL; + emu_store_regd((opcode[1] >> 4) & 15); + emu_store_regd(((opcode[1] >> 4) & 15) + 2); + emu_store_regd((opcode[4] >> 4) & 15); + emu_store_regd(((opcode[4] >> 4) & 15) + 2); + opc = *((__u32 *) opcode); + dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mathemu_copy_from_user(&temp, dxb, 16); + /* call the emulation function */ + _fex = ((int (*)(int,long double *,int)) jump_table[opcode[5]]) + (opcode[1] >> 4, (double *) &temp, opcode[4] >> 4); + emu_load_regd((opcode[1] >> 4) & 15); + emu_load_regd(((opcode[1] >> 4) & 15) + 2); + break; + } + case 5: /* RXF format, double constant */ { + __u64 *dxb, temp; + __u32 opc; + + emu_store_regd((opcode[1] >> 4) & 15); + emu_store_regd((opcode[4] >> 4) & 15); + opc = *((__u32 *) opcode); + dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mathemu_copy_from_user(&temp, dxb, 8); + /* call the emulation function */ + _fex = ((int (*)(int, double *, int)) jump_table[opcode[5]]) + (opcode[1] >> 4, (double *) &temp, opcode[4] >> 4); + emu_load_regd((opcode[1] >> 4) & 15); + break; + } + case 6: /* RXF format, float constant */ { + __u32 *dxb, temp; + __u32 opc; + + emu_store_rege((opcode[1] >> 4) & 15); + emu_store_rege((opcode[4] >> 4) & 15); + opc = *((__u32 *) opcode); + dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mathemu_get_user(temp, dxb); + /* call the emulation function */ + _fex = ((int (*)(int, float *, int)) jump_table[opcode[5]]) + (opcode[1] >> 4, (float *) &temp, opcode[4] >> 4); + emu_load_rege((opcode[4] >> 4) & 15); + break; + } + case 7: /* RXE format, double constant */ + /* store double and load long double */ + { + __u64 *dxb, temp; + __u32 opc; + if ((opcode[1] >> 4) & 0x20) + return SIGILL; + emu_store_regd((opcode[1] >> 4) & 15); + opc = *((__u32 *) opcode); + dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mathemu_copy_from_user(&temp, dxb, 8); + /* call the emulation function */ + _fex = ((int (*)(int, double *)) jump_table[opcode[5]]) + (opcode[1] >> 4, (double *) &temp); + emu_load_regd((opcode[1] >> 4) & 15); + emu_load_regd(((opcode[1] >> 4) & 15) + 2); + break; + } + case 8: /* RXE format, float constant */ + /* store float and load double */ + { + __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); + mathemu_get_user(temp, dxb); + /* call the emulation function */ + _fex = ((int (*)(int, float *)) jump_table[opcode[5]]) + (opcode[1] >> 4, (float *) &temp); + emu_load_regd((opcode[1] >> 4) & 15); + break; + } + case 9: /* RXE format, float constant */ + /* store float and load long double */ + { + __u32 *dxb, temp; + __u32 opc; + if ((opcode[1] >> 4) & 0x20) + return SIGILL; + emu_store_rege((opcode[1] >> 4) & 15); + opc = *((__u32 *) opcode); + dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mathemu_get_user(temp, dxb); + /* call the emulation function */ + _fex = ((int (*)(int, float *)) jump_table[opcode[5]]) + (opcode[1] >> 4, (float *) &temp); + emu_load_regd((opcode[1] >> 4) & 15); + emu_load_regd(((opcode[1] >> 4) & 15) + 2); + break; + } + default: /* invalid operation */ + return SIGILL; + } + if (_fex != 0) { + current->thread.fp_regs.fpc |= _fex; + if (current->thread.fp_regs.fpc & (_fex << 8)) + return SIGFPE; + } + return 0; +} + +/* + * Emulate LDR Rx,Ry with Rx or Ry not in {0, 2, 4, 6} + */ +int math_emu_ldr(__u8 *opcode) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + __u16 opc = *((__u16 *) opcode); + + if ((opc & 0x90) == 0) { /* test if rx in {0,2,4,6} */ + /* we got an exception therfore ry can't be in {0,2,4,6} */ + __asm__ __volatile ( /* load rx from fp_regs.fprs[ry] */ + " bras 1,0f\n" + " ld 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" (opc & 0xf0), + "a" (&fp_regs->fprs[opc & 0xf].d) + : "1" ); + } else if ((opc & 0x9) == 0) { /* test if ry in {0,2,4,6} */ + __asm__ __volatile ( /* store ry to fp_regs.fprs[rx] */ + " bras 1,0f\n" + " std 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" ((opc & 0xf) << 4), + "a" (&fp_regs->fprs[(opc & 0xf0)>>4].d) + : "1" ); + } else /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */ + fp_regs->fprs[(opc & 0xf0) >> 4] = fp_regs->fprs[opc & 0xf]; + return 0; +} + +/* + * Emulate LER Rx,Ry with Rx or Ry not in {0, 2, 4, 6} + */ +int math_emu_ler(__u8 *opcode) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + __u16 opc = *((__u16 *) opcode); + + if ((opc & 0x90) == 0) { /* test if rx in {0,2,4,6} */ + /* we got an exception therfore ry can't be in {0,2,4,6} */ + __asm__ __volatile ( /* load rx from fp_regs.fprs[ry] */ + " bras 1,0f\n" + " le 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" (opc & 0xf0), + "a" (&fp_regs->fprs[opc & 0xf].f) + : "1" ); + } else if ((opc & 0x9) == 0) { /* test if ry in {0,2,4,6} */ + __asm__ __volatile ( /* store ry to fp_regs.fprs[rx] */ + " bras 1,0f\n" + " ste 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" ((opc & 0xf) << 4), + "a" (&fp_regs->fprs[(opc & 0xf0) >> 4].f) + : "1" ); + } else /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */ + fp_regs->fprs[(opc & 0xf0) >> 4] = fp_regs->fprs[opc & 0xf]; + return 0; +} + +/* + * Emulate LD R,D(X,B) with R not in {0, 2, 4, 6} + */ +int math_emu_ld(__u8 *opcode, struct pt_regs * regs) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + __u32 opc = *((__u32 *) opcode); + __u64 *dxb; + + dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mathemu_copy_from_user(&fp_regs->fprs[(opc >> 20) & 0xf].d, dxb, 8); + return 0; +} + +/* + * Emulate LE R,D(X,B) with R not in {0, 2, 4, 6} + */ +int math_emu_le(__u8 *opcode, struct pt_regs * regs) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + __u32 opc = *((__u32 *) opcode); + __u32 *mem, *dxb; + + dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mem = (__u32 *) (&fp_regs->fprs[(opc >> 20) & 0xf].f); + mathemu_get_user(mem[0], dxb); + return 0; +} + +/* + * Emulate STD R,D(X,B) with R not in {0, 2, 4, 6} + */ +int math_emu_std(__u8 *opcode, struct pt_regs * regs) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + __u32 opc = *((__u32 *) opcode); + __u64 *dxb; + + dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mathemu_copy_to_user(dxb, &fp_regs->fprs[(opc >> 20) & 0xf].d, 8); + return 0; +} + +/* + * Emulate STE R,D(X,B) with R not in {0, 2, 4, 6} + */ +int math_emu_ste(__u8 *opcode, struct pt_regs * regs) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + __u32 opc = *((__u32 *) opcode); + __u32 *mem, *dxb; + + dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mem = (__u32 *) (&fp_regs->fprs[(opc >> 20) & 0xf].f); + mathemu_put_user(mem[0], dxb); + return 0; +} + +/* + * Emulate LFPC D(B) + */ +int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) { + __u32 opc = *((__u32 *) opcode); + __u32 *dxb, temp; + + dxb= (__u32 *) calc_addr(regs, 0, opc>>12, opc); + mathemu_get_user(temp, dxb); + if ((temp & ~FPC_VALID_MASK) != 0) + return SIGILL; + current->thread.fp_regs.fpc = temp; + return 0; +} + +/* + * Emulate STFPC D(B) + */ +int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) { + __u32 opc = *((__u32 *) opcode); + __u32 *dxb; + + dxb= (__u32 *) calc_addr(regs, 0, opc>>12, opc); + mathemu_put_user(current->thread.fp_regs.fpc, dxb); + return 0; +} + +/* + * Emulate SRNM D(B) + */ +int math_emu_srnm(__u8 *opcode, struct pt_regs *regs) { + __u32 opc = *((__u32 *) opcode); + __u32 temp; + + temp = calc_addr(regs, 0, opc>>12, opc); + current->thread.fp_regs.fpc &= ~3; + current->thread.fp_regs.fpc |= (temp & 3); + return 0; +} + +/* broken compiler ... */ +long long +__negdi2 (long long u) +{ + + union lll { + long long ll; + long s[2]; + }; + + union lll w,uu; + + uu.ll = u; + + w.s[1] = -uu.s[1]; + w.s[0] = -uu.s[0] - ((int) w.s[1] != 0); + + return w.ll; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/math-emu/qrnnd.S linux.ac/arch/s390/math-emu/qrnnd.S --- linux.vanilla/arch/s390/math-emu/qrnnd.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/s390/math-emu/qrnnd.S Thu Apr 12 11:59:46 2001 @@ -0,0 +1,77 @@ +# S/390 __udiv_qrnnd + +# r2 : &__r +# r3 : upper half of 64 bit word n +# r4 : lower half of 64 bit word n +# r5 : divisor d +# the reminder r of the division is to be stored to &__r and +# the quotient q is to be returned + + .text + .globl __udiv_qrnnd +__udiv_qrnnd: + st %r2,24(%r15) # store pointer to reminder for later + lr %r0,%r3 # reload n + lr %r1,%r4 + ltr %r2,%r5 # reload and test divisor + jp 5f + # divisor >= 0x80000000 + srdl %r0,2 # n/4 + srl %r2,1 # d/2 + slr %r1,%r2 # special case if last bit of d is set + brc 3,0f # (n/4) div (n/2) can overflow by 1 + ahi %r0,-1 # trick: subtract n/2, then divide +0: dr %r0,%r2 # signed division + ahi %r1,1 # trick part 2: add 1 to the quotient + # now (n >> 2) = (d >> 1) * %r1 + %r0 + lhi %r3,1 + nr %r3,%r1 # test last bit of q + jz 1f + alr %r0,%r2 # add (d>>1) to r +1: srl %r1,1 # q >>= 1 + # now (n >> 2) = (d&-2) * %r1 + %r0 + lhi %r3,1 + nr %r3,%r5 # test last bit of d + jz 2f + slr %r0,%r1 # r -= q + brc 3,2f # borrow ? + alr %r0,%r5 # r += d + ahi %r1,-1 +2: # now (n >> 2) = d * %r1 + %r0 + alr %r1,%r1 # q <<= 1 + alr %r0,%r0 # r <<= 1 + brc 12,3f # overflow on r ? + slr %r0,%r5 # r -= d + ahi %r1,1 # q += 1 +3: lhi %r3,2 + nr %r3,%r4 # test next to last bit of n + jz 4f + ahi %r0,1 # r += 1 +4: clr %r0,%r5 # r >= d ? + jl 6f + slr %r0,%r5 # r -= d + ahi %r1,1 # q += 1 + # now (n >> 1) = d * %r1 + %r0 + j 6f +5: # divisor < 0x80000000 + srdl %r0,1 + dr %r0,%r2 # signed division + # now (n >> 1) = d * %r1 + %r0 +6: alr %r1,%r1 # q <<= 1 + alr %r0,%r0 # r <<= 1 + brc 12,7f # overflow on r ? + slr %r0,%r5 # r -= d + ahi %r1,1 # q += 1 +7: lhi %r3,1 + nr %r3,%r4 # isolate last bit of n + alr %r0,%r3 # r += (n & 1) + clr %r0,%r5 # r >= d ? + jl 8f + slr %r0,%r5 # r -= d + ahi %r1,1 # q += 1 +8: # now n = d * %r1 + %r0 + l %r2,24(%r15) + st %r0,0(%r2) + lr %r2,%r1 + br %r14 + .end __udiv_qrnnd diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/math-emu/sfp-util.h linux.ac/arch/s390/math-emu/sfp-util.h --- linux.vanilla/arch/s390/math-emu/sfp-util.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/s390/math-emu/sfp-util.h Thu Apr 12 11:59:46 2001 @@ -0,0 +1,63 @@ +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <asm/byteorder.h> + +#define add_ssaaaa(sh, sl, ah, al, bh, bl) ({ \ + unsigned int __sh = (ah); \ + unsigned int __sl = (al); \ + __asm__ (" alr %1,%3\n" \ + " brc 12,0f\n" \ + " ahi %0,1\n" \ + "0: alr %0,%2" \ + : "+&d" (__sh), "+d" (__sl) \ + : "d" (bh), "d" (bl) : "cc" ); \ + (sh) = __sh; \ + (sl) = __sl; \ +}) + +#define sub_ddmmss(sh, sl, ah, al, bh, bl) ({ \ + unsigned int __sh = (ah); \ + unsigned int __sl = (al); \ + __asm__ (" slr %1,%3\n" \ + " brc 3,0f\n" \ + " ahi %0,-1\n" \ + "0: slr %0,%2" \ + : "+&d" (__sh), "+d" (__sl) \ + : "d" (bh), "d" (bl) : "cc" ); \ + (sh) = __sh; \ + (sl) = __sl; \ +}) + +/* a umul b = a mul b + (a>=2<<31) ? b<<32:0 + (b>=2<<31) ? a<<32:0 */ +#define umul_ppmm(wh, wl, u, v) ({ \ + unsigned int __wh = u; \ + unsigned int __wl = v; \ + __asm__ (" ltr 1,%0\n" \ + " mr 0,%1\n" \ + " jnm 0f\n" \ + " alr 0,%1\n" \ + "0: ltr %1,%1\n" \ + " jnm 1f\n" \ + " alr 0,%0\n" \ + "1: lr %0,0\n" \ + " lr %1,1\n" \ + : "+d" (__wh), "+d" (__wl) \ + : : "0", "1", "cc" ); \ + wh = __wh; \ + wl = __wl; \ +}) + +#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 0 + +#define abort() return 0 + +#define __BYTE_ORDER __BIG_ENDIAN diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/mm/fault.c linux.ac/arch/s390/mm/fault.c --- linux.vanilla/arch/s390/mm/fault.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/s390/mm/fault.c Thu Apr 12 11:59:46 2001 @@ -21,6 +21,7 @@ #include <linux/mm.h> #include <linux/smp.h> #include <linux/smp_lock.h> +#include <linux/compatmac.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -263,3 +264,123 @@ } +typedef struct _pseudo_wait_t { + struct _pseudo_wait_t *next; + wait_queue_head_t queue; + unsigned long address; + int resolved; +} pseudo_wait_t; + +static pseudo_wait_t *pseudo_lock_queue = NULL; +static spinlock_t pseudo_wait_spinlock; /* spinlock to protect lock queue */ + +/* + * This routine handles pseudo page faults. + */ +asmlinkage void +do_pseudo_page_fault(struct pt_regs *regs, unsigned long error_code) +{ + DECLARE_WAITQUEUE(wait, current); + pseudo_wait_t wait_struct; + pseudo_wait_t *ptr, *last, *next; + unsigned long psw_mask; + unsigned long address; + int kernel_address; + + /* + * get psw mask of Program old psw to find out, + * if user or kernel mode + */ + psw_mask = S390_lowcore.program_old_psw.mask; + + /* + * get the failing address + * more specific the segment and page table portion of + * the address + */ + address = S390_lowcore.trans_exc_code & 0xfffff000; + + if (address & 0x80000000) { + /* high bit set -> a page has been swapped in by VM */ + address &= 0x7fffffff; + spin_lock(&pseudo_wait_spinlock); + last = NULL; + ptr = pseudo_lock_queue; + while (ptr != NULL) { + next = ptr->next; + if (address == ptr->address) { + /* + * This is one of the processes waiting + * for the page. Unchain from the queue. + * There can be more than one process + * waiting for the same page. VM presents + * an initial and a completion interrupt for + * every process that tries to access a + * page swapped out by VM. + */ + if (last == NULL) + pseudo_lock_queue = next; + else + last->next = next; + /* now wake up the process */ + ptr->resolved = 1; + wake_up(&ptr->queue); + } else + last = ptr; + ptr = next; + } + spin_unlock(&pseudo_wait_spinlock); + } else { + /* Pseudo page faults in kernel mode is a bad idea */ + if (!(psw_mask & PSW_PROBLEM_STATE)) { + /* + * VM presents pseudo page faults if the interrupted + * state was not disabled for interrupts. So we can + * get pseudo page fault interrupts while running + * in kernel mode. We simply access the page here + * while we are running disabled. VM will then swap + * in the page synchronously. + */ + kernel_address = 0; + switch (S390_lowcore.trans_exc_code & 3) { + case 0: /* Primary Segment Table Descriptor */ + kernel_address = 1; + break; + case 1: /* STD determined via access register */ + if (S390_lowcore.exc_access_id == 0 || + regs->acrs[S390_lowcore.exc_access_id]==0) + kernel_address = 1; + break; + case 2: /* Secondary Segment Table Descriptor */ + case 3: /* Home Segment Table Descriptor */ + break; + } + if (kernel_address) + /* dereference a virtual kernel address */ + __asm__ __volatile__ ( + " ic 0,0(%0)" + : : "a" (address) : "0"); + else + /* dereference a virtual user address */ + __asm__ __volatile__ ( + " la 2,0(%0)\n" + " sacf 512\n" + " ic 2,0(2)\n" + " sacf 0" + : : "a" (address) : "2" ); + + return; + } + /* initialize and add element to pseudo_lock_queue */ + init_waitqueue_head (&wait_struct.queue); + wait_struct.address = address; + wait_struct.resolved = 0; + spin_lock(&pseudo_wait_spinlock); + wait_struct.next = pseudo_lock_queue; + pseudo_lock_queue = &wait_struct; + spin_unlock(&pseudo_wait_spinlock); + /* go to sleep */ + wait_event(wait_struct.queue, wait_struct.resolved); + } +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/mm/init.c linux.ac/arch/s390/mm/init.c --- linux.vanilla/arch/s390/mm/init.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390/mm/init.c Thu Apr 12 12:00:34 2001 @@ -35,27 +35,14 @@ #include <asm/pgalloc.h> #include <asm/dma.h> #include <asm/lowcore.h> +#include <asm/tlb.h> -static unsigned long totalram_pages; +mmu_gather_t mmu_gathers[NR_CPUS]; -/* - * BAD_PAGE is the page that is used for page faults when linux - * is out-of-memory. Older versions of linux just did a - * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving an inode - * unused etc.. - * - * BAD_PAGETABLE is the accompanying page-table: it is initialized - * to point to BAD_PAGE entries. - * - * ZERO_PAGE is a special page that is used for zero-initialized - * data and COW. - */ +static unsigned long totalram_pages; pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE))); -char empty_bad_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); -pte_t empty_bad_pte_table[PTRS_PER_PTE] __attribute__((__aligned__(PAGE_SIZE))); static int test_access(unsigned long loc) { @@ -84,53 +71,6 @@ return rc; } -static pte_t * get_bad_pte_table(void) -{ - pte_t v; - int i; - - v = pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED)); - - for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++) - empty_bad_pte_table[i] = v; - - return empty_bad_pte_table; -} - -static inline void invalidate_page(pte_t *pte) -{ - int i; - for (i=0;i<PTRS_PER_PTE;i++) - pte_clear(pte++); -} - -pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) -{ - unsigned long pte; - - pte = (unsigned long) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - invalidate_page((pte_t*) pte); - pmd_val(pmd[0]) = _PAGE_TABLE + __pa(pte); - pmd_val(pmd[1]) = _PAGE_TABLE + __pa(pte)+1024; - pmd_val(pmd[2]) = _PAGE_TABLE + __pa(pte)+2048; - pmd_val(pmd[3]) = _PAGE_TABLE + __pa(pte)+3072; - return (pte_t *) pte + offset; - } - pte = (unsigned long) get_bad_pte_table(); - pmd_val(pmd[0]) = _PAGE_TABLE + __pa(pte); - pmd_val(pmd[1]) = _PAGE_TABLE + __pa(pte)+1024; - pmd_val(pmd[2]) = _PAGE_TABLE + __pa(pte)+2048; - pmd_val(pmd[3]) = _PAGE_TABLE + __pa(pte)+3072; - return NULL; - } - free_page(pte); - if (pmd_bad(*pmd)) - BUG(); - return (pte_t *) pmd_page(*pmd) + offset; -} - int do_check_pgt_cache(int low, int high) { int freed = 0; @@ -139,9 +79,9 @@ if(pgd_quicklist) free_pgd_slow(get_pgd_fast()), freed += 2; if(pmd_quicklist) - free_pmd_slow(get_pmd_fast()), freed++; + pmd_free_slow(pmd_alloc_one_fast(NULL, 0)), freed++; if(pte_quicklist) - free_pte_slow(get_pte_fast()), freed++; + pte_free_slow(pte_alloc_one_fast(NULL, 0)), freed++; } while(pgtable_cache_size > low); } return freed; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/mm/ioremap.c linux.ac/arch/s390/mm/ioremap.c --- linux.vanilla/arch/s390/mm/ioremap.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390/mm/ioremap.c Thu Apr 12 12:00:34 2001 @@ -54,7 +54,7 @@ if (address >= end) BUG(); do { - pte_t * pte = pte_alloc_kernel(pmd, address); + pte_t * pte = pte_alloc(&init_mm, pmd, address); if (!pte) return -ENOMEM; remap_area_pte(pte, address, end - address, address + phys_addr, flags); @@ -67,6 +67,7 @@ static int remap_area_pages(unsigned long address, unsigned long phys_addr, unsigned long size, unsigned long flags) { + int error; pgd_t * dir; unsigned long end = address + size; @@ -75,17 +76,21 @@ flush_cache_all(); if (address >= end) BUG(); + spin_lock(&init_mm.page_table_lock); do { - pmd_t *pmd = pmd_alloc_kernel(dir, address); + pmd_t *pmd; + pmd = pmd_alloc(&init_mm, dir, address); + error = -ENOMEM; if (!pmd) - return -ENOMEM; + break; if (remap_area_pmd(pmd, address, end - address, phys_addr + address, flags)) - return -ENOMEM; - set_pgdir(address, *dir); + break; + error = 0; address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; } while (address && (address < end)); + spin_unlock(&init_mm.page_table_lock); flush_tlb_all(); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/tools/dasdfmt/dasdfmt.c linux.ac/arch/s390/tools/dasdfmt/dasdfmt.c --- linux.vanilla/arch/s390/tools/dasdfmt/dasdfmt.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/s390/tools/dasdfmt/dasdfmt.c Thu Apr 12 12:00:34 2001 @@ -7,6 +7,7 @@ * Author(s): Utz Bacher, <utz.bacher@de.ibm.com> * * Device-in-use-checks by Fritz Elfert, <felfert@to.com> + * Compatible Disk Layout enhancements by Carsten Otte, <cotte@de.ibm.com> * * Still to do: * detect non-switch parameters ("dasdfmt -n 170 XY") and complain about them @@ -157,14 +158,15 @@ exit_usage(int exitcode) { #ifdef RANGE_FORMATTING - printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] [<range>] " \ + printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] [<range>] " \ "<diskspec>\n\n",prog_name); #else /* RANGE_FORMATTING */ - printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] " \ + printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] " \ "<diskspec>\n\n",prog_name); #endif /* RANGE_FORMATTING */ printf(" -t means testmode\n"); printf(" -v means verbose mode\n"); + printf(" -C means format compatible disk layout\n"); printf(" -V means print version\n"); printf(" -L means don't write disk label\n"); printf(" <label> is a label which is converted to EBCDIC and " \ @@ -200,7 +202,7 @@ /* fgets(line,sizeof(line),file); omit first line */ while (fgets(line,sizeof(line),file)!=NULL) { - rc=sscanf(line,"%X %*[(A-Z)] at (%d:%d)",&d,&ma_i,&mi_i); + rc=sscanf(line,"%X %*[(A-Z) ] at (%d:%d)",&d,&ma_i,&mi_i); ma=ma_i; mi=mi_i; if ( (rc==3) && @@ -218,7 +220,8 @@ fclose(file); ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to find device in the /proc " \ - "filesystem (are you sure to have the right param line?)\n", + "filesystem (are you sure to have the right parameter " \ + "dasd=xxx?)\n", prog_name); } @@ -488,14 +491,14 @@ } check_mounted(major_no, minor_no); + get_xno_from_xno(&devno,&major_no,&minor_no, + GIVEN_MAJOR|GIVEN_MINOR); if ((!writenolabel) && (!labelspec)) { sprintf(label,"LNX1 x%04x",devno); } if ( ((withoutprompt)&&(verbosity>=1)) || (!withoutprompt) ) { - get_xno_from_xno(&devno,&major_no,&minor_no, - GIVEN_MAJOR|GIVEN_MINOR); printf("\nI am going to format the device %s in the " \ "following way:\n",dev_name); printf(" Device number of device : 0x%x\n",devno); @@ -505,6 +508,9 @@ "no":"yes"); if (!writenolabel) printf(" Disk label : %s\n",label); + if (format_params.intensity != DASD_FORMAT_DEFAULT_INTENSITY) + printf(" Compatible Disk Layout : %s\n",(format_params.intensity&0x08)? + "yes":"no"); #ifdef RANGE_FORMATTING printf(" Start track : %d\n" \ ,format_params.start_unit); @@ -558,7 +564,7 @@ } - rc=ioctl(fd,BLKGETSIZE,&new_blksize); + rc=ioctl(fd,BLKSSZGET,&new_blksize); if (rc) { ERRMSG("%s: the ioctl call to get blocksize " \ "returned with the following error " \ @@ -664,9 +670,9 @@ opterr=0; #ifdef RANGE_FORMATTING - while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:hLty?vV")) !=EOF) { + while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:ChLty?vV")) !=EOF) { #endif /* RANGE_FORMATTING */ - while ( (oc=getopt(argc,argv,"b:n:l:f:hLty?vV")) !=EOF) { + while ( (oc=getopt(argc,argv,"b:n:l:f:ChLty?vV")) !=EOF) { switch (oc) { case 'y': withoutprompt=1; @@ -686,6 +692,9 @@ case 'h': exit_usage(0); + case 'C': + format_params.intensity&=0x08; + break; case 'V': printf("%s version 0.99\n",prog_name); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/tools/silo/silo.c linux.ac/arch/s390/tools/silo/silo.c --- linux.vanilla/arch/s390/tools/silo/silo.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390/tools/silo/silo.c Thu Apr 12 12:00:34 2001 @@ -9,6 +9,9 @@ * Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com> * Fritz Elfert <felfert@to.com> contributed support for * /etc/silo.conf based on Intel's lilo + * Changes : + * 01/15/01 Holger Smolinski <Holger.Smolinski@de.ibm.com> + * adapted to deal with devices and bootsects of various sizes */ #include <stddef.h> @@ -376,7 +379,7 @@ if ( errno == ENOENT ) { ITRY (creat ( o-> bootmap, O_RDWR )); } else { - PRINT_LEVEL(1,"Cannot acces bootmap file '%s': %s\n",o->bootmap, + PRINT_LEVEL(1,"Cannot access bootmap file '%s': %s\n",o->bootmap, strerror(errno)); } } @@ -482,6 +485,7 @@ int bs, boots; char *tmpdev; char buffer[4096]={0,}; + int blocksize, sectsize; ITRY (d_fd = open (o->ipldevice, O_RDWR | O_SYNC)); ITRY (fstat (d_fd, &d_st)); ITRY (s_fd = open (o->bootmap, O_RDWR | O_TRUNC | O_CREAT | O_SYNC)); @@ -508,6 +512,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(bd_fd,BLKSSZGET,&blocksize)); ITRY (ioctl(s_fd,FIBMAP,&boots)); ITRY (ioctl (bd_fd, BIODASDRWTB, &boots)); PRINT_LEVEL (1, "Bootmap is in block no: 0x%08x\n", boots); @@ -515,13 +520,21 @@ close(s_fd); ITRY (unlink(tmpdev)); /* Now patch the bootsector */ + ITRY (stat (o->bootsect, &b_st)); + if ((sectsize = b_st.st_size) > blocksize ) + { + ERROR_LEVEL (0,"Bootsector is larger than sectorsize of volume %d vs %d\n", sectsize, blocksize); + rc = -1; + errno = EINVAL; + } ITRY (b_fd = open (o->bootsect, O_RDONLY)); - NTRY (read (b_fd, buffer, 4096)); + ITRY (read (b_fd, buffer, sectsize)); memset (buffer + 0xe0, 0, 8); *(int *) (buffer + 0xe0) = boots; if ( o -> testlevel <= 0 ) { - NTRY (write (d_fd, buffer, 4096)); - NTRY (write (d_fd, buffer, 4096)); + ITRY (write (d_fd, buffer, sectsize)); + ITRY (lseek (d_fd, blocksize, SEEK_SET)); + ITRY (write (d_fd, buffer, sectsize)); } close (b_fd); close (d_fd); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/boot/Makefile linux.ac/arch/s390x/boot/Makefile --- linux.vanilla/arch/s390x/boot/Makefile Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/boot/Makefile Thu Apr 12 12:00:34 2001 @@ -25,7 +25,7 @@ image: $(CONFIGURE) $(TOPDIR)/vmlinux \ iplfba.boot ipleckd.boot ipldump.boot $(OBJCOPY) -O binary $(TOPDIR)/vmlinux image - $(NM) $(TOPDIR)/vmlinux | grep -v '\(compiled\)\|\( [aU] \)\|\(\.\)\|\(LASH[RL]DI\)' | sort > $(TOPDIR)/System.map + $(NM) $(TOPDIR)/vmlinux | grep -v '\(compiled\)\|\( [aUw] \)\|\(\.\)\|\(LASH[RL]DI\)' | sort > $(TOPDIR)/System.map listing: ../../../vmlinux $(OBJDUMP) --disassemble --disassemble-all --disassemble-zeroes --reloc $(TOPDIR)/vmlinux > listing diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/config.in linux.ac/arch/s390x/config.in --- linux.vanilla/arch/s390x/config.in Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/config.in Thu Apr 12 12:00:34 2001 @@ -47,12 +47,13 @@ bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL -define CONFIG_KCORE ELF +define_bool CONFIG_KCORE_ELF y tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG endmenu + source drivers/s390/Config.in if [ "$CONFIG_NET" = "y" ]; then @@ -68,6 +69,6 @@ if [ "$CONFIG_CTC" = "y" ]; then bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG fi -# this does not work. bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/defconfig linux.ac/arch/s390x/defconfig --- linux.vanilla/arch/s390x/defconfig Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/defconfig Thu Apr 12 12:00:34 2001 @@ -1,5 +1,5 @@ # -# Automatically generated by make menuconfig: don't edit +# Automatically generated make config: don't edit # # CONFIG_ISA is not set # CONFIG_EISA is not set @@ -37,6 +37,7 @@ CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y +CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set # CONFIG_PROCESS_DEBUG is not set @@ -50,9 +51,14 @@ CONFIG_BLK_DEV_RAM_SIZE=24576 CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_XPRAM=m + +# +# S/390 block device drivers +# CONFIG_DASD=y CONFIG_DASD_ECKD=y CONFIG_DASD_FBA=y +# CONFIG_DASD_DIAG is not set # # Multi-device support (RAID and LVM) @@ -64,20 +70,31 @@ CONFIG_MD_RAID1=m CONFIG_MD_RAID5=m CONFIG_BLK_DEV_LVM=m -CONFIG_LVM_PROC_FS=y # # Character device drivers # CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 + +# +# S/390 character device drivers +# CONFIG_3215=y CONFIG_3215_CONSOLE=y CONFIG_HWC=y CONFIG_HWC_CONSOLE=y CONFIG_S390_TAPE=m + +# +# S/390 tape interface support +# CONFIG_S390_TAPE_CHAR=y CONFIG_S390_TAPE_BLOCK=y + +# +# S/390 tape hardware support +# CONFIG_S390_TAPE_3490=y CONFIG_S390_TAPE_3480=y @@ -89,6 +106,10 @@ CONFIG_NET_ETHERNET=y CONFIG_TR=y # CONFIG_FDDI is not set + +# +# S/390 network device drivers +# # CONFIG_CHANDEV is not set CONFIG_CTC=m CONFIG_IUCV=m @@ -110,11 +131,16 @@ # CONFIG_IP_PNP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set + +# +# +# # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set @@ -139,6 +165,8 @@ # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -193,8 +221,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -212,8 +238,10 @@ # CONFIG_SGI_PARTITION is not set # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # # Kernel hacking # +# CONFIG_MAGIC_SYSRQ is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/Makefile linux.ac/arch/s390x/kernel/Makefile --- linux.vanilla/arch/s390x/kernel/Makefile Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/kernel/Makefile Thu Apr 12 12:00:34 2001 @@ -14,7 +14,7 @@ O_TARGET := kernel.o -export-objs := s390_ksyms.o +export-objs := debug.o ebcdic.o irq.o s390_ext.o smp.o s390_ksyms.o obj-y := lowcore.o entry.o bitmap.o traps.o time.o process.o irq.o \ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ semaphore.o s390fpu.o reipl.o s390_ext.o debug.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/binfmt_elf32.c linux.ac/arch/s390x/kernel/binfmt_elf32.c --- linux.vanilla/arch/s390x/kernel/binfmt_elf32.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/s390x/kernel/binfmt_elf32.c Thu Apr 12 12:00:34 2001 @@ -23,7 +23,8 @@ * This is used to ensure we don't load something for the wrong architecture. */ #define elf_check_arch(x) \ - ((x)->e_machine == ELF_ARCH && (x)->e_ident[EI_CLASS] == ELF_CLASS) + (((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \ + && (x)->e_ident[EI_CLASS] == ELF_CLASS) /* ELF register definitions */ #define NUM_GPRS 16 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/cpcmd.c linux.ac/arch/s390x/kernel/cpcmd.c --- linux.vanilla/arch/s390x/kernel/cpcmd.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/kernel/cpcmd.c Thu Apr 12 12:00:34 2001 @@ -10,6 +10,7 @@ #include <linux/kernel.h> #include <linux/string.h> #include <asm/ebcdic.h> +#include <asm/cpcmd.h> void cpcmd(char *cmd, char *response, int rlen) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/cpcmd.h linux.ac/arch/s390x/kernel/cpcmd.h --- linux.vanilla/arch/s390x/kernel/cpcmd.h Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/kernel/cpcmd.h Thu Jan 1 01:00:00 1970 @@ -1,14 +0,0 @@ -/* - * arch/s390/kernel/cpcmd.h - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), - */ - -#ifndef __CPCMD__ -#define __CPCMD__ - -extern void cpcmd(char *cmd, char *response, int rlen); - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/cpprintk.c linux.ac/arch/s390x/kernel/cpprintk.c --- linux.vanilla/arch/s390x/kernel/cpprintk.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/kernel/cpprintk.c Thu Jan 1 01:00:00 1970 @@ -1,25 +0,0 @@ -#include "cpcmd.h" -#include <linux/mm.h> -#include <linux/tty_driver.h> -#include <linux/smp_lock.h> -#include <linux/console.h> -#include <linux/init.h> - -#include <asm/uaccess.h> - -static char buf[1024]; - -asmlinkage int s390printk(const char *fmt, ...) -{ - va_list args; - int i; - unsigned long flags; - spin_lock_irqsave(&console_lock, flags); - va_start(args, fmt); - i = vsprintf(&buf[0],"MSG * ",args); - i = vsprintf(&buf[i], fmt, args); - va_end(args); - cpcmd(buf,0,0); - spin_unlock_irqrestore(&console_lock, flags); - return i; -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/debug.c linux.ac/arch/s390x/kernel/debug.c --- linux.vanilla/arch/s390x/kernel/debug.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/kernel/debug.c Thu Apr 12 12:00:34 2001 @@ -15,45 +15,53 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/malloc.h> -#include <linux/vmalloc.h> #include <linux/ctype.h> #include <linux/version.h> #include <asm/uaccess.h> #include <asm/semaphore.h> -#ifdef MODULE #include <linux/module.h> -#endif #include <asm/debug.h> #define MIN(a,b) (((a)<(b))?(a):(b)) - -#if defined(CONFIG_ARCH_S390X) -#define DEBUG_PROC_HEADER_SIZE 46 -#else -#define DEBUG_PROC_HEADER_SIZE 38 -#endif - -#define ADD_BUFFER 1000 +#define DEBUG_PROLOG_ENTRY -1 /* 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 */ + loff_t offset; /* offset of last read in file */ + int act_area; /* number of last formated area */ + int act_entry; /* last formated entry (offset */ + /* relative to beginning of last */ + /* formated area) */ + size_t act_entry_offset; /* up to this offset we copied */ + /* in last read the last formated */ + /* entry to userland */ + char temp_buf[2048]; /* buffer for output */ + debug_info_t *debug_info_org; /* original debug information */ + debug_info_t *debug_info_snap; /* snapshot of debug information */ struct debug_view *view; /* used view of debug info */ } file_private_info_t; +typedef struct +{ + char *string; + /* + * This assumes that all args are converted into longs + * on L/390 this is the case for all types of parameter + * except of floats, and long long (32 bit) + * + */ + long args[0]; +} debug_sprintf_entry; + + 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, @@ -83,6 +91,9 @@ static int debug_raw_header_fn(debug_info_t * id, struct debug_view *view, int area, debug_entry_t * entry, char *out_buf); +static int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, debug_sprintf_entry *curr_event); + /* globals */ struct debug_view debug_raw_view = { @@ -90,6 +101,7 @@ NULL, &debug_raw_header_fn, &debug_raw_format_fn, + NULL, NULL }; @@ -98,6 +110,7 @@ NULL, &debug_dflt_header_fn, &debug_hex_ascii_format_fn, + NULL, NULL }; @@ -106,9 +119,22 @@ &debug_prolog_level_fn, NULL, NULL, - &debug_input_level_fn + &debug_input_level_fn, + NULL +}; + +struct debug_view debug_sprintf_view = { + "sprintf", + NULL, + &debug_dflt_header_fn, + (debug_format_proc_t*)&debug_sprintf_format_fn, + NULL, + NULL }; + +unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION; + /* static globals */ static debug_info_t *debug_area_first = NULL; @@ -137,64 +163,108 @@ static struct proc_dir_entry *debug_proc_root_entry; - /* functions */ /* - * debug_info_create - * - create new debug-info + * debug_info_alloc + * - alloc new debug-info */ -static debug_info_t* debug_info_create(char *name, int page_order, +static debug_info_t* debug_info_alloc(char *name, int page_order, int nr_areas, int buf_size) { debug_info_t* rc; int i; - /* alloc everything */ + /* alloc everything */ - rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC); - if(!rc) + rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC); + if(!rc) goto fail_malloc_rc; rc->active_entry = (int*)kmalloc(nr_areas * sizeof(int), GFP_ATOMIC); if(!rc->active_entry) goto fail_malloc_active_entry; memset(rc->active_entry, 0, nr_areas * sizeof(int)); - rc->areas = (debug_entry_t **) kmalloc(nr_areas * - sizeof(debug_entry_t *), - GFP_ATOMIC); - if (!rc->areas) - goto fail_malloc_areas; - 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); - } - goto fail_malloc_areas2; - } else { - memset(rc->areas[i], 0, PAGE_SIZE << page_order); - } - } + rc->areas = (debug_entry_t **) kmalloc(nr_areas * + sizeof(debug_entry_t *), + GFP_ATOMIC); + if (!rc->areas) + goto fail_malloc_areas; + 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); + } + goto fail_malloc_areas2; + } else { + memset(rc->areas[i], 0, PAGE_SIZE << page_order); + } + } + + /* initialize members */ - /* initialize members */ + spin_lock_init(&rc->lock); + 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; + 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->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *)); + memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS * + sizeof(struct proc_dir_entry*)); + atomic_set(&(rc->ref_count), 0); + + return rc; + +fail_malloc_areas2: + kfree(rc->areas); +fail_malloc_areas: + kfree(rc->active_entry); +fail_malloc_active_entry: + kfree(rc); +fail_malloc_rc: + return NULL; +} + +/* + * debug_info_free + * - free memory debug-info + */ + +static void debug_info_free(debug_info_t* db_info){ + int i; + 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); + kfree(db_info->active_entry); + kfree(db_info); +} + +/* + * debug_info_create + * - create new debug-info + */ + +static debug_info_t* debug_info_create(char *name, int page_order, + int nr_areas, int buf_size) +{ + debug_info_t* rc; + + rc = debug_info_alloc(name, page_order, nr_areas, buf_size); + if(!rc) + goto out; + + + /* create proc rood directory */ - spin_lock_init(&rc->lock); - 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; - 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->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *)); - memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS * - sizeof(struct proc_dir_entry*)); - 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 | @@ -216,16 +286,29 @@ rc->next = NULL; debug_info_get(rc); +out: return rc; +} -fail_malloc_areas2: - kfree(rc->areas); -fail_malloc_areas: - kfree(rc->active_entry); -fail_malloc_active_entry: - kfree(rc); -fail_malloc_rc: - return NULL; +/* + * debug_info_copy + * - copy debug-info + */ + +static debug_info_t* debug_info_copy(debug_info_t* in) +{ + int i; + debug_info_t* rc; + rc = debug_info_alloc(in->name, in->page_order, + in->nr_areas, in->buf_size); + if(!rc) + goto out; + + for(i = 0; i < in->nr_areas; i++){ + memcpy(rc->areas[i],in->areas[i], PAGE_SIZE << in->page_order); + } +out: + return rc; } /* @@ -261,49 +344,120 @@ } 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); - kfree(db_info->active_entry); if(db_info == debug_area_first) debug_area_first = db_info->next; if(db_info == debug_area_last) debug_area_last = db_info->prev; if(db_info->prev) db_info->prev->next = db_info->next; if(db_info->next) db_info->next->prev = db_info->prev; - kfree(db_info); + debug_info_free(db_info); } } +/* + * debug_format_entry: + * - format one debug entry and return size of formated data + */ + +static int debug_format_entry(file_private_info_t *p_info) +{ + debug_info_t *id_org = p_info->debug_info_org; + debug_info_t *id_snap = p_info->debug_info_snap; + struct debug_view *view = p_info->view; + debug_entry_t *act_entry; + size_t len = 0; + if(p_info->act_entry == DEBUG_PROLOG_ENTRY){ + /* print prolog */ + if (view->prolog_proc) + len += view->prolog_proc(id_org, view,p_info->temp_buf); + goto out; + } + + act_entry = (debug_entry_t *) ((char*)id_snap->areas[p_info->act_area] + + p_info->act_entry); + + if (act_entry->id.stck == 0LL) + goto out; /* empty entry */ + if (view->header_proc) + len += view->header_proc(id_org, view, p_info->act_area, + act_entry, p_info->temp_buf + len); + if (view->format_proc) + len += view->format_proc(id_org, view, p_info->temp_buf + len, + DEBUG_DATA(act_entry)); + out: + return len; +} + +/* + * debug_next_entry: + * - goto next entry in p_info + */ + +extern inline int debug_next_entry(file_private_info_t *p_info) +{ + debug_info_t *id = p_info->debug_info_snap; + if(p_info->act_entry == DEBUG_PROLOG_ENTRY){ + p_info->act_entry = 0; + goto out; + } + if ((p_info->act_entry += id->entry_size) + > ((PAGE_SIZE << (id->page_order)) + - id->entry_size)){ + + /* next area */ + p_info->act_entry = 0; + p_info->act_area++; + if(p_info->act_area >= id->nr_areas) + return 1; + } +out: + return 0; +} /* * debug_output: * - called for user read() - * - copies formated output form private_data of the file - * handle to the user buffer + * - copies formated debug entries 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 */ + size_t len, /* length of buffer */ loff_t *offset /* offset in the file */ ) { - loff_t len; + size_t count = 0; + size_t entry_offset, size = 0; 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" */ + if (*offset != p_info->offset) + return -EPIPE; + if(p_info->act_area >= p_info->debug_info_snap->nr_areas) + return 0; + + entry_offset = p_info->act_entry_offset; + + while(count < len){ + size = debug_format_entry(p_info); + size = MIN((len - count), (size - entry_offset)); + + if(size){ + if ((rc = copy_to_user(user_buf + count, + p_info->temp_buf + entry_offset, size))) + return rc; + } + count += size; + entry_offset = 0; + if(count != len) + if(debug_next_entry(p_info)) + goto out; } +out: + p_info->offset = *offset + count; + p_info->act_entry_offset = size; + *offset = p_info->offset; + return count; } /* @@ -322,68 +476,16 @@ 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, + rc = p_info->view->input_proc(p_info->debug_info_org, p_info->view, file, user_buf, length, offset); + else + rc = -EPERM; 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, - DEBUG_DATA(act_entry)); - 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 @@ -392,17 +494,14 @@ static int debug_open(struct inode *inode, struct file *file) { - int i = 0, size = 0, rc = 0, f_entry_size = 0; + int i = 0, rc = 0; file_private_info_t *p_info; - debug_info_t* debug_info; + debug_info_t *debug_info, *debug_info_snapshot; #ifdef DEBUG printk("debug_open\n"); #endif - -#ifdef MODULE MOD_INC_USE_COUNT; -#endif down(&debug_lock); /* find debug log and view */ @@ -422,87 +521,41 @@ /* 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"); + + /* make snapshot of current debug areas to get it consistent */ + + debug_info_snapshot = debug_info_copy(debug_info); + + if(!debug_info_snapshot){ + printk(KERN_ERR "debug_open: debug_info_copy failed (out of mem)\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_info->views[i]->prolog_proc) - size += - debug_info->views[i]->prolog_proc(debug_info, - debug_info-> - views[i], NULL); - - if (debug_info->views[i]->header_proc) - f_entry_size = - debug_info->views[i]->header_proc(debug_info, - debug_info-> - views[i], 0, NULL, - NULL); - if (debug_info->views[i]->format_proc) - f_entry_size += - debug_info->views[i]->format_proc(debug_info, - debug_info-> - views[i], NULL, - NULL); - - size += f_entry_size - * (PAGE_SIZE / debug_info->entry_size - << debug_info->page_order) - * debug_info->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); + if ((file->private_data = + kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) { + printk(KERN_ERR "debug_open: kmalloc failed\n"); + debug_info_free(debug_info_snapshot); rc = -ENOMEM; goto out; } - - p_info->size = size; - p_info->debug_info = debug_info; + p_info = (file_private_info_t *) file->private_data; + p_info->offset = 0; + p_info->debug_info_snap = debug_info_snapshot; + p_info->debug_info_org = debug_info; p_info->view = debug_info->views[i]; + p_info->act_area = 0; + p_info->act_entry = DEBUG_PROLOG_ENTRY; + p_info->act_entry_offset = 0; - spin_lock_irq(&debug_info->lock); - - p_info->len = - debug_format_output(debug_info, p_info->data, size, - debug_info->views[i]); -#ifdef DEBUG - { - int ilen = p_info->len; - printk("debug_open: len: %i\n", ilen); - } -#endif - - spin_unlock_irq(&debug_info->lock); debug_info_get(debug_info); out: up(&debug_lock); -#ifdef MODULE if (rc != 0) MOD_DEC_USE_COUNT; -#endif return rc; } @@ -518,18 +571,11 @@ #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 + debug_info_free(p_info->debug_info_snap); + debug_info_put(p_info->debug_info_org); + kfree(file->private_data); MOD_DEC_USE_COUNT; -#endif return 0; /* success */ } @@ -607,9 +653,7 @@ { debug_info_t *rc = NULL; -#ifdef MODULE MOD_INC_USE_COUNT; -#endif if (!initialized) debug_init(); down(&debug_lock); @@ -626,9 +670,7 @@ out: if (rc == NULL){ printk(KERN_ERR "debug: debug_register failed for %s\n",name); -#ifdef MODULE MOD_DEC_USE_COUNT; -#endif } up(&debug_lock); return rc; @@ -648,9 +690,7 @@ debug_info_put(id); up(&debug_lock); -#ifdef MODULE MOD_DEC_USE_COUNT; -#endif out: return; } @@ -662,7 +702,7 @@ void debug_set_level(debug_info_t* id, int new_level) { - long flags; + unsigned long flags; if(!id) return; spin_lock_irqsave(&id->lock,flags); @@ -687,7 +727,7 @@ * - set active entry to next in the ring buffer */ -static inline void proceed_active_entry(debug_info_t * id) +extern 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)) @@ -699,7 +739,7 @@ * - set active area to next in the ring buffer */ -static inline void proceed_active_area(debug_info_t * id) +extern inline void proceed_active_area(debug_info_t * id) { id->active_area++; id->active_area = id->active_area % id->nr_areas; @@ -709,7 +749,7 @@ * get_active_entry: */ -static inline debug_entry_t *get_active_entry(debug_info_t * id) +extern 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]); @@ -720,160 +760,126 @@ * - set timestamp, caller address, cpu number etc. */ -static inline debug_entry_t *debug_common(debug_info_t * id) +extern inline debug_entry_t *debug_common(debug_info_t * id, int level, + const void *buf, int len, int exception) { + unsigned long flags; debug_entry_t *active; + spin_lock_irqsave(&id->lock, flags); 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; + active->id.fields.exception = exception; + active->id.fields.level = level; memset(DEBUG_DATA(active), 0, id->buf_size); memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size)); proceed_active_entry(id); + if(exception) + proceed_active_area(id); spin_unlock_irqrestore(&id->lock, flags); - out: + return active; } /* - * debug_int_event: + * debug_event_common: + * - write debug entry with given size */ -debug_entry_t *debug_int_event(debug_info_t * id, int level, - unsigned int tag) +debug_entry_t *debug_event_common(debug_info_t * id, int level, const 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(DEBUG_DATA(active), 0, id->buf_size); - memcpy(DEBUG_DATA(active), &tag, MIN(sizeof(unsigned int), id->buf_size)); - proceed_active_entry(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; + return debug_common(id, level, buf, len, 0); } /* - * debug_text_event: + * debug_exception_common: + * - write debug entry with given size and switch to next debug area */ -debug_entry_t *debug_text_event(debug_info_t * id, int level, - const char *txt) +debug_entry_t *debug_exception_common(debug_info_t * id, int level, + const 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); - memset(DEBUG_DATA(active), 0, id->buf_size); - strncpy(DEBUG_DATA(active), txt, MIN(strlen(txt), id->buf_size)); - active->id.fields.exception = 0; - proceed_active_entry(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; - + return debug_common(id, level, buf, len, 1); } /* - * debug_exception: + * counts arguments in format string for sprintf view */ -debug_entry_t *debug_exception(debug_info_t * id, int level, void *buf, - int len) +extern inline int debug_count_numargs(char *string) { - long flags; - debug_entry_t *active = NULL; + int numargs=0; - if ((!id) || (level > id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - active->id.fields.exception = 1; - memset(DEBUG_DATA(active), 0, id->buf_size); - memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size)); - proceed_active_entry(id); - proceed_active_area(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; + while(*string) { + if(*string++=='%') + numargs++; + } + return(numargs); } /* - * debug_int_exception: + * debug_sprintf_event: */ -debug_entry_t *debug_int_exception(debug_info_t * id, int level, - unsigned int tag) +debug_entry_t *debug_sprintf_event(debug_info_t* id, + int level,char *string,...) { - long flags; - debug_entry_t *active = NULL; + va_list ap; + int numargs,alloc_size,idx; + debug_sprintf_entry *curr_event; + debug_entry_t *retval = NULL; - if ((!id) || (level > id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - active->id.fields.exception = 1; - memset(DEBUG_DATA(active), 0, id->buf_size); - memcpy(DEBUG_DATA(active), &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; + if((!id) || (level > id->level)) + return NULL; + else { + numargs=debug_count_numargs(string); + alloc_size=offsetof(debug_sprintf_entry,args[numargs]); + curr_event=alloca(alloc_size); + + if(curr_event){ + va_start(ap,string); + curr_event->string=string; + for(idx=0;idx<numargs;idx++) + curr_event->args[idx]=va_arg(ap,long); + retval=debug_common(id,level, curr_event,alloc_size,0); + va_end(ap); + } + return retval; + } } /* - * debug_text_exception: + * debug_sprintf_exception: */ -debug_entry_t *debug_text_exception(debug_info_t * id, int level, - const char *txt) +debug_entry_t *debug_sprintf_exception(debug_info_t* id, + int level,char *string,...) { - 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(DEBUG_DATA(active), 0, id->buf_size); - strncpy(DEBUG_DATA(active), txt, 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; + va_list ap; + int numargs,alloc_size,idx; + debug_sprintf_entry *curr_event; + debug_entry_t *retval = NULL; + if((!id) || (level > id->level)) + return NULL; + else { + numargs=debug_count_numargs(string); + alloc_size=offsetof(debug_sprintf_entry,args[numargs]); + curr_event=alloca(alloc_size); + + if(curr_event){ + va_start(ap,string); + curr_event->string=string; + for(idx=0;idx<numargs;idx++) + curr_event->args[idx]=va_arg(ap,long); + retval=debug_common(id,level, curr_event,alloc_size,1); + va_end(ap); + } + return retval; + } } /* @@ -908,7 +914,7 @@ { int rc = 0; int i; - long flags; + unsigned long flags; mode_t mode = S_IFREG; if (!id) @@ -951,7 +957,7 @@ { int rc = 0; int i; - long flags; + unsigned long flags; if (!id) goto out; @@ -987,13 +993,8 @@ { int rc = 0; - if (out_buf == NULL) { - rc = 2; - goto out; - } if(id->level == -1) rc = sprintf(out_buf,"-\n"); else rc = sprintf(out_buf, "%i\n", id->level); - out: return rc; } @@ -1010,8 +1011,10 @@ if (*offset != 0) goto out; - if ((rc = copy_from_user(input_buf, user_buf, 1))) + if (copy_from_user(input_buf, user_buf, 1)){ + rc = -EFAULT; goto out; + } if (isdigit(input_buf[0])) { int new_level = ((int) input_buf[0] - (int) '0'); debug_set_level(id, new_level); @@ -1036,10 +1039,7 @@ int rc; rc = sizeof(debug_entry_t); - if (out_buf == NULL) - goto out; memcpy(out_buf,entry,sizeof(debug_entry_t)); - out: return rc; } @@ -1053,10 +1053,7 @@ int rc; rc = id->buf_size; - if (out_buf == NULL || in_buf == NULL) - goto out; memcpy(out_buf, in_buf, id->buf_size); - out: return rc; } @@ -1069,10 +1066,6 @@ { int i, rc = 0; - if (out_buf == NULL || in_buf == NULL) { - rc = id->buf_size * 4 + 3; - goto out; - } for (i = 0; i < id->buf_size; i++) { rc += sprintf(out_buf + rc, "%02x ", ((unsigned char *) in_buf)[i]); @@ -1086,7 +1079,6 @@ rc += sprintf(out_buf + rc, "%c", c); } rc += sprintf(out_buf + rc, "\n"); - out: return rc; } @@ -1102,12 +1094,9 @@ char *except_str; unsigned long caller; int rc = 0; + unsigned int level; - if (out_buf == NULL) { - rc = DEBUG_PROC_HEADER_SIZE; - goto out; - } - + level = entry->id.fields.level; time = entry->id.stck; /* adjust todclock to 1970 */ time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096); @@ -1119,18 +1108,60 @@ except_str = "-"; caller = (unsigned long) entry->caller; #if defined(CONFIG_ARCH_S390X) - rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %016lx ", - area, time_val.tv_sec, - time_val.tv_usec, except_str, - entry->id.fields.cpuid, caller); + rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %016lx ", + area, time_val.tv_sec, time_val.tv_usec, level, + except_str, entry->id.fields.cpuid, caller); #else 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); + rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %08lx ", + area, time_val.tv_sec, time_val.tv_usec, level, + except_str, entry->id.fields.cpuid, caller); #endif - out: + return rc; +} + +/* + * prints debug data sprintf-formated: + * debug_sprinf_event/exception calls must be used together with this view + */ + +#define DEBUG_SPRINTF_MAX_ARGS 10 + +int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, debug_sprintf_entry *curr_event) +{ + int num_longs, num_used_args = 0,i, rc = 0; + int index[DEBUG_SPRINTF_MAX_ARGS]; + + /* count of longs fit into one entry */ + num_longs = id->buf_size / sizeof(long); + + if(num_longs < 1) + goto out; /* bufsize of entry too small */ + if(num_longs == 1) { + /* no args, we use only the string */ + strcpy(out_buf, curr_event->string); + rc = strlen(curr_event->string); + goto out; + } + + /* number of arguments used for sprintf (without the format string) */ + num_used_args = MIN(DEBUG_SPRINTF_MAX_ARGS, (num_longs - 1)); + + memset(index,0, DEBUG_SPRINTF_MAX_ARGS * sizeof(int)); + + for(i = 0; i < num_used_args; i++) + index[i] = i; + + rc = sprintf(out_buf, curr_event->string, curr_event->args[index[0]], + curr_event->args[index[1]], curr_event->args[index[2]], + curr_event->args[index[3]], curr_event->args[index[4]], + curr_event->args[index[5]], curr_event->args[index[6]], + curr_event->args[index[7]], curr_event->args[index[8]], + curr_event->args[index[9]]); + +out: + return rc; } @@ -1165,3 +1196,17 @@ } #endif /* MODULE */ + +EXPORT_SYMBOL(debug_register); +EXPORT_SYMBOL(debug_unregister); +EXPORT_SYMBOL(debug_set_level); +EXPORT_SYMBOL(debug_register_view); +EXPORT_SYMBOL(debug_unregister_view); +EXPORT_SYMBOL(debug_event_common); +EXPORT_SYMBOL(debug_exception_common); +EXPORT_SYMBOL(debug_hex_ascii_view); +EXPORT_SYMBOL(debug_raw_view); +EXPORT_SYMBOL(debug_dflt_header_fn); +EXPORT_SYMBOL(debug_sprintf_view); +EXPORT_SYMBOL(debug_sprintf_exception); +EXPORT_SYMBOL(debug_sprintf_event); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/ebcdic.c linux.ac/arch/s390x/kernel/ebcdic.c --- linux.vanilla/arch/s390x/kernel/ebcdic.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/kernel/ebcdic.c Thu Apr 12 12:00:34 2001 @@ -9,6 +9,7 @@ * Martin Peschke <peschke@fh-brandenburg.de> */ +#include <linux/module.h> #include <asm/types.h> /* @@ -389,3 +390,11 @@ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; + +EXPORT_SYMBOL_NOVERS(_ascebc_500); +EXPORT_SYMBOL_NOVERS(_ebcasc_500); +EXPORT_SYMBOL_NOVERS(_ascebc); +EXPORT_SYMBOL_NOVERS(_ebcasc); +EXPORT_SYMBOL_NOVERS(_ebc_tolower); +EXPORT_SYMBOL_NOVERS(_ebc_toupper); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/entry.S linux.ac/arch/s390x/kernel/entry.S --- linux.vanilla/arch/s390x/kernel/entry.S Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/s390x/kernel/entry.S Thu Apr 12 12:00:34 2001 @@ -9,56 +9,53 @@ * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), */ +#define ASSEMBLY + #include <linux/sys.h> #include <linux/linkage.h> #include <linux/config.h> #include <asm/lowcore.h> #include <asm/errno.h> -#define ASSEMBLY #include <asm/smp.h> -#include <asm/s390-regs-common.h> +#include <asm/ptrace.h> /* - * 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 - * me grief when I modify the pt_regs + * Stack layout for the system_call stack entry. + * The first few entries are identical to the user_regs_struct. */ 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) -SP_R2 = (SP_R1+GPR_SIZE) -SP_R3 = (SP_R2+GPR_SIZE) -SP_R4 = (SP_R3+GPR_SIZE) -SP_R5 = (SP_R4+GPR_SIZE) -SP_R6 = (SP_R5+GPR_SIZE) -SP_R7 = (SP_R6+GPR_SIZE) -SP_R8 = (SP_R7+GPR_SIZE) -SP_R9 = (SP_R8+GPR_SIZE) -SP_RA = (SP_R9+GPR_SIZE) -SP_RB = (SP_RA+GPR_SIZE) -SP_RC = (SP_RB+GPR_SIZE) -SP_RD = (SP_RC+GPR_SIZE) -SP_RE = (SP_RD+GPR_SIZE) -SP_RF = (SP_RE+GPR_SIZE) -SP_AREGS = (SP_RF+GPR_SIZE) -SP_ORIG_R2 = (SP_AREGS+(NUM_ACRS*ACR_SIZE)) +SP_PSW = STACK_FRAME_OVERHEAD + PT_PSWMASK +SP_R0 = STACK_FRAME_OVERHEAD + PT_GPR0 +SP_R1 = STACK_FRAME_OVERHEAD + PT_GPR1 +SP_R2 = STACK_FRAME_OVERHEAD + PT_GPR2 +SP_R3 = STACK_FRAME_OVERHEAD + PT_GPR3 +SP_R4 = STACK_FRAME_OVERHEAD + PT_GPR4 +SP_R5 = STACK_FRAME_OVERHEAD + PT_GPR5 +SP_R6 = STACK_FRAME_OVERHEAD + PT_GPR6 +SP_R7 = STACK_FRAME_OVERHEAD + PT_GPR7 +SP_R8 = STACK_FRAME_OVERHEAD + PT_GPR8 +SP_R9 = STACK_FRAME_OVERHEAD + PT_GPR9 +SP_R10 = STACK_FRAME_OVERHEAD + PT_GPR10 +SP_R11 = STACK_FRAME_OVERHEAD + PT_GPR11 +SP_R12 = STACK_FRAME_OVERHEAD + PT_GPR12 +SP_R13 = STACK_FRAME_OVERHEAD + PT_GPR13 +SP_R14 = STACK_FRAME_OVERHEAD + PT_GPR14 +SP_R15 = STACK_FRAME_OVERHEAD + PT_GPR15 +SP_AREGS = STACK_FRAME_OVERHEAD + PT_ACR0 +SP_ORIG_R2 = STACK_FRAME_OVERHEAD + PT_ORIGGPR2 +/* Now the additional entries */ SP_TRAP = (SP_ORIG_R2+GPR_SIZE) #if CONFIG_REMOTE_DEBUG SP_CRREGS = (SP_TRAP+4) /* 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 - 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_SIZE = (SP_SVC_STEP+4) +SP_SIZE = (SP_PGM_OLD_ILC+4) /* * these defines are offsets into the thread_struct */ @@ -72,6 +69,8 @@ _TSS_ERROR = (_TSS_PROT+8) _TSS_TRAP = (_TSS_ERROR+4) _TSS_PER = (_TSS_TRAP+4) +_TSS_IEEE = (_TSS_PER+72) +_TSS_FLAGS = (_TSS_IEEE+8) /* * these are offsets into the task-struct. @@ -83,31 +82,6 @@ tsk_ptrace = 40 processor = 100 -/* PSW related defines */ -disable = 0xFC -enable = 0x03 -daton = 0x04 - - -#if 0 -/* some code left lying around in case we need a - * printk for debugging purposes - */ - sysc_printk: .long printk - sysc_msg: .string "<2>r15 %X\n" - .align 4 - -# basr %r13,0 - lg %r0,SP_PSW+8(%r15) - sllg %r0,%r0,1 - chi %r0,0 - jnz sysc_dn - la %r2,sysc_msg-sysc_lit(%r13) - lgr %r3,%r15 - brasl %r14,sysc_printk -sysc_dn: -#endif - /* * Register usage in interrupt handlers: * R9 - pointer to current task structure @@ -116,38 +90,41 @@ * R15 - kernel stack pointer */ -#define SAVE_ALL(psworg) \ - stmg %r14,%r15,__LC_SAVE_AREA ; \ - stam %a2,%a4,__LC_SAVE_AREA+16 ; \ - tm psworg+1,0x01 ; /* test problem state bit */ \ - jz 0f ; /* skip stack setup save */ \ - lg %r15,__LC_KERNEL_STACK ; /* problem state -> load ksp */ \ - slr %r14,%r14 ; \ - sar %a2,%r14 ; /* set ac.reg. 2 to primary space */ \ - lhi %r14,1 ; \ - sar %a4,%r14 ; /* set access reg. 4 to home space */ \ -0: aghi %r15,-SP_SIZE ; /* make room for registers & psw */ \ - nill %r15,0xfff8 ; /* align stack pointer to 8 */ \ - stmg %r0,%r14,SP_R0(%r15) ; /* store gprs 0-14 to kernel stack */ \ - stg %r2,SP_ORIG_R2(%r15) ; /* store original content of gpr 2 */ \ - mvc SP_RE(16,%r15),__LC_SAVE_AREA ; /* move R15 to stack */ \ - stam %a0,%a15,SP_AREGS(%r15) ; /* store access registers to kst. */\ - mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+16 ; /* store ac. regs */ \ - mvc SP_PSW(16,%r15),psworg; /* move user PSW to stack */ \ - lhi %r0,psworg ; /* store trap indication */ \ - st %r0,SP_TRAP(%r15) ; \ - xc 0(8,%r15),0(%r15) ; /* clear back chain */ - -#define RESTORE_ALL \ - mvc __LC_RETURN_PSW(16),SP_PSW(%r15) ; /* move user PSW to lowcore */ \ - lam %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \ - lmg %r0,%r15,SP_R0(%r15) ; /* load gprs 0-15 of user */ \ - ni __LC_RETURN_PSW+1,0xfd ; /* clear wait state bit */ \ - lpswe __LC_RETURN_PSW /* back to caller */ + .macro SAVE_ALL psworg # system entry macro + stmg %r14,%r15,__LC_SAVE_AREA + stam %a2,%a4,__LC_SAVE_AREA+16 + tm \psworg+1,0x01 # test problem state bit + jz 0f # skip stack setup save + lg %r15,__LC_KERNEL_STACK # problem state -> load ksp + slr %r14,%r14 + sar %a2,%r14 # set ac.reg. 2 to primary space + lhi %r14,1 + sar %a4,%r14 # set access reg. 4 to home space +0: aghi %r15,-SP_SIZE # make room for registers & psw + nill %r15,0xfff8 # align stack pointer to 8 + stmg %r0,%r14,SP_R0(%r15) # store gprs 0-14 to kernel stack + stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 + mvc SP_R14(16,%r15),__LC_SAVE_AREA # move R15 to stack + stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst. + mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+16 # store ac. regs + mvc SP_PSW(16,%r15),\psworg # move user PSW to stack + lhi %r0,\psworg # store trap indication + st %r0,SP_TRAP(%r15) + xc 0(8,%r15),0(%r15) # clear back chain + .endm + + .macro RESTORE_ALL # system exit macro + mvc __LC_RETURN_PSW(16),SP_PSW(%r15) # move user PSW to lowcore + lam %a0,%a15,SP_AREGS(%r15) # load the access registers + lmg %r0,%r15,SP_R0(%r15) # load gprs 0-15 of user + ni __LC_RETURN_PSW+1,0xfd # clear wait state bit + lpswe __LC_RETURN_PSW # back to caller + .endm -#define GET_CURRENT /* load pointer to task_struct to R9 */ \ - lghi %r9,-16384 ; \ + .macro GET_CURRENT + lghi %r9,-16384 # load pointer to task_struct to %r9 ngr %r9,15 + .endm /* @@ -162,7 +139,7 @@ lg %r4,_TSS_PTREGS(%r3) tm SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ? jz resume_noper # if not we're fine - stctg %r9,%r11,48(%r15) # We are using per stuff + stctg %c9,%c11,48(%r15) # We are using per stuff clc _TSS_PER(24,%r3),48(%r15) je resume_noper # we got away without bashing TLB's lctlg %c9,%c11,_TSS_PER(%r3) # Nope we didn't @@ -191,10 +168,11 @@ .globl system_call system_call: - SAVE_ALL(__LC_SVC_OLD_PSW) - xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15) + SAVE_ALL __LC_SVC_OLD_PSW + mvi SP_PGM_OLD_ILC(%r15),1 # mark PGM_OLD_ILC as invalid pgm_system_call: - larl %r1,sys_call_table + GET_CURRENT # load pointer to task_struct to R9 + larl %r7,sys_call_table llgc %r8,__LC_SVC_INT_CODE+1 # get svc number from lowcore stosm 48(%r15),0x03 # reenable interrupts sll %r8,3 @@ -202,8 +180,7 @@ jo sysc_noemu la %r8,4(%r8) # use 31 bit emulation system calls sysc_noemu: - GET_CURRENT # load pointer to task_struct to R9 - lgf %r8,0(%r8,%r1) # load address of system call routine + lgf %r8,0(%r8,%r7) # load address of system call routine tm tsk_ptrace+7(%r9),0x02 # PT_TRACESYS jnz sysc_tracesys basr %r14,%r8 # call sys_xxxx @@ -212,7 +189,6 @@ # changing anything here !! sysc_return: - GET_CURRENT # load pointer to task_struct to R9 tm SP_PSW+1(%r15),0x01 # returning to user ? jno sysc_leave # no-> skip bottom half, resched & signal # @@ -228,12 +204,12 @@ lg %r0,need_resched(%r9) # get need_resched from task_struct ltgr %r0,%r0 jnz sysc_reschedule - icm %r0,15,sigpending(%r9) # get sigpending from task_struct + icm %r0,15,sigpending(%r9) # get sigpending from task_struct jnz sysc_signal_return sysc_leave: - icm %r0,15,SP_SVC_STEP(%r15) # get sigpending from task_struct - jnz pgm_svcret - stnsm 48(%r15),disable # disable I/O and ext. interrupts + tm SP_PGM_OLD_ILC(%r15),0xff + jz pgm_svcret + stnsm 48(%r15),0xfc # disable I/O and ext. interrupts RESTORE_ALL # @@ -667,7 +643,7 @@ je pgm_svcper # no interesting special case, ignore PER event lm %r13,%r15,__LC_SAVE_AREA - lpsw __LC_PGM_OLD_PSW + lpswe __LC_PGM_OLD_PSW # it was a single stepped SVC that is causing all the trouble pgm_svcper: tm __LC_SVC_OLD_PSW+1,0x01 # test problem state bit @@ -681,7 +657,7 @@ nill %r15,0xfff8 # align stack pointer to 8 stmg %r0,%r14,SP_R0(%r15) # store gprs 0-14 to kernel stack stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 - mvc SP_RE(16,%r15),__LC_SAVE_AREA # move R14-R15 to stack + mvc SP_R14(16,%r15),__LC_SAVE_AREA # move R14-R15 to stack stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst. mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+16 # store ac. regs mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW # move user PSW to stack @@ -689,14 +665,13 @@ st %r0,SP_TRAP(%r15) xc 0(8,%r15),0(%r15) # clear back chain - 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 j pgm_system_call # now do the svc pgm_svcret: lhi %r0,__LC_PGM_OLD_PSW # set trap indication back to pgm_chk st %r0,SP_TRAP(%r15) llgh %r7,SP_PGM_OLD_ILC(%r15) # get ilc from stack - xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15) + mvi SP_PGM_OLD_ILC(%r15),1 # mark PGM_OLD_ILC as invalid j pgm_no_sv pgm_sv: tm __LC_PGM_OLD_PSW+1,0x01 # test problem state bit @@ -710,15 +685,16 @@ nill %r15,0xfff8 # align stack pointer to 8 stmg %r0,%r14,SP_R0(%r15) # store gprs 0-14 to kernel stack stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 - mvc SP_RE(16,%r15),__LC_SAVE_AREA # move R14-R15 to stack + mvc SP_R14(16,%r15),__LC_SAVE_AREA # move R14-R15 to stack stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst. mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+16 # store ac. regs mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW # move user PSW to stack lhi %r0,__LC_PGM_OLD_PSW # store trap indication st %r0,SP_TRAP(%r15) xc 0(8,%r15),0(%r15) # clear back chain - xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15) - llgh %r7,__LC_PGM_ILC # load instruction length + mvi SP_PGM_OLD_ILC(%r15),1 # mark PGM_OLD_ILC as invalid + llgh %r7,__LC_PGM_ILC # load instruction length + GET_CURRENT pgm_no_sv: llgh %r8,__LC_PGM_INT_CODE # N.B. saved int code used later KEEP it stosm 48(%r15),0x03 # reenable interrupts @@ -726,8 +702,8 @@ nr %r3,%r8 # clear per-event-bit & move to r3 je pgm_dn # none of Martins exceptions occurred bypass sll %r3,3 - larl %r9,pgm_check_table - lg %r9,0(%r3,%r9) # load address of handler routine + larl %r1,pgm_check_table + lg %r1,0(%r3,%r1) # load address of handler routine srl %r3,3 la %r2,SP_PTREGS(%r15) # address of register-save area chi %r3,0x4 # protection-exception ? @@ -735,7 +711,7 @@ lg %r5,SP_PSW+8(15) # load psw addr slgr %r5,%r7 # substract ilc from psw stg %r5,SP_PSW+8(15) # store corrected psw addr -pgm_go: basr %r14,%r9 # branch to interrupt-handler +pgm_go: basr %r14,%r1 # branch to interrupt-handler pgm_dn: nill %r8,0x80 # check for per exception je sysc_return la %r2,SP_PTREGS(15) # address of register-save area @@ -747,17 +723,17 @@ */ .globl io_int_handler io_int_handler: - SAVE_ALL(__LC_IO_OLD_PSW) + SAVE_ALL __LC_IO_OLD_PSW + GET_CURRENT # load pointer to task_struct to R9 la %r2,SP_PTREGS(%r15) # address of register-save area llgh %r3,__LC_SUBCHANNEL_NR # load subchannel number - llgf %r4,__LC_IO_INT_PARM # load interruption parm - llgf %r5,__LC_IO_INT_WORD # load interruption word + llgf %r4,__LC_IO_INT_PARM # load interuption parm + llgf %r5,__LC_IO_INT_WORD # load interuption word brasl %r14,do_IRQ # call standard irq handler io_return: - GET_CURRENT # load pointer to task_struct to R9 tm SP_PSW+1(%r15),0x01 # returning to user ? - jz io_leave # no-> skip resched & signal + jno io_leave # no-> skip resched & signal stosm 48(%r15),0x03 # reenable interrupts # # check, if bottom-half has to be done @@ -775,7 +751,7 @@ icm %r0,15,sigpending(%r9) # get sigpending from task_struct jnz io_signal_return io_leave: - stnsm 48(%r15),disable # disable I/O and ext. interrupts + stnsm 48(%r15),0xfc # disable I/O and ext. interrupts RESTORE_ALL # @@ -807,34 +783,35 @@ */ .globl ext_int_handler ext_int_handler: - SAVE_ALL(__LC_EXT_OLD_PSW) + SAVE_ALL __LC_EXT_OLD_PSW + GET_CURRENT # load pointer to task_struct to R9 la %r2,SP_PTREGS(%r15) # address of register-save area llgh %r3,__LC_EXT_INT_CODE # error code lgr %r1,%r3 # calculate index = code & 0xff nill %r1,0xff sll %r1,3 - larl %r9,ext_int_hash - lg %r9,0(%r1,%r9) # get first list entry for hash value - ltgr %r9,%r9 # == NULL ? + larl %r4,ext_int_hash + lg %r4,0(%r1,%r4) # get first list entry for hash value + ltgr %r4,%r4 # == NULL ? jz io_return # yes, nothing to do, exit ext_int_loop: - ch %r3,16(%r9) # compare external interrupt code + ch %r3,16(%r4) # compare external interrupt code je ext_int_found - lg %r9,0(%r9) # next list entry - ltgr %r9,%r9 + lg %r4,0(%r4) # next list entry + ltgr %r4,%r4 jnz ext_int_loop j io_return ext_int_found: - lg %r9,8(%r9) # get handler address + lg %r4,8(%r4) # get handler address larl %r14,io_return - br %r9 # branch to ext call handler + br %r4 # branch to ext call handler /* * Machine check handler routines */ .globl mcck_int_handler mcck_int_handler: - SAVE_ALL(__LC_MCK_OLD_PSW) + SAVE_ALL __LC_MCK_OLD_PSW brasl %r14,s390_do_machine_check mcck_return: RESTORE_ALL @@ -848,7 +825,7 @@ lg %r15,__LC_KERNEL_STACK # load ksp lctlg %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs lam %a0,%a15,__LC_AREGS_SAVE_AREA - stosm 0(%r15),daton # now we can turn dat on + stosm 0(%r15),0x04 # now we can turn dat on lmg %r6,%r15,48(%r15) # load registers from clone jg start_secondary #else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/exec32.c linux.ac/arch/s390x/kernel/exec32.c --- linux.vanilla/arch/s390x/kernel/exec32.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/s390x/kernel/exec32.c Thu Apr 12 12:00:34 2001 @@ -82,3 +82,4 @@ return 0; } +EXPORT_SYMBOL(setup_arg_pages32); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/head.S linux.ac/arch/s390x/kernel/head.S --- linux.vanilla/arch/s390x/kernel/head.S Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/kernel/head.S Thu Apr 12 12:00:34 2001 @@ -261,8 +261,9 @@ l %r1,0xb8 # load ipl subchannel number la %r2,IPL_BS # load start address bas %r14,.Lloader # load rest of ipl image - st %r1,__LC_IPLDEV # store ipl device number l %r12,.Lparm # pointer to parameter area + st %r1,__LC_IPLDEV # store ipl device number + st %r1,IPL_DEVICE+4-PARMAREA(%r12) # # load parameter file from ipl device @@ -405,16 +406,18 @@ sr %r3,%r2 la %r3,1(%r3) .done: - st %r3,MEMORY_SIZE-PARMAREA(%r11) + l %r1,.memsize + st %r3,4(%r1) slr %r0,%r0 - st %r0,INITRD_SIZE-PARMAREA(%r11) - st %r0,INITRD_START-PARMAREA(%r11) + st %r0,INITRD_SIZE+4-PARMAREA(%r11) + st %r0,INITRD_START+4-PARMAREA(%r11) j startup # continue with startup .tbl: .long _ebcasc # translate table .cmd: .long COMMAND_LINE # address of command line buffer .parm: .long PARMAREA .fourmeg: .long 0x00400000 # 4M .pgmnw: .long 0x00080000,.pgmx +.memsize: .long memory_size .lowcase: .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 .byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f @@ -480,21 +483,35 @@ bno .Lloop-.LPG1(%r13) # r1 < 0x80000000 -> loop .Lchkmem: ng %r1,.L4malign-.LPG1(%r13) # align to multiples of 4M - stg %r1,MEMORY_SIZE-PARMAREA(%r12) # store memory size + lg %r2,.Lmemsize-.LPG1(%r13) # address of variable memory_size + stg %r1,0(%r2) # store memory size + + lg %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags # # find out if we are running under VM # stidp __LC_CPUID # store cpuid tm __LC_CPUID,0xff # running under VM ? bno .Lnovm-.LPG1(%r13) - oi MACHINE_FLAGS+7-PARMAREA(%r12),1 # set VM flag + oi 7(%r12),1 # set VM flag .Lnovm: lh %r0,__LC_CPUID+4 # get cpu version chi %r0,0x7490 # running on a P/390 ? bne .Lnop390-.LPG1(%r13) - oi MACHINE_FLAGS+7-PARMAREA(%r12),4 # set P/390 flag + oi 7(%r12),4 # set P/390 flag .Lnop390: +# +# find out if we have the MVPG instruction +# + mvc __LC_PGM_NEW_PSW(16),.Lpcmvpg-.LPG1(%r13) + sgr %r0,%r0 + lghi %r1,0 + lghi %r2,0 + mvpg %r1,%r2 # Test CSP instruction + oi 7(%r12),16 # set MVPG flag +.Lchkmvpg: + lpswe .Lentry-.LPG1(13) # jump to _stext in primary-space, # virtual and never return ... .align 16 @@ -516,24 +533,23 @@ .quad 0xc0000000 # cr14: machine check handling off .quad 0 # cr15: linkage stack operations .Lpcmem:.quad 0x0000000180000000,.Lchkmem +.Lpcmvpg:.quad 0x0000000180000000,.Lchkmvpg .Lflt0: .double 0 .Lparm1:.quad PARMAREA .Lhighoff:.long 0x7fffffff .L4malign:.quad 0xffffffffffc00000 .Lbigmem:.quad 0x04000000 .Lmaxchunk:.quad 0x00ffffff +.Lmemsize:.quad memory_size +.Lmflags:.quad machine_flags # # params at 10400 (setup.h) # .org PARMAREA - .quad 0x0100 # ORIG_ROOT_DEV: ramdisk major/minor - .word 0 # MOUNT_ROOT_RDONLY: no - .quad 0 # MEMORY_SIZE - .quad 0 # MACHINE_FLAGS (bit 0:VM) + .quad 0 # IPL_DEVICE .quad RAMDISK_ORIGIN # INITRD_START .quad RAMDISK_SIZE # INITRD_SIZE - .word 0 # RAMDISK_FLAGS .org COMMAND_LINE .byte "root=/dev/ram0 ro" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/irq.c linux.ac/arch/s390x/kernel/irq.c --- linux.vanilla/arch/s390x/kernel/irq.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/kernel/irq.c Thu Apr 12 12:00:34 2001 @@ -11,6 +11,7 @@ * S/390 I/O interrupt processing and I/O request processing is * implemented in arch/s390/kernel/s390io.c */ +#include <linux/module.h> #include <linux/config.h> #include <linux/ptrace.h> #include <linux/errno.h> @@ -351,48 +352,6 @@ #endif -/* - * Note : This fuction should be eliminated as it doesn't comply with the - * S/390 irq scheme we have implemented ... - */ -int handle_IRQ_event(unsigned int irq, int cpu, struct pt_regs * regs) -{ - struct irqaction * action; - int status; - - status = 0; - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - return( -ENODEV); - - action = ioinfo[irq]->irq_desc.action; - - if (action) - { - status |= 1; - - if (!(action->flags & SA_INTERRUPT)) - __sti(); - - do - { - status |= action->flags; - action->handler(irq, action->dev_id, regs); - action = action->next; - } while (action); - - if (status & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); - __cli(); - - } /* endif */ - - return status; -} - -void enable_nop(int irq) -{ -} void __init init_IRQ(void) { @@ -421,3 +380,8 @@ /* For now, nothing... */ } +EXPORT_SYMBOL(__global_cli); +EXPORT_SYMBOL(__global_sti); +EXPORT_SYMBOL(__global_save_flags); +EXPORT_SYMBOL(__global_restore_flags); +EXPORT_SYMBOL(global_bh_lock); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/irqextras390.c linux.ac/arch/s390x/kernel/irqextras390.c --- linux.vanilla/arch/s390x/kernel/irqextras390.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/kernel/irqextras390.c Thu Jan 1 01:00:00 1970 @@ -1,35 +0,0 @@ -/* - * arch/s390/kernel/irqextras390.c - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), - * - * Some channel code by D.J. Barrow - */ - -/* - -*/ -#include<asm/irqextras390.h> -#include<asm/lowcore.h> - -#if 0 -// fixchannelprogram is now obselete -void fixchannelprogram(orb_bits_t *orbptr) -{ - __u32 newAddress=orbptr->ccw_program_address; - fixccws(orbptr->ccw_program_address); - orbptr->ccw_program_address=newAddress; - orbptr->ccw_program_address=(ccw1_t *)(((__u32)orbptr->ccw_program_address)); -} -#endif - -void fixccws(ccw1_bits_t *ccwptr) -{ - for(;;ccwptr++) - { // Just hope nobody starts doing prefixing - if(!ccwptr->cc) - break; - } -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/process.c linux.ac/arch/s390x/kernel/process.c --- linux.vanilla/arch/s390x/kernel/process.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/kernel/process.c Mon Apr 16 12:37:04 2001 @@ -28,7 +28,7 @@ #include <linux/stddef.h> #include <linux/unistd.h> #include <linux/ptrace.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/user.h> #include <linux/a.out.h> @@ -42,7 +42,6 @@ #include <asm/system.h> #include <asm/io.h> #include <asm/processor.h> -#include <asm/misc390.h> #include <asm/irq.h> spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED; @@ -300,12 +299,10 @@ unsigned long fprs[2]; /* fpr 4 and 6 */ unsigned long empty[2]; #if CONFIG_REMOTE_DEBUG - gdb_pt_regs childregs; + struct gdb_pt_regs childregs; #else - pt_regs childregs; + struct pt_regs childregs; #endif - __u32 pgm_old_ilc; /* single step magic from entry.S */ - __u32 pgm_svc_step; } *frame; frame = (struct stack_frame *) (4*PAGE_SIZE + (unsigned long) p) -1; @@ -321,7 +318,7 @@ /* fake return stack for resume(), don't go back to schedule */ frame->gprs[9] = (unsigned long) frame; - frame->pgm_svc_step = 0; /* Nope we aren't single stepping an svc */ + frame->childregs.old_ilc = -1; /* We are not single stepping an svc */ /* save fprs, if used in last task */ save_fp_regs(&p->thread.fp_regs); p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _REGION_TABLE; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/ptrace.c linux.ac/arch/s390x/kernel/ptrace.c --- linux.vanilla/arch/s390x/kernel/ptrace.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/kernel/ptrace.c Thu Apr 12 12:00:34 2001 @@ -153,7 +153,7 @@ useraddr = 2 * useraddr + sizeof(addr_t) / 2; else if(useraddr < PT_ACR0 / 2 + (PT_ORIGGPR2 - PT_ACR0)) useraddr = useraddr + PT_ACR0 / 2; - else if(useraddr < PT_ACR0 / 2 + (sizeof(user_regs_struct) - sizeof(addr_t) / 2 - PT_ACR0)) + else if(useraddr < PT_ACR0 / 2 + (sizeof(struct user_regs_struct) - sizeof(addr_t) / 2 - PT_ACR0)) useraddr = useraddr + PT_ACR0 / 2 + sizeof(addr_t) / 2; } #endif @@ -174,15 +174,15 @@ { copymax=PT_PSWMASK; } - else if(useraddr<(PT_PSWMASK+PSW_MASK_SIZE)) + else if(useraddr<(PT_PSWMASK+8)) { - copymax=(PT_PSWMASK+PSW_MASK_SIZE); + copymax=(PT_PSWMASK+8); if(writingtouser) mask=PSW_MASK_DEBUGCHANGE; } - else if(useraddr<(PT_PSWADDR+PSW_ADDR_SIZE)) + else if(useraddr<(PT_PSWADDR+8)) { - copymax=PT_PSWADDR+PSW_ADDR_SIZE; + copymax=PT_PSWADDR+8; mask=PSW_ADDR_DEBUGCHANGE; } else @@ -194,9 +194,9 @@ copymax=(PT_FPR15+sizeof(freg_t)); realuseraddr=(addr_t)&(((u8 *)&task->thread.fp_regs)[useraddr-PT_FPC]); } - else if(useraddr<sizeof(user_regs_struct)) + else if(useraddr<sizeof(struct user_regs_struct)) { - copymax=sizeof(user_regs_struct); + copymax=sizeof(struct user_regs_struct); realuseraddr=(addr_t)&(((u8 *)&task->thread.per_info)[useraddr-PT_CR_9]); } else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/s390_ext.c linux.ac/arch/s390x/kernel/s390_ext.c --- linux.vanilla/arch/s390x/kernel/s390_ext.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/kernel/s390_ext.c Thu Apr 12 12:00:34 2001 @@ -7,6 +7,7 @@ * Martin Schwidefsky (schwidefsky@de.ibm.com) */ +#include <linux/module.h> #include <linux/kernel.h> #include <linux/malloc.h> #include <asm/lowcore.h> @@ -74,4 +75,6 @@ return 0; } +EXPORT_SYMBOL(register_external_interrupt); +EXPORT_SYMBOL(unregister_external_interrupt); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/s390_ksyms.c linux.ac/arch/s390x/kernel/s390_ksyms.c --- linux.vanilla/arch/s390x/kernel/s390_ksyms.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/kernel/s390_ksyms.c Thu Apr 12 12:00:34 2001 @@ -4,71 +4,18 @@ * S390 version */ #include <linux/config.h> -#include <linux/module.h> -#include <linux/string.h> #include <linux/highuid.h> -#include <asm/ccwcache.h> -#include <asm/debug.h> -#include <asm/irq.h> -#include <asm/s390_ext.h> -#include <asm/s390dyn.h> -#include <asm/ebcdic.h> +#include <linux/module.h> +#include <linux/mm.h> #include <asm/checksum.h> #include <asm/delay.h> #include <asm/pgalloc.h> -#include <asm/idals.h> -#if CONFIG_CHANDEV -#include <asm/chandev.h> -#endif +#include <asm/setup.h> #if CONFIG_IP_MULTICAST #include <net/arp.h> #endif /* - * I/O subsystem - */ -EXPORT_SYMBOL(halt_IO); -EXPORT_SYMBOL(clear_IO); -EXPORT_SYMBOL(do_IO); -EXPORT_SYMBOL(resume_IO); -EXPORT_SYMBOL(ioinfo); -EXPORT_SYMBOL(get_dev_info_by_irq); -EXPORT_SYMBOL(get_dev_info_by_devno); -EXPORT_SYMBOL(get_irq_by_devno); -EXPORT_SYMBOL(get_devno_by_irq); -EXPORT_SYMBOL(get_irq_first); -EXPORT_SYMBOL(get_irq_next); -EXPORT_SYMBOL(read_conf_data); -EXPORT_SYMBOL(read_dev_chars); -EXPORT_SYMBOL(s390_request_irq_special); -EXPORT_SYMBOL(s390_device_register); -EXPORT_SYMBOL(s390_device_unregister); - -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_set_level); -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_ascii_view); -EXPORT_SYMBOL(debug_raw_view); -EXPORT_SYMBOL(debug_dflt_header_fn); - -/* * memory management */ EXPORT_SYMBOL(_oi_bitmap); @@ -94,6 +41,7 @@ EXPORT_SYMBOL_NOVERS(strlen); EXPORT_SYMBOL_NOVERS(strchr); EXPORT_SYMBOL_NOVERS(strcmp); +EXPORT_SYMBOL_NOVERS(strcat); EXPORT_SYMBOL_NOVERS(strncat); EXPORT_SYMBOL_NOVERS(strncmp); EXPORT_SYMBOL_NOVERS(strncpy); @@ -102,56 +50,22 @@ EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL_NOVERS(strpbrk); -EXPORT_SYMBOL_NOVERS(_ascebc_500); -EXPORT_SYMBOL_NOVERS(_ebcasc_500); -EXPORT_SYMBOL_NOVERS(_ascebc); -EXPORT_SYMBOL_NOVERS(_ebcasc); -EXPORT_SYMBOL_NOVERS(_ebc_tolower); -EXPORT_SYMBOL_NOVERS(_ebc_toupper); - /* * binfmt_elf loader */ -EXPORT_SYMBOL(get_pte_slow); -EXPORT_SYMBOL(get_pmd_slow); extern int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs); EXPORT_SYMBOL(dump_fpu); -#ifdef CONFIG_S390_SUPPORT -extern int setup_arg_pages32(struct linux_binprm *bprm); -EXPORT_SYMBOL(setup_arg_pages32); -#endif EXPORT_SYMBOL(overflowuid); EXPORT_SYMBOL(overflowgid); /* * misc. */ -EXPORT_SYMBOL(module_list); +EXPORT_SYMBOL(machine_flags); EXPORT_SYMBOL(__udelay); -#ifdef CONFIG_SMP -#include <asm/smplock.h> -EXPORT_SYMBOL(__global_cli); -EXPORT_SYMBOL(__global_sti); -EXPORT_SYMBOL(__global_save_flags); -EXPORT_SYMBOL(__global_restore_flags); -EXPORT_SYMBOL(lowcore_ptr); -EXPORT_SYMBOL(global_bh_lock); -EXPORT_SYMBOL(kernel_flag); -EXPORT_SYMBOL(smp_ctl_set_bit); -EXPORT_SYMBOL(smp_ctl_clear_bit); -#endif EXPORT_SYMBOL(kernel_thread); -#if CONFIG_CHANDEV -EXPORT_SYMBOL(chandev_register_and_probe); -EXPORT_SYMBOL(chandev_request_irq); -EXPORT_SYMBOL(chandev_unregister); -EXPORT_SYMBOL(chandev_initdevice); -EXPORT_SYMBOL(chandev_initnetdevice); -#endif + #if CONFIG_IP_MULTICAST /* Required for lcs gigibit ethernet multicast support */ EXPORT_SYMBOL(arp_mc_map); #endif -EXPORT_SYMBOL(s390_daemonize); -EXPORT_SYMBOL (set_normalized_cda); - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/setup.c linux.ac/arch/s390x/kernel/setup.c --- linux.vanilla/arch/s390x/kernel/setup.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/kernel/setup.c Thu Apr 12 12:00:34 2001 @@ -21,7 +21,7 @@ #include <linux/stddef.h> #include <linux/unistd.h> #include <linux/ptrace.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/user.h> #include <linux/a.out.h> #include <linux/tty.h> @@ -38,10 +38,13 @@ #include <asm/system.h> #include <asm/smp.h> #include <asm/mmu_context.h> +#include <asm/cpcmd.h> /* * Machine setup.. */ +unsigned long memory_size = 0; +unsigned long machine_flags = 0; __u16 boot_cpu_addr; int cpus_initialized = 0; unsigned long cpu_initialized = 0; @@ -50,17 +53,8 @@ /* * Setup options */ - -#ifdef CONFIG_BLK_DEV_RAM -extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ -extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt*/ -extern int rd_image_start; /* starting block # of image */ -#endif - -extern int root_mountflags; extern int _text,_etext, _edata, _end; - /* * This is set up by the setup-routine at boot-time * for S390 need to find out, what we have to setup @@ -205,18 +199,9 @@ "We are running under VM\n" : "We are running native\n"); - ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV); -#ifdef CONFIG_BLK_DEV_RAM - rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; - rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); - rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); -#endif - /* nasty stuff with PARMAREAs. we use head.S or parameterline - if (!MOUNT_ROOT_RDONLY) - root_mountflags &= ~MS_RDONLY; - */ + ROOT_DEV = to_kdev_t(0x0100); memory_start = (unsigned long) &_end; /* fixit if use $CODELO etc*/ - memory_end = MEMORY_SIZE; /* detected in head.s */ + memory_end = memory_size; /* detected in head.s */ init_mm.start_code = PAGE_OFFSET; init_mm.end_code = (unsigned long) &_etext; init_mm.end_data = (unsigned long) &_edata; @@ -303,9 +288,6 @@ * bootmem allocator with an invalid RAM area. */ reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size); - - - #ifdef CONFIG_BLK_DEV_INITRD if (INITRD_START) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/signal.c linux.ac/arch/s390x/kernel/signal.c --- linux.vanilla/arch/s390x/kernel/signal.c Sat Feb 17 00:02:35 2001 +++ linux.ac/arch/s390x/kernel/signal.c Thu Apr 12 12:00:34 2001 @@ -188,7 +188,7 @@ int err; s390_fp_regs fpregs; - err = __copy_to_user(&sregs->regs,regs,sizeof(s390_regs_common)); + err = __copy_to_user(&sregs->regs,regs,sizeof(_s390_regs_common)); if(!err) { save_fp_regs(&fpregs); @@ -203,7 +203,7 @@ int err; s390_fp_regs fpregs; psw_t saved_psw=regs->psw; - err=__copy_from_user(regs,&sregs->regs,sizeof(s390_regs_common)); + err=__copy_from_user(regs,&sregs->regs,sizeof(_s390_regs_common)); if(!err) { regs->orig_gpr2 = -1; /* disable syscall checks */ @@ -219,7 +219,7 @@ } static int -restore_sigcontext(struct sigcontext *sc, pt_regs *regs, +restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs, _sigregs *sregs,sigset_t *set) { unsigned int err; @@ -562,6 +562,7 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: + case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (do_coredump(signr, regs)) exit_code |= 0x80; /* FALLTHRU */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/signal32.c linux.ac/arch/s390x/kernel/signal32.c --- linux.vanilla/arch/s390x/kernel/signal32.c Sat Feb 17 00:02:35 2001 +++ linux.ac/arch/s390x/kernel/signal32.c Thu Apr 12 12:00:34 2001 @@ -343,7 +343,7 @@ } static int -restore_sigcontext32(struct sigcontext32 *sc, pt_regs *regs, +restore_sigcontext32(struct sigcontext32 *sc, struct pt_regs *regs, _sigregs32 *sregs,sigset_t *set) { unsigned int err; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/smp.c linux.ac/arch/s390x/kernel/smp.c --- linux.vanilla/arch/s390x/kernel/smp.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/kernel/smp.c Thu Apr 12 12:00:34 2001 @@ -20,6 +20,7 @@ * cpu_number_map in other architectures. */ +#include <linux/module.h> #include <linux/init.h> #include <linux/mm.h> @@ -33,8 +34,7 @@ #include <asm/pgalloc.h> #include <asm/irq.h> #include <asm/s390_ext.h> - -#include "cpcmd.h" +#include <asm/cpcmd.h> /* prototypes */ extern int cpu_idle(void * unused); @@ -392,7 +392,7 @@ /* stop all processors */ - smp_signal_others(sigp_stop, 0, TRUE, NULL); + smp_signal_others(sigp_stop, 0, 1, NULL); /* store status of all processors in their lowcores (real 0) */ @@ -574,7 +574,7 @@ struct pt_regs regs; /* don't care about the psw and regs settings since we'll never reschedule the forked task. */ - memset(®s,0,sizeof(pt_regs)); + memset(®s,0,sizeof(struct pt_regs)); return do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0); } @@ -758,3 +758,8 @@ } } +EXPORT_SYMBOL(lowcore_ptr); +EXPORT_SYMBOL(kernel_flag); +EXPORT_SYMBOL(smp_ctl_set_bit); +EXPORT_SYMBOL(smp_ctl_clear_bit); +EXPORT_SYMBOL(smp_num_cpus); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/kernel/sys_s390.c linux.ac/arch/s390x/kernel/sys_s390.c --- linux.vanilla/arch/s390x/kernel/sys_s390.c Tue Apr 3 17:31:57 2001 +++ linux.ac/arch/s390x/kernel/sys_s390.c Thu Apr 12 12:00:34 2001 @@ -123,7 +123,7 @@ * * This is really horribly ugly. */ -asmlinkage int sys_ipc (uint call, int first, int second, +asmlinkage int sys_ipc (uint call, int first, long second, unsigned long third, void *ptr) { struct ipc_kludge tmp; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/lib/Makefile linux.ac/arch/s390x/lib/Makefile --- linux.vanilla/arch/s390x/lib/Makefile Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/lib/Makefile Thu Apr 12 12:00:34 2001 @@ -12,7 +12,8 @@ L_TARGET = lib.a -obj-y = checksum.o delay.o memset.o strcmp.o strncpy.o uaccess.o +obj-y = checksum.o delay.o memset.o misaligned.o strcmp.o strncpy.o uaccess.o +export-objs += misaligned.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/lib/delay.c linux.ac/arch/s390x/lib/delay.c --- linux.vanilla/arch/s390x/lib/delay.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/lib/delay.c Thu Apr 12 12:00:34 2001 @@ -1,5 +1,5 @@ /* - * arch/s390/kernel/delay.c + * arch/s390x/kernel/delay.c * Precise Delay Loops for S390 * * S390 version diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/lib/misaligned.c linux.ac/arch/s390x/lib/misaligned.c --- linux.vanilla/arch/s390x/lib/misaligned.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/s390x/lib/misaligned.c Thu Apr 12 12:00:34 2001 @@ -0,0 +1,34 @@ +/* + * arch/s390/lib/misaligned.c + * S390 misalignment panic stubs + * + * S390 version + * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com). + * + * xchg wants to panic if the pointer is not aligned. To avoid multiplying + * the panic message over and over again, the panic is done in the helper + * functions __misaligned_u64, __misaligned_u32 and __misaligned_u16. + */ + +#include <linux/module.h> +#include <linux/kernel.h> + +void __misaligned_u16(void) +{ + panic("misaligned (__u16 *) in __xchg\n"); +} + +void __misaligned_u32(void) +{ + panic("misaligned (__u32 *) in __xchg\n"); +} + +void __misaligned_u64(void) +{ + panic("misaligned (__u64 *) in __xchg\n"); +} + +EXPORT_SYMBOL(__misaligned_u16); +EXPORT_SYMBOL(__misaligned_u32); +EXPORT_SYMBOL(__misaligned_u64); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/mm/fault.c linux.ac/arch/s390x/mm/fault.c --- linux.vanilla/arch/s390x/mm/fault.c Tue Apr 3 17:31:57 2001 +++ linux.ac/arch/s390x/mm/fault.c Thu Apr 12 12:00:34 2001 @@ -33,6 +33,34 @@ extern void die(const char *,struct pt_regs *,long); +extern spinlock_t timerlist_lock; + +/* + * Unlock any spinlocks which will prevent us from getting the + * message out + */ +void bust_spinlocks(int yes) +{ + spin_lock_init(&timerlist_lock); + if (yes) { + oops_in_progress = 1; +#ifdef CONFIG_SMP + atomic_set(&global_irq_lock,0); +#endif + } else { + int loglevel_save = console_loglevel; + oops_in_progress = 0; + /* + * OK, the message is on the console. Now we call printk() + * without oops_in_progress set so that printk will give klogd + * a poke. Hold onto your hats... + */ + console_loglevel = 15; /* NMI oopser may have shut the console up */ + printk(" "); + console_loglevel = loglevel_save; + } +} + /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/mm/init.c linux.ac/arch/s390x/mm/init.c --- linux.vanilla/arch/s390x/mm/init.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/mm/init.c Thu Apr 12 12:00:34 2001 @@ -35,31 +35,14 @@ #include <asm/pgalloc.h> #include <asm/dma.h> #include <asm/lowcore.h> +#include <asm/tlb.h> + +mmu_gather_t mmu_gathers[NR_CPUS]; static unsigned long totalram_pages; -/* - * empty_bad_page is the page that is used for page faults when linux - * is out-of-memory. Older versions of linux just did a - * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving an inode - * unused etc.. - * - * empty_bad_pte_table is the accompanying page-table: it is initialized - * to point to BAD_PAGE entries. - * - * empty_bad_pmd_table is the accompanying segment table: it is initialized - * to point to empty_bad_pte_table page tables. - * - * ZERO_PAGE is a special page that is used for zero-initialized - * data and COW. - */ - pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE))); -char empty_bad_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); -pmd_t empty_bad_pmd_table[PTRS_PER_PMD] __attribute__((__aligned__(PAGE_SIZE))); -pte_t empty_bad_pte_table[PTRS_PER_PTE] __attribute__((__aligned__(PAGE_SIZE))); static int test_access(unsigned long loc) { @@ -88,79 +71,6 @@ return rc; } -static pmd_t *get_bad_pmd_table(void) -{ - pmd_t v; - int i; - - pmd_set(&v, empty_bad_pte_table); - - for (i = 0; i < PTRS_PER_PMD; i++) - empty_bad_pmd_table[i] = v; - - return empty_bad_pmd_table; -} - -static pte_t *get_bad_pte_table(void) -{ - pte_t v; - int i; - - v = pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED)); - - for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++) - empty_bad_pte_table[i] = v; - - return empty_bad_pte_table; -} - -pmd_t * -get_pmd_slow(pgd_t *pgd, unsigned long offset) -{ - pmd_t *pmd; - int i; - - pmd = (pmd_t *) __get_free_pages(GFP_KERNEL,2); - if (pgd_none(*pgd)) { - if (pmd) { - for (i = 0; i < PTRS_PER_PMD; i++) - pmd_clear(pmd+i); - pgd_set(pgd, pmd); - return pmd + offset; - } - pmd = (pmd_t *) get_bad_pmd_table(); - pgd_set(pgd, pmd); - return NULL; - } - free_pages((unsigned long)pmd,2); - if (pgd_bad(*pgd)) - BUG(); - return (pmd_t *) pgd_page(*pgd) + offset; -} - -pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - int i; - - pte = (pte_t*) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - for (i=0;i<PTRS_PER_PTE;i++) - pte_clear(pte+i); - pmd_set(pmd,pte); - return pte + offset; - } - pte = (pte_t*) get_bad_pte_table(); - pmd_set(pmd,pte); - return NULL; - } - free_page(__pa(pte)); - if (pmd_bad(*pmd)) - BUG(); - return (pte_t *) pmd_page(*pmd) + offset; -} - int do_check_pgt_cache(int low, int high) { int freed = 0; @@ -169,9 +79,9 @@ if(pgd_quicklist) free_pgd_slow(get_pgd_fast()), freed += 4; if(pmd_quicklist) - free_pmd_slow(get_pmd_fast()), freed += 4; + pmd_free_slow(pmd_alloc_one_fast(NULL, 0)), freed += 4; if(pte_quicklist) - free_pte_slow(get_pte_fast()), freed++; + pte_free_slow(pte_alloc_one_fast(NULL, 0)), freed++; } while(pgtable_cache_size > low); } return freed; @@ -259,34 +169,34 @@ for (i = 0 ; i < PTRS_PER_PGD ; i++,pg_dir++) { if (address >= end_mem) { - pgd_clear(pg_dir); - continue; + pgd_clear(pg_dir); + continue; } pm_dir = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE*4); - pgd_set(pg_dir,pm_dir); + pgd_populate(&init_mm, pg_dir, pm_dir); for (j = 0 ; j < PTRS_PER_PMD ; j++,pm_dir++) { - if (address >= end_mem) { - pmd_clear(pm_dir); - continue; - } - + if (address >= end_mem) { + pmd_clear(pm_dir); + continue; + } + pt_dir = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); - pmd_set(pm_dir,pt_dir); + pmd_populate(&init_mm, pm_dir, pt_dir); for (k = 0 ; k < PTRS_PER_PTE ; k++,pt_dir++) { - pte = mk_pte_phys(address, PAGE_KERNEL); - if (address >= end_mem) { - pte_clear(&pte); - continue; - } - set_pte(pt_dir, pte); - address += PAGE_SIZE; + pte = mk_pte_phys(address, PAGE_KERNEL); + if (address >= end_mem) { + pte_clear(&pte); + continue; + } + set_pte(pt_dir, pte); + address += PAGE_SIZE; } } } - + /* enable virtual mapping in kernel mode */ __asm__ __volatile__("lctlg 1,1,%0\n\t" "lctlg 7,7,%0\n\t" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/mm/ioremap.c linux.ac/arch/s390x/mm/ioremap.c --- linux.vanilla/arch/s390x/mm/ioremap.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/mm/ioremap.c Thu Apr 12 12:00:34 2001 @@ -54,7 +54,7 @@ if (address >= end) BUG(); do { - pte_t * pte = pte_alloc_kernel(pmd, address); + pte_t * pte = pte_alloc(&init_mm, pmd, address); if (!pte) return -ENOMEM; remap_area_pte(pte, address, end - address, address + phys_addr, flags); @@ -67,6 +67,7 @@ static int remap_area_pages(unsigned long address, unsigned long phys_addr, unsigned long size, unsigned long flags) { + int error; pgd_t * dir; unsigned long end = address + size; @@ -75,17 +76,21 @@ flush_cache_all(); if (address >= end) BUG(); + spin_lock(&init_mm.page_table_lock); do { - pmd_t *pmd = pmd_alloc_kernel(dir, address); + pmd_t *pmd; + pmd = pmd_alloc(&init_mm, dir, address); + error = -ENOMEM; if (!pmd) - return -ENOMEM; + break; if (remap_area_pmd(pmd, address, end - address, phys_addr + address, flags)) - return -ENOMEM; - set_pgdir(address, *dir); + break; + error = 0; address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; } while (address && (address < end)); + spin_unlock(&init_mm.page_table_lock); flush_tlb_all(); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/tools/dasdfmt/dasdfmt.8 linux.ac/arch/s390x/tools/dasdfmt/dasdfmt.8 --- linux.vanilla/arch/s390x/tools/dasdfmt/dasdfmt.8 Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/tools/dasdfmt/dasdfmt.8 Mon Apr 9 23:46:07 2001 @@ -1,68 +1,68 @@ -.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 -\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-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 - \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. -The second form uses simply the device number. - -.SH BUGS -None so far ;-) - -.SH AUTHOR -.nf -This man-page was written by Fritz Elfert <felfert@to.com> -.fi +.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 +\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-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 + \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. +The second form uses simply the device number. + +.SH BUGS +None so far ;-) + +.SH AUTHOR +.nf +This man-page was written by Fritz Elfert <felfert@to.com> +.fi diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/tools/dasdfmt/dasdfmt.c linux.ac/arch/s390x/tools/dasdfmt/dasdfmt.c --- linux.vanilla/arch/s390x/tools/dasdfmt/dasdfmt.c Tue Apr 3 17:31:57 2001 +++ linux.ac/arch/s390x/tools/dasdfmt/dasdfmt.c Thu Apr 12 12:00:34 2001 @@ -7,6 +7,7 @@ * Author(s): Utz Bacher, <utz.bacher@de.ibm.com> * * Device-in-use-checks by Fritz Elfert, <felfert@to.com> + * Compatible Disk Layout enhancements by Carsten Otte, <cotte@de.ibm.com> * * Still to do: * detect non-switch parameters ("dasdfmt -n 170 XY") and complain about them @@ -157,14 +158,15 @@ exit_usage(int exitcode) { #ifdef RANGE_FORMATTING - printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] [<range>] " \ + printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] [<range>] " \ "<diskspec>\n\n",prog_name); #else /* RANGE_FORMATTING */ - printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] " \ + printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] " \ "<diskspec>\n\n",prog_name); #endif /* RANGE_FORMATTING */ printf(" -t means testmode\n"); printf(" -v means verbose mode\n"); + printf(" -C means format compatible disk layout\n"); printf(" -V means print version\n"); printf(" -L means don't write disk label\n"); printf(" <label> is a label which is converted to EBCDIC and " \ @@ -200,7 +202,7 @@ /* fgets(line,sizeof(line),file); omit first line */ while (fgets(line,sizeof(line),file)!=NULL) { - rc=sscanf(line,"%X %*[(A-Z)] at (%d:%d)",&d,&ma_i,&mi_i); + rc=sscanf(line,"%X %*[(A-Z) ] at (%d:%d)",&d,&ma_i,&mi_i); ma=ma_i; mi=mi_i; if ( (rc==3) && @@ -218,7 +220,8 @@ fclose(file); ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to find device in the /proc " \ - "filesystem (are you sure to have the right param line?)\n", + "filesystem (are you sure to have the right parameter " \ + "dasd=xxx?)\n", prog_name); } @@ -488,14 +491,14 @@ } check_mounted(major_no, minor_no); + get_xno_from_xno(&devno,&major_no,&minor_no, + GIVEN_MAJOR|GIVEN_MINOR); if ((!writenolabel) && (!labelspec)) { sprintf(label,"LNX1 x%04x",devno); } if ( ((withoutprompt)&&(verbosity>=1)) || (!withoutprompt) ) { - get_xno_from_xno(&devno,&major_no,&minor_no, - GIVEN_MAJOR|GIVEN_MINOR); printf("\nI am going to format the device %s in the " \ "following way:\n",dev_name); printf(" Device number of device : 0x%x\n",devno); @@ -505,6 +508,9 @@ "no":"yes"); if (!writenolabel) printf(" Disk label : %s\n",label); + if (format_params.intensity != DASD_FORMAT_DEFAULT_INTENSITY) + printf(" Compatible Disk Layout : %s\n",(format_params.intensity&0x08)? + "yes":"no"); #ifdef RANGE_FORMATTING printf(" Start track : %d\n" \ ,format_params.start_unit); @@ -558,7 +564,7 @@ } - rc=ioctl(fd,BLKGETSIZE,&new_blksize); + rc=ioctl(fd,BLKSSZGET,&new_blksize); if (rc) { ERRMSG("%s: the ioctl call to get blocksize " \ "returned with the following error " \ @@ -664,9 +670,9 @@ opterr=0; #ifdef RANGE_FORMATTING - while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:hLty?vV")) !=EOF) { + while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:ChLty?vV")) !=EOF) { #endif /* RANGE_FORMATTING */ - while ( (oc=getopt(argc,argv,"b:n:l:f:hLty?vV")) !=EOF) { + while ( (oc=getopt(argc,argv,"b:n:l:f:ChLty?vV")) !=EOF) { switch (oc) { case 'y': withoutprompt=1; @@ -686,6 +692,9 @@ case 'h': exit_usage(0); + case 'C': + format_params.intensity&=0x08; + break; case 'V': printf("%s version 0.99\n",prog_name); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/tools/silo/silo.c linux.ac/arch/s390x/tools/silo/silo.c --- linux.vanilla/arch/s390x/tools/silo/silo.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/tools/silo/silo.c Thu Apr 12 12:00:34 2001 @@ -9,6 +9,9 @@ * Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com> * Fritz Elfert <felfert@to.com> contributed support for * /etc/silo.conf based on Intel's lilo + * Changes : + * 01/15/01 Holger Smolinski <Holger.Smolinski@de.ibm.com> + * adapted to deal with devices and bootsects of various sizes */ #include <stddef.h> @@ -376,7 +379,7 @@ if ( errno == ENOENT ) { ITRY (creat ( o-> bootmap, O_RDWR )); } else { - PRINT_LEVEL(1,"Cannot acces bootmap file '%s': %s\n",o->bootmap, + PRINT_LEVEL(1,"Cannot access bootmap file '%s': %s\n",o->bootmap, strerror(errno)); } } @@ -482,6 +485,7 @@ int bs, boots; char *tmpdev; char buffer[4096]={0,}; + int blocksize, sectsize; ITRY (d_fd = open (o->ipldevice, O_RDWR | O_SYNC)); ITRY (fstat (d_fd, &d_st)); ITRY (s_fd = open (o->bootmap, O_RDWR | O_TRUNC | O_CREAT | O_SYNC)); @@ -508,6 +512,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(bd_fd,BLKSSZGET,&blocksize)); ITRY (ioctl(s_fd,FIBMAP,&boots)); ITRY (ioctl (bd_fd, BIODASDRWTB, &boots)); PRINT_LEVEL (1, "Bootmap is in block no: 0x%08x\n", boots); @@ -515,13 +520,21 @@ close(s_fd); ITRY (unlink(tmpdev)); /* Now patch the bootsector */ + ITRY (stat (o->bootsect, &b_st)); + if ((sectsize = b_st.st_size) > blocksize ) + { + ERROR_LEVEL (0,"Bootsector is larger than sectorsize of volume %d vs %d\n", sectsize, blocksize); + rc = -1; + errno = EINVAL; + } ITRY (b_fd = open (o->bootsect, O_RDONLY)); - NTRY (read (b_fd, buffer, 4096)); + ITRY (read (b_fd, buffer, sectsize)); memset (buffer + 0xe0, 0, 8); *(int *) (buffer + 0xe0) = boots; if ( o -> testlevel <= 0 ) { - NTRY (write (d_fd, buffer, 4096)); - NTRY (write (d_fd, buffer, 4096)); + ITRY (write (d_fd, buffer, sectsize)); + ITRY (lseek (d_fd, blocksize, SEEK_SET)); + ITRY (write (d_fd, buffer, sectsize)); } close (b_fd); close (d_fd); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390x/vmlinux.lds linux.ac/arch/s390x/vmlinux.lds --- linux.vanilla/arch/s390x/vmlinux.lds Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390x/vmlinux.lds Thu Apr 12 12:00:34 2001 @@ -26,6 +26,10 @@ __ksymtab : { *(__ksymtab) } __stop___ksymtab = .; + __start___kallsyms = .; /* All kernel symbols */ + __kallsyms : { *(__kallsyms) } + __stop___kallsyms = .; + _etext = .; /* End of text section */ .data : { /* Data */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/Makefile linux.ac/arch/sh/kernel/Makefile --- linux.vanilla/arch/sh/kernel/Makefile Thu Jan 4 21:19:13 2001 +++ linux.ac/arch/sh/kernel/Makefile Sat Apr 14 01:18:00 2001 @@ -20,16 +20,23 @@ obj-$(CONFIG_CF_ENABLER) += cf-enabler.o obj-$(CONFIG_CPU_SH4) += fpu.o -obj-$(CONFIG_PCI) += pci-sh.o obj-$(CONFIG_SH_RTC) += rtc.o obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o +ifeq ($(CONFIG_PCI),y) +obj-y += pci-sh.o +obj-$(CONFIG_CPU_SUBTYPE_ST40STB1)+= pci_st40.o +endif + obj-$(CONFIG_SH_HP600) += mach_hp600.o machine-specific-objs += mach_hp600.o obj-$(CONFIG_SH_SOLUTION_ENGINE)+= mach_se.o setup_se.o io_se.o led_se.o machine-specific-objs += mach_se.o setup_se.o io_se.o led_se.o +obj-$(CONFIG_SH_CAT68701) += mach_cat68701.o io_cat68701.o +machine-specific-objs += mach_cat68701.o io_cat68701.o + obj-$(CONFIG_SH_CQREEK) += setup_cqreek.o machine-specific-objs += setup_cqreek.o @@ -39,9 +46,13 @@ obj-$(CONFIG_HD64461) += setup_hd64461.o io_hd64461.o machine-specific-objs += setup_hd64461.o io_hd64461.o +obj-$(CONFIG_CPU_SUBTYPE_ST40STB1) +=irq_intc2.o + # Doesn't compile well, so don't include in machine-specific-objs -obj-$(CONFIG_HD64465) += setup_hd64465.o io_hd64465.o -obj-$(CONFIG_SH_FOOBAR) += mach_foobar.o +obj-$(CONFIG_HD64465) += setup_hd64465.o io_hd64465.o hd64465_gpio.o +obj-$(CONFIG_SH_DMIDA) += mach_dmida.o +obj-$(CONFIG_SH_EC3104) += setup_ec3104.o io_ec3104.o mach_ec3104.o +obj-$(CONFIG_SH_DREAMCAST) += mach_dc.o setup_dc.o io_dc.o ifeq ($(CONFIG_SH_GENERIC),y) obj-y += $(machine-specific-objs) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/cf-enabler.c linux.ac/arch/sh/kernel/cf-enabler.c --- linux.vanilla/arch/sh/kernel/cf-enabler.c Thu Aug 10 21:03:25 2000 +++ linux.ac/arch/sh/kernel/cf-enabler.c Sat Apr 14 01:18:00 2001 @@ -8,13 +8,41 @@ * Enable the CF configuration. */ +#include <linux/config.h> #include <linux/init.h> #include <asm/io.h> #include <asm/irq.h> -#include <asm/hitachi_se.h> +#define CF_CIS_BASE 0xb8000000 +/* + * You can connect Compact Flash directly to the bus of SuperH. + * This is the enabler for that. + * + * SIM: How generic is this really? It looks pretty board, or at + * least SH sub-type, specific to me. + * I know it doesn't work on the Overdrive! + */ + +/* + * 0xB8000000 : Attribute + * 0xB8001000 : Common Memory + * 0xBA000000 : I/O + */ +static int __init cf_init_default(void) +{ +#ifdef CONFIG_IDE + /* Enable the card, and set the level interrupt */ + ctrl_outw(0x0042, CF_CIS_BASE+0x0200); +#endif + make_imask_irq(14); + disable_irq(14); + return 0; +} + +#if defined(CONFIG_SH_GENERIC) || defined(CONFIG_SH_SOLUTION_ENGINE) +#include <asm/hitachi_se.h> /* * SolutionEngine @@ -70,37 +98,14 @@ ctrl_outb(0x42, PA_MRSHPC_MW2 + 0x200); return 0; } - -#define CF_CIS_BASE 0xb8000000 -/* - * You can connect Compact Flash directly to the bus of SuperH. - * This is the enabler for that. - * - * SIM: How generic is this really? It looks pretty board, or at - * least SH sub-type, specific to me. - * I know it doesn't work on the Overdrive! - */ - -/* - * 0xB8000000 : Attribute - * 0xB8001000 : Common Memory - * 0xBA000000 : I/O - */ - -static int __init cf_init_default(void) -{ - /* Enable the card, and set the level interrupt */ - ctrl_outw(0x0042, CF_CIS_BASE+0x0200); - make_imask_irq(14); - disable_irq(14); - return 0; -} +#endif int __init cf_init(void) { - if (MACH_SE) { +#if defined(CONFIG_SH_GENERIC) || defined(CONFIG_SH_SOLUTION_ENGINE) + if (MACH_SE) return cf_init_se(); - } +#endif return cf_init_default(); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/entry.S linux.ac/arch/sh/kernel/entry.S --- linux.vanilla/arch/sh/kernel/entry.S Mon Jan 29 02:56:00 2001 +++ linux.ac/arch/sh/kernel/entry.S Sat Apr 14 01:18:22 2001 @@ -182,7 +182,7 @@ jsr @r0 mov r15, r4 ! - tst #0xff, r0 + tst r0, r0 bf/s 0f lds r10, pr rts @@ -550,10 +550,10 @@ ret_with_reschedule: stc k_current, r1 mov.l @(need_resched,r1), r0 - tst #0xff, r0 + tst r0, r0 bf reschedule mov.l @(sigpending,r1), r0 - tst #0xff, r0 + tst r0, r0 bt restore_all signal_return: mov r15, r4 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/hd64465_gpio.c linux.ac/arch/sh/kernel/hd64465_gpio.c --- linux.vanilla/arch/sh/kernel/hd64465_gpio.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/sh/kernel/hd64465_gpio.c Sat Apr 14 01:18:22 2001 @@ -0,0 +1,185 @@ +/* + * $Id: hd64465_gpio.c,v 1.1 2001/01/02 15:35:22 mjd Exp $ + * by Greg Banks <gbanks@pocketpenguins.com> + * (c) 2000 PocketPenguins Inc + * + * GPIO pin support for HD64465 companion chip. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/ioport.h> +#include <asm/io.h> +#include <asm/hd64465_gpio.h> + +#define _PORTOF(portpin) (((portpin)>>3)&0x7) +#define _PINOF(portpin) ((portpin)&0x7) + +/* Register addresses parametrised on port */ +#define GPIO_CR(port) (HD64465_REG_GPACR+((port)<<1)) +#define GPIO_DR(port) (HD64465_REG_GPADR+((port)<<1)) +#define GPIO_ICR(port) (HD64465_REG_GPAICR+((port)<<1)) +#define GPIO_ISR(port) (HD64465_REG_GPAISR+((port)<<1)) + +#define GPIO_NPORTS 5 + +#define MODNAME "hd64465_gpio" + +EXPORT_SYMBOL(hd64465_gpio_configure); +EXPORT_SYMBOL(hd64465_gpio_get_pin); +EXPORT_SYMBOL(hd64465_gpio_get_port); +EXPORT_SYMBOL(hd64465_gpio_register_irq); +EXPORT_SYMBOL(hd64465_gpio_set_pin); +EXPORT_SYMBOL(hd64465_gpio_set_port); +EXPORT_SYMBOL(hd64465_gpio_unregister_irq); + +/* TODO: each port should be protected with a spinlock */ + + +void hd64465_gpio_configure(int portpin, int direction) +{ + unsigned short cr; + unsigned int shift = (_PINOF(portpin)<<1); + + cr = inw(GPIO_CR(_PORTOF(portpin))); + cr &= ~(3<<shift); + cr |= direction<<shift; + outw(cr, GPIO_CR(_PORTOF(portpin))); +} + +void hd64465_gpio_set_pin(int portpin, unsigned int value) +{ + unsigned short d; + unsigned short mask = 1<<(_PINOF(portpin)); + + d = inw(GPIO_DR(_PORTOF(portpin))); + if (value) + d |= mask; + else + d &= ~mask; + outw(d, GPIO_DR(_PORTOF(portpin))); +} + +unsigned int hd64465_gpio_get_pin(int portpin) +{ + return inw(GPIO_DR(_PORTOF(portpin))) & (1<<(_PINOF(portpin))); +} + +/* TODO: for cleaner atomicity semantics, add a mask to this routine */ + +void hd64465_gpio_set_port(int port, unsigned int value) +{ + outw(value, GPIO_DR(port)); +} + +unsigned int hd64465_gpio_get_port(int port) +{ + return inw(GPIO_DR(port)); +} + + +static struct { + void (*func)(int portpin, void *dev); + void *dev; +} handlers[GPIO_NPORTS * 8]; + +static void hd64465_gpio_interrupt(int irq, void *dev, struct pt_regs *regs) +{ + unsigned short port, pin, isr, mask, portpin; + + for (port=0 ; port<GPIO_NPORTS ; port++) { + isr = inw(GPIO_ISR(port)); + + for (pin=0 ; pin<8 ; pin++) { + mask = 1<<pin; + if (isr & mask) { + portpin = (port<<3)|pin; + if (handlers[portpin].func != 0) + handlers[portpin].func(portpin, handlers[portpin].dev); + else + printk(KERN_NOTICE "unexpected GPIO interrupt, pin %c%d\n", + port+'A', (int)pin); + } + } + + /* Write 1s back to ISR to clear it? That's what the manual says.. */ + outw(isr, GPIO_ISR(port)); + } +} + +void hd64465_gpio_register_irq(int portpin, int mode, + void (*handler)(int portpin, void *dev), void *dev) +{ + unsigned long flags; + unsigned short icr, mask; + + if (handler == 0) + return; + + save_and_cli(flags); + + handlers[portpin].func = handler; + handlers[portpin].dev = dev; + + /* + * Configure Interrupt Control Register + */ + icr = inw(GPIO_ICR(_PORTOF(portpin))); + mask = (1<<_PINOF(portpin)); + + /* unmask interrupt */ + icr &= ~mask; + + /* set TS bit */ + mask <<= 8; + icr &= ~mask; + if (mode == HD64465_GPIO_RISING) + icr |= mask; + + outw(icr, GPIO_ICR(_PORTOF(portpin))); + + restore_flags(flags); +} + +void hd64465_gpio_unregister_irq(int portpin) +{ + unsigned long flags; + unsigned short icr; + + save_and_cli(flags); + + /* + * Configure Interrupt Control Register + */ + icr = inw(GPIO_ICR(_PORTOF(portpin))); + icr |= (1<<_PINOF(portpin)); /* mask interrupt */ + outw(icr, GPIO_ICR(_PORTOF(portpin))); + + handlers[portpin].func = 0; + handlers[portpin].dev = 0; + + restore_flags(flags); +} + +static int __init hd64465_gpio_init(void) +{ + /* TODO: check return values */ + request_region(HD64465_REG_GPACR, 0x1000, MODNAME); + request_irq(HD64465_IRQ_GPIO, hd64465_gpio_interrupt, + SA_INTERRUPT, MODNAME, 0); + + printk("HD64465 GPIO layer on irq %d\n", HD64465_IRQ_GPIO); + return 0; +} + +static void __exit hd64465_gpio_exit(void) +{ + release_region(HD64465_REG_GPACR, 0x1000); + free_irq(HD64465_IRQ_GPIO, 0); +} + +module_init(hd64465_gpio_init); +module_exit(hd64465_gpio_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/io.c linux.ac/arch/sh/kernel/io.c --- linux.vanilla/arch/sh/kernel/io.c Mon Oct 2 19:57:34 2000 +++ linux.ac/arch/sh/kernel/io.c Sat Apr 14 01:18:22 2001 @@ -8,123 +8,149 @@ */ #include <asm/io.h> +#include <linux/module.h> -unsigned int _inb(unsigned long port) +unsigned char _inb(unsigned long port) { return __inb(port); } +EXPORT_SYMBOL(_inb); -unsigned int _inw(unsigned long port) +unsigned short _inw(unsigned long port) { return __inw(port); } +EXPORT_SYMBOL(_inw); unsigned int _inl(unsigned long port) { return __inl(port); } +EXPORT_SYMBOL(_inl); void _outb(unsigned char b, unsigned long port) { __outb(b, port); } +EXPORT_SYMBOL(_outb); void _outw(unsigned short b, unsigned long port) { __outw(b, port); } +EXPORT_SYMBOL(_outw); + void _outl(unsigned int b, unsigned long port) { __outl(b, port); } +EXPORT_SYMBOL(_outl); + -unsigned int _inb_p(unsigned long port) +unsigned char _inb_p(unsigned long port) { return __inb_p(port); } +EXPORT_SYMBOL(_inb_p); -unsigned int _inw_p(unsigned long port) +unsigned short _inw_p(unsigned long port) { return __inw_p(port); } +EXPORT_SYMBOL(_inw_p); + void _outb_p(unsigned char b, unsigned long port) { __outb_p(b, port); } +EXPORT_SYMBOL(_outb_p); void _outw_p(unsigned short b, unsigned long port) { __outw_p(b, port); } +EXPORT_SYMBOL(_outw_p); void _insb(unsigned long port, void *buffer, unsigned long count) { return __insb(port, buffer, count); } +EXPORT_SYMBOL(_insb); void _insw(unsigned long port, void *buffer, unsigned long count) { __insw(port, buffer, count); } +EXPORT_SYMBOL(_insw); void _insl(unsigned long port, void *buffer, unsigned long count) { __insl(port, buffer, count); } +EXPORT_SYMBOL(_insl); void _outsb(unsigned long port, const void *buffer, unsigned long count) { __outsb(port, buffer, count); } +EXPORT_SYMBOL(_outsb); void _outsw(unsigned long port, const void *buffer, unsigned long count) { __outsw(port, buffer, count); } +EXPORT_SYMBOL(_outsw); void _outsl(unsigned long port, const void *buffer, unsigned long count) { __outsl(port, buffer, count); } +EXPORT_SYMBOL(_outsl); -unsigned long ___raw_readb(unsigned long addr) +unsigned char ___raw_readb(unsigned long addr) { return __readb(addr); } +EXPORT_SYMBOL(___raw_readb); -unsigned long ___raw_readw(unsigned long addr) +unsigned short ___raw_readw(unsigned long addr) { return __readw(addr); } +EXPORT_SYMBOL(___raw_readw); -unsigned long ___raw_readl(unsigned long addr) +unsigned int ___raw_readl(unsigned long addr) { return __readl(addr); } +EXPORT_SYMBOL(___raw_readl); -unsigned long _readb(unsigned long addr) +unsigned char _readb(unsigned long addr) { unsigned long r = __readb(addr); mb(); return r; } +EXPORT_SYMBOL(_readb); -unsigned long _readw(unsigned long addr) +unsigned short _readw(unsigned long addr) { unsigned long r = __readw(addr); mb(); return r; } +EXPORT_SYMBOL(_readw); -unsigned long _readl(unsigned long addr) +unsigned int _readl(unsigned long addr) { unsigned long r = __readl(addr); mb(); return r; } +EXPORT_SYMBOL(_readl); void ___raw_writeb(unsigned char b, unsigned long addr) { @@ -135,29 +161,34 @@ { __writew(b, addr); } +EXPORT_SYMBOL(___raw_writew); void ___raw_writel(unsigned int b, unsigned long addr) { __writel(b, addr); } +EXPORT_SYMBOL(___raw_writel); void _writeb(unsigned char b, unsigned long addr) { __writeb(b, addr); mb(); } +EXPORT_SYMBOL(_writeb); void _writew(unsigned short b, unsigned long addr) { __writew(b, addr); mb(); } +EXPORT_SYMBOL(_writew); void _writel(unsigned int b, unsigned long addr) { __writel(b, addr); mb(); } +EXPORT_SYMBOL(_writel); /* * Copy data from IO memory space to "real" memory space. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/io_cat68701.c linux.ac/arch/sh/kernel/io_cat68701.c --- linux.vanilla/arch/sh/kernel/io_cat68701.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/sh/kernel/io_cat68701.c Sat Apr 14 01:18:22 2001 @@ -0,0 +1,248 @@ +/* + * linux/arch/sh/kernel/io_cat68701.c + * + * Copyright (C) 2000 Niibe Yutaka + * 2001 Yutaro Ebihara + * + * I/O routine and setup routines for A-ONE Corp CAT-68701 SH7708 Board + * + * 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 <asm/io.h> +#include <asm/machvec.h> +#include <linux/module.h> + +#define SH3_PCMCIA_BUG_WORKAROUND 1 +#define DUMMY_READ_AREA6 0xba000000 + +#define PORT2ADDR(x) (cat68701_isa_port2addr(x)) + +static inline void delay(void) +{ + ctrl_inw(0xa0000000); +} + +unsigned char cat68701_inb(unsigned long port) +{ + return *(volatile unsigned char*)PORT2ADDR(port); +} + +unsigned short cat68701_inw(unsigned long port) +{ + return *(volatile unsigned short*)PORT2ADDR(port); +} + +unsigned int cat68701_inl(unsigned long port) +{ + return *(volatile unsigned long*)PORT2ADDR(port); +} + +unsigned char cat68701_inb_p(unsigned long port) +{ + unsigned long v = *(volatile unsigned char*)PORT2ADDR(port); + + delay(); + return v; +} + +unsigned short cat68701_inw_p(unsigned long port) +{ + unsigned long v = *(volatile unsigned short*)PORT2ADDR(port); + + delay(); + return v; +} + +unsigned int cat68701_inl_p(unsigned long port) +{ + unsigned long v = *(volatile unsigned long*)PORT2ADDR(port); + + delay(); + return v; +} + +void cat68701_insb(unsigned long port, void *buffer, unsigned long count) +{ + unsigned char *buf=buffer; + while(count--) *buf++=inb(port); +} + +void cat68701_insw(unsigned long port, void *buffer, unsigned long count) +{ + unsigned short *buf=buffer; + while(count--) *buf++=inw(port); +#ifdef SH3_PCMCIA_BUG_WORKAROUND + ctrl_inb (DUMMY_READ_AREA6); +#endif +} + +void cat68701_insl(unsigned long port, void *buffer, unsigned long count) +{ + unsigned long *buf=buffer; + while(count--) *buf++=inl(port); +#ifdef SH3_PCMCIA_BUG_WORKAROUND + ctrl_inb (DUMMY_READ_AREA6); +#endif +} + +void cat68701_outb(unsigned char b, unsigned long port) +{ + *(volatile unsigned char*)PORT2ADDR(port) = b; +} + +void cat68701_outw(unsigned short b, unsigned long port) +{ + *(volatile unsigned short*)PORT2ADDR(port) = b; +} + +void cat68701_outl(unsigned int b, unsigned long port) +{ + *(volatile unsigned long*)PORT2ADDR(port) = b; +} + +void cat68701_outb_p(unsigned char b, unsigned long port) +{ + *(volatile unsigned char*)PORT2ADDR(port) = b; + delay(); +} + +void cat68701_outw_p(unsigned short b, unsigned long port) +{ + *(volatile unsigned short*)PORT2ADDR(port) = b; + delay(); +} + +void cat68701_outl_p(unsigned int b, unsigned long port) +{ + *(volatile unsigned long*)PORT2ADDR(port) = b; + delay(); +} + +void cat68701_outsb(unsigned long port, const void *buffer, unsigned long count) +{ + const unsigned char *buf=buffer; + while(count--) outb(*buf++, port); +} + +void cat68701_outsw(unsigned long port, const void *buffer, unsigned long count) +{ + const unsigned short *buf=buffer; + while(count--) outw(*buf++, port); +#ifdef SH3_PCMCIA_BUG_WORKAROUND + ctrl_inb (DUMMY_READ_AREA6); +#endif +} + +void cat68701_outsl(unsigned long port, const void *buffer, unsigned long count) +{ + const unsigned long *buf=buffer; + while(count--) outl(*buf++, port); +#ifdef SH3_PCMCIA_BUG_WORKAROUND + ctrl_inb (DUMMY_READ_AREA6); +#endif +} + +unsigned char cat68701_readb(unsigned long addr) +{ + return *(volatile unsigned char*)addr; +} + +unsigned short cat68701_readw(unsigned long addr) +{ + return *(volatile unsigned short*)addr; +} + +unsigned int cat68701_readl(unsigned long addr) +{ + return *(volatile unsigned long*)addr; +} + +void cat68701_writeb(unsigned char b, unsigned long addr) +{ + *(volatile unsigned char*)addr = b; +} + +void cat68701_writew(unsigned short b, unsigned long addr) +{ + *(volatile unsigned short*)addr = b; +} + +void cat68701_writel(unsigned int b, unsigned long addr) +{ + *(volatile unsigned long*)addr = b; +} + +void * cat68701_ioremap(unsigned long offset, unsigned long size) +{ + return (void *) P2SEGADDR(offset); +} +EXPORT_SYMBOL(cat68701_ioremap); + +void cat68701_iounmap(void *addr) +{ +} +EXPORT_SYMBOL(cat68701_iounmap); + +unsigned long cat68701_isa_port2addr(unsigned long offset) +{ + /* CompactFlash (IDE) */ + if(((offset >= 0x1f0) && (offset <= 0x1f7)) || (offset==0x3f6)) + return 0xba000000 + offset; + + /* INPUT PORT */ + if((offset >= 0x3fc) && (offset <= 0x3fd)) + return 0xb4007000 + offset; + + /* OUTPUT PORT */ + if((offset >= 0x3fe) && (offset <= 0x3ff)) + return 0xb4007400 + offset; + + return offset + 0xb4000000; /* other I/O (EREA 5)*/ +} + + +int cat68701_irq_demux(int irq) +{ + if(irq==13) return 14; + if(irq==7) return 10; + return irq; +} + + + +/*-------------------------------------------------------*/ + +void setup_cat68701(){ + /* dummy read erea5 (CS8900A) */ +} + +void init_cat68701_IRQ(){ + make_imask_irq(10); + make_imask_irq(14); +} + +#ifdef CONFIG_HEARTBEAT +#include <linux/sched.h> +void heartbeat_cat68701() +{ + static unsigned int cnt = 0, period = 0 , bit = 0; + cnt += 1; + if (cnt < period) { + return; + } + cnt = 0; + + /* Go through the points (roughly!): + * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110 + */ + period = 110 - ( (300<<FSHIFT)/ + ((avenrun[0]/5) + (3<<FSHIFT)) ); + + if(bit){ bit=0; }else{ bit=1; } + outw(bit<<15,0x3fe); +} +#endif /* CONFIG_HEARTBEAT */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/io_dc.c linux.ac/arch/sh/kernel/io_dc.c --- linux.vanilla/arch/sh/kernel/io_dc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/sh/kernel/io_dc.c Sat Apr 14 01:18:22 2001 @@ -0,0 +1,13 @@ +/* + * $Id: io_dc.c,v 1.1 2001/04/01 15:02:00 yaegashi Exp $ + * I/O routines for SEGA Dreamcast + */ + +#include <linux/config.h> +#include <asm/io.h> +#include <asm/machvec.h> + +unsigned long dreamcast_isa_port2addr(unsigned long offset) +{ + return offset + 0xa0000000; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/io_ec3104.c linux.ac/arch/sh/kernel/io_ec3104.c --- linux.vanilla/arch/sh/kernel/io_ec3104.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/sh/kernel/io_ec3104.c Sat Apr 14 01:18:22 2001 @@ -0,0 +1,83 @@ +/* + * linux/arch/sh/kernel/io_ec3104.c + * EC3104 companion chip support + * + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> + * + */ +/* EC3104 note: + * This code was written without any documentation about the EC3104 chip. While + * I hope I got most of the basic functionality right, the register names I use + * are most likely completely different from those in the chip documentation. + * + * If you have any further information about the EC3104, please tell me + * (prumpf@tux.org). + */ + + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <asm/io.h> +#include <asm/page.h> +#include <asm/ec3104.h> + +/* + * EC3104 has a real ISA bus which we redirect low port accesses to (the + * actual device on mine is a ESS 1868, and I don't want to hack the driver + * more than strictly necessary). I am not going to duplicate the + * hard coding of PC addresses (for the 16550s aso) here though; it's just + * too ugly. + */ + +#define low_port(port) ((port) < 0x10000) + +static inline unsigned long port2addr(unsigned long port) +{ + switch(port >> 16) { + case 0: + return EC3104_ISA_BASE + port * 2; + + /* XXX hack. it's unclear what to do about the serial ports */ + case 1: + return EC3104_BASE + (port&0xffff) * 4; + + default: + /* XXX PCMCIA */ + return 0; + } +} + +unsigned char ec3104_inb(unsigned long port) +{ + u8 ret; + + ret = *(volatile u8 *)port2addr(port); + + return ret; +} + +unsigned short ec3104_inw(unsigned long port) +{ + BUG(); +} + +unsigned long ec3104_inl(unsigned long port) +{ + BUG(); +} + +void ec3104_outb(unsigned char data, unsigned long port) +{ + *(volatile u8 *)port2addr(port) = data; +} + +void ec3104_outw(unsigned short data, unsigned long port) +{ + BUG(); +} + +void ec3104_outl(unsigned long data, unsigned long port) +{ + BUG(); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/io_generic.c linux.ac/arch/sh/kernel/io_generic.c --- linux.vanilla/arch/sh/kernel/io_generic.c Thu Aug 10 21:03:25 2000 +++ linux.ac/arch/sh/kernel/io_generic.c Sat Apr 14 01:18:22 2001 @@ -15,6 +15,7 @@ #include <asm/io.h> #include <asm/machvec.h> +#include <linux/module.h> #if defined(__sh3__) /* I'm not sure SH7709 has this kind of bug */ @@ -31,22 +32,22 @@ ctrl_inw(0xa0000000); } -unsigned long generic_inb(unsigned int port) +unsigned char generic_inb(unsigned long port) { return *(volatile unsigned char*)PORT2ADDR(port); } -unsigned long generic_inw(unsigned int port) +unsigned short generic_inw(unsigned long port) { return *(volatile unsigned short*)PORT2ADDR(port); } -unsigned long generic_inl(unsigned int port) +unsigned int generic_inl(unsigned long port) { return *(volatile unsigned long*)PORT2ADDR(port); } -unsigned long generic_inb_p(unsigned int port) +unsigned char generic_inb_p(unsigned long port) { unsigned long v = *(volatile unsigned char*)PORT2ADDR(port); @@ -54,7 +55,7 @@ return v; } -unsigned long generic_inw_p(unsigned int port) +unsigned short generic_inw_p(unsigned long port) { unsigned long v = *(volatile unsigned short*)PORT2ADDR(port); @@ -62,7 +63,7 @@ return v; } -unsigned long generic_inl_p(unsigned int port) +unsigned int generic_inl_p(unsigned long port) { unsigned long v = *(volatile unsigned long*)PORT2ADDR(port); @@ -70,13 +71,13 @@ return v; } -void generic_insb(unsigned int port, void *buffer, unsigned long count) +void generic_insb(unsigned long port, void *buffer, unsigned long count) { unsigned char *buf=buffer; while(count--) *buf++=inb(port); } -void generic_insw(unsigned int port, void *buffer, unsigned long count) +void generic_insw(unsigned long port, void *buffer, unsigned long count) { unsigned short *buf=buffer; while(count--) *buf++=inw(port); @@ -85,7 +86,7 @@ #endif } -void generic_insl(unsigned int port, void *buffer, unsigned long count) +void generic_insl(unsigned long port, void *buffer, unsigned long count) { unsigned long *buf=buffer; while(count--) *buf++=inl(port); @@ -94,46 +95,46 @@ #endif } -void generic_outb(unsigned long b, unsigned int port) +void generic_outb(unsigned char b, unsigned long port) { *(volatile unsigned char*)PORT2ADDR(port) = b; } -void generic_outw(unsigned long b, unsigned int port) +void generic_outw(unsigned short b, unsigned long port) { *(volatile unsigned short*)PORT2ADDR(port) = b; } -void generic_outl(unsigned long b, unsigned int port) +void generic_outl(unsigned int b, unsigned long port) { *(volatile unsigned long*)PORT2ADDR(port) = b; } -void generic_outb_p(unsigned long b, unsigned int port) +void generic_outb_p(unsigned char b, unsigned long port) { *(volatile unsigned char*)PORT2ADDR(port) = b; delay(); } -void generic_outw_p(unsigned long b, unsigned int port) +void generic_outw_p(unsigned short b, unsigned long port) { *(volatile unsigned short*)PORT2ADDR(port) = b; delay(); } -void generic_outl_p(unsigned long b, unsigned int port) +void generic_outl_p(unsigned int b, unsigned long port) { *(volatile unsigned long*)PORT2ADDR(port) = b; delay(); } -void generic_outsb(unsigned int port, const void *buffer, unsigned long count) +void generic_outsb(unsigned long port, const void *buffer, unsigned long count) { const unsigned char *buf=buffer; while(count--) outb(*buf++, port); } -void generic_outsw(unsigned int port, const void *buffer, unsigned long count) +void generic_outsw(unsigned long port, const void *buffer, unsigned long count) { const unsigned short *buf=buffer; while(count--) outw(*buf++, port); @@ -142,7 +143,7 @@ #endif } -void generic_outsl(unsigned int port, const void *buffer, unsigned long count) +void generic_outsl(unsigned long port, const void *buffer, unsigned long count) { const unsigned long *buf=buffer; while(count--) outl(*buf++, port); @@ -151,17 +152,17 @@ #endif } -unsigned long generic_readb(unsigned long addr) +unsigned char generic_readb(unsigned long addr) { return *(volatile unsigned char*)addr; } -unsigned long generic_readw(unsigned long addr) +unsigned short generic_readw(unsigned long addr) { return *(volatile unsigned short*)addr; } -unsigned long generic_readl(unsigned long addr) +unsigned int generic_readl(unsigned long addr) { return *(volatile unsigned long*)addr; } @@ -185,15 +186,12 @@ { return (void *) P2SEGADDR(offset); } - -void * generic_ioremap_nocache (unsigned long offset, unsigned long size) -{ - return (void *) P2SEGADDR(offset); -} +EXPORT_SYMBOL(generic_ioremap); void generic_iounmap(void *addr) { } +EXPORT_SYMBOL(generic_iounmap); unsigned long generic_isa_port2addr(unsigned long offset) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/io_hd64461.c linux.ac/arch/sh/kernel/io_hd64461.c --- linux.vanilla/arch/sh/kernel/io_hd64461.c Wed Aug 9 21:59:04 2000 +++ linux.ac/arch/sh/kernel/io_hd64461.c Sat Apr 14 01:18:22 2001 @@ -27,6 +27,12 @@ detail of CF's memory mapped addressing. */ if (0x1f0<=port && port<=0x1f7) return 0xb5000000 + port; if (port == 0x3f6) return 0xb50001fe; + if (port == 0x3f7) return 0xb50001ff; + + /* ide1 */ + if (0x170<=port && port<=0x177) return 0xba000000 + port; + if (port == 0x376) return 0xba000376; + if (port == 0x377) return 0xba000377; #endif /* ??? */ @@ -50,80 +56,80 @@ ctrl_inw(0xa0000000); } -unsigned long hd64461_inb(unsigned int port) +unsigned char hd64461_inb(unsigned long port) { return *(volatile unsigned char*)PORT2ADDR(port); } -unsigned long hd64461_inb_p(unsigned int port) +unsigned char hd64461_inb_p(unsigned long port) { unsigned long v = *(volatile unsigned char*)PORT2ADDR(port); delay(); return v; } -unsigned long hd64461_inw(unsigned int port) +unsigned short hd64461_inw(unsigned long port) { return *(volatile unsigned short*)PORT2ADDR(port); } -unsigned long hd64461_inl(unsigned int port) +unsigned int hd64461_inl(unsigned long port) { return *(volatile unsigned long*)PORT2ADDR(port); } -void hd64461_insb(unsigned int port, void *buffer, unsigned long count) +void hd64461_insb(unsigned long port, void *buffer, unsigned long count) { unsigned char *buf=buffer; while(count--) *buf++=inb(port); } -void hd64461_insw(unsigned int port, void *buffer, unsigned long count) +void hd64461_insw(unsigned long port, void *buffer, unsigned long count) { unsigned short *buf=buffer; while(count--) *buf++=inw(port); } -void hd64461_insl(unsigned int port, void *buffer, unsigned long count) +void hd64461_insl(unsigned long port, void *buffer, unsigned long count) { unsigned long *buf=buffer; while(count--) *buf++=inl(port); } -void hd64461_outb(unsigned long b, unsigned int port) +void hd64461_outb(unsigned char b, unsigned long port) { *(volatile unsigned char*)PORT2ADDR(port) = b; } -void hd64461_outb_p(unsigned long b, unsigned int port) +void hd64461_outb_p(unsigned char b, unsigned long port) { *(volatile unsigned char*)PORT2ADDR(port) = b; delay(); } -void hd64461_outw(unsigned long b, unsigned int port) +void hd64461_outw(unsigned short b, unsigned long port) { *(volatile unsigned short*)PORT2ADDR(port) = b; } -void hd64461_outl(unsigned long b, unsigned int port) +void hd64461_outl(unsigned int b, unsigned long port) { *(volatile unsigned long*)PORT2ADDR(port) = b; } -void hd64461_outsb(unsigned int port, const void *buffer, unsigned long count) +void hd64461_outsb(unsigned long port, const void *buffer, unsigned long count) { const unsigned char *buf=buffer; while(count--) outb(*buf++, port); } -void hd64461_outsw(unsigned int port, const void *buffer, unsigned long count) +void hd64461_outsw(unsigned long port, const void *buffer, unsigned long count) { const unsigned short *buf=buffer; while(count--) outw(*buf++, port); } -void hd64461_outsl(unsigned int port, const void *buffer, unsigned long count) +void hd64461_outsl(unsigned long port, const void *buffer, unsigned long count) { const unsigned long *buf=buffer; while(count--) outl(*buf++, port); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/io_hd64465.c linux.ac/arch/sh/kernel/io_hd64465.c --- linux.vanilla/arch/sh/kernel/io_hd64465.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/sh/kernel/io_hd64465.c Sat Apr 14 01:18:22 2001 @@ -0,0 +1,249 @@ +/* + * $Id: io_hd64465.c,v 1.6 2001/02/15 09:13:51 dave_mckay Exp $ + * by Greg Banks <gbanks@pocketpenguins.com> + * (c) 2000 PocketPenguins Inc + * + * Derived from io_hd64461.c, which bore the message: + * Copyright (C) 2000 YAEGASHI Takeshi + * + * Typical I/O routines for HD64465 system. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <asm/io.h> +#include <asm/hd64465.h> + + +#define HD64465_DEBUG 0 + +#if HD64465_DEBUG +#define DPRINTK(args...) printk(args) +#define DIPRINTK(n, args...) if (hd64465_io_debug>(n)) printk(args) +#else +#define DPRINTK(args...) +#define DIPRINTK(n, args...) +#endif + + + +/* This is a hack suitable only for debugging IO port problems */ +int hd64465_io_debug; +EXPORT_SYMBOL(hd64465_io_debug); + +/* Low iomap maps port 0-1K to addresses in 8byte chunks */ +#define HD64465_IOMAP_LO_THRESH 0x400 +#define HD64465_IOMAP_LO_SHIFT 3 +#define HD64465_IOMAP_LO_MASK ((1<<HD64465_IOMAP_LO_SHIFT)-1) +#define HD64465_IOMAP_LO_NMAP (HD64465_IOMAP_LO_THRESH>>HD64465_IOMAP_LO_SHIFT) +static unsigned long hd64465_iomap_lo[HD64465_IOMAP_LO_NMAP]; +static unsigned char hd64465_iomap_lo_shift[HD64465_IOMAP_LO_NMAP]; + +/* High iomap maps port 1K-64K to addresses in 1K chunks */ +#define HD64465_IOMAP_HI_THRESH 0x10000 +#define HD64465_IOMAP_HI_SHIFT 10 +#define HD64465_IOMAP_HI_MASK ((1<<HD64465_IOMAP_HI_SHIFT)-1) +#define HD64465_IOMAP_HI_NMAP (HD64465_IOMAP_HI_THRESH>>HD64465_IOMAP_HI_SHIFT) +static unsigned long hd64465_iomap_hi[HD64465_IOMAP_HI_NMAP]; +static unsigned char hd64465_iomap_hi_shift[HD64465_IOMAP_HI_NMAP]; + +#ifndef MAX +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif + +void hd64465_port_map(unsigned short baseport, unsigned int nports, + unsigned long addr, unsigned char shift) +{ + unsigned int port, endport = baseport + nports; + + DPRINTK("hd64465_port_map(base=0x%04hx, n=0x%04hx, addr=0x%08lx,endport=0x%04x)\n", + baseport, nports, addr,endport); + + for (port = baseport ; + port < endport && port < HD64465_IOMAP_LO_THRESH ; + port += (1<<HD64465_IOMAP_LO_SHIFT)) { + DPRINTK(" maplo[0x%x] = 0x%08lx\n", port, addr); + hd64465_iomap_lo[port>>HD64465_IOMAP_LO_SHIFT] = addr; + hd64465_iomap_lo_shift[port>>HD64465_IOMAP_LO_SHIFT] = shift; + addr += (1<<(HD64465_IOMAP_LO_SHIFT)); + } + + for (port = MAX(baseport, HD64465_IOMAP_LO_THRESH) ; + port < endport && port < HD64465_IOMAP_HI_THRESH ; + port += (1<<HD64465_IOMAP_HI_SHIFT)) { + DPRINTK(" maphi[0x%x] = 0x%08lx\n", port, addr); + hd64465_iomap_hi[port>>HD64465_IOMAP_HI_SHIFT] = addr; + hd64465_iomap_hi_shift[port>>HD64465_IOMAP_HI_SHIFT] = shift; + addr += (1<<(HD64465_IOMAP_HI_SHIFT)); + } +} +EXPORT_SYMBOL(hd64465_port_map); + +void hd64465_port_unmap(unsigned short baseport, unsigned int nports) +{ + unsigned int port, endport = baseport + nports; + + DPRINTK("hd64465_port_unmap(base=0x%04hx, n=0x%04hx)\n", + baseport, nports); + + for (port = baseport ; + port < endport && port < HD64465_IOMAP_LO_THRESH ; + port += (1<<HD64465_IOMAP_LO_SHIFT)) { + hd64465_iomap_lo[port>>HD64465_IOMAP_LO_SHIFT] = 0; + } + + for (port = MAX(baseport, HD64465_IOMAP_LO_THRESH) ; + port < endport && port < HD64465_IOMAP_HI_THRESH ; + port += (1<<HD64465_IOMAP_HI_SHIFT)) { + hd64465_iomap_hi[port>>HD64465_IOMAP_HI_SHIFT] = 0; + } +} +EXPORT_SYMBOL(hd64465_port_unmap); + +static /*__inline__*/ unsigned long PORT2ADDR(unsigned long port) +{ + unsigned long addr = 0; + unsigned char shift; + + /* handle remapping of low IO ports */ + if (port < HD64465_IOMAP_LO_THRESH) { + addr = hd64465_iomap_lo[port >> HD64465_IOMAP_LO_SHIFT]; + shift = hd64465_iomap_lo_shift[port >> HD64465_IOMAP_LO_SHIFT]; + if (addr != 0) + addr += (port & HD64465_IOMAP_LO_MASK) << shift; + else + printk(KERN_NOTICE "io_hd64465: access to un-mapped port %lx\n", port); + } else if (port < HD64465_IOMAP_HI_THRESH) { + addr = hd64465_iomap_hi[port >> HD64465_IOMAP_HI_SHIFT]; + shift = hd64465_iomap_hi_shift[port >> HD64465_IOMAP_HI_SHIFT]; + if (addr != 0) + addr += (port & HD64465_IOMAP_HI_MASK) << shift; + else + printk(KERN_NOTICE "io_hd64465: access to un-mapped port %lx\n", port); + } + + /* HD64465 internal devices (0xb0000000) */ + else if (port < 0x20000) + addr = CONFIG_HD64465_IOBASE + port - 0x10000; + + /* Whole physical address space (0xa0000000) */ + else + addr = P2SEGADDR(port); + + DIPRINTK(2, "PORT2ADDR(0x%08lx) = 0x%08lx\n", port, addr); + + return addr; +} + +static inline void delay(void) +{ + ctrl_inw(0xa0000000); +} + +unsigned char hd64465_inb(unsigned long port) +{ + unsigned long addr = PORT2ADDR(port); + unsigned long b = (addr == 0 ? 0 : *(volatile unsigned char*)addr); + + DIPRINTK(0, "inb(%08lx) = %02x\n", addr, (unsigned)b); + return b; +} + +unsigned char hd64465_inb_p(unsigned long port) +{ + unsigned long v; + unsigned long addr = PORT2ADDR(port); + + v = (addr == 0 ? 0 : *(volatile unsigned char*)addr); + delay(); + DIPRINTK(0, "inb_p(%08lx) = %02x\n", addr, (unsigned)v); + return v; +} + +unsigned short hd64465_inw(unsigned long port) +{ + unsigned long addr = PORT2ADDR(port); + unsigned long b = (addr == 0 ? 0 : *(volatile unsigned short*)addr); + DIPRINTK(0, "inw(%08lx) = %04lx\n", addr, b); + return b; +} + +unsigned int hd64465_inl(unsigned long port) +{ + unsigned long addr = PORT2ADDR(port); + unsigned int b = (addr == 0 ? 0 : *(volatile unsigned long*)addr); + DIPRINTK(0, "inl(%08lx) = %08x\n", addr, b); + return b; +} + +void hd64465_insb(unsigned long port, void *buffer, unsigned long count) +{ + unsigned char *buf=buffer; + while(count--) *buf++=inb(port); +} + +void hd64465_insw(unsigned long port, void *buffer, unsigned long count) +{ + unsigned short *buf=buffer; + while(count--) *buf++=inw(port); +} + +void hd64465_insl(unsigned long port, void *buffer, unsigned long count) +{ + unsigned long *buf=buffer; + while(count--) *buf++=inl(port); +} + +void hd64465_outb(unsigned char b, unsigned long port) +{ + unsigned long addr = PORT2ADDR(port); + + DIPRINTK(0, "outb(%02x, %08lx)\n", (unsigned)b, addr); + if (addr != 0) + *(volatile unsigned char*)addr = b; +} + +void hd64465_outb_p(unsigned char b, unsigned long port) +{ + unsigned long addr = PORT2ADDR(port); + + DIPRINTK(0, "outb_p(%02x, %08lx)\n", (unsigned)b, addr); + if (addr != 0) + *(volatile unsigned char*)addr = b; + delay(); +} + +void hd64465_outw(unsigned short b, unsigned long port) +{ + unsigned long addr = PORT2ADDR(port); + DIPRINTK(0, "outw(%04x, %08lx)\n", (unsigned)b, addr); + if (addr != 0) + *(volatile unsigned short*)addr = b; +} + +void hd64465_outl(unsigned int b, unsigned long port) +{ + unsigned long addr = PORT2ADDR(port); + DIPRINTK(0, "outl(%08x, %08lx)\n", b, addr); + if (addr != 0) + *(volatile unsigned long*)addr = b; +} + +void hd64465_outsb(unsigned long port, const void *buffer, unsigned long count) +{ + const unsigned char *buf=buffer; + while(count--) outb(*buf++, port); +} + +void hd64465_outsw(unsigned long port, const void *buffer, unsigned long count) +{ + const unsigned short *buf=buffer; + while(count--) outw(*buf++, port); +} + +void hd64465_outsl(unsigned long port, const void *buffer, unsigned long count) +{ + const unsigned long *buf=buffer; + while(count--) outl(*buf++, port); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/io_se.c linux.ac/arch/sh/kernel/io_se.c --- linux.vanilla/arch/sh/kernel/io_se.c Wed Aug 9 21:59:04 2000 +++ linux.ac/arch/sh/kernel/io_se.c Sat Apr 14 01:18:22 2001 @@ -43,7 +43,7 @@ } static inline int -shifted_port(unsigned int port) +shifted_port(unsigned long port) { /* For IDE registers, value is not shifted */ if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6) @@ -53,10 +53,10 @@ } #define maybebadio(name,port) \ - printk("bad PC-like io %s for port 0x%x at 0x%08x\n", \ + printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \ #name, (port), (__u32) __builtin_return_address(0)) -unsigned long se_inb(unsigned int port) +unsigned char se_inb(unsigned long port) { if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) return *(__u8 *) (sh_pcic_io_wbase + 0x40000 + port); @@ -66,7 +66,7 @@ return (*port2adr(port))&0xff; } -unsigned long se_inb_p(unsigned int port) +unsigned char se_inb_p(unsigned long port) { unsigned long v; @@ -80,7 +80,7 @@ return v; } -unsigned long se_inw(unsigned int port) +unsigned short se_inw(unsigned long port) { if (port >= 0x2000 || (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)) @@ -90,13 +90,13 @@ return 0; } -unsigned long se_inl(unsigned int port) +unsigned int se_inl(unsigned long port) { maybebadio(inl, port); return 0; } -void se_outb(unsigned long value, unsigned int port) +void se_outb(unsigned char value, unsigned long port) { if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) *(__u8 *)(sh_pcic_io_wbase + port) = value; @@ -106,7 +106,7 @@ *(port2adr(port)) = value; } -void se_outb_p(unsigned long value, unsigned int port) +void se_outb_p(unsigned char value, unsigned long port) { if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) *(__u8 *)(sh_pcic_io_wbase + port) = value; @@ -117,7 +117,7 @@ delay(); } -void se_outw(unsigned long value, unsigned int port) +void se_outw(unsigned short value, unsigned long port) { if (port >= 0x2000 || (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)) @@ -126,12 +126,12 @@ maybebadio(outw, port); } -void se_outl(unsigned long value, unsigned int port) +void se_outl(unsigned int value, unsigned long port) { maybebadio(outl, port); } -void se_insb(unsigned int port, void *addr, unsigned long count) +void se_insb(unsigned long port, void *addr, unsigned long count) { volatile __u16 *p = port2adr(port); @@ -148,19 +148,19 @@ } } -void se_insw(unsigned int port, void *addr, unsigned long count) +void se_insw(unsigned long port, void *addr, unsigned long count) { volatile __u16 *p = port2adr(port); while (count--) *((__u16 *) addr)++ = *p; } -void se_insl(unsigned int port, void *addr, unsigned long count) +void se_insl(unsigned long port, void *addr, unsigned long count) { maybebadio(insl, port); } -void se_outsb(unsigned int port, const void *addr, unsigned long count) +void se_outsb(unsigned long port, const void *addr, unsigned long count) { volatile __u16 *p = port2adr(port); @@ -177,29 +177,29 @@ } } -void se_outsw(unsigned int port, const void *addr, unsigned long count) +void se_outsw(unsigned long port, const void *addr, unsigned long count) { volatile __u16 *p = port2adr(port); while (count--) *p = *((__u16 *) addr)++; } -void se_outsl(unsigned int port, const void *addr, unsigned long count) +void se_outsl(unsigned long port, const void *addr, unsigned long count) { maybebadio(outsw, port); } -unsigned long se_readb(unsigned long addr) +unsigned char se_readb(unsigned long addr) { return *(volatile unsigned char*)addr; } -unsigned long se_readw(unsigned long addr) +unsigned short se_readw(unsigned long addr) { return *(volatile unsigned short*)addr; } -unsigned long se_readl(unsigned long addr) +unsigned int se_readl(unsigned long addr) { return *(volatile unsigned long*)addr; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/io_unknown.c linux.ac/arch/sh/kernel/io_unknown.c --- linux.vanilla/arch/sh/kernel/io_unknown.c Wed Aug 9 21:59:04 2000 +++ linux.ac/arch/sh/kernel/io_unknown.c Sat Apr 14 01:18:22 2001 @@ -43,5 +43,4 @@ UNKNOWN_ALIAS(writel) UNKNOWN_ALIAS(isa_port2addr) UNKNOWN_ALIAS(ioremap) -UNKNOWN_ALIAS(ioremap_nocache) UNKNOWN_ALIAS(iounmap) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/irq_intc2.c linux.ac/arch/sh/kernel/irq_intc2.c --- linux.vanilla/arch/sh/kernel/irq_intc2.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/sh/kernel/irq_intc2.c Sat Apr 14 01:18:22 2001 @@ -0,0 +1,127 @@ +/* + * linux/arch/sh/kernel/irq_intc2.c + * + * Copyright (C) 2001 David J. Mckay (david.mckay@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Interrupt handling for INTC2-based IRQ. + * + * These are the "new Hitachi style" interrupts, as present on the + * Hitachi 7751 and the STM ST40 STB1. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/irq.h> + +#include <asm/system.h> +#include <asm/io.h> +#include <asm/machvec.h> + + +struct intc2_data { + unsigned int addr; /* Address of Interrupt Priority Register */ + int mask; /*Mask to apply */ +}; + + +static struct intc2_data intc2_data[NR_INTC2_IRQS]; + +static void enable_intc2_irq(unsigned int irq); +static void disable_intc2_irq(unsigned int irq); + +/* shutdown is same as "disable" */ +#define shutdown_intc2_irq disable_intc2_irq + +static void mask_and_ack_intc2(unsigned int); +static void end_intc2_irq(unsigned int irq); + +static unsigned int startup_intc2_irq(unsigned int irq) +{ + enable_intc2_irq(irq); + return 0; /* never anything pending */ +} + +static struct hw_interrupt_type intc2_irq_type = { + "INTC2-based-IRQ", + startup_intc2_irq, + shutdown_intc2_irq, + enable_intc2_irq, + disable_intc2_irq, + mask_and_ack_intc2, + end_intc2_irq +}; + +static void disable_intc2_irq(unsigned int irq) +{ + unsigned addr; + int offset=irq-INTC2_FIRST_IRQ; + unsigned val,flags; + + // Sanity check + if(offset<0 || offset>=NR_INTC2_IRQS) return; + + addr=intc2_data[offset].addr+INTC2_INTMSK_OFFSET; + + save_and_cli(flags); + val=ctrl_inl(addr); + val|=intc2_data[offset].mask; + ctrl_outl(val,addr); + + restore_flags(flags); +} + +static void enable_intc2_irq(unsigned int irq) +{ + int offset=irq-INTC2_FIRST_IRQ; + + // Sanity check + if(offset<0 || offset>=NR_INTC2_IRQS) return; + + ctrl_outl(intc2_data[offset].mask, + intc2_data[offset].addr+INTC2_INTMSKCLR_OFFSET); + +} + +static void mask_and_ack_intc2(unsigned int irq) +{ + disable_intc2_irq(irq); +} + +static void end_intc2_irq(unsigned int irq) +{ + enable_intc2_irq(irq); +} + +void make_intc2_irq(unsigned int irq, unsigned int addr, + unsigned int group,int pos, int priority) +{ + int offset=irq-INTC2_FIRST_IRQ; + unsigned flags,val; + + if(offset<0 || offset>=NR_INTC2_IRQS) { + return; + } + + disable_irq_nosync(irq); + /* Fill the the data we need */ + intc2_data[offset].addr=addr; + intc2_data[offset].mask=1<<pos; + + /* Set the priority level */ + save_and_cli(flags); + val=ctrl_inl(addr+INTC2_INTPRI_OFFSET); + val|=(priority)<< (group<<4); + ctrl_outl(val,addr+INTC2_INTPRI_OFFSET); + restore_flags(flags); + + irq_desc[irq].handler=&intc2_irq_type; + + disable_intc2_irq(irq); +} + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/irq_ipr.c linux.ac/arch/sh/kernel/irq_ipr.c --- linux.vanilla/arch/sh/kernel/irq_ipr.c Mon Oct 2 19:57:34 2000 +++ linux.ac/arch/sh/kernel/irq_ipr.c Sat Apr 14 01:18:22 2001 @@ -116,14 +116,96 @@ disable_ipr_irq(irq); } +#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) +static unsigned char pint_map[256]; +static unsigned long portcr_mask = 0; + +static void enable_pint_irq(unsigned int irq); +static void disable_pint_irq(unsigned int irq); + +/* shutdown is same as "disable" */ +#define shutdown_pint_irq disable_pint_irq + +static void mask_and_ack_pint(unsigned int); +static void end_pint_irq(unsigned int irq); + +static unsigned int startup_pint_irq(unsigned int irq) +{ + enable_pint_irq(irq); + return 0; /* never anything pending */ +} + +static struct hw_interrupt_type pint_irq_type = { + "PINT-IRQ", + startup_pint_irq, + shutdown_pint_irq, + enable_pint_irq, + disable_pint_irq, + mask_and_ack_pint, + end_pint_irq +}; + +static void disable_pint_irq(unsigned int irq) +{ + unsigned long val, flags; + + save_and_cli(flags); + val = ctrl_inw(INTC_INTER); + val &= ~(1 << (irq - PINT_IRQ_BASE)); + ctrl_outw(val, INTC_INTER); /* disable PINTn */ + portcr_mask &= ~(3 << (irq - PINT_IRQ_BASE)*2); + restore_flags(flags); +} + +static void enable_pint_irq(unsigned int irq) +{ + unsigned long val, flags; + + save_and_cli(flags); + val = ctrl_inw(INTC_INTER); + val |= 1 << (irq - PINT_IRQ_BASE); + ctrl_outw(val, INTC_INTER); /* enable PINTn */ + portcr_mask |= 3 << (irq - PINT_IRQ_BASE)*2; + restore_flags(flags); +} + +static void mask_and_ack_pint(unsigned int irq) +{ + disable_pint_irq(irq); +} + +static void end_pint_irq(unsigned int irq) +{ + enable_pint_irq(irq); +} + +void make_pint_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + irq_desc[irq].handler = &pint_irq_type; + disable_pint_irq(irq); +} +#endif + void __init init_IRQ(void) { + int i; + make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY); make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY); +#ifdef SCI_ERI_IRQ make_ipr_irq(SCI_ERI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); make_ipr_irq(SCI_RXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); make_ipr_irq(SCI_TXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); +#endif + +#ifdef SCIF1_ERI_IRQ + make_ipr_irq(SCIF1_ERI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); + make_ipr_irq(SCIF1_RXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); + make_ipr_irq(SCIF1_BRI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); + make_ipr_irq(SCIF1_TXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); +#endif #ifdef SCIF_ERI_IRQ make_ipr_irq(SCIF_ERI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); @@ -171,12 +253,30 @@ * You should set corresponding bits of PFC to "00" * to enable these interrupts. */ - make_ipr_irq(IRQ0_IRQ, IRQ0_IRP_ADDR, IRQ0_IRP_POS, IRQ0_PRIORITY); - make_ipr_irq(IRQ1_IRQ, IRQ1_IRP_ADDR, IRQ1_IRP_POS, IRQ1_PRIORITY); - make_ipr_irq(IRQ2_IRQ, IRQ2_IRP_ADDR, IRQ2_IRP_POS, IRQ2_PRIORITY); - make_ipr_irq(IRQ3_IRQ, IRQ3_IRP_ADDR, IRQ3_IRP_POS, IRQ3_PRIORITY); - make_ipr_irq(IRQ4_IRQ, IRQ4_IRP_ADDR, IRQ4_IRP_POS, IRQ4_PRIORITY); - make_ipr_irq(IRQ5_IRQ, IRQ5_IRP_ADDR, IRQ5_IRP_POS, IRQ5_PRIORITY); + make_ipr_irq(IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, IRQ0_PRIORITY); + make_ipr_irq(IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, IRQ1_PRIORITY); + make_ipr_irq(IRQ2_IRQ, IRQ2_IPR_ADDR, IRQ2_IPR_POS, IRQ2_PRIORITY); + make_ipr_irq(IRQ3_IRQ, IRQ3_IPR_ADDR, IRQ3_IPR_POS, IRQ3_PRIORITY); + make_ipr_irq(IRQ4_IRQ, IRQ4_IPR_ADDR, IRQ4_IPR_POS, IRQ4_PRIORITY); + make_ipr_irq(IRQ5_IRQ, IRQ5_IPR_ADDR, IRQ5_IPR_POS, IRQ5_PRIORITY); + make_ipr_irq(PINT0_IRQ, PINT0_IPR_ADDR, PINT0_IPR_POS, PINT0_PRIORITY); + make_ipr_irq(PINT8_IRQ, PINT8_IPR_ADDR, PINT8_IPR_POS, PINT8_PRIORITY); + enable_ipr_irq(PINT0_IRQ); + enable_ipr_irq(PINT8_IRQ); + + for(i = 0; i < 16; i++) + make_pint_irq(PINT_IRQ_BASE + i); + for(i = 0; i < 256; i++) + { + if(i & 1) pint_map[i] = 0; + else if(i & 2) pint_map[i] = 1; + else if(i & 4) pint_map[i] = 2; + else if(i & 8) pint_map[i] = 3; + else if(i & 0x10) pint_map[i] = 4; + else if(i & 0x20) pint_map[i] = 5; + else if(i & 0x40) pint_map[i] = 6; + else if(i & 0x80) pint_map[i] = 7; + } #endif /* CONFIG_CPU_SUBTYPE_SH7707 || CONFIG_CPU_SUBTYPE_SH7709 */ /* Perform the machine specific initialisation */ @@ -184,3 +284,43 @@ sh_mv.mv_init_irq(); } } +#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) +int ipr_irq_demux(int irq) +{ + unsigned long creg, dreg, d, sav; + + if(irq == PINT0_IRQ) + { +#if defined(CONFIG_CPU_SUBTYPE_SH7707) + creg = PORT_PACR; + dreg = PORT_PADR; +#else + creg = PORT_PCCR; + dreg = PORT_PCDR; +#endif + sav = ctrl_inw(creg); + ctrl_outw(sav | portcr_mask, creg); + d = (~ctrl_inb(dreg) ^ ctrl_inw(INTC_ICR2)) & ctrl_inw(INTC_INTER) & 0xff; + ctrl_outw(sav, creg); + if(d == 0) return irq; + return PINT_IRQ_BASE + pint_map[d]; + } + else if(irq == PINT8_IRQ) + { +#if defined(CONFIG_CPU_SUBTYPE_SH7707) + creg = PORT_PBCR; + dreg = PORT_PBDR; +#else + creg = PORT_PFCR; + dreg = PORT_PFDR; +#endif + sav = ctrl_inw(creg); + ctrl_outw(sav | (portcr_mask >> 16), creg); + d = (~ctrl_inb(dreg) ^ (ctrl_inw(INTC_ICR2) >> 8)) & (ctrl_inw(INTC_INTER) >> 8) & 0xff; + ctrl_outw(sav, creg); + if(d == 0) return irq; + return PINT_IRQ_BASE + 8 + pint_map[d]; + } + return irq; +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/mach_cat68701.c linux.ac/arch/sh/kernel/mach_cat68701.c --- linux.vanilla/arch/sh/kernel/mach_cat68701.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/sh/kernel/mach_cat68701.c Sat Apr 14 01:18:22 2001 @@ -0,0 +1,72 @@ +/* + * linux/arch/sh/kernel/mach_cat68701.c + * + * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) + * 2001 Yutaro Ebihara (ebihara@si-linux.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Machine vector for the A-ONE corp. CAT-68701 SH7708 board + */ + +#include <linux/config.h> +#include <linux/init.h> + +#include <asm/machvec.h> +#include <asm/rtc.h> +#include <asm/machvec_init.h> +#include <asm/io_cat68701.h> + +/* + * The Machine Vector + */ + +struct sh_machine_vector mv_cat68701 __initmv = { + mv_name: "CAT-68701", + mv_nr_irqs: 32, + mv_inb: cat68701_inb, + mv_inw: cat68701_inw, + mv_inl: cat68701_inl, + mv_outb: cat68701_outb, + mv_outw: cat68701_outw, + mv_outl: cat68701_outl, + + mv_inb_p: cat68701_inb_p, + mv_inw_p: cat68701_inw, + mv_inl_p: cat68701_inl, + mv_outb_p: cat68701_outb_p, + mv_outw_p: cat68701_outw, + mv_outl_p: cat68701_outl, + + mv_insb: cat68701_insb, + mv_insw: cat68701_insw, + mv_insl: cat68701_insl, + mv_outsb: cat68701_outsb, + mv_outsw: cat68701_outsw, + mv_outsl: cat68701_outsl, + + mv_readb: cat68701_readb, + mv_readw: cat68701_readw, + mv_readl: cat68701_readl, + mv_writeb: cat68701_writeb, + mv_writew: cat68701_writew, + mv_writel: cat68701_writel, + + mv_ioremap: cat68701_ioremap, + mv_iounmap: cat68701_iounmap, + + mv_isa_port2addr: cat68701_isa_port2addr, + mv_irq_demux: cat68701_irq_demux, + + mv_init_arch: setup_cat68701, + mv_init_irq: init_cat68701_IRQ, +#ifdef CONFIG_HEARTBEAT + mv_heartbeat: heartbeat_cat68701, +#endif + + mv_rtc_gettimeofday: sh_rtc_gettimeofday, + mv_rtc_settimeofday: sh_rtc_settimeofday, + +}; +ALIAS_MV(cat68701) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/mach_dc.c linux.ac/arch/sh/kernel/mach_dc.c --- linux.vanilla/arch/sh/kernel/mach_dc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/sh/kernel/mach_dc.c Sat Apr 14 01:18:22 2001 @@ -0,0 +1,66 @@ +/* + * $Id: mach_dc.c,v 1.1 2001/04/01 15:02:00 yaegashi Exp $ + * SEGA Dreamcast machine vector + */ + +#include <linux/init.h> + +#include <asm/machvec.h> +#include <asm/machvec_init.h> + +#include <asm/io_generic.h> +#include <asm/io_dc.h> +#include <asm/irq.h> + +void __init setup_dreamcast(void); +void __init dreamcast_pcibios_init(void); + +/* + * The Machine Vector + */ + +struct sh_machine_vector mv_dreamcast __initmv = { + mv_name: "dreamcast", + + mv_nr_irqs: 48, + + mv_inb: generic_inb, + mv_inw: generic_inw, + mv_inl: generic_inl, + mv_outb: generic_outb, + mv_outw: generic_outw, + mv_outl: generic_outl, + + mv_inb_p: generic_inb_p, + mv_inw_p: generic_inw, + mv_inl_p: generic_inl, + mv_outb_p: generic_outb_p, + mv_outw_p: generic_outw, + mv_outl_p: generic_outl, + + mv_insb: generic_insb, + mv_insw: generic_insw, + mv_insl: generic_insl, + mv_outsb: generic_outsb, + mv_outsw: generic_outsw, + mv_outsl: generic_outsl, + + mv_readb: generic_readb, + mv_readw: generic_readw, + mv_readl: generic_readl, + mv_writeb: generic_writeb, + mv_writew: generic_writew, + mv_writel: generic_writel, + + mv_ioremap: generic_ioremap, + mv_iounmap: generic_iounmap, + + mv_init_arch: setup_dreamcast, +#ifdef CONFIG_PCI + mv_init_pci: dreamcast_pcibios_init, +#endif + mv_isa_port2addr: dreamcast_isa_port2addr, + + mv_hw_dreamcast: 1, +}; +ALIAS_MV(dreamcast) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/mach_dmida.c linux.ac/arch/sh/kernel/mach_dmida.c --- linux.vanilla/arch/sh/kernel/mach_dmida.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/sh/kernel/mach_dmida.c Sat Apr 14 01:18:22 2001 @@ -0,0 +1,73 @@ +/* + * linux/arch/sh/kernel/mach_dmida.c + * + * by Greg Banks <gbanks@pocketpenguins.com> + * (c) 2000 PocketPenguins Inc + * + * Derived from mach_hp600.c, which bore the message: + * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Machine vector for the DataMyte Industrial Digital Assistant(tm). + * See http://www.dmida.com + * + */ + +#include <linux/init.h> + +#include <asm/machvec.h> +#include <asm/rtc.h> +#include <asm/machvec_init.h> + +#include <asm/io.h> +#include <asm/hd64465.h> +#include <asm/irq.h> + +/* + * The Machine Vector + */ + +struct sh_machine_vector mv_dmida __initmv = { + mv_name: "DMIDA", + + mv_nr_irqs: HD64465_IRQ_BASE+HD64465_IRQ_NUM, + + mv_inb: hd64465_inb, + mv_inw: hd64465_inw, + mv_inl: hd64465_inl, + mv_outb: hd64465_outb, + mv_outw: hd64465_outw, + mv_outl: hd64465_outl, + + mv_inb_p: hd64465_inb_p, + mv_inw_p: hd64465_inw, + mv_inl_p: hd64465_inl, + mv_outb_p: hd64465_outb_p, + mv_outw_p: hd64465_outw, + mv_outl_p: hd64465_outl, + + mv_insb: hd64465_insb, + mv_insw: hd64465_insw, + mv_insl: hd64465_insl, + mv_outsb: hd64465_outsb, + mv_outsw: hd64465_outsw, + mv_outsl: hd64465_outsl, + + mv_readb: generic_readb, + mv_readw: generic_readw, + mv_readl: generic_readl, + mv_writeb: generic_writeb, + mv_writew: generic_writew, + mv_writel: generic_writel, + + mv_irq_demux: hd64465_irq_demux, + + mv_rtc_gettimeofday: sh_rtc_gettimeofday, + mv_rtc_settimeofday: sh_rtc_settimeofday, + + mv_hw_hd64465: 1, +}; +ALIAS_MV(dmida) + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/mach_ec3104.c linux.ac/arch/sh/kernel/mach_ec3104.c --- linux.vanilla/arch/sh/kernel/mach_ec3104.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/sh/kernel/mach_ec3104.c Sat Apr 14 01:18:22 2001 @@ -0,0 +1,69 @@ +/* + * linux/arch/sh/kernel/mach_ec3104.c + * EC3104 companion chip support + * + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> + * + */ +/* EC3104 note: + * This code was written without any documentation about the EC3104 chip. While + * I hope I got most of the basic functionality right, the register names I use + * are most likely completely different from those in the chip documentation. + * + * If you have any further information about the EC3104, please tell me + * (prumpf@tux.org). + */ + +#include <linux/init.h> + +#include <asm/machvec.h> +#include <asm/rtc.h> +#include <asm/machvec_init.h> + +#include <asm/io.h> +#include <asm/irq.h> + +/* + * The Machine Vector + */ + +struct sh_machine_vector mv_ec3104 __initmv = { + mv_name: "EC3104", + + mv_nr_irqs: 96, + + mv_inb: ec3104_inb, + mv_inw: ec3104_inw, + mv_inl: ec3104_inl, + mv_outb: ec3104_outb, + mv_outw: ec3104_outw, + mv_outl: ec3104_outl, + + mv_inb_p: generic_inb_p, + mv_inw_p: generic_inw, + mv_inl_p: generic_inl, + mv_outb_p: generic_outb_p, + mv_outw_p: generic_outw, + mv_outl_p: generic_outl, + + mv_insb: generic_insb, + mv_insw: generic_insw, + mv_insl: generic_insl, + mv_outsb: generic_outsb, + mv_outsw: generic_outsw, + mv_outsl: generic_outsl, + + mv_readb: generic_readb, + mv_readw: generic_readw, + mv_readl: generic_readl, + mv_writeb: generic_writeb, + mv_writew: generic_writew, + mv_writel: generic_writel, + + mv_irq_demux: ec3104_irq_demux, + + mv_rtc_gettimeofday: sh_rtc_gettimeofday, + mv_rtc_settimeofday: sh_rtc_settimeofday, +}; + +ALIAS_MV(ec3104) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/mach_hp600.c linux.ac/arch/sh/kernel/mach_hp600.c --- linux.vanilla/arch/sh/kernel/mach_hp600.c Wed Aug 9 21:59:04 2000 +++ linux.ac/arch/sh/kernel/mach_hp600.c Sat Apr 14 01:18:22 2001 @@ -12,6 +12,7 @@ #include <linux/init.h> #include <asm/machvec.h> +#include <asm/rtc.h> #include <asm/machvec_init.h> #include <asm/io_hd64461.h> @@ -22,8 +23,8 @@ * The Machine Vector */ -struct sh_machine_vector mv_hp600 __initmv = { - mv_name: "HP600", +struct sh_machine_vector mv_hp620 __initmv = { + mv_name: "hp620", mv_nr_irqs: 80, /* HD64461_IRQBASE+16, see hd64461.h */ @@ -57,7 +58,101 @@ mv_irq_demux: hd64461_irq_demux, + mv_rtc_gettimeofday: sh_rtc_gettimeofday, + mv_rtc_settimeofday: sh_rtc_settimeofday, + + mv_hw_hp600: 1, + mv_hw_hp620: 1, + mv_hw_hd64461: 1, +}; +ALIAS_MV(hp620) + + +struct sh_machine_vector mv_hp680 __initmv = { + mv_name: "hp680", + + mv_nr_irqs: 80, /* HD64461_IRQBASE+16, see hd64461.h */ + + mv_inb: hd64461_inb, + mv_inw: hd64461_inw, + mv_inl: hd64461_inl, + mv_outb: hd64461_outb, + mv_outw: hd64461_outw, + mv_outl: hd64461_outl, + + mv_inb_p: hd64461_inb_p, + mv_inw_p: hd64461_inw, + mv_inl_p: hd64461_inl, + mv_outb_p: hd64461_outb_p, + mv_outw_p: hd64461_outw, + mv_outl_p: hd64461_outl, + + mv_insb: hd64461_insb, + mv_insw: hd64461_insw, + mv_insl: hd64461_insl, + mv_outsb: hd64461_outsb, + mv_outsw: hd64461_outsw, + mv_outsl: hd64461_outsl, + + mv_readb: generic_readb, + mv_readw: generic_readw, + mv_readl: generic_readl, + mv_writeb: generic_writeb, + mv_writew: generic_writew, + mv_writel: generic_writel, + + mv_irq_demux: hd64461_irq_demux, + + mv_rtc_gettimeofday: sh_rtc_gettimeofday, + mv_rtc_settimeofday: sh_rtc_settimeofday, + + mv_hw_hp600: 1, + mv_hw_hp680: 1, + mv_hw_hd64461: 1, +}; +ALIAS_MV(hp680) + + +struct sh_machine_vector mv_hp690 __initmv = { + mv_name: "hp690", + + mv_nr_irqs: 80, /* HD64461_IRQBASE+16, see hd64461.h */ + + mv_inb: hd64461_inb, + mv_inw: hd64461_inw, + mv_inl: hd64461_inl, + mv_outb: hd64461_outb, + mv_outw: hd64461_outw, + mv_outl: hd64461_outl, + + mv_inb_p: hd64461_inb_p, + mv_inw_p: hd64461_inw, + mv_inl_p: hd64461_inl, + mv_outb_p: hd64461_outb_p, + mv_outw_p: hd64461_outw, + mv_outl_p: hd64461_outl, + + mv_insb: hd64461_insb, + mv_insw: hd64461_insw, + mv_insl: hd64461_insl, + mv_outsb: hd64461_outsb, + mv_outsw: hd64461_outsw, + mv_outsl: hd64461_outsl, + + mv_readb: generic_readb, + mv_readw: generic_readw, + mv_readl: generic_readl, + mv_writeb: generic_writeb, + mv_writew: generic_writew, + mv_writel: generic_writel, + + mv_irq_demux: hd64461_irq_demux, + + mv_rtc_gettimeofday: sh_rtc_gettimeofday, + mv_rtc_settimeofday: sh_rtc_settimeofday, + mv_hw_hp600: 1, + mv_hw_hp690: 1, mv_hw_hd64461: 1, }; -ALIAS_MV(hp600) +ALIAS_MV(hp690) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/mach_se.c linux.ac/arch/sh/kernel/mach_se.c --- linux.vanilla/arch/sh/kernel/mach_se.c Thu Aug 10 21:03:25 2000 +++ linux.ac/arch/sh/kernel/mach_se.c Sat Apr 14 01:18:22 2001 @@ -13,6 +13,7 @@ #include <linux/init.h> #include <asm/machvec.h> +#include <asm/rtc.h> #include <asm/machvec_init.h> #include <asm/io_se.h> @@ -65,7 +66,6 @@ mv_writel: se_writel, mv_ioremap: generic_ioremap, - mv_ioremap_nocache: generic_ioremap_nocache, mv_iounmap: generic_iounmap, mv_isa_port2addr: se_isa_port2addr, @@ -75,6 +75,9 @@ #ifdef CONFIG_HEARTBEAT mv_heartbeat: heartbeat_se, #endif + + mv_rtc_gettimeofday: sh_rtc_gettimeofday, + mv_rtc_settimeofday: sh_rtc_settimeofday, mv_hw_se: 1, }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/mach_unknown.c linux.ac/arch/sh/kernel/mach_unknown.c --- linux.vanilla/arch/sh/kernel/mach_unknown.c Thu Aug 10 21:03:25 2000 +++ linux.ac/arch/sh/kernel/mach_unknown.c Sat Apr 14 01:18:22 2001 @@ -17,6 +17,7 @@ #include <asm/io_unknown.h> +#include <asm/rtc.h> /* * The Machine Vector */ @@ -61,9 +62,11 @@ mv_writel: unknown_writel, mv_ioremap: unknown_ioremap, - mv_ioremap_nocache: unknown_ioremap_nocache, mv_iounmap: unknown_iounmap, mv_isa_port2addr: unknown_isa_port2addr, + + mv_rtc_gettimeofday: sh_rtc_gettimeofday, + mv_rtc_settimeofday: sh_rtc_settimeofday, }; ALIAS_MV(unknown) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/pci_st40.c linux.ac/arch/sh/kernel/pci_st40.c --- linux.vanilla/arch/sh/kernel/pci_st40.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/sh/kernel/pci_st40.c Sat Apr 14 01:18:22 2001 @@ -0,0 +1,494 @@ +/* + * Copyright (C) 2001 David J. Mckay (david.mckay@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Support functions for the ST40 PCI hardware. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/types.h> +#include <asm/pci.h> +#include <linux/irq.h> + +#include "pci_st40.h" + +/* This is in P2 of course */ +#define ST40PCI_BASE_ADDRESS (0xb0000000) +#define ST40PCI_MEM_ADDRESS (ST40PCI_BASE_ADDRESS+0x0) +#define ST40PCI_IO_ADDRESS (ST40PCI_BASE_ADDRESS+0x06000000) +#define ST40PCI_REG_ADDRESS (ST40PCI_BASE_ADDRESS+0x07000000) + +#define ST40PCI_REG(x) (ST40PCI_REG_ADDRESS+(ST40PCI_##x)) + +#define ST40PCI_WRITE(reg,val) writel((val),ST40PCI_REG(reg)) +#define ST40PCI_WRITE_SHORT(reg,val) writew((val),ST40PCI_REG(reg)) +#define ST40PCI_WRITE_BYTE(reg,val) writeb((val),ST40PCI_REG(reg)) + +#define ST40PCI_READ(reg) readl(ST40PCI_REG(reg)) +#define ST40PCI_READ_SHORT(reg) readw(ST40PCI_REG(reg)) +#define ST40PCI_READ_BYTE(reg) readb(ST40PCI_REG(reg)) + +#define ST40PCI_SERR_IRQ 64 +#define ST40PCI_SERR_INT_GROUP 0 +#define ST40PCI_SERR_INT_POS 0 +#define ST40PCI_SERR_INT_PRI 15 + +#define ST40PCI_ERR_IRQ 65 +#define ST40PCI_ERR_INT_GROUP 1 +#define ST40PCI_ERR_INT_POS 1 +#define ST40PCI_ERR_INT_PRI 14 + + +/* Macros to extract PLL params */ +#define PLL_MDIV(reg) ( ((unsigned)reg) & 0xff ) +#define PLL_NDIV(reg) ( (((unsigned)reg)>>8) & 0xff ) +#define PLL_PDIV(reg) ( (((unsigned)reg)>>16) & 0x3 ) +#define PLL_SETUP(reg) ( (((unsigned)reg)>>19) & 0x1ff ) + +/* Build up the appropriate settings */ +#define PLL_SET(mdiv,ndiv,pdiv,setup) \ +( ((mdiv)&0xff) | (((ndiv)&0xff)<<8) | (((pdiv)&3)<<16)| (((setup)&0x1ff)<<19)) + +#define PLLPCICR (0xbb040000+0x10) + +#define PLLPCICR_POWERON (1<<28) +#define PLLPCICR_OUT_EN (1<<29) +#define PLLPCICR_LOCKSELECT (1<<30) +#define PLLPCICR_LOCK (1<<31) + + +#define PLL_25MHZ 0x793c8512 +#define PLL_33MHZ PLL_SET(18,88,3,295) + + +static __init void SetPCIPLL(void) +{ + /* Stop the PLL */ + writel(0, PLLPCICR); + + /* Always run at 33Mhz. The PCI clock is totally async + * to the rest of the system + */ + writel(PLL_33MHZ | PLLPCICR_POWERON, PLLPCICR); + + printk("ST40PCI: Waiting for PCI PLL to lock\n"); + while ((readl(PLLPCICR) & PLLPCICR_LOCK) == 0); + writel(readl(PLLPCICR) | PLLPCICR_OUT_EN, PLLPCICR); +} + + +static void st40_pci_irq(int irq, void *dev_instance, struct pt_regs *regs) +{ + + unsigned pci_int, pci_air, pci_cir, pci_aint; + + pci_int = ST40PCI_READ(INT); + pci_cir = ST40PCI_READ(CIR); + pci_air = ST40PCI_READ(AIR); + + if (pci_int) { + printk("PCI INTERRUPT!\n"); + printk("PCI INT -> 0x%x\n", pci_int & 0xffff); + printk("PCI AIR -> 0x%x\n", pci_air); + printk("PCI CIR -> 0x%x\n", pci_cir); + ST40PCI_WRITE(INT, ~0); + } + + pci_aint = ST40PCI_READ(AINT); + if (pci_aint) { + printk("PCI ARB INTERRUPT!\n"); + printk("PCI AINT -> 0x%x\n", pci_aint); + printk("PCI AIR -> 0x%x\n", pci_air); + printk("PCI CIR -> 0x%x\n", pci_cir); + ST40PCI_WRITE(AINT, ~0); + } + +} + + +/* Rounds a number UP to the nearest power of two. Used for + * sizing the PCI window. + */ +static u32 __init r2p2(u32 num) +{ + int i = 31; + u32 tmp = num; + + if (num == 0) + return 0; + + do { + if (tmp & (1 << 31)) + break; + i--; + tmp <<= 1; + } while (i >= 0); + + tmp = 1 << i; + /* If the original number isn't a power of 2, round it up */ + if (tmp != num) + tmp <<= 1; + + return tmp; +} + + +int __init st40pci_init(unsigned memStart, unsigned memSize) +{ + u32 lsr0; + + SetPCIPLL(); + + /* Initialises the ST40 pci subsystem, performing a reset, then programming + * up the address space decoders appropriately + */ + + /* Should reset core here as well methink */ + + ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_SOFT_RESET); + + /* Loop while core resets */ + while (ST40PCI_READ(CR) & CR_SOFT_RESET); + + /* Now, lets reset all the cards on the bus with extreme prejudice */ + ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_RSTCTL); + udelay(250); + + /* Set bus active, take it out of reset */ + ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_CFINT | CR_PFCS | CR_PFE); + + /* The PCI spec says that no access must be made to the bus until 1 second + * after reset. This seem ludicrously long, but some delay is needed here + */ + mdelay(1000); + + /* Switch off interrupts */ + ST40PCI_WRITE(INTM, 0); + ST40PCI_WRITE(AINT, 0); + + /* Allow it to be a master */ + + ST40PCI_WRITE_SHORT(CSR_CMD, + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | + PCI_COMMAND_IO); + + /* Accesse to the 0xb0000000 -> 0xb6000000 area will go through to 0x10000000 -> 0x16000000 + * on the PCI bus. This allows a nice 1-1 bus to phys mapping. + */ + + + ST40PCI_WRITE(MBR, 0x10000000); + /* Always set the max size 128M (actually, it is only 96MB wide) */ + ST40PCI_WRITE(MBMR, 0x07ff0000); + + /* I/O addresses are mapped at 0xb6000000 -> 0xb7000000. These are changed to 0, to + * allow cards that have legacy io such as vga to function correctly. This gives a + * maximum of 64K of io/space as only the bottom 16 bits of the address are copied + * over to the bus when the transaction is made. 64K of io space is more than enough + */ + ST40PCI_WRITE(IOBR, 0x0); + /* Set up the 64K window */ + ST40PCI_WRITE(IOBMR, 0x0); + + /* Now we set up the mbars so the PCI bus can see the memory of the machine */ + + if (memSize < (64 * 1024)) { + printk("Ridiculous memory size of 0x%x?\n",memSize); + return 0; + } + + lsr0 = + (memSize > + (512 * 1024 * 1024)) ? 0x1fff0001 : ((r2p2(memSize) - + 0x10000) | 0x1); + + ST40PCI_WRITE(LSR0, lsr0); + + ST40PCI_WRITE(CSR_MBAR0, memStart); + ST40PCI_WRITE(LAR0, memStart); + + /* Maximise timeout values */ + ST40PCI_WRITE_BYTE(CSR_TRDY, 0xff); + ST40PCI_WRITE_BYTE(CSR_RETRY, 0xff); + ST40PCI_WRITE_BYTE(CSR_MIT, 0xff); + + + /* Install the pci interrupt handlers */ + make_intc2_irq(ST40PCI_SERR_IRQ, INTC2_BASE0, + ST40PCI_SERR_INT_GROUP, ST40PCI_SERR_INT_POS, + ST40PCI_SERR_INT_PRI); + + make_intc2_irq(ST40PCI_ERR_IRQ, INTC2_BASE0, ST40PCI_ERR_INT_GROUP, + ST40PCI_ERR_INT_POS, ST40PCI_ERR_INT_PRI); + + + return 1; +} + + +#define SET_CONFIG_BITS(bus,devfn,where)\ + (((bus) << 16) | ((devfn) << 8) | ((where) & ~3) | (bus!=0)) + +#define CONFIG_CMD(dev, where) SET_CONFIG_BITS((dev)->bus->number,(dev)->devfn,where) + + +static int CheckForMasterAbort(void) +{ + if (ST40PCI_READ(INT) & INT_MADIM) { + /* Should we clear config space version as well ??? */ + ST40PCI_WRITE(INT, INT_MADIM); + ST40PCI_WRITE_SHORT(CSR_STATUS, 0); + return 1; + } + + return 0; +} + +/* Write to config register */ +static int st40pci_read_config_byte(struct pci_dev *dev, int where, + u8 * val) +{ + ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where)); + + *val = ST40PCI_READ_BYTE(PDR + (where & 3)); + + if (CheckForMasterAbort()) + *val = 0xff; + + + return PCIBIOS_SUCCESSFUL; +} + +static int st40pci_read_config_word(struct pci_dev *dev, int where, + u16 * val) +{ + ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where)); + + *val = ST40PCI_READ_SHORT(PDR + (where & 2)); + + if (CheckForMasterAbort()) + *val = 0xffff; + + return PCIBIOS_SUCCESSFUL; +} + + +static int st40pci_read_config_dword(struct pci_dev *dev, int where, + u32 * val) +{ + + ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where)); + + *val = ST40PCI_READ(PDR); + + if (CheckForMasterAbort()) + *val = 0xffffffff; + + return PCIBIOS_SUCCESSFUL; +} + +static int st40pci_write_config_byte(struct pci_dev *dev, int where, + u8 val) +{ + ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where)); + + ST40PCI_WRITE_BYTE(PDR + (where & 3), val); + + CheckForMasterAbort(); + + return PCIBIOS_SUCCESSFUL; +} + + +static int st40pci_write_config_word(struct pci_dev *dev, int where, + u16 val) +{ + ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where)); + + ST40PCI_WRITE_SHORT(PDR + (where & 2), val); + + CheckForMasterAbort(); + + return PCIBIOS_SUCCESSFUL; +} + +static int st40pci_write_config_dword(struct pci_dev *dev, int where, + u32 val) +{ + ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where)); + + ST40PCI_WRITE(PDR, val); + + CheckForMasterAbort(); + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops pci_config_ops = { + st40pci_read_config_byte, + st40pci_read_config_word, + st40pci_read_config_dword, + st40pci_write_config_byte, + st40pci_write_config_word, + st40pci_write_config_dword +}; + + +/* Everything hangs off this */ +static struct pci_bus *pci_root_bus; + + +static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin) +{ + return PCI_SLOT(dev->devfn); +} + + +/* This needs to be shunted out of here into the board specific bit */ +#define HARP_PCI_IRQ 1 +#define HARP_BRIDGE_IRQ 2 +#define OVERDRIVE_SLOT0_IRQ 0 + +static int __init map_harp_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + switch (slot) { +#ifdef CONFIG_SH_STB1_HARP + case 2: /*This is the PCI slot on the */ + return HARP_PCI_IRQ; + case 1: /* this is the bridge */ + return HARP_BRIDGE_IRQ; +#elif defined(CONFIG_SH_STB1_OVERDRIVE) + case 1: + case 2: + case 3: + return slot - 1; +#else +#error Unknown board +#endif + default: + return -1; + } +} + + +void __init +pcibios_fixup_pbus_ranges(struct pci_bus *bus, + struct pbus_set_ranges_data *ranges) +{ + ranges->io_start -= bus->resource[0]->start; + ranges->io_end -= bus->resource[0]->start; + ranges->mem_start -= bus->resource[1]->start; + ranges->mem_end -= bus->resource[1]->start; +} + +void __init st40_pcibios_init(void) +{ + extern unsigned long memory_start, memory_end; + + /* The pci subsytem needs to know where memory is and how much + * of it there is. I've simply made these globals. A better mechanism + * is probably needed. + */ + st40pci_init(PHYSADDR(memory_start), + PHYSADDR(memory_end) - PHYSADDR(memory_start)); + + if (request_irq(ST40PCI_ERR_IRQ, st40_pci_irq, + SA_INTERRUPT, "st40pci", NULL)) { + printk(KERN_ERR "st40pci: Cannot hook interrupt\n"); + return; + } + + /* Enable the PCI interrupts on the device */ + ST40PCI_WRITE(INTM, ~0); + ST40PCI_WRITE(AINT, ~0); + + /* Map the io address apprioately */ +#ifdef CONFIG_HD64465 + hd64465_port_map(PCIBIOS_MIN_IO, (64 * 1024) - PCIBIOS_MIN_IO + 1, + ST40_IO_ADDR + PCIBIOS_MIN_IO, 0); +#endif + + /* ok, do the scan man */ + pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL); + pci_assign_unassigned_resources(); + pci_fixup_irqs(no_swizzle, map_harp_irq); + +} + +int pcibios_enable_device(struct pci_dev *dev) +{ + + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for (idx = 0; idx < 6; idx++) { + r = dev->resource + idx; + if (!r->start && r->end) { + printk(KERN_ERR + "PCI: Device %s not available because" + " of resource collisions\n", + dev->slot_name); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (cmd != old_cmd) { + printk("PCI: enabling device %s (%04x -> %04x)\n", + dev->slot_name, old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; + +} + +void __init pcibios_fixup_bus(struct pci_bus *bus) +{ +} + +void pcibios_align_resource(void *data, struct resource *res, + unsigned long size) +{ +} + +void __init pcibios_update_resource(struct pci_dev *dev, + struct resource *root, + struct resource *res, int resource) +{ + + unsigned long where, size; + u32 reg; + + printk("PCI: Assigning %3s %08lx to %s\n", + res->flags & IORESOURCE_IO ? "IO" : "MEM", + res->start, dev->name); + + where = PCI_BASE_ADDRESS_0 + resource * 4; + size = res->end - res->start; + + pci_read_config_dword(dev, where, ®); + reg = (reg & size) | (((u32) (res->start - root->start)) & ~size); + pci_write_config_dword(dev, where, reg); + +} + + +void __init pcibios_update_irq(struct pci_dev *dev, int irq) +{ + printk("PCI: Assigning IRQ %02d to %s\n", irq, dev->name); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/pci_st40.h linux.ac/arch/sh/kernel/pci_st40.h --- linux.vanilla/arch/sh/kernel/pci_st40.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/sh/kernel/pci_st40.h Sat Apr 14 01:18:22 2001 @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2001 David J. Mckay (david.mckay@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Defintions for the ST40 PCI hardware. + */ + +#ifndef __PCI_ST40_H__ +#define __PCI_ST40_H__ + +#define ST40PCI_VCR_STATUS 0x00 + +#define ST40PCI_VCR_VERSION 0x08 + +#define ST40PCI_CR 0x10 + +#define CR_SOFT_RESET (1<<12) +#define CR_PFCS (1<<11) +#define CR_PFE (1<<9) +#define CR_BMAM (1<<6) +#define CR_HOST (1<<5) +#define CR_CLKEN (1<<4) +#define CR_SOCS (1<<3) +#define CR_IOCS (1<<2) +#define CR_RSTCTL (1<<1) +#define CR_CFINT (1<<0) +#define CR_LOCK_MASK 0x5a000000 + + +#define ST40PCI_LSR0 0X14 +#define ST40PCI_LAR0 0x1c + +#define ST40PCI_INT 0x24 +#define INT_MADIM (1<<2) + + +#define ST40PCI_INTM 0x28 +#define ST40PCI_AIR 0x2c +#define ST40PCI_CIR 0x30 +#define ST40PCI_AINT 0x40 +#define ST40PCI_AINTM 0x44 +#define ST40PCI_BMIR 0x48 +#define ST40PCI_PAR 0x4c +#define ST40PCI_MBR 0x50 +#define ST40PCI_IOBR 0x54 +#define ST40PCI_PINT 0x58 +#define ST40PCI_PINTM 0x5c +#define ST40PCI_MBMR 0x70 +#define ST40PCI_IOBMR 0x74 +#define ST40PCI_PDR 0x78 + +/* These are configs space registers */ +#define ST40PCI_CSR_VID 0x10000 +#define ST40PCI_CSR_DID 0x10002 +#define ST40PCI_CSR_CMD 0x10004 +#define ST40PCI_CSR_STATUS 0x10006 +#define ST40PCI_CSR_MBAR0 0x10010 +#define ST40PCI_CSR_TRDY 0x10040 +#define ST40PCI_CSR_RETRY 0x10041 +#define ST40PCI_CSR_MIT 0x1000d + +#define ST40_IO_ADDR 0xb6000000 + +#endif /* __PCI_ST40_H__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/process.c linux.ac/arch/sh/kernel/process.c --- linux.vanilla/arch/sh/kernel/process.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/sh/kernel/process.c Mon Apr 16 12:37:04 2001 @@ -139,10 +139,6 @@ /* * 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. */ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { /* Don't use this in BL=1(cli). Or else, CPU resets! */ @@ -154,7 +150,7 @@ register unsigned long __sc9 __asm__ ("r9") = (long) fn; __asm__("trapa #0x12\n\t" /* Linux/SH system call */ - "tst #0xff, r0\n\t" /* child or parent? */ + "tst r0, r0\n\t" /* child or parent? */ "bf 1f\n\t" /* parent - jump */ "jsr @r9\n\t" /* call fn */ " mov r8, r4\n\t" /* push argument */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/ptrace.c linux.ac/arch/sh/kernel/ptrace.c --- linux.vanilla/arch/sh/kernel/ptrace.c Fri Dec 29 22:07:20 2000 +++ linux.ac/arch/sh/kernel/ptrace.c Sat Apr 14 01:18:22 2001 @@ -175,14 +175,16 @@ if (request == PTRACE_ATTACH) { if (child == tsk) goto out_tsk; - if ((!child->dumpable || - (tsk->uid != child->euid) || + if(((tsk->uid != child->euid) || (tsk->uid != child->suid) || (tsk->uid != child->uid) || (tsk->gid != child->egid) || (tsk->gid != child->sgid) || (!cap_issubset(child->cap_permitted, tsk->cap_permitted)) || (tsk->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) + goto out_tsk; + rmb(); + if (!child->dumpable && !capable(CAP_SYS_PTRACE)) goto out_tsk; /* the same process cannot be attached many times */ if (child->ptrace & PT_PTRACED) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/rtc.c linux.ac/arch/sh/kernel/rtc.c --- linux.vanilla/arch/sh/kernel/rtc.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/sh/kernel/rtc.c Sat Apr 14 01:18:22 2001 @@ -7,6 +7,7 @@ #include <linux/init.h> #include <linux/kernel.h> +#include <linux/sched.h> #include <linux/time.h> #include <asm/io.h> @@ -44,6 +45,8 @@ #define RMONAR 0xfffffeda #define RCR1 0xfffffedc #define RCR2 0xfffffede + +#define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */ #elif defined(__SH4__) /* SH-4 RTC */ #define R64CNT 0xffc80000 @@ -62,6 +65,8 @@ #define RMONAR 0xffc80034 #define RCR1 0xffc80038 #define RCR2 0xffc8003c + +#define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */ #endif #ifndef BCD_TO_BIN @@ -79,7 +84,7 @@ again: do { ctrl_outb(0, RCR1); /* Clear CF-bit */ - sec128 = ctrl_inb(RSECCNT); + sec128 = ctrl_inb(R64CNT); sec = ctrl_inb(RSECCNT); min = ctrl_inb(RMINCNT); hr = ctrl_inb(RHRCNT); @@ -96,6 +101,14 @@ #endif } while ((ctrl_inb(RCR1) & RCR1_CF) != 0); +#if RTC_BIT_INVERTED != 0 + /* Work around to avoid reading correct value. */ + if (sec128 == RTC_BIT_INVERTED) { + schedule_timeout(1); + goto again; + } +#endif + BCD_TO_BIN(yr100); BCD_TO_BIN(yr); BCD_TO_BIN(mon); @@ -125,7 +138,7 @@ } tv->tv_sec = mktime(yr100 * 100 + yr, mon, day, hr, min, sec); - tv->tv_usec = (sec128 * 1000000) / 128; + tv->tv_usec = ((sec128 ^ RTC_BIT_INVERTED) * 1000000) / 128; } static int set_rtc_time(unsigned long nowtime) @@ -170,5 +183,9 @@ int sh_rtc_settimeofday(const struct timeval *tv) { +#if RTC_BIT_INVERTED != 0 + /* This is not accurate, but better than nothing. */ + schedule_timeout(HZ/2); +#endif return set_rtc_time(tv->tv_sec); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/setup.c linux.ac/arch/sh/kernel/setup.c --- linux.vanilla/arch/sh/kernel/setup.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/sh/kernel/setup.c Sat Apr 14 01:18:22 2001 @@ -50,6 +50,7 @@ struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE, 0, 0, 0, }; struct screen_info screen_info; +unsigned char aux_device_present = 0xaa; #ifdef CONFIG_BLK_DEV_RAM extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ @@ -61,6 +62,19 @@ struct sh_machine_vector sh_mv; #endif +/* We need this to satisfy some external references. */ +struct screen_info screen_info = { + 0, 25, /* orig-x, orig-y */ + 0, /* unused */ + 0, /* orig-video-page */ + 0, /* orig-video-mode */ + 80, /* orig-video-cols */ + 0,0,0, /* ega_ax, ega_bx, ega_cx */ + 25, /* orig-video-lines */ + 0, /* orig-video-isVGA */ + 16 /* orig-video-points */ +}; + extern void fpu_init(void); extern int root_mountflags; extern int _text, _etext, _edata, _end; @@ -115,7 +129,7 @@ { "Kernel data", 0, 0 } }; -static unsigned long memory_start, memory_end; +unsigned long memory_start, memory_end; #ifdef CONFIG_SH_EARLY_PRINTK /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/setup_cqreek.c linux.ac/arch/sh/kernel/setup_cqreek.c --- linux.vanilla/arch/sh/kernel/setup_cqreek.c Mon Oct 2 19:57:34 2000 +++ linux.ac/arch/sh/kernel/setup_cqreek.c Sat Apr 14 01:18:22 2001 @@ -1,4 +1,4 @@ -/* $Id: setup_cqreek.c,v 1.5 2000/09/18 05:51:24 gniibe Exp $ +/* $Id: setup_cqreek.c,v 1.6 2001/02/14 09:36:42 gniibe Exp $ * * arch/sh/kernel/setup_cqreek.c * @@ -18,6 +18,7 @@ #include <asm/irq.h> #include <asm/machvec.h> #include <asm/machvec_init.h> +#include <asm/rtc.h> #define BRIDGE_FEATURE 0x0002 @@ -247,5 +248,11 @@ mv_init_irq: init_cqreek_IRQ, mv_isa_port2addr: cqreek_port2addr, + + mv_ioremap: generic_ioremap, + mv_iounmap: generic_iounmap, + + mv_rtc_gettimeofday: sh_rtc_gettimeofday, + mv_rtc_settimeofday: sh_rtc_settimeofday, }; ALIAS_MV(cqreek) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/setup_dc.c linux.ac/arch/sh/kernel/setup_dc.c --- linux.vanilla/arch/sh/kernel/setup_dc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/sh/kernel/setup_dc.c Sat Apr 14 01:18:22 2001 @@ -0,0 +1,360 @@ +/* + * $Id: setup_dc.c,v 1.1 2001/04/01 15:02:00 yaegashi Exp $ + * SEGA Dreamcast support + */ + +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/param.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/pci.h> + +#include <asm/io.h> +#include <asm/irq.h> + +#define GAPSPCI_REGS 0x01001400 +#define GAPSPCI_DMA_BASE 0x01840000 +#define GAPSPCI_DMA_SIZE 32768 +#define GAPSPCI_BBA_CONFIG 0x01001600 + +#define GAPSPCI_IRQ 11 +#define GAPSPCI_INTC 0x005f6924 + +static int gapspci_dma_used; + +static struct pci_bus *pci_root_bus; + +static void disable_gapspci_irq(unsigned int irq) +{ + unsigned long flags; + unsigned long intc; + + save_and_cli(flags); + intc = inl(GAPSPCI_INTC); + intc &= ~(1<<3); + outl(intc, GAPSPCI_INTC); + restore_flags(flags); +} + + +static void enable_gapspci_irq(unsigned int irq) +{ + unsigned long flags; + unsigned long intc; + + save_and_cli(flags); + intc = inl(GAPSPCI_INTC); + intc |= (1<<3); + outl(intc, GAPSPCI_INTC); + restore_flags(flags); +} + + +static void mask_and_ack_gapspci_irq(unsigned int irq) +{ + unsigned long flags; + unsigned long intc; + + save_and_cli(flags); + intc = inl(GAPSPCI_INTC); + intc &= ~(1<<3); + outl(intc, GAPSPCI_INTC); + restore_flags(flags); +} + + +static void end_gapspci_irq(unsigned int irq) +{ + enable_gapspci_irq(irq); +} + + +static unsigned int startup_gapspci_irq(unsigned int irq) +{ + enable_gapspci_irq(irq); + return 0; +} + + +static void shutdown_gapspci_irq(unsigned int irq) +{ + disable_gapspci_irq(irq); +} + + +static struct hw_interrupt_type gapspci_irq_type = { + "GAPSPCI-IRQ", + startup_gapspci_irq, + shutdown_gapspci_irq, + enable_gapspci_irq, + disable_gapspci_irq, + mask_and_ack_gapspci_irq, + end_gapspci_irq +}; + + +static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin) +{ + return PCI_SLOT(dev->devfn); +} + +static int __init map_od_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + return GAPSPCI_IRQ; +} + +int __init setup_dreamcast(void) +{ + gapspci_init(); + + printk(KERN_INFO "SEGA Dreamcast support.\n"); +#if 0 + printk(KERN_INFO "BCR1: 0x%08x\n", ctrl_inl(0xff800000)); + printk(KERN_INFO "BCR2: 0x%08x\n", ctrl_inw(0xff800004)); + printk(KERN_INFO "WCR1: 0x%08x\n", ctrl_inl(0xff800008)); + printk(KERN_INFO "WCR2: 0x%08x\n", ctrl_inl(0xff80000c)); + printk(KERN_INFO "WCR3: 0x%08x\n", ctrl_inl(0xff800010)); + printk(KERN_INFO "MCR: 0x%08x\n", ctrl_inl(0xff800014)); + printk(KERN_INFO "PCR: 0x%08x\n", ctrl_inw(0xff800018)); +/* + * BCR1: 0xa3020008 + * BCR2: 0x0001 + * WCR1: 0x01110111 + * WCR2: 0x618066d8 + * WCR3: 0x07777777 + * MCR: 0xc00a0e24 + * PCR: 0x0000 + */ +#endif + return 0; +} + + +/* + * Dreamcast PCI: Supports SEGA Broadband Adaptor only. + */ + +#define BBA_SELECTED(dev) (dev->bus->number==0 && dev->devfn==0) + +static int gapspci_read_config_byte(struct pci_dev *dev, int where, + u8 * val) +{ + if (BBA_SELECTED(dev)) + *val = inb(GAPSPCI_BBA_CONFIG+where); + else + *val = 0xff; + + return PCIBIOS_SUCCESSFUL; +} + +static int gapspci_read_config_word(struct pci_dev *dev, int where, + u16 * val) +{ + if (BBA_SELECTED(dev)) + *val = inw(GAPSPCI_BBA_CONFIG+where); + else + *val = 0xffff; + + return PCIBIOS_SUCCESSFUL; +} + +static int gapspci_read_config_dword(struct pci_dev *dev, int where, + u32 * val) +{ + if (BBA_SELECTED(dev)) + *val = inl(GAPSPCI_BBA_CONFIG+where); + else + *val = 0xffffffff; + + return PCIBIOS_SUCCESSFUL; +} + +static int gapspci_write_config_byte(struct pci_dev *dev, int where, + u8 val) +{ + if (BBA_SELECTED(dev)) + outb(val, GAPSPCI_BBA_CONFIG+where); + + return PCIBIOS_SUCCESSFUL; +} + + +static int gapspci_write_config_word(struct pci_dev *dev, int where, + u16 val) +{ + if (BBA_SELECTED(dev)) + outw(val, GAPSPCI_BBA_CONFIG+where); + + return PCIBIOS_SUCCESSFUL; +} + +static int gapspci_write_config_dword(struct pci_dev *dev, int where, + u32 val) +{ + if (BBA_SELECTED(dev)) + outl(val, GAPSPCI_BBA_CONFIG+where); + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops pci_config_ops = { + gapspci_read_config_byte, + gapspci_read_config_word, + gapspci_read_config_dword, + gapspci_write_config_byte, + gapspci_write_config_word, + gapspci_write_config_dword +}; + + +void pcibios_align_resource(void *data, struct resource *res, + unsigned long size) +{ +} + + +void __init pcibios_update_irq(struct pci_dev *dev, int irq) +{ +} + + +void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) +{ +} + + +int pcibios_enable_device(struct pci_dev *dev) +{ + + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for (idx = 0; idx < 6; idx++) { + r = dev->resource + idx; + if (!r->start && r->end) { + printk(KERN_ERR + "PCI: Device %s not available because" + " of resource collisions\n", + dev->slot_name); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (cmd != old_cmd) { + printk("PCI: enabling device %s (%04x -> %04x)\n", + dev->slot_name, old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; + +} + + +void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, + dma_addr_t * dma_handle) +{ + unsigned long buf; + + if (gapspci_dma_used+size > GAPSPCI_DMA_SIZE) + return NULL; + + buf = GAPSPCI_DMA_BASE+gapspci_dma_used; + + gapspci_dma_used = PAGE_ALIGN(gapspci_dma_used+size); + + printk("pci_alloc_consistent: %d bytes at 0x%08x\n", size, buf); + + *dma_handle = (dma_addr_t)buf; + + return (void *)P2SEGADDR(buf); +} + + +void pci_free_consistent(struct pci_dev *hwdev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ +} + + +void __init +pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges) +{ +} + +void __init pcibios_fixup_bus(struct pci_bus *bus) +{ + struct list_head *ln; + struct pci_dev *dev; + + for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) { + dev = pci_dev_b(ln); + if (!BBA_SELECTED(dev)) continue; + + printk("PCI: MMIO fixup to %s\n", dev->name); + dev->resource[1].start=0x01001700; + dev->resource[1].end=0x010017ff; + } +} + + +void __init dreamcast_pcibios_init(void) +{ + pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL); + /* pci_assign_unassigned_resources(); */ + pci_fixup_irqs(no_swizzle, map_od_irq); +} + + +static __init int gapspci_init(void) +{ + int i; + char idbuf[16]; + + for(i=0; i<16; i++) + idbuf[i]=inb(GAPSPCI_REGS+i); + + if(strncmp(idbuf, "GAPSPCI_BRIDGE_2", 16)) + return -1; + + outl(0x5a14a501, GAPSPCI_REGS+0x18); + + for(i=0; i<1000000; i++); + + if(inl(GAPSPCI_REGS+0x18)!=1) + return -1; + + outl(0x01000000, GAPSPCI_REGS+0x20); + outl(0x01000000, GAPSPCI_REGS+0x24); + + outl(GAPSPCI_DMA_BASE, GAPSPCI_REGS+0x28); + outl(GAPSPCI_DMA_BASE+GAPSPCI_DMA_SIZE, GAPSPCI_REGS+0x2c); + + outl(1, GAPSPCI_REGS+0x14); + outl(1, GAPSPCI_REGS+0x34); + + gapspci_dma_used=0; + + /* */ + irq_desc[GAPSPCI_IRQ].handler = &gapspci_irq_type; + + /* Setting Broadband Adapter */ + outw(0xf900, GAPSPCI_BBA_CONFIG+0x06); + outl(0x00000000, GAPSPCI_BBA_CONFIG+0x30); + outb(0x00, GAPSPCI_BBA_CONFIG+0x3c); + outb(0xf0, GAPSPCI_BBA_CONFIG+0x0d); + outw(0x0006, GAPSPCI_BBA_CONFIG+0x04); + outl(0x00002001, GAPSPCI_BBA_CONFIG+0x10); + outl(0x01000000, GAPSPCI_BBA_CONFIG+0x14); + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/setup_ec3104.c linux.ac/arch/sh/kernel/setup_ec3104.c --- linux.vanilla/arch/sh/kernel/setup_ec3104.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/sh/kernel/setup_ec3104.c Sat Apr 14 01:18:22 2001 @@ -0,0 +1,242 @@ +/* + * linux/arch/sh/kernel/setup_ec3104.c + * EC3104 companion chip support + * + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> + * + */ +/* EC3104 note: + * This code was written without any documentation about the EC3104 chip. While + * I hope I got most of the basic functionality right, the register names I use + * are most likely completely different from those in the chip documentation. + * + * If you have any further information about the EC3104, please tell me + * (prumpf@tux.org). + */ + +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/param.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/types.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/ec3104.h> + +/* This is for debugging mostly; here's the table that I intend to keep + * in here: + * + * index function base addr power interrupt bit + * 0 power b0ec0000 --- 00000001 (unused) + * 1 irqs b0ec1000 --- 00000002 (unused) + * 2 ?? b0ec2000 b0ec0008 00000004 + * 3 PS2 (1) b0ec3000 b0ec000c 00000008 + * 4 PS2 (2) b0ec4000 b0ec0010 00000010 + * 5 ?? b0ec5000 b0ec0014 00000020 + * 6 I2C b0ec6000 b0ec0018 00000040 + * 7 serial (1) b0ec7000 b0ec001c 00000080 + * 8 serial (2) b0ec8000 b0ec0020 00000100 + * 9 serial (3) b0ec9000 b0ec0024 00000200 + * 10 serial (4) b0eca000 b0ec0028 00000400 + * 12 GPIO (1) b0ecc000 b0ec0030 + * 13 GPIO (2) b0ecc000 b0ec0030 + * 16 pcmcia (1) b0ed0000 b0ec0040 00010000 + * 17 pcmcia (2) b0ed1000 b0ec0044 00020000 + */ + +/* I used the register names from another interrupt controller I worked with, + * since it seems to be identical to the ec3104 except that all bits are + * inverted: + * + * IRR: Interrupt Request Register (pending and enabled interrupts) + * IMR: Interrupt Mask Register (which interrupts are enabled) + * IPR: Interrupt Pending Register (pending interrupts, even disabled ones) + * + * 0 bits mean pending or enabled, 1 bits mean not pending or disabled. all + * IRQs seem to be level-triggered. + */ + +#define EC3104_IRR (EC3104_BASE + 0x1000) +#define EC3104_IMR (EC3104_BASE + 0x1004) +#define EC3104_IPR (EC3104_BASE + 0x1008) + +#define ctrl_readl(addr) (*(volatile u32 *)(addr)) +#define ctrl_writel(data,addr) (*(volatile u32 *)(addr) = (data)) +#define ctrl_readb(addr) (*(volatile u8 *)(addr)) + +static char *ec3104_name(unsigned index) +{ + switch(index) { + case 0: + return "power management"; + case 1: + return "interrupts"; + case 3: + return "PS2 (1)"; + case 4: + return "PS2 (2)"; + case 5: + return "I2C (1)"; + case 6: + return "I2C (2)"; + case 7: + return "serial (1)"; + case 8: + return "serial (2)"; + case 9: + return "serial (3)"; + case 10: + return "serial (4)"; + case 16: + return "pcmcia (1)"; + case 17: + return "pcmcia (2)"; + default: { + static char buf[32]; + + sprintf(buf, "unknown (%d)", index); + + return buf; + } + } +} + +int get_pending_interrupts(char *buf) +{ + u32 ipr; + u32 bit; + char *p = buf; + + p += sprintf(p, "pending: ("); + + ipr = ctrl_inl(EC3104_IPR); + + for (bit = 1; bit < 32; bit++) + if (!(ipr & (1<<bit))) + p += sprintf(p, "%s ", ec3104_name(bit)); + + p += sprintf(p, ")\n"); + + return p - buf; +} + +static inline u32 ec3104_irq2mask(unsigned int irq) +{ + return (1 << (irq - EC3104_IRQBASE)); +} + +static inline void mask_ec3104_irq(unsigned int irq) +{ + u32 mask; + + mask = ctrl_readl(EC3104_IMR); + + mask |= ec3104_irq2mask(irq); + + ctrl_writel(mask, EC3104_IMR); +} + +static inline void unmask_ec3104_irq(unsigned int irq) +{ + u32 mask; + + mask = ctrl_readl(EC3104_IMR); + + mask &= ~ec3104_irq2mask(irq); + + ctrl_writel(mask, EC3104_IMR); +} + +static void disable_ec3104_irq(unsigned int irq) +{ + mask_ec3104_irq(irq); +} + +static void enable_ec3104_irq(unsigned int irq) +{ + unmask_ec3104_irq(irq); +} + +static void mask_and_ack_ec3104_irq(unsigned int irq) +{ + mask_ec3104_irq(irq); +} + +static void end_ec3104_irq(unsigned int irq) +{ + unmask_ec3104_irq(irq); +} + +static unsigned int startup_ec3104_irq(unsigned int irq) +{ + unmask_ec3104_irq(irq); + + return 0; +} + +static void shutdown_ec3104_irq(unsigned int irq) +{ + mask_ec3104_irq(irq); + +} + +static struct hw_interrupt_type ec3104_int = { + typename: "EC3104", + enable: enable_ec3104_irq, + disable: disable_ec3104_irq, + ack: mask_and_ack_ec3104_irq, + end: end_ec3104_irq, + startup: startup_ec3104_irq, + shutdown: shutdown_ec3104_irq, +}; + +/* Yuck. the _demux API is ugly */ +int ec3104_irq_demux(int irq) +{ + if (irq == EC3104_IRQ) { + unsigned int mask; + + mask = ctrl_readl(EC3104_IRR); + + if (mask == 0xffffffff) + return EC3104_IRQ; + else + return EC3104_IRQBASE + ffz(mask); + } + + return irq; +} + +int __init setup_ec3104(void) +{ + char str[8]; + int i; + + if (!MACH_EC3104) + printk("!MACH_EC3104\n"); + + if (0) + return 0; + + for (i=0; i<8; i++) + str[i] = ctrl_readb(EC3104_BASE + i); + + for (i = EC3104_IRQBASE; i < EC3104_IRQBASE + 32; i++) + irq_desc[i].handler = &ec3104_int; + + printk("initializing EC3104 \"%.8s\" at %08x, IRQ %d, IRQ base %d\n", + str, EC3104_BASE, EC3104_IRQ, EC3104_IRQBASE); + + + /* mask all interrupts. this should have been done by the boot + * loader for us but we want to be sure ... */ + ctrl_writel(0xffffffff, EC3104_IMR); + + return 0; +} + +module_init(setup_ec3104); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/setup_hd64461.c linux.ac/arch/sh/kernel/setup_hd64461.c --- linux.vanilla/arch/sh/kernel/setup_hd64461.c Wed Aug 9 21:59:04 2000 +++ linux.ac/arch/sh/kernel/setup_hd64461.c Sat Apr 14 01:18:22 2001 @@ -88,7 +88,7 @@ static void hd64461_interrupt(int irq, void *dev_id, struct pt_regs *regs) { printk(KERN_INFO - "HD64461: spurious interrupt, nirr: 0x%lx nimr: 0x%lx\n", + "HD64461: spurious interrupt, nirr: 0x%x nimr: 0x%x\n", inw(HD64461_NIRR), inw(HD64461_NIMR)); } @@ -104,7 +104,7 @@ if (irq == 16) irq = CONFIG_HD64461_IRQ; else irq += HD64461_IRQBASE; } - return irq; + return __irq_demux(irq); } static struct irqaction irq0 = { hd64461_interrupt, SA_INTERRUPT, 0, "HD64461", NULL, NULL}; @@ -120,10 +120,9 @@ printk(KERN_INFO "HD64461 configured at 0x%x on irq %d(mapped into %d to %d)\n", CONFIG_HD64461_IOBASE, CONFIG_HD64461_IRQ, HD64461_IRQBASE, HD64461_IRQBASE+15); -#ifdef CONFIG_CPU_SUBTYPE_SH7709 - /* IRQ line for HD64461 should be set level trigger mode("10"). */ - /* And this should be done earlier than the kernel starts. */ - ctrl_outw(0x0200, INTC_ICR1); /* when connected to IRQ4. */ + +#if defined(CONFIG_CPU_SUBTYPE_SH7709) /* Should be at processor specific part.. */ + outw(0x2240, INTC_ICR1); #endif outw(0xffff, HD64461_NIMR); @@ -135,7 +134,7 @@ #ifdef CONFIG_HD64461_ENABLER printk(KERN_INFO "HD64461: enabling PCMCIA devices\n"); - outb(0x04, HD64461_PCC1CSCIER); + outb(0x4c, HD64461_PCC1CSCIER); outb(0x00, HD64461_PCC1CSCR); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/setup_hd64465.c linux.ac/arch/sh/kernel/setup_hd64465.c --- linux.vanilla/arch/sh/kernel/setup_hd64465.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/sh/kernel/setup_hd64465.c Sat Apr 14 01:18:22 2001 @@ -0,0 +1,207 @@ +/* + * $Id: setup_hd64465.c,v 1.3 2001/02/07 17:52:53 stuart_menefy Exp $ + * + * Setup and IRQ handling code for the HD64465 companion chip. + * by Greg Banks <gbanks@pocketpenguins.com> + * Copyright (c) 2000 PocketPenguins Inc + * + * Derived from setup_hd64461.c which bore the message: + * Copyright (C) 2000 YAEGASHI Takeshi + */ + +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/param.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/irq.h> + +#include <asm/io.h> +#include <asm/irq.h> + +#include <asm/hd64465.h> + +#undef HD64465_DEBUG + +#ifdef HD64465_DEBUG +#define DPRINTK(args...) printk(args) +#else +#define DPRINTK(args...) +#endif + +static void disable_hd64465_irq(unsigned int irq) +{ + unsigned long flags; + unsigned short nimr; + unsigned short mask = 1 << (irq - HD64465_IRQ_BASE); + + DPRINTK("disable_hd64465_irq(%d): mask=%x\n", irq, mask); + save_and_cli(flags); + nimr = inw(HD64465_REG_NIMR); + nimr |= mask; + outw(nimr, HD64465_REG_NIMR); + restore_flags(flags); +} + + +static void enable_hd64465_irq(unsigned int irq) +{ + unsigned long flags; + unsigned short nimr; + unsigned short mask = 1 << (irq - HD64465_IRQ_BASE); + + DPRINTK("enable_hd64465_irq(%d): mask=%x\n", irq, mask); + save_and_cli(flags); + nimr = inw(HD64465_REG_NIMR); + nimr &= ~mask; + outw(nimr, HD64465_REG_NIMR); + restore_flags(flags); +} + + +static void mask_and_ack_hd64465(unsigned int irq) +{ + disable_hd64465_irq(irq); +} + + +static void end_hd64465_irq(unsigned int irq) +{ + enable_hd64465_irq(irq); +} + + +static unsigned int startup_hd64465_irq(unsigned int irq) +{ + enable_hd64465_irq(irq); + return 0; +} + + +static void shutdown_hd64465_irq(unsigned int irq) +{ + disable_hd64465_irq(irq); +} + + +static struct hw_interrupt_type hd64465_irq_type = { + typename: "HD64465-IRQ", + startup: startup_hd64465_irq, + shutdown: shutdown_hd64465_irq, + enable: enable_hd64465_irq, + disable: disable_hd64465_irq, + ack: mask_and_ack_hd64465, + end: end_hd64465_irq +}; + + +static void hd64465_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + printk(KERN_INFO + "HD64465: spurious interrupt, nirr: 0x%x nimr: 0x%x\n", + inw(HD64465_REG_NIRR), inw(HD64465_REG_NIMR)); +} + + +/*====================================================*/ + +/* + * Support for a secondary IRQ demux step. This is necessary + * because the HD64465 presents a very thin interface to the + * PCMCIA bus; a lot of features (such as remapping interrupts) + * normally done in hardware by other PCMCIA host bridges is + * instead done in software. + */ +static struct +{ + int (*func)(int, void *); + void *dev; +} hd64465_demux[HD64465_IRQ_NUM]; + +void hd64465_register_irq_demux(int irq, + int (*demux)(int irq, void *dev), void *dev) +{ + hd64465_demux[irq - HD64465_IRQ_BASE].func = demux; + hd64465_demux[irq - HD64465_IRQ_BASE].dev = dev; +} +EXPORT_SYMBOL(hd64465_register_irq_demux); + +void hd64465_unregister_irq_demux(int irq) +{ + hd64465_demux[irq - HD64465_IRQ_BASE].func = 0; +} +EXPORT_SYMBOL(hd64465_unregister_irq_demux); + + + +int hd64465_irq_demux(int irq) +{ + if (irq == CONFIG_HD64465_IRQ) { + unsigned short i, bit; + unsigned short nirr = inw(HD64465_REG_NIRR); + unsigned short nimr = inw(HD64465_REG_NIMR); + + DPRINTK("hd64465_irq_demux, nirr=%04x, nimr=%04x\n", nirr, nimr); + nirr &= ~nimr; + for (bit = 1, i = 0 ; i < HD64465_IRQ_NUM ; bit <<= 1, i++) + if (nirr & bit) + break; + + if (i < HD64465_IRQ_NUM) { + irq = HD64465_IRQ_BASE + i; + if (hd64465_demux[i].func != 0) + irq = hd64465_demux[i].func(irq, hd64465_demux[i].dev); + } + } + return irq; +} + +static struct irqaction irq0 = { hd64465_interrupt, SA_INTERRUPT, 0, "HD64465", NULL, NULL}; + + +static int __init setup_hd64465(void) +{ + int i; + unsigned short rev; + unsigned short smscr; + + if (!MACH_HD64465) + return 0; + + printk(KERN_INFO "HD64465 configured at 0x%x on irq %d(mapped into %d to %d)\n", + CONFIG_HD64465_IOBASE, + CONFIG_HD64465_IRQ, + HD64465_IRQ_BASE, + HD64465_IRQ_BASE+HD64465_IRQ_NUM-1); + + if (inw(HD64465_REG_SDID) != HD64465_SDID) { + printk(KERN_ERR "HD64465 device ID not found, check base address\n"); + } + + rev = inw(HD64465_REG_SRR); + printk(KERN_INFO "HD64465 hardware revision %d.%d\n", (rev >> 8) & 0xff, rev & 0xff); + + outw(0xffff, HD64465_REG_NIMR); /* mask all interrupts */ + + for (i = 0; i < HD64465_IRQ_NUM ; i++) { + irq_desc[HD64465_IRQ_BASE + i].handler = &hd64465_irq_type; + } + + setup_irq(CONFIG_HD64465_IRQ, &irq0); + +#ifdef CONFIG_SERIAL + /* wake up the UART from STANDBY at this point */ + smscr = inw(HD64465_REG_SMSCR); + outw(smscr & (~HD64465_SMSCR_UARTST), HD64465_REG_SMSCR); + + /* remap IO ports for first ISA serial port to HD64465 UART */ + hd64465_port_map(0x3f8, 8, CONFIG_HD64465_IOBASE + 0x8000, 1); +#endif + + return 0; +} + +module_init(setup_hd64465); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/sh_ksyms.c linux.ac/arch/sh/kernel/sh_ksyms.c --- linux.vanilla/arch/sh/kernel/sh_ksyms.c Tue Apr 3 17:31:57 2001 +++ linux.ac/arch/sh/kernel/sh_ksyms.c Sat Apr 14 01:18:22 2001 @@ -17,6 +17,7 @@ #include <asm/io.h> #include <asm/hardirq.h> #include <asm/delay.h> +#include <asm/pgalloc.h> #include <linux/irq.h> extern void dump_thread(struct pt_regs *, struct user *); @@ -45,6 +46,7 @@ EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strncat); /* mem exports */ EXPORT_SYMBOL(memchr); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/kernel/time.c linux.ac/arch/sh/kernel/time.c --- linux.vanilla/arch/sh/kernel/time.c Thu Jan 4 21:19:13 2001 +++ linux.ac/arch/sh/kernel/time.c Sat Apr 14 01:18:22 2001 @@ -57,6 +57,13 @@ #define TMU0_TCR 0xffd80010 /* Word access */ #define FRQCR 0xffc00000 + +/* Core Processor Version Register */ +#define CCN_PVR 0xff000030 +#define CCN_PVR_CHIP_SHIFT 24 +#define CCN_PVR_CHIP_MASK 0xff +#define CCN_PVR_CHIP_ST40STB1 0x4 + #endif extern rwlock_t xtime_lock; @@ -289,13 +296,62 @@ static int ifc_table[] = { 1, 2, 3, 4, 6, 8, 1, 1 }; #define bfc_table ifc_table /* Same */ static int pfc_table[] = { 2, 3, 4, 6, 8, 2, 2, 2 }; + +#ifdef CONFIG_CPU_SUBTYPE_ST40STB1 + struct frqcr_data { + unsigned short frqcr; + struct { + unsigned char multiplier; + unsigned char divisor; + } factor[3]; + }; + + static struct frqcr_data st40_frqcr_table[] = { + { 0x000, {{1,1}, {1,1}, {1,2}}}, + { 0x002, {{1,1}, {1,1}, {1,4}}}, + { 0x004, {{1,1}, {1,1}, {1,8}}}, + { 0x008, {{1,1}, {1,2}, {1,2}}}, + { 0x00A, {{1,1}, {1,2}, {1,4}}}, + { 0x00C, {{1,1}, {1,2}, {1,8}}}, + { 0x011, {{1,1}, {2,3}, {1,6}}}, + { 0x013, {{1,1}, {2,3}, {1,3}}}, + { 0x01A, {{1,1}, {1,2}, {1,4}}}, + { 0x01C, {{1,1}, {1,2}, {1,8}}}, + { 0x023, {{1,1}, {2,3}, {1,3}}}, + { 0x02C, {{1,1}, {1,2}, {1,8}}}, + { 0x048, {{1,2}, {1,2}, {1,4}}}, + { 0x04A, {{1,2}, {1,2}, {1,6}}}, + { 0x04C, {{1,2}, {1,2}, {1,8}}}, + { 0x05A, {{1,2}, {1,3}, {1,6}}}, + { 0x05C, {{1,2}, {1,3}, {1,6}}}, + { 0x063, {{1,2}, {1,4}, {1,4}}}, + { 0x06C, {{1,2}, {1,4}, {1,8}}}, + { 0x091, {{1,3}, {1,3}, {1,6}}}, + { 0x093, {{1,3}, {1,3}, {1,6}}}, + { 0x0A3, {{1,3}, {1,6}, {1,6}}}, + { 0x0DA, {{1,4}, {1,4}, {1,8}}}, + { 0x0DC, {{1,4}, {1,4}, {1,8}}}, + { 0x0EC, {{1,4}, {1,8}, {1,8}}}, + { 0x123, {{1,4}, {1,4}, {1,8}}}, + { 0x16C, {{1,4}, {1,8}, {1,8}}}, + }; +#endif #endif +#if defined(CONFIG_SH_DREAMCAST) + xtime.tv_sec = 0; + xtime.tv_usec = 0; +#else rtc_gettimeofday(&xtime); +#endif setup_irq(TIMER_IRQ, &irq0); +#if defined(CONFIG_SH_DREAMCAST) + timer_freq = 50*1000*1000/4; +#else timer_freq = get_timer_frequency(); +#endif module_clock = timer_freq * 4; @@ -316,15 +372,53 @@ } #elif defined(__SH4__) { + unsigned long pvr; frqcr = ctrl_inw(FRQCR); - ifc = ifc_table[(frqcr>> 6) & 0x0007]; - bfc = bfc_table[(frqcr>> 3) & 0x0007]; - pfc = pfc_table[frqcr & 0x0007]; + +#ifdef CONFIG_CPU_SUBTYPE_ST40STB1 + /* This should probably be moved into the SH3 probing code, and then use the processor + * structure to determine which CPU we are running on. + */ + pvr = ctrl_inl(CCN_PVR); + printk("PVR %08x\n", pvr); + + if (((pvr >>CCN_PVR_CHIP_SHIFT) & CCN_PVR_CHIP_MASK) == CCN_PVR_CHIP_ST40STB1) { + /* Unfortunatly the STB1 FRQCR values are different from the 7750 ones */ + struct frqcr_data *d; + int a; + + for (a=0; a<ARRAY_SIZE(st40_frqcr_table); a++) { + d = &st40_frqcr_table[a]; + if (d->frqcr == (frqcr & 0x1ff)) + break; + } + if (a == ARRAY_SIZE(st40_frqcr_table)) { + d = st40_frqcr_table; + printk("ERROR: Unrecognised FRQCR value, using default multipliers\n"); + } + + printk("Clock multipliers: CPU: %d/%d Bus: %d/%d Periph: %d/%d\n", + d->factor[0].multiplier, d->factor[0].divisor, + d->factor[1].multiplier, d->factor[1].divisor, + d->factor[2].multiplier, d->factor[2].divisor); + + master_clock = module_clock * d->factor[2].divisor / d->factor[2].multiplier; + bus_clock = master_clock * d->factor[1].multiplier / d->factor[1].divisor; + cpu_clock = master_clock * d->factor[0].multiplier / d->factor[0].divisor; + goto skip_calc; + } else +#endif + { + ifc = ifc_table[(frqcr>> 6) & 0x0007]; + bfc = bfc_table[(frqcr>> 3) & 0x0007]; + pfc = pfc_table[frqcr & 0x0007]; + } } #endif master_clock = module_clock * pfc; bus_clock = master_clock / bfc; cpu_clock = master_clock / ifc; + skip_calc: printk("CPU clock: %d.%02dMHz\n", (cpu_clock / 1000000), (cpu_clock % 1000000)/10000); printk("Bus clock: %d.%02dMHz\n", diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/mm/cache.c linux.ac/arch/sh/mm/cache.c --- linux.vanilla/arch/sh/mm/cache.c Mon Jan 29 02:56:00 2001 +++ linux.ac/arch/sh/mm/cache.c Sat Apr 14 01:18:22 2001 @@ -148,7 +148,13 @@ cpu_data->type = CPU_SH7729; } #elif defined(__SH4__) +#ifdef CONFIG_CPU_SUBTYPE_ST40STB1 + cpu_data->type = CPU_ST40STB1; +#elif defined(CONFIG_CPU_SUBTYPE_SH7750) cpu_data->type = CPU_SH7750; +#else +#error Unknown SH4 CPU type +#endif #endif } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/mm/extable.c linux.ac/arch/sh/mm/extable.c --- linux.vanilla/arch/sh/mm/extable.c Wed Nov 10 16:31:37 1999 +++ linux.ac/arch/sh/mm/extable.c Sat Apr 14 01:18:22 2001 @@ -46,7 +46,7 @@ /* The kernel is the last "module" -- no need to treat it special. */ struct module *mp; for (mp = module_list; mp != NULL; mp = mp->next) { - if (mp->ex_table_start == NULL) + if (mp->ex_table_start == NULL || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING))) continue; ret = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/mm/init.c linux.ac/arch/sh/mm/init.c --- linux.vanilla/arch/sh/mm/init.c Wed Nov 29 06:43:39 2000 +++ linux.ac/arch/sh/mm/init.c Sat Apr 14 01:18:22 2001 @@ -34,6 +34,9 @@ #include <asm/pgalloc.h> #include <asm/mmu_context.h> #include <asm/io.h> +#include <asm/tlb.h> + +mmu_gather_t mmu_gathers[NR_CPUS]; /* * Cache of MMU context last used. @@ -45,104 +48,25 @@ extern unsigned long init_smp_mappings(unsigned long); -/* - * BAD_PAGE is the page that is used for page faults when linux - * is out-of-memory. Older versions of linux just did a - * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving an inode - * unused etc.. - * - * BAD_PAGETABLE is the accompanying page-table: it is initialized - * to point to BAD_PAGE entries. - * - * ZERO_PAGE is a special page that is used for zero-initialized - * data and COW. - */ - -unsigned long empty_bad_page[1024]; -pte_t empty_bad_pte_table[PTRS_PER_PTE]; extern unsigned long empty_zero_page[1024]; -static pte_t * get_bad_pte_table(void) -{ - pte_t v; - int i; - - v = pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED)); - - for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++) - empty_bad_pte_table[i] = v; - - return empty_bad_pte_table; -} - -void __handle_bad_pmd(pmd_t *pmd) -{ - pmd_ERROR(*pmd); - set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(get_bad_pte_table()))); -} - -void __handle_bad_pmd_kernel(pmd_t *pmd) -{ - pmd_ERROR(*pmd); - set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(get_bad_pte_table()))); -} - -pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - clear_page(pte); - set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte))); - return pte + offset; - } - set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(get_bad_pte_table()))); - return NULL; - } - free_page((unsigned long)pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - -pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) -{ - unsigned long pte; - - pte = (unsigned long) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - clear_page((void *)pte); - set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))); - return (pte_t *)pte + offset; - } - set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(get_bad_pte_table()))); - return NULL; - } - free_page(pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - int do_check_pgt_cache(int low, int high) { int freed = 0; if (pgtable_cache_size > high) { do { - if (pgd_quicklist) - free_pgd_slow(get_pgd_fast()), freed++; - if (pmd_quicklist) - free_pmd_slow(get_pmd_fast()), freed++; - if (pte_quicklist) - free_pte_slow(get_pte_fast()), freed++; + if (pgd_quicklist) { + free_pgd_slow(get_pgd_fast()); + freed++; + } + if (pmd_quicklist) { + pmd_free_slow(pmd_alloc_one_fast(NULL, 0)); + freed++; + } + if (pte_quicklist) { + pte_free_slow(pte_alloc_one_fast(NULL, 0)); + freed++; + } } while (pgtable_cache_size > low); } return freed; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sh/mm/ioremap.c linux.ac/arch/sh/mm/ioremap.c --- linux.vanilla/arch/sh/mm/ioremap.c Fri Oct 13 20:06:52 2000 +++ linux.ac/arch/sh/mm/ioremap.c Sat Apr 14 01:18:22 2001 @@ -25,14 +25,18 @@ end = address + size; if (end > PMD_SIZE) end = PMD_SIZE; + if (address >= end) + BUG(); do { - if (!pte_none(*pte)) + if (!pte_none(*pte)) { printk("remap_area_pte: page already exists\n"); + BUG(); + } set_pte(pte, mk_pte_phys(phys_addr, pgprot)); address += PAGE_SIZE; phys_addr += PAGE_SIZE; pte++; - } while (address < end); + } while (address && address < end); } static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, @@ -45,38 +49,48 @@ if (end > PGDIR_SIZE) end = PGDIR_SIZE; phys_addr -= address; + if (address >= end) + BUG(); do { - pte_t * pte = pte_alloc_kernel(pmd, address); + pte_t * pte = pte_alloc(&init_mm, pmd, address); if (!pte) return -ENOMEM; remap_area_pte(pte, address, end - address, address + phys_addr, flags); address = (address + PMD_SIZE) & PMD_MASK; pmd++; - } while (address < end); + } while (address && address < end); return 0; } static int remap_area_pages(unsigned long address, unsigned long phys_addr, - unsigned long size, unsigned long flags) + unsigned long size, unsigned long flags) { + int error; pgd_t * dir; unsigned long end = address + size; phys_addr -= address; - dir = pgd_offset_k(address); + dir = pgd_offset(&init_mm, address); flush_cache_all(); - while (address < end) { - pmd_t *pmd = pmd_alloc_kernel(dir, address); + if (address >= end) + BUG(); + spin_lock(&init_mm.page_table_lock); + do { + pmd_t *pmd; + pmd = pmd_alloc(&init_mm, dir, address); + error = -ENOMEM; if (!pmd) - return -ENOMEM; + break; if (remap_area_pmd(pmd, address, end - address, phys_addr + address, flags)) - return -ENOMEM; + break; + error = 0; address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; - } + } while (address && (address < end)); + spin_unlock(&init_mm.page_table_lock); flush_tlb_all(); - return 0; + return error; } /* @@ -106,7 +120,7 @@ /* * Don't remap the low PCI/ISA area, it's always mapped.. */ - if (phys_addr >= 0xA0000 && last_addr <= 0x100000) + if (phys_addr >= 0xA0000 && last_addr < 0x100000) return phys_to_virt(phys_addr); /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc/kernel/irq.c linux.ac/arch/sparc/kernel/irq.c --- linux.vanilla/arch/sparc/kernel/irq.c Mon Feb 19 03:49:44 2001 +++ linux.ac/arch/sparc/kernel/irq.c Tue Apr 3 17:54:36 2001 @@ -8,7 +8,7 @@ * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1995 Pete A. Zaitcev (zaitcev@metabyte.com) * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) - * Copyright (C) 1998-2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 1998-2000 Anton Blanchard (anton@samba.org) */ #include <linux/config.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc/kernel/setup.c linux.ac/arch/sparc/kernel/setup.c --- linux.vanilla/arch/sparc/kernel/setup.c Mon Feb 19 03:49:54 2001 +++ linux.ac/arch/sparc/kernel/setup.c Tue Apr 3 17:54:36 2001 @@ -2,7 +2,7 @@ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 2000 Anton Blanchard (anton@samba.org) */ #include <linux/errno.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc/kernel/sys_sparc.c linux.ac/arch/sparc/kernel/sys_sparc.c --- linux.vanilla/arch/sparc/kernel/sys_sparc.c Tue Apr 3 17:31:57 2001 +++ linux.ac/arch/sparc/kernel/sys_sparc.c Sat Apr 14 01:18:22 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.68 2001/03/24 09:36:10 davem Exp $ +/* $Id: sys_sparc.c,v 1.69 2001/03/27 02:36:37 davem Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that @@ -36,19 +36,28 @@ #define COLOUR_ALIGN(addr) (((addr)+SHMLBA-1)&~(SHMLBA-1)) -unsigned long get_unmapped_area(unsigned long addr, unsigned long len) +unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { struct vm_area_struct * vmm; + if (flags & MAP_FIXED) { + /* We do not accept a shared mapping if it would violate + * cache aliasing constraints. + */ + if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1))) + return -EINVAL; + return addr; + } + /* See asm-sparc/uaccess.h */ if (len > TASK_SIZE - PAGE_SIZE) - return 0; + return -ENOMEM; if (ARCH_SUN4C_SUN4 && len > 0x20000000) - return 0; + return -ENOMEM; if (!addr) addr = TASK_UNMAPPED_BASE; - if (current->thread.flags & SPARC_FLAG_MMAPSHARED) + if (flags & MAP_SHARED) addr = COLOUR_ALIGN(addr); else addr = PAGE_ALIGN(addr); @@ -60,11 +69,11 @@ vmm = find_vma(current->mm, PAGE_OFFSET); } if (TASK_SIZE - PAGE_SIZE - len < addr) - return 0; + return -ENOMEM; if (!vmm || addr + len <= vmm->vm_start) return addr; addr = vmm->vm_end; - if (current->thread.flags & SPARC_FLAG_MMAPSHARED) + if (flags & MAP_SHARED) addr = COLOUR_ALIGN(addr); } } @@ -233,15 +242,10 @@ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (flags & MAP_SHARED) - current->thread.flags |= SPARC_FLAG_MMAPSHARED; - down_write(¤t->mm->mmap_sem); retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); up_write(¤t->mm->mmap_sem); - current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED); - out_putf: if (file) fput(file); @@ -285,9 +289,6 @@ new_len > TASK_SIZE - PAGE_SIZE) goto out; down_write(¤t->mm->mmap_sem); - vma = find_vma(current->mm, addr); - if (vma && (vma->vm_flags & VM_SHARED)) - current->thread.flags |= SPARC_FLAG_MMAPSHARED; if (flags & MREMAP_FIXED) { if (ARCH_SUN4C_SUN4 && new_addr < 0xe0000000 && @@ -298,17 +299,31 @@ } else if ((ARCH_SUN4C_SUN4 && addr < 0xe0000000 && addr + new_len > 0x20000000) || addr + new_len > TASK_SIZE - PAGE_SIZE) { + unsigned long (*get_addr)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); + unsigned long map_flags = 0; + struct file *file = NULL; + ret = -ENOMEM; if (!(flags & MREMAP_MAYMOVE)) goto out_sem; - new_addr = get_unmapped_area (addr, new_len); - if (!new_addr) + + vma = find_vma(current->mm, addr); + if (vma) { + if (vma->vm_flags & VM_SHARED) + map_flags |= MAP_SHARED; + file = vma->vm_file; + } + + new_addr = get_unmapped_area(file, addr, new_len, + vma ? vma->vm_pgoff : 0, + map_flags); + ret = new_addr; + if (new_addr & ~PAGE_MASK) goto out_sem; flags |= MREMAP_FIXED; } ret = do_mremap(addr, old_len, new_len, flags, new_addr); out_sem: - current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED); up_write(¤t->mm->mmap_sem); out: return ret; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc/kernel/sys_sunos.c linux.ac/arch/sparc/kernel/sys_sunos.c --- linux.vanilla/arch/sparc/kernel/sys_sunos.c Tue Apr 3 17:31:57 2001 +++ linux.ac/arch/sparc/kernel/sys_sunos.c Tue Apr 3 17:54:36 2001 @@ -605,7 +605,7 @@ struct sunos_nfs_mount_args { struct sockaddr_in *addr; /* file server address */ - struct nfs_fh *fh; /* File handle to be mounted */ + struct nfs3_fh *fh; /* File handle to be mounted */ int flags; /* flags */ int wsize; /* write size in bytes */ int rsize; /* read size in bytes */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc/lib/debuglocks.c linux.ac/arch/sparc/lib/debuglocks.c --- linux.vanilla/arch/sparc/lib/debuglocks.c Fri Sep 10 19:06:19 1999 +++ linux.ac/arch/sparc/lib/debuglocks.c Tue Apr 3 17:54:36 2001 @@ -29,11 +29,9 @@ static inline void show(char *str, spinlock_t *lock, unsigned long caller) { int cpu = smp_processor_id(); - extern spinlock_t console_lock; - if (lock != &console_lock) - printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n",str, - lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); + printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n",str, + lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); } static inline void show_read(char *str, rwlock_t *lock, unsigned long caller) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc/lib/memset.S linux.ac/arch/sparc/lib/memset.S --- linux.vanilla/arch/sparc/lib/memset.S Tue Jun 20 01:59:38 2000 +++ linux.ac/arch/sparc/lib/memset.S Sat Apr 14 01:18:32 2001 @@ -188,7 +188,7 @@ b 30f add %o0, %o1, %o0 30: -/* %o4 is faulting address, %o5 is %pc where fault occured */ +/* %o4 is faulting address, %o5 is %pc where fault occurred */ save %sp, -104, %sp mov %i5, %o0 mov %i7, %o1 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc/mm/fault.c linux.ac/arch/sparc/mm/fault.c --- linux.vanilla/arch/sparc/mm/fault.c Tue Apr 3 17:31:57 2001 +++ linux.ac/arch/sparc/mm/fault.c Tue Apr 3 17:54:36 2001 @@ -378,7 +378,7 @@ pmd = pmd_offset(pgd, address); pmd_k = pmd_offset(pgd_k, address); - if (pmd_present(*pmd) || !pmd_present(*pmd_k)) + if (!pmd_present(*pmd_k)) goto bad_area_nosemaphore; pmd_val(*pmd) = pmd_val(*pmd_k); return; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc/mm/generic.c linux.ac/arch/sparc/mm/generic.c --- linux.vanilla/arch/sparc/mm/generic.c Wed Aug 9 21:49:55 2000 +++ linux.ac/arch/sparc/mm/generic.c Sat Apr 14 01:18:37 2001 @@ -1,4 +1,4 @@ -/* $Id: generic.c,v 1.10 2000/08/09 00:00:15 davem Exp $ +/* $Id: generic.c,v 1.12 2001/04/09 21:40:46 davem Exp $ * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * @@ -21,11 +21,7 @@ struct page *ptpage = pte_page(page); if ((!VALID_PAGE(ptpage)) || PageReserved(ptpage)) return; - /* - * free_page() used to be able to clear swap cache - * entries. We may now have to do it manually. - */ - free_page_and_swap_cache(ptpage); + page_cache_release(ptpage); return; } swap_free(pte_to_swp_entry(page)); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc/mm/init.c linux.ac/arch/sparc/mm/init.c --- linux.vanilla/arch/sparc/mm/init.c Tue Apr 3 17:31:57 2001 +++ linux.ac/arch/sparc/mm/init.c Tue Apr 3 17:54:36 2001 @@ -1,10 +1,10 @@ -/* $Id: init.c,v 1.97 2001/02/26 02:57:34 anton Exp $ +/* $Id: init.c,v 1.96 2000/11/30 08:51:50 anton Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com.au) + * Copyright (C) 2000 Anton Blanchard (anton@samba.org) */ #include <linux/config.h> @@ -32,6 +32,9 @@ #include <asm/page.h> #include <asm/pgtable.h> #include <asm/vaddrs.h> +#include <asm/tlb.h> + +mmu_gather_t mmu_gathers[NR_CPUS]; unsigned long *sparc_valid_addr_bitmap; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc/mm/srmmu.c linux.ac/arch/sparc/mm/srmmu.c --- linux.vanilla/arch/sparc/mm/srmmu.c Tue Apr 3 17:31:57 2001 +++ linux.ac/arch/sparc/mm/srmmu.c Tue Apr 3 17:54:36 2001 @@ -5,7 +5,7 @@ * Copyright (C) 1995 Pete Zaitcev * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - * Copyright (C) 1999,2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 1999,2000 Anton Blanchard (anton@samba.org) */ #include <linux/config.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc/mm/sun4c.c linux.ac/arch/sparc/mm/sun4c.c --- linux.vanilla/arch/sparc/mm/sun4c.c Tue Apr 3 17:31:57 2001 +++ linux.ac/arch/sparc/mm/sun4c.c Tue Apr 3 17:54:36 2001 @@ -4,7 +4,7 @@ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1996 Andrew Tridgell (Andrew.Tridgell@anu.edu.au) - * Copyright (C) 1997-2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 1997-2000 Anton Blanchard (anton@samba.org) * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/config.in linux.ac/arch/sparc64/config.in --- linux.vanilla/arch/sparc64/config.in Tue Apr 3 17:31:57 2001 +++ linux.ac/arch/sparc64/config.in Sat Apr 14 01:19:45 2001 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.136 2001/03/24 06:04:24 davem Exp $ +# $Id: config.in,v 1.139 2001/01/18 04:47:44 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -21,6 +21,8 @@ mainmenu_option next_comment comment 'General setup' +tristate 'UltraSPARC-III bootbus i2c controller driver' CONFIG_BBC_I2C + define_bool CONFIG_VT y define_bool CONFIG_VT_CONSOLE y @@ -202,6 +204,8 @@ endmenu fi endmenu + +source drivers/message/fusion/Config.in source drivers/fc4/Config.in diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/defconfig linux.ac/arch/sparc64/defconfig --- linux.vanilla/arch/sparc64/defconfig Tue Apr 3 17:31:57 2001 +++ linux.ac/arch/sparc64/defconfig Sat Apr 14 01:18:50 2001 @@ -17,6 +17,7 @@ # # General setup # +CONFIG_BBC_I2C=m CONFIG_VT=y CONFIG_VT_CONSOLE=y # CONFIG_SMP is not set @@ -307,7 +308,7 @@ CONFIG_SCSI_QLOGICPTI=m CONFIG_SCSI_AIC7XXX=m CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 -CONFIG_AIC7XXX_RESET_DELAY=5000 +CONFIG_AIC7XXX_RESET_DELAY_MS=5000 CONFIG_SCSI_AIC7XXX_OLD=m CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT=y CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8 @@ -519,11 +520,13 @@ # 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_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_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set # CONFIG_NLS_ISO8859_1 is not set # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set @@ -531,11 +534,12 @@ # 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_13 is not set # CONFIG_NLS_ISO8859_14 is not set # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set # CONFIG_NLS_UTF8 is not set # @@ -606,7 +610,6 @@ # USB Serial Converter support # CONFIG_USB_SERIAL=m -# CONFIG_USB_SERIAL_DEBUG is not set CONFIG_USB_SERIAL_GENERIC=y CONFIG_USB_SERIAL_BELKIN=m CONFIG_USB_SERIAL_WHITEHEAT=m diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/Makefile linux.ac/arch/sparc64/kernel/Makefile --- linux.vanilla/arch/sparc64/kernel/Makefile Tue Apr 3 17:31:57 2001 +++ linux.ac/arch/sparc64/kernel/Makefile Sat Apr 14 01:18:50 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.64 2001/02/28 05:59:45 davem Exp $ +# $Id: Makefile,v 1.66 2001/04/03 12:29:38 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -24,7 +24,7 @@ traps.o devices.o auxio.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ unaligned.o central.o pci.o starfire.o semaphore.o \ - power.o sbus.o iommu_common.o sparc64_ksyms.o + power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o obj-$(CONFIG_PCI) += ebus.o pci_common.o pci_iommu.o \ pci_psycho.o pci_sabre.o pci_schizo.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/chmc.c linux.ac/arch/sparc64/kernel/chmc.c --- linux.vanilla/arch/sparc64/kernel/chmc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/sparc64/kernel/chmc.c Sat Apr 14 01:18:50 2001 @@ -0,0 +1,451 @@ +/* $Id: chmc.c,v 1.3 2001/04/03 12:49:47 davem Exp $ + * memctrlr.c: Driver for UltraSPARC-III memory controller. + * + * Copyright (C) 2001 David S. Miller (davem@redhat.com) + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/list.h> +#include <linux/init.h> +#include <asm/spitfire.h> +#include <asm/chmctrl.h> +#include <asm/oplib.h> +#include <asm/io.h> + +#define CHMCTRL_NDGRPS 2 +#define CHMCTRL_NDIMMS 4 + +#define DIMMS_PER_MC (CHMCTRL_NDGRPS * CHMCTRL_NDIMMS) + +/* OBP memory-layout property format. */ +struct obp_map { + unsigned char dimm_map[144]; + unsigned char pin_map[576]; +}; + +#define DIMM_LABEL_SZ 8 + +struct obp_mem_layout { + /* One max 8-byte string label per DIMM. Usually + * this matches the label on the motherboard where + * that DIMM resides. + */ + char dimm_labels[DIMMS_PER_MC][DIMM_LABEL_SZ]; + + /* If symmetric use map[0], else it is + * asymmetric and map[1] should be used. + */ + char symmetric; + + struct obp_map map[2]; +}; + +#define CHMCTRL_NBANKS 4 + +struct bank_info { + struct mctrl_info *mp; + int bank_id; + + u64 raw_reg; + int valid; + int uk; + int um; + int lk; + int lm; + int interleave; + unsigned long base; + unsigned long size; +}; + +struct mctrl_info { + struct list_head list; + int portid; + int index; + + struct obp_mem_layout layout_prop; + int layout_size; + + void *regs; + + u64 timing_control1; + u64 timing_control2; + u64 timing_control3; + u64 timing_control4; + u64 memaddr_control; + + struct bank_info logical_banks[CHMCTRL_NBANKS]; +}; + +static LIST_HEAD(mctrl_list); + +/* Does BANK decode PHYS_ADDR? */ +static int bank_match(struct bank_info *bp, unsigned long phys_addr) +{ + unsigned long upper_bits = (phys_addr & PA_UPPER_BITS) >> PA_UPPER_BITS_SHIFT; + unsigned long lower_bits = (phys_addr & PA_LOWER_BITS) >> PA_LOWER_BITS_SHIFT; + + /* Bank must be enabled to match. */ + if (bp->valid == 0) + return 0; + + /* Would BANK match upper bits? */ + upper_bits ^= bp->um; /* What bits are different? */ + upper_bits = ~upper_bits; /* Invert. */ + upper_bits |= bp->uk; /* What bits don't matter for matching? */ + upper_bits = ~upper_bits; /* Invert. */ + + if (upper_bits) + return 0; + + /* Would BANK match lower bits? */ + lower_bits ^= bp->lm; /* What bits are different? */ + lower_bits = ~lower_bits; /* Invert. */ + lower_bits |= bp->lk; /* What bits don't matter for matching? */ + lower_bits = ~lower_bits; /* Invert. */ + + if (lower_bits) + return 0; + + /* I always knew you'd be the one. */ + return 1; +} + +/* Given PHYS_ADDR, search memory controller banks for a match. */ +static struct bank_info *find_bank(unsigned long phys_addr) +{ + struct list_head *mctrl_head = &mctrl_list; + struct list_head *mctrl_entry = mctrl_head->next; + + for (;;) { + struct mctrl_info *mp = + list_entry(mctrl_entry, struct mctrl_info, list); + int bank_no; + + if (mctrl_entry == mctrl_head) + break; + mctrl_entry = mctrl_entry->next; + + for (bank_no = 0; bank_no < CHMCTRL_NBANKS; bank_no++) { + struct bank_info *bp; + + bp = &mp->logical_banks[bank_no]; + if (bank_match(bp, phys_addr)) + return bp; + } + } + + return NULL; +} + +/* This is the main purpose of this driver. */ +#define SYNDROME_MIN -1 +#define SYNDROME_MAX 144 +int chmc_getunumber(int syndrome_code, + unsigned long phys_addr, + char *buf, int buflen) +{ + struct bank_info *bp; + struct obp_mem_layout *prop; + int bank_in_controller, first_dimm; + + bp = find_bank(phys_addr); + if (bp == NULL || + syndrome_code < SYNDROME_MIN || + syndrome_code > SYNDROME_MAX) { + buf[0] = '?'; + buf[1] = '?'; + buf[2] = '?'; + buf[3] = '\0'; + return 0; + } + + prop = &bp->mp->layout_prop; + bank_in_controller = bp->bank_id & (CHMCTRL_NBANKS - 1); + first_dimm = (bank_in_controller & (CHMCTRL_NDGRPS - 1)); + first_dimm *= CHMCTRL_NDIMMS; + + if (syndrome_code != SYNDROME_MIN) { + struct obp_map *map; + int qword, where_in_line, where, map_index, map_offset; + unsigned int map_val; + + /* Yaay, single bit error so we can figure out + * the exact dimm. + */ + if (prop->symmetric) + map = &prop->map[0]; + else + map = &prop->map[1]; + + /* Covert syndrome code into the way the bits are + * positioned on the bus. + */ + if (syndrome_code < 144 - 16) + syndrome_code += 16; + else if (syndrome_code < 144) + syndrome_code -= (144 - 7); + else if (syndrome_code < (144 + 3)) + syndrome_code -= (144 + 3 - 4); + else + syndrome_code -= 144 + 3; + + /* All this magic has to do with how a cache line + * comes over the wire on Safari. A 64-bit line + * comes over in 4 quadword cycles, each of which + * transmit ECC/MTAG info as well as the actual + * data. 144 bits per quadword, 576 total. + */ +#define LINE_SIZE 64 +#define LINE_ADDR_MSK (LINE_SIZE - 1) +#define QW_PER_LINE 4 +#define QW_BYTES (LINE_SIZE / QW_PER_LINE) +#define QW_BITS 144 +#define LAST_BIT (576 - 1) + + qword = (phys_addr & LINE_ADDR_MSK) / QW_BYTES; + where_in_line = ((3 - qword) * QW_BITS) + syndrome_code; + where = (LAST_BIT - where_in_line); + map_index = where >> 2; + map_offset = where & 0x3; + map_val = map->dimm_map[map_index]; + map_val = ((map_val >> ((3 - map_offset) << 1)) & (2 - 1)); + + sprintf(buf, "%s, pin %3d", + prop->dimm_labels[first_dimm + map_val], + map->pin_map[where_in_line]); + } else { + int dimm; + + /* Multi-bit error, we just dump out all the + * dimm labels assosciated with this bank. + */ + for (dimm = 0; dimm < CHMCTRL_NDIMMS; dimm++) { + sprintf(buf, "%s ", + prop->dimm_labels[first_dimm + dimm]); + buf += strlen(buf); + } + } + return 0; +} + +/* Accessing the registers is slightly complicated. If you want + * to get at the memory controller which is on the same processor + * the code is executing, you must use special ASI load/store else + * you go through the global mapping. + */ +static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset) +{ + unsigned long ret; + + if (mp->portid == smp_processor_id()) { + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=r" (ret) + : "r" (offset), "i" (ASI_MCU_CTRL_REG)); + } else { + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=r" (ret) + : "r" (mp->regs + offset), + "i" (ASI_PHYS_BYPASS_EC_E)); + } + return ret; +} + +#if 0 /* currently unused */ +static void write_mcreg(struct mctrl_info *mp, unsigned long offset, u64 val) +{ + if (mp->portid == smp_processor_id()) { + __asm__ __volatile__("stxa %0, [%1] %2" + : : "r" (val), + "r" (offset), "i" (ASI_MCU_CTRL_REG)); + } else { + __asm__ __volatile__("ldxa %0, [%1] %2" + : : "r" (val), + "r" (mp->regs + offset), + "i" (ASI_PHYS_BYPASS_EC_E)); + } +} +#endif + +static void interpret_one_decode_reg(struct mctrl_info *mp, int which_bank, u64 val) +{ + struct bank_info *p = &mp->logical_banks[which_bank]; + + p->mp = mp; + p->bank_id = (CHMCTRL_NBANKS * mp->portid) + which_bank; + p->raw_reg = val; + p->valid = (val & MEM_DECODE_VALID) >> MEM_DECODE_VALID_SHIFT; + p->uk = (val & MEM_DECODE_UK) >> MEM_DECODE_UK_SHIFT; + p->um = (val & MEM_DECODE_UM) >> MEM_DECODE_UM_SHIFT; + p->lk = (val & MEM_DECODE_LK) >> MEM_DECODE_LK_SHIFT; + p->lm = (val & MEM_DECODE_LM) >> MEM_DECODE_LM_SHIFT; + + p->base = (p->um); + p->base &= ~(p->uk); + p->base <<= PA_UPPER_BITS_SHIFT; + + switch(p->lk) { + case 0xf: + default: + p->interleave = 1; + break; + + case 0xe: + p->interleave = 2; + break; + + case 0xc: + p->interleave = 4; + break; + + case 0x8: + p->interleave = 8; + break; + + case 0x0: + p->interleave = 16; + break; + }; + + /* UK[10] is reserved, and UK[11] is not set for the SDRAM + * bank size definition. + */ + p->size = (((unsigned long)p->uk & + ((1UL << 10UL) - 1UL)) + 1UL) << PA_UPPER_BITS_SHIFT; + p->size /= p->interleave; +} + +static void fetch_decode_regs(struct mctrl_info *mp) +{ + if (mp->layout_size == 0) + return; + + interpret_one_decode_reg(mp, 0, + read_mcreg(mp, CHMCTRL_DECODE1)); + interpret_one_decode_reg(mp, 1, + read_mcreg(mp, CHMCTRL_DECODE2)); + interpret_one_decode_reg(mp, 2, + read_mcreg(mp, CHMCTRL_DECODE3)); + interpret_one_decode_reg(mp, 3, + read_mcreg(mp, CHMCTRL_DECODE4)); +} + +static int init_one_mctrl(int node, int index) +{ + struct mctrl_info *mp = kmalloc(sizeof(*mp), GFP_KERNEL); + int portid = prom_getintdefault(node, "portid", -1); + struct linux_prom64_registers p_reg_prop; + int t; + + if (!mp) + return -1; + memset(mp, 0, sizeof(*mp)); + if (portid == -1) + goto fail; + + mp->portid = portid; + mp->layout_size = prom_getproplen(node, "memory-layout"); + if (mp->layout_size < 0) + mp->layout_size = 0; + if (mp->layout_size > sizeof(mp->layout_prop)) + goto fail; + + if (mp->layout_size > 0) + prom_getproperty(node, "memory-layout", + (char *) &mp->layout_prop, + mp->layout_size); + + t = prom_getproperty(node, "reg", + (char *) &p_reg_prop, + sizeof(p_reg_prop)); + if (t < 0 || p_reg_prop.reg_size != 0x48) + goto fail; + + mp->regs = ioremap(p_reg_prop.phys_addr, p_reg_prop.reg_size); + if (mp->regs == NULL) + goto fail; + + if (mp->layout_size != 0UL) { + mp->timing_control1 = read_mcreg(mp, CHMCTRL_TCTRL1); + mp->timing_control2 = read_mcreg(mp, CHMCTRL_TCTRL2); + mp->timing_control3 = read_mcreg(mp, CHMCTRL_TCTRL3); + mp->timing_control4 = read_mcreg(mp, CHMCTRL_TCTRL4); + mp->memaddr_control = read_mcreg(mp, CHMCTRL_MACTRL); + } + + fetch_decode_regs(mp); + + mp->index = index; + + list_add(&mp->list, &mctrl_list); + + /* Report the device. */ + printk(KERN_INFO "chmc%d: US3 memory controller at %p [%s]\n", + mp->index, + mp->regs, (mp->layout_size ? "ACTIVE" : "INACTIVE")); + + return 0; + +fail: + if (mp) { + if (mp->regs != NULL) + iounmap(mp->regs); + kfree(mp); + } + return -1; +} + +static int __init probe_for_string(char *name, int index) +{ + int node = prom_getchild(prom_root_node); + + while ((node = prom_searchsiblings(node, name)) != 0) { + int ret = init_one_mctrl(node, index); + + if (!ret) + index++; + + node = prom_getsibling(node); + if (!node) + break; + } + + return index; +} + +static int __init chmc_init(void) +{ + int index; + + /* This driver is only for cheetah platforms. */ + if (tlb_type != cheetah) + return -ENODEV; + + index = probe_for_string("memory-controller", 0); + index = probe_for_string("mc-us3", index); + + return 0; +} + +static void __exit chmc_cleanup(void) +{ + struct list_head *head = &mctrl_list; + struct list_head *tmp = head->next; + + for (;;) { + struct mctrl_info *p = + list_entry(tmp, struct mctrl_info, list); + if (tmp == head) + break; + tmp = tmp->next; + + list_del(&p->list); + iounmap(p->regs); + kfree(p); + } +} + +module_init(chmc_init); +module_exit(chmc_cleanup); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/dtlb_prot.S linux.ac/arch/sparc64/kernel/dtlb_prot.S --- linux.vanilla/arch/sparc64/kernel/dtlb_prot.S Mon Nov 13 04:37:16 2000 +++ linux.ac/arch/sparc64/kernel/dtlb_prot.S Sat Apr 14 01:18:50 2001 @@ -1,4 +1,4 @@ -/* $Id: dtlb_prot.S,v 1.21 2000/11/10 08:28:45 davem Exp $ +/* $Id: dtlb_prot.S,v 1.22 2001/04/11 23:40:32 davem Exp $ * dtlb_prot.S: DTLB protection trap strategy. * This is included directly into the trap table. * @@ -43,7 +43,7 @@ nop nop -/* PROT ** ICACHE line 3: Unused... */ +/* PROT ** ICACHE line 4: Unused... */ nop nop nop diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/entry.S linux.ac/arch/sparc64/kernel/entry.S --- linux.vanilla/arch/sparc64/kernel/entry.S Tue Apr 3 17:31:57 2001 +++ linux.ac/arch/sparc64/kernel/entry.S Sat Apr 14 01:18:50 2001 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.127 2001/03/23 07:56:30 davem Exp $ +/* $Id: entry.S,v 1.128 2001/03/28 10:56:34 davem Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -19,6 +19,7 @@ #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/visasm.h> +#include <asm/estate.h> /* #define SYSCALL_TRACING */ @@ -788,6 +789,284 @@ call cee_log add %sp, STACK_BIAS + REGWIN_SZ, %o2 ba,a,pt %xcc, rtrap_clr_l6 + + /* Capture I/D/E-cache state into per-cpu error scoreboard. + * + * %g1: (TL>=0) ? 1 : 0 + * %g2: scratch + * %g3: scratch + * %g4: AFSR + * %g5: AFAR + * %g6: current thread ptr + * %g7: scratch + */ +#define CHEETAH_LOG_ERROR \ + /* Put "TL1" software bit into AFSR. */ \ + and %g1, 0x1, %g1; \ + sllx %g1, 63, %g2; \ + or %g4, %g2, %g4; \ + /* Get log entry pointer for this cpu at this trap level. */ \ + ldxa [%g0] ASI_SAFARI_CONFIG, %g2; \ + srlx %g2, 17, %g2; \ + and %g2, 0x3ff, %g2; \ + sllx %g2, 9, %g2; \ + sethi %hi(cheetah_error_log), %g3; \ + ldx [%g3 + %lo(cheetah_error_log)], %g3; \ + brz,pn %g3, 80f; \ + nop; \ + add %g3, %g2, %g3; \ + sllx %g1, 8, %g1; \ + add %g3, %g1, %g1; \ + /* %g1 holds pointer to the top of the logging scoreboard */ \ + ldx [%g1 + 0x0], %g7; \ + cmp %g7, -1; \ + bne,pn %xcc, 80f; \ + nop; \ + stx %g4, [%g1 + 0x0]; \ + stx %g5, [%g1 + 0x8]; \ + add %g1, 0x10, %g1; \ + /* %g1 now points to D-cache logging area */ \ + set 0x3ff8, %g2; /* DC_addr mask */ \ + and %g5, %g2, %g2; /* DC_addr bits of AFAR */ \ + srlx %g5, 12, %g3; \ + or %g3, 1, %g3; /* PHYS tag + valid */ \ +10: ldxa [%g2] ASI_DCACHE_TAG, %g7; \ + cmp %g3, %g7; /* TAG match? */ \ + bne,pt %xcc, 13f; \ + nop; \ + /* Yep, what we want, capture state. */ \ + stx %g2, [%g1 + 0x20]; \ + stx %g7, [%g1 + 0x28]; \ + /* A membar Sync is required before and after utag access. */ \ + membar #Sync; \ + ldxa [%g2] ASI_DCACHE_UTAG, %g7; \ + membar #Sync; \ + stx %g7, [%g1 + 0x30]; \ + ldxa [%g2] ASI_DCACHE_SNOOP_TAG, %g7; \ + stx %g7, [%g1 + 0x38]; \ + clr %g3; \ +12: ldxa [%g2 + %g3] ASI_DCACHE_DATA, %g7; \ + stx %g7, [%g1]; \ + add %g3, (1 << 5), %g3; \ + cmp %g3, (4 << 5); \ + bl,pt %xcc, 12b; \ + add %g1, 0x8, %g1; \ + ba,pt %xcc, 20f; \ + add %g1, 0x20, %g1; \ +13: sethi %hi(1 << 14), %g7; \ + add %g2, %g7, %g2; \ + srlx %g2, 14, %g7; \ + cmp %g7, 4; \ + bl,pt %xcc, 10b; \ + nop; \ + add %g1, 0x40, %g1; \ +20: /* %g1 now points to I-cache logging area */ \ + set 0x1fe0, %g2; /* IC_addr mask */ \ + and %g5, %g2, %g2; /* IC_addr bits of AFAR */ \ + sllx %g2, 1, %g2; /* IC_addr[13:6]==VA[12:5] */ \ + srlx %g5, (13 - 8), %g3; /* Make PTAG */ \ + andn %g3, 0xff, %g3; /* Mask off undefined bits */ \ +21: ldxa [%g2] ASI_IC_TAG, %g7; \ + andn %g7, 0xff, %g7; \ + cmp %g3, %g7; \ + bne,pt %xcc, 23f; \ + nop; \ + /* Yep, what we want, capture state. */ \ + stx %g2, [%g1 + 0x40]; \ + stx %g7, [%g1 + 0x48]; \ + add %g2, (1 << 3), %g2; \ + ldxa [%g2] ASI_IC_TAG, %g7; \ + add %g2, (1 << 3), %g2; \ + stx %g7, [%g1 + 0x50]; \ + ldxa [%g2] ASI_IC_TAG, %g7; \ + add %g2, (1 << 3), %g2; \ + stx %g7, [%g1 + 0x60]; \ + ldxa [%g2] ASI_IC_TAG, %g7; \ + stx %g7, [%g1 + 0x68]; \ + sub %g2, (3 << 3), %g2; \ + ldxa [%g2] ASI_IC_STAG, %g7; \ + stx %g7, [%g1 + 0x58]; \ + clr %g3; \ + srlx %g2, 2, %g2; \ +22: ldxa [%g2 + %g3] ASI_IC_INSTR, %g7; \ + stx %g7, [%g1]; \ + add %g3, (1 << 3), %g3; \ + cmp %g3, (8 << 3); \ + bl,pt %xcc, 22b; \ + add %g1, 0x8, %g1; \ + ba,pt %xcc, 30f; \ + add %g1, 0x30, %g1; \ +23: sethi %hi(1 << 14), %g7; \ + add %g2, %g7, %g2; \ + srlx %g2, 14, %g7; \ + cmp %g7, 4; \ + bl,pt %xcc, 21b; \ + nop; \ + add %g1, 0x70, %g1; \ +30: /* %g1 now points to E-cache logging area */ \ + andn %g5, (32 - 1), %g2; /* E-cache subblock */ \ + stx %g2, [%g1 + 0x20]; \ + ldxa [%g2] ASI_EC_TAG_DATA, %g7; \ + stx %g7, [%g1 + 0x28]; \ + ldxa [%g2] ASI_EC_R, %g0; \ + clr %g3; \ +31: ldxa [%g3] ASI_EC_DATA, %g7; \ + stx %g7, [%g1 + %g3]; \ + add %g3, 0x8, %g3; \ + cmp %g3, 0x20; \ + bl,pt %xcc, 31b; \ + nop; \ +80: /* DONE */ + + /* These get patched into the trap table at boot time + * once we know we have a cheetah processor. + */ + .globl cheetah_fecc_trap_vector, cheetah_fecc_trap_vector_tl1 +cheetah_fecc_trap_vector: + membar #Sync + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1 + andn %g1, DCU_DC | DCU_IC, %g1 + stxa %g1, [%g0] ASI_DCU_CONTROL_REG + membar #Sync + sethi %hi(cheetah_fast_ecc), %g2 + jmpl %g2 + %lo(cheetah_fast_ecc), %g0 + mov 0, %g1 +cheetah_fecc_trap_vector_tl1: + membar #Sync + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1 + andn %g1, DCU_DC | DCU_IC, %g1 + stxa %g1, [%g0] ASI_DCU_CONTROL_REG + membar #Sync + sethi %hi(cheetah_fast_ecc), %g2 + jmpl %g2 + %lo(cheetah_fast_ecc), %g0 + mov 1, %g1 + .globl cheetah_cee_trap_vector, cheetah_cee_trap_vector_tl1 +cheetah_cee_trap_vector: + membar #Sync + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1 + andn %g1, DCU_IC, %g1 + stxa %g1, [%g0] ASI_DCU_CONTROL_REG + membar #Sync + sethi %hi(cheetah_cee), %g2 + jmpl %g2 + %lo(cheetah_cee), %g0 + mov 0, %g1 +cheetah_cee_trap_vector_tl1: + membar #Sync + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1 + andn %g1, DCU_IC, %g1 + stxa %g1, [%g0] ASI_DCU_CONTROL_REG + membar #Sync + sethi %hi(cheetah_cee), %g2 + jmpl %g2 + %lo(cheetah_cee), %g0 + mov 1, %g1 + .globl cheetah_deferred_trap_vector, cheetah_deferred_trap_vector_tl1 +cheetah_deferred_trap_vector: + membar #Sync + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1; + andn %g1, DCU_DC | DCU_IC, %g1; + stxa %g1, [%g0] ASI_DCU_CONTROL_REG; + membar #Sync; + sethi %hi(cheetah_deferred_trap), %g2 + jmpl %g2 + %lo(cheetah_deferred_trap), %g0 + mov 0, %g1 +cheetah_deferred_trap_vector_tl1: + membar #Sync; + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1; + andn %g1, DCU_DC | DCU_IC, %g1; + stxa %g1, [%g0] ASI_DCU_CONTROL_REG; + membar #Sync; + sethi %hi(cheetah_deferred_trap), %g2 + jmpl %g2 + %lo(cheetah_deferred_trap), %g0 + mov 1, %g1 + + /* Cheetah FECC trap handling, we get here from tl{0,1}_fecc + * in the trap table. That code has done a memory barrier + * and has disabled both the I-cache and D-cache in the DCU + * control register. The I-cache is disabled so that we may + * capture the corrupted cache line, and the D-cache is disabled + * because corrupt data may have been placed there and we don't + * want to reference it. + * + * %g1 is one if this trap occured at %tl >= 1. + * + * Next, we turn off error reporting so that we don't recurse. + */ + .globl cheetah_fast_ecc +cheetah_fast_ecc: + ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2 + andn %g2, ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN, %g2 + stxa %g2, [%g0] ASI_ESTATE_ERROR_EN + membar #Sync + + /* Fetch and clear AFSR/AFAR */ + ldxa [%g0] ASI_AFSR, %g4 + ldxa [%g0] ASI_AFAR, %g5 + stxa %g4, [%g0] ASI_AFSR + membar #Sync + + CHEETAH_LOG_ERROR + + rdpr %pil, %g2 + wrpr %g0, 15, %pil + ba,pt %xcc, etrap_irq + rd %pc, %g7 + mov %l4, %o1 + mov %l5, %o2 + call cheetah_fecc_handler + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,a,pt %xcc, rtrap_clr_l6 + + /* Our caller has disabled I-cache and performed membar Sync. */ + .globl cheetah_cee +cheetah_cee: + ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2 + andn %g2, ESTATE_ERROR_CEEN, %g2 + stxa %g2, [%g0] ASI_ESTATE_ERROR_EN + membar #Sync + + /* Fetch and clear AFSR/AFAR */ + ldxa [%g0] ASI_AFSR, %g4 + ldxa [%g0] ASI_AFAR, %g5 + stxa %g4, [%g0] ASI_AFSR + membar #Sync + + CHEETAH_LOG_ERROR + + rdpr %pil, %g2 + wrpr %g0, 15, %pil + ba,pt %xcc, etrap_irq + rd %pc, %g7 + mov %l4, %o1 + mov %l5, %o2 + call cheetah_cee_handler + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,a,pt %xcc, rtrap_clr_l6 + + /* Our caller has disabled I-cache+D-cache and performed membar Sync. */ + .globl cheetah_deferred_trap +cheetah_deferred_trap: + ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2 + andn %g2, ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN, %g2 + stxa %g2, [%g0] ASI_ESTATE_ERROR_EN + membar #Sync + + /* Fetch and clear AFSR/AFAR */ + ldxa [%g0] ASI_AFSR, %g4 + ldxa [%g0] ASI_AFAR, %g5 + stxa %g4, [%g0] ASI_AFSR + membar #Sync + + CHEETAH_LOG_ERROR + + rdpr %pil, %g2 + wrpr %g0, 15, %pil + ba,pt %xcc, etrap_irq + rd %pc, %g7 + mov %l4, %o1 + mov %l5, %o2 + call cheetah_deferred_handler + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,a,pt %xcc, rtrap_clr_l6 .globl __do_privact __do_privact: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/head.S linux.ac/arch/sparc64/kernel/head.S --- linux.vanilla/arch/sparc64/kernel/head.S Tue Apr 3 17:31:57 2001 +++ linux.ac/arch/sparc64/kernel/head.S Sat Apr 14 01:18:50 2001 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.75 2001/03/22 09:54:26 davem Exp $ +/* $Id: head.S,v 1.77 2001/04/05 12:44:34 davem Exp $ * head.S: Initial boot code for the Sparc64 port of Linux. * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -90,13 +90,25 @@ mov DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1 wr %g1, %asr18 - sethi %uhi(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 - or %g5, %ulo(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 + sethi %uhi(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 + or %g5, %ulo(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 sllx %g5, 32, %g5 or %g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5 - ldxa [%g0] ASI_DCU_CONTROL_REG, %g3 - or %g5, %g3, %g5 stxa %g5, [%g0] ASI_DCU_CONTROL_REG + membar #Sync + + mov TSB_EXTENSION_P, %g3 + stxa %g0, [%g3] ASI_DMMU + stxa %g0, [%g3] ASI_IMMU + membar #Sync + + mov TSB_EXTENSION_S, %g3 + stxa %g0, [%g3] ASI_DMMU + membar #Sync + + mov TSB_EXTENSION_N, %g3 + stxa %g0, [%g3] ASI_DMMU + stxa %g0, [%g3] ASI_IMMU membar #Sync wrpr %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/ioctl32.c linux.ac/arch/sparc64/kernel/ioctl32.c --- linux.vanilla/arch/sparc64/kernel/ioctl32.c Tue Apr 3 17:31:58 2001 +++ linux.ac/arch/sparc64/kernel/ioctl32.c Sat Apr 14 01:18:50 2001 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.110 2001/03/22 12:51:25 davem Exp $ +/* $Id: ioctl32.c,v 1.111 2001/03/27 07:28:43 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) @@ -527,6 +527,55 @@ return err; } +static inline int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct ifreq ifr; + mm_segment_t old_fs; + int err, len; + u32 data, ethcmd; + + if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) + return -EFAULT; + ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL); + if (!ifr.ifr_data) + return -EAGAIN; + + __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); + + if (get_user(ethcmd, (u32 *)A(data))) { + err = -EFAULT; + goto out; + } + switch (ethcmd) { + case ETHTOOL_GDRVINFO: len = sizeof(struct ethtool_drvinfo); break; + case ETHTOOL_GSET: + case ETHTOOL_SSET: + default: len = sizeof(struct ethtool_cmd); break; + } + + if (copy_from_user(ifr.ifr_data, (char *)A(data), len)) { + err = -EFAULT; + goto out; + } + + old_fs = get_fs(); + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&ifr); + set_fs (old_fs); + if (!err) { + u32 data; + + __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); + len = copy_to_user((char *)A(data), ifr.ifr_data, len); + if (len) + err = -EFAULT; + } + +out: + free_page((unsigned long)ifr.ifr_data); + return err; +} + static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg) { struct ifreq ifr; @@ -548,23 +597,11 @@ case SIOCGPPPSTATS: case SIOCGPPPCSTATS: case SIOCGPPPVER: - case SIOCETHTOOL: if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) return -EFAULT; ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL); if (!ifr.ifr_data) return -EAGAIN; - if(cmd == SIOCETHTOOL) { - u32 data; - - __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); - if(copy_from_user(ifr.ifr_data, - (char *)A(data), - sizeof(struct ethtool_cmd))) { - free_page((unsigned long)ifr.ifr_data); - return -EFAULT; - } - } break; default: if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) @@ -594,14 +631,11 @@ case SIOCGPPPSTATS: case SIOCGPPPCSTATS: case SIOCGPPPVER: - case SIOCETHTOOL: { u32 data; int len; __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); - if(cmd == SIOCETHTOOL) - len = sizeof(struct ethtool_cmd); if(cmd == SIOCGPPPVER) len = strlen((char *)ifr.ifr_data) + 1; else if(cmd == SIOCGPPPCSTATS) @@ -627,6 +661,14 @@ err = -EFAULT; break; } + } else { + switch (cmd) { + case SIOCGPPPSTATS: + case SIOCGPPPCSTATS: + case SIOCGPPPVER: + free_page((unsigned long)ifr.ifr_data); + break; + } } return err; } @@ -3705,7 +3747,7 @@ HANDLE_IOCTL(SIOCGPPPVER, dev_ifsioc) HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc) HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc) -HANDLE_IOCTL(SIOCETHTOOL, dev_ifsioc) +HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl) HANDLE_IOCTL(SIOCADDRT, routing_ioctl) HANDLE_IOCTL(SIOCDELRT, routing_ioctl) /* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/pci.c linux.ac/arch/sparc64/kernel/pci.c --- linux.vanilla/arch/sparc64/kernel/pci.c Tue Apr 3 17:31:58 2001 +++ linux.ac/arch/sparc64/kernel/pci.c Sat Apr 14 01:20:10 2001 @@ -1,4 +1,4 @@ -/* $Id: pci.c,v 1.23 2001/03/14 04:17:14 davem Exp $ +/* $Id: pci.c,v 1.24 2001/03/28 10:56:34 davem Exp $ * pci.c: UltraSparc PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -73,6 +73,7 @@ spinlock_t pci_poke_lock = SPIN_LOCK_UNLOCKED; volatile int pci_poke_in_progress; +volatile int pci_poke_cpu = -1; volatile int pci_poke_faulted; /* Probe for all PCI controllers in the system. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/pci_impl.h linux.ac/arch/sparc64/kernel/pci_impl.h --- linux.vanilla/arch/sparc64/kernel/pci_impl.h Mon Mar 27 19:35:56 2000 +++ linux.ac/arch/sparc64/kernel/pci_impl.h Sat Apr 14 01:20:10 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_impl.h,v 1.6 2000/03/25 05:18:11 davem Exp $ +/* $Id: pci_impl.h,v 1.7 2001/03/28 10:56:34 davem Exp $ * pci_impl.h: Helper definitions for PCI controller support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -41,6 +41,7 @@ /* Configuration space access. */ extern spinlock_t pci_poke_lock; extern volatile int pci_poke_in_progress; +extern volatile int pci_poke_cpu; extern volatile int pci_poke_faulted; static __inline__ void pci_config_read8(u8 *addr, u8 *ret) @@ -49,6 +50,7 @@ u8 byte; spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_cpu = smp_processor_id(); pci_poke_in_progress = 1; pci_poke_faulted = 0; __asm__ __volatile__("membar #Sync\n\t" @@ -58,6 +60,7 @@ : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) : "memory"); pci_poke_in_progress = 0; + pci_poke_cpu = -1; if (!pci_poke_faulted) *ret = byte; spin_unlock_irqrestore(&pci_poke_lock, flags); @@ -69,6 +72,7 @@ u16 word; spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_cpu = smp_processor_id(); pci_poke_in_progress = 1; pci_poke_faulted = 0; __asm__ __volatile__("membar #Sync\n\t" @@ -78,6 +82,7 @@ : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) : "memory"); pci_poke_in_progress = 0; + pci_poke_cpu = -1; if (!pci_poke_faulted) *ret = word; spin_unlock_irqrestore(&pci_poke_lock, flags); @@ -89,6 +94,7 @@ u32 dword; spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_cpu = smp_processor_id(); pci_poke_in_progress = 1; pci_poke_faulted = 0; __asm__ __volatile__("membar #Sync\n\t" @@ -98,6 +104,7 @@ : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) : "memory"); pci_poke_in_progress = 0; + pci_poke_cpu = -1; if (!pci_poke_faulted) *ret = dword; spin_unlock_irqrestore(&pci_poke_lock, flags); @@ -108,6 +115,7 @@ unsigned long flags; spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_cpu = smp_processor_id(); pci_poke_in_progress = 1; pci_poke_faulted = 0; __asm__ __volatile__("membar #Sync\n\t" @@ -117,6 +125,7 @@ : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) : "memory"); pci_poke_in_progress = 0; + pci_poke_cpu = -1; spin_unlock_irqrestore(&pci_poke_lock, flags); } @@ -125,6 +134,7 @@ unsigned long flags; spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_cpu = smp_processor_id(); pci_poke_in_progress = 1; pci_poke_faulted = 0; __asm__ __volatile__("membar #Sync\n\t" @@ -134,6 +144,7 @@ : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) : "memory"); pci_poke_in_progress = 0; + pci_poke_cpu = -1; spin_unlock_irqrestore(&pci_poke_lock, flags); } @@ -142,6 +153,7 @@ unsigned long flags; spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_cpu = smp_processor_id(); pci_poke_in_progress = 1; pci_poke_faulted = 0; __asm__ __volatile__("membar #Sync\n\t" @@ -151,6 +163,7 @@ : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) : "memory"); pci_poke_in_progress = 0; + pci_poke_cpu = -1; spin_unlock_irqrestore(&pci_poke_lock, flags); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/process.c linux.ac/arch/sparc64/kernel/process.c --- linux.vanilla/arch/sparc64/kernel/process.c Tue Apr 3 17:31:58 2001 +++ linux.ac/arch/sparc64/kernel/process.c Mon Apr 16 12:37:04 2001 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.116 2001/03/24 09:36:01 davem Exp $ +/* $Id: process.c,v 1.117 2001/03/30 07:10:41 davem Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/smp.c linux.ac/arch/sparc64/kernel/smp.c --- linux.vanilla/arch/sparc64/kernel/smp.c Tue Apr 3 17:31:59 2001 +++ linux.ac/arch/sparc64/kernel/smp.c Sat Apr 14 01:20:10 2001 @@ -415,9 +415,7 @@ /* Setup the dispatch data registers. */ __asm__ __volatile__("stxa %0, [%3] %6\n\t" - "membar #Sync\n\t" "stxa %1, [%4] %6\n\t" - "membar #Sync\n\t" "stxa %2, [%5] %6\n\t" "membar #Sync\n\t" : /* no outputs */ @@ -994,6 +992,8 @@ cycles_t cacheflush_time; +extern unsigned long cheetah_tune_scheduling(void); + static void __init smp_tune_scheduling (void) { unsigned long orig_flush_base, flush_base, flags, *p; @@ -1011,6 +1011,11 @@ * of moving a process from one cpu to another). */ printk("SMP: Calibrating ecache flush... "); + if (tlb_type == cheetah) { + cacheflush_time = cheetah_tune_scheduling(); + goto report; + } + ecache_size = prom_getintdefault(linux_cpus[0].prom_node, "ecache-size", (512 * 1024)); if (ecache_size > (4 * 1024 * 1024)) @@ -1063,7 +1068,7 @@ cacheflush_time = ((ecache_size << 2) + (ecache_size << 1)); } - +report: printk("Using heuristic of %d cycles.\n", (int) cacheflush_time); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/sparc64_ksyms.c linux.ac/arch/sparc64/kernel/sparc64_ksyms.c --- linux.vanilla/arch/sparc64/kernel/sparc64_ksyms.c Tue Apr 3 17:31:59 2001 +++ linux.ac/arch/sparc64/kernel/sparc64_ksyms.c Sat Apr 14 01:20:10 2001 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.102 2001/03/24 09:36:01 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.104 2001/04/05 11:08:11 davem Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -149,6 +149,8 @@ EXPORT_SYMBOL(_do_write_unlock); #endif +EXPORT_SYMBOL(smp_call_function); + #endif /* semaphores */ @@ -180,7 +182,7 @@ EXPORT_SYMBOL(__flushw_user); EXPORT_SYMBOL(tlb_type); - +EXPORT_SYMBOL(get_fb_unmapped_area); EXPORT_SYMBOL(flush_icache_range); EXPORT_SYMBOL(__flush_dcache_page); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/starfire.c linux.ac/arch/sparc64/kernel/starfire.c --- linux.vanilla/arch/sparc64/kernel/starfire.c Mon Feb 19 03:49:54 2001 +++ linux.ac/arch/sparc64/kernel/starfire.c Tue Apr 3 17:54:37 2001 @@ -2,7 +2,7 @@ * starfire.c: Starfire/E10000 support. * * Copyright (C) 1998 David S. Miller (davem@redhat.com) - * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 2000 Anton Blanchard (anton@samba.org) */ #include <linux/kernel.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/sys_sparc.c linux.ac/arch/sparc64/kernel/sys_sparc.c --- linux.vanilla/arch/sparc64/kernel/sys_sparc.c Tue Apr 3 17:31:59 2001 +++ linux.ac/arch/sparc64/kernel/sys_sparc.c Sat Apr 14 01:20:10 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.50 2001/03/24 09:36:10 davem Exp $ +/* $Id: sys_sparc.c,v 1.51 2001/03/27 02:36:37 davem Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that @@ -42,19 +42,28 @@ #define COLOUR_ALIGN(addr) (((addr)+SHMLBA-1)&~(SHMLBA-1)) -unsigned long get_unmapped_area(unsigned long addr, unsigned long len) +unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { struct vm_area_struct * vmm; unsigned long task_size = TASK_SIZE; + if (flags & MAP_FIXED) { + /* We do not accept a shared mapping if it would violate + * cache aliasing constraints. + */ + if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1))) + return -EINVAL; + return addr; + } + if (current->thread.flags & SPARC_FLAG_32BIT) task_size = 0xf0000000UL; if (len > task_size || len > -PAGE_OFFSET) - return 0; + return -ENOMEM; if (!addr) addr = TASK_UNMAPPED_BASE; - if (current->thread.flags & SPARC_FLAG_MMAPSHARED) + if (flags & MAP_SHARED) addr = COLOUR_ALIGN(addr); else addr = PAGE_ALIGN(addr); @@ -68,15 +77,58 @@ vmm = find_vma(current->mm, PAGE_OFFSET); } if (task_size < addr) - return 0; + return -ENOMEM; if (!vmm || addr + len <= vmm->vm_start) return addr; addr = vmm->vm_end; - if (current->thread.flags & SPARC_FLAG_MMAPSHARED) + if (flags & MAP_SHARED) addr = COLOUR_ALIGN(addr); } } +/* Try to align mapping such that we align it as much as possible. */ +unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, unsigned long len, unsigned long pgoff, unsigned long flags) +{ + unsigned long align_goal, addr = -ENOMEM; + + if (flags & MAP_FIXED) { + /* Ok, don't mess with it. */ + return get_unmapped_area(NULL, addr, len, pgoff, flags); + } + flags &= ~MAP_SHARED; + + align_goal = PAGE_SIZE; + if (len >= (4UL * 1024 * 1024)) + align_goal = (4UL * 1024 * 1024); + else if (len >= (512UL * 1024)) + align_goal = (512UL * 1024); + else if (len >= (64UL * 1024)) + align_goal = (64UL * 1024); + + do { + addr = get_unmapped_area(NULL, orig_addr, len + (align_goal - PAGE_SIZE), pgoff, flags); + if (!(addr & ~PAGE_MASK)) { + addr = (addr + (align_goal - 1UL)) & ~(align_goal - 1UL); + break; + } + + if (align_goal == (4UL * 1024 * 1024)) + align_goal = (512UL * 1024); + else if (align_goal == (512UL * 1024)) + align_goal = (64UL * 1024); + else + align_goal = PAGE_SIZE; + } while ((addr & ~PAGE_MASK) && align_goal > PAGE_SIZE); + + /* Mapping is smaller than 64K or larger areas could not + * be obtained. + */ + if (addr & ~PAGE_MASK) + addr = get_unmapped_area(NULL, orig_addr, len, pgoff, flags); + + return addr; +} + extern asmlinkage unsigned long sys_brk(unsigned long brk); asmlinkage unsigned long sparc_brk(unsigned long brk) @@ -240,15 +292,10 @@ goto out_putf; } - if (flags & MAP_SHARED) - current->thread.flags |= SPARC_FLAG_MMAPSHARED; - down_write(¤t->mm->mmap_sem); retval = do_mmap(file, addr, len, prot, flags, off); up_write(¤t->mm->mmap_sem); - current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED); - out_putf: if (file) fput(file); @@ -286,25 +333,37 @@ if (addr < PAGE_OFFSET && addr + old_len > -PAGE_OFFSET) goto out; down_write(¤t->mm->mmap_sem); - vma = find_vma(current->mm, addr); - if (vma && (vma->vm_flags & VM_SHARED)) - current->thread.flags |= SPARC_FLAG_MMAPSHARED; if (flags & MREMAP_FIXED) { if (new_addr < PAGE_OFFSET && new_addr + new_len > -PAGE_OFFSET) goto out_sem; } else if (addr < PAGE_OFFSET && addr + new_len > -PAGE_OFFSET) { + unsigned long (*get_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); + unsigned long map_flags = 0; + struct file *file = NULL; + ret = -ENOMEM; if (!(flags & MREMAP_MAYMOVE)) goto out_sem; - new_addr = get_unmapped_area(addr, new_len); - if (!new_addr) + + vma = find_vma(current->mm, addr); + if (vma) { + if (vma->vm_flags & VM_SHARED) + map_flags |= MAP_SHARED; + file = vma->vm_file; + } + + /* MREMAP_FIXED checked above. */ + new_addr = get_unmapped_area(file, addr, new_len, + vma ? vma->vm_pgoff : 0, + map_flags); + ret = new_addr; + if (new_addr & ~PAGE_MASK) goto out_sem; flags |= MREMAP_FIXED; } ret = do_mremap(addr, old_len, new_len, flags, new_addr); out_sem: - current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED); up_write(¤t->mm->mmap_sem); out: return ret; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/sys_sparc32.c linux.ac/arch/sparc64/kernel/sys_sparc32.c --- linux.vanilla/arch/sparc64/kernel/sys_sparc32.c Tue Apr 3 17:31:59 2001 +++ linux.ac/arch/sparc64/kernel/sys_sparc32.c Sat Apr 14 01:20:10 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.174 2001/03/24 09:36:10 davem Exp $ +/* $Id: sys_sparc32.c,v 1.175 2001/03/27 02:36:37 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -904,7 +904,7 @@ { int cmds = cmd >> SUBCMDSHIFT; int err; - struct dqblk d; + struct dqblk32 d; mm_segment_t old_fs; char *spec; @@ -4134,24 +4134,36 @@ if (addr > 0xf0000000UL - old_len) goto out; down_write(¤t->mm->mmap_sem); - vma = find_vma(current->mm, addr); - if (vma && (vma->vm_flags & VM_SHARED)) - current->thread.flags |= SPARC_FLAG_MMAPSHARED; if (flags & MREMAP_FIXED) { if (new_addr > 0xf0000000UL - new_len) goto out_sem; } else if (addr > 0xf0000000UL - new_len) { + unsigned long (*get_addr)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); + unsigned long map_flags = 0; + struct file *file = NULL; + ret = -ENOMEM; if (!(flags & MREMAP_MAYMOVE)) goto out_sem; - new_addr = get_unmapped_area(addr, new_len); - if (!new_addr) + + vma = find_vma(current->mm, addr); + if (vma) { + if (vma->vm_flags & VM_SHARED) + map_flags |= MAP_SHARED; + file = vma->vm_file; + } + + /* MREMAP_FIXED checked above. */ + new_addr = get_unmapped_addr(file, addr, new_len, + vma ? vma->vm_pgoff : 0, + map_flags); + ret = new_addr; + if (new_addr & ~PAGE_MASK) goto out_sem; flags |= MREMAP_FIXED; } ret = do_mremap(addr, old_len, new_len, flags, new_addr); out_sem: - current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED); up_write(¤t->mm->mmap_sem); out: return ret; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/sys_sunos32.c linux.ac/arch/sparc64/kernel/sys_sunos32.c --- linux.vanilla/arch/sparc64/kernel/sys_sunos32.c Tue Apr 3 17:31:59 2001 +++ linux.ac/arch/sparc64/kernel/sys_sunos32.c Tue Apr 3 17:54:37 2001 @@ -570,7 +570,7 @@ struct sunos_nfs_mount_args { struct sockaddr_in *addr; /* file server address */ - struct nfs_fh *fh; /* File handle to be mounted */ + struct nfs3_fh *fh; /* File handle to be mounted */ int flags; /* flags */ int wsize; /* write size in bytes */ int rsize; /* read size in bytes */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/trampoline.S linux.ac/arch/sparc64/kernel/trampoline.S --- linux.vanilla/arch/sparc64/kernel/trampoline.S Tue Apr 3 17:31:59 2001 +++ linux.ac/arch/sparc64/kernel/trampoline.S Sat Apr 14 01:20:18 2001 @@ -1,4 +1,4 @@ -/* $Id: trampoline.S,v 1.19 2001/03/22 09:54:26 davem Exp $ +/* $Id: trampoline.S,v 1.21 2001/04/05 12:44:34 davem Exp $ * trampoline.S: Jump start slave processors on sparc64. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -44,14 +44,26 @@ mov DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1 wr %g1, %asr18 - sethi %uhi(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 - or %g5, %ulo(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 + sethi %uhi(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 + or %g5, %ulo(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 sllx %g5, 32, %g5 or %g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5 - ldxa [%g0] ASI_DCU_CONTROL_REG, %g3 - or %g5, %g3, %g5 stxa %g5, [%g0] ASI_DCU_CONTROL_REG membar #Sync + + mov TSB_EXTENSION_P, %g3 + stxa %g0, [%g3] ASI_DMMU + stxa %g0, [%g3] ASI_IMMU + membar #Sync + + mov TSB_EXTENSION_S, %g3 + stxa %g0, [%g3] ASI_DMMU + membar #Sync + + mov TSB_EXTENSION_N, %g3 + stxa %g0, [%g3] ASI_DMMU + stxa %g0, [%g3] ASI_IMMU + membar #Sync /* Disable STICK_INT interrupts. */ sethi %hi(0x80000000), %g5 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/traps.c linux.ac/arch/sparc64/kernel/traps.c --- linux.vanilla/arch/sparc64/kernel/traps.c Tue Apr 3 17:31:59 2001 +++ linux.ac/arch/sparc64/kernel/traps.c Sat Apr 14 01:20:18 2001 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.73 2001/03/22 07:26:03 davem Exp $ +/* $Id: traps.c,v 1.76 2001/04/03 13:46:31 davem Exp $ * arch/sparc64/kernel/traps.c * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -15,6 +15,7 @@ #include <linux/signal.h> #include <linux/smp.h> #include <linux/smp_lock.h> +#include <linux/mm.h> #include <asm/delay.h> #include <asm/system.h> @@ -27,231 +28,13 @@ #include <asm/fpumacro.h> #include <asm/lsu.h> #include <asm/dcu.h> +#include <asm/estate.h> +#include <asm/chafsr.h> #include <asm/psrcompat.h> #ifdef CONFIG_KMOD #include <linux/kmod.h> #endif -/* #define SYSCALL_TRACING */ -/* #define VERBOSE_SYSCALL_TRACING */ -/* #define DEBUG_FPU */ - -#ifdef SYSCALL_TRACING -#ifdef VERBOSE_SYSCALL_TRACING -struct sdesc { - int scall_num; - char *name; - int num_args; - char arg_is_string[6]; -} sdesc_entries[] = { - { 0, "setup", 0, }, - { 1, "exit", 1, { 0, } }, - { 2, "fork", 0, }, - { 3, "read", 3, { 0, 0, 0, } }, - { 4, "write", 3, { 0, 0, 0, } }, - { 5, "open", 3, { 1, 0, 0, } }, - { 6, "close", 1, { 0, } }, - { 7, "wait4", 4, { 0, 0, 0, 0, } }, - { 8, "creat", 2, { 1, 0, } }, - { 9, "link", 2, { 1, 1, } }, - { 10, "unlink", 1, { 1, } }, - { 11, "execv", 2, { 1, 0, } }, - { 12, "chdir", 1, { 1, } }, - { 15, "chmod", 2, { 1, 0, } }, - { 16, "chown", 3, { 1, 0, 0, } }, - { 17, "brk", 1, { 0, } }, - { 19, "lseek", 3, { 0, 0, 0, } }, - { 27, "alarm", 1, { 0, } }, - { 29, "pause", 0, }, - { 33, "access", 2, { 1, 0, } }, - { 36, "sync", 0, }, - { 37, "kill", 2, { 0, 0, } }, - { 38, "stat", 2, { 1, 0, } }, - { 40, "lstat", 2, { 1, 0, } }, - { 41, "dup", 1, { 0, } }, - { 42, "pipd", 0, }, - { 54, "ioctl", 3, { 0, 0, 0, } }, - { 57, "symlink", 2, { 1, 1, } }, - { 58, "readlink", 3, { 1, 0, 0, } }, - { 59, "execve", 3, { 1, 0, 0, } }, - { 60, "umask", 1, { 0, } }, - { 62, "fstat", 2, { 0, 0, } }, - { 64, "getpagesize", 0, }, - { 71, "mmap", 6, { 0, 0, 0, 0, 0, 0, } }, - { 73, "munmap", 2, { 0, 0, } }, - { 74, "mprotect", 3, { 0, 0, 0, } }, - { 83, "setitimer", 3, { 0, 0, 0, } }, - { 90, "dup2", 2, { 0, 0, } }, - { 92, "fcntl", 3, { 0, 0, 0, } }, - { 93, "select", 5, { 0, 0, 0, 0, 0, } }, - { 97, "socket", 3, { 0, 0, 0, } }, - { 98, "connect", 3, { 0, 0, 0, } }, - { 99, "accept", 3, { 0, 0, 0, } }, - { 101, "send", 4, { 0, 0, 0, 0, } }, - { 102, "recv", 4, { 0, 0, 0, 0, } }, - { 104, "bind", 3, { 0, 0, 0, } }, - { 105, "setsockopt", 5, { 0, 0, 0, 0, 0, } }, - { 106, "listen", 2, { 0, 0, } }, - { 120, "readv", 3, { 0, 0, 0, } }, - { 121, "writev", 3, { 0, 0, 0, } }, - { 123, "fchown", 3, { 0, 0, 0, } }, - { 124, "fchmod", 2, { 0, 0, } }, - { 128, "rename", 2, { 1, 1, } }, - { 129, "truncate", 2, { 1, 0, } }, - { 130, "ftruncate", 2, { 0, 0, } }, - { 131, "flock", 2, { 0, 0, } }, - { 136, "mkdir", 2, { 1, 0, } }, - { 137, "rmdir", 1, { 1, } }, - { 146, "killpg", 1, { 0, } }, - { 157, "statfs", 2, { 1, 0, } }, - { 158, "fstatfs", 2, { 0, 0, } }, - { 159, "umount", 1, { 1, } }, - { 167, "mount", 5, { 1, 1, 1, 0, 0, } }, - { 174, "getdents", 3, { 0, 0, 0, } }, - { 176, "fchdir", 2, { 0, 0, } }, - { 198, "sigaction", 3, { 0, 0, 0, } }, - { 201, "sigsuspend", 1, { 0, } }, - { 206, "socketcall", 2, { 0, 0, } }, - { 216, "sigreturn", 0, }, - { 230, "newselect", 5, { 0, 0, 0, 0, 0, } }, - { 236, "llseek", 5, { 0, 0, 0, 0, 0, } }, - { 251, "sysctl", 1, { 0, } }, -}; -#define NUM_SDESC_ENTRIES (sizeof(sdesc_entries) / sizeof(sdesc_entries[0])) -#endif - -#ifdef VERBOSE_SYSCALL_TRACING -static char scall_strbuf[512]; -#endif - -void syscall_trace_entry(unsigned long g1, struct pt_regs *regs) -{ -#ifdef VERBOSE_SYSCALL_TRACING - struct sdesc *sdp; - int i; -#endif - -#if 0 - if (!current->pid) return; -#endif - printk("SYS[%s:%d]: PC(%016lx) <%3d> ", - current->comm, current->pid, regs->tpc, (int)g1); -#ifdef VERBOSE_SYSCALL_TRACING - sdp = NULL; - for(i = 0; i < NUM_SDESC_ENTRIES; i++) - if(sdesc_entries[i].scall_num == g1) { - sdp = &sdesc_entries[i]; - break; - } - if(sdp) { - printk("%s(", sdp->name); - for(i = 0; i < sdp->num_args; i++) { - if(i) - printk(","); - if(!sdp->arg_is_string[i]) { - if (current->thread.flags & SPARC_FLAG_32BIT) - printk("%08x", (unsigned int)regs->u_regs[UREG_I0 + i]); - else - printk("%016lx", regs->u_regs[UREG_I0 + i]); - } else { - if (current->thread.flags & SPARC_FLAG_32BIT) - strncpy_from_user(scall_strbuf, - (char *)(regs->u_regs[UREG_I0 + i] & 0xffffffff), - 512); - else - strncpy_from_user(scall_strbuf, - (char *)regs->u_regs[UREG_I0 + i], - 512); - printk("%s", scall_strbuf); - } - } - printk(") "); - } -#endif -} - -unsigned long syscall_trace_exit(unsigned long retval, struct pt_regs *regs) -{ -#if 0 - if (current->pid) -#endif - printk("ret[%016lx]\n", retval); - return retval; -} -#endif /* SYSCALL_TRACING */ - -#if 1 -void rtrap_check(struct pt_regs *regs) -{ - register unsigned long pgd_phys asm("o1"); - register unsigned long pgd_cache asm("o2"); - register unsigned long g1_or_g3 asm("o3"); - register unsigned long g2 asm("o4"); - unsigned long ctx; - -#if 0 - do { - unsigned long test; - __asm__ __volatile__("rdpr %%pstate, %0" - : "=r" (test)); - if((test & PSTATE_MG) != 0 || - (test & PSTATE_IE) == 0) { - printk("rtrap_check: Bogus pstate[%016lx]\n", test); - return; - } - } while(0); -#endif - - __asm__ __volatile__(" - rdpr %%pstate, %%o5 - wrpr %%o5, %4, %%pstate - or %%g1, %%g3, %2 - mov %%g2, %3 - mov %%g7, %0 - mov %5, %1 - ldxa [%1] %6, %1 - wrpr %%o5, 0x0, %%pstate" - : "=r" (pgd_phys), "=r" (pgd_cache), - "=r" (g1_or_g3), "=r" (g2) - : "i" (PSTATE_IE | PSTATE_MG), "i" (TSB_REG), - "i" (ASI_DMMU) - : "o5"); - - ctx = spitfire_get_secondary_context(); - - if((pgd_phys != __pa(current->mm->pgd)) || - ((pgd_cache != 0) && - (pgd_cache != pgd_val(current->mm->pgd[0])<<11UL)) || - (g1_or_g3 != (0xfffffffe00000000UL | 0x0000000000000018UL)) || -#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000) -#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) - (g2 != (KERN_HIGHBITS | KERN_LOWBITS)) || -#undef KERN_HIGHBITS -#undef KERN_LOWBITS - ((ctx != (current->mm->context & 0x3ff)) || - (ctx == 0) || - (CTX_HWBITS(current->mm->context) != ctx))) { - printk("SHIT[%s:%d]: " - "(PP[%016lx] CACH[%016lx] CTX[%lx] g1g3[%016lx] g2[%016lx]) ", - current->comm, current->pid, - pgd_phys, pgd_cache, ctx, g1_or_g3, g2); - printk("SHIT[%s:%d]: " - "[PP[%016lx] CACH[%016lx] CTX[%lx]] PC[%016lx:%016lx]\n", - current->comm, current->pid, - __pa(current->mm->pgd), - pgd_val(current->mm->pgd[0]), - current->mm->context & 0x3ff, - regs->tpc, regs->tnpc); - show_regs(regs); -#if 1 - __sti(); - while(1) - barrier(); -#endif - } -} -#endif - void bad_trap (struct pt_regs *regs, long lvl) { siginfo_t info; @@ -290,10 +73,8 @@ siginfo_t info; if (regs->tstate & TSTATE_PRIV) { -#if 1 - printk("instruction_access_exception: Shit SFSR[%016lx] SFAR[%016lx], going.\n", + printk("instruction_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n", sfsr, sfar); -#endif die_if_kernel("Iax", regs); } if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { @@ -331,16 +112,11 @@ return; } /* Shit... */ -#if 1 - printk("data_access_exception: Shit SFSR[%016lx] SFAR[%016lx], going.\n", + printk("data_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n", sfsr, sfar); -#endif die_if_kernel("Dax", regs); } -#if 0 - else - rtrap_check(regs); -#endif + info.si_signo = SIGSEGV; info.si_errno = 0; info.si_code = SEGV_MAPERR; @@ -352,6 +128,7 @@ #ifdef CONFIG_PCI /* This is really pathetic... */ extern volatile int pci_poke_in_progress; +extern volatile int pci_poke_cpu; extern volatile int pci_poke_faulted; #endif @@ -405,7 +182,7 @@ void do_dae(struct pt_regs *regs) { #ifdef CONFIG_PCI - if (pci_poke_in_progress) { + if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) { clean_and_reenable_l1_caches(); pci_poke_faulted = 1; @@ -539,6 +316,986 @@ } } +/* Cheetah error trap handling. */ +static unsigned long ecache_flush_physbase; +static unsigned long ecache_flush_linesize; +static unsigned long ecache_flush_size; + +/* WARNING: The error trap handlers in assembly know the precise + * layout of the following structure. + * + * C-level handlers below use this information to log the error + * and then determine how to recover (if possible). + */ +struct cheetah_err_info { +/*0x00*/u64 afsr; +/*0x08*/u64 afar; + + /* D-cache state */ +/*0x10*/u64 dcache_data[4]; /* The actual data */ +/*0x30*/u64 dcache_index; /* D-cache index */ +/*0x38*/u64 dcache_tag; /* D-cache tag/valid */ +/*0x40*/u64 dcache_utag; /* D-cache microtag */ +/*0x48*/u64 dcache_stag; /* D-cache snooptag */ + + /* I-cache state */ +/*0x50*/u64 icache_data[8]; /* The actual insns + predecode */ +/*0x90*/u64 icache_index; /* I-cache index */ +/*0x98*/u64 icache_tag; /* I-cache phys tag */ +/*0xa0*/u64 icache_utag; /* I-cache microtag */ +/*0xa8*/u64 icache_stag; /* I-cache snooptag */ +/*0xb0*/u64 icache_upper; /* I-cache upper-tag */ +/*0xb8*/u64 icache_lower; /* I-cache lower-tag */ + + /* E-cache state */ +/*0xc0*/u64 ecache_data[4]; /* 32 bytes from staging registers */ +/*0xe0*/u64 ecache_index; /* E-cache index */ +/*0xe8*/u64 ecache_tag; /* E-cache tag/state */ + +/*0xf0*/u64 __pad[32 - 30]; +}; +#define CHAFSR_INVALID ((u64)-1L) + +/* This is allocated at boot time based upon the largest hardware + * cpu ID in the system. We allocate two entries per cpu, one for + * TL==0 logging and one for TL >= 1 logging. + */ +struct cheetah_err_info *cheetah_error_log; + +static __inline__ struct cheetah_err_info *cheetah_get_error_log(unsigned long afsr) +{ + struct cheetah_err_info *p; + int cpu = smp_processor_id(); + + if (!cheetah_error_log) + return NULL; + + p = cheetah_error_log + (cpu * 2); + if ((afsr & CHAFSR_TL1) != 0UL) + p++; + + return p; +} + +extern unsigned int tl0_fecc[], tl1_fecc[]; +extern unsigned int tl0_cee[], tl1_cee[]; +extern unsigned int tl0_iae[], tl1_iae[]; +extern unsigned int tl0_dae[], tl1_dae[]; +extern unsigned int cheetah_fecc_trap_vector[], cheetah_fecc_trap_vector_tl1[]; +extern unsigned int cheetah_cee_trap_vector[], cheetah_cee_trap_vector_tl1[]; +extern unsigned int cheetah_deferred_trap_vector[], cheetah_deferred_trap_vector_tl1[]; + +void cheetah_ecache_flush_init(void) +{ + unsigned long largest_size, smallest_linesize, order; + char type[16]; + int node, highest_cpu, i; + + /* Scan all cpu device tree nodes, note two values: + * 1) largest E-cache size + * 2) smallest E-cache line size + */ + largest_size = 0UL; + smallest_linesize = ~0UL; + node = prom_getchild(prom_root_node); + while ((node = prom_getsibling(node)) != 0) { + prom_getstring(node, "device_type", type, sizeof(type)); + if (!strcmp(type, "cpu")) { + unsigned long val; + + val = prom_getintdefault(node, "ecache-size", + (2 * 1024 * 1024)); + if (val > largest_size) + largest_size = val; + val = prom_getintdefault(node, "ecache-line-size", 64); + if (val < smallest_linesize) + smallest_linesize = val; + } + } + if (largest_size == 0UL || smallest_linesize == ~0UL) { + prom_printf("cheetah_ecache_flush_init: Cannot probe cpu E-cache " + "parameters.\n"); + prom_halt(); + } + + ecache_flush_size = (2 * largest_size); + ecache_flush_linesize = smallest_linesize; + + /* Discover a physically contiguous chunk of physical + * memory in 'sp_banks' of size ecache_flush_size calculated + * above. Store the physical base of this area at + * ecache_flush_physbase. + */ + for (node = 0; ; node++) { + if (sp_banks[node].num_bytes == 0) + break; + if (sp_banks[node].num_bytes >= ecache_flush_size) { + ecache_flush_physbase = sp_banks[node].base_addr; + break; + } + } + + /* Note: Zero would be a valid value of ecache_flush_physbase so + * don't use that as the success test. :-) + */ + if (sp_banks[node].num_bytes == 0) { + prom_printf("cheetah_ecache_flush_init: Cannot find %d byte " + "contiguous physical memory.\n", ecache_flush_size); + prom_halt(); + } + + /* Now allocate error trap reporting scoreboard. */ + highest_cpu = 0; +#ifdef CONFIG_SMP + for (i = 0; i < NR_CPUS; i++) { + if ((1UL << i) & cpu_present_map) + highest_cpu = i; + } +#endif + highest_cpu++; + node = highest_cpu * (2 * sizeof(struct cheetah_err_info)); + for (order = 0; order < MAX_ORDER; order++) { + if ((PAGE_SIZE << order) >= node) + break; + } + cheetah_error_log = (struct cheetah_err_info *) + __get_free_pages(GFP_KERNEL, order); + if (!cheetah_error_log) { + prom_printf("cheetah_ecache_flush_init: Failed to allocate " + "error logging scoreboard (%d bytes).\n", node); + prom_halt(); + } + memset(cheetah_error_log, 0, PAGE_SIZE << order); + + /* Mark all AFSRs as invalid so that the trap handler will + * log new new information there. + */ + for (i = 0; i < 2 * highest_cpu; i++) + cheetah_error_log[i].afsr = CHAFSR_INVALID; + + /* Now patch trap tables. */ + memcpy(tl0_fecc, cheetah_fecc_trap_vector, (8 * 4)); + memcpy(tl1_fecc, cheetah_fecc_trap_vector_tl1, (8 * 4)); + memcpy(tl0_cee, cheetah_cee_trap_vector, (8 * 4)); + memcpy(tl1_cee, cheetah_cee_trap_vector_tl1, (8 * 4)); + memcpy(tl0_iae, cheetah_deferred_trap_vector, (8 * 4)); + memcpy(tl1_iae, cheetah_deferred_trap_vector_tl1, (8 * 4)); + memcpy(tl0_dae, cheetah_deferred_trap_vector, (8 * 4)); + memcpy(tl1_dae, cheetah_deferred_trap_vector_tl1, (8 * 4)); + flushi(PAGE_OFFSET); +} + +static void cheetah_flush_ecache(void) +{ + unsigned long flush_base = ecache_flush_physbase; + unsigned long flush_linesize = ecache_flush_linesize; + unsigned long flush_size = ecache_flush_size; + + __asm__ __volatile__("1: subcc %0, %4, %0\n\t" + " bne,pt %%xcc, 1b\n\t" + " ldxa [%2 + %0] %3, %%g0\n\t" + : "=&r" (flush_size) + : "0" (flush_size), "r" (flush_base), + "i" (ASI_PHYS_USE_EC), "r" (flush_linesize)); +} + +static void cheetah_flush_ecache_line(unsigned long physaddr) +{ + unsigned long alias; + + physaddr &= ~(8UL - 1UL); + physaddr = (ecache_flush_physbase + + (physaddr & ((ecache_flush_size>>1UL) - 1UL))); + alias = physaddr + (ecache_flush_size >> 1UL); + __asm__ __volatile__("ldxa [%0] %2, %%g0\n\t" + "ldxa [%1] %2, %%g0\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (physaddr), "r" (alias), + "i" (ASI_PHYS_USE_EC)); +} + +#ifdef CONFIG_SMP +unsigned long cheetah_tune_scheduling(void) +{ + unsigned long tick1, tick2, raw; + + __asm__ __volatile__("rd %%tick, %0" : "=r" (tick1)); + cheetah_flush_ecache(); + __asm__ __volatile__("rd %%tick, %0" : "=r" (tick2)); + + raw = (tick2 - tick1); + + return (raw - (raw >> 2)); +} +#endif + +/* Unfortunately, the diagnostic access to the I-cache tags we need to + * use to clear the thing interferes with I-cache coherency transactions. + * + * So we must only flush the I-cache when it is disabled. + */ +static void cheetah_flush_icache(void) +{ + unsigned long dcu_save, i; + + /* Save current DCU, disable I-cache. */ + __asm__ __volatile__("ldxa [%%g0] %1, %0\n\t" + "or %0, %2, %%g1\n\t" + "stxa %%g1, [%%g0] %1\n\t" + "membar #Sync" + : "=r" (dcu_save) + : "i" (ASI_DCU_CONTROL_REG), "i" (DCU_IC) + : "g1"); + + /* Clear the valid bits in all the tags. */ + for (i = 0; i < (1 << 16); i += (1 << 5)) { + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (i | (2 << 3)), "i" (ASI_IC_TAG)); + } + + /* Restore DCU register */ + __asm__ __volatile__("stxa %0, [%%g0] %1\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (dcu_save), "i" (ASI_DCU_CONTROL_REG)); +} + +static void cheetah_flush_dcache(void) +{ + unsigned long i; + + for (i = 0; i < (1 << 16); i += (1 << 5)) { + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (i), "i" (ASI_DCACHE_TAG)); + } +} + +/* Conversion tables used to frob Cheetah AFSR syndrome values into + * something palatable to the memory controller driver get_unumber + * routine. + */ +#define MT0 137 +#define MT1 138 +#define MT2 139 +#define NONE 254 +#define MTC0 140 +#define MTC1 141 +#define MTC2 142 +#define MTC3 143 +#define C0 128 +#define C1 129 +#define C2 130 +#define C3 131 +#define C4 132 +#define C5 133 +#define C6 134 +#define C7 135 +#define C8 136 +#define M2 144 +#define M3 145 +#define M4 146 +#define M 147 +static unsigned char cheetah_ecc_syntab[] = { +/*00*/NONE, C0, C1, M2, C2, M2, M3, 47, C3, M2, M2, 53, M2, 41, 29, M, +/*01*/C4, M, M, 50, M2, 38, 25, M2, M2, 33, 24, M2, 11, M, M2, 16, +/*02*/C5, M, M, 46, M2, 37, 19, M2, M, 31, 32, M, 7, M2, M2, 10, +/*03*/M2, 40, 13, M2, 59, M, M2, 66, M, M2, M2, 0, M2, 67, 71, M, +/*04*/C6, M, M, 43, M, 36, 18, M, M2, 49, 15, M, 63, M2, M2, 6, +/*05*/M2, 44, 28, M2, M, M2, M2, 52, 68, M2, M2, 62, M2, M3, M3, M4, +/*06*/M2, 26, 106, M2, 64, M, M2, 2, 120, M, M2, M3, M, M3, M3, M4, +/*07*/116, M2, M2, M3, M2, M3, M, M4, M2, 58, 54, M2, M, M4, M4, M3, +/*08*/C7, M2, M, 42, M, 35, 17, M2, M, 45, 14, M2, 21, M2, M2, 5, +/*09*/M, 27, M, M, 99, M, M, 3, 114, M2, M2, 20, M2, M3, M3, M, +/*0a*/M2, 23, 113, M2, 112, M2, M, 51, 95, M, M2, M3, M2, M3, M3, M2, +/*0b*/103, M, M2, M3, M2, M3, M3, M4, M2, 48, M, M, 73, M2, M, M3, +/*0c*/M2, 22, 110, M2, 109, M2, M, 9, 108, M2, M, M3, M2, M3, M3, M, +/*0d*/102, M2, M, M, M2, M3, M3, M, M2, M3, M3, M2, M, M4, M, M3, +/*0e*/98, M, M2, M3, M2, M, M3, M4, M2, M3, M3, M4, M3, M, M, M, +/*0f*/M2, M3, M3, M, M3, M, M, M, 56, M4, M, M3, M4, M, M, M, +/*10*/C8, M, M2, 39, M, 34, 105, M2, M, 30, 104, M, 101, M, M, 4, +/*11*/M, M, 100, M, 83, M, M2, 12, 87, M, M, 57, M2, M, M3, M, +/*12*/M2, 97, 82, M2, 78, M2, M2, 1, 96, M, M, M, M, M, M3, M2, +/*13*/94, M, M2, M3, M2, M, M3, M, M2, M, 79, M, 69, M, M4, M, +/*14*/M2, 93, 92, M, 91, M, M2, 8, 90, M2, M2, M, M, M, M, M4, +/*15*/89, M, M, M3, M2, M3, M3, M, M, M, M3, M2, M3, M2, M, M3, +/*16*/86, M, M2, M3, M2, M, M3, M, M2, M, M3, M, M3, M, M, M3, +/*17*/M, M, M3, M2, M3, M2, M4, M, 60, M, M2, M3, M4, M, M, M2, +/*18*/M2, 88, 85, M2, 84, M, M2, 55, 81, M2, M2, M3, M2, M3, M3, M4, +/*19*/77, M, M, M, M2, M3, M, M, M2, M3, M3, M4, M3, M2, M, M, +/*1a*/74, M, M2, M3, M, M, M3, M, M, M, M3, M, M3, M, M4, M3, +/*1b*/M2, 70, 107, M4, 65, M2, M2, M, 127, M, M, M, M2, M3, M3, M, +/*1c*/80, M2, M2, 72, M, 119, 118, M, M2, 126, 76, M, 125, M, M4, M3, +/*1d*/M2, 115, 124, M, 75, M, M, M3, 61, M, M4, M, M4, M, M, M, +/*1e*/M, 123, 122, M4, 121, M4, M, M3, 117, M2, M2, M3, M4, M3, M, M, +/*1f*/111, M, M, M, M4, M3, M3, M, M, M, M3, M, M3, M2, M, M +}; +static unsigned char cheetah_mtag_syntab[] = { + NONE, MTC0, + MTC1, NONE, + MTC2, NONE, + NONE, MT0, + MTC3, NONE, + NONE, MT1, + NONE, MT2, + NONE, NONE +}; + +/* This table is ordered in priority of errors and matches the + * AFAR overwrite policy as well. + */ +static struct { + unsigned long mask; + char *name; +} cheetah_error_table[] = { + { CHAFSR_PERR, "System interface protocol error" }, + { CHAFSR_IERR, "Internal processor error" }, + { CHAFSR_ISAP, "System request parity error on incoming addresss" }, + { CHAFSR_UCU, "Uncorrectable E-cache ECC error for ifetch/data" }, + { CHAFSR_UCC, "SW Correctable E-cache ECC error for ifetch/data" }, + { CHAFSR_UE, "Uncorrectable system bus data ECC error for read" }, + { CHAFSR_EDU, "Uncorrectable E-cache ECC error for stmerge/blkld" }, + { CHAFSR_EMU, "Uncorrectable system bus MTAG error" }, + { CHAFSR_WDU, "Uncorrectable E-cache ECC error for writeback" }, + { CHAFSR_CPU, "Uncorrectable ECC error for copyout" }, + { CHAFSR_CE, "HW corrected system bus data ECC error for read" }, + { CHAFSR_EDC, "HW corrected E-cache ECC error for stmerge/blkld" }, + { CHAFSR_EMC, "HW corrected system bus MTAG ECC error" }, + { CHAFSR_WDC, "HW corrected E-cache ECC error for writeback" }, + { CHAFSR_CPC, "HW corrected ECC error for copyout" }, + { CHAFSR_TO, "Unmapped error from system bus" }, + { CHAFSR_BERR, "Bus error response from system bus" }, + /* These two do not update the AFAR. */ + { CHAFSR_IVC, "HW corrected system bus data ECC error for ivec read" }, + { CHAFSR_IVU, "Uncorrectable system bus data ECC error for ivec read" }, + { 0, NULL } +}; + +/* Return the highest priority error conditon mentioned. */ +static __inline__ unsigned long cheetah_get_hipri(unsigned long afsr) +{ + unsigned long tmp = 0; + int i; + + for (i = 0; cheetah_error_table[i].mask; i++) { + if ((tmp = (afsr & cheetah_error_table[i].mask)) != 0UL) + return tmp; + } + return tmp; +} + +static char *cheetah_get_string(unsigned long bit) +{ + int i; + + for (i = 0; cheetah_error_table[i].mask; i++) { + if ((bit & cheetah_error_table[i].mask) != 0UL) + return cheetah_error_table[i].name; + } + return "???"; +} + +extern int chmc_getunumber(int, unsigned long, char *, int); + +static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *info, + unsigned long afsr, unsigned long afar, int recoverable) +{ + unsigned long hipri; + char unum[256]; + + printk("%s" "ERROR(%d): Cheetah error trap taken afsr[%016lx] afar[%016lx] TL1(%d)\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + afsr, afar, + (afsr & CHAFSR_TL1) ? 1 : 0); + printk("%s" "ERROR(%d): TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + regs->tpc, regs->tnpc, regs->tstate); + printk("%s" "ERROR(%d): M_SYND(%lx), E_SYND(%lx)%s%s\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT, + (afsr & CHAFSR_E_SYNDROME) >> CHAFSR_E_SYNDROME_SHIFT, + (afsr & CHAFSR_ME) ? ", Multiple Errors" : "", + (afsr & CHAFSR_PRIV) ? ", Privileged" : ""); + hipri = cheetah_get_hipri(afsr); + printk("%s" "ERROR(%d): Highest priority error (%016lx) \"%s\"\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + hipri, cheetah_get_string(hipri)); + + /* Try to get unumber if relevant. */ +#define ESYND_ERRORS (CHAFSR_IVC | CHAFSR_IVU | \ + CHAFSR_CPC | CHAFSR_CPU | \ + CHAFSR_UE | CHAFSR_CE | \ + CHAFSR_EDC | CHAFSR_EDU | \ + CHAFSR_UCC | CHAFSR_UCU | \ + CHAFSR_WDU | CHAFSR_WDC) +#define MSYND_ERRORS (CHAFSR_EMC | CHAFSR_EMU) + if (afsr & ESYND_ERRORS) { + int syndrome; + int ret; + + syndrome = (afsr & CHAFSR_E_SYNDROME) >> CHAFSR_E_SYNDROME_SHIFT; + syndrome = cheetah_ecc_syntab[syndrome]; + ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum)); + if (ret != -1) + printk("%s" "ERROR(%d): AFAR E-syndrome [%s]\n", + (recoverable ? KERN_WARNING : KERN_CRIT), + smp_processor_id(), unum); + } else if (afsr & MSYND_ERRORS) { + int syndrome; + int ret; + + syndrome = (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT; + syndrome = cheetah_mtag_syntab[syndrome]; + ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum)); + if (ret != -1) + printk("%s" "ERROR(%d): AFAR M-syndrome [%s]\n", + (recoverable ? KERN_WARNING : KERN_CRIT), + smp_processor_id(), unum); + } + + /* Now dump the cache snapshots. */ + printk("%s" "ERROR(%d): D-cache idx[%x] tag[%016lx] utag[%016lx] stag[%016lx]\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + (int) info->dcache_index, + info->dcache_tag, + info->dcache_utag, + info->dcache_stag); + printk("%s" "ERROR(%d): D-cache data0[%016lx] data1[%016lx] data2[%016lx] data3[%016lx]\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + info->dcache_data[0], + info->dcache_data[1], + info->dcache_data[2], + info->dcache_data[3]); + printk("%s" "ERROR(%d): I-cache idx[%x] tag[%016lx] utag[%016lx] stag[%016lx] " + "u[%016lx] l[%016lx]\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + (int) info->icache_index, + info->icache_tag, + info->icache_utag, + info->icache_stag, + info->icache_upper, + info->icache_lower); + printk("%s" "ERROR(%d): I-cache INSN0[%016lx] INSN1[%016lx] INSN2[%016lx] INSN3[%016lx]\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + info->icache_data[0], + info->icache_data[1], + info->icache_data[2], + info->icache_data[3]); + printk("%s" "ERROR(%d): I-cache INSN4[%016lx] INSN5[%016lx] INSN6[%016lx] INSN7[%016lx]\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + info->icache_data[4], + info->icache_data[5], + info->icache_data[6], + info->icache_data[7]); + printk("%s" "ERROR(%d): E-cache idx[%x] tag[%016lx]\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + (int) info->ecache_index, info->ecache_tag); + printk("%s" "ERROR(%d): E-cache data0[%016lx] data1[%016lx] data2[%016lx] data3[%016lx]\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + info->ecache_data[0], + info->ecache_data[1], + info->ecache_data[2], + info->ecache_data[3]); + + afsr = (afsr & ~hipri) & CHAFSR_ERRORS; + while (afsr != 0UL) { + unsigned long bit = cheetah_get_hipri(afsr); + + printk("%s" "ERROR: Multiple-error (%016lx) \"%s\"\n", + (recoverable ? KERN_WARNING : KERN_CRIT), + bit, cheetah_get_string(bit)); + + afsr &= ~bit; + } + + if (!recoverable) + printk(KERN_CRIT "ERROR: This condition is not recoverable.\n"); +} + +static int cheetah_recheck_errors(struct cheetah_err_info *logp) +{ + unsigned long afsr, afar; + int ret = 0; + + __asm__ __volatile__("ldxa [%%g0] %1, %0\n\t" + : "=r" (afsr) + : "i" (ASI_AFSR)); + if ((afsr & CHAFSR_ERRORS) != 0) { + if (logp != NULL) { + __asm__ __volatile__("ldxa [%%g0] %1, %0\n\t" + : "=r" (afar) + : "i" (ASI_AFAR)); + logp->afsr = afsr; + logp->afar = afar; + } + ret = 1; + } + __asm__ __volatile__("stxa %0, [%%g0] %1\n\t" + "membar #Sync\n\t" + : : "r" (afsr), "i" (ASI_AFSR)); + + return ret; +} + +void cheetah_fecc_handler(struct pt_regs *regs, unsigned long afsr, unsigned long afar) +{ + struct cheetah_err_info local_snapshot, *p; + int recoverable; + + /* Flush E-cache */ + cheetah_flush_ecache(); + + p = cheetah_get_error_log(afsr); + if (!p) { + prom_printf("ERROR: Early Fast-ECC error afsr[%016lx] afar[%016lx]\n", + afsr, afar); + prom_printf("ERROR: CPU(%d) TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n", + smp_processor_id(), regs->tpc, regs->tnpc, regs->tstate); + prom_halt(); + } + + /* Grab snapshot of logged error. */ + memcpy(&local_snapshot, p, sizeof(local_snapshot)); + + /* If the current trap snapshot does not match what the + * trap handler passed along into our args, big trouble. + * In such a case, mark the local copy as invalid. + * + * Else, it matches and we mark the afsr in the non-local + * copy as invalid so we may log new error traps there. + */ + if (p->afsr != afsr || p->afar != afar) + local_snapshot.afsr = CHAFSR_INVALID; + else + p->afsr = CHAFSR_INVALID; + + cheetah_flush_icache(); + cheetah_flush_dcache(); + + /* Re-enable I-cache/D-cache */ + __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t" + "or %%g1, %1, %%g1\n\t" + "stxa %%g1, [%%g0] %0\n\t" + "membar #Sync" + : /* no outputs */ + : "i" (ASI_DCU_CONTROL_REG), + "i" (DCU_DC | DCU_IC) + : "g1"); + + /* Re-enable error reporting */ + __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t" + "or %%g1, %1, %%g1\n\t" + "stxa %%g1, [%%g0] %0\n\t" + "membar #Sync" + : /* no outputs */ + : "i" (ASI_ESTATE_ERROR_EN), + "i" (ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN) + : "g1"); + + /* Decide if we can continue after handling this trap and + * logging the error. + */ + recoverable = 1; + if (afsr & (CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP)) + recoverable = 0; + + /* Re-check AFSR/AFAR. What we are looking for here is whether a new + * error was logged while we had error reporting traps disabled. + */ + if (cheetah_recheck_errors(&local_snapshot)) { + unsigned long new_afsr = local_snapshot.afsr; + + /* If we got a new asynchronous error, die... */ + if (new_afsr & (CHAFSR_EMU | CHAFSR_EDU | + CHAFSR_WDU | CHAFSR_CPU | + CHAFSR_IVU | CHAFSR_UE | + CHAFSR_BERR | CHAFSR_TO)) + recoverable = 0; + } + + /* Log errors. */ + cheetah_log_errors(regs, &local_snapshot, afsr, afar, recoverable); + + if (!recoverable) + panic("Irrecoverable Fast-ECC error trap.\n"); + + /* Flush E-cache to kick the error trap handlers out. */ + cheetah_flush_ecache(); +} + +/* Try to fix a correctable error by pushing the line out from + * the E-cache. Recheck error reporting registers to see if the + * problem is intermittent. + */ +static int cheetah_fix_ce(unsigned long physaddr) +{ + unsigned long orig_estate; + unsigned long alias1, alias2; + int ret; + + /* Make sure correctable error traps are disabled. */ + __asm__ __volatile__("ldxa [%%g0] %2, %0\n\t" + "andn %0, %1, %%g1\n\t" + "stxa %%g1, [%%g0] %2\n\t" + "membar #Sync" + : "=&r" (orig_estate) + : "i" (ESTATE_ERROR_CEEN), + "i" (ASI_ESTATE_ERROR_EN) + : "g1"); + + /* We calculate alias addresses that will force the + * cache line in question out of the E-cache. Then + * we bring it back in with an atomic instruction so + * that we get it in some modified/exclusive state, + * then we displace it again to try and get proper ECC + * pushed back into the system. + */ + physaddr &= ~(8UL - 1UL); + alias1 = (ecache_flush_physbase + + (physaddr & ((ecache_flush_size >> 1) - 1))); + alias2 = alias1 + (ecache_flush_size >> 1); + __asm__ __volatile__("ldxa [%0] %3, %%g0\n\t" + "ldxa [%1] %3, %%g0\n\t" + "casxa [%2] %3, %%g0, %%g0\n\t" + "ldxa [%0] %3, %%g0\n\t" + "ldxa [%1] %3, %%g0\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (alias1), "r" (alias2), + "r" (physaddr), "i" (ASI_PHYS_USE_EC)); + + /* Did that trigger another error? */ + if (cheetah_recheck_errors(NULL)) { + /* Try one more time. */ + __asm__ __volatile__("ldxa [%0] %1, %%g0\n\t" + "membar #Sync" + : : "r" (physaddr), "i" (ASI_PHYS_USE_EC)); + if (cheetah_recheck_errors(NULL)) + ret = 2; + else + ret = 1; + } else { + /* No new error, intermittent problem. */ + ret = 0; + } + + /* Restore error enables. */ + __asm__ __volatile__("stxa %0, [%%g0] %1\n\t" + "membar #Sync" + : : "r" (orig_estate), "i" (ASI_ESTATE_ERROR_EN)); + + return ret; +} + +/* Return non-zero if PADDR is a valid physical memory address. */ +static int cheetah_check_main_memory(unsigned long paddr) +{ + int i; + + for (i = 0; ; i++) { + if (sp_banks[i].num_bytes == 0) + break; + if (paddr >= sp_banks[i].base_addr && + paddr < (sp_banks[i].base_addr + sp_banks[i].num_bytes)) + return 1; + } + return 0; +} + +void cheetah_cee_handler(struct pt_regs *regs, unsigned long afsr, unsigned long afar) +{ + struct cheetah_err_info local_snapshot, *p; + int recoverable, is_memory; + + p = cheetah_get_error_log(afsr); + if (!p) { + prom_printf("ERROR: Early CEE error afsr[%016lx] afar[%016lx]\n", + afsr, afar); + prom_printf("ERROR: CPU(%d) TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n", + smp_processor_id(), regs->tpc, regs->tnpc, regs->tstate); + prom_halt(); + } + + /* Grab snapshot of logged error. */ + memcpy(&local_snapshot, p, sizeof(local_snapshot)); + + /* If the current trap snapshot does not match what the + * trap handler passed along into our args, big trouble. + * In such a case, mark the local copy as invalid. + * + * Else, it matches and we mark the afsr in the non-local + * copy as invalid so we may log new error traps there. + */ + if (p->afsr != afsr || p->afar != afar) + local_snapshot.afsr = CHAFSR_INVALID; + else + p->afsr = CHAFSR_INVALID; + + is_memory = cheetah_check_main_memory(afar); + + if (is_memory && (afsr & CHAFSR_CE) != 0UL) { + /* XXX Might want to log the results of this operation + * XXX somewhere... -DaveM + */ + cheetah_fix_ce(afar); + } + + { + int flush_all, flush_line; + + flush_all = flush_line = 0; + if ((afsr & CHAFSR_EDC) != 0UL) { + if ((afsr & CHAFSR_ERRORS) == CHAFSR_EDC) + flush_line = 1; + else + flush_all = 1; + } else if ((afsr & CHAFSR_CPC) != 0UL) { + if ((afsr & CHAFSR_ERRORS) == CHAFSR_CPC) + flush_line = 1; + else + flush_all = 1; + } + + /* Trap handler only disabled I-cache, flush it. */ + cheetah_flush_icache(); + + /* Re-enable I-cache */ + __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t" + "or %%g1, %1, %%g1\n\t" + "stxa %%g1, [%%g0] %0\n\t" + "membar #Sync" + : /* no outputs */ + : "i" (ASI_DCU_CONTROL_REG), + "i" (DCU_IC) + : "g1"); + + if (flush_all) + cheetah_flush_ecache(); + else if (flush_line) + cheetah_flush_ecache_line(afar); + } + + /* Re-enable error reporting */ + __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t" + "or %%g1, %1, %%g1\n\t" + "stxa %%g1, [%%g0] %0\n\t" + "membar #Sync" + : /* no outputs */ + : "i" (ASI_ESTATE_ERROR_EN), + "i" (ESTATE_ERROR_CEEN) + : "g1"); + + /* Decide if we can continue after handling this trap and + * logging the error. + */ + recoverable = 1; + if (afsr & (CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP)) + recoverable = 0; + + /* Re-check AFSR/AFAR */ + (void) cheetah_recheck_errors(&local_snapshot); + + /* Log errors. */ + cheetah_log_errors(regs, &local_snapshot, afsr, afar, recoverable); + + if (!recoverable) + panic("Irrecoverable Correctable-ECC error trap.\n"); +} + +void cheetah_deferred_handler(struct pt_regs *regs, unsigned long afsr, unsigned long afar) +{ + struct cheetah_err_info local_snapshot, *p; + int recoverable, is_memory; + +#ifdef CONFIG_PCI + /* Check for the special PCI poke sequence. */ + if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) { + cheetah_flush_icache(); + cheetah_flush_dcache(); + + /* Re-enable I-cache/D-cache */ + __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t" + "or %%g1, %1, %%g1\n\t" + "stxa %%g1, [%%g0] %0\n\t" + "membar #Sync" + : /* no outputs */ + : "i" (ASI_DCU_CONTROL_REG), + "i" (DCU_DC | DCU_IC) + : "g1"); + + /* Re-enable error reporting */ + __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t" + "or %%g1, %1, %%g1\n\t" + "stxa %%g1, [%%g0] %0\n\t" + "membar #Sync" + : /* no outputs */ + : "i" (ASI_ESTATE_ERROR_EN), + "i" (ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN) + : "g1"); + + (void) cheetah_recheck_errors(NULL); + + pci_poke_faulted = 1; + regs->tpc += 4; + regs->tnpc = regs->tpc + 4; + return; + } +#endif + + p = cheetah_get_error_log(afsr); + if (!p) { + prom_printf("ERROR: Early deferred error afsr[%016lx] afar[%016lx]\n", + afsr, afar); + prom_printf("ERROR: CPU(%d) TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n", + smp_processor_id(), regs->tpc, regs->tnpc, regs->tstate); + prom_halt(); + } + + /* Grab snapshot of logged error. */ + memcpy(&local_snapshot, p, sizeof(local_snapshot)); + + /* If the current trap snapshot does not match what the + * trap handler passed along into our args, big trouble. + * In such a case, mark the local copy as invalid. + * + * Else, it matches and we mark the afsr in the non-local + * copy as invalid so we may log new error traps there. + */ + if (p->afsr != afsr || p->afar != afar) + local_snapshot.afsr = CHAFSR_INVALID; + else + p->afsr = CHAFSR_INVALID; + + is_memory = cheetah_check_main_memory(afar); + + { + int flush_all, flush_line; + + flush_all = flush_line = 0; + if ((afsr & CHAFSR_EDU) != 0UL) { + if ((afsr & CHAFSR_ERRORS) == CHAFSR_EDU) + flush_line = 1; + else + flush_all = 1; + } else if ((afsr & CHAFSR_BERR) != 0UL) { + if ((afsr & CHAFSR_ERRORS) == CHAFSR_BERR) + flush_line = 1; + else + flush_all = 1; + } + + cheetah_flush_icache(); + cheetah_flush_dcache(); + + /* Re-enable I/D caches */ + __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t" + "or %%g1, %1, %%g1\n\t" + "stxa %%g1, [%%g0] %0\n\t" + "membar #Sync" + : /* no outputs */ + : "i" (ASI_DCU_CONTROL_REG), + "i" (DCU_IC | DCU_DC) + : "g1"); + + if (flush_all) + cheetah_flush_ecache(); + else if (flush_line) + cheetah_flush_ecache_line(afar); + } + + /* Re-enable error reporting */ + __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t" + "or %%g1, %1, %%g1\n\t" + "stxa %%g1, [%%g0] %0\n\t" + "membar #Sync" + : /* no outputs */ + : "i" (ASI_ESTATE_ERROR_EN), + "i" (ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN) + : "g1"); + + /* Decide if we can continue after handling this trap and + * logging the error. + */ + recoverable = 1; + if (afsr & (CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP)) + recoverable = 0; + + /* Re-check AFSR/AFAR. What we are looking for here is whether a new + * error was logged while we had error reporting traps disabled. + */ + if (cheetah_recheck_errors(&local_snapshot)) { + unsigned long new_afsr = local_snapshot.afsr; + + /* If we got a new asynchronous error, die... */ + if (new_afsr & (CHAFSR_EMU | CHAFSR_EDU | + CHAFSR_WDU | CHAFSR_CPU | + CHAFSR_IVU | CHAFSR_UE | + CHAFSR_BERR | CHAFSR_TO)) + recoverable = 0; + } + + /* Log errors. */ + cheetah_log_errors(regs, &local_snapshot, afsr, afar, recoverable); + + /* "Recoverable" here means we try to yank the page from ever + * being newly used again. This depends upon a few things: + * 1) Must be main memory, and AFAR must be valid. + * 2) If we trapped from use, OK. + * 3) Else, if we trapped from kernel we must find exception + * table entry (ie. we have to have been accessing user + * space). + * + * If AFAR is not in main memory, or we trapped from kernel + * and cannot find an exception table entry, it is unacceptable + * to try and continue. + */ + if (recoverable && is_memory) { + if ((regs->tstate & TSTATE_PRIV) == 0UL) { + /* OK, usermode access. */ + recoverable = 1; + } else { + unsigned long g2 = regs->u_regs[UREG_G2]; + unsigned long fixup = search_exception_table(regs->tpc, &g2); + + if (fixup != 0UL) { + /* OK, kernel access to userspace. */ + recoverable = 1; + + } else { + /* BAD, privileged state is corrupted. */ + recoverable = 0; + } + + if (recoverable) { + struct page *page = virt_to_page(__va(afar)); + + if (VALID_PAGE(page)) + get_page(page); + else + recoverable = 0; + + /* Only perform fixup if we still have a + * recoverable condition. + */ + if (fixup != 0UL && recoverable) { + regs->tpc = fixup; + regs->tnpc = regs->tpc + 4; + regs->u_regs[UREG_G2] = g2; + } + } + } + } else { + recoverable = 0; + } + + if (!recoverable) + panic("Irrecoverable deferred error trap.\n"); +} + void do_fpe_common(struct pt_regs *regs) { if(regs->tstate & TSTATE_PRIV) { @@ -575,9 +1332,6 @@ void do_fpieee(struct pt_regs *regs) { -#ifdef DEBUG_FPU - printk("fpieee %016lx\n", current->thread.xfsr[0]); -#endif do_fpe_common(regs); } @@ -594,10 +1348,8 @@ ret = do_mathemu(regs, f); break; } - if (ret) return; -#ifdef DEBUG_FPU - printk("fpother %016lx\n", current->thread.xfsr[0]); -#endif + if (ret) + return; do_fpe_common(regs); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/ttable.S linux.ac/arch/sparc64/kernel/ttable.S --- linux.vanilla/arch/sparc64/kernel/ttable.S Tue Apr 3 17:31:59 2001 +++ linux.ac/arch/sparc64/kernel/ttable.S Sat Apr 14 01:20:18 2001 @@ -1,12 +1,16 @@ -/* $Id: ttable.S,v 1.32 2001/03/23 07:56:30 davem Exp $ - * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions. +/* $Id: ttable.S,v 1.33 2001/03/28 10:56:34 davem Exp $ + * ttable.S: Sparc V9 Trap Table(s) with SpitFire/Cheetah extensions. * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996, 2001 David S. Miller (davem@caip.rutgers.edu) */ #include <linux/config.h> - .globl sparc64_ttable_tl0, sparc64_ttable_tl1, + .globl sparc64_ttable_tl0, sparc64_ttable_tl1 + .globl tl0_fecc, tl1_fecc + .globl tl0_cee, tl1_cee + .globl tl0_iae, tl1_iae + .globl tl0_dae, tl1_dae sparc64_ttable_tl0: tl0_resv000: BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3) @@ -64,7 +68,8 @@ #include "dtlb_base.S" tl0_daprot: #include "dtlb_prot.S" -tl0_resv070: BTRAP(0x70) BTRAP(0x71) BTRAP(0x72) BTRAP(0x73) BTRAP(0x74) BTRAP(0x75) +tl0_fecc: BTRAP(0x70) /* Fast-ECC on Cheetah */ +tl0_resv071: BTRAP(0x71) BTRAP(0x72) BTRAP(0x73) BTRAP(0x74) BTRAP(0x75) tl0_resv076: BTRAP(0x76) BTRAP(0x77) BTRAP(0x78) BTRAP(0x79) BTRAP(0x7a) BTRAP(0x7b) tl0_resv07c: BTRAP(0x7c) BTRAP(0x7d) BTRAP(0x7e) BTRAP(0x7f) tl0_s0n: SPILL_0_NORMAL @@ -203,13 +208,30 @@ tl1_ivec: TRAP_IVEC tl1_paw: TRAPTL1(do_paw_tl1) tl1_vaw: TRAPTL1(do_vaw_tl1) -tl1_cee: TRAPTL1_CEE + + /* The grotty trick to save %g1 into current->thread.kernel_cntd0 + * is because when we take this trap we could be interrupting trap + * code already using the trap alternate global registers. It is + * better to corrupt a performance counter than corrupt trap register + * state. We cross our fingers and pray that this store/load does + * not cause yet another CEE trap. + */ +tl1_cee: membar #Sync + stx %g1, [%g6 + AOFF_task_thread + AOFF_thread_kernel_cntd0] + ldxa [%g0] ASI_AFSR, %g1 + membar #Sync + stxa %g1, [%g0] ASI_AFSR + membar #Sync + ldx [%g6 + AOFF_task_thread + AOFF_thread_kernel_cntd0], %g1 + retry + tl1_iamiss: BTRAPTL1(0x64) BTRAPTL1(0x65) BTRAPTL1(0x66) BTRAPTL1(0x67) tl1_damiss: #include "dtlb_backend.S" tl1_daprot: #include "dtlb_prot.S" -tl1_resv070: BTRAPTL1(0x70) BTRAPTL1(0x71) BTRAPTL1(0x72) BTRAPTL1(0x73) +tl1_fecc: BTRAP(0x70) /* Fast-ECC on Cheetah */ +tl1_resc071: BTRAPTL1(0x71) BTRAPTL1(0x72) BTRAPTL1(0x73) tl1_resv074: BTRAPTL1(0x74) BTRAPTL1(0x75) BTRAPTL1(0x76) BTRAPTL1(0x77) tl1_resv078: BTRAPTL1(0x78) BTRAPTL1(0x79) BTRAPTL1(0x7a) BTRAPTL1(0x7b) tl1_resv07c: BTRAPTL1(0x7c) BTRAPTL1(0x7d) BTRAPTL1(0x7e) BTRAPTL1(0x7f) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/unaligned.c linux.ac/arch/sparc64/kernel/unaligned.c --- linux.vanilla/arch/sparc64/kernel/unaligned.c Tue Apr 3 17:31:59 2001 +++ linux.ac/arch/sparc64/kernel/unaligned.c Sat Apr 14 01:20:18 2001 @@ -1,4 +1,4 @@ -/* $Id: unaligned.c,v 1.21 2001/03/21 11:46:20 davem Exp $ +/* $Id: unaligned.c,v 1.23 2001/04/09 04:29:03 davem Exp $ * unaligned.c: Unaligned load/store trap handling with special * cases for the kernel to do them more quickly. * @@ -12,6 +12,7 @@ #include <linux/mm.h> #include <asm/asi.h> #include <asm/ptrace.h> +#include <asm/pstate.h> #include <asm/processor.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -376,6 +377,9 @@ regs->tpc = fixup; regs->tnpc = regs->tpc + 4; regs->u_regs [UREG_G2] = g2; + + regs->tstate &= ~TSTATE_ASI; + regs->tstate |= (ASI_AIUS << 24UL); } asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, unsigned long sfar, unsigned long sfsr) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/lib/blockops.S linux.ac/arch/sparc64/lib/blockops.S --- linux.vanilla/arch/sparc64/lib/blockops.S Tue Apr 3 17:31:59 2001 +++ linux.ac/arch/sparc64/lib/blockops.S Sat Apr 14 01:20:18 2001 @@ -1,4 +1,4 @@ -/* $Id: blockops.S,v 1.30 2001/03/22 13:10:10 davem Exp $ +/* $Id: blockops.S,v 1.31 2001/04/05 11:08:12 davem Exp $ * blockops.S: UltraSparc block zero optimized routines. * * Copyright (C) 1996, 1998, 1999, 2000 David S. Miller (davem@redhat.com) @@ -399,7 +399,6 @@ jmpl %o7 + 0x8, %g0 wrpr %g3, 0x0, %pstate - /* We will write cheetah optimized versions later. */ .globl cheetah_patch_pgcopyops cheetah_patch_pgcopyops: sethi %hi(FIX_INSN_1), %g1 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/mm/generic.c linux.ac/arch/sparc64/mm/generic.c --- linux.vanilla/arch/sparc64/mm/generic.c Tue Apr 3 17:31:59 2001 +++ linux.ac/arch/sparc64/mm/generic.c Sat Apr 14 01:20:25 2001 @@ -1,4 +1,4 @@ -/* $Id: generic.c,v 1.16 2001/03/25 04:40:05 davem Exp $ +/* $Id: generic.c,v 1.17 2001/04/09 04:08:06 davem Exp $ * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * @@ -8,6 +8,7 @@ #include <linux/kernel.h> #include <linux/mm.h> #include <linux/swap.h> +#include <linux/pagemap.h> #include <asm/pgalloc.h> #include <asm/pgtable.h> @@ -21,11 +22,7 @@ struct page *ptpage = pte_page(page); if ((!VALID_PAGE(ptpage)) || PageReserved(ptpage)) return; - /* - * free_page() used to be able to clear swap cache - * entries. We may now have to do it manually. - */ - free_page_and_swap_cache(ptpage); + page_cache_release(ptpage); return; } swap_free(pte_to_swp_entry(page)); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/mm/init.c linux.ac/arch/sparc64/mm/init.c --- linux.vanilla/arch/sparc64/mm/init.c Tue Apr 3 17:31:59 2001 +++ linux.ac/arch/sparc64/mm/init.c Sat Apr 14 01:20:25 2001 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.172 2001/03/24 09:36:01 davem Exp $ +/* $Id: init.c,v 1.174 2001/03/30 07:10:42 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) @@ -30,6 +30,9 @@ #include <asm/vaddrs.h> #include <asm/dma.h> #include <asm/starfire.h> +#include <asm/tlb.h> + +mmu_gather_t mmu_gathers[NR_CPUS]; extern void device_scan(void); @@ -1126,6 +1129,7 @@ /* paging_init() sets up the page tables */ extern void sun_serial_setup(void); +extern void cheetah_ecache_flush_init(void); static unsigned long last_valid_pfn; @@ -1466,6 +1470,9 @@ datapages << (PAGE_SHIFT-10), initpages << (PAGE_SHIFT-10), PAGE_OFFSET, (last_valid_pfn << PAGE_SHIFT)); + + if (tlb_type == cheetah) + cheetah_ecache_flush_init(); } void free_initmem (void) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/mm/modutil.c linux.ac/arch/sparc64/mm/modutil.c --- linux.vanilla/arch/sparc64/mm/modutil.c Mon Feb 19 03:49:54 2001 +++ linux.ac/arch/sparc64/mm/modutil.c Sat Apr 14 01:20:25 2001 @@ -1,4 +1,4 @@ -/* $Id: modutil.c,v 1.7 2001/02/13 01:16:44 davem Exp $ +/* $Id: modutil.c,v 1.8 2001/04/04 00:49:39 davem Exp $ * arch/sparc64/mm/modutil.c * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -59,7 +59,7 @@ *p = area; if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, GFP_KERNEL, PAGE_KERNEL)) { - vfree(addr); + module_unmap(addr); return NULL; } return addr; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/solaris/timod.c linux.ac/arch/sparc64/solaris/timod.c --- linux.vanilla/arch/sparc64/solaris/timod.c Sat Aug 5 02:16:11 2000 +++ linux.ac/arch/sparc64/solaris/timod.c Tue Apr 3 17:54:37 2001 @@ -611,7 +611,7 @@ return 0; } default: - printk("timod_putmsg: unsuported command %u.\n", ret); + printk("timod_putmsg: unsupported command %u.\n", ret); break; } return -EINVAL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/Makefile linux.ac/arch/um/Makefile --- linux.vanilla/arch/um/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/Makefile Sun Apr 15 22:55:58 2001 @@ -0,0 +1,80 @@ +include arch/$(ARCH)/Makefile-$(SUBARCH) + +include/linux/version.h: arch/$(ARCH)/Makefile + +ARCH_DIR = $(TOPDIR)/arch/um + +MAKEBOOT = $(MAKE) -C $(ARCH_DIR)/boot + +ifeq ($(CONFIG_DEBUGSYM),y) +DEBUG = -g +CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) +endif + +ifeq ($(CONFIG_GCOV),y) +CFLAGS += -fprofile-arcs -ftest-coverage +endif + +ifeq ($(CONFIG_GPROF), y) +PROFILE += -pg -DPROFILING +LINK_PROFILE = $(PROFILE) -Wl,--wrap,__monstartup +endif + +SUBDIRS += $(ARCH_DIR)/fs $(ARCH_DIR)/drivers $(ARCH_DIR)/kernel \ + $(ARCH_DIR)/sys-$(SUBARCH) + +LIBS += $(shell [ -e $(ARCH_DIR)/fs/fs.o ] && echo $(ARCH_DIR)/fs/fs.o) \ + $(ARCH_DIR)/kernel/um.o $(ARCH_DIR)/drivers/um_drivers.o \ + $(ARCH_DIR)/sys-$(SUBARCH)/sys.o + +ifeq ($(CONFIG_PT_PROXY), y) +SUBDIRS += $(ARCH_DIR)/ptproxy +LIBS += $(ARCH_DIR)/ptproxy/ptproxy.a +endif + +NESTING = 0 + +CFLAGS += $(DEBUG) $(PROFILE) $(ARCH_CFLAGS) -D__arch_um__ \ + -DSUBARCH=\"$(SUBARCH)\" -DNESTING=$(NESTING) + +#-D_FILE_OFFSET_BITS=64 + +LINKFLAGS += -r + +$(ARCH_DIR)/link.ld: + m4 -DSTART=$(shell echo $$((($(NESTING) + 1) * $(START_ADDR)))) \ + -DSUBARCH=$(SUBARCH) $(ARCH_DIR)/link.ld.in > $(ARCH_DIR)/link.ld + +ARCH_SYMLINKS = include/asm-um/arch arch/um/include/sysdep + +linux: $(ARCH_SYMLINKS) $(ARCH_DIR)/main.o vmlinux $(ARCH_DIR)/link.ld + mv vmlinux vmlinux.o + $(CC) -Wl,-T,$(ARCH_DIR)/link.ld $(LINK_PROFILE) -o linux -static \ + $(ARCH_DIR)/main.o vmlinux.o -L/usr/lib + rm -f $(ARCH_DIR)/link.ld + +USER_CFLAGS = $(patsubst -I%,,$(CFLAGS)) +USER_CFLAGS += -I../include + +$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c + $(CC) -D__KERNEL__ $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< + +archmrproper: + $(MAKE) -C $(ARCH_DIR)/sys-$(SUBARCH) archmrproper + rm -f linux x.i $(ARCH_SYMLINKS) include/asm \ + $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) + +archclean: + rm -f link.ld + @$(MAKEBOOT) clean + +archdep: $(ARCH_SYMLINKS) + @$(MAKEBOOT) dep + +include/asm-um/arch: + cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch + +arch/um/include/sysdep: + cd $(TOPDIR)/arch/um/include && ln -sf sysdep-$(SUBARCH) sysdep + +export SUBARCH diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/Makefile-i386 linux.ac/arch/um/Makefile-i386 --- linux.vanilla/arch/um/Makefile-i386 Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/Makefile-i386 Mon Apr 9 23:25:02 2001 @@ -0,0 +1,2 @@ +START_ADDR = 0x10000000 +ARCH_CFLAGS = -U__$(SUBARCH)__ -U$(SUBARCH) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/Makefile-ia64 linux.ac/arch/um/Makefile-ia64 --- linux.vanilla/arch/um/Makefile-ia64 Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/Makefile-ia64 Mon Apr 9 23:25:02 2001 @@ -0,0 +1 @@ +START_ADDR = 0x1000000000000000 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/Makefile-ppc linux.ac/arch/um/Makefile-ppc --- linux.vanilla/arch/um/Makefile-ppc Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/Makefile-ppc Mon Apr 9 23:25:02 2001 @@ -0,0 +1,2 @@ +START_ADDR = 0x20000000 +ARCH_CFLAGS = -U__powerpc__ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/boot/Makefile linux.ac/arch/um/boot/Makefile --- linux.vanilla/arch/um/boot/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/boot/Makefile Mon Apr 9 23:25:02 2001 @@ -0,0 +1,3 @@ +dep: + +clean: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/config.in linux.ac/arch/um/config.in --- linux.vanilla/arch/um/config.in Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/config.in Mon Apr 9 23:25:02 2001 @@ -0,0 +1,80 @@ +define_bool CONFIG_USERMODE y + +mainmenu_name "Linux/Usermode Kernel Configuration" + +define_bool CONFIG_ISA y +define_bool CONFIG_SBUS n + +define_bool CONFIG_UID16 y + +mainmenu_option next_comment +comment 'Code maturity level options' +bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL +endmenu + +mainmenu_option next_comment +comment 'Processor features' +bool 'Symmetric multi-processing support' CONFIG_SMP +comment 'General Setup' +define_bool CONFIG_STDIO_CONSOLE y +bool 'Enable loadable module support' CONFIG_MODULES +bool 'Networking support' CONFIG_NET +bool 'System V IPC' CONFIG_SYSVIPC +bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT +bool 'Sysctl support' CONFIG_SYSCTL +tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT +tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC +bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS +if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then + int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 +bool 'Virtual serial line' CONFIG_SSL +tristate 'Host filesystem' CONFIG_HOSTFS +fi +endmenu + +mainmenu_option next_comment +comment 'Block devices' +define_bool CONFIG_BLK_DEV_UBD y +bool 'Always do synchronous disk IO for UBD' CONFIG_BLK_DEV_UBD_SYNC +tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP +dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET +tristate 'RAM disk support' CONFIG_BLK_DEV_RAM +if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then + int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096 +fi +dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM +endmenu + +if [ "$CONFIG_NET" = "y" ]; then + source net/Config.in +fi + +if [ "$CONFIG_NET" = "y" ]; then + mainmenu_option next_comment + comment 'Network device support' + + bool 'Network device support' CONFIG_NETDEVICES + if [ "$CONFIG_NETDEVICES" = "y" ]; then + bool 'Virtual ethernet device' CONFIG_NET_UM_ETH + if [ "$CONFIG_NET_UM_ETH" = "y" ]; then + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_NETLINK" = "y" ]; then + tristate 'Ethertap network tap (EXPERIMENTAL)' CONFIG_ETHERTAP + fi + fi + fi + fi + bool 'Old slip-based network device' CONFIG_NET_UMN + endmenu +fi + +source fs/Config.in + +mainmenu_option next_comment +comment 'Kernel hacking' +bool 'Enable kernel debugging symbols' CONFIG_DEBUGSYM +dep_bool 'Enable ptrace proxy' CONFIG_PT_PROXY $CONFIG_DEBUGSYM +dep_bool 'Enable gprof support' CONFIG_GPROF $CONFIG_DEBUGSYM +dep_bool 'Enable gcov support' CONFIG_GCOV $CONFIG_DEBUGSYM +endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/config.release linux.ac/arch/um/config.release --- linux.vanilla/arch/um/config.release Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/config.release Mon Apr 9 23:25:02 2001 @@ -0,0 +1,192 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_USERMODE=y +CONFIG_ISA=y +# CONFIG_SBUS is not set +CONFIG_UID16=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Processor features +# +# CONFIG_SMP is not set + +# +# General Setup +# +CONFIG_STDIO_CONSOLE=y +CONFIG_MODULES=y +CONFIG_NET=y +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +CONFIG_SSL=y +CONFIG_HOSTFS=y + +# +# Block devices +# +CONFIG_BLK_DEV_UBD=y +# CONFIG_BLK_DEV_UBD_SYNC is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +CONFIG_NET_UM_ETH=y +CONFIG_NET_UMN=y + +# +# File systems +# +CONFIG_QUOTA=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m +CONFIG_REISERFS_FS=y +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_UMSDOS_FS=y +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +CONFIG_MINIX_FS=m +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_SUNRPC is not set +# CONFIG_LOCKD is not set +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# 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_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 +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_UTF8 is not set + +# +# Kernel hacking +# +# CONFIG_DEBUGSYM is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/defconfig linux.ac/arch/um/defconfig --- linux.vanilla/arch/um/defconfig Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/defconfig Mon Apr 9 23:25:02 2001 @@ -0,0 +1,195 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_USERMODE=y +CONFIG_ISA=y +# CONFIG_SBUS is not set +CONFIG_UID16=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Processor features +# +# CONFIG_SMP is not set + +# +# General Setup +# +CONFIG_STDIO_CONSOLE=y +CONFIG_MODULES=y +CONFIG_NET=y +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +CONFIG_SSL=y +CONFIG_HOSTFS=m + +# +# Block devices +# +CONFIG_BLK_DEV_UBD=y +# CONFIG_BLK_DEV_UBD_SYNC is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +CONFIG_NET_UM_ETH=y +CONFIG_NET_UMN=y + +# +# File systems +# +CONFIG_QUOTA=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_UMSDOS_FS=m +CONFIG_VFAT_FS=m +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set +CONFIG_ISO9660_FS=m +# CONFIG_JOLIET is not set +CONFIG_MINIX_FS=m +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_SUNRPC is not set +# CONFIG_LOCKD is not set +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# 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_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 +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_UTF8 is not set + +# +# Kernel hacking +# +CONFIG_DEBUGSYM=y +CONFIG_PT_PROXY=y +# CONFIG_GPROF is not set +# CONFIG_GCOV is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/drivers/Makefile linux.ac/arch/um/drivers/Makefile --- linux.vanilla/arch/um/drivers/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/drivers/Makefile Mon Apr 9 23:25:02 2001 @@ -0,0 +1,39 @@ +# +# Copyright (C) 2000 Jeff Dike (jdike@karaya.com) +# Licensed under the GPL +# + +O_TARGET := um_drivers.o + +obj-y = +obj-m = + +EXTRA_CFLAGS = -I../include + +USER_CFLAGS = $(patsubst -I%,,$(CFLAGS)) +USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) +USER_CFLAGS += $(EXTRA_CFLAGS) + +CFLAGS_stdio_console.o := $(CFLAGS) +CFLAGS_stdio_console_user.o := $(USER_CFLAGS) +CFLAGS_ssl.o := $(CFLAGS) +CFLAGS_chan_kern.o := $(CFLAGS) +CFLAGS_chan_user.o := $(USER_CFLAGS) +CFLAGS_ubd.o := $(CFLAGS) +CFLAGS_ubd_user.o := $(USER_CFLAGS) +CFLAGS_umn_kern.o := $(CFLAGS) +CFLAGS_umn_user.o := $(USER_CFLAGS) +CFLAGS_eth_kern.o := $(CFLAGS) +CFLAGS_eth_user.o := $(USER_CFLAGS) + +obj-$(CONFIG_STDIO_CONSOLE) += stdio_console.o stdio_console_user.o +obj-$(CONFIG_SSL) += ssl.o +obj-$(CONFIG_SSL) += chan_user.o chan_kern.o +obj-$(CONFIG_STDIO_CONSOLE) += chan_user.o chan_kern.o +obj-$(CONFIG_BLK_DEV_UBD) += ubd.o ubd_user.o +obj-$(CONFIG_NET_UMN) += umn_user.o umn_kern.o +obj-$(CONFIG_NET_UM_ETH) += eth_kern.o eth_user.o + +override CFLAGS = + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/drivers/chan_kern.c linux.ac/arch/um/drivers/chan_kern.c --- linux.vanilla/arch/um/drivers/chan_kern.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/drivers/chan_kern.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <linux/stddef.h> +#include <linux/tty.h> +#include <asm/irq.h> +#include "chan.h" +#include "user_util.h" +#include "kern.h" + +void tty_interrupt(struct io_chan *chan, void *tty_ptr, int count) +{ + struct tty_struct *tty = tty_ptr; + int n; + + if(count == 0) return; + n = tty_read(&chan->in, tty); + tty_flip_buffer_push(tty); + if(n > 0) chan->in.hung_up = 0; + if(n >= 0) reactivate_fd(chan->in.fd); +} + +void tty_eof(void *tty_ptr, int *hung_up) +{ + struct tty_struct *tty = tty_ptr; + + if(tty == NULL) return; + if(!*hung_up) tty_hangup(tty); + *hung_up = 1; +} + +void tty_receive_char(void *tty_ptr, char ch) +{ + struct tty_struct *tty = tty_ptr; + + if(tty == NULL) return; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + return; + if((tty->flip.flag_buf_ptr == NULL) || + (tty->flip.char_buf_ptr == NULL)) + return; + tty->flip.count++; + *tty->flip.flag_buf_ptr++ = TTY_NORMAL; + *tty->flip.char_buf_ptr++ = ch; +} + +static void accept_interrupt(int irq, void *dev, struct pt_regs *unused) +{ + accept_connection(dev); +} + +static int setup_accept_irq(int fd, void *data) +{ + return(um_request_irq(ACCEPT_IRQ, fd, accept_interrupt, + SA_INTERRUPT | SA_SHIRQ, "socket", data)); +} + +static int open_chan(struct chan *chan, int (*irq_setup)(int fd, void *data), + int input, void *data) +{ + struct io_chan subchan; + int err; + + if(chan->opened) return(0); + switch(chan->type){ + case XTERM: + err = open_xterm(chan); + break; + case PTY: + err = open_pty(chan); + break; + case TTY: + err = open_tty(chan); + break; + case PTS: + err = open_pts(chan); + break; + case FD: + err = open_fd(chan); + break; + case SOCKET: + subchan = ((struct io_chan) + PTS_IO_CHAN_INIT(NULL, -1, 1, INIT_STATIC)); + err = open_chan_pair(&subchan, irq_setup, data); + if(err) return(err); + chan->data.sock.pty = subchan.in.fd; + err = open_socket(chan); + irq_setup = setup_accept_irq; + data = chan; + break; + default: + printk("open_chan : Unknown channel type - %d\n", chan->type); + err = -ENODEV; + break; + } + if(err) return(err); + if(input && irq_setup) err = (*irq_setup)(chan->fd, data); + if(err) return(err); + chan->opened = 1; + return(0); +} + +int open_chan_pair(struct io_chan *chan, int (*irq_setup)(int fd, void *data), + void *data) +{ + int err; + + err = open_chan(&chan->in, irq_setup, 1, data); + if(err) return(err); + if(chan->out.type != COPY) + err = open_chan(&chan->out, irq_setup, 0, data); + return(err); +} + +static void close_chan(struct chan *chan) +{ + switch(chan->type){ + case XTERM: + if(chan->data.xterm.pid != -1) + kill(chan->data.xterm.pid, SIGKILL); + break; + default: + break; + } +} + +void close_chan_pair(struct io_chan *chan) +{ + close_chan(&chan->in); + if(chan->out.type != COPY) + close_chan(&chan->out); +} + +int write_chan(struct io_chan *chan, const char *buf, int len) +{ + struct chan *c; + int n; + + if(chan->out.type == COPY) c = &chan->in; + else c = &chan->out; + if(c->fd == -1) return(-ENODEV); + n = write(c->fd, buf, len); + if(errno == EAGAIN) n = 0; + if(n < 0) return(-errno); + return(n); +} + +static int parse_chan(char *str, int device, struct chan *chan, int pri, + struct chan_opts *opts) +{ + if(pri <= chan->init_pri) return(0); + if(!strncmp(str, "pty", strlen("pty"))){ + *chan = ((struct chan) PTY_CHAN_INIT(opts->announce, + opts->dev, opts->raw_pty, + pri)); + } + else if(!strncmp(str, "tty", strlen("tty"))){ + char *tty_name; + + tty_name = &str[strlen("tty")]; + if(*tty_name != ':'){ + printk("parse_chan : channel type 'tty' must " + "specify a device\n"); + return(-1); + } + tty_name++; + *chan = ((struct chan) TTY_CHAN_INIT(tty_name, opts->raw_pty, + pri)); + } + else if(!strncmp(str, "pts", strlen("pts"))){ + *chan = ((struct chan) PTS_CHAN_INIT(opts->announce, + opts->dev, opts->raw_pty, + pri)); + } + else if(!strncmp(str, "xterm", strlen("xterm"))){ + *chan = ((struct chan) + XTERM_CHAN_INIT(device, opts->xterm_title, + opts->raw_pty, pri)); + } + else if(!strncmp(str, "socket", strlen("socket"))){ + char *sock; + int n; + + sock = &str[strlen("socket")]; + if(*sock != ':'){ + printk("parse_chan : channel type 'socket' must " + "specify a socket\n"); + return(-1); + } + sock++; + n = simple_strtoul(sock, NULL, 0); + if(n == 0){ + printk("parse_chan : invalid socket number - '%s'\n", + sock); + return(-1); + } + *chan = ((struct chan) SOCK_CHAN_INIT(n, pri)); + } + else if(!strncmp(str, "fd", strlen("fd"))){ + char *fd, *end; + int n; + + fd = &str[strlen("fd")]; + if(*fd != ':'){ + printk("parse_chan : channel type 'fd' must " + "specify a file descriptor\n"); + return(-1); + } + fd++; + n = simple_strtoul(fd, &end, 0); + if(*end != '\0'){ + printk("parse_chan : couldn't parse file descriptor " + "'%s'", fd); + return(-1); + } + *chan = ((struct chan) FD_CHAN_INIT(n, pri)); + return(0); + } + else { + printk("parse_chan couldn't parse \"%s\"\n", str); + return(-1); + } + chan->init_pri = pri; + return(0); +} + +int parse_chan_pair(char *str, int device, struct io_chan *chan, int pri, + struct chan_opts *opts) +{ + char *in, *out; + int err; + + if((out = strchr(str, ',')) != NULL){ + in = str; + *out = '\0'; + out++; + err = parse_chan(in, device, &chan->in, pri, opts); + if(err) return(err); + err = parse_chan(out, device, &chan->out, pri, opts); + return(err); + } + else { + err = parse_chan(str, device, &chan->in, pri, opts); + if(err) return(err); + chan->out.type = COPY; + return(0); + } +} + + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/drivers/chan_user.c linux.ac/arch/um/drivers/chan_user.c --- linux.vanilla/arch/um/drivers/chan_user.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/drivers/chan_user.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <termios.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include "ssl.h" +#include "chan.h" +#include "user.h" +#include "user_util.h" +#include "kern_util.h" + +int tty_read(struct chan *chan, void *tty) +{ + int n, count = 0; + char ch; + + while((n = read(chan->fd, &ch, sizeof(ch))) == sizeof(ch)){ + tty_receive_char(tty, ch); + count++; + } + if(n < 0){ + if(errno == EIO){ + tty_eof(tty, &chan->hung_up); + return(0); + } + else if(errno != EAGAIN){ + printk("tty_read read failed, errno = %d\n", errno); + return(-1); + } + } + return(1); +} + +int open_fd(struct chan *chan) +{ + raw(chan->fd, 0); + return(0); +} + +struct xterm_info { + char tty[2]; + int fd; + int console_num; + int *pid_out; + char *title; +}; + +static void xterm_tramp(void *arg) +{ + struct xterm_info *info; + int pid; + char title[256], flag[sizeof("Sxxnn\0")]; + + info = arg; + sprintf(flag, "-S%c%c%d", info->tty[0], info->tty[1], info->fd); + sprintf(title, info->title, info->console_num); + if((pid = fork()) != 0) *info->pid_out = pid; + else { + execlp("xterm", "xterm", flag, "-T", title, NULL); + printk("execlp of xterm failed - errno = %d\n", errno); + exit(1); + } +} + +static int getmaster(char *line, int raw) +{ + struct termios tt; + struct stat stb; + char *pty, *bank, *cp; + int master; + + pty = &line[strlen("/dev/ptyp")]; + for (bank = "pqrs"; *bank; bank++) { + line[strlen("/dev/pty")] = *bank; + *pty = '0'; + if (stat(line, &stb) < 0) + break; + for (cp = "0123456789abcdef"; *cp; cp++) { + *pty = *cp; + master = open(line, O_RDWR); + if (master >= 0) { + char *tp = &line[strlen("/dev/")]; + int ok; + + /* verify slave side is usable */ + *tp = 't'; + ok = access(line, R_OK|W_OK) == 0; + *tp = 'p'; + if (ok) { + if(raw){ + tcgetattr(master, &tt); + cfmakeraw(&tt); + tcsetattr(master, TCSADRAIN, + &tt); + } + return(master); + } + (void) close(master); + } + } + } + return(-1); +} + +int open_xterm(struct chan *chan) +{ + struct xterm_info info; + int master, slave; + char dev[] = "/dev/ptyXX", c; + + master = getmaster(dev, chan->data.xterm.raw); + if(master == -1) return(-ENODEV); + dev[strlen("/dev/")] = 't'; + slave = open(dev, O_RDWR); + if(slave == -1) return(-errno); + info.tty[0] = dev[strlen("/dev/pty")]; + info.tty[1] = dev[strlen("/dev/ptyX")]; + info.fd = master; + info.console_num = chan->data.xterm.line; + info.pid_out = &chan->data.xterm.pid; + info.title = chan->data.xterm.title; + tracing_cb(xterm_tramp, &info); + while((read(slave, &c, sizeof(c)) == sizeof(c)) && (c != '\n')) ; + if(chan->data.xterm.raw) raw(slave, 1); + chan->fd = slave; + return(0); +} + +int open_pty(struct chan *chan) +{ + char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx"; + + chan->fd = getmaster(dev, chan->data.pty.raw); + if(chan->fd < 0) return(-errno); + if(chan->data.pty.announce) + (*chan->data.pty.announce)(dev, chan->data.pty.dev); + return(0); +} + +int open_tty(struct chan *chan) +{ + int fd; + + fd = open(chan->data.tty.dev, O_RDWR); + if(fd < 0) return(-errno); + chan->fd = fd; + if(chan->data.tty.raw) raw(fd, 1); + return(0); +} + +int open_pts(struct chan *chan) +{ + int fd; + + if((fd = get_pty()) < 0){ + printk("open_pts : Failed to open pts\n"); + return(-errno); + } + chan->fd = fd; + if(chan->data.tty.raw) raw(fd, 1); + if(chan->data.pts.announce) + (*chan->data.pts.announce)(ptsname(fd), chan->data.pts.dev); + return(0); +} + +int open_socket(struct chan *chan) +{ + struct sockaddr_in addr; + int sock; + + sock = socket(PF_INET, SOCK_STREAM, 0); + if(sock < 0) return(-errno); + addr.sin_family = AF_INET; + addr.sin_port = htons(chan->data.sock.port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + if(bind(sock, &addr, sizeof(addr)) < 0) return(-errno); + if(listen(sock, 1) < 0) return(-errno); + chan->data.sock.connected = 0; + chan->fd = sock; + return(0); +} + +struct telnetd_args { + int fd; + char helper[sizeof("/tmp/uml_dev/nnnn\0")]; +}; + +static void telnetd_tramp(void *arg) +{ + struct telnetd_args info = *((struct telnetd_args *) arg); + + if(fork() == 0){ + dup2(info.fd, 0); + dup2(info.fd, 1); + dup2(info.fd, 2); + close(info.fd); + execlp("in.telnetd", "in.telnetd", "-L", info.helper, NULL); + printk("execlp of telnetd failed - errno = %d\n", errno); + exit(1); + } +} + +void accept_connection(struct chan *chan) +{ + struct telnetd_args info; + char *name; + + if((info.fd = accept(chan->fd, NULL, 0)) < 0){ + printk("tty_read: accept failed - errno = %d\n", + errno); + return; + } + mkdir("/tmp/uml_dev", 0777); + name = ptsname(chan->data.sock.pty); + name = rindex(name, '/'); + sprintf(info.helper, "/tmp/uml_dev%s", name); + if(symlink("/home/jdike/bin/telnet_helper", info.helper)){ + printk("symlink from '%s' failed, errno = %d\n", info.helper, + errno); + return; + } + tracing_cb(telnetd_tramp, &info); + chan->data.sock.connected = 1; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/drivers/eth_kern.c linux.ac/arch/um/drivers/eth_kern.c --- linux.vanilla/arch/um/drivers/eth_kern.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/drivers/eth_kern.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,384 @@ +#include <linux/config.h> +#include <linux/module.h> + +#include <linux/kernel.h> +#include <linux/malloc.h> +#include <linux/init.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/in.h> + +#include "user_util.h" +#include "eth_net.h" +#include "radix.h" + +extern int uml_net_user_mac(void); +extern int uml_net_user_close(int); +extern int uml_net_user_open(struct sockaddr *, void *, int, int); +extern int uml_net_user_join(int, int); +extern int uml_net_user_tx(int, char *, int); +extern int uml_net_user_rx(int, char *, int); + +#define MAC_NODE_NIBBLE 6 +#define MAC_TREE_DEPTH 48 + +struct mac_node { + RADIX_ENTRY(mac_node,MAC_NODE_NIBBLE) next; + int action; +}; + +RADIX_HEAD(mac_tree,mac_node); + +struct uml_net_private { + spinlock_t lock; + int socket; + int net_num; + struct net_device_stats stats; + struct net_device *next; + struct sockaddr addr; +}; + +static struct mac_tree mac_tree; +static struct net_device *uml_net_dev = NULL; + +void uml_net_interrupt(int, void *, struct pt_regs *); + +static int uml_net_rx(struct net_device *); +static int uml_net_open(struct net_device *); +static int uml_net_close(struct net_device *); +static int uml_net_set_mac(struct net_device *, void *); +static void uml_net_tx_timeout(struct net_device *dev); +static void uml_net_set_multicast_list(struct net_device *); +static int uml_net_ioctl(struct net_device *, struct ifreq *, int); +static int uml_net_start_xmit(struct sk_buff *, struct net_device *); +static struct net_device_stats *uml_net_get_stats(struct net_device *); +static int uml_net_insert_mac_tree(long long key,int value); + +int __init uml_net_probe(void) +{ + struct net_device *dev = NULL; + struct uml_net_private *lp; + struct sockaddr_in *sin; + long long key; + char *priv; + int i; + + RADIX_INIT(&mac_tree); + if(uml_net_insert_mac_tree(0xffffffffffff,0)) return -1; + + for (i = 0; i < 4; i++) { + + dev = init_etherdev(NULL, 0); + + if (dev == NULL) + return -ENOMEM; + + printk("User-mode Linux network interface 0.011 (%s)\n", + dev->name); + + if ((priv = kmalloc(sizeof(struct uml_net_private) + 15, + GFP_KERNEL)) == NULL) { + return -ENOMEM; + } + + lp = (struct uml_net_private *)(((unsigned long)priv + 15) + & ~15); + + memset(lp, 0, sizeof(struct uml_net_private)); + sin = (struct sockaddr_in *)&lp->addr; + + sin->sin_family = AF_INET; + sin->sin_port = htons(UML_NET_PORT); + sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + lp->net_num = 100; + + /* Fill in the generic fields of the device structure. */ + ether_setup(dev); + + dev->priv = lp; + dev->open = uml_net_open; + dev->hard_start_xmit = uml_net_start_xmit; + dev->stop = uml_net_close; + dev->get_stats = uml_net_get_stats; + dev->set_multicast_list = uml_net_set_multicast_list; + dev->tx_timeout = uml_net_tx_timeout; + dev->set_mac_address = 0; // uml_net_set_mac; + dev->do_ioctl = uml_net_ioctl; + dev->watchdog_timeo = (HZ >> 1); + lp->next = uml_net_dev; + uml_net_dev = dev; + + spin_lock_init(&lp->lock); + + key = uml_net_user_mac(); + key <<= 16; + memcpy(dev->dev_addr, &key, ETH_ALEN); + uml_net_insert_mac_tree(key,dev->ifindex); + } + return 0; +} + +static int uml_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct uml_net_private *lp = (struct uml_net_private *)dev->priv; + + spin_lock(&lp->lock); + + if(dev->flags & IFF_UP) { + spin_unlock(&lp->lock); + return -EBUSY; + } + + switch (cmd) { + case SIOCDEVPRIVATE: + { + /* setting net number */ + lp->net_num = ifr->ifr_flags; + break; + } + case SIOCDEVPRIVATE+1: + { + + /* setting dst addr */ + if(ifr->ifr_dstaddr.sa_family) { + memcpy(&lp->addr, &ifr->ifr_dstaddr, + sizeof(struct sockaddr)); + } + break; + } + } + + spin_unlock(&lp->lock); + return 0; +} + +static int uml_net_open(struct net_device *dev) +{ + struct uml_net_private *lp = (struct uml_net_private *)dev->priv; + int err = 0; + + spin_lock(&lp->lock); + if(lp->socket) { + spin_unlock(&lp->lock); + return(-ENXIO); + } + lp->socket = uml_net_user_open(&lp->addr, (void *)dev, dev->irq, + lp->net_num); + + if (lp->socket < 0) { + printk("uml_net_open: failed(%d)\n", lp->socket); + lp->socket = 0; + spin_unlock(&lp->lock); + return -ENETUNREACH; + } + + dev->irq = UM_ETH_IRQ; + if((err = um_request_irq(dev->irq, lp->socket, uml_net_interrupt, + SA_INTERRUPT | SA_SHIRQ, dev->name, dev)) != 0) { + spin_unlock(&lp->lock); + uml_net_user_close(lp->socket); + printk("uml_net_open: failed to get irq(%d)\n", err); + return -ENETUNREACH; + } + + spin_unlock(&lp->lock); + + netif_start_queue(dev); + + return 0; +} + +static void uml_net_tx_timeout(struct net_device *dev) +{ + printk("uml_net_tx_timeout enter\n"); + + dev->trans_start = jiffies; + netif_wake_queue(dev); + + printk("uml_net_tx_timeout exit\n"); +} + +static int uml_net_get_mac_node(long long key) +{ + int res = 0; + int value = -1; + RADIX_GET(&mac_tree,mac_node,next,MAC_NODE_NIBBLE,long long, + key,48,action,value,res); + if(res) { + return -1; + } + return value; +} + +static int uml_net_insert_mac_tree(long long key,int value) +{ + int res = 0; + + RADIX_INSERT(&mac_tree,mac_node,next,MAC_NODE_NIBBLE,long long, + key,48,res); + + if(res) { + return -1; + } + RADIX_SET(&mac_tree,mac_node,next,MAC_NODE_NIBBLE,long long, + key,48,action,value,res); + if(res) { + return -1; + } + return 0; +} + +static int uml_net_set_mac(struct net_device *dev, void *addr) +{ + struct uml_net_private *lp = (struct uml_net_private *)dev->priv; + struct sockaddr *hwaddr = (struct sockaddr *)addr; + long long key = 0; + + memcpy(&key,hwaddr->sa_data,ETH_ALEN); + uml_net_insert_mac_tree(key,dev->ifindex); + + spin_lock(&lp->lock); + memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN); + spin_unlock(&lp->lock); + + return 0; +} + +static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct uml_net_private *lp = (struct uml_net_private *)dev->priv; + unsigned long flags; + int size; + + netif_stop_queue(dev); + + spin_lock_irqsave(&lp->lock, flags); + + size = uml_net_user_tx(lp->socket, skb->data, skb->len); + if (size == skb->len) { + lp->stats.tx_packets++; + lp->stats.tx_bytes += skb->len; + dev->trans_start = jiffies; + netif_start_queue(dev); + /* this is normally done in the interrupt when tx finishes */ + netif_wake_queue(dev); + } else { + printk("uml_net_start_xmit: failed(%d)\n", size); + } + + spin_unlock_irqrestore(&lp->lock, flags); + + dev_kfree_skb(skb); + + return 0; +} + +void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct uml_net_private *lp = (struct uml_net_private *)dev->priv; + int count = 0; + int retval = 0; + + spin_lock(&lp->lock); + + while ((retval = uml_net_rx(dev)) > 0) { + count++; + if(count > 100) { + break; + } + } + + spin_unlock(&lp->lock); + + if (retval < 0) { + uml_net_close(dev); + } +} + +static int uml_net_rx(struct net_device *dev) +{ + struct uml_net_private *lp = (struct uml_net_private *)dev->priv; + unsigned char buffer[MAX_PACKET]; + struct sk_buff *skb; + int pkt_len = 0; + unsigned int value; + long long key = 0; + + if ((pkt_len = uml_net_user_rx(lp->socket, buffer, MAX_PACKET)) > 0) { + /* + * look at the dev flags and the dest MAC to determin if this + * frame is for us + */ + + if (dev->flags & IFF_PROMISC) { + goto uml_net_rx_accept; + } + + memcpy(&key,buffer,ETH_ALEN); + if ((key & 0x010000000000) && (dev->flags & IFF_ALLMULTI)) { + goto uml_net_rx_accept; + } + + value = uml_net_get_mac_node(key); + if (value == dev->ifindex || value == 0) { + goto uml_net_rx_accept; + } + + goto uml_net_rx_drop; /* No match */ + +uml_net_rx_accept: + if ((skb = dev_alloc_skb(MAX_PACKET)) != NULL) { + skb->dev = dev; + skb_reserve(skb, 2); + skb_put(skb, pkt_len); + eth_copy_and_sum(skb, buffer, pkt_len, 0); + + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + + lp->stats.rx_bytes += skb->len; + lp->stats.rx_packets++; + } + return 1; + } else if(pkt_len < 0) { + return -1; + } + return 0; + +uml_net_rx_drop: + lp->stats.rx_dropped++; + return 1; +} + +static int uml_net_close(struct net_device *dev) +{ + struct uml_net_private *lp = (struct uml_net_private *)dev->priv; + + netif_stop_queue(dev); + + spin_lock(&lp->lock); + + uml_net_user_close(lp->socket); + lp->socket = 0; + free_irq(dev->irq, dev); + + spin_unlock(&lp->lock); + return 0; +} + +static struct net_device_stats *uml_net_get_stats(struct net_device *dev) +{ + struct uml_net_private *lp = (struct uml_net_private *)dev->priv; + return &lp->stats; +} + +static void uml_net_set_multicast_list(struct net_device *dev) +{ + if (dev->flags & IFF_PROMISC) { + printk("%s: Promiscuous mode enabled.\n", dev->name); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/drivers/eth_net.h linux.ac/arch/um/drivers/eth_net.h --- linux.vanilla/arch/um/drivers/eth_net.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/drivers/eth_net.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,13 @@ +#ifndef INCLUDE_NET_ETH_NET_H +#define INCLUDE_NET_ETH_NET_H + +#define MAX_PACKET 1544 +#define UML_NET_PORT 5299 +#define DEFAULT_NET_NUM 100 +#define UML_HDR_SIZE (sizeof(unsigned int)*2) + +enum packet_type { + PACKET_DATA = 1, + PACKET_MGMT +}; +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/drivers/eth_user.c linux.ac/arch/um/drivers/eth_user.c --- linux.vanilla/arch/um/drivers/eth_user.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/drivers/eth_user.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,166 @@ +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> +#include <stdlib.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/time.h> +#include <time.h> +#include <sched.h> +#include <signal.h> +#include <errno.h> + +#include "user.h" +#include "user_util.h" +#include "eth_net.h" + +int uml_net_user_mac(void) +{ + static int first = 1; + + if(first) { + srand(time(NULL)); + first = 0; + } + return rand(); +} + +static int nb_write(int fd, void *buf, int tot) { + int len = 0; + int remain = tot; + int retval; + +write_try_again: + retval = write(fd, buf+len, remain); + if (retval < 0) { + if (errno == EAGAIN || errno == EINTR) { + goto write_try_again; + } + return -1; + } + if (retval < remain) { + remain -= retval; + len += retval; + goto write_try_again; + } + return 0; +} + +static int nb_read(int fd, void *buf, int tot, int flag) { + int len = 0; + int remain = tot; + int retval; + +read_try_again: + retval = read(fd, buf+len, remain); + if (retval < 0) { + if (errno == EINTR) { + goto read_try_again; + } + if (flag && (errno == EAGAIN)) { + goto read_try_again; + } else { + return 0; + } + return -1; + } + if(retval < remain) { + if(!retval) { + return -1; + } + len += retval; + remain -= retval; + flag = 1; + goto read_try_again; + } + return tot; +} + +int uml_net_user_join(int fd, int net_num) +{ + unsigned int header[3]; + + if (fd < 0) + return -ENOTCONN; + + header[0] = htonl(PACKET_MGMT); + header[1] = htonl(sizeof(unsigned int)); + header[2] = htonl(net_num); + + return nb_write(fd, header, UML_HDR_SIZE + sizeof(unsigned int)); +} + +int uml_net_user_open(struct sockaddr *addr, void *dev, int irq,int net_num) +{ + int new_fd; + + if ((new_fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) + return -ENOMEM; + + if (connect(new_fd,(struct sockaddr*)addr, + sizeof(struct sockaddr)) < 0) { + close(new_fd); + return -ENOTCONN; + } + + if(uml_net_user_join(new_fd,net_num) < 0) { + close(new_fd); + return -ENOTCONN; + } + + return new_fd; +} + +int uml_net_user_tx(int fd, char *buffer, int len) +{ + unsigned char hbuf[MAX_PACKET + UML_HDR_SIZE]; + unsigned char *buf = hbuf + UML_HDR_SIZE; + unsigned int *header = (unsigned int*)hbuf; + int retval = 0; + + if (fd < 0) + return -ENOTCONN; + + if(len > MAX_PACKET) panic("Too big packet"); + + memcpy(buf,buffer,len); + + header[0] = htonl(PACKET_DATA); + header[1] = htonl(len); + + retval = nb_write(fd, hbuf, UML_HDR_SIZE + len); + if (retval) { + return -1; + } + return len; +} + +int uml_net_user_rx(int fd, char *buf, int len) +{ + int retval = 0; + int header[2]; + + if (fd < 0) + return -1; + + retval = nb_read(fd, header, UML_HDR_SIZE,0); + if (retval < 0) { + return -1; + } + if(retval) { + retval = nb_read(fd, buf, ntohl(header[1]),1); + if (retval < 0) { + return -1; + } + } + + reactivate_fd(fd); + return retval; +} + +int __inline__ uml_net_user_close(int fd) +{ + shutdown(fd,SHUT_RDWR); + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/drivers/radix.h linux.ac/arch/um/drivers/radix.h --- linux.vanilla/arch/um/drivers/radix.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/drivers/radix.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,143 @@ +#ifndef _RADIX_H_ +#define _RADIX_H_ + +#include <asm/atomic.h> + +#define RADIX_INIT(head) \ +{ \ + (head)->RdX_root = NULL; \ +} + +#define RADIX_ENTRY(type,bits) \ +struct { \ + struct type *RdX_next[(0x01 << bits)]; \ +} + +#define RADIX_HEAD(name,type) \ +struct name { \ + struct type *RdX_root; \ +}; + +#define RADIX_INSERT(head,type,field,bits,tdef,key,klen,result) \ +{ \ + struct type **RdX_node = &((head)->RdX_root); \ + tdef RdX_mask; \ + int RdX_index; \ + int RdX_size = sizeof(tdef)*8; \ + char RdX_status = 0; \ + int RdX_count = 0; \ + \ + if(klen % bits) result = -1; \ + else { \ + RdX_mask = (0x01 << bits)-1; \ + while((RdX_count*bits) < klen) { \ + RdX_status = 1; \ + if(!(*RdX_node)) { \ + RdX_status = 2; \ + (*RdX_node) = (struct type *)kmalloc(sizeof(struct type), \ + GFP_KERNEL); \ + if(!(*RdX_node)) { \ + result = -2; \ + break; \ + } \ + RdX_status = 3; \ + memset((*RdX_node),0,sizeof(struct type)); \ + RdX_status = 4; \ + } \ + RdX_index = (key >> (RdX_size - bits - (RdX_count * bits))) & RdX_mask; \ + RdX_status = 5; \ + RdX_node = &((*RdX_node)->field.RdX_next[RdX_index]); \ + RdX_status = 6; \ + RdX_count++; \ + result = 0; \ + } \ + if(result != -2 && (!(*RdX_node))) { \ + (*RdX_node) = (struct type *)kmalloc(sizeof(struct type), \ + GFP_KERNEL); \ + if(!(*RdX_node)) { \ + result = -2; \ + } else { \ + memset((*RdX_node),0,sizeof(struct type)); \ + } \ + } \ + } \ +} + +#define RADIX_DO(head,type,field,bits,tdef,key,klen,flm,elem,result,RxD_set) \ +{ \ + struct type *RdX_node = (head)->RdX_root; \ + tdef RdX_mask; \ + int RdX_index; \ + int RdX_size = sizeof(tdef)*8; \ + int RdX_count = 0; \ + \ + if(klen % bits) result = -1; \ + else { \ + RdX_mask = (0x01 << bits)-1; \ + while((RdX_count*bits) < klen) { \ + if(!RdX_node) { \ + result = -2; \ + break; \ + } else { \ + RdX_index = (key >> (RdX_size - bits - (RdX_count * bits))) & RdX_mask;\ + RdX_node = RdX_node->field.RdX_next[RdX_index]; \ + } \ + RdX_count++; \ + } \ + if(!RdX_node) { \ + result = -3; \ + } else { \ + if(RxD_set) { \ + RdX_node->flm = elem; \ + } else { \ + elem = RdX_node->flm; \ + } \ + result = 0; \ + } \ + } \ +} + +#define RADIX_SET(head,type,field,bits,tdef,key,klen,flm,elem,result) \ + RADIX_DO(head,type,field,bits,tdef,key,klen,flm,elem,result,1) +#define RADIX_GET(head,type,field,bits,tdef,key,klen,flm,elem,result) \ + RADIX_DO(head,type,field,bits,tdef,key,klen,flm,elem,result,0) + +#define RADIX_VISIT_ALL(head,type,field,bits,visit,extra) \ +{ \ + int RdX_node_count = (0x1 << bits); \ + struct type *RdX_stack[RdX_node_count]; \ + int RdX_stack_count[RdX_node_count]; \ + int RdX_stack_depth = 0; \ + struct type *RdX_node; \ + int RdX_done = 0; \ + int R = 0; \ + \ + if((RdX_node = (head)->RdX_root)) { \ + while(!RdX_done) { \ + if(RdX_node->field.RdX_next[R]) { \ + RdX_stack[RdX_stack_depth] = RdX_node; \ + RdX_stack_count[RdX_stack_depth] = R + 1; \ + RdX_stack_depth++; \ + RdX_node = RdX_node->field.RdX_next[R]; \ + R = 0; \ + } else { \ + R++; \ + if(R >= RdX_node_count) { \ + if(visit(RdX_node,extra)) { \ + RdX_done = 1; \ + break; \ + } \ + RdX_stack_depth--; \ + if(RdX_stack_depth >= 0) { \ + RdX_node = RdX_stack[RdX_stack_depth]; \ + R = RdX_stack_count[RdX_stack_depth]; \ + } else { \ + RdX_done = 1; \ + } \ + } \ + } \ + } \ + } \ +} + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/drivers/ssl.c linux.ac/arch/um/drivers/ssl.c --- linux.vanilla/arch/um/drivers/ssl.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/drivers/ssl.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/fs.h" +#include "linux/tty.h" +#include "linux/tty_driver.h" +#include "linux/major.h" +#include "linux/mm.h" +#include "linux/init.h" +#include "asm/termbits.h" +#include "asm/irq.h" +#include "ssl.h" +#include "chan.h" +#include "user_util.h" +#include "kern_util.h" +#include "kern.h" + +static int ssl_version = 1; + +static struct tty_driver ssl_driver; + +static int ssl_refcount = 0; + +#define NR_PORTS 64 + +static struct tty_struct *ssl_table[NR_PORTS]; +static struct termios *ssl_termios[NR_PORTS]; +static struct termios *ssl_termios_locked[NR_PORTS]; + +static struct ssl { + struct io_chan chan; + int count; + struct tty_struct *tty; +} private[NR_PORTS] = { [0 ... NR_PORTS - 1] = + { PTY_IO_CHAN_INIT(NULL, 0, 1, INIT_STATIC), + 0, NULL } }; + +static void ssl_interrupt(int irq, void *dev, struct pt_regs *unused) +{ + struct ssl *line = dev; + + tty_interrupt(&line->chan, line->tty, line->count); +} + +static int setup_ssl_irq(int fd, void *data) +{ + return(um_request_irq(SSL_IRQ, fd, ssl_interrupt, + SA_INTERRUPT | SA_SHIRQ, "ssl", data)); +} + +void ssl_announce(char *dev_name, int dev) +{ + printk("Serial line %d assigned device '%s'\n", dev, dev_name); +} + +DECLARE_MUTEX(ssl_sem); + +int ssl_open(struct tty_struct *tty, struct file *filp) +{ + int line, err; + + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= NR_PORTS)) + return -ENODEV; + down(&ssl_sem); + if(tty == NULL) panic("NULL tty in ssl_open"); + private[line].tty = tty; + tty->driver_data = &private[line]; + err = open_chan_pair(&private[line].chan, setup_ssl_irq, + &private[line]); + up(&ssl_sem); + if(err){ + printk("Couldn't open serial line %d - errno = %d\n", line, + -err); + up(&ssl_sem); + return(err); + } + private[line].count++; + up(&ssl_sem); + return(0); +} + +static void ssl_close(struct tty_struct *tty, struct file * filp) +{ + int line; + + line = MINOR(tty->device) - tty->driver.minor_start; + private[line].count--; + if(private[line].count == 0) private[line].tty = NULL; +} + +static int ssl_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int line; + + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= NR_PORTS)) + panic("Bad tty in ssl_put_char"); + return(write_chan(&private[line].chan, buf, count)); +} + +static void ssl_put_char(struct tty_struct *tty, unsigned char ch) +{ + int line; + + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= NR_PORTS)) + panic("Bad tty in ssl_put_char"); + write_chan(&private[line].chan, &ch, sizeof(ch)); +} + +static void ssl_flush_chars(struct tty_struct *tty) +{ + return; +} + +static int ssl_write_room(struct tty_struct *tty) +{ + return(16384); +} + +static int ssl_chars_in_buffer(struct tty_struct *tty) +{ + return(0); +} + +static void ssl_flush_buffer(struct tty_struct *tty) +{ + return; +} + +static int ssl_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int ret; + + ret = 0; + switch(cmd){ + case TCGETS: + case TCSETS: + case TCFLSH: + case TCSETSF: + case TCSETSW: + case TCGETA: + ret = -ENOIOCTLCMD; + break; + default: + printk("Unimplemented ioctl in ssl_ioctl : 0x%x\n", cmd); + ret = -ENOIOCTLCMD; + break; + } + return(ret); +} + +static void ssl_throttle(struct tty_struct * tty) +{ + printk("Someone should implement ssl_throttle\n"); +} + +static void ssl_unthrottle(struct tty_struct * tty) +{ + printk("Someone should implement ssl_unthrottle\n"); +} + +static void ssl_set_termios(struct tty_struct *tty, + struct termios *old_termios) +{ +} + +static void ssl_stop(struct tty_struct *tty) +{ + printk("Someone should implement ssl_stop\n"); +} + +static void ssl_start(struct tty_struct *tty) +{ + printk("Someone should implement ssl_start\n"); +} + +void ssl_hangup(struct tty_struct *tty) +{ +} + +extern void tty_register_devfs (struct tty_driver *driver, unsigned int flags, + unsigned int minor); +extern void tty_unregister_devfs (struct tty_driver *driver, unsigned minor); + +int ssl_init(void) +{ + int i; + + for(i=0;i<sizeof(private)/sizeof(private[0]);i++){ + if(private[i].chan.in.init_pri == INIT_STATIC) + private[i].chan = ((struct io_chan) + PTY_IO_CHAN_INIT(ssl_announce, + i, 1, + INIT_STATIC)); + } + + printk(KERN_INFO "Initializing software serial port version %d\n", + ssl_version); + + /* Initialize the tty_driver structure */ + + memset(&ssl_driver, 0, sizeof(struct tty_driver)); + ssl_driver.magic = TTY_DRIVER_MAGIC; + ssl_driver.name = "serial/%d"; + ssl_driver.major = TTYAUX_MAJOR; + ssl_driver.minor_start = 64; + ssl_driver.num = NR_PORTS; + ssl_driver.type = TTY_DRIVER_TYPE_SERIAL; + ssl_driver.subtype = 0; + ssl_driver.init_termios = tty_std_termios; + ssl_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + ssl_driver.flags = TTY_DRIVER_REAL_RAW; + ssl_driver.refcount = &ssl_refcount; + ssl_driver.table = ssl_table; + ssl_driver.termios = ssl_termios; + ssl_driver.termios_locked = ssl_termios_locked; + + ssl_driver.open = ssl_open; + ssl_driver.close = ssl_close; + ssl_driver.write = ssl_write; + ssl_driver.put_char = ssl_put_char; + ssl_driver.flush_chars = ssl_flush_chars; + ssl_driver.write_room = ssl_write_room; + ssl_driver.chars_in_buffer = ssl_chars_in_buffer; + ssl_driver.flush_buffer = ssl_flush_buffer; + ssl_driver.ioctl = ssl_ioctl; + ssl_driver.throttle = ssl_throttle; + ssl_driver.unthrottle = ssl_unthrottle; + ssl_driver.set_termios = ssl_set_termios; + ssl_driver.stop = ssl_stop; + ssl_driver.start = ssl_start; + ssl_driver.hangup = ssl_hangup; + if (tty_register_driver(&ssl_driver)) + panic("Couldn't register ssl driver\n"); + return(0); +} + +__initcall(ssl_init); + +static struct chan_opts opts = { + announce: ssl_announce, + dev: -1, + xterm_title: "Serial Line #%d", + raw_pty: 1 +}; + +static int ssl_chan_setup(char *str) +{ + int i, n; + char *end; + + if(*str == '=') n = -1; + else { + n = simple_strtoul(str, &end, 0); + if(*end != '='){ + printk("ssl_chan_setup failed to parse \"%s\"\n", + str); + return(1); + } + str = end; + } + str++; + if(n == -1){ + for(i=0;i<sizeof(private)/sizeof(private[0]);i++){ + opts.dev = i; + if(parse_chan_pair(str, i, &private[i].chan, INIT_ALL, + &opts)) + return(1); + } + } + else { + opts.dev = n; + parse_chan_pair(str, n, &private[n].chan, INIT_ONE, &opts); + } + return(1); +} + +__setup("ssl", ssl_chan_setup); + +static void ssl_exit(void) +{ + int i; + + for(i=0;i<sizeof(private)/sizeof(private[0]);i++){ + close_chan_pair(&private[i].chan); + } +} + +__exitcall(ssl_exit); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/drivers/ssl.h linux.ac/arch/um/drivers/ssl.h --- linux.vanilla/arch/um/drivers/ssl.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/drivers/ssl.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SSL_H__ +#define __SSL_H__ + +extern int ssl_read(int fd, int line); +extern void ssl_receive_char(int line, char ch); + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/drivers/stdio_console.c linux.ac/arch/um/drivers/stdio_console.c --- linux.vanilla/arch/um/drivers/stdio_console.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/drivers/stdio_console.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/posix_types.h" +#include "linux/tty.h" +#include "linux/types.h" +#include "linux/major.h" +#include "linux/kdev_t.h" +#include "linux/console.h" +#include "linux/string.h" +#include "linux/sched.h" +#include "linux/init.h" +#include "linux/interrupt.h" +#include "asm/current.h" +#include "asm/softirq.h" +#include "stdio_console.h" +#include "chan.h" +#include "user_util.h" +#include "kern_util.h" + +#define MAX_TTYS (8) + +static struct tty_driver console_driver; +static struct tty_struct *console_table[MAX_TTYS]; +static struct termios *console_termios[MAX_TTYS]; +static struct termios *console_termios_locked[MAX_TTYS]; +static int console_refcount; + +#define INIT_VT \ + { XTERM_IO_CHAN_INIT(-1, "Virtual Console #%d", 1, INIT_STATIC), 0, \ + NULL } + +static struct vt { + struct io_chan chan; + int count; + struct tty_struct *tty; +} vts[MAX_TTYS] = { { STDIO_IO_CHAN_INIT(INIT_STATIC), 0, NULL }, + [ 1 ... MAX_TTYS - 1 ] = INIT_VT }; + +static void console_interrupt(int irq, void *dev, struct pt_regs *unused) +{ + struct vt *term = dev; + + tty_interrupt(&term->chan, term->tty, term->count); +} + +DECLARE_MUTEX(stdio_sem); + +static int setup_console_irq(int fd, void *data) +{ + return(um_request_irq(CONSOLE_IRQ, fd, console_interrupt, + SA_INTERRUPT | SA_SHIRQ, "console", data)); +} + +static int open_console(int line, struct tty_struct *tty) +{ + int err; + + down(&stdio_sem); + err = open_chan_pair(&vts[line].chan, setup_console_irq, &vts[line]); + if(err < 0){ + printk("Failed to open virtual console %d, errno = %d\n", + line, err); + up(&stdio_sem); + return(err); + } + vts[line].count++; + vts[line].tty = tty; + up(&stdio_sem); + return(0); +} + +static int con_open(struct tty_struct * tty, struct file * filp) +{ + int line, ret; + + line = MINOR(tty->device) - tty->driver.minor_start; + ret = open_console(line, tty); + update_console_size(CHAN_IN_FD(vts[line].chan), &tty->winsize.ws_row, + &tty->winsize.ws_col); + return(ret); +} + +static void con_close(struct tty_struct * tty, struct file * filp) +{ + int line; + + line = MINOR(tty->device) - tty->driver.minor_start; + vts[line].count--; +} + +static int con_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int line; + + line = MINOR(tty->device) - tty->driver.minor_start; + return(write_chan(&vts[line].chan, buf, count)); +} + +static int write_room(struct tty_struct * tty) +{ + return(1024); +} + +static void set_termios(struct tty_struct *tty, struct termios * old) +{ +} + +static int chars_in_buffer(struct tty_struct *tty) +{ + return(0); +} + +extern void tty_register_devfs(struct tty_driver *driver, unsigned int flags, + unsigned int minor); +extern void tty_unregister_devfs (struct tty_driver *driver, unsigned minor); + +int stdio_init(void) +{ + int i; + + for(i=0;i<sizeof(vts)/sizeof(vts[0]);i++){ + if((vts[i].chan.in.type == XTERM) && + (vts[i].chan.in.init_pri == INIT_STATIC)) + vts[i].chan = + ((struct io_chan) + XTERM_IO_CHAN_INIT(i, "Virtual Console #%d", + 1, INIT_STATIC)); + } + + printk(KERN_INFO "Initializing stdio console driver\n"); + memset(&console_driver, 0, sizeof(struct tty_driver)); + console_driver.magic = TTY_DRIVER_MAGIC; + console_driver.driver_name = "stdio console"; + console_driver.name = "ttys/%d"; + console_driver.major = TTY_MAJOR; + console_driver.minor_start = 0; + console_driver.num = 8; + console_driver.type = TTY_DRIVER_TYPE_CONSOLE; + console_driver.subtype = SYSTEM_TYPE_CONSOLE; + console_driver.init_termios = tty_std_termios; + console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + console_driver.refcount = &console_refcount; + console_driver.table = console_table; + console_driver.termios = console_termios; + console_driver.termios_locked = console_termios_locked; + + console_driver.open = con_open; + console_driver.close = con_close; + console_driver.write = con_write; + console_driver.put_char = NULL; + console_driver.flush_chars = NULL; + console_driver.write_room = write_room; + console_driver.chars_in_buffer = chars_in_buffer; + console_driver.flush_buffer = NULL; + console_driver.ioctl = NULL; + console_driver.throttle = NULL; + console_driver.unthrottle = NULL; + console_driver.send_xchar = NULL; + console_driver.set_termios = set_termios; + console_driver.stop = NULL; + console_driver.start = NULL; + console_driver.hangup = NULL; + console_driver.break_ctl = NULL; + console_driver.wait_until_sent = NULL; + console_driver.read_proc = NULL; + if (tty_register_driver(&console_driver)) + panic("Couldn't register console driver\n"); + for(i=0;i<MAX_TTYS;i++){ + tty_register_devfs(&console_driver, 0, i); + } + open_console(0, NULL); + return(0); +} + +__initcall(stdio_init); + +static void console_write(struct console *console, const char *string, + unsigned len) +{ + cooked(CHAN_OUT_FD(vts[console->index].chan)); + write_chan(&vts[console->index].chan, string, len); + raw(CHAN_OUT_FD(vts[console->index].chan), 0); +} + +static kdev_t console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, c->index); +} + +static int console_setup(struct console *co, char *options) +{ + return(0); +} + +static struct console stdiocons = { + "tty", + console_write, + NULL, + console_device, + NULL, + NULL, + console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +void stdio_console_init(void) +{ + save_console_flags(); + register_console(&stdiocons); +} + +void stdio_announce(char *dev_name, int dev) +{ + printk("Virtual console %d assigned device '%s'\n", dev, dev_name); +} + +static struct chan_opts opts = { + announce: stdio_announce, + dev: -1, + xterm_title: "Virtual Console #%d", + raw_pty: 1 +}; + +static int console_chan_setup(char *str) +{ + int i, n; + char *end; + + if(*str == '=') n = -1; + else { + n = simple_strtoul(str, &end, 0); + if(*end != '='){ + printk("console_chan_setup failed to parse \"%s\"\n", + str); + return(1); + } + str = end; + } + str++; + if(n == -1){ + for(i=0;i<sizeof(vts)/sizeof(vts[0]);i++){ + opts.dev = i; + if(parse_chan_pair(str, i, &vts[i].chan, INIT_ALL, + &opts)) + return(1); + } + } + else { + opts.dev = n; + parse_chan_pair(str, n, &vts[n].chan, INIT_ONE, &opts); + } + return(1); +} + +__setup("con", console_chan_setup); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/drivers/stdio_console.h linux.ac/arch/um/drivers/stdio_console.h --- linux.vanilla/arch/um/drivers/stdio_console.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/drivers/stdio_console.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __STDIO_CONSOLE_H +#define __STDIO_CONSOLE_H + +extern int stdio_console_thread(unsigned long sp); +extern int stdio_start_thread(int pid); +extern void open_vt(int n, int *pid_out, int *in_fd_out, int *out_fd_out); +extern void update_console_size(int fd, unsigned short *rows_out, + unsigned short *cols_out); +extern void save_console_flags(void); +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/drivers/stdio_console_user.c linux.ac/arch/um/drivers/stdio_console_user.c --- linux.vanilla/arch/um/drivers/stdio_console_user.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/drivers/stdio_console_user.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <unistd.h> +#include <signal.h> +#include <sched.h> +#include <errno.h> +#include <termios.h> +#include <sys/select.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include "stdio_console.h" +#include "user_util.h" +#include "kern_util.h" +#include "user.h" + +struct termios cooked_tt; + +void save_console_flags(void) +{ + if(isatty(0)) tcgetattr(0, &cooked_tt); + else if(isatty(1)) tcgetattr(1, &cooked_tt); + else tcgetattr(2, &cooked_tt); +} + +void cooked(int fd) +{ + tcsetattr(fd, TCSADRAIN, &cooked_tt); +} + +void update_console_size(int fd, unsigned short *rows_out, + unsigned short *cols_out) +{ + struct winsize size; + + if(ioctl(fd, TIOCGWINSZ, &size) == 0){ + *rows_out = size.ws_row; + *cols_out = size.ws_col; + } +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/drivers/ubd.c linux.ac/arch/um/drivers/ubd.c --- linux.vanilla/arch/um/drivers/ubd.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/drivers/ubd.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,549 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "ubd_user.h" +#define MAJOR_NR UBD_MAJOR +#include "linux/blk.h" +#include "linux/blkdev.h" +#include "linux/hdreg.h" +#include "linux/init.h" +#include "linux/devfs_fs_kernel.h" +#include "linux/cdrom.h" +#include <linux/proc_fs.h> +#include "asm/segment.h" +#include "asm/uaccess.h" +#include "asm/irq.h" +#include "user_util.h" +#include "kern_util.h" +#include "kern.h" + +static int ubd_open(struct inode * inode, struct file * filp); +static int ubd_release(struct inode * inode, struct file * file); +static int ubd_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg); + +#define MAX_DEV (8) + +static int blk_sizes[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = BLOCK_SIZE }; + +static int hardsect_sizes[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = BLOCK_SIZE }; + +static int sizes[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = 0 }; + +static struct block_device_operations ubd_blops = { + open: ubd_open, + release: ubd_release, + ioctl: ubd_ioctl, +}; + +static struct hd_struct ubd_part[MAX_DEV] = +{ [ 0 ... MAX_DEV - 1 ] = { 0, 0, 0 } }; + +static int fake_major = 0; + +static struct gendisk ubd_gendisk = { + MAJOR_NR, /* Major number */ + "ubd", /* Major name */ + 0, /* Bits to shift to get real from partition */ + 1, /* Number of partitions per real */ + ubd_part, /* hd struct */ + sizes, /* block sizes */ + MAX_DEV, /* number */ + NULL, /* internal */ + NULL, /* next */ + &ubd_blops, /* file operations */ +}; + +static struct gendisk fake_gendisk = { + 0, /* Major number */ + "ubd", /* Major name */ + 0, /* Bits to shift to get real from partition */ + 1, /* Number of partitions per real */ + ubd_part, /* hd struct */ + sizes, /* block sizes */ + MAX_DEV, /* number */ + NULL, /* internal */ + NULL, /* next */ + &ubd_blops, /* file operations */ +}; + +#ifdef CONFIG_BLK_DEV_UBD_SYNC +#define OPEN_FLAGS O_RDWR | O_SYNC +#else +#define OPEN_FLAGS O_RDWR +#endif + +struct { + char *file; + int is_dir; + int count; + int fd; + __u64 size; + int boot_openflags; + int openflags; +} ubd_dev[MAX_DEV] = { { "root_fs", 0, 0, -1, 0, OPEN_FLAGS, OPEN_FLAGS }, + [ 1 ... MAX_DEV - 1 ] = + { NULL, 0, 0, -1, -1, OPEN_FLAGS, OPEN_FLAGS } }; + +static struct hd_driveid ubd_id = { + cyls: 0, + heads: 128, + sectors: 32, +}; + +static int fake_ide = 0; +static struct proc_dir_entry *proc_ide_root = NULL; +static struct proc_dir_entry *proc_ide = NULL; + +static void make_proc_ide(void) +{ + proc_ide_root = proc_mkdir("ide", 0); + proc_ide = proc_mkdir("ide0", proc_ide_root); +} + +static int proc_ide_read_media(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int len; + + strcpy(page, "disk\n"); + len = strlen("disk\n"); + len -= off; + if (len < count){ + *eof = 1; + if (len <= 0) return 0; + } + else len = count; + *start = page + off; + return len; + +} + +static void make_ide_entries(char *dev_name) +{ + struct proc_dir_entry *dir, *ent; + char name[64]; + + if(!fake_ide) return; + if(proc_ide_root == NULL) make_proc_ide(); + dir = proc_mkdir(dev_name, proc_ide); + ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir); + if(!ent) return; + ent->nlink = 1; + ent->data = NULL; + ent->read_proc = proc_ide_read_media; + ent->write_proc = NULL; + sprintf(name,"ide0/%s", dev_name); + proc_symlink(dev_name, proc_ide_root, name); +} + +static int fake_ide_setup(char *str) +{ + fake_ide = 1; + return(1); +} + +__setup("fake_ide", fake_ide_setup); + +static int ubd_setup(char *str) +{ + int n; + int sync, perm = O_RDWR; + + n = *str++; + if(n == '='){ + char *end; + int major; + + if(!strcmp(str, "sync")){ + sync = 1; + return(1); + } + major = simple_strtoul(str, &end, 0); + if(*end != '\0'){ + printk("ubd_setup : didn't parse major number\n"); + return(1); + } + fake_gendisk.major = major; + fake_major = major; + printk("Setting extra ubd major number to %d\n", major); + return(1); + } + if(n < '0'){ + printk("ubd_setup : index out of range\n"); + return(1); + } + n -= '0'; + if(n >= MAX_DEV){ + printk("ubd_setup : index out of range\n"); + return(1); + } + sync = ubd_dev[n].boot_openflags & O_SYNC; + if (*str == 'r') { + perm = O_RDONLY; + str++; + } + if (*str == 's') { + sync = O_SYNC; + str++; + } + if(*str++ != '='){ + printk("ubd_setup : Expected '='\n"); + return(1); + } + ubd_dev[n].file = str; + ubd_dev[n].boot_openflags = perm | sync; + return(1); +} + +__setup("ubd", ubd_setup); + +static int fakehd(char *str) +{ + printk("fakehd : Changing ubd_gendisk.major_name to \"hd\".\n"); + ubd_gendisk.major_name = "hd"; + return(1); +} + +__setup("fakehd", fakehd); + +static void do_ubd_request(request_queue_t * q); + +int thread_fds[2] = { -1, -1 }; + +int intr_count = 0; + +extern int errno; + +#ifdef CONFIG_SMP +#error end_request needs some locking +#endif + +static void ubd_finish(void) +{ + int nsect; + + nsect = CURRENT->current_nr_sectors; + CURRENT->sector += nsect; + CURRENT->buffer += nsect << 9; + CURRENT->errors = 0; + CURRENT->nr_sectors -= nsect; + CURRENT->current_nr_sectors = 0; + end_request(1); +} + +static void ubd_handler(void) +{ + struct io_thread_req req; + + DEVICE_INTR = NULL; + intr_count++; + if(read_ubd_fs(thread_fds[0], &req, sizeof(req)) != sizeof(req)){ + printk("Pid %d - spurious interrupt in ubd_handler, " + "errno = %d\n", getpid(), errno); + return; + } + if((req.offset != ((__u64) (CURRENT->sector)) << 9) || + (req.length != (CURRENT->current_nr_sectors) << 9)) + panic("I/O op mismatch"); + ubd_finish(); + reactivate_fd(thread_fds[0]); + if (!QUEUE_EMPTY) do_ubd_request(NULL); +} + +static void ubd_intr(int irq, void *dev, struct pt_regs *unused) +{ + ubd_handler(); +} + +static int io_pid = -1; + +void kill_io_thread(void) +{ + if(io_pid != -1) kill(io_pid, SIGKILL); +} + +__exitcall(kill_io_thread); + +int sync = 0; + +int ubd_init(void) +{ + unsigned long stack; + int i, err; + char name[6], dev_name[sizeof("ubd0x")]; + devfs_handle_t devfs_handle; + request_queue_t *q; + + devfs_handle = devfs_mk_dir (NULL, "ubd", NULL); + if (devfs_register_blkdev(MAJOR_NR, "ubd", &ubd_blops)) { + printk("ubd: unable to get major %d\n", MAJOR_NR); + return -1; + } + q = BLK_DEFAULT_QUEUE(MAJOR_NR); + blk_init_queue(q, DEVICE_REQUEST); + elevator_init(&q->elevator, ELEVATOR_NOOP); + read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */ + blksize_size[MAJOR_NR] = blk_sizes; + hardsect_size[MAJOR_NR] = hardsect_sizes; + ubd_gendisk.next = gendisk_head; + gendisk_head = &ubd_gendisk; + if (fake_major != 0){ + if(devfs_register_blkdev(fake_major, "ubd", &ubd_blops)) { + printk("ubd: unable to get major %d\n", fake_major); + return -1; + } + blk_init_queue(BLK_DEFAULT_QUEUE(fake_major), DEVICE_REQUEST); + read_ahead[fake_major] = 8; /* 8 sector (4kB) read-ahead */ + blksize_size[fake_major] = blk_sizes; + fake_gendisk.next = gendisk_head; + gendisk_head = &fake_gendisk; + } + for(i=0;i<MAX_DEV;i++){ + if(ubd_dev[i].file == NULL) continue; + ubd_dev[i].size = file_size(ubd_dev[i].file); + if(ubd_dev[i].size != -1){ + ubd_part[i].start_sect = 0; + ubd_part[i].nr_sects = ubd_dev[i].size / blk_sizes[i]; + sizes[i] = ubd_part[i].nr_sects; + } + sprintf(name, "%d", i); + devfs_register (devfs_handle, name, DEVFS_FL_DEFAULT, + MAJOR_NR, i, + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |S_IWGRP, + &ubd_blops, NULL); + if(fake_major != 0){ + devfs_register (devfs_handle, name, + DEVFS_FL_DEFAULT, fake_major, i, + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP | + S_IWGRP, &ubd_blops, NULL); + } + if(!strcmp(ubd_gendisk.major_name, "ubd")){ + sprintf(dev_name, "%s%d", ubd_gendisk.major_name, i); + } + else { + sprintf(dev_name, "%s%c", ubd_gendisk.major_name, + i + 'a'); + } + make_ide_entries(dev_name); + } + if(sync){ + printk("ubd : Synchronous mode\n"); + return(0); + } + stack = alloc_stack(); + io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), + thread_fds); + if(io_pid < 0){ + printk("ubd : Failed to start I/O thread (errno = %d) - " + "falling back to synchronous I/O\n", -io_pid); + return(0); + } + err = um_request_irq(UBD_IRQ, thread_fds[0], ubd_intr, SA_INTERRUPT, + "ubd", ubd_dev); + if(err != 0) printk("um_request_irq failed - errno = %d\n", -err); + return(err); +} + +__initcall(ubd_init); + +static int ubd_open(struct inode * inode, struct file * filp) +{ + int n; + + n = DEVICE_NR(inode->i_rdev); + if(n > MAX_DEV) + return -ENODEV; + if(ubd_is_dir(ubd_dev[n].file)){ + ubd_dev[n].is_dir = 1; + return(0); + } + ubd_dev[n].openflags = ubd_dev[n].boot_openflags; + if(ubd_dev[n].count == 0){ + if((ubd_dev[n].fd = open_ubd_fs(ubd_dev[n].file, + &ubd_dev[n].openflags)) < 0){ + printk("ubd%d: Can't open \"%s\": errno = %d\n", n, + ubd_dev[n].file, -ubd_dev[n].fd); + } + } + if(ubd_dev[n].fd < 0) + return -ENODEV; + ubd_dev[n].count++; + if ((filp->f_mode & FMODE_WRITE) && + ((ubd_dev[n].openflags & ~O_SYNC) == O_RDONLY)){ + if(--ubd_dev[n].count == 0) close_fd(ubd_dev[n].fd); + return -EROFS; + } + return(0); +} + +static int ubd_release(struct inode * inode, struct file * file) +{ + int n; + + n = DEVICE_NR(inode->i_rdev); + if(n > MAX_DEV) + return -ENODEV; + if(--ubd_dev[n].count == 0) close_fd(ubd_dev[n].fd); + return(0); +} + +static void do_one_request(void) +{ + struct io_thread_req req; + int block, nsect, dev, again; + + if(CURRENT->rq_status == RQ_INACTIVE) return; + if (DEVICE_INTR) return; + do { + again = 0; + INIT_REQUEST; + block = CURRENT->sector; + nsect = CURRENT->current_nr_sectors; + dev = MINOR(CURRENT->rq_dev); + if(ubd_dev[dev].is_dir){ + strcpy(CURRENT->buffer, "HOSTFS:"); + strcat(CURRENT->buffer, ubd_dev[dev].file); + end_request(1); + return; + } + req.read = (CURRENT->cmd == READ); + req.fd = ubd_dev[dev].fd; + req.offset = ((__u64) block) << 9; + req.length = nsect << 9; + req.buffer = CURRENT->buffer; + req.req = CURRENT; + if((req.offset >= ubd_dev[dev].size) && + (ubd_dev[dev].size != -1)){ + end_request(0); + again = 1; + } + } while(again); + if(thread_fds[0] == -1){ + do_io(&req); + ubd_finish(); + } + else { + SET_INTR(ubd_handler); + write_ubd_fs(thread_fds[1], (char *) &req, sizeof(req)); + } +} + +static void do_ubd_request(request_queue_t * q) +{ + if(thread_fds[0] == -1){ + while(!QUEUE_EMPTY){ + do_one_request(); + } + } + else { + do_one_request(); + } +} + +static int ubd_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct hd_geometry *loc = (struct hd_geometry *) arg; + int dev, err; + + if ((!inode) || !(inode->i_rdev)) + return -EINVAL; + dev = DEVICE_NR(inode->i_rdev); + if (dev > MAX_DEV) + return -EINVAL; + switch (cmd) { + struct hd_geometry g; + struct cdrom_volctrl volume; + case HDIO_GETGEO: + if (!loc) return -EINVAL; + g.heads = 128; + g.sectors = 32; + g.cylinders = ubd_dev[dev].size / (128 * 32); + g.start = 2; + return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; + case BLKRASET: + if(!suser()) return -EACCES; + if(arg > 0xff) return -EINVAL; + read_ahead[MAJOR(inode->i_rdev)] = arg; + return 0; + case BLKRAGET: + if (!arg) return -EINVAL; + err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); + if (err) + return err; + return 0; + case BLKGETSIZE: /* Return device size */ + if (!arg) return -EINVAL; + err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); + if (err) + return err; + put_user(ubd_dev[dev].size >> 9, (long *) arg); + return 0; + case BLKFLSBUF: + if(!suser()) return -EACCES; + return 0; + + case BLKRRPART: /* Re-read partition tables */ + return 0; /* revalidate_hddisk(inode->i_rdev, 1); */ + + case HDIO_SET_UNMASKINTR: + if (!suser()) return -EACCES; + if ((arg > 1) || (MINOR(inode->i_rdev) & 0x3F)) + return -EINVAL; + return 0; + + case HDIO_GET_UNMASKINTR: + if (!arg) return -EINVAL; + err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); + if (err) + return err; + return 0; + + case HDIO_GET_MULTCOUNT: + if (!arg) return -EINVAL; + err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); + if (err) + return err; + return 0; + + case HDIO_SET_MULTCOUNT: + if (!suser()) return -EACCES; + if (MINOR(inode->i_rdev) & 0x3F) return -EINVAL; + return 0; + + case HDIO_GET_IDENTITY: + ubd_id.cyls = ubd_dev[dev].size / (128 * 32); + if (copy_to_user((char *) arg, (char *) &ubd_id, + sizeof(ubd_id))) + return -EFAULT; + return 0; + + case CDROMVOLREAD: + if(copy_from_user(&volume, (char *) arg, sizeof(volume))) + return -EFAULT; + volume.channel0 = 255; + volume.channel1 = 255; + volume.channel2 = 255; + volume.channel3 = 255; + if(copy_from_user((char *) arg, &volume, sizeof(volume))) + return -EFAULT; + return 0; + + default: + return -EINVAL; + } +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/drivers/ubd_user.c linux.ac/arch/um/drivers/ubd_user.c --- linux.vanilla/arch/um/drivers/ubd_user.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/drivers/ubd_user.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <unistd.h> +#include <errno.h> +#include <sched.h> +#include <signal.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/fcntl.h> +#include "user_util.h" +#include "user.h" +#include "ubd_user.h" + +extern void panic(char *fmt, ...); + +int open_ubd_fs(char *file, int *openflags) +{ + int fd; + + if((fd = open(file, *openflags, 0)) < 0){ + if((*openflags != O_RDWR) || + ((errno != EROFS) && (errno != EACCES))) return(-errno); + *openflags = O_RDONLY; + if((fd = open(file, *openflags, 0)) < 0) return(-errno); + } + return(fd); +} + +int read_ubd_fs(int fd, void *buffer, int len) +{ + return(read(fd, buffer, len)); +} + +int write_ubd_fs(int fd, char *buffer, int len) +{ + return(write(fd, buffer, len)); +} + +int ubd_is_dir(char *file) +{ + struct stat buf; + + if(stat(file, &buf) < 0) return(0); + return(S_ISDIR(buf.st_mode)); +} + +int do_io(struct io_thread_req *req) +{ + int n; + + if(lseek(req->fd, req->offset, SEEK_SET) < 0){ + printk("do_io - lseek failed : errno = %d\n", + errno); + return(-1); + } + if(req->read){ + n = read(req->fd, req->buffer, req->length); + if(n != req->length) + memset(&req->buffer[n], 0, req->length - n); + else if(n <= 0){ + printk("do_io - read returned %d : " + "errno = %d\n", n, errno); + return(-1); + } + } + else { + n = write(req->fd, req->buffer, req->length); + if(n != req->length){ + printk("do_io - write returned %d : " + "errno = %d\n", n, errno); + return(-1); + } + } + return(0); +} + +int kernel_fds[2] = { -1, -1 }; + +int io_count = 0; + +int io_thread(void *arg) +{ + struct io_thread_req req; + int n; + + while(1){ + n = read(kernel_fds[0], &req, sizeof(req)); + if(n < 0) printk("io_thread - read returned %d, errno = %d\n", + n, errno); + else if(n < sizeof(req)){ + printk("io_thread - short read : length = %d\n", n); + continue; + } + io_count++; + do_io(&req); + if(write(kernel_fds[1], &req, sizeof(req)) != sizeof(req)) + printk("io_thread - write failed, errno = %d\n", + errno); + } +} + +int start_io_thread(unsigned long sp, int *fds_out) +{ + int pid; + + if((kernel_fds[0] = get_pty()) < 0) return(-1); + raw(kernel_fds[0], 1); + if((fds_out[0] = open(ptsname(kernel_fds[0]), O_RDWR)) < 0){ + printk("Couldn't open tty for slip line\n"); + return(-1); + } + fds_out[1] = fds_out[0]; + kernel_fds[1] = kernel_fds[0]; + pid = clone(io_thread, (void *) sp, CLONE_VM | CLONE_FILES | SIGCHLD, + NULL); + if(pid < 0){ + printk("start_io_thread - clone failed : errno = %d\n", errno); + return(-errno); + } + return(pid); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/drivers/umn_kern.c linux.ac/arch/um/drivers/umn_kern.c --- linux.vanilla/arch/um/drivers/umn_kern.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/drivers/umn_kern.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/init.h" +#include "linux/netdevice.h" +#include "linux/skbuff.h" +#include "linux/if_arp.h" +#include "linux/init.h" +#include <linux/spinlock.h> +#include "umn.h" +#include "user_util.h" +#include "kern.h" +#include "kern_util.h" + +struct umn { + int used; + int tty_fd; + int slave; + int slipno; + int rcount; + int esc; + char rbuff[3000]; + int buffsize; + struct net_device dev; + char *ptp_addr; + spinlock_t lock; +}; + +struct umn umn = { 0, -1, -1, -1, -1, 0, { }, 0, { }, "192.168.0.254", + SPIN_LOCK_UNLOCKED }; + +static int xmit(struct sk_buff *skb, struct net_device *dev) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&umn.lock, flags); + ret = umn_send_packet(umn.tty_fd, skb->data, skb->len); + dev_kfree_skb(skb); + spin_unlock_irqrestore(&umn.lock, flags); + return(ret); +} + +void umn_rcv(char *data, int len) +{ + struct sk_buff *skb; + + skb = dev_alloc_skb(len); + memcpy(skb_put(skb, len), data, len); + skb->mac.raw = skb->data; + skb->dev = &umn.dev; + skb->protocol = htons(ETH_P_IP); + netif_rx(skb); +} + +/* SLIP protocol characters. */ +#define END 0300 /* indicates end of frame */ +#define ESC 0333 /* indicates byte stuffing */ +#define ESC_END 0334 /* ESC ESC_END means END 'data' */ +#define ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */ + +void slip_unesc(unsigned char s) +{ + + switch(s) { + case END: + if (umn.rcount > 2) { + umn_rcv(umn.rbuff, umn.rcount); + } + umn.esc = 0; + umn.rcount = 0; + return; + + case ESC: + umn.esc = 1; + return; + case ESC_ESC: + if(umn.esc){ + umn.esc = 0; + s = ESC; + } + break; + case ESC_END: + if(umn.esc){ + umn.esc = 0; + s = END; + } + break; + } + if (umn.rcount < umn.buffsize) { + umn.rbuff[umn.rcount++] = s; + return; + } + printk("umn receive overflow\n"); +} + +spinlock_t umn_lock = SPIN_LOCK_UNLOCKED; + +void umn_handler(int irq, void *dev, struct pt_regs *unused) +{ + umn_read(umn.tty_fd); + reactivate_fd(umn.tty_fd); +} + +static int umn_open(struct net_device *dev) +{ + int err; + + spin_lock(&umn_lock); + if(umn.used){ + spin_unlock(&umn_lock); + return(-ENXIO); + } + umn.used = 1; + spin_unlock(&umn_lock); + umn.tty_fd = open_umn_tty(&umn.slave, &umn.slipno); + umn.rcount = 0; + umn.esc = 0; + umn.buffsize = sizeof(umn.rbuff)/sizeof(umn.rbuff[0]); + if((err = um_request_irq(UMN_IRQ, umn.tty_fd, umn_handler, + SA_INTERRUPT, "umn", &umn)) != 0){ + printk("umn_init : request_irq failed - errno = %d\n", -err); + return(err); + } + if(umn.tty_fd == -1) return(-1); + else return(0); +} + +static int umn_close (struct net_device *dev) +{ + spin_lock(&umn_lock); + if(!umn.used){ + spin_unlock(&umn_lock); + return(-ENXIO); + } + umn.used = 0; + spin_unlock(&umn_lock); + close_umn_tty(umn.tty_fd, umn.slave); + free_irq(UMN_IRQ, &umn); + return(0); +} + +static int umn_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) +{ + printk("umn ioctl = %d\n", cmd); + if((cmd >= SIOCDEVPRIVATE) && (cmd <= SIOCDEVPRIVATE + 15)) + return(-EOPNOTSUPP); + return(-EOPNOTSUPP); +} + +static int set_addr(struct net_device *dev, void *addr) +{ + struct sockaddr *sa; + char in_addr[sizeof("255.255.255.255")]; + unsigned char *eth_addr; + + sa = addr; + eth_addr = (unsigned char *) sa->sa_data; + sprintf(in_addr, "%d.%d.%d.%d", eth_addr[0], eth_addr[1], + eth_addr[2], eth_addr[3]); + return(set_umn_addr(umn.slave, in_addr, umn.ptp_addr)); +} + +static int init_dev(struct net_device *dev) +{ + dev->mtu = 1500; + dev->hard_start_xmit = xmit; + dev->open = umn_open; + dev->stop = umn_close; + dev->get_stats = NULL; + dev->do_ioctl = umn_ioctl; + dev->hard_header_len = 0; + dev->addr_len = 4; + dev->type = ARPHRD_ETHER; + dev->tx_queue_len = 256; + dev->set_mac_address = set_addr; + dev_init_buffers(dev); + dev->flags = IFF_NOARP; + return 0; +} + +int __init umn_init(void) +{ + struct net_device *d; + + d = &umn.dev; + strncpy(d->name, "umn", IFNAMSIZ); + d->init = init_dev; + if(register_netdev(d)) + printk("Couldn't initialize umn\n"); + return(0); +} + +__initcall(umn_init); + +static int umn_setup(char *str) +{ + if(*str++ != '='){ + printk("umn_setup : Expected '='\n"); + return(1); + } + umn.ptp_addr = str; + return(1); +} + +__setup("umn", umn_setup); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/drivers/umn_user.c linux.ac/arch/um/drivers/umn_user.c --- linux.vanilla/arch/um/drivers/umn_user.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/drivers/umn_user.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <fcntl.h> +#include <termios.h> +#include <wait.h> +#include <signal.h> +#include <sched.h> +#include <errno.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/vfs.h> +#include "umn.h" +#include "user_util.h" +#include "kern_util.h" +#include "user.h" + +char in_buff[3000]; +char out_buff[3000]; + +/* SLIP protocol characters. */ +#define END 0300 /* indicates end of frame */ +#define ESC 0333 /* indicates byte stuffing */ +#define ESC_END 0334 /* ESC ESC_END means END 'data' */ +#define ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */ + +static int slip_esc(unsigned char *s, unsigned char *d, int len) +{ + unsigned char *ptr = d; + unsigned char c; + + /* + * Send an initial END character to flush out any + * data that may have accumulated in the receiver + * due to line noise. + */ + + *ptr++ = END; + + /* + * For each byte in the packet, send the appropriate + * character sequence, according to the SLIP protocol. + */ + + while (len-- > 0) { + switch(c = *s++) { + case END: + *ptr++ = ESC; + *ptr++ = ESC_END; + break; + case ESC: + *ptr++ = ESC; + *ptr++ = ESC_ESC; + break; + default: + *ptr++ = c; + break; + } + } + *ptr++ = END; + return (ptr - d); +} + +int umn_send_packet(int fd, void *data, int len) +{ + int actual, n; + + actual = slip_esc(data, out_buff, len); + n = write(fd, out_buff, actual); + if(n == actual) return(0); + else return(1); +} + +void umn_read(int fd) +{ + int i, n; + + while(1){ + n = read(fd, in_buff, sizeof(in_buff)/sizeof(in_buff[0])); + if(n == 0) printk("umn_read hit EOF\n"); + else if(n < 0){ + if(errno == EIO){ + close(fd); + return; + } + else if((errno == EBADF) || (errno == EAGAIN)) return; + printk("umn_read had error, errno = %d\n", errno); + } + else { + for(i=0;i<n;i++) + slip_unesc(in_buff[i]); + } + } +} + +static int set_up_tty(int fd) +{ + int i; + struct termios tios; + + if (tcgetattr(fd, &tios) < 0) { + printk("could not get initial terminal attributes\n"); + return(-1); + } + + tios.c_cflag = CS8 | CREAD | HUPCL | CLOCAL; + tios.c_iflag = IGNBRK | IGNPAR; + tios.c_oflag = 0; + tios.c_lflag = 0; + for (i = 0; i < NCCS; i++) + tios.c_cc[i] = 0; + tios.c_cc[VMIN] = 1; + tios.c_cc[VTIME] = 0; + + cfsetospeed(&tios, B38400); + cfsetispeed(&tios, B38400); + + if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) { + printk("failed to set terminal attributes\n"); + return(-1); + } + return(0); +} + +struct helper_arg { + void *tramp_arg; + int fd; +}; + +static int ifconfig_addr_tramp(void *arg) +{ + struct helper_arg *args = arg; + char **argv = args->tramp_arg, error[256]; + + execvp(argv[0], argv); + sprintf(error, "exec of %s failed, errno = %d\n", argv[0], errno); + write(args->fd, error, strlen(error)); + return(1); +} + +static int run_ifconfig(char *prog, void *args, char *error_out, + int error_len) +{ + unsigned long stack; + int pid, status, fds[2], n; + struct helper_arg arg; + + stack = alloc_stack(); + pipe(fds); + arg.tramp_arg = args; + arg.fd = fds[1]; + pid = clone(ifconfig_addr_tramp, (void *) stack_sp(stack), SIGCHLD, + &arg); + close(fds[1]); + if(pid < 0){ + printk("clone of \"%s\" failed\n", prog); + return(-1); + } + pid = waitpid(pid, &status, 0); + n = read(fds[0], error_out, error_len - 1); + error_out[n] = '\0'; + if(pid < 0){ + printk("wait for \"%s\" failed - errno = %d\n", prog, errno); + return(-1); + } + if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){ + close(fds[0]); + return(-1); + } + close(fds[0]); + free_stack(stack); + return(0); +} + +int open_umn_tty(int *slave_out, int *slipno_out) +{ + int sfd, mfd; + + if((mfd = get_pty()) < 0){ + printk("umn : Failed to open pty\n"); + return(-1); + } + if((sfd = open(ptsname(mfd), O_RDWR)) < 0){ + printk("Couldn't open tty for slip line\n"); + return(-1); + } + if(set_up_tty(sfd)) return(-1); + *slave_out = sfd; + return(mfd); +} + +int slipify(int fd) +{ + int disc, sencap, n; + + disc = N_SLIP; + sencap = 0; + if((n = ioctl(fd, TIOCSETD, &disc)) < 0){ + printk("Failed to set slip line discipline - errno = %d\n", + errno); + return(-1); + } + if(ioctl(fd, SIOCSIFENCAP, &sencap) < 0){ + printk("Couldn't set slip encapsulation - errno = %d\n", + errno); + return(-1); + } + return(n); +} + +int set_umn_addr(int fd, char *addr, char *ptp_addr) +{ + char slip_name[sizeof("slxxxx")], fd_name[sizeof("nnnnn")]; + char errors[3][256]; + char *helper_args[] = { "umn_helper", fd_name, ptp_addr, addr, + NULL }; + char *ifconfig_args[] = { "um_ifconfig", slip_name, ptp_addr, + "pointopoint", addr, "up", NULL }; + int slipno; + + sprintf(fd_name, "%d", fd); + if(!run_ifconfig(helper_args[0], helper_args, errors[0], + sizeof(errors[0]))) + return(0); + if((slipno = slipify(fd)) == -1){ + printk("umn - umn_helper failed : %s\n", errors[0]); + return(1); + } + sprintf(slip_name, "sl%d", slipno); + if(!run_ifconfig(ifconfig_args[0], ifconfig_args, errors[1], + sizeof(errors[1]))) + return(0); + if(getuid() == 0){ + ifconfig_args[0] = "ifconfig"; + if(!run_ifconfig(ifconfig_args[0], ifconfig_args, errors[2], + sizeof(errors[2]))) + return(0); + } + else errors[2][0] = '\0'; + printk("umn - umn_helper failed : %s\n", errors[0]); + printk("umn - um_ifconfig failed : %s\n", errors[1]); + if(errors[2][0] != '\0'){ + printk("umn - ifconfig failed : %s\n", errors[2]); + } + return(1); +} + +void close_umn_tty(int master, int slave) +{ + close(slave); + close(master); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/fs/Makefile linux.ac/arch/um/fs/Makefile --- linux.vanilla/arch/um/fs/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/fs/Makefile Mon Apr 9 23:25:02 2001 @@ -0,0 +1,16 @@ +# +# Copyright (C) 2000 Jeff Dike (jdike@karaya.com) +# Licensed under the GPL +# + +O_TARGET := fs.o + +subdir-$(CONFIG_HOSTFS) = hostfs + +MOD_SUB_DIRS := $(subdir-m) +SUB_DIRS := $(subdir-y) + +obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o)) +obj-m += $(join $(subdir-m),$(subdir-m:%=/%.o)) + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/fs/hostfs/Makefile linux.ac/arch/um/fs/hostfs/Makefile --- linux.vanilla/arch/um/fs/hostfs/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/fs/hostfs/Makefile Mon Apr 9 23:25:02 2001 @@ -0,0 +1,25 @@ +# +# Copyright (C) 2000 Jeff Dike (jdike@karaya.com) +# Licensed under the GPL +# + +EXTRA_CFLAGS += -I../../include +USER_CFLAGS := $(patsubst -I%,,$(CFLAGS)) + +O_TARGET := +obj-y := + +ifneq ($(CONFIG_HOSTFS), n) + O_TARGET := hostfs.o + obj-y := hostfs_kern.o hostfs_user.o + CFLAGS_hostfs_kern.o := $(CFLAGS) + CFLAGS_hostfs_user.o := $(USER_CFLAGS) +endif + +ifeq ($(CONFIG_HOSTFS), m) + obj-m := $(O_TARGET) +endif + +override CFLAGS = + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/fs/hostfs/hostfs.h linux.ac/arch/um/fs/hostfs/hostfs.h --- linux.vanilla/arch/um/fs/hostfs/hostfs.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/fs/hostfs/hostfs.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,68 @@ +#ifndef __UM_FS_HOSTFS +#define __UM_FS_HOSTFS + +#define HOSTFS_FILE 1 +#define HOSTFS_DIR 2 +#define HOSTFS_SYMLINK 3 + +/* These are exactly the same definitions as in fs.h, but the names are + * changed so that this file can be included in both kernel and user files. + */ + +#define HOSTFS_ATTR_MODE 1 +#define HOSTFS_ATTR_UID 2 +#define HOSTFS_ATTR_GID 4 +#define HOSTFS_ATTR_SIZE 8 +#define HOSTFS_ATTR_ATIME 16 +#define HOSTFS_ATTR_MTIME 32 +#define HOSTFS_ATTR_CTIME 64 +#define HOSTFS_ATTR_ATIME_SET 128 +#define HOSTFS_ATTR_MTIME_SET 256 +#define HOSTFS_ATTR_FORCE 512 /* Not a change, but a change it */ +#define HOSTFS_ATTR_ATTR_FLAG 1024 + +struct hostfs_iattr { + unsigned int ia_valid; + mode_t ia_mode; + uid_t ia_uid; + gid_t ia_gid; + loff_t ia_size; + time_t ia_atime; + time_t ia_mtime; + time_t ia_ctime; + unsigned int ia_attr_flags; +}; + +extern int stat_file(const char *path, int *dev_out, unsigned long *inode_out, + int *mode_out, int *nlink_out, int *uid_out, + int *gid_out, unsigned long *size_out, + unsigned long *atime_out, unsigned long *mtime_out, + unsigned long *ctime_out, int *blksize_out, + int *blocks_out); +extern int access_file(char *path, int r, int w, int x); +extern int open_file(char *path, int r, int w); +extern int file_type(const char *path); +extern void *open_dir(char *path, int *err_out); +extern char *read_dir(void *stream, unsigned long long *pos, int *len_out); +extern void close_file(void *stream); +extern void close_dir(void *stream); +extern int read_file(int fd, unsigned long long *offset, char *buf, int len); +extern int write_file(int fd, unsigned long long *offset, const char *buf, + int len, int append); +extern int lseek_file(int fd, long long offset, int whence); +extern int file_create(char *name, int ur, int uw, int ux, int gr, + int gw, int gx, int or, int ow, int ox); +extern int set_attr(const char *file, struct hostfs_iattr *attrs); +extern int make_symlink(const char *from, const char *to); +extern int unlink_file(const char *file); +extern int do_mkdir(const char *file, int mode); +extern int do_rmdir(const char *file); +extern int link_file(const char *from, const char *to); +extern int do_readlink(char *file, char *buf, int size); +extern int rename_file(char *from, char *to); +extern int do_statfs(char *root, long *bsize_out, long *blocks_out, + long *bfree_out, long *bavail_out, long *files_out, + long *ffree_out, void *fsid_out, int fsid_size, + long *namelen_out, long *spare_out); + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/fs/hostfs/hostfs_kern.c linux.ac/arch/um/fs/hostfs/hostfs_kern.c --- linux.vanilla/arch/um/fs/hostfs/hostfs_kern.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/fs/hostfs/hostfs_kern.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,691 @@ +/* + * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <linux/stddef.h> +#include <linux/fs.h> +#include <linux/version.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/pagemap.h> +#include <asm/uaccess.h> +#include "hostfs.h" +#include "kern_util.h" +#include "kern.h" +#include "user_util.h" + +int hostfs_d_delete(struct dentry *dentry) +{ + return(1); +} + +struct dentry_operations hostfs_dentry_ops = { + d_delete: hostfs_d_delete, +}; + +static char *root_ino = "/"; + +#define HOSTFS_SUPER_MAGIC 0x00c0ffee + +static struct inode_operations hostfs_iops; +static struct address_space_operations hostfs_link_aops; + +static char *dentry_name(struct dentry *dentry, int extra) +{ + struct dentry *parent; + char *root, *name; + int len; + + len = 0; + parent = dentry; + while(parent->d_parent != parent){ + len += parent->d_name.len + 1; + parent = parent->d_parent; + } + root = parent->d_inode->u.generic_ip; + len += strlen(root); + name = kmalloc(len + extra + 1, GFP_KERNEL); + if(name == NULL) return(NULL); + + name[len] = '\0'; + parent = dentry; + while(parent->d_parent != parent){ + len -= parent->d_name.len + 1; + name[len] = '/'; + strncpy(&name[len + 1], parent->d_name.name, + parent->d_name.len); + parent = parent->d_parent; + } + strncpy(name, root, strlen(root)); + return(name); +} + +static char *inode_name(struct inode *ino, int extra) +{ + struct dentry *dentry; + + dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias); + return(dentry_name(dentry, extra)); +} + +static int read_name(struct inode *ino, char *name) +{ + int err; + + err = stat_file(name, (int *) &ino->i_dev, &ino->i_ino, + (int *) &ino->i_mode, (int *) &ino->i_nlink, + &ino->i_uid, &ino->i_gid, + (unsigned long *) &ino->i_size, + &ino->i_atime, &ino->i_mtime, &ino->i_ctime, + (int *) &ino->i_blksize, (int *) &ino->i_blocks); + if(err) return(err); + if((ino->i_sb->s_dev == ROOT_DEV) && (ino->i_uid == getuid())) + ino->i_uid = 0; + return(0); +} + +static int read_inode(struct inode *ino) +{ + char *name; + int err; + + name = inode_name(ino, 0); + if(name == NULL) return(-ENOMEM); + err = read_name(ino, name); + kfree(name); + return(err); +} + +void hostfs_delete_inode(struct inode *ino) +{ + if(ino->u.generic_ip) kfree(ino->u.generic_ip); + ino->u.generic_ip = NULL; + clear_inode(ino); +} + +int hostfs_statfs(struct super_block *sb, struct statfs *sf) +{ + int err; + + err = do_statfs(sb->s_root->d_inode->u.generic_ip, &sf->f_bsize, + &sf->f_blocks, &sf->f_bfree, &sf->f_bavail, + &sf->f_files, &sf->f_ffree, &sf->f_fsid, + sizeof(sf->f_fsid), &sf->f_namelen, sf->f_spare); + if(err) return(err); + sf->f_type = HOSTFS_SUPER_MAGIC; + return(0); +} + +static struct super_operations hostfs_sbops = { + put_inode: force_delete, + delete_inode: hostfs_delete_inode, + statfs: hostfs_statfs, +}; + +ssize_t hostfs_write(struct file *file, const char *buf, size_t len, + loff_t *start) +{ + unsigned long page = __get_free_page(GFP_KERNEL); + int ret, one_len, n; + + if(page == 0) return(-ENOMEM); + ret = 0; + while(len > 0){ + one_len = (len < PAGE_SIZE) ? len : PAGE_SIZE; + if(copy_from_user((void *) page, &buf[ret], one_len)){ + ret = -EFAULT; + break; + } + n = write_file((int) file->private_data, start, (void *) page, + one_len, file->f_flags & O_APPEND); + if(n < 0){ + ret = n; + break; + } + ret += n; + len -= n; + if(n < one_len) break; + } + free_page(page); + return(ret); +} + +int hostfs_readdir(struct file *file, void *ent, filldir_t filldir) +{ + void *dir; + char *name; + unsigned long long next; + int error, len; + + name = dentry_name(file->f_dentry, 0); + if(name == NULL) return(-ENOMEM); + dir = open_dir(name, &error); + kfree(name); + if(dir == NULL) return(-error); + next = file->f_pos; + while((name = read_dir(dir, &next, &len)) != NULL){ + error = (*filldir)(ent, name, len, file->f_pos, + file->f_dentry->d_inode->i_ino, + DT_UNKNOWN); + if(error) break; + file->f_pos = next; + } + close_dir(dir); + return(0); +} + +unsigned int hostfs_poll(struct file *file, struct poll_table_struct *table) +{ + not_implemented(); + return(-EINVAL); +} + +int hostfs_ioctl(struct inode *ino, struct file *file, unsigned int code, + unsigned long data) +{ + not_implemented(); + return(-EINVAL); +} + +int hostfs_file_open(struct inode *ino, struct file *file) +{ + char *name; + int r = 0, w = 0, fd; + + if(file->f_mode & FMODE_READ) r = 1; + if(file->f_mode & FMODE_WRITE) w = 1; + name = dentry_name(file->f_dentry, 0); + if(name == NULL) return(-ENOMEM); + fd = open_file(name, r, w); + kfree(name); + if(fd < 0) return(fd); + file->private_data = (void *) fd; + return(0); +} + +int hostfs_dir_open(struct inode *ino, struct file *file) +{ + return(0); +} + +int hostfs_file_release(struct inode *ino, struct file *file) +{ + close_file(file->private_data); + return(0); +} + +int hostfs_dir_release(struct inode *ino, struct file *file) +{ + return(0); +} + +int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + return(0); +} + +int hostfs_fasync(int fd, struct file *file, int on) +{ + not_implemented(); + return(-EINVAL); +} + +static struct file_operations hostfs_file_fops = { + owner: NULL, + read: generic_file_read, + write: hostfs_write, + poll: hostfs_poll, + mmap: generic_file_mmap, + open: hostfs_file_open, + release: hostfs_file_release, + fsync: hostfs_fsync, + fasync: hostfs_fasync +}; + +static struct file_operations hostfs_dir_fops = { + owner: NULL, + readdir: hostfs_readdir, + poll: hostfs_poll, + ioctl: hostfs_ioctl, + open: hostfs_dir_open, + release: hostfs_dir_release, + fsync: hostfs_fsync, + fasync: hostfs_fasync +}; + +int hostfs_writepage(struct page *page) +{ + not_implemented(); + return(-EINVAL); +} + +int hostfs_readpage(struct file *file, struct page *page) +{ + char *buffer; + long long start; + int err = 0; + + start = page->index << PAGE_CACHE_SHIFT; + buffer = kmap(page); + err = read_file((int) file->private_data, &start, buffer, + PAGE_CACHE_SIZE); + if(err > 0){ + flush_dcache_page(page); + SetPageUptodate(page); + if (PageError(page)) ClearPageError(page); + err = 0; + } + kunmap(page); + UnlockPage(page); + return(err); +} + +int hostfs_prepare_write(struct file *file, struct page *page, unsigned from, + unsigned to) +{ + not_implemented(); + return(-EINVAL); +} + +int hostfs_commit_write(struct file *file, struct page *page, unsigned from, + unsigned to) +{ + not_implemented(); + return(-EINVAL); +} + +static struct address_space_operations hostfs_aops = { + writepage: hostfs_writepage, + readpage: hostfs_readpage, + prepare_write: hostfs_prepare_write, + commit_write: hostfs_commit_write +}; + +static struct inode *get_inode(struct super_block *sb, struct dentry *dentry, + int *error) +{ + struct inode *inode; + char *name; + int type, err = 0; + + inode = get_empty_inode(); + if(inode == NULL) return(NULL); + inode->u.generic_ip = NULL; + if(error) *error = 0; + insert_inode_hash(inode); + if(dentry){ + name = dentry_name(dentry, 0); + if(name == NULL){ + err = -ENOMEM; + goto out; + } + type = file_type(name); + kfree(name); + } + else type = HOSTFS_DIR; + inode->i_sb = sb; + + if(type == HOSTFS_SYMLINK) + inode->i_op = &page_symlink_inode_operations; + else inode->i_op = &hostfs_iops; + + if(type == HOSTFS_DIR) inode->i_fop = &hostfs_dir_fops; + else inode->i_fop = &hostfs_file_fops; + + if(type == HOSTFS_SYMLINK) inode->i_mapping->a_ops = &hostfs_link_aops; + else inode->i_mapping->a_ops = &hostfs_aops; + + return(inode); + out: + iput(inode); + if(error) *error = err; + return(NULL); +} + +int hostfs_create(struct inode *dir, struct dentry *dentry, int mode) +{ + struct inode *inode; + char *name; + int error; + + inode = get_inode(dir->i_sb, dentry, &error); + if(error) return(error); + name = dentry_name(dentry, 0); + if(name == NULL){ + iput(inode); + return(-ENOMEM); + } + error = file_create(name, + mode | S_IRUSR, mode | S_IWUSR, mode | S_IXUSR, + mode | S_IRGRP, mode | S_IWGRP, mode | S_IXGRP, + mode | S_IROTH, mode | S_IWOTH, mode | S_IXOTH); + if(!error) error = read_name(inode, name); + kfree(name); + if(error){ + iput(inode); + return(error); + } + d_instantiate(dentry, inode); + return(0); +} + +struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry) +{ + struct inode *inode; + char *name; + int error; + + inode = get_inode(ino->i_sb, dentry, &error); + if(error != 0) return(ERR_PTR(error)); + name = dentry_name(dentry, 0); + if(name == NULL) return(ERR_PTR(-ENOMEM)); + error = read_name(inode, name); + kfree(name); + if(error){ + iput(inode); + if(error == -ENOENT) inode = NULL; + else return(ERR_PTR(error)); + } + d_add(dentry, inode); + dentry->d_op = &hostfs_dentry_ops; + return(NULL); +} + +static char *inode_dentry_name(struct inode *ino, struct dentry *dentry) +{ + char *file; + int len; + + file = inode_name(ino, dentry->d_name.len + 2); + if(file == NULL) return(NULL); + strcat(file, "/"); + len = strlen(file); + strncat(file, dentry->d_name.name, dentry->d_name.len); + file[len + dentry->d_name.len] = '\0'; + return(file); +} + +int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from) +{ + char *from_name, *to_name; + int err; + + if((from_name = inode_dentry_name(ino, from)) == NULL) + return(-ENOMEM); + to_name = dentry_name(to, 0); + if(to_name == NULL){ + kfree(from_name); + return(-ENOMEM); + } + err = link_file(to_name, from_name); + kfree(from_name); + kfree(to_name); + return(err); +} + +int hostfs_unlink(struct inode *ino, struct dentry *dentry) +{ + char *file; + int err; + + if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM); + err = unlink_file(file); + kfree(file); + return(err); +} + +int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to) +{ + char *file; + int err; + + if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM); + err = make_symlink(file, to); + kfree(file); + return(err); +} + +int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode) +{ + char *file; + int err; + + if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM); + err = do_mkdir(file, mode); + kfree(file); + return(err); +} + +int hostfs_rmdir(struct inode *ino, struct dentry *dentry) +{ + char *file; + int err; + + if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM); + err = do_rmdir(file); + kfree(file); + return(err); +} + +int hostfs_mknod(struct inode *ino, struct dentry *dentry, int mode, int dev) +{ + not_implemented(); + return(-EINVAL); +} + +int hostfs_rename(struct inode *from_ino, struct dentry *from, + struct inode *to_ino, struct dentry *to) +{ + char *from_name, *to_name; + int err; + + if((from_name = inode_dentry_name(from_ino, from)) == NULL) + return(-ENOMEM); + if((to_name = inode_dentry_name(to_ino, to)) == NULL){ + kfree(from_name); + return(-ENOMEM); + } + err = rename_file(from_name, to_name); + kfree(from_name); + kfree(to_name); + return(err); +} + +void hostfs_truncate(struct inode *ino) +{ + not_implemented(); +} + +int hostfs_permission(struct inode *ino, int desired) +{ + char *name; + int r = 0, w = 0, x = 0, err; + + if(desired & MAY_READ) r = 1; + if(desired & MAY_WRITE) w = 1; + if(desired & MAY_EXEC) x = 1; + name = inode_name(ino, 0); + if(name == NULL) return(-ENOMEM); + err = access_file(name, r, w, x); + kfree(name); + return(err); +} + +int hostfs_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct hostfs_iattr attrs; + char *name; + int err; + + attrs.ia_valid = 0; + if(attr->ia_valid & ATTR_MODE){ + attrs.ia_valid |= HOSTFS_ATTR_MODE; + attrs.ia_mode = attr->ia_mode; + } + if(attr->ia_valid & ATTR_UID){ + attrs.ia_valid |= HOSTFS_ATTR_UID; + attrs.ia_uid = attr->ia_uid; + } + if(attr->ia_valid & ATTR_GID){ + attrs.ia_valid |= HOSTFS_ATTR_GID; + attrs.ia_gid = attr->ia_gid; + } + if(attr->ia_valid & ATTR_SIZE){ + attrs.ia_valid |= HOSTFS_ATTR_SIZE; + attrs.ia_size = attr->ia_size; + } + if(attr->ia_valid & ATTR_ATIME){ + attrs.ia_valid |= HOSTFS_ATTR_ATIME; + attrs.ia_atime = attr->ia_atime; + } + if(attr->ia_valid & ATTR_MTIME){ + attrs.ia_valid |= HOSTFS_ATTR_MTIME; + attrs.ia_mtime = attr->ia_mtime; + } + if(attr->ia_valid & ATTR_CTIME){ + attrs.ia_valid |= HOSTFS_ATTR_CTIME; + attrs.ia_ctime = attr->ia_ctime; + } + if(attr->ia_valid & ATTR_ATIME_SET){ + attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET; + } + if(attr->ia_valid & ATTR_MTIME_SET){ + attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET; + } + name = dentry_name(dentry, 0); + if(name == NULL) return(-ENOMEM); + err = set_attr(name, &attrs); + kfree(name); + return(err); +} + +int hostfs_getattr(struct dentry *dentry, struct iattr *attr) +{ + not_implemented(); + return(-EINVAL); +} + +static struct inode_operations hostfs_iops = { + create: hostfs_create, + lookup: hostfs_lookup, + link: hostfs_link, + unlink: hostfs_unlink, + symlink: hostfs_symlink, + mkdir: hostfs_mkdir, + rmdir: hostfs_rmdir, + mknod: hostfs_mknod, + rename: hostfs_rename, + truncate: hostfs_truncate, + permission: hostfs_permission, + setattr: hostfs_setattr, + getattr: hostfs_getattr, +}; + +int hostfs_link_readpage(struct file *file, struct page *page) +{ + char *buffer, *name; + long long start; + int err; + + start = page->index << PAGE_CACHE_SHIFT; + buffer = kmap(page); + name = inode_name(page->mapping->host, 0); + if(name == NULL) return(-ENOMEM); + err = do_readlink(name, buffer, PAGE_CACHE_SIZE); + kfree(name); + if(err == 0){ + flush_dcache_page(page); + SetPageUptodate(page); + if (PageError(page)) ClearPageError(page); + } + kunmap(page); + UnlockPage(page); + return(err); +} + +static struct address_space_operations hostfs_link_aops = { + readpage: hostfs_link_readpage, +}; + +static struct super_block *hostfs_read_super_common(struct super_block *sb, + char *data) +{ + struct inode * root_inode; + char *name; + + sb->s_blocksize = 1024; + sb->s_blocksize_bits = 10; + sb->s_magic = HOSTFS_SUPER_MAGIC; + sb->s_op = &hostfs_sbops; + if((data == NULL) || (*((char *) data) == '\0')) data = root_ino; + name = kmalloc(strlen(data) + 1, GFP_KERNEL); + if(name == NULL) return(NULL); + strcpy(name, data); + root_inode = get_inode(sb, NULL, NULL); + if(root_inode == NULL){ + kfree(name); + return(NULL); + } + root_inode->u.generic_ip = name; + sb->s_root = d_alloc_root(root_inode); + if(read_inode(root_inode)){ + kfree(name); + iput(root_inode); + return(NULL); + } + return(sb); +} + +struct super_block *hostfs_read_super(struct super_block *sb, void *data, + int silent) +{ + return(hostfs_read_super_common(sb, data)); +} + +struct super_block *hostfs_root_read_super(struct super_block *sb, void *data, + int silent) +{ + struct buffer_head * bh; + struct super_block *ret = NULL; + kdev_t dev = sb->s_dev; + int blocksize = get_hardblocksize(dev); + + if(blocksize == 0) blocksize = BLOCK_SIZE; + if(!(bh = bread (dev, 0, blocksize))) return NULL; + if(strncmp(bh->b_data, "HOSTFS:", strlen("HOSTFS:"))) goto out; + ret = hostfs_read_super_common(sb, bh->b_data + strlen("HOSTFS:")); + out: + brelse (bh); + return(ret); +} + +DECLARE_FSTYPE(hostfs_type, "hostfs", hostfs_read_super, 0); +DECLARE_FSTYPE_DEV(hostfs_root_type, "root hostfs", hostfs_root_read_super); + +static int __init init_hostfs(void) +{ + return(register_filesystem(&hostfs_type) || + register_filesystem(&hostfs_root_type)); +} + +static void __exit exit_hostfs(void) +{ + unregister_filesystem(&hostfs_type); + unregister_filesystem(&hostfs_root_type); +} + +module_init(init_hostfs) +module_exit(exit_hostfs) + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/fs/hostfs/hostfs_user.c linux.ac/arch/um/fs/hostfs/hostfs_user.c --- linux.vanilla/arch/um/fs/hostfs/hostfs_user.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/fs/hostfs/hostfs_user.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <unistd.h> +#include <stdio.h> +#include <fcntl.h> +#include <dirent.h> +#include <errno.h> +#include <utime.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/vfs.h> +#include "hostfs.h" +#include "kern_util.h" +#include "user.h" + +int stat_file(const char *path, int *dev_out, unsigned long *inode_out, + int *mode_out, int *nlink_out, int *uid_out, int *gid_out, + unsigned long *size_out, unsigned long *atime_out, + unsigned long *mtime_out, unsigned long *ctime_out, + int *blksize_out, int *blocks_out) +{ + struct stat buf; + + if(lstat(path, &buf) < 0) + return(-errno); + if(dev_out != NULL) *dev_out = buf.st_dev; + if(inode_out != NULL) *inode_out = buf.st_ino; + if(mode_out != NULL) *mode_out = buf.st_mode; + if(nlink_out != NULL) *nlink_out = buf.st_nlink; + if(uid_out != NULL) *uid_out = buf.st_uid; + if(gid_out != NULL) *gid_out = buf.st_gid; + if(size_out != NULL) *size_out = buf.st_size; + if(atime_out != NULL) *atime_out = buf.st_atime; + if(mtime_out != NULL) *mtime_out = buf.st_mtime; + if(ctime_out != NULL) *ctime_out = buf.st_ctime; + if(blksize_out != NULL) *blksize_out = buf.st_blksize; + if(blocks_out != NULL) *blocks_out = buf.st_blocks; + return(0); +} + +int file_type(const char *path) +{ + struct stat buf; + + if(lstat(path, &buf) < 0) return(-errno); + if(S_ISDIR(buf.st_mode)) return(HOSTFS_DIR); + else if(S_ISLNK(buf.st_mode)) return(HOSTFS_SYMLINK); + else return(HOSTFS_FILE); +} + +int access_file(char *path, int r, int w, int x) +{ + int mode = 0; + + if(r) mode = R_OK; + if(w) mode |= W_OK; + if(x) mode |= X_OK; + if(access(path, mode) != 0) return(-errno); + else return(0); +} + +int open_file(char *path, int r, int w) +{ + int mode = 0, fd; + + if(r && !w) mode = O_RDONLY; + else if(!r && w) mode = O_WRONLY; + else if(r && w) mode = O_RDWR; + else panic("Impossible mode in open_file"); + fd = open(path, mode); + if(fd < 0) return(-errno); + else return(fd); +} + +void *open_dir(char *path, int *err_out) +{ + DIR *dir; + + dir = opendir(path); + *err_out = errno; + if(dir == NULL) return(NULL); + return(dir); +} + +char *read_dir(void *stream, unsigned long long *pos, int *len_out) +{ + DIR *dir = stream; + struct dirent *ent; + + seekdir(dir, *pos); + ent = readdir(dir); + if(ent == NULL) return(NULL); + *len_out = strlen(ent->d_name); + *pos = telldir(dir); + return(ent->d_name); +} + +int read_file(int fd, unsigned long long *offset, char *buf, int len) +{ + int n; + + if(lseek(fd, *offset, SEEK_SET) != *offset) + return(-errno); + n = read(fd, buf, len); + if(n < 0) return(-errno); + *offset += n; + return(n); +} + +int write_file(int fd, unsigned long long *offset, const char *buf, int len, + int append) +{ + int n, where, off; + + off = *offset; + where = SEEK_SET; + if(append){ + where = SEEK_END; + off = 0; + } + if((off = lseek(fd, off, where)) == (off_t) -1) + return(-errno); + n = write(fd, buf, len); + if(n < 0) return(-errno); + *offset = off + n; + return(n); +} + +int lseek_file(int fd, long long offset, int whence) +{ + int ret; + + ret = lseek(fd, (int) offset, whence); + if(ret < 0) return(-errno); + return(0); +} + +void close_file(void *stream) +{ + close((int) stream); +} + +void close_dir(void *stream) +{ + closedir(stream); +} + +int file_create(char *name, int ur, int uw, int ux, int gr, + int gw, int gx, int or, int ow, int ox) +{ + int mode, fd; + + mode = 0; + mode |= ur ? S_IRUSR : 0; + mode |= uw ? S_IWUSR : 0; + mode |= ux ? S_IXUSR : 0; + mode |= gr ? S_IRGRP : 0; + mode |= gw ? S_IWGRP : 0; + mode |= gx ? S_IXGRP : 0; + mode |= or ? S_IROTH : 0; + mode |= ow ? S_IWOTH : 0; + mode |= ox ? S_IXOTH : 0; + fd = open(name, O_CREAT, mode); + if(fd < 0) return(-errno); + close(fd); + return(0); +} + +int set_attr(const char *file, struct hostfs_iattr *attrs) +{ + struct utimbuf buf; + int err, ma; + + if(attrs->ia_valid & HOSTFS_ATTR_MODE){ + if(chmod(file, attrs->ia_mode) != 0) return(-errno); + } + if(attrs->ia_valid & HOSTFS_ATTR_UID){ + if(chown(file, attrs->ia_uid, -1)) return(-errno); + } + if(attrs->ia_valid & HOSTFS_ATTR_GID){ + if(chown(file, -1, attrs->ia_gid)) return(-errno); + } + if(attrs->ia_valid & HOSTFS_ATTR_SIZE){ + if(truncate(file, attrs->ia_size)) return(-errno); + } + ma = HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET; + if((attrs->ia_valid & ma) == ma){ + buf.actime = attrs->ia_atime; + buf.modtime = attrs->ia_mtime; + if(utime(file, &buf) != 0) return(-errno); + } + else { + if(attrs->ia_valid & HOSTFS_ATTR_ATIME_SET){ + err = stat_file(file, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, &buf.modtime, NULL, + NULL, NULL); + if(err != 0) return(err); + buf.actime = attrs->ia_atime; + if(utime(file, &buf) != 0) return(-errno); + } + if(attrs->ia_valid & HOSTFS_ATTR_MTIME_SET){ + err = stat_file(file, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, &buf.actime, NULL, NULL, + NULL, NULL); + if(err != 0) return(err); + buf.modtime = attrs->ia_mtime; + if(utime(file, &buf) != 0) return(-errno); + } + } + if(attrs->ia_valid & HOSTFS_ATTR_CTIME) ; + if(attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)){ + err = stat_file(file, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, &attrs->ia_atime, &attrs->ia_mtime, + NULL, NULL, NULL); + if(err != 0) return(err); + } + return(0); +} + +int make_symlink(const char *from, const char *to) +{ + int err; + + err = symlink(to, from); + if(err) return(-errno); + return(0); +} + +int unlink_file(const char *file) +{ + int err; + + err = unlink(file); + if(err) return(-errno); + return(0); +} + +int do_mkdir(const char *file, int mode) +{ + int err; + + err = mkdir(file, mode); + if(err) return(-errno); + return(0); +} + +int do_rmdir(const char *file) +{ + int err; + + err = rmdir(file); + if(err) return(-errno); + return(0); +} + +int link_file(const char *to, const char *from) +{ + int err; + + err = link(to, from); + if(err) return(-errno); + return(0); +} + +int do_readlink(char *file, char *buf, int size) +{ + int err; + + err = readlink(file, buf, size); + if(err < 0) return(-errno); + if(err < size) buf[err] = '\0'; + return(0); +} + +int rename_file(char *from, char *to) +{ + int err; + + err = rename(from, to); + if(err < 0) return(-errno); + return(0); +} + +int do_statfs(char *root, long *bsize_out, long *blocks_out, long *bfree_out, + long *bavail_out, long *files_out, long *ffree_out, + void *fsid_out, int fsid_size, long *namelen_out, + long *spare_out) +{ + struct statfs buf; + int err; + + err = statfs(root, &buf); + if(err < 0) return(-errno); + *bsize_out = buf.f_bsize; + *blocks_out = buf.f_blocks; + *bfree_out = buf.f_bfree; + *bavail_out = buf.f_bavail; + *files_out = buf.f_files; + *ffree_out = buf.f_ffree; + memcpy(fsid_out, &buf.f_fsid, + sizeof(buf.f_fsid) > fsid_size ? fsid_size : + sizeof(buf.f_fsid)); + *namelen_out = buf.f_namelen; + spare_out[0] = buf.f_spare[0]; + spare_out[1] = buf.f_spare[1]; + spare_out[2] = buf.f_spare[2]; + spare_out[3] = buf.f_spare[3]; + spare_out[4] = buf.f_spare[4]; + spare_out[5] = buf.f_spare[5]; + return(0); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/include/chan.h linux.ac/arch/um/include/chan.h --- linux.vanilla/arch/um/include/chan.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/include/chan.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __TTY_H__ +#define __TTY_H__ + +struct chan { + enum { XTERM, PTY, SOCKET, FD, TTY, PTS, FILE_CHAN, COPY } type; + int fd; + int hung_up; + int opened; + int init_pri; + union { + struct { + int pid; + int line; + char *title; + int raw; + } xterm; + struct { + void (*announce)(char *dev_name, int dev); + int dev; + int raw; + } pty, pts; + struct { + char *dev; + int raw; + void *tty_state; + } tty; + struct { + int port; + int connected; + int pty; + } sock; + } data; +}; + +struct io_chan { + struct chan in; + struct chan out; +}; + +#define INIT_STATIC (0) +#define INIT_ALL (1) +#define INIT_ONE (2) + +#define PTY_CHAN_INIT(announce, dev, raw, pri) \ + { PTY, -1, 1, 0, pri, { pty: { announce, dev, raw } } } + +#define PTS_CHAN_INIT(announce, dev, raw, pri) \ + { PTS, -1, 0, 0, pri, { pts: { announce, dev, raw } } } + +#define XTERM_CHAN_INIT(n, title, raw, pri) \ + { XTERM, -1, 0, 0, pri, { xterm: { -1, n, title, raw } } } + +#define TTY_CHAN_INIT(dev, raw, pri) \ + { TTY, -1, 0, 0, pri, { tty: { dev, raw } } } + +#define SOCK_CHAN_INIT(port, pri) \ + { SOCKET, -1, 0, 0, pri, { sock: { port, 0, -1 } } } + +#define FD_CHAN_INIT(fd, pri) { FD, fd, 0, 0, pri } + +#define COPY_CHAN_INIT() { COPY } + +#define PTY_IO_CHAN_INIT(announce, data, raw, pri) \ + { PTY_CHAN_INIT(announce, data, raw, pri), COPY_CHAN_INIT() } + +#define PTS_IO_CHAN_INIT(announce, data, raw, pri) \ + { PTS_CHAN_INIT(announce, data, raw, pri), COPY_CHAN_INIT() } + +#define XTERM_IO_CHAN_INIT(n, title, raw, pri) \ + { XTERM_CHAN_INIT(n, title, raw, pri), COPY_CHAN_INIT() } + +#define STDIO_IO_CHAN_INIT(pri) \ + { { FD, 0, 0, 0, pri, { } }, { FD, 1, 0, 0, pri, { } } } + +#define TTY_IO_CHAN_INIT(dev, raw, pri) \ + { TTY_CHAN_INIT(dev, raw, pri), COPY_CHAN_INIT() } + +#define SOCK_IO_CHAN_INIT(port, pri) \ + { SOCK_CHAN_INIT(port, pri), COPY_CHAN_INIT() } + +#define FD_IO_CHAN_INIT(in, out, pri) \ + { FD_CHAN_INIT(in, pri), FD_CHAN_INIT(out, pri) } + +#define CHAN_IN_FD(chan) ((chan).in.fd) +#define CHAN_OUT_FD(chan) (((chan).out.type == COPY) ? ((chan).in.fd) : \ + ((chan).out.fd)) + +struct chan_opts { + void (*announce)(char *dev_name, int dev); + int dev; + char *xterm_title; + int raw_pty; +}; + +extern int tty_read(struct chan *chan, void *tty); +extern void tty_eof(void *tty_ptr, int *hung_up); +extern void tty_interrupt(struct io_chan *chan, void *tty_ptr, int count); +extern void tty_receive_char(void *tty_ptr, char ch); +extern int open_chan_pair(struct io_chan *chan, + int (*irq_setup)(int fd, void *data), void *data); +extern int open_fd(struct chan *chan); +extern int open_xterm(struct chan *chan); +extern int open_pty(struct chan *chan); +extern int open_tty(struct chan *chan); +extern int open_pts(struct chan *chan); +extern int open_socket(struct chan *chan); +extern int write_chan(struct io_chan *chan, const char *buf, int len); +extern int parse_chan_pair(char *str, int device, struct io_chan *chan, + int pri, struct chan_opts *opts); +extern void accept_connection(struct chan *chan); +extern void close_chan_pair(struct io_chan *chan); + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/include/debug.h linux.ac/arch/um/include/debug.h --- linux.vanilla/arch/um/include/debug.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/include/debug.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,9 @@ +#ifndef __DEBUG_H +#define __DEBUG_H + +extern void debugger_proxy(int status, pid_t pid); +extern void child_proxy(pid_t pid, int status); +extern void init_proxy (pid_t, int, int); +extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd); + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/include/kern.h linux.ac/arch/um/include/kern.h --- linux.vanilla/arch/um/include/kern.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/include/kern.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __KERN_H__ +#define __KERN_H__ + +/* These are all user-mode things which are convenient to call directly + * from kernel code and for which writing a wrapper is too much of a pain. + * The regular include files can't be included because this file is included + * only into kernel code, and user-space includes conflict with kernel + * includes. + */ + +extern int errno; + +extern int getpid(void); +extern int clone(int (*proc)(void *), void *sp, int flags, void *data); +extern int sleep(int); +extern int printf(char *fmt, ...); +extern char *strerror(int errnum); +extern char *ptsname(int __fd); +extern int munmap(void *, int); +extern void *sbrk(int increment); +extern void *malloc(int size); +extern void perror(char *err); +extern int kill(int pid, int sig); +extern int getuid(void); + +#endif __KERN_H__ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/include/kern_util.h linux.ac/arch/um/include/kern_util.h --- linux.vanilla/arch/um/include/kern_util.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/include/kern_util.h Sun Apr 15 22:56:45 2001 @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __KERN_UTIL_H__ +#define __KERN_UTIL_H__ + +#include "sysdep/ptrace.h" + +#define x(s) #s +#define xx(s) x(s) + +#ifndef _UNISTD_H +extern int write(int, const char *, int); +#endif + +extern int ncpus; +extern char *linux_prog; +extern char *gdb_init; + +typedef long syscall_handler_t(struct sys_pt_regs regs); +extern syscall_handler_t *sys_call_table[]; + +extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg); +extern unsigned long stack_sp(unsigned long page); +extern int kernel_thread_proc(void *data); +extern long execute_syscall(struct sys_pt_regs regs); +extern void syscall_segv(int sig); +extern int current_pid(void); +extern void do_bh(void); +extern void set_init_pid(int pid); +extern unsigned long alloc_stack(void); +extern int do_signal(void *t, unsigned long *error, int *again_out); +extern int is_stack_fault(unsigned long sp); +extern unsigned long segv(unsigned long address, unsigned long ip, + int is_write, int is_user); +extern int set_user_thread(void *task, int on, int restore_regs); +extern void syscall_ready(void); +extern void set_tracing(void *t, int tracing); +extern int is_tracing(void *task); +extern int segv_syscall(void); +extern void ret_from_sys_call(void *t); +extern void add_perm_vma(unsigned long start, unsigned long end, char rperm, + char wperm, char xperm, char private); +extern void kern_finish_exec(void *task, int new_pid, unsigned long stack); +extern int page_size(void); +extern int page_mask(void); +extern int need_finish_fork(void); +extern int do_proc_op(void *t, int proc_id); +extern void free_stack(unsigned long stack); +extern void add_input_request(int op, void (*proc)(int), void *arg); +extern char *current_comm(void); +extern int sys_execve(char *file, char **argv, char **env); +extern void *current_sigstack(void *t); +extern char *current_cmd(void); +extern void timer_handler(int sig, void *sc, int usermode); +extern int set_signals(int enable); +extern void force_sigbus(void); +extern int pid_to_processor_id(int pid); +extern void block_signals(void); +extern void unblock_signals(void); +extern void deliver_signals(void *t); +extern void lock_syscall(void); +extern void unlock_syscall(void); +extern void lock_trap(void); +extern void unlock_trap(void); +extern void lock_pid(void); +extern void unlock_pid(void); +extern int cpu_idle(void); +extern void finish_fork(void); +extern void *get_current_task(void); +extern void paging_init(void); +extern unsigned long um_virt_to_phys(void *t, unsigned long addr); +extern void init_flush_vm(void); +extern void *process_state(void *t, unsigned long *cr2_out, int *err_out); +extern struct sys_pt_regs *syscall_state(void *t, void **stack_out, + int *size_out); +extern int have_signals(void *t, int altstack); +extern void syscall_trace(void); +extern void save_altstack(void *t, unsigned long sp); +extern struct sys_pt_regs *altstack_state(void *t, void **stack_out, + int *size_out); +extern int hz(void); +extern int switching_modes(void *t); +extern void idle_timer(void); +extern unsigned int do_IRQ(int irq, int user_mode); +extern int external_pid(void *t); +extern void boot_timer_handler(int sig); +extern void interrupt_end(void); +extern void tracing_reboot(void); +extern void tracing_halt(void); +extern void tracing_cb(void (*proc)(void *), void *arg); +extern void probe_stack(unsigned long sp); +extern void debugger_signal(int status, int pid); +extern void child_signal(int pid, int status); +extern int init_ptrace_proxy(int idle_pid, int startup, int stop); +extern void add_process_vmas(void); +extern void check_stack_overflow(void *ptr); +extern void relay_signal(int sig, void *sc, int usermode); +extern int singlestepping(void *t); +extern void not_implemented(void); +extern void setup_kernel_stack(void); +extern void set_syscall_regs(void *t); +extern void finish_fork_handler(int sig); +extern int user_context(unsigned long sp); +extern void timer_irq(int user_mode); +extern void signal_deliverer(void); +extern void set_repeat_syscall(int again); +extern int get_repeat_syscall(void *t); +extern void set_sigreturn_syscall(int syscall); +extern void force_flush_all(void); +extern void unprotect_stack(unsigned long stack); +extern void kern_start_exec(int new_pid); +extern void do_exitcalls(void); +extern int get_restore_regs(void *t); +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/include/sysdep-i386/ptrace.h linux.ac/arch/um/include/sysdep-i386/ptrace.h --- linux.vanilla/arch/um/include/sysdep-i386/ptrace.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/include/sysdep-i386/ptrace.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SYSDEP_I386_PTRACE_H +#define __SYSDEP_I386_PTRACE_H + +struct sys_pt_regs { + unsigned long regs[17]; +}; + +#define EMPTY_REGS { { [ 0 ... 16 ] = 0 } } + +#define UM_REG(r, n) ((r)->regs[n]) + +#define UM_IP(r) UM_REG(r, EIP) +#define UM_SP(r) UM_REG(r, UESP) +#define UM_ELF_ZERO(r) UM_REG(r, EDX) + +#define UM_SYSCALL_RET(r) UM_REG(r, EAX) +#define UM_SYSCALL_NR(r) UM_REG(r, ORIG_EAX) +#define UM_SYSCALL_ARG1(r) UM_REG(r, EBX) +#define UM_SYSCALL_ARG2(r) UM_REG(r, ECX) +#define UM_SYSCALL_ARG3(r) UM_REG(r, EDX) +#define UM_SYSCALL_ARG4(r) UM_REG(r, ESI) +#define UM_SYSCALL_ARG5(r) UM_REG(r, EDI) +#define UM_SYSCALL_ARG6(r) UM_REG(r, EBP) + +#define UM_SYSCALL_NR_OFFSET (ORIG_EAX * sizeof(long)) +#define UM_SP_OFFSET (UESP * sizeof(long)) +#define UM_IP_OFFSET (EIP * sizeof(long)) +#define UM_ELF_ZERO_OFFSET (EDX * sizeof(long)) + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/include/sysdep-i386/sigcontext.h linux.ac/arch/um/include/sysdep-i386/sigcontext.h --- linux.vanilla/arch/um/include/sysdep-i386/sigcontext.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/include/sysdep-i386/sigcontext.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SYS_SIGCONTEXT_I386_H +#define __SYS_SIGCONTEXT_I386_H + +#define SC_FAULT_ADDR(sc) ((sc)->cr2) +#define SC_FAULT_WRITE(sc) (((sc)->err) & 2) + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/include/sysdep-i386/syscalls.h linux.ac/arch/um/include/sysdep-i386/syscalls.h --- linux.vanilla/arch/um/include/sysdep-i386/syscalls.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/include/sysdep-i386/syscalls.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "asm/unistd.h" +#include "kern_util.h" + +extern syscall_handler_t sys_modify_ldt; + +#define ARCH_SYSCALLS \ + [ __NR_vm86old ] = sys_ni_syscall, \ + [ __NR_modify_ldt ] = sys_modify_ldt, \ + [ __NR_lchown32 ] = sys_lchown, \ + [ __NR_getuid32 ] = sys_getuid, \ + [ __NR_getgid32 ] = sys_getgid, \ + [ __NR_geteuid32 ] = sys_geteuid, \ + [ __NR_getegid32 ] = sys_getegid, \ + [ __NR_setreuid32 ] = sys_setreuid, \ + [ __NR_setregid32 ] = sys_setregid, \ + [ __NR_getgroups32 ] = sys_getgroups, \ + [ __NR_setgroups32 ] = sys_setgroups, \ + [ __NR_fchown32 ] = sys_fchown, \ + [ __NR_setresuid32 ] = sys_setresuid, \ + [ __NR_getresuid32 ] = sys_getresuid, \ + [ __NR_setresgid32 ] = sys_setresgid, \ + [ __NR_getresgid32 ] = sys_getresgid, \ + [ __NR_chown32 ] = sys_chown, \ + [ __NR_setuid32 ] = sys_setuid, \ + [ __NR_setgid32 ] = sys_setgid, \ + [ __NR_setfsuid32 ] = sys_setfsuid, \ + [ __NR_setfsgid32 ] = sys_setfsgid, \ + [ __NR_pivot_root ] = sys_pivot_root, \ + [ __NR_mincore ] = sys_mincore, \ + [ __NR_madvise ] = sys_madvise + +#define LAST_SYSCALL __NR_madvise + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/include/sysdep-ia64/ptrace.h linux.ac/arch/um/include/sysdep-ia64/ptrace.h --- linux.vanilla/arch/um/include/sysdep-ia64/ptrace.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/include/sysdep-ia64/ptrace.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SYSDEP_IA64_PTRACE_H +#define __SYSDEP_IA64_PTRACE_H + +struct sys_pt_regs { + int foo; +}; + +#define EMPTY_REGS { 0 } + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/include/sysdep-ia64/sigcontext.h linux.ac/arch/um/include/sysdep-ia64/sigcontext.h --- linux.vanilla/arch/um/include/sysdep-ia64/sigcontext.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/include/sysdep-ia64/sigcontext.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SYSDEP_IA64_SIGCONTEXT_H +#define __SYSDEP_IA64_SIGCONTEXT_H + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/include/sysdep-ia64/syscalls.h linux.ac/arch/um/include/sysdep-ia64/syscalls.h --- linux.vanilla/arch/um/include/sysdep-ia64/syscalls.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/include/sysdep-ia64/syscalls.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SYSDEP_IA64_SYSCALLS_H +#define __SYSDEP_IA64_SYSCALLS_H + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/include/sysdep-ppc/ptrace.h linux.ac/arch/um/include/sysdep-ppc/ptrace.h --- linux.vanilla/arch/um/include/sysdep-ppc/ptrace.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/include/sysdep-ppc/ptrace.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,67 @@ +/* + * Licensed under the GPL + */ + +#ifndef __SYS_PTRACE_PPC_H +#define __SYS_PTRACE_PPC_H + +/* the following taken from <asm-ppc/ptrace.h> */ + +#ifdef CONFIG_PPC64 +#define PPC_REG unsigned long /*long*/ +#else +#define PPC_REG unsigned long +#endif +struct sys_pt_regs_s { + PPC_REG gpr[32]; + PPC_REG nip; + PPC_REG msr; + PPC_REG orig_gpr3; /* Used for restarting system calls */ + PPC_REG ctr; + PPC_REG link; + PPC_REG xer; + PPC_REG ccr; + PPC_REG mq; /* 601 only (not used at present) */ + /* Used on APUS to hold IPL value. */ + PPC_REG trap; /* Reason for being here */ + PPC_REG dar; /* Fault registers */ + PPC_REG dsisr; + PPC_REG result; /* Result of a system call */ +}; + +struct sys_pt_regs { + union { + struct sys_pt_regs_s s; + PPC_REG regs[sizeof(struct sys_pt_regs_s) / sizeof(PPC_REG)]; + } u; +}; + +#define EMPTY_REGS { { { { [ 0 ... 31 ] = 0 }, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } } + +#define UM_SYSCALL_RET(r) ((r)->u.s.gpr[3]) +#define UM_SP(r) ((r)->u.s.gpr[1]) +#define UM_SYSCALL_NR(r) ((r)->u.s.gpr[3]) +#define UM_SYSCALL_ARG1(r) ((r)->u.s.gpr[4]) +#define UM_SYSCALL_ARG2(r) ((r)->u.s.gpr[5]) +#define UM_SYSCALL_ARG3(r) ((r)->u.s.gpr[7]) +#define UM_SYSCALL_ARG4(r) ((r)->u.s.gpr[8]) +#define UM_SYSCALL_ARG5(r) ((r)->u.s.gpr[9]) +#define UM_SYSCALL_ARG6(r) ((r)->u.s.gpr[10]) + +#define UM_SYSCALL_NR_OFFSET (PT_R3 * sizeof(PPC_REG)) +#define UM_SP_OFFSET (PT_R1 * sizeof(PPC_REG)) +#define UM_IP_OFFSET (PT_NIP * sizeof(PPC_REG)) + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/include/ubd_user.h linux.ac/arch/um/include/ubd_user.h --- linux.vanilla/arch/um/include/ubd_user.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/include/ubd_user.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __UM_UBD_USER_H +#define __UM_UBD_USER_H + +#include "asm/types.h" + +struct io_thread_req { + int read; + int fd; + __u64 offset; + unsigned long length; + char *buffer; + void *req; +}; + +extern int open_ubd_fs(char *file, int *openflags); +extern int read_ubd_fs(int fd, void *buffer, int len); +extern int write_ubd_fs(int fd, char *buffer, int len); +extern int start_io_thread(unsigned long sp, int *fds_out); +extern int do_io(struct io_thread_req *req); +extern int ubd_is_dir(char *file); + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/include/umn.h linux.ac/arch/um/include/umn.h --- linux.vanilla/arch/um/include/umn.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/include/umn.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __UMN_H +#define __UMN_H + +extern int open_umn_tty(int *slave_out, int *slipno_out); +extern void close_umn_tty(int master, int slave); +extern int umn_send_packet(int fd, void *data, int len); +extern int set_umn_addr(int fd, char *addr, char *ptp_addr); +extern void slip_unesc(unsigned char s); +extern void umn_read(int fd); + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/include/user.h linux.ac/arch/um/include/user.h --- linux.vanilla/arch/um/include/user.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/include/user.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __USER_H__ +#define __USER_H__ + +extern void panic(char *fmt, ...); +extern int printk(char *fmt, ...); +extern void schedule(void); +extern void *kmalloc(int size, int flags); +extern void kfree(void *ptr); + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/include/user_util.h linux.ac/arch/um/include/user_util.h --- linux.vanilla/arch/um/include/user_util.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/include/user_util.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __USER_UTIL_H__ +#define __USER_UTIL_H__ + +#include "asm/types.h" +#include "sysdep/ptrace.h" + +extern int grantpt(int __fd); +extern int unlockpt(int __fd); +extern char *ptsname(int __fd); + +#ifndef _UNISTD_H +extern int write(int, const char *, int); +#endif + +#define y(s) #s +#define yy(s) y(s) + +enum { OP_NONE, OP_EXEC, OP_SWITCH, OP_THREAD, OP_FORK, OP_FORK_FINISH, + OP_TRACE_ON, OP_TRACE_OFF, OP_REBOOT, OP_HALT, OP_CB }; + +struct cpu_task { + int pid; + void *task; +}; + +extern struct cpu_task cpu_tasks[]; + +extern int physmem_fd; +extern int brk_fd; + +extern unsigned long low_physmem; +extern unsigned long high_physmem; +extern unsigned long physmem; +extern unsigned long end_vm; +extern unsigned long start_vm; + +extern void *last_brk; +extern void *brk_start; + +extern int physmem_inode; + +extern int tracing_pid; + +extern char host_info[]; + +extern char saved_command_line[]; +extern char command_line[]; + +extern void *open_maps(void); +extern int read_map(void *fd, unsigned long *start_out, + unsigned long *end_out, char *r_out, char *w_out, + char *x_out, char *p_out); +extern void close_maps(void *fd); +extern unsigned long get_brk(void); +extern __u64 file_size(char *file); +extern void stop(void); +extern int proc_start_thread(unsigned long ip, unsigned long sp); +extern void stack_protections(unsigned long address, int len); +extern void abandon_proc_space(int (*proc)(void *), unsigned long sp); +extern int signals(int (*init_proc)(void *), void *sp); +extern unsigned long setup_memory(unsigned long total_size, + unsigned long physmem_size, int *fd_out, + int *inode_out); +extern void map(unsigned long virt, void *p, unsigned long len, + int r, int w, int x); +extern int unmap(unsigned long address, unsigned long len); +extern void protect(unsigned long addr, unsigned long len, int r, int w, + int x); +extern void stop_pid(int pid); +extern void kill_pid(int pid); +extern void trap_pid(int pid); +extern void usr1_pid(int pid); +extern void cont_pid(int pid); +extern int __personality(int); +extern void signal_handler(void *task, unsigned long handler, int sig); +extern int syscall_handler(void *unused); +extern int do_syscall(void *task, int pid); +extern int wait_for_stop(int pid, int sig, int cont_type); +extern void *add_signal_handler(int sig, void (*handler)(int)); +extern void signal_init(void); +extern void finish_exec(int old_pid, int new_pid, struct sys_pt_regs *regs); +extern int start_fork_tramp(unsigned long sig_stack, unsigned long temp_stack, + int clone_vm, int (*tramp)(void *)); +extern void trace_myself(void); +extern void block_shlib_mem(void); +extern void unblock_shlib_mem(void); +extern void get_profile_timer(void); +extern void set_timers(int set_signal); +extern int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags); +extern int input_loop(void); +extern void usr1_and_wait(int pid); +extern void set_handler(int sig, void (*handler)(int), int flags, ...); +extern void set_sigstack(void *stack); +extern void (*set_signal_handler(int sig, void (*new_handler)(int)))(int); +extern void continue_execing_proc(int pid); +extern int linux_main(int argc, char **argv); +extern void remap_data(void *segment_start, void *segment_end); +extern void set_cmdline(char *cmd); +extern void continue_fork(void *task, int pid, struct sys_pt_regs *regs); +extern void input_cb(void (*proc)(void *), void *arg, int arg_len); +extern void setup_input(void); +extern int exit_kernel(int pid, void *task, int *signal_out); +extern int alt_stack_handler(void *arg); +extern int setup_altstack(unsigned long stack, int stack_size); +extern void process_stack_handler(int sig); +extern int get_pty(void); +extern void save_signal_state(int *sig_ptr); +extern void change_sig(int signal, int on); +extern void fill_in_regs(struct sys_pt_regs *regs, void *sc); +extern void fill_in_sigcontext(void *sc, struct sys_pt_regs *regs, + unsigned long cr2, int err); +extern int activate_fd(int irq, int fd, void *dev_id); +extern void reactivate_fd(int fd); +extern void free_irq_fd(void *dev_id); +extern void forward_interrupts(int pid); +extern void init_irq_signals(int on_sigstack); +extern void *um_kmalloc(int size); +extern int raw(int fd, int complain); +extern void cooked(int fd); +extern int switcheroo(int fd, int prot, void *from, void *to, int size); +extern int create_vm_file(unsigned long len); +extern void *update_brk(void); +extern void check_brk(void *process_brk); +extern void idle_sleep(int secs); +extern int get_one_stack(char **stack_out, struct sys_pt_regs *regs_out); +extern void sig_handler(int sig); +extern void irq_handler(int sig); +extern void setup_machinename(char *machine_out); +extern void setup_hostinfo(void); +extern void add_arg(char *cmd_line, char *arg); +extern void sigio_handler(int sig, void *sc, int usermode); +extern void init_new_thread(void *sig_stack, void (*usr1_handler)(int)); +extern void start_exec(int old_pid, int new_pid, int *error, + struct sys_pt_regs *regs); +extern void attach_process(int pid); +extern void calc_sigframe_size(void); +extern int fork_tramp(void *sig_stack); +extern void do_exec(int old_pid, int new_pid); +extern void tracer_panic(char *msg, ...); +extern void close_fd(int); +extern char *get_umid(void); +extern void ptrace_cont_pid(int pid); +extern void create_pid_file(char *name); +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/Makefile linux.ac/arch/um/kernel/Makefile --- linux.vanilla/arch/um/kernel/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/Makefile Mon Apr 9 23:25:02 2001 @@ -0,0 +1,73 @@ +OBJ = um.o + +OBJS = process.o current.o exec_kern.o exec_user.o init_task.o irq.o \ + irq_user.o mem.o ptrace.o reboot.o resource.o \ + segment.o setup.o signal_user.o smp.o syscall_kern.o \ + syscall_user.o sys_call_table.o time.o time_kern.o tlb.o trap_kern.o \ + trap_user.o um_arch.o user_util.o + +OX_OBJS = ksyms.o process_kern.o signal_kern.o user_syms.o + +EXTRA_CFLAGS += -I../include + +USER_CFLAGS := $(patsubst -I%,,$(CFLAGS)) +USER_CFLAGS += -I../include + +UNMAP_CFLAGS := $(patsubst -pg,,$(USER_CFLAGS)) + +ifeq ($(CONFIG_MODULES), y) + DMODULES = -DCONFIG_MODULES +endif + +ifeq ($(CONFIG_MODVERSIONS), y) + DMODVERSIONS = -DCONFIG_MODVERSIONS +endif + +CFLAGS_user_syms.o = -DAUTOCONF_INCLUDED $(DMODULES) $(DMODVERSIONS) -I- \ + -I../include + +all: $(OBJ) unmap_fin.o + +exec_user.o: exec_user.c + $(CC) -D__KERNEL__ $(USER_CFLAGS) -c -o $@ $< + +process.o: process.c + $(CC) -D__KERNEL__ $(USER_CFLAGS) -c -o $@ $< + +syscall_user.o: syscall_user.c + $(CC) -D__KERNEL__ $(USER_CFLAGS) -c -o $@ $< + +trap_user.o: trap_user.c + $(CC) -D__KERNEL__ $(USER_CFLAGS) -c -o $@ $< + +signal_user.o: signal_user.c + $(CC) -D__KERNEL__ $(USER_CFLAGS) -c -o $@ $< + +time.o: time.c + $(CC) -D__KERNEL__ $(USER_CFLAGS) -c -o $@ $< + +user_util.o: user_util.c + $(CC) -D__KERNEL__ $(USER_CFLAGS) -c -o $@ $< + +irq_user.o: irq_user.c + $(CC) -D__KERNEL__ $(USER_CFLAGS) -c -o $@ $< + +unmap.o: unmap.c + echo $(UNMAP_CFLAGS) + $(CC) -D__KERNEL__ $(UNMAP_CFLAGS) -c -o $@ $< + +unmap_fin.o : unmap.o + ld -r -o $@ $< -lc -L/usr/lib + +$(OBJ): $(OBJS) $(OX_OBJS) + rm -f $@ + $(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@ + +clean: + rm -f $(OBJS) $(OX_OBJS) + +modules: + +fastdep: + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/current.c linux.ac/arch/um/kernel/current.c --- linux.vanilla/arch/um/kernel/current.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/current.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/sched.h" + +#ifndef __SMP__ + +struct task_struct *current_task; + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/exec_kern.c linux.ac/arch/um/kernel/exec_kern.c --- linux.vanilla/arch/um/kernel/exec_kern.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/exec_kern.c Sun Apr 15 22:56:45 2001 @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/malloc.h" +#include "linux/smp_lock.h" +#include "asm/ptrace.h" +#include "asm/pgtable.h" +#include "asm/pgalloc.h" +#include "user_util.h" +#include "kern_util.h" +#include "kern.h" + +extern struct mm_struct kernel_maps; + +static void add_kernel_vma(struct task_struct *task) +{ + struct vm_area_struct *vma, *new; + + if(task->mm != init_task.mm){ + for(vma = kernel_maps.mmap;vma != NULL;vma = vma->vm_next){ + new = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if(!new) panic("No memory in add_kernel_vma"); + *new = *vma; + new->vm_next = NULL; + new->vm_flags |= VM_LOCKED; + new->vm_avl_height = 0; + new->vm_avl_left = NULL; + new->vm_avl_right = NULL; + new->vm_next_share = NULL; + new->vm_pprev_share = NULL; + if(new->vm_file != NULL) + atomic_inc(&new->vm_file->f_count); + insert_vm_struct(task->mm, new); + } + } +} + +static void check_vma(unsigned long addr) +{ + struct vm_area_struct *vma; + + vma = find_vma(current->mm, addr); + if((vma == NULL) || (vma->vm_start > addr)) force_sigbus(); +} + +static int exec_tramp(void *sig_stack) +{ + block_signals(); + init_new_thread(sig_stack, NULL); + kill(getpid(), SIGSTOP); + return(0); +} + +void flush_thread(void) +{ + unsigned long stack; + int new_pid; + + stack = alloc_stack(); + new_pid = start_fork_tramp(current->thread.kernel_stack, + stack, 0, exec_tramp); + if(new_pid < 0) do_exit(SIGKILL); + forward_interrupts(new_pid); + current->thread.request.op = OP_EXEC; + current->thread.request.u.exec.pid = new_pid; + unprotect_stack((unsigned long) current); + usr1_pid(getpid()); + + current->thread.extern_pid = new_pid; + free_page(stack); + protect(physmem, high_physmem - physmem, 1, 1, 0); + stack = (unsigned long) current; + protect(stack + PAGE_SIZE, PAGE_SIZE, 0, 0, 0); + stack_protections(stack + 2 * PAGE_SIZE, 2 * PAGE_SIZE); + force_flush_all(); + check_brk(brk_start); + current->thread.starting_exec = 1; + current->thread.mm_changes = 0; + unblock_signals(); +} + +void start_thread(struct pt_regs * regs, unsigned long eip, unsigned long esp) +{ + check_vma(current->mm->brk - 1); + check_vma(eip); + current->addr_limit.seg = STACK_TOP; + current->thread.starting_exec = 0; + add_kernel_vma(current); + flush_tlb_mm(current->mm); + if(UM_SP(¤t->thread.process_regs) == 0) + current->thread.process_regs = current->thread.syscall_regs; + UM_IP(¤t->thread.process_regs) = eip; + UM_SP(¤t->thread.process_regs) = esp; + UM_ELF_ZERO(¤t->thread.process_regs) = 0; +} + +static int execve1(char *file, char **argv, char **env) +{ + int error; + + error = do_execve(file, argv, env, NULL); + if (error == 0){ + current->ptrace &= ~PT_DTRACE; + set_cmdline(current_cmd()); + } + return(error); +} + +int um_execve(char *file, char **argv, char **env) +{ + if(execve1(file, argv, env) == 0) set_user_thread(current, 1, 1); + return(-1); +} + +int sys_execve(char *file, char **argv, char **env) +{ + int error; + char *filename; + + lock_kernel(); + filename = getname((char *) file); + error = PTR_ERR(filename); + if (IS_ERR(filename)) goto out; + error = execve1(filename, argv, env); + putname(filename); + out: + unlock_kernel(); + return(error); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/exec_user.c linux.ac/arch/um/kernel/exec_user.c --- linux.vanilla/arch/um/kernel/exec_user.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/exec_user.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <sched.h> +#include <sys/wait.h> +#include <sys/ptrace.h> +#include <asm/ptrace.h> +#include <signal.h> +#include "user_util.h" +#include "kern_util.h" +#include "user.h" + +void do_exec(int old_pid, int new_pid) +{ + struct sys_pt_regs regs; + + if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) || + (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0) || + (waitpid(new_pid, 0, WUNTRACED) < 0)) + tracer_panic("do_exec failed to attach proc"); + + if(ptrace(PTRACE_GETREGS, old_pid, 0, ®s) < 0) + tracer_panic("do_exec failed to get registers"); + + kill(old_pid, SIGKILL); + + if((ptrace(PTRACE_SETREGS, new_pid, 0, ®s) < 0) || + (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0)) + tracer_panic("do_exec failed to start new proc"); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/init_task.c linux.ac/arch/um/kernel/init_task.c --- linux.vanilla/arch/um/kernel/init_task.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/init_task.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/mm.h" +#include "linux/sched.h" +#include "asm/uaccess.h" +#include "asm/pgtable.h" +#include "user_util.h" + +static struct vm_area_struct init_mmap = INIT_MMAP; +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS; +struct mm_struct init_mm = INIT_MM(init_mm); + +/* + * Initial task structure. + * + * We need to make sure that this is 16384-byte aligned due to the + * way process stacks are handled. This is done by having a special + * "init_task" linker map entry.. + */ + +union task_union init_task_union +__attribute__((__section__(".data.init_task"))) = +{ INIT_TASK(init_task_union.task) }; + +struct task_struct *alloc_task_struct(void){ + struct task_struct *task; + + task = (struct task_struct *) __get_free_pages(GFP_KERNEL,2); + if(task == NULL) return(NULL); + return(task); +} + +void unprotect_stack(unsigned long stack) +{ + protect(stack, 4 * PAGE_SIZE, 1, 1, 0); +} + +void free_task_struct(struct task_struct *task) +{ + free_pages((unsigned long) task, 2); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/irq.c linux.ac/arch/um/kernel/irq.c --- linux.vanilla/arch/um/kernel/irq.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/irq.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,808 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + * Derived (i.e. mostly copied) from arch/i386/kernel/irq.c: + * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar + */ + +#include "linux/kernel.h" +#include "linux/smp.h" +#include "linux/irq.h" +#include "linux/kernel_stat.h" +#include "linux/interrupt.h" +#include "linux/random.h" +#include "linux/slab.h" +#include "linux/file.h" +#include "linux/proc_fs.h" +#include "linux/init.h" +#include "asm/irq.h" +#include "asm/hw_irq.h" +#include "asm/hardirq.h" +#include "asm/atomic.h" +#include "asm/signal.h" +#include "asm/system.h" +#include "asm/errno.h" +#include "asm/uaccess.h" +#include "user_util.h" + +static void register_irq_proc (unsigned int irq); + +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = + { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}}; + +/* + * Generic no controller code + */ + +static void enable_none(unsigned int irq) { } +static unsigned int startup_none(unsigned int irq) { return 0; } +static void disable_none(unsigned int irq) { } +static void ack_none(unsigned int irq) +{ +/* + * 'what should we do if we get a hw irq event on an illegal vector'. + * each architecture has to answer this themselves, it doesnt deserve + * a generic callback i think. + */ +#if CONFIG_X86 + printk("unexpected IRQ trap at vector %02x\n", irq); +#ifdef CONFIG_X86_LOCAL_APIC + /* + * Currently unexpected vectors happen only on SMP and APIC. + * We _must_ ack these because every local APIC has only N + * irq slots per priority level, and a 'hanging, unacked' IRQ + * holds up an irq slot - in excessive cases (when multiple + * unexpected vectors occur) that might lock up the APIC + * completely. + */ + ack_APIC_irq(); +#endif +#endif +} + +/* startup is the same as "enable", shutdown is same as "disable" */ +#define shutdown_none disable_none +#define end_none enable_none + +struct hw_interrupt_type no_irq_type = { + "none", + startup_none, + shutdown_none, + enable_none, + disable_none, + ack_none, + end_none +}; + +volatile unsigned long irq_err_count; + +/* + * Generic, controller-independent functions: + */ + +int get_irq_list(char *buf) +{ + int i, j; + struct irqaction * action; + char *p = buf; + + p += sprintf(p, " "); + for (j=0; j<smp_num_cpus; j++) + p += sprintf(p, "CPU%d ",j); + *p++ = '\n'; + + for (i = 0 ; i < NR_IRQS ; i++) { + action = irq_desc[i].action; + if (!action) + continue; + p += sprintf(p, "%3d: ",i); +#ifndef CONFIG_SMP + p += sprintf(p, "%10u ", kstat_irqs(i)); +#else + for (j = 0; j < smp_num_cpus; j++) + p += sprintf(p, "%10u ", + kstat.irqs[cpu_logical_map(j)][i]); +#endif + p += sprintf(p, " %14s", irq_desc[i].handler->typename); + p += sprintf(p, " %s", action->name); + + for (action=action->next; action; action = action->next) + p += sprintf(p, ", %s", action->name); + *p++ = '\n'; + } + p += sprintf(p, "\n"); +#if CONFIG_SMP + p += sprintf(p, "LOC: "); + for (j = 0; j < smp_num_cpus; j++) + p += sprintf(p, "%10u ", + apic_timer_irqs[cpu_logical_map(j)]); + p += sprintf(p, "\n"); +#endif + p += sprintf(p, "ERR: %10lu\n", irq_err_count); + return p - buf; +} + + +/* + * This should really return information about whether + * we should do bottom half handling etc. Right now we + * end up _always_ checking the bottom half, which is a + * waste of time and is not what some drivers would + * prefer. + */ +int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, + struct irqaction * action) +{ + int status; + int cpu = smp_processor_id(); + + irq_enter(cpu, irq); + + status = 1; /* Force the "do bottom halves" bit */ + + if (!(action->flags & SA_INTERRUPT)) + __sti(); + + do { + status |= action->flags; + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + if (status & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + __cli(); + + irq_exit(cpu, irq); + + return status; +} + +/* + * Generic enable/disable code: this just calls + * down into the PIC-specific version for the actual + * hardware disable after having gotten the irq + * controller lock. + */ + +/** + * disable_irq_nosync - disable an irq without waiting + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Disables of an interrupt + * stack. Unlike disable_irq(), this function does not ensure existing + * instances of the IRQ handler have completed before returning. + * + * This function may be called from IRQ context. + */ + +void inline disable_irq_nosync(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + if (!desc->depth++) { + desc->status |= IRQ_DISABLED; + desc->handler->disable(irq); + } + spin_unlock_irqrestore(&desc->lock, flags); +} + +/** + * disable_irq - disable an irq and wait for completion + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Disables of an interrupt + * stack. That is for two disables you need two enables. This + * function waits for any pending IRQ handlers for this interrupt + * to complete before returning. If you use this function while + * holding a resource the IRQ handler may need you will deadlock. + * + * This function may be called - with care - from IRQ context. + */ + +void disable_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + + if (!local_irq_count(smp_processor_id())) { + do { + barrier(); + } while (irq_desc[irq].status & IRQ_INPROGRESS); + } +} + +/** + * enable_irq - enable interrupt handling on an irq + * @irq: Interrupt to enable + * + * Re-enables the processing of interrupts on this IRQ line + * providing no disable_irq calls are now in effect. + * + * This function may be called from IRQ context. + */ + +void enable_irq(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + switch (desc->depth) { + case 1: { + unsigned int status = desc->status & ~IRQ_DISABLED; + desc->status = status; + if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { + desc->status = status | IRQ_REPLAY; + hw_resend_irq(desc->handler,irq); + } + desc->handler->enable(irq); + /* fall-through */ + } + default: + desc->depth--; + break; + case 0: + printk("enable_irq() unbalanced from %p\n", + __builtin_return_address(0)); + } + spin_unlock_irqrestore(&desc->lock, flags); +} + +/* + * do_IRQ handles all normal device IRQ's (the special + * SMP cross-CPU interrupts have their own specific + * handlers). + */ +unsigned int do_IRQ(int irq, int user_mode) +{ + /* + * 0 return value means that this irq is already being + * handled by some other CPU. (or is disabled) + */ + int cpu = smp_processor_id(); + irq_desc_t *desc = irq_desc + irq; + struct irqaction * action; + struct pt_regs regs; + unsigned int status; + + regs.user_mode = user_mode; + kstat.irqs[cpu][irq]++; + spin_lock(&desc->lock); + desc->handler->ack(irq); + /* + REPLAY is when Linux resends an IRQ that was dropped earlier + WAITING is used by probe to mark irqs that are being tested + */ + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); + status |= IRQ_PENDING; /* we _want_ to handle it */ + + /* + * If the IRQ is disabled for whatever reason, we cannot + * use the action we have. + */ + action = NULL; + if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { + action = desc->action; + status &= ~IRQ_PENDING; /* we commit to handling */ + status |= IRQ_INPROGRESS; /* we are handling it */ + } + desc->status = status; + + /* + * If there is no IRQ handler or it was disabled, exit early. + Since we set PENDING, if another processor is handling + a different instance of this same irq, the other processor + will take care of it. + */ + if (!action) + goto out; + + /* + * Edge triggered interrupts need to remember + * pending events. + * This applies to any hw interrupts that allow a second + * instance of the same irq to arrive while we are in do_IRQ + * or in the handler. But the code here only handles the _second_ + * instance of the irq, not the third or fourth. So it is mostly + * useful for irq hardware that does not mask cleanly in an + * SMP environment. + */ + for (;;) { + spin_unlock(&desc->lock); + handle_IRQ_event(irq, ®s, action); + spin_lock(&desc->lock); + + if (!(desc->status & IRQ_PENDING)) + break; + desc->status &= ~IRQ_PENDING; + } + desc->status &= ~IRQ_INPROGRESS; +out: + /* + * The ->end() handler has to deal with interrupts which got + * disabled while the handler was running. + */ + desc->handler->end(irq); + spin_unlock(&desc->lock); + + if (softirq_active(cpu) & softirq_mask(cpu)) + do_softirq(); + return 1; +} + +/** + * request_irq - allocate an interrupt line + * @irq: Interrupt line to allocate + * @handler: Function to be called when the IRQ occurs + * @irqflags: Interrupt type flags + * @devname: An ascii name for the claiming device + * @dev_id: A cookie passed back to the handler function + * + * This call allocates interrupt resources and enables the + * interrupt line and IRQ handling. From the point this + * call is made your handler function may be invoked. Since + * your handler function must clear any interrupt the board + * raises, you must take care both to initialise your hardware + * and to set up the interrupt handler in the right order. + * + * Dev_id must be globally unique. Normally the address of the + * device data structure is used as the cookie. Since the handler + * receives this value it makes sense to use it. + * + * If your interrupt is shared you must pass a non NULL dev_id + * as this is required when freeing the interrupt. + * + * Flags: + * + * SA_SHIRQ Interrupt is shared + * + * SA_INTERRUPT Disable local interrupts while processing + * + * SA_SAMPLE_RANDOM The interrupt can be used for entropy + * + */ + +int request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char * devname, + void *dev_id) +{ + int retval; + struct irqaction * action; + +#if 1 + /* + * Sanity-check: shared interrupts should REALLY pass in + * a real dev-ID, otherwise we'll have trouble later trying + * to figure out which interrupt is which (messes up the + * interrupt freeing logic etc). + */ + if (irqflags & SA_SHIRQ) { + if (!dev_id) + printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]); + } +#endif + + if (irq >= NR_IRQS) + return -EINVAL; + if (!handler) + return -EINVAL; + + action = (struct irqaction *) + kmalloc(sizeof(struct irqaction), GFP_KERNEL); + if (!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + retval = setup_irq(irq, action); + if (retval) + kfree(action); + return retval; +} + +int um_request_irq(unsigned int irq, int fd, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, const char * devname, + void *dev_id) +{ + int retval; + + retval = request_irq(irq, handler, irqflags, devname, dev_id); + if(retval) return(retval); + return(activate_fd(irq, fd, dev_id)); +} + +/* this was setup_x86_irq but it seems pretty generic */ +int setup_irq(unsigned int irq, struct irqaction * new) +{ + int shared = 0; + unsigned long flags; + struct irqaction *old, **p; + irq_desc_t *desc = irq_desc + irq; + + /* + * 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(&desc->lock,flags); + p = &desc->action; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) { + spin_unlock_irqrestore(&desc->lock,flags); + return -EBUSY; + } + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + *p = new; + + if (!shared) { + desc->depth = 0; + desc->status &= ~IRQ_DISABLED; + desc->handler->startup(irq); + } + spin_unlock_irqrestore(&desc->lock,flags); + + register_irq_proc(irq); + return 0; +} + +/** + * free_irq - free an interrupt + * @irq: Interrupt line to free + * @dev_id: Device identity to free + * + * Remove an interrupt handler. The handler is removed and if the + * interrupt line is no longer in use by any driver it is disabled. + * On a shared IRQ the caller must ensure the interrupt is disabled + * on the card it drives before calling this function. The function + * does not return until any executing interrupts for this IRQ + * have completed. + * + * This function may be called from interrupt context. + * + * Bugs: Attempting to free an irq in a handler for the same irq hangs + * the machine. + */ + +void free_irq(unsigned int irq, void *dev_id) +{ + irq_desc_t *desc; + struct irqaction **p; + unsigned long flags; + + if (irq >= NR_IRQS) + return; + + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; + for (;;) { + struct irqaction * action = *p; + if (action) { + struct irqaction **pp = p; + p = &action->next; + if (action->dev_id != dev_id) + continue; + + /* Found it - now remove it from the list of entries */ + *pp = action->next; + if (!desc->action) { + desc->status |= IRQ_DISABLED; + desc->handler->shutdown(irq); + } + free_irq_fd(dev_id); + spin_unlock_irqrestore(&desc->lock,flags); + +#ifdef CONFIG_SMP + /* Wait to make sure it's not being used on another CPU */ + while (desc->status & IRQ_INPROGRESS) + barrier(); +#endif + kfree(action); + return; + } + printk("Trying to free free IRQ%d\n",irq); + spin_unlock_irqrestore(&desc->lock,flags); + return; + } +} + +static struct proc_dir_entry * root_irq_dir; +static struct proc_dir_entry * irq_dir [NR_IRQS]; +static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; + +static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; + +#define HEX_DIGITS 8 + +static int irq_affinity_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08lx\n", irq_affinity[(long)data]); +} + +static unsigned int parse_hex_value (const char *buffer, + unsigned long count, unsigned long *ret) +{ + unsigned char hexnum [HEX_DIGITS]; + unsigned long value; + int i; + + if (!count) + return -EINVAL; + if (count > HEX_DIGITS) + count = HEX_DIGITS; + if (copy_from_user(hexnum, buffer, count)) + return -EFAULT; + + /* + * Parse the first 8 characters as a hex string, any non-hex char + * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same. + */ + value = 0; + + for (i = 0; i < count; i++) { + unsigned int c = hexnum[i]; + + switch (c) { + case '0' ... '9': c -= '0'; break; + case 'a' ... 'f': c -= 'a'-10; break; + case 'A' ... 'F': c -= 'A'-10; break; + default: + goto out; + } + value = (value << 4) | c; + } +out: + *ret = value; + return 0; +} + +static int irq_affinity_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int irq = (long) data, full_count = count, err; + unsigned long new_value; + + if (!irq_desc[irq].handler->set_affinity) + return -EIO; + + err = parse_hex_value(buffer, count, &new_value); + +#if CONFIG_SMP + /* + * Do not allow disabling IRQs completely - it's a too easy + * way to make the system unusable accidentally :-) At least + * one online CPU still has to be targeted. + */ + if (!(new_value & cpu_online_map)) + return -EINVAL; +#endif + + irq_affinity[irq] = new_value; + irq_desc[irq].handler->set_affinity(irq, new_value); + + return full_count; +} + +static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + unsigned long *mask = (unsigned long *) data; + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08lx\n", *mask); +} + +static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + unsigned long *mask = (unsigned long *) data, full_count = count, err; + unsigned long new_value; + + err = parse_hex_value(buffer, count, &new_value); + if (err) + return err; + + *mask = new_value; + return full_count; +} + +#define MAX_NAMELEN 10 + +static void register_irq_proc (unsigned int irq) +{ + struct proc_dir_entry *entry; + char name [MAX_NAMELEN]; + + if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) || + irq_dir[irq]) + return; + + memset(name, 0, MAX_NAMELEN); + sprintf(name, "%d", irq); + + /* create /proc/irq/1234 */ + irq_dir[irq] = proc_mkdir(name, root_irq_dir); + + /* create /proc/irq/1234/smp_affinity */ + entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); + + entry->nlink = 1; + entry->data = (void *)(long)irq; + entry->read_proc = irq_affinity_read_proc; + entry->write_proc = irq_affinity_write_proc; + + smp_affinity_entry[irq] = entry; +} + +unsigned long prof_cpu_mask = -1; + +void init_irq_proc (void) +{ + struct proc_dir_entry *entry; + int i; + + /* create /proc/irq */ + root_irq_dir = proc_mkdir("irq", 0); + + /* create /proc/irq/prof_cpu_mask */ + entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); + + entry->nlink = 1; + entry->data = (void *)&prof_cpu_mask; + entry->read_proc = prof_cpu_mask_read_proc; + entry->write_proc = prof_cpu_mask_write_proc; + + /* + * Create entries for all existing IRQs. + */ + for (i = 0; i < NR_IRQS; i++) + register_irq_proc(i); +} + +unsigned long probe_irq_on(void) +{ + return(0); +} + +int probe_irq_off(unsigned long val) +{ + return(0); +} + +static unsigned int startup_SIGIO_irq(unsigned int irq) +{ + return(0); +} + +static void shutdown_SIGIO_irq(unsigned int irq) +{ +} + +static void enable_SIGIO_irq(unsigned int irq) +{ +} + +static void disable_SIGIO_irq(unsigned int irq) +{ +} + +static void mask_and_ack_SIGIO(unsigned int irq) +{ +} + +static void end_SIGIO_irq(unsigned int irq) +{ +} + +static unsigned int startup_SIGVTALRM_irq(unsigned int irq) +{ + return(0); +} + +static void shutdown_SIGVTALRM_irq(unsigned int irq) +{ +} + +static void enable_SIGVTALRM_irq(unsigned int irq) +{ +} + +static void disable_SIGVTALRM_irq(unsigned int irq) +{ +} + +static void mask_and_ack_SIGVTALRM(unsigned int irq) +{ +} + +static void end_SIGVTALRM_irq(unsigned int irq) +{ +} + +static struct hw_interrupt_type SIGIO_irq_type = { + "SIGIO", + startup_SIGIO_irq, + shutdown_SIGIO_irq, + enable_SIGIO_irq, + disable_SIGIO_irq, + mask_and_ack_SIGIO, + end_SIGIO_irq, + NULL +}; + +static struct hw_interrupt_type SIGVTALRM_irq_type = { + "SIGVTALRM", + startup_SIGVTALRM_irq, + shutdown_SIGVTALRM_irq, + enable_SIGVTALRM_irq, + disable_SIGVTALRM_irq, + mask_and_ack_SIGVTALRM, + end_SIGVTALRM_irq, + NULL +}; + +void __init init_IRQ(void) +{ + int i; + + irq_desc[TIMER_IRQ].status = IRQ_DISABLED; + irq_desc[TIMER_IRQ].action = 0; + irq_desc[TIMER_IRQ].depth = 1; + irq_desc[TIMER_IRQ].handler = &SIGVTALRM_irq_type; + enable_irq(TIMER_IRQ); + for(i=1;i<NR_IRQS;i++){ + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = 0; + irq_desc[i].depth = 1; + irq_desc[i].handler = &SIGIO_irq_type; + enable_irq(i); + } + init_irq_signals(0); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/irq_user.c linux.ac/arch/um/kernel/irq_user.c --- linux.vanilla/arch/um/kernel/irq_user.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/irq_user.c Sun Apr 15 22:55:58 2001 @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/time.h> +#include "user_util.h" +#include "kern_util.h" +#include "user.h" + +struct irq_fd { + struct irq_fd *next; + void *id; + int fd; + int irq; + int pid; +}; + +static struct irq_fd *active_fds = NULL; +static fd_set active_fd_mask; +static int max_fd = -1; + +extern int io_count, intr_count; + +void sigio_handler(int sig, void *sc, int usermode) +{ + struct irq_fd *irq_fd, *next; + struct timeval tv; + fd_set fds; + int i, n, fd; + + while(1){ + tv.tv_sec = 0; + tv.tv_usec = 0; + fds = active_fd_mask; + if((n = select(max_fd + 1, &fds, NULL, NULL, &tv)) < 0){ + printk("sigio_handler : select returned %d, " + "errno = %d\n", n, errno); + break; + } + if(n == 0) break; + for(i=0;i<=max_fd;i++){ + if(FD_ISSET(i, &fds)) FD_CLR(i, &active_fd_mask); + } + for(irq_fd=active_fds;irq_fd != NULL;irq_fd = next){ + /* These mysterious assignments protect us against + * the irq handler freeing the irq from under us. + */ + next = irq_fd->next; + fd = irq_fd->fd; + if(FD_ISSET(irq_fd->fd, &fds)) + do_IRQ(irq_fd->irq, usermode); + } + } +} + +int activate_fd(int irq, int fd, void *dev_id) +{ + struct irq_fd *new_fd; + int pid, retval; + + for(new_fd = active_fds;new_fd;new_fd = new_fd->next){ + if(new_fd->fd == fd){ + printk("Registering fd %d twice\n", fd); + printk("Irqs : %d, %d\n", new_fd->irq, irq); + printk("Ids : 0x%x, 0x%x\n", new_fd->id, dev_id); + return(-EIO); + } + } + if((retval = fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK)) < 0){ + printk("Failed to set O_ASYNC and O_NONBLOCK on fd # %d, " + "errno = %d\n", fd, errno); + return(-retval); + } + pid = external_pid(NULL); + if((retval = fcntl(fd, F_SETOWN, pid)) < 0){ + printk("Failed to fcntl F_SETOWN fd %d to pid %d, " + "errno = %d\n", pid, errno); + return(-retval); + } + new_fd = um_kmalloc(sizeof(*new_fd)); + if(new_fd == NULL) return(-ENOMEM); + new_fd->next = active_fds; + new_fd->id = dev_id; + new_fd->irq = irq; + new_fd->fd = fd; + new_fd->pid = external_pid(NULL); + active_fds = new_fd; + if(fd > max_fd) max_fd = fd; + FD_SET(fd, &active_fd_mask); + return(0); +} + +void free_irq_fd(void *dev_id) +{ + struct irq_fd **prev; + + prev = &active_fds; + while(*prev != NULL){ + if((*prev)->id == dev_id){ + struct irq_fd *old_fd = *prev; + *prev = (*prev)->next; + FD_CLR(old_fd->fd, &active_fd_mask); + kfree(old_fd); + return; + } + prev = &(*prev)->next; + } +} + +void reactivate_fd(int fd) +{ + FD_SET(fd, &active_fd_mask); +} + +void forward_interrupts(int pid) +{ + struct irq_fd *irq; + + for(irq=active_fds;irq != NULL;irq = irq->next){ + if(fcntl(irq->fd, F_SETOWN, pid) < 0){ + int save_errno = errno; + if(fcntl(irq->fd, F_GETOWN, 0) != pid){ + printk("Failed to forward %d to pid %d, " + "errno = %d\n", irq->fd, pid, + save_errno); + } + } + irq->pid = pid; + } +} + +void init_irq_signals(int on_sigstack) +{ + int flags; + + flags = on_sigstack ? SA_ONSTACK : 0; + set_handler(SIGVTALRM, irq_handler, flags, SIGUSR1, SIGVTALRM, + SIGALRM, SIGIO, SIGUSR2, -1); + set_handler(SIGIO, irq_handler, flags, SIGUSR1, SIGVTALRM, + SIGALRM, SIGIO, SIGUSR2, -1); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/ksyms.c linux.ac/arch/um/kernel/ksyms.c --- linux.vanilla/arch/um/kernel/ksyms.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/ksyms.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,17 @@ +#include "linux/module.h" +#include "linux/string.h" +#include "asm/current.h" +#include "asm/delay.h" +#include "asm/processor.h" +#include "asm/unistd.h" +#include "kern_util.h" +#include "user_util.h" + +EXPORT_SYMBOL(stop); +EXPORT_SYMBOL(strtok); +EXPORT_SYMBOL(physmem); +EXPORT_SYMBOL(current_task); +EXPORT_SYMBOL(set_signals); +EXPORT_SYMBOL(kernel_thread); +EXPORT_SYMBOL(__const_udelay); +EXPORT_SYMBOL(sys_waitpid); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/mem.c linux.ac/arch/um/kernel/mem.c --- linux.vanilla/arch/um/kernel/mem.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/mem.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/types.h" +#include "linux/mm.h" +#include "linux/fs.h" +#include "linux/init.h" +#include "linux/bootmem.h" +#include "linux/swap.h" +#include "asm/page.h" +#include "asm/pgtable.h" +#include "asm/pgalloc.h" +#include "asm/bitops.h" +#include "user_util.h" +#include "kern_util.h" +#include "kern.h" + +unsigned long high_physmem; + +unsigned long low_physmem; + +unsigned long vm_start; + +unsigned long vm_end; + +pgd_t swapper_pg_dir[1024]; + +unsigned long *empty_zero_page = NULL; + +unsigned long *empty_bad_page = NULL; + +const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; + +static unsigned long totalram_pages = 0; + +extern char __init_begin, __init_end; + +void mem_init(void) +{ + max_mapnr = num_physpages = max_low_pfn; + + /* clear the zero-page */ + memset((void *) empty_zero_page, 0, PAGE_SIZE); + + /* this will put all low memory onto the freelists */ + totalram_pages += free_all_bootmem(); + printk("Memory: %luk available\n", + (unsigned long) nr_free_pages() << (PAGE_SHIFT-10)); +} + +void paging_init(void) +{ + unsigned long zones_size[MAX_NR_ZONES]; + int i; + + empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE); + empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE); + for(i=0;i<sizeof(zones_size)/sizeof(zones_size[0]);i++) + zones_size[i] = 0; + zones_size[1] = (high_physmem >> PAGE_SHIFT) - + (physmem >> PAGE_SHIFT) - zones_size[0]; + free_area_init(zones_size); +} + +static int meminfo_22 = 0; + +static int meminfo_compat(char *str) +{ + meminfo_22 = 1; + return(1); +} + +__setup("22_meminfo", meminfo_compat); + +void si_meminfo(struct sysinfo *val) +{ + val->totalram = totalram_pages; + val->sharedram = 0; + val->freeram = nr_free_pages(); + val->bufferram = atomic_read(&buffermem_pages); + val->totalhigh = 0; + val->freehigh = 0; + val->mem_unit = PAGE_SIZE; + if(meminfo_22){ + val->freeram <<= PAGE_SHIFT; + val->bufferram <<= PAGE_SHIFT; + val->totalram <<= PAGE_SHIFT; + val->sharedram <<= PAGE_SHIFT; + } +} + +pte_t __bad_page(void) +{ + clear_page(empty_bad_page); + return pte_mkdirty(mk_pte((struct page *) empty_bad_page, + PAGE_SHARED)); +} + +/* This can't do anything because nothing in the kernel image can be freed + * since it's not in kernel physical memory. + */ + +void free_initmem(void) +{ +} + +#ifdef CONFIG_BLK_DEV_INITRD + +/* It's unclear to me whether the area start -> end is in kernel memory, so + * this does nothing for now... + */ + +void free_initrd_mem(unsigned long start, unsigned long end) +{ +} +#endif + +int do_check_pgt_cache(int low, int high) +{ + int freed = 0; + if(pgtable_cache_size > high) { + do { + if (pgd_quicklist) { + free_pgd_slow(get_pgd_fast()); + freed++; + } + if (pmd_quicklist) { + pmd_free_slow(pmd_alloc_one_fast(NULL, 0)); + freed++; + } + if (pte_quicklist) { + pte_free_slow(pte_alloc_one_fast(NULL, 0)); + freed++; + } + } while(pgtable_cache_size > low); + } + return freed; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/mprot.h linux.ac/arch/um/kernel/mprot.h --- linux.vanilla/arch/um/kernel/mprot.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/mprot.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __MPROT_H__ +#define __MPROT_H__ + +extern void no_access(unsigned long addr, unsigned int len); + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/process.c linux.ac/arch/um/kernel/process.c --- linux.vanilla/arch/um/kernel/process.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/process.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,361 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdio.h> +#include <unistd.h> +#include <signal.h> +#include <sched.h> +#include <errno.h> +#include <string.h> +#include <stdarg.h> +#include <sys/time.h> +#include <sys/ptrace.h> +#include <sys/wait.h> +#include <sys/mman.h> +#include <asm/ptrace.h> +#include <asm/sigcontext.h> +#include "user_util.h" +#include "kern_util.h" +#include "user.h" +#include "sysdep/ptrace.h" + +void stop_pid(int pid) +{ + kill(pid, SIGSTOP); +} + +void kill_pid(int pid) +{ + kill(pid, SIGKILL); +} + +void trap_pid(int pid) +{ + kill(pid, SIGTRAP); +} + +void usr1_pid(int pid) +{ + kill(pid, SIGUSR1); +} + +void cont_pid(int pid) +{ + kill(pid, SIGCONT); +} + +void set_sigstack(void *sig_stack) +{ + stack_t stack; + + stack.ss_sp = (__ptr_t) sig_stack; + stack.ss_flags = 0; + stack.ss_size = 2 * page_size() - sizeof(void *); + if(sigaltstack(&stack, NULL) != 0) + panic("sigaltstack failed"); +} + +void set_handler(int sig, void (*handler)(int), int flags, ...) +{ + struct sigaction action; + va_list ap; + int mask; + + va_start(ap, flags); + action.sa_handler = handler; + sigemptyset(&action.sa_mask); + while((mask = va_arg(ap, int)) != -1){ + sigaddset(&action.sa_mask, mask); + } + action.sa_flags = flags; + action.sa_restorer = NULL; + if(sigaction(sig, &action, NULL) < 0) + panic("sigaction failed"); +} + +void init_new_thread(void *sig_stack, void (*usr1_handler)(int)) +{ + int flags = 0; + + if(sig_stack != NULL){ + set_sigstack(sig_stack); + flags = SA_ONSTACK; + } + set_handler(SIGSEGV, sig_handler, flags, SIGVTALRM, SIGUSR1, + SIGALRM, SIGIO, -1); + set_handler(SIGTRAP, sig_handler, flags, SIGVTALRM, SIGUSR1, + SIGALRM, SIGIO, -1); + set_handler(SIGFPE, sig_handler, flags, SIGVTALRM, SIGUSR1, + SIGALRM, SIGIO, -1); + set_handler(SIGUSR2, process_stack_handler, SA_NODEFER, SIGUSR1, -1); + change_sig(SIGUSR2, 1); + if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1); + signal(SIGCHLD, SIG_IGN); + set_timers(1); + init_irq_signals(sig_stack != NULL); +} + +int fork_tramp(void *sig_stack) +{ + block_signals(); + init_new_thread(sig_stack, finish_fork_handler); + kill(getpid(), SIGSTOP); + return(0); +} + +struct tramp { + int (*tramp)(void *); + unsigned long temp_stack; + unsigned long stack; + int flags; + int pid; +}; + +int outer_tramp(void *arg) +{ + struct tramp *t; + + t = arg; + t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2, + t->flags, (void *) t->stack); + if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT); + exit(0); +} + +int start_fork_tramp(unsigned long sig_stack, unsigned long temp_stack, + int clone_vm, int (*tramp)(void *)) +{ + struct tramp arg; + unsigned long sp; + int new_pid, flags, status, err; + + /* The trampoline will run on the temporary stack */ + sp = stack_sp(temp_stack); + + flags = CLONE_FILES | SIGCHLD; + if(clone_vm) flags |= CLONE_VM; + + arg.tramp = tramp; + arg.temp_stack = temp_stack; + arg.stack = sig_stack; + arg.flags = flags; + + /* Start the process and wait for it to stop itself */ + new_pid = clone(outer_tramp, (void *) sp, flags, &arg); + if(new_pid < 0) return(-errno); + while((err = waitpid(new_pid, &status, 0) < 0) && (errno == EINTR)) ; + if(err < 0) panic("Waiting for outer trampoline failed - errno = %d", + errno); + if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) + panic("outer trampoline didn't exit 0"); + + return(arg.pid); +} + +void trace_myself(void) +{ + if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) + panic("ptrace failed in trace_myself"); +} + +void usr1_and_wait(int pid) +{ + sigset_t new_mask, old_mask; + + sigemptyset(&new_mask); + sigaddset(&new_mask, SIGUSR1); + sigprocmask(SIG_BLOCK, &new_mask, &old_mask); + usr1_pid(pid); + sigsuspend(&old_mask); + sigprocmask(SIG_SETMASK, &old_mask, NULL); +} + +void signal_handler(void *task, unsigned long h, int sig) +{ + void (*handler)(int, struct sigcontext); + struct sigcontext sc; + void *regs; + unsigned long cr2; + int err; + + regs = process_state(task, &cr2, &err); + fill_in_sigcontext(&sc, regs, cr2, err); + handler = (void (*)(int, struct sigcontext)) h; + (*handler)(sig, sc); +} + +void (*set_signal_handler(int sig, void (*new_handler)(int)))(int) +{ + struct sigaction action; + void (*old_handler)(int); + + sigaction(sig, NULL, &action); + old_handler = action.sa_handler; + action.sa_handler = new_handler; + sigaction(sig, &action, NULL); + return(old_handler); +} + +void continue_fork(void *task, int pid, struct sys_pt_regs *regs) +{ + if(ptrace(PTRACE_CONT, pid, 0, SIGUSR1) < 0) + tracer_panic("Couldn't continue forked process"); + wait_for_stop(pid, SIGSTOP, PTRACE_CONT); + if(ptrace(PTRACE_SETREGS, pid, 0, regs) < 0) + tracer_panic("Couldn't restore registers"); +} + +int setup_altstack(unsigned long stack, int stack_size) +{ + struct sys_pt_regs *regs; + unsigned long sp; + int pid; + + sp = stack + stack_size - sizeof(void *); + pid = clone(alt_stack_handler, (void *) sp, + CLONE_VM | CLONE_FILES | SIGCHLD, NULL); + if(pid < 0) return(-errno); + wait_for_stop(pid, SIGSTOP, PTRACE_CONT); + regs = altstack_state(NULL, NULL, NULL); + if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) + panic("Couldn't get altstack state"); + save_altstack(NULL, UM_SP(regs)); + kill(pid, SIGKILL); + if(waitpid(pid, NULL, WNOHANG) < 0) + printk("setup_altstack : waitpid failed, errno = %d\n", + errno); + return(0); +} + +void change_sig(int signal, int on) +{ + sigset_t sigset; + + sigemptyset(&sigset); + sigaddset(&sigset, signal); + sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, NULL); +} + +void *last_brk; + +void *update_brk(void) +{ + void *current_brk; + int len, off; + + current_brk = sbrk(0); + if(current_brk == last_brk) return(current_brk); + off = last_brk - brk_start; + if(lseek(brk_fd, off, SEEK_SET) != off){ + panic("update_brk : lseek failed - errno = %d", errno); + } + len = current_brk - last_brk; + if(write(brk_fd, last_brk, len) != len){ + panic("update_brk : write failed - errno = %d", errno); + } + last_brk = current_brk; + return(current_brk); +} + +void check_brk(void *process_brk) +{ + if(last_brk == process_brk) return; + if(mmap(process_brk, last_brk - process_brk, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, + brk_fd, process_brk - brk_start) != process_brk){ + panic("check_brk : mmap failed - errno = %d", errno); + } +} + +int get_one_stack(char **stack_out, struct sys_pt_regs *regs_out) +{ + void *stack; + unsigned long sp; + int pid, n; + + if((stack = mmap(NULL, page_size(), + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) == MAP_FAILED){ + perror("get_one_stack : couldn't mmap stack"); + exit(1); + } + sp = stack_sp((unsigned long) stack); + pid = clone(syscall_handler, (void *) sp, SIGCHLD, NULL); + if(pid < 0){ + perror("get_one_stack : couldn't start thread"); + exit(1); + } + if(ptrace(PTRACE_ATTACH, pid, 0, 0) < 0){ + perror("get_one_stack : couldn't attach to child"); + exit(1); + } + wait_for_stop(pid, SIGSTOP, PTRACE_CONT); + ptrace(PTRACE_CONT, pid, 0, 0); + wait_for_stop(pid, SIGSTOP, PTRACE_CONT); + if(ptrace(PTRACE_GETREGS, pid, 0, regs_out) < 0){ + perror("get_one_stack : couldn't get registers"); + exit(1); + } + sp = regs_out->regs[UESP]; + sp &= ~sizeof(unsigned long); + while(sp < (unsigned long) stack + page_size()){ + *((unsigned long *) sp) = ptrace(PTRACE_PEEKDATA, pid, + (void *) sp, NULL); + sp += sizeof(unsigned long); + } + ptrace(PTRACE_KILL, pid, 0, 0); + waitpid(pid, NULL, 0); + n = page_size() - (regs_out->regs[UESP] & ~page_mask()); + *stack_out = stack; + + return(n); +} + +void attach_process(int pid) +{ + if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) || + (ptrace(PTRACE_CONT, pid, 0, 0) < 0)) + tracer_panic("OP_FORK failed to attach pid"); + wait_for_stop(pid, SIGSTOP, PTRACE_CONT); +} + +int signal_frame_size; +static void *local_addr; + +static void frame_size(int sig) +{ + int n; + + signal_frame_size = (unsigned long) local_addr - (unsigned long) &n; +} + +void calc_sigframe_size(void) +{ + int n; + + signal(SIGUSR1, frame_size); + local_addr = &n; + usr1_pid(getpid()); +} + +void tracer_panic(char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vprintf(format, ap); + while(1) sleep(10); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/process_kern.c linux.ac/arch/um/kernel/process_kern.c --- linux.vanilla/arch/um/kernel/process_kern.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/process_kern.c Sun Apr 15 22:56:45 2001 @@ -0,0 +1,816 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/sched.h" +#include "linux/interrupt.h" +#include "linux/mm.h" +#include "linux/malloc.h" +#include "linux/utsname.h" +#include "linux/fs.h" +#include "linux/utime.h" +#include "linux/smp_lock.h" +#include "linux/module.h" +#include "linux/init.h" +#include "asm/unistd.h" +#include "asm/mman.h" +#include "asm/segment.h" +#include "asm/stat.h" +#include "asm/pgtable.h" +#include "asm/pgalloc.h" +#include "asm/spinlock.h" +#include "asm/uaccess.h" +#include "asm/user.h" +#include "user_util.h" +#include "kern_util.h" +#include "kern.h" + +struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } }; + +static struct task_struct *get_task(int pid, int require) +{ + struct task_struct *task, *ret; + + ret = NULL; + read_lock(&tasklist_lock); + for_each_task(task){ + if(task->pid == pid){ + ret = task; + break; + } + } + read_unlock(&tasklist_lock); + if(require && (ret == NULL)) panic("get_task couldn't find a task\n"); + return(ret); +} + +int external_pid(void *t) +{ + struct task_struct *task = t; + if(task == NULL) task = current; + return(task->thread.extern_pid); +} + +void free_stack(unsigned long stack) +{ + free_page(stack); +} + +void set_init_pid(int pid) +{ + init_task.thread.extern_pid = pid; +} + +int set_user_thread(void *t, int on, int restore_regs) +{ + struct task_struct *task; + int ret; + + if(t == NULL) task = current; + else task = t; + if(on == task->thread.tracing) return(on); + ret = task->thread.tracing; + task->thread.request.op = on ? OP_TRACE_ON : OP_TRACE_OFF; + task->thread.request.u.tracing.restore_regs = restore_regs; + usr1_pid(getpid()); + return(ret); +} + +void set_tracing(void *task, int tracing) +{ + ((struct task_struct *) task)->thread.tracing = tracing; +} + +int is_tracing(void *t) +{ + struct task_struct *task; + + if(t == NULL) task = current; + else task = t; + return(task->thread.tracing); +} + +extern void schedule_tail(struct task_struct *prev); + +static int new_thread_proc(void *t) +{ + struct task_struct *task; + int (*fn)(void *), pid; + void *arg; + + task = t; + trace_myself(); + init_new_thread(NULL, NULL); + pid = getpid(); + fn = task->thread.request.u.thread.proc; + arg = task->thread.request.u.thread.arg; + task->thread.extern_pid = pid; + stop_pid(pid); + set_cmdline("(kernel thread)"); + init_flush_vm(); + if(current->thread.request.u.cswitch.from != NULL) + schedule_tail(current->thread.request.u.cswitch.from); + (*fn)(arg); + do_exit(0); + return(0); +} + +unsigned long alloc_stack(void) +{ + unsigned long page; + + if((page = __get_free_page(GFP_KERNEL)) == 0) + panic("Couldn't allocate new stack"); + stack_protections(page, PAGE_SIZE); + return(page); +} + +extern int inited_cpus; + +static int start_kernel_thread(struct task_struct *task, int (*fn)(void *), + void *arg, int cpu) +{ + int extern_pid; + unsigned long sp; + + sp = ((unsigned long) task) + 4 * PAGE_SIZE - sizeof(void *); + task->thread.request.u.thread.proc = fn; + task->thread.request.u.thread.arg = arg; + task->thread.extern_pid = -1; + extern_pid = clone_and_wait(new_thread_proc, task, (void *) sp, + CLONE_FILES | SIGCHLD); + if(task->thread.extern_pid == -1) + tracer_panic("task didn't set its pid"); + task->mm = NULL; + task->active_mm = NULL; +#ifdef __SMP__ + if(cpu != -1){ + cpu_tasks[cpu].pid = extern_pid; + cpu_tasks[cpu].task = task; + inited_cpus++; + init_tasks[cpu] = task; + cpu_number_map[cpu] = cpu; + task->processor = cpu; + cont_pid(extern_pid); + } +#endif + return(extern_pid); +} + +static int kernel_thread1(int (*fn)(void *), void * arg, unsigned long flags, + int cpu, int *extern_pid_out) +{ + struct task_struct *new_task; + int pid, extern_pid; + + pid = do_fork(CLONE_VM | flags, 0, NULL, 0); + if(pid < 0) panic("do_fork failed in kernel_thread"); + new_task = get_task(pid, 1); + current->thread.request.op = OP_THREAD; + current->thread.request.u.thread.proc = fn; + current->thread.request.u.thread.arg = arg; + current->thread.request.u.thread.flags = flags; + current->thread.request.u.thread.new_task = new_task; + current->thread.request.u.thread.cpu = cpu; + usr1_pid(getpid()); + extern_pid = current->thread.request.u.thread.new_pid; + if(extern_pid < 0){ + printk("Kernel thread failed : errno = %d", -extern_pid); + return(extern_pid); + } + if(extern_pid_out != NULL) *extern_pid_out = extern_pid; + current->thread.request.u.cswitch.from = NULL; + return(pid); +} + +int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + return(kernel_thread1(fn, arg, flags, -1, NULL)); +} + +void switch_mm(struct mm_struct *prev, struct mm_struct *next, + struct task_struct *tsk, unsigned cpu) +{ + if (prev != next) + clear_bit(cpu, &prev->cpu_vm_mask); + set_bit(cpu, &next->cpu_vm_mask); +} + +void *_switch_to(void *prev, void *next) +{ + struct task_struct *from, *to; + + from = prev; + to = next; + current->thread.request.op = OP_SWITCH; + current->thread.request.u.cswitch.to = next; + current->thread.brk = update_brk(); + forward_interrupts(to->thread.extern_pid); + block_signals(); + usr1_pid(getpid()); + flush_tlb_kernel_vm(); + check_brk(current->thread.brk); + unblock_signals(); + return(current->thread.request.u.cswitch.from); +} + +void do_bh(void) +{ +#ifndef __SMP__ + if (softirq_active(0) & softirq_mask(0)){ + do_softirq(); + unblock_signals(); + } +#else +#error Need to update do_bh +#endif +} + +void ret_from_sys_call(void *t) +{ + struct task_struct *task; + + task = t; + if(task == NULL) task = current; + do_bh(); + if(task->need_resched) schedule(); + if((task->sigpending != 0) && (task->thread.npending == 0)){ + block_signals(); + do_signal(task, NULL, NULL); + unblock_signals(); + } +} + +void release_thread(struct task_struct *task) +{ +} + +void exit_thread(void) +{ + unprotect_stack((unsigned long) current); +} + +char *generic_stack = NULL; +int generic_stack_size = 0; +struct sys_pt_regs generic_regs; +struct sys_pt_regs generic_regs_mask; + +void set_syscall_regs(void *t) +{ + struct sys_pt_regs *regs; + int i; + struct task_struct *task = t; + + regs = &task->thread.syscall_regs; + for(i = 0; i < sizeof(regs->regs)/sizeof(regs->regs[0]); i++){ + task->thread.syscall_regs.regs[i] = generic_regs.regs[i]; + if(generic_regs_mask.regs[i]) + task->thread.syscall_regs.regs[i] += + task->thread.kernel_stack + PAGE_SIZE; + } +} + +int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, + unsigned long stack_top, struct task_struct * p, + struct pt_regs * regs) +{ + int new_pid, clone_vm; + unsigned long stack; + + p->thread = (struct thread_struct) INIT_THREAD; + p->thread.kernel_stack = (unsigned long) p + 2 * PAGE_SIZE; + p->thread.tracing = current->thread.forking; + set_syscall_regs(p); + if(current->thread.forking){ + p->thread.tracing = 0; + stack = alloc_stack(); + clone_vm = (p->mm == current->mm); + new_pid = start_fork_tramp(p->thread.kernel_stack, stack, + clone_vm, fork_tramp); + if(new_pid < 0){ + printk("copy_thread : clone failed with errno = %d", + -new_pid); + return(new_pid); + } + current->thread.request.op = OP_FORK; + current->thread.request.u.fork.pid = new_pid; + usr1_pid(getpid()); + p->thread.process_regs = current->thread.process_regs; + UM_SYSCALL_RET(&p->thread.process_regs) = 0; + if(sp != 0) UM_SP(&p->thread.process_regs) = sp; + p->thread.extern_pid = new_pid; + p->thread.request.op = OP_FORK_FINISH; + p->thread.request.u.fork_finish.stack = stack; + } + current->need_resched = 1; + return(0); +} + +void tracing_reboot(void) +{ + current->thread.request.op = OP_REBOOT; + usr1_pid(getpid()); +} + +void tracing_halt(void) +{ + current->thread.request.op = OP_HALT; + usr1_pid(getpid()); +} + +void tracing_cb(void (*proc)(void *), void *arg) +{ + if(getpid() == tracing_pid){ + (*proc)(arg); + } + else { + current->thread.request.op = OP_CB; + current->thread.request.u.cb.proc = proc; + current->thread.request.u.cb.arg = arg; + usr1_pid(getpid()); + } +} + +struct { + struct task_struct *from; + struct task_struct *to; + int processor; +} switch_record[1024]; + +int switch_index = 0; + +int do_proc_op(void *t, int proc_id) +{ + struct task_struct *task, *to; + struct thread_struct *thread; + int op, pid; + + task = t; + thread = &task->thread; + op = thread->request.op; + switch(op){ + case OP_NONE: + case OP_TRACE_ON: + case OP_TRACE_OFF: + break; + case OP_EXEC: + do_exec(thread->extern_pid, thread->request.u.exec.pid); + break; + case OP_SWITCH: + if((task->state == TASK_ZOMBIE) && + (thread->extern_pid != -1)) + kill_pid(thread->extern_pid); + to = thread->request.u.cswitch.to; + switch_record[switch_index].from = task; + switch_record[switch_index].to = to; + switch_record[switch_index++].processor = to->processor; + if(switch_index == 1024) switch_index = 0; +#ifdef __SMP__ + cpu_tasks[proc_id].task = to; + cpu_tasks[proc_id].pid = to->thread.extern_pid; + if(cpu_tasks[0].pid == cpu_tasks[1].pid) + tracer_panic("Scheduled a process on two processors"); +#else + current = to; +#endif + if(to->thread.request.op == OP_FORK_FINISH){ + to->thread.request.u.fork_finish.from = task; + continue_fork(to, to->thread.extern_pid, + &to->thread.process_regs); + to->thread.request.op = OP_NONE; + set_tracing(to, 1); + } + else to->thread.request.u.cswitch.from = task; + cont_pid(to->thread.extern_pid); + break; + case OP_THREAD: + pid = start_kernel_thread(thread->request.u.thread.new_task, + thread->request.u.thread.proc, + thread->request.u.thread.arg, + thread->request.u.thread.cpu); + thread->request.u.thread.new_pid = pid; + break; + case OP_FORK: + attach_process(thread->request.u.fork.pid); + break; + case OP_CB: + (*thread->request.u.cb.proc)(thread->request.u.cb.arg); + break; + case OP_REBOOT: + case OP_HALT: + break; + default: + tracer_panic("Bad op in do_proc_op"); + break; + } + thread->request.op = OP_NONE; + return(op); +} + +unsigned long stack_sp(unsigned long page) +{ + return(page + PAGE_SIZE - sizeof(void *)); +} + +int current_pid(void) +{ + return(current->pid); +} + +static void do_idle(void) +{ + idle_timer(); + + while(1){ + /* endless idle loop with no priority at all */ + current->nice = 20; + current->counter = -100; + + /* + * although we are an idle CPU, we do not want to + * get into the scheduler unnecessarily. + */ + if (current->need_resched) { + schedule(); + check_pgt_cache(); + } + idle_sleep(10); + } +} + +static int idle_proc(void *unused) +{ + del_from_runqueue(current); + init_idle(); +#ifdef __SMP__ + smp_num_cpus++; +#endif + do_idle(); + return(0); +} + +int cpu_idle(void) +{ + int i, pid; + + if(ncpus > 1){ + printk("Starting up other processors:\n"); + for(i=1;i<ncpus;i++){ + kernel_thread1(idle_proc, NULL, 0, i, &pid); + printk("\t#%d - idle thread pid = %d\n", i, pid); + } + } + do_idle(); + return(0); +} + +int page_size(void) +{ + return(PAGE_SIZE); +} + +int page_mask(void) +{ + return(PAGE_MASK); +} + +char *current_comm(void) +{ + return(current->comm); +} + +void *current_sigstack(void *t) +{ + struct task_struct *task; + + if(t == NULL) task = current; + else task = t; + return((void *) task->thread.kernel_stack); +} + +unsigned long um_virt_to_phys(void *t, unsigned long addr) +{ + struct task_struct *task; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + task = t; + if(task->mm == NULL) return(0xffffffff); + pgd = pgd_offset(task->mm, addr); + pmd = pmd_offset(pgd, addr); + if(!pmd_present(*pmd)) return(0xffffffff); + pte = pte_offset(pmd, addr); + if(!pte_present(*pte)) return(0xffffffff); + return((pte_val(*pte) & PAGE_MASK) + (addr & ~PAGE_MASK)); +} + +char *current_cmd(void) +{ +#ifdef __SMP__ + return("(Unknown)"); +#else + unsigned long addr; + + if((addr = um_virt_to_phys(current, + current->mm->arg_start)) == 0xffffffff) + return("(Unknown)"); + else return((char *) addr); +#endif +} + +void force_sigbus(void) +{ + printk("Killing pid %d because of a lack of memory\n", current->pid); + lock_kernel(); + sigaddset(¤t->pending.signal, SIGBUS); + recalc_sigpending(current); + current->flags |= PF_SIGNALED; + do_exit(SIGBUS | 0x80); +} + +void finish_fork_handler(int sig) +{ + unsigned long stack; + + init_flush_vm(); + check_brk(brk_start); + if(current->mm != current->p_pptr->mm) + protect(physmem, high_physmem - physmem, 1, 1, 0); + stack = (unsigned long) current; + protect(stack + PAGE_SIZE, PAGE_SIZE, 0, 0, 0); + stack_protections(stack + 2 * PAGE_SIZE, 2 * PAGE_SIZE); + if(current->thread.request.u.fork_finish.from) + schedule_tail(current->thread.request.u.fork_finish.from); + free_page(current->thread.request.u.fork_finish.stack); + change_sig(SIGUSR1, 1); + unblock_signals(); + kill(getpid(), SIGSTOP); +} + +void *get_current_task(void) +{ + return(current); +} + +void *process_state(void *t, unsigned long *cr2_out, int *err_out) +{ + struct task_struct *task; + + if(t == NULL) task = current; + else task = t; + if(cr2_out) *cr2_out = task->thread.cr2; + if(err_out) *err_out = task->thread.err; + return(&task->thread.process_regs); +} + +struct sys_pt_regs *syscall_state(void *t, void **stack_out, int *size_out) +{ + struct task_struct *task; + + task = t; + *stack_out = generic_stack; + *size_out = generic_stack_size; + return(&task->thread.syscall_regs); +} + +int get_repeat_syscall(void *t) +{ + struct task_struct *task; + + if(t == NULL) task = current; + else task = t; + return(task->thread.repeat_syscall); +} + +void set_repeat_syscall(int again) +{ + current->thread.repeat_syscall = again; +} + +void save_altstack(void *t, unsigned long sp) +{ + struct task_struct *task; + void *stack; + int n; + + if(t == NULL) task = current; + else task = t; + if(task->thread.altstack != NULL) kfree(task->thread.altstack); + n = PAGE_SIZE - (sp & ~PAGE_MASK); + stack = kmalloc(n, GFP_KERNEL); + if(stack == NULL) panic("save_altstack : kmalloc failed"); + memcpy(stack, (void *) sp, n); + task->thread.altstack = stack; + task->thread.altstack_size = n; +} + +struct sys_pt_regs *altstack_state(void *t, void **stack_out, int *size_out) +{ + struct task_struct *task; + + if(t == NULL) task = current; + else task = t; + if(stack_out != NULL) *stack_out = task->thread.altstack; + if(size_out != NULL) *size_out = task->thread.altstack_size; + return(&task->thread.altstack_regs); +} + +extern int signal_frame_size; + +void probe_stack(unsigned long sp) +{ + int n, delta; + + delta = signal_frame_size; + get_user(n, (int *) sp); + put_user(n, (int *) sp); + get_user(n, (int *) (sp - delta)); + put_user(n, (int *) (sp - delta)); +} + +void dump_thread(struct pt_regs *regs, struct user *u) +{ +} + +int have_signals(void *t, int altstack) +{ + struct task_struct *task; + + if(t == NULL) task = current; + else task = t; + if(task->thread.npending == 1){ + if((altstack && (task->thread.signal.sp != 0)) || + (!altstack && (task->thread.signal.sp == 0))) + return(1); + } + return(0); +} + +int switching_modes(void *t) +{ + struct task_struct *task; + + task = t; + return(task->thread.request.op == OP_TRACE_OFF); +} + +void enable_hlt(void) +{ + panic("enable_hlt"); +} + +void disable_hlt(void) +{ + panic("disable_hlt"); +} + +void interrupt_end(void) +{ + if(current->need_resched) schedule(); + if(current->thread.npending == 0) do_signal(current, NULL, NULL); + if(current->thread.npending > 0) + probe_stack(current->thread.process_regs.regs[UESP]); +} + +void *um_kmalloc(int size) +{ + return(kmalloc(size, GFP_KERNEL)); +} + +void *get_fault_addr(void) +{ + return(current->thread.fault_addr); +} + +EXPORT_SYMBOL(get_fault_addr); + +void set_fault_addr(void *addr) +{ + current->thread.fault_addr = addr; +} + +EXPORT_SYMBOL(set_fault_addr); + +int singlestepping(void *t) +{ + struct task_struct *task; + int ret; + + task = (struct task_struct *) t; + ret = (task->ptrace & PT_DTRACE); + task->ptrace &= ~PT_DTRACE; + return(ret); +} + +void not_implemented(void) +{ + printk("Something isn't implemented in here\n"); +} + +EXPORT_SYMBOL(not_implemented); + +void setup_kernel_stack(void) +{ + struct sys_pt_regs regs1, regs2; + char *stack1, *stack2; + unsigned long s1, s2, n1, n2, off1, off2; + int size, i; + + size = get_one_stack(&stack1, ®s1); + if(get_one_stack(&stack2, ®s2) != size){ + printf("setup_kernel_stack : differing stack sizes\n"); + exit(1); + } + s1 = (unsigned long) stack1; + s2 = (unsigned long) stack2; + generic_stack = malloc(size); + generic_stack_size = size; + if(generic_stack == NULL){ + perror("setup_kernel_stack : allocating new stack"); + exit(1); + } + for(i = PAGE_SIZE - size; i < PAGE_SIZE - sizeof(void *); i++){ + /* This is horribly word-length- and byte-order-dependent */ + n1 = stack1[i] | (stack1[i + 1] << 8) | + (stack1[i + 2] << 16) | stack1[i + 3] << 24; + n2 = stack2[i] | (stack2[i + 1] << 8) | + (stack2[i + 2] << 16) | stack2[i + 3] << 24; + + /* Internal pointers have to be different on different + * stacks, and they have to point to the stack page. If not, + * then keep looking. + */ + if((n1 == n2) || ((n1 & PAGE_MASK) != s1) || + ((n2 & PAGE_MASK) != s2)) continue; + + /* The offsets have to be the same and they have to point + * within the used area of the stack. + */ + off1 = n1 & ~PAGE_MASK; + off2 = n2 & ~PAGE_MASK; + if((off1 == off2) && (off1 > PAGE_SIZE - size)){ + printf("Found a frame pointer on the stack\n"); + exit(1); + } + } + memcpy(generic_stack, &stack1[PAGE_SIZE - size], size); + if((munmap(stack1, PAGE_SIZE) < 0) || + (munmap(stack2, PAGE_SIZE) < 0)){ + perror("setup_kernel_stack : unmapping temp stacks"); + exit(1); + } + for(i = 0; i < sizeof(regs1.regs)/sizeof(regs1.regs[0]); i++){ + generic_regs.regs[i] = regs1.regs[i]; + generic_regs_mask.regs[i] = 0; + if((regs1.regs[i] == regs2.regs[i]) || + ((regs1.regs[i] & PAGE_MASK) != s1) || + ((regs2.regs[i] & PAGE_MASK) != s2)) continue; + off1 = regs1.regs[i] & ~PAGE_MASK; + off2 = regs2.regs[i] & ~PAGE_MASK; + if((off1 == off2) && (off1 >= PAGE_SIZE - size)){ + generic_regs.regs[i] = regs1.regs[i] - s1; + generic_regs_mask.regs[i] = 1; + } + } +} + +int user_context(unsigned long sp) +{ + return((sp & (PAGE_MASK << 1)) != current->thread.kernel_stack); +} + +int get_restore_regs(void *t) +{ + struct task_struct *task = t; + + return(task->thread.request.u.tracing.restore_regs); +} + +extern void remove_pid_file(void); +__exitcall(remove_pid_file); + +extern exitcall_t __exitcall_begin, __exitcall_end; + +void do_exitcalls(void) +{ + exitcall_t *call; + + call = &__exitcall_begin; + do { + (*call)(); + call++; + } while (call < &__exitcall_end); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/ptrace.c linux.ac/arch/um/kernel/ptrace.c --- linux.vanilla/arch/um/kernel/ptrace.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/ptrace.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/sched.h" +#include "linux/mm.h" +#include "linux/errno.h" +#include "linux/smp_lock.h" +#include "asm/ptrace.h" +#include "asm/uaccess.h" +#include "kern_util.h" + +int sys_ptrace(long request, long pid, long addr, long data) +{ + struct task_struct *child; + int i, ret; + + lock_kernel(); + ret = -EPERM; + if (request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->ptrace & PT_PTRACED) + goto out; + /* set the ptrace bit in the process flags. */ + current->ptrace |= PT_PTRACED; + ret = 0; + goto out; + } + ret = -ESRCH; + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + if (child) + get_task_struct(child); + read_unlock(&tasklist_lock); + if (!child) + goto out; + + ret = -EPERM; + if (pid == 1) /* you may not mess with init */ + goto out_tsk; + + if (request == PTRACE_ATTACH) { + if (child == current) + goto out_tsk; + if ((!child->dumpable || + (current->uid != child->euid) || + (current->uid != child->suid) || + (current->uid != child->uid) || + (current->gid != child->egid) || + (current->gid != child->sgid) || + (!cap_issubset(child->cap_permitted, current->cap_permitted)) || + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) + goto out_tsk; + /* the same process cannot be attached many times */ + if (child->ptrace & PT_PTRACED) + goto out_tsk; + child->ptrace |= PT_PTRACED; + + write_lock_irq(&tasklist_lock); + if (child->p_pptr != current) { + REMOVE_LINKS(child); + child->p_pptr = current; + SET_LINKS(child); + } + write_unlock_irq(&tasklist_lock); + + send_sig(SIGSTOP, child, 1); + ret = 0; + goto out_tsk; + } + ret = -ESRCH; + if (!(child->ptrace & PT_PTRACED)) + goto out_tsk; + if (child->state != TASK_STOPPED) { + if (request != PTRACE_KILL) + goto out_tsk; + } + if (child->p_pptr != current) + goto out_tsk; + switch (request) { + /* when I and D space are separate, these will need to be fixed. */ + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; + int copied; + + ret = -EIO; + if(overlaps_kernel(addr, sizeof(tmp))) break; + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + if (copied != sizeof(tmp)) + break; + ret = put_user(tmp,(unsigned long *) data); + break; + } + + /* read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: { + unsigned long tmp; + + ret = -EIO; + if ((addr & 3) || addr < 0) + break; + + tmp = 0; /* Default return condition */ + if(addr < 17*sizeof(long)){ + tmp = getreg(child, addr); + ret = put_user(tmp,(unsigned long *) data); + } + break; + } + + /* when I and D space are separate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + ret = -EIO; + if (access_process_vm(child, addr, &data, sizeof(data), + 1) != sizeof(data)) + break; + ret = 0; + break; + + case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + ret = -EIO; + if ((addr & 3) || addr < 0) + break; + + if (addr < 17*sizeof(long)) { + ret = putreg(child, addr, data); + break; + } + + break; + + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: { /* restart after signal. */ + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + if (request == PTRACE_SYSCALL) + child->ptrace |= PT_TRACESYS; + else + child->ptrace &= ~PT_TRACESYS; + child->exit_code = data; + wake_up_process(child); + ret = 0; + break; + } + +/* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: { + ret = 0; + if (child->state == TASK_ZOMBIE) /* already dead */ + break; + child->exit_code = SIGKILL; + wake_up_process(child); + break; + } + + case PTRACE_SINGLESTEP: { /* set the trap flag. */ + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + child->ptrace &= ~PT_TRACESYS; + child->ptrace |= PT_DTRACE; + child->exit_code = data; + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + break; + } + + case PTRACE_DETACH: { /* detach a process that was attached. */ + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); + child->exit_code = data; + write_lock_irq(&tasklist_lock); + REMOVE_LINKS(child); + child->p_pptr = child->p_opptr; + SET_LINKS(child); + write_unlock_irq(&tasklist_lock); + wake_up_process(child); + ret = 0; + break; + } + + case PTRACE_GETREGS: { /* Get all gp regs from the child. */ + if (!access_ok(VERIFY_WRITE, (unsigned *)data, 17*sizeof(long))) { + ret = -EIO; + break; + } + for ( i = 0; i < 17*sizeof(long); i += sizeof(long) ) { + __put_user(getreg(child, i),(unsigned long *) data); + data += sizeof(long); + } + ret = 0; + break; + } + + case PTRACE_SETREGS: { /* Set all gp regs in the child. */ + unsigned long tmp = 0; + if (!access_ok(VERIFY_READ, (unsigned *)data, 17*sizeof(long))) { + ret = -EIO; + break; + } + for ( i = 0; i < 17*sizeof(long); i += sizeof(long) ) { + __get_user(tmp, (unsigned long *) data); + putreg(child, i, tmp); + data += sizeof(long); + } + ret = 0; + break; + } + + case PTRACE_GETFPREGS: { /* Get the child FPU state. */ + ret = -EIO; + break; + } + + case PTRACE_SETFPREGS: { /* Set the child FPU state. */ + ret = -EIO; + break; + } + + default: + ret = -EIO; + break; + } + out_tsk: + free_task_struct(child); + out: + unlock_kernel(); + return ret; +} + +void syscall_trace(void) +{ + if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) + != (PT_PTRACED|PT_TRACESYS)) + return; + current->exit_code = SIGTRAP; + current->state = TASK_STOPPED; + notify_parent(current, SIGCHLD); + schedule(); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/reboot.c linux.ac/arch/um/kernel/reboot.c --- linux.vanilla/arch/um/kernel/reboot.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/reboot.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/sched.h" +#include "user_util.h" +#include "kern_util.h" +#include "kern.h" + +static void kill_off_processes(void) +{ + struct task_struct *p; + int me; + + me = getpid(); + for_each_task(p){ + if(p->thread.extern_pid != me) kill_pid(p->thread.extern_pid); + } + kill_pid(init_task.thread.extern_pid); +} + +void machine_restart(char * __unused) +{ + kill_off_processes(); + do_exitcalls(); + tracing_reboot(); + kill_pid(getpid()); +} + +void machine_power_off(void) +{ + kill_off_processes(); + do_exitcalls(); + tracing_halt(); + kill_pid(getpid()); +} + +void machine_halt(void) +{ + machine_power_off(); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/resource.c linux.ac/arch/um/kernel/resource.c --- linux.vanilla/arch/um/kernel/resource.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/resource.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/pci.h" + +unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, + unsigned long start, unsigned long size) +{ + return start; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/segment.c linux.ac/arch/um/kernel/segment.c --- linux.vanilla/arch/um/kernel/segment.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/segment.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/sched.h" +#include "linux/mm.h" +#include "asm/mmu_context.h" + +void release_segments(struct mm_struct *mm) +{ + struct mm_changes *changes = mm->context.segments; + + if(changes != NULL) free_page((unsigned long) changes); + mm->context.segments = NULL; +} + +void activate_mm(struct mm_struct *old_mm, struct mm_struct *new_mm) +{ + struct mm_changes *new; + + new = NULL; /* (struct mm_changes *) get_free_page(GFP_KERNEL); */ + new_mm->context.segments = new; + if(new == NULL) return; + new->count = 0; + new->barrier = -1; +} + +void copy_segments(struct task_struct *p, struct mm_struct *new_mm) +{ + activate_mm(p->mm, new_mm); + p->thread.mm_changes = 0; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/setup.c linux.ac/arch/um/kernel/setup.c --- linux.vanilla/arch/um/kernel/setup.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/setup.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "asm/processor.h" + +struct cpuinfo_um boot_cpu_data = { 0, 0, 0, 0 }; + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/signal_kern.c linux.ac/arch/um/kernel/signal_kern.c --- linux.vanilla/arch/um/kernel/signal_kern.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/signal_kern.c Thu Apr 12 17:43:20 2001 @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/stddef.h" +#include "linux/sys.h" +#include "linux/sched.h" +#include "linux/wait.h" +#include "linux/kernel.h" +#include "linux/smp_lock.h" +#include "linux/module.h" +#include "asm/signal.h" +#include "asm/uaccess.h" +#include "user_util.h" +#include "kern_util.h" +#include "kern.h" + +EXPORT_SYMBOL(block_signals); +EXPORT_SYMBOL(unblock_signals); + +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + /* First 32bits of unions are always present. */ + err |= __put_user(from->si_pid, &to->si_pid); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + +#define _S(nr) (1<<((nr)-1)) + +#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) + +/* + * OK, we're invoking a handler + */ +static int handle_signal(struct task_struct *task, unsigned long signr, + struct k_sigaction *ka, sigset_t *oldset, + unsigned long *error) +{ + __sighandler_t handler; + sigset_t save; + int ret = 0; + + if((error != NULL) && (*error != 0)){ + switch (*error) { + case -ERESTARTNOHAND: + *error = -EINTR; + break; + + case -ERESTARTSYS: + if (!(ka->sa.sa_flags & SA_RESTART)) { + *error = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + ret = 1; + break; + } + } + handler = ka->sa.sa_handler; + + save = *oldset; + + if (ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + + if (!(ka->sa.sa_flags & SA_NODEFER)) { + spin_lock_irq(&task->sigmask_lock); + sigorsets(&task->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(&task->blocked,signr); + recalc_sigpending(task); + spin_unlock_irq(&task->sigmask_lock); + } + + if(task->thread.npending == 1) panic("Too many queued signals"); + task->thread.signal.signal = signr; + task->thread.signal.sp = 0; + if (ka->sa.sa_flags & SA_ONSTACK) { + if (! on_sig_stack(UM_SP(¤t->thread.process_regs))) + task->thread.signal.sp = + current->sas_ss_sp + current->sas_ss_size; + } + + task->thread.signal.handler = (unsigned long) handler; + task->thread.npending = 1; + task->thread.saved_sigs = save; + + return(ret); +} + +/* + * Note that 'init' is a special process: it doesn't get signals it doesn't + * want to handle. Thus you cannot kill init even with a SIGKILL even by + * mistake. + * + * Note that we go through the signals twice: once to check the signals that + * the kernel can handle, and then we build all the user-level signal handling + * stack-frames in one go after that. + */ + +static int kern_do_signal(void *t, sigset_t *oldset, unsigned long *error, + int *again_out) +{ + struct task_struct *task; + siginfo_t info; + struct k_sigaction *ka; + int again; + + task = t; + if(task == NULL) task = current; + if (!oldset) + oldset = ¤t->blocked; + + if(again_out) *again_out = 0; + for (;;) { + unsigned long signr; + + spin_lock_irq(&task->sigmask_lock); + signr = dequeue_signal(&task->blocked, &info); + spin_unlock_irq(&task->sigmask_lock); + + if (!signr) + break; + + if ((task->ptrace & PT_PTRACED) && signr != SIGKILL) { + /* Let the debugger run. */ + task->exit_code = signr; + task->state = TASK_STOPPED; + notify_parent(task, SIGCHLD); + schedule(); + + /* We're back. Did the debugger cancel the sig? */ + if (!(signr = task->exit_code)) + continue; + task->exit_code = 0; + + /* The debugger continued. Ignore SIGSTOP. */ + if (signr == SIGSTOP) + continue; + + /* Update the siginfo structure. Is this good? */ + if (signr != info.si_signo) { + info.si_signo = signr; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = task->p_pptr->pid; + info.si_uid = task->p_pptr->uid; + } + + /* If the (new) signal is now blocked, requeue it. */ + if (sigismember(&task->blocked, signr)) { + send_sig_info(signr, &info, task); + continue; + } + } + + ka = &task->sig->action[signr-1]; + if (ka->sa.sa_handler == SIG_IGN) { + if (signr != SIGCHLD) + continue; + /* Check for SIGCHLD: it's special. */ + while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) + /* nothing */; + continue; + } + + if (ka->sa.sa_handler == SIG_DFL) { + int exit_code = signr; + + /* Init gets no signals it doesn't want. */ + if (task->pid == 1) + continue; + + switch (signr) { + case SIGCONT: case SIGCHLD: case SIGWINCH: + continue; + + case SIGTSTP: case SIGTTIN: case SIGTTOU: + if (is_orphaned_pgrp(task->pgrp)) + continue; + /* FALLTHRU */ + + case SIGSTOP: + task->state = TASK_STOPPED; + task->exit_code = signr; + if (!(task->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) + notify_parent(task, SIGCHLD); + schedule(); + continue; + + case SIGQUIT: case SIGILL: case SIGTRAP: + case SIGABRT: case SIGFPE: case SIGSEGV: + case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: + if(do_coredump(signr, NULL)) + exit_code |= 0x80; + /* FALLTHRU */ + + default: + sigaddset(&task->pending.signal, signr); + recalc_sigpending(task); + task->flags |= PF_SIGNALED; + do_exit(exit_code); + /* NOTREACHED */ + } + } + + /* Whee! Actually deliver the signal. */ + again = handle_signal(task, signr, ka, oldset, error); + if(again_out && (*again_out == 0)) *again_out = again; + return(1); + } + return(0); +} + +int do_signal(void *t, unsigned long *error, int *again_out) +{ + return(kern_do_signal(t, NULL, error, again_out)); +} + +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ +int +sys_sigsuspend(int history0, int history1, old_sigset_t mask) +{ + sigset_t saveset; + + mask &= _BLOCKABLE; + spin_lock_irq(¤t->sigmask_lock); + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (kern_do_signal(current, &saveset, NULL, NULL)) + return -EINTR; + } +} + +int +sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize) +{ + sigset_t saveset, newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + sigdelsetmask(&newset, ~_BLOCKABLE); + + spin_lock_irq(¤t->sigmask_lock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (kern_do_signal(current, &saveset, NULL, NULL)) + return -EINTR; + } +} + +void signal_deliverer(void) +{ + struct task_struct *task; + struct sys_pt_regs regs; + sigset_t sigs; + unsigned long handler; + int repeat, signal; + +#ifdef __SMP__ +#error signal_deliverer needs some SMP work +#else + task = current; +#endif + regs = task->thread.process_regs; + repeat = task->thread.repeat_syscall; + sigs = task->thread.saved_sigs; + signal = task->thread.signal.signal; + handler = task->thread.signal.handler; + task->thread.npending = 0; + signal_handler(task, handler, signal); + task->thread.process_regs = regs; + task->thread.repeat_syscall = repeat; + task->thread.saved_sigs = sigs; +} + +void set_sigreturn_syscall(int syscall) +{ + current->thread.sigreturn_syscall = syscall; +} + +int sys_sigreturn(struct sys_pt_regs regs) +{ + sigdelsetmask(¤t->thread.saved_sigs, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = current->thread.saved_sigs; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + UM_SYSCALL_NR(¤t->thread.process_regs) = + current->thread.sigreturn_syscall; + return(UM_SYSCALL_RET(®s)); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/signal_user.c linux.ac/arch/um/kernel/signal_user.c --- linux.vanilla/arch/um/kernel/signal_user.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/signal_user.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdlib.h> +#include <signal.h> +#include "user_util.h" +#include "user.h" + +static void change_signals(int type) +{ + sigset_t mask; + + sigemptyset(&mask); + sigaddset(&mask, SIGVTALRM); + sigaddset(&mask, SIGALRM); + sigaddset(&mask, SIGIO); + if(sigprocmask(type, &mask, NULL) < 0) + panic("Failed to change signal mask"); +} + +void block_signals(void) +{ + change_signals(SIG_BLOCK); +} + +void unblock_signals(void) +{ + change_signals(SIG_UNBLOCK); +} + +#define SIGIO_BIT 0 +#define SIGVTALRM_BIT 1 + +static int enable_mask(sigset_t *mask) +{ + int sigs; + + sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT; + sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT; + sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT; + return(sigs); +} + +int set_signals(int enable) +{ + sigset_t mask; + int ret; + + sigemptyset(&mask); + if(enable & (1 << SIGIO_BIT)) sigaddset(&mask, SIGIO); + if(enable & (1 << SIGVTALRM_BIT)){ + sigaddset(&mask, SIGVTALRM); + sigaddset(&mask, SIGALRM); + } + if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0) + panic("Failed to enable signals"); + ret = enable_mask(&mask); + sigemptyset(&mask); + if((enable & (1 << SIGIO_BIT)) == 0) sigaddset(&mask, SIGIO); + if((enable & (1 << SIGVTALRM_BIT)) == 0){ + sigaddset(&mask, SIGVTALRM); + sigaddset(&mask, SIGALRM); + } + if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0) + panic("Failed to block signals"); + return(ret); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/smp.c linux.ac/arch/um/kernel/smp.c --- linux.vanilla/arch/um/kernel/smp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/smp.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/sched.h" +#include "linux/threads.h" +#include "asm/smp.h" +#include "asm/processor.h" +#include "asm/spinlock.h" +#include "asm/softirq.h" +#include "asm/hardirq.h" +#include "user_util.h" +#include "kern_util.h" +#include "kern.h" + +#ifdef __SMP__ + +/* Total count of live CPUs */ +int smp_num_cpus = 0; + +/* The 'big kernel lock' */ +spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; + +/* Per CPU bogomips and other parameters */ +struct cpuinfo_um cpu_data[NR_CPUS]; + +/* which CPU maps to which logical number */ +int cpu_number_map[NR_CPUS]; + +spinlock_t um_bh_lock = SPIN_LOCK_UNLOCKED; + +atomic_t global_bh_count; +atomic_t global_bh_lock; + +unsigned char global_irq_holder = NO_PROC_ID; +unsigned volatile int global_irq_lock; + +/* Set when the idlers are all forked */ +int smp_threads_ready = 0; +int num_reschedules_sent = 0; + +void smp_send_reschedule(int cpu) +{ + num_reschedules_sent++; +} + +static void show(char * str) +{ + int cpu = smp_processor_id(); + + printk("\n%s, CPU %d:\n", str, cpu); +} + +#define MAXCOUNT 100000000 + +static inline void wait_on_bh(void) +{ + int count = MAXCOUNT; + do { + if (!--count) { + show("wait_on_bh"); + count = ~0; + } + /* nothing .. wait for the other bh's to go away */ + } while (atomic_read(&global_bh_count) != 0); +} + +/* + * This is called when we want to synchronize with + * bottom half handlers. We need to wait until + * no other CPU is executing any bottom half handler. + * + * Don't wait if we're already running in an interrupt + * context or are inside a bh handler. + */ +void synchronize_bh(void) +{ + if (atomic_read(&global_bh_count) && !in_interrupt()) + wait_on_bh(); +} + +void smp_send_stop(void) +{ + printk("Stopping all CPUs\n"); +} + +void smp_commence(void) +{ +} + +void smp_boot_cpus(void) +{ + if(ncpus < 1){ + printk("ncpus set to 1\n"); + ncpus = 1; + } + else if(ncpus > NR_CPUS){ + printk("ncpus can't be greater than NR_CPUS, set to %d\n", NR_CPUS); + ncpus = NR_CPUS; + } +} + +int setup_profiling_timer(unsigned int multiplier) +{ + printk("setup_profiling_timer\n"); + return(0); +} + +#endif + +int inited_cpus = 1; + +int pid_to_processor_id(int pid) +{ + int i; + + for(i=0;i<inited_cpus;i++){ + if(cpu_tasks[i].pid == pid) return(i); + } + panic("hard_smp_processor failed"); + return(-1); +} + +#ifdef __SMP__ +int hard_smp_processor_id(void) +{ + return(pid_to_processor_id(getpid())); +} +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/sys_call_table.c linux.ac/arch/um/kernel/sys_call_table.c --- linux.vanilla/arch/um/kernel/sys_call_table.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/sys_call_table.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,447 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/unistd.h" +#include "asm/signal.h" +#include "linux/sys.h" +#include "sysdep/syscalls.h" +#include "kern_util.h" + +extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_exit; +extern syscall_handler_t sys_fork; +extern syscall_handler_t sys_read; +extern syscall_handler_t sys_write; +extern syscall_handler_t sys_creat; +extern syscall_handler_t sys_link; +extern syscall_handler_t sys_unlink; +extern syscall_handler_t sys_chdir; +extern syscall_handler_t sys_time; +extern syscall_handler_t sys_mknod; +extern syscall_handler_t sys_chmod; +extern syscall_handler_t sys_lchown16; +extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_stat; +extern syscall_handler_t sys_lseek; +extern syscall_handler_t sys_getpid; +extern syscall_handler_t sys_mount; +extern syscall_handler_t sys_oldumount; +extern syscall_handler_t sys_setuid16; +extern syscall_handler_t sys_getuid16; +extern syscall_handler_t sys_stime; +extern syscall_handler_t sys_ptrace; +extern syscall_handler_t sys_alarm; +extern syscall_handler_t sys_fstat; +extern syscall_handler_t sys_pause; +extern syscall_handler_t sys_utime; +extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_access; +extern syscall_handler_t sys_nice; +extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_sync; +extern syscall_handler_t sys_kill; +extern syscall_handler_t sys_rename; +extern syscall_handler_t sys_mkdir; +extern syscall_handler_t sys_rmdir; +extern syscall_handler_t sys_pipe; +extern syscall_handler_t sys_times; +extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_brk; +extern syscall_handler_t sys_setgid16; +extern syscall_handler_t sys_getgid16; +extern syscall_handler_t sys_signal; +extern syscall_handler_t sys_geteuid16; +extern syscall_handler_t sys_getegid16; +extern syscall_handler_t sys_acct; +extern syscall_handler_t sys_umount; +extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_ioctl; +extern syscall_handler_t sys_fcntl; +extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_setpgid; +extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_olduname; +extern syscall_handler_t sys_umask; +extern syscall_handler_t sys_chroot; +extern syscall_handler_t sys_ustat; +extern syscall_handler_t sys_dup2; +extern syscall_handler_t sys_getppid; +extern syscall_handler_t sys_getpgrp; +extern syscall_handler_t sys_setsid; +extern syscall_handler_t sys_sigaction; +extern syscall_handler_t sys_sgetmask; +extern syscall_handler_t sys_ssetmask; +extern syscall_handler_t sys_setreuid16; +extern syscall_handler_t sys_setregid16; +extern syscall_handler_t sys_sigsuspend; +extern syscall_handler_t sys_sigpending; +extern syscall_handler_t sys_sethostname; +extern syscall_handler_t sys_setrlimit; +extern syscall_handler_t sys_old_getrlimit; +extern syscall_handler_t sys_getrusage; +extern syscall_handler_t sys_gettimeofday; +extern syscall_handler_t sys_settimeofday; +extern syscall_handler_t sys_getgroups16; +extern syscall_handler_t sys_setgroups16; +extern syscall_handler_t old_select; +extern syscall_handler_t sys_symlink; +extern syscall_handler_t sys_lstat; +extern syscall_handler_t sys_readlink; +extern syscall_handler_t sys_uselib; +extern syscall_handler_t sys_swapon; +extern syscall_handler_t sys_reboot; +extern syscall_handler_t old_readdir; +extern syscall_handler_t old_mmap; +extern syscall_handler_t sys_munmap; +extern syscall_handler_t sys_truncate; +extern syscall_handler_t sys_ftruncate; +extern syscall_handler_t sys_fchmod; +extern syscall_handler_t sys_fchown16; +extern syscall_handler_t sys_getpriority; +extern syscall_handler_t sys_setpriority; +extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_statfs; +extern syscall_handler_t sys_fstatfs; +extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_socketcall; +extern syscall_handler_t sys_syslog; +extern syscall_handler_t sys_setitimer; +extern syscall_handler_t sys_getitimer; +extern syscall_handler_t sys_newstat; +extern syscall_handler_t sys_newlstat; +extern syscall_handler_t sys_newfstat; +extern syscall_handler_t sys_uname; +extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_vhangup; +extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_wait4; +extern syscall_handler_t sys_swapoff; +extern syscall_handler_t sys_sysinfo; +extern syscall_handler_t sys_ipc; +extern syscall_handler_t sys_fsync; +extern syscall_handler_t sys_sigreturn; +extern syscall_handler_t sys_clone; +extern syscall_handler_t sys_setdomainname; +extern syscall_handler_t sys_newuname; +extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_adjtimex; +extern syscall_handler_t sys_mprotect; +extern syscall_handler_t sys_sigprocmask; +extern syscall_handler_t sys_create_module; +extern syscall_handler_t sys_init_module; +extern syscall_handler_t sys_delete_module; +extern syscall_handler_t sys_get_kernel_syms; +extern syscall_handler_t sys_quotactl; +extern syscall_handler_t sys_getpgid; +extern syscall_handler_t sys_fchdir; +extern syscall_handler_t sys_bdflush; +extern syscall_handler_t sys_sysfs; +extern syscall_handler_t sys_personality; +extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_setfsuid16; +extern syscall_handler_t sys_setfsgid16; +extern syscall_handler_t sys_llseek; +extern syscall_handler_t sys_getdents; +extern syscall_handler_t sys_select; +extern syscall_handler_t sys_flock; +extern syscall_handler_t sys_msync; +extern syscall_handler_t sys_readv; +extern syscall_handler_t sys_writev; +extern syscall_handler_t sys_getsid; +extern syscall_handler_t sys_fdatasync; +extern syscall_handler_t sys_sysctl; +extern syscall_handler_t sys_mlock; +extern syscall_handler_t sys_munlock; +extern syscall_handler_t sys_mlockall; +extern syscall_handler_t sys_munlockall; +extern syscall_handler_t sys_sched_setparam; +extern syscall_handler_t sys_sched_getparam; +extern syscall_handler_t sys_sched_setscheduler; +extern syscall_handler_t sys_sched_getscheduler; +extern syscall_handler_t sys_sched_yield; +extern syscall_handler_t sys_sched_get_priority_max; +extern syscall_handler_t sys_sched_get_priority_min; +extern syscall_handler_t sys_sched_rr_get_interval; +extern syscall_handler_t sys_nanosleep; +extern syscall_handler_t sys_mremap; +extern syscall_handler_t sys_setresuid16; +extern syscall_handler_t sys_getresuid16; +extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_query_module; +extern syscall_handler_t sys_poll; +extern syscall_handler_t sys_nfsservctl; +extern syscall_handler_t sys_setresgid16; +extern syscall_handler_t sys_getresgid16; +extern syscall_handler_t sys_prctl; +extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_rt_sigaction; +extern syscall_handler_t sys_rt_sigprocmask; +extern syscall_handler_t sys_rt_sigpending; +extern syscall_handler_t sys_rt_sigtimedwait; +extern syscall_handler_t sys_rt_sigqueueinfo; +extern syscall_handler_t sys_rt_sigsuspend; +extern syscall_handler_t sys_pread; +extern syscall_handler_t sys_pwrite; +extern syscall_handler_t sys_chown16; +extern syscall_handler_t sys_getcwd; +extern syscall_handler_t sys_capget; +extern syscall_handler_t sys_capset; +extern syscall_handler_t sys_sigaltstack; +extern syscall_handler_t sys_sendfile; +extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_vfork; +extern syscall_handler_t sys_getrlimit; +extern syscall_handler_t sys_mmap2; +extern syscall_handler_t sys_truncate64; +extern syscall_handler_t sys_ftruncate64; +extern syscall_handler_t sys_stat64; +extern syscall_handler_t sys_lstat64; +extern syscall_handler_t sys_fstat64; +extern syscall_handler_t sys_lchown; +extern syscall_handler_t sys_getuid; +extern syscall_handler_t sys_getgid; +extern syscall_handler_t sys_geteuid; +extern syscall_handler_t sys_getegid; +extern syscall_handler_t sys_setreuid; +extern syscall_handler_t sys_setregid; +extern syscall_handler_t sys_getgroups; +extern syscall_handler_t sys_setgroups; +extern syscall_handler_t sys_fchown; +extern syscall_handler_t sys_setresuid; +extern syscall_handler_t sys_getresuid; +extern syscall_handler_t sys_setresgid; +extern syscall_handler_t sys_getresgid; +extern syscall_handler_t sys_chown; +extern syscall_handler_t sys_setuid; +extern syscall_handler_t sys_setgid; +extern syscall_handler_t sys_setfsuid; +extern syscall_handler_t sys_setfsgid; +extern syscall_handler_t sys_pivot_root; +extern syscall_handler_t sys_mincore; +extern syscall_handler_t sys_madvise; + +extern syscall_handler_t um_mount; + +syscall_handler_t *sys_call_table[] = { + [ 0 ] = sys_ni_syscall, + [ __NR_exit ] = sys_exit, + [ __NR_fork ] = sys_fork, + [ __NR_read ] = sys_read, + [ __NR_write ] = sys_write, + + /* These three are declared differently in asm/unistd.h */ + [ __NR_open ] = (syscall_handler_t *) sys_open, + [ __NR_close ] = (syscall_handler_t *) sys_close, + [ __NR_waitpid ] = (syscall_handler_t *) sys_waitpid, + [ __NR_creat ] = sys_creat, + [ __NR_link ] = sys_link, + [ __NR_unlink ] = sys_unlink, + + /* declared differently in kern_util.h */ + [ __NR_execve ] = (syscall_handler_t *) sys_execve, + [ __NR_chdir ] = sys_chdir, + [ __NR_time ] = sys_time, + [ __NR_mknod ] = sys_mknod, + [ __NR_chmod ] = sys_chmod, + [ __NR_lchown ] = sys_lchown16, + [ __NR_break ] = sys_ni_syscall, + [ __NR_oldstat ] = sys_stat, + [ __NR_lseek ] = sys_lseek, + [ __NR_getpid ] = sys_getpid, + [ __NR_mount ] = um_mount, + [ __NR_umount ] = sys_oldumount, + [ __NR_setuid ] = sys_setuid16, + [ __NR_getuid ] = sys_getuid16, + [ __NR_stime ] = sys_stime, + [ __NR_ptrace ] = sys_ptrace, + [ __NR_alarm ] = sys_alarm, + [ __NR_oldfstat ] = sys_fstat, + [ __NR_pause ] = sys_pause, + [ __NR_utime ] = sys_utime, + [ __NR_stty ] = sys_ni_syscall, + [ __NR_gtty ] = sys_ni_syscall, + [ __NR_access ] = sys_access, + [ __NR_nice ] = sys_nice, + [ __NR_ftime ] = sys_ni_syscall, + [ __NR_sync ] = sys_sync, + [ __NR_kill ] = sys_kill, + [ __NR_rename ] = sys_rename, + [ __NR_mkdir ] = sys_mkdir, + [ __NR_rmdir ] = sys_rmdir, + + /* Declared differently in asm/unistd.h */ + [ __NR_dup ] = (syscall_handler_t *) sys_dup, + [ __NR_pipe ] = sys_pipe, + [ __NR_times ] = sys_times, + [ __NR_prof ] = sys_ni_syscall, + [ __NR_brk ] = sys_brk, + [ __NR_setgid ] = sys_setgid16, + [ __NR_getgid ] = sys_getgid16, + [ __NR_signal ] = sys_signal, + [ __NR_geteuid ] = sys_geteuid16, + [ __NR_getegid ] = sys_getegid16, + [ __NR_acct ] = sys_acct, + [ __NR_umount2 ] = sys_umount, + [ __NR_lock ] = sys_ni_syscall, + [ __NR_ioctl ] = sys_ioctl, + [ __NR_fcntl ] = sys_fcntl, + [ __NR_mpx ] = sys_ni_syscall, + [ __NR_setpgid ] = sys_setpgid, + [ __NR_ulimit ] = sys_ni_syscall, + [ __NR_oldolduname ] = sys_olduname, + [ __NR_umask ] = sys_umask, + [ __NR_chroot ] = sys_chroot, + [ __NR_ustat ] = sys_ustat, + [ __NR_dup2 ] = sys_dup2, + [ __NR_getppid ] = sys_getppid, + [ __NR_getpgrp ] = sys_getpgrp, + [ __NR_setsid ] = sys_setsid, + [ __NR_sigaction ] = sys_sigaction, + [ __NR_sgetmask ] = sys_sgetmask, + [ __NR_ssetmask ] = sys_ssetmask, + [ __NR_setreuid ] = sys_setreuid16, + [ __NR_setregid ] = sys_setregid16, + [ __NR_sigsuspend ] = sys_sigsuspend, + [ __NR_sigpending ] = sys_sigpending, + [ __NR_sethostname ] = sys_sethostname, + [ __NR_setrlimit ] = sys_setrlimit, + [ __NR_getrlimit ] = sys_old_getrlimit, + [ __NR_getrusage ] = sys_getrusage, + [ __NR_gettimeofday ] = sys_gettimeofday, + [ __NR_settimeofday ] = sys_settimeofday, + [ __NR_getgroups ] = sys_getgroups16, + [ __NR_setgroups ] = sys_setgroups16, + [ __NR_select ] = old_select, + [ __NR_symlink ] = sys_symlink, + [ __NR_oldlstat ] = sys_lstat, + [ __NR_readlink ] = sys_readlink, + [ __NR_uselib ] = sys_uselib, + [ __NR_swapon ] = sys_swapon, + [ __NR_reboot ] = sys_reboot, + [ __NR_readdir ] = old_readdir, + [ __NR_mmap ] = old_mmap, + [ __NR_munmap ] = sys_munmap, + [ __NR_truncate ] = sys_truncate, + [ __NR_ftruncate ] = sys_ftruncate, + [ __NR_fchmod ] = sys_fchmod, + [ __NR_fchown ] = sys_fchown16, + [ __NR_getpriority ] = sys_getpriority, + [ __NR_setpriority ] = sys_setpriority, + [ __NR_profil ] = sys_ni_syscall, + [ __NR_statfs ] = sys_statfs, + [ __NR_fstatfs ] = sys_fstatfs, + [ __NR_ioperm ] = sys_ni_syscall, + [ __NR_socketcall ] = sys_socketcall, + [ __NR_syslog ] = sys_syslog, + [ __NR_setitimer ] = sys_setitimer, + [ __NR_getitimer ] = sys_getitimer, + [ __NR_stat ] = sys_newstat, + [ __NR_lstat ] = sys_newlstat, + [ __NR_fstat ] = sys_newfstat, + [ __NR_olduname ] = sys_uname, + [ __NR_iopl ] = sys_ni_syscall, + [ __NR_vhangup ] = sys_vhangup, + [ __NR_idle ] = sys_ni_syscall, + [ __NR_wait4 ] = sys_wait4, + [ __NR_swapoff ] = sys_swapoff, + [ __NR_sysinfo ] = sys_sysinfo, + [ __NR_ipc ] = sys_ipc, + [ __NR_fsync ] = sys_fsync, + [ __NR_sigreturn ] = sys_sigreturn, + [ __NR_clone ] = sys_clone, + [ __NR_setdomainname ] = sys_setdomainname, + [ __NR_uname ] = sys_newuname, + [ __NR_adjtimex ] = sys_adjtimex, + [ __NR_mprotect ] = sys_mprotect, + [ __NR_sigprocmask ] = sys_sigprocmask, + [ __NR_create_module ] = sys_create_module, + [ __NR_init_module ] = sys_init_module, + [ __NR_delete_module ] = sys_delete_module, + [ __NR_get_kernel_syms ] = sys_get_kernel_syms, + [ __NR_quotactl ] = sys_quotactl, + [ __NR_getpgid ] = sys_getpgid, + [ __NR_fchdir ] = sys_fchdir, + [ __NR_bdflush ] = sys_bdflush, + [ __NR_sysfs ] = sys_sysfs, + [ __NR_personality ] = sys_personality, + [ __NR_afs_syscall ] = sys_ni_syscall, + [ __NR_setfsuid ] = sys_setfsuid16, + [ __NR_setfsgid ] = sys_setfsgid16, + [ __NR__llseek ] = sys_llseek, + [ __NR_getdents ] = sys_getdents, + [ __NR__newselect ] = sys_select, + [ __NR_flock ] = sys_flock, + [ __NR_msync ] = sys_msync, + [ __NR_readv ] = sys_readv, + [ __NR_writev ] = sys_writev, + [ __NR_getsid ] = sys_getsid, + [ __NR_fdatasync ] = sys_fdatasync, + [ __NR__sysctl ] = sys_sysctl, + [ __NR_mlock ] = sys_mlock, + [ __NR_munlock ] = sys_munlock, + [ __NR_mlockall ] = sys_mlockall, + [ __NR_munlockall ] = sys_munlockall, + [ __NR_sched_setparam ] = sys_sched_setparam, + [ __NR_sched_getparam ] = sys_sched_getparam, + [ __NR_sched_setscheduler ] = sys_sched_setscheduler, + [ __NR_sched_getscheduler ] = sys_sched_getscheduler, + [ __NR_sched_yield ] = sys_sched_yield, + [ __NR_sched_get_priority_max ] = sys_sched_get_priority_max, + [ __NR_sched_get_priority_min ] = sys_sched_get_priority_min, + [ __NR_sched_rr_get_interval ] = sys_sched_rr_get_interval, + [ __NR_nanosleep ] = sys_nanosleep, + [ __NR_mremap ] = sys_mremap, + [ __NR_setresuid ] = sys_setresuid16, + [ __NR_getresuid ] = sys_getresuid16, + [ __NR_vm86 ] = sys_ni_syscall, + [ __NR_query_module ] = sys_query_module, + [ __NR_poll ] = sys_poll, + [ __NR_nfsservctl ] = sys_nfsservctl, + [ __NR_setresgid ] = sys_setresgid16, + [ __NR_getresgid ] = sys_getresgid16, + [ __NR_prctl ] = sys_prctl, + [ __NR_rt_sigreturn ] = sys_ni_syscall, + [ __NR_rt_sigaction ] = sys_rt_sigaction, + [ __NR_rt_sigprocmask ] = sys_rt_sigprocmask, + [ __NR_rt_sigpending ] = sys_rt_sigpending, + [ __NR_rt_sigtimedwait ] = sys_rt_sigtimedwait, + [ __NR_rt_sigqueueinfo ] = sys_rt_sigqueueinfo, + [ __NR_rt_sigsuspend ] = sys_rt_sigsuspend, + [ __NR_pread ] = sys_pread, + [ __NR_pwrite ] = sys_pwrite, + [ __NR_chown ] = sys_chown16, + [ __NR_getcwd ] = sys_getcwd, + [ __NR_capget ] = sys_capget, + [ __NR_capset ] = sys_capset, + [ __NR_sigaltstack ] = sys_sigaltstack, + [ __NR_sendfile ] = sys_sendfile, + [ __NR_getpmsg ] = sys_ni_syscall, + [ __NR_putpmsg ] = sys_ni_syscall, + [ __NR_vfork ] = sys_vfork, + [ __NR_ugetrlimit ] = sys_getrlimit, + [ __NR_mmap2 ] = sys_mmap2, + [ __NR_truncate64 ] = sys_truncate64, + [ __NR_ftruncate64 ] = sys_ftruncate64, + [ __NR_stat64 ] = sys_stat64, + [ __NR_lstat64 ] = sys_lstat64, + [ __NR_fstat64 ] = sys_fstat64, + ARCH_SYSCALLS, + [ LAST_SYSCALL + 1 ... NR_syscalls ] = + (syscall_handler_t *) sys_ni_syscall +}; + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/syscall_kern.c linux.ac/arch/um/kernel/syscall_kern.c --- linux.vanilla/arch/um/kernel/syscall_kern.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/syscall_kern.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/sched.h" +#include "linux/file.h" +#include "linux/smp_lock.h" +#include "linux/mm.h" +#include "linux/utsname.h" +#include "linux/msg.h" +#include "linux/shm.h" +#include "linux/sys.h" +#include "linux/unistd.h" +#include "asm/mman.h" +#include "asm/uaccess.h" +#include "asm/ipc.h" +#include "kern_util.h" +#include "user_util.h" + +long um_mount(char * dev_name, char * dir_name, char * type, + unsigned long new_flags, void * data) +{ + if(type == NULL) type = ""; + return(sys_mount(dev_name, dir_name, type, new_flags, data)); +} + +long sys_fork(void) +{ + long ret; + + current->thread.forking = 1; + ret = do_fork(SIGCHLD, 0, NULL, 0); + current->thread.forking = 0; + return(ret); +} + +long sys_clone(unsigned long clone_flags, unsigned long newsp) +{ + long ret; + + current->thread.forking = 1; + ret = do_fork(clone_flags, newsp, NULL, 0); + current->thread.forking = 0; + return(ret); +} + +long sys_vfork(void) +{ + long ret; + + current->thread.forking = 1; + ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0); + current->thread.forking = 0; + return(ret); +} + +/* common code for old and new mmaps */ +static inline long do_mmap2( + unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + int error = -EBADF; + struct file * file = NULL; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + goto out; + } + + down_write(¤t->mm->mmap_sem); + error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + up_write(¤t->mm->mmap_sem); + + if (file) + fput(file); + out: + return error; +} + +long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + return do_mmap2(addr, len, prot, flags, fd, pgoff); +} + +/* + * Perform the select(nd, in, out, ex, tv) and mmap() system + * calls. Linux/i386 didn't use to be able to handle more than + * 4 system call parameters, so these system calls used a memory + * block for parameter passing.. + */ + +struct mmap_arg_struct { + unsigned long addr; + unsigned long len; + unsigned long prot; + unsigned long flags; + unsigned long fd; + unsigned long offset; +}; + +int old_mmap(struct mmap_arg_struct *arg) +{ + struct mmap_arg_struct a; + int err = -EFAULT; + + if (copy_from_user(&a, arg, sizeof(a))) + goto out; + + err = -EINVAL; + if (a.offset & ~PAGE_MASK) + goto out; + + err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); + out: + return err; +} +/* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way unix traditionally does this, though. + */ +int sys_pipe(unsigned long * fildes) +{ + int fd[2]; + int error; + + error = do_pipe(fd); + if (!error) { + if (copy_to_user(fildes, fd, 2*sizeof(int))) + error = -EFAULT; + } + return error; +} + +int sys_pause(void) +{ + current->state = TASK_INTERRUPTIBLE; + schedule(); + return -ERESTARTNOHAND; +} + +int sys_sigaction(int sig, const struct old_sigaction *act, + struct old_sigaction *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +struct sel_arg_struct { + unsigned long n; + fd_set *inp, *outp, *exp; + struct timeval *tvp; +}; + +int old_select(struct sel_arg_struct *arg) +{ + struct sel_arg_struct a; + + if (copy_from_user(&a, arg, sizeof(a))) + return -EFAULT; + /* sys_select() does the appropriate kernel locking */ + return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); +} + +/* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. + * + * This is really horribly ugly. + */ +int sys_ipc (uint call, int first, int second, + int third, void *ptr, long fifth) +{ + int version, ret; + + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + switch (call) { + case SEMOP: + return sys_semop (first, (struct sembuf *)ptr, second); + case SEMGET: + return sys_semget (first, second, third); + case SEMCTL: { + union semun fourth; + if (!ptr) + return -EINVAL; + if (get_user(fourth.__pad, (void **) ptr)) + return -EFAULT; + return sys_semctl (first, second, third, fourth); + } + + case MSGSND: + return sys_msgsnd (first, (struct msgbuf *) ptr, + second, third); + case MSGRCV: + switch (version) { + case 0: { + struct ipc_kludge tmp; + if (!ptr) + return -EINVAL; + + if (copy_from_user(&tmp, + (struct ipc_kludge *) ptr, + sizeof (tmp))) + return -EFAULT; + return sys_msgrcv (first, tmp.msgp, second, + tmp.msgtyp, third); + } + default: + panic("msgrcv with version != 0"); + return sys_msgrcv (first, + (struct msgbuf *) ptr, + second, fifth, third); + } + case MSGGET: + return sys_msgget ((key_t) first, second); + case MSGCTL: + return sys_msgctl (first, second, (struct msqid_ds *) ptr); + + case SHMAT: + switch (version) { + default: { + ulong raddr; + ret = sys_shmat (first, (char *) ptr, second, &raddr); + if (ret) + return ret; + return put_user (raddr, (ulong *) third); + } + case 1: /* iBCS2 emulator entry point */ + if (!segment_eq(get_fs(), get_ds())) + return -EINVAL; + return sys_shmat (first, (char *) ptr, second, (ulong *) third); + } + case SHMDT: + return sys_shmdt ((char *)ptr); + case SHMGET: + return sys_shmget (first, second, third); + case SHMCTL: + return sys_shmctl (first, second, + (struct shmid_ds *) ptr); + default: + return -EINVAL; + } +} + +int sys_uname(struct old_utsname * name) +{ + int err; + if (!name) + return -EFAULT; + down_read(&uts_sem); + err=copy_to_user(name, &system_utsname, sizeof (*name)); + up_read(&uts_sem); + return err?-EFAULT:0; +} + +int sys_olduname(struct oldold_utsname * name) +{ + int error; + + if (!name) + return -EFAULT; + if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) + return -EFAULT; + + down_read(&uts_sem); + + error = __copy_to_user(&name->sysname,&system_utsname.sysname, + __OLD_UTS_LEN); + error |= __put_user(0,name->sysname+__OLD_UTS_LEN); + error |= __copy_to_user(&name->nodename,&system_utsname.nodename, + __OLD_UTS_LEN); + error |= __put_user(0,name->nodename+__OLD_UTS_LEN); + error |= __copy_to_user(&name->release,&system_utsname.release, + __OLD_UTS_LEN); + error |= __put_user(0,name->release+__OLD_UTS_LEN); + error |= __copy_to_user(&name->version,&system_utsname.version, + __OLD_UTS_LEN); + error |= __put_user(0,name->version+__OLD_UTS_LEN); + error |= __copy_to_user(&name->machine,&system_utsname.machine, + __OLD_UTS_LEN); + error |= __put_user(0,name->machine+__OLD_UTS_LEN); + + up_read(&uts_sem); + + error = error ? -EFAULT : 0; + + return error; +} + +int sys_sigaltstack(const stack_t *uss, stack_t *uoss) +{ + unsigned long old_sp = current->sas_ss_sp; + int old_size = current->sas_ss_size, res; + + res = do_sigaltstack(uss, uoss, UM_SP(¤t->thread.process_regs)); + if((res == 0) || (current->sas_ss_sp != old_sp) || + (current->sas_ss_size != old_size)){ + res = setup_altstack(current->sas_ss_sp, + current->sas_ss_size); + } + return(res); +} + +int nsyscalls = 0; + +long execute_syscall(struct sys_pt_regs regs) +{ + long res; + int syscall; + + current->thread.nsyscalls++; + nsyscalls++; + syscall = UM_SYSCALL_NR(®s); + if(syscall == -1) + panic("syscall thread activated without a system call"); + if((syscall >= NR_syscalls) || (syscall < 0)) + return(-ENOSYS); + res = (*sys_call_table[syscall])(regs); + return(res); +} + +spinlock_t syscall_lock = SPIN_LOCK_UNLOCKED; + +void lock_syscall(void) +{ + spin_lock(&syscall_lock); +} + +void unlock_syscall(void) +{ + spin_unlock(&syscall_lock); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/syscall_user.c linux.ac/arch/um/kernel/syscall_user.c --- linux.vanilla/arch/um/kernel/syscall_user.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/syscall_user.c Sun Apr 15 22:56:45 2001 @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +/* XXX FIXME : Ensure that SIGIO and SIGVTALRM can't happen immediately + * after setting up syscall stack + * SIGIO and SIGVTALRM should block SIGUSR2 + * block SIGVTALRM in any code that's under wait_for_stop + */ + +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sched.h> +#include <signal.h> +#include <errno.h> +#include <sys/wait.h> +#include <sys/ptrace.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <asm/unistd.h> +#include <asm/page.h> +#include <asm/ptrace.h> +#include "user_util.h" +#include "kern_util.h" +#include "user.h" +#include "sysdep/ptrace.h" + +struct { + int syscall; + int pid; + int result; + struct timeval start; + struct timeval end; +} syscall_record[1024]; + +int syscall_index = 0; + +void process_stack_handler(int sig) +{ + signal_deliverer(); +} + +int alt_stack_handler(void *arg) +{ + ptrace(PTRACE_TRACEME, 0, 0, 0); + kill(getpid(), SIGSTOP); + signal_deliverer(); + return(0); +} + +int syscall_handler(void *unused) +{ + struct sys_pt_regs *regs; + long result; + int index, syscall, again; + + kill(getpid(), SIGSTOP); + syscall_trace(); + lock_syscall(); + if(syscall_index == 1024) syscall_index = 0; + index = syscall_index; + syscall_index++; + unlock_syscall(); + regs = process_state(NULL, NULL, NULL); + syscall = UM_SYSCALL_NR(regs); + syscall_record[index].syscall = UM_SYSCALL_NR(regs); + syscall_record[index].pid = current_pid(); + syscall_record[index].result = 0xdeadbeef; + gettimeofday(&syscall_record[index].start, NULL); + result = execute_syscall(*regs); + again = 0; + if((result == -ERESTARTNOHAND) || (result == -ERESTARTSYS) || + (result == -ERESTARTNOINTR)) + do_signal(NULL, &result, &again); + UM_SYSCALL_RET(regs) = result; + set_repeat_syscall(again); + syscall_trace(); + syscall_record[index].result = UM_SYSCALL_RET(regs); + gettimeofday(&syscall_record[index].end, NULL); + ret_from_sys_call(NULL); + if(have_signals(NULL, 0)) probe_stack(UM_SP(regs)); + /* XXX + * This is a race, set_user_thread has to be called with signals off + */ + set_user_thread(NULL, 1, 1); + return(0); +} + +int exit_kernel(int pid, void *task, int *signal_out) +{ + void *stack; + struct sys_pt_regs *regs; + unsigned long sp; + int tracing, again, n, restore; + + tracing = 1; + *signal_out = 0; + again = get_repeat_syscall(task); + set_repeat_syscall(0); + restore = get_restore_regs(task); + if(restore){ + regs = process_state(task, NULL, NULL); + if(ptrace(PTRACE_SETREGS, pid, 0, regs) < 0) + tracer_panic("Couldn't restore registers"); + } + if(have_signals(task, 0)) + *signal_out = SIGUSR2; + else if(have_signals(task, 1)){ + regs = altstack_state(task, &stack, &n); + if(ptrace(PTRACE_SETREGS, pid, 0, regs) < 0) + panic("Couldn't set alternate stack state"); + sp = um_virt_to_phys(task, UM_SP(regs)); + memcpy((void *) sp, stack, n); + } + else if(again){ + regs = syscall_state(task, &stack, &n); + if(ptrace(PTRACE_SETREGS, pid, 0, regs) < 0) + panic("Couldn't restart system call"); + memcpy((void *) UM_SP(regs), stack, n); + tracing = 0; + } + return(tracing); +} + +extern unsigned long _stext, _etext; + +int do_syscall(void *task, int pid) +{ + void *stack; + struct sys_pt_regs *regs, proc_regs; + int syscall, n; + + if(ptrace(PTRACE_GETREGS, pid, 0, &proc_regs) < 0) + tracer_panic("Couldn't read registers"); + + syscall = UM_SYSCALL_NR(&proc_regs); + if(syscall < 1) return(0); + + if((syscall != __NR_sigreturn) && + ((unsigned long *) proc_regs.regs[EIP] >= &_stext) && + ((unsigned long *) proc_regs.regs[EIP] <= &_etext)) + tracer_panic("I'm tracing myself and I can't get out"); + regs = process_state(task, NULL, NULL); + if(syscall == __NR_sigreturn){ + set_sigreturn_syscall(UM_SYSCALL_NR(regs)); + UM_SYSCALL_NR(regs) = __NR_sigreturn; + } + else *regs = proc_regs; + set_tracing(task, 0); + regs = syscall_state(task, &stack, &n); + if(ptrace(PTRACE_SETREGS, pid, 0, regs) < 0) + tracer_panic("Couldn't set system call state"); + memcpy((void *) UM_SP(regs), stack, n); + + if((ptrace(PTRACE_POKEUSER, pid, UM_SYSCALL_NR_OFFSET, + __NR_getpid) < 0) || + (ptrace(PTRACE_CONT, pid, 0, 0) < 0)){ + printk("Failed to change syscall number to __NR_getpid\n"); + if(errno == EIO){ + printk("You probably didn't apply the ptrace patch " + "to your hosting kernel\n"); + } + else printk("errno = %d\n", errno); + tracer_panic("do_syscall : Couldn't force getpid"); + } + return(1); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/time.c linux.ac/arch/um/kernel/time.c --- linux.vanilla/arch/um/kernel/time.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/time.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdio.h> +#include <unistd.h> + +/* This mess is because timeradd and timersub are protected by __USE_GNU + * on Debian systems + */ +#ifndef __USE_GNU +#define __REM_GNU +#define __USE_GNU +#include <sys/time.h> +#endif +#ifdef __REM_GNU +#undef __USE_GNU +#undef __REM_GNU +#endif + +#include <sys/time.h> +#include <signal.h> +#include <errno.h> +#include "user_util.h" +#include "kern_util.h" +#include "user.h" + +void timer_handler(int sig, void *sc, int usermode) +{ + timer_irq(usermode); +} + +static struct itimerval profile_interval; + +void get_profile_timer(void) +{ + getitimer(ITIMER_PROF, &profile_interval); +} + +static void set_interval(int timer_type) +{ + struct itimerval interval; + + interval.it_interval.tv_sec = 0; + interval.it_interval.tv_usec = 1000000/hz(); + interval.it_value.tv_sec = 0; + interval.it_value.tv_usec = 1000000/hz(); + if(setitimer(timer_type, &interval, NULL) == -1) + panic("setitimer failed - errno = %d\n", errno); +} + +void idle_timer(void) +{ + if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR) + panic("Couldn't unset SIGVTALRM handler"); + set_handler(SIGALRM, irq_handler, 0, SIGUSR1, SIGVTALRM, + SIGALRM, SIGIO, SIGUSR2, -1); + set_interval(ITIMER_REAL); +} + +void time_init(void) +{ + if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR) + panic("Couldn't set SIGVTALRM handler"); + set_interval(ITIMER_VIRTUAL); +} + +void set_timers(int set_signal) +{ + __sighandler_t handler; + struct sigaction action; + + if(set_signal){ + if(signal(SIGVTALRM, irq_handler) == SIG_ERR) + panic("Couldn't set SIGVTALRM handler"); + set_interval(ITIMER_VIRTUAL); + } + handler = signal(SIGPROF, SIG_DFL); + action.sa_handler = handler; + sigemptyset(&action.sa_mask); + action.sa_flags = SA_RESTART; + action.sa_restorer = NULL; + if(sigaction(SIGPROF, &action, NULL) < 0) + panic("sigaction failed"); + if(setitimer(ITIMER_PROF, &profile_interval, NULL) == -1) + panic("setitimer ITIMER_PROF failed - errno = %d\n", errno); +} + +struct timeval local_offset = { 0, 0 }; + +void do_gettimeofday(struct timeval *tv) +{ + gettimeofday(tv, NULL); + timeradd(tv, &local_offset, tv); +} + +void do_settimeofday(struct timeval *tv) +{ + struct timeval now; + + gettimeofday(&now, NULL); + timersub(tv, &now, &local_offset); +} + +void idle_sleep(int secs) +{ + struct timespec ts; + + ts.tv_sec = secs; + ts.tv_nsec = 0; + nanosleep(&ts, &ts); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/time_kern.c linux.ac/arch/um/kernel/time_kern.c --- linux.vanilla/arch/um/kernel/time_kern.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/time_kern.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/unistd.h" +#include "linux/stddef.h" +#include "linux/spinlock.h" +#include "linux/sched.h" +#include "linux/interrupt.h" +#include "linux/init.h" +#include "linux/delay.h" +#include "asm/param.h" +#include "asm/current.h" +#include "kern_util.h" +#include "user_util.h" + +extern rwlock_t xtime_lock; + +extern struct timeval xtime; + +int hz(void) +{ + return(HZ); +} + +void timer_irq(int user_mode) +{ + do_IRQ(TIMER_IRQ, user_mode); +} + +void boot_timer_handler(int sig) +{ + struct pt_regs regs; + + regs.user_mode = 0; + do_timer(®s); +} + +void timer(int irq, void *dev, struct pt_regs *regs) +{ + do_timer(regs); + write_lock(&xtime_lock); + gettimeofday(&xtime, NULL); + write_unlock(&xtime_lock); +} + +void __delay(unsigned long time) +{ + int i; + + for(i=0;i<loops_per_jiffy * HZ;i++) ; +} + +extern void __udelay(unsigned long usecs) +{ + int i, n; + + n = (loops_per_jiffy * HZ) / 1000000; + for(i=0;i<n;i++) ; +} + +extern void __const_udelay(unsigned long usecs) +{ + int i, n; + + n = (loops_per_jiffy * HZ) / 1000000; + for(i=0;i<n;i++) ; +} + +int __init timer_init(void) +{ + int err; + + if((err = request_irq(TIMER_IRQ, timer, SA_INTERRUPT, "timer", + NULL)) != 0) + printk("timer_init : request_irq failed - errno = %d\n", -err); + return(0); +} + +__initcall(timer_init); + + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/tlb.c linux.ac/arch/um/kernel/tlb.c --- linux.vanilla/arch/um/kernel/tlb.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/tlb.c Sun Apr 15 22:52:23 2001 @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/sched.h" +#include "linux/malloc.h" +#include "linux/bootmem.h" +#include "asm/pgtable.h" +#include "asm/pgalloc.h" +#include "asm/a.out.h" +#include "asm/processor.h" +#include "asm/mmu_context.h" +#include "user_util.h" +#include "kern_util.h" +#include "kern.h" + +struct mm_struct kernel_maps = EMPTY_MM; + +static void fix_range(struct mm_struct *proc_mm, unsigned long start_addr, + unsigned long end_addr, int force) +{ + struct mm_struct *mm; + pgd_t *npgd; + pmd_t *npmd; + pte_t *npte; + unsigned long addr; + int r, w, x; + + if((current->thread.extern_pid != -1) && + (current->thread.extern_pid != getpid())) + panic("fix_range fixing wrong address space"); + mm = proc_mm; + if(mm == NULL){ + start_addr = start_vm; + end_addr = end_vm; + } + for(addr=start_addr;addr<end_addr;){ + if(force){ + struct vm_area_struct *vma; + vma = find_vma(&kernel_maps, addr); + if(vma && (vma->vm_start <= addr)){ + addr = vma->vm_end; + continue; + } + } + + if((addr >= start_vm) && (addr < end_vm)) mm = &init_mm; + else mm = proc_mm; + npgd = pgd_offset(mm, addr); + npmd = pmd_offset(npgd, addr); + if(pmd_present(*npmd)){ + npte = pte_offset(npmd, addr); + r = pte_read(*npte); + w = pte_write(*npte); + x = pte_exec(*npte); + if(!pte_dirty(*npte)) w = 0; + if(!pte_young(*npte)){ + r = 0; + w = 0; + } + if(mm == &init_mm){ + unsigned long mask; + + mask = PAGE_MASK | _PAGE_NEWPAGE | + _PAGE_NEWPROT; + if((pte_val(*npte) & ~mask) == + pgprot_val(PAGE_KERNEL)){ + r = 1; + w = 1; + x = 1; + } + else if((pte_val(*npte) & ~mask) == + pgprot_val(PAGE_KERNEL_RO)){ + r = 1; + w = 0; + x = 1; + } + } + if(force || !pte_present(*npte) || pte_newpage(*npte)){ + munmap((void *) addr, PAGE_SIZE); + if(pte_present(*npte)) + map(addr, + page_address(pte_page(*npte)), + PAGE_SIZE, r, w, x); + } + else if(pte_newprot(*npte)) + protect(addr, PAGE_SIZE, r, w, x); + if((mm == proc_mm) && pte_present(*npte)) + *npte = pte_mkuptodate(*npte); + addr += PAGE_SIZE; + } + else { + unsigned long end, len; + + end = (addr + PMD_SIZE) & PMD_MASK; + len = end - addr; + if(force || pmd_newpage(*npmd)){ + munmap((void *) addr, len); + if(mm == proc_mm) + pmd_mkuptodate(*npmd); + } + addr += len; + } + } +} + +void init_flush_vm(void) +{ + pgd_t *npgd; + pmd_t *npmd; + pte_t *npte; + unsigned long addr; + int r, w, x; + + for(addr=start_vm;addr<end_vm;){ + npgd = pgd_offset(&init_mm, addr); + npmd = pmd_offset(npgd, addr); + if(pmd_present(*npmd)){ + npte = pte_offset(npmd, addr); + if(pte_present(*npte)){ + unsigned long mask; + + mask = PAGE_MASK | _PAGE_NEWPAGE | + _PAGE_NEWPROT; + r = pte_read(*npte); + w = pte_write(*npte); + x = pte_exec(*npte); + if((pte_val(*npte) & ~mask) == + pgprot_val(PAGE_KERNEL)){ + r = 1; + w = 1; + x = 1; + } + else if((pte_val(*npte) & ~mask) == + pgprot_val(PAGE_KERNEL_RO)){ + r = 1; + w = 0; + x = 1; + } + map(addr, page_address(pte_page(*npte)), + PAGE_SIZE, r, w, x); + } + addr += PAGE_SIZE; + } + else addr += PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE; + } +} + +int barriers = 0; +int page_changes = 0; +int page_flushes = 0; +int range_flushes = 0; + +void flush_tlb_range(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + if((mm != NULL) && ((mm != current->mm) || + (atomic_read(&mm->mm_count) > 1))){ + struct mm_changes *changes = mm->context.segments; + if(changes != NULL){ + changes->barrier = changes->count; + barriers++; + } + } + if(mm == current->mm) fix_range(mm, start, end, 0); +} + +void flush_tlb_mm(struct mm_struct *mm) +{ + flush_tlb_range(mm, 0, STACK_TOP); +} + +void flush_tlb_kernel_vm(void) +{ + if(current->mm != NULL){ + struct mm_changes *changes = current->mm->context.segments; + if((changes == NULL) || + (current->thread.mm_changes < changes->barrier) || + (changes->count - current->thread.mm_changes > + CHANGES_PAGES(changes))){ + range_flushes++; + fix_range(current->mm, 0, STACK_TOP, 0); + if(changes != NULL) + current->thread.mm_changes = changes->count; + } + else { + unsigned long page; + int i; + + for(i=current->thread.mm_changes;i<changes->count;i++){ + page_flushes++; + page = CHANGES_PAGE(changes, i); + fix_range(current->mm, page, + page + PAGE_SIZE, 0); + } + current->thread.mm_changes = changes->count; + } + } + fix_range(NULL, start_vm, end_vm, 0); +} + +void flush_tlb_page(struct vm_area_struct *vma, unsigned long address) +{ + address &= PAGE_MASK; +#ifdef notdef + if((vma->vm_mm != current->mm) || + (atomic_read(&vma->vm_mm->mm_count) > 1)){ + struct mm_changes *changes = vma->vm_mm->segments; + if(changes != NULL){ + ADD_CHANGE(changes, address); + page_changes++; + } + } +#endif + if(vma->vm_mm == current->mm) + fix_range(current->mm, address, address + PAGE_SIZE, 0); +} + +void flush_tlb_all(void) +{ + flush_tlb_range(current->mm, 0, STACK_TOP); +} + +void force_flush_all(void) +{ + fix_range(current->mm, 0, STACK_TOP, 1); +} + +static pgprot_t vm_prot(char r, char w, char x, char p) +{ + if((r == '-') && (w == '-') && (x == '-')) return(PAGE_NONE); + else if(w == '-') return(PAGE_READONLY); + else if(p == 'p') return(PAGE_COPY); + else return(PAGE_SHARED); +} + +static unsigned short vm_flags(char r, char w, char x, char p) +{ + unsigned short flags; + + flags = 0; + if(r == 'r') flags |= VM_READ; + if(w == 'w') flags |= VM_WRITE; + if(x == 'x') flags |= VM_EXEC; + if(p == '-') flags |= VM_SHARED; + return(flags); +} + +static struct vm_area_struct *process_vmas; +static int num_process_vmas = 0; + +void add_perm_vma(unsigned long start, unsigned long end, char rperm, + char wperm, char xperm, char private) +{ + struct vm_area_struct *vma; + + vma = &process_vmas[num_process_vmas++]; + *vma = ((struct vm_area_struct) { + &kernel_maps, start, end, NULL, + vm_prot(rperm, wperm, xperm, private), + vm_flags(rperm, wperm, xperm, private), 0, NULL, NULL, NULL, + NULL, NULL, 0, NULL, 0 + }); + insert_vm_struct(&kernel_maps, vma); +} + +void add_process_vmas(void) +{ + unsigned long start, end; + void *maps; + char rperm, wperm, xperm, private; + + if(process_vmas == NULL){ + int count = 0; + + maps = open_maps(); + while(read_map(maps, NULL, NULL, NULL, NULL, NULL, NULL)) + count++; + close_maps(maps); + process_vmas = malloc((count + 1) * sizeof(*process_vmas)); + if(process_vmas == NULL) + panic("Couldn't allocate process_vmas"); + } + maps = open_maps(); + while(read_map(maps, &start, &end, &rperm, &wperm, &xperm, &private)){ + if(start == 0x40000000) continue; + add_perm_vma(start, end, rperm, wperm, xperm, private); + } + close_maps(maps); +} + +pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address) +{ + return(pgd_offset(mm, address)); +} + +pmd_t *pmd_offset_proc(pgd_t *pgd, unsigned long address) +{ + return(pmd_offset(pgd, address)); +} + +pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address) +{ + return(pte_offset(pmd, address)); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/trap_kern.c linux.ac/arch/um/kernel/trap_kern.c --- linux.vanilla/arch/um/kernel/trap_kern.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/trap_kern.c Sun Apr 15 22:53:42 2001 @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/kernel.h" +#include "linux/sched.h" +#include "linux/mm.h" +#include "linux/spinlock.h" +#include "linux/config.h" +#include "linux/init.h" +#include "asm/semaphore.h" +#include "asm/pgtable.h" +#include "asm/pgalloc.h" +#include "asm/a.out.h" +#include "user_util.h" +#include "kern_util.h" +#include "kern.h" +#include "chan.h" +#include "debug.h" + +extern int nsyscalls; + +unsigned long segv(unsigned long address, unsigned long ip, int is_write, + int is_user) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + struct siginfo si; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long page; + int ok; + + if(mm == NULL) panic("Segfault with no mm"); + down_read(&mm->mmap_sem); + vma = find_vma(mm, address); + ok = 1; + if(!vma) ok = 0; + else if(vma->vm_start > address){ + if((vma->vm_flags & VM_STACK_FLAGS) != VM_STACK_FLAGS) ok = 0; + else if(expand_stack(vma, address)) ok = 0; + } + if(!ok){ + if(current->thread.fault_addr != NULL){ + unsigned long new_ip = + (unsigned long) current->thread.fault_addr; + current->thread.fault_addr = (void *) address; + up_read(&mm->mmap_sem); + return(new_ip); + } + if(!is_user) + panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", + address, ip); + si.si_signo = SIGSEGV; + si.si_code = SEGV_ACCERR; + si.si_addr = (void *) address; + current->thread.cr2 = address; + current->thread.err = is_write; + force_sig_info(SIGSEGV, &si, current); + up_read(&mm->mmap_sem); + return(0); + } + page = address & PAGE_MASK; + if(page == (unsigned long) current + PAGE_SIZE) + panic("Kernel stack overflow"); + pgd = pgd_offset(mm, page); + pmd = pmd_offset(pgd, page); + if(current->thread.starting_exec && pmd_present(*pmd) && + pte_present(*pte_offset(pmd, page))){ + up_read(&mm->mmap_sem); + flush_tlb_range(mm, page, page + PAGE_SIZE); + return(0); + } + do { + switch (handle_mm_fault(mm, vma, address, is_write)) { + case 1: + current->min_flt++; + break; + case 2: + current->maj_flt++; + break; + case 0: + up_read(&mm->mmap_sem); + force_sigbus(); + return(0); + default: + up_read(&mm->mmap_sem); + force_sig(SIGBUS, current); + return(0); + } + pte = pte_offset(pmd, page); + pte_mkyoung(*pte); + if(is_write) pte_mkdirty(*pte); + } while(is_write && !pte_write(*pte)); + if(is_write && !pte_write(*pte)) panic("page not writeable"); + if(!is_write && !pte_present(*pte)){ + printk("Page disappeared while handling fault"); + force_sigbus(); + } + flush_tlb_page(vma, page); + up_read(&mm->mmap_sem); + return(0); +} + +void relay_signal(int sig, void *sc, int usermode) +{ + force_sig(sig, current); +} + +void trap_init(void) +{ +} + +spinlock_t trap_lock = SPIN_LOCK_UNLOCKED; + +void lock_trap(void) +{ + spin_lock(&trap_lock); +} + +void unlock_trap(void) +{ + spin_unlock(&trap_lock); +} + +extern int debugger_pid; +extern int debugger_fd; + +#ifdef CONFIG_PT_PROXY + +void debugger_signal(int status, pid_t pid) +{ + debugger_proxy(status, pid); +} + +void child_signal(pid_t pid, int status) +{ + child_proxy(pid, status); +} + +struct io_chan gdb_chan = XTERM_IO_CHAN_INIT(0, "", 1, INIT_STATIC); +char *gdb_init = "xterm"; + +static void gdb_announce(char *dev_name, int dev) +{ + printf("gdb assigned device '%s'\n", dev_name); +} + +static struct chan_opts opts = { + announce: gdb_announce, + dev: -1, + xterm_title: "UML kernel debugger", + raw_pty: 0 +}; + +void signal_usr1(int sig) +{ + if(debugger_pid != -1){ + printk("The debugger is already running\n"); + return; + } + if(parse_chan_pair(gdb_init, 0, &gdb_chan, INIT_ONE, &opts)) return; + debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd); + init_proxy(debugger_pid, 0, 0); +} + +int init_ptrace_proxy(int idle_pid, int startup, int stop) +{ + int pid, status; + + if(parse_chan_pair(gdb_init, 0, &gdb_chan, INIT_ONE, &opts)){ + ptrace(PTRACE_CONT, idle_pid, 0, 0); + return(-1); + } + pid = start_debugger(linux_prog, startup, stop, &debugger_fd); + status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT); + if(pid < 0){ + ptrace(PTRACE_CONT, idle_pid, 0, 0); + return(-1); + } + init_proxy(pid, 1, status); + return(pid); +} + +void exit_debugger(void) +{ + close_chan_pair(&gdb_chan); +} + +__exitcall(exit_debugger); + +#else + +void debugger_signal(int status, pid_t pid){ } +void child_signal(pid_t pid, int status){ } +int init_ptrace_proxy(int idle_pid, int startup, int stop) +{ + printk("debug requested when CONFIG_PT_PROXY is off\n"); + wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT); + ptrace(PTRACE_CONT, idle_pid, 0, 0); + return(-1); +} + +void signal_usr1(int sig) +{ + printk("debug requested when CONFIG_PT_PROXY is off\n"); +} + +#endif +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/trap_user.c linux.ac/arch/um/kernel/trap_user.c --- linux.vanilla/arch/um/kernel/trap_user.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/trap_user.c Sun Apr 15 22:56:45 2001 @@ -0,0 +1,355 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdio.h> +#include <unistd.h> +#include <signal.h> +#include <errno.h> +#include <sched.h> +#include <fcntl.h> +#include <sys/ptrace.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include <asm/page.h> +#include <asm/unistd.h> +#include <asm/ptrace.h> +#include "user_util.h" +#include "kern_util.h" +#include "user.h" +#include "sysdep/sigcontext.h" + +static void signal_segv(int sig) +{ + write(2, "Seg fault in signals\n", strlen("Seg fault in signals\n")); + for(;;) ; +} + +int detach(int pid) +{ + return(ptrace(PTRACE_DETACH, pid, 0, SIGSTOP)); +} + +int debug = 0; +int debug_stop = 1; + +static int signal_tramp(void *arg) +{ + int (*proc)(void *); + + if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) + panic("ptrace PTRACE_TRACEME failed"); + signal(SIGUSR1, SIG_IGN); + signal(SIGSEGV, sig_handler); + set_timers(0); + set_cmdline("(idle thread)"); + set_init_pid(getpid()); + proc = arg; + return((*proc)(NULL)); +} + +#ifdef __SMP__ +#error need to make these arrays +#endif + +int debugger_pid = -1; +int debugger_fd = -1; + +struct { + unsigned long address; + int is_write; + int pid; + unsigned long sp; + int is_user; +} segfault_record[1024]; + +int segfault_index = 0; + +struct { + int pid; + int signal; + unsigned long addr; + struct timeval time; +} signal_record[1024]; + +int signal_index = 0; +int nsignals = 0; +int debug_trace = 0; +extern int io_nsignals, io_count, intr_count; + +extern void signal_usr1(int sig); + +struct timeval last_exit; +int last_status; +int last_pid; + +int tracing_pid; + +int signals(int (*init_proc)(void *), void *sp) +{ + void *task = NULL; + unsigned long eip = 0; + int status, pid = 0, sig, cont_type, tracing = 0, op = 0; + int last_index, proc_id, save_errno = 0; + + setup_kernel_stack(); + calc_sigframe_size(); + signal(SIGSEGV, signal_segv); + signal(SIGUSR1, signal_usr1); + signal(SIGPIPE, SIG_IGN); + tracing_pid = getpid(); + printk("tracing thread pid = %d\n", tracing_pid); + pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc); + if(debug) debugger_pid = init_ptrace_proxy(pid, 1, debug_stop); + set_cmdline("(tracing thread)"); + if(debug_trace){ + printk("Tracing thread pausing to be attached\n"); + stop(); + } + while(1){ + if((pid = waitpid(-1, &status, WUNTRACED)) <= 0){ + if(errno != ECHILD){ + printk("wait failed - errno = %d\n", errno); + } + continue; + } + save_errno = errno; + if(pid == debugger_pid){ + if(WIFEXITED(status) || WIFSIGNALED(status)) + debugger_pid = -1; + debugger_signal(status, external_pid(NULL)); + continue; + } + nsignals++; + if(WIFEXITED(status)){ + gettimeofday(&last_exit, NULL); + last_status = WIFEXITED(status); + last_pid = pid; + } +#ifdef notdef + { + printk("Child %d exited with status %d\n", pid, + WEXITSTATUS(status)); + } +#endif + else if(WIFSIGNALED(status)){ + sig = WTERMSIG(status); + if(sig != 9){ + printk("Child %d exited with signal %d\n", pid, + sig); + } + } + else if(WIFSTOPPED(status)){ + sig = WSTOPSIG(status); + if(signal_index == 1024){ + signal_index = 0; + last_index = 1023; + } + else last_index = signal_index - 1; + if(((sig == SIGPROF) || (sig == SIGVTALRM) || + (sig == SIGALRM)) && + (signal_record[last_index].signal == sig) && + (signal_record[last_index].pid == pid)) + signal_index = last_index; + signal_record[signal_index].pid = pid; + gettimeofday(&signal_record[signal_index].time, NULL); + eip = ptrace(PTRACE_PEEKUSER, pid, EIP * 4, 0); + signal_record[signal_index].addr = eip; + signal_record[signal_index++].signal = sig; +#ifdef __SMP__ + proc_id = pid_to_processor_id(pid); + task = cpu_tasks[proc_id].task; +#else + proc_id = 0; + task = get_current_task(); +#endif + tracing = is_tracing(task); + switch(sig){ + case SIGUSR1: + sig = 0; + op = do_proc_op(task, proc_id); + switch(op){ + case OP_EXEC: + case OP_SWITCH: + continue; + case OP_TRACE_ON: + tracing = exit_kernel(pid, task, &sig); + break; + case OP_TRACE_OFF: + tracing = 0; + break; + case OP_REBOOT: + case OP_HALT: + ptrace(PTRACE_KILL, pid, 0, 0); + if(debugger_pid != -1){ + kill(debugger_pid, SIGKILL); + close(debugger_fd); + } + return(op == OP_REBOOT); + case OP_NONE: + printk("Detaching pid %d\n", pid); + detach(pid); + continue; + default: + break; + } + break; + case SIGSTOP: + if(debugger_pid != -1) + child_signal(pid, status); + continue; + case SIGBUS: + case SIGILL: + tracer_panic("Unexpectedly got signal %d in " + "signals", sig); + break; + case SIGTRAP: + sig = 0; + if(switching_modes(task)) tracing = 0; + else { + if(!do_syscall(task, pid)){ + if(!tracing) + child_signal(pid, + status); + else { + tracing = 0; + sig = SIGTRAP; + break; + } + } + continue; + } + break; + case SIGCONT: + break; + case SIGSEGV: + case SIGIO: + case SIGALRM: + case SIGVTALRM: + case SIGFPE: + tracing = 0; + break; + case SIGPROF: + if(tracing) sig = 0; + break; + case SIGCHLD: + sig = 0; + break; + default: + if(debugger_pid != -1){ + child_signal(pid, status); + continue; + } + break; + } + set_tracing(task, tracing); + if(tracing != 0){ + if(singlestepping(task)) + cont_type = PTRACE_SINGLESTEP; + else cont_type = PTRACE_SYSCALL; + } + else cont_type = PTRACE_CONT; + + /* XXX This doesn't close the hole totally - there + * is still a race between the ptrace and the child + * continuing. This thread needs separate data from + * the children. + */ + errno = save_errno; + if(ptrace(cont_type, pid, 0, sig) != 0){ + sleep(1); + if(ptrace(cont_type, pid, 0, sig) != 0){ + tracer_panic("ptrace failed to " + "continue process - " + "errno = %d\n", + errno); + } + } + } + } + return(0); +} + +int nsegfaults = 0; + +void segv_handler(int sig, void *sc, int usermode) +{ + struct sigcontext_struct *context = sc; + unsigned long new_ip; + int index; + + lock_trap(); + index = segfault_index++; + if(segfault_index == 1024) segfault_index = 0; + unlock_trap(); + nsegfaults++; + segfault_record[index].address = SC_FAULT_ADDR(context); + segfault_record[index].pid = getpid(); + segfault_record[index].is_write = SC_FAULT_WRITE(context); + segfault_record[index].sp = context->esp_at_signal; + segfault_record[index].is_user = usermode; + new_ip = segv(SC_FAULT_ADDR(context), context->eip, + SC_FAULT_WRITE(context), usermode); + if(new_ip != 0) context->eip = new_ip; +} + +static void (*handlers[])(int, void *, int) = { + [ SIGTRAP ] relay_signal, + [ SIGFPE ] relay_signal, + [ SIGSEGV] segv_handler, + [ SIGIO ] sigio_handler, + [ SIGVTALRM ] timer_handler, + [ SIGALRM ] timer_handler +}; + +void irq_handler(int sig) +{ + struct sigcontext_struct *sc; + int user_mode, save_errno = errno; + + sc = (struct sigcontext_struct *) (&sig + 1); + user_mode = user_context(sc->esp_at_signal); + change_sig(SIGUSR1, 1); + (*handlers[sig])(sig, sc, user_mode); + if(user_mode) interrupt_end(); + block_signals(); + change_sig(SIGUSR1, 0); + set_user_thread(NULL, user_mode, 0); + errno = save_errno; +} + +void sig_handler(int sig) +{ + struct sigcontext_struct *sc; + int user_mode, save_errno = errno; + + sc = (struct sigcontext_struct *) (&sig + 1); + user_mode = user_context(sc->esp_at_signal); + change_sig(SIGUSR1, 1); + unblock_signals(); + if(user_mode){ + fill_in_regs(process_state(NULL, NULL, NULL), sc); + } + (*handlers[sig])(sig, sc, user_mode); + if(user_mode){ + interrupt_end(); + block_signals(); + } + change_sig(SIGUSR1, 0); + set_user_thread(NULL, user_mode, 0); + errno = save_errno; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/um_arch.c linux.ac/arch/um/kernel/um_arch.c --- linux.vanilla/arch/um/kernel/um_arch.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/um_arch.c Sun Apr 15 22:51:14 2001 @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/sched.h" +#include "linux/mm.h" +#include "linux/types.h" +#include "linux/tty.h" +#include "linux/init.h" +#include "linux/bootmem.h" +#include "linux/spinlock.h" +#include "linux/utsname.h" +#include "asm/page.h" +#include "asm/pgtable.h" +#include "asm/ptrace.h" +#include "asm/elf.h" +#include "asm/user.h" +#include "ubd_user.h" +#include "asm/current.h" +#include "user_util.h" +#include "kern_util.h" +#include "kern.h" +#include "mprot.h" + +unsigned long _stext; + +#define DEFAULT_COMMAND_LINE "root=/dev/ubd0" + +unsigned long thread_saved_pc(struct thread_struct *thread) +{ + panic("Someone should implement thread_saved_pc"); + return(0); +} + +int get_cpuinfo(char * buffer){ + char *p = buffer; + p += sprintf(p, "processor\t: user-mode\n"); + p += sprintf(p, "bogomips\t: %lu.%02lu\n", + loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ)) % 100); + p += sprintf(p, "host\t\t: %s\n", host_info); + + return(strlen(buffer)); +} + +pte_t * __bad_pagetable(void) +{ + panic("Someone should implement __bad_pagetable"); + return(NULL); +} + +extern void start_kernel(void); + +extern int debug; +extern int debug_stop; + +static int start_kernel_proc(void *unused) +{ + int pid; + + block_signals(); + pid = getpid(); + block_signals(); +#ifdef __SMP__ + cpu_tasks[0].pid = pid; + cpu_tasks[0].task = current; + smp_num_cpus = 1; +#else + current_task = &init_task_union.task; +#endif + if(debug) stop_pid(getpid()); + start_kernel(); + return(0); +} + +#define XSTRING(s) #s +#define STRING(s) XSTRING(s) + +int physmem_fd = -1; + +extern unsigned long high_physmem; + +unsigned long physmem; +unsigned long start_vm; +unsigned long end_vm; +int physmem_inode; + +int ncpus = 1; + +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define PFN_PHYS(x) ((x) << PAGE_SHIFT) + +static char *argv1_begin = NULL; +static char *argv1_end = NULL; + +#define ROUND_UP(addr) ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1) +#define ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK)) + +void set_cmdline(char *cmd) +{ + strcpy(argv1_begin, "["); + strncat(argv1_begin, cmd, argv1_end - argv1_begin - strlen("[]")); + strcat(argv1_begin, "]"); + memset(argv1_begin + strlen(argv1_begin), '\0', + argv1_end - argv1_begin - strlen(argv1_begin)); +} + +static char *usage_string = +"User Mode Linux v%s" +" available at http://user-mode-linux.sourceforge.net/\n\n" +"--help\n Prints this message\n" +"--version\n Gives the version number of the kernel\n" +"root=<file containing the root fs>\n" +" This is actually used by the generic kernel in exactly the same\n" +" way as in any other kernel. If you configure a number of block\n" +" devices and want to boot off something other than ubd0, you \n" +" would use something like:\n" +" root=/dev/ubd5\n\n" +"mem=<Amount of desired ram>\n" +" This controls how much \"physical\" memory the kernel allocates\n" +" for the system. The size is specified as a number followed by\n" +" one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n" +" This is not related to the amount of memory in the physical\n" +" machine. It can be more, and the excess, if it's ever used, will\n" +" just be swapped out.\n Example: mem=64M\n\n" +#ifdef CONFIG_SMP +"ncpus=<# of desired CPUs>\n" +" This tells an SMP kernel how many virtual processors to start.\n" +" Currently, this has no effect because SMP isn't enabled.\n\n" +#endif +"debugtrace\n" +" Causes the tracing thread to pause until it is attached by a\n" +" debugger and continued. This is mostly for debugging crashes\n" +" early during boot, and should be pretty much obsoleted by\n" +" the debug switch.\n\n" +"debug\n" +" Starts up the kernel under the control of gdb. See the \n" +" kernel debugging tutorial and the debugging session pages\n" +" at http://user-mode-linux.sourceforge.net/ for more information\n\n" +"umn=<ip-address>\n" +" This sets the ip address of the host side of the slip device \n" +" that the umn device configures. This is necessary if you want\n" +" to set up networking, but your local net isn't 192.168.0.x,\n" +" or you want to run multiple virtual machines on a network,\n" +" in which case, you need to assign different ip addresses to the\n" +" different machines.\n\n" +"ubd<n>=<filename>\n" +" This is used to associate a device with a file in the underlying\n" +" filesystem. Usually, there is a filesystem in the file, but \n" +" that's not required. Swap devices containing swap files can be\n" +" specified like this. Also, a file which doesn't contain a\n" +" filesystem can have its contents read in the virtual \n" +" machine by running dd on the device. n must be in the range\n" +" 0 to 7. Appending an 'r' to the number will cause that device\n" +" to be mounted read-only. For example ubd1r=./ext_fs\n\n"; + +static void Usage(void) +{ + printf(usage_string, system_utsname.release); + exit(0); +} + +extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end; +extern int debug_trace; + +void *brk_start; +int brk_fd; + +int linux_main(int argc, char **argv) +{ + unsigned long start_pfn, end_pfn, bootmap_size; + unsigned long physmem_size, virtmem_size; + unsigned int i, have_root, add; + char *retptr; + void *sp; + + remap_data(ROUND_DOWN(&_stext), ROUND_UP(&_etext)); + remap_data(ROUND_DOWN(&_sdata), ROUND_UP(&_edata)); + brk_start = sbrk(0); + remap_data(ROUND_DOWN(&__bss_start), ROUND_UP(brk_start)); + last_brk = (void *) brk_start; + brk_fd = create_vm_file(0); + + /* Create fake command line from argv[]. */ + have_root = 0; + physmem_size = 16 * 1024 * 1024; + virtmem_size = physmem_size; + for (i = 1; i < argc; i++){ + if((i == 1) && (argv[i][0] == ' ')) continue; + add = 1; + if(!strncmp(argv[i], "root=", strlen("root="))) have_root = 1; + else if(!strncmp(argv[i], "mem=", strlen("mem="))) + physmem_size = memparse(argv[i] + strlen("mem="), + &retptr); +#ifdef __SMP__ + else if(!strncmp(argv[i], "ncpus=", strlen("ncpus="))) + ncpus = strtoul(argv[i] + strlen("ncpus="), NULL, 10); +#endif + else if(!strcmp(argv[i], "debugtrace")) debug_trace = 1; + else if(!strncmp(argv[i], "debug", strlen("debug"))){ + debug = 1; + debug_stop = 1; + if(!strcmp(argv[i], "debug=go")){ + debug_stop = 0; + add = 0; + } + } +#ifdef CONFIG_PT_PROXY + else if(!strncmp(argv[i], "gdb=", strlen("gdb="))) + gdb_init = &argv[i][strlen("gdb=")]; +#endif + else if(!strncmp(argv[i], "umid=", strlen("umid="))){ + create_pid_file(&argv[i][strlen("umid=")]); + } + else if(!strcmp(argv[i], "--version")){ + printf("%s\n", system_utsname.release); + exit(0); + } + else if(!strcmp(argv[i], "--help")){ + Usage(); + } + if(add) add_arg(saved_command_line, argv[i]); + } + if(have_root == 0) add_arg(saved_command_line, DEFAULT_COMMAND_LINE); + + setup_machinename(system_utsname.machine); + + argv1_begin = argv[1]; + argv1_end = &argv[1][strlen(argv[1])]; + + add_process_vmas(); + unblock_shlib_mem(); + physmem = setup_memory(physmem_size + VMALLOC_OFFSET + virtmem_size, + physmem_size, &physmem_fd, &physmem_inode); + high_physmem = physmem + physmem_size; + start_vm = physmem + physmem_size + VMALLOC_OFFSET; + end_vm = start_vm + virtmem_size; + add_perm_vma(physmem, end_vm, 'r', 'w', 'x', '-'); + + start_pfn = PFN_UP(__pa(physmem)); + end_pfn = PFN_DOWN(__pa(high_physmem)); + bootmap_size = init_bootmem(start_pfn, end_pfn - start_pfn); + free_bootmem(__pa(physmem) + bootmap_size, + high_physmem - physmem - bootmap_size); + + init_task.thread.kernel_stack = (unsigned long) &init_task + + 2 * PAGE_SIZE; +#ifndef __SMP__ + current = &init_task; +#endif + protect(((unsigned long) &init_task) + PAGE_SIZE, PAGE_SIZE, 0, 0, 0); + stack_protections(init_task.thread.kernel_stack, 2 * PAGE_SIZE); + sp = (void *) init_task.thread.kernel_stack + 2 * PAGE_SIZE - + sizeof(unsigned long); + return(signals(start_kernel_proc, sp)); +} + +void setup_arch(char **cmdline_p) +{ + paging_init(); + strcpy(command_line, saved_command_line); + *cmdline_p = command_line; + setup_hostinfo(); +} + +void check_bugs(void) +{ + return; +} + +spinlock_t pid_lock = SPIN_LOCK_UNLOCKED; + +void lock_pid(void) +{ + spin_lock(&pid_lock); +} + +void unlock_pid(void) +{ + spin_unlock(&pid_lock); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/unmap.c linux.ac/arch/um/kernel/unmap.c --- linux.vanilla/arch/um/kernel/unmap.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/unmap.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdio.h> +#include <errno.h> +#include <sys/mman.h> +#include "user.h" + +int switcheroo(int fd, int prot, void *from, void *to, int size) +{ + if(munmap(to, size) < 0){ + return(-1); + } + if(mmap(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) != to){ + return(-1); + } + if(munmap(from, size) < 0){ + return(-1); + } + return(0); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/user_syms.c linux.ac/arch/um/kernel/user_syms.c --- linux.vanilla/arch/um/kernel/user_syms.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/user_syms.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,90 @@ +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <dirent.h> +#include <errno.h> +#include <utime.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/vfs.h> +#include "user_util.h" + +/* Had to steal this from linux/module.h because that file can't be included + * since this includes various user-level headers. + */ + +struct module_symbol +{ + unsigned long value; + const char *name; +}; + +/* Indirect stringification. */ + +#define __MODULE_STRING_1(x) #x +#define __MODULE_STRING(x) __MODULE_STRING_1(x) + +#if !defined(AUTOCONF_INCLUDED) + +#define __EXPORT_SYMBOL(sym,str) error config_must_be_included_before_module +#define EXPORT_SYMBOL(var) error config_must_be_included_before_module +#define EXPORT_SYMBOL_NOVERS(var) error config_must_be_included_before_module + +#elif !defined(CONFIG_MODULES) + +#define __EXPORT_SYMBOL(sym,str) +#define EXPORT_SYMBOL(var) +#define EXPORT_SYMBOL_NOVERS(var) + +#else + +#define __EXPORT_SYMBOL(sym, str) \ +const char __kstrtab_##sym[] \ +__attribute__((section(".kstrtab"))) = str; \ +const struct module_symbol __ksymtab_##sym \ +__attribute__((section("__ksymtab"))) = \ +{ (unsigned long)&sym, __kstrtab_##sym } + +#if defined(MODVERSIONS) || !defined(CONFIG_MODVERSIONS) +#define EXPORT_SYMBOL(var) __EXPORT_SYMBOL(var, __MODULE_STRING(var)) +#else +#define EXPORT_SYMBOL(var) __EXPORT_SYMBOL(var, __MODULE_STRING(__VERSIONED_SYMBOL(var))) +#endif + +#define EXPORT_SYMBOL_NOVERS(var) __EXPORT_SYMBOL(var, __MODULE_STRING(var)) + +#endif + +EXPORT_SYMBOL(__errno_location); + +EXPORT_SYMBOL(access); +EXPORT_SYMBOL(open); +EXPORT_SYMBOL(close); +EXPORT_SYMBOL(read); +EXPORT_SYMBOL(write); +EXPORT_SYMBOL(__xstat); +EXPORT_SYMBOL(__lxstat); +EXPORT_SYMBOL(lseek); +EXPORT_SYMBOL(chown); +EXPORT_SYMBOL(truncate); +EXPORT_SYMBOL(utime); +EXPORT_SYMBOL(chmod); +EXPORT_SYMBOL(rename); + +EXPORT_SYMBOL(symlink); +EXPORT_SYMBOL(link); +EXPORT_SYMBOL(unlink); +EXPORT_SYMBOL(readlink); + +EXPORT_SYMBOL(mkdir); +EXPORT_SYMBOL(rmdir); +EXPORT_SYMBOL(opendir); +EXPORT_SYMBOL(readdir); +EXPORT_SYMBOL(closedir); +EXPORT_SYMBOL(seekdir); +EXPORT_SYMBOL(telldir); + +EXPORT_SYMBOL(statfs); + +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(getuid); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/kernel/user_util.c linux.ac/arch/um/kernel/user_util.c --- linux.vanilla/arch/um/kernel/user_util.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/kernel/user_util.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,456 @@ +/* + * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <limits.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/ptrace.h> +#include <sys/mount.h> +#include <sys/utsname.h> +#include <ctype.h> +#include <signal.h> +#include <wait.h> +#include <errno.h> +#include <stdarg.h> +#include <sched.h> +#include <termios.h> +#include <string.h> +#include "user_util.h" +#include "kern_util.h" +#include "user.h" + +#define COMMAND_LINE_SIZE _POSIX_ARG_MAX + +char saved_command_line[COMMAND_LINE_SIZE] = { 0 }; +char command_line[COMMAND_LINE_SIZE] = { 0 }; + +void add_arg(char *cmd_line, char *arg) +{ + if (strlen(cmd_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) { + printf("add_arg: Too much command line!\n"); + exit(1); + } + if(strlen(cmd_line) > 0) strcat(cmd_line, " "); + strcat(cmd_line, arg); +} + +void *open_maps(void) +{ + void *maps; + + maps = fopen("/proc/self/maps", "r"); + if(!maps){ + perror("open_maps"); + exit(1); + } + return(maps); +} + +int read_map(void *maps, unsigned long *start_out, unsigned long *end_out, + char *r_out, char *w_out, char *x_out, char *p_out) +{ + unsigned int inode; + unsigned long long offset; + unsigned long start, end, major, minor; + int ret; + char r, w, x, p; + + ret = fscanf(maps, "%lx-%lx %c%c%c%c %Lx %lx:%lx %d%*[^\n]", &start, + &end, &r, &w, &x, &p, &offset, &major, &minor, + &inode); + if (ret == EOF) return 0; + else if (ret != 10){ + perror("Scanning a map line"); + exit(1); + } + if(start_out != NULL) *start_out = start; + if(end_out != NULL) *end_out = end; + if(r_out != NULL) *r_out = r; + if(w_out != NULL) *w_out = w; + if(x_out != NULL) *x_out = x; + if(p_out != NULL) *p_out = p; + return(1); +} + +void close_maps(void *maps) +{ + fclose(maps); +} + +int create_vm_file(unsigned long len) +{ + char tempname[32]; + int fd; + char zero; + + strcpy(tempname, "/tmp/vm_file-XXXXXX"); + if ((fd = mkstemp(tempname)) < 0) { + perror("open - cannot create /tmp/vm_file-XXXXXX"); + exit(1); + } + if(unlink(tempname) < 0){ + perror("unlink"); + exit(1); + } + if (fchmod(fd, 0777) < 0){ + perror("fchmod"); + exit(1); + } + if(len > 0){ + if(lseek(fd, len, SEEK_SET) < 0){ + perror("lseek"); + exit(1); + } + zero = 0; + if(write(fd, &zero, 1) != 1){ + perror("write"); + exit(1); + } + } + return(fd); +} + +void remap_data(void *segment_start, void *segment_end) +{ + void *addr; + unsigned long start, end, size; + void *maps; + int data, prot; + char r, w, x; + + maps= open_maps(); + while(read_map(maps, &start, &end, &r, &w, &x, NULL) != 0){ + if(((unsigned long) segment_start >= start) && + ((unsigned long) segment_end <= end)){ + prot = PROT_READ | PROT_WRITE | PROT_EXEC; + size = (unsigned long) segment_end - + (unsigned long) segment_start; + data = create_vm_file(size); + if((addr = mmap(NULL, size, PROT_WRITE | PROT_READ, + MAP_SHARED, data, 0)) < 0){ + perror("mapping new data segment"); + exit(1); + } + memcpy(addr, segment_start, size); + if(switcheroo(data, prot, addr, segment_start, + size) < 0){ + printf("switcheroo failed\n"); + exit(1); + } + close_maps(maps); + return; + } + } + fprintf(stderr, "remap_data couldn't find data segment 0x%lx - 0x%lx " + "in /proc/self/maps\n", (unsigned long) segment_start, + (unsigned long) segment_end); + exit(1); +} + +__u64 file_size(char *file) +{ + struct stat buf; + + if(stat(file, &buf) == -1){ + printk("Couldn't stat \"%s\" : errno = %d\n", file, errno); + return(-1); + } + if(S_ISBLK(buf.st_mode)){ + int size, fd; + + if((fd = open(file, O_RDONLY)) < 0){ + printk("Couldn't open \"%s\", errno = %d\n", file, + errno); + return(-1); + } + if(ioctl(fd, BLKGETSIZE, &size) < 0){ + printk("Couldn't get the block size of \"%s\", " + "errno = %d\n", file, errno); + close(fd); + return(-1); + } + size *= 512; + close(fd); + return(size); + } + return(buf.st_size); +} + +void stop(void) +{ + while(1) sleep(1000000); +} + +void stack_protections(unsigned long address, int len) +{ + mprotect((void *) address, len, PROT_READ | PROT_WRITE | PROT_EXEC); +} + +static unsigned long physmem_start = 0x50000000 + NESTING * 0x10000000; + +unsigned long setup_memory(unsigned long total_size, + unsigned long physmem_size, int *fd_out, + int *inode_out) +{ + void *mem; + struct stat buf; + + mem = mmap((void *) physmem_start, total_size, PROT_NONE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if(mem < 0){ + perror("Mapping all of memory"); + exit(1); + } + munmap(mem, total_size); + *fd_out = create_vm_file(physmem_size); + if(mmap(mem, physmem_size, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, *fd_out, 0) != mem){ + perror("Mapping physical memory"); + exit(1); + } + if(fstat(*fd_out, &buf) < 0){ + perror("Stat-ing phymem_fd"); + exit(1); + } + *inode_out = buf.st_ino; + return((unsigned long) mem); +} + +void map(unsigned long virt, void *p, unsigned long len, int r, + int w, int x) +{ + unsigned long phys = (unsigned long) p; + int prot; + + prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | + (x ? PROT_EXEC : 0); + if((phys < physmem) || (phys > high_physmem)) + panic("map : physmem out of range"); + phys -= physmem; + if(mmap((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, physmem_fd, + phys) != (void *) virt){ + panic("Error mapping a page - errno = %d", errno); + } +} + +void protect(unsigned long addr, unsigned long len, int r, int w, int x) +{ + int prot; + + prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | + (x ? PROT_EXEC : 0); + if(mprotect((void *) addr, len, prot) == -1){ + perror("Protecting a page"); + panic("protect failed"); + } +} + +int wait_for_stop(int pid, int sig, int cont_type) +{ + int status, ret; + + while(1){ + if(((ret = waitpid(pid, &status, WUNTRACED)) < 0) || + !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){ + if(ret < 0){ + if(errno == EINTR) continue; + printk("wait failed, errno = %d\n", errno); + } + else if(WIFEXITED(status)) + printk("process exited with status %d\n", + WEXITSTATUS(status)); + else if(WIFSIGNALED(status)) + printk("process exited with signal %d\n", + WTERMSIG(status)); + else if((WSTOPSIG(status) == SIGVTALRM) || + (WSTOPSIG(status) == SIGALRM) || + (WSTOPSIG(status) == SIGIO) || + (WSTOPSIG(status) == SIGCHLD)){ + ptrace(cont_type, pid, 0, WSTOPSIG(status)); + continue; + } + else printk("process stopped with signal %d\n", + WSTOPSIG(status)); + panic("wait_for_stop failed to wait for %d to stop " + "with %d\n", pid, sig); + } + return(status); + } +} + +static int mem_blocked = 0; + +void block_shlib_mem(void) +{ + if(mem_blocked || (NESTING > 0)) return; + mem_blocked = 1; + if(mmap((void *) 0x40000000, 0x20000000, PROT_NONE, + MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, -1, + 0) != (void *) 0x40000000){ + printf("mmap failed in linux_main\n"); + exit(1); + } +} + +void unblock_shlib_mem(void) +{ + if(NESTING == 0){ + mem_blocked = 0; + munmap((void *) 0x40000000, 0x20000000); + } +} + +int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags) +{ + int pid; + + pid = clone(fn, sp, flags, arg); + if(pid < 0) return(-1); + wait_for_stop(pid, SIGSTOP, PTRACE_CONT); + return(pid); +} + +struct grantpt_info { + int fd; + int res; + int err; +}; + +static void grantpt_cb(void *arg) +{ + struct grantpt_info *info = arg; + + info->res = grantpt(info->fd); + info->err = errno; +} + +int get_pty(void) +{ + struct grantpt_info info; + int fd; + + if((fd = open("/dev/ptmx", O_RDWR)) < 0){ + printk("get_pty : Couldn't open /dev/ptmx - errno = %d\n", + errno); + return(-1); + } + info.fd = fd; + tracing_cb(grantpt_cb, &info); + if(info.res < 0){ + printk("get_ptr : Couldn't grant pty - errno = %d\n", + info.err); + return(-1); + } + if(unlockpt(fd) < 0){ + printk("get_ptr : Couldn't unlock pty - errno = %d\n", errno); + return(-1); + } + return(fd); +} + +int raw(int fd, int complain) +{ + struct termios tt; + int err; + + tcgetattr(fd, &tt); + cfmakeraw(&tt); + err = tcsetattr(fd, TCSADRAIN, &tt); + if((err < 0) && complain){ + printk("tcsetattr failed, errno = %d\n", errno); + return(-errno); + } + return(0); +} + +void setup_machinename(char *machine_out) +{ + struct utsname host; + + uname(&host); + strcpy(machine_out, host.machine); +} + +char host_info[(_UTSNAME_LENGTH + 1) * 4 + _UTSNAME_NODENAME_LENGTH + 1]; + +void setup_hostinfo(void) +{ + struct utsname host; + + uname(&host); + sprintf(host_info, "%s %s %s %s %s", host.sysname, host.nodename, + host.release, host.version, host.machine); +} + +void close_fd(int fd) +{ + close(fd); +} + +#define UMID_LEN 64 +char umid[UMID_LEN] = { 0 }; + +void create_pid_file(char *name) +{ + char tmp[sizeof("/tmp/uml/") + UMID_LEN + 1]; + int fd; + static int umid_inited = 0; + + if(umid_inited){ + printk("Unique machine name can't be set twice\n"); + return; + } + if((mkdir("/tmp/uml", 0777) < 0) && + (errno != EEXIST)){ + printk("Failed to create /tmp/uml - errno = %s\n", errno); + return; + } + umid_inited = 1; + if(strlen(name) > UMID_LEN - 1) + printk("Unique machine name is being truncated to %s " + "characters\n", UMID_LEN); + strncpy(umid, name, UMID_LEN - 1); + umid[UMID_LEN - 1] = '\0'; + sprintf(tmp, "/tmp/uml/%s", umid); + if((fd = open(tmp, O_RDWR | O_CREAT | O_EXCL, 0644)) < 0){ + printk("Open of machine pid file \"%s\" failed - " + "errno = %d\n", umid, errno); + return; + } + sprintf(tmp, "%d\n", getpid()); + if(write(fd, tmp, strlen(tmp)) != strlen(tmp)) + printk("Write of pid file failed - errno = %d\n", errno); + close(fd); +} + +void remove_pid_file(void) +{ + char tmp[sizeof("/tmp/uml/") + UMID_LEN + 1]; + + if(umid[0] == '\0') return; + sprintf(tmp, "/tmp/uml/%s", umid); + unlink(tmp); + return; +} + +char *get_umid(void) +{ + return(umid); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/link.ld.in linux.ac/arch/um/link.ld.in --- linux.vanilla/arch/um/link.ld.in Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/link.ld.in Mon Apr 9 23:25:02 2001 @@ -0,0 +1,166 @@ +OUTPUT_FORMAT("elf32-SUBARCH") +OUTPUT_ARCH(SUBARCH) +ENTRY(_start) + +SECTIONS +{ + . = START() + SIZEOF_HEADERS; + /* Read-only sections, merged into text segment: */ + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .plt : { *(.plt) } + .remap : { arch/um/kernel/unmap_fin.o (.text) } + + . = ALIGN(4096); /* Init code and data */ + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(16); + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { *(.initcall.init) } + __initcall_end = .; + . = ALIGN(4096); + __init_end = .; + __exitcall_begin = .; + .exitcall : { *(.exitcall.exit) } + __exitcall_end = .; + + _stext = .; + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0x9090 + .kstrtab : { *(.kstrtab) } + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + __ksymtab : { *(__ksymtab) } + __stop___ksymtab = .; + .fini : { *(.fini) } =0x9090 + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + _etext = .; + PROVIDE (etext = .); + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x1000) + (. & (0x1000 - 1)); + .data : + { + _sdata = .; + PROVIDE (sdata = .); + . = ALIGN(16384); /* init_task */ + *(.data.init_task) + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .ctors : + { + *(.ctors) + } + .dtors : + { + *(.dtors) + } + + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + . = ALIGN(0x1000); + .sbss : + { + __bss_start = .; + PROVIDE(_bss_start = .); + *(.sbss) + *(.scommon) + } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (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) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/main.c linux.ac/arch/um/main.c --- linux.vanilla/arch/um/main.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/main.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <termios.h> +#include <string.h> +#include <sys/resource.h> +#include <linux/personality.h> +#include "include/user_util.h" + + +unsigned long stacksizelim; + +char *linux_prog; + +#define PGD_BOUND (4 * 1024 * 1024) +#define STACKSIZE (8 * 1024 * 1024) +#define THREAD_NAME_LEN (256) + +char padding[THREAD_NAME_LEN] = { [ 0 ... THREAD_NAME_LEN - 2] = ' ', '\0' }; + +int main(int argc, char **argv, char **envp) +{ + struct termios tt; + struct rlimit lim; + int ret, i; + char **new_argv; + + /* Allocate memory for thread command lines */ + if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){ + new_argv = malloc((argc + 2) * sizeof(char*)); + if(!new_argv) { + perror("Allocating extended argv"); + exit(1); + } + + new_argv[0] = argv[0]; + new_argv[1] = padding; + + for(i = 2; i <= argc; i++) + new_argv[i] = argv[i - 1]; + new_argv[argc + 1] = NULL; + + execvp(new_argv[0], new_argv); + perror("execing with extended args"); + exit(1); + } + + linux_prog = argv[0]; + block_shlib_mem(); + if(getrlimit(RLIMIT_STACK, &lim) < 0){ + perror("getrlimit"); + exit(1); + } + if((lim.rlim_cur == RLIM_INFINITY) || (lim.rlim_cur > STACKSIZE)){ + lim.rlim_cur = STACKSIZE; + if(setrlimit(RLIMIT_STACK, &lim) < 0){ + perror("setrlimit"); + exit(1); + } + } + stacksizelim = (lim.rlim_cur + PGD_BOUND - 1) & ~(PGD_BOUND - 1); + get_profile_timer(); + if(isatty(0)) tcgetattr(0, &tt); + else if(isatty(1)) tcgetattr(1, &tt); + else tcgetattr(2, &tt); + + if((new_argv = malloc((argc + 1) * sizeof(char *))) == NULL){ + perror("Mallocing argv"); + exit(1); + } + for(i=0;i<argc;i++){ + if((new_argv[i] = strdup(argv[i])) == NULL){ + perror("Mallocing an arg"); + exit(1); + } + } + new_argv[argc] = NULL; + + ret = linux_main(argc, argv); + + /* Reboot */ + if(ret){ + printf("\n"); + tcsetattr(0, TCSADRAIN, &tt); + execve(new_argv[0], new_argv, envp); + perror("Failed to exec kernel"); + ret = 1; + } + if(isatty(0)) tcsetattr(0, TCSADRAIN, &tt); + else if(isatty(1)) tcsetattr(1, TCSADRAIN, &tt); + else tcsetattr(2, TCSADRAIN, &tt); + printf("\n"); + return(ret); +} + +#ifdef PROFILING +extern void block_shlib_mem(void); +extern void __real___monstartup (unsigned long, unsigned long); + +void __wrap___monstartup (unsigned long lowpc, unsigned long highpc) +{ + block_shlib_mem(); + __real___monstartup(lowpc, highpc); +} +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/ptproxy/Makefile linux.ac/arch/um/ptproxy/Makefile --- linux.vanilla/arch/um/ptproxy/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/ptproxy/Makefile Mon Apr 9 23:25:02 2001 @@ -0,0 +1,30 @@ +LIB = ptproxy.a + +OBJS = proxy.o ptrace.o sysdep.o wait.o + +USER_CFLAGS = $(patsubst -I%,,$(CFLAGS)) +USER_CFLAGS := $(patsubst -U$(SUBARCH),,$(USER_CFLAGS)) +USER_CFLAGS += -I../include + +all: $(LIB) + +$(LIB): $(OBJS) $(OX_OBJS) + rm -f $@ + ar cr $@ $^ + +proxy.o: proxy.c + $(CC) -D__KERNEL__ $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< + +ptrace.o: ptrace.c + $(CC) -D__KERNEL__ $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< + +sysdep.o: sysdep.c + $(CC) -D__KERNEL__ $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< + +wait.o: wait.c + $(CC) -D__KERNEL__ $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< + +clean: + rm -f *.o core child ptproxy + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/ptproxy/proxy.c linux.ac/arch/um/ptproxy/proxy.c --- linux.vanilla/arch/um/ptproxy/proxy.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/ptproxy/proxy.c Sun Apr 15 22:53:42 2001 @@ -0,0 +1,283 @@ +/********************************************************************** +proxy.c + +Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing +terms and conditions. + +Jeff Dike (jdike@karaya.com) : Modified for integration into uml +**********************************************************************/ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> +#include <fcntl.h> +#include <termios.h> +#include <sys/wait.h> +#include <sys/types.h> +#include <sys/ptrace.h> +#include <sys/ioctl.h> +#include <asm/unistd.h> + +#include "ptproxy.h" +#include "sysdep.h" +#include "wait.h" + +#include "user_util.h" +#include "chan.h" +#include "user.h" + +static void debugger_normal_return (debugger_state *, pid_t); + +/* + * Handle debugger trap, i.e. syscall. + */ + +void +debugger_syscall (debugger_state *debugger, pid_t child) +{ + int cancel = 0; + long arg1, arg2, arg3, arg4, arg5; + int syscall; + + syscall = syscall_get_number (debugger->pid); + syscall_get_args (debugger->pid, &arg1, &arg2, &arg3, &arg4, &arg5); + + switch (syscall) + { + case __NR_execve: + debugger->handle_trace = debugger_syscall; /* execve never returns */ + break; + case __NR_ptrace: + if(debugger->debugee->pid != 0) arg2 = debugger->debugee->pid; + proxy_ptrace (debugger, arg1, arg2, arg3, arg4, child); + cancel = 1; + debugger->handle_trace = debugger_cancelled_return; + break; + case __NR_waitpid: + case __NR_wait4: + proxy_wait (debugger, + syscall == __NR_waitpid ? WAIT_WAITPID : + syscall == __NR_wait4 ? WAIT_WAIT4 : -1, + debugger->debugee->pid, (int *)arg2, arg3, + (void *)arg4); + cancel = 1; + debugger->handle_trace = proxy_wait_return; + break; + case __NR_kill: + if(arg1 == debugger->debugee->pid){ + debugger->result = kill(child, arg2); + cancel = 1; + debugger->handle_trace = debugger_cancelled_return; + } + else { + debugger->handle_trace = debugger_normal_return; + } + break; + default: + debugger->handle_trace = debugger_normal_return; + } + + if (cancel) + syscall_cancel (debugger->pid); + + syscall_continue (debugger->pid); +} + +void +debugger_normal_return (debugger_state *debugger, pid_t unused) +{ + debugger->handle_trace = debugger_syscall; + syscall_continue (debugger->pid); +} + +void +debugger_cancelled_return (debugger_state *debugger, pid_t unused) +{ + syscall_set_result (debugger->pid, debugger->result); + debugger->handle_trace = debugger_syscall; + syscall_continue (debugger->pid); +} + +#ifdef __SMP__ +#error need to make these arrays +#endif + +static debugger_state debugger; +static debugee_state debugee; + +void +init_proxy (pid_t debugger_pid, int stopped, int status) +{ + debugger.pid = debugger_pid; + debugger.handle_trace = debugger_syscall; + debugger.debugee = &debugee; + debugger.stopped = 0; + + debugee.pid = 0; + debugee.traced = 0; + debugee.stopped = stopped; + debugee.event = 0; + debugee.zombie = 0; + debugee.died = 0; + debugee.debugger = &debugger; + debugee.wait_status = status; +} + +void debugger_proxy(int status, int pid) +{ + if (WIFSTOPPED (status)) + { + /* debugger got a signal */ + + if (WSTOPSIG (status) == SIGTRAP) + { + debugger.handle_trace (&debugger, pid); + } + else + { + /* go on as usual */ + ptrace (PTRACE_SYSCALL, debugger.pid, + 0, WSTOPSIG (status)); + } + } + else if (WIFEXITED (status)) + { + /* debugger exited with status + WEXITSTATUS (status) */ + } + else if (WIFSIGNALED (status)) + { + /* debugger died from signal + WTERMSIG (status) */ + } + else + { + /* unknown event */ + panic("proxy got unknown status (0x%x) on debugger " + "(pid %d)", status, debugger.pid); + exit (1); + } +} + +void child_proxy(pid_t pid, int status) +{ + debugee.stopped = 1; + debugee.event = 1; + debugee.wait_status = status; + + if (WIFSTOPPED (status)) + { + /* child got a signal */ + } + else if (WIFEXITED (status)) + { + /* child exited with status WEXITSTATUS + (status) */ + debugee.zombie = 1; + } + else if (WIFSIGNALED (status)) + { + /* child died from signal WTERMSIG + (status) */ + debugee.zombie = 1; + } + else + { + /* unknown event */ + panic("proxy got unknown status (0x%x) on child " + "(pid %d)", status, pid); + } + + if (debugee.stopped) + { + int r; + + r = kill (debugger.pid, SIGCHLD); + if (debugger.stopped) + proxy_wait_return (&debugger, -1); + } +} + +extern struct io_chan gdb_chan; + +int start_debugger(char *prog, int startup, int stop, int *fd_out) +{ + int err, slave, child; + + err = open_chan_pair(&gdb_chan, NULL, NULL); + if(err) return(err); + slave = CHAN_OUT_FD(gdb_chan); + if((child = fork()) == 0){ + char tempname[sizeof("/tmp/gdb_init-XXXXXX")]; + char arg[sizeof("--command=/tmp/gdb_init-XXXXXX")]; + int fd; + + if(setsid() < 0) perror("setsid"); + if((dup2(slave, 0) < 0) || (dup2(slave, 1) < 0) || + (dup2(slave, 2) < 0)){ + printk("start_debugger : dup2 failed, errno = %d\n", + errno); + exit(1); + } + if(ioctl(0, TIOCSCTTY, 0) < 0){ + printk("start_debugger : TIOCSCTTY failed, " + "errno = %d\n", errno); + exit(1); + } + if(tcsetpgrp (1, getpid()) < 0){ + printk("start_debugger : tcsetpgrp failed, " + "errno = %d\n", errno); +#ifdef notdef + exit(1); +#endif + } + strcpy(tempname, "/tmp/gdb_init-XXXXXX"); + if((fd = mkstemp(tempname)) < 0){ + printk("start_debugger : mkstmp failed, errno = %d\n", + errno); + exit(1); + } + sprintf(arg, "--command=%s", tempname); + write(fd, "att 1\n", strlen("att 1\n")); + write(fd, "b panic\n", strlen("b panic\n")); + write(fd, "b stop\n", strlen("b stop\n")); + write(fd, "handle SIGWINCH nostop noprint\n", + strlen("handle SIGWINCH nostop noprint\n")); + if(startup){ + if(stop){ + write(fd, "b start_kernel\n", + strlen("b start_kernel\n")); + } + write(fd, "c\n", strlen("c\n")); + } + if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){ + printk("start_debugger : PTRACE_TRACEME failed, " + "errno = %d\n", errno); + exit(1); + } + execlp("gdb", "gdb", arg, prog, NULL); + printk("start_debugger : exec of gdb failed, errno = %d\n", + errno); + } + if(child < 0){ + printk("start_debugger : fork for gdb failed, errno = %d\n", + errno); + return(-1); + } + *fd_out = slave; + return(child); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/ptproxy/ptproxy.h linux.ac/arch/um/ptproxy/ptproxy.h --- linux.vanilla/arch/um/ptproxy/ptproxy.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/ptproxy/ptproxy.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,42 @@ +/********************************************************************** +ptproxy.h + +Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing +terms and conditions. +**********************************************************************/ + +#include <sys/types.h> + +typedef struct debugger debugger_state; +typedef struct debugee debugee_state; + +struct debugger +{ + pid_t pid; + long result; + int wait_options; + int *wait_status_ptr; + unsigned stopped : 1; + void (*handle_trace) (debugger_state *, pid_t); + + debugee_state *debugee; +}; + +struct debugee +{ + pid_t pid; + int wait_status; + unsigned died : 1; + unsigned event : 1; + unsigned stopped : 1; + unsigned trace_singlestep : 1; + unsigned trace_syscall : 1; + unsigned traced : 1; + unsigned zombie : 1; + + debugger_state *debugger; +}; + +extern void debugger_syscall (debugger_state *, pid_t); +extern void debugger_cancelled_return (debugger_state *, pid_t); +extern void proxy_ptrace (struct debugger *, int, pid_t, long, long, pid_t); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/ptproxy/ptrace.c linux.ac/arch/um/ptproxy/ptrace.c --- linux.vanilla/arch/um/ptproxy/ptrace.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/ptproxy/ptrace.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,206 @@ +/********************************************************************** +ptrace.c + +Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing +terms and conditions. + +Jeff Dike (jdike@karaya.com) : Modified for integration into uml +**********************************************************************/ + +#include <errno.h> +#include <unistd.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/ptrace.h> + +#include "ptproxy.h" + +struct { + int op; + pid_t pid; + long addr; + long data; + pid_t child; + struct timeval tv; +} ptrace_record[1024]; + +int ptrace_index = 0; + +void +proxy_ptrace (struct debugger *debugger, int arg1, pid_t arg2, + long arg3, long arg4, pid_t child) +{ + int status; + + if(ptrace_index == 1024) ptrace_index = 0; + ptrace_record[ptrace_index].op = arg1; + ptrace_record[ptrace_index].pid = arg2; + ptrace_record[ptrace_index].data = arg3; + ptrace_record[ptrace_index].addr = arg4; + ptrace_record[ptrace_index].child = child; + gettimeofday(&ptrace_record[ptrace_index++].tv, NULL); + if (debugger->debugee->died) + { + debugger->result = -ESRCH; + debugger->handle_trace = debugger_cancelled_return; + } + + switch (arg1) + { + case PTRACE_ATTACH: + if (debugger->debugee->traced) + debugger->result = -EPERM; + else + { + debugger->result = 0; + debugger->debugee->pid = arg2; + debugger->debugee->traced = 1; + if(!debugger->debugee->stopped) kill(child, SIGSTOP); + else { + child_proxy(child, + debugger->debugee->wait_status); + } + } + break; + + case PTRACE_CONT: + debugger->result = ptrace (PTRACE_CONT, child, arg3, arg4); + break; + + case PTRACE_DETACH: + if (debugger->debugee->traced) + { + debugger->result = 0; + debugger->debugee->traced = 0; + kill(child, SIGCONT); + } + else + debugger->result = -EPERM; + break; + + case PTRACE_GETFPREGS: + { + long regs[27]; + int i; + + debugger->result = ptrace (PTRACE_GETFPREGS, child, 0, regs); + if (debugger->result == -1) + debugger->result = -errno; + else + { + for (i = 0; i < 27; i++) + ptrace (PTRACE_POKEDATA, debugger->pid, + arg4 + 4 * i, regs[i]); + } + } + break; + + case PTRACE_GETREGS: + { + long regs[17]; + int i; + + debugger->result = ptrace (PTRACE_GETREGS, child, 0, regs); + if (debugger->result == -1) + debugger->result = -errno; + else + { + for (i = 0; i < 17; i++) + ptrace (PTRACE_POKEDATA, debugger->pid, + arg4 + 4 * i, regs[i]); + } + } + break; + + case PTRACE_KILL: + debugger->result = ptrace (PTRACE_KILL, child, arg3, arg4); + if (debugger->result == -1) + debugger->result = -errno; + break; + + case PTRACE_PEEKDATA: + case PTRACE_PEEKTEXT: + case PTRACE_PEEKUSER: + errno = 0; + debugger->result = ptrace (arg1, child, arg3, 0); + if (debugger->result == -1 && errno != 0) + debugger->result = -errno; + else + { + ptrace (PTRACE_POKEDATA, debugger->pid, arg4, + debugger->result); + debugger->result = 0; + } + break; + case PTRACE_POKEDATA: + case PTRACE_POKETEXT: + case PTRACE_POKEUSER: + debugger->result = ptrace (arg1, child, arg3, arg4); + if (debugger->result == -1) + debugger->result = -errno; + break; + + case PTRACE_SETFPREGS: + { + long regs[27]; + int i; + + for (i = 0; i < 27; i++) + regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid, + arg4 + 4 * i, 0); + debugger->result = ptrace (PTRACE_SETFPREGS, child, 0, regs); + if (debugger->result == -1) + debugger->result = -errno; + } + break; + + case PTRACE_SETREGS: + { + long regs[17]; + int i; + + for (i = 0; i < 17; i++) + regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid, + arg4 + 4 * i, 0); + debugger->result = ptrace (PTRACE_SETREGS, child, 0, regs); + if (debugger->result == -1) + debugger->result = -errno; + } + break; + + case PTRACE_SINGLESTEP: + debugger->result = ptrace (PTRACE_SINGLESTEP, child, arg3, + arg4); + if (debugger->result == -1) + debugger->result = -errno; + else { + status = wait_for_stop(child, SIGTRAP, + PTRACE_SINGLESTEP); + child_proxy(child, status); + } + break; + + case PTRACE_SYSCALL: + debugger->result = -EINVAL; + break; + + case PTRACE_TRACEME: + debugger->result = -EINVAL; + break; + + default: + debugger->result = -EINVAL; + } +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/ptproxy/sysdep.c linux.ac/arch/um/ptproxy/sysdep.c --- linux.vanilla/arch/um/ptproxy/sysdep.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/ptproxy/sysdep.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,75 @@ +/********************************************************************** +sysdep.c + +Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing +terms and conditions. +**********************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/ptrace.h> + +#include <linux/unistd.h> + +#ifdef i386 +# define REG_SYSCALL (4 * 11) +# define REG_RESULT (4 * 6) +# define REG_ARG1 (4 * 0) +# define REG_ARG2 (4 * 1) +# define REG_ARG3 (4 * 2) +# define REG_ARG4 (4 * 3) +# define REG_ARG5 (4 * 4) +#endif +#ifdef arm +# define REG_SYSCALL (4 * 17) +# define REG_RESULT (4 * 0) +# define REG_ARG1 (4 * 0) +# define REG_ARG2 (4 * 1) +# define REG_ARG3 (4 * 2) +# define REG_ARG4 (4 * 3) +# define REG_ARG5 (4 * 4) +#endif + +int +syscall_get_number (pid_t pid) +{ + return ptrace (PTRACE_PEEKUSER, pid, REG_SYSCALL, 0); +} + +void +syscall_cancel (pid_t pid) +{ + int err; + + err = ptrace (PTRACE_POKEUSER, pid, REG_SYSCALL, __NR_getpid); + if (err == -1) + { + fprintf (stderr, "ptproxy: couldn't cancel syscall: errno = %d\n", + errno); + exit (1); + } +} + +void +syscall_get_args (pid_t pid, long *arg1, long *arg2, + long *arg3, long *arg4, long *arg5) +{ + *arg1 = ptrace (PTRACE_PEEKUSER, pid, REG_ARG1, 0); + *arg2 = ptrace (PTRACE_PEEKUSER, pid, REG_ARG2, 0); + *arg3 = ptrace (PTRACE_PEEKUSER, pid, REG_ARG3, 0); + *arg4 = ptrace (PTRACE_PEEKUSER, pid, REG_ARG4, 0); + *arg5 = ptrace (PTRACE_PEEKUSER, pid, REG_ARG5, 0); +} + +void +syscall_set_result (pid_t pid, long result) +{ + ptrace (PTRACE_POKEUSER, pid, REG_RESULT, result); +} + +void +syscall_continue (pid_t pid) +{ + ptrace (PTRACE_SYSCALL, pid, 0, 0); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/ptproxy/sysdep.h linux.ac/arch/um/ptproxy/sysdep.h --- linux.vanilla/arch/um/ptproxy/sysdep.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/ptproxy/sysdep.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,13 @@ +/********************************************************************** +sysdep.h + +Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing +terms and conditions. +**********************************************************************/ + +extern int syscall_get_number (pid_t pid); +extern void syscall_cancel (pid_t pid); +extern void syscall_get_args (pid_t pid, long *arg1, long *arg2, + long *arg3, long *arg4, long *arg5); +extern void syscall_set_result (pid_t pid, long result); +extern void syscall_continue (pid_t pid); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/ptproxy/wait.c linux.ac/arch/um/ptproxy/wait.c --- linux.vanilla/arch/um/ptproxy/wait.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/ptproxy/wait.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,79 @@ +/********************************************************************** +wait.c + +Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing +terms and conditions. + +**********************************************************************/ + +#include <errno.h> +#include <sys/wait.h> +#include <sys/ptrace.h> + +#include "ptproxy.h" +#include "sysdep.h" +#include "wait.h" + +void +proxy_wait (struct debugger *debugger, enum wait_type type, pid_t pid, + int *status, int options, void *rusage) +{ + debugger->wait_status_ptr = status; + debugger->wait_options = options; +} + +void +proxy_wait_return (struct debugger *debugger, pid_t unused) +{ + debugger->stopped = 0; + + if (debugger->debugee->died) + { + debugger->result = -ECHILD; + debugger_cancelled_return (debugger, -1); + return; + } + + if (debugger->wait_options & __WCLONE) + { + debugger->result = -ECHILD; + debugger_cancelled_return (debugger, -1); + return; + } + + if (debugger->debugee->zombie && debugger->debugee->event) + debugger->debugee->died = 1; + + if (debugger->wait_options & WNOHANG) + { + if (debugger->debugee->event) + { + debugger->debugee->event = 0; + ptrace (PTRACE_POKEDATA, debugger->pid, + debugger->wait_status_ptr, debugger->debugee->wait_status); + /* if (wait4) + ptrace (PTRACE_POKEDATA, pid, rusage_ptr, ...); */ + debugger->result = debugger->debugee->pid; + } + else + { + debugger->result = 0; + } + debugger_cancelled_return (debugger, -1); + return; + } + + if (debugger->debugee->event) + { + debugger->debugee->event = 0; + ptrace (PTRACE_POKEDATA, debugger->pid, + debugger->wait_status_ptr, debugger->debugee->wait_status); + /* if (wait4) + ptrace (PTRACE_POKEDATA, pid, rusage_ptr, ...); */ + debugger->result = debugger->debugee->pid; + debugger_cancelled_return (debugger, -1); + return; + } + + debugger->stopped = 1; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/ptproxy/wait.h linux.ac/arch/um/ptproxy/wait.h --- linux.vanilla/arch/um/ptproxy/wait.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/ptproxy/wait.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,18 @@ +/********************************************************************** +wait.h + +Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing +terms and conditions. +**********************************************************************/ + +enum wait_type +{ + WAIT_WAIT, + WAIT_WAITPID, + WAIT_WAIT3, + WAIT_WAIT4 +}; + +extern void proxy_wait (struct debugger *debugger, enum wait_type type, + pid_t arg1, int *arg2, int arg3, void *arg4); +extern void proxy_wait_return (struct debugger *debugger, pid_t unused); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/sys-i386/Makefile linux.ac/arch/um/sys-i386/Makefile --- linux.vanilla/arch/um/sys-i386/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/sys-i386/Makefile Mon Apr 9 23:25:02 2001 @@ -0,0 +1,50 @@ +OBJ = sys.o + +OBJS = checksum.o ldt.o old-checksum.o ptrace.o semaphore.o sigcontext.o +OX_OBJS = ksyms.o + +USER_CFLAGS = $(patsubst -I%,,$(CFLAGS)) +USER_CFLAGS += -I../include + +CFLAGS += -I../include + +SYMLINKS = semaphore.c old-checksum.c checksum.S + +all: $(OBJ) + +$(OBJ): $(OBJS) $(OX_OBJS) + rm -f $@ + $(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@ + +sigcontext.o: sigcontext.c + $(CC) -D__KERNEL__ $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< + +ldt.o: ldt.c + $(CC) -D__KERNEL__ $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< + +checksum.S old-checksum.c: + -rm -f $@ + -ln -s $(TOPDIR)/arch/i386/lib/$@ $@ + +semaphore.c: + -rm -f $@ + -ln -s $(TOPDIR)/arch/i386/kernel/$@ $@ + +clean: + rm -f $(OBJS) $(OX_OBJS) + +fastdep: + +archmrproper: + rm -f $(SYMLINKS) + +archclean: + rm -f link.ld + @$(MAKEBOOT) clean + +archdep: + @$(MAKEBOOT) dep + +modules: + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/sys-i386/ksyms.c linux.ac/arch/um/sys-i386/ksyms.c --- linux.vanilla/arch/um/sys-i386/ksyms.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/sys-i386/ksyms.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,18 @@ +#include "linux/module.h" +#include "linux/in6.h" +#include "asm/byteorder.h" +#include "asm/semaphore.h" +#include "asm/uaccess.h" +#include "asm/checksum.h" +#include "asm/errno.h" + +EXPORT_SYMBOL(__down_failed); +EXPORT_SYMBOL(__down_failed_interruptible); +EXPORT_SYMBOL(__down_failed_trylock); +EXPORT_SYMBOL(__up_wakeup); +EXPORT_SYMBOL(__down_write_failed); +EXPORT_SYMBOL(__down_read_failed); +EXPORT_SYMBOL(__rwsem_wake); + +/* Networking helper routines. */ +EXPORT_SYMBOL(csum_partial_copy_generic); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/sys-i386/ldt.c linux.ac/arch/um/sys-i386/ldt.c --- linux.vanilla/arch/um/sys-i386/ldt.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/sys-i386/ldt.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +int sys_modify_ldt(int func, void *ptr, unsigned long bytecount) +{ + return modify_ldt(func, ptr, bytecount); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/sys-i386/ptrace.c linux.ac/arch/um/sys-i386/ptrace.c --- linux.vanilla/arch/um/sys-i386/ptrace.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/sys-i386/ptrace.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/sched.h" +#include "asm/ptrace.h" + +/* determines which flags the user has access to. */ +/* 1 = access 0 = no access */ +#define FLAG_MASK 0x00044dd5 + +int putreg(struct task_struct *child, unsigned long regno, + unsigned long value) +{ + switch (regno >> 2) { + case FS: + if (value && (value & 3) != 3) + return -EIO; + child->thread.process_regs.regs[FS] = value; + return 0; + case GS: + if (value && (value & 3) != 3) + return -EIO; + child->thread.process_regs.regs[GS] = value; + return 0; + case DS: + case ES: + if (value && (value & 3) != 3) + return -EIO; + value &= 0xffff; + break; + case SS: + case CS: + if ((value & 3) != 3) + return -EIO; + value &= 0xffff; + break; + case EFL: + value &= FLAG_MASK; + value |= child->thread.process_regs.regs[EFL]; + break; + } + child->thread.process_regs.regs[regno >> 2] = value; + return 0; +} + +unsigned long getreg(struct task_struct *child, unsigned long regno) +{ + unsigned long retval = ~0UL; + + switch (regno >> 2) { + case FS: + case GS: + case DS: + case ES: + case SS: + case CS: + retval = 0xffff; + /* fall through */ + default: + retval &= child->thread.process_regs.regs[regno >> 2]; + } + return retval; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/sys-i386/sigcontext.c linux.ac/arch/um/sys-i386/sigcontext.c --- linux.vanilla/arch/um/sys-i386/sigcontext.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/sys-i386/sigcontext.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <asm/ptrace.h> +#include <asm/sigcontext.h> +#include "sysdep/ptrace.h" +#include "user_util.h" + +void fill_in_sigcontext(void *sc_ptr, struct sys_pt_regs *regs, + unsigned long cr2, int err) +{ + struct sigcontext *sc; + + sc = sc_ptr; + sc->ebx = regs->regs[EBX]; + sc->ecx = regs->regs[ECX]; + sc->edx = regs->regs[EDX]; + sc->esi = regs->regs[ESI]; + sc->edi = regs->regs[EDI]; + sc->ebp = regs->regs[EBP]; + sc->eax = regs->regs[EAX]; + sc->ds = regs->regs[DS]; + sc->es = regs->regs[ES]; + sc->fs = regs->regs[FS]; + sc->gs = regs->regs[GS]; + sc->eip = regs->regs[EIP]; + sc->cs = regs->regs[CS]; + sc->eflags = regs->regs[EFL]; + sc->esp_at_signal = regs->regs[UESP]; + sc->ss = regs->regs[SS]; + sc->err = err; + sc->cr2 = cr2; +} + +void fill_in_regs(struct sys_pt_regs *regs, void *sc_ptr) +{ + struct sigcontext *sc; + + sc = sc_ptr; + regs->regs[EBX] = sc->ebx; + regs->regs[ECX] = sc->ecx; + regs->regs[EDX] = sc->edx; + regs->regs[ESI] = sc->esi; + regs->regs[EDI] = sc->edi; + regs->regs[EBP] = sc->ebp; + regs->regs[EAX] = sc->eax; + regs->regs[DS] = sc->ds; + regs->regs[ES] = sc->es; + regs->regs[FS] = sc->fs; + regs->regs[GS] = sc->gs; + regs->regs[EIP] = sc->eip; + regs->regs[CS] = sc->cs; + regs->regs[EFL] = sc->eflags; + regs->regs[UESP] = sc->esp_at_signal; + regs->regs[SS] = sc->ss; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/sys-ia64/Makefile linux.ac/arch/um/sys-ia64/Makefile --- linux.vanilla/arch/um/sys-ia64/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/sys-ia64/Makefile Mon Apr 9 23:25:02 2001 @@ -0,0 +1,26 @@ +OBJ = sys.o + +OBJS = + +all: $(OBJ) + +$(OBJ): $(OBJS) + rm -f $@ + $(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@ +clean: + rm -f $(OBJS) + +fastdep: + +archmrproper: + +archclean: + rm -f link.ld + @$(MAKEBOOT) clean + +archdep: + @$(MAKEBOOT) dep + +modules: + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/sys-ppc/Makefile linux.ac/arch/um/sys-ppc/Makefile --- linux.vanilla/arch/um/sys-ppc/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/sys-ppc/Makefile Mon Apr 9 23:25:02 2001 @@ -0,0 +1,27 @@ +OBJ = sys.o + +OBJS = ptrace.o sigcontext.o checksum.o miscthings.o bitops.o + +USER_CFLAGS = $(patsubst -I%,,$(CFLAGS)) +USER_CFLAGS += -I../include -I$(TOPDIR)/include + +all: $(OBJ) + +$(OBJ): $(OBJS) + rm -f $@ + $(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@ + +ptrace.o: ptrace.c + $(CC) -D__KERNEL__ $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< + +sigcontext.o: sigcontext.c + $(CC) -D__KERNEL__ $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< + +clean: + rm -f $(OBJS) + +fastdep: + +modules: + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/sys-ppc/miscthings.c linux.ac/arch/um/sys-ppc/miscthings.c --- linux.vanilla/arch/um/sys-ppc/miscthings.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/sys-ppc/miscthings.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,16 @@ +#include <linux/config.h> +#include <linux/threads.h> + +unsigned int local_bh_count[NR_CPUS]; +unsigned long isa_io_base = 0; + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/sys-ppc/ptrace.c linux.ac/arch/um/sys-ppc/ptrace.c --- linux.vanilla/arch/um/sys-ppc/ptrace.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/sys-ppc/ptrace.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,28 @@ +#include "linux/sched.h" +#include "asm/ptrace.h" + +int putreg(struct task_struct *child, unsigned long regno, + unsigned long value) +{ + child->thread.process_regs.u.regs[regno >> 2] = value; + return 0; +} + +unsigned long getreg(struct task_struct *child, unsigned long regno) +{ + unsigned long retval = ~0UL; + + retval &= child->thread.process_regs.u.regs[regno >> 2]; + return retval; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/um/sys-ppc/sigcontext.c linux.ac/arch/um/sys-ppc/sigcontext.c --- linux.vanilla/arch/um/sys-ppc/sigcontext.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/um/sys-ppc/sigcontext.c Mon Apr 9 23:25:02 2001 @@ -0,0 +1,48 @@ +#include <asm/ptrace.h> +#include <asm/sigcontext.h> +#include "sysdep/ptrace.h" +#include "user_util.h" + +void fill_in_sigcontext(struct sigcontext *sc, struct sys_pt_regs *regs, + unsigned long cr2, int err) +{ +#if 0 + int i; + // general purpose regs + for (i=0; i<32; ++i) { + sc->regs->gpr[i] = regs->u.regs[PT_R0 + i]; + } + sc->regs->nip = regs->u.regs[PT_NIP]; + sc->regs->msr = regs->u.regs[PT_MSR]; + sc->regs->orig_gpr3 = regs->u.regs[PT_ORIG_R3]; + sc->regs->ctr = regs->u.regs[PT_CTR]; + sc->regs->link = regs->u.regs[PT_LNK]; + sc->regs->xer = regs->u.regs[PT_XER]; + sc->regs->ccr = regs->u.regs[PT_CCR]; + sc->regs->mq = regs->u.regs[PT_MQ]; + sc->regs->trap = err; + sc->regs->dar = cr2; +#endif + *(sc->regs) = *regs; + // DAR, DSISR, RESULT? +} + +void fill_in_regs(struct sys_pt_regs *regs, void *sc_ptr) +{ + struct sigcontext *sc; + + sc = sc_ptr; + + *(sc->regs) = *regs; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/Makefile linux.ac/drivers/Makefile --- linux.vanilla/drivers/Makefile Fri Dec 29 22:07:21 2000 +++ linux.ac/drivers/Makefile Tue Apr 3 17:54:37 2001 @@ -6,8 +6,9 @@ # -mod-subdirs := dio mtd sbus video macintosh usb input telephony sgi i2o ide \ - scsi md ieee1394 pnp isdn atm fc4 net/hamradio i2c acpi +mod-subdirs := dio mtd sbus video macintosh usb input telephony sgi ide \ + message/i2o message/fusion scsi md ieee1394 pnp isdn atm \ + fc4 net/hamradio i2c acpi subdir-y := block char net parport sound misc media cdrom subdir-m := $(subdir-y) @@ -15,6 +16,7 @@ subdir-$(CONFIG_DIO) += dio subdir-$(CONFIG_PCI) += pci +subdir-$(CONFIG_GSC) += gsc subdir-$(CONFIG_PCMCIA) += pcmcia subdir-$(CONFIG_MTD) += mtd subdir-$(CONFIG_SBUS) += sbus @@ -30,7 +32,8 @@ subdir-$(CONFIG_SGI) += sgi subdir-$(CONFIG_IDE) += ide subdir-$(CONFIG_SCSI) += scsi -subdir-$(CONFIG_I2O) += i2o +subdir-$(CONFIG_I2O) += message/i2o +subdir-$(CONFIG_FUSION) += message/fusion subdir-$(CONFIG_MD) += md subdir-$(CONFIG_IEEE1394) += ieee1394 subdir-$(CONFIG_PNP) += pnp @@ -44,4 +47,3 @@ subdir-$(CONFIG_ACPI) += acpi include $(TOPDIR)/Rules.make - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/acpi/cpu.c linux.ac/drivers/acpi/cpu.c --- linux.vanilla/drivers/acpi/cpu.c Fri Feb 9 19:45:58 2001 +++ linux.ac/drivers/acpi/cpu.c Tue Apr 17 16:45:56 2001 @@ -335,13 +335,12 @@ acpi_pm_timer_init(); - if (acpi_use_idle) { #ifdef CONFIG_SMP - if (smp_num_cpus == 1) - pm_idle = acpi_idle; + if (acpi_use_idle && (smp_num_cpus == 1)) { #else - pm_idle = acpi_idle; + if (acpi_use_idle) { #endif + pm_idle = acpi_idle; printk(KERN_INFO "ACPI: Using ACPI idle\n"); printk(KERN_INFO "ACPI: If experiencing system slowness, try adding \"acpi=no-idle\" to cmdline\n"); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/acpi/dispatcher/dswload.c linux.ac/drivers/acpi/dispatcher/dswload.c --- linux.vanilla/drivers/acpi/dispatcher/dswload.c Mon Jan 22 21:23:42 2001 +++ linux.ac/drivers/acpi/dispatcher/dswload.c Tue Apr 17 16:45:56 2001 @@ -455,6 +455,11 @@ arg = acpi_ps_get_arg (op, 2); } + if (arg == NULL) { + status = AE_NOT_FOUND; + break; + } + /* * Enter the Name_string into the namespace */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/atm/firestream.c linux.ac/drivers/atm/firestream.c --- linux.vanilla/drivers/atm/firestream.c Sat Feb 17 00:02:35 2001 +++ linux.ac/drivers/atm/firestream.c Thu Apr 12 12:01:08 2001 @@ -294,6 +294,8 @@ #endif +static int fs_keystream = 0; + #ifdef DEBUG /* I didn't forget to set this to zero before shipping. Hit me with a stick if you get this with the debug default not set to zero again. -- REW */ @@ -308,6 +310,7 @@ #endif MODULE_PARM(loopback, "i"); MODULE_PARM(num, "i"); +MODULE_PARM(fs_keystream, "i"); /* XXX Add rx_buf_sizes, and rx_pool_sizes As per request Amar. -- REW */ #endif @@ -377,7 +380,7 @@ -/* It seems the ATM forum recomends this horribly complicated 16bit +/* It seems the ATM forum recommends this horribly complicated 16bit * floating point format. Turns out the Ambassador uses the exact same * encoding. I just copied it over. If Mitch agrees, I'll move it over * to the atm_misc file or something like that. (and remove it from @@ -716,6 +719,8 @@ switch (STATUS_CODE (qe)) { + case 0x01: /* This is for AAL0 where we put the chip in streaming mode */ + /* Fall through */ case 0x02: /* Process a real txdone entry. */ tmp = qe->p0; @@ -796,6 +801,8 @@ /* Single buffer packet */ switch (STATUS_CODE (qe)) { + case 0x1: + /* Fall through for streaming mode */ case 0x2:/* Packet received OK.... */ if (atm_vcc) { skb = pe->skb; @@ -877,7 +884,9 @@ if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) set_bit(ATM_VF_ADDR, &atm_vcc->flags); - if (atm_vcc->qos.aal != ATM_AAL5) return -EINVAL; /* XXX AAL0 */ + if ((atm_vcc->qos.aal != ATM_AAL5) && + (atm_vcc->qos.aal != ATM_AAL2)) + return -EINVAL; /* XXX AAL0 */ fs_dprintk (FS_DEBUG_OPEN, "fs: (itf %d): open %d.%d\n", atm_vcc->dev->number, atm_vcc->vpi, atm_vcc->vci); @@ -946,12 +955,27 @@ need to wait for completion anyway, to see if it completed succesfully. */ - tc->flags = 0 + switch (atm_vcc->qos.aal) { + case ATM_AAL2: + case ATM_AAL0: + tc->flags = 0 + | TC_FLAGS_TRANSPARENT_PAYLOAD + | TC_FLAGS_PACKET + | (1 << 28) + | TC_FLAGS_TYPE_UBR /* XXX Change to VBR -- PVDL */ + | TC_FLAGS_CAL0; + break; + case ATM_AAL5: + tc->flags = 0 | TC_FLAGS_AAL5 | TC_FLAGS_PACKET /* ??? */ | TC_FLAGS_TYPE_CBR | TC_FLAGS_CAL0; - + break; + default: + printk ("Unknown aal: %d\n", atm_vcc->qos.aal); + tc->flags = 0; + } /* Docs are vague about this atm_hdr field. By the way, the FS * chip makes odd errors if lower bits are set.... -- REW */ tc->atm_hdr = (vpi << 20) | (vci << 4); @@ -1025,7 +1049,6 @@ for (bfp = 0;bfp < FS_NR_FREE_POOLS; bfp++) if (atm_vcc->qos.rxtp.max_sdu <= dev->rx_fp[bfp].bufsize) break; - if (bfp >= FS_NR_FREE_POOLS) { fs_dprintk (FS_DEBUG_OPEN, "No free pool fits sdu: %d.\n", atm_vcc->qos.rxtp.max_sdu); @@ -1037,12 +1060,23 @@ return -EINVAL; } - submit_command (dev, &dev->hp_txq, - QE_CMD_CONFIG_RX | QE_CMD_IMM_INQ | vcc->channo, - RC_FLAGS_AAL5 | - RC_FLAGS_BFPS_BFP * bfp | - RC_FLAGS_RXBM_PSB, 0, 0); - + switch (atm_vcc->qos.aal) { + case ATM_AAL0: + case ATM_AAL2: + submit_command (dev, &dev->hp_txq, + QE_CMD_CONFIG_RX | QE_CMD_IMM_INQ | vcc->channo, + RC_FLAGS_TRANSP | + RC_FLAGS_BFPS_BFP * bfp | + RC_FLAGS_RXBM_PSB, 0, 0); + break; + case ATM_AAL5: + submit_command (dev, &dev->hp_txq, + QE_CMD_CONFIG_RX | QE_CMD_IMM_INQ | vcc->channo, + RC_FLAGS_AAL5 | + RC_FLAGS_BFPS_BFP * bfp | + RC_FLAGS_RXBM_PSB, 0, 0); + break; + }; if (IS_FS50 (dev)) { submit_command (dev, &dev->hp_txq, QE_CMD_REG_WR | QE_CMD_IMM_INQ, @@ -1697,7 +1731,7 @@ /* AN3: 10 */ write_fs (dev, SARMODE1, 0 - | (0 * SARMODE1_DEFHEC) /* XXX PHY */ + | (fs_keystream * SARMODE1_DEFHEC) /* XXX PHY */ | ((loopback == 1) * SARMODE1_TSTLP) /* XXX Loopback mode enable... */ | (1 * SARMODE1_DCRM) | (1 * SARMODE1_DCOAM) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/atm/firestream.h linux.ac/drivers/atm/firestream.h --- linux.vanilla/drivers/atm/firestream.h Fri Dec 29 22:35:47 2000 +++ linux.ac/drivers/atm/firestream.h Thu Apr 12 12:01:08 2001 @@ -369,6 +369,9 @@ }; #define TC_FLAGS_AAL5 (0x0 << 29) +#define TC_FLAGS_TRANSPARENT_PAYLOAD (0x1 << 29) +#define TC_FLAGS_TRANSPARENT_CELL (0x2 << 29) +#define TC_FLAGS_STREAMING (0x1 << 28) #define TC_FLAGS_PACKET (0x0) #define TC_FLAGS_TYPE_ABR (0x0 << 22) #define TC_FLAGS_TYPE_CBR (0x1 << 22) @@ -498,8 +501,8 @@ /* Within limits this is user-configurable. */ /* Note: Currently the sum (10 -> 1k channels) is hardcoded in the driver. */ -#define FS155_VPI_BITS 5 -#define FS155_VCI_BITS 5 +#define FS155_VPI_BITS 4 +#define FS155_VCI_BITS 6 #define FS155_CHANNEL_BITS (FS155_VPI_BITS + FS155_VCI_BITS) #define FS155_NR_CHANNELS (1 << FS155_CHANNEL_BITS) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/atm/zatm.c linux.ac/drivers/atm/zatm.c --- linux.vanilla/drivers/atm/zatm.c Tue Jul 18 22:55:01 2000 +++ linux.ac/drivers/atm/zatm.c Thu Apr 12 12:01:08 2001 @@ -1826,9 +1826,13 @@ devs++; zatm_dev = (struct zatm_dev *) kmalloc(sizeof(struct zatm_dev),GFP_KERNEL); - if (!zatm_dev) break; + if (!zatm_dev) { + printk(KERN_EMERG "zatm.c: memory shortage\n"); + goto out; + } } } +out: return devs; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/Config.in linux.ac/drivers/block/Config.in --- linux.vanilla/drivers/block/Config.in Sat Feb 3 20:13:19 2001 +++ linux.ac/drivers/block/Config.in Tue Apr 3 17:54:37 2001 @@ -42,7 +42,7 @@ tristate 'RAM disk support' CONFIG_BLK_DEV_RAM if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then - int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096 + int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096 fi dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/DAC960.c linux.ac/drivers/block/DAC960.c --- linux.vanilla/drivers/block/DAC960.c Wed Feb 21 05:26:22 2001 +++ linux.ac/drivers/block/DAC960.c Tue Apr 3 17:54:37 2001 @@ -506,16 +506,20 @@ void *DataPointer) { DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); - DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; - DAC960_V1_CommandStatus_T CommandStatus; - DAC960_V1_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - CommandMailbox->Type3.CommandOpcode = CommandOpcode; - CommandMailbox->Type3.BusAddress = Virtual_to_Bus32(DataPointer); - DAC960_ExecuteCommand(Command); - CommandStatus = Command->V1.CommandStatus; - DAC960_DeallocateCommand(Command); - return (CommandStatus == DAC960_V1_NormalCompletion); + if (Command == NULL) { + return false; + } else { + DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; + DAC960_V1_CommandStatus_T CommandStatus; + DAC960_V1_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + CommandMailbox->Type3.CommandOpcode = CommandOpcode; + CommandMailbox->Type3.BusAddress = Virtual_to_Bus32(DataPointer); + DAC960_ExecuteCommand(Command); + CommandStatus = Command->V1.CommandStatus; + DAC960_DeallocateCommand(Command); + return (CommandStatus == DAC960_V1_NormalCompletion); + } } @@ -532,18 +536,22 @@ void *DataPointer) { DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); - DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; - DAC960_V1_CommandStatus_T CommandStatus; - DAC960_V1_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - CommandMailbox->Type3D.CommandOpcode = CommandOpcode; - CommandMailbox->Type3D.Channel = Channel; - CommandMailbox->Type3D.TargetID = TargetID; - CommandMailbox->Type3D.BusAddress = Virtual_to_Bus32(DataPointer); - DAC960_ExecuteCommand(Command); - CommandStatus = Command->V1.CommandStatus; - DAC960_DeallocateCommand(Command); - return (CommandStatus == DAC960_V1_NormalCompletion); + if (Command == NULL) { + return false; + } else { + DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; + DAC960_V1_CommandStatus_T CommandStatus; + DAC960_V1_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + CommandMailbox->Type3D.CommandOpcode = CommandOpcode; + CommandMailbox->Type3D.Channel = Channel; + CommandMailbox->Type3D.TargetID = TargetID; + CommandMailbox->Type3D.BusAddress = Virtual_to_Bus32(DataPointer); + DAC960_ExecuteCommand(Command); + CommandStatus = Command->V1.CommandStatus; + DAC960_DeallocateCommand(Command); + return (CommandStatus == DAC960_V1_NormalCompletion); + } } @@ -559,29 +567,33 @@ unsigned int DataByteCount) { DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); - DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; - DAC960_V2_CommandStatus_T CommandStatus; - DAC960_V2_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - CommandMailbox->Common.CommandOpcode = DAC960_V2_IOCTL; - CommandMailbox->Common.CommandControlBits + if (Command == NULL) { + return false; + } else { + DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; + DAC960_V2_CommandStatus_T CommandStatus; + DAC960_V2_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + CommandMailbox->Common.CommandOpcode = DAC960_V2_IOCTL; + CommandMailbox->Common.CommandControlBits .DataTransferControllerToHost = true; - CommandMailbox->Common.CommandControlBits + CommandMailbox->Common.CommandControlBits .NoAutoRequestSense = true; - CommandMailbox->Common.DataTransferSize = DataByteCount; - CommandMailbox->Common.IOCTL_Opcode = IOCTL_Opcode; - CommandMailbox->Common.DataTransferMemoryAddress + CommandMailbox->Common.DataTransferSize = DataByteCount; + CommandMailbox->Common.IOCTL_Opcode = IOCTL_Opcode; + CommandMailbox->Common.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus64(DataPointer); - CommandMailbox->Common.DataTransferMemoryAddress + Virtual_to_Bus64(DataPointer); + CommandMailbox->Common.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = - CommandMailbox->Common.DataTransferSize; - DAC960_ExecuteCommand(Command); - CommandStatus = Command->V2.CommandStatus; - DAC960_DeallocateCommand(Command); - return (CommandStatus == DAC960_V2_NormalCompletion); + CommandMailbox->Common.DataTransferSize; + DAC960_ExecuteCommand(Command); + CommandStatus = Command->V2.CommandStatus; + DAC960_DeallocateCommand(Command); + return (CommandStatus == DAC960_V2_NormalCompletion); + } } @@ -597,30 +609,34 @@ unsigned int DataByteCount) { DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); - DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; - DAC960_V2_CommandStatus_T CommandStatus; - DAC960_V2_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - CommandMailbox->ControllerInfo.CommandOpcode = DAC960_V2_IOCTL; - CommandMailbox->ControllerInfo.CommandControlBits + if (Command == NULL) { + return false; + } else { + DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; + DAC960_V2_CommandStatus_T CommandStatus; + DAC960_V2_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + CommandMailbox->ControllerInfo.CommandOpcode = DAC960_V2_IOCTL; + CommandMailbox->ControllerInfo.CommandControlBits .DataTransferControllerToHost = true; - CommandMailbox->ControllerInfo.CommandControlBits + CommandMailbox->ControllerInfo.CommandControlBits .NoAutoRequestSense = true; - CommandMailbox->ControllerInfo.DataTransferSize = DataByteCount; - CommandMailbox->ControllerInfo.ControllerNumber = 0; - CommandMailbox->ControllerInfo.IOCTL_Opcode = IOCTL_Opcode; - CommandMailbox->ControllerInfo.DataTransferMemoryAddress + CommandMailbox->ControllerInfo.DataTransferSize = DataByteCount; + CommandMailbox->ControllerInfo.ControllerNumber = 0; + CommandMailbox->ControllerInfo.IOCTL_Opcode = IOCTL_Opcode; + CommandMailbox->ControllerInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus64(DataPointer); - CommandMailbox->ControllerInfo.DataTransferMemoryAddress + Virtual_to_Bus64(DataPointer); + CommandMailbox->ControllerInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = - CommandMailbox->ControllerInfo.DataTransferSize; - DAC960_ExecuteCommand(Command); - CommandStatus = Command->V2.CommandStatus; - DAC960_DeallocateCommand(Command); - return (CommandStatus == DAC960_V2_NormalCompletion); + CommandMailbox->ControllerInfo.DataTransferSize; + DAC960_ExecuteCommand(Command); + CommandStatus = Command->V2.CommandStatus; + DAC960_DeallocateCommand(Command); + return (CommandStatus == DAC960_V2_NormalCompletion); + } } @@ -639,31 +655,35 @@ unsigned int DataByteCount) { DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); - DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; - DAC960_V2_CommandStatus_T CommandStatus; - DAC960_V2_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - CommandMailbox->LogicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL; - CommandMailbox->LogicalDeviceInfo.CommandControlBits + if (Command == NULL) { + return false; + } else { + DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; + DAC960_V2_CommandStatus_T CommandStatus; + DAC960_V2_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + CommandMailbox->LogicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL; + CommandMailbox->LogicalDeviceInfo.CommandControlBits .DataTransferControllerToHost = true; - CommandMailbox->LogicalDeviceInfo.CommandControlBits + CommandMailbox->LogicalDeviceInfo.CommandControlBits .NoAutoRequestSense = true; - CommandMailbox->LogicalDeviceInfo.DataTransferSize = DataByteCount; - CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber = - LogicalDeviceNumber; - CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode = IOCTL_Opcode; - CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress + CommandMailbox->LogicalDeviceInfo.DataTransferSize = DataByteCount; + CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber = + LogicalDeviceNumber; + CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode = IOCTL_Opcode; + CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus64(DataPointer); - CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress + Virtual_to_Bus64(DataPointer); + CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = - CommandMailbox->LogicalDeviceInfo.DataTransferSize; - DAC960_ExecuteCommand(Command); - CommandStatus = Command->V2.CommandStatus; - DAC960_DeallocateCommand(Command); - return (CommandStatus == DAC960_V2_NormalCompletion); + CommandMailbox->LogicalDeviceInfo.DataTransferSize; + DAC960_ExecuteCommand(Command); + CommandStatus = Command->V2.CommandStatus; + DAC960_DeallocateCommand(Command); + return (CommandStatus == DAC960_V2_NormalCompletion); + } } @@ -683,32 +703,36 @@ unsigned int DataByteCount) { DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); - DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; - DAC960_V2_CommandStatus_T CommandStatus; - DAC960_V2_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL; - CommandMailbox->PhysicalDeviceInfo.CommandControlBits + if (Command == NULL) { + return false; + } else { + DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; + DAC960_V2_CommandStatus_T CommandStatus; + DAC960_V2_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL; + CommandMailbox->PhysicalDeviceInfo.CommandControlBits .DataTransferControllerToHost = true; - CommandMailbox->PhysicalDeviceInfo.CommandControlBits + CommandMailbox->PhysicalDeviceInfo.CommandControlBits .NoAutoRequestSense = true; - CommandMailbox->PhysicalDeviceInfo.DataTransferSize = DataByteCount; - CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.LogicalUnit = LogicalUnit; - CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.TargetID = TargetID; - CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.Channel = Channel; - CommandMailbox->PhysicalDeviceInfo.IOCTL_Opcode = IOCTL_Opcode; - CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress + CommandMailbox->PhysicalDeviceInfo.DataTransferSize = DataByteCount; + CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.LogicalUnit = LogicalUnit; + CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.TargetID = TargetID; + CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.Channel = Channel; + CommandMailbox->PhysicalDeviceInfo.IOCTL_Opcode = IOCTL_Opcode; + CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus64(DataPointer); - CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress + Virtual_to_Bus64(DataPointer); + CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = - CommandMailbox->PhysicalDeviceInfo.DataTransferSize; - DAC960_ExecuteCommand(Command); - CommandStatus = Command->V2.CommandStatus; - DAC960_DeallocateCommand(Command); - return (CommandStatus == DAC960_V2_NormalCompletion); + CommandMailbox->PhysicalDeviceInfo.DataTransferSize; + DAC960_ExecuteCommand(Command); + CommandStatus = Command->V2.CommandStatus; + DAC960_DeallocateCommand(Command); + return (CommandStatus == DAC960_V2_NormalCompletion); + } } @@ -724,21 +748,25 @@ OperationDevice) { DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); - DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; - DAC960_V2_CommandStatus_T CommandStatus; - DAC960_V2_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - CommandMailbox->DeviceOperation.CommandOpcode = DAC960_V2_IOCTL; - CommandMailbox->DeviceOperation.CommandControlBits + if (Command == NULL) { + return false; + } else { + DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; + DAC960_V2_CommandStatus_T CommandStatus; + DAC960_V2_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + CommandMailbox->DeviceOperation.CommandOpcode = DAC960_V2_IOCTL; + CommandMailbox->DeviceOperation.CommandControlBits .DataTransferControllerToHost = true; - CommandMailbox->DeviceOperation.CommandControlBits + CommandMailbox->DeviceOperation.CommandControlBits .NoAutoRequestSense = true; - CommandMailbox->DeviceOperation.IOCTL_Opcode = IOCTL_Opcode; - CommandMailbox->DeviceOperation.OperationDevice = OperationDevice; - DAC960_ExecuteCommand(Command); - CommandStatus = Command->V2.CommandStatus; - DAC960_DeallocateCommand(Command); - return (CommandStatus == DAC960_V2_NormalCompletion); + CommandMailbox->DeviceOperation.IOCTL_Opcode = IOCTL_Opcode; + CommandMailbox->DeviceOperation.OperationDevice = OperationDevice; + DAC960_ExecuteCommand(Command); + CommandStatus = Command->V2.CommandStatus; + DAC960_DeallocateCommand(Command); + return (CommandStatus == DAC960_V2_NormalCompletion); + } } @@ -1423,20 +1451,27 @@ kmalloc(sizeof(DAC960_V2_PhysicalDeviceInfo_T), GFP_ATOMIC); if (PhysicalDeviceInfo == NULL) return DAC960_Failure(Controller, "PHYSICAL DEVICE ALLOCATION"); + InquiryUnitSerialNumber = (DAC960_SCSI_Inquiry_UnitSerialNumber_T *) + kmalloc(sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), GFP_ATOMIC); + if (InquiryUnitSerialNumber == NULL) { + kfree(PhysicalDeviceInfo); + return DAC960_Failure(Controller, "SERIAL NUMBER ALLOCATION"); + } + Command = DAC960_AllocateCommand(Controller); + if (Command == NULL) { + kfree(PhysicalDeviceInfo); + kfree(InquiryUnitSerialNumber); + return DAC960_Failure(Controller, "COMMAND ALLOCATION"); + } Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex] = PhysicalDeviceInfo; memcpy(PhysicalDeviceInfo, NewPhysicalDeviceInfo, sizeof(DAC960_V2_PhysicalDeviceInfo_T)); - InquiryUnitSerialNumber = (DAC960_SCSI_Inquiry_UnitSerialNumber_T *) - kmalloc(sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), GFP_ATOMIC); - if (InquiryUnitSerialNumber == NULL) - return DAC960_Failure(Controller, "SERIAL NUMBER ALLOCATION"); Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex] = InquiryUnitSerialNumber; memset(InquiryUnitSerialNumber, 0, sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; - Command = DAC960_AllocateCommand(Controller); CommandMailbox = &Command->V2.CommandMailbox; DAC960_V2_ClearCommand(Command); Command->CommandType = DAC960_ImmediateCommand; @@ -4128,7 +4163,8 @@ if (InquiryUnitSerialNumber == NULL && PhysicalDeviceInfo != NULL) { - kfree(PhysicalDeviceInfo); + if (PhysicalDeviceInfo) + kfree(PhysicalDeviceInfo); PhysicalDeviceInfo = NULL; } DAC960_Critical("Physical Device %d:%d Now Exists%s\n", diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/Makefile linux.ac/drivers/block/Makefile --- linux.vanilla/drivers/block/Makefile Fri Dec 29 22:07:21 2000 +++ linux.ac/drivers/block/Makefile Mon Apr 9 23:39:31 2001 @@ -10,7 +10,9 @@ O_TARGET := block.o -export-objs := ll_rw_blk.o blkpg.o loop.o DAC960.o +mod-subdirs := paride + +export-objs := ll_rw_blk.o blkpg.o elevator.o loop.o DAC960.o obj-y := ll_rw_blk.o blkpg.o genhd.o elevator.o @@ -27,11 +29,17 @@ obj-$(CONFIG_BLK_DEV_PS2) += ps2esdi.o obj-$(CONFIG_BLK_DEV_XD) += xd.o obj-$(CONFIG_BLK_CPQ_DA) += cpqarray.o -obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o +obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o obj-$(CONFIG_BLK_DEV_NBD) += nbd.o subdir-$(CONFIG_PARIDE) += paride + +ifeq ($(CONFIG_ARCH_ACORN),y) +mod-subdirs += ../acorn/block +subdir-y += ../acorn/block +obj-y += ../acorn/block/acorn-block.o +endif include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/acsi_slm.c linux.ac/drivers/block/acsi_slm.c --- linux.vanilla/drivers/block/acsi_slm.c Fri Feb 9 19:30:22 2001 +++ linux.ac/drivers/block/acsi_slm.c Tue Apr 3 17:54:38 2001 @@ -378,19 +378,22 @@ length = slm_getstats( (char *)page, MINOR(node->i_rdev) ); if (length < 0) { - free_page( page ); - return( length ); + count = length; + goto out; } if (file->f_pos >= length) { - free_page( page ); - return( 0 ); + count = 0; + goto out; } if (count + file->f_pos > length) count = length - file->f_pos; end = count + file->f_pos; - copy_to_user( buf, (char *)page + file->f_pos, count ); - free_page( page ); + if (copy_to_user(buf, (char *)page + file->f_pos, count)) { + count = -EFAULT; + goto out; + } file->f_pos = end; +out: free_page( page ); return( count ); } @@ -648,7 +651,8 @@ if (filled + n > BufferSize) n = BufferSize - filled; - copy_from_user( BufferP, buf, n ); + if (copy_from_user(BufferP, buf, n)) + return -EFAULT; BufferP += n; filled += n; @@ -725,8 +729,9 @@ if (put_user(stat, (long *)&((struct SLM_status *)arg)->stat)) return -EFAULT; - copy_to_user( ((struct SLM_status *)arg)->str, str, - strlen(str) + 1 ); + if (copy_to_user( ((struct SLM_status *)arg)->str, str, + strlen(str) + 1)) + return -EFAULT; } return( stat ); } @@ -734,10 +739,6 @@ case SLMIOGPSIZE: { /* get paper size */ int w, h; - err = verify_area( VERIFY_WRITE, (long *)arg, - sizeof(struct SLM_paper_size) ); - if (err) return( err ); - if ((err = slm_get_pagesize( device, &w, &h ))) return( err ); if (put_user(w, (long *)&((struct SLM_paper_size *)arg)->width)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/cciss.c linux.ac/drivers/block/cciss.c --- linux.vanilla/drivers/block/cciss.c Fri Feb 9 19:30:22 2001 +++ linux.ac/drivers/block/cciss.c Tue Apr 3 17:54:38 2001 @@ -583,13 +583,15 @@ if (iocommand.Request.Type.Direction == XFER_WRITE) { /* Copy the data into the buffer we created */ - if (copy_from_user(buff, iocommand.buf, iocommand.buf_size)) + if (copy_from_user(buff, iocommand.buf, + iocommand.buf_size)) { + kfree(buff); return -EFAULT; + } } if ((c = cmd_alloc(NULL)) == NULL) { - if(buff!=NULL) - kfree(buff); + kfree(buff); return -ENOMEM; } // Fill in the command type @@ -636,8 +638,7 @@ if ( copy_to_user((void *) arg, &iocommand, sizeof( IOCTL_Command_struct) ) ) { cmd_free(NULL, c); - if (buff != NULL) - kfree(buff); + kfree(buff); return( -EFAULT); } @@ -648,11 +649,11 @@ { cmd_free(NULL, c); kfree(buff); + return -EFAULT; } } cmd_free(NULL, c); - if (buff != NULL) - kfree(buff); + kfree(buff); return(0); } @@ -761,7 +762,7 @@ hba[ctlr]->gendisk.nr_real = 0; /* - * Tell the array controller not to give us any interupts while + * Tell the array controller not to give us any interrupts while * we check the new geometry. Then turn interrupts back on when * we're done. */ @@ -1087,7 +1088,7 @@ if (timeout) status = 0; if(cmd->err_info->CommandStatus != 0) - { /* an error has occured */ + { /* an error has occurred */ switch(cmd->err_info->CommandStatus) { case CMD_TARGET_STATUS: @@ -1846,12 +1847,9 @@ || (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); + kfree(hba[i]->cmd_pool_bits); + kfree(hba[i]->cmd_pool); + kfree(hba[i]->errinfo_pool); free_irq(hba[i]->intr, hba[i]); unregister_blkdev(MAJOR_NR+i, hba[i]->devname); num_cntlrs_reg--; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/cciss.h linux.ac/drivers/block/cciss.h --- linux.vanilla/drivers/block/cciss.h Sat Feb 3 20:13:19 2001 +++ linux.ac/drivers/block/cciss.h Sun Apr 15 23:31:54 2001 @@ -122,7 +122,7 @@ } /* - * This card is the oposite of the other cards. + * This card is the opposite of the other cards. * 0 turns interrupts on... * 0x08 turns them off... */ @@ -138,7 +138,7 @@ } } /* - * This card is the oposite of the other cards. + * This card is the opposite of the other cards. * 0 turns interrupts on... * 0x04 turns them off... */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/cciss_cmd.h linux.ac/drivers/block/cciss_cmd.h --- linux.vanilla/drivers/block/cciss_cmd.h Sat Sep 23 01:11:37 2000 +++ linux.ac/drivers/block/cciss_cmd.h Tue Apr 3 17:54:38 2001 @@ -222,7 +222,7 @@ ErrDescriptor_struct ErrDesc; SGDescriptor_struct SG[MAXSGENTRIES]; /* information associated with the command */ - __u32 busaddr; /* physical addres of this record */ + __u32 busaddr; /* physical address of this record */ ErrorInfo_struct * err_info; /* pointer to the allocated mem */ int cmd_type; struct _CommandList_struct *prev; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/elevator.c linux.ac/drivers/block/elevator.c --- linux.vanilla/drivers/block/elevator.c Fri Feb 16 00:58:34 2001 +++ linux.ac/drivers/block/elevator.c Mon Apr 9 23:39:31 2001 @@ -220,3 +220,11 @@ *elevator = type; elevator->queue_ID = queue_ID++; } + +EXPORT_SYMBOL(elevator_init); +EXPORT_SYMBOL(elevator_linus_merge); +EXPORT_SYMBOL(elevator_linus_merge_cleanup); +EXPORT_SYMBOL(elevator_linus_merge_req); +EXPORT_SYMBOL(elevator_noop_merge); +EXPORT_SYMBOL(elevator_noop_merge_cleanup); +EXPORT_SYMBOL(elevator_noop_merge_req); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/genhd.c linux.ac/drivers/block/genhd.c --- linux.vanilla/drivers/block/genhd.c Mon Sep 18 07:16:35 2000 +++ linux.ac/drivers/block/genhd.c Tue Apr 3 17:54:38 2001 @@ -23,6 +23,9 @@ #ifdef CONFIG_BLK_DEV_DAC960 extern void DAC960_Initialize(void); #endif +#ifdef CONFIG_FUSION_BOOT +extern int fusion_init(void); +#endif extern int net_dev_init(void); extern void console_map_init(void); extern int soc_probe(void); @@ -44,6 +47,9 @@ #endif #ifdef CONFIG_BLK_DEV_DAC960 DAC960_Initialize(); +#endif +#ifdef CONFIG_FUSION_BOOT + fusion_init(); #endif #ifdef CONFIG_FC4_SOC /* This has to be done before scsi_dev_init */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/ll_rw_blk.c linux.ac/drivers/block/ll_rw_blk.c --- linux.vanilla/drivers/block/ll_rw_blk.c Tue Apr 3 17:32:00 2001 +++ linux.ac/drivers/block/ll_rw_blk.c Sat Apr 14 01:20:25 2001 @@ -231,8 +231,7 @@ * If a driver processes several requests at once, it must remove them (or * at least all but one of them) from the request queue. * - * When a queue is plugged (see blk_queue_pluggable()) the head will be - * assumed to be inactive. + * When a queue is plugged the head will be assumed to be inactive. **/ void blk_queue_headactive(request_queue_t * q, int active) @@ -241,35 +240,6 @@ } /** - * blk_queue_pluggable - define a plugging function for a request queue - * @q: the request queue to which the function will apply - * @plug: the function to be called to plug a queue - * - * Description: - * A request queue will be "plugged" if a request is added to it - * while it is empty. This allows a number of requests to be added - * before any are processed, thus providing an opportunity for these - * requests to be merged or re-ordered. - * The default plugging function (generic_plug_device()) sets the - * "plugged" flag for the queue and adds a task to the $tq_disk task - * queue to unplug the queue and call the request function at a - * later time. - * - * A device driver may provide an alternate plugging function by - * passing it to blk_queue_pluggable(). This function should set - * the "plugged" flag if it want calls to the request_function to be - * blocked, and should place a task on $tq_disk which will unplug - * the queue. Alternately it can simply do nothing and there-by - * disable plugging of the device. - **/ - -void blk_queue_pluggable (request_queue_t * q, plug_device_fn *plug) -{ - q->plug_device_fn = plug; -} - - -/** * blk_queue_make_request - define an alternate make_request function for a device * @q: the request queue for the device to be affected * @mfn: the alternate make_request function @@ -395,6 +365,11 @@ */ for (i = 0; i < queue_nr_requests; i++) { rq = kmem_cache_alloc(request_cachep, SLAB_KERNEL); + if (rq == NULL) { + /* We'll get a `leaked requests' message from blk_cleanup_queue */ + printk(KERN_EMERG "blk_init_free_list: error allocating requests\n"); + break; + } memset(rq, 0, sizeof(struct request)); rq->rq_status = RQ_INACTIVE; list_add(&rq->table, &q->request_freelist[i & 1]); @@ -453,6 +428,7 @@ q->plug_tq.routine = &generic_unplug_device; q->plug_tq.data = q; q->plugged = 0; + /* * These booleans describe the queue properties. We set the * default (and most common) values here. Other drivers can @@ -590,7 +566,7 @@ list_add(&req->queue, insert_here); } -void inline blk_refill_freelist(request_queue_t *q, int rw) +inline void blk_refill_freelist(request_queue_t *q, int rw) { if (q->pending_free[rw]) { list_splice(&q->pending_freelist[rw], &q->request_freelist[rw]); @@ -602,7 +578,7 @@ /* * Must be called with io_request_lock held and interrupts disabled */ -void inline blkdev_release_request(struct request *req) +inline void blkdev_release_request(struct request *req) { request_queue_t *q = req->q; int rw = req->cmd; @@ -959,6 +935,20 @@ if (!test_bit(BH_Lock, &bh->b_state)) BUG(); + /* + * don't lock any more buffers if we are above the high + * water mark. instead start I/O on the queued stuff. + */ + if (atomic_read(&queued_sectors) >= high_queued_sectors) { + run_task_queue(&tq_disk); + if (rw == READA) { + bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); + return; + } + wait_event(blk_buffers_wait, + atomic_read(&queued_sectors) < low_queued_sectors); + } + set_bit(BH_Req, &bh->b_state); /* @@ -1060,16 +1050,6 @@ for (i = 0; i < nr; i++) { struct buffer_head *bh = bhs[i]; - /* - * don't lock any more buffers if we are above the high - * water mark. instead start I/O on the queued stuff. - */ - if (atomic_read(&queued_sectors) >= high_queued_sectors) { - run_task_queue(&tq_disk); - wait_event(blk_buffers_wait, - atomic_read(&queued_sectors) < low_queued_sectors); - } - /* Only one thread can actually submit the I/O. */ if (test_and_set_bit(BH_Lock, &bh->b_state)) continue; @@ -1320,15 +1300,19 @@ #ifdef CONFIG_DDV ddv_init(); #endif -#ifdef CONFIG_BLK_DEV_NBD - nbd_init(); -#endif #ifdef CONFIG_MDISK mdisk_init(); #endif #ifdef CONFIG_DASD dasd_init(); #endif +#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_BLOCK) + tapeblock_init(); +#endif +#ifdef CONFIG_BLK_DEV_XPRAM + xpram_init(); +#endif + #ifdef CONFIG_SUN_JSFLASH jsfd_init(); #endif @@ -1343,7 +1327,6 @@ EXPORT_SYMBOL(__blk_get_queue); EXPORT_SYMBOL(blk_cleanup_queue); EXPORT_SYMBOL(blk_queue_headactive); -EXPORT_SYMBOL(blk_queue_pluggable); EXPORT_SYMBOL(blk_queue_make_request); EXPORT_SYMBOL(generic_make_request); EXPORT_SYMBOL(blkdev_release_request); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/nbd.c linux.ac/drivers/block/nbd.c --- linux.vanilla/drivers/block/nbd.c Tue Apr 3 17:32:00 2001 +++ linux.ac/drivers/block/nbd.c Tue Apr 3 17:54:38 2001 @@ -26,12 +26,11 @@ * structure with userland */ -#undef NBD_PLUGGABLE #define PARANOIA #include <linux/major.h> #include <linux/module.h> - +#include <linux/init.h> #include <linux/sched.h> #include <linux/fs.h> #include <linux/stat.h> @@ -68,8 +67,6 @@ static int requests_out; #endif -static void nbd_plug_device(request_queue_t *q, kdev_t dev) { } - static int nbd_open(struct inode *inode, struct file *file) { int dev; @@ -88,7 +85,7 @@ /* * Send or receive packet. */ -static int nbd_xmit(int send, struct socket *sock, char *buf, int size) +static int nbd_xmit(int send, struct socket *sock, char *buf, int size, int msg_flags) { mm_segment_t oldfs; int result; @@ -118,7 +115,7 @@ msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_namelen = 0; - msg.msg_flags = 0; + msg.msg_flags = msg_flags | MSG_NOSIGNAL; if (send) result = sock_sendmsg(sock, &msg, size); @@ -151,23 +148,28 @@ { int result; struct nbd_request request; + unsigned long size = req->nr_sectors << 9; DEBUG("NBD: sending control, "); request.magic = htonl(NBD_REQUEST_MAGIC); request.type = htonl(req->cmd); request.from = cpu_to_be64( (u64) req->sector << 9); - request.len = htonl(req->current_nr_sectors << 9); + request.len = htonl(size); memcpy(request.handle, &req, sizeof(req)); - result = nbd_xmit(1, sock, (char *) &request, sizeof(request)); + result = nbd_xmit(1, sock, (char *) &request, sizeof(request), req->cmd == WRITE ? MSG_MORE : 0); if (result <= 0) FAIL("Sendmsg failed for control."); if (req->cmd == WRITE) { + struct buffer_head *bh = req->bh; DEBUG("data, "); - result = nbd_xmit(1, sock, req->buffer, req->current_nr_sectors << 9); - if (result <= 0) - FAIL("Send data failed."); + do { + result = nbd_xmit(1, sock, bh->b_data, bh->b_size, bh->b_reqnext == NULL ? 0 : MSG_MORE); + if (result <= 0) + FAIL("Send data failed."); + bh = bh->b_reqnext; + } while(bh); } return; @@ -185,7 +187,7 @@ DEBUG("reading control, "); reply.magic = 0; - result = nbd_xmit(0, lo->sock, (char *) &reply, sizeof(reply)); + result = nbd_xmit(0, lo->sock, (char *) &reply, sizeof(reply), MSG_WAITALL); if (result <= 0) HARDFAIL("Recv control failed."); memcpy(&xreq, reply.handle, sizeof(xreq)); @@ -200,10 +202,14 @@ if (ntohl(reply.error)) FAIL("Other side returned error."); if (req->cmd == READ) { + struct buffer_head *bh = req->bh; DEBUG("data, "); - result = nbd_xmit(0, lo->sock, req->buffer, req->current_nr_sectors << 9); - if (result <= 0) - HARDFAIL("Recv data failed."); + do { + result = nbd_xmit(0, lo->sock, bh->b_data, bh->b_size, MSG_WAITALL); + if (result <= 0) + HARDFAIL("Recv data failed."); + bh = bh->b_reqnext; + } while(bh); } DEBUG("done.\n"); return req; @@ -217,7 +223,6 @@ void nbd_do_it(struct nbd_device *lo) { struct request *req; - int dequeued; down (&lo->queue_lock); while (1) { @@ -245,11 +250,9 @@ list_del(&req->queue); up (&lo->queue_lock); - dequeued = nbd_end_request(req); + nbd_end_request(req); down (&lo->queue_lock); - if (!dequeued) - list_add(&req->queue, &lo->queue_head); } out: up (&lo->queue_lock); @@ -258,7 +261,6 @@ void nbd_clear_que(struct nbd_device *lo) { struct request *req; - int dequeued; #ifdef PARANOIA if (lo->magic != LO_MAGIC) { @@ -283,11 +285,9 @@ list_del(&req->queue); up(&lo->queue_lock); - dequeued = nbd_end_request(req); + nbd_end_request(req); down(&lo->queue_lock); - if (!dequeued) - list_add(&req->queue, &lo->queue_head); } } @@ -477,11 +477,7 @@ * (Just smiley confuses emacs :-) */ -#ifdef MODULE -#define nbd_init init_module -#endif - -int nbd_init(void) +static int __init nbd_init(void) { int i; @@ -501,9 +497,6 @@ blksize_size[MAJOR_NR] = nbd_blksizes; blk_size[MAJOR_NR] = nbd_sizes; blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_nbd_request); -#ifndef NBD_PLUGGABLE - blk_queue_pluggable(BLK_DEFAULT_QUEUE(MAJOR_NR), nbd_plug_device); -#endif blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0); for (i = 0; i < MAX_NBD; i++) { nbd_dev[i].refcnt = 0; @@ -528,8 +521,7 @@ return 0; } -#ifdef MODULE -void cleanup_module(void) +static void __exit nbd_cleanup(void) { devfs_unregister (devfs_handle); blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); @@ -539,4 +531,9 @@ else printk("nbd: module cleaned up.\n"); } -#endif + +module_init(nbd_init); +module_exit(nbd_cleanup); + +MODULE_DESCRIPTION("Network Block Device"); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/paride/Config.in linux.ac/drivers/block/paride/Config.in --- linux.vanilla/drivers/block/paride/Config.in Mon Jan 24 19:21:47 2000 +++ linux.ac/drivers/block/paride/Config.in Tue Apr 10 18:13:16 2001 @@ -20,7 +20,8 @@ dep_tristate ' Parallel port generic ATAPI devices' CONFIG_PARIDE_PG $CONFIG_PARIDE comment 'Parallel IDE protocol modules' dep_tristate ' ATEN EH-100 protocol' CONFIG_PARIDE_ATEN $CONFIG_PARIDE -dep_tristate ' MicroSolutions backpack protocol' CONFIG_PARIDE_BPCK $CONFIG_PARIDE +dep_tristate ' MicroSolutions backpack (Series 5) protocol' CONFIG_PARIDE_BPCK $CONFIG_PARIDE +dep_tristate ' MicroSolutions backpack (Series 6) protocol' CONFIG_PARIDE_BPCK6 $CONFIG_PARIDE dep_tristate ' DataStor Commuter protocol' CONFIG_PARIDE_COMM $CONFIG_PARIDE dep_tristate ' DataStor EP-2000 protocol' CONFIG_PARIDE_DSTR $CONFIG_PARIDE dep_tristate ' FIT TD-2000 protocol' CONFIG_PARIDE_FIT2 $CONFIG_PARIDE diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/paride/Makefile linux.ac/drivers/block/paride/Makefile --- linux.vanilla/drivers/block/paride/Makefile Fri Dec 29 22:07:21 2000 +++ linux.ac/drivers/block/paride/Makefile Tue Apr 10 18:13:16 2001 @@ -27,5 +27,6 @@ obj-$(CONFIG_PARIDE_ON20) += on20.o obj-$(CONFIG_PARIDE_ON26) += on26.o obj-$(CONFIG_PARIDE_KTTI) += ktti.o +obj-$(CONFIG_PARIDE_BPCK6) += bpck6.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/paride/bpck6.c linux.ac/drivers/block/paride/bpck6.c --- linux.vanilla/drivers/block/paride/bpck6.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/block/paride/bpck6.c Tue Apr 10 18:13:16 2001 @@ -0,0 +1,317 @@ +/* + backpack.c (c) 2001 Micro Solutions Inc. + Released under the terms of the GNU General Public license + + backpack.c is a low-level protocol driver for the Micro Solutions + "BACKPACK" parallel port IDE adapter + (Works on Series 6 drives) + + Written by: Ken Hahn (linux-dev@micro-solutions.com) + Clive Turvey (linux-dev@micro-solutions.com) + +*/ + +/* + This is Ken's linux wrapper for the PPC library + Version 1.0.0 is the backpack driver for which source is not available + Version 2.0.0 is the first to have source released + Version 2.0.1 is the "Cox-ified" source code + Version 2.0.2 - fixed version string usage, and made ppc functions static +*/ + + +/* PARAMETERS */ +int verbose=0; /* set this to 1 to see debugging messages and whatnot */ + +#define BACKPACK_VERSION "2.0.2" + +#define EXPORT_SYMTAB +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/malloc.h> +#include <linux/types.h> +#include <asm/io.h> + +#if defined(CONFIG_PARPORT_MODULE)||defined(CONFIG_PARPORT) +#include <linux/parport.h> +#endif + +#include "ppc6lnx.c" +#include "paride.h" + + + +#define PPCSTRUCT(pi) ((PPC *)(pi->private)) + +/****************************************************************/ +/* + ATAPI CDROM DRIVE REGISTERS +*/ +#define ATAPI_DATA 0 /* data port */ +#define ATAPI_ERROR 1 /* error register (read) */ +#define ATAPI_FEATURES 1 /* feature register (write) */ +#define ATAPI_INT_REASON 2 /* interrupt reason register */ +#define ATAPI_COUNT_LOW 4 /* byte count register (low) */ +#define ATAPI_COUNT_HIGH 5 /* byte count register (high) */ +#define ATAPI_DRIVE_SEL 6 /* drive select register */ +#define ATAPI_STATUS 7 /* status port (read) */ +#define ATAPI_COMMAND 7 /* command port (write) */ +#define ATAPI_ALT_STATUS 0x0e /* alternate status reg (read) */ +#define ATAPI_DEVICE_CONTROL 0x0e /* device control (write) */ +/****************************************************************/ + +static int bpck6_read_regr(PIA *pi, int cont, int reg) +{ + unsigned int out; + + /* check for bad settings */ + if (reg<0 || reg>7 || cont<0 || cont>2) + { + return(-1); + } + out=ppc6_rd_port(PPCSTRUCT(pi),cont?reg|8:reg); + return(out); +} + +static void bpck6_write_regr(PIA *pi, int cont, int reg, int val) +{ + /* check for bad settings */ + if (reg>=0 && reg<=7 && cont>=0 && cont<=1) + { + ppc6_wr_port(PPCSTRUCT(pi),cont?reg|8:reg,(u8)val); + } +} + +static void bpck6_write_block( PIA *pi, char * buf, int len ) +{ + ppc6_wr_port16_blk(PPCSTRUCT(pi),ATAPI_DATA,buf,(u32)len>>1); +} + +static void bpck6_read_block( PIA *pi, char * buf, int len ) +{ + ppc6_rd_port16_blk(PPCSTRUCT(pi),ATAPI_DATA,buf,(u32)len>>1); +} + +static void bpck6_connect ( PIA *pi ) +{ + if(verbose) + { + printk(KERN_DEBUG "connect\n"); + } + + if(pi->mode >=2) + { + PPCSTRUCT(pi)->mode=4+pi->mode-2; + } + else if(pi->mode==1) + { + PPCSTRUCT(pi)->mode=3; + } + else + { + PPCSTRUCT(pi)->mode=1; + } + + ppc6_open(PPCSTRUCT(pi)); + ppc6_wr_extout(PPCSTRUCT(pi),0x3); +} + +static void bpck6_disconnect ( PIA *pi ) +{ + if(verbose) + { + printk("disconnect\n"); + } + ppc6_wr_extout(PPCSTRUCT(pi),0x0); + ppc6_close(PPCSTRUCT(pi)); +} + +static int bpck6_test_port ( PIA *pi ) /* check for 8-bit port */ +{ + if(verbose) + { + printk(KERN_DEBUG "PARPORT indicates modes=%x for lp=0x%lx\n", + ((struct pardevice*)(pi->pardev))->port->modes, + ((struct pardevice *)(pi->pardev))->port->base); + } + + /*copy over duplicate stuff.. initialize state info*/ + PPCSTRUCT(pi)->ppc_id=pi->unit; + PPCSTRUCT(pi)->lpt_addr=pi->port; + +#ifdef CONFIG_PARPORT_PC_MODULE +#define CONFIG_PARPORT_PC +#endif + +#ifdef CONFIG_PARPORT_PC + /* look at the parport device to see if what modes we can use */ + if(((struct pardevice *)(pi->pardev))->port->modes & + (PARPORT_MODE_EPP) + ) + { + return 5; /* Can do EPP*/ + } + else if(((struct pardevice *)(pi->pardev))->port->modes & + (PARPORT_MODE_TRISTATE) + ) + { + return 2; + } + else /*Just flat SPP*/ + { + return 1; + } +#else + /* there is no way of knowing what kind of port we have + default to the highest mode possible */ + return 5; +#endif +} + +static int bpck6_probe_unit ( PIA *pi ) +{ + int out; + + if(verbose) + { + printk(KERN_DEBUG "PROBE UNIT %x on port:%x\n",pi->unit,pi->port); + } + + /*SET PPC UNIT NUMBER*/ + PPCSTRUCT(pi)->ppc_id=pi->unit; + + /*LOWER DOWN TO UNIDIRECTIONAL*/ + PPCSTRUCT(pi)->mode=1; + + out=ppc6_open(PPCSTRUCT(pi)); + + if(verbose) + { + printk(KERN_DEBUG "ppc_open returned %2x\n",out); + } + + if(out) + { + ppc6_close(PPCSTRUCT(pi)); + return(1); + if(verbose) + { + printk(KERN_DEBUG "leaving probe\n"); + } + } + else + { + if(verbose) + { + printk(KERN_DEBUG "Failed open\n"); + } + return(0); + } +} + +static void bpck6_log_adapter( PIA *pi, char * scratch, int verbose ) +{ + char *mode_string[5]= + {"4-bit","8-bit","EPP-8","EPP-16","EPP-32"}; + + printk("%s: BACKPACK Protocol Driver V"BACKPACK_VERSION"\n",pi->device); + printk("%s: Copyright 2001 by Micro Solutions, Inc., DeKalb IL.\n",pi->device); + printk("%s: BACKPACK %s, Micro Solutions BACKPACK Drive at 0x%x\n", + pi->device,BACKPACK_VERSION,pi->port); + printk("%s: Unit: %d Mode:%d (%s) Delay %d\n",pi->device, + pi->unit,pi->mode,mode_string[pi->mode],pi->delay); +} + +static void bpck6_init_proto(PIA *pi) +{ + int i; + + /* allocate a state structure for this item */ + pi->private=(int)kmalloc(sizeof(PPC),GFP_KERNEL); + + if(pi->private==(int)NULL) + { + printk(KERN_ERR "%s: ERROR COULDN'T ALLOCATE MEMORY\n",pi->device); + return; + } + else + { + MOD_INC_USE_COUNT; + } + + for(i=0;i<sizeof(PPC);i++) + { + ((unsigned char *)(pi->private))[i]=0; + } +} + +static void bpck6_release_proto(PIA *pi) +{ + MOD_DEC_USE_COUNT; + /* free after use count decremented so that we aren't using it + when it is decremented */ + kfree((void *)(pi->private)); +} + +struct pi_protocol bpck6 = { "bpck6", /* name for proto*/ + 0, /* index into proto table */ + 5, /* max mode =5 */ + 2, /* 2-5 use epp (need 8 ports) */ + 0, /* no delay (not used anyway) */ + 255, /* we can have units up to 255 */ + bpck6_write_regr, + bpck6_read_regr, + bpck6_write_block, + bpck6_read_block, + bpck6_connect, + bpck6_disconnect, + bpck6_test_port, + bpck6_probe_unit, + 0, + bpck6_log_adapter, + bpck6_init_proto, + bpck6_release_proto + }; + + +EXPORT_SYMBOL(bpck6_write_regr); +EXPORT_SYMBOL(bpck6_read_regr); +EXPORT_SYMBOL(bpck6_write_block); +EXPORT_SYMBOL(bpck6_read_block); +EXPORT_SYMBOL(bpck6_connect); +EXPORT_SYMBOL(bpck6_disconnect); +EXPORT_SYMBOL(bpck6_test_port); +EXPORT_SYMBOL(bpck6_probe_unit); +EXPORT_SYMBOL(bpck6_log_adapter); +EXPORT_SYMBOL(bpck6_init_proto); +EXPORT_SYMBOL(bpck6_release_proto); + +/*---------------------------MODULE STUFF-----------------------*/ + +#ifdef MODULE +/*module information*/ + +static int init_module(void) +{ + printk(KERN_INFO "bpck6: BACKPACK Protocol Driver V"BACKPACK_VERSION"\n"); + printk(KERN_INFO "bpck6: Copyright 2001 by Micro Solutions, Inc., DeKalb IL. USA\n"); + + if(verbose) + { + printk(KERN_DEBUG "bpck6: verbose debug enabled.\n"); + } + + return pi_register(&bpck6) - 1; +} + +void cleanup_module(void) +{ + pi_unregister(&bpck6); +} + +MODULE_AUTHOR("Micro Solutions Inc."); +MODULE_DESCRIPTION("BACKPACK Protocol module, compatible with PARIDE"); +MODULE_PARM(verbose,"i"); + +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/paride/paride.c linux.ac/drivers/block/paride/paride.c --- linux.vanilla/drivers/block/paride/paride.c Sun Feb 4 18:05:29 2001 +++ linux.ac/drivers/block/paride/paride.c Tue Apr 10 18:13:26 2001 @@ -15,9 +15,10 @@ 1.04 GRG 1998.11.28 added support for FRIQ 1.05 TMW 2000.06.06 use parport_find_number instead of parport_enumerate + 1.06 TMW 2001.03.26 more sane parport-or-not resource management */ -#define PI_VERSION "1.05" +#define PI_VERSION "1.06" #include <linux/module.h> #include <linux/config.h> @@ -160,8 +161,10 @@ void pi_release( PIA *pi) { pi_unregister_parport(pi); - if ((!pi->pardev)&&(pi->reserved)) +#ifndef CONFIG_PARPORT + if (pi->reserved) release_region(pi->port,pi->reserved); +#endif /* !CONFIG_PARPORT */ pi->proto->release_proto(pi); } @@ -234,7 +237,7 @@ MOD_DEC_USE_COUNT; } -static void pi_register_parport( PIA *pi, int verbose) +static int pi_register_parport( PIA *pi, int verbose) { #ifdef CONFIG_PARPORT @@ -242,15 +245,16 @@ struct parport *port; port = parport_find_base (pi->port); - if (!port) return; + if (!port) + return 0; pi->pardev = parport_register_device(port, pi->device,NULL, pi_wake_up,NULL, 0,(void *)pi); parport_put_port (port); - if (!pi->pardev) return; - + if (!pi->pardev) + return 0; init_waitqueue_head(&pi->parq); @@ -258,8 +262,9 @@ port->name); pi->parname = (char *)port->name; - #endif + + return 1; } static int pi_probe_mode( PIA *pi, int max, char * scratch, int verbose) @@ -271,7 +276,9 @@ range = 3; if (pi->mode >= pi->proto->epp_first) range = 8; if ((range == 8) && (pi->port % 8)) return 0; - if ((!pi->pardev) && check_region(pi->port,range)) return 0; +#ifndef CONFIG_PARPORT + if (check_region(pi->port,range)) return 0; +#endif /* !CONFIG_PARPORT */ pi->reserved = range; return (!pi_test_proto(pi,scratch,verbose)); } @@ -280,7 +287,9 @@ range = 3; if (pi->mode >= pi->proto->epp_first) range = 8; if ((range == 8) && (pi->port % 8)) break; - if ((!pi->pardev) && check_region(pi->port,range)) break; +#ifndef CONFIG_PARPORT + if (check_region(pi->port,range)) break; +#endif /* !CONFIG_PARPORT */ pi->reserved = range; if (!pi_test_proto(pi,scratch,verbose)) best = pi->mode; } @@ -299,9 +308,12 @@ e = pi->proto->max_units; } - pi_register_parport(pi,verbose); + if (!pi_register_parport(pi,verbose)) + return 0; - if ((!pi->pardev) && check_region(pi->port,3)) return 0; +#ifndef CONFIG_PARPORT + if (check_region(pi->port,3)) return 0; +#endif /* !CONFIG_PARPORT */ if (pi->proto->test_port) { pi_claim(pi); @@ -391,8 +403,9 @@ return 0; } - if (!pi->pardev) - request_region(pi->port,pi->reserved,pi->device); +#ifndef CONFIG_PARPORT + request_region(pi->port,pi->reserved,pi->device); +#endif /* !CONFIG_PARPORT */ if (pi->parname) printk("%s: Sharing %s at 0x%x\n",pi->device, @@ -407,11 +420,16 @@ int init_module(void) -{ int k; +{ + int k; + const char *indicate_pp = ""; +#ifdef CONFIG_PARPORT + indicate_pp = " (parport)"; +#endif for (k=0;k<MAX_PROTOS;k++) protocols[k] = 0; - printk("paride: version %s installed\n",PI_VERSION); + printk("paride: version %s installed%s\n",PI_VERSION,indicate_pp); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/paride/ppc6lnx.c linux.ac/drivers/block/paride/ppc6lnx.c --- linux.vanilla/drivers/block/paride/ppc6lnx.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/block/paride/ppc6lnx.c Tue Apr 10 18:13:26 2001 @@ -0,0 +1,950 @@ +/* + ppc6lnx.c (c) 2001 Micro Solutions Inc. + Released under the terms of the GNU General Public license + + ppc6lnx.c is a par of the protocol driver for the Micro Solutions + "BACKPACK" parallel port IDE adapter + (Works on Series 6 drives) + +*/ + +//*************************************************************************** + +// PPC 6 Code in C sanitized for LINUX +// Original x86 ASM by Ron, Converted to C by Clive + +//*************************************************************************** + + +#define port_stb 1 +#define port_afd 2 +#define cmd_stb port_afd +#define port_init 4 +#define data_stb port_init +#define port_sel 8 +#define port_int 16 +#define port_dir 0x20 + +#define ECR_EPP 0x80 +#define ECR_BI 0x20 + +//*************************************************************************** + +// 60772 Commands + +#define ACCESS_REG 0x00 +#define ACCESS_PORT 0x40 + +#define ACCESS_READ 0x00 +#define ACCESS_WRITE 0x20 + +// 60772 Command Prefix + +#define CMD_PREFIX_SET 0xe0 // Special command that modifies the next command's operation +#define CMD_PREFIX_RESET 0xc0 // Resets current cmd modifier reg bits + #define PREFIX_IO16 0x01 // perform 16-bit wide I/O + #define PREFIX_FASTWR 0x04 // enable PPC mode fast-write + #define PREFIX_BLK 0x08 // enable block transfer mode + +// 60772 Registers + +#define REG_STATUS 0x00 // status register + #define STATUS_IRQA 0x01 // Peripheral IRQA line + #define STATUS_EEPROM_DO 0x40 // Serial EEPROM data bit +#define REG_VERSION 0x01 // PPC version register (read) +#define REG_HWCFG 0x02 // Hardware Config register +#define REG_RAMSIZE 0x03 // Size of RAM Buffer + #define RAMSIZE_128K 0x02 +#define REG_EEPROM 0x06 // EEPROM control register + #define EEPROM_SK 0x01 // eeprom SK bit + #define EEPROM_DI 0x02 // eeprom DI bit + #define EEPROM_CS 0x04 // eeprom CS bit + #define EEPROM_EN 0x08 // eeprom output enable +#define REG_BLKSIZE 0x08 // Block transfer len (24 bit) + +//*************************************************************************** + +typedef struct ppc_storage { + u16 lpt_addr; // LPT base address + u8 ppc_id; + u8 mode; // operating mode + // 0 = PPC Uni SW + // 1 = PPC Uni FW + // 2 = PPC Bi SW + // 3 = PPC Bi FW + // 4 = EPP Byte + // 5 = EPP Word + // 6 = EPP Dword + u8 ppc_flags; + u8 org_data; // original LPT data port contents + u8 org_ctrl; // original LPT control port contents + u8 cur_ctrl; // current control port contents +} PPC; + +//*************************************************************************** + +// ppc_flags + +#define fifo_wait 0x10 + +//*************************************************************************** + +// DONT CHANGE THESE LEST YOU BREAK EVERYTHING - BIT FIELD DEPENDENCIES + +#define PPCMODE_UNI_SW 0 +#define PPCMODE_UNI_FW 1 +#define PPCMODE_BI_SW 2 +#define PPCMODE_BI_FW 3 +#define PPCMODE_EPP_BYTE 4 +#define PPCMODE_EPP_WORD 5 +#define PPCMODE_EPP_DWORD 6 + +//*************************************************************************** + +static int ppc6_select(PPC *ppc); +static void ppc6_deselect(PPC *ppc); +static void ppc6_send_cmd(PPC *ppc, u8 cmd); +static void ppc6_wr_data_byte(PPC *ppc, u8 data); +static u8 ppc6_rd_data_byte(PPC *ppc); +static u8 ppc6_rd_port(PPC *ppc, u8 port); +static void ppc6_wr_port(PPC *ppc, u8 port, u8 data); +static u8 ppc6_rd_reg(PPC *ppc, u8 reg); +static void ppc6_wr_reg(PPC *ppc, u8 reg, u8 data); +static u8 ppc6_version(PPC *ppc); +static void ppc6_rd_data_blk(PPC *ppc, u8 *data, long count); +static void ppc6_wait_for_fifo(PPC *ppc); +static void ppc6_wr_data_blk(PPC *ppc, u8 *data, long count); +static void ppc6_rd_port16_blk(PPC *ppc, u8 port, u8 *data, long length); +static u16 ppc6_rd_port16(PPC *ppc, u8 port); +static void ppc6_wr_port16(PPC *ppc, u8 port, u16 data); +static void ppc6_wr_port16_blk(PPC *ppc, u8 port, u8 *data, long length); +static u8 ppc6_rd_eeprom_reg(PPC *ppc); +static void ppc6_wr_eeprom_reg(PPC *ppc, u8 data); +static void ppc6_eeprom_start(PPC *ppc); +static void ppc6_eeprom_end(PPC *ppc); +static void ppc6_set_cs(PPC *ppc); +static void ppc6_reset_cs(PPC *ppc); +static u8 ppc6_rd_eeprom_bit(PPC *ppc); +static void ppc6_eeprom_ready_wait(PPC *ppc); +static void ppc6_wr_eeprom_bit(PPC *ppc, u8 bit); +static u16 ppc6_eeprom_read(PPC *ppc, u8 addr); +static u8 ppc6_irq_test(PPC *ppc); +static u8 ppc6_rd_extout(PPC *ppc); +static void ppc6_wr_extout(PPC *ppc, u8 regdata); +static int ppc6_open(PPC *ppc); +static void ppc6_close(PPC *ppc); + +//*************************************************************************** + +static int ppc6_select(PPC *ppc) +{ + u8 i, j, k; + + i = inb(ppc->lpt_addr + 1); + + if (i & 1) + outb(i, ppc->lpt_addr + 1); + + ppc->org_data = inb(ppc->lpt_addr); + + ppc->org_ctrl = inb(ppc->lpt_addr + 2) & 0x5F; // readback ctrl + + ppc->cur_ctrl = ppc->org_ctrl; + + ppc->cur_ctrl |= port_sel; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + if (ppc->org_data == 'b') + outb('x', ppc->lpt_addr); + + outb('b', ppc->lpt_addr); + outb('p', ppc->lpt_addr); + outb(ppc->ppc_id, ppc->lpt_addr); + outb(~ppc->ppc_id,ppc->lpt_addr); + + ppc->cur_ctrl &= ~port_sel; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + ppc->cur_ctrl = (ppc->cur_ctrl & port_int) | port_init; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + i = ppc->mode & 0x0C; + + if (i == 0) + i = (ppc->mode & 2) | 1; + + outb(i, ppc->lpt_addr); + + ppc->cur_ctrl |= port_sel; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + // DELAY + + ppc->cur_ctrl |= port_afd; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + j = ((i & 0x08) << 4) | ((i & 0x07) << 3); + + k = inb(ppc->lpt_addr + 1) & 0xB8; + + if (j == k) + { + ppc->cur_ctrl &= ~port_afd; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + k = (inb(ppc->lpt_addr + 1) & 0xB8) ^ 0xB8; + + if (j == k) + { + if (i & 4) // EPP + ppc->cur_ctrl &= ~(port_sel | port_init); + else // PPC/ECP + ppc->cur_ctrl &= ~port_sel; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + return(1); + } + } + + outb(ppc->org_ctrl, ppc->lpt_addr + 2); + + outb(ppc->org_data, ppc->lpt_addr); + + return(0); // FAIL +} + +//*************************************************************************** + +static void ppc6_deselect(PPC *ppc) +{ + if (ppc->mode & 4) // EPP + ppc->cur_ctrl |= port_init; + else // PPC/ECP + ppc->cur_ctrl |= port_sel; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + outb(ppc->org_data, ppc->lpt_addr); + + outb((ppc->org_ctrl | port_sel), ppc->lpt_addr + 2); + + outb(ppc->org_ctrl, ppc->lpt_addr + 2); +} + +//*************************************************************************** + +static void ppc6_send_cmd(PPC *ppc, u8 cmd) +{ + switch(ppc->mode) + { + case PPCMODE_UNI_SW : + case PPCMODE_UNI_FW : + case PPCMODE_BI_SW : + case PPCMODE_BI_FW : + { + outb(cmd, ppc->lpt_addr); + + ppc->cur_ctrl ^= cmd_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + break; + } + + case PPCMODE_EPP_BYTE : + case PPCMODE_EPP_WORD : + case PPCMODE_EPP_DWORD : + { + outb(cmd, ppc->lpt_addr + 3); + + break; + } + } +} + +//*************************************************************************** + +static void ppc6_wr_data_byte(PPC *ppc, u8 data) +{ + switch(ppc->mode) + { + case PPCMODE_UNI_SW : + case PPCMODE_UNI_FW : + case PPCMODE_BI_SW : + case PPCMODE_BI_FW : + { + outb(data, ppc->lpt_addr); + + ppc->cur_ctrl ^= data_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + break; + } + + case PPCMODE_EPP_BYTE : + case PPCMODE_EPP_WORD : + case PPCMODE_EPP_DWORD : + { + outb(data, ppc->lpt_addr + 4); + + break; + } + } +} + +//*************************************************************************** + +static u8 ppc6_rd_data_byte(PPC *ppc) +{ + u8 data; + + switch(ppc->mode) + { + case PPCMODE_UNI_SW : + case PPCMODE_UNI_FW : + { + ppc->cur_ctrl = (ppc->cur_ctrl & ~port_stb) ^ data_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + // DELAY + + data = inb(ppc->lpt_addr + 1); + + data = ((data & 0x80) >> 1) | ((data & 0x38) >> 3); + + ppc->cur_ctrl |= port_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + // DELAY + + data |= inb(ppc->lpt_addr + 1) & 0xB8; + + break; + } + + case PPCMODE_BI_SW : + case PPCMODE_BI_FW : + { + ppc->cur_ctrl |= port_dir; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + ppc->cur_ctrl = (ppc->cur_ctrl | port_stb) ^ data_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + data = inb(ppc->lpt_addr); + + ppc->cur_ctrl &= ~port_stb; + + outb(ppc->cur_ctrl,ppc->lpt_addr + 2); + + ppc->cur_ctrl &= ~port_dir; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + break; + } + + case PPCMODE_EPP_BYTE : + case PPCMODE_EPP_WORD : + case PPCMODE_EPP_DWORD : + { + outb((ppc->cur_ctrl | port_dir),ppc->lpt_addr + 2); + + data = inb(ppc->lpt_addr + 4); + + outb(ppc->cur_ctrl,ppc->lpt_addr + 2); + + break; + } + } + + return(data); +} + +//*************************************************************************** + +static u8 ppc6_rd_port(PPC *ppc, u8 port) +{ + ppc6_send_cmd(ppc,(u8)(port | ACCESS_PORT | ACCESS_READ)); + + return(ppc6_rd_data_byte(ppc)); +} + +//*************************************************************************** + +static void ppc6_wr_port(PPC *ppc, u8 port, u8 data) +{ + ppc6_send_cmd(ppc,(u8)(port | ACCESS_PORT | ACCESS_WRITE)); + + ppc6_wr_data_byte(ppc, data); +} + +//*************************************************************************** + +static u8 ppc6_rd_reg(PPC *ppc, u8 reg) +{ + ppc6_send_cmd(ppc,(u8)(reg | ACCESS_REG | ACCESS_READ)); + + return(ppc6_rd_data_byte(ppc)); +} + +//*************************************************************************** + +static void ppc6_wr_reg(PPC *ppc, u8 reg, u8 data) +{ + ppc6_send_cmd(ppc,(u8)(reg | ACCESS_REG | ACCESS_WRITE)); + + ppc6_wr_data_byte(ppc, data); +} + +//*************************************************************************** + +static u8 ppc6_version(PPC *ppc) +{ + ppc6_send_cmd(ppc,(REG_VERSION | ACCESS_REG | ACCESS_READ)); + + return(ppc6_rd_data_byte(ppc) & 0x3F); +} + +//*************************************************************************** + +static void ppc6_rd_data_blk(PPC *ppc, u8 *data, long count) +{ + switch(ppc->mode) + { + case PPCMODE_UNI_SW : + case PPCMODE_UNI_FW : + { + while(count) + { + u8 d; + + ppc->cur_ctrl = (ppc->cur_ctrl & ~port_stb) ^ data_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + // DELAY + + d = inb(ppc->lpt_addr + 1); + + d = ((d & 0x80) >> 1) | ((d & 0x38) >> 3); + + ppc->cur_ctrl |= port_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + // DELAY + + d |= inb(ppc->lpt_addr + 1) & 0xB8; + + *data++ = d; + count--; + } + + break; + } + + case PPCMODE_BI_SW : + case PPCMODE_BI_FW : + { + ppc->cur_ctrl |= port_dir; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + ppc->cur_ctrl |= port_stb; + + while(count) + { + ppc->cur_ctrl ^= data_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + *data++ = inb(ppc->lpt_addr); + count--; + } + + ppc->cur_ctrl &= ~port_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + ppc->cur_ctrl &= ~port_dir; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + break; + } + + case PPCMODE_EPP_BYTE : + { + outb((ppc->cur_ctrl | port_dir), ppc->lpt_addr + 2); + + // DELAY + + while(count) + { + *data++ = inb(ppc->lpt_addr + 4); + count--; + } + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + break; + } + + case PPCMODE_EPP_WORD : + { + outb((ppc->cur_ctrl | port_dir), ppc->lpt_addr + 2); + + // DELAY + + while(count > 1) + { + *((u16 *)data) = inw(ppc->lpt_addr + 4); + data += 2; + count -= 2; + } + + while(count) + { + *data++ = inb(ppc->lpt_addr + 4); + count--; + } + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + break; + } + + case PPCMODE_EPP_DWORD : + { + outb((ppc->cur_ctrl | port_dir),ppc->lpt_addr + 2); + + // DELAY + + while(count > 3) + { + *((u32 *)data) = inl(ppc->lpt_addr + 4); + data += 4; + count -= 4; + } + + while(count) + { + *data++ = inb(ppc->lpt_addr + 4); + count--; + } + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + break; + } + } + +} + +//*************************************************************************** + +static void ppc6_wait_for_fifo(PPC *ppc) +{ + int i; + + if (ppc->ppc_flags & fifo_wait) + { + for(i=0; i<20; i++) + inb(ppc->lpt_addr + 1); + } +} + +//*************************************************************************** + +static void ppc6_wr_data_blk(PPC *ppc, u8 *data, long count) +{ + switch(ppc->mode) + { + case PPCMODE_UNI_SW : + case PPCMODE_BI_SW : + { + while(count--) + { + outb(*data++, ppc->lpt_addr); + + ppc->cur_ctrl ^= data_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + } + + break; + } + + case PPCMODE_UNI_FW : + case PPCMODE_BI_FW : + { + u8 this, last; + + ppc6_send_cmd(ppc,(CMD_PREFIX_SET | PREFIX_FASTWR)); + + ppc->cur_ctrl |= port_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + last = *data; + + outb(last, ppc->lpt_addr); + + while(count) + { + this = *data++; + count--; + + if (this == last) + { + ppc->cur_ctrl ^= data_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + } + else + { + outb(this, ppc->lpt_addr); + + last = this; + } + } + + ppc->cur_ctrl &= ~port_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + ppc6_send_cmd(ppc,(CMD_PREFIX_RESET | PREFIX_FASTWR)); + + break; + } + + case PPCMODE_EPP_BYTE : + { + while(count) + { + outb(*data++,ppc->lpt_addr + 4); + count--; + } + + ppc6_wait_for_fifo(ppc); + + break; + } + + case PPCMODE_EPP_WORD : + { + while(count > 1) + { + outw(*((u16 *)data),ppc->lpt_addr + 4); + data += 2; + count -= 2; + } + + while(count) + { + outb(*data++,ppc->lpt_addr + 4); + count--; + } + + ppc6_wait_for_fifo(ppc); + + break; + } + + case PPCMODE_EPP_DWORD : + { + while(count > 3) + { + outl(*((u32 *)data),ppc->lpt_addr + 4); + data += 4; + count -= 4; + } + + while(count) + { + outb(*data++,ppc->lpt_addr + 4); + count--; + } + + ppc6_wait_for_fifo(ppc); + + break; + } + } +} + +//*************************************************************************** + +static void ppc6_rd_port16_blk(PPC *ppc, u8 port, u8 *data, long length) +{ + length = length << 1; + + ppc6_send_cmd(ppc, (REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE)); + ppc6_wr_data_byte(ppc,(u8)length); + ppc6_wr_data_byte(ppc,(u8)(length >> 8)); + ppc6_wr_data_byte(ppc,0); + + ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK)); + + ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_READ)); + + ppc6_rd_data_blk(ppc, data, length); + + ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK)); +} + +//*************************************************************************** + +static u16 ppc6_rd_port16(PPC *ppc, u8 port) +{ + u16 data; + + ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16)); + + ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_READ)); + + data = ppc6_rd_data_byte(ppc); + + ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_READ)); + + data += (u16)ppc6_rd_data_byte(ppc) << 8; + + ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16)); + + return(data); +} + +//*************************************************************************** + +static void ppc6_wr_port16(PPC *ppc, u8 port, u16 data) +{ + ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16)); + + ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_WRITE)); + + ppc6_wr_data_byte(ppc, (u8)data); + + ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_WRITE)); + + ppc6_wr_data_byte(ppc, (u8)(data >> 8)); + + ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16)); +} + +//*************************************************************************** + +static void ppc6_wr_port16_blk(PPC *ppc, u8 port, u8 *data, long length) +{ + length = length << 1; + + ppc6_send_cmd(ppc, (REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE)); + ppc6_wr_data_byte(ppc,(u8)length); + ppc6_wr_data_byte(ppc,(u8)(length >> 8)); + ppc6_wr_data_byte(ppc,0); + + ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK)); + + ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_WRITE)); + + ppc6_wr_data_blk(ppc, data, length); + + ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK)); +} + +//*************************************************************************** + +static u8 ppc6_rd_eeprom_reg(PPC *ppc) +{ + ppc6_send_cmd(ppc, (REG_EEPROM | ACCESS_REG | ACCESS_READ)); + + return(ppc6_rd_data_byte(ppc)); +} + +//*************************************************************************** + +static void ppc6_wr_eeprom_reg(PPC *ppc, u8 data) +{ + ppc6_send_cmd(ppc, (REG_EEPROM | ACCESS_REG | ACCESS_WRITE)); + + ppc6_wr_data_byte(ppc, data); +} + +//*************************************************************************** + +static void ppc6_eeprom_start(PPC *ppc) +{ + ppc6_wr_eeprom_reg(ppc, EEPROM_EN); +} + +//*************************************************************************** + +static void ppc6_eeprom_end(PPC *ppc) +{ + ppc6_wr_eeprom_reg(ppc, 0); +} + +//*************************************************************************** + +static void ppc6_set_cs(PPC *ppc) +{ + ppc6_wr_eeprom_reg(ppc, (u8)(ppc6_rd_eeprom_reg(ppc) | EEPROM_CS)); +} + +//*************************************************************************** + +static void ppc6_reset_cs(PPC *ppc) +{ + ppc6_wr_eeprom_reg(ppc, (u8)(ppc6_rd_eeprom_reg(ppc) & ~EEPROM_CS)); +} + +//*************************************************************************** + +static u8 ppc6_rd_eeprom_bit(PPC *ppc) +{ + ppc6_send_cmd(ppc, (REG_STATUS | ACCESS_REG | ACCESS_READ)); + + if (ppc6_rd_data_byte(ppc) & STATUS_EEPROM_DO) + return(1); + else + return(0); +} + +//*************************************************************************** + +static void ppc6_eeprom_ready_wait(PPC *ppc) +{ + ppc6_set_cs(ppc); + + while(ppc6_rd_eeprom_bit(ppc)); + + ppc6_reset_cs(ppc); +} + +//*************************************************************************** + +static void ppc6_wr_eeprom_bit(PPC *ppc, u8 bit) +{ + u8 eereg; + + eereg = ppc6_rd_eeprom_reg(ppc); + + eereg &= ~(EEPROM_SK | EEPROM_DI); + + if (bit & 1) + eereg |= EEPROM_DI; + + ppc6_wr_eeprom_reg(ppc, eereg); + + eereg |= EEPROM_SK; + + ppc6_wr_eeprom_reg(ppc, eereg); + + eereg &= ~EEPROM_SK; + + ppc6_wr_eeprom_reg(ppc, eereg); +} + +//*************************************************************************** + +static u16 ppc6_eeprom_read(PPC *ppc, u8 addr) +{ + int i; + u16 data; + + ppc6_set_cs(ppc); + + ppc6_wr_eeprom_bit(ppc, 1); // Start bit + + ppc6_wr_eeprom_bit(ppc, 1); // opcode 10 (read) + ppc6_wr_eeprom_bit(ppc, 0); + + for(i=0; i<6; i++) + ppc6_wr_eeprom_bit(ppc, (u8)((addr >> (5 - i)) & 1)); + + data = 0; + + for(i=0; i<16; i++) + { + ppc6_wr_eeprom_bit(ppc,0); + + data = (data << 1) | ppc6_rd_eeprom_bit(ppc); + } + + ppc6_reset_cs(ppc); + + return(data); +} + +//*************************************************************************** + +static u8 ppc6_irq_test(PPC *ppc) +{ + ppc6_send_cmd(ppc,(REG_STATUS | ACCESS_REG | ACCESS_READ)); + + return(ppc6_rd_data_byte(ppc) & STATUS_IRQA); +} + +//*************************************************************************** + +static u8 ppc6_rd_extout(PPC *ppc) +{ + ppc6_send_cmd(ppc,(REG_VERSION | ACCESS_REG | ACCESS_READ)); + + return((ppc6_rd_data_byte(ppc) & 0xC0) >> 6); +} + +//*************************************************************************** + +static void ppc6_wr_extout(PPC *ppc, u8 regdata) +{ + ppc6_send_cmd(ppc,(REG_VERSION | ACCESS_REG | ACCESS_WRITE)); + + ppc6_wr_data_byte(ppc, (u8)((regdata & 0x03) << 6)); +} + +//*************************************************************************** + +static int ppc6_open(PPC *ppc) +{ + int ret; + + ret = ppc6_select(ppc); + + if (ret == 0) + return(ret); + + ppc->ppc_flags &= ~fifo_wait; + + ppc6_send_cmd(ppc, (ACCESS_REG | ACCESS_WRITE | REG_RAMSIZE)); + ppc6_wr_data_byte(ppc, RAMSIZE_128K); + + ppc6_send_cmd(ppc, (ACCESS_REG | ACCESS_READ | REG_VERSION)); + + if ((ppc6_rd_data_byte(ppc) & 0x3F) == 0x0C) + ppc->ppc_flags |= fifo_wait; + + return(ret); +} + +//*************************************************************************** + +static void ppc6_close(PPC *ppc) +{ + ppc6_deselect(ppc); +} + +//*************************************************************************** + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/ps2esdi.c linux.ac/drivers/block/ps2esdi.c --- linux.vanilla/drivers/block/ps2esdi.c Fri Oct 27 07:35:47 2000 +++ linux.ac/drivers/block/ps2esdi.c Sun Apr 15 23:14:50 2001 @@ -52,6 +52,7 @@ #include <asm/io.h> #include <asm/segment.h> #include <asm/dma.h> +#include <asm/mca_dma.h> #include <asm/uaccess.h> #define PS2ESDI_IRQ 14 @@ -89,8 +90,6 @@ static void ps2esdi_initial_reset_int_handler(u_int); static void ps2esdi_geometry_int_handler(u_int); -static void ps2esdi_continue_request(void); - static int ps2esdi_open(struct inode *inode, struct file *file); static int ps2esdi_release(struct inode *inode, struct file *file); @@ -469,29 +468,26 @@ DEVICE_NAME, CURRENT_DEV, MINOR(CURRENT->rq_dev), CURRENT->cmd, CURRENT->sector, - CURRENT->nr_sectors, CURRENT->buffer); + CURRENT->current_nr_sectors, CURRENT->buffer); #endif /* standard macro that ensures that requests are really on the list + sanity checks. */ INIT_REQUEST; - if (virt_to_bus(CURRENT->buffer + CURRENT->nr_sectors * 512) > 16 * MB) { + if (virt_to_bus(CURRENT->buffer + CURRENT->current_nr_sectors * 512) > 16 * MB) { printk("%s: DMA above 16MB not supported\n", DEVICE_NAME); end_request(FAIL); - if (!QUEUE_EMPTY) - do_ps2esdi_request(q); - return; } /* check for above 16Mb dmas */ - if ((CURRENT_DEV < ps2esdi_drives) && - (CURRENT->sector + CURRENT->nr_sectors <= + else if ((CURRENT_DEV < ps2esdi_drives) && + (CURRENT->sector + CURRENT->current_nr_sectors <= ps2esdi[MINOR(CURRENT->rq_dev)].nr_sects)) { #if 0 printk("%s:got request. device : %d minor : %d command : %d sector : %ld count : %ld\n", DEVICE_NAME, - CURRENT_DEV, MINOR(CURRENT->dev), + CURRENT_DEV, MINOR(CURRENT->rq_dev), CURRENT->cmd, CURRENT->sector, - CURRENT->nr_sectors); + CURRENT->current_nr_sectors); #endif @@ -500,21 +496,17 @@ #if 0 printk("%s: blocknumber : %d\n", DEVICE_NAME, block); #endif - count = CURRENT->nr_sectors; + count = CURRENT->current_nr_sectors; switch (CURRENT->cmd) { case READ: ps2esdi_readwrite(READ, CURRENT_DEV, block, count); - return; break; case WRITE: ps2esdi_readwrite(WRITE, CURRENT_DEV, block, count); - return; break; default: printk("%s: Unknown command\n", DEVICE_NAME); end_request(FAIL); - if (!QUEUE_EMPTY) - do_ps2esdi_request(q); break; } /* handle different commands */ } @@ -523,8 +515,6 @@ printk("Grrr. error. ps2esdi_drives: %d, %lu %lu\n", ps2esdi_drives, CURRENT->sector, ps2esdi[MINOR(CURRENT->rq_dev)].nr_sects); end_request(FAIL); - if (!QUEUE_EMPTY) - do_ps2esdi_request(q); } } /* main strategy routine */ @@ -570,8 +560,6 @@ u_short cmd_blk[TYPE_1_CMD_BLK_LENGTH]; /* do some relevant arithmatic */ - CURRENT->current_nr_sectors = - (count < (2 * MAX_16BIT / SECT_SIZE)) ? count : (2 * MAX_16BIT / SECT_SIZE); track = block / ps2esdi_info[drive].sect; head = track % ps2esdi_info[drive].head; cylinder = track / ps2esdi_info[drive].head; @@ -590,13 +578,8 @@ /* send the command block to the controller */ if (ps2esdi_out_cmd_blk(cmd_blk)) { printk("%s: Controller failed\n", DEVICE_NAME); - if ((++CURRENT->errors) < MAX_RETRIES) - return do_ps2esdi_request(NULL); - else { + if ((++CURRENT->errors) >= MAX_RETRIES) end_request(FAIL); - if (!QUEUE_EMPTY) - do_ps2esdi_request(NULL); - } } /* check for failure to put out the command block */ else { @@ -675,33 +658,23 @@ /* prepare for dma - do all the necessary setup */ static void ps2esdi_prep_dma(char *buffer, u_short length, u_char dma_xmode) { - u_int tc; - - buffer=(char *)virt_to_bus(buffer); - + unsigned long flags; #if 0 - printk("ps2esdi: b_wait: %p\n", CURRENT->bh->b_wait); + printk("ps2esdi: b_wait: %p\n", &CURRENT->bh->b_wait); #endif - cli(); + flags = claim_dma_lock(); - outb(dma_arb_level | DMA_MASK_CHAN, PORT_DMA_FN); + mca_disable_dma(dma_arb_level); - outb(dma_arb_level | DMA_WRITE_ADDR, PORT_DMA_FN); - outb((u_int) buffer & (u_int) 0xff, PORT_DMA_EX); - outb(((u_int) buffer >> 8) & (u_int) 0xff, PORT_DMA_EX); - outb(((u_int) buffer >> 16) & (u_int) 0xff, PORT_DMA_EX); + mca_set_dma_addr(dma_arb_level, virt_to_bus(buffer)); - outb(dma_arb_level | DMA_WRITE_TC, PORT_DMA_FN); - tc = (length * SECT_SIZE / 2) - 1; - outb(tc & 0xff, PORT_DMA_EX); - outb((tc >> 8) & 0xff, PORT_DMA_EX); + mca_set_dma_count(dma_arb_level, length * 512 / 2); - outb(dma_arb_level | DMA_WRITE_MODE, PORT_DMA_FN); - outb(dma_xmode, PORT_DMA_EX); + mca_set_dma_mode(dma_arb_level, dma_xmode); - outb(dma_arb_level | DMA_UNMASK_CHAN, PORT_DMA_FN); + mca_enable_dma(dma_arb_level); - sti(); + release_dma_lock(flags); } /* prepare for dma */ @@ -871,20 +844,26 @@ static void ps2esdi_normal_interrupt_handler(u_int int_ret_code) { + unsigned long flags; u_int status; + u_int ending; int i; switch (int_ret_code & 0x0f) { case INT_TRANSFER_REQ: ps2esdi_prep_dma(CURRENT->buffer, CURRENT->current_nr_sectors, - (CURRENT->cmd == READ) ? DMA_READ_16 : DMA_WRITE_16); + (CURRENT->cmd == READ) + ? MCA_DMA_MODE_16 | MCA_DMA_MODE_WRITE | MCA_DMA_MODE_XFER + : MCA_DMA_MODE_16 | MCA_DMA_MODE_READ); outb(CTRL_ENABLE_DMA | CTRL_ENABLE_INTR, ESDI_CONTROL); + ending = -1; break; case INT_ATTN_ERROR: printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME, int_ret_code); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); + ending = FAIL; break; case INT_CMD_COMPLETE: @@ -893,13 +872,10 @@ printk("%s: timeout reading status word\n", DEVICE_NAME); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - if ((++CURRENT->errors) < MAX_RETRIES) - do_ps2esdi_request(NULL); - else { - end_request(FAIL); - if (!QUEUE_EMPTY) - do_ps2esdi_request(NULL); - } + if ((++CURRENT->errors) >= MAX_RETRIES) + ending = FAIL; + else + ending = -1; break; } status = inw(ESDI_STT_INT); @@ -910,15 +886,16 @@ outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); #if 0 - printk("ps2esdi: cmd_complete b_wait: %p\n", CURRENT->bh->b_wait); + printk("ps2esdi: cmd_complete b_wait: %p\n", &CURRENT->bh->b_wait); #endif - ps2esdi_continue_request(); + ending = SUCCES; break; default: printk("%s: interrupt for unknown command %02X\n", DEVICE_NAME, status & 0x1f); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); + ending = -1; break; } break; @@ -929,7 +906,7 @@ dump_cmd_complete_status(int_ret_code); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - ps2esdi_continue_request(); + ending = SUCCES; break; case INT_CMD_WARNING: case INT_CMD_ABORT: @@ -939,22 +916,17 @@ dump_cmd_complete_status(int_ret_code); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - if ((++CURRENT->errors) < MAX_RETRIES) - do_ps2esdi_request(NULL); - else { - end_request(FAIL); - if (!QUEUE_EMPTY) - do_ps2esdi_request(NULL); - } + if ((++CURRENT->errors) >= MAX_RETRIES) + ending = FAIL; + else + ending = -1; break; case INT_CMD_BLK_ERR: dump_cmd_complete_status(int_ret_code); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - end_request(FAIL); - if (!QUEUE_EMPTY) - do_ps2esdi_request(NULL); + ending = FAIL; break; case INT_CMD_FORMAT: @@ -962,12 +934,14 @@ ,DEVICE_NAME); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); + ending = -1; break; case INT_RESET: /* BA printk("%s: reset completed.\n", DEVICE_NAME) */ ; outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); + ending = -1; break; default: @@ -975,24 +949,16 @@ DEVICE_NAME, int_ret_code & 0xf); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); + ending = -1; break; } - -} /* handle interrupts */ - - -static void ps2esdi_continue_request(void) -{ - if (CURRENT->nr_sectors -= CURRENT->current_nr_sectors) { - CURRENT->buffer += CURRENT->current_nr_sectors * SECT_SIZE; - CURRENT->sector += CURRENT->current_nr_sectors; - do_ps2esdi_request(NULL); - } else { - end_request(SUCCES); - if (!QUEUE_EMPTY) - do_ps2esdi_request(NULL); + if(ending != -1) { + spin_lock_irqsave(io_request_lock, flags); + end_request(ending); + do_ps2esdi_request(BLK_DEFAULT_QUEUE(MAJOR_NR)); + spin_unlock_irqrestore(io_request_lock, flags); } -} +} /* handle interrupts */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/rd.c linux.ac/drivers/block/rd.c --- linux.vanilla/drivers/block/rd.c Fri Feb 9 19:30:22 2001 +++ linux.ac/drivers/block/rd.c Tue Apr 3 17:54:38 2001 @@ -466,7 +466,7 @@ * romfs * gzip */ -int __init +static int __init identify_ramdisk_image(kdev_t device, struct file *fp, int start_block) { const int size = 512; @@ -690,6 +690,7 @@ done: if (infile.f_op->release) infile.f_op->release(inode, &infile); + blkdev_put(out_inode->i_bdev, BDEV_FILE); set_fs(fs); return; free_inodes: /* free inodes on error */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/smart1,2.h linux.ac/drivers/block/smart1,2.h --- linux.vanilla/drivers/block/smart1,2.h Sat Jun 24 05:04:36 2000 +++ linux.ac/drivers/block/smart1,2.h Tue Apr 3 17:54:38 2001 @@ -45,7 +45,7 @@ } /* - * This card is the oposite of the other cards. + * This card is the opposite of the other cards. * 0 turns interrupts on... * 0x08 turns them off... */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/swim3.c linux.ac/drivers/block/swim3.c --- linux.vanilla/drivers/block/swim3.c Tue Sep 19 16:31:53 2000 +++ linux.ac/drivers/block/swim3.c Tue Apr 3 17:54:38 2001 @@ -248,10 +248,7 @@ int swim3_init(void); #ifndef CONFIG_PMAC_PBOOK -static inline int check_media_bay(struct device_node *which_bay, int what) -{ - return 1; -} +#define check_media_bay(which, what) 1 #endif static void swim3_select(struct floppy_state *fs, int sel) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/cdrom/cdrom.c linux.ac/drivers/cdrom/cdrom.c --- linux.vanilla/drivers/cdrom/cdrom.c Tue Apr 3 17:32:00 2001 +++ linux.ac/drivers/cdrom/cdrom.c Tue Apr 3 17:54:38 2001 @@ -323,8 +323,8 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, unsigned long arg); -int cdrom_get_last_written(kdev_t dev, long *last_written); -int cdrom_get_next_writable(kdev_t dev, long *next_writable); +int cdrom_get_last_written(kdev_t dev, unsigned int *last_written); +int cdrom_get_next_writable(kdev_t dev, unsigned int *next_writable); #ifdef CONFIG_SYSCTL static void cdrom_sysctl_register(void); @@ -1140,14 +1140,23 @@ memset(&rpc_state, 0, sizeof(rpc_state_t)); cgc.buffer = (char *) &rpc_state; - if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; - - ai->lrpcs.type = rpc_state.type_code; - ai->lrpcs.vra = rpc_state.vra; - ai->lrpcs.ucca = rpc_state.ucca; - ai->lrpcs.region_mask = rpc_state.region_mask; - ai->lrpcs.rpc_scheme = rpc_state.rpc_scheme; + /* + * we already checked dvd capability, so if it fails + * assume it's a rpc phase-1 drive and report that back. + * this is necessary at least on some toshiba drives, + * that don't support REPORT_KEY with key format 001000b + */ + cgc.quiet = 1; + if ((ret = cdo->generic_packet(cdi, &cgc))) { + ai->lrpcs.type = 0; + ai->lrpcs.rpc_scheme = 0; + } else { + ai->lrpcs.type = rpc_state.type_code; + ai->lrpcs.vra = rpc_state.vra; + ai->lrpcs.ucca = rpc_state.ucca; + ai->lrpcs.region_mask = rpc_state.region_mask; + ai->lrpcs.rpc_scheme = rpc_state.rpc_scheme; + } break; /* Set region settings */ @@ -1897,8 +1906,10 @@ if (cgc->data_direction == CGC_DATA_UNKNOWN) return -EINVAL; + if (cgc->data_direction == CGC_DATA_NONE && cgc->buflen) + return -EINVAL; - if (cgc->buflen < 0 || cgc->buflen >= 131072) + if (cgc->buflen >= 131072) return -EINVAL; if ((ubuf = cgc->buffer)) { @@ -1909,24 +1920,24 @@ usense = cgc->sense; cgc->sense = &sense; + ret = -EFAULT; if (usense && !access_ok(VERIFY_WRITE, usense, sizeof(*usense))) - return -EFAULT; + goto out; - if (cgc->data_direction == CGC_DATA_READ) { + if (cgc->data_direction == CGC_DATA_READ) if (!access_ok(VERIFY_READ, ubuf, cgc->buflen)) - return -EFAULT; - } else if (cgc->data_direction == CGC_DATA_WRITE) { - if (copy_from_user(cgc->buffer, ubuf, cgc->buflen)) { - kfree(cgc->buffer); - return -EFAULT; - } - } + goto out; + else if (cgc->data_direction == CGC_DATA_WRITE) + if (copy_from_user(cgc->buffer, ubuf, cgc->buflen)) + goto out; ret = cdi->ops->generic_packet(cdi, cgc); __copy_to_user(usense, cgc->sense, sizeof(*usense)); if (!ret && cgc->data_direction == CGC_DATA_READ) __copy_to_user(ubuf, cgc->buffer, cgc->buflen); - kfree(cgc->buffer); +out: + if (cgc->buffer) + kfree(cgc->buffer); return ret; } @@ -1936,7 +1947,7 @@ struct cdrom_device_ops *cdo = cdi->ops; struct cdrom_generic_command cgc; kdev_t dev = cdi->dev; - char buffer[32]; + unsigned char buffer[32]; int ret = 0; memset(&cgc, 0, sizeof(cgc)); @@ -2094,7 +2105,7 @@ case CDROMVOLCTRL: case CDROMVOLREAD: { struct cdrom_volctrl volctrl; - char mask[32]; + unsigned char mask[32]; unsigned short offset; cdinfo(CD_DO_IOCTL, "entering CDROMVOLUME\n"); @@ -2205,19 +2216,19 @@ return cdrom_do_cmd(cdi, &cgc); } case CDROM_NEXT_WRITABLE: { - long next = 0; + unsigned int next = 0; cdinfo(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n"); if ((ret = cdrom_get_next_writable(dev, &next))) return ret; - IOCTL_OUT(arg, long, next); + IOCTL_OUT(arg, unsigned int, next); return 0; } case CDROM_LAST_WRITTEN: { - long last = 0; + unsigned int last = 0; cdinfo(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n"); if ((ret = cdrom_get_last_written(dev, &last))) return ret; - IOCTL_OUT(arg, long, last); + IOCTL_OUT(arg, unsigned int, last); return 0; } } /* switch */ @@ -2282,7 +2293,7 @@ /* return the last written block on the CD-R media. this is for the udf file system. */ -int cdrom_get_last_written(kdev_t dev, long *last_written) +int cdrom_get_last_written(kdev_t dev, unsigned int *last_written) { struct cdrom_device_info *cdi = cdrom_find_device(dev); struct cdrom_tocentry toc; @@ -2334,7 +2345,7 @@ } /* return the next writable block. also for udf file system. */ -int cdrom_get_next_writable(kdev_t dev, long *next_writable) +int cdrom_get_next_writable(kdev_t dev, unsigned int *next_writable) { struct cdrom_device_info *cdi = cdrom_find_device(dev); disc_information di; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/cdrom/sbpcd.c linux.ac/drivers/cdrom/sbpcd.c --- linux.vanilla/drivers/cdrom/sbpcd.c Sat Feb 17 00:02:35 2001 +++ linux.ac/drivers/cdrom/sbpcd.c Tue Apr 10 18:13:32 2001 @@ -350,7 +350,7 @@ #ifndef SBPCD_ISSUE #define SBPCD_ISSUE 1 -#endif SBPCD_ISSUE +#endif /* SBPCD_ISSUE */ #include <linux/module.h> @@ -420,7 +420,7 @@ #else #define SBPCD_CLI #define SBPCD_STI -#endif SBPCD_DIS_IRQ +#endif /* SBPCD_DIS_IRQ */ /*==========================================================================*/ /* * auto-probing address list @@ -478,9 +478,9 @@ 0x370, 0, /* Lasermate, CI-101P */ 0x290, 1, /* Soundblaster 16 */ 0x310, 0, /* Lasermate, CI-101P, WDH-7001C */ -#endif MODULE +#endif /* MODULE */ #endif -#endif DISTRIBUTION +#endif /* DISTRIBUTION */ }; #else static int sbpcd[] = {CDROM_PORT, SBPRO}; /* probe with user's setup only */ @@ -570,7 +570,7 @@ (1<<DBG_TOC) | (1<<DBG_MUL) | (1<<DBG_UPC)); -#endif DISTRIBUTION +#endif /* DISTRIBUTION */ static int sbpcd_ioaddr = CDROM_PORT; /* default I/O base address */ static int sbpro_type = SBPRO; @@ -622,7 +622,7 @@ #if FUTURE static DECLARE_WAIT_QUEUE_HEAD(sbp_waitq); -#endif FUTURE +#endif /* FUTURE */ static int teac=SBP_TEAC_SPEED; static int buffers=SBP_BUFFER_FRAMES; @@ -647,7 +647,7 @@ #if OLD_BUSY static volatile u_char busy_data; static volatile u_char busy_audio; /* true semaphores would be safer */ -#endif OLD_BUSY +#endif /* OLD_BUSY */ static DECLARE_MUTEX(ioctl_read_sem); static u_long timeout; static volatile u_char timed_out_delay; @@ -664,7 +664,7 @@ static u_int maxtim_data= 9000; #else static u_int maxtim_data= 3000; -#endif LONG_TIMING +#endif /* LONG_TIMING */ #if DISTRIBUTION static int n_retries=6; #else @@ -729,7 +729,7 @@ u_char vol_ctrl2; char vol_chan3; u_char vol_ctrl3; -#endif 000 +#endif /*000 */ u_char volume_control; /* TEAC on/off bits */ u_char SubQ_ctl_adr; @@ -758,7 +758,7 @@ u_int TocEnt_address; #if SAFE_MIXED char has_data; -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ u_char ored_ctl_adr; /* to detect if CDROM contains data tracks */ struct { @@ -808,7 +808,7 @@ #define MSG_LEVEL KERN_NOTICE #else #define MSG_LEVEL KERN_INFO -#endif DISTRIBUTION +#endif /* DISTRIBUTION */ char buf[256]; va_list args; @@ -824,7 +824,7 @@ printk(buf); #if KLOGD_PAUSE sbp_sleep(KLOGD_PAUSE); /* else messages get lost */ -#endif KLOGD_PAUSE +#endif /* KLOGD_PAUSE */ return; } /*==========================================================================*/ @@ -1148,7 +1148,7 @@ } j=i-response_count; if (j>0) msg(DBG_INF,"ResponseInfo: got %d trailing bytes.\n",j); -#endif 000 +#endif /* 000 */ for (j=0;j<i;j++) sprintf(&msgbuf[j*3]," %02X",infobuf[j]); msgbuf[j*3]=0; @@ -1400,7 +1400,7 @@ if (drvcmd[0]==CMDT_READ_VER) sbp_sleep(HZ); /* fixme */ #if 01 OUT(CDo_sel_i_d,1); -#endif 01 +#endif /* 01 */ if (teac==2) { if ((i=CDi_stat_loop_T()) == -1) break; @@ -1409,7 +1409,7 @@ { #if 0 OUT(CDo_sel_i_d,1); -#endif 0 +#endif /* 0 */ i=inb(CDi_status); } if (!(i&s_not_data_ready)) /* f.e. CMDT_DISKINFO */ @@ -1433,7 +1433,7 @@ l=1; msg(DBG_TEA,"cmd_out_T: do_16bit: false first byte!\n"); } -#endif TEST_FALSE_FF +#endif /* TEST_FALSE_FF */ } else infobuf[l++]=inb(CDi_data); i=inb(CDi_status); @@ -2028,7 +2028,7 @@ msg(DBG_TEA, "================CMDT_RESET given=================.\n"); sbp_sleep(3*HZ); } -#endif 1 +#endif /* 1 */ flush_status(); i=GetStatus(); if (i<0) return i; @@ -2349,7 +2349,7 @@ i=ResponseStatus(); #if 0 sbp_sleep(HZ); -#endif 0 +#endif /* 0 */ i=ResponseStatus(); } if (i<0) @@ -2694,7 +2694,7 @@ D_S[d].vol_ctrl2=0xFF; D_S[d].vol_chan3=3; D_S[d].vol_ctrl3=0xFF; -#endif 000 +#endif /* 000 */ D_S[d].diskstate_flags |= volume_bit; return (0); } @@ -2994,20 +2994,20 @@ int i; #if TEST_UPC int block, checksum; -#endif TEST_UPC +#endif /* TEST_UPC */ if (fam2_drive) return (0); /* not implemented yet */ if (famT_drive) return (0); /* not implemented yet */ if (famV_drive) return (0); /* not implemented yet */ #if 1 if (fam0_drive) return (0); /* but it should work */ -#endif 1 +#endif D_S[d].diskstate_flags &= ~upc_bit; #if TEST_UPC for (block=CD_MSF_OFFSET+1;block<CD_MSF_OFFSET+200;block++) { -#endif TEST_UPC +#endif /* TEST_UPC */ clr_cmdbuf(); if (fam1_drive) { @@ -3016,7 +3016,7 @@ drvcmd[1]=(block>>16)&0xFF; drvcmd[2]=(block>>8)&0xFF; drvcmd[3]=block&0xFF; -#endif TEST_UPC +#endif /* TEST_UPC */ response_count=8; flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; } @@ -3027,7 +3027,7 @@ drvcmd[2]=(block>>16)&0xFF; drvcmd[3]=(block>>8)&0xFF; drvcmd[4]=block&0xFF; -#endif TEST_UPC +#endif /* TEST_UPC */ response_count=0; flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; } @@ -3058,12 +3058,12 @@ } #if TEST_UPC checksum=0; -#endif TEST_UPC +#endif /* TEST_UPC */ for (i=0;i<(fam1_drive?8:16);i++) { #if TEST_UPC checksum |= infobuf[i]; -#endif TEST_UPC +#endif /* TEST_UPC */ sprintf(&msgbuf[i*3], " %02X", infobuf[i]); } msgbuf[i*3]=0; @@ -3071,7 +3071,7 @@ #if TEST_UPC if ((checksum&0x7F)!=0) break; } -#endif TEST_UPC +#endif /* TEST_UPC */ D_S[d].UPC_ctl_adr=0; if (fam1_drive) i=0; else i=2; @@ -3256,7 +3256,7 @@ i=cmd_out(); /* which buffer to use? */ return (i); } -#endif FUTURE +#endif /* FUTURE */ /*==========================================================================*/ static void __init check_datarate(void) { @@ -3283,7 +3283,7 @@ datarate++; #if 1 if (datarate>0x6FFFFFFF) break; -#endif 00000 +#endif } while (!timed_out_delay); del_timer(&delay_timer); @@ -3299,7 +3299,7 @@ maxtim_data=datarate/100; #else maxtim_data=datarate/300; -#endif LONG_TIMING +#endif /* LONG_TIMING */ #if 0 msg(DBG_TIM,"maxtim_8 %d, maxtim_data %d.\n", maxtim_8, maxtim_data); #endif @@ -3453,7 +3453,7 @@ OUT(CDo_reset,0); sbp_sleep(6*HZ); OUT(CDo_enable,D_S[d].drv_sel); -#endif 0 +#endif drvcmd[0]=CMD2_READ_VER; response_count=12; flags_cmd_out=f_putcmd; @@ -3743,7 +3743,7 @@ OUT(port+3,save_port3); return (0); /* in any case - no real "function" at time */ } -#endif PATH_CHECK +#endif /* PATH_CHECK */ /*==========================================================================*/ /*==========================================================================*/ /* @@ -3850,7 +3850,7 @@ if (func2==tell_UPC) return (-1); #else return (0); -#endif 000 +#endif } /*==========================================================================*/ static int check_allowed2(u_char func1, u_char func2) @@ -3868,7 +3868,7 @@ } #else return (0); -#endif 000 +#endif } /*==========================================================================*/ static int check_allowed3(u_char func1, u_char func2) @@ -3902,7 +3902,7 @@ if (func1==audio_resume) return (-1); #else return (0); -#endif 000 +#endif } /*==========================================================================*/ static int seek_pos_audio_end(void) @@ -3914,7 +3914,7 @@ i=cc_Seek(i,0); return (i); } -#endif FUTURE +#endif /* FUTURE */ /*==========================================================================*/ static int ReadToC(void) { @@ -4152,7 +4152,7 @@ } return (0); } -#endif FUTURE +#endif /* FUTURE */ /*==========================================================================*/ /*==========================================================================*/ /* @@ -4250,7 +4250,7 @@ msg(DBG_IOC,"ioctl: CDROMREADMODE1 requested.\n"); #if SAFE_MIXED if (D_S[d].has_data>1) RETURN_UP(-EBUSY); -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ cc_ModeSelect(CD_FRAMESIZE); cc_ModeSense(); D_S[d].mode=READ_M1; @@ -4260,7 +4260,7 @@ msg(DBG_IOC,"ioctl: CDROMREADMODE2 requested.\n"); #if SAFE_MIXED if (D_S[d].has_data>1) RETURN_UP(-EBUSY); -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ cc_ModeSelect(CD_FRAMESIZE_RAW1); cc_ModeSense(); D_S[d].mode=READ_M2; @@ -4303,7 +4303,7 @@ if (famT_drive) RETURN_UP(-EINVAL); #if SAFE_MIXED if (D_S[d].has_data>1) RETURN_UP(-EBUSY); -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ if (D_S[d].aud_buf==NULL) RETURN_UP(-EINVAL); i=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_read_audio)); if (i) RETURN_UP(i); @@ -4328,7 +4328,7 @@ #if OLD_BUSY while (busy_data) sbp_sleep(HZ/10); /* wait a bit */ busy_audio=1; -#endif OLD_BUSY +#endif /* OLD_BUSY */ error_flag=0; for (data_tries=5; data_tries>0; data_tries--) { @@ -4460,7 +4460,7 @@ i=cc_DriveReset(); /* ugly fix to prevent a hang */ #else i=cc_ReadError(); -#endif 0000 +#endif continue; } if (fam0L_drive) @@ -4515,7 +4515,7 @@ D_S[d].mode=READ_M1; #if OLD_BUSY busy_audio=0; -#endif OLD_BUSY +#endif /* OLD_BUSY */ if (data_tries == 0) { msg(DBG_AUD,"read_audio: failed after 5 tries in line %d.\n", __LINE__); @@ -4601,7 +4601,7 @@ msg(DBG_IOC,"ioctl: CDROMPLAYMSF entered.\n"); #if SAFE_MIXED if (D_S[d].has_data>1) RETURN_UP(-EBUSY); -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ if (D_S[d].audio_state==audio_playing) { i=cc_Pause_Resume(1); @@ -4636,7 +4636,7 @@ msg(DBG_IOC,"ioctl: CDROMPLAYTRKIND entered.\n"); #if SAFE_MIXED if (D_S[d].has_data>1) RETURN_UP(-EBUSY); -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ if (D_S[d].audio_state==audio_playing) { msg(DBG_IOX,"CDROMPLAYTRKIND: already audio_playing.\n"); @@ -4699,7 +4699,7 @@ msg(DBG_IOC,"ioctl: CDROMSTOP entered.\n"); #if SAFE_MIXED if (D_S[d].has_data>1) RETURN_UP(-EBUSY); -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ i=cc_Pause_Resume(1); D_S[d].audio_state=0; #if 0 @@ -4942,7 +4942,7 @@ #if OLD_BUSY while (busy_audio) sbp_sleep(HZ); /* wait a bit */ busy_data=1; -#endif OLD_BUSY +#endif /* OLD_BUSY */ if (D_S[i].audio_state==audio_playing) goto err_done; if (d!=i) switch_drive(i); @@ -4973,7 +4973,7 @@ i=prepare(0,0); /* at moment not really a hassle check, but ... */ if (i!=0) msg(DBG_INF,"\"prepare\" tells error %d -- ignored\n", i); -#endif FUTURE +#endif /* FUTURE */ if (!st_spinning) cc_SpinUp(); @@ -4999,7 +4999,7 @@ { #if SAFE_MIXED D_S[d].has_data=2; /* is really a data disk */ -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ #ifdef DEBUG_GTL printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 3, Time:%li\n", xnr, req, req->sector, req->nr_sectors, jiffies); @@ -5014,7 +5014,7 @@ err_done: #if OLD_BUSY busy_data=0; -#endif OLD_BUSY +#endif /* OLD_BUSY */ #ifdef DEBUG_GTL printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 4 (error), Time:%li\n", xnr, req, req->sector, req->nr_sectors, jiffies); @@ -5373,17 +5373,17 @@ #if 0 if (!success) -#endif 0 +#endif do { if (fam0LV_drive) cc_ReadStatus(); #if 1 if (famT_drive) msg(DBG_TEA, "================before ResponseStatus=================.\n", i); -#endif 1 +#endif i=ResponseStatus(); /* builds status_bits, returns orig. status (old) or faked p_success (new) */ #if 1 if (famT_drive) msg(DBG_TEA, "================ResponseStatus: %d=================.\n", i); -#endif 1 +#endif if (i<0) { msg(DBG_INF,"bad cc_ReadStatus after read: %02X\n", D_S[d].status_bits); @@ -5443,11 +5443,11 @@ msg(DBG_INF,"CD contains no data tracks.\n"); #if SAFE_MIXED D_S[d].has_data=0; -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ } #if SAFE_MIXED else if (D_S[d].has_data<1) D_S[d].has_data=1; -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ } if (!st_spinning) cc_SpinUp(); RETURN_UP(0); @@ -5485,7 +5485,7 @@ D_S[d].open_count=0; #if SAFE_MIXED D_S[d].has_data=0; -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ } } up(&ioctl_read_sem); @@ -5697,7 +5697,7 @@ int __init __SBPCD_INIT(void) #else int __init SBPCD_INIT(void) -#endif MODULE +#endif /* MODULE */ { char nbuff[16]; int i=0, j=0; @@ -5724,10 +5724,10 @@ msg(DBG_INF,"with your REAL address.\n"); msg(DBG_INF,"= = = = = = = = = = END of WARNING = = = = = == = = =\n"); } -#endif DISTRIBUTION +#endif /* DISTRIBUTION */ sbpcd[0]=sbpcd_ioaddr; /* possibly changed by kernel command line */ sbpcd[1]=sbpro_type; /* possibly changed by kernel command line */ -#endif MODULE +#endif /* MODULE */ for (port_index=0;port_index<NUM_PROBE;port_index+=2) { @@ -5745,7 +5745,7 @@ sbpcd_setup((char *)type); #if DISTRIBUTION msg(DBG_INF,"Scanning 0x%X (%s)...\n", CDo_command, type); -#endif DISTRIBUTION +#endif /* DISTRIBUTION */ if (sbpcd[port_index+1]==2) { i=config_spea(); @@ -5753,7 +5753,7 @@ } #ifdef PATH_CHECK if (check_card(addr[1])) continue; -#endif PATH_CHECK +#endif /* PATH_CHECK */ i=check_drives(); msg(DBG_INI,"check_drives done.\n"); if (i>=0) break; /* drive found */ @@ -5766,7 +5766,7 @@ return -EIO; #else goto init_done; -#endif MODULE +#endif /* MODULE */ } if (port_index>0) @@ -5783,7 +5783,7 @@ switch_drive(j); #if 1 if (!famL_drive) cc_DriveReset(); -#endif 0 +#endif if (!st_spinning) cc_SpinUp(); D_S[j].sbp_first_frame = -1; /* First frame in buffer */ D_S[j].sbp_last_frame = -1; /* Last frame in buffer */ @@ -5794,7 +5794,7 @@ D_S[j].f_eject=0; #if EJECT if (!fam0_drive) D_S[j].f_eject=1; -#endif EJECT +#endif /* EJECT */ cc_ReadStatus(); i=ResponseStatus(); /* returns orig. status or p_busy_new */ if (famT_drive) i=ResponseStatus(); /* returns orig. status or p_busy_new */ @@ -5840,7 +5840,7 @@ #if SOUND_BASE OUT(MIXER_addr,MIXER_CD_Volume); /* select SB Pro mixer register */ OUT(MIXER_data,0xCC); /* one nibble per channel, max. value: 0xFF */ -#endif SOUND_BASE +#endif /* SOUND_BASE */ if (devfs_register_blkdev(MAJOR_NR, major_name, &cdrom_fops) != 0) { @@ -5849,7 +5849,7 @@ return -EIO; #else goto init_done; -#endif MODULE +#endif /* MODULE */ } blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); #ifdef DONT_MERGE_REQUESTS @@ -5871,7 +5871,7 @@ switch_drive(j); #if SAFE_MIXED D_S[j].has_data=0; -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ /* * allocate memory for the frame buffers */ @@ -5894,7 +5894,7 @@ } #ifdef MODULE msg(DBG_INF,"data buffer size: %d frames.\n",buffers); -#endif MODULE +#endif /* MODULE */ if (D_S[j].sbp_audsiz>0) { D_S[j].aud_buf=(u_char *) vmalloc(D_S[j].sbp_audsiz*CD_FRAMESIZE_RAW); @@ -5934,15 +5934,15 @@ #if !(SBPCD_ISSUE-1) #ifdef CONFIG_SBPCD2 sbpcd2_init(); -#endif CONFIG_SBPCD2 +#endif /* CONFIG_SBPCD2 */ #ifdef CONFIG_SBPCD3 sbpcd3_init(); -#endif CONFIG_SBPCD3 +#endif /* CONFIG_SBPCD3 */ #ifdef CONFIG_SBPCD4 sbpcd4_init(); -#endif CONFIG_SBPCD4 -#endif !(SBPCD_ISSUE-1) -#endif MODULE +#endif /* CONFIG_SBPCD4 */ +#endif /* !(SBPCD_ISSUE-1) */ +#endif /* MODULE */ return 0; } /*==========================================================================*/ @@ -5981,7 +5981,7 @@ module_exit(sbpcd_exit); -#endif MODULE +#endif /* MODULE */ /*==========================================================================*/ /* * Check if the media has changed in the CD-ROM drive. @@ -6004,7 +6004,7 @@ D_S[d].diskstate_flags &= ~cd_size_bit; #if SAFE_MIXED D_S[d].has_data=0; -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ return (1); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/Makefile linux.ac/drivers/char/Makefile --- linux.vanilla/drivers/char/Makefile Tue Apr 3 17:32:00 2001 +++ linux.ac/drivers/char/Makefile Mon Apr 9 23:39:31 2001 @@ -23,7 +23,7 @@ export-objs := busmouse.o console.o keyboard.o sysrq.o \ misc.o pty.o random.o selection.o serial.o \ - tty_io.o + tty_io.o tty_ioctl.o mod-subdirs := joystick ftape drm pcmcia @@ -41,6 +41,34 @@ SERIAL = endif +ifeq ($(ARCH),s390x) + KEYMAP = + KEYBD = + CONSOLE = + SERIAL = +endif + +ifeq ($(ARCH),s390) + KEYMAP = + KEYBD = + CONSOLE = + SERIAL = +endif + +ifeq ($(ARCH),s390x) + KEYMAP = + KEYBD = + CONSOLE = + SERIAL = +endif + +ifeq ($(ARCH),s390x) + KEYMAP = + KEYBD = + CONSOLE = + SERIAL = +endif + ifeq ($(ARCH),m68k) ifdef CONFIG_AMIGA KEYBD = amikeyb.o @@ -57,6 +85,12 @@ ifneq ($(CONFIG_PC_KEYB),y) KEYBD = endif +endif + +ifeq ($(ARCH),um) + KEYMAP = + KEYBD = + CONSOLE = endif ifeq ($(ARCH),sh) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/agp/agp.h linux.ac/drivers/char/agp/agp.h --- linux.vanilla/drivers/char/agp/agp.h Tue Feb 13 22:13:43 2001 +++ linux.ac/drivers/char/agp/agp.h Tue Apr 3 17:54:38 2001 @@ -119,6 +119,9 @@ void (*free_by_type) (agp_memory *); unsigned long (*agp_alloc_page) (void); void (*agp_destroy_page) (unsigned long); + int (*suspend)(void); + void (*resume)(void); + }; #define OUTREG32(mmap, addr, val) __raw_writel((val), (mmap)+(addr)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/agp/agpgart_be.c linux.ac/drivers/char/agp/agpgart_be.c --- linux.vanilla/drivers/char/agp/agpgart_be.c Tue Feb 13 22:13:43 2001 +++ linux.ac/drivers/char/agp/agpgart_be.c Tue Apr 10 16:55:31 2001 @@ -38,6 +38,7 @@ #include <linux/init.h> #include <linux/pagemap.h> #include <linux/miscdevice.h> +#include <linux/pm.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -627,6 +628,15 @@ return 0; } +static int agp_generic_suspend(void) +{ + return 0; +} + +static void agp_generic_resume(void) +{ +} + static int agp_generic_free_gatt_table(void) { int page_order; @@ -775,28 +785,31 @@ static unsigned long agp_generic_alloc_page(void) { - void *pt; - - pt = (void *) __get_free_page(GFP_KERNEL); - if (pt == NULL) { + struct page * page; + + page = alloc_page(GFP_KERNEL); + if (page == NULL) { return 0; } - atomic_inc(&virt_to_page(pt)->count); - set_bit(PG_locked, &virt_to_page(pt)->flags); + atomic_inc(&page->count); + set_bit(PG_locked, &page->flags); atomic_inc(&agp_bridge.current_memory_agp); - return (unsigned long) pt; + return (unsigned long)page_address(page); } -static void agp_generic_destroy_page(unsigned long page) +static void agp_generic_destroy_page(unsigned long addr) { - void *pt = (void *) page; + void *pt = (void *) addr; + struct page *page; if (pt == NULL) { return; } - atomic_dec(&virt_to_page(pt)->count); - clear_bit(PG_locked, &virt_to_page(pt)->flags); - wake_up(&virt_to_page(pt)->wait); + + page = virt_to_page(pt); + atomic_dec(&page->count); + clear_bit(PG_locked, &page->flags); + wake_up(&page->wait); free_page((unsigned long) pt); atomic_dec(&agp_bridge.current_memory_agp); } @@ -1083,6 +1096,8 @@ agp_bridge.free_by_type = intel_i810_free_by_type; agp_bridge.agp_alloc_page = agp_generic_alloc_page; agp_bridge.agp_destroy_page = agp_generic_destroy_page; + agp_bridge.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; return 0; } @@ -1233,6 +1248,10 @@ return addr | agp_bridge.masks[0].mask; } +static void intel_resume(void) +{ + intel_configure(); +} /* Setup function */ static gatt_mask intel_generic_masks[] = @@ -1275,6 +1294,8 @@ agp_bridge.free_by_type = agp_generic_free_by_type; agp_bridge.agp_alloc_page = agp_generic_alloc_page; agp_bridge.agp_destroy_page = agp_generic_destroy_page; + agp_bridge.suspend = agp_generic_suspend; + agp_bridge.resume = intel_resume; return 0; @@ -1305,6 +1326,8 @@ agp_bridge.free_by_type = agp_generic_free_by_type; agp_bridge.agp_alloc_page = agp_generic_alloc_page; agp_bridge.agp_destroy_page = agp_generic_destroy_page; + agp_bridge.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; return 0; @@ -1335,6 +1358,8 @@ agp_bridge.free_by_type = agp_generic_free_by_type; agp_bridge.agp_alloc_page = agp_generic_alloc_page; agp_bridge.agp_destroy_page = agp_generic_destroy_page; + agp_bridge.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; return 0; @@ -1452,6 +1477,8 @@ agp_bridge.free_by_type = agp_generic_free_by_type; agp_bridge.agp_alloc_page = agp_generic_alloc_page; agp_bridge.agp_destroy_page = agp_generic_destroy_page; + agp_bridge.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; return 0; @@ -1563,6 +1590,8 @@ agp_bridge.free_by_type = agp_generic_free_by_type; agp_bridge.agp_alloc_page = agp_generic_alloc_page; agp_bridge.agp_destroy_page = agp_generic_destroy_page; + agp_bridge.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; return 0; } @@ -1938,6 +1967,8 @@ agp_bridge.free_by_type = agp_generic_free_by_type; agp_bridge.agp_alloc_page = agp_generic_alloc_page; agp_bridge.agp_destroy_page = agp_generic_destroy_page; + agp_bridge.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; return 0; @@ -2092,15 +2123,15 @@ static unsigned long ali_alloc_page(void) { - void *pt; + struct page *page; u32 temp; - pt = (void *) __get_free_page(GFP_KERNEL); - if (pt == NULL) + page = alloc_page(GFP_KERNEL); + if (page == NULL) return 0; - atomic_inc(&virt_to_page(pt)->count); - set_bit(PG_locked, &virt_to_page(pt)->flags); + atomic_inc(&page->count); + set_bit(PG_locked, &page->flags); atomic_inc(&agp_bridge.current_memory_agp); global_cache_flush(); @@ -2109,16 +2140,17 @@ pci_read_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, &temp); pci_write_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | - virt_to_phys((void *)pt)) | + virt_to_phys(page_address(page))) | ALI_CACHE_FLUSH_EN )); } - return (unsigned long) pt; + return (unsigned long)page_address(page); } -static void ali_destroy_page(unsigned long page) +static void ali_destroy_page(unsigned long addr) { u32 temp; - void *pt = (void *) page; + void *pt = (void *) addr; + struct page *page; if (pt == NULL) return; @@ -2133,9 +2165,10 @@ ALI_CACHE_FLUSH_EN)); } - atomic_dec(&virt_to_page(pt)->count); - clear_bit(PG_locked, &virt_to_page(pt)->flags); - wake_up(&virt_to_page(pt)->wait); + page = virt_to_page(pt); + atomic_dec(&page->count); + clear_bit(PG_locked, &page->flags); + wake_up(&page->wait); free_page((unsigned long) pt); atomic_dec(&agp_bridge.current_memory_agp); } @@ -2181,6 +2214,8 @@ agp_bridge.free_by_type = agp_generic_free_by_type; agp_bridge.agp_alloc_page = ali_alloc_page; agp_bridge.agp_destroy_page = ali_destroy_page; + agp_bridge.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; return 0; @@ -2312,6 +2347,7 @@ "Intel", "Generic", intel_generic_setup }, + #endif /* CONFIG_AGP_INTEL */ #ifdef CONFIG_AGP_SIS @@ -2759,6 +2795,19 @@ } } +static int agp_power(struct pm_dev *dev, pm_request_t rq, void *data) +{ + switch(rq) + { + case PM_SUSPEND: + return agp_bridge.suspend(); + case PM_RESUME: + agp_bridge.resume(); + return 0; + } + return 0; +} + extern int agp_frontend_initialize(void); extern void agp_frontend_cleanup(void); @@ -2793,11 +2842,14 @@ } inter_module_register("drm_agp", THIS_MODULE, &drm_agp); + + pm_register(PM_PCI_DEV, PM_PCI_ID(agp_bridge.dev), agp_power); return 0; } static void __exit agp_cleanup(void) { + pm_unregister_all(agp_power); agp_frontend_cleanup(); agp_backend_cleanup(); inter_module_unregister("drm_agp"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/agp/agpgart_fe.c linux.ac/drivers/char/agp/agpgart_fe.c --- linux.vanilla/drivers/char/agp/agpgart_fe.c Tue Apr 3 17:32:00 2001 +++ linux.ac/drivers/char/agp/agpgart_fe.c Thu Apr 12 12:01:41 2001 @@ -879,7 +879,7 @@ return -ENOMEM; } if (copy_from_user(segment, (void *) reserve.seg_list, - GFP_KERNEL)) { + sizeof(agp_segment) * reserve.seg_count)) { kfree(segment); return -EFAULT; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/amiserial.c linux.ac/drivers/char/amiserial.c --- linux.vanilla/drivers/char/amiserial.c Sat Feb 17 00:02:35 2001 +++ linux.ac/drivers/char/amiserial.c Tue Apr 3 17:54:38 2001 @@ -2288,7 +2288,7 @@ * Print a string to the serial port trying not to disturb * any possible real use of the port... * - * The console_lock must be held when we get here. + * The console must be locked when we get here. */ static void serial_console_write(struct console *co, const char *s, unsigned count) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/console.c linux.ac/drivers/char/console.c --- linux.vanilla/drivers/char/console.c Fri Feb 9 19:30:22 2001 +++ linux.ac/drivers/char/console.c Mon Apr 9 23:56:25 2001 @@ -69,6 +69,9 @@ * * Removed old-style timers, introduced console_timer, made timer * deletion SMP-safe. 17Jun00, Andrew Morton <andrewm@uow.edu.au> + * + * Removed console_lock, enabled interrupts across all console operations + * 13 March 2001, Andrew Morton */ #include <linux/module.h> @@ -103,8 +106,6 @@ #include <asm/uaccess.h> #include <asm/bitops.h> -#include <asm/linux_logo.h> - #include "console_macros.h" @@ -151,6 +152,7 @@ static void set_cursor(int currcons); static void hide_cursor(int currcons); static void unblank_screen_t(unsigned long dummy); +static void console_callback(void *ignored); static int printable; /* Is console ready for printing? */ @@ -161,6 +163,10 @@ static int blankinterval = 10*60*HZ; static int vesa_off_interval; +static struct tq_struct console_callback_tq = { + routine: console_callback, +}; + /* * fg_console is the current virtual console, * last_console is the last used one, @@ -182,15 +188,13 @@ /* * Unfortunately, we need to delay tty echo when we're currently writing to the - * console since the code is (and always was) not re-entrant, so we insert - * all filp requests to con_task_queue instead of tq_timer and run it from - * the console_tasklet. The console_tasklet is protected by the IRQ - * protected console_lock. + * console since the code is (and always was) not re-entrant, so we schedule + * all flip requests to process context with schedule-task() and run it from + * console_callback(). */ -DECLARE_TASK_QUEUE(con_task_queue); /* - * For the same reason, we defer scrollback to the console tasklet. + * For the same reason, we defer scrollback to the console callback. */ static int scrollback_delta; @@ -234,7 +238,12 @@ static inline void scrolldelta(int lines) { scrollback_delta += lines; - tasklet_schedule(&console_tasklet); + schedule_console_callback(); +} + +void schedule_console_callback(void) +{ + schedule_task(&console_callback_tq); } static void scrup(int currcons, unsigned int t, unsigned int b, int nr) @@ -1028,6 +1037,7 @@ color = def_color; } +/* console_sem is held */ static void csi_m(int currcons) { int i; @@ -1167,6 +1177,7 @@ return report_mouse; } +/* console_sem is held */ static void set_mode(int currcons, int on_off) { int i; @@ -1232,6 +1243,7 @@ } } +/* console_sem is held */ static void setterm_command(int currcons) { switch(par[0]) { @@ -1286,19 +1298,7 @@ } } -static void insert_line(int currcons, unsigned int nr) -{ - scrdown(currcons,y,bottom,nr); - need_wrap = 0; -} - - -static void delete_line(int currcons, unsigned int nr) -{ - scrup(currcons,y,bottom,nr); - need_wrap = 0; -} - +/* console_sem is held */ static void csi_at(int currcons, unsigned int nr) { if (nr > video_num_columns - x) @@ -1308,15 +1308,18 @@ insert_char(currcons, nr); } +/* console_sem is held */ static void csi_L(int currcons, unsigned int nr) { if (nr > video_num_lines - y) nr = video_num_lines - y; else if (!nr) nr = 1; - insert_line(currcons, nr); + scrdown(currcons,y,bottom,nr); + need_wrap = 0; } +/* console_sem is held */ static void csi_P(int currcons, unsigned int nr) { if (nr > video_num_columns - x) @@ -1326,15 +1329,18 @@ delete_char(currcons, nr); } +/* console_sem is held */ static void csi_M(int currcons, unsigned int nr) { if (nr > video_num_lines - y) nr = video_num_lines - y; else if (!nr) nr=1; - delete_line(currcons, nr); + scrup(currcons,y,bottom,nr); + need_wrap = 0; } +/* console_sem is held (except via vc_init->reset_terminal */ static void save_cur(int currcons) { saved_x = x; @@ -1349,6 +1355,7 @@ saved_G1 = G1_charset; } +/* console_sem is held */ static void restore_cur(int currcons) { gotoxy(currcons,saved_x,saved_y); @@ -1369,6 +1376,7 @@ EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, ESpalette }; +/* console_sem is held (except via vc_init()) */ static void reset_terminal(int currcons, int do_clear) { top = 0; @@ -1424,6 +1432,7 @@ csi_J(currcons,2); } +/* console_sem is held */ static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c) { /* @@ -1804,6 +1813,7 @@ #define CON_BUF_SIZE PAGE_SIZE DECLARE_MUTEX(con_buf_sem); +/* acquires console_sem */ static int do_con_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { @@ -1844,6 +1854,7 @@ again: if (count > CON_BUF_SIZE) count = CON_BUF_SIZE; + console_conditional_schedule(); if (copy_from_user(con_buf, buf, count)) { n = 0; /* ?? are error codes legal here ?? */ goto out; @@ -1859,7 +1870,7 @@ * the console spinlock during the entire write. */ - spin_lock_irq(&console_lock); + acquire_console_sem(); himask = hi_font_mask; charmask = himask ? 0x1ff : 0xff; @@ -1977,7 +1988,8 @@ do_con_trol(tty, currcons, c); } FLUSH - spin_unlock_irq(&console_lock); + console_conditional_schedule(); + release_console_sem(); out: if (from_user) { @@ -2001,23 +2013,17 @@ } /* - * This is the console switching tasklet. + * This is the console switching callback. * - * Doing console switching in a tasklet allows + * Doing console switching in a process context allows * us to do the switches asynchronously (needed when we want * to switch due to a keyboard interrupt). Synchronization * with other console code and prevention of re-entrancy is - * ensured with console_lock. + * ensured with console_sem. */ -static void console_softint(unsigned long ignored) +static void console_callback(void *ignored) { - /* Runs the task queue outside of the console lock. These - * callbacks can come back into the console code and thus - * will perform their own locking. - */ - run_task_queue(&con_task_queue); - - spin_lock_irq(&console_lock); + acquire_console_sem(); if (want_console >= 0) { if (want_console != fg_console && vc_cons_allocated(want_console)) { @@ -2041,7 +2047,13 @@ scrollback_delta = 0; } - spin_unlock_irq(&console_lock); + release_console_sem(); +} + +void set_console(int nr) +{ + want_console = nr; + schedule_console_callback(); } #ifdef CONFIG_VT_CONSOLE @@ -2049,7 +2061,7 @@ /* * Console on virtual terminal * - * The console_lock must be held when we get here. + * The console must be locked when we get here. */ void vt_console_print(struct console *co, const char * b, unsigned count) @@ -2136,6 +2148,9 @@ } set_cursor(currcons); + if (!oops_in_progress) + poke_blanked_console(); + quit: clear_bit(0, &printing); } @@ -2160,27 +2175,45 @@ * Handling of Linux-specific VC ioctls */ +/* + * Generally a bit racy with respect to console_sem(). + * + * There are some functions which don't need it. + * + * There are some functions which can sleep for arbitrary periods (paste_selection) + * but we don't need the lock there anyway. + * + * set_selection has locking, and definitely needs it + */ + int tioclinux(struct tty_struct *tty, unsigned long arg) { char type, data; + int ret; if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE) return -EINVAL; - if (current->tty != tty && !suser()) + if (current->tty != tty && !capable(CAP_SYS_ADMIN)) return -EPERM; if (get_user(type, (char *)arg)) return -EFAULT; + ret = 0; switch (type) { case 2: - return set_selection(arg, tty, 1); + acquire_console_sem(); + ret = set_selection(arg, tty, 1); + release_console_sem(); + break; case 3: - return paste_selection(tty); + ret = paste_selection(tty); + break; case 4: unblank_screen(); - return 0; + break; case 5: - return sel_loadlut(arg); + ret = sel_loadlut(arg); + break; case 6: /* @@ -2190,24 +2223,33 @@ * related to the kernel should not use this. */ data = shift_state; - return __put_user(data, (char *) arg); + ret = __put_user(data, (char *) arg); + break; case 7: data = mouse_reporting(); - return __put_user(data, (char *) arg); + ret = __put_user(data, (char *) arg); + break; case 10: set_vesa_blanking(arg); - return 0; + break;; case 11: /* set kmsg redirect */ - if (!suser()) - return -EPERM; - if (get_user(data, (char *)arg+1)) - return -EFAULT; - kmsg_redirect = data; - return 0; + if (!capable(CAP_SYS_ADMIN)) { + ret = -EPERM; + } else { + if (get_user(data, (char *)arg+1)) + ret = -EFAULT; + else + kmsg_redirect = data; + } + break; case 12: /* get fg_console */ - return fg_console; + ret = fg_console; + break; + default: + ret = -EINVAL; + break; } - return -EINVAL; + return ret; } /* @@ -2228,6 +2270,8 @@ static void con_put_char(struct tty_struct *tty, unsigned char ch) { + if (in_interrupt()) + return; /* n_r3964 calls put_char() from interrupt context */ pm_access(pm_con); do_con_write(tty, 0, &ch, 1); } @@ -2292,13 +2336,15 @@ static void con_flush_chars(struct tty_struct *tty) { - unsigned long flags; struct vt_struct *vt = (struct vt_struct *)tty->driver_data; + if (in_interrupt()) /* from flush_to_ldisc */ + return; + pm_access(pm_con); - spin_lock_irqsave(&console_lock, flags); + acquire_console_sem(); set_cursor(vt->vc_num); - spin_unlock_irqrestore(&console_lock, flags); + release_console_sem(); } /* @@ -2369,8 +2415,6 @@ struct tty_driver console_driver; static int console_refcount; -DECLARE_TASKLET_DISABLED(console_tasklet, console_softint, 0); - void __init con_init(void) { const char *display_desc = NULL; @@ -2455,9 +2499,6 @@ #ifdef CONFIG_VT_CONSOLE register_console(&vt_console_driver); #endif - - tasklet_enable(&console_tasklet); - tasklet_schedule(&console_tasklet); } #ifndef VT_SINGLE_DRIVER @@ -2563,6 +2604,9 @@ console_driver.minor_start + i); } +/* + * This is called by a timer handler + */ static void vesa_powerdown(void) { struct vc_data *c = vc_cons[fg_console].d; @@ -2583,9 +2627,12 @@ } } +/* + * This is a timer handler + */ static void vesa_powerdown_screen(unsigned long dummy) { - console_timer.function = unblank_screen_t; /* I don't have a clue why this is necessary */ + console_timer.function = unblank_screen_t; vesa_powerdown(); } @@ -2644,11 +2691,17 @@ timer_do_blank_screen(entering_gfx, 0); } +/* + * This is a timer handler + */ static void unblank_screen_t(unsigned long dummy) { unblank_screen(); } +/* + * Called by timer as well as from vt_console_driver + */ void unblank_screen(void) { int currcons; @@ -2664,18 +2717,25 @@ if (blankinterval) { mod_timer(&console_timer, jiffies + blankinterval); } - currcons = fg_console; console_blanked = 0; if (console_blank_hook) console_blank_hook(0); set_palette(currcons); - if (sw->con_blank(vc_cons[currcons].d, 0)) + if (sw->con_blank(vc_cons[currcons].d, 0)) { + if (vcmode != KD_TEXT) + return; /* Low-level driver cannot restore -> do it ourselves */ update_screen(fg_console); + } + if (vcmode != KD_TEXT) + return; set_cursor(fg_console); } +/* + * This is both a user-level callable and a timer handler + */ static void blank_screen(unsigned long dummy) { timer_do_blank_screen(0, 1); @@ -2683,7 +2743,7 @@ void poke_blanked_console(void) { - del_timer(&console_timer); /* Can't use _sync here: called from tasklet */ + del_timer(&console_timer); if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) return; if (console_blanked) { @@ -2831,9 +2891,9 @@ op->data = temp; } - spin_lock_irq(&console_lock); + acquire_console_sem(); rc = sw->con_font_op(vc_cons[currcons].d, op); - spin_unlock_irq(&console_lock); + release_console_sem(); op->data = old_op.data; if (!rc && !set) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/cyclades.c linux.ac/drivers/char/cyclades.c --- linux.vanilla/drivers/char/cyclades.c Wed Nov 15 08:41:03 2000 +++ linux.ac/drivers/char/cyclades.c Tue Apr 10 18:13:42 2001 @@ -209,7 +209,7 @@ * board type. * * Revision 1.36.4.30 1997/05/16 15:30:00 daniel - * Changes to suport new cycladesZ boards. + * Changes to support new cycladesZ boards. * * Revision 1.36.4.29 1997/05/12 11:30:00 daniel * Merge of Bentson's and Daniel's version 1.36.4.28. @@ -241,7 +241,7 @@ * varying too fast. * * Revision 1.36.4.27 1997/03/26 10:30:00 daniel - * Changed for suport linux versions 2.1.X. + * Changed for support linux versions 2.1.X. * Backward compatible with linux versions 2.0.X. * Corrected illegal use of filler field in * CH_CTRL struct. @@ -676,14 +676,6 @@ #include <linux/stat.h> #include <linux/proc_fs.h> - -#ifdef CONFIG_COBALT_27 -#include <asm/page.h> -#include <asm/pgtable.h> - -#define CACHED_TO_UNCACHED(x) (((unsigned long)(x) & \ - (unsigned long)0x1fffffff) + KSEG1) -#endif #define cy_put_user put_user diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/dz.c linux.ac/drivers/char/dz.c --- linux.vanilla/drivers/char/dz.c Tue Apr 3 17:32:00 2001 +++ linux.ac/drivers/char/dz.c Tue Apr 3 17:54:39 2001 @@ -1436,7 +1436,7 @@ * dz_console_print () * * dz_console_print is registered for printk. - * The console_lock must be held when we get here. + * The console must be locked when we get here. * ------------------------------------------------------------------- */ static void dz_console_print (struct console *cons, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/epca.c linux.ac/drivers/char/epca.c --- linux.vanilla/drivers/char/epca.c Sat Feb 17 00:02:35 2001 +++ linux.ac/drivers/char/epca.c Tue Apr 3 17:54:39 2001 @@ -769,7 +769,7 @@ globalwinon(ch); /* ----------------------------------------------------------------- - Anding against size will wrap the pointer back to its begining + Anding against size will wrap the pointer back to its beginning position if it is necessary. This will only work if size is a power of 2 which should always be the case. Size is determined by the cards on board FEP/OS. @@ -789,7 +789,7 @@ tail = bc->tout; /* ------------------------------------------------------------------ - Anding against size will wrap the pointer back to its begining + Anding against size will wrap the pointer back to its beginning position if it is necessary. This will only work if size is a power of 2 which should always be the case. Size is determined by the cards on board FEP/OS. @@ -818,7 +818,7 @@ tail head The above diagram shows that buffer locations 2,3,4,5 and 6 have - data to be transmited, while head points at the next empty + data to be transmitted, while head points at the next empty location. To calculate how much space is available first we have to determine if the head pointer (tin) has wrapped. To do this compare the head pointer to the tail pointer, If head is equal @@ -827,9 +827,9 @@ that value from the buffers size. A one is subtracted from the new value to indicate how much space is available between the head pointer and end of buffer; as well as the space between the - begining of the buffer and the tail. If the head is not greater + beginning of the buffer and the tail. If the head is not greater or equal to the tail this indicates that the head has wrapped - around to the begining of the buffer. To calculate the space + around to the beginning of the buffer. To calculate the space available in this case simply subtract head from tail. This new value minus one represents the space available betwwen the head and tail pointers. In this example head (7) is greater than tail (2) @@ -849,7 +849,7 @@ head tail The above diagram shows that buffer locations 7,8,9,0 and 1 have - data to be transmited, while head points at the next empty + data to be transmitted, while head points at the next empty location. To find the space available we compare head to tail. If head is not equal to, or greater than tail this indicates that head has wrapped around. In this case head (2) is not equal to, or @@ -1339,7 +1339,7 @@ } /* --------------------------------------------------------------- - Allow someone else to be scheduled. We will occasionaly go + Allow someone else to be scheduled. We will occasionally go through this loop until one of the above conditions change. The below schedule call will allow other processes to enter and prevent this loop from hogging the cpu. @@ -1574,7 +1574,8 @@ cli(); if ((tty_unregister_driver(&pc_driver)) || - (tty_unregister_driver(&pc_callout))) + (tty_unregister_driver(&pc_callout)) || + (tty_unregister_driver(&pc_info))) { printk(KERN_WARNING "<Error> - DIGI : cleanup_module failed to un-register tty driver\n"); restore_flags(flags); @@ -1685,7 +1686,7 @@ the boards array is correct. This could be wrong if the card in question is PCI (And therefore has no ports entry in the boards structure.) The rest of the - information will be valid for PCI because the begining + information will be valid for PCI because the beginning of pc_init scans for PCI and determines i/o and base memory addresses. I am not sure if it is possible to read the number of ports supported by the card prior to @@ -1937,7 +1938,7 @@ /* ------------------------------------------------------------- This call is made by the user via. the ioctl call DIGI_INIT. - It is resposible for setting up all the card specific stuff. + It is responsible for setting up all the card specific stuff. ---------------------------------------------------------------- */ bd = &boards[crd]; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/esp.c linux.ac/drivers/char/esp.c --- linux.vanilla/drivers/char/esp.c Fri Feb 9 19:30:22 2001 +++ linux.ac/drivers/char/esp.c Tue Apr 10 18:13:42 2001 @@ -1907,7 +1907,7 @@ return get_lsr_info(info, (unsigned int *) arg); case TIOCSERSWILD: - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/ftape/zftape/zftape-vtbl.c linux.ac/drivers/char/ftape/zftape/zftape-vtbl.c --- linux.vanilla/drivers/char/ftape/zftape/zftape-vtbl.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/char/ftape/zftape/zftape-vtbl.c Tue Apr 10 18:13:56 2001 @@ -431,7 +431,7 @@ /* this functions translates the failed_sector_log, misused as * EOF-marker list, into a virtual volume table. The table mustn't be * written to tape, because this would occupy the first data segment, - * which should be the volume table, but is actualy the first segment + * which should be the volume table, but is actually the first segment * that is filled with data (when using standard ftape). We assume, * that we get a non-empty failed_sector_log. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/hp600_keyb.c linux.ac/drivers/char/hp600_keyb.c --- linux.vanilla/drivers/char/hp600_keyb.c Fri Sep 22 22:21:17 2000 +++ linux.ac/drivers/char/hp600_keyb.c Sat Apr 14 01:21:24 2001 @@ -1,13 +1,17 @@ /* - * $Id: hp600_keyb.c,v 1.1 2000/06/10 21:45:30 yaegashi Exp $ + * $Id$ * Copyright (C) 2000 YAEGASHI Takeshi - * HP600 keyboard scan routine and translate table + * HP600 keyboard scan routine and translation table + * Copyright (C) 2000 Niibe Yutaka + * HP620 keyboard translation table */ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/init.h> -#include <linux/delay.h> + +#include <asm/machvec.h> +#include <asm/delay.h> #include <asm/io.h> #include "scan_keyb.h" @@ -17,55 +21,119 @@ #define PFDR 0xa400012a #define PGDR 0xa400012c #define PHDR 0xa400012e +#define PJDR 0xa4000130 +#define PKDR 0xa4000132 +#define PLDR 0xa4000134 + +static const unsigned char hp620_japanese_table[] = { + /* PTD1 */ + 0x0a, 0x0b, 0x0c, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + /* PTD5 */ + 0x18, 0x19, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + /* PTD7 */ + 0x26, 0x1a, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + /* PTE0 */ + 0x27, 0x1b, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2a, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + /* PTE1 */ + 0x35, 0x28, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x3a, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x34, + /* PTE3 */ + 0x48, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x2d, 0x2e, 0x7b, 0x30, 0x31, 0x32, 0x33, + /* PTE6 */ + 0x4b, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x2c, 0x38, 0x00, 0x39, 0x79, 0x7d, 0x73, + /* PTE7 */ + 0x41, 0x42, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, + /* **** */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; -static const unsigned char hp690_japanese_table[]={ - 0x00, 0x00, 0x00, 0x01, 0x00, 0x29, 0x70, 0x3a, - 0x3f, 0x3e, 0x40, 0x41, 0x42, 0x3d, 0x3c, 0x3b, - - 0x00, 0x00, 0x00, 0x2c, 0x00, 0x1c, 0x28, 0x35, - 0x31, 0x30, 0x32, 0x33, 0x34, 0x2f, 0x2e, 0x2d, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x50, - 0x7b, 0x38, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, +static const unsigned char hp680_japanese_table[] = { + /* PTD1 */ + 0x3a, 0x70, 0x29, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x3b, 0x3c, 0x3d, 0x42, 0x41, 0x40, 0x3e, 0x3f, + /* PTD5 */ + 0x35, 0x28, 0x1c, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x2d, 0x2e, 0x2f, 0x34, 0x33, 0x32, 0x30, 0x31, + /* PTD7 */ + 0x50, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x38, 0x7b, + /* PTE0 */ + 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, + 0x1d, 0x00, 0x39, 0x53, 0x73, 0xf9, 0x00, 0x00, + /* PTE1 */ + 0x27, 0x1b, 0x2b, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x1f, 0x20, 0x21, 0x26, 0x25, 0x24, 0x22, 0x23, + /* PTE3 */ + 0x48, 0x7d, 0x36, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* PTE6 */ + 0x19, 0x1a, 0x0e, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x11, 0x12, 0x13, 0x18, 0x17, 0x16, 0x14, 0x15, + /* PTE7 */ + 0x0b, 0x0c, 0x0d, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x04, 0x05, 0x0a, 0x09, 0x08, 0x06, 0x07, + /* **** */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xf9, 0x73, 0x53, 0x39, 0x00, 0x1d, - - 0x00, 0x00, 0x00, 0x1e, 0x00, 0x2b, 0x1b, 0x27, - 0x23, 0x22, 0x24, 0x25, 0x26, 0x21, 0x20, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; - 0x00, 0x00, 0x00, 0x0f, 0x00, 0x36, 0x7d, 0x48, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x00, 0x0e, 0x1a, 0x19, - 0x15, 0x14, 0x16, 0x17, 0x18, 0x13, 0x12, 0x11, +static int hp620_japanese_scan_kbd(unsigned char *s) +{ + int i; + unsigned char matrix_switch[] = { + 0xfd, 0xff, /* PTD1 */ + 0xdf, 0xff, /* PTD5 */ + 0x7f, 0xff, /* PTD7 */ + 0xff, 0xfe, /* PTE0 */ + 0xff, 0xfd, /* PTE1 */ + 0xff, 0xf7, /* PTE3 */ + 0xff, 0xbf, /* PTE6 */ + 0xff, 0x7f, /* PTE7 */ + }, *t=matrix_switch; - 0x00, 0x00, 0x00, 0x02, 0x00, 0x0d, 0x0c, 0x0b, - 0x07, 0x06, 0x08, 0x09, 0x0a, 0x05, 0x04, 0x03, + for(i=0; i<8; i++) { + ctrl_outb(*t++, PDDR); + ctrl_outb(*t++, PEDR); + udelay(50); + *s++=ctrl_inb(PCDR); + *s++=ctrl_inb(PFDR); + } - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; + ctrl_outb(0xff, PDDR); + ctrl_outb(0xff, PEDR); + *s++=ctrl_inb(PGDR); + *s++=ctrl_inb(PHDR); -static const unsigned char hp690_switch[]= { - 0xfd, 0xff, - 0xdf, 0xff, - 0x7f, 0xff, - 0xff, 0xfe, - 0xff, 0xfd, - 0xff, 0xf7, - 0xff, 0xbf, - 0xff, 0x7f, -}; + return 0; +} -static void hp690_japanese_scan_kbd(unsigned char *s) +static int hp680_japanese_scan_kbd(unsigned char *s) { int i; - unsigned const char *t=hp690_switch; + unsigned char matrix_switch[] = { + 0xfd, 0xff, /* PTD1 */ + 0xdf, 0xff, /* PTD5 */ + 0x7f, 0xff, /* PTD7 */ + 0xff, 0xfe, /* PTE0 */ + 0xff, 0xfd, /* PTE1 */ + 0xff, 0xf7, /* PTE3 */ + 0xff, 0xbf, /* PTE6 */ + 0xff, 0x7f, /* PTE7 */ + }, *t=matrix_switch; - for(i=0; i<9; i++) { + for(i=0; i<8; i++) { ctrl_outb(*t++, PDDR); ctrl_outb(*t++, PEDR); *s++=ctrl_inb(PCDR); @@ -77,18 +145,25 @@ *s++=ctrl_inb(PGDR); *s++=ctrl_inb(PHDR); + + return 0; } void __init hp600_kbd_init_hw(void) { scan_kbd_init(); - register_scan_keyboard(hp690_japanese_scan_kbd, - hp690_japanese_table, 18); + + if (MACH_HP620) + register_scan_keyboard(hp620_japanese_scan_kbd, + hp620_japanese_table, 18); + else if (MACH_HP680 || MACH_HP690) + register_scan_keyboard(hp680_japanese_scan_kbd, + hp680_japanese_table, 18); + printk(KERN_INFO "HP600 matrix scan keyboard registered\n"); } - /**************************************************************** HP Jornada 690(Japanese version) keyboard scan matrix @@ -102,7 +177,6 @@ PTE6 REC Q on/off BS @ P PTE7 REC 1 on/off ^ - 0 - PTF7 PTF6 PTF5 PTF4 PTF3 PTF2 PTF1 PTF0 PTD1 F5 F4 F6 F7 F8 F3 F2 F1 PTD5 N B M , . V C X @@ -129,3 +203,136 @@ L: 0x0c3c 0x26 F F IP F F IP IP F ****************************************************************/ + +/**************************************************************** +HP Jornada 620(Japanese version) keyboard scan matrix + + PTC7 PTC6 PTC5 PTC4 PTC3 PTC2 PTC1 PTC0 +PTD1 EREC BS Ctrl on/off - 0 9 +PTD5 EREC BS Ctrl on/off ^ P O +PTD7 EREC BS Ctrl on/off ] @ L +PTE0 EREC BS Ctrl on/off Han/Zen [ ; +PTE1 EREC BS Ctrl on/off Enter : / +PTE3 EREC BS Ctrl on/off Right Up +PTE6 EREC BS Ctrl on/off Down Left +PTE7 EREC BS Ctrl on/off F8 F7 + + PTF7 PTF6 PTF5 PTF4 PTF3 PTF2 PTF1 PTF0 +PTD1 8 7 6 5 4 3 2 1 +PTD5 I U Y T R E W Q +PTD7 K J H G F D S A +PTE0 ESC Tab Shift +PTE1 . V Caps Hira +PTE3 , M N B Muhen C X +PTE6 _ \ Henkan Space Alt Z +PTE7 F6 F5 F4 F3 F2 F1 REC + + PTH0 +* on/off + + 7 6 5 4 3 2 1 0 +C: 0xffff 0xff IP IP IP IP IP IP IP IP +D: 0x4404 0xaf O F O F F F O F +E: 0x5045 0xff O O F F O F O O +F: 0xffff 0xff IP IP IP IP IP IP IP IP +G: 0xd5ff 0x00 IP O O O IP IP IP IP +H: 0x63ff 0xd1 O I F IP IP IP IP IP +J: 0x0004 0x02 F F F F F F O F +K: 0x0401 0xff F F O F F F F O +L: 0x0c00 0x20 F F IP F F F F F + +ADCSR: 0x08 +ADCR: 0x3f + + ****************************************************************/ + +/**************************************************************** +Japanese 109 keyboard scan code layout + + E02A- E1- +01 3B 3C 3D 3E 3F 40 41 42 43 44 57 58 E037 46 1045 + +29 02 03 04 05 06 07 08 09 0A 0B 0C 0D 7D 0E E052 E047 E049 45 E035 37 4A +0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C E053 E04F E051 47 48 49 4E +3A 1E 1F 20 21 22 23 24 25 26 27 28 2B 4B 4C 4D +2A 2C 2D 2E 2F 30 31 32 33 34 35 73 36 E048 4F 50 51 E0- +1D DB 38 7B 39 79 70 E038 DC DD E01D E04B E050 E04D 52 53 1C + +****************************************************************/ + +#if 0 +int __init hp620_keyboard_test(void) +{ + int i; + unsigned char s[18]; + unsigned long a, b, c, d; + + printk("PCCR: %04lx, PCDR: %02lx\n", + ctrl_inw(0xa4000104), ctrl_inb(0xa4000124)); + printk("PDCR: %04lx, PDDR: %02lx\n", + ctrl_inw(0xa4000106), ctrl_inb(0xa4000126)); + printk("PECR: %04lx, PEDR: %02lx\n", + ctrl_inw(0xa4000108), ctrl_inb(0xa4000128)); + printk("PFCR: %04lx, PFDR: %02lx\n", + ctrl_inw(0xa400010a), ctrl_inb(0xa400012a)); + printk("PGCR: %04lx, PGDR: %02lx\n", + ctrl_inw(0xa400010c), ctrl_inb(0xa400012c)); + printk("PHCR: %04lx, PHDR: %02lx\n", + ctrl_inw(0xa400010e), ctrl_inb(0xa400012e)); + printk("PJCR: %04lx, PJDR: %02lx\n", + ctrl_inw(0xa4000110), ctrl_inb(0xa4000130)); + printk("PKCR: %04lx, PKDR: %02lx\n", + ctrl_inw(0xa4000112), ctrl_inb(0xa4000132)); + printk("PLCR: %04lx, PLDR: %02lx\n", + ctrl_inw(0xa4000114), ctrl_inb(0xa4000134)); + + printk("ADCSR: %02lx, ADCR: %02lx\n", + ctrl_inb(0xa4000090), ctrl_inb(0xa4000092)); + + ctrl_inb(0xa4000004); + ctrl_inb(0xa4000006); + ctrl_inb(0xa4000008); + ctrl_outb(0, 0xa4000004); + ctrl_outb(0, 0xa4000006); + ctrl_outb(0, 0xa4000008); + ctrl_outb(0, 0xa4000090); + ctrl_outb(0x3b, 0xa4000090); + + while(1) { + hp620_japanese_scan_kbd(s); + for(i=0; i<18; i+=2) + printk("%02x%02x ", s[i], s[i+1]); + +#if 0 + ctrl_outb(~2, PJDR); + printk("%02lx%02lx ", ctrl_inb(PCDR), ctrl_inb(PFDR)); + ctrl_outb(0xff, PJDR); + ctrl_outb(~1, PKDR); + printk("%02lx%02lx ", ctrl_inb(PCDR), ctrl_inb(PFDR)); + ctrl_outb(~32, PKDR); + printk("%02lx%02lx ", ctrl_inb(PCDR), ctrl_inb(PFDR)); + ctrl_outb(0xff, PKDR); +#endif + + printk("%02lx%02lx%02lx%02lx ", a, b, c, d); + if(ctrl_inb(0xa4000090)&0x80) { + a=ctrl_inb(0xa4000080); + b=ctrl_inb(0xa4000084); + c=ctrl_inb(0xa4000088); + d=ctrl_inb(0xa400008c); + ctrl_outb(0x3b, 0xa4000090); + } + printk("%02lx%02lx%02lx ", + ctrl_inb(0xa4000004), + ctrl_inb(0xa4000006), + ctrl_inb(0xa4000008)); + + printk("\n"); + } + + return 0; +} +module_init(keyboard_probe); +#endif + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/i810_rng.c linux.ac/drivers/char/i810_rng.c --- linux.vanilla/drivers/char/i810_rng.c Tue Apr 3 17:32:00 2001 +++ linux.ac/drivers/char/i810_rng.c Sat Apr 14 01:21:24 2001 @@ -35,7 +35,7 @@ /* * core module and version information */ -#define RNG_VERSION "0.9.5" +#define RNG_VERSION "0.9.6" #define RNG_MODULE_NAME "i810_rng" #define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION #define PFX RNG_MODULE_NAME ": " @@ -81,26 +81,13 @@ #define RNG_ADDR 0xFFBC015F #define RNG_ADDR_LEN 3 -#define RNG_MAX_ENTROPY 8 /* max entropy h/w is capable of */ - #define RNG_MISCDEV_MINOR 183 /* official */ - -/* - * number of bytes required for a FIPS test. - * do not alter unless you really, I mean - * REALLY know what you are doing. - */ -#define RNG_FIPS_TEST_THRESHOLD 2500 - - /* * various RNG status variables. they are globals * as we only support a single RNG device */ -static int rng_hw_enabled; /* is the RNG h/w enabled? */ static void *rng_mem; /* token to our ioremap'd RNG register area */ -static struct pci_dev *rng_pdev; /* Firmware Hub PCI device found during PCI probe */ static struct semaphore rng_open_sem; /* Semaphore for serializing rng_open/release */ @@ -113,18 +100,17 @@ return readb (rng_mem + RNG_HW_STATUS); } - -static inline void rng_hwstatus_set (u8 hw_status) +static inline u8 rng_hwstatus_set (u8 hw_status) { assert (rng_mem != NULL); writeb (hw_status, rng_mem + RNG_HW_STATUS); + return rng_hwstatus (); } static inline int rng_data_present (void) { assert (rng_mem != NULL); - assert (rng_hw_enabled > 0); return (readb (rng_mem + RNG_STATUS) & RNG_DATA_PRESENT) ? 1 : 0; } @@ -133,65 +119,67 @@ static inline int rng_data_read (void) { assert (rng_mem != NULL); - assert (rng_hw_enabled > 0); return readb (rng_mem + RNG_DATA); } - /* - * rng_enable - enable or disable the RNG hardware + * rng_enable - enable the RNG hardware */ -static int rng_enable (int enable) + +static int rng_enable (void) { - int rc = 0, action = 0; + int rc = 0; u8 hw_status, new_status; DPRINTK ("ENTER\n"); hw_status = rng_hwstatus (); - if (enable) { - rng_hw_enabled++; - MOD_INC_USE_COUNT; - } else { - if (rng_hw_enabled) { - rng_hw_enabled--; - MOD_DEC_USE_COUNT; + if ((hw_status & RNG_ENABLED) == 0) { + new_status = rng_hwstatus_set (hw_status | RNG_ENABLED); + + if (new_status & RNG_ENABLED) + printk (KERN_INFO PFX "RNG h/w enabled\n"); + else { + printk (KERN_ERR PFX "Unable to enable the RNG\n"); + rc = -EIO; } } - if (rng_hw_enabled && ((hw_status & RNG_ENABLED) == 0)) { - rng_hwstatus_set (hw_status | RNG_ENABLED); - action = 1; - } + DPRINTK ("EXIT, returning %d\n", rc); + return rc; +} - else if (!rng_hw_enabled && (hw_status & RNG_ENABLED)) { - rng_hwstatus_set (hw_status & ~RNG_ENABLED); - action = 2; - } +/* + * rng_disable - disable the RNG hardware + */ - new_status = rng_hwstatus (); +static void rng_disable(void) +{ + u8 hw_status, new_status; - if (action == 1) { - if (new_status & RNG_ENABLED) - printk (KERN_INFO PFX "RNG h/w enabled\n"); - else - printk (KERN_ERR PFX "Unable to enable the RNG\n"); - } else if (action == 2) { + DPRINTK ("ENTER\n"); + + hw_status = rng_hwstatus (); + + if (hw_status & RNG_ENABLED) { + new_status = rng_hwstatus_set (hw_status & ~RNG_ENABLED); + if ((new_status & RNG_ENABLED) == 0) printk (KERN_INFO PFX "RNG h/w disabled\n"); - else + else { printk (KERN_ERR PFX "Unable to disable the RNG\n"); + } } - DPRINTK ("EXIT, returning %d\n", rc); - return rc; + DPRINTK ("EXIT\n"); } - static int rng_dev_open (struct inode *inode, struct file *filp) { + int rc; + if ((filp->f_mode & FMODE_READ) == 0) return -EINVAL; if (filp->f_mode & FMODE_WRITE) @@ -206,9 +194,10 @@ return -ERESTARTSYS; } - if (rng_enable (1)) { + rc = rng_enable (); + if (rc) { up (&rng_open_sem); - return -EIO; + return rc; } return 0; @@ -217,7 +206,7 @@ static int rng_dev_release (struct inode *inode, struct file *filp) { - rng_enable(0); + rng_disable (); up (&rng_open_sem); return 0; } @@ -315,8 +304,9 @@ } /* turn RNG h/w off, if it's on */ - rc = rng_enable (0); - if (rc) { + if (hw_status & RNG_ENABLED) + hw_status = rng_hwstatus_set (hw_status & ~RNG_ENABLED); + if (hw_status & RNG_ENABLED) { printk (KERN_ERR PFX "cannot disable RNG, aborting\n"); goto err_out_free_map; } @@ -381,8 +371,6 @@ printk (KERN_INFO RNG_DRIVER_NAME " loaded\n"); - rng_pdev = pdev; - DPRINTK ("EXIT, returning 0\n"); return 0; } @@ -395,13 +383,9 @@ { DPRINTK ("ENTER\n"); - assert (rng_hw_enabled == 0); - misc_deregister (&rng_miscdev); iounmap (rng_mem); - - rng_pdev = NULL; DPRINTK ("EXIT\n"); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/ip2.c linux.ac/drivers/char/ip2.c --- linux.vanilla/drivers/char/ip2.c Sat Feb 17 00:02:35 2001 +++ linux.ac/drivers/char/ip2.c Tue Apr 3 17:54:39 2001 @@ -6,7 +6,6 @@ // __initdata should work as advertized // -#include <linux/config.h> #include <linux/module.h> #include <linux/version.h> #include <linux/init.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/isicom.c linux.ac/drivers/char/isicom.c --- linux.vanilla/drivers/char/isicom.c Wed Dec 6 20:06:18 2000 +++ linux.ac/drivers/char/isicom.c Tue Apr 10 18:13:56 2001 @@ -16,6 +16,10 @@ * * 10/6/99 sameer Merged the ISA and PCI drivers to * a new unified driver. + * 09/06/01 acme@conectiva.com.br use capable, not suser, do + * restore_flags on failure in + * isicom_send_break, verify put_user + * result * *********************************************************** * * To use this driver you also need the support package. You @@ -1354,13 +1358,13 @@ while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0)); if (!wait) { printk(KERN_DEBUG "ISICOM: Card found busy in isicom_send_break.\n"); - return; + goto out; } outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base); outw((length & 0xff) << 8 | 0x00, base); outw((length & 0xff00), base); InterruptTheCard(base); - restore_flags(flags); +out: restore_flags(flags); } static int isicom_get_modem_info(struct isi_port * port, unsigned int * value) @@ -1375,8 +1379,7 @@ ((status & ISI_DSR) ? TIOCM_DSR : 0) | ((status & ISI_CTS) ? TIOCM_CTS : 0) | ((status & ISI_RI ) ? TIOCM_RI : 0); - put_user(info, (unsigned int *) value); - return 0; + return put_user(info, (unsigned int *) value); } static int isicom_set_modem_info(struct isi_port * port, unsigned int cmd, @@ -1438,7 +1441,7 @@ reconfig_port = ((port->flags & ASYNC_SPD_MASK) != (newinfo.flags & ASYNC_SPD_MASK)); - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { if ((newinfo.close_delay != port->close_delay) || (newinfo.closing_wait != port->closing_wait) || ((newinfo.flags & ~ASYNC_USR_MASK) != diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/joystick/Config.in linux.ac/drivers/char/joystick/Config.in --- linux.vanilla/drivers/char/joystick/Config.in Tue Aug 22 19:55:47 2000 +++ linux.ac/drivers/char/joystick/Config.in Thu Apr 12 12:02:00 2001 @@ -11,6 +11,7 @@ dep_tristate ' ns558 gameports' CONFIG_INPUT_NS558 $CONFIG_INPUT dep_tristate ' PDPI Lightning 4 gamecard' CONFIG_INPUT_LIGHTNING $CONFIG_INPUT dep_tristate ' Aureal Vortex and Trident 4DWave gameports' CONFIG_INPUT_PCIGAME $CONFIG_INPUT + dep_tristate ' Crystal SoundFusion gameports' CONFIG_INPUT_CS461X $CONFIG_INPUT comment 'Gameport joysticks' dep_tristate ' Classic PC analog joysticks and gamepads' CONFIG_INPUT_ANALOG $CONFIG_INPUT @@ -31,6 +32,7 @@ dep_tristate ' LogiCad3d Magellan/SpaceMouse 6dof controller' CONFIG_INPUT_MAGELLAN $CONFIG_INPUT dep_tristate ' SpaceTec SpaceOrb/Avenger 6dof controller' CONFIG_INPUT_SPACEORB $CONFIG_INPUT dep_tristate ' SpaceTec SpaceBall 4000 FLX 6dof controller' CONFIG_INPUT_SPACEBALL $CONFIG_INPUT + dep_tristate ' Gravis Stinger gamepad' CONFIG_INPUT_STINGER $CONFIG_INPUT dep_tristate ' I-Force/Serial controllers' CONFIG_INPUT_IFORCE_232 $CONFIG_INPUT dep_tristate ' I-Force/USB controllers' CONFIG_INPUT_IFORCE_USB $CONFIG_INPUT $CONFIG_USB diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/joystick/Makefile linux.ac/drivers/char/joystick/Makefile --- linux.vanilla/drivers/char/joystick/Makefile Fri Dec 29 22:07:21 2000 +++ linux.ac/drivers/char/joystick/Makefile Thu Apr 12 12:02:00 2001 @@ -35,11 +35,13 @@ obj-$(CONFIG_INPUT_NS558) += ns558.o gameport.o obj-$(CONFIG_INPUT_LIGHTNING) += lightning.o gameport.o obj-$(CONFIG_INPUT_PCIGAME) += pcigame.o gameport.o +obj-$(CONFIG_INPUT_CS461X) += cs461x.o gameport.o obj-$(CONFIG_INPUT_WARRIOR) += warrior.o serio.o obj-$(CONFIG_INPUT_MAGELLAN) += magellan.o serio.o obj-$(CONFIG_INPUT_SPACEORB) += spaceorb.o serio.o obj-$(CONFIG_INPUT_SPACEBALL) += spaceball.o serio.o +obj-$(CONFIG_INPUT_STINGER) += stinger.o serio.o obj-$(CONFIG_INPUT_IFORCE_232) += iforce.o serio.o obj-$(CONFIG_INPUT_IFORCE_USB) += iforce.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/joystick/adi.c linux.ac/drivers/char/joystick/adi.c --- linux.vanilla/drivers/char/joystick/adi.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/char/joystick/adi.c Thu Apr 12 12:02:00 2001 @@ -1,5 +1,5 @@ /* - * $Id: adi.c,v 1.12 2000/06/03 20:18:52 vojtech Exp $ + * $Id: adi.c,v 1.15 2001/01/09 13:32:39 vojtech Exp $ * * Copyright (c) 1998-2000 Vojtech Pavlik * @@ -370,7 +370,8 @@ adi->cname[i] = adi_get_bits(adi, 8); adi->cname[i] = 0; - if (adi->length != (t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4)) { + t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4; + if (adi->length != t && adi->length != t + (t & 1)) { printk(KERN_WARNING "adi: Expected length %d != data length %d\n", t, adi->length); adi->length = 0; return; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/joystick/cobra.c linux.ac/drivers/char/joystick/cobra.c --- linux.vanilla/drivers/char/joystick/cobra.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/char/joystick/cobra.c Thu Apr 12 12:02:00 2001 @@ -131,7 +131,7 @@ input_report_abs(dev, ABS_Y, ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1)); for (j = 0; cobra_btn[j]; j++) - input_report_key(dev, cobra_btn[j], data[i] & (0x20 << i)); + input_report_key(dev, cobra_btn[j], data[i] & (0x20 << j)); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/joystick/cs461x.c linux.ac/drivers/char/joystick/cs461x.c --- linux.vanilla/drivers/char/joystick/cs461x.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/char/joystick/cs461x.c Thu Apr 12 12:02:00 2001 @@ -0,0 +1,331 @@ +/* + The all defines and part of code (such as cs461x_*) are + contributed from ALSA 0.5.8 sources. + See http://www.alsa-project.org/ for sources + + Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610 +*/ + +#include <asm/io.h> + +#include <linux/module.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/gameport.h> +#include <linux/slab.h> +#include <linux/pci.h> + +MODULE_AUTHOR("Victor Krapivin <vik@belcaf.minsk.by>"); + +/* + These options are experimental + +#define COOKED_MODE +#define CS461X_FULL_MAP + +*/ + +#ifndef PCI_VENDOR_ID_CIRRUS +#define PCI_VENDOR_ID_CIRRUS 0x1013 +#endif +#ifndef PCI_DEVICE_ID_CIRRUS_4610 +#define PCI_DEVICE_ID_CIRRUS_4610 0x6001 +#endif +#ifndef PCI_DEVICE_ID_CIRRUS_4612 +#define PCI_DEVICE_ID_CIRRUS_4612 0x6003 +#endif +#ifndef PCI_DEVICE_ID_CIRRUS_4615 +#define PCI_DEVICE_ID_CIRRUS_4615 0x6004 +#endif + +/* Registers */ + +#define BA0_JSPT 0x00000480 +#define BA0_JSCTL 0x00000484 +#define BA0_JSC1 0x00000488 +#define BA0_JSC2 0x0000048C +#define BA0_JSIO 0x000004A0 + +/* Bits for JSPT */ + +#define JSPT_CAX 0x00000001 +#define JSPT_CAY 0x00000002 +#define JSPT_CBX 0x00000004 +#define JSPT_CBY 0x00000008 +#define JSPT_BA1 0x00000010 +#define JSPT_BA2 0x00000020 +#define JSPT_BB1 0x00000040 +#define JSPT_BB2 0x00000080 + +/* Bits for JSCTL */ + +#define JSCTL_SP_MASK 0x00000003 +#define JSCTL_SP_SLOW 0x00000000 +#define JSCTL_SP_MEDIUM_SLOW 0x00000001 +#define JSCTL_SP_MEDIUM_FAST 0x00000002 +#define JSCTL_SP_FAST 0x00000003 +#define JSCTL_ARE 0x00000004 + +/* Data register pairs masks */ + +#define JSC1_Y1V_MASK 0x0000FFFF +#define JSC1_X1V_MASK 0xFFFF0000 +#define JSC1_Y1V_SHIFT 0 +#define JSC1_X1V_SHIFT 16 +#define JSC2_Y2V_MASK 0x0000FFFF +#define JSC2_X2V_MASK 0xFFFF0000 +#define JSC2_Y2V_SHIFT 0 +#define JSC2_X2V_SHIFT 16 + +/* JS GPIO */ + +#define JSIO_DAX 0x00000001 +#define JSIO_DAY 0x00000002 +#define JSIO_DBX 0x00000004 +#define JSIO_DBY 0x00000008 +#define JSIO_AXOE 0x00000010 +#define JSIO_AYOE 0x00000020 +#define JSIO_BXOE 0x00000040 +#define JSIO_BYOE 0x00000080 + +/* + The card initialization code is obfuscated; the module cs461x + need to be loaded after ALSA modules initialized and something + played on the CS 4610 chip (see sources for details of CS4610 + initialization code from ALSA) +*/ + +/* Card specific definitions */ + +#define CS461X_BA0_SIZE 0x2000 +#define CS461X_BA1_DATA0_SIZE 0x3000 +#define CS461X_BA1_DATA1_SIZE 0x3800 +#define CS461X_BA1_PRG_SIZE 0x7000 +#define CS461X_BA1_REG_SIZE 0x0100 + +#define BA1_SP_DMEM0 0x00000000 +#define BA1_SP_DMEM1 0x00010000 +#define BA1_SP_PMEM 0x00020000 +#define BA1_SP_REG 0x00030000 + +#define BA1_DWORD_SIZE (13 * 1024 + 512) +#define BA1_MEMORY_COUNT 3 + +/* + Only one CS461x card is still suppoted; the code requires + redesign to avoid this limitatuion. +*/ + +static unsigned long ba0_addr; +static unsigned int *ba0; + +#ifdef CS461X_FULL_MAP +static unsigned long ba1_addr; +static union ba1_t { + struct { + unsigned int *data0; + unsigned int *data1; + unsigned int *pmem; + unsigned int *reg; + } name; + unsigned int *idx[4]; +} ba1; + +static void cs461x_poke(unsigned long reg, unsigned int val) +{ + ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff] = val; +} + +static unsigned int cs461x_peek(unsigned long reg) +{ + return ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]; +} + +#endif + +static void cs461x_pokeBA0(unsigned long reg, unsigned int val) +{ + ba0[reg >> 2] = val; +} + +static unsigned int cs461x_peekBA0(unsigned long reg) +{ + return ba0[reg >> 2]; +} + +static int cs461x_free(struct pci_dev *pdev) +{ + struct gameport *port = (struct gameport *)pdev->driver_data; + if(port){ + gameport_unregister_port(port); + kfree(port); + } + if (ba0) iounmap(ba0); +#ifdef CS461X_FULL_MAP + if (ba1.name.data0) iounmap(ba1.name.data0); + if (ba1.name.data1) iounmap(ba1.name.data1); + if (ba1.name.pmem) iounmap(ba1.name.pmem); + if (ba1.name.reg) iounmap(ba1.name.reg); +#endif + return 0; +} + +static void cs461x_gameport_trigger(struct gameport *gameport) +{ + cs461x_pokeBA0(BA0_JSPT, 0xFF); //outb(gameport->io, 0xFF); +} + +static unsigned char cs461x_gameport_read(struct gameport *gameport) +{ + return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io); +} + +static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons) +{ + unsigned js1, js2, jst; + + js1 = cs461x_peekBA0(BA0_JSC1); + js2 = cs461x_peekBA0(BA0_JSC2); + jst = cs461x_peekBA0(BA0_JSPT); + + *buttons = (~jst >> 4) & 0x0F; + + axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF; + axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF; + axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF; + axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF; + + for(jst=0;jst<4;++jst) + if(axes[jst]==0xFFFF) axes[jst] = -1; + return 0; +} + +static int cs461x_gameport_open(struct gameport *gameport, int mode) +{ + switch (mode) { +#ifdef COOKED_MODE + case GAMEPORT_MODE_COOKED: + return 0; +#endif + case GAMEPORT_MODE_RAW: + return 0; + default: + return -1; + } + return 0; +} + +static struct pci_device_id cs461x_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */ + { PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */ + { PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */ + { 0, } +}; +MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl); + +static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int rc; + struct gameport* port; + + rc = pci_enable_device(pdev); + if (rc) { + printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n", + pdev->bus->number, pdev->devfn, rc); + return rc; + } + + ba0_addr = pci_resource_start(pdev, 0); +#ifdef CS461X_FULL_MAP + ba1_addr = pci_resource_start(pdev, 1); +#endif + if (ba0_addr == 0 || ba0_addr == ~0 +#ifdef CS461X_FULL_MAP + || ba1_addr == 0 || ba1_addr == ~0 +#endif + ) { + printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr); +#ifdef CS461X_FULL_MAP + printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr); +#endif + cs461x_free(pdev); + return -ENOMEM; + } + + ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE); +#ifdef CS461X_FULL_MAP + ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE); + ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE); + ba1.name.pmem = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE); + ba1.name.reg = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE); + + if (ba0 == NULL || ba1.name.data0 == NULL || + ba1.name.data1 == NULL || ba1.name.pmem == NULL || + ba1.name.reg == NULL) { + cs461x_free(pdev); + return -ENOMEM; + } +#else + if (ba0 == NULL){ + cs461x_free(pdev); + return -ENOMEM; + } +#endif + printk(KERN_INFO "CS461x PCI: %lx[%d]\n", + ba0_addr, CS461X_BA0_SIZE); + + if (!(port = kmalloc(sizeof(struct gameport), GFP_KERNEL))) { + printk(KERN_ERR "Memory allocation failed.\n"); + cs461x_free(pdev); + return -ENOMEM; + } + memset(port, 0, sizeof(struct gameport)); + + port->io = -1; + port->size = -1; + pdev->driver_data = port; + + port->open = cs461x_gameport_open; + port->read = cs461x_gameport_read; + port->trigger = cs461x_gameport_trigger; +#ifdef COOKED_MODE + port->cooked_read = cs461x_gameport_cooked_read; +#endif + + cs461x_pokeBA0(BA0_JSIO, 0xFF); // ? + cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW); + + gameport_register_port(port); + + printk(KERN_INFO "gameport%d: CS461x PCI", port->number); + if (port->size > 1) printk(" size %d", port->size); + printk(" speed %d kHz\n", port->speed); + + return 0; +} + +static void __devexit cs461x_pci_remove(struct pci_dev *pdev) +{ + cs461x_free(pdev); +} + +static struct pci_driver cs461x_pci_driver = { + name: "PCI Gameport", + id_table: cs461x_pci_tbl, + probe: cs461x_pci_probe, + remove: cs461x_pci_remove, +}; + +int __init js_cs461x_init(void) +{ + return pci_module_init(&cs461x_pci_driver); +} + +void __exit js_cs461x_exit(void) +{ + pci_unregister_driver(&cs461x_pci_driver); +} + +module_init(js_cs461x_init); +module_exit(js_cs461x_exit); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/joystick/gamecon.c linux.ac/drivers/char/joystick/gamecon.c --- linux.vanilla/drivers/char/joystick/gamecon.c Mon Aug 14 21:55:01 2000 +++ linux.ac/drivers/char/joystick/gamecon.c Thu Apr 12 12:02:00 2001 @@ -1,11 +1,11 @@ /* - * $Id: gamecon.c,v 1.5 2000/06/25 09:56:58 vojtech Exp $ + * $Id: gamecon.c,v 1.11 2000/11/01 12:38:53 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * * Based on the work of: * Andree Borrmann John Dahlstrom - * David Kuder + * David Kuder Nathan Hand * * Sponsored by SuSE */ @@ -75,8 +75,7 @@ static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 }; static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick", - "Multisystem 2-button joystick", "N64 controller", "PSX pad", - "PSX NegCon", "PSX Analog contoller" }; + "Multisystem 2-button joystick", "N64 controller", "PSX controller" }; /* * N64 support. */ @@ -205,22 +204,30 @@ /* * PSX support - */ - -#define GC_PSX_DELAY 10 -#define GC_PSX_LENGTH 8 /* talk to the controller in bytes */ + * + * See documentation at: + * http://www.dim.com/~mackys/psxmemcard/ps-eng2.txt + * http://www.gamesx.com/controldata/psxcont/psxcont.htm + * ftp://milano.usal.es/pablo/ + * + */ + +#define GC_PSX_DELAY 60 /* 60 usec */ +#define GC_PSX_LENGTH 8 /* talk to the controller in bytes */ + +#define GC_PSX_MOUSE 1 /* Mouse */ +#define GC_PSX_NEGCON 2 /* NegCon */ +#define GC_PSX_NORMAL 4 /* Digital / Analog or Rumble in Digital mode */ +#define GC_PSX_ANALOG 5 /* Analog in Analog mode / Rumble in Green mode */ +#define GC_PSX_RUMBLE 7 /* Rumble in Red mode */ + +#define GC_PSX_CLOCK 0x04 /* Pin 4 */ +#define GC_PSX_COMMAND 0x01 /* Pin 1 */ +#define GC_PSX_POWER 0xf8 /* Pins 5-9 */ +#define GC_PSX_SELECT 0x02 /* Pin 3 */ -#define GC_PSX_MOUSE 0x12 /* PSX Mouse */ -#define GC_PSX_NEGCON 0x23 /* NegCon pad */ -#define GC_PSX_NORMAL 0x41 /* Standard Digital controller */ -#define GC_PSX_ANALOGR 0x73 /* Analog controller in Red mode */ -#define GC_PSX_ANALOGG 0x53 /* Analog controller in Green mode */ - -#define GC_PSX_CLOCK 0x04 /* Pin 3 */ -#define GC_PSX_COMMAND 0x01 /* Pin 1 */ -#define GC_PSX_POWER 0xf8 /* Pins 5-9 */ -#define GC_PSX_SELECT 0x02 /* Pin 2 */ -#define GC_PSX_NOPOWER 0x04 +#define GC_PSX_ID(x) ((x) >> 4) /* High nibble is device type */ +#define GC_PSX_LEN(x) ((x) & 0xf) /* Low nibble is length in words */ static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y }; static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y, @@ -233,19 +240,17 @@ static int gc_psx_command(struct gc *gc, int b) { - int i, cmd, ret = 0; + int i, cmd, data = 0; - cmd = (b & 1) ? GC_PSX_COMMAND : 0; - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++, b >>= 1) { + cmd = (b & 1) ? GC_PSX_COMMAND : 0; parport_write_data(gc->pd->port, cmd | GC_PSX_POWER); udelay(GC_PSX_DELAY); - ret |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) ? (1 << i) : 0; - cmd = (b & 1) ? GC_PSX_COMMAND : 0; + data |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) ? (1 << i) : 0; parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER); udelay(GC_PSX_DELAY); - b >>= 1; } - return ret; + return data; } /* @@ -253,29 +258,31 @@ * device identifier code. */ -static int gc_psx_read_packet(struct gc *gc, int length, unsigned char *data) +static int gc_psx_read_packet(struct gc *gc, unsigned char *data) { - int i, ret; + int i, id; unsigned long flags; + parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */ + udelay(GC_PSX_DELAY * 2); + parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER); /* Deselect, begin command */ + udelay(GC_PSX_DELAY * 2); + __save_flags(flags); __cli(); - parport_write_data(gc->pd->port, GC_PSX_POWER); - - parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */ - udelay(GC_PSX_DELAY * 2); gc_psx_command(gc, 0x01); /* Access pad */ - ret = gc_psx_command(gc, 0x42); /* Get device id */ - if (gc_psx_command(gc, 0) == 'Z') /* okay? */ - for (i = 0; i < length; i++) + id = gc_psx_command(gc, 0x42); /* Get device id */ + if (gc_psx_command(gc, 0) == 0x5a) { /* Okay? */ + for (i = 0; i < GC_PSX_LEN(id) * 2; i++) data[i] = gc_psx_command(gc, 0); - else ret = -1; + } else id = 0; - parport_write_data(gc->pd->port, GC_PSX_SELECT | GC_PSX_CLOCK | GC_PSX_POWER); __restore_flags(flags); - return ret; + parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); + + return GC_PSX_ID(id); } /* @@ -316,8 +323,8 @@ input_report_abs(dev + i, ABS_X, axes[0]); input_report_abs(dev + i, ABS_Y, -axes[1]); - input_report_abs(dev + i, ABS_HAT0X, !!(s & data[7]) - !!(s & data[6])); - input_report_abs(dev + i, ABS_HAT0Y, !!(s & data[5]) - !!(s & data[4])); + input_report_abs(dev + i, ABS_HAT0X, !(s & data[6]) - !(s & data[7])); + input_report_abs(dev + i, ABS_HAT0Y, !(s & data[4]) - !(s & data[5])); for (j = 0; j < 10; j++) input_report_key(dev + i, gc_n64_btn[j], s & data[gc_n64_bytes[j]]); @@ -338,8 +345,8 @@ s = gc_status_bit[i]; if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) { - input_report_abs(dev + i, ABS_X, !!(s & data[7]) - !!(s & data[6])); - input_report_abs(dev + i, ABS_Y, !!(s & data[5]) - !!(s & data[4])); + input_report_abs(dev + i, ABS_X, ! - !(s & data[6]) - !(s & data[7])); + input_report_abs(dev + i, ABS_Y, ! - !(s & data[4]) - !(s & data[5])); } if (s & gc->pads[GC_NES]) @@ -365,8 +372,8 @@ s = gc_status_bit[i]; if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) { - input_report_abs(dev + i, ABS_X, !!(s & data[3]) - !!(s & data[2])); - input_report_abs(dev + i, ABS_Y, !!(s & data[1]) - !!(s & data[0])); + input_report_abs(dev + i, ABS_X, !(s & data[2]) - !(s & data[3])); + input_report_abs(dev + i, ABS_Y, !(s & data[0]) - !(s & data[1])); input_report_key(dev + i, BTN_TRIGGER, s & data[4]); } @@ -385,37 +392,37 @@ if (gc->pads[GC_PSX] & gc_status_bit[i]) break; - switch (gc_psx_read_packet(gc, 6, data)) { + switch (gc_psx_read_packet(gc, data)) { + + case GC_PSX_RUMBLE: + + input_report_key(dev + i, BTN_THUMB, ~data[0] & 0x04); + input_report_key(dev + i, BTN_THUMB2, ~data[0] & 0x02); + + case GC_PSX_NEGCON: + case GC_PSX_ANALOG: - case GC_PSX_ANALOGG: - for (j = 0; j < 4; j++) input_report_abs(dev + i, gc_psx_abs[j], data[j + 2]); - input_report_abs(dev + i, ABS_HAT0X, !!(data[0]&0x20) - !!(data[0]&0x80)); - input_report_abs(dev + i, ABS_HAT0Y, !!(data[0]&0x40) - !!(data[0]&0x10)); + input_report_abs(dev + i, ABS_HAT0X, !(data[0] & 0x20) - !(data[0] & 0x80)); + input_report_abs(dev + i, ABS_HAT0Y, !(data[0] & 0x40) - !(data[0] & 0x10)); for (j = 0; j < 8; j++) - input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << i)); + input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j)); input_report_key(dev + i, BTN_START, ~data[0] & 0x08); input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01); break; - case GC_PSX_ANALOGR: - - input_report_key(dev + i, BTN_THUMB, ~data[0] & 0x04); - input_report_key(dev + i, BTN_THUMB2, ~data[0] & 0x02); - case GC_PSX_NORMAL: - case GC_PSX_NEGCON: - input_report_abs(dev + i, ABS_X, 128 + !!(data[0] & 0x20) * 127 - !!(data[0] & 0x80) * 128); - input_report_abs(dev + i, ABS_Y, 128 + !!(data[0] & 0x40) * 127 - !!(data[0] & 0x10) * 128); + input_report_abs(dev + i, ABS_X, 128 + !(data[0] & 0x20) * 127 - !(data[0] & 0x80) * 128); + input_report_abs(dev + i, ABS_Y, 128 + !(data[0] & 0x40) * 127 - !(data[0] & 0x10) * 128); for (j = 0; j < 8; j++) - input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << i)); + input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j)); input_report_key(dev + i, BTN_START, ~data[0] & 0x08); input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01); @@ -448,14 +455,12 @@ } } - - static struct gc __init *gc_probe(int *config) { struct gc *gc; struct parport *pp; - int i, j, psx, pbtn; - unsigned char data[2]; + int i, j, psx; + unsigned char data[32]; if (config[0] < 0) return NULL; @@ -545,44 +550,42 @@ case GC_PSX: - psx = gc_psx_read_packet(gc, 2, data); + psx = gc_psx_read_packet(gc, data); switch(psx) { case GC_PSX_NEGCON: - config[i + 1] += 1; case GC_PSX_NORMAL: - pbtn = 10; - break; + case GC_PSX_ANALOG: + case GC_PSX_RUMBLE: - case GC_PSX_ANALOGG: - case GC_PSX_ANALOGR: - config[i + 1] += 2; - pbtn = 12; for (j = 0; j < 6; j++) { psx = gc_psx_abs[j]; set_bit(psx, gc->dev[i].absbit); - gc->dev[i].absmin[psx] = 4; - gc->dev[i].absmax[psx] = 252; - gc->dev[i].absflat[psx] = 2; + if (j < 4) { + gc->dev[i].absmin[psx] = 4; + gc->dev[i].absmax[psx] = 252; + gc->dev[i].absflat[psx] = 2; + } else { + gc->dev[i].absmin[psx] = -1; + gc->dev[i].absmax[psx] = 1; + } } + + for (j = 0; j < 12; j++) + set_bit(gc_psx_btn[j], gc->dev[i].keybit); + break; - case -1: + case 0: gc->pads[GC_PSX] &= ~gc_status_bit[i]; - pbtn = 0; printk(KERN_ERR "gamecon.c: No PSX controller found.\n"); break; default: gc->pads[GC_PSX] &= ~gc_status_bit[i]; - pbtn = 0; printk(KERN_WARNING "gamecon.c: Unsupported PSX controller %#x," " please report to <vojtech@suse.cz>.\n", psx); } - - for (j = 0; j < pbtn; j++) - set_bit(gc_psx_btn[j], gc->dev[i].keybit); - break; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/joystick/iforce.c linux.ac/drivers/char/joystick/iforce.c --- linux.vanilla/drivers/char/joystick/iforce.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/char/joystick/iforce.c Thu Apr 12 12:02:00 2001 @@ -33,6 +33,7 @@ #include <linux/input.h> #include <linux/module.h> #include <linux/init.h> +#include <linux/spinlock.h> #include <linux/usb.h> #include <linux/serio.h> #include <linux/config.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/joystick/ns558.c linux.ac/drivers/char/joystick/ns558.c --- linux.vanilla/drivers/char/joystick/ns558.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/char/joystick/ns558.c Thu Apr 12 12:02:00 2001 @@ -1,5 +1,5 @@ /* - * $Id: ns558.c,v 1.16 2000/08/17 20:03:56 vojtech Exp $ + * $Id: ns558.c,v 1.27 2001/03/28 09:25:05 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * Copyright (c) 1999 Brian Gerst @@ -47,7 +47,7 @@ #define NS558_PNP 2 #define NS558_PCI 3 -static int ns558_isa_portlist[] = { 0x201, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209, +static int ns558_isa_portlist[] = { 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209, 0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 }; struct ns558 { @@ -230,26 +230,30 @@ /* * PnP IDs: * + * @P@0001 - ALS 100 (no comp. ID) * CTL00c1 - SB AWE32 PnP * CTL00c3 - SB AWE64 PnP * CTL00f0 - SB16 PnP / Vibra 16x - * CTL7001 - SB Vibra16C PnP - * CSC0b35 - Crystal ** doesn't have compatibility ID ** + * CTL7001 - SB Vibra16C PnP (no comp. ID) + * CTL7002 - SB AWE32 (no comp. ID) + * CSC0b35 - Crystal (no comp. ID) * TER1141 - Terratec AD1818 * YMM0800 - Yamaha OPL3-SA3 * * PNPb02f - Generic gameport */ -static struct pnp_devid { - unsigned int vendor, device; -} pnp_devids[] = { - { ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7002) }, - { ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0b35) }, - { ISAPNP_VENDOR('P','N','P'), ISAPNP_DEVICE(0xb02f) }, +static struct isapnp_device_id pnp_devids[] = { + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('@','P','@'), ISAPNP_DEVICE(0x0001), 0 }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7001), 0 }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7002), 0 }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0b35), 0 }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P','N','P'), ISAPNP_DEVICE(0xb02f), 0 }, { 0, }, }; +MODULE_DEVICE_TABLE(isapnp, pnp_devids); + static struct ns558* ns558_pnp_probe(struct pci_dev *dev, struct ns558 *next) { int ioport, iolen; @@ -306,7 +310,7 @@ int i = 0; #ifdef NSS558_ISAPNP struct pci_dev *dev = NULL; - struct pnp_devid *devid; + struct isapnp_device_id *devid; #endif /* @@ -329,7 +333,7 @@ #ifdef NSS558_ISAPNP for (devid = pnp_devids; devid->vendor; devid++) { - while ((dev = isapnp_find_dev(NULL, devid->vendor, devid->device, dev))) { + while ((dev = isapnp_find_dev(NULL, devid->vendor, devid->function, dev))) { ns558 = ns558_pnp_probe(dev, ns558); } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/joystick/sidewinder.c linux.ac/drivers/char/joystick/sidewinder.c --- linux.vanilla/drivers/char/joystick/sidewinder.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/char/joystick/sidewinder.c Thu Apr 12 12:02:00 2001 @@ -1,5 +1,5 @@ /* - * $Id: sidewinder.c,v 1.16 2000/07/14 09:02:41 vojtech Exp $ + * $Id: sidewinder.c,v 1.18 2001/02/28 07:09:30 vojtech Exp $ * * Copyright (c) 1998-2000 Vojtech Pavlik * @@ -334,7 +334,7 @@ input_report_abs(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1)); for (j = 0; j < 10; j++) - input_report_key(dev, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1)); + input_report_key(dev + i, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1)); } return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/joystick/spaceball.c linux.ac/drivers/char/joystick/spaceball.c --- linux.vanilla/drivers/char/joystick/spaceball.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/char/joystick/spaceball.c Thu Apr 12 12:02:00 2001 @@ -1,5 +1,5 @@ /* - * $Id: spaceball.c,v 1.7 2000/06/24 11:55:40 vojtech Exp $ + * $Id: spaceball.c,v 1.8 2000/11/23 11:42:39 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * @@ -108,10 +108,8 @@ /* * Spaceball 4000 FLX packets all start with a one letter packet-type decriptor, - * and end in 0x0d. It uses '^' as an escape for 0x0d characters which can - * occur in the axis values. ^M, ^Q and ^S all mean 0x0d, depending (I think) - * on whether the axis value is increasing, decreasing, or same as before. - * (I don't see why this is useful). + * and end in 0x0d. It uses '^' as an escape for CR, XOFF and XON characters which + * can occur in the axis values. */ static void spaceball_interrupt(struct serio *serio, unsigned char data, unsigned int flags) @@ -126,7 +124,7 @@ return; case '^': if (!spaceball->escape) { - spaceball->escape ^= 1; + spaceball->escape = 1; return; } spaceball->escape = 0; @@ -135,7 +133,7 @@ case 'S': if (spaceball->escape) { spaceball->escape = 0; - data = 0xd; + data &= 0x1f; } default: if (spaceball->escape) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/joystick/stinger.c linux.ac/drivers/char/joystick/stinger.c --- linux.vanilla/drivers/char/joystick/stinger.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/char/joystick/stinger.c Thu Apr 12 12:02:00 2001 @@ -0,0 +1,200 @@ +/* + * $Id: stinger.c,v 1.1 2000/07/17 10:42:14 vojtech Exp $ + * + * Copyright (c) 2000 Vojtech Pavlik + * Copyright (c) 2000 Mark Fletcher + * + * Sponsored by SuSE + */ + +/* + * Gravis Stinger gamepad driver for Linux + */ + +/* + * This program is free warftware; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <linux/serio.h> +#include <linux/init.h> + +/* + * Constants. + */ + +#define STINGER_MAX_LENGTH 8 + +static char *stinger_name = "Gravis Stinger"; + +/* + * Per-Stinger data. + */ + +struct stinger { + struct input_dev dev; + int idx; + unsigned char data[STINGER_MAX_LENGTH]; +}; + +/* + * stinger_process_packet() decodes packets the driver receives from the + * Stinger. It updates the data accordingly. + */ + +static void stinger_process_packet(struct stinger *stinger) +{ + struct input_dev *dev = &stinger->dev; + unsigned char *data = stinger->data; + + if (!stinger->idx) return; + + input_report_key(dev, BTN_A, ((data[0] & 0x20) >> 5)); + input_report_key(dev, BTN_B, ((data[0] & 0x10) >> 4)); + input_report_key(dev, BTN_C, ((data[0] & 0x08) >> 3)); + input_report_key(dev, BTN_X, ((data[0] & 0x04) >> 2)); + input_report_key(dev, BTN_Y, ((data[3] & 0x20) >> 5)); + input_report_key(dev, BTN_Z, ((data[3] & 0x10) >> 4)); + input_report_key(dev, BTN_TL, ((data[3] & 0x08) >> 3)); + input_report_key(dev, BTN_TR, ((data[3] & 0x04) >> 2)); + input_report_key(dev, BTN_SELECT, ((data[3] & 0x02) >> 1)); + input_report_key(dev, BTN_START, (data[3] & 0x01)); + + input_report_abs(dev, ABS_X, ((data[1] & 0x3F) - ((data[0] & 0x01) << 6))); + input_report_abs(dev, ABS_Y, ((data[2] & 0x3F) - ((data[0] & 0x02) << 5))); + + return; +} + +/* + * stinger_interrupt() is called by the low level driver when characters + * are ready for us. We then buffer them for further processing, or call the + * packet processing routine. + */ + +static void stinger_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct stinger* stinger = serio->private; + + /* All Stinger packets are 4 bytes */ + + if (stinger->idx < STINGER_MAX_LENGTH) + stinger->data[stinger->idx++] = data; + + if (stinger->idx == 4) { + stinger_process_packet(stinger); + stinger->idx = 0; + } + + return; +} + +/* + * stinger_disconnect() is the opposite of stinger_connect() + */ + +static void stinger_disconnect(struct serio *serio) +{ + struct stinger* stinger = serio->private; + input_unregister_device(&stinger->dev); + serio_close(serio); + kfree(stinger); +} + +/* + * stinger_connect() is the routine that is called when someone adds a + * new serio device. It looks for the Stinger, and if found, registers + * it as an input device. + */ + +static void stinger_connect(struct serio *serio, struct serio_dev *dev) +{ + struct stinger *stinger; + int i; + + if (serio->type != (SERIO_RS232 | SERIO_STINGER)) + return; + + if (!(stinger = kmalloc(sizeof(struct stinger), GFP_KERNEL))) + return; + + memset(stinger, 0, sizeof(struct stinger)); + + stinger->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + stinger->dev.keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) | \ + BIT(BTN_Y) | BIT(BTN_Z) | BIT(BTN_TL) | BIT(BTN_TR) | \ + BIT(BTN_START) | BIT(BTN_SELECT); + stinger->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + + stinger->dev.name = stinger_name; + stinger->dev.idbus = BUS_RS232; + stinger->dev.idvendor = SERIO_STINGER; + stinger->dev.idproduct = 0x0001; + stinger->dev.idversion = 0x0100; + + for (i = 0; i < 2; i++) { + stinger->dev.absmax[ABS_X+i] = 64; + stinger->dev.absmin[ABS_X+i] = -64; + stinger->dev.absflat[ABS_X+i] = 4; + } + + stinger->dev.private = stinger; + + serio->private = stinger; + + if (serio_open(serio, dev)) { + kfree(stinger); + return; + } + + input_register_device(&stinger->dev); + + printk(KERN_INFO "input%d: %s on serio%d\n", stinger->dev.number, stinger_name, serio->number); +} + +/* + * The serio device structure. + */ + +static struct serio_dev stinger_dev = { + interrupt: stinger_interrupt, + connect: stinger_connect, + disconnect: stinger_disconnect, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +int __init stinger_init(void) +{ + serio_register_device(&stinger_dev); + return 0; +} + +void __exit stinger_exit(void) +{ + serio_unregister_device(&stinger_dev); +} + +module_init(stinger_init); +module_exit(stinger_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/joystick/tmdc.c linux.ac/drivers/char/joystick/tmdc.c --- linux.vanilla/drivers/char/joystick/tmdc.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/char/joystick/tmdc.c Thu Apr 12 12:02:00 2001 @@ -1,5 +1,5 @@ /* - * $Id: tmdc.c,v 1.18 2000/06/08 19:59:59 vojtech Exp $ + * $Id: tmdc.c,v 1.23 2000/11/29 19:52:24 vojtech Exp $ * * Copyright (c) 1998-2000 Vojtech Pavlik * @@ -49,6 +49,8 @@ #define TMDC_MODE_M3DI 1 #define TMDC_MODE_3DRP 3 +#define TMDC_MODE_AT 4 +#define TMDC_MODE_FM 8 #define TMDC_MODE_FGP 163 #define TMDC_BYTE_ID 10 @@ -57,21 +59,35 @@ #define TMDC_ABS 7 #define TMDC_ABS_HAT 4 -#define TMDC_BTN_PAD 10 -#define TMDC_BTN_JOY 16 +#define TMDC_BTN 16 static unsigned char tmdc_byte_a[16] = { 0, 1, 3, 4, 6, 7 }; static unsigned char tmdc_byte_d[16] = { 2, 5, 8, 9 }; -static unsigned char tmdc_abs[TMDC_ABS] = +static signed char tmdc_abs[TMDC_ABS] = { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE, ABS_RX, ABS_RY, ABS_RZ }; -static unsigned char tmdc_abs_hat[TMDC_ABS_HAT] = +static signed char tmdc_abs_hat[TMDC_ABS_HAT] = { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y }; -static unsigned short tmdc_btn_pad[TMDC_BTN_PAD] = +static signed char tmdc_abs_at[TMDC_ABS] = + { ABS_X, ABS_Y, ABS_RUDDER, -1, ABS_THROTTLE }; +static signed char tmdc_abs_fm[TMDC_ABS] = + { ABS_RX, ABS_RY, ABS_X, ABS_Y }; + +static short tmdc_btn_pad[TMDC_BTN] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR }; -static unsigned short tmdc_btn_joy[TMDC_BTN_JOY] = +static short tmdc_btn_joy[TMDC_BTN] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE, BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z }; +static short tmdc_btn_fm[TMDC_BTN] = + { BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 }; +static short tmdc_btn_at[TMDC_BTN] = + { BTN_TRIGGER, BTN_THUMB2, BTN_PINKIE, BTN_THUMB, BTN_BASE6, BTN_BASE5, BTN_BASE4, + BTN_BASE3, BTN_BASE2, BTN_BASE }; + +static struct { + int x; + int y; +} tmdc_hat_to_axis[] = {{ 0, 0}, { 1, 0}, { 0,-1}, {-1, 0}, { 0, 1}}; struct tmdc { struct gameport *gameport; @@ -79,6 +95,11 @@ struct input_dev dev[2]; char name[2][64]; int mode[2]; + signed char *abs[2]; + short *btn[2]; + unsigned char absc[2]; + unsigned char btnc[2][4]; + unsigned char btno[2][4]; int used; int reads; int bads; @@ -145,7 +166,7 @@ struct tmdc *tmdc = (void *) private; struct input_dev *dev; unsigned char r, bad = 0; - int i, j; + int i, j, k, l; tmdc->reads++; @@ -162,44 +183,34 @@ dev = tmdc->dev + j; - for (i = 0; i < data[j][TMDC_BYTE_DEF] >> 4; i++) - input_report_abs(dev, tmdc_abs[i], data[j][tmdc_byte_a[i]]); + for (i = 0; i < tmdc->absc[j]; i++) { + if (tmdc->abs[j][i] < 0) continue; + input_report_abs(dev, tmdc->abs[j][i], data[j][tmdc_byte_a[i]]); + } switch (tmdc->mode[j]) { case TMDC_MODE_M3DI: i = tmdc_byte_d[0]; - input_report_abs(dev, ABS_HAT0X, ((data[j][i] >> 3) & 1) - ((data[j][i] >> 1) & 1)); input_report_abs(dev, ABS_HAT0Y, ((data[j][i] >> 2) & 1) - ( data[j][i] & 1)); - - for (i = 0; i < 4; i++) - input_report_key(dev, tmdc_btn_joy[i], - (data[j][tmdc_byte_d[0]] >> (i + 4)) & 1); - for (i = 0; i < 2; i++) - input_report_key(dev, tmdc_btn_joy[i + 4], - (data[j][tmdc_byte_d[1]] >> (i + 6)) & 1); - break; - case TMDC_MODE_3DRP: - case TMDC_MODE_FGP: - - for (i = 0; i < 10; i++) - input_report_key(dev, tmdc_btn_pad[i], - (data[j][tmdc_byte_d[i >> 3]] >> (i & 7)) & 1); + case TMDC_MODE_AT: + i = tmdc_byte_a[3]; + input_report_abs(dev, ABS_HAT0X, tmdc_hat_to_axis[(data[j][i] - 141) / 25].x); + input_report_abs(dev, ABS_HAT0Y, tmdc_hat_to_axis[(data[j][i] - 141) / 25].y); break; - default: - - for (i = 0; i < ((data[j][TMDC_BYTE_DEF] & 0xf) << 3) && i < TMDC_BTN_JOY; i++) - input_report_key(dev, tmdc_btn_joy[i], - (data[j][tmdc_byte_d[i >> 3]] >> (i & 7)) & 1); - - break; + } + for (k = l = 0; k < 4; k++) { + for (i = 0; i < tmdc->btnc[j][k]; i++) + input_report_key(dev, tmdc->btn[j][i + l], + ((data[j][tmdc_byte_d[k]] >> (i + tmdc->btno[j][k])) & 1)); + l += tmdc->btnc[j][k]; } } @@ -229,20 +240,25 @@ static void tmdc_connect(struct gameport *gameport, struct gameport_dev *dev) { - struct tmdc *tmdc; - struct js_tm_models { + struct models { unsigned char id; char *name; char abs; char hats; - char joybtn; - char padbtn; - } models[] = { { 1, "ThrustMaster Millenium 3D Inceptor", 6, 0, 6, 0 }, - { 3, "ThrustMaster Rage 3D Gamepad", 2, 0, 0, 10 }, - { 163, "Thrustmaster Fusion GamePad", 2, 0, 0, 10 }, - { 0, "Unknown %d-axis, %d-button TM device %d", 0, 0, 0, 0 }}; + char btnc[4]; + char btno[4]; + signed char *axes; + short *buttons; + } models[] = { { 1, "ThrustMaster Millenium 3D Inceptor", 6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy }, + { 3, "ThrustMaster Rage 3D Gamepad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, + { 4, "ThrustMaster Attack Throttle", 5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at }, + { 8, "ThrustMaster FragMaster", 4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm }, + { 163, "Thrustmaster Fusion GamePad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, + { 0, "Unknown %d-axis, %d-button TM device %d", 0, 0, { 0, 0 }, { 0, 0 }, tmdc_abs, tmdc_btn_joy }}; + unsigned char data[2][TMDC_MAX_LENGTH]; - int i, j, m; + struct tmdc *tmdc; + int i, j, k, l, m; if (!(tmdc = kmalloc(sizeof(struct tmdc), GFP_KERNEL))) return; @@ -268,12 +284,23 @@ for (m = 0; models[m].id && models[m].id != tmdc->mode[j]; m++); + tmdc->abs[j] = models[m].axes; + tmdc->btn[j] = models[m].buttons; + if (!models[m].id) { models[m].abs = data[j][TMDC_BYTE_DEF] >> 4; - models[m].joybtn = (data[j][TMDC_BYTE_DEF] & 0xf) << 3; + for (k = 0; k < 4; k++) + models[m].btnc[k] = k < (data[j][TMDC_BYTE_DEF] & 0xf) ? 8 : 0; } - sprintf(tmdc->name[j], models[m].name, models[m].abs, models[m].joybtn, tmdc->mode[j]); + tmdc->absc[j] = models[m].abs; + for (k = 0; k < 4; k++) { + tmdc->btnc[j][k] = models[m].btnc[k]; + tmdc->btno[j][k] = models[m].btno[k]; + } + + sprintf(tmdc->name[j], models[m].name, models[m].abs, + (data[j][TMDC_BYTE_DEF] & 0xf) << 3, tmdc->mode[j]); tmdc->dev[j].private = tmdc; tmdc->dev[j].open = tmdc_open; @@ -288,11 +315,12 @@ tmdc->dev[j].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; i < models[m].abs && i < TMDC_ABS; i++) { - set_bit(tmdc_abs[i], tmdc->dev[j].absbit); - tmdc->dev[j].absmin[tmdc_abs[i]] = 8; - tmdc->dev[j].absmax[tmdc_abs[i]] = 248; - tmdc->dev[j].absfuzz[tmdc_abs[i]] = 2; - tmdc->dev[j].absflat[tmdc_abs[i]] = 4; + if (tmdc->abs[i] < 0) continue; + set_bit(tmdc->abs[j][i], tmdc->dev[j].absbit); + tmdc->dev[j].absmin[tmdc->abs[j][i]] = 8; + tmdc->dev[j].absmax[tmdc->abs[j][i]] = 248; + tmdc->dev[j].absfuzz[tmdc->abs[j][i]] = 2; + tmdc->dev[j].absflat[tmdc->abs[j][i]] = 4; } for (i = 0; i < models[m].hats && i < TMDC_ABS_HAT; i++) { @@ -301,11 +329,11 @@ tmdc->dev[j].absmax[tmdc_abs_hat[i]] = 1; } - for (i = 0; i < models[m].joybtn && i < TMDC_BTN_JOY; i++) - set_bit(tmdc_btn_joy[i], tmdc->dev[j].keybit); - - for (i = 0; i < models[m].padbtn && i < TMDC_BTN_PAD; i++) - set_bit(tmdc_btn_pad[i], tmdc->dev[j].keybit); + for (k = l = 0; k < 4; k++) { + for (i = 0; i < models[m].btnc[k] && i < TMDC_BTN; i++) + set_bit(tmdc->btn[j][i + l], tmdc->dev[j].keybit); + l += models[m].btnc[k]; + } input_register_device(tmdc->dev + j); printk(KERN_INFO "input%d: %s on gameport%d.%d\n", diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/keyboard.c linux.ac/drivers/char/keyboard.c --- linux.vanilla/drivers/char/keyboard.c Mon Oct 16 20:58:51 2000 +++ linux.ac/drivers/char/keyboard.c Tue Apr 3 17:54:40 2001 @@ -205,15 +205,12 @@ char raw_mode; pm_access(pm_kbd); - - do_poke_blanked_console = 1; - tasklet_schedule(&console_tasklet); add_keyboard_randomness(scancode | up_flag); tty = ttytab? ttytab[fg_console]: NULL; if (tty && (!tty->driver_data)) { /* - * We touch the tty structure via the the ttytab array + * We touch the tty structure via the ttytab array * without knowing whether or not tty is open, which * is inherently dangerous. We currently rely on that * fact that console_open sets tty->driver_data when @@ -233,7 +230,7 @@ * Convert scancode to keycode */ if (!kbd_translate(scancode, &keycode, raw_mode)) - return; + goto out; /* * At this point the variable `keycode' contains the keycode. @@ -252,11 +249,11 @@ #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ if (keycode == SYSRQ_KEY) { sysrq_pressed = !up_flag; - return; + goto out; } else if (sysrq_pressed) { if (!up_flag) { handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty); - return; + goto out; } } #endif @@ -298,7 +295,7 @@ if (type >= 0xf0) { type -= 0xf0; if (raw_mode && ! (TYPES_ALLOWED_IN_RAW_MODE & (1 << type))) - return; + goto out; if (type == KT_LETTER) { type = KT_LATIN; if (vc_kbd_led(kbd, VC_CAPSLOCK)) { @@ -322,13 +319,16 @@ compute_shiftstate(); kbd->slockstate = 0; /* play it safe */ #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); #endif } } +out: + do_poke_blanked_console = 1; + schedule_console_callback(); } @@ -750,7 +750,7 @@ k = i*BITS_PER_LONG; for(j=0; j<BITS_PER_LONG; j++,k++) if(test_bit(k, key_down)) { - sym = U(plain_map[k]); + sym = U(key_maps[0][k]); if(KTYP(sym) == KT_SHIFT || KTYP(sym) == KT_SLOCK) { val = KVAL(sym); if (val == KVAL(K_CAPSSHIFT)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/lp.c linux.ac/drivers/char/lp.c --- linux.vanilla/drivers/char/lp.c Tue Apr 3 17:32:01 2001 +++ linux.ac/drivers/char/lp.c Tue Apr 3 17:56:33 2001 @@ -141,6 +141,17 @@ /* ROUND_UP macro from fs/select.c */ #define ROUND_UP(x,y) (((x)+(y)-1)/(y)) +/* printer_ieee1284_id is declared as its own variable so that it + can be in the __initdata section. */ +static __initdata char printer_ieee1284_id[] = "CLS:PRINTER"; + +static __initdata struct parport_device_id printer_id_tbl[] = { + { printer_ieee1284_id }, + { } +}; + +MODULE_DEVICE_TABLE(parport, printer_id_tbl); + static devfs_handle_t devfs_handle = NULL; struct lp_struct lp_table[LP_NO]; @@ -539,7 +550,7 @@ * non-zero to get the latter behaviour. */ #define CONSOLE_LP_STRICT 1 -/* The console_lock must be held when we get here. */ +/* The console must be locked when we get here. */ static void lp_console_write (struct console *co, const char *s, unsigned count) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/machzwd.c linux.ac/drivers/char/machzwd.c --- linux.vanilla/drivers/char/machzwd.c Tue Apr 3 17:32:01 2001 +++ linux.ac/drivers/char/machzwd.c Tue Apr 3 17:54:40 2001 @@ -26,6 +26,7 @@ * */ +#include <linux/config.h> #include <linux/module.h> #include <linux/version.h> #include <linux/types.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/mem.c linux.ac/drivers/char/mem.c --- linux.vanilla/drivers/char/mem.c Tue Apr 3 17:32:01 2001 +++ linux.ac/drivers/char/mem.c Mon Apr 9 23:36:59 2001 @@ -41,6 +41,9 @@ #ifdef CONFIG_MDA_CONSOLE extern void mda_console_init(void); #endif +#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR) +extern void tapechar_init(void); +#endif #if defined(CONFIG_ADB) extern void adbdev_init(void); #endif @@ -639,6 +642,9 @@ #endif #ifdef CONFIG_FTAPE ftape_init(); +#endif +#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR) + tapechar_init(); #endif #if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR) tapechar_init(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/misc.c linux.ac/drivers/char/misc.c --- linux.vanilla/drivers/char/misc.c Tue Apr 3 17:32:01 2001 +++ linux.ac/drivers/char/misc.c Tue Apr 3 17:54:40 2001 @@ -73,10 +73,8 @@ extern int rtc_DP8570A_init(void); extern int rtc_MK48T08_init(void); extern int ds1286_init(void); -extern int dsp56k_init(void); extern int radio_init(void); extern int pmu_device_init(void); -extern int qpmouse_init(void); extern int tosh_init(void); static int misc_read_proc(char *buf, char **start, off_t offset, @@ -173,10 +171,20 @@ int misc_register(struct miscdevice * misc) { static devfs_handle_t devfs_handle; - + struct miscdevice *c; + if (misc->next || misc->prev) return -EBUSY; down(&misc_sem); + c = misc_list.next; + + while ((c != &misc_list) && (c->minor != misc->minor)) + c = c->next; + if (c != &misc_list) { + up(&misc_sem); + return -EBUSY; + } + if (misc->minor == MISC_DYNAMIC_MINOR) { int i = DYNAMIC_MINORS; while (--i >= 0) @@ -245,9 +253,6 @@ int __init misc_init(void) { create_proc_read_entry("misc", 0, 0, misc_read_proc, NULL); -#if defined CONFIG_82C710_MOUSE - qpmouse_init(); -#endif #ifdef CONFIG_MVME16x rtc_MK48T08_init(); #endif @@ -256,9 +261,6 @@ #endif #ifdef CONFIG_SGI_DS1286 ds1286_init(); -#endif -#ifdef CONFIG_ATARI_DSP56K - dsp56k_init(); #endif #ifdef CONFIG_MISC_RADIO radio_init(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/n_r3964.c linux.ac/drivers/char/n_r3964.c --- linux.vanilla/drivers/char/n_r3964.c Fri Feb 9 19:30:22 2001 +++ linux.ac/drivers/char/n_r3964.c Tue Apr 10 18:13:56 2001 @@ -7,7 +7,7 @@ * http://www.pap-philips.de * ----------------------------------------------------------- * This software may be used and distributed according to the terms of - * the GNU Public License, incorporated herein by reference. + * the GNU General Public License, incorporated herein by reference. * * Author: * L. Haag @@ -65,7 +65,7 @@ //#define DEBUG_QUEUE -/* Log successfull handshake and protocol operations */ +/* Log successful handshake and protocol operations */ //#define DEBUG_PROTO_S /* Log handshake and protocol errors: */ @@ -983,13 +983,14 @@ { queue_the_message: - save_flags(flags); - cli(); - pMsg = kmalloc(sizeof(struct r3964_message), GFP_KERNEL); TRACE_M("add_msg - kmalloc %x",(int)pMsg); - if(pMsg==NULL) + if(pMsg==NULL) { return; + } + + save_flags(flags); + cli(); pMsg->msg_id = msg_id; pMsg->arg = arg; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/n_tty.c linux.ac/drivers/char/n_tty.c --- linux.vanilla/drivers/char/n_tty.c Fri Feb 9 19:30:22 2001 +++ linux.ac/drivers/char/n_tty.c Tue Apr 10 18:13:56 2001 @@ -15,7 +15,7 @@ * This file also contains code originally written by Linus Torvalds, * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994. * - * This file may be redistributed under the terms of the GNU Public + * This file may be redistributed under the terms of the GNU General Public * License. * * Reduced memory usage for older ARM systems - Russell King. @@ -100,7 +100,7 @@ unsigned long flags; /* * The problem of stomping on the buffers ends here. - * Why didn't anyone see this one comming? --AJK + * Why didn't anyone see this one coming? --AJK */ spin_lock_irqsave(&tty->read_lock, flags); put_tty_queue_nolock(c, tty); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/pc_keyb.c linux.ac/drivers/char/pc_keyb.c --- linux.vanilla/drivers/char/pc_keyb.c Tue Apr 3 17:32:01 2001 +++ linux.ac/drivers/char/pc_keyb.c Tue Apr 10 18:14:10 2001 @@ -1016,6 +1016,8 @@ misc_register(&psaux_mouse); queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); + if (queue == NULL) + panic("psaux_init(): out of memory"); memset(queue, 0, sizeof(*queue)); queue->head = queue->tail = 0; init_waitqueue_head(&queue->proc_list); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/pcwd.c linux.ac/drivers/char/pcwd.c --- linux.vanilla/drivers/char/pcwd.c Fri Feb 9 19:30:22 2001 +++ linux.ac/drivers/char/pcwd.c Tue Apr 10 18:14:09 2001 @@ -462,8 +462,8 @@ outb_p(0xA5, current_readport + 3); spin_unlock(&io_lock); } - unlock_kernel(); #endif + unlock_kernel(); } return 0; } @@ -502,7 +502,7 @@ static inline char *get_firmware(void) { - int i, found = 0, count = 0, one, ten, hund, minor; + int i, found = 0, count = 0, one = 0, ten = 0, hund = 0, minor = 0; char *ret; ret = kmalloc(6, GFP_KERNEL); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/qpmouse.c linux.ac/drivers/char/qpmouse.c --- linux.vanilla/drivers/char/qpmouse.c Fri Feb 9 19:30:22 2001 +++ linux.ac/drivers/char/qpmouse.c Tue Apr 3 17:54:40 2001 @@ -24,9 +24,8 @@ */ #include <linux/module.h> - -#include <linux/sched.h> #include <linux/kernel.h> +#include <linux/sched.h> #include <linux/interrupt.h> #include <linux/fcntl.h> #include <linux/errno.h> @@ -146,11 +145,11 @@ fasync_qp(-1, file, 0); if (!--qp_count) { if (!poll_qp_status()) - printk("Warning: Mouse device busy in release_qp()\n"); + printk(KERN_WARNING "Warning: Mouse device busy in release_qp()\n"); status = inb_p(qp_status); outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status); if (!poll_qp_status()) - printk("Warning: Mouse device busy in release_qp()\n"); + printk(KERN_WARNING "Warning: Mouse device busy in release_qp()\n"); free_irq(QP_IRQ, NULL); } unlock_kernel(); @@ -188,7 +187,7 @@ outb_p(status, qp_status); /* Enable interrupts */ while (!poll_qp_status()) { - printk("Error: Mouse device busy in open_qp()\n"); + printk(KERN_ERR "Error: Mouse device busy in open_qp()\n"); qp_count--; status &= ~(QP_ENABLE|QP_INTS_ON); outb_p(status, qp_status); @@ -303,7 +302,9 @@ * Initialize driver. */ static struct miscdevice qp_mouse = { - PSMOUSE_MINOR, "QPmouse", &qp_fops + minor: PSMOUSE_MINOR, + name: "QPmouse", + fops: &qp_fops, }; /* @@ -337,37 +338,36 @@ return 1; } -int __init qpmouse_init(void) +static const char msg_banner[] __initdata = KERN_INFO "82C710 type pointing device detected -- driver installed.\n"; +static const char msg_nomem[] __initdata = KERN_ERR "qpmouse: no queue memory.\n"; + +static int __init qpmouse_init_driver(void) { if (!probe_qp()) return -EIO; - printk(KERN_INFO "82C710 type pointing device detected -- driver installed.\n"); + printk(msg_banner); + /* 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"); + if (queue == NULL) { + printk(msg_nomem); return -ENOMEM; - } + } qp_present = 1; misc_register(&qp_mouse); memset(queue, 0, sizeof(*queue)); queue->head = queue->tail = 0; init_waitqueue_head(&queue->proc_list); - return 0; } -#ifdef MODULE -int init_module(void) -{ - return qpmouse_init(); -} - -void cleanup_module(void) +static void __exit qpmouse_exit_driver(void) { misc_deregister(&qp_mouse); kfree(queue); } -#endif + +module_init(qpmouse_init_driver); +module_exit(qpmouse_exit_driver); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/qtronix.c linux.ac/drivers/char/qtronix.c --- linux.vanilla/drivers/char/qtronix.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/char/qtronix.c Tue Apr 3 17:54:40 2001 @@ -0,0 +1,597 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Qtronix 990P infrared keyboard driver. + * + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.com + * + * + * The bottom portion of this driver was take from + * pc_keyb.c Please see that file for copyrights. + * + * 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 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. + * + * 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 <linux/config.h> + +/* + * NOTE: + * + * This driver has only been tested with the Consumer IR + * port of the ITE 8172 system controller. + * + * You do not need this driver if you are using the ps/2 or + * USB adapter that the keyboard ships with. You only need + * this driver if your board has a IR port and the keyboard + * data is being sent directly to the IR. In that case, + * you also need some low-level IR support. See it8172_cir.c. + * + */ + +#ifdef CONFIG_QTRONIX_KEYBOARD + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> + +#include <asm/it8172/it8172.h> +#include <asm/it8172/it8172_int.h> +#include <asm/it8172/it8172_cir.h> + +#include <linux/spinlock.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/mm.h> +#include <linux/signal.h> +#include <linux/init.h> +#include <linux/kbd_ll.h> +#include <linux/delay.h> +#include <linux/random.h> +#include <linux/poll.h> +#include <linux/miscdevice.h> +#include <linux/malloc.h> +#include <linux/kbd_kern.h> +#include <linux/smp_lock.h> +#include <asm/io.h> +#include <linux/pc_keyb.h> + +#include <asm/keyboard.h> +#include <asm/bitops.h> +#include <asm/uaccess.h> +#include <asm/irq.h> +#include <asm/system.h> + +#define leading1 0 +#define leading2 0xF + +#define KBD_CIR_PORT 0 +#define AUX_RECONNECT 170 /* scancode when ps2 device is plugged (back) in */ + +static int data_index; +struct cir_port *cir; +static unsigned char kbdbytes[5]; +static unsigned char cir_data[32]; /* we only need 16 chars */ + +static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs); +static int handle_data(unsigned char *p_data); +static inline void handle_mouse_event(unsigned char scancode); +static inline void handle_keyboard_event(unsigned char scancode, int down); +static int __init psaux_init(void); + +static struct aux_queue *queue; /* Mouse data buffer. */ +static int aux_count = 0; + +/* + * Keys accessed through the 'Fn' key + * The Fn key does not produce a key-up sequence. So, the first + * time the user presses it, it will be key-down event. The key + * stays down until the user presses it again. + */ +#define NUM_FN_KEYS 56 +static unsigned char fn_keys[NUM_FN_KEYS] = { + 0,0,0,0,0,0,0,0, /* 0 7 */ + 8,9,10,93,0,0,0,0, /* 8 15 */ + 0,0,0,0,0,0,0,5, /* 16 23 */ + 6,7,91,0,0,0,0,0, /* 24 31 */ + 0,0,0,0,0,2,3,4, /* 32 39 */ + 92,0,0,0,0,0,0,0, /* 40 47 */ + 0,0,0,0,11,0,94,95 /* 48 55 */ + +}; + +void init_qtronix_990P_kbd(void) +{ + int retval; + + cir = (struct cir_port *)kmalloc(sizeof(struct cir_port), GFP_KERNEL); + if (!cir) { + printk("Unable to initialize Qtronix keyboard\n"); + return; + } + + /* + * revisit + * this should be programmable, somehow by the, by the user. + */ + cir->port = KBD_CIR_PORT; + cir->baud_rate = 0x1d; + cir->rdwos = 0; + cir->rxdcr = 0x3; + cir->hcfs = 0; + cir->fifo_tl = 0; + cir->cfq = 0x1d; + cir_port_init(cir); + + retval = request_irq(IT8172_CIR0_IRQ, kbd_int_handler, + (unsigned long )(SA_INTERRUPT|SA_SHIRQ), + (const char *)"Qtronix IR Keyboard", (void *)cir); + + if (retval) { + printk("unable to allocate cir %d irq %d\n", + cir->port, IT8172_CIR0_IRQ); + } +#ifdef CONFIG_PSMOUSE + psaux_init(); +#endif +} + +static inline unsigned char BitReverse(unsigned short key) +{ + unsigned char rkey = 0; + rkey |= (key & 0x1) << 7; + rkey |= (key & 0x2) << 5; + rkey |= (key & 0x4) << 3; + rkey |= (key & 0x8) << 1; + rkey |= (key & 0x10) >> 1; + rkey |= (key & 0x20) >> 3; + rkey |= (key & 0x40) >> 5; + rkey |= (key & 0x80) >> 7; + return rkey; + +} + + +static inline u_int8_t UpperByte(u_int8_t data) +{ + return (data >> 4); +} + + +static inline u_int8_t LowerByte(u_int8_t data) +{ + return (data & 0xF); +} + + +int CheckSumOk(u_int8_t byte1, u_int8_t byte2, + u_int8_t byte3, u_int8_t byte4, u_int8_t byte5) +{ + u_int8_t CheckSum; + + CheckSum = (byte1 & 0x0F) + byte2 + byte3 + byte4 + byte5; + if ( LowerByte(UpperByte(CheckSum) + LowerByte(CheckSum)) != UpperByte(byte1) ) + return 0; + else + return 1; +} + + +static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct cir_port *cir; + int j; + unsigned char int_status; + + cir = (struct cir_port *)dev_id; + int_status = get_int_status(cir);; + if (int_status & 0x4) { + clear_fifo(cir); + return; + } + + while (cir_get_rx_count(cir)) { + + cir_data[data_index] = cir_read_data(cir); + + if (data_index == 0) {/* expecting first byte */ + if (cir_data[data_index] != leading1) { + //printk("!leading byte %x\n", cir_data[data_index]); + set_rx_active(cir); + clear_fifo(cir); + continue; + } + } + if (data_index == 1) { + if ((cir_data[data_index] & 0xf) != leading2) { + set_rx_active(cir); + data_index = 0; /* start over */ + clear_fifo(cir); + continue; + } + } + + if ( (cir_data[data_index] == 0xff)) { /* last byte */ + //printk("data_index %d\n", data_index); + set_rx_active(cir); +#if 0 + for (j=0; j<=data_index; j++) { + printk("rx_data %d: %x\n", j, cir_data[j]); + } +#endif + data_index = 0; + handle_data(cir_data); + return; + } + else if (data_index>16) { + set_rx_active(cir); +#if 0 + printk("warning: data_index %d\n", data_index); + for (j=0; j<=data_index; j++) { + printk("rx_data %d: %x\n", j, cir_data[j]); + } +#endif + data_index = 0; + clear_fifo(cir); + return; + } + data_index++; + } +} + + +#define NUM_KBD_BYTES 5 +static int handle_data(unsigned char *p_data) +{ + u_int32_t bit_bucket; + u_int32_t i, j; + u_int32_t got_bits, next_byte; + int down = 0; + + /* Reorganize the bit stream */ + for (i=0; i<16; i++) + p_data[i] = BitReverse(~p_data[i]); + + /* + * We've already previously checked that p_data[0] + * is equal to leading1 and that (p_data[1] & 0xf) + * is equal to leading2. These twelve bits are the + * leader code. We can now throw them away (the 12 + * bits) and continue parsing the stream. + */ + bit_bucket = p_data[1] << 12; + got_bits = 4; + next_byte = 2; + + /* + * Process four bits at a time + */ + for (i=0; i<NUM_KBD_BYTES; i++) { + + kbdbytes[i]=0; + + for (j=0; j<8; j++) /* 8 bits per byte */ + { + if (got_bits < 4) { + bit_bucket |= (p_data[next_byte++] << (8 - got_bits)); + got_bits += 8; + } + + if ((bit_bucket & 0xF000) == 0x8000) { + /* Convert 1000b to 1 */ + kbdbytes[i] = 0x80 | (kbdbytes[i] >> 1); + got_bits -= 4; + bit_bucket = bit_bucket << 4; + } + else if ((bit_bucket & 0xC000) == 0x8000) { + /* Convert 10b to 0 */ + kbdbytes[i] = kbdbytes[i] >> 1; + got_bits -= 2; + bit_bucket = bit_bucket << 2; + } + else { + /* bad serial stream */ + return 1; + } + + if (next_byte > 16) { + //printk("error: too many bytes\n"); + return 1; + } + } + } + + + if (!CheckSumOk(kbdbytes[0], kbdbytes[1], + kbdbytes[2], kbdbytes[3], kbdbytes[4])) { + //printk("checksum failed\n"); + return 1; + } + + if (kbdbytes[1] & 0x08) { + //printk("m: %x %x %x\n", kbdbytes[1], kbdbytes[2], kbdbytes[3]); + handle_mouse_event(kbdbytes[1]); + handle_mouse_event(kbdbytes[2]); + handle_mouse_event(kbdbytes[3]); + } + else { + if (kbdbytes[2] == 0) down = 1; +#if 0 + if (down) + printk("down %d\n", kbdbytes[3]); + else + printk("up %d\n", kbdbytes[3]); +#endif + handle_keyboard_event(kbdbytes[3], down); + } + return 0; +} + + +spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; +static unsigned char handle_kbd_event(void); + + +int pckbd_setkeycode(unsigned int scancode, unsigned int keycode) +{ + printk("pckbd_setkeycode scancode %x keycode %x\n", scancode, keycode); + return 0; +} + +int pckbd_getkeycode(unsigned int scancode) +{ + return scancode; +} + + +int pckbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) +{ + static int prev_scancode = 0; + + if (scancode == 0x00 || scancode == 0xff) { + prev_scancode = 0; + return 0; + } + + /* todo */ + if (!prev_scancode && scancode == 160) { /* Fn key down */ + //printk("Fn key down\n"); + prev_scancode = 160; + return 0; + } + else if (prev_scancode && scancode == 160) { /* Fn key up */ + //printk("Fn key up\n"); + prev_scancode = 0; + return 0; + } + + /* todo */ + if (prev_scancode == 160) { + if (scancode <= NUM_FN_KEYS) { + *keycode = fn_keys[scancode]; + //printk("fn keycode %d\n", *keycode); + } + else + return 0; + } + else if (scancode <= 127) { + *keycode = scancode; + } + else + return 0; + + + return 1; +} + +char pckbd_unexpected_up(unsigned char keycode) +{ + //printk("pckbd_unexpected_up\n"); + return 0; +} + +static unsigned char kbd_exists = 1; + +static inline void handle_keyboard_event(unsigned char scancode, int down) +{ + kbd_exists = 1; + handle_scancode(scancode, down); + tasklet_schedule(&keyboard_tasklet); +} + + +void pckbd_leds(unsigned char leds) +{ +} + +/* dummy */ +void pckbd_init_hw(void) +{ +} + + + +static inline void handle_mouse_event(unsigned char scancode) +{ + if(scancode == AUX_RECONNECT){ + queue->head = queue->tail = 0; /* Flush input queue */ + // __aux_write_ack(AUX_ENABLE_DEV); /* ping the mouse :) */ + return; + } + + add_mouse_randomness(scancode); + if (aux_count) { + int head = queue->head; + + queue->buf[head] = scancode; + head = (head + 1) & (AUX_BUF_SIZE-1); + if (head != queue->tail) { + queue->head = head; + kill_fasync(&queue->fasync, SIGIO, POLL_IN); + wake_up_interruptible(&queue->proc_list); + } + } +} + +static unsigned char get_from_queue(void) +{ + unsigned char result; + unsigned long flags; + + spin_lock_irqsave(&kbd_controller_lock, flags); + result = queue->buf[queue->tail]; + queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); + spin_unlock_irqrestore(&kbd_controller_lock, flags); + return result; +} + + +static inline int queue_empty(void) +{ + return queue->head == queue->tail; +} + +static int fasync_aux(int fd, struct file *filp, int on) +{ + int retval; + + //printk("fasync_aux\n"); + retval = fasync_helper(fd, filp, on, &queue->fasync); + if (retval < 0) + return retval; + return 0; +} + + +/* + * Random magic cookie for the aux device + */ +#define AUX_DEV ((void *)queue) + +static int release_aux(struct inode * inode, struct file * file) +{ + lock_kernel(); + fasync_aux(-1, file, 0); + aux_count--; + unlock_kernel(); + return 0; +} + +static int open_aux(struct inode * inode, struct file * file) +{ + if (aux_count++) { + return 0; + } + queue->head = queue->tail = 0; /* Flush input queue */ + return 0; +} + +/* + * Put bytes from input queue to buffer. + */ + +static ssize_t read_aux(struct file * file, char * buffer, + size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + ssize_t i = count; + unsigned char c; + + if (queue_empty()) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + add_wait_queue(&queue->proc_list, &wait); +repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (queue_empty() && !signal_pending(current)) { + schedule(); + goto repeat; + } + current->state = TASK_RUNNING; + remove_wait_queue(&queue->proc_list, &wait); + } + while (i > 0 && !queue_empty()) { + c = get_from_queue(); + put_user(c, buffer++); + i--; + } + if (count-i) { + file->f_dentry->d_inode->i_atime = CURRENT_TIME; + return count-i; + } + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + +/* + * Write to the aux device. + */ + +static ssize_t write_aux(struct file * file, const char * buffer, + size_t count, loff_t *ppos) +{ + /* + * The ITE boards this was tested on did not have the + * transmit wires connected. + */ + return count; +} + +static unsigned int aux_poll(struct file *file, poll_table * wait) +{ + poll_wait(file, &queue->proc_list, wait); + if (!queue_empty()) + return POLLIN | POLLRDNORM; + return 0; +} + +struct file_operations psaux_fops = { + read: read_aux, + write: write_aux, + poll: aux_poll, + open: open_aux, + release: release_aux, + fasync: fasync_aux, +}; + +/* + * Initialize driver. + */ +static struct miscdevice psaux_mouse = { + PSMOUSE_MINOR, "psaux", &psaux_fops +}; + +static int __init psaux_init(void) +{ + misc_register(&psaux_mouse); + queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); + memset(queue, 0, sizeof(*queue)); + queue->head = queue->tail = 0; + init_waitqueue_head(&queue->proc_list); + + return 0; +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/qtronixmap.map linux.ac/drivers/char/qtronixmap.map --- linux.vanilla/drivers/char/qtronixmap.map Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/char/qtronixmap.map Tue Apr 3 17:54:40 2001 @@ -0,0 +1,287 @@ +# Default kernel keymap. This uses 7 modifier combinations. +keymaps 0-2,4-5,8,12 +# Change the above line into +# keymaps 0-2,4-6,8,12 +# in case you want the entries +# altgr control keycode 83 = Boot +# altgr control keycode 111 = Boot +# below. +# +# In fact AltGr is used very little, and one more keymap can +# be saved by mapping AltGr to Alt (and adapting a few entries): +# keycode 100 = Alt +# +keycode 1 = grave asciitilde + alt keycode 1 = Meta_Escape +keycode 2 = one exclam + alt keycode 2 = Meta_one +keycode 3 = two at at + control keycode 3 = nul + shift control keycode 3 = nul + alt keycode 3 = Meta_two +keycode 4 = three numbersign + control keycode 4 = Escape + alt keycode 4 = Meta_three +keycode 5 = four dollar dollar + control keycode 5 = Control_backslash + alt keycode 5 = Meta_four +keycode 6 = five percent + control keycode 6 = Control_bracketright + alt keycode 6 = Meta_five +keycode 7 = six asciicircum + control keycode 7 = Control_asciicircum + alt keycode 7 = Meta_six +keycode 8 = seven ampersand braceleft + control keycode 8 = Control_underscore + alt keycode 8 = Meta_seven +keycode 9 = eight asterisk bracketleft + control keycode 9 = Delete + alt keycode 9 = Meta_eight +keycode 10 = nine parenleft bracketright + alt keycode 10 = Meta_nine +keycode 11 = zero parenright braceright + alt keycode 11 = Meta_zero +keycode 12 = minus underscore backslash + control keycode 12 = Control_underscore + shift control keycode 12 = Control_underscore + alt keycode 12 = Meta_minus +keycode 13 = equal plus + alt keycode 13 = Meta_equal +keycode 15 = Delete Delete + control keycode 15 = BackSpace + alt keycode 15 = Meta_Delete +keycode 16 = Tab Tab + alt keycode 16 = Meta_Tab +keycode 17 = q +keycode 18 = w +keycode 19 = e +keycode 20 = r +keycode 21 = t +keycode 22 = y +keycode 23 = u +keycode 24 = i +keycode 25 = o +keycode 26 = p +keycode 27 = bracketleft braceleft + control keycode 27 = Escape + alt keycode 27 = Meta_bracketleft +keycode 28 = bracketright braceright + control keycode 28 = Control_bracketright + alt keycode 28 = Meta_bracketright +keycode 29 = backslash bar + control keycode 29 = Control_backslash + alt keycode 29 = Meta_backslash +keycode 30 = Caps_Lock +keycode 31 = a +keycode 32 = s +keycode 33 = d +keycode 34 = f +keycode 35 = g +keycode 36 = h +keycode 37 = j +keycode 38 = k +keycode 39 = l +keycode 40 = semicolon colon + alt keycode 39 = Meta_semicolon +keycode 41 = apostrophe quotedbl + control keycode 40 = Control_g + alt keycode 40 = Meta_apostrophe +keycode 42 = grave asciitilde + control keycode 41 = nul + alt keycode 41 = Meta_grave +keycode 43 = Return + alt keycode 43 = Meta_Control_m +keycode 44 = Shift +keycode 46 = z +keycode 47 = x +keycode 48 = c +keycode 49 = v +keycode 50 = b +keycode 51 = n +keycode 52 = m +keycode 53 = comma less + alt keycode 51 = Meta_comma +keycode 54 = period greater + control keycode 52 = Compose + alt keycode 52 = Meta_period +keycode 55 = slash question + control keycode 53 = Delete + alt keycode 53 = Meta_slash +keycode 57 = Shift +keycode 58 = Control +keycode 60 = Alt +keycode 61 = space space + control keycode 61 = nul + alt keycode 61 = Meta_space +keycode 62 = Alt + +keycode 75 = Insert +keycode 76 = Delete + +keycode 83 = Up +keycode 84 = Down + +keycode 85 = Prior + shift keycode 85 = Scroll_Backward +keycode 86 = Next + shift keycode 86 = Scroll_Forward +keycode 89 = Right + alt keycode 89 = Incr_Console +keycode 79 = Left + alt keycode 79 = Decr_Console + +keycode 90 = Num_Lock + shift keycode 90 = Bare_Num_Lock + +keycode 91 = minus +keycode 92 = plus +keycode 93 = KP_Multiply +keycode 94 = period +keycode 95 = KP_Divide + +keycode 107 = Select +keycode 108 = Down + +keycode 110 = Escape Escape + alt keycode 1 = Meta_Escape + +keycode 112 = F1 F11 Console_13 + control keycode 112 = F1 + alt keycode 112 = Console_1 + control alt keycode 112 = Console_1 +keycode 113 = F2 F12 Console_14 + control keycode 113 = F2 + alt keycode 113 = Console_2 + control alt keycode 113 = Console_2 +keycode 114 = F3 F13 Console_15 + control keycode 114 = F3 + alt keycode 114 = Console_3 + control alt keycode 114 = Console_3 +keycode 115 = F4 F14 Console_16 + control keycode 115 = F4 + alt keycode 115 = Console_4 + control alt keycode 115 = Console_4 +keycode 116 = F5 F15 Console_17 + control keycode 116 = F5 + alt keycode 116 = Console_5 + control alt keycode 116 = Console_5 +keycode 117 = F6 F16 Console_18 + control keycode 117 = F6 + alt keycode 117 = Console_6 + control alt keycode 117 = Console_6 +keycode 118 = F7 F17 Console_19 + control keycode 118 = F7 + alt keycode 118 = Console_7 + control alt keycode 118 = Console_7 +keycode 119 = F8 F18 Console_20 + control keycode 119 = F8 + alt keycode 119 = Console_8 + control alt keycode 119 = Console_8 +keycode 120 = F9 F19 Console_21 + control keycode 120 = F9 + alt keycode 120 = Console_9 + control alt keycode 120 = Console_9 +keycode 121 = F10 F20 Console_22 + control keycode 121 = F10 + alt keycode 121 = Console_10 + control alt keycode 121 = Console_10 + +keycode 126 = Pause + + +string F1 = "\033[[A" +string F2 = "\033[[B" +string F3 = "\033[[C" +string F4 = "\033[[D" +string F5 = "\033[[E" +string F6 = "\033[17~" +string F7 = "\033[18~" +string F8 = "\033[19~" +string F9 = "\033[20~" +string F10 = "\033[21~" +string F11 = "\033[23~" +string F12 = "\033[24~" +string F13 = "\033[25~" +string F14 = "\033[26~" +string F15 = "\033[28~" +string F16 = "\033[29~" +string F17 = "\033[31~" +string F18 = "\033[32~" +string F19 = "\033[33~" +string F20 = "\033[34~" +string Find = "\033[1~" +string Insert = "\033[2~" +string Remove = "\033[3~" +string Select = "\033[4~" +string Prior = "\033[5~" +string Next = "\033[6~" +string Macro = "\033[M" +string Pause = "\033[P" +compose '`' 'A' to 'Ŕ' +compose '`' 'a' to 'ŕ' +compose '\'' 'A' to 'Á' +compose '\'' 'a' to 'á' +compose '^' 'A' to 'Â' +compose '^' 'a' to 'â' +compose '~' 'A' to 'Ă' +compose '~' 'a' to 'ă' +compose '"' 'A' to 'Ä' +compose '"' 'a' to 'ä' +compose 'O' 'A' to 'Ĺ' +compose 'o' 'a' to 'ĺ' +compose '0' 'A' to 'Ĺ' +compose '0' 'a' to 'ĺ' +compose 'A' 'A' to 'Ĺ' +compose 'a' 'a' to 'ĺ' +compose 'A' 'E' to 'Ć' +compose 'a' 'e' to 'ć' +compose ',' 'C' to 'Ç' +compose ',' 'c' to 'ç' +compose '`' 'E' to 'Č' +compose '`' 'e' to 'č' +compose '\'' 'E' to 'É' +compose '\'' 'e' to 'é' +compose '^' 'E' to 'Ę' +compose '^' 'e' to 'ę' +compose '"' 'E' to 'Ë' +compose '"' 'e' to 'ë' +compose '`' 'I' to 'Ě' +compose '`' 'i' to 'ě' +compose '\'' 'I' to 'Í' +compose '\'' 'i' to 'í' +compose '^' 'I' to 'Î' +compose '^' 'i' to 'î' +compose '"' 'I' to 'Ď' +compose '"' 'i' to 'ď' +compose '-' 'D' to 'Đ' +compose '-' 'd' to 'đ' +compose '~' 'N' to 'Ń' +compose '~' 'n' to 'ń' +compose '`' 'O' to 'Ň' +compose '`' 'o' to 'ň' +compose '\'' 'O' to 'Ó' +compose '\'' 'o' to 'ó' +compose '^' 'O' to 'Ô' +compose '^' 'o' to 'ô' +compose '~' 'O' to 'Ő' +compose '~' 'o' to 'ő' +compose '"' 'O' to 'Ö' +compose '"' 'o' to 'ö' +compose '/' 'O' to 'Ř' +compose '/' 'o' to 'ř' +compose '`' 'U' to 'Ů' +compose '`' 'u' to 'ů' +compose '\'' 'U' to 'Ú' +compose '\'' 'u' to 'ú' +compose '^' 'U' to 'Ű' +compose '^' 'u' to 'ű' +compose '"' 'U' to 'Ü' +compose '"' 'u' to 'ü' +compose '\'' 'Y' to 'Ý' +compose '\'' 'y' to 'ý' +compose 'T' 'H' to 'Ţ' +compose 't' 'h' to 'ţ' +compose 's' 's' to 'ß' +compose '"' 'y' to '˙' +compose 's' 'z' to 'ß' +compose 'i' 'j' to '˙' diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/random.c linux.ac/drivers/char/random.c --- linux.vanilla/drivers/char/random.c Sat Feb 17 00:02:36 2001 +++ linux.ac/drivers/char/random.c Sun Apr 15 23:17:35 2001 @@ -610,7 +610,7 @@ static void batch_entropy_process(void *private_); /* note: the size must be a power of 2 */ -static int batch_entropy_init(int size, struct entropy_store *r) +static int __init batch_entropy_init(int size, struct entropy_store *r) { batch_entropy_pool = kmalloc(2*size*sizeof(__u32), GFP_KERNEL); if (!batch_entropy_pool) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/raw.c linux.ac/drivers/char/raw.c --- linux.vanilla/drivers/char/raw.c Mon Oct 2 04:35:15 2000 +++ linux.ac/drivers/char/raw.c Tue Apr 3 17:54:40 2001 @@ -184,7 +184,8 @@ * major/minor numbers make sense. */ - if (rq.block_major == NODEV || + if ((rq.block_major == NODEV && + rq.block_minor != NODEV) || rq.block_major > MAX_BLKDEV || rq.block_minor > MINORMASK) { err = -EINVAL; @@ -277,8 +278,11 @@ if ((*offp & sector_mask) || (size & sector_mask)) return -EINVAL; - if ((*offp >> sector_bits) > limit) + if ((*offp >> sector_bits) >= limit) { + if (size) + return -ENXIO; return 0; + } /* * We'll just use one kiobuf @@ -310,24 +314,21 @@ err = map_user_kiobuf(rw, iobuf, (unsigned long) buf, iosize); if (err) break; -#if 0 - err = lock_kiovec(1, &iobuf, 1); - if (err) - break; -#endif - + for (i=0; i < blocks; i++) b[i] = blocknr++; err = brw_kiovec(rw, 1, &iobuf, dev, b, sector_size); - + if (rw == READ && err > 0) + mark_dirty_kiobuf(iobuf, err); + if (err >= 0) { transferred += err; size -= err; buf += err; } - unmap_kiobuf(iobuf); /* The unlock_kiobuf is implicit here */ + unmap_kiobuf(iobuf); if (err != iosize) break; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/rio/rio_linux.c linux.ac/drivers/char/rio/rio_linux.c --- linux.vanilla/drivers/char/rio/rio_linux.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/char/rio/rio_linux.c Tue Apr 3 17:54:40 2001 @@ -1031,8 +1031,10 @@ free2:kfree (p->RIOHosts); free1:kfree (p); free0: - rio_dprintk (RIO_DEBUG_INIT, "Not enough memory! %p %p %p %p %p\n", - p, p->RIOHosts, p->RIOPortp, rio_termios, rio_termios); + if (p) { + rio_dprintk (RIO_DEBUG_INIT, "Not enough memory! %p %p %p %p %p\n", + p, p->RIOHosts, p->RIOPortp, rio_termios, rio_termios); + } return -ENOMEM; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/rio/rioctrl.c linux.ac/drivers/char/rio/rioctrl.c --- linux.vanilla/drivers/char/rio/rioctrl.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/char/rio/rioctrl.c Tue Apr 3 17:54:40 2001 @@ -764,7 +764,7 @@ PortP->Config &= ~RIO_WAITDRAIN; } /* - ** Store setings if locking or unlocking port or if the + ** Store settings if locking or unlocking port or if the ** port is not locked, when setting the store option. */ if (PortP->Mapped && diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/scan_keyb.c linux.ac/drivers/char/scan_keyb.c --- linux.vanilla/drivers/char/scan_keyb.c Fri Feb 9 19:30:22 2001 +++ linux.ac/drivers/char/scan_keyb.c Sat Apr 14 01:21:59 2001 @@ -18,33 +18,40 @@ #include <linux/miscdevice.h> #include <linux/slab.h> #include <linux/kbd_kern.h> +#include <linux/timer.h> + +#define SCANHZ (HZ/20) struct scan_keyboard { struct scan_keyboard *next; - void (*scan)(unsigned char *buffer); + int (*scan)(unsigned char *buffer); const unsigned char *table; unsigned char *s0, *s1; int length; }; - + +static int scan_jiffies=0; static struct scan_keyboard *keyboards=NULL; -static struct tq_struct task_scan_kbd; +struct timer_list scan_timer; static void check_kbd(const unsigned char *table, unsigned char *new, unsigned char *old, int length) { int need_tasklet_schedule=0; - unsigned char xor, bit; + unsigned int xor, bit; while(length-->0) { if((xor=*new^*old)==0) { table+=8; } else { - for(bit=0x80; bit!=0; bit>>=1) { + for(bit=0x01; bit<0x100; bit<<=1) { if(xor&bit) { handle_scancode(*table, !(*new&bit)); need_tasklet_schedule=1; +#if 0 + printk("0x%x %s\n", *table, (*new&bit)?"released":"pressed"); +#endif } table++; } @@ -57,26 +64,39 @@ } -static void scan_kbd(void *dummy) +static void scan_kbd(unsigned long dummy) { struct scan_keyboard *kbd; + scan_jiffies++; + for(kbd=keyboards; kbd!=NULL; kbd=kbd->next) { - if(jiffies&1) { - kbd->scan(kbd->s0); - check_kbd(kbd->table, kbd->s0, kbd->s1, kbd->length); + if(scan_jiffies&1) { + if(!kbd->scan(kbd->s0)) + check_kbd(kbd->table, + kbd->s0, kbd->s1, kbd->length); + else + memcpy(kbd->s0, kbd->s1, kbd->length); } else { - kbd->scan(kbd->s1); - check_kbd(kbd->table, kbd->s1, kbd->s0, kbd->length); + if(!kbd->scan(kbd->s1)) + check_kbd(kbd->table, + kbd->s1, kbd->s0, kbd->length); + else + memcpy(kbd->s1, kbd->s0, kbd->length); } } - queue_task(&task_scan_kbd, &tq_timer); + + init_timer(&scan_timer); + scan_timer.expires = jiffies + SCANHZ; + scan_timer.data = 0; + scan_timer.function = scan_kbd; + add_timer(&scan_timer); } -int register_scan_keyboard(void (*scan)(unsigned char *buffer), +int register_scan_keyboard(int (*scan)(unsigned char *buffer), const unsigned char *table, int length) { @@ -98,8 +118,8 @@ if (kbd->s1 == NULL) goto error_free_s0; - kbd->scan(kbd->s0); - kbd->scan(kbd->s1); + memset(kbd->s0, -1, kbd->length); + memset(kbd->s1, -1, kbd->length); kbd->next=keyboards; keyboards=kbd; @@ -119,11 +139,11 @@ void __init scan_kbd_init(void) { + init_timer(&scan_timer); + scan_timer.expires = jiffies + SCANHZ; + scan_timer.data = 0; + scan_timer.function = scan_kbd; + add_timer(&scan_timer); - INIT_LIST_HEAD(task_scan_kbd.list); - task_scan_kbd.sync=0; - task_scan_kbd.routine=scan_kbd; - task_scan_kbd.data=NULL; - queue_task(&task_scan_kbd, &tq_timer); printk(KERN_INFO "Generic scan keyboard driver initialized\n"); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/scan_keyb.h linux.ac/drivers/char/scan_keyb.h --- linux.vanilla/drivers/char/scan_keyb.h Fri Jul 21 22:21:06 2000 +++ linux.ac/drivers/char/scan_keyb.h Sat Apr 14 01:21:59 2001 @@ -6,7 +6,7 @@ * Generic scan keyboard driver */ -int register_scan_keyboard(void (*scan)(unsigned char *buffer), +int register_scan_keyboard(int (*scan)(unsigned char *buffer), const unsigned char *table, int length); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/serial.c linux.ac/drivers/char/serial.c --- linux.vanilla/drivers/char/serial.c Tue Apr 3 17:32:01 2001 +++ linux.ac/drivers/char/serial.c Tue Apr 10 18:14:15 2001 @@ -59,8 +59,8 @@ * */ -static char *serial_version = "5.05"; -static char *serial_revdate = "2000-12-13"; +static char *serial_version = "5.05a"; +static char *serial_revdate = "2001-03-20"; /* * Serial driver configuration section. Here are the various options: @@ -3924,11 +3924,6 @@ return; } - if (!(board->flags & SPCI_FL_ISPNP) && pci_enable_device(dev)) { - printk("serial: PCI device enable failed\n"); - return; - } - /* * Run the initialization function, if any */ @@ -4610,7 +4605,8 @@ * (Should we try to make guesses for multiport serial devices * later?) */ - if ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL || + if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) && + ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) || (dev->class & 0xff) > 6) return 1; @@ -4639,6 +4635,7 @@ const struct pci_device_id *ent) { struct pci_board *board, tmp; + int rc; for (board = pci_boards; board->vendor; board++) { if (board->vendor != (unsigned short) PCI_ANY_ID && @@ -4656,6 +4653,9 @@ break; } + rc = pci_enable_device(dev); + if (rc) return rc; + if (board->vendor == 0 && serial_pci_guess_board(dev, board)) return -ENODEV; else if (serial_pci_guess_board(dev, &tmp) == 0) { @@ -4708,6 +4708,8 @@ static struct pci_device_id serial_pci_tbl[] __devinitdata = { { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, }, + { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_MODEM << 8, 0xffff00, }, { 0, } }; @@ -5724,6 +5726,10 @@ case 9600: default: cflag |= B9600; + /* + * Set this to a sane value to prevent a divide error + */ + baud = 9600; break; } switch(bits) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/serial167.c linux.ac/drivers/char/serial167.c --- linux.vanilla/drivers/char/serial167.c Tue Nov 28 01:11:26 2000 +++ linux.ac/drivers/char/serial167.c Tue Apr 3 17:54:40 2001 @@ -2725,7 +2725,7 @@ * Of course, once the console has been registered, we had better ensure * that serial167_init() doesn't leave the chip non-functional. * - * The console_lock must be held when we get here. + * The console must be locked when we get here. */ void serial167_console_write(struct console *co, const char *str, unsigned count) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/serial_amba.c linux.ac/drivers/char/serial_amba.c --- linux.vanilla/drivers/char/serial_amba.c Fri Feb 9 19:30:22 2001 +++ linux.ac/drivers/char/serial_amba.c Tue Apr 3 17:54:40 2001 @@ -1881,7 +1881,7 @@ * Print a string to the serial port trying not to disturb * any possible real use of the port... * - * The console_lock must be held when we get here. + * The console must be locked when we get here. */ static void ambauart_console_write(struct console *co, const char *s, u_int count) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/sh-sci.c linux.ac/drivers/char/sh-sci.c --- linux.vanilla/drivers/char/sh-sci.c Fri Feb 9 19:30:22 2001 +++ linux.ac/drivers/char/sh-sci.c Sat Apr 14 01:22:07 2001 @@ -74,6 +74,8 @@ static void sci_hungup(void *ptr); static void sci_close(void *ptr); static int sci_chars_in_buffer(void *ptr); +static int sci_request_irq(struct sci_port *port); +static void sci_free_irq(struct sci_port *port); static int sci_init_drivers(void); static struct tty_driver sci_driver, sci_callout_driver; @@ -83,8 +85,8 @@ static struct termios *sci_termios[SCI_NPORTS]; static struct termios *sci_termios_locked[SCI_NPORTS]; -int sci_refcount; -int sci_debug = 0; +static int sci_refcount; +static int sci_debug = 0; #ifdef MODULE MODULE_PARM(sci_debug, "i"); @@ -102,7 +104,7 @@ do status = sci_in(port, SCxSR); while (!(status & SCxSR_TDxE(port))); - + sci_out(port, SCxTDR, c); sci_in(port, SCxSR); /* Dummy read */ sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); @@ -626,10 +628,10 @@ dprintk("sci: BREAK detected\n"); } -#if defined(CONFIG_CPU_SUBTYPE_SH7750) +#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_ST40STB1) /* XXX: Handle SCIF overrun error */ - if (port->type == PORT_SCIF && (ctrl_inw(SCLSR2) & SCIF_ORER) != 0) { - ctrl_outw(0, SCLSR2); + if (port->type == PORT_SCIF && (sci_in(port, SCLSR) & SCIF_ORER) != 0) { + sci_out(port, SCLSR, 0); if(tty->flip.count<TTY_FLIPBUF_SIZE) { copied++; *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; @@ -796,6 +798,7 @@ port->gs.flags &= ~ GS_ACTIVE; if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) sci_setsignals(port, 0, 0); + sci_free_irq(port); } /* ********************************************************************** * @@ -828,8 +831,7 @@ */ retval = gs_init_port(&port->gs); if (retval) { - port->gs.count--; - return retval; + goto failed_1; } port->gs.flags |= GS_ACTIVE; @@ -837,14 +839,17 @@ if (port->gs.count == 1) { MOD_INC_USE_COUNT; + + retval = sci_request_irq(port); + if (retval) { + goto failed_2; + } } retval = gs_block_til_ready(port, filp); if (retval) { - MOD_DEC_USE_COUNT; - port->gs.count--; - return retval; + goto failed_3; } if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) { @@ -870,6 +875,14 @@ port->gs.pgrp = current->pgrp; return 0; + +failed_3: + sci_free_irq(port); +failed_2: + MOD_DEC_USE_COUNT; +failed_1: + port->gs.count--; + return retval; } static void sci_hungup(void *ptr) @@ -1094,29 +1107,46 @@ return 0; } -int __init sci_init(void) +static int sci_request_irq(struct sci_port *port) { - struct sci_port *port; - int i, j; + int i; void (*handlers[4])(int irq, void *ptr, struct pt_regs *regs) = { sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt, sci_br_interrupt, }; + for (i=0; i<4; i++) { + if (!port->irqs[i]) continue; + if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT, + "sci", port)) { + printk(KERN_ERR "sci: Cannot allocate irq.\n"); + return -ENODEV; + } + } + return 0; +} + +static void sci_free_irq(struct sci_port *port) +{ + int i; + + for (i=0; i<4; i++) { + if (!port->irqs[i]) continue; + free_irq(port->irqs[i], port); + } +} + +int __init sci_init(void) +{ + struct sci_port *port; + int j; + printk("SuperH SCI(F) driver initialized\n"); for (j=0; j<SCI_NPORTS; j++) { port = &sci_ports[j]; printk("ttySC%d at 0x%08x is a %s\n", j, port->base, (port->type == PORT_SCI) ? "SCI" : "SCIF"); - for (i=0; i<4; i++) { - if (!port->irqs[i]) continue; - if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT, - "sci", port)) { - printk(KERN_ERR "sci: Cannot allocate irq.\n"); - return -ENODEV; - } - } } sci_init_drivers(); @@ -1135,11 +1165,6 @@ void cleanup_module(void) { - int i; - - for (i=SCI_ERI_IRQ; i<SCI_TEI_IRQ; i++) /* XXX: irq_end?? */ - free_irq(i, port); - tty_unregister_driver(&sci_driver); tty_unregister_driver(&sci_callout_driver); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/sh-sci.h linux.ac/drivers/char/sh-sci.h --- linux.vanilla/drivers/char/sh-sci.h Mon Oct 2 19:57:34 2000 +++ linux.ac/drivers/char/sh-sci.h Sat Apr 14 01:22:07 2001 @@ -25,6 +25,7 @@ #define SH3_SCIF_IRQS { 56, 57, 59, 58 } #define SH3_IRDA_IRQS { 52, 53, 55, 54 } #define SH4_SCIF_IRQS { 40, 41, 43, 42 } +#define STB1_SCIF1_IRQS {23, 24, 26, 25 } #if defined(CONFIG_CPU_SUBTYPE_SH7708) # define SCI_NPORTS 1 @@ -53,12 +54,22 @@ } # define SCSPTR1 0xffe0001c /* 8 bit SCI */ # define SCSPTR2 0xFFE80020 /* 16 bit SCIF */ -# define SCLSR2 0xFFE80024 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* overrun error bit */ # define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \ 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \ 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ ) # define SCI_AND_SCIF +#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1) +# define SCI_NPORTS 2 +# define SCI_INIT { \ + { {}, PORT_SCIF, 0xffe00000, STB1_SCIF1_IRQS, sci_init_pins_scif }, \ + { {}, PORT_SCIF, 0xffe80000, SH4_SCIF_IRQS, sci_init_pins_scif } \ +} +# define SCSPTR1 0xffe00020 /* 16 bit SCIF */ +# define SCSPTR2 0xffe80020 /* 16 bit SCIF */ +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +# define SCIF_ONLY #else # error CPU subtype not defined #endif @@ -260,6 +271,7 @@ SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8) SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16) SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) +SCIF_FNS(SCLSR, 0, 0, 0x24, 16) #define sci_in(port, reg) sci_##reg##_in(port) #define sci_out(port, reg, value) sci_##reg##_out(port, value) @@ -285,11 +297,24 @@ #elif defined(CONFIG_CPU_SUBTYPE_SH7750) static inline int sci_rxd_in(struct sci_port *port) { +#ifndef SCIF_ONLY if (port->base == 0xffe00000) return ctrl_inb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */ +#endif +#ifndef SCI_ONLY if (port->base == 0xffe80000) return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */ +#endif return 1; +} +#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1) +static inline int sci_rxd_in(struct sci_port *port) +{ + if (port->base == 0xffe00000) + return ctrl_inw(SCSPTR1)&0x0001 ? 1 : 0; /* SCIF */ + else + return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */ + } #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/sx.c linux.ac/drivers/char/sx.c --- linux.vanilla/drivers/char/sx.c Tue Apr 3 17:32:02 2001 +++ linux.ac/drivers/char/sx.c Tue Apr 10 22:43:51 2001 @@ -1767,6 +1767,21 @@ } + +static void sx_break (struct tty_struct * tty, int flag) +{ + struct sx_port *port = tty->driver_data; + int rv; + + if (flag) + rv = sx_send_command (port, HS_START, -1, HS_IDLE_BREAK); + else + rv = sx_send_command (port, HS_STOP, -1, HS_IDLE_OPEN); + if (rv != 1) printk (KERN_ERR "sx: couldn't send break (%x).\n", + read_sx_byte (port->board, CHAN_OFFSET (port, hi_hstat))); +} + + static int sx_ioctl (struct tty_struct * tty, struct file * filp, unsigned int cmd, unsigned long arg) { @@ -1835,7 +1850,6 @@ sx_reconfigure_port(port); } break; - default: rc = -ENOIOCTLCMD; break; @@ -2215,6 +2229,7 @@ sx_driver.table = sx_table; sx_driver.termios = sx_termios; sx_driver.termios_locked = sx_termios_locked; + sx_driver.break_ctl = sx_break; sx_driver.open = sx_open; sx_driver.close = gs_close; @@ -2297,6 +2312,7 @@ /* Adjust the values in the "driver" */ sx_driver.termios = sx_termios; sx_driver.termios_locked = sx_termios_locked; + sx_driver.break_ctl = sx_break; port = sx_ports; for (i = 0; i < nboards; i++) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/synclink.c linux.ac/drivers/char/synclink.c --- linux.vanilla/drivers/char/synclink.c Tue Apr 3 17:32:02 2001 +++ linux.ac/drivers/char/synclink.c Sun Apr 15 23:11:26 2001 @@ -1,7 +1,7 @@ /* * linux/drivers/char/synclink.c * - * $Id: synclink.c,v 3.2 2000/11/06 22:34:38 paul Exp $ + * $Id: synclink.c,v 3.8 2001/03/30 17:30:38 ez Exp $ * * Device driver for Microgate SyncLink ISA and PCI * high speed multiprotocol serial adapters. @@ -107,8 +107,12 @@ #endif #ifdef CONFIG_SYNCLINK_SYNCPPP +#if LINUX_VERSION_CODE < VERSION(2,4,3) +#include "../net/wan/syncppp.h" +#else #include <net/syncppp.h> #endif +#endif #include <asm/segment.h> #define GET_USER(error,value,addr) error = get_user(value,addr) @@ -176,6 +180,14 @@ int cts_down; }; +/* transmit holding buffer definitions*/ +#define MAX_TX_HOLDING_BUFFERS 5 +struct tx_holding_buffer { + int buffer_size; + unsigned char * buffer; +}; + + /* * Device instance data structure */ @@ -241,11 +253,21 @@ DMABUFFERENTRY *rx_buffer_list; /* list of receive buffer entries */ unsigned int current_rx_buffer; + int num_tx_dma_buffers; /* number of tx dma frames required */ + int tx_dma_buffers_used; unsigned int tx_buffer_count; /* count of total allocated Tx buffers */ DMABUFFERENTRY *tx_buffer_list; /* list of transmit buffer entries */ + int start_tx_dma_buffer; /* tx dma buffer to start tx dma operation */ + int current_tx_buffer; /* next tx dma buffer to be loaded */ unsigned char *intermediate_rxbuffer; + int num_tx_holding_buffers; /* number of tx holding buffer allocated */ + int get_tx_holding_index; /* next tx holding buffer for adapter to load */ + int put_tx_holding_index; /* next tx holding buffer to store user request */ + int tx_holding_count; /* number of tx holding buffers waiting */ + struct tx_holding_buffer tx_holding_buffers[MAX_TX_HOLDING_BUFFERS]; + int rx_enabled; int rx_overflow; @@ -685,6 +707,8 @@ #define usc_TCmd(a,b) usc_OutReg((a), TCSR, (u16)((a)->tcsr_value + (b))) #define usc_RCmd(a,b) usc_OutReg((a), RCSR, (b)) +#define usc_SetTransmitSyncChars(a,s0,s1) usc_OutReg((a), TSR, (u16)(((u16)s0<<8)|(u16)s1)) + void usc_process_rxoverrun_sync( struct mgsl_struct *info ); void usc_start_receiver( struct mgsl_struct *info ); void usc_stop_receiver( struct mgsl_struct *info ); @@ -775,7 +799,10 @@ */ void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex ); int mgsl_get_rx_frame( struct mgsl_struct *info ); +int mgsl_get_raw_rx_frame( struct mgsl_struct *info ); void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info ); +void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info ); +int num_free_tx_dma_buffers(struct mgsl_struct *info); void mgsl_load_tx_dma_buffer( struct mgsl_struct *info, const char *Buffer, unsigned int BufferSize); void mgsl_load_pci_memory(char* TargetPtr, const char* SourcePtr, unsigned short count); @@ -790,6 +817,10 @@ void mgsl_free_buffer_list_memory(struct mgsl_struct *info); int mgsl_alloc_intermediate_rxbuffer_memory(struct mgsl_struct *info); void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info); +int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info); +void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info); +int load_next_tx_holding_buffer(struct mgsl_struct *info); +int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize); /* * Bottom half interrupt handlers @@ -810,6 +841,7 @@ void mgsl_isr_io_pin( struct mgsl_struct *info ); void mgsl_isr_misc( struct mgsl_struct *info ); void mgsl_isr_receive_dma( struct mgsl_struct *info ); +void mgsl_isr_transmit_dma( struct mgsl_struct *info ); typedef void (*isr_dispatch_func)(struct mgsl_struct *); @@ -874,6 +906,8 @@ static int debug_level = 0; static int maxframe[MAX_TOTAL_DEVICES] = {0,}; static int dosyncppp[MAX_TOTAL_DEVICES] = {0,}; +static int txdmabufs[MAX_TOTAL_DEVICES] = {0,}; +static int txholdbufs[MAX_TOTAL_DEVICES] = {0,}; MODULE_PARM(break_on_load,"i"); MODULE_PARM(ttymajor,"i"); @@ -884,9 +918,11 @@ MODULE_PARM(debug_level,"i"); MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); +MODULE_PARM(txdmabufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); +MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); static char *driver_name = "SyncLink serial driver"; -static char *driver_version = "3.2"; +static char *driver_version = "3.8"; static int __init synclink_init_one (struct pci_dev *dev, const struct pci_device_id *ent); @@ -1096,11 +1132,14 @@ void mgsl_bh_receive(struct mgsl_struct *info) { + int (*get_rx_frame)(struct mgsl_struct *info) = + (info->params.mode == MGSL_MODE_HDLC ? mgsl_get_rx_frame : mgsl_get_raw_rx_frame); + if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):mgsl_bh_receive(%s)\n", __FILE__,__LINE__,info->device_name); - while( mgsl_get_rx_frame(info) ); + while( (get_rx_frame)(info) ); } void mgsl_bh_transmit(struct mgsl_struct *info) @@ -1318,11 +1357,6 @@ #endif } else info->input_signal_events.dcd_down++; -#ifdef CONFIG_HARD_PPS - if ((info->flags & ASYNC_HARDPPS_CD) && - (status & MISCSTATUS_DCD_LATCHED)) - hardpps(); -#endif } if (status & MISCSTATUS_CTS_LATCHED) { @@ -1609,6 +1643,58 @@ } /* end of mgsl_isr_receive_dma() */ +/* mgsl_isr_transmit_dma() + * + * This function services a transmit DMA channel interrupt. + * + * For this driver there is one source of transmit DMA interrupts + * as identified in the Transmit DMA Mode Register (TDMR): + * + * BIT2 EOB End of Buffer. This interrupt occurs when a + * transmit DMA buffer has been emptied. + * + * The driver maintains enough transmit DMA buffers to hold at least + * one max frame size transmit frame. When operating in a buffered + * transmit mode, there may be enough transmit DMA buffers to hold at + * least two or more max frame size frames. On an EOB condition, + * determine if there are any queued transmit buffers and copy into + * transmit DMA buffers if we have room. + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void mgsl_isr_transmit_dma( struct mgsl_struct *info ) +{ + u16 status; + + /* clear interrupt pending and IUS bit for Tx DMA IRQ */ + usc_OutDmaReg(info, CDIR, BIT8+BIT0 ); + + /* Read the transmit DMA status to identify interrupt type. */ + /* This also clears the status bits. */ + + status = usc_InDmaReg( info, TDMR ); + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):mgsl_isr_transmit_dma(%s) status=%04X\n", + __FILE__,__LINE__,info->device_name,status); + + if ( status & BIT2 ) { + --info->tx_dma_buffers_used; + + /* if there are transmit frames queued, + * try to load the next one + */ + if ( load_next_tx_holding_buffer(info) ) { + /* if call returns non-zero value, we have + * at least one free tx holding buffer + */ + info->pending_bh |= BH_TRANSMIT; + } + } + +} /* end of mgsl_isr_transmit_dma() */ + /* mgsl_interrupt() * * Interrupt service routine entry point. @@ -1652,6 +1738,8 @@ /* Dispatch interrupt vector */ if ( UscVector ) (*UscIsrTable[UscVector])(info); + else if ( (DmaVector&(BIT10|BIT9)) == BIT10) + mgsl_isr_transmit_dma(info); else mgsl_isr_receive_dma(info); @@ -1818,7 +1906,9 @@ usc_stop_transmitter(info); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - if (info->params.mode == MGSL_MODE_HDLC || info->netcount) + if (info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW || + info->netcount) usc_set_sync_mode(info); else usc_set_async_mode(info); @@ -1970,8 +2060,7 @@ spin_lock_irqsave(&info->irq_spinlock,flags); - if ( (info->params.mode != MGSL_MODE_HDLC) || - !info->tx_active ) { + if ( (info->params.mode == MGSL_MODE_ASYNC ) || !info->tx_active ) { if (info->xmit_cnt < SERIAL_XMIT_SIZE - 1) { info->xmit_buf[info->xmit_head++] = ch; @@ -2015,8 +2104,8 @@ spin_lock_irqsave(&info->irq_spinlock,flags); if (!info->tx_active) { - if ( (info->params.mode == MGSL_MODE_HDLC) && - info->xmit_cnt ) { + if ( (info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW) && info->xmit_cnt ) { /* operating in synchronous (frame oriented) mode */ /* copy data from circular xmit_buf to */ /* transmit DMA buffer. */ @@ -2060,11 +2149,51 @@ if (!tty || !info->xmit_buf || !tmp_buf) goto cleanup; - if ( info->params.mode == MGSL_MODE_HDLC ) { + if ( info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW ) { + /* operating in synchronous (frame oriented) mode */ /* operating in synchronous (frame oriented) mode */ - if (info->tx_active) { - ret = 0; goto cleanup; + + if ( info->params.mode == MGSL_MODE_HDLC ) { + ret = 0; + goto cleanup; + } + /* transmitter is actively sending data - + * if we have multiple transmit dma and + * holding buffers, attempt to queue this + * frame for transmission at a later time. + */ + if (info->tx_holding_count >= info->num_tx_holding_buffers ) { + /* no tx holding buffers available */ + ret = 0; + goto cleanup; + } + + /* queue transmit frame request */ + ret = count; + if (from_user) { + down(&tmp_buf_sem); + COPY_FROM_USER(err,tmp_buf, buf, count); + if (err) { + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):mgsl_write(%s) sync user buf copy failed\n", + __FILE__,__LINE__,info->device_name); + ret = -EFAULT; + } else + save_tx_buffer_request(info,tmp_buf,count); + up(&tmp_buf_sem); + } + else + save_tx_buffer_request(info,buf,count); + + /* if we have sufficient tx dma buffers, + * load the next buffered tx request + */ + spin_lock_irqsave(&info->irq_spinlock,flags); + load_next_tx_holding_buffer(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + goto cleanup; } /* if operating in HDLC LoopMode and the adapter */ @@ -2200,7 +2329,8 @@ printk("%s(%d):mgsl_write_room(%s)=%d\n", __FILE__,__LINE__, info->device_name,ret ); - if ( info->params.mode == MGSL_MODE_HDLC ) { + if ( info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW ) { /* operating in synchronous (frame oriented) mode */ if ( info->tx_active ) return 0; @@ -2234,10 +2364,11 @@ printk("%s(%d):mgsl_chars_in_buffer(%s)=%d\n", __FILE__,__LINE__, info->device_name,info->xmit_cnt ); - if ( info->params.mode == MGSL_MODE_HDLC ) { + if ( info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW ) { /* operating in synchronous (frame oriented) mode */ if ( info->tx_active ) - return info->tx_buffer_list[0].rcc; + return info->max_frame_size; else return 0; } @@ -2627,11 +2758,11 @@ unsigned long flags; int s; int rc=0; - u16 regval; struct mgsl_icount cprev, cnow; - int events = 0; + int events; int mask; - struct _input_signal_events signal_events_prev, signal_events_now; + struct _input_signal_events oldsigs, newsigs; + DECLARE_WAITQUEUE(wait, current); COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int)); if (rc) { @@ -2644,114 +2775,99 @@ spin_lock_irqsave(&info->irq_spinlock,flags); + /* return immediately if state matches requested events */ usc_get_serial_signals(info); s = info->serial_signals; + events = mask & + ( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) + + ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) + + ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) + + ((s & SerialSignal_RI) ? MgslEvent_RiActive :MgslEvent_RiInactive) ); + if (events) { + spin_unlock_irqrestore(&info->irq_spinlock,flags); + goto exit; + } - /* note the counters on entry */ + /* save current irq counts */ cprev = info->icount; - signal_events_prev = info->input_signal_events; + oldsigs = info->input_signal_events; - if (mask & MgslEvent_ExitHuntMode) { - /* enable exit hunt mode IRQ */ - regval = usc_InReg(info,RICR); - if (!(regval & RXSTATUS_EXITED_HUNT)) - usc_OutReg(info, RICR, regval | RXSTATUS_EXITED_HUNT); + /* enable hunt and idle irqs if needed */ + if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) { + u16 oldreg = usc_InReg(info,RICR); + u16 newreg = oldreg + + (mask & MgslEvent_ExitHuntMode ? RXSTATUS_EXITED_HUNT:0) + + (mask & MgslEvent_IdleReceived ? RXSTATUS_IDLE_RECEIVED:0); + if (oldreg != newreg) + usc_OutReg(info, RICR, newreg); } - if (mask & MgslEvent_IdleReceived) { - /* enable idle mode received IRQ */ - regval = usc_InReg(info,RICR); - if (!(regval & RXSTATUS_IDLE_RECEIVED)) - usc_OutReg(info, RICR, regval | RXSTATUS_IDLE_RECEIVED); - } + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&info->event_wait_q, &wait); spin_unlock_irqrestore(&info->irq_spinlock,flags); - /* Determine if any user requested events for input signals is currently TRUE */ - - events |= (mask & ((s & SerialSignal_DSR) ? - MgslEvent_DsrActive:MgslEvent_DsrInactive)); - - events |= (mask & ((s & SerialSignal_DCD) ? - MgslEvent_DcdActive:MgslEvent_DcdInactive)); - - events |= (mask & ((s & SerialSignal_CTS) ? - MgslEvent_CtsActive:MgslEvent_CtsInactive)); - - events |= (mask & ((s & SerialSignal_RI) ? - MgslEvent_RiActive:MgslEvent_RiInactive)); - - while(!events) { - /* sleep until event occurs */ - interruptible_sleep_on(&info->event_wait_q); - - /* see if a signal woke us */ + for(;;) { + schedule(); if (signal_pending(current)) { rc = -ERESTARTSYS; break; } + /* get current irq counts */ spin_lock_irqsave(&info->irq_spinlock,flags); - - /* get icount and serial signal states */ cnow = info->icount; - signal_events_now = info->input_signal_events; + newsigs = info->input_signal_events; + set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&info->irq_spinlock,flags); - if (signal_events_now.dsr_up != signal_events_prev.dsr_up && - mask & MgslEvent_DsrActive ) - events |= MgslEvent_DsrActive; - - if (signal_events_now.dsr_down != signal_events_prev.dsr_down && - mask & MgslEvent_DsrInactive ) - events |= MgslEvent_DsrInactive; - - if (signal_events_now.dcd_up != signal_events_prev.dcd_up && - mask & MgslEvent_DcdActive ) - events |= MgslEvent_DcdActive; - - if (signal_events_now.dcd_down != signal_events_prev.dcd_down && - mask & MgslEvent_DcdInactive ) - events |= MgslEvent_DcdInactive; - - if (signal_events_now.cts_up != signal_events_prev.cts_up && - mask & MgslEvent_CtsActive ) - events |= MgslEvent_CtsActive; - - if (signal_events_now.cts_down != signal_events_prev.cts_down && - mask & MgslEvent_CtsInactive ) - events |= MgslEvent_CtsInactive; - - if (signal_events_now.ri_up != signal_events_prev.ri_up && - mask & MgslEvent_RiActive ) - events |= MgslEvent_RiActive; - - if (signal_events_now.ri_down != signal_events_prev.ri_down && - mask & MgslEvent_RiInactive ) - events |= MgslEvent_RiInactive; - - if (cnow.exithunt != cprev.exithunt) - events |= (mask & MgslEvent_ExitHuntMode); + /* if no change, wait aborted for some reason */ + if (newsigs.dsr_up == oldsigs.dsr_up && + newsigs.dsr_down == oldsigs.dsr_down && + newsigs.dcd_up == oldsigs.dcd_up && + newsigs.dcd_down == oldsigs.dcd_down && + newsigs.cts_up == oldsigs.cts_up && + newsigs.cts_down == oldsigs.cts_down && + newsigs.ri_up == oldsigs.ri_up && + newsigs.ri_down == oldsigs.ri_down && + cnow.exithunt == cprev.exithunt && + cnow.rxidle == cprev.rxidle) { + rc = -EIO; + break; + } - if (cnow.rxidle != cprev.rxidle) - events |= (mask & MgslEvent_IdleReceived); + events = mask & + ( (newsigs.dsr_up != oldsigs.dsr_up ? MgslEvent_DsrActive:0) + + (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) + + (newsigs.dcd_up != oldsigs.dcd_up ? MgslEvent_DcdActive:0) + + (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) + + (newsigs.cts_up != oldsigs.cts_up ? MgslEvent_CtsActive:0) + + (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) + + (newsigs.ri_up != oldsigs.ri_up ? MgslEvent_RiActive:0) + + (newsigs.ri_down != oldsigs.ri_down ? MgslEvent_RiInactive:0) + + (cnow.exithunt != cprev.exithunt ? MgslEvent_ExitHuntMode:0) + + (cnow.rxidle != cprev.rxidle ? MgslEvent_IdleReceived:0) ); + if (events) + break; cprev = cnow; - signal_events_prev = signal_events_now; + oldsigs = newsigs; } + remove_wait_queue(&info->event_wait_q, &wait); + set_current_state(TASK_RUNNING); + if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) { spin_lock_irqsave(&info->irq_spinlock,flags); if (!waitqueue_active(&info->event_wait_q)) { /* disable enable exit hunt mode/idle rcvd IRQs */ - regval = usc_InReg(info,RICR); - usc_OutReg(info, RICR, regval & + usc_OutReg(info, RICR, usc_InReg(info,RICR) & ~(RXSTATUS_EXITED_HUNT + RXSTATUS_IDLE_RECEIVED)); } spin_unlock_irqrestore(&info->irq_spinlock,flags); } - +exit: if ( rc == 0 ) PUT_USER(rc, events, mask_ptr); @@ -2759,6 +2875,56 @@ } /* end of mgsl_wait_event() */ +static int modem_input_wait(struct mgsl_struct *info,int arg) +{ + unsigned long flags; + int rc; + struct mgsl_icount cprev, cnow; + DECLARE_WAITQUEUE(wait, current); + + /* save current irq counts */ + spin_lock_irqsave(&info->irq_spinlock,flags); + cprev = info->icount; + add_wait_queue(&info->status_event_wait_q, &wait); + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + for(;;) { + schedule(); + if (signal_pending(current)) { + rc = -ERESTARTSYS; + break; + } + + /* get new irq counts */ + spin_lock_irqsave(&info->irq_spinlock,flags); + cnow = info->icount; + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + /* if no change, wait aborted for some reason */ + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { + rc = -EIO; + break; + } + + /* check for change in caller specified modem input */ + 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)) { + rc = 0; + break; + } + + cprev = cnow; + } + remove_wait_queue(&info->status_event_wait_q, &wait); + set_current_state(TASK_RUNNING); + return rc; +} + /* get_modem_info() * * Read the state of the serial control and @@ -2926,7 +3092,7 @@ int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg) { int error; - struct mgsl_icount cprev, cnow; /* kernel counter temps */ + struct mgsl_icount cnow; /* kernel counter temps */ struct serial_icounter_struct *p_cuser; /* user space */ unsigned long flags; @@ -2961,37 +3127,12 @@ while(MOD_IN_USE) MOD_DEC_USE_COUNT; return 0; - /* - * 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 + + /* Wait for modem input (DCD,RI,DSR,CTS) change + * as specified by mask in arg (TIOCM_RNG/DSR/CD/CTS) */ case TIOCMIWAIT: - spin_lock_irqsave(&info->irq_spinlock,flags); - /* note the counters on entry */ - cprev = info->icount; - spin_unlock_irqrestore(&info->irq_spinlock,flags); - while (1) { - interruptible_sleep_on(&info->status_event_wait_q); - /* 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 */ + return modem_input_wait(info,(int)arg); /* * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) @@ -3243,7 +3384,8 @@ if (timeout) char_time = MIN(char_time, timeout); - if ( info->params.mode == MGSL_MODE_HDLC ) { + if ( info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW ) { while (info->tx_active) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(char_time); @@ -3601,7 +3743,8 @@ if (info->serial_signals & SerialSignal_RI) strcat(stat_buf, "|RI"); - if (info->params.mode == MGSL_MODE_HDLC) { + if (info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW ) { ret += sprintf(buf+ret, " HDLC txok:%d rxok:%d", info->icount.txok, info->icount.rxok); if (info->icount.txunder) @@ -3742,15 +3885,15 @@ * * This leaves 62 4K pages. * - * The next N pages are used for a transmit frame. We - * reserve enough 4K page blocks to hold the configured - * MaxFrameSize + * The next N pages are used for transmit frame(s). We + * reserve enough 4K page blocks to hold the required + * number of transmit dma buffers (num_tx_dma_buffers), + * each of MaxFrameSize size. * * Of the remaining pages (62-N), determine how many can * be used to receive full MaxFrameSize inbound frames */ - - info->tx_buffer_count = BuffersPerFrame; + info->tx_buffer_count = info->num_tx_dma_buffers * BuffersPerFrame; info->rx_buffer_count = 62 - info->tx_buffer_count; } else { /* Calculate the number of PAGE_SIZE buffers needed for */ @@ -3763,7 +3906,7 @@ /* End of List condition if all receive buffers are used when */ /* using linked list DMA buffers. */ - info->tx_buffer_count = BuffersPerFrame; + info->tx_buffer_count = info->num_tx_dma_buffers * BuffersPerFrame; info->rx_buffer_count = (BuffersPerFrame * MAXRXFRAMES) + 6; /* @@ -3783,12 +3926,14 @@ if ( mgsl_alloc_buffer_list_memory( info ) < 0 || mgsl_alloc_frame_memory(info, info->rx_buffer_list, info->rx_buffer_count) < 0 || mgsl_alloc_frame_memory(info, info->tx_buffer_list, info->tx_buffer_count) < 0 || - mgsl_alloc_intermediate_rxbuffer_memory(info) < 0 ) { + mgsl_alloc_intermediate_rxbuffer_memory(info) < 0 || + mgsl_alloc_intermediate_txbuffer_memory(info) < 0 ) { printk("%s(%d):Can't allocate DMA buffer memory\n",__FILE__,__LINE__); return -ENOMEM; } mgsl_reset_rx_dma_buffers( info ); + mgsl_reset_tx_dma_buffers( info ); return 0; @@ -4044,6 +4189,149 @@ } /* end of mgsl_free_intermediate_rxbuffer_memory() */ +/* + * mgsl_alloc_intermediate_txbuffer_memory() + * + * Allocate intermdiate transmit buffer(s) large enough to hold max_frame_size. + * This buffer is used to load transmit frames into the adapter's dma transfer + * buffers when there is sufficient space. + * + * Arguments: + * + * info pointer to device instance data + * + * Return Value: 0 if success, otherwise -ENOMEM + */ +int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info) +{ + int i; + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk("%s %s(%d) allocating %d tx holding buffers\n", + info->device_name, __FILE__,__LINE__,info->num_tx_holding_buffers); + + memset(info->tx_holding_buffers,0,sizeof(info->tx_holding_buffers)); + + for ( i=0; i<info->num_tx_holding_buffers; ++i) { + info->tx_holding_buffers[i].buffer = + kmalloc(info->max_frame_size, GFP_KERNEL); + if ( info->tx_holding_buffers[i].buffer == NULL ) + return -ENOMEM; + } + + return 0; + +} /* end of mgsl_alloc_intermediate_txbuffer_memory() */ + +/* + * mgsl_free_intermediate_txbuffer_memory() + * + * + * Arguments: + * + * info pointer to device instance data + * + * Return Value: None + */ +void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info) +{ + int i; + + for ( i=0; i<info->num_tx_holding_buffers; ++i ) { + if ( info->tx_holding_buffers[i].buffer ) { + kfree(info->tx_holding_buffers[i].buffer); + info->tx_holding_buffers[i].buffer=NULL; + } + } + + info->get_tx_holding_index = 0; + info->put_tx_holding_index = 0; + info->tx_holding_count = 0; + +} /* end of mgsl_free_intermediate_txbuffer_memory() */ + + +/* + * load_next_tx_holding_buffer() + * + * attempts to load the next buffered tx request into the + * tx dma buffers + * + * Arguments: + * + * info pointer to device instance data + * + * Return Value: 1 if next buffered tx request loaded + * into adapter's tx dma buffer, + * 0 otherwise + */ +int load_next_tx_holding_buffer(struct mgsl_struct *info) +{ + int ret = 0; + + if ( info->tx_holding_count ) { + /* determine if we have enough tx dma buffers + * to accomodate the next tx frame + */ + struct tx_holding_buffer *ptx = + &info->tx_holding_buffers[info->get_tx_holding_index]; + int num_free = num_free_tx_dma_buffers(info); + int num_needed = ptx->buffer_size / DMABUFFERSIZE; + if ( ptx->buffer_size % DMABUFFERSIZE ) + ++num_needed; + + if (num_needed <= num_free) { + info->xmit_cnt = ptx->buffer_size; + mgsl_load_tx_dma_buffer(info,ptx->buffer,ptx->buffer_size); + + --info->tx_holding_count; + if ( ++info->get_tx_holding_index >= info->num_tx_holding_buffers) + info->get_tx_holding_index=0; + + /* restart transmit timer */ + del_timer(&info->tx_timer); + info->tx_timer.expires = jiffies + jiffies_from_ms(5000); + add_timer(&info->tx_timer); + + ret = 1; + } + } + + return ret; +} + +/* + * save_tx_buffer_request() + * + * attempt to store transmit frame request for later transmission + * + * Arguments: + * + * info pointer to device instance data + * Buffer pointer to buffer containing frame to load + * BufferSize size in bytes of frame in Buffer + * + * Return Value: 1 if able to store, 0 otherwise + */ +int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize) +{ + struct tx_holding_buffer *ptx; + + if ( info->tx_holding_count >= info->num_tx_holding_buffers ) { + return 0; /* all buffers in use */ + } + + ptx = &info->tx_holding_buffers[info->put_tx_holding_index]; + ptx->buffer_size = BufferSize; + memcpy( ptx->buffer, Buffer, BufferSize); + + ++info->tx_holding_count; + if ( ++info->put_tx_holding_index >= info->num_tx_holding_buffers) + info->put_tx_holding_index=0; + + return 1; +} + int mgsl_claim_resources(struct mgsl_struct *info) { if (request_region(info->io_base,info->io_addr_size,"synclink") == NULL) { @@ -4120,7 +4408,7 @@ return 0; errout: mgsl_release_resources(info); - return ENODEV; + return -ENODEV; } /* end of mgsl_claim_resources() */ @@ -4141,6 +4429,7 @@ } mgsl_free_dma_buffers(info); mgsl_free_intermediate_rxbuffer_memory(info); + mgsl_free_intermediate_txbuffer_memory(info); if ( info->io_addr_requested ) { release_region(info->io_base,info->io_addr_size); @@ -4187,6 +4476,20 @@ if (maxframe[info->line]) info->max_frame_size = maxframe[info->line]; info->dosyncppp = dosyncppp[info->line]; + + if (txdmabufs[info->line]) { + info->num_tx_dma_buffers = txdmabufs[info->line]; + if (info->num_tx_dma_buffers < 1) + info->num_tx_dma_buffers = 1; + } + + if (txholdbufs[info->line]) { + info->num_tx_holding_buffers = txholdbufs[info->line]; + if (info->num_tx_holding_buffers < 1) + info->num_tx_holding_buffers = 1; + else if (info->num_tx_holding_buffers > MAX_TX_HOLDING_BUFFERS) + info->num_tx_holding_buffers = MAX_TX_HOLDING_BUFFERS; + } } mgsl_device_count++; @@ -4255,6 +4558,8 @@ spin_lock_init(&info->netlock); memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); info->idle_mode = HDLC_TXIDLE_FLAGS; + info->num_tx_dma_buffers = 1; + info->num_tx_holding_buffers = 0; } return info; @@ -4432,6 +4737,7 @@ unsigned long flags; int rc; struct mgsl_struct *info; + struct mgsl_struct *tmp; printk("Unloading %s: version %s\n", driver_name, driver_version); save_flags(flags); @@ -4451,7 +4757,9 @@ mgsl_sppp_delete(info); #endif mgsl_release_resources(info); + tmp = info; info = info->next_device; + kfree(tmp); } if (tmp_buf) { @@ -4691,6 +4999,27 @@ * * 0000 0110 0000 0110 = 0x0606 */ + if (info->params.mode == MGSL_MODE_RAW) { + RegValue = 0x0001; /* Set Receive mode = external sync */ + + usc_OutReg( info, IOCR, /* Set IOCR DCD is RxSync Detect Input */ + (unsigned short)((usc_InReg(info, IOCR) & ~(BIT13|BIT12)) | BIT12)); + + /* + * TxSubMode: + * CMR <15> 0 Don't send CRC on Tx Underrun + * CMR <14> x undefined + * CMR <13> 0 Send preamble before openning sync + * CMR <12> 0 Send 8-bit syncs, 1=send Syncs per TxLength + * + * TxMode: + * CMR <11-8) 0100 MonoSync + * + * 0x00 0100 xxxx xxxx 04xx + */ + RegValue |= 0x0400; + } + else { RegValue = 0x0606; @@ -4700,12 +5029,14 @@ RegValue |= BIT15; else if ( info->params.flags & HDLC_FLAG_UNDERRUN_CRC ) RegValue |= BIT15 + BIT14; + } if ( info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE ) RegValue |= BIT13; } - if ( info->params.flags & HDLC_FLAG_SHARE_ZERO ) + if ( info->params.mode == MGSL_MODE_HDLC && + (info->params.flags & HDLC_FLAG_SHARE_ZERO) ) RegValue |= BIT12; if ( info->params.addr_filter != 0xff ) @@ -4745,15 +5076,13 @@ case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14 + BIT13; break; } - if ( info->params.crc_type == HDLC_CRC_16_CCITT ) + if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_16_CCITT ) RegValue |= BIT9; - else if ( info->params.crc_type == HDLC_CRC_32_CCITT ) + else if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_32_CCITT ) RegValue |= ( BIT12 | BIT10 | BIT9 ); usc_OutReg( info, RMR, RegValue ); - - /* Set the Receive count Limit Register (RCLR) to 0xffff. */ /* When an opening flag of an SDLC frame is recognized the */ /* Receive Character count (RCC) is loaded with the value in */ @@ -4822,9 +5151,9 @@ case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14 + BIT13; break; } - if ( info->params.crc_type == HDLC_CRC_16_CCITT ) + if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_16_CCITT ) RegValue |= BIT9 + BIT8; - else if ( info->params.crc_type == HDLC_CRC_32_CCITT ) + else if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_32_CCITT ) RegValue |= ( BIT12 | BIT10 | BIT9 | BIT8); usc_OutReg( info, TMR, RegValue ); @@ -5495,7 +5824,8 @@ usc_OutReg( info, CCSR, (u16)(usc_InReg(info,CCSR) | BIT13) ); usc_RTCmd( info, RTCmd_PurgeRxFifo ); - if ( info->params.mode == MGSL_MODE_HDLC ) { + if ( info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW ) { /* DMA mode Transfers */ /* Program the DMA controller. */ /* Enable the DMA controller end of buffer interrupt. */ @@ -5585,8 +5915,14 @@ /* Transmit DMA buffer is loaded, so program USC */ /* to send the frame contained in the buffers. */ + FrameSize = info->tx_buffer_list[info->start_tx_dma_buffer].rcc; - FrameSize = info->tx_buffer_list[0].rcc; + /* if operating in Raw sync mode, reset the rcc component + * of the tx dma buffer entry, otherwise, the serial controller + * will send a closing sync char after this count. + */ + if ( info->params.mode == MGSL_MODE_RAW ) + info->tx_buffer_list[info->start_tx_dma_buffer].rcc = 0; /* Program the Transmit Character Length Register (TCLR) */ /* and clear FIFO (TCC is loaded with TCLR on FIFO clear) */ @@ -5595,7 +5931,7 @@ usc_RTCmd( info, RTCmd_PurgeTxFifo ); /* Program the address of the 1st DMA Buffer Entry in linked list */ - phys_addr = info->tx_buffer_list[0].phys_entry; + phys_addr = info->tx_buffer_list[info->start_tx_dma_buffer].phys_entry; usc_OutDmaReg( info, NTARL, (u16)phys_addr ); usc_OutDmaReg( info, NTARU, (u16)(phys_addr >> 16) ); @@ -5603,6 +5939,19 @@ usc_ClearIrqPendingBits( info, TRANSMIT_STATUS ); usc_EnableInterrupts( info, TRANSMIT_STATUS ); + if ( info->params.mode == MGSL_MODE_RAW && + info->num_tx_dma_buffers > 1 ) { + /* When running external sync mode, attempt to 'stream' transmit */ + /* by filling tx dma buffers as they become available. To do this */ + /* we need to enable Tx DMA EOB Status interrupts : */ + /* */ + /* 1. Arm End of Buffer (EOB) Transmit DMA Interrupt (BIT2 of TDIAR) */ + /* 2. Enable Transmit DMA Interrupts (BIT0 of DICR) */ + + usc_OutDmaReg( info, TDIAR, BIT2|BIT3 ); + usc_OutDmaReg( info, DICR, (u16)(usc_InDmaReg(info,DICR) | BIT0) ); + } + /* Initialize Transmit DMA Channel */ usc_DmaCmd( info, DmaCmd_InitTxChannel ); @@ -6026,6 +6375,9 @@ void usc_loopback_frame( struct mgsl_struct *info ) { int i; + unsigned long oldmode = info->params.mode; + + info->params.mode = MGSL_MODE_HDLC; usc_DisableMasterIrqBit( info ); @@ -6079,6 +6431,8 @@ usc_EnableMasterIrqBit(info); + info->params.mode = oldmode; + } /* end of usc_loopback_frame() */ /* usc_set_sync_mode() Programs the USC for SDLC communications. @@ -6130,6 +6484,38 @@ info->tcsr_value += usc_idle_mode; usc_OutReg(info, TCSR, info->tcsr_value); + /* + * if SyncLink WAN adapter is running in external sync mode, the + * transmitter has been set to Monosync in order to try to mimic + * a true raw outbound bit stream. Monosync still sends an open/close + * sync char at the start/end of a frame. Try to match those sync + * patterns to the idle mode set here + */ + if ( info->params.mode == MGSL_MODE_RAW ) { + unsigned char syncpat = 0; + switch( info->idle_mode ) { + case HDLC_TXIDLE_FLAGS: + syncpat = 0x7e; + break; + case HDLC_TXIDLE_ALT_ZEROS_ONES: + syncpat = 0x55; + break; + case HDLC_TXIDLE_ZEROS: + case HDLC_TXIDLE_SPACE: + syncpat = 0x00; + break; + case HDLC_TXIDLE_ONES: + case HDLC_TXIDLE_MARK: + syncpat = 0xff; + break; + case HDLC_TXIDLE_ALT_MARK_SPACE: + syncpat = 0xaa; + break; + } + + usc_SetTransmitSyncChars(info,syncpat,syncpat); + } + } /* end of usc_set_txidle() */ /* usc_get_serial_signals() @@ -6307,6 +6693,48 @@ */ /* + * mgsl_reset_tx_dma_buffers() + * + * Set the count for all transmit buffers to 0 to indicate the + * buffer is available for use and set the current buffer to the + * first buffer. This effectively makes all buffers free and + * discards any data in buffers. + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info ) +{ + unsigned int i; + + for ( i = 0; i < info->tx_buffer_count; i++ ) { + *((unsigned long *)&(info->tx_buffer_list[i].count)) = 0; + } + + info->current_tx_buffer = 0; + info->start_tx_dma_buffer = 0; + info->tx_dma_buffers_used = 0; + + info->get_tx_holding_index = 0; + info->put_tx_holding_index = 0; + info->tx_holding_count = 0; + +} /* end of mgsl_reset_tx_dma_buffers() */ + +/* + * num_free_tx_dma_buffers() + * + * returns the number of free tx dma buffers available + * + * Arguments: info pointer to device instance data + * Return Value: number of free tx dma buffers + */ +int num_free_tx_dma_buffers(struct mgsl_struct *info) +{ + return info->tx_buffer_count - info->tx_dma_buffers_used; +} + +/* * mgsl_reset_rx_dma_buffers() * * Set the count for all receive buffers to DMABUFFERSIZE @@ -6392,10 +6820,11 @@ unsigned int StartIndex, EndIndex; /* index of 1st and last buffers of Rx frame */ unsigned short status; DMABUFFERENTRY *pBufEntry; - unsigned int framesize; + unsigned int framesize = 0; int ReturnCode = 0; unsigned long flags; struct tty_struct *tty = info->tty; + int return_frame = 0; /* * current_rx_buffer points to the 1st buffer of the next available @@ -6451,14 +6880,20 @@ info->icount.rxabort++; else if ( status & RXSTATUS_OVERRUN ) info->icount.rxover++; - else + else { info->icount.rxcrc++; + if ( info->params.crc_type & HDLC_CRC_RETURN_EX ) + return_frame = 1; + } framesize = 0; #ifdef CONFIG_SYNCLINK_SYNCPPP info->netstats.rx_errors++; info->netstats.rx_frame_errors++; #endif - } else { + } else + return_frame = 1; + + if ( return_frame ) { /* receive frame has no errors, get frame size. * The frame size is the starting value of the RCC (which was * set to 0xffff) minus the ending value of the RCC (decremented @@ -6483,7 +6918,9 @@ MIN(framesize,DMABUFFERSIZE),0); if (framesize) { - if (framesize > info->max_frame_size) + if ( ( (info->params.crc_type & HDLC_CRC_RETURN_EX) && + ((framesize+1) > info->max_frame_size) ) || + (framesize > info->max_frame_size) ) info->icount.rxlong++; else { /* copy dma buffer(s) to contiguous intermediate buffer */ @@ -6491,6 +6928,7 @@ int index = StartIndex; unsigned char *ptmp = info->intermediate_rxbuffer; + if ( !(status & RXSTATUS_CRC_ERROR)) info->icount.rxok++; while(copy_count) { @@ -6509,6 +6947,18 @@ index = 0; } + if ( info->params.crc_type & HDLC_CRC_RETURN_EX ) { + ++framesize; + *ptmp = (status & RXSTATUS_CRC_ERROR ? + RX_CRC_ERROR : + RX_OK); + + if ( debug_level >= DEBUG_LEVEL_DATA ) + printk("%s(%d):mgsl_get_rx_frame(%s) rx frame status=%d\n", + __FILE__,__LINE__,info->device_name, + *ptmp); + } + #ifdef CONFIG_SYNCLINK_SYNCPPP if (info->netcount) { /* pass frame to syncppp device */ @@ -6518,6 +6968,7 @@ #endif { /* Call the line discipline receive callback directly. */ + if ( tty && tty->ldisc.receive_buf ) tty->ldisc.receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); } } @@ -6547,6 +6998,180 @@ } /* end of mgsl_get_rx_frame() */ +/* mgsl_get_raw_rx_frame() + * + * This function attempts to return a received frame from the + * receive DMA buffers when running in external loop mode. In this mode, + * we will return at most one DMABUFFERSIZE frame to the application. + * The USC receiver is triggering off of DCD going active to start a new + * frame, and DCD going inactive to terminate the frame (similar to + * processing a closing flag character). + * + * In this routine, we will return DMABUFFERSIZE "chunks" at a time. + * If DCD goes inactive, the last Rx DMA Buffer will have a non-zero + * status field and the RCC field will indicate the length of the + * entire received frame. We take this RCC field and get the modulus + * of RCC and DMABUFFERSIZE to determine if number of bytes in the + * last Rx DMA buffer and return that last portion of the frame. + * + * Arguments: info pointer to device extension + * Return Value: 1 if frame returned, otherwise 0 + */ +int mgsl_get_raw_rx_frame(struct mgsl_struct *info) +{ + unsigned int CurrentIndex, NextIndex; + unsigned short status; + DMABUFFERENTRY *pBufEntry; + unsigned int framesize = 0; + int ReturnCode = 0; + unsigned long flags; + struct tty_struct *tty = info->tty; + + /* + * current_rx_buffer points to the 1st buffer of the next available + * receive frame. The status field is set by the 16C32 after + * completing a receive frame. If the status field of this buffer + * is zero, either the USC is still filling this buffer or this + * is one of a series of buffers making up a received frame. + * + * If the count field of this buffer is zero, the USC is either + * using this buffer or has used this buffer. Look at the count + * field of the next buffer. If that next buffer's count is + * non-zero, the USC is still actively using the current buffer. + * Otherwise, if the next buffer's count field is zero, the + * current buffer is complete and the USC is using the next + * buffer. + */ + CurrentIndex = NextIndex = info->current_rx_buffer; + ++NextIndex; + if ( NextIndex == info->rx_buffer_count ) + NextIndex = 0; + + if ( info->rx_buffer_list[CurrentIndex].status != 0 || + (info->rx_buffer_list[CurrentIndex].count == 0 && + info->rx_buffer_list[NextIndex].count == 0)) { + /* + * Either the status field of this dma buffer is non-zero + * (indicating the last buffer of a receive frame) or the next + * buffer is marked as in use -- implying this buffer is complete + * and an intermediate buffer for this received frame. + */ + + status = info->rx_buffer_list[CurrentIndex].status; + + if ( status & (RXSTATUS_SHORT_FRAME + RXSTATUS_OVERRUN + + RXSTATUS_CRC_ERROR + RXSTATUS_ABORT) ) { + if ( status & RXSTATUS_SHORT_FRAME ) + info->icount.rxshort++; + else if ( status & RXSTATUS_ABORT ) + info->icount.rxabort++; + else if ( status & RXSTATUS_OVERRUN ) + info->icount.rxover++; + else + info->icount.rxcrc++; + framesize = 0; + } else { + /* + * A receive frame is available, get frame size and status. + * + * The frame size is the starting value of the RCC (which was + * set to 0xffff) minus the ending value of the RCC (decremented + * once for each receive character) minus 2 or 4 for the 16-bit + * or 32-bit CRC. + * + * If the status field is zero, this is an intermediate buffer. + * It's size is 4K. + * + * If the DMA Buffer Entry's Status field is non-zero, the + * receive operation completed normally (ie: DCD dropped). The + * RCC field is valid and holds the received frame size. + * It is possible that the RCC field will be zero on a DMA buffer + * entry with a non-zero status. This can occur if the total + * frame size (number of bytes between the time DCD goes active + * to the time DCD goes inactive) exceeds 65535 bytes. In this + * case the 16C32 has underrun on the RCC count and appears to + * stop updating this counter to let us know the actual received + * frame size. If this happens (non-zero status and zero RCC), + * simply return the entire RxDMA Buffer + */ + if ( status ) { + /* + * In the event that the final RxDMA Buffer is + * terminated with a non-zero status and the RCC + * field is zero, we interpret this as the RCC + * having underflowed (received frame > 65535 bytes). + * + * Signal the event to the user by passing back + * a status of RxStatus_CrcError returning the full + * buffer and let the app figure out what data is + * actually valid + */ + if ( info->rx_buffer_list[CurrentIndex].rcc ) + framesize = RCLRVALUE - info->rx_buffer_list[CurrentIndex].rcc; + else + framesize = DMABUFFERSIZE; + } + else + framesize = DMABUFFERSIZE; + } + + if ( framesize > DMABUFFERSIZE ) { + /* + * if running in raw sync mode, ISR handler for + * End Of Buffer events terminates all buffers at 4K. + * If this frame size is said to be >4K, get the + * actual number of bytes of the frame in this buffer. + */ + framesize = framesize % DMABUFFERSIZE; + } + + + if ( debug_level >= DEBUG_LEVEL_BH ) + printk("%s(%d):mgsl_get_raw_rx_frame(%s) status=%04X size=%d\n", + __FILE__,__LINE__,info->device_name,status,framesize); + + if ( debug_level >= DEBUG_LEVEL_DATA ) + mgsl_trace_block(info,info->rx_buffer_list[CurrentIndex].virt_addr, + MIN(framesize,DMABUFFERSIZE),0); + + if (framesize) { + /* copy dma buffer(s) to contiguous intermediate buffer */ + /* NOTE: we never copy more than DMABUFFERSIZE bytes */ + + pBufEntry = &(info->rx_buffer_list[CurrentIndex]); + memcpy( info->intermediate_rxbuffer, pBufEntry->virt_addr, framesize); + info->icount.rxok++; + + /* Call the line discipline receive callback directly. */ + if ( tty && tty->ldisc.receive_buf ) + tty->ldisc.receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); + } + + /* Free the buffers used by this frame. */ + mgsl_free_rx_frame_buffers( info, CurrentIndex, CurrentIndex ); + + ReturnCode = 1; + } + + + if ( info->rx_enabled && info->rx_overflow ) { + /* The receiver needs to restarted because of + * a receive overflow (buffer or FIFO). If the + * receive buffers are now empty, then restart receiver. + */ + + if ( !info->rx_buffer_list[CurrentIndex].status && + info->rx_buffer_list[CurrentIndex].count ) { + spin_lock_irqsave(&info->irq_spinlock,flags); + usc_start_receiver(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + } + } + + return ReturnCode; + +} /* end of mgsl_get_raw_rx_frame() */ + /* mgsl_load_tx_dma_buffer() * * Load the transmit DMA buffer with the specified data. @@ -6576,12 +7201,19 @@ info->cmr_value |= BIT13; } + /* begin loading the frame in the next available tx dma + * buffer, remember it's starting location for setting + * up tx dma operation + */ + i = info->current_tx_buffer; + info->start_tx_dma_buffer = i; + /* Setup the status and RCC (Frame Size) fields of the 1st */ /* buffer entry in the transmit DMA buffer list. */ - info->tx_buffer_list[0].status = info->cmr_value & 0xf000; - info->tx_buffer_list[0].rcc = BufferSize; - info->tx_buffer_list[0].count = BufferSize; + info->tx_buffer_list[i].status = info->cmr_value & 0xf000; + info->tx_buffer_list[i].rcc = BufferSize; + info->tx_buffer_list[i].count = BufferSize; /* Copy frame data from 1st source buffer to the DMA buffers. */ /* The frame data may span multiple DMA buffers. */ @@ -6590,6 +7222,9 @@ /* Get a pointer to next DMA buffer entry. */ pBufEntry = &info->tx_buffer_list[i++]; + if ( i == info->tx_buffer_count ) + i=0; + /* Calculate the number of bytes that can be copied from */ /* the source buffer to this DMA buffer. */ if ( BufferSize > DMABUFFERSIZE ) @@ -6609,8 +7244,13 @@ /* Advance source pointer and reduce remaining data count. */ Buffer += Copycount; BufferSize -= Copycount; + + ++info->tx_dma_buffers_used; } + /* remember next available tx dma buffer */ + info->current_tx_buffer = i; + } /* end of mgsl_load_tx_dma_buffer() */ /* @@ -6741,7 +7381,7 @@ unsigned int i; char *TmpPtr; BOOLEAN rc = TRUE; - unsigned short status; + unsigned short status=0; unsigned long EndTime; unsigned long flags; MGSL_PARAMS tmp_params; @@ -6998,7 +7638,7 @@ status = info->rx_buffer_list[0].status; if ( status & (BIT8 + BIT3 + BIT1) ) { - /* receive error has occurred */ + /* receive error has occured */ rc = FALSE; } else { if ( memcmp( info->tx_buffer_list[0].virt_addr , @@ -7219,7 +7859,9 @@ if ( debug_level >= DEBUG_LEVEL_INFO ) printk( "%s(%d):mgsl_tx_timeout(%s)\n", __FILE__,__LINE__,info->device_name); - if(info->tx_active && info->params.mode == MGSL_MODE_HDLC) { + if(info->tx_active && + (info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW) ) { info->icount.txtimeout++; } spin_lock_irqsave(&info->irq_spinlock,flags); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/sysrq.c linux.ac/drivers/char/sysrq.c --- linux.vanilla/drivers/char/sysrq.c Fri Feb 9 19:30:22 2001 +++ linux.ac/drivers/char/sysrq.c Tue Apr 17 16:27:45 2001 @@ -6,6 +6,10 @@ * * (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz> * based on ideas by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz> + * + * (c) 2000 Crutcher Dunnavant <crutcher@redhat.com> + * overhauled to use key registration + * based upon discusions in irc://irc.openprojects.net/#kernelnewbies */ #include <linux/config.h> @@ -23,6 +27,9 @@ #include <linux/quotaops.h> #include <linux/smp_lock.h> #include <linux/module.h> +#include <linux/irq.h> + +#include <linux/spinlock.h> #include <asm/ptrace.h> @@ -36,130 +43,71 @@ /* Machine specific power off function */ void (*sysrq_power_off)(void); -EXPORT_SYMBOL(sysrq_power_off); - -/* Send a signal to all user processes */ +/* Loglevel sysrq handler */ +static void sysrq_handle_loglevel(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) { + int i; + i = key - '0'; + console_loglevel = 7; + printk("%d\n", i); + console_loglevel = i; +} +static struct sysrq_key_op sysrq_loglevel_op = { + handler: sysrq_handle_loglevel, + help_msg: "loglevel0-8", + action_msg: "Loglevel set to ", +}; -static void send_sig_all(int sig, int even_init) -{ - struct task_struct *p; - for_each_task(p) { - if (p->mm) { /* Not swapper nor kernel thread */ - if (p->pid == 1 && even_init) /* Ugly hack to kill init */ - p->pid = 0x8000; - force_sig(sig, p); - } - } +/* SAK sysrq handler */ +#ifdef CONFIG_VT +static void sysrq_handle_SAK(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) { + if (tty) + do_SAK(tty); + reset_vc(fg_console); } +static struct sysrq_key_op sysrq_SAK_op = { + handler: sysrq_handle_SAK, + help_msg: "saK", + action_msg: "SAK\n", +}; +#endif -/* - * This function is called by the keyboard handler when SysRq is pressed - * and any other keycode arrives. - */ -void handle_sysrq(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) -{ - int orig_log_level = console_loglevel; +/* unraw sysrq handler */ +static void sysrq_handle_unraw(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) { + if (kbd) + kbd->kbdmode = VC_XLATE; +} +static struct sysrq_key_op sysrq_unraw_op = { + handler: sysrq_handle_unraw, + help_msg: "unRaw", + action_msg: "Keyboard mode set to XLATE\n", +}; - if (!sysrq_enabled) - return; - if (!key) - return; +/* reboot sysrq handler */ +static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) { + machine_restart(NULL); +} +static struct sysrq_key_op sysrq_reboot_op = { + handler: sysrq_handle_reboot, + help_msg: "reBoot", + action_msg: "Resetting\n", +}; - console_loglevel = 7; - printk(KERN_INFO "SysRq: "); - switch (key) { - case 'r': /* R -- Reset raw mode */ - if (kbd) { - kbd->kbdmode = VC_XLATE; - printk("Keyboard mode set to XLATE\n"); - } - break; -#ifdef CONFIG_VT - case 'k': /* K -- SAK */ - printk("SAK\n"); - if (tty) - do_SAK(tty); - reset_vc(fg_console); - break; -#endif - case 'b': /* B -- boot immediately */ - printk("Resetting\n"); - machine_restart(NULL); - break; - case 'o': /* O -- power off */ - if (sysrq_power_off) { - printk("Power off\n"); - sysrq_power_off(); - } - break; - case 's': /* S -- emergency sync */ - printk("Emergency Sync\n"); - emergency_sync_scheduled = EMERG_SYNC; - wakeup_bdflush(0); - break; - case 'u': /* U -- emergency remount R/O */ - printk("Emergency Remount R/O\n"); - emergency_sync_scheduled = EMERG_REMOUNT; - wakeup_bdflush(0); - break; - case 'p': /* P -- show PC */ - printk("Show Regs\n"); - if (pt_regs) - show_regs(pt_regs); - break; - case 't': /* T -- show task info */ - printk("Show State\n"); - show_state(); - break; - case 'm': /* M -- show memory info */ - printk("Show Memory\n"); - show_mem(); - break; - case '0' ... '9': /* 0-9 -- set console logging level */ - orig_log_level = key - '0'; - printk("Log level set to %d\n", orig_log_level); - break; - case 'e': /* E -- terminate all user processes */ - printk("Terminate All Tasks\n"); - send_sig_all(SIGTERM, 0); - orig_log_level = 8; /* We probably have killed syslogd */ - break; - case 'i': /* I -- kill all user processes */ - printk("Kill All Tasks\n"); - send_sig_all(SIGKILL, 0); - orig_log_level = 8; - break; - case 'l': /* L -- kill all processes including init */ - printk("Kill ALL Tasks (even init)\n"); - send_sig_all(SIGKILL, 1); - orig_log_level = 8; - break; - default: /* Unknown: help */ - if (kbd) - printk("unRaw "); -#ifdef CONFIG_VT - if (tty) - printk("saK "); -#endif - printk("Boot "); - if (sysrq_power_off) - printk("Off "); - printk("Sync Unmount showPc showTasks showMem loglevel0-8 tErm kIll killalL\n"); - /* Don't use 'A' as it's handled specially on the Sparc */ - } - console_loglevel = orig_log_level; -} -/* Aux routines for the syncer */ +/* SYNC SYSRQ HANDLERS BLOCK */ -static int is_local_disk(kdev_t dev) /* Guess if the device is a local hard drive */ -{ - unsigned int major = MAJOR(dev); +/* do_emergency_sync helper function */ +/* Guesses if the device is a local hard drive */ +static int is_local_disk(kdev_t dev) { + unsigned int major; + major = MAJOR(dev); switch (major) { case IDE0_MAJOR: @@ -180,13 +128,17 @@ } } +/* do_emergency_sync helper function */ static void go_sync(struct super_block *sb, int remount_flag) { + int orig_loglevel; + orig_loglevel = console_loglevel; + console_loglevel = 7; printk(KERN_INFO "%sing device %s ... ", remount_flag ? "Remount" : "Sync", kdevname(sb->s_dev)); - if (remount_flag) { /* Remount R/O */ + if (remount_flag) { /* Remount R/O */ int ret, flags; struct list_head *p; @@ -216,12 +168,12 @@ } } else printk("nothing to do\n"); - } else { - fsync_dev(sb->s_dev); /* Sync only */ + } else { /* Sync only */ + fsync_dev(sb->s_dev); printk("OK\n"); } + console_loglevel = orig_loglevel; } - /* * Emergency Sync or Unmount. We cannot do it directly, so we set a special * flag and wake up the bdflush kernel thread which immediately calls this function. @@ -231,10 +183,10 @@ int emergency_sync_scheduled; -void do_emergency_sync(void) -{ +void do_emergency_sync(void) { struct super_block *sb; int remount_flag; + int orig_loglevel; lock_kernel(); remount_flag = (emergency_sync_scheduled == EMERG_REMOUNT); @@ -253,5 +205,270 @@ go_sync(sb, remount_flag); unlock_kernel(); + + orig_loglevel = console_loglevel; + console_loglevel = 7; printk(KERN_INFO "Done.\n"); + console_loglevel = orig_loglevel; +} + +static void sysrq_handle_sync(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) { + emergency_sync_scheduled = EMERG_SYNC; + wakeup_bdflush(0); +} +static struct sysrq_key_op sysrq_sync_op = { + handler: sysrq_handle_sync, + help_msg: "Sync", + action_msg: "Emergency Sync\n", +}; + +static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) { + emergency_sync_scheduled = EMERG_REMOUNT; + wakeup_bdflush(0); +} +static struct sysrq_key_op sysrq_mountro_op = { + handler: sysrq_handle_mountro, + help_msg: "Unmount", + action_msg: "Emergency Remount R/0\n", +}; + +/* END SYNC SYSRQ HANDLERS BLOCK */ + + +/* SHOW SYSRQ HANDLERS BLOCK */ + +static void sysrq_handle_showregs(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) { + if (pt_regs) + show_regs(pt_regs); +} +static struct sysrq_key_op sysrq_showregs_op = { + handler: sysrq_handle_showregs, + help_msg: "showPc", + action_msg: "Show Regs\n", +}; + + +static void sysrq_handle_showstate(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) { + show_state(); +} +static struct sysrq_key_op sysrq_showstate_op = { + handler: sysrq_handle_showstate, + help_msg: "showTasks", + action_msg: "Show State\n", +}; + + +static void sysrq_handle_showmem(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) { + show_mem(); +} +static struct sysrq_key_op sysrq_showmem_op = { + handler: sysrq_handle_showmem, + help_msg: "showMem", + action_msg: "Show Memory\n", +}; + +/* SHOW SYSRQ HANDLERS BLOCK */ + + +/* SIGNAL SYSRQ HANDLERS BLOCK */ + +/* signal sysrq helper function + * Sends a signal to all user processes */ +static void send_sig_all(int sig, int even_init) +{ + struct task_struct *p; + + for_each_task(p) { + if (p->mm) { /* Not swapper nor kernel thread */ + if (p->pid == 1 && even_init) + /* Ugly hack to kill init */ + p->pid = 0x8000; + force_sig(sig, p); + } + } +} + +static void sysrq_handle_term(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) { + send_sig_all(SIGTERM, 0); + console_loglevel = 8; +} +static struct sysrq_key_op sysrq_term_op = { + handler: sysrq_handle_term, + help_msg: "tErm", + action_msg: "Terminate All Tasks\n", +}; + +static void sysrq_handle_kill(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) { + send_sig_all(SIGKILL, 0); + console_loglevel = 8; +} +static struct sysrq_key_op sysrq_kill_op = { + handler: sysrq_handle_kill, + help_msg: "kIll", + action_msg: "Kill All Tasks\n", +}; + +static void sysrq_handle_killall(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) { + send_sig_all(SIGKILL, 1); + console_loglevel = 8; +} +static struct sysrq_key_op sysrq_killall_op = { + handler: sysrq_handle_killall, + help_msg: "killalL", + action_msg: "Kill All Tasks (even init)\n", +}; + +/* END SIGNAL SYSRQ HANDLERS BLOCK */ + + +/* Key Operations table and lock */ +spinlock_t sysrq_key_table_lock = SPIN_LOCK_UNLOCKED; +#define SYSRQ_KEY_TABLE_LENGTH 36 +static struct sysrq_key_op *sysrq_key_table[SYSRQ_KEY_TABLE_LENGTH] = { +/* 0 */ &sysrq_loglevel_op, +/* 1 */ &sysrq_loglevel_op, +/* 2 */ &sysrq_loglevel_op, +/* 3 */ &sysrq_loglevel_op, +/* 4 */ &sysrq_loglevel_op, +/* 5 */ &sysrq_loglevel_op, +/* 6 */ &sysrq_loglevel_op, +/* 7 */ &sysrq_loglevel_op, +/* 8 */ &sysrq_loglevel_op, +/* 9 */ &sysrq_loglevel_op, +/* a */ NULL, /* Don't use for system provided sysrqs, + it is handled specially on the spark + and will never arive */ +/* b */ &sysrq_reboot_op, +/* c */ NULL, +/* d */ NULL, +/* e */ &sysrq_term_op, +/* f */ NULL, +/* g */ NULL, +/* h */ NULL, +/* i */ &sysrq_kill_op, +/* j */ NULL, +#ifdef CONFIG_VT +/* k */ &sysrq_SAK_op, +#else +/* k */ NULL, +#endif +/* l */ &sysrq_killall_op, +/* m */ &sysrq_showmem_op, +/* n */ NULL, +/* o */ NULL, /* This will often be registered + as 'Off' at init time */ +/* p */ &sysrq_showregs_op, +/* q */ NULL, +/* r */ &sysrq_unraw_op, +/* s */ &sysrq_sync_op, +/* t */ &sysrq_showstate_op, +/* u */ &sysrq_mountro_op, +/* v */ NULL, +/* w */ NULL, +/* x */ NULL, +/* w */ NULL, +/* z */ NULL +}; + +/* key2index calculation, -1 on invalid index */ +static __inline__ int sysrq_key_table_key2index(int key) { + int retval; + if ((key >= '0') & (key <= '9')) { + retval = key - '0'; + } else if ((key >= 'a') & (key <= 'z')) { + retval = key + 10 - 'a'; + } else { + retval = -1; + } + return retval; +} + +/* + * table lock and unlocking functions, exposed to modules + */ + +void __sysrq_lock_table (void) { spin_lock(&sysrq_key_table_lock); } + +void __sysrq_unlock_table (void) { spin_unlock(&sysrq_key_table_lock); } + +/* + * get and put functions for the table, exposed to modules. + */ + +struct sysrq_key_op *__sysrq_get_key_op (int key) { + struct sysrq_key_op *op_p; + int i; + + i = sysrq_key_table_key2index(key); + op_p = (i == -1) ? NULL : sysrq_key_table[i]; + return op_p; } + +void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p) { + int i; + + i = sysrq_key_table_key2index(key); + if (i != -1) + sysrq_key_table[i] = op_p; +} + +/* + * This function is called by the keyboard handler when SysRq is pressed + * and any other keycode arrives. + */ + +void handle_sysrq(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) { + if (!sysrq_enabled) + return; + + __sysrq_lock_table(); + __handle_sysrq_nolock(key, pt_regs, kbd, tty); + __sysrq_unlock_table(); +} + +/* + * This is the non-locking version of handle_sysrq + * It must/can only be called by sysrq key handlers, + * as they are inside of the lock + */ + +void __handle_sysrq_nolock(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) { + struct sysrq_key_op *op_p; + int orig_log_level; + int i, j; + + if (!sysrq_enabled) + return; + + orig_log_level = console_loglevel; + console_loglevel = 7; + printk(KERN_INFO "SysRq : "); + + op_p = __sysrq_get_key_op(key); + if (op_p) { + printk ("%s", op_p->action_msg); + op_p->handler(key, pt_regs, kbd, tty); + } else { + printk("HELP : "); + /* Only print the help msg once per handler */ + for (i=0; i<SYSRQ_KEY_TABLE_LENGTH; i++) + if (sysrq_key_table[i]) { + for (j=0; sysrq_key_table[i] != sysrq_key_table[j]; j++); + if (j == i) + printk ("%s ", sysrq_key_table[i]->help_msg); + } + printk ("\n"); + } + console_loglevel = orig_log_level; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/toshiba.c linux.ac/drivers/char/toshiba.c --- linux.vanilla/drivers/char/toshiba.c Wed Sep 27 21:53:56 2000 +++ linux.ac/drivers/char/toshiba.c Tue Apr 10 18:14:58 2001 @@ -1,19 +1,24 @@ /* toshiba.c -- Linux driver for accessing the SMM on Toshiba laptops * - * Copyright (c) 1996-2000 Jonathan A. Buzzard (jonathan@buzzard.org.uk) + * Copyright (c) 1996-2001 Jonathan A. Buzzard (jonathan@buzzard.org.uk) * * Valuable assistance and patches from: * Tom May <tom@you-bastards.com> * Rob Napier <rnapier@employees.org> * * Fn status port numbers for machine ID's courtesy of + * 0xfc02: Scott Eisert <scott.e@sky-eye.com> + * 0xfc04: Steve VanDevender <stevev@efn.org> * 0xfc08: Garth Berry <garth@itsbruce.net> + * 0xfc0a: Egbert Eich <eich@xfree86.org> + * 0xfc10: Andrew Lofthouse <Andrew.Lofthouse@robins.af.mil> * 0xfc11: Spencer Olson <solson@novell.com> * 0xfc13: Claudius Frankewitz <kryp@gmx.de> * 0xfc15: Tom May <tom@you-bastards.com> * 0xfc17: Dave Konrad <konrad@xenia.it> * 0xfc1a: George Betzos <betzos@engr.colostate.edu> * 0xfc1d: Arthur Liu <armie@slap.mine.nu> + * 0xfcd1: Mr. Dave Konrad <konrad@xenia.it> * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * @@ -46,7 +51,7 @@ * */ -#define TOSH_VERSION "1.7 22/6/2000" +#define TOSH_VERSION "1.9 22/3/2001" #define TOSH_DEBUG 0 #include <linux/module.h> @@ -117,27 +122,6 @@ /* - * At some point we need to emulate setting the HDD auto off times for - * the new laptops. We can do this by calling the ide_ioctl on /dev/hda. - * The values we need for the various times are - * - * Disabled 0x00 - * 1 minute 0x0c - * 3 minutes 0x24 - * 5 minutes 0x3c - * 10 minutes 0x78 - * 15 minutes 0xb4 - * 20 minutes 0xf0 - * 30 minutes 0xf1 - * - */ -/*static int tosh_emulate_hdd(SMMRegisters *regs) -{ - return 0; -}*/ - - -/* * For the Portage 610CT and the Tecra 700CS/700CDT emulate the HCI fan function */ static int tosh_emulate_fan(SMMRegisters *regs) @@ -348,11 +332,12 @@ static void tosh_set_fn_port(void) { switch (tosh_id) { + case 0xfc02: case 0xfc04: case 0xfc09: case 0xfc0a: case 0xfc10: case 0xfc11: case 0xfc13: case 0xfc15: case 0xfc1a: tosh_fn = 0x62; break; - case 0xfc08: case 0xfc17: case 0xfc1d: case 0xfcd1: - case 0xfce0: case 0xfce2: + case 0xfc08: case 0xfc17: case 0xfc1d: case 0xfcd1: case 0xfce0: + case 0xfce2: tosh_fn = 0x68; break; default: @@ -472,7 +457,6 @@ 0xa0-0xbf we can't. We just have to live dangerously and use the ports anyway, oh boy! */ - /* do we need to emulate the fan? */ if ((tosh_id==0xfccb) || (tosh_id==0xfccc)) @@ -501,7 +485,9 @@ misc_register(&tosh_device); /* register the proc entry */ + create_proc_info_entry("toshiba", 0, NULL, tosh_get_info); + return 0; } @@ -514,9 +500,11 @@ void cleanup_module(void) { /* remove the proc entry */ + remove_proc_entry("toshiba", NULL); /* unregister the device file */ + misc_deregister(&tosh_device); } #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/tty_io.c linux.ac/drivers/char/tty_io.c --- linux.vanilla/drivers/char/tty_io.c Tue Apr 3 17:32:02 2001 +++ linux.ac/drivers/char/tty_io.c Mon Apr 9 23:41:02 2001 @@ -61,6 +61,9 @@ * Reduced memory usage for older ARM systems * -- Russell King <rmk@arm.linux.org.uk> * + * Don't call close after a failed open. + * -- Maciej W. Rozycki <macro@ds2.pg.gda.pl>, 21-Jan-2001 + * * Move do_SAK() into process context. Less stack use in devfs functions. * alloc_tty_struct() always uses kmalloc() -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01 */ @@ -125,6 +128,12 @@ extern struct tty_driver ptm_driver[]; /* Unix98 pty masters; for /dev/ptmx */ extern struct tty_driver pts_driver[]; /* Unix98 pty slaves; for /dev/ptmx */ #endif +#ifdef CONFIG_3270 +extern void tub3270_initfunc(void); +#ifdef CONFIG_3270_CONSOLE +extern void tub3270_con_init(void); +#endif +#endif /* * redirect is the pseudo-tty that console output @@ -148,8 +157,11 @@ extern long serial167_console_init(void); extern void console_8xx_init(void); extern int rs_8xx_init(void); +extern void mac_scc_console_init(void); extern void hwc_console_init(void); +extern void hwc_tty_init(void); extern void con3215_init(void); +extern void tty3215_init(void); extern void rs285_console_init(void); extern void sa1100_rs_console_init(void); extern void sgi_serial_console_init(void); @@ -1039,7 +1051,7 @@ * WSH 09/09/97: rewritten to avoid some nasty race conditions that could * lead to double frees or releasing memory still in use. */ -static void release_dev(struct file * filp) +static void release_dev(struct file * filp, int do_close) { struct tty_struct *tty, *o_tty; int pty_master, tty_closing, o_tty_closing, do_sleep; @@ -1117,7 +1129,7 @@ } #endif - if (tty->driver.close) + if (do_close && tty->driver.close) tty->driver.close(tty, filp); /* @@ -1193,7 +1205,7 @@ * We've decremented tty->count, so we should zero out * filp->private_data, to break the link between the tty and * the file descriptor. Otherwise if filp_close() blocks before - * the the file descriptor is removed from the inuse_filp + * the file descriptor is removed from the inuse_filp * list, check_tty_count() could observe a discrepancy and * printk a warning message to the user. */ @@ -1280,7 +1292,7 @@ static int tty_open(struct inode * inode, struct file * filp) { struct tty_struct *tty; - int noctty, retval; + int noctty, retval, open_ok; kdev_t device; unsigned short saved_flags; char buf[64]; @@ -1365,9 +1377,12 @@ #ifdef TTY_DEBUG_HANGUP printk("opening %s...", tty_name(tty, buf)); #endif - if (tty->driver.open) + open_ok = 0; + if (tty->driver.open) { retval = tty->driver.open(tty, filp); - else + if (!retval) + open_ok = 1; + } else retval = -ENODEV; filp->f_flags = saved_flags; @@ -1380,7 +1395,7 @@ tty_name(tty, buf)); #endif - release_dev(filp); + release_dev(filp, open_ok); if (retval != -ERESTARTSYS) return retval; if (signal_pending(current)) @@ -1422,7 +1437,7 @@ static int tty_release(struct inode * inode, struct file * filp) { lock_kernel(); - release_dev(filp); + release_dev(filp, 1); unlock_kernel(); return 0; } @@ -2050,6 +2065,7 @@ EXPORT_SYMBOL(tty_register_devfs); EXPORT_SYMBOL(tty_unregister_devfs); +EXPORT_SYMBOL(tty_register_ldisc); /* * Called by a tty driver to register itself. @@ -2180,6 +2196,10 @@ #ifdef CONFIG_SERIAL_CONSOLE #if (defined(CONFIG_8xx) || defined(CONFIG_8260)) console_8xx_init(); +#elif defined(CONFIG_MAC_SERIAL) + mac_scc_console_init(); +#elif defined(CONFIG_PARISC) + pdc_console_init(); #elif defined(CONFIG_SERIAL) serial_console_init(); #endif /* CONFIG_8xx */ @@ -2199,9 +2219,15 @@ #ifdef CONFIG_3215 con3215_init(); #endif +#ifdef CONFIG_3270_CONSOLE + tub3270_con_init(); +#endif #ifdef CONFIG_HWC hwc_console_init(); #endif +#ifdef CONFIG_STDIO_CONSOLE + stdio_console_init(); +#endif #ifdef CONFIG_SERIAL_21285_CONSOLE rs285_console_init(); #endif @@ -2342,5 +2368,14 @@ #endif #ifdef CONFIG_VT vcs_init(); +#endif +#ifdef CONFIG_3215 + tty3215_init(); +#endif +#ifdef CONFIG_HWC + hwc_tty_init(); +#endif +#ifdef CONFIG_3270 + tub3270_initfunc(); #endif } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/tty_ioctl.c linux.ac/drivers/char/tty_ioctl.c --- linux.vanilla/drivers/char/tty_ioctl.c Thu Mar 16 03:48:06 2000 +++ linux.ac/drivers/char/tty_ioctl.c Tue Apr 3 17:54:41 2001 @@ -18,6 +18,7 @@ #include <linux/fcntl.h> #include <linux/string.h> #include <linux/mm.h> +#include <linux/module.h> #include <asm/io.h> #include <asm/bitops.h> @@ -519,3 +520,5 @@ return -ENOIOCTLCMD; } } + +EXPORT_SYMBOL(n_tty_ioctl); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/vc_screen.c linux.ac/drivers/char/vc_screen.c --- linux.vanilla/drivers/char/vc_screen.c Mon Oct 16 20:58:51 2000 +++ linux.ac/drivers/char/vc_screen.c Tue Apr 3 17:54:41 2001 @@ -109,7 +109,7 @@ /* Select the proper current console and verify * sanity of the situation under the console lock. */ - spin_lock_irq(&console_lock); + acquire_console_sem(); attr = (currcons & 128); currcons = (currcons & 127); @@ -232,13 +232,16 @@ } } - /* Finally, temporarily drop the console lock and push + /* Finally, release the console semaphore while we push * all the data to userspace from our temporary buffer. + * + * AKPM: Even though it's a semaphore, we should drop it because + * the pagefault handling code may want to call printk(). */ - spin_unlock_irq(&console_lock); + release_console_sem(); ret = copy_to_user(buf, con_buf_start, orig_count); - spin_lock_irq(&console_lock); + acquire_console_sem(); if (ret) { read += (orig_count - ret); @@ -254,7 +257,7 @@ if (read) ret = read; unlock_out: - spin_unlock_irq(&console_lock); + release_console_sem(); up(&con_buf_sem); return ret; } @@ -276,7 +279,7 @@ /* Select the proper current console and verify * sanity of the situation under the console lock. */ - spin_lock_irq(&console_lock); + acquire_console_sem(); attr = (currcons & 128); currcons = (currcons & 127); @@ -310,9 +313,9 @@ /* Temporarily drop the console lock so that we can read * in the write data from userspace safely. */ - spin_unlock_irq(&console_lock); + release_console_sem(); ret = copy_from_user(con_buf, buf, this_round); - spin_lock_irq(&console_lock); + acquire_console_sem(); if (ret) { this_round -= ret; @@ -436,7 +439,7 @@ ret = written; unlock_out: - spin_unlock_irq(&console_lock); + release_console_sem(); up(&con_buf_sem); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/vme_scc.c linux.ac/drivers/char/vme_scc.c --- linux.vanilla/drivers/char/vme_scc.c Fri Feb 9 19:30:22 2001 +++ linux.ac/drivers/char/vme_scc.c Tue Apr 3 17:54:41 2001 @@ -1047,7 +1047,7 @@ *p = ch; } -/* The console_lock must be held when we get here. */ +/* The console must be locked when we get here. */ static void scc_console_write (struct console *co, const char *str, unsigned count) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/vt.c linux.ac/drivers/char/vt.c --- linux.vanilla/drivers/char/vt.c Fri Feb 9 19:30:22 2001 +++ linux.ac/drivers/char/vt.c Tue Apr 3 17:54:41 2001 @@ -23,6 +23,7 @@ #include <linux/major.h> #include <linux/fs.h> #include <linux/console.h> +#include <linux/irq.h> #include <asm/io.h> #include <asm/uaccess.h> @@ -833,9 +834,9 @@ * make sure we are atomic with respect to * other console switches.. */ - spin_lock_irq(&console_lock); + acquire_console_sem(); complete_change_console(newvt); - spin_unlock_irq(&console_lock); + release_console_sem(); } } @@ -1169,7 +1170,8 @@ vt_cons[new_console]->vt_mode.frsig = 0; vt_cons[new_console]->vt_pid = -1; vt_cons[new_console]->vt_newvt = -1; - reset_palette (new_console) ; + if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */ + reset_palette (new_console) ; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/gsc/Makefile linux.ac/drivers/gsc/Makefile --- linux.vanilla/drivers/gsc/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/gsc/Makefile Tue Apr 3 17:54:41 2001 @@ -0,0 +1,28 @@ +# +# Makefile for the HP Gecko (GSC) bus specific drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now inherited from the +# parent makefile. +# + +O_TARGET := gscbus.o + +obj-y := gsc.o +obj-m := +obj-n := +obj- := + +obj-$(CONFIG_GSC_DINO) += dino.o +obj-$(CONFIG_GSC_LASI) += busdevice.o lasi.o asp.o +obj-$(CONFIG_GSC_WAX) += wax.o +obj-$(CONFIG_LASI_HARMONY) += harmony.o +obj-$(CONFIG_LASI_82596) += lan.o +obj-$(CONFIG_SERIAL) += serial.o +obj-$(CONFIG_HIL) += hil.o +obj-$(CONFIG_WAX_EISA) += wax_eisa.o + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/gsc/README.dino linux.ac/drivers/gsc/README.dino --- linux.vanilla/drivers/gsc/README.dino Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/gsc/README.dino Tue Apr 3 17:54:41 2001 @@ -0,0 +1,28 @@ +/* +** HP VISUALIZE Workstation PCI Bus Defect +** +** "HP has discovered a potential system defect that can affect +** the behavior of five models of HP VISUALIZE workstations when +** equipped with third-party or customer-installed PCI I/O expansion +** cards. The defect is limited to the HP C180, C160, C160L, B160L, +** and B132L VISUALIZE workstations, and will only be encountered +** when data is transmitted through PCI I/O expansion cards on the +** PCI bus. HP-supplied graphics cards that utilize the PCI bus are +** not affected." +** +** REVISIT: "go/pci_defect" link below is stale. +** HP Internal can use <http://hpfcdma.fc.hp.com:80/Dino/> +** +** Product First Good Serial Number +** C200/C240 (US) US67350000 +**B132L+/B180 (US) US67390000 +** C200 (Europe) 3713G01000 +** B180L (Europe) 3720G01000 +** +** Note that many boards were fixed/replaced under a free replacement +** program. Assume a machine is only "suspect" until proven otherwise. +** +** "The pci_check program will also be available as application +** patch PHSS_12295" +*/ + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/gsc/asp.c linux.ac/drivers/gsc/asp.c --- linux.vanilla/drivers/gsc/asp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/gsc/asp.c Tue Apr 3 17:54:41 2001 @@ -0,0 +1,125 @@ +/* + * ASP Device Driver + * + * (c) Copyright 2000 The Puffin Group Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * by Helge Deller <deller@gmx.de> + */ + +#include <linux/config.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/malloc.h> +#include <asm/gsc.h> +#include <asm/led.h> + +#include "busdevice.h" + +#define ASP_GSC_IRQ 3 /* hardcoded interrupt for GSC */ + +#define ASP_HPA_HARD 0xF0800000 /* hardcoded HPA for ASP */ +#define ASP_VER_OFFSET 0x2F020 /* offset of ASP version */ + +#define OFFSET_ASP_LED 0x20 /* offset to HPA of the LED */ + +#undef USE_VIPER /* VIPER - graphics-board */ + +static int +asp_find_irq(struct busdevice *busdev_dev, struct hp_device *dev) +{ + int irq; + int off = ((int) dev->hpa) & 0xffff; + + /* + ** "irq" bits below are numbered relative to most significant bit. + */ + switch (off) { + case 0x1000: irq = 30; break; /* FIXME? (29,30 or 2 !)*/ /* HIL */ + case 0x2000: irq = 25; break; /* RS232 B */ + case 0x3000: irq = 26; break; /* RS232 A */ + case 0x4000: irq = 24; break; /* Centronics/Parallel Port */ + case 0x5000: irq = 22; break; /* SCSI */ + case 0x6000: irq = 23; break; /* LAN */ + + case 0x0000: irq = 18; break; /* Audio ??? */ + case 0x9000: irq = 18; break; /* Audio ??? */ + + case 0xF000: irq = 17; break; /* ASP itself */ + default: irq = -1; break; /* unknown */ + } + + return irq; +} + +int __init +asp_init_chip(struct hp_device *d, struct pa_iodc_driver *dri) +{ + struct busdevice *asp; + struct gsc_irq gsc_irq; + int irq, ret; + + asp = kmalloc(sizeof(struct busdevice), GFP_KERNEL); + if(!asp) + return -ENOMEM; + + asp->name = "ASP"; + asp->find_irq = asp_find_irq; + + /* The PDC-Firmware reports the ASP at 0xF082F000, + but we must use a HPA of 0xF0820000 */ + asp->hpa = (char *) ASP_HPA_HARD; + asp->version = gsc_readb(asp->hpa + ASP_VER_OFFSET); + printk(KERN_INFO "%s version %d at 0x%p found.\n", + asp->name, asp->version, asp->hpa); + + /* Stop ASP hissing for a bit */ +// asp_init_irq(asp); + + /* the IRQ ASP should use */ + ret = -EBUSY; + irq = gsc_claim_irq(&gsc_irq, ASP_GSC_IRQ); + if (irq < 0) { + printk(KERN_ERR __FUNCTION__ ": cannot get GSC irq\n"); + goto out; + } + + ret = request_irq(gsc_irq.irq, busdev_barked, 0, "asp", asp); + if (ret < 0) + goto out; + + /* Save this for debugging later */ + asp->parent_irq = gsc_irq.irq; + asp->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data; + +#ifdef USE_VIPER + /* Tell VIPER which IRQ ASP has been assigned. */ + gsc_writel(1<<gsc_irq.irq, 0xfffbf088); + gsc_writel(~0, 0xfffbf088); +#endif + + /* enable IRQ's for devices below ASP */ +// gsc_writel(asp->eim, asp->hpa + OFFSET_IAR); + + /* Done init'ing, register this driver */ + ret = register_busdevice( d, asp ); + if (ret) + goto out; + + /* initialize the chassis LEDs */ +#ifdef CONFIG_CHASSIS_LCD_LED + register_led_driver( DISPLAY_MODEL_OLD_ASP, LED_CMD_REG_NONE, + (char *) (asp->hpa + OFFSET_ASP_LED) ); +#endif + + return 0; + +out: + kfree(asp); + return ret; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/gsc/busdevice.c linux.ac/drivers/gsc/busdevice.c --- linux.vanilla/drivers/gsc/busdevice.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/gsc/busdevice.c Tue Apr 3 17:54:41 2001 @@ -0,0 +1,282 @@ +/* + * LASI/ASP/WAX/EISA interrupt manager + * + * (c) Copyright 1999 Red Hat Software + * Portions (c) Copyright 1999 The Puffin Group Inc. + * Portions (c) Copyright 1999 Hewlett-Packard + * + * 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. + * + * by Alan Cox <alan@redhat.com> and + * Alex deVries <adevries@thepuffingroup.com> + * Helge Deller <deller@gmx.de> + */ + +#include <linux/config.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/malloc.h> +#include <linux/bitops.h> +#include <asm/io.h> +#include <asm/hardware.h> +#include <asm/gsc.h> + +#include "busdevice.h" + + +#undef DEBUG + +#ifdef DEBUG +#define DEBPRINTK printk +#else +#define DEBPRINTK(x,...) +#endif + + +static struct pa_iodc_driver busdev_drivers_for[] __initdata = { +/* I'm pretty sure this covers them all. */ + {HPHW_BA, 0x0, 0, 0x00081, 0, 0, + DRIVER_CHECK_HWTYPE + DRIVER_CHECK_SVERSION, + "Lasi", "generic", (void *) lasi_init_chip}, + {HPHW_BA, 0x0, 0, 0x00070, 0, 0, + DRIVER_CHECK_HWTYPE + DRIVER_CHECK_SVERSION, + "ASP", "generic", (void *) asp_init_chip}, + { 0 } +}; + + +/* IRQ bits must be numbered from Most Significant Bit */ +#define BUSDEV_FIX_IRQ(x) (31-(x)) +#define BUSDEV_MASK_IRQ(x) (1<<(BUSDEV_FIX_IRQ(x))) + + +static struct busdevice *busdev_list = NULL; + + +int busdevice_alloc_irq( struct hp_device *dev ) +{ + struct busdevice *busdev = busdev_list; + int irq; + + if (!busdev) + { + printk(KERN_ERR "%s(0x%p): No LASI/ASP/WAX found in system yet !\n", + __FUNCTION__, dev); + return 0; + } + + /* See if this Device belongs to a LASI/ASP/WAX we know about */ + /* deller: Changed to test only the 3 highest nibbles of the + address-range, since ASP uses hpa of 0xf080yyyy, but devices are + at address 0xf082yyyy ! */ + while (busdev && + (((unsigned long) busdev->hpa & ~0xfffff) != ((unsigned long) dev->hpa & ~0xfffff))) + { + busdev = busdev->next; + } + + if (!busdev) + { + printk(KERN_WARNING "%s(0x%p): No known LASI/ASP/WAX owns device at 0x%p !\n", + __FUNCTION__, dev, dev->hpa); + return 0; + } + + /* find the correspondig IRQ */ + irq = busdev->find_irq(busdev, dev); + + if (irq < 0) { + printk(KERN_ERR "%s(0x%p): %s has never seen the HPA offset of 0x%lx.\n", + __FUNCTION__, dev->hpa, busdev->name, + ((unsigned long) dev->hpa) & 0xffff ); + return (0); + } + + DEBPRINTK (KERN_INFO "%s(0x%p) on %s 0x%x + %d = %d\n", + __FUNCTION__, dev->hpa, busdev->name, + busdev->busdev_region->data.irqbase, irq, + busdev->busdev_region->data.irqbase + irq); + + return busdev->busdev_region->data.irqbase + irq; +} + + +/* + * Deliver interrupts + */ + +void busdev_barked(int busdev_irq, void *dev, struct pt_regs *regs) +{ + u32 irq; + struct busdevice *busdev = (struct busdevice *) dev; + + /* + Don't need to protect OFFSET_IRR with spinlock since this is + the only place it's touched. + Protect busdev_region by disabling this region's interrupts, + modifying the region, and then re-enabling the region. + */ + + irq = gsc_readl(busdev->hpa+OFFSET_IRR); + if(irq==0) + printk(KERN_ERR "%s: barking without apparent reason.\n", busdev->name); + else { + DEBPRINTK ("%s (0x%x) barked, mask=0x%x, irq=%d\n", + busdev->name, busdev->busdev_region->data.irqbase, + irq, BUSDEV_FIX_IRQ(ffs(irq))+1 ); + + do_irq_mask((unsigned long) irq, busdev->busdev_region, regs); + } +} + +static void +busdev_disable_irq(void *irq_dev, int irq) +{ + /* Disable the IRQ line by clearing the bit in the IMR */ + u32 imr = gsc_readl(BUSDEV_DEV(irq_dev)->hpa+OFFSET_IMR); + imr &= ~(BUSDEV_MASK_IRQ(irq)); + + DEBPRINTK( KERN_WARNING "%s(%p, %d) %s: IMR 0x%x\n", + __FUNCTION__, irq_dev, irq, BUSDEV_DEV(irq_dev)->name, imr); + + gsc_writel(imr, BUSDEV_DEV(irq_dev)->hpa+OFFSET_IMR); +} + + +static void +busdev_enable_irq(void *irq_dev, int irq) +{ + /* Enable the IRQ line by setting the bit in the IMR */ + char *addr = (char*) (BUSDEV_DEV(irq_dev)->hpa + OFFSET_IMR); + u32 imr = gsc_readl(addr); + imr |= BUSDEV_MASK_IRQ(irq); + + DEBPRINTK (KERN_WARNING "%s(%p, %d) %s: IMR 0x%x\n", + __FUNCTION__, irq_dev, irq, BUSDEV_DEV(irq_dev)->name, imr); + + gsc_writel(imr, addr); +// gsc_writel(~0L, addr); + +/* FIXME: read IPR to make sure the IRQ isn't already pending. +** If so, we need to read IRR and manually call do_irq_mask(). +** This code should be shared with busdev_unmask_irq(). +*/ +} + +static void +busdev_mask_irq(void *irq_dev, int irq) +{ +/* FIXME: Clear the IMR bit in busdev for that IRQ */ +} + +static void +busdev_unmask_irq(void *irq_dev, int irq) +{ +/* FIXME: Read IPR. Set the IMR bit in busdev for that IRQ. + call do_irq_mask() if IPR is non-zero +*/ +} + +struct irq_region_ops busdev_irq_ops = { + busdev_disable_irq, /* disable_irq */ + busdev_enable_irq, /* enable_irq */ + busdev_mask_irq, /* void (* mask_irq)(void *dev, int irq) */ + busdev_unmask_irq /* void (* unmask_irq)(void *dev, int irq) */ +}; + + +#define DEBUG_BUSDEVICE( dev ) \ + do { \ + printk(KERN_WARNING "%s IRQ %d EIM 0x%x", dev->name, dev->parent_irq, dev->eim); \ + if (gsc_readl(dev->hpa + OFFSET_IMR)) \ + printk(KERN_WARNING " IMR is non-zero! (0x%x)", gsc_readl(dev->hpa + OFFSET_IMR)); \ + printk("\n"); \ + } while (0) + + +int register_busdevice( struct hp_device *gsc_parent, + struct busdevice *busdev ) +{ + struct resource *res; + + busdev->spinlock = SPIN_LOCK_UNLOCKED; + busdev->gsc = gsc_parent; + + /* the IRQs we simulate */ + busdev->busdev_region = alloc_irq_region(32, &busdev_irq_ops, + IRQ_REG_MASK|IRQ_REG_DIS, busdev->name, busdev); + if(!busdev->busdev_region) + return (-ENOMEM); + + /* allocate resource region */ + res = kmalloc(sizeof(struct resource), GFP_KERNEL); + if (res) { + res->name = busdev->name; + res->start = (unsigned long) busdev->hpa; + res->end = res->start + 0x100000 - 1; + res->flags = IORESOURCE_IO; /* do not mark it busy ! */ + res->child = NULL; + request_resource(&ioport_resource, res); + request_region(res->start, OFFSET_IAR + sizeof(int), "reserved"); + } + +#if 0 + DEBUG_BUSDEVICE( busdev ); +#endif + + busdev->next = busdev_list; + busdev_list = busdev; + + return 0; +} + + + +/* + * Initialize all controller chips (LASI/ASP/WAX) and attached devices. + */ +extern int parport_gsc_init (void); +extern void register_lan_drivers(void); +extern void register_hil_drivers(void); +extern int lasi_psaux_init(void); +extern int gsc_ps2_init(void); + + + +int __init busdevices_init(void) +{ + register_driver(busdev_drivers_for); + +#ifdef CONFIG_GSC_WAX + register_wax_driver(); +#endif + +#ifdef CONFIG_PARPORT_GSC + parport_gsc_init(); /* parallel port driver */ +#endif + +#ifdef CONFIG_LASI_82596 + register_lan_drivers(); /* LASI/ASP LAN (i82596) */ +#endif + +#ifdef CONFIG_GSC_PS2 + gsc_ps2_init(); /* PS aux driver */ +#endif + +#ifdef CONFIG_HIL + register_hil_drivers(); /* Human Interface Loop driver */ +#endif + +#ifdef CONFIG_SOUND_GSC_HARMONY + register_harmony_drivers(); +#endif + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/gsc/busdevice.h linux.ac/drivers/gsc/busdevice.h --- linux.vanilla/drivers/gsc/busdevice.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/gsc/busdevice.h Tue Apr 3 17:54:41 2001 @@ -0,0 +1,49 @@ +#ifndef BUSDEVICE_H +#define BUSDEVICE_H + +#include <linux/types.h> +#include <linux/interrupt.h> +#include <asm/hardware.h> +#include <asm/gsc.h> + +#define OFFSET_IRR 0x0000 /* Interrupt request register */ +#define OFFSET_IMR 0x0004 /* Interrupt mask register */ +#define OFFSET_IPR 0x0008 /* Interrupt pending register */ +#define OFFSET_ICR 0x000C /* Interrupt control register */ +#define OFFSET_IAR 0x0010 /* Interrupt address register */ + + +struct busdevice +{ + struct busdevice *next; + struct hp_device *gsc; + volatile char *hpa; + char *name; + int version; + int type; + int parent_irq; + int eim; + struct irq_region *busdev_region; + spinlock_t spinlock; + int (*find_irq) (struct busdevice *this_dev, struct hp_device *dev); +}; + +/* short cut to keep the compiler happy */ +#define BUSDEV_DEV(x) ((struct busdevice *) (x)) + +int register_busdevice( struct hp_device *gsc_parent, struct busdevice *busdev_new ); + +/* returns a virtual irq for device at dev->hpa (works for all LASI/ASP/WAX) */ +int busdevice_alloc_irq( struct hp_device *dev ); + +void busdev_barked(int busdev_irq, void *dev, struct pt_regs *regs); + +extern unsigned int hil_base; /* BASE of HIL-Port */ +extern unsigned int hil_irq; /* IRQ of HIL-Port */ + +int lasi_init_chip(struct hp_device *d, struct pa_iodc_driver * dri); +int asp_init_chip(struct hp_device *d, struct pa_iodc_driver * dri); +int wax_init_chip(struct hp_device *d, struct pa_iodc_driver * dri); +/* int eisa_wax_init_chip(struct hp_device *d, struct pa_iodc_driver * dri); */ + +#endif /* BUSDEVICE_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/gsc/dino.c linux.ac/drivers/gsc/dino.c --- linux.vanilla/drivers/gsc/dino.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/gsc/dino.c Tue Apr 3 17:54:41 2001 @@ -0,0 +1,948 @@ +/* +** DINO manager +** +** (c) Copyright 1999 Red Hat Software +** (c) Copyright 1999 SuSE GmbH +** (c) Copyright 1999,2000 Hewlett-Packard Company +** (c) Copyright 2000 Grant Grundler +** +** 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 module provides access to Dino PCI bus (config/IOport spaces) +** and helps manage Dino IRQ lines. +** +** Dino interrupt handling is a bit complicated. +** Dino always writes to the broadcast EIR via irr0 for now. +** (BIG WARNING: using broadcast EIR is a really bad thing for SMP!) +** Only one processor interrupt is used for the 11 IRQ line +** inputs to dino. +** +** The different between Built-in Dino and Card-Mode +** dino is in chip initialization and pci device initialization. +** +** Linux drivers can only use Card-Mode Dino if pci devices I/O port +** BARs are configured and used by the driver. Programming MMIO address +** requires substantial knowledge of available Host I/O address ranges +** is currently not supported. Port/Config accessor functions are the +** same. "BIOS" differences are handled within the existing routines. +*/ + + +/* +** TODO: The RS232 (can be console) integrated in Dino needs to be exported +** as a child of Dino since the IRQ handling has to go through Dino. +** If firmware tells us it's present (hversion specific PDC call), +** that means it's lines are connected to a port out the back of the +** box. It then needs to show up on some device list and in Dino's +** "irq_region". +** +** TODO: create a virtual address for each Dino HPA. +** GSC code might be able to do this since IODC data tells us +** how many pages are used. PCI subsystem could (must?) do this +** for PCI drivers devices which implement/use MMIO registers. +*/ + +#include <linux/delay.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/malloc.h> +#include <linux/interrupt.h> /* for struct irqaction */ +#include <linux/spinlock.h> /* for spinlock_t and prototypes */ + +#include <asm/pdc.h> +#include <asm/page.h> +#include <asm/segment.h> +#include <asm/system.h> +#include <asm/io.h> +#include <asm/hardware.h> + +#include <asm/irq.h> /* for "gsc" irq functions */ +#include <asm/gsc.h> + + +#undef DINO_DEBUG + +#ifdef DINO_DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +/* +** Config accessor functions only pass in the 8-bit bus number +** and not the 8-bit "PCI Segment" number. Each Dino will be +** assigned a PCI bus number based on "when" it's discovered. +** +** The "secondary" bus number is set to this before calling +** pci_scan_bus(). If any PPB's are present, the scan will +** discover them and update the "secondary" and "subordinate" +** fields in Dino's pci_bus structure. +** +** Changes in the configuration *will* result in a different +** bus number for each dino. +*/ + +/* +** If hversion is what is read from Dino, we should be OK. +** If it's what PDC told us, J2240 PDC reports the hv_model wrong +** for the first Dino. I think it reports 0x05d. <sigh>... +** +** But life gets worse...the "lba" PCI bus adapter (used in newer +** B/C/J/L/N-class) has the same hversion. Also need to test sversion +** when support for "lba" is added as well. +*/ + +// REVISIT: 715 reports card-mode Dino IODC data wrong. +// May need to read it "by hand". +#define is_card_dino(dev) (dev->sversion == 0x9d || dev->sversion == 0x8080) +#define dino_hrev(dev) (dev->hversion & 0xf) + +static int dino_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri); + +static struct pa_iodc_driver dino_drivers_for[] = { + + /* A180 reports the card-mode Dino as: */ + {HPHW_A_DMA, 0x004, 0, 0x0009D, 0, 0x80, + DRIVER_CHECK_HVERSION + DRIVER_CHECK_HVERSION_REV + + DRIVER_CHECK_SVERSION, + "Dino", "3.x (card mode)",(void *) dino_driver_callback}, + + /* 715 reports same card-mode Dino, uh, erm,...differently. + ** bug in pdc_iodc_read() PDC support? + */ + {HPHW_A_DMA, 0x444, 0, 0x8080, 0, 0x80, + DRIVER_CHECK_HVERSION + DRIVER_CHECK_SVERSION + + DRIVER_CHECK_HWTYPE, + "Dino", "3.x (card mode)",(void *) dino_driver_callback}, + + {HPHW_BRIDGE, 0x680, 0x3, 0xa, 0,0, + DRIVER_CHECK_HVERSION + DRIVER_CHECK_HVERSION_REV + + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + "Dino", "3.1 (bridge mode)", (void *) dino_driver_callback}, + + {HPHW_BRIDGE, 0x680, 0x02, 0xa, 0,0, + DRIVER_CHECK_HVERSION + DRIVER_CHECK_HVERSION_REV + + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + "Dino", "3.0 (bridge mode)", (void *) dino_driver_callback}, + + {HPHW_BRIDGE, 0x680, 0x01, 0xa, 0,0, + DRIVER_CHECK_HVERSION + DRIVER_CHECK_HVERSION_REV + + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + "Dino", "2.1 (bridge mode)", (void *) dino_driver_callback}, + + {HPHW_BRIDGE, 0x680, 0x00, 0xa, 0,0, + DRIVER_CHECK_HVERSION + DRIVER_CHECK_HVERSION_REV + + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + "Dino", "2.0 (bridge mode)", (void *) dino_driver_callback}, + + {HPHW_BRIDGE, 0x05d, 0x03, 0xa, 0,0, + DRIVER_CHECK_HVERSION + DRIVER_CHECK_HVERSION_REV + + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + "Dino", "J2240 (bridge mode)", (void *) dino_driver_callback}, + + {0,0,0,0,0,0, + 0, + (char *) NULL,(char *) NULL,(void *) NULL} +}; + + +#define DINO_IAR0 0x004 +#define DINO_IODC_ADDR 0x008 +#define DINO_IODC_DATA_0 0x008 +#define DINO_IODC_DATA_1 0x008 +#define DINO_IRR0 0x00C +#define DINO_IAR1 0x010 +#define DINO_IRR1 0x014 +#define DINO_IMR 0x018 +#define DINO_IPR 0x01C +#define DINO_TOC_ADDR 0x020 +#define DINO_ICR 0x024 +#define DINO_ILR 0x028 +#define DINO_IO_COMMAND 0x030 +#define DINO_IO_STATUS 0x034 +#define DINO_IO_CONTROL 0x038 +#define DINO_IO_GSC_ERR_RESP 0x040 +#define DINO_IO_ERR_INFO 0x044 +#define DINO_IO_PCI_ERR_RESP 0x048 +#define DINO_IO_FBB_EN 0x05c +#define DINO_IO_ADDR_EN 0x060 +#define DINO_PCI_ADDR 0x064 +#define DINO_CONFIG_DATA 0x068 +#define DINO_IO_DATA 0x06c +#define DINO_MEM_DATA 0x070 /* Dino 3.x only */ +#define DINO_GSC2X_CONFIG 0x7b4 +#define DINO_GMASK 0x800 +#define DINO_PAMR 0x804 +#define DINO_PAPR 0x808 +#define DINO_DAMODE 0x80c +#define DINO_PCICMD 0x810 +#define DINO_PCISTS 0x814 +#define DINO_MLTIM 0x81c +#define DINO_BRDG_FEAT 0x820 +#define DINO_PCIROR 0x824 +#define DINO_PCIWOR 0x828 +#define DINO_TLTIM 0x830 + +#define DINO_VERSION_20 0x0 +#define DINO_VERSION_21 0x1 +#define DINO_VERSION_30 0x2 +#define DINO_VERSION_31 0x3 +#define DINO_VERSION_UNKNOWN 0xf + +#define DINO_MODE_CARD 0 +#define DINO_MODE_BRIDGE 1 +#define DINO_MODE_UNKNOWN 2 + +#define DINO_IRQS 11 /* bits 0-10 are architected */ +#define DINO_IRR_MASK 0x5ff /* only 10 bits are implemented */ + +#define DINO_MASK_IRQ(x) (1<<(x)) + +#define PCIINTA 0x001 +#define PCIINTB 0x002 +#define PCIINTC 0x004 +#define PCIINTD 0x008 +#define PCIINTE 0x010 +#define PCIINTF 0x020 +#define GSCEXTINT 0x040 +/* #define xxx 0x080 - bit 7 is "default" */ +/* #define xxx 0x100 - bit 8 not used */ +/* #define xxx 0x200 - bit 9 not used */ +#define RS232INT 0x400 + +/* REVISIT: replace dino_version with something GSC generic */ +struct dino_version_mapping +{ + u16 hversion; /* model:12 rev:4 */ + u8 spa; + u8 type; + char *version_string; +}; + + + char *base_addr; /* REVISIT: declare this volatile */ + +struct dino_device +{ + struct pci_hba_data hba; /* 'C' inheritance - must be first */ + spinlock_t dinosaur_pen; + unsigned long txn_addr; /* EIR addr to generate interrupt */ + u32 txn_data; /* EIR data assign to each dino */ + int irq; /* Virtual IRQ dino uses */ + struct irq_region *dino_region; /* region for this Dino */ + +/* REVISIT - replace these hba.io_space and hba.memspace? */ + unsigned long mmio_addr; /* FIXME: card-mode support */ + u32 ioport_addr; /* card-mode support */ + + u32 imr; /* IRQ's which are enabled */ +#ifdef DINO_DEBUG + unsigned int dino_irr0; /* save most recent IRQ line stat */ +#endif +}; + +/* Looks nice and keeps the compiler happy */ +#define DINO_DEV(d) ((struct dino_device *) d) + + + +/*********************************************** +** +** Dino Configuration Space Accessor Functions +** +************************************************/ + +#define le8_to_cpu(x) (x) +#define cpu_to_le8(x) (x) + +#define DINO_CFG_TOK(bus,dfn,pos) ((u32) ((bus)<<16 | (dfn)<<8 | (pos))) + +#define DINO_CFG_RD(type, size, mask) \ +static int dino_cfg_read##size (struct pci_dev *dev, int pos, u##size *data) \ +{ \ + struct dino_device *d = DINO_DEV(dev->bus->sysdata); \ + u32 local_bus = (dev->bus->parent == NULL) ? 0 : dev->bus->secondary; \ + u32 v = DINO_CFG_TOK(local_bus, dev->devfn, (pos&~3)); \ + unsigned long flags; \ + spin_lock_irqsave(&d->dinosaur_pen, flags); \ + /* tell HW which CFG address */ \ + gsc_writel(v, d->hba.base_addr + DINO_PCI_ADDR); \ + /* generate cfg read cycle */ \ + *data = le##size##_to_cpu(gsc_read##type(d->hba.base_addr+DINO_CONFIG_DATA+(pos&mask))); \ + spin_unlock_irqrestore(&d->dinosaur_pen, flags); \ + return 0; \ +} + +DINO_CFG_RD(b, 8, 3) +DINO_CFG_RD(w, 16, 2) +DINO_CFG_RD(l, 32, 0) + + +/* +** Dino address stepping "feature": +** When address stepping, Dino attempts to drive the bus one cycle too soon +** even though the type of cycle (config vs. MMIO) might be different. +** The read of Ven/Prod ID is harmless and avoids Dino's address stepping. +*/ +#define DINO_CFG_WR(type, size, mask) \ +static int dino_cfg_write##size (struct pci_dev *dev, int pos, u##size data) \ +{ \ + struct dino_device *d = DINO_DEV(dev->bus->sysdata); \ + u32 local_bus = (dev->bus->parent == NULL) ? 0 : dev->bus->secondary; \ + u32 v = DINO_CFG_TOK(local_bus, dev->devfn, (pos&~3)); \ + unsigned long flags; \ + spin_lock_irqsave(&d->dinosaur_pen, flags); \ + /* avoid address stepping feature */ \ + gsc_writel(v & 0xffffff00, d->hba.base_addr + DINO_PCI_ADDR); \ + (volatile int) gsc_readl(d->hba.base_addr + DINO_CONFIG_DATA); \ + /* tell HW which CFG address */ \ + gsc_writel(v, d->hba.base_addr + DINO_PCI_ADDR); \ + /* generate cfg read cycle */ \ + gsc_write##type(cpu_to_le##size(data), d->hba.base_addr+DINO_CONFIG_DATA+(pos&mask)); \ + spin_unlock_irqrestore(&d->dinosaur_pen, flags); \ + return 0; \ +} + +DINO_CFG_WR(b, 8, 3) +DINO_CFG_WR(w, 16, 2) +DINO_CFG_WR(l, 32, 0) + +static struct pci_ops dino_cfg_ops = { + dino_cfg_read8, dino_cfg_read16, dino_cfg_read32, + dino_cfg_write8, dino_cfg_write16, dino_cfg_write32 +}; + + + +/******************************************************* +** +** Dino "I/O Port" Space Accessor Functions +** +** Many PCI devices don't require use of I/O port space (eg Tulip, +** NCR720) since they export the same registers to both MMIO and +** I/O port space. Performance is going to stink if drivers use +** I/O port instead of MMIO. +** +********************************************************/ + + +#define DINO_PORT_IN(type, size, mask) \ +static u##size dino_in##size (struct pci_hba_data *d, u16 addr) \ +{ \ + u##size v; \ + unsigned long flags; \ + spin_lock_irqsave(&(DINO_DEV(d)->dinosaur_pen), flags); \ + /* tell HW which IO Port address */ \ + gsc_writel((u32) addr & ~3, d->base_addr + DINO_PCI_ADDR); \ + /* generate I/O PORT read cycle */ \ + v = gsc_read##type(d->base_addr+DINO_IO_DATA+(addr&mask)); \ + spin_unlock_irqrestore(&(DINO_DEV(d)->dinosaur_pen), flags); \ + return le##size##_to_cpu(v); \ +} + +DINO_PORT_IN(b, 8, 3) +DINO_PORT_IN(w, 16, 2) +DINO_PORT_IN(l, 32, 0) + +#define DINO_PORT_OUT(type, size, mask) \ +static void dino_out##size (struct pci_hba_data *d, u16 addr, u##size val) \ +{ \ + unsigned long flags; \ + spin_lock_irqsave(&(DINO_DEV(d)->dinosaur_pen), flags); \ + /* tell HW which CFG address */ \ + gsc_writel((u32) addr, d->base_addr + DINO_PCI_ADDR); \ + /* generate cfg write cycle */ \ + gsc_write##type(cpu_to_le##size(val), d->base_addr+DINO_IO_DATA+(addr&mask)); \ + spin_unlock_irqrestore(&(DINO_DEV(d)->dinosaur_pen), flags); \ +} + +DINO_PORT_OUT(b, 8, 3) +DINO_PORT_OUT(w, 16, 2) +DINO_PORT_OUT(l, 32, 0) + +struct pci_port_ops dino_port_ops = { + dino_in8, dino_in16, dino_in32, + dino_out8, dino_out16, dino_out32 +}; + + + +/* +** One time initialization to let the world know Dino is here. +** This is the only routine which is NOT static. +** Must be called exactly once before pci_init(). +*/ +int __init dino_init(void) +{ + /* This claim any Dino devices discovered to date + ** and invoke our driver_callback. + */ + register_driver(dino_drivers_for); + return 0; +} + + +static void +dino_mask_irq(void *irq_dev, int irq) +{ + struct dino_device *dino_dev = DINO_DEV(irq_dev); + + DBG(KERN_WARNING __FUNCTION__ "(0x%p, %d)\n", irq_dev, irq); + + if (NULL == irq_dev || irq > DINO_IRQS || irq < 0) { + printk(KERN_WARNING __FUNCTION__ "(0x%lx, %d) - not a dino irq?\n", + (long) irq_dev, irq); + BUG(); + } else { + /* + ** Clear the matching bit in the IMR register + */ + dino_dev->imr &= ~(DINO_MASK_IRQ(irq)); + gsc_writel(dino_dev->imr, dino_dev->hba.base_addr+DINO_IMR); + } +} + + +static void +dino_unmask_irq(void *irq_dev, int irq) +{ + struct dino_device *dino_dev = DINO_DEV(irq_dev); + u32 tmp; + + DBG(KERN_WARNING __FUNCTION__ "(0x%p, %d)\n", irq_dev, irq); + + if (NULL == irq_dev || irq > DINO_IRQS) { + printk(KERN_WARNING __FUNCTION__ ": %d not a dino irq?\n", irq); + BUG(); + return; + } + + /* set the matching bit in the IMR register */ + dino_dev->imr |= DINO_MASK_IRQ(irq); /* used in dino_isr() */ + gsc_writel( dino_dev->imr, dino_dev->hba.base_addr+DINO_IMR); + + /* Emulate "Level Triggered" Interrupt + ** Basically, a driver is blowing it if the IRQ line is asserted + ** while the IRQ is disabled. But tulip.c seems to do that.... + ** Give 'em a kluge award and a nice round of applause! + ** + ** The gsc_write will generate an interrupt which invokes dino_isr(). + ** dino_isr() will read IPR and find nothing. But then catch this + ** when it also checks ILR. + */ + tmp = gsc_readl(dino_dev->hba.base_addr+DINO_ILR); + if (tmp & DINO_MASK_IRQ(irq)) { + DBG(KERN_WARNING __FUNCTION__ " IRQ asserted! (ILR 0x%x)\n", tmp); + gsc_writel(dino_dev->txn_data, dino_dev->txn_addr); + } +} + + + +static void +dino_enable_irq(void *irq_dev, int irq) +{ + struct dino_device *dino_dev = DINO_DEV(irq_dev); + + /* + ** clear pending IRQ bits + ** + ** This does NOT change ILR state! + ** See comments in dino_unmask_irq() for ILR usage. + */ + (volatile void) gsc_readl(dino_dev->hba.base_addr+DINO_IPR); + + dino_unmask_irq(irq_dev, irq); +} + + +static struct irq_region_ops dino_irq_ops = { + dino_mask_irq, + dino_enable_irq, + dino_mask_irq, /* void (* mask_irq)(void *dev, int irq) */ + dino_unmask_irq /* void (* unmask_irq)(void *dev, int irq) */ +}; + + +/* + * Handle a Processor interrupt generated by Dino. + * + * ilr_loop counter is a kluge to prevent a "stuck" IRQ line from + * wedging the CPU. Could be removed or made optional at some point. + */ +static void +dino_isr(int irq, void *intr_dev, struct pt_regs *regs) +{ + struct dino_device *dino_dev = DINO_DEV(intr_dev); + u32 mask; + int ilr_loop = 5; + extern void do_irq(struct irqaction *a, int i, struct pt_regs *p); + + + /* read and acknowledge pending interrupts */ +#ifdef DINO_DEBUG + dino_dev->dino_irr0 = +#endif + mask = gsc_readl(dino_dev->hba.base_addr+DINO_IRR0) & DINO_IRR_MASK; + +ilr_again: + while (mask) + { + int irq; + + /* + ** Perform a binary search on set bits + ** INT 8 & 9 are not supported. + */ + if (mask & (PCIINTA | PCIINTC | PCIINTE | GSCEXTINT | RS232INT)) + { + if (mask & (PCIINTA | PCIINTC)) { + irq = (mask & PCIINTA) ? 0 : 2; + } else { + if (mask & (PCIINTE | GSCEXTINT)) { + irq = (mask & PCIINTE) ? 4 : 6; + } else irq = 10; /* RS232 INTERRUPT */ + } + } else { + if (mask & (PCIINTB | PCIINTD)) { + irq = (mask & PCIINTB) ? 1 : 3; + } else { + irq = (mask & PCIINTF) ? 5 : 7; + } + } + + mask &= ~(1<<irq); + + DBG(KERN_WARNING __FUNCTION__ "(%x, %p) mask %0x\n", + irq, intr_dev, mask); + do_irq(&dino_dev->dino_region->action[irq], + dino_dev->dino_region->data.irqbase + irq, + regs); + + } + + /* Support for level triggered IRQ lines. + ** + ** Dropping this support would make this routine *much* faster. + ** But since PCI requires level triggered IRQ line to share lines... + ** device drivers may assume lines are level triggered (and not + ** edge triggered like EISA/ISA can be). + */ + if (0 != (mask = gsc_readl(dino_dev->hba.base_addr+DINO_ILR) & dino_dev->imr)) + { + --ilr_loop; + goto ilr_again; + } +} + +static void __init +dino_bios_init(void) +{ + DBG("dino_bios_init\n"); +} + + +static void __init +dino_set_bars(struct pci_dev *dev) +{ + struct dino_device *dino_dev = DINO_DEV(dev->bus->sysdata); + int i; + + /* Adjust the I/O Port space addresses */ + for (i=0; i<6; i++) + { + u32 bar_val = 0; + + /* + ** Calculate next properly aligned address. + */ + if (dev->resource[i].flags & IORESOURCE_IO) + { + unsigned long sz = dev->resource[i].end - + dev->resource[i].start; + + /* Round up to nearest "sz" alignment */ + dino_dev->ioport_addr += (u32) sz; + dino_dev->ioport_addr &= (u32) ~sz; + bar_val = dino_dev->ioport_addr; + + /* point to next unused addr */ + dino_dev->ioport_addr += (u32) sz + 1; + + dev->resource[i].start = bar_val; + dev->resource[i].end = bar_val + sz; + DBG(KERN_WARNING __FUNCTION__ " %0x:%0x [%d] ioport %x start 0x%x sz %lx\n", + dev->bus->number, dev->devfn, i, + dino_dev->ioport_addr, bar_val, sz); + } else { + /* NOT SUPPORTED */ + dev->resource[i].start = dev->resource[i].end = + bar_val = 0; + } + + /* Write the new address */ + dino_cfg_write32(dev, (i*4)+0x10, bar_val); + } + + + /* + ** Enable the command register + ** + ** FIXME: This is put here because PCI subsystem could + ** be doing all of this for us. + */ + dino_cfg_write32(dev, PCI_COMMAND, + PCI_COMMAND_SERR | + PCI_COMMAND_PARITY | PCI_COMMAND_INVALIDATE | + PCI_COMMAND_MASTER | PCI_COMMAND_IO); +} + + +static void __init +dino_card_fixup(struct pci_dev *dev) +{ + u8 irq_pin; + + /* + ** REVISIT: card-mode PCI-PCI expansion chassis do exist. + ** Not sure they were ever productized. + ** Die here since we'll die later in dino_inb() anyway. + */ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + panic("Card-Mode Dino: PCI-PCI Bridge not supported\n"); + } + +/* +** FIXME: PCI subsystem in linux 2.4 manage and program I/O Port space +** for us if we told it which addresses it could use. +*/ + /* + ** Program the I/O Port space BARs. + */ + dino_set_bars(dev); + + /* + ** Set Latency Timer to 0xff (not a shared bus) + ** Set CACHELINE_SIZE. + */ + dino_cfg_write16(dev, PCI_CACHE_LINE_SIZE, 0xff00 | L1_CACHE_BYTES/4); + + /* + ** Program INT_LINE for card-mode devices. + ** The cards are hardwired according to this algorithm. + ** And it doesn't matter if PPB's are present or not since + ** the IRQ lines bypass the PPB. + ** + ** "-1" converts INTA-D (1-4) to PCIINTA-D (0-3) range. + ** The additional "-1" adjusts for skewing the IRQ<->slot. + */ + dino_cfg_read8(dev, PCI_INTERRUPT_PIN, &irq_pin); + dev->irq = (irq_pin + (dev->devfn >> 3) - 2) % 4 ; + + + /* Shouldn't really need to do this but it's in case someone tries + ** to bypass PCI services and look at the card themselves. + */ + dino_cfg_write8(dev, PCI_INTERRUPT_LINE, dev->irq); +} + + +static void __init +dino_fixup_bus(struct pci_bus *bus) +{ + struct list_head *ln; + struct pci_dev *dev; + struct dino_device *dino_dev = DINO_DEV(bus->sysdata); + int hba_num = dino_dev->hba.hba_num << 16; + + DBG(KERN_WARNING __FUNCTION__ "(0x%p) bus %d sysdata 0x%p\n", + bus, bus->secondary, bus->sysdata); + + list_for_each(ln, &bus->devices) { + int i; + + dev = pci_dev_b(ln); + if (is_card_dino(dino_dev->hba.iodc_info)) + dino_card_fixup(dev); + + /* + ** P2PB's only have 2 BARs, no IRQs. + ** I'd like to just ignore them for now. + */ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) + continue; + + /* Adjust the I/O Port space addresses */ + for (i = 0; i < 6; i++) { + struct resource *res = &dev->resource[i]; + if (res->flags & IORESOURCE_IO) { + res->start |= hba_num; + res->end |= hba_num; + } + } + + /* Adjust INT_LINE for that busses region */ + dev->irq = dino_dev->dino_region->data.irqbase + dev->irq; + } +} + + +struct pci_bios_ops dino_bios_ops = { + dino_bios_init, + dino_fixup_bus /* void dino_fixup_bus(struct pci_bus *bus) */ +}; + + +/* + * Initialise a DINO controller chip + */ + +static void __init +dino_card_init(struct dino_device *dino_dev) +{ + u32 brdg_feat = 0x04784e05; + + gsc_writel(0x00000000, dino_dev->hba.base_addr+DINO_GMASK); + gsc_writel(0x00000001, dino_dev->hba.base_addr+DINO_IO_FBB_EN); + gsc_writel(0x00000000, dino_dev->hba.base_addr+DINO_ICR); + +#if 1 +/* REVISIT - should be a runtime check (eg if (CPU_IS_PCX_L) ...) */ + /* + ** PCX-L processors don't support XQL like Dino wants it. + ** PCX-L2 ignore XQL signal and it doesn't matter. + */ + brdg_feat &= ~0x4; /* UXQL */ +#endif + gsc_writel( brdg_feat, dino_dev->hba.base_addr+DINO_BRDG_FEAT); + + /* + ** Don't enable address decoding until we know which I/O range + ** currently is available from the host. Only affects MMIO + ** and not I/O port space. + */ + gsc_writel(0x00000000, dino_dev->hba.base_addr+DINO_IO_ADDR_EN); + + dino_dev->ioport_addr = 0x00001000; /* Make believe */ + dino_dev->mmio_addr = 0xf0800000; /* FIXME: Make believe */ + + gsc_writel(0x00000000, dino_dev->hba.base_addr+DINO_DAMODE); + gsc_writel(0x00222222, dino_dev->hba.base_addr+DINO_PCIROR); + gsc_writel(0x00222222, dino_dev->hba.base_addr+DINO_PCIWOR); + + gsc_writel(0x00000040, dino_dev->hba.base_addr+DINO_MLTIM); + gsc_writel(0x00000080, dino_dev->hba.base_addr+DINO_IO_CONTROL); + gsc_writel(0x0000008c, dino_dev->hba.base_addr+DINO_TLTIM); + + /* Disable PAMR before writing PAPR */ + gsc_writel(0x0000007e, dino_dev->hba.base_addr+DINO_PAMR); + gsc_writel(0x0000007f, dino_dev->hba.base_addr+DINO_PAPR); + gsc_writel(0x00000000, dino_dev->hba.base_addr+DINO_PAMR); + + /* + ** Dino ERS encourage to enable FBB (0x6f). + ** We can't until we know *all* devices below us can support it. + ** (Something in device configuration header tells us). + */ + gsc_writel(0x0000004f, dino_dev->hba.base_addr+DINO_PCICMD); + + /* Somewhere, the PCI spec says give devices 1 second + ** to recover from the #RESET being de-asserted. + ** Experience shows most devices only need 10ms. + ** This short-cut speeds up booting significantly. + */ + mdelay(pci_post_reset_delay); + +} + +static void __init +dino_bridge_init(struct dino_device *dino_dev) +{ + u32 io_addr, bpos=0, bmask=1; + + /* + ** Decoding IO_ADDR_EN only works for Built-in Dino + ** since PDC has already initialized this. + */ + + io_addr = gsc_readl(dino_dev->hba.base_addr+DINO_IO_ADDR_EN); + + for ( ; ((bmask & io_addr) == 0) && (bpos <33); + bmask<<=1, bpos++) { + }; + + if (bpos == 33) { + printk(KERN_WARNING "%s: IO_ADDR_EN hasn't been configured.\n", __FUNCTION__ ); + BUG(); + } + + /* + ** Calculate the base of the Host I/O address range + ** Dino will forward to the PCI bus. + */ + dino_dev->mmio_addr = 0xf0000000 + (bpos << 23); /* bpos x 8MB */ + dino_dev->ioport_addr = 0; /* not used for bridge mode */ +} + +static int __init +dino_common_init(struct dino_device *dino_dev) +{ + int status; + u32 eim; + struct gsc_irq gsc_irq; + struct resource *res; + + pcibios_register_hba((struct pci_hba_data *) dino_dev); + + pci_bios = &dino_bios_ops; /* used by pci_scan_bus() */ + pci_port = &dino_port_ops; + + /* + ** Note: SMP systems can make use of IRR1/IAR1 registers + ** But it won't buy much performance except in very + ** specific applications/configurations. Note Dino + ** still only has 11 IRQ input lines - just map some them + ** to a different processor. + */ + dino_dev->irq = gsc_alloc_irq(&gsc_irq); + dino_dev->txn_addr = gsc_irq.txn_addr; + dino_dev->txn_data = gsc_irq.txn_data; + eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data; + + /* + ** Dino needs a PA "IRQ" to get a processor's attention. + ** arch/parisc/kernel/irq.c returns an EIRR bit. + */ + if(dino_dev->irq < 0) + { + printk(KERN_WARNING "Dino %lx: gsc_alloc_irq() failed\n", + (long) dino_dev->hba.base_addr); + return(1); + } + + status = request_irq(dino_dev->irq, dino_isr, 0,"dino", dino_dev); + if(status) { + printk(KERN_WARNING "Dino %lx: request_irq() failed with %d\n", + (long) dino_dev->hba.base_addr,status); + return(1); + } + + /* + ** Tell generic interrupt support we have 11 bits which need + ** be checked in the interrupt handler. + */ + dino_dev->dino_region = alloc_irq_region( DINO_IRQS, &dino_irq_ops, + IRQ_REG_MASK|IRQ_REG_DIS, "dino", dino_dev); + + if(NULL == dino_dev->dino_region) { + printk(KERN_WARNING "Dino %lx: alloc_irq_region() failed\n", + (long) dino_dev->hba.base_addr); + return(1); + } + + /* + ** This enables DINO to generate interrupts when it sees + ** any of it's inputs *change*. Just asserting an IRQ + ** before it's enabled (ie unmasked) isn't good enough. + */ + gsc_writel(eim, dino_dev->hba.base_addr+DINO_IAR0); + + /* + ** Some platforms don't clear Dino's IRR0 register at boot time. + ** Reading will clear it now. + */ + (void) gsc_readl(dino_dev->hba.base_addr+DINO_IRR0); + + /* allocate I/O Port resource region */ + res = &dino_dev->hba.io_space; + res->name = "Dino I/O Port space"; + res->start = (unsigned long) dino_dev->hba.hba_num << 16; + res->end = res->start + 0xffffUL; + res->flags = IORESOURCE_IO; /* do not mark it busy ! */ + res->child = NULL; + if (request_resource(&ioport_resource, res) < 0) { + printk(KERN_ERR "DINO: request I/O Port region failed 0x%lx/%lx (hpa 0x%p)\n" + , res->start, res->end, dino_dev->hba.base_addr); + return(1); + } + + return(0); +} + + + +/* +** Determine if dino should claim this chip (return 0) or not (return 1). +** If so, initialize the chip appropriately (card-mode vs bridge mode). +** Much of the initialization is common though. +*/ +static int __init +dino_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri) +{ + struct dino_device *dino_dev; // Dino specific control struct + + printk("Dino version %s found at 0x%p\n",dri->version, d->hpa); + + if (!request_mem_region((ulong) d->hpa, PAGE_SIZE, "Dino HPA")) { + printk(KERN_ERR "DINO: Hey! Someone took my MMIO space (0x%p)!\n", + d->hpa); + return 1; + } + + /* + ** Card-mode dino don't have the same problem as built-in. + ** The data corruption problem in their case was fixed + ** by changing the PAL. + */ + if (!is_card_dino(d) && (d->hversion_rev < 3)) { + printk(KERN_WARNING +"\n\nThe GSCtoPCI (Dino hrev %d) bus converter found may exhibit\n" +"data corruption. See Service Note Numbers: A4190A-01, A4191A-01.\n" +"Systems shipped after Aug 20, 1997 will not exhibit this problem.\n" +"Models affected: C180, C160, C160L, B160L, and B132L workstations.\n\n", + d->hversion_rev); +/* REVISIT: why are C200/C240 listed in the README table but not +** "Models affected"? Could be an ommission in the original literature. +*/ + } + + dino_dev = kmalloc(sizeof(struct dino_device), GFP_KERNEL); + if (!dino_dev) + { + printk("dino_init_chip - couldn't alloc dino_device\n"); + return(1); + } + + memset(dino_dev, 0, sizeof(struct dino_device)); + + dino_dev->hba.iodc_info = d; + dino_dev->hba.base_addr = d->hpa; /* faster access */ + dino_dev->dinosaur_pen = SPIN_LOCK_UNLOCKED; + + if (is_card_dino(d)) + { + dino_card_init(dino_dev); + } else { + dino_bridge_init(dino_dev); + } + + if (dino_common_init(dino_dev)) + return(1); + + /* + ** It's not used to avoid chicken/egg problems + ** with configuration accessor functions. + */ + dino_dev->hba.hba_bus = + pci_scan_bus(dino_dev->hba.hba_num, &dino_cfg_ops, (void *) dino_dev); + + return 0; +} + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/gsc/gsc.c linux.ac/drivers/gsc/gsc.c --- linux.vanilla/drivers/gsc/gsc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/gsc/gsc.c Tue Apr 3 17:54:41 2001 @@ -0,0 +1,286 @@ +/* + * The Gecko device driver + * + * (c) Copyright 1999 The Puffin Group Inc. + * (c) Copyright 1999 SuSE GmbH (Philipp Rumpf, prumpf@tux.org) + * + * 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 is the GSC code. + * + * by Alex deVries <adevries@thepuffingroup.com> + * + */ + +#include <linux/errno.h> +#include <linux/config.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/proc_fs.h> +#include <asm/gsc.h> +#include <asm/led.h> + +#include <asm/io.h> +#include <asm/delay.h> +#include <linux/malloc.h> +#include <linux/smp_lock.h> +#include <linux/interrupt.h> + +#include <asm/page.h> +#include <asm/segment.h> +#include <asm/system.h> +#include <asm/smp.h> +#include <linux/spinlock.h> + +#include <asm/irq.h> +#include <asm/machdep.h> + +#include <asm/processor.h> /* for boot_cpu_data */ +/* +** Intended for ccio/sba/cpu statistics under /proc/bus/{runway|gsc} +*/ +struct proc_dir_entry * proc_runway_root = NULL; +struct proc_dir_entry * proc_gsc_root = NULL; + + +/* values available for io_command: */ +#define CMD_STOP 0 /* halt any I/O, enable diagnostic access */ +#define CMD_FLUSH 1 /* abort DMA */ +#define CMD_CHAIN 2 /* initiate DMA */ +#define CMD_CLEAR 3 /* clear errors */ +#define CMD_RESET 5 /* reset any module */ +#define CMD_PORT 32 /* set port bit on bus convertor */ + +u8 _gsc_readb(void *addr) +{ + long flags; + u8 ret; + + asm volatile( + " rsm 2,%0 + ldbx 0(%2),%1 + mtsm %0" + : "=&r" (flags), "=r" (ret) : "r" (addr) ); + + return ret; +} + +u16 _gsc_readw(void *addr) +{ + long flags; + u16 ret; + + asm volatile( + " rsm 2,%0 + ldhx 0(%2),%1 + mtsm %0" + : "=&r" (flags), "=r" (ret) : "r" (addr) ); + + return ret; +} + +u32 _gsc_readl(void *addr) +{ + long flags; + u32 ret; + + asm volatile( + " rsm 2,%0 + ldwx 0(%2),%1 + mtsm %0" + : "=&r" (flags), "=r" (ret) : "r" (addr) ); + + return ret; +} + +u64 _gsc_readq(void *addr) +{ + u64 ret; +#if BITS_PER_LONG > 32 + long flags; + asm volatile( + " rsm 2,%0 + ldd 0(%2),%1 + mtsm %0" + : "=&r" (flags), "=r" (ret) : "r" (addr) ); +#else + /* two reads may have side effects.. */ + ret = _gsc_readl(addr); + ret <<= 32; + ret |= _gsc_readl(addr+4); +#endif + return ret; +} + +void _gsc_writeb(u8 val, void *addr) +{ + long flags; + asm volatile( + " rsm 2,%0 + stbs %1,0(%2) + mtsm %0" + : "=&r" (flags) : "r" (val), "r" (addr) ); +} + +void _gsc_writew(u16 val, void *addr) +{ + long flags; + asm volatile( + " rsm 2,%0 + sths %1,0(%2) + mtsm %0" + : "=&r" (flags) : "r" (val), "r" (addr) ); +} + +void _gsc_writel(u32 val, void *addr) +{ + long flags; + asm volatile( + " rsm 2,%0 + stws %1,0(%2) + mtsm %0" + : "=&r" (flags) : "r" (val), "r" (addr) ); +} + +void _gsc_writeq(u64 val, void *addr) +{ +#if BITS_PER_LONG > 32 + long flags; + asm volatile( + " rsm 2,%0 + std %1,0(%2) + mtsm %0" + : "=&r" (flags) : "r" (val), "r" (addr) ); +#else + /* two writes may have side effects.. */ + _gsc_writel(val>>32, addr); + _gsc_writel(val, addr+4); +#endif +} + + +int gsc_alloc_irq(struct gsc_irq *i) +{ + int irq = txn_alloc_irq(); + if(irq < 0) { + printk("cannot get irq\n"); + return irq; + } + + i->txn_addr = txn_alloc_addr(irq); + i->txn_data = txn_alloc_data(irq, GSC_EIM_WIDTH); + i->irq = irq; + + return irq; +} + + +int gsc_claim_irq(struct gsc_irq *i, int irq) +{ + int c = irq; + + irq += IRQ_FROM_REGION(CPU_IRQ_REGION); /* virtualize the IRQ first */ + + irq = txn_claim_irq(irq); + if(irq < 0) { + printk("cannot claim irq %d\n", c); + return irq; + } + + i->txn_addr = txn_alloc_addr(irq); + i->txn_data = txn_alloc_data(irq, GSC_EIM_WIDTH); + i->irq = irq; + + return irq; +} + + +void __init gsc_init(void) +{ +#if defined(CONFIG_PCI) +#if defined(CONFIG_GSC_DINO) + extern void dino_init(void); +#endif + /* FIXME: This isn't GSC related. + ** In fact, these boxes don't have GSC at all. + ** It's just a convient place to put these + ** calls for testing pre-release code. + */ + +#if defined(CONFIG_IOSAPIC) + extern void iosapic_init(void); +#endif +#if defined(CONFIG_PCI_LBA) + extern void lba_init(void); +#endif +#if defined(CONFIG_IOMMU_SBA) + extern void sba_init(void); +#endif +#endif /* CONFIG_PCI */ +#if defined(CONFIG_IOMMU_CCIO) + extern void ccio_init(void); +#endif +#ifdef CONFIG_GSC_LASI + extern void busdevices_init(void); +#endif + + /* + ** Can't call proc_mkdir() until after proc_root_init() has been + ** called by start_kernel(). In other words, this code can't + ** live in arch/.../setup.c because start_parisc() calls + ** start_kernel(). + */ + switch (boot_cpu_data.cpu_type) { + case pcxl: + case pcxl2: + if (NULL == proc_gsc_root) + { + proc_gsc_root = proc_mkdir("bus/gsc", 0); + } + break; + case pcxt_: + case pcxu: + case pcxu_: + case pcxw: + case pcxw_: + if (NULL == proc_runway_root) + { + proc_runway_root = proc_mkdir("bus/runway", 0); + } + break; + } + + +#ifdef CONFIG_GSC_LASI + busdevices_init(); +#endif + +#if defined(CONFIG_PCI) +#if defined(CONFIG_GSC_DINO) + dino_init(); +#endif +#if defined(CONFIG_IOSAPIC) + iosapic_init(); +#endif +#if defined(CONFIG_PCI_LBA) + lba_init(); +#endif +#if defined(CONFIG_IOMMU_SBA) + sba_init(); +#endif +#endif + +#if defined(CONFIG_IOMMU_CCIO) + ccio_init(); +#endif + +#ifdef CONFIG_CHASSIS_LCD_LED + register_led_regions(); /* register LED port info in procfs */ +#endif +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/gsc/hil.c linux.ac/drivers/gsc/hil.c --- linux.vanilla/drivers/gsc/hil.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/gsc/hil.c Tue Apr 3 17:54:41 2001 @@ -0,0 +1,63 @@ +/* + * HIL Device Initialisation for LASI/ASP/WAX + * + * (c) Copyright 2000 The Puffin Group Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * by Helge Deller <deller@gmx.de> + */ + +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/malloc.h> +#include <asm/gsc.h> + +#include "busdevice.h" + +unsigned int hil_base; /* BASE of HIL-Port, will be set by WAX or ASP ! */ +unsigned int hil_irq; + +extern int hil_keyb_init(void); + +static int __init +hil_init_chip(struct hp_device *d, struct pa_iodc_driver *dri) +{ + int retval, irq; + + irq = busdevice_alloc_irq(d); + + if (!irq) { + printk(__FILE__ ": IRQ not found for HIL at 0x%p\n", d->hpa); + return -ENODEV; + } + + hil_base = (unsigned int) d->hpa; + hil_irq = irq; /* store the IRQ */ + + printk(KERN_INFO "Found HIL at 0x%x, IRQ %d\n", hil_base, hil_irq); + + /* hil_keyb_init() uses hil_base and hil_irq */ + retval = hil_keyb_init(); /* Human Interface Loop driver */ + + return retval; +} + + +static struct pa_iodc_driver hil_drivers_for[] __initdata = { + {HPHW_FIO, 0x0, 0x0, 0x73, 0x0, 0, + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + "HIL", "712, 715 or similiar", (void *) hil_init_chip}, + { 0 } +}; + +void __init +register_hil_drivers(void) +{ + register_driver(hil_drivers_for); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/gsc/lan.c linux.ac/drivers/gsc/lan.c --- linux.vanilla/drivers/gsc/lan.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/gsc/lan.c Tue Apr 3 17:54:41 2001 @@ -0,0 +1,82 @@ +/* + * LAN Device Initialisation for LASI/ASP + * + * (c) Copyright 2000 The Puffin Group Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * by Helge Deller <deller@gmx.de> + */ + +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/malloc.h> +#include <asm/gsc.h> + +#include "busdevice.h" + +#include <linux/netdevice.h> + + +extern int __init lasi_i82596_probe(struct net_device *dev); +extern int __init asp_i82596_probe(struct net_device *dev); + + +static int __init +lan_init_chip(struct hp_device *d, struct pa_iodc_driver *dri) +{ + struct net_device *netdevice; + int retval, irq; + + irq = busdevice_alloc_irq(d); + + if (!irq) { + printk(KERN_ERR __FILE__ ": IRQ not found for i82596 at 0x%p\n", d->hpa); + return -ENODEV; + } + + printk(KERN_INFO "Found i82596 at 0x%p, IRQ %d\n", d->hpa, irq); + + netdevice = kmalloc(sizeof(*netdevice), GFP_KERNEL); + if (!netdevice) + return -ENOMEM; + + memset(netdevice, 0, sizeof(*netdevice)); + strcpy(netdevice->name,"eth0"); + netdevice->base_addr = (unsigned long) d->hpa; + netdevice->irq = irq; + netdevice->init = + (d->sversion == 0x72) ? asp_i82596_probe :lasi_i82596_probe; + + retval = register_netdevice(netdevice); + + if (retval) { + printk(KERN_WARNING __FILE__ ": register_netdevice ret'd %d\n", retval); + kfree(netdevice); + return -ENODEV; + }; + + return retval; +} + + +static struct pa_iodc_driver lan_drivers_for[] __initdata = { + {HPHW_FIO, 0x0, 0x0, 0x8a, 0x0, 0, + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + "Lasi i82596 LAN", "712, 715 or similiar", (void *) lan_init_chip}, + {HPHW_FIO, 0x0, 0x0, 0x72, 0x0, 0, + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + "ASP i82596 LAN", "700 or similiar (old)", (void *) lan_init_chip}, + { 0 } +}; + +void __init +register_lan_drivers(void) +{ + register_driver(lan_drivers_for); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/gsc/lasi.c linux.ac/drivers/gsc/lasi.c --- linux.vanilla/drivers/gsc/lasi.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/gsc/lasi.c Tue Apr 3 17:54:41 2001 @@ -0,0 +1,227 @@ +/* + * LASI Device Driver + * + * (c) Copyright 1999 Red Hat Software + * Portions (c) Copyright 1999 The Puffin Group Inc. + * Portions (c) Copyright 1999 Hewlett-Packard + * + * 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. + * + * by Alan Cox <alan@redhat.com> and + * Alex deVries <adevries@thepuffingroup.com> + */ + +#include <linux/config.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/malloc.h> +#include <linux/pm.h> +#include <asm/gsc.h> +#include <asm/led.h> +#include <linux/irq.h> + +#include "busdevice.h" + + +#define LASI_VER 0xC008 /* LASI Version */ + +#define LASI_IO_CONF 0x7FFFE /* LASI primary configuration register */ +#define LASI_IO_CONF2 0x7FFFF /* LASI secondary configuration register */ + +static int +lasi_find_irq(struct busdevice *lasi_dev, struct hp_device *dev) +{ + int irq; + int off = ((int) dev->hpa) & 0xffff; + + /* + ** "irq" bits below are numbered relative to most significant bit. + */ + switch (off) { + case 0x0000: irq = 17; break; /* Lasi itself */ + case 0x2000: irq = 24; break; /* Centronics/Parallel Port on Lasi */ + case 0x4000: irq = 18; break; /* Audio */ +// case 0x4???: irq = 13; break; /* ISDN */ + case 0x5000: irq = 26; break; /* RS232 */ + case 0x6000: irq = 22; break; /* SCSI */ + case 0x7000: irq = 23; break; /* LAN */ + case 0x8000: irq = 5; break; /* PS/2 Keyboard and Mouse */ + case 0xA000: irq = 11; break; /* Floppy Disk Controller */ + default: irq = -1; break; /* unknown */ + } + + return irq; +} + +static void __init +lasi_init_irq(struct busdevice *this_lasi) +{ + char *lasi_base = (char *) this_lasi->hpa; + + /* Stop LASI barking for a bit */ + gsc_writel(0x00000000, lasi_base+OFFSET_IMR); + + /* clear pending interrupts */ + (volatile u32) gsc_readl(lasi_base+OFFSET_IRR); + + /* We're not really convinced we want to reset the onboard + * devices. Firmware does it for us... + */ + + /* Resets */ + /* gsc_writel(0xFFFFFFFF, lasi_base+0x2000);*/ /* Parallel */ + gsc_writel(0xFFFFFFFF, lasi_base+0x4004); /* Audio */ + /* gsc_writel(0xFFFFFFFF, lasi_base+0x5000);*/ /* Serial */ + /* gsc_writel(0xFFFFFFFF, lasi_base+0x6000);*/ /* SCSI */ + gsc_writel(0xFFFFFFFF, lasi_base+0x7000); /* LAN */ + gsc_writel(0xFFFFFFFF, lasi_base+0x8000); /* Keyboard */ + gsc_writel(0xFFFFFFFF, lasi_base+0xA000); /* FDC */ + + /* Ok we hit it on the head with a hammer, our Dog is now + ** comatose and muzzled. Devices will now unmask LASI + ** interrupts as they are registered as irq's in the LASI range. + */ +} + + +/* + ** lasi_led_init() + ** + ** lasi_led_init() initializes the LED controller on the LASI. + ** + ** Since Mirage and Electra machines use a different LED + ** address register, we need to check for these machines + ** explicitly. + */ + +#ifndef CONFIG_CHASSIS_LCD_LED + +#define lasi_led_init(x) /* nothing */ + +#else + +void __init lasi_led_init(char *lasi_hpa) +{ + char *datareg; + + switch (CPU_HVERSION) { + /* Gecko machines have only one single LED, which can be permanently + turned on by writing a zero into the power control register. */ + case 0x600: /* Gecko (712/60) */ + case 0x601: /* Gecko (712/80) */ + case 0x602: /* Gecko (712/100) */ + case 0x603: /* Anole 64 (743/64) */ + case 0x604: /* Anole 100 (743/100) */ + case 0x605: /* Gecko (712/120) */ + datareg = lasi_hpa + 0x0000C000; + gsc_writeb(0, datareg); + return; /* no need to register the LED interrupt-function */ + + /* Mirage and Electra machines need special offsets */ + case 0x60A: /* Mirage Jr (715/64) */ + case 0x60B: /* Mirage 100 */ + case 0x60C: /* Mirage 100+ */ + case 0x60D: /* Electra 100 */ + case 0x60E: /* Electra 120 */ + datareg = lasi_hpa - 0x00020000; + break; + + default: + datareg = lasi_hpa + 0x0000C000; + break; + } /* switch() */ + + register_led_driver(DISPLAY_MODEL_LASI, LED_CMD_REG_NONE, datareg); +} +#endif + +/* + * lasi_power_off + * + * Function for lasi to turn off the power. This is accomplished by setting a + * 1 to PWR_ON_L in the Power Control Register + * + * KNOWN BUG: doesn't work yet on 715/64 /80 and /100 (new 715 machines) and above + */ + +static char * lasi_power_off_hpa; + +static void lasi_power_off(void) +{ + char *datareg; + + /* calculate addr of the Power Control Register */ + datareg = lasi_power_off_hpa + 0x0000C000; + + /* Power down the machine */ + gsc_writel(0x02, datareg); + +} + +int __init +lasi_init_chip(struct hp_device *d, struct pa_iodc_driver *dri) +{ + struct busdevice *lasi; + struct gsc_irq gsc_irq; + int irq, ret; + + lasi = kmalloc(sizeof(struct busdevice), GFP_KERNEL); + if (!lasi) + return -ENOMEM; + + lasi->name = "Lasi"; + lasi->hpa = d->hpa; + lasi->find_irq = lasi_find_irq; + + /* Check the 4-bit (yes, only 4) version register */ + lasi->version = gsc_readl(lasi->hpa + LASI_VER) & 0xf; + printk(KERN_INFO "%s version %d at 0x%p found.\n", + lasi->name, lasi->version, lasi->hpa); + + /* initialize the chassis LEDs really early */ + lasi_led_init((char *)lasi->hpa); + + /* Stop LASI barking for a bit */ + lasi_init_irq(lasi); + + /* the IRQ lasi should use */ + irq = gsc_alloc_irq(&gsc_irq); + if (irq < 0) { + printk(KERN_ERR __FUNCTION__ ": cannot get GSC irq\n"); + kfree(lasi); + return -EBUSY; + } + + ret = request_irq(gsc_irq.irq, busdev_barked, 0, "lasi", lasi); + if (ret < 0) { + kfree(lasi); + return ret; + } + + /* Save this for debugging later */ + lasi->parent_irq = gsc_irq.irq; + lasi->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data; + + /* enable IRQ's for devices below LASI */ + gsc_writel(lasi->eim, lasi->hpa + OFFSET_IAR); + + /* Done init'ing, register this driver */ + ret = register_busdevice( d, lasi ); + if (ret) { + kfree(lasi); + return ret; + } + + /* initialize the power off function */ + /* FIXME: Record the LASI HPA for the power off function. This should + * ensure that only the first LASI (the one controlling the power off) + * should set the HPA here */ + lasi_power_off_hpa = (char *)lasi->hpa; + pm_power_off = lasi_power_off; + + return ret; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/gsc/lasi.h linux.ac/drivers/gsc/lasi.h --- linux.vanilla/drivers/gsc/lasi.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/gsc/lasi.h Tue Apr 3 17:54:41 2001 @@ -0,0 +1,15 @@ + +/* The driver doesn't *really* need to know this. +** But we don't want to forget either... +** busdevice_alloc_irq() will figure out which IRQ a given +** device is using. +*/ +#define LASI_SERIAL_IRQ 26 /* Built-in RS-232C */ +#define LASI_CENT_IRQ 24 /* Built-in Parallel Interface */ +#define LASI_LAN_IRQ 23 /* Built-in LAN */ +#define LASI_SCSI_IRQ 22 /* Built-in SCSI */ +#define LASI_AUDIO_2_IRQ 18 /* Built-in Audio */ +#define LASI_IRQ 17 /* Bus-error interrupt */ +#define LASI_ISDN_IRQ 13 /* Built-in ISDN */ +#define LASI_FLOPPY_IRQ 11 /* Built-in Floppy Drive */ +#define LASI_KBD_IRQ 5 /* Built-in Keyboard/Mouse */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/gsc/serial.c linux.ac/drivers/gsc/serial.c --- linux.vanilla/drivers/gsc/serial.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/gsc/serial.c Tue Apr 3 17:54:41 2001 @@ -0,0 +1,112 @@ +/* + * Serial Device Initialisation for LASI/ASP/WAX + * + * (c) Copyright 2000 The Puffin Group Inc. + * (c) Copyright 2000-2001 Helge Deller <deller@gmx.de> + * + * 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 <linux/config.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/timex.h> +#include <linux/malloc.h> +#include <linux/random.h> +#include <linux/serial.h> + +#include <asm/serial.h> +#include <asm/io.h> +#include <asm/hardware.h> +#include <asm/gsc.h> + +#include "busdevice.h" + + +static int serial_line_nr; + +static int __init +serial_init_chip(struct hp_device *d, struct pa_iodc_driver *dri) +{ + struct serial_struct *serial; + int retval, irq; + + irq = busdevice_alloc_irq(d); + if (!irq) { +#ifndef CONFIG_GSC_WAX + if (serial_line_nr == 1) + printk(KERN_INFO "This kernel was compiled without WAX support, but apparently you will need to\n" + "enable WAX support in order to use the 2nd serial port (ttyS1) on this machine.\n"); +#endif + printk(KERN_WARNING "IRQ not found for serial device at 0x%p\n", d->hpa); + return -ENODEV; + } + + serial = kmalloc(sizeof(*serial), GFP_KERNEL); + if (!serial) + return -ENOMEM; + + memset(serial, 0, sizeof(struct serial_struct)); + + /* autoconfig() sets state->type. + ** Here we are setting the "info->type" + */ + serial->type = PORT_16550A; + + serial->line = serial_line_nr; + serial->iomem_base = (void*) (((unsigned long) d->hpa) + 0x800); + +#ifdef CONFIG_SERIAL_CONSOLE + /* FIXME: inb/outb have been aliased to gsc_readb/writeb in serial.c */ + serial->port = (unsigned long) serial->iomem_base; +#endif + + serial->irq = irq; + serial->io_type = SERIAL_IO_GSC; /* define access method */ + serial->flags = 0; + serial->xmit_fifo_size = 16; + serial->custom_divisor = 0; + serial->baud_base = LASI_BASE_BAUD; + + retval = register_serial(serial); + if (retval < 0) { + printk(KERN_WARNING "%s:%s: register_serial ret'd %d\n", + __FILE__, __FUNCTION__, retval); + kfree(serial); + return -ENODEV; + } + + serial_line_nr++; + return 0; +} + + +static struct pa_iodc_driver serial_drivers_for[] __initdata = { + {HPHW_FIO, 0x05F, 0x0, 0x00081, 0x0, 0, /* A-class 180 */ + DRIVER_CHECK_HVERSION + DRIVER_CHECK_HVERSION_REV + + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + "serial device", "unknown", (void *) serial_init_chip}, + {HPHW_FIO, 0x0, 0x0, 0x8c, 0x0, 0, /* 715/64 */ + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + "serial device", "715/new or similiar", (void *) serial_init_chip}, + {HPHW_FIO, 0x0, 0x0, 0x75, 0x0, 0, /* 715/33 */ + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + "serial device", "712, 715/old or similiar", (void *) serial_init_chip}, + { 0 } +}; + +void __init +probe_serial_gsc(void) +{ + register_driver(serial_drivers_for); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/gsc/wax.c linux.ac/drivers/gsc/wax.c --- linux.vanilla/drivers/gsc/wax.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/gsc/wax.c Tue Apr 3 17:54:41 2001 @@ -0,0 +1,155 @@ +/* + * WAX Device Driver + * + * (c) Copyright 2000 The Puffin Group Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * by Helge Deller <deller@gmx.de> + */ + +#include <linux/config.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/malloc.h> +#include <asm/io.h> +#include <asm/hardware.h> +#include <asm/gsc.h> +#include <asm/irq.h> + +#include "busdevice.h" + + +#define WAX_GSC_IRQ 7 /* Hardcoded Interrupt for GSC */ +#define WAX_GSC_NMI_IRQ 29 + +static struct pa_iodc_driver wax_driver_for[] = { + {HPHW_BA, 0x0, 0, 0x0008e, 0, 0, + DRIVER_CHECK_HWTYPE + DRIVER_CHECK_SVERSION, + "Wax", "generic", (void *) wax_init_chip}, + {0} +}; + +int __init register_wax_driver(void) { + register_driver(wax_driver_for); +} + +static int wax_find_irq(struct busdevice *lasi_dev, struct hp_device *dev) +{ + int irq; + int off = ((int) dev->hpa) & 0xffff; + + /* + ** "irq" bits below are numbered relative to most significant bit. + */ + switch (off) { + case 0x0000: irq = -1; break; /* FIXME? WAX itself */ + case 0x1000: irq = 30; break; /* HIL */ + case 0x2000: irq = 25; break; /* RS232 No.2 on WAX (No.1 is on Lasi) */ + default: irq = -1; break; /* unknown */ + } + + return irq; +} + +#ifdef CONFIG_HIL +/* Reset (NMI) via HIL-Keyboard. */ +static void +wax_hil_nmi(int irq, void *handle, struct pt_regs *regs) +{ + printk(KERN_CRIT "HIL-NMI !\n"); +} +#endif + +static void __init +wax_init_irq(struct busdevice *wax) +{ + char *base = (char *) wax->hpa; + + /* Stop WAX barking for a bit */ + gsc_writel(0x00000000, base+OFFSET_IMR); + + /* clear pending interrupts */ + (volatile u32) gsc_readl(base+OFFSET_IRR); + + /* We're not really convinced we want to reset the onboard + * devices. Firmware does it for us... + */ + + /* Resets */ +// gsc_writel(0xFFFFFFFF, base+0x1000); /* HIL */ +// gsc_writel(0xFFFFFFFF, base+0x2000); /* RS232-B on Wax */ + + /* Ok we hit it on the head with a hammer, our Dog is now + ** comatose and muzzled. Devices will now unmask WAX + ** interrupts as they are registered as irq's in the WAX range. + */ +} + +int __init +wax_init_chip(struct hp_device *d, struct pa_iodc_driver *dri) +{ + struct busdevice *wax; + struct gsc_irq gsc_irq; + int irq, ret; + + wax = kmalloc(sizeof(struct busdevice), GFP_KERNEL); + if(!wax) + return -ENOMEM; + + wax->name = "Wax"; + wax->hpa = d->hpa; + wax->find_irq = wax_find_irq; + + wax->version = 0; /* gsc_readb(wax->hpa+WAX_VER); */ + printk(KERN_INFO "%s at 0x%p found.\n", wax->name, wax->hpa); + + /* Stop wax hissing for a bit */ + wax_init_irq(wax); + + /* the IRQ wax should use */ + irq = gsc_claim_irq(&gsc_irq, WAX_GSC_IRQ); + if (irq < 0) { + printk(KERN_ERR __FUNCTION__ ": cannot get GSC irq\n"); + kfree(wax); + return -EBUSY; + } + + ret = request_irq(gsc_irq.irq, busdev_barked, 0, "wax", wax); + if (ret < 0) { + kfree(wax); + return ret; + } + + /* Save this for debugging later */ + wax->parent_irq = gsc_irq.irq; + wax->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data; + + /* enable IRQ's for devices below WAX */ +// gsc_writel(wax->eim, wax->hpa + OFFSET_IAR); + + /* Done init'ing, register this driver */ + ret = register_busdevice( d, wax ); + if (ret) + kfree(wax); + + /* Register the HIL-Keyboard NMI-Handler */ +#ifdef CONFIG_HIL + request_irq( (wax->busdev_region->data.irqbase) + WAX_GSC_NMI_IRQ, + &wax_hil_nmi, 0, "wax_hil_nmi", NULL); + printk("%s: HIL Keyboard-NMI registered.\n", wax->name); +#endif + +#ifdef CONFIG_WAX_EISA + register_wax_eisa_driver(); +#endif + + return ret; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/gsc/wax_eisa.c linux.ac/drivers/gsc/wax_eisa.c --- linux.vanilla/drivers/gsc/wax_eisa.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/gsc/wax_eisa.c Tue Apr 3 17:54:41 2001 @@ -0,0 +1,140 @@ +/* + * WAX EISA Bus Adapter Device Driver + * + * (c) Copyright 2000 Linuxcare Canada + * + * 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. + * + * by Alex deVries <alex@linuxcare.com> + */ + +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/malloc.h> +#include <asm/io.h> +#include <asm/hardware.h> +#include <asm/gsc.h> +#include <asm/irq.h> +#include <asm/pci.h> +#include <asm/processor.h> + +#include "busdevice.h" + +static int wax_eisa_driver_init(struct hp_device *d, struct pa_iodc_driver *dri); + +static struct pa_iodc_driver wax_eisa_drivers_for[] = { + {HPHW_BA, 0x01B, 0, 0x0008e, 0x0, 0x0, + DRIVER_CHECK_HWTYPE + DRIVER_CHECK_SVERSION, + "Wax EISA BA", "Wax EISA BA", (void *) wax_eisa_driver_init}, + {HPHW_BA, 0x01B, 0, 0x00076, 0x0, 0x0, + DRIVER_CHECK_HWTYPE + DRIVER_CHECK_SVERSION, + "Wax EISA BA", "Wax EISA BA", (void *) wax_eisa_driver_init}, + {0,0,0,0,0,0,0, + (char *) NULL,(char *) NULL,(void *) NULL} +}; + +#define WAX_EISA_OUT(type, size) \ +static void wax_out##type (u##size d, int addr) \ +{ \ + u32 out_addr; \ + if (((addr >= 0x00080000) && (addr < 0x00100000)) || \ + ((addr >= 0x00500000) && (addr < 0x03C00000))) { \ + out_addr = 0xfc000000 + ((addr & 0xfc00) >> 6) + \ + ((addr & 0x03f8) << 9) + (addr & 0x0007) ; \ + gsc_write##type(d,out_addr); \ + } else { \ + printk("Wax EISA: Ack, cannot write to 0x%x\n",addr); \ + } \ +} + +WAX_EISA_OUT(b,8) +WAX_EISA_OUT(w,16) +WAX_EISA_OUT(l,32) + +#define WAX_EISA_IN(type, size) \ +static u##size wax_in##type (int addr) \ +{ \ + u32 out_addr; \ + if (((addr >= 0x00080000) && (addr < 0x00100000)) || \ + ((addr >= 0x00500000) && (addr < 0x03C00000))) { \ + out_addr = 0xfc000000 + ((addr & 0xfc00) >> 6) + \ + ((addr & 0x03f8) << 9) + (addr & 0x0007) ; \ + return gsc_read##type(out_addr); \ + } else { \ + printk("WAX EISA Ack, cannot read from 0x%x\n",addr); \ + return -1; \ + } \ +} + +WAX_EISA_IN(b,8) +WAX_EISA_IN(w,16) +WAX_EISA_IN(l,32) + +static struct pci_port_ops wax_port_ops = { + wax_inb, wax_inl, wax_inw, + wax_outb, wax_outl, wax_outw +}; + +struct pci_hba_data wax_eisa_hba; + +#define outsl(x) outl((x)) +#define insl(x) inl((x)) + +/* +The following need to be created still. +memset_io +isa_memcpy_toio(a,b,c) memcpy_toio +isa_memset_io +memcpy_frioio +isa_memcpy_from_io + +*/ +#define isa_readl(x) inl((x)) + + + +void __init +register_wax_eisa_driver(void) +{ + register_driver(wax_eisa_drivers_for); +} + +static int +wax_eisa_driver_init(struct hp_device *d, struct pa_iodc_driver *dri) { + + int version; + + /* It sounds unusual, but because the parisc-linux PCI infrastructure + has been done so well, I'm just going to register the WAX EISA + bus adapter as a PCI device. This is to handle the in{w|l|b} + and out{w|l|b} routines. */ + + version = gsc_readw(d->hpa+0x7000); + printk(KERN_INFO "Wax EISA bus adapter version 0x%x at 0x%p\n",version,d->hpa); + + pcibios_register_hba((struct pci_hba_data *) &wax_port_ops); + +#if 0 + /* Turn off lock control */ + gsc_writeb(0x0,d->hpa + 0x10001); + + /* Disable the FIFO */ + gsc_writeb(0x0,d->hpa + 0x11001); + + /* Disable multiple splits and concurrent bus accesses */ + gsc_writeb(0x0,d->hpa + 0x12001); + +#endif + + EISA_bus = 1; + + return 0; + +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/i2o/Config.in linux.ac/drivers/i2o/Config.in --- linux.vanilla/drivers/i2o/Config.in Wed Apr 12 17:38:53 2000 +++ linux.ac/drivers/i2o/Config.in Thu Jan 1 01:00:00 1970 @@ -1,16 +0,0 @@ -mainmenu_option next_comment -comment 'I2O device support' - -tristate 'I2O support' CONFIG_I2O - -if [ "$CONFIG_PCI" = "y" ]; then - dep_tristate ' I2O PCI support' CONFIG_I2O_PCI $CONFIG_I2O -fi -dep_tristate ' I2O Block OSM' CONFIG_I2O_BLOCK $CONFIG_I2O -if [ "$CONFIG_NET" = "y" ]; then - dep_tristate ' I2O LAN OSM' CONFIG_I2O_LAN $CONFIG_I2O -fi -dep_tristate ' I2O SCSI OSM' CONFIG_I2O_SCSI $CONFIG_I2O $CONFIG_SCSI -dep_tristate ' I2O /proc support' CONFIG_I2O_PROC $CONFIG_I2O - -endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/i2o/Makefile linux.ac/drivers/i2o/Makefile --- linux.vanilla/drivers/i2o/Makefile Fri Dec 29 22:07:21 2000 +++ linux.ac/drivers/i2o/Makefile Thu Jan 1 01:00:00 1970 @@ -1,20 +0,0 @@ -# -# Makefile for the kernel I2O OSM. -# -# Note : at this point, these files are compiled on all systems. -# In the future, some of these should be built conditionally. -# - -O_TARGET := i2o.o - -export-objs := i2o_pci.o i2o_core.o i2o_config.o i2o_block.o i2o_lan.o i2o_scsi.o i2o_proc.o - -obj-$(CONFIG_I2O_PCI) += i2o_pci.o -obj-$(CONFIG_I2O) += i2o_core.o i2o_config.o -obj-$(CONFIG_I2O_BLOCK) += i2o_block.o -obj-$(CONFIG_I2O_LAN) += i2o_lan.o -obj-$(CONFIG_I2O_SCSI) += i2o_scsi.o -obj-$(CONFIG_I2O_PROC) += i2o_proc.o - -include $(TOPDIR)/Rules.make - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/i2o/README linux.ac/drivers/i2o/README --- linux.vanilla/drivers/i2o/README Mon Jun 19 21:30:55 2000 +++ linux.ac/drivers/i2o/README Thu Jan 1 01:00:00 1970 @@ -1,98 +0,0 @@ - - Linux I2O Support (c) Copyright 1999 Red Hat Software - and others. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version - 2 of the License, or (at your option) any later version. - -AUTHORS (so far) - -Alan Cox, Building Number Three Ltd. - Core code, SCSI and Block OSMs - -Steve Ralston, LSI Logic Corp. - Debugging SCSI and Block OSM - -Deepak Saxena, Intel Corp. - Various core/block extensions - /proc interface, bug fixes - Ioctl interfaces for control - Debugging LAN OSM - -Philip Rumpf - Fixed assorted dumb SMP locking bugs - -Juha Sievanen, University of Helsinki Finland - LAN OSM code - /proc interface to LAN class - Bug fixes - Core code extensions - -Auvo Häkkinen, University of Helsinki Finland - LAN OSM code - /Proc interface to LAN class - Bug fixes - Core code extensions - -Taneli Vähäkangas, University of Helsinki Finland - Fixes to i2o_config - -CREDITS - - This work was made possible by - -Red Hat Software - Funding for the Building #3 part of the project - -Symbios Logic (Now LSI) - Host adapters, hints, known to work platforms when I hit - compatibility problems - -BoxHill Corporation - Loan of initial FibreChannel disk array used for development work. - -European Comission - Funding the work done by the University of Helsinki - -SysKonnect - Loan of FDDI and Gigabit Ethernet cards - -ASUSTeK - Loan of I2O motherboard - -STATUS: - -o The core setup works within limits. -o The scsi layer seems to almost work. - I'm still chasing down the hang bug. -o The block OSM is mostly functional -o LAN OSM works with FDDI and Ethernet cards. - -TO DO: - -General: -o Provide hidden address space if asked -o Long term message flow control -o PCI IOP's without interrupts are not supported yet -o Push FAIL handling into the core -o DDM control interfaces for module load etc -o Add I2O 2.0 support (Deffered to 2.5 kernel) - -Block: -o Multiple major numbers -o Read ahead and cache handling stuff. Talk to Ingo and people -o Power management -o Finish Media changers - -SCSI: -o Find the right way to associate drives/luns/busses - -Lan: -o Performance tuning -o Test Fibre Channel code - -Tape: -o Anyone seen anything implementing this ? - (D.S: Will attempt to do so if spare cycles permit) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/i2o/README.ioctl linux.ac/drivers/i2o/README.ioctl --- linux.vanilla/drivers/i2o/README.ioctl Mon Jun 19 21:30:55 2000 +++ linux.ac/drivers/i2o/README.ioctl Thu Jan 1 01:00:00 1970 @@ -1,394 +0,0 @@ - -Linux I2O User Space Interface -rev 0.3 - 04/20/99 - -============================================================================= -Originally written by Deepak Saxena(deepak@plexity.net) -Currently maintained by Deepak Saxena(deepak@plexity.net) -============================================================================= - -I. Introduction - -The Linux I2O subsystem provides a set of ioctl() commands that can be -utilized by user space applications to communicate with IOPs and devices -on individual IOPs. This document defines the specific ioctl() commands -that are available to the user and provides examples of their uses. - -This document assumes the reader is familiar with or has access to the -I2O specification as no I2O message parameters are outlined. For information -on the specification, see http://www.i2osig.org - -This document and the I2O user space interface are currently maintained -by Deepak Saxena. Please send all comments, errata, and bug fixes to -deepak@csociety.purdue.edu - -II. IOP Access - -Access to the I2O subsystem is provided through the device file named -/dev/i2o/ctl. This file is a character file with major number 10 and minor -number 166. It can be created through the following command: - - mknod /dev/i2o/ctl c 10 166 - -III. Determining the IOP Count - - SYNOPSIS - - ioctl(fd, I2OGETIOPS, int *count); - - u8 count[MAX_I2O_CONTROLLERS]; - - DESCRIPTION - - This function returns the system's active IOP table. count should - point to a buffer containing MAX_I2O_CONTROLLERS entries. Upon - returning, each entry will contain a non-zero value if the given - IOP unit is active, and NULL if it is inactive or non-existent. - - RETURN VALUE. - - Returns 0 if no errors occur, and -1 otherwise. If an error occurs, - errno is set appropriately: - - EFAULT Invalid user space pointer was passed - -IV. Getting Hardware Resource Table - - SYNOPSIS - - ioctl(fd, I2OHRTGET, struct i2o_cmd_hrt *hrt); - - struct i2o_cmd_hrtlct - { - u32 iop; /* IOP unit number */ - void *resbuf; /* Buffer for result */ - u32 *reslen; /* Buffer length in bytes */ - }; - - DESCRIPTION - - This function returns the Hardware Resource Table of the IOP specified - by hrt->iop in the buffer pointed to by hrt->resbuf. The actual size of - the data is written into *(hrt->reslen). - - RETURNS - - This function returns 0 if no errors occur. If an error occurs, -1 - is returned and errno is set appropriately: - - EFAULT Invalid user space pointer was passed - ENXIO Invalid IOP number - ENOBUFS Buffer not large enough. If this occurs, the required - buffer length is written into *(hrt->reslen) - -V. Getting Logical Configuration Table - - SYNOPSIS - - ioctl(fd, I2OLCTGET, struct i2o_cmd_lct *lct); - - struct i2o_cmd_hrtlct - { - u32 iop; /* IOP unit number */ - void *resbuf; /* Buffer for result */ - u32 *reslen; /* Buffer length in bytes */ - }; - - DESCRIPTION - - This function returns the Logical Configuration Table of the IOP specified - by lct->iop in the buffer pointed to by lct->resbuf. The actual size of - the data is written into *(lct->reslen). - - RETURNS - - This function returns 0 if no errors occur. If an error occurs, -1 - is returned and errno is set appropriately: - - EFAULT Invalid user space pointer was passed - ENXIO Invalid IOP number - ENOBUFS Buffer not large enough. If this occurs, the required - buffer length is written into *(lct->reslen) - -VI. Settting Parameters - - SYNOPSIS - - ioctl(fd, I2OPARMSET, struct i2o_parm_setget *ops); - - struct i2o_cmd_psetget - { - u32 iop; /* IOP unit number */ - u32 tid; /* Target device TID */ - void *opbuf; /* Operation List buffer */ - u32 oplen; /* Operation List buffer length in bytes */ - void *resbuf; /* Result List buffer */ - u32 *reslen; /* Result List buffer length in bytes */ - }; - - DESCRIPTION - - This function posts a UtilParamsSet message to the device identified - by ops->iop and ops->tid. The operation list for the message is - sent through the ops->opbuf buffer, and the result list is written - into the buffer pointed to by ops->resbuf. The number of bytes - written is placed into *(ops->reslen). - - RETURNS - - The return value is the size in bytes of the data written into - ops->resbuf if no errors occur. If an error occurs, -1 is returned - and errno is set appropriatly: - - EFAULT Invalid user space pointer was passed - ENXIO Invalid IOP number - ENOBUFS Buffer not large enough. If this occurs, the required - buffer length is written into *(ops->reslen) - ETIMEDOUT Timeout waiting for reply message - ENOMEM Kernel memory allocation error - - A return value of 0 does not mean that the value was actually - changed properly on the IOP. The user should check the result - list to determine the specific status of the transaction. - -VII. Getting Parameters - - SYNOPSIS - - ioctl(fd, I2OPARMGET, struct i2o_parm_setget *ops); - - struct i2o_parm_setget - { - u32 iop; /* IOP unit number */ - u32 tid; /* Target device TID */ - void *opbuf; /* Operation List buffer */ - u32 oplen; /* Operation List buffer length in bytes */ - void *resbuf; /* Result List buffer */ - u32 *reslen; /* Result List buffer length in bytes */ - }; - - DESCRIPTION - - This function posts a UtilParamsGet message to the device identified - by ops->iop and ops->tid. The operation list for the message is - sent through the ops->opbuf buffer, and the result list is written - into the buffer pointed to by ops->resbuf. The actual size of data - written is placed into *(ops->reslen). - - RETURNS - - EFAULT Invalid user space pointer was passed - ENXIO Invalid IOP number - ENOBUFS Buffer not large enough. If this occurs, the required - buffer length is written into *(ops->reslen) - ETIMEDOUT Timeout waiting for reply message - ENOMEM Kernel memory allocation error - - A return value of 0 does not mean that the value was actually - properly retreived. The user should check the result list - to determine the specific status of the transaction. - -VIII. Downloading Software - - SYNOPSIS - - ioctl(fd, I2OSWDL, struct i2o_sw_xfer *sw); - - struct i2o_sw_xfer - { - u32 iop; /* IOP unit number */ - u8 flags; /* DownloadFlags field */ - u8 sw_type; /* Software type */ - u32 sw_id; /* Software ID */ - void *buf; /* Pointer to software buffer */ - u32 *swlen; /* Length of software buffer */ - u32 *maxfrag; /* Number of fragments */ - u32 *curfrag; /* Current fragment number */ - }; - - DESCRIPTION - - This function downloads a software fragment pointed by sw->buf - to the iop identified by sw->iop. The DownloadFlags, SwID, SwType - and SwSize fields of the ExecSwDownload message are filled in with - the values of sw->flags, sw->sw_id, sw->sw_type and *(sw->swlen). - - The fragments _must_ be sent in order and be 8K in size. The last - fragment _may_ be shorter, however. The kernel will compute its - size based on information in the sw->swlen field. - - Please note that SW transfers can take a long time. - - RETURNS - - This function returns 0 no errors occur. If an error occurs, -1 - is returned and errno is set appropriatly: - - EFAULT Invalid user space pointer was passed - ENXIO Invalid IOP number - ETIMEDOUT Timeout waiting for reply message - ENOMEM Kernel memory allocation error - -IX. Uploading Software - - SYNOPSIS - - ioctl(fd, I2OSWUL, struct i2o_sw_xfer *sw); - - struct i2o_sw_xfer - { - u32 iop; /* IOP unit number */ - u8 flags; /* UploadFlags */ - u8 sw_type; /* Software type */ - u32 sw_id; /* Software ID */ - void *buf; /* Pointer to software buffer */ - u32 *swlen; /* Length of software buffer */ - u32 *maxfrag; /* Number of fragments */ - u32 *curfrag; /* Current fragment number */ - }; - - DESCRIPTION - - This function uploads a software fragment from the IOP identified - by sw->iop, sw->sw_type, sw->sw_id and optionally sw->swlen fields. - The UploadFlags, SwID, SwType and SwSize fields of the ExecSwUpload - message are filled in with the values of sw->flags, sw->sw_id, - sw->sw_type and *(sw->swlen). - - The fragments _must_ be requested in order and be 8K in size. The - user is responsible for allocating memory pointed by sw->buf. The - last fragment _may_ be shorter. - - Please note that SW transfers can take a long time. - - RETURNS - - This function returns 0 if no errors occur. If an error occurs, -1 - is returned and errno is set appropriatly: - - EFAULT Invalid user space pointer was passed - ENXIO Invalid IOP number - ETIMEDOUT Timeout waiting for reply message - ENOMEM Kernel memory allocation error - -X. Removing Software - - SYNOPSIS - - ioctl(fd, I2OSWDEL, struct i2o_sw_xfer *sw); - - struct i2o_sw_xfer - { - u32 iop; /* IOP unit number */ - u8 flags; /* RemoveFlags */ - u8 sw_type; /* Software type */ - u32 sw_id; /* Software ID */ - void *buf; /* Unused */ - u32 *swlen; /* Length of the software data */ - u32 *maxfrag; /* Unused */ - u32 *curfrag; /* Unused */ - }; - - DESCRIPTION - - This function removes software from the IOP identified by sw->iop. - The RemoveFlags, SwID, SwType and SwSize fields of the ExecSwRemove message - are filled in with the values of sw->flags, sw->sw_id, sw->sw_type and - *(sw->swlen). Give zero in *(sw->len) if the value is unknown. IOP uses - *(sw->swlen) value to verify correct identication of the module to remove. - The actual size of the module is written into *(sw->swlen). - - RETURNS - - This function returns 0 if no errors occur. If an error occurs, -1 - is returned and errno is set appropriatly: - - EFAULT Invalid user space pointer was passed - ENXIO Invalid IOP number - ETIMEDOUT Timeout waiting for reply message - ENOMEM Kernel memory allocation error - -X. Validating Configuration - - SYNOPSIS - - ioctl(fd, I2OVALIDATE, int *iop); - u32 iop; - - DESCRIPTION - - This function posts an ExecConfigValidate message to the controller - identified by iop. This message indicates that the the current - configuration is accepted. The iop changes the status of suspect drivers - to valid and may delete old drivers from its store. - - RETURNS - - This function returns 0 if no erro occur. If an error occurs, -1 is - returned and errno is set appropriatly: - - ETIMEDOUT Timeout waiting for reply message - ENXIO Invalid IOP number - -XI. Configuration Dialog - - SYNOPSIS - - ioctl(fd, I2OHTML, struct i2o_html *htquery); - struct i2o_html - { - u32 iop; /* IOP unit number */ - u32 tid; /* Target device ID */ - u32 page; /* HTML page */ - void *resbuf; /* Buffer for reply HTML page */ - u32 *reslen; /* Length in bytes of reply buffer */ - void *qbuf; /* Pointer to HTTP query string */ - u32 qlen; /* Length in bytes of query string buffer */ - }; - - DESCRIPTION - - This function posts an UtilConfigDialog message to the device identified - by htquery->iop and htquery->tid. The requested HTML page number is - provided by the htquery->page field, and the resultant data is stored - in the buffer pointed to by htquery->resbuf. If there is an HTTP query - string that is to be sent to the device, it should be sent in the buffer - pointed to by htquery->qbuf. If there is no query string, this field - should be set to NULL. The actual size of the reply received is written - into *(htquery->reslen). - - RETURNS - - This function returns 0 if no error occur. If an error occurs, -1 - is returned and errno is set appropriatly: - - EFAULT Invalid user space pointer was passed - ENXIO Invalid IOP number - ENOBUFS Buffer not large enough. If this occurs, the required - buffer length is written into *(ops->reslen) - ETIMEDOUT Timeout waiting for reply message - ENOMEM Kernel memory allocation error - -XII. Events - - In the process of determining this. Current idea is to have use - the select() interface to allow user apps to periodically poll - the /dev/i2o/ctl device for events. When select() notifies the user - that an event is available, the user would call read() to retrieve - a list of all the events that are pending for the specific device. - -============================================================================= -Revision History -============================================================================= - -Rev 0.1 - 04/01/99 -- Initial revision - -Rev 0.2 - 04/06/99 -- Changed return values to match UNIX ioctl() standard. Only return values - are 0 and -1. All errors are reported through errno. -- Added summary of proposed possible event interfaces - -Rev 0.3 - 04/20/99 -- Changed all ioctls() to use pointers to user data instead of actual data -- Updated error values to match the code diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/i2o/i2o_block.c linux.ac/drivers/i2o/i2o_block.c --- linux.vanilla/drivers/i2o/i2o_block.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/i2o/i2o_block.c Thu Jan 1 01:00:00 1970 @@ -1,1756 +0,0 @@ -/* - * I2O Random Block Storage Class OSM - * - * (C) Copyright 1999 Red Hat Software - * - * Written by Alan Cox, Building Number Three 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 is a beta test release. Most of the good code was taken - * from the nbd driver by Pavel Machek, who in turn took some of it - * from loop.c. Isn't free software great for reusability 8) - * - * Fixes/additions: - * Steve Ralston: - * Multiple device handling error fixes, - * Added a queue depth. - * Alan Cox: - * FC920 has an rmw bug. Dont or in the end marker. - * Removed queue walk, fixed for 64bitness. - * Deepak Saxena: - * Independent queues per IOP - * Support for dynamic device creation/deletion - * Code cleanup - * Support for larger I/Os through merge* functions - * (taken from DAC960 driver) - * Boji T Kannanthanam: - * Reduced the timeout during RAID 5 creation. - * This is to prevent race condition when a RAID volume - * is created and immediately deleted. - * - * To do: - * Serial number scanning to find duplicates for FC multipathing - * Remove the random timeout in the code needed for RAID 5 - * volume creation. - */ - -#include <linux/major.h> - -#include <linux/module.h> - -#include <linux/sched.h> -#include <linux/fs.h> -#include <linux/stat.h> -#include <linux/errno.h> -#include <linux/file.h> -#include <linux/ioctl.h> -#include <linux/i2o.h> -#include <linux/blkdev.h> -#include <linux/blkpg.h> -#include <linux/slab.h> -#include <linux/hdreg.h> - -#include <linux/notifier.h> -#include <linux/reboot.h> - -#include <asm/uaccess.h> -#include <asm/semaphore.h> -#include <asm/io.h> -#include <asm/atomic.h> -#include <linux/smp_lock.h> -#include <linux/wait.h> - -#define MAJOR_NR I2O_MAJOR - -#include <linux/blk.h> - -#define MAX_I2OB 16 - -#define MAX_I2OB_DEPTH 128 -#define MAX_I2OB_RETRIES 4 - -//#define DRIVERDEBUG -#ifdef DRIVERDEBUG -#define DEBUG( s ) -#else -#define DEBUG( s ) printk( s ) -#endif - -/* - * Events that this OSM is interested in - */ -#define I2OB_EVENT_MASK (I2O_EVT_IND_BSA_VOLUME_LOAD | \ - I2O_EVT_IND_BSA_VOLUME_UNLOAD | \ - I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ | \ - I2O_EVT_IND_BSA_CAPACITY_CHANGE) - - -/* - * I2O Block Error Codes - should be in a header file really... - */ -#define I2O_BSA_DSC_SUCCESS 0x0000 -#define I2O_BSA_DSC_MEDIA_ERROR 0x0001 -#define I2O_BSA_DSC_ACCESS_ERROR 0x0002 -#define I2O_BSA_DSC_DEVICE_FAILURE 0x0003 -#define I2O_BSA_DSC_DEVICE_NOT_READY 0x0004 -#define I2O_BSA_DSC_MEDIA_NOT_PRESENT 0x0005 -#define I2O_BSA_DSC_MEDIA_LOCKED 0x0006 -#define I2O_BSA_DSC_MEDIA_FAILURE 0x0007 -#define I2O_BSA_DSC_PROTOCOL_FAILURE 0x0008 -#define I2O_BSA_DSC_BUS_FAILURE 0x0009 -#define I2O_BSA_DSC_ACCESS_VIOLATION 0x000A -#define I2O_BSA_DSC_WRITE_PROTECTED 0x000B -#define I2O_BSA_DSC_DEVICE_RESET 0x000C -#define I2O_BSA_DSC_VOLUME_CHANGED 0x000D -#define I2O_BSA_DSC_TIMEOUT 0x000E - -/* - * Some of these can be made smaller later - */ - -static int i2ob_blksizes[MAX_I2OB<<4]; -static int i2ob_hardsizes[MAX_I2OB<<4]; -static int i2ob_sizes[MAX_I2OB<<4]; -static int i2ob_media_change_flag[MAX_I2OB]; -static u32 i2ob_max_sectors[MAX_I2OB<<4]; - -static int i2ob_context; - -/* - * I2O Block device descriptor - */ -struct i2ob_device -{ - struct i2o_controller *controller; - struct i2o_device *i2odev; - int unit; - int tid; - int flags; - int refcnt; - struct request *head, *tail; - request_queue_t *req_queue; - int max_segments; - int done_flag; -}; - -/* - * FIXME: - * We should cache align these to avoid ping-ponging lines on SMP - * boxes under heavy I/O load... - */ -struct i2ob_request -{ - struct i2ob_request *next; - struct request *req; - int num; -}; - -/* - * Per IOP requst queue information - * - * We have a separate requeust_queue_t per IOP so that a heavilly - * loaded I2O block device on an IOP does not starve block devices - * across all I2O controllers. - * - */ -struct i2ob_iop_queue -{ - atomic_t queue_depth; - struct i2ob_request request_queue[MAX_I2OB_DEPTH]; - struct i2ob_request *i2ob_qhead; - request_queue_t req_queue; -}; -static struct i2ob_iop_queue *i2ob_queues[MAX_I2O_CONTROLLERS] = {NULL}; - -/* - * Each I2O disk is one of these. - */ - -static struct i2ob_device i2ob_dev[MAX_I2OB<<4]; -static int i2ob_dev_count = 0; -static struct hd_struct i2ob[MAX_I2OB<<4]; -static struct gendisk i2ob_gendisk; /* Declared later */ - -/* - * Mutex and spin lock for event handling synchronization - * evt_msg contains the last event. - */ -DECLARE_MUTEX(i2ob_evt_sem); -static spinlock_t i2ob_evt_lock = SPIN_LOCK_UNLOCKED; -static unsigned int evt_msg[MSG_FRAME_SIZE>>2]; -DECLARE_WAIT_QUEUE_HEAD(i2ob_evt_wait); - -static struct timer_list i2ob_timer; -static int i2ob_timer_started = 0; - -static void i2o_block_reply(struct i2o_handler *, struct i2o_controller *, - struct i2o_message *); -static void i2ob_new_device(struct i2o_controller *, struct i2o_device *); -static void i2ob_del_device(struct i2o_controller *, struct i2o_device *); -static void i2ob_reboot_event(void); -static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int); -static void i2ob_end_request(struct request *); -static void i2ob_request(request_queue_t *); -static int i2ob_init_iop(unsigned int); -static request_queue_t* i2ob_get_queue(kdev_t); -static int i2ob_query_device(struct i2ob_device *, int, int, void*, int); -static int do_i2ob_revalidate(kdev_t, int); -static int i2ob_evt(void *); - -static int evt_pid = 0; -static int evt_running = 0; - -/* - * I2O OSM registration structure...keeps getting bigger and bigger :) - */ -static struct i2o_handler i2o_block_handler = -{ - i2o_block_reply, - i2ob_new_device, - i2ob_del_device, - i2ob_reboot_event, - "I2O Block OSM", - 0, - I2O_CLASS_RANDOM_BLOCK_STORAGE -}; - -/* - * Get a message - */ - -static u32 i2ob_get(struct i2ob_device *dev) -{ - struct i2o_controller *c=dev->controller; - return I2O_POST_READ32(c); -} - -/* - * Turn a Linux block request into an I2O block read/write. - */ - -static int i2ob_send(u32 m, struct i2ob_device *dev, struct i2ob_request *ireq, u32 base, int unit) -{ - struct i2o_controller *c = dev->controller; - int tid = dev->tid; - unsigned long msg; - unsigned long mptr; - u64 offset; - struct request *req = ireq->req; - struct buffer_head *bh = req->bh; - int count = req->nr_sectors<<9; - char *last = NULL; - unsigned short size = 0; - - // printk(KERN_INFO "i2ob_send called\n"); - /* Map the message to a virtual address */ - msg = c->mem_offset + m; - - /* - * Build the message based on the request. - */ - __raw_writel(i2ob_context|(unit<<8), msg+8); - __raw_writel(ireq->num, msg+12); - __raw_writel(req->nr_sectors << 9, msg+20); - - /* This can be optimised later - just want to be sure its right for - starters */ - offset = ((u64)(req->sector+base)) << 9; - __raw_writel( offset & 0xFFFFFFFF, msg+24); - __raw_writel(offset>>32, msg+28); - mptr=msg+32; - - if(req->cmd == READ) - { - __raw_writel(I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid, msg+4); - /* We don't yet do cache/readahead and other magic */ - __raw_writel(1<<16, msg+16); - while(bh!=NULL) - { - if(bh->b_data == last) { - size += bh->b_size; - last += bh->b_size; - if(bh->b_reqnext) - __raw_writel(0x14000000|(size), mptr-8); - else - __raw_writel(0xD4000000|(size), mptr-8); - } - else - { - if(bh->b_reqnext) - __raw_writel(0x10000000|(bh->b_size), mptr); - else - __raw_writel(0xD0000000|(bh->b_size), mptr); - __raw_writel(virt_to_bus(bh->b_data), mptr+4); - mptr += 8; - size = bh->b_size; - last = bh->b_data + size; - } - - count -= bh->b_size; - bh = bh->b_reqnext; - } - } - else if(req->cmd == WRITE) - { - __raw_writel(I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid, msg+4); - /* - * Allow replies to come back once data is cached in the controller - * This allows us to handle writes quickly thus giving more of the - * queue to reads. - */ - __raw_writel(0x00000010, msg+16); - while(bh!=NULL) - { - if(bh->b_data == last) { - size += bh->b_size; - last += bh->b_size; - if(bh->b_reqnext) - __raw_writel(0x14000000|(size), mptr-8); - else - __raw_writel(0xD4000000|(size), mptr-8); - } - else - { - if(bh->b_reqnext) - __raw_writel(0x14000000|(bh->b_size), mptr); - else - __raw_writel(0xD4000000|(bh->b_size), mptr); - __raw_writel(virt_to_bus(bh->b_data), mptr+4); - mptr += 8; - size = bh->b_size; - last = bh->b_data + size; - } - - count -= bh->b_size; - bh = bh->b_reqnext; - } - } - __raw_writel(I2O_MESSAGE_SIZE(mptr-msg)>>2 | SGL_OFFSET_8, msg); - - if(req->current_nr_sectors > i2ob_max_sectors[unit]) - printk("Gathered sectors %ld.\n", - req->current_nr_sectors); - - if(count != 0) - { - printk(KERN_ERR "Request count botched by %d.\n", count); - } - - i2o_post_message(c,m); - atomic_inc(&i2ob_queues[c->unit]->queue_depth); - - return 0; -} - -/* - * Remove a request from the _locked_ request list. We update both the - * list chain and if this is the last item the tail pointer. Caller - * must hold the lock. - */ - -static inline void i2ob_unhook_request(struct i2ob_request *ireq, - unsigned int iop) -{ - ireq->next = i2ob_queues[iop]->i2ob_qhead; - i2ob_queues[iop]->i2ob_qhead = ireq; -} - -/* - * Request completion handler - */ - -static inline void i2ob_end_request(struct request *req) -{ - /* - * Loop until all of the buffers that are linked - * to this request have been marked updated and - * unlocked. - */ - - while (end_that_request_first( req, !req->errors, "i2o block" )); - - /* - * It is now ok to complete the request. - */ - end_that_request_last( req ); -} - -/* - * Request merging functions - */ -static inline int i2ob_new_segment(request_queue_t *q, struct request *req, - int __max_segments) -{ - int max_segments = i2ob_dev[MINOR(req->rq_dev)].max_segments; - - if (__max_segments < max_segments) - max_segments = __max_segments; - - if (req->nr_segments < max_segments) { - req->nr_segments++; - return 1; - } - return 0; -} - -static int i2ob_back_merge(request_queue_t *q, struct request *req, - struct buffer_head *bh, int __max_segments) -{ - if (req->bhtail->b_data + req->bhtail->b_size == bh->b_data) - return 1; - return i2ob_new_segment(q, req, __max_segments); -} - -static int i2ob_front_merge(request_queue_t *q, struct request *req, - struct buffer_head *bh, int __max_segments) -{ - if (bh->b_data + bh->b_size == req->bh->b_data) - return 1; - return i2ob_new_segment(q, req, __max_segments); -} - -static int i2ob_merge_requests(request_queue_t *q, - struct request *req, - struct request *next, - int __max_segments) -{ - int max_segments = i2ob_dev[MINOR(req->rq_dev)].max_segments; - int total_segments = req->nr_segments + next->nr_segments; - - if (__max_segments < max_segments) - max_segments = __max_segments; - - if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data) - total_segments--; - - if (total_segments > max_segments) - return 0; - - req->nr_segments = total_segments; - return 1; -} - - -/* - * OSM reply handler. This gets all the message replies - */ - -static void i2o_block_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg) -{ - unsigned long flags; - struct i2ob_request *ireq = NULL; - u8 st; - u32 *m = (u32 *)msg; - u8 unit = (m[2]>>8)&0xF0; /* low 4 bits are partition */ - struct i2ob_device *dev = &i2ob_dev[(unit&0xF0)]; - - /* - * FAILed message - */ - if(m[0] & (1<<13)) - { - /* - * FAILed message from controller - * We increment the error count and abort it - * - * In theory this will never happen. The I2O block class - * speficiation states that block devices never return - * FAILs but instead use the REQ status field...but - * better be on the safe side since no one really follows - * the spec to the book :) - */ - ireq=&i2ob_queues[c->unit]->request_queue[m[3]]; - ireq->req->errors++; - - spin_lock_irqsave(&io_request_lock, flags); - i2ob_unhook_request(ireq, c->unit); - i2ob_end_request(ireq->req); - spin_unlock_irqrestore(&io_request_lock, flags); - - /* Now flush the message by making it a NOP */ - m[0]&=0x00FFFFFF; - m[0]|=(I2O_CMD_UTIL_NOP)<<24; - i2o_post_message(c,virt_to_bus(m)); - - return; - } - - if(msg->function == I2O_CMD_UTIL_EVT_REGISTER) - { - spin_lock(&i2ob_evt_lock); - memcpy(&evt_msg, m, msg->size); - spin_unlock(&i2ob_evt_lock); - wake_up_interruptible(&i2ob_evt_wait); - return; - } - - if(!dev->i2odev) - { - /* - * This is HACK, but Intel Integrated RAID allows user - * to delete a volume that is claimed, locked, and in use - * by the OS. We have to check for a reply from a - * non-existent device and flag it as an error or the system - * goes kaput... - */ - ireq=&i2ob_queues[c->unit]->request_queue[m[3]]; - ireq->req->errors++; - printk(KERN_WARNING "I2O Block: Data transfer to deleted device!\n"); - spin_lock_irqsave(&io_request_lock, flags); - i2ob_unhook_request(ireq, c->unit); - i2ob_end_request(ireq->req); - spin_unlock_irqrestore(&io_request_lock, flags); - return; - } - - /* - * Lets see what is cooking. We stuffed the - * request in the context. - */ - - ireq=&i2ob_queues[c->unit]->request_queue[m[3]]; - st=m[4]>>24; - - if(st!=0) - { - char *bsa_errors[] = - { - "Success", - "Media Error", - "Failure communicating to device", - "Device Failure", - "Device is not ready", - "Media not present", - "Media is locked by another user", - "Media has failed", - "Failure communicating to device", - "Device bus failure", - "Device is locked by another user", - "Device is write protected", - "Device has reset", - "Volume has changed, waiting for acknowledgement" - }; - - printk(KERN_ERR "\n/dev/%s error: %s", dev->i2odev->dev_name, - bsa_errors[m[4]&0XFFFF]); - if(m[4]&0x00FF0000) - printk(" - DDM attempted %d retries", (m[4]>>16)&0x00FF ); - printk("\n"); - - ireq->req->errors++; - } - else - ireq->req->errors = 0; - - /* - * Dequeue the request. We use irqsave locks as one day we - * may be running polled controllers from a BH... - */ - - spin_lock_irqsave(&io_request_lock, flags); - i2ob_unhook_request(ireq, c->unit); - i2ob_end_request(ireq->req); - atomic_dec(&i2ob_queues[c->unit]->queue_depth); - - /* - * We may be able to do more I/O - */ - i2ob_request(dev->req_queue); - - spin_unlock_irqrestore(&io_request_lock, flags); -} - -/* - * Event handler. Needs to be a separate thread b/c we may have - * to do things like scan a partition table, or query parameters - * which cannot be done from an interrupt or from a bottom half. - */ -static int i2ob_evt(void *dummy) -{ - unsigned int evt; - unsigned int flags; - int unit; - int i; - - lock_kernel(); - daemonize(); - unlock_kernel(); - - strcpy(current->comm, "i2oblock"); - evt_running = 1; - - while(1) - { -#warning "RACE" - interruptible_sleep_on(&i2ob_evt_wait); - if(signal_pending(current)) { - evt_running = 0; - return 0; - } - - printk(KERN_INFO "Doing something in i2o_block event thread\n"); - - /* - * Keep another CPU/interrupt from overwriting the - * message while we're reading it - * - * We stuffed the unit in the TxContext and grab the event mask - * None of the BSA we care about events have EventData - */ - spin_lock_irqsave(&i2ob_evt_lock, flags); - unit = evt_msg[3]; - evt = evt_msg[4]; - spin_unlock_irqrestore(&i2ob_evt_lock, flags); - - switch(evt) - { - /* - * New volume loaded on same TID, so we just re-install. - * The TID/controller don't change as it is the same - * I2O device. It's just new media that we have to - * rescan. - */ - case I2O_EVT_IND_BSA_VOLUME_LOAD: - { - i2ob_install_device(i2ob_dev[unit].i2odev->controller, - i2ob_dev[unit].i2odev, unit); - break; - } - - /* - * No media, so set all parameters to 0 and set the media - * change flag. The I2O device is still valid, just doesn't - * have media, so we don't want to clear the controller or - * device pointer. - */ - case I2O_EVT_IND_BSA_VOLUME_UNLOAD: - { - for(i = unit; i <= unit+15; i++) - { - i2ob_sizes[i] = 0; - i2ob_hardsizes[i] = 0; - i2ob_max_sectors[i] = 0; - i2ob[i].nr_sects = 0; - i2ob_gendisk.part[i].nr_sects = 0; - } - i2ob_media_change_flag[unit] = 1; - break; - } - - case I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ: - printk(KERN_WARNING "%s: Attempt to eject locked media\n", - i2ob_dev[unit].i2odev->dev_name); - break; - - /* - * The capacity has changed and we are going to be - * updating the max_sectors and other information - * about this disk. We try a revalidate first. If - * the block device is in use, we don't want to - * do that as there may be I/Os bound for the disk - * at the moment. In that case we read the size - * from the device and update the information ourselves - * and the user can later force a partition table - * update through an ioctl. - */ - case I2O_EVT_IND_BSA_CAPACITY_CHANGE: - { - u64 size; - - if(do_i2ob_revalidate(MKDEV(MAJOR_NR, unit),0) != -EBUSY) - continue; - - if(i2ob_query_device(&i2ob_dev[unit], 0x0004, 0, &size, 8) !=0 ) - i2ob_query_device(&i2ob_dev[unit], 0x0000, 4, &size, 8); - - spin_lock_irqsave(&io_request_lock, flags); - i2ob_sizes[unit] = (int)(size>>10); - i2ob_gendisk.part[unit].nr_sects = size>>9; - i2ob[unit].nr_sects = (int)(size>>9); - spin_unlock_irqrestore(&io_request_lock, flags); - break; - } - - /* - * An event we didn't ask for. Call the card manufacturer - * and tell them to fix their firmware :) - */ - default: - printk(KERN_INFO "%s: Received event we didn't register for\n" - KERN_INFO " Call I2O card manufacturer\n", - i2ob_dev[unit].i2odev->dev_name); - break; - } - }; - - return 0; -} - -/* - * The timer handler will attempt to restart requests - * that are queued to the driver. This handler - * currently only gets called if the controller - * had no more room in its inbound fifo. - */ - -static void i2ob_timer_handler(unsigned long q) -{ - unsigned long flags; - - /* - * We cannot touch the request queue or the timer - * flag without holding the io_request_lock. - */ - spin_lock_irqsave(&io_request_lock,flags); - - /* - * Clear the timer started flag so that - * the timer can be queued again. - */ - i2ob_timer_started = 0; - - /* - * Restart any requests. - */ - i2ob_request((request_queue_t*)q); - - /* - * Free the lock. - */ - spin_unlock_irqrestore(&io_request_lock,flags); -} - -/* - * The I2O block driver is listed as one of those that pulls the - * front entry off the queue before processing it. This is important - * to remember here. If we drop the io lock then CURRENT will change - * on us. We must unlink CURRENT in this routine before we return, if - * we use it. - */ -static void i2ob_request(request_queue_t *q) -{ - struct request *req; - struct i2ob_request *ireq; - int unit; - struct i2ob_device *dev; - u32 m; - - // printk(KERN_INFO "i2ob_request() called with queue %p\n", q); - - while (!list_empty(&q->queue_head)) { - /* - * On an IRQ completion if there is an inactive - * request on the queue head it means it isnt yet - * ready to dispatch. - */ - req = blkdev_entry_next_request(&q->queue_head); - - if(req->rq_status == RQ_INACTIVE) - return; - - unit = MINOR(req->rq_dev); - dev = &i2ob_dev[(unit&0xF0)]; - - /* - * Queue depths probably belong with some kind of - * generic IOP commit control. Certainly its not right - * its global! - */ - if(atomic_read(&i2ob_queues[dev->unit]->queue_depth)>=MAX_I2OB_DEPTH) - break; - - /* Get a message */ - m = i2ob_get(dev); - - if(m==0xFFFFFFFF) - { - /* - * See if the timer has already been queued. - */ - if (!i2ob_timer_started) - { - printk(KERN_ERR "i2ob: starting timer\n"); - - /* - * Set the timer_started flag to insure - * that the timer is only queued once. - * Queing it more than once will corrupt - * the timer queue. - */ - i2ob_timer_started = 1; - - /* - * Set up the timer to expire in - * 500ms. - */ - i2ob_timer.expires = jiffies + (HZ >> 1); - i2ob_timer.data = (unsigned int)q; - - /* - * Start it. - */ - - add_timer(&i2ob_timer); - } - } - - /* - * Everything ok, so pull from kernel queue onto our queue - */ - req->errors = 0; - blkdev_dequeue_request(req); - req->sem = NULL; - - ireq = i2ob_queues[dev->unit]->i2ob_qhead; - i2ob_queues[dev->unit]->i2ob_qhead = ireq->next; - ireq->req = req; - - i2ob_send(m, dev, ireq, i2ob[unit].start_sect, (unit&0xF0)); - } -} - - -/* - * SCSI-CAM for ioctl geometry mapping - * Duplicated with SCSI - this should be moved into somewhere common - * perhaps genhd ? - * - * LBA -> CHS mapping table taken from: - * - * "Incorporating the I2O Architecture into BIOS for Intel Architecture - * Platforms" - * - * This is an I2O document that is only available to I2O members, - * not developers. - * - * From my understanding, this is how all the I2O cards do this - * - * Disk Size | Sectors | Heads | Cylinders - * ---------------+---------+-------+------------------- - * 1 < X <= 528M | 63 | 16 | X/(63 * 16 * 512) - * 528M < X <= 1G | 63 | 32 | X/(63 * 32 * 512) - * 1 < X <528M | 63 | 16 | X/(63 * 16 * 512) - * 1 < X <528M | 63 | 16 | X/(63 * 16 * 512) - * - */ -#define BLOCK_SIZE_528M 1081344 -#define BLOCK_SIZE_1G 2097152 -#define BLOCK_SIZE_21G 4403200 -#define BLOCK_SIZE_42G 8806400 -#define BLOCK_SIZE_84G 17612800 - -static void i2o_block_biosparam( - unsigned long capacity, - unsigned short *cyls, - unsigned char *hds, - unsigned char *secs) -{ - unsigned long heads, sectors, cylinders; - - sectors = 63L; /* Maximize sectors per track */ - if(capacity <= BLOCK_SIZE_528M) - heads = 16; - else if(capacity <= BLOCK_SIZE_1G) - heads = 32; - else if(capacity <= BLOCK_SIZE_21G) - heads = 64; - else if(capacity <= BLOCK_SIZE_42G) - heads = 128; - else - heads = 255; - - cylinders = capacity / (heads * sectors); - - *cyls = (unsigned short) cylinders; /* Stuff return values */ - *secs = (unsigned char) sectors; - *hds = (unsigned char) heads; -} - - -/* - * Rescan the partition tables - */ - -static int do_i2ob_revalidate(kdev_t dev, int maxu) -{ - int minor=MINOR(dev); - int i; - - minor&=0xF0; - - i2ob_dev[minor].refcnt++; - if(i2ob_dev[minor].refcnt>maxu+1) - { - i2ob_dev[minor].refcnt--; - return -EBUSY; - } - - for( i = 15; i>=0 ; i--) - { - int m = minor+i; - kdev_t d = MKDEV(MAJOR_NR, m); - struct super_block *sb = get_super(d); - - sync_dev(d); - if(sb) - invalidate_inodes(sb); - invalidate_buffers(d); - i2ob_gendisk.part[m].start_sect = 0; - i2ob_gendisk.part[m].nr_sects = 0; - } - - /* - * Do a physical check and then reconfigure - */ - - i2ob_install_device(i2ob_dev[minor].controller, i2ob_dev[minor].i2odev, - minor); - i2ob_dev[minor].refcnt--; - return 0; -} - -/* - * Issue device specific ioctl calls. - */ - -static int i2ob_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct i2ob_device *dev; - int minor; - - /* Anyone capable of this syscall can do *real bad* things */ - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (!inode) - return -EINVAL; - minor = MINOR(inode->i_rdev); - if (minor >= (MAX_I2OB<<4)) - return -ENODEV; - - dev = &i2ob_dev[minor]; - switch (cmd) { - case BLKGETSIZE: - return put_user(i2ob[minor].nr_sects, (long *) arg); - - case HDIO_GETGEO: - { - struct hd_geometry g; - int u=minor&0xF0; - i2o_block_biosparam(i2ob_sizes[u]<<1, - &g.cylinders, &g.heads, &g.sectors); - g.start = i2ob[minor].start_sect; - return copy_to_user((void *)arg,&g, sizeof(g))?-EFAULT:0; - } - - case BLKRRPART: - if(!capable(CAP_SYS_ADMIN)) - return -EACCES; - return do_i2ob_revalidate(inode->i_rdev,1); - - case BLKFLSBUF: - case BLKROSET: - case BLKROGET: - case BLKRASET: - case BLKRAGET: - case BLKPG: - return blk_ioctl(inode->i_rdev, cmd, arg); - - default: - return -EINVAL; - } -} - -/* - * Close the block device down - */ - -static int i2ob_release(struct inode *inode, struct file *file) -{ - struct i2ob_device *dev; - int minor; - - minor = MINOR(inode->i_rdev); - if (minor >= (MAX_I2OB<<4)) - return -ENODEV; - dev = &i2ob_dev[(minor&0xF0)]; - - /* - * This is to deail with the case of an application - * opening a device and then the device dissapears while - * it's in use, and then the application tries to release - * it. ex: Unmounting a deleted RAID volume at reboot. - * If we send messages, it will just cause FAILs since - * the TID no longer exists. - */ - if(!dev->i2odev) - return 0; - - /* Sync the device so we don't get errors */ - fsync_dev(inode->i_rdev); - - if (dev->refcnt <= 0) - printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt); - dev->refcnt--; - if(dev->refcnt==0) - { - /* - * Flush the onboard cache on unmount - */ - u32 msg[5]; - int *query_done = &dev->done_flag; - msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid; - msg[2] = i2ob_context|0x40000000; - msg[3] = (u32)query_done; - msg[4] = 60<<16; - i2o_post_wait(dev->controller, msg, 20, 2); - - /* - * Unlock the media - */ - msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid; - msg[2] = i2ob_context|0x40000000; - msg[3] = (u32)query_done; - msg[4] = -1; - i2o_post_wait(dev->controller, msg, 20, 2); - - /* - * Now unclaim the device. - */ - if (i2o_release_device(dev->i2odev, &i2o_block_handler)) - printk(KERN_ERR "i2ob_release: controller rejected unclaim.\n"); - - } - MOD_DEC_USE_COUNT; - return 0; -} - -/* - * Open the block device. - */ - -static int i2ob_open(struct inode *inode, struct file *file) -{ - int minor; - struct i2ob_device *dev; - - if (!inode) - return -EINVAL; - minor = MINOR(inode->i_rdev); - if (minor >= MAX_I2OB<<4) - return -ENODEV; - dev=&i2ob_dev[(minor&0xF0)]; - - if(!dev->i2odev) - return -ENODEV; - - if(dev->refcnt++==0) - { - u32 msg[6]; - - if(i2o_claim_device(dev->i2odev, &i2o_block_handler)) - { - dev->refcnt--; - printk(KERN_INFO "I2O Block: Could not open device\n"); - return -EBUSY; - } - - /* - * Mount the media if needed. Note that we don't use - * the lock bit. Since we have to issue a lock if it - * refuses a mount (quite possible) then we might as - * well just send two messages out. - */ - msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_BLOCK_MMOUNT<<24|HOST_TID<<12|dev->tid; - msg[4] = -1; - msg[5] = 0; - i2o_post_wait(dev->controller, msg, 24, 2); - - /* - * Lock the media - */ - msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_BLOCK_MLOCK<<24|HOST_TID<<12|dev->tid; - msg[4] = -1; - i2o_post_wait(dev->controller, msg, 20, 2); - } - MOD_INC_USE_COUNT; - return 0; -} - -/* - * Issue a device query - */ - -static int i2ob_query_device(struct i2ob_device *dev, int table, - int field, void *buf, int buflen) -{ - return i2o_query_scalar(dev->controller, dev->tid, - table, field, buf, buflen); -} - - -/* - * Install the I2O block device we found. - */ - -static int i2ob_install_device(struct i2o_controller *c, struct i2o_device *d, int unit) -{ - u64 size; - u32 blocksize; - u32 limit; - u8 type; - u32 flags, status; - struct i2ob_device *dev=&i2ob_dev[unit]; - int i; - - /* - * For logging purposes... - */ - printk(KERN_INFO "i2ob: Installing tid %d device at unit %d\n", - d->lct_data.tid, unit); - - /* - * Ask for the current media data. If that isn't supported - * then we ask for the device capacity data - */ - if(i2ob_query_device(dev, 0x0004, 1, &blocksize, 4) != 0 - || i2ob_query_device(dev, 0x0004, 0, &size, 8) !=0 ) - { - i2ob_query_device(dev, 0x0000, 3, &blocksize, 4); - i2ob_query_device(dev, 0x0000, 4, &size, 8); - } - - i2ob_query_device(dev, 0x0000, 5, &flags, 4); - i2ob_query_device(dev, 0x0000, 6, &status, 4); - i2ob_sizes[unit] = (int)(size>>10); - i2ob_hardsizes[unit] = blocksize; - i2ob_gendisk.part[unit].nr_sects = size>>9; - i2ob[unit].nr_sects = (int)(size>>9); - - /* Set limit based on inbound frame size */ - limit = (d->controller->status_block->inbound_frame_size - 8)/2; - limit = limit<<9; - - /* - * Max number of Scatter-Gather Elements - */ - i2ob_dev[unit].max_segments = - (d->controller->status_block->inbound_frame_size - 8)/2; - - printk(KERN_INFO "Max Segments set to %d\n", - i2ob_dev[unit].max_segments); - printk(KERN_INFO "Byte limit is %d.\n", limit); - - for(i=unit;i<=unit+15;i++) - { - i2ob_max_sectors[i]=MAX_SECTORS; - i2ob_dev[i].max_segments = - (d->controller->status_block->inbound_frame_size - 8)/2; - } - - i2ob_query_device(dev, 0x0000, 0, &type, 1); - - sprintf(d->dev_name, "%s%c", i2ob_gendisk.major_name, 'a' + (unit>>4)); - - printk(KERN_INFO "%s: ", d->dev_name); - switch(type) - { - case 0: printk("Disk Storage");break; - case 4: printk("WORM");break; - case 5: printk("CD-ROM");break; - case 7: printk("Optical device");break; - default: - printk("Type %d", type); - } - if(status&(1<<10)) - printk("(RAID)"); - if(((flags & (1<<3)) && !(status & (1<<3))) || - ((flags & (1<<4)) && !(status & (1<<4)))) - { - printk(KERN_INFO " Not loaded.\n"); - return 1; - } - printk("- %dMb, %d byte sectors", - (int)(size>>20), blocksize); - if(status&(1<<0)) - { - u32 cachesize; - i2ob_query_device(dev, 0x0003, 0, &cachesize, 4); - cachesize>>=10; - if(cachesize>4095) - printk(", %dMb cache", cachesize>>10); - else - printk(", %dKb cache", cachesize); - } - printk(".\n"); - printk(KERN_INFO "%s: Maximum sectors/read set to %d.\n", - d->dev_name, i2ob_max_sectors[unit]); - - /* - * If this is the first I2O block device found on this IOP, - * we need to initialize all the queue data structures - * before any I/O can be performed. If it fails, this - * device is useless. - */ - if(!i2ob_queues[c->unit]) { - if(i2ob_init_iop(c->unit)) - return 1; - } - - /* - * This will save one level of lookup/indirection in critical - * code so that we can directly get the queue ptr from the - * device instead of having to go the IOP data structure. - */ - dev->req_queue = &i2ob_queues[c->unit]->req_queue; - - grok_partitions(&i2ob_gendisk, unit>>4, 1<<4, (long)(size>>9)); - - /* - * Register for the events we're interested in and that the - * device actually supports. - */ - i2o_event_register(c, d->lct_data.tid, i2ob_context, unit, - (I2OB_EVENT_MASK & d->lct_data.event_capabilities)); - - return 0; -} - -/* - * Initialize IOP specific queue structures. This is called - * once for each IOP that has a block device sitting behind it. - */ -static int i2ob_init_iop(unsigned int unit) -{ - int i; - - i2ob_queues[unit] = (struct i2ob_iop_queue*) - kmalloc(sizeof(struct i2ob_iop_queue), GFP_ATOMIC); - if(!i2ob_queues[unit]) - { - printk(KERN_WARNING - "Could not allocate request queue for I2O block device!\n"); - return -1; - } - - for(i = 0; i< MAX_I2OB_DEPTH; i++) - { - i2ob_queues[unit]->request_queue[i].next = - &i2ob_queues[unit]->request_queue[i+1]; - i2ob_queues[unit]->request_queue[i].num = i; - } - - /* Queue is MAX_I2OB + 1... */ - i2ob_queues[unit]->request_queue[i].next = NULL; - i2ob_queues[unit]->i2ob_qhead = &i2ob_queues[unit]->request_queue[0]; - atomic_set(&i2ob_queues[unit]->queue_depth, 0); - - blk_init_queue(&i2ob_queues[unit]->req_queue, i2ob_request); - blk_queue_headactive(&i2ob_queues[unit]->req_queue, 0); - i2ob_queues[unit]->req_queue.back_merge_fn = i2ob_back_merge; - i2ob_queues[unit]->req_queue.front_merge_fn = i2ob_front_merge; - i2ob_queues[unit]->req_queue.merge_requests_fn = i2ob_merge_requests; - i2ob_queues[unit]->req_queue.queuedata = &i2ob_queues[unit]; - - return 0; -} - -/* - * Get the request queue for the given device. - */ -static request_queue_t* i2ob_get_queue(kdev_t dev) -{ - int unit = MINOR(dev)&0xF0; - - return i2ob_dev[unit].req_queue; -} - -/* - * Probe the I2O subsytem for block class devices - */ -static void i2ob_probe(void) -{ - int i; - int unit = 0; - int warned = 0; - - for(i=0; i< MAX_I2O_CONTROLLERS; i++) - { - struct i2o_controller *c=i2o_find_controller(i); - struct i2o_device *d; - - if(c==NULL) - continue; - - for(d=c->devices;d!=NULL;d=d->next) - { - if(d->lct_data.class_id!=I2O_CLASS_RANDOM_BLOCK_STORAGE) - continue; - - if(d->lct_data.user_tid != 0xFFF) - continue; - - if(i2o_claim_device(d, &i2o_block_handler)) - { - printk(KERN_WARNING "i2o_block: Controller %d, TID %d\n", c->unit, - d->lct_data.tid); - printk(KERN_WARNING "\tDevice refused claim! Skipping installation\n"); - continue; - } - - if(unit<MAX_I2OB<<4) - { - /* - * Get the device and fill in the - * Tid and controller. - */ - struct i2ob_device *dev=&i2ob_dev[unit]; - dev->i2odev = d; - dev->controller = c; - dev->unit = c->unit; - dev->tid = d->lct_data.tid; - - if(i2ob_install_device(c,d,unit)) - printk(KERN_WARNING "Could not install I2O block device\n"); - else - { - unit+=16; - i2ob_dev_count++; - - /* We want to know when device goes away */ - i2o_device_notify_on(d, &i2o_block_handler); - } - } - else - { - if(!warned++) - printk(KERN_WARNING "i2o_block: too many device, registering only %d.\n", unit>>4); - } - i2o_release_device(d, &i2o_block_handler); - } - i2o_unlock_controller(c); - } -} - -/* - * New device notification handler. Called whenever a new - * I2O block storage device is added to the system. - * - * Should we spin lock around this to keep multiple devs from - * getting updated at the same time? - * - */ -void i2ob_new_device(struct i2o_controller *c, struct i2o_device *d) -{ - struct i2ob_device *dev; - int unit = 0; - - printk(KERN_INFO "i2o_block: New device detected\n"); - printk(KERN_INFO " Controller %d Tid %d\n",c->unit, d->lct_data.tid); - - /* Check for available space */ - if(i2ob_dev_count>=MAX_I2OB<<4) - { - printk(KERN_ERR "i2o_block: No more devices allowed!\n"); - return; - } - for(unit = 0; unit < (MAX_I2OB<<4); unit += 16) - { - if(!i2ob_dev[unit].i2odev) - break; - } - - /* - * Creating a RAID 5 volume takes a little while and the UTIL_CLAIM - * will fail if we don't give the card enough time to do it's magic, - * so we just sleep for a little while and let it do it's thing - */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(3*HZ); - - if(i2o_claim_device(d, &i2o_block_handler)) - { - printk(KERN_INFO - "i2o_block: Unable to claim device. Installation aborted\n"); - return; - } - - dev = &i2ob_dev[unit]; - dev->i2odev = d; - dev->controller = c; - dev->tid = d->lct_data.tid; - - if(i2ob_install_device(c,d,unit)) - printk(KERN_ERR "i2o_block: Could not install new device\n"); - else - { - i2ob_dev_count++; - i2o_device_notify_on(d, &i2o_block_handler); - } - - i2o_release_device(d, &i2o_block_handler); - - return; -} - -/* - * Deleted device notification handler. Called when a device we - * are talking to has been deleted by the user or some other - * mysterious fource outside the kernel. - */ -void i2ob_del_device(struct i2o_controller *c, struct i2o_device *d) -{ - int unit = 0; - int i = 0; - int flags; - - spin_lock_irqsave(&io_request_lock, flags); - - /* - * Need to do this...we somtimes get two events from the IRTOS - * in a row and that causes lots of problems. - */ - i2o_device_notify_off(d, &i2o_block_handler); - - printk(KERN_INFO "I2O Block Device Deleted\n"); - - for(unit = 0; unit < MAX_I2OB<<4; unit += 16) - { - if(i2ob_dev[unit].i2odev == d) - { - printk(KERN_INFO " /dev/%s: Controller %d Tid %d\n", - d->dev_name, c->unit, d->lct_data.tid); - break; - } - } - if(unit >= MAX_I2OB<<4) - { - printk(KERN_ERR "i2ob_del_device called, but not in dev table!\n"); - return; - } - - /* - * This will force errors when i2ob_get_queue() is called - * by the kenrel. - */ - i2ob_dev[unit].req_queue = NULL; - for(i = unit; i <= unit+15; i++) - { - i2ob_dev[i].i2odev = NULL; - i2ob_sizes[i] = 0; - i2ob_hardsizes[i] = 0; - i2ob_max_sectors[i] = 0; - i2ob[i].nr_sects = 0; - i2ob_gendisk.part[i].nr_sects = 0; - } - spin_unlock_irqrestore(&io_request_lock, flags); - - /* - * Sync the device...this will force all outstanding I/Os - * to attempt to complete, thus causing error messages. - * We have to do this as the user could immediatelly create - * a new volume that gets assigned the same minor number. - * If there are still outstanding writes to the device, - * that could cause data corruption on the new volume! - * - * The truth is that deleting a volume that you are currently - * accessing will do _bad things_ to your system. This - * handler will keep it from crashing, but must probably - * you'll have to do a 'reboot' to get the system running - * properly. Deleting disks you are using is dumb. - * Umount them first and all will be good! - * - * It's not this driver's job to protect the system from - * dumb user mistakes :) - */ - if(i2ob_dev[unit].refcnt) - fsync_dev(MKDEV(MAJOR_NR,unit)); - - /* - * Decrease usage count for module - */ - while(i2ob_dev[unit].refcnt--) - MOD_DEC_USE_COUNT; - - i2ob_dev[unit].refcnt = 0; - - i2ob_dev[i].tid = 0; - - /* - * Do we need this? - * The media didn't really change...the device is just gone - */ - i2ob_media_change_flag[unit] = 1; - - i2ob_dev_count--; - - return; -} - -/* - * Have we seen a media change ? - */ -static int i2ob_media_change(kdev_t dev) -{ - int i=MINOR(dev); - i>>=4; - if(i2ob_media_change_flag[i]) - { - i2ob_media_change_flag[i]=0; - return 1; - } - return 0; -} - -static int i2ob_revalidate(kdev_t dev) -{ - return do_i2ob_revalidate(dev, 0); -} - -/* - * Reboot notifier. This is called by i2o_core when the system - * shuts down. - */ -static void i2ob_reboot_event(void) -{ - int i; - - for(i=0;i<MAX_I2OB;i++) - { - struct i2ob_device *dev=&i2ob_dev[(i<<4)]; - - if(dev->refcnt!=0) - { - /* - * Flush the onboard cache - */ - u32 msg[5]; - int *query_done = &dev->done_flag; - msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid; - msg[2] = i2ob_context|0x40000000; - msg[3] = (u32)query_done; - msg[4] = 60<<16; - i2o_post_wait(dev->controller, msg, 20, 2); - - /* - * Unlock the media - */ - msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid; - msg[2] = i2ob_context|0x40000000; - msg[3] = (u32)query_done; - msg[4] = -1; - i2o_post_wait(dev->controller, msg, 20, 2); - } - } -} - -static struct block_device_operations i2ob_fops = -{ - open: i2ob_open, - release: i2ob_release, - ioctl: i2ob_ioctl, - check_media_change: i2ob_media_change, - revalidate: i2ob_revalidate, -}; - - -static struct gendisk i2ob_gendisk = -{ - MAJOR_NR, - "i2o/hd", - 4, - 1<<4, - i2ob, - i2ob_sizes, - 0, - NULL, - NULL -}; - - -/* - * And here should be modules and kernel interface - * (Just smiley confuses emacs :-) - */ - -#ifdef MODULE -#define i2o_block_init init_module -#endif - -int i2o_block_init(void) -{ - int i; - - printk(KERN_INFO "I2O Block Storage OSM v0.9\n"); - printk(KERN_INFO " (c) Copyright 1999, 2000 Red Hat Software.\n"); - - /* - * Register the block device interfaces - */ - - if (register_blkdev(MAJOR_NR, "i2o_block", &i2ob_fops)) { - printk(KERN_ERR "Unable to get major number %d for i2o_block\n", - MAJOR_NR); - return -EIO; - } -#ifdef MODULE - printk(KERN_INFO "i2o_block: registered device at major %d\n", MAJOR_NR); -#endif - - /* - * Now fill in the boiler plate - */ - - blksize_size[MAJOR_NR] = i2ob_blksizes; - hardsect_size[MAJOR_NR] = i2ob_hardsizes; - blk_size[MAJOR_NR] = i2ob_sizes; - max_sectors[MAJOR_NR] = i2ob_max_sectors; - blk_dev[MAJOR_NR].queue = i2ob_get_queue; - - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), i2ob_request); - blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0); - - for (i = 0; i < MAX_I2OB << 4; i++) { - i2ob_dev[i].refcnt = 0; - i2ob_dev[i].flags = 0; - i2ob_dev[i].controller = NULL; - i2ob_dev[i].i2odev = NULL; - i2ob_dev[i].tid = 0; - i2ob_dev[i].head = NULL; - i2ob_dev[i].tail = NULL; - i2ob_blksizes[i] = 1024; - i2ob_max_sectors[i] = 2; - } - - /* - * Set up the queue - */ - for(i = 0; i < MAX_I2O_CONTROLLERS; i++) - { - i2ob_queues[i] = NULL; - } - - /* - * Timers - */ - - init_timer(&i2ob_timer); - i2ob_timer.function = i2ob_timer_handler; - i2ob_timer.data = 0; - - /* - * Register the OSM handler as we will need this to probe for - * drives, geometry and other goodies. - */ - - if(i2o_install_handler(&i2o_block_handler)<0) - { - unregister_blkdev(MAJOR_NR, "i2o_block"); - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); - printk(KERN_ERR "i2o_block: unable to register OSM.\n"); - return -EINVAL; - } - i2ob_context = i2o_block_handler.context; - - /* - * Initialize event handling thread - */ - init_MUTEX_LOCKED(&i2ob_evt_sem); - evt_pid = kernel_thread(i2ob_evt, NULL, CLONE_SIGHAND); - if(evt_pid < 0) - { - printk(KERN_ERR - "i2o_block: Could not initialize event thread. Aborting\n"); - i2o_remove_handler(&i2o_block_handler); - return 0; - } - - /* - * Finally see what is actually plugged in to our controllers - */ - for (i = 0; i < MAX_I2OB; i++) - register_disk(&i2ob_gendisk, MKDEV(MAJOR_NR,i<<4), 1<<4, - &i2ob_fops, 0); - i2ob_probe(); - - return 0; -} - -#ifdef MODULE - -EXPORT_NO_SYMBOLS; -MODULE_AUTHOR("Red Hat Software"); -MODULE_DESCRIPTION("I2O Block Device OSM"); - -void cleanup_module(void) -{ - struct gendisk **gdp; - int i; - - /* - * Unregister for updates from any devices..otherwise we still - * get them and the core jumps to random memory :O - */ - if(i2ob_dev_count) { - struct i2o_device *d; - for(i = 0; i < MAX_I2OB; i++) - if((d=i2ob_dev[i<<4].i2odev)) { - i2o_device_notify_off(d, &i2o_block_handler); - i2o_event_register(d->controller, d->lct_data.tid, - i2ob_context, i<<4, 0); - } - } - - /* - * Flush the OSM - */ - - i2o_remove_handler(&i2o_block_handler); - - /* - * Return the block device - */ - if (unregister_blkdev(MAJOR_NR, "i2o_block") != 0) - printk("i2o_block: cleanup_module failed\n"); - - /* - * free request queue - */ - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); - - if(evt_running) { - i = kill_proc(evt_pid, SIGTERM, 1); - if(!i) { - int count = 5 * 100; - while(evt_running && --count) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - } - - if(!count) - printk(KERN_ERR "Giving up on i2oblock thread...\n"); - } - } - - - /* - * Why isnt register/unregister gendisk in the kernel ??? - */ - - for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) - if (*gdp == &i2ob_gendisk) - break; - -} -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/i2o/i2o_config.c linux.ac/drivers/i2o/i2o_config.c --- linux.vanilla/drivers/i2o/i2o_config.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/i2o/i2o_config.c Thu Jan 1 01:00:00 1970 @@ -1,969 +0,0 @@ -/* - * I2O Configuration Interface Driver - * - * (C) Copyright 1999 Red Hat Software - * - * Written by Alan Cox, Building Number Three Ltd - * - * Modified 04/20/1999 by Deepak Saxena - * - Added basic ioctl() support - * Modified 06/07/1999 by Deepak Saxena - * - Added software download ioctl (still testing) - * Modified 09/10/1999 by Auvo Häkkinen - * - Changes to i2o_cfg_reply(), ioctl_parms() - * - Added ioct_validate() - * Modified 09/30/1999 by Taneli Vähäkangas - * - Fixed ioctl_swdl() - * Modified 10/04/1999 by Taneli Vähäkangas - * - Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel() - * Modified 11/18/199 by Deepak Saxena - * - Added event managmenet support - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/i2o.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/miscdevice.h> -#include <linux/mm.h> -#include <linux/spinlock.h> -#include <linux/smp_lock.h> - -#include <asm/uaccess.h> -#include <asm/io.h> - -static int i2o_cfg_context = -1; -static void *page_buf; -static void *i2o_buffer; -static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED; -struct wait_queue *i2o_wait_queue; - -#define MODINC(x,y) (x = x++ % y) - -struct i2o_cfg_info -{ - struct file* fp; - struct fasync_struct *fasync; - struct i2o_evt_info event_q[I2O_EVT_Q_LEN]; - u16 q_in; // Queue head index - u16 q_out; // Queue tail index - u16 q_len; // Queue length - u16 q_lost; // Number of lost events - u32 q_id; // Event queue ID...used as tx_context - struct i2o_cfg_info *next; -}; -static struct i2o_cfg_info *open_files = NULL; -static int i2o_cfg_info_id = 0; - -static int ioctl_getiops(unsigned long); -static int ioctl_gethrt(unsigned long); -static int ioctl_getlct(unsigned long); -static int ioctl_parms(unsigned long, unsigned int); -static int ioctl_html(unsigned long); -static int ioctl_swdl(unsigned long); -static int ioctl_swul(unsigned long); -static int ioctl_swdel(unsigned long); -static int ioctl_validate(unsigned long); -static int ioctl_evt_reg(unsigned long, struct file *); -static int ioctl_evt_get(unsigned long, struct file *); -static int cfg_fasync(int, struct file*, int); - -/* - * This is the callback for any message we have posted. The message itself - * will be returned to the message pool when we return from the IRQ - * - * This runs in irq context so be short and sweet. - */ -static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *m) -{ - u32 *msg = (u32 *)m; - - if (msg[0] & MSG_FAIL) { - u32 *preserved_msg = (u32*)(c->mem_offset + msg[7]); - - printk(KERN_ERR "i2o_config: IOP failed to process the msg.\n"); - - /* Release the preserved msg frame by resubmitting it as a NOP */ - - preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0; - preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0; - preserved_msg[2] = 0; - i2o_post_message(c, msg[7]); - } - - if (msg[4] >> 24) // ReqStatus != SUCCESS - i2o_report_status(KERN_INFO,"i2o_config", msg); - - if(m->function == I2O_CMD_UTIL_EVT_REGISTER) - { - struct i2o_cfg_info *inf; - - for(inf = open_files; inf; inf = inf->next) - if(inf->q_id == msg[3]) - break; - - // - // If this is the case, it means that we're getting - // events for a file descriptor that's been close()'d - // w/o the user unregistering for events first. - // The code currently assumes that the user will - // take care of unregistering for events before closing - // a file. - // - // TODO: - // Should we track event registartion and deregister - // for events when a file is close()'d so this doesn't - // happen? That would get rid of the search through - // the linked list since file->private_data could point - // directly to the i2o_config_info data structure...but - // it would mean having all sorts of tables to track - // what each file is registered for...I think the - // current method is simpler. - DS - // - if(!inf) - return; - - inf->event_q[inf->q_in].id.iop = c->unit; - inf->event_q[inf->q_in].id.tid = m->target_tid; - inf->event_q[inf->q_in].id.evt_mask = msg[4]; - - // - // Data size = msg size - reply header - // - inf->event_q[inf->q_in].data_size = (m->size - 5) * 4; - if(inf->event_q[inf->q_in].data_size) - memcpy(inf->event_q[inf->q_in].evt_data, - (unsigned char *)(msg + 5), - inf->event_q[inf->q_in].data_size); - - spin_lock(&i2o_config_lock); - MODINC(inf->q_in, I2O_EVT_Q_LEN); - if(inf->q_len == I2O_EVT_Q_LEN) - { - MODINC(inf->q_out, I2O_EVT_Q_LEN); - inf->q_lost++; - } - else - { - // Keep I2OEVTGET on another CPU from touching this - inf->q_len++; - } - spin_unlock(&i2o_config_lock); - - -// printk(KERN_INFO "File %p w/id %d has %d events\n", -// inf->fp, inf->q_id, inf->q_len); - - kill_fasync(&inf->fasync, SIGIO, POLL_IN); - } - - return; -} - -/* - * Each of these describes an i2o message handler. They are - * multiplexed by the i2o_core code - */ - -struct i2o_handler cfg_handler= -{ - i2o_cfg_reply, - NULL, - NULL, - NULL, - "Configuration", - 0, - 0xffffffff // All classes -}; - -static long long cfg_llseek(struct file *file, long long offset, int origin) -{ - return -ESPIPE; -} - - -static ssize_t cfg_write(struct file *file, const char *buf, size_t count, loff_t *ppos) -{ - printk(KERN_INFO "i2o_config write not yet supported\n"); - - return 0; -} - - -static ssize_t cfg_read(struct file *file, char *buf, size_t count, loff_t *ptr) -{ - return 0; -} - -/* - * IOCTL Handler - */ -static int cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd, - unsigned long arg) -{ - int ret; - - switch(cmd) - { - case I2OGETIOPS: - ret = ioctl_getiops(arg); - break; - - case I2OHRTGET: - ret = ioctl_gethrt(arg); - break; - - case I2OLCTGET: - ret = ioctl_getlct(arg); - break; - - case I2OPARMSET: - ret = ioctl_parms(arg, I2OPARMSET); - break; - - case I2OPARMGET: - ret = ioctl_parms(arg, I2OPARMGET); - break; - - case I2OSWDL: - ret = ioctl_swdl(arg); - break; - - case I2OSWUL: - ret = ioctl_swul(arg); - break; - - case I2OSWDEL: - ret = ioctl_swdel(arg); - break; - - case I2OVALIDATE: - ret = ioctl_validate(arg); - break; - - case I2OHTML: - ret = ioctl_html(arg); - break; - - case I2OEVTREG: - ret = ioctl_evt_reg(arg, fp); - break; - - case I2OEVTGET: - ret = ioctl_evt_get(arg, fp); - break; - - default: - ret = -EINVAL; - } - - return ret; -} - -int ioctl_getiops(unsigned long arg) -{ - u8 *user_iop_table = (u8*)arg; - struct i2o_controller *c = NULL; - int i; - u8 foo[MAX_I2O_CONTROLLERS]; - - if(!access_ok(VERIFY_WRITE, user_iop_table, MAX_I2O_CONTROLLERS)) - return -EFAULT; - - for(i = 0; i < MAX_I2O_CONTROLLERS; i++) - { - c = i2o_find_controller(i); - if(c) - { - foo[i] = 1; - i2o_unlock_controller(c); - } - else - { - foo[i] = 0; - } - } - - __copy_to_user(user_iop_table, foo, MAX_I2O_CONTROLLERS); - return 0; -} - -int ioctl_gethrt(unsigned long arg) -{ - struct i2o_controller *c; - struct i2o_cmd_hrtlct *cmd = (struct i2o_cmd_hrtlct*)arg; - struct i2o_cmd_hrtlct kcmd; - i2o_hrt *hrt; - int len; - u32 reslen; - int ret = 0; - - if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct))) - return -EFAULT; - - if(get_user(reslen, kcmd.reslen) < 0) - return -EFAULT; - - if(kcmd.resbuf == NULL) - return -EFAULT; - - c = i2o_find_controller(kcmd.iop); - if(!c) - return -ENXIO; - - hrt = (i2o_hrt *)c->hrt; - - i2o_unlock_controller(c); - - len = 8 + ((hrt->entry_len * hrt->num_entries) << 2); - - /* We did a get user...so assuming mem is ok...is this bad? */ - put_user(len, kcmd.reslen); - if(len > reslen) - ret = -ENOBUFS; - if(copy_to_user(kcmd.resbuf, (void*)hrt, len)) - ret = -EFAULT; - - return ret; -} - -int ioctl_getlct(unsigned long arg) -{ - struct i2o_controller *c; - struct i2o_cmd_hrtlct *cmd = (struct i2o_cmd_hrtlct*)arg; - struct i2o_cmd_hrtlct kcmd; - i2o_lct *lct; - int len; - int ret = 0; - u32 reslen; - - if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct))) - return -EFAULT; - - if(get_user(reslen, kcmd.reslen) < 0) - return -EFAULT; - - if(kcmd.resbuf == NULL) - return -EFAULT; - - c = i2o_find_controller(kcmd.iop); - if(!c) - return -ENXIO; - - lct = (i2o_lct *)c->lct; - i2o_unlock_controller(c); - - len = (unsigned int)lct->table_size << 2; - put_user(len, kcmd.reslen); - if(len > reslen) - ret = -ENOBUFS; - else if(copy_to_user(kcmd.resbuf, (void*)lct, len)) - ret = -EFAULT; - - return ret; -} - -static int ioctl_parms(unsigned long arg, unsigned int type) -{ - int ret = 0; - struct i2o_controller *c; - struct i2o_cmd_psetget *cmd = (struct i2o_cmd_psetget*)arg; - struct i2o_cmd_psetget kcmd; - u32 reslen; - u8 *ops; - u8 *res; - int len; - - u32 i2o_cmd = (type == I2OPARMGET ? - I2O_CMD_UTIL_PARAMS_GET : - I2O_CMD_UTIL_PARAMS_SET); - - if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_psetget))) - return -EFAULT; - - if(get_user(reslen, kcmd.reslen)) - return -EFAULT; - - c = i2o_find_controller(kcmd.iop); - if(!c) - return -ENXIO; - - ops = (u8*)kmalloc(kcmd.oplen, GFP_KERNEL); - if(!ops) - { - i2o_unlock_controller(c); - return -ENOMEM; - } - - if(copy_from_user(ops, kcmd.opbuf, kcmd.oplen)) - { - i2o_unlock_controller(c); - kfree(ops); - return -EFAULT; - } - - /* - * It's possible to have a _very_ large table - * and that the user asks for all of it at once... - */ - res = (u8*)kmalloc(65536, GFP_KERNEL); - if(!res) - { - i2o_unlock_controller(c); - kfree(ops); - return -ENOMEM; - } - - len = i2o_issue_params(i2o_cmd, c, kcmd.tid, - ops, kcmd.oplen, res, 65536); - i2o_unlock_controller(c); - kfree(ops); - - if (len < 0) { - kfree(res); - return -EAGAIN; - } - - put_user(len, kcmd.reslen); - if(len > reslen) - ret = -ENOBUFS; - else if(copy_to_user(cmd->resbuf, res, len)) - ret = -EFAULT; - - kfree(res); - - return ret; -} - -int ioctl_html(unsigned long arg) -{ - struct i2o_html *cmd = (struct i2o_html*)arg; - struct i2o_html kcmd; - struct i2o_controller *c; - u8 *res = NULL; - void *query = NULL; - int ret = 0; - int token; - u32 len; - u32 reslen; - u32 msg[MSG_FRAME_SIZE/4]; - - if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_html))) - { - printk(KERN_INFO "i2o_config: can't copy html cmd\n"); - return -EFAULT; - } - - if(get_user(reslen, kcmd.reslen) < 0) - { - printk(KERN_INFO "i2o_config: can't copy html reslen\n"); - return -EFAULT; - } - - if(!kcmd.resbuf) - { - printk(KERN_INFO "i2o_config: NULL html buffer\n"); - return -EFAULT; - } - - c = i2o_find_controller(kcmd.iop); - if(!c) - return -ENXIO; - - if(kcmd.qlen) /* Check for post data */ - { - query = kmalloc(kcmd.qlen, GFP_KERNEL); - if(!query) - { - i2o_unlock_controller(c); - return -ENOMEM; - } - if(copy_from_user(query, kcmd.qbuf, kcmd.qlen)) - { - i2o_unlock_controller(c); - printk(KERN_INFO "i2o_config: could not get query\n"); - kfree(query); - return -EFAULT; - } - } - - res = kmalloc(65536, GFP_KERNEL); - if(!res) - { - i2o_unlock_controller(c); - return -ENOMEM; - } - - msg[1] = (I2O_CMD_UTIL_CONFIG_DIALOG << 24)|HOST_TID<<12|kcmd.tid; - msg[2] = i2o_cfg_context; - msg[3] = 0; - msg[4] = kcmd.page; - msg[5] = 0xD0000000|65536; - msg[6] = virt_to_bus(res); - if(!kcmd.qlen) /* Check for post data */ - msg[0] = SEVEN_WORD_MSG_SIZE|SGL_OFFSET_5; - else - { - msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_5; - msg[5] = 0x50000000|65536; - msg[7] = 0xD4000000|(kcmd.qlen); - msg[8] = virt_to_bus(query); - } - - token = i2o_post_wait(c, msg, 9*4, 10); - if(token) - { - printk(KERN_DEBUG "token = %#10x\n", token); - i2o_unlock_controller(c); - kfree(res); - if(kcmd.qlen) kfree(query); - - return -ETIMEDOUT; - } - i2o_unlock_controller(c); - - len = strnlen(res, 65536); - put_user(len, kcmd.reslen); - if(len > reslen) - ret = -ENOMEM; - if(copy_to_user(kcmd.resbuf, res, len)) - ret = -EFAULT; - - kfree(res); - if(kcmd.qlen) - kfree(query); - - return ret; -} - -int ioctl_swdl(unsigned long arg) -{ - struct i2o_sw_xfer kxfer; - struct i2o_sw_xfer *pxfer = (struct i2o_sw_xfer *)arg; - unsigned char maxfrag = 0, curfrag = 1; - unsigned char *buffer; - u32 msg[9]; - unsigned int status = 0, swlen = 0, fragsize = 8192; - struct i2o_controller *c; - - if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) - return -EFAULT; - - if(get_user(swlen, kxfer.swlen) < 0) - return -EFAULT; - - if(get_user(maxfrag, kxfer.maxfrag) < 0) - return -EFAULT; - - if(get_user(curfrag, kxfer.curfrag) < 0) - return -EFAULT; - - if(curfrag==maxfrag) fragsize = swlen-(maxfrag-1)*8192; - - if(!kxfer.buf || !access_ok(VERIFY_READ, kxfer.buf, fragsize)) - return -EFAULT; - - c = i2o_find_controller(kxfer.iop); - if(!c) - return -ENXIO; - - buffer=kmalloc(fragsize, GFP_KERNEL); - if (buffer==NULL) - { - i2o_unlock_controller(c); - return -ENOMEM; - } - __copy_from_user(buffer, kxfer.buf, fragsize); - - msg[0]= NINE_WORD_MSG_SIZE | SGL_OFFSET_7; - msg[1]= I2O_CMD_SW_DOWNLOAD<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2]= (u32)cfg_handler.context; - msg[3]= 0; - msg[4]= (((u32)kxfer.flags)<<24) | (((u32)kxfer.sw_type)<<16) | - (((u32)maxfrag)<<8) | (((u32)curfrag)); - msg[5]= swlen; - msg[6]= kxfer.sw_id; - msg[7]= (0xD0000000 | fragsize); - msg[8]= virt_to_bus(buffer); - -// printk("i2o_config: swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); - status = i2o_post_wait(c, msg, sizeof(msg), 60); - - i2o_unlock_controller(c); - kfree(buffer); - - if (status != I2O_POST_WAIT_OK) - { - // it fails if you try and send frags out of order - // and for some yet unknown reasons too - printk(KERN_INFO "i2o_config: swdl failed, DetailedStatus = %d\n", status); - return -ETIMEDOUT; - } - - return 0; -} - -int ioctl_swul(unsigned long arg) -{ - struct i2o_sw_xfer kxfer; - struct i2o_sw_xfer *pxfer = (struct i2o_sw_xfer *)arg; - unsigned char maxfrag = 0, curfrag = 1; - unsigned char *buffer; - u32 msg[9]; - unsigned int status = 0, swlen = 0, fragsize = 8192; - struct i2o_controller *c; - - if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) - return -EFAULT; - - if(get_user(swlen, kxfer.swlen) < 0) - return -EFAULT; - - if(get_user(maxfrag, kxfer.maxfrag) < 0) - return -EFAULT; - - if(get_user(curfrag, kxfer.curfrag) < 0) - return -EFAULT; - - if(curfrag==maxfrag) fragsize = swlen-(maxfrag-1)*8192; - - if(!kxfer.buf || !access_ok(VERIFY_WRITE, kxfer.buf, fragsize)) - return -EFAULT; - - c = i2o_find_controller(kxfer.iop); - if(!c) - return -ENXIO; - - buffer=kmalloc(fragsize, GFP_KERNEL); - if (buffer==NULL) - { - i2o_unlock_controller(c); - return -ENOMEM; - } - - msg[0]= NINE_WORD_MSG_SIZE | SGL_OFFSET_7; - msg[1]= I2O_CMD_SW_UPLOAD<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2]= (u32)cfg_handler.context; - msg[3]= 0; - msg[4]= (u32)kxfer.flags<<24|(u32)kxfer.sw_type<<16|(u32)maxfrag<<8|(u32)curfrag; - msg[5]= swlen; - msg[6]= kxfer.sw_id; - msg[7]= (0xD0000000 | fragsize); - msg[8]= virt_to_bus(buffer); - -// printk("i2o_config: swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); - status = i2o_post_wait(c, msg, sizeof(msg), 60); - i2o_unlock_controller(c); - - if (status != I2O_POST_WAIT_OK) - { - kfree(buffer); - printk(KERN_INFO "i2o_config: swul failed, DetailedStatus = %d\n", status); - return -ETIMEDOUT; - } - - __copy_to_user(kxfer.buf, buffer, fragsize); - kfree(buffer); - - return 0; -} - -int ioctl_swdel(unsigned long arg) -{ - struct i2o_controller *c; - struct i2o_sw_xfer kxfer, *pxfer = (struct i2o_sw_xfer *)arg; - u32 msg[7]; - unsigned int swlen; - int token; - - if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) - return -EFAULT; - - if (get_user(swlen, kxfer.swlen) < 0) - return -EFAULT; - - c = i2o_find_controller(kxfer.iop); - if (!c) - return -ENXIO; - - msg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0; - msg[1] = I2O_CMD_SW_REMOVE<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2] = (u32)i2o_cfg_context; - msg[3] = 0; - msg[4] = (u32)kxfer.flags<<24 | (u32)kxfer.sw_type<<16; - msg[5] = swlen; - msg[6] = kxfer.sw_id; - - token = i2o_post_wait(c, msg, sizeof(msg), 10); - i2o_unlock_controller(c); - - if (token != I2O_POST_WAIT_OK) - { - printk(KERN_INFO "i2o_config: swdel failed, DetailedStatus = %d\n", token); - return -ETIMEDOUT; - } - - return 0; -} - -int ioctl_validate(unsigned long arg) -{ - int token; - int iop = (int)arg; - u32 msg[4]; - struct i2o_controller *c; - - c=i2o_find_controller(iop); - if (!c) - return -ENXIO; - - msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_CONFIG_VALIDATE<<24 | HOST_TID<<12 | iop; - msg[2] = (u32)i2o_cfg_context; - msg[3] = 0; - - token = i2o_post_wait(c, msg, sizeof(msg), 10); - i2o_unlock_controller(c); - - if (token != I2O_POST_WAIT_OK) - { - printk(KERN_INFO "Can't validate configuration, ErrorStatus = %d\n", - token); - return -ETIMEDOUT; - } - - return 0; -} - -static int ioctl_evt_reg(unsigned long arg, struct file *fp) -{ - u32 msg[5]; - struct i2o_evt_id *pdesc = (struct i2o_evt_id *)arg; - struct i2o_evt_id kdesc; - struct i2o_controller *iop; - struct i2o_device *d; - - if (copy_from_user(&kdesc, pdesc, sizeof(struct i2o_evt_id))) - return -EFAULT; - - /* IOP exists? */ - iop = i2o_find_controller(kdesc.iop); - if(!iop) - return -ENXIO; - i2o_unlock_controller(iop); - - /* Device exists? */ - for(d = iop->devices; d; d = d->next) - if(d->lct_data.tid == kdesc.tid) - break; - - if(!d) - return -ENODEV; - - msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_UTIL_EVT_REGISTER<<24 | HOST_TID<<12 | kdesc.tid; - msg[2] = (u32)i2o_cfg_context; - msg[3] = (u32)fp->private_data; - msg[4] = kdesc.evt_mask; - - i2o_post_this(iop, msg, 20); - - return 0; -} - -static int ioctl_evt_get(unsigned long arg, struct file *fp) -{ - u32 id = (u32)fp->private_data; - struct i2o_cfg_info *p = NULL; - struct i2o_evt_get *uget = (struct i2o_evt_get*)arg; - struct i2o_evt_get kget; - unsigned int flags; - - // access_ok doesn't check for NULL?!?! - if(!arg) - return -EFAULT; - - if(!access_ok(VERIFY_WRITE, uget, sizeof(struct i2o_evt_get))) - return -EFAULT; - - for(p = open_files; p; p = p->next) - if(p->q_id == id) - break; - - if(!p->q_len) - { - return -ENOENT; - return 0; - } - - memcpy(&kget.info, &p->event_q[p->q_out], sizeof(struct i2o_evt_info)); - MODINC(p->q_out, I2O_EVT_Q_LEN); - spin_lock_irqsave(&i2o_config_lock, flags); - p->q_len--; - kget.pending = p->q_len; - kget.lost = p->q_lost; - spin_unlock_irqrestore(&i2o_config_lock, flags); - - __copy_to_user(uget, &kget, sizeof(struct i2o_evt_get)); - - return 0; -} - -static int cfg_open(struct inode *inode, struct file *file) -{ - struct i2o_cfg_info *tmp = - (struct i2o_cfg_info *)kmalloc(sizeof(struct i2o_cfg_info), GFP_KERNEL); - unsigned int flags; - - if(!tmp) - return -ENOMEM; - - file->private_data = (void*)(i2o_cfg_info_id++); - tmp->fp = file; - tmp->fasync = NULL; - tmp->q_id = (u32)file->private_data; - tmp->q_len = 0; - tmp->q_in = 0; - tmp->q_out = 0; - tmp->q_lost = 0; - tmp->next = open_files; - - spin_lock_irqsave(&i2o_config_lock, flags); - open_files = tmp; - spin_unlock_irqrestore(&i2o_config_lock, flags); - - return 0; -} - -static int cfg_release(struct inode *inode, struct file *file) -{ - u32 id = (u32)file->private_data; - struct i2o_cfg_info *p1, *p2; - unsigned int flags; - - lock_kernel(); - p1 = p2 = NULL; - - spin_lock_irqsave(&i2o_config_lock, flags); - for(p1 = open_files; p1; ) - { - if(p1->q_id == id) - { - - if(p1->fasync) - cfg_fasync(-1, file, 0); - if(p2) - p2->next = p1->next; - else - open_files = p1->next; - - kfree(p1); - break; - } - p2 = p1; - p1 = p1->next; - } - spin_unlock_irqrestore(&i2o_config_lock, flags); - unlock_kernel(); - - return 0; -} - -static int cfg_fasync(int fd, struct file *fp, int on) -{ - u32 id = (u32)fp->private_data; - struct i2o_cfg_info *p; - - for(p = open_files; p; p = p->next) - if(p->q_id == id) - break; - - if(!p) - return -EBADF; - - return fasync_helper(fd, fp, on, &p->fasync); -} - -static struct file_operations config_fops = -{ - owner: THIS_MODULE, - llseek: cfg_llseek, - read: cfg_read, - write: cfg_write, - ioctl: cfg_ioctl, - open: cfg_open, - release: cfg_release, - fasync: cfg_fasync, -}; - -static struct miscdevice i2o_miscdev = { - I2O_MINOR, - "i2octl", - &config_fops -}; - -#ifdef MODULE -int init_module(void) -#else -int __init i2o_config_init(void) -#endif -{ - printk(KERN_INFO "I2O configuration manager v 0.04.\n"); - printk(KERN_INFO " (C) Copyright 1999 Red Hat Software\n"); - - if((page_buf = kmalloc(4096, GFP_KERNEL))==NULL) - { - printk(KERN_ERR "i2o_config: no memory for page buffer.\n"); - return -ENOBUFS; - } - if(misc_register(&i2o_miscdev)==-1) - { - printk(KERN_ERR "i2o_config: can't register device.\n"); - kfree(page_buf); - return -EBUSY; - } - /* - * Install our handler - */ - if(i2o_install_handler(&cfg_handler)<0) - { - kfree(page_buf); - printk(KERN_ERR "i2o_config: handler register failed.\n"); - misc_deregister(&i2o_miscdev); - return -EBUSY; - } - /* - * The low 16bits of the transaction context must match this - * for everything we post. Otherwise someone else gets our mail - */ - i2o_cfg_context = cfg_handler.context; - return 0; -} - -#ifdef MODULE - -void cleanup_module(void) -{ - misc_deregister(&i2o_miscdev); - - if(page_buf) - kfree(page_buf); - if(i2o_cfg_context != -1) - i2o_remove_handler(&cfg_handler); - if(i2o_buffer) - kfree(i2o_buffer); -} - -EXPORT_NO_SYMBOLS; -MODULE_AUTHOR("Red Hat Software"); -MODULE_DESCRIPTION("I2O Configuration"); - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/i2o/i2o_core.c linux.ac/drivers/i2o/i2o_core.c --- linux.vanilla/drivers/i2o/i2o_core.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/i2o/i2o_core.c Thu Jan 1 01:00:00 1970 @@ -1,3290 +0,0 @@ -/* - * Core I2O structure managment - * - * (C) Copyright 1999 Red Hat Software - * - * Written by Alan Cox, Building Number Three 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. - * - * A lot of the I2O message side code from this is taken from the - * Red Creek RCPCI45 adapter driver by Red Creek Communications - * - * Fixes by: - * Philipp Rumpf - * Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI> - * Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI> - * Deepak Saxena <deepak@plexity.net> - * Boji T Kannanthanam <boji.t.kannanthanam@intel.com> - * - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/pci.h> - -#include <linux/i2o.h> - -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include <linux/smp_lock.h> - -#include <linux/bitops.h> -#include <linux/wait.h> -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/tqueue.h> -#include <linux/interrupt.h> -#include <linux/sched.h> -#include <asm/semaphore.h> - -#include <asm/io.h> -#include <linux/reboot.h> - -#include "i2o_lan.h" - -// #define DRIVERDEBUG - -#ifdef DRIVERDEBUG -#define dprintk(s, args...) printk(s, ## args) -#else -#define dprintk(s, args...) -#endif - -/* OSM table */ -static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES] = {NULL}; - -/* Controller list */ -static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS] = {NULL}; -struct i2o_controller *i2o_controller_chain = NULL; -int i2o_num_controllers = 0; - -/* Initiator Context for Core message */ -static int core_context = 0; - -/* Initialization && shutdown functions */ -static void i2o_sys_init(void); -static void i2o_sys_shutdown(void); -static int i2o_reset_controller(struct i2o_controller *); -static int i2o_reboot_event(struct notifier_block *, unsigned long , void *); -static int i2o_online_controller(struct i2o_controller *); -static int i2o_init_outbound_q(struct i2o_controller *); -static int i2o_post_outbound_messages(struct i2o_controller *); - -/* Reply handler */ -static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *, - struct i2o_message *); - -/* Various helper functions */ -static int i2o_lct_get(struct i2o_controller *); -static int i2o_lct_notify(struct i2o_controller *); -static int i2o_hrt_get(struct i2o_controller *); - -static int i2o_build_sys_table(void); -static int i2o_systab_send(struct i2o_controller *c); - -/* I2O core event handler */ -static int i2o_core_evt(void *); -static int evt_pid; -static int evt_running; - -/* Dynamic LCT update handler */ -static int i2o_dyn_lct(void *); - -void i2o_report_controller_unit(struct i2o_controller *, struct i2o_device *); - -/* - * I2O System Table. Contains information about - * all the IOPs in the system. Used to inform IOPs - * about each other's existence. - * - * sys_tbl_ver is the CurrentChangeIndicator that is - * used by IOPs to track changes. - */ -static struct i2o_sys_tbl *sys_tbl = NULL; -static int sys_tbl_ind = 0; -static int sys_tbl_len = 0; - -/* - * This spin lock is used to keep a device from being - * added and deleted concurrently across CPUs or interrupts. - * This can occur when a user creates a device and immediatelly - * deletes it before the new_dev_notify() handler is called. - */ -static spinlock_t i2o_dev_lock = SPIN_LOCK_UNLOCKED; - -#ifdef MODULE -/* - * Function table to send to bus specific layers - * See <include/linux/i2o.h> for explanation of this - */ -static struct i2o_core_func_table i2o_core_functions = -{ - i2o_install_controller, - i2o_activate_controller, - i2o_find_controller, - i2o_unlock_controller, - i2o_run_queue, - i2o_delete_controller -}; - -#ifdef CONFIG_I2O_PCI_MODULE -extern int i2o_pci_core_attach(struct i2o_core_func_table *); -extern void i2o_pci_core_detach(void); -#endif /* CONFIG_I2O_PCI_MODULE */ - -#endif /* MODULE */ - -/* - * Structures and definitions for synchronous message posting. - * See i2o_post_wait() for description. - */ -struct i2o_post_wait_data -{ - int status; - u32 id; - wait_queue_head_t *wq; - struct i2o_post_wait_data *next; -}; -static struct i2o_post_wait_data *post_wait_queue = NULL; -static u32 post_wait_id = 0; // Unique ID for each post_wait -static spinlock_t post_wait_lock = SPIN_LOCK_UNLOCKED; -static void i2o_post_wait_complete(u32, int); - -/* OSM descriptor handler */ -static struct i2o_handler i2o_core_handler = -{ - (void *)i2o_core_reply, - NULL, - NULL, - NULL, - "I2O core layer", - 0, - I2O_CLASS_EXECUTIVE -}; - - -/* - * Used when queing a reply to be handled later - */ -struct reply_info -{ - struct i2o_controller *iop; - u32 msg[MSG_FRAME_SIZE]; -}; -static struct reply_info evt_reply; -static struct reply_info events[I2O_EVT_Q_LEN]; -static int evt_in = 0; -static int evt_out = 0; -static int evt_q_len = 0; -#define MODINC(x,y) ((x) = ((x) + 1) % (y)) - -/* - * I2O configuration spinlock. This isnt a big deal for contention - * so we have one only - */ - -static DECLARE_MUTEX(i2o_configuration_lock); - -/* - * Event spinlock. Used to keep event queue sane and from - * handling multiple events simultaneously. - */ -static spinlock_t i2o_evt_lock = SPIN_LOCK_UNLOCKED; - -/* - * Semaphore used to syncrhonize event handling thread with - * interrupt handler. - */ -DECLARE_MUTEX(evt_sem); -DECLARE_WAIT_QUEUE_HEAD(evt_wait); - -static struct notifier_block i2o_reboot_notifier = -{ - i2o_reboot_event, - NULL, - 0 -}; - - -/* - * I2O Core reply handler - */ -static void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c, - struct i2o_message *m) -{ - u32 *msg=(u32 *)m; - u32 status; - u32 context = msg[2]; - - if (msg[0] & MSG_FAIL) // Fail bit is set - { - u32 *preserved_msg = (u32*)(c->mem_offset + msg[7]); - - i2o_report_status(KERN_INFO, "i2o_core", msg); - i2o_dump_message(preserved_msg); - - /* If the failed request needs special treatment, - * it should be done here. */ - - /* Release the preserved msg by resubmitting it as a NOP */ - - preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0; - preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0; - preserved_msg[2] = 0; - i2o_post_message(c, msg[7]); - - /* If reply to i2o_post_wait failed, return causes a timeout */ - - return; - } - -#ifdef DRIVERDEBUG - i2o_report_status(KERN_INFO, "i2o_core", msg); -#endif - - if(msg[2]&0x80000000) // Post wait message - { - if (msg[4] >> 24) - status = -(msg[4] & 0xFFFF); - else - status = I2O_POST_WAIT_OK; - - i2o_post_wait_complete(context, status); - return; - } - - if(m->function == I2O_CMD_UTIL_EVT_REGISTER) - { - memcpy(events[evt_in].msg, msg, (msg[0]>>16)<<2); - events[evt_in].iop = c; - - spin_lock(&i2o_evt_lock); - MODINC(evt_in, I2O_EVT_Q_LEN); - if(evt_q_len == I2O_EVT_Q_LEN) - MODINC(evt_out, I2O_EVT_Q_LEN); - else - evt_q_len++; - spin_unlock(&i2o_evt_lock); - - up(&evt_sem); - wake_up_interruptible(&evt_wait); - return; - } - - if(m->function == I2O_CMD_LCT_NOTIFY) - { - up(&c->lct_sem); - return; - } - - /* - * If this happens, we want to dump the message to the syslog so - * it can be sent back to the card manufacturer by the end user - * to aid in debugging. - * - */ - printk(KERN_WARNING "%s: Unsolicited message reply sent to core!" - "Message dumped to syslog\n", - c->name); - i2o_dump_message(msg); - - return; -} - -/** - * i2o_install_handler - install a message handler - * @h: Handler structure - * - * Install an I2O handler - these handle the asynchronous messaging - * from the card once it has initialised. If the table of handlers is - * full then -ENOSPC is returned. On a success 0 is returned and the - * context field is set by the function. The structure is part of the - * system from this time onwards. It must not be freed until it has - * been uninstalled - */ - -int i2o_install_handler(struct i2o_handler *h) -{ - int i; - down(&i2o_configuration_lock); - for(i=0;i<MAX_I2O_MODULES;i++) - { - if(i2o_handlers[i]==NULL) - { - h->context = i; - i2o_handlers[i]=h; - up(&i2o_configuration_lock); - return 0; - } - } - up(&i2o_configuration_lock); - return -ENOSPC; -} - -/** - * i2o_remove_handler - remove an i2o message handler - * @h: handler - * - * Remove a message handler previously installed with i2o_install_handler. - * After this function returns the handler object can be freed or re-used - */ - -int i2o_remove_handler(struct i2o_handler *h) -{ - i2o_handlers[h->context]=NULL; - return 0; -} - - -/* - * Each I2O controller has a chain of devices on it. - * Each device has a pointer to it's LCT entry to be used - * for fun purposes. - */ - -/** - * i2o_install_device - attach a device to a controller - * @c: controller - * @d: device - * - * Add a new device to an i2o controller. This can be called from - * non interrupt contexts only. It adds the device and marks it as - * unclaimed. The device memory becomes part of the kernel and must - * be uninstalled before being freed or reused. Zero is returned - * on success. - */ - -int i2o_install_device(struct i2o_controller *c, struct i2o_device *d) -{ - int i; - - down(&i2o_configuration_lock); - d->controller=c; - d->owner=NULL; - d->next=c->devices; - c->devices=d; - *d->dev_name = 0; - - for(i = 0; i < I2O_MAX_MANAGERS; i++) - d->managers[i] = NULL; - - up(&i2o_configuration_lock); - return 0; -} - -/* we need this version to call out of i2o_delete_controller */ - -int __i2o_delete_device(struct i2o_device *d) -{ - struct i2o_device **p; - int i; - - p=&(d->controller->devices); - - /* - * Hey we have a driver! - * Check to see if the driver wants us to notify it of - * device deletion. If it doesn't we assume that it - * is unsafe to delete a device with an owner and - * fail. - */ - if(d->owner) - { - if(d->owner->dev_del_notify) - { - dprintk(KERN_INFO "Device has owner, notifying\n"); - d->owner->dev_del_notify(d->controller, d); - if(d->owner) - { - printk(KERN_WARNING - "Driver \"%s\" did not release device!\n", d->owner->name); - return -EBUSY; - } - } - else - return -EBUSY; - } - - /* - * Tell any other users who are talking to this device - * that it's going away. We assume that everything works. - */ - for(i=0; i < I2O_MAX_MANAGERS; i++) - { - if(d->managers[i] && d->managers[i]->dev_del_notify) - d->managers[i]->dev_del_notify(d->controller, d); - } - - while(*p!=NULL) - { - if(*p==d) - { - /* - * Destroy - */ - *p=d->next; - kfree(d); - return 0; - } - p=&((*p)->next); - } - printk(KERN_ERR "i2o_delete_device: passed invalid device.\n"); - return -EINVAL; -} - -/** - * i2o_delete_device - remove an i2o device - * @d: device to remove - * - * This function unhooks a device from a controller. The device - * will not be unhooked if it has an owner who does not wish to free - * it, or if the owner lacks a dev_del_notify function. In that case - * -EBUSY is returned. On success 0 is returned. Other errors cause - * negative errno values to be returned - */ - -int i2o_delete_device(struct i2o_device *d) -{ - int ret; - - down(&i2o_configuration_lock); - - /* - * Seek, locate - */ - - ret = __i2o_delete_device(d); - - up(&i2o_configuration_lock); - - return ret; -} - -/** - * i2o_install_controller - attach a controller - * @c: controller - * - * Add a new controller to the i2o layer. This can be called from - * non interrupt contexts only. It adds the controller and marks it as - * unused with no devices. If the tables are full or memory allocations - * fail then a negative errno code is returned. On success zero is - * returned and the controller is bound to the system. The structure - * must not be freed or reused until being uninstalled. - */ - -int i2o_install_controller(struct i2o_controller *c) -{ - int i; - down(&i2o_configuration_lock); - for(i=0;i<MAX_I2O_CONTROLLERS;i++) - { - if(i2o_controllers[i]==NULL) - { - c->dlct = (i2o_lct*)kmalloc(8192, GFP_KERNEL); - if(c->dlct==NULL) - { - up(&i2o_configuration_lock); - return -ENOMEM; - } - i2o_controllers[i]=c; - c->devices = NULL; - c->next=i2o_controller_chain; - i2o_controller_chain=c; - c->unit = i; - c->page_frame = NULL; - c->hrt = NULL; - c->lct = NULL; - c->status_block = NULL; - sprintf(c->name, "i2o/iop%d", i); - i2o_num_controllers++; - init_MUTEX_LOCKED(&c->lct_sem); - up(&i2o_configuration_lock); - return 0; - } - } - printk(KERN_ERR "No free i2o controller slots.\n"); - up(&i2o_configuration_lock); - return -EBUSY; -} - -/** - * i2o_delete_controller - delete a controller - * @c: controller - * - * Remove an i2o controller from the system. If the controller or its - * devices are busy then -EBUSY is returned. On a failure a negative - * errno code is returned. On success zero is returned. - */ - -int i2o_delete_controller(struct i2o_controller *c) -{ - struct i2o_controller **p; - int users; - char name[16]; - int stat; - - dprintk(KERN_INFO "Deleting controller %s\n", c->name); - - /* - * Clear event registration as this can cause weird behavior - */ - if(c->status_block->iop_state == ADAPTER_STATE_OPERATIONAL) - i2o_event_register(c, core_context, 0, 0, 0); - - down(&i2o_configuration_lock); - if((users=atomic_read(&c->users))) - { - dprintk(KERN_INFO "I2O: %d users for controller %s\n", users, - c->name); - up(&i2o_configuration_lock); - return -EBUSY; - } - while(c->devices) - { - if(__i2o_delete_device(c->devices)<0) - { - /* Shouldnt happen */ - c->bus_disable(c); - up(&i2o_configuration_lock); - return -EBUSY; - } - } - - /* - * If this is shutdown time, the thread's already been killed - */ - if(c->lct_running) { - stat = kill_proc(c->lct_pid, SIGTERM, 1); - if(!stat) { - int count = 10 * 100; - while(c->lct_running && --count) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - } - - if(!count) - printk(KERN_ERR - "%s: LCT thread still running!\n", - c->name); - } - } - - p=&i2o_controller_chain; - - while(*p) - { - if(*p==c) - { - /* Ask the IOP to switch to RESET state */ - i2o_reset_controller(c); - - /* Release IRQ */ - c->destructor(c); - - *p=c->next; - up(&i2o_configuration_lock); - - if(c->page_frame) - kfree(c->page_frame); - if(c->hrt) - kfree(c->hrt); - if(c->lct) - kfree(c->lct); - if(c->status_block) - kfree(c->status_block); - if(c->dlct) - kfree(c->dlct); - - i2o_controllers[c->unit]=NULL; - memcpy(name, c->name, strlen(c->name)+1); - kfree(c); - dprintk(KERN_INFO "%s: Deleted from controller chain.\n", name); - - i2o_num_controllers--; - return 0; - } - p=&((*p)->next); - } - up(&i2o_configuration_lock); - printk(KERN_ERR "i2o_delete_controller: bad pointer!\n"); - return -ENOENT; -} - -/** - * i2o_unlock_controller - unlock a controller - * @c: controller to unlock - * - * Take a lock on an i2o controller. This prevents it being deleted. - * i2o controllers are not refcounted so a deletion of an in use device - * will fail, not take affect on the last dereference. - */ - -void i2o_unlock_controller(struct i2o_controller *c) -{ - atomic_dec(&c->users); -} - -/** - * i2o_find_controller - return a locked controller - * @n: controller number - * - * Returns a pointer to the controller object. The controller is locked - * on return. NULL is returned if the controller is not found. - */ - -struct i2o_controller *i2o_find_controller(int n) -{ - struct i2o_controller *c; - - if(n<0 || n>=MAX_I2O_CONTROLLERS) - return NULL; - - down(&i2o_configuration_lock); - c=i2o_controllers[n]; - if(c!=NULL) - atomic_inc(&c->users); - up(&i2o_configuration_lock); - return c; -} - -/** - * i2o_issue_claim - claim or release a device - * @cmd: command - * @c: controller to claim for - * @tid: i2o task id - * @type: type of claim - * - * Issue I2O UTIL_CLAIM and UTIL_RELEASE messages. The message to be sent - * is set by cmd. The tid is the task id of the object to claim and the - * type is the claim type (see the i2o standard) - * - * Zero is returned on success. - */ - -static int i2o_issue_claim(u32 cmd, struct i2o_controller *c, int tid, u32 type) -{ - u32 msg[5]; - - msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; - msg[1] = cmd << 24 | HOST_TID<<12 | tid; - msg[3] = 0; - msg[4] = type; - - return i2o_post_wait(c, msg, sizeof(msg), 60); -} - -/* - * i2o_claim_device - claim a device for use by an OSM - * @d: device to claim - * @h: handler for this device - * - * Do the leg work to assign a device to a given OSM on Linux. The - * kernel updates the internal handler data for the device and then - * performs an I2O claim for the device, attempting to claim the - * device as primary. If the attempt fails a negative errno code - * is returned. On success zero is returned. - */ - -int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h) -{ - down(&i2o_configuration_lock); - if (d->owner) { - printk(KERN_INFO "Device claim called, but dev allready owned by %s!", - h->name); - up(&i2o_configuration_lock); - return -EBUSY; - } - d->owner=h; - - if(i2o_issue_claim(I2O_CMD_UTIL_CLAIM ,d->controller,d->lct_data.tid, - I2O_CLAIM_PRIMARY)) - { - d->owner = NULL; - return -EBUSY; - } - up(&i2o_configuration_lock); - return 0; -} - -/** - * i2o_release_device - release a device that the OSM is using - * @d: device to claim - * @h: handler for this device - * - * Drop a claim by an OSM on a given I2O device. The handler is cleared - * and 0 is returned on success. - * - */ - -int i2o_release_device(struct i2o_device *d, struct i2o_handler *h) -{ - int err = 0; - - down(&i2o_configuration_lock); - if (d->owner != h) { - printk(KERN_INFO "Claim release called, but not owned by %s!", - h->name); - up(&i2o_configuration_lock); - return -ENOENT; - } - - d->owner = NULL; - - if(i2o_issue_claim(I2O_CMD_UTIL_RELEASE, d->controller, d->lct_data.tid, - I2O_CLAIM_PRIMARY)) - { - err = -ENXIO; - d->owner = h; - } - - up(&i2o_configuration_lock); - return err; -} - -/* - * Called by OSMs to let the core know that they want to be - * notified if the given device is deleted from the system. - */ -int i2o_device_notify_on(struct i2o_device *d, struct i2o_handler *h) -{ - int i; - - if(d->num_managers == I2O_MAX_MANAGERS) - return -ENOSPC; - - for(i = 0; i < I2O_MAX_MANAGERS; i++) - { - if(!d->managers[i]) - { - d->managers[i] = h; - break; - } - } - - d->num_managers++; - - return 0; -} - -/* - * Called by OSMs to let the core know that they no longer - * are interested in the fate of the given device. - */ -int i2o_device_notify_off(struct i2o_device *d, struct i2o_handler *h) -{ - int i; - - for(i=0; i < I2O_MAX_MANAGERS; i++) - { - if(d->managers[i] == h) - { - d->managers[i] = NULL; - d->num_managers--; - return 0; - } - } - - return -ENOENT; -} - -/* - * Event registration API - */ -int i2o_event_register(struct i2o_controller *c, u32 tid, - u32 init_context, u32 tr_context, u32 evt_mask) -{ - u32 msg[5]; // Not performance critical, so we just - // i2o_post_this it instead of building it - // in IOP memory - - msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_UTIL_EVT_REGISTER<<24 | HOST_TID<<12 | tid; - msg[2] = init_context; - msg[3] = tr_context; - msg[4] = evt_mask; - - return i2o_post_this(c, msg, sizeof(msg)); -} - -/* - * Event ack API - * - * We just take a pointer to the original UTIL_EVENT_REGISTER reply - * message and change the function code since that's what spec - * describes an EventAck message looking like. - */ - -int i2o_event_ack(struct i2o_controller *c, u32 *msg) -{ - struct i2o_message *m = (struct i2o_message *)msg; - - m->function = I2O_CMD_UTIL_EVT_ACK; - - return i2o_post_wait(c, msg, m->size * 4, 2); -} - -/* - * Core event handler. Runs as a separate thread and is woken - * up whenever there is an Executive class event. - */ -static int i2o_core_evt(void *reply_data) -{ - struct reply_info *reply = (struct reply_info *) reply_data; - u32 *msg = reply->msg; - struct i2o_controller *c = NULL; - int flags; - - lock_kernel(); - daemonize(); - unlock_kernel(); - - strcpy(current->comm, "i2oevtd"); - evt_running = 1; - - while(1) - { - down_interruptible(&evt_sem); - if(signal_pending(current)) - { - dprintk(KERN_INFO "I2O event thread dead\n"); - evt_running = 0; - return 0; - } - - /* - * Copy the data out of the queue so that we don't have to lock - * around the whole function and just around the qlen update - */ - spin_lock_irqsave(&i2o_evt_lock, flags); - memcpy(reply, &events[evt_out], sizeof(struct reply_info)); - MODINC(evt_out, I2O_EVT_Q_LEN); - evt_q_len--; - spin_unlock_irqrestore(&i2o_evt_lock, flags); - - c = reply->iop; - dprintk(KERN_INFO "I2O IRTOS EVENT: iop%d, event %#10x\n", c->unit, msg[4]); - - /* - * We do not attempt to delete/quiesce/etc. the controller if - * some sort of error indidication occurs. We may want to do - * so in the future, but for now we just let the user deal with - * it. One reason for this is that what to do with an error - * or when to send what ćrror is not really agreed on, so - * we get errors that may not be fatal but just look like they - * are...so let the user deal with it. - */ - switch(msg[4]) - { - case I2O_EVT_IND_EXEC_RESOURCE_LIMITS: - printk(KERN_ERR "%s: Out of resources\n", c->name); - break; - - case I2O_EVT_IND_EXEC_POWER_FAIL: - printk(KERN_ERR "%s: Power failure\n", c->name); - break; - - case I2O_EVT_IND_EXEC_HW_FAIL: - { - char *fail[] = - { - "Unknown Error", - "Power Lost", - "Code Violation", - "Parity Error", - "Code Execution Exception", - "Watchdog Timer Expired" - }; - - if(msg[5] <= 6) - printk(KERN_ERR "%s: Hardware Failure: %s\n", - c->name, fail[msg[5]]); - else - printk(KERN_ERR "%s: Unknown Hardware Failure\n", c->name); - - break; - } - - /* - * New device created - * - Create a new i2o_device entry - * - Inform all interested drivers about this device's existence - */ - case I2O_EVT_IND_EXEC_NEW_LCT_ENTRY: - { - struct i2o_device *d = (struct i2o_device *) - kmalloc(sizeof(struct i2o_device), GFP_KERNEL); - int i; - - memcpy(&d->lct_data, &msg[5], sizeof(i2o_lct_entry)); - - d->next = NULL; - d->controller = c; - d->flags = 0; - - i2o_report_controller_unit(c, d); - i2o_install_device(c,d); - - for(i = 0; i < MAX_I2O_MODULES; i++) - { - if(i2o_handlers[i] && - i2o_handlers[i]->new_dev_notify && - (i2o_handlers[i]->class&d->lct_data.class_id)) - { - spin_lock(&i2o_dev_lock); - i2o_handlers[i]->new_dev_notify(c,d); - spin_unlock(&i2o_dev_lock); - } - } - - break; - } - - /* - * LCT entry for a device has been modified, so update it - * internally. - */ - case I2O_EVT_IND_EXEC_MODIFIED_LCT: - { - struct i2o_device *d; - i2o_lct_entry *new_lct = (i2o_lct_entry *)&msg[5]; - - for(d = c->devices; d; d = d->next) - { - if(d->lct_data.tid == new_lct->tid) - { - memcpy(&d->lct_data, new_lct, sizeof(i2o_lct_entry)); - break; - } - } - break; - } - - case I2O_EVT_IND_CONFIGURATION_FLAG: - printk(KERN_WARNING "%s requires user configuration\n", c->name); - break; - - case I2O_EVT_IND_GENERAL_WARNING: - printk(KERN_WARNING "%s: Warning notification received!" - "Check configuration for errors!\n", c->name); - break; - - default: - printk(KERN_WARNING "%s: No handler for event (0x%08x)\n", c->name, msg[4]); - break; - } - } - - return 0; -} - -/* - * Dynamic LCT update. This compares the LCT with the currently - * installed devices to check for device deletions..this needed b/c there - * is no DELETED_LCT_ENTRY EventIndicator for the Executive class so - * we can't just have the event handler do this...annoying - * - * This is a hole in the spec that will hopefully be fixed someday. - */ -static int i2o_dyn_lct(void *foo) -{ - struct i2o_controller *c = (struct i2o_controller *)foo; - struct i2o_device *d = NULL; - struct i2o_device *d1 = NULL; - int i = 0; - int found = 0; - int entries; - void *tmp; - char name[16]; - - lock_kernel(); - daemonize(); - unlock_kernel(); - - sprintf(name, "iop%d_lctd", c->unit); - strcpy(current->comm, name); - - c->lct_running = 1; - - while(1) - { - down_interruptible(&c->lct_sem); - if(signal_pending(current)) - { - dprintk(KERN_ERR "%s: LCT thread dead\n", c->name); - c->lct_running = 0; - return 0; - } - - entries = c->dlct->table_size; - entries -= 3; - entries /= 9; - - dprintk(KERN_INFO "%s: Dynamic LCT Update\n",c->name); - dprintk(KERN_INFO "%s: Dynamic LCT contains %d entries\n", c->name, entries); - - if(!entries) - { - printk(KERN_INFO "%s: Empty LCT???\n", c->name); - continue; - } - - /* - * Loop through all the devices on the IOP looking for their - * LCT data in the LCT. We assume that TIDs are not repeated. - * as that is the only way to really tell. It's been confirmed - * by the IRTOS vendor(s?) that TIDs are not reused until they - * wrap arround(4096), and I doubt a system will up long enough - * to create/delete that many devices. - */ - for(d = c->devices; d; ) - { - found = 0; - d1 = d->next; - - for(i = 0; i < entries; i++) - { - if(d->lct_data.tid == c->dlct->lct_entry[i].tid) - { - found = 1; - break; - } - } - if(!found) - { - dprintk(KERN_INFO "i2o_core: Deleted device!\n"); - spin_lock(&i2o_dev_lock); - i2o_delete_device(d); - spin_unlock(&i2o_dev_lock); - } - d = d1; - } - - /* - * Tell LCT to renotify us next time there is a change - */ - i2o_lct_notify(c); - - /* - * Copy new LCT into public LCT - * - * Possible race if someone is reading LCT while we are copying - * over it. If this happens, we'll fix it then. but I doubt that - * the LCT will get updated often enough or will get read by - * a user often enough to worry. - */ - if(c->lct->table_size < c->dlct->table_size) - { - tmp = c->lct; - c->lct = kmalloc(c->dlct->table_size<<2, GFP_KERNEL); - if(!c->lct) - { - printk(KERN_ERR "%s: No memory for LCT!\n", c->name); - c->lct = tmp; - continue; - } - kfree(tmp); - } - memcpy(c->lct, c->dlct, c->dlct->table_size<<2); - } - - return 0; -} - -/** - * i2o_run_queue - process pending events on a controller - * @c: controller to process - * - * This is called by the bus specific driver layer when an interrupt - * or poll of this card interface is desired. - */ - -void i2o_run_queue(struct i2o_controller *c) -{ - struct i2o_message *m; - u32 mv; - u32 *msg; - - /* - * Old 960 steppings had a bug in the I2O unit that caused - * the queue to appear empty when it wasn't. - */ - if((mv=I2O_REPLY_READ32(c))==0xFFFFFFFF) - mv=I2O_REPLY_READ32(c); - - while(mv!=0xFFFFFFFF) - { - struct i2o_handler *i; - m=(struct i2o_message *)bus_to_virt(mv); - msg=(u32*)m; - - /* - * Temporary Debugging - */ - if(m->function==0x15) - printk(KERN_ERR "%s: UTFR!\n", c->name); - - i=i2o_handlers[m->initiator_context&(MAX_I2O_MODULES-1)]; - if(i && i->reply) - i->reply(i,c,m); - else - { - printk(KERN_WARNING "I2O: Spurious reply to handler %d\n", - m->initiator_context&(MAX_I2O_MODULES-1)); - } - i2o_flush_reply(c,mv); - mb(); - - /* That 960 bug again... */ - if((mv=I2O_REPLY_READ32(c))==0xFFFFFFFF) - mv=I2O_REPLY_READ32(c); - } -} - - -/** - * i2o_get_class_name - do i2o class name lookup - * @class: class number - * - * Return a descriptive string for an i2o class - */ - -const char *i2o_get_class_name(int class) -{ - int idx = 16; - static char *i2o_class_name[] = { - "Executive", - "Device Driver Module", - "Block Device", - "Tape Device", - "LAN Interface", - "WAN Interface", - "Fibre Channel Port", - "Fibre Channel Device", - "SCSI Device", - "ATE Port", - "ATE Device", - "Floppy Controller", - "Floppy Device", - "Secondary Bus Port", - "Peer Transport Agent", - "Peer Transport", - "Unknown" - }; - - switch(class&0xFFF) - { - case I2O_CLASS_EXECUTIVE: - idx = 0; break; - case I2O_CLASS_DDM: - idx = 1; break; - case I2O_CLASS_RANDOM_BLOCK_STORAGE: - idx = 2; break; - case I2O_CLASS_SEQUENTIAL_STORAGE: - idx = 3; break; - case I2O_CLASS_LAN: - idx = 4; break; - case I2O_CLASS_WAN: - idx = 5; break; - case I2O_CLASS_FIBRE_CHANNEL_PORT: - idx = 6; break; - case I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL: - idx = 7; break; - case I2O_CLASS_SCSI_PERIPHERAL: - idx = 8; break; - case I2O_CLASS_ATE_PORT: - idx = 9; break; - case I2O_CLASS_ATE_PERIPHERAL: - idx = 10; break; - case I2O_CLASS_FLOPPY_CONTROLLER: - idx = 11; break; - case I2O_CLASS_FLOPPY_DEVICE: - idx = 12; break; - case I2O_CLASS_BUS_ADAPTER_PORT: - idx = 13; break; - case I2O_CLASS_PEER_TRANSPORT_AGENT: - idx = 14; break; - case I2O_CLASS_PEER_TRANSPORT: - idx = 15; break; - } - - return i2o_class_name[idx]; -} - - -/** - * i2o_wait_message - * @c: controller - * @why: explanation - * - * This function waits up to 5 seconds for a message slot to be - * available. If no message is available it prints an error message - * that is expected to be what the message will be used for (eg - * "get_status"). 0xFFFFFFFF is returned on a failure. - * - * On a success the message is returned. This is the physical page - * frame offset address from the read port. (See the i2o spec) - */ - -u32 i2o_wait_message(struct i2o_controller *c, char *why) -{ - long time=jiffies; - u32 m; - while((m=I2O_POST_READ32(c))==0xFFFFFFFF) - { - if((jiffies-time)>=5*HZ) - { - dprintk(KERN_ERR "%s: Timeout waiting for message frame to send %s.\n", - c->name, why); - return 0xFFFFFFFF; - } - schedule(); - barrier(); - } - return m; -} - -/** - * i2o_report_controller_unit - print information about a tid - * @c: controller - * @d: device - * - * Dump an information block associated with a given unit (TID). The - * tables are read and a block of text is output to printk that is - * formatted intended for the user. - */ - -void i2o_report_controller_unit(struct i2o_controller *c, struct i2o_device *d) -{ - char buf[64]; - char str[22]; - int ret; - int unit = d->lct_data.tid; - - printk(KERN_INFO "Target ID %d.\n", unit); - - if((ret=i2o_query_scalar(c, unit, 0xF100, 3, buf, 16))>=0) - { - buf[16]=0; - printk(KERN_INFO " Vendor: %s\n", buf); - } - if((ret=i2o_query_scalar(c, unit, 0xF100, 4, buf, 16))>=0) - { - buf[16]=0; - printk(KERN_INFO " Device: %s\n", buf); - } -#if 0 - if(i2o_query_scalar(c, unit, 0xF100, 5, buf, 16)>=0) - { - buf[16]=0; - printk(KERN_INFO " Description: %s\n", buf); - } -#endif - if((ret=i2o_query_scalar(c, unit, 0xF100, 6, buf, 8))>=0) - { - buf[8]=0; - printk(KERN_INFO " Rev: %s\n", buf); - } - - printk(KERN_INFO " Class: "); - sprintf(str, "%-21s", i2o_get_class_name(d->lct_data.class_id)); - printk("%s\n", str); - - printk(KERN_INFO " Subclass: 0x%04X\n", d->lct_data.sub_class); - printk(KERN_INFO " Flags: "); - - if(d->lct_data.device_flags&(1<<0)) - printk("C"); // ConfigDialog requested - if(d->lct_data.device_flags&(1<<1)) - printk("U"); // Multi-user capable - if(!(d->lct_data.device_flags&(1<<4))) - printk("P"); // Peer service enabled! - if(!(d->lct_data.device_flags&(1<<5))) - printk("M"); // Mgmt service enabled! - printk("\n"); - -} - - -/* - * Parse the hardware resource table. Right now we print it out - * and don't do a lot with it. We should collate these and then - * interact with the Linux resource allocation block. - * - * Lets prove we can read it first eh ? - * - * This is full of endianisms! - */ - -static int i2o_parse_hrt(struct i2o_controller *c) -{ -#ifdef DRIVERDEBUG - u32 *rows=(u32*)c->hrt; - u8 *p=(u8 *)c->hrt; - u8 *d; - int count; - int length; - int i; - int state; - - if(p[3]!=0) - { - printk(KERN_ERR "%s: HRT table for controller is too new a version.\n", - c->name); - return -1; - } - - count=p[0]|(p[1]<<8); - length = p[2]; - - printk(KERN_INFO "%s: HRT has %d entries of %d bytes each.\n", - c->name, count, length<<2); - - rows+=2; - - for(i=0;i<count;i++) - { - printk(KERN_INFO "Adapter %08X: ", rows[0]); - p=(u8 *)(rows+1); - d=(u8 *)(rows+2); - state=p[1]<<8|p[0]; - - printk("TID %04X:[", state&0xFFF); - state>>=12; - if(state&(1<<0)) - printk("H"); /* Hidden */ - if(state&(1<<2)) - { - printk("P"); /* Present */ - if(state&(1<<1)) - printk("C"); /* Controlled */ - } - if(state>9) - printk("*"); /* Hard */ - - printk("]:"); - - switch(p[3]&0xFFFF) - { - case 0: - /* Adapter private bus - easy */ - printk("Local bus %d: I/O at 0x%04X Mem 0x%08X", - p[2], d[1]<<8|d[0], *(u32 *)(d+4)); - break; - case 1: - /* ISA bus */ - printk("ISA %d: CSN %d I/O at 0x%04X Mem 0x%08X", - p[2], d[2], d[1]<<8|d[0], *(u32 *)(d+4)); - break; - - case 2: /* EISA bus */ - printk("EISA %d: Slot %d I/O at 0x%04X Mem 0x%08X", - p[2], d[3], d[1]<<8|d[0], *(u32 *)(d+4)); - break; - - case 3: /* MCA bus */ - printk("MCA %d: Slot %d I/O at 0x%04X Mem 0x%08X", - p[2], d[3], d[1]<<8|d[0], *(u32 *)(d+4)); - break; - - case 4: /* PCI bus */ - printk("PCI %d: Bus %d Device %d Function %d", - p[2], d[2], d[1], d[0]); - break; - - case 0x80: /* Other */ - default: - printk("Unsupported bus type."); - break; - } - printk("\n"); - rows+=length; - } -#endif - return 0; -} - -/* - * The logical configuration table tells us what we can talk to - * on the board. Most of the stuff isn't interesting to us. - */ - -static int i2o_parse_lct(struct i2o_controller *c) -{ - int i; - int max; - int tid; - struct i2o_device *d; - i2o_lct *lct = c->lct; - - if (lct == NULL) { - printk(KERN_ERR "%s: LCT is empty???\n", c->name); - return -1; - } - - max = lct->table_size; - max -= 3; - max /= 9; - - printk(KERN_INFO "%s: LCT has %d entries.\n", c->name, max); - - if(lct->iop_flags&(1<<0)) - printk(KERN_WARNING "%s: Configuration dialog desired.\n", c->name); - - for(i=0;i<max;i++) - { - d = (struct i2o_device *)kmalloc(sizeof(struct i2o_device), GFP_KERNEL); - if(d==NULL) - { - printk(KERN_CRIT "i2o_core: Out of memory for I2O device data.\n"); - return -ENOMEM; - } - - d->controller = c; - d->next = NULL; - - memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry)); - - d->flags = 0; - tid = d->lct_data.tid; - - i2o_report_controller_unit(c, d); - - i2o_install_device(c, d); - } - return 0; -} - - -/** - * i2o_quiesce_controller - quiesce controller - * @c: controller - * - * Quiesce an IOP. Causes IOP to make external operation quiescent - * (i2o 'READY' state). Internal operation of the IOP continues normally. - */ - -int i2o_quiesce_controller(struct i2o_controller *c) -{ - u32 msg[4]; - int ret; - - i2o_status_get(c); - - /* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */ - - if ((c->status_block->iop_state != ADAPTER_STATE_READY) && - (c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL)) - { - return 0; - } - - msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID; - msg[3] = 0; - - /* Long timeout needed for quiesce if lots of devices */ - - if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240))) - printk(KERN_INFO "%s: Unable to quiesce (status=%#x).\n", - c->name, -ret); - else - dprintk(KERN_INFO "%s: Quiesced.\n", c->name); - - i2o_status_get(c); // Entered READY state - return ret; -} - -/** - * i2o_enable_controller - move controller from ready to operational - * @c: controller - * - * Enable IOP. This allows the IOP to resume external operations and - * reverses the effect of a quiesce. In the event of an error a negative - * errno code is returned. - */ - -int i2o_enable_controller(struct i2o_controller *c) -{ - u32 msg[4]; - int ret; - - i2o_status_get(c); - - /* Enable only allowed on READY state */ - if(c->status_block->iop_state != ADAPTER_STATE_READY) - return -EINVAL; - - msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID; - - /* How long of a timeout do we need? */ - - if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240))) - printk(KERN_ERR "%s: Could not enable (status=%#x).\n", - c->name, -ret); - else - dprintk(KERN_INFO "%s: Enabled.\n", c->name); - - i2o_status_get(c); // entered OPERATIONAL state - - return ret; -} - -/** - * i2o_clear_controller - clear a controller - * @c: controller - * - * Clear an IOP to HOLD state, ie. terminate external operations, clear all - * input queues and prepare for a system restart. IOP's internal operation - * continues normally and the outbound queue is alive. - * The IOP is not expected to rebuild its LCT. - */ - -int i2o_clear_controller(struct i2o_controller *c) -{ - struct i2o_controller *iop; - u32 msg[4]; - int ret; - - /* Quiesce all IOPs first */ - - for (iop = i2o_controller_chain; iop; iop = iop->next) - i2o_quiesce_controller(iop); - - msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1]=I2O_CMD_ADAPTER_CLEAR<<24|HOST_TID<<12|ADAPTER_TID; - msg[3]=0; - - if ((ret=i2o_post_wait(c, msg, sizeof(msg), 30))) - printk(KERN_INFO "%s: Unable to clear (status=%#x).\n", - c->name, -ret); - else - dprintk(KERN_INFO "%s: Cleared.\n",c->name); - - i2o_status_get(c); - - /* Enable other IOPs */ - - for (iop = i2o_controller_chain; iop; iop = iop->next) - if (iop != c) - i2o_enable_controller(iop); - - return ret; -} - - -/** - * i2o_reset_controller - * @c: controller to reset - * - * Reset the IOP into INIT state and wait until IOP gets into RESET state. - * Terminate all external operations, clear IOP's inbound and outbound - * queues, terminate all DDMs, and reload the IOP's operating environment - * and all local DDMs. The IOP rebuilds its LCT. - */ - -static int i2o_reset_controller(struct i2o_controller *c) -{ - struct i2o_controller *iop; - u32 m; - u8 *status; - u32 *msg; - long time; - - /* Quiesce all IOPs first */ - - for (iop = i2o_controller_chain; iop; iop = iop->next) - i2o_quiesce_controller(iop); - - m=i2o_wait_message(c, "AdapterReset"); - if(m==0xFFFFFFFF) - return -ETIMEDOUT; - msg=(u32 *)(c->mem_offset+m); - - status=(void *)kmalloc(4, GFP_KERNEL); - if(status==NULL) { - printk(KERN_ERR "IOP reset failed - no free memory.\n"); - return -ENOMEM; - } - memset(status, 0, 4); - - msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID; - msg[2]=core_context; - msg[3]=0; - msg[4]=0; - msg[5]=0; - msg[6]=virt_to_bus(status); - msg[7]=0; /* 64bit host FIXME */ - - i2o_post_message(c,m); - - /* Wait for a reply */ - time=jiffies; - while(status[0]==0) - { - if((jiffies-time)>=20*HZ) - { - printk(KERN_ERR "IOP reset timeout.\n"); - kfree(status); - return -ETIMEDOUT; - } - schedule(); - barrier(); - } - - if (status[0]==I2O_CMD_IN_PROGRESS) - { - /* - * Once the reset is sent, the IOP goes into the INIT state - * which is indeterminate. We need to wait until the IOP - * has rebooted before we can let the system talk to - * it. We read the inbound Free_List until a message is - * available. If we can't read one in the given ammount of - * time, we assume the IOP could not reboot properly. - */ - - dprintk(KERN_INFO "%s: Reset in progress, waiting for reboot...\n", - c->name); - - time = jiffies; - m = I2O_POST_READ32(c); - while(m == 0XFFFFFFFF) - { - if((jiffies-time) >= 30*HZ) - { - printk(KERN_ERR "%s: Timeout waiting for IOP reset.\n", - c->name); - return -ETIMEDOUT; - } - schedule(); - barrier(); - m = I2O_POST_READ32(c); - } - i2o_flush_reply(c,m); - } - - /* If IopReset was rejected or didn't perform reset, try IopClear */ - - i2o_status_get(c); - if (status[0] == I2O_CMD_REJECTED || - c->status_block->iop_state != ADAPTER_STATE_RESET) - { - printk(KERN_WARNING "%s: Reset rejected, trying to clear\n",c->name); - i2o_clear_controller(c); - } - else - dprintk(KERN_INFO "%s: Reset completed.\n", c->name); - - /* Enable other IOPs */ - - for (iop = i2o_controller_chain; iop; iop = iop->next) - if (iop != c) - i2o_enable_controller(iop); - - kfree(status); - return 0; -} - - -/** - * i2o_status_get - get the status block for the IOP - * @c: controller - * - * Issue a status query on the controller. This updates the - * attached status_block. If the controller fails to reply or an - * error occurs then a negative errno code is returned. On success - * zero is returned and the status_blok is updated. - */ - -int i2o_status_get(struct i2o_controller *c) -{ - long time; - u32 m; - u32 *msg; - u8 *status_block; - - if (c->status_block == NULL) - { - c->status_block = (i2o_status_block *) - kmalloc(sizeof(i2o_status_block),GFP_KERNEL); - if (c->status_block == NULL) - { - printk(KERN_CRIT "%s: Get Status Block failed; Out of memory.\n", - c->name); - return -ENOMEM; - } - } - - status_block = (u8*)c->status_block; - memset(c->status_block,0,sizeof(i2o_status_block)); - - m=i2o_wait_message(c, "StatusGet"); - if(m==0xFFFFFFFF) - return -ETIMEDOUT; - msg=(u32 *)(c->mem_offset+m); - - msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1]=I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID; - msg[2]=core_context; - msg[3]=0; - msg[4]=0; - msg[5]=0; - msg[6]=virt_to_bus(c->status_block); - msg[7]=0; /* 64bit host FIXME */ - msg[8]=sizeof(i2o_status_block); /* always 88 bytes */ - - i2o_post_message(c,m); - - /* Wait for a reply */ - - time=jiffies; - while(status_block[87]!=0xFF) - { - if((jiffies-time)>=5*HZ) - { - printk(KERN_ERR "%s: Get status timeout.\n",c->name); - return -ETIMEDOUT; - } - schedule(); - barrier(); - } - -#ifdef DRIVERDEBUG - printk(KERN_INFO "%s: State = ", c->name); - switch (c->status_block->iop_state) { - case 0x01: - printk("INIT\n"); - break; - case 0x02: - printk("RESET\n"); - break; - case 0x04: - printk("HOLD\n"); - break; - case 0x05: - printk("READY\n"); - break; - case 0x08: - printk("OPERATIONAL\n"); - break; - case 0x10: - printk("FAILED\n"); - break; - case 0x11: - printk("FAULTED\n"); - break; - default: - printk("%x (unknown !!)\n",c->status_block->iop_state); -} -#endif - - return 0; -} - -/* - * Get the Hardware Resource Table for the device. - * The HRT contains information about possible hidden devices - * but is mostly useless to us - */ -int i2o_hrt_get(struct i2o_controller *c) -{ - u32 msg[6]; - int ret, size = sizeof(i2o_hrt); - - /* Read first just the header to figure out the real size */ - - do { - if (c->hrt == NULL) { - c->hrt=kmalloc(size, GFP_KERNEL); - if (c->hrt == NULL) { - printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", c->name); - return -ENOMEM; - } - } - - msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4; - msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[3]= 0; - msg[4]= (0xD0000000 | size); /* Simple transaction */ - msg[5]= virt_to_bus(c->hrt); /* Dump it here */ - - if ((ret = i2o_post_wait(c, msg, sizeof(msg), 20))) { - printk(KERN_ERR "%s: Unable to get HRT (status=%#x)\n", - c->name, -ret); - return ret; - } - - if (c->hrt->num_entries * c->hrt->entry_len << 2 > size) { - size = c->hrt->num_entries * c->hrt->entry_len << 2; - kfree(c->hrt); - c->hrt = NULL; - } - } while (c->hrt == NULL); - - i2o_parse_hrt(c); // just for debugging - - return 0; -} - -/* - * Send the I2O System Table to the specified IOP - * - * The system table contains information about all the IOPs in the - * system. It is build and then sent to each IOP so that IOPs can - * establish connections between each other. - * - */ -static int i2o_systab_send(struct i2o_controller *iop) -{ - u32 msg[12]; - u32 privmem[2]; - u32 privio[2]; - int ret; - - privmem[0] = iop->status_block->current_mem_base; - privmem[1] = iop->status_block->current_mem_size; - privio[0] = iop->status_block->current_io_base; - privio[1] = iop->status_block->current_io_size; - - msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6; - msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[3] = 0; - msg[4] = (0<<16) | ((iop->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */ - msg[5] = 0; /* Segment 0 */ - - /* - * Provide three SGL-elements: - * System table (SysTab), Private memory space declaration and - * Private i/o space declaration - */ - msg[6] = 0x54000000 | sys_tbl_len; - msg[7] = virt_to_bus(sys_tbl); - msg[8] = 0x54000000 | 0; - msg[9] = virt_to_bus(privmem); - msg[10] = 0xD4000000 | 0; - msg[11] = virt_to_bus(privio); - - if ((ret=i2o_post_wait(iop, msg, sizeof(msg), 120))) - printk(KERN_INFO "%s: Unable to set SysTab (status=%#x).\n", - iop->name, -ret); - else - dprintk(KERN_INFO "%s: SysTab set.\n", iop->name); - - i2o_status_get(iop); // Entered READY state - - return ret; - - } - -/* - * Initialize I2O subsystem. - */ -static void __init i2o_sys_init(void) -{ - struct i2o_controller *iop, *niop = NULL; - - printk(KERN_INFO "Activating I2O controllers...\n"); - printk(KERN_INFO "This may take a few minutes if there are many devices\n"); - - /* In INIT state, Activate IOPs */ - for (iop = i2o_controller_chain; iop; iop = niop) { - dprintk(KERN_INFO "Calling i2o_activate_controller for %s...\n", - iop->name); - niop = iop->next; - if (i2o_activate_controller(iop) < 0) - i2o_delete_controller(iop); - } - - /* Active IOPs in HOLD state */ - -rebuild_sys_tab: - if (i2o_controller_chain == NULL) - return; - - /* - * If build_sys_table fails, we kill everything and bail - * as we can't init the IOPs w/o a system table - */ - dprintk(KERN_INFO "i2o_core: Calling i2o_build_sys_table...\n"); - if (i2o_build_sys_table() < 0) { - i2o_sys_shutdown(); - return; - } - - /* If IOP don't get online, we need to rebuild the System table */ - for (iop = i2o_controller_chain; iop; iop = niop) { - niop = iop->next; - dprintk(KERN_INFO "Calling i2o_online_controller for %s...\n", iop->name); - if (i2o_online_controller(iop) < 0) { - i2o_delete_controller(iop); - goto rebuild_sys_tab; - } - } - - /* Active IOPs now in OPERATIONAL state */ - - /* - * Register for status updates from all IOPs - */ - for(iop = i2o_controller_chain; iop; iop=iop->next) { - - /* Create a kernel thread to deal with dynamic LCT updates */ - iop->lct_pid = kernel_thread(i2o_dyn_lct, iop, CLONE_SIGHAND); - - /* Update change ind on DLCT */ - iop->dlct->change_ind = iop->lct->change_ind; - - /* Start dynamic LCT updates */ - i2o_lct_notify(iop); - - /* Register for all events from IRTOS */ - i2o_event_register(iop, core_context, 0, 0, 0xFFFFFFFF); - } -} - -/** - * i2o_sys_shutdown - shutdown I2O system - * - * Bring down each i2o controller and then return. Each controller - * is taken through an orderly shutdown - */ - -static void i2o_sys_shutdown(void) -{ - struct i2o_controller *iop, *niop; - - /* Delete all IOPs from the controller chain */ - /* that will reset all IOPs too */ - - for (iop = i2o_controller_chain; iop; iop = niop) { - niop = iop->next; - i2o_delete_controller(iop); - } -} - -/** - * i2o_activate_controller - bring controller up to HOLD - * @iop: controller - * - * This function brings an I2O controller into HOLD state. The adapter - * is reset if neccessary and then the queues and resource table - * are read. -1 is returned on a failure, 0 on success. - * - */ - -int i2o_activate_controller(struct i2o_controller *iop) -{ - /* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */ - /* In READY state, Get status */ - - if (i2o_status_get(iop) < 0) { - printk(KERN_INFO "Unable to obtain status of %s, " - "attempting a reset.\n", iop->name); - if (i2o_reset_controller(iop) < 0) - return -1; - } - - if(iop->status_block->iop_state == ADAPTER_STATE_FAULTED) { - printk(KERN_CRIT "%s: hardware fault\n", iop->name); - return -1; - } - - if (iop->status_block->i2o_version > I2OVER15) { - printk(KERN_ERR "%s: Not running vrs. 1.5. of the I2O Specification.\n", - iop->name); - return -1; - } - - if (iop->status_block->iop_state == ADAPTER_STATE_READY || - iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL || - iop->status_block->iop_state == ADAPTER_STATE_HOLD || - iop->status_block->iop_state == ADAPTER_STATE_FAILED) - { - dprintk(KERN_INFO "%s: Already running, trying to reset...\n", - iop->name); - if (i2o_reset_controller(iop) < 0) - return -1; - } - - if (i2o_init_outbound_q(iop) < 0) - return -1; - - if (i2o_post_outbound_messages(iop)) - return -1; - - /* In HOLD state */ - - if (i2o_hrt_get(iop) < 0) - return -1; - - return 0; -} - - -/** - * i2o_init_outbound_queue - setup the outbound queue - * @c: controller - * - * Clear and (re)initialize IOP's outbound queue. Returns 0 on - * success or a negative errno code on a failure. - */ - -int i2o_init_outbound_q(struct i2o_controller *c) -{ - u8 *status; - u32 m; - u32 *msg; - u32 time; - - dprintk(KERN_INFO "%s: Initializing Outbound Queue...\n", c->name); - m=i2o_wait_message(c, "OutboundInit"); - if(m==0xFFFFFFFF) - return -ETIMEDOUT; - msg=(u32 *)(c->mem_offset+m); - - status = kmalloc(4,GFP_KERNEL); - if (status==NULL) { - printk(KERN_ERR "%s: Outbound Queue initialization failed - no free memory.\n", - c->name); - return -ENOMEM; - } - memset(status, 0, 4); - - msg[0]= EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6; - msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2]= core_context; - msg[3]= 0x0106; /* Transaction context */ - msg[4]= 4096; /* Host page frame size */ - /* Frame size is in words. Pick 128, its what everyone elses uses and - other sizes break some adapters. */ - msg[5]= MSG_FRAME_SIZE<<16|0x80; /* Outbound msg frame size and Initcode */ - msg[6]= 0xD0000004; /* Simple SG LE, EOB */ - msg[7]= virt_to_bus(status); - - i2o_post_message(c,m); - - barrier(); - time=jiffies; - while(status[0] < I2O_CMD_REJECTED) - { - if((jiffies-time)>=30*HZ) - { - if(status[0]==0x00) - printk(KERN_ERR "%s: Ignored queue initialize request.\n", - c->name); - else - printk(KERN_ERR "%s: Outbound queue initialize timeout.\n", - c->name); - kfree(status); - return -ETIMEDOUT; - } - schedule(); - barrier(); - } - - if(status[0] != I2O_CMD_COMPLETED) - { - printk(KERN_ERR "%s: IOP outbound initialise failed.\n", c->name); - kfree(status); - return -ETIMEDOUT; - } - - return 0; -} - -/** - * i2o_post_outbound_messages - fill message queue - * @c: controller - * - * Allocate a message frame and load the messages into the IOP. The - * function returns zero on success or a negative errno code on - * failure. - */ - -int i2o_post_outbound_messages(struct i2o_controller *c) -{ - int i; - u32 m; - /* Alloc space for IOP's outbound queue message frames */ - - c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL); - if(c->page_frame==NULL) { - printk(KERN_CRIT "%s: Outbound Q initialize failed; out of memory.\n", - c->name); - return -ENOMEM; - } - m=virt_to_bus(c->page_frame); - - /* Post frames */ - - for(i=0; i< NMBR_MSG_FRAMES; i++) { - I2O_REPLY_WRITE32(c,m); - mb(); - m += MSG_FRAME_SIZE; - } - - return 0; -} - -/* - * Get the IOP's Logical Configuration Table - */ -int i2o_lct_get(struct i2o_controller *c) -{ - u32 msg[8]; - int ret, size = c->status_block->expected_lct_size; - - do { - if (c->lct == NULL) { - c->lct = kmalloc(size, GFP_KERNEL); - if(c->lct == NULL) { - printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n", - c->name); - return -ENOMEM; - } - } - memset(c->lct, 0, size); - - msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6; - msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID; - /* msg[2] filled in i2o_post_wait */ - msg[3] = 0; - msg[4] = 0xFFFFFFFF; /* All devices */ - msg[5] = 0x00000000; /* Report now */ - msg[6] = 0xD0000000|size; - msg[7] = virt_to_bus(c->lct); - - if ((ret=i2o_post_wait(c, msg, sizeof(msg), 120))) { - printk(KERN_ERR "%s: LCT Get failed (status=%#x.\n", - c->name, -ret); - return ret; - } - - if (c->lct->table_size << 2 > size) { - size = c->lct->table_size << 2; - kfree(c->lct); - c->lct = NULL; - } - } while (c->lct == NULL); - - if ((ret=i2o_parse_lct(c)) < 0) - return ret; - - return 0; -} - -/* - * Like above, but used for async notification. The main - * difference is that we keep track of the CurrentChangeIndiicator - * so that we only get updates when it actually changes. - * - */ -int i2o_lct_notify(struct i2o_controller *c) -{ - u32 msg[8]; - - msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6; - msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2] = core_context; - msg[3] = 0xDEADBEEF; - msg[4] = 0xFFFFFFFF; /* All devices */ - msg[5] = c->dlct->change_ind+1; /* Next change */ - msg[6] = 0xD0000000|8192; - msg[7] = virt_to_bus(c->dlct); - - return i2o_post_this(c, msg, sizeof(msg)); -} - -/* - * Bring a controller online into OPERATIONAL state. - */ -int i2o_online_controller(struct i2o_controller *iop) -{ - if (i2o_systab_send(iop) < 0) - return -1; - - /* In READY state */ - - dprintk(KERN_INFO "%s: Attempting to enable...\n", iop->name); - if (i2o_enable_controller(iop) < 0) - return -1; - - /* In OPERATIONAL state */ - - dprintk(KERN_INFO "%s: Attempting to get/parse lct...\n", iop->name); - if (i2o_lct_get(iop) < 0) - return -1; - - return 0; -} - -/* - * Build system table - * - * The system table contains information about all the IOPs in the - * system (duh) and is used by the Executives on the IOPs to establish - * peer2peer connections. We're not supporting peer2peer at the moment, - * but this will be needed down the road for things like lan2lan forwarding. - */ -static int i2o_build_sys_table(void) -{ - struct i2o_controller *iop = NULL; - struct i2o_controller *niop = NULL; - int count = 0; - - sys_tbl_len = sizeof(struct i2o_sys_tbl) + // Header + IOPs - (i2o_num_controllers) * - sizeof(struct i2o_sys_tbl_entry); - - if(sys_tbl) - kfree(sys_tbl); - - sys_tbl = kmalloc(sys_tbl_len, GFP_KERNEL); - if(!sys_tbl) { - printk(KERN_CRIT "SysTab Set failed. Out of memory.\n"); - return -ENOMEM; - } - memset((void*)sys_tbl, 0, sys_tbl_len); - - sys_tbl->num_entries = i2o_num_controllers; - sys_tbl->version = I2OVERSION; /* TODO: Version 2.0 */ - sys_tbl->change_ind = sys_tbl_ind++; - - for(iop = i2o_controller_chain; iop; iop = niop) - { - niop = iop->next; - - /* - * Get updated IOP state so we have the latest information - * - * We should delete the controller at this point if it - * doesn't respond since if it's not on the system table - * it is techninically not part of the I2O subsyßtem... - */ - if(i2o_status_get(iop)) { - printk(KERN_ERR "%s: Deleting b/c could not get status while" - "attempting to build system table\n", iop->name); - i2o_delete_controller(iop); - sys_tbl->num_entries--; - continue; // try the next one - } - - sys_tbl->iops[count].org_id = iop->status_block->org_id; - sys_tbl->iops[count].iop_id = iop->unit + 2; - sys_tbl->iops[count].seg_num = 0; - sys_tbl->iops[count].i2o_version = - iop->status_block->i2o_version; - sys_tbl->iops[count].iop_state = - iop->status_block->iop_state; - sys_tbl->iops[count].msg_type = - iop->status_block->msg_type; - sys_tbl->iops[count].frame_size = - iop->status_block->inbound_frame_size; - sys_tbl->iops[count].last_changed = sys_tbl_ind - 1; // ?? - sys_tbl->iops[count].iop_capabilities = - iop->status_block->iop_capabilities; - sys_tbl->iops[count].inbound_low = - (u32)virt_to_bus(iop->post_port); - sys_tbl->iops[count].inbound_high = 0; // TODO: 64-bit support - - count++; - } - -#ifdef DRIVERDEBUG -{ - u32 *table; - table = (u32*)sys_tbl; - for(count = 0; count < (sys_tbl_len >>2); count++) - printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", count, table[count]); -} -#endif - - return 0; -} - - -/* - * Run time support routines - */ - -/* - * Generic "post and forget" helpers. This is less efficient - we do - * a memcpy for example that isnt strictly needed, but for most uses - * this is simply not worth optimising - */ - -int i2o_post_this(struct i2o_controller *c, u32 *data, int len) -{ - u32 m; - u32 *msg; - unsigned long t=jiffies; - - do - { - mb(); - m = I2O_POST_READ32(c); - } - while(m==0xFFFFFFFF && (jiffies-t)<HZ); - - if(m==0xFFFFFFFF) - { - printk(KERN_ERR "%s: Timeout waiting for message frame!\n", - c->name); - return -ETIMEDOUT; - } - msg = (u32 *)(c->mem_offset + m); - memcpy_toio(msg, data, len); - i2o_post_message(c,m); - return 0; -} - -/* - * This core API allows an OSM to post a message and then be told whether - * or not the system received a successful reply. It is useful when - * the OSM does not want to know the exact 3 - */ -int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout) -{ - DECLARE_WAIT_QUEUE_HEAD(wq_i2o_post); - int status = 0; - int flags = 0; - struct i2o_post_wait_data *p1, *p2; - struct i2o_post_wait_data *wait_data = - kmalloc(sizeof(struct i2o_post_wait_data), GFP_KERNEL); - - if(!wait_data) - return -ENOMEM; - - /* - * The spin locking is needed to keep anyone from playing - * with the queue pointers and id while we do the same - */ - spin_lock_irqsave(&post_wait_lock, flags); - wait_data->next = post_wait_queue; - post_wait_queue = wait_data; - wait_data->id = (++post_wait_id) & 0x7fff; - spin_unlock_irqrestore(&post_wait_lock, flags); - - wait_data->wq = &wq_i2o_post; - wait_data->status = -ETIMEDOUT; - - msg[2] = 0x80000000|(u32)core_context|((u32)wait_data->id<<16); - - if ((status = i2o_post_this(c, msg, len))==0) { - interruptible_sleep_on_timeout(&wq_i2o_post, HZ * timeout); - status = wait_data->status; - } - -#ifdef DRIVERDEBUG - if(status == -ETIMEDOUT) - printk(KERN_INFO "%s: POST WAIT TIMEOUT\n",c->name); -#endif - - /* - * Remove the entry from the queue. - * Since i2o_post_wait() may have been called again by - * a different thread while we were waiting for this - * instance to complete, we're not guaranteed that - * this entry is at the head of the queue anymore, so - * we need to search for it, find it, and delete it. - */ - p2 = NULL; - spin_lock_irqsave(&post_wait_lock, flags); - for(p1 = post_wait_queue; p1; p2 = p1, p1 = p1->next) { - if(p1 == wait_data) { - if(p2) - p2->next = p1->next; - else - post_wait_queue = p1->next; - - break; - } - } - spin_unlock_irqrestore(&post_wait_lock, flags); - - kfree(wait_data); - - return status; -} - -/* - * i2o_post_wait is completed and we want to wake up the - * sleeping proccess. Called by core's reply handler. - */ -static void i2o_post_wait_complete(u32 context, int status) -{ - struct i2o_post_wait_data *p1 = NULL; - - /* - * We need to search through the post_wait - * queue to see if the given message is still - * outstanding. If not, it means that the IOP - * took longer to respond to the message than we - * had allowed and timer has already expired. - * Not much we can do about that except log - * it for debug purposes, increase timeout, and recompile - * - * Lock needed to keep anyone from moving queue pointers - * around while we're looking through them. - */ - spin_lock(&post_wait_lock); - for(p1 = post_wait_queue; p1; p1 = p1->next) { - if(p1->id == ((context >> 16) & 0x7fff)) { - p1->status = status; - wake_up_interruptible(p1->wq); - spin_unlock(&post_wait_lock); - return; - } - } - spin_unlock(&post_wait_lock); - - printk(KERN_DEBUG "i2o_post_wait reply after timeout!\n"); -} - -/* Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET - * - * This function can be used for all UtilParamsGet/Set operations. - * The OperationList is given in oplist-buffer, - * and results are returned in reslist-buffer. - * Note that the minimum sized reslist is 8 bytes and contains - * ResultCount, ErrorInfoSize, BlockStatus and BlockSize. - */ -int i2o_issue_params(int cmd, struct i2o_controller *iop, int tid, - void *oplist, int oplen, void *reslist, int reslen) -{ - u32 msg[9]; - u8 *res = (u8 *)reslist; - u32 *res32 = (u32*)reslist; - u32 *restmp = (u32*)reslist; - int len = 0; - int i = 0; - int wait_status; - - msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5; - msg[1] = cmd << 24 | HOST_TID << 12 | tid; - msg[3] = 0; - msg[4] = 0; - msg[5] = 0x54000000 | oplen; /* OperationList */ - msg[6] = virt_to_bus(oplist); - msg[7] = 0xD0000000 | reslen; /* ResultList */ - msg[8] = virt_to_bus(reslist); - - if((wait_status = i2o_post_wait(iop, msg, sizeof(msg), 10))) - return wait_status; /* -DetailedStatus */ - - /* - * Calculate number of bytes of Result LIST - * We need to loop through each Result BLOCK and grab the length - */ - restmp = res32 + 1; - len = 1; - for(i = 0; i < (res32[0]&0X0000FFFF); i++) - { - if(restmp[0]&0x00FF0000) /* BlockStatus != SUCCESS */ - { - printk(KERN_WARNING "%s - Error:\n ErrorInfoSize = 0x%02x, " - "BlockStatus = 0x%02x, BlockSize = 0x%04x\n", - (cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET" - : "PARAMS_GET", - res32[1]>>24, (res32[1]>>16)&0xFF, res32[1]&0xFFFF); - - /* - * If this is the only request,than we return an error - */ - if((res32[0]&0x0000FFFF) == 1) - return -((res[1] >> 16) & 0xFF); /* -BlockStatus */ - } - - len += restmp[0] & 0x0000FFFF; /* Length of res BLOCK */ - restmp += restmp[0] & 0x0000FFFF; /* Skip to next BLOCK */ - } - - return (len << 2); /* bytes used by result list */ -} - -/* - * Query one scalar group value or a whole scalar group. - */ -int i2o_query_scalar(struct i2o_controller *iop, int tid, - int group, int field, void *buf, int buflen) -{ - u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field }; - u8 resblk[8+buflen]; /* 8 bytes for header */ - int size; - - if (field == -1) /* whole group */ - opblk[4] = -1; - - size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid, - opblk, sizeof(opblk), resblk, sizeof(resblk)); - - if (size < 0) - return size; - - memcpy(buf, resblk+8, buflen); /* cut off header */ - return size; -} - -/* - * Set a scalar group value or a whole group. - */ -int i2o_set_scalar(struct i2o_controller *iop, int tid, - int group, int field, void *buf, int buflen) -{ - u16 *opblk; - u8 resblk[8+buflen]; /* 8 bytes for header */ - int size; - - opblk = kmalloc(buflen+64, GFP_KERNEL); - if (opblk == NULL) - { - printk(KERN_ERR "i2o: no memory for operation buffer.\n"); - return -ENOMEM; - } - - opblk[0] = 1; /* operation count */ - opblk[1] = 0; /* pad */ - opblk[2] = I2O_PARAMS_FIELD_SET; - opblk[3] = group; - - if(field == -1) { /* whole group */ - opblk[4] = -1; - memcpy(opblk+5, buf, buflen); - } - else /* single field */ - { - opblk[4] = 1; - opblk[5] = field; - memcpy(opblk+6, buf, buflen); - } - - size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, - opblk, 12+buflen, resblk, sizeof(resblk)); - - kfree(opblk); - return size; -} - -/* - * if oper == I2O_PARAMS_TABLE_GET, get from all rows - * if fieldcount == -1 return all fields - * ibuf and ibuflen are unused (use NULL, 0) - * else return specific fields - * ibuf contains fieldindexes - * - * if oper == I2O_PARAMS_LIST_GET, get from specific rows - * if fieldcount == -1 return all fields - * ibuf contains rowcount, keyvalues - * else return specific fields - * fieldcount is # of fieldindexes - * ibuf contains fieldindexes, rowcount, keyvalues - * - * You could also use directly function i2o_issue_params(). - */ -int i2o_query_table(int oper, struct i2o_controller *iop, int tid, int group, - int fieldcount, void *ibuf, int ibuflen, - void *resblk, int reslen) -{ - u16 *opblk; - int size; - - opblk = kmalloc(10 + ibuflen, GFP_KERNEL); - if (opblk == NULL) - { - printk(KERN_ERR "i2o: no memory for query buffer.\n"); - return -ENOMEM; - } - - opblk[0] = 1; /* operation count */ - opblk[1] = 0; /* pad */ - opblk[2] = oper; - opblk[3] = group; - opblk[4] = fieldcount; - memcpy(opblk+5, ibuf, ibuflen); /* other params */ - - size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET,iop, tid, - opblk, 10+ibuflen, resblk, reslen); - - kfree(opblk); - return size; -} - -/* - * Clear table group, i.e. delete all rows. - */ -int i2o_clear_table(struct i2o_controller *iop, int tid, int group) -{ - u16 opblk[] = { 1, 0, I2O_PARAMS_TABLE_CLEAR, group }; - u8 resblk[32]; /* min 8 bytes for result header */ - - return i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, - opblk, sizeof(opblk), resblk, sizeof(resblk)); -} - -/* - * Add a new row into a table group. - * - * if fieldcount==-1 then we add whole rows - * buf contains rowcount, keyvalues - * else just specific fields are given, rest use defaults - * buf contains fieldindexes, rowcount, keyvalues - */ -int i2o_row_add_table(struct i2o_controller *iop, int tid, - int group, int fieldcount, void *buf, int buflen) -{ - u16 *opblk; - u8 resblk[32]; /* min 8 bytes for header */ - int size; - - opblk = kmalloc(buflen+64, GFP_KERNEL); - if (opblk == NULL) - { - printk(KERN_ERR "i2o: no memory for operation buffer.\n"); - return -ENOMEM; - } - - opblk[0] = 1; /* operation count */ - opblk[1] = 0; /* pad */ - opblk[2] = I2O_PARAMS_ROW_ADD; - opblk[3] = group; - opblk[4] = fieldcount; - memcpy(opblk+5, buf, buflen); - - size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, - opblk, 10+buflen, resblk, sizeof(resblk)); - - kfree(opblk); - return size; -} - - -/* - * Used for error reporting/debugging purposes. - * Following fail status are common to all classes. - * The preserved message must be handled in the reply handler. - */ -void i2o_report_fail_status(u8 req_status, u32* msg) -{ - static char *FAIL_STATUS[] = { - "0x80", /* not used */ - "SERVICE_SUSPENDED", /* 0x81 */ - "SERVICE_TERMINATED", /* 0x82 */ - "CONGESTION", - "FAILURE", - "STATE_ERROR", - "TIME_OUT", - "ROUTING_FAILURE", - "INVALID_VERSION", - "INVALID_OFFSET", - "INVALID_MSG_FLAGS", - "FRAME_TOO_SMALL", - "FRAME_TOO_LARGE", - "INVALID_TARGET_ID", - "INVALID_INITIATOR_ID", - "INVALID_INITIATOR_CONTEX", /* 0x8F */ - "UNKNOWN_FAILURE" /* 0xFF */ - }; - - if (req_status == I2O_FSC_TRANSPORT_UNKNOWN_FAILURE) - printk("TRANSPORT_UNKNOWN_FAILURE (%0#2x)\n.", req_status); - else - printk("TRANSPORT_%s.\n", FAIL_STATUS[req_status & 0x0F]); - - /* Dump some details */ - - printk(KERN_ERR " InitiatorId = %d, TargetId = %d\n", - (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF); - printk(KERN_ERR " LowestVersion = 0x%02X, HighestVersion = 0x%02X\n", - (msg[4] >> 8) & 0xFF, msg[4] & 0xFF); - printk(KERN_ERR " FailingHostUnit = 0x%04X, FailingIOP = 0x%03X\n", - msg[5] >> 16, msg[5] & 0xFFF); - - printk(KERN_ERR " Severity: 0x%02X ", (msg[4] >> 16) & 0xFF); - if (msg[4] & (1<<16)) - printk("(FormatError), " - "this msg can never be delivered/processed.\n"); - if (msg[4] & (1<<17)) - printk("(PathError), " - "this msg can no longer be delivered/processed.\n"); - if (msg[4] & (1<<18)) - printk("(PathState), " - "the system state does not allow delivery.\n"); - if (msg[4] & (1<<19)) - printk("(Congestion), resources temporarily not available;" - "do not retry immediately.\n"); -} - -/* - * Used for error reporting/debugging purposes. - * Following reply status are common to all classes. - */ -void i2o_report_common_status(u8 req_status) -{ - static char *REPLY_STATUS[] = { - "SUCCESS", - "ABORT_DIRTY", - "ABORT_NO_DATA_TRANSFER", - "ABORT_PARTIAL_TRANSFER", - "ERROR_DIRTY", - "ERROR_NO_DATA_TRANSFER", - "ERROR_PARTIAL_TRANSFER", - "PROCESS_ABORT_DIRTY", - "PROCESS_ABORT_NO_DATA_TRANSFER", - "PROCESS_ABORT_PARTIAL_TRANSFER", - "TRANSACTION_ERROR", - "PROGRESS_REPORT" - }; - - if (req_status > I2O_REPLY_STATUS_PROGRESS_REPORT) - printk("RequestStatus = %0#2x", req_status); - else - printk("%s", REPLY_STATUS[req_status]); -} - -/* - * Used for error reporting/debugging purposes. - * Following detailed status are valid for executive class, - * utility class, DDM class and for transaction error replies. - */ -static void i2o_report_common_dsc(u16 detailed_status) -{ - static char *COMMON_DSC[] = { - "SUCCESS", - "0x01", // not used - "BAD_KEY", - "TCL_ERROR", - "REPLY_BUFFER_FULL", - "NO_SUCH_PAGE", - "INSUFFICIENT_RESOURCE_SOFT", - "INSUFFICIENT_RESOURCE_HARD", - "0x08", // not used - "CHAIN_BUFFER_TOO_LARGE", - "UNSUPPORTED_FUNCTION", - "DEVICE_LOCKED", - "DEVICE_RESET", - "INAPPROPRIATE_FUNCTION", - "INVALID_INITIATOR_ADDRESS", - "INVALID_MESSAGE_FLAGS", - "INVALID_OFFSET", - "INVALID_PARAMETER", - "INVALID_REQUEST", - "INVALID_TARGET_ADDRESS", - "MESSAGE_TOO_LARGE", - "MESSAGE_TOO_SMALL", - "MISSING_PARAMETER", - "TIMEOUT", - "UNKNOWN_ERROR", - "UNKNOWN_FUNCTION", - "UNSUPPORTED_VERSION", - "DEVICE_BUSY", - "DEVICE_NOT_AVAILABLE" - }; - - if (detailed_status > I2O_DSC_DEVICE_NOT_AVAILABLE) - printk(" / DetailedStatus = %0#4x.\n", detailed_status); - else - printk(" / %s.\n", COMMON_DSC[detailed_status]); -} - -/* - * Used for error reporting/debugging purposes - */ -static void i2o_report_lan_dsc(u16 detailed_status) -{ - static char *LAN_DSC[] = { // Lan detailed status code strings - "SUCCESS", - "DEVICE_FAILURE", - "DESTINATION_NOT_FOUND", - "TRANSMIT_ERROR", - "TRANSMIT_ABORTED", - "RECEIVE_ERROR", - "RECEIVE_ABORTED", - "DMA_ERROR", - "BAD_PACKET_DETECTED", - "OUT_OF_MEMORY", - "BUCKET_OVERRUN", - "IOP_INTERNAL_ERROR", - "CANCELED", - "INVALID_TRANSACTION_CONTEXT", - "DEST_ADDRESS_DETECTED", - "DEST_ADDRESS_OMITTED", - "PARTIAL_PACKET_RETURNED", - "TEMP_SUSPENDED_STATE", // last Lan detailed status code - "INVALID_REQUEST" // general detailed status code - }; - - if (detailed_status > I2O_DSC_INVALID_REQUEST) - printk(" / %0#4x.\n", detailed_status); - else - printk(" / %s.\n", LAN_DSC[detailed_status]); -} - -/* - * Used for error reporting/debugging purposes - */ -static void i2o_report_util_cmd(u8 cmd) -{ - switch (cmd) { - case I2O_CMD_UTIL_NOP: - printk("UTIL_NOP, "); - break; - case I2O_CMD_UTIL_ABORT: - printk("UTIL_ABORT, "); - break; - case I2O_CMD_UTIL_CLAIM: - printk("UTIL_CLAIM, "); - break; - case I2O_CMD_UTIL_RELEASE: - printk("UTIL_CLAIM_RELEASE, "); - break; - case I2O_CMD_UTIL_CONFIG_DIALOG: - printk("UTIL_CONFIG_DIALOG, "); - break; - case I2O_CMD_UTIL_DEVICE_RESERVE: - printk("UTIL_DEVICE_RESERVE, "); - break; - case I2O_CMD_UTIL_DEVICE_RELEASE: - printk("UTIL_DEVICE_RELEASE, "); - break; - case I2O_CMD_UTIL_EVT_ACK: - printk("UTIL_EVENT_ACKNOWLEDGE, "); - break; - case I2O_CMD_UTIL_EVT_REGISTER: - printk("UTIL_EVENT_REGISTER, "); - break; - case I2O_CMD_UTIL_LOCK: - printk("UTIL_LOCK, "); - break; - case I2O_CMD_UTIL_LOCK_RELEASE: - printk("UTIL_LOCK_RELEASE, "); - break; - case I2O_CMD_UTIL_PARAMS_GET: - printk("UTIL_PARAMS_GET, "); - break; - case I2O_CMD_UTIL_PARAMS_SET: - printk("UTIL_PARAMS_SET, "); - break; - case I2O_CMD_UTIL_REPLY_FAULT_NOTIFY: - printk("UTIL_REPLY_FAULT_NOTIFY, "); - break; - default: - printk("Cmd = %0#2x, ",cmd); - } -} - -/* - * Used for error reporting/debugging purposes - */ -static void i2o_report_exec_cmd(u8 cmd) -{ - switch (cmd) { - case I2O_CMD_ADAPTER_ASSIGN: - printk("EXEC_ADAPTER_ASSIGN, "); - break; - case I2O_CMD_ADAPTER_READ: - printk("EXEC_ADAPTER_READ, "); - break; - case I2O_CMD_ADAPTER_RELEASE: - printk("EXEC_ADAPTER_RELEASE, "); - break; - case I2O_CMD_BIOS_INFO_SET: - printk("EXEC_BIOS_INFO_SET, "); - break; - case I2O_CMD_BOOT_DEVICE_SET: - printk("EXEC_BOOT_DEVICE_SET, "); - break; - case I2O_CMD_CONFIG_VALIDATE: - printk("EXEC_CONFIG_VALIDATE, "); - break; - case I2O_CMD_CONN_SETUP: - printk("EXEC_CONN_SETUP, "); - break; - case I2O_CMD_DDM_DESTROY: - printk("EXEC_DDM_DESTROY, "); - break; - case I2O_CMD_DDM_ENABLE: - printk("EXEC_DDM_ENABLE, "); - break; - case I2O_CMD_DDM_QUIESCE: - printk("EXEC_DDM_QUIESCE, "); - break; - case I2O_CMD_DDM_RESET: - printk("EXEC_DDM_RESET, "); - break; - case I2O_CMD_DDM_SUSPEND: - printk("EXEC_DDM_SUSPEND, "); - break; - case I2O_CMD_DEVICE_ASSIGN: - printk("EXEC_DEVICE_ASSIGN, "); - break; - case I2O_CMD_DEVICE_RELEASE: - printk("EXEC_DEVICE_RELEASE, "); - break; - case I2O_CMD_HRT_GET: - printk("EXEC_HRT_GET, "); - break; - case I2O_CMD_ADAPTER_CLEAR: - printk("EXEC_IOP_CLEAR, "); - break; - case I2O_CMD_ADAPTER_CONNECT: - printk("EXEC_IOP_CONNECT, "); - break; - case I2O_CMD_ADAPTER_RESET: - printk("EXEC_IOP_RESET, "); - break; - case I2O_CMD_LCT_NOTIFY: - printk("EXEC_LCT_NOTIFY, "); - break; - case I2O_CMD_OUTBOUND_INIT: - printk("EXEC_OUTBOUND_INIT, "); - break; - case I2O_CMD_PATH_ENABLE: - printk("EXEC_PATH_ENABLE, "); - break; - case I2O_CMD_PATH_QUIESCE: - printk("EXEC_PATH_QUIESCE, "); - break; - case I2O_CMD_PATH_RESET: - printk("EXEC_PATH_RESET, "); - break; - case I2O_CMD_STATIC_MF_CREATE: - printk("EXEC_STATIC_MF_CREATE, "); - break; - case I2O_CMD_STATIC_MF_RELEASE: - printk("EXEC_STATIC_MF_RELEASE, "); - break; - case I2O_CMD_STATUS_GET: - printk("EXEC_STATUS_GET, "); - break; - case I2O_CMD_SW_DOWNLOAD: - printk("EXEC_SW_DOWNLOAD, "); - break; - case I2O_CMD_SW_UPLOAD: - printk("EXEC_SW_UPLOAD, "); - break; - case I2O_CMD_SW_REMOVE: - printk("EXEC_SW_REMOVE, "); - break; - case I2O_CMD_SYS_ENABLE: - printk("EXEC_SYS_ENABLE, "); - break; - case I2O_CMD_SYS_MODIFY: - printk("EXEC_SYS_MODIFY, "); - break; - case I2O_CMD_SYS_QUIESCE: - printk("EXEC_SYS_QUIESCE, "); - break; - case I2O_CMD_SYS_TAB_SET: - printk("EXEC_SYS_TAB_SET, "); - break; - default: - printk("Cmd = %#02x, ",cmd); - } -} - -/* - * Used for error reporting/debugging purposes - */ -static void i2o_report_lan_cmd(u8 cmd) -{ - switch (cmd) { - case LAN_PACKET_SEND: - printk("LAN_PACKET_SEND, "); - break; - case LAN_SDU_SEND: - printk("LAN_SDU_SEND, "); - break; - case LAN_RECEIVE_POST: - printk("LAN_RECEIVE_POST, "); - break; - case LAN_RESET: - printk("LAN_RESET, "); - break; - case LAN_SUSPEND: - printk("LAN_SUSPEND, "); - break; - default: - printk("Cmd = %0#2x, ",cmd); - } -} - -/* - * Used for error reporting/debugging purposes. - * Report Cmd name, Request status, Detailed Status. - */ -void i2o_report_status(const char *severity, const char *str, u32 *msg) -{ - u8 cmd = (msg[1]>>24)&0xFF; - u8 req_status = (msg[4]>>24)&0xFF; - u16 detailed_status = msg[4]&0xFFFF; - struct i2o_handler *h = i2o_handlers[msg[2] & (MAX_I2O_MODULES-1)]; - - printk("%s%s: ", severity, str); - - if (cmd < 0x1F) // Utility cmd - i2o_report_util_cmd(cmd); - - else if (cmd >= 0xA0 && cmd <= 0xEF) // Executive cmd - i2o_report_exec_cmd(cmd); - - else if (h->class == I2O_CLASS_LAN && cmd >= 0x30 && cmd <= 0x3F) - i2o_report_lan_cmd(cmd); // LAN cmd - else - printk("Cmd = %0#2x, ", cmd); // Other cmds - - if (msg[0] & MSG_FAIL) { - i2o_report_fail_status(req_status, msg); - return; - } - - i2o_report_common_status(req_status); - - if (cmd < 0x1F || (cmd >= 0xA0 && cmd <= 0xEF)) - i2o_report_common_dsc(detailed_status); - else if (h->class == I2O_CLASS_LAN && cmd >= 0x30 && cmd <= 0x3F) - i2o_report_lan_dsc(detailed_status); - else - printk(" / DetailedStatus = %0#4x.\n", detailed_status); -} - -/* Used to dump a message to syslog during debugging */ -void i2o_dump_message(u32 *msg) -{ -#ifdef DRIVERDEBUG - int i; - printk(KERN_INFO "Dumping I2O message size %d @ %p\n", - msg[0]>>16&0xffff, msg); - for(i = 0; i < ((msg[0]>>16)&0xffff); i++) - printk(KERN_INFO " msg[%d] = %0#10x\n", i, msg[i]); -#endif -} - -/* - * I2O reboot/shutdown notification. - * - * - Call each OSM's reboot notifier (if one exists) - * - Quiesce each IOP in the system - * - * Each IOP has to be quiesced before we can ensure that the system - * can be properly shutdown as a transaction that has already been - * acknowledged still needs to be placed in permanent store on the IOP. - * The SysQuiesce causes the IOP to force all HDMs to complete their - * transactions before returning, so only at that point is it safe - * - */ -static int i2o_reboot_event(struct notifier_block *n, unsigned long code, void -*p) -{ - int i = 0; - struct i2o_controller *c = NULL; - - if(code != SYS_RESTART && code != SYS_HALT && code != SYS_POWER_OFF) - return NOTIFY_DONE; - - printk(KERN_INFO "Shutting down I2O system.\n"); - printk(KERN_INFO - " This could take a few minutes if there are many devices attached\n"); - - for(i = 0; i < MAX_I2O_MODULES; i++) - { - if(i2o_handlers[i] && i2o_handlers[i]->reboot_notify) - i2o_handlers[i]->reboot_notify(); - } - - for(c = i2o_controller_chain; c; c = c->next) - { - if(i2o_quiesce_controller(c)) - { - printk(KERN_WARNING "i2o: Could not quiesce %s." " - Verify setup on next system power up.\n", c->name); - } - } - - printk(KERN_INFO "I2O system down.\n"); - return NOTIFY_DONE; -} - - -#ifdef MODULE - -EXPORT_SYMBOL(i2o_controller_chain); -EXPORT_SYMBOL(i2o_num_controllers); -EXPORT_SYMBOL(i2o_find_controller); -EXPORT_SYMBOL(i2o_unlock_controller); -EXPORT_SYMBOL(i2o_status_get); - -EXPORT_SYMBOL(i2o_install_handler); -EXPORT_SYMBOL(i2o_remove_handler); - -EXPORT_SYMBOL(i2o_claim_device); -EXPORT_SYMBOL(i2o_release_device); -EXPORT_SYMBOL(i2o_device_notify_on); -EXPORT_SYMBOL(i2o_device_notify_off); - -EXPORT_SYMBOL(i2o_post_this); -EXPORT_SYMBOL(i2o_post_wait); - -EXPORT_SYMBOL(i2o_query_scalar); -EXPORT_SYMBOL(i2o_set_scalar); -EXPORT_SYMBOL(i2o_query_table); -EXPORT_SYMBOL(i2o_clear_table); -EXPORT_SYMBOL(i2o_row_add_table); -EXPORT_SYMBOL(i2o_issue_params); - -EXPORT_SYMBOL(i2o_event_register); -EXPORT_SYMBOL(i2o_event_ack); - -EXPORT_SYMBOL(i2o_report_status); -EXPORT_SYMBOL(i2o_dump_message); - -EXPORT_SYMBOL(i2o_get_class_name); - -MODULE_AUTHOR("Red Hat Software"); -MODULE_DESCRIPTION("I2O Core"); - - -int init_module(void) -{ - printk(KERN_INFO "I2O Core - (C) Copyright 1999 Red Hat Software\n"); - if (i2o_install_handler(&i2o_core_handler) < 0) - { - printk(KERN_ERR - "i2o_core: Unable to install core handler.\nI2O stack not loaded!"); - return 0; - } - - core_context = i2o_core_handler.context; - - /* - * Attach core to I2O PCI transport (and others as they are developed) - */ -#ifdef CONFIG_I2O_PCI_MODULE - if(i2o_pci_core_attach(&i2o_core_functions) < 0) - printk(KERN_INFO "i2o: No PCI I2O controllers found\n"); -#endif - - /* - * Initialize event handling thread - */ - init_MUTEX_LOCKED(&evt_sem); - evt_pid = kernel_thread(i2o_core_evt, &evt_reply, CLONE_SIGHAND); - if(evt_pid < 0) - { - printk(KERN_ERR "I2O: Could not create event handler kernel thread\n"); - i2o_remove_handler(&i2o_core_handler); - return 0; - } - else - printk(KERN_INFO "I2O: Event thread created as pid %d\n", evt_pid); - - if(i2o_num_controllers) - i2o_sys_init(); - - register_reboot_notifier(&i2o_reboot_notifier); - - return 0; -} - -void cleanup_module(void) -{ - int stat; - - unregister_reboot_notifier(&i2o_reboot_notifier); - - if(i2o_num_controllers) - i2o_sys_shutdown(); - - /* - * If this is shutdown time, the thread has already been killed - */ - if(evt_running) { - stat = kill_proc(evt_pid, SIGTERM, 1); - if(!stat) { - int count = 10 * 100; - while(evt_running && count--) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - } - - if(!count) - printk(KERN_ERR "i2o: Event thread still running!\n"); - } - } - -#ifdef CONFIG_I2O_PCI_MODULE - i2o_pci_core_detach(); -#endif - - i2o_remove_handler(&i2o_core_handler); - - unregister_reboot_notifier(&i2o_reboot_notifier); -} - -#else - -extern int i2o_block_init(void); -extern int i2o_config_init(void); -extern int i2o_lan_init(void); -extern int i2o_pci_init(void); -extern int i2o_proc_init(void); -extern int i2o_scsi_init(void); - -int __init i2o_init(void) -{ - printk(KERN_INFO "Loading I2O Core - (c) Copyright 1999 Red Hat Software\n"); - - if (i2o_install_handler(&i2o_core_handler) < 0) - { - printk(KERN_ERR - "i2o_core: Unable to install core handler.\nI2O stack not loaded!"); - return 0; - } - - core_context = i2o_core_handler.context; - - /* - * Initialize event handling thread - * We may not find any controllers, but still want this as - * down the road we may have hot pluggable controllers that - * need to be dealt with. - */ - init_MUTEX_LOCKED(&evt_sem); - if((evt_pid = kernel_thread(i2o_core_evt, &evt_reply, CLONE_SIGHAND)) < 0) - { - printk(KERN_ERR "I2O: Could not create event handler kernel thread\n"); - i2o_remove_handler(&i2o_core_handler); - return 0; - } - - -#ifdef CONFIG_I2O_PCI - i2o_pci_init(); -#endif - - if(i2o_num_controllers) - i2o_sys_init(); - - register_reboot_notifier(&i2o_reboot_notifier); - - i2o_config_init(); -#ifdef CONFIG_I2O_BLOCK - i2o_block_init(); -#endif -#ifdef CONFIG_I2O_LAN - i2o_lan_init(); -#endif -#ifdef CONFIG_I2O_PROC - i2o_proc_init(); -#endif - return 0; -} - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/i2o/i2o_lan.c linux.ac/drivers/i2o/i2o_lan.c --- linux.vanilla/drivers/i2o/i2o_lan.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/i2o/i2o_lan.c Thu Jan 1 01:00:00 1970 @@ -1,1575 +0,0 @@ -/* - * drivers/i2o/i2o_lan.c - * - * I2O LAN CLASS OSM May 26th 2000 - * - * (C) Copyright 1999, 2000 University of Helsinki, - * Department of Computer Science - * - * This code is still under development / test. - * - * 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. - * - * Authors: Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI> - * Fixes: Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI> - * Taneli Vähäkangas <Taneli.Vahakangas@cs.Helsinki.FI> - * Deepak Saxena <deepak@plexity.net> - * - * Tested: in FDDI environment (using SysKonnect's DDM) - * in Gigabit Eth environment (using SysKonnect's DDM) - * in Fast Ethernet environment (using Intel 82558 DDM) - * - * TODO: tests for other LAN classes (Token Ring, Fibre Channel) - */ - -#include <linux/config.h> -#include <linux/module.h> - -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/fddidevice.h> -#include <linux/trdevice.h> -#include <linux/fcdevice.h> - -#include <linux/skbuff.h> -#include <linux/if_arp.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/tqueue.h> -#include <asm/io.h> - -#include <linux/errno.h> - -#include <linux/i2o.h> -#include "i2o_lan.h" - -//#define DRIVERDEBUG -#ifdef DRIVERDEBUG -#define dprintk(s, args...) printk(s, ## args) -#else -#define dprintk(s, args...) -#endif - -/* The following module parameters are used as default values - * for per interface values located in the net_device private area. - * Private values are changed via /proc filesystem. - */ -static u32 max_buckets_out = I2O_LAN_MAX_BUCKETS_OUT; -static u32 bucket_thresh = I2O_LAN_BUCKET_THRESH; -static u32 rx_copybreak = I2O_LAN_RX_COPYBREAK; -static u8 tx_batch_mode = I2O_LAN_TX_BATCH_MODE; -static u32 i2o_event_mask = I2O_LAN_EVENT_MASK; - -#define MAX_LAN_CARDS 16 -static struct net_device *i2o_landevs[MAX_LAN_CARDS+1]; -static int unit = -1; /* device unit number */ - -static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m); -static void i2o_lan_send_post_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m); -static int i2o_lan_receive_post(struct net_device *dev); -static void i2o_lan_receive_post_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m); -static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg); - -static int i2o_lan_reset(struct net_device *dev); -static void i2o_lan_handle_event(struct net_device *dev, u32 *msg); - -/* Structures to register handlers for the incoming replies. */ - -static struct i2o_handler i2o_lan_send_handler = { - i2o_lan_send_post_reply, // For send replies - NULL, - NULL, - NULL, - "I2O LAN OSM send", - -1, - I2O_CLASS_LAN -}; -static int lan_send_context; - -static struct i2o_handler i2o_lan_receive_handler = { - i2o_lan_receive_post_reply, // For receive replies - NULL, - NULL, - NULL, - "I2O LAN OSM receive", - -1, - I2O_CLASS_LAN -}; -static int lan_receive_context; - -static struct i2o_handler i2o_lan_handler = { - i2o_lan_reply, // For other replies - NULL, - NULL, - NULL, - "I2O LAN OSM", - -1, - I2O_CLASS_LAN -}; -static int lan_context; - -DECLARE_TASK_QUEUE(i2o_post_buckets_task); -struct tq_struct run_i2o_post_buckets_task = { - routine: (void (*)(void *)) run_task_queue, - data: (void *) 0 -}; - -/* Functions to handle message failures and transaction errors: -==============================================================*/ - -/* - * i2o_lan_handle_failure(): Fail bit has been set since IOP's message - * layer cannot deliver the request to the target, or the target cannot - * process the request. - */ -static void i2o_lan_handle_failure(struct net_device *dev, u32 *msg) -{ - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; - struct i2o_controller *iop = i2o_dev->controller; - - u32 *preserved_msg = (u32*)(iop->mem_offset + msg[7]); - u32 *sgl_elem = &preserved_msg[4]; - struct sk_buff *skb = NULL; - u8 le_flag; - - i2o_report_status(KERN_INFO, dev->name, msg); - - /* If PacketSend failed, free sk_buffs reserved by upper layers */ - - if (msg[1] >> 24 == LAN_PACKET_SEND) { - do { - skb = (struct sk_buff *)(sgl_elem[1]); - dev_kfree_skb_irq(skb); - - atomic_dec(&priv->tx_out); - - le_flag = *sgl_elem >> 31; - sgl_elem +=3; - } while (le_flag == 0); /* Last element flag not set */ - - if (netif_queue_stopped(dev)) - netif_wake_queue(dev); - } - - /* If ReceivePost failed, free sk_buffs we have reserved */ - - if (msg[1] >> 24 == LAN_RECEIVE_POST) { - do { - skb = (struct sk_buff *)(sgl_elem[1]); - dev_kfree_skb_irq(skb); - - atomic_dec(&priv->buckets_out); - - le_flag = *sgl_elem >> 31; - sgl_elem +=3; - } while (le_flag == 0); /* Last element flag not set */ - } - - /* Release the preserved msg frame by resubmitting it as a NOP */ - - preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0; - preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0; - preserved_msg[2] = 0; - i2o_post_message(iop, msg[7]); -} -/* - * i2o_lan_handle_transaction_error(): IOP or DDM has rejected the request - * for general cause (format error, bad function code, insufficient resources, - * etc.). We get one transaction_error for each failed transaction. - */ -static void i2o_lan_handle_transaction_error(struct net_device *dev, u32 *msg) -{ - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct sk_buff *skb; - - i2o_report_status(KERN_INFO, dev->name, msg); - - /* If PacketSend was rejected, free sk_buff reserved by upper layers */ - - if (msg[1] >> 24 == LAN_PACKET_SEND) { - skb = (struct sk_buff *)(msg[3]); // TransactionContext - dev_kfree_skb_irq(skb); - atomic_dec(&priv->tx_out); - - if (netif_queue_stopped(dev)) - netif_wake_queue(dev); - } - - /* If ReceivePost was rejected, free sk_buff we have reserved */ - - if (msg[1] >> 24 == LAN_RECEIVE_POST) { - skb = (struct sk_buff *)(msg[3]); - dev_kfree_skb_irq(skb); - atomic_dec(&priv->buckets_out); - } -} - -/* - * i2o_lan_handle_status(): Common parts of handling a not succeeded request - * (status != SUCCESS). - */ -static int i2o_lan_handle_status(struct net_device *dev, u32 *msg) -{ - /* Fail bit set? */ - - if (msg[0] & MSG_FAIL) { - i2o_lan_handle_failure(dev, msg); - return -1; - } - - /* Message rejected for general cause? */ - - if ((msg[4]>>24) == I2O_REPLY_STATUS_TRANSACTION_ERROR) { - i2o_lan_handle_transaction_error(dev, msg); - return -1; - } - - /* Else have to handle it in the callback function */ - - return 0; -} - -/* Callback functions called from the interrupt routine: -=======================================================*/ - -/* - * i2o_lan_send_post_reply(): Callback function to handle PostSend replies. - */ -static void i2o_lan_send_post_reply(struct i2o_handler *h, - struct i2o_controller *iop, struct i2o_message *m) -{ - u32 *msg = (u32 *)m; - u8 unit = (u8)(msg[2]>>16); // InitiatorContext - struct net_device *dev = i2o_landevs[unit]; - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - u8 trl_count = msg[3] & 0x000000FF; - - if ((msg[4] >> 24) != I2O_REPLY_STATUS_SUCCESS) { - if (i2o_lan_handle_status(dev, msg)) - return; - } - -#ifdef DRIVERDEBUG - i2o_report_status(KERN_INFO, dev->name, msg); -#endif - - /* DDM has handled transmit request(s), free sk_buffs. - * We get similar single transaction reply also in error cases - * (except if msg failure or transaction error). - */ - while (trl_count) { - dev_kfree_skb_irq((struct sk_buff *)msg[4 + trl_count]); - dprintk(KERN_INFO "%s: tx skb freed (trl_count=%d).\n", - dev->name, trl_count); - atomic_dec(&priv->tx_out); - trl_count--; - } - - /* If priv->tx_out had reached tx_max_out, the queue was stopped */ - - if (netif_queue_stopped(dev)) - netif_wake_queue(dev); -} - -/* - * i2o_lan_receive_post_reply(): Callback function to process incoming packets. - */ -static void i2o_lan_receive_post_reply(struct i2o_handler *h, - struct i2o_controller *iop, struct i2o_message *m) -{ - u32 *msg = (u32 *)m; - u8 unit = (u8)(msg[2]>>16); // InitiatorContext - struct net_device *dev = i2o_landevs[unit]; - - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_bucket_descriptor *bucket = (struct i2o_bucket_descriptor *)&msg[6]; - struct i2o_packet_info *packet; - u8 trl_count = msg[3] & 0x000000FF; - struct sk_buff *skb, *old_skb; - unsigned long flags = 0; - - if ((msg[4] >> 24) != I2O_REPLY_STATUS_SUCCESS) { - if (i2o_lan_handle_status(dev, msg)) - return; - - i2o_lan_release_buckets(dev, msg); - return; - } - -#ifdef DRIVERDEBUG - i2o_report_status(KERN_INFO, dev->name, msg); -#endif - - /* Else we are receiving incoming post. */ - - while (trl_count--) { - skb = (struct sk_buff *)bucket->context; - packet = (struct i2o_packet_info *)bucket->packet_info; - atomic_dec(&priv->buckets_out); - - /* Sanity checks: Any weird characteristics in bucket? */ - - if (packet->flags & 0x0f || ! packet->flags & 0x40) { - if (packet->flags & 0x01) - printk(KERN_WARNING "%s: packet with errors, error code=0x%02x.\n", - dev->name, packet->status & 0xff); - - /* The following shouldn't happen, unless parameters in - * LAN_OPERATION group are changed during the run time. - */ - if (packet->flags & 0x0c) - printk(KERN_DEBUG "%s: multi-bucket packets not supported!\n", - dev->name); - - if (! packet->flags & 0x40) - printk(KERN_DEBUG "%s: multiple packets in a bucket not supported!\n", - dev->name); - - dev_kfree_skb_irq(skb); - - bucket++; - continue; - } - - /* Copy short packet to a new skb */ - - if (packet->len < priv->rx_copybreak) { - old_skb = skb; - skb = (struct sk_buff *)dev_alloc_skb(packet->len+2); - if (skb == NULL) { - printk(KERN_ERR "%s: Can't allocate skb.\n", dev->name); - return; - } - skb_reserve(skb, 2); - memcpy(skb_put(skb, packet->len), old_skb->data, packet->len); - - spin_lock_irqsave(&priv->fbl_lock, flags); - if (priv->i2o_fbl_tail < I2O_LAN_MAX_BUCKETS_OUT) - priv->i2o_fbl[++priv->i2o_fbl_tail] = old_skb; - else - dev_kfree_skb_irq(old_skb); - - spin_unlock_irqrestore(&priv->fbl_lock, flags); - } else - skb_put(skb, packet->len); - - /* Deliver to upper layers */ - - skb->dev = dev; - skb->protocol = priv->type_trans(skb, dev); - netif_rx(skb); - - dev->last_rx = jiffies; - - dprintk(KERN_INFO "%s: Incoming packet (%d bytes) delivered " - "to upper level.\n", dev->name, packet->len); - - bucket++; // to next Packet Descriptor Block - } - -#ifdef DRIVERDEBUG - if (msg[5] == 0) - printk(KERN_INFO "%s: DDM out of buckets (priv->count = %d)!\n", - dev->name, atomic_read(&priv->buckets_out)); -#endif - - /* If DDM has already consumed bucket_thresh buckets, post new ones */ - - if (atomic_read(&priv->buckets_out) <= priv->max_buckets_out - priv->bucket_thresh) { - run_i2o_post_buckets_task.data = (void *)dev; - queue_task(&run_i2o_post_buckets_task, &tq_immediate); - mark_bh(IMMEDIATE_BH); - } - - return; -} - -/* - * i2o_lan_reply(): Callback function to handle other incoming messages - * except SendPost and ReceivePost. - */ -static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, - struct i2o_message *m) -{ - u32 *msg = (u32 *)m; - u8 unit = (u8)(msg[2]>>16); // InitiatorContext - struct net_device *dev = i2o_landevs[unit]; - - if ((msg[4] >> 24) != I2O_REPLY_STATUS_SUCCESS) { - if (i2o_lan_handle_status(dev, msg)) - return; - - /* In other error cases just report and continue */ - - i2o_report_status(KERN_INFO, dev->name, msg); - } - -#ifdef DRIVERDEBUG - i2o_report_status(KERN_INFO, dev->name, msg); -#endif - switch (msg[1] >> 24) { - case LAN_RESET: - case LAN_SUSPEND: - /* default reply without payload */ - break; - - case I2O_CMD_UTIL_EVT_REGISTER: - case I2O_CMD_UTIL_EVT_ACK: - i2o_lan_handle_event(dev, msg); - break; - - case I2O_CMD_UTIL_PARAMS_SET: - /* default reply, results in ReplyPayload (not examined) */ - switch (msg[3] >> 16) { - case 1: dprintk(KERN_INFO "%s: Reply to set MAC filter mask.\n", - dev->name); - break; - case 2: dprintk(KERN_INFO "%s: Reply to set MAC table.\n", - dev->name); - break; - default: printk(KERN_WARNING "%s: Bad group 0x%04X\n", - dev->name,msg[3] >> 16); - } - break; - - default: - printk(KERN_ERR "%s: No handler for the reply.\n", - dev->name); - i2o_report_status(KERN_INFO, dev->name, msg); - } -} - -/* Functions used by the above callback functions: -=================================================*/ -/* - * i2o_lan_release_buckets(): Free unused buckets (sk_buffs). - */ -static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg) -{ - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - u8 trl_elem_size = (u8)(msg[3]>>8 & 0x000000FF); - u8 trl_count = (u8)(msg[3] & 0x000000FF); - u32 *pskb = &msg[6]; - - while (trl_count--) { - dprintk(KERN_DEBUG "%s: Releasing unused rx skb %p (trl_count=%d).\n", - dev->name, (struct sk_buff*)(*pskb),trl_count+1); - dev_kfree_skb_irq((struct sk_buff *)(*pskb)); - pskb += 1 + trl_elem_size; - atomic_dec(&priv->buckets_out); - } -} - -/* - * i2o_lan_event_reply(): Handle events. - */ -static void i2o_lan_handle_event(struct net_device *dev, u32 *msg) -{ - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; - struct i2o_controller *iop = i2o_dev->controller; - u32 max_evt_data_size =iop->status_block->inbound_frame_size-5; - struct i2o_reply { - u32 header[4]; - u32 evt_indicator; - u32 data[max_evt_data_size]; - } *evt = (struct i2o_reply *)msg; - int evt_data_len = ((msg[0]>>16) - 5) * 4; /* real size*/ - - printk(KERN_INFO "%s: I2O event - ", dev->name); - - if (msg[1]>>24 == I2O_CMD_UTIL_EVT_ACK) { - printk("Event acknowledgement reply.\n"); - return; - } - - /* Else evt->function == I2O_CMD_UTIL_EVT_REGISTER) */ - - switch (evt->evt_indicator) { - case I2O_EVT_IND_STATE_CHANGE: { - struct state_data { - u16 status; - u8 state; - u8 data; - } *evt_data = (struct state_data *)(evt->data[0]); - - printk("State chance 0x%08x.\n", evt->data[0]); - - /* If the DDM is in error state, recovery may be - * possible if status = Transmit or Receive Control - * Unit Inoperable. - */ - if (evt_data->state==0x05 && evt_data->status==0x0003) - i2o_lan_reset(dev); - break; - } - - case I2O_EVT_IND_FIELD_MODIFIED: { - u16 *work16 = (u16 *)evt->data; - printk("Group 0x%04x, field %d changed.\n", work16[0], work16[1]); - break; - } - - case I2O_EVT_IND_VENDOR_EVT: { - int i; - printk("Vendor event:\n"); - for (i = 0; i < evt_data_len / 4; i++) - printk(" 0x%08x\n", evt->data[i]); - break; - } - - case I2O_EVT_IND_DEVICE_RESET: - /* Spec 2.0 p. 6-121: - * The event of _DEVICE_RESET should also be responded - */ - printk("Device reset.\n"); - if (i2o_event_ack(iop, msg) < 0) - printk("%s: Event Acknowledge timeout.\n", dev->name); - break; - -#if 0 - case I2O_EVT_IND_EVT_MASK_MODIFIED: - printk("Event mask modified, 0x%08x.\n", evt->data[0]); - break; - - case I2O_EVT_IND_GENERAL_WARNING: - printk("General warning 0x%04x.\n", evt->data[0]); - break; - - case I2O_EVT_IND_CONFIGURATION_FLAG: - printk("Configuration requested.\n"); - break; - - case I2O_EVT_IND_CAPABILITY_CHANGE: - printk("Capability change 0x%04x.\n", evt->data[0]); - break; - - case I2O_EVT_IND_DEVICE_STATE: - printk("Device state changed 0x%08x.\n", evt->data[0]); - break; -#endif - case I2O_LAN_EVT_LINK_DOWN: - netif_carrier_off(dev); - printk("Link to the physical device is lost.\n"); - break; - - case I2O_LAN_EVT_LINK_UP: - netif_carrier_on(dev); - printk("Link to the physical device is (re)established.\n"); - break; - - case I2O_LAN_EVT_MEDIA_CHANGE: - printk("Media change.\n"); - break; - default: - printk("0x%08x. No handler.\n", evt->evt_indicator); - } -} - -/* - * i2o_lan_receive_post(): Post buckets to receive packets. - */ -static int i2o_lan_receive_post(struct net_device *dev) -{ - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; - struct i2o_controller *iop = i2o_dev->controller; - struct sk_buff *skb; - u32 m, *msg; - u32 bucket_len = (dev->mtu + dev->hard_header_len); - u32 total = priv->max_buckets_out - atomic_read(&priv->buckets_out); - u32 bucket_count; - u32 *sgl_elem; - unsigned long flags; - - /* Send (total/bucket_count) separate I2O requests */ - - while (total) { - m = I2O_POST_READ32(iop); - if (m == 0xFFFFFFFF) - return -ETIMEDOUT; - msg = (u32 *)(iop->mem_offset + m); - - bucket_count = (total >= priv->sgl_max) ? priv->sgl_max : total; - total -= bucket_count; - atomic_add(bucket_count, &priv->buckets_out); - - dprintk(KERN_INFO "%s: Sending %d buckets (size %d) to LAN DDM.\n", - dev->name, bucket_count, bucket_len); - - /* Fill in the header */ - - __raw_writel(I2O_MESSAGE_SIZE(4 + 3 * bucket_count) | SGL_OFFSET_4, msg); - __raw_writel(LAN_RECEIVE_POST<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid, msg+1); - __raw_writel(priv->unit << 16 | lan_receive_context, msg+2); - __raw_writel(bucket_count, msg+3); - sgl_elem = &msg[4]; - - /* Fill in the payload - contains bucket_count SGL elements */ - - while (bucket_count--) { - spin_lock_irqsave(&priv->fbl_lock, flags); - if (priv->i2o_fbl_tail >= 0) - skb = priv->i2o_fbl[priv->i2o_fbl_tail--]; - else { - skb = dev_alloc_skb(bucket_len + 2); - if (skb == NULL) { - spin_unlock_irqrestore(&priv->fbl_lock, flags); - return -ENOMEM; - } - skb_reserve(skb, 2); - } - spin_unlock_irqrestore(&priv->fbl_lock, flags); - - __raw_writel(0x51000000 | bucket_len, sgl_elem); - __raw_writel((u32)skb, sgl_elem+1); - __raw_writel(virt_to_bus(skb->data), sgl_elem+2); - sgl_elem += 3; - } - - /* set LE flag and post */ - __raw_writel(__raw_readl(sgl_elem-3) | 0x80000000, (sgl_elem-3)); - i2o_post_message(iop, m); - } - - return 0; -} - -/* Functions called from the network stack, and functions called by them: -========================================================================*/ - -/* - * i2o_lan_reset(): Reset the LAN adapter into the operational state and - * restore it to full operation. - */ -static int i2o_lan_reset(struct net_device *dev) -{ - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; - struct i2o_controller *iop = i2o_dev->controller; - u32 msg[5]; - - dprintk(KERN_INFO "%s: LAN RESET MESSAGE.\n", dev->name); - msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; - msg[1] = LAN_RESET<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid; - msg[2] = priv->unit << 16 | lan_context; // InitiatorContext - msg[3] = 0; // TransactionContext - msg[4] = 0; // Keep posted buckets - - if (i2o_post_this(iop, msg, sizeof(msg)) < 0) - return -ETIMEDOUT; - - return 0; -} - -/* - * i2o_lan_suspend(): Put LAN adapter into a safe, non-active state. - * IOP replies to any LAN class message with status error_no_data_transfer - * / suspended. - */ -static int i2o_lan_suspend(struct net_device *dev) -{ - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; - struct i2o_controller *iop = i2o_dev->controller; - u32 msg[5]; - - dprintk(KERN_INFO "%s: LAN SUSPEND MESSAGE.\n", dev->name); - msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; - msg[1] = LAN_SUSPEND<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid; - msg[2] = priv->unit << 16 | lan_context; // InitiatorContext - msg[3] = 0; // TransactionContext - msg[4] = 1 << 16; // return posted buckets - - if (i2o_post_this(iop, msg, sizeof(msg)) < 0) - return -ETIMEDOUT; - - return 0; -} - -/* - * i2o_set_ddm_parameters: - * These settings are done to ensure proper initial values for DDM. - * They can be changed via proc file system or vai configuration utility. - */ -static void i2o_set_ddm_parameters(struct net_device *dev) -{ - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; - struct i2o_controller *iop = i2o_dev->controller; - u32 val; - - /* - * When PacketOrphanlimit is set to the maximum packet length, - * the packets will never be split into two separate buckets - */ - val = dev->mtu + dev->hard_header_len; - if (i2o_set_scalar(iop, i2o_dev->lct_data.tid, 0x0004, 2, &val, sizeof(val)) < 0) - printk(KERN_WARNING "%s: Unable to set PacketOrphanLimit.\n", - dev->name); - else - dprintk(KERN_INFO "%s: PacketOrphanLimit set to %d.\n", - dev->name, val); - - /* When RxMaxPacketsBucket = 1, DDM puts only one packet into bucket */ - - val = 1; - if (i2o_set_scalar(iop, i2o_dev->lct_data.tid, 0x0008, 4, &val, sizeof(val)) <0) - printk(KERN_WARNING "%s: Unable to set RxMaxPacketsBucket.\n", - dev->name); - else - dprintk(KERN_INFO "%s: RxMaxPacketsBucket set to %d.\n", - dev->name, val); - return; -} - -/* Functions called from the network stack: -==========================================*/ - -/* - * i2o_lan_open(): Open the device to send/receive packets via - * the network device. - */ -static int i2o_lan_open(struct net_device *dev) -{ - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; - struct i2o_controller *iop = i2o_dev->controller; - u32 mc_addr_group[64]; - - MOD_INC_USE_COUNT; - - if (i2o_claim_device(i2o_dev, &i2o_lan_handler)) { - printk(KERN_WARNING "%s: Unable to claim the I2O LAN device.\n", dev->name); - MOD_DEC_USE_COUNT; - return -EAGAIN; - } - dprintk(KERN_INFO "%s: I2O LAN device (tid=%d) claimed by LAN OSM.\n", - dev->name, i2o_dev->lct_data.tid); - - if (i2o_event_register(iop, i2o_dev->lct_data.tid, - priv->unit << 16 | lan_context, 0, priv->i2o_event_mask) < 0) - printk(KERN_WARNING "%s: Unable to set the event mask.\n", dev->name); - - i2o_lan_reset(dev); - - /* Get the max number of multicast addresses */ - - if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0001, -1, - &mc_addr_group, sizeof(mc_addr_group)) < 0 ) { - printk(KERN_WARNING "%s: Unable to query LAN_MAC_ADDRESS group.\n", dev->name); - MOD_DEC_USE_COUNT; - return -EAGAIN; - } - priv->max_size_mc_table = mc_addr_group[8]; - - /* Malloc space for free bucket list to resuse reveive post buckets */ - - priv->i2o_fbl = kmalloc(priv->max_buckets_out * sizeof(struct sk_buff *), - GFP_KERNEL); - if (priv->i2o_fbl == NULL) { - MOD_DEC_USE_COUNT; - return -ENOMEM; - } - priv->i2o_fbl_tail = -1; - priv->send_active = 0; - - i2o_set_ddm_parameters(dev); - i2o_lan_receive_post(dev); - - netif_start_queue(dev); - - return 0; -} - -/* - * i2o_lan_close(): End the transfering. - */ -static int i2o_lan_close(struct net_device *dev) -{ - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; - struct i2o_controller *iop = i2o_dev->controller; - int ret = 0; - - netif_stop_queue(dev); - i2o_lan_suspend(dev); - - if (i2o_event_register(iop, i2o_dev->lct_data.tid, - priv->unit << 16 | lan_context, 0, 0) < 0) - printk(KERN_WARNING "%s: Unable to clear the event mask.\n", - dev->name); - - while (priv->i2o_fbl_tail >= 0) - dev_kfree_skb(priv->i2o_fbl[priv->i2o_fbl_tail--]); - - kfree(priv->i2o_fbl); - - if (i2o_release_device(i2o_dev, &i2o_lan_handler)) { - printk(KERN_WARNING "%s: Unable to unclaim I2O LAN device " - "(tid=%d).\n", dev->name, i2o_dev->lct_data.tid); - ret = -EBUSY; - } - - MOD_DEC_USE_COUNT; - - return ret; -} - -/* - * i2o_lan_tx_timeout(): Tx timeout handler. - */ -static void i2o_lan_tx_timeout(struct net_device *dev) -{ - if (!netif_queue_stopped(dev)) - netif_start_queue(dev); -} - -/* - * i2o_lan_batch_send(): Send packets in batch. - * Both i2o_lan_sdu_send and i2o_lan_packet_send use this. - */ -static void i2o_lan_batch_send(struct net_device *dev) -{ - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_controller *iop = priv->i2o_dev->controller; - - spin_lock_irq(&priv->tx_lock); - if (priv->tx_count != 0) { - dev->trans_start = jiffies; - i2o_post_message(iop, priv->m); - dprintk(KERN_DEBUG "%s: %d packets sent.\n", dev->name, priv->tx_count); - priv->tx_count = 0; - } - priv->send_active = 0; - spin_unlock_irq(&priv->tx_lock); - MOD_DEC_USE_COUNT; -} - -#ifdef CONFIG_NET_FC -/* - * i2o_lan_sdu_send(): Send a packet, MAC header added by the DDM. - * Must be supported by Fibre Channel, optional for Ethernet/802.3, - * Token Ring, FDDI - */ -static int i2o_lan_sdu_send(struct sk_buff *skb, struct net_device *dev) -{ - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; - struct i2o_controller *iop = i2o_dev->controller; - int tickssofar = jiffies - dev->trans_start; - u32 m, *msg; - u32 *sgl_elem; - - spin_lock_irq(&priv->tx_lock); - - priv->tx_count++; - atomic_inc(&priv->tx_out); - - /* - * If tx_batch_mode = 0x00 forced to immediate mode - * If tx_batch_mode = 0x01 forced to batch mode - * If tx_batch_mode = 0x10 switch automatically, current mode immediate - * If tx_batch_mode = 0x11 switch automatically, current mode batch - * If gap between two packets is > 0 ticks, switch to immediate - */ - if (priv->tx_batch_mode >> 1) // switch automatically - priv->tx_batch_mode = tickssofar ? 0x02 : 0x03; - - if (priv->tx_count == 1) { - m = I2O_POST_READ32(iop); - if (m == 0xFFFFFFFF) { - spin_unlock_irq(&priv->tx_lock); - return 1; - } - msg = (u32 *)(iop->mem_offset + m); - priv->m = m; - - __raw_writel(NINE_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4, msg); - __raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid, msg+1); - __raw_writel(priv->unit << 16 | lan_send_context, msg+2); // InitiatorContext - __raw_writel(1 << 30 | 1 << 3, msg+3); // TransmitControlWord - - __raw_writel(0xD7000000 | skb->len, msg+4); // MAC hdr included - __raw_writel((u32)skb, msg+5); // TransactionContext - __raw_writel(virt_to_bus(skb->data), msg+6); - __raw_writel((u32)skb->mac.raw, msg+7); - __raw_writel((u32)skb->mac.raw+4, msg+8); - - if ((priv->tx_batch_mode & 0x01) && !priv->send_active) { - priv->send_active = 1; - MOD_INC_USE_COUNT; - if (schedule_task(&priv->i2o_batch_send_task) == 0) - MOD_DEC_USE_COUNT; - } - } else { /* Add new SGL element to the previous message frame */ - - msg = (u32 *)(iop->mem_offset + priv->m); - sgl_elem = &msg[priv->tx_count * 5 + 1]; - - __raw_writel(I2O_MESSAGE_SIZE((__raw_readl(msg)>>16) + 5) | 1<<12 | SGL_OFFSET_4, msg); - __raw_writel(__raw_readl(sgl_elem-5) & 0x7FFFFFFF, sgl_elem-5); /* clear LE flag */ - __raw_writel(0xD5000000 | skb->len, sgl_elem); - __raw_writel((u32)skb, sgl_elem+1); - __raw_writel(virt_to_bus(skb->data), sgl_elem+2); - __raw_writel((u32)(skb->mac.raw), sgl_elem+3); - __raw_writel((u32)(skb->mac.raw)+1, sgl_elem+4); - } - - /* If tx not in batch mode or frame is full, send immediatelly */ - - if (!(priv->tx_batch_mode & 0x01) || priv->tx_count == priv->sgl_max) { - dev->trans_start = jiffies; - i2o_post_message(iop, priv->m); - dprintk(KERN_DEBUG "%s: %d packets sent.\n", dev->name, priv->tx_count); - priv->tx_count = 0; - } - - /* If DDMs TxMaxPktOut reached, stop queueing layer to send more */ - - if (atomic_read(&priv->tx_out) >= priv->tx_max_out) - netif_stop_queue(dev); - - spin_unlock_irq(&priv->tx_lock); - return 0; -} -#endif CONFIG_NET_FC - -/* - * i2o_lan_packet_send(): Send a packet as is, including the MAC header. - * - * Must be supported by Ethernet/802.3, Token Ring, FDDI, optional for - * Fibre Channel - */ -static int i2o_lan_packet_send(struct sk_buff *skb, struct net_device *dev) -{ - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; - struct i2o_controller *iop = i2o_dev->controller; - int tickssofar = jiffies - dev->trans_start; - u32 m, *msg; - u32 *sgl_elem; - - spin_lock_irq(&priv->tx_lock); - - priv->tx_count++; - atomic_inc(&priv->tx_out); - - /* - * If tx_batch_mode = 0x00 forced to immediate mode - * If tx_batch_mode = 0x01 forced to batch mode - * If tx_batch_mode = 0x10 switch automatically, current mode immediate - * If tx_batch_mode = 0x11 switch automatically, current mode batch - * If gap between two packets is > 0 ticks, switch to immediate - */ - if (priv->tx_batch_mode >> 1) // switch automatically - priv->tx_batch_mode = tickssofar ? 0x02 : 0x03; - - if (priv->tx_count == 1) { - m = I2O_POST_READ32(iop); - if (m == 0xFFFFFFFF) { - spin_unlock_irq(&priv->tx_lock); - return 1; - } - msg = (u32 *)(iop->mem_offset + m); - priv->m = m; - - __raw_writel(SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4, msg); - __raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid, msg+1); - __raw_writel(priv->unit << 16 | lan_send_context, msg+2); // InitiatorContext - __raw_writel(1 << 30 | 1 << 3, msg+3); // TransmitControlWord - // bit 30: reply as soon as transmission attempt is complete - // bit 3: Supress CRC generation - __raw_writel(0xD5000000 | skb->len, msg+4); // MAC hdr included - __raw_writel((u32)skb, msg+5); // TransactionContext - __raw_writel(virt_to_bus(skb->data), msg+6); - - if ((priv->tx_batch_mode & 0x01) && !priv->send_active) { - priv->send_active = 1; - MOD_INC_USE_COUNT; - if (schedule_task(&priv->i2o_batch_send_task) == 0) - MOD_DEC_USE_COUNT; - } - } else { /* Add new SGL element to the previous message frame */ - - msg = (u32 *)(iop->mem_offset + priv->m); - sgl_elem = &msg[priv->tx_count * 3 + 1]; - - __raw_writel(I2O_MESSAGE_SIZE((__raw_readl(msg)>>16) + 3) | 1<<12 | SGL_OFFSET_4, msg); - __raw_writel(__raw_readl(sgl_elem-3) & 0x7FFFFFFF, sgl_elem-3); /* clear LE flag */ - __raw_writel(0xD5000000 | skb->len, sgl_elem); - __raw_writel((u32)skb, sgl_elem+1); - __raw_writel(virt_to_bus(skb->data), sgl_elem+2); - } - - /* If tx is in immediate mode or frame is full, send now */ - - if (!(priv->tx_batch_mode & 0x01) || priv->tx_count == priv->sgl_max) { - dev->trans_start = jiffies; - i2o_post_message(iop, priv->m); - dprintk(KERN_DEBUG "%s: %d packets sent.\n", dev->name, priv->tx_count); - priv->tx_count = 0; - } - - /* If DDMs TxMaxPktOut reached, stop queueing layer to send more */ - - if (atomic_read(&priv->tx_out) >= priv->tx_max_out) - netif_stop_queue(dev); - - spin_unlock_irq(&priv->tx_lock); - return 0; -} - -/* - * i2o_lan_get_stats(): Fill in the statistics. - */ -static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev) -{ - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; - struct i2o_controller *iop = i2o_dev->controller; - u64 val64[16]; - u64 supported_group[4] = { 0, 0, 0, 0 }; - - if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0100, -1, val64, - sizeof(val64)) < 0) - printk(KERN_INFO "%s: Unable to query LAN_HISTORICAL_STATS.\n", dev->name); - else { - dprintk(KERN_DEBUG "%s: LAN_HISTORICAL_STATS queried.\n", dev->name); - priv->stats.tx_packets = val64[0]; - priv->stats.tx_bytes = val64[1]; - priv->stats.rx_packets = val64[2]; - priv->stats.rx_bytes = val64[3]; - priv->stats.tx_errors = val64[4]; - priv->stats.rx_errors = val64[5]; - priv->stats.rx_dropped = val64[6]; - } - - if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0180, -1, - &supported_group, sizeof(supported_group)) < 0) - printk(KERN_INFO "%s: Unable to query LAN_SUPPORTED_OPTIONAL_HISTORICAL_STATS.\n", dev->name); - - if (supported_group[2]) { - if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0183, -1, - val64, sizeof(val64)) < 0) - printk(KERN_INFO "%s: Unable to query LAN_OPTIONAL_RX_HISTORICAL_STATS.\n", dev->name); - else { - dprintk(KERN_DEBUG "%s: LAN_OPTIONAL_RX_HISTORICAL_STATS queried.\n", dev->name); - priv->stats.multicast = val64[4]; - priv->stats.rx_length_errors = val64[10]; - priv->stats.rx_crc_errors = val64[0]; - } - } - - if (i2o_dev->lct_data.sub_class == I2O_LAN_ETHERNET) { - u64 supported_stats = 0; - if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0200, -1, - val64, sizeof(val64)) < 0) - printk(KERN_INFO "%s: Unable to query LAN_802_3_HISTORICAL_STATS.\n", dev->name); - else { - dprintk(KERN_DEBUG "%s: LAN_802_3_HISTORICAL_STATS queried.\n", dev->name); - priv->stats.transmit_collision = val64[1] + val64[2]; - priv->stats.rx_frame_errors = val64[0]; - priv->stats.tx_carrier_errors = val64[6]; - } - - if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0280, -1, - &supported_stats, sizeof(supported_stats)) < 0) - printk(KERN_INFO "%s: Unable to query LAN_SUPPORTED_802_3_HISTORICAL_STATS.\n", dev->name); - - if (supported_stats != 0) { - if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0281, -1, - val64, sizeof(val64)) < 0) - printk(KERN_INFO "%s: Unable to query LAN_OPTIONAL_802_3_HISTORICAL_STATS.\n", dev->name); - else { - dprintk(KERN_DEBUG "%s: LAN_OPTIONAL_802_3_HISTORICAL_STATS queried.\n", dev->name); - if (supported_stats & 0x1) - priv->stats.rx_over_errors = val64[0]; - if (supported_stats & 0x4) - priv->stats.tx_heartbeat_errors = val64[2]; - } - } - } - -#ifdef CONFIG_TR - if (i2o_dev->lct_data.sub_class == I2O_LAN_TR) { - if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0300, -1, - val64, sizeof(val64)) < 0) - printk(KERN_INFO "%s: Unable to query LAN_802_5_HISTORICAL_STATS.\n", dev->name); - else { - struct tr_statistics *stats = - (struct tr_statistics *)&priv->stats; - dprintk(KERN_DEBUG "%s: LAN_802_5_HISTORICAL_STATS queried.\n", dev->name); - - stats->line_errors = val64[0]; - stats->internal_errors = val64[7]; - stats->burst_errors = val64[4]; - stats->A_C_errors = val64[2]; - stats->abort_delimiters = val64[3]; - stats->lost_frames = val64[1]; - /* stats->recv_congest_count = ?; FIXME ??*/ - stats->frame_copied_errors = val64[5]; - stats->frequency_errors = val64[6]; - stats->token_errors = val64[9]; - } - /* Token Ring optional stats not yet defined */ - } -#endif - -#ifdef CONFIG_FDDI - if (i2o_dev->lct_data.sub_class == I2O_LAN_FDDI) { - if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0400, -1, - val64, sizeof(val64)) < 0) - printk(KERN_INFO "%s: Unable to query LAN_FDDI_HISTORICAL_STATS.\n", dev->name); - else { - dprintk(KERN_DEBUG "%s: LAN_FDDI_HISTORICAL_STATS queried.\n", dev->name); - priv->stats.smt_cf_state = val64[0]; - memcpy(priv->stats.mac_upstream_nbr, &val64[1], FDDI_K_ALEN); - memcpy(priv->stats.mac_downstream_nbr, &val64[2], FDDI_K_ALEN); - priv->stats.mac_error_cts = val64[3]; - priv->stats.mac_lost_cts = val64[4]; - priv->stats.mac_rmt_state = val64[5]; - memcpy(priv->stats.port_lct_fail_cts, &val64[6], 8); - memcpy(priv->stats.port_lem_reject_cts, &val64[7], 8); - memcpy(priv->stats.port_lem_cts, &val64[8], 8); - memcpy(priv->stats.port_pcm_state, &val64[9], 8); - } - /* FDDI optional stats not yet defined */ - } -#endif - -#ifdef CONFIG_NET_FC - /* Fibre Channel Statistics not yet defined in 1.53 nor 2.0 */ -#endif - - return (struct net_device_stats *)&priv->stats; -} - -/* - * i2o_lan_set_mc_filter(): Post a request to set multicast filter. - */ -int i2o_lan_set_mc_filter(struct net_device *dev, u32 filter_mask) -{ - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; - struct i2o_controller *iop = i2o_dev->controller; - u32 msg[10]; - - msg[0] = TEN_WORD_MSG_SIZE | SGL_OFFSET_5; - msg[1] = I2O_CMD_UTIL_PARAMS_SET << 24 | HOST_TID << 12 | i2o_dev->lct_data.tid; - msg[2] = priv->unit << 16 | lan_context; - msg[3] = 0x0001 << 16 | 3 ; // TransactionContext: group&field - msg[4] = 0; - msg[5] = 0xCC000000 | 16; // Immediate data SGL - msg[6] = 1; // OperationCount - msg[7] = 0x0001<<16 | I2O_PARAMS_FIELD_SET; // Group, Operation - msg[8] = 3 << 16 | 1; // FieldIndex, FieldCount - msg[9] = filter_mask; // Value - - return i2o_post_this(iop, msg, sizeof(msg)); -} - -/* - * i2o_lan_set_mc_table(): Post a request to set LAN_MULTICAST_MAC_ADDRESS table. - */ -int i2o_lan_set_mc_table(struct net_device *dev) -{ - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; - struct i2o_controller *iop = i2o_dev->controller; - struct dev_mc_list *mc; - u32 msg[10 + 2 * dev->mc_count]; - u8 *work8 = (u8 *)(msg + 10); - - msg[0] = I2O_MESSAGE_SIZE(10 + 2 * dev->mc_count) | SGL_OFFSET_5; - msg[1] = I2O_CMD_UTIL_PARAMS_SET << 24 | HOST_TID << 12 | i2o_dev->lct_data.tid; - msg[2] = priv->unit << 16 | lan_context; // InitiatorContext - msg[3] = 0x0002 << 16 | (u16)-1; // TransactionContext - msg[4] = 0; // OperationFlags - msg[5] = 0xCC000000 | (16 + 8 * dev->mc_count); // Immediate data SGL - msg[6] = 2; // OperationCount - msg[7] = 0x0002 << 16 | I2O_PARAMS_TABLE_CLEAR; // Group, Operation - msg[8] = 0x0002 << 16 | I2O_PARAMS_ROW_ADD; // Group, Operation - msg[9] = dev->mc_count << 16 | (u16)-1; // RowCount, FieldCount - - for (mc = dev->mc_list; mc ; mc = mc->next, work8 += 8) { - memset(work8, 0, 8); - memcpy(work8, mc->dmi_addr, mc->dmi_addrlen); // Values - } - - return i2o_post_this(iop, msg, sizeof(msg)); -} - -/* - * i2o_lan_set_multicast_list(): Enable a network device to receive packets - * not send to the protocol address. - */ -static void i2o_lan_set_multicast_list(struct net_device *dev) -{ - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - u32 filter_mask; - - if (dev->flags & IFF_PROMISC) { - filter_mask = 0x00000002; - dprintk(KERN_INFO "%s: Enabling promiscuous mode...\n", dev->name); - } else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > priv->max_size_mc_table) { - filter_mask = 0x00000004; - dprintk(KERN_INFO "%s: Enabling all multicast mode...\n", dev->name); - } else if (dev->mc_count) { - filter_mask = 0x00000000; - dprintk(KERN_INFO "%s: Enabling multicast mode...\n", dev->name); - if (i2o_lan_set_mc_table(dev) < 0) - printk(KERN_WARNING "%s: Unable to send MAC table.\n", dev->name); - } else { - filter_mask = 0x00000300; // Broadcast, Multicast disabled - dprintk(KERN_INFO "%s: Enabling unicast mode...\n", dev->name); - } - - /* Finally copy new FilterMask to DDM */ - - if (i2o_lan_set_mc_filter(dev, filter_mask) < 0) - printk(KERN_WARNING "%s: Unable to send MAC FilterMask.\n", dev->name); -} - -/* - * i2o_lan_change_mtu(): Change maximum transfer unit size. - */ -static int i2o_lan_change_mtu(struct net_device *dev, int new_mtu) -{ - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; - u32 max_pkt_size; - - if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data.tid, - 0x0000, 6, &max_pkt_size, 4) < 0) - return -EFAULT; - - if (new_mtu < 68 || new_mtu > 9000 || new_mtu > max_pkt_size) - return -EINVAL; - - dev->mtu = new_mtu; - - i2o_lan_suspend(dev); // to SUSPENDED state, return buckets - - while (priv->i2o_fbl_tail >= 0) // free buffered buckets - dev_kfree_skb(priv->i2o_fbl[priv->i2o_fbl_tail--]); - - i2o_lan_reset(dev); // to OPERATIONAL state - i2o_set_ddm_parameters(dev); // reset some parameters - i2o_lan_receive_post(dev); // post new buckets (new size) - - return 0; -} - -/* Functions to initialize I2O LAN OSM: -======================================*/ - -/* - * i2o_lan_register_device(): Register LAN class device to kernel. - */ -struct net_device *i2o_lan_register_device(struct i2o_device *i2o_dev) -{ - struct net_device *dev = NULL; - struct i2o_lan_local *priv = NULL; - u8 hw_addr[8]; - u32 tx_max_out = 0; - unsigned short (*type_trans)(struct sk_buff *, struct net_device *); - void (*unregister_dev)(struct net_device *dev); - - switch (i2o_dev->lct_data.sub_class) { - case I2O_LAN_ETHERNET: - dev = init_etherdev(NULL, sizeof(struct i2o_lan_local)); - if (dev == NULL) - return NULL; - type_trans = eth_type_trans; - unregister_dev = unregister_netdev; - break; - -#ifdef CONFIG_ANYLAN - case I2O_LAN_100VG: - printk(KERN_ERR "i2o_lan: 100base VG not yet supported.\n"); - return NULL; - break; -#endif - -#ifdef CONFIG_TR - case I2O_LAN_TR: - dev = init_trdev(NULL, sizeof(struct i2o_lan_local)); - if (dev==NULL) - return NULL; - type_trans = tr_type_trans; - unregister_dev = unregister_trdev; - break; -#endif - -#ifdef CONFIG_FDDI - case I2O_LAN_FDDI: - { - int size = sizeof(struct net_device) + sizeof(struct i2o_lan_local); - - dev = (struct net_device *) kmalloc(size, GFP_KERNEL); - if (dev == NULL) - return NULL; - memset((char *)dev, 0, size); - dev->priv = (void *)(dev + 1); - - if (dev_alloc_name(dev, "fddi%d") < 0) { - printk(KERN_WARNING "i2o_lan: Too many FDDI devices.\n"); - kfree(dev); - return NULL; - } - type_trans = fddi_type_trans; - unregister_dev = (void *)unregister_netdevice; - - fddi_setup(dev); - register_netdev(dev); - } - break; -#endif - -#ifdef CONFIG_NET_FC - case I2O_LAN_FIBRE_CHANNEL: - dev = init_fcdev(NULL, sizeof(struct i2o_lan_local)); - if (dev == NULL) - return NULL; - type_trans = NULL; -/* FIXME: Move fc_type_trans() from drivers/net/fc/iph5526.c to net/802/fc.c - * and export it in include/linux/fcdevice.h - * type_trans = fc_type_trans; - */ - unregister_dev = (void *)unregister_fcdev; - break; -#endif - - case I2O_LAN_UNKNOWN: - default: - printk(KERN_ERR "i2o_lan: LAN type 0x%04x not supported.\n", - i2o_dev->lct_data.sub_class); - return NULL; - } - - priv = (struct i2o_lan_local *)dev->priv; - priv->i2o_dev = i2o_dev; - priv->type_trans = type_trans; - priv->sgl_max = (i2o_dev->controller->status_block->inbound_frame_size - 4) / 3; - atomic_set(&priv->buckets_out, 0); - - /* Set default values for user configurable parameters */ - /* Private values are changed via /proc file system */ - - priv->max_buckets_out = max_buckets_out; - priv->bucket_thresh = bucket_thresh; - priv->rx_copybreak = rx_copybreak; - priv->tx_batch_mode = tx_batch_mode & 0x03; - priv->i2o_event_mask = i2o_event_mask; - - priv->tx_lock = SPIN_LOCK_UNLOCKED; - priv->fbl_lock = SPIN_LOCK_UNLOCKED; - - unit++; - i2o_landevs[unit] = dev; - priv->unit = unit; - - if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data.tid, - 0x0001, 0, &hw_addr, sizeof(hw_addr)) < 0) { - printk(KERN_ERR "%s: Unable to query hardware address.\n", dev->name); - unit--; - unregister_dev(dev); - kfree(dev); - return NULL; - } - dprintk(KERN_DEBUG "%s: hwaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", - dev->name, hw_addr[0], hw_addr[1], hw_addr[2], hw_addr[3], - hw_addr[4], hw_addr[5]); - - dev->addr_len = 6; - memcpy(dev->dev_addr, hw_addr, 6); - - if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data.tid, - 0x0007, 2, &tx_max_out, sizeof(tx_max_out)) < 0) { - printk(KERN_ERR "%s: Unable to query max TX queue.\n", dev->name); - unit--; - unregister_dev(dev); - kfree(dev); - return NULL; - } - dprintk(KERN_INFO "%s: Max TX Outstanding = %d.\n", dev->name, tx_max_out); - priv->tx_max_out = tx_max_out; - atomic_set(&priv->tx_out, 0); - priv->tx_count = 0; - - INIT_LIST_HEAD(&priv->i2o_batch_send_task.list); - priv->i2o_batch_send_task.sync = 0; - priv->i2o_batch_send_task.routine = (void *)i2o_lan_batch_send; - priv->i2o_batch_send_task.data = (void *)dev; - - dev->open = i2o_lan_open; - dev->stop = i2o_lan_close; - dev->get_stats = i2o_lan_get_stats; - dev->set_multicast_list = i2o_lan_set_multicast_list; - dev->tx_timeout = i2o_lan_tx_timeout; - dev->watchdog_timeo = I2O_LAN_TX_TIMEOUT; - -#ifdef CONFIG_NET_FC - if (i2o_dev->lct_data.sub_class == I2O_LAN_FIBRE_CHANNEL) - dev->hard_start_xmit = i2o_lan_sdu_send; - else -#endif - dev->hard_start_xmit = i2o_lan_packet_send; - - if (i2o_dev->lct_data.sub_class == I2O_LAN_ETHERNET) - dev->change_mtu = i2o_lan_change_mtu; - - return dev; -} - -#ifdef MODULE -#define i2o_lan_init init_module -#endif - -int __init i2o_lan_init(void) -{ - struct net_device *dev; - int i; - - printk(KERN_INFO "I2O LAN OSM (C) 1999 University of Helsinki.\n"); - - /* Module params are used as global defaults for private values */ - - if (max_buckets_out > I2O_LAN_MAX_BUCKETS_OUT) - max_buckets_out = I2O_LAN_MAX_BUCKETS_OUT; - if (bucket_thresh > max_buckets_out) - bucket_thresh = max_buckets_out; - - /* Install handlers for incoming replies */ - - if (i2o_install_handler(&i2o_lan_send_handler) < 0) { - printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n"); - return -EINVAL; - } - lan_send_context = i2o_lan_send_handler.context; - - if (i2o_install_handler(&i2o_lan_receive_handler) < 0) { - printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n"); - return -EINVAL; - } - lan_receive_context = i2o_lan_receive_handler.context; - - if (i2o_install_handler(&i2o_lan_handler) < 0) { - printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n"); - return -EINVAL; - } - lan_context = i2o_lan_handler.context; - - for(i=0; i <= MAX_LAN_CARDS; i++) - i2o_landevs[i] = NULL; - - for (i=0; i < MAX_I2O_CONTROLLERS; i++) { - struct i2o_controller *iop = i2o_find_controller(i); - struct i2o_device *i2o_dev; - - if (iop==NULL) - continue; - - for (i2o_dev=iop->devices;i2o_dev != NULL;i2o_dev=i2o_dev->next) { - - if (i2o_dev->lct_data.class_id != I2O_CLASS_LAN) - continue; - - /* Make sure device not already claimed by an ISM */ - if (i2o_dev->lct_data.user_tid != 0xFFF) - continue; - - if (unit == MAX_LAN_CARDS) { - i2o_unlock_controller(iop); - printk(KERN_WARNING "i2o_lan: Too many I2O LAN devices.\n"); - return -EINVAL; - } - - dev = i2o_lan_register_device(i2o_dev); - if (dev == NULL) { - printk(KERN_ERR "i2o_lan: Unable to register I2O LAN device 0x%04x.\n", - i2o_dev->lct_data.sub_class); - continue; - } - - printk(KERN_INFO "%s: I2O LAN device registered, " - "subclass = 0x%04x, unit = %d, tid = %d.\n", - dev->name, i2o_dev->lct_data.sub_class, - ((struct i2o_lan_local *)dev->priv)->unit, - i2o_dev->lct_data.tid); - } - - i2o_unlock_controller(iop); - } - - dprintk(KERN_INFO "%d I2O LAN devices found and registered.\n", unit+1); - - return 0; -} - -#ifdef MODULE - -void cleanup_module(void) -{ - int i; - - for (i = 0; i <= unit; i++) { - struct net_device *dev = i2o_landevs[i]; - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; - - switch (i2o_dev->lct_data.sub_class) { - case I2O_LAN_ETHERNET: - unregister_netdev(dev); - break; -#ifdef CONFIG_FDDI - case I2O_LAN_FDDI: - unregister_netdevice(dev); - break; -#endif -#ifdef CONFIG_TR - case I2O_LAN_TR: - unregister_trdev(dev); - break; -#endif -#ifdef CONFIG_NET_FC - case I2O_LAN_FIBRE_CHANNEL: - unregister_fcdev(dev); - break; -#endif - default: - printk(KERN_WARNING "%s: Spurious I2O LAN subclass 0x%08x.\n", - dev->name, i2o_dev->lct_data.sub_class); - } - - dprintk(KERN_INFO "%s: I2O LAN device unregistered.\n", - dev->name); - kfree(dev); - } - - i2o_remove_handler(&i2o_lan_handler); - i2o_remove_handler(&i2o_lan_send_handler); - i2o_remove_handler(&i2o_lan_receive_handler); -} - -EXPORT_NO_SYMBOLS; - -MODULE_AUTHOR("University of Helsinki, Department of Computer Science"); -MODULE_DESCRIPTION("I2O Lan OSM"); - -MODULE_PARM(max_buckets_out, "1-" __MODULE_STRING(I2O_LAN_MAX_BUCKETS_OUT) "i"); -MODULE_PARM_DESC(max_buckets_out, "Total number of buckets to post (1-)"); -MODULE_PARM(bucket_thresh, "1-" __MODULE_STRING(I2O_LAN_MAX_BUCKETS_OUT) "i"); -MODULE_PARM_DESC(bucket_thresh, "Bucket post threshold (1-)"); -MODULE_PARM(rx_copybreak, "1-" "i"); -MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy only small frames (1-)"); -MODULE_PARM(tx_batch_mode, "0-2" "i"); -MODULE_PARM_DESC(tx_batch_mode, "0=Send immediatelly, 1=Send in batches, 2=Switch automatically"); - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/i2o/i2o_lan.h linux.ac/drivers/i2o/i2o_lan.h --- linux.vanilla/drivers/i2o/i2o_lan.h Mon Dec 11 21:20:00 2000 +++ linux.ac/drivers/i2o/i2o_lan.h Thu Jan 1 01:00:00 1970 @@ -1,159 +0,0 @@ -/* - * i2o_lan.h I2O LAN Class definitions - * - * I2O LAN CLASS OSM May 26th 2000 - * - * (C) Copyright 1999, 2000 University of Helsinki, - * Department of Computer Science - * - * This code is still under development / test. - * - * Author: Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI> - * Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI> - * Taneli Vähäkangas <Taneli.Vahakangas@cs.Helsinki.FI> - */ - -#ifndef _I2O_LAN_H -#define _I2O_LAN_H - -/* Default values for tunable parameters first */ - -#define I2O_LAN_MAX_BUCKETS_OUT 96 -#define I2O_LAN_BUCKET_THRESH 18 /* 9 buckets in one message */ -#define I2O_LAN_RX_COPYBREAK 200 -#define I2O_LAN_TX_TIMEOUT (1*HZ) -#define I2O_LAN_TX_BATCH_MODE 2 /* 2=automatic, 1=on, 0=off */ -#define I2O_LAN_EVENT_MASK 0 /* 0=None, 0xFFC00002=All */ - -/* LAN types */ -#define I2O_LAN_ETHERNET 0x0030 -#define I2O_LAN_100VG 0x0040 -#define I2O_LAN_TR 0x0050 -#define I2O_LAN_FDDI 0x0060 -#define I2O_LAN_FIBRE_CHANNEL 0x0070 -#define I2O_LAN_UNKNOWN 0x00000000 - -/* Connector types */ - -/* Ethernet */ -#define I2O_LAN_AUI (I2O_LAN_ETHERNET << 4) + 0x00000001 -#define I2O_LAN_10BASE5 (I2O_LAN_ETHERNET << 4) + 0x00000002 -#define I2O_LAN_FIORL (I2O_LAN_ETHERNET << 4) + 0x00000003 -#define I2O_LAN_10BASE2 (I2O_LAN_ETHERNET << 4) + 0x00000004 -#define I2O_LAN_10BROAD36 (I2O_LAN_ETHERNET << 4) + 0x00000005 -#define I2O_LAN_10BASE_T (I2O_LAN_ETHERNET << 4) + 0x00000006 -#define I2O_LAN_10BASE_FP (I2O_LAN_ETHERNET << 4) + 0x00000007 -#define I2O_LAN_10BASE_FB (I2O_LAN_ETHERNET << 4) + 0x00000008 -#define I2O_LAN_10BASE_FL (I2O_LAN_ETHERNET << 4) + 0x00000009 -#define I2O_LAN_100BASE_TX (I2O_LAN_ETHERNET << 4) + 0x0000000A -#define I2O_LAN_100BASE_FX (I2O_LAN_ETHERNET << 4) + 0x0000000B -#define I2O_LAN_100BASE_T4 (I2O_LAN_ETHERNET << 4) + 0x0000000C -#define I2O_LAN_1000BASE_SX (I2O_LAN_ETHERNET << 4) + 0x0000000D -#define I2O_LAN_1000BASE_LX (I2O_LAN_ETHERNET << 4) + 0x0000000E -#define I2O_LAN_1000BASE_CX (I2O_LAN_ETHERNET << 4) + 0x0000000F -#define I2O_LAN_1000BASE_T (I2O_LAN_ETHERNET << 4) + 0x00000010 - -/* AnyLAN */ -#define I2O_LAN_100VG_ETHERNET (I2O_LAN_100VG << 4) + 0x00000001 -#define I2O_LAN_100VG_TR (I2O_LAN_100VG << 4) + 0x00000002 - -/* Token Ring */ -#define I2O_LAN_4MBIT (I2O_LAN_TR << 4) + 0x00000001 -#define I2O_LAN_16MBIT (I2O_LAN_TR << 4) + 0x00000002 - -/* FDDI */ -#define I2O_LAN_125MBAUD (I2O_LAN_FDDI << 4) + 0x00000001 - -/* Fibre Channel */ -#define I2O_LAN_POINT_POINT (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000001 -#define I2O_LAN_ARB_LOOP (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000002 -#define I2O_LAN_PUBLIC_LOOP (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000003 -#define I2O_LAN_FABRIC (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000004 - -#define I2O_LAN_EMULATION 0x00000F00 -#define I2O_LAN_OTHER 0x00000F01 -#define I2O_LAN_DEFAULT 0xFFFFFFFF - -/* LAN class functions */ - -#define LAN_PACKET_SEND 0x3B -#define LAN_SDU_SEND 0x3D -#define LAN_RECEIVE_POST 0x3E -#define LAN_RESET 0x35 -#define LAN_SUSPEND 0x37 - -/* LAN DetailedStatusCode defines */ -#define I2O_LAN_DSC_SUCCESS 0x00 -#define I2O_LAN_DSC_DEVICE_FAILURE 0x01 -#define I2O_LAN_DSC_DESTINATION_NOT_FOUND 0x02 -#define I2O_LAN_DSC_TRANSMIT_ERROR 0x03 -#define I2O_LAN_DSC_TRANSMIT_ABORTED 0x04 -#define I2O_LAN_DSC_RECEIVE_ERROR 0x05 -#define I2O_LAN_DSC_RECEIVE_ABORTED 0x06 -#define I2O_LAN_DSC_DMA_ERROR 0x07 -#define I2O_LAN_DSC_BAD_PACKET_DETECTED 0x08 -#define I2O_LAN_DSC_OUT_OF_MEMORY 0x09 -#define I2O_LAN_DSC_BUCKET_OVERRUN 0x0A -#define I2O_LAN_DSC_IOP_INTERNAL_ERROR 0x0B -#define I2O_LAN_DSC_CANCELED 0x0C -#define I2O_LAN_DSC_INVALID_TRANSACTION_CONTEXT 0x0D -#define I2O_LAN_DSC_DEST_ADDRESS_DETECTED 0x0E -#define I2O_LAN_DSC_DEST_ADDRESS_OMITTED 0x0F -#define I2O_LAN_DSC_PARTIAL_PACKET_RETURNED 0x10 -#define I2O_LAN_DSC_SUSPENDED 0x11 - -struct i2o_packet_info { - u32 offset : 24; - u32 flags : 8; - u32 len : 24; - u32 status : 8; -}; - -struct i2o_bucket_descriptor { - u32 context; /* FIXME: 64bit support */ - struct i2o_packet_info packet_info[1]; -}; - -/* Event Indicator Mask Flags for LAN OSM */ - -#define I2O_LAN_EVT_LINK_DOWN 0x01 -#define I2O_LAN_EVT_LINK_UP 0x02 -#define I2O_LAN_EVT_MEDIA_CHANGE 0x04 - -#include <linux/netdevice.h> -#include <linux/fddidevice.h> - -struct i2o_lan_local { - u8 unit; - struct i2o_device *i2o_dev; - - struct fddi_statistics stats; /* see also struct net_device_stats */ - unsigned short (*type_trans)(struct sk_buff *, struct net_device *); - atomic_t buckets_out; /* nbr of unused buckets on DDM */ - atomic_t tx_out; /* outstanding TXes */ - u8 tx_count; /* packets in one TX message frame */ - u16 tx_max_out; /* DDM's Tx queue len */ - u8 sgl_max; /* max SGLs in one message frame */ - u32 m; /* IOP address of the batch msg frame */ - - struct tq_struct i2o_batch_send_task; - int send_active; - struct sk_buff **i2o_fbl; /* Free bucket list (to reuse skbs) */ - int i2o_fbl_tail; - spinlock_t fbl_lock; - - spinlock_t tx_lock; - - u32 max_size_mc_table; /* max number of multicast addresses */ - - /* LAN OSM configurable parameters are here: */ - - u16 max_buckets_out; /* max nbr of buckets to send to DDM */ - u16 bucket_thresh; /* send more when this many used */ - u16 rx_copybreak; - - u8 tx_batch_mode; /* Set when using batch mode sends */ - u32 i2o_event_mask; /* To turn on interesting event flags */ -}; - -#endif /* _I2O_LAN_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/i2o/i2o_pci.c linux.ac/drivers/i2o/i2o_pci.c --- linux.vanilla/drivers/i2o/i2o_pci.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/i2o/i2o_pci.c Thu Jan 1 01:00:00 1970 @@ -1,351 +0,0 @@ -/* - * Find I2O capable controllers on the PCI bus, and register/install - * them with the I2O layer - * - * (C) Copyright 1999 Red Hat Software - * - * Written by Alan Cox, Building Number Three Ltd - * Modified by Deepak Saxena <deepak@plexity.net> - * Modified by Boji T Kannanthanam <boji.t.kannanthanam@intel.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. - * - * TODO: - * Support polled I2O PCI controllers. - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/i2o.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <asm/io.h> - -#ifdef CONFIG_MTRR -#include <asm/mtrr.h> -#endif // CONFIG_MTRR - -#ifdef MODULE -/* - * Core function table - * See <include/linux/i2o.h> for an explanation - */ -static struct i2o_core_func_table *core; - -/* Core attach function */ -extern int i2o_pci_core_attach(struct i2o_core_func_table *); -extern void i2o_pci_core_detach(void); -#endif /* MODULE */ - -/* - * Free bus specific resources - */ -static void i2o_pci_dispose(struct i2o_controller *c) -{ - I2O_IRQ_WRITE32(c,0xFFFFFFFF); - if(c->bus.pci.irq > 0) - free_irq(c->bus.pci.irq, c); - iounmap(((u8 *)c->post_port)-0x40); - -#ifdef CONFIG_MTRR - if(c->bus.pci.mtrr_reg0 > 0) - mtrr_del(c->bus.pci.mtrr_reg0, 0, 0); - if(c->bus.pci.mtrr_reg1 > 0) - mtrr_del(c->bus.pci.mtrr_reg1, 0, 0); -#endif -} - -/* - * No real bus specific handling yet (note that later we will - * need to 'steal' PCI devices on i960 mainboards) - */ - -static int i2o_pci_bind(struct i2o_controller *c, struct i2o_device *dev) -{ - MOD_INC_USE_COUNT; - return 0; -} - -static int i2o_pci_unbind(struct i2o_controller *c, struct i2o_device *dev) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* - * Bus specific enable/disable functions - */ -static void i2o_pci_enable(struct i2o_controller *c) -{ - I2O_IRQ_WRITE32(c, 0); - c->enabled = 1; -} - -static void i2o_pci_disable(struct i2o_controller *c) -{ - I2O_IRQ_WRITE32(c, 0xFFFFFFFF); - c->enabled = 0; -} - -/* - * Bus specific interrupt handler - */ - -static void i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r) -{ - struct i2o_controller *c = dev_id; -#ifdef MODULE - core->run_queue(c); -#else - i2o_run_queue(c); -#endif /* MODULE */ -} - -/* - * Install a PCI (or in theory AGP) i2o controller - * - * TODO: Add support for polled controllers - */ -int __init i2o_pci_install(struct pci_dev *dev) -{ - struct i2o_controller *c=kmalloc(sizeof(struct i2o_controller), - GFP_KERNEL); - u8 *mem; - u32 memptr = 0; - u32 size; - - int i; - - if(c==NULL) - { - printk(KERN_ERR "i2o: Insufficient memory to add controller.\n"); - return -ENOMEM; - } - memset(c, 0, sizeof(*c)); - - for(i=0; i<6; i++) - { - /* Skip I/O spaces */ - if(!(pci_resource_flags(dev, i) & IORESOURCE_IO)) - { - memptr = pci_resource_start(dev, i); - break; - } - } - - if(i==6) - { - printk(KERN_ERR "i2o: I2O controller has no memory regions defined.\n"); - kfree(c); - return -EINVAL; - } - - size = dev->resource[i].end-dev->resource[i].start+1; - /* Map the I2O controller */ - - printk(KERN_INFO "i2o: PCI I2O controller at 0x%08X size=%d\n", memptr, size); - mem = ioremap(memptr, size); - if(mem==NULL) - { - printk(KERN_ERR "i2o: Unable to map controller.\n"); - kfree(c); - return -EINVAL; - } - - c->bus.pci.irq = -1; - - c->irq_mask = (volatile u32 *)(mem+0x34); - c->post_port = (volatile u32 *)(mem+0x40); - c->reply_port = (volatile u32 *)(mem+0x44); - - c->mem_phys = memptr; - c->mem_offset = (u32)mem; - c->destructor = i2o_pci_dispose; - - c->bind = i2o_pci_bind; - c->unbind = i2o_pci_unbind; - c->bus_enable = i2o_pci_enable; - c->bus_disable = i2o_pci_disable; - - c->type = I2O_TYPE_PCI; - - /* - * Enable Write Combining MTRR for IOP's memory region - */ -#ifdef CONFIG_MTRR - c->bus.pci.mtrr_reg0 = - mtrr_add(c->mem_phys, size, MTRR_TYPE_WRCOMB, 1); -/* -* If it is an INTEL i960 I/O processor then set the first 64K to Uncacheable -* since the region contains the Messaging unit which shouldn't be cached. -*/ - c->bus.pci.mtrr_reg1 = -1; - if(dev->vendor == PCI_VENDOR_ID_INTEL) - { - printk(KERN_INFO "I2O: MTRR workaround for Intel i960 processor\n"); - c->bus.pci.mtrr_reg1 = - mtrr_add(c->mem_phys, 65536, MTRR_TYPE_UNCACHABLE, 1); - if(c->bus.pci.mtrr_reg1< 0) - printk(KERN_INFO "i2o_pci: Error in setting MTRR_TYPE_UNCACHABLE\n"); - } - -#endif - - I2O_IRQ_WRITE32(c,0xFFFFFFFF); - -#ifdef MODULE - i = core->install(c); -#else - i = i2o_install_controller(c); -#endif /* MODULE */ - - if(i<0) - { - printk(KERN_ERR "i2o: Unable to install controller.\n"); - kfree(c); - iounmap(mem); - return i; - } - - c->bus.pci.irq = dev->irq; - if(c->bus.pci.irq) - { - i=request_irq(dev->irq, i2o_pci_interrupt, SA_SHIRQ, - c->name, c); - if(i<0) - { - printk(KERN_ERR "%s: unable to allocate interrupt %d.\n", - c->name, dev->irq); - c->bus.pci.irq = -1; -#ifdef MODULE - core->delete(c); -#else - i2o_delete_controller(c); -#endif /* MODULE */ - kfree(c); - iounmap(mem); - return -EBUSY; - } - } - - printk(KERN_INFO "%s: Installed at IRQ%d\n", c->name, dev->irq); - I2O_IRQ_WRITE32(c,0x0); - c->enabled = 1; - return 0; -} - -int __init i2o_pci_scan(void) -{ - struct pci_dev *dev; - int count=0; - - printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n"); - - pci_for_each_dev(dev) - { - if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O) - continue; - if((dev->class&0xFF)>1) - { - printk(KERN_INFO "i2o: I2O Controller found but does not support I2O 1.5 (skipping).\n"); - continue; - } - if (pci_enable_device(dev)) - continue; - printk(KERN_INFO "i2o: I2O controller on bus %d at %d.\n", - dev->bus->number, dev->devfn); - pci_set_master(dev); - if(i2o_pci_install(dev)==0) - count++; - } - if(count) - printk(KERN_INFO "i2o: %d I2O controller%s found and installed.\n", count, - count==1?"":"s"); - return count?count:-ENODEV; -} - -#ifdef I2O_HOTPLUG_SUPPORT -/* - * Activate a newly found PCI I2O controller - * Not used now, but will be needed in future for - * hot plug PCI support - */ -static void i2o_pci_activate(i2o_controller * c) -{ - int i=0; - struct i2o_controller *c; - - if(c->type == I2O_TYPE_PCI) - { - I2O_IRQ_WRITE32(c,0); -#ifdef MODULE - if(core->activate(c)) -#else - if(i2o_activate_controller(c)) -#endif /* MODULE */ - { - printk("%s: Failed to initialize.\n", c->name); -#ifdef MODULE - core->unlock(c); - core->delete(c); -#else - i2o_unlock_controller(c); - i2o_delete_controller(c); -#endif - continue; - } - } -} -#endif // I2O_HOTPLUG_SUPPORT - -#ifdef MODULE - -int i2o_pci_core_attach(struct i2o_core_func_table *table) -{ - MOD_INC_USE_COUNT; - - core = table; - - return i2o_pci_scan(); -} - -void i2o_pci_core_detach(void) -{ - core = NULL; - - MOD_DEC_USE_COUNT; -} - -int init_module(void) -{ - printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n"); - - core = NULL; - - return 0; - -} - -void cleanup_module(void) -{ -} - -EXPORT_SYMBOL(i2o_pci_core_attach); -EXPORT_SYMBOL(i2o_pci_core_detach); - -MODULE_AUTHOR("Red Hat Software"); -MODULE_DESCRIPTION("I2O PCI Interface"); - -#else -void __init i2o_pci_init(void) -{ - printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n"); - i2o_pci_scan(); -} -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/i2o/i2o_proc.c linux.ac/drivers/i2o/i2o_proc.c --- linux.vanilla/drivers/i2o/i2o_proc.c Sat Nov 18 00:51:47 2000 +++ linux.ac/drivers/i2o/i2o_proc.c Thu Jan 1 01:00:00 1970 @@ -1,3372 +0,0 @@ -/* - * procfs handler for Linux I2O subsystem - * - * (c) Copyright 1999 Deepak Saxena - * - * Originally written by Deepak Saxena(deepak@plexity.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. - * - * This is an initial test release. The code is based on the design - * of the ide procfs system (drivers/block/ide-proc.c). Some code - * taken from i2o-core module by Alan Cox. - * - * DISCLAIMER: This code is still under development/test and may cause - * your system to behave unpredictably. Use at your own discretion. - * - * LAN entries by Juha Sievänen (Juha.Sievanen@cs.Helsinki.FI), - * Auvo Häkkinen (Auvo.Hakkinen@cs.Helsinki.FI) - * University of Helsinki, Department of Computer Science - */ - -/* - * set tabstop=3 - */ - -/* - * TODO List - * - * - Add support for any version 2.0 spec changes once 2.0 IRTOS is - * is available to test with - * - Clean up code to use official structure definitions - */ - -// FIXME! -#define FMT_U64_HEX "0x%08x%08x" -#define U64_VAL(pu64) *((u32*)(pu64)+1), *((u32*)(pu64)) - -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/i2o.h> -#include <linux/proc_fs.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/spinlock.h> - -#include <asm/io.h> -#include <asm/uaccess.h> -#include <asm/byteorder.h> - -#include "i2o_lan.h" - -/* - * Structure used to define /proc entries - */ -typedef struct _i2o_proc_entry_t -{ - char *name; /* entry name */ - mode_t mode; /* mode */ - read_proc_t *read_proc; /* read func */ - write_proc_t *write_proc; /* write func */ -} i2o_proc_entry; - -// #define DRIVERDEBUG - -static int i2o_proc_read_lct(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_hrt(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_status(char *, char **, off_t, int, int *, void *); - -static int i2o_proc_read_hw(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_ddm_table(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_driver_store(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_drivers_stored(char *, char **, off_t, int, int *, void *); - -static int i2o_proc_read_groups(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_phys_device(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_claimed(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_users(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_priv_msgs(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_authorized_users(char *, char **, off_t, int, int *, void *); - -static int i2o_proc_read_dev_name(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_dev_identity(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_ddm_identity(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_uinfo(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_sgl_limits(char *, char **, off_t, int, int *, void *); - -static int i2o_proc_read_sensors(char *, char **, off_t, int, int *, void *); - -static int print_serial_number(char *, int, u8 *, int); - -static int i2o_proc_create_entries(void *, i2o_proc_entry *, - struct proc_dir_entry *); -static void i2o_proc_remove_entries(i2o_proc_entry *, struct proc_dir_entry *); -static int i2o_proc_add_controller(struct i2o_controller *, - struct proc_dir_entry * ); -static void i2o_proc_remove_controller(struct i2o_controller *, - struct proc_dir_entry * ); -static void i2o_proc_add_device(struct i2o_device *, struct proc_dir_entry *); -static void i2o_proc_remove_device(struct i2o_device *); -static int create_i2o_procfs(void); -static int destroy_i2o_procfs(void); -static void i2o_proc_new_dev(struct i2o_controller *, struct i2o_device *); -static void i2o_proc_dev_del(struct i2o_controller *, struct i2o_device *); - -static int i2o_proc_read_lan_dev_info(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_mac_addr(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_mcast_addr(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_batch_control(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_operation(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_media_operation(char *, char **, off_t, int, - int *, void *); -static int i2o_proc_read_lan_alt_addr(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_tx_info(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_rx_info(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_hist_stats(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_eth_stats(char *, char **, off_t, int, - int *, void *); -static int i2o_proc_read_lan_tr_stats(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_fddi_stats(char *, char **, off_t, int, int *, - void *); - -static struct proc_dir_entry *i2o_proc_dir_root; - -/* - * I2O OSM descriptor - */ -static struct i2o_handler i2o_proc_handler = -{ - NULL, - i2o_proc_new_dev, - i2o_proc_dev_del, - NULL, - "I2O procfs Layer", - 0, - 0xffffffff // All classes -}; - -/* - * IOP specific entries...write field just in case someone - * ever wants one. - */ -static i2o_proc_entry generic_iop_entries[] = -{ - {"hrt", S_IFREG|S_IRUGO, i2o_proc_read_hrt, NULL}, - {"lct", S_IFREG|S_IRUGO, i2o_proc_read_lct, NULL}, - {"status", S_IFREG|S_IRUGO, i2o_proc_read_status, NULL}, - {"hw", S_IFREG|S_IRUGO, i2o_proc_read_hw, NULL}, - {"ddm_table", S_IFREG|S_IRUGO, i2o_proc_read_ddm_table, NULL}, - {"driver_store", S_IFREG|S_IRUGO, i2o_proc_read_driver_store, NULL}, - {"drivers_stored", S_IFREG|S_IRUGO, i2o_proc_read_drivers_stored, NULL}, - {NULL, 0, NULL, NULL} -}; - -/* - * Device specific entries - */ -static i2o_proc_entry generic_dev_entries[] = -{ - {"groups", S_IFREG|S_IRUGO, i2o_proc_read_groups, NULL}, - {"phys_dev", S_IFREG|S_IRUGO, i2o_proc_read_phys_device, NULL}, - {"claimed", S_IFREG|S_IRUGO, i2o_proc_read_claimed, NULL}, - {"users", S_IFREG|S_IRUGO, i2o_proc_read_users, NULL}, - {"priv_msgs", S_IFREG|S_IRUGO, i2o_proc_read_priv_msgs, NULL}, - {"authorized_users", S_IFREG|S_IRUGO, i2o_proc_read_authorized_users, NULL}, - {"dev_identity", S_IFREG|S_IRUGO, i2o_proc_read_dev_identity, NULL}, - {"ddm_identity", S_IFREG|S_IRUGO, i2o_proc_read_ddm_identity, NULL}, - {"user_info", S_IFREG|S_IRUGO, i2o_proc_read_uinfo, NULL}, - {"sgl_limits", S_IFREG|S_IRUGO, i2o_proc_read_sgl_limits, NULL}, - {"sensors", S_IFREG|S_IRUGO, i2o_proc_read_sensors, NULL}, - {NULL, 0, NULL, NULL} -}; - -/* - * Storage unit specific entries (SCSI Periph, BS) with device names - */ -static i2o_proc_entry rbs_dev_entries[] = -{ - {"dev_name", S_IFREG|S_IRUGO, i2o_proc_read_dev_name, NULL}, - {NULL, 0, NULL, NULL} -}; - -#define SCSI_TABLE_SIZE 13 -static char *scsi_devices[] = -{ - "Direct-Access Read/Write", - "Sequential-Access Storage", - "Printer", - "Processor", - "WORM Device", - "CD-ROM Device", - "Scanner Device", - "Optical Memory Device", - "Medium Changer Device", - "Communications Device", - "Graphics Art Pre-Press Device", - "Graphics Art Pre-Press Device", - "Array Controller Device" -}; - -/* private */ - -/* - * Generic LAN specific entries - * - * Should groups with r/w entries have their own subdirectory? - * - */ -static i2o_proc_entry lan_entries[] = -{ - {"lan_dev_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_dev_info, NULL}, - {"lan_mac_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_mac_addr, NULL}, - {"lan_mcast_addr", S_IFREG|S_IRUGO|S_IWUSR, - i2o_proc_read_lan_mcast_addr, NULL}, - {"lan_batch_ctrl", S_IFREG|S_IRUGO|S_IWUSR, - i2o_proc_read_lan_batch_control, NULL}, - {"lan_operation", S_IFREG|S_IRUGO, i2o_proc_read_lan_operation, NULL}, - {"lan_media_operation", S_IFREG|S_IRUGO, - i2o_proc_read_lan_media_operation, NULL}, - {"lan_alt_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_alt_addr, NULL}, - {"lan_tx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_tx_info, NULL}, - {"lan_rx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_rx_info, NULL}, - - {"lan_hist_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_hist_stats, NULL}, - {NULL, 0, NULL, NULL} -}; - -/* - * Port specific LAN entries - * - */ -static i2o_proc_entry lan_eth_entries[] = -{ - {"lan_eth_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_eth_stats, NULL}, - {NULL, 0, NULL, NULL} -}; - -static i2o_proc_entry lan_tr_entries[] = -{ - {"lan_tr_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_tr_stats, NULL}, - {NULL, 0, NULL, NULL} -}; - -static i2o_proc_entry lan_fddi_entries[] = -{ - {"lan_fddi_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_fddi_stats, NULL}, - {NULL, 0, NULL, NULL} -}; - - -static char *chtostr(u8 *chars, int n) -{ - char tmp[256]; - tmp[0] = 0; - return strncat(tmp, (char *)chars, n); -} - -static int i2o_report_query_status(char *buf, int block_status, char *group) -{ - switch (block_status) - { - case -ETIMEDOUT: - return sprintf(buf, "Timeout reading group %s.\n",group); - case -ENOMEM: - return sprintf(buf, "No free memory to read the table.\n"); - case -I2O_PARAMS_STATUS_INVALID_GROUP_ID: - return sprintf(buf, "Group %s not supported.\n", group); - default: - return sprintf(buf, "Error reading group %s. BlockStatus 0x%02X\n", - group, -block_status); - } -} - -static char* bus_strings[] = -{ - "Local Bus", - "ISA", - "EISA", - "MCA", - "PCI", - "PCMCIA", - "NUBUS", - "CARDBUS" -}; - -static spinlock_t i2o_proc_lock = SPIN_LOCK_UNLOCKED; - -int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_controller *c = (struct i2o_controller *)data; - i2o_hrt *hrt = (i2o_hrt *)c->hrt; - u32 bus; - int count; - int i; - - spin_lock(&i2o_proc_lock); - - len = 0; - - if(hrt->hrt_version) - { - len += sprintf(buf+len, - "HRT table for controller is too new a version.\n"); - spin_unlock(&i2o_proc_lock); - return len; - } - - count = hrt->num_entries; - - if((count * hrt->entry_len + 8) > 2048) { - printk(KERN_WARNING "i2o_proc: HRT does not fit into buffer\n"); - len += sprintf(buf+len, - "HRT table too big to fit in buffer.\n"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "HRT has %d entries of %d bytes each.\n", - count, hrt->entry_len << 2); - - for(i = 0; i < count; i++) - { - len += sprintf(buf+len, "Entry %d:\n", i); - len += sprintf(buf+len, " Adapter ID: %0#10x\n", - hrt->hrt_entry[i].adapter_id); - len += sprintf(buf+len, " Controlling tid: %0#6x\n", - hrt->hrt_entry[i].parent_tid); - - if(hrt->hrt_entry[i].bus_type != 0x80) - { - bus = hrt->hrt_entry[i].bus_type; - len += sprintf(buf+len, " %s Information\n", bus_strings[bus]); - - switch(bus) - { - case I2O_BUS_LOCAL: - len += sprintf(buf+len, " IOBase: %0#6x,", - hrt->hrt_entry[i].bus.local_bus.LbBaseIOPort); - len += sprintf(buf+len, " MemoryBase: %0#10x\n", - hrt->hrt_entry[i].bus.local_bus.LbBaseMemoryAddress); - break; - - case I2O_BUS_ISA: - len += sprintf(buf+len, " IOBase: %0#6x,", - hrt->hrt_entry[i].bus.isa_bus.IsaBaseIOPort); - len += sprintf(buf+len, " MemoryBase: %0#10x,", - hrt->hrt_entry[i].bus.isa_bus.IsaBaseMemoryAddress); - len += sprintf(buf+len, " CSN: %0#4x,", - hrt->hrt_entry[i].bus.isa_bus.CSN); - break; - - case I2O_BUS_EISA: - len += sprintf(buf+len, " IOBase: %0#6x,", - hrt->hrt_entry[i].bus.eisa_bus.EisaBaseIOPort); - len += sprintf(buf+len, " MemoryBase: %0#10x,", - hrt->hrt_entry[i].bus.eisa_bus.EisaBaseMemoryAddress); - len += sprintf(buf+len, " Slot: %0#4x,", - hrt->hrt_entry[i].bus.eisa_bus.EisaSlotNumber); - break; - - case I2O_BUS_MCA: - len += sprintf(buf+len, " IOBase: %0#6x,", - hrt->hrt_entry[i].bus.mca_bus.McaBaseIOPort); - len += sprintf(buf+len, " MemoryBase: %0#10x,", - hrt->hrt_entry[i].bus.mca_bus.McaBaseMemoryAddress); - len += sprintf(buf+len, " Slot: %0#4x,", - hrt->hrt_entry[i].bus.mca_bus.McaSlotNumber); - break; - - case I2O_BUS_PCI: - len += sprintf(buf+len, " Bus: %0#4x", - hrt->hrt_entry[i].bus.pci_bus.PciBusNumber); - len += sprintf(buf+len, " Dev: %0#4x", - hrt->hrt_entry[i].bus.pci_bus.PciDeviceNumber); - len += sprintf(buf+len, " Func: %0#4x", - hrt->hrt_entry[i].bus.pci_bus.PciFunctionNumber); - len += sprintf(buf+len, " Vendor: %0#6x", - hrt->hrt_entry[i].bus.pci_bus.PciVendorID); - len += sprintf(buf+len, " Device: %0#6x\n", - hrt->hrt_entry[i].bus.pci_bus.PciDeviceID); - break; - - default: - len += sprintf(buf+len, " Unsupported Bus Type\n"); - } - } - else - len += sprintf(buf+len, " Unknown Bus Type\n"); - } - - spin_unlock(&i2o_proc_lock); - - return len; -} - -int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_controller *c = (struct i2o_controller*)data; - i2o_lct *lct = (i2o_lct *)c->lct; - int entries; - int i; - -#define BUS_TABLE_SIZE 3 - static char *bus_ports[] = - { - "Generic Bus", - "SCSI Bus", - "Fibre Channel Bus" - }; - - spin_lock(&i2o_proc_lock); - len = 0; - - entries = (lct->table_size - 3)/9; - - len += sprintf(buf, "LCT contains %d %s\n", entries, - entries == 1 ? "entry" : "entries"); - if(lct->boot_tid) - len += sprintf(buf+len, "Boot Device @ ID %d\n", lct->boot_tid); - - len += - sprintf(buf+len, "Current Change Indicator: %#10x\n", lct->change_ind); - - for(i = 0; i < entries; i++) - { - len += sprintf(buf+len, "Entry %d\n", i); - len += sprintf(buf+len, " Class, SubClass : %s", i2o_get_class_name(lct->lct_entry[i].class_id)); - - /* - * Classes which we'll print subclass info for - */ - switch(lct->lct_entry[i].class_id & 0xFFF) - { - case I2O_CLASS_RANDOM_BLOCK_STORAGE: - switch(lct->lct_entry[i].sub_class) - { - case 0x00: - len += sprintf(buf+len, ", Direct-Access Read/Write"); - break; - - case 0x04: - len += sprintf(buf+len, ", WORM Drive"); - break; - - case 0x05: - len += sprintf(buf+len, ", CD-ROM Drive"); - break; - - case 0x07: - len += sprintf(buf+len, ", Optical Memory Device"); - break; - - default: - len += sprintf(buf+len, ", Unknown (0x%02x)", - lct->lct_entry[i].sub_class); - break; - } - break; - - case I2O_CLASS_LAN: - switch(lct->lct_entry[i].sub_class & 0xFF) - { - case 0x30: - len += sprintf(buf+len, ", Ethernet"); - break; - - case 0x40: - len += sprintf(buf+len, ", 100base VG"); - break; - - case 0x50: - len += sprintf(buf+len, ", IEEE 802.5/Token-Ring"); - break; - - case 0x60: - len += sprintf(buf+len, ", ANSI X3T9.5 FDDI"); - break; - - case 0x70: - len += sprintf(buf+len, ", Fibre Channel"); - break; - - default: - len += sprintf(buf+len, ", Unknown Sub-Class (0x%02x)", - lct->lct_entry[i].sub_class & 0xFF); - break; - } - break; - - case I2O_CLASS_SCSI_PERIPHERAL: - if(lct->lct_entry[i].sub_class < SCSI_TABLE_SIZE) - len += sprintf(buf+len, ", %s", - scsi_devices[lct->lct_entry[i].sub_class]); - else - len += sprintf(buf+len, ", Unknown Device Type"); - break; - - case I2O_CLASS_BUS_ADAPTER_PORT: - if(lct->lct_entry[i].sub_class < BUS_TABLE_SIZE) - len += sprintf(buf+len, ", %s", - bus_ports[lct->lct_entry[i].sub_class]); - else - len += sprintf(buf+len, ", Unknown Bus Type"); - break; - } - len += sprintf(buf+len, "\n"); - - len += sprintf(buf+len, " Local TID : 0x%03x\n", lct->lct_entry[i].tid); - len += sprintf(buf+len, " User TID : 0x%03x\n", lct->lct_entry[i].user_tid); - len += sprintf(buf+len, " Parent TID : 0x%03x\n", - lct->lct_entry[i].parent_tid); - len += sprintf(buf+len, " Identity Tag : 0x%x%x%x%x%x%x%x%x\n", - lct->lct_entry[i].identity_tag[0], - lct->lct_entry[i].identity_tag[1], - lct->lct_entry[i].identity_tag[2], - lct->lct_entry[i].identity_tag[3], - lct->lct_entry[i].identity_tag[4], - lct->lct_entry[i].identity_tag[5], - lct->lct_entry[i].identity_tag[6], - lct->lct_entry[i].identity_tag[7]); - len += sprintf(buf+len, " Change Indicator : %0#10x\n", - lct->lct_entry[i].change_ind); - len += sprintf(buf+len, " Event Capab Mask : %0#10x\n", - lct->lct_entry[i].device_flags); - } - - spin_unlock(&i2o_proc_lock); - return len; -} - -int i2o_proc_read_status(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_controller *c = (struct i2o_controller*)data; - char prodstr[25]; - int version; - - spin_lock(&i2o_proc_lock); - len = 0; - - i2o_status_get(c); // reread the status block - - len += sprintf(buf+len,"Organization ID : %0#6x\n", - c->status_block->org_id); - - version = c->status_block->i2o_version; - -/* FIXME for Spec 2.0 - if (version == 0x02) { - len += sprintf(buf+len,"Lowest I2O version supported: "); - switch(workspace[2]) { - case 0x00: - len += sprintf(buf+len,"1.0\n"); - break; - case 0x01: - len += sprintf(buf+len,"1.5\n"); - break; - case 0x02: - len += sprintf(buf+len,"2.0\n"); - break; - } - - len += sprintf(buf+len, "Highest I2O version supported: "); - switch(workspace[3]) { - case 0x00: - len += sprintf(buf+len,"1.0\n"); - break; - case 0x01: - len += sprintf(buf+len,"1.5\n"); - break; - case 0x02: - len += sprintf(buf+len,"2.0\n"); - break; - } - } -*/ - len += sprintf(buf+len,"IOP ID : %0#5x\n", - c->status_block->iop_id); - len += sprintf(buf+len,"Host Unit ID : %0#6x\n", - c->status_block->host_unit_id); - len += sprintf(buf+len,"Segment Number : %0#5x\n", - c->status_block->segment_number); - - len += sprintf(buf+len, "I2O version : "); - switch (version) { - case 0x00: - len += sprintf(buf+len,"1.0\n"); - break; - case 0x01: - len += sprintf(buf+len,"1.5\n"); - break; - case 0x02: - len += sprintf(buf+len,"2.0\n"); - break; - default: - len += sprintf(buf+len,"Unknown version\n"); - } - - len += sprintf(buf+len, "IOP State : "); - switch (c->status_block->iop_state) { - case 0x01: - len += sprintf(buf+len,"INIT\n"); - break; - - case 0x02: - len += sprintf(buf+len,"RESET\n"); - break; - - case 0x04: - len += sprintf(buf+len,"HOLD\n"); - break; - - case 0x05: - len += sprintf(buf+len,"READY\n"); - break; - - case 0x08: - len += sprintf(buf+len,"OPERATIONAL\n"); - break; - - case 0x10: - len += sprintf(buf+len,"FAILED\n"); - break; - - case 0x11: - len += sprintf(buf+len,"FAULTED\n"); - break; - - default: - len += sprintf(buf+len,"Unknown\n"); - break; - } - - len += sprintf(buf+len,"Messenger Type : "); - switch (c->status_block->msg_type) { - case 0x00: - len += sprintf(buf+len,"Memory mapped\n"); - break; - case 0x01: - len += sprintf(buf+len,"Memory mapped only\n"); - break; - case 0x02: - len += sprintf(buf+len,"Remote only\n"); - break; - case 0x03: - len += sprintf(buf+len,"Memory mapped and remote\n"); - break; - default: - len += sprintf(buf+len,"Unknown\n"); - } - - len += sprintf(buf+len,"Inbound Frame Size : %d bytes\n", - c->status_block->inbound_frame_size<<2); - len += sprintf(buf+len,"Max Inbound Frames : %d\n", - c->status_block->max_inbound_frames); - len += sprintf(buf+len,"Current Inbound Frames : %d\n", - c->status_block->cur_inbound_frames); - len += sprintf(buf+len,"Max Outbound Frames : %d\n", - c->status_block->max_outbound_frames); - - /* Spec doesn't say if NULL terminated or not... */ - memcpy(prodstr, c->status_block->product_id, 24); - prodstr[24] = '\0'; - len += sprintf(buf+len,"Product ID : %s\n", prodstr); - len += sprintf(buf+len,"Expected LCT Size : %d bytes\n", - c->status_block->expected_lct_size); - - len += sprintf(buf+len,"IOP Capabilities\n"); - len += sprintf(buf+len," Context Field Size Support : "); - switch (c->status_block->iop_capabilities & 0x0000003) { - case 0: - len += sprintf(buf+len,"Supports only 32-bit context fields\n"); - break; - case 1: - len += sprintf(buf+len,"Supports only 64-bit context fields\n"); - break; - case 2: - len += sprintf(buf+len,"Supports 32-bit and 64-bit context fields, " - "but not concurrently\n"); - break; - case 3: - len += sprintf(buf+len,"Supports 32-bit and 64-bit context fields " - "concurrently\n"); - break; - default: - len += sprintf(buf+len,"0x%08x\n",c->status_block->iop_capabilities); - } - len += sprintf(buf+len," Current Context Field Size : "); - switch (c->status_block->iop_capabilities & 0x0000000C) { - case 0: - len += sprintf(buf+len,"not configured\n"); - break; - case 4: - len += sprintf(buf+len,"Supports only 32-bit context fields\n"); - break; - case 8: - len += sprintf(buf+len,"Supports only 64-bit context fields\n"); - break; - case 12: - len += sprintf(buf+len,"Supports both 32-bit or 64-bit context fields " - "concurrently\n"); - break; - default: - len += sprintf(buf+len,"\n"); - } - len += sprintf(buf+len," Inbound Peer Support : %s\n", - (c->status_block->iop_capabilities & 0x00000010) ? "Supported" : "Not supported"); - len += sprintf(buf+len," Outbound Peer Support : %s\n", - (c->status_block->iop_capabilities & 0x00000020) ? "Supported" : "Not supported"); - len += sprintf(buf+len," Peer to Peer Support : %s\n", - (c->status_block->iop_capabilities & 0x00000040) ? "Supported" : "Not supported"); - - len += sprintf(buf+len, "Desired private memory size : %d kB\n", - c->status_block->desired_mem_size>>10); - len += sprintf(buf+len, "Allocated private memory size : %d kB\n", - c->status_block->current_mem_size>>10); - len += sprintf(buf+len, "Private memory base address : %0#10x\n", - c->status_block->current_mem_base); - len += sprintf(buf+len, "Desired private I/O size : %d kB\n", - c->status_block->desired_io_size>>10); - len += sprintf(buf+len, "Allocated private I/O size : %d kB\n", - c->status_block->current_io_size>>10); - len += sprintf(buf+len, "Private I/O base address : %0#10x\n", - c->status_block->current_io_base); - - spin_unlock(&i2o_proc_lock); - - return len; -} - -int i2o_proc_read_hw(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_controller *c = (struct i2o_controller*)data; - static u32 work32[5]; - static u8 *work8 = (u8*)work32; - static u16 *work16 = (u16*)work32; - int token; - u32 hwcap; - - static char *cpu_table[] = - { - "Intel 80960 series", - "AMD2900 series", - "Motorola 68000 series", - "ARM series", - "MIPS series", - "Sparc series", - "PowerPC series", - "Intel x86 series" - }; - - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_scalar(c, ADAPTER_TID, 0x0000, -1, &work32, sizeof(work32)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0000 IOP Hardware"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "I2O Vendor ID : %0#6x\n", work16[0]); - len += sprintf(buf+len, "Product ID : %0#6x\n", work16[1]); - len += sprintf(buf+len, "CPU : "); - if(work8[16] > 8) - len += sprintf(buf+len, "Unknown\n"); - else - len += sprintf(buf+len, "%s\n", cpu_table[work8[16]]); - /* Anyone using ProcessorVersion? */ - - len += sprintf(buf+len, "RAM : %dkB\n", work32[1]>>10); - len += sprintf(buf+len, "Non-Volatile Mem : %dkB\n", work32[2]>>10); - - hwcap = work32[3]; - len += sprintf(buf+len, "Capabilities : 0x%08x\n", hwcap); - len += sprintf(buf+len, " [%s] Self booting\n", - (hwcap&0x00000001) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Upgradable IRTOS\n", - (hwcap&0x00000002) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Supports downloading DDMs\n", - (hwcap&0x00000004) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Supports installing DDMs\n", - (hwcap&0x00000008) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Battery-backed RAM\n", - (hwcap&0x00000010) ? "+" : "-"); - - spin_unlock(&i2o_proc_lock); - - return len; -} - - -/* Executive group 0003h - Executing DDM List (table) */ -int i2o_proc_read_ddm_table(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_controller *c = (struct i2o_controller*)data; - int token; - int i; - - typedef struct _i2o_exec_execute_ddm_table { - u16 ddm_tid; - u8 module_type; - u8 reserved; - u16 i2o_vendor_id; - u16 module_id; - u8 module_name_version[28]; - u32 data_size; - u32 code_size; - } i2o_exec_execute_ddm_table; - - struct - { - u16 result_count; - u16 pad; - u16 block_size; - u8 block_status; - u8 error_info_size; - u16 row_count; - u16 more_flag; - i2o_exec_execute_ddm_table ddm_table[MAX_I2O_MODULES]; - } result; - - i2o_exec_execute_ddm_table ddm_table; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - c, ADAPTER_TID, - 0x0003, -1, - NULL, 0, - &result, sizeof(result)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0003 Executing DDM List"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "Tid Module_type Vendor Mod_id Module_name Vrs Data_size Code_size\n"); - ddm_table=result.ddm_table[0]; - - for(i=0; i < result.row_count; ddm_table=result.ddm_table[++i]) - { - len += sprintf(buf+len, "0x%03x ", ddm_table.ddm_tid & 0xFFF); - - switch(ddm_table.module_type) - { - case 0x01: - len += sprintf(buf+len, "Downloaded DDM "); - break; - case 0x22: - len += sprintf(buf+len, "Embedded DDM "); - break; - default: - len += sprintf(buf+len, " "); - } - - len += sprintf(buf+len, "%-#7x", ddm_table.i2o_vendor_id); - len += sprintf(buf+len, "%-#8x", ddm_table.module_id); - len += sprintf(buf+len, "%-29s", chtostr(ddm_table.module_name_version, 28)); - len += sprintf(buf+len, "%9d ", ddm_table.data_size); - len += sprintf(buf+len, "%8d", ddm_table.code_size); - - len += sprintf(buf+len, "\n"); - } - - spin_unlock(&i2o_proc_lock); - - return len; -} - - -/* Executive group 0004h - Driver Store (scalar) */ -int i2o_proc_read_driver_store(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_controller *c = (struct i2o_controller*)data; - u32 work32[8]; - int token; - - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_scalar(c, ADAPTER_TID, 0x0004, -1, &work32, sizeof(work32)); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0004 Driver Store"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "Module limit : %d\n" - "Module count : %d\n" - "Current space : %d kB\n" - "Free space : %d kB\n", - work32[0], work32[1], work32[2]>>10, work32[3]>>10); - - spin_unlock(&i2o_proc_lock); - - return len; -} - - -/* Executive group 0005h - Driver Store Table (table) */ -int i2o_proc_read_drivers_stored(char *buf, char **start, off_t offset, - int len, int *eof, void *data) -{ - typedef struct _i2o_driver_store { - u16 stored_ddm_index; - u8 module_type; - u8 reserved; - u16 i2o_vendor_id; - u16 module_id; - u8 module_name_version[28]; - u8 date[8]; - u32 module_size; - u32 mpb_size; - u32 module_flags; - } i2o_driver_store_table; - - struct i2o_controller *c = (struct i2o_controller*)data; - int token; - int i; - - struct - { - u16 result_count; - u16 pad; - u16 block_size; - u8 block_status; - u8 error_info_size; - u16 row_count; - u16 more_flag; - i2o_driver_store_table dst[MAX_I2O_MODULES]; - } result; - - i2o_driver_store_table dst; - - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - c, ADAPTER_TID, 0x0005, -1, NULL, 0, - &result, sizeof(result)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0005 DRIVER STORE TABLE"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "# Module_type Vendor Mod_id Module_name Vrs" - "Date Mod_size Par_size Flags\n"); - for(i=0, dst=result.dst[0]; i < result.row_count; dst=result.dst[++i]) - { - len += sprintf(buf+len, "%-3d", dst.stored_ddm_index); - switch(dst.module_type) - { - case 0x01: - len += sprintf(buf+len, "Downloaded DDM "); - break; - case 0x22: - len += sprintf(buf+len, "Embedded DDM "); - break; - default: - len += sprintf(buf+len, " "); - } - -#if 0 - if(c->i2oversion == 0x02) - len += sprintf(buf+len, "%-d", dst.module_state); -#endif - - len += sprintf(buf+len, "%-#7x", dst.i2o_vendor_id); - len += sprintf(buf+len, "%-#8x", dst.module_id); - len += sprintf(buf+len, "%-29s", chtostr(dst.module_name_version,28)); - len += sprintf(buf+len, "%-9s", chtostr(dst.date,8)); - len += sprintf(buf+len, "%8d ", dst.module_size); - len += sprintf(buf+len, "%8d ", dst.mpb_size); - len += sprintf(buf+len, "0x%04x", dst.module_flags); -#if 0 - if(c->i2oversion == 0x02) - len += sprintf(buf+len, "%d", - dst.notification_level); -#endif - len += sprintf(buf+len, "\n"); - } - - spin_unlock(&i2o_proc_lock); - - return len; -} - - -/* Generic group F000h - Params Descriptor (table) */ -int i2o_proc_read_groups(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - int token; - int i; - u8 properties; - - typedef struct _i2o_group_info - { - u16 group_number; - u16 field_count; - u16 row_count; - u8 properties; - u8 reserved; - } i2o_group_info; - - struct - { - u16 result_count; - u16 pad; - u16 block_size; - u8 block_status; - u8 error_info_size; - u16 row_count; - u16 more_flag; - i2o_group_info group[256]; - } result; - - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, 0xF000, -1, NULL, 0, - &result, sizeof(result)); - - if (token < 0) { - len = i2o_report_query_status(buf+len, token, "0xF000 Params Descriptor"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "# Group FieldCount RowCount Type Add Del Clear\n"); - - for (i=0; i < result.row_count; i++) - { - len += sprintf(buf+len, "%-3d", i); - len += sprintf(buf+len, "0x%04X ", result.group[i].group_number); - len += sprintf(buf+len, "%10d ", result.group[i].field_count); - len += sprintf(buf+len, "%8d ", result.group[i].row_count); - - properties = result.group[i].properties; - if (properties & 0x1) len += sprintf(buf+len, "Table "); - else len += sprintf(buf+len, "Scalar "); - if (properties & 0x2) len += sprintf(buf+len, " + "); - else len += sprintf(buf+len, " - "); - if (properties & 0x4) len += sprintf(buf+len, " + "); - else len += sprintf(buf+len, " - "); - if (properties & 0x8) len += sprintf(buf+len, " + "); - else len += sprintf(buf+len, " - "); - - len += sprintf(buf+len, "\n"); - } - - if (result.more_flag) - len += sprintf(buf+len, "There is more...\n"); - - spin_unlock(&i2o_proc_lock); - - return len; -} - - -/* Generic group F001h - Physical Device Table (table) */ -int i2o_proc_read_phys_device(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - int token; - int i; - - struct - { - u16 result_count; - u16 pad; - u16 block_size; - u8 block_status; - u8 error_info_size; - u16 row_count; - u16 more_flag; - u32 adapter_id[64]; - } result; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, - 0xF001, -1, NULL, 0, - &result, sizeof(result)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF001 Physical Device Table"); - spin_unlock(&i2o_proc_lock); - return len; - } - - if (result.row_count) - len += sprintf(buf+len, "# AdapterId\n"); - - for (i=0; i < result.row_count; i++) - { - len += sprintf(buf+len, "%-2d", i); - len += sprintf(buf+len, "%#7x\n", result.adapter_id[i]); - } - - if (result.more_flag) - len += sprintf(buf+len, "There is more...\n"); - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* Generic group F002h - Claimed Table (table) */ -int i2o_proc_read_claimed(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - int token; - int i; - - struct { - u16 result_count; - u16 pad; - u16 block_size; - u8 block_status; - u8 error_info_size; - u16 row_count; - u16 more_flag; - u16 claimed_tid[64]; - } result; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, - 0xF002, -1, NULL, 0, - &result, sizeof(result)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF002 Claimed Table"); - spin_unlock(&i2o_proc_lock); - return len; - } - - if (result.row_count) - len += sprintf(buf+len, "# ClaimedTid\n"); - - for (i=0; i < result.row_count; i++) - { - len += sprintf(buf+len, "%-2d", i); - len += sprintf(buf+len, "%#7x\n", result.claimed_tid[i]); - } - - if (result.more_flag) - len += sprintf(buf+len, "There is more...\n"); - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* Generic group F003h - User Table (table) */ -int i2o_proc_read_users(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - int token; - int i; - - typedef struct _i2o_user_table - { - u16 instance; - u16 user_tid; - u8 claim_type; - u8 reserved1; - u16 reserved2; - } i2o_user_table; - - struct - { - u16 result_count; - u16 pad; - u16 block_size; - u8 block_status; - u8 error_info_size; - u16 row_count; - u16 more_flag; - i2o_user_table user[64]; - } result; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, - 0xF003, -1, NULL, 0, - &result, sizeof(result)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF003 User Table"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "# Instance UserTid ClaimType\n"); - - for(i=0; i < result.row_count; i++) - { - len += sprintf(buf+len, "%-3d", i); - len += sprintf(buf+len, "%#8x ", result.user[i].instance); - len += sprintf(buf+len, "%#7x ", result.user[i].user_tid); - len += sprintf(buf+len, "%#9x\n", result.user[i].claim_type); - } - - if (result.more_flag) - len += sprintf(buf+len, "There is more...\n"); - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* Generic group F005h - Private message extensions (table) (optional) */ -int i2o_proc_read_priv_msgs(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - int token; - int i; - - typedef struct _i2o_private - { - u16 ext_instance; - u16 organization_id; - u16 x_function_code; - } i2o_private; - - struct - { - u16 result_count; - u16 pad; - u16 block_size; - u8 block_status; - u8 error_info_size; - u16 row_count; - u16 more_flag; - i2o_private extension[64]; - } result; - - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, - 0xF000, -1, - NULL, 0, - &result, sizeof(result)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF005 Private Message Extensions (optional)"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "Instance# OrgId FunctionCode\n"); - - for(i=0; i < result.row_count; i++) - { - len += sprintf(buf+len, "%0#9x ", result.extension[i].ext_instance); - len += sprintf(buf+len, "%0#6x ", result.extension[i].organization_id); - len += sprintf(buf+len, "%0#6x", result.extension[i].x_function_code); - - len += sprintf(buf+len, "\n"); - } - - if(result.more_flag) - len += sprintf(buf+len, "There is more...\n"); - - spin_unlock(&i2o_proc_lock); - - return len; -} - - -/* Generic group F006h - Authorized User Table (table) */ -int i2o_proc_read_authorized_users(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - int token; - int i; - - struct - { - u16 result_count; - u16 pad; - u16 block_size; - u8 block_status; - u8 error_info_size; - u16 row_count; - u16 more_flag; - u32 alternate_tid[64]; - } result; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, - 0xF006, -1, - NULL, 0, - &result, sizeof(result)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF006 Autohorized User Table"); - spin_unlock(&i2o_proc_lock); - return len; - } - - if (result.row_count) - len += sprintf(buf+len, "# AlternateTid\n"); - - for(i=0; i < result.row_count; i++) - { - len += sprintf(buf+len, "%-2d", i); - len += sprintf(buf+len, "%#7x ", result.alternate_tid[i]); - } - - if (result.more_flag) - len += sprintf(buf+len, "There is more...\n"); - - spin_unlock(&i2o_proc_lock); - return len; -} - - -/* Generic group F100h - Device Identity (scalar) */ -int i2o_proc_read_dev_identity(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[128]; // allow for "stuff" + up to 256 byte (max) serial number - // == (allow) 512d bytes (max) - static u16 *work16 = (u16*)work32; - int token; - - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0xF100, -1, - &work32, sizeof(work32)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token ,"0xF100 Device Identity"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "Device Class : %s\n", i2o_get_class_name(work16[0])); - len += sprintf(buf+len, "Owner TID : %0#5x\n", work16[2]); - len += sprintf(buf+len, "Parent TID : %0#5x\n", work16[3]); - len += sprintf(buf+len, "Vendor info : %s\n", chtostr((u8 *)(work32+2), 16)); - len += sprintf(buf+len, "Product info : %s\n", chtostr((u8 *)(work32+6), 16)); - len += sprintf(buf+len, "Description : %s\n", chtostr((u8 *)(work32+10), 16)); - len += sprintf(buf+len, "Product rev. : %s\n", chtostr((u8 *)(work32+14), 8)); - - len += sprintf(buf+len, "Serial number : "); - len = print_serial_number(buf, len, - (u8*)(work32+16), - /* allow for SNLen plus - * possible trailing '\0' - */ - sizeof(work32)-(16*sizeof(u32))-2 - ); - len += sprintf(buf+len, "\n"); - - spin_unlock(&i2o_proc_lock); - - return len; -} - - -int i2o_proc_read_dev_name(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - - if ( d->dev_name[0] == '\0' ) - return 0; - - len = sprintf(buf, "%s\n", d->dev_name); - - return len; -} - - -/* Generic group F101h - DDM Identity (scalar) */ -int i2o_proc_read_ddm_identity(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - int token; - - struct - { - u16 ddm_tid; - u8 module_name[24]; - u8 module_rev[8]; - u8 sn_format; - u8 serial_number[12]; - u8 pad[256]; // allow up to 256 byte (max) serial number - } result; - - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0xF101, -1, - &result, sizeof(result)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF101 DDM Identity"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "Registering DDM TID : 0x%03x\n", result.ddm_tid); - len += sprintf(buf+len, "Module name : %s\n", chtostr(result.module_name, 24)); - len += sprintf(buf+len, "Module revision : %s\n", chtostr(result.module_rev, 8)); - - len += sprintf(buf+len, "Serial number : "); - len = print_serial_number(buf, len, result.serial_number, sizeof(result)-36); - /* allow for SNLen plus possible trailing '\0' */ - - len += sprintf(buf+len, "\n"); - - spin_unlock(&i2o_proc_lock); - - return len; -} - -/* Generic group F102h - User Information (scalar) */ -int i2o_proc_read_uinfo(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - int token; - - struct - { - u8 device_name[64]; - u8 service_name[64]; - u8 physical_location[64]; - u8 instance_number[4]; - } result; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0xF102, -1, - &result, sizeof(result)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF102 User Information"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "Device name : %s\n", chtostr(result.device_name, 64)); - len += sprintf(buf+len, "Service name : %s\n", chtostr(result.service_name, 64)); - len += sprintf(buf+len, "Physical name : %s\n", chtostr(result.physical_location, 64)); - len += sprintf(buf+len, "Instance number : %s\n", chtostr(result.instance_number, 4)); - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* Generic group F103h - SGL Operating Limits (scalar) */ -int i2o_proc_read_sgl_limits(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[12]; - static u16 *work16 = (u16 *)work32; - static u8 *work8 = (u8 *)work32; - int token; - - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0xF103, -1, - &work32, sizeof(work32)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF103 SGL Operating Limits"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "SGL chain size : %d\n", work32[0]); - len += sprintf(buf+len, "Max SGL chain size : %d\n", work32[1]); - len += sprintf(buf+len, "SGL chain size target : %d\n", work32[2]); - len += sprintf(buf+len, "SGL frag count : %d\n", work16[6]); - len += sprintf(buf+len, "Max SGL frag count : %d\n", work16[7]); - len += sprintf(buf+len, "SGL frag count target : %d\n", work16[8]); - - if (d->i2oversion == 0x02) - { - len += sprintf(buf+len, "SGL data alignment : %d\n", work16[8]); - len += sprintf(buf+len, "SGL addr limit : %d\n", work8[20]); - len += sprintf(buf+len, "SGL addr sizes supported : "); - if (work8[21] & 0x01) - len += sprintf(buf+len, "32 bit "); - if (work8[21] & 0x02) - len += sprintf(buf+len, "64 bit "); - if (work8[21] & 0x04) - len += sprintf(buf+len, "96 bit "); - if (work8[21] & 0x08) - len += sprintf(buf+len, "128 bit "); - len += sprintf(buf+len, "\n"); - } - - spin_unlock(&i2o_proc_lock); - - return len; -} - -/* Generic group F200h - Sensors (scalar) */ -int i2o_proc_read_sensors(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - int token; - - struct - { - u16 sensor_instance; - u8 component; - u16 component_instance; - u8 sensor_class; - u8 sensor_type; - u8 scaling_exponent; - u32 actual_reading; - u32 minimum_reading; - u32 low2lowcat_treshold; - u32 lowcat2low_treshold; - u32 lowwarn2low_treshold; - u32 low2lowwarn_treshold; - u32 norm2lowwarn_treshold; - u32 lowwarn2norm_treshold; - u32 nominal_reading; - u32 hiwarn2norm_treshold; - u32 norm2hiwarn_treshold; - u32 high2hiwarn_treshold; - u32 hiwarn2high_treshold; - u32 hicat2high_treshold; - u32 hi2hicat_treshold; - u32 maximum_reading; - u8 sensor_state; - u16 event_enable; - } result; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0xF200, -1, - &result, sizeof(result)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF200 Sensors (optional)"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "Sensor instance : %d\n", result.sensor_instance); - - len += sprintf(buf+len, "Component : %d = ", result.component); - switch (result.component) - { - case 0: len += sprintf(buf+len, "Other"); - break; - case 1: len += sprintf(buf+len, "Planar logic Board"); - break; - case 2: len += sprintf(buf+len, "CPU"); - break; - case 3: len += sprintf(buf+len, "Chassis"); - break; - case 4: len += sprintf(buf+len, "Power Supply"); - break; - case 5: len += sprintf(buf+len, "Storage"); - break; - case 6: len += sprintf(buf+len, "External"); - break; - } - len += sprintf(buf+len,"\n"); - - len += sprintf(buf+len, "Component instance : %d\n", result.component_instance); - len += sprintf(buf+len, "Sensor class : %s\n", - result.sensor_class ? "Analog" : "Digital"); - - len += sprintf(buf+len, "Sensor type : %d = ",result.sensor_type); - switch (result.sensor_type) - { - case 0: len += sprintf(buf+len, "Other\n"); - break; - case 1: len += sprintf(buf+len, "Thermal\n"); - break; - case 2: len += sprintf(buf+len, "DC voltage (DC volts)\n"); - break; - case 3: len += sprintf(buf+len, "AC voltage (AC volts)\n"); - break; - case 4: len += sprintf(buf+len, "DC current (DC amps)\n"); - break; - case 5: len += sprintf(buf+len, "AC current (AC volts)\n"); - break; - case 6: len += sprintf(buf+len, "Door open\n"); - break; - case 7: len += sprintf(buf+len, "Fan operational\n"); - break; - } - - len += sprintf(buf+len, "Scaling exponent : %d\n", result.scaling_exponent); - len += sprintf(buf+len, "Actual reading : %d\n", result.actual_reading); - len += sprintf(buf+len, "Minimum reading : %d\n", result.minimum_reading); - len += sprintf(buf+len, "Low2LowCat treshold : %d\n", result.low2lowcat_treshold); - len += sprintf(buf+len, "LowCat2Low treshold : %d\n", result.lowcat2low_treshold); - len += sprintf(buf+len, "LowWarn2Low treshold : %d\n", result.lowwarn2low_treshold); - len += sprintf(buf+len, "Low2LowWarn treshold : %d\n", result.low2lowwarn_treshold); - len += sprintf(buf+len, "Norm2LowWarn treshold : %d\n", result.norm2lowwarn_treshold); - len += sprintf(buf+len, "LowWarn2Norm treshold : %d\n", result.lowwarn2norm_treshold); - len += sprintf(buf+len, "Nominal reading : %d\n", result.nominal_reading); - len += sprintf(buf+len, "HiWarn2Norm treshold : %d\n", result.hiwarn2norm_treshold); - len += sprintf(buf+len, "Norm2HiWarn treshold : %d\n", result.norm2hiwarn_treshold); - len += sprintf(buf+len, "High2HiWarn treshold : %d\n", result.high2hiwarn_treshold); - len += sprintf(buf+len, "HiWarn2High treshold : %d\n", result.hiwarn2high_treshold); - len += sprintf(buf+len, "HiCat2High treshold : %d\n", result.hicat2high_treshold); - len += sprintf(buf+len, "High2HiCat treshold : %d\n", result.hi2hicat_treshold); - len += sprintf(buf+len, "Maximum reading : %d\n", result.maximum_reading); - - len += sprintf(buf+len, "Sensor state : %d = ", result.sensor_state); - switch (result.sensor_state) - { - case 0: len += sprintf(buf+len, "Normal\n"); - break; - case 1: len += sprintf(buf+len, "Abnormal\n"); - break; - case 2: len += sprintf(buf+len, "Unknown\n"); - break; - case 3: len += sprintf(buf+len, "Low Catastrophic (LoCat)\n"); - break; - case 4: len += sprintf(buf+len, "Low (Low)\n"); - break; - case 5: len += sprintf(buf+len, "Low Warning (LoWarn)\n"); - break; - case 6: len += sprintf(buf+len, "High Warning (HiWarn)\n"); - break; - case 7: len += sprintf(buf+len, "High (High)\n"); - break; - case 8: len += sprintf(buf+len, "High Catastrophic (HiCat)\n"); - break; - } - - len += sprintf(buf+len, "Event_enable : 0x%02X\n", result.event_enable); - len += sprintf(buf+len, " [%s] Operational state change. \n", - (result.event_enable & 0x01) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] Low catastrophic. \n", - (result.event_enable & 0x02) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] Low reading. \n", - (result.event_enable & 0x04) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] Low warning. \n", - (result.event_enable & 0x08) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] Change back to normal from out of range state. \n", - (result.event_enable & 0x10) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] High warning. \n", - (result.event_enable & 0x20) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] High reading. \n", - (result.event_enable & 0x40) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] High catastrophic. \n", - (result.event_enable & 0x80) ? "+" : "-" ); - - spin_unlock(&i2o_proc_lock); - return len; -} - - -static int print_serial_number(char *buff, int pos, u8 *serialno, int max_len) -{ - int i; - - /* 19990419 -sralston - * The I2O v1.5 (and v2.0 so far) "official specification" - * got serial numbers WRONG! - * Apparently, and despite what Section 3.4.4 says and - * Figure 3-35 shows (pg 3-39 in the pdf doc), - * the convention / consensus seems to be: - * + First byte is SNFormat - * + Second byte is SNLen (but only if SNFormat==7 (?)) - * + (v2.0) SCSI+BS may use IEEE Registered (64 or 128 bit) format - */ - switch(serialno[0]) - { - case I2O_SNFORMAT_BINARY: /* Binary */ - pos += sprintf(buff+pos, "0x"); - for(i = 0; i < serialno[1]; i++) - { - pos += sprintf(buff+pos, "%02X", serialno[2+i]); - } - break; - - case I2O_SNFORMAT_ASCII: /* ASCII */ - if ( serialno[1] < ' ' ) /* printable or SNLen? */ - { - /* sanity */ - max_len = (max_len < serialno[1]) ? max_len : serialno[1]; - serialno[1+max_len] = '\0'; - - /* just print it */ - pos += sprintf(buff+pos, "%s", &serialno[2]); - } - else - { - /* print chars for specified length */ - for(i = 0; i < serialno[1]; i++) - { - pos += sprintf(buff+pos, "%c", serialno[2+i]); - } - } - break; - - case I2O_SNFORMAT_UNICODE: /* UNICODE */ - pos += sprintf(buff+pos, "UNICODE Format. Can't Display\n"); - break; - - case I2O_SNFORMAT_LAN48_MAC: /* LAN-48 MAC Address */ - pos += sprintf(buff+pos, - "LAN-48 MAC address @ %02X:%02X:%02X:%02X:%02X:%02X", - serialno[2], serialno[3], - serialno[4], serialno[5], - serialno[6], serialno[7]); - break; - - case I2O_SNFORMAT_WAN: /* WAN MAC Address */ - /* FIXME: Figure out what a WAN access address looks like?? */ - pos += sprintf(buff+pos, "WAN Access Address"); - break; - -/* plus new in v2.0 */ - case I2O_SNFORMAT_LAN64_MAC: /* LAN-64 MAC Address */ - /* FIXME: Figure out what a LAN-64 address really looks like?? */ - pos += sprintf(buff+pos, - "LAN-64 MAC address @ [?:%02X:%02X:?] %02X:%02X:%02X:%02X:%02X:%02X", - serialno[8], serialno[9], - serialno[2], serialno[3], - serialno[4], serialno[5], - serialno[6], serialno[7]); - break; - - - case I2O_SNFORMAT_DDM: /* I2O DDM */ - pos += sprintf(buff+pos, - "DDM: Tid=%03Xh, Rsvd=%04Xh, OrgId=%04Xh", - *(u16*)&serialno[2], - *(u16*)&serialno[4], - *(u16*)&serialno[6]); - break; - - case I2O_SNFORMAT_IEEE_REG64: /* IEEE Registered (64-bit) */ - case I2O_SNFORMAT_IEEE_REG128: /* IEEE Registered (128-bit) */ - /* FIXME: Figure if this is even close?? */ - pos += sprintf(buff+pos, - "IEEE NodeName(hi,lo)=(%08Xh:%08Xh), PortName(hi,lo)=(%08Xh:%08Xh)\n", - *(u32*)&serialno[2], - *(u32*)&serialno[6], - *(u32*)&serialno[10], - *(u32*)&serialno[14]); - break; - - - case I2O_SNFORMAT_UNKNOWN: /* Unknown 0 */ - case I2O_SNFORMAT_UNKNOWN2: /* Unknown 0xff */ - default: - pos += sprintf(buff+pos, "Unknown data format (0x%02x)", - serialno[0]); - break; - } - - return pos; -} - -const char * i2o_get_connector_type(int conn) -{ - int idx = 16; - static char *i2o_connector_type[] = { - "OTHER", - "UNKNOWN", - "AUI", - "UTP", - "BNC", - "RJ45", - "STP DB9", - "FIBER MIC", - "APPLE AUI", - "MII", - "DB9", - "HSSDC", - "DUPLEX SC FIBER", - "DUPLEX ST FIBER", - "TNC/BNC", - "HW DEFAULT" - }; - - switch(conn) - { - case 0x00000000: - idx = 0; - break; - case 0x00000001: - idx = 1; - break; - case 0x00000002: - idx = 2; - break; - case 0x00000003: - idx = 3; - break; - case 0x00000004: - idx = 4; - break; - case 0x00000005: - idx = 5; - break; - case 0x00000006: - idx = 6; - break; - case 0x00000007: - idx = 7; - break; - case 0x00000008: - idx = 8; - break; - case 0x00000009: - idx = 9; - break; - case 0x0000000A: - idx = 10; - break; - case 0x0000000B: - idx = 11; - break; - case 0x0000000C: - idx = 12; - break; - case 0x0000000D: - idx = 13; - break; - case 0x0000000E: - idx = 14; - break; - case 0xFFFFFFFF: - idx = 15; - break; - } - - return i2o_connector_type[idx]; -} - - -const char * i2o_get_connection_type(int conn) -{ - int idx = 0; - static char *i2o_connection_type[] = { - "Unknown", - "AUI", - "10BASE5", - "FIORL", - "10BASE2", - "10BROAD36", - "10BASE-T", - "10BASE-FP", - "10BASE-FB", - "10BASE-FL", - "100BASE-TX", - "100BASE-FX", - "100BASE-T4", - "1000BASE-SX", - "1000BASE-LX", - "1000BASE-CX", - "1000BASE-T", - "100VG-ETHERNET", - "100VG-TOKEN RING", - "4MBIT TOKEN RING", - "16 Mb Token Ring", - "125 MBAUD FDDI", - "Point-to-point", - "Arbitrated loop", - "Public loop", - "Fabric", - "Emulation", - "Other", - "HW default" - }; - - switch(conn) - { - case I2O_LAN_UNKNOWN: - idx = 0; - break; - case I2O_LAN_AUI: - idx = 1; - break; - case I2O_LAN_10BASE5: - idx = 2; - break; - case I2O_LAN_FIORL: - idx = 3; - break; - case I2O_LAN_10BASE2: - idx = 4; - break; - case I2O_LAN_10BROAD36: - idx = 5; - break; - case I2O_LAN_10BASE_T: - idx = 6; - break; - case I2O_LAN_10BASE_FP: - idx = 7; - break; - case I2O_LAN_10BASE_FB: - idx = 8; - break; - case I2O_LAN_10BASE_FL: - idx = 9; - break; - case I2O_LAN_100BASE_TX: - idx = 10; - break; - case I2O_LAN_100BASE_FX: - idx = 11; - break; - case I2O_LAN_100BASE_T4: - idx = 12; - break; - case I2O_LAN_1000BASE_SX: - idx = 13; - break; - case I2O_LAN_1000BASE_LX: - idx = 14; - break; - case I2O_LAN_1000BASE_CX: - idx = 15; - break; - case I2O_LAN_1000BASE_T: - idx = 16; - break; - case I2O_LAN_100VG_ETHERNET: - idx = 17; - break; - case I2O_LAN_100VG_TR: - idx = 18; - break; - case I2O_LAN_4MBIT: - idx = 19; - break; - case I2O_LAN_16MBIT: - idx = 20; - break; - case I2O_LAN_125MBAUD: - idx = 21; - break; - case I2O_LAN_POINT_POINT: - idx = 22; - break; - case I2O_LAN_ARB_LOOP: - idx = 23; - break; - case I2O_LAN_PUBLIC_LOOP: - idx = 24; - break; - case I2O_LAN_FABRIC: - idx = 25; - break; - case I2O_LAN_EMULATION: - idx = 26; - break; - case I2O_LAN_OTHER: - idx = 27; - break; - case I2O_LAN_DEFAULT: - idx = 28; - break; - } - - return i2o_connection_type[idx]; -} - - -/* LAN group 0000h - Device info (scalar) */ -int i2o_proc_read_lan_dev_info(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[56]; - static u8 *work8 = (u8*)work32; - static u16 *work16 = (u16*)work32; - static u64 *work64 = (u64*)work32; - int token; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0000, -1, &work32, 56*4); - if (token < 0) { - len += i2o_report_query_status(buf+len, token, "0x0000 LAN Device Info"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "LAN Type : "); - switch (work16[0]) - { - case 0x0030: - len += sprintf(buf+len, "Ethernet, "); - break; - case 0x0040: - len += sprintf(buf+len, "100Base VG, "); - break; - case 0x0050: - len += sprintf(buf+len, "Token Ring, "); - break; - case 0x0060: - len += sprintf(buf+len, "FDDI, "); - break; - case 0x0070: - len += sprintf(buf+len, "Fibre Channel, "); - break; - default: - len += sprintf(buf+len, "Unknown type (0x%04x), ", work16[0]); - break; - } - - if (work16[1]&0x00000001) - len += sprintf(buf+len, "emulated LAN, "); - else - len += sprintf(buf+len, "physical LAN port, "); - - if (work16[1]&0x00000002) - len += sprintf(buf+len, "full duplex\n"); - else - len += sprintf(buf+len, "simplex\n"); - - len += sprintf(buf+len, "Address format : "); - switch(work8[4]) { - case 0x00: - len += sprintf(buf+len, "IEEE 48bit\n"); - break; - case 0x01: - len += sprintf(buf+len, "FC IEEE\n"); - break; - default: - len += sprintf(buf+len, "Unknown (0x%02x)\n", work8[4]); - break; - } - - len += sprintf(buf+len, "State : "); - switch(work8[5]) - { - case 0x00: - len += sprintf(buf+len, "Unknown\n"); - break; - case 0x01: - len += sprintf(buf+len, "Unclaimed\n"); - break; - case 0x02: - len += sprintf(buf+len, "Operational\n"); - break; - case 0x03: - len += sprintf(buf+len, "Suspended\n"); - break; - case 0x04: - len += sprintf(buf+len, "Resetting\n"); - break; - case 0x05: - len += sprintf(buf+len, "ERROR: "); - if(work16[3]&0x0001) - len += sprintf(buf+len, "TxCU inoperative "); - if(work16[3]&0x0002) - len += sprintf(buf+len, "RxCU inoperative "); - if(work16[3]&0x0004) - len += sprintf(buf+len, "Local mem alloc "); - len += sprintf(buf+len, "\n"); - break; - case 0x06: - len += sprintf(buf+len, "Operational no Rx\n"); - break; - case 0x07: - len += sprintf(buf+len, "Suspended no Rx\n"); - break; - default: - len += sprintf(buf+len, "Unspecified\n"); - break; - } - - len += sprintf(buf+len, "Min packet size : %d\n", work32[2]); - len += sprintf(buf+len, "Max packet size : %d\n", work32[3]); - len += sprintf(buf+len, "HW address : " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - work8[16],work8[17],work8[18],work8[19], - work8[20],work8[21],work8[22],work8[23]); - - len += sprintf(buf+len, "Max Tx wire speed : %d bps\n", (int)work64[3]); - len += sprintf(buf+len, "Max Rx wire speed : %d bps\n", (int)work64[4]); - - len += sprintf(buf+len, "Min SDU packet size : 0x%08x\n", work32[10]); - len += sprintf(buf+len, "Max SDU packet size : 0x%08x\n", work32[11]); - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* LAN group 0001h - MAC address table (scalar) */ -int i2o_proc_read_lan_mac_addr(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[48]; - static u8 *work8 = (u8*)work32; - int token; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0001, -1, &work32, 48*4); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0001 LAN MAC Address"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "Active address : " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - work8[0],work8[1],work8[2],work8[3], - work8[4],work8[5],work8[6],work8[7]); - len += sprintf(buf+len, "Current address : " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - work8[8],work8[9],work8[10],work8[11], - work8[12],work8[13],work8[14],work8[15]); - len += sprintf(buf+len, "Functional address mask : " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - work8[16],work8[17],work8[18],work8[19], - work8[20],work8[21],work8[22],work8[23]); - - len += sprintf(buf+len,"HW/DDM capabilities : 0x%08x\n", work32[7]); - len += sprintf(buf+len," [%s] Unicast packets supported\n", - (work32[7]&0x00000001)?"+":"-"); - len += sprintf(buf+len," [%s] Promiscuous mode supported\n", - (work32[7]&0x00000002)?"+":"-"); - len += sprintf(buf+len," [%s] Promiscuous multicast mode supported\n", - (work32[7]&0x00000004)?"+":"-"); - len += sprintf(buf+len," [%s] Broadcast reception disabling supported\n", - (work32[7]&0x00000100)?"+":"-"); - len += sprintf(buf+len," [%s] Multicast reception disabling supported\n", - (work32[7]&0x00000200)?"+":"-"); - len += sprintf(buf+len," [%s] Functional address disabling supported\n", - (work32[7]&0x00000400)?"+":"-"); - len += sprintf(buf+len," [%s] MAC reporting supported\n", - (work32[7]&0x00000800)?"+":"-"); - - len += sprintf(buf+len,"Filter mask : 0x%08x\n", work32[6]); - len += sprintf(buf+len," [%s] Unicast packets disable\n", - (work32[6]&0x00000001)?"+":"-"); - len += sprintf(buf+len," [%s] Promiscuous mode enable\n", - (work32[6]&0x00000002)?"+":"-"); - len += sprintf(buf+len," [%s] Promiscuous multicast mode enable\n", - (work32[6]&0x00000004)?"+":"-"); - len += sprintf(buf+len," [%s] Broadcast packets disable\n", - (work32[6]&0x00000100)?"+":"-"); - len += sprintf(buf+len," [%s] Multicast packets disable\n", - (work32[6]&0x00000200)?"+":"-"); - len += sprintf(buf+len," [%s] Functional address disable\n", - (work32[6]&0x00000400)?"+":"-"); - - if (work32[7]&0x00000800) { - len += sprintf(buf+len, " MAC reporting mode : "); - if (work32[6]&0x00000800) - len += sprintf(buf+len, "Pass only priority MAC packets to user\n"); - else if (work32[6]&0x00001000) - len += sprintf(buf+len, "Pass all MAC packets to user\n"); - else if (work32[6]&0x00001800) - len += sprintf(buf+len, "Pass all MAC packets (promiscuous) to user\n"); - else - len += sprintf(buf+len, "Do not pass MAC packets to user\n"); - } - len += sprintf(buf+len, "Number of multicast addresses : %d\n", work32[8]); - len += sprintf(buf+len, "Perfect filtering for max %d multicast addresses\n", - work32[9]); - len += sprintf(buf+len, "Imperfect filtering for max %d multicast addresses\n", - work32[10]); - - spin_unlock(&i2o_proc_lock); - - return len; -} - -/* LAN group 0002h - Multicast MAC address table (table) */ -int i2o_proc_read_lan_mcast_addr(char *buf, char **start, off_t offset, - int len, int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - int token; - int i; - u8 mc_addr[8]; - - struct - { - u16 result_count; - u16 pad; - u16 block_size; - u8 block_status; - u8 error_info_size; - u16 row_count; - u16 more_flag; - u8 mc_addr[256][8]; - } result; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, 0x0002, -1, - NULL, 0, &result, sizeof(result)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x002 LAN Multicast MAC Address"); - spin_unlock(&i2o_proc_lock); - return len; - } - - for (i = 0; i < result.row_count; i++) - { - memcpy(mc_addr, result.mc_addr[i], 8); - - len += sprintf(buf+len, "MC MAC address[%d]: " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - i, mc_addr[0], mc_addr[1], mc_addr[2], - mc_addr[3], mc_addr[4], mc_addr[5], - mc_addr[6], mc_addr[7]); - } - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* LAN group 0003h - Batch Control (scalar) */ -int i2o_proc_read_lan_batch_control(char *buf, char **start, off_t offset, - int len, int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[9]; - int token; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0003, -1, &work32, 9*4); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0003 LAN Batch Control"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "Batch mode "); - if (work32[0]&0x00000001) - len += sprintf(buf+len, "disabled"); - else - len += sprintf(buf+len, "enabled"); - if (work32[0]&0x00000002) - len += sprintf(buf+len, " (current setting)"); - if (work32[0]&0x00000004) - len += sprintf(buf+len, ", forced"); - else - len += sprintf(buf+len, ", toggle"); - len += sprintf(buf+len, "\n"); - - len += sprintf(buf+len, "Max Rx batch count : %d\n", work32[5]); - len += sprintf(buf+len, "Max Rx batch delay : %d\n", work32[6]); - len += sprintf(buf+len, "Max Tx batch delay : %d\n", work32[7]); - len += sprintf(buf+len, "Max Tx batch count : %d\n", work32[8]); - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* LAN group 0004h - LAN Operation (scalar) */ -int i2o_proc_read_lan_operation(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[5]; - int token; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0004, -1, &work32, 20); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0004 LAN Operation"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "Packet prepadding (32b words) : %d\n", work32[0]); - len += sprintf(buf+len, "Transmission error reporting : %s\n", - (work32[1]&1)?"on":"off"); - len += sprintf(buf+len, "Bad packet handling : %s\n", - (work32[1]&0x2)?"by host":"by DDM"); - len += sprintf(buf+len, "Packet orphan limit : %d\n", work32[2]); - - len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[3]); - len += sprintf(buf+len, " [%s] HW CRC supression\n", - (work32[3]&0x00000004) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW IPv4 checksum\n", - (work32[3]&0x00000100) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW TCP checksum\n", - (work32[3]&0x00000200) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW UDP checksum\n", - (work32[3]&0x00000400) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW RSVP checksum\n", - (work32[3]&0x00000800) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW ICMP checksum\n", - (work32[3]&0x00001000) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Loopback supression enable\n", - (work32[3]&0x00002000) ? "+" : "-"); - - len += sprintf(buf+len, "Rx modes : 0x%08x\n", work32[4]); - len += sprintf(buf+len, " [%s] FCS in payload\n", - (work32[4]&0x00000004) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW IPv4 checksum validation\n", - (work32[4]&0x00000100) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW TCP checksum validation\n", - (work32[4]&0x00000200) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW UDP checksum validation\n", - (work32[4]&0x00000400) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW RSVP checksum validation\n", - (work32[4]&0x00000800) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW ICMP checksum validation\n", - (work32[4]&0x00001000) ? "+" : "-"); - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* LAN group 0005h - Media operation (scalar) */ -int i2o_proc_read_lan_media_operation(char *buf, char **start, off_t offset, - int len, int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - int token; - - struct - { - u32 connector_type; - u32 connection_type; - u64 current_tx_wire_speed; - u64 current_rx_wire_speed; - u8 duplex_mode; - u8 link_status; - u8 reserved; - u8 duplex_mode_target; - u32 connector_type_target; - u32 connection_type_target; - } result; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0005, -1, &result, sizeof(result)); - if (token < 0) { - len += i2o_report_query_status(buf+len, token, "0x0005 LAN Media Operation"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "Connector type : %s\n", - i2o_get_connector_type(result.connector_type)); - len += sprintf(buf+len, "Connection type : %s\n", - i2o_get_connection_type(result.connection_type)); - - len += sprintf(buf+len, "Current Tx wire speed : %d bps\n", (int)result.current_tx_wire_speed); - len += sprintf(buf+len, "Current Rx wire speed : %d bps\n", (int)result.current_rx_wire_speed); - len += sprintf(buf+len, "Duplex mode : %s duplex\n", - (result.duplex_mode)?"Full":"Half"); - - len += sprintf(buf+len, "Link status : "); - switch (result.link_status) - { - case 0x00: - len += sprintf(buf+len, "Unknown\n"); - break; - case 0x01: - len += sprintf(buf+len, "Normal\n"); - break; - case 0x02: - len += sprintf(buf+len, "Failure\n"); - break; - case 0x03: - len += sprintf(buf+len, "Reset\n"); - break; - default: - len += sprintf(buf+len, "Unspecified\n"); - } - - len += sprintf(buf+len, "Duplex mode target : "); - switch (result.duplex_mode_target){ - case 0: - len += sprintf(buf+len, "Half duplex\n"); - break; - case 1: - len += sprintf(buf+len, "Full duplex\n"); - break; - default: - len += sprintf(buf+len, "\n"); - } - - len += sprintf(buf+len, "Connector type target : %s\n", - i2o_get_connector_type(result.connector_type_target)); - len += sprintf(buf+len, "Connection type target : %s\n", - i2o_get_connection_type(result.connection_type_target)); - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* LAN group 0006h - Alternate address (table) (optional) */ -int i2o_proc_read_lan_alt_addr(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - int token; - int i; - u8 alt_addr[8]; - struct - { - u16 result_count; - u16 pad; - u16 block_size; - u8 block_status; - u8 error_info_size; - u16 row_count; - u16 more_flag; - u8 alt_addr[256][8]; - } result; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, - 0x0006, -1, NULL, 0, &result, sizeof(result)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token, "0x0006 LAN Alternate Address (optional)"); - spin_unlock(&i2o_proc_lock); - return len; - } - - for (i=0; i < result.row_count; i++) - { - memcpy(alt_addr,result.alt_addr[i],8); - len += sprintf(buf+len, "Alternate address[%d]: " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - i, alt_addr[0], alt_addr[1], alt_addr[2], - alt_addr[3], alt_addr[4], alt_addr[5], - alt_addr[6], alt_addr[7]); - } - - spin_unlock(&i2o_proc_lock); - return len; -} - - -/* LAN group 0007h - Transmit info (scalar) */ -int i2o_proc_read_lan_tx_info(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[8]; - int token; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0007, -1, &work32, 8*4); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0007 LAN Transmit Info"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "Tx Max SG elements per packet : %d\n", work32[0]); - len += sprintf(buf+len, "Tx Max SG elements per chain : %d\n", work32[1]); - len += sprintf(buf+len, "Tx Max outstanding packets : %d\n", work32[2]); - len += sprintf(buf+len, "Tx Max packets per request : %d\n", work32[3]); - - len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[4]); - len += sprintf(buf+len, " [%s] No DA in SGL\n", - (work32[4]&0x00000002) ? "+" : "-"); - len += sprintf(buf+len, " [%s] CRC suppression\n", - (work32[4]&0x00000004) ? "+" : "-"); - len += sprintf(buf+len, " [%s] MAC insertion\n", - (work32[4]&0x00000010) ? "+" : "-"); - len += sprintf(buf+len, " [%s] RIF insertion\n", - (work32[4]&0x00000020) ? "+" : "-"); - len += sprintf(buf+len, " [%s] IPv4 checksum generation\n", - (work32[4]&0x00000100) ? "+" : "-"); - len += sprintf(buf+len, " [%s] TCP checksum generation\n", - (work32[4]&0x00000200) ? "+" : "-"); - len += sprintf(buf+len, " [%s] UDP checksum generation\n", - (work32[4]&0x00000400) ? "+" : "-"); - len += sprintf(buf+len, " [%s] RSVP checksum generation\n", - (work32[4]&0x00000800) ? "+" : "-"); - len += sprintf(buf+len, " [%s] ICMP checksum generation\n", - (work32[4]&0x00001000) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Loopback enabled\n", - (work32[4]&0x00010000) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Loopback suppression enabled\n", - (work32[4]&0x00020000) ? "+" : "-"); - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* LAN group 0008h - Receive info (scalar) */ -int i2o_proc_read_lan_rx_info(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[8]; - int token; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0008, -1, &work32, 8*4); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0008 LAN Receive Info"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf ,"Rx Max size of chain element : %d\n", work32[0]); - len += sprintf(buf+len, "Rx Max Buckets : %d\n", work32[1]); - len += sprintf(buf+len, "Rx Max Buckets in Reply : %d\n", work32[3]); - len += sprintf(buf+len, "Rx Max Packets in Bucket : %d\n", work32[4]); - len += sprintf(buf+len, "Rx Max Buckets in Post : %d\n", work32[5]); - - len += sprintf(buf+len, "Rx Modes : 0x%08x\n", work32[2]); - len += sprintf(buf+len, " [%s] FCS reception\n", - (work32[2]&0x00000004) ? "+" : "-"); - len += sprintf(buf+len, " [%s] IPv4 checksum validation \n", - (work32[2]&0x00000100) ? "+" : "-"); - len += sprintf(buf+len, " [%s] TCP checksum validation \n", - (work32[2]&0x00000200) ? "+" : "-"); - len += sprintf(buf+len, " [%s] UDP checksum validation \n", - (work32[2]&0x00000400) ? "+" : "-"); - len += sprintf(buf+len, " [%s] RSVP checksum validation \n", - (work32[2]&0x00000800) ? "+" : "-"); - len += sprintf(buf+len, " [%s] ICMP checksum validation \n", - (work32[2]&0x00001000) ? "+" : "-"); - - spin_unlock(&i2o_proc_lock); - return len; -} - -static int i2o_report_opt_field(char *buf, char *field_name, - int field_nbr, int supp_fields, u64 *value) -{ - if (supp_fields & (1 << field_nbr)) - return sprintf(buf, "%-24s : " FMT_U64_HEX "\n", field_name, U64_VAL(value)); - else - return sprintf(buf, "%-24s : Not supported\n", field_name); -} - -/* LAN group 0100h - LAN Historical statistics (scalar) */ -/* LAN group 0180h - Supported Optional Historical Statistics (scalar) */ -/* LAN group 0182h - Optional Non Media Specific Transmit Historical Statistics (scalar) */ -/* LAN group 0183h - Optional Non Media Specific Receive Historical Statistics (scalar) */ - -int i2o_proc_read_lan_hist_stats(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - int token; - - struct - { - u64 tx_packets; - u64 tx_bytes; - u64 rx_packets; - u64 rx_bytes; - u64 tx_errors; - u64 rx_errors; - u64 rx_dropped; - u64 adapter_resets; - u64 adapter_suspends; - } stats; // 0x0100 - - static u64 supp_groups[4]; // 0x0180 - - struct - { - u64 tx_retries; - u64 tx_directed_bytes; - u64 tx_directed_packets; - u64 tx_multicast_bytes; - u64 tx_multicast_packets; - u64 tx_broadcast_bytes; - u64 tx_broadcast_packets; - u64 tx_group_addr_packets; - u64 tx_short_packets; - } tx_stats; // 0x0182 - - struct - { - u64 rx_crc_errors; - u64 rx_directed_bytes; - u64 rx_directed_packets; - u64 rx_multicast_bytes; - u64 rx_multicast_packets; - u64 rx_broadcast_bytes; - u64 rx_broadcast_packets; - u64 rx_group_addr_packets; - u64 rx_short_packets; - u64 rx_long_packets; - u64 rx_runt_packets; - } rx_stats; // 0x0183 - - struct - { - u64 ipv4_generate; - u64 ipv4_validate_success; - u64 ipv4_validate_errors; - u64 tcp_generate; - u64 tcp_validate_success; - u64 tcp_validate_errors; - u64 udp_generate; - u64 udp_validate_success; - u64 udp_validate_errors; - u64 rsvp_generate; - u64 rsvp_validate_success; - u64 rsvp_validate_errors; - u64 icmp_generate; - u64 icmp_validate_success; - u64 icmp_validate_errors; - } chksum_stats; // 0x0184 - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0100, -1, &stats, sizeof(stats)); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x100 LAN Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "Tx packets : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_packets)); - len += sprintf(buf+len, "Tx bytes : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_bytes)); - len += sprintf(buf+len, "Rx packets : " FMT_U64_HEX "\n", - U64_VAL(&stats.rx_packets)); - len += sprintf(buf+len, "Rx bytes : " FMT_U64_HEX "\n", - U64_VAL(&stats.rx_bytes)); - len += sprintf(buf+len, "Tx errors : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_errors)); - len += sprintf(buf+len, "Rx errors : " FMT_U64_HEX "\n", - U64_VAL(&stats.rx_errors)); - len += sprintf(buf+len, "Rx dropped : " FMT_U64_HEX "\n", - U64_VAL(&stats.rx_dropped)); - len += sprintf(buf+len, "Adapter resets : " FMT_U64_HEX "\n", - U64_VAL(&stats.adapter_resets)); - len += sprintf(buf+len, "Adapter suspends : " FMT_U64_HEX "\n", - U64_VAL(&stats.adapter_suspends)); - - /* Optional statistics follows */ - /* Get 0x0180 to see which optional groups/fields are supported */ - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0180, -1, &supp_groups, sizeof(supp_groups)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token, "0x180 LAN Supported Optional Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } - - if (supp_groups[1]) /* 0x0182 */ - { - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0182, -1, &tx_stats, sizeof(tx_stats)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x182 LAN Optional Tx Historical Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "==== Optional TX statistics (group 0182h)\n"); - - len += i2o_report_opt_field(buf+len, "Tx RetryCount", - 0, supp_groups[1], &tx_stats.tx_retries); - len += i2o_report_opt_field(buf+len, "Tx DirectedBytes", - 1, supp_groups[1], &tx_stats.tx_directed_bytes); - len += i2o_report_opt_field(buf+len, "Tx DirectedPackets", - 2, supp_groups[1], &tx_stats.tx_directed_packets); - len += i2o_report_opt_field(buf+len, "Tx MulticastBytes", - 3, supp_groups[1], &tx_stats.tx_multicast_bytes); - len += i2o_report_opt_field(buf+len, "Tx MulticastPackets", - 4, supp_groups[1], &tx_stats.tx_multicast_packets); - len += i2o_report_opt_field(buf+len, "Tx BroadcastBytes", - 5, supp_groups[1], &tx_stats.tx_broadcast_bytes); - len += i2o_report_opt_field(buf+len, "Tx BroadcastPackets", - 6, supp_groups[1], &tx_stats.tx_broadcast_packets); - len += i2o_report_opt_field(buf+len, "Tx TotalGroupAddrPackets", - 7, supp_groups[1], &tx_stats.tx_group_addr_packets); - len += i2o_report_opt_field(buf+len, "Tx TotalPacketsTooShort", - 8, supp_groups[1], &tx_stats.tx_short_packets); - } - - if (supp_groups[2]) /* 0x0183 */ - { - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0183, -1, &rx_stats, sizeof(rx_stats)); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x183 LAN Optional Rx Historical Stats"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "==== Optional RX statistics (group 0183h)\n"); - - len += i2o_report_opt_field(buf+len, "Rx CRCErrorCount", - 0, supp_groups[2], &rx_stats.rx_crc_errors); - len += i2o_report_opt_field(buf+len, "Rx DirectedBytes", - 1, supp_groups[2], &rx_stats.rx_directed_bytes); - len += i2o_report_opt_field(buf+len, "Rx DirectedPackets", - 2, supp_groups[2], &rx_stats.rx_directed_packets); - len += i2o_report_opt_field(buf+len, "Rx MulticastBytes", - 3, supp_groups[2], &rx_stats.rx_multicast_bytes); - len += i2o_report_opt_field(buf+len, "Rx MulticastPackets", - 4, supp_groups[2], &rx_stats.rx_multicast_packets); - len += i2o_report_opt_field(buf+len, "Rx BroadcastBytes", - 5, supp_groups[2], &rx_stats.rx_broadcast_bytes); - len += i2o_report_opt_field(buf+len, "Rx BroadcastPackets", - 6, supp_groups[2], &rx_stats.rx_broadcast_packets); - len += i2o_report_opt_field(buf+len, "Rx TotalGroupAddrPackets", - 7, supp_groups[2], &rx_stats.rx_group_addr_packets); - len += i2o_report_opt_field(buf+len, "Rx TotalPacketsTooShort", - 8, supp_groups[2], &rx_stats.rx_short_packets); - len += i2o_report_opt_field(buf+len, "Rx TotalPacketsTooLong", - 9, supp_groups[2], &rx_stats.rx_long_packets); - len += i2o_report_opt_field(buf+len, "Rx TotalPacketsRunt", - 10, supp_groups[2], &rx_stats.rx_runt_packets); - } - - if (supp_groups[3]) /* 0x0184 */ - { - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0184, -1, &chksum_stats, sizeof(chksum_stats)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x184 LAN Optional Chksum Historical Stats"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "==== Optional CHKSUM statistics (group 0x0184)\n"); - - len += i2o_report_opt_field(buf+len, "IPv4 Generate", - 0, supp_groups[3], &chksum_stats.ipv4_generate); - len += i2o_report_opt_field(buf+len, "IPv4 ValidateSuccess", - 1, supp_groups[3], &chksum_stats.ipv4_validate_success); - len += i2o_report_opt_field(buf+len, "IPv4 ValidateError", - 2, supp_groups[3], &chksum_stats.ipv4_validate_errors); - len += i2o_report_opt_field(buf+len, "TCP Generate", - 3, supp_groups[3], &chksum_stats.tcp_generate); - len += i2o_report_opt_field(buf+len, "TCP ValidateSuccess", - 4, supp_groups[3], &chksum_stats.tcp_validate_success); - len += i2o_report_opt_field(buf+len, "TCP ValidateError", - 5, supp_groups[3], &chksum_stats.tcp_validate_errors); - len += i2o_report_opt_field(buf+len, "UDP Generate", - 6, supp_groups[3], &chksum_stats.udp_generate); - len += i2o_report_opt_field(buf+len, "UDP ValidateSuccess", - 7, supp_groups[3], &chksum_stats.udp_validate_success); - len += i2o_report_opt_field(buf+len, "UDP ValidateError", - 8, supp_groups[3], &chksum_stats.udp_validate_errors); - len += i2o_report_opt_field(buf+len, "RSVP Generate", - 9, supp_groups[3], &chksum_stats.rsvp_generate); - len += i2o_report_opt_field(buf+len, "RSVP ValidateSuccess", - 10, supp_groups[3], &chksum_stats.rsvp_validate_success); - len += i2o_report_opt_field(buf+len, "RSVP ValidateError", - 11, supp_groups[3], &chksum_stats.rsvp_validate_errors); - len += i2o_report_opt_field(buf+len, "ICMP Generate", - 12, supp_groups[3], &chksum_stats.icmp_generate); - len += i2o_report_opt_field(buf+len, "ICMP ValidateSuccess", - 13, supp_groups[3], &chksum_stats.icmp_validate_success); - len += i2o_report_opt_field(buf+len, "ICMP ValidateError", - 14, supp_groups[3], &chksum_stats.icmp_validate_errors); - } - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* LAN group 0200h - Required Ethernet Statistics (scalar) */ -/* LAN group 0280h - Optional Ethernet Statistics Supported (scalar) */ -/* LAN group 0281h - Optional Ethernet Historical Statistics (scalar) */ -int i2o_proc_read_lan_eth_stats(char *buf, char **start, off_t offset, - int len, int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - int token; - - struct - { - u64 rx_align_errors; - u64 tx_one_collisions; - u64 tx_multiple_collisions; - u64 tx_deferred; - u64 tx_late_collisions; - u64 tx_max_collisions; - u64 tx_carrier_lost; - u64 tx_excessive_deferrals; - } stats; - - static u64 supp_fields; - struct - { - u64 rx_overrun; - u64 tx_underrun; - u64 tx_heartbeat_failure; - } hist_stats; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0200, -1, &stats, sizeof(stats)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0200 LAN Ethernet Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "Rx alignment errors : " FMT_U64_HEX "\n", - U64_VAL(&stats.rx_align_errors)); - len += sprintf(buf+len, "Tx one collisions : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_one_collisions)); - len += sprintf(buf+len, "Tx multicollisions : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_multiple_collisions)); - len += sprintf(buf+len, "Tx deferred : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_deferred)); - len += sprintf(buf+len, "Tx late collisions : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_late_collisions)); - len += sprintf(buf+len, "Tx max collisions : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_max_collisions)); - len += sprintf(buf+len, "Tx carrier lost : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_carrier_lost)); - len += sprintf(buf+len, "Tx excessive deferrals : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_excessive_deferrals)); - - /* Optional Ethernet statistics follows */ - /* Get 0x0280 to see which optional fields are supported */ - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0280, -1, &supp_fields, sizeof(supp_fields)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0280 LAN Supported Optional Ethernet Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } - - if (supp_fields) /* 0x0281 */ - { - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0281, -1, &stats, sizeof(stats)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0281 LAN Optional Ethernet Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "==== Optional ETHERNET statistics (group 0x0281)\n"); - - len += i2o_report_opt_field(buf+len, "Rx Overrun", - 0, supp_fields, &hist_stats.rx_overrun); - len += i2o_report_opt_field(buf+len, "Tx Underrun", - 1, supp_fields, &hist_stats.tx_underrun); - len += i2o_report_opt_field(buf+len, "Tx HeartbeatFailure", - 2, supp_fields, &hist_stats.tx_heartbeat_failure); - } - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* LAN group 0300h - Required Token Ring Statistics (scalar) */ -/* LAN group 0380h, 0381h - Optional Statistics not yet defined (TODO) */ -int i2o_proc_read_lan_tr_stats(char *buf, char **start, off_t offset, - int len, int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - static u64 work64[13]; - int token; - - static char *ring_status[] = - { - "", - "", - "", - "", - "", - "Ring Recovery", - "Single Station", - "Counter Overflow", - "Remove Received", - "", - "Auto-Removal Error 1", - "Lobe Wire Fault", - "Transmit Beacon", - "Soft Error", - "Hard Error", - "Signal Loss" - }; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0300, -1, &work64, sizeof(work64)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0300 Token Ring Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "LineErrors : " FMT_U64_HEX "\n", - U64_VAL(&work64[0])); - len += sprintf(buf+len, "LostFrames : " FMT_U64_HEX "\n", - U64_VAL(&work64[1])); - len += sprintf(buf+len, "ACError : " FMT_U64_HEX "\n", - U64_VAL(&work64[2])); - len += sprintf(buf+len, "TxAbortDelimiter : " FMT_U64_HEX "\n", - U64_VAL(&work64[3])); - len += sprintf(buf+len, "BursErrors : " FMT_U64_HEX "\n", - U64_VAL(&work64[4])); - len += sprintf(buf+len, "FrameCopiedErrors : " FMT_U64_HEX "\n", - U64_VAL(&work64[5])); - len += sprintf(buf+len, "FrequencyErrors : " FMT_U64_HEX "\n", - U64_VAL(&work64[6])); - len += sprintf(buf+len, "InternalErrors : " FMT_U64_HEX "\n", - U64_VAL(&work64[7])); - len += sprintf(buf+len, "LastRingStatus : %s\n", ring_status[work64[8]]); - len += sprintf(buf+len, "TokenError : " FMT_U64_HEX "\n", - U64_VAL(&work64[9])); - len += sprintf(buf+len, "UpstreamNodeAddress : " FMT_U64_HEX "\n", - U64_VAL(&work64[10])); - len += sprintf(buf+len, "LastRingID : " FMT_U64_HEX "\n", - U64_VAL(&work64[11])); - len += sprintf(buf+len, "LastBeaconType : " FMT_U64_HEX "\n", - U64_VAL(&work64[12])); - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* LAN group 0400h - Required FDDI Statistics (scalar) */ -/* LAN group 0480h, 0481h - Optional Statistics, not yet defined (TODO) */ -int i2o_proc_read_lan_fddi_stats(char *buf, char **start, off_t offset, - int len, int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - static u64 work64[11]; - int token; - - static char *conf_state[] = - { - "Isolated", - "Local a", - "Local b", - "Local ab", - "Local s", - "Wrap a", - "Wrap b", - "Wrap ab", - "Wrap s", - "C-Wrap a", - "C-Wrap b", - "C-Wrap s", - "Through", - }; - - static char *ring_state[] = - { - "Isolated", - "Non-op", - "Rind-op", - "Detect", - "Non-op-Dup", - "Ring-op-Dup", - "Directed", - "Trace" - }; - - static char *link_state[] = - { - "Off", - "Break", - "Trace", - "Connect", - "Next", - "Signal", - "Join", - "Verify", - "Active", - "Maintenance" - }; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0400, -1, &work64, sizeof(work64)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0400 FDDI Required Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "ConfigurationState : %s\n", conf_state[work64[0]]); - len += sprintf(buf+len, "UpstreamNode : " FMT_U64_HEX "\n", - U64_VAL(&work64[1])); - len += sprintf(buf+len, "DownStreamNode : " FMT_U64_HEX "\n", - U64_VAL(&work64[2])); - len += sprintf(buf+len, "FrameErrors : " FMT_U64_HEX "\n", - U64_VAL(&work64[3])); - len += sprintf(buf+len, "FramesLost : " FMT_U64_HEX "\n", - U64_VAL(&work64[4])); - len += sprintf(buf+len, "RingMgmtState : %s\n", ring_state[work64[5]]); - len += sprintf(buf+len, "LCTFailures : " FMT_U64_HEX "\n", - U64_VAL(&work64[6])); - len += sprintf(buf+len, "LEMRejects : " FMT_U64_HEX "\n", - U64_VAL(&work64[7])); - len += sprintf(buf+len, "LEMCount : " FMT_U64_HEX "\n", - U64_VAL(&work64[8])); - len += sprintf(buf+len, "LConnectionState : %s\n", - link_state[work64[9]]); - - spin_unlock(&i2o_proc_lock); - return len; -} - -static int i2o_proc_create_entries(void *data, i2o_proc_entry *pentry, - struct proc_dir_entry *parent) -{ - struct proc_dir_entry *ent; - - while(pentry->name != NULL) - { - ent = create_proc_entry(pentry->name, pentry->mode, parent); - if(!ent) return -1; - - ent->data = data; - ent->read_proc = pentry->read_proc; - ent->write_proc = pentry->write_proc; - ent->nlink = 1; - - pentry++; - } - - return 0; -} - -static void i2o_proc_remove_entries(i2o_proc_entry *pentry, - struct proc_dir_entry *parent) -{ - while(pentry->name != NULL) - { - remove_proc_entry(pentry->name, parent); - pentry++; - } -} - -static int i2o_proc_add_controller(struct i2o_controller *pctrl, - struct proc_dir_entry *root ) -{ - struct proc_dir_entry *dir, *dir1; - struct i2o_device *dev; - char buff[10]; - - sprintf(buff, "iop%d", pctrl->unit); - - dir = proc_mkdir(buff, root); - if(!dir) - return -1; - - pctrl->proc_entry = dir; - - i2o_proc_create_entries(pctrl, generic_iop_entries, dir); - - for(dev = pctrl->devices; dev; dev = dev->next) - { - sprintf(buff, "%0#5x", dev->lct_data.tid); - - dir1 = proc_mkdir(buff, dir); - dev->proc_entry = dir1; - - if(!dir1) - printk(KERN_INFO "i2o_proc: Could not allocate proc dir\n"); - - i2o_proc_add_device(dev, dir1); - } - - return 0; -} - -void i2o_proc_new_dev(struct i2o_controller *c, struct i2o_device *d) -{ - char buff[10]; - -#ifdef DRIVERDEBUG - printk(KERN_INFO "Adding new device to /proc/i2o/iop%d\n", c->unit); -#endif - sprintf(buff, "%0#5x", d->lct_data.tid); - - d->proc_entry = proc_mkdir(buff, c->proc_entry); - - if(!d->proc_entry) - { - printk(KERN_WARNING "i2o: Could not allocate procdir!\n"); - return; - } - - i2o_proc_add_device(d, d->proc_entry); -} - -void i2o_proc_add_device(struct i2o_device *dev, struct proc_dir_entry *dir) -{ - i2o_proc_create_entries(dev, generic_dev_entries, dir); - - /* Inform core that we want updates about this device's status */ - i2o_device_notify_on(dev, &i2o_proc_handler); - switch(dev->lct_data.class_id) - { - case I2O_CLASS_SCSI_PERIPHERAL: - case I2O_CLASS_RANDOM_BLOCK_STORAGE: - i2o_proc_create_entries(dev, rbs_dev_entries, dir); - break; - case I2O_CLASS_LAN: - i2o_proc_create_entries(dev, lan_entries, dir); - switch(dev->lct_data.sub_class) - { - case I2O_LAN_ETHERNET: - i2o_proc_create_entries(dev, lan_eth_entries, dir); - break; - case I2O_LAN_FDDI: - i2o_proc_create_entries(dev, lan_fddi_entries, dir); - break; - case I2O_LAN_TR: - i2o_proc_create_entries(dev, lan_tr_entries, dir); - break; - default: - break; - } - break; - default: - break; - } -} - -static void i2o_proc_remove_controller(struct i2o_controller *pctrl, - struct proc_dir_entry *parent) -{ - char buff[10]; - struct i2o_device *dev; - - /* Remove unused device entries */ - for(dev=pctrl->devices; dev; dev=dev->next) - i2o_proc_remove_device(dev); - - if(!atomic_read(&pctrl->proc_entry->count)) - { - sprintf(buff, "iop%d", pctrl->unit); - - i2o_proc_remove_entries(generic_iop_entries, pctrl->proc_entry); - - remove_proc_entry(buff, parent); - pctrl->proc_entry = NULL; - } -} - -void i2o_proc_remove_device(struct i2o_device *dev) -{ - struct proc_dir_entry *de=dev->proc_entry; - char dev_id[10]; - - sprintf(dev_id, "%0#5x", dev->lct_data.tid); - - i2o_device_notify_off(dev, &i2o_proc_handler); - /* Would it be safe to remove _files_ even if they are in use? */ - if((de) && (!atomic_read(&de->count))) - { - i2o_proc_remove_entries(generic_dev_entries, de); - switch(dev->lct_data.class_id) - { - case I2O_CLASS_SCSI_PERIPHERAL: - case I2O_CLASS_RANDOM_BLOCK_STORAGE: - i2o_proc_remove_entries(rbs_dev_entries, de); - break; - case I2O_CLASS_LAN: - { - i2o_proc_remove_entries(lan_entries, de); - switch(dev->lct_data.sub_class) - { - case I2O_LAN_ETHERNET: - i2o_proc_remove_entries(lan_eth_entries, de); - break; - case I2O_LAN_FDDI: - i2o_proc_remove_entries(lan_fddi_entries, de); - break; - case I2O_LAN_TR: - i2o_proc_remove_entries(lan_tr_entries, de); - break; - } - } - remove_proc_entry(dev_id, dev->controller->proc_entry); - } - } -} - -void i2o_proc_dev_del(struct i2o_controller *c, struct i2o_device *d) -{ -#ifdef DRIVERDEBUG - printk(KERN_INFO, "Deleting device %d from iop%d\n", - d->lct_data.tid, c->unit); -#endif - - i2o_proc_remove_device(d); -} - -static int create_i2o_procfs(void) -{ - struct i2o_controller *pctrl = NULL; - int i; - - i2o_proc_dir_root = proc_mkdir("i2o", 0); - if(!i2o_proc_dir_root) - return -1; - - for(i = 0; i < MAX_I2O_CONTROLLERS; i++) - { - pctrl = i2o_find_controller(i); - if(pctrl) - { - i2o_proc_add_controller(pctrl, i2o_proc_dir_root); - i2o_unlock_controller(pctrl); - } - }; - - return 0; -} - -static int __exit destroy_i2o_procfs(void) -{ - struct i2o_controller *pctrl = NULL; - int i; - - for(i = 0; i < MAX_I2O_CONTROLLERS; i++) - { - pctrl = i2o_find_controller(i); - if(pctrl) - { - i2o_proc_remove_controller(pctrl, i2o_proc_dir_root); - i2o_unlock_controller(pctrl); - } - } - - if(!atomic_read(&i2o_proc_dir_root->count)) - remove_proc_entry("i2o", 0); - else - return -1; - - return 0; -} - -int __init i2o_proc_init(void) -{ - if (i2o_install_handler(&i2o_proc_handler) < 0) - { - printk(KERN_ERR "i2o_proc: Unable to install PROC handler.\n"); - return 0; - } - - if(create_i2o_procfs()) - return -EBUSY; - - return 0; -} - -MODULE_AUTHOR("Deepak Saxena"); -MODULE_DESCRIPTION("I2O procfs Handler"); - -static void __exit i2o_proc_exit(void) -{ - destroy_i2o_procfs(); - i2o_remove_handler(&i2o_proc_handler); -} - -#ifdef MODULE -module_init(i2o_proc_init); -#endif -module_exit(i2o_proc_exit); - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/i2o/i2o_scsi.c linux.ac/drivers/i2o/i2o_scsi.c --- linux.vanilla/drivers/i2o/i2o_scsi.c Mon Oct 30 22:44:29 2000 +++ linux.ac/drivers/i2o/i2o_scsi.c Thu Jan 1 01:00:00 1970 @@ -1,911 +0,0 @@ -/* - * 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. - * - * Complications for I2O scsi - * - * o Each (bus,lun) is a logical device in I2O. We keep a map - * table. We spoof failed selection for unmapped units - * o Request sense buffers can come back for free. - * o Scatter gather is a bit dynamic. We have to investigate at - * setup time. - * o Some of our resources are dynamically shared. The i2o core - * needs a message reservation protocol to avoid swap v net - * deadlocking. We need to back off queue requests. - * - * In general the firmware wants to help. Where its help isn't performance - * useful we just ignore the aid. Its not worth the code in truth. - * - * Fixes: - * Steve Ralston : Scatter gather now works - * - * To Do - * 64bit cleanups - * Fix the resource management problems. - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/string.h> -#include <linux/ioport.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/timer.h> -#include <linux/delay.h> -#include <linux/proc_fs.h> -#include <asm/dma.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/atomic.h> -#include <linux/blk.h> -#include <linux/version.h> -#include <linux/i2o.h> -#include "../scsi/scsi.h" -#include "../scsi/hosts.h" -#include "../scsi/sd.h" -#include "i2o_scsi.h" - -#define VERSION_STRING "Version 0.0.1" - -#define dprintk(x) - -#define MAXHOSTS 32 - -struct i2o_scsi_host -{ - struct i2o_controller *controller; - s16 task[16][8]; /* Allow 16 devices for now */ - unsigned long tagclock[16][8]; /* Tag clock for queueing */ - s16 bus_task; /* The adapter TID */ -}; - -static int scsi_context; -static int lun_done; -static int i2o_scsi_hosts; - -static u32 *retry[32]; -static struct i2o_controller *retry_ctrl[32]; -static struct timer_list retry_timer; -static int retry_ct = 0; - -static atomic_t queue_depth; - -/* - * SG Chain buffer support... - */ - -#define SG_MAX_FRAGS 64 - -/* - * FIXME: we should allocate one of these per bus we find as we - * locate them not in a lump at boot. - */ - -typedef struct _chain_buf -{ - u32 sg_flags_cnt[SG_MAX_FRAGS]; - u32 sg_buf[SG_MAX_FRAGS]; -} chain_buf; - -#define SG_CHAIN_BUF_SZ sizeof(chain_buf) - -#define SG_MAX_BUFS (i2o_num_controllers * I2O_SCSI_CAN_QUEUE) -#define SG_CHAIN_POOL_SZ (SG_MAX_BUFS * SG_CHAIN_BUF_SZ) - -static int max_sg_len = 0; -static chain_buf *sg_chain_pool = NULL; -static int sg_chain_tag = 0; -static int sg_max_frags = SG_MAX_FRAGS; - -/* - * Retry congested frames. This actually needs pushing down into - * i2o core. We should only bother the OSM with this when we can't - * queue and retry the frame. Or perhaps we should call the OSM - * and its default handler should be this in the core, and this - * call a 2nd "I give up" handler in the OSM ? - */ - -static void i2o_retry_run(unsigned long f) -{ - int i; - unsigned long flags; - - save_flags(flags); - cli(); - - for(i=0;i<retry_ct;i++) - i2o_post_message(retry_ctrl[i], virt_to_bus(retry[i])); - retry_ct=0; - - restore_flags(flags); -} - -static void flush_pending(void) -{ - int i; - unsigned long flags; - - save_flags(flags); - cli(); - - for(i=0;i<retry_ct;i++) - { - retry[i][0]&=~0xFFFFFF; - retry[i][0]|=I2O_CMD_UTIL_NOP<<24; - i2o_post_message(retry_ctrl[i],virt_to_bus(retry[i])); - } - retry_ct=0; - - restore_flags(flags); -} - -static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg) -{ - Scsi_Cmnd *current_command; - u32 *m = (u32 *)msg; - u8 as,ds,st; - - if(m[0] & (1<<13)) - { - printk("IOP fail.\n"); - printk("From %d To %d Cmd %d.\n", - (m[1]>>12)&0xFFF, - m[1]&0xFFF, - m[1]>>24); - printk("Failure Code %d.\n", m[4]>>24); - if(m[4]&(1<<16)) - printk("Format error.\n"); - if(m[4]&(1<<17)) - printk("Path error.\n"); - if(m[4]&(1<<18)) - printk("Path State.\n"); - if(m[4]&(1<<18)) - printk("Congestion.\n"); - - m=(u32 *)bus_to_virt(m[7]); - printk("Failing message is %p.\n", m); - - if((m[4]&(1<<18)) && retry_ct < 32) - { - retry_ctrl[retry_ct]=c; - retry[retry_ct]=m; - if(!retry_ct++) - { - retry_timer.expires=jiffies+1; - add_timer(&retry_timer); - } - } - else - { - /* Create a scsi error for this */ - current_command = (Scsi_Cmnd *)m[3]; - printk("Aborted %ld\n", current_command->serial_number); - - spin_lock_irq(&io_request_lock); - current_command->result = DID_ERROR << 16; - current_command->scsi_done(current_command); - spin_unlock_irq(&io_request_lock); - - /* Now flush the message by making it a NOP */ - m[0]&=0x00FFFFFF; - m[0]|=(I2O_CMD_UTIL_NOP)<<24; - i2o_post_message(c,virt_to_bus(m)); - } - return; - } - - - /* - * Low byte is device status, next is adapter status, - * (then one byte reserved), then request status. - */ - ds=(u8)m[4]; - as=(u8)(m[4]>>8); - st=(u8)(m[4]>>24); - - dprintk(("i2o got a scsi reply %08X: ", m[0])); - dprintk(("m[2]=%08X: ", m[2])); - dprintk(("m[4]=%08X\n", m[4])); - - if(m[2]&0x80000000) - { - if(m[2]&0x40000000) - { - dprintk(("Event.\n")); - lun_done=1; - return; - } - printk(KERN_ERR "i2o_scsi: bus reset reply.\n"); - return; - } - - current_command = (Scsi_Cmnd *)m[3]; - - /* - * Is this a control request coming back - eg an abort ? - */ - - if(current_command==NULL) - { - if(st) - dprintk(("SCSI abort: %08X", m[4])); - dprintk(("SCSI abort completed.\n")); - return; - } - - dprintk(("Completed %ld\n", current_command->serial_number)); - - atomic_dec(&queue_depth); - - if(st == 0x06) - { - if(m[5] < current_command->underflow) - { - int i; - printk(KERN_ERR "SCSI: underflow 0x%08X 0x%08X\n", - m[5], current_command->underflow); - printk("Cmd: "); - for(i=0;i<15;i++) - printk("%02X ", current_command->cmnd[i]); - printk(".\n"); - } - else st=0; - } - - if(st) - { - /* An error has occured */ - - dprintk((KERN_DEBUG "SCSI error %08X", m[4])); - - if (as == 0x0E) - /* SCSI Reset */ - current_command->result = DID_RESET << 16; - else if (as == 0x0F) - current_command->result = DID_PARITY << 16; - else - current_command->result = DID_ERROR << 16; - } - else - /* - * It worked maybe ? - */ - current_command->result = DID_OK << 16 | ds; - spin_lock(&io_request_lock); - current_command->scsi_done(current_command); - spin_unlock(&io_request_lock); - return; -} - -struct i2o_handler i2o_scsi_handler= -{ - i2o_scsi_reply, - NULL, - NULL, - NULL, - "I2O SCSI OSM", - 0, - I2O_CLASS_SCSI_PERIPHERAL -}; - -static int i2o_find_lun(struct i2o_controller *c, struct i2o_device *d, int *target, int *lun) -{ - u8 reply[8]; - - if(i2o_query_scalar(c, d->lct_data.tid, 0, 3, reply, 4)<0) - return -1; - - *target=reply[0]; - - if(i2o_query_scalar(c, d->lct_data.tid, 0, 4, reply, 8)<0) - return -1; - - *lun=reply[1]; - - dprintk(("SCSI (%d,%d)\n", *target, *lun)); - return 0; -} - -void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt) -{ - struct i2o_device *unit; - struct i2o_scsi_host *h =(struct i2o_scsi_host *)shpnt->hostdata; - int lun; - int target; - - h->controller=c; - h->bus_task=d->lct_data.tid; - - for(target=0;target<16;target++) - for(lun=0;lun<8;lun++) - h->task[target][lun] = -1; - - for(unit=c->devices;unit!=NULL;unit=unit->next) - { - dprintk(("Class %03X, parent %d, want %d.\n", - unit->lct_data.class_id, unit->lct_data.parent_tid, d->lct_data.tid)); - - /* Only look at scsi and fc devices */ - if ( (unit->lct_data.class_id != I2O_CLASS_SCSI_PERIPHERAL) - && (unit->lct_data.class_id != I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL) - ) - continue; - - /* On our bus ? */ - dprintk(("Found a disk (%d).\n", unit->lct_data.tid)); - if ((unit->lct_data.parent_tid == d->lct_data.tid) - || (unit->lct_data.parent_tid == d->lct_data.parent_tid) - ) - { - u16 limit; - dprintk(("Its ours.\n")); - if(i2o_find_lun(c, unit, &target, &lun)==-1) - { - printk(KERN_ERR "i2o_scsi: Unable to get lun for tid %d.\n", unit->lct_data.tid); - continue; - } - dprintk(("Found disk %d %d.\n", target, lun)); - h->task[target][lun]=unit->lct_data.tid; - h->tagclock[target][lun]=jiffies; - - /* Get the max fragments/request */ - i2o_query_scalar(c, d->lct_data.tid, 0xF103, 3, &limit, 2); - - /* sanity */ - if ( limit == 0 ) - { - printk(KERN_WARNING "i2o_scsi: Ignoring unreasonable SG limit of 0 from IOP!\n"); - limit = 1; - } - - shpnt->sg_tablesize = limit; - - dprintk(("i2o_scsi: set scatter-gather to %d.\n", - shpnt->sg_tablesize)); - } - } -} - -int i2o_scsi_detect(Scsi_Host_Template * tpnt) -{ - unsigned long flags; - struct Scsi_Host *shpnt = NULL; - int i; - int count; - - printk("i2o_scsi.c: %s\n", VERSION_STRING); - - if(i2o_install_handler(&i2o_scsi_handler)<0) - { - printk(KERN_ERR "i2o_scsi: Unable to install OSM handler.\n"); - return 0; - } - scsi_context = i2o_scsi_handler.context; - - if((sg_chain_pool = kmalloc(SG_CHAIN_POOL_SZ, GFP_KERNEL)) == NULL) - { - printk("i2o_scsi: Unable to alloc %d byte SG chain buffer pool.\n", SG_CHAIN_POOL_SZ); - printk("i2o_scsi: SG chaining DISABLED!\n"); - sg_max_frags = 11; - } - else - { - printk(" chain_pool: %d bytes @ %p\n", SG_CHAIN_POOL_SZ, sg_chain_pool); - printk(" (%d byte buffers X %d can_queue X %d i2o controllers)\n", - SG_CHAIN_BUF_SZ, I2O_SCSI_CAN_QUEUE, i2o_num_controllers); - sg_max_frags = SG_MAX_FRAGS; // 64 - } - - init_timer(&retry_timer); - retry_timer.data = 0UL; - retry_timer.function = i2o_retry_run; - -// printk("SCSI OSM at %d.\n", scsi_context); - - for (count = 0, i = 0; i < MAX_I2O_CONTROLLERS; i++) - { - struct i2o_controller *c=i2o_find_controller(i); - struct i2o_device *d; - /* - * This controller doesn't exist. - */ - - if(c==NULL) - continue; - - /* - * Fixme - we need some altered device locking. This - * is racing with device addition in theory. Easy to fix. - */ - - for(d=c->devices;d!=NULL;d=d->next) - { - /* - * bus_adapter, SCSI (obsolete), or FibreChannel busses only - */ - if( (d->lct_data.class_id!=I2O_CLASS_BUS_ADAPTER_PORT) // bus_adapter -// && (d->lct_data.class_id!=I2O_CLASS_FIBRE_CHANNEL_PORT) // FC_PORT - ) - continue; - - shpnt = scsi_register(tpnt, sizeof(struct i2o_scsi_host)); - if(shpnt==NULL) - continue; - save_flags(flags); - cli(); - shpnt->unique_id = (u32)d; - shpnt->io_port = 0; - shpnt->n_io_port = 0; - shpnt->irq = 0; - shpnt->this_id = /* Good question */15; - restore_flags(flags); - i2o_scsi_init(c, d, shpnt); - count++; - } - } - i2o_scsi_hosts = count; - - if(count==0) - { - if(sg_chain_pool!=NULL) - { - kfree(sg_chain_pool); - sg_chain_pool = NULL; - } - flush_pending(); - del_timer(&retry_timer); - i2o_remove_handler(&i2o_scsi_handler); - } - - return count; -} - -int i2o_scsi_release(struct Scsi_Host *host) -{ - if(--i2o_scsi_hosts==0) - { - if(sg_chain_pool!=NULL) - { - kfree(sg_chain_pool); - sg_chain_pool = NULL; - } - flush_pending(); - del_timer(&retry_timer); - i2o_remove_handler(&i2o_scsi_handler); - } - return 0; -} - - -const char *i2o_scsi_info(struct Scsi_Host *SChost) -{ - struct i2o_scsi_host *hostdata; - - hostdata = (struct i2o_scsi_host *)SChost->hostdata; - - return(&hostdata->controller->name[0]); -} - - -/* - * From the wd93 driver: - * Returns true if there will be a DATA_OUT phase with this command, - * false otherwise. - * (Thanks to Joerg Dorchain for the research and suggestion.) - * - */ -static int is_dir_out(Scsi_Cmnd *cmd) -{ - switch (cmd->cmnd[0]) - { - case WRITE_6: case WRITE_10: case WRITE_12: - case WRITE_LONG: case WRITE_SAME: case WRITE_BUFFER: - case WRITE_VERIFY: case WRITE_VERIFY_12: - case COMPARE: case COPY: case COPY_VERIFY: - case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW: - case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12: - case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE: - case MODE_SELECT: case MODE_SELECT_10: case LOG_SELECT: - case SEND_DIAGNOSTIC: case CHANGE_DEFINITION: case UPDATE_BLOCK: - case SET_WINDOW: case MEDIUM_SCAN: case SEND_VOLUME_TAG: - case 0xea: - return 1; - default: - return 0; - } -} - -int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) -{ - int i; - int tid; - struct i2o_controller *c; - Scsi_Cmnd *current_command; - struct Scsi_Host *host; - struct i2o_scsi_host *hostdata; - u32 *msg, *mptr; - u32 m; - u32 *lenptr; - int direction; - int scsidir; - u32 len; - u32 reqlen; - u32 tag; - - static int max_qd = 1; - - /* - * Do the incoming paperwork - */ - - host = SCpnt->host; - hostdata = (struct i2o_scsi_host *)host->hostdata; - SCpnt->scsi_done = done; - - if(SCpnt->target > 15) - { - printk(KERN_ERR "i2o_scsi: Wild target %d.\n", SCpnt->target); - return -1; - } - - tid = hostdata->task[SCpnt->target][SCpnt->lun]; - - dprintk(("qcmd: Tid = %d\n", tid)); - - current_command = SCpnt; /* set current command */ - current_command->scsi_done = done; /* set ptr to done function */ - - /* We don't have such a device. Pretend we did the command - and that selection timed out */ - - if(tid == -1) - { - SCpnt->result = DID_NO_CONNECT << 16; - done(SCpnt); - return 0; - } - - dprintk(("Real scsi messages.\n")); - - c = hostdata->controller; - - /* - * Obtain an I2O message. Right now we _have_ to obtain one - * until the scsi layer stuff is cleaned up. - */ - - do - { - mb(); - m = I2O_POST_READ32(c); - } - while(m==0xFFFFFFFF); - msg = (u32 *)(c->mem_offset + m); - - /* - * Put together a scsi execscb message - */ - - len = SCpnt->request_bufflen; - direction = 0x00000000; // SGL IN (osm<--iop) - - /* - * The scsi layer should be handling this stuff - */ - - scsidir = 0x00000000; // DATA NO XFER - if(len) - { - if(is_dir_out(SCpnt)) - { - direction=0x04000000; // SGL OUT (osm-->iop) - scsidir =0x80000000; // DATA OUT (iop-->dev) - } - else - { - scsidir =0x40000000; // DATA IN (iop<--dev) - } - } - - __raw_writel(I2O_CMD_SCSI_EXEC<<24|HOST_TID<<12|tid, &msg[1]); - __raw_writel(scsi_context, &msg[2]); /* So the I2O layer passes to us */ - /* Sorry 64bit folks. FIXME */ - __raw_writel((u32)SCpnt, &msg[3]); /* We want the SCSI control block back */ - - /* LSI_920_PCI_QUIRK - * - * Intermittant observations of msg frame word data corruption - * observed on msg[4] after: - * WRITE, READ-MODIFY-WRITE - * operations. 19990606 -sralston - * - * (Hence we build this word via tag. Its good practice anyway - * we don't want fetches over PCI needlessly) - */ - - tag=0; - - /* - * Attach tags to the devices - */ - if(SCpnt->device->tagged_supported) - { - /* - * Some drives are too stupid to handle fairness issues - * with tagged queueing. We throw in the odd ordered - * tag to stop them starving themselves. - */ - if((jiffies - hostdata->tagclock[SCpnt->target][SCpnt->lun]) > (5*HZ)) - { - tag=0x01800000; /* ORDERED! */ - hostdata->tagclock[SCpnt->target][SCpnt->lun]=jiffies; - } - else - { - /* Hmmm... I always see value of 0 here, - * of which {HEAD_OF, ORDERED, SIMPLE} are NOT! -sralston - */ - if(SCpnt->tag == HEAD_OF_QUEUE_TAG) - tag=0x01000000; - else if(SCpnt->tag == ORDERED_QUEUE_TAG) - tag=0x01800000; - } - } - - /* Direction, disconnect ok, tag, CDBLen */ - __raw_writel(scsidir|0x20000000|SCpnt->cmd_len|tag, &msg[4]); - - mptr=msg+5; - - /* - * Write SCSI command into the message - always 16 byte block - */ - - memcpy_toio(mptr, SCpnt->cmnd, 16); - mptr+=4; - lenptr=mptr++; /* Remember me - fill in when we know */ - - reqlen = 12; // SINGLE SGE - - /* - * Now fill in the SGList and command - * - * FIXME: we need to set the sglist limits according to the - * message size of the I2O controller. We might only have room - * for 6 or so worst case - */ - - if(SCpnt->use_sg) - { - struct scatterlist *sg = (struct scatterlist *)SCpnt->request_buffer; - int chain = 0; - - len = 0; - - if((sg_max_frags > 11) && (SCpnt->use_sg > 11)) - { - chain = 1; - /* - * Need to chain! - */ - __raw_writel(direction|0xB0000000|(SCpnt->use_sg*2*4), mptr++); - __raw_writel(virt_to_bus(sg_chain_pool + sg_chain_tag), mptr); - mptr = (u32*)(sg_chain_pool + sg_chain_tag); - if (SCpnt->use_sg > max_sg_len) - { - max_sg_len = SCpnt->use_sg; - printk("i2o_scsi: Chain SG! SCpnt=%p, SG_FragCnt=%d, SG_idx=%d\n", - SCpnt, SCpnt->use_sg, sg_chain_tag); - } - if ( ++sg_chain_tag == SG_MAX_BUFS ) - sg_chain_tag = 0; - for(i = 0 ; i < SCpnt->use_sg; i++) - { - *mptr++=direction|0x10000000|sg->length; - len+=sg->length; - *mptr++=virt_to_bus(sg->address); - sg++; - } - mptr[-2]=direction|0xD0000000|(sg-1)->length; - } - else - { - for(i = 0 ; i < SCpnt->use_sg; i++) - { - __raw_writel(direction|0x10000000|sg->length, mptr++); - len+=sg->length; - __raw_writel(virt_to_bus(sg->address), mptr++); - sg++; - } - - /* Make this an end of list. Again evade the 920 bug and - unwanted PCI read traffic */ - - __raw_writel(direction|0xD0000000|(sg-1)->length, &mptr[-2]); - } - - if(!chain) - reqlen = mptr - msg; - - __raw_writel(len, lenptr); - - if(len != SCpnt->underflow) - printk("Cmd len %08X Cmd underflow %08X\n", - len, SCpnt->underflow); - } - else - { - dprintk(("non sg for %p, %d\n", SCpnt->request_buffer, - SCpnt->request_bufflen)); - __raw_writel(len = SCpnt->request_bufflen, lenptr); - if(len == 0) - { - reqlen = 9; - } - else - { - __raw_writel(0xD0000000|direction|SCpnt->request_bufflen, mptr++); - __raw_writel(virt_to_bus(SCpnt->request_buffer), mptr++); - } - } - - /* - * Stick the headers on - */ - - __raw_writel(reqlen<<16 | SGL_OFFSET_10, msg); - - /* Queue the message */ - i2o_post_message(c,m); - - atomic_inc(&queue_depth); - - if(atomic_read(&queue_depth)> max_qd) - { - max_qd=atomic_read(&queue_depth); - printk("Queue depth now %d.\n", max_qd); - } - - mb(); - dprintk(("Issued %ld\n", current_command->serial_number)); - - return 0; -} - -static void internal_done(Scsi_Cmnd * SCpnt) -{ - SCpnt->SCp.Status++; -} - -int i2o_scsi_command(Scsi_Cmnd * SCpnt) -{ - i2o_scsi_queuecommand(SCpnt, internal_done); - SCpnt->SCp.Status = 0; - while (!SCpnt->SCp.Status) - barrier(); - return SCpnt->result; -} - -int i2o_scsi_abort(Scsi_Cmnd * SCpnt) -{ - struct i2o_controller *c; - struct Scsi_Host *host; - struct i2o_scsi_host *hostdata; - u32 *msg; - u32 m; - int tid; - - printk("i2o_scsi: Aborting command block.\n"); - - host = SCpnt->host; - hostdata = (struct i2o_scsi_host *)host->hostdata; - tid = hostdata->task[SCpnt->target][SCpnt->lun]; - if(tid==-1) - { - printk(KERN_ERR "impossible command to abort.\n"); - return SCSI_ABORT_NOT_RUNNING; - } - c = hostdata->controller; - - /* - * Obtain an I2O message. Right now we _have_ to obtain one - * until the scsi layer stuff is cleaned up. - */ - - do - { - mb(); - m = I2O_POST_READ32(c); - } - while(m==0xFFFFFFFF); - msg = bus_to_virt(c->mem_offset + m); - - __raw_writel(FIVE_WORD_MSG_SIZE, &msg[0]); - __raw_writel(I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|tid, &msg[1]); - __raw_writel(scsi_context, &msg[2]); - __raw_writel(0, &msg[3]); /* Not needed for an abort */ - __raw_writel((u32)SCpnt, &msg[4]); - wmb(); - i2o_post_message(c,m); - wmb(); - return SCSI_ABORT_PENDING; -} - -int i2o_scsi_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) -{ - int tid; - struct i2o_controller *c; - struct Scsi_Host *host; - struct i2o_scsi_host *hostdata; - u32 m; - u32 *msg; - - /* - * Find the TID for the bus - */ - - printk("i2o_scsi: Attempting to reset the bus.\n"); - - host = SCpnt->host; - hostdata = (struct i2o_scsi_host *)host->hostdata; - tid = hostdata->bus_task; - c = hostdata->controller; - - /* - * Now send a SCSI reset request. Any remaining commands - * will be aborted by the IOP. We need to catch the reply - * possibly ? - */ - - m = I2O_POST_READ32(c); - - /* - * No free messages, try again next time - no big deal - */ - - if(m == 0xFFFFFFFF) - return SCSI_RESET_PUNT; - - msg = bus_to_virt(c->mem_offset + m); - __raw_writel(FOUR_WORD_MSG_SIZE|SGL_OFFSET_0, &msg[0]); - __raw_writel(I2O_CMD_SCSI_BUSRESET<<24|HOST_TID<<12|tid, &msg[1]); - __raw_writel(scsi_context|0x80000000, &msg[2]); - /* We use the top bit to split controller and unit transactions */ - /* Now store unit,tid so we can tie the completion back to a specific device */ - __raw_writel(c->unit << 16 | tid, &msg[3]); - i2o_post_message(c,m); - return SCSI_RESET_PENDING; -} - -/* - * This is anyones guess quite frankly. - */ - -int i2o_scsi_bios_param(Disk * disk, kdev_t dev, int *ip) -{ - int size; - - size = disk->capacity; - ip[0] = 64; /* heads */ - ip[1] = 32; /* sectors */ - if ((ip[2] = size >> 11) > 1024) { /* cylinders, test for big disk */ - ip[0] = 255; /* heads */ - ip[1] = 63; /* sectors */ - ip[2] = size / (255 * 63); /* cylinders */ - } - return 0; -} - -MODULE_AUTHOR("Red Hat Software"); - -static Scsi_Host_Template driver_template = I2OSCSI; - -#include "../scsi/scsi_module.c" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/i2o/i2o_scsi.h linux.ac/drivers/i2o/i2o_scsi.h --- linux.vanilla/drivers/i2o/i2o_scsi.h Mon Dec 11 21:20:04 2000 +++ linux.ac/drivers/i2o/i2o_scsi.h Thu Jan 1 01:00:00 1970 @@ -1,47 +0,0 @@ -#ifndef _I2O_SCSI_H -#define _I2O_SCSI_H - -#if !defined(LINUX_VERSION_CODE) -#include <linux/version.h> -#endif - -#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) - -#include <linux/types.h> -#include <linux/kdev_t.h> - -#define I2O_SCSI_ID 15 -#define I2O_SCSI_CAN_QUEUE 4 -#define I2O_SCSI_CMD_PER_LUN 6 - -extern int i2o_scsi_detect(Scsi_Host_Template *); -extern const char *i2o_scsi_info(struct Scsi_Host *); -extern int i2o_scsi_command(Scsi_Cmnd *); -extern int i2o_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -extern int i2o_scsi_abort(Scsi_Cmnd *); -extern int i2o_scsi_reset(Scsi_Cmnd *, unsigned int); -extern int i2o_scsi_bios_param(Disk *, kdev_t, int *); -extern void i2o_scsi_setup(char *str, int *ints); -extern int i2o_scsi_release(struct Scsi_Host *host); - -#define I2OSCSI { \ - next: NULL, \ - proc_name: "i2o_scsi", \ - name: "I2O SCSI Layer", \ - detect: i2o_scsi_detect, \ - release: i2o_scsi_release, \ - info: i2o_scsi_info, \ - command: i2o_scsi_command, \ - queuecommand: i2o_scsi_queuecommand, \ - abort: i2o_scsi_abort, \ - reset: i2o_scsi_reset, \ - bios_param: i2o_scsi_bios_param, \ - can_queue: I2O_SCSI_CAN_QUEUE, \ - this_id: I2O_SCSI_ID, \ - sg_tablesize: 8, \ - cmd_per_lun: I2O_SCSI_CMD_PER_LUN, \ - unchecked_isa_dma: 0, \ - use_clustering: ENABLE_CLUSTERING \ - } - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/Config.in linux.ac/drivers/ide/Config.in --- linux.vanilla/drivers/ide/Config.in Fri Feb 16 01:22:08 2001 +++ linux.ac/drivers/ide/Config.in Tue Apr 3 17:54:41 2001 @@ -64,6 +64,10 @@ dep_mbool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' PIIXn Tuning support' CONFIG_PIIX_TUNING $CONFIG_BLK_DEV_PIIX $CONFIG_IDEDMA_PCI_AUTO fi + if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then + dep_mbool ' IT8172 IDE support' CONFIG_BLK_DEV_IT8172 $CONFIG_BLK_DEV_IDEDMA_PCI + dep_mbool ' IT8172 IDE Tuning support' CONFIG_IT8172_TUNING $CONFIG_BLK_DEV_IT8172 $CONFIG_IDEDMA_PCI_AUTO + fi dep_bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL dep_bool ' PROMISE PDC20246/PDC20262/PDC20267 support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI @@ -97,17 +101,20 @@ dep_bool ' RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE $CONFIG_ARCH_ACORN fi if [ "$CONFIG_AMIGA" = "y" ]; then - dep_bool ' Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE $CONFIG_AMIGA - dep_mbool ' Amiga IDE Doubler support (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE $CONFIG_EXPERIMENTAL + dep_bool ' Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE $CONFIG_AMIGA + dep_mbool ' Amiga IDE Doubler support (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE $CONFIG_EXPERIMENTAL fi if [ "$CONFIG_ZORRO" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_mbool ' Buddha/Catweasel IDE interface support (EXPERIMENTAL)' CONFIG_BLK_DEV_BUDDHA $CONFIG_ZORRO $CONFIG_EXPERIMENTAL + dep_mbool ' Buddha/Catweasel IDE interface support (EXPERIMENTAL)' CONFIG_BLK_DEV_BUDDHA $CONFIG_ZORRO $CONFIG_EXPERIMENTAL fi if [ "$CONFIG_ATARI" = "y" ]; then - dep_bool ' Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE $CONFIG_ATARI + dep_bool ' Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE $CONFIG_ATARI fi if [ "$CONFIG_MAC" = "y" ]; then - dep_bool ' Macintosh Quadra/Powerbook IDE interface support' CONFIG_BLK_DEV_MAC_IDE $CONFIG_MAC + dep_bool ' Macintosh Quadra/Powerbook IDE interface support' CONFIG_BLK_DEV_MAC_IDE $CONFIG_MAC + fi + if [ "$CONFIG_Q40" = "y" ]; then + dep_bool ' Q40/Q60 IDE interface support' CONFIG_BLK_DEV_Q40IDE $CONFIG_Q40 fi bool ' Other IDE chipset support' CONFIG_IDE_CHIPSETS @@ -163,6 +170,7 @@ "$CONFIG_BLK_DEV_OSB4" = "y" -o \ "$CONFIG_BLK_DEV_PDC202XX" = "y" -o \ "$CONFIG_BLK_DEV_PIIX" = "y" -o \ + "$CONFIG_BLK_DEV_IT8172" = "y" -o \ "$CONFIG_BLK_DEV_SIS5513" = "y" -o \ "$CONFIG_BLK_DEV_SLC90E66" = "y" -o \ "$CONFIG_BLK_DEV_SL82C105" = "y" -o \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/Makefile linux.ac/drivers/ide/Makefile --- linux.vanilla/drivers/ide/Makefile Fri Dec 29 22:07:22 2000 +++ linux.ac/drivers/ide/Makefile Tue Apr 3 17:54:41 2001 @@ -24,6 +24,7 @@ obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd.o obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o +obj-$(CONFIG_BLK_DEV_IT8172) += it8172.o ide-obj-$(CONFIG_BLK_DEV_AEC62XX) += aec62xx.o ide-obj-$(CONFIG_BLK_DEV_ALI14XX) += ali14xx.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/ali14xx.c linux.ac/drivers/ide/ali14xx.c --- linux.vanilla/drivers/ide/ali14xx.c Fri Apr 14 06:54:26 2000 +++ linux.ac/drivers/ide/ali14xx.c Tue Apr 3 17:54:41 2001 @@ -81,9 +81,9 @@ {0x2d, 0x32, 0x2e, 0x33}, /* drive 3 */ }; -static int basePort = 0; /* base port address */ -static int regPort = 0; /* port for register number */ -static int dataPort = 0; /* port for register data */ +static int basePort; /* base port address */ +static int regPort; /* port for register number */ +static int dataPort; /* port for register data */ static byte regOn; /* output to base port to access registers */ static byte regOff; /* output to base port to close registers */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/alim15x3.c linux.ac/drivers/ide/alim15x3.c --- linux.vanilla/drivers/ide/alim15x3.c Tue Nov 7 19:02:24 2000 +++ linux.ac/drivers/ide/alim15x3.c Tue Apr 3 17:54:41 2001 @@ -233,8 +233,8 @@ } #endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ -static byte m5229_revision = 0; -static byte chip_is_1543c_e = 0; +static byte m5229_revision; +static byte chip_is_1543c_e; byte ali_proc = 0; static struct pci_dev *isa_dev; @@ -687,7 +687,8 @@ * M1543C or newer for DMAing */ hwif->dmaproc = &ali15x3_dmaproc; - hwif->autodma = 1; + if (!noautodma) + hwif->autodma = 1; } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/amd7409.c linux.ac/drivers/ide/amd7409.c --- linux.vanilla/drivers/ide/amd7409.c Tue Nov 7 19:02:24 2000 +++ linux.ac/drivers/ide/amd7409.c Tue Apr 3 17:54:41 2001 @@ -455,7 +455,8 @@ if (hwif->dma_base) { hwif->dmaproc = &amd7409_dmaproc; - hwif->autodma = 1; + if (!noautodma) + hwif->autodma = 1; } else { hwif->autodma = 0; hwif->drives[0].autotune = 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/buddha.c linux.ac/drivers/ide/buddha.c --- linux.vanilla/drivers/ide/buddha.c Tue Nov 28 01:57:34 2000 +++ linux.ac/drivers/ide/buddha.c Tue Apr 3 17:54:41 2001 @@ -87,7 +87,7 @@ * Board information */ -static u_long buddha_board = 0; +static u_long buddha_board; static int buddha_num_hwifs = -1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/cy82c693.c linux.ac/drivers/ide/cy82c693.c --- linux.vanilla/drivers/ide/cy82c693.c Tue Jun 20 15:52:36 2000 +++ linux.ac/drivers/ide/cy82c693.c Tue Apr 3 17:54:41 2001 @@ -442,7 +442,8 @@ #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->dmaproc = &cy82c693_dmaproc; - hwif->autodma = 1; + if (!noautodma) + hwif->autodma = 1; } #endif /* CONFIG_BLK_DEV_IDEDMA */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/hpt34x.c linux.ac/drivers/ide/hpt34x.c --- linux.vanilla/drivers/ide/hpt34x.c Tue Jun 20 15:52:36 2000 +++ linux.ac/drivers/ide/hpt34x.c Tue Apr 3 17:54:41 2001 @@ -419,7 +419,11 @@ unsigned short pcicmd = 0; pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd); - hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0; + if (!noautodma) + hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0; + else + hwif->autodma = 0; + hwif->dmaproc = &hpt34x_dmaproc; } else { hwif->drives[0].autotune = 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/hpt366.c linux.ac/drivers/ide/hpt366.c --- linux.vanilla/drivers/ide/hpt366.c Sat Jan 27 16:45:58 2001 +++ linux.ac/drivers/ide/hpt366.c Tue Apr 3 17:54:41 2001 @@ -51,6 +51,16 @@ }; const char *bad_ata100_5[] = { + "IBM-DTLA-307075", + "IBM-DTLA-307060", + "IBM-DTLA-307045", + "IBM-DTLA-307030", + "IBM-DTLA-307020", + "IBM-DTLA-307015", + "IBM-DTLA-305040", + "IBM-DTLA-305030", + "IBM-DTLA-305020", + "WDC AC310200R", NULL }; @@ -223,8 +233,8 @@ byte hpt366_proc = 0; extern char *ide_xfer_verbose (byte xfer_rate); -byte hpt363_shared_irq = 0; -byte hpt363_shared_pin = 0; +byte hpt363_shared_irq; +byte hpt363_shared_pin; static unsigned int pci_rev_check_hpt3xx (struct pci_dev *dev) { @@ -706,7 +716,10 @@ } else { hwif->dmaproc = &hpt366_dmaproc; } - hwif->autodma = 1; + if (!noautodma) + hwif->autodma = 1; + else + hwif->autodma = 0; } else { hwif->autodma = 0; hwif->drives[0].autotune = 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/ide-cd.c linux.ac/drivers/ide/ide-cd.c --- linux.vanilla/drivers/ide/ide-cd.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/ide/ide-cd.c Tue Apr 3 17:54:41 2001 @@ -254,7 +254,7 @@ * They will disappear later when I get the time to * do it cleanly. * - Minimize the TOC reading - only do it when we - * know a media change has occured. + * know a media change has occurred. * - Moved all the CDROMREADx ioctls to the Uniform layer. * - Heiko Eissfeldt <heiko@colossus.escape.de> supplied * some fixes for CDI. @@ -1984,7 +1984,7 @@ /* Now try to get the total cdrom capacity. */ minor = (drive->select.b.unit) << PARTN_BITS; dev = MKDEV(HWIF(drive)->major, minor); - stat = cdrom_get_last_written(dev, (long *)&toc->capacity); + stat = cdrom_get_last_written(dev, &toc->capacity); if (stat) stat = cdrom_read_capacity(drive, &toc->capacity, sense); if (stat) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/ide-dma.c linux.ac/drivers/ide/ide-dma.c --- linux.vanilla/drivers/ide/ide-dma.c Mon Jan 15 21:08:15 2001 +++ linux.ac/drivers/ide/ide-dma.c Tue Apr 3 17:54:41 2001 @@ -119,6 +119,12 @@ { "WDC AC31600H" , "ALL" }, { "WDC AC32100H" , "24.09P07" }, { "WDC AC23200L" , "21.10N21" }, + { "Compaq CRD-8241B" , "ALL" }, + { "CRD-8400B" , "ALL" }, + { "SanDisk SDP3B-64" , "ALL" }, + { "SAMSUNG CD-ROM SN-124", "ALL" }, + { "PLEXTOR CD-R PX-W8432T", "ALL" }, + { "ATAPI CD-ROM DRIVE 40X MAXIMUM", "ALL" }, { 0 , 0 } }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/ide-features.c linux.ac/drivers/ide/ide-features.c --- linux.vanilla/drivers/ide/ide-features.c Fri Feb 9 19:40:02 2001 +++ linux.ac/drivers/ide/ide-features.c Tue Apr 3 17:54:41 2001 @@ -228,7 +228,7 @@ #ifndef CONFIG_IDEDMA_IVB if ((drive->id->hw_config & 0x6000) == 0) { #else /* !CONFIG_IDEDMA_IVB */ - if (((drive->id->hw_config & 0x2000) == 0) || + if (((drive->id->hw_config & 0x2000) == 0) && ((drive->id->hw_config & 0x4000) == 0)) { #endif /* CONFIG_IDEDMA_IVB */ printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", drive->name); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/ide-floppy.c linux.ac/drivers/ide/ide-floppy.c --- linux.vanilla/drivers/ide/ide-floppy.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/ide/ide-floppy.c Tue Apr 3 17:54:41 2001 @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/ide-floppy.c Version 0.9 Jul 4, 1999 + * linux/drivers/ide/ide-floppy.c Version 0.9.sv Jan 6 2001 * * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il> */ @@ -29,9 +29,18 @@ * 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 <shanos@es.co.nz> for pointing this out. + * Ver 0.9.sv Jan 6 01 Sam Varshavchik <mrsam@courier-mta.com> + * Implement low level formatting. Reimplemented + * IDEFLOPPY_CAPABILITIES_PAGE, since we need the srfp + * bit. My LS-120 drive barfs on + * IDEFLOPPY_CAPABILITIES_PAGE, but maybe it's just me. + * Compromise by not reporting a failure to get this + * mode page. Implemented four IOCTLs in order to + * implement formatting. IOCTls begin with 0x4600, + * 0x46 is 'F' as in Format. */ -#define IDEFLOPPY_VERSION "0.9" +#define IDEFLOPPY_VERSION "0.9.sv" #include <linux/config.h> #include <linux/module.h> @@ -228,6 +237,7 @@ * Last error information */ byte sense_key, asc, ascq; + int progress_indication; /* * Device information @@ -236,7 +246,7 @@ idefloppy_capacity_descriptor_t capacity; /* Last format capacity */ idefloppy_flexible_disk_page_t flexible_disk_page; /* Copy of the flexible disk page */ int wp; /* Write protect */ - + int srfp; /* Supports format progress report */ unsigned int flags; /* Status/Action flags */ } idefloppy_floppy_t; @@ -246,6 +256,7 @@ #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_FORMAT_IN_PROGRESS 3 /* Format in progress */ /* * ATAPI floppy drive packet commands @@ -276,6 +287,15 @@ #define MODE_SENSE_SAVED 0x03 /* + * IOCTLs used in low-level formatting. + */ + +#define IDEFLOPPY_IOCTL_FORMAT_SUPPORTED 0x4600 +#define IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY 0x4601 +#define IDEFLOPPY_IOCTL_FORMAT_START 0x4602 +#define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS 0x4603 + +/* * Special requests for our block device strategy routine. */ #define IDEFLOPPY_FIRST_RQ 90 @@ -559,7 +579,7 @@ u8 asc; /* Additional Sense Code */ u8 ascq; /* Additional Sense Code Qualifier */ u8 replaceable_unit_code; /* Field Replaceable Unit Code */ - u8 reserved[3]; + u8 sksv[3]; u8 pad[2]; /* Padding to 20 bytes */ } idefloppy_request_sense_result_t; @@ -746,6 +766,8 @@ idefloppy_floppy_t *floppy = drive->driver_data; floppy->sense_key = result->sense_key; floppy->asc = result->asc; floppy->ascq = result->ascq; + floppy->progress_indication= result->sksv[0] & 0x80 ? + (unsigned short)get_unaligned((u16 *)(result->sksv+1)):0x10000; #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); @@ -954,7 +976,7 @@ return ide_do_reset (drive); } ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); /* Set the interrupt routine */ - atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */ + atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */ return ide_started; } @@ -1062,6 +1084,22 @@ pc->request_transfer = 255; } +static void idefloppy_create_format_unit_cmd (idefloppy_pc_t *pc, int b, int l) +{ + idefloppy_init_pc (pc); + pc->c[0] = IDEFLOPPY_FORMAT_UNIT_CMD; + pc->c[1] = 0x17; + + memset(pc->buffer, 0, 12); + pc->buffer[1] = 0xA2; /* Format list header, byte 1: FOV/DCRT/IMM */ + pc->buffer[3] = 8; + + put_unaligned(htonl(b), (unsigned int *)(&pc->buffer[4])); + put_unaligned(htonl(l), (unsigned int *)(&pc->buffer[8])); + pc->buffer_size=12; + set_bit(PC_WRITING, &pc->flags); +} + /* * A mode sense command is used to "sense" floppy parameters. */ @@ -1235,6 +1273,25 @@ return 0; } +static int idefloppy_get_capability_page(ide_drive_t *drive) +{ + idefloppy_floppy_t *floppy = drive->driver_data; + idefloppy_pc_t pc; + idefloppy_mode_parameter_header_t *header; + idefloppy_capabilities_page_t *page; + + floppy->srfp=0; + idefloppy_create_mode_sense_cmd (&pc, IDEFLOPPY_CAPABILITIES_PAGE, + MODE_SENSE_CURRENT); + if (idefloppy_queue_pc_tail (drive,&pc)) { + return 1; + } + header = (idefloppy_mode_parameter_header_t *) pc.buffer; + page= (idefloppy_capabilities_page_t *)(header+1); + floppy->srfp=page->srfp; + return (0); +} + /* * Determine if a media is present in the floppy drive, and if so, * its LBA capacity. @@ -1286,11 +1343,172 @@ #endif /* IDEFLOPPY_DEBUG_INFO */ } (void) idefloppy_get_flexible_disk_page (drive); + (void) idefloppy_get_capability_page (drive); + drive->part[0].nr_sects = floppy->blocks * floppy->bs_factor; return rc; } /* +** Obtain the list of formattable capacities. +** Very similar to idefloppy_get_capacity, except that we push the capacity +** descriptors to userland, instead of our own structures. +** +** Userland gives us the following structure: +** +** struct idefloppy_format_capacities { +** int nformats; +** struct { +** int nblocks; +** int blocksize; +** } formats[]; +** } ; +** +** userland initializes nformats to the number of allocated formats[] +** records. On exit we set nformats to the number of records we've +** actually initialized. +** +*/ + +static int idefloppy_get_format_capacities (ide_drive_t *drive, + struct inode *inode, + struct file *file, + int *arg) /* Cheater */ +{ + idefloppy_pc_t pc; + idefloppy_capacity_header_t *header; + idefloppy_capacity_descriptor_t *descriptor; + int i, descriptors, blocks, length; + int u_array_size; + int u_index; + int *argp; + + if (get_user(u_array_size, arg)) + return (-EFAULT); + + if (u_array_size <= 0) + return (-EINVAL); + + idefloppy_create_read_capacity_cmd (&pc); + if (idefloppy_queue_pc_tail (drive, &pc)) { + printk (KERN_ERR "ide-floppy: Can't get floppy parameters\n"); + return (-EIO); + } + header = (idefloppy_capacity_header_t *) pc.buffer; + descriptors = header->length / + sizeof (idefloppy_capacity_descriptor_t); + descriptor = (idefloppy_capacity_descriptor_t *) (header + 1); + + u_index=0; + argp=arg+1; + + /* + ** We always skip the first capacity descriptor. That's the + ** current capacity. We are interested in the remaining descriptors, + ** the formattable capacities. + */ + + for (i=0; i<descriptors; i++, descriptor++) + { + if (u_index >= u_array_size) + break; /* User-supplied buffer too small */ + if (i == 0) + continue; /* Skip the first descriptor */ + + blocks = ntohl (descriptor->blocks); + length = ntohs (descriptor->length); + + if (put_user(blocks, argp)) + return (-EFAULT); + ++argp; + + if (put_user(length, argp)) + return (-EFAULT); + ++argp; + + ++u_index; + } + + if (put_user(u_index, arg)) + return (-EFAULT); + return (0); +} + +/* +** Send ATAPI_FORMAT_UNIT to the drive. +** +** Userland gives us the following structure: +** +** struct idefloppy_format_command { +** int nblocks; +** int blocksize; +** } ; +*/ + +static int idefloppy_begin_format(ide_drive_t *drive, + struct inode *inode, + struct file *file, + int *arg) +{ + int blocks; + int length; + idefloppy_pc_t pc; + + if (get_user(blocks, arg) + || get_user(length, arg+1)) + { + return (-EFAULT); + } + + idefloppy_create_format_unit_cmd(&pc, blocks, length); + if (idefloppy_queue_pc_tail (drive, &pc)) + { + return (-EIO); + } + return (0); +} + +/* +** Get ATAPI_FORMAT_UNIT progress indication. +** +** Userland gives a pointer to an int. The int is set to a progresss +** indicator 0-65536, with 65536=100%. +** +** If the drive does not support format progress indication, we just return +** a 65536, screw it. +*/ + +static int idefloppy_get_format_progress(ide_drive_t *drive, + struct inode *inode, + struct file *file, + int *arg) +{ + idefloppy_floppy_t *floppy = drive->driver_data; + idefloppy_pc_t pc; + int progress_indication=0x10000; + + if (floppy->srfp) + { + idefloppy_create_request_sense_cmd(&pc); + if (idefloppy_queue_pc_tail (drive, &pc)) + { + return (-EIO); + } + + if (floppy->sense_key == 2 && floppy->asc == 4 && + floppy->ascq == 4) + { + progress_indication=floppy->progress_indication; + } + } + + if (put_user(progress_indication, arg)) + return (-EFAULT); + + return (0); +} + +/* * Our special ide-floppy ioctl's. * * Currently there aren't any ioctl's. @@ -1299,15 +1517,67 @@ unsigned int cmd, unsigned long arg) { idefloppy_pc_t pc; + int prevent = (arg) ? 1 : 0; - if (cmd == CDROMEJECT) { + switch (cmd) { + case CDROMEJECT: + prevent = 0; + /* fall through */ + case CDROM_LOCKDOOR: if (drive->usage > 1) return -EBUSY; - idefloppy_create_prevent_cmd (&pc, 0); - (void) idefloppy_queue_pc_tail (drive, &pc); - idefloppy_create_start_stop_cmd (&pc, 2); + idefloppy_create_prevent_cmd (&pc, prevent); (void) idefloppy_queue_pc_tail (drive, &pc); + if (cmd == CDROMEJECT) { + idefloppy_create_start_stop_cmd (&pc, 2); + (void) idefloppy_queue_pc_tail (drive, &pc); + } return 0; + case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED: + return (0); + case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY: + return (idefloppy_get_format_capacities(drive, inode, file, + (int *)arg)); + case IDEFLOPPY_IOCTL_FORMAT_START: + + if (!(file->f_mode & 2)) + return (-EPERM); + + { + idefloppy_floppy_t *floppy = drive->driver_data; + + set_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags); + + if (drive->usage > 1) + { + /* Don't format if someone is using the disk */ + + clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, + &floppy->flags); + return -EBUSY; + } + else + { + int rc=idefloppy_begin_format(drive, inode, + file, + (int *)arg); + + if (rc) + clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, + &floppy->flags); + return (rc); + + /* + ** Note, the bit will be cleared when the device is + ** closed. This is the cleanest way to handle the + ** situation where the drive does not support + ** format progress reporting. + */ + } + } + case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS: + return (idefloppy_get_format_progress(drive, inode, file, + (int *)arg)); } return -EIO; } @@ -1326,16 +1596,22 @@ MOD_INC_USE_COUNT; if (drive->usage == 1) { + + clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags); + /* Just in case */ + idefloppy_create_test_unit_ready_cmd(&pc); if (idefloppy_queue_pc_tail(drive, &pc)) { idefloppy_create_start_stop_cmd (&pc, 1); (void) idefloppy_queue_pc_tail (drive, &pc); } + if (idefloppy_get_capacity (drive)) { drive->usage--; MOD_DEC_USE_COUNT; return -EIO; } + if (floppy->wp && (filp->f_mode & 2)) { drive->usage--; MOD_DEC_USE_COUNT; @@ -1346,6 +1622,12 @@ (void) idefloppy_queue_pc_tail (drive, &pc); check_disk_change(inode->i_rdev); } + else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags)) + { + drive->usage--; + MOD_DEC_USE_COUNT; + return -EBUSY; + } return 0; } @@ -1358,9 +1640,13 @@ #endif /* IDEFLOPPY_DEBUG_LOG */ if (!drive->usage) { + idefloppy_floppy_t *floppy = drive->driver_data; + invalidate_buffers (inode->i_rdev); idefloppy_create_prevent_cmd (&pc, 0); (void) idefloppy_queue_pc_tail (drive, &pc); + + clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags); } MOD_DEC_USE_COUNT; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/ide-pci.c linux.ac/drivers/ide/ide-pci.c --- linux.vanilla/drivers/ide/ide-pci.c Wed Jan 3 00:58:45 2001 +++ linux.ac/drivers/ide/ide-pci.c Tue Apr 3 17:54:41 2001 @@ -74,6 +74,7 @@ #define DEVID_AMD7409 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409}) #define DEVID_SLC90E66 ((ide_pci_devid_t){PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1}) #define DEVID_OSB4 ((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE}) +#define DEVID_ITE8172G ((ide_pci_devid_t){PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G}) #define IDE_IGNORE ((void *)-1) @@ -185,8 +186,8 @@ #define INIT_HPT366 &ide_init_hpt366 #define DMA_HPT366 &ide_dmacapable_hpt366 #else -static byte hpt363_shared_irq = 0; -static byte hpt363_shared_pin = 0; +static byte hpt363_shared_irq; +static byte hpt363_shared_pin; #define PCI_HPT366 NULL #define ATA66_HPT366 NULL #define INIT_HPT366 NULL @@ -246,6 +247,18 @@ #define INIT_PIIX NULL #endif +#ifdef CONFIG_BLK_DEV_IT8172 +extern unsigned int pci_init_it8172(struct pci_dev *, const char *); +extern unsigned int ata66_it8172(ide_hwif_t *); +extern void ide_init_it8172(ide_hwif_t *); +#define PCI_IT8172 &pci_init_it8172 +#define INIT_IT8172 &ide_init_it8172 +#else +#define PCI_IT8172 NULL +#define ATA66_IT8172 NULL +#define INIT_IT8172 NULL +#endif + #ifdef CONFIG_BLK_DEV_RZ1000 extern void ide_init_rz1000(ide_hwif_t *); #define INIT_RZ1000 &ide_init_rz1000 @@ -381,6 +394,7 @@ {DEVID_AMD7409, "AMD7409", PCI_AMD7409, ATA66_AMD7409, INIT_AMD7409, DMA_AMD7409, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, {DEVID_SLC90E66,"SLC90E66", PCI_SLC90E66, ATA66_SLC90E66, INIT_SLC90E66, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_OSB4, "ServerWorks OSB4", PCI_OSB4, ATA66_OSB4, INIT_OSB4, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_ITE8172G,"IT8172G", PCI_IT8172, NULL, INIT_IT8172, NULL, {{0x00,0x00,0x00}, {0x40,0x00,0x01}}, ON_BOARD, 0 }, {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }}; /* @@ -525,7 +539,8 @@ unsigned int class_rev; #ifdef CONFIG_IDEDMA_AUTO - autodma = 1; + if (!noautodma) + autodma = 1; #endif pci_enable_device(dev); @@ -753,6 +768,12 @@ if (hpt363_shared_pin && hpt363_shared_irq) { d->bootable = ON_BOARD; printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", d->name, pin1, pin2); +#if 0 + /* I forgot why I did this once, but it fixed something. */ + pci_write_config_byte(dev2, PCI_INTERRUPT_PIN, dev->irq); + printk("PCI: %s: Fixing interrupt %d pin %d to ZERO \n", d->name, dev2->irq, pin2); + pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, 0); +#endif } break; } @@ -784,6 +805,8 @@ return; else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))) return; /* CY82C693 is more than only a IDE controller */ + else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_ITE8172G) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))) + return; /* IT8172G is also more than only an IDE controller */ else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) && !(PCI_FUNC(dev->devfn) & 1)) return; /* UM8886A/BF pair */ else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/ide-pmac.c linux.ac/drivers/ide/ide-pmac.c --- linux.vanilla/drivers/ide/ide-pmac.c Fri Feb 16 01:22:08 2001 +++ linux.ac/drivers/ide/ide-pmac.c Tue Apr 3 17:54:41 2001 @@ -176,7 +176,8 @@ if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table) { ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc; #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO - ide_hwifs[ix].autodma = 1; + if (!noautodma) + ide_hwifs[ix].autodma = 1; #endif } } @@ -676,7 +677,8 @@ ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc; #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO - ide_hwifs[ix].autodma = 1; + if (!noautodma) + ide_hwifs[ix].autodma = 1; #endif } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/ide-pnp.c linux.ac/drivers/ide/ide-pnp.c --- linux.vanilla/drivers/ide/ide-pnp.c Thu May 25 02:38:26 2000 +++ linux.ac/drivers/ide/ide-pnp.c Mon Apr 9 23:54:12 2001 @@ -49,7 +49,7 @@ /* ISA PnP device table entry */ struct pnp_dev_t { - unsigned int vendor, device; + unsigned short card_vendor, card_device, vendor, device; int (*init_fn)(struct pci_dev *dev, int enable); }; @@ -82,7 +82,8 @@ /* Add your devices here :)) */ struct pnp_dev_t idepnp_devices[] __initdata = { /* Generic ESDI/IDE/ATA compatible hard disk controller */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0600), + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0600), pnpide_generic_init }, { 0 } }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/ide-tape.c linux.ac/drivers/ide/ide-tape.c --- linux.vanilla/drivers/ide/ide-tape.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/ide/ide-tape.c Tue Apr 3 17:54:41 2001 @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/ide-tape.c Version 1.16f Dec 15, 1999 + * linux/drivers/ide/ide-tape.c Version 1.17 Jan, 2001 * * Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il> * @@ -274,6 +274,18 @@ * this section correctly, a hypothetical and unwanted situation * is being described) * Ver 1.16f Dec 15 99 Change place of the secondary OnStream header frames. + * Ver 1.17 Nov 2000 / Jan 2001 Marcel Mol, marcel@mesa.nl + * - Add idetape_onstream_mode_sense_tape_parameter_page + * function to get tape capacity in frames: tape->capacity. + * - Add support for DI-50 drives( or any DI- drive). + * - 'workaround' for read error/blank block arround block 3000. + * - Implement Early warning for end of media for Onstream. + * - Cosmetic code changes for readability. + * - Idetape_position_tape should not use SKIP bit during + * Onstream read recovery. + * - Add capacity, logical_blk_num and first/last_frame_position + * to /proc/ide/hd?/settings. + * - Module use count was gone in the Linux 2.4 driver. * * * Here are some words from the first releases of hd.c, which are quoted @@ -384,7 +396,7 @@ * sharing a (fast) ATA-2 disk with any (slow) new ATAPI device. */ -#define IDETAPE_VERSION "1.16f" +#define IDETAPE_VERSION "1.17" #include <linux/config.h> #include <linux/module.h> @@ -421,7 +433,11 @@ #define OS_CONFIG_PARTITION (0xff) #define OS_DATA_PARTITION (0) #define OS_PARTITION_VERSION (1) +#define OS_EW 300 +#define OS_ADR_MINREV 2 +#define OS_DATA_STARTFRAME1 20 +#define OS_DATA_ENDFRAME1 2980 /* * partition */ @@ -512,12 +528,33 @@ } os_header_t; /* + * OnStream Tape Parameters Page + */ +typedef struct { + unsigned page_code :6; /* Page code - Should be 0x2b */ + unsigned reserved1_6 :1; + unsigned ps :1; + __u8 reserved2; + __u8 density; /* kbpi */ + __u8 reserved3,reserved4; + __u16 segtrk; /* segment of per track */ + __u16 trks; /* tracks per tape */ + __u8 reserved5,reserved6,reserved7,reserved8,reserved9,reserved10; +} onstream_tape_paramtr_page_t; + +/* * OnStream ADRL frame */ #define OS_FRAME_SIZE (32 * 1024 + 512) #define OS_DATA_SIZE (32 * 1024) #define OS_AUX_SIZE (512) +/* + * internal error codes for onstream + */ +#define OS_PART_ERROR 2 +#define OS_WRITE_ERROR 1 + #include <linux/mtio.h> /**************************** Tunable parameters *****************************/ @@ -949,6 +986,7 @@ int eod_frame_addr; unsigned long cmd_start_time; unsigned long max_cmd_time; + unsigned capacity; /* * Optimize the number of "buffer filling" @@ -1157,7 +1195,7 @@ typedef union { unsigned all :8; struct { - unsigned dma :1; /* Using DMA of PIO */ + unsigned dma :1; /* Using DMA or PIO */ unsigned reserved321 :3; /* Reserved */ unsigned reserved654 :3; /* Reserved (Tag Type) */ unsigned reserved7 :1; /* Reserved */ @@ -1287,7 +1325,9 @@ * by ide-tape. */ #define IDETAPE_CAPABILITIES_PAGE 0x2a +#define IDETAPE_PARAMTR_PAGE 0x2b /* onstream only */ #define IDETAPE_BLOCK_SIZE_PAGE 0x30 +#define IDETAPE_BUFFER_FILLING_PAGE 0x33 /* * Mode Parameter Header for the MODE SENSE packet command @@ -1428,6 +1468,14 @@ #endif /* IDETAPE_DEBUG_LOG_VERBOSE */ /* + * Function declarations + * + */ +static void idetape_onstream_mode_sense_tape_parameter_page(ide_drive_t *drive, int debug); +static int idetape_chrdev_release (struct inode *inode, struct file *filp); +static void idetape_write_release (struct inode *inode); + +/* * Too bad. The drive wants to send us data which we are not ready to accept. * Just throw it away. */ @@ -1452,7 +1500,8 @@ #endif /* IDETAPE_DEBUG_BUGS */ count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), bcount); atapi_input_bytes (drive, bh->b_data + atomic_read(&bh->b_count), count); - bcount -= count; atomic_add(count, &bh->b_count); + bcount -= count; + atomic_add(count, &bh->b_count); if (atomic_read(&bh->b_count) == bh->b_size) { bh = bh->b_reqnext; if (bh) @@ -1476,7 +1525,9 @@ #endif /* IDETAPE_DEBUG_BUGS */ count = IDE_MIN (pc->b_count, bcount); atapi_output_bytes (drive, pc->b_data, count); - bcount -= count; pc->b_data += count; pc->b_count -= count; + bcount -= count; + pc->b_data += count; + pc->b_count -= count; if (!pc->b_count) { pc->bh = bh = bh->b_reqnext; if (bh) { @@ -1577,20 +1628,23 @@ * to analyze the request sense. We currently do not utilize this * information. */ -static void idetape_analyze_error (ide_drive_t *drive,idetape_request_sense_result_t *result) +static void idetape_analyze_error (ide_drive_t *drive, idetape_request_sense_result_t *result) { idetape_tape_t *tape = drive->driver_data; idetape_pc_t *pc = tape->failed_pc; - tape->sense = *result; - tape->sense_key = result->sense_key; tape->asc = result->asc; tape->ascq = result->ascq; + tape->sense = *result; + tape->sense_key = result->sense_key; + tape->asc = result->asc; + tape->ascq = result->ascq; #if IDETAPE_DEBUG_LOG /* * Without debugging, we only log an error if we decided to * give up retrying. */ if (tape->debug_level >= 1) - printk (KERN_INFO "ide-tape: pc = %x, sense key = %x, asc = %x, ascq = %x\n",pc->c[0],result->sense_key,result->asc,result->ascq); + printk (KERN_INFO "ide-tape: pc = %x, sense key = %x, asc = %x, ascq = %x\n", + pc->c[0], result->sense_key, result->asc, result->ascq); #if IDETAPE_DEBUG_LOG_VERBOSE if (tape->debug_level >= 1) printk (KERN_INFO "ide-tape: pc = %s, sense key = %x, asc = %x, ascq = %x\n", @@ -1660,7 +1714,7 @@ static void idetape_active_next_stage (ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; - idetape_stage_t *stage=tape->next_stage; + idetape_stage_t *stage = tape->next_stage; struct request *rq = &stage->rq; #if IDETAPE_DEBUG_LOG @@ -1676,9 +1730,9 @@ rq->buffer = NULL; rq->bh = stage->bh; - tape->active_data_request=rq; - tape->active_stage=stage; - tape->next_stage=stage->next; + tape->active_data_request = rq; + tape->active_stage = stage; + tape->next_stage = stage->next; } /* @@ -1756,12 +1810,12 @@ return; } #endif /* IDETAPE_DEBUG_BUGS */ - stage=tape->first_stage; - tape->first_stage=stage->next; + stage = tape->first_stage; + tape->first_stage = stage->next; idetape_kfree_stage (tape, stage); tape->nr_stages--; if (tape->first_stage == NULL) { - tape->last_stage=NULL; + tape->last_stage = NULL; #if IDETAPE_DEBUG_BUGS if (tape->next_stage != NULL) printk (KERN_ERR "ide-tape: bug: tape->next_stage != NULL\n"); @@ -1821,12 +1875,12 @@ } #endif if (tape->onstream && !tape->raw) { - if (tape->first_frame_position == 0xba4) { + if (tape->first_frame_position == OS_DATA_ENDFRAME1) { #if ONSTREAM_DEBUG - if (tape->debug_level >= 2) - printk("ide-tape: %s: skipping over config parition..\n", tape->name); + if (tape->debug_level >= 2) + printk("ide-tape: %s: skipping over config parition..\n", tape->name); #endif - tape->onstream_write_error = 2; + tape->onstream_write_error = OS_PART_ERROR; if (tape->sem) up(tape->sem); } @@ -1839,7 +1893,7 @@ if (tape->onstream && !tape->raw && error == IDETAPE_ERROR_GENERAL && tape->sense.sense_key == 3) { clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags); printk(KERN_ERR "ide-tape: %s: write error, enabling error recovery\n", tape->name); - tape->onstream_write_error = 1; + tape->onstream_write_error = OS_WRITE_ERROR; remove_stage = 0; tape->nr_pending_stages++; tape->next_stage = tape->first_stage; @@ -1883,11 +1937,11 @@ printk (KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n"); #endif /* IDETAPE_DEBUG_LOG */ if (!tape->pc->error) { - idetape_analyze_error (drive,(idetape_request_sense_result_t *) tape->pc->buffer); - idetape_end_request (1,HWGROUP (drive)); + idetape_analyze_error (drive, (idetape_request_sense_result_t *) tape->pc->buffer); + idetape_end_request (1, HWGROUP (drive)); } else { printk (KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n"); - idetape_end_request (0,HWGROUP (drive)); + idetape_end_request (0, HWGROUP (drive)); } return ide_stopped; } @@ -1980,7 +2034,7 @@ idetape_status_reg_t status; idetape_bcount_reg_t bcount; idetape_ireason_reg_t ireason; - idetape_pc_t *pc=tape->pc; + idetape_pc_t *pc = tape->pc; unsigned int temp; unsigned long cmd_time; @@ -2011,7 +2065,7 @@ */ set_bit (PC_DMA_ERROR, &pc->flags); } else if (!status.b.check) { - pc->actually_transferred=pc->request_transfer; + pc->actually_transferred = pc->request_transfer; idetape_update_buffers (pc); } #if IDETAPE_DEBUG_LOG @@ -2064,7 +2118,7 @@ return ide_stopped; } if (tape->failed_pc == pc) - tape->failed_pc=NULL; + tape->failed_pc = NULL; return pc->callback(drive); /* Command finished - Call the callback function */ } #ifdef CONFIG_BLK_DEV_IDEDMA @@ -2075,9 +2129,9 @@ return ide_do_reset (drive); } #endif /* CONFIG_BLK_DEV_IDEDMA */ - bcount.b.high=IN_BYTE (IDE_BCOUNTH_REG); /* Get the number of bytes to transfer */ - bcount.b.low=IN_BYTE (IDE_BCOUNTL_REG); /* on this interrupt */ - ireason.all=IN_BYTE (IDE_IREASON_REG); + bcount.b.high = IN_BYTE (IDE_BCOUNTH_REG); /* Get the number of bytes to transfer */ + bcount.b.low = IN_BYTE (IDE_BCOUNTL_REG); /* on this interrupt */ + ireason.all = IN_BYTE (IDE_IREASON_REG); if (ireason.b.cod) { printk (KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n"); @@ -2093,8 +2147,8 @@ if ( temp > pc->request_transfer) { if (temp > pc->buffer_size) { printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n"); - idetape_discard_data (drive,bcount.all); - ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD,NULL); + idetape_discard_data (drive, bcount.all); + ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); return ide_started; } #if IDETAPE_DEBUG_LOG @@ -2114,13 +2168,13 @@ else atapi_input_bytes (drive,pc->current_position,bcount.all); /* Read the current buffer */ } - pc->actually_transferred+=bcount.all; /* Update the current position */ + pc->actually_transferred += bcount.all; /* Update the current position */ pc->current_position+=bcount.all; #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 2) printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all); #endif - ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD,NULL); /* And set the interrupt handler again */ + ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); /* And set the interrupt handler again */ return ide_started; } @@ -2178,7 +2232,7 @@ printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n"); return startstop; } - ireason.all=IN_BYTE (IDE_IREASON_REG); + ireason.all = IN_BYTE (IDE_IREASON_REG); while (retries-- && (!ireason.b.cod || ireason.b.io)) { printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, retrying\n"); udelay(100); @@ -2203,7 +2257,7 @@ { idetape_tape_t *tape = drive->driver_data; idetape_bcount_reg_t bcount; - int dma_ok=0; + int dma_ok = 0; #if IDETAPE_DEBUG_BUGS if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) { @@ -2212,8 +2266,8 @@ #endif /* IDETAPE_DEBUG_BUGS */ if (tape->failed_pc == NULL && pc->c[0] != IDETAPE_REQUEST_SENSE_CMD) - tape->failed_pc=pc; - tape->pc=pc; /* Set the current packet command */ + tape->failed_pc = pc; + tape->pc = pc; /* Set the current packet command */ if (pc->retries > IDETAPE_MAX_PC_RETRIES || test_bit (PC_ABORT, &pc->flags)) { /* @@ -2223,24 +2277,25 @@ * example). */ if (!test_bit (PC_ABORT, &pc->flags)) { - if (!(pc->c[0] == 0 && tape->sense_key == 2 && tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8))) { + if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD && tape->sense_key == 2 && + tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8))) { printk (KERN_ERR "ide-tape: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n", tape->name, pc->c[0], tape->sense_key, tape->asc, tape->ascq); - if (tape->onstream && pc->c[0] == 8 && tape->sense_key == 3 && tape->asc == 0x11) /* AJN-1: 11 should be 0x11 */ + if (tape->onstream && pc->c[0] == IDETAPE_READ_CMD && tape->sense_key == 3 && tape->asc == 0x11) /* AJN-1: 11 should be 0x11 */ printk(KERN_ERR "ide-tape: %s: enabling read error recovery\n", tape->name); } pc->error = IDETAPE_ERROR_GENERAL; /* Giving up */ } - tape->failed_pc=NULL; + tape->failed_pc = NULL; return pc->callback(drive); } #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 2) - printk (KERN_INFO "ide-tape: Retry number - %d\n",pc->retries); + printk (KERN_INFO "ide-tape: Retry number - %d\n", pc->retries); #endif /* IDETAPE_DEBUG_LOG */ pc->retries++; - pc->actually_transferred=0; /* We haven't transferred any data yet */ + pc->actually_transferred = 0; /* We haven't transferred any data yet */ pc->current_position=pc->buffer; bcount.all=pc->request_transfer; /* Request to transfer the entire buffer at once */ @@ -2250,15 +2305,15 @@ (void) HWIF(drive)->dmaproc(ide_dma_off, drive); } if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) - dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive); + dma_ok = !HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive); #endif /* CONFIG_BLK_DEV_IDEDMA */ if (IDE_CONTROL_REG) - OUT_BYTE (drive->ctl,IDE_CONTROL_REG); - OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG); /* Use PIO/DMA */ - OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG); - OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG); - OUT_BYTE (drive->select.all,IDE_SELECT_REG); + OUT_BYTE (drive->ctl, IDE_CONTROL_REG); + OUT_BYTE (dma_ok ? 1 : 0, IDE_FEATURE_REG); /* Use PIO/DMA */ + OUT_BYTE (bcount.b.high, IDE_BCOUNTH_REG); + OUT_BYTE (bcount.b.low, IDE_BCOUNTL_REG); + OUT_BYTE (drive->select.all, IDE_SELECT_REG); #ifdef CONFIG_BLK_DEV_IDEDMA if (dma_ok) { /* Begin DMA, if necessary */ set_bit (PC_DMA_IN_PROGRESS, &pc->flags); @@ -2287,7 +2342,7 @@ printk (KERN_INFO "ide-tape: Reached idetape_pc_callback\n"); #endif /* IDETAPE_DEBUG_LOG */ - idetape_end_request (tape->pc->error ? 0:1, HWGROUP(drive)); + idetape_end_request (tape->pc->error ? 0 : 1, HWGROUP(drive)); return ide_stopped; } @@ -2333,7 +2388,7 @@ if (tape->debug_level >= 1) printk(KERN_INFO "ide-tape: buffer fill callback, %d/%d\n", tape->cur_frames, tape->max_frames); #endif - idetape_end_request (tape->pc->error ? 0:1, HWGROUP(drive)); + idetape_end_request (tape->pc->error ? 0 : 1, HWGROUP(drive)); return ide_stopped; } @@ -2344,7 +2399,7 @@ pc = idetape_next_pc_storage (drive); rq = idetape_next_rq_storage (drive); - idetape_create_mode_sense_cmd (pc, 0x33); + idetape_create_mode_sense_cmd (pc, IDETAPE_BUFFER_FILLING_PAGE); pc->callback = idetape_onstream_buffer_fill_callback; idetape_queue_pc_head (drive, pc, rq); } @@ -2564,7 +2619,7 @@ * We do not support buffer cache originated requests. */ printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%d)\n", drive->name, rq->cmd); - ide_end_request (0,HWGROUP (drive)); /* Let the common code handle it */ + ide_end_request (0, HWGROUP (drive)); /* Let the common code handle it */ return ide_stopped; } @@ -2578,7 +2633,7 @@ if (postponed_rq != NULL) if (rq != postponed_rq) { printk (KERN_ERR "ide-tape: ide-tape.c bug - Two DSC requests were queued\n"); - idetape_end_request (0,HWGROUP (drive)); + idetape_end_request (0, HWGROUP (drive)); return ide_stopped; } #endif /* IDETAPE_DEBUG_BUGS */ @@ -2624,8 +2679,15 @@ tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time); calculate_speeds(drive); if (tape->onstream && tape->max_frames && - ((rq->cmd == IDETAPE_WRITE_RQ && (tape->cur_frames == tape->max_frames || (tape->speed_control && tape->cur_frames > 5 && (tape->insert_speed > tape->max_insert_speed || (0 /* tape->cur_frames > 30 && tape->tape_still_time > 200 */))))) || - (rq->cmd == IDETAPE_READ_RQ && (tape->cur_frames == 0 || (tape->speed_control && (tape->cur_frames < tape->max_frames - 5) && tape->insert_speed > tape->max_insert_speed)) && rq->nr_sectors))) { + ((rq->cmd == IDETAPE_WRITE_RQ && + ( tape->cur_frames == tape->max_frames || + ( tape->speed_control && tape->cur_frames > 5 && + (tape->insert_speed > tape->max_insert_speed || + (0 /* tape->cur_frames > 30 && tape->tape_still_time > 200 */) ) ) ) ) || + (rq->cmd == IDETAPE_READ_RQ && + ( tape->cur_frames == 0 || + ( tape->speed_control && (tape->cur_frames < tape->max_frames - 5) && + tape->insert_speed > tape->max_insert_speed ) ) && rq->nr_sectors) ) ) { #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 4) printk(KERN_INFO "ide-tape: postponing request, cmd %d, cur %d, max %d\n", @@ -2672,7 +2734,7 @@ if (jiffies > tape->last_buffer_fill + 5 * HZ / 100) tape->req_buffer_fill = 1; } - pc=idetape_next_pc_storage (drive); + pc = idetape_next_pc_storage (drive); idetape_create_read_cmd (tape, pc, rq->current_nr_sectors, rq->bh); break; case IDETAPE_WRITE_RQ: @@ -2689,12 +2751,12 @@ tape->req_buffer_fill = 1; calculate_speeds(drive); } - pc=idetape_next_pc_storage (drive); + pc = idetape_next_pc_storage (drive); idetape_create_write_cmd (tape, pc, rq->current_nr_sectors, rq->bh); break; case IDETAPE_READ_BUFFER_RQ: tape->postpone_cnt = 0; - pc=idetape_next_pc_storage (drive); + pc = idetape_next_pc_storage (drive); idetape_create_read_buffer_cmd (tape, pc, rq->current_nr_sectors, rq->bh); break; case IDETAPE_ABORTED_WRITE_RQ: @@ -2710,7 +2772,7 @@ idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive)); return ide_stopped; case IDETAPE_PC_RQ1: - pc=(idetape_pc_t *) rq->buffer; + pc = (idetape_pc_t *) rq->buffer; rq->cmd = IDETAPE_PC_RQ2; break; case IDETAPE_PC_RQ2: @@ -2718,7 +2780,7 @@ return ide_stopped; default: printk (KERN_ERR "ide-tape: bug in IDETAPE_RQ_CMD macro\n"); - idetape_end_request (0,HWGROUP (drive)); + idetape_end_request (0, HWGROUP (drive)); return ide_stopped; } return idetape_issue_packet_command (drive, pc); @@ -2844,7 +2906,9 @@ #endif /* IDETAPE_DEBUG_BUGS */ count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), n); copy_from_user (bh->b_data + atomic_read(&bh->b_count), buf, count); - n -= count; atomic_add(count, &bh->b_count); buf += count; + n -= count; + atomic_add(count, &bh->b_count); + buf += count; if (atomic_read(&bh->b_count) == bh->b_size) { bh = bh->b_reqnext; if (bh) @@ -2868,7 +2932,10 @@ #endif /* IDETAPE_DEBUG_BUGS */ count = IDE_MIN (tape->b_count, n); copy_to_user (buf, tape->b_data, count); - n -= count; tape->b_data += count; tape->b_count -= count; buf += count; + n -= count; + tape->b_data += count; + tape->b_count -= count; + buf += count; if (!tape->b_count) { tape->bh = bh = bh->b_reqnext; if (bh) { @@ -2920,10 +2987,10 @@ if (tape->last_stage != NULL) tape->last_stage->next=stage; else - tape->first_stage=tape->next_stage=stage; - tape->last_stage=stage; + tape->first_stage = tape->next_stage=stage; + tape->last_stage = stage; if (tape->next_stage == NULL) - tape->next_stage=tape->last_stage; + tape->next_stage = tape->last_stage; tape->nr_stages++; tape->nr_pending_stages++; spin_unlock_irqrestore(&tape->spinlock, flags); @@ -2953,26 +3020,21 @@ par->par_desc_ver = OS_PARTITION_VERSION; par->wrt_pass_cntr = htons(0xffff); par->first_frame_addr = htonl(0); - par->last_frame_addr = htonl(0xbb7); + par->last_frame_addr = htonl(0xbb7); /* 2999 */ + aux->frame_seq_num = htonl(0); + aux->logical_blk_num_high = htonl(0); + aux->logical_blk_num = htonl(0); + aux->next_mark_addr = htonl(tape->first_mark_addr); } else { aux->update_frame_cntr = htonl(0); par->partition_num = OS_DATA_PARTITION; par->par_desc_ver = OS_PARTITION_VERSION; par->wrt_pass_cntr = htons(tape->wrt_pass_cntr); - par->first_frame_addr = htonl(0x14); - par->last_frame_addr = htonl(19239 * 24); - } - if (frame_type != OS_FRAME_TYPE_HEADER) { + par->first_frame_addr = htonl(OS_DATA_STARTFRAME1); + par->last_frame_addr = htonl(tape->capacity); aux->frame_seq_num = htonl(logical_blk_num); aux->logical_blk_num_high = htonl(0); aux->logical_blk_num = htonl(logical_blk_num); - } else { - aux->frame_seq_num = htonl(0); - aux->logical_blk_num_high = htonl(0); - aux->logical_blk_num = htonl(0); - } - - if (frame_type != OS_FRAME_TYPE_HEADER) { dat->dat_sz = 8; dat->reserved1 = 0; dat->entry_cnt = 1; @@ -2987,11 +3049,10 @@ else dat->dat_list[0].flags = OS_DAT_FLAGS_DATA; dat->dat_list[0].reserved = 0; - } else - aux->next_mark_addr = htonl(tape->first_mark_addr); - aux->filemark_cnt = ntohl(tape->filemark_cnt); - aux->phys_fm = ntohl(0xffffffff); - aux->last_mark_addr = ntohl(tape->last_mark_addr); + } + aux->filemark_cnt = ntohl(tape->filemark_cnt); /* shouldn't this be htonl ?? */ + aux->phys_fm = ntohl(0xffffffff); /* shouldn't this be htonl ?? */ + aux->last_mark_addr = ntohl(tape->last_mark_addr); /* shouldn't this be htonl ?? */ } /* @@ -3042,7 +3103,7 @@ if (result->bpu) { printk (KERN_INFO "ide-tape: Block location is unknown to the tape\n"); clear_bit (IDETAPE_ADDRESS_VALID, &tape->flags); - idetape_end_request (0,HWGROUP (drive)); + idetape_end_request (0, HWGROUP (drive)); } else { #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 2) @@ -3053,10 +3114,10 @@ tape->last_frame_position = ntohl (result->last_block); tape->blocks_in_buffer = result->blocks_in_buffer[2]; set_bit (IDETAPE_ADDRESS_VALID, &tape->flags); - idetape_end_request (1,HWGROUP (drive)); + idetape_end_request (1, HWGROUP (drive)); } } else { - idetape_end_request (0,HWGROUP (drive)); + idetape_end_request (0, HWGROUP (drive)); } return ide_stopped; } @@ -3076,8 +3137,8 @@ idetape_init_pc (pc); pc->c[0] = IDETAPE_WRITE_FILEMARK_CMD; if (tape->onstream) - pc->c[1] = 1; - pc->c[4] = write_filemark; + pc->c[1] = 1; /* Immed bit */ + pc->c[4] = write_filemark; /* not used for OnStream ?? */ set_bit (PC_WAIT_FOR_DSC, &pc->flags); pc->callback = &idetape_pc_callback; } @@ -3109,7 +3170,7 @@ * the request to the request list without waiting for it to be serviced ! * In that case, we usually use idetape_queue_pc_head. */ -static int __idetape_queue_pc_tail (ide_drive_t *drive,idetape_pc_t *pc) +static int __idetape_queue_pc_tail (ide_drive_t *drive, idetape_pc_t *pc) { struct request rq; @@ -3150,7 +3211,7 @@ return 0; if (tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2) { idetape_create_load_unload_cmd (drive, &pc, IDETAPE_LU_LOAD_MASK); - __idetape_queue_pc_tail(drive,&pc); + __idetape_queue_pc_tail(drive, &pc); idetape_create_test_unit_ready_cmd(&pc); if (!__idetape_queue_pc_tail(drive, &pc)) return 0; @@ -3169,7 +3230,8 @@ int rc; rc = __idetape_queue_pc_tail(drive, pc); - if (rc) return rc; + if (rc) + return rc; if (tape->onstream && test_bit(PC_WAIT_FOR_DSC, &pc->flags)) rc = idetape_wait_ready(drive, 60 * 10 * HZ); /* AJN-4: Changed from 5 to 10 minutes; because retension takes approx. 8:20 with Onstream 30GB tape */ @@ -3182,7 +3244,7 @@ int rc; idetape_create_write_filemark_cmd(drive, &pc, 0); - if ((rc = idetape_queue_pc_tail (drive,&pc))) + if ((rc = idetape_queue_pc_tail (drive, &pc))) return rc; idetape_wait_ready(drive, 60 * 5 * HZ); return 0; @@ -3206,7 +3268,7 @@ idetape_flush_tape_buffers(drive); #endif idetape_create_read_position_cmd(&pc); - if (idetape_queue_pc_tail (drive,&pc)) + if (idetape_queue_pc_tail (drive, &pc)) return -1; position = tape->first_frame_position; #ifdef NO_LONGER_REQUIRED @@ -3231,12 +3293,17 @@ idetape_init_pc (pc); pc->c[0] = IDETAPE_LOCATE_CMD; if (tape->onstream) - pc->c[1] = 1; + pc->c[1] = 1; /* Immediate bit */ else pc->c[1] = 2; put_unaligned (htonl (block), (unsigned int *) &pc->c[3]); pc->c[8] = partition; if (tape->onstream) + /* + * Set SKIP bit. + * In case of write error this will write buffered + * data in the drive to this new position! + */ pc->c[9] = skip << 7; set_bit (PC_WAIT_FOR_DSC, &pc->flags); pc->callback = &idetape_pc_callback; @@ -3307,11 +3374,12 @@ __idetape_discard_read_pipeline(drive); idetape_wait_ready(drive, 60 * 5 * HZ); idetape_create_locate_cmd (drive, &pc, block, partition, skip); - retval=idetape_queue_pc_tail (drive,&pc); - if (retval) return (retval); + retval = idetape_queue_pc_tail (drive, &pc); + if (retval) + return (retval); idetape_create_read_position_cmd (&pc); - return (idetape_queue_pc_tail (drive,&pc)); + return (idetape_queue_pc_tail (drive, &pc)); } static void idetape_discard_read_pipeline (ide_drive_t *drive, int restore_position) @@ -3339,7 +3407,7 @@ { idetape_pc_t pc; - idetape_create_mode_sense_cmd (&pc, 0x33); + idetape_create_mode_sense_cmd (&pc, IDETAPE_BUFFER_FILLING_PAGE); pc.callback = idetape_onstream_buffer_fill_callback; (void) idetape_queue_pc_tail(drive, &pc); } @@ -3447,33 +3515,41 @@ idetape_tape_t *tape = drive->driver_data; unsigned int block; - if (tape->onstream_write_error == 1) { - printk(KERN_ERR "ide-tape: %s: detected physical bad block at %u\n", tape->name, ntohl(tape->sense.information)); - block = ntohl(tape->sense.information) + 80; + if (tape->onstream_write_error == OS_WRITE_ERROR) { + printk(KERN_ERR "ide-tape: %s: onstream_write_error_recovery: detected physical bad block at %u, logical %u first frame %u last_frame %u bufblocks %u stages %u skipping %u frames\n", + tape->name, ntohl(tape->sense.information), tape->logical_blk_num, + tape->first_frame_position, tape->last_frame_position, + tape->blocks_in_buffer, tape->nr_stages, + (ntohl(tape->sense.command_specific) >> 16) & 0xff ); + block = ntohl(tape->sense.information) + ((ntohl(tape->sense.command_specific) >> 16) & 0xff); idetape_update_stats(drive); printk(KERN_ERR "ide-tape: %s: relocating %d buffered logical blocks to physical block %u\n", tape->name, tape->cur_frames, block); +#if 0 /* isn't once enough ??? MM */ idetape_update_stats(drive); +#endif if (tape->firmware_revision_num >= 106) idetape_position_tape(drive, block, 0, 1); else { idetape_onstream_read_back_buffer(drive); idetape_position_tape(drive, block, 0, 0); } +#if 0 /* already done in idetape_position_tape MM */ idetape_read_position(drive); +#endif #if ONSTREAM_DEBUG if (tape->debug_level >= 1) printk(KERN_ERR "ide-tape: %s: positioning complete, cur_frames %d, pos %d, tape pos %d\n", tape->name, tape->cur_frames, tape->first_frame_position, tape->last_frame_position); #endif - } else if (tape->onstream_write_error == 2) { + } else if (tape->onstream_write_error == OS_PART_ERROR) { #if ONSTREAM_DEBUG if (tape->debug_level >= 1) printk(KERN_INFO "ide-tape: %s: skipping over config partition\n", tape->name); #endif idetape_flush_tape_buffers(drive); block = idetape_read_position(drive); - if (block != 0xba4) - printk(KERN_ERR "ide-tape: warning, current position %d, expected %d\n", block, 0xba4); - idetape_position_tape(drive, 0xbb8, 0, 0); + if (block != OS_DATA_ENDFRAME1) + printk(KERN_ERR "ide-tape: warning, current position %d, expected %d\n", block, OS_DATA_ENDFRAME1); + idetape_position_tape(drive, 0xbb8, 0, 0); /* 3000 */ } tape->onstream_write_error = 0; } @@ -3572,48 +3648,48 @@ return 1; } if (rq->errors == IDETAPE_ERROR_GENERAL) { - printk(KERN_INFO "ide-tape: %s: skipping frame, read error\n", tape->name); + printk(KERN_INFO "ide-tape: %s: skipping frame %d, read error\n", tape->name, tape->first_frame_position); return 0; } if (rq->errors == IDETAPE_ERROR_EOD) { - printk(KERN_INFO "ide-tape: %s: skipping frame, eod\n", tape->name); + printk(KERN_INFO "ide-tape: %s: skipping frame %d, eod\n", tape->name, tape->first_frame_position); return 0; } if (ntohl(aux->format_id) != 0) { - printk(KERN_INFO "ide-tape: %s: skipping frame, format_id %u\n", tape->name, ntohl(aux->format_id)); + printk(KERN_INFO "ide-tape: %s: skipping frame %d, format_id %u\n", tape->name, tape->first_frame_position, ntohl(aux->format_id)); return 0; } if (memcmp(aux->application_sig, tape->application_sig, 4) != 0) { - printk(KERN_INFO "ide-tape: %s: skipping frame, incorrect application signature\n", tape->name); + printk(KERN_INFO "ide-tape: %s: skipping frame %d, incorrect application signature\n", tape->name, tape->first_frame_position); return 0; } if (aux->frame_type != OS_FRAME_TYPE_DATA && aux->frame_type != OS_FRAME_TYPE_EOD && aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_INFO "ide-tape: %s: skipping frame, frame type %x\n", tape->name, aux->frame_type); + printk(KERN_INFO "ide-tape: %s: skipping frame %d, frame type %x\n", tape->name, tape->first_frame_position, aux->frame_type); return 0; } if (par->partition_num != OS_DATA_PARTITION) { if (!tape->linux_media || tape->linux_media_version != 2) { - printk(KERN_INFO "ide-tape: %s: skipping frame, partition num %d\n", tape->name, par->partition_num); + printk(KERN_INFO "ide-tape: %s: skipping frame %d, partition num %d\n", tape->name, tape->first_frame_position, par->partition_num); return 0; } } if (par->par_desc_ver != OS_PARTITION_VERSION) { - printk(KERN_INFO "ide-tape: %s: skipping frame, partition version %d\n", tape->name, par->par_desc_ver); + printk(KERN_INFO "ide-tape: %s: skipping frame %d, partition version %d\n", tape->name, tape->first_frame_position, par->par_desc_ver); return 0; } if (ntohs(par->wrt_pass_cntr) != tape->wrt_pass_cntr) { - printk(KERN_INFO "ide-tape: %s: skipping frame, wrt_pass_cntr %d (expected %d)(logical_blk_num %u)\n", tape->name, ntohs(par->wrt_pass_cntr), tape->wrt_pass_cntr, ntohl(aux->logical_blk_num)); + printk(KERN_INFO "ide-tape: %s: skipping frame %d, wrt_pass_cntr %d (expected %d)(logical_blk_num %u)\n", tape->name, tape->first_frame_position, ntohs(par->wrt_pass_cntr), tape->wrt_pass_cntr, ntohl(aux->logical_blk_num)); return 0; } if (aux->frame_seq_num != aux->logical_blk_num) { - printk(KERN_INFO "ide-tape: %s: skipping frame, seq != logical\n", tape->name); + printk(KERN_INFO "ide-tape: %s: skipping frame %d, seq != logical\n", tape->name, tape->first_frame_position); return 0; } if (logical_blk_num != -1 && ntohl(aux->logical_blk_num) != logical_blk_num) { if (!quiet) - printk(KERN_INFO "ide-tape: %s: skipping frame, logical_blk_num %u (expected %d)\n", tape->name, ntohl(aux->logical_blk_num), logical_blk_num); + printk(KERN_INFO "ide-tape: %s: skipping frame %d, logical_blk_num %u (expected %d)\n", tape->name, tape->first_frame_position, ntohl(aux->logical_blk_num), logical_blk_num); return 0; } if (aux->frame_type == OS_FRAME_TYPE_MARKER) { @@ -3689,7 +3765,7 @@ idetape_switch_buffers (tape, new_stage); idetape_init_stage(drive, new_stage, OS_FRAME_TYPE_DATA, tape->logical_blk_num); tape->logical_blk_num++; - idetape_add_stage_tail (drive,new_stage); + idetape_add_stage_tail (drive, new_stage); tape->pipeline_head++; #if USE_IOTRACE IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); @@ -3766,7 +3842,7 @@ } #endif /* IDETAPE_DEBUG_BUGS */ if (tape->merge_stage_size) { - blocks=tape->merge_stage_size/tape->tape_block_size; + blocks = tape->merge_stage_size / tape->tape_block_size; if (tape->merge_stage_size % tape->tape_block_size) { blocks++; i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size; @@ -3797,7 +3873,7 @@ tape->merge_stage = NULL; } clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags); - tape->chrdev_direction=idetape_direction_none; + tape->chrdev_direction = idetape_direction_none; /* * On the next backup, perform the feedback loop again. @@ -3874,13 +3950,13 @@ rq.sector = tape->first_frame_position; rq.nr_sectors = rq.current_nr_sectors = blocks; if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) && tape->nr_stages <= max_stages) { - new_stage=idetape_kmalloc_stage (tape); + new_stage = idetape_kmalloc_stage (tape); while (new_stage != NULL) { - new_stage->rq=rq; - idetape_add_stage_tail (drive,new_stage); + new_stage->rq = rq; + idetape_add_stage_tail (drive, new_stage); if (tape->nr_stages >= max_stages) break; - new_stage=idetape_kmalloc_stage (tape); + new_stage = idetape_kmalloc_stage (tape); } } if (!idetape_pipeline_active(tape)) { @@ -3922,16 +3998,23 @@ #endif clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); position = idetape_read_position(drive); + printk(KERN_INFO "ide-tape: %s: blank block detected at %d\n", tape->name, position); if (position >= 3000 && position < 3080) - position += 32; - if (position >= 2980 && position < 3000) + position += 32; /* Why is this check and number ??? MM */ + if (position >= OS_DATA_ENDFRAME1 && position < 3000) position = 3000; else + /* + * compensate for write errors that generally skip 80 frames, + * expect around 20 read errors in a row... + */ position += 60; - if (position >= 2980 && position < 3000) + if (position >= OS_DATA_ENDFRAME1 && position < 3000) position = 3000; - printk(KERN_INFO "ide-tape: %s: blank block detected, positioning tape to block %d\n", tape->name, position); - idetape_position_tape(drive, position, 0, 1); + printk(KERN_INFO "ide-tape: %s: positioning tape to block %d\n", tape->name, position); + if (position == 3000) /* seems to be needed to correctly position at block 3000 MM */ + idetape_position_tape(drive, 0, 0, 0); + idetape_position_tape(drive, position, 0, 0); cnt += 40; continue; } else @@ -4089,12 +4172,14 @@ #endif /* IDETAPE_DEBUG_LOG */ idetape_create_rewind_cmd (drive, &pc); - retval=idetape_queue_pc_tail (drive,&pc); - if (retval) return retval; + retval = idetape_queue_pc_tail (drive, &pc); + if (retval) + return retval; idetape_create_read_position_cmd (&pc); - retval = idetape_queue_pc_tail (drive,&pc); - if (retval) return retval; + retval = idetape_queue_pc_tail (drive, &pc); + if (retval) + return retval; tape->logical_blk_num = 0; return 0; } @@ -4412,7 +4497,7 @@ switch (mt_op) { case MTFSF: idetape_create_space_cmd (&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK); - return (idetape_queue_pc_tail (drive,&pc)); + return (idetape_queue_pc_tail (drive, &pc)); case MTFSFM: if (!tape->capabilities.sprev) return (-EIO); @@ -4423,7 +4508,7 @@ if (!tape->capabilities.sprev) return (-EIO); idetape_create_space_cmd (&pc,-(mt_count+count),IDETAPE_SPACE_OVER_FILEMARK); - return (idetape_queue_pc_tail (drive,&pc)); + return (idetape_queue_pc_tail (drive, &pc)); case MTBSFM: if (!tape->capabilities.sprev) return (-EIO); @@ -4460,7 +4545,7 @@ struct inode *inode = file->f_dentry->d_inode; ide_drive_t *drive = get_drive_ptr (inode->i_rdev); idetape_tape_t *tape = drive->driver_data; - ssize_t bytes_read,temp,actually_read=0, rc; + ssize_t bytes_read,temp, actually_read = 0, rc; if (ppos != &file->f_pos) { /* "A request was outside the capabilities of the device." */ @@ -4482,28 +4567,32 @@ } if ((rc = idetape_initiate_read(drive, tape->max_stages)) < 0) return rc; - if (count==0) + if (count == 0) return (0); if (tape->merge_stage_size) { - actually_read=IDE_MIN (tape->merge_stage_size,count); + actually_read = IDE_MIN (tape->merge_stage_size, count); idetape_copy_stage_to_user (tape, buf, tape->merge_stage, actually_read); - buf += actually_read; tape->merge_stage_size -= actually_read; count-=actually_read; + buf += actually_read; + tape->merge_stage_size -= actually_read; + count -= actually_read; } while (count >= tape->stage_size) { - bytes_read=idetape_add_chrdev_read_request (drive, tape->capabilities.ctl); + bytes_read = idetape_add_chrdev_read_request (drive, tape->capabilities.ctl); if (bytes_read <= 0) goto finish; idetape_copy_stage_to_user (tape, buf, tape->merge_stage, bytes_read); - buf += bytes_read; count -= bytes_read; actually_read += bytes_read; + buf += bytes_read; + count -= bytes_read; + actually_read += bytes_read; } if (count) { bytes_read=idetape_add_chrdev_read_request (drive, tape->capabilities.ctl); if (bytes_read <= 0) goto finish; - temp=IDE_MIN (count,bytes_read); + temp = IDE_MIN (count, bytes_read); idetape_copy_stage_to_user (tape, buf, tape->merge_stage, temp); - actually_read+=temp; - tape->merge_stage_size=bytes_read-temp; + actually_read += temp; + tape->merge_stage_size = bytes_read-temp; } finish: if (!actually_read && test_bit (IDETAPE_FILEMARK, &tape->flags)) { @@ -4515,7 +4604,8 @@ return 0; } if (tape->onstream && !actually_read && test_and_clear_bit(IDETAPE_READ_ERROR, &tape->flags)) { - printk(KERN_ERR "ide-tape: %s: unrecovered read error on logical block number %d, skipping\n", tape->name, tape->logical_blk_num); + printk(KERN_ERR "ide-tape: %s: unrecovered read error on logical block number %d, skipping\n", + tape->name, tape->logical_blk_num); tape->logical_blk_num++; return -EIO; } @@ -4576,6 +4666,37 @@ return; } +static void idetape_write_filler (ide_drive_t *drive, int block, int cnt) +{ + idetape_tape_t *tape = drive->driver_data; + idetape_stage_t *stage; + int rc; + + if (!tape->onstream || tape->raw) + return; + stage = __idetape_kmalloc_stage(tape, 1, 1); + if (stage == NULL) + return; + idetape_init_stage(drive, stage, OS_FRAME_TYPE_FILL, 0); + idetape_wait_ready(drive, 60 * 5 * HZ); + rc = idetape_position_tape(drive, block, 0, 0); +#if ONSTREAM_DEBUG + printk(KERN_INFO "write_filler: positioning failed it returned %d\n", rc); +#endif + if (rc != 0) + return; /* don't write fillers if we cannot position the tape. */ + + strcpy(stage->bh->b_data, "Filler"); + while (cnt--) { + if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) { + printk(KERN_INFO "ide-tape: %s: write_filler: couldn't write header frame\n", tape->name); + __idetape_kfree_stage (stage); + return; + } + } + __idetape_kfree_stage (stage); +} + static void __idetape_write_header (ide_drive_t *drive, int block, int cnt) { idetape_tape_t *tape = drive->driver_data; @@ -4591,12 +4712,12 @@ memset(&header, 0, sizeof(header)); strcpy(header.ident_str, "ADR_SEQ"); header.major_rev = 1; - header.minor_rev = 2; + header.minor_rev = OS_ADR_MINREV; header.par_num = 1; header.partition.partition_num = OS_DATA_PARTITION; header.partition.par_desc_ver = OS_PARTITION_VERSION; - header.partition.first_frame_addr = htonl(0x14); - header.partition.last_frame_addr = htonl(19239 * 24); + header.partition.first_frame_addr = htonl(OS_DATA_STARTFRAME1); + header.partition.last_frame_addr = htonl(tape->capacity); header.partition.wrt_pass_cntr = htons(tape->wrt_pass_cntr); header.partition.eod_frame_addr = htonl(tape->eod_frame_addr); memcpy(stage->bh->b_data, &header, sizeof(header)); @@ -4623,7 +4744,7 @@ return; tape->update_frame_cntr++; __idetape_write_header(drive, 5, 5); - __idetape_write_header(drive, 0xbae, 5); + __idetape_write_header(drive, 0xbae, 5); /* 2990 */ if (locate_eod) { #if ONSTREAM_DEBUG if (tape->debug_level >= 2) @@ -4639,22 +4760,39 @@ struct inode *inode = file->f_dentry->d_inode; ide_drive_t *drive = get_drive_ptr (inode->i_rdev); idetape_tape_t *tape = drive->driver_data; - ssize_t retval,actually_written=0; + ssize_t retval, actually_written = 0; int position; if (ppos != &file->f_pos) { /* "A request was outside the capabilities of the device." */ return -ENXIO; } - if (tape->onstream && (count != tape->tape_block_size)) { - printk(KERN_ERR "ide-tape: %s: use %d bytes as block size (%Zd used)\n", tape->name, tape->tape_block_size, count); - return -EINVAL; - } + #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 3) printk (KERN_INFO "ide-tape: Reached idetape_chrdev_write, count %Zd\n", count); #endif /* IDETAPE_DEBUG_LOG */ + if (tape->onstream) { + if (count != tape->tape_block_size) { + printk(KERN_ERR "ide-tape: %s: chrdev_write: use %d bytes as block size (%d used)\n", + tape->name, tape->tape_block_size, count); + return -EINVAL; + } + /* + * Check if we reach the end of the tape. Just assume the whole pipeline + * is filled with write requests! + */ + if (tape->first_frame_position + tape->nr_stages >= tape->capacity - OS_EW) { +#if ONSTREAM_DEBUG + printk(KERN_INFO, "chrdev_write: Write truncated at EOM early warning"); +#endif + if (tape->chrdev_direction == idetape_direction_write) + idetape_write_release(inode); + return -ENOSPC; + } + } + if (tape->chrdev_direction != idetape_direction_write) { /* Initialize write operation */ if (tape->chrdev_direction == idetape_direction_read) idetape_discard_read_pipeline (drive, 1); @@ -4671,17 +4809,17 @@ if (tape->onstream) { position = idetape_read_position(drive); - if (position <= 20) { + if (position <= OS_DATA_STARTFRAME1) { tape->logical_blk_num = 0; tape->wrt_pass_cntr++; #if ONSTREAM_DEBUG if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: %s: logical block num 0, setting eod to 20\n", tape->name); + printk(KERN_INFO "ide-tape: %s: logical block num 0, setting eod to %d\n", tape->name, OS_DATA_STARTFRAME1); if (tape->debug_level >= 2) printk(KERN_INFO "ide-tape: %s: allocating new write pass counter %d\n", tape->name, tape->wrt_pass_cntr); #endif tape->filemark_cnt = 0; - tape->eod_frame_addr = 20; + tape->eod_frame_addr = OS_DATA_STARTFRAME1; tape->first_mark_addr = tape->last_mark_addr = -1; idetape_write_header(drive, 1); } @@ -4715,7 +4853,7 @@ printk("ide-tape: first_frame_position %d\n", tape->first_frame_position); #endif } - if (count==0) + if (count == 0) return (0); if (tape->restart_speed_control_req) idetape_restart_speed_control(drive); @@ -4723,32 +4861,35 @@ #if IDETAPE_DEBUG_BUGS if (tape->merge_stage_size >= tape->stage_size) { printk (KERN_ERR "ide-tape: bug: merge buffer too big\n"); - tape->merge_stage_size=0; + tape->merge_stage_size = 0; } #endif /* IDETAPE_DEBUG_BUGS */ - actually_written=IDE_MIN (tape->stage_size-tape->merge_stage_size,count); + actually_written = IDE_MIN (tape->stage_size - tape->merge_stage_size, count); idetape_copy_stage_from_user (tape, tape->merge_stage, buf, actually_written); - buf+=actually_written;tape->merge_stage_size+=actually_written;count-=actually_written; + buf += actually_written; + tape->merge_stage_size += actually_written; + count -= actually_written; if (tape->merge_stage_size == tape->stage_size) { tape->merge_stage_size = 0; - retval=idetape_add_chrdev_write_request (drive, tape->capabilities.ctl); + retval = idetape_add_chrdev_write_request (drive, tape->capabilities.ctl); if (retval <= 0) return (retval); } } while (count >= tape->stage_size) { idetape_copy_stage_from_user (tape, tape->merge_stage, buf, tape->stage_size); - buf+=tape->stage_size;count-=tape->stage_size; - retval=idetape_add_chrdev_write_request (drive, tape->capabilities.ctl); - actually_written+=tape->stage_size; + buf += tape->stage_size; + count -= tape->stage_size; + retval = idetape_add_chrdev_write_request (drive, tape->capabilities.ctl); + actually_written += tape->stage_size; if (retval <= 0) return (retval); } if (count) { actually_written+=count; idetape_copy_stage_from_user (tape, tape->merge_stage, buf, count); - tape->merge_stage_size+=count; + tape->merge_stage_size += count; } return (actually_written); } @@ -4760,8 +4901,8 @@ idetape_pc_t pc; if (!tape->onstream) { - idetape_create_write_filemark_cmd(drive, &pc,1); /* Write a filemark */ - if (idetape_queue_pc_tail (drive,&pc)) { + idetape_create_write_filemark_cmd(drive, &pc, 1); /* Write a filemark */ + if (idetape_queue_pc_tail (drive, &pc)) { printk (KERN_ERR "ide-tape: Couldn't write a filemark\n"); return -EIO; } @@ -4937,24 +5078,24 @@ if (idetape_rewind_tape(drive)) return -EIO; if (tape->onstream && !tape->raw) - return idetape_position_tape(drive, 20, 0, 0); + return idetape_position_tape(drive, OS_DATA_STARTFRAME1, 0, 0); return 0; case MTLOAD: idetape_discard_read_pipeline (drive, 0); idetape_create_load_unload_cmd (drive, &pc, IDETAPE_LU_LOAD_MASK); - return (idetape_queue_pc_tail (drive,&pc)); + return (idetape_queue_pc_tail (drive, &pc)); case MTUNLOAD: case MTOFFL: idetape_discard_read_pipeline (drive, 0); idetape_create_load_unload_cmd (drive, &pc,!IDETAPE_LU_LOAD_MASK); - return (idetape_queue_pc_tail (drive,&pc)); + return (idetape_queue_pc_tail (drive, &pc)); case MTNOP: idetape_discard_read_pipeline (drive, 0); return (idetape_flush_tape_buffers (drive)); case MTRETEN: idetape_discard_read_pipeline (drive, 0); idetape_create_load_unload_cmd (drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK); - return (idetape_queue_pc_tail (drive,&pc)); + return (idetape_queue_pc_tail (drive, &pc)); case MTEOM: if (tape->onstream) { #if ONSTREAM_DEBUG @@ -4968,24 +5109,30 @@ return -EIO; return 0; } - idetape_create_space_cmd (&pc,0,IDETAPE_SPACE_TO_EOD); - return (idetape_queue_pc_tail (drive,&pc)); + idetape_create_space_cmd (&pc, 0, IDETAPE_SPACE_TO_EOD); + return (idetape_queue_pc_tail (drive, &pc)); case MTERASE: if (tape->onstream) { - tape->eod_frame_addr = 20; + tape->eod_frame_addr = OS_DATA_STARTFRAME1; tape->logical_blk_num = 0; tape->first_mark_addr = tape->last_mark_addr = -1; idetape_position_tape(drive, tape->eod_frame_addr, 0, 0); idetape_write_eod(drive); idetape_flush_tape_buffers (drive); idetape_write_header(drive, 0); + /* + * write filler frames to the unused frames... + * REMOVE WHEN going to LIN4 application type... + */ + idetape_write_filler(drive, OS_DATA_STARTFRAME1 - 10, 10); + idetape_write_filler(drive, OS_DATA_ENDFRAME1, 10); idetape_flush_tape_buffers (drive); (void) idetape_rewind_tape (drive); return 0; } (void) idetape_rewind_tape (drive); idetape_create_erase_cmd (&pc); - return (idetape_queue_pc_tail (drive,&pc)); + return (idetape_queue_pc_tail (drive, &pc)); case MTSETBLK: if (tape->onstream) { if (mt_count != tape->tape_block_size) { @@ -5028,14 +5175,14 @@ case MTLOCK: if (!idetape_create_prevent_cmd(drive, &pc, 1)) return 0; - retval = idetape_queue_pc_tail (drive,&pc); + retval = idetape_queue_pc_tail (drive, &pc); if (retval) return retval; tape->door_locked = DOOR_EXPLICITLY_LOCKED; return 0; case MTUNLOCK: if (!idetape_create_prevent_cmd(drive, &pc, 0)) return 0; - retval = idetape_queue_pc_tail (drive,&pc); + retval = idetape_queue_pc_tail (drive, &pc); if (retval) return retval; tape->door_locked = DOOR_UNLOCKED; return 0; @@ -5113,7 +5260,7 @@ mtget.mt_gstat |= GMT_ONLINE(0xffffffff); if (tape->first_stage && tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) mtget.mt_gstat |= GMT_EOD(0xffffffff); - if (position <= 20) + if (position <= OS_DATA_STARTFRAME1) mtget.mt_gstat |= GMT_BOT(0xffffffff); } if (copy_to_user ((char *) arg,(char *) &mtget, sizeof (struct mtget))) @@ -5150,7 +5297,7 @@ tape->header_ok = tape->linux_media = 0; tape->update_frame_cntr = 0; tape->wrt_pass_cntr = 0; - tape->eod_frame_addr = 20; + tape->eod_frame_addr = OS_DATA_STARTFRAME1; tape->first_mark_addr = tape->last_mark_addr = -1; stage = __idetape_kmalloc_stage (tape, 0, 0); if (stage == NULL) @@ -5172,8 +5319,8 @@ __idetape_kfree_stage (stage); return 0; } - if (header->major_rev != 1 || (header->minor_rev != 1 && header->minor_rev != 2)) - printk(KERN_INFO "ide-tape: warning: revision %d.%d detected (1.1/1.2 supported)\n", header->major_rev, header->minor_rev); + if (header->major_rev != 1 || (header->minor_rev > OS_ADR_MINREV)) + printk(KERN_INFO "ide-tape: warning: revision %d.%d detected (up to 1.%d supported)\n", header->major_rev, header->minor_rev, OS_ADR_MINREV); if (header->par_num != 1) printk(KERN_INFO "ide-tape: warning: %d partitions defined, only one supported\n", header->par_num); tape->wrt_pass_cntr = ntohs(header->partition.wrt_pass_cntr); @@ -5182,12 +5329,14 @@ tape->first_mark_addr = ntohl(aux->next_mark_addr); tape->last_mark_addr = ntohl(aux->last_mark_addr); tape->update_frame_cntr = ntohl(aux->update_frame_cntr); - memcpy(tape->application_sig, aux->application_sig, 4); tape->application_sig[4] = 0; + memcpy(tape->application_sig, aux->application_sig, 4); + tape->application_sig[4] = 0; if (memcmp(tape->application_sig, "LIN", 3) == 0) { tape->linux_media = 1; tape->linux_media_version = tape->application_sig[3] - '0'; if (tape->linux_media_version != 3) - printk(KERN_INFO "ide-tape: %s: Linux media version %d detected (current 3)\n", tape->name, tape->linux_media_version); + printk(KERN_INFO "ide-tape: %s: Linux media version %d detected (current 3)\n", + tape->name, tape->linux_media_version); } else { printk(KERN_INFO "ide-tape: %s: non Linux media detected (%s)\n", tape->name, tape->application_sig); tape->linux_media = 0; @@ -5214,18 +5363,14 @@ for (block = 5; block < 10; block++) if (__idetape_analyze_headers(drive, block)) goto ok; -#if 0 - for (block = 0xbae; block < 0xbb8; block++) -#else - for (block = 0xbae; block < 0xbb3; block++) -#endif + for (block = 0xbae; block < 0xbb3; block++) /* 2990 - 2994 */ if (__idetape_analyze_headers(drive, block)) goto ok; printk(KERN_ERR "ide-tape: %s: failed to find valid ADRL header\n", tape->name); return 0; ok: - if (position < 20) - position = 20; + if (position < OS_DATA_STARTFRAME1) + position = OS_DATA_STARTFRAME1; idetape_position_tape(drive, position, 0, 0); tape->header_ok = 1; return 1; @@ -5251,6 +5396,7 @@ if (test_and_set_bit (IDETAPE_BUSY, &tape->flags)) return -EBUSY; + MOD_INC_USE_COUNT; if (!tape->onstream) { idetape_read_position(drive); if (!test_bit (IDETAPE_ADDRESS_VALID, &tape->flags)) @@ -5263,18 +5409,22 @@ tape->tape_block_size = tape->stage_size = 32768; tape->raw = 0; } + idetape_onstream_mode_sense_tape_parameter_page(drive, tape->debug_level); } if (idetape_wait_ready(drive, 60 * HZ)) { clear_bit(IDETAPE_BUSY, &tape->flags); printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name); + MOD_DEC_USE_COUNT; return -EBUSY; } idetape_read_position(drive); + MOD_DEC_USE_COUNT; clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags); if (tape->chrdev_direction == idetape_direction_none) { + MOD_INC_USE_COUNT; if (idetape_create_prevent_cmd(drive, &pc, 1)) { - if (!idetape_queue_pc_tail (drive,&pc)) { + if (!idetape_queue_pc_tail (drive, &pc)) { if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) tape->door_locked = DOOR_LOCKED; } @@ -5287,6 +5437,28 @@ return 0; } +static void idetape_write_release (struct inode *inode) +{ + ide_drive_t *drive = get_drive_ptr (inode->i_rdev); + idetape_tape_t *tape = drive->driver_data; + unsigned int minor=MINOR (inode->i_rdev); + + idetape_empty_write_pipeline (drive); + tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0); + if (tape->merge_stage != NULL) { + idetape_pad_zeros (drive, tape->tape_block_size * (tape->user_bs_factor - 1)); + __idetape_kfree_stage (tape->merge_stage); + tape->merge_stage = NULL; + } + idetape_write_filemark(drive); + idetape_write_eod(drive); + idetape_flush_tape_buffers (drive); + idetape_write_header(drive, minor >= 128); + idetape_flush_tape_buffers (drive); + + return; +} + /* * Our character device release function. */ @@ -5305,18 +5477,7 @@ #endif /* IDETAPE_DEBUG_LOG */ if (tape->chrdev_direction == idetape_direction_write) { - idetape_empty_write_pipeline (drive); - tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0); - if (tape->merge_stage != NULL) { - idetape_pad_zeros (drive, tape->tape_block_size * (tape->user_bs_factor - 1)); - __idetape_kfree_stage (tape->merge_stage); - tape->merge_stage = NULL; - } - idetape_write_filemark(drive); - idetape_write_eod(drive); - idetape_flush_tape_buffers (drive); - idetape_write_header(drive, minor >= 128); - idetape_flush_tape_buffers (drive); + idetape_write_release(inode); } if (tape->chrdev_direction == idetape_direction_read) { if (minor < 128) @@ -5333,9 +5494,10 @@ if (tape->chrdev_direction == idetape_direction_none) { if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) { if (idetape_create_prevent_cmd(drive, &pc, 0)) - if (!idetape_queue_pc_tail (drive,&pc)) + if (!idetape_queue_pc_tail (drive, &pc)) tape->door_locked = DOOR_UNLOCKED; } + MOD_DEC_USE_COUNT; } clear_bit (IDETAPE_BUSY, &tape->flags); unlock_kernel(); @@ -5491,7 +5653,7 @@ pc.buffer[4 + 5] = vendor[3]; pc.buffer[4 + 6] = 0; pc.buffer[4 + 7] = 0; - if (idetape_queue_pc_tail (drive,&pc)) + if (idetape_queue_pc_tail (drive, &pc)) printk (KERN_ERR "ide-tape: Couldn't set vendor name to %s\n", vendor); } @@ -5513,7 +5675,7 @@ pc.buffer[4 + 1] = 2; pc.buffer[4 + 2] = 4; pc.buffer[4 + 3] = retries; - if (idetape_queue_pc_tail (drive,&pc)) + if (idetape_queue_pc_tail (drive, &pc)) printk (KERN_ERR "ide-tape: Couldn't set retries to %d\n", retries); } #endif @@ -5530,8 +5692,8 @@ /* * Get the current block size from the block size mode page */ - idetape_create_mode_sense_cmd (&pc,IDETAPE_BLOCK_SIZE_PAGE); - if (idetape_queue_pc_tail (drive,&pc)) + idetape_create_mode_sense_cmd (&pc, IDETAPE_BLOCK_SIZE_PAGE); + if (idetape_queue_pc_tail (drive, &pc)) printk (KERN_ERR "ide-tape: can't get tape block size mode page\n"); header = (idetape_mode_parameter_header_t *) pc.buffer; bs = (idetape_block_size_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl); @@ -5552,7 +5714,7 @@ bs->record32 = 0; bs->record32_5 = 1; idetape_create_mode_select_cmd(&pc, sizeof(*header) + sizeof(*bs)); - if (idetape_queue_pc_tail (drive,&pc)) + if (idetape_queue_pc_tail (drive, &pc)) printk (KERN_ERR "ide-tape: Couldn't set tape block size mode page\n"); #if ONSTREAM_DEBUG @@ -5575,7 +5737,7 @@ idetape_inquiry_result_t *inquiry; idetape_create_inquiry_cmd(&pc); - if (idetape_queue_pc_tail (drive,&pc)) { + if (idetape_queue_pc_tail (drive, &pc)) { printk (KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name); return; } @@ -5618,6 +5780,34 @@ } /* + * idetape_get_mode_sense_parameters asks the tape about its various + * parameters. This may work for other drives to??? + */ +static void idetape_onstream_mode_sense_tape_parameter_page(ide_drive_t *drive, int debug) +{ + idetape_tape_t *tape = drive->driver_data; + idetape_pc_t pc; + idetape_mode_parameter_header_t *header; + onstream_tape_paramtr_page_t *prm; + + idetape_create_mode_sense_cmd (&pc, IDETAPE_PARAMTR_PAGE); + if (idetape_queue_pc_tail (drive, &pc)) { + printk (KERN_ERR "ide-tape: Can't get tape parameters page - probably no tape inserted in onstream drive\n"); + return; + } + header = (idetape_mode_parameter_header_t *) pc.buffer; + prm = (onstream_tape_paramtr_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl); + + tape->capacity = ntohs(prm->segtrk) * ntohs(prm->trks); + if (debug) { + printk (KERN_INFO "ide-tape: %s <-> %s: Tape length %dMB (%d frames/track, %d tracks = %d blocks, density: %dKbpi)\n", + drive->name, tape->name, tape->capacity/32, ntohs(prm->segtrk), ntohs(prm->trks), tape->capacity, prm->density); + } + + return; +} + +/* * idetape_get_mode_sense_results asks the tape about its various * parameters. In particular, we will adjust our data transfer buffer * size to the recommended value as returned by the tape. @@ -5629,8 +5819,8 @@ idetape_mode_parameter_header_t *header; idetape_capabilities_page_t *capabilities; - idetape_create_mode_sense_cmd (&pc,IDETAPE_CAPABILITIES_PAGE); - if (idetape_queue_pc_tail (drive,&pc)) { + idetape_create_mode_sense_cmd (&pc, IDETAPE_CAPABILITIES_PAGE); + if (idetape_queue_pc_tail (drive, &pc)) { printk (KERN_ERR "ide-tape: Can't get tape parameters - assuming some default values\n"); tape->tape_block_size = 512; tape->capabilities.ctl = 52; tape->capabilities.speed = 450; tape->capabilities.buffer_size = 6 * 52; @@ -5721,6 +5911,9 @@ ide_add_setting(drive, "tape_still_time",SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->tape_still_time, NULL); ide_add_setting(drive, "max_insert_speed",SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->max_insert_speed, NULL); ide_add_setting(drive, "insert_size", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->insert_size, NULL); + ide_add_setting(drive, "capacity", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->capacity, NULL); + ide_add_setting(drive, "first_frame", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->first_frame_position, NULL); + ide_add_setting(drive, "logical_blk", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->logical_blk_num, NULL); } } @@ -5747,7 +5940,7 @@ spin_lock_init(&tape->spinlock); drive->driver_data = tape; drive->ready_stat = 0; /* An ATAPI device ignores DRDY */ - if (strstr(drive->id->model, "OnStream DI-30")) + if (strstr(drive->id->model, "OnStream DI-")) tape->onstream = 1; drive->dsc_overlap = 1; #ifdef CONFIG_BLK_DEV_IDEPCI @@ -5778,8 +5971,10 @@ idetape_get_inquiry_results(drive); idetape_get_mode_sense_results(drive); - if (tape->onstream) - idetape_configure_onstream(drive); + if (tape->onstream) { + idetape_onstream_mode_sense_tape_parameter_page(drive, 1); + idetape_configure_onstream(drive); + } tape->user_bs_factor = 1; tape->stage_size = tape->capabilities.ctl * tape->tape_block_size; @@ -5867,8 +6062,8 @@ char *out = page; int len; - len = sprintf(out,"%s\n", tape->name); - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); + len = sprintf(out, "%s\n", tape->name); + PROC_IDE_READ_RETURN(page, start, off, count, eof, len); } static ide_proc_entry_t idetape_proc[] = { @@ -5962,7 +6157,7 @@ continue; } if (drive->scsi) { - if (strstr(drive->id->model, "OnStream DI-30")) { + if (strstr(drive->id->model, "OnStream DI-")) { printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model); } else { printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/ide.c linux.ac/drivers/ide/ide.c --- linux.vanilla/drivers/ide/ide.c Tue Apr 3 17:32:02 2001 +++ linux.ac/drivers/ide/ide.c Thu Apr 12 12:02:12 2001 @@ -179,6 +179,8 @@ static int ide_lock; #endif /* __mc68000__ || CONFIG_APUS */ +int noautodma = 0; + /* * ide_modules keeps track of the available IDE chipset/probe/driver modules. */ @@ -789,7 +791,11 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err) { unsigned long flags; - struct request *rq = HWGROUP(drive)->rq; + struct request *rq; + + spin_lock_irqsave(&io_request_lock, flags); + rq = HWGROUP(drive)->rq; + spin_unlock_irqrestore(&io_request_lock, flags); if (rq->cmd == IDE_DRIVE_CMD) { byte *args = (byte *) rq->buffer; @@ -815,10 +821,8 @@ spin_lock_irqsave(&io_request_lock, flags); blkdev_dequeue_request(rq); HWGROUP(drive)->rq = NULL; - blkdev_release_request(rq); + end_that_request_last(rq); spin_unlock_irqrestore(&io_request_lock, flags); - if (rq->sem != NULL) - up(rq->sem); /* inform originator that rq has been serviced */ } /* @@ -1695,7 +1699,7 @@ unsigned long flags; ide_hwgroup_t *hwgroup = HWGROUP(drive); unsigned int major = HWIF(drive)->major; - struct list_head * queue_head; + struct list_head *queue_head = &drive->queue.queue_head; DECLARE_MUTEX_LOCKED(sem); #ifdef CONFIG_BLK_DEV_PDC4030 @@ -1708,7 +1712,6 @@ if (action == ide_wait) rq->sem = &sem; spin_lock_irqsave(&io_request_lock, flags); - queue_head = &drive->queue.queue_head; if (list_empty(queue_head) || action == ide_preempt) { if (action == ide_preempt) hwgroup->rq = NULL; @@ -2892,6 +2895,12 @@ return 1; } #endif /* CONFIG_BLK_DEV_IDEDOUBLER */ + + if (!strcmp(s, "ide=nodma")) { + printk("IDE: Prevented DMA\n"); + noautodma = 1; + return 1; + } #ifdef CONFIG_BLK_DEV_IDEPCI if (!strcmp(s, "ide=reverse")) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/it8172.c linux.ac/drivers/ide/it8172.c --- linux.vanilla/drivers/ide/it8172.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/ide/it8172.c Tue Apr 3 17:54:41 2001 @@ -0,0 +1,283 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * IT8172 IDE controller support + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * stevel@mvista.com or support@mvista.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. + * + * 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. + * + * 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 <linux/config.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/ioport.h> +#include <linux/pci.h> +#include <linux/hdreg.h> +#include <linux/ide.h> +#include <linux/delay.h> +#include <linux/init.h> + +#include <asm/io.h> +#include <asm/it8172/it8172_int.h> + +#include "ide_modes.h" + +/* + * Prototypes + */ +static void it8172_tune_drive (ide_drive_t *drive, byte pio); +#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING) +static byte it8172_dma_2_pio (byte xfer_rate); +static int it8172_tune_chipset (ide_drive_t *drive, byte speed); +static int it8172_config_drive_for_dma (ide_drive_t *drive); +static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive); +#endif +unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name); +void __init ide_init_it8172 (ide_hwif_t *hwif); + + +/* + * Based on settings done by AMI BIOS + * (might be usefull if drive is not registered in CMOS for any reason). + */ +static void it8172_tune_drive (ide_drive_t *drive, byte pio) +{ + unsigned long flags; + u16 master_data; + byte slave_data; + int is_slave = (&HWIF(drive)->drives[1] == drive); + int master_port = HWIF(drive)->index ? 0x42 : 0x40; + int slave_port = 0x44; + /* ISP RTC */ + byte timings[][2] = { { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; + + pio = ide_get_best_pio_mode(drive, pio, 5, NULL); + pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data); + if (is_slave) { + master_data = master_data | 0x4000; + if (pio > 1) + /* enable PPE, IE and TIME */ + master_data = master_data | 0x0070; + pci_read_config_byte(HWIF(drive)->pci_dev, slave_port, &slave_data); + slave_data = slave_data & (HWIF(drive)->index ? 0x0f : 0xf0); + slave_data = slave_data | + ((timings[pio][0] << 2) | (timings[pio][1] + << (HWIF(drive)->index ? 4 : 0))); + } else { + master_data = master_data & 0xccf8; + if (pio > 1) + /* enable PPE, IE and TIME */ + master_data = master_data | 0x0007; + master_data = master_data | (timings[pio][0] << 12) | + (timings[pio][1] << 8); + } + save_flags(flags); + cli(); + pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data); + if (is_slave) + pci_write_config_byte(HWIF(drive)->pci_dev, slave_port, slave_data); + restore_flags(flags); +} + +#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING) +/* + * + */ +static byte it8172_dma_2_pio (byte xfer_rate) +{ + switch(xfer_rate) { + case XFER_UDMA_5: + case XFER_UDMA_4: + case XFER_UDMA_3: + case XFER_UDMA_2: + case XFER_UDMA_1: + case XFER_UDMA_0: + case XFER_MW_DMA_2: + case XFER_PIO_4: + return 4; + case XFER_MW_DMA_1: + case XFER_PIO_3: + return 3; + case XFER_SW_DMA_2: + case XFER_PIO_2: + return 2; + case XFER_MW_DMA_0: + case XFER_SW_DMA_1: + case XFER_SW_DMA_0: + case XFER_PIO_1: + case XFER_PIO_0: + case XFER_PIO_SLOW: + default: + return 0; + } +} + +static int it8172_tune_chipset (ide_drive_t *drive, byte speed) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + int a_speed = 3 << (drive->dn * 4); + int u_flag = 1 << drive->dn; + int u_speed = 0; + int err = 0; + byte reg48, reg4a; + + pci_read_config_byte(dev, 0x48, ®48); + pci_read_config_byte(dev, 0x4a, ®4a); + + switch(speed) { + case XFER_UDMA_4: + case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break; + case XFER_UDMA_5: + case XFER_UDMA_3: + case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break; + case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: + case XFER_SW_DMA_2: break; + default: return -1; + } + + if (speed >= XFER_UDMA_0) { + if (!(reg48 & u_flag)) + pci_write_config_byte(dev, 0x48, reg48|u_flag); + if (!(reg4a & u_speed)) { + pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed); + pci_write_config_byte(dev, 0x4a, reg4a|u_speed); + } + } + if (speed < XFER_UDMA_0) { + if (reg48 & u_flag) + pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); + if (reg4a & a_speed) + pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed); + } + + it8172_tune_drive(drive, it8172_dma_2_pio(speed)); + +#if IT8172_DEBUG + printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn); +#endif + if (!drive->init_speed) + drive->init_speed = speed; + err = ide_config_drive_speed(drive, speed); + drive->current_speed = speed; + return err; +} + +static int it8172_config_drive_for_dma (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + byte speed; + + if (id->dma_ultra & 0x0010) { + speed = XFER_UDMA_2; + } else if (id->dma_ultra & 0x0008) { + speed = XFER_UDMA_1; + } else if (id->dma_ultra & 0x0004) { + speed = XFER_UDMA_2; + } else if (id->dma_ultra & 0x0002) { + speed = XFER_UDMA_1; + } else if (id->dma_ultra & 0x0001) { + speed = XFER_UDMA_0; + } else if (id->dma_mword & 0x0004) { + speed = XFER_MW_DMA_2; + } else if (id->dma_mword & 0x0002) { + speed = XFER_MW_DMA_1; + } else if (id->dma_1word & 0x0004) { + speed = XFER_SW_DMA_2; + } else { + speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); + } + + (void) it8172_tune_chipset(drive, speed); + + return ((int)((id->dma_ultra >> 11) & 7) ? ide_dma_on : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + ((id->dma_1word >> 8) & 7) ? ide_dma_on : + ide_dma_off_quietly); +} + +static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive) +{ + switch (func) { + case ide_dma_check: + return ide_dmaproc((ide_dma_action_t)it8172_config_drive_for_dma(drive), + drive); + default : + break; + } + /* Other cases are done by generic IDE-DMA code. */ + return ide_dmaproc(func, drive); +} +#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_IT8172_TUNING) */ + +unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name) +{ + unsigned char progif; + + /* + * Place both IDE interfaces into PCI "native" mode + */ + (void)pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); + (void)pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05); + + return IT8172_IDE_IRQ; +} + + +void __init ide_init_it8172 (ide_hwif_t *hwif) +{ + struct pci_dev* dev = hwif->pci_dev; + unsigned long cmdBase, ctrlBase; + + hwif->tuneproc = &it8172_tune_drive; + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + + if (!hwif->dma_base) + return; + +#ifndef CONFIG_BLK_DEV_IDEDMA + hwif->autodma = 0; +#else /* CONFIG_BLK_DEV_IDEDMA */ +#ifdef CONFIG_IT8172_TUNING + hwif->autodma = 1; + hwif->dmaproc = &it8172_dmaproc; + hwif->speedproc = &it8172_tune_chipset; +#endif /* CONFIG_IT8172_TUNING */ +#endif /* !CONFIG_BLK_DEV_IDEDMA */ + + cmdBase = dev->resource[0].start; + ctrlBase = dev->resource[1].start; + + ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL); + memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); + hwif->noprobe = 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/opti621.c linux.ac/drivers/ide/opti621.c --- linux.vanilla/drivers/ide/opti621.c Tue Nov 7 19:02:24 2000 +++ linux.ac/drivers/ide/opti621.c Tue Apr 3 17:54:41 2001 @@ -118,7 +118,7 @@ /* Uncommnent for disable read prefetch. * There is some readprefetch capatibility in hdparm, * but when I type hdparm -P 1 /dev/hda, I got errors - * and till reset drive is inacessible. + * and till reset drive is inaccessible. * This (hw) read prefetch is safe on my drive. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/osb4.c linux.ac/drivers/ide/osb4.c --- linux.vanilla/drivers/ide/osb4.c Sun Feb 4 18:05:30 2001 +++ linux.ac/drivers/ide/osb4.c Tue Apr 3 17:54:42 2001 @@ -402,10 +402,16 @@ #ifdef DEBUG printk("%s: reg64 == 0x%08x\n", name, reg64); #endif - reg64 &= ~0x0000A000; -#ifdef CONFIG_SMP - reg64 |= 0x00008000; -#endif + +// reg64 &= ~0x0000A000; +//#ifdef CONFIG_SMP +// reg64 |= 0x00008000; +//#endif + /* Assume the APIC was set up properly by the BIOS for now . If it + wasnt we need to do a fix up _way_ earlier. Bits 15,10,3 control + APIC enable, routing and decode */ + + reg64 &= ~0x00002000; pci_write_config_dword(isa_dev, 0x64, reg64); pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40); @@ -441,7 +447,8 @@ #else /* CONFIG_BLK_DEV_IDEDMA */ if (hwif->dma_base) { - hwif->autodma = 1; + if (!noautodma) + hwif->autodma = 1; hwif->dmaproc = &osb4_dmaproc; } else { hwif->autodma = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/pdc202xx.c linux.ac/drivers/ide/pdc202xx.c --- linux.vanilla/drivers/ide/pdc202xx.c Sat Feb 17 00:02:36 2001 +++ linux.ac/drivers/ide/pdc202xx.c Tue Apr 3 17:54:42 2001 @@ -224,6 +224,7 @@ "QUANTUM FIREBALLlct08 08", "QUANTUM FIREBALLP KA6.4", "QUANTUM FIREBALLP LM20.4", + "QUANTUM FIREBALLP KX20.5", "QUANTUM FIREBALLP LM20.5", NULL }; @@ -861,7 +862,8 @@ #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->dmaproc = &pdc202xx_dmaproc; - hwif->autodma = 1; + if (!noautodma) + hwif->autodma = 1; } else { hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/piix.c linux.ac/drivers/ide/piix.c --- linux.vanilla/drivers/ide/piix.c Tue Apr 3 17:32:02 2001 +++ linux.ac/drivers/ide/piix.c Tue Apr 3 17:54:42 2001 @@ -514,7 +514,8 @@ hwif->autodma = 0; #else /* CONFIG_BLK_DEV_IDEDMA */ #ifdef CONFIG_PIIX_TUNING - hwif->autodma = 1; + if (!noautodma) + hwif->autodma = 1; hwif->dmaproc = &piix_dmaproc; hwif->speedproc = &piix_tune_chipset; #endif /* CONFIG_PIIX_TUNING */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/rz1000.c linux.ac/drivers/ide/rz1000.c --- linux.vanilla/drivers/ide/rz1000.c Fri Apr 14 06:54:26 2000 +++ linux.ac/drivers/ide/rz1000.c Tue Apr 3 17:54:42 2001 @@ -94,4 +94,4 @@ init_rz1000 (dev, "RZ1001"); } -#endif CONFIG_BLK_DEV_IDEPCI +#endif /* CONFIG_BLK_DEV_IDEPCI */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/sis5513.c linux.ac/drivers/ide/sis5513.c --- linux.vanilla/drivers/ide/sis5513.c Wed Jan 3 00:58:45 2001 +++ linux.ac/drivers/ide/sis5513.c Tue Apr 3 17:54:42 2001 @@ -629,7 +629,8 @@ case PCI_DEVICE_ID_SI_5600: case PCI_DEVICE_ID_SI_5597: case PCI_DEVICE_ID_SI_5591: - hwif->autodma = 1; + if (!noautodma) + hwif->autodma = 1; hwif->dmaproc = &sis5513_dmaproc; break; #endif /* CONFIG_BLK_DEV_IDEDMA */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/slc90e66.c linux.ac/drivers/ide/slc90e66.c --- linux.vanilla/drivers/ide/slc90e66.c Tue Apr 3 17:32:02 2001 +++ linux.ac/drivers/ide/slc90e66.c Tue Apr 3 17:54:42 2001 @@ -372,10 +372,10 @@ if (!hwif->dma_base) return; -#ifndef CONFIG_BLK_DEV_IDEDMA hwif->autodma = 0; -#else /* CONFIG_BLK_DEV_IDEDMA */ - hwif->autodma = 1; +#ifdef CONFIG_BLK_DEV_IDEDMA + if (!noautodma) + hwif->autodma = 1; hwif->dmaproc = &slc90e66_dmaproc; hwif->speedproc = &slc90e66_tune_chipset; #endif /* !CONFIG_BLK_DEV_IDEDMA */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/via82cxxx.c linux.ac/drivers/ide/via82cxxx.c --- linux.vanilla/drivers/ide/via82cxxx.c Sat Feb 3 19:27:43 2001 +++ linux.ac/drivers/ide/via82cxxx.c Tue Apr 3 17:54:42 2001 @@ -1,5 +1,5 @@ /* - * $Id: via82cxxx.c,v 3.20 2001/01/27 10:13:60 vojtech Exp $ + * $Id: via82cxxx.c,v 3.23 2001/03/09 09:30:00 vojtech Exp $ * * Copyright (c) 2000-2001 Vojtech Pavlik * @@ -32,14 +32,9 @@ * PIO 0-5, MWDMA 0-2, SWDMA 0-2 and UDMA 0-5 * * (this includes UDMA33, 66 and 100) modes. UDMA66 and higher modes are - * autodetected only in case the BIOS has detected a 80 wire cable. To ignore - * the BIOS data, use 'ide0=ata66' or 'ide1=ata66' on the kernel command line. - * - * For correct operation it's needed to tell the driver the speed of the PCI - * bus. The default, and most common value is 33 MHz. Most likely, your system - * is using this value and you don't need to use any command line options. If - * you run your PCI bus speed at 25, 30, 37, 40 or 42 MHz, use the 'idebus=xx' - * option of the IDE driver. Note that this has nothing to do with UDMA66. + * autoenabled only in case the BIOS has detected a 80 wire cable. To ignore + * the BIOS data and assume the cable is present, use 'ide0=ata66' or + * 'ide1=ata66' on the kernel command line. */ /* @@ -84,15 +79,16 @@ #define VIA_ADDRESS_SETUP 0x4c #define VIA_UDMA_TIMING 0x50 -#define VIA_UDMA 0x07 -#define VIA_UDMA_NONE 0x00 -#define VIA_UDMA_33 0x01 -#define VIA_UDMA_66 0x02 -#define VIA_UDMA_100 0x03 -#define VIA_BAD_PREQ 0x10 -#define VIA_BAD_CLK66 0x20 -#define VIA_SET_FIFO 0x40 -#define VIA_SET_THRESH 0x80 +#define VIA_UDMA 0x007 +#define VIA_UDMA_NONE 0x000 +#define VIA_UDMA_33 0x001 +#define VIA_UDMA_66 0x002 +#define VIA_UDMA_100 0x003 +#define VIA_BAD_PREQ 0x010 /* Crashes if PREQ# till DDACK# set */ +#define VIA_BAD_CLK66 0x020 /* 66 MHz clock doesn't work correctly */ +#define VIA_SET_FIFO 0x040 /* Needs to have FIFO split set */ +#define VIA_SET_THRESH 0x080 /* Needs to have FIFO thresholds set */ +#define VIA_BAD_PIO 0x100 /* Always uses 26 PCICLK/xfer regardles of PIO mode */ /* * VIA SouthBridge chips. @@ -103,13 +99,15 @@ unsigned short id; unsigned char rev_min; unsigned char rev_max; - unsigned char flags; + unsigned short flags; } via_isa_bridges[] = { +#ifdef VIA_NEW_BRIDGES_TESTED { "vt8233", PCI_DEVICE_ID_VIA_8233_0, 0x00, 0x2f, VIA_UDMA_100 }, { "vt8231", PCI_DEVICE_ID_VIA_8231, 0x00, 0x2f, VIA_UDMA_66 }, - { "vt82c686b", PCI_DEVICE_ID_VIA_82C686, 0x40, 0x4f, VIA_UDMA_100 }, +#endif + { "vt82c686b", PCI_DEVICE_ID_VIA_82C686, 0x40, 0x4f, VIA_UDMA_100 | VIA_BAD_PIO }, { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, 0x10, 0x2f, VIA_UDMA_66 }, - { "vt82c686", PCI_DEVICE_ID_VIA_82C686, 0x00, 0x0f, VIA_UDMA_66 }, + { "vt82c686", PCI_DEVICE_ID_VIA_82C686, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 }, { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, 0x10, 0x2f, VIA_UDMA_66 }, { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 }, { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ }, @@ -123,6 +121,7 @@ static unsigned char via_enabled; static unsigned int via_80w; static unsigned int via_clock; +static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100" }; /* * VIA /proc entry. @@ -145,8 +144,8 @@ static int via_get_info(char *buffer, char **addr, off_t offset, int count) { - short speed[4], cycle[4], setup[4], active[4], - recover[4], uen[4], udma[4], active8b[4], recover8b[4]; + short speed[4], cycle[4], setup[4], active[4], recover[4], den[4], + uen[4], udma[4], umul[4], active8b[4], recover8b[4]; struct pci_dev *dev = bmide_dev; unsigned int v, u, i; unsigned short c, w; @@ -155,12 +154,13 @@ via_print("----------VIA BusMastering IDE Configuration----------------"); - via_print("Driver Version: 3.20"); + via_print("Driver Version: 3.23"); via_print("South Bridge: VIA %s", via_config->name); pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t); pci_read_config_byte(dev, PCI_REVISION_ID, &x); via_print("Revision: ISA %#x IDE %#x", t, x); + via_print("Highest DMA rate: %s", via_dma[via_config->flags & VIA_UDMA]); via_print("BM-DMA base: %#x", via_base); via_print("PCI clock: %dMHz", via_clock); @@ -200,28 +200,43 @@ else u = 0; for (i = 0; i < 4; i++) { + setup[i] = ((t >> ((3 - i) << 1)) & 0x3) + 1; recover8b[i] = ((w >> ((1 - (i >> 1)) << 3)) & 0xf) + 1; active8b[i] = ((w >> (((1 - (i >> 1)) << 3) + 4)) & 0xf) + 1; active[i] = ((v >> (((3 - i) << 3) + 4)) & 0xf) + 1; recover[i] = ((v >> ((3 - i) << 3)) & 0xf) + 1; udma[i] = ((u >> ((3 - i) << 3)) & 0x7) + 2; + umul[i] = ((u >> (((3 - i) & 2) << 3)) & 0x8) ? 1 : 2; + uen[i] = ((u >> ((3 - i) << 3)) & 0x20); + den[i] = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2)); + + speed[i] = 20 * via_clock / (active[i] + recover[i]); + cycle[i] = 1000 / via_clock * (active[i] + recover[i]); - if ((via_config->flags & VIA_UDMA) == VIA_UDMA_100) { - speed[i] = 2000 / udma[i]; - cycle[i] = 10 * udma[i]; + if (!uen[i] || !den[i]) continue; - } - uen[i] = (u >> ((3 - i) << 3)) & 0x20; - udma[i] *= ((u >> (((3 - i) & 2) << 3)) & 0x8) ? 1 : 2; + switch (via_config->flags & VIA_UDMA) { + + case VIA_UDMA_100: + speed[i] = 2000 / udma[i]; + cycle[i] = 10 * udma[i]; + break; + + case VIA_UDMA_66: + speed[i] = 40 * via_clock / (udma[i] * umul[i]); + cycle[i] = 500 / via_clock * (udma[i] * umul[i]); + break; - speed[i] = 40 * via_clock / (uen[i] ? udma[i] : (active[i] + recover[i]) * 2); - cycle[i] = 1000 / via_clock * (uen[i] ? udma[i] : (active[i] + recover[i]) * 2) / 2; + case VIA_UDMA_33: + speed[i] = 20 * via_clock / udma[i]; + cycle[i] = 1000 / via_clock * udma[i]; + break; + } } - via_print_drive("Transfer Mode: ", "%10s", - (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2)) ? (uen[i] ? "UDMA" : "DMA") : "PIO"); + via_print_drive("Transfer Mode: ", "%10s", den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO"); via_print_drive("Address Setup: ", "%8dns", (1000 / via_clock) * setup[i]); via_print_drive("Cmd Active: ", "%8dns", (1000 / via_clock) * active8b[i]); @@ -342,12 +357,13 @@ short speed = ide_find_best_mode(drive, XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA | (via_config->flags & VIA_UDMA ? XFER_UDMA : 0) | - (w80 && (via_config->flags & VIA_UDMA) == VIA_UDMA_66 ? XFER_UDMA_66 : 0) | - (w80 && (via_config->flags & VIA_UDMA) == VIA_UDMA_100 ? XFER_UDMA_100 : 0)); - - func = ((speed & XFER_MODE) != XFER_PIO) ? ide_dma_on : ide_dma_off_quietly; + (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) | + (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0)); via_set_drive(drive, speed); + + func = (HWIF(drive)->autodma && (speed & XFER_MODE) != XFER_PIO) + ? ide_dma_on : ide_dma_off_quietly; } return ide_dmaproc(func, drive); @@ -459,11 +475,7 @@ pci_read_config_byte(isa, PCI_REVISION_ID, &t); printk(KERN_INFO "VP_IDE: VIA %s (rev %02x) IDE %s controller on pci%s\n", - via_config->name, t, - (via_config->flags & VIA_UDMA) == VIA_UDMA_100 ? "UDMA100" : - (via_config->flags & VIA_UDMA) == VIA_UDMA_66 ? "UDMA66" : - (via_config->flags & VIA_UDMA) == VIA_UDMA_33 ? "UDMA33" : "MWDMA16", - dev->slot_name); + via_config->name, t, via_dma[via_config->flags & VIA_UDMA], dev->slot_name); /* * Setup /proc/ide/via entry. @@ -471,11 +483,11 @@ #ifdef CONFIG_PROC_FS if (!via_proc) { - via_proc = 1; via_base = pci_resource_start(dev, 4); bmide_dev = dev; isa_dev = isa; via_display_info = &via_get_info; + via_proc = 1; } #endif @@ -506,7 +518,8 @@ if (hwif->dma_base) { hwif->dmaproc = &via82cxxx_dmaproc; #ifdef CONFIG_IDEDMA_AUTO - hwif->autodma = 1; + if (!noautodma) + hwif->autodma = 1; #endif } #endif /* CONFIG_BLK_DEV_IDEDMA */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ieee1394/pcilynx.c linux.ac/drivers/ieee1394/pcilynx.c --- linux.vanilla/drivers/ieee1394/pcilynx.c Tue Apr 3 17:32:02 2001 +++ linux.ac/drivers/ieee1394/pcilynx.c Tue Apr 3 17:54:42 2001 @@ -1355,10 +1355,10 @@ lynx->id = num_of_cards-1; lynx->dev = dev; - lynx->lock = SPIN_LOCK_UNLOCKED; - lynx->phy_reg_lock = SPIN_LOCK_UNLOCKED; + lynx->lock = SPIN_LOCK_UNLOCKED; + lynx->phy_reg_lock = SPIN_LOCK_UNLOCKED; - if (pci_set_dma_mask(dev, 0xffffffff)) { + if (!pci_dma_supported(dev, 0xffffffff)) { FAIL("DMA address limits not supported for PCILynx hardware %d", lynx->id); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ieee1394/video1394.c linux.ac/drivers/ieee1394/video1394.c --- linux.vanilla/drivers/ieee1394/video1394.c Wed Jan 3 00:45:38 2001 +++ linux.ac/drivers/ieee1394/video1394.c Tue Apr 3 17:54:42 2001 @@ -35,6 +35,7 @@ #include <linux/proc_fs.h> #include <linux/tqueue.h> #include <linux/delay.h> +#include <linux/init.h> #include <asm/pgtable.h> #include <asm/page.h> @@ -130,8 +131,10 @@ quadlet_t isoXmitIntEvent); static struct video_card video_cards[MAX_OHCI1394_CARDS]; -static int num_of_video_cards = 0; -static struct video_template video_tmpl = { irq_handler }; +static int num_of_video_cards; +static struct video_template video_tmpl = { + irq_handler: irq_handler, +}; /* Taken from bttv.c */ /*******************************/ @@ -302,13 +305,12 @@ d = (struct dma_iso_ctx *)kmalloc(sizeof(struct dma_iso_ctx), GFP_KERNEL); - memset(d, 0, sizeof(struct dma_iso_ctx)); - if (d==NULL) { PRINT(KERN_ERR, ohci->id, "failed to allocate dma_iso_ctx"); return NULL; } + memset(d, 0, sizeof(struct dma_iso_ctx)); d->ohci = (void *)ohci; d->ctx = ctx; d->channel = channel; @@ -963,8 +965,10 @@ if (wait_event_interruptible(d->waitq, d->buffer_status[v.buffer] == VIDEO1394_BUFFER_READY) - == -ERESTARTSYS) + == -ERESTARTSYS) { + spin_unlock_irqrestore(&d->lock,flags); return -EINTR; + } #endif d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE; break; @@ -1296,32 +1300,17 @@ } } -#ifdef MODULE - /* EXPORT_NO_SYMBOLS; */ MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>"); MODULE_DESCRIPTION("driver for digital video on OHCI board"); MODULE_SUPPORTED_DEVICE("video1394"); -void cleanup_module(void) -{ - int i; - unregister_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME); - - for (i=0; i<num_of_video_cards; i++) - remove_card(&video_cards[i]); - printk(KERN_INFO "removed " VIDEO1394_DRIVER_NAME " module\n"); -} - -int init_module(void) +static int __init video1394_init_driver(void) { struct ti_ohci *ohci; int i; - - memset(video_cards, 0, MAX_OHCI1394_CARDS * sizeof(struct video_card)); - num_of_video_cards = 0; for (i=0; i<MAX_OHCI1394_CARDS; i++) { ohci=ohci1394_get_struct(i); @@ -1349,6 +1338,16 @@ return 0; } -#endif /* MODULE */ +static void __exit video1394_exit_driver(void) +{ + int i; + unregister_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME); + + for (i=0; i<num_of_video_cards; i++) + remove_card(&video_cards[i]); + printk(KERN_INFO "removed " VIDEO1394_DRIVER_NAME " module\n"); +} +module_init(video1394_init_driver); +module_exit(video1394_exit_driver); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/input/evdev.c linux.ac/drivers/input/evdev.c --- linux.vanilla/drivers/input/evdev.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/input/evdev.c Tue Apr 3 17:54:42 2001 @@ -1,5 +1,5 @@ /* - * $Id: evdev.c,v 1.10 2000/06/23 09:23:00 vojtech Exp $ + * $Id: evdev.c,v 1.16 2000/10/17 07:41:53 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * @@ -145,7 +145,19 @@ static ssize_t evdev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos) { - return -EINVAL; + struct evdev_list *list = file->private_data; + struct input_event event; + int retval = 0; + + while (retval < count) { + + if (copy_from_user(&event, buffer + retval, sizeof(struct input_event))) + return -EFAULT; + input_event(list->evdev->handle.dev, event.type, event.code, event.value); + retval += sizeof(struct input_event); + } + + return retval; } static ssize_t evdev_read(struct file * file, char * buffer, size_t count, loff_t *ppos) @@ -310,7 +322,7 @@ evdev->devfs = input_register_minor("event%d", minor, EVDEV_MINOR_BASE); - printk(KERN_INFO "event%d: Event device for input%d\n", minor, dev->number); +// printk(KERN_INFO "event%d: Event device for input%d\n", minor, dev->number); return &evdev->handle; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/input/joydev.c linux.ac/drivers/input/joydev.c --- linux.vanilla/drivers/input/joydev.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/input/joydev.c Thu Apr 12 12:02:19 2001 @@ -1,5 +1,5 @@ /* - * $Id: joydev.c,v 1.13 2000/08/14 21:05:26 vojtech Exp $ + * $Id: joydev.c,v 1.19 2001/01/10 19:49:40 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * Copyright (c) 1999 Colin Van Dyke @@ -232,9 +232,10 @@ if (count == sizeof(struct JS_DATA_TYPE)) { struct JS_DATA_TYPE data; + int i; - data.buttons = ((joydev->nkey > 0 && test_bit(joydev->keypam[0], input->key)) ? 1 : 0) | - ((joydev->nkey > 1 && test_bit(joydev->keypam[1], input->key)) ? 2 : 0); + for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++) + data.buttons |= test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0; data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x; data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y; @@ -323,7 +324,7 @@ struct joydev_list *list = file->private_data; struct joydev *joydev = list->joydev; struct input_dev *dev = joydev->handle.dev; - + int i; switch (cmd) { @@ -360,6 +361,28 @@ case JSIOCGCORR: return copy_to_user((struct js_corr *) arg, joydev->corr, sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0; + case JSIOCSAXMAP: + if (copy_from_user((__u8 *) arg, joydev->abspam, sizeof(__u8) * ABS_MAX)) + return -EFAULT; + for (i = 0; i < ABS_MAX; i++) { + if (joydev->abspam[i] > ABS_MAX) return -EINVAL; + joydev->absmap[joydev->abspam[i]] = i; + } + return 0; + case JSIOCGAXMAP: + return copy_to_user((__u8 *) arg, joydev->abspam, + sizeof(__u8) * ABS_MAX) ? -EFAULT : 0; + case JSIOCSBTNMAP: + if (copy_from_user((__u16 *) arg, joydev->absmap, sizeof(__u16) * (KEY_MAX - BTN_MISC))) + return -EFAULT; + for (i = 0; i < KEY_MAX - BTN_MISC; i++); { + if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) return -EINVAL; + joydev->keymap[joydev->abspam[i - BTN_MISC]] = i; + } + return 0; + case JSIOCGBTNMAP: + return copy_to_user((__u16 *) arg, joydev->keypam, + sizeof(__u16) * (KEY_MAX - BTN_MISC)) ? -EFAULT : 0; default: if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) { int len; @@ -454,7 +477,7 @@ joydev->devfs = input_register_minor("js%d", minor, JOYDEV_MINOR_BASE); - printk(KERN_INFO "js%d: Joystick device for input%d\n", minor, dev->number); +// printk(KERN_INFO "js%d: Joystick device for input%d\n", minor, dev->number); return &joydev->handle; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/input/keybdev.c linux.ac/drivers/input/keybdev.c --- linux.vanilla/drivers/input/keybdev.c Tue Apr 3 17:32:02 2001 +++ linux.ac/drivers/input/keybdev.c Tue Apr 3 17:54:42 2001 @@ -37,7 +37,7 @@ #include <linux/module.h> #include <linux/kbd_kern.h> -#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || defined(__mips__) || defined(CONFIG_SPARC64) +#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || defined(__mips__) || defined(CONFIG_PPC) || defined(CONFIG_SPARC64) static int x86_sysrq_alt = 0; #ifdef CONFIG_SPARC64 @@ -62,8 +62,46 @@ 308,310,313,314,315,317,318,319,320,321,322,323,324,325,326,330, 332,340,341,342,343,344,345,346,356,359,365,368,369,370,371,372 }; +#ifdef CONFIG_MAC_EMUMOUSEBTN +extern int mac_hid_mouse_emulate_buttons(int, int, int); +#endif /* CONFIG_MAC_EMUMOUSEBTN */ +#ifdef CONFIG_MAC_ADBKEYCODES +extern int mac_hid_keyboard_sends_linux_keycodes(void); +#else +#define mac_hid_keyboard_sends_linux_keycodes() 0 +#endif /* CONFIG_MAC_ADBKEYCODES */ +#if defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_ADB_KEYBOARD) +static unsigned char mac_keycodes[256] = { + 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48, + 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,128, 1, + 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9, + 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96, + 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83, + 84, 85, 82, 65, 42, 0, 10,103,111, 0, 0, 0, 0, 0, 0, 0, + 76,125, 75,105,124,110,115, 62,116, 59, 60,119, 61,121,114,117, + 0, 0, 0, 0,127, 81, 0,113, 0, 0, 0, 0, 95, 55, 55, 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, 94, 0, 93, 0, 0, 0, 0, 0, 0,104,102 }; +#endif /* CONFIG_MAC_ADBKEYCODES || CONFIG_ADB_KEYBOARD */ + static int emulate_raw(unsigned int keycode, int down) { +#ifdef CONFIG_MAC_EMUMOUSEBTN + if (mac_hid_mouse_emulate_buttons(1, keycode, down)) + return 0; +#endif /* CONFIG_MAC_EMUMOUSEBTN */ +#if defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_ADB_KEYBOARD) + if (!mac_hid_keyboard_sends_linux_keycodes()) { + if (keycode > 255 || !mac_keycodes[keycode]) + return -1; + + handle_scancode((mac_keycodes[keycode] & 0x7f), down); + return 0; + } +#endif /* CONFIG_MAC_ADBKEYCODES || CONFIG_ADB_KEYBOARD */ + if (keycode > 255 || !x86_keycodes[keycode]) return -1; @@ -105,30 +143,7 @@ return 0; } - -#elif defined(CONFIG_ADB_KEYBOARD) - -static unsigned char mac_keycodes[128] = - { 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48, - 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,128, 1, - 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9, - 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96, - 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83, - 84, 85, 82, 65, 42, 0, 10,103,111, 0, 0, 0, 0, 0, 0, 0, - 76,125, 75,105,124, 0,115, 62,116, 59, 60,119, 61,121,114,117, - 0, 0, 0, 0,127, 81, 0,113, 0, 0, 0, 0, 0, 55, 55 }; - -static int emulate_raw(unsigned int keycode, int down) -{ - if (keycode > 127 || !mac_keycodes[keycode]) - return -1; - - handle_scancode(mac_keycodes[keycode] & 0x7f, down); - - return 0; -} - -#endif +#endif /* CONFIG_X86 || CONFIG_IA64 || __alpha__ || __mips__ || CONFIG_PPC */ static struct input_handler keybdev_handler; @@ -178,14 +193,14 @@ input_open_device(handle); - printk(KERN_INFO "keybdev.c: Adding keyboard: input%d\n", dev->number); +// printk(KERN_INFO "keybdev.c: Adding keyboard: input%d\n", dev->number); return handle; } static void keybdev_disconnect(struct input_handle *handle) { - printk(KERN_INFO "keybdev.c: Removing keyboard: input%d\n", handle->dev->number); +// printk(KERN_INFO "keybdev.c: Removing keyboard: input%d\n", handle->dev->number); input_close_device(handle); kfree(handle); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/input/mousedev.c linux.ac/drivers/input/mousedev.c --- linux.vanilla/drivers/input/mousedev.c Tue Apr 3 17:32:02 2001 +++ linux.ac/drivers/input/mousedev.c Tue Apr 3 17:54:42 2001 @@ -1,9 +1,9 @@ /* - * $Id: mousedev.c,v 1.15 2000/08/14 21:05:26 vojtech Exp $ + * $Id: mousedev.c,v 1.24 2000/11/15 10:57:45 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * - * Input driver to PS/2 or ImPS/2 device driver module. + * Input driver to ImExPS/2 device driver module. * * Sponsored by SuSE */ @@ -66,20 +66,22 @@ signed char ps2[6]; unsigned long buttons; unsigned char ready, buffer, bufsiz; - unsigned char mode, genseq, impseq; + unsigned char mode, imexseq, impsseq; }; -#define MOUSEDEV_GENIUS_LEN 5 -#define MOUSEDEV_IMPS_LEN 6 +#define MOUSEDEV_SEQ_LEN 6 -static unsigned char mousedev_genius_seq[] = { 0xe8, 3, 0xe6, 0xe6, 0xe6 }; static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 }; +static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 }; static struct input_handler mousedev_handler; static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; static struct mousedev mousedev_mix; +static int xres = CONFIG_INPUT_MOUSEDEV_SCREEN_X; +static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y; + static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { struct mousedev *mousedevs[3] = { handle->private, &mousedev_mix, NULL }; @@ -99,12 +101,12 @@ switch (code) { case ABS_X: size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X]; - list->dx += (value * CONFIG_INPUT_MOUSEDEV_SCREEN_X - list->oldx) / size; + list->dx += (value * xres - list->oldx) / size; list->oldx += list->dx * size; break; case ABS_Y: size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y]; - list->dy -= (value * CONFIG_INPUT_MOUSEDEV_SCREEN_Y - list->oldy) / size; + list->dy -= (value * yres - list->oldy) / size; list->oldy -= list->dy * size; break; } @@ -124,12 +126,12 @@ case BTN_TOUCH: case BTN_LEFT: index = 0; break; case BTN_4: - case BTN_EXTRA: if (list->mode > 1) { index = 4; break; } + case BTN_EXTRA: if (list->mode == 2) { index = 4; break; } case BTN_STYLUS: case BTN_1: case BTN_RIGHT: index = 1; break; case BTN_3: - case BTN_SIDE: if (list->mode > 1) { index = 3; break; } + case BTN_SIDE: if (list->mode == 2) { index = 3; break; } case BTN_2: case BTN_STYLUS2: case BTN_MIDDLE: index = 2; break; @@ -257,14 +259,19 @@ list->dy -= list->ps2[off + 2]; list->bufsiz = off + 3; - if (list->mode > 1) - list->ps2[off] |= ((list->buttons & 0x18) << 3); + if (list->mode == 2) { + list->ps2[off + 3] = (list->dz > 7 ? 7 : (list->dz < -7 ? -7 : list->dz)); + list->dz -= list->ps2[off + 3]; + list->ps2[off + 3] = (list->ps2[off + 3] & 0x0f) | ((list->buttons & 0x18) << 1); + list->bufsiz++; + } - if (list->mode) { + if (list->mode == 1) { list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz)); - list->bufsiz++; list->dz -= list->ps2[off + 3]; + list->bufsiz++; } + if (!list->dx && !list->dy && (!list->mode || !list->dz)) list->ready = 0; list->buffer = list->bufsiz; } @@ -278,27 +285,26 @@ for (i = 0; i < count; i++) { - if (get_user(c, &buffer[i])) + if (get_user(c, buffer + i)) return -EFAULT; - if (c == mousedev_genius_seq[list->genseq]) { - if (++list->genseq == MOUSEDEV_GENIUS_LEN) { - list->genseq = 0; - list->ready = 1; + if (c == mousedev_imex_seq[list->imexseq]) { + if (++list->imexseq == MOUSEDEV_SEQ_LEN) { + list->imexseq = 0; list->mode = 2; } - } else list->genseq = 0; + } else list->imexseq = 0; - if (c == mousedev_imps_seq[list->impseq]) { - if (++list->impseq == MOUSEDEV_IMPS_LEN) { - list->impseq = 0; - list->ready = 1; + if (c == mousedev_imps_seq[list->impsseq]) { + if (++list->impsseq == MOUSEDEV_SEQ_LEN) { + list->impsseq = 0; list->mode = 1; } - } else list->impseq = 0; + } else list->impsseq = 0; list->ps2[0] = 0xfa; list->bufsiz = 1; + list->ready = 1; switch (c) { @@ -307,16 +313,16 @@ break; case 0xf2: /* Get ID */ - list->ps2[1] = (list->mode == 1) ? 3 : 0; + switch (list->mode) { + case 0: list->ps2[1] = 0; + case 1: list->ps2[1] = 3; + case 2: list->ps2[1] = 4; + } list->bufsiz = 2; break; case 0xe9: /* Get info */ - if (list->mode == 2) { - list->ps2[1] = 0x00; list->ps2[2] = 0x33; list->ps2[3] = 0x55; - } else { - list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200; - } + list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200; list->bufsiz = 4; break; } @@ -434,7 +440,7 @@ if (mousedev_mix.open) input_open_device(&mousedev->handle); - printk(KERN_INFO "mouse%d: PS/2 mouse device for input%d\n", minor, dev->number); +// printk(KERN_INFO "mouse%d: PS/2 mouse device for input%d\n", minor, dev->number); return &mousedev->handle; } @@ -491,3 +497,7 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); MODULE_DESCRIPTION("Input driver to PS/2 or ImPS/2 device driver"); +MODULE_PARM(xres, "i"); +MODULE_PARM_DESC(xres, "Horizontal screen resolution"); +MODULE_PARM(yres, "i"); +MODULE_PARM_DESC(yres, "Vertical screen resolution"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/Config.in linux.ac/drivers/isdn/Config.in --- linux.vanilla/drivers/isdn/Config.in Tue Apr 3 17:32:02 2001 +++ linux.ac/drivers/isdn/Config.in Tue Apr 17 15:32:07 2001 @@ -76,8 +76,8 @@ bool ' Am7930' CONFIG_HISAX_AMD7930 fi fi - - dep_tristate ' Sedlbauer PCMCIA cs module' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_PCMCIA + dep_tristate 'Sedlbauer PCMCIA cards' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_PCMCIA + dep_tristate 'ELSA PCMCIA MicroLink cards' CONFIG_HISAX_ELSA_CS $CONFIG_PCMCIA fi endmenu @@ -130,8 +130,8 @@ dep_tristate ' AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI $CONFIG_ISDN_CAPI $CONFIG_PCI dep_mbool ' AVM B1 PCI V4 support' CONFIG_ISDN_DRV_AVMB1_B1PCIV4 $CONFIG_ISDN_DRV_AVMB1_B1PCI dep_tristate ' AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA $CONFIG_ISDN_CAPI - dep_tristate ' AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA $CONFIG_ISDN_CAPI $CONFIG_PCMCIA - dep_tristate ' AVM B1/M1/M2 PCMCIA cs module' CONFIG_ISDN_DRV_AVMB1_AVM_CS $CONFIG_ISDN_DRV_AVMB1_B1PCMCIA + dep_tristate ' AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA $CONFIG_ISDN_CAPI + dep_tristate ' AVM B1/M1/M2 PCMCIA cs module' CONFIG_ISDN_DRV_AVMB1_AVM_CS $CONFIG_ISDN_DRV_AVMB1_B1PCMCIA $CONFIG_PCMCIA dep_tristate ' AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI $CONFIG_ISDN_CAPI $CONFIG_PCI dep_tristate ' AVM C4 support' CONFIG_ISDN_DRV_AVMB1_C4 $CONFIG_ISDN_CAPI $CONFIG_PCI fi diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/b1pci.c linux.ac/drivers/isdn/avmb1/b1pci.c --- linux.vanilla/drivers/isdn/avmb1/b1pci.c Tue Apr 3 17:32:03 2001 +++ linux.ac/drivers/isdn/avmb1/b1pci.c Tue Apr 17 15:32:07 2001 @@ -327,7 +327,7 @@ div4->detach_ctr(ctrl); free_irq(card->irq, card); - iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + iounmap(card->mbase); release_region(card->port, AVMB1_PORTLEN); ctrl->driverdata = 0; kfree(card->ctrlinfo); @@ -358,7 +358,6 @@ static int b1pciv4_add_card(struct capi_driver *driver, struct capicardparams *p) { - unsigned long base, page_offset; avmcard *card; avmctrl_info *cinfo; int retval; @@ -409,12 +408,8 @@ return -EBUSY; } - base = card->membase & PAGE_MASK; - page_offset = card->membase - base; - card->mbase = ioremap_nocache(base, page_offset + 64); - if (card->mbase) { - card->mbase += page_offset; - } else { + card->mbase = ioremap_nocache(card->membase, 64); + if (!card->mbase) { printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n", driver->name, card->membase); kfree(card->ctrlinfo); @@ -429,7 +424,7 @@ if ((retval = b1pciv4_detect(card)) != 0) { printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n", driver->name, card->port, retval); - iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + iounmap(card->mbase); kfree(card->ctrlinfo); kfree(card->dma); kfree(card); @@ -445,7 +440,7 @@ if (retval) { printk(KERN_ERR "%s: unable to get IRQ %d.\n", driver->name, card->irq); - iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + iounmap(card->mbase); release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card->dma); @@ -457,7 +452,7 @@ cinfo->capi_ctrl = div4->attach_ctr(driver, card->name, cinfo); if (!cinfo->capi_ctrl) { printk(KERN_ERR "%s: attach controller failed.\n", driver->name); - iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + iounmap(card->mbase); free_irq(card->irq, card); release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); @@ -508,21 +503,21 @@ struct capicardparams param; int retval; + if (pci_enable_device(dev) < 0) { + printk(KERN_ERR "%s: failed to enable AVM-B1\n", + driver->name); + return -ENODEV; + } + param.irq = dev->irq; + if (pci_resource_start(dev, 2)) { /* B1 PCI V4 */ #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 driver = &b1pciv4_driver; + + pci_set_master(dev); #endif param.membase = pci_resource_start(dev, 0); param.port = pci_resource_start(dev, 2); - param.irq = dev->irq; - - retval = pci_enable_device (dev); - if (retval != 0) { - printk(KERN_ERR - "%s: failed to enable AVM-B1 V4 at i/o %#x, irq %d, mem %#x err=%d\n", - driver->name, param.port, param.irq, param.membase, retval); - return -EIO; - } printk(KERN_INFO "%s: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n", @@ -540,15 +535,7 @@ } else { param.membase = 0; param.port = pci_resource_start(dev, 1); - param.irq = dev->irq; - retval = pci_enable_device (dev); - if (retval != 0) { - printk(KERN_ERR - "%s: failed to enable AVM-B1 at i/o %#x, irq %d, err=%d\n", - driver->name, param.port, param.irq, retval); - return -EIO; - } printk(KERN_INFO "%s: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n", driver->name, param.port, param.irq); @@ -570,7 +557,6 @@ #endif struct pci_dev *dev = NULL; char *p; - int retval; MOD_INC_USE_COUNT; @@ -592,50 +578,29 @@ printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision); di = attach_capi_driver(driver); - if (!di) { printk(KERN_ERR "%s: failed to attach capi_driver\n", driver->name); MOD_DEC_USE_COUNT; - return -EIO; + return -ENODEV; } #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 printk(KERN_INFO "%s: revision %s\n", driverv4->name, driverv4->revision); div4 = attach_capi_driver(driverv4); - if (!div4) { detach_capi_driver(driver); printk(KERN_ERR "%s: failed to attach capi_driver\n", driverv4->name); MOD_DEC_USE_COUNT; - return -EIO; + return -ENODEV; } #endif -#ifdef CONFIG_PCI - if (!pci_present()) { - printk(KERN_ERR "%s: no PCI bus present\n", driver->name); - detach_capi_driver(driver); -#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 - detach_capi_driver(driverv4); -#endif - MOD_DEC_USE_COUNT; - return -EIO; - } - while ((dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, dev))) { - retval = add_card(dev); - if (retval != 0) { - detach_capi_driver(driver); -#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 - detach_capi_driver(driverv4); -#endif - MOD_DEC_USE_COUNT; - return retval; - } - ncards++; + if (add_card(dev) == 0) + ncards++; } if (ncards) { printk(KERN_INFO "%s: %d B1-PCI card(s) detected\n", @@ -649,12 +614,7 @@ detach_capi_driver(driverv4); #endif MOD_DEC_USE_COUNT; - return -ESRCH; -#else - printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name); - MOD_DEC_USE_COUNT; - return -EIO; -#endif + return -ENODEV; } static void __exit b1pci_exit(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/c4.c linux.ac/drivers/isdn/avmb1/c4.c --- linux.vanilla/drivers/isdn/avmb1/c4.c Tue Apr 3 17:32:03 2001 +++ linux.ac/drivers/isdn/avmb1/c4.c Tue Apr 17 15:32:07 2001 @@ -1012,7 +1012,7 @@ } free_irq(card->irq, card); - iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + iounmap(card->mbase); release_region(card->port, AVMB1_PORTLEN); ctrl->driverdata = 0; kfree(card->ctrlinfo); @@ -1194,7 +1194,6 @@ static int c4_add_card(struct capi_driver *driver, struct capicardparams *p) { - unsigned long base, page_offset; avmctrl_info *cinfo; avmcard *card; int retval; @@ -1249,12 +1248,8 @@ return -EBUSY; } - base = card->membase & PAGE_MASK; - page_offset = card->membase - base; - card->mbase = ioremap_nocache(base, page_offset + 128); - if (card->mbase) { - card->mbase += page_offset; - } else { + card->mbase = ioremap_nocache(card->membase, 128); + if (card->mbase == 0) { printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n", driver->name, card->membase); kfree(card->ctrlinfo); @@ -1267,7 +1262,7 @@ if ((retval = c4_detect(card)) != 0) { printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n", driver->name, card->port, retval); - iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + iounmap(card->mbase); kfree(card->ctrlinfo); kfree(card->dma); kfree(card); @@ -1282,7 +1277,7 @@ if (retval) { printk(KERN_ERR "%s: unable to get IRQ %d.\n", driver->name, card->irq); - iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + iounmap(card->mbase); release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card->dma); @@ -1302,7 +1297,7 @@ cinfo = &card->ctrlinfo[i]; di->detach_ctr(cinfo->capi_ctrl); } - iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + iounmap(card->mbase); free_irq(card->irq, card); release_region(card->port, AVMB1_PORTLEN); kfree(card->dma); @@ -1364,20 +1359,11 @@ printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision); di = attach_capi_driver(driver); - if (!di) { printk(KERN_ERR "%s: failed to attach capi_driver\n", driver->name); MOD_DEC_USE_COUNT; - return -EIO; - } - -#ifdef CONFIG_PCI - if (!pci_present()) { - printk(KERN_ERR "%s: no PCI bus present\n", driver->name); - detach_capi_driver(driver); - MOD_DEC_USE_COUNT; - return -EIO; + return -ENODEV; } while ((dev = pci_find_subsys( @@ -1385,20 +1371,17 @@ PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4, dev))) { struct capicardparams param; + if (pci_enable_device(dev) < 0) { + printk(KERN_ERR "%s: failed to enable AVM-C4\n", + driver->name); + continue; + } + pci_set_master(dev); + param.port = pci_resource_start(dev, 1); param.irq = dev->irq; param.membase = pci_resource_start(dev, 0); - - retval = pci_enable_device (dev); - if (retval != 0) { - printk(KERN_ERR - "%s: failed to enable AVM-C4 at i/o %#x, irq %d, mem %#x err=%d\n", - driver->name, param.port, param.irq, param.membase, retval); - detach_capi_driver(driver); - MOD_DEC_USE_COUNT; - return -EIO; - } - + printk(KERN_INFO "%s: PCI BIOS reports AVM-C4 at i/o %#x, irq %d, mem %#x\n", driver->name, param.port, param.irq, param.membase); @@ -1407,9 +1390,7 @@ printk(KERN_ERR "%s: no AVM-C4 at i/o %#x, irq %d detected, mem %#x\n", driver->name, param.port, param.irq, param.membase); - detach_capi_driver(driver); - MOD_DEC_USE_COUNT; - return retval; + continue; } ncards++; } @@ -1422,12 +1403,7 @@ printk(KERN_ERR "%s: NO C4 card detected\n", driver->name); detach_capi_driver(driver); MOD_DEC_USE_COUNT; - return -ESRCH; -#else - printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name); - MOD_DEC_USE_COUNT; - return -EIO; -#endif + return -ENODEV; } static void __exit c4_exit(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/capi.c linux.ac/drivers/isdn/avmb1/capi.c --- linux.vanilla/drivers/isdn/avmb1/capi.c Tue Apr 3 17:32:03 2001 +++ linux.ac/drivers/isdn/avmb1/capi.c Tue Apr 17 15:32:07 2001 @@ -1,11 +1,14 @@ /* - * $Id: capi.c,v 1.44.6.8 2001/03/21 08:52:21 kai Exp $ + * $Id: capi.c,v 1.44.6.9 2001/04/08 17:51:42 kai Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capi.c,v $ + * Revision 1.44.6.9 2001/04/08 17:51:42 kai + * merge various fixes from HEAD (found by the CHECKER project) + * * Revision 1.44.6.8 2001/03/21 08:52:21 kai * merge from main branch: fix buffer for revision string (calle) * @@ -268,7 +271,7 @@ #include "capifs.h" #endif -static char *revision = "$Revision: 1.44.6.8 $"; +static char *revision = "$Revision: 1.44.6.9 $"; MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)"); @@ -533,9 +536,6 @@ memset(np, 0, sizeof(struct capincci)); np->ncci = ncci; np->cdev = cdev; - for (pp=&cdev->nccis; *pp; pp = &(*pp)->next) - ; - *pp = np; #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE mp = 0; if (cdev->userflags & CAPIFLAG_HIGHJACKING) @@ -553,6 +553,9 @@ #endif } #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + for (pp=&cdev->nccis; *pp; pp = &(*pp)->next) + ; + *pp = np; return np; } @@ -1001,6 +1004,8 @@ return -ENODEV; skb = alloc_skb(count, GFP_USER); + if (!skb) + return -ENOMEM; if ((retval = copy_from_user(skb_put(skb, count), buf, count))) { kfree_skb(skb); @@ -1332,6 +1337,7 @@ #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capi_raw_open %d\n", GET_USE_COUNT(THIS_MODULE)); #endif + mp->datahandle = 0; mp->file = file; file->private_data = (void *)mp; @@ -1417,6 +1423,8 @@ return -EINVAL; skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_USER); + if (!skb) + return -ENOMEM; skb_reserve(skb, CAPI_DATA_B3_REQ_LEN); if ((retval = copy_from_user(skb_put(skb, count), buf, count))) { @@ -2116,6 +2124,7 @@ static int __init capi_init(void) { char *p; + char *compileinfo; MOD_INC_USE_COUNT; @@ -2196,8 +2205,17 @@ (void)proc_init(); - printk(KERN_NOTICE "capi20: Rev%s: started up with major %d\n", - rev, capi_major); +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) + compileinfo = " (middleware+capifs)"; +#else + compileinfo = " (no capifs)"; +#endif +#else + compileinfo = " (no middleware)"; +#endif + printk(KERN_NOTICE "capi20: Rev %s: started up with major %d%s\n", + rev, capi_major, compileinfo); MOD_DEC_USE_COUNT; return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/capidrv.c linux.ac/drivers/isdn/avmb1/capidrv.c --- linux.vanilla/drivers/isdn/avmb1/capidrv.c Tue Apr 3 17:32:03 2001 +++ linux.ac/drivers/isdn/avmb1/capidrv.c Tue Apr 17 15:32:07 2001 @@ -1,11 +1,14 @@ /* - * $Id: capidrv.c,v 1.39.6.4 2001/03/21 08:52:21 kai Exp $ + * $Id: capidrv.c,v 1.39.6.5 2001/04/08 17:51:42 kai Exp $ * * ISDN4Linux Driver, using capi20 interface (kernelcapi) * * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capidrv.c,v $ + * Revision 1.39.6.5 2001/04/08 17:51:42 kai + * merge various fixes from HEAD (found by the CHECKER project) + * * Revision 1.39.6.4 2001/03/21 08:52:21 kai * merge from main branch: fix buffer for revision string (calle) * @@ -231,7 +234,7 @@ #include "capicmd.h" #include "capidrv.h" -static char *revision = "$Revision: 1.39.6.4 $"; +static char *revision = "$Revision: 1.39.6.5 $"; static int debugmode = 0; MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>"); @@ -2069,8 +2072,8 @@ __u16 datahandle; if (!card) { - printk(KERN_ERR "capidrv-%d: if_sendbuf called with invalid driverId %d!\n", - card->contrnr, id); + printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n", + id); return 0; } if (debugmode > 1) @@ -2139,8 +2142,8 @@ __u8 *p; if (!card) { - printk(KERN_ERR "capidrv-%d: if_readstat called with invalid driverId %d!\n", - card->contrnr, id); + printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n", + id); return -ENODEV; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/t1pci.c linux.ac/drivers/isdn/avmb1/t1pci.c --- linux.vanilla/drivers/isdn/avmb1/t1pci.c Tue Apr 3 17:32:03 2001 +++ linux.ac/drivers/isdn/avmb1/t1pci.c Tue Apr 17 15:32:07 2001 @@ -124,7 +124,7 @@ di->detach_ctr(ctrl); free_irq(card->irq, card); - iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + iounmap(card->mbase); release_region(card->port, AVMB1_PORTLEN); ctrl->driverdata = 0; kfree(card->ctrlinfo); @@ -138,7 +138,6 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p) { - unsigned long base, page_offset; avmcard *card; avmctrl_info *cinfo; int retval; @@ -189,12 +188,8 @@ return -EBUSY; } - base = card->membase & PAGE_MASK; - page_offset = card->membase - base; - card->mbase = ioremap_nocache(base, page_offset + 64); - if (card->mbase) { - card->mbase += page_offset; - } else { + card->mbase = ioremap_nocache(card->membase, 64); + if (!card->mbase) { printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n", driver->name, card->membase); kfree(card->ctrlinfo); @@ -213,7 +208,7 @@ else printk(KERN_NOTICE "%s: card at 0x%x, but cabel not connected or T1 has no power (%d)\n", driver->name, card->port, retval); - iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + iounmap(card->mbase); kfree(card->ctrlinfo); kfree(card->dma); kfree(card); @@ -228,7 +223,7 @@ if (retval) { printk(KERN_ERR "%s: unable to get IRQ %d.\n", driver->name, card->irq); - iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + iounmap(card->mbase); release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card->dma); @@ -240,7 +235,7 @@ cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo); if (!cinfo->capi_ctrl) { printk(KERN_ERR "%s: attach controller failed.\n", driver->name); - iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + iounmap(card->mbase); free_irq(card->irq, card); release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); @@ -318,7 +313,6 @@ printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision); di = attach_capi_driver(driver); - if (!di) { printk(KERN_ERR "%s: failed to attach capi_driver\n", driver->name); @@ -326,31 +320,20 @@ return -EIO; } -#ifdef CONFIG_PCI - if (!pci_present()) { - printk(KERN_ERR "%s: no PCI bus present\n", driver->name); - detach_capi_driver(driver); - MOD_DEC_USE_COUNT; - return -EIO; - } - while ((dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_T1, dev))) { struct capicardparams param; + if (pci_enable_device(dev) < 0) { + printk(KERN_ERR "%s: failed to enable AVM-T1-PCI\n", + driver->name); + continue; + } + pci_set_master(dev); + param.port = pci_resource_start(dev, 1); param.irq = dev->irq; param.membase = pci_resource_start(dev, 0); - retval = pci_enable_device (dev); - if (retval != 0) { - printk(KERN_ERR - "%s: failed to enable AVM-T1-PCI at i/o %#x, irq %d, mem %#x err=%d\n", - driver->name, param.port, param.irq, param.membase, retval); - detach_capi_driver(&t1pci_driver); - MOD_DEC_USE_COUNT; - return -EIO; - } - printk(KERN_INFO "%s: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n", driver->name, param.port, param.irq, param.membase); @@ -359,9 +342,7 @@ printk(KERN_ERR "%s: no AVM-T1-PCI at i/o %#x, irq %d detected, mem %#x\n", driver->name, param.port, param.irq, param.membase); - detach_capi_driver(&t1pci_driver); - MOD_DEC_USE_COUNT; - return retval; + continue; } ncards++; } @@ -374,12 +355,7 @@ printk(KERN_ERR "%s: NO T1-PCI card detected\n", driver->name); detach_capi_driver(&t1pci_driver); MOD_DEC_USE_COUNT; - return -ESRCH; -#else - printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name); - MOD_DEC_USE_COUNT; - return -EIO; -#endif + return -ENODEV; } static void __exit t1pci_exit(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/eicon_idi.c linux.ac/drivers/isdn/eicon/eicon_idi.c --- linux.vanilla/drivers/isdn/eicon/eicon_idi.c Tue Apr 3 17:32:03 2001 +++ linux.ac/drivers/isdn/eicon/eicon_idi.c Tue Apr 17 15:32:07 2001 @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.c,v 1.41.6.1 2001/02/10 14:44:09 kai Exp $ +/* $Id: eicon_idi.c,v 1.41.6.2 2001/04/07 21:41:44 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * IDI interface @@ -36,7 +36,7 @@ #undef EICON_FULL_SERVICE_OKTETT -char *eicon_idi_revision = "$Revision: 1.41.6.1 $"; +char *eicon_idi_revision = "$Revision: 1.41.6.2 $"; eicon_manifbuf *manbuf; @@ -2221,7 +2221,10 @@ static char *connmsg[] = {"", "V.21", "V.23", "V.22", "V.22bis", "V.32bis", "V.34", "V.8", "Bell 212A", "Bell 103", "V.29 Leased", "V.33 Leased", "V.90", - "V.21 CH2", "V.27ter", "V.29", "V.33", "V.17"}; + "V.21 CH2", "V.27ter", "V.29", "V.33", "V.17", "V.32", "K56Flex", + "X2", "V.18", "V.18LH", "V.18HL", "V.21LH", "V.21HL", + "Bell 103LH", "Bell 103HL", "V.23", "V.23", "EDT 110", + "Baudot45", "Baudot47", "Baudot50", "DTMF" }; static u_char dtmf_code[] = { '1','4','7','*','2','5','8','0','3','6','9','#','A','B','C','D' }; @@ -2243,7 +2246,11 @@ cmd.driver = ccard->myid; cmd.command = ISDN_STAT_BCONN; cmd.arg = chan->No; - sprintf(cmd.parm.num, "%d/%s", p->speed, connmsg[p->norm]); + if (p->norm > 34) { + sprintf(cmd.parm.num, "%d/(%d)", p->speed, p->norm); + } else { + sprintf(cmd.parm.num, "%d/%s", p->speed, connmsg[p->norm]); + } ccard->interface.statcallb(&cmd); } eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DCD_ON time %d\n", chan->No, p->time); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/Makefile linux.ac/drivers/isdn/hisax/Makefile --- linux.vanilla/drivers/isdn/hisax/Makefile Tue Apr 3 17:32:04 2001 +++ linux.ac/drivers/isdn/hisax/Makefile Thu Apr 12 12:02:31 2001 @@ -54,8 +54,9 @@ # Each configuration option enables a list of files. -obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o +obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o obj-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o +obj-$(CONFIG_HISAX_ELSA_CS) += elsa_cs.o MD5FILES := isac.c isdnl1.c isdnl2.c isdnl3.c \ tei.c callc.c cert.c l3dss1.c l3_1tr6.c \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/bkm_a8.c linux.ac/drivers/isdn/hisax/bkm_a8.c --- linux.vanilla/drivers/isdn/hisax/bkm_a8.c Tue Apr 3 17:32:04 2001 +++ linux.ac/drivers/isdn/hisax/bkm_a8.c Tue Apr 17 15:32:07 2001 @@ -1,4 +1,4 @@ -/* $Id: bkm_a8.c,v 1.14.6.4 2001/02/16 16:43:25 kai Exp $ +/* $Id: bkm_a8.c,v 1.14.6.5 2001/04/15 14:51:09 keil Exp $ * bkm_a8.c low level stuff for Scitel Quadro (4*S0, passive) * derived from the original file sedlbauer.c * derived from the original file niccy.c @@ -27,7 +27,7 @@ extern const char *CardType[]; -const char sct_quadro_revision[] = "$Revision: 1.14.6.4 $"; +const char sct_quadro_revision[] = "$Revision: 1.14.6.5 $"; static const char *sct_quadro_subtypes[] = { @@ -205,9 +205,9 @@ void release_io_sct_quadro(struct IsdnCardState *cs) { - release_region(cs->hw.ax.base & 0xffffffc0, 256); + release_region(cs->hw.ax.base & 0xffffffc0, 128); if (cs->subtyp == SCT_1) - release_region(cs->hw.ax.plx_adr, 256); + release_region(cs->hw.ax.plx_adr, 64); } static void @@ -403,9 +403,9 @@ switch(cs->subtyp) { case 1: cs->hw.ax.base = pci_ioaddr5 + 0x00; - if (sct_alloc_io(pci_ioaddr1, 256)) + if (sct_alloc_io(pci_ioaddr1, 128)) return(0); - if (sct_alloc_io(pci_ioaddr5, 256)) + if (sct_alloc_io(pci_ioaddr5, 64)) return(0); /* disable all IPAC */ writereg(pci_ioaddr5, pci_ioaddr5 + 4, @@ -419,17 +419,17 @@ break; case 2: cs->hw.ax.base = pci_ioaddr4 + 0x08; - if (sct_alloc_io(pci_ioaddr4, 256)) + if (sct_alloc_io(pci_ioaddr4, 64)) return(0); break; case 3: cs->hw.ax.base = pci_ioaddr3 + 0x10; - if (sct_alloc_io(pci_ioaddr3, 256)) + if (sct_alloc_io(pci_ioaddr3, 64)) return(0); break; case 4: cs->hw.ax.base = pci_ioaddr2 + 0x20; - if (sct_alloc_io(pci_ioaddr2, 256)) + if (sct_alloc_io(pci_ioaddr2, 64)) return(0); break; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/config.c linux.ac/drivers/isdn/hisax/config.c --- linux.vanilla/drivers/isdn/hisax/config.c Tue Apr 3 17:32:04 2001 +++ linux.ac/drivers/isdn/hisax/config.c Tue Apr 17 15:32:07 2001 @@ -1,4 +1,4 @@ -/* $Id: config.c,v 2.57.6.11 2001/03/13 16:17:08 kai Exp $ +/* $Id: config.c,v 2.57.6.13 2001/04/08 19:41:28 kai Exp $ * * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden @@ -914,13 +914,12 @@ save_flags(flags); cli(); - if (!(cs = (struct IsdnCardState *) - kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC))) { + cs = kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC); + if (!cs) { printk(KERN_WARNING "HiSax: No memory for IsdnCardState(card %d)\n", cardnr + 1); - restore_flags(flags); - return (0); + goto out; } memset(cs, 0, sizeof(struct IsdnCardState)); card->cs = cs; @@ -939,241 +938,235 @@ #endif cs->protocol = card->protocol; - if ((card->typ > 0) && (card->typ <= ISDN_CTYPE_COUNT)) { - if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for dlog(card %d)\n", - cardnr + 1); - restore_flags(flags); - return (0); - } - if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for status_buf(card %d)\n", - cardnr + 1); - kfree(cs->dlog); - restore_flags(flags); - return (0); - } - cs->stlist = NULL; - cs->status_read = cs->status_buf; - cs->status_write = cs->status_buf; - cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1; - cs->typ = card->typ; - strcpy(cs->iif.id, id); - cs->iif.channels = 2; - cs->iif.maxbufsize = MAX_DATA_SIZE; - cs->iif.hl_hdrlen = MAX_HEADER_LEN; - cs->iif.features = - ISDN_FEATURE_L2_X75I | - ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L2_HDLC_56K | - ISDN_FEATURE_L2_TRANS | - ISDN_FEATURE_L3_TRANS | + if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) { + printk(KERN_WARNING + "HiSax: Card Type %d out of range\n", + card->typ); + goto outf_cs; + } + if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for dlog(card %d)\n", + cardnr + 1); + goto outf_cs; + } + if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for status_buf(card %d)\n", + cardnr + 1); + goto outf_dlog; + } + cs->stlist = NULL; + cs->status_read = cs->status_buf; + cs->status_write = cs->status_buf; + cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1; + cs->typ = card->typ; + strcpy(cs->iif.id, id); + cs->iif.channels = 2; + cs->iif.maxbufsize = MAX_DATA_SIZE; + cs->iif.hl_hdrlen = MAX_HEADER_LEN; + cs->iif.features = + ISDN_FEATURE_L2_X75I | + ISDN_FEATURE_L2_HDLC | + ISDN_FEATURE_L2_HDLC_56K | + ISDN_FEATURE_L2_TRANS | + ISDN_FEATURE_L3_TRANS | #ifdef CONFIG_HISAX_1TR6 - ISDN_FEATURE_P_1TR6 | + ISDN_FEATURE_P_1TR6 | #endif #ifdef CONFIG_HISAX_EURO - ISDN_FEATURE_P_EURO | + ISDN_FEATURE_P_EURO | #endif #ifdef CONFIG_HISAX_NI1 - ISDN_FEATURE_P_NI1 | + ISDN_FEATURE_P_NI1 | #endif - 0; - - cs->iif.command = HiSax_command; - cs->iif.writecmd = NULL; - cs->iif.writebuf_skb = HiSax_writebuf_skb; - cs->iif.readstat = HiSax_readstatus; - register_isdn(&cs->iif); - cs->myid = cs->iif.channels; - printk(KERN_INFO - "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1, - (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : - (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" : - (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" : - (card->protocol == ISDN_PTYPE_NI1) ? "NI1" : - "NONE", cs->iif.id, cs->myid); - switch (card->typ) { + 0; + + cs->iif.command = HiSax_command; + cs->iif.writecmd = NULL; + cs->iif.writebuf_skb = HiSax_writebuf_skb; + cs->iif.readstat = HiSax_readstatus; + register_isdn(&cs->iif); + cs->myid = cs->iif.channels; + printk(KERN_INFO + "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1, + (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : + (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" : + (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" : + (card->protocol == ISDN_PTYPE_NI1) ? "NI1" : + "NONE", cs->iif.id, cs->myid); + switch (card->typ) { #if CARD_TELES0 - case ISDN_CTYPE_16_0: - case ISDN_CTYPE_8_0: - ret = setup_teles0(card); - break; + case ISDN_CTYPE_16_0: + case ISDN_CTYPE_8_0: + ret = setup_teles0(card); + break; #endif #if CARD_TELES3 - case ISDN_CTYPE_16_3: - case ISDN_CTYPE_PNP: - case ISDN_CTYPE_TELESPCMCIA: - case ISDN_CTYPE_COMPAQ_ISA: - ret = setup_teles3(card); - break; + case ISDN_CTYPE_16_3: + case ISDN_CTYPE_PNP: + case ISDN_CTYPE_TELESPCMCIA: + case ISDN_CTYPE_COMPAQ_ISA: + ret = setup_teles3(card); + break; #endif #if CARD_S0BOX - case ISDN_CTYPE_S0BOX: - ret = setup_s0box(card); - break; + case ISDN_CTYPE_S0BOX: + ret = setup_s0box(card); + break; #endif #if CARD_TELESPCI - case ISDN_CTYPE_TELESPCI: - ret = setup_telespci(card); - break; + case ISDN_CTYPE_TELESPCI: + ret = setup_telespci(card); + break; #endif #if CARD_AVM_A1 - case ISDN_CTYPE_A1: - ret = setup_avm_a1(card); - break; + case ISDN_CTYPE_A1: + ret = setup_avm_a1(card); + break; #endif #if CARD_AVM_A1_PCMCIA - case ISDN_CTYPE_A1_PCMCIA: - ret = setup_avm_a1_pcmcia(card); - break; + case ISDN_CTYPE_A1_PCMCIA: + ret = setup_avm_a1_pcmcia(card); + break; #endif #if CARD_FRITZPCI - case ISDN_CTYPE_FRITZPCI: - ret = setup_avm_pcipnp(card); - break; + case ISDN_CTYPE_FRITZPCI: + ret = setup_avm_pcipnp(card); + break; #endif #if CARD_ELSA - case ISDN_CTYPE_ELSA: - case ISDN_CTYPE_ELSA_PNP: - case ISDN_CTYPE_ELSA_PCMCIA: - case ISDN_CTYPE_ELSA_PCI: - ret = setup_elsa(card); - break; + case ISDN_CTYPE_ELSA: + case ISDN_CTYPE_ELSA_PNP: + case ISDN_CTYPE_ELSA_PCMCIA: + case ISDN_CTYPE_ELSA_PCI: + ret = setup_elsa(card); + break; #endif #if CARD_IX1MICROR2 - case ISDN_CTYPE_IX1MICROR2: - ret = setup_ix1micro(card); - break; + case ISDN_CTYPE_IX1MICROR2: + ret = setup_ix1micro(card); + break; #endif #if CARD_DIEHLDIVA - case ISDN_CTYPE_DIEHLDIVA: - ret = setup_diva(card); - break; + case ISDN_CTYPE_DIEHLDIVA: + ret = setup_diva(card); + break; #endif #if CARD_ASUSCOM - case ISDN_CTYPE_ASUSCOM: - ret = setup_asuscom(card); - break; + case ISDN_CTYPE_ASUSCOM: + ret = setup_asuscom(card); + break; #endif #if CARD_TELEINT - case ISDN_CTYPE_TELEINT: - ret = setup_TeleInt(card); - break; + case ISDN_CTYPE_TELEINT: + ret = setup_TeleInt(card); + break; #endif #if CARD_SEDLBAUER - case ISDN_CTYPE_SEDLBAUER: - case ISDN_CTYPE_SEDLBAUER_PCMCIA: - case ISDN_CTYPE_SEDLBAUER_FAX: - ret = setup_sedlbauer(card); - break; + case ISDN_CTYPE_SEDLBAUER: + case ISDN_CTYPE_SEDLBAUER_PCMCIA: + case ISDN_CTYPE_SEDLBAUER_FAX: + ret = setup_sedlbauer(card); + break; #endif #if CARD_SPORTSTER - case ISDN_CTYPE_SPORTSTER: - ret = setup_sportster(card); - break; + case ISDN_CTYPE_SPORTSTER: + ret = setup_sportster(card); + break; #endif #if CARD_MIC - case ISDN_CTYPE_MIC: - ret = setup_mic(card); - break; + case ISDN_CTYPE_MIC: + ret = setup_mic(card); + break; #endif #if CARD_NETJET_S - case ISDN_CTYPE_NETJET_S: - ret = setup_netjet_s(card); - break; + case ISDN_CTYPE_NETJET_S: + ret = setup_netjet_s(card); + break; #endif #if CARD_HFCS - case ISDN_CTYPE_TELES3C: - case ISDN_CTYPE_ACERP10: - ret = setup_hfcs(card); - break; + case ISDN_CTYPE_TELES3C: + case ISDN_CTYPE_ACERP10: + ret = setup_hfcs(card); + break; #endif #if CARD_HFC_PCI - case ISDN_CTYPE_HFC_PCI: - ret = setup_hfcpci(card); - break; + case ISDN_CTYPE_HFC_PCI: + ret = setup_hfcpci(card); + break; #endif #if CARD_HFC_SX - case ISDN_CTYPE_HFC_SX: - ret = setup_hfcsx(card); - break; + case ISDN_CTYPE_HFC_SX: + ret = setup_hfcsx(card); + break; #endif #if CARD_NICCY - case ISDN_CTYPE_NICCY: - ret = setup_niccy(card); - break; + case ISDN_CTYPE_NICCY: + ret = setup_niccy(card); + break; #endif #if CARD_AMD7930 - case ISDN_CTYPE_AMD7930: - ret = setup_amd7930(card); - break; + case ISDN_CTYPE_AMD7930: + ret = setup_amd7930(card); + break; #endif #if CARD_ISURF - case ISDN_CTYPE_ISURF: - ret = setup_isurf(card); - break; + case ISDN_CTYPE_ISURF: + ret = setup_isurf(card); + break; #endif #if CARD_HSTSAPHIR - case ISDN_CTYPE_HSTSAPHIR: - ret = setup_saphir(card); - break; + case ISDN_CTYPE_HSTSAPHIR: + ret = setup_saphir(card); + break; #endif #if CARD_TESTEMU - case ISDN_CTYPE_TESTEMU: - ret = setup_testemu(card); - break; + case ISDN_CTYPE_TESTEMU: + ret = setup_testemu(card); + break; #endif #if CARD_BKM_A4T - case ISDN_CTYPE_BKM_A4T: - ret = setup_bkm_a4t(card); - break; + case ISDN_CTYPE_BKM_A4T: + ret = setup_bkm_a4t(card); + break; #endif #if CARD_SCT_QUADRO - case ISDN_CTYPE_SCT_QUADRO: - ret = setup_sct_quadro(card); - break; + case ISDN_CTYPE_SCT_QUADRO: + ret = setup_sct_quadro(card); + break; #endif #if CARD_GAZEL - case ISDN_CTYPE_GAZEL: - ret = setup_gazel(card); - break; + case ISDN_CTYPE_GAZEL: + ret = setup_gazel(card); + break; #endif #if CARD_W6692 - case ISDN_CTYPE_W6692: - ret = setup_w6692(card); - break; + case ISDN_CTYPE_W6692: + ret = setup_w6692(card); + break; #endif #if CARD_NETJET_U - case ISDN_CTYPE_NETJET_U: - ret = setup_netjet_u(card); - break; + case ISDN_CTYPE_NETJET_U: + ret = setup_netjet_u(card); + break; #endif - default: - printk(KERN_WARNING - "HiSax: Support for %s Card not selected\n", - CardType[card->typ]); - ll_unload(cs); - restore_flags(flags); - return (0); - } - } else { + default: printk(KERN_WARNING - "HiSax: Card Type %d out of range\n", - card->typ); - restore_flags(flags); - return (0); + "HiSax: Support for %s Card not selected\n", + CardType[card->typ]); + ll_unload(cs); + goto outf_cs; } if (!ret) { ll_unload(cs); - restore_flags(flags); - return (0); + goto outf_cs; } if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) { printk(KERN_WARNING "HiSax: No memory for isac rcvbuf\n"); - return (1); + ll_unload(cs); + goto outf_cs; } cs->rcvidx = 0; cs->tx_skb = NULL; @@ -1190,21 +1183,31 @@ ret = init_card(cs); if (ret) { closecard(cardnr); - restore_flags(flags); - return (0); + ret = 0; + goto outf_cs; } init_tei(cs, cs->protocol); ret = CallcNewChan(cs); if (ret) { closecard(cardnr); - restore_flags(flags); - return 0; + ret = 0; + goto outf_cs; } /* ISAR needs firmware download first */ if (!test_bit(HW_ISAR, &cs->HW_Flags)) ll_run(cs, 0); + + ret = 1; + goto out; + + outf_dlog: + kfree(cs->dlog); + outf_cs: + kfree(cs); + card->cs = NULL; + out: restore_flags(flags); - return (1); + return ret; } void __devinit @@ -1253,9 +1256,6 @@ } else { printk(KERN_WARNING "HiSax: Card %s not installed !\n", CardType[cards[i].typ]); - if (cards[i].cs) - kfree((void *) cards[i].cs); - cards[i].cs = NULL; HiSax_shiftcards(i); nrcards--; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/elsa_cs.c linux.ac/drivers/isdn/hisax/elsa_cs.c --- linux.vanilla/drivers/isdn/hisax/elsa_cs.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/elsa_cs.c Tue Apr 17 15:32:07 2001 @@ -0,0 +1,558 @@ +/*====================================================================== + + An elsa_cs PCMCIA client driver + + This driver is for the Elsa PCM ISDN Cards, i.e. the MicroLink + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + <dahinds@users.sourceforge.net>. Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Modifications from dummy_cs.c are Copyright (C) 1999-2001 Klaus + Lichtenwalder <Lichtenwalder@ACM.org>. All Rights Reserved. + +======================================================================*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/ioport.h> +#include <asm/io.h> +#include <asm/system.h> + +#include <pcmcia/version.h> +#include <pcmcia/cs_types.h> +#include <pcmcia/cs.h> +#include <pcmcia/cistpl.h> +#include <pcmcia/cisreg.h> +#include <pcmcia/ds.h> +#include <pcmcia/bus_ops.h> + +/* + All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If + you do not define PCMCIA_DEBUG at all, all the debug code will be + left out. If you compile with PCMCIA_DEBUG=0, the debug code will + be present but disabled -- but it can then be enabled for specific + modules at load time with a 'pc_debug=#' option to insmod. +*/ + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); +static char *version = +"elsa_cs.c $Revision: 1.1.2.1 $ $Date: 2001/04/15 08:01:34 $ (K.Lichtenwalder)"; +#else +#define DEBUG(n, args...) +#endif + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* Bit map of interrupts to choose from, the old way */ +/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, 3 */ +static u_long irq_mask = 0xdeb8; + +/* Newer, simpler way of listing specific interrupts */ +static int irq_list[4] = { -1 }; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +static int protocol = 2; /* EURO-ISDN Default */ +MODULE_PARM(protocol, "i"); + +extern int elsa_init_pcmcia(int, int, int*, int); + +/*====================================================================*/ + +/* + The event() function is this driver's Card Services event handler. + It will be called by Card Services when an appropriate card status + event is received. The config() and release() entry points are + used to configure or release a socket, in response to card insertion + and ejection events. They are invoked from the elsa_cs event + handler. +*/ + +static void elsa_cs_config(dev_link_t *link); +static void elsa_cs_release(u_long arg); +static int elsa_cs_event(event_t event, int priority, + event_callback_args_t *args); + +/* + The attach() and detach() entry points are used to create and destroy + "instances" of the driver, where each instance represents everything + needed to manage one actual PCMCIA card. +*/ + +static dev_link_t *elsa_cs_attach(void); +static void elsa_cs_detach(dev_link_t *); + +/* + The dev_info variable is the "key" that is used to match up this + device driver with appropriate cards, through the card configuration + database. +*/ + +static dev_info_t dev_info = "elsa_cs"; + +/* + A linked list of "instances" of the elsa_cs device. Each actual + PCMCIA card corresponds to one device instance, and is described + by one dev_link_t structure (defined in ds.h). + + You may not want to use a linked list for this -- for example, the + memory card driver uses an array of dev_link_t pointers, where minor + device numbers are used to derive the corresponding array index. +*/ + +static dev_link_t *dev_list = NULL; + +/* + A dev_link_t structure has fields for most things that are needed + to keep track of a socket, but there will usually be some device + specific information that also needs to be kept track of. The + 'priv' pointer in a dev_link_t structure can be used to point to + a device-specific private data structure, like this. + + To simplify the data structure handling, we actually include the + dev_link_t structure in the device's private data structure. + + A driver needs to provide a dev_node_t structure for each device + on a card. In some cases, there is only one device per card (for + example, ethernet cards, modems). In other cases, there may be + many actual or logical devices (SCSI adapters, memory cards with + multiple partitions). The dev_node_t structures need to be kept + in a linked list starting at the 'dev' field of a dev_link_t + structure. We allocate them in the card's private data structure, + because they generally shouldn't be allocated dynamically. + In this case, we also provide a flag to indicate if a device is + "stopped" due to a power management event, or card ejection. The + device IO routines can use a flag like this to throttle IO to a + card that is not ready to accept it. + + The bus_operations pointer is used on platforms for which we need + to use special socket-specific versions of normal IO primitives + (inb, outb, readb, writeb, etc) for card IO. +*/ + +typedef struct local_info_t { + dev_link_t link; + dev_node_t node; + int busy; + struct bus_operations *bus; +} local_info_t; + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret}; + CardServices(ReportError, handle, &err); +} + +/*====================================================================== + + elsa_cs_attach() creates an "instance" of the driver, allocatingx + local data structures for one device. The device is registered + with Card Services. + + The dev_link structure is initialized, but we don't actually + configure the card at this point -- we wait until we receive a + card insertion event. + +======================================================================*/ + +static dev_link_t *elsa_cs_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + local_info_t *local; + int ret, i; + void elsa_interrupt(int, void *, struct pt_regs *); + + DEBUG(0, "elsa_cs_attach()\n"); + + /* Allocate space for private device-specific data */ + local = kmalloc(sizeof(local_info_t), GFP_KERNEL); + if (!local) return NULL; + memset(local, 0, sizeof(local_info_t)); + link = &local->link; link->priv = local; + + /* Initialize the dev_link_t structure */ + link->release.function = &elsa_cs_release; + link->release.data = (u_long)link; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID|IRQ_SHARE_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = NULL; + + /* + General socket configuration defaults can go here. In this + client, we assume very little, and rely on the CIS for almost + everything. In most clients, many details (i.e., number, sizes, + and attributes of IO windows) are fixed by the nature of the + device, and can be hard-wired here. + */ + link->io.NumPorts1 = 8; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.IOAddrLines = 3; + + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &elsa_cs_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + elsa_cs_detach(link); + return NULL; + } + + return link; +} /* elsa_cs_attach */ + +/*====================================================================== + + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + +======================================================================*/ + +static void elsa_cs_detach(dev_link_t *link) +{ + dev_link_t **linkp; + local_info_t *info = link->priv; + int ret; + + DEBUG(0, "elsa_cs_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + del_timer(&link->release); + if (link->state & DEV_CONFIG) + elsa_cs_release((u_long)link); + + /* + If the device is currently configured and active, we won't + actually delete it yet. Instead, it is marked so that when + the release() function is called, that will trigger a proper + detach(). + */ + if (link->state & DEV_CONFIG) { + DEBUG(0, "elsa_cs: detach postponed, '%s' " + "still locked\n", link->dev->dev_name); + link->state |= DEV_STALE_LINK; + return; + } + + /* Break the link with Card Services */ + if (link->handle) { + ret = CardServices(DeregisterClient, link->handle); + if (ret != CS_SUCCESS) + cs_error(link->handle, DeregisterClient, ret); + } + + /* Unlink device structure and free it */ + *linkp = link->next; + kfree(info); + +} /* elsa_cs_detach */ + +/*====================================================================== + + elsa_cs_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + device available to the system. + +======================================================================*/ +static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, + cisparse_t *parse) +{ + int i; + i = CardServices(fn, handle, tuple); + if (i != CS_SUCCESS) return i; + i = CardServices(GetTupleData, handle, tuple); + if (i != CS_SUCCESS) return i; + return CardServices(ParseTuple, handle, tuple, parse); +} + +#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) +#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) + +static void elsa_cs_config(dev_link_t *link) +{ + client_handle_t handle; + tuple_t tuple; + cisparse_t parse; + local_info_t *dev; + int i, j, last_fn; + u_short buf[128]; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; + + DEBUG(0, "elsa_config(0x%p)\n", link); + handle = link->handle; + dev = link->priv; + + /* + This reads the card's CONFIG tuple to find its configuration + registers. + */ + tuple.DesiredTuple = CISTPL_CONFIG; + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleDataMax = 255; + tuple.TupleOffset = 0; + tuple.Attributes = 0; + i = first_tuple(handle, &tuple, &parse); + if (i != CS_SUCCESS) { + last_fn = ParseTuple; + goto cs_failed; + } + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; tuple.TupleDataMax = 255; + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + i = first_tuple(handle, &tuple, &parse); + while (i == CS_SUCCESS) { + if ( (cf->io.nwin > 0) && cf->io.win[0].base) { + printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n"); + link->conf.ConfigIndex = cf->index; + link->io.BasePort1 = cf->io.win[0].base; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) break; + } else { + printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n"); + link->conf.ConfigIndex = cf->index; + for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) { + link->io.BasePort1 = j; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) break; + } + break; + } + i = next_tuple(handle, &tuple, &parse); + } + + if (i != CS_SUCCESS) { + last_fn = RequestIO; + goto cs_failed; + } + + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) { + link->irq.AssignedIRQ = 0; + last_fn = RequestIRQ; + goto cs_failed; + } + + i = CardServices(RequestConfiguration, link->handle, &link->conf); + if (i != CS_SUCCESS) { + last_fn = RequestConfiguration; + goto cs_failed; + } + + /* At this point, the dev_node_t structure(s) should be + initialized and arranged in a linked list at link->dev. *//* */ + sprintf(dev->node.dev_name, "elsa"); + dev->node.major = dev->node.minor = 0x0; + + link->dev = &dev->node; + + /* Finally, report what we've done */ + printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", + dev->node.dev_name, link->conf.ConfigIndex, + link->conf.Vcc/10, link->conf.Vcc%10); + if (link->conf.Vpp1) + printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); + if (link->conf.Attributes & CONF_ENABLE_IRQ) + printk(", irq %d", link->irq.AssignedIRQ); + if (link->io.NumPorts1) + printk(", io 0x%04x-0x%04x", link->io.BasePort1, + link->io.BasePort1+link->io.NumPorts1-1); + if (link->io.NumPorts2) + printk(" & 0x%04x-0x%04x", link->io.BasePort2, + link->io.BasePort2+link->io.NumPorts2-1); + printk("\n"); + + link->state &= ~DEV_CONFIG_PENDING; + + elsa_init_pcmcia(link->io.BasePort1, link->irq.AssignedIRQ, + &(((local_info_t*)link->priv)->busy), + protocol); + return; +cs_failed: + cs_error(link->handle, last_fn, i); + elsa_cs_release((u_long)link); +} /* elsa_cs_config */ + +/*====================================================================== + + After a card is removed, elsa_cs_release() will unregister the net + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + +======================================================================*/ + +static void elsa_cs_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + + DEBUG(0, "elsa_cs_release(0x%p)\n", link); + + /* + If the device is currently in use, we won't release until it + is actually closed, because until then, we can't be sure that + no one will try to access the device or its data structures. + */ + if (link->open) { + DEBUG(1, "elsa_cs: release postponed, '%s' " + "still open\n", link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + /* Unlink the device chain */ + link->dev = NULL; + + /* Don't bother checking to see if these succeed or not */ + if (link->win) + CardServices(ReleaseWindow, link->win); + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + link->state &= ~DEV_CONFIG; + + if (link->state & DEV_STALE_LINK) + elsa_cs_detach(link); + +} /* elsa_cs_release */ + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the net drivers from trying + to talk to the card any more. + + When a CARD_REMOVAL event is received, we immediately set a flag + to block future accesses to this device. All the functions that + actually access the device should check this flag to make sure + the card is still present. + +======================================================================*/ + +static int elsa_cs_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + local_info_t *dev = link->priv; + + DEBUG(1, "elsa_cs_event(%d)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + ((local_info_t*)link->priv)->busy = 1; + mod_timer(&link->release, jiffies + HZ/20); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + dev->bus = args->bus; + elsa_cs_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + /* Mark the device as stopped, to block IO until later */ + dev->busy = 1; + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) + CardServices(RequestConfiguration, link->handle, &link->conf); + dev->busy = 0; + break; + } + return 0; +} /* elsa_cs_event */ + +/*====================================================================*/ + +static int __init init_elsa_cs(void) +{ + servinfo_t serv; + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "elsa_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &elsa_cs_attach, &elsa_cs_detach); + return 0; +} + +static void __exit exit_elsa_cs(void) +{ + DEBUG(0, "elsa_cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + elsa_cs_detach(dev_list); +} + +module_init(init_elsa_cs); +module_exit(exit_elsa_cs); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/hfc_pci.c linux.ac/drivers/isdn/hisax/hfc_pci.c --- linux.vanilla/drivers/isdn/hisax/hfc_pci.c Tue Apr 3 17:32:04 2001 +++ linux.ac/drivers/isdn/hisax/hfc_pci.c Tue Apr 17 15:32:07 2001 @@ -1,4 +1,4 @@ -/* $Id: hfc_pci.c,v 1.34.6.4 2001/02/13 10:33:58 kai Exp $ +/* $Id: hfc_pci.c,v 1.34.6.5 2001/04/08 19:32:26 kai Exp $ * hfc_pci.c low level driver for CCD´s hfc-pci based cards * @@ -35,7 +35,7 @@ extern const char *CardType[]; -static const char *hfcpci_revision = "$Revision: 1.34.6.4 $"; +static const char *hfcpci_revision = "$Revision: 1.34.6.5 $"; /* table entry in the PCI devices list */ typedef struct { @@ -235,6 +235,59 @@ return (NULL); } +/***************************************/ +/* clear the desired B-channel rx fifo */ +/***************************************/ +static void hfcpci_clear_fifo_rx(struct IsdnCardState *cs, int fifo) +{ u_char fifo_state; + bzfifo_type *bzr; + + if (fifo) { + bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2; + fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B2RX; + } else { + bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1; + fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B1RX; + } + if (fifo_state) + cs->hw.hfcpci.fifo_en ^= fifo_state; + Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); + cs->hw.hfcpci.last_bfifo_cnt[fifo] = 0; + bzr->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1; + bzr->za[MAX_B_FRAMES].z2 = bzr->za[MAX_B_FRAMES].z1; + bzr->f1 = MAX_B_FRAMES; + bzr->f2 = bzr->f1; /* init F pointers to remain constant */ + if (fifo_state) + cs->hw.hfcpci.fifo_en |= fifo_state; + Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); +} + +/***************************************/ +/* clear the desired B-channel tx fifo */ +/***************************************/ +static void hfcpci_clear_fifo_tx(struct IsdnCardState *cs, int fifo) +{ u_char fifo_state; + bzfifo_type *bzt; + + if (fifo) { + bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2; + fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B2TX; + } else { + bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1; + fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B1TX; + } + if (fifo_state) + cs->hw.hfcpci.fifo_en ^= fifo_state; + Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); + bzt->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1; + bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1; + bzt->f1 = MAX_B_FRAMES; + bzt->f2 = bzt->f1; /* init F pointers to remain constant */ + if (fifo_state) + cs->hw.hfcpci.fifo_en |= fifo_state; + Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); +} + /*********************************************/ /* read a complete B-frame out of the buffer */ /*********************************************/ @@ -428,7 +481,7 @@ { long flags; struct IsdnCardState *cs = bcs->cs; - int rcnt; + int rcnt, real_fifo; int receive, count = 5; struct sk_buff *skb; bzfifo_type *bz; @@ -440,9 +493,11 @@ if ((bcs->channel) && (!cs->hw.hfcpci.bswapped)) { bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2; bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b2; + real_fifo = 1; } else { bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1; bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b1; + real_fifo = 0; } Begin: count--; @@ -475,6 +530,11 @@ rcnt = bz->f1 - bz->f2; if (rcnt < 0) rcnt += MAX_B_FRAMES + 1; + if (cs->hw.hfcpci.last_bfifo_cnt[real_fifo] > rcnt + 1) { + rcnt = 0; + hfcpci_clear_fifo_rx(cs, real_fifo); + } + cs->hw.hfcpci.last_bfifo_cnt[real_fifo] = rcnt; if (rcnt > 1) receive = 1; else @@ -1253,7 +1313,6 @@ mode_hfcpci(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; - bzfifo_type *bzr, *bzt; int flags, fifo2; if (cs->debug & L1_DEB_HSCX) @@ -1300,6 +1359,8 @@ } break; case (L1_MODE_TRANS): + hfcpci_clear_fifo_rx(cs, fifo2); + hfcpci_clear_fifo_tx(cs, fifo2); if (bc) { cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA; cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA; @@ -1312,26 +1373,16 @@ cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC); cs->hw.hfcpci.ctmt |= 2; cs->hw.hfcpci.conn &= ~0x18; - bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2; - bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2; } else { cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1; cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC); cs->hw.hfcpci.ctmt |= 1; cs->hw.hfcpci.conn &= ~0x03; - bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1; - bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1; } - bzr->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1; - bzr->za[MAX_B_FRAMES].z2 = bzr->za[MAX_B_FRAMES].z1; - bzr->f1 = MAX_B_FRAMES; - bzr->f2 = bzr->f1; /* init F pointers to remain constant */ - bzt->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1; - bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1; - bzt->f1 = MAX_B_FRAMES; - bzt->f2 = bzt->f1; /* init F pointers to remain constant */ break; case (L1_MODE_HDLC): + hfcpci_clear_fifo_rx(cs, fifo2); + hfcpci_clear_fifo_tx(cs, fifo2); if (bc) { cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA; cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA; @@ -1340,11 +1391,13 @@ cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA; } if (fifo2) { + cs->hw.hfcpci.last_bfifo_cnt[1] = 0; cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2; cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC); cs->hw.hfcpci.ctmt &= ~2; cs->hw.hfcpci.conn &= ~0x18; } else { + cs->hw.hfcpci.last_bfifo_cnt[0] = 0; cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1; cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC); cs->hw.hfcpci.ctmt &= ~1; @@ -1633,7 +1686,8 @@ #endif /* CONFIG_PCI */ -int __init setup_hfcpci(struct IsdnCard *card) +int __init +setup_hfcpci(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; @@ -1645,7 +1699,7 @@ #endif strcpy(tmp, hfcpci_revision); printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp)); -#ifdef CONFIG_PCI +#if CONFIG_PCI cs->hw.hfcpci.int_s1 = 0; cs->dc.hfcpci.ph_state = 0; cs->hw.hfcpci.fifo = 255; @@ -1659,6 +1713,7 @@ if (tmp_hfcpci) { if (pci_enable_device(tmp_hfcpci)) continue; + pci_set_master(tmp_hfcpci); if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[ 0].start & PCI_BASE_ADDRESS_IO_MASK))) continue; else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/hfc_pci.h linux.ac/drivers/isdn/hisax/hfc_pci.h --- linux.vanilla/drivers/isdn/hisax/hfc_pci.h Sun Aug 6 20:43:41 2000 +++ linux.ac/drivers/isdn/hisax/hfc_pci.h Tue Apr 17 15:32:07 2001 @@ -1,4 +1,4 @@ -/* $Id: hfc_pci.h,v 1.8 2000/06/26 08:59:13 keil Exp $ +/* $Id: hfc_pci.h,v 1.8.6.1 2001/04/08 19:32:26 kai Exp $ * * specific defines for CCD's HFC 2BDS0 PCI chips * @@ -178,6 +178,9 @@ #define HFCPCI_FIFOEN_B1 0x03 #define HFCPCI_FIFOEN_B2 0x0C #define HFCPCI_FIFOEN_DTX 0x10 +#define HFCPCI_FIFOEN_B1TX 0x01 +#define HFCPCI_FIFOEN_B1RX 0x02 +#define HFCPCI_FIFOEN_B2TX 0x04 #define HFCPCI_FIFOEN_B2RX 0x08 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/hisax.h linux.ac/drivers/isdn/hisax/hisax.h --- linux.vanilla/drivers/isdn/hisax/hisax.h Tue Apr 3 17:32:04 2001 +++ linux.ac/drivers/isdn/hisax/hisax.h Tue Apr 17 18:07:14 2001 @@ -1,4 +1,4 @@ -/* $Id: hisax.h,v 2.52.6.3 2001/02/16 16:43:27 kai Exp $ +/* $Id: hisax.h,v 2.52.6.4 2001/04/08 19:32:26 kai Exp $ * * Basic declarations, defines and prototypes * @@ -687,6 +687,7 @@ unsigned char *pci_io; /* start of PCI IO memory */ void *share_start; /* shared memory for Fifos start */ void *fifos; /* FIFO memory */ + int last_bfifo_cnt[2]; /* marker saving last b-fifo frame count */ struct timer_list timer; }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/isar.c linux.ac/drivers/isdn/hisax/isar.c --- linux.vanilla/drivers/isdn/hisax/isar.c Tue Apr 3 17:32:05 2001 +++ linux.ac/drivers/isdn/hisax/isar.c Tue Apr 17 15:32:07 2001 @@ -1,4 +1,4 @@ -/* $Id: isar.c,v 1.17.6.1 2001/02/16 16:43:27 kai Exp $ +/* $Id: isar.c,v 1.17.6.2 2001/04/08 17:51:42 kai Exp $ * * isar.c ISAR (Siemens PSB 7110) specific routines * @@ -383,12 +383,12 @@ } else { printk(KERN_DEBUG"isar selftest not OK %x/%x/%x\n", ireg->cmsb, ireg->clsb, ireg->par[0]); - ret = 1;goto reterror; + ret = 1;goto reterrflg; } ireg->iis = 0; if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) { printk(KERN_ERR"isar RQST SVN failed\n"); - ret = 1;goto reterror; + ret = 1;goto reterrflg; } cnt = 30000; /* max 300 ms */ while ((ireg->iis != ISAR_IIS_DIAG) && cnt) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hysdn/boardergo.c linux.ac/drivers/isdn/hysdn/boardergo.c --- linux.vanilla/drivers/isdn/hysdn/boardergo.c Tue Apr 3 17:32:05 2001 +++ linux.ac/drivers/isdn/hysdn/boardergo.c Tue Apr 17 15:32:07 2001 @@ -386,7 +386,9 @@ dpr->ToPcInt = 1; /* interrupt to E1 for all cards */ restore_flags(flags); - if ((i = hysdn_net_create(card))) { + if ((hynet_enable & (1 << card->myid)) + && (i = hysdn_net_create(card))) + { ergo_stopcard(card); card->state = CARD_STATE_BOOTERR; return (i); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hysdn/hycapi.c linux.ac/drivers/isdn/hysdn/hycapi.c --- linux.vanilla/drivers/isdn/hysdn/hycapi.c Tue Apr 3 17:32:05 2001 +++ linux.ac/drivers/isdn/hysdn/hycapi.c Tue Apr 17 15:32:07 2001 @@ -41,7 +41,10 @@ #include "hysdn_defs.h" #include <linux/kernelcapi.h> -static char hycapi_revision[]="$Revision: 1.8.6.1 $"; +static char hycapi_revision[]="$Revision: 1.11 $"; + +unsigned int hycapi_enable = 0xffffffff; +MODULE_PARM(hycapi_enable, "i"); typedef struct _hycapi_appl { unsigned int ctrl_mask; @@ -542,15 +545,11 @@ printk(KERN_NOTICE "hycapi_rx_capipkt\n"); #endif if(!cinfo) { - printk(KERN_ERR "HYSDN Card%d: no HYCAPI-controller!\n", - card->myid); return; } ctrl = cinfo->capi_ctrl; if(!ctrl) { - printk(KERN_ERR "HYSDN Card%d: no CAPI-controller (1)!\n", - card->myid); return; } if(len < CAPI_MSG_BASELEN) { @@ -644,8 +643,6 @@ printk(KERN_NOTICE "hycapi_tx_capiack\n"); #endif if(!cinfo) { - printk(KERN_ERR "HYSDN Card%d: no CAPI-controller (2)!\n", - card->myid); return; } spin_lock_irq(&cinfo->lock); @@ -671,8 +668,6 @@ { hycapictrl_info *cinfo = card->hyctrlinfo; if(!cinfo) { - printk(KERN_ERR "HYSDN Card%d: no CAPI-controller! (3)\n", - card->myid); return (struct sk_buff *)NULL; } if (!cinfo->sk_count) @@ -792,6 +787,9 @@ #ifdef HYCAPI_PRINTFNAMES printk(KERN_NOTICE "hycapi_capi_create\n"); #endif + if((hycapi_enable & (1 << card->myid)) == 0) { + return 1; + } if (!card->hyctrlinfo) { cinfo = (hycapictrl_info *) kmalloc(sizeof(hycapictrl_info), GFP_ATOMIC); if (!cinfo) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hysdn/hysdn_defs.h linux.ac/drivers/isdn/hysdn/hysdn_defs.h --- linux.vanilla/drivers/isdn/hysdn/hysdn_defs.h Wed Nov 29 05:44:41 2000 +++ linux.ac/drivers/isdn/hysdn/hysdn_defs.h Tue Apr 17 18:09:42 2001 @@ -273,6 +273,7 @@ extern int hysdn_tx_cfgline(hysdn_card *, uchar *, word); /* send one cfg line */ /* hysdn_net.c */ +extern unsigned int hynet_enable; extern char *hysdn_net_revision; extern int hysdn_net_create(hysdn_card *); /* create a new net device */ extern int hysdn_net_release(hysdn_card *); /* delete the device */ @@ -282,6 +283,7 @@ extern void hysdn_rx_netpkt(hysdn_card *, uchar *, word); /* rxed packet from network */ #ifdef CONFIG_HYSDN_CAPI +extern unsigned int hycapi_enable; extern struct capi_driver_interface *hy_di; extern int hycapi_capi_create(hysdn_card *); /* create a new capi device */ extern int hycapi_capi_release(hysdn_card *); /* delete the device */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hysdn/hysdn_net.c linux.ac/drivers/isdn/hysdn/hysdn_net.c --- linux.vanilla/drivers/isdn/hysdn/hysdn_net.c Tue Apr 3 17:32:05 2001 +++ linux.ac/drivers/isdn/hysdn/hysdn_net.c Tue Apr 17 15:32:07 2001 @@ -37,8 +37,11 @@ #include "hysdn_defs.h" +unsigned int hynet_enable = 0xffffffff; +MODULE_PARM(hynet_enable, "i"); + /* store the actual version for log reporting */ -char *hysdn_net_revision = "$Revision: 1.8.6.1 $"; +char *hysdn_net_revision = "$Revision: 1.10 $"; #define MAX_SKB_BUFFERS 20 /* number of buffers for keeping TX-data */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hysdn/hysdn_procconf.c linux.ac/drivers/isdn/hysdn/hysdn_procconf.c --- linux.vanilla/drivers/isdn/hysdn/hysdn_procconf.c Tue Apr 3 17:32:05 2001 +++ linux.ac/drivers/isdn/hysdn/hysdn_procconf.c Tue Apr 17 15:32:07 2001 @@ -41,7 +41,7 @@ #define CONF_STATE_DETECT 0 /* waiting for detect */ #define CONF_STATE_CONF 1 /* writing config data */ #define CONF_STATE_POF 2 /* writing pof data */ -#define CONF_LINE_LEN 80 /* 80 chars max */ +#define CONF_LINE_LEN 255 /* 255 chars max */ struct conf_writedata { hysdn_card *card; /* card the device is connected to */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hysdn/hysdn_sched.c linux.ac/drivers/isdn/hysdn/hysdn_sched.c --- linux.vanilla/drivers/isdn/hysdn/hysdn_sched.c Tue Apr 3 17:32:05 2001 +++ linux.ac/drivers/isdn/hysdn/hysdn_sched.c Tue Apr 17 15:32:08 2001 @@ -47,7 +47,10 @@ switch (chan) { case CHAN_NDIS_DATA: - hysdn_rx_netpkt(card, buf, len); /* give packet to network handler */ + if (hynet_enable & (1 << card->myid)) { + /* give packet to network handler */ + hysdn_rx_netpkt(card, buf, len); + } break; case CHAN_ERRLOG: @@ -58,7 +61,9 @@ #ifdef CONFIG_HYSDN_CAPI case CHAN_CAPI: /* give packet to CAPI handler */ - hycapi_rx_capipkt(card, buf, len); + if (hycapi_enable & (1 << card->myid)) { + hycapi_rx_capipkt(card, buf, len); + } break; #endif /* CONFIG_HYSDN_CAPI */ default: @@ -115,7 +120,9 @@ return (1); /* tell that data should be send */ } /* error log start and able to send */ /* now handle network interface packets */ - if ((skb = hysdn_tx_netget(card)) != NULL) { + if ((hynet_enable & (1 << card->myid)) && + (skb = hysdn_tx_netget(card)) != NULL) + { if (skb->len <= maxlen) { memcpy(buf, skb->data, skb->len); /* copy the packet to the buffer */ *len = skb->len; @@ -126,7 +133,9 @@ hysdn_tx_netack(card); /* aknowledge packet -> throw away */ } /* send a network packet if available */ #ifdef CONFIG_HYSDN_CAPI - if((skb = hycapi_tx_capiget(card)) != NULL) { + if( ((hycapi_enable & (1 << card->myid))) && + ((skb = hycapi_tx_capiget(card)) != NULL) ) + { if (skb->len <= maxlen) { memcpy(buf, skb->data, skb->len); *len = skb->len; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/isdn_common.c linux.ac/drivers/isdn/isdn_common.c --- linux.vanilla/drivers/isdn/isdn_common.c Tue Apr 3 17:32:06 2001 +++ linux.ac/drivers/isdn/isdn_common.c Tue Apr 17 15:32:08 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.114.6.8 2001/02/16 16:43:22 kai Exp $ +/* $Id: isdn_common.c,v 1.114.6.10 2001/04/08 19:14:00 kai Exp $ * Linux ISDN subsystem, common used functions (linklevel). * @@ -51,7 +51,7 @@ isdn_dev *dev; -static char *isdn_revision = "$Revision: 1.114.6.8 $"; +static char *isdn_revision = "$Revision: 1.114.6.10 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -260,7 +260,6 @@ static int isdn_timer_cnt1 = 0; static int isdn_timer_cnt2 = 0; static int isdn_timer_cnt3 = 0; -static int isdn_timer_cnt4 = 0; static void isdn_timer_funct(ulong dummy) @@ -284,16 +283,11 @@ isdn_timer_cnt2 = 0; if (tf & ISDN_TIMER_NETHANGUP) isdn_net_autohup(); - if (++isdn_timer_cnt3 > ISDN_TIMER_RINGING) { + if (++isdn_timer_cnt3 >= ISDN_TIMER_RINGING) { isdn_timer_cnt3 = 0; if (tf & ISDN_TIMER_MODEMRING) isdn_tty_modem_ring(); } - if (++isdn_timer_cnt4 > ISDN_TIMER_KEEPINT) { - isdn_timer_cnt4 = 0; - if (tf & ISDN_TIMER_KEEPALIVE) - isdn_net_slarp_out(); - } if (tf & ISDN_TIMER_CARRIER) isdn_tty_carrier_timeout(); } @@ -312,7 +306,7 @@ void isdn_timer_ctrl(int tf, int onoff) { - int flags; + int flags, old_tflags; save_flags(flags); cli(); @@ -321,11 +315,12 @@ isdn_timer_cnt1 = 0; isdn_timer_cnt2 = 0; } + old_tflags = dev->tflags; if (onoff) dev->tflags |= tf; else dev->tflags &= ~tf; - if (dev->tflags) + if (dev->tflags && !old_tflags) mod_timer(&dev->timer, jiffies+ISDN_TIMER_RES); restore_flags(flags); } @@ -1026,7 +1021,7 @@ retval = -ENODEV; goto out; } - if (minor < ISDN_MINOR_CTRL) { + if (minor <= ISDN_MINOR_BMAX) { printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor); drvidx = isdn_minor2drv(minor); if (drvidx < 0) { @@ -1119,7 +1114,7 @@ return -ENODEV; lock_kernel(); - if (minor < ISDN_MINOR_CTRL) { + if (minor <= ISDN_MINOR_BMAX) { printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor); drvidx = isdn_minor2drv(minor); if (drvidx < 0) { @@ -1272,7 +1267,7 @@ } if (!dev->drivers) return -ENODEV; - if (minor < ISDN_MINOR_CTRL) { + if (minor <= ISDN_MINOR_BMAX) { drvidx = isdn_minor2drv(minor); if (drvidx < 0) return -ENODEV; @@ -1687,7 +1682,7 @@ } if (!dev->channels) goto out; - if (minor < ISDN_MINOR_CTRL) { + if (minor <= ISDN_MINOR_BMAX) { printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor); drvidx = isdn_minor2drv(minor); if (drvidx < 0) @@ -1747,7 +1742,7 @@ goto out; } isdn_unlock_drivers(); - if (minor < ISDN_MINOR_CTRL) + if (minor <= ISDN_MINOR_BMAX) goto out; if (minor <= ISDN_MINOR_CTRLMAX) { if (dev->profd == current) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/isdn_net.c linux.ac/drivers/isdn/isdn_net.c --- linux.vanilla/drivers/isdn/isdn_net.c Thu Feb 8 18:40:25 2001 +++ linux.ac/drivers/isdn/isdn_net.c Tue Apr 17 15:32:08 2001 @@ -22,6 +22,11 @@ * */ +/* Jan 2001: fix CISCO HDLC Bjoern A. Zeeb <i4l@zabbadoz.net> + * for info on the protocol, see + * http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt + */ + #include <linux/config.h> #define __NO_VERSION__ #include <linux/module.h> @@ -182,7 +187,10 @@ int isdn_net_force_dial_lp(isdn_net_local *); static int isdn_net_start_xmit(struct sk_buff *, struct net_device *); -char *isdn_net_revision = "$Revision: 1.140.6.3 $"; +static void isdn_net_ciscohdlck_connected(isdn_net_local *lp); +static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp); + +char *isdn_net_revision = "$Revision: 1.144 $"; /* * Code for raw-networking over ISDN @@ -454,6 +462,8 @@ pops -> disconn_ind(cprot); #endif /* CONFIG_ISDN_X25 */ if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) { + if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) + isdn_net_ciscohdlck_disconnected(lp); #ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) isdn_ppp_free(lp); @@ -498,7 +508,7 @@ lp->dialstate = 0; isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1); if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) - isdn_timer_ctrl(ISDN_TIMER_KEEPALIVE, 1); + isdn_net_ciscohdlck_connected(lp); if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) { if (lp->master) { /* is lp a slave? */ isdn_net_dev *nd = ((isdn_net_local *)lp->master->priv)->netdev; @@ -660,7 +670,7 @@ isdn_net_hangup(&p->dev); break; } - if (!strcmp(lp->dial->num, "LEASED")) { + if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) { restore_flags(flags); lp->dialstate = 4; printk(KERN_INFO "%s: Open leased line ...\n", lp->name); @@ -1415,92 +1425,347 @@ return htons(ETH_P_802_2); } -static void -isdn_net_slarp_send(isdn_net_local *lp, int is_reply) + +/* + * CISCO HDLC keepalive specific stuff + */ +static struct sk_buff* +isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len) { unsigned short hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen; - struct sk_buff *skb = alloc_skb(hl + sizeof(cisco_hdr) + sizeof(cisco_slarp), GFP_ATOMIC); - unsigned long t = (jiffies / HZ * 1000000); - cisco_hdr *ch; - cisco_slarp *s; + struct sk_buff *skb; + skb = alloc_skb(hl + len, GFP_ATOMIC); if (!skb) { - printk(KERN_WARNING - "%s: Could not allocate SLARP reply\n", lp->name); - return; + printk("isdn out of mem at %s:%d!\n", __FILE__, __LINE__); + return 0; } skb_reserve(skb, hl); - ch = (cisco_hdr *)skb_put(skb, sizeof(cisco_hdr)); - ch->addr = CISCO_ADDR_UNICAST; - ch->ctrl = 0; - ch->type = htons(CISCO_TYPE_SLARP); - s = (cisco_slarp *)skb_put(skb, sizeof(cisco_slarp)); - if (is_reply) { - s->code = htonl(CISCO_SLARP_REPLY); - memset(&s->slarp.reply.ifaddr, 0, sizeof(__u32)); - memset(&s->slarp.reply.netmask, 0, sizeof(__u32)); - } else { - lp->cisco_myseq++; - s->code = htonl(CISCO_SLARP_KEEPALIVE); - s->slarp.keepalive.my_seq = htonl(lp->cisco_myseq); - s->slarp.keepalive.your_seq = htonl(lp->cisco_yourseq); - } - s->rel = 0xffff; - s->t1 = t >> 16; - s->t0 = t & 0xffff; - isdn_net_write_super(lp, skb); + return skb; } -static void -isdn_net_slarp_in(isdn_net_local *lp, struct sk_buff *skb) +/* cisco hdlck device private ioctls */ +int +isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - cisco_slarp *s = (cisco_slarp *)skb->data; + isdn_net_local *lp = (isdn_net_local *) dev->priv; + unsigned long len = 0; + unsigned long expires = 0; + int tmp = 0; + int period = lp->cisco_keepalive_period; + char debserint = lp->cisco_debserint; + int rc = 0; + + if (lp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK) + return -EINVAL; + + switch (cmd) { + /* get/set keepalive period */ + case SIOCGKEEPPERIOD: + len = (unsigned long)sizeof(lp->cisco_keepalive_period); + if (copy_to_user((char *)ifr->ifr_ifru.ifru_data, + (int *)&lp->cisco_keepalive_period, len)) + rc = -EFAULT; + break; + case SIOCSKEEPPERIOD: + tmp = lp->cisco_keepalive_period; + len = (unsigned long)sizeof(lp->cisco_keepalive_period); + if (copy_from_user((int *)&period, + (char *)ifr->ifr_ifru.ifru_data, len)) + rc = -EFAULT; + if ((period > 0) && (period <= 32767)) + lp->cisco_keepalive_period = period; + else + rc = -EINVAL; + if (!rc && (tmp != lp->cisco_keepalive_period)) { + expires = (unsigned long)(jiffies + + lp->cisco_keepalive_period * HZ); + mod_timer(&lp->cisco_timer, expires); + printk(KERN_INFO "%s: Keepalive period set " + "to %d seconds.\n", + lp->name, lp->cisco_keepalive_period); + } + break; - switch (ntohl(s->code)) { - case CISCO_SLARP_REQUEST: - isdn_net_slarp_send(lp, 1); + /* get/set debugging */ + case SIOCGDEBSERINT: + len = (unsigned long)sizeof(lp->cisco_debserint); + if (copy_to_user((char *)ifr->ifr_ifru.ifru_data, + (char *)&lp->cisco_debserint, len)) + rc = -EFAULT; break; - case CISCO_SLARP_REPLY: - /* Ignore replies */ + case SIOCSDEBSERINT: + len = (unsigned long)sizeof(lp->cisco_debserint); + if (copy_from_user((char *)&debserint, + (char *)ifr->ifr_ifru.ifru_data, len)) + rc = -EFAULT; + if ((debserint >= 0) && (debserint <= 64)) + lp->cisco_debserint = debserint; + else + rc = -EINVAL; break; - case CISCO_SLARP_KEEPALIVE: - lp->cisco_yourseq = s->slarp.keepalive.my_seq; - if (ntohl(s->slarp.keepalive.my_seq == lp->cisco_myseq)) { - if (lp->cisco_loop++ == 2) { - printk(KERN_WARNING "%s: Keepalive Loop\n", - lp->name); - lp->cisco_myseq ^= jiffies; - } - } else - lp->cisco_loop = 0; + + default: + rc = -EINVAL; break; } - kfree_skb(skb); + return (rc); } -/* - * Called every 10 sec. via timer-interrupt if - * any network-interface has Cisco-Keepalive-Encapsulation - * and is online. - * Send Keepalive-Packet and re-schedule. - */ -void -isdn_net_slarp_out(void) +/* called via cisco_timer.function */ +static void +isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data) { - isdn_net_dev *p = dev->netdev; - int anymore = 0; + isdn_net_local *lp = (isdn_net_local *) data; + struct sk_buff *skb; + unsigned char *p; + unsigned long last_cisco_myseq = lp->cisco_myseq; + int myseq_diff = 0; - while (p) { - isdn_net_local *l = p->local; - if ((l->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) && - (l->flags & ISDN_NET_CONNECTED) && - (!l->dialstate) ) { - anymore = 1; - isdn_net_slarp_send(l, 0); + if (!(lp->flags & ISDN_NET_CONNECTED) || lp->dialstate) { + printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); + return; + } + lp->cisco_myseq++; + + myseq_diff = (lp->cisco_myseq - lp->cisco_mineseen); + if ((lp->cisco_line_state) && ((myseq_diff >= 3)||(myseq_diff <= -3))) { + /* line up -> down */ + lp->cisco_line_state = 0; + printk (KERN_WARNING + "UPDOWN: Line protocol on Interface %s," + " changed state to down\n", lp->name); + /* should stop routing higher-level data accross */ + } else if ((!lp->cisco_line_state) && + (myseq_diff >= 0) && (myseq_diff <= 2)) { + /* line down -> up */ + lp->cisco_line_state = 1; + printk (KERN_WARNING + "UPDOWN: Line protocol on Interface %s," + " changed state to up\n", lp->name); + /* restart routing higher-level data accross */ + } + + if (lp->cisco_debserint) + printk (KERN_DEBUG "%s: HDLC " + "myseq %lu, mineseen %lu%c, yourseen %lu, %s\n", + lp->name, last_cisco_myseq, lp->cisco_mineseen, + ((last_cisco_myseq == lp->cisco_mineseen) ? '*' : 040), + lp->cisco_yourseq, + ((lp->cisco_line_state) ? "line up" : "line down")); + + skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14); + if (!skb) + return; + + p = skb_put(skb, 4 + 14); + + /* cisco header */ + p += put_u8 (p, CISCO_ADDR_UNICAST); + p += put_u8 (p, CISCO_CTRL); + p += put_u16(p, CISCO_TYPE_SLARP); + + /* slarp keepalive */ + p += put_u32(p, CISCO_SLARP_KEEPALIVE); + p += put_u32(p, lp->cisco_myseq); + p += put_u32(p, lp->cisco_yourseq); + p += put_u16(p, 0xffff); // reliablity, always 0xffff + + isdn_net_write_super(lp, skb); + + lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ; + + add_timer(&lp->cisco_timer); +} + +static void +isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp) +{ + struct sk_buff *skb; + unsigned char *p; + + skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14); + if (!skb) + return; + + p = skb_put(skb, 4 + 14); + + /* cisco header */ + p += put_u8 (p, CISCO_ADDR_UNICAST); + p += put_u8 (p, CISCO_CTRL); + p += put_u16(p, CISCO_TYPE_SLARP); + + /* slarp request */ + p += put_u32(p, CISCO_SLARP_REQUEST); + p += put_u32(p, 0); // address + p += put_u32(p, 0); // netmask + p += put_u16(p, 0); // unused + + isdn_net_write_super(lp, skb); +} + +static void +isdn_net_ciscohdlck_connected(isdn_net_local *lp) +{ + lp->cisco_myseq = 0; + lp->cisco_mineseen = 0; + lp->cisco_yourseq = 0; + lp->cisco_keepalive_period = ISDN_TIMER_KEEPINT; + lp->cisco_last_slarp_in = 0; + lp->cisco_line_state = 0; + lp->cisco_debserint = 0; + + /* send slarp request because interface/seq.no.s reset */ + isdn_net_ciscohdlck_slarp_send_request(lp); + + init_timer(&lp->cisco_timer); + lp->cisco_timer.data = (unsigned long) lp; + lp->cisco_timer.function = isdn_net_ciscohdlck_slarp_send_keepalive; + lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ; + add_timer(&lp->cisco_timer); +} + +static void +isdn_net_ciscohdlck_disconnected(isdn_net_local *lp) +{ + del_timer(&lp->cisco_timer); +} + +static void +isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp) +{ + struct sk_buff *skb; + unsigned char *p; + struct in_device *in_dev = NULL; + u32 addr = 0; /* local ipv4 address */ + u32 mask = 0; /* local netmask */ + + if ((in_dev = lp->netdev->dev.ip_ptr) != NULL) { + /* take primary(first) address of interface */ + struct in_ifaddr *ifa = in_dev->ifa_list; + if (ifa != NULL) { + addr = ifa->ifa_local; + mask = ifa->ifa_mask; } - p = (isdn_net_dev *) p->next; } - isdn_timer_ctrl(ISDN_TIMER_KEEPALIVE, anymore); + + skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14); + if (!skb) + return; + + p = skb_put(skb, 4 + 14); + + /* cisco header */ + p += put_u8 (p, CISCO_ADDR_UNICAST); + p += put_u8 (p, CISCO_CTRL); + p += put_u16(p, CISCO_TYPE_SLARP); + + /* slarp reply, send own ip/netmask; if values are nonsense remote + * should think we are unable to provide it with an address via SLARP */ + p += put_u32(p, CISCO_SLARP_REPLY); + p += put_u32(p, addr); // address + p += put_u32(p, mask); // netmask + p += put_u16(p, 0); // unused + + isdn_net_write_super(lp, skb); +} + +static void +isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb) +{ + unsigned char *p; + int period; + __u32 code; + __u32 my_seq, addr; + __u32 your_seq, mask; + __u16 unused; + + if (skb->len < 14) + return; + + p = skb->data; + p += get_u32(p, &code); + + switch (code) { + case CISCO_SLARP_REQUEST: + lp->cisco_yourseq = 0; + isdn_net_ciscohdlck_slarp_send_reply(lp); + break; + case CISCO_SLARP_REPLY: + /* Ignore replies - at least for now */ + if (lp->cisco_debserint) { + p += get_u32(p, &addr); + p += get_u32(p, &mask); + p += get_u16(p, &unused); + printk(KERN_DEBUG "%s: got slarp reply (%ul/%ul) - " + "ignored\n", lp->name, addr, mask); + } + break; + case CISCO_SLARP_KEEPALIVE: + period = (int)((jiffies - lp->cisco_last_slarp_in + + HZ/2 - 1) / HZ); + if (lp->cisco_debserint && + (period != lp->cisco_keepalive_period) && + lp->cisco_last_slarp_in) { + printk(KERN_DEBUG "%s: Keepalive period mismatch - " + "is %d but should be %d.\n", + lp->name, period, lp->cisco_keepalive_period); + } + lp->cisco_last_slarp_in = jiffies; + p += get_u32(p, &my_seq); + p += get_u32(p, &your_seq); + p += get_u16(p, &unused); + lp->cisco_yourseq = my_seq; + lp->cisco_mineseen = your_seq; + break; + } +} + +static void +isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb) +{ + unsigned char *p; + __u8 addr; + __u8 ctrl; + __u16 type; + + if (skb->len < 4) + goto out_free; + + p = skb->data; + p += get_u8 (p, &addr); + p += get_u8 (p, &ctrl); + p += get_u16(p, &type); + skb_pull(skb, 4); + + if (addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) { + printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n", + lp->name, addr); + goto out_free; + } + if (ctrl != CISCO_CTRL) { + printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n", + lp->name, ctrl); + goto out_free; + } + + switch (type) { + case CISCO_TYPE_INET: + skb->protocol = htons(ETH_P_IP); + netif_rx(skb); + break; + case CISCO_TYPE_SLARP: + isdn_net_ciscohdlck_slarp_in(lp, skb); + goto out_free; + default: + printk(KERN_WARNING "%s: Unknown Cisco type 0x%04x\n", + lp->name, type); + goto out_free; + } + return; + + out_free: + kfree_skb(skb); } /* @@ -1517,8 +1782,6 @@ #ifdef CONFIG_ISDN_X25 struct concap_proto *cprot = lp -> netdev -> cprot; #endif - cisco_hdr *ch; - lp->transcount += skb->len; lp->stats.rx_packets++; @@ -1558,36 +1821,8 @@ skb->protocol = htons(ETH_P_IP); break; case ISDN_NET_ENCAP_CISCOHDLCK: - ch = (cisco_hdr *)skb->data; - if ((ch->addr != CISCO_ADDR_UNICAST) && - (ch->addr != CISCO_ADDR_BROADCAST) ) { - printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n", - lp->name, ch->addr); - kfree_skb(skb); - return; - } - if (ch->ctrl != 0) { - printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n", - lp->name, ch->ctrl); - kfree_skb(skb); - return; - } - switch (ntohs(ch->type)) { - case CISCO_TYPE_INET: - skb_pull(skb, 4); - skb->protocol = htons(ETH_P_IP); - break; - case CISCO_TYPE_SLARP: - skb_pull(skb, 4); - isdn_net_slarp_in(olp, skb); - return; - default: - printk(KERN_WARNING "%s: Unknown Cisco type 0x%04x\n", - lp->name, ch->type); - kfree_skb(skb); - return; - } - break; + isdn_net_ciscohdlck_receive(lp, skb); + return; case ISDN_NET_ENCAP_CISCOHDLC: /* CISCO-HDLC IP with type field and fake I-frame-header */ skb_pull(skb, 2); @@ -1705,6 +1940,7 @@ void *daddr, void *saddr, unsigned plen) { isdn_net_local *lp = dev->priv; + unsigned char *p; ushort len = 0; switch (lp->p_encap) { @@ -1733,10 +1969,11 @@ len = 2; break; case ISDN_NET_ENCAP_CISCOHDLC: - skb_push(skb, 4); - skb->data[0] = 0x0f; - skb->data[1] = 0x00; - *((ushort *) & skb->data[2]) = htons(type); + case ISDN_NET_ENCAP_CISCOHDLCK: + p = skb_push(skb, 4); + p += put_u8 (p, CISCO_ADDR_UNICAST); + p += put_u8 (p, CISCO_CTRL); + p += put_u16(p, type); len = 4; break; #ifdef CONFIG_ISDN_X25 @@ -1842,9 +2079,7 @@ ndev->stop = &isdn_net_close; ndev->get_stats = &isdn_net_get_stats; ndev->rebuild_header = &isdn_net_rebuild_header; -#ifdef CONFIG_ISDN_PPP - ndev->do_ioctl = isdn_ppp_dev_ioctl; -#endif + ndev->do_ioctl = NULL; return 0; } @@ -2508,6 +2743,7 @@ #else p->dev.type = ARPHRD_PPP; /* change ARP type */ p->dev.addr_len = 0; + p->dev.do_ioctl = isdn_ppp_dev_ioctl; #endif break; case ISDN_NET_ENCAP_X25IFACE: @@ -2519,6 +2755,9 @@ p->dev.type = ARPHRD_X25; /* change ARP type */ p->dev.addr_len = 0; #endif + break; + case ISDN_NET_ENCAP_CISCOHDLCK: + p->dev.do_ioctl = isdn_ciscohdlck_dev_ioctl; break; default: if( cfg->p_encap >= 0 && diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/isdn_net.h linux.ac/drivers/isdn/isdn_net.h --- linux.vanilla/drivers/isdn/isdn_net.h Tue Aug 8 23:03:57 2000 +++ linux.ac/drivers/isdn/isdn_net.h Tue Apr 17 15:32:08 2001 @@ -33,31 +33,9 @@ * Definitions for Cisco-HDLC header. */ -typedef struct cisco_hdr { - __u8 addr; /* unicast/broadcast */ - __u8 ctrl; /* Always 0 */ - __u16 type; /* IP-typefield */ -} cisco_hdr; - -typedef struct cisco_slarp { - __u32 code; /* SLREQ/SLREPLY/KEEPALIVE */ - union { - struct { - __u32 ifaddr; /* My interface address */ - __u32 netmask; /* My interface netmask */ - } reply; - struct { - __u32 my_seq; /* Packet sequence number */ - __u32 your_seq; - } keepalive; - } slarp; - __u16 rel; /* Always 0xffff */ - __u16 t1; /* Uptime in usec >> 16 */ - __u16 t0; /* Uptime in usec & 0xffff */ -} cisco_slarp; - #define CISCO_ADDR_UNICAST 0x0f #define CISCO_ADDR_BROADCAST 0x8f +#define CISCO_CTRL 0x00 #define CISCO_TYPE_INET 0x0800 #define CISCO_TYPE_SLARP 0x8035 #define CISCO_SLARP_REPLY 0 @@ -83,7 +61,6 @@ extern int isdn_net_force_dial(char *); extern isdn_net_dev *isdn_net_findif(char *); extern int isdn_net_rcv_skb(int, struct sk_buff *); -extern void isdn_net_slarp_out(void); extern int isdn_net_dial_req(isdn_net_local *); extern void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb); extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb); @@ -166,6 +143,52 @@ master_lp->netdev->queue = lp->next; lp->next = lp->last = lp; /* (re)set own pointers */ spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags); +} + +static inline int +put_u8(unsigned char *p, __u8 x) +{ + p[0] = x; + return 1; +} + +static inline int +put_u16(unsigned char *p, __u16 x) +{ + p[0] = x >> 8; + p[1] = x; + return 2; +} + +static inline int +put_u32(unsigned char *p, __u32 x) +{ + p[0] = x >> 24; + p[1] = x >> 16; + p[2] = x >> 8; + p[3] = x; + return 4; +} + +static inline int +get_u8(unsigned char *p, __u8 *x) +{ + *x = p[0]; + return 1; +} + +static inline int +get_u16(unsigned char *p, __u16 *x) +{ + *x = (p[0] << 8) + p[1]; + return 2; +} + +static inline int +get_u32(unsigned char *p, __u32 *x) +{ + *x = (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; + return 4; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/isdn_ppp.c linux.ac/drivers/isdn/isdn_ppp.c --- linux.vanilla/drivers/isdn/isdn_ppp.c Thu Feb 8 18:40:25 2001 +++ linux.ac/drivers/isdn/isdn_ppp.c Tue Apr 17 15:32:08 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.c,v 1.85.6.2 2001/01/23 17:45:02 kai Exp $ +/* $Id: isdn_ppp.c,v 1.85.6.4 2001/04/08 18:53:07 kai Exp $ * * Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -83,7 +83,7 @@ static int isdn_ppp_bundle(struct ippp_struct *, int unit); #endif /* CONFIG_ISDN_MPP */ -char *isdn_ppp_revision = "$Revision: 1.85.6.2 $"; +char *isdn_ppp_revision = "$Revision: 1.85.6.4 $"; static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; @@ -165,6 +165,7 @@ int unit = 0; long flags; struct ippp_struct *is; + int retval; save_flags(flags); cli(); @@ -197,12 +198,14 @@ if (i >= ISDN_MAX_CHANNELS) { restore_flags(flags); printk(KERN_WARNING "isdn_ppp_bind: Can't find a (free) connection to the ipppd daemon.\n"); - return -1; + retval = -1; + goto out; } unit = isdn_ppp_if_get_unit(lp->name); /* get unit number from interface name .. ugly! */ if (unit < 0) { printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", lp->name); - return -1; + retval = -1; + goto out; } lp->ppp_slot = i; @@ -211,13 +214,16 @@ is->unit = unit; is->state = IPPP_OPEN | IPPP_ASSIGNED; /* assigned to a netdevice but not connected */ #ifdef CONFIG_ISDN_MPP - if (isdn_ppp_mp_init(lp, NULL) < 0) - return -ENOMEM; + retval = isdn_ppp_mp_init(lp, NULL); + if (retval < 0) + goto out; #endif /* CONFIG_ISDN_MPP */ - restore_flags(flags); + retval = lp->ppp_slot; - return lp->ppp_slot; + out: + restore_flags(flags); + return retval; } /* @@ -2431,6 +2437,13 @@ switch(skb->data[0]) { case CCP_CONFREQ: + if(is->debug & 0x10) + printk(KERN_DEBUG "Disable compression here!\n"); + if(proto == PPP_CCP) + mis->compflags &= ~SC_COMP_ON; + else + is->compflags &= ~SC_LINK_COMP_ON; + break; case CCP_TERMREQ: case CCP_TERMACK: if(is->debug & 0x10) @@ -2546,6 +2559,17 @@ /* TODO: Clean this up with new Reset semantics */ +/* I believe the CCP handling as-is is done wrong. Compressed frames + * should only be sent/received after CCP reaches UP state, which means + * both sides have sent CONF_ACK. Currently, we handle both directions + * independently, which means we may accept compressed frames too early + * (supposedly not a problem), but may also mean we send compressed frames + * too early, which may turn out to be a problem. + * This part of state machine should actually be handled by (i)pppd, but + * that's too big of a change now. --kai + */ + + static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb) { struct ippp_struct *mis,*is = ippp_table[lp->ppp_slot]; @@ -2580,6 +2604,13 @@ switch(data[2]) { case CCP_CONFREQ: + if(is->debug & 0x10) + printk(KERN_DEBUG "Disable decompression here!\n"); + if(proto == PPP_CCP) + is->compflags &= ~SC_DECOMP_ON; + else + is->compflags &= ~SC_LINK_DECOMP_ON; + break; case CCP_TERMREQ: case CCP_TERMACK: if(is->debug & 0x10) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/pcbit/drv.c linux.ac/drivers/isdn/pcbit/drv.c --- linux.vanilla/drivers/isdn/pcbit/drv.c Tue Apr 3 17:32:06 2001 +++ linux.ac/drivers/isdn/pcbit/drv.c Thu Apr 12 12:02:46 2001 @@ -412,7 +412,6 @@ return len; } - int pcbit_writecmd(const u_char* buf, int len, int user, int driver, int channel) { struct pcbit_dev * dev; @@ -436,32 +435,36 @@ if (len > BANK4 + 1) { printk("pcbit_writecmd: invalid length %d\n", len); - return -EFAULT; + return -EINVAL; } if (user) { - u_char cbuf[1024]; + u_char *cbuf = kmalloc(len, GFP_KERNEL); + if (!cbuf) + return -ENOMEM; - copy_from_user(cbuf, buf, len); - for (i=0; i<len; i++) - writeb(cbuf[i], dev->sh_mem + i); + if (copy_from_user(cbuf, buf, len)) { + kfree(cbuf); + return -EFAULT; + } + memcpy_toio(dev->sh_mem, cbuf, len); + kfree(cbuf); } else memcpy_toio(dev->sh_mem, buf, len); return len; - break; case L2_FWMODE: /* this is the hard part */ /* dumb board */ - if (len < 0) - return -EINVAL; - if (user) { /* get it into kernel space */ if ((ptr = kmalloc(len, GFP_KERNEL))==NULL) return -ENOMEM; - copy_from_user(ptr, buf, len); + if (copy_from_user(ptr, buf, len)) { + kfree(ptr); + return -EFAULT; + } loadbuf = ptr; } else @@ -493,12 +496,9 @@ kfree(ptr); return errstat ? errstat : len; - - break; default: return -EBUSY; } - return 0; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/sc/interrupt.c linux.ac/drivers/isdn/sc/interrupt.c --- linux.vanilla/drivers/isdn/sc/interrupt.c Tue Apr 3 17:32:06 2001 +++ linux.ac/drivers/isdn/sc/interrupt.c Tue Apr 17 15:32:08 2001 @@ -1,5 +1,5 @@ /* - * $Id: interrupt.c,v 1.4.8.1 2001/03/13 16:17:09 kai Exp $ + * $Id: interrupt.c,v 1.4.8.2 2001/04/08 17:51:43 kai Exp $ * Copyright (C) 1996 SpellCaster Telecommunications Inc. * * This program is free software; you can redistribute it and/or modify @@ -34,7 +34,6 @@ extern int indicate_status(int, int, ulong, char *); extern void check_phystat(unsigned long); -extern void dump_messages(int); extern int receivemessage(int, RspMessage *); extern int sendmessage(int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int *); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/sc/message.c linux.ac/drivers/isdn/sc/message.c --- linux.vanilla/drivers/isdn/sc/message.c Mon Nov 8 00:34:00 1999 +++ linux.ac/drivers/isdn/sc/message.c Tue Apr 17 15:32:08 2001 @@ -1,5 +1,5 @@ /* - * $Id: message.c,v 1.5 1999/09/04 06:20:07 keil Exp $ + * $Id: message.c,v 1.5.8.1 2001/04/08 17:51:43 kai Exp $ * Copyright (C) 1996 SpellCaster Telecommunications Inc. * * message.c - functions for sending and receiving control messages @@ -38,55 +38,12 @@ extern unsigned int cinst; /* - * Obligitory function prototypes + * Obligatory function prototypes */ extern int indicate_status(int,ulong,char*); extern int scm_command(isdn_ctrl *); extern void *memcpy_fromshmem(int, void *, const void *, size_t); -/* - * Dump message queue in shared memory to screen - */ -void dump_messages(int card) -{ - DualPortMemory dpm; - unsigned long flags; - - int i =0; - - if (!IS_VALID_CARD(card)) { - pr_debug("Invalid param: %d is not a valid card id\n", card); - } - - save_flags(flags); - cli(); - outb(adapter[card]->ioport[adapter[card]->shmem_pgport], - (adapter[card]->shmem_magic >> 14) | 0x80); - memcpy_fromshmem(card, &dpm, 0, sizeof(dpm)); - restore_flags(flags); - - pr_debug("%s: Dumping Request Queue\n", adapter[card]->devicename); - for (i = 0; i < dpm.req_head; i++) { - pr_debug("%s: Message #%d: (%d,%d,%d), link: %d\n", - adapter[card]->devicename, i, - dpm.req_queue[i].type, - dpm.req_queue[i].class, - dpm.req_queue[i].code, - dpm.req_queue[i].phy_link_no); - } - - pr_debug("%s: Dumping Response Queue\n", adapter[card]->devicename); - for (i = 0; i < dpm.rsp_head; i++) { - pr_debug("%s: Message #%d: (%d,%d,%d), link: %d, status: %d\n", - adapter[card]->devicename, i, - dpm.rsp_queue[i].type, - dpm.rsp_queue[i].class, - dpm.rsp_queue[i].code, - dpm.rsp_queue[i].phy_link_no, - dpm.rsp_queue[i].rsp_status); - } - -} /* * receive a message from the board diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/macintosh/mac_hid.c linux.ac/drivers/macintosh/mac_hid.c --- linux.vanilla/drivers/macintosh/mac_hid.c Sun Sep 17 17:48:05 2000 +++ linux.ac/drivers/macintosh/mac_hid.c Tue Apr 3 17:54:45 2001 @@ -473,9 +473,19 @@ #ifdef CONFIG_MAC_ADBKEYCODES memcpy(pc_key_maps_save, key_maps, sizeof(key_maps)); - if (!keyboard_sends_linux_keycodes) + 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(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 + } +#endif /* CONFIG_MAC_ADBKEYCODES */ #ifdef CONFIG_MAC_EMUMOUSEBTN emumousebtn_input_register(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/macintosh/mac_keyb.c linux.ac/drivers/macintosh/mac_keyb.c --- linux.vanilla/drivers/macintosh/mac_keyb.c Mon Dec 4 01:48:19 2000 +++ linux.ac/drivers/macintosh/mac_keyb.c Tue Apr 3 17:54:45 2001 @@ -305,7 +305,7 @@ return 1; } -int mackbd_unexpected_up(unsigned char keycode) +char mackbd_unexpected_up(unsigned char keycode) { return 0x80; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/macintosh/via-cuda.c linux.ac/drivers/macintosh/via-cuda.c --- linux.vanilla/drivers/macintosh/via-cuda.c Sun Sep 17 17:48:05 2000 +++ linux.ac/drivers/macintosh/via-cuda.c Tue Apr 3 17:54:45 2001 @@ -170,7 +170,7 @@ } /* Clear and enable interrupts, but only on PPC. On 68K it's done */ - /* for us by the the main VIA driver in arch/m68k/mac/via.c */ + /* for us by the main VIA driver in arch/m68k/mac/via.c */ #ifndef CONFIG_MAC via[IFR] = 0x7f; eieio(); /* clear interrupts by writing 1s */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/md/Config.in linux.ac/drivers/md/Config.in --- linux.vanilla/drivers/md/Config.in Mon Jan 29 21:16:00 2001 +++ linux.ac/drivers/md/Config.in Tue Apr 3 17:54:45 2001 @@ -6,12 +6,12 @@ bool 'Multiple devices driver support (RAID and LVM)' CONFIG_MD -dep_tristate ' RAID support' CONFIG_BLK_DEV_MD $CONFIG_MD -dep_tristate ' Linear (append) mode' CONFIG_MD_LINEAR $CONFIG_BLK_DEV_MD -dep_tristate ' RAID-0 (striping) mode' CONFIG_MD_RAID0 $CONFIG_BLK_DEV_MD -dep_tristate ' RAID-1 (mirroring) mode' CONFIG_MD_RAID1 $CONFIG_BLK_DEV_MD -dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD +dep_tristate ' RAID support' CONFIG_BLK_DEV_MD $CONFIG_MD +dep_tristate ' Linear (append) mode' CONFIG_MD_LINEAR $CONFIG_BLK_DEV_MD +dep_tristate ' RAID-0 (striping) mode' CONFIG_MD_RAID0 $CONFIG_BLK_DEV_MD +dep_tristate ' RAID-1 (mirroring) mode' CONFIG_MD_RAID1 $CONFIG_BLK_DEV_MD +dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD -dep_tristate ' Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM $CONFIG_MD +dep_tristate ' Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM $CONFIG_MD endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/md/lvm.c linux.ac/drivers/md/lvm.c --- linux.vanilla/drivers/md/lvm.c Mon Jan 29 00:11:20 2001 +++ linux.ac/drivers/md/lvm.c Sat Apr 14 01:22:14 2001 @@ -147,7 +147,10 @@ * 08/01/2001 - Removed conditional compiles related to PROC_FS, * procfs is always supported now. (JT) * 12/01/2001 - avoided flushing logical volume in case of shrinking - * because of unecessary overhead in case of heavy updates + * because of unnecessary overhead in case of heavy updates + * 05/04/2001 - lvm_map bugs: don't use b_blocknr/b_dev in lvm_map, it + * destroys stacking devices. call b_end_io on failed maps. + * (Jens Axboe) * */ @@ -164,12 +167,6 @@ #include <linux/config.h> #include <linux/version.h> -#ifdef MODVERSIONS -#undef MODULE -#define MODULE -#include <linux/modversions.h> -#endif - #include <linux/module.h> #include <linux/kernel.h> @@ -1480,14 +1477,14 @@ */ static int lvm_map(struct buffer_head *bh, int rw) { - int minor = MINOR(bh->b_dev); + int minor = MINOR(bh->b_rdev); int ret = 0; ulong index; ulong pe_start; ulong size = bh->b_size >> 9; - ulong rsector_tmp = bh->b_blocknr * size; + ulong rsector_tmp = bh->b_rsector; ulong rsector_sav; - kdev_t rdev_tmp = bh->b_dev; + kdev_t rdev_tmp = bh->b_rdev; kdev_t rdev_sav; vg_t *vg_this = vg[VG_BLK(minor)]; lv_t *lv = vg_this->lv[LV_BLK(minor)]; @@ -1676,8 +1673,12 @@ */ static int lvm_make_request_fn(request_queue_t *q, int rw, - struct buffer_head *bh) { - return (lvm_map(bh, rw) < 0) ? 0 : 1; + struct buffer_head *bh) +{ + int ret = lvm_map(bh, rw); + if (ret < 0) + buffer_IO_error(bh); + return ret; } @@ -1933,7 +1934,9 @@ if ( ret != 0) return ret; pv_ptr = vg_ptr->pv[p]; vg_ptr->pe_total += pv_ptr->pe_total; - lvm_do_create_proc_entry_of_pv(vg_ptr, pv_ptr); +#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS + lvm_do_create_proc_entry_of_pv ( vg_ptr, pv_ptr); +#endif return 0; } } @@ -1983,6 +1986,8 @@ lv_t *lv_ptr = NULL; pv_t *pv_ptr = NULL; + if (vg_ptr == NULL) return -ENXIO; + if (copy_from_user(vg_name, arg, sizeof(vg_name)) != 0) return -EFAULT; @@ -2902,8 +2907,6 @@ } } } - - /* * remove a /proc entry for a logical volume */ @@ -2917,6 +2920,7 @@ remove_proc_entry(basename, vg_ptr->lv_subdir_pde); } } + /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/md/md.c linux.ac/drivers/md/md.c --- linux.vanilla/drivers/md/md.c Tue Apr 3 17:32:06 2001 +++ linux.ac/drivers/md/md.c Tue Apr 10 18:14:58 2001 @@ -1063,10 +1063,10 @@ } printk(".\n"); if (err) { - printk("errors occured during superblock update, repeating\n"); + printk("errors occurred during superblock update, repeating\n"); if (--count) goto repeat; - printk("excessive errors occured during superblock update, exiting\n"); + printk("excessive errors occurred during superblock update, exiting\n"); } return 0; } @@ -3910,4 +3910,3 @@ MD_EXPORT_SYMBOL(md_interrupt_thread); MD_EXPORT_SYMBOL(mddev_map); MD_EXPORT_SYMBOL(md_check_ordering); - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/md/raid1.c linux.ac/drivers/md/raid1.c --- linux.vanilla/drivers/md/raid1.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/md/raid1.c Tue Apr 3 17:54:46 2001 @@ -832,6 +832,7 @@ struct mirror_info *tmp, *sdisk, *fdisk, *rdisk, *adisk; mdp_super_t *sb = mddev->sb; mdp_disk_t *failed_desc, *spare_desc, *added_desc; + mdk_rdev_t *spare_rdev, *failed_rdev; print_raid1_conf(conf); md_spin_lock_irq(&conf->device_lock); @@ -989,6 +990,11 @@ /* * do the switch finally */ + spare_rdev = find_rdev_nr(mddev, spare_desc->number); + failed_rdev = find_rdev_nr(mddev, failed_desc->number); + if (spare_rdev && failed_rdev) + xchg_values(spare_rdev->desc_nr, failed_rdev->desc_nr); + xchg_values(*spare_desc, *failed_desc); xchg_values(*fdisk, *sdisk); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/md/raid5.c linux.ac/drivers/md/raid5.c --- linux.vanilla/drivers/md/raid5.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/md/raid5.c Tue Apr 3 17:54:46 2001 @@ -157,11 +157,11 @@ memset(bh, 0, sizeof (struct buffer_head)); init_waitqueue_head(&bh->b_wait); page = alloc_page(priority); - bh->b_data = page_address(page); - if (!bh->b_data) { + if (!page) { kfree(bh); return 1; } + bh->b_data = page_address(page); atomic_set(&bh->b_count, 0); bh->b_page = page; sh->bh_cache[i] = bh; @@ -1267,11 +1267,13 @@ if (conf->working_disks != conf->raid_disks) goto out; tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) + goto out; tmp->b_size = 4096; tmp->b_page = alloc_page(GFP_KERNEL); - tmp->b_data = page_address(tmp->b_page); - if (!tmp->b_data) + if (!tmp->b_page) goto out; + tmp->b_data = page_address(tmp->b_page); md_clear_page(tmp->b_data); memset(bh, 0, MD_SB_DISKS * sizeof(struct buffer_head *)); for (i = 0; i < conf->raid_disks; i++) { @@ -1704,6 +1706,7 @@ struct disk_info *tmp, *sdisk, *fdisk, *rdisk, *adisk; mdp_super_t *sb = mddev->sb; mdp_disk_t *failed_desc, *spare_desc, *added_desc; + mdk_rdev_t *spare_rdev, *failed_rdev; print_raid5_conf(conf); md_spin_lock_irq(&conf->device_lock); @@ -1875,6 +1878,11 @@ /* * do the switch finally */ + spare_rdev = find_rdev_nr(mddev, spare_desc->number); + failed_rdev = find_rdev_nr(mddev, failed_desc->number); + if (spare_rdev && failed_rdev) + xchg_values(spare_rdev->desc_nr, failed_rdev->desc_nr); + xchg_values(*spare_desc, *failed_desc); xchg_values(*fdisk, *sdisk); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/radio/Config.in linux.ac/drivers/media/radio/Config.in --- linux.vanilla/drivers/media/radio/Config.in Tue Apr 3 17:32:08 2001 +++ linux.ac/drivers/media/radio/Config.in Tue Apr 3 17:54:46 2001 @@ -23,7 +23,7 @@ fi dep_tristate ' Guillemot MAXI Radio FM 2000 radio' CONFIG_RADIO_MAXIRADIO $CONFIG_VIDEO_DEV 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 ' miroSOUND PCM20 radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV $CONFIG_SOUND_ACI_MIXER dep_tristate ' SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then hex ' SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/radio/Makefile linux.ac/drivers/media/radio/Makefile --- linux.vanilla/drivers/media/radio/Makefile Tue Apr 3 17:32:08 2001 +++ linux.ac/drivers/media/radio/Makefile Tue Apr 3 17:54:46 2001 @@ -23,7 +23,9 @@ export-objs := -list-multi := +list-multi := miropcm20.o + +miropcm20-objs := radio-miropcm20.o rds-miropcm20.o obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o @@ -34,9 +36,12 @@ obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o -obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o +obj-$(CONFIG_RADIO_MIROPCM20) += miropcm20.o obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o include $(TOPDIR)/Rules.make + +miropcm20.o: $(miropcm20-objs) + $(LD) -r -o $@ $(miropcm20-objs) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/radio/radio-miropcm20.c linux.ac/drivers/media/radio/radio-miropcm20.c --- linux.vanilla/drivers/media/radio/radio-miropcm20.c Tue Apr 3 17:32:08 2001 +++ linux.ac/drivers/media/radio/radio-miropcm20.c Tue Apr 3 17:54:46 2001 @@ -2,62 +2,53 @@ * (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl> * Thanks to Norberto Pellici for the ACI device interface specification * The API part is based on the radiotrack driver by M. Kirkwood - * This driver relies on the aci mixer (drivers/sound/lowlevel/aci.c) + * This driver relies on the aci mixer (drivers/sound/aci.c) * Look there for further info... */ -#include <linux/module.h> /* Modules */ -#include <linux/init.h> /* Initdata */ -#include <asm/uaccess.h> /* copy to/from user */ -#include <linux/videodev.h> /* kernel radio structs */ -#include "../../sound/miroaci.h" /* ACI Control by acimixer */ +/* Revision history: + * + * 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl> + * 2000-09-05 Robert Siemer <Robert.Siemer@gmx.de> + * removed unfinished volume control (maybe adding it later again) + * use OSS-mixer; added stereo control + */ + +/* What ever you think about the ACI, version 0x07 is not very well! + * I cant get frequency, 'tuner status', 'tuner flags' or mute/mono + * conditions... Robert + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/videodev.h> +#include <linux/devfs_fs_kernel.h> +#include <asm/uaccess.h> + +char * aci_radio_name; + +#include "../../sound/aci.h" static int users = 0; struct pcm20_device { - int port; - int curvol; - unsigned long curfreq; + unsigned long freq; int muted; + int stereo; }; -/* local things */ - - -static void pcm20_mute(struct pcm20_device *dev) +static int pcm20_mute(struct pcm20_device *dev, unsigned char mute) { - - dev->muted = 1; - aci_write_cmd(0xa3,0x01); - + dev->muted = mute; + return aci_write_cmd(0xa3, mute); } -static int pcm20_setvol(struct pcm20_device *dev, int vol) +static int pcm20_stereo(struct pcm20_device *dev, unsigned char stereo) { - - if(vol == dev->curvol) { /* requested volume = current */ - if (dev->muted) { /* user is unmuting the card */ - dev->muted = 0; - aci_write_cmd(0xa3,0x00); /* enable card */ - } - - return 0; - } - - if(vol == 0) { /* volume = 0 means mute the card */ - aci_write_cmd(0x3d, 0x20); - aci_write_cmd(0x35, 0x20); - return 0; - } - - dev->muted = 0; - aci_write_cmd(0x3d, 32-vol); /* Right Channel */ - aci_write_cmd(0x35, 32-vol); /* Left Channel */ - dev->curvol = vol; - - return 0; + dev->stereo = stereo; + return aci_write_cmd(0xa4, !stereo); } static int pcm20_setfreq(struct pcm20_device *dev, unsigned long freq) @@ -65,28 +56,79 @@ unsigned char freql; unsigned char freqh; - freq = (freq * 10) / 16; - freql = freq & 0xff; - freqh = freq >> 8; + dev->freq=freq; + freq /= 160; + if (!(aci_version==0x07 || aci_version>=0xb0)) + freq /= 10; /* I don't know exactly which version + * needs this hack */ + freql = freq & 0xff; + freqh = freq >> 8; - aci_write_cmd_d(0xa7, freql, freqh); /* Tune to frequency */ + aci_rds_cmd(RDS_RESET, 0, 0); + pcm20_stereo(dev, 1); - return 0; + return aci_rw_cmd(0xa7, freql, freqh); /* Tune to frequency */ } -int pcm20_getsigstr(struct pcm20_device *dev) +static int pcm20_getflags(struct pcm20_device *dev, __u32 *flags, __u16 *signal) { + /* okay, check for signal, stereo and rds here... */ + int i; unsigned char buf; - aci_indexed_cmd(0xf0, 0x32, &buf); - if ((buf & 0x80) == 0x80) + + if ((i=aci_rw_cmd(0xa9, -1, -1))<0) + return i; +#if DEBUG + printk("check_sig: 0x%x\n", i); +#endif + if (i & 0x80) { + /* no signal from tuner */ + *flags=0; + *signal=0; + return 0; + } else + *signal=0xffff; + + if ((i=aci_rw_cmd(0xa8, -1, -1))<0) + return i; + if (i & 0x40) { + *flags=0; + } else { + /* stereo */ + *flags=VIDEO_TUNER_STEREO_ON; + /* I cant see stereo, when forced to mono */ + dev->stereo=1; + } + + if ((i=aci_rds_cmd(RDS_STATUS, &buf, 1))<0) + return i; + if (buf & 1) + /* RDS available */ + *flags|=VIDEO_TUNER_RDS_ON; + else return 0; - return 1; /* signal present */ + + if ((i=aci_rds_cmd(RDS_RXVALUE, &buf, 1))<0) + return i; +#if DEBUG + printk("rds-signal: %d\n", buf); +#endif + if (buf > 15) { + printk("rds-miropcm20: RX strengths unexpected high...\n"); + buf=15; + } + /* refine signal */ + if ((*signal=SCALE(15, 0xffff, buf))==0) + *signal = 1; + + return 0; } static int pcm20_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { struct pcm20_device *pcm20=dev->priv; + int i; switch(cmd) { @@ -113,11 +155,11 @@ return -EFAULT; if(v.tuner) /* Only 1 tuner */ return -EINVAL; - v.rangelow=(int)(87.5*16); - v.rangehigh=(int)(108.0*16); - v.flags=0; + v.rangelow=87*16000; + v.rangehigh=108*16000; + pcm20_getflags(pcm20, &v.flags, &v.signal); + v.flags|=VIDEO_TUNER_LOW; v.mode=VIDEO_MODE_AUTO; - v.signal=0xFFFF*pcm20_getsigstr(pcm20); strcpy(v.name, "FM"); if(copy_to_user(arg,&v, sizeof(v))) return -EFAULT; @@ -134,20 +176,28 @@ return 0; } case VIDIOCGFREQ: - if(copy_to_user(arg, &pcm20->curfreq, sizeof(pcm20->curfreq))) + if(copy_to_user(arg, &pcm20->freq, sizeof(pcm20->freq))) return -EFAULT; return 0; case VIDIOCSFREQ: - if(copy_from_user(&pcm20->curfreq, arg,sizeof(pcm20->curfreq))) + if(copy_from_user(&pcm20->freq, arg, sizeof(pcm20->freq))) return -EFAULT; - pcm20_setfreq(pcm20, pcm20->curfreq); - return 0; + i=pcm20_setfreq(pcm20, pcm20->freq); +#if DEBUG + printk("First view (setfreq): 0x%x\n", i); +#endif + return i; case VIDIOCGAUDIO: { struct video_audio v; memset(&v,0, sizeof(v)); - v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME; - v.volume=pcm20->curvol * 2048; + v.flags=VIDEO_AUDIO_MUTABLE; + if (pcm20->muted) + v.flags|=VIDEO_AUDIO_MUTE; + v.mode=VIDEO_SOUND_STEREO; + if (pcm20->stereo) + v.mode|=VIDEO_SOUND_MONO; + /* v.step=2048; */ strcpy(v.name, "Radio"); if(copy_to_user(arg,&v, sizeof(v))) return -EFAULT; @@ -157,14 +207,15 @@ { struct video_audio v; if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; + return -EFAULT; if(v.audio) return -EINVAL; - if(v.flags&VIDEO_AUDIO_MUTE) - pcm20_mute(pcm20); - else - pcm20_setvol(pcm20,v.volume/2048); + pcm20_mute(pcm20, !!(v.flags&VIDEO_AUDIO_MUTE)); + if(v.flags&VIDEO_SOUND_MONO) + pcm20_stereo(pcm20, 0); + if(v.flags&VIDEO_SOUND_STEREO) + pcm20_stereo(pcm20, 1); return 0; } @@ -186,7 +237,12 @@ users--; } -static struct pcm20_device pcm20_unit; +static struct pcm20_device pcm20_unit= +{ + freq: 87*16000, + muted: 1, + stereo: 0 +}; static struct video_device pcm20_radio= { @@ -197,24 +253,23 @@ open: pcm20_open, close: pcm20_close, ioctl: pcm20_ioctl, + priv: &pcm20_unit }; static int __init pcm20_init(void) { - - pcm20_radio.priv=&pcm20_unit; - if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO)==-1) return -EINVAL; + if(attach_aci_rds()<0) { + video_unregister_device(&pcm20_radio); + return -EINVAL; + } +#if DEBUG + printk("v4l-name: %s\n", devfs_get_name(pcm20_radio.devfs_handle, 0)); +#endif printk(KERN_INFO "Miro PCM20 radio card driver.\n"); - /* mute card - prevents noisy bootups */ - - /* this ensures that the volume is all the way down */ - - pcm20_unit.curvol = 0; - return 0; } @@ -225,9 +280,9 @@ static void __exit pcm20_cleanup(void) { + unload_aci_rds(); video_unregister_device(&pcm20_radio); } module_init(pcm20_init); module_exit(pcm20_cleanup); - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/radio/rds-miropcm20.c linux.ac/drivers/media/radio/rds-miropcm20.c --- linux.vanilla/drivers/media/radio/rds-miropcm20.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/media/radio/rds-miropcm20.c Tue Apr 3 17:54:46 2001 @@ -0,0 +1,249 @@ +/* + * Many thanks to Fred Seidel <seidel@metabox.de>, the + * designer of the RDS decoder hardware. With his help + * I was able to code this driver. + * Thanks also to Norberto Pellicci, Dominic Mounteney + * <DMounteney@pinnaclesys.com> and www.teleauskunft.de + * for good hints on finding Fred. It was somewhat hard + * to locate him here in Germany... [: + * + * Revision history: + * + * 2000-08-09 Robert Siemer <Robert.Siemer@gmx.de> + * RDS support for MiroSound PCM20 radio + */ + +#define _NO_VERSION_ + +/* #include <linux/kernel.h> */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <asm/semaphore.h> +#include <asm/io.h> +#include "../../sound/aci.h" + +#define WATCHMASK 0352 /* 11101010 */ + +#define DEBUG 0 + +static struct semaphore aci_rds_sem; + + +#define RDS_BUSYMASK 0x10 /* Bit 4 */ +#define RDS_CLOCKMASK 0x08 /* Bit 3 */ +#define RDS_DATAMASK 0x04 /* Bit 2 */ + + +static void print_matrix(char array[], unsigned int length) +{ + int i, j; + + for (i=0; i<length; i++) { + printk("aci-rds: "); + for (j=7; j>=0; j--) { + printk("%d", (array[i] >> j) & 0x1); + } + if (i%8 == 0) + printk(" byte-border\n"); + else + printk("\n"); + } +} + +static int byte2trans(unsigned char byte, unsigned char sendbuffer[], int size) +{ + int i; + + if (size != 8) + return -1; + for (i = 7; i >= 0; i--) + sendbuffer[7-i] = (byte & (1 << i)) ? RDS_DATAMASK : 0; + sendbuffer[0] |= RDS_CLOCKMASK; + + return 0; +} + +static int trans2byte(unsigned char buffer[], int size) +{ + int i; + unsigned char byte=0; + + if (size != 8) + return -1; + for (i = 7; i >= 0; i--) + byte |= ((buffer[7-i] & RDS_DATAMASK) ? 1 : 0) << i; + + return byte; +} + +static int trans2data(unsigned char readbuffer[], int readsize, unsigned char data[], int datasize) +{ + int i,j; + + if (readsize != datasize*8) + return -1; + for (i = 0; i < datasize; i++) + if ((j=trans2byte(&readbuffer[i*8], 8)) < 0) + return -1; + else + data[i]=j; + return 0; +} + +static int rds_waitread(void) +{ + unsigned char byte; + int i=2000; + + do { + byte=inb(RDS_REGISTER); + if ((byte & WATCHMASK) != WATCHMASK) + printk("aci-rds: Hidden information discoverd!\n"); + i--; + } + while ((byte & RDS_BUSYMASK) && i); + + if (i) { +#if DEBUG + printk("rds_waitread()"); + print_matrix(&byte, 1); +#endif + return (byte); + } else { + printk("aci-rds: rds_waitread() timeout...\n"); + return -1; + } +} + +/* dont use any ..._nowait() function if you are not sure what you do... */ + +static inline void rds_rawwrite_nowait(unsigned char byte) +{ +#if DEBUG + printk("rds_rawwrite()"); + print_matrix(&byte, 1); +#endif + outb(byte, RDS_REGISTER); +} + +static int rds_rawwrite(unsigned char byte) +{ + if (rds_waitread() >= 0) { + rds_rawwrite_nowait(byte); + return 0; + } else + return -1; +} + +static int rds_write(unsigned char cmd) +{ + unsigned char sendbuffer[8]; + int i; + + if (byte2trans(cmd, sendbuffer, 8) != 0){ + return -1; + } else { + for (i=0; i<8; i++) { + rds_rawwrite(sendbuffer[i]); + } + } + return 0; +} + +static int rds_readcycle_nowait(void) +{ + rds_rawwrite_nowait(0); + return rds_waitread(); +} + +static int rds_readcycle(void) +{ + if (rds_rawwrite(0) < 0) + return -1; + return rds_waitread(); +} + +static int rds_read(unsigned char databuffer[], int datasize) +{ + +#define READSIZE (8*datasize) + + int i,j; + unsigned char* readbuffer; + + if (!datasize) /* nothing to read */ + return 0; + + /* to be able to use rds_readcycle_nowait() + I have to readwait() here */ + if (rds_waitread() < 0) + return -1; + + if ((readbuffer=kmalloc(READSIZE, GFP_KERNEL)) == 0) { + printk("aci-rds: Out of memory...\n"); + return -ENOMEM; + } else { + if (signal_pending(current)) { + kfree(readbuffer); + return -EINTR; + } + } + + for (i=0; i< READSIZE; i++) + if((j=rds_readcycle_nowait()) < 0) { + kfree(readbuffer); + return -1; + } else + readbuffer[i]=j; + if (trans2data(readbuffer, READSIZE, databuffer, datasize) < 0) { + kfree(readbuffer); + return -1; + } + kfree(readbuffer); + return 0; +} + +static int rds_ack(void) +{ + int i=rds_readcycle(); + + if (i < 0) + return -1; + if (i & RDS_DATAMASK) { + return 0; /* ACK */ + } else { + return 1; /* NACK */ + } +} + +int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize) +{ + int ret; + + if (down_interruptible(&aci_rds_sem)) + return -EINTR; + + if (rds_write(cmd)) + ret = -2; + + /* RDS_RESET doesn't need further processing */ + if (cmd!=RDS_RESET && (rds_ack() || rds_read(databuffer, datasize))) + ret = -1; + else + ret = 0; + + up(&aci_rds_sem); + + return ret; +} + +int __init attach_aci_rds(void) +{ + init_MUTEX(&aci_rds_sem); + return 0; +} + +void __exit unload_aci_rds(void) +{ +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/Config.in linux.ac/drivers/media/video/Config.in --- linux.vanilla/drivers/media/video/Config.in Sat Feb 17 00:02:36 2001 +++ linux.ac/drivers/media/video/Config.in Tue Apr 3 23:52:23 2001 @@ -21,6 +21,13 @@ dep_tristate ' QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT fi fi +if [ "$CONFIG_PARPORT" != "n" ]; then + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_PARPORT_1284" != "n" ]; then + dep_tristate ' Winbond W9966CF Webcam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_W9966 $CONFIG_VIDEO_DEV $CONFIG_PARPORT + fi + fi +fi dep_tristate ' CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV if [ "$CONFIG_VIDEO_CPIA" != "n" ]; then if [ "$CONFIG_PARPORT_1284" != "n" ]; then @@ -39,7 +46,6 @@ dep_tristate ' Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)' CONFIG_VIDEO_STRADIS $CONFIG_VIDEO_DEV $CONFIG_PCI fi dep_tristate ' Zoran ZR36057/36060 Video For Linux' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C -dep_tristate ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN dep_tristate ' Zoran ZR36120/36125 Video For Linux' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/Makefile linux.ac/drivers/media/video/Makefile --- linux.vanilla/drivers/media/video/Makefile Fri Dec 29 22:07:22 2000 +++ linux.ac/drivers/media/video/Makefile Sun Apr 15 15:12:50 2001 @@ -38,12 +38,13 @@ tda7432.o tda9875.o tuner.o obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o -obj-$(CONFIG_VIDEO_ZR36120) += zoran.o i2c-old.o tuner.o saa7110.o saa7111.o saa7185.o +obj-$(CONFIG_VIDEO_ZR36120) += zoran.o obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o i2c-old.o obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o i2c-old.o obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o -obj-$(CONFIG_VIDEO_ZORAN) += buz.o i2c-old.o saa7110.o saa7111.o saa7185.o +obj-$(CONFIG_VIDEO_W9966) += w9966.o +obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o i2c-old.o saa7110.o saa7111.o saa7185.o adv7175.o bt819.o bt856.o obj-$(CONFIG_VIDEO_LML33) += bt856.o bt819.o obj-$(CONFIG_VIDEO_PMS) += pms.o obj-$(CONFIG_VIDEO_PLANB) += planb.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/adv7175.c linux.ac/drivers/media/video/adv7175.c --- linux.vanilla/drivers/media/video/adv7175.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/media/video/adv7175.c Tue Apr 3 17:54:46 2001 @@ -0,0 +1,478 @@ +#define DEBUGLEVEL 0 +/* + adv7175 - adv7175a video encoder driver version 0.0.3 + + Copyright (C) 1998 Dave Perks <dperks@ibm.net> + + Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net> + Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> + - some corrections for Pinnacle Systems Inc. DC10plus card. + + 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 <linux/module.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/malloc.h> +#include <linux/mm.h> +#include <linux/pci.h> +#include <linux/signal.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <linux/sched.h> +#include <asm/segment.h> +#include <linux/types.h> +#include <linux/wrapper.h> + +#include <linux/videodev.h> +#include <linux/version.h> +#include <asm/uaccess.h> + +#include <linux/i2c-old.h> + +#include <linux/video_encoder.h> + +#if (DEBUGLEVEL > 0) +#define DEBUG(x...) x /* Debug driver */ +#else +#define DEBUG(x...) +#endif + +/* ----------------------------------------------------------------------- */ + +struct adv7175 { + struct i2c_bus *bus; + int addr; + unsigned char reg[128]; + + int norm; + int input; + int enable; + int bright; + int contrast; + int hue; + int sat; +}; + +#define I2C_ADV7175 0xd4 +#define I2C_ADV7176 0x54 + +static char adv7175_name[] = "adv7175"; +static char adv7176_name[] = "adv7176"; +static char unknown_name[] = "UNKNOWN"; + +#if (DEBUGLEVEL > 0) +static char *inputs[] = { "pass_through", "play_back", "color_bar" }; +static char *norms[] = { "PAL", "NTSC", "SECAM->PAL (may not work!)" }; +#endif + +#define I2C_DELAY 10 + +/* ----------------------------------------------------------------------- */ + +static int adv7175_write(struct adv7175 *dev, unsigned char subaddr, unsigned char data) +{ + int ack; + + LOCK_I2C_BUS(dev->bus); + + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, data, I2C_DELAY); + dev->reg[subaddr] = data; + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return ack; +} + +static unsigned char adv7175_read(struct adv7175 *dev, unsigned char subaddr) +{ + unsigned char data; + + LOCK_I2C_BUS(dev->bus); + + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); + i2c_sendbyte(dev->bus, dev->addr + 1, I2C_DELAY); + data = i2c_readbyte(dev->bus, 1); + dev->reg[subaddr] = data; + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return data; +} + +static int adv7175_write_block(struct adv7175 *dev, + unsigned const char *data, unsigned int len) +{ + int ack = 0; + unsigned subaddr; + + while (len > 1) { + LOCK_I2C_BUS(dev->bus); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, (subaddr = *data++), I2C_DELAY); + ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); + len -= 2; + while (len > 1 && *data == ++subaddr) { + data++; + ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); + len -= 2; + } + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + } + return ack; +} + +/* ----------------------------------------------------------------------- */ +// Output filter: S-Video Composite + +#define MR050 0x11 //0x09 +#define MR060 0x14 //0x0c + +//--------------------------------------------------------------------------- + +#define TR0MODE 0x46 +#define TR0RST 0x80 + +#define TR1CAPT 0x80 +#define TR1PLAY 0x00 + +static const unsigned char init_common[] = { + + 0x00, MR050, /* MR0, PAL enabled */ + 0x01, 0x00, /* MR1 */ + 0x02, 0x0c, /* subc. freq. */ + 0x03, 0x8c, /* subc. freq. */ + 0x04, 0x79, /* subc. freq. */ + 0x05, 0x26, /* subc. freq. */ + 0x06, 0x40, /* subc. phase */ + + 0x07, TR0MODE, /* TR0, 16bit */ + 0x08, 0x21, /* */ + 0x09, 0x00, /* */ + 0x0a, 0x00, /* */ + 0x0b, 0x00, /* */ + 0x0c, TR1CAPT, /* TR1 */ + 0x0d, 0x4f, /* MR2 */ + 0x0e, 0x00, /* */ + 0x0f, 0x00, /* */ + 0x10, 0x00, /* */ + 0x11, 0x00, /* */ + 0x12, 0x00, /* MR3 */ + 0x24, 0x00, /* */ +}; + +static const unsigned char init_pal[] = { + 0x00, MR050, /* MR0, PAL enabled */ + 0x01, 0x00, /* MR1 */ + 0x02, 0x0c, /* subc. freq. */ + 0x03, 0x8c, /* subc. freq. */ + 0x04, 0x79, /* subc. freq. */ + 0x05, 0x26, /* subc. freq. */ + 0x06, 0x40, /* subc. phase */ +}; + +static const unsigned char init_ntsc[] = { + 0x00, MR060, /* MR0, NTSC enabled */ + 0x01, 0x00, /* MR1 */ + 0x02, 0x55, /* subc. freq. */ + 0x03, 0x55, /* subc. freq. */ + 0x04, 0x55, /* subc. freq. */ + 0x05, 0x25, /* subc. freq. */ + 0x06, 0x1a, /* subc. phase */ +}; + +static int adv7175_attach(struct i2c_device *device) +{ + int i; + struct adv7175 *encoder; + char *dname; + + MOD_INC_USE_COUNT; + + device->data = encoder = kmalloc(sizeof(struct adv7175), GFP_KERNEL); + if (encoder == NULL) { + MOD_DEC_USE_COUNT; + return -ENOMEM; + } + + + memset(encoder, 0, sizeof(struct adv7175)); + if ((device->addr == I2C_ADV7175) || (device->addr == (I2C_ADV7175 + 2))) { + dname = adv7175_name; + } else if ((device->addr == I2C_ADV7176) || (device->addr == (I2C_ADV7176 + 2))) { + dname = adv7176_name; + } else { + // We should never get here!!! + dname = unknown_name; + } + strcpy(device->name, dname); + encoder->bus = device->bus; + encoder->addr = device->addr; + encoder->norm = VIDEO_MODE_PAL; + encoder->input = 0; + encoder->enable = 1; + + i = adv7175_write_block(encoder, init_common, sizeof(init_common)); + if (i >= 0) { + i = adv7175_write(encoder, 0x07, TR0MODE | TR0RST); + i = adv7175_write(encoder, 0x07, TR0MODE); + i = adv7175_read(encoder, 0x12); + printk(KERN_INFO "%s_attach: %s rev. %d at 0x%02x\n", + device->name, dname, i & 1, device->addr); + } + if (i < 0) { + printk(KERN_ERR "%s_attach: init error %d\n", device->name, + i); + } + + return 0; +} + + +static int adv7175_detach(struct i2c_device *device) +{ + kfree(device->data); + MOD_DEC_USE_COUNT; + return 0; +} + +static int adv7175_command(struct i2c_device *device, unsigned int cmd, + void *arg) +{ + struct adv7175 *encoder = device->data; + + switch (cmd) { + + case ENCODER_GET_CAPABILITIES: + { + struct video_encoder_capability *cap = arg; + + cap->flags = VIDEO_ENCODER_PAL | VIDEO_ENCODER_NTSC + // | VIDEO_ENCODER_SECAM + // | VIDEO_ENCODER_CCIR + ; + cap->inputs = 2; + cap->outputs = 1; + } + break; + + case ENCODER_SET_NORM: + { + int iarg = *(int *) arg; + + if (encoder->norm != iarg) { + switch (iarg) { + + case VIDEO_MODE_NTSC: + adv7175_write_block(encoder, + init_ntsc, + sizeof + (init_ntsc)); + if (encoder->input == 0) + adv7175_write(encoder, 0x0d, 0x4f); // Enable genlock + adv7175_write(encoder, 0x07, + TR0MODE | TR0RST); + adv7175_write(encoder, 0x07, + TR0MODE); + break; + + case VIDEO_MODE_PAL: + adv7175_write_block(encoder, + init_pal, + sizeof + (init_pal)); + if (encoder->input == 0) + adv7175_write(encoder, 0x0d, 0x4f); // Enable genlock + adv7175_write(encoder, 0x07, + TR0MODE | TR0RST); + adv7175_write(encoder, 0x07, + TR0MODE); + break; + + case VIDEO_MODE_SECAM: // WARNING! ADV7176 does not support SECAM. + // This is an attempt to convert SECAM->PAL (typically + // it does not work due to genlock: when decoder + // is in SECAM and encoder in in PAL the subcarrier + // can not be syncronized with horizontal frequency) + adv7175_write_block(encoder, + init_pal, + sizeof + (init_pal)); + if (encoder->input == 0) + adv7175_write(encoder, 0x0d, 0x49); // Disable genlock + adv7175_write(encoder, 0x07, + TR0MODE | TR0RST); + adv7175_write(encoder, 0x07, + TR0MODE); + break; + default: + printk(KERN_ERR + "%s: illegal norm: %d\n", + device->name, iarg); + return -EINVAL; + + } + DEBUG(printk + (KERN_INFO "%s: switched to %s\n", + device->name, norms[iarg])); + encoder->norm = iarg; + } + } + break; + + case ENCODER_SET_INPUT: + { + int iarg = *(int *) arg; + + /* RJ: *iarg = 0: input is from SAA7110 + *iarg = 1: input is from ZR36060 + *iarg = 2: color bar */ + + if (encoder->input != iarg) { + switch (iarg) { + + case 0: + adv7175_write(encoder, 0x01, 0x00); + adv7175_write(encoder, 0x0c, TR1CAPT); /* TR1 */ + if (encoder->norm == + VIDEO_MODE_SECAM) + adv7175_write(encoder, 0x0d, 0x49); // Disable genlock + else + adv7175_write(encoder, 0x0d, 0x4f); // Enable genlock + adv7175_write(encoder, 0x07, + TR0MODE | TR0RST); + adv7175_write(encoder, 0x07, + TR0MODE); + //udelay(10); + break; + + case 1: + adv7175_write(encoder, 0x01, 0x00); + adv7175_write(encoder, 0x0c, TR1PLAY); /* TR1 */ + adv7175_write(encoder, 0x0d, 0x49); + adv7175_write(encoder, 0x07, + TR0MODE | TR0RST); + adv7175_write(encoder, 0x07, + TR0MODE); + //udelay(10); + break; + + case 2: + adv7175_write(encoder, 0x01, 0x80); + adv7175_write(encoder, 0x0d, 0x49); + adv7175_write(encoder, 0x07, + TR0MODE | TR0RST); + adv7175_write(encoder, 0x07, + TR0MODE); + //udelay(10); + break; + + default: + printk(KERN_ERR + "%s: illegal input: %d\n", + device->name, iarg); + return -EINVAL; + + } + DEBUG(printk + (KERN_INFO "%s: switched to %s\n", + device->name, inputs[iarg])); + encoder->input = iarg; + } + } + break; + + case ENCODER_SET_OUTPUT: + { + int *iarg = arg; + + /* not much choice of outputs */ + if (*iarg != 0) { + return -EINVAL; + } + } + break; + + case ENCODER_ENABLE_OUTPUT: + { + int *iarg = arg; + + encoder->enable = !!*iarg; + adv7175_write(encoder, 0x61, + (encoder-> + reg[0x61] & 0xbf) | (encoder-> + enable ? 0x00 : + 0x40)); + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static struct i2c_driver i2c_driver_adv7175 = { + "adv7175", /* name */ + I2C_DRIVERID_VIDEOENCODER, /* ID */ + I2C_ADV7175, I2C_ADV7175 + 3, + + adv7175_attach, + adv7175_detach, + adv7175_command +}; + +static struct i2c_driver i2c_driver_adv7176 = { + "adv7175", /* name */ + I2C_DRIVERID_VIDEOENCODER, /* ID */ + I2C_ADV7176, I2C_ADV7176 + 3, + + adv7175_attach, + adv7175_detach, + adv7175_command +}; + +EXPORT_NO_SYMBOLS; + +static int adv7175_init(void) +{ + int res_adv7175 = 0, res_adv7176 = 0; + res_adv7175 = i2c_register_driver(&i2c_driver_adv7175); + res_adv7176 = i2c_register_driver(&i2c_driver_adv7176); + return (res_adv7175 | res_adv7176); // Any idea how to make it better? +} + +static void adv7175_exit(void) +{ + i2c_unregister_driver(&i2c_driver_adv7176); + i2c_unregister_driver(&i2c_driver_adv7175); +} + +module_init(adv7175_init); +module_exit(adv7175_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/bt819.c linux.ac/drivers/media/video/bt819.c --- linux.vanilla/drivers/media/video/bt819.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/media/video/bt819.c Tue Apr 3 17:54:46 2001 @@ -0,0 +1,496 @@ +/* + bt819 - BT819A VideoStream Decoder (Rockwell Part) + + Copyright (C) 1999 Mike Bernson <mike@mlb.org> + Copyright (C) 1998 Dave Perks <dperks@ibm.net> + + Modifications for LML33/DC10plus unified driver + Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> + + This code was modify/ported from the saa7111 driver written + by Dave Perks. + + 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 <linux/module.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/malloc.h> +#include <linux/mm.h> +#include <linux/pci.h> +#include <linux/signal.h> +#include <linux/sched.h> + +#include <linux/videodev.h> + +#include <linux/i2c-old.h> +#include <linux/video_decoder.h> + +#define DEBUG(x) x /* Debug driver */ + +/* ----------------------------------------------------------------------- */ + +struct bt819 { + struct i2c_bus *bus; + int addr; + unsigned char reg[32]; + + int initialized; + int norm; + int input; + int enable; + int bright; + int contrast; + int hue; + int sat; +}; + +struct timing { + int hactive; + int hdelay; + int vactive; + int vdelay; + int hscale; + int vscale; +}; + +struct timing timing_data[] = { + {864 - 24, 2, 623, 1, 0x0504, 0x0000}, + {858 - 24, 2, 523, 1, 0x00f8, 0x0000}, +// { 858-68, 64, 523, 1, 0x00f8, 0x0000 }, +}; + +#define I2C_BT819 0x8a + +#define I2C_DELAY 10 + +/* ----------------------------------------------------------------------- */ + +static int bt819_write(struct bt819 *dev, unsigned char subaddr, + unsigned char data) +{ + int ack; + + LOCK_I2C_BUS(dev->bus); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, data, I2C_DELAY); + dev->reg[subaddr] = data; + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return ack; +} + +static int bt819_setbit(struct bt819 *dev, int subaddr, int bit, int data) +{ + return bt819_write(dev, subaddr, (dev->reg[subaddr] & ~(1 << bit)) | (data ? (1 << bit) : 0)); +} + +static int bt819_write_block(struct bt819 *dev, unsigned const char *data, + unsigned int len) +{ + int ack; + unsigned subaddr; + + ack = 0; + while (len > 1) { + LOCK_I2C_BUS(dev->bus); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, (subaddr = *data++), I2C_DELAY); + ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), + I2C_DELAY); + len -= 2; + while (len > 1 && *data == ++subaddr) { + data++; + ack = + i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); + len -= 2; + } + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + } + return ack; +} + +static int bt819_read(struct bt819 *dev, unsigned char subaddr) +{ + int data; + + LOCK_I2C_BUS(dev->bus); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr | 1, I2C_DELAY); + data = i2c_readbyte(dev->bus, 1); + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return data; +} + +static int bt819_init(struct i2c_device *device) +{ + struct bt819 *decoder; + + static unsigned char init[] = { + //0x1f, 0x00, /* Reset */ + 0x01, 0x59, /* 0x01 input format */ + 0x02, 0x00, /* 0x02 temporal decimation */ + 0x03, 0x12, /* 0x03 Cropping msb */ + 0x04, 0x16, /* 0x04 Vertical Delay, lsb */ + 0x05, 0xe0, /* 0x05 Vertical Active lsb */ + 0x06, 0x80, /* 0x06 Horizontal Delay lsb */ + 0x07, 0xd0, /* 0x07 Horizontal Active lsb */ + 0x08, 0x00, /* 0x08 Horizontal Scaling msb */ + 0x09, 0xf8, /* 0x09 Horizontal Scaling lsb */ + 0x0a, 0x00, /* 0x0a Brightness control */ + 0x0b, 0x30, /* 0x0b Miscellaneous control */ + 0x0c, 0xd8, /* 0x0c Luma Gain lsb */ + 0x0d, 0xfe, /* 0x0d Chroma Gain (U) lsb */ + 0x0e, 0xb4, /* 0x0e Chroma Gain (V) msb */ + 0x0f, 0x00, /* 0x0f Hue control */ + 0x12, 0x04, /* 0x12 Output Format */ + 0x13, 0x20, /* 0x13 Vertial Scaling msb 0x60, */ + 0x14, 0x00, /* 0x14 Vertial Scaling lsb */ + 0x16, 0x04, /* 0x16 Video Timing Polarity 0x02, */ + 0x18, 0x68, /* 0x18 AGC Delay */ + 0x19, 0x5d, /* 0x19 Burst Gate Delay */ + 0x1a, 0x80, /* 0x1a ADC Interface */ + }; + + struct timing *timing; + + decoder = device->data; + timing = &timing_data[decoder->norm]; + + init[3 * 2 - 1] = (((timing->vdelay >> 8) & 0x03) << 6) | + (((timing->vactive >> 8) & 0x03) << 4) | + (((timing->hdelay >> 8) & 0x03) << 2) | + ((timing->hactive >> 8) & 0x03); + init[4 * 2 - 1] = timing->vdelay & 0xff; + init[5 * 2 - 1] = timing->vactive & 0xff; + init[6 * 2 - 1] = timing->hdelay & 0xff; + init[7 * 2 - 1] = timing->hactive & 0xff; + init[8 * 2 - 1] = timing->hscale >> 8; + init[9 * 2 - 1] = timing->hscale & 0xff; + + bt819_write(decoder, 0x1f, 0x00); + mdelay(1); + return bt819_write_block(decoder, init, sizeof(init)); + +} + +/* ----------------------------------------------------------------------- */ + +static int bt819_attach(struct i2c_device *device) +{ + int i; + struct bt819 *decoder; + + MOD_INC_USE_COUNT; + + device->data = decoder = kmalloc(sizeof(struct bt819), GFP_KERNEL); + if (decoder == NULL) { + MOD_DEC_USE_COUNT; + return -ENOMEM; + } + + memset(decoder, 0, sizeof(struct bt819)); + strcpy(device->name, "bt819"); + decoder->bus = device->bus; + decoder->addr = device->addr; + decoder->norm = VIDEO_MODE_NTSC; + decoder->input = 0; + decoder->enable = 1; + decoder->bright = 32768; + decoder->contrast = 32768; + decoder->hue = 32768; + decoder->sat = 32768; + decoder->initialized = 0; + + i = bt819_init(device); + if (i < 0) { + printk(KERN_ERR "%s: bt819_attach: init status %d\n", + decoder->bus->name, i); + } else { + printk(KERN_INFO "%s: bt819_attach: chip version %x\n", + decoder->bus->name, bt819_read(decoder, + 0x17) & 0x0f); + } + return 0; +} + +static int bt819_detach(struct i2c_device *device) +{ + kfree(device->data); + MOD_DEC_USE_COUNT; + return 0; +} + +static int bt819_command(struct i2c_device *device, unsigned int cmd, void *arg) +{ + int temp; + + struct bt819 *decoder = device->data; + //return 0; + + if (!decoder->initialized) { // First call to bt819_init could be + bt819_init(device); // without #FRST = 0 + decoder->initialized = 1; + } + + switch (cmd) { + + case DECODER_GET_CAPABILITIES: + { + struct video_decoder_capability *cap = arg; + + cap->flags + = VIDEO_DECODER_PAL + | VIDEO_DECODER_NTSC | VIDEO_DECODER_CCIR; + cap->inputs = 8; + cap->outputs = 1; + } + break; + + case DECODER_GET_STATUS: + { + int *iarg = arg; + int status; + int res; + + status = bt819_read(decoder, 0x00); + res = 0; + if ((status & 0x80)) { + res |= DECODER_STATUS_GOOD; + } + switch (decoder->norm) { + case VIDEO_MODE_NTSC: + res |= DECODER_STATUS_NTSC; + break; + case VIDEO_MODE_PAL: + res |= DECODER_STATUS_PAL; + break; + default: + case VIDEO_MODE_AUTO: + if ((status & 0x10)) { + res |= DECODER_STATUS_PAL; + } else { + res |= DECODER_STATUS_NTSC; + } + break; + } + res |= DECODER_STATUS_COLOR; + *iarg = res; + + DEBUG(printk(KERN_INFO "%s-bt819: get status %x\n", + decoder->bus->name, *iarg)); + } + break; + + case DECODER_SET_NORM: + { + int *iarg = arg; + struct timing *timing; + + DEBUG(printk(KERN_INFO "%s-bt819: set norm %x\n", + decoder->bus->name, *iarg)); + + if (*iarg == VIDEO_MODE_NTSC) { + bt819_setbit(decoder, 0x01, 0, 1); + bt819_setbit(decoder, 0x01, 1, 0); + bt819_write(decoder, 0x18, 0x68); + bt819_write(decoder, 0x19, 0x5d); + //bt819_setbit(decoder, 0x1a, 5, 1); + timing = &timing_data[VIDEO_MODE_NTSC]; + } else { + bt819_setbit(decoder, 0x01, 0, 1); + bt819_setbit(decoder, 0x01, 1, 1); + bt819_write(decoder, 0x18, 0x7f); + bt819_write(decoder, 0x19, 0x72); + //bt819_setbit(decoder, 0x1a, 5, 0); + timing = &timing_data[VIDEO_MODE_PAL]; + } + + bt819_write(decoder, 0x03, + (((timing->vdelay >> 8) & 0x03) << 6) | + (((timing-> + vactive >> 8) & 0x03) << 4) | + (((timing-> + hdelay >> 8) & 0x03) << 2) | + ((timing->hactive >> 8) & 0x03)); + bt819_write(decoder, 0x04, timing->vdelay & 0xff); + bt819_write(decoder, 0x05, timing->vactive & 0xff); + bt819_write(decoder, 0x06, timing->hdelay & 0xff); + bt819_write(decoder, 0x07, timing->hactive & 0xff); + bt819_write(decoder, 0x08, timing->hscale >> 8); + bt819_write(decoder, 0x09, timing->hscale & 0xff); + decoder->norm = *iarg; + } + break; + + case DECODER_SET_INPUT: + { + int *iarg = arg; + + DEBUG(printk(KERN_INFO "%s-bt819: set input %x\n", + decoder->bus->name, *iarg)); + + if (*iarg < 0 || *iarg > 7) { + return -EINVAL; + } + + if (decoder->input != *iarg) { + decoder->input = *iarg; + /* select mode */ + if (decoder->input == 0) { + bt819_setbit(decoder, 0x0b, 6, 0); + bt819_setbit(decoder, 0x1a, 1, 1); + } else { + bt819_setbit(decoder, 0x0b, 6, 1); + bt819_setbit(decoder, 0x1a, 1, 0); + } + } + } + break; + + case DECODER_SET_OUTPUT: + { + int *iarg = arg; + + DEBUG(printk(KERN_INFO "%s-bt819: set output %x\n", + decoder->bus->name, *iarg)); + + /* not much choice of outputs */ + if (*iarg != 0) { + return -EINVAL; + } + } + break; + + case DECODER_ENABLE_OUTPUT: + { + int *iarg = arg; + int enable = (*iarg != 0); + + DEBUG(printk + (KERN_INFO "%s-bt819: enable output %x\n", + decoder->bus->name, *iarg)); + + if (decoder->enable != enable) { + decoder->enable = enable; + + if (decoder->enable) { + bt819_setbit(decoder, 0x16, 7, 0); + } else { + bt819_setbit(decoder, 0x16, 7, 1); + } + } + } + break; + + case DECODER_SET_PICTURE: + { + struct video_picture *pic = arg; + + DEBUG(printk + (KERN_INFO + "%s-bt819: set picture brightness %d contrast %d colour %d\n", + decoder->bus->name, pic->brightness, + pic->contrast, pic->colour)); + + + if (decoder->bright != pic->brightness) { + /* We want -128 to 127 we get 0-65535 */ + decoder->bright = pic->brightness; + bt819_write(decoder, 0x0a, + (decoder->bright >> 8) - 128); + } + + if (decoder->contrast != pic->contrast) { + /* We want 0 to 511 we get 0-65535 */ + decoder->contrast = pic->contrast; + bt819_write(decoder, 0x0c, + (decoder-> + contrast >> 7) & 0xff); + bt819_setbit(decoder, 0x0b, 2, + ((decoder-> + contrast >> 15) & 0x01)); + } + + if (decoder->sat != pic->colour) { + /* We want 0 to 511 we get 0-65535 */ + decoder->sat = pic->colour; + bt819_write(decoder, 0x0d, + (decoder->sat >> 7) & 0xff); + bt819_setbit(decoder, 0x0b, 1, + ((decoder-> + sat >> 15) & 0x01)); + + temp = (decoder->sat * 201) / 237; + bt819_write(decoder, 0x0e, + (temp >> 7) & 0xff); + bt819_setbit(decoder, 0x0b, 0, + (temp >> 15) & 0x01); + } + + if (decoder->hue != pic->hue) { + /* We want -128 to 127 we get 0-65535 */ + decoder->hue = pic->hue; + bt819_write(decoder, 0x0f, + 128 - (decoder->hue >> 8)); + } + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static struct i2c_driver i2c_driver_bt819 = { + "bt819", /* name */ + I2C_DRIVERID_VIDEODECODER, /* ID */ + I2C_BT819, I2C_BT819 + 1, + + bt819_attach, + bt819_detach, + bt819_command +}; + +EXPORT_NO_SYMBOLS; + +static int bt819_setup(void) +{ + return i2c_register_driver(&i2c_driver_bt819); +} + +static void bt819_exit(void) +{ + i2c_unregister_driver(&i2c_driver_bt819); +} + +module_init(bt819_setup); +module_exit(bt819_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/bt856.c linux.ac/drivers/media/video/bt856.c --- linux.vanilla/drivers/media/video/bt856.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/media/video/bt856.c Tue Apr 3 17:54:46 2001 @@ -0,0 +1,303 @@ +/* + bt856 - BT856A Digital Video Encoder (Rockwell Part) + + Copyright (C) 1999 Mike Bernson <mike@mlb.org> + Copyright (C) 1998 Dave Perks <dperks@ibm.net> + + Modifications for LML33/DC10plus unified driver + Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> + + This code was modify/ported from the saa7111 driver written + by Dave Perks. + + 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 <linux/module.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/malloc.h> +#include <linux/mm.h> +#include <linux/pci.h> +#include <linux/signal.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <linux/sched.h> +#include <asm/segment.h> +#include <linux/types.h> +#include <linux/wrapper.h> + +#include <linux/videodev.h> +#include <linux/version.h> +#include <asm/uaccess.h> + +#include <linux/i2c-old.h> +#include <linux/video_encoder.h> + +#define DEBUG(x) x /* Debug driver */ + +/* ----------------------------------------------------------------------- */ + +struct bt856 { + struct i2c_bus *bus; + int addr; + unsigned char reg[128]; + + int norm; + int enable; + int bright; + int contrast; + int hue; + int sat; +}; + +#define I2C_BT856 0x88 + +#define I2C_DELAY 10 + +/* ----------------------------------------------------------------------- */ + +static int bt856_write(struct bt856 *dev, unsigned char subaddr, + unsigned char data) +{ + int ack; + + LOCK_I2C_BUS(dev->bus); + + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, data, I2C_DELAY); + dev->reg[subaddr] = data; + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return ack; +} + +static int bt856_setbit(struct bt856 *dev, int subaddr, int bit, int data) +{ + return bt856_write(dev, subaddr,(dev->reg[subaddr] & ~(1 << bit)) | (data ? (1 << bit) : 0)); +} + +/* ----------------------------------------------------------------------- */ + +static int bt856_attach(struct i2c_device *device) +{ + struct bt856 *encoder; + + /* This chip is not on the buz card but at the same address saa7185 */ + //if (memcmp(device->bus->name, "buz", 3) == 0 || memcmp(device->bus->name, "zr36057", 6) == 0) + // return 1; + + MOD_INC_USE_COUNT; + device->data = encoder = kmalloc(sizeof(struct bt856), GFP_KERNEL); + + if (encoder == NULL) { + MOD_DEC_USE_COUNT; + return -ENOMEM; + } + + + memset(encoder, 0, sizeof(struct bt856)); + strcpy(device->name, "bt856"); + encoder->bus = device->bus; + encoder->addr = device->addr; + encoder->norm = VIDEO_MODE_NTSC; + encoder->enable = 1; + + DEBUG(printk(KERN_INFO "%s-bt856: attach\n", encoder->bus->name)); + + bt856_write(encoder, 0xdc, 0x18); + bt856_write(encoder, 0xda, 0); + bt856_write(encoder, 0xde, 0); + + bt856_setbit(encoder, 0xdc, 3, 1); + //bt856_setbit(encoder, 0xdc, 6, 0); + bt856_setbit(encoder, 0xdc, 4, 1); + + switch (encoder->norm) { + + case VIDEO_MODE_NTSC: + bt856_setbit(encoder, 0xdc, 2, 0); + break; + + case VIDEO_MODE_PAL: + bt856_setbit(encoder, 0xdc, 2, 1); + break; + } + + bt856_setbit(encoder, 0xdc, 1, 1); + bt856_setbit(encoder, 0xde, 4, 0); + bt856_setbit(encoder, 0xde, 3, 1); + return 0; +} + + +static int bt856_detach(struct i2c_device *device) +{ + kfree(device->data); + MOD_DEC_USE_COUNT; + return 0; +} + +static int bt856_command(struct i2c_device *device, unsigned int cmd, + void *arg) +{ + struct bt856 *encoder = device->data; + + switch (cmd) { + + case ENCODER_GET_CAPABILITIES: + { + struct video_encoder_capability *cap = arg; + + DEBUG(printk + (KERN_INFO "%s-bt856: get capabilities\n", + encoder->bus->name)); + + cap->flags + = VIDEO_ENCODER_PAL + | VIDEO_ENCODER_NTSC | VIDEO_ENCODER_CCIR; + cap->inputs = 2; + cap->outputs = 1; + } + break; + + case ENCODER_SET_NORM: + { + int *iarg = arg; + + DEBUG(printk(KERN_INFO "%s-bt856: set norm %d\n", + encoder->bus->name, *iarg)); + + switch (*iarg) { + + case VIDEO_MODE_NTSC: + bt856_setbit(encoder, 0xdc, 2, 0); + break; + + case VIDEO_MODE_PAL: + bt856_setbit(encoder, 0xdc, 2, 1); + bt856_setbit(encoder, 0xda, 0, 0); + //bt856_setbit(encoder, 0xda, 0, 1); + break; + + default: + return -EINVAL; + + } + encoder->norm = *iarg; + } + break; + + case ENCODER_SET_INPUT: + { + int *iarg = arg; + + DEBUG(printk(KERN_INFO "%s-bt856: set input %d\n", + encoder->bus->name, *iarg)); + + /* We only have video bus. + *iarg = 0: input is from bt819 + *iarg = 1: input is from ZR36060 */ + + switch (*iarg) { + + case 0: + bt856_setbit(encoder, 0xde, 4, 0); + bt856_setbit(encoder, 0xde, 3, 1); + bt856_setbit(encoder, 0xdc, 3, 1); + bt856_setbit(encoder, 0xdc, 6, 0); + break; + case 1: + bt856_setbit(encoder, 0xde, 4, 0); + bt856_setbit(encoder, 0xde, 3, 1); + bt856_setbit(encoder, 0xdc, 3, 1); + bt856_setbit(encoder, 0xdc, 6, 1); + break; + case 2: // Color bar + bt856_setbit(encoder, 0xdc, 3, 0); + bt856_setbit(encoder, 0xde, 4, 1); + break; + default: + return -EINVAL; + + } + } + break; + + case ENCODER_SET_OUTPUT: + { + int *iarg = arg; + + DEBUG(printk(KERN_INFO "%s-bt856: set output %d\n", + encoder->bus->name, *iarg)); + + /* not much choice of outputs */ + if (*iarg != 0) { + return -EINVAL; + } + } + break; + + case ENCODER_ENABLE_OUTPUT: + { + int *iarg = arg; + + encoder->enable = !!*iarg; + + DEBUG(printk + (KERN_INFO "%s-bt856: enable output %d\n", + encoder->bus->name, encoder->enable)); + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static struct i2c_driver i2c_driver_bt856 = { + "bt856", /* name */ + I2C_DRIVERID_VIDEOENCODER, /* ID */ + I2C_BT856, I2C_BT856 + 1, + bt856_attach, + bt856_detach, + bt856_command +}; + +EXPORT_NO_SYMBOLS; + +static int bt856_init(void) +{ + return i2c_register_driver(&i2c_driver_bt856); +} + +static void bt856_exit(void) +{ + i2c_unregister_driver(&i2c_driver_bt856); +} + +module_init(bt856_init); +module_exit(bt856_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/bttv-cards.c linux.ac/drivers/media/video/bttv-cards.c --- linux.vanilla/drivers/media/video/bttv-cards.c Mon Feb 19 22:43:36 2001 +++ linux.ac/drivers/media/video/bttv-cards.c Thu Apr 12 12:03:34 2001 @@ -1404,7 +1404,7 @@ bits_out = (PT2254_DBS_IN_2>>(vol%5)); /* tens */ bits_out |= (PT2254_DBS_IN_10>>(vol/5)); - bits_out |= PT2254_L_CHANEL | PT2254_R_CHANEL; + bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL; data = btread(BT848_GPIO_DATA); data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| WINVIEW_PT2254_STROBE); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/bttv.h linux.ac/drivers/media/video/bttv.h --- linux.vanilla/drivers/media/video/bttv.h Tue Apr 3 17:32:08 2001 +++ linux.ac/drivers/media/video/bttv.h Tue Apr 17 18:11:26 2001 @@ -91,8 +91,8 @@ #define I2C_DPL3518 0x84 /* more card-specific defines */ -#define PT2254_L_CHANEL 0x10 -#define PT2254_R_CHANEL 0x08 +#define PT2254_L_CHANNEL 0x10 +#define PT2254_R_CHANNEL 0x08 #define PT2254_DBS_IN_2 0x400 #define PT2254_DBS_IN_10 0x20000 #define WINVIEW_PT2254_CLK 0x40 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/buz.c linux.ac/drivers/media/video/buz.c --- linux.vanilla/drivers/media/video/buz.c Tue Apr 3 17:32:08 2001 +++ linux.ac/drivers/media/video/buz.c Thu Jan 1 01:00:00 1970 @@ -1,3463 +0,0 @@ -/* - buz - Iomega Buz driver version 1.0 - - Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de> - - based on - - buz.0.0.3 Copyright (C) 1998 Dave Perks <dperks@ibm.net> - - and - - bttv - Bt848 frame grabber driver - - Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - & Marcus Metzler (mocm@thp.uni-koeln.de) - - 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 <linux/module.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/pci.h> -#include <linux/signal.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/page.h> -#include <linux/sched.h> -#include <asm/segment.h> -#include <linux/types.h> -#include <linux/wrapper.h> -#include <linux/spinlock.h> -#include <linux/vmalloc.h> - -#include <linux/videodev.h> - -#include <linux/version.h> -#include <asm/uaccess.h> - -#include <linux/i2c-old.h> -#include "buz.h" -#include <linux/video_decoder.h> -#include <linux/video_encoder.h> - -#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | /* ZR36057_ISR_GIRQ1 | ZR36057_ISR_CodRepIRQ | */ ZR36057_ISR_JPEGRepIRQ ) -#define GPIO_MASK 0xdf - -/* - - BUZ - - GPIO0 = 1, take board out of reset - GPIO1 = 1, take JPEG codec out of sleep mode - GPIO3 = 1, deassert FRAME# to 36060 - - - GIRQ0 signals a vertical sync of the video signal - GIRQ1 signals that ZR36060's DATERR# line is asserted. - - SAA7111A - - In their infinite wisdom, the Iomega engineers decided to - use the same input line for composite and S-Video Color, - although there are two entries not connected at all! - Through this ingenious strike, it is not possible to - keep two running video sources connected at the same time - to Composite and S-VHS input! - - mode 0 - N/C - mode 1 - S-Video Y - mode 2 - noise or something I don't know - mode 3 - Composite and S-Video C - mode 4 - N/C - mode 5 - S-Video (gain C independently selectable of gain Y) - mode 6 - N/C - mode 7 - S-Video (gain C adapted to gain Y) - */ - -#define MAJOR_VERSION 1 /* driver major version */ -#define MINOR_VERSION 0 /* driver minor version */ - -#define BUZ_NAME "Iomega BUZ V-1.0" /* name of the driver */ - -#define DEBUG(x) /* Debug driver */ -#define IDEBUG(x) /* Debug interrupt handler */ -#define IOCTL_DEBUG(x) - - -/* The parameters for this driver */ - -/* - The video mem address of the video card. - The driver has a little database for some videocards - to determine it from there. If your video card is not in there - you have either to give it to the driver as a parameter - or set in in a VIDIOCSFBUF ioctl - */ - -static unsigned long vidmem; /* Video memory base address (default 0) */ - -/* Special purposes only: */ - -static int triton; /* 0=no (default), 1=yes */ -static int natoma; /* 0=no (default), 1=yes */ - -/* - Number and size of grab buffers for Video 4 Linux - The vast majority of applications should not need more than 2, - the very popular BTTV driver actually does ONLY have 2. - Time sensitive applications might need more, the maximum - is VIDEO_MAX_FRAME (defined in <linux/videodev.h>). - - The size is set so that the maximum possible request - can be satisfied. Decrease it, if bigphys_area alloc'd - memory is low. If you don't have the bigphys_area patch, - set it to 128 KB. Will you allow only to grab small - images with V4L, but that's better than nothing. - - v4l_bufsize has to be given in KB ! - - */ - -static int v4l_nbufs = 2; -static int v4l_bufsize = 128; /* Everybody should be able to work with this setting */ - -/* - Default input and video norm at startup of the driver. - */ - -static int default_input; /* 0=Composite (default), 1=S-VHS */ -static int default_norm; /* 0=PAL (default), 1=NTSC */ - -MODULE_PARM(vidmem, "i"); -MODULE_PARM(triton, "i"); -MODULE_PARM(natoma, "i"); -MODULE_PARM(v4l_nbufs, "i"); -MODULE_PARM(v4l_bufsize, "i"); -MODULE_PARM(default_input, "i"); -MODULE_PARM(default_norm, "i"); - -/* Anybody who uses more than four? */ -#define BUZ_MAX 4 - -static int zoran_num; /* number of Buzs in use */ -static struct zoran zoran[BUZ_MAX]; - -/* forward references */ - -static void v4l_fbuffer_free(struct zoran *zr); -static void jpg_fbuffer_free(struct zoran *zr); -static void zoran_feed_stat_com(struct zoran *zr); - - - -/* - * Allocate the V4L grab buffers - * - * These have to be pysically contiguous. - * If v4l_bufsize <= KMALLOC_MAXSIZE we use kmalloc - */ - -static int v4l_fbuffer_alloc(struct zoran *zr) -{ - int i, off; - unsigned char *mem; - - for (i = 0; i < v4l_nbufs; i++) { - if (zr->v4l_gbuf[i].fbuffer) - printk(KERN_WARNING "%s: v4l_fbuffer_alloc: buffer %d allready allocated ?\n", zr->name, i); - - if (v4l_bufsize <= KMALLOC_MAXSIZE) { - /* Use kmalloc */ - - mem = (unsigned char *) kmalloc(v4l_bufsize, GFP_KERNEL); - if (mem == 0) { - printk(KERN_ERR "%s: kmalloc for V4L bufs failed\n", zr->name); - v4l_fbuffer_free(zr); - return -ENOBUFS; - } - zr->v4l_gbuf[i].fbuffer = mem; - zr->v4l_gbuf[i].fbuffer_phys = virt_to_phys(mem); - zr->v4l_gbuf[i].fbuffer_bus = virt_to_bus(mem); - for (off = 0; off < v4l_bufsize; off += PAGE_SIZE) - mem_map_reserve(virt_to_page(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; - } - } - - return 0; -} - -/* free the V4L grab buffers */ -static void v4l_fbuffer_free(struct zoran *zr) -{ - int i, off; - unsigned char *mem; - - for (i = 0; i < v4l_nbufs; i++) { - if (!zr->v4l_gbuf[i].fbuffer) - continue; - - mem = zr->v4l_gbuf[i].fbuffer; - for (off = 0; off < v4l_bufsize; off += PAGE_SIZE) - mem_map_unreserve(virt_to_page(mem + off)); - kfree((void *) zr->v4l_gbuf[i].fbuffer); - zr->v4l_gbuf[i].fbuffer = NULL; - } -} - -/* - * Allocate the MJPEG grab buffers. - * - * If the requested buffer size is smaller than KMALLOC_MAXSIZE, - * kmalloc is used to request a physically contiguous area, - * else we allocate the memory in framgents with get_free_page. - * - * If a Natoma chipset is present and this is a revision 1 zr36057, - * each MJPEG buffer needs to be physically contiguous. - * (RJ: This statement is from Dave Perks' original driver, - * I could never check it because I have a zr36067) - * The driver cares about this because it reduces the buffer - * size to KMALLOC_MAXSIZE in that case (which forces contiguous allocation). - * - * RJ: The contents grab buffers needs never be accessed in the driver. - * Therefore there is no need to allocate them with vmalloc in order - * to get a contiguous virtual memory space. - * I don't understand why many other drivers first allocate them with - * vmalloc (which uses internally also get_free_page, but delivers you - * virtual addresses) and then again have to make a lot of efforts - * to get the physical address. - * - */ - -static int jpg_fbuffer_alloc(struct zoran *zr) -{ - int i, j, off, alloc_contig; - unsigned long mem; - - /* Decide if we should alloc contiguous or fragmented memory */ - /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */ - - alloc_contig = (zr->jpg_bufsize < KMALLOC_MAXSIZE); - - for (i = 0; i < zr->jpg_nbufs; i++) { - if (zr->jpg_gbuf[i].frag_tab) - printk(KERN_WARNING "%s: jpg_fbuffer_alloc: buffer %d allready allocated ???\n", zr->name, i); - - /* Allocate fragment table for this buffer */ - - mem = get_free_page(GFP_KERNEL); - if (mem == 0) { - printk(KERN_ERR "%s: jpg_fbuffer_alloc: get_free_page (frag_tab) failed for buffer %d\n", zr->name, i); - jpg_fbuffer_free(zr); - return -ENOBUFS; - } - memset((void *) mem, 0, PAGE_SIZE); - zr->jpg_gbuf[i].frag_tab = (u32 *) mem; - zr->jpg_gbuf[i].frag_tab_bus = virt_to_bus((void *) mem); - - if (alloc_contig) { - mem = (unsigned long) kmalloc(zr->jpg_bufsize, GFP_KERNEL); - if (mem == 0) { - jpg_fbuffer_free(zr); - return -ENOBUFS; - } - zr->jpg_gbuf[i].frag_tab[0] = virt_to_bus((void *) mem); - zr->jpg_gbuf[i].frag_tab[1] = ((zr->jpg_bufsize / 4) << 1) | 1; - for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE) - mem_map_reserve(virt_to_page(mem + off)); - } else { - /* jpg_bufsize is alreay page aligned */ - for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { - mem = get_free_page(GFP_KERNEL); - if (mem == 0) { - jpg_fbuffer_free(zr); - return -ENOBUFS; - } - zr->jpg_gbuf[i].frag_tab[2 * j] = virt_to_bus((void *) mem); - zr->jpg_gbuf[i].frag_tab[2 * j + 1] = (PAGE_SIZE / 4) << 1; - mem_map_reserve(virt_to_page(mem)); - } - - zr->jpg_gbuf[i].frag_tab[2 * j - 1] |= 1; - } - } - - DEBUG(printk("jpg_fbuffer_alloc: %d KB allocated\n", - (zr->jpg_nbufs * zr->jpg_bufsize) >> 10)); - zr->jpg_buffers_allocated = 1; - return 0; -} - -/* free the MJPEG grab buffers */ -static void jpg_fbuffer_free(struct zoran *zr) -{ - int i, j, off, alloc_contig; - unsigned char *mem; - - /* Decide if we should alloc contiguous or fragmented memory */ - /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */ - - alloc_contig = (zr->jpg_bufsize < KMALLOC_MAXSIZE); - - for (i = 0; i < zr->jpg_nbufs; i++) { - if (!zr->jpg_gbuf[i].frag_tab) - continue; - - if (alloc_contig) { - if (zr->jpg_gbuf[i].frag_tab[0]) { - mem = (unsigned char *) bus_to_virt(zr->jpg_gbuf[i].frag_tab[0]); - for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE) - mem_map_unreserve(virt_to_page(mem + off)); - kfree((void *) mem); - zr->jpg_gbuf[i].frag_tab[0] = 0; - zr->jpg_gbuf[i].frag_tab[1] = 0; - } - } else { - for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { - if (!zr->jpg_gbuf[i].frag_tab[2 * j]) - break; - mem_map_unreserve(virt_to_page(bus_to_virt(zr->jpg_gbuf[i].frag_tab[2 * j]))); - free_page((unsigned long) bus_to_virt(zr->jpg_gbuf[i].frag_tab[2 * j])); - zr->jpg_gbuf[i].frag_tab[2 * j] = 0; - zr->jpg_gbuf[i].frag_tab[2 * j + 1] = 0; - } - } - - free_page((unsigned long) zr->jpg_gbuf[i].frag_tab); - zr->jpg_gbuf[i].frag_tab = NULL; - } - zr->jpg_buffers_allocated = 0; -} - - -/* ----------------------------------------------------------------------- */ - -/* I2C functions */ - -#define I2C_DELAY 10 - - -/* software I2C functions */ - -static void i2c_setlines(struct i2c_bus *bus, int ctrl, int data) -{ - struct zoran *zr = (struct zoran *) bus->data; - btwrite((data << 1) | ctrl, ZR36057_I2CBR); - btread(ZR36057_I2CBR); - udelay(I2C_DELAY); -} - -static int i2c_getdataline(struct i2c_bus *bus) -{ - struct zoran *zr = (struct zoran *) bus->data; - return (btread(ZR36057_I2CBR) >> 1) & 1; -} - -static void attach_inform(struct i2c_bus *bus, int id) -{ - DEBUG(struct zoran *zr = (struct zoran *) bus->data); - DEBUG(printk(BUZ_DEBUG "-%u: i2c attach %02x\n", zr->id, id)); -} - -static void detach_inform(struct i2c_bus *bus, int id) -{ - DEBUG(struct zoran *zr = (struct zoran *) bus->data); - DEBUG(printk(BUZ_DEBUG "-%u: i2c detach %02x\n", zr->id, id)); -} - -static struct i2c_bus zoran_i2c_bus_template = { - name: "zr36057", - id: I2C_BUSID_BT848, - bus_lock: SPIN_LOCK_UNLOCKED, - - attach_inform: attach_inform, - detach_inform: detach_inform, - - i2c_setlines: i2c_setlines, - i2c_getdataline: i2c_getdataline, -}; - - -/* ----------------------------------------------------------------------- */ - -static void GPIO(struct zoran *zr, unsigned bit, unsigned value) -{ - u32 reg; - u32 mask; - - mask = 1 << (24 + bit); - reg = btread(ZR36057_GPPGCR1) & ~mask; - if (value) { - reg |= mask; - } - btwrite(reg, ZR36057_GPPGCR1); - /* Stop any PCI posting on the GPIO bus */ - btread(ZR36057_I2CBR); -} - - -/* - * Set the registers for the size we have specified. Don't bother - * trying to understand this without the ZR36057 manual in front of - * you [AC]. - * - * PS: The manual is free for download in .pdf format from - * www.zoran.com - nicely done those folks. - */ - -struct tvnorm { - u16 Wt, Wa, Ht, Ha, HStart, VStart; -}; - -static struct tvnorm tvnorms[] = -{ - /* PAL-BDGHI */ - {864, 720, 625, 576, 31, 16}, - /* NTSC */ - {858, 720, 525, 480, 21, 8}, -}; -#define TVNORMS (sizeof(tvnorms) / sizeof(tvnorm)) - -static int format2bpp(int format) -{ - int bpp; - - /* Determine the number of bytes per pixel for the video format requested */ - - switch (format) { - - case VIDEO_PALETTE_YUV422: - bpp = 2; - break; - - case VIDEO_PALETTE_RGB555: - bpp = 2; - break; - - case VIDEO_PALETTE_RGB565: - bpp = 2; - break; - - case VIDEO_PALETTE_RGB24: - bpp = 3; - break; - - case VIDEO_PALETTE_RGB32: - bpp = 4; - break; - - default: - bpp = 0; - } - - return bpp; -} - -/* - * set geometry - */ -static void zr36057_set_vfe(struct zoran *zr, int video_width, int video_height, - unsigned int video_format) -{ - struct tvnorm *tvn; - unsigned HStart, HEnd, VStart, VEnd; - unsigned DispMode; - unsigned VidWinWid, VidWinHt; - unsigned hcrop1, hcrop2, vcrop1, vcrop2; - unsigned Wa, We, Ha, He; - unsigned X, Y, HorDcm, VerDcm; - u32 reg; - unsigned mask_line_size; - - if (zr->params.norm < 0 || zr->params.norm > 1) { - printk(KERN_ERR "%s: set_vfe: video_norm = %d not valid\n", zr->name, zr->params.norm); - return; - } - if (video_width < BUZ_MIN_WIDTH || video_height < BUZ_MIN_HEIGHT) { - printk(KERN_ERR "%s: set_vfe: w=%d h=%d not valid\n", zr->name, video_width, video_height); - return; - } - tvn = &tvnorms[zr->params.norm]; - - Wa = tvn->Wa; - Ha = tvn->Ha; - - /* if window has more than half of active height, - switch on interlacing - we want the full information */ - - zr->video_interlace = (video_height > Ha / 2); - -/**** zr36057 ****/ - - /* horizontal */ - VidWinWid = video_width; - X = (VidWinWid * 64 + tvn->Wa - 1) / tvn->Wa; - We = (VidWinWid * 64) / X; - HorDcm = 64 - X; - hcrop1 = 2 * ((tvn->Wa - We) / 4); - hcrop2 = tvn->Wa - We - hcrop1; - HStart = tvn->HStart | 1; - HEnd = HStart + tvn->Wa - 1; - HStart += hcrop1; - HEnd -= hcrop2; - reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart) - | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd); - reg |= ZR36057_VFEHCR_HSPol; - btwrite(reg, ZR36057_VFEHCR); - - /* Vertical */ - DispMode = !zr->video_interlace; - VidWinHt = DispMode ? video_height : video_height / 2; - Y = (VidWinHt * 64 * 2 + tvn->Ha - 1) / tvn->Ha; - He = (VidWinHt * 64) / Y; - VerDcm = 64 - Y; - vcrop1 = (tvn->Ha / 2 - He) / 2; - vcrop2 = tvn->Ha / 2 - He - vcrop1; - VStart = tvn->VStart; - VEnd = VStart + tvn->Ha / 2 - 1; - VStart += vcrop1; - VEnd -= vcrop2; - reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart) - | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd); - reg |= ZR36057_VFEVCR_VSPol; - btwrite(reg, ZR36057_VFEVCR); - - /* scaler and pixel format */ - reg = 0 // ZR36057_VFESPFR_ExtFl /* Trying to live without ExtFl */ - | (HorDcm << ZR36057_VFESPFR_HorDcm) - | (VerDcm << ZR36057_VFESPFR_VerDcm) - | (DispMode << ZR36057_VFESPFR_DispMode) - | ZR36057_VFESPFR_LittleEndian; - /* RJ: I don't know, why the following has to be the opposite - of the corresponding ZR36060 setting, but only this way - we get the correct colors when uncompressing to the screen */ - reg |= ZR36057_VFESPFR_VCLKPol; - /* RJ: Don't know if that is needed for NTSC also */ - reg |= ZR36057_VFESPFR_TopField; - switch (video_format) { - - case VIDEO_PALETTE_YUV422: - reg |= ZR36057_VFESPFR_YUV422; - break; - - case VIDEO_PALETTE_RGB555: - reg |= ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ErrDif; - break; - - case VIDEO_PALETTE_RGB565: - reg |= ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ErrDif; - break; - - case VIDEO_PALETTE_RGB24: - reg |= ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_Pack24; - break; - - case VIDEO_PALETTE_RGB32: - reg |= ZR36057_VFESPFR_RGB888; - break; - - default: - printk(KERN_INFO "%s: Unknown color_fmt=%x\n", zr->name, video_format); - return; - - } - if (HorDcm >= 48) { - reg |= 3 << ZR36057_VFESPFR_HFilter; /* 5 tap filter */ - } else if (HorDcm >= 32) { - reg |= 2 << ZR36057_VFESPFR_HFilter; /* 4 tap filter */ - } else if (HorDcm >= 16) { - reg |= 1 << ZR36057_VFESPFR_HFilter; /* 3 tap filter */ - } - btwrite(reg, ZR36057_VFESPFR); - - /* display configuration */ - - reg = (16 << ZR36057_VDCR_MinPix) - | (VidWinHt << ZR36057_VDCR_VidWinHt) - | (VidWinWid << ZR36057_VDCR_VidWinWid); - if (triton) - reg &= ~ZR36057_VDCR_Triton; - else - reg |= ZR36057_VDCR_Triton; - btwrite(reg, ZR36057_VDCR); - - /* Write overlay clipping mask data, but don't enable overlay clipping */ - /* RJ: since this makes only sense on the screen, we use - zr->window.width instead of video_width */ - - mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; - reg = virt_to_bus(zr->overlay_mask); - btwrite(reg, ZR36057_MMTR); - reg = virt_to_bus(zr->overlay_mask + mask_line_size); - btwrite(reg, ZR36057_MMBR); - reg = mask_line_size - (zr->window.width + 31) / 32; - if (DispMode == 0) - reg += mask_line_size; - reg <<= ZR36057_OCR_MaskStride; - btwrite(reg, ZR36057_OCR); - -} - -/* - * Switch overlay on or off - */ - -static void zr36057_overlay(struct zoran *zr, int on) -{ - int fmt, bpp; - u32 reg; - - if (on) { - /* do the necessary settings ... */ - - btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); /* switch it off first */ - - switch (zr->buffer.depth) { - case 15: - fmt = VIDEO_PALETTE_RGB555; - bpp = 2; - break; - case 16: - fmt = VIDEO_PALETTE_RGB565; - bpp = 2; - break; - case 24: - fmt = VIDEO_PALETTE_RGB24; - bpp = 3; - break; - case 32: - fmt = VIDEO_PALETTE_RGB32; - bpp = 4; - break; - default: - fmt = 0; - bpp = 0; - } - - zr36057_set_vfe(zr, zr->window.width, zr->window.height, fmt); - - /* Start and length of each line MUST be 4-byte aligned. - This should be allready checked before the call to this routine. - All error messages are internal driver checking only! */ - - /* video display top and bottom registers */ - - reg = (u32) zr->buffer.base - + zr->window.x * bpp - + zr->window.y * zr->buffer.bytesperline; - btwrite(reg, ZR36057_VDTR); - if (reg & 3) - printk(KERN_ERR "%s: zr36057_overlay: video_address not aligned\n", zr->name); - if (zr->video_interlace) - reg += zr->buffer.bytesperline; - btwrite(reg, ZR36057_VDBR); - - /* video stride, status, and frame grab register */ - - reg = zr->buffer.bytesperline - zr->window.width * bpp; - if (zr->video_interlace) - reg += zr->buffer.bytesperline; - if (reg & 3) - printk(KERN_ERR "%s: zr36057_overlay: video_stride not aligned\n", zr->name); - reg = (reg << ZR36057_VSSFGR_DispStride); - reg |= ZR36057_VSSFGR_VidOvf; /* clear overflow status */ - btwrite(reg, ZR36057_VSSFGR); - - /* Set overlay clipping */ - - if (zr->window.clipcount) - btor(ZR36057_OCR_OvlEnable, ZR36057_OCR); - - /* ... and switch it on */ - - btor(ZR36057_VDCR_VidEn, ZR36057_VDCR); - } else { - /* Switch it off */ - - btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); - } -} - -/* - * The overlay mask has one bit for each pixel on a scan line, - * and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels. - */ -static void write_overlay_mask(struct zoran *zr, struct video_clip *vp, int count) -{ - unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; - u32 *mask; - int x, y, width, height; - unsigned i, j, k; - u32 reg; - - /* fill mask with one bits */ - memset(zr->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT); - reg = 0; - - for (i = 0; i < count; ++i) { - /* pick up local copy of clip */ - x = vp[i].x; - y = vp[i].y; - width = vp[i].width; - height = vp[i].height; - - /* trim clips that extend beyond the window */ - if (x < 0) { - width += x; - x = 0; - } - if (y < 0) { - height += y; - y = 0; - } - if (x + width > zr->window.width) { - width = zr->window.width - x; - } - if (y + height > zr->window.height) { - height = zr->window.height - y; - } - /* ignore degenerate clips */ - if (height <= 0) { - continue; - } - if (width <= 0) { - continue; - } - /* apply clip for each scan line */ - for (j = 0; j < height; ++j) { - /* reset bit for each pixel */ - /* this can be optimized later if need be */ - mask = zr->overlay_mask + (y + j) * mask_line_size; - for (k = 0; k < width; ++k) { - mask[(x + k) / 32] &= ~((u32) 1 << (x + k) % 32); - } - } - } -} - -/* Enable/Disable uncompressed memory grabbing of the 36057 */ - -static void zr36057_set_memgrab(struct zoran *zr, int mode) -{ - if (mode) { - if (btread(ZR36057_VSSFGR) & (ZR36057_VSSFGR_SnapShot | ZR36057_VSSFGR_FrameGrab)) - printk(KERN_WARNING "%s: zr36057_set_memgrab_on with SnapShot or FrameGrab on ???\n", zr->name); - - /* switch on VSync interrupts */ - - btwrite(IRQ_MASK, ZR36057_ISR); // Clear Interrupts - - btor(ZR36057_ICR_GIRQ0, ZR36057_ICR); - - /* enable SnapShot */ - - btor(ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); - - /* Set zr36057 video front end and enable video */ - -#ifdef XAWTV_HACK - zr36057_set_vfe(zr, zr->gwidth > 720 ? 720 : zr->gwidth, zr->gheight, zr->gformat); -#else - zr36057_set_vfe(zr, zr->gwidth, zr->gheight, zr->gformat); -#endif - - zr->v4l_memgrab_active = 1; - } else { - zr->v4l_memgrab_active = 0; - - /* switch off VSync interrupts */ - - btand(~ZR36057_ICR_GIRQ0, ZR36057_ICR); - - /* reenable grabbing to screen if it was running */ - - if (zr->v4l_overlay_active) { - zr36057_overlay(zr, 1); - } else { - btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); - btand(~ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); - } - } -} - -static int wait_grab_pending(struct zoran *zr) -{ - unsigned long flags; - - /* wait until all pending grabs are finished */ - - if (!zr->v4l_memgrab_active) - return 0; - - while (zr->v4l_pend_tail != zr->v4l_pend_head) { - interruptible_sleep_on(&zr->v4l_capq); - if (signal_pending(current)) - return -ERESTARTSYS; - } - - spin_lock_irqsave(&zr->lock, flags); - zr36057_set_memgrab(zr, 0); - spin_unlock_irqrestore(&zr->lock, flags); - - return 0; -} - -/* - * V4L Buffer grabbing - */ - -static int v4l_grab(struct zoran *zr, struct video_mmap *mp) -{ - unsigned long flags; - int res, bpp; - - /* - * There is a long list of limitations to what is allowed to be grabbed - * We don't output error messages her, since some programs (e.g. xawtv) - * just try several settings to find out what is valid or not. - */ - - /* No grabbing outside the buffer range! */ - - if (mp->frame >= v4l_nbufs || mp->frame < 0) - return -EINVAL; - - /* Check size and format of the grab wanted */ - - if (mp->height < BUZ_MIN_HEIGHT || mp->width < BUZ_MIN_WIDTH) - return -EINVAL; - if (mp->height > BUZ_MAX_HEIGHT || mp->width > BUZ_MAX_WIDTH) - return -EINVAL; - - bpp = format2bpp(mp->format); - if (bpp == 0) - return -EINVAL; - - /* Check against available buffer size */ - - if (mp->height * mp->width * bpp > v4l_bufsize) - return -EINVAL; - - /* The video front end needs 4-byte alinged line sizes */ - - if ((bpp == 2 && (mp->width & 1)) || (bpp == 3 && (mp->width & 3))) - return -EINVAL; - - /* - * To minimize the time spent in the IRQ routine, we avoid setting up - * the video front end there. - * If this grab has different parameters from a running streaming capture - * we stop the streaming capture and start it over again. - */ - - if (zr->v4l_memgrab_active && - (zr->gwidth != mp->width || zr->gheight != mp->height || zr->gformat != mp->format)) { - res = wait_grab_pending(zr); - if (res) - return res; - } - zr->gwidth = mp->width; - zr->gheight = mp->height; - zr->gformat = mp->format; - zr->gbpl = bpp * zr->gwidth; - - - spin_lock_irqsave(&zr->lock, flags); - - /* make sure a grab isn't going on currently with this buffer */ - - switch (zr->v4l_gbuf[mp->frame].state) { - - default: - case BUZ_STATE_PEND: - res = -EBUSY; /* what are you doing? */ - break; - - case BUZ_STATE_USER: - case BUZ_STATE_DONE: - /* since there is at least one unused buffer there's room for at least one more pend[] entry */ - zr->v4l_pend[zr->v4l_pend_head++ & V4L_MASK_FRAME] = mp->frame; - zr->v4l_gbuf[mp->frame].state = BUZ_STATE_PEND; - res = 0; - break; - - } - - /* put the 36057 into frame grabbing mode */ - - if (!res && !zr->v4l_memgrab_active) - zr36057_set_memgrab(zr, 1); - - spin_unlock_irqrestore(&zr->lock, flags); - - return res; -} - -/* - * Sync on a V4L buffer - */ - -static int v4l_sync(struct zoran *zr, int frame) -{ - unsigned long flags; - - - /* check passed-in frame number */ - if (frame >= v4l_nbufs || frame < 0) { - printk(KERN_ERR "%s: v4l_sync: frame %d is invalid\n", zr->name, frame); - return -EINVAL; - } - /* Check if is buffer was queued at all */ - - if (zr->v4l_gbuf[frame].state == BUZ_STATE_USER) { -// printk(KERN_ERR "%s: v4l_sync: Trying to sync on a buffer which was not queued?\n", zr->name); - return -EINVAL; - } - /* wait on this buffer to get ready */ - - while (zr->v4l_gbuf[frame].state == BUZ_STATE_PEND) { - interruptible_sleep_on(&zr->v4l_capq); - if (signal_pending(current)) - return -ERESTARTSYS; - } - - /* buffer should now be in BUZ_STATE_DONE */ - - if (zr->v4l_gbuf[frame].state != BUZ_STATE_DONE) - printk(KERN_ERR "%s: v4l_sync - internal error\n", zr->name); - - /* Check if streaming capture has finished */ - - spin_lock_irqsave(&zr->lock, flags); - - if (zr->v4l_pend_tail == zr->v4l_pend_head) - zr36057_set_memgrab(zr, 0); - - spin_unlock_irqrestore(&zr->lock, flags); - - return 0; -} -/***************************************************************************** - * * - * Set up the Buz-specific MJPEG part * - * * - *****************************************************************************/ - -/* - * Wait til post office is no longer busy - */ - -static int post_office_wait(struct zoran *zr) -{ - u32 por; - u32 ct=0; - - while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) { - ct++; - if(ct>100000) - { - printk(KERN_ERR "%s: timeout on post office.\n", zr->name); - return -1; - } - /* wait for something to happen */ - } - if ((por & ZR36057_POR_POPen) != 0) { - printk(KERN_WARNING "%s: pop pending %08x\n", zr->name, por); - return -1; - } - if ((por & (ZR36057_POR_POTime | ZR36057_POR_POPen)) != 0) { - printk(KERN_WARNING "%s: pop timeout %08x\n", zr->name, por); - return -1; - } - return 0; -} - -static int post_office_write(struct zoran *zr, unsigned guest, unsigned reg, unsigned value) -{ - u32 por; - - post_office_wait(zr); - por = ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16) | (value & 0xFF); - btwrite(por, ZR36057_POR); - return post_office_wait(zr); -} - -static int post_office_read(struct zoran *zr, unsigned guest, unsigned reg) -{ - u32 por; - - post_office_wait(zr); - por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16); - btwrite(por, ZR36057_POR); - if (post_office_wait(zr) < 0) { - return -1; - } - return btread(ZR36057_POR) & 0xFF; -} - -static int zr36060_write_8(struct zoran *zr, unsigned reg, unsigned val) -{ - if (post_office_wait(zr) - || post_office_write(zr, 0, 1, reg >> 8) - || post_office_write(zr, 0, 2, reg)) { - return -1; - } - return post_office_write(zr, 0, 3, val); -} - -static int zr36060_write_16(struct zoran *zr, unsigned reg, unsigned val) -{ - if (zr36060_write_8(zr, reg + 0, val >> 8)) { - return -1; - } - return zr36060_write_8(zr, reg + 1, val >> 0); -} - -static int zr36060_write_24(struct zoran *zr, unsigned reg, unsigned val) -{ - if (zr36060_write_8(zr, reg + 0, val >> 16)) { - return -1; - } - return zr36060_write_16(zr, reg + 1, val >> 0); -} - -static int zr36060_write_32(struct zoran *zr, unsigned reg, unsigned val) -{ - if (zr36060_write_16(zr, reg + 0, val >> 16)) { - return -1; - } - return zr36060_write_16(zr, reg + 2, val >> 0); -} - -static u32 zr36060_read_8(struct zoran *zr, unsigned reg) -{ - if (post_office_wait(zr) - || post_office_write(zr, 0, 1, reg >> 8) - || post_office_write(zr, 0, 2, reg)) { - return -1; - } - return post_office_read(zr, 0, 3) & 0xFF; -} - -static int zr36060_reset(struct zoran *zr) -{ - return post_office_write(zr, 3, 0, 0); -} - -static void zr36060_sleep(struct zoran *zr, int sleep) -{ - GPIO(zr, 1, !sleep); -} - - -static void zr36060_set_jpg(struct zoran *zr, enum zoran_codec_mode mode) -{ - struct tvnorm *tvn; - u32 reg; - int size; - - reg = (1 << 0) /* CodeMstr */ - |(0 << 2) /* CFIS=0 */ - |(0 << 6) /* Endian=0 */ - |(0 << 7); /* Code16=0 */ - zr36060_write_8(zr, 0x002, reg); - - switch (mode) { - - case BUZ_MODE_MOTION_DECOMPRESS: - case BUZ_MODE_STILL_DECOMPRESS: - reg = 0x00; /* Codec mode = decompression */ - break; - - case BUZ_MODE_MOTION_COMPRESS: - case BUZ_MODE_STILL_COMPRESS: - default: - reg = 0xa4; /* Codec mode = compression with variable scale factor */ - break; - - } - zr36060_write_8(zr, 0x003, reg); - - reg = 0x00; /* reserved, mbz */ - zr36060_write_8(zr, 0x004, reg); - - reg = 0xff; /* 510 bits/block */ - zr36060_write_8(zr, 0x005, reg); - - /* JPEG markers */ - reg = (zr->params.jpeg_markers) & 0x38; /* DRI, DQT, DHT */ - if (zr->params.COM_len) - reg |= JPEG_MARKER_COM; - if (zr->params.APP_len) - reg |= JPEG_MARKER_APP; - zr36060_write_8(zr, 0x006, reg); - - reg = (0 << 3) /* DATERR=0 */ - |(0 << 2) /* END=0 */ - |(0 << 1) /* EOI=0 */ - |(0 << 0); /* EOAV=0 */ - zr36060_write_8(zr, 0x007, reg); - - /* code volume */ - - /* Target field size in pixels: */ - tvn = &tvnorms[zr->params.norm]; - size = (tvn->Ha / 2) * (tvn->Wa) / (zr->params.HorDcm) / (zr->params.VerDcm); - - /* Target compressed field size in bits: */ - size = size * 16; /* uncompressed size in bits */ - size = size * zr->params.quality / 400; /* quality = 100 is a compression ratio 1:4 */ - - /* Lower limit (arbitrary, 1 KB) */ - if (size < 8192) - size = 8192; - - /* Upper limit: 7/8 of the code buffers */ - if (size * zr->params.field_per_buff > zr->jpg_bufsize * 7) - size = zr->jpg_bufsize * 7 / zr->params.field_per_buff; - - reg = size; - zr36060_write_32(zr, 0x009, reg); - - /* how do we set initial SF as a function of quality parameter? */ - reg = 0x0100; /* SF=1.0 */ - zr36060_write_16(zr, 0x011, reg); - - reg = 0x00ffffff; /* AF=max */ - zr36060_write_24(zr, 0x013, reg); - - reg = 0x0000; /* test */ - zr36060_write_16(zr, 0x024, reg); -} - -static void zr36060_set_video(struct zoran *zr, enum zoran_codec_mode mode) -{ - struct tvnorm *tvn; - u32 reg; - - reg = (0 << 7) /* Video8=0 */ - |(0 << 6) /* Range=0 */ - |(0 << 3) /* FlDet=0 */ - |(1 << 2) /* FlVedge=1 */ - |(0 << 1) /* FlExt=0 */ - |(0 << 0); /* SyncMstr=0 */ - - /* According to ZR36067 documentation, FlDet should correspond - to the odd_even flag of the ZR36067 */ - if (zr->params.odd_even) - reg |= (1 << 3); - - if (mode != BUZ_MODE_STILL_DECOMPRESS) { - /* limit pixels to range 16..235 as per CCIR-601 */ - reg |= (1 << 6); /* Range=1 */ - } - zr36060_write_8(zr, 0x030, reg); - - reg = (0 << 7) /* VCLKPol=0 */ - |(0 << 6) /* PValPol=0 */ - |(1 << 5) /* PoePol=1 */ - |(0 << 4) /* SImgPol=0 */ - |(0 << 3) /* BLPol=0 */ - |(0 << 2) /* FlPol=0 */ - |(0 << 1) /* HSPol=0, sync on falling edge */ - |(1 << 0); /* VSPol=1 */ - zr36060_write_8(zr, 0x031, reg); - - switch (zr->params.HorDcm) { - default: - case 1: - reg = (0 << 0); - break; /* HScale = 0 */ - - case 2: - reg = (1 << 0); - break; /* HScale = 1 */ - - case 4: - reg = (2 << 0); - break; /* HScale = 2 */ - } - if (zr->params.VerDcm == 2) - reg |= (1 << 2); - zr36060_write_8(zr, 0x032, reg); - - reg = 0x80; /* BackY */ - zr36060_write_8(zr, 0x033, reg); - - reg = 0xe0; /* BackU */ - zr36060_write_8(zr, 0x034, reg); - - reg = 0xe0; /* BackV */ - zr36060_write_8(zr, 0x035, reg); - - /* sync generator */ - - tvn = &tvnorms[zr->params.norm]; - - reg = tvn->Ht - 1; /* Vtotal */ - zr36060_write_16(zr, 0x036, reg); - - reg = tvn->Wt - 1; /* Htotal */ - zr36060_write_16(zr, 0x038, reg); - - reg = 6 - 1; /* VsyncSize */ - zr36060_write_8(zr, 0x03a, reg); - - reg = 100 - 1; /* HsyncSize */ - zr36060_write_8(zr, 0x03b, reg); - - reg = tvn->VStart - 1; /* BVstart */ - zr36060_write_8(zr, 0x03c, reg); - - reg += tvn->Ha / 2; /* BVend */ - zr36060_write_16(zr, 0x03e, reg); - - reg = tvn->HStart - 1; /* BHstart */ - zr36060_write_8(zr, 0x03d, reg); - - reg += tvn->Wa; /* BHend */ - zr36060_write_16(zr, 0x040, reg); - - /* active area */ - reg = zr->params.img_y + tvn->VStart; /* Vstart */ - zr36060_write_16(zr, 0x042, reg); - - reg += zr->params.img_height; /* Vend */ - zr36060_write_16(zr, 0x044, reg); - - reg = zr->params.img_x + tvn->HStart; /* Hstart */ - zr36060_write_16(zr, 0x046, reg); - - reg += zr->params.img_width; /* Hend */ - zr36060_write_16(zr, 0x048, reg); - - /* subimage area */ - reg = zr->params.img_y + tvn->VStart; /* SVstart */ - zr36060_write_16(zr, 0x04a, reg); - - reg += zr->params.img_height; /* SVend */ - zr36060_write_16(zr, 0x04c, reg); - - reg = zr->params.img_x + tvn->HStart; /* SHstart */ - zr36060_write_16(zr, 0x04e, reg); - - reg += zr->params.img_width; /* SHend */ - zr36060_write_16(zr, 0x050, reg); -} - -static void zr36060_set_jpg_SOF(struct zoran *zr) -{ - u32 reg; - - - reg = 0xffc0; /* SOF marker */ - zr36060_write_16(zr, 0x060, reg); - - reg = 17; /* SOF length */ - zr36060_write_16(zr, 0x062, reg); - - reg = 8; /* precision 8 bits */ - zr36060_write_8(zr, 0x064, reg); - - reg = zr->params.img_height / zr->params.VerDcm; /* image height */ - zr36060_write_16(zr, 0x065, reg); - - reg = zr->params.img_width / zr->params.HorDcm; /* image width */ - zr36060_write_16(zr, 0x067, reg); - - reg = 3; /* 3 color components */ - zr36060_write_8(zr, 0x069, reg); - - reg = 0x002100; /* Y component */ - zr36060_write_24(zr, 0x06a, reg); - - reg = 0x011101; /* U component */ - zr36060_write_24(zr, 0x06d, reg); - - reg = 0x021101; /* V component */ - zr36060_write_24(zr, 0x070, reg); -} - -static void zr36060_set_jpg_SOS(struct zoran *zr) -{ - u32 reg; - - - reg = 0xffda; /* SOS marker */ - zr36060_write_16(zr, 0x07a, reg); - - reg = 12; /* SOS length */ - zr36060_write_16(zr, 0x07c, reg); - - reg = 3; /* 3 color components */ - zr36060_write_8(zr, 0x07e, reg); - - reg = 0x0000; /* Y component */ - zr36060_write_16(zr, 0x07f, reg); - - reg = 0x0111; /* U component */ - zr36060_write_16(zr, 0x081, reg); - - reg = 0x0211; /* V component */ - zr36060_write_16(zr, 0x083, reg); - - reg = 0x003f00; /* Start, end spectral scans */ - zr36060_write_24(zr, 0x085, reg); -} - -static void zr36060_set_jpg_DRI(struct zoran *zr) -{ - u32 reg; - - - reg = 0xffdd; /* DRI marker */ - zr36060_write_16(zr, 0x0c0, reg); - - reg = 4; /* DRI length */ - zr36060_write_16(zr, 0x0c2, reg); - - reg = 8; /* length in MCUs */ - zr36060_write_16(zr, 0x0c4, reg); -} - -static void zr36060_set_jpg_DQT(struct zoran *zr) -{ - unsigned i; - unsigned adr; - static const u8 dqt[] = - { - 0xff, 0xdb, /* DHT marker */ - 0x00, 0x84, /* DHT length */ - 0x00, /* table ID 0 */ - 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, - 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, - 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, - 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, - 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44, - 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, - 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, - 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, - 0x01, /* table ID 1 */ - 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, - 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 - }; - - /* write fixed quantitization tables */ - adr = 0x0cc; - for (i = 0; i < sizeof(dqt); ++i) { - zr36060_write_8(zr, adr++, dqt[i]); - } -} - -static void zr36060_set_jpg_DHT(struct zoran *zr) -{ - unsigned i; - unsigned adr; - static const u8 dht[] = - { - 0xff, 0xc4, /* DHT marker */ - 0x01, 0xa2, /* DHT length */ - 0x00, /* table class 0, ID 0 */ - 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, /* # codes of length 1..8 */ - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* # codes of length 8..16 */ - 0x00, /* values for codes of length 2 */ - 0x01, 0x02, 0x03, 0x04, 0x05, /* values for codes of length 3 */ - 0x06, /* values for codes of length 4 */ - 0x07, /* values for codes of length 5 */ - 0x08, /* values for codes of length 6 */ - 0x09, /* values for codes of length 7 */ - 0x0a, /* values for codes of length 8 */ - 0x0b, /* values for codes of length 9 */ - 0x01, /* table class 0, ID 1 */ - 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* # codes of length 1..8 */ - 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, /* # codes of length 9..16 */ - 0x00, 0x01, 0x02, /* values for codes of length 2 */ - 0x03, /* values for codes of length 3 */ - 0x04, /* values for codes of length 4 */ - 0x05, /* values for codes of length 5 */ - 0x06, /* values for codes of length 6 */ - 0x07, /* values for codes of length 7 */ - 0x08, /* values for codes of length 8 */ - 0x09, /* values for codes of length 9 */ - 0x0a, /* values for codes of length 10 */ - 0x0b, /* values for codes of length 11 */ - 0x10, - 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, - 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, - 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, - 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, - 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, - 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, - 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, - 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, - 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, - 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, - 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, - 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, - 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, - 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, - 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, - 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, - 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, - 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, - 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, - 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, - 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, - 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, - 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, - 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, - 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, - 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, - 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, - 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, - 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, - 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, - 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, - 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, - 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, - 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, - 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, - 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, - 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, - 0xf6, 0xf7, 0xf8, 0xf9, 0xfa - }; - - /* write fixed Huffman tables */ - adr = 0x1d4; - for (i = 0; i < sizeof(dht); ++i) { - zr36060_write_8(zr, adr++, dht[i]); - } -} - -static void zr36060_set_jpg_APP(struct zoran *zr) -{ - unsigned adr; - int len, i; - u32 reg; - - - len = zr->params.APP_len; - if (len < 0) - len = 0; - if (len > 60) - len = 60; - - i = zr->params.APPn; - if (i < 0) - i = 0; - if (i > 15) - i = 15; - - reg = 0xffe0 + i; /* APPn marker */ - zr36060_write_16(zr, 0x380, reg); - - reg = len + 2; /* APPn len */ - zr36060_write_16(zr, 0x382, reg); - - /* write APPn data */ - adr = 0x384; - for (i = 0; i < 60; i++) { - zr36060_write_8(zr, adr++, (i < len ? zr->params.APP_data[i] : 0)); - } -} - -static void zr36060_set_jpg_COM(struct zoran *zr) -{ - unsigned adr; - int len, i; - u32 reg; - - - len = zr->params.COM_len; - if (len < 0) - len = 0; - if (len > 60) - len = 60; - - reg = 0xfffe; /* COM marker */ - zr36060_write_16(zr, 0x3c0, reg); - - reg = len + 2; /* COM len */ - zr36060_write_16(zr, 0x3c2, reg); - - /* write COM data */ - adr = 0x3c4; - for (i = 0; i < 60; i++) { - zr36060_write_8(zr, adr++, (i < len ? zr->params.COM_data[i] : 0)); - } -} - -static void zr36060_set_cap(struct zoran *zr, enum zoran_codec_mode mode) -{ - unsigned i; - u32 reg; - - zr36060_reset(zr); - mdelay(10); - - reg = (0 << 7) /* Load=0 */ - |(1 << 0); /* SynRst=1 */ - zr36060_write_8(zr, 0x000, reg); - - zr36060_set_jpg(zr, mode); - zr36060_set_video(zr, mode); - zr36060_set_jpg_SOF(zr); - zr36060_set_jpg_SOS(zr); - zr36060_set_jpg_DRI(zr); - zr36060_set_jpg_DQT(zr); - zr36060_set_jpg_DHT(zr); - zr36060_set_jpg_APP(zr); - zr36060_set_jpg_COM(zr); - - reg = (1 << 7) /* Load=1 */ - |(0 << 0); /* SynRst=0 */ - zr36060_write_8(zr, 0x000, reg); - - /* wait for codec to unbusy */ - for (i = 0; i < 1000; ++i) { - reg = zr36060_read_8(zr, 0x001); - if ((reg & (1 << 7)) == 0) { - DEBUG(printk(KERN_DEBUG "060: loaded, loops=%u\n", i)); - return; - } - udelay(1000); - } - printk(KERN_INFO "060: stuck busy, statux=%02x\n", reg); -} - -static void zr36057_set_jpg(struct zoran *zr, enum zoran_codec_mode mode) -{ - struct tvnorm *tvn; - u32 reg; - int i; - - tvn = &tvnorms[zr->params.norm]; - - /* assert P_Reset */ - btwrite(0, ZR36057_JPC); - - /* re-initialize DMA ring stuff */ - zr->jpg_que_head = 0; - zr->jpg_dma_head = 0; - zr->jpg_dma_tail = 0; - zr->jpg_que_tail = 0; - zr->jpg_seq_num = 0; - for (i = 0; i < BUZ_NUM_STAT_COM; ++i) { - zr->stat_com[i] = 1; /* mark as unavailable to zr36057 */ - } - for (i = 0; i < zr->jpg_nbufs; i++) { - zr->jpg_gbuf[i].state = BUZ_STATE_USER; /* nothing going on */ - } - - /* MJPEG compression mode */ - switch (mode) { - - case BUZ_MODE_MOTION_COMPRESS: - default: - reg = ZR36057_JMC_MJPGCmpMode; - break; - - case BUZ_MODE_MOTION_DECOMPRESS: - reg = ZR36057_JMC_MJPGExpMode; - reg |= ZR36057_JMC_SyncMstr; - /* RJ: The following is experimental - improves the output to screen */ - if (zr->params.VFIFO_FB) - reg |= ZR36057_JMC_VFIFO_FB; - break; - - case BUZ_MODE_STILL_COMPRESS: - reg = ZR36057_JMC_JPGCmpMode; - break; - - case BUZ_MODE_STILL_DECOMPRESS: - reg = ZR36057_JMC_JPGExpMode; - break; - - } - reg |= ZR36057_JMC_JPG; - if (zr->params.field_per_buff == 1) - reg |= ZR36057_JMC_Fld_per_buff; - btwrite(reg, ZR36057_JMC); - - /* vertical */ - btor(ZR36057_VFEVCR_VSPol, ZR36057_VFEVCR); - reg = (6 << ZR36057_VSP_VsyncSize) | (tvn->Ht << ZR36057_VSP_FrmTot); - btwrite(reg, ZR36057_VSP); - reg = ((zr->params.img_y + tvn->VStart) << ZR36057_FVAP_NAY) - | (zr->params.img_height << ZR36057_FVAP_PAY); - btwrite(reg, ZR36057_FVAP); - - /* horizontal */ - btor(ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR); - reg = ((tvn->Wt - 100) << ZR36057_HSP_HsyncStart) | (tvn->Wt << ZR36057_HSP_LineTot); - btwrite(reg, ZR36057_HSP); - reg = ((zr->params.img_x + tvn->HStart) << ZR36057_FHAP_NAX) - | (zr->params.img_width << ZR36057_FHAP_PAX); - btwrite(reg, ZR36057_FHAP); - - /* field process parameters */ - if (zr->params.odd_even) - reg = ZR36057_FPP_Odd_Even; - else - reg = 0; - btwrite(reg, ZR36057_FPP); - - /* Set proper VCLK Polarity, else colors will be wrong during playback */ - btor(ZR36057_VFESPFR_VCLKPol, ZR36057_VFESPFR); - - /* code base address and FIFO threshold */ - reg = virt_to_bus(zr->stat_com); - btwrite(reg, ZR36057_JCBA); - reg = 0x50; - btwrite(reg, ZR36057_JCFT); - - /* JPEG codec guest ID */ - reg = (1 << ZR36057_JCGI_JPEGuestID) | (0 << ZR36057_JCGI_JPEGuestReg); - btwrite(reg, ZR36057_JCGI); - - /* Code transfer guest ID */ - reg = (0 << ZR36057_MCTCR_CodGuestID) | (3 << ZR36057_MCTCR_CodGuestReg); - reg |= ZR36057_MCTCR_CFlush; - btwrite(reg, ZR36057_MCTCR); - - /* deassert P_Reset */ - btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC); -} - -static void zr36057_enable_jpg(struct zoran *zr, enum zoran_codec_mode mode) -{ - static int zero = 0; - static int one = 1; - - switch (mode) { - - case BUZ_MODE_MOTION_COMPRESS: - zr36060_set_cap(zr, mode); - zr36057_set_jpg(zr, mode); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &one); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &zero); - - /* deassert P_Reset, assert Code transfer enable */ - btwrite(IRQ_MASK, ZR36057_ISR); - btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR); - break; - - case BUZ_MODE_MOTION_DECOMPRESS: - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &zero); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &one); - zr36060_set_cap(zr, mode); - zr36057_set_jpg(zr, mode); - - /* deassert P_Reset, assert Code transfer enable */ - btwrite(IRQ_MASK, ZR36057_ISR); - btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR); - break; - - case BUZ_MODE_IDLE: - default: - /* shut down processing */ - btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR); - btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC); - btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC); - btand(~ZR36057_JMC_SyncMstr, ZR36057_JMC); - btand(~ZR36057_JMC_Go_en, ZR36057_JMC); - btwrite(0, ZR36057_ISR); - zr36060_reset(zr); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &one); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &zero); - break; - - } - zr->codec_mode = mode; -} - -/* - * Queue a MJPEG buffer for capture/playback - */ - -static int jpg_qbuf(struct zoran *zr, int frame, enum zoran_codec_mode mode) -{ - unsigned long flags; - int res; - - /* Check if buffers are allocated */ - - if (!zr->jpg_buffers_allocated) { - printk(KERN_ERR "%s: jpg_qbuf: buffers not yet allocated\n", zr->name); - return -ENOMEM; - } - /* Does the user want to stop streaming? */ - - if (frame < 0) { - if (zr->codec_mode == mode) { - zr36057_enable_jpg(zr, BUZ_MODE_IDLE); - return 0; - } else { - printk(KERN_ERR "%s: jpg_qbuf - stop streaming but not in streaming mode\n", zr->name); - return -EINVAL; - } - } - /* No grabbing outside the buffer range! */ - - if (frame >= zr->jpg_nbufs) { - printk(KERN_ERR "%s: jpg_qbuf: buffer %d out of range\n", zr->name, frame); - return -EINVAL; - } - /* what is the codec mode right now? */ - - if (zr->codec_mode == BUZ_MODE_IDLE) { - /* Ok load up the zr36060 and go */ - zr36057_enable_jpg(zr, mode); - } else if (zr->codec_mode != mode) { - /* wrong codec mode active - invalid */ - printk(KERN_ERR "%s: jpg_qbuf - codec in wrong mode\n", zr->name); - return -EINVAL; - } - spin_lock_irqsave(&zr->lock, flags); - - /* make sure a grab isn't going on currently with this buffer */ - - switch (zr->jpg_gbuf[frame].state) { - - default: - case BUZ_STATE_DMA: - case BUZ_STATE_PEND: - case BUZ_STATE_DONE: - res = -EBUSY; /* what are you doing? */ - break; - - case BUZ_STATE_USER: - /* since there is at least one unused buffer there's room for at least one more pend[] entry */ - zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] = frame; - zr->jpg_gbuf[frame].state = BUZ_STATE_PEND; - zoran_feed_stat_com(zr); - res = 0; - break; - - } - - spin_unlock_irqrestore(&zr->lock, flags); - - /* Start the zr36060 when the first frame is queued */ - if (zr->jpg_que_head == 1) { - btor(ZR36057_JMC_Go_en, ZR36057_JMC); - btwrite(ZR36057_JPC_P_Reset | ZR36057_JPC_CodTrnsEn | ZR36057_JPC_Active, ZR36057_JPC); - } - return res; -} - -/* - * Sync on a MJPEG buffer - */ - -static int jpg_sync(struct zoran *zr, struct zoran_sync *bs) -{ - unsigned long flags; - int frame; - - if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS && - zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) { - return -EINVAL; - } - while (zr->jpg_que_tail == zr->jpg_dma_tail) { - interruptible_sleep_on(&zr->jpg_capq); - if (signal_pending(current)) - return -ERESTARTSYS; - } - - spin_lock_irqsave(&zr->lock, flags); - - frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME]; - - /* buffer should now be in BUZ_STATE_DONE */ - - if (zr->jpg_gbuf[frame].state != BUZ_STATE_DONE) - printk(KERN_ERR "%s: jpg_sync - internal error\n", zr->name); - - *bs = zr->jpg_gbuf[frame].bs; - zr->jpg_gbuf[frame].state = BUZ_STATE_USER; - - spin_unlock_irqrestore(&zr->lock, flags); - - return 0; -} - -/* when this is called the spinlock must be held */ -static void zoran_feed_stat_com(struct zoran *zr) -{ - /* move frames from pending queue to DMA */ - - int frame, i, max_stat_com; - - max_stat_com = (zr->params.TmpDcm == 1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1); - - while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com - && zr->jpg_dma_head != zr->jpg_que_head) { - - frame = zr->jpg_pend[zr->jpg_dma_head & BUZ_MASK_FRAME]; - if (zr->params.TmpDcm == 1) { - /* fill 1 stat_com entry */ - i = zr->jpg_dma_head & BUZ_MASK_STAT_COM; - zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus; - } else { - /* fill 2 stat_com entries */ - i = (zr->jpg_dma_head & 1) * 2; - zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus; - zr->stat_com[i + 1] = zr->jpg_gbuf[frame].frag_tab_bus; - } - zr->jpg_gbuf[frame].state = BUZ_STATE_DMA; - zr->jpg_dma_head++; - - } -} - -/* when this is called the spinlock must be held */ -static void zoran_reap_stat_com(struct zoran *zr) -{ - /* move frames from DMA queue to done queue */ - - int i; - u32 stat_com; - unsigned int seq; - unsigned int dif; - int frame; - struct zoran_gbuffer *gbuf; - - /* In motion decompress we don't have a hardware frame counter, - we just count the interrupts here */ - - if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) - zr->jpg_seq_num++; - - while (zr->jpg_dma_tail != zr->jpg_dma_head) { - if (zr->params.TmpDcm == 1) - i = zr->jpg_dma_tail & BUZ_MASK_STAT_COM; - else - i = (zr->jpg_dma_tail & 1) * 2 + 1; - - stat_com = zr->stat_com[i]; - - if ((stat_com & 1) == 0) { - return; - } - frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME]; - gbuf = &zr->jpg_gbuf[frame]; - get_fast_time(&gbuf->bs.timestamp); - - if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { - gbuf->bs.length = (stat_com & 0x7fffff) >> 1; - - /* update sequence number with the help of the counter in stat_com */ - - seq = stat_com >> 24; - dif = (seq - zr->jpg_seq_num) & 0xff; - zr->jpg_seq_num += dif; - } else { - gbuf->bs.length = 0; - } - gbuf->bs.seq = zr->params.TmpDcm == 2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num; - gbuf->state = BUZ_STATE_DONE; - - zr->jpg_dma_tail++; - } -} - -static void zoran_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - u32 stat, astat; - int count; - struct zoran *zr; - unsigned long flags; - - zr = (struct zoran *) dev_id; - count = 0; - - spin_lock_irqsave(&zr->lock, flags); - while (1) { - /* get/clear interrupt status bits */ - stat = btread(ZR36057_ISR); - astat = stat & IRQ_MASK; - if (!astat) { - break; - } - btwrite(astat, ZR36057_ISR); - IDEBUG(printk(BUZ_DEBUG "-%u: astat %08x stat %08x\n", zr->id, astat, stat)); - -#if (IRQ_MASK & ZR36057_ISR_GIRQ0) - if (astat & ZR36057_ISR_GIRQ0) { - - /* Interrupts may still happen when zr->v4l_memgrab_active is switched off. - We simply ignore them */ - - if (zr->v4l_memgrab_active) { - -/* A lot more checks should be here ... */ - if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot) == 0) - printk(KERN_WARNING "%s: BuzIRQ with SnapShot off ???\n", zr->name); - - if (zr->v4l_grab_frame != NO_GRAB_ACTIVE) { - /* There is a grab on a frame going on, check if it has finished */ - - if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_FrameGrab) == 0) { - /* it is finished, notify the user */ - - zr->v4l_gbuf[zr->v4l_grab_frame].state = BUZ_STATE_DONE; - zr->v4l_grab_frame = NO_GRAB_ACTIVE; - zr->v4l_grab_seq++; - zr->v4l_pend_tail++; - } - } - if (zr->v4l_grab_frame == NO_GRAB_ACTIVE) - wake_up_interruptible(&zr->v4l_capq); - - /* Check if there is another grab queued */ - - if (zr->v4l_grab_frame == NO_GRAB_ACTIVE && - zr->v4l_pend_tail != zr->v4l_pend_head) { - - int frame = zr->v4l_pend[zr->v4l_pend_tail & V4L_MASK_FRAME]; - u32 reg; - - zr->v4l_grab_frame = frame; - - /* Set zr36057 video front end and enable video */ - - /* Buffer address */ - - reg = zr->v4l_gbuf[frame].fbuffer_bus; - btwrite(reg, ZR36057_VDTR); - if (zr->video_interlace) - reg += zr->gbpl; - btwrite(reg, ZR36057_VDBR); - - /* video stride, status, and frame grab register */ - -#ifdef XAWTV_HACK - reg = (zr->gwidth > 720) ? ((zr->gwidth & ~3) - 720) * zr->gbpl / zr->gwidth : 0; -#else - reg = 0; -#endif - if (zr->video_interlace) - reg += zr->gbpl; - reg = (reg << ZR36057_VSSFGR_DispStride); - reg |= ZR36057_VSSFGR_VidOvf; - reg |= ZR36057_VSSFGR_SnapShot; - reg |= ZR36057_VSSFGR_FrameGrab; - btwrite(reg, ZR36057_VSSFGR); - - btor(ZR36057_VDCR_VidEn, ZR36057_VDCR); - } - } - } -#endif /* (IRQ_MASK & ZR36057_ISR_GIRQ0) */ - -#if (IRQ_MASK & ZR36057_ISR_GIRQ1) - if (astat & ZR36057_ISR_GIRQ1) { - unsigned csr = zr36060_read_8(zr, 0x001); - unsigned isr = zr36060_read_8(zr, 0x008); - - IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_GIRQ1 60_code=%02x 60_intr=%02x\n", - zr->name, csr, isr)); - - btand(~ZR36057_ICR_GIRQ1, ZR36057_ICR); - zoran_reap_stat_com(zr); - zoran_feed_stat_com(zr); - } -#endif /* (IRQ_MASK & ZR36057_ISR_GIRQ1) */ - -#if (IRQ_MASK & ZR36057_ISR_CodRepIRQ) - if (astat & ZR36057_ISR_CodRepIRQ) { - IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n", zr->name)); - btand(~ZR36057_ICR_CodRepIRQ, ZR36057_ICR); - } -#endif /* (IRQ_MASK & ZR36057_ISR_CodRepIRQ) */ - -#if (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) - if ((astat & ZR36057_ISR_JPEGRepIRQ) && - (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS || - zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)) { - zoran_reap_stat_com(zr); - zoran_feed_stat_com(zr); - wake_up_interruptible(&zr->jpg_capq); - } -#endif /* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */ - - count++; - if (count > 10) { - printk(KERN_WARNING "%s: irq loop %d\n", zr->name, count); - if (count > 20) { - btwrite(0, ZR36057_ICR); - printk(KERN_ERR "%s: IRQ lockup, cleared int mask\n", zr->name); - break; - } - } - } - spin_unlock_irqrestore(&zr->lock, flags); -} - -/* Check a zoran_params struct for correctness, insert default params */ - -static int zoran_check_params(struct zoran *zr, struct zoran_params *params) -{ - int err = 0, err0 = 0; - - /* insert constant params */ - - params->major_version = MAJOR_VERSION; - params->minor_version = MINOR_VERSION; - - /* Check input and norm */ - - if (params->input != 0 && params->input != 1) { - err++; - } - if (params->norm != VIDEO_MODE_PAL && params->norm != VIDEO_MODE_NTSC) { - err++; - } - /* Check decimation, set default values for decimation = 1, 2, 4 */ - - switch (params->decimation) { - case 1: - - params->HorDcm = 1; - params->VerDcm = 1; - params->TmpDcm = 1; - params->field_per_buff = 2; - - params->img_x = 0; - params->img_y = 0; - params->img_width = 720; - params->img_height = tvnorms[params->norm].Ha / 2; - break; - - case 2: - - params->HorDcm = 2; - params->VerDcm = 1; - params->TmpDcm = 2; - params->field_per_buff = 1; - - params->img_x = 8; - params->img_y = 0; - params->img_width = 704; - params->img_height = tvnorms[params->norm].Ha / 2; - break; - - case 4: - - params->HorDcm = 4; - params->VerDcm = 2; - params->TmpDcm = 2; - params->field_per_buff = 1; - - params->img_x = 8; - params->img_y = 0; - params->img_width = 704; - params->img_height = tvnorms[params->norm].Ha / 2; - break; - - case 0: - - /* We have to check the data the user has set */ - - if (params->HorDcm != 1 && params->HorDcm != 2 && params->HorDcm != 4) - err0++; - if (params->VerDcm != 1 && params->VerDcm != 2) - err0++; - if (params->TmpDcm != 1 && params->TmpDcm != 2) - err0++; - if (params->field_per_buff != 1 && params->field_per_buff != 2) - err0++; - - if (params->img_x < 0) - err0++; - if (params->img_y < 0) - err0++; - if (params->img_width < 0) - err0++; - if (params->img_height < 0) - err0++; - if (params->img_x + params->img_width > 720) - err0++; - if (params->img_y + params->img_height > tvnorms[params->norm].Ha / 2) - err0++; - if (params->img_width % (16 * params->HorDcm) != 0) - err0++; - if (params->img_height % (8 * params->VerDcm) != 0) - err0++; - - if (err0) { - err++; - } - break; - - default: - err++; - break; - } - - if (params->quality > 100) - params->quality = 100; - if (params->quality < 5) - params->quality = 5; - - if (params->APPn < 0) - params->APPn = 0; - if (params->APPn > 15) - params->APPn = 15; - if (params->APP_len < 0) - params->APP_len = 0; - if (params->APP_len > 60) - params->APP_len = 60; - if (params->COM_len < 0) - params->COM_len = 0; - if (params->COM_len > 60) - params->COM_len = 60; - - if (err) - return -EINVAL; - - return 0; - -} -static void zoran_open_init_params(struct zoran *zr) -{ - int i; - - /* Per default, map the V4L Buffers */ - - zr->map_mjpeg_buffers = 0; - - /* User must explicitly set a window */ - - zr->window_set = 0; - - zr->window.x = 0; - zr->window.y = 0; - zr->window.width = 0; - zr->window.height = 0; - zr->window.chromakey = 0; - zr->window.flags = 0; - zr->window.clips = NULL; - zr->window.clipcount = 0; - - zr->video_interlace = 0; - - zr->v4l_memgrab_active = 0; - zr->v4l_overlay_active = 0; - - zr->v4l_grab_frame = NO_GRAB_ACTIVE; - zr->v4l_grab_seq = 0; - - zr->gwidth = 0; - zr->gheight = 0; - zr->gformat = 0; - zr->gbpl = 0; - - /* DMA ring stuff for V4L */ - - zr->v4l_pend_tail = 0; - zr->v4l_pend_head = 0; - for (i = 0; i < v4l_nbufs; i++) { - zr->v4l_gbuf[i].state = BUZ_STATE_USER; /* nothing going on */ - } - - /* Set necessary params and call zoran_check_params to set the defaults */ - - zr->params.decimation = 1; - - zr->params.quality = 50; /* default compression factor 8 */ - zr->params.odd_even = 1; - - zr->params.APPn = 0; - zr->params.APP_len = 0; /* No APPn marker */ - for (i = 0; i < 60; i++) - zr->params.APP_data[i] = 0; - - zr->params.COM_len = 0; /* No COM marker */ - for (i = 0; i < 60; i++) - zr->params.COM_data[i] = 0; - - zr->params.VFIFO_FB = 0; - - memset(zr->params.reserved, 0, sizeof(zr->params.reserved)); - - zr->params.jpeg_markers = JPEG_MARKER_DHT | JPEG_MARKER_DQT; - - i = zoran_check_params(zr, &zr->params); - if (i) - printk(KERN_ERR "%s: zoran_open_init_params internal error\n", zr->name); -} - -/* - * Open a buz card. Right now the flags stuff is just playing - */ - -static int zoran_open(struct video_device *dev, int flags) -{ - struct zoran *zr = (struct zoran *) dev; - - DEBUG(printk(KERN_INFO ": zoran_open\n")); - - switch (flags) { - - case 0: - if (zr->user) - return -EBUSY; - zr->user++; - - if (v4l_fbuffer_alloc(zr) < 0) { - zr->user--; - return -ENOMEM; - } - /* default setup */ - - zoran_open_init_params(zr); - - zr36057_enable_jpg(zr, BUZ_MODE_IDLE); - - btwrite(IRQ_MASK, ZR36057_ISR); // Clears interrupts - - btor(ZR36057_ICR_IntPinEn, ZR36057_ICR); - - break; - - default: - return -EBUSY; - - } - return 0; -} - -static void zoran_close(struct video_device *dev) -{ - struct zoran *zr = (struct zoran *) dev; - - DEBUG(printk(KERN_INFO ": zoran_close\n")); - - /* disable interrupts */ - btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); - - /* wake up sleeping beauties */ - wake_up_interruptible(&zr->v4l_capq); - wake_up_interruptible(&zr->jpg_capq); - - zr36057_enable_jpg(zr, BUZ_MODE_IDLE); - zr36057_set_memgrab(zr, 0); - if (zr->v4l_overlay_active) - zr36057_overlay(zr, 0); - - zr->user--; - - v4l_fbuffer_free(zr); - jpg_fbuffer_free(zr); - zr->jpg_nbufs = 0; - - DEBUG(printk(KERN_INFO ": zoran_close done\n")); -} - - -static long zoran_read(struct video_device *dev, char *buf, unsigned long count, int nonblock) -{ - return -EINVAL; -} - -static long zoran_write(struct video_device *dev, const char *buf, unsigned long count, int nonblock) -{ - return -EINVAL; -} - -/* - * ioctl routine - */ - - -static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct zoran *zr = (struct zoran *) dev; - - switch (cmd) { - - case VIDIOCGCAP: - { - struct video_capability b; - IOCTL_DEBUG(printk("buz ioctl VIDIOCGCAP\n")); - strncpy(b.name, zr->video_dev.name, sizeof(b.name)); - b.type = VID_TYPE_CAPTURE | - VID_TYPE_OVERLAY | - VID_TYPE_CLIPPING | - VID_TYPE_FRAMERAM | - VID_TYPE_SCALES; - /* theoretically we could also flag VID_TYPE_SUBCAPTURE - but this is not even implemented in the BTTV driver */ - - b.channels = 2; /* composite, svhs */ - b.audios = 0; - b.maxwidth = BUZ_MAX_WIDTH; - b.maxheight = BUZ_MAX_HEIGHT; - b.minwidth = BUZ_MIN_WIDTH; - b.minheight = BUZ_MIN_HEIGHT; - if (copy_to_user(arg, &b, sizeof(b))) { - return -EFAULT; - } - return 0; - } - - case VIDIOCGCHAN: - { - struct video_channel v; - - if (copy_from_user(&v, arg, sizeof(v))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl VIDIOCGCHAN for channel %d\n", v.channel)); - switch (v.channel) { - case 0: - strcpy(v.name, "Composite"); - break; - case 1: - strcpy(v.name, "SVHS"); - break; - default: - return -EINVAL; - } - v.tuners = 0; - v.flags = 0; - v.type = VIDEO_TYPE_CAMERA; - v.norm = zr->params.norm; - if (copy_to_user(arg, &v, sizeof(v))) { - return -EFAULT; - } - return 0; - } - - /* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says: - - * "The VIDIOCSCHAN ioctl takes an integer argument and switches the capture to this input." - * ^^^^^^^ - * The famos BTTV driver has it implemented with a struct video_channel argument - * and we follow it for compatibility reasons - * - * BTW: this is the only way the user can set the norm! - */ - - case VIDIOCSCHAN: - { - struct video_channel v; - int input; - int on, res; - - if (copy_from_user(&v, arg, sizeof(v))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl VIDIOCSCHAN: channel=%d, norm=%d\n", v.channel, v.norm)); - switch (v.channel) { - case 0: - input = 3; - break; - case 1: - input = 7; - break; - default: - return -EINVAL; - } - - if (v.norm != VIDEO_MODE_PAL - && v.norm != VIDEO_MODE_NTSC) { - return -EINVAL; - } - zr->params.norm = v.norm; - zr->params.input = v.channel; - - /* We switch overlay off and on since a change in the norm - needs different VFE settings */ - - on = zr->v4l_overlay_active && !zr->v4l_memgrab_active; - if (on) - zr36057_overlay(zr, 0); - - 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); - - if (on) - zr36057_overlay(zr, 1); - - /* Make sure the changes come into effect */ - res = wait_grab_pending(zr); - if (res) - return res; - - return 0; - } - - case VIDIOCGTUNER: - case VIDIOCSTUNER: - return -EINVAL; - - case VIDIOCGPICT: - { - struct video_picture p = zr->picture; - - IOCTL_DEBUG(printk("buz ioctl VIDIOCGPICT\n")); - p.depth = zr->buffer.depth; - switch (zr->buffer.depth) { - case 15: - p.palette = VIDEO_PALETTE_RGB555; - break; - - case 16: - p.palette = VIDEO_PALETTE_RGB565; - break; - - case 24: - p.palette = VIDEO_PALETTE_RGB24; - break; - - case 32: - p.palette = VIDEO_PALETTE_RGB32; - break; - } - - if (copy_to_user(arg, &p, sizeof(p))) { - return -EFAULT; - } - return 0; - } - - case VIDIOCSPICT: - { - struct video_picture p; - - if (copy_from_user(&p, arg, sizeof(p))) { - return -EFAULT; - } - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p); - IOCTL_DEBUG(printk("buz ioctl VIDIOCSPICT bri=%d hue=%d col=%d con=%d dep=%d pal=%d\n", - p.brightness, p.hue, p.colour, p.contrast, p.depth, p.palette)); - /* The depth and palette values have no meaning to us, - should we return -EINVAL if they don't fit ? */ - zr->picture = p; - return 0; - } - - case VIDIOCCAPTURE: - { - int v, res; - - if (copy_from_user(&v, arg, sizeof(v))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl VIDIOCCAPTURE: %d\n", v)); - /* If there is nothing to do, return immediatly */ - - if ((v && zr->v4l_overlay_active) || (!v && !zr->v4l_overlay_active)) - return 0; - - if (v == 0) { - zr->v4l_overlay_active = 0; - if (!zr->v4l_memgrab_active) - zr36057_overlay(zr, 0); - /* When a grab is running, the video simply won't be switched on any more */ - } else { - if (!zr->buffer_set || !zr->window_set) { - return -EINVAL; - } - zr->v4l_overlay_active = 1; - if (!zr->v4l_memgrab_active) - zr36057_overlay(zr, 1); - /* When a grab is running, the video will be switched on when grab is finished */ - } - /* Make sure the changes come into effect */ - res = wait_grab_pending(zr); - if (res) - return res; - return 0; - } - - case VIDIOCGWIN: - { - IOCTL_DEBUG(printk("buz ioctl VIDIOCGWIN\n")); - if (copy_to_user(arg, &zr->window, sizeof(zr->window))) { - return -EFAULT; - } - return 0; - } - - case VIDIOCSWIN: - { - struct video_clip *vcp; - struct video_window vw; - int on, end, res; - - if (copy_from_user(&vw, arg, sizeof(vw))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl VIDIOCSWIN: x=%d y=%d w=%d h=%d clipcount=%d\n", vw.x, vw.y, vw.width, vw.height, vw.clipcount)); - if (!zr->buffer_set) { - return -EINVAL; - } - /* - * The video front end needs 4-byte alinged line sizes, we correct that - * silently here if necessary - */ - - if (zr->buffer.depth == 15 || zr->buffer.depth == 16) { - end = (vw.x + vw.width) & ~1; /* round down */ - vw.x = (vw.x + 1) & ~1; /* round up */ - vw.width = end - vw.x; - } - if (zr->buffer.depth == 24) { - end = (vw.x + vw.width) & ~3; /* round down */ - vw.x = (vw.x + 3) & ~3; /* round up */ - vw.width = end - vw.x; - } -#if 0 - // At least xawtv seems to care about the following - just leave it away - /* - * Also corrected silently (as long as window fits at all): - * video not fitting the screen - */ -#if 0 - if (vw.x < 0 || vw.y < 0 || vw.x + vw.width > zr->buffer.width || - vw.y + vw.height > zr->buffer.height) { - printk(BUZ_ERR ": VIDIOCSWIN: window does not fit frame buffer: %dx%d+%d*%d\n", - vw.width, vw.height, vw.x, vw.y); - return -EINVAL; - } -#else - if (vw.x < 0) - vw.x = 0; - if (vw.y < 0) - vw.y = 0; - if (vw.x + vw.width > zr->buffer.width) - vw.width = zr->buffer.width - vw.x; - if (vw.y + vw.height > zr->buffer.height) - vw.height = zr->buffer.height - vw.y; -#endif -#endif - - /* Check for valid parameters */ - if (vw.width < BUZ_MIN_WIDTH || vw.height < BUZ_MIN_HEIGHT || - vw.width > BUZ_MAX_WIDTH || vw.height > BUZ_MAX_HEIGHT) { - return -EINVAL; - } -#ifdef XAWTV_HACK - if (vw.width > 720) - vw.width = 720; -#endif - - zr->window.x = vw.x; - zr->window.y = vw.y; - zr->window.width = vw.width; - zr->window.height = vw.height; - zr->window.chromakey = 0; - zr->window.flags = 0; // RJ: Is this intended for interlace on/off ? - - zr->window.clips = NULL; - zr->window.clipcount = vw.clipcount; - - /* - * If an overlay is running, we have to switch it off - * and switch it on again in order to get the new settings in effect. - * - * We also want to avoid that the overlay mask is written - * when an overlay is running. - */ - - on = zr->v4l_overlay_active && !zr->v4l_memgrab_active; - if (on) - zr36057_overlay(zr, 0); - - /* - * Write the overlay mask if clips are wanted. - */ - if (vw.clipcount) { - vcp = vmalloc(sizeof(struct video_clip) * (vw.clipcount + 4)); - if (vcp == NULL) { - return -ENOMEM; - } - if (copy_from_user(vcp, vw.clips, sizeof(struct video_clip) * vw.clipcount)) { - vfree(vcp); - return -EFAULT; - } - write_overlay_mask(zr, vcp, vw.clipcount); - vfree(vcp); - } - if (on) - zr36057_overlay(zr, 1); - zr->window_set = 1; - - /* Make sure the changes come into effect */ - res = wait_grab_pending(zr); - if (res) - return res; - - return 0; - } - - case VIDIOCGFBUF: - { - IOCTL_DEBUG(printk("buz ioctl VIDIOCGFBUF\n")); - if (copy_to_user(arg, &zr->buffer, sizeof(zr->buffer))) { - return -EFAULT; - } - return 0; - } - - case VIDIOCSFBUF: - { - struct video_buffer v; - - if (!capable(CAP_SYS_ADMIN) - || !capable(CAP_SYS_RAWIO)) - return -EPERM; - - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - - IOCTL_DEBUG(printk("buz ioctl VIDIOCSFBUF: base=0x%x w=%d h=%d depth=%d bpl=%d\n", (u32) v.base, v.width, v.height, v.depth, v.bytesperline)); - if (zr->v4l_overlay_active) { - /* Has the user gotten crazy ... ? */ - return -EINVAL; - } - if (v.depth != 15 - && v.depth != 16 - && v.depth != 24 - && v.depth != 32) { - return -EINVAL; - } - if (v.height <= 0 || v.width <= 0 || v.bytesperline <= 0) { - return -EINVAL; - } - if (v.bytesperline & 3) { - return -EINVAL; - } - if (v.base) { - zr->buffer.base = (void *) ((unsigned long) v.base & ~3); - } - zr->buffer.height = v.height; - zr->buffer.width = v.width; - zr->buffer.depth = v.depth; - zr->buffer.bytesperline = v.bytesperline; - - if (zr->buffer.base) - zr->buffer_set = 1; - zr->window_set = 0; /* The user should set new window parameters */ - return 0; - } - - /* RJ: what is VIDIOCKEY intended to do ??? */ - - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - return -EINVAL; - - case VIDIOCSYNC: - { - int v; - - if (copy_from_user(&v, arg, sizeof(v))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl VIDIOCSYNC %d\n", v)); - return v4l_sync(zr, v); - } - - case VIDIOCMCAPTURE: - { - struct video_mmap vm; - - if (copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl VIDIOCMCAPTURE frame=%d geom=%dx%d fmt=%d\n", - vm.frame, vm.height, vm.width, vm.format)); - return v4l_grab(zr, &vm); - } - - case VIDIOCGMBUF: - { - struct video_mbuf vm; - int i; - - IOCTL_DEBUG(printk("buz ioctl VIDIOCGMBUF\n")); - - vm.size = v4l_nbufs * v4l_bufsize; - vm.frames = v4l_nbufs; - for (i = 0; i < v4l_nbufs; i++) { - vm.offsets[i] = i * v4l_bufsize; - } - - /* The next mmap will map the V4L buffers */ - zr->map_mjpeg_buffers = 0; - - if (copy_to_user(arg, &vm, sizeof(vm))) { - return -EFAULT; - } - return 0; - } - - case VIDIOCGUNIT: - { - struct video_unit vu; - - IOCTL_DEBUG(printk("buz ioctl VIDIOCGUNIT\n")); - vu.video = zr->video_dev.minor; - vu.vbi = VIDEO_NO_UNIT; - vu.radio = VIDEO_NO_UNIT; - vu.audio = VIDEO_NO_UNIT; - vu.teletext = VIDEO_NO_UNIT; - if (copy_to_user(arg, &vu, sizeof(vu))) - return -EFAULT; - return 0; - } - - /* - * RJ: In principal we could support subcaptures for V4L grabbing. - * Not even the famous BTTV driver has them, however. - * If there should be a strong demand, one could consider - * to implement them. - */ - case VIDIOCGCAPTURE: - case VIDIOCSCAPTURE: - return -EINVAL; - - case BUZIOC_G_PARAMS: - { - IOCTL_DEBUG(printk("buz ioctl BUZIOC_G_PARAMS\n")); - if (copy_to_user(arg, &(zr->params), sizeof(zr->params))) - return -EFAULT; - return 0; - } - - case BUZIOC_S_PARAMS: - { - struct zoran_params bp; - int input, on; - - if (zr->codec_mode != BUZ_MODE_IDLE) { - return -EINVAL; - } - if (copy_from_user(&bp, arg, sizeof(bp))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl BUZIOC_S_PARAMS\n")); - - /* Check the params first before overwriting our internal values */ - - if (zoran_check_params(zr, &bp)) - return -EINVAL; - - zr->params = bp; - - /* Make changes of input and norm go into effect immediatly */ - - /* We switch overlay off and on since a change in the norm - needs different VFE settings */ - - on = zr->v4l_overlay_active && !zr->v4l_memgrab_active; - if (on) - zr36057_overlay(zr, 0); - - input = zr->params.input == 0 ? 3 : 7; - 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); - - if (on) - zr36057_overlay(zr, 1); - - if (copy_to_user(arg, &bp, sizeof(bp))) { - return -EFAULT; - } - return 0; - } - - case BUZIOC_REQBUFS: - { - struct zoran_requestbuffers br; - - if (zr->jpg_buffers_allocated) { - return -EINVAL; - } - if (copy_from_user(&br, arg, sizeof(br))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl BUZIOC_REQBUFS count = %lu size=%lu\n", - br.count, br.size)); - /* Enforce reasonable lower and upper limits */ - if (br.count < 4) - br.count = 4; /* Could be choosen smaller */ - if (br.count > BUZ_MAX_FRAME) - br.count = BUZ_MAX_FRAME; - br.size = PAGE_ALIGN(br.size); - if (br.size < 8192) - br.size = 8192; /* Arbitrary */ - /* br.size is limited by 1 page for the stat_com tables to a Maximum of 2 MB */ - if (br.size > (512 * 1024)) - br.size = (512 * 1024); /* 512 K should be enough */ - if (zr->need_contiguous && br.size > KMALLOC_MAXSIZE) - br.size = KMALLOC_MAXSIZE; - - zr->jpg_nbufs = br.count; - zr->jpg_bufsize = br.size; - - if (jpg_fbuffer_alloc(zr)) - return -ENOMEM; - - /* The next mmap will map the MJPEG buffers */ - zr->map_mjpeg_buffers = 1; - - if (copy_to_user(arg, &br, sizeof(br))) { - return -EFAULT; - } - return 0; - } - - case BUZIOC_QBUF_CAPT: - { - int nb; - - if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl BUZIOC_QBUF_CAPT %d\n", nb)); - return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_COMPRESS); - } - - case BUZIOC_QBUF_PLAY: - { - int nb; - - if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl BUZIOC_QBUF_PLAY %d\n", nb)); - return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_DECOMPRESS); - } - - case BUZIOC_SYNC: - { - struct zoran_sync bs; - int res; - - IOCTL_DEBUG(printk("buz ioctl BUZIOC_SYNC\n")); - res = jpg_sync(zr, &bs); - if (copy_to_user(arg, &bs, sizeof(bs))) { - return -EFAULT; - } - return res; - } - - case BUZIOC_G_STATUS: - { - struct zoran_status bs; - int norm, input, status; - - if (zr->codec_mode != BUZ_MODE_IDLE) { - return -EINVAL; - } - if (copy_from_user(&bs, arg, sizeof(bs))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl BUZIOC_G_STATUS\n")); - switch (bs.input) { - case 0: - input = 3; - break; - case 1: - input = 7; - break; - default: - return -EINVAL; - } - - /* Set video norm to VIDEO_MODE_AUTO */ - - norm = VIDEO_MODE_AUTO; - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm); - - /* sleep 1 second */ - - schedule_timeout(HZ); - - /* Get status of video decoder */ - - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_STATUS, &status); - bs.signal = (status & DECODER_STATUS_GOOD) ? 1 : 0; - bs.norm = (status & DECODER_STATUS_NTSC) ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL; - bs.color = (status & DECODER_STATUS_COLOR) ? 1 : 0; - - /* restore previous input and norm */ - input = zr->params.input == 0 ? 3 : 7; - 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); - - if (copy_to_user(arg, &bs, sizeof(bs))) { - return -EFAULT; - } - return 0; - } - - default: - return -ENOIOCTLCMD; - - } - return 0; -} - - -/* - * This maps the buffers to user space. - * - * Depending on the state of zr->map_mjpeg_buffers - * the V4L or the MJPEG buffers are mapped - * - */ - -static int zoran_mmap(struct video_device *dev, const char *adr, unsigned long size) -{ - struct zoran *zr = (struct zoran *) dev; - unsigned long start = (unsigned long) adr; - unsigned long page, pos, todo, fraglen; - int i, j; - - if (zr->map_mjpeg_buffers) { - /* Map the MJPEG buffers */ - - if (!zr->jpg_buffers_allocated) { - return -ENOMEM; - } - if (size > zr->jpg_nbufs * zr->jpg_bufsize) { - return -EINVAL; - } - - for (i = 0; i < zr->jpg_nbufs; i++) { - for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { - fraglen = (zr->jpg_gbuf[i].frag_tab[2 * j + 1] & ~1) << 1; - todo = size; - if (todo > fraglen) - todo = fraglen; - pos = (unsigned long) zr->jpg_gbuf[i].frag_tab[2 * j]; - page = virt_to_phys(bus_to_virt(pos)); /* should just be pos on i386 */ - if (remap_page_range(start, page, todo, PAGE_SHARED)) { - printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name); - return -EAGAIN; - } - size -= todo; - start += todo; - if (size == 0) - break; - if (zr->jpg_gbuf[i].frag_tab[2 * j + 1] & 1) - break; /* was last fragment */ - } - if (size == 0) - break; - } - } else { - /* Map the V4L buffers */ - - if (size > v4l_nbufs * v4l_bufsize) { - return -EINVAL; - } - - for (i = 0; i < v4l_nbufs; i++) { - todo = size; - if (todo > v4l_bufsize) - todo = v4l_bufsize; - page = zr->v4l_gbuf[i].fbuffer_phys; - DEBUG(printk("V4L remap page range %d 0x%x %d to 0x%x\n", i, page, todo, start)); - if (remap_page_range(start, page, todo, PAGE_SHARED)) { - printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name); - return -EAGAIN; - } - size -= todo; - start += todo; - if (size == 0) - break; - } - } - return 0; -} - -static struct video_device zoran_template = -{ - owner: THIS_MODULE, - name: BUZ_NAME, - type: VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM | - VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE, - hardware: VID_HARDWARE_ZR36067, - open: zoran_open, - close: zoran_close, - read: zoran_read, - write: zoran_write, - ioctl: zoran_ioctl, - mmap: zoran_mmap, -}; - -static int zr36057_init(int i) -{ - struct zoran *zr = &zoran[i]; - unsigned long mem; - unsigned mem_needed; - int j; - int rev; - - /* reset zr36057 */ - btwrite(0, ZR36057_SPGPPCR); - mdelay(10); - - /* default setup of all parameters which will persist beetween opens */ - - zr->user = 0; - - init_waitqueue_head(&zr->v4l_capq); - init_waitqueue_head(&zr->jpg_capq); - - zr->map_mjpeg_buffers = 0; /* Map V4L buffers by default */ - - zr->jpg_nbufs = 0; - zr->jpg_bufsize = 0; - zr->jpg_buffers_allocated = 0; - - zr->buffer_set = 0; /* Flag if frame buffer has been set */ - zr->buffer.base = (void *) vidmem; - zr->buffer.width = 0; - zr->buffer.height = 0; - zr->buffer.depth = 0; - zr->buffer.bytesperline = 0; - - zr->params.norm = default_norm ? 1 : 0; /* Avoid nonsense settings from user */ - zr->params.input = default_input ? 1 : 0; /* Avoid nonsense settings from user */ - zr->video_interlace = 0; - - /* Should the following be reset at every open ? */ - - zr->picture.colour = 32768; - zr->picture.brightness = 32768; - zr->picture.hue = 32768; - zr->picture.contrast = 32768; - zr->picture.whiteness = 0; - zr->picture.depth = 0; - zr->picture.palette = 0; - - for (j = 0; j < VIDEO_MAX_FRAME; j++) { - zr->v4l_gbuf[i].fbuffer = 0; - zr->v4l_gbuf[i].fbuffer_phys = 0; - zr->v4l_gbuf[i].fbuffer_bus = 0; - } - - zr->stat_com = 0; - - /* default setup (will be repeated at every open) */ - - zoran_open_init_params(zr); - - /* allocate memory *before* doing anything to the hardware in case allocation fails */ - - /* STAT_COM table and overlay mask */ - - mem_needed = (BUZ_NUM_STAT_COM + ((BUZ_MAX_WIDTH + 31) / 32) * BUZ_MAX_HEIGHT) * 4; - mem = (unsigned long) kmalloc(mem_needed, GFP_KERNEL); - if (!mem) { - return -ENOMEM; - } - memset((void *) mem, 0, mem_needed); - - zr->stat_com = (u32 *) mem; - for (j = 0; j < BUZ_NUM_STAT_COM; j++) { - zr->stat_com[j] = 1; /* mark as unavailable to zr36057 */ - } - zr->overlay_mask = (u32 *) (mem + BUZ_NUM_STAT_COM * 4); - - /* Initialize zr->jpg_gbuf */ - - for (j = 0; j < BUZ_MAX_FRAME; j++) { - zr->jpg_gbuf[j].frag_tab = 0; - zr->jpg_gbuf[j].frag_tab_bus = 0; - zr->jpg_gbuf[j].state = BUZ_STATE_USER; - zr->jpg_gbuf[j].bs.frame = j; - } - - /* take zr36057 out of reset now */ - btwrite(ZR36057_SPGPPCR_SoftReset, ZR36057_SPGPPCR); - mdelay(10); - - /* stop all DMA processes */ - btwrite(ZR36057_MCTCR_CFlush, ZR36057_MCTCR); - btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); - /* assert P_Reset */ - btwrite(0, ZR36057_JPC); - - switch(zr->board) - { - case BOARD_BUZ: - - /* set up GPIO direction */ - btwrite(ZR36057_SPGPPCR_SoftReset | 0, ZR36057_SPGPPCR); - - /* Set up guest bus timing - Guests 0..3 Tdur=12, Trec=3 */ - btwrite((GPIO_MASK << 24) | 0x8888, ZR36057_GPPGCR1); - mdelay(10); - - /* reset video decoder */ - - GPIO(zr, 0, 0); - mdelay(10); - GPIO(zr, 0, 1); - mdelay(10); - - /* reset JPEG codec */ - zr36060_sleep(zr, 0); - mdelay(10); - zr36060_reset(zr); - mdelay(10); - - /* display codec revision */ - if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) { - printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n", - zr->name, zr36060_read_8(zr, 0x023)); - } else { - printk(KERN_ERR "%s: Zoran ZR36060 not found (Rev=%d)\n", zr->name, rev); - kfree((void *) zr->stat_com); - return -1; - } - break; - - case BOARD_LML33: -// btwrite(btread(ZR36057_SPGPPCR)&~ZR36057_SPGPPCR_SoftReset , ZR36057_SPGPPCR); -// udelay(100); -// btwrite(btread(ZR36057_SPGPPCR)|ZR36057_SPGPPCR_SoftReset , ZR36057_SPGPPCR); -// udelay(1000); - - /* - * Set up the GPIO direction - */ - btwrite(btread(ZR36057_SPGPPCR_SoftReset)|0 , ZR36057_SPGPPCR); - /* Set up guest bus timing - Guests 0..2 Tdur=12, Trec=3 */ - btwrite(0xFF00F888, ZR36057_GPPGCR1); - mdelay(10); - GPIO(zr, 5, 0); /* Analog video bypass */ - udelay(3000); - GPIO(zr, 0, 0); /* Reset 819 */ - udelay(3000); - GPIO(zr, 0, 1); /* 819 back */ - udelay(3000); - /* reset JPEG codec */ - zr36060_sleep(zr, 0); - udelay(3000); - zr36060_reset(zr); - udelay(3000); - - /* display codec revision */ - if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) { - printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n", - zr->name, zr36060_read_8(zr, 0x023)); - } else { - printk(KERN_ERR "%s: Zoran ZR36060 not found (rev=%d)\n", zr->name, rev); - kfree((void *) zr->stat_com); - return -1; - } - break; - } - /* i2c */ - memcpy(&zr->i2c, &zoran_i2c_bus_template, sizeof(struct i2c_bus)); - sprintf(zr->i2c.name, "zoran%u", zr->id); - zr->i2c.data = zr; - if (i2c_register_bus(&zr->i2c) < 0) { - kfree((void *) zr->stat_com); - return -1; - } - /* - * Now add the template and register the device unit. - */ - memcpy(&zr->video_dev, &zoran_template, sizeof(zoran_template)); - sprintf(zr->video_dev.name, "zoran%u", zr->id); - if (video_register_device(&zr->video_dev, VFL_TYPE_GRABBER) < 0) { - i2c_unregister_bus(&zr->i2c); - kfree((void *) zr->stat_com); - return -1; - } - /* toggle JPEG codec sleep to sync PLL */ - zr36060_sleep(zr, 1); - mdelay(10); - zr36060_sleep(zr, 0); - mdelay(10); - - /* Enable bus-mastering */ - pci_set_master(zr->pci_dev); - - 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); - - /* set individual interrupt enables (without GIRQ0) - but don't global enable until zoran_open() */ - - btwrite(IRQ_MASK & ~ZR36057_ISR_GIRQ0, ZR36057_ICR); - - if(request_irq(zr->pci_dev->irq, zoran_irq, - SA_SHIRQ | SA_INTERRUPT, zr->name, (void *) zr)<0) - { - printk(KERN_ERR "%s: Can't assign irq.\n", zr->name); - video_unregister_device(&zr->video_dev); - i2c_unregister_bus(&zr->i2c); - kfree((void *) zr->stat_com); - return -1; - } - zr->initialized = 1; - return 0; -} - - - -static void release_zoran(void) -{ - u8 command; - int i; - struct zoran *zr; - - for (i = 0; i < zoran_num; i++) { - zr = &zoran[i]; - - if (!zr->initialized) - continue; - - /* unregister i2c_bus */ - i2c_unregister_bus((&zr->i2c)); - - /* disable PCI bus-mastering */ - pci_read_config_byte(zr->pci_dev, PCI_COMMAND, &command); - command &= ~PCI_COMMAND_MASTER; - pci_write_config_byte(zr->pci_dev, PCI_COMMAND, command); - - /* put chip into reset */ - btwrite(0, ZR36057_SPGPPCR); - - free_irq(zr->pci_dev->irq, zr); - - /* unmap and free memory */ - - kfree((void *) zr->stat_com); - - iounmap(zr->zr36057_mem); - - video_unregister_device(&zr->video_dev); - } -} - -/* - * Scan for a Buz card (actually for the PCI controller ZR36057), - * request the irq and map the io memory - */ - -static int find_zr36057(void) -{ - unsigned char latency; - struct zoran *zr; - struct pci_dev *dev = NULL; - - zoran_num = 0; - - while (zoran_num < BUZ_MAX - && (dev = pci_find_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) { - zr = &zoran[zoran_num]; - zr->pci_dev = dev; - zr->zr36057_mem = NULL; - zr->id = zoran_num; - sprintf(zr->name, "zoran%u", zr->id); - - spin_lock_init(&zr->lock); - - if (pci_enable_device(dev)) - continue; - - zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0); - pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision); - if (zr->revision < 2) { - printk(KERN_INFO "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n", - zr->name, zr->revision, zr->pci_dev->irq, zr->zr36057_adr); - } else { - unsigned short ss_vendor_id, ss_id; - - ss_vendor_id = zr->pci_dev->subsystem_vendor; - ss_id = zr->pci_dev->subsystem_device; - printk(KERN_INFO "%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n", - zr->name, zr->revision, zr->pci_dev->irq, zr->zr36057_adr); - printk(KERN_INFO "%s: subsystem vendor=0x%04x id=0x%04x\n", - zr->name, ss_vendor_id, ss_id); - if(ss_vendor_id==0xFF10 && ss_id == 0xDE41) - { - zr->board = BOARD_LML33; - printk(KERN_INFO "%s: LML33 detected.\n", zr->name); - } - } - - zr->zr36057_mem = ioremap(zr->zr36057_adr, 0x1000); - if (!zr->zr36057_mem) { - printk(KERN_ERR "%s: ioremap failed\n", zr->name); - break; - } - - /* set PCI latency timer */ - pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, &latency); - if (latency != 48) { - printk(KERN_INFO "%s: Changing PCI latency from %d to 48.\n", zr->name, latency); - latency = 48; - pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, latency); - } - zoran_num++; - } - if (zoran_num == 0) - printk(KERN_INFO "zoran: no cards found.\n"); - - return zoran_num; -} - -static void handle_chipset(void) -{ - if(pci_pci_problems&PCIPCI_FAIL) - { - printk(KERN_WARNING "buz: This configuration is known to have PCI to PCI DMA problems\n"); - printk(KERN_WARNING "buz: You may not be able to use overlay mode.\n"); - } - - - if(pci_pci_problems&PCIPCI_TRITON) - { - printk("buz: Enabling Triton support.\n"); - triton = 1; - } - - if(pci_pci_problems&PCIPCI_NATOMA) - { - printk("buz: Enabling Natoma workaround.\n"); - natoma = 1; - } -} - -#ifdef MODULE -int init_module(void) -#else -int init_zoran_cards(struct video_init *unused) -#endif -{ - int i; - - - printk(KERN_INFO "Zoran driver 1.00 (c) 1999 Rainer Johanni, Dave Perks.\n"); - - /* Look for Buz cards */ - - if (find_zr36057() <= 0) { - return -EIO; - } - printk(KERN_INFO"zoran: %d zoran card(s) found\n", zoran_num); - - if (zoran_num == 0) - return -ENXIO; - - - /* check the parameters we have been given, adjust if necessary */ - - if (v4l_nbufs < 0) - v4l_nbufs = 0; - if (v4l_nbufs > VIDEO_MAX_FRAME) - v4l_nbufs = VIDEO_MAX_FRAME; - /* The user specfies the in KB, we want them in byte (and page aligned) */ - v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024); - if (v4l_bufsize < 32768) - v4l_bufsize = 32768; - /* 2 MB is arbitrary but sufficient for the maximum possible images */ - if (v4l_bufsize > 2048 * 1024) - v4l_bufsize = 2048 * 1024; - - printk(KERN_INFO "zoran: using %d V4L buffers of size %d KB\n", v4l_nbufs, v4l_bufsize >> 10); - - /* Use parameter for vidmem or try to find a video card */ - - if (vidmem) { - printk(KERN_INFO "zoran: Using supplied video memory base address @ 0x%lx\n", vidmem); - } - - /* check if we have a Triton or Natome chipset */ - - handle_chipset(); - - /* take care of Natoma chipset and a revision 1 zr36057 */ - - for (i = 0; i < zoran_num; i++) { - if (natoma && zoran[i].revision <= 1) { - zoran[i].need_contiguous = 1; - printk(KERN_INFO "%s: ZR36057/Natome bug, max. buffer size is 128K\n", zoran[i].name); - } else { - zoran[i].need_contiguous = 0; - } - } - - /* initialize the Buzs */ - - /* We have to know which ones must be released if an error occurs */ - for (i = 0; i < zoran_num; i++) - zoran[i].initialized = 0; - - for (i = 0; i < zoran_num; i++) { - if (zr36057_init(i) < 0) { - release_zoran(); - return -EIO; - } - } - - return 0; -} - - - -#ifdef MODULE - -void cleanup_module(void) -{ - release_zoran(); -} - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/buz.h linux.ac/drivers/media/video/buz.h --- linux.vanilla/drivers/media/video/buz.h Mon Dec 11 21:15:49 2000 +++ linux.ac/drivers/media/video/buz.h Thu Jan 1 01:00:00 1970 @@ -1,319 +0,0 @@ -/* - buz - Iomega Buz driver - - Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de> - - based on - - buz.0.0.3 Copyright (C) 1998 Dave Perks <dperks@ibm.net> - - and - - bttv - Bt848 frame grabber driver - Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) - - 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 _BUZ_H_ -#define _BUZ_H_ - -/* The Buz only supports a maximum width of 720, but some V4L - applications (e.g. xawtv are more happy with 768). - If XAWTV_HACK is defined, we try to fake a device with bigger width */ - -#define XAWTV_HACK - -#ifdef XAWTV_HACK -#define BUZ_MAX_WIDTH 768 /* never display more than 768 pixels */ -#else -#define BUZ_MAX_WIDTH 720 /* never display more than 720 pixels */ -#endif -#define BUZ_MAX_HEIGHT 576 /* never display more than 576 rows */ -#define BUZ_MIN_WIDTH 32 /* never display less than 32 pixels */ -#define BUZ_MIN_HEIGHT 24 /* never display less than 24 rows */ - -struct zoran_requestbuffers { - unsigned long count; /* Number of buffers for MJPEG grabbing */ - unsigned long size; /* Size PER BUFFER in bytes */ -}; - -struct zoran_sync { - unsigned long frame; /* number of buffer that has been free'd */ - unsigned long length; /* number of code bytes in buffer (capture only) */ - unsigned long seq; /* frame sequence number */ - struct timeval timestamp; /* timestamp */ -}; - -struct zoran_status { - int input; /* Input channel, has to be set prior to BUZIOC_G_STATUS */ - int signal; /* Returned: 1 if valid video signal detected */ - int norm; /* Returned: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ - int color; /* Returned: 1 if color signal detected */ -}; - -struct zoran_params { - - /* The following parameters can only be queried */ - - int major_version; /* Major version number of driver */ - int minor_version; /* Minor version number of driver */ - - /* Main control parameters */ - - int input; /* Input channel: 0 = Composite, 1 = S-VHS */ - int norm; /* Norm: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ - int decimation; /* decimation of captured video, - enlargement of video played back. - Valid values are 1, 2, 4 or 0. - 0 is a special value where the user - has full control over video scaling */ - - /* The following parameters only have to be set if decimation==0, - for other values of decimation they provide the data how the image is captured */ - - int HorDcm; /* Horizontal decimation: 1, 2 or 4 */ - int VerDcm; /* Vertical decimation: 1 or 2 */ - int TmpDcm; /* Temporal decimation: 1 or 2, - if TmpDcm==2 in capture every second frame is dropped, - in playback every frame is played twice */ - int field_per_buff; /* Number of fields per buffer: 1 or 2 */ - int img_x; /* start of image in x direction */ - int img_y; /* start of image in y direction */ - int img_width; /* image width BEFORE decimation, - must be a multiple of HorDcm*16 */ - int img_height; /* image height BEFORE decimation, - must be a multiple of VerDcm*8 */ - - /* --- End of parameters for decimation==0 only --- */ - - /* JPEG control parameters */ - - int quality; /* Measure for quality of compressed images. - Scales linearly with the size of the compressed images. - Must be beetween 0 and 100, 100 is a compression - ratio of 1:4 */ - - int odd_even; /* Which field should come first ??? */ - - int APPn; /* Number of APP segment to be written, must be 0..15 */ - int APP_len; /* Length of data in JPEG APPn segment */ - char APP_data[60]; /* Data in the JPEG APPn segment. */ - - int COM_len; /* Length of data in JPEG COM segment */ - char COM_data[60]; /* Data in JPEG COM segment */ - - unsigned long jpeg_markers; /* Which markers should go into the JPEG output. - Unless you exactly know what you do, leave them untouched. - Inluding less markers will make the resulting code - smaller, but there will be fewer aplications - which can read it. - The presence of the APP and COM marker is - influenced by APP0_len and COM_len ONLY! */ -#define JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */ -#define JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */ -#define JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */ -#define JPEG_MARKER_COM (1<<6) /* Comment segment */ -#define JPEG_MARKER_APP (1<<7) /* App segment, driver will allways use APP0 */ - - int VFIFO_FB; /* Flag for enabling Video Fifo Feedback. - If this flag is turned on and JPEG decompressing - is going to the screen, the decompress process - is stopped every time the Video Fifo is full. - This enables a smooth decompress to the screen - but the video output signal will get scrambled */ - - /* Misc */ - - char reserved[312]; /* Makes 512 bytes for this structure */ -}; - -/* - Private IOCTL to set up for displaying MJPEG - */ -#define BUZIOC_G_PARAMS _IOR ('v', BASE_VIDIOCPRIVATE+0, struct zoran_params) -#define BUZIOC_S_PARAMS _IOWR('v', BASE_VIDIOCPRIVATE+1, struct zoran_params) -#define BUZIOC_REQBUFS _IOWR('v', BASE_VIDIOCPRIVATE+2, struct zoran_requestbuffers) -#define BUZIOC_QBUF_CAPT _IOW ('v', BASE_VIDIOCPRIVATE+3, int) -#define BUZIOC_QBUF_PLAY _IOW ('v', BASE_VIDIOCPRIVATE+4, int) -#define BUZIOC_SYNC _IOR ('v', BASE_VIDIOCPRIVATE+5, struct zoran_sync) -#define BUZIOC_G_STATUS _IOWR('v', BASE_VIDIOCPRIVATE+6, struct zoran_status) - - -#ifdef __KERNEL__ - -#define BUZ_NUM_STAT_COM 4 -#define BUZ_MASK_STAT_COM 3 - -#define BUZ_MAX_FRAME 256 /* Must be a power of 2 */ -#define BUZ_MASK_FRAME 255 /* Must be BUZ_MAX_FRAME-1 */ - -#if VIDEO_MAX_FRAME <= 32 -#define V4L_MAX_FRAME 32 -#elif VIDEO_MAX_FRAME <= 64 -#define V4L_MAX_FRAME 64 -#else -#error "Too many video frame buffers to handle" -#endif -#define V4L_MASK_FRAME (V4L_MAX_FRAME - 1) - - -#include "zr36057.h" - -enum zoran_codec_mode { - BUZ_MODE_IDLE, /* nothing going on */ - BUZ_MODE_MOTION_COMPRESS, /* grabbing frames */ - BUZ_MODE_MOTION_DECOMPRESS, /* playing frames */ - BUZ_MODE_STILL_COMPRESS, /* still frame conversion */ - BUZ_MODE_STILL_DECOMPRESS /* still frame conversion */ -}; - -enum zoran_buffer_state { - BUZ_STATE_USER, /* buffer is owned by application */ - BUZ_STATE_PEND, /* buffer is queued in pend[] ready to feed to I/O */ - BUZ_STATE_DMA, /* buffer is queued in dma[] for I/O */ - BUZ_STATE_DONE /* buffer is ready to return to application */ -}; - -struct zoran_gbuffer { - u32 *frag_tab; /* addresses of frag table */ - u32 frag_tab_bus; /* same value cached to save time in ISR */ - enum zoran_buffer_state state; /* non-zero if corresponding buffer is in use in grab queue */ - struct zoran_sync bs; /* DONE: info to return to application */ -}; - -struct v4l_gbuffer { - char *fbuffer; /* virtual address of frame buffer */ - unsigned long fbuffer_phys; /* physical address of frame buffer */ - unsigned long fbuffer_bus; /* bus address of frame buffer */ - enum zoran_buffer_state state; /* state: unused/pending/done */ -}; - -struct zoran { - struct video_device video_dev; - struct i2c_bus i2c; - - int initialized; /* flag if zoran has been correctly initalized */ - int user; /* number of current users (0 or 1) */ - - unsigned short id; /* number of this device */ - char name[32]; /* name of this device */ - struct pci_dev *pci_dev; /* PCI device */ - unsigned char revision; /* revision of zr36057 */ - int board; /* Board type */ -#define BOARD_BUZ 0 -#define BOARD_LML33 1 - unsigned int zr36057_adr; /* bus address of IO mem returned by PCI BIOS */ - unsigned char *zr36057_mem; /* pointer to mapped IO memory */ - - int map_mjpeg_buffers; /* Flag which bufferset will map by next mmap() */ - - spinlock_t lock; /* Spinlock */ - - /* Video for Linux parameters */ - - struct video_picture picture; /* Current picture params */ - struct video_buffer buffer; /* Current buffer params */ - struct video_window window; /* Current window params */ - int buffer_set, window_set; /* Flags if the above structures are set */ - int video_interlace; /* Image on screen is interlaced */ - - u32 *overlay_mask; - - wait_queue_head_t v4l_capq; /* wait here for grab to finish */ - - int v4l_overlay_active; /* Overlay grab is activated */ - int v4l_memgrab_active; /* Memory grab is activated */ - - int v4l_grab_frame; /* Frame number being currently grabbed */ -#define NO_GRAB_ACTIVE (-1) - int v4l_grab_seq; /* Number of frames grabbed */ - int gwidth; /* Width of current memory capture */ - int gheight; /* Height of current memory capture */ - int gformat; /* Format of ... */ - int gbpl; /* byte per line of ... */ - - /* V4L grab queue of frames pending */ - - unsigned v4l_pend_head; - unsigned v4l_pend_tail; - int v4l_pend[V4L_MAX_FRAME]; - - struct v4l_gbuffer v4l_gbuf[VIDEO_MAX_FRAME]; /* V4L buffers' info */ - - /* Buz MJPEG parameters */ - - unsigned long jpg_nbufs; /* Number of buffers */ - unsigned long jpg_bufsize; /* Size of mjpeg buffers in bytes */ - int jpg_buffers_allocated; /* Flag if buffers are allocated */ - int need_contiguous; /* Flag if contiguous buffers are needed */ - - enum zoran_codec_mode codec_mode; /* status of codec */ - struct zoran_params params; /* structure with a lot of things to play with */ - - wait_queue_head_t jpg_capq; /* wait here for grab to finish */ - - /* grab queue counts/indices, mask with BUZ_MASK_STAT_COM before using as index */ - /* (dma_head - dma_tail) is number active in DMA, must be <= BUZ_NUM_STAT_COM */ - /* (value & BUZ_MASK_STAT_COM) corresponds to index in stat_com table */ - unsigned long jpg_que_head; /* Index where to put next buffer which is queued */ - unsigned long jpg_dma_head; /* Index of next buffer which goes into stat_com */ - unsigned long jpg_dma_tail; /* Index of last buffer in stat_com */ - unsigned long jpg_que_tail; /* Index of last buffer in queue */ - unsigned long jpg_seq_num; /* count of frames since grab/play started */ - - /* zr36057's code buffer table */ - u32 *stat_com; /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */ - - /* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */ - int jpg_pend[BUZ_MAX_FRAME]; - - /* array indexed by frame number */ - struct zoran_gbuffer jpg_gbuf[BUZ_MAX_FRAME]; /* MJPEG buffers' info */ -}; - -#endif - -/*The following should be done in more portable way. It depends on define - of _ALPHA_BUZ in the Makefile. */ - -#ifdef _ALPHA_BUZ -#define btwrite(dat,adr) writel((dat),(char *) (zr->zr36057_adr+(adr))) -#define btread(adr) readl(zr->zr36057_adr+(adr)) -#else -#define btwrite(dat,adr) writel((dat), (char *) (zr->zr36057_mem+(adr))) -#define btread(adr) readl(zr->zr36057_mem+(adr)) -#endif - -#define btand(dat,adr) btwrite((dat) & btread(adr), adr) -#define btor(dat,adr) btwrite((dat) | btread(adr), adr) -#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) - -#define I2C_TSA5522 0xc2 -#define I2C_TDA9850 0xb6 -#define I2C_HAUPEE 0xa0 -#define I2C_STBEE 0xae -#define I2C_SAA7111 0x48 -#define I2C_SAA7185 0x88 - -#define TDA9850_CON1 0x04 -#define TDA9850_CON2 0x05 -#define TDA9850_CON3 0x06 -#define TDA9850_CON4 0x07 -#define TDA9850_ALI1 0x08 -#define TDA9850_ALI2 0x09 -#define TDA9850_ALI3 0x0a - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/cpia.c linux.ac/drivers/media/video/cpia.c --- linux.vanilla/drivers/media/video/cpia.c Tue Apr 3 17:32:08 2001 +++ linux.ac/drivers/media/video/cpia.c Tue Apr 10 18:15:05 2001 @@ -2832,7 +2832,7 @@ DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame, vm.width, vm.height); #endif - if (vm.frame<0||vm.frame>FRAME_NUM) { + if (vm.frame<0||vm.frame>=FRAME_NUM) { retval = -EINVAL; break; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/saa7110.c linux.ac/drivers/media/video/saa7110.c --- linux.vanilla/drivers/media/video/saa7110.c Thu Dec 30 01:08:55 1999 +++ linux.ac/drivers/media/video/saa7110.c Tue Apr 3 17:54:46 2001 @@ -19,6 +19,7 @@ */ #include <linux/module.h> +#include <linux/init.h> #include <linux/types.h> #include <linux/delay.h> #include <linux/slab.h> @@ -398,7 +399,7 @@ /* ----------------------------------------------------------------------- */ -struct i2c_driver i2c_driver_saa7110 = +static struct i2c_driver i2c_driver_saa7110 = { "saa7110", /* name */ @@ -412,18 +413,16 @@ EXPORT_NO_SYMBOLS; -#ifdef MODULE -int init_module(void) -#else -int saa7110_init(void) -#endif +static int saa7110_init(void) { return i2c_register_driver(&i2c_driver_saa7110); } -#ifdef MODULE -void cleanup_module(void) +static void saa7110_exit(void) { i2c_unregister_driver(&i2c_driver_saa7110); } -#endif + + +module_init(saa7110_init); +module_exit(saa7110_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/saa7111.c linux.ac/drivers/media/video/saa7111.c --- linux.vanilla/drivers/media/video/saa7111.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/media/video/saa7111.c Tue Apr 3 17:54:46 2001 @@ -1,46 +1,41 @@ /* - saa7111 - Philips SAA7111A video decoder driver version 0.0.3 + saa7111 - Philips SAA7111A video decoder driver version 0.0.3 - Copyright (C) 1998 Dave Perks <dperks@ibm.net> + Copyright (C) 1998 Dave Perks <dperks@ibm.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. - - 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. - */ + Slight changes for video timing and attachment output by + Wolfgang Scherr <scherr@net4you.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. + + 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 <linux/module.h> +#include <linux/init.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/fs.h> #include <linux/kernel.h> #include <linux/major.h> -#include <linux/slab.h> +#include <linux/malloc.h> #include <linux/mm.h> -#include <linux/pci.h> -#include <linux/signal.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/page.h> #include <linux/sched.h> -#include <asm/segment.h> -#include <linux/types.h> -#include <linux/wrapper.h> #include <linux/videodev.h> #include <linux/version.h> -#include <asm/uaccess.h> - #include <linux/i2c-old.h> + #include <linux/video_decoder.h> #define DEBUG(x) /* Debug driver */ @@ -67,7 +62,8 @@ /* ----------------------------------------------------------------------- */ -static int saa7111_write(struct saa7111 *dev, unsigned char subaddr, unsigned char data) +static int saa7111_write(struct saa7111 *dev, unsigned char subaddr, + unsigned char data) { int ack; @@ -82,9 +78,10 @@ return ack; } -static int saa7111_write_block(struct saa7111 *dev, unsigned const char *data, unsigned int len) +static int saa7111_write_block(struct saa7111 *dev, + unsigned const char *data, unsigned int len) { - int ack = 0; + int ack = -1; unsigned subaddr; while (len > 1) { @@ -96,7 +93,10 @@ len -= 2; while (len > 1 && *data == ++subaddr) { data++; - ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); + ack = + i2c_sendbyte(dev->bus, + (dev->reg[subaddr] = + *data++), I2C_DELAY); len -= 2; } i2c_stop(dev->bus); @@ -128,20 +128,19 @@ int i; struct saa7111 *decoder; - static const unsigned char init[] = - { + static const unsigned char init[] = { 0x00, 0x00, /* 00 - ID byte */ 0x01, 0x00, /* 01 - reserved */ - /*front end */ + /*front end */ 0x02, 0xd0, /* 02 - FUSE=3, GUDL=2, MODE=0 */ 0x03, 0x23, /* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */ 0x04, 0x00, /* 04 - GAI1=256 */ 0x05, 0x00, /* 05 - GAI2=256 */ - /* decoder */ - 0x06, 0xf6, /* 06 - HSB at 13(50Hz) / 17(60Hz) pixels after end of last line */ - 0x07, 0xdd, /* 07 - HSS at 113(50Hz) / 117(60Hz) pixels after end of last line */ + /* decoder */ + 0x06, 0xf3, /* 06 - HSB at 13(50Hz) / 17(60Hz) pixels after end of last line */ + 0x07, 0x13, /* 07 - HSS at 113(50Hz) / 117(60Hz) pixels after end of last line */ 0x08, 0xc8, /* 08 - AUFD=1, FSEL=1, EXFIL=0, VTRC=1, HPLL=0, VNOI=0 */ 0x09, 0x01, /* 09 - BYPS=0, PREF=0, BPSS=0, VBLB=0, UPTCV=0, APER=1 */ 0x0a, 0x80, /* 0a - BRIG=128 */ @@ -160,11 +159,14 @@ 0x17, 0x00, /* 17 - VBI */ }; + MOD_INC_USE_COUNT; + device->data = decoder = kmalloc(sizeof(struct saa7111), GFP_KERNEL); - if (decoder == NULL) { + if (decoder == NULL) + { + MOD_DEC_USE_COUNT; return -ENOMEM; } - MOD_INC_USE_COUNT; memset(decoder, 0, sizeof(struct saa7111)); strcpy(device->name, "saa7111"); @@ -180,9 +182,11 @@ i = saa7111_write_block(decoder, init, sizeof(init)); if (i < 0) { - printk(KERN_ERR "%s_attach: init status %d\n", device->name, i); + printk(KERN_ERR "%s_attach: init status %d\n", + device->name, i); } else { - printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7111_read(decoder, 0x00)); + printk(KERN_INFO "%s_attach: chip version %x\n", + device->name, saa7111_read(decoder, 0x00) >> 4); } return 0; } @@ -195,7 +199,8 @@ return 0; } -static int saa7111_command(struct i2c_device *device, unsigned int cmd, void *arg) +static int saa7111_command(struct i2c_device *device, unsigned int cmd, + void *arg) { struct saa7111 *decoder = device->data; @@ -209,9 +214,12 @@ for (i = 0; i < 32; i += 16) { int j; - printk("KERN_DEBUG %s: %03x", device->name, i); + printk("KERN_DEBUG %s: %03x", device->name, + i); for (j = 0; j < 16; ++j) { - printk(" %02x", saa7111_read(decoder, i + j)); + printk(" %02x", + saa7111_read(decoder, + i + j)); } printk("\n"); } @@ -226,8 +234,7 @@ cap->flags = VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC - | VIDEO_DECODER_AUTO - | VIDEO_DECODER_CCIR; + | VIDEO_DECODER_AUTO | VIDEO_DECODER_CCIR; cap->inputs = 8; cap->outputs = 1; } @@ -274,15 +281,21 @@ switch (*iarg) { case VIDEO_MODE_NTSC: - saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x40); + saa7111_write(decoder, 0x08, + (decoder-> + reg[0x08] & 0x3f) | 0x40); break; case VIDEO_MODE_PAL: - saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x00); + saa7111_write(decoder, 0x08, + (decoder-> + reg[0x08] & 0x3f) | 0x00); break; case VIDEO_MODE_AUTO: - saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x80); + saa7111_write(decoder, 0x08, + (decoder-> + reg[0x08] & 0x3f) | 0x80); break; default: @@ -300,12 +313,20 @@ if (*iarg < 0 || *iarg > 7) { return -EINVAL; } + if (decoder->input != *iarg) { decoder->input = *iarg; /* select mode */ - saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input); + saa7111_write(decoder, 0x02, + (decoder-> + reg[0x02] & 0xf8) | + decoder->input); /* bypass chrominance trap for modes 4..7 */ - saa7111_write(decoder, 0x09, (decoder->reg[0x09] & 0x7f) | ((decoder->input > 3) ? 0x80 : 0)); + saa7111_write(decoder, 0x09, + (decoder-> + reg[0x09] & 0x7f) | + ((decoder->input > + 3) ? 0x80 : 0)); } } break; @@ -330,19 +351,34 @@ decoder->enable = enable; // RJ: If output should be disabled (for playing videos), we also need a open PLL. - // The input is set to 0 (where no input source is connected), although this - // is not necessary. - // - // If output should be enabled, we have to reverse the above. +// The input is set to 0 (where no input source is connected), although this +// is not necessary. +// +// If output should be enabled, we have to reverse the above. if (decoder->enable) { - saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input); - saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0xfb)); - saa7111_write(decoder, 0x11, (decoder->reg[0x11] & 0xf3) | 0x0c); + saa7111_write(decoder, 0x02, + (decoder-> + reg[0x02] & 0xf8) | + decoder->input); + saa7111_write(decoder, 0x08, + (decoder-> + reg[0x08] & 0xfb)); + saa7111_write(decoder, 0x11, + (decoder-> + reg[0x11] & 0xf3) | + 0x0c); } else { - saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8)); - saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0xfb) | 0x04); - saa7111_write(decoder, 0x11, (decoder->reg[0x11] & 0xf3)); + saa7111_write(decoder, 0x02, + (decoder-> + reg[0x02] & 0xf8)); + saa7111_write(decoder, 0x08, + (decoder-> + reg[0x08] & 0xfb) | + 0x04); + saa7111_write(decoder, 0x11, + (decoder-> + reg[0x11] & 0xf3)); } } } @@ -355,22 +391,26 @@ if (decoder->bright != pic->brightness) { /* We want 0 to 255 we get 0-65535 */ decoder->bright = pic->brightness; - saa7111_write(decoder, 0x0a, decoder->bright >> 8); + saa7111_write(decoder, 0x0a, + decoder->bright >> 8); } if (decoder->contrast != pic->contrast) { /* We want 0 to 127 we get 0-65535 */ decoder->contrast = pic->contrast; - saa7111_write(decoder, 0x0b, decoder->contrast >> 9); + saa7111_write(decoder, 0x0b, + decoder->contrast >> 9); } if (decoder->sat != pic->colour) { /* We want 0 to 127 we get 0-65535 */ decoder->sat = pic->colour; - saa7111_write(decoder, 0x0c, decoder->sat >> 9); + saa7111_write(decoder, 0x0c, + decoder->sat >> 9); } if (decoder->hue != pic->hue) { /* We want -128 to 127 we get 0-65535 */ decoder->hue = pic->hue; - saa7111_write(decoder, 0x0d, (decoder->hue - 32768) >> 8); + saa7111_write(decoder, 0x0d, + (decoder->hue - 32768) >> 8); } } break; @@ -384,8 +424,7 @@ /* ----------------------------------------------------------------------- */ -struct i2c_driver i2c_driver_saa7111 = -{ +static struct i2c_driver i2c_driver_saa7111 = { "saa7111", /* name */ I2C_DRIVERID_VIDEODECODER, /* ID */ I2C_SAA7111, I2C_SAA7111 + 1, @@ -397,22 +436,15 @@ EXPORT_NO_SYMBOLS; -#ifdef MODULE -int init_module(void) -#else -int saa7111_init(void) -#endif +static int saa7111_init(void) { return i2c_register_driver(&i2c_driver_saa7111); } - - -#ifdef MODULE - -void cleanup_module(void) +static void saa7111_exit(void) { i2c_unregister_driver(&i2c_driver_saa7111); } -#endif +module_init(saa7111_init); +module_exit(saa7111_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/saa7185.c linux.ac/drivers/media/video/saa7185.c --- linux.vanilla/drivers/media/video/saa7185.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/media/video/saa7185.c Tue Apr 3 17:54:46 2001 @@ -1,30 +1,34 @@ /* - saa7185 - Philips SAA7185B video encoder driver version 0.0.3 + saa7185 - Philips SAA7185B video encoder driver version 0.0.3 - Copyright (C) 1998 Dave Perks <dperks@ibm.net> + Copyright (C) 1998 Dave Perks <dperks@ibm.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. - - 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. - */ + Slight changes for video timing and attachment output by + Wolfgang Scherr <scherr@net4you.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. + + 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 <linux/module.h> +#include <linux/init.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/fs.h> #include <linux/kernel.h> #include <linux/major.h> -#include <linux/slab.h> +#include <linux/malloc.h> #include <linux/mm.h> #include <linux/pci.h> #include <linux/signal.h> @@ -41,9 +45,10 @@ #include <asm/uaccess.h> #include <linux/i2c-old.h> + #include <linux/video_encoder.h> -#define DEBUG(x) x /* Debug driver */ +#define DEBUG(x) /* Debug driver */ /* ----------------------------------------------------------------------- */ @@ -66,13 +71,31 @@ /* ----------------------------------------------------------------------- */ -static int saa7185_write(struct saa7185 *dev, unsigned char subaddr, unsigned char data) +static int saa7185_read(struct saa7185 *dev) { int ack; LOCK_I2C_BUS(dev->bus); i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr | 1, I2C_DELAY); + ack = i2c_readbyte(dev->bus, 1); + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return ack; +} + +static int saa7185_write(struct saa7185 *dev, unsigned char subaddr, + unsigned char data) +{ + int ack; + + DEBUG(printk + (KERN_DEBUG "SAA7185: %02x set to %02x\n", subaddr, data); + ) + LOCK_I2C_BUS(dev->bus); + + i2c_start(dev->bus); i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); ack = i2c_sendbyte(dev->bus, data, I2C_DELAY); @@ -82,9 +105,10 @@ return ack; } -static int saa7185_write_block(struct saa7185 *dev, unsigned const char *data, unsigned int len) +static int saa7185_write_block(struct saa7185 *dev, + unsigned const char *data, unsigned int len) { - int ack = 0; + int ack = -1; unsigned subaddr; while (len > 1) { @@ -107,8 +131,7 @@ /* ----------------------------------------------------------------------- */ -static const unsigned char init_common[] = -{ +static const unsigned char init_common[] = { 0x3a, 0x0f, /* CBENB=0, V656=0, VY2C=1, YUV2C=1, MY2C=1, MUV2C=1 */ 0x42, 0x6b, /* OVLY0=107 */ @@ -155,7 +178,7 @@ 0x6c, 0x20, /* SRCV1=0, TRCV2=1, ORCV1=0, PRCV1=0, CBLF=0, ORCV2=0, PRCV2=0 */ 0x6d, 0x00, /* SRCM1=0, CCEN=0 */ - 0x6e, 0x0e, /* HTRIG=0x00e, approx. centered, at least for PAL */ + 0x6e, 0x0e, /* HTRIG=0x005, approx. centered, at least for PAL */ 0x6f, 0x00, /* HTRIG upper bits */ 0x70, 0x20, /* PHRES=0, SBLN=1, VTRIG=0 */ @@ -182,8 +205,7 @@ 0x7d, 0x20, /* LAL=244, FAL=22 */ }; -static const unsigned char init_pal[] = -{ +static const unsigned char init_pal[] = { 0x61, 0x1e, /* FISE=0, PAL=1, SCBW=1, RTCE=1, YGS=1, INPI=0, DOWN=0 */ 0x62, 0xc8, /* DECTYP=1, BSTA=72 */ 0x63, 0xcb, /* FSC0 */ @@ -192,8 +214,7 @@ 0x66, 0x2a, /* FSC3 */ }; -static const unsigned char init_ntsc[] = -{ +static const unsigned char init_ntsc[] = { 0x61, 0x1d, /* FISE=1, PAL=0, SCBW=1, RTCE=1, YGS=1, INPI=0, DOWN=0 */ 0x62, 0xe6, /* DECTYP=1, BSTA=102 */ 0x63, 0x1f, /* FSC0 */ @@ -207,11 +228,14 @@ int i; struct saa7185 *encoder; + MOD_INC_USE_COUNT; + device->data = encoder = kmalloc(sizeof(struct saa7185), GFP_KERNEL); if (encoder == NULL) { + MOD_DEC_USE_COUNT; return -ENOMEM; } - MOD_INC_USE_COUNT; + memset(encoder, 0, sizeof(struct saa7185)); strcpy(device->name, "saa7185"); @@ -222,23 +246,33 @@ i = saa7185_write_block(encoder, init_common, sizeof(init_common)); if (i >= 0) { - i = saa7185_write_block(encoder, init_ntsc, sizeof(init_ntsc)); + i = saa7185_write_block(encoder, init_ntsc, + sizeof(init_ntsc)); } if (i < 0) { - printk(KERN_ERR "%s_attach: init error %d\n", device->name, i); + printk(KERN_ERR "%s_attach: init error %d\n", device->name, + i); + } else { + printk(KERN_INFO "%s_attach: chip version %d\n", + device->name, saa7185_read(encoder) >> 5); } + return 0; } static int saa7185_detach(struct i2c_device *device) { - kfree(device->data); + struct saa7185 *encoder = device->data; + saa7185_write(encoder, 0x61, (encoder->reg[0x61]) | 0x40); /* SW: output off is active */ + //saa7185_write(encoder, 0x3a, (encoder->reg[0x3a]) | 0x80); /* SW: color bar */ + kfree(encoder); MOD_DEC_USE_COUNT; return 0; } -static int saa7185_command(struct i2c_device *device, unsigned int cmd, void *arg) +static int saa7185_command(struct i2c_device *device, unsigned int cmd, + void *arg) { struct saa7185 *encoder = device->data; @@ -251,8 +285,7 @@ cap->flags = VIDEO_ENCODER_PAL | VIDEO_ENCODER_NTSC - | VIDEO_ENCODER_SECAM - | VIDEO_ENCODER_CCIR; + | VIDEO_ENCODER_SECAM | VIDEO_ENCODER_CCIR; cap->inputs = 1; cap->outputs = 1; } @@ -265,11 +298,13 @@ switch (*iarg) { case VIDEO_MODE_NTSC: - saa7185_write_block(encoder, init_ntsc, sizeof(init_ntsc)); + saa7185_write_block(encoder, init_ntsc, + sizeof(init_ntsc)); break; case VIDEO_MODE_PAL: - saa7185_write_block(encoder, init_pal, sizeof(init_pal)); + saa7185_write_block(encoder, init_pal, + sizeof(init_pal)); break; case VIDEO_MODE_SECAM: @@ -285,12 +320,6 @@ { int *iarg = arg; -#if 0 - /* not much choice of inputs */ - if (*iarg != 0) { - return -EINVAL; - } -#else /* RJ: *iarg = 0: input is from SA7111 *iarg = 1: input is from ZR36060 */ @@ -298,19 +327,25 @@ case 0: /* Switch RTCE to 1 */ - saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08); + saa7185_write(encoder, 0x61, + (encoder-> + reg[0x61] & 0xf7) | 0x08); + saa7185_write(encoder, 0x6e, 0x01); break; case 1: /* Switch RTCE to 0 */ - saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xf7) | 0x00); + saa7185_write(encoder, 0x61, + (encoder-> + reg[0x61] & 0xf7) | 0x00); + /* SW: a slight sync problem... */ + saa7185_write(encoder, 0x6e, 0x00); break; default: return -EINVAL; } -#endif } break; @@ -330,7 +365,11 @@ int *iarg = arg; encoder->enable = !!*iarg; - saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xbf) | (encoder->enable ? 0x00 : 0x40)); + saa7185_write(encoder, 0x61, + (encoder-> + reg[0x61] & 0xbf) | (encoder-> + enable ? 0x00 : + 0x40)); } break; @@ -343,8 +382,7 @@ /* ----------------------------------------------------------------------- */ -struct i2c_driver i2c_driver_saa7185 = -{ +static struct i2c_driver i2c_driver_saa7185 = { "saa7185", /* name */ I2C_DRIVERID_VIDEOENCODER, /* ID */ I2C_SAA7185, I2C_SAA7185 + 1, @@ -356,22 +394,15 @@ EXPORT_NO_SYMBOLS; -#ifdef MODULE -int init_module(void) -#else -int saa7185_init(void) -#endif +static int saa7185_init(void) { return i2c_register_driver(&i2c_driver_saa7185); } - - -#ifdef MODULE - -void cleanup_module(void) +static void saa7185_exit(void) { i2c_unregister_driver(&i2c_driver_saa7185); } -#endif +module_init(saa7185_init); +module_exit(saa7185_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/stradis.c linux.ac/drivers/media/video/stradis.c --- linux.vanilla/drivers/media/video/stradis.c Tue Apr 3 17:32:08 2001 +++ linux.ac/drivers/media/video/stradis.c Tue Apr 10 18:15:05 2001 @@ -54,8 +54,8 @@ #include "cs8420.h" #define DEBUG(x) /* debug driver */ -#undef IDEBUG(x) /* debug irq handler */ -#undef MDEBUG(x) /* debug memory management */ +#undef IDEBUG /* debug irq handler */ +#undef MDEBUG /* debug memory management */ #define SAA7146_MAX 6 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/tda9875.c linux.ac/drivers/media/video/tda9875.c --- linux.vanilla/drivers/media/video/tda9875.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/media/video/tda9875.c Tue Apr 3 17:54:46 2001 @@ -80,8 +80,8 @@ #define TDA9875_DACOS 0x13 /*DAC i/o select (ADC) 0b0000100*/ #define TDA9875_LOSR 0x16 /*Line output select regirter 0b0100 0001*/ -#define TDA9875_CH1V 0x0c /*Chanel 1 volume (mute)*/ -#define TDA9875_CH2V 0x0d /*Chanel 2 volume (mute)*/ +#define TDA9875_CH1V 0x0c /*Channel 1 volume (mute)*/ +#define TDA9875_CH2V 0x0d /*Channel 2 volume (mute)*/ #define TDA9875_SC1 0x14 /*SCART 1 in (mono)*/ #define TDA9875_SC2 0x15 /*SCART 2 in (mono)*/ @@ -182,8 +182,8 @@ tda9875_write(client, TDA9875_SC1, 0x00 ); /* SCART 1 (SC1)*/ tda9875_write(client, TDA9875_SC2, 0x01 ); /* SCART 2 (sc2)*/ - tda9875_write(client, TDA9875_CH1V, 0x10 ); /* Chanel volume 1 mute*/ - tda9875_write(client, TDA9875_CH2V, 0x10 ); /* Chanel volume 2 mute */ + tda9875_write(client, TDA9875_CH1V, 0x10 ); /* Channel volume 1 mute*/ + tda9875_write(client, TDA9875_CH2V, 0x10 ); /* Channel volume 2 mute */ tda9875_write(client, TDA9875_DACOS, 0x02 ); /* sig DAC i/o(in:nicam)*/ tda9875_write(client, TDA9875_ADCIS, 0x6f ); /* sig ADC input(in:mono)*/ tda9875_write(client, TDA9875_LOSR, 0x00 ); /* line out (in:mono)*/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/tvaudio.c linux.ac/drivers/media/video/tvaudio.c --- linux.vanilla/drivers/media/video/tvaudio.c Mon Feb 19 22:43:36 2001 +++ linux.ac/drivers/media/video/tvaudio.c Tue Apr 3 17:54:46 2001 @@ -124,7 +124,7 @@ /* ---------------------------------------------------------------------- */ -/* i2c adresses */ +/* i2c addresses */ static unsigned short normal_i2c[] = { I2C_TDA8425 >> 1, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/w9966.c linux.ac/drivers/media/video/w9966.c --- linux.vanilla/drivers/media/video/w9966.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/media/video/w9966.c Tue Apr 3 23:49:26 2001 @@ -0,0 +1,948 @@ +/* + Winbond w9966cf Webcam parport driver. + + Version 0.3 + + Copyright (C) 2001 Jakob Kemi <jakob.kemi@post.utfors.se> + + 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. +*/ +/* + Supported devices: + *Lifeview FlyCam Supra (using the Phillips saa7111a chip) + + Does any other model using the w9966 interface chip exist ? + + Todo: + + *Add a working EPP mode, since DMA ECP read isn't implemented + in the parport drivers. (That's why it's so sloow) + + *Add working hue, color and brightness. This should be an + easy one since it's well documented in the saa7111 pdf-file. + + *Add support for other ccd-control chips than the saa7111 + please send me feedback on what kind of chips you have. + + *Add proper probing. I don't know what's wrong with the IEEE1284 + parport drivers but (IEEE1284_MODE_NIBBLE|IEEE1284_DEVICE_ID) + and nibble read seems to be broken for some peripherals. + + *Add probing for onboard SRAM, port directions etc. (if possible) + + *Add support for the hardware compressed modes (maybe using v4l2) + + *Fix better support for the capture window (no skewed images, v4l + interface to capt. window) + + *Probably some bugs that I don't know of + + Please support me by sending feedback! + + Changes: + + Alan Cox: Removed RGB mode for kernel merge, added THIS_MODULE + and owner support for newer module locks +*/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/videodev.h> +#include <linux/parport.h> + +//#define DEBUG // Undef me for production + +#ifdef DEBUG +#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: "__FUNCTION__ "(): "x, ##a) +#else +#define DPRINTF(x...) +#endif + +/* + * Defines, simple typedefs etc. + */ + +#define W9966_DRIVERNAME "W9966CF Webcam" +#define W9966_MAXCAMS 4 // Maximum number of cameras +#define W9966_RBUFFER 2048 // Read buffer (must be an even number) +#define W9966_SRAMSIZE 131072 // 128kb +#define W9966_SRAMID 0x02 // check w9966cf.pdf + +// Empirically determined window limits +#define W9966_WND_MIN_X 16 +#define W9966_WND_MIN_Y 14 +#define W9966_WND_MAX_X 705 +#define W9966_WND_MAX_Y 253 +#define W9966_WND_MAX_W (W9966_WND_MAX_X - W9966_WND_MIN_X) +#define W9966_WND_MAX_H (W9966_WND_MAX_Y - W9966_WND_MIN_Y) + +// Keep track of our current state +#define W9966_STATE_PDEV 0x01 +#define W9966_STATE_CLAIMED 0x02 +#define W9966_STATE_VDEV 0x04 + +#define W9966_I2C_W_ID 0x48 +#define W9966_I2C_R_ID 0x49 +#define W9966_I2C_R_DATA 0x08 +#define W9966_I2C_R_CLOCK 0x04 +#define W9966_I2C_W_DATA 0x02 +#define W9966_I2C_W_CLOCK 0x01 + +struct w9966_dev { + unsigned char dev_state; + unsigned char i2c_state; + unsigned short ppmode; + struct parport* pport; + struct pardevice* pdev; + struct video_device vdev; + unsigned short width; + unsigned short height; +// Currently inimplemented +// unsigned char brightness; +// unsigned char contrast; +}; + +/* + * Module specific properties + */ + +MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>"); +MODULE_DESCRIPTION("Winbond w9966cf WebCam driver"); + +#ifdef MODULE +static const char* pardev[] = {[0 ... W9966_MAXCAMS] = ""}; +#else +static const char* pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"}; +#endif +MODULE_PARM(pardev, "1-" __MODULE_STRING(W9966_MAXCAMS) "s"); +MODULE_PARM_DESC(pardev, "pardev: where to search for\n\ +\teach camera. 'aggressive' means brute-force search.\n\ +\tEg: >pardev=parport3,aggressive,parport2,parport1< would assign +\tcam 1 to parport3 and search every parport for cam 2 etc..."); + +static int parmode = 0; +MODULE_PARM(parmode, "i"); +MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp"); + +/* + * Private data + */ + +static struct w9966_dev w9966_cams[W9966_MAXCAMS]; + +/* + * Private function declares + */ + +static inline void w9966_setState(struct w9966_dev* cam, int mask, int val); +static inline int w9966_getState(struct w9966_dev* cam, int mask, int val); +static inline void w9966_pdev_claim(struct w9966_dev *vdev); +static inline void w9966_pdev_release(struct w9966_dev *vdev); + +static int w9966_rReg(struct w9966_dev* cam, int reg); +static int w9966_wReg(struct w9966_dev* cam, int reg, int data); +static int w9966_rReg_i2c(struct w9966_dev* cam, int reg); +static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data); +static int w9966_findlen(int near, int size, int maxlen); +static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor); +static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h); + +static int w9966_init(struct w9966_dev* cam, struct parport* port); +static void w9966_term(struct w9966_dev* cam); + +static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state); +static inline void w9966_i2c_setscl(struct w9966_dev* cam, int state); +static inline int w9966_i2c_getsda(struct w9966_dev* cam); +static inline int w9966_i2c_getscl(struct w9966_dev* cam); +static int w9966_i2c_wbyte(struct w9966_dev* cam, int data); +static int w9966_i2c_rbyte(struct w9966_dev* cam); + +static int w9966_v4l_open(struct video_device *vdev, int mode); +static void w9966_v4l_close(struct video_device *vdev); +static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg); +static long w9966_v4l_read(struct video_device *vdev, char *buf, unsigned long count, int noblock); + +/* + * Private function defines + */ + + +// Set camera phase flags, so we know what to uninit when terminating +static inline void w9966_setState(struct w9966_dev* cam, int mask, int val) +{ + cam->dev_state = (cam->dev_state & ~mask) ^ val; +} + +// Get camera phase flags +static inline int w9966_getState(struct w9966_dev* cam, int mask, int val) +{ + return ((cam->dev_state & mask) == val); +} + +// Claim parport for ourself +static inline void w9966_pdev_claim(struct w9966_dev* cam) +{ + if (w9966_getState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED)) + return; + parport_claim_or_block(cam->pdev); + w9966_setState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED); +} + +// Release parport for others to use +static inline void w9966_pdev_release(struct w9966_dev* cam) +{ + if (w9966_getState(cam, W9966_STATE_CLAIMED, 0)) + return; + parport_release(cam->pdev); + w9966_setState(cam, W9966_STATE_CLAIMED, 0); +} + +// Read register from W9966 interface-chip +// Expects a claimed pdev +// -1 on error, else register data (byte) +static int w9966_rReg(struct w9966_dev* cam, int reg) +{ + // ECP, read, regtransfer, REG, REG, REG, REG, REG + const unsigned char addr = 0x80 | (reg & 0x1f); + unsigned char val; + + if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0) + return -1; + if (parport_write(cam->pport, &addr, 1) != 1) + return -1; + if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0) + return -1; + if (parport_read(cam->pport, &val, 1) != 1) + return -1; + + return val; +} + +// Write register to W9966 interface-chip +// Expects a claimed pdev +// -1 on error +static int w9966_wReg(struct w9966_dev* cam, int reg, int data) +{ + // ECP, write, regtransfer, REG, REG, REG, REG, REG + const unsigned char addr = 0xc0 | (reg & 0x1f); + const unsigned char val = data; + + if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0) + return -1; + if (parport_write(cam->pport, &addr, 1) != 1) + return -1; + if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0) + return -1; + if (parport_write(cam->pport, &val, 1) != 1) + return -1; + + return 0; +} + +// Initialize camera device. Setup all internal flags, set a +// default video mode, setup ccd-chip, register v4l device etc.. +// Also used for 'probing' of hardware. +// -1 on error +static int w9966_init(struct w9966_dev* cam, struct parport* port) +{ + if (cam->dev_state != 0) + return -1; + + cam->pport = port; + +// Select requested transfer mode + switch(parmode) + { + default: // Auto-detect (priority: hw-ecp, hw-epp, sw-ecp) + case 0: + if (port->modes & PARPORT_MODE_ECP) + cam->ppmode = IEEE1284_MODE_ECP; + else if (port->modes & PARPORT_MODE_EPP) + cam->ppmode = IEEE1284_MODE_EPP; + else + cam->ppmode = IEEE1284_MODE_ECP; + break; + case 1: // hw- or sw-ecp + cam->ppmode = IEEE1284_MODE_ECP; + break; + case 2: // hw- or sw-epp + cam->ppmode = IEEE1284_MODE_EPP; + break; + } + +// Tell the parport driver that we exists + cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL); + if (cam->pdev == NULL) { + DPRINTF("parport_register_device() failed\n"); + return -1; + } + w9966_setState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV); + + w9966_pdev_claim(cam); + +// Setup a default capture mode + if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) { + DPRINTF("w9966_setup() failed.\n"); + return -1; + } + + w9966_pdev_release(cam); + +// Fill in the video_device struct and register us to v4l + memset(&cam->vdev, 0, sizeof(struct video_device)); + strcpy(cam->vdev.name, W9966_DRIVERNAME); + cam->vdev.type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; + cam->vdev.hardware = VID_HARDWARE_W9966; + cam->vdev.open = &w9966_v4l_open; + cam->vdev.close = &w9966_v4l_close; + cam->vdev.read = &w9966_v4l_read; + cam->vdev.ioctl = &w9966_v4l_ioctl; + cam->vdev.priv = (void*)cam; + cam->vdev.owner = THIS_MODULE; + + if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER) == -1) + return -1; + + w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV); + + // All ok + printk( + "w9966cf: Found and initialized a webcam on %s.\n", + cam->pport->name + ); + return 0; +} + + +// Terminate everything gracefully +static void w9966_term(struct w9966_dev* cam) +{ +// Unregister from v4l + if (w9966_getState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) { + video_unregister_device(&cam->vdev); + w9966_setState(cam, W9966_STATE_VDEV, 0); + } + +// Terminate from IEEE1284 mode and release pdev block + if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) { + w9966_pdev_claim(cam); + parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT); + w9966_pdev_release(cam); + } + +// Unregister from parport + if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) { + parport_unregister_device(cam->pdev); + w9966_setState(cam, W9966_STATE_PDEV, 0); + } +} + + +// Find a good length for capture window (used both for W and H) +// A bit ugly but pretty functional. The capture length +// have to match the downscale +static int w9966_findlen(int near, int size, int maxlen) +{ + int bestlen = size; + int besterr = abs(near - bestlen); + int len; + + for(len = size+1;len < maxlen;len++) + { + int err; + if ( ((64*size) %len) != 0) + continue; + + err = abs(near - len); + + // Only continue as long as we keep getting better values + if (err > besterr) + break; + + besterr = err; + bestlen = len; + } + + return bestlen; +} + +// Modify capture window (if necessary) +// and calculate downscaling +// Return -1 on error +static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor) +{ + int maxlen = max - min; + int len = *end - *beg + 1; + int newlen = w9966_findlen(len, size, maxlen); + int err = newlen - len; + + // Check for bad format + if (newlen > maxlen || newlen < size) + return -1; + + // Set factor (6 bit fixed) + *factor = (64*size) / newlen; + if (*factor == 64) + *factor = 0x00; // downscale is disabled + else + *factor |= 0x80; // set downscale-enable bit + + // Modify old beginning and end + *beg -= err / 2; + *end += err - (err / 2); + + // Move window if outside borders + if (*beg < min) { + *end += min - *beg; + *beg += min - *beg; + } + if (*end > max) { + *beg -= *end - max; + *end -= *end - max; + } + + return 0; +} + +// Setup the cameras capture window etc. +// Expects a claimed pdev +// return -1 on error +static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h) +{ + unsigned int i; + unsigned int enh_s, enh_e; + unsigned char scale_x, scale_y; + unsigned char regs[0x1c]; + unsigned char saa7111_regs[] = { + 0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00, + 0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00, + 0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0 + }; + + + if (w*h*2 > W9966_SRAMSIZE) + { + DPRINTF("capture window exceeds SRAM size!.\n"); + w = 200; h = 160; // Pick default values + } + + if (w < 2) w = 2; + if (h < 1) h = 1; + if (w > W9966_WND_MAX_W) w = W9966_WND_MAX_W; + if (h > W9966_WND_MAX_H) h = W9966_WND_MAX_H; + + cam->width = w; + cam->height = h; + + enh_s = 0; + enh_e = w*h*2; + +// Modify capture window if necessary and calculate downscaling + if ( + w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 || + w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0 + ) return -1; + + DPRINTF( + "%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n", + w, h, x1, x2, y1, y2, scale_x&~0x80, scale_y&~0x80 + ); + +// Setup registers + regs[0x00] = 0x00; // Set normal operation + regs[0x01] = 0x18; // Capture mode + regs[0x02] = scale_y; // V-scaling + regs[0x03] = scale_x; // H-scaling + + // Capture window + regs[0x04] = (x1 & 0x0ff); // X-start (8 low bits) + regs[0x05] = (x1 & 0x300)>>8; // X-start (2 high bits) + regs[0x06] = (y1 & 0x0ff); // Y-start (8 low bits) + regs[0x07] = (y1 & 0x300)>>8; // Y-start (2 high bits) + regs[0x08] = (x2 & 0x0ff); // X-end (8 low bits) + regs[0x09] = (x2 & 0x300)>>8; // X-end (2 high bits) + regs[0x0a] = (y2 & 0x0ff); // Y-end (8 low bits) + + regs[0x0c] = W9966_SRAMID; // SRAM-banks (1x 128kb) + + // Enhancement layer + regs[0x0d] = (enh_s& 0x000ff); // Enh. start (0-7) + regs[0x0e] = (enh_s& 0x0ff00)>>8; // Enh. start (8-15) + regs[0x0f] = (enh_s& 0x70000)>>16; // Enh. start (16-17/18??) + regs[0x10] = (enh_e& 0x000ff); // Enh. end (0-7) + regs[0x11] = (enh_e& 0x0ff00)>>8; // Enh. end (8-15) + regs[0x12] = (enh_e& 0x70000)>>16; // Enh. end (16-17/18??) + + // Misc + regs[0x13] = 0x40; // VEE control (raw 4:2:2) + regs[0x17] = 0x00; // ??? + regs[0x18] = cam->i2c_state = 0x00; // Serial bus + regs[0x19] = 0xff; // I/O port direction control + regs[0x1a] = 0xff; // I/O port data register + regs[0x1b] = 0x10; // ??? + +// Reset (ECP-fifo & serial-bus) + if (w9966_wReg(cam, 0x00, 0x03) == -1) + return -1; + +// Write regs to w9966cf chip + for (i = 0; i < 0x1c; i++) + if (w9966_wReg(cam, i, regs[i]) == -1) + return -1; + +// Write regs to saa7111 chip + for (i = 0; i < 0x20; i++) + if (w9966_wReg_i2c(cam, i, saa7111_regs[i]) == -1) + return -1; + + return 0; +} + +/* + * Ugly and primitive i2c protocol functions + */ + +// Sets the data line on the i2c bus. +// Expects a claimed pdev. Add error checking?? +static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state) +{ + if (state) + cam->i2c_state |= W9966_I2C_W_DATA; + else + cam->i2c_state &= ~W9966_I2C_W_DATA; + + w9966_wReg(cam, 0x18, cam->i2c_state); + udelay(5); +} + +// Sets the clock line on the i2c bus. +// Expects a claimed pdev. Add error checking?? +static inline void w9966_i2c_setscl(struct w9966_dev* cam, int state) +{ + if (state) + cam->i2c_state |= W9966_I2C_W_CLOCK; + else + cam->i2c_state &= ~W9966_I2C_W_CLOCK; + + w9966_wReg(cam, 0x18, cam->i2c_state); + udelay(5); + + // we go to high, we also expect the peripheral to ack. + // maybe we should add a timeout + if (state) + while (!w9966_i2c_getscl(cam)){} +} + +// Get peripheral data line +// Expects a claimed pdev. Maybe we should add error checking. +static inline int w9966_i2c_getsda(struct w9966_dev* cam) +{ + const unsigned char state = w9966_rReg(cam, 0x18); + return ((state & W9966_I2C_R_DATA) > 0); +} + +// Get peripheral clock line +// Expects a claimed pdev. Maybe we should add error checking. +static inline int w9966_i2c_getscl(struct w9966_dev* cam) +{ + const unsigned char state = w9966_rReg(cam, 0x18); + return ((state & W9966_I2C_R_CLOCK) > 0); +} + +// Write a byte with ack on the i2c bus. Good for both +// addresses and data. Expects a claimed pdev. +// Maybe we should add error checking. +static int w9966_i2c_wbyte(struct w9966_dev* cam, int data) +{ + int i; + for (i = 7; i >= 0; i--) + { + w9966_i2c_setsda(cam, (data >> i) & 0x01); + + w9966_i2c_setscl(cam, 1); + w9966_i2c_setscl(cam, 0); + } + + w9966_i2c_setsda(cam, 1); + w9966_i2c_setscl(cam, 1); + + w9966_i2c_setscl(cam, 0); + return 0; +} + +// Read a data byte with ack from the i2c-bus +// Expects a claimed pdev. Maybe we should add error checking. +static int w9966_i2c_rbyte(struct w9966_dev* cam) +{ + unsigned char data = 0x00; + int i; + + w9966_i2c_setsda(cam, 1); + + for (i = 0; i < 8; i++) + { + w9966_i2c_setscl(cam, 1); + data = data << 1; + if (w9966_i2c_getsda(cam)) + data |= 0x01; + + w9966_i2c_setscl(cam, 0); + } + return data; +} + +// Read a register from the i2c device. +// Expects claimed pdev. Ignores errors for now. +static int w9966_rReg_i2c(struct w9966_dev* cam, int reg) +{ + unsigned char data; + + w9966_i2c_setsda(cam, 0); + w9966_i2c_setscl(cam, 0); + + w9966_i2c_wbyte(cam, W9966_I2C_W_ID); + + w9966_i2c_wbyte(cam, reg); + + w9966_i2c_setsda(cam, 1); + w9966_i2c_setscl(cam, 1); + w9966_i2c_setsda(cam, 0); + w9966_i2c_setscl(cam, 0); + + w9966_i2c_wbyte(cam, W9966_I2C_R_ID); + + data = w9966_i2c_rbyte(cam); + + w9966_i2c_setsda(cam, 0); + w9966_i2c_setscl(cam, 1); + w9966_i2c_setsda(cam, 1); + + return data; +} + +// Write a register from the i2c device. +// Expects claimed pdev. Ignores errors for now. +static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data) +{ + w9966_i2c_setsda(cam, 0); + w9966_i2c_setscl(cam, 0); + + w9966_i2c_wbyte(cam, W9966_I2C_W_ID); + + w9966_i2c_wbyte(cam, reg); + + w9966_i2c_wbyte(cam, data); + + w9966_i2c_setsda(cam, 0); + w9966_i2c_setscl(cam, 1); + w9966_i2c_setsda(cam, 1); + + return 0; +} + +/* + * Video4linux interfacing + */ + +static int w9966_v4l_open(struct video_device *vdev, int flags) +{ + return 0; +} + +static void w9966_v4l_close(struct video_device *vdev) +{ +} + +static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) +{ + struct w9966_dev *cam = (struct w9966_dev*)vdev->priv; + + switch(cmd) + { + case VIDIOCGCAP: + { + struct video_capability vcap = { + W9966_DRIVERNAME, // name + VID_TYPE_CAPTURE | VID_TYPE_SCALES, // type + 1, 0, // vid, aud channels + W9966_WND_MAX_W, // max w + W9966_WND_MAX_H, // max h + 2, 1 // min w, min h + }; + + if(copy_to_user(arg, &vcap, sizeof(vcap)) != 0) + return -EFAULT; + + return 0; + } + case VIDIOCGCHAN: + { + struct video_channel vch; + if(copy_from_user(&vch, arg, sizeof(vch)) != 0) + return -EFAULT; + + if(vch.channel != 0) // We only support one channel (#0) + return -EINVAL; + + strcpy(vch.name, "CCD-input"); + vch.flags = 0; // We have no tuner or audio + vch.tuners = 0; + vch.type = VIDEO_TYPE_CAMERA; + vch.norm = 0; // ??? + + if(copy_to_user(arg, &vch, sizeof(vch)) != 0) + return -EFAULT; + + return 0; + } + case VIDIOCSCHAN: + { + struct video_channel vch; + if(copy_from_user(&vch, arg, sizeof(vch) ) != 0) + return -EFAULT; + + if(vch.channel != 0) + return -EINVAL; + + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner vtune; + if(copy_from_user(&vtune, arg, sizeof(vtune)) != 0) + return -EFAULT; + + if(vtune.tuner != 0); + return -EINVAL; + + strcpy(vtune.name, "Foo-tuner"); + vtune.rangelow = 0; + vtune.rangehigh = 0; + vtune.flags = VIDEO_TUNER_NORM; + vtune.mode = VIDEO_MODE_AUTO; + vtune.signal = 0xffff; + + if(copy_to_user(arg, &vtune, sizeof(vtune)) != 0) + return -EFAULT; + + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner vtune; + if (copy_from_user(&vtune, arg, sizeof(vtune)) != 0) + return -EFAULT; + + if (vtune.tuner != 0) + return -EINVAL; + + if (vtune.mode != VIDEO_MODE_AUTO) + return -EINVAL; + + return 0; + } + case VIDIOCGPICT: + { + struct video_picture vpic = { + 0x8000, // brightness + 0x8000, // hue + 0x8000, // color + 0x8000, // contrast + 0x8000, // whiteness + 16, VIDEO_PALETTE_YUV422// bpp, palette format + }; + + if(copy_to_user(arg, &vpic, sizeof(vpic)) != 0) + return -EFAULT; + + return 0; + } + case VIDIOCSPICT: + { + struct video_picture vpic; + if(copy_from_user(&vpic, arg, sizeof(vpic)) != 0) + return -EFAULT; + + if (vpic.depth != 16 || vpic.palette != VIDEO_PALETTE_YUV422) + return -EINVAL; + + // Just ignore any parameters (hue, color etc..) for now + return 0; + } + case VIDIOCSWIN: + { + int ret; + struct video_window vwin; + + if (copy_from_user(&vwin, arg, sizeof(vwin)) != 0) + return -EFAULT; + if (vwin.flags != 0) + return -EINVAL; + if (vwin.clipcount != 0) + return -EINVAL; + if (vwin.width < 2 || vwin.width > W9966_WND_MAX_W) + return -EINVAL; + if (vwin.height < 1 || vwin.height > W9966_WND_MAX_H) + return -EINVAL; + + // Update camera regs + w9966_pdev_claim(cam); + ret = w9966_setup(cam, 0, 0, 1023, 1023, vwin.width, vwin.height); + w9966_pdev_release(cam); + + if (ret != 0) { + DPRINTF("VIDIOCSWIN: w9966_setup() failed.\n"); + return -EFAULT; + } + + return 0; + } + case VIDIOCGWIN: + { + struct video_window vwin; + memset(&vwin, 0, sizeof(vwin)); + + vwin.width = cam->width; + vwin.height = cam->height; + + if(copy_to_user(arg, &vwin, sizeof(vwin)) != 0) + return -EFAULT; + + return 0; + } + // Unimplemented + case VIDIOCCAPTURE: + case VIDIOCGFBUF: + case VIDIOCSFBUF: + case VIDIOCKEY: + case VIDIOCGFREQ: + case VIDIOCSFREQ: + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + return -EINVAL; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +// Capture and read data in normal 16bit YUV422 format +static long w9966_v4l_read(struct video_device *vdev, char *buf, unsigned long count, int noblock) +{ + struct w9966_dev *cam = (struct w9966_dev *)vdev->priv; + unsigned char addr = 0xa0; // ECP, read, CCD-transfer, 00000 + unsigned char* dest = (unsigned char*)buf; + unsigned long dleft = count; + + // Why would anyone want more than this?? + if (count > cam->width * cam->height * 2) + DPRINTF("Requested %lu bytes, full frame is %d bytes.\n", count, cam->width*cam->height*2); + + w9966_pdev_claim(cam); + w9966_wReg(cam, 0x00, 0x02); // Reset ECP-FIFO buffer + w9966_wReg(cam, 0x00, 0x00); // Return to normal operation + w9966_wReg(cam, 0x01, 0x98); // Enable capture + + // write special capture-addr and negotiate into data transfer + if ( + (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0 )|| + (parport_write(cam->pport, &addr, 1) != 1 )|| + (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0 ) + ) { + w9966_pdev_release(cam); + return -EFAULT; + } + + while(dleft > 0) + { + unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft; + unsigned char tbuf[W9966_RBUFFER]; + + if (parport_read(cam->pport, tbuf, tsize) < tsize) { + w9966_pdev_release(cam); + return -EFAULT; + } + if (copy_to_user(dest, tbuf, tsize) != 0) { + w9966_pdev_release(cam); + return -EFAULT; + } + dest += tsize; + dleft -= tsize; + } + + w9966_wReg(cam, 0x01, 0x18); // Disable capture + w9966_pdev_release(cam); + + return count; +} + + +// Called once for every parport on init +static void w9966_attach(struct parport *port) +{ + int i; + + for (i = 0; i < W9966_MAXCAMS; i++) + { + if (w9966_cams[i].dev_state != 0) // Cam is already assigned + continue; + if ( + strcmp(pardev[i], "aggressive") == 0 || + strcmp(pardev[i], port->name) == 0 + ) { + if (w9966_init(&w9966_cams[i], port) != 0) + w9966_term(&w9966_cams[i]); + break; // return + } + } +} + +// Called once for every parport on termination +static void w9966_detach(struct parport *port) +{ + int i; + for (i = 0; i < W9966_MAXCAMS; i++) + if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port) + w9966_term(&w9966_cams[i]); +} + + +static struct parport_driver w9966_ppd = { + W9966_DRIVERNAME, + w9966_attach, + w9966_detach, + NULL +}; + +// Module entry point +static int __init w9966_mod_init(void) +{ + int i; + for (i = 0; i < W9966_MAXCAMS; i++) + w9966_cams[i].dev_state = 0; + + return parport_register_driver(&w9966_ppd); +} + +// Module cleanup +static void __exit w9966_mod_term(void) +{ + parport_unregister_driver(&w9966_ppd); +} + +module_init(w9966_mod_init); +module_exit(w9966_mod_term); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/zoran.h linux.ac/drivers/media/video/zoran.h --- linux.vanilla/drivers/media/video/zoran.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/media/video/zoran.h Tue Apr 3 18:47:11 2001 @@ -0,0 +1,374 @@ +/* + zoran - Iomega Buz driver + + Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de> + + based on + + zoran.0.0.3 Copyright (C) 1998 Dave Perks <dperks@ibm.net> + + and + + bttv - Bt848 frame grabber driver + Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) + + 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 _BUZ_H_ +#define _BUZ_H_ + +#include <linux/config.h> + +#if LINUX_VERSION_CODE < 0x20212 +typedef struct wait_queue *wait_queue_head_t; +#endif + +/* The Buz only supports a maximum width of 720, but some V4L + applications (e.g. xawtv are more happy with 768). + If XAWTV_HACK is defined, we try to fake a device with bigger width */ + +//#define XAWTV_HACK + +//#ifdef XAWTV_HACK +//#define BUZ_MAX_WIDTH 768 /* never display more than 768 pixels */ +#define BUZ_MAX_WIDTH (zr->timing->Wa) +//#else +//#define BUZ_MAX_WIDTH 720 /* never display more than 720 pixels */ +//#endif +//#define BUZ_MAX_HEIGHT 576 /* never display more than 576 rows */ +#define BUZ_MAX_HEIGHT (zr->timing->Ha) +#define BUZ_MIN_WIDTH 32 /* never display less than 32 pixels */ +#define BUZ_MIN_HEIGHT 24 /* never display less than 24 rows */ + +struct zoran_requestbuffers { + unsigned long count; /* Number of buffers for MJPEG grabbing */ + unsigned long size; /* Size PER BUFFER in bytes */ +}; + +struct zoran_sync { + unsigned long frame; /* number of buffer that has been free'd */ + unsigned long length; /* number of code bytes in buffer (capture only) */ + unsigned long seq; /* frame sequence number */ + struct timeval timestamp; /* timestamp */ +}; + +struct zoran_status { + int input; /* Input channel, has to be set prior to BUZIOC_G_STATUS */ + int signal; /* Returned: 1 if valid video signal detected */ + int norm; /* Returned: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ + int color; /* Returned: 1 if color signal detected */ +}; + +struct zoran_params { + + /* The following parameters can only be queried */ + + int major_version; /* Major version number of driver */ + int minor_version; /* Minor version number of driver */ + + /* Main control parameters */ + + int input; /* Input channel: 0 = Composite, 1 = S-VHS */ + int norm; /* Norm: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ + int decimation; /* decimation of captured video, + enlargement of video played back. + Valid values are 1, 2, 4 or 0. + 0 is a special value where the user + has full control over video scaling */ + + /* The following parameters only have to be set if decimation==0, + for other values of decimation they provide the data how the image is captured */ + + int HorDcm; /* Horizontal decimation: 1, 2 or 4 */ + int VerDcm; /* Vertical decimation: 1 or 2 */ + int TmpDcm; /* Temporal decimation: 1 or 2, + if TmpDcm==2 in capture every second frame is dropped, + in playback every frame is played twice */ + int field_per_buff; /* Number of fields per buffer: 1 or 2 */ + int img_x; /* start of image in x direction */ + int img_y; /* start of image in y direction */ + int img_width; /* image width BEFORE decimation, + must be a multiple of HorDcm*16 */ + int img_height; /* image height BEFORE decimation, + must be a multiple of VerDcm*8 */ + + /* --- End of parameters for decimation==0 only --- */ + + /* JPEG control parameters */ + + int quality; /* Measure for quality of compressed images. + Scales linearly with the size of the compressed images. + Must be beetween 0 and 100, 100 is a compression + ratio of 1:4 */ + + int odd_even; /* Which field should come first ??? */ + + int APPn; /* Number of APP segment to be written, must be 0..15 */ + int APP_len; /* Length of data in JPEG APPn segment */ + char APP_data[60]; /* Data in the JPEG APPn segment. */ + + int COM_len; /* Length of data in JPEG COM segment */ + char COM_data[60]; /* Data in JPEG COM segment */ + + unsigned long jpeg_markers; /* Which markers should go into the JPEG output. + Unless you exactly know what you do, leave them untouched. + Inluding less markers will make the resulting code + smaller, but there will be fewer aplications + which can read it. + The presence of the APP and COM marker is + influenced by APP0_len and COM_len ONLY! */ +#define JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */ +#define JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */ +#define JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */ +#define JPEG_MARKER_COM (1<<6) /* Comment segment */ +#define JPEG_MARKER_APP (1<<7) /* App segment, driver will allways use APP0 */ + + int VFIFO_FB; /* Flag for enabling Video Fifo Feedback. + If this flag is turned on and JPEG decompressing + is going to the screen, the decompress process + is stopped every time the Video Fifo is full. + This enables a smooth decompress to the screen + but the video output signal will get scrambled */ + + /* Misc */ + + char reserved[312]; /* Makes 512 bytes for this structure */ +}; + +/* +Private IOCTL to set up for displaying MJPEG +*/ +#define BUZIOC_G_PARAMS _IOR ('v', BASE_VIDIOCPRIVATE+0, struct zoran_params) +#define BUZIOC_S_PARAMS _IOWR('v', BASE_VIDIOCPRIVATE+1, struct zoran_params) +#define BUZIOC_REQBUFS _IOWR('v', BASE_VIDIOCPRIVATE+2, struct zoran_requestbuffers) +#define BUZIOC_QBUF_CAPT _IOW ('v', BASE_VIDIOCPRIVATE+3, int) +#define BUZIOC_QBUF_PLAY _IOW ('v', BASE_VIDIOCPRIVATE+4, int) +#define BUZIOC_SYNC _IOR ('v', BASE_VIDIOCPRIVATE+5, struct zoran_sync) +#define BUZIOC_G_STATUS _IOWR('v', BASE_VIDIOCPRIVATE+6, struct zoran_status) + + +#ifdef __KERNEL__ + +#define BUZ_NUM_STAT_COM 4 +#define BUZ_MASK_STAT_COM 3 + +#define BUZ_MAX_FRAME 256 /* Must be a power of 2 */ +#define BUZ_MASK_FRAME 255 /* Must be BUZ_MAX_FRAME-1 */ + +#if VIDEO_MAX_FRAME <= 32 +# define V4L_MAX_FRAME 32 +#elif VIDEO_MAX_FRAME <= 64 +# define V4L_MAX_FRAME 64 +#else +# error "Too many video frame buffers to handle" +#endif +#define V4L_MASK_FRAME (V4L_MAX_FRAME - 1) + + +#include "zr36057.h" + +enum card_type { + UNKNOWN = 0, + DC10, + DC10plus, + LML33, + BUZ +}; + +enum zoran_codec_mode { + BUZ_MODE_IDLE, /* nothing going on */ + BUZ_MODE_MOTION_COMPRESS, /* grabbing frames */ + BUZ_MODE_MOTION_DECOMPRESS, /* playing frames */ + BUZ_MODE_STILL_COMPRESS, /* still frame conversion */ + BUZ_MODE_STILL_DECOMPRESS /* still frame conversion */ +}; + +enum zoran_buffer_state { + BUZ_STATE_USER, /* buffer is owned by application */ + BUZ_STATE_PEND, /* buffer is queued in pend[] ready to feed to I/O */ + BUZ_STATE_DMA, /* buffer is queued in dma[] for I/O */ + BUZ_STATE_DONE /* buffer is ready to return to application */ +}; + +struct zoran_gbuffer { + u32 *frag_tab; /* addresses of frag table */ + u32 frag_tab_bus; /* same value cached to save time in ISR */ + enum zoran_buffer_state state; /* non-zero if corresponding buffer is in use in grab queue */ + struct zoran_sync bs; /* DONE: info to return to application */ +}; + +struct v4l_gbuffer { + char *fbuffer; /* virtual address of frame buffer */ + unsigned long fbuffer_phys; /* physical address of frame buffer */ + unsigned long fbuffer_bus; /* bus address of frame buffer */ + enum zoran_buffer_state state; /* state: unused/pending/done */ +}; + +struct tvnorm { + u16 Wt, Wa, HStart, HSyncStart, Ht, Ha, VStart; +}; + +struct zoran { + struct video_device video_dev; + struct i2c_bus i2c; + + int initialized; /* flag if zoran has been correctly initalized */ + int user; /* number of current users (0 or 1) */ + enum card_type card; + struct tvnorm *timing; + + unsigned short id; /* number of this device */ + char name[32]; /* name of this device */ + struct pci_dev *pci_dev; /* PCI device */ + unsigned char revision; /* revision of zr36057 */ + unsigned int zr36057_adr; /* bus address of IO mem returned by PCI BIOS */ + unsigned char *zr36057_mem; /* pointer to mapped IO memory */ + + int map_mjpeg_buffers; /* Flag which bufferset will map by next mmap() */ + + spinlock_t lock; /* Spinlock */ + + /* Video for Linux parameters */ + + struct video_picture picture; /* Current picture params */ + struct video_buffer buffer; /* Current buffer params */ + struct video_window window; /* Current window params */ + int buffer_set, window_set; /* Flags if the above structures are set */ + int video_interlace; /* Image on screen is interlaced */ + + u32 *overlay_mask; + wait_queue_head_t v4l_capq; + + int v4l_overlay_active; /* Overlay grab is activated */ + int v4l_memgrab_active; /* Memory grab is activated */ + + int v4l_grab_frame; /* Frame number being currently grabbed */ +#define NO_GRAB_ACTIVE (-1) + int v4l_grab_seq; /* Number of frames grabbed */ + int gwidth; /* Width of current memory capture */ + int gheight; /* Height of current memory capture */ + int gformat; /* Format of ... */ + int gbpl; /* byte per line of ... */ + + /* V4L grab queue of frames pending */ + + unsigned v4l_pend_head; + unsigned v4l_pend_tail; + int v4l_pend[V4L_MAX_FRAME]; + + struct v4l_gbuffer v4l_gbuf[VIDEO_MAX_FRAME]; /* V4L buffers' info */ + + /* Buz MJPEG parameters */ + + unsigned long jpg_nbufs; /* Number of buffers */ + unsigned long jpg_bufsize; /* Size of mjpeg buffers in bytes */ + int jpg_buffers_allocated; /* Flag if buffers are allocated */ + int need_contiguous; /* Flag if contiguous buffers are needed */ + + enum zoran_codec_mode codec_mode; /* status of codec */ + struct zoran_params params; /* structure with a lot of things to play with */ + + wait_queue_head_t jpg_capq; /* wait here for grab to finish */ + + /* grab queue counts/indices, mask with BUZ_MASK_STAT_COM before using as index */ + /* (dma_head - dma_tail) is number active in DMA, must be <= BUZ_NUM_STAT_COM */ + /* (value & BUZ_MASK_STAT_COM) corresponds to index in stat_com table */ + unsigned long jpg_que_head; /* Index where to put next buffer which is queued */ + unsigned long jpg_dma_head; /* Index of next buffer which goes into stat_com */ + unsigned long jpg_dma_tail; /* Index of last buffer in stat_com */ + unsigned long jpg_que_tail; /* Index of last buffer in queue */ + unsigned long jpg_seq_num; /* count of frames since grab/play started */ + unsigned long jpg_err_seq; /* last seq_num before error */ + unsigned long jpg_err_shift; + unsigned long jpg_queued_num; /* count of frames queued since grab/play started */ + + /* zr36057's code buffer table */ + u32 *stat_com; /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */ + + /* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */ + int jpg_pend[BUZ_MAX_FRAME]; + + /* array indexed by frame number */ + struct zoran_gbuffer jpg_gbuf[BUZ_MAX_FRAME]; /* MJPEG buffers' info */ + + /* Additional stuff for testing */ +#ifdef CONFIG_PROC_FS + + struct proc_dir_entry *zoran_proc; + +#endif + int testing; + int jpeg_error; + int intr_counter_GIRQ1; + int intr_counter_GIRQ0; + int intr_counter_CodRepIRQ; + int intr_counter_JPEGRepIRQ; + int field_counter; + int IRQ1_in; + int IRQ1_out; + int JPEG_in; + int JPEG_out; + int JPEG_0; + int JPEG_1; + int END_event_missed; + int JPEG_missed; + int JPEG_error; + int num_errors; + int JPEG_max_missed; + int JPEG_min_missed; + + u32 last_isr; + unsigned long frame_num; + + wait_queue_head_t test_q; +}; + +#endif + +/*The following should be done in more portable way. It depends on define + of _ALPHA_BUZ in the Makefile.*/ + +#ifdef _ALPHA_BUZ +#define btwrite(dat,adr) writel((dat),(char *) (zr->zr36057_adr+(adr))) +#define btread(adr) readl(zr->zr36057_adr+(adr)) +#else +#define btwrite(dat,adr) writel((dat), (char *) (zr->zr36057_mem+(adr))) +#define btread(adr) readl(zr->zr36057_mem+(adr)) +#endif + +#define btand(dat,adr) btwrite((dat) & btread(adr), adr) +#define btor(dat,adr) btwrite((dat) | btread(adr), adr) +#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) + +#define I2C_TSA5522 0xc2 +#define I2C_TDA9850 0xb6 +#define I2C_HAUPEE 0xa0 +#define I2C_STBEE 0xae +#define I2C_SAA7111 0x48 +#define I2C_SAA7110 0x9c +#define I2C_SAA7185 0x88 +//#define I2C_ADV7175 0xd4 +#define I2C_ADV7175 0x54 + +#define TDA9850_CON1 0x04 +#define TDA9850_CON2 0x05 +#define TDA9850_CON3 0x06 +#define TDA9850_CON4 0x07 +#define TDA9850_ALI1 0x08 +#define TDA9850_ALI2 0x09 +#define TDA9850_ALI3 0x0a + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/zoran_procfs.c linux.ac/drivers/media/video/zoran_procfs.c --- linux.vanilla/drivers/media/video/zoran_procfs.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/media/video/zoran_procfs.c Tue Apr 3 17:54:46 2001 @@ -0,0 +1,170 @@ +#include <linux/config.h> +#include <linux/ctype.h> + +struct procfs_params_zr36067 { + char *name; + short reg; + u32 mask; + short bit; +}; + +static struct procfs_params_zr36067 zr67[] = { + {"HSPol", 0x000, 1, 30}, + {"HStart", 0x000, 0x3ff, 10}, + {"HEnd", 0x000, 0x3ff, 0}, + + {"VSPol", 0x004, 1, 30}, + {"VStart", 0x004, 0x3ff, 10}, + {"VEnd", 0x004, 0x3ff, 0}, + + {"ExtFl", 0x008, 1, 26}, + {"TopField", 0x008, 1, 25}, + {"VCLKPol", 0x008, 1, 24}, + {"DupFld", 0x008, 1, 20}, + {"LittleEndian", 0x008, 1, 0}, + + {"HsyncStart", 0x10c, 0xffff, 16}, + {"LineTot", 0x10c, 0xffff, 0}, + + {"NAX", 0x110, 0xffff, 16}, + {"PAX", 0x110, 0xffff, 0}, + + {"NAY", 0x114, 0xffff, 16}, + {"PAY", 0x114, 0xffff, 0}, +/* {"",,,}, */ + + {NULL, 0, 0, 0}, +}; + +static void setparam(struct zoran *zr, char *name, char *sval) +{ + int i, reg0, reg, val; + i = 0; + while (zr67[i].name != NULL) { + if (!strncmp(name, zr67[i].name, strlen(zr67[i].name))) { + reg = reg0 = btread(zr67[i].reg); + reg &= ~(zr67[i].mask << zr67[i].bit); + if (!isdigit(sval[0])) + break; + val = simple_strtoul(sval, NULL, 0); + if ((val & ~zr67[i].mask)) + break; + reg |= (val & zr67[i].mask) << zr67[i].bit; + printk(KERN_INFO "%s: setparam: setting ZR36067 register 0x%03x: 0x%08x=>0x%08x %s=%d\n", + zr->name, zr67[i].reg, reg0, reg, zr67[i].name, val); + btwrite(reg, zr67[i].reg); + break; + } + i++; + } +} + +/* This macro was stolen from /usr/src/drivers/char/nvram.c and modified */ +#define PRINT_PROC(args...) \ + do { \ + if (begin + len > offset + size) { \ + *eof = 0; \ + break; \ + } \ + len += sprintf( buffer+len, ##args ); \ + if (begin + len < offset) { \ + begin += len; \ + len = 0; \ + } \ + } while(0) + +static int zoran_read_proc(char *buffer, char **start, off_t offset, int size, int *eof, void *data) +{ +#ifdef CONFIG_PROC_FS + int len = 0; + off_t begin = 0; + + int i; + struct zoran *zr; + + zr = (struct zoran *) data; + DEBUG2(printk(KERN_INFO "%s: read_proc: buffer=%x, offset=%d, size=%d, data=%x\n", zr->name, (int) buffer, (int) offset, size, (int) data)); + *eof = 1; + PRINT_PROC("ZR36067 registers:"); + for (i = 0; i < 0x130; i += 4) { + if (!(i % 16)) { + PRINT_PROC("\n%03X", i); + } + PRINT_PROC(" %08X ", btread(i)); + } + PRINT_PROC("\n"); + if (offset >= len + begin) { + return 0; + } + *start = buffer + begin - offset; + return ((size < begin + len - offset) ? size : begin + len - offset); +#endif + return 0; +} + +static int zoran_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) +{ +#ifdef CONFIG_PROC_FS + char *string, *sp; + char *line, *ldelim, *varname, *svar, *tdelim; + struct zoran *zr; + + zr = (struct zoran *) data; + + string = sp = vmalloc(count + 1); + if (!string) { + printk(KERN_ERR "%s: write_proc: can not allocate memory\n", zr->name); + return -ENOMEM; + } + memcpy(string, buffer, count); + string[count] = 0; + DEBUG2(printk(KERN_INFO "%s: write_proc: name=%s count=%lu data=%x\n", zr->name, file->f_dentry->d_name.name, count, (int) data)); + ldelim = " \t\n"; + tdelim = "="; + line = strpbrk(sp, ldelim); + while (line) { + *line = 0; + svar = strpbrk(sp, tdelim); + if (svar) { + *svar = 0; + varname = sp; + svar++; + setparam(zr, varname, svar); + } + sp = line + 1; + line = strpbrk(sp, ldelim); + } + vfree(string); +#endif + return count; +} + +static int zoran_proc_init(int i) +{ +#ifdef CONFIG_PROC_FS + char name[8]; + sprintf(name, "zoran%d", i); + if ((zoran[i].zoran_proc = create_proc_entry(name, 0, 0))) { + zoran[i].zoran_proc->read_proc = zoran_read_proc; + zoran[i].zoran_proc->write_proc = zoran_write_proc; + zoran[i].zoran_proc->data = &zoran[i]; + printk(KERN_INFO "%s: procfs entry /proc/%s allocated. data=%x\n", zoran[i].name, name, (int) zoran[i].zoran_proc->data); + } else { + printk(KERN_ERR "%s: Unable to initialise /proc/%s\n", zoran[i].name, name); + return 1; + } +#endif + return 0; +} + +static void zoran_proc_cleanup(int i) +{ +#ifdef CONFIG_PROC_FS + char name[8]; + sprintf(name, "zoran%d", i); + if (zoran[i].zoran_proc) { + remove_proc_entry(name, 0); + } + zoran[i].zoran_proc = NULL; +#endif +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/zr36057.h linux.ac/drivers/media/video/zr36057.h --- linux.vanilla/drivers/media/video/zr36057.h Tue Jul 6 04:09:40 1999 +++ linux.ac/drivers/media/video/zr36057.h Tue Apr 3 17:54:47 2001 @@ -1,22 +1,22 @@ /* - zr36057.h - zr36057 register offsets + zr36057.h - zr36057 register offsets - Copyright (C) 1998 Dave Perks <dperks@ibm.net> + Copyright (C) 1998 Dave Perks <dperks@ibm.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. - - 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 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 _ZR36057_H_ #define _ZR36057_H_ @@ -24,19 +24,19 @@ /* Zoran ZR36057 registers */ -#define ZR36057_VFEHCR 0x000 /* Video Front End, Horizontal Configuration Register */ +#define ZR36057_VFEHCR 0x000 /* Video Front End, Horizontal Configuration Register */ #define ZR36057_VFEHCR_HSPol (1<<30) #define ZR36057_VFEHCR_HStart 10 #define ZR36057_VFEHCR_HEnd 0 #define ZR36057_VFEHCR_Hmask 0x3ff -#define ZR36057_VFEVCR 0x004 /* Video Front End, Vertical Configuration Register */ +#define ZR36057_VFEVCR 0x004 /* Video Front End, Vertical Configuration Register */ #define ZR36057_VFEVCR_VSPol (1<<30) #define ZR36057_VFEVCR_VStart 10 #define ZR36057_VFEVCR_VEnd 0 #define ZR36057_VFEVCR_Vmask 0x3ff -#define ZR36057_VFESPFR 0x008 /* Video Front End, Scaler and Pixel Format Register */ +#define ZR36057_VFESPFR 0x008 /* Video Front End, Scaler and Pixel Format Register */ #define ZR36057_VFESPFR_ExtFl (1<<26) #define ZR36057_VFESPFR_TopField (1<<25) #define ZR36057_VFESPFR_VCLKPol (1<<24) @@ -52,65 +52,65 @@ #define ZR36057_VFESPFR_Pack24 (1<<1) #define ZR36057_VFESPFR_LittleEndian (1<<0) -#define ZR36057_VDTR 0x00c /* Video Display "Top" Register */ +#define ZR36057_VDTR 0x00c /* Video Display "Top" Register */ -#define ZR36057_VDBR 0x010 /* Video Display "Bottom" Register */ +#define ZR36057_VDBR 0x010 /* Video Display "Bottom" Register */ -#define ZR36057_VSSFGR 0x014 /* Video Stride, Status, and Frame Grab Register */ +#define ZR36057_VSSFGR 0x014 /* Video Stride, Status, and Frame Grab Register */ #define ZR36057_VSSFGR_DispStride 16 #define ZR36057_VSSFGR_VidOvf (1<<8) #define ZR36057_VSSFGR_SnapShot (1<<1) #define ZR36057_VSSFGR_FrameGrab (1<<0) -#define ZR36057_VDCR 0x018 /* Video Display Configuration Register */ +#define ZR36057_VDCR 0x018 /* Video Display Configuration Register */ #define ZR36057_VDCR_VidEn (1<<31) #define ZR36057_VDCR_MinPix 24 #define ZR36057_VDCR_Triton (1<<24) #define ZR36057_VDCR_VidWinHt 12 #define ZR36057_VDCR_VidWinWid 0 -#define ZR36057_MMTR 0x01c /* Masking Map "Top" Register */ +#define ZR36057_MMTR 0x01c /* Masking Map "Top" Register */ -#define ZR36057_MMBR 0x020 /* Masking Map "Bottom" Register */ +#define ZR36057_MMBR 0x020 /* Masking Map "Bottom" Register */ -#define ZR36057_OCR 0x024 /* Overlay Control Register */ +#define ZR36057_OCR 0x024 /* Overlay Control Register */ #define ZR36057_OCR_OvlEnable (1 << 15) #define ZR36057_OCR_MaskStride 0 -#define ZR36057_SPGPPCR 0x028 /* System, PCI, and General Purpose Pins Control Register */ +#define ZR36057_SPGPPCR 0x028 /* System, PCI, and General Purpose Pins Control Register */ #define ZR36057_SPGPPCR_SoftReset (1<<24) -#define ZR36057_GPPGCR1 0x02c /* General Purpose Pins and GuestBus Control Register (1) */ +#define ZR36057_GPPGCR1 0x02c /* General Purpose Pins and GuestBus Control Register (1) */ -#define ZR36057_MCSAR 0x030 /* MPEG Code Source Address Register */ +#define ZR36057_MCSAR 0x030 /* MPEG Code Source Address Register */ -#define ZR36057_MCTCR 0x034 /* MPEG Code Transfer Control Register */ +#define ZR36057_MCTCR 0x034 /* MPEG Code Transfer Control Register */ #define ZR36057_MCTCR_CodTime (1 << 30) #define ZR36057_MCTCR_CEmpty (1 << 29) #define ZR36057_MCTCR_CFlush (1 << 28) #define ZR36057_MCTCR_CodGuestID 20 #define ZR36057_MCTCR_CodGuestReg 16 -#define ZR36057_MCMPR 0x038 /* MPEG Code Memory Pointer Register */ +#define ZR36057_MCMPR 0x038 /* MPEG Code Memory Pointer Register */ -#define ZR36057_ISR 0x03c /* Interrupt Status Register */ +#define ZR36057_ISR 0x03c /* Interrupt Status Register */ #define ZR36057_ISR_GIRQ1 (1<<30) #define ZR36057_ISR_GIRQ0 (1<<29) #define ZR36057_ISR_CodRepIRQ (1<<28) #define ZR36057_ISR_JPEGRepIRQ (1<<27) -#define ZR36057_ICR 0x040 /* Interrupt Control Register */ +#define ZR36057_ICR 0x040 /* Interrupt Control Register */ #define ZR36057_ICR_GIRQ1 (1<<30) #define ZR36057_ICR_GIRQ0 (1<<29) #define ZR36057_ICR_CodRepIRQ (1<<28) #define ZR36057_ICR_JPEGRepIRQ (1<<27) #define ZR36057_ICR_IntPinEn (1<<24) -#define ZR36057_I2CBR 0x044 /* I2C Bus Register */ +#define ZR36057_I2CBR 0x044 /* I2C Bus Register */ #define ZR36057_I2CBR_SDA (1<<1) #define ZR36057_I2CBR_SCL (1<<0) -#define ZR36057_JMC 0x100 /* JPEG Mode and Control */ +#define ZR36057_JMC 0x100 /* JPEG Mode and Control */ #define ZR36057_JMC_JPG (1 << 31) #define ZR36057_JMC_JPGExpMode (0 << 29) #define ZR36057_JMC_JPGCmpMode (1 << 29) @@ -124,45 +124,45 @@ #define ZR36057_JMC_CFIFO_FB (1 << 1) #define ZR36057_JMC_Stll_LitEndian (1 << 0) -#define ZR36057_JPC 0x104 /* JPEG Process Control */ +#define ZR36057_JPC 0x104 /* JPEG Process Control */ #define ZR36057_JPC_P_Reset (1 << 7) #define ZR36057_JPC_CodTrnsEn (1 << 5) #define ZR36057_JPC_Active (1 << 0) -#define ZR36057_VSP 0x108 /* Vertical Sync Parameters */ +#define ZR36057_VSP 0x108 /* Vertical Sync Parameters */ #define ZR36057_VSP_VsyncSize 16 #define ZR36057_VSP_FrmTot 0 -#define ZR36057_HSP 0x10c /* Horizontal Sync Parameters */ +#define ZR36057_HSP 0x10c /* Horizontal Sync Parameters */ #define ZR36057_HSP_HsyncStart 16 #define ZR36057_HSP_LineTot 0 -#define ZR36057_FHAP 0x110 /* Field Horizontal Active Portion */ +#define ZR36057_FHAP 0x110 /* Field Horizontal Active Portion */ #define ZR36057_FHAP_NAX 16 #define ZR36057_FHAP_PAX 0 -#define ZR36057_FVAP 0x114 /* Field Vertical Active Portion */ +#define ZR36057_FVAP 0x114 /* Field Vertical Active Portion */ #define ZR36057_FVAP_NAY 16 #define ZR36057_FVAP_PAY 0 -#define ZR36057_FPP 0x118 /* Field Process Parameters */ +#define ZR36057_FPP 0x118 /* Field Process Parameters */ #define ZR36057_FPP_Odd_Even (1 << 0) -#define ZR36057_JCBA 0x11c /* JPEG Code Base Address */ +#define ZR36057_JCBA 0x11c /* JPEG Code Base Address */ -#define ZR36057_JCFT 0x120 /* JPEG Code FIFO Threshold */ +#define ZR36057_JCFT 0x120 /* JPEG Code FIFO Threshold */ -#define ZR36057_JCGI 0x124 /* JPEG Codec Guest ID */ +#define ZR36057_JCGI 0x124 /* JPEG Codec Guest ID */ #define ZR36057_JCGI_JPEGuestID 4 #define ZR36057_JCGI_JPEGuestReg 0 -#define ZR36057_GCR2 0x12c /* GuestBus Control Register (2) */ +#define ZR36057_GCR2 0x12c /* GuestBus Control Register (2) */ -#define ZR36057_POR 0x200 /* Post Office Register */ +#define ZR36057_POR 0x200 /* Post Office Register */ #define ZR36057_POR_POPen (1<<25) #define ZR36057_POR_POTime (1<<24) #define ZR36057_POR_PODir (1<<23) -#define ZR36057_STR 0x300 /* "Still" Transfer Register */ +#define ZR36057_STR 0x300 /* "Still" Transfer Register */ #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/zr36060.h linux.ac/drivers/media/video/zr36060.h --- linux.vanilla/drivers/media/video/zr36060.h Tue Jul 6 04:09:40 1999 +++ linux.ac/drivers/media/video/zr36060.h Tue Apr 3 17:54:47 2001 @@ -1,22 +1,22 @@ /* - zr36060.h - zr36060 register offsets + zr36060.h - zr36060 register offsets - Copyright (C) 1998 Dave Perks <dperks@ibm.net> + Copyright (C) 1998 Dave Perks <dperks@ibm.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. + 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. + 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. - */ + 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 _ZR36060_H_ #define _ZR36060_H_ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/media/video/zr36067.c linux.ac/drivers/media/video/zr36067.c --- linux.vanilla/drivers/media/video/zr36067.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/media/video/zr36067.c Sun Apr 15 15:18:12 2001 @@ -0,0 +1,4881 @@ +#define DEBUGLEVEL 0 +#define MAX_KMALLOC_MEM (128*1024) + +/* + Miro/Pinnacle Systems Inc. DC10/DC10plus and + Linux Media Labs LML33 video capture boards driver + now with IOMega BUZ support! + + Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> + + Changes for BUZ by Wolfgang Scherr <scherr@net4you.net> + + Based on + + Miro DC10 driver + Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net> + + Iomega Buz driver version 1.0 + Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de> + + buz.0.0.3 + Copyright (C) 1998 Dave Perks <dperks@ibm.net> + + bttv - Bt848 frame grabber driver + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@thp.uni-koeln.de) + + + 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 <linux/config.h> +#include <linux/version.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/malloc.h> +#include <linux/mm.h> +#include <linux/pci.h> +#include <linux/signal.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <linux/sched.h> +#include <asm/segment.h> +#include <linux/types.h> +#include <linux/wrapper.h> + +#include <linux/spinlock.h> +#include <linux/vmalloc.h> +#include <linux/i2c-old.h> +#define MAP_NR(x) virt_to_page(x) +#define ZORAN_HARDWARE VID_HARDWARE_ZR36067 + +#include <linux/videodev.h> + +#include <asm/uaccess.h> +#include <linux/proc_fs.h> + +#include "zoran.h" +#include <linux/video_decoder.h> +#include <linux/video_encoder.h> + +// RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined +#if !defined(CONFIG_BIGPHYS_AREA) +//#undef CONFIG_BIGPHYS_AREA +#define BUZ_USE_HIMEM +#endif + +#if defined(CONFIG_BIGPHYS_AREA) +# include <linux/bigphysarea.h> +#endif + +#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | ZR36057_ISR_GIRQ1 | /* ZR36057_ISR_CodRepIRQ | */ ZR36057_ISR_JPEGRepIRQ ) // SW +//#define GPIO_MASK 0xcd +//#define GPIO_MASK 0x8d + +/* +DC10: +GPIO0 = /RESET ZR 36060 +GPIO1 = VIDEO BUS DIRECTION (0: CAPTURE, 1: DISPLAY) +GPIO2 = VIDEO BUS ENABLE (0: ON, 1: OFF) +GPIO3 = /SLEEP ZR 36060 +GPIO4 = ADC7175 (video out) FREQUENCY (0: LCC/SAA7110, 1: 27 MHz (quarz)) +GPIO5 = ZORAN FREQUENCY (0: LCC and LCC2 from SAA7110, + 1: 27 and 13.5 MHz (quarz)) +GPIO6 = /FRAME ZR 36060 +GPIO7 = /RESET ADV7175 (video out) +(I think they lost the SAA7110 reset.....) + +GIRQ0 signals that ZR36060's DATERR# line is asserted. +GIRQ1 signals a vertical sync of the video signal (VS SAA7110) + + SAA7110A: + mode 0 - Composite + mode 1 - + mode 2 - + mode 3 - + mode 4 - + mode 5 - internal Composite (from PCTV) + mode 6 - + mode 7 - S-Video + +BUZ: +GPIO0 = 1, take board out of reset +GPIO1 = 1, take JPEG codec out of sleep mode +GPIO3 = 1, deassert FRAME# to 36060 + +GIRQ0 signals a vertical sync of the video signal +GIRQ1 signals that ZR36060's DATERR# line is asserted. + +SAA7111A + + In their infinite wisdom, the Iomega engineers decided to + use the same input line for composite and S-Video Color, + although there are two entries not connected at all! + Through this ingenious strike, it is not possible to + keep two running video sources connected at the same time + to Composite and S-VHS input! + + mode 0 - N/C + mode 1 - S-Video Y + mode 2 - noise or something I don't know + mode 3 - Composite and S-Video C + mode 4 - N/C + mode 5 - S-Video (gain C independently selectable of gain Y) + mode 6 - N/C + mode 7 - S-Video (gain C adapted to gain Y) +*/ + +#define MAJOR_VERSION 0 /* driver major version */ +#define MINOR_VERSION 7 /* driver minor version */ + +#define ZORAN_NAME "zr36067" /* name of the device */ + +#define BUZ_ERR KERN_ERR ZORAN_NAME +#define BUZ_DEBUG KERN_INFO ZORAN_NAME +#define BUZ_INFO KERN_INFO ZORAN_NAME +#define BUZ_WARNING KERN_WARNING ZORAN_NAME + +#if(DEBUGLEVEL>0) +#define DEBUG1(x...) x +#else +#define DEBUG1(x...) +#endif + +#if(DEBUGLEVEL>1) +#define DEBUG2(x...) x +#else +#define DEBUG2(x...) +#endif + +#if(DEBUGLEVEL>2) +#define DEBUG3(x...) x +#else +#define DEBUG3(x...) +#endif + +#if(DEBUGLEVEL>3) +#define DEBUG4(x...) x +#else +#define DEBUG4(x...) +#endif + +/* The parameters for this driver */ + +/* + The video mem address of the video card. + The driver has a little database for some videocards + to determine it from there. If your video card is not in there + you have either to give it to the driver as a parameter + or set in in a VIDIOCSFBUF ioctl + */ + +static unsigned long vidmem = 0; /* Video memory base address */ + +/* Special purposes only: */ + +static int triton = 0; /* 0=no, 1=yes */ +static int natoma = 0; /* 0=no, 1=yes */ + +/* + Number and size of grab buffers for Video 4 Linux + The vast majority of applications should not need more than 2, + the very popular BTTV driver actually does ONLY have 2. + Time sensitive applications might need more, the maximum + is VIDEO_MAX_FRAME (defined in <linux/videodev.h>). + + The size is set so that the maximum possible request + can be satisfied. Decrease it, if bigphys_area alloc'd + memory is low. If you don't have the bigphys_area patch, + set it to 128 KB. Will you allow only to grab small + images with V4L, but that's better than nothing. + + v4l_bufsize has to be given in KB ! + +*/ + +static int v4l_nbufs = 2; +static int v4l_bufsize = 128; /* Everybody should be able to work with this setting */ + +/* + Default input and video norm at startup of the driver. +*/ + +static int default_input = 0; /* 0=Composite, 1=S-VHS */ +static int default_norm = 0; /* 0=PAL, 1=NTSC 2=SECAM */ +static int lock_norm = 0; /* 1=Don't change TV standard (norm) */ + +static int pass_through = 0; /* 1=Pass through TV signal when device is not used */ + /* 0=Show color bar when device is not used (LML33: only if lml33dpath=1) */ + +static int lml33dpath = 0; /* 1 will use digital path in capture mode instead of analog. + It can be used for picture adjustments using tool like xawtv + while watching image on TV monitor connected to the output. + However, due to absence of 75 Ohm load on Bt819 input, there + will be some image imperfections */ + +MODULE_PARM(vidmem, "i"); +MODULE_PARM(triton, "i"); +MODULE_PARM(natoma, "i"); +MODULE_PARM(v4l_nbufs, "i"); +MODULE_PARM(v4l_bufsize, "i"); +MODULE_PARM(default_input, "i"); +MODULE_PARM(default_norm, "i"); +MODULE_PARM(lock_norm, "i"); +MODULE_PARM(pass_through, "i"); +MODULE_PARM(lml33dpath, "i"); + +/* Anybody who uses more than four? */ +#define BUZ_MAX 4 + +static int zoran_num; /* number of Buzs in use */ +static struct zoran zoran[BUZ_MAX]; + +/* forward references */ + +static void v4l_fbuffer_free(struct zoran *zr); +static void jpg_fbuffer_free(struct zoran *zr); +static void zoran_feed_stat_com(struct zoran *zr); + +/* + * Allocate the V4L grab buffers + * + * These have to be pysically contiguous. + * If v4l_bufsize <= MAX_KMALLOC_MEM we use kmalloc + * else we try to allocate them with bigphysarea_alloc_pages + * if the bigphysarea patch is present in the kernel, + * else we try to use high memory (if the user has bootet + * Linux with the necessary memory left over). + */ + +static int v4l_fbuffer_alloc(struct zoran *zr) +{ + int i, off; + unsigned char *mem; + + for (i = 0; i < v4l_nbufs; i++) { + if (zr->v4l_gbuf[i].fbuffer) + printk(KERN_WARNING + "%s: v4l_fbuffer_alloc: buffer %d allready allocated ???\n", + zr->name, i); + + //udelay(20); + if (v4l_bufsize <= MAX_KMALLOC_MEM) { + /* Use kmalloc */ + + mem = + (unsigned char *) kmalloc(v4l_bufsize, + GFP_KERNEL); + if (mem == 0) { + printk(KERN_ERR + "%s: kmalloc for V4L bufs failed\n", + zr->name); + v4l_fbuffer_free(zr); + return -ENOBUFS; + } + zr->v4l_gbuf[i].fbuffer = mem; + zr->v4l_gbuf[i].fbuffer_phys = virt_to_phys(mem); + zr->v4l_gbuf[i].fbuffer_bus = virt_to_bus(mem); + for (off = 0; off < v4l_bufsize; off += PAGE_SIZE) + mem_map_reserve(MAP_NR(mem + off)); + DEBUG1(printk + (KERN_INFO + "%s: V4L frame %d mem 0x%lx (bus: 0x%lx)\n", + zr->name, i, (unsigned long) mem, + virt_to_bus(mem))); + } else { +#if defined(CONFIG_BIGPHYS_AREA) + /* Use bigphysarea_alloc_pages */ + + int n = (v4l_bufsize + PAGE_SIZE - 1) / PAGE_SIZE; + mem = + (unsigned char *) bigphysarea_alloc_pages(n, 0, + GFP_KERNEL); + if (mem == 0) { + printk(KERN_ERR + "%s: bigphysarea_alloc_pages for V4L bufs failed\n", + zr->name); + v4l_fbuffer_free(zr); + return -ENOBUFS; + } + zr->v4l_gbuf[i].fbuffer = mem; + zr->v4l_gbuf[i].fbuffer_phys = virt_to_phys(mem); + zr->v4l_gbuf[i].fbuffer_bus = virt_to_bus(mem); + DEBUG1(printk + (KERN_INFO + "%s: Bigphysarea frame %d mem 0x%x (bus: 0x%x)\n", + zr->name, i, (unsigned) mem, + (unsigned) virt_to_bus(mem))); + + /* Zero out the allocated memory */ + memset(zr->v4l_gbuf[i].fbuffer, 0, v4l_bufsize); +#else + /* No bigphysarea present, usage of high memory disabled, + but user wants buffers of more than MAX_KMALLOC_MEM */ + printk(KERN_ERR + "%s: No bigphysarea_patch present, usage of high memory disabled,\n", + zr->name); + printk(KERN_ERR + "%s: sorry, could not allocate V4L buffers of size %d KB.\n", + zr->name, v4l_bufsize >> 10); + return -ENOBUFS; +#endif + } + } + + return 0; +} + +/* free the V4L grab buffers */ + +static void v4l_fbuffer_free(struct zoran *zr) +{ + int i, off; + unsigned char *mem; + + for (i = 0; i < v4l_nbufs; i++) { + if (!zr->v4l_gbuf[i].fbuffer) + continue; + + if (v4l_bufsize <= MAX_KMALLOC_MEM) { + mem = zr->v4l_gbuf[i].fbuffer; + for (off = 0; off < v4l_bufsize; off += PAGE_SIZE) + mem_map_unreserve(MAP_NR(mem + off)); + kfree((void *) zr->v4l_gbuf[i].fbuffer); + } +#if defined(CONFIG_BIGPHYS_AREA) + else + bigphysarea_free_pages((void *) zr->v4l_gbuf[i]. + fbuffer); +#endif + zr->v4l_gbuf[i].fbuffer = NULL; + } +} + +/* + * Allocate the MJPEG grab buffers. + * + * If the requested buffer size is smaller than MAX_KMALLOC_MEM, + * kmalloc is used to request a physically contiguous area, + * else we allocate the memory in framgents with get_free_page. + * + * If a Natoma chipset is present and this is a revision 1 zr36057, + * each MJPEG buffer needs to be physically contiguous. + * (RJ: This statement is from Dave Perks' original driver, + * I could never check it because I have a zr36067) + * The driver cares about this because it reduces the buffer + * size to MAX_KMALLOC_MEM in that case (which forces contiguous allocation). + * + * RJ: The contents grab buffers needs never be accessed in the driver. + * Therefore there is no need to allocate them with vmalloc in order + * to get a contiguous virtual memory space. + * I don't understand why many other drivers first allocate them with + * vmalloc (which uses internally also get_free_page, but delivers you + * virtual addresses) and then again have to make a lot of efforts + * to get the physical address. + * + */ + +static int jpg_fbuffer_alloc(struct zoran *zr) +{ + int i, j, off; //alloc_contig; + unsigned long mem; + + /* Decide if we should alloc contiguous or fragmented memory */ + /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */ + + //alloc_contig = (zr->jpg_bufsize <= MAX_KMALLOC_MEM); + + for (i = 0; i < zr->jpg_nbufs; i++) { + if (zr->jpg_gbuf[i].frag_tab) + printk(KERN_WARNING + "%s: jpg_fbuffer_alloc: buffer %d allready allocated ???\n", + zr->name, i); + + /* Allocate fragment table for this buffer */ + + mem = get_free_page(GFP_KERNEL); + if (mem == 0) { + printk(KERN_ERR + "%s: jpg_fbuffer_alloc: get_free_page (frag_tab) failed for buffer %d\n", + zr->name, i); + jpg_fbuffer_free(zr); + return -ENOBUFS; + } + memset((void *) mem, 0, PAGE_SIZE); + zr->jpg_gbuf[i].frag_tab = (u32 *) mem; + zr->jpg_gbuf[i].frag_tab_bus = virt_to_bus((void *) mem); + + //if (alloc_contig) { + if (zr->need_contiguous) { + mem = (unsigned long) kmalloc(zr->jpg_bufsize, GFP_KERNEL); + if (mem == 0) { + printk(KERN_ERR "%s: jpg_fbuffer_alloc: kmalloc failed for buffer %d\n", + zr->name, i); + jpg_fbuffer_free(zr); + return -ENOBUFS; + } + zr->jpg_gbuf[i].frag_tab[0] = virt_to_bus((void *) mem); + zr->jpg_gbuf[i].frag_tab[1] = + ((zr->jpg_bufsize / 4) << 1) | 1; + for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE) + mem_map_reserve(MAP_NR(mem + off)); + } else { + /* jpg_bufsize is allreay page aligned */ + for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) + { + mem = get_free_page(GFP_KERNEL); + if (mem == 0) { + printk(KERN_ERR + "%s: jpg_fbuffer_alloc: get_free_page failed for buffer %d\n", + zr->name, i); + jpg_fbuffer_free(zr); + return -ENOBUFS; + } + + zr->jpg_gbuf[i].frag_tab[2 * j] = + virt_to_bus((void *) mem); + zr->jpg_gbuf[i].frag_tab[2 * j + 1] = + (PAGE_SIZE / 4) << 1; + mem_map_reserve(MAP_NR(mem)); + } + + zr->jpg_gbuf[i].frag_tab[2 * j - 1] |= 1; + } + } + + DEBUG1(printk + ("%s: jpg_fbuffer_alloc: %ld KB allocated\n", zr->name, + (zr->jpg_nbufs * zr->jpg_bufsize) >> 10)); + zr->jpg_buffers_allocated = 1; + return 0; +} + +/* free the MJPEG grab buffers */ +static void jpg_fbuffer_free(struct zoran *zr) +{ + int i, j, off; // alloc_contig; + unsigned char *mem; + + /* Decide if we should alloc contiguous or fragmented memory */ + /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */ + + //alloc_contig = (zr->jpg_bufsize <= MAX_KMALLOC_MEM); + + for (i = 0; i < zr->jpg_nbufs; i++) { + if (!zr->jpg_gbuf[i].frag_tab) + continue; + + //if (alloc_contig) { + if (zr->need_contiguous) { + if (zr->jpg_gbuf[i].frag_tab[0]) { + mem = + (unsigned char *) bus_to_virt(zr-> + jpg_gbuf + [i]. + frag_tab + [0]); + for (off = 0; off < zr->jpg_bufsize; + off += PAGE_SIZE) + mem_map_unreserve(MAP_NR + (mem + off)); + kfree((void *) mem); + zr->jpg_gbuf[i].frag_tab[0] = 0; + zr->jpg_gbuf[i].frag_tab[1] = 0; + } + } else { + for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { + if (!zr->jpg_gbuf[i].frag_tab[2 * j]) + break; + mem_map_unreserve(MAP_NR + (bus_to_virt + (zr->jpg_gbuf[i]. + frag_tab[2 * j]))); + free_page((unsigned long) + bus_to_virt(zr->jpg_gbuf[i]. + frag_tab[2 * j])); + zr->jpg_gbuf[i].frag_tab[2 * j] = 0; + zr->jpg_gbuf[i].frag_tab[2 * j + 1] = 0; + } + } + + free_page((unsigned long) zr->jpg_gbuf[i].frag_tab); + zr->jpg_gbuf[i].frag_tab = NULL; + } + zr->jpg_buffers_allocated = 0; +} + + +/* ----------------------------------------------------------------------- */ + +/* I2C functions */ + +#define I2C_DELAY 10 + + +/* software I2C functions */ + +static void i2c_setlines(struct i2c_bus *bus, int ctrl, int data) +{ + struct zoran *zr = (struct zoran *) bus->data; + btwrite((data << 1) | ctrl, ZR36057_I2CBR); + udelay(I2C_DELAY); +} + +static int i2c_getdataline(struct i2c_bus *bus) +{ + struct zoran *zr = (struct zoran *) bus->data; + return (btread(ZR36057_I2CBR) >> 1) & 1; +} + +static void attach_inform(struct i2c_bus *bus, int id) +{ + int i; + struct zoran *zr = (struct zoran *) bus->data; + + DEBUG1(printk(KERN_DEBUG "%s: i2c attach %02x\n", zr->name, id)); + for (i = 0; i < bus->devcount; i++) { + if (strcmp(bus->devices[i]->name, "saa7110") == 0) { + if (zr->revision < 2) { + zr->card = DC10; + sprintf(zr->name, "DC10[%u]", zr->id); + } else { + zr->card = DC10plus; + sprintf(zr->name, "DC10plus[%u]", zr->id); + } + break; + } + if (strcmp(bus->devices[i]->name, "bt819") == 0) { + zr->card = LML33; + sprintf(zr->name, "LML33[%u]", zr->id); + break; + } + if (strcmp(bus->devices[i]->name, "saa7111") == 0) { + zr->card = BUZ; + sprintf(zr->name, "Buz[%u]", zr->id); + break; + } + } +} + +static void detach_inform(struct i2c_bus *bus, int id) +{ + DEBUG1(struct zoran *zr = (struct zoran *) bus->data); + DEBUG1(printk(KERN_DEBUG "%s: i2c detach %02x\n", zr->name, id)); +} + +static struct i2c_bus zoran_i2c_bus_template = { + "zr36057", + I2C_BUSID_BT848, + NULL, + + SPIN_LOCK_UNLOCKED, + + attach_inform, + detach_inform, + + i2c_setlines, + i2c_getdataline, + NULL, + NULL, +}; + +/* + * Set the registers for the size we have specified. Don't bother + * trying to understand this without the ZR36057 manual in front of + * you [AC]. + * + * PS: The manual is free for download in .pdf format from + * www.zoran.com - nicely done those folks. + */ + +static struct tvnorm f50sqpixel = { 944, 768, 83, 880, 625, 576, 16 }; +static struct tvnorm f60sqpixel = { 780, 640, 51, 716, 525, 480, 12 }; + +static struct tvnorm f50ccir601 = { 864, 720, 75, 804, 625, 576, 18 }; +static struct tvnorm f60ccir601 = { 858, 720, 57, 788, 525, 480, 16 }; + +static struct tvnorm *dc10norms[] = { + &f50sqpixel, /* PAL-BDGHI */ + &f60sqpixel, /* NTSC */ + &f50sqpixel, /* SECAM */ +}; + +static struct tvnorm *lml33norms[] = { + &f50ccir601, /* PAL-BDGHI */ + &f60ccir601, /* NTSC */ + NULL, /* SECAM (not supported in LML33) */ +}; + +static struct tvnorm *buznorms[] = { + &f50ccir601, /* PAL-BDGHI */ + &f60ccir601, /* NTSC */ + NULL, /* SECAM */ +}; + +static struct tvnorm *unsupported[] = { + NULL, /* PAL-BDGHI */ + NULL, /* NTSC */ + NULL, /* SECAM */ +}; + +static struct tvnorm **cardnorms[] = { + unsupported, /* UNKNOWN */ + dc10norms, /* DC10 */ + dc10norms, /* DC10plus */ + lml33norms, /* LML33 */ + buznorms, /* Buz */ +}; + +static u32 cardvsync[] = { + 0, /* UNKNOWN */ + ZR36057_ISR_GIRQ1, /* DC10 */ + ZR36057_ISR_GIRQ1, /* DC10plus */ + ZR36057_ISR_GIRQ0, /* LML33 */ + ZR36057_ISR_GIRQ0, /* Buz */ +}; + +static u32 cardjpegint[] = { + 0, /* UNKNOWN */ + ZR36057_ISR_GIRQ0, /* DC10 */ + ZR36057_ISR_GIRQ0, /* DC10plus */ + ZR36057_ISR_GIRQ1, /* LML33 */ + ZR36057_ISR_GIRQ1, /* Buz */ +}; + +static int format2bpp(int format) +{ + int bpp; + + /* Determine the number of bytes per pixel for the video format requested */ + + switch (format) { + + case VIDEO_PALETTE_YUV422: + bpp = 2; + break; + + case VIDEO_PALETTE_RGB555: + bpp = 2; + break; + + case VIDEO_PALETTE_RGB565: + bpp = 2; + break; + + case VIDEO_PALETTE_RGB24: + bpp = 3; + break; + + case VIDEO_PALETTE_RGB32: + bpp = 4; + break; + + default: + bpp = 0; + } + + return bpp; +} + +static void zr36057_adjust_vfe(struct zoran *zr, + enum zoran_codec_mode mode) +{ + u32 reg; + switch (mode) { + case BUZ_MODE_MOTION_DECOMPRESS: + btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR); + reg = btread(ZR36057_VFEHCR); + if (reg & (1 << 10)) { + reg += ((1 << 10) | 1); + } + btwrite(reg, ZR36057_VFEHCR); + break; + case BUZ_MODE_MOTION_COMPRESS: + case BUZ_MODE_IDLE: + default: + if (zr->params.norm == VIDEO_MODE_NTSC) + btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR); + else + btor(ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR); + reg = btread(ZR36057_VFEHCR); + if (!(reg & (1 << 10))) { + reg -= ((1 << 10) | 1); + } + btwrite(reg, ZR36057_VFEHCR); + break; + } +} + +/* + * set geometry + */ +static void zr36057_set_vfe(struct zoran *zr, int video_width, + int video_height, unsigned int video_format) +{ + struct tvnorm *tvn; + unsigned HStart, HEnd, VStart, VEnd; + unsigned DispMode; + unsigned VidWinWid, VidWinHt; + unsigned hcrop1, hcrop2, vcrop1, vcrop2; + unsigned Wa, We, Ha, He; + unsigned X, Y, HorDcm, VerDcm; + u32 reg; + unsigned mask_line_size; + + tvn = zr->timing; + + Wa = tvn->Wa; + Ha = tvn->Ha; + + //printk (BUZ_INFO ": width = %d, height = %d\n", video_width, video_height); + + if (zr->params.norm != VIDEO_MODE_PAL + && zr->params.norm != VIDEO_MODE_NTSC + && zr->params.norm != VIDEO_MODE_SECAM) { + printk(KERN_ERR "%s: set_vfe: video_norm = %d not valid\n", + zr->name, zr->params.norm); + return; + } + if (video_width < BUZ_MIN_WIDTH || video_height < BUZ_MIN_HEIGHT + || video_width > Wa || video_height > Ha) { + printk(KERN_ERR "%s: set_vfe: w=%d h=%d not valid\n", + zr->name, video_width, video_height); + return; + } + + /* if window has more than half of active height, + switch on interlacing - we want the full information */ + + zr->video_interlace = (video_height > Ha / 2); + + /**** zr36057 ****/ + + /* horizontal */ + VidWinWid = video_width; + X = (VidWinWid * 64 + tvn->Wa - 1) / tvn->Wa; + We = (VidWinWid * 64) / X; + HorDcm = 64 - X; + hcrop1 = 2 * ((tvn->Wa - We) / 4); + hcrop2 = tvn->Wa - We - hcrop1; + HStart = tvn->HStart | 1; + if (zr->card == LML33) + HStart += 62; + if (zr->card == BUZ) { //HStart += 67; + HStart += 44; + } + HEnd = HStart + tvn->Wa - 1; + HStart += hcrop1; + HEnd -= hcrop2; + reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart) + | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd); + if (zr->card != BUZ) + reg |= ZR36057_VFEHCR_HSPol; + btwrite(reg, ZR36057_VFEHCR); + + /* Vertical */ + DispMode = !zr->video_interlace; + VidWinHt = DispMode ? video_height : video_height / 2; + Y = (VidWinHt * 64 * 2 + tvn->Ha - 1) / tvn->Ha; + He = (VidWinHt * 64) / Y; + VerDcm = 64 - Y; + vcrop1 = (tvn->Ha / 2 - He) / 2; + vcrop2 = tvn->Ha / 2 - He - vcrop1; + VStart = tvn->VStart; + VEnd = VStart + tvn->Ha / 2 - 1; + VStart += vcrop1; + VEnd -= vcrop2; + reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart) + | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd); + reg |= ZR36057_VFEVCR_VSPol; + btwrite(reg, ZR36057_VFEVCR); + + /* scaler and pixel format */ + reg = 0; + reg |= (HorDcm << ZR36057_VFESPFR_HorDcm); + reg |= (VerDcm << ZR36057_VFESPFR_VerDcm); + reg |= (DispMode << ZR36057_VFESPFR_DispMode); + reg |= ZR36057_VFESPFR_LittleEndian; + /* RJ: I don't know, why the following has to be the opposite + of the corresponding ZR36060 setting, but only this way + we get the correct colors when uncompressing to the screen */ + //reg |= ZR36057_VFESPFR_VCLKPol; /**/ + /* RJ: Don't know if that is needed for NTSC also */ + if (zr->params.norm != VIDEO_MODE_NTSC) + reg |= ZR36057_VFESPFR_ExtFl; // NEEDED!!!!!!! Wolfgang + reg |= ZR36057_VFESPFR_TopField; + switch (video_format) { + + case VIDEO_PALETTE_YUV422: + reg |= ZR36057_VFESPFR_YUV422; + break; + + case VIDEO_PALETTE_RGB555: + reg |= ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ErrDif; + break; + + case VIDEO_PALETTE_RGB565: + reg |= ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ErrDif; + break; + + case VIDEO_PALETTE_RGB24: + reg |= ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_Pack24; + break; + + case VIDEO_PALETTE_RGB32: + reg |= ZR36057_VFESPFR_RGB888; + break; + + default: + printk(KERN_INFO "%s: Unknown color_fmt=%x\n", zr->name, + video_format); + return; + + } + if (HorDcm >= 48) { + reg |= 3 << ZR36057_VFESPFR_HFilter; /* 5 tap filter */ + } else if (HorDcm >= 32) { + reg |= 2 << ZR36057_VFESPFR_HFilter; /* 4 tap filter */ + } else if (HorDcm >= 16) { + reg |= 1 << ZR36057_VFESPFR_HFilter; /* 3 tap filter */ + } + btwrite(reg, ZR36057_VFESPFR); + + /* display configuration */ + + reg = (16 << ZR36057_VDCR_MinPix) + | (VidWinHt << ZR36057_VDCR_VidWinHt) + | (VidWinWid << ZR36057_VDCR_VidWinWid); + if (triton || zr->revision <= 1) + reg &= ~ZR36057_VDCR_Triton; + else + reg |= ZR36057_VDCR_Triton; + btwrite(reg, ZR36057_VDCR); + + /* Write overlay clipping mask data, but don't enable overlay clipping */ + /* RJ: since this makes only sense on the screen, we use + zr->window.width instead of video_width */ + + mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; + reg = virt_to_bus(zr->overlay_mask); + btwrite(reg, ZR36057_MMTR); + reg = virt_to_bus(zr->overlay_mask + mask_line_size); + btwrite(reg, ZR36057_MMBR); + reg = mask_line_size - (zr->window.width + 31) / 32; + if (DispMode == 0) + reg += mask_line_size; + reg <<= ZR36057_OCR_MaskStride; + btwrite(reg, ZR36057_OCR); + + zr36057_adjust_vfe(zr, zr->codec_mode); + +} + +/* + * Switch overlay on or off + */ + +static void zr36057_overlay(struct zoran *zr, int on) +{ + int fmt, bpp; + u32 reg; + + if (on) { + /* do the necessary settings ... */ + + btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); /* switch it off first */ + + switch (zr->buffer.depth) { + case 15: + fmt = VIDEO_PALETTE_RGB555; + bpp = 2; + break; + case 16: + fmt = VIDEO_PALETTE_RGB565; + bpp = 2; + break; + case 24: + fmt = VIDEO_PALETTE_RGB24; + bpp = 3; + break; + case 32: + fmt = VIDEO_PALETTE_RGB32; + bpp = 4; + break; + default: + fmt = 0; + bpp = 0; + } + + zr36057_set_vfe(zr, zr->window.width, zr->window.height, + fmt); + + /* Start and length of each line MUST be 4-byte aligned. + This should be allready checked before the call to this routine. + All error messages are internal driver checking only! */ + + /* video display top and bottom registers */ + + reg = + (u32) zr->buffer.base + zr->window.x * bpp + + zr->window.y * zr->buffer.bytesperline; + btwrite(reg, ZR36057_VDTR); + if (reg & 3) + printk(KERN_ERR + "%s: zr36057_overlay: video_address not aligned\n", + zr->name); + if (zr->video_interlace) + reg += zr->buffer.bytesperline; + btwrite(reg, ZR36057_VDBR); + + /* video stride, status, and frame grab register */ + + reg = zr->buffer.bytesperline - zr->window.width * bpp; + if (zr->video_interlace) + reg += zr->buffer.bytesperline; + if (reg & 3) + printk(KERN_ERR + "%s: zr36057_overlay: video_stride not aligned\n", + zr->name); + reg = (reg << ZR36057_VSSFGR_DispStride); + reg |= ZR36057_VSSFGR_VidOvf; /* clear overflow status */ + btwrite(reg, ZR36057_VSSFGR); + + /* Set overlay clipping */ + + if (zr->window.clipcount) + btor(ZR36057_OCR_OvlEnable, ZR36057_OCR); + + /* ... and switch it on */ + + btor(ZR36057_VDCR_VidEn, ZR36057_VDCR); + } else { + /* Switch it off */ + + btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); + } +} + +/* + * The overlay mask has one bit for each pixel on a scan line, + * and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels. + */ +static void write_overlay_mask(struct zoran *zr, struct video_clip *vp, + int count) +{ + unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; + u32 *mask; + int x, y, width, height; + unsigned i, j, k; + u32 reg; + + /* fill mask with one bits */ + memset(zr->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT); + reg = 0; + + for (i = 0; i < count; ++i) { + /* pick up local copy of clip */ + x = vp[i].x; + y = vp[i].y; + width = vp[i].width; + height = vp[i].height; + + /* trim clips that extend beyond the window */ + if (x < 0) { + width += x; + x = 0; + } + if (y < 0) { + height += y; + y = 0; + } + if (x + width > zr->window.width) { + width = zr->window.width - x; + } + if (y + height > zr->window.height) { + height = zr->window.height - y; + } + + /* ignore degenerate clips */ + if (height <= 0) { + continue; + } + if (width <= 0) { + continue; + } + + /* apply clip for each scan line */ + for (j = 0; j < height; ++j) { + /* reset bit for each pixel */ + /* this can be optimized later if need be */ + mask = zr->overlay_mask + (y + j) * mask_line_size; + for (k = 0; k < width; ++k) { + mask[(x + k) / 32] &= + ~((u32) 1 << (x + k) % 32); + } + } + } +} + +/* Enable/Disable uncompressed memory grabbing of the 36057 */ + +static void zr36057_set_memgrab(struct zoran *zr, int mode) +{ + if (mode) { + if (btread(ZR36057_VSSFGR) & + (ZR36057_VSSFGR_SnapShot | ZR36057_VSSFGR_FrameGrab)) + printk(KERN_WARNING + "%s: zr36057_set_memgrab_on with SnapShot or FrameGrab on ???\n", + zr->name); + + /* switch on VSync interrupts */ + + btwrite(IRQ_MASK, ZR36057_ISR); // Clear Interrupts + btor(cardvsync[zr->card], ZR36057_ICR); // SW + + /* enable SnapShot */ + + btor(ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); + + /* Set zr36057 video front end and enable video */ + + zr36057_set_vfe(zr, zr->gwidth, zr->gheight, zr->gformat); + + zr->v4l_memgrab_active = 1; + } else { + zr->v4l_memgrab_active = 0; + + /* switch off VSync interrupts */ + + //btand(~ZR36057_ICR_GIRQ1, ZR36057_ICR); // SW + + /* reenable grabbing to screen if it was running */ + + if (zr->v4l_overlay_active) { + zr36057_overlay(zr, 1); + } else { + btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); + btand(~ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); + } + } +} + +static int wait_grab_pending(struct zoran *zr) +{ + unsigned long flags; + + /* wait until all pending grabs are finished */ + + if (!zr->v4l_memgrab_active) + return 0; + + while (zr->v4l_pend_tail != zr->v4l_pend_head) { + interruptible_sleep_on(&zr->v4l_capq); + if (signal_pending(current)) + return -ERESTARTSYS; + } + + spin_lock_irqsave(&zr->lock, flags); + zr36057_set_memgrab(zr, 0); + spin_unlock_irqrestore(&zr->lock, flags); + + return 0; +} + +/* + * V4L Buffer grabbing + */ + +static int v4l_grab(struct zoran *zr, struct video_mmap *mp) +{ + unsigned long flags; + int res, bpp; + + /* + * There is a long list of limitations to what is allowed to be grabbed + * We don't output error messages her, since some programs (e.g. xawtv) + * just try several settings to find out what is valid or not. + */ + + /* No grabbing outside the buffer range! */ + + if (mp->frame >= v4l_nbufs || mp->frame < 0) { + DEBUG2(printk + (KERN_ERR "%s: Can not grab frame %d\n", zr->name, + mp->frame)); + return -EINVAL; + } + + /* Check size and format of the grab wanted */ + + if (mp->height < BUZ_MIN_HEIGHT || mp->width < BUZ_MIN_WIDTH + || mp->height > BUZ_MAX_HEIGHT || mp->width > BUZ_MAX_WIDTH) { + DEBUG2(printk + (KERN_ERR "%s: Wrong frame size.\n", zr->name)); + return -EINVAL; + } + + bpp = format2bpp(mp->format); + if (bpp == 0) { + DEBUG2(printk + (KERN_ERR "%s: Wrong bytes-per-pixel format\n", + zr->name)); + return -EINVAL; + } + + /* Check against available buffer size */ + + if (mp->height * mp->width * bpp > v4l_bufsize) { + DEBUG2(printk + (KERN_ERR "%s: Video buffer size is too small\n", + zr->name)); + return -EINVAL; + } + + /* The video front end needs 4-byte alinged line sizes */ + + if ((bpp == 2 && (mp->width & 1)) || (bpp == 3 && (mp->width & 3))) { + DEBUG2(printk + (KERN_ERR "%s: Wrong frame alingment\n", zr->name)); + return -EINVAL; + } + + /* + * To minimize the time spent in the IRQ routine, we avoid setting up + * the video front end there. + * If this grab has different parameters from a running streaming capture + * we stop the streaming capture and start it over again. + */ + + if (zr->v4l_memgrab_active + && (zr->gwidth != mp->width || zr->gheight != mp->height + || zr->gformat != mp->format)) { + res = wait_grab_pending(zr); + if (res) + return res; + } + zr->gwidth = mp->width; + zr->gheight = mp->height; + zr->gformat = mp->format; + zr->gbpl = bpp * zr->gwidth; + + + spin_lock_irqsave(&zr->lock, flags); + + /* make sure a grab isn't going on currently with this buffer */ + + switch (zr->v4l_gbuf[mp->frame].state) { + + default: + case BUZ_STATE_PEND: + res = -EBUSY; /* what are you doing? */ + break; + + case BUZ_STATE_USER: + case BUZ_STATE_DONE: + /* since there is at least one unused buffer there's room for at least one more pend[] entry */ + zr->v4l_pend[zr->v4l_pend_head++ & V4L_MASK_FRAME] = + mp->frame; + zr->v4l_gbuf[mp->frame].state = BUZ_STATE_PEND; + res = 0; + break; + + } + + /* put the 36057 into frame grabbing mode */ + + if (!res && !zr->v4l_memgrab_active) + zr36057_set_memgrab(zr, 1); + + spin_unlock_irqrestore(&zr->lock, flags); + //DEBUG2(printk(KERN_INFO "%s: Frame grab 3...\n", zr->name)); + + return res; +} + +/* + * Sync on a V4L buffer + */ + +static int v4l_sync(struct zoran *zr, int frame) +{ + unsigned long flags; + + /* check passed-in frame number */ + + if (frame >= v4l_nbufs || frame < 0) { + printk(KERN_ERR "%s: v4l_sync: frame %d is invalid\n", + zr->name, frame); + return -EINVAL; + } + + /* Check if is buffer was queued at all */ + + if (zr->v4l_gbuf[frame].state == BUZ_STATE_USER) { + printk(KERN_ERR + "%s: v4l_sync: Attempt to sync on a buffer which was not queued?\n", + zr->name); + return -EPROTO; + } + + /* wait on this buffer to get ready */ + + while (zr->v4l_gbuf[frame].state == BUZ_STATE_PEND) { + interruptible_sleep_on(&zr->v4l_capq); + if (signal_pending(current)) + return -ERESTARTSYS; + } + + /* buffer should now be in BUZ_STATE_DONE */ + + if (zr->v4l_gbuf[frame].state != BUZ_STATE_DONE) + printk(KERN_ERR "%s: v4l_sync - internal error\n", + zr->name); + + /* Check if streaming capture has finished */ + + spin_lock_irqsave(&zr->lock, flags); + + if (zr->v4l_pend_tail == zr->v4l_pend_head) + zr36057_set_memgrab(zr, 0); + + spin_unlock_irqrestore(&zr->lock, flags); + + return 0; +} + +/***************************************************************************** + * * + * Set up the Buz-specific MJPEG part * + * * + *****************************************************************************/ + +/* +Wait til post office is no longer busy */ +static int post_office_wait(struct zoran *zr) +{ + u32 por; + +// while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) { + while ((por = btread(ZR36057_POR)) & ZR36057_POR_POPen) { + /* wait for something to happen */ + } + if ((por & ZR36057_POR_POTime) && zr->card != LML33 + && zr->card != BUZ) { + /* In LML33/BUZ \GWS line is not connected, so it has always timeout set */ + printk(KERN_INFO "%s: pop timeout %08x\n", zr->name, por); + return -1; + } + return 0; +} + +static int post_office_write(struct zoran *zr, unsigned guest, + unsigned reg, unsigned value) +{ + u32 por; + + por = + ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) | + ((reg & 7) << 16) | (value & 0xFF); + btwrite(por, ZR36057_POR); + return post_office_wait(zr); +} + +static int post_office_read(struct zoran *zr, unsigned guest, unsigned reg) +{ + u32 por; + + por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16); + btwrite(por, ZR36057_POR); + if (post_office_wait(zr) < 0) { + return -1; + } + return btread(ZR36057_POR) & 0xFF; +} + +static int zr36060_write_8(struct zoran *zr, unsigned reg, unsigned val) +{ + if (post_office_wait(zr) + || post_office_write(zr, 0, 1, reg >> 8) + || post_office_write(zr, 0, 2, reg)) { + return -1; + } + return post_office_write(zr, 0, 3, val); +} + +static int zr36060_write_16(struct zoran *zr, unsigned reg, unsigned val) +{ + if (zr36060_write_8(zr, reg + 0, val >> 8)) { + return -1; + } + return zr36060_write_8(zr, reg + 1, val >> 0); +} + +static int zr36060_write_24(struct zoran *zr, unsigned reg, unsigned val) +{ + if (zr36060_write_8(zr, reg + 0, val >> 16)) { + return -1; + } + return zr36060_write_16(zr, reg + 1, val >> 0); +} + +static int zr36060_write_32(struct zoran *zr, unsigned reg, unsigned val) +{ + if (zr36060_write_16(zr, reg + 0, val >> 16)) { + return -1; + } + return zr36060_write_16(zr, reg + 2, val >> 0); +} + +static u32 zr36060_read_8(struct zoran *zr, unsigned reg) +{ + if (post_office_wait(zr) + || post_office_write(zr, 0, 1, reg >> 8) + || post_office_write(zr, 0, 2, reg)) { + return -1; + } + return post_office_read(zr, 0, 3) & 0xFF; +} + +/* ----------------------------------------------------------------------- */ + +static void GPIO(struct zoran *zr, unsigned bit, unsigned value) +{ + u32 reg; + u32 mask; + + mask = 1 << (24 + bit); + reg = btread(ZR36057_GPPGCR1) & ~mask; + if (value) { + reg |= mask; + } + btwrite(reg, ZR36057_GPPGCR1); + udelay(1); +} + + +static void zr36060_sleep(struct zoran *zr, int sleep) +{ + switch (zr->card) { + case DC10: + case DC10plus: + GPIO(zr, 3, !sleep); + break; + case BUZ: + case LML33: + GPIO(zr, 1, !sleep); + break; + default: + break; + } + if (!sleep) + udelay(500); + else + udelay(2); +} + +static int zr36060_reset(struct zoran *zr) +{ + switch (zr->card) { + case DC10: + case DC10plus: + zr36060_sleep(zr, 0); + GPIO(zr, 0, 0); + udelay(2); + GPIO(zr, 0, 1); + udelay(2); + break; + case LML33: + case BUZ: + zr36060_sleep(zr, 0); + post_office_write(zr, 3, 0, 0); + udelay(2); + default: + } + return 0; +} + +static void set_frame(struct zoran *zr, int val) +{ + switch (zr->card) { + case DC10: + case DC10plus: + GPIO(zr, 6, val); + break; + case LML33: + case BUZ: + GPIO(zr, 3, val); + break; + default: + break; + } +} + +static void set_videobus_dir(struct zoran *zr, int val) +{ + switch (zr->card) { + case DC10: + case DC10plus: + GPIO(zr, 1, val); + break; + case LML33: + if (lml33dpath == 0) + GPIO(zr, 5, val); + else + GPIO(zr, 5, 1); + break; + case BUZ: + default: + break; + } +} + +static void set_videobus_enable(struct zoran *zr, int val) +{ + switch (zr->card) { + case LML33: + GPIO(zr, 7, val); + break; + case DC10: + case DC10plus: + case BUZ: + default: + break; + } +} + +static void zr36060_set_jpg(struct zoran *zr, enum zoran_codec_mode mode) +{ + struct tvnorm *tvn; + u32 reg; + int size, blocks; + + reg = (1 << 0) /* CodeMstr */ + |(0 << 2) /* CFIS=0 */ + |(0 << 6) /* Endian=0 */ + |(0 << 7); /* Code16=0 */ + zr36060_write_8(zr, 0x002, reg); + + switch (mode) { + + case BUZ_MODE_MOTION_DECOMPRESS: + case BUZ_MODE_STILL_DECOMPRESS: + reg = 0x00; /* Codec mode = decompression */ + break; + + case BUZ_MODE_MOTION_COMPRESS: + case BUZ_MODE_STILL_COMPRESS: + default: + reg = 0xa4; /* Codec mode = compression with variable scale factor */ + break; + + } + zr36060_write_8(zr, 0x003, reg); + + reg = 0x00; /* reserved, mbz */ + zr36060_write_8(zr, 0x004, reg); + + /* code volume */ + + /* Target field size in pixels: */ + tvn = zr->timing; + size = + (tvn->Ha / 2) * (tvn->Wa) / (zr->params.HorDcm) / + (zr->params.VerDcm); + blocks = size / 64; + + /* Target compressed field size in bits: */ + size = size * 16; /* uncompressed size in bits */ + size = size * zr->params.quality / 400; /* quality = 100 is a compression ratio 1:4 */ + + /* Lower limit (arbitrary, 1 KB) */ + if (size < 8192) + size = 8192; + + /* Upper limit: 6/8 of the code buffers */ + if (size * zr->params.field_per_buff > zr->jpg_bufsize * 6) + size = zr->jpg_bufsize * 6 / zr->params.field_per_buff; + + reg = size * 4 / blocks; + if (reg > 0xf0) + reg = 0xf0; /* 480 bits/block, does 0xff represents unlimited? */ + zr36060_write_8(zr, 0x005, reg); + + /* JPEG markers */ + reg = (zr->params.jpeg_markers) & 0x38; /* DRI, DQT, DHT */ + if (zr->params.COM_len) + reg |= JPEG_MARKER_COM; + if (zr->params.APP_len) + reg |= JPEG_MARKER_APP; + zr36060_write_8(zr, 0x006, reg); + + if (zr->card != LML33 && zr->card != BUZ) { + reg = (0 << 3) /* EOAV=0 */ + |(0 << 2) /* EOI=0 */ + |(0 << 1) /* END=0 */ + |(1 << 0); /* DATERR=1 */ + } else { + reg = (0 << 3) /* EOAV=0 */ + |(0 << 2) /* EOI=0 */ + |(0 << 1) /* END=0 */ + |(0 << 0); /* DATERR=0 */ + } + zr36060_write_8(zr, 0x007, reg); + + reg = size; + zr36060_write_32(zr, 0x009, reg); + + reg = (size * 10) / 11; + zr36060_write_32(zr, 0x00d, reg); // Not needed for compr. with variable scale factor, just in case ... + + /* how do we set initial SF as a function of quality parameter? */ + reg = 0x0100; /* SF=1.0 */ + zr36060_write_16(zr, 0x011, reg); + + reg = 0x00ffffff; /* AF=max */ + zr36060_write_24(zr, 0x013, reg); + + reg = 0x0000; /* test */ + zr36060_write_16(zr, 0x024, reg); + + //post_office_read(zr,1,0); +} + +static void zr36060_set_video(struct zoran *zr, enum zoran_codec_mode mode) +{ + struct tvnorm *tvn; + u32 reg; + unsigned HStart; + + tvn = zr->timing; + + reg = (0 << 7) /* Video8 */ + |(0 << 6) /* Range */ + |(0 << 3) /* FlDet */ + |(1 << 2) /* FlVedge */ + |(0 << 1) /* FlExt */ + |(0 << 0); /* SyncMstr */ + + if (mode != BUZ_MODE_STILL_DECOMPRESS) { + /* limit pixels to range 16..235 as per CCIR-601 */ + reg |= (1 << 6); /* Range=1 */ + } + zr36060_write_8(zr, 0x030, reg); + + switch (zr->card) { + case DC10: + case DC10plus: + reg = (0 << 7) /* VCLKPol */ + |(0 << 6) /* PValPol */ + |(0 << 5) /* PoePol */ + |(0 << 4) /* SImgPol */ + |(1 << 3) /* BLPol */ + |(1 << 2) /* FlPol */ + |(1 << 1) /* HSPol */ + |(1 << 0); /* VSPol */ + break; + case LML33: + reg = (0 << 7) /* VCLKPol=0 */ + |(0 << 6) /* PValPol=0 */ + |(1 << 5) /* PoePol=1 */ + |(0 << 4) /* SImgPol=0 */ + |(0 << 3) /* BLPol=0 */ + |(0 << 2) /* FlPol=0 */ + |(0 << 1) /* HSPol=0, sync on falling edge */ + |(1 << 0); /* VSPol=1 */ + break; + case BUZ: + default: + reg = (0 << 7) /* VCLKPol=0 */ + |(0 << 6) /* PValPol=0 */ + |(1 << 5) /* PoePol=1 */ + |(0 << 4) /* SImgPol=0 */ + |(0 << 3) /* BLPol=0 */ + |(0 << 2) /* FlPol=0 */ + |(1 << 1) /* HSPol=0, sync on falling edge */ + |(1 << 0); /* VSPol=1 */ + break; + } + zr36060_write_8(zr, 0x031, reg); + + switch (zr->params.HorDcm) { + default: + case 1: + reg = (0 << 0); + break; /* HScale = 0 */ + + case 2: + reg = (1 << 0); + break; /* HScale = 1 */ + + case 4: + reg = (2 << 0); + break; /* HScale = 2 */ + } + if (zr->params.VerDcm == 2) + reg |= (1 << 2); + zr36060_write_8(zr, 0x032, reg); + + reg = 0x00; /* BackY */ + zr36060_write_8(zr, 0x033, reg); + + reg = 0x80; /* BackU */ + zr36060_write_8(zr, 0x034, reg); + + reg = 0x80; /* BackV */ + zr36060_write_8(zr, 0x035, reg); + + /* sync generator */ + + reg = tvn->Ht - 1; /* Vtotal */ + zr36060_write_16(zr, 0x036, reg); + + reg = tvn->Wt - 1; /* Htotal */ + zr36060_write_16(zr, 0x038, reg); + + reg = 6 - 1; /* VsyncSize */ + zr36060_write_8(zr, 0x03a, reg); + + //reg = 30 - 1; /* HsyncSize */ + reg = (zr->params.norm == 1 ? 57 : 68); + zr36060_write_8(zr, 0x03b, reg); + + reg = tvn->VStart - 1; /* BVstart */ + zr36060_write_8(zr, 0x03c, reg); + + reg += tvn->Ha / 2; /* BVend */ + zr36060_write_16(zr, 0x03e, reg); + + reg = tvn->HStart + 64 - 1; /* BHstart */ + zr36060_write_8(zr, 0x03d, reg); + + reg += tvn->Wa; /* BHend */ + zr36060_write_16(zr, 0x040, reg); + + /* active area */ + reg = zr->params.img_y + tvn->VStart; /* Vstart */ + zr36060_write_16(zr, 0x042, reg); + + reg += zr->params.img_height; /* Vend */ + zr36060_write_16(zr, 0x044, reg); + + HStart = tvn->HStart; + if (zr->card == BUZ) { + HStart += 44; + } else { + HStart += 64; + } + reg = zr->params.img_x + HStart; /* Hstart */ + zr36060_write_16(zr, 0x046, reg); + + reg += zr->params.img_width; /* Hend */ + zr36060_write_16(zr, 0x048, reg); + + /* subimage area */ + reg = tvn->VStart - 4; /* SVstart */ + zr36060_write_16(zr, 0x04a, reg); + + reg += tvn->Ha / 2 + 8; /* SVend */ + zr36060_write_16(zr, 0x04c, reg); + + reg = tvn->HStart + 64 - 4; /* SHstart */ + zr36060_write_16(zr, 0x04e, reg); + + reg += tvn->Wa + 8; /* SHend */ + zr36060_write_16(zr, 0x050, reg); +} + +static void zr36060_set_jpg_SOF(struct zoran *zr) +{ + u32 reg; + + + reg = 0xffc0; /* SOF marker */ + zr36060_write_16(zr, 0x060, reg); + + reg = 17; /* SOF length */ + zr36060_write_16(zr, 0x062, reg); + + reg = 8; /* precision 8 bits */ + zr36060_write_8(zr, 0x064, reg); + + reg = zr->params.img_height / zr->params.VerDcm; /* image height */ + zr36060_write_16(zr, 0x065, reg); + + reg = zr->params.img_width / zr->params.HorDcm; /* image width */ + zr36060_write_16(zr, 0x067, reg); + + reg = 3; /* 3 color components */ + zr36060_write_8(zr, 0x069, reg); + + reg = 0x002100; /* Y component */ + zr36060_write_24(zr, 0x06a, reg); + + reg = 0x011101; /* U component */ + zr36060_write_24(zr, 0x06d, reg); + + reg = 0x021101; /* V component */ + zr36060_write_24(zr, 0x070, reg); +} + +static void zr36060_set_jpg_SOS(struct zoran *zr) +{ + u32 reg; + + + reg = 0xffda; /* SOS marker */ + zr36060_write_16(zr, 0x07a, reg); + + reg = 12; /* SOS length */ + zr36060_write_16(zr, 0x07c, reg); + + reg = 3; /* 3 color components */ + zr36060_write_8(zr, 0x07e, reg); + + reg = 0x0000; /* Y component */ + zr36060_write_16(zr, 0x07f, reg); + + reg = 0x0111; /* U component */ + zr36060_write_16(zr, 0x081, reg); + + reg = 0x0211; /* V component */ + zr36060_write_16(zr, 0x083, reg); + + reg = 0x003f00; /* Start, end spectral scans */ + zr36060_write_24(zr, 0x085, reg); +} + +static void zr36060_set_jpg_DRI(struct zoran *zr) +{ + u32 reg; + + + reg = 0xffdd; /* DRI marker */ + zr36060_write_16(zr, 0x0c0, reg); + + reg = 4; /* DRI length */ + zr36060_write_16(zr, 0x0c2, reg); + + reg = 8; /* length in MCUs */ + zr36060_write_16(zr, 0x0c4, reg); +} + +static void zr36060_set_jpg_DQT(struct zoran *zr) +{ + unsigned i; + unsigned adr; + static const u8 dqt[] = { + 0xff, 0xdb, /* DHT marker */ + 0x00, 0x84, /* DHT length */ + 0x00, /* table ID 0 */ + 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, + 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, + 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, + 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, + 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44, + 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, + 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, + 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, + 0x01, /* table ID 1 */ + 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, + 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 + }; + + /* write fixed quantitization tables */ + adr = 0x0cc; + for (i = 0; i < sizeof(dqt); ++i) { + zr36060_write_8(zr, adr++, dqt[i]); + } +} + +static void zr36060_set_jpg_DHT(struct zoran *zr) +{ + unsigned i; + unsigned adr; + static const u8 dht[] = { + 0xff, 0xc4, /* DHT marker */ + 0x01, 0xa2, /* DHT length */ + 0x00, /* table class 0, ID 0 */ + 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, /* # codes of length 1..8 */ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* # codes of length 8..16 */ + 0x00, /* values for codes of length 2 */ + 0x01, 0x02, 0x03, 0x04, 0x05, /* values for codes of length 3 */ + 0x06, /* values for codes of length 4 */ + 0x07, /* values for codes of length 5 */ + 0x08, /* values for codes of length 6 */ + 0x09, /* values for codes of length 7 */ + 0x0a, /* values for codes of length 8 */ + 0x0b, /* values for codes of length 9 */ + 0x01, /* table class 0, ID 1 */ + 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* # codes of length 1..8 */ + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, /* # codes of length 9..16 */ + 0x00, 0x01, 0x02, /* values for codes of length 2 */ + 0x03, /* values for codes of length 3 */ + 0x04, /* values for codes of length 4 */ + 0x05, /* values for codes of length 5 */ + 0x06, /* values for codes of length 6 */ + 0x07, /* values for codes of length 7 */ + 0x08, /* values for codes of length 8 */ + 0x09, /* values for codes of length 9 */ + 0x0a, /* values for codes of length 10 */ + 0x0b, /* values for codes of length 11 */ + 0x10, + 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, + 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, + 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, + 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, + 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, + 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, + 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, + 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, + 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, + 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, + 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, + 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, + 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, + 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, + 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, + 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0xf7, 0xf8, 0xf9, 0xfa + }; + + /* write fixed Huffman tables */ + adr = 0x1d4; + for (i = 0; i < sizeof(dht); ++i) { + zr36060_write_8(zr, adr++, dht[i]); + } +} + +static void zr36060_set_jpg_APP(struct zoran *zr) +{ + unsigned adr; + int len, i; + u32 reg; + + + len = zr->params.APP_len; + if (len < 0) + len = 0; + if (len > 60) + len = 60; + + i = zr->params.APPn; + if (i < 0) + i = 0; + if (i > 15) + i = 15; + + reg = 0xffe0 + i; /* APPn marker */ + zr36060_write_16(zr, 0x380, reg); + + reg = len + 2; /* APPn len */ + zr36060_write_16(zr, 0x382, reg); + + /* write APPn data */ + adr = 0x384; + for (i = 0; i < 60; i++) { + zr36060_write_8(zr, adr++, + (i < len ? zr->params.APP_data[i] : 0)); + } +} + +static void zr36060_set_jpg_COM(struct zoran *zr) +{ + unsigned adr; + int len, i; + u32 reg; + + + len = zr->params.COM_len; + if (len < 0) + len = 0; + if (len > 60) + len = 60; + + reg = 0xfffe; /* COM marker */ + zr36060_write_16(zr, 0x3c0, reg); + + reg = len + 2; /* COM len */ + zr36060_write_16(zr, 0x3c2, reg); + + /* write COM data */ + adr = 0x3c4; + for (i = 0; i < 60; i++) { + zr36060_write_8(zr, adr++, + (i < len ? zr->params.COM_data[i] : 0)); + } +} + +static void zr36060_set_cap(struct zoran *zr, enum zoran_codec_mode mode) +{ + unsigned i; + u32 reg; + + zr36060_reset(zr); + mdelay(10); + + reg = (0 << 7) /* Load=0 */ + |(1 << 0); /* SynRst=1 */ + zr36060_write_8(zr, 0x000, reg); + + zr36060_set_jpg(zr, mode); + zr36060_set_video(zr, mode); + zr36060_set_jpg_SOF(zr); + zr36060_set_jpg_SOS(zr); + zr36060_set_jpg_DRI(zr); + zr36060_set_jpg_DQT(zr); + zr36060_set_jpg_DHT(zr); + zr36060_set_jpg_APP(zr); + zr36060_set_jpg_COM(zr); + + reg = (1 << 7) /* Load=1 */ + |(1 << 0); /* SynRst=0 */ + zr36060_write_8(zr, 0x000, reg); + + /* wait for codec to unbusy */ + for (i = 0; i < 100000; ++i) { + reg = zr36060_read_8(zr, 0x001); + if ((reg & (1 << 7)) == 0) { + return; + } + //udelay(100); + } + printk(KERN_ERR "%sZR36060: stuck busy, statux=%02x\n", zr->name, + reg); +} + +static void init_jpeg_queue(struct zoran *zr) +{ + int i; + /* re-initialize DMA ring stuff */ + zr->jpg_que_head = 0; + zr->jpg_dma_head = 0; + zr->jpg_dma_tail = 0; + zr->jpg_que_tail = 0; + zr->jpg_seq_num = 0; + zr->JPEG_error = 0; + zr->num_errors = 0; + zr->jpg_err_seq = 0; + zr->jpg_err_shift = 0; + zr->jpg_queued_num = 0; + for (i = 0; i < zr->jpg_nbufs; i++) { + zr->jpg_gbuf[i].state = BUZ_STATE_USER; /* nothing going on */ + } + for (i = 0; i < BUZ_NUM_STAT_COM; i++) { + zr->stat_com[i] = 1; /* mark as unavailable to zr36057 */ + } +} + +static void zr36057_set_jpg(struct zoran *zr, enum zoran_codec_mode mode) +{ + struct tvnorm *tvn; + u32 reg; + + tvn = zr->timing; + + /* assert P_Reset */ + btwrite(0, ZR36057_JPC); + + /* MJPEG compression mode */ + switch (mode) { + + case BUZ_MODE_MOTION_COMPRESS: + default: + reg = ZR36057_JMC_MJPGCmpMode; + break; + + case BUZ_MODE_MOTION_DECOMPRESS: + reg = ZR36057_JMC_MJPGExpMode; + reg |= ZR36057_JMC_SyncMstr; + /* RJ: The following is experimental - improves the output to screen */ + //if(zr->params.VFIFO_FB) reg |= ZR36057_JMC_VFIFO_FB; // No, it doesn't. SM + break; + + case BUZ_MODE_STILL_COMPRESS: + reg = ZR36057_JMC_JPGCmpMode; + break; + + case BUZ_MODE_STILL_DECOMPRESS: + reg = ZR36057_JMC_JPGExpMode; + break; + + } + reg |= ZR36057_JMC_JPG; + if (zr->params.field_per_buff == 1) + reg |= ZR36057_JMC_Fld_per_buff; + btwrite(reg, ZR36057_JMC); + + /* vertical */ + btor(ZR36057_VFEVCR_VSPol, ZR36057_VFEVCR); + reg = + (6 << ZR36057_VSP_VsyncSize) | (tvn->Ht << ZR36057_VSP_FrmTot); + btwrite(reg, ZR36057_VSP); + reg = ((zr->params.img_y + tvn->VStart) << ZR36057_FVAP_NAY) + | (zr->params.img_height << ZR36057_FVAP_PAY); + btwrite(reg, ZR36057_FVAP); + + /* horizontal */ + btor(ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR); + reg = + ((tvn->HSyncStart) << ZR36057_HSP_HsyncStart) | (tvn-> + Wt << + ZR36057_HSP_LineTot); + btwrite(reg, ZR36057_HSP); + reg = ((zr->params.img_x + tvn->HStart + 4) << ZR36057_FHAP_NAX) + | (zr->params.img_width << ZR36057_FHAP_PAX); + btwrite(reg, ZR36057_FHAP); + + /* field process parameters */ + if (zr->params.odd_even) + reg = ZR36057_FPP_Odd_Even; + else + reg = 0; + if (mode == BUZ_MODE_MOTION_DECOMPRESS && zr->card != LML33 + && zr->card != BUZ) + reg ^= ZR36057_FPP_Odd_Even; + + btwrite(reg, ZR36057_FPP); + + /* Set proper VCLK Polarity, else colors will be wrong during playback */ + //btor(ZR36057_VFESPFR_VCLKPol, ZR36057_VFESPFR); + + /* code base address */ + reg = virt_to_bus(zr->stat_com); + btwrite(reg, ZR36057_JCBA); + + /* FIFO threshold (FIFO is 160. double words) */ + /* NOTE: decimal values here */ + switch (mode) { + + case BUZ_MODE_STILL_COMPRESS: + case BUZ_MODE_MOTION_COMPRESS: + reg = 140; + break; + + case BUZ_MODE_STILL_DECOMPRESS: + case BUZ_MODE_MOTION_DECOMPRESS: + reg = 20; + break; + + default: + reg = 80; + break; + + } + btwrite(reg, ZR36057_JCFT); + zr36057_adjust_vfe(zr, mode); + +} + +#if (DEBUGLEVEL > 2) +static void dump_guests(struct zoran *zr) +{ + int i, guest[8]; + + for (i = 1; i < 8; i++) { // Don't read zr36060 here + guest[i] = post_office_read(zr, i, 0); + } + + printk(KERN_INFO "%s: Guests:", zr->name); + + for (i = 1; i < 8; i++) { + printk(" 0x%02x", guest[i]); + } + printk("\n"); +} + +static unsigned long get_time(void) +{ + struct timeval tv; + do_gettimeofday(&tv); + return (1000000 * tv.tv_sec + tv.tv_usec); +} + +static void detect_guest_activity(struct zoran *zr) +{ + int timeout, i, j, res, guest[8], guest0[8], change[8][3]; + unsigned long t0, t1; + + dump_guests(zr); + printk(KERN_INFO "%s: Detecting guests activity, please wait...\n", + zr->name); + for (i = 1; i < 8; i++) { // Don't read zr36060 here + guest0[i] = guest[i] = post_office_read(zr, i, 0); + } + + timeout = 0; + j = 0; + t0 = get_time(); + while (timeout < 10000) { + udelay(10); + timeout++; + for (i = 1; (i < 8) && (j < 8); i++) { + res = post_office_read(zr, i, 0); + if (res != guest[i]) { + t1 = get_time(); + change[j][0] = (t1 - t0); + t0 = t1; + change[j][1] = i; + change[j][2] = res; + j++; + guest[i] = res; + } + } + if (j >= 8) + break; + } + printk(KERN_INFO "%s: Guests:", zr->name); + + for (i = 1; i < 8; i++) { + printk(" 0x%02x", guest0[i]); + } + printk("\n"); + if (j == 0) { + printk(KERN_INFO "%s: No activity detected.\n", zr->name); + return; + } + for (i = 0; i < j; i++) { + printk(KERN_INFO "%s: %6d: %d => 0x%02x\n", zr->name, + change[i][0], change[i][1], change[i][2]); + } +} +#endif + +static void print_interrupts(struct zoran *zr) +{ + int res, noerr; + noerr = 0; + printk(KERN_INFO "%s: interrupts received:", zr->name); + if ((res = zr->field_counter) < -1 || res > 1) { + printk(" FD:%d", res); + } + if ((res = zr->intr_counter_GIRQ1) != 0) { + printk(" GIRQ1:%d", res); + noerr++; + } + if ((res = zr->intr_counter_GIRQ0) != 0) { + printk(" GIRQ0:%d", res); + noerr++; + } + if ((res = zr->intr_counter_CodRepIRQ) != 0) { + printk(" CodRepIRQ:%d", res); + noerr++; + } + if ((res = zr->intr_counter_JPEGRepIRQ) != 0) { + printk(" JPEGRepIRQ:%d", res); + noerr++; + } + if (zr->JPEG_max_missed) { + printk(" JPEG delays: max=%d min=%d", zr->JPEG_max_missed, + zr->JPEG_min_missed); + } + if (zr->END_event_missed) { + printk(" ENDs missed: %d", zr->END_event_missed); + } + //if (zr->jpg_queued_num) { + printk(" queue_state=%ld/%ld/%ld/%ld", zr->jpg_que_tail, + zr->jpg_dma_tail, zr->jpg_dma_head, zr->jpg_que_head); + //} + if (!noerr) { + printk(": no interrupts detected."); + } + printk("\n"); +} + +static void clear_interrupt_counters(struct zoran *zr) +{ + zr->intr_counter_GIRQ1 = 0; + zr->intr_counter_GIRQ0 = 0; + zr->intr_counter_CodRepIRQ = 0; + zr->intr_counter_JPEGRepIRQ = 0; + zr->field_counter = 0; + zr->IRQ1_in = 0; + zr->IRQ1_out = 0; + zr->JPEG_in = 0; + zr->JPEG_out = 0; + zr->JPEG_0 = 0; + zr->JPEG_1 = 0; + zr->END_event_missed = 0; + zr->JPEG_missed = 0; + zr->JPEG_max_missed = 0; + zr->JPEG_min_missed = 0x7fffffff; +} + +static u32 count_reset_interrupt(struct zoran *zr) +{ + u32 isr; + if ((isr = btread(ZR36057_ISR) & 0x78000000)) { + if (isr & ZR36057_ISR_GIRQ1) { + btwrite(ZR36057_ISR_GIRQ1, ZR36057_ISR); + zr->intr_counter_GIRQ1++; + } + if (isr & ZR36057_ISR_GIRQ0) { + btwrite(ZR36057_ISR_GIRQ0, ZR36057_ISR); + zr->intr_counter_GIRQ0++; + } + if (isr & ZR36057_ISR_CodRepIRQ) { + btwrite(ZR36057_ISR_CodRepIRQ, ZR36057_ISR); + zr->intr_counter_CodRepIRQ++; + } + if (isr & ZR36057_ISR_JPEGRepIRQ) { + btwrite(ZR36057_ISR_JPEGRepIRQ, ZR36057_ISR); + zr->intr_counter_JPEGRepIRQ++; + } + } + return isr; +} + +static void jpeg_start(struct zoran *zr) +{ + int reg; + zr->frame_num = 0; + + btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC); // /P_Reset + btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR); // \CFlush + btor(ZR36057_JPC_CodTrnsEn, ZR36057_JPC); // /CodTrnsEn + btwrite(IRQ_MASK, ZR36057_ISR); // Clear IRQs + btwrite(IRQ_MASK | ZR36057_ICR_IntPinEn, ZR36057_ICR); // Enable IRQs + + set_frame(zr, 0); // \FRAME + + /* JPEG codec guest ID */ + reg = + (1 << ZR36057_JCGI_JPEGuestID) | (0 << + ZR36057_JCGI_JPEGuestReg); + btwrite(reg, ZR36057_JCGI); + + btor(ZR36057_JPC_Active, ZR36057_JPC); // /Active + btor(ZR36057_JMC_Go_en, ZR36057_JMC); // /Go_en + udelay(30); + set_frame(zr, 1); // /FRAME +} + +static void zr36057_enable_jpg(struct zoran *zr, + enum zoran_codec_mode mode) +{ + static int zero = 0; + static int one = 1; + unsigned long timeout; + + zr->codec_mode = mode; + switch (mode) { + + case BUZ_MODE_MOTION_COMPRESS: + set_videobus_enable(zr, 0); + set_videobus_dir(zr, 0); // GPIO(zr, 1, 0); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, + DECODER_ENABLE_OUTPUT, &one); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, + ENCODER_SET_INPUT, &zero); + set_videobus_enable(zr, 1); + zr36060_sleep(zr, 0); + zr36060_set_cap(zr, mode); // Load ZR36060 + init_jpeg_queue(zr); + zr36057_set_jpg(zr, mode); // \P_Reset, ... Video param, FIFO + + clear_interrupt_counters(zr); + DEBUG1(printk + (KERN_INFO "%s: enable_jpg MOTION_COMPRESS\n", + zr->name)); + break; + + case BUZ_MODE_MOTION_DECOMPRESS: + set_videobus_enable(zr, 0); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, + DECODER_ENABLE_OUTPUT, &zero); + set_videobus_dir(zr, 1); // GPIO(zr, 1, 1); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, + ENCODER_SET_INPUT, &one); + set_videobus_enable(zr, 1); + zr36060_sleep(zr, 0); + zr36060_set_cap(zr, mode); // Load ZR36060 + init_jpeg_queue(zr); + zr36057_set_jpg(zr, mode); // \P_Reset, ... Video param, FIFO + + clear_interrupt_counters(zr); + DEBUG1(printk + (KERN_INFO "%s: enable_jpg MOTION_DECOMPRESS\n", + zr->name)); + break; + + case BUZ_MODE_IDLE: + default: + /* shut down processing */ + btand(~(cardjpegint[zr->card] | ZR36057_ICR_JPEGRepIRQ), + ZR36057_ICR); + btwrite(cardjpegint[zr->card] | ZR36057_ICR_JPEGRepIRQ, + ZR36057_ISR); + btand(~ZR36057_JMC_Go_en, ZR36057_JMC); // \Go_en + + timeout = jiffies + HZ / 20; + while (jiffies < timeout) + schedule(); + + set_videobus_dir(zr, 0); // GPIO(zr, 1, 0); + set_frame(zr, 1); //GPIO(zr, 6, 1); // /FRAME + btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR); // /CFlush + btwrite(0, ZR36057_JPC); // \P_Reset,\CodTrnsEn,\Active + btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC); + btand(~ZR36057_JMC_SyncMstr, ZR36057_JMC); + zr36060_reset(zr); + zr36060_sleep(zr, 1); + zr36057_adjust_vfe(zr, mode); + set_videobus_enable(zr, 0); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, + DECODER_ENABLE_OUTPUT, &one); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, + ENCODER_SET_INPUT, &zero); + set_videobus_enable(zr, 1); + DEBUG1(printk + (KERN_INFO "%s: enable_jpg IDLE\n", zr->name)); + break; + + } +} + +/* + * Queue a MJPEG buffer for capture/playback + */ + +static int jpg_qbuf(struct zoran *zr, int frame, + enum zoran_codec_mode mode) +{ + unsigned long flags; + int res; + + /* Check if buffers are allocated */ + + if (!zr->jpg_buffers_allocated) { + printk(KERN_ERR + "%s: jpg_qbuf: buffers not yet allocated\n", + zr->name); + return -ENOMEM; + } + + /* Does the user want to stop streaming? */ + + if (frame < 0) { + if (zr->codec_mode == mode) { + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); + return 0; + } else { + printk(KERN_ERR + "%s: jpg_qbuf - stop streaming but not in streaming mode\n", + zr->name); + return -EINVAL; + } + } + + /* No grabbing outside the buffer range! */ + + if (frame >= zr->jpg_nbufs) { + printk(KERN_ERR "%s: jpg_qbuf: buffer %d out of range\n", + zr->name, frame); + return -EINVAL; + } + + /* what is the codec mode right now? */ + + if (zr->codec_mode == BUZ_MODE_IDLE) { + /* Ok load up the zr36060 */ + zr36057_enable_jpg(zr, mode); + } else if (zr->codec_mode != mode) { + /* wrong codec mode active - invalid */ + printk(KERN_ERR "%s: jpg_qbuf - codec in wrong mode\n", + zr->name); + return -EINVAL; + } + + spin_lock_irqsave(&zr->lock, flags); + + /* make sure a grab isn't going on currently with this buffer */ + + switch (zr->jpg_gbuf[frame].state) { + + case BUZ_STATE_DONE: + DEBUG1(printk + (KERN_WARNING + "%s: Warning: queing frame in BUZ_STATE_DONE state\n", + zr->name)); + case BUZ_STATE_USER: + /* since there is at least one unused buffer there's room for at least one more pend[] entry */ + zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] = frame; + zr->jpg_gbuf[frame].state = BUZ_STATE_PEND; + zoran_feed_stat_com(zr); + res = 0; + break; + + default: + case BUZ_STATE_DMA: + case BUZ_STATE_PEND: + res = -EBUSY; /* what are you doing? */ + break; + + } + + spin_unlock_irqrestore(&zr->lock, flags); + + /* Start the zr36060 when the first frame is queued */ + if (zr->jpg_que_head == 1) + jpeg_start(zr); + + return res; +} + +/* + * Sync on a MJPEG buffer + */ + +static int jpg_sync(struct zoran *zr, struct zoran_sync *bs) +{ + unsigned long flags; + int frame, timeout; + + if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS + && zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) { + printk(KERN_ERR + "%s: BUZIOCSYNC: - codec not in streaming mode\n", + zr->name); + return -EINVAL; + } + while (zr->jpg_que_tail == zr->jpg_dma_tail) { + if (zr->jpg_dma_tail == zr->jpg_dma_head) + break; + timeout = + interruptible_sleep_on_timeout(&zr->jpg_capq, 10 * HZ); + if (!timeout) { + btand(~ZR36057_JMC_Go_en, ZR36057_JMC); + udelay(1); + printk(KERN_ERR + "%s: timeout: codec isr=0x%02x, csr=0x%02x\n", + zr->name, zr36060_read_8(zr, 0x008), + zr36060_read_8(zr, 0x001)); + return -ETIME; + } else if (signal_pending(current)) + return -ERESTARTSYS; + } + + spin_lock_irqsave(&zr->lock, flags); + + if (zr->jpg_dma_tail != zr->jpg_dma_head) + frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME]; + else + frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME]; + /* buffer should now be in BUZ_STATE_DONE */ + +#if(DEBUGLEVEL > 0) + if (zr->jpg_gbuf[frame].state != BUZ_STATE_DONE) + printk(KERN_ERR "%s: jpg_sync - internal error\n", + zr->name); +#endif + + *bs = zr->jpg_gbuf[frame].bs; + zr->jpg_gbuf[frame].state = BUZ_STATE_USER; + + spin_unlock_irqrestore(&zr->lock, flags); + + return 0; +} + +/* when this is called the spinlock must be held */ +static void zoran_feed_stat_com(struct zoran *zr) +{ + /* move frames from pending queue to DMA */ + + int frame, i, max_stat_com; + + max_stat_com = + (zr->params.TmpDcm == + 1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1); + + while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com + && zr->jpg_dma_head < zr->jpg_que_head) { + + frame = zr->jpg_pend[zr->jpg_dma_head & BUZ_MASK_FRAME]; + if (zr->params.TmpDcm == 1) { + /* fill 1 stat_com entry */ + i = (zr->jpg_dma_head - + zr->jpg_err_shift) & BUZ_MASK_STAT_COM; + if (!(zr->stat_com[i] & 1)) + break; + zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus; + } else { + /* fill 2 stat_com entries */ + i = ((zr->jpg_dma_head - + zr->jpg_err_shift) & 1) * 2; + if (!(zr->stat_com[i] & 1)) + break; + zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus; + zr->stat_com[i + 1] = + zr->jpg_gbuf[frame].frag_tab_bus; + } + zr->jpg_gbuf[frame].state = BUZ_STATE_DMA; + zr->jpg_dma_head++; + + } + if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) + zr->jpg_queued_num++; +} + +/* when this is called the spinlock must be held */ +static void zoran_reap_stat_com(struct zoran *zr) +{ + /* move frames from DMA queue to done queue */ + + int i; + u32 stat_com; + unsigned int seq; + unsigned int dif; + int frame; + struct zoran_gbuffer *gbuf; + + /* In motion decompress we don't have a hardware frame counter, + we just count the interrupts here */ + + if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) { + zr->jpg_seq_num++; + } + while (zr->jpg_dma_tail < zr->jpg_dma_head) { + if (zr->params.TmpDcm == 1) + i = (zr->jpg_dma_tail - + zr->jpg_err_shift) & BUZ_MASK_STAT_COM; + else + i = ((zr->jpg_dma_tail - + zr->jpg_err_shift) & 1) * 2 + 1; + + stat_com = zr->stat_com[i]; + + if ((stat_com & 1) == 0) { + return; + } + frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME]; + gbuf = &zr->jpg_gbuf[frame]; + get_fast_time(&gbuf->bs.timestamp); + + if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { + gbuf->bs.length = (stat_com & 0x7fffff) >> 1; + + /* update sequence number with the help of the counter in stat_com */ + + seq = ((stat_com >> 24) + zr->jpg_err_seq) & 0xff; + dif = (seq - zr->jpg_seq_num) & 0xff; + zr->jpg_seq_num += dif; + } else { + gbuf->bs.length = 0; + } + gbuf->bs.seq = + zr->params.TmpDcm == + 2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num; + gbuf->state = BUZ_STATE_DONE; + + zr->jpg_dma_tail++; + } +} + +static void error_handler(struct zoran *zr, u32 astat, u32 stat) +{ + /* This is JPEG error handling part */ + if ((zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) + && (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS)) { + //printk(KERN_ERR "%s: Internal error: error handling request in mode %d\n", zr->name, zr->codec_mode); + return; + } + if ((stat & 1) == 0 + && zr->codec_mode == BUZ_MODE_MOTION_COMPRESS + && zr->jpg_dma_tail - zr->jpg_que_tail >= zr->jpg_nbufs) { + /* No free buffers... */ + zoran_reap_stat_com(zr); + zoran_feed_stat_com(zr); + wake_up_interruptible(&zr->jpg_capq); + zr->JPEG_missed = 0; + return; + } + if (zr->JPEG_error != 1) { + /* + * First entry: error just happened during normal operation + * + * In BUZ_MODE_MOTION_COMPRESS: + * + * Possible glitch in TV signal. In this case we should + * stop the codec and wait for good quality signal before + * restarting it to avoid further problems + * + * In BUZ_MODE_MOTION_DECOMPRESS: + * + * Bad JPEG frame: we have to mark it as processed (codec crashed + * and was not able to do it itself), and to remove it from queue. + */ + btand(~ZR36057_JMC_Go_en, ZR36057_JMC); + udelay(1); + stat = + stat | (post_office_read(zr, 7, 0) & 3) << 8 | + zr36060_read_8(zr, 0x008); + btwrite(0, ZR36057_JPC); + btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR); + zr36060_reset(zr); + zr36060_sleep(zr, 1); + zr->JPEG_error = 1; + zr->num_errors++; + /* Report error */ +#if(DEBUGLEVEL > 1) + if (zr->num_errors <= 8) { + long frame; + frame = + zr->jpg_pend[zr-> + jpg_dma_tail & BUZ_MASK_FRAME]; + printk(KERN_ERR + "%s: JPEG error stat=0x%08x(0x%08x) queue_state=%ld/%ld/%ld/%ld seq=%ld frame=%ld. Codec stopped. ", + zr->name, stat, zr->last_isr, + zr->jpg_que_tail, zr->jpg_dma_tail, + zr->jpg_dma_head, zr->jpg_que_head, + zr->jpg_seq_num, frame); + printk("stat_com frames:"); + { + int i, j; + for (j = 0; j < BUZ_NUM_STAT_COM; j++) { + for (i = 0; i < zr->jpg_nbufs; i++) { + if (zr->stat_com[j] == + zr->jpg_gbuf[i]. + frag_tab_bus) { + printk("% d->%d", + j, i); + } + } + } + printk("\n"); + } + } +#endif + /* Find an entry in stat_com and rotate contents */ + { + int i; + + if (zr->params.TmpDcm == 1) + i = (zr->jpg_dma_tail - + zr-> + jpg_err_shift) & BUZ_MASK_STAT_COM; + else + i = ((zr->jpg_dma_tail - + zr->jpg_err_shift) & 1) * 2; + if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) { + /* Mimic zr36067 operation */ + zr->stat_com[i] |= 1; + if (zr->params.TmpDcm != 1) + zr->stat_com[i + 1] |= 1; + /* Refill */ + zoran_reap_stat_com(zr); + zoran_feed_stat_com(zr); + wake_up_interruptible(&zr->jpg_capq); + /* Find an entry in stat_com again after refill */ + if (zr->params.TmpDcm == 1) + i = (zr->jpg_dma_tail - + zr-> + jpg_err_shift) & + BUZ_MASK_STAT_COM; + else + i = ((zr->jpg_dma_tail - + zr->jpg_err_shift) & 1) * 2; + } + if (i) { + /* Rotate stat_comm entries to make current entry first */ + int j; + u32 bus_addr[BUZ_NUM_STAT_COM]; + + memcpy(bus_addr, zr->stat_com, + sizeof(bus_addr)); + for (j = 0; j < BUZ_NUM_STAT_COM; j++) { + zr->stat_com[j] = + bus_addr[(i + + j) & + BUZ_MASK_STAT_COM]; + } + zr->jpg_err_shift += i; + zr->jpg_err_shift &= BUZ_MASK_STAT_COM; + } + if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) + zr->jpg_err_seq = zr->jpg_seq_num; /* + 1; */ + } + } + /* Now the stat_comm buffer is ready for restart */ + { + int status; + + status = 0; + if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) + i2c_control_device(&zr->i2c, + I2C_DRIVERID_VIDEODECODER, + DECODER_GET_STATUS, &status); + if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS + || (status & DECODER_STATUS_GOOD)) { + /********** RESTART code *************/ + zr36060_reset(zr); + zr36060_set_cap(zr, zr->codec_mode); + zr36057_set_jpg(zr, zr->codec_mode); + jpeg_start(zr); +#if(DEBUGLEVEL > 1) + if (zr->num_errors <= 8) + printk(KERN_INFO "%s: Restart\n", + zr->name); +#endif + zr->JPEG_missed = 0; + zr->JPEG_error = 2; + /********** End RESTART code ***********/ + } + } +} + +static void zoran_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 stat, astat; + int count; + struct zoran *zr; + unsigned long flags; + + zr = (struct zoran *) dev_id; + count = 0; + + if (zr->testing) { + /* Testing interrupts */ + spin_lock_irqsave(&zr->lock, flags); + while ((stat = count_reset_interrupt(zr))) { + if (count++ > 100) { + btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); + printk(KERN_ERR + "%s: IRQ lockup while testing, isr=0x%08x, cleared int mask\n", + zr->name, stat); + wake_up_interruptible(&zr->test_q); + } + } + zr->last_isr = stat; + spin_unlock_irqrestore(&zr->lock, flags); + return; + } + + spin_lock_irqsave(&zr->lock, flags); + while (1) { + /* get/clear interrupt status bits */ + stat = count_reset_interrupt(zr); + astat = stat & IRQ_MASK; + if (!astat) { + break; + } + if (astat & cardvsync[zr->card]) { // SW + + if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS + || zr->codec_mode == + BUZ_MODE_MOTION_COMPRESS) { + /* count missed interrupts */ + zr->JPEG_missed++; + } + //post_office_read(zr,1,0); + /* Interrupts may still happen when zr->v4l_memgrab_active is switched off. + We simply ignore them */ + + if (zr->v4l_memgrab_active) { + + /* A lot more checks should be here ... */ + if ((btread(ZR36057_VSSFGR) & + ZR36057_VSSFGR_SnapShot) == 0) + printk(KERN_WARNING + "%s: BuzIRQ with SnapShot off ???\n", + zr->name); + + if (zr->v4l_grab_frame != NO_GRAB_ACTIVE) { + /* There is a grab on a frame going on, check if it has finished */ + + if ((btread(ZR36057_VSSFGR) & + ZR36057_VSSFGR_FrameGrab) == + 0) { + /* it is finished, notify the user */ + + zr->v4l_gbuf[zr-> + v4l_grab_frame]. + state = BUZ_STATE_DONE; + zr->v4l_grab_frame = + NO_GRAB_ACTIVE; + zr->v4l_grab_seq++; + zr->v4l_pend_tail++; + } + } + + if (zr->v4l_grab_frame == NO_GRAB_ACTIVE) + wake_up_interruptible(&zr-> + v4l_capq); + + /* Check if there is another grab queued */ + + if (zr->v4l_grab_frame == NO_GRAB_ACTIVE + && zr->v4l_pend_tail != + zr->v4l_pend_head) { + + int frame = + zr->v4l_pend[zr-> + v4l_pend_tail & + V4L_MASK_FRAME]; + u32 reg; + + zr->v4l_grab_frame = frame; + + /* Set zr36057 video front end and enable video */ + + /* Buffer address */ + + reg = + zr->v4l_gbuf[frame]. + fbuffer_bus; + btwrite(reg, ZR36057_VDTR); + if (zr->video_interlace) + reg += zr->gbpl; + btwrite(reg, ZR36057_VDBR); + + /* video stride, status, and frame grab register */ + + reg = 0; + if (zr->video_interlace) + reg += zr->gbpl; + reg = + (reg << + ZR36057_VSSFGR_DispStride); + reg |= ZR36057_VSSFGR_VidOvf; + reg |= ZR36057_VSSFGR_SnapShot; + reg |= ZR36057_VSSFGR_FrameGrab; + btwrite(reg, ZR36057_VSSFGR); + + btor(ZR36057_VDCR_VidEn, + ZR36057_VDCR); + } + } + } +#if (IRQ_MASK & ZR36057_ISR_CodRepIRQ) + if (astat & ZR36057_ISR_CodRepIRQ) { + zr->intr_counter_CodRepIRQ++; + IDEBUG(printk + (KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n", + zr->name)); + btand(~ZR36057_ICR_CodRepIRQ, ZR36057_ICR); + } +#endif /* (IRQ_MASK & ZR36057_ISR_CodRepIRQ) */ + +#if (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) + if (astat & ZR36057_ISR_JPEGRepIRQ) { + + if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS + || zr->codec_mode == + BUZ_MODE_MOTION_COMPRESS) { +#if(DEBUGLEVEL > 1) + if (!zr->frame_num || zr->JPEG_error) { + printk(KERN_INFO + "%s: first frame ready: state=0x%08x odd_even=%d field_per_buff=%d delay=%d\n", + zr->name, stat, + zr->params.odd_even, + zr->params.field_per_buff, + zr->JPEG_missed); + { + char sc[] = "0000"; + char sv[5]; + int i; + strcpy(sv, sc); + for (i = 0; i < 4; i++) { + if (zr-> + stat_com[i] & + 1) + sv[i] = + '1'; + } + sv[4] = 0; + printk(KERN_INFO + "%s: stat_com=%s queue_state=%ld/%ld/%ld/%ld\n", + zr->name, sv, + zr->jpg_que_tail, + zr->jpg_dma_tail, + zr->jpg_dma_head, + zr->jpg_que_head); + } + } else { + if (zr->JPEG_missed > zr->JPEG_max_missed) // Get statistics + zr->JPEG_max_missed = + zr->JPEG_missed; + if (zr->JPEG_missed < + zr->JPEG_min_missed) + zr->JPEG_min_missed = + zr->JPEG_missed; + } +#endif +#if(DEBUGLEVEL > 2) + if (zr->frame_num < 6) { + int i; + printk("%s: seq=%ld stat_com:", + zr->name, zr->jpg_seq_num); + for (i = 0; i < 4; i++) { + printk(" %08x", + zr->stat_com[i]); + } + printk("\n"); + } +#endif + zr->frame_num++; + zr->JPEG_missed = 0; + zr->JPEG_error = 0; + zoran_reap_stat_com(zr); + zoran_feed_stat_com(zr); + wake_up_interruptible(&zr->jpg_capq); + } //else { + // printk(KERN_ERR "%s: JPEG interrupt while not in motion (de)compress mode!\n", zr->name); + //} + } +#endif /* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */ + + if ((astat & cardjpegint[zr->card]) /* DATERR interrupt received */ + ||zr->JPEG_missed > 25 /* Too many fields missed without processing */ + || zr->JPEG_error == 1 /* We are already in error processing */ + || ((zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) + && (zr-> + frame_num & (zr->JPEG_missed > + zr->params.field_per_buff))) + /* fields missed during decompression */ + ) { + error_handler(zr, astat, stat); + } + + count++; + if (count > 10) { + printk(KERN_WARNING "%s: irq loop %d\n", zr->name, + count); + if (count > 20) { + btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); + printk(KERN_ERR + "%s: IRQ lockup, cleared int mask\n", + zr->name); + break; + } + } + zr->last_isr = stat; + } + spin_unlock_irqrestore(&zr->lock, flags); +} + +/* Check a zoran_params struct for correctness, insert default params */ + +static int zoran_check_params(struct zoran *zr, + struct zoran_params *params) +{ + int err = 0, err0 = 0; + + /* insert constant params */ + + params->major_version = MAJOR_VERSION; + params->minor_version = MINOR_VERSION; + + /* Check input and norm: must be set by calling VIDIOCSCHAN only! */ + + params->norm = zr->params.norm; + params->input = zr->params.input; + + /* Check decimation, set default values for decimation = 1, 2, 4 */ + + switch (params->decimation) { + case 1: + + params->HorDcm = 1; + params->VerDcm = 1; + params->TmpDcm = 1; + params->field_per_buff = 2; + + params->img_x = 0; + params->img_y = 0; + params->img_width = zr->timing->Wa; + params->img_height = zr->timing->Ha / 2; + break; + + case 2: + + params->HorDcm = 2; + params->VerDcm = 1; + params->TmpDcm = 2; + params->field_per_buff = 1; + + params->img_x = 8; + params->img_y = 0; + params->img_width = zr->timing->Wa; + params->img_height = zr->timing->Ha / 2; + break; + + case 4: + + params->HorDcm = 4; + params->VerDcm = 2; + params->TmpDcm = 2; + params->field_per_buff = 1; + + params->img_x = 8; + params->img_y = 0; + params->img_width = zr->timing->Wa; + params->img_height = zr->timing->Ha / 2; + break; + + case 0: + + /* We have to check the data the user has set */ + + if (params->HorDcm != 1 && params->HorDcm != 2 + && params->HorDcm != 4) + err0++; + if (params->VerDcm != 1 && params->VerDcm != 2) + err0++; + if (params->TmpDcm != 1 && params->TmpDcm != 2) + err0++; + if (params->field_per_buff != 1 + && params->field_per_buff != 2) + err0++; + + if (params->img_x < 0) + err0++; + if (params->img_y < 0) + err0++; + if (params->img_width < 0) + err0++; + if (params->img_height < 0) + err0++; + if (params->img_x + params->img_width > zr->timing->Wa) + err0++; + if (params->img_y + params->img_height > + zr->timing->Ha / 2) + err0++; + if (params->HorDcm) { + if (params->img_width % (16 * params->HorDcm) != 0) + err0++; + if (params->img_height % (8 * params->VerDcm) != 0) + err0++; + } + + if (err0) { + printk(KERN_ERR + "%s: SET PARAMS: error in params for decimation = 0\n", + zr->name); + err++; + } + break; + + default: + printk(KERN_ERR + "%s: SET PARAMS: decimation = %d, must be 0, 1, 2 or 4\n", + zr->name, params->decimation); + err++; + break; + } + + if (params->quality > 100) + params->quality = 100; + if (params->quality < 5) + params->quality = 5; + + if (params->APPn < 0) + params->APPn = 0; + if (params->APPn > 15) + params->APPn = 15; + if (params->APP_len < 0) + params->APP_len = 0; + if (params->APP_len > 60) + params->APP_len = 60; + if (params->COM_len < 0) + params->COM_len = 0; + if (params->COM_len > 60) + params->COM_len = 60; + + if (err) + return -EINVAL; + + return 0; + +} +static void zoran_open_init_params(struct zoran *zr) +{ + int i; + + /* Per default, map the V4L Buffers */ + + zr->map_mjpeg_buffers = 0; + + /* User must explicitly set a window */ + + zr->window_set = 0; + + zr->window.x = 0; + zr->window.y = 0; + zr->window.width = 0; + zr->window.height = 0; + zr->window.chromakey = 0; + zr->window.flags = 0; + zr->window.clips = NULL; + zr->window.clipcount = 0; + + zr->video_interlace = 0; + + zr->v4l_memgrab_active = 0; + zr->v4l_overlay_active = 0; + + zr->v4l_grab_frame = NO_GRAB_ACTIVE; + zr->v4l_grab_seq = 0; + + zr->gwidth = 0; + zr->gheight = 0; + zr->gformat = 0; + zr->gbpl = 0; + + /* DMA ring stuff for V4L */ + + zr->v4l_pend_tail = 0; + zr->v4l_pend_head = 0; + for (i = 0; i < v4l_nbufs; i++) { + zr->v4l_gbuf[i].state = BUZ_STATE_USER; /* nothing going on */ + } + + /* Set necessary params and call zoran_check_params to set the defaults */ + + zr->params.decimation = 1; + + zr->params.quality = 50; /* default compression factor 8 */ + if (zr->card != BUZ) + zr->params.odd_even = 1; + else + zr->params.odd_even = 0; + + zr->params.APPn = 0; + zr->params.APP_len = 0; /* No APPn marker */ + for (i = 0; i < 60; i++) + zr->params.APP_data[i] = 0; + + zr->params.COM_len = 0; /* No COM marker */ + for (i = 0; i < 60; i++) + zr->params.COM_data[i] = 0; + + zr->params.VFIFO_FB = 0; + + memset(zr->params.reserved, 0, sizeof(zr->params.reserved)); + + zr->params.jpeg_markers = JPEG_MARKER_DHT | JPEG_MARKER_DQT; + + i = zoran_check_params(zr, &zr->params); + if (i) + printk(KERN_ERR + "%s: zoran_open_init_params internal error\n", + zr->name); + + clear_interrupt_counters(zr); + zr->testing = 0; +} + +/* + * Open a zoran card. Right now the flags stuff is just playing + */ + +static int zoran_open(struct video_device *dev, int flags) +{ + struct zoran *zr = (struct zoran *) dev; + //int one = 1; + + DEBUG1(printk + (KERN_INFO "%s: zoran_open, %s pid=[%d]\n", zr->name, + current->comm, current->pid)); + + switch (flags) { + + case 0: + if (zr->user > 1) { + printk(KERN_WARNING + "%s: zoran_open: Buz is allready in use\n", + zr->name); + return -EBUSY; + } + zr->user++; + + if (zr->user == 1 && v4l_fbuffer_alloc(zr) < 0) { + zr->user--; + printk(KERN_ERR + "%s: zoran_open: v4l_fbuffer_alloc failed\n", + zr->name); + return -ENOMEM; + } + + /* default setup */ + + if (zr->user == 1) { /* First device open */ + zoran_open_init_params(zr); + + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); + + btwrite(IRQ_MASK, ZR36057_ISR); // Clears interrupts + btor(ZR36057_ICR_IntPinEn, ZR36057_ICR); + dev->busy = 0; /* Allow second open */ + } + + break; + + default: + printk(KERN_WARNING + "%s: zoran_open: flags = 0x%x not yet supported\n", + zr->name, flags); + return -EBUSY; + break; + + } + MOD_INC_USE_COUNT; + return 0; +} + +static void zoran_close(struct video_device *dev) +{ + struct zoran *zr = (struct zoran *) dev; + int zero = 0, two = 2; + + DEBUG1(printk + (KERN_INFO "%s: zoran_close, %s pid=[%d]\n", zr->name, + current->comm, current->pid)); + /* Clean up JPEG process */ + + wake_up_interruptible(&zr->jpg_capq); + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); + jpg_fbuffer_free(zr); + zr->jpg_nbufs = 0; + + if (zr->user == 1) { /* Last process */ + /* disable interrupts */ + btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); + +#if(DEBUGLEVEL > 1) + print_interrupts(zr); +#endif + /* Overlay off */ + wake_up_interruptible(&zr->v4l_capq); + zr36057_set_memgrab(zr, 0); + if (zr->v4l_overlay_active) + zr36057_overlay(zr, 0); + v4l_fbuffer_free(zr); + + if (!pass_through) { /* Switch to color bar */ + set_videobus_enable(zr, 0); + i2c_control_device(&zr->i2c, + I2C_DRIVERID_VIDEODECODER, + DECODER_ENABLE_OUTPUT, &zero); + i2c_control_device(&zr->i2c, + I2C_DRIVERID_VIDEOENCODER, + ENCODER_SET_INPUT, &two); + set_videobus_enable(zr, 1); + } + } + + zr->user--; + + MOD_DEC_USE_COUNT; + DEBUG2(printk(KERN_INFO "%s: zoran_close done\n", zr->name)); +} + + +static long zoran_read(struct video_device *dev, char *buf, + unsigned long count, int nonblock) +{ + return -EINVAL; +} + +static long zoran_write(struct video_device *dev, const char *buf, + unsigned long count, int nonblock) +{ + return -EINVAL; +} + +/* + * ioctl routine + */ + + +static int zoran_ioctl(struct video_device *dev, unsigned int cmd, + void *arg) +{ + struct zoran *zr = (struct zoran *) dev; + + switch (cmd) { + + case VIDIOCGCAP: + { + struct video_capability b; + DEBUG2(printk("%s: ioctl VIDIOCGCAP\n", zr->name)); + + strncpy(b.name, zr->video_dev.name, + sizeof(b.name)); + b.type = + VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | + VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM | + VID_TYPE_SCALES; + /* theoretically we could also flag VID_TYPE_SUBCAPTURE + but this is not even implemented in the BTTV driver */ + + if (zr->card == DC10 || zr->card == DC10plus) { + b.channels = 3; /* composite, svhs, internal */ + } else { + b.channels = 2; /* composite, svhs */ + } + b.audios = 0; + b.maxwidth = BUZ_MAX_WIDTH; + b.maxheight = BUZ_MAX_HEIGHT; + b.minwidth = BUZ_MIN_WIDTH; + b.minheight = BUZ_MIN_HEIGHT; + if (copy_to_user(arg, &b, sizeof(b))) { + return -EFAULT; + } + return 0; + } + break; + + case VIDIOCGCHAN: + { + struct video_channel v; + + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + DEBUG2(printk + ("%s: ioctl VIDIOCGCHAN for channel %d\n", + zr->name, v.channel)); + switch (v.channel) { + case 0: + strcpy(v.name, "Composite"); + break; + case 1: + strcpy(v.name, "SVHS"); + break; + case 2: + if (zr->card == DC10 + || zr->card == DC10plus) { + strcpy(v.name, "Internal/comp"); + break; + } + default: + printk(KERN_ERR + "%s: VIDIOCGCHAN on not existing channel %d\n", + zr->name, v.channel); + return -EINVAL; + } + v.tuners = 0; + v.flags = 0; + v.type = VIDEO_TYPE_CAMERA; + v.norm = zr->params.norm; + if (copy_to_user(arg, &v, sizeof(v))) { + return -EFAULT; + } + return 0; + } + break; + + /* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says: + + * "The VIDIOCSCHAN ioctl takes an integer argument and switches the capture to this input." + * ^^^^^^^ + * The famos BTTV driver has it implemented with a struct video_channel argument + * and we follow it for compatibility reasons + * + * BTW: this is the only way the user can set the norm! + */ + + case VIDIOCSCHAN: + { + struct video_channel v; + int input; + int on, res; + int encoder_norm; + + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + + if (zr->codec_mode != BUZ_MODE_IDLE) { + if (v.norm != zr->params.norm + || v.channel != zr->params.input) { + printk(KERN_ERR + "%s: VIDIOCSCHAN called while the card in capture/playback mode\n", + zr->name); + return -EINVAL; + } else { + printk(BUZ_WARNING + "%s: Warning: VIDIOCSCHAN called while the card in capture/playback mode\n", + zr->name); + } + } + + DEBUG2(printk + ("%s: ioctl VIDIOCSCHAN: channel=%d, norm=%d\n", + zr->name, v.channel, v.norm)); + switch (v.channel) { + case 0: + if (zr->card == BUZ) + input = 3; + else + input = 0; + break; + case 1: + input = 7; + break; + case 2: + if (zr->card == DC10 + || zr->card == DC10plus) { + input = 5; + break; + } + default: + printk(KERN_ERR + "%s: VIDIOCSCHAN on not existing channel %d\n", + zr->name, v.channel); + return -EINVAL; + break; + } + + if (lock_norm && v.norm != zr->params.norm) { + if (lock_norm > 1) { + printk(KERN_WARNING + "%s: VIDIOCSCHAN: TV standard is locked, can not switch norm.\n", + zr->name); + return -EINVAL; + } else { + printk(KERN_WARNING + "%s: VIDIOCSCHAN: TV standard is locked, norm was not changed.\n", + zr->name); + v.norm = zr->params.norm; + } + } + + if (!cardnorms[zr->card][v.norm]) { + printk(KERN_ERR + "%s: VIDIOCSCHAN with not supported norm %d\n", + zr->name, v.norm); + return -EOPNOTSUPP; + break; + } + encoder_norm = v.norm; + + zr->params.norm = v.norm; + zr->params.input = v.channel; + zr->timing = cardnorms[zr->card][zr->params.norm]; + + /* We switch overlay off and on since a change in the norm + needs different VFE settings */ + + on = zr->v4l_overlay_active + && !zr->v4l_memgrab_active; + if (on) + zr36057_overlay(zr, 0); + + set_videobus_enable(zr, 0); + 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, + &encoder_norm); + set_videobus_enable(zr, 1); + + if (on) + zr36057_overlay(zr, 1); + + /* Make sure the changes come into effect */ + res = wait_grab_pending(zr); + if (res) + return res; + + return 0; + } + break; + + case VIDIOCGTUNER: + { + printk(KERN_ERR + "%s: ioctl VIDIOCGTUNER not supported\n", + zr->name); + return -EINVAL; + } + break; + + case VIDIOCSTUNER: + { + printk(KERN_ERR + "%s: ioctl VIDIOCSTUNER not supported\n", + zr->name); + return -EINVAL; + } + break; + + case VIDIOCGPICT: + { + struct video_picture p = zr->picture; + + DEBUG2(printk + ("%s: ioctl VIDIOCGPICT\n", zr->name)); + p.depth = zr->buffer.depth; + switch (zr->buffer.depth) { + case 15: + p.palette = VIDEO_PALETTE_RGB555; + break; + + case 16: + p.palette = VIDEO_PALETTE_RGB565; + break; + + case 24: + p.palette = VIDEO_PALETTE_RGB24; + break; + + case 32: + p.palette = VIDEO_PALETTE_RGB32; + break; + } + + if (copy_to_user(arg, &p, sizeof(p))) { + return -EFAULT; + } + return 0; + } + break; + + case VIDIOCSPICT: + { + struct video_picture p; + + if (copy_from_user(&p, arg, sizeof(p))) { + return -EFAULT; + } + i2c_control_device(&zr->i2c, + I2C_DRIVERID_VIDEODECODER, + DECODER_SET_PICTURE, &p); + DEBUG2(printk + ("%s: ioctl VIDIOCSPICT bri=%d hue=%d col=%d con=%d dep=%d pal=%d\n", + zr->name, p.brightness, p.hue, p.colour, + p.contrast, p.depth, p.palette)); + /* The depth and palette values have no meaning to us, + should we return -EINVAL if they don't fit ? */ + zr->picture = p; + return 0; + } + break; + + case VIDIOCCAPTURE: + { + int v, res; + + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + DEBUG2(printk + ("%s: ioctl VIDIOCCAPTURE: %d\n", zr->name, + v)); + + /* If there is nothing to do, return immediatly */ + + if ((v && zr->v4l_overlay_active) + || (!v && !zr->v4l_overlay_active)) + return 0; + + if (v == 0) { + zr->v4l_overlay_active = 0; + if (!zr->v4l_memgrab_active) + zr36057_overlay(zr, 0); + /* When a grab is running, the video simply won't be switched on any more */ + } else { + if (!zr->buffer_set || !zr->window_set) { + printk(KERN_ERR + "%s: VIDIOCCAPTURE: buffer or window not set\n", + zr->name); + return -EINVAL; + } + zr->v4l_overlay_active = 1; + if (!zr->v4l_memgrab_active) + zr36057_overlay(zr, 1); + /* When a grab is running, the video will be switched on when grab is finished */ + } + /* Make sure the changes come into effect */ + res = wait_grab_pending(zr); + if (res) + return res; + return 0; + } + break; + + case VIDIOCGWIN: + { + DEBUG2(printk("%s: ioctl VIDIOCGWIN\n", zr->name)); + if (copy_to_user + (arg, &zr->window, sizeof(zr->window))) { + return -EFAULT; + } + return 0; + } + break; + + case VIDIOCSWIN: + { + struct video_clip *vcp; + struct video_window vw; + struct tvnorm *tvn; + int on, end, res, Wa, Ha; + + tvn = zr->timing; + + Wa = tvn->Wa; + Ha = tvn->Ha; + + if (copy_from_user(&vw, arg, sizeof(vw))) { + return -EFAULT; + } + + DEBUG2(printk + ("%s: ioctl VIDIOCSWIN: x=%d y=%d w=%d h=%d clipcount=%d\n", + zr->name, vw.x, vw.y, vw.width, vw.height, + vw.clipcount)); + + if (!zr->buffer_set) { + printk(KERN_ERR + "%s: VIDIOCSWIN: frame buffer has to be set first\n", + zr->name); + return -EINVAL; + } + + /* + * The video front end needs 4-byte alinged line sizes, we correct that + * silently here if necessary + */ + + if (zr->buffer.depth == 15 + || zr->buffer.depth == 16) { + end = (vw.x + vw.width) & ~1; /* round down */ + vw.x = (vw.x + 1) & ~1; /* round up */ + vw.width = end - vw.x; + } + + if (zr->buffer.depth == 24) { + end = (vw.x + vw.width) & ~3; /* round down */ + vw.x = (vw.x + 3) & ~3; /* round up */ + vw.width = end - vw.x; + } + + if (vw.width > Wa) + vw.width = Wa; + if (vw.height > Ha) + vw.height = Ha; + + /* Check for vaild parameters */ + if (vw.width < BUZ_MIN_WIDTH + || vw.height < BUZ_MIN_HEIGHT + || vw.width > BUZ_MAX_WIDTH + || vw.height > BUZ_MAX_HEIGHT) { + printk(KERN_ERR + "%s: VIDIOCSWIN: width = %d or height = %d invalid\n", + zr->name, vw.width, vw.height); + return -EINVAL; + } + + zr->window.x = vw.x; + zr->window.y = vw.y; + zr->window.width = vw.width; + zr->window.height = vw.height; + zr->window.chromakey = 0; + zr->window.flags = 0; // RJ: Is this intended for interlace on/off ? + zr->window.clips = NULL; + zr->window.clipcount = vw.clipcount; + + /* + * If an overlay is running, we have to switch it off + * and switch it on again in order to get the new settings in effect. + * + * We also want to avoid that the overlay mask is written + * when an overlay is running. + */ + + on = zr->v4l_overlay_active + && !zr->v4l_memgrab_active; + if (on) + zr36057_overlay(zr, 0); + + /* + * Write the overlay mask if clips are wanted. + */ + if (vw.clipcount) { + vcp = + vmalloc(sizeof(struct video_clip) * + (vw.clipcount + 4)); + if (vcp == NULL) { + printk(KERN_ERR + "%s: zoran_ioctl: Alloc of clip mask failed\n", + zr->name); + return -ENOMEM; + } + if (copy_from_user + (vcp, vw.clips, + sizeof(struct video_clip) * + vw.clipcount)) { + vfree(vcp); + return -EFAULT; + } + write_overlay_mask(zr, vcp, vw.clipcount); + vfree(vcp); + } + + if (on) + zr36057_overlay(zr, 1); + zr->window_set = 1; + + /* Make sure the changes come into effect */ + res = wait_grab_pending(zr); + if (res) + return res; + + return 0; + } + break; + + case VIDIOCGFBUF: + { + DEBUG2(printk + ("%s: ioctl VIDIOCGFBUF\n", zr->name)); + if (copy_to_user + (arg, &zr->buffer, sizeof(zr->buffer))) { + return -EFAULT; + } + return 0; + } + break; + + case VIDIOCSFBUF: + { + struct video_buffer v; + + /* RJ: Isn't this too restrictive? As long as the user doesn't set + the base address it shouldn't be too dangerous */ + + if (!capable(CAP_SYS_ADMIN)) { + printk(KERN_ERR + "%s: Only the superuser may issue VIDIOCSFBUF ioctl\n", + zr->name); + return -EPERM; + } + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + DEBUG2(printk + ("%s: ioctl VIDIOCSFBUF: base=0x%x w=%d h=%d depth=%d bpl=%d\n", + zr->name, (u32) v.base, v.width, v.height, + v.depth, v.bytesperline)); + if (zr->v4l_overlay_active) { + /* Has the user gotten crazy ... ? */ + printk(KERN_ERR + "%s: VIDIOCSFBUF not allowed when overlay active\n", + zr->name); + return -EINVAL; + } + if (v.depth != 15 && v.depth != 16 && v.depth != 24 + && v.depth != 32) { + printk(KERN_ERR + "%s: VIDIOCSFBUF: depth=%d not supported\n", + zr->name, v.depth); + return -EINVAL; + } + if (v.height <= 0 || v.width <= 0 + || v.bytesperline <= 0) { + printk(KERN_ERR + "%s: VIDIOCSFBUF: invalid height/width/bpl value\n", + zr->name); + return -EINVAL; + } + if (v.bytesperline & 3) { + printk(KERN_ERR + "%s: VIDIOCSFBUF: bytesperline must be 4-byte aligned\n", + zr->name); + return -EINVAL; + } + if (v.base) { + zr->buffer.base = + (void *) ((unsigned long) v.base & ~3); + } + zr->buffer.height = v.height; + zr->buffer.width = v.width; + zr->buffer.depth = v.depth; + zr->buffer.bytesperline = v.bytesperline; + + if (zr->buffer.base) + zr->buffer_set = 1; + zr->window_set = 0; /* The user should set new window parameters */ + return 0; + } + break; + + /* RJ: what is VIDIOCKEY intended to do ??? */ + + case VIDIOCKEY: + { + /* Will be handled higher up .. */ + DEBUG2(printk("%s: ioctl VIDIOCKEY\n", zr->name)); + return 0; + } + break; + + case VIDIOCGFREQ: + { + printk(KERN_ERR + "%s: ioctl VIDIOCGFREQ not supported\n", + zr->name); + return -EINVAL; + } + break; + + case VIDIOCSFREQ: + { + printk(KERN_ERR + "%s: ioctl VIDIOCSFREQ not supported\n", + zr->name); + return -EINVAL; + } + break; + + case VIDIOCGAUDIO: + { + printk(KERN_ERR + "%s: ioctl VIDIOCGAUDIO not supported\n", + zr->name); + return -EINVAL; + } + break; + + case VIDIOCSAUDIO: + { + printk(KERN_ERR + "%s: ioctl VIDIOCSAUDIO not supported\n", + zr->name); + return -EINVAL; + } + break; + + case VIDIOCSYNC: + { + int v; + + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + DEBUG3(printk + ("%s: ioctl VIDIOCSYNC %d\n", zr->name, v)); + return v4l_sync(zr, v); + } + break; + + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + + if (copy_from_user + ((void *) &vm, (void *) arg, sizeof(vm))) { + return -EFAULT; + } + DEBUG2(printk + ("%s: ioctl VIDIOCMCAPTURE frame=%d geom=%dx%d fmt=%d\n", + zr->name, vm.frame, vm.width, vm.height, + vm.format)); + return v4l_grab(zr, &vm); + } + break; + + case VIDIOCGMBUF: + { + struct video_mbuf vm; + int i; + + DEBUG2(printk + ("%s: ioctl VIDIOCGMBUF\n", zr->name)); + vm.size = v4l_nbufs * v4l_bufsize; + vm.frames = v4l_nbufs; + for (i = 0; i < v4l_nbufs; i++) { + vm.offsets[i] = i * v4l_bufsize; + } + + /* The next mmap will map the V4L buffers */ + zr->map_mjpeg_buffers = 0; + + if (copy_to_user(arg, &vm, sizeof(vm))) { + return -EFAULT; + } + return 0; + } + break; + + case VIDIOCGUNIT: + { + struct video_unit vu; + + DEBUG2(printk + ("%s: ioctl VIDIOCGUNIT\n", zr->name)); + vu.video = zr->video_dev.minor; + vu.vbi = VIDEO_NO_UNIT; + vu.radio = VIDEO_NO_UNIT; + vu.audio = VIDEO_NO_UNIT; + vu.teletext = VIDEO_NO_UNIT; + if (copy_to_user(arg, &vu, sizeof(vu))) { + return -EFAULT; + } + return 0; + } + break; + + /* + * RJ: In principal we could support subcaptures for V4L grabbing. + * Not even the famous BTTV driver has them, however. + * If there should be a strong demand, one could consider + * to implement them. + */ + case VIDIOCGCAPTURE: + { + printk(KERN_ERR + "%s: ioctl VIDIOCGCAPTURE not supported\n", + zr->name); + return -EINVAL; + } + break; + + case VIDIOCSCAPTURE: + { + printk(KERN_ERR + "%s: ioctl VIDIOCSCAPTURE not supported\n", + zr->name); + return -EINVAL; + } + break; + + case BUZIOC_G_PARAMS: + { + DEBUG2(printk + ("%s: ioctl BUZIOC_G_PARAMS\n", zr->name)); + + if (copy_to_user + (arg, &(zr->params), sizeof(zr->params))) { + return -EFAULT; + } + return 0; + } + break; + + case BUZIOC_S_PARAMS: + { + struct zoran_params bp; + /* int input, on; */ + + if (zr->codec_mode != BUZ_MODE_IDLE) { + printk(KERN_ERR + "%s: BUZIOC_S_PARAMS called but Buz in capture/playback mode\n", + zr->name); + return -EINVAL; + } + + if (copy_from_user(&bp, arg, sizeof(bp))) { + return -EFAULT; + } + DEBUG2(printk + ("%s: ioctl BUZIOC_S_PARAMS\n", zr->name)); + + /* Check the params first before overwriting our internal values */ + + if (zoran_check_params(zr, &bp)) + return -EINVAL; + + zr->params = bp; + + /* Make changes of input and norm go into effect immediatly */ + + /* We switch overlay off and on since a change in the norm + needs different VFE settings */ + + if (copy_to_user(arg, &bp, sizeof(bp))) { + return -EFAULT; + } + return 0; + } + break; + + case BUZIOC_REQBUFS: + { + struct zoran_requestbuffers br; + + if (zr->jpg_buffers_allocated) { + printk(KERN_ERR + "%s: BUZIOC_REQBUFS: buffers allready allocated\n", + zr->name); + return -EINVAL; + } + if (copy_from_user(&br, arg, sizeof(br))) { + return -EFAULT; + } + DEBUG2(printk + ("%s: ioctl BUZIOC_REQBUFS count = %lu size=%lu\n", + zr->name, br.count, br.size)); + + /* Enforce reasonable lower and upper limits */ + if (br.count < 4) + br.count = 4; /* Could be choosen smaller */ + if (br.count > BUZ_MAX_FRAME) + br.count = BUZ_MAX_FRAME; + br.size = PAGE_ALIGN(br.size); + if (br.size < 8192) + br.size = 8192; /* Arbitrary */ + /* br.size is limited by 1 page for the stat_com tables to a Maximum of 2 MB */ + if (br.size > (512 * 1024)) + br.size = (512 * 1024); /* 512 K should be enough */ + if (zr->need_contiguous + && br.size > MAX_KMALLOC_MEM) + br.size = MAX_KMALLOC_MEM; + + zr->jpg_nbufs = br.count; + zr->jpg_bufsize = br.size; + + if (jpg_fbuffer_alloc(zr)) + return -ENOMEM; + + /* The next mmap will map the MJPEG buffers */ + zr->map_mjpeg_buffers = 1; + + if (copy_to_user(arg, &br, sizeof(br))) { + return -EFAULT; + } + return 0; + } + break; + + case BUZIOC_QBUF_CAPT: + { + int nb; + + if (copy_from_user + ((void *) &nb, (void *) arg, sizeof(int))) { + return -EFAULT; + } + DEBUG4(printk + ("%s: ioctl BUZIOC_QBUF_CAPT %d\n", + zr->name, nb)); + return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_COMPRESS); + } + break; + + case BUZIOC_QBUF_PLAY: + { + int nb; + + if (copy_from_user + ((void *) &nb, (void *) arg, sizeof(int))) { + return -EFAULT; + } + DEBUG4(printk + ("%s: ioctl BUZIOC_QBUF_PLAY %d\n", + zr->name, nb)); + return jpg_qbuf(zr, nb, + BUZ_MODE_MOTION_DECOMPRESS); + } + break; + + case BUZIOC_SYNC: + { + struct zoran_sync bs; + int res; + + DEBUG4(printk + ("%s: ioctl BUZIOC_SYNC\n", zr->name)); + res = jpg_sync(zr, &bs); + if (copy_to_user(arg, &bs, sizeof(bs))) { + return -EFAULT; + } + return res; + } + break; + + case BUZIOC_G_STATUS: + { + struct zoran_status bs; + int norm, input, status; + unsigned long timeout; + + if (zr->codec_mode != BUZ_MODE_IDLE) { + printk(KERN_ERR + "%s: BUZIOC_G_STATUS called but Buz in capture/playback mode\n", + zr->name); + return -EINVAL; + } + + if (copy_from_user(&bs, arg, sizeof(bs))) { + return -EFAULT; + } + DEBUG2(printk + ("%s: ioctl BUZIOC_G_STATUS\n", zr->name)); + + switch (bs.input) { + case 0: + if (zr->card == BUZ) + input = 3; + else + input = 0; + break; + case 1: + input = 7; + break; + default: + printk(KERN_ERR + "%s: BUZIOC_G_STATUS on not existing input %d\n", + zr->name, bs.input); + return -EINVAL; + } + + /* Set video norm to VIDEO_MODE_AUTO */ + + norm = VIDEO_MODE_AUTO; + set_videobus_enable(zr, 0); + i2c_control_device(&zr->i2c, + I2C_DRIVERID_VIDEODECODER, + DECODER_SET_INPUT, &input); + i2c_control_device(&zr->i2c, + I2C_DRIVERID_VIDEODECODER, + DECODER_SET_NORM, &norm); + set_videobus_enable(zr, 1); + + /* sleep 1 second */ + + timeout = jiffies + 1 * HZ; + while (jiffies < timeout) + schedule(); + + /* Get status of video decoder */ + + i2c_control_device(&zr->i2c, + I2C_DRIVERID_VIDEODECODER, + DECODER_GET_STATUS, &status); + bs.signal = (status & DECODER_STATUS_GOOD) ? 1 : 0; + + if (status & DECODER_STATUS_NTSC) + bs.norm = VIDEO_MODE_NTSC; + else if (status & DECODER_STATUS_SECAM) + bs.norm = VIDEO_MODE_SECAM; + else + bs.norm = VIDEO_MODE_PAL; + + bs.color = (status & DECODER_STATUS_COLOR) ? 1 : 0; + + /* restore previous input and norm */ + if (zr->card == BUZ) + input = zr->params.input == 0 ? 3 : 7; + else + input = zr->params.input == 0 ? 0 : 7; + set_videobus_enable(zr, 0); + 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); + set_videobus_enable(zr, 1); + + if (copy_to_user(arg, &bs, sizeof(bs))) { + return -EFAULT; + } + return 0; + } + break; + + default: + DEBUG1(printk + ("%s: UNKNOWN ioctl cmd: 0x%x\n", zr->name, cmd)); + return -ENOIOCTLCMD; + break; + + } + return 0; +} + + +/* + * This maps the buffers to user space. + * + * Depending on the state of zr->map_mjpeg_buffers + * the V4L or the MJPEG buffers are mapped + * + */ + +static int zoran_mmap(struct video_device *dev, const char *adr, + unsigned long size) +{ + struct zoran *zr = (struct zoran *) dev; + unsigned long start = (unsigned long) adr; + unsigned long page, pos, todo, fraglen; + int i, j; + + DEBUG2(printk + (KERN_INFO "%s: mmap at 0x%08lx, size %lu\n", zr->name, + start, size)); + if (zr->map_mjpeg_buffers) { + /* Map the MJPEG buffers */ + + if (!zr->jpg_buffers_allocated) { + printk(KERN_ERR + "%s: zoran_mmap(MJPEG): buffers not yet allocated\n", + zr->name); + return -ENOMEM; + } + + if (size > zr->jpg_nbufs * zr->jpg_bufsize) { + printk(KERN_ERR + "%s: zoran_mmap(MJPEG): Max size is %lu - you wanted %lu\n", + zr->name, zr->jpg_nbufs * zr->jpg_bufsize, + size); + return -EINVAL; + } + + if (size != zr->jpg_nbufs * zr->jpg_bufsize) + printk(KERN_WARNING + "%s: zoran_mmap(MJPEG): Expected %lu - you wanted %lu\n", + zr->name, zr->jpg_nbufs * zr->jpg_bufsize, + size); + + for (i = 0; i < zr->jpg_nbufs; i++) { + for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { + fraglen = + (zr->jpg_gbuf[i]. + frag_tab[2 * j + 1] & ~1) << 1; + todo = size; + if (todo > fraglen) + todo = fraglen; + pos = + (unsigned long) zr->jpg_gbuf[i]. + frag_tab[2 * j]; + page = virt_to_phys(bus_to_virt(pos)); /* should just be pos on i386 */ + if (remap_page_range + (start, page, todo, PAGE_SHARED)) { + printk(KERN_ERR + "%s: zoran_mmap(V4L): remap_page_range failed\n", + zr->name); + return -EAGAIN; + } + size -= todo; + start += todo; + if (size == 0) + break; + if (zr->jpg_gbuf[i]. + frag_tab[2 * j + 1] & 1) + break; /* was last fragment */ + } + if (size == 0) + break; + } + } else { + /* Map the V4L buffers */ + + if (size > v4l_nbufs * v4l_bufsize) { + printk(KERN_ERR + "%s: zoran_mmap(V4L): Max size is %d - you wanted %ld\n", + zr->name, v4l_nbufs * v4l_bufsize, size); + return -EINVAL; + } + + if (size != v4l_nbufs * v4l_bufsize) + printk(KERN_WARNING + "%s: zoran_mmap(V4L): Expected %d - you wanted %ld\n", + zr->name, v4l_nbufs * v4l_bufsize, size); + + for (i = 0; i < v4l_nbufs; i++) { + todo = size; + if (todo > v4l_bufsize) + todo = v4l_bufsize; + page = zr->v4l_gbuf[i].fbuffer_phys; + DEBUG2(printk + ("V4L remap page range %d 0x%lx %ld to 0x%lx\n", + i, page, todo, start)); + if (remap_page_range + (start, page, todo, PAGE_SHARED)) { + printk(KERN_ERR + "%s: zoran_mmap(V4L): remap_page_range failed\n", + zr->name); + return -EAGAIN; + } + size -= todo; + start += todo; + if (size == 0) + break; + } + } + return 0; +} + +static int zoran_init_done(struct video_device *dev) +{ + return 0; +} + +static struct video_device zoran_template = { + THIS_MODULE, + ZORAN_NAME, + VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | + VID_TYPE_FRAMERAM | VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE, + ZORAN_HARDWARE, + zoran_open, + zoran_close, + zoran_read, + zoran_write, + NULL, + zoran_ioctl, + zoran_mmap, + zoran_init_done, + NULL, + 0, + 0 +}; + +/* + * initialize video front end + */ +static void zr36057_init_vfe(struct zoran *zr) +{ + u32 reg; + reg = btread(ZR36057_VFESPFR); + reg |= ZR36057_VFESPFR_LittleEndian; + reg &= ~ZR36057_VFESPFR_VCLKPol; + reg |= ZR36057_VFESPFR_ExtFl; + reg |= ZR36057_VFESPFR_TopField; + btwrite(reg, ZR36057_VFESPFR); + reg = btread(ZR36057_VDCR); + if (triton || zr->revision <= 1) + reg &= ~ZR36057_VDCR_Triton; + else + reg |= ZR36057_VDCR_Triton; + btwrite(reg, ZR36057_VDCR); +} + +static void test_interrupts(struct zoran *zr) +{ + int timeout, icr; + + clear_interrupt_counters(zr); + zr->testing = 1; + icr = btread(ZR36057_ICR); + btwrite(0x78000000 | ZR36057_ICR_IntPinEn, ZR36057_ICR); + timeout = interruptible_sleep_on_timeout(&zr->test_q, 1 * HZ); + btwrite(0, ZR36057_ICR); + btwrite(0x78000000, ZR36057_ISR); + zr->testing = 0; + printk(KERN_INFO "%s: Testing interrupts...\n", zr->name); + if (timeout) { + printk(": time spent: %d\n", 1 * HZ - timeout); + } + print_interrupts(zr); + btwrite(icr, ZR36057_ICR); +} + +static int zr36057_init(int i) +{ + struct zoran *zr = &zoran[i]; + unsigned long mem; + unsigned mem_needed; + int j; + int two = 2; + int zero = 0; + + printk(KERN_INFO "%s: Initializing card[%d], zr=%x\n", zr->name, i, (int) zr); + + /* default setup of all parameters which will persist beetween opens */ + + zr->user = 0; + + init_waitqueue_head(&zr->v4l_capq); + init_waitqueue_head(&zr->jpg_capq); + init_waitqueue_head(&zr->test_q); + + zr->map_mjpeg_buffers = 0; /* Map V4L buffers by default */ + + zr->jpg_nbufs = 0; + zr->jpg_bufsize = 0; + zr->jpg_buffers_allocated = 0; + + zr->buffer_set = 0; /* Flag if frame buffer has been set */ + zr->buffer.base = (void *) vidmem; + zr->buffer.width = 0; + zr->buffer.height = 0; + zr->buffer.depth = 0; + zr->buffer.bytesperline = 0; + + zr->params.norm = default_norm = (default_norm < 3 ? default_norm : VIDEO_MODE_PAL); /* Avoid nonsense settings from user */ + if (!(zr->timing = cardnorms[zr->card][zr->params.norm])) { + printk(KERN_WARNING + "%s: default TV statdard not supported by hardware. PAL will be used.\n", + zr->name); + zr->params.norm = VIDEO_MODE_PAL; + zr->timing = cardnorms[zr->card][zr->params.norm]; + } + zr->params.input = default_input = (default_input ? 1 : 0); /* Avoid nonsense settings from user */ + zr->video_interlace = 0; + + /* Should the following be reset at every open ? */ + + zr->picture.colour = 32768; + zr->picture.brightness = 32768; + zr->picture.hue = 32768; + zr->picture.contrast = 32768; + zr->picture.whiteness = 0; + zr->picture.depth = 0; + zr->picture.palette = 0; + + for (j = 0; j < VIDEO_MAX_FRAME; j++) { + zr->v4l_gbuf[i].fbuffer = 0; + zr->v4l_gbuf[i].fbuffer_phys = 0; + zr->v4l_gbuf[i].fbuffer_bus = 0; + } + + zr->stat_com = 0; + + /* default setup (will be repeated at every open) */ + + zoran_open_init_params(zr); + + /* allocate memory *before* doing anything to the hardware in case allocation fails */ + + /* STAT_COM table and overlay mask */ + + mem_needed = (BUZ_NUM_STAT_COM + ((BUZ_MAX_WIDTH + 31) / 32) * BUZ_MAX_HEIGHT) * 4; + mem = (unsigned long) kmalloc(mem_needed, GFP_KERNEL); + if (!mem) { + printk(KERN_ERR "%s: zr36057_init: kmalloc (STAT_COM + ovl.mask) failed\n", zr->name); + return -ENOMEM; + } + memset((void *) mem, 0, mem_needed); + + zr->stat_com = (u32 *) mem; + for (j = 0; j < BUZ_NUM_STAT_COM; j++) { + zr->stat_com[j] = 1; /* mark as unavailable to zr36057 */ + } + zr->overlay_mask = (u32 *) (mem + BUZ_NUM_STAT_COM * 4); + + /* Initialize zr->jpg_gbuf */ + + for (j = 0; j < BUZ_MAX_FRAME; j++) { + zr->jpg_gbuf[j].frag_tab = 0; + zr->jpg_gbuf[j].frag_tab_bus = 0; + zr->jpg_gbuf[j].state = BUZ_STATE_USER; + zr->jpg_gbuf[j].bs.frame = j; + } + + /* + * Now add the template and register the device unit. + */ + memcpy(&zr->video_dev, &zoran_template, sizeof(zoran_template)); + strcpy(zr->video_dev.name, zr->name); + if (video_register_device(&zr->video_dev, VFL_TYPE_GRABBER) < 0) { + i2c_unregister_bus(&zr->i2c); + kfree((void *) zr->stat_com); + return -1; + } + + /* Enable bus-mastering */ + pci_set_master(zr->pci_dev); + + if (zr->card == BUZ) + j = zr->params.input == 0 ? 3 : 7; + else + j = zr->params.input == 0 ? 0 : 7; + set_videobus_enable(zr, 0); + 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); + set_videobus_enable(zr, 1); + + /* toggle JPEG codec sleep to sync PLL */ + zr36060_sleep(zr, 1); + zr36060_sleep(zr, 0); + + /* set individual interrupt enables (without GIRQ1) + but don't global enable until zoran_open() */ + + //btwrite(IRQ_MASK & ~ZR36057_ISR_GIRQ1, ZR36057_ICR); // SW + // It looks like using only JPEGRepIRQEn is not always reliable, + // may be when JPEG codec crashes it won't generate IRQ? So, + btwrite(IRQ_MASK, ZR36057_ICR); // Enable Vsync interrupts too. SM + + zr36057_init_vfe(zr); + + zr->zoran_proc = NULL; + zr->initialized = 1; + + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); +#if (DEBUGLEVEL > 2) + detect_guest_activity(zr); +#endif + test_interrupts(zr); + btwrite(IRQ_MASK, ZR36057_ICR); // Enable Vsync interrupts too. SM + if (!pass_through) { + set_videobus_enable(zr, 0); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, + DECODER_ENABLE_OUTPUT, &zero); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, + ENCODER_SET_INPUT, &two); + set_videobus_enable(zr, 1); + } + return 0; +} + +#include "zoran_procfs.c" + +static void release_dc10(void) +{ + u8 command; + int i; + struct zoran *zr; + + for (i = 0; i < zoran_num; i++) { + zr = &zoran[i]; + + if (!zr->initialized) + continue; + + /* unregister i2c_bus */ + i2c_unregister_bus((&zr->i2c)); + + /* disable PCI bus-mastering */ + pci_read_config_byte(zr->pci_dev, PCI_COMMAND, &command); + command &= ~PCI_COMMAND_MASTER; + pci_write_config_byte(zr->pci_dev, PCI_COMMAND, command); + + /* put chip into reset */ + btwrite(0, ZR36057_SPGPPCR); + + free_irq(zr->pci_dev->irq, zr); + + /* unmap and free memory */ + + kfree((void *) zr->stat_com); + + zoran_proc_cleanup(i); + iounmap(zr->zr36057_mem); + + video_unregister_device(&zr->video_dev); + } +} + +/* + * Scan for a Buz card (actually for the PCI contoler ZR36057), + * request the irq and map the io memory + */ + +static int find_zr36057(void) +{ + unsigned char latency, need_latency; + struct zoran *zr; + struct pci_dev *dev = NULL; + int result; + + zoran_num = 0; + + while (zoran_num < BUZ_MAX + && (dev = + pci_find_device(PCI_VENDOR_ID_ZORAN, + PCI_DEVICE_ID_ZORAN_36057, + dev)) != NULL) { + zr = &zoran[zoran_num]; + zr->pci_dev = dev; + zr->zr36057_mem = NULL; + zr->id = zoran_num; + sprintf(zr->name, "MJPEG[%u]", zr->id); + + spin_lock_init(&zr->lock); + + if (pci_enable_device(dev)) + continue; + + zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0); + pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, + &zr->revision); + if (zr->revision < 2) { + printk(KERN_INFO + "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n", + zr->name, zr->revision, zr->pci_dev->irq, + zr->zr36057_adr); + } else { + unsigned short ss_vendor_id, ss_id; + ss_vendor_id = zr->pci_dev->subsystem_vendor; + ss_id = zr->pci_dev->subsystem_device; + printk(KERN_INFO + "%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n", + zr->name, zr->revision, zr->pci_dev->irq, + zr->zr36057_adr); + printk(KERN_INFO + "%s: subsystem vendor=0x%04x id=0x%04x\n", + zr->name, ss_vendor_id, ss_id); + } + + zr->zr36057_mem = ioremap_nocache(zr->zr36057_adr, 0x1000); + if (!zr->zr36057_mem) { + printk(KERN_ERR "%s: ioremap failed\n", zr->name); + /* XXX handle error */ + } + + result = request_irq(zr->pci_dev->irq, zoran_irq, SA_SHIRQ | SA_INTERRUPT, zr->name, (void *) zr); + if (result < 0) { + if (result == -EINVAL) { + printk(KERN_ERR + "%s: Bad irq number or handler\n", + zr->name); + } else if (result == -EBUSY) { + printk(KERN_ERR + "%s: IRQ %d busy, change your PnP config in BIOS\n", + zr->name, zr->pci_dev->irq); + } else { + printk(KERN_ERR + "%s: Can't assign irq, error code %d\n", + zr->name, result); + } + iounmap(zr->zr36057_mem); + continue; + } + + /* set PCI latency timer */ + pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, &latency); + need_latency = zr->revision > 1 ? 32 : 48; + if (latency != need_latency) { + printk(KERN_INFO "%s: Changing PCI latency from %d to %d.\n", zr->name, latency, need_latency); + pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, need_latency); + } + + btwrite(0, ZR36057_SPGPPCR); + mdelay(1); + btwrite(ZR36057_SPGPPCR_SoftReset, ZR36057_SPGPPCR); + mdelay(1); + + /* assert P_Reset */ + btwrite(0, ZR36057_JPC); + + /* set up GPIO direction - all output */ + btwrite(ZR36057_SPGPPCR_SoftReset | 0, ZR36057_SPGPPCR); + btwrite((0x81 << 24) | 0x8888, ZR36057_GPPGCR1); + + /* i2c */ + memcpy(&zr->i2c, &zoran_i2c_bus_template, + sizeof(struct i2c_bus)); + strcpy(zr->i2c.name, zr->name); + zr->i2c.data = zr; + printk(KERN_INFO "%s: Initializing i2c bus...\n", zr->name); + if (i2c_register_bus(&zr->i2c) < 0) { + /* put chip into reset */ + btwrite(0, ZR36057_SPGPPCR); + free_irq(zr->pci_dev->irq, zr); + iounmap(zr->zr36057_mem); + printk(KERN_ERR "%s: Can't initialize i2c bus\n", zr->name); + continue; + } + + if (zr->card != DC10 && zr->card != DC10plus + && zr->card != LML33 && zr->card != BUZ) { + /* unregister i2c_bus */ + i2c_unregister_bus((&zr->i2c)); + /* put chip into reset */ + btwrite(0, ZR36057_SPGPPCR); + free_irq(zr->pci_dev->irq, zr); + iounmap(zr->zr36057_mem); + printk(KERN_ERR "%s: Card not supported\n", + zr->name); + continue; + } + printk(KERN_INFO "%s card detected\n", zr->name); + if (zr->card == LML33) { + GPIO(zr, 2, 1); // Set Composite input/output + } + + /* reset JPEG codec */ + zr36060_sleep(zr, 1); + zr36060_reset(zr); + + /* video bus enabled */ + + /* display codec revision */ + if (zr36060_read_8(zr, 0x022) == 0x33) { + printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n", + zr->name, zr36060_read_8(zr, 0x023)); + } else { + /* unregister i2c_bus */ + i2c_unregister_bus((&zr->i2c)); + /* put chip into reset */ + btwrite(0, ZR36057_SPGPPCR); + free_irq(zr->pci_dev->irq, zr); + iounmap(zr->zr36057_mem); + printk(KERN_ERR "%s: Zoran ZR36060 not found\n", + zr->name); + continue; + } + + zoran_num++; + } + if (zoran_num == 0) { + printk(KERN_INFO "No known MJPEG cards found.\n"); + } + return zoran_num; +} + +static void handle_chipset(void) +{ + int index; + struct pci_dev *dev = NULL; + + if(pci_pci_problems & PCIPCI_FAIL) + printk(KERN_WARNING "Chipset may not support reliable PCI-PCI DMA.\n"); + + if(pci_pci_problems & PCIPCI_TRITON) + { + printk("enabling Triton support.\n"); + triton = 1; + } + + if(pci_pci_problems & PCIPCI_NATOMA) + { + printk("enabling Natoma workaround.\n"); + natoma = 1; + } +} + +static int init_dc10_cards(void) +{ + int i; + + memset(zoran, 0, sizeof(zoran)); + printk(KERN_INFO + "Zoran ZR36060 + ZR36057/67 MJPEG board driver version %d.%d\n", + MAJOR_VERSION, MINOR_VERSION); + + /* Look for cards */ + + if (find_zr36057() < 0) { + return -EIO; + } + if (zoran_num == 0) + return 0; //-ENXIO; + + printk(KERN_INFO "MJPEG: %d card(s) found\n", zoran_num); + + /* check the parameters we have been given, adjust if necessary */ + + if (v4l_nbufs < 0) + v4l_nbufs = 0; + if (v4l_nbufs > VIDEO_MAX_FRAME) + v4l_nbufs = VIDEO_MAX_FRAME; + /* The user specfies the in KB, we want them in byte (and page aligned) */ + v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024); + if (v4l_bufsize < 32768) + v4l_bufsize = 32768; + /* 2 MB is arbitrary but sufficient for the maximum possible images */ + if (v4l_bufsize > 2048 * 1024) + v4l_bufsize = 2048 * 1024; + + printk(KERN_INFO "MJPEG: using %d V4L buffers of size %d KB\n", + v4l_nbufs, v4l_bufsize >> 10); + + /* Use parameter for vidmem or try to find a video card */ + + if (vidmem) { + printk(KERN_INFO + "MJPEG: Using supplied video memory base address @ 0x%lx\n", + vidmem); + } + /* check if we have a Triton or Natome chipset */ + + handle_chipset(); + + /* take care of Natoma chipset and a revision 1 zr36057 */ + + for (i = 0; i < zoran_num; i++) { + if (natoma && zoran[i].revision <= 1) { + zoran[i].need_contiguous = 1; + printk(KERN_INFO + "%s: ZR36057/Natoma bug, max. buffer size is 128K\n", + zoran[i].name); + } else { + zoran[i].need_contiguous = 0; + } + } + + /* initialize the Buzs */ + + /* We have to know which ones must be released if an error occurs */ + for (i = 0; i < zoran_num; i++) + zoran[i].initialized = 0; + + for (i = 0; i < zoran_num; i++) { + if (zr36057_init(i) < 0) { + release_dc10(); + return -EIO; + } + zoran_proc_init(i); + } + + return 0; +} + +static void unload_dc10_cards(void) +{ + release_dc10(); +} + + +module_init(init_dc10_cards); +module_exit(unload_dc10_cards); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/Config.in linux.ac/drivers/message/fusion/Config.in --- linux.vanilla/drivers/message/fusion/Config.in Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/Config.in Tue Apr 3 23:12:52 2001 @@ -0,0 +1,39 @@ +mainmenu_option next_comment +comment 'Fusion MPT device support' + +dep_tristate "Fusion MPT (base + ScsiHost) drivers" CONFIG_FUSION $CONFIG_SCSI $CONFIG_BLK_DEV_SD + +if [ "$CONFIG_FUSION" = "y" -o "$CONFIG_FUSION" = "m" ]; then + + if [ "$CONFIG_BLK_DEV_SD" = "y" -a "$CONFIG_FUSION" = "y" ]; then + define_bool CONFIG_FUSION_BOOT y + comment "(ability to boot linux kernel from Fusion device is ENABLED!)" + else + define_bool CONFIG_FUSION_BOOT n + comment "(ability to boot linux kernel from Fusion device is DISABLED!)" + fi + + if [ "$CONFIG_MODULES" = "y" ]; then + # How can we force these options to module or nothing? + dep_tristate " Enhanced SCSI error reporting" CONFIG_FUSION_ISENSE $CONFIG_FUSION m + dep_tristate " Fusion MPT misc device (ioctl) driver" CONFIG_FUSION_CTL $CONFIG_FUSION m + fi + + dep_tristate " Fusion MPT LAN driver" CONFIG_FUSION_LAN $CONFIG_FUSION $CONFIG_NET + if [ "$CONFIG_FUSION_LAN" != "n" ]; then + define_bool CONFIG_NET_FC y + fi + +else + + define_bool CONFIG_FUSION_BOOT n + # These <should> be define_tristate, but we leave them define_bool + # for backward compatibility with pre-linux-2.2.15 kernels. + # (Bugzilla:fibrebugs, #384) + define_bool CONFIG_FUSION_ISENSE n + define_bool CONFIG_FUSION_CTL n + define_bool CONFIG_FUSION_LAN n + +fi + +endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/Makefile linux.ac/drivers/message/fusion/Makefile --- linux.vanilla/drivers/message/fusion/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/Makefile Tue Apr 3 17:54:47 2001 @@ -0,0 +1,72 @@ +# +# Makefile for the LSI Logic Fusion MPT (Message Passing Technology) drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now inherited from the +# parent makefile. +# +# Note 3! If you want to turn on various debug defines for an extended period of +# time but don't want them lingering around in the Makefile when you pass it on +# to someone else, use the MPT_CFLAGS env variable (thanks Steve). -nromer + +#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-{ LSI_LOGIC + +# Architecture-specific... +# # intel +#EXTRA_CFLAGS += -g +# # sparc64 +#EXTRA_CFLAGS += -gstabs+ + +EXTRA_CFLAGS += -I. ${MPT_CFLAGS} + +# Fusion MPT drivers; recognized debug defines... +# MPT general: +#EXTRA_CFLAGS += -DDEBUG +#EXTRA_CFLAGS += -DMPT_DEBUG +#EXTRA_CFLAGS += -DMPT_DEBUG_MSG_FRAME +#EXTRA_CFLAGS += -DMPT_DEBUG_SPINLOCK +# driver/module specifics... +# For mptbase: +#CFLAGS_mptbase.o += -DMPT_DEBUG_HANDSHAKE +#CFLAGS_mptbase.o += -DMPT_DEBUG_IRQ +# For {mptscsih, mptctl}: +#CFLAGS_mptscsih.o += -DMPT_SCSI_USE_NEW_EH +#CFLAGS_mptscsih.o += -DMPT_SCSI_CACHE_AUTOSENSE +#CFLAGS_mptscsih.o += -DMPT_DEBUG_SG +#CFLAGS_mptctl.o += -DMPT_DEBUG_SG +# For mptlan: +#CFLAGS_mptlan.o += -DMPT_LAN_IO_DEBUG +# For isense: + +# EXP... +##mptscsih-objs := scsihost.o scsiherr.o + +#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC + +O_TARGET := fusion.o + +export-objs := mptbase.o mptscsih.o mptlan.o mptctl.o isense.o + +# ? what's list-multi for? +#list-multi := fusion.o mptscsih.o + +obj-$(CONFIG_FUSION) += mptbase.o mptscsih.o +obj-$(CONFIG_FUSION_ISENSE) += isense.o +obj-$(CONFIG_FUSION_CTL) += mptctl.o +obj-$(CONFIG_FUSION_LAN) += mptlan.o + +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) + +include $(TOPDIR)/Rules.make + + +# EXP... +## Fusion MPT extra's... +##mptscsih.o: $(mptscsih-objs) +## $(LD) -r -o $@ $(mptscsih-objs) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/ascq_tbl.c linux.ac/drivers/message/fusion/ascq_tbl.c --- linux.vanilla/drivers/message/fusion/ascq_tbl.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/ascq_tbl.c Tue Apr 3 17:54:47 2001 @@ -0,0 +1,2416 @@ +#ifndef SCSI_ASCQ_TBL_C_INCLUDED +#define SCSI_ASCQ_TBL_C_INCLUDED + +/* AuToMaGiCaLlY generated from: "t10.org/asc-num.txt" + ******************************************************************************* + * File: ASC-NUM.TXT + * + * SCSI ASC/ASCQ Assignments + * Numeric Sorted Listing + * as of 5/18/00 + * + * D - DIRECT ACCESS DEVICE (SBC-2) device column key + * .T - SEQUENTIAL ACCESS DEVICE (SSC) ------------------- + * . L - PRINTER DEVICE (SSC) blank = reserved + * . P - PROCESSOR DEVICE (SPC) not blank = allowed + * . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC-2) + * . . R - CD DEVICE (MMC) + * . . S - SCANNER DEVICE (SCSI-2) + * . . .O - OPTICAL MEMORY DEVICE (SBC-2) + * . . . M - MEDIA CHANGER DEVICE (SMC) + * . . . C - COMMUNICATION DEVICE (SCSI-2) + * . . . .A - STORAGE ARRAY DEVICE (SCC) + * . . . . E - ENCLOSURE SERVICES DEVICE (SES) + * . . . . B - SIMPLIFIED DIRECT-ACCESS DEVICE (RBC) + * . . . . .K - OPTICAL CARD READER/WRITER DEVICE (OCRW) + * ASC/ASCQ DTLPWRSOMCAEBK Description + * ------- -------------- ---------------------------------------------------- + */ + +static char SenseDevTypes001[] = "DTLPWRSOMCAEBK"; +static char SenseDevTypes002[] = ".T............"; +static char SenseDevTypes003[] = ".T....S......."; +static char SenseDevTypes004[] = ".TL...S......."; +static char SenseDevTypes005[] = ".....R........"; +static char SenseDevTypes006[] = "DTL.WRSOM.AEBK"; +static char SenseDevTypes007[] = "D...W..O....BK"; +static char SenseDevTypes008[] = "D...WR.OM...BK"; +static char SenseDevTypes009[] = "DTL.W.SO....BK"; +static char SenseDevTypes010[] = "DTL..R.O....B."; +static char SenseDevTypes011[] = "DT..W..OMCA.BK"; +static char SenseDevTypes012[] = ".............."; +static char SenseDevTypes013[] = "DTL.WRSOMCAEBK"; +static char SenseDevTypes014[] = "DTL.WRSOM...BK"; +static char SenseDevTypes015[] = "DT...R.OM...BK"; +static char SenseDevTypes016[] = "DTLPWRSO.C...K"; +static char SenseDevTypes017[] = "DT..WR.O....B."; +static char SenseDevTypes018[] = "....WR.O.....K"; +static char SenseDevTypes019[] = "....WR.O......"; +static char SenseDevTypes020[] = ".T...RS......."; +static char SenseDevTypes021[] = ".............K"; +static char SenseDevTypes022[] = "DT..W..O....B."; +static char SenseDevTypes023[] = "DT..WRSO....BK"; +static char SenseDevTypes024[] = "DT..W.SO....BK"; +static char SenseDevTypes025[] = "....WR.O....B."; +static char SenseDevTypes026[] = "....W..O....B."; +static char SenseDevTypes027[] = "DT.....O....BK"; +static char SenseDevTypes028[] = "DTL.WRSO....BK"; +static char SenseDevTypes029[] = "DT..WR.O....BK"; +static char SenseDevTypes030[] = "DT..W..O....BK"; +static char SenseDevTypes031[] = "D...WR.O....BK"; +static char SenseDevTypes032[] = "D......O.....K"; +static char SenseDevTypes033[] = "D......O....BK"; +static char SenseDevTypes034[] = "DT..WR.OM...BK"; +static char SenseDevTypes035[] = "D............."; +static char SenseDevTypes036[] = "DTLPWRSOMCAE.K"; +static char SenseDevTypes037[] = "DTLPWRSOMCA.BK"; +static char SenseDevTypes038[] = ".T...R........"; +static char SenseDevTypes039[] = "DT..WR.OM...B."; +static char SenseDevTypes040[] = "DTL.WRSOMCAE.K"; +static char SenseDevTypes041[] = "DTLPWRSOMCAE.."; +static char SenseDevTypes042[] = "......S......."; +static char SenseDevTypes043[] = "............B."; +static char SenseDevTypes044[] = "DTLPWRSO.CA..K"; +static char SenseDevTypes045[] = "DT...R.......K"; +static char SenseDevTypes046[] = "D.L..R.O....B."; +static char SenseDevTypes047[] = "..L..........."; +static char SenseDevTypes048[] = ".TL..........."; +static char SenseDevTypes049[] = "DTLPWRSOMC..BK"; +static char SenseDevTypes050[] = "DT..WR.OMCAEBK"; +static char SenseDevTypes051[] = "DT..WR.OMCAEB."; +static char SenseDevTypes052[] = ".T...R.O......"; +static char SenseDevTypes053[] = "...P.........."; +static char SenseDevTypes054[] = "DTLPWRSOM.AE.K"; +static char SenseDevTypes055[] = "DTLPWRSOM.AE.."; +static char SenseDevTypes056[] = ".......O......"; +static char SenseDevTypes057[] = "DTLPWRSOM...BK"; +static char SenseDevTypes058[] = "DT..WR.O..A.BK"; +static char SenseDevTypes059[] = "DTLPWRSOM....K"; +static char SenseDevTypes060[] = "D......O......"; +static char SenseDevTypes061[] = ".....R......B."; +static char SenseDevTypes062[] = "D...........B."; +static char SenseDevTypes063[] = "............BK"; +static char SenseDevTypes064[] = "..........A..."; + +static ASCQ_Table_t ASCQ_Table[] = { + { + 0x00, 0x00, + SenseDevTypes001, + "NO ADDITIONAL SENSE INFORMATION" + }, + { + 0x00, 0x01, + SenseDevTypes002, + "FILEMARK DETECTED" + }, + { + 0x00, 0x02, + SenseDevTypes003, + "END-OF-PARTITION/MEDIUM DETECTED" + }, + { + 0x00, 0x03, + SenseDevTypes002, + "SETMARK DETECTED" + }, + { + 0x00, 0x04, + SenseDevTypes003, + "BEGINNING-OF-PARTITION/MEDIUM DETECTED" + }, + { + 0x00, 0x05, + SenseDevTypes004, + "END-OF-DATA DETECTED" + }, + { + 0x00, 0x06, + SenseDevTypes001, + "I/O PROCESS TERMINATED" + }, + { + 0x00, 0x11, + SenseDevTypes005, + "AUDIO PLAY OPERATION IN PROGRESS" + }, + { + 0x00, 0x12, + SenseDevTypes005, + "AUDIO PLAY OPERATION PAUSED" + }, + { + 0x00, 0x13, + SenseDevTypes005, + "AUDIO PLAY OPERATION SUCCESSFULLY COMPLETED" + }, + { + 0x00, 0x14, + SenseDevTypes005, + "AUDIO PLAY OPERATION STOPPED DUE TO ERROR" + }, + { + 0x00, 0x15, + SenseDevTypes005, + "NO CURRENT AUDIO STATUS TO RETURN" + }, + { + 0x00, 0x16, + SenseDevTypes001, + "OPERATION IN PROGRESS" + }, + { + 0x00, 0x17, + SenseDevTypes006, + "CLEANING REQUESTED" + }, + { + 0x01, 0x00, + SenseDevTypes007, + "NO INDEX/SECTOR SIGNAL" + }, + { + 0x02, 0x00, + SenseDevTypes008, + "NO SEEK COMPLETE" + }, + { + 0x03, 0x00, + SenseDevTypes009, + "PERIPHERAL DEVICE WRITE FAULT" + }, + { + 0x03, 0x01, + SenseDevTypes002, + "NO WRITE CURRENT" + }, + { + 0x03, 0x02, + SenseDevTypes002, + "EXCESSIVE WRITE ERRORS" + }, + { + 0x04, 0x00, + SenseDevTypes001, + "LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE" + }, + { + 0x04, 0x01, + SenseDevTypes001, + "LOGICAL UNIT IS IN PROCESS OF BECOMING READY" + }, + { + 0x04, 0x02, + SenseDevTypes001, + "LOGICAL UNIT NOT READY, INITIALIZING CMD. REQUIRED" + }, + { + 0x04, 0x03, + SenseDevTypes001, + "LOGICAL UNIT NOT READY, MANUAL INTERVENTION REQUIRED" + }, + { + 0x04, 0x04, + SenseDevTypes010, + "LOGICAL UNIT NOT READY, FORMAT IN PROGRESS" + }, + { + 0x04, 0x05, + SenseDevTypes011, + "LOGICAL UNIT NOT READY, REBUILD IN PROGRESS" + }, + { + 0x04, 0x06, + SenseDevTypes011, + "LOGICAL UNIT NOT READY, RECALCULATION IN PROGRESS" + }, + { + 0x04, 0x07, + SenseDevTypes001, + "LOGICAL UNIT NOT READY, OPERATION IN PROGRESS" + }, + { + 0x04, 0x08, + SenseDevTypes005, + "LOGICAL UNIT NOT READY, LONG WRITE IN PROGRESS" + }, + { + 0x04, 0x09, + SenseDevTypes001, + "LOGICAL UNIT NOT READY, SELF-TEST IN PROGRESS" + }, + { + 0x04, 0x10, + SenseDevTypes012, + "auxiliary memory code 2 (99-148) [proposed]" + }, + { + 0x05, 0x00, + SenseDevTypes013, + "LOGICAL UNIT DOES NOT RESPOND TO SELECTION" + }, + { + 0x06, 0x00, + SenseDevTypes008, + "NO REFERENCE POSITION FOUND" + }, + { + 0x07, 0x00, + SenseDevTypes014, + "MULTIPLE PERIPHERAL DEVICES SELECTED" + }, + { + 0x08, 0x00, + SenseDevTypes013, + "LOGICAL UNIT COMMUNICATION FAILURE" + }, + { + 0x08, 0x01, + SenseDevTypes013, + "LOGICAL UNIT COMMUNICATION TIME-OUT" + }, + { + 0x08, 0x02, + SenseDevTypes013, + "LOGICAL UNIT COMMUNICATION PARITY ERROR" + }, + { + 0x08, 0x03, + SenseDevTypes015, + "LOGICAL UNIT COMMUNICATION CRC ERROR (ULTRA-DMA/32)" + }, + { + 0x08, 0x04, + SenseDevTypes016, + "UNREACHABLE COPY TARGET" + }, + { + 0x09, 0x00, + SenseDevTypes017, + "TRACK FOLLOWING ERROR" + }, + { + 0x09, 0x01, + SenseDevTypes018, + "TRACKING SERVO FAILURE" + }, + { + 0x09, 0x02, + SenseDevTypes018, + "FOCUS SERVO FAILURE" + }, + { + 0x09, 0x03, + SenseDevTypes019, + "SPINDLE SERVO FAILURE" + }, + { + 0x09, 0x04, + SenseDevTypes017, + "HEAD SELECT FAULT" + }, + { + 0x0A, 0x00, + SenseDevTypes001, + "ERROR LOG OVERFLOW" + }, + { + 0x0B, 0x00, + SenseDevTypes001, + "WARNING" + }, + { + 0x0B, 0x01, + SenseDevTypes001, + "WARNING - SPECIFIED TEMPERATURE EXCEEDED" + }, + { + 0x0B, 0x02, + SenseDevTypes001, + "WARNING - ENCLOSURE DEGRADED" + }, + { + 0x0C, 0x00, + SenseDevTypes020, + "WRITE ERROR" + }, + { + 0x0C, 0x01, + SenseDevTypes021, + "WRITE ERROR - RECOVERED WITH AUTO REALLOCATION" + }, + { + 0x0C, 0x02, + SenseDevTypes007, + "WRITE ERROR - AUTO REALLOCATION FAILED" + }, + { + 0x0C, 0x03, + SenseDevTypes007, + "WRITE ERROR - RECOMMEND REASSIGNMENT" + }, + { + 0x0C, 0x04, + SenseDevTypes022, + "COMPRESSION CHECK MISCOMPARE ERROR" + }, + { + 0x0C, 0x05, + SenseDevTypes022, + "DATA EXPANSION OCCURRED DURING COMPRESSION" + }, + { + 0x0C, 0x06, + SenseDevTypes022, + "BLOCK NOT COMPRESSIBLE" + }, + { + 0x0C, 0x07, + SenseDevTypes005, + "WRITE ERROR - RECOVERY NEEDED" + }, + { + 0x0C, 0x08, + SenseDevTypes005, + "WRITE ERROR - RECOVERY FAILED" + }, + { + 0x0C, 0x09, + SenseDevTypes005, + "WRITE ERROR - LOSS OF STREAMING" + }, + { + 0x0C, 0x0A, + SenseDevTypes005, + "WRITE ERROR - PADDING BLOCKS ADDED" + }, + { + 0x0C, 0x0B, + SenseDevTypes012, + "auxiliary memory code 4 (99-148) [proposed]" + }, + { + 0x10, 0x00, + SenseDevTypes007, + "ID CRC OR ECC ERROR" + }, + { + 0x11, 0x00, + SenseDevTypes023, + "UNRECOVERED READ ERROR" + }, + { + 0x11, 0x01, + SenseDevTypes023, + "READ RETRIES EXHAUSTED" + }, + { + 0x11, 0x02, + SenseDevTypes023, + "ERROR TOO LONG TO CORRECT" + }, + { + 0x11, 0x03, + SenseDevTypes024, + "MULTIPLE READ ERRORS" + }, + { + 0x11, 0x04, + SenseDevTypes007, + "UNRECOVERED READ ERROR - AUTO REALLOCATE FAILED" + }, + { + 0x11, 0x05, + SenseDevTypes025, + "L-EC UNCORRECTABLE ERROR" + }, + { + 0x11, 0x06, + SenseDevTypes025, + "CIRC UNRECOVERED ERROR" + }, + { + 0x11, 0x07, + SenseDevTypes026, + "DATA RE-SYNCHRONIZATION ERROR" + }, + { + 0x11, 0x08, + SenseDevTypes002, + "INCOMPLETE BLOCK READ" + }, + { + 0x11, 0x09, + SenseDevTypes002, + "NO GAP FOUND" + }, + { + 0x11, 0x0A, + SenseDevTypes027, + "MISCORRECTED ERROR" + }, + { + 0x11, 0x0B, + SenseDevTypes007, + "UNRECOVERED READ ERROR - RECOMMEND REASSIGNMENT" + }, + { + 0x11, 0x0C, + SenseDevTypes007, + "UNRECOVERED READ ERROR - RECOMMEND REWRITE THE DATA" + }, + { + 0x11, 0x0D, + SenseDevTypes017, + "DE-COMPRESSION CRC ERROR" + }, + { + 0x11, 0x0E, + SenseDevTypes017, + "CANNOT DECOMPRESS USING DECLARED ALGORITHM" + }, + { + 0x11, 0x0F, + SenseDevTypes005, + "ERROR READING UPC/EAN NUMBER" + }, + { + 0x11, 0x10, + SenseDevTypes005, + "ERROR READING ISRC NUMBER" + }, + { + 0x11, 0x11, + SenseDevTypes005, + "READ ERROR - LOSS OF STREAMING" + }, + { + 0x11, 0x12, + SenseDevTypes012, + "auxiliary memory code 3 (99-148) [proposed]" + }, + { + 0x12, 0x00, + SenseDevTypes007, + "ADDRESS MARK NOT FOUND FOR ID FIELD" + }, + { + 0x13, 0x00, + SenseDevTypes007, + "ADDRESS MARK NOT FOUND FOR DATA FIELD" + }, + { + 0x14, 0x00, + SenseDevTypes028, + "RECORDED ENTITY NOT FOUND" + }, + { + 0x14, 0x01, + SenseDevTypes029, + "RECORD NOT FOUND" + }, + { + 0x14, 0x02, + SenseDevTypes002, + "FILEMARK OR SETMARK NOT FOUND" + }, + { + 0x14, 0x03, + SenseDevTypes002, + "END-OF-DATA NOT FOUND" + }, + { + 0x14, 0x04, + SenseDevTypes002, + "BLOCK SEQUENCE ERROR" + }, + { + 0x14, 0x05, + SenseDevTypes030, + "RECORD NOT FOUND - RECOMMEND REASSIGNMENT" + }, + { + 0x14, 0x06, + SenseDevTypes030, + "RECORD NOT FOUND - DATA AUTO-REALLOCATED" + }, + { + 0x15, 0x00, + SenseDevTypes014, + "RANDOM POSITIONING ERROR" + }, + { + 0x15, 0x01, + SenseDevTypes014, + "MECHANICAL POSITIONING ERROR" + }, + { + 0x15, 0x02, + SenseDevTypes029, + "POSITIONING ERROR DETECTED BY READ OF MEDIUM" + }, + { + 0x16, 0x00, + SenseDevTypes007, + "DATA SYNCHRONIZATION MARK ERROR" + }, + { + 0x16, 0x01, + SenseDevTypes007, + "DATA SYNC ERROR - DATA REWRITTEN" + }, + { + 0x16, 0x02, + SenseDevTypes007, + "DATA SYNC ERROR - RECOMMEND REWRITE" + }, + { + 0x16, 0x03, + SenseDevTypes007, + "DATA SYNC ERROR - DATA AUTO-REALLOCATED" + }, + { + 0x16, 0x04, + SenseDevTypes007, + "DATA SYNC ERROR - RECOMMEND REASSIGNMENT" + }, + { + 0x17, 0x00, + SenseDevTypes023, + "RECOVERED DATA WITH NO ERROR CORRECTION APPLIED" + }, + { + 0x17, 0x01, + SenseDevTypes023, + "RECOVERED DATA WITH RETRIES" + }, + { + 0x17, 0x02, + SenseDevTypes029, + "RECOVERED DATA WITH POSITIVE HEAD OFFSET" + }, + { + 0x17, 0x03, + SenseDevTypes029, + "RECOVERED DATA WITH NEGATIVE HEAD OFFSET" + }, + { + 0x17, 0x04, + SenseDevTypes025, + "RECOVERED DATA WITH RETRIES AND/OR CIRC APPLIED" + }, + { + 0x17, 0x05, + SenseDevTypes031, + "RECOVERED DATA USING PREVIOUS SECTOR ID" + }, + { + 0x17, 0x06, + SenseDevTypes007, + "RECOVERED DATA WITHOUT ECC - DATA AUTO-REALLOCATED" + }, + { + 0x17, 0x07, + SenseDevTypes031, + "RECOVERED DATA WITHOUT ECC - RECOMMEND REASSIGNMENT" + }, + { + 0x17, 0x08, + SenseDevTypes031, + "RECOVERED DATA WITHOUT ECC - RECOMMEND REWRITE" + }, + { + 0x17, 0x09, + SenseDevTypes031, + "RECOVERED DATA WITHOUT ECC - DATA REWRITTEN" + }, + { + 0x18, 0x00, + SenseDevTypes029, + "RECOVERED DATA WITH ERROR CORRECTION APPLIED" + }, + { + 0x18, 0x01, + SenseDevTypes031, + "RECOVERED DATA WITH ERROR CORR. & RETRIES APPLIED" + }, + { + 0x18, 0x02, + SenseDevTypes031, + "RECOVERED DATA - DATA AUTO-REALLOCATED" + }, + { + 0x18, 0x03, + SenseDevTypes005, + "RECOVERED DATA WITH CIRC" + }, + { + 0x18, 0x04, + SenseDevTypes005, + "RECOVERED DATA WITH L-EC" + }, + { + 0x18, 0x05, + SenseDevTypes031, + "RECOVERED DATA - RECOMMEND REASSIGNMENT" + }, + { + 0x18, 0x06, + SenseDevTypes031, + "RECOVERED DATA - RECOMMEND REWRITE" + }, + { + 0x18, 0x07, + SenseDevTypes007, + "RECOVERED DATA WITH ECC - DATA REWRITTEN" + }, + { + 0x19, 0x00, + SenseDevTypes032, + "DEFECT LIST ERROR" + }, + { + 0x19, 0x01, + SenseDevTypes032, + "DEFECT LIST NOT AVAILABLE" + }, + { + 0x19, 0x02, + SenseDevTypes032, + "DEFECT LIST ERROR IN PRIMARY LIST" + }, + { + 0x19, 0x03, + SenseDevTypes032, + "DEFECT LIST ERROR IN GROWN LIST" + }, + { + 0x1A, 0x00, + SenseDevTypes001, + "PARAMETER LIST LENGTH ERROR" + }, + { + 0x1B, 0x00, + SenseDevTypes001, + "SYNCHRONOUS DATA TRANSFER ERROR" + }, + { + 0x1C, 0x00, + SenseDevTypes033, + "DEFECT LIST NOT FOUND" + }, + { + 0x1C, 0x01, + SenseDevTypes033, + "PRIMARY DEFECT LIST NOT FOUND" + }, + { + 0x1C, 0x02, + SenseDevTypes033, + "GROWN DEFECT LIST NOT FOUND" + }, + { + 0x1D, 0x00, + SenseDevTypes029, + "MISCOMPARE DURING VERIFY OPERATION" + }, + { + 0x1E, 0x00, + SenseDevTypes007, + "RECOVERED ID WITH ECC CORRECTION" + }, + { + 0x1F, 0x00, + SenseDevTypes032, + "PARTIAL DEFECT LIST TRANSFER" + }, + { + 0x20, 0x00, + SenseDevTypes001, + "INVALID COMMAND OPERATION CODE" + }, + { + 0x20, 0x01, + SenseDevTypes012, + "access controls code 1 (99-314) [proposed]" + }, + { + 0x20, 0x02, + SenseDevTypes012, + "access controls code 2 (99-314) [proposed]" + }, + { + 0x20, 0x03, + SenseDevTypes012, + "access controls code 3 (99-314) [proposed]" + }, + { + 0x21, 0x00, + SenseDevTypes034, + "LOGICAL BLOCK ADDRESS OUT OF RANGE" + }, + { + 0x21, 0x01, + SenseDevTypes034, + "INVALID ELEMENT ADDRESS" + }, + { + 0x22, 0x00, + SenseDevTypes035, + "ILLEGAL FUNCTION (USE 20 00, 24 00, OR 26 00)" + }, + { + 0x24, 0x00, + SenseDevTypes001, + "INVALID FIELD IN CDB" + }, + { + 0x24, 0x01, + SenseDevTypes001, + "CDB DECRYPTION ERROR" + }, + { + 0x25, 0x00, + SenseDevTypes001, + "LOGICAL UNIT NOT SUPPORTED" + }, + { + 0x26, 0x00, + SenseDevTypes001, + "INVALID FIELD IN PARAMETER LIST" + }, + { + 0x26, 0x01, + SenseDevTypes001, + "PARAMETER NOT SUPPORTED" + }, + { + 0x26, 0x02, + SenseDevTypes001, + "PARAMETER VALUE INVALID" + }, + { + 0x26, 0x03, + SenseDevTypes036, + "THRESHOLD PARAMETERS NOT SUPPORTED" + }, + { + 0x26, 0x04, + SenseDevTypes001, + "INVALID RELEASE OF PERSISTENT RESERVATION" + }, + { + 0x26, 0x05, + SenseDevTypes037, + "DATA DECRYPTION ERROR" + }, + { + 0x26, 0x06, + SenseDevTypes016, + "TOO MANY TARGET DESCRIPTORS" + }, + { + 0x26, 0x07, + SenseDevTypes016, + "UNSUPPORTED TARGET DESCRIPTOR TYPE CODE" + }, + { + 0x26, 0x08, + SenseDevTypes016, + "TOO MANY SEGMENT DESCRIPTORS" + }, + { + 0x26, 0x09, + SenseDevTypes016, + "UNSUPPORTED SEGMENT DESCRIPTOR TYPE CODE" + }, + { + 0x26, 0x0A, + SenseDevTypes016, + "UNEXPECTED INEXACT SEGMENT" + }, + { + 0x26, 0x0B, + SenseDevTypes016, + "INLINE DATA LENGTH EXCEEDED" + }, + { + 0x26, 0x0C, + SenseDevTypes016, + "INVALID OPERATION FOR COPY SOURCE OR DESTINATION" + }, + { + 0x26, 0x0D, + SenseDevTypes016, + "COPY SEGMENT GRANULARITY VIOLATION" + }, + { + 0x27, 0x00, + SenseDevTypes029, + "WRITE PROTECTED" + }, + { + 0x27, 0x01, + SenseDevTypes029, + "HARDWARE WRITE PROTECTED" + }, + { + 0x27, 0x02, + SenseDevTypes029, + "LOGICAL UNIT SOFTWARE WRITE PROTECTED" + }, + { + 0x27, 0x03, + SenseDevTypes038, + "ASSOCIATED WRITE PROTECT" + }, + { + 0x27, 0x04, + SenseDevTypes038, + "PERSISTENT WRITE PROTECT" + }, + { + 0x27, 0x05, + SenseDevTypes038, + "PERMANENT WRITE PROTECT" + }, + { + 0x28, 0x00, + SenseDevTypes001, + "NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED" + }, + { + 0x28, 0x01, + SenseDevTypes039, + "IMPORT OR EXPORT ELEMENT ACCESSED" + }, + { + 0x29, 0x00, + SenseDevTypes001, + "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED" + }, + { + 0x29, 0x01, + SenseDevTypes001, + "POWER ON OCCURRED" + }, + { + 0x29, 0x02, + SenseDevTypes001, + "SCSI BUS RESET OCCURRED" + }, + { + 0x29, 0x03, + SenseDevTypes001, + "BUS DEVICE RESET FUNCTION OCCURRED" + }, + { + 0x29, 0x04, + SenseDevTypes001, + "DEVICE INTERNAL RESET" + }, + { + 0x29, 0x05, + SenseDevTypes001, + "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED" + }, + { + 0x29, 0x06, + SenseDevTypes001, + "TRANSCEIVER MODE CHANGED TO LVD" + }, + { + 0x2A, 0x00, + SenseDevTypes013, + "PARAMETERS CHANGED" + }, + { + 0x2A, 0x01, + SenseDevTypes013, + "MODE PARAMETERS CHANGED" + }, + { + 0x2A, 0x02, + SenseDevTypes040, + "LOG PARAMETERS CHANGED" + }, + { + 0x2A, 0x03, + SenseDevTypes036, + "RESERVATIONS PREEMPTED" + }, + { + 0x2A, 0x04, + SenseDevTypes041, + "RESERVATIONS RELEASED" + }, + { + 0x2A, 0x05, + SenseDevTypes041, + "REGISTRATIONS PREEMPTED" + }, + { + 0x2B, 0x00, + SenseDevTypes016, + "COPY CANNOT EXECUTE SINCE HOST CANNOT DISCONNECT" + }, + { + 0x2C, 0x00, + SenseDevTypes001, + "COMMAND SEQUENCE ERROR" + }, + { + 0x2C, 0x01, + SenseDevTypes042, + "TOO MANY WINDOWS SPECIFIED" + }, + { + 0x2C, 0x02, + SenseDevTypes042, + "INVALID COMBINATION OF WINDOWS SPECIFIED" + }, + { + 0x2C, 0x03, + SenseDevTypes005, + "CURRENT PROGRAM AREA IS NOT EMPTY" + }, + { + 0x2C, 0x04, + SenseDevTypes005, + "CURRENT PROGRAM AREA IS EMPTY" + }, + { + 0x2C, 0x05, + SenseDevTypes043, + "ILLEGAL POWER CONDITION REQUEST" + }, + { + 0x2D, 0x00, + SenseDevTypes002, + "OVERWRITE ERROR ON UPDATE IN PLACE" + }, + { + 0x2E, 0x00, + SenseDevTypes044, + "ERROR DETECTED BY THIRD PARTY TEMPORARY INITIATOR" + }, + { + 0x2E, 0x01, + SenseDevTypes044, + "THIRD PARTY DEVICE FAILURE" + }, + { + 0x2E, 0x02, + SenseDevTypes044, + "COPY TARGET DEVICE NOT REACHABLE" + }, + { + 0x2E, 0x03, + SenseDevTypes044, + "INCORRECT COPY TARGET DEVICE TYPE" + }, + { + 0x2E, 0x04, + SenseDevTypes044, + "COPY TARGET DEVICE DATA UNDERRUN" + }, + { + 0x2E, 0x05, + SenseDevTypes044, + "COPY TARGET DEVICE DATA OVERRUN" + }, + { + 0x2F, 0x00, + SenseDevTypes001, + "COMMANDS CLEARED BY ANOTHER INITIATOR" + }, + { + 0x30, 0x00, + SenseDevTypes034, + "INCOMPATIBLE MEDIUM INSTALLED" + }, + { + 0x30, 0x01, + SenseDevTypes029, + "CANNOT READ MEDIUM - UNKNOWN FORMAT" + }, + { + 0x30, 0x02, + SenseDevTypes029, + "CANNOT READ MEDIUM - INCOMPATIBLE FORMAT" + }, + { + 0x30, 0x03, + SenseDevTypes045, + "CLEANING CARTRIDGE INSTALLED" + }, + { + 0x30, 0x04, + SenseDevTypes029, + "CANNOT WRITE MEDIUM - UNKNOWN FORMAT" + }, + { + 0x30, 0x05, + SenseDevTypes029, + "CANNOT WRITE MEDIUM - INCOMPATIBLE FORMAT" + }, + { + 0x30, 0x06, + SenseDevTypes017, + "CANNOT FORMAT MEDIUM - INCOMPATIBLE MEDIUM" + }, + { + 0x30, 0x07, + SenseDevTypes006, + "CLEANING FAILURE" + }, + { + 0x30, 0x08, + SenseDevTypes005, + "CANNOT WRITE - APPLICATION CODE MISMATCH" + }, + { + 0x30, 0x09, + SenseDevTypes005, + "CURRENT SESSION NOT FIXATED FOR APPEND" + }, + { + 0x31, 0x00, + SenseDevTypes029, + "MEDIUM FORMAT CORRUPTED" + }, + { + 0x31, 0x01, + SenseDevTypes046, + "FORMAT COMMAND FAILED" + }, + { + 0x32, 0x00, + SenseDevTypes007, + "NO DEFECT SPARE LOCATION AVAILABLE" + }, + { + 0x32, 0x01, + SenseDevTypes007, + "DEFECT LIST UPDATE FAILURE" + }, + { + 0x33, 0x00, + SenseDevTypes002, + "TAPE LENGTH ERROR" + }, + { + 0x34, 0x00, + SenseDevTypes001, + "ENCLOSURE FAILURE" + }, + { + 0x35, 0x00, + SenseDevTypes001, + "ENCLOSURE SERVICES FAILURE" + }, + { + 0x35, 0x01, + SenseDevTypes001, + "UNSUPPORTED ENCLOSURE FUNCTION" + }, + { + 0x35, 0x02, + SenseDevTypes001, + "ENCLOSURE SERVICES UNAVAILABLE" + }, + { + 0x35, 0x03, + SenseDevTypes001, + "ENCLOSURE SERVICES TRANSFER FAILURE" + }, + { + 0x35, 0x04, + SenseDevTypes001, + "ENCLOSURE SERVICES TRANSFER REFUSED" + }, + { + 0x36, 0x00, + SenseDevTypes047, + "RIBBON, INK, OR TONER FAILURE" + }, + { + 0x37, 0x00, + SenseDevTypes013, + "ROUNDED PARAMETER" + }, + { + 0x38, 0x00, + SenseDevTypes043, + "EVENT STATUS NOTIFICATION" + }, + { + 0x38, 0x02, + SenseDevTypes043, + "ESN - POWER MANAGEMENT CLASS EVENT" + }, + { + 0x38, 0x04, + SenseDevTypes043, + "ESN - MEDIA CLASS EVENT" + }, + { + 0x38, 0x06, + SenseDevTypes043, + "ESN - DEVICE BUSY CLASS EVENT" + }, + { + 0x39, 0x00, + SenseDevTypes040, + "SAVING PARAMETERS NOT SUPPORTED" + }, + { + 0x3A, 0x00, + SenseDevTypes014, + "MEDIUM NOT PRESENT" + }, + { + 0x3A, 0x01, + SenseDevTypes034, + "MEDIUM NOT PRESENT - TRAY CLOSED" + }, + { + 0x3A, 0x02, + SenseDevTypes034, + "MEDIUM NOT PRESENT - TRAY OPEN" + }, + { + 0x3A, 0x03, + SenseDevTypes039, + "MEDIUM NOT PRESENT - LOADABLE" + }, + { + 0x3A, 0x04, + SenseDevTypes039, + "MEDIUM NOT PRESENT - MEDIUM AUXILIARY MEMORY ACCESSIBLE" + }, + { + 0x3B, 0x00, + SenseDevTypes048, + "SEQUENTIAL POSITIONING ERROR" + }, + { + 0x3B, 0x01, + SenseDevTypes002, + "TAPE POSITION ERROR AT BEGINNING-OF-MEDIUM" + }, + { + 0x3B, 0x02, + SenseDevTypes002, + "TAPE POSITION ERROR AT END-OF-MEDIUM" + }, + { + 0x3B, 0x03, + SenseDevTypes047, + "TAPE OR ELECTRONIC VERTICAL FORMS UNIT NOT READY" + }, + { + 0x3B, 0x04, + SenseDevTypes047, + "SLEW FAILURE" + }, + { + 0x3B, 0x05, + SenseDevTypes047, + "PAPER JAM" + }, + { + 0x3B, 0x06, + SenseDevTypes047, + "FAILED TO SENSE TOP-OF-FORM" + }, + { + 0x3B, 0x07, + SenseDevTypes047, + "FAILED TO SENSE BOTTOM-OF-FORM" + }, + { + 0x3B, 0x08, + SenseDevTypes002, + "REPOSITION ERROR" + }, + { + 0x3B, 0x09, + SenseDevTypes042, + "READ PAST END OF MEDIUM" + }, + { + 0x3B, 0x0A, + SenseDevTypes042, + "READ PAST BEGINNING OF MEDIUM" + }, + { + 0x3B, 0x0B, + SenseDevTypes042, + "POSITION PAST END OF MEDIUM" + }, + { + 0x3B, 0x0C, + SenseDevTypes003, + "POSITION PAST BEGINNING OF MEDIUM" + }, + { + 0x3B, 0x0D, + SenseDevTypes034, + "MEDIUM DESTINATION ELEMENT FULL" + }, + { + 0x3B, 0x0E, + SenseDevTypes034, + "MEDIUM SOURCE ELEMENT EMPTY" + }, + { + 0x3B, 0x0F, + SenseDevTypes005, + "END OF MEDIUM REACHED" + }, + { + 0x3B, 0x11, + SenseDevTypes034, + "MEDIUM MAGAZINE NOT ACCESSIBLE" + }, + { + 0x3B, 0x12, + SenseDevTypes034, + "MEDIUM MAGAZINE REMOVED" + }, + { + 0x3B, 0x13, + SenseDevTypes034, + "MEDIUM MAGAZINE INSERTED" + }, + { + 0x3B, 0x14, + SenseDevTypes034, + "MEDIUM MAGAZINE LOCKED" + }, + { + 0x3B, 0x15, + SenseDevTypes034, + "MEDIUM MAGAZINE UNLOCKED" + }, + { + 0x3B, 0x16, + SenseDevTypes005, + "MECHANICAL POSITIONING OR CHANGER ERROR" + }, + { + 0x3D, 0x00, + SenseDevTypes036, + "INVALID BITS IN IDENTIFY MESSAGE" + }, + { + 0x3E, 0x00, + SenseDevTypes001, + "LOGICAL UNIT HAS NOT SELF-CONFIGURED YET" + }, + { + 0x3E, 0x01, + SenseDevTypes001, + "LOGICAL UNIT FAILURE" + }, + { + 0x3E, 0x02, + SenseDevTypes001, + "TIMEOUT ON LOGICAL UNIT" + }, + { + 0x3E, 0x03, + SenseDevTypes001, + "LOGICAL UNIT FAILED SELF-TEST" + }, + { + 0x3E, 0x04, + SenseDevTypes001, + "LOGICAL UNIT UNABLE TO UPDATE SELF-TEST LOG" + }, + { + 0x3F, 0x00, + SenseDevTypes001, + "TARGET OPERATING CONDITIONS HAVE CHANGED" + }, + { + 0x3F, 0x01, + SenseDevTypes001, + "MICROCODE HAS BEEN CHANGED" + }, + { + 0x3F, 0x02, + SenseDevTypes049, + "CHANGED OPERATING DEFINITION" + }, + { + 0x3F, 0x03, + SenseDevTypes001, + "INQUIRY DATA HAS CHANGED" + }, + { + 0x3F, 0x04, + SenseDevTypes050, + "COMPONENT DEVICE ATTACHED" + }, + { + 0x3F, 0x05, + SenseDevTypes050, + "DEVICE IDENTIFIER CHANGED" + }, + { + 0x3F, 0x06, + SenseDevTypes051, + "REDUNDANCY GROUP CREATED OR MODIFIED" + }, + { + 0x3F, 0x07, + SenseDevTypes051, + "REDUNDANCY GROUP DELETED" + }, + { + 0x3F, 0x08, + SenseDevTypes051, + "SPARE CREATED OR MODIFIED" + }, + { + 0x3F, 0x09, + SenseDevTypes051, + "SPARE DELETED" + }, + { + 0x3F, 0x0A, + SenseDevTypes050, + "VOLUME SET CREATED OR MODIFIED" + }, + { + 0x3F, 0x0B, + SenseDevTypes050, + "VOLUME SET DELETED" + }, + { + 0x3F, 0x0C, + SenseDevTypes050, + "VOLUME SET DEASSIGNED" + }, + { + 0x3F, 0x0D, + SenseDevTypes050, + "VOLUME SET REASSIGNED" + }, + { + 0x3F, 0x0E, + SenseDevTypes041, + "REPORTED LUNS DATA HAS CHANGED" + }, + { + 0x3F, 0x0F, + SenseDevTypes001, + "ECHO BUFFER OVERWRITTEN" + }, + { + 0x3F, 0x10, + SenseDevTypes039, + "MEDIUM LOADABLE" + }, + { + 0x3F, 0x11, + SenseDevTypes039, + "MEDIUM AUXILIARY MEMORY ACCESSIBLE" + }, + { + 0x40, 0x00, + SenseDevTypes035, + "RAM FAILURE (SHOULD USE 40 NN)" + }, + { + 0x40, 0xFF, + SenseDevTypes001, + "DIAGNOSTIC FAILURE ON COMPONENT NN (80H-FFH)" + }, + { + 0x41, 0x00, + SenseDevTypes035, + "DATA PATH FAILURE (SHOULD USE 40 NN)" + }, + { + 0x42, 0x00, + SenseDevTypes035, + "POWER-ON OR SELF-TEST FAILURE (SHOULD USE 40 NN)" + }, + { + 0x43, 0x00, + SenseDevTypes001, + "MESSAGE ERROR" + }, + { + 0x44, 0x00, + SenseDevTypes001, + "INTERNAL TARGET FAILURE" + }, + { + 0x45, 0x00, + SenseDevTypes001, + "SELECT OR RESELECT FAILURE" + }, + { + 0x46, 0x00, + SenseDevTypes049, + "UNSUCCESSFUL SOFT RESET" + }, + { + 0x47, 0x00, + SenseDevTypes001, + "SCSI PARITY ERROR" + }, + { + 0x47, 0x01, + SenseDevTypes001, + "DATA PHASE CRC ERROR DETECTED" + }, + { + 0x47, 0x02, + SenseDevTypes001, + "SCSI PARITY ERROR DETECTED DURING ST DATA PHASE" + }, + { + 0x47, 0x03, + SenseDevTypes001, + "INFORMATION UNIT CRC ERROR DETECTED" + }, + { + 0x47, 0x04, + SenseDevTypes001, + "ASYNCHRONOUS INFORMATION PROTECTION ERROR DETECTED" + }, + { + 0x48, 0x00, + SenseDevTypes001, + "INITIATOR DETECTED ERROR MESSAGE RECEIVED" + }, + { + 0x49, 0x00, + SenseDevTypes001, + "INVALID MESSAGE ERROR" + }, + { + 0x4A, 0x00, + SenseDevTypes001, + "COMMAND PHASE ERROR" + }, + { + 0x4B, 0x00, + SenseDevTypes001, + "DATA PHASE ERROR" + }, + { + 0x4C, 0x00, + SenseDevTypes001, + "LOGICAL UNIT FAILED SELF-CONFIGURATION" + }, + { + 0x4D, 0xFF, + SenseDevTypes001, + "TAGGED OVERLAPPED COMMANDS (NN = QUEUE TAG)" + }, + { + 0x4E, 0x00, + SenseDevTypes001, + "OVERLAPPED COMMANDS ATTEMPTED" + }, + { + 0x50, 0x00, + SenseDevTypes002, + "WRITE APPEND ERROR" + }, + { + 0x50, 0x01, + SenseDevTypes002, + "WRITE APPEND POSITION ERROR" + }, + { + 0x50, 0x02, + SenseDevTypes002, + "POSITION ERROR RELATED TO TIMING" + }, + { + 0x51, 0x00, + SenseDevTypes052, + "ERASE FAILURE" + }, + { + 0x52, 0x00, + SenseDevTypes002, + "CARTRIDGE FAULT" + }, + { + 0x53, 0x00, + SenseDevTypes014, + "MEDIA LOAD OR EJECT FAILED" + }, + { + 0x53, 0x01, + SenseDevTypes002, + "UNLOAD TAPE FAILURE" + }, + { + 0x53, 0x02, + SenseDevTypes034, + "MEDIUM REMOVAL PREVENTED" + }, + { + 0x54, 0x00, + SenseDevTypes053, + "SCSI TO HOST SYSTEM INTERFACE FAILURE" + }, + { + 0x55, 0x00, + SenseDevTypes053, + "SYSTEM RESOURCE FAILURE" + }, + { + 0x55, 0x01, + SenseDevTypes033, + "SYSTEM BUFFER FULL" + }, + { + 0x55, 0x02, + SenseDevTypes054, + "INSUFFICIENT RESERVATION RESOURCES" + }, + { + 0x55, 0x03, + SenseDevTypes041, + "INSUFFICIENT RESOURCES" + }, + { + 0x55, 0x04, + SenseDevTypes055, + "INSUFFICIENT REGISTRATION RESOURCES" + }, + { + 0x55, 0x05, + SenseDevTypes012, + "access controls code 4 (99-314) [proposed]" + }, + { + 0x55, 0x06, + SenseDevTypes012, + "auxiliary memory code 1 (99-148) [proposed]" + }, + { + 0x57, 0x00, + SenseDevTypes005, + "UNABLE TO RECOVER TABLE-OF-CONTENTS" + }, + { + 0x58, 0x00, + SenseDevTypes056, + "GENERATION DOES NOT EXIST" + }, + { + 0x59, 0x00, + SenseDevTypes056, + "UPDATED BLOCK READ" + }, + { + 0x5A, 0x00, + SenseDevTypes057, + "OPERATOR REQUEST OR STATE CHANGE INPUT" + }, + { + 0x5A, 0x01, + SenseDevTypes034, + "OPERATOR MEDIUM REMOVAL REQUEST" + }, + { + 0x5A, 0x02, + SenseDevTypes058, + "OPERATOR SELECTED WRITE PROTECT" + }, + { + 0x5A, 0x03, + SenseDevTypes058, + "OPERATOR SELECTED WRITE PERMIT" + }, + { + 0x5B, 0x00, + SenseDevTypes059, + "LOG EXCEPTION" + }, + { + 0x5B, 0x01, + SenseDevTypes059, + "THRESHOLD CONDITION MET" + }, + { + 0x5B, 0x02, + SenseDevTypes059, + "LOG COUNTER AT MAXIMUM" + }, + { + 0x5B, 0x03, + SenseDevTypes059, + "LOG LIST CODES EXHAUSTED" + }, + { + 0x5C, 0x00, + SenseDevTypes060, + "RPL STATUS CHANGE" + }, + { + 0x5C, 0x01, + SenseDevTypes060, + "SPINDLES SYNCHRONIZED" + }, + { + 0x5C, 0x02, + SenseDevTypes060, + "SPINDLES NOT SYNCHRONIZED" + }, + { + 0x5D, 0x00, + SenseDevTypes001, + "FAILURE PREDICTION THRESHOLD EXCEEDED" + }, + { + 0x5D, 0x01, + SenseDevTypes061, + "MEDIA FAILURE PREDICTION THRESHOLD EXCEEDED" + }, + { + 0x5D, 0x02, + SenseDevTypes005, + "LOGICAL UNIT FAILURE PREDICTION THRESHOLD EXCEEDED" + }, + { + 0x5D, 0x10, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE" + }, + { + 0x5D, 0x11, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x12, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x13, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x14, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS" + }, + { + 0x5D, 0x15, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH" + }, + { + 0x5D, 0x16, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH" + }, + { + 0x5D, 0x17, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE CHANNEL PARAMETRICS" + }, + { + 0x5D, 0x18, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE CONTROLLER DETECTED" + }, + { + 0x5D, 0x19, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE" + }, + { + 0x5D, 0x1A, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE SEEK TIME PERFORMANCE" + }, + { + 0x5D, 0x1B, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE SPIN-UP RETRY COUNT" + }, + { + 0x5D, 0x1C, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT" + }, + { + 0x5D, 0x20, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE GENERAL HARD DRIVE FAILURE" + }, + { + 0x5D, 0x21, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x22, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE DATA ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x23, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE SEEK ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x24, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE TOO MANY BLOCK REASSIGNS" + }, + { + 0x5D, 0x25, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE ACCESS TIMES TOO HIGH" + }, + { + 0x5D, 0x26, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE START UNIT TIMES TOO HIGH" + }, + { + 0x5D, 0x27, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE CHANNEL PARAMETRICS" + }, + { + 0x5D, 0x28, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE CONTROLLER DETECTED" + }, + { + 0x5D, 0x29, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE THROUGHPUT PERFORMANCE" + }, + { + 0x5D, 0x2A, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE SEEK TIME PERFORMANCE" + }, + { + 0x5D, 0x2B, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE SPIN-UP RETRY COUNT" + }, + { + 0x5D, 0x2C, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT" + }, + { + 0x5D, 0x30, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE GENERAL HARD DRIVE FAILURE" + }, + { + 0x5D, 0x31, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x32, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE DATA ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x33, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE SEEK ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x34, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE TOO MANY BLOCK REASSIGNS" + }, + { + 0x5D, 0x35, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE ACCESS TIMES TOO HIGH" + }, + { + 0x5D, 0x36, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE START UNIT TIMES TOO HIGH" + }, + { + 0x5D, 0x37, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE CHANNEL PARAMETRICS" + }, + { + 0x5D, 0x38, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE CONTROLLER DETECTED" + }, + { + 0x5D, 0x39, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE THROUGHPUT PERFORMANCE" + }, + { + 0x5D, 0x3A, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE SEEK TIME PERFORMANCE" + }, + { + 0x5D, 0x3B, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE SPIN-UP RETRY COUNT" + }, + { + 0x5D, 0x3C, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT" + }, + { + 0x5D, 0x40, + SenseDevTypes062, + "SERVO IMPENDING FAILURE GENERAL HARD DRIVE FAILURE" + }, + { + 0x5D, 0x41, + SenseDevTypes062, + "SERVO IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x42, + SenseDevTypes062, + "SERVO IMPENDING FAILURE DATA ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x43, + SenseDevTypes062, + "SERVO IMPENDING FAILURE SEEK ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x44, + SenseDevTypes062, + "SERVO IMPENDING FAILURE TOO MANY BLOCK REASSIGNS" + }, + { + 0x5D, 0x45, + SenseDevTypes062, + "SERVO IMPENDING FAILURE ACCESS TIMES TOO HIGH" + }, + { + 0x5D, 0x46, + SenseDevTypes062, + "SERVO IMPENDING FAILURE START UNIT TIMES TOO HIGH" + }, + { + 0x5D, 0x47, + SenseDevTypes062, + "SERVO IMPENDING FAILURE CHANNEL PARAMETRICS" + }, + { + 0x5D, 0x48, + SenseDevTypes062, + "SERVO IMPENDING FAILURE CONTROLLER DETECTED" + }, + { + 0x5D, 0x49, + SenseDevTypes062, + "SERVO IMPENDING FAILURE THROUGHPUT PERFORMANCE" + }, + { + 0x5D, 0x4A, + SenseDevTypes062, + "SERVO IMPENDING FAILURE SEEK TIME PERFORMANCE" + }, + { + 0x5D, 0x4B, + SenseDevTypes062, + "SERVO IMPENDING FAILURE SPIN-UP RETRY COUNT" + }, + { + 0x5D, 0x4C, + SenseDevTypes062, + "SERVO IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT" + }, + { + 0x5D, 0x50, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE" + }, + { + 0x5D, 0x51, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x52, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE DATA ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x53, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x54, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS" + }, + { + 0x5D, 0x55, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE ACCESS TIMES TOO HIGH" + }, + { + 0x5D, 0x56, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE START UNIT TIMES TOO HIGH" + }, + { + 0x5D, 0x57, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE CHANNEL PARAMETRICS" + }, + { + 0x5D, 0x58, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE CONTROLLER DETECTED" + }, + { + 0x5D, 0x59, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE THROUGHPUT PERFORMANCE" + }, + { + 0x5D, 0x5A, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE SEEK TIME PERFORMANCE" + }, + { + 0x5D, 0x5B, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE SPIN-UP RETRY COUNT" + }, + { + 0x5D, 0x5C, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT" + }, + { + 0x5D, 0x60, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE" + }, + { + 0x5D, 0x61, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x62, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x63, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x64, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS" + }, + { + 0x5D, 0x65, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH" + }, + { + 0x5D, 0x66, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH" + }, + { + 0x5D, 0x67, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE CHANNEL PARAMETRICS" + }, + { + 0x5D, 0x68, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE CONTROLLER DETECTED" + }, + { + 0x5D, 0x69, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE" + }, + { + 0x5D, 0x6A, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE SEEK TIME PERFORMANCE" + }, + { + 0x5D, 0x6B, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE SPIN-UP RETRY COUNT" + }, + { + 0x5D, 0x6C, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT" + }, + { + 0x5D, 0xFF, + SenseDevTypes001, + "FAILURE PREDICTION THRESHOLD EXCEEDED (FALSE)" + }, + { + 0x5E, 0x00, + SenseDevTypes044, + "LOW POWER CONDITION ON" + }, + { + 0x5E, 0x01, + SenseDevTypes044, + "IDLE CONDITION ACTIVATED BY TIMER" + }, + { + 0x5E, 0x02, + SenseDevTypes044, + "STANDBY CONDITION ACTIVATED BY TIMER" + }, + { + 0x5E, 0x03, + SenseDevTypes044, + "IDLE CONDITION ACTIVATED BY COMMAND" + }, + { + 0x5E, 0x04, + SenseDevTypes044, + "STANDBY CONDITION ACTIVATED BY COMMAND" + }, + { + 0x5E, 0x41, + SenseDevTypes043, + "POWER STATE CHANGE TO ACTIVE" + }, + { + 0x5E, 0x42, + SenseDevTypes043, + "POWER STATE CHANGE TO IDLE" + }, + { + 0x5E, 0x43, + SenseDevTypes043, + "POWER STATE CHANGE TO STANDBY" + }, + { + 0x5E, 0x45, + SenseDevTypes043, + "POWER STATE CHANGE TO SLEEP" + }, + { + 0x5E, 0x47, + SenseDevTypes063, + "POWER STATE CHANGE TO DEVICE CONTROL" + }, + { + 0x60, 0x00, + SenseDevTypes042, + "LAMP FAILURE" + }, + { + 0x61, 0x00, + SenseDevTypes042, + "VIDEO ACQUISITION ERROR" + }, + { + 0x61, 0x01, + SenseDevTypes042, + "UNABLE TO ACQUIRE VIDEO" + }, + { + 0x61, 0x02, + SenseDevTypes042, + "OUT OF FOCUS" + }, + { + 0x62, 0x00, + SenseDevTypes042, + "SCAN HEAD POSITIONING ERROR" + }, + { + 0x63, 0x00, + SenseDevTypes005, + "END OF USER AREA ENCOUNTERED ON THIS TRACK" + }, + { + 0x63, 0x01, + SenseDevTypes005, + "PACKET DOES NOT FIT IN AVAILABLE SPACE" + }, + { + 0x64, 0x00, + SenseDevTypes005, + "ILLEGAL MODE FOR THIS TRACK" + }, + { + 0x64, 0x01, + SenseDevTypes005, + "INVALID PACKET SIZE" + }, + { + 0x65, 0x00, + SenseDevTypes001, + "VOLTAGE FAULT" + }, + { + 0x66, 0x00, + SenseDevTypes042, + "AUTOMATIC DOCUMENT FEEDER COVER UP" + }, + { + 0x66, 0x01, + SenseDevTypes042, + "AUTOMATIC DOCUMENT FEEDER LIFT UP" + }, + { + 0x66, 0x02, + SenseDevTypes042, + "DOCUMENT JAM IN AUTOMATIC DOCUMENT FEEDER" + }, + { + 0x66, 0x03, + SenseDevTypes042, + "DOCUMENT MISS FEED AUTOMATIC IN DOCUMENT FEEDER" + }, + { + 0x67, 0x00, + SenseDevTypes064, + "CONFIGURATION FAILURE" + }, + { + 0x67, 0x01, + SenseDevTypes064, + "CONFIGURATION OF INCAPABLE LOGICAL UNITS FAILED" + }, + { + 0x67, 0x02, + SenseDevTypes064, + "ADD LOGICAL UNIT FAILED" + }, + { + 0x67, 0x03, + SenseDevTypes064, + "MODIFICATION OF LOGICAL UNIT FAILED" + }, + { + 0x67, 0x04, + SenseDevTypes064, + "EXCHANGE OF LOGICAL UNIT FAILED" + }, + { + 0x67, 0x05, + SenseDevTypes064, + "REMOVE OF LOGICAL UNIT FAILED" + }, + { + 0x67, 0x06, + SenseDevTypes064, + "ATTACHMENT OF LOGICAL UNIT FAILED" + }, + { + 0x67, 0x07, + SenseDevTypes064, + "CREATION OF LOGICAL UNIT FAILED" + }, + { + 0x67, 0x08, + SenseDevTypes064, + "ASSIGN FAILURE OCCURRED" + }, + { + 0x67, 0x09, + SenseDevTypes064, + "MULTIPLY ASSIGNED LOGICAL UNIT" + }, + { + 0x68, 0x00, + SenseDevTypes064, + "LOGICAL UNIT NOT CONFIGURED" + }, + { + 0x69, 0x00, + SenseDevTypes064, + "DATA LOSS ON LOGICAL UNIT" + }, + { + 0x69, 0x01, + SenseDevTypes064, + "MULTIPLE LOGICAL UNIT FAILURES" + }, + { + 0x69, 0x02, + SenseDevTypes064, + "PARITY/DATA MISMATCH" + }, + { + 0x6A, 0x00, + SenseDevTypes064, + "INFORMATIONAL, REFER TO LOG" + }, + { + 0x6B, 0x00, + SenseDevTypes064, + "STATE CHANGE HAS OCCURRED" + }, + { + 0x6B, 0x01, + SenseDevTypes064, + "REDUNDANCY LEVEL GOT BETTER" + }, + { + 0x6B, 0x02, + SenseDevTypes064, + "REDUNDANCY LEVEL GOT WORSE" + }, + { + 0x6C, 0x00, + SenseDevTypes064, + "REBUILD FAILURE OCCURRED" + }, + { + 0x6D, 0x00, + SenseDevTypes064, + "RECALCULATE FAILURE OCCURRED" + }, + { + 0x6E, 0x00, + SenseDevTypes064, + "COMMAND TO LOGICAL UNIT FAILED" + }, + { + 0x6F, 0x00, + SenseDevTypes005, + "COPY PROTECTION KEY EXCHANGE FAILURE - AUTHENTICATION FAILURE" + }, + { + 0x6F, 0x01, + SenseDevTypes005, + "COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT PRESENT" + }, + { + 0x6F, 0x02, + SenseDevTypes005, + "COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT ESTABLISHED" + }, + { + 0x6F, 0x03, + SenseDevTypes005, + "READ OF SCRAMBLED SECTOR WITHOUT AUTHENTICATION" + }, + { + 0x6F, 0x04, + SenseDevTypes005, + "MEDIA REGION CODE IS MISMATCHED TO LOGICAL UNIT REGION" + }, + { + 0x6F, 0x05, + SenseDevTypes005, + "DRIVE REGION MUST BE PERMANENT/REGION RESET COUNT ERROR" + }, + { + 0x70, 0xFF, + SenseDevTypes002, + "DECOMPRESSION EXCEPTION SHORT ALGORITHM ID OF NN" + }, + { + 0x71, 0x00, + SenseDevTypes002, + "DECOMPRESSION EXCEPTION LONG ALGORITHM ID" + }, + { + 0x72, 0x00, + SenseDevTypes005, + "SESSION FIXATION ERROR" + }, + { + 0x72, 0x01, + SenseDevTypes005, + "SESSION FIXATION ERROR WRITING LEAD-IN" + }, + { + 0x72, 0x02, + SenseDevTypes005, + "SESSION FIXATION ERROR WRITING LEAD-OUT" + }, + { + 0x72, 0x03, + SenseDevTypes005, + "SESSION FIXATION ERROR - INCOMPLETE TRACK IN SESSION" + }, + { + 0x72, 0x04, + SenseDevTypes005, + "EMPTY OR PARTIALLY WRITTEN RESERVED TRACK" + }, + { + 0x72, 0x05, + SenseDevTypes005, + "NO MORE TRACK RESERVATIONS ALLOWED" + }, + { + 0x73, 0x00, + SenseDevTypes005, + "CD CONTROL ERROR" + }, + { + 0x73, 0x01, + SenseDevTypes005, + "POWER CALIBRATION AREA ALMOST FULL" + }, + { + 0x73, 0x02, + SenseDevTypes005, + "POWER CALIBRATION AREA IS FULL" + }, + { + 0x73, 0x03, + SenseDevTypes005, + "POWER CALIBRATION AREA ERROR" + }, + { + 0x73, 0x04, + SenseDevTypes005, + "PROGRAM MEMORY AREA UPDATE FAILURE" + }, + { + 0x73, 0x05, + SenseDevTypes005, + "PROGRAM MEMORY AREA IS FULL" + }, + { + 0x73, 0x06, + SenseDevTypes005, + "RMA/PMA IS FULL" + }, +}; + +static int ASCQ_TableSize = 463; + + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/ascq_tbl.sh linux.ac/drivers/message/fusion/ascq_tbl.sh --- linux.vanilla/drivers/message/fusion/ascq_tbl.sh Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/ascq_tbl.sh Tue Apr 3 17:54:47 2001 @@ -0,0 +1,109 @@ +#!/bin/sh +# +# ascq_tbl.sh - Translate SCSI t10.org's "asc-num.txt" file of +# SCSI Additional Sense Code & Qualifiers (ASC/ASCQ's) +# into something useful in C, creating "ascq_tbl.c" file. +# +#*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*# + +PREF_INFILE="t10.org/asc-num.txt" # From SCSI t10.org +PREF_OUTFILE="ascq_tbl.c" + +#*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*# + +xlate_ascq() { + cat | awk ' + BEGIN { + DQ = "\042"; + OUTFILE = "'"${PREF_OUTFILE}"'"; + TRUE = 1; + FALSE = 0; + #debug = TRUE; + + # read and discard all lines up to and including the one that begins + # with the "magic token" of "------- -------------- ---"... + headers_gone = FALSE; + while (!headers_gone) { + if (getline <= 0) + exit 1; + header_line[++hdrs] = $0; + if (debug) + printf("header_line[%d] = :%s:\n", ++hdrs, $0); + if ($0 ~ /^------- -------------- ---/) { + headers_gone = TRUE; + } + } + outcount = 0; + } + + (NF > 1) { + ++outcount; + if (debug) + printf( "DBG: %s\n", $0 ); + ASC[outcount] = substr($0,1,2); + ASCQ[outcount] = substr($0,5,2); + devtypes = substr($0,10,14); + gsub(/ /, ".", devtypes); + DESCRIP[outcount] = substr($0,26); + + if (!(devtypes in DevTypesVoodoo)) { + DevTypesVoodoo[devtypes] = ++voodoo; + DevTypesIdx[voodoo] = devtypes; + } + DEVTYPES[outcount] = DevTypesVoodoo[devtypes]; + + # Handle 0xNN exception stuff... + if (ASCQ[outcount] == "NN" || ASCQ[outcount] == "nn") + ASCQ[outcount] = "FF"; + } + + END { + printf("#ifndef SCSI_ASCQ_TBL_C_INCLUDED\n") > OUTFILE; + printf("#define SCSI_ASCQ_TBL_C_INCLUDED\n") >> OUTFILE; + + printf("\n/* AuToMaGiCaLlY generated from: %s'"${FIN}"'%s\n", DQ, DQ) >> OUTFILE; + printf(" *******************************************************************************\n") >> OUTFILE; + for (i=1; i<=hdrs; i++) { + printf(" * %s\n", header_line[i]) >> OUTFILE; + } + printf(" */\n") >> OUTFILE; + + printf("\n") >> OUTFILE; + for (i=1; i<=voodoo; i++) { + printf("static char SenseDevTypes%03d[] = %s%s%s;\n", i, DQ, DevTypesIdx[i], DQ) >> OUTFILE; + } + + printf("\nstatic ASCQ_Table_t ASCQ_Table[] = {\n") >> OUTFILE; + for (i=1; i<=outcount; i++) { + printf(" {\n") >> OUTFILE; + printf(" 0x%s, 0x%s,\n", ASC[i], ASCQ[i]) >> OUTFILE; + printf(" SenseDevTypes%03d,\n", DEVTYPES[i]) >> OUTFILE; + printf(" %s%s%s\n", DQ, DESCRIP[i], DQ) >> OUTFILE; + printf(" },\n") >> OUTFILE; + } + printf( "};\n\n" ) >> OUTFILE; + + printf( "static int ASCQ_TableSize = %d;\n\n", outcount ) >> OUTFILE; + printf( "Total of %d ASC/ASCQ records generated\n", outcount ); + printf("\n#endif\n") >> OUTFILE; + close(OUTFILE); + }' + return +} + +#*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*# + +# main() +if [ $# -lt 1 ]; then + echo "INFO: No input filename supplied - using: $PREF_INFILE" >&2 + FIN=$PREF_INFILE +else + FIN="$1" + if [ "$FIN" != "$PREF_INFILE" ]; then + echo "INFO: Ok, I'll try chewing on '$FIN' for SCSI ASC/ASCQ combos..." >&2 + fi + shift +fi + +cat $FIN | xlate_ascq +exit 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/isense.c linux.ac/drivers/message/fusion/isense.c --- linux.vanilla/drivers/message/fusion/isense.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/isense.c Tue Apr 3 17:54:47 2001 @@ -0,0 +1,122 @@ +/* + * linux/drivers/message/fusion/isense.c + * Little linux driver / shim that interfaces with the Fusion MPT + * Linux base driver to provide english readable strings in SCSI + * Error Report logging output. This module implements SCSI-3 + * Opcode lookup and a sorted table of SCSI-3 ASC/ASCQ strings. + * + * Copyright (c) 1991-2001 Steven J. Ralston + * Written By: Steven J. Ralston + * (yes I wrote some of the orig. code back in 1991!) + * (mailto:Steve.Ralston@lsil.com) + * + * $Id: isense.c,v 1.28 2001/01/14 23:11:09 sralston Exp $ + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + 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. + + NO WARRANTY + THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + solely responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, damage to or loss of data, + programs or equipment, and unavailability or interruption of operations. + + DISCLAIMER OF LIABILITY + NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/version.h> + +/* Hmmm, avoid undefined spinlock_t on lk-2.2.14-5.0 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) +#include <asm/spinlock.h> +#endif + +#define MODULEAUTHOR "Steven J. Ralston" +#define COPYRIGHT "Copyright (c) 2000 " MODULEAUTHOR +#include "mptbase.h" + +#include "isense.h" + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Private data... + */ + +/* + * YIKES! I don't usually #include C source files, but.. + * The following #include's pulls in our needed ASCQ_Table[] array, + * ASCQ_TableSz integer, and ScsiOpcodeString[] array! + */ +#include "ascq_tbl.c" +#include "scsiops.c" + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#define my_NAME "SCSI-3 Opcodes & ASC/ASCQ Strings" +#define my_VERSION MPT_LINUX_VERSION_COMMON +#define MYNAM "isense" + +EXPORT_NO_SYMBOLS; +MODULE_AUTHOR(MODULEAUTHOR); +MODULE_DESCRIPTION(my_NAME); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +int __init isense_init(void) +{ + show_mptmod_ver(my_NAME, my_VERSION); + + /* + * Install our handler + */ + if (mpt_register_ascqops_strings(&ASCQ_Table[0], ASCQ_TableSize, ScsiOpcodeString) != 1) + { + printk(KERN_ERR MYNAM ": ERROR: Can't register with Fusion MPT base driver!\n"); + return -EBUSY; + } + printk(KERN_INFO MYNAM ": Registered SCSI-3 Opcodes & ASC/ASCQ Strings\n"); + return 0; +} + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static void isense_exit(void) +{ +#ifdef MODULE + mpt_deregister_ascqops_strings(); +#endif + printk(KERN_INFO MYNAM ": Deregistered SCSI-3 Opcodes & ASC/ASCQ Strings\n"); +} + +module_init(isense_init); +module_exit(isense_exit); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/isense.h linux.ac/drivers/message/fusion/isense.h --- linux.vanilla/drivers/message/fusion/isense.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/isense.h Sat Apr 14 15:39:07 2001 @@ -0,0 +1,95 @@ +#ifndef ISENSE_H_INCLUDED +#define ISENSE_H_INCLUDED +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#ifdef __KERNEL__ +#include <linux/types.h> /* needed for u8, etc. */ +#include <linux/string.h> /* needed for strcat */ +#include <linux/kernel.h> /* needed for sprintf */ +#else + #ifndef U_STUFF_DEFINED + #define U_STUFF_DEFINED + typedef unsigned char u8; + typedef unsigned short u16; + typedef unsigned int u32; + #endif +#endif + +#include "scsi3.h" /* needed for all things SCSI */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Defines and typedefs... + */ + +#ifdef __KERNEL__ +#define PrintF(x) printk x +#else +#define PrintF(x) printf x +#endif + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#define RETRY_STATUS ((int) 1) +#define PUT_STATUS ((int) 0) + +/* + * A generic structure to hold info about IO request that caused + * a Request Sense to be performed, and the resulting Sense Data. + */ +typedef struct IO_Info +{ + char *DevIDStr; /* String of chars which identifies the device. */ + u8 *cdbPtr; /* Pointer (Virtual/Logical addr) to CDB bytes of + IO request that caused ContAllegianceCond. */ + u8 *sensePtr; /* Pointer (Virtual/Logical addr) to Sense Data + returned by Request Sense operation. */ + u8 *dataPtr; /* Pointer (Virtual/Logical addr) to Data buffer + of IO request caused ContAllegianceCondition. */ + u8 *inqPtr; /* Pointer (Virtual/Logical addr) to Inquiry Data for + IO *Device* that caused ContAllegianceCondition. */ + u8 SCSIStatus; /* SCSI status byte of IO request that caused + Contingent Allegiance Condition. */ + u8 DoDisplay; /* Shall we display any messages? */ + u16 rsvd_align1; + u32 ComplCode; /* Four-byte OS-dependent completion code. */ + u32 NotifyL; /* Four-byte OS-dependent notification field. */ +} IO_Info_t; + +/* + * SCSI Additional Sense Code and Additional Sense Code Qualifier table. + */ +typedef struct ASCQ_Table +{ + u8 ASC; + u8 ASCQ; + char *DevTypes; + char *Description; +} ASCQ_Table_t; + +#if 0 +/* + * SCSI Opcodes table. + */ +typedef struct SCSI_OPS_Table +{ + u8 OpCode; + char *DevTypes; + char *ScsiCmndStr; +} SCSI_OPS_Table_t; +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Public entry point prototypes + */ + +/* in scsiherr.c, needed by mptscsih.c */ +extern int mpt_ScsiHost_ErrorReport(IO_Info_t *ioop); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/linux_compat.h linux.ac/drivers/message/fusion/linux_compat.h --- linux.vanilla/drivers/message/fusion/linux_compat.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/linux_compat.h Tue Apr 17 18:12:40 2001 @@ -0,0 +1,199 @@ +/* drivers/message/fusion/linux_compat.h */ + +#ifndef FUSION_LINUX_COMPAT_H +#define FUSION_LINUX_COMPAT_H +/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#include <linux/version.h> +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/pci.h> + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) + typedef unsigned int dma_addr_t; +# endif +#else +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,42) + typedef unsigned int dma_addr_t; +# endif +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) +/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/* This block snipped from lk-2.2.18/include/linux/init.h { */ +/* + * Used for initialization calls.. + */ +typedef int (*initcall_t)(void); +typedef void (*exitcall_t)(void); + +#define __init_call __attribute__ ((unused,__section__ (".initcall.init"))) +#define __exit_call __attribute__ ((unused,__section__ (".exitcall.exit"))) + +extern initcall_t __initcall_start, __initcall_end; + +#define __initcall(fn) \ + static initcall_t __initcall_##fn __init_call = fn +#define __exitcall(fn) \ + static exitcall_t __exitcall_##fn __exit_call = fn + +#ifdef MODULE +/* These macros create a dummy inline: gcc 2.9x does not count alias + as usage, hence the `unused function' warning when __init functions + are declared static. We use the dummy __*_module_inline functions + both to kill the warning and check the type of the init/cleanup + function. */ +typedef int (*__init_module_func_t)(void); +typedef void (*__cleanup_module_func_t)(void); +#define module_init(x) \ + int init_module(void) __attribute__((alias(#x))); \ + extern inline __init_module_func_t __init_module_inline(void) \ + { return x; } +#define module_exit(x) \ + void cleanup_module(void) __attribute__((alias(#x))); \ + extern inline __cleanup_module_func_t __cleanup_module_inline(void) \ + { return x; } + +#else +#define module_init(x) __initcall(x); +#define module_exit(x) __exitcall(x); +#endif +/* } block snipped from lk-2.2.18/include/linux/init.h */ + +/* Wait queues. */ +#define DECLARE_WAIT_QUEUE_HEAD(name) \ + struct wait_queue * (name) = NULL +#define DECLARE_WAITQUEUE(name, task) \ + struct wait_queue (name) = { (task), NULL } + +#if defined(__sparc__) && defined(__sparc_v9__) +/* The sparc64 ioremap implementation is wrong in 2.2.x, + * but fixing it would break all of the drivers which + * workaround it. Fixed in 2.3.x onward. -DaveM + */ +#define ARCH_IOREMAP(base) ((unsigned long) (base)) +#else +#define ARCH_IOREMAP(base) ioremap(base) +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#else /* LINUX_VERSION_CODE must be >= KERNEL_VERSION(2,2,18) */ + +/* No ioremap bugs in >2.3.x kernels. */ +#define ARCH_IOREMAP(base) ioremap(base) + +/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) */ + + +/* PCI/driver subsystem { */ +#ifndef pci_for_each_dev +#define pci_for_each_dev(dev) for((dev)=pci_devices; (dev)!=NULL; (dev)=(dev)->next) +#define pci_peek_next_dev(dev) ((dev)->next ? (dev)->next : NULL) +#define DEVICE_COUNT_RESOURCE 6 +#define PCI_BASEADDR_FLAGS(idx) base_address[idx] +#define PCI_BASEADDR_START(idx) base_address[idx] & ~0xFUL +/* + * We have to keep track of the original value using + * a temporary, and not by just sticking pdev->base_address[x] + * back. pdev->base_address[x] is an opaque cookie that can + * be used by the PCI implementation on a given Linux port + * for any purpose. -DaveM + */ +#define PCI_BASEADDR_SIZE(__pdev, __idx) \ +({ unsigned int size, tmp; \ + pci_read_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), &tmp); \ + pci_write_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), 0xffffffff); \ + pci_read_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), &size); \ + pci_write_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), tmp); \ + (4 - size); \ +}) +#else +#define pci_peek_next_dev(dev) ((dev) != pci_dev_g(&pci_devices) ? pci_dev_g((dev)->global_list.next) : NULL) +#define PCI_BASEADDR_FLAGS(idx) resource[idx].flags +#define PCI_BASEADDR_START(idx) resource[idx].start +#define PCI_BASEADDR_SIZE(dev,idx) (dev)->resource[idx].end - (dev)->resource[idx].start + 1 +#endif /* } ifndef pci_for_each_dev */ + + +/* procfs compat stuff... */ +#ifdef CONFIG_PROC_FS +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28) +#define CREATE_PROCDIR_ENTRY(x,y) create_proc_entry(x, S_IFDIR, y) +/* This is a macro so we don't need to pull all the procfs + * headers into this file. -DaveM + */ +#define create_proc_read_entry(name, mode, base, __read_proc, __data) \ +({ struct proc_dir_entry *__res=create_proc_entry(name,mode,base); \ + if (__res) { \ + __res->read_proc=(__read_proc); \ + __res->data=(__data); \ + } \ + __res; \ +}) +#else +#define CREATE_PROCDIR_ENTRY(x,y) proc_mkdir(x, y) +#endif +#endif + +/* Compatability for the 2.3.x PCI DMA API. */ +#ifndef PCI_DMA_BIDIRECTIONAL +/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#define PCI_DMA_BIDIRECTIONAL 0 +#define PCI_DMA_TODEVICE 1 +#define PCI_DMA_FROMDEVICE 2 +#define PCI_DMA_NONE 3 + +#ifdef __KERNEL__ +#include <asm/page.h> +/* Pure 2^n version of get_order */ +static __inline__ int __get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} +#endif + +#define pci_alloc_consistent(hwdev, size, dma_handle) \ +({ void *__ret = (void *)__get_free_pages(GFP_ATOMIC, __get_order(size)); \ + if (__ret != NULL) { \ + memset(__ret, 0, size); \ + *(dma_handle) = virt_to_bus(__ret); \ + } \ + __ret; \ +}) + +#define pci_free_consistent(hwdev, size, vaddr, dma_handle) \ + free_pages((unsigned long)vaddr, __get_order(size)) + +#define pci_map_single(hwdev, ptr, size, direction) \ + virt_to_bus(ptr); + +#define pci_unmap_single(hwdev, dma_addr, size, direction) \ + do { /* Nothing to do */ } while (0) + +#define pci_map_sg(hwdev, sg, nents, direction) (nents) +#define pci_unmap_sg(hwdev, sg, nents, direction) \ + do { /* Nothing to do */ } while(0) + +#define sg_dma_address(sg) (virt_to_bus((sg)->address)) +#define sg_dma_len(sg) ((sg)->length) + +/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#endif /* PCI_DMA_BIDIRECTIONAL */ + +/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#endif /* _LINUX_COMPAT_H */ + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/lsi/fc_log.h linux.ac/drivers/message/fusion/lsi/fc_log.h --- linux.vanilla/drivers/message/fusion/lsi/fc_log.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/lsi/fc_log.h Tue Apr 3 17:54:47 2001 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2000-2001 LSI Logic Corporation. All rights reserved. + * + * NAME: fc_log.h + * SUMMARY: MPI IocLogInfo definitions for the SYMFC9xx chips + * DESCRIPTION: Contains the enumerated list of values that may be returned + * in the IOCLogInfo field of a MPI Default Reply Message. + * + * CREATION DATE: 6/02/2000 + * ID: $Id: fc_log.h,v 4.2 2001/03/01 18:28:59 fibre Exp $ + */ + + +/* + * MpiIocLogInfo_t enum + * + * These 32 bit values are used in the IOCLogInfo field of the MPI reply + * messages. + * The value is 0xabcccccc where + * a = The type of log info as per the MPI spec. Since these codes are + * all for Fibre Channel this value will always be 2. + * b = Specifies a subclass of the firmware where + * 0 = FCP Initiator + * 1 = FCP Target + * 2 = LAN + * 3 = MPI Message Layer + * 4 = FC Link + * 5 = Context Manager + * 6 = Invalid Field Offset + * 7 = State Change Info + * all others are reserved for future use + * c = A specific value within the subclass. + * + * NOTE: Any new values should be added to the end of each subclass so that the + * codes remain consistent across firmware releases. + */ +typedef enum _MpiIocLogInfoFc +{ + MPI_IOCLOGINFO_FC_INIT_BASE = 0x20000000, + MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME = 0x20000001, /* received an out of order frame - unsupported */ + MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME = 0x20000002, /* bad start of frame primative */ + MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME = 0x20000003, /* bad end of frame primative */ + MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN = 0x20000004, /* Receiver hardware detected overrun */ + MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER = 0x20000005, /* Other errors caught by IOC which require retries */ + MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD = 0x20000006, /* Main processor could not initialize sub-processor */ + + MPI_IOCLOGINFO_FC_TARGET_BASE = 0x21000000, + MPI_IOCLOGINFO_FC_TARGET_NO_PDISC = 0x21000001, /* not sent because we are waiting for a PDISC from the initiator */ + MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN = 0x21000002, /* not sent because we are not logged in to the remote node */ + MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP = 0x21000003, /* Data Out, Auto Response, not sent due to a LIP */ + MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP = 0x21000004, /* Data In, Auto Response, not sent due to a LIP */ + MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA = 0x21000005, /* Data In, Auto Response, missing data frames */ + MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP = 0x21000006, /* Data Out, No Response, not sent due to a LIP */ + MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP = 0x21000007, /* Auto-response after a write not sent due to a LIP */ + MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP = 0x21000008, /* Data In, No Response, not completed due to a LIP */ + MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA = 0x21000009, /* Data In, No Response, missing data frames */ + MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP = 0x2100000a, /* Manual Response not sent due to a LIP */ + MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3 = 0x2100000b, /* not sent because remote node does not support Class 3 */ + MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID = 0x2100000c, /* not sent because login to remote node not validated */ + MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND = 0x2100000e, /* cleared from the outbound after a logout */ + MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN = 0x2100000f, /* cleared waiting for data after a logout */ + + MPI_IOCLOGINFO_FC_LAN_BASE = 0x22000000, + MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING = 0x22000001, /* Transaction Context Sgl Missing */ + MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE = 0x22000002, /* Transaction Context found before an EOB */ + MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET = 0x22000003, /* Transaction Context value has reserved bits set */ + MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG = 0x22000004, /* Invalid SGL Flags */ + + MPI_IOCLOGINFO_FC_MSG_BASE = 0x23000000, + + MPI_IOCLOGINFO_FC_LINK_BASE = 0x24000000, + MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT = 0x24000001, /* Loop initialization timed out */ + MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED = 0x24000002, /* Another system controller already initialized the loop */ + MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED = 0x24000003, /* Not synchronized to signal or still negotiating (possible cable problem) */ + + MPI_IOCLOGINFO_FC_CTX_BASE = 0x25000000, + + MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET = 0x26000000, /* The lower 24 bits give the byte offset of the field in the request message that is invalid. */ + MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET = 0x26ffffff, + + MPI_IOCLOGINFO_FC_STATE_CHANGE = 0x27000000 /* The lower 24 bits give additional information concerning state change */ + +} MpiIocLogInfoFc_t; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/lsi/mpi.h linux.ac/drivers/message/fusion/lsi/mpi.h --- linux.vanilla/drivers/message/fusion/lsi/mpi.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/lsi/mpi.h Tue Apr 3 17:54:47 2001 @@ -0,0 +1,643 @@ +/* + * Copyright (c) 2000-2001 LSI Logic Corporation. + * + * + * Name: MPI.H + * Title: MPI Message independent structures and definitions + * Creation Date: July 27, 2000 + * + * MPI Version: 01.01.06 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 05-24-00 00.10.02 Added MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH definition. + * 06-06-00 01.00.01 Update MPI_VERSION_MAJOR and MPI_VERSION_MINOR. + * 06-22-00 01.00.02 Added MPI_IOCSTATUS_LAN_ definitions. + * Removed LAN_SUSPEND function definition. + * Added MPI_MSGFLAGS_CONTINUATION_REPLY definition. + * 06-30-00 01.00.03 Added MPI_CONTEXT_REPLY_TYPE_LAN definition. + * Added MPI_GET/SET_CONTEXT_REPLY_TYPE macros. + * 07-27-00 01.00.04 Added MPI_FAULT_ definitions. + * Removed MPI_IOCSTATUS_MSG/DATA_XFER_ERROR definitions. + * Added MPI_IOCSTATUS_INTERNAL_ERROR definition. + * Added MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH. + * 11-02-00 01.01.01 Original release for post 1.0 work. + * 12-04-00 01.01.02 Added new function codes. + * 01-09-01 01.01.03 Added more definitions to the system interface section + * Added MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT. + * 01-25-01 01.01.04 Changed MPI_VERSION_MINOR from 0x00 to 0x01. + * 02-20-01 01.01.05 Started using MPI_POINTER. + * Fixed value for MPI_DIAG_RW_ENABLE. + * Added defines for MPI_DIAG_PREVENT_IOC_BOOT and + * MPI_DIAG_CLEAR_FLASH_BAD_SIG. + * Obsoleted MPI_IOCSTATUS_TARGET_FC_ defines. + * 02-27-01 01.01.06 Removed MPI_HOST_INDEX_REGISTER define. + * Added function codes for RAID. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_H +#define MPI_H + + +/***************************************************************************** +* +* M P I V e r s i o n D e f i n i t i o n s +* +*****************************************************************************/ + +#define MPI_VERSION_MAJOR (0x01) +#define MPI_VERSION_MINOR (0x01) +#define MPI_VERSION ((MPI_VERSION_MAJOR << 8) | MPI_VERSION_MINOR) + +/* Note: The major versions of 0xe0 through 0xff are reserved */ + +/***************************************************************************** +* +* I O C S t a t e D e f i n i t i o n s +* +*****************************************************************************/ + +#define MPI_IOC_STATE_RESET (0x00000000) +#define MPI_IOC_STATE_READY (0x10000000) +#define MPI_IOC_STATE_OPERATIONAL (0x20000000) +#define MPI_IOC_STATE_FAULT (0x40000000) + +#define MPI_IOC_STATE_MASK (0xF0000000) +#define MPI_IOC_STATE_SHIFT (28) + +/* Fault state codes (product independent range 0x8000-0xFFFF) */ + +#define MPI_FAULT_REQUEST_MESSAGE_PCI_PARITY_ERROR (0x8111) +#define MPI_FAULT_REQUEST_MESSAGE_PCI_BUS_FAULT (0x8112) +#define MPI_FAULT_REPLY_MESSAGE_PCI_PARITY_ERROR (0x8113) +#define MPI_FAULT_REPLY_MESSAGE_PCI_BUS_FAULT (0x8114) +#define MPI_FAULT_DATA_SEND_PCI_PARITY_ERROR (0x8115) +#define MPI_FAULT_DATA_SEND_PCI_BUS_FAULT (0x8116) +#define MPI_FAULT_DATA_RECEIVE_PCI_PARITY_ERROR (0x8117) +#define MPI_FAULT_DATA_RECEIVE_PCI_BUS_FAULT (0x8118) + + +/***************************************************************************** +* +* P C I S y s t e m I n t e r f a c e R e g i s t e r s +* +*****************************************************************************/ + +/* S y s t e m D o o r b e l l */ +#define MPI_DOORBELL_OFFSET (0x00000000) +#define MPI_DOORBELL_ACTIVE (0x08000000) +#define MPI_DOORBELL_ACTIVE_SHIFT (27) +#define MPI_DOORBELL_WHO_INIT_MASK (0x07000000) +#define MPI_DOORBELL_WHO_INIT_SHIFT (24) +#define MPI_DOORBELL_FUNCTION_MASK (0xFF000000) +#define MPI_DOORBELL_FUNCTION_SHIFT (24) +#define MPI_DOORBELL_ADD_DWORDS_MASK (0x00FF0000) +#define MPI_DOORBELL_ADD_DWORDS_SHIFT (16) +#define MPI_DOORBELL_DATA_MASK (0x0000FFFF) + + +#define MPI_WRITE_SEQUENCE_OFFSET (0x00000004) +#define MPI_WRSEQ_KEY_VALUE_MASK (0x0000000F) +#define MPI_WRSEQ_1ST_KEY_VALUE (0x04) +#define MPI_WRSEQ_2ND_KEY_VALUE (0x0B) +#define MPI_WRSEQ_3RD_KEY_VALUE (0x02) +#define MPI_WRSEQ_4TH_KEY_VALUE (0x07) +#define MPI_WRSEQ_5TH_KEY_VALUE (0x0D) + +#define MPI_DIAGNOSTIC_OFFSET (0x00000008) +#define MPI_DIAG_CLEAR_FLASH_BAD_SIG (0x00000400) +#define MPI_DIAG_PREVENT_IOC_BOOT (0x00000200) +#define MPI_DIAG_DRWE (0x00000080) +#define MPI_DIAG_FLASH_BAD_SIG (0x00000040) +#define MPI_DIAG_RESET_HISTORY (0x00000020) +#define MPI_DIAG_RW_ENABLE (0x00000010) +#define MPI_DIAG_RESET_ADAPTER (0x00000004) +#define MPI_DIAG_DISABLE_ARM (0x00000002) +#define MPI_DIAG_MEM_ENABLE (0x00000001) + +#define MPI_TEST_BASE_ADDRESS_OFFSET (0x0000000C) + +#define MPI_DIAG_RW_DATA_OFFSET (0x00000010) + +#define MPI_DIAG_RW_ADDRESS_OFFSET (0x00000014) + +#define MPI_HOST_INTERRUPT_STATUS_OFFSET (0x00000030) +#define MPI_HIS_IOP_DOORBELL_STATUS (0x80000000) +#define MPI_HIS_REPLY_MESSAGE_INTERRUPT (0x00000008) +#define MPI_HIS_DOORBELL_INTERRUPT (0x00000001) + +#define MPI_HOST_INTERRUPT_MASK_OFFSET (0x00000034) +#define MPI_HIM_RIM (0x00000008) +#define MPI_HIM_DIM (0x00000001) + +#define MPI_REQUEST_QUEUE_OFFSET (0x00000040) +#define MPI_REQUEST_POST_FIFO_OFFSET (0x00000040) + +#define MPI_REPLY_QUEUE_OFFSET (0x00000044) +#define MPI_REPLY_POST_FIFO_OFFSET (0x00000044) +#define MPI_REPLY_FREE_FIFO_OFFSET (0x00000044) + + + +/***************************************************************************** +* +* M e s s a g e F r a m e D e s c r i p t o r s +* +*****************************************************************************/ + +#define MPI_REQ_MF_DESCRIPTOR_NB_MASK (0x00000003) +#define MPI_REQ_MF_DESCRIPTOR_F_BIT (0x00000004) +#define MPI_REQ_MF_DESCRIPTOR_ADDRESS_MASK (0xFFFFFFF8) + +#define MPI_ADDRESS_REPLY_A_BIT (0x80000000) +#define MPI_ADDRESS_REPLY_ADDRESS_MASK (0x7FFFFFFF) + +#define MPI_CONTEXT_REPLY_A_BIT (0x80000000) +#define MPI_CONTEXT_REPLY_TYPE_MASK (0x60000000) +#define MPI_CONTEXT_REPLY_TYPE_SCSI_INIT (0x00) +#define MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET (0x01) +#define MPI_CONTEXT_REPLY_TYPE_LAN (0x02) +#define MPI_CONTEXT_REPLY_TYPE_SHIFT (29) +#define MPI_CONTEXT_REPLY_CONTEXT_MASK (0x1FFFFFFF) + + +/****************************************************************************/ +/* Context Reply macros */ +/****************************************************************************/ + +#define MPI_GET_CONTEXT_REPLY_TYPE(x) (((x) & MPI_CONTEXT_REPLY_TYPE_MASK) \ + >> MPI_CONTEXT_REPLY_TYPE_SHIFT) + +#define MPI_SET_CONTEXT_REPLY_TYPE(x, typ) \ + ((x) = ((x) & ~MPI_CONTEXT_REPLY_TYPE_MASK) | \ + (((typ) << MPI_CONTEXT_REPLY_TYPE_SHIFT) & \ + MPI_CONTEXT_REPLY_TYPE_MASK)) + + +/***************************************************************************** +* +* M e s s a g e F u n c t i o n s +* 0x80 -> 0x8F reserved for private message use per product +* +* +*****************************************************************************/ + +#define MPI_FUNCTION_SCSI_IO_REQUEST (0x00) +#define MPI_FUNCTION_SCSI_TASK_MGMT (0x01) +#define MPI_FUNCTION_IOC_INIT (0x02) +#define MPI_FUNCTION_IOC_FACTS (0x03) +#define MPI_FUNCTION_CONFIG (0x04) +#define MPI_FUNCTION_PORT_FACTS (0x05) +#define MPI_FUNCTION_PORT_ENABLE (0x06) +#define MPI_FUNCTION_EVENT_NOTIFICATION (0x07) +#define MPI_FUNCTION_EVENT_ACK (0x08) +#define MPI_FUNCTION_FW_DOWNLOAD (0x09) +#define MPI_FUNCTION_TARGET_CMD_BUFFER_POST (0x0A) +#define MPI_FUNCTION_TARGET_ASSIST (0x0B) +#define MPI_FUNCTION_TARGET_STATUS_SEND (0x0C) +#define MPI_FUNCTION_TARGET_MODE_ABORT (0x0D) +#define MPI_FUNCTION_TARGET_FC_BUF_POST_LINK_SRVC (0x0E) /* obsolete name */ +#define MPI_FUNCTION_TARGET_FC_RSP_LINK_SRVC (0x0F) /* obsolete name */ +#define MPI_FUNCTION_TARGET_FC_EX_SEND_LINK_SRVC (0x10) /* obsolete name */ +#define MPI_FUNCTION_TARGET_FC_ABORT (0x11) /* obsolete name */ +#define MPI_FUNCTION_FC_LINK_SRVC_BUF_POST (0x0E) +#define MPI_FUNCTION_FC_LINK_SRVC_RSP (0x0F) +#define MPI_FUNCTION_FC_EX_LINK_SRVC_SEND (0x10) +#define MPI_FUNCTION_FC_ABORT (0x11) +#define MPI_FUNCTION_FW_UPLOAD (0x12) +#define MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND (0x13) +#define MPI_FUNCTION_FC_PRIMITIVE_SEND (0x14) + +#define MPI_FUNCTION_RAID_VOLUME (0x15) +#define MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH (0x16) + +#define MPI_FUNCTION_LAN_SEND (0x20) +#define MPI_FUNCTION_LAN_RECEIVE (0x21) +#define MPI_FUNCTION_LAN_RESET (0x22) + +#define MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40) +#define MPI_FUNCTION_IO_UNIT_RESET (0x41) +#define MPI_FUNCTION_HANDSHAKE (0x42) +#define MPI_FUNCTION_REPLY_FRAME_REMOVAL (0x43) + + + +/***************************************************************************** +* +* S c a t t e r G a t h e r E l e m e n t s +* +*****************************************************************************/ + +/****************************************************************************/ +/* Simple element structures */ +/****************************************************************************/ + +typedef struct _SGE_SIMPLE32 +{ + U32 FlagsLength; + U32 Address; +} SGE_SIMPLE32, MPI_POINTER PTR_SGE_SIMPLE32, + SGESimple32_t, MPI_POINTER pSGESimple32_t; + +typedef struct _SGE_SIMPLE64 +{ + U32 FlagsLength; + U64 Address; +} SGE_SIMPLE64, MPI_POINTER PTR_SGE_SIMPLE64, + SGESimple64_t, MPI_POINTER pSGESimple64_t; + +typedef struct _SGE_SIMPLE_UNION +{ + U32 FlagsLength; + union + { + U32 Address32; + U64 Address64; + }u; +} SGESimpleUnion_t, MPI_POINTER pSGESimpleUnion_t, + SGE_SIMPLE_UNION, MPI_POINTER PTR_SGE_SIMPLE_UNION; + +/****************************************************************************/ +/* Chain element structures */ +/****************************************************************************/ + +typedef struct _SGE_CHAIN32 +{ + U16 Length; + U8 NextChainOffset; + U8 Flags; + U32 Address; +} SGE_CHAIN32, MPI_POINTER PTR_SGE_CHAIN32, + SGEChain32_t, MPI_POINTER pSGEChain32_t; + +typedef struct _SGE_CHAIN64 +{ + U16 Length; + U8 NextChainOffset; + U8 Flags; + U64 Address; +} SGE_CHAIN64, MPI_POINTER PTR_SGE_CHAIN64, + SGEChain64_t, MPI_POINTER pSGEChain64_t; + +typedef struct _SGE_CHAIN_UNION +{ + U16 Length; + U8 NextChainOffset; + U8 Flags; + union + { + U32 Address32; + U64 Address64; + }u; +} SGE_CHAIN_UNION, MPI_POINTER PTR_SGE_CHAIN_UNION, + SGEChainUnion_t, MPI_POINTER pSGEChainUnion_t; + +/****************************************************************************/ +/* Transaction Context element */ +/****************************************************************************/ + +typedef struct _SGE_TRANSACTION32 +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 TransactionContext[1]; + U32 TransactionDetails[1]; +} SGE_TRANSACTION32, MPI_POINTER PTR_SGE_TRANSACTION32, + SGETransaction32_t, MPI_POINTER pSGETransaction32_t; + +typedef struct _SGE_TRANSACTION64 +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 TransactionContext[2]; + U32 TransactionDetails[1]; +} SGE_TRANSACTION64, MPI_POINTER PTR_SGE_TRANSACTION64, + SGETransaction64_t, MPI_POINTER pSGETransaction64_t; + +typedef struct _SGE_TRANSACTION96 +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 TransactionContext[3]; + U32 TransactionDetails[1]; +} SGE_TRANSACTION96, MPI_POINTER PTR_SGE_TRANSACTION96, + SGETransaction96_t, MPI_POINTER pSGETransaction96_t; + +typedef struct _SGE_TRANSACTION128 +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 TransactionContext[4]; + U32 TransactionDetails[1]; +} SGE_TRANSACTION128, MPI_POINTER PTR_SGE_TRANSACTION128, + SGETransaction_t128, MPI_POINTER pSGETransaction_t128; + +typedef struct _SGE_TRANSACTION_UNION +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + union + { + U32 TransactionContext32[1]; + U32 TransactionContext64[2]; + U32 TransactionContext96[3]; + U32 TransactionContext128[4]; + }u; + U32 TransactionDetails[1]; +} SGE_TRANSACTION_UNION, MPI_POINTER PTR_SGE_TRANSACTION_UNION, + SGETransactionUnion_t, MPI_POINTER pSGETransactionUnion_t; + + +/****************************************************************************/ +/* SGE IO types union for IO SGL's */ +/****************************************************************************/ + +typedef struct _SGE_IO_UNION +{ + union + { + SGE_SIMPLE_UNION Simple; + SGE_CHAIN_UNION Chain; + } u; +} SGE_IO_UNION, MPI_POINTER PTR_SGE_IO_UNION, + SGEIOUnion_t, MPI_POINTER pSGEIOUnion_t; + +/****************************************************************************/ +/* SGE union for SGL's with Simple and Transaction elements */ +/****************************************************************************/ + +typedef struct _SGE_TRANS_SIMPLE_UNION +{ + union + { + SGE_SIMPLE_UNION Simple; + SGE_TRANSACTION_UNION Transaction; + } u; +} SGE_TRANS_SIMPLE_UNION, MPI_POINTER PTR_SGE_TRANS_SIMPLE_UNION, + SGETransSimpleUnion_t, MPI_POINTER pSGETransSimpleUnion_t; + +/****************************************************************************/ +/* All SGE types union */ +/****************************************************************************/ + +typedef struct _SGE_MPI_UNION +{ + union + { + SGE_SIMPLE_UNION Simple; + SGE_CHAIN_UNION Chain; + SGE_TRANSACTION_UNION Transaction; + } u; +} SGE_MPI_UNION, MPI_POINTER PTR_SGE_MPI_UNION, + MPI_SGE_UNION_t, MPI_POINTER pMPI_SGE_UNION_t, + SGEAllUnion_t, MPI_POINTER pSGEAllUnion_t; + + +/****************************************************************************/ +/* SGE field definition and masks */ +/****************************************************************************/ + +/* Flags field bit definitions */ + +#define MPI_SGE_FLAGS_LAST_ELEMENT (0x80) +#define MPI_SGE_FLAGS_END_OF_BUFFER (0x40) +#define MPI_SGE_FLAGS_ELEMENT_TYPE_MASK (0x30) +#define MPI_SGE_FLAGS_LOCAL_ADDRESS (0x08) +#define MPI_SGE_FLAGS_DIRECTION (0x04) +#define MPI_SGE_FLAGS_ADDRESS_SIZE (0x02) +#define MPI_SGE_FLAGS_END_OF_LIST (0x01) + +#define MPI_SGE_FLAGS_SHIFT (24) + +#define MPI_SGE_LENGTH_MASK (0x00FFFFFF) +#define MPI_SGE_CHAIN_LENGTH_MASK (0x0000FFFF) + +/* Element Type */ + +#define MPI_SGE_FLAGS_TRANSACTION_ELEMENT (0x00) +#define MPI_SGE_FLAGS_SIMPLE_ELEMENT (0x10) +#define MPI_SGE_FLAGS_CHAIN_ELEMENT (0x30) +#define MPI_SGE_FLAGS_ELEMENT_MASK (0x30) + +/* Address location */ + +#define MPI_SGE_FLAGS_SYSTEM_ADDRESS (0x00) + +/* Direction */ + +#define MPI_SGE_FLAGS_IOC_TO_HOST (0x00) +#define MPI_SGE_FLAGS_HOST_TO_IOC (0x04) + +/* Address Size */ + +#define MPI_SGE_FLAGS_32_BIT_ADDRESSING (0x00) +#define MPI_SGE_FLAGS_64_BIT_ADDRESSING (0x02) + +/* Context Size */ + +#define MPI_SGE_FLAGS_32_BIT_CONTEXT (0x00) +#define MPI_SGE_FLAGS_64_BIT_CONTEXT (0x02) +#define MPI_SGE_FLAGS_96_BIT_CONTEXT (0x04) +#define MPI_SGE_FLAGS_128_BIT_CONTEXT (0x06) + +#define MPI_SGE_CHAIN_OFFSET_MASK (0x00FF0000) +#define MPI_SGE_CHAIN_OFFSET_SHIFT (16) + + +/****************************************************************************/ +/* SGE operation Macros */ +/****************************************************************************/ + + /* SIMPLE FlagsLength manipulations... */ +#define MPI_SGE_SET_FLAGS(f) ((U32)(f) << MPI_SGE_FLAGS_SHIFT) +#define MPI_SGE_GET_FLAGS(fl) (((fl) & ~MPI_SGE_LENGTH_MASK) >> MPI_SGE_FLAGS_SHIFT) +#define MPI_SGE_LENGTH(fl) ((fl) & MPI_SGE_LENGTH_MASK) +#define MPI_SGE_CHAIN_LENGTH(fl) ((fl) & MPI_SGE_CHAIN_LENGTH_MASK) + +#define MPI_SGE_SET_FLAGS_LENGTH(f,l) (MPI_SGE_SET_FLAGS(f) | MPI_SGE_LENGTH(l)) + +#define MPI_pSGE_GET_FLAGS(psg) MPI_SGE_GET_FLAGS((psg)->FlagsLength) +#define MPI_pSGE_GET_LENGTH(psg) MPI_SGE_LENGTH((psg)->FlagsLength) +#define MPI_pSGE_SET_FLAGS_LENGTH(psg,f,l) (psg)->FlagsLength = MPI_SGE_SET_FLAGS_LENGTH(f,l) + /* CAUTION - The following are READ-MODIFY-WRITE! */ +#define MPI_pSGE_SET_FLAGS(psg,f) (psg)->FlagsLength |= MPI_SGE_SET_FLAGS(f) +#define MPI_pSGE_SET_LENGTH(psg,l) (psg)->FlagsLength |= MPI_SGE_LENGTH(l) + +#define MPI_GET_CHAIN_OFFSET(x) ((x&MPI_SGE_CHAIN_OFFSET_MASK)>>MPI_SGE_CHAIN_OFFSET_SHIFT) + + + +/***************************************************************************** +* +* S t a n d a r d M e s s a g e S t r u c t u r e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* Standard message request header for all request messages */ +/****************************************************************************/ + +typedef struct _MSG_REQUEST_HEADER +{ + U8 Reserved[2]; /* function specific */ + U8 ChainOffset; + U8 Function; + U8 Reserved1[3]; /* function specific */ + U8 MsgFlags; + U32 MsgContext; +} MSG_REQUEST_HEADER, MPI_POINTER PTR_MSG_REQUEST_HEADER, + MPIHeader_t, MPI_POINTER pMPIHeader_t; + + +/****************************************************************************/ +/* Default Reply */ +/****************************************************************************/ + +typedef struct _MSG_DEFAULT_REPLY +{ + U8 Reserved[2]; /* function specific */ + U8 MsgLength; + U8 Function; + U8 Reserved1[3]; /* function specific */ + U8 MsgFlags; + U32 MsgContext; + U8 Reserved2[2]; /* function specific */ + U16 IOCStatus; + U32 IOCLogInfo; +} MSG_DEFAULT_REPLY, MPI_POINTER PTR_MSG_DEFAULT_REPLY, + MPIDefaultReply_t, MPI_POINTER pMPIDefaultReply_t; + + +/* MsgFlags definition for all replies */ + +#define MPI_MSGFLAGS_CONTINUATION_REPLY (0x80) + + +/***************************************************************************** +* +* I O C S t a t u s V a l u e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* Common IOCStatus values for all replies */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_SUCCESS (0x0000) +#define MPI_IOCSTATUS_INVALID_FUNCTION (0x0001) +#define MPI_IOCSTATUS_BUSY (0x0002) +#define MPI_IOCSTATUS_INVALID_SGL (0x0003) +#define MPI_IOCSTATUS_INTERNAL_ERROR (0x0004) +#define MPI_IOCSTATUS_RESERVED (0x0005) +#define MPI_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006) +#define MPI_IOCSTATUS_INVALID_FIELD (0x0007) +#define MPI_IOCSTATUS_INVALID_STATE (0x0008) + +/****************************************************************************/ +/* Config IOCStatus values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020) +#define MPI_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021) +#define MPI_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022) +#define MPI_IOCSTATUS_CONFIG_INVALID_DATA (0x0023) +#define MPI_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024) +#define MPI_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025) + +/****************************************************************************/ +/* SCSIIO Reply (SPI & FCP) initiator values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040) +#define MPI_IOCSTATUS_SCSI_INVALID_BUS (0x0041) +#define MPI_IOCSTATUS_SCSI_INVALID_TARGETID (0x0042) +#define MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043) +#define MPI_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044) +#define MPI_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045) +#define MPI_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046) +#define MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047) +#define MPI_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048) +#define MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049) +#define MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A) +#define MPI_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B) +#define MPI_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C) + +/****************************************************************************/ +/* SCSI (SPI & FCP) target values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_TARGET_PRIORITY_IO (0x0060) +#define MPI_IOCSTATUS_TARGET_INVALID_PORT (0x0061) +#define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX (0x0062) +#define MPI_IOCSTATUS_TARGET_ABORTED (0x0063) +#define MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE (0x0064) +#define MPI_IOCSTATUS_TARGET_NO_CONNECTION (0x0065) +#define MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006A) +#define MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT (0x006B) + +/****************************************************************************/ +/* Additional FCP target values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_TARGET_FC_ABORTED (0x0066) /* obsolete */ +#define MPI_IOCSTATUS_TARGET_FC_RX_ID_INVALID (0x0067) /* obsolete */ +#define MPI_IOCSTATUS_TARGET_FC_DID_INVALID (0x0068) /* obsolete */ +#define MPI_IOCSTATUS_TARGET_FC_NODE_LOGGED_OUT (0x0069) /* obsolete */ + +/****************************************************************************/ +/* Fibre Channel Direct Access values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_FC_ABORTED (0x0066) +#define MPI_IOCSTATUS_FC_RX_ID_INVALID (0x0067) +#define MPI_IOCSTATUS_FC_DID_INVALID (0x0068) +#define MPI_IOCSTATUS_FC_NODE_LOGGED_OUT (0x0069) + +/****************************************************************************/ +/* LAN values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND (0x0080) +#define MPI_IOCSTATUS_LAN_DEVICE_FAILURE (0x0081) +#define MPI_IOCSTATUS_LAN_TRANSMIT_ERROR (0x0082) +#define MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED (0x0083) +#define MPI_IOCSTATUS_LAN_RECEIVE_ERROR (0x0084) +#define MPI_IOCSTATUS_LAN_RECEIVE_ABORTED (0x0085) +#define MPI_IOCSTATUS_LAN_PARTIAL_PACKET (0x0086) +#define MPI_IOCSTATUS_LAN_CANCELED (0x0087) + + +/****************************************************************************/ +/* IOCStatus flag to indicate that log info is available */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE (0x8000) +#define MPI_IOCSTATUS_MASK (0x7FFF) + +/****************************************************************************/ +/* LogInfo Types */ +/****************************************************************************/ + +#define MPI_IOCLOGINFO_TYPE_MASK (0xF0000000) +#define MPI_IOCLOGINFO_TYPE_NONE (0x00) +#define MPI_IOCLOGINFO_TYPE_SCSI (0x01) +#define MPI_IOCLOGINFO_TYPE_FC (0x02) +#define MPI_IOCLOGINFO_LOG_DATA_MASK (0x0FFFFFFF) + + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/lsi/mpi_cnfg.h linux.ac/drivers/message/fusion/lsi/mpi_cnfg.h --- linux.vanilla/drivers/message/fusion/lsi/mpi_cnfg.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/lsi/mpi_cnfg.h Tue Apr 3 17:54:47 2001 @@ -0,0 +1,971 @@ +/* + * Copyright (c) 2000-2001 LSI Logic Corporation. + * + * + * Name: MPI_CNFG.H + * Title: MPI Config message, structures, and Pages + * Creation Date: July 27, 2000 + * + * MPI Version: 01.01.09 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 06-08-00 01.00.02 Added _PAGEVERSION definitions for all pages. + * Added FcPhLowestVersion, FcPhHighestVersion, Reserved2 + * fields to FC_DEVICE_0 page, updated the page version. + * Changed _FREE_RUNNING_CLOCK to _PACING_TRANSFERS in + * SCSI_PORT_0, SCSI_DEVICE_0 and SCSI_DEVICE_1 pages + * and updated the page versions. + * Added _RESPONSE_ID_MASK definition to SCSI_PORT_1 + * page and updated the page version. + * Added Information field and _INFO_PARAMS_NEGOTIATED + * definitionto SCSI_DEVICE_0 page. + * 06-22-00 01.00.03 Removed batch controls from LAN_0 page and updated the + * page version. + * Added BucketsRemaining to LAN_1 page, redefined the + * state values, and updated the page version. + * Revised bus width definitions in SCSI_PORT_0, + * SCSI_DEVICE_0 and SCSI_DEVICE_1 pages. + * 06-30-00 01.00.04 Added MaxReplySize to LAN_1 page and updated the page + * version. + * Moved FC_DEVICE_0 PageAddress description to spec. + * 07-27-00 01.00.05 Corrected the SubsystemVendorID and SubsystemID field + * widths in IOC_0 page and updated the page version. + * 11-02-00 01.01.01 Original release for post 1.0 work + * Added Manufacturing pages, IO Unit Page 2, SCSI SPI + * Port Page 2, FC Port Page 4, FC Port Page 5 + * 11-15-00 01.01.02 Interim changes to match proposals + * 12-04-00 01.01.03 Config page changes to match MPI rev 1.00.01. + * 12-05-00 01.01.04 Modified config page actions. + * 01-09-01 01.01.05 Added defines for page address formats. + * Data size for Manufacturing pages 2 and 3 no longer + * defined here. + * Io Unit Page 2 size is fixed at 4 adapters and some + * flags were changed. + * SCSI Port Page 2 Device Settings modified. + * New fields added to FC Port Page 0 and some flags + * cleaned up. + * Removed impedance flash from FC Port Page 1. + * Added FC Port pages 6 and 7. + * 01-25-01 01.01.06 Added MaxInitiators field to FcPortPage0. + * 01-29-01 01.01.07 Changed some defines to make them 32 character unique. + * Added some LinkType defines for FcPortPage0. + * 02-20-01 01.01.08 Started using MPI_POINTER. + * 02-27-01 01.01.09 Replaced MPI_CONFIG_PAGETYPE_SCSI_LUN with + * MPI_CONFIG_PAGETYPE_RAID_VOLUME. + * Added definitions and structures for IOC Page 2 and + * RAID Volume Page 2. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_CNFG_H +#define MPI_CNFG_H + + +/***************************************************************************** +* +* C o n f i g M e s s a g e a n d S t r u c t u r e s +* +*****************************************************************************/ + +typedef struct _CONFIG_PAGE_HEADER +{ + U8 PageVersion; + U8 PageLength; + U8 PageNumber; + U8 PageType; +} fCONFIG_PAGE_HEADER, MPI_POINTER PTR_CONFIG_PAGE_HEADER, + ConfigPageHeader_t, MPI_POINTER pConfigPageHeader_t; + +typedef union _CONFIG_PAGE_HEADER_UNION +{ + ConfigPageHeader_t Struct; + U8 Bytes[4]; + U16 Word16[2]; + U32 Word32; +} ConfigPageHeaderUnion, MPI_POINTER pConfigPageHeaderUnion, + fCONFIG_PAGE_HEADER_UNION, MPI_POINTER PTR_CONFIG_PAGE_HEADER_UNION; + + +/****************************************************************************/ +/* PageType field values */ +/****************************************************************************/ +#define MPI_CONFIG_PAGEATTR_READ_ONLY (0x00) +#define MPI_CONFIG_PAGEATTR_CHANGEABLE (0x10) +#define MPI_CONFIG_PAGEATTR_PERSISTENT (0x20) +#define MPI_CONFIG_PAGEATTR_MASK (0xF0) + +#define MPI_CONFIG_PAGETYPE_IO_UNIT (0x00) +#define MPI_CONFIG_PAGETYPE_IOC (0x01) +#define MPI_CONFIG_PAGETYPE_BIOS (0x02) +#define MPI_CONFIG_PAGETYPE_SCSI_PORT (0x03) +#define MPI_CONFIG_PAGETYPE_SCSI_DEVICE (0x04) +#define MPI_CONFIG_PAGETYPE_FC_PORT (0x05) +#define MPI_CONFIG_PAGETYPE_FC_DEVICE (0x06) +#define MPI_CONFIG_PAGETYPE_LAN (0x07) +#define MPI_CONFIG_PAGETYPE_RAID_VOLUME (0x08) +#define MPI_CONFIG_PAGETYPE_MANUFACTURING (0x09) +#define MPI_CONFIG_PAGETYPE_MASK (0x0F) + +#define MPI_CONFIG_TYPENUM_MASK (0x0FFF) + + +/**************************************************************************** + * PageAddres field values + ****************************************************************************/ +#define MPI_SCSI_PORT_PGAD_PORT_MASK (0x000000FF) + +#define MPI_SCSI_DEVICE_TARGET_ID_MASK (0x000000FF) +#define MPI_SCSI_DEVICE_TARGET_ID_SHIFT (0) +#define MPI_SCSI_DEVICE_BUS_MASK (0x0000FF00) +#define MPI_SCSI_DEVICE_BUS_SHIFT (8) + +#define MPI_SCSI_LUN_TARGET_ID_MASK (0x000000FF) +#define MPI_SCSI_LUN_TARGET_ID_SHIFT (0) +#define MPI_SCSI_LUN_BUS_MASK (0x0000FF00) +#define MPI_SCSI_LUN_BUS_SHIFT (8) +#define MPI_SCSI_LUN_LUN_MASK (0x00FF0000) +#define MPI_SCSI_LUN_LUN_SHIFT (16) + +#define MPI_FC_PORT_PGAD_PORT_MASK (0xF0000000) +#define MPI_FC_PORT_PGAD_PORT_SHIFT (28) +#define MPI_FC_PORT_PGAD_FORM_MASK (0x0F000000) +#define MPI_FC_PORT_PGAD_FORM_INDEX (0x01000000) +#define MPI_FC_PORT_PGAD_INDEX_MASK (0x0000FFFF) +#define MPI_FC_PORT_PGAD_INDEX_SHIFT (0) + +#define MPI_FC_DEVICE_PGAD_PORT_MASK (0xF0000000) +#define MPI_FC_DEVICE_PGAD_PORT_SHIFT (28) +#define MPI_FC_DEVICE_PGAD_FORM_MASK (0x0F000000) +#define MPI_FC_DEVICE_PGAD_FORM_NEXT_DID (0x00000000) +#define MPI_FC_DEVICE_PGAD_ND_PORT_MASK (0xF0000000) +#define MPI_FC_DEVICE_PGAD_ND_PORT_SHIFT (28) +#define MPI_FC_DEVICE_PGAD_ND_DID_MASK (0x00FFFFFF) +#define MPI_FC_DEVICE_PGAD_ND_DID_SHIFT (0) +#define MPI_FC_DEVICE_PGAD_FORM_BUS_TID (0x01000000) +#define MPI_FC_DEVICE_PGAD_BT_BUS_MASK (0x0000FF00) +#define MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT (8) +#define MPI_FC_DEVICE_PGAD_BT_TID_MASK (0x000000FF) +#define MPI_FC_DEVICE_PGAD_BT_TID_SHIFT (0) + + +/****************************************************************************/ +/* Config Request Message */ +/****************************************************************************/ +typedef struct _MSG_CONFIG +{ + U8 Action; + U8 Reserved; + U8 ChainOffset; + U8 Function; + U8 Reserved1[3]; + U8 MsgFlags; + U32 MsgContext; + U8 Reserved2[8]; + fCONFIG_PAGE_HEADER Header; + U32 PageAddress; + SGE_IO_UNION PageBufferSGE; +} MSG_CONFIG, MPI_POINTER PTR_MSG_CONFIG, + Config_t, MPI_POINTER pConfig_t; + + +/****************************************************************************/ +/* Action field values */ +/****************************************************************************/ +#define MPI_CONFIG_ACTION_PAGE_HEADER (0x00) +/*#define MPI_CONFIG_ACTION_PAGE_READ (0x01) *//* obsolete */ +#define MPI_CONFIG_ACTION_PAGE_READ_CURRENT (0x01) +/*#define MPI_CONFIG_ACTION_PAGE_WRITE (0x02) *//* obsolete */ +#define MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT (0x02) +#define MPI_CONFIG_ACTION_PAGE_DEFAULT (0x03) +/*#define MPI_CONFIG_ACTION_PAGE_WRITE_COMMIT (0x04) */ /* obsolete */ +#define MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM (0x04) +#define MPI_CONFIG_ACTION_PAGE_READ_DEFAULT (0x05) +#define MPI_CONFIG_ACTION_PAGE_READ_NVRAM (0x06) + + +/* Config Reply Message */ +typedef struct _MSG_CONFIG_REPLY +{ + U8 Action; + U8 Reserved; + U8 MsgLength; + U8 Function; + U8 Reserved1[3]; + U8 MsgFlags; + U32 MsgContext; + U8 Reserved2[2]; + U16 IOCStatus; + U32 IOCLogInfo; + fCONFIG_PAGE_HEADER Header; +} MSG_CONFIG_REPLY, MPI_POINTER PTR_MSG_CONFIG_REPLY, + ConfigReply_t, MPI_POINTER pConfigReply_t; + + + +/***************************************************************************** +* +* C o n f i g u r a t i o n P a g e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* Manufacturing Config pages */ +/****************************************************************************/ +#define MPI_MANUFACTPAGE_DEVICEID_FC909 (0x0621) +#define MPI_MANUFACTPAGE_DEVICEID_FC919 (0x0624) +#define MPI_MANUFACTPAGE_DEVICEID_FC929 (0x0622) +#define MPI_MANUFACTPAGE_DEVID_53C1030 (0x0030) +#define MPI_MANUFACTPAGE_DEVID_53C1030ZC (0x0031) +#define MPI_MANUFACTPAGE_DEVID_53C1035 (0x0035) + +typedef struct _CONFIG_PAGE_MANUFACTURING_0 +{ + fCONFIG_PAGE_HEADER Header; + U8 ChipName[16]; + U8 ChipRevision[8]; + U8 BoardName[16]; + U8 BoardAssembly[16]; + U8 BoardTracerNumber[16]; + +} fCONFIG_PAGE_MANUFACTURING_0, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_0, + ManufacturingPage0_t, MPI_POINTER pManufacturingPage0_t; + +#define MPI_MANUFACTURING0_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_MANUFACTURING_1 +{ + fCONFIG_PAGE_HEADER Header; + U8 VPD[256]; +} fCONFIG_PAGE_MANUFACTURING_1, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_1, + ManufacturingPage1_t, MPI_POINTER pManufacturingPage1_t; + +#define MPI_MANUFACTURING1_PAGEVERSION (0x00) + + +typedef struct _MPI_CHIP_REVISION_ID +{ + U16 DeviceID; + U8 PCIRevisionID; + U8 Reserved; +} MPI_CHIP_REVISION_ID, MPI_POINTER PTR_MPI_CHIP_REVISION_ID, + MpiChipRevisionId_t, MPI_POINTER pMpiChipRevisionId_t; + + +typedef struct _CONFIG_PAGE_MANUFACTURING_2 +{ + fCONFIG_PAGE_HEADER Header; + MPI_CHIP_REVISION_ID ChipId; + U32 HwSettings[1]; +} fCONFIG_PAGE_MANUFACTURING_2, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_2, + ManufacturingPage2_t, MPI_POINTER pManufacturingPage2_t; + +#define MPI_MANUFACTURING2_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_MANUFACTURING_3 +{ + fCONFIG_PAGE_HEADER Header; + MPI_CHIP_REVISION_ID ChipId; + U32 Info[1]; +} fCONFIG_PAGE_MANUFACTURING_3, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_3, + ManufacturingPage3_t, MPI_POINTER pManufacturingPage3_t; + +#define MPI_MANUFACTURING3_PAGEVERSION (0x00) + + +/****************************************************************************/ +/* IO Unit Config Pages */ +/****************************************************************************/ + +typedef struct _CONFIG_PAGE_IO_UNIT_0 +{ + fCONFIG_PAGE_HEADER Header; + U64 UniqueValue; +} fCONFIG_PAGE_IO_UNIT_0, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_0, + IOUnitPage0_t, MPI_POINTER pIOUnitPage0_t; + +#define MPI_IOUNITPAGE0_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_IO_UNIT_1 +{ + fCONFIG_PAGE_HEADER Header; + U32 Flags; +} fCONFIG_PAGE_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_1, + IOUnitPage1_t, MPI_POINTER pIOUnitPage1_t; + +#define MPI_IOUNITPAGE1_PAGEVERSION (0x00) + +#define MPI_IOUNITPAGE1_MULTI_FUNCTION (0x00000000) +#define MPI_IOUNITPAGE1_SINGLE_FUNCTION (0x00000001) +#define MPI_IOUNITPAGE1_MULTI_PATHING (0x00000002) +#define MPI_IOUNITPAGE1_SINGLE_PATHING (0x00000000) + +#define MPI_IOUNITPAGE1_FORCE_32 (0x00000080) + + +typedef struct _MPI_ADAPTER_INFO +{ + U8 PciBusNumber; + U8 PciDeviceAndFunctionNumber; + U16 AdapterFlags; +} MPI_ADAPTER_INFO, MPI_POINTER PTR_MPI_ADAPTER_INFO, + MpiAdapterInfo_t, MPI_POINTER pMpiAdapterInfo_t; + +#define MPI_ADAPTER_INFO_FLAGS_EMBEDDED (0x0001) +#define MPI_ADAPTER_INFO_FLAGS_INIT_STATUS (0x0002) + +typedef struct _CONFIG_PAGE_IO_UNIT_2 +{ + fCONFIG_PAGE_HEADER Header; + U32 Flags; + U32 BiosVersion; + MPI_ADAPTER_INFO AdapterOrder[4]; +} fCONFIG_PAGE_IO_UNIT_2, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_2, + IOUnitPage2_t, MPI_POINTER pIOUnitPage2_t; + +#define MPI_IOUNITPAGE2_PAGEVERSION (0x00) + +#define MPI_IOUNITPAGE2_FLAGS_RAID_DISABLE (0x00000001) +#define MPI_IOUNITPAGE2_FLAGS_PAUSE_ON_ERROR (0x00000002) +#define MPI_IOUNITPAGE2_FLAGS_VERBOSE_ENABLE (0x00000004) +#define MPI_IOUNITPAGE2_FLAGS_COLOR_VIDEO_DISABLE (0x00000008) +#define MPI_IOUNITPAGE2_FLAGS_DONT_HOOK_INT_40 (0x00000010) + + +/****************************************************************************/ +/* IOC Config Pages */ +/****************************************************************************/ + +typedef struct _CONFIG_PAGE_IOC_0 +{ + fCONFIG_PAGE_HEADER Header; + U32 TotalNVStore; + U32 FreeNVStore; + U16 VendorID; + U16 DeviceID; + U8 RevisionID; + U8 Reserved[3]; + U32 ClassCode; + U16 SubsystemVendorID; + U16 SubsystemID; +} fCONFIG_PAGE_IOC_0, MPI_POINTER PTR_CONFIG_PAGE_IOC_0, + IOCPage0_t, MPI_POINTER pIOCPage0_t; + +#define MPI_IOCPAGE0_PAGEVERSION (0x01) + +typedef struct _CONFIG_PAGE_IOC_1 +{ + fCONFIG_PAGE_HEADER Header; + U32 Flags; + U32 CoalescingTimeout; + U8 CoalescingDepth; + U8 Reserved[3]; +} fCONFIG_PAGE_IOC_1, MPI_POINTER PTR_CONFIG_PAGE_IOC_1, + IOCPage1_t, MPI_POINTER pIOCPage1_t; + +#define MPI_IOCPAGE1_PAGEVERSION (0x00) + +#define MPI_IOCPAGE1_REPLY_COALESCING (0x00000001) + +typedef struct _CONFIG_PAGE_IOC_2_RAID_VOL +{ + U8 VolumeTargetID; + U8 VolumeBus; + U16 Reserved; + U8 VolumeVersionMinor; + U8 VolumeVersionMajor; + U8 VolumeRaidType; + U8 Reserved1; +} fCONFIG_PAGE_IOC_2_RAID_VOL, MPI_POINTER PTR_CONFIG_PAGE_IOC_2_RAID_VOL, + ConfigPageIoc2RaidVol_t, MPI_POINTER pConfigPageIoc2RaidVol_t; + +typedef struct _CONFIG_PAGE_IOC_2 +{ + fCONFIG_PAGE_HEADER Header; + U32 CapabilitiesFlags; + U8 NumActiveVolumes; + U8 MaxVolumes; + U16 Reserved; + fCONFIG_PAGE_IOC_2_RAID_VOL RaidVolume[1]; +} fCONFIG_PAGE_IOC_2, MPI_POINTER PTR_CONFIG_PAGE_IOC_2, + IOCPage2_t, MPI_POINTER pIOCPage2_t; + +#define MPI_IOCPAGE2_PAGEVERSION (0x00) + +/* IOC Page 2 Capabilities flags */ + +#define MPI_IOCPAGE2_CAP_FLAGS_RAID_0_SUPPORT (0x00000001) +#define MPI_IOCPAGE2_CAP_FLAGS_RAID_1_SUPPORT (0x00000002) +#define MPI_IOCPAGE2_CAP_FLAGS_LSI_MIRROR_SUPPORT (0x00000004) +#define MPI_IOCPAGE2_CAP_FLAGS_RAID_5_SUPPORT (0x00000008) +#define MPI_IOCPAGE2_CAP_FLAGS_RAID_10_SUPPORT (0x00000010) + +/* IOC Page 2 Volume RAID Type values */ + +#define MPI_IOCPAGE2_VOL_TYPE_RAID_0 (0x00) +#define MPI_IOCPAGE2_VOL_TYPE_RAID_1 (0x01) +#define MPI_IOCPAGE2_VOL_TYPE_LSI_MIRROR (0x02) +#define MPI_IOCPAGE2_VOL_TYPE_RAID_5 (0x05) +#define MPI_IOCPAGE2_VOL_TYPE_RAID_10 (0x0A) + + +/****************************************************************************/ +/* SCSI Port Config Pages */ +/****************************************************************************/ + +typedef struct _CONFIG_PAGE_SCSI_PORT_0 +{ + fCONFIG_PAGE_HEADER Header; + U32 Capabilities; + U32 PhysicalInterface; +} fCONFIG_PAGE_SCSI_PORT_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_0, + SCSIPortPage0_t, MPI_POINTER pSCSIPortPage0_t; + +#define MPI_SCSIPORTPAGE0_PAGEVERSION (0x01) + +#define MPI_SCSIPORTPAGE0_CAP_IU (0x00000001) +#define MPI_SCSIPORTPAGE0_CAP_DT (0x00000002) +#define MPI_SCSIPORTPAGE0_CAP_QAS (0x00000004) +#define MPI_SCSIPORTPAGE0_CAP_PACING_TRANSFERS (0x00000008) +#define MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK (0x0000FF00) +#define MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK (0x00FF0000) +#define MPI_SCSIPORTPAGE0_CAP_WIDE (0x20000000) +#define MPI_SCSIPORTPAGE0_CAP_AIP (0x80000000) + +#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK (0x00000003) +#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD (0x01) +#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE (0x02) +#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_LVD (0x03) + +typedef struct _CONFIG_PAGE_SCSI_PORT_1 +{ + fCONFIG_PAGE_HEADER Header; + U32 Configuration; +} fCONFIG_PAGE_SCSI_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_1, + SCSIPortPage1_t, MPI_POINTER pSCSIPortPage1_t; + +#define MPI_SCSIPORTPAGE1_PAGEVERSION (0x01) + +#define MPI_SCSIPORTPAGE1_CFG_PORT_SCSI_ID_MASK (0x000000FF) +#define MPI_SCSIPORTPAGE1_CFG_PORT_RESPONSE_ID_MASK (0xFFFF0000) + +typedef struct _MPI_DEVICE_INFO +{ + U8 Timeout; + U8 SyncFactor; + U16 DeviceFlags; +} MPI_DEVICE_INFO, MPI_POINTER PTR_MPI_DEVICE_INFO, + MpiDeviceInfo_t, MPI_POINTER pMpiDeviceInfo_t; + +typedef struct _CONFIG_PAGE_SCSI_PORT_2 +{ + fCONFIG_PAGE_HEADER Header; + U32 PortFlags; + U32 PortSettings; + MPI_DEVICE_INFO DeviceSettings[16]; +} fCONFIG_PAGE_SCSI_PORT_2, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_2, + SCSIPortPage2_t, MPI_POINTER pSCSIPortPage2_t; + +#define MPI_SCSIPORTPAGE2_PAGEVERSION (0x01) + +#define MPI_SCSIPORTPAGE2_PORT_FLAGS_SCAN_HIGH_TO_LOW (0x00000001) +#define MPI_SCSIPORTPAGE2_PORT_FLAGS_PARITY_ENABLE (0x00000002) +#define MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET (0x00000004) +#define MPI_SCSIPORTPAGE2_PORT_FLAGS_ALTERNATE_CHS (0x00000008) +#define MPI_SCSIPORTPAGE2_PORT_FLAGS_TERMINATION_DISABLE (0x00000010) + +#define MPI_SCSIPORTPAGE2_PORT_HOST_ID_MASK (0x0000000F) +#define MPI_SCSIPORTPAGE2_PORT_MASK_INIT_HBA (0x00000030) +#define MPI_SCSIPORTPAGE2_PORT_DISABLE_INIT_HBA (0x00000000) +#define MPI_SCSIPORTPAGE2_PORT_BIOS_INIT_HBA (0x00000010) +#define MPI_SCSIPORTPAGE2_PORT_OS_INIT_HBA (0x00000020) +#define MPI_SCSIPORTPAGE2_PORT_BIOS_OS_INIT_HBA (0x00000030) +#define MPI_SCSIPORTPAGE2_PORT_REMOVABLE_MEDIA (0x000000C0) +#define MPI_SCSIPORTPAGE2_PORT_SPINUP_DELAY_MASK (0x00000F00) +#define MPI_SCSIPORTPAGE2_PORT_MASK_NEGO_MASTER_SETTINGS (0x00003000) +#define MPI_SCSIPORTPAGE2_PORT_NEGO_MASTER_SETTINGS (0x00000000) +#define MPI_SCSIPORTPAGE2_PORT_NONE_MASTER_SETTINGS (0x00000001) +#define MPI_SCSIPORTPAGE2_PORT_ALL_MASTER_SETTINGS (0x00000003) + +#define MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE (0x00000001) +#define MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE (0x00000002) +#define MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE (0x00000004) +#define MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE (0x00000008) +#define MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE (0x00000010) +#define MPI_SCSIPORTPAGE2_DEVICE_BOOT_CHOICE (0x00000020) + + +/****************************************************************************/ +/* SCSI Target Device Config Pages */ +/****************************************************************************/ + +typedef struct _CONFIG_PAGE_SCSI_DEVICE_0 +{ + fCONFIG_PAGE_HEADER Header; + U32 NegotiatedParameters; + U32 Information; +} fCONFIG_PAGE_SCSI_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_0, + SCSIDevicePage0_t, MPI_POINTER pSCSIDevicePage0_t; + +#define MPI_SCSIDEVPAGE0_PAGEVERSION (0x01) + +#define MPI_SCSIDEVPAGE0_NP_IU (0x00000001) +#define MPI_SCSIDEVPAGE0_NP_DT (0x00000002) +#define MPI_SCSIDEVPAGE0_NP_QAS (0x00000004) +#define MPI_SCSIDEVPAGE0_NP_PACING_TRANSFERS (0x00000008) +#define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK (0x0000FF00) +#define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK (0x00FF0000) +#define MPI_SCSIDEVPAGE0_NP_WIDE (0x20000000) +#define MPI_SCSIDEVPAGE0_NP_AIP (0x80000000) + +#define MPI_SCSIDEVPAGE0_INFO_PARAMS_NEGOTIATED (0x00000001) + +typedef struct _CONFIG_PAGE_SCSI_DEVICE_1 +{ + fCONFIG_PAGE_HEADER Header; + U32 RequestedParameters; + U32 DomainValidation; + U32 Configuration; +} fCONFIG_PAGE_SCSI_DEVICE_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_1, + SCSIDevicePage1_t, MPI_POINTER pSCSIDevicePage1_t; + +#define MPI_SCSIDEVPAGE1_PAGEVERSION (0x01) + +#define MPI_SCSIDEVPAGE1_RP_IU (0x00000001) +#define MPI_SCSIDEVPAGE1_RP_DT (0x00000002) +#define MPI_SCSIDEVPAGE1_RP_QAS (0x00000004) +#define MPI_SCSIDEVPAGE1_RP_PACING_TRANSFERS (0x00000008) +#define MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK (0x0000FF00) +#define MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK (0x00FF0000) +#define MPI_SCSIDEVPAGE1_RP_WIDE (0x20000000) +#define MPI_SCSIDEVPAGE1_RP_AIP (0x80000000) + +#define MPI_SCSIDEVPAGE1_DV_LVD_DRIVE_STRENGTH_MASK (0x00000003) +#define MPI_SCSIDEVPAGE1_DV_SE_SLEW_RATE_MASK (0x00000300) + +#define MPI_SCSIDEVPAGE1_CONF_PPR_ALLOWED (0x00000001) + +/****************************************************************************/ +/* FC Port Config Pages */ +/****************************************************************************/ + +typedef struct _CONFIG_PAGE_FC_PORT_0 +{ + fCONFIG_PAGE_HEADER Header; + U32 Flags; + U8 MPIPortNumber; + U8 LinkType; + U8 PortState; + U8 Reserved; + U32 PortIdentifier; + U64 WWNN; + U64 WWPN; + U32 SupportedServiceClass; + U32 SupportedSpeeds; + U32 CurrentSpeed; + U32 MaxFrameSize; + U64 FabricWWNN; + U64 FabricWWPN; + U32 DiscoveredPortsCount; + U32 MaxInitiators; +} fCONFIG_PAGE_FC_PORT_0, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_0, + FCPortPage0_t, MPI_POINTER pFCPortPage0_t; + +#define MPI_FCPORTPAGE0_PAGEVERSION (0x01) + +#define MPI_FCPORTPAGE0_FLAGS_PROT_MASK (0x0000000F) +#define MPI_FCPORTPAGE0_FLAGS_PROT_FCP_INIT (MPI_PORTFACTS_PROTOCOL_INITIATOR) +#define MPI_FCPORTPAGE0_FLAGS_PROT_FCP_TARG (MPI_PORTFACTS_PROTOCOL_TARGET) +#define MPI_FCPORTPAGE0_FLAGS_PROT_LAN (MPI_PORTFACTS_PROTOCOL_LAN) +#define MPI_FCPORTPAGE0_FLAGS_PROT_LOGBUSADDR (MPI_PORTFACTS_PROTOCOL_LOGBUSADDR) + +#define MPI_FCPORTPAGE0_FLAGS_ALIAS_ALPA_SUPPORTED (0x00000010) +#define MPI_FCPORTPAGE0_FLAGS_ALIAS_WWN_SUPPORTED (0x00000020) +#define MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID (0x00000030) + +#define MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK (0x00000700) +#define MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT (0x00000000) +#define MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP (0x00000100) +#define MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT (0x00000200) +#define MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP (0x00000300) +#define MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT (0x00000700) + +#define MPI_FCPORTPAGE0_LTYPE_RESERVED (0x00) +#define MPI_FCPORTPAGE0_LTYPE_OTHER (0x01) +#define MPI_FCPORTPAGE0_LTYPE_UNKNOWN (0x02) +#define MPI_FCPORTPAGE0_LTYPE_COPPER (0x03) +#define MPI_FCPORTPAGE0_LTYPE_SINGLE_1300 (0x04) +#define MPI_FCPORTPAGE0_LTYPE_SINGLE_1500 (0x05) +#define MPI_FCPORTPAGE0_LTYPE_50_LASER_MULTI (0x06) +#define MPI_FCPORTPAGE0_LTYPE_50_LED_MULTI (0x07) +#define MPI_FCPORTPAGE0_LTYPE_62_LASER_MULTI (0x08) +#define MPI_FCPORTPAGE0_LTYPE_62_LED_MULTI (0x09) +#define MPI_FCPORTPAGE0_LTYPE_MULTI_LONG_WAVE (0x0A) +#define MPI_FCPORTPAGE0_LTYPE_MULTI_SHORT_WAVE (0x0B) +#define MPI_FCPORTPAGE0_LTYPE_LASER_SHORT_WAVE (0x0C) +#define MPI_FCPORTPAGE0_LTYPE_LED_SHORT_WAVE (0x0D) +#define MPI_FCPORTPAGE0_LTYPE_1300_LONG_WAVE (0x0E) +#define MPI_FCPORTPAGE0_LTYPE_1500_LONG_WAVE (0x0F) + +#define MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN (0x01) /*(SNIA)HBA_PORTSTATE_UNKNOWN 1 Unknown */ +#define MPI_FCPORTPAGE0_PORTSTATE_ONLINE (0x02) /*(SNIA)HBA_PORTSTATE_ONLINE 2 Operational */ +#define MPI_FCPORTPAGE0_PORTSTATE_OFFLINE (0x03) /*(SNIA)HBA_PORTSTATE_OFFLINE 3 User Offline */ +#define MPI_FCPORTPAGE0_PORTSTATE_BYPASSED (0x04) /*(SNIA)HBA_PORTSTATE_BYPASSED 4 Bypassed */ +#define MPI_FCPORTPAGE0_PORTSTATE_DIAGNOST (0x05) /*(SNIA)HBA_PORTSTATE_DIAGNOSTICS 5 In diagnostics mode */ +#define MPI_FCPORTPAGE0_PORTSTATE_LINKDOWN (0x06) /*(SNIA)HBA_PORTSTATE_LINKDOWN 6 Link Down */ +#define MPI_FCPORTPAGE0_PORTSTATE_ERROR (0x07) /*(SNIA)HBA_PORTSTATE_ERROR 7 Port Error */ +#define MPI_FCPORTPAGE0_PORTSTATE_LOOPBACK (0x08) /*(SNIA)HBA_PORTSTATE_LOOPBACK 8 Loopback */ + +#define MPI_FCPORTPAGE0_SUPPORT_CLASS_1 (0x00000001) +#define MPI_FCPORTPAGE0_SUPPORT_CLASS_2 (0x00000002) +#define MPI_FCPORTPAGE0_SUPPORT_CLASS_3 (0x00000004) + +#define MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED (0x00000001) /* (SNIA)HBA_PORTSPEED_1GBIT 1 1 GBit/sec */ +#define MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED (0x00000002) /* (SNIA)HBA_PORTSPEED_2GBIT 2 2 GBit/sec */ +#define MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED (0x00000004) /* (SNIA)HBA_PORTSPEED_10GBIT 4 10 GBit/sec */ + +#define MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED +#define MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED +#define MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED + + +typedef struct _CONFIG_PAGE_FC_PORT_1 +{ + fCONFIG_PAGE_HEADER Header; + U32 Flags; + U64 NoSEEPROMWWNN; + U64 NoSEEPROMWWPN; + U8 HardALPA; + U8 LinkConfig; + U8 TopologyConfig; + U8 Reserved; +} fCONFIG_PAGE_FC_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_1, + FCPortPage1_t, MPI_POINTER pFCPortPage1_t; + +#define MPI_FCPORTPAGE1_PAGEVERSION (0x01) + +#define MPI_FCPORTPAGE1_FLAGS_SORT_BY_DID (0x00000001) +#define MPI_FCPORTPAGE1_FLAGS_SORT_BY_WWN (0x00000000) + +#define MPI_FCPORTPAGE1_FLAGS_PROT_MASK (0xF0000000) +#define MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT (28) +#define MPI_FCPORTPAGE1_FLAGS_PROT_FCP_INIT ((U32)MPI_PORTFACTS_PROTOCOL_INITIATOR << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT) +#define MPI_FCPORTPAGE1_FLAGS_PROT_FCP_TARG ((U32)MPI_PORTFACTS_PROTOCOL_TARGET << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT) +#define MPI_FCPORTPAGE1_FLAGS_PROT_LAN ((U32)MPI_PORTFACTS_PROTOCOL_LAN << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT) +#define MPI_FCPORTPAGE1_FLAGS_PROT_LOGBUSADDR ((U32)MPI_PORTFACTS_PROTOCOL_LOGBUSADDR << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT) + +#define MPI_FCPORTPAGE1_HARD_ALPA_NOT_USED (0xFF) + +#define MPI_FCPORTPAGE1_LCONFIG_SPEED_MASK (0x0F) +#define MPI_FCPORTPAGE1_LCONFIG_SPEED_1GIG (0x00) +#define MPI_FCPORTPAGE1_LCONFIG_SPEED_2GIG (0x01) +#define MPI_FCPORTPAGE1_LCONFIG_SPEED_4GIG (0x02) +#define MPI_FCPORTPAGE1_LCONFIG_SPEED_10GIG (0x03) +#define MPI_FCPORTPAGE1_LCONFIG_SPEED_AUTO (0x0F) + +#define MPI_FCPORTPAGE1_TOPOLGY_MASK (0x0F) +#define MPI_FCPORTPAGE1_TOPOLGY_NLPORT (0x01) +#define MPI_FCPORTPAGE1_TOPOLGY_NPORT (0x02) +#define MPI_FCPORTPAGE1_TOPOLGY_AUTO (0x0F) + + +typedef struct _CONFIG_PAGE_FC_PORT_2 +{ + fCONFIG_PAGE_HEADER Header; + U8 NumberActive; + U8 ALPA[126]; + U8 Reserved; +} fCONFIG_PAGE_FC_PORT_2, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_2, + FCPortPage2_t, MPI_POINTER pFCPortPage2_t; + +#define MPI_FCPORTPAGE2_PAGEVERSION (0x00) + + +typedef struct _FC_PORT_PERSISTENT +{ + U64 WWNN; + U64 WWPN; + U8 TargetID; + U8 Bus; + U16 Flags; +} FC_PORT_PERSISTENT, MPI_POINTER PTR_FC_PORT_PERSISTENT, + PersistentData_t, MPI_POINTER pPersistentData_t; + +#define MPI_PERSISTENT_FLAGS_SHIFT (16) +#define MPI_PERSISTENT_FLAGS_ENTRY_VALID (0x0001) +#define MPI_PERSISTENT_FLAGS_SCAN_ID (0x0002) +#define MPI_PERSISTENT_FLAGS_SCAN_LUNS (0x0004) +#define MPI_PERSISTENT_FLAGS_BOOT_DEVICE (0x0008) + +typedef struct _CONFIG_PAGE_FC_PORT_3 +{ + fCONFIG_PAGE_HEADER Header; + FC_PORT_PERSISTENT Entry[1]; +} fCONFIG_PAGE_FC_PORT_3, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_3, + FCPortPage3_t, MPI_POINTER pFCPortPage3_t; + +#define MPI_FCPORTPAGE3_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_FC_PORT_4 +{ + fCONFIG_PAGE_HEADER Header; + U32 PortFlags; + U32 PortSettings; +} fCONFIG_PAGE_FC_PORT_4, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_4, + FCPortPage4_t, MPI_POINTER pFCPortPage4_t; + +#define MPI_FCPORTPAGE4_PAGEVERSION (0x00) + +#define MPI_FCPORTPAGE4_PORT_FLAGS_ALTERNATE_CHS (0x00000008) + +#define MPI_FCPORTPAGE4_PORT_MASK_INIT_HBA (0x00000030) +#define MPI_FCPORTPAGE4_PORT_DISABLE_INIT_HBA (0x00000000) +#define MPI_FCPORTPAGE4_PORT_BIOS_INIT_HBA (0x00000010) +#define MPI_FCPORTPAGE4_PORT_OS_INIT_HBA (0x00000020) +#define MPI_FCPORTPAGE4_PORT_BIOS_OS_INIT_HBA (0x00000030) +#define MPI_FCPORTPAGE4_PORT_REMOVABLE_MEDIA (0x000000C0) +#define MPI_FCPORTPAGE4_PORT_SPINUP_DELAY_MASK (0x00000F00) + + +typedef struct _CONFIG_PAGE_FC_PORT_5_ALIAS_INFO +{ + U8 Flags; + U8 AliasAlpa; + U16 Reserved; + U64 AliasWWNN; + U64 AliasWWPN; +} fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5_ALIAS_INFO, + FcPortPage5AliasInfo_t, MPI_POINTER pFcPortPage5AliasInfo_t; + +typedef struct _CONFIG_PAGE_FC_PORT_5 +{ + fCONFIG_PAGE_HEADER Header; + fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO AliasInfo[1]; +} fCONFIG_PAGE_FC_PORT_5, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5, + FCPortPage5_t, MPI_POINTER pFCPortPage5_t; + +#define MPI_FCPORTPAGE5_PAGEVERSION (0x00) + +#define MPI_FCPORTPAGE5_FLAGS_ALIAS_ALPA_VALID (0x01) +#define MPI_FCPORTPAGE5_FLAGS_ALIAS_WWN_VALID (0x02) + + +typedef struct _CONFIG_PAGE_FC_PORT_6 +{ + fCONFIG_PAGE_HEADER Header; + U32 Reserved; + U64 TimeSinceReset; + U64 TxFrames; + U64 RxFrames; + U64 TxWords; + U64 RxWords; + U64 LipCount; + U64 NosCount; + U64 ErrorFrames; + U64 DumpedFrames; + U64 LinkFailureCount; + U64 LossOfSyncCount; + U64 LossOfSignalCount; + U64 PrimativeSeqErrCount; + U64 InvalidTxWordCount; + U64 InvalidCrcCount; + U64 FcpInitiatorIoCount; +} fCONFIG_PAGE_FC_PORT_6, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_6, + FCPortPage6_t, MPI_POINTER pFCPortPage6_t; + +#define MPI_FCPORTPAGE6_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_FC_PORT_7 +{ + fCONFIG_PAGE_HEADER Header; + U32 Reserved; + U8 PortSymbolicName[256]; +} fCONFIG_PAGE_FC_PORT_7, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_7, + FCPortPage7_t, MPI_POINTER pFCPortPage7_t; + +#define MPI_FCPORTPAGE7_PAGEVERSION (0x00) + + +/****************************************************************************/ +/* FC Device Config Pages */ +/****************************************************************************/ + +typedef struct _CONFIG_PAGE_FC_DEVICE_0 +{ + fCONFIG_PAGE_HEADER Header; + U64 WWNN; + U64 WWPN; + U32 PortIdentifier; + U8 Protocol; + U8 Flags; + U16 BBCredit; + U16 MaxRxFrameSize; + U8 Reserved1; + U8 PortNumber; + U8 FcPhLowestVersion; + U8 FcPhHighestVersion; + U8 CurrentTargetID; + U8 CurrentBus; +} fCONFIG_PAGE_FC_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_FC_DEVICE_0, + FCDevicePage0_t, MPI_POINTER pFCDevicePage0_t; + +#define MPI_FC_DEVICE_PAGE0_PAGEVERSION (0x02) + +#define MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID (0x01) + +#define MPI_FC_DEVICE_PAGE0_PROT_IP (0x01) +#define MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET (0x02) +#define MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR (0x04) + +#define MPI_FC_DEVICE_PAGE0_PGAD_PORT_MASK (MPI_FC_DEVICE_PGAD_PORT_MASK) +#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_MASK (MPI_FC_DEVICE_PGAD_FORM_MASK) +#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_NEXT_DID (MPI_FC_DEVICE_PGAD_FORM_NEXT_DID) +#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_BUS_TID (MPI_FC_DEVICE_PGAD_FORM_BUS_TID) +#define MPI_FC_DEVICE_PAGE0_PGAD_DID_MASK (MPI_FC_DEVICE_PGAD_ND_DID_MASK) +#define MPI_FC_DEVICE_PAGE0_PGAD_BUS_MASK (MPI_FC_DEVICE_PGAD_BT_BUS_MASK) +#define MPI_FC_DEVICE_PAGE0_PGAD_BUS_SHIFT (MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT) +#define MPI_FC_DEVICE_PAGE0_PGAD_TID_MASK (MPI_FC_DEVICE_PGAD_BT_TID_MASK) + + +/****************************************************************************/ +/* RAID Volume Config Pages */ +/****************************************************************************/ + +typedef struct _RAIDVOL2_EM_PHYS_ID +{ + U8 TargetID; + U8 Bus; + U8 IocNumber; + U8 PhysDiskNumber; + U8 Reserved[8]; + U8 PhysicalDiskIdentifier[16]; + U8 ProductId[16]; + U8 InfoOffset0; + U8 InfoSize0; + U8 InfoOffset1; + U8 InfoSize1; + U8 Info[32]; +} RAIDVOL2_EM_PHYS_ID, MPI_POINTER PTR_RAIDVOL2_EM_PHYS_ID, + RaidVol2EmPhysicalID_t, MPI_POINTER pRaidVol2EmPhysicalID_t; + +typedef struct _RAIDVOL2_EM_DISK_INFO +{ + U32 DiskStatus; + U32 DeviceSettings; + U16 ErrorCount; + U16 Reserved; + U8 ErrorCdbByte; + U8 ErrorSenseKey; + U8 ErrorASC; + U8 ErrorASCQ; + U16 SmartCount; + U8 SmartASC; + U8 SmartASCQ; +} RAIDVOL2_EM_DISK_INFO, MPI_POINTER PTR_RAIDVOL2_EM_DISK_INFO, + RaidVol2EmDiskInfo_t, MPI_POINTER pRaidVol2EmDiskInfo_t; + +/* RAID Volume 2 EM Physical Disk DiskStatus flags */ + +#define MPI_RAIDVOLPAGE2_PHYS_DISK_PRIMARY (0x00000001) +#define MPI_RAIDVOLPAGE2_PHYS_DISK_SECONDARY (0x00000002) +#define MPI_RAIDVOLPAGE2_PHYS_DISK_HOT_SPARE (0x00000004) +#define MPI_RAIDVOLPAGE2_PHYS_DISK_OUT_OF_SYNC (0x00000008) +#define MPI_RAIDVOLPAGE2_PHYS_DISK_OFFLINE (0x00000010) +#define MPI_RAIDVOLPAGE2_PHYS_DISK_NOT_RESPONDING (0x00000020) + +typedef struct _RAIDVOL2_EM_PHYSICAL_DISK +{ + RAIDVOL2_EM_PHYS_ID Id; + RAIDVOL2_EM_DISK_INFO Info; +} RAIDVOL2_EM_PHYSICAL_DISK, MPI_POINTER PTR_RAIDVOL2_EM_PHYSICAL_DISK, + RaidVol2EmPhysicalDisk_t, MPI_POINTER pRaidVol2EmPhysicalDisk_t; + +#define MPI_RAIDVOLPAGE2_MAX_DISKS (3) + +typedef struct _CONFIG_PAGE_RAID_VOL_2 +{ + fCONFIG_PAGE_HEADER Header; + U32 VolumeStatus; + U32 VolumeSettings; + U32 Reserved; + U64 MaxLba; + U32 BlockSize; + U8 InquirySize; + U8 NumPhysicalDisks; + U16 Reserved1; + U8 InquiryData[56]; + RAIDVOL2_EM_PHYSICAL_DISK EMPhysicalDisk[MPI_RAIDVOLPAGE2_MAX_DISKS]; +} fCONFIG_PAGE_RAID_VOL_2, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_2, + RaidVolumePage2_t, MPI_POINTER pRaidVolumePage2_t; + +#define MPI_RAIDVOLPAGE2_PAGEVERSION (0x00) + +/* RAID Volume Page 2 VolumeStatus defines */ + +#define MPI_RAIDVOLPAGE2_STATUS_ENABLED (0x00000001) +#define MPI_RAIDVOLPAGE2_STATUS_QUIESCED (0x00000002) +#define MPI_RAIDVOLPAGE2_STATUS_RESYNC_IN_PROGRESS (0x00000004) +#define MPI_RAIDVOLPAGE2_STATUS_DEGRADED (0x00000008) + +/* RAID Volume Page 2 VolumeSettings defines */ + +#define MPI_RAIDVOLPAGE2_SETTING_WRITE_CACHING_ENABLE (0x00000001) +#define MPI_RAIDVOLPAGE2_SETTING_OFFLINE_ON_SMART (0x00000002) +#define MPI_RAIDVOLPAGE2_SETTING_AUTO_CONFIGURE (0x00000004) + + +/****************************************************************************/ +/* LAN Config Pages */ +/****************************************************************************/ + +typedef struct _CONFIG_PAGE_LAN_0 +{ + ConfigPageHeader_t Header; + U16 TxRxModes; + U16 Reserved; + U32 PacketPrePad; +} fCONFIG_PAGE_LAN_0, MPI_POINTER PTR_CONFIG_PAGE_LAN_0, + LANPage0_t, MPI_POINTER pLANPage0_t; + +#define MPI_LAN_PAGE0_PAGEVERSION (0x01) + +#define MPI_LAN_PAGE0_RETURN_LOOPBACK (0x0000) +#define MPI_LAN_PAGE0_SUPPRESS_LOOPBACK (0x0001) +#define MPI_LAN_PAGE0_LOOPBACK_MASK (0x0001) + +typedef struct _CONFIG_PAGE_LAN_1 +{ + ConfigPageHeader_t Header; + U16 Reserved; + U8 CurrentDeviceState; + U8 Reserved1; + U32 MinPacketSize; + U32 MaxPacketSize; + U32 HardwareAddressLow; + U32 HardwareAddressHigh; + U32 MaxWireSpeedLow; + U32 MaxWireSpeedHigh; + U32 BucketsRemaining; + U32 MaxReplySize; + U32 NegWireSpeedHigh; + U32 NegWireSpeedLow; +} fCONFIG_PAGE_LAN_1, MPI_POINTER PTR_CONFIG_PAGE_LAN_1, + LANPage1_t, MPI_POINTER pLANPage1_t; + +#define MPI_LAN_PAGE1_PAGEVERSION (0x03) + +#define MPI_LAN_PAGE1_DEV_STATE_RESET (0x00) +#define MPI_LAN_PAGE1_DEV_STATE_OPERATIONAL (0x01) + +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/lsi/mpi_fc.h linux.ac/drivers/message/fusion/lsi/mpi_fc.h --- linux.vanilla/drivers/message/fusion/lsi/mpi_fc.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/lsi/mpi_fc.h Tue Apr 3 23:12:52 2001 @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2000-2001 LSI Logic Corporation. + * + * + * Name: MPI_FC.H + * Title: MPI Fibre Channel messages and structures + * Creation Date: June 12, 2000 + * + * MPI Version: 01.01.05 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 06-12-00 01.00.02 Added _MSG_FC_ABORT_REPLY structure. + * 11-02-00 01.01.01 Original release for post 1.0 work + * 12-04-00 01.01.02 Added messages for Common Transport Send and + * Primitive Send. + * 01-09-01 01.01.03 Modifed some of the new flags to have an MPI prefix + * and modified the FcPrimitiveSend flags. + * 01-25-01 01.01.04 Move InitiatorIndex in LinkServiceRsp reply to a larger + * field. + * Added FC_ABORT_TYPE_CT_SEND_REQUEST and + * FC_ABORT_TYPE_EXLINKSEND_REQUEST for FcAbort request. + * Added MPI_FC_PRIM_SEND_FLAGS_STOP_SEND. + * 02-20-01 01.01.05 Started using MPI_POINTER. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_FC_H +#define MPI_FC_H + + +/***************************************************************************** +* +* F C T a r g e t M o d e M e s s a g e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* Link Service Buffer Post messages */ +/****************************************************************************/ + +typedef struct _MSG_LINK_SERVICE_BUFFER_POST_REQUEST +{ + U8 BufferPostFlags; /* 00h */ + U8 BufferCount; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved; /* 04h */ + U8 Reserved1; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + SGE_TRANS_SIMPLE_UNION SGL; +} MSG_LINK_SERVICE_BUFFER_POST_REQUEST, + MPI_POINTER PTR_MSG_LINK_SERVICE_BUFFER_POST_REQUEST, + LinkServiceBufferPostRequest_t, MPI_POINTER pLinkServiceBufferPostRequest_t; + +#define LINK_SERVICE_BUFFER_POST_FLAGS_PORT_MASK (0x01) + +typedef struct _WWNFORMAT +{ + U32 PortNameHigh; /* 00h */ + U32 PortNameLow; /* 04h */ + U32 NodeNameHigh; /* 08h */ + U32 NodeNameLow; /* 0Ch */ +} WWNFORMAT, + WwnFormat_t; + +/* Link Service Buffer Post Reply */ +typedef struct _MSG_LINK_SERVICE_BUFFER_POST_REPLY +{ + U8 Flags; /* 00h */ + U8 Reserved; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 PortNumber; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved2; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 TransferLength; /* 14h */ + U32 TransactionContext; /* 18h */ + U32 Rctl_Did; /* 1Ch */ + U32 Csctl_Sid; /* 20h */ + U32 Type_Fctl; /* 24h */ + U16 SeqCnt; /* 28h */ + U8 Dfctl; /* 2Ah */ + U8 SeqId; /* 2Bh */ + U16 Rxid; /* 2Ch */ + U16 Oxid; /* 2Eh */ + U32 Parameter; /* 30h */ + WWNFORMAT Wwn; /* 34h */ +} MSG_LINK_SERVICE_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_LINK_SERVICE_BUFFER_POST_REPLY, + LinkServiceBufferPostReply_t, MPI_POINTER pLinkServiceBufferPostReply_t; + +#define MPI_LS_BUF_POST_REPLY_FLAG_NO_RSP_NEEDED (0x80) + +#define MPI_FC_DID_MASK (0x00FFFFFF) +#define MPI_FC_DID_SHIFT (0) +#define MPI_FC_RCTL_MASK (0xFF000000) +#define MPI_FC_RCTL_SHIFT (24) +#define MPI_FC_SID_MASK (0x00FFFFFF) +#define MPI_FC_SID_SHIFT (0) +#define MPI_FC_CSCTL_MASK (0xFF000000) +#define MPI_FC_CSCTL_SHIFT (24) +#define MPI_FC_FCTL_MASK (0x00FFFFFF) +#define MPI_FC_FCTL_SHIFT (0) +#define MPI_FC_TYPE_MASK (0xFF000000) +#define MPI_FC_TYPE_SHIFT (24) + +/* obsolete name for the above */ +#define FCP_TARGET_DID_MASK (0x00FFFFFF) +#define FCP_TARGET_DID_SHIFT (0) +#define FCP_TARGET_RCTL_MASK (0xFF000000) +#define FCP_TARGET_RCTL_SHIFT (24) +#define FCP_TARGET_SID_MASK (0x00FFFFFF) +#define FCP_TARGET_SID_SHIFT (0) +#define FCP_TARGET_CSCTL_MASK (0xFF000000) +#define FCP_TARGET_CSCTL_SHIFT (24) +#define FCP_TARGET_FCTL_MASK (0x00FFFFFF) +#define FCP_TARGET_FCTL_SHIFT (0) +#define FCP_TARGET_TYPE_MASK (0xFF000000) +#define FCP_TARGET_TYPE_SHIFT (24) + + +/****************************************************************************/ +/* Link Service Response messages */ +/****************************************************************************/ + +typedef struct _MSG_LINK_SERVICE_RSP_REQUEST +{ + U8 RspFlags; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Rctl_Did; /* 0Ch */ + U32 Csctl_Sid; /* 10h */ + U32 Type_Fctl; /* 14h */ + U16 SeqCnt; /* 18h */ + U8 Dfctl; /* 1Ah */ + U8 SeqId; /* 1Bh */ + U16 Rxid; /* 1Ch */ + U16 Oxid; /* 1Eh */ + U32 Parameter; /* 20h */ + SGE_SIMPLE_UNION SGL; /* 24h */ +} MSG_LINK_SERVICE_RSP_REQUEST, MPI_POINTER PTR_MSG_LINK_SERVICE_RSP_REQUEST, + LinkServiceRspRequest_t, MPI_POINTER pLinkServiceRspRequest_t; + +#define LINK_SERVICE_RSP_FLAGS_IMMEDIATE (0x80) +#define LINK_SERVICE_RSP_FLAGS_PORT_MASK (0x01) + + +/* Link Service Response Reply */ +typedef struct _MSG_LINK_SERVICE_RSP_REPLY +{ + U16 Reserved; /* 00h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved3; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 InitiatorIndex; /* 14h */ +} MSG_LINK_SERVICE_RSP_REPLY, MPI_POINTER PTR_MSG_LINK_SERVICE_RSP_REPLY, + LinkServiceRspReply_t, MPI_POINTER pLinkServiceRspReply_t; + + +/****************************************************************************/ +/* Extended Link Service Send messages */ +/****************************************************************************/ + +typedef struct _MSG_EXLINK_SERVICE_SEND_REQUEST +{ + U8 SendFlags; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U32 MsgFlags_Did; /* 04h */ + U32 MsgContext; /* 08h */ + U32 ElsCommandCode; /* 0Ch */ + SGE_SIMPLE_UNION SGL; /* 10h */ +} MSG_EXLINK_SERVICE_SEND_REQUEST, MPI_POINTER PTR_MSG_EXLINK_SERVICE_SEND_REQUEST, + ExLinkServiceSendRequest_t, MPI_POINTER pExLinkServiceSendRequest_t; + +#define EX_LINK_SERVICE_SEND_DID_MASK (0x00FFFFFF) +#define EX_LINK_SERVICE_SEND_DID_SHIFT (0) +#define EX_LINK_SERVICE_SEND_MSGFLAGS_MASK (0xFF000000) +#define EX_LINK_SERVICE_SEND_MSGFLAGS_SHIFT (24) + + +/* Extended Link Service Send Reply */ +typedef struct _MSG_EXLINK_SERVICE_SEND_REPLY +{ + U16 Reserved; /* 00h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved3; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 ResponseLength; /* 14h */ +} MSG_EXLINK_SERVICE_SEND_REPLY, MPI_POINTER PTR_MSG_EXLINK_SERVICE_SEND_REPLY, + ExLinkServiceSendReply_t, MPI_POINTER pExLinkServiceSendReply_t; + +/****************************************************************************/ +/* FC Abort messages */ +/****************************************************************************/ + +typedef struct _MSG_FC_ABORT_REQUEST +{ + U8 AbortFlags; /* 00h */ + U8 AbortType; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 TransactionContextToAbort; /* 0Ch */ +} MSG_FC_ABORT_REQUEST, MPI_POINTER PTR_MSG_FC_ABORT_REQUEST, + FcAbortRequest_t, MPI_POINTER pFcAbortRequest_t; + +#define FC_ABORT_FLAG_PORT_MASK (0x01) + +#define FC_ABORT_TYPE_ALL_FC_BUFFERS (0x00) +#define FC_ABORT_TYPE_EXACT_FC_BUFFER (0x01) +#define FC_ABORT_TYPE_CT_SEND_REQUEST (0x02) +#define FC_ABORT_TYPE_EXLINKSEND_REQUEST (0x03) + +/* FC Abort Reply */ +typedef struct _MSG_FC_ABORT_REPLY +{ + U16 Reserved; /* 00h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved3; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ +} MSG_FC_ABORT_REPLY, MPI_POINTER PTR_MSG_FC_ABORT_REPLY, + FcAbortReply_t, MPI_POINTER pFcAbortReply_t; + + +/****************************************************************************/ +/* FC Common Transport Send messages */ +/****************************************************************************/ + +typedef struct _MSG_FC_COMMON_TRANSPORT_SEND_REQUEST +{ + U8 SendFlags; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U32 MsgFlags_Did; /* 04h */ + U32 MsgContext; /* 08h */ + U16 CTCommandCode; /* 0Ch */ + U8 FsType; /* 0Eh */ + U8 Reserved1; /* 0Fh */ + SGE_SIMPLE_UNION SGL; /* 10h */ +} MSG_FC_COMMON_TRANSPORT_SEND_REQUEST, + MPI_POINTER PTR_MSG_FC_COMMON_TRANSPORT_SEND_REQUEST, + FcCommonTransportSendRequest_t, MPI_POINTER pFcCommonTransportSendRequest_t; + +#define MPI_FC_CT_SEND_DID_MASK (0x00FFFFFF) +#define MPI_FC_CT_SEND_DID_SHIFT (0) +#define MPI_FC_CT_SEND_MSGFLAGS_MASK (0xFF000000) +#define MPI_FC_CT_SEND_MSGFLAGS_SHIFT (24) + + +/* FC Common Transport Send Reply */ +typedef struct _MSG_FC_COMMON_TRANSPORT_SEND_REPLY +{ + U16 Reserved; /* 00h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved3; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 ResponseLength; /* 14h */ +} MSG_FC_COMMON_TRANSPORT_SEND_REPLY, MPI_POINTER PTR_MSG_FC_COMMON_TRANSPORT_SEND_REPLY, + FcCommonTransportSendReply_t, MPI_POINTER pFcCommonTransportSendReply_t; + + +/****************************************************************************/ +/* FC Primitive Send messages */ +/****************************************************************************/ + +typedef struct _MSG_FC_PRIMITIVE_SEND_REQUEST +{ + U8 SendFlags; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 FcPrimitive[4]; /* 0Ch */ +} MSG_FC_PRIMITIVE_SEND_REQUEST, MPI_POINTER PTR_MSG_FC_PRIMITIVE_SEND_REQUEST, + FcPrimitiveSendRequest_t, MPI_POINTER pFcPrimitiveSendRequest_t; + +#define MPI_FC_PRIM_SEND_FLAGS_PORT_MASK (0x01) +#define MPI_FC_PRIM_SEND_FLAGS_STOP_SEND (0x08) +#define MPI_FC_PRIM_SEND_FLAGS_SEND_ONCE (0x10) +#define MPI_FC_PRIM_SEND_FLAGS_SEND_AROUND (0x20) +#define MPI_FC_PRIM_SEND_FLAGS_UNTIL_FULL (0x40) +#define MPI_FC_PRIM_SEND_FLAGS_FOREVER (0x80) + +/* FC Primitive Send Reply */ +typedef struct _MSG_FC_PRIMITIVE_SEND_REPLY +{ + U8 SendFlags; /* 00h */ + U8 Reserved; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved3; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ +} MSG_FC_PRIMITIVE_SEND_REPLY, MPI_POINTER PTR_MSG_FC_PRIMITIVE_SEND_REPLY, + FcPrimitiveSendReply_t, MPI_POINTER pFcPrimitiveSendReply_t; + +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/lsi/mpi_history.txt linux.ac/drivers/message/fusion/lsi/mpi_history.txt --- linux.vanilla/drivers/message/fusion/lsi/mpi_history.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/lsi/mpi_history.txt Tue Apr 3 17:54:47 2001 @@ -0,0 +1,237 @@ + + ============================== + MPI Header File Change History + ============================== + + Copyright (c) 2000-2001 LSI Logic Corporation. + + --------------------------------------- + Header Set Release Version: 01.01.08 + Header Set Release Date: 02-27-01 + --------------------------------------- + + Filename Current version Prior version + ---------- --------------- ------------- + mpi.h 01.01.06 01.01.05 + mpi_ioc.h 01.01.05 01.01.04 + mpi_cnfg.h 01.01.09 01.01.08 + mpi_init.h 01.01.03 01.01.03 + mpi_targ.h 01.01.03 01.01.03 + mpi_fc.h 01.01.05 01.01.05 + mpi_lan.h 01.01.02 01.01.02 + mpi_raid.h 01.01.01 none + mpi_type.h 01.01.02 01.01.02 + mpi_history.txt 01.01.08 01.01.07 + + + * Date Version Description + * -------- -------- ------------------------------------------------------ + +mpi.h + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 05-24-00 00.10.02 Added MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH definition. + * 06-06-00 01.00.01 Update MPI_VERSION_MAJOR and MPI_VERSION_MINOR. + * 06-22-00 01.00.02 Added MPI_IOCSTATUS_LAN_ definitions. + * Removed LAN_SUSPEND function definition. + * Added MPI_MSGFLAGS_CONTINUATION_REPLY definition. + * 06-30-00 01.00.03 Added MPI_CONTEXT_REPLY_TYPE_LAN definition. + * Added MPI_GET/SET_CONTEXT_REPLY_TYPE macros. + * 07-27-00 01.00.04 Added MPI_FAULT_ definitions. + * Removed MPI_IOCSTATUS_MSG/DATA_XFER_ERROR definitions. + * Added MPI_IOCSTATUS_INTERNAL_ERROR definition. + * Added MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH. + * 11-02-00 01.01.01 Original release for post 1.0 work + * 12-04-00 01.01.02 Added new function codes. + * 01-09-01 01.01.03 Added more definitions to the system interface section + * Added MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT. + * 01-25-01 01.01.04 Changed MPI_VERSION_MINOR from 0x00 to 0x01. + * 02-20-01 01.01.05 Started using MPI_POINTER. + * Added defines for MPI_DIAG_PREVENT_IOC_BOOT and + * MPI_DIAG_CLEAR_FLASH_BAD_SIG. + * Obsoleted MPI_IOCSTATUS_TARGET_FC_ defines. + * 02-27-01 01.01.06 Removed MPI_HOST_INDEX_REGISTER define. + * Added function codes for RAID. + * -------------------------------------------------------------------------- + +mpi_ioc.h + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 05-24-00 00.10.02 Added _MSG_IOC_INIT_REPLY structure. + * 06-06-00 01.00.01 Added CurReplyFrameSize field to _MSG_IOC_FACTS_REPLY. + * 06-12-00 01.00.02 Added _MSG_PORT_ENABLE_REPLY structure. + * Added _MSG_EVENT_ACK_REPLY structure. + * Added _MSG_FW_DOWNLOAD_REPLY structure. + * Added _MSG_TOOLBOX_REPLY structure. + * 06-30-00 01.00.03 Added MaxLanBuckets to _PORT_FACT_REPLY structure. + * 07-27-00 01.00.04 Added _EVENT_DATA structure definitions for _SCSI, + * _LINK_STATUS, _LOOP_STATE and _LOGOUT. + * 08-11-00 01.00.05 Switched positions of MsgLength and Function fields in + * _MSG_EVENT_ACK_REPLY structure to match specification. + * 11-02-00 01.01.01 Original release for post 1.0 work + * Added a value for Manufacturer to WhoInit + * 12-04-00 01.01.02 Modified IOCFacts reply, added FWUpload messages, and + * removed toolbox message. + * 01-09-01 01.01.03 Added event enabled and disabled defines. + * Added structures for FwHeader and DataHeader. + * Added ImageType to FwUpload reply. + * 02-20-01 01.01.04 Started using MPI_POINTER. + * 02-27-01 01.01.05 Added event for RAID status change and its event data. + * Added IocNumber field to MSG_IOC_FACTS_REPLY. + * -------------------------------------------------------------------------- + +mpi_cnfg.h + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 06-08-00 01.00.02 Added _PAGEVERSION definitions for all pages. + * Added FcPhLowestVersion, FcPhHighestVersion, Reserved2 + * fields to FC_DEVICE_0 page, updated the page version. + * Changed _FREE_RUNNING_CLOCK to _PACING_TRANSFERS in + * SCSI_PORT_0, SCSI_DEVICE_0 and SCSI_DEVICE_1 pages + * and updated the page versions. + * Added _RESPONSE_ID_MASK definition to SCSI_PORT_1 + * page and updated the page version. + * Added Information field and _INFO_PARAMS_NEGOTIATED + * definitionto SCSI_DEVICE_0 page. + * 06-22-00 01.00.03 Removed batch controls from LAN_0 page and updated the + * page version. + * Added BucketsRemaining to LAN_1 page, redefined the + * state values, and updated the page version. + * Revised bus width definitions in SCSI_PORT_0, + * SCSI_DEVICE_0 and SCSI_DEVICE_1 pages. + * 06-30-00 01.00.04 Added MaxReplySize to LAN_1 page and updated the page + * version. + * Moved FC_DEVICE_0 PageAddress description to spec. + * 07-27-00 01.00.05 Corrected the SubsystemVendorID and SubsystemID field + * widths in IOC_0 page and updated the page version. + * 11-02-00 01.01.01 Original release for post 1.0 work + * Added Manufacturing pages, IO Unit Page 2, SCSI SPI + * Port Page 2, FC Port Page 4, FC Port Page 5 + * 12-04-00 01.01.03 Config page changes to match MPI rev 1.00.01. + * 12-05-00 01.01.04 Modified config page actions. + * 01-09-01 01.01.05 Added defines for page address formats. + * Data size for Manufacturing pages 2 and 3 no longer + * defined here. + * Io Unit Page 2 size is fixed at 4 adapters and some + * flags were changed. + * SCSI Port Page 2 Device Settings modified. + * New fields added to FC Port Page 0 and some flags + * cleaned up. + * Removed impedance flash from FC Port Page 1. + * Added FC Port pages 6 and 7. + * 01-25-01 01.01.06 Added MaxInitiators field to FcPortPage0. + * 01-29-01 01.01.07 Changed some defines to make them 32 character unique. + * Added some LinkType defines for FcPortPage0. + * 02-20-01 01.01.08 Started using MPI_POINTER. + * 02-27-01 01.01.09 Replaced MPI_CONFIG_PAGETYPE_SCSI_LUN with + * MPI_CONFIG_PAGETYPE_RAID_VOLUME. + * Added definitions and structures for IOC Page 2 and + * RAID Volume Page 2. + * -------------------------------------------------------------------------- + +mpi_init.h + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 05-24-00 00.10.02 Added SenseBufferLength to _MSG_SCSI_IO_REPLY. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 06-08-00 01.00.02 Added MPI_SCSI_RSP_INFO_ definitions. + * 11-02-00 01.01.01 Original release for post 1.0 work + * 12-04-00 01.01.02 Added MPI_SCSIIO_CONTROL_NO_DISCONNECT. + * 02-20-01 01.01.03 Started using MPI_POINTER. + * -------------------------------------------------------------------------- + +mpi_targ.h + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 06-22-00 01.00.02 Added _MSG_TARGET_CMD_BUFFER_POST_REPLY structure. + * Corrected DECSRIPTOR typo to DESCRIPTOR. + * 11-02-00 01.01.01 Original release for post 1.0 work + * Modified target mode to use IoIndex instead of + * HostIndex and IocIndex. Added Alias. + * 01-09-01 01.01.02 Added defines for TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER + * and TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER. + * 02-20-01 01.01.03 Started using MPI_POINTER. + * Added structures for MPI_TARGET_SCSI_SPI_CMD_BUFFER and + * MPI_TARGET_FCP_CMD_BUFFER. + * -------------------------------------------------------------------------- + +mpi_fc.h + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 06-12-00 01.00.02 Added _MSG_FC_ABORT_REPLY structure. + * 11-02-00 01.01.01 Original release for post 1.0 work + * 12-04-00 01.01.02 Added messages for Common Transport Send and + * Primitive Send. + * 01-09-01 01.01.03 Modifed some of the new flags to have an MPI prefix + * and modified the FcPrimitiveSend flags. + * 01-25-01 01.01.04 Move InitiatorIndex in LinkServiceRsp reply to a larger + * field. + * Added FC_ABORT_TYPE_CT_SEND_REQUEST and + * FC_ABORT_TYPE_EXLINKSEND_REQUEST for FcAbort request. + * Added MPI_FC_PRIM_SEND_FLAGS_STOP_SEND. + * 02-20-01 01.01.05 Started using MPI_POINTER. + * -------------------------------------------------------------------------- + +mpi_lan.h + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 05-24-00 00.10.02 Added LANStatus field to _MSG_LAN_SEND_REPLY. + * Added LANStatus field to _MSG_LAN_RECEIVE_POST_REPLY. + * Moved ListCount field in _MSG_LAN_RECEIVE_POST_REPLY. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 06-12-00 01.00.02 Added MPI_ to BUCKETSTATUS_ definitions. + * 06-22-00 01.00.03 Major changes to match new LAN definition in 1.0 spec. + * 06-30-00 01.00.04 Added Context Reply definitions per revised proposal. + * Changed transaction context usage to bucket/buffer. + * 07-05-00 01.00.05 Removed LAN_RECEIVE_POST_BUCKET_CONTEXT_MASK definition + * to lan private header file + * 11-02-00 01.01.01 Original release for post 1.0 work + * 02-20-01 01.01.02 Started using MPI_POINTER. + * -------------------------------------------------------------------------- + +mpi_raid.h + * 02-27-01 01.01.01 Original release for this file. + * -------------------------------------------------------------------------- + +mpi_type.h + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 11-02-00 01.01.01 Original release for post 1.0 work + * 02-20-01 01.01.02 Added define and ifdef for MPI_POINTER. + * -------------------------------------------------------------------------- + +mpi_history.txt Parts list history + +Filename 01.01.08 01.01.07 01.01.06 01.01.05 01.01.04 +---------- -------- -------- -------- -------- -------- +mpi.h 01.01.06 01.01.05 01.01.04 01.01.04 01.01.03 +mpi_ioc.h 01.01.05 01.01.04 01.01.03 01.01.03 01.01.03 +mpi_cnfg.h 01.01.09 01.01.08 01.01.07 01.01.06 01.01.05 +mpi_init.h 01.01.03 01.01.03 01.01.02 01.01.02 01.01.02 +mpi_targ.h 01.01.03 01.01.03 01.01.02 01.01.02 01.01.02 +mpi_fc.h 01.01.05 01.01.05 01.01.04 01.01.04 01.01.03 +mpi_lan.h 01.01.02 01.01.02 01.01.01 01.01.01 01.01.01 +mpi_raid.h 01.01.01 +mpi_type.h 01.01.02 01.01.02 01.01.01 01.01.01 01.01.01 + +Filename 01.01.03 01.01.02 01.01.01 01.00.07 01.00.06 01.00.05 +---------- -------- -------- -------- -------- -------- -------- +mpi.h 01.01.02 01.01.02 01.01.01 01.00.04 01.00.04 01.00.03 +mpi_ioc.h 01.01.02 01.01.02 01.01.01 01.00.05 01.00.04 01.00.03 +mpi_cnfg.h 01.01.04 01.01.03 01.01.01 01.00.05 01.00.05 01.00.04 +mpi_init.h 01.01.02 01.01.02 01.01.01 01.00.02 01.00.02 01.00.02 +mpi_targ.h 01.01.01 01.01.01 01.01.01 01.00.02 01.00.02 01.00.02 +mpi_fc.h 01.01.02 01.01.02 01.01.01 01.00.02 01.00.02 01.00.02 +mpi_lan.h 01.01.01 01.01.01 01.01.01 01.00.05 01.00.05 01.00.05 +mpi_type.h 01.01.01 01.01.01 01.01.01 01.00.01 01.00.01 01.00.01 + +Filename 01.00.04 01.00.03 01.00.02 01.00.01 00.10.02 00.10.01 +---------- -------- -------- -------- -------- -------- -------- +mpi.h 01.00.02 01.00.01 01.00.01 01.00.01 00.10.02 00.10.01 +mpi_ioc.h 01.00.02 01.00.02 01.00.01 01.00.01 00.10.02 00.10.01 +mpi_cnfg.h 01.00.03 01.00.02 01.00.02 01.00.01 00.10.01 00.10.01 +mpi_init.h 01.00.02 01.00.02 01.00.02 01.00.01 00.10.02 00.10.01 +mpi_targ.h 01.00.02 01.00.01 01.00.01 01.00.01 00.10.01 00.10.01 +mpi_fc.h 01.00.02 01.00.02 01.00.01 01.00.01 00.10.01 00.10.01 +mpi_lan.h 01.00.03 01.00.02 01.00.01 01.00.01 00.10.02 00.10.01 +mpi_type.h 01.00.01 01.00.01 01.00.01 01.00.01 00.10.01 00.10.01 + + + * -------------------------------------------------------------------------- + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/lsi/mpi_init.h linux.ac/drivers/message/fusion/lsi/mpi_init.h --- linux.vanilla/drivers/message/fusion/lsi/mpi_init.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/lsi/mpi_init.h Tue Apr 3 17:54:47 2001 @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2000-2001 LSI Logic Corporation. + * + * + * Name: MPI_INIT.H + * Title: MPI initiator mode messages and structures + * Creation Date: June 8, 2000 + * + * MPI Version: 01.01.03 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 05-24-00 00.10.02 Added SenseBufferLength to _MSG_SCSI_IO_REPLY. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 06-08-00 01.00.02 Added MPI_SCSI_RSP_INFO_ definitions. + * 11-02-00 01.01.01 Original release for post 1.0 work. + * 12-04-00 01.01.02 Added MPI_SCSIIO_CONTROL_NO_DISCONNECT. + * 02-20-01 01.01.03 Started using MPI_POINTER. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_INIT_H +#define MPI_INIT_H + + +/***************************************************************************** +* +* S C S I I n i t i a t o r M e s s a g e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* SCSI IO messages and assocaited structures */ +/****************************************************************************/ + +typedef struct _MSG_SCSI_IO_REQUEST +{ + U8 TargetID; + U8 Bus; + U8 ChainOffset; + U8 Function; + U8 CDBLength; + U8 SenseBufferLength; + U8 Reserved; + U8 MsgFlags; + U32 MsgContext; + U8 LUN[8]; + U32 Control; + U8 CDB[16]; + U32 DataLength; + U32 SenseBufferLowAddr; + SGE_IO_UNION SGL; +} MSG_SCSI_IO_REQUEST, MPI_POINTER PTR_MSG_SCSI_IO_REQUEST, + SCSIIORequest_t, MPI_POINTER pSCSIIORequest_t; + + +/* SCSIO MsgFlags bits */ + +#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH (0x01) +#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32 (0x00) +#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 (0x01) +#define MPI_SCSIIO_MSGFLGS_SENSE_LOCATION (0x02) +#define MPI_SCSIIO_MSGFLGS_SENSE_LOC_HOST (0x00) +#define MPI_SCSIIO_MSGFLGS_SENSE_LOC_IOC (0x02) + +/* SCSIIO LUN fields */ + +#define MPI_SCSIIO_LUN_FIRST_LEVEL_ADDRESSING (0x0000FFFF) +#define MPI_SCSIIO_LUN_SECOND_LEVEL_ADDRESSING (0xFFFF0000) +#define MPI_SCSIIO_LUN_THIRD_LEVEL_ADDRESSING (0x0000FFFF) +#define MPI_SCSIIO_LUN_FOURTH_LEVEL_ADDRESSING (0xFFFF0000) +#define MPI_SCSIIO_LUN_LEVEL_1_WORD (0xFF00) +#define MPI_SCSIIO_LUN_LEVEL_1_DWORD (0x0000FF00) + +/* SCSIO Control bits */ + +#define MPI_SCSIIO_CONTROL_DATADIRECTION_MASK (0x03000000) +#define MPI_SCSIIO_CONTROL_NODATATRANSFER (0x00000000) +#define MPI_SCSIIO_CONTROL_WRITE (0x01000000) +#define MPI_SCSIIO_CONTROL_READ (0x02000000) + +#define MPI_SCSIIO_CONTROL_ADDCDBLEN_MASK (0x3C000000) +#define MPI_SCSIIO_CONTROL_ADDCDBLEN_SHIFT (26) + +#define MPI_SCSIIO_CONTROL_TASKATTRIBUTE_MASK (0x00000700) +#define MPI_SCSIIO_CONTROL_SIMPLEQ (0x00000000) +#define MPI_SCSIIO_CONTROL_HEADOFQ (0x00000100) +#define MPI_SCSIIO_CONTROL_ORDEREDQ (0x00000200) +#define MPI_SCSIIO_CONTROL_ACAQ (0x00000400) +#define MPI_SCSIIO_CONTROL_UNTAGGED (0x00000500) +#define MPI_SCSIIO_CONTROL_NO_DISCONNECT (0x00000700) + +#define MPI_SCSIIO_CONTROL_TASKMANAGE_MASK (0x00FF0000) +#define MPI_SCSIIO_CONTROL_OBSOLETE (0x00800000) +#define MPI_SCSIIO_CONTROL_CLEAR_ACA_RSV (0x00400000) +#define MPI_SCSIIO_CONTROL_TARGET_RESET (0x00200000) +#define MPI_SCSIIO_CONTROL_LUN_RESET_RSV (0x00100000) +#define MPI_SCSIIO_CONTROL_RESERVED (0x00080000) +#define MPI_SCSIIO_CONTROL_CLR_TASK_SET_RSV (0x00040000) +#define MPI_SCSIIO_CONTROL_ABORT_TASK_SET (0x00020000) +#define MPI_SCSIIO_CONTROL_RESERVED2 (0x00010000) + + +/* SCSIIO reply structure */ +typedef struct _MSG_SCSI_IO_REPLY +{ + U8 TargetID; + U8 Bus; + U8 MsgLength; + U8 Function; + U8 CDBLength; + U8 SenseBufferLength; + U8 Reserved; + U8 MsgFlags; + U32 MsgContext; + U8 SCSIStatus; + U8 SCSIState; + U16 IOCStatus; + U32 IOCLogInfo; + U32 TransferCount; + U32 SenseCount; + U32 ResponseInfo; +} MSG_SCSI_IO_REPLY, MPI_POINTER PTR_MSG_SCSI_IO_REPLY, + SCSIIOReply_t, MPI_POINTER pSCSIIOReply_t; + + +/* SCSIIO Reply SCSIStatus values (SAM-2 status codes) */ + +#define MPI_SCSI_STATUS_SUCCESS (0x00) +#define MPI_SCSI_STATUS_CHECK_CONDITION (0x02) +#define MPI_SCSI_STATUS_CONDITION_MET (0x04) +#define MPI_SCSI_STATUS_BUSY (0x08) +#define MPI_SCSI_STATUS_INTERMEDIATE (0x10) +#define MPI_SCSI_STATUS_INTERMEDIATE_CONDMET (0x14) +#define MPI_SCSI_STATUS_RESERVATION_CONFLICT (0x18) +#define MPI_SCSI_STATUS_COMMAND_TERMINATED (0x22) +#define MPI_SCSI_STATUS_TASK_SET_FULL (0x28) +#define MPI_SCSI_STATUS_ACA_ACTIVE (0x30) + + +/* SCSIIO Reply SCSIState values */ + +#define MPI_SCSI_STATE_AUTOSENSE_VALID (0x01) +#define MPI_SCSI_STATE_AUTOSENSE_FAILED (0x02) +#define MPI_SCSI_STATE_NO_SCSI_STATUS (0x04) +#define MPI_SCSI_STATE_TERMINATED (0x08) +#define MPI_SCSI_STATE_RESPONSE_INFO_VALID (0x10) + +/* SCSIIO Reply ResponseInfo values */ +/* (FCP-1 RSP_CODE values and SPI-3 Packetized Failure codes) */ + +#define MPI_SCSI_RSP_INFO_FUNCTION_COMPLETE (0x00000000) +#define MPI_SCSI_RSP_INFO_FCP_BURST_LEN_ERROR (0x01000000) +#define MPI_SCSI_RSP_INFO_CMND_FIELDS_INVALID (0x02000000) +#define MPI_SCSI_RSP_INFO_FCP_DATA_RO_ERROR (0x03000000) +#define MPI_SCSI_RSP_INFO_TASK_MGMT_UNSUPPORTED (0x04000000) +#define MPI_SCSI_RSP_INFO_TASK_MGMT_FAILED (0x05000000) +#define MPI_SCSI_RSP_INFO_SPI_LQ_INVALID_TYPE (0x06000000) + + +/****************************************************************************/ +/* SCSI Task Management messages */ +/****************************************************************************/ + +typedef struct _MSG_SCSI_TASK_MGMT +{ + U8 TargetID; + U8 Bus; + U8 ChainOffset; + U8 Function; + U8 Reserved; + U8 TaskType; + U8 Reserved1; + U8 MsgFlags; + U32 MsgContext; + U8 LUN[8]; + U32 Reserved2[7]; + U32 TaskMsgContext; +} MSG_SCSI_TASK_MGMT, MPI_POINTER PTR_SCSI_TASK_MGMT, + SCSITaskMgmt_t, MPI_POINTER pSCSITaskMgmt_t; + +/* TaskType values */ + +#define MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x00000001) +#define MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x00000002) +#define MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x00000003) +#define MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS (0x00000004) + +/* MsgFlags bits */ +#define MPI_SCSITASKMGMT_MSGFLAGS_LIP_RESET_OPTION (0x00000002) + +/* SCSI Task Management Reply */ +typedef struct _MSG_SCSI_TASK_MGMT_REPLY +{ + U8 TargetID; + U8 Bus; + U8 MsgLength; + U8 Function; + U8 Reserved; + U8 TaskType; + U8 Reserved1; + U8 MsgFlags; + U32 MsgContext; + U8 Reserved2[2]; + U16 IOCStatus; + U32 IOCLogInfo; + U32 TerminationCount; +} MSG_SCSI_TASK_MGMT_REPLY, MPI_POINTER PTR_MSG_SCSI_TASK_MGMT_REPLY, + SCSITaskMgmtReply_t, MPI_POINTER pSCSITaskMgmtReply_t; + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/lsi/mpi_ioc.h linux.ac/drivers/message/fusion/lsi/mpi_ioc.h --- linux.vanilla/drivers/message/fusion/lsi/mpi_ioc.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/lsi/mpi_ioc.h Tue Apr 3 17:54:47 2001 @@ -0,0 +1,583 @@ +/* + * Copyright (c) 2000-2001 LSI Logic Corporation. + * + * + * Name: MPI_IOC.H + * Title: MPI IOC, Port, Event, FW Load, and ToolBox messages + * Creation Date: August 11, 2000 + * + * MPI Version: 01.01.05 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 05-24-00 00.10.02 Added _MSG_IOC_INIT_REPLY structure. + * 06-06-00 01.00.01 Added CurReplyFrameSize field to _MSG_IOC_FACTS_REPLY. + * 06-12-00 01.00.02 Added _MSG_PORT_ENABLE_REPLY structure. + * Added _MSG_EVENT_ACK_REPLY structure. + * Added _MSG_FW_DOWNLOAD_REPLY structure. + * Added _MSG_TOOLBOX_REPLY structure. + * 06-30-00 01.00.03 Added MaxLanBuckets to _PORT_FACT_REPLY structure. + * 07-27-00 01.00.04 Added _EVENT_DATA structure definitions for _SCSI, + * _LINK_STATUS, _LOOP_STATE and _LOGOUT. + * 08-11-00 01.00.05 Switched positions of MsgLength and Function fields in + * _MSG_EVENT_ACK_REPLY structure to match specification. + * 11-02-00 01.01.01 Original release for post 1.0 work. + * Added a value for Manufacturer to WhoInit. + * 12-04-00 01.01.02 Modified IOCFacts reply, added FWUpload messages, and + * removed toolbox message. + * 01-09-01 01.01.03 Added event enabled and disabled defines. + * Added structures for FwHeader and DataHeader. + * Added ImageType to FwUpload reply. + * 02-20-01 01.01.04 Started using MPI_POINTER. + * 02-27-01 01.01.05 Added event for RAID status change and its event data. + * Added IocNumber field to MSG_IOC_FACTS_REPLY. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_IOC_H +#define MPI_IOC_H + + +/***************************************************************************** +* +* I O C M e s s a g e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* IOCInit message */ +/****************************************************************************/ + +typedef struct _MSG_IOC_INIT +{ + U8 WhoInit; + U8 Reserved; + U8 ChainOffset; + U8 Function; + U8 Flags; + U8 MaxDevices; + U8 MaxBuses; + U8 MsgFlags; + U32 MsgContext; + U16 ReplyFrameSize; + U8 Reserved1[2]; + U32 HostMfaHighAddr; + U32 SenseBufferHighAddr; +} MSG_IOC_INIT, MPI_POINTER PTR_MSG_IOC_INIT, + IOCInit_t, MPI_POINTER pIOCInit_t; + +typedef struct _MSG_IOC_INIT_REPLY +{ + U8 WhoInit; + U8 Reserved; + U8 MsgLength; + U8 Function; + U8 Flags; + U8 MaxDevices; + U8 MaxBuses; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved2; + U16 IOCStatus; + U32 IOCLogInfo; +} MSG_IOC_INIT_REPLY, MPI_POINTER PTR_MSG_IOC_INIT_REPLY, + IOCInitReply_t, MPI_POINTER pIOCInitReply_t; + +/* WhoInit values */ + +#define MPI_WHOINIT_NO_ONE (0x00) +#define MPI_WHOINIT_SYSTEM_BIOS (0x01) +#define MPI_WHOINIT_ROM_BIOS (0x02) +#define MPI_WHOINIT_PCI_PEER (0x03) +#define MPI_WHOINIT_HOST_DRIVER (0x04) +#define MPI_WHOINIT_MANUFACTURER (0x05) + + +/****************************************************************************/ +/* IOC Facts message */ +/****************************************************************************/ + +typedef struct _MSG_IOC_FACTS +{ + U8 Reserved[2]; + U8 ChainOffset; + U8 Function; + U8 Reserved1[3]; + U8 MsgFlags; + U32 MsgContext; +} MSG_IOC_FACTS, MPI_POINTER PTR_IOC_FACTS, + IOCFacts_t, MPI_POINTER pIOCFacts_t; + +/* IOC Facts Reply */ + +typedef struct _MSG_IOC_FACTS_REPLY +{ + U16 MsgVersion; + U8 MsgLength; + U8 Function; + U16 Reserved; + U8 IOCNumber; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved2; + U16 IOCStatus; + U32 IOCLogInfo; + U8 MaxChainDepth; + U8 WhoInit; + U8 BlockSize; + U8 Flags; + U16 ReplyQueueDepth; + U16 RequestFrameSize; + U16 FWVersion; + U16 ProductID; + U32 CurrentHostMfaHighAddr; + U16 GlobalCredits; + U8 NumberOfPorts; + U8 EventState; + U32 CurrentSenseBufferHighAddr; + U16 CurReplyFrameSize; + U8 MaxDevices; + U8 MaxBuses; + U32 FWImageSize; + U32 DataImageSize; +} MSG_IOC_FACTS_REPLY, MPI_POINTER PTR_MSG_IOC_FACTS_REPLY, + IOCFactsReply_t, MPI_POINTER pIOCFactsReply_t; + +#define MPI_IOCFACTS_MSGVERSION_MAJOR_MASK (0xFF00) +#define MPI_IOCFACTS_MSGVERSION_MINOR_MASK (0x00FF) + +#define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT (0x01) +#define MPI_IOCFACTS_FLAGS_DATA_IMAGE_UPLOAD (0x02) + +#define MPI_IOCFACTS_EVENTSTATE_DISABLED (0x00) +#define MPI_IOCFACTS_EVENTSTATE_ENABLED (0x01) + + + +/***************************************************************************** +* +* P o r t M e s s a g e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* Port Facts message and Reply */ +/****************************************************************************/ + +typedef struct _MSG_PORT_FACTS +{ + U8 Reserved[2]; + U8 ChainOffset; + U8 Function; + U8 Reserved1[2]; + U8 PortNumber; + U8 MsgFlags; + U32 MsgContext; +} MSG_PORT_FACTS, MPI_POINTER PTR_MSG_PORT_FACTS, + PortFacts_t, MPI_POINTER pPortFacts_t; + +typedef struct _MSG_PORT_FACTS_REPLY +{ + U16 Reserved; + U8 MsgLength; + U8 Function; + U16 Reserved1; + U8 PortNumber; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved2; + U16 IOCStatus; + U32 IOCLogInfo; + U8 Reserved3; + U8 PortType; + U16 MaxDevices; + U16 PortSCSIID; + U16 ProtocolFlags; + U16 MaxPostedCmdBuffers; + U16 MaxPersistentIDs; + U16 MaxLanBuckets; + U16 Reserved4; + U32 Reserved5; +} MSG_PORT_FACTS_REPLY, MPI_POINTER PTR_MSG_PORT_FACTS_REPLY, + PortFactsReply_t, MPI_POINTER pPortFactsReply_t; + + +/* PortTypes values */ + +#define MPI_PORTFACTS_PORTTYPE_INACTIVE (0x00) +#define MPI_PORTFACTS_PORTTYPE_SCSI (0x01) +#define MPI_PORTFACTS_PORTTYPE_FC (0x10) + +/* ProtocolFlags values */ + +#define MPI_PORTFACTS_PROTOCOL_LOGBUSADDR (0x01) +#define MPI_PORTFACTS_PROTOCOL_LAN (0x02) +#define MPI_PORTFACTS_PROTOCOL_TARGET (0x04) +#define MPI_PORTFACTS_PROTOCOL_INITIATOR (0x08) + + +/****************************************************************************/ +/* Port Enable Message */ +/****************************************************************************/ + +typedef struct _MSG_PORT_ENABLE +{ + U8 Reserved[2]; + U8 ChainOffset; + U8 Function; + U8 Reserved1[2]; + U8 PortNumber; + U8 MsgFlags; + U32 MsgContext; +} MSG_PORT_ENABLE, MPI_POINTER PTR_MSG_PORT_ENABLE, + PortEnable_t, MPI_POINTER pPortEnable_t; + +typedef struct _MSG_PORT_ENABLE_REPLY +{ + U8 Reserved[2]; + U8 MsgLength; + U8 Function; + U8 Reserved1[2]; + U8 PortNumber; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved2; + U16 IOCStatus; + U32 IOCLogInfo; +} MSG_PORT_ENABLE_REPLY, MPI_POINTER PTR_MSG_PORT_ENABLE_REPLY, + PortEnableReply_t, MPI_POINTER pPortEnableReply_t; + + +/***************************************************************************** +* +* E v e n t M e s s a g e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* Event Notification messages */ +/****************************************************************************/ + +typedef struct _MSG_EVENT_NOTIFY +{ + U8 Switch; + U8 Reserved; + U8 ChainOffset; + U8 Function; + U8 Reserved1[3]; + U8 MsgFlags; + U32 MsgContext; +} MSG_EVENT_NOTIFY, MPI_POINTER PTR_MSG_EVENT_NOTIFY, + EventNotification_t, MPI_POINTER pEventNotification_t; + +/* Event Notification Reply */ + +typedef struct _MSG_EVENT_NOTIFY_REPLY +{ + U16 EventDataLength; + U8 MsgLength; + U8 Function; + U8 Reserved1[2]; + U8 AckRequired; + U8 MsgFlags; + U32 MsgContext; + U8 Reserved2[2]; + U16 IOCStatus; + U32 IOCLogInfo; + U32 Event; + U32 EventContext; + U32 Data[1]; +} MSG_EVENT_NOTIFY_REPLY, MPI_POINTER PTR_MSG_EVENT_NOTIFY_REPLY, + EventNotificationReply_t, MPI_POINTER pEventNotificationReply_t; + +/* Event Acknowledge */ + +typedef struct _MSG_EVENT_ACK +{ + U8 Reserved[2]; + U8 ChainOffset; + U8 Function; + U8 Reserved1[3]; + U8 MsgFlags; + U32 MsgContext; + U32 Event; + U32 EventContext; +} MSG_EVENT_ACK, MPI_POINTER PTR_MSG_EVENT_ACK, + EventAck_t, MPI_POINTER pEventAck_t; + +typedef struct _MSG_EVENT_ACK_REPLY +{ + U8 Reserved[2]; + U8 MsgLength; + U8 Function; + U8 Reserved1[3]; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved2; + U16 IOCStatus; + U32 IOCLogInfo; +} MSG_EVENT_ACK_REPLY, MPI_POINTER PTR_MSG_EVENT_ACK_REPLY, + EventAckReply_t, MPI_POINTER pEventAckReply_t; + + +/* Switch */ + +#define MPI_EVENT_NOTIFICATION_SWITCH_OFF (0x00) +#define MPI_EVENT_NOTIFICATION_SWITCH_ON (0x01) + +/* Event */ + +#define MPI_EVENT_NONE (0x00000000) +#define MPI_EVENT_LOG_DATA (0x00000001) +#define MPI_EVENT_STATE_CHANGE (0x00000002) +#define MPI_EVENT_UNIT_ATTENTION (0x00000003) +#define MPI_EVENT_IOC_BUS_RESET (0x00000004) +#define MPI_EVENT_EXT_BUS_RESET (0x00000005) +#define MPI_EVENT_RESCAN (0x00000006) +#define MPI_EVENT_LINK_STATUS_CHANGE (0x00000007) +#define MPI_EVENT_LOOP_STATE_CHANGE (0x00000008) +#define MPI_EVENT_LOGOUT (0x00000009) +#define MPI_EVENT_EVENT_CHANGE (0x0000000A) +#define MPI_EVENT_RAID_STATUS_CHANGE (0x0000000B) + +/* AckRequired field values */ + +#define MPI_EVENT_NOTIFICATION_ACK_NOT_REQUIRED (0x00) +#define MPI_EVENT_NOTIFICATION_ACK_REQUIRED (0x01) + +/* SCSI Event data for Port, Bus and Device forms) */ + +typedef struct _EVENT_DATA_SCSI +{ + U8 TargetID; + U8 BusPort; + U16 Reserved; +} EVENT_DATA_SCSI, MPI_POINTER PTR_EVENT_DATA_SCSI, + EventDataScsi_t, MPI_POINTER pEventDataScsi_t; + +/* MPI Link Status Change Event data */ + +typedef struct _EVENT_DATA_LINK_STATUS +{ + U8 State; + U8 Reserved; + U16 Reserved1; + U8 Reserved2; + U8 Port; + U16 Reserved3; +} EVENT_DATA_LINK_STATUS, MPI_POINTER PTR_EVENT_DATA_LINK_STATUS, + EventDataLinkStatus_t, MPI_POINTER pEventDataLinkStatus_t; + +#define MPI_EVENT_LINK_STATUS_FAILURE (0x00000000) +#define MPI_EVENT_LINK_STATUS_ACTIVE (0x00000001) + +/* MPI Loop State Change Event data */ + +typedef struct _EVENT_DATA_LOOP_STATE +{ + U8 Character4; + U8 Character3; + U8 Type; + U8 Reserved; + U8 Reserved1; + U8 Port; + U16 Reserved2; +} EVENT_DATA_LOOP_STATE, MPI_POINTER PTR_EVENT_DATA_LOOP_STATE, + EventDataLoopState_t, MPI_POINTER pEventDataLoopState_t; + +#define MPI_EVENT_LOOP_STATE_CHANGE_LIP (0x0001) +#define MPI_EVENT_LOOP_STATE_CHANGE_LPE (0x0002) +#define MPI_EVENT_LOOP_STATE_CHANGE_LPB (0x0003) + +/* MPI LOGOUT Event data */ + +typedef struct _EVENT_DATA_LOGOUT +{ + U32 NPortID; + U8 Reserved; + U8 Port; + U16 Reserved1; +} EVENT_DATA_LOGOUT, MPI_POINTER PTR_EVENT_DATA_LOGOUT, + EventDataLogout_t, MPI_POINTER pEventDataLogout_t; + +/* MPI RAID Status Change Event data */ + +typedef struct _EVENT_DATA_RAID_STATUS_CHANGE +{ + U8 VolumeTargetID; + U8 VolumeBus; + U8 ReasonCode; + U8 PhysDiskNum; + U8 ASC; + U8 ASCQ; + U16 Reserved; +} EVENT_DATA_RAID_STATUS_CHANGE, MPI_POINTER PTR_EVENT_DATA_RAID_STATUS_CHANGE, + MpiEventDataRaidStatusChange_t, MPI_POINTER pMpiEventDataRaidStatusChange_t; + + +/* MPI RAID Status Change Event data ReasonCode values */ + +#define MPI_EVENT_RAID_DATA_RC_VOLUME_OPTIMAL (0x00) +#define MPI_EVENT_RAID_DATA_RC_VOLUME_DEGRADED (0x01) +#define MPI_EVENT_RAID_DATA_RC_STARTED_RESYNC (0x02) +#define MPI_EVENT_RAID_DATA_RC_DISK_ADDED (0x03) +#define MPI_EVENT_RAID_DATA_RC_DISK_NOT_RESPONDING (0x04) +#define MPI_EVENT_RAID_DATA_RC_SMART_DATA (0x05) + + +/***************************************************************************** +* +* F i r m w a r e L o a d M e s s a g e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* Firmware Download message and associated structures */ +/****************************************************************************/ + +typedef struct _MSG_FW_DOWNLOAD +{ + U8 ImageType; + U8 Reserved; + U8 ChainOffset; + U8 Function; + U8 Reserved1[3]; + U8 MsgFlags; + U32 MsgContext; + SGE_MPI_UNION SGL; +} MSG_FW_DOWNLOAD, MPI_POINTER PTR_MSG_FW_DOWNLOAD, + FWDownload_t, MPI_POINTER pFWDownload_t; + +#define MPI_FW_DOWNLOAD_ITYPE_RESERVED (0x00) +#define MPI_FW_DOWNLOAD_ITYPE_FW (0x01) +#define MPI_FW_DOWNLOAD_ITYPE_BIOS (0x02) + + +typedef struct _FWDownloadTCSGE +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 Reserved1; + U32 ImageOffset; + U32 ImageSize; +} FW_DOWNLOAD_TCSGE, MPI_POINTER PTR_FW_DOWNLOAD_TCSGE, + FWDownloadTCSGE_t, MPI_POINTER pFWDownloadTCSGE_t; + +/* Firmware Download reply */ +typedef struct _MSG_FW_DOWNLOAD_REPLY +{ + U8 ImageType; + U8 Reserved; + U8 MsgLength; + U8 Function; + U8 Reserved1[3]; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved2; + U16 IOCStatus; + U32 IOCLogInfo; +} MSG_FW_DOWNLOAD_REPLY, MPI_POINTER PTR_MSG_FW_DOWNLOAD_REPLY, + FWDownloadReply_t, MPI_POINTER pFWDownloadReply_t; + + +/****************************************************************************/ +/* Firmware Upload message and associated structures */ +/****************************************************************************/ + +typedef struct _MSG_FW_UPLOAD +{ + U8 ImageType; + U8 Reserved; + U8 ChainOffset; + U8 Function; + U8 Reserved1[3]; + U8 MsgFlags; + U32 MsgContext; + SGE_MPI_UNION SGL; +} MSG_FW_UPLOAD, MPI_POINTER PTR_MSG_FW_UPLOAD, + FWUpload_t, MPI_POINTER pFWUpload_t; + +#define MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM (0x00) +#define MPI_FW_UPLOAD_ITYPE_FW_FLASH (0x01) +#define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02) +#define MPI_FW_UPLOAD_ITYPE_DATA_IOC_MEM (0x03) + +typedef struct _FWUploadTCSGE +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 Reserved1; + U32 ImageOffset; + U32 ImageSize; +} FW_UPLOAD_TCSGE, MPI_POINTER PTR_FW_UPLOAD_TCSGE, + FWUploadTCSGE_t, MPI_POINTER pFWUploadTCSGE_t; + +/* Firmware Upload reply */ +typedef struct _MSG_FW_UPLOAD_REPLY +{ + U8 ImageType; + U8 Reserved; + U8 MsgLength; + U8 Function; + U8 Reserved1[3]; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved2; + U16 IOCStatus; + U32 IOCLogInfo; + U32 ActualImageSize; +} MSG_FW_UPLOAD_REPLY, MPI_POINTER PTR_MSG_FW_UPLOAD_REPLY, + FWUploadReply_t, MPI_POINTER pFWUploadReply_t; + + +typedef struct _MPI_FW_HEADER +{ + U32 ArmBranchInstruction0; + U32 Signature0; + U32 Signature1; + U32 Signature2; + U32 ArmBranchInstruction1; + U32 ArmBranchInstruction2; + U32 Reserved; + U32 Checksum; + U16 VendorId; + U16 ProductId; + U16 FwVersion; + U16 Reserved1; + U32 SeqCodeVersion; + U32 ImageSize; + U32 Reserved2; + U32 LoadStartAddress; + U32 IopResetVectorValue; + U32 IopResetRegAddr; + U32 VersionNameWhat; + U8 VersionName[32]; + U32 VendorNameWhat; + U8 VendorName[32]; +} MPI_FW_HEADER, MPI_POINTER PTR_MPI_FW_HEADER, + MpiFwHeader_t, MPI_POINTER pMpiFwHeader_t; + +#define MPI_FW_HEADER_WHAT_SIGNATURE (0x29232840) + + +typedef struct _MPI_DATA_HEADER +{ + U32 Signature; + U16 FunctionNumber; + U16 Length; + U32 Checksum; + U32 LoadStartAddress; +} MPI_DATA_HEADER, MPI_POINTER PTR_MPI_DATA_HEADER, + MpiDataHeader_t, MPI_POINTER pMpiDataHeader_t; + +#define MPI_DATA_HEADER_SIGNATURE (0x43504147) + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/lsi/mpi_lan.h linux.ac/drivers/message/fusion/lsi/mpi_lan.h --- linux.vanilla/drivers/message/fusion/lsi/mpi_lan.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/lsi/mpi_lan.h Tue Apr 3 23:12:52 2001 @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2000-2001 LSI Logic Corporation. + * + * + * Name: MPI_LAN.H + * Title: MPI LAN messages and structures + * Creation Date: June 30, 2000 + * + * MPI Version: 01.01.02 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 05-24-00 00.10.02 Added LANStatus field to _MSG_LAN_SEND_REPLY. + * Added LANStatus field to _MSG_LAN_RECEIVE_POST_REPLY. + * Moved ListCount field in _MSG_LAN_RECEIVE_POST_REPLY. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 06-12-00 01.00.02 Added MPI_ to BUCKETSTATUS_ definitions. + * 06-22-00 01.00.03 Major changes to match new LAN definition in 1.0 spec. + * 06-30-00 01.00.04 Added Context Reply definitions per revised proposal. + * Changed transaction context usage to bucket/buffer. + * 07-05-00 01.00.05 Removed LAN_RECEIVE_POST_BUCKET_CONTEXT_MASK definition + * to lan private header file + * 11-02-00 01.01.01 Original release for post 1.0 work + * 02-20-01 01.01.02 Started using MPI_POINTER. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_LAN_H +#define MPI_LAN_H + + +/****************************************************************************** +* +* L A N M e s s a g e s +* +*******************************************************************************/ + +/* LANSend messages */ + +typedef struct _MSG_LAN_SEND_REQUEST +{ + U16 Reserved; + U8 ChainOffset; + U8 Function; + U16 Reserved2; + U8 PortNumber; + U8 MsgFlags; + U32 MsgContext; + SGE_MPI_UNION SG_List[1]; +} MSG_LAN_SEND_REQUEST, MPI_POINTER PTR_MSG_LAN_SEND_REQUEST, + LANSendRequest_t, MPI_POINTER pLANSendRequest_t; + + +typedef struct _MSG_LAN_SEND_REPLY +{ + U16 Reserved; + U8 MsgLength; + U8 Function; + U8 Reserved2; + U8 NumberOfContexts; + U8 PortNumber; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved3; + U16 IOCStatus; + U32 IOCLogInfo; + U32 BufferContext; +} MSG_LAN_SEND_REPLY, MPI_POINTER PTR_MSG_LAN_SEND_REPLY, + LANSendReply_t, MPI_POINTER pLANSendReply_t; + + +/* LANReceivePost */ + +typedef struct _MSG_LAN_RECEIVE_POST_REQUEST +{ + U16 Reserved; + U8 ChainOffset; + U8 Function; + U16 Reserved2; + U8 PortNumber; + U8 MsgFlags; + U32 MsgContext; + U32 BucketCount; + SGE_MPI_UNION SG_List[1]; +} MSG_LAN_RECEIVE_POST_REQUEST, MPI_POINTER PTR_MSG_LAN_RECEIVE_POST_REQUEST, + LANReceivePostRequest_t, MPI_POINTER pLANReceivePostRequest_t; + + +typedef struct _MSG_LAN_RECEIVE_POST_REPLY +{ + U16 Reserved; + U8 MsgLength; + U8 Function; + U8 Reserved2; + U8 NumberOfContexts; + U8 PortNumber; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved3; + U16 IOCStatus; + U32 IOCLogInfo; + U32 BucketsRemaining; + U32 PacketOffset; + U32 PacketLength; + U32 BucketContext[1]; +} MSG_LAN_RECEIVE_POST_REPLY, MPI_POINTER PTR_MSG_LAN_RECEIVE_POST_REPLY, + LANReceivePostReply_t, MPI_POINTER pLANReceivePostReply_t; + + +/* LANReset */ + +typedef struct _MSG_LAN_RESET_REQUEST +{ + U16 Reserved; + U8 ChainOffset; + U8 Function; + U16 Reserved2; + U8 PortNumber; + U8 MsgFlags; + U32 MsgContext; +} MSG_LAN_RESET_REQUEST, MPI_POINTER PTR_MSG_LAN_RESET_REQUEST, + LANResetRequest_t, MPI_POINTER pLANResetRequest_t; + + +typedef struct _MSG_LAN_RESET_REPLY +{ + U16 Reserved; + U8 MsgLength; + U8 Function; + U16 Reserved2; + U8 PortNumber; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved3; + U16 IOCStatus; + U32 IOCLogInfo; +} MSG_LAN_RESET_REPLY, MPI_POINTER PTR_MSG_LAN_RESET_REPLY, + LANResetReply_t, MPI_POINTER pLANResetReply_t; + + +/****************************************************************************/ +/* LAN Context Reply defines and macros */ +/****************************************************************************/ + +#define LAN_REPLY_PACKET_LENGTH_MASK (0x0000FFFF) +#define LAN_REPLY_PACKET_LENGTH_SHIFT (0) +#define LAN_REPLY_BUCKET_CONTEXT_MASK (0x07FF0000) +#define LAN_REPLY_BUCKET_CONTEXT_SHIFT (16) +#define LAN_REPLY_BUFFER_CONTEXT_MASK (0x07FFFFFF) +#define LAN_REPLY_BUFFER_CONTEXT_SHIFT (0) +#define LAN_REPLY_FORM_MASK (0x18000000) +#define LAN_REPLY_FORM_RECEIVE_SINGLE (0x00) +#define LAN_REPLY_FORM_RECEIVE_MULTIPLE (0x01) +#define LAN_REPLY_FORM_SEND_SINGLE (0x02) +#define LAN_REPLY_FORM_MESSAGE_CONTEXT (0x03) +#define LAN_REPLY_FORM_SHIFT (27) + +#define GET_LAN_PACKET_LENGTH(x) (((x) & LAN_REPLY_PACKET_LENGTH_MASK) \ + >> LAN_REPLY_PACKET_LENGTH_SHIFT) + +#define SET_LAN_PACKET_LENGTH(x, lth) \ + ((x) = ((x) & ~LAN_REPLY_PACKET_LENGTH_MASK) | \ + (((lth) << LAN_REPLY_PACKET_LENGTH_SHIFT) & \ + LAN_REPLY_PACKET_LENGTH_MASK)) + +#define GET_LAN_BUCKET_CONTEXT(x) (((x) & LAN_REPLY_BUCKET_CONTEXT_MASK) \ + >> LAN_REPLY_BUCKET_CONTEXT_SHIFT) + +#define SET_LAN_BUCKET_CONTEXT(x, ctx) \ + ((x) = ((x) & ~LAN_REPLY_BUCKET_CONTEXT_MASK) | \ + (((ctx) << LAN_REPLY_BUCKET_CONTEXT_SHIFT) & \ + LAN_REPLY_BUCKET_CONTEXT_MASK)) + +#define GET_LAN_BUFFER_CONTEXT(x) (((x) & LAN_REPLY_BUFFER_CONTEXT_MASK) \ + >> LAN_REPLY_BUFFER_CONTEXT_SHIFT) + +#define SET_LAN_BUFFER_CONTEXT(x, ctx) \ + ((x) = ((x) & ~LAN_REPLY_BUFFER_CONTEXT_MASK) | \ + (((ctx) << LAN_REPLY_BUFFER_CONTEXT_SHIFT) & \ + LAN_REPLY_BUFFER_CONTEXT_MASK)) + +#define GET_LAN_FORM(x) (((x) & LAN_REPLY_FORM_MASK) \ + >> LAN_REPLY_FORM_SHIFT) + +#define SET_LAN_FORM(x, frm) \ + ((x) = ((x) & ~LAN_REPLY_FORM_MASK) | \ + (((frm) << LAN_REPLY_FORM_SHIFT) & \ + LAN_REPLY_FORM_MASK)) + + +/****************************************************************************/ +/* LAN Current Device State defines */ +/****************************************************************************/ + +#define MPI_LAN_DEVICE_STATE_RESET (0x00) +#define MPI_LAN_DEVICE_STATE_OPERATIONAL (0x01) + + +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/lsi/mpi_targ.h linux.ac/drivers/message/fusion/lsi/mpi_targ.h --- linux.vanilla/drivers/message/fusion/lsi/mpi_targ.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/lsi/mpi_targ.h Tue Apr 3 17:54:47 2001 @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2000-2001 LSI Logic Corporation. + * + * + * Name: MPI_TARG.H + * Title: MPI Target mode messages and structures + * Creation Date: June 22, 2000 + * + * MPI Version: 01.01.03 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 06-22-00 01.00.02 Added _MSG_TARGET_CMD_BUFFER_POST_REPLY structure. + * Corrected DECSRIPTOR typo to DESCRIPTOR. + * 11-02-00 01.01.01 Original release for post 1.0 work + * Modified target mode to use IoIndex instead of + * HostIndex and IocIndex. Added Alias. + * 01-09-01 01.01.02 Added defines for TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER + * and TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER. + * 02-20-01 01.01.03 Started using MPI_POINTER. + * Added structures for MPI_TARGET_SCSI_SPI_CMD_BUFFER and + * MPI_TARGET_FCP_CMD_BUFFER. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_TARG_H +#define MPI_TARG_H + + +/****************************************************************************** +* +* S C S I T a r g e t M e s s a g e s +* +*******************************************************************************/ + +typedef struct _CMD_BUFFER_DESCRIPTOR +{ + U16 IoIndex; + U16 Reserved; + union + { + U32 PhysicalAddress32; + U64 PhysicalAddress64; + } u; +} CMD_BUFFER_DESCRIPTOR, MPI_POINTER PTR_CMD_BUFFER_DESCRIPTOR, + CmdBufferDescriptor_t, MPI_POINTER pCmdBufferDescriptor_t; + + +/****************************************************************************/ +/* Target Command Buffer Post Request */ +/****************************************************************************/ + +typedef struct _MSG_TARGET_CMD_BUFFER_POST_REQUEST +{ + U8 BufferPostFlags; + U8 BufferCount; + U8 ChainOffset; + U8 Function; + U8 BufferLength; + U8 Reserved; + U8 Reserved1; + U8 MsgFlags; + U32 MsgContext; + CMD_BUFFER_DESCRIPTOR Buffer[1]; +} MSG_TARGET_CMD_BUFFER_POST_REQUEST, MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_REQUEST, + TargetCmdBufferPostRequest_t, MPI_POINTER pTargetCmdBufferPostRequest_t; + +#define CMD_BUFFER_POST_FLAGS_PORT_MASK (0x01) +#define CMD_BUFFER_POST_FLAGS_ADDR_MODE_MASK (0x80) +#define CMD_BUFFER_POST_FLAGS_ADDR_MODE_32 (0) +#define CMD_BUFFER_POST_FLAGS_ADDR_MODE_64 (1) +#define CMD_BUFFER_POST_FLAGS_64_BIT_ADDR (0x80) + +#define CMD_BUFFER_POST_IO_INDEX_MASK (0x00003FFF) + + +typedef struct _MSG_TARGET_CMD_BUFFER_POST_REPLY +{ + U8 BufferPostFlags; + U8 BufferCount; + U8 MsgLength; + U8 Function; + U8 BufferLength; + U8 Reserved; + U8 Reserved1; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved2; + U16 IOCStatus; + U32 IOCLogInfo; +} MSG_TARGET_CMD_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_REPLY, + TargetCmdBufferPostReply_t, MPI_POINTER pTargetCmdBufferPostReply_t; + + +typedef struct _MSG_PRIORITY_CMD_RECEIVED_REPLY +{ + U16 Reserved; + U8 MsgLength; + U8 Function; + U16 Reserved1; + U8 Reserved2; + U8 MsgFlags; + U32 MsgContext; + U8 PriorityReason; + U8 Reserved3; + U16 IOCStatus; + U32 IOCLogInfo; + U32 ReplyWord; +} MSG_PRIORITY_CMD_RECEIVED_REPLY, MPI_POINTER PTR_MSG_PRIORITY_CMD_RECEIVED_REPLY, + PriorityCommandReceivedReply_t, MPI_POINTER pPriorityCommandReceivedReply_t; + +#define PRIORITY_REASON_NO_DISCONNECT (0x00) +#define PRIORITY_REASON_SCSI_TASK_MANAGEMENT (0x01) +#define PRIORITY_REASON_UNKNOWN (0xFF) + + +typedef struct _MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY +{ + U16 Reserved; + U8 MsgLength; + U8 Function; + U16 Reserved1; + U8 Reserved2; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved3; + U16 IOCStatus; + U32 IOCLogInfo; + U32 ReplyWord; +} MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY, + MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY, + TargetCmdBufferPostErrorReply_t, MPI_POINTER pTargetCmdBufferPostErrorReply_t; + + +typedef struct _MPI_TARGET_FCP_CMD_BUFFER +{ + U8 FcpLun[8]; + U8 FcpCntl[4]; + U8 FcpCdb[16]; + U32 FcpDl; +} MPI_TARGET_FCP_CMD_BUFFER, MPI_POINTER PTR_MPI_TARGET_FCP_CMD_BUFFER, + MpiTargetFcpCmdBuffer, MPI_POINTER pMpiTargetFcpCmdBuffer; + + +typedef struct _MPI_TARGET_SCSI_SPI_CMD_BUFFER +{ + /* SPI L_Q information unit */ + U8 L_QType; + U8 Reserved; + U16 Tag; + U8 LogicalUnitNumber[8]; + U32 DataLength; + /* SPI command information unit */ + U8 ReservedFirstByteOfCommandIU; + U8 TaskAttribute; + U8 TaskManagementFlags; + U8 AdditionalCDBLength; + U8 CDB[16]; +} MPI_TARGET_SCSI_SPI_CMD_BUFFER, + MPI_POINTER PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER, + MpiTargetScsiSpiCmdBuffer, MPI_POINTER pMpiTargetScsiSpiCmdBuffer; + + +/****************************************************************************/ +/* Target Assist Request */ +/****************************************************************************/ + +typedef struct _MSG_TARGET_ASSIST_REQUEST +{ + U8 StatusCode; + U8 TargetAssistFlags; + U8 ChainOffset; + U8 Function; + U16 QueueTag; + U8 Reserved; + U8 MsgFlags; + U32 MsgContext; + U32 ReplyWord; + U8 LUN[8]; + U32 RelativeOffset; + U32 DataLength; + SGE_IO_UNION SGL[1]; +} MSG_TARGET_ASSIST_REQUEST, MPI_POINTER PTR_MSG_TARGET_ASSIST_REQUEST, + TargetAssistRequest_t, MPI_POINTER pTargetAssistRequest_t; + +#define TARGET_ASSIST_FLAGS_DATA_DIRECTION (0x01) +#define TARGET_ASSIST_FLAGS_AUTO_STATUS (0x02) +#define TARGET_ASSIST_FLAGS_HIGH_PRIORITY (0x04) +#define TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER (0x80) + + +typedef struct _MSG_TARGET_ERROR_REPLY +{ + U16 Reserved; + U8 MsgLength; + U8 Function; + U16 Reserved1; + U8 Reserved2; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved3; + U16 IOCStatus; + U32 IOCLogInfo; + U32 ReplyWord; + U32 TransferCount; +} MSG_TARGET_ERROR_REPLY, MPI_POINTER PTR_MSG_TARGET_ERROR_REPLY, + TargetErrorReply_t, MPI_POINTER pTargetErrorReply_t; + + +/****************************************************************************/ +/* Target Status Send Request */ +/****************************************************************************/ + +typedef struct _MSG_TARGET_STATUS_SEND_REQUEST +{ + U8 StatusCode; + U8 StatusFlags; + U8 ChainOffset; + U8 Function; + U16 QueueTag; + U8 Reserved; + U8 MsgFlags; + U32 MsgContext; + U32 ReplyWord; + U8 LUN[8]; + SGE_SIMPLE_UNION StatusDataSGE; +} MSG_TARGET_STATUS_SEND_REQUEST, MPI_POINTER PTR_MSG_TARGET_STATUS_SEND_REQUEST, + TargetStatusSendRequest_t, MPI_POINTER pTargetStatusSendRequest_t; + +#define TARGET_STATUS_SEND_FLAGS_AUTO_GOOD_STATUS (0x01) +#define TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER (0x80) + + +/****************************************************************************/ +/* Target Mode Abort Request */ +/****************************************************************************/ + +typedef struct _MSG_TARGET_MODE_ABORT_REQUEST +{ + U8 AbortType; + U8 Reserved; + U8 ChainOffset; + U8 Function; + U16 Reserved1; + U8 Reserved2; + U8 MsgFlags; + U32 MsgContext; + U32 ReplyWord; + U32 MsgContextToAbort; +} MSG_TARGET_MODE_ABORT, MPI_POINTER PTR_MSG_TARGET_MODE_ABORT, + TargetModeAbort_t, MPI_POINTER pTargetModeAbort_t; + +#define TARGET_MODE_ABORT_TYPE_ALL_CMD_BUFFERS (0x00) +#define TARGET_MODE_ABORT_TYPE_ALL_IO (0x01) +#define TARGET_MODE_ABORT_TYPE_EXACT_IO (0x02) +#define TARGET_MODE_ABORT_TYPE_EXACT_IO_REQUEST (0x03) + +/* Target Mode Abort Reply */ + +typedef struct _MSG_TARGET_MODE_ABORT_REPLY +{ + U16 Reserved; + U8 MsgLength; + U8 Function; + U16 Reserved1; + U8 Reserved2; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved3; + U16 IOCStatus; + U32 IOCLogInfo; + U32 AbortCount; +} MSG_TARGET_MODE_ABORT_REPLY, MPI_POINTER PTR_MSG_TARGET_MODE_ABORT_REPLY, + TargetModeAbortReply_t, MPI_POINTER pTargetModeAbortReply_t; + + +/****************************************************************************/ +/* Target Mode Context Reply */ +/****************************************************************************/ + +#define TARGET_MODE_REPLY_IO_INDEX_MASK (0x00003FFF) +#define TARGET_MODE_REPLY_IO_INDEX_SHIFT (0) +#define TARGET_MODE_REPLY_INITIATOR_INDEX_MASK (0x03FFC000) +#define TARGET_MODE_REPLY_INITIATOR_INDEX_SHIFT (14) +#define TARGET_MODE_REPLY_ALIAS_MASK (0x0C000000) +#define TARGET_MODE_REPLY_ALIAS_SHIFT (26) +#define TARGET_MODE_REPLY_PORT_MASK (0x10000000) +#define TARGET_MODE_REPLY_PORT_SHIFT (28) + + +#define GET_IO_INDEX(x) (((x) & TARGET_MODE_REPLY_IO_INDEX_MASK) \ + >> TARGET_MODE_REPLY_IO_INDEX_SHIFT) + +#define SET_IO_INDEX(t, i) \ + ((t) = ((t) & ~TARGET_MODE_REPLY_IO_INDEX_MASK) | \ + (((i) << TARGET_MODE_REPLY_IO_INDEX_SHIFT) & \ + TARGET_MODE_REPLY_IO_INDEX_MASK)) + +#define GET_INITIATOR_INDEX(x) (((x) & TARGET_MODE_REPLY_INITIATOR_INDEX_MASK) \ + >> TARGET_MODE_REPLY_INITIATOR_INDEX_SHIFT) + +#define SET_INITIATOR_INDEX(t, ii) \ + ((t) = ((t) & ~TARGET_MODE_REPLY_INITIATOR_INDEX_MASK) | \ + (((ii) << TARGET_MODE_REPLY_INITIATOR_INDEX_SHIFT) & \ + TARGET_MODE_REPLY_INITIATOR_INDEX_MASK)) + +#define GET_ALIAS(x) (((x) & TARGET_MODE_REPLY_ALIAS_MASK) \ + >> TARGET_MODE_REPLY_ALIAS_SHIFT) + +#define SET_ALIAS(t, a) ((t) = ((t) & ~TARGET_MODE_REPLY_ALIAS_MASK) | \ + (((a) << TARGET_MODE_REPLY_ALIAS_SHIFT) & \ + TARGET_MODE_REPLY_ALIAS_MASK)) + +#define GET_PORT(x) (((x) & TARGET_MODE_REPLY_PORT_MASK) \ + >> TARGET_MODE_REPLY_PORT_SHIFT) + +#define SET_PORT(t, p) ((t) = ((t) & ~TARGET_MODE_REPLY_PORT_MASK) | \ + (((p) << TARGET_MODE_REPLY_PORT_SHIFT) & \ + TARGET_MODE_REPLY_PORT_MASK)) + + +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/lsi/mpi_type.h linux.ac/drivers/message/fusion/lsi/mpi_type.h --- linux.vanilla/drivers/message/fusion/lsi/mpi_type.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/lsi/mpi_type.h Tue Apr 3 17:54:47 2001 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2000-2001 LSI Logic Corporation. + * + * + * Name: MPI_TYPE.H + * Title: MPI Basic type definitions + * Creation Date: June 6, 2000 + * + * MPI Version: 01.01.02 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 11-02-00 01.01.01 Original release for post 1.0 work + * 02-20-01 01.01.02 Added define and ifdef for MPI_POINTER. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_TYPE_H +#define MPI_TYPE_H + + +/******************************************************************************* + * Define MPI_POINTER if it hasn't already been defined. By default MPI_POINTER + * is defined to be a near pointer. MPI_POINTER can be defined as a far pointer + * by defining MPI_POINTER as "far *" before this header file is included. + */ +#ifndef MPI_POINTER +#define MPI_POINTER * +#endif + + +/***************************************************************************** +* +* B a s i c T y p e s +* +*****************************************************************************/ + +typedef signed char S8; +typedef unsigned char U8; +typedef signed short S16; +typedef unsigned short U16; + + +#if defined(unix) || defined(__arm) || defined(ALPHA) + + typedef signed int S32; + typedef unsigned int U32; + +#else + + typedef signed long S32; + typedef unsigned long U32; + +#endif + + +typedef struct _S64 +{ + U32 Low; + S32 High; +} S64; + +typedef struct _U64 +{ + U32 Low; + U32 High; +} U64; + + +/****************************************************************************/ +/* Pointers */ +/****************************************************************************/ + +typedef S8 *PS8; +typedef U8 *PU8; +typedef S16 *PS16; +typedef U16 *PU16; +typedef S32 *PS32; +typedef U32 *PU32; +typedef S64 *PS64; +typedef U64 *PU64; + + +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/mptbase.c linux.ac/drivers/message/fusion/mptbase.c --- linux.vanilla/drivers/message/fusion/mptbase.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/mptbase.c Tue Apr 3 23:12:52 2001 @@ -0,0 +1,3360 @@ +/* + * linux/drivers/message/fusion/mptbase.c + * High performance SCSI + LAN / Fibre Channel device drivers. + * This is the Fusion MPT base driver which supports multiple + * (SCSI + LAN) specialized protocol drivers. + * For use with PCI chip/adapter(s): + * LSIFC9xx/LSI409xx Fibre Channel + * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * + * Credits: + * There are lots of people not mentioned below that deserve credit + * and thanks but won't get it here - sorry in advance that you + * got overlooked. + * + * This driver would not exist if not for Alan Cox's development + * of the linux i2o driver. + * + * A special thanks to Noah Romer (LSI Logic) for tons of work + * and tough debugging on the LAN driver, especially early on;-) + * And to Roger Hickerson (LSI Logic) for tirelessly supporting + * this driver project. + * + * All manner of help from Stephen Shirron (LSI Logic): + * low-level FC analysis, debug + various fixes in FCxx firmware, + * initial port to alpha platform, various driver code optimizations, + * being a faithful sounding board on all sorts of issues & ideas, + * etc. + * + * A huge debt of gratitude is owed to David S. Miller (DaveM) + * for fixing much of the stupid and broken stuff in the early + * driver while porting to sparc64 platform. THANK YOU! + * + * Special thanks goes to the I2O LAN driver people at the + * University of Helsinki, who, unbeknownst to them, provided + * the inspiration and initial structure for this driver. + * + * A really huge debt of gratitude is owed to Eddie C. Dost + * for gobs of hard work fixing and optimizing LAN code. + * THANK YOU! + * + * Copyright (c) 1999-2001 LSI Logic Corporation + * Originally By: Steven J. Ralston + * (mailto:Steve.Ralston@lsil.com) + * + * $Id: mptbase.c,v 1.47 2001/03/22 10:32:23 sralston Exp $ + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + 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. + + NO WARRANTY + THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + solely responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, damage to or loss of data, + programs or equipment, and unavailability or interruption of operations. + + DISCLAIMER OF LIABILITY + NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#include <linux/config.h> +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/blkdev.h> +#include <linux/delay.h> +#include <linux/proc_fs.h> +#include <asm/io.h> +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +#include "mptbase.h" + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#define my_NAME "Fusion MPT base driver" +#define my_VERSION MPT_LINUX_VERSION_COMMON +#define MYNAM "mptbase" + +MODULE_AUTHOR(MODULEAUTHOR); +MODULE_DESCRIPTION(my_NAME); + +/* + * cmd line parameters + */ +MODULE_PARM(PortIo, "0-1i"); +MODULE_PARM_DESC(PortIo, "[0]=Use mmap, 1=Use port io"); +MODULE_PARM(HardReset, "0-1i"); +MODULE_PARM_DESC(HardReset, "0=Disable HardReset, [1]=Enable HardReset"); +static int PortIo = 0; +static int HardReset = 1; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Public data... + */ +int mpt_lan_index = 0; +int mpt_stm_index = 0; + +void *mpt_v_ASCQ_TablePtr = NULL; +const char **mpt_ScsiOpcodesPtr = NULL; +int mpt_ASCQ_TableSz = 0; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Private data... + */ + /* Adapter lookup table */ +static MPT_ADAPTER *mpt_adapters[MPT_MAX_ADAPTERS] = {0}; +static MPT_ADAPTER_TRACKER MptAdapters; + /* Callback lookup table */ +static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS]; + /* Protocol driver class lookup table */ +static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS]; + /* Event handler lookup table */ +static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS]; + +static int FusionInitCalled = 0; +static int mpt_base_index = -1; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Forward protos... + */ +static void mpt_interrupt(int irq, void *bus_id, struct pt_regs *r); +static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply); + +static int mpt_adapter_install(struct pci_dev *pdev); +static void mpt_detect_929_bound_ports(MPT_ADAPTER *this, struct pci_dev *pdev); +static void mpt_adapter_disable(MPT_ADAPTER *ioc); +static void mpt_adapter_dispose(MPT_ADAPTER *ioc); + +static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc); +static u32 GetIocState(MPT_ADAPTER *ioc, int cooked); +static int GetIocFacts(MPT_ADAPTER *ioc); +static int GetPortFacts(MPT_ADAPTER *ioc); +static int SendIocInit(MPT_ADAPTER *ioc); +static int SendPortEnable(MPT_ADAPTER *ioc, int portnum); +static int mpt_fc9x9_reset(MPT_ADAPTER *ioc); +static int KickStart(MPT_ADAPTER *ioc); +static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type); +static int PrimeIocFifos(MPT_ADAPTER *ioc); +static int HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply); +static int WaitForDoorbellAck(MPT_ADAPTER *ioc); +static int WaitForDoorbellInt(MPT_ADAPTER *ioc); +static int WaitForDoorbellReply(MPT_ADAPTER *ioc); +static int GetLanConfigPages(MPT_ADAPTER *ioc); +static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch); +static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp); + +static int procmpt_create(void); +#ifdef CONFIG_PROC_FS +static int procmpt_destroy(void); +#endif +static int procmpt_read_summary(char *page, char **start, off_t off, int count, int *eof, void *data); +static int procmpt_read_dbg(char *page, char **start, off_t off, int count, int *eof, void *data); +/*static int procmpt_info(char *buf, char **start, off_t offset, int len);*/ + +static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers); +static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info); +static void mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info); + +static struct proc_dir_entry *procmpt_root_dir = NULL; + +int fusion_init(void); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* 20000207 -sralston + * GRRRRR... IOSpace (port i/o) register access (for the 909) is back! + * 20000517 -sralston + * Let's trying going back to default mmap register access... + */ + +static inline u32 CHIPREG_READ32(volatile u32 *a) +{ + if (PortIo) + return inl((unsigned long)a); + else + return readl(a); +} + +static inline void CHIPREG_WRITE32(volatile u32 *a, u32 v) +{ + if (PortIo) + outl(v, (unsigned long)a); + else + writel(v, a); +} + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_interrupt - MPT adapter (IOC) specific interrupt handler. + * @irq: irq number (not used) + * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure + * @r: pt_regs pointer (not used) + * + * This routine is registered via the request_irq() kernel API call, + * and handles all interrupts generated from a specific MPT adapter + * (also referred to as a IO Controller or IOC). + * This routine must clear the interrupt from the adapter and does + * so by reading the reply FIFO. Multiple replies may be processed + * per single call to this routine; up to MPT_MAX_REPLIES_PER_ISR + * which is currently set to 32 in mptbase.h. + * + * This routine handles register-level access of the adapter but + * dispatches (calls) a protocol-specific callback routine to handle + * the protocol-specific details of the MPT request completion. + */ +static void +mpt_interrupt(int irq, void *bus_id, struct pt_regs *r) +{ + MPT_ADAPTER *ioc; + MPT_FRAME_HDR *mf; + MPT_FRAME_HDR *mr; + u32 pa; + u32 *m; + int req_idx; + int cb_idx; + int type; + int freeme; + int count = 0; + + ioc = bus_id; + + /* + * Drain the reply FIFO! + * + * NOTES: I've seen up to 10 replies processed in this loop, so far... + * Update: I've seen up to 9182 replies processed in this loop! ?? + * Update: Limit ourselves to processing max of N replies + * (bottom of loop). + */ + while (1) { + + if ((pa = CHIPREG_READ32(&ioc->chip->ReplyFifo)) == 0xFFFFFFFF) + return; + + cb_idx = 0; + freeme = 0; + + /* + * Check for non-TURBO reply! + */ + if (pa & MPI_ADDRESS_REPLY_A_BIT) { + dma_addr_t reply_dma_addr; + u16 ioc_stat; + + /* non-TURBO reply! Hmmm, something may be up... + * Newest turbo reply mechanism; get address + * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)! + */ + reply_dma_addr = (pa = (pa << 1)); + + /* Map DMA address of reply header to cpu address. */ + m = (u32 *) ((u8 *)ioc->reply_frames + + (reply_dma_addr - ioc->reply_frames_dma)); + + mr = (MPT_FRAME_HDR *) m; + req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx); + cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx; + mf = MPT_INDEX_2_MFPTR(ioc, req_idx); + + dprintk((KERN_INFO MYNAM ": %s: Got non-TURBO reply=%p\n", + ioc->name, mr)); + DBG_DUMP_REPLY_FRAME(mr) + + /* NEW! 20010301 -sralston + * Check/log IOC log info + */ + ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus); + if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { + u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo); + if ((int)ioc->chip_type <= (int)FC929) + mpt_fc_log_info(ioc, log_info); + else + mpt_sp_log_info(ioc, log_info); + } + } else { + /* + * Process turbo (context) reply... + */ + dirqprintk((KERN_INFO MYNAM ": %s: Got TURBO reply(=%08x)\n", ioc->name, pa)); + type = (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT); + if (type == MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET) { + cb_idx = mpt_stm_index; + mf = NULL; + mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); + } else if (type == MPI_CONTEXT_REPLY_TYPE_LAN) { + cb_idx = mpt_lan_index; + /* + * BUG FIX! 20001218 -sralston + * Blind set of mf to NULL here was fatal + * after lan_reply says "freeme" + * Fix sort of combined with an optimization here; + * added explicit check for case where lan_reply + * was just returning 1 and doing nothing else. + * For this case skip the callback, but set up + * proper mf value first here:-) + */ + if ((pa & 0x58000000) == 0x58000000) { + req_idx = pa & 0x0000FFFF; + mf = MPT_INDEX_2_MFPTR(ioc, req_idx); + freeme = 1; + /* + * IMPORTANT! Invalidate the callback! + */ + cb_idx = 0; + } else { + mf = NULL; + } + mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); + } else { + req_idx = pa & 0x0000FFFF; + cb_idx = (pa & 0x00FF0000) >> 16; + mf = MPT_INDEX_2_MFPTR(ioc, req_idx); + mr = NULL; + } + pa = 0; /* No reply flush! */ + } + + /* Check for (valid) IO callback! */ + if (cb_idx) { + /* Do the callback! */ + freeme = (*(MptCallbacks[cb_idx]))(ioc, mf, mr); + } + + if (pa) { + /* Flush (non-TURBO) reply with a WRITE! */ + CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa); + } + + if (freeme) { + unsigned long flags; + + /* Put Request back on FreeQ! */ + spin_lock_irqsave(&ioc->FreeQlock, flags); + Q_ADD_TAIL(&ioc->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + } + + count++; + dirqprintk((KERN_INFO MYNAM ": %s: ISR processed frame #%d\n", ioc->name, count)); + mb(); + + if (count >= MPT_MAX_REPLIES_PER_ISR) { + dirqprintk((KERN_INFO MYNAM ": %s: ISR processed %d replies.", + ioc->name, count)); + dirqprintk((" Giving this ISR a break!\n")); + return; + } + + } /* drain reply FIFO */ +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mpt_base_reply - MPT base driver's callback routine; all base driver + * "internal" request/reply processing is routed here. + * Currently used for EventNotification and EventAck handling. + * @ioc: Pointer to MPT_ADAPTER structure + * @mf: Pointer to original MPT request frame + * @reply: Pointer to MPT reply frame (NULL if TurboReply) + * + * Returns 1 indicating original alloc'd request frame ptr + * should be freed, or 0 if it shouldn't. + */ +static int +mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) +{ + int freereq = 1; + u8 func; + + dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply() called\n", ioc->name)); + + if ((mf == NULL) || + (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { + printk(KERN_ERR MYNAM ": %s: ERROR - NULL or BAD request frame ptr! (=%p)\n", + ioc->name, mf); + return 1; + } + + if (reply == NULL) { + dprintk((KERN_ERR MYNAM ": %s: ERROR - Unexpected NULL Event (turbo?) reply!\n", + ioc->name)); + return 1; + } + + if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) { + dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf)); + DBG_DUMP_REQUEST_FRAME_HDR(mf) + } + + func = reply->u.hdr.Function; + dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply, Function=%02Xh\n", + ioc->name, func)); + + if (func == MPI_FUNCTION_EVENT_NOTIFICATION) { + EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply; + int evHandlers = 0; + int results; + + results = ProcessEventNotification(ioc, pEvReply, &evHandlers); + if (results != evHandlers) { + /* CHECKME! Any special handling needed here? */ + dprintk((KERN_WARNING MYNAM ": %s: Hmmm... Called %d event handlers, sum results = %d\n", + ioc->name, evHandlers, results)); + } + + /* + * Hmmm... It seems that EventNotificationReply is an exception + * to the rule of one reply per request. + */ + if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) + freereq = 0; +#ifdef CONFIG_PROC_FS +// LogEvent(ioc, pEvReply); +#endif + } else if (func == MPI_FUNCTION_EVENT_ACK) { + dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply, EventAck reply received\n", + ioc->name)); + } else { + printk(KERN_ERR MYNAM ": %s: ERROR - Unexpected msg function (=%02Xh) reply received!\n", + ioc->name, func); + } + + /* + * Conditionally tell caller to free the original + * EventNotification/EventAck/unexpected request frame! + */ + return freereq; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_register - Register protocol-specific main callback handler. + * @cbfunc: callback function pointer + * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value) + * + * This routine is called by a protocol-specific driver (SCSI host, + * LAN, SCSI target) to register it's reply callback routine. Each + * protocol-specific driver must do this before it will be able to + * use any IOC resources, such as obtaining request frames. + * + * NOTES: The SCSI protocol driver currently calls this routine twice + * in order to register separate callbacks; one for "normal" SCSI IO + * and another for MptScsiTaskMgmt requests. + * + * Returns a positive integer valued "handle" in the + * range (and S.O.D. order) {7,6,...,1} if successful. + * Any non-positive return value (including zero!) should be considered + * an error by the caller. + */ +int +mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass) +{ + int r = -1; + int i; + +#ifndef MODULE + /* + * Handle possibility of the mptscsih_detect() routine getting + * called *before* fusion_init! + */ + if (!FusionInitCalled) { + dprintk((KERN_INFO MYNAM ": Hmmm, calling fusion_init from mpt_register!\n")); + /* + * NOTE! We'll get recursion here, as fusion_init() + * calls mpt_register()! + */ + fusion_init(); + FusionInitCalled++; + } +#endif + + /* + * Search for empty callback slot in this order: {7,6,...,1} + * (slot/handle 0 is reserved!) + */ + for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) { + if (MptCallbacks[i] == NULL) { + MptCallbacks[i] = cbfunc; + MptDriverClass[i] = dclass; + MptEvHandlers[i] = NULL; + r = i; + if (cbfunc != mpt_base_reply) { + MOD_INC_USE_COUNT; + } + break; + } + } + + return r; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_deregister - Deregister a protocol drivers resources. + * @cb_idx: previously registered callback handle + * + * Each protocol-specific driver should call this routine when it's + * module is unloaded. + */ +void +mpt_deregister(int cb_idx) +{ + if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) { + MptCallbacks[cb_idx] = NULL; + MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER; + MptEvHandlers[cb_idx] = NULL; + if (cb_idx != mpt_base_index) { + MOD_DEC_USE_COUNT; + } + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_event_register - Register protocol-specific event callback + * handler. + * @cb_idx: previously registered (via mpt_register) callback handle + * @ev_cbfunc: callback function + * + * This routine can be called by one or more protocol-specific drivers + * if/when they choose to be notified of MPT events. + * + * Returns 0 for success. + */ +int +mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc) +{ + if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) + return -1; + + MptEvHandlers[cb_idx] = ev_cbfunc; + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_event_deregister - Deregister protocol-specific event callback + * handler. + * @cb_idx: previously registered callback handle + * + * Each protocol-specific driver should call this routine + * when it does not (or can no longer) handle events, + * or when it's module is unloaded. + */ +void +mpt_event_deregister(int cb_idx) +{ + if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) + return; + + MptEvHandlers[cb_idx] = NULL; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024) + * allocated per MPT adapter. + * @handle: Handle of registered MPT protocol driver + * @iocid: IOC unique identifier (integer) + * + * Returns pointer to a MPT request frame or %NULL if none are available. + */ +MPT_FRAME_HDR* +mpt_get_msg_frame(int handle, int iocid) +{ + MPT_FRAME_HDR *mf = NULL; + MPT_ADAPTER *iocp; + unsigned long flags; + + /* validate handle and ioc identifier */ + iocp = mpt_adapters[iocid]; + spin_lock_irqsave(&iocp->FreeQlock, flags); + if (! Q_IS_EMPTY(&iocp->FreeQ)) { + int req_offset; + + mf = iocp->FreeQ.head; + Q_DEL_ITEM(&mf->u.frame.linkage); + mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */ + req_offset = (u8 *)mf - (u8 *)iocp->req_frames; + /* u16! */ + mf->u.frame.hwhdr.msgctxu.fld.req_idx = + cpu_to_le16(req_offset / iocp->req_sz); + mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; + } + spin_unlock_irqrestore(&iocp->FreeQlock, flags); + dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n", + iocp->name, handle, iocid, mf)); + return mf; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_put_msg_frame - Send a protocol specific MPT request frame + * to a IOC. + * @handle: Handle of registered MPT protocol driver + * @iocid: IOC unique identifier (integer) + * @mf: Pointer to MPT request frame + * + * This routine posts a MPT request frame to the request post FIFO of a + * specific MPT adapter. + */ +void +mpt_put_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf) +{ + MPT_ADAPTER *iocp; + + iocp = mpt_adapters[iocid]; + if (iocp != NULL) { + dma_addr_t mf_dma_addr; + int req_offset; + + /* ensure values are reset properly! */ + mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */ + req_offset = (u8 *)mf - (u8 *)iocp->req_frames; + /* u16! */ + mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_offset / iocp->req_sz); + mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; + +#ifdef MPT_DEBUG_MSG_FRAME + { + u32 *m = mf->u.frame.hwhdr.__hdr; + int i, n; + + printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ", + iocp->name, m); + n = iocp->req_sz/4 - 1; + while (m[n] == 0) + n--; + for (i=0; i<=n; i++) { + if (i && ((i%8)==0)) + printk("\n" KERN_INFO " "); + printk(" %08x", le32_to_cpu(m[i])); + } + printk("\n"); + } +#endif + + mf_dma_addr = iocp->req_frames_dma + req_offset; + CHIPREG_WRITE32(&iocp->chip->RequestFifo, mf_dma_addr); + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_free_msg_frame - Place MPT request frame back on FreeQ. + * @handle: Handle of registered MPT protocol driver + * @iocid: IOC unique identifier (integer) + * @mf: Pointer to MPT request frame + * + * This routine places a MPT request frame back on the MPT adapter's + * FreeQ. + */ +void +mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf) +{ + MPT_ADAPTER *iocp; + unsigned long flags; + + iocp = mpt_adapters[iocid]; + if (iocp != NULL) { + /* Put Request back on FreeQ! */ + spin_lock_irqsave(&iocp->FreeQlock, flags); + Q_ADD_TAIL(&iocp->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR); + spin_unlock_irqrestore(&iocp->FreeQlock, flags); + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_send_handshake_request - Send MPT request via doorbell + * handshake method. + * @handle: Handle of registered MPT protocol driver + * @iocid: IOC unique identifier (integer) + * @reqBytes: Size of the request in bytes + * @req: Pointer to MPT request frame + * + * This routine is used exclusively by mptscsih to send MptScsiTaskMgmt + * requests since they are required to be sent via doorbell handshake. + * + * NOTE: It is the callers responsibility to byte-swap fields in the + * request which are greater than 1 byte in size. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req) +{ + MPT_ADAPTER *iocp; + int r = 0; + + iocp = mpt_adapters[iocid]; + if (iocp != NULL) { + u8 *req_as_bytes; + int i; + + /* + * Emulate what mpt_put_msg_frame() does /wrt to sanity + * setting cb_idx/req_idx. But ONLY if this request + * is in proper (pre-alloc'd) request buffer range... + */ + i = MFPTR_2_MPT_INDEX(iocp,(MPT_FRAME_HDR*)req); + if (reqBytes >= 12 && i >= 0 && i < iocp->req_depth) { + MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req; + mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(i); + mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; + } + + /* Make sure there are no doorbells */ + CHIPREG_WRITE32(&iocp->chip->IntStatus, 0); + + CHIPREG_WRITE32(&iocp->chip->Doorbell, + ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) | + ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT))); + + /* Wait for IOC doorbell int */ + if ((i = WaitForDoorbellInt(iocp)) < 0) { + /* FIXME! Recovery action(s)? */ + /*i = unresponsive_ioc(i);*/ + return i; + } + + dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n", + iocp->name, i)); + + CHIPREG_WRITE32(&iocp->chip->IntStatus, 0); + + if ((r = WaitForDoorbellAck(iocp)) < 0) + return -2; + + /* Send request via doorbell handshake */ + req_as_bytes = (u8 *) req; + for (i = 0; i < reqBytes/4; i++) { + u32 word; + + word = ((req_as_bytes[(i*4) + 0] << 0) | + (req_as_bytes[(i*4) + 1] << 8) | + (req_as_bytes[(i*4) + 2] << 16) | + (req_as_bytes[(i*4) + 3] << 24)); + CHIPREG_WRITE32(&iocp->chip->Doorbell, word); + if ((r = WaitForDoorbellAck(iocp)) < 0) { + r = -3; + break; + } + } + + /* Make sure there are no doorbells */ + CHIPREG_WRITE32(&iocp->chip->IntStatus, 0); + + } + + return r; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_adapter_find_first - Find first MPT adapter pointer. + * + * Returns first MPT adapter pointer or %NULL if no MPT adapters + * are present. + */ +MPT_ADAPTER * +mpt_adapter_find_first(void) +{ + MPT_ADAPTER *this = NULL; + + if (! Q_IS_EMPTY(&MptAdapters)) + this = MptAdapters.head; + + return this; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_adapter_find_next - Find next MPT adapter pointer. + * @prev: Pointer to previous MPT adapter + * + * Returns next MPT adapter pointer or %NULL if there are no more. + */ +MPT_ADAPTER * +mpt_adapter_find_next(MPT_ADAPTER *prev) +{ + MPT_ADAPTER *next = NULL; + + if (prev && (prev->forw != (MPT_ADAPTER*)&MptAdapters.head)) + next = prev->forw; + + return next; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_pci_scan - Scan PCI devices for MPT adapters. + * + * Returns count of MPT adapters found, keying off of PCI vendor and + * device_id's. + */ +int __init +mpt_pci_scan(void) +{ + struct pci_dev *pdev; + struct pci_dev *pdev2; + int found = 0; + int count = 0; + int r; + + dprintk((KERN_INFO MYNAM ": Checking for MPT adapters...\n")); + + /* + * NOTE: The 929 (I believe) will appear as 2 separate PCI devices, + * one for each channel. + */ + pci_for_each_dev(pdev) { + pdev2 = NULL; + if (pdev->vendor != 0x1000) + continue; + + if ((pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC909) && + (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC929) && +#if 0 + /* FIXME! FC919 */ + (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC919) && + /* FIXME! C103x family */ + (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030) && + (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030_ZC) && + (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1035) && +#endif + 1) { + dprintk((KERN_INFO MYNAM ": Skipping LSI device=%04xh\n", pdev->device)); + continue; + } + + /* GRRRRR + * 929 dual function devices may be presented in Func 1,0 order, + * but we'd really really rather have them in Func 0,1 order. + * Do some kind of look ahead here... + */ + if (pdev->devfn & 1) { + pdev2 = pci_peek_next_dev(pdev); + if (pdev2 && (pdev2->vendor == 0x1000) && + (PCI_SLOT(pdev2->devfn) == PCI_SLOT(pdev->devfn)) && + (pdev2->device == MPI_MANUFACTPAGE_DEVICEID_FC929) && + (pdev2->bus->number == pdev->bus->number) && + !(pdev2->devfn & 1)) { + dprintk((KERN_INFO MYNAM ": MPT adapter found: PCI bus/dfn=%02x/%02xh, class=%08x, id=%xh\n", + pdev2->bus->number, pdev2->devfn, pdev2->class, pdev2->device)); + found++; + if ((r = mpt_adapter_install(pdev2)) == 0) + count++; + } else { + pdev2 = NULL; + } + } + + dprintk((KERN_INFO MYNAM ": MPT adapter found: PCI bus/dfn=%02x/%02xh, class=%08x, id=%xh\n", + pdev->bus->number, pdev->devfn, pdev->class, pdev->device)); + found++; + if ((r = mpt_adapter_install(pdev)) == 0) + count++; + + if (pdev2) + pdev = pdev2; + } + + printk(KERN_INFO MYNAM ": %d MPT adapter%s found, %d installed.\n", + found, (found==1) ? "" : "s", count); + + if (count == 0) + return -ENODEV; + +#ifdef CONFIG_PROC_FS + if (procmpt_create() != 0) + printk(KERN_WARNING MYNAM ": WARNING! - %s creation failed!\n", + MPT_PROCFS_MPTBASEDIR); +#endif + + return count; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_verify_adapter - Given a unique IOC identifier, set pointer to + * the associated MPT adapter structure. + * @iocid: IOC unique identifier (integer) + * @iocpp: Pointer to pointer to IOC adapter + * + * Returns iocid and sets iocpp. + */ +int +mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp) +{ + MPT_ADAPTER *p; + + *iocpp = NULL; + if (iocid >= MPT_MAX_ADAPTERS) + return -1; + + p = mpt_adapters[iocid]; + if (p == NULL) + return -1; + + *iocpp = p; + return iocid; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_adapter_install - Install a PCI intelligent MPT adapter. + * @pdev: Pointer to pci_dev structure + * + * This routine performs all the steps necessary to bring the IOC of + * a MPT adapter to a OPERATIONAL state. This includes registering + * memory regions, registering the interrupt, and allocating request + * and reply memory pools. + * + * This routine also pre-fetches the LAN MAC address of a Fibre Channel + * MPT adapter. + * + * Returns 0 for success, non-zero for failure. + * + * TODO: Add support for polled controllers + */ +static int __init +mpt_adapter_install(struct pci_dev *pdev) +{ + MPT_ADAPTER *ioc; + char *myname; + u8 *mem; + unsigned long mem_phys; + unsigned long port; + u32 msize; + u32 psize; + u32 ioc_state; + int i; + int r = -ENODEV; + int cntdn; + int len; + int statefault = 0; + + ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_KERNEL); + if (ioc == NULL) { + printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n"); + return -ENOMEM; + } + memset(ioc, 0, sizeof(*ioc)); + ioc->req_sz = MPT_REQ_SIZE; /* avoid div by zero! */ + ioc->alloc_total = sizeof(MPT_ADAPTER); + + ioc->pcidev = pdev; + + /* Find lookup slot. GRRRR... */ + for (i=0; i < MPT_MAX_ADAPTERS; i++) { + if (mpt_adapters[i] == NULL) { + ioc->id = i; /* Assign adapter unique id (lookup) */ + break; + } + } + if (i == MPT_MAX_ADAPTERS) { + printk(KERN_ERR MYNAM ": ERROR - mpt_adapters[%d] table overflow!\n", i); + kfree(ioc); + return -ENFILE; + } + + mem_phys = msize = 0; + port = psize = 0; + for (i=0; i < DEVICE_COUNT_RESOURCE; i++) { + if (pdev->PCI_BASEADDR_FLAGS(i) & PCI_BASE_ADDRESS_SPACE_IO) { + /* Get I/O space! */ + port = pdev->PCI_BASEADDR_START(i); + psize = PCI_BASEADDR_SIZE(pdev,i); + } else { + /* Get memmap */ + mem_phys = pdev->PCI_BASEADDR_START(i); + msize = PCI_BASEADDR_SIZE(pdev,i); + break; + } + } + ioc->mem_size = msize; + + if (i == DEVICE_COUNT_RESOURCE) { + printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n"); + kfree(ioc); + return -EINVAL; + } + + dprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize)); + dprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize)); + dprintk((KERN_INFO MYNAM ": Using %s register access method\n", PortIo ? "PortIo" : "MemMap")); + + mem = NULL; + if (! PortIo) { + /* Get logical ptr for PciMem0 space */ + /*mem = ioremap(mem_phys, msize);*/ + mem = ioremap(mem_phys, 0x100); + if (mem == NULL) { + printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n"); + kfree(ioc); + return -EINVAL; + } + ioc->memmap = mem; + } + dprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys)); + + if (PortIo) { + u8 *pmem = (u8*)port; + ioc->mem_phys = port; + ioc->chip = (SYSIF_REGS*)pmem; + } else { + ioc->mem_phys = mem_phys; + ioc->chip = (SYSIF_REGS*)mem; + } + + ioc->chip_type = FCUNK; + if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) { + ioc->chip_type = FC909; + ioc->prod_name = "LSIFC909"; + } + else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) { + ioc->chip_type = FC929; + ioc->prod_name = "LSIFC929"; + } +#if 0 + else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) { + ioc->chip_type = C1030; + ioc->prod_name = "LSIFC919"; + } + else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_53C1030) { + ioc->chip_type = C1030; + ioc->prod_name = "LSI53C1030"; + } +#endif + + myname = "iocN"; + len = strlen(myname); + memcpy(ioc->name, myname, len+1); + ioc->name[len-1] = '0' + ioc->id; + + Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR); + spin_lock_init(&ioc->FreeQlock); + + /* Disable all! */ + CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + ioc->active = 0; + + ioc->pci_irq = -1; + if (pdev->irq) { + r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc); + + if (r < 0) { + printk(KERN_ERR MYNAM ": %s: ERROR - Unable to allocate interrupt %d!\n", + ioc->name, pdev->irq); + iounmap(mem); + kfree(ioc); + return -EBUSY; + } + + ioc->pci_irq = pdev->irq; + + pci_set_master(pdev); /* ?? */ + + dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq)); + } + + /* tack onto tail of our MPT adapter list */ + Q_ADD_TAIL(&MptAdapters, ioc, MPT_ADAPTER); + + /* Set lookup ptr. */ + mpt_adapters[ioc->id] = ioc; + + /* NEW! 20010220 -sralston + * Check for "929 bound ports" to reduce redundant resets. + */ + if (ioc->chip_type == FC929) + mpt_detect_929_bound_ports(ioc, pdev); + + /* Get current [raw] IOC state */ + ioc_state = GetIocState(ioc, 0); + dhsprintk((KERN_INFO MYNAM ": %s initial [raw] state=%08x\n", ioc->name, ioc_state)); + + /* + * Check to see if IOC got left/stuck in doorbell handshake + * grip of death. If so, hard reset the IOC. + */ + if (ioc_state & MPI_DOORBELL_ACTIVE) { + statefault = 1; + printk(KERN_WARNING MYNAM ": %s: Uh-oh, unexpected doorbell active!\n", + ioc->name); + } + + /* + * Check to see if IOC is in FAULT state. + * If so, hard reset the IOC. + */ + if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { + statefault = 2; + printk(KERN_WARNING MYNAM ": %s: Uh-oh, IOC is in FAULT state!!!\n", + ioc->name); + printk(KERN_WARNING " FAULT code = %04xh\n", + ioc_state & MPI_DOORBELL_DATA_MASK); + } + + if (HardReset || statefault) { + if ((r = KickStart(ioc)) != 0) { + r = -ENODEV; + goto ioc_up_fail; + } + } + + /* + * Loop here waiting for IOC to come READY. + */ + i = 0; + cntdn = HZ * 10; + while ((ioc_state = GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) { + if (ioc_state == MPI_IOC_STATE_OPERATIONAL) { + /* + * BIOS or previous driver load left IOC in OP state. + * Reset messaging FIFOs. + */ + dprintk((KERN_WARNING MYNAM ": %s: Sending IOC msg unit reset!\n", ioc->name)); + if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET)) != 0) { + printk(KERN_ERR MYNAM ": %s: ERROR - IOC msg unit reset failed!\n", ioc->name); + r = -ENODEV; + goto ioc_up_fail; + } + } else if (ioc_state == MPI_IOC_STATE_RESET) { + /* + * Something is wrong. Try to get IOC back + * to a known state. + */ + dprintk((KERN_WARNING MYNAM ": %s: Sending IO unit reset!\n", ioc->name)); + if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET)) != 0) { + printk(KERN_ERR MYNAM ": %s: ERROR - IO unit reset failed!\n", ioc->name); + r = -ENODEV; + goto ioc_up_fail; + } + } + + i++; cntdn--; + if (!cntdn) { + printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n", + ioc->name, (i+5)/HZ); + r = -ETIME; + goto ioc_up_fail; + } + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + + if (statefault) { + printk(KERN_WARNING MYNAM ": %s: Whew! Recovered from %s\n", + ioc->name, statefault==1 ? "stuck handshake" : "IOC FAULT"); + } + + /* Enable! (reply interrupt) */ + CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM)); + ioc->active = 1; + + /* Get IOC facts! (first time, ioc->facts0 and ioc->pfacts0) */ + if ((r = GetIocFacts(ioc)) != 0) + goto ioc_up_fail; + + /* Does IocFacts.EventState need any looking at / attention here? */ + + if ((r = SendIocInit(ioc)) != 0) + goto ioc_up_fail; + + /* + * Prime reply & request queues! + * (mucho alloc's) + */ + if ((r = PrimeIocFifos(ioc)) != 0) + goto ioc_up_fail; + + /* Get IOC facts again! (2nd time, ioc->factsN and ioc->pfactsN) */ + if ((r = GetIocFacts(ioc)) != 0) + goto ioc_up_fail; + + /* Does IocFacts.EventState need any looking at / attention here? */ + + MptDisplayIocCapabilities(ioc); + + if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { + /* + * Pre-fetch the ports LAN MAC address! + * (LANPage1_t stuff) + */ + (void) GetLanConfigPages(ioc); +#ifdef MPT_DEBUG + { + u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; + dprintk((KERN_INFO MYNAM ": %s: LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] )); + } +#endif + } + + /* NEW! 20010120 -sralston + * Enable MPT base driver management of EventNotification + * and EventAck handling. + */ + (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */ + + return 0; + +ioc_up_fail: + //Q_DEL_ITEM(ioc); + //mpt_adapter_dispose(ioc); + mpt_adapter_disable(ioc); + return r; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mpt_detect_929_bound_ports - Search for PCI bus/dev_function + * which matches PCI bus/dev_function (+/-1) for newly discovered 929. + * @ioc: Pointer to MPT adapter structure + * @pdev: Pointer to (struct pci_dev) structure + * + * If match on PCI dev_function +/-1 is found, bind the two MPT adapters + * using alt_ioc pointer fields in their %MPT_ADAPTER structures. + */ +static void +mpt_detect_929_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev) +{ + MPT_ADAPTER *ioc_srch = mpt_adapter_find_first(); + unsigned int match_lo, match_hi; + + match_lo = pdev->devfn-1; + match_hi = pdev->devfn+1; + dprintk((KERN_INFO MYNAM ": %s: PCI bus/devfn=%x/%x, searching for devfn match on %x or %x\n", + ioc->name, pdev->bus->number, pdev->devfn, match_lo, match_hi)); + + while (ioc_srch != NULL) { + struct pci_dev *_pcidev = ioc_srch->pcidev; + + if ( (_pcidev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) && + (_pcidev->bus->number == pdev->bus->number) && + (_pcidev->devfn == match_lo || _pcidev->devfn == match_hi) ) { + /* Paranoia checks */ + if (ioc->alt_ioc != NULL) { + printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n", + ioc->name, ioc->alt_ioc->name); + break; + } else if (ioc_srch->alt_ioc != NULL) { + printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n", + ioc_srch->name, ioc_srch->alt_ioc->name); + break; + } + dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n", + ioc->name, ioc_srch->name)); + ioc_srch->alt_ioc = ioc; + ioc->alt_ioc = ioc_srch; + ioc->sod_reset = ioc->alt_ioc->sod_reset; + ioc->last_kickstart = ioc->alt_ioc->last_kickstart; + break; + } + ioc_srch = mpt_adapter_find_next(ioc_srch); + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mpt_adapter_disable - Disable misbehaving MPT adapter. + * @this: Pointer to MPT adapter structure + */ +static void +mpt_adapter_disable(MPT_ADAPTER *this) +{ + if (this != NULL) { + int sz; + + /* Disable adapter interrupts! */ + CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF); + /* Clear any lingering interrupt */ + CHIPREG_WRITE32(&this->chip->IntStatus, 0); + this->active = 0; + + if (this->reply_alloc != NULL) { + sz = (this->reply_sz * this->reply_depth) + 128; + pci_free_consistent(this->pcidev, sz, + this->reply_alloc, this->reply_alloc_dma); + this->reply_frames = NULL; + this->reply_alloc = NULL; + this->alloc_total -= sz; + } + + if (this->req_alloc != NULL) { + sz = (this->req_sz * this->req_depth) + 128; + /* + * Rounding UP to nearest 4-kB boundary here... + */ + sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000; + pci_free_consistent(this->pcidev, sz, + this->req_alloc, this->req_alloc_dma); + this->req_frames = NULL; + this->req_alloc = NULL; + this->alloc_total -= sz; + } + + if (this->sense_buf_pool != NULL) { + sz = (this->req_depth * 256); + pci_free_consistent(this->pcidev, sz, + this->sense_buf_pool, this->sense_buf_pool_dma); + this->sense_buf_pool = NULL; + this->alloc_total -= sz; + } + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mpt_adapter_dispose - Free all resources associated with a MPT + * adapter. + * @this: Pointer to MPT adapter structure + * + * This routine unregisters h/w resources and frees all alloc'd memory + * associated with a MPT adapter structure. + */ +static void +mpt_adapter_dispose(MPT_ADAPTER *this) +{ + if (this != NULL) { + int sz_first, sz_last; + + sz_first = this->alloc_total; + + mpt_adapter_disable(this); + + if (this->pci_irq != -1) { + free_irq(this->pci_irq, this); + this->pci_irq = -1; + } + + if (this->memmap != NULL) + iounmap((u8 *) this->memmap); + +#if defined(CONFIG_MTRR) && 0 + if (this->mtrr_reg > 0) { + mtrr_del(this->mtrr_reg, 0, 0); + dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", this->name)); + } +#endif + + /* Zap the adapter lookup ptr! */ + mpt_adapters[this->id] = NULL; + + sz_last = this->alloc_total; + dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n", + this->name, sz_first-sz_last+(int)sizeof(*this), sz_first)); + kfree(this); + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * MptDisplayIocCapabilities - Disply IOC's capacilities. + * @ioc: Pointer to MPT adapter structure + */ +static void +MptDisplayIocCapabilities(MPT_ADAPTER *ioc) +{ + int i = 0; + + printk(KERN_INFO "%s: ", ioc->name); + if (ioc->prod_name && strlen(ioc->prod_name) > 3) + printk("%s: ", ioc->prod_name+3); + printk("Capabilities={"); + + if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) { + printk("Initiator"); + i++; + } + + if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) { + printk("%sTarget", i ? "," : ""); + i++; + } + + if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { + printk("%sLAN", i ? "," : ""); + i++; + } + +#if 0 + /* + * This would probably evoke more questions than it's worth + */ + if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) { + printk("%sLogBusAddr", i ? "," : ""); + i++; + } +#endif + + printk("}\n"); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * GetIocState - Get the current state of a MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * @cooked: Request raw or cooked IOC state + * + * Returns all IOC Doorbell register bits if cooked==0, else just the + * Doorbell bits in MPI_IOC_STATE_MASK. + */ +static u32 +GetIocState(MPT_ADAPTER *ioc, int cooked) +{ + u32 s, sc; + + /* Get! */ + s = CHIPREG_READ32(&ioc->chip->Doorbell); + dprintk((KERN_INFO MYNAM ": %s: raw state = %08x\n", ioc->name, s)); + sc = s & MPI_IOC_STATE_MASK; + + /* Save! */ + ioc->last_state = sc; + + return cooked ? sc : s; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * GetIocFacts - Send IOCFacts request to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * + * Returns 0 for success, non-zero for failure. + */ +static int +GetIocFacts(MPT_ADAPTER *ioc) +{ + IOCFacts_t get_facts; + IOCFactsReply_t *facts; + int r; + int req_sz; + int reply_sz; + u32 status; + + /* IOC *must* NOT be in RESET state! */ + if (ioc->last_state == MPI_IOC_STATE_RESET) { + printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n", + ioc->name, + ioc->last_state ); + return -44; + } + + facts = &ioc->facts0; + /* Nth (2,3,...) time thru? (been here, done that?) */ + if (ioc->facts0.Function == MPI_FUNCTION_IOC_FACTS) { + facts = &ioc->factsN; + } + + /* Destination (reply area)... */ + reply_sz = sizeof(*facts); + memset(facts, 0, reply_sz); + + /* Request area (get_facts on the stack right now!) */ + req_sz = sizeof(get_facts); + memset(&get_facts, 0, req_sz); + + get_facts.Function = MPI_FUNCTION_IOC_FACTS; + /* Assert: All other get_facts fields are zero! */ + + dprintk((KERN_INFO MYNAM ": %s: Sending IocFacts%s request\n", + ioc->name, facts == &ioc->facts0 ? "0" : "N" )); + + /* No non-zero fields in the get_facts request are greater than + * 1 byte in size, so we can just fire it off as is. + */ + r = HandShakeReqAndReply(ioc, + req_sz, (u32*)&get_facts, + reply_sz, (u16*)facts); + if (r != 0) + return r; + + /* + * Now byte swap the necessary fields before any further + * inspection of reply contents. + * + * But need to do some sanity checks on MsgLength (byte) field + * to make sure we don't zero IOC's req_sz! + */ + /* Did we get a valid reply? */ + if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) { + facts->MsgVersion = le16_to_cpu(facts->MsgVersion); + facts->MsgContext = le32_to_cpu(facts->MsgContext); + facts->IOCStatus = le16_to_cpu(facts->IOCStatus); + facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo); + status = facts->IOCStatus & MPI_IOCSTATUS_MASK; + /* CHECKME! IOCStatus, IOCLogInfo */ + + facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth); + facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize); + facts->FWVersion = le16_to_cpu(facts->FWVersion); + facts->ProductID = le16_to_cpu(facts->ProductID); + facts->CurrentHostMfaHighAddr = + le32_to_cpu(facts->CurrentHostMfaHighAddr); + facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits); + facts->CurrentSenseBufferHighAddr = + le32_to_cpu(facts->CurrentSenseBufferHighAddr); + facts->CurReplyFrameSize = + le16_to_cpu(facts->CurReplyFrameSize); + + /* + * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx + * Older MPI-1.00.xx struct had 13 dwords, and enlarged + * to 14 in MPI-1.01.0x. + */ + if (facts->MsgLength >= sizeof(IOCFactsReply_t)/sizeof(u32) && facts->MsgVersion > 0x0100) { + facts->FWImageSize = le32_to_cpu(facts->FWImageSize); + facts->DataImageSize = le32_to_cpu(facts->DataImageSize); + } + + if (facts->RequestFrameSize) { + /* + * Set values for this IOC's REQUEST queue size & depth... + */ + ioc->req_sz = MIN(MPT_REQ_SIZE, facts->RequestFrameSize * 4); + + /* + * Set values for this IOC's REPLY queue size & depth... + * + * BUG? FIX? 20000516 -nromer & sralston + * GRRR... The following did not translate well from MPI v0.09: + * ioc->reply_sz = MIN(MPT_REPLY_SIZE, facts->ReplySize * 4); + * to 0.10: + * ioc->reply_sz = MIN(MPT_REPLY_SIZE, facts->BlockSize * 4); + * Was trying to minimally optimize to smallest possible reply size + * (and greatly reduce kmalloc size). But LAN may need larger reply? + * + * So for now, just set reply size to request size. FIXME? + */ + ioc->reply_sz = ioc->req_sz; + } else { + /* Something is wrong! */ + printk(KERN_ERR MYNAM ": %s: ERROR - IOC reported invalid 0 request size!\n", + ioc->name); + ioc->req_sz = MPT_REQ_SIZE; + ioc->reply_sz = MPT_REPLY_SIZE; + return -55; + } + ioc->req_depth = MIN(MPT_REQ_DEPTH, facts->GlobalCredits); + ioc->reply_depth = MIN(MPT_REPLY_DEPTH, facts->ReplyQueueDepth); + + dprintk((KERN_INFO MYNAM ": %s: reply_sz=%3d, reply_depth=%4d\n", + ioc->name, ioc->reply_sz, ioc->reply_depth)); + dprintk((KERN_INFO MYNAM ": %s: req_sz =%3d, req_depth =%4d\n", + ioc->name, ioc->req_sz, ioc->req_depth)); + + /* Get port facts! */ + if ( (r = GetPortFacts(ioc)) != 0 ) + return r; + } else { + printk(KERN_ERR MYNAM ": %s: ERROR - Invalid IOC facts reply!\n", + ioc->name); + return -66; + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * GetPortFacts - Send PortFacts request to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * + * Returns 0 for success, non-zero for failure. + */ +static int +GetPortFacts(MPT_ADAPTER *ioc) +{ + PortFacts_t get_pfacts; + PortFactsReply_t *pfacts; + int i; + int req_sz; + int reply_sz; + + /* IOC *must* NOT be in RESET state! */ + if (ioc->last_state == MPI_IOC_STATE_RESET) { + printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n", + ioc->name, + ioc->last_state ); + return -4; + } + + pfacts = &ioc->pfacts0; + /* Nth (2,3,...) time thru? (been here, done that?) */ + if (ioc->pfacts0.Function == MPI_FUNCTION_PORT_FACTS) { + pfacts = &ioc->pfactsN; + } + + /* Destination (reply area)... */ + reply_sz = sizeof(*pfacts); + memset(pfacts, 0, reply_sz); + + /* Request area (get_pfacts on the stack right now!) */ + req_sz = sizeof(get_pfacts); + memset(&get_pfacts, 0, req_sz); + + get_pfacts.Function = MPI_FUNCTION_PORT_FACTS; + /* Assert: All other get_pfacts fields are zero! */ + + dprintk((KERN_INFO MYNAM ": %s: Sending PortFacts%s request\n", + ioc->name, pfacts == &ioc->pfacts0 ? "0" : "N" )); + + /* No non-zero fields in the get_pfacts request are greater than + * 1 byte in size, so we can just fire it off as is. + */ + i = HandShakeReqAndReply(ioc, req_sz, (u32*)&get_pfacts, + reply_sz, (u16*)pfacts); + if (i != 0) + return i; + + /* Did we get a valid reply? */ + + /* Now byte swap the necessary fields in the response. */ + pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext); + pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus); + pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo); + pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices); + pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID); + pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags); + pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers); + pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs); + pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets); + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * SendIocInit - Send IOCInit request to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * + * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state. + * + * Returns 0 for success, non-zero for failure. + */ +static int +SendIocInit(MPT_ADAPTER *ioc) +{ + IOCInit_t ioc_init; + MPIDefaultReply_t init_reply; + u32 state; + int r; + int count; + int cntdn; + + memset(&ioc_init, 0, sizeof(ioc_init)); + memset(&init_reply, 0, sizeof(init_reply)); + + ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER; +/* ioc_init.ChainOffset = 0; */ + ioc_init.Function = MPI_FUNCTION_IOC_INIT; +/* ioc_init.Flags = 0; */ + + /*ioc_init.MaxDevices = 16;*/ + ioc_init.MaxDevices = 255; +/* ioc_init.MaxBuses = 16; */ + ioc_init.MaxBuses = 1; + +/* ioc_init.MsgFlags = 0; */ +/* ioc_init.MsgContext = cpu_to_le32(0x00000000); */ + ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */ + ioc_init.HostMfaHighAddr = cpu_to_le32(0); /* Say we 32-bit! for now */ + + dprintk((KERN_INFO MYNAM ": %s: Sending IOCInit (req @ %p)\n", ioc->name, &ioc_init)); + + r = HandShakeReqAndReply(ioc, sizeof(IOCInit_t), (u32*)&ioc_init, + sizeof(MPIDefaultReply_t), (u16*)&init_reply); + if (r != 0) + return r; + + /* No need to byte swap the multibyte fields in the reply + * since we don't even look at it's contents. + */ + + if ((r = SendPortEnable(ioc, 0)) != 0) + return r; + + /* YIKES! SUPER IMPORTANT!!! + * Poll IocState until _OPERATIONAL while IOC is doing + * LoopInit and TargetDiscovery! + */ + count = 0; + cntdn = HZ * 60; /* chg'd from 30 to 60 seconds */ + state = GetIocState(ioc, 1); + while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + + if (!cntdn) { + printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_OP state timeout(%d)!\n", + ioc->name, (count+5)/HZ); + return -9; + } + + state = GetIocState(ioc, 1); + count++; + } + dhsprintk((KERN_INFO MYNAM ": %s: INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n", + ioc->name, count)); + + return r; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * SendPortEnable - Send PortEnable request to MPT adapter port. + * @ioc: Pointer to MPT_ADAPTER structure + * @portnum: Port number to enable + * + * Send PortEnable to bring IOC to OPERATIONAL state. + * + * Returns 0 for success, non-zero for failure. + */ +static int +SendPortEnable(MPT_ADAPTER *ioc, int portnum) +{ + PortEnable_t port_enable; + MPIDefaultReply_t reply_buf; + int i; + int req_sz; + int reply_sz; + + /* Destination... */ + reply_sz = sizeof(MPIDefaultReply_t); + memset(&reply_buf, 0, reply_sz); + + req_sz = sizeof(PortEnable_t); + memset(&port_enable, 0, req_sz); + + port_enable.Function = MPI_FUNCTION_PORT_ENABLE; + port_enable.PortNumber = portnum; +/* port_enable.ChainOffset = 0; */ +/* port_enable.MsgFlags = 0; */ +/* port_enable.MsgContext = 0; */ + + dprintk((KERN_INFO MYNAM ": %s: Sending Port(%d)Enable (req @ %p)\n", + ioc->name, portnum, &port_enable)); + + i = HandShakeReqAndReply(ioc, req_sz, (u32*)&port_enable, + reply_sz, (u16*)&reply_buf); + if (i != 0) + return i; + + /* We do not even look at the reply, so we need not + * swap the multi-byte fields. + */ + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * KickStart - Perform hard reset of MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * + * This routine places MPT adapter in diagnostic mode via the + * WriteSequence register, and then performs a hard reset of adapter + * via the Diagnostic register. + * + * Returns 0 for success, non-zero for failure. + */ +static int +KickStart(MPT_ADAPTER *ioc) +{ + int r; + u32 ioc_state; + int cnt = 0; + + dprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name)); + + if (ioc->chip_type == FC909) { + r = mpt_fc9x9_reset(ioc); + } else if (ioc->chip_type == FC929) { + unsigned long delta; + + delta = jiffies - ioc->last_kickstart; + dprintk((KERN_INFO MYNAM ": %s: 929 KickStart, last=%ld, delta = %ld\n", + ioc->name, ioc->last_kickstart, delta)); + if ((ioc->sod_reset == 0) || (delta >= 10*HZ)) + r = mpt_fc9x9_reset(ioc); + else { + dprintk((KERN_INFO MYNAM ": %s: Skipping KickStart (delta=%ld)!\n", + ioc->name, delta)); + return 0; + } + /* TODO! Add FC919! + } else if (ioc->chip_type == FC919) { + */ + /* TODO! Add C1030! + } else if (ioc->chip_type == C1030) { + */ + } else { + printk(KERN_ERR MYNAM ": %s: ERROR - Bad chip_type (0x%x)\n", + ioc->name, ioc->chip_type); + return -5; + } + + if (r != 0) + return -r; + + dprintk((KERN_INFO MYNAM ": %s: Diagnostic reset successful\n", + ioc->name)); + + for (cnt=0; cnt<HZ*20; cnt++) { + if ((ioc_state = GetIocState(ioc, 1)) == MPI_IOC_STATE_READY) { + dprintk((KERN_INFO MYNAM ": %s: KickStart successful! (cnt=%d)\n", + ioc->name, cnt)); + return 0; + } + /* udelay(10000) ? */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + + printk(KERN_ERR MYNAM ": %s: ERROR - Failed to come READY after reset!\n", + ioc->name); + return -1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mpt_fc9x9_reset - Perform hard reset of FC9x9 adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * + * This routine places FC9x9 adapter in diagnostic mode via the + * WriteSequence register, and then performs a hard reset of adapter + * via the Diagnostic register. + * + * Returns 0 for success, non-zero for failure. + */ +static int +mpt_fc9x9_reset(MPT_ADAPTER *ioc) +{ + u32 diagval; + + /* Use "Diagnostic reset" method! (only thing available!) */ + + /* + * Extra read to handle 909 B.0 chip problem with reset + * logic not finishing the RAM access before hard reset hits. + * (? comment taken from NT SYMMPI source) + */ + (void) CHIPREG_READ32(&ioc->chip->Fubar); + + /* + * Write magic sequence to WriteSequence register. + * But, send 0x0F first to insure a reset to the beginning of the sequence. + */ + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_KEY_VALUE_MASK); + + /* Now write magic sequence */ + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); + dprintk((KERN_INFO MYNAM ": %s: Wrote magic DiagWriteEn sequence\n", + ioc->name)); + + /* Now hit the reset bit in the Diagnostic register */ + CHIPREG_WRITE32(&ioc->chip->Diagnostic, MPI_DIAG_RESET_ADAPTER); + + udelay(100); + + if ((diagval = CHIPREG_READ32(&ioc->chip->Diagnostic)) & + (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_DISABLE_ARM)) { + printk(KERN_ERR MYNAM ": %s: ERROR - Diagnostic reset FAILED!\n", + ioc->name); + return -9; + } + + /* TODO! + * Cleanup all event stuff for this IOC; + * re-issue EventNotification request if needed. + */ + if (ioc->factsN.Function) + ioc->factsN.EventState = 0; + + /* NEW! 20010220 -sralston + * Try to avoid redundant resets of the 929. + */ + ioc->sod_reset++; + ioc->last_kickstart = jiffies; + if (ioc->alt_ioc) { + ioc->alt_ioc->sod_reset = ioc->sod_reset; + ioc->alt_ioc->last_kickstart = ioc->last_kickstart; + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * SendIocReset - Send IOCReset request to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * @reset_type: reset type, expected values are + * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET + * + * Send IOCReset request to the MPT adapter. + * + * Returns 0 for success, non-zero for failure. + */ +static int +SendIocReset(MPT_ADAPTER *ioc, u8 reset_type) +{ + int r; + + printk(KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n", + ioc->name, reset_type); + CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT); + if ((r = WaitForDoorbellAck(ioc)) < 0) + return r; + + /* TODO! + * Cleanup all event stuff for this IOC; re-issue EventNotification + * request if needed. + */ + if (ioc->factsN.Function) + ioc->factsN.EventState = 0; + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * PrimeIocFifos - Initialize IOC request and reply FIFOs. + * @ioc: Pointer to MPT_ADAPTER structure + * + * This routine allocates memory for the MPT reply and request frame + * pools, and primes the IOC reply FIFO with reply frames. + * + * Returns 0 for success, non-zero for failure. + */ +static int +PrimeIocFifos(MPT_ADAPTER *ioc) +{ + MPT_FRAME_HDR *mf; + unsigned long b; + dma_addr_t aligned_mem_dma; + u8 *mem, *aligned_mem; + int i, sz; + + /* Prime reply FIFO... */ + + if (ioc->reply_frames == NULL) { + sz = (ioc->reply_sz * ioc->reply_depth) + 128; + mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->reply_alloc_dma); + if (mem == NULL) + goto out_fail; + + memset(mem, 0, sz); + ioc->alloc_total += sz; + ioc->reply_alloc = mem; + dprintk((KERN_INFO MYNAM ": %s.reply_alloc @ %p[%08x], sz=%d bytes\n", + ioc->name, mem, ioc->reply_alloc_dma, sz)); + + b = (unsigned long) mem; + b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */ + aligned_mem = (u8 *) b; + ioc->reply_frames = (MPT_FRAME_HDR *) aligned_mem; + ioc->reply_frames_dma = + (ioc->reply_alloc_dma + (aligned_mem - mem)); + aligned_mem_dma = ioc->reply_frames_dma; + dprintk((KERN_INFO MYNAM ": %s.reply_frames @ %p[%08x]\n", + ioc->name, aligned_mem, aligned_mem_dma)); + + for (i = 0; i < ioc->reply_depth; i++) { + /* Write each address to the IOC! */ + CHIPREG_WRITE32(&ioc->chip->ReplyFifo, aligned_mem_dma); + aligned_mem_dma += ioc->reply_sz; + } + } + + + /* Request FIFO - WE manage this! */ + + if (ioc->req_frames == NULL) { + sz = (ioc->req_sz * ioc->req_depth) + 128; + /* + * Rounding UP to nearest 4-kB boundary here... + */ + sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000; + + mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->req_alloc_dma); + if (mem == NULL) + goto out_fail; + + memset(mem, 0, sz); + ioc->alloc_total += sz; + ioc->req_alloc = mem; + dprintk((KERN_INFO MYNAM ": %s.req_alloc @ %p[%08x], sz=%d bytes\n", + ioc->name, mem, ioc->req_alloc_dma, sz)); + + b = (unsigned long) mem; + b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */ + aligned_mem = (u8 *) b; + ioc->req_frames = (MPT_FRAME_HDR *) aligned_mem; + ioc->req_frames_dma = + (ioc->req_alloc_dma + (aligned_mem - mem)); + aligned_mem_dma = ioc->req_frames_dma; + + dprintk((KERN_INFO MYNAM ": %s.req_frames @ %p[%08x]\n", + ioc->name, aligned_mem, aligned_mem_dma)); + + for (i = 0; i < ioc->req_depth; i++) { + mf = (MPT_FRAME_HDR *) aligned_mem; + + /* Queue REQUESTs *internally*! */ + Q_ADD_TAIL(&ioc->FreeQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR); + aligned_mem += ioc->req_sz; + } + +#if defined(CONFIG_MTRR) && 0 + /* + * Enable Write Combining MTRR for IOC's memory region. + * (at least as much as we can; "size and base must be + * multiples of 4 kiB" + */ + ioc->mtrr_reg = mtrr_add(ioc->req_alloc_dma, + sz, + MTRR_TYPE_WRCOMB, 1); + dprintk((KERN_INFO MYNAM ": %s: MTRR region registered (base:size=%08x:%x)\n", + ioc->name, ioc->req_alloc_dma, + sz )); +#endif + + } + + if (ioc->sense_buf_pool == NULL) { + sz = (ioc->req_depth * 256); + ioc->sense_buf_pool = + pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma); + if (ioc->sense_buf_pool == NULL) + goto out_fail; + + ioc->alloc_total += sz; + } + + return 0; + +out_fail: + if (ioc->reply_alloc != NULL) { + sz = (ioc->reply_sz * ioc->reply_depth) + 128; + pci_free_consistent(ioc->pcidev, + sz, + ioc->reply_alloc, ioc->reply_alloc_dma); + ioc->reply_frames = NULL; + ioc->reply_alloc = NULL; + ioc->alloc_total -= sz; + } + if (ioc->req_alloc != NULL) { + sz = (ioc->req_sz * ioc->req_depth) + 128; + /* + * Rounding UP to nearest 4-kB boundary here... + */ + sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000; + pci_free_consistent(ioc->pcidev, + sz, + ioc->req_alloc, ioc->req_alloc_dma); +#if defined(CONFIG_MTRR) && 0 + if (ioc->mtrr_reg > 0) { + mtrr_del(ioc->mtrr_reg, 0, 0); + dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", + ioc->name)); + } +#endif + ioc->req_frames = NULL; + ioc->req_alloc = NULL; + ioc->alloc_total -= sz; + } + if (ioc->sense_buf_pool != NULL) { + sz = (ioc->req_depth * 256); + pci_free_consistent(ioc->pcidev, + sz, + ioc->sense_buf_pool, ioc->sense_buf_pool_dma); + ioc->sense_buf_pool = NULL; + } + return -1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * HandShakeReqAndReply - Send MPT request to and receive reply from + * IOC via doorbell handshake method. + * @ioc: Pointer to MPT_ADAPTER structure + * @reqBytes: Size of the request in bytes + * @req: Pointer to MPT request frame + * @replyBytes: Expected size of the reply in bytes + * @u16reply: Pointer to area where reply should be written + * + * NOTES: It is the callers responsibility to byte-swap fields in the + * request which are greater than 1 byte in size. It is also the + * callers responsibility to byte-swap response fields which are + * greater than 1 byte in size. + * + * Returns 0 for success, non-zero for failure. + */ +static int +HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply) +{ + MPIDefaultReply_t *mptReply; + int failcnt = 0; + int t; + + /* + * Get ready to cache a handshake reply + */ + ioc->hs_reply_idx = 0; + mptReply = (MPIDefaultReply_t *) ioc->hs_reply; + mptReply->MsgLength = 0; + + /* + * Make sure there are no doorbells (WRITE 0 to IntStatus reg), + * then tell IOC that we want to handshake a request of N words. + * (WRITE u32val to Doorbell reg). + */ + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + CHIPREG_WRITE32(&ioc->chip->Doorbell, + ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) | + ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT))); + + /* + * Wait for IOC's doorbell handshake int + */ + if ((t = WaitForDoorbellInt(ioc)) < 0) + failcnt++; + + dhsprintk((KERN_INFO MYNAM ": %s: HandShake request start, WaitCnt=%d%s\n", + ioc->name, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); + + /* + * Clear doorbell int (WRITE 0 to IntStatus reg), + * then wait for IOC to ACKnowledge that it's ready for + * our handshake request. + */ + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + if (!failcnt && (t = WaitForDoorbellAck(ioc)) < 0) + failcnt++; + + if (!failcnt) { + int i; + u8 *req_as_bytes = (u8 *) req; + + /* + * Stuff request words via doorbell handshake, + * with ACK from IOC for each. + */ + for (i = 0; !failcnt && i < reqBytes/4; i++) { + u32 word = ((req_as_bytes[(i*4) + 0] << 0) | + (req_as_bytes[(i*4) + 1] << 8) | + (req_as_bytes[(i*4) + 2] << 16) | + (req_as_bytes[(i*4) + 3] << 24)); + + CHIPREG_WRITE32(&ioc->chip->Doorbell, word); + if ((t = WaitForDoorbellAck(ioc)) < 0) + failcnt++; + } + + dmfprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req)); + DBG_DUMP_REQUEST_FRAME_HDR(req) + + dhsprintk((KERN_INFO MYNAM ": %s: HandShake request post done, WaitCnt=%d%s\n", + ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : "")); + + /* + * Wait for completion of doorbell handshake reply from the IOC + */ + if (!failcnt && (t = WaitForDoorbellReply(ioc)) < 0) + failcnt++; + + /* + * Copy out the cached reply... + */ + for(i=0; i < MIN(replyBytes/2,mptReply->MsgLength*2); i++) + u16reply[i] = ioc->hs_reply[i]; + } else { + return -99; + } + + return -failcnt; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit + * in it's IntStatus register. + * @ioc: Pointer to MPT_ADAPTER structure + * + * This routine waits (up to ~30 seconds max) for IOC doorbell + * handshake ACKnowledge. + * + * Returns a negative value on failure, else wait loop count. + */ +static int +WaitForDoorbellAck(MPT_ADAPTER *ioc) +{ + int cntdn = HZ * 30; /* ~30 seconds */ + int count = 0; + u32 intstat; + + while (--cntdn) { + intstat = CHIPREG_READ32(&ioc->chip->IntStatus); + if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS)) + break; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + count++; + } + + if (cntdn) { + dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell ACK (cnt=%d)\n", + ioc->name, count)); + return count; + } + + printk(KERN_ERR MYNAM ": %s: ERROR - Doorbell ACK timeout(%d)!\n", + ioc->name, (count+5)/HZ); + return -1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit + * in it's IntStatus register. + * @ioc: Pointer to MPT_ADAPTER structure + * + * This routine waits (up to ~30 seconds max) for IOC doorbell interrupt. + * + * Returns a negative value on failure, else wait loop count. + */ +static int +WaitForDoorbellInt(MPT_ADAPTER *ioc) +{ + int cntdn = HZ * 30; /* ~30 seconds */ + int count = 0; + u32 intstat; + + while (--cntdn) { + intstat = CHIPREG_READ32(&ioc->chip->IntStatus); + if (intstat & MPI_HIS_DOORBELL_INTERRUPT) + break; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + count++; + } + + if (cntdn) { + dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell INT (cnt=%d)\n", + ioc->name, count)); + return count; + } + + printk(KERN_ERR MYNAM ": %s: ERROR - Doorbell INT timeout(%d)!\n", + ioc->name, (count+5)/HZ); + return -1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * WaitForDoorbellReply - Wait for and capture a IOC handshake reply. + * @ioc: Pointer to MPT_ADAPTER structure + * + * This routine polls the IOC for a handshake reply, 16 bits at a time. + * Reply is cached to IOC private area large enough to hold a maximum + * of 128 bytes of reply data. + * + * Returns a negative value on failure, else size of reply in WORDS. + */ +static int +WaitForDoorbellReply(MPT_ADAPTER *ioc) +{ + int u16cnt = 0; + int failcnt = 0; + int t; + u16 *hs_reply = ioc->hs_reply; + volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply; + u16 hword; + + hs_reply[0] = hs_reply[1] = hs_reply[7] = 0; + + /* + * Get first two u16's so we can look at IOC's intended reply MsgLength + */ + for (u16cnt=0; !failcnt && u16cnt < 2; u16cnt++) { + if ((t = WaitForDoorbellInt(ioc)) < 0) + failcnt++; + hs_reply[u16cnt] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + } + + dhsprintk((KERN_INFO MYNAM ": %s: First handshake reply word=%08x%s\n", + ioc->name, le32_to_cpu(*(u32 *)hs_reply), + failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); + + /* + * If no error (and IOC said MsgLength is > 0), piece together + * reply 16 bits at a time. + */ + for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) { + if ((t = WaitForDoorbellInt(ioc)) < 0) + failcnt++; + hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); + /* don't overflow our IOC hs_reply[] buffer! */ + if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0])) + hs_reply[u16cnt] = hword; + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + } + + if (!failcnt && (t = WaitForDoorbellInt(ioc)) < 0) + failcnt++; + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + + if (failcnt) { + printk(KERN_ERR MYNAM ": %s: ERROR - Handshake reply failure!\n", + ioc->name); + return -failcnt; + } +#if 0 + else if (u16cnt != (2 * mptReply->MsgLength)) { + return -101; + } + else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { + return -102; + } +#endif + + dmfprintk((KERN_INFO MYNAM ": %s: Got Handshake reply:\n", ioc->name)); + DBG_DUMP_REPLY_FRAME(mptReply) + + dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell REPLY (sz=%d)\n", + ioc->name, u16cnt/2)); + return u16cnt/2; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * GetLanConfigPages - Fetch LANConfig pages. + * @ioc: Pointer to MPT_ADAPTER structure + * + * Returns 0 for success, non-zero for failure. + */ +static int +GetLanConfigPages(MPT_ADAPTER *ioc) +{ + Config_t config_req; + ConfigReply_t config_reply; + LANPage0_t *page0; + dma_addr_t page0_dma; + LANPage1_t *page1; + dma_addr_t page1_dma; + int i; + int req_sz; + int reply_sz; + int data_sz; + +/* LANPage0 */ + /* Immediate destination (reply area)... */ + reply_sz = sizeof(config_reply); + memset(&config_reply, 0, reply_sz); + + /* Ultimate destination... */ + page0 = &ioc->lan_cnfg_page0; + data_sz = sizeof(*page0); + memset(page0, 0, data_sz); + + /* Request area (config_req on the stack right now!) */ + req_sz = sizeof(config_req); + memset(&config_req, 0, req_sz); + config_req.Function = MPI_FUNCTION_CONFIG; + config_req.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + /* config_req.Header.PageVersion = 0; */ + /* config_req.Header.PageLength = 0; */ + config_req.Header.PageNumber = 0; + config_req.Header.PageType = MPI_CONFIG_PAGETYPE_LAN; + /* config_req.PageAddress = 0; */ + config_req.PageBufferSGE.u.Simple.FlagsLength = cpu_to_le32( + ((MPI_SGE_FLAGS_LAST_ELEMENT | + MPI_SGE_FLAGS_END_OF_BUFFER | + MPI_SGE_FLAGS_END_OF_LIST | + MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_SYSTEM_ADDRESS | + MPI_SGE_FLAGS_32_BIT_ADDRESSING | + MPI_SGE_FLAGS_32_BIT_CONTEXT) << MPI_SGE_FLAGS_SHIFT) | + (u32)data_sz + ); + page0_dma = pci_map_single(ioc->pcidev, page0, data_sz, PCI_DMA_FROMDEVICE); + config_req.PageBufferSGE.u.Simple.u.Address32 = cpu_to_le32(page0_dma); + + dprintk((KERN_INFO MYNAM ": %s: Sending Config request LAN_PAGE_0\n", + ioc->name)); + + i = HandShakeReqAndReply(ioc, req_sz, (u32*)&config_req, + reply_sz, (u16*)&config_reply); + pci_unmap_single(ioc->pcidev, page0_dma, data_sz, PCI_DMA_FROMDEVICE); + if (i != 0) + return i; + + /* Now byte swap the necessary LANPage0 fields */ + +/* LANPage1 */ + /* Immediate destination (reply area)... */ + reply_sz = sizeof(config_reply); + memset(&config_reply, 0, reply_sz); + + /* Ultimate destination... */ + page1 = &ioc->lan_cnfg_page1; + data_sz = sizeof(*page1); + memset(page1, 0, data_sz); + + /* Request area (config_req on the stack right now!) */ + req_sz = sizeof(config_req); + memset(&config_req, 0, req_sz); + config_req.Function = MPI_FUNCTION_CONFIG; + config_req.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + /* config_req.Header.PageVersion = 0; */ + /* config_req.Header.PageLength = 0; */ + config_req.Header.PageNumber = 1; + config_req.Header.PageType = MPI_CONFIG_PAGETYPE_LAN; + /* config_req.PageAddress = 0; */ + config_req.PageBufferSGE.u.Simple.FlagsLength = cpu_to_le32( + ((MPI_SGE_FLAGS_LAST_ELEMENT | + MPI_SGE_FLAGS_END_OF_BUFFER | + MPI_SGE_FLAGS_END_OF_LIST | + MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_SYSTEM_ADDRESS | + MPI_SGE_FLAGS_32_BIT_ADDRESSING | + MPI_SGE_FLAGS_32_BIT_CONTEXT) << MPI_SGE_FLAGS_SHIFT) | + (u32)data_sz + ); + page1_dma = pci_map_single(ioc->pcidev, page1, data_sz, PCI_DMA_FROMDEVICE); + config_req.PageBufferSGE.u.Simple.u.Address32 = cpu_to_le32(page1_dma); + + dprintk((KERN_INFO MYNAM ": %s: Sending Config request LAN_PAGE_1\n", + ioc->name)); + + i = HandShakeReqAndReply(ioc, req_sz, (u32*)&config_req, + reply_sz, (u16*)&config_reply); + pci_unmap_single(ioc->pcidev, page1_dma, data_sz, PCI_DMA_FROMDEVICE); + if (i != 0) + return i; + + /* Now byte swap the necessary LANPage1 fields */ + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * SendEventNotification - Send EventNotification (on or off) request + * to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * @EvSwitch: Event switch flags + */ +static int +SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch) +{ + EventNotification_t *evnp; + + evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc->id); + if (evnp == NULL) { + dprintk((KERN_WARNING MYNAM ": %s: WARNING - Unable to allocate a event request frame!\n", + ioc->name)); + return 0; + } + memset(evnp, 0, sizeof(*evnp)); + + dprintk((KERN_INFO MYNAM ": %s: Sending EventNotification(%d)\n", ioc->name, EvSwitch)); + + evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION; + evnp->ChainOffset = 0; + evnp->MsgFlags = 0; + evnp->Switch = EvSwitch; + + mpt_put_msg_frame(mpt_base_index, ioc->id, (MPT_FRAME_HDR *)evnp); + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * SendEventAck - Send EventAck request to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * @evnp: Pointer to original EventNotification request + */ +static int +SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp) +{ + EventAck_t *pAck; + + if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) { + printk(KERN_WARNING MYNAM ": %s: WARNING - Unable to allocate event ACK request frame!\n", + ioc->name); + return -1; + } + memset(pAck, 0, sizeof(*pAck)); + + dprintk((KERN_INFO MYNAM ": %s: Sending EventAck\n", ioc->name)); + + pAck->Function = MPI_FUNCTION_EVENT_ACK; + pAck->ChainOffset = 0; + pAck->MsgFlags = 0; + pAck->Event = evnp->Event; + pAck->EventContext = evnp->EventContext; + + mpt_put_msg_frame(mpt_base_index, ioc->id, (MPT_FRAME_HDR *)pAck); + + return 0; +} + +#ifdef CONFIG_PROC_FS /* { */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff... + */ + +#define PROC_MPT_READ_RETURN(page,start,off,count,eof,len) \ +{ \ + len -= off; \ + if (len < count) { \ + *eof = 1; \ + if (len <= 0) \ + return 0; \ + } else \ + len = count; \ + *start = page + off; \ + return len; \ +} + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries. + * + * Returns 0 for success, non-zero for failure. + */ +static int +procmpt_create(void) +{ + MPT_ADAPTER *ioc; + struct proc_dir_entry *ent; + int errcnt = 0; + + /* + * BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt" + * (single level) to multi level (e.g. "driver/message/fusion") + * something here needs to change. -sralston + */ + procmpt_root_dir = CREATE_PROCDIR_ENTRY(MPT_PROCFS_MPTBASEDIR, NULL); + if (procmpt_root_dir == NULL) + return -ENOTDIR; + + if ((ioc = mpt_adapter_find_first()) != NULL) { + ent = create_proc_read_entry(MPT_PROCFS_SUMMARY_NODE, 0, NULL, procmpt_read_summary, NULL); + if (ent == NULL) { + printk(KERN_WARNING MYNAM ": WARNING - Could not create %s entry!\n", + MPT_PROCFS_SUMMARY_PATHNAME); + errcnt++; + } + } + + while (ioc != NULL) { + char pname[32]; + int namelen; + /* + * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter. + */ + namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name); + if ((ent = CREATE_PROCDIR_ENTRY(pname, NULL)) != NULL) { + /* + * And populate it with: "summary" and "dbg" file entries. + */ + (void) sprintf(pname+namelen, "/summary"); + ent = create_proc_read_entry(pname, 0, NULL, procmpt_read_summary, ioc); + if (ent == NULL) { + errcnt++; + printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n", + ioc->name, pname); + } +//#ifdef MPT_DEBUG + /* DEBUG aid! */ + (void) sprintf(pname+namelen, "/dbg"); + ent = create_proc_read_entry(pname, 0, NULL, procmpt_read_dbg, ioc); + if (ent == NULL) { + errcnt++; + printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n", + ioc->name, pname); + } +//#endif + } else { + errcnt++; + printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n", + ioc->name, pname); + + } + + ioc = mpt_adapter_find_next(ioc); + } + + if (errcnt) { +// remove_proc_entry("mpt", 0); + return -ENOTDIR; + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries. + * + * Returns 0 for success, non-zero for failure. + */ +static int +procmpt_destroy(void) +{ + MPT_ADAPTER *ioc; + + /* + * BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt" + * (single level) to multi level (e.g. "driver/message/fusion") + * something here needs to change. -sralston + */ + + ioc = mpt_adapter_find_first(); + if (ioc != NULL) { + remove_proc_entry(MPT_PROCFS_SUMMARY_NODE, 0); + } + + while (ioc != NULL) { + char pname[32]; + int namelen; + /* + * Tear down each "/proc/mpt/iocN" subdirectory. + */ + namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name); + (void) sprintf(pname+namelen, "/summary"); + remove_proc_entry(pname, 0); +//#ifdef MPT_DEBUG + (void) sprintf(pname+namelen, "/dbg"); + remove_proc_entry(pname, 0); +//#endif + (void) sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name); + remove_proc_entry(pname, 0); + + ioc = mpt_adapter_find_next(ioc); + } + + if (atomic_read((atomic_t *)&procmpt_root_dir->count) == 0) { + remove_proc_entry(MPT_PROCFS_MPTBASEDIR, 0); + return 0; + } + + return -1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * procmpt_read_summary - Handle read request from /proc/mpt/summary + * or from /proc/mpt/iocN/summary. + * @page: Pointer to area to write information + * @start: Pointer to start pointer + * @off: Offset to start writing + * @count: + * @eof: Pointer to EOF integer + * @data: Pointer + * + * Returns numbers of characters written to process performing the read. + */ +static int +procmpt_read_summary(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + MPT_ADAPTER *ioc; + char *out = page; + int len; + + if (data == NULL) + ioc = mpt_adapter_find_first(); + else + ioc = data; + +// Too verbose! +// out += sprintf(out, "Attached Fusion MPT I/O Controllers:%s\n", ioc ? "" : " none"); + + while (ioc) { + int more = 0; + +// Too verbose! +// mpt_print_ioc_facts(ioc, out, &more, 0); + mpt_print_ioc_summary(ioc, out, &more, 0); + + out += more; + if ((out-page) >= count) { + break; + } + + if (data == NULL) + ioc = mpt_adapter_find_next(ioc); + else + ioc = NULL; /* force exit for iocN */ + } + len = out - page; + + PROC_MPT_READ_RETURN(page,start,off,count,eof,len); +} + +// debug aid! +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * procmpt_read_dbg - Handle read request from /proc/mpt/iocN/dbg. + * @page: Pointer to area to write information + * @start: Pointer to start pointer + * @off: Offset to start writing + * @count: + * @eof: Pointer to EOF integer + * @data: Pointer + * + * Returns numbers of characters written to process performing the read. + */ +static int +procmpt_read_dbg(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + MPT_ADAPTER *ioc; + char *out = page; + int len; + + ioc = data; + + while (ioc) { + int more = 0; + + mpt_print_ioc_facts(ioc, out, &more, 0); + + out += more; + if ((out-page) >= count) { + break; + } + ioc = NULL; + } + len = out - page; + + PROC_MPT_READ_RETURN(page,start,off,count,eof,len); +} +#endif /* CONFIG_PROC_FS } */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static void +mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc) +{ + if ((ioc->facts0.FWVersion & 0xF000) == 0xE000) + sprintf(buf, " (Exp %02d%02d)", + (ioc->facts0.FWVersion & 0x0F00) >> 8, /* Month */ + ioc->facts0.FWVersion & 0x001F); /* Day */ + else + buf[0] ='\0'; + + /* insider hack! */ + if (ioc->facts0.FWVersion & 0x0080) { + strcat(buf, " [MDBG]"); + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer. + * @ioc: Pointer to MPT_ADAPTER structure + * @buffer: Pointer to buffer where IOC summary info should be written + * @size: Pointer to number of bytes we wrote (set by this routine) + * @len: Offset at which to start writing in buffer + * + * This routine writes (english readable) ASCII text, which represents + * a summary of IOC information, to a buffer. + */ +void +mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len) +{ + char expVer[32]; + int y; + + + mpt_get_fw_exp_ver(expVer, ioc); + + /* + * Shorter summary of attached ioc's... + */ + y = sprintf(buffer+len, "%s: %s, %s%04xh%s, Ports=%d, MaxQ=%d", + ioc->name, + ioc->prod_name, + MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */ + ioc->facts0.FWVersion, + expVer, + ioc->facts0.NumberOfPorts, + ioc->req_depth); + + if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { + u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; + y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X", + a[5], a[4], a[3], a[2], a[1], a[0]); + } + + if (!ioc->active) + y += sprintf(buffer+len+y, " (disabled)"); + + y += sprintf(buffer+len+y, "\n"); + + *size = y; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_print_ioc_facts - Write ASCII summary of IOC facts to a buffer. + * @ioc: Pointer to MPT_ADAPTER structure + * @buffer: Pointer to buffer where IOC facts should be written + * @size: Pointer to number of bytes we wrote (set by this routine) + * @len: Offset at which to start writing in buffer + * + * This routine writes (english readable) ASCII text, which represents + * a summary of the IOC facts, to a buffer. + */ +void +mpt_print_ioc_facts(MPT_ADAPTER *ioc, char *buffer, int *size, int len) +{ + char expVer[32]; + char iocName[16]; + int sz; + int y; + + + mpt_get_fw_exp_ver(expVer, ioc); + + strcpy(iocName, ioc->name); + y = sprintf(buffer+len, "%s:\n", iocName); + + y += sprintf(buffer+len+y, " ProductID = 0x%04x\n", ioc->facts0.ProductID); + y += sprintf(buffer+len+y, " PortNumber = %d (of %d)\n", + ioc->pfacts0.PortNumber+1, + ioc->facts0.NumberOfPorts); + if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { + u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; + y += sprintf(buffer+len+y, " LanAddr = 0x%02x:%02x:%02x:%02x:%02x:%02x\n", + a[5], a[4], a[3], a[2], a[1], a[0]); + } + y += sprintf(buffer+len+y, " FWVersion = 0x%04x%s\n", ioc->facts0.FWVersion, expVer); + y += sprintf(buffer+len+y, " MsgVersion = 0x%04x\n", ioc->facts0.MsgVersion); + y += sprintf(buffer+len+y, " WhoInit = 0x%02x\n", ioc->facts0.WhoInit); + y += sprintf(buffer+len+y, " EventState = 0x%02x\n", ioc->facts0.EventState); + y += sprintf(buffer+len+y, " CurrentHostMfaHighAddr = 0x%08x\n", + ioc->facts0.CurrentHostMfaHighAddr); + y += sprintf(buffer+len+y, " CurrentSenseBufferHighAddr = 0x%08x\n", + ioc->facts0.CurrentSenseBufferHighAddr); + y += sprintf(buffer+len+y, " MaxChainDepth = 0x%02x frames\n", ioc->facts0.MaxChainDepth); + y += sprintf(buffer+len+y, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts0.BlockSize); + + y += sprintf(buffer+len+y, " RequestFrames @ 0x%p (Dma @ 0x%08x)\n", + ioc->req_alloc, ioc->req_alloc_dma); + /* + * Rounding UP to nearest 4-kB boundary here... + */ + sz = (ioc->req_sz * ioc->req_depth) + 128; + sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000; + y += sprintf(buffer+len+y, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n", + ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz); + y += sprintf(buffer+len+y, " {MaxReqSz=%d} {MaxReqDepth=%d}\n", + 4*ioc->facts0.RequestFrameSize, + ioc->facts0.GlobalCredits); + + y += sprintf(buffer+len+y, " ReplyFrames @ 0x%p (Dma @ 0x%08x)\n", + ioc->reply_alloc, ioc->reply_alloc_dma); + sz = (ioc->reply_sz * ioc->reply_depth) + 128; + y += sprintf(buffer+len+y, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n", + ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz); + y += sprintf(buffer+len+y, " {MaxRepSz=%d} {MaxRepDepth=%d}\n", + ioc->factsN.CurReplyFrameSize, + ioc->facts0.ReplyQueueDepth); + + *size = y; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static char * +EventDescriptionStr(u8 event, u32 evData0) +{ + char *ds = NULL; + + switch(event) { + case MPI_EVENT_NONE: + ds = "None"; + break; + case MPI_EVENT_LOG_DATA: + ds = "Log Data"; + break; + case MPI_EVENT_STATE_CHANGE: + ds = "State Change"; + break; + case MPI_EVENT_UNIT_ATTENTION: + ds = "Unit Attention"; + break; + case MPI_EVENT_IOC_BUS_RESET: + ds = "IOC Bus Reset"; + break; + case MPI_EVENT_EXT_BUS_RESET: + ds = "External Bus Reset"; + break; + case MPI_EVENT_RESCAN: + ds = "Bus Rescan Event"; + /* Ok, do we need to do anything here? As far as + I can tell, this is when a new device gets added + to the loop. */ + break; + case MPI_EVENT_LINK_STATUS_CHANGE: + if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE) + ds = "Link Status(FAILURE) Change"; + else + ds = "Link Status(ACTIVE) Change"; + break; + case MPI_EVENT_LOOP_STATE_CHANGE: + if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP) + ds = "Loop State(LIP) Change"; + else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE) + ds = "Loop State(LPE) Change"; /* ??? */ + else + ds = "Loop State(LPB) Change"; /* ??? */ + break; + case MPI_EVENT_LOGOUT: + ds = "Logout"; + break; + case MPI_EVENT_EVENT_CHANGE: + if (evData0) + ds = "Events(ON) Change"; + else + ds = "Events(OFF) Change"; + break; + /* + * MPT base "custom" events may be added here... + */ + default: + ds = "Unknown"; + break; + } + return ds; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * ProcessEventNotification - Route a received EventNotificationReply to + * all currently regeistered event handlers. + * @ioc: Pointer to MPT_ADAPTER structure + * @pEventReply: Pointer to EventNotification reply frame + * @evHandlers: Pointer to integer, number of event handlers + * + * Returns sum of event handlers return values. + */ +static int +ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers) +{ + u16 evDataLen; + u32 evData0 = 0; +// u32 evCtx; + int i; + int r = 0; + int handlers = 0; + char *evStr; + u8 event; + + /* + * Do platform normalization of values + */ + event = le32_to_cpu(pEventReply->Event) & 0xFF; +// evCtx = le32_to_cpu(pEventReply->EventContext); + evDataLen = le16_to_cpu(pEventReply->EventDataLength); + if (evDataLen) { + evData0 = le32_to_cpu(pEventReply->Data[0]); + } + + evStr = EventDescriptionStr(event, evData0); + dprintk((KERN_INFO MYNAM ": %s: MPT event (%s=%02Xh) detected!\n", + ioc->name, + evStr, + event)); + +#if defined(MPT_DEBUG) || defined(MPT_DEBUG_EVENTS) + printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO); + for (i = 0; i < evDataLen; i++) + printk(" %08x", le32_to_cpu(pEventReply->Data[i])); + printk("\n"); +#endif + + /* + * Do general / base driver event processing + */ + switch(event) { + case MPI_EVENT_NONE: /* 00 */ + case MPI_EVENT_LOG_DATA: /* 01 */ + case MPI_EVENT_STATE_CHANGE: /* 02 */ + case MPI_EVENT_UNIT_ATTENTION: /* 03 */ + case MPI_EVENT_IOC_BUS_RESET: /* 04 */ + case MPI_EVENT_EXT_BUS_RESET: /* 05 */ + case MPI_EVENT_RESCAN: /* 06 */ + case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */ + case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */ + case MPI_EVENT_LOGOUT: /* 09 */ + default: + break; + case MPI_EVENT_EVENT_CHANGE: /* 0A */ + if (evDataLen) { + u8 evState = evData0 & 0xFF; + + /* CHECKME! What if evState unexpectedly says OFF (0)? */ + + /* Update EventState field in cached IocFacts */ + if (ioc->factsN.Function) { + ioc->factsN.EventState = evState; + } + } + break; + } + + /* + * Call each currently registered protocol event handler. + */ + for (i=MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) { + if (MptEvHandlers[i]) { + dprintk((KERN_INFO MYNAM ": %s: Routing Event to event handler #%d\n", + ioc->name, i)); + r += (*(MptEvHandlers[i]))(ioc, pEventReply); + handlers++; + } + } + /* FIXME? Examine results here? */ + + /* + * If needed, send (a single) EventAck. + */ + if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) { + if ((i = SendEventAck(ioc, pEventReply)) != 0) { + } + } + + *evHandlers = handlers; + return r; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mpt_fc_log_info - Log information returned from Fibre Channel IOC. + * @ioc: Pointer to MPT_ADAPTER structure + * @log_info: U32 LogInfo reply word from the IOC + * + * Refer to lsi/fc_log.h. + */ +static void +mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info) +{ + static char *subcl_str[8] = { + "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer", + "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info" + }; + char *desc = "unknown"; + u8 subcl = (log_info >> 24) & 0x7; + u32 SubCl = log_info & 0x27000000; + + switch(log_info) { +/* FCP Initiator */ + case MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME: + desc = "Received an out of order frame - unsupported"; + break; + case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME: + desc = "Bad start of frame primative"; + break; + case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME: + desc = "Bad end of frame primative"; + break; + case MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN: + desc = "Receiver hardware detected overrun"; + break; + case MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER: + desc = "Other errors caught by IOC which require retries"; + break; + case MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD: + desc = "Main processor could not initialize sub-processor"; + break; +/* FC Target */ + case MPI_IOCLOGINFO_FC_TARGET_NO_PDISC: + desc = "Not sent because we are waiting for a PDISC from the initiator"; + break; + case MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN: + desc = "Not sent because we are not logged in to the remote node"; + break; + case MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP: + desc = "Data Out, Auto Response, not sent due to a LIP"; + break; + case MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP: + desc = "Data In, Auto Response, not sent due to a LIP"; + break; + case MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA: + desc = "Data In, Auto Response, missing data frames"; + break; + case MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP: + desc = "Data Out, No Response, not sent due to a LIP"; + break; + case MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP: + desc = "Auto-response after a write not sent due to a LIP"; + break; + case MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP: + desc = "Data In, No Response, not completed due to a LIP"; + break; + case MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA: + desc = "Data In, No Response, missing data frames"; + break; + case MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP: + desc = "Manual Response not sent due to a LIP"; + break; + case MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3: + desc = "Not sent because remote node does not support Class 3"; + break; + case MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID: + desc = "Not sent because login to remote node not validated"; + break; + case MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND: + desc = "Cleared from the outbound after a logout"; + break; + case MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN: + desc = "Cleared waiting for data after a logout"; + break; +/* LAN */ + case MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING: + desc = "Transaction Context Sgl Missing"; + break; + case MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE: + desc = "Transaction Context found before an EOB"; + break; + case MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET: + desc = "Transaction Context value has reserved bits set"; + break; + case MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG: + desc = "Invalid SGL Flags"; + break; +/* FC Link */ + case MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT: + desc = "Loop initialization timed out"; + break; + case MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED: + desc = "Another system controller already initialized the loop"; + break; + case MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED: + desc = "Not synchronized to signal or still negotiating (possible cable problem)"; + break; + } + + printk(KERN_INFO MYNAM ": %s: LogInfo(0x%08x): SubCl={%s}", + ioc->name, log_info, subcl_str[subcl]); + if (SubCl == MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET) + printk(", byte_offset=%d\n", log_info & MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET); + else if (SubCl == MPI_IOCLOGINFO_FC_STATE_CHANGE) + printk("\n"); /* StateChg in LogInfo & 0x00FFFFFF, above */ + else + printk("\n" KERN_INFO " %s\n", desc); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mpt_sp_log_info - Log information returned from SCSI Parallel IOC. + * @ioc: Pointer to MPT_ADAPTER structure + * @mr: Pointer to MPT reply frame + * @log_info: U32 LogInfo word from the IOC + * + * Refer to lsi/sp_log.h. + */ +static void +mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info) +{ + /* FIXME! */ + printk(KERN_INFO MYNAM ": %s: LogInfo(0x%08x)\n", ioc->name, log_info); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_register_ascqops_strings - Register SCSI ASC/ASCQ and SCSI + * OpCode strings from the (optional) isense module. + * @ascqTable: Pointer to ASCQ_Table_t structure + * @ascqtbl_sz: Number of entries in ASCQ_Table + * @opsTable: Pointer to array of SCSI OpCode strings (char pointers) + * + * Specialized driver registration routine for the isense driver. + */ +int +mpt_register_ascqops_strings(/*ASCQ_Table_t*/void *ascqTable, int ascqtbl_sz, const char **opsTable) +{ + int r = 0; + + if (ascqTable && ascqtbl_sz && opsTable) { + mpt_v_ASCQ_TablePtr = ascqTable; + mpt_ASCQ_TableSz = ascqtbl_sz; + mpt_ScsiOpcodesPtr = opsTable; + printk(KERN_INFO MYNAM ": English readable SCSI-3 strings enabled:-)\n"); + r = 1; + } + MOD_INC_USE_COUNT; + return r; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_deregister_ascqops_strings - Deregister SCSI ASC/ASCQ and SCSI + * OpCode strings from the isense driver. + * + * Specialized driver deregistration routine for the isense driver. + */ +void +mpt_deregister_ascqops_strings(void) +{ + mpt_v_ASCQ_TablePtr = NULL; + mpt_ASCQ_TableSz = 0; + mpt_ScsiOpcodesPtr = NULL; + printk(KERN_INFO MYNAM ": English readable SCSI-3 strings disabled)-:\n"); + MOD_DEC_USE_COUNT; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +EXPORT_SYMBOL(mpt_register); +EXPORT_SYMBOL(mpt_deregister); +EXPORT_SYMBOL(mpt_event_register); +EXPORT_SYMBOL(mpt_event_deregister); +EXPORT_SYMBOL(mpt_get_msg_frame); +EXPORT_SYMBOL(mpt_put_msg_frame); +EXPORT_SYMBOL(mpt_free_msg_frame); +EXPORT_SYMBOL(mpt_send_handshake_request); +EXPORT_SYMBOL(mpt_adapter_find_first); +EXPORT_SYMBOL(mpt_adapter_find_next); +EXPORT_SYMBOL(mpt_verify_adapter); +EXPORT_SYMBOL(mpt_print_ioc_summary); +EXPORT_SYMBOL(mpt_lan_index); +EXPORT_SYMBOL(mpt_stm_index); + +EXPORT_SYMBOL(mpt_register_ascqops_strings); +EXPORT_SYMBOL(mpt_deregister_ascqops_strings); +EXPORT_SYMBOL(mpt_v_ASCQ_TablePtr); +EXPORT_SYMBOL(mpt_ASCQ_TableSz); +EXPORT_SYMBOL(mpt_ScsiOpcodesPtr); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * fusion_init - Fusion MPT base driver initialization routine. + * + * Returns 0 for success, non-zero for failure. + */ +int __init fusion_init(void) +{ + int i; + + if (FusionInitCalled++) { + dprintk((KERN_INFO MYNAM ": INFO - Driver late-init entry point called\n")); + return 0; + } + + show_mptmod_ver(my_NAME, my_VERSION); + printk(KERN_INFO COPYRIGHT "\n"); + + Q_INIT(&MptAdapters, MPT_ADAPTER); /* set to empty */ + for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) { + MptCallbacks[i] = NULL; + MptDriverClass[i] = MPTUNKNOWN_DRIVER; + MptEvHandlers[i] = NULL; + } + + /* NEW! 20010120 -sralston + * Register ourselves (mptbase) in order to facilitate + * EventNotification handling. + */ + mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER); + + if ((i = mpt_pci_scan()) < 0) + return i; + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * fusion_exit - Perform driver unload cleanup. + * + * This routine frees all resources associated with each MPT adapter + * and removes all %MPT_PROCFS_MPTBASEDIR entries. + */ +static void fusion_exit(void) +{ + MPT_ADAPTER *this; + int i; + + dprintk((KERN_INFO MYNAM ": fusion_exit() called!\n")); + + /* + * Paranoia; disable interrupts on all MPT adapters. + */ + for (i=0; i<MPT_MAX_ADAPTERS; i++) { + if ((this = mpt_adapters[i]) != NULL) { + /* Disable adapter interrupts! */ + CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF); + /* Clear any lingering interrupt */ + CHIPREG_WRITE32(&this->chip->IntStatus, 0); + this->active = 0; + } + } + + /* Whups? 20010120 -sralston + * Moved this *above* removal of all MptAdapters! + */ +#ifdef CONFIG_PROC_FS + procmpt_destroy(); +#endif + + while (! Q_IS_EMPTY(&MptAdapters)) { + this = MptAdapters.head; + Q_DEL_ITEM(this); + mpt_adapter_dispose(this); + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +module_init(fusion_init); +module_exit(fusion_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/mptbase.h linux.ac/drivers/message/fusion/mptbase.h --- linux.vanilla/drivers/message/fusion/mptbase.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/mptbase.h Tue Apr 17 18:12:40 2001 @@ -0,0 +1,581 @@ +/* + * linux/drivers/message/fusion/mptbase.h + * High performance SCSI + LAN / Fibre Channel device drivers. + * For use with PCI chip/adapter(s): + * LSIFC9xx/LSI409xx Fibre Channel + * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * + * Credits: + * (see mptbase.c) + * + * Copyright (c) 1999-2001 LSI Logic Corporation + * Originally By: Steven J. Ralston + * (mailto:Steve.Ralston@lsil.com) + * + * $Id: mptbase.h,v 1.38 2001/03/22 10:54:30 sralston Exp $ + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + 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. + + NO WARRANTY + THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + solely responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, damage to or loss of data, + programs or equipment, and unavailability or interruption of operations. + + DISCLAIMER OF LIABILITY + NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + 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 +*/ + +#ifndef MPTBASE_H_INCLUDED +#define MPTBASE_H_INCLUDED +/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#include "linux_compat.h" /* linux-2.2.x (vs. -2.4.x) tweaks */ + +#include "lsi/mpi_type.h" +#include "lsi/mpi.h" /* Fusion MPI(nterface) basic defs */ +#include "lsi/mpi_ioc.h" /* Fusion MPT IOC(ontroller) defs */ +#include "lsi/mpi_cnfg.h" /* IOC configuration support */ +#include "lsi/mpi_init.h" /* SCSI Host (initiator) protocol support */ +#include "lsi/mpi_lan.h" /* LAN over FC protocol support */ + +//#include "lsi/mpi_fc.h" /* Fibre Channel (lowlevel) support */ +//#include "lsi/mpi_targ.h" /* SCSI/FCP Target protcol support */ +#include "lsi/fc_log.h" + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#ifndef MODULEAUTHOR +#define MODULEAUTHOR "LSI Logic Corporation" +#endif + +#ifndef COPYRIGHT +#define COPYRIGHT "Copyright (c) 1999-2001 " MODULEAUTHOR +#endif + +#define MPT_LINUX_VERSION_COMMON "1.00.11" +#define MPT_LINUX_VERSION_EXP "0.09.66-EXP" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-1.00.11" +#define WHAT_MAGIC_STRING "@" "(" "#" ")" + +#define show_mptmod_ver(s,ver) \ + printk(KERN_INFO "%s %s\n", s, ver); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Fusion MPT(linux) driver configurable stuff... + */ +#define MPT_MAX_ADAPTERS 16 +#define MPT_MAX_PROTOCOL_DRIVERS 8 + +#define MPT_MISCDEV_BASENAME "mptctl" +#define MPT_MISCDEV_PATHNAME "/dev/" MPT_MISCDEV_BASENAME + +#define MPT_PROCFS_MPTBASEDIR "mpt" + /* chg it to "driver/fusion" ? */ +#define MPT_PROCFS_SUMMARY_NODE MPT_PROCFS_MPTBASEDIR "/summary" +#define MPT_PROCFS_SUMMARY_PATHNAME "/proc/" MPT_PROCFS_SUMMARY_NODE +#define MPT_FW_REV_MAGIC_ID_STRING "FwRev=" + +#ifdef __KERNEL__ /* { */ +#define MPT_MAX_REQ_DEPTH 1023 +#define MPT_REQ_DEPTH 256 +#define MPT_MIN_REQ_DEPTH 128 + +#define MPT_MAX_REPLY_DEPTH MPT_MAX_REQ_DEPTH +#define MPT_REPLY_DEPTH 128 +#define MPT_MIN_REPLY_DEPTH 8 +#define MPT_MAX_REPLIES_PER_ISR 32 + +#define MPT_MAX_FRAME_SIZE 128 +#define MPT_REQ_SIZE 128 +#define MPT_REPLY_SIZE 128 + +#define MPT_SG_BUCKETS_PER_HUNK 1 + +#ifdef MODULE +#define MPT_REQ_DEPTH_RANGE_STR __MODULE_STRING(MPT_MIN_REQ_DEPTH) "-" __MODULE_STRING(MPT_MAX_REQ_DEPTH) +#define MPT_REPLY_DEPTH_RANGE_STR __MODULE_STRING(MPT_MIN_REPLY_DEPTH) "-" __MODULE_STRING(MPT_MAX_REPLY_DEPTH) +#define MPT_REPLY_SIZE_RANGE_STR __MODULE_STRING(MPT_MIN_REPLY_SIZE) "-" __MODULE_STRING(MPT_MAX_FRAME_SIZE) +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * MPT protocol driver defs... + */ +typedef enum { + MPTBASE_DRIVER, /* MPT base class */ + MPTCTL_DRIVER, /* MPT ioctl class */ + MPTSCSIH_DRIVER, /* MPT SCSI host (initiator) class */ + MPTLAN_DRIVER, /* MPT LAN class */ + MPTSTM_DRIVER, /* MPT SCSI target mode class */ + MPTUNKNOWN_DRIVER +} MPT_DRIVER_CLASS; + +/* + * MPT adapter / port / bus / device info structures... + */ + +typedef union _MPT_FRAME_TRACKER { + struct { + struct _MPT_FRAME_HDR *forw; + struct _MPT_FRAME_HDR *back; + u32 arg1; + void *argp1; + } linkage; + /* + * NOTE: On non-32-bit systems, where pointers are LARGE, + * using the linkage pointers destroys our sacred MsgContext + * field contents. But we don't care anymore because these + * are now reset in mpt_put_msg_frame() just prior to sending + * a request off to the IOC. + */ + struct { + u32 __hdr[2]; + /* + * The following _MUST_ match the location of the + * MsgContext field in the MPT message headers. + */ + union { + u32 MsgContext; + struct { + u16 req_idx; /* Request index */ + u8 cb_idx; /* callback function index */ + u8 rsvd; + } fld; + } msgctxu; + } hwhdr; +} MPT_FRAME_TRACKER; + +/* + * We might want to view/access a frame as: + * 1) generic request header + * 2) SCSIIORequest + * 3) SCSIIOReply + * 4) MPIDefaultReply + * 5) frame tracker + */ +typedef struct _MPT_FRAME_HDR { + union { + MPIHeader_t hdr; + SCSIIORequest_t scsireq; + SCSIIOReply_t sreply; + MPIDefaultReply_t reply; + MPT_FRAME_TRACKER frame; + } u; +} MPT_FRAME_HDR; + +typedef struct _MPT_Q_TRACKER { + MPT_FRAME_HDR *head; + MPT_FRAME_HDR *tail; +} MPT_Q_TRACKER; + + +typedef struct _MPT_SGL_HDR { + SGESimple32_t sge[1]; +} MPT_SGL_HDR; + +typedef struct _MPT_SGL64_HDR { + SGESimple64_t sge[1]; +} MPT_SGL64_HDR; + + +typedef struct _Q_ITEM { + struct _Q_ITEM *forw; + struct _Q_ITEM *back; +} Q_ITEM; + +typedef struct _Q_TRACKER { + struct _Q_ITEM *head; + struct _Q_ITEM *tail; +} Q_TRACKER; + + +/* + * Chip-specific stuff... + */ + +typedef enum { + FC909 = 0x0909, + FC919 = 0x0919, + FC929 = 0x0929, + C1030 = 0x1030, + FCUNK = 0xFBAD +} CHIP_TYPE; + +/* + * System interface register set + */ + +typedef struct _SYSIF_REGS +{ + u32 Doorbell; /* 00 System<->IOC Doorbell reg */ + u32 WriteSequence; /* 04 Write Sequence register */ + u32 Diagnostic; /* 08 Diagnostic register */ + u32 TestBase; /* 0C Test Base Address */ + u32 Reserved1[8]; /* 10-2F reserved for future use */ + u32 IntStatus; /* 30 Interrupt Status */ + u32 IntMask; /* 34 Interrupt Mask */ + u32 Reserved2[2]; /* 38-3F reserved for future use */ + u32 RequestFifo; /* 40 Request Post/Free FIFO */ + u32 ReplyFifo; /* 44 Reply Post/Free FIFO */ + u32 Reserved3[2]; /* 48-4F reserved for future use */ + u32 HostIndex; /* 50 Host Index register */ + u32 Reserved4[15]; /* 54-8F */ + u32 Fubar; /* 90 For Fubar usage */ + u32 Reserved5[27]; /* 94-FF */ +} SYSIF_REGS; + +/* + * NOTE: Use MPI_{DOORBELL,WRITESEQ,DIAG}_xxx defs in lsi/mpi.h + * in conjunction with SYSIF_REGS accesses! + */ + + +typedef struct _MPT_ADAPTER +{ + struct _MPT_ADAPTER *forw; + struct _MPT_ADAPTER *back; + int id; /* Unique adapter id {0,1,2,...} */ + int pci_irq; + IOCFactsReply_t facts0; + IOCFactsReply_t factsN; + char name[32]; /* "iocN" */ + char *prod_name; /* "LSIFC9x9" */ + u32 mem_phys; /* == f4020000 (mmap) */ + volatile SYSIF_REGS *chip; /* == c8817000 (mmap) */ + CHIP_TYPE chip_type; + int mem_size; + int alloc_total; + u32 last_state; + int active; + int sod_reset; + unsigned long last_kickstart; + PortFactsReply_t pfacts0; + PortFactsReply_t pfactsN; + LANPage0_t lan_cnfg_page0; + LANPage1_t lan_cnfg_page1; + u8 *reply_alloc; /* Reply frames alloc ptr */ + dma_addr_t reply_alloc_dma; + MPT_FRAME_HDR *reply_frames; /* Reply frames - rounded up! */ + dma_addr_t reply_frames_dma; + int reply_depth; + int reply_sz; + /* We (host driver) get to manage our own RequestQueue! */ + u8 *req_alloc; /* Request frames alloc ptr */ + dma_addr_t req_alloc_dma; + MPT_FRAME_HDR *req_frames; /* Request msg frames for PULL mode! */ + dma_addr_t req_frames_dma; + int req_depth; + int req_sz; + spinlock_t FreeQlock; + MPT_Q_TRACKER FreeQ; + /* Pool of SCSI sense buffers for commands coming from + * the SCSI mid-layer. We have one 256 byte sense buffer + * for each REQ entry. + */ + u8 *sense_buf_pool; + dma_addr_t sense_buf_pool_dma; + int hs_reply_idx; + u32 hs_req[MPT_MAX_FRAME_SIZE/sizeof(u32)]; + u16 hs_reply[MPT_MAX_FRAME_SIZE/sizeof(u16)]; + struct pci_dev *pcidev; + struct _MPT_ADAPTER *alt_ioc; +/* atomic_t userCnt; */ + u8 *memmap; + int mtrr_reg; + struct Scsi_Host *sh; + struct proc_dir_entry *ioc_dentry; +} MPT_ADAPTER; + + +typedef struct _MPT_ADAPTER_TRACKER { + MPT_ADAPTER *head; + MPT_ADAPTER *tail; +} MPT_ADAPTER_TRACKER; + +/* + * New return value convention: + * 1 = Ok to free associated request frame + * 0 = not Ok ... + */ +typedef int (*MPT_CALLBACK)(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply); +typedef int (*MPT_EVHANDLER)(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply); + +/* + * Fibre Channel (SCSI) target device... + */ +typedef struct _FC_TARGET { + struct _FC_TARGET *forw; + struct _FC_TARGET *back; + int bus_id; + int target_id; + int lun_exists[32]; + u8 inquiry_data[36]; + u8 last_sense[256]; +} FC_TARGET; + +typedef struct _FCDEV_TRACKER { + FC_TARGET *head; + FC_TARGET *tail; +} FCDEV_TRACKER; + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Funky (private) macros... + */ +#ifdef MPT_DEBUG +#define dprintk(x) printk x +#else +#define dprintk(x) +#endif + +#ifdef MPT_DEBUG_HANDSHAKE +#define dhsprintk(x) printk x +#else +#define dhsprintk(x) +#endif + +#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME) +#define dmfprintk(x) printk x +#else +#define dmfprintk(x) +#endif + +#ifdef MPT_DEBUG_IRQ +#define dirqprintk(x) printk x +#else +#define dirqprintk(x) +#endif + +#ifdef MPT_DEBUG_EVENTS +#define deventprintk(x) printk x +#else +#define deventprintk(x) +#endif + +#ifdef MPT_DEBUG_SPINLOCK +#define dslprintk(x) printk x +#else +#define dslprintk(x) +#endif + +#ifdef MPT_DEBUG_SG +#define dsgprintk(x) printk x +#else +#define dsgprintk(x) +#endif + + +#define MPT_INDEX_2_MFPTR(ioc,idx) \ + (MPT_FRAME_HDR*)( (u8*)(ioc)->req_frames + (ioc)->req_sz * (idx) ) + +#define MFPTR_2_MPT_INDEX(ioc,mf) \ + (int)( ((u8*)mf - (u8*)(ioc)->req_frames) / (ioc)->req_sz ) + +#define Q_INIT(q,type) (q)->head = (q)->tail = (type*)(q) +#define Q_IS_EMPTY(q) ((Q_ITEM*)(q)->head == (Q_ITEM*)(q)) + +#define Q_ADD_TAIL(qt,i,type) { \ + Q_TRACKER *_qt = (Q_TRACKER*)(qt); \ + Q_ITEM *oldTail = _qt->tail; \ + (i)->forw = (type*)_qt; \ + (i)->back = (type*)oldTail; \ + oldTail->forw = (Q_ITEM*)(i); \ + _qt->tail = (Q_ITEM*)(i); \ +} + +#define Q_ADD_HEAD(qt,i,type) { \ + Q_TRACKER *_qt = (Q_TRACKER*)(qt); \ + Q_ITEM *oldHead = _qt->head; \ + (i)->forw = (type*)oldHead; \ + (i)->back = (type*)_qt; \ + oldHead->back = (Q_ITEM*)(i); \ + _qt->head = (Q_ITEM*)(i); \ +} + +#define Q_DEL_ITEM(i) { \ + Q_ITEM *_forw = (Q_ITEM*)(i)->forw; \ + Q_ITEM *_back = (Q_ITEM*)(i)->back; \ + _back->forw = _forw; \ + _forw->back = _back; \ +} + + +#define SWAB4(value) \ + (u32)( (((value) & 0x000000ff) << 24) \ + | (((value) & 0x0000ff00) << 8) \ + | (((value) & 0x00ff0000) >> 8) \ + | (((value) & 0xff000000) >> 24) ) + + +#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME) +#define DBG_DUMP_REPLY_FRAME(mfp) \ + { u32 *m = (u32 *)(mfp); \ + int i, n = (le32_to_cpu(m[0]) & 0x00FF0000) >> 16; \ + printk(KERN_INFO " "); \ + for (i=0; i<n; i++) \ + printk(" %08x", le32_to_cpu(m[i])); \ + printk("\n"); \ + } +#define DBG_DUMP_REQUEST_FRAME_HDR(mfp) \ + { int i, n = 3; \ + u32 *m = (u32 *)(mfp); \ + printk(KERN_INFO " "); \ + for (i=0; i<n; i++) \ + printk(" %08x", le32_to_cpu(m[i])); \ + printk("\n"); \ + } +#else +#define DBG_DUMP_REPLY_FRAME(mfp) +#define DBG_DUMP_REQUEST_FRAME_HDR(mfp) +#endif + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#endif /* } __KERNEL__ */ + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/* + * MPT Control IOCTLs and structures + */ +#define MPT_MAGIC_NUMBER 'm' +#define MPTRWPERF _IOWR(MPT_MAGIC_NUMBER,0,struct mpt_raw_r_w) +#define MPTRWPERF_CHK _IOR(MPT_MAGIC_NUMBER,13,struct mpt_raw_r_w) +#define MPTRWPERF_RESET _IOR(MPT_MAGIC_NUMBER,14,struct mpt_raw_r_w) +#define MPTFWDOWNLOAD _IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer) +#define MPTSCSICMD _IOWR(MPT_MAGIC_NUMBER,16,struct mpt_scsi_cmd) + +/* + * Define something *vague* enough that caller doesn't + * really need to know anything about device parameters + * (blk_size, capacity, etc.) + */ +struct mpt_raw_r_w { + unsigned int iocnum; /* IOC unit number */ + unsigned int port; /* IOC port number */ + unsigned int target; /* SCSI Target */ + unsigned int lun; /* SCSI LUN */ + unsigned int iters; /* N iterations */ + unsigned short nblks; /* number of blocks per IO */ + unsigned short qdepth; /* max Q depth on this device */ + unsigned char range; /* 0-100% of FULL disk capacity, 0=use (nblks X iters) */ + unsigned char skip; /* % of disk to skip */ + unsigned char rdwr; /* 0-100%, 0=pure ReaDs, 100=pure WRites */ + unsigned char seqran; /* 0-100%, 0=pure SEQential, 100=pure RANdom */ + unsigned int cache_sz; /* In Kb! Optimize hits to N Kb cache size */ +}; + +struct mpt_fw_xfer { + unsigned int iocnum; /* IOC unit number */ +/* u8 flags;*/ /* Message flags - bit field */ + unsigned int fwlen; + void *bufp; /* Pointer to firmware buffer */ +}; + +struct mpt_scsi_cmd { + unsigned int iocnum; /* IOC unit number */ + unsigned int port; /* IOC port number */ + unsigned int target; /* SCSI Target */ + unsigned int lun; /* SCSI LUN */ + SCSIIORequest_t scsi_req; + SCSIIOReply_t scsi_reply; +}; + +struct mpt_ioctl_sanity { + unsigned int iocnum; +}; + +#ifdef __KERNEL__ /* { */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/* + * Public entry points... + */ +extern int mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass); +extern void mpt_deregister(int cb_idx); +extern int mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc); +extern void mpt_event_deregister(int cb_idx); +extern int mpt_register_ascqops_strings(/*ASCQ_Table_t*/void *ascqTable, int ascqtbl_sz, const char **opsTable); +extern void mpt_deregister_ascqops_strings(void); +extern MPT_FRAME_HDR *mpt_get_msg_frame(int handle, int iocid); +extern void mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf); +extern void mpt_put_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf); +extern int mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req); +extern int mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp); +extern MPT_ADAPTER *mpt_adapter_find_first(void); +extern MPT_ADAPTER *mpt_adapter_find_next(MPT_ADAPTER *prev); +extern void mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len); +extern void mpt_print_ioc_facts(MPT_ADAPTER *ioc, char *buf, int *size, int len); + +/* + * Public data decl's... + */ +extern int mpt_lan_index; /* needed by mptlan.c */ +extern int mpt_stm_index; /* needed by mptstm.c */ + +extern void *mpt_v_ASCQ_TablePtr; +extern const char **mpt_ScsiOpcodesPtr; +extern int mpt_ASCQ_TableSz; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#endif /* } __KERNEL__ */ + +/* + * More (public) macros... + */ +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef offsetof +#define offsetof(t, m) ((size_t) (&((t *)0)->m)) +#endif + +#if defined(__alpha__) || defined(__sparc_v9__) +#define CAST_U32_TO_PTR(x) ((void *)(u64)x) +#define CAST_PTR_TO_U32(x) ((u32)(u64)x) +#else +#define CAST_U32_TO_PTR(x) ((void *)x) +#define CAST_PTR_TO_U32(x) ((u32)x) +#endif + +#define MPT_PROTOCOL_FLAGS_c_c_c_c(pflags) \ + ((pflags) & MPI_PORTFACTS_PROTOCOL_INITIATOR) ? 'I' : 'i', \ + ((pflags) & MPI_PORTFACTS_PROTOCOL_TARGET) ? 'T' : 't', \ + ((pflags) & MPI_PORTFACTS_PROTOCOL_LAN) ? 'L' : 'l', \ + ((pflags) & MPI_PORTFACTS_PROTOCOL_LOGBUSADDR) ? 'B' : 'b' + +/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/mptctl.c linux.ac/drivers/message/fusion/mptctl.c --- linux.vanilla/drivers/message/fusion/mptctl.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/mptctl.c Tue Apr 3 23:12:52 2001 @@ -0,0 +1,1296 @@ +/* + * linux/drivers/message/fusion/mptctl.c + * Fusion MPT misc device (ioctl) driver. + * For use with PCI chip/adapter(s): + * LSIFC9xx/LSI409xx Fibre Channel + * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * + * Credits: + * This driver would not exist if not for Alan Cox's development + * of the linux i2o driver. + * + * A huge debt of gratitude is owed to David S. Miller (DaveM) + * for fixing much of the stupid and broken stuff in the early + * driver while porting to sparc64 platform. THANK YOU! + * + * A big THANKS to Eddie C. Dost for fixing the ioctl path + * and most importantly f/w download on sparc64 platform! + * (plus Eddie's other helpful hints and insights) + * + * Thanks to Arnaldo Carvalho de Melo for finding and patching + * a potential memory leak in mpt_ioctl_do_fw_download(), + * and for some kmalloc insight:-) + * + * (see also mptbase.c) + * + * Copyright (c) 1999-2001 LSI Logic Corporation + * Originally By: Steven J. Ralston, Noah Romer + * (mailto:Steve.Ralston@lsil.com) + * + * $Id: mptctl.c,v 1.23 2001/03/21 19:42:31 sralston Exp $ + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + 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. + + NO WARRANTY + THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + solely responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, damage to or loss of data, + programs or equipment, and unavailability or interruption of operations. + + DISCLAIMER OF LIABILITY + NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/miscdevice.h> + +#include <asm/io.h> +#include <asm/uaccess.h> + +#include <linux/proc_fs.h> + +#define COPYRIGHT "Copyright (c) 1999-2001 LSI Logic Corporation" +#define MODULEAUTHOR "Steven J. Ralston, Noah Romer" +#include "mptbase.h" + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#define my_NAME "Fusion MPT misc device (ioctl) driver" +#define my_VERSION MPT_LINUX_VERSION_COMMON +#define MYNAM "mptctl" + +EXPORT_NO_SYMBOLS; +MODULE_AUTHOR(MODULEAUTHOR); +MODULE_DESCRIPTION(my_NAME); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +static int mptctl_id = -1; +static int rwperf_reset = 0; +static struct semaphore mptctl_syscall_sem_ioc[MPT_MAX_ADAPTERS]; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +static int mpt_ioctl_rwperf(unsigned long arg); +static int mpt_ioctl_rwperf_status(unsigned long arg); +static int mpt_ioctl_rwperf_reset(unsigned long arg); +static int mpt_ioctl_fw_download(unsigned long arg); +static int mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen); +static int mpt_ioctl_scsi_cmd(unsigned long arg); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Scatter gather list (SGL) sizes and limits... + */ +//#define MAX_SCSI_FRAGS 9 +#define MAX_FRAGS_SPILL1 9 +#define MAX_FRAGS_SPILL2 15 +#define FRAGS_PER_BUCKET (MAX_FRAGS_SPILL2 + 1) + +//#define MAX_CHAIN_FRAGS 64 +//#define MAX_CHAIN_FRAGS (15+15+15+16) +#define MAX_CHAIN_FRAGS (4 * MAX_FRAGS_SPILL2 + 1) + +// Define max sg LIST bytes ( == (#frags + #chains) * 8 bytes each) +// Works out to: 592d bytes! (9+1)*8 + 4*(15+1)*8 +// ^----------------- 80 + 512 +#define MAX_SGL_BYTES ((MAX_FRAGS_SPILL1 + 1 + (4 * FRAGS_PER_BUCKET)) * 8) + +/* linux only seems to ever give 128kB MAX contiguous (GFP_USER) mem bytes */ +#define MAX_KMALLOC_SZ (128*1024) + +struct buflist { + u8 *kptr; + int len; +}; + +#define myMAX_TARGETS (1<<4) +#define myMAX_LUNS (1<<3) +#define myMAX_T_MASK (myMAX_TARGETS-1) +#define myMAX_L_MASK (myMAX_LUNS-1) +static u8 DevInUse[myMAX_TARGETS][myMAX_LUNS] = {{0,0}}; +static u32 DevIosCount[myMAX_TARGETS][myMAX_LUNS] = {{0,0}}; + +static u32 fwReplyBuffer[16]; +static pMPIDefaultReply_t ReplyMsg = NULL; + +/* some private forw protos */ +static SGESimple32_t *kbuf_alloc_2_sgl( int bytes, u32 dir, int *frags, + struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc); +static void kfree_sgl( SGESimple32_t *sgl, dma_addr_t sgl_dma, + struct buflist *buflist, MPT_ADAPTER *ioc); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptctl_syscall_down - Down the MPT adapter syscall semaphore. + * @ioc: Pointer to MPT adapter + * @nonblock: boolean, non-zero if O_NONBLOCK is set + * + * All of the mptctl commands can potentially sleep, which is illegal + * with a spinlock held, thus we perform mutual exclusion here. + * + * Returns negative errno on error, or zero for success. + */ +static inline int +mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock) +{ + dprintk((KERN_INFO MYNAM "::mpt_syscall_down(%p,%d) called\n", ioc, nonblock)); + + if (nonblock) { + if (down_trylock(&mptctl_syscall_sem_ioc[ioc->id])) + return -EAGAIN; + } else { + if (down_interruptible(&mptctl_syscall_sem_ioc[ioc->id])) + return -ERESTARTSYS; + } + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * This is the callback for any message we have posted. The message itself + * will be returned to the message pool when we return from the IRQ + * + * This runs in irq context so be short and sweet. + */ +static int +mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) +{ + u8 targ; + + //dprintk((KERN_DEBUG MYNAM ": Got mptctl_reply()!\n")); + + if (req && req->u.hdr.Function == MPI_FUNCTION_SCSI_IO_REQUEST) { + targ = req->u.scsireq.TargetID & myMAX_T_MASK; + DevIosCount[targ][0]--; + } else if (reply && req && req->u.hdr.Function == MPI_FUNCTION_FW_DOWNLOAD) { + // NOTE: Expects/requires non-Turbo reply! + dprintk((KERN_INFO MYNAM ": Caching MPI_FUNCTION_FW_DOWNLOAD reply!\n")); + memcpy(fwReplyBuffer, reply, MIN(sizeof(fwReplyBuffer), 4*reply->u.reply.MsgLength)); + ReplyMsg = (pMPIDefaultReply_t) fwReplyBuffer; + } + + return 1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static loff_t +mptctl_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static ssize_t +mptctl_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + printk(KERN_ERR MYNAM ": ioctl WRITE not yet supported\n"); + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static ssize_t +mptctl_read(struct file *file, char *buf, size_t count, loff_t *ptr) +{ + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * MPT ioctl handler + */ +static int +mpt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct mpt_ioctl_sanity *usanity = (struct mpt_ioctl_sanity *) arg; + struct mpt_ioctl_sanity ksanity; + int iocnum; + unsigned iocnumX; + int nonblock = (file->f_flags & O_NONBLOCK); + int ret; + MPT_ADAPTER *iocp = NULL; + + dprintk((KERN_INFO MYNAM "::mpt_ioctl() called\n")); + + if (copy_from_user(&ksanity, usanity, sizeof(ksanity))) { + printk(KERN_ERR "%s::mpt_ioctl() @%d - " + "Unable to copy mpt_ioctl_sanity data @ %p\n", + __FILE__, __LINE__, (void*)usanity); + return -EFAULT; + } + ret = -ENXIO; /* (-6) No such device or address */ + + /* Verify intended MPT adapter */ + iocnumX = ksanity.iocnum & 0xFF; + if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || + (iocp == NULL)) { + printk(KERN_ERR "%s::mpt_ioctl() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnumX); + return -ENODEV; + } + + if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0) + return ret; + + dprintk((KERN_INFO MYNAM "::mpt_ioctl() - Using %s\n", iocp->name)); + + switch(cmd) { + case MPTRWPERF: + ret = mpt_ioctl_rwperf(arg); + break; + case MPTRWPERF_CHK: + ret = mpt_ioctl_rwperf_status(arg); + break; + case MPTRWPERF_RESET: + ret = mpt_ioctl_rwperf_reset(arg); + break; + case MPTFWDOWNLOAD: + ret = mpt_ioctl_fw_download(arg); + break; + case MPTSCSICMD: + ret = mpt_ioctl_scsi_cmd(arg); + break; + default: + ret = -EINVAL; + } + + up(&mptctl_syscall_sem_ioc[iocp->id]); + + return ret; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int mptctl_open(struct inode *inode, struct file *file) +{ + /* + * Should support multiple management users + */ + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int mptctl_release(struct inode *inode, struct file *file) +{ + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_ioctl_fw_download(unsigned long arg) +{ + struct mpt_fw_xfer *ufwdl = (struct mpt_fw_xfer *) arg; + struct mpt_fw_xfer kfwdl; + + dprintk((KERN_INFO "mpt_ioctl_fwdl called. mptctl_id = %xh\n", mptctl_id)); //tc + if (copy_from_user(&kfwdl, ufwdl, sizeof(struct mpt_fw_xfer))) { + printk(KERN_ERR "%s@%d::_ioctl_fwdl - " + "Unable to copy mpt_fw_xfer struct @ %p\n", + __FILE__, __LINE__, (void*)ufwdl); + return -EFAULT; + } + + return mpt_ioctl_do_fw_download(kfwdl.iocnum, kfwdl.bufp, kfwdl.fwlen); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * MPT FW Download + */ +static int +mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen) +{ + FWDownload_t *dlmsg; + MPT_FRAME_HDR *mf; + MPT_ADAPTER *iocp; +// char *fwbuf; +// dma_addr_t fwbuf_dma; + FWDownloadTCSGE_t *fwVoodoo; +// SGEAllUnion_t *fwSgl; + int ret; + + SGESimple32_t *sgl; + SGESimple32_t *sgOut, *sgIn; + dma_addr_t sgl_dma; + struct buflist *buflist; + struct buflist *bl; + int numfrags = 0; + int maxfrags; + int n = 0; + u32 sgdir; + u32 nib; + int fw_bytes_copied = 0; + u16 iocstat; + int i; + + dprintk((KERN_INFO "mpt_ioctl_do_fwdl called. mptctl_id = %xh.\n", mptctl_id)); + + dprintk((KERN_INFO "DbG: kfwdl.bufp = %p\n", ufwbuf)); + dprintk((KERN_INFO "DbG: kfwdl.fwlen = %d\n", (int)fwlen)); + dprintk((KERN_INFO "DbG: kfwdl.ioc = %04xh\n", ioc)); + + if ((ioc = mpt_verify_adapter(ioc, &iocp)) < 0) { + printk("%s@%d::_ioctl_fwdl - ioc%d not found!\n", + __FILE__, __LINE__, ioc); + return -ENXIO; /* (-6) No such device or address */ + } + + if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) + return -EAGAIN; + dlmsg = (FWDownload_t*) mf; + fwVoodoo = (FWDownloadTCSGE_t *) &dlmsg->SGL; + sgOut = (SGESimple32_t *) (fwVoodoo + 1); + + /* + * Construct f/w download request + */ + dlmsg->ImageType = MPI_FW_DOWNLOAD_ITYPE_FW; + dlmsg->Reserved = 0; + dlmsg->ChainOffset = 0; + dlmsg->Function = MPI_FUNCTION_FW_DOWNLOAD; + dlmsg->Reserved1[0] = dlmsg->Reserved1[1] = dlmsg->Reserved1[2] = 0; + dlmsg->MsgFlags = 0; + + fwVoodoo->Reserved = 0; + fwVoodoo->ContextSize = 0; + fwVoodoo->DetailsLength = 12; + fwVoodoo->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT; + fwVoodoo->Reserved1 = 0; + fwVoodoo->ImageOffset = 0; + fwVoodoo->ImageSize = cpu_to_le32(fwlen); + + /* + * Need to kmalloc area(s) for holding firmware image bytes. + * But we need to do it piece meal, using a proper + * scatter gather list (with 128kB MAX hunks). + * + * A practical limit here might be # of sg hunks that fit into + * a single IOC request frame; 12 or 8 (see below), so: + * For FC9xx: 12 x 128kB == 1.5 mB (max) + * For C1030: 8 x 128kB == 1 mB (max) + * We could support chaining, but things get ugly(ier:) + */ + sgdir = 0x04000000; /* IOC will READ from sys mem */ + if ((sgl = kbuf_alloc_2_sgl(fwlen, sgdir, &numfrags, &buflist, &sgl_dma, iocp)) == NULL) + return -ENOMEM; + + /* + * We should only need SGL with 2 simple_32bit entries (up to 256 kB) + * for FC9xx f/w image, but calculate max number of sge hunks + * we can fit into a request frame, and limit ourselves to that. + * (currently no chain support) + * For FC9xx: (128-12-16)/8 = 12.5 = 12 + * For C1030: (96-12-16)/8 = 8.5 = 8 + */ + maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) / sizeof(SGESimple32_t); + if (numfrags > maxfrags) { + ret = -EMLINK; + goto fwdl_out; + } + + dprintk((KERN_INFO "DbG: sgl buffer = %p, sgfrags = %d\n", sgl, numfrags)); + + /* + * Parse SG list, copying sgl itself, + * plus f/w image hunks from user space as we go... + */ + ret = -EFAULT; + sgIn = sgl; + bl = buflist; + for (i=0; i < numfrags; i++) { + nib = (sgIn->FlagsLength & 0xF0000000) >> 28; + /* skip ignore/chain. */ + if (nib == 0 || nib == 3) { + ; + } else if (sgIn->Address) { + *sgOut = *sgIn; + n++; + if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) { + printk(KERN_ERR "%s@%d::_ioctl_fwdl - " + "Unable to copy f/w buffer hunk#%d @ %p\n", + __FILE__, __LINE__, n, (void*)ufwbuf); + goto fwdl_out; + } + fw_bytes_copied += bl->len; + } + sgIn++; + bl++; + sgOut++; + } + +#ifdef MPT_DEBUG + { + u32 *m = (u32 *)mf; + printk(KERN_INFO MYNAM ": F/W download request:\n" KERN_INFO " "); + for (i=0; i < 7+numfrags*2; i++) + printk(" %08x", le32_to_cpu(m[i])); + printk("\n"); + } +#endif + + /* + * Finally, perform firmware download. + */ + ReplyMsg = NULL; + mpt_put_msg_frame(mptctl_id, ioc, mf); + + /* + * Wait until the reply has been received + */ + { + int foo = 0; + + while (ReplyMsg == NULL) { + if (!(foo%1000000)) { + dprintk((KERN_INFO "DbG::_do_fwdl: " + "In ReplyMsg loop - iteration %d\n", + foo)); //tc + } + ret = -ETIME; + if (++foo > 60000000) + goto fwdl_out; + mb(); + schedule(); + barrier(); + } + } + + if (sgl) + kfree_sgl(sgl, sgl_dma, buflist, iocp); + + iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK; + if (iocstat == MPI_IOCSTATUS_SUCCESS) { + printk(KERN_INFO MYNAM ": F/W update successfully sent to %s!\n", iocp->name); + return 0; + } else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) { + printk(KERN_WARNING MYNAM ": ?Hmmm... %s says it doesn't support F/W download!?!\n", + iocp->name); + printk(KERN_WARNING MYNAM ": (time to go bang on somebodies door)\n"); + return -EBADRQC; + } else if (iocstat == MPI_IOCSTATUS_BUSY) { + printk(KERN_WARNING MYNAM ": Warning! %s says: IOC_BUSY!\n", iocp->name); + printk(KERN_WARNING MYNAM ": (try again later?)\n"); + return -EBUSY; + } else { + printk(KERN_WARNING MYNAM "::ioctl_fwdl() ERROR! %s returned [bad] status = %04xh\n", + iocp->name, iocstat); + printk(KERN_WARNING MYNAM ": (bad VooDoo)\n"); + return -ENOMSG; + } + return 0; + +fwdl_out: + kfree_sgl(sgl, sgl_dma, buflist, iocp); + return ret; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * NEW rwperf (read/write performance) stuff starts here... + */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static SGESimple32_t * +kbuf_alloc_2_sgl(int bytes, u32 sgdir, int *frags, + struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc) +{ + SGESimple32_t *sglbuf = NULL; + struct buflist *buflist = NULL; + int numfrags = 0; + int fragcnt = 0; + int alloc_sz = MIN(bytes,MAX_KMALLOC_SZ); // avoid kernel warning msg! + int bytes_allocd = 0; + int this_alloc; + SGESimple32_t *sgl; + u32 pa; // phys addr + SGEChain32_t *last_chain = NULL; + SGEChain32_t *old_chain = NULL; + int chaincnt = 0; + int i, buflist_ent; + int sg_spill = MAX_FRAGS_SPILL1; + int dir; + + *frags = 0; + *blp = NULL; + i = MAX_SGL_BYTES / 8; + buflist = kmalloc(i, GFP_USER); + if (buflist == NULL) + return NULL; + memset(buflist, 0, i); + buflist_ent = 0; + + sglbuf = pci_alloc_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf_dma); + if (sglbuf == NULL) + goto free_and_fail; + + if (sgdir & 0x04000000) + dir = PCI_DMA_TODEVICE; + else + dir = PCI_DMA_FROMDEVICE; + + sgl = sglbuf; + while (bytes_allocd < bytes) { + this_alloc = MIN(alloc_sz, bytes-bytes_allocd); + buflist[buflist_ent].len = this_alloc; + buflist[buflist_ent].kptr = pci_alloc_consistent(ioc->pcidev, + this_alloc, + &pa); + if (buflist[buflist_ent].kptr == NULL) { + alloc_sz = alloc_sz / 2; + if (alloc_sz == 0) { + printk(KERN_WARNING MYNAM "-SG: No can do - " + "not enough memory! :-(\n"); + printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n", + numfrags); + goto free_and_fail; + } + continue; + } else { + dma_addr_t dma_addr; + + bytes_allocd += this_alloc; + + /* Write one SIMPLE sge */ + sgl->FlagsLength = cpu_to_le32(0x10000000|sgdir|this_alloc); + dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir); + sgl->Address = cpu_to_le32(dma_addr); + + fragcnt++; + numfrags++; + sgl++; + buflist_ent++; + } + + if (bytes_allocd >= bytes) + break; + + /* Need to chain? */ + if (fragcnt == sg_spill) { + dma_addr_t chain_link; + + if (last_chain != NULL) + last_chain->NextChainOffset = 0x1E; + + fragcnt = 0; + sg_spill = MAX_FRAGS_SPILL2; + + /* fixup previous SIMPLE sge */ + sgl[-1].FlagsLength |= cpu_to_le32(0x80000000); + + chain_link = (*sglbuf_dma) + + ((u8 *)(sgl+1) - (u8 *)sglbuf); + + /* Write one CHAIN sge */ + sgl->FlagsLength = cpu_to_le32(0x30000080); + sgl->Address = cpu_to_le32(chain_link); + + old_chain = last_chain; + last_chain = (SGEChain32_t*)sgl; + chaincnt++; + numfrags++; + sgl++; + } + + /* overflow check... */ + if (numfrags*8 > MAX_SGL_BYTES) { + /* GRRRRR... */ + printk(KERN_WARNING MYNAM "-SG: No can do - " + "too many SG frags! :-(\n"); + printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n", + numfrags); + goto free_and_fail; + } + } + + /* Last sge fixup: set LE+eol+eob bits */ + sgl[-1].FlagsLength |= cpu_to_le32(0xC1000000); + + /* Chain fixup needed? */ + if (last_chain != NULL && fragcnt < 16) + last_chain->Length = cpu_to_le16(fragcnt * 8); + + *frags = numfrags; + *blp = buflist; + + dprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - " + "%d SG frags generated! (%d CHAIN%s)\n", + numfrags, chaincnt, chaincnt>1?"s":"")); + + dprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - " + "last (big) alloc_sz=%d\n", + alloc_sz)); + + return sglbuf; + +free_and_fail: + if (sglbuf != NULL) { + int i; + + for (i = 0; i < numfrags; i++) { + dma_addr_t dma_addr; + u8 *kptr; + int len; + + if ((sglbuf[i].FlagsLength >> 24) == 0x30) + continue; + + dma_addr = le32_to_cpu(sglbuf[i].Address); + kptr = buflist[i].kptr; + len = buflist[i].len; + + pci_free_consistent(ioc->pcidev, len, kptr, dma_addr); + } + pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf, *sglbuf_dma); + } + kfree(buflist); + return NULL; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static void +kfree_sgl(SGESimple32_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc) +{ + SGESimple32_t *sg = sgl; + struct buflist *bl = buflist; + u32 nib; + int dir; + int n = 0; + + if (sg->FlagsLength & 0x04000000) + dir = PCI_DMA_TODEVICE; + else + dir = PCI_DMA_FROMDEVICE; + + nib = (sg->FlagsLength & 0xF0000000) >> 28; + while (! (nib & 0x4)) { /* eob */ + /* skip ignore/chain. */ + if (nib == 0 || nib == 3) { + ; + } else if (sg->Address) { + dma_addr_t dma_addr; + void *kptr; + int len; + + dma_addr = le32_to_cpu(sg->Address); + kptr = bl->kptr; + len = bl->len; + pci_unmap_single(ioc->pcidev, dma_addr, len, dir); + pci_free_consistent(ioc->pcidev, len, kptr, dma_addr); + n++; + } + sg++; + bl++; + nib = (sg->FlagsLength & 0xF0000000) >> 28; + } + + /* we're at eob! */ + if (sg->Address) { + dma_addr_t dma_addr; + void *kptr; + int len; + + dma_addr = le32_to_cpu(sg->Address); + kptr = bl->kptr; + len = bl->len; + pci_unmap_single(ioc->pcidev, dma_addr, len, dir); + pci_free_consistent(ioc->pcidev, len, kptr, dma_addr); + n++; + } + + pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sgl, sgl_dma); + kfree(buflist); + dprintk((KERN_INFO MYNAM "-SG: Free'd 1 SGL buf + %d kbufs!\n", n)); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_ioctl_rwperf_init(struct mpt_raw_r_w *dest, unsigned long src, + char *caller, MPT_ADAPTER **iocpp) +{ + char *myname = "_rwperf_init()"; + int ioc; + + /* get copy of structure passed from user space */ + if (copy_from_user(dest, (void*)src, sizeof(*dest))) { + printk(KERN_ERR MYNAM "::%s() @%d - Can't copy mpt_raw_r_w data @ %p\n", + myname, __LINE__, (void*)src); + return -EFAULT; /* (-14) Bad address */ + } else { + dprintk((KERN_INFO MYNAM "-perf: PerfInfo.{ioc,targ,qd,iters,nblks}" + ": %d %d %d %d %d\n", + dest->iocnum, dest->target, + (int)dest->qdepth, dest->iters, dest->nblks )); + dprintk((KERN_INFO MYNAM "-perf: PerfInfo.{cache,skip,range,rdwr,seqran}" + ": %d %d %d %d %d\n", + dest->cache_sz, dest->skip, dest->range, + dest->rdwr, dest->seqran )); + + /* Get the MPT adapter id. */ + if ((ioc = mpt_verify_adapter(dest->iocnum, iocpp)) < 0) { + printk(KERN_ERR MYNAM "::%s() @%d - ioc%d not found!\n", + myname, __LINE__, dest->iocnum); + return -ENXIO; /* (-6) No such device or address */ + } else { + dprintk((MYNAM "-perf: %s using mpt/ioc%x, target %02xh\n", + caller, dest->iocnum, dest->target)); + } + } + + return ioc; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/* Treat first N blocks of disk as sacred! */ +#define SACRED_BLOCKS 100 + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_ioctl_rwperf(unsigned long arg) +{ + struct mpt_raw_r_w kPerfInfo; + /* NOTE: local copy, on stack==KERNEL_SPACE! */ + u8 target, targetM; + u8 lun, lunM; + u8 scsiop; + int qdepth; + int iters; + int cache_sz; + u32 xferbytes; + u32 scsidir; + u32 qtag; + u32 scsictl; + u32 sgdir; + u32 blkno; + u32 sbphys; + SGESimple32_t *sgl; + dma_addr_t sgl_dma; + struct buflist *buflist; + SGESimple32_t *sgOut, *sgIn; + int numfrags; + u32 *msg; + int i; + int ioc; + MPT_FRAME_HDR *mf; + MPT_ADAPTER *iocp; + int sgfragcpycnt; + int blklo, blkhi; + u8 nextchainoffset; + u8 *SenseBuf; + dma_addr_t SenseBufDMA; + char *myname = "_rwperf()"; + + dprintk((KERN_INFO "%s - starting...\n", myname)); + + /* Validate target device */ + if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0) + return ioc; + + /* Allocate DMA'able memory for the sense buffer. */ + SenseBuf = pci_alloc_consistent(iocp->pcidev, 256, &SenseBufDMA); + + /* set perf parameters from input */ + target = kPerfInfo.target & 0x0FF; + targetM = target & myMAX_T_MASK; + lun = kPerfInfo.lun & 0x1F; // LUN=31 max + lunM = lun & myMAX_L_MASK; + qdepth = kPerfInfo.qdepth; + iters = kPerfInfo.iters; + xferbytes = ((u32)kPerfInfo.nblks)<<9; + + DevInUse[targetM][lunM] = 1; + DevIosCount[targetM][lunM] = 0; + + cache_sz = kPerfInfo.cache_sz * 1024; // CacheSz in kB! + + /* ToDo: */ + /* get capacity (?) */ + + + // pre-build, one time, everything we can for speed in the loops below... + + scsiop = 0x28; // default to SCSI READ! + scsidir = MPI_SCSIIO_CONTROL_READ; // DATA IN (host<--ioc<--dev) + // 02000000 + qtag = MPI_SCSIIO_CONTROL_SIMPLEQ; // 00000000 + + if (xferbytes == 0) { + // Do 0-byte READ!!! + // IMPORTANT! Need to set no SCSI DIR for this! + scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER; + } + + scsictl = scsidir | qtag; + + /* + * Set sgdir for DMA transfer. + */ +// sgdir = 0x04000000; // SCSI WRITE + sgdir = 0x00000000; // SCSI READ + + if ((sgl = kbuf_alloc_2_sgl(MAX(512,xferbytes), sgdir, &numfrags, &buflist, &sgl_dma, iocp)) == NULL) + return -ENOMEM; + + sgfragcpycnt = MIN(10,numfrags); + nextchainoffset = 0; + if (numfrags > 10) + nextchainoffset = 0x1E; + + sbphys = SenseBufDMA; + + rwperf_reset = 0; + +// do { // target-loop + + blkno = SACRED_BLOCKS; // Treat first N blocks as sacred! + // FIXME! Skip option + blklo = blkno; + blkhi = blkno; + + do { // inner-loop + + while ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { + mb(); + schedule(); + barrier(); + } + msg = (u32*)mf; + + /* Start piecing the SCSIIORequest together */ + msg[0] = 0x00000000 | nextchainoffset<<16 | target; + msg[1] = 0x0000FF0A; // 255 sense bytes, 10-byte CDB! + msg[3] = lun << 8; + msg[4] = 0; + msg[5] = scsictl; + + // 16 bytes of CDB @ msg[6,7,8,9] are below... + + msg[6] = ( ((blkno & 0xFF000000) >> 8) + | ((blkno & 0x00FF0000) << 8) + | scsiop ); + msg[7] = ( (((u32)kPerfInfo.nblks & 0x0000FF00) << 16) + | ((blkno & 0x000000FF) << 8) + | ((blkno & 0x0000FF00) >> 8) ); + msg[8] = (kPerfInfo.nblks & 0x00FF); + msg[9] = 0; + + msg[10] = xferbytes; + +// msg[11] = 0xD0000100; +// msg[12] = sbphys; +// msg[13] = 0; + msg[11] = sbphys; + + // Copy the SGL... + if (xferbytes) { + sgOut = (SGESimple32_t*)&msg[12]; + sgIn = sgl; + for (i=0; i < sgfragcpycnt; i++) + *sgOut++ = *sgIn++; + } + + // fubar! QueueDepth issue!!! + while ( !rwperf_reset + && (DevIosCount[targetM][lunM] >= MIN(qdepth,64)) ) + { + mb(); + schedule(); + barrier(); + } + +// blkno += kPerfInfo.nblks; +// EXP Stuff! +// Try optimizing to certain cache size for the target! +// by keeping blkno within cache range if at all possible +#if 0 + if ( cache_sz + && ((2 * kPerfInfo.nblks) <= (cache_sz>>9)) + && ((blkno + kPerfInfo.nblks) > ((cache_sz>>9) + SACRED_BLOCKS)) ) + blkno = SACRED_BLOCKS; + else + blkno += kPerfInfo.nblks; +#endif +// Ok, cheat! + if (cache_sz && ((blkno + kPerfInfo.nblks) > ((cache_sz>>9) + SACRED_BLOCKS)) ) + blkno = SACRED_BLOCKS; + else + blkno += kPerfInfo.nblks; + + if (blkno > blkhi) + blkhi = blkno; + + DevIosCount[targetM][lunM]++; + + /* + * Finally, post the request + */ + mpt_put_msg_frame(mptctl_id, ioc, mf); + + + /* let linux breath! */ + mb(); + schedule(); + barrier(); + + //dprintk((KERN_DEBUG MYNAM "-perf: inner-loop, cnt=%d\n", iters)); + + } while ((--iters > 0) && !rwperf_reset); + + dprintk((KERN_INFO MYNAM "-perf: DbG: blklo=%d, blkhi=%d\n", blklo, blkhi)); + dprintk((KERN_INFO MYNAM "-perf: target-loop, thisTarget=%d\n", target)); + +// // TEMPORARY! +// target = 0; + +// } while (target); + + + if (DevIosCount[targetM][lunM]) { + dprintk((KERN_INFO " DbG: DevIosCount[%d][%d]=%d\n", + targetM, lunM, DevIosCount[targetM][lunM])); + } + + while (DevIosCount[targetM][lunM]) { + //dprintk((KERN_DEBUG " DbG: Waiting... DevIosCount[%d][%d]=%d\n", + // targetM, lunM, DevIosCount[targetM][lunM])); + mb(); + schedule(); + barrier(); + } + DevInUse[targetM][lunM] = 0; + + pci_free_consistent(iocp->pcidev, 256, SenseBuf, SenseBufDMA); + + if (sgl) + kfree_sgl(sgl, sgl_dma, buflist, iocp); + + dprintk((KERN_INFO " *** done ***\n")); + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_ioctl_rwperf_status(unsigned long arg) +{ + struct mpt_raw_r_w kPerfInfo; + /* NOTE: local copy, on stack==KERNEL_SPACE! */ + MPT_ADAPTER *iocp; + int ioc; +// u8 targ; +// u8 lun; + int T, L; + char *myname = "_rwperf_status()"; + + + dprintk((KERN_INFO "%s - starting...\n", myname)); + + /* Get a pointer to the MPT adapter. */ + if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0) + return ioc; + + /* set perf parameters from input */ +// targ = kPerfInfo.target & 0xFF; +// lun = kPerfInfo.lun & 0x1F; + + for (T=0; T < myMAX_TARGETS; T++) + for (L=0; L < myMAX_LUNS; L++) + if (DevIosCount[T][L]) { + printk(KERN_INFO "%s: ioc%d->00:%02x:%02x" + ", IosCnt=%d\n", + myname, ioc, T, L, DevIosCount[T][L] ); + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_ioctl_rwperf_reset(unsigned long arg) +{ + struct mpt_raw_r_w kPerfInfo; + /* NOTE: local copy, on stack==KERNEL_SPACE! */ + MPT_ADAPTER *iocp; + int ioc; +// u8 targ; +// u8 lun; + int T, L; + int i; + char *myname = "_rwperf_reset()"; + + dprintk((KERN_INFO "%s - starting...\n", myname)); + + /* Get MPT adapter id. */ + if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0) + return ioc; + + /* set perf parameters from input */ +// targ = kPerfInfo.target & 0xFF; +// lun = kPerfInfo.lun & 0x1F; + + rwperf_reset = 1; + for (i=0; i < 1000000; i++) { + mb(); + schedule(); + barrier(); + } + rwperf_reset = 0; + + for (T=0; T < myMAX_TARGETS; T++) + for (L=0; L < myMAX_LUNS; L++) + if (DevIosCount[T][L]) { + printk(KERN_INFO "%s: ioc%d->00:%02x:%02x, " + "IosCnt RESET! (from %d to 0)\n", + myname, ioc, T, L, DevIosCount[T][L] ); + DevIosCount[T][L] = 0; + DevInUse[T][L] = 0; + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_ioctl_scsi_cmd(unsigned long arg) +{ + return -ENOSYS; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +static struct file_operations mptctl_fops = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,51) + owner: THIS_MODULE, +#endif + llseek: mptctl_llseek, + read: mptctl_read, + write: mptctl_write, + ioctl: mpt_ioctl, + open: mptctl_open, + release: mptctl_release, +}; + +static struct miscdevice mptctl_miscdev = { + MPT_MINOR, + MYNAM, + &mptctl_fops +}; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#if defined(__sparc__) && defined(__sparc_v9__) /*{*/ + +/* The dynamic ioctl32 compat. registry only exists in >2.3.x sparc64 kernels */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) /*{*/ +extern int register_ioctl32_conversion(unsigned int cmd, + int (*handler)(unsigned int, + unsigned int, + unsigned long, + struct file *)); +int unregister_ioctl32_conversion(unsigned int cmd); + +struct mpt_fw_xfer32 { + unsigned int iocnum; + unsigned int fwlen; + u32 bufp; +}; + +#define MPTFWDOWNLOAD32 _IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer32) + +extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +sparc32_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd, + unsigned long arg, struct file *filp) +{ + struct mpt_fw_xfer32 kfw32; + struct mpt_fw_xfer kfw; + MPT_ADAPTER *iocp = NULL; + int iocnum, iocnumX; + int nonblock = (filp->f_flags & O_NONBLOCK); + int ret; + + dprintk((KERN_INFO MYNAM "::sparc32_mptfwxfer_ioctl() called\n")); + + if (copy_from_user(&kfw32, (char *)arg, sizeof(kfw32))) + return -EFAULT; + + /* Verify intended MPT adapter */ + iocnumX = kfw32.iocnum & 0xFF; + if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || + (iocp == NULL)) { + printk(KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n", + __LINE__, iocnumX); + return -ENODEV; + } + + if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0) + return ret; + + kfw.iocnum = iocnum; + kfw.fwlen = kfw32.fwlen; + kfw.bufp = (void *)(unsigned long)kfw32.bufp; + + ret = mpt_ioctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen); + + up(&mptctl_syscall_sem_ioc[iocp->id]); + + return ret; +} + +#if 0 /* { */ +static int +sparc32_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd, + unsigned long arg, struct file *filp) +{ + struct mpt_fw_xfer32 kfw32; + struct mpt_fw_xfer kfw; + mm_segment_t old_fs; + int ret; + + dprintk((KERN_INFO MYNAM "::sparc32_mptfwxfer_ioctl() called\n")); + + if (copy_from_user(&kfw32, (char *)arg, sizeof(kfw32))) + return -EFAULT; + + /* Verify intended MPT adapter */ + iocnumX = kfw32.iocnum & 0xFF; + if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || + (iocp == NULL)) { + printk(KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n", + __LINE__, iocnumX); + return -ENODEV; + } + + if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0) + return ret; + + kfw.iocnum = iocnum; + kfw.fwlen = kfw32.fwlen; + kfw.bufp = (void *)(unsigned long)kfw32.bufp; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, MPTFWDOWNLOAD, (unsigned long)&kfw); + set_fs(old_fs); + + up(&mptctl_syscall_sem_ioc[iocp->id]); + + return ret; +} +#endif /* #if 0 } */ + +#endif /*} linux >= 2.3.x */ +#endif /*} sparc */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +int __init mptctl_init(void) +{ + int err; + int i; + int where = 1; + + show_mptmod_ver(my_NAME, my_VERSION); + + for (i=0; i<MPT_MAX_ADAPTERS; i++) { + sema_init(&mptctl_syscall_sem_ioc[i], 1); + } + +#if defined(__sparc__) && defined(__sparc_v9__) /*{*/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) /*{*/ + err = register_ioctl32_conversion(MPTRWPERF, NULL); + if (++where && err) goto out_fail; + err = register_ioctl32_conversion(MPTRWPERF_CHK, NULL); + if (++where && err) goto out_fail; + err = register_ioctl32_conversion(MPTRWPERF_RESET, NULL); + if (++where && err) goto out_fail; + err = register_ioctl32_conversion(MPTFWDOWNLOAD32, + sparc32_mptfwxfer_ioctl); + if (++where && err) goto out_fail; +#endif /*} linux >= 2.3.x */ +#endif /*} sparc */ + + if (misc_register(&mptctl_miscdev) == -1) { + printk(KERN_ERR MYNAM ": Can't register misc device [minor=%d].\n", MPT_MINOR); + err = -EBUSY; + goto out_fail; + } + printk(KERN_INFO MYNAM ": Registered with Fusion MPT base driver\n"); + printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n", + mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor); + + /* + * Install our handler + */ + ++where; + if ((mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER)) < 0) { + printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n"); + misc_deregister(&mptctl_miscdev); + err = -EBUSY; + goto out_fail; + } + + return 0; + +out_fail: + +#if defined(__sparc__) && defined(__sparc_v9__) /*{*/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) /*{*/ + printk(KERN_ERR MYNAM ": ERROR: Failed to register ioctl32_conversion!" + " (%d:err=%d)\n", where, err); + unregister_ioctl32_conversion(MPTRWPERF); + unregister_ioctl32_conversion(MPTRWPERF_CHK); + unregister_ioctl32_conversion(MPTRWPERF_RESET); + unregister_ioctl32_conversion(MPTFWDOWNLOAD32); +#endif /*} linux >= 2.3.x */ +#endif /*} sparc */ + + return err; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +void mptctl_exit(void) +{ + misc_deregister(&mptctl_miscdev); + printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n", + mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor); + printk(KERN_INFO MYNAM ": Deregistered from Fusion MPT base driver\n"); + + mpt_deregister(mptctl_id); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +module_init(mptctl_init); +module_exit(mptctl_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/mptlan.c linux.ac/drivers/message/fusion/mptlan.c --- linux.vanilla/drivers/message/fusion/mptlan.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/mptlan.c Tue Apr 3 17:54:47 2001 @@ -0,0 +1,1462 @@ +/* + * linux/drivers/message/fusion/mptlan.c + * IP Over Fibre Channel device driver. + * For use with PCI chip/adapter(s): + * LSIFC9xx/LSI409xx Fibre Channel + * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * + * Credits: + * This driver would not exist if not for Alan Cox's development + * of the linux i2o driver. + * + * Special thanks goes to the I2O LAN driver people at the + * University of Helsinki, who, unbeknownst to them, provided + * the inspiration and initial structure for this driver. + * + * A huge debt of gratitude is owed to David S. Miller (DaveM) + * for fixing much of the stupid and broken stuff in the early + * driver while porting to sparc64 platform. THANK YOU! + * + * A really huge debt of gratitude is owed to Eddie C. Dost + * for gobs of hard work fixing and optimizing LAN code. + * THANK YOU! + * + * (see also mptbase.c) + * + * Copyright (c) 2000-2001 LSI Logic Corporation + * Originally By: Noah Romer + * + * $Id: mptlan.c,v 1.25 2001/03/02 22:12:04 sralston Exp $ + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + 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. + + NO WARRANTY + THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + solely responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, damage to or loss of data, + programs or equipment, and unavailability or interruption of operations. + + DISCLAIMER OF LIABILITY + NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + 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 +*/ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Define statements used for debugging + */ +//#define MPT_LAN_IO_DEBUG + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#include "mptlan.h" +#include <linux/init.h> +#include <linux/module.h> +#include <linux/fs.h> + +#define MYNAM "mptlan" + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * MPT LAN message sizes without variable part. + */ +#define MPT_LAN_RECEIVE_POST_REQUEST_SIZE \ + (sizeof(LANReceivePostRequest_t) - sizeof(SGE_MPI_UNION)) + +#define MPT_LAN_TRANSACTION32_SIZE \ + (sizeof(SGETransaction32_t) - sizeof(u32)) + +/* + * Fusion MPT LAN private structures + */ + +struct BufferControl { + struct sk_buff *skb; + dma_addr_t dma; + unsigned int len; +}; + +struct mpt_lan_priv { + MPT_ADAPTER *mpt_dev; + u8 pnum; /* Port number in the IOC. This is not a Unix network port! */ + + atomic_t buckets_out; /* number of unused buckets on IOC */ + int bucketthresh; /* Send more when this many used */ + + int *mpt_txfidx; /* Free Tx Context list */ + int mpt_txfidx_tail; + spinlock_t txfidx_lock; + + int *mpt_rxfidx; /* Free Rx Context list */ + int mpt_rxfidx_tail; + spinlock_t rxfidx_lock; + + struct BufferControl *RcvCtl; /* Receive BufferControl structs */ + struct BufferControl *SendCtl; /* Send BufferControl structs */ + + int max_buckets_out; /* Max buckets to send to IOC */ + int tx_max_out; /* IOC's Tx queue len */ + + u32 total_posted; + u32 total_received; + struct net_device_stats stats; /* Per device statistics */ + + struct tq_struct post_buckets_task; + unsigned long post_buckets_active; +}; + +struct mpt_lan_ohdr { + u16 dtype; + u8 daddr[FC_ALEN]; + u16 stype; + u8 saddr[FC_ALEN]; +}; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/* + * Forward protos... + */ +static int lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, + MPT_FRAME_HDR *reply); +static int mpt_lan_open(struct net_device *dev); +static int mpt_lan_reset(struct net_device *dev); +static int mpt_lan_close(struct net_device *dev); +static void mpt_lan_post_receive_buckets(void *dev_id); +static void mpt_lan_wake_post_buckets_task(struct net_device *dev); +static int mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg); +static int mpt_lan_receive_post_reply(struct net_device *dev, + LANReceivePostReply_t *pRecvRep); +static int mpt_lan_send_turbo(struct net_device *dev, u32 tmsg); +static int mpt_lan_send_reply(struct net_device *dev, + LANSendReply_t *pSendRep); +static int mpt_lan_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); +static unsigned short mpt_lan_type_trans(struct sk_buff *skb, + struct net_device *dev); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Fusion MPT LAN private data + */ +static int LanCtx = -1; + +static u32 max_buckets_out = 127; +static u32 tx_max_out_p = 127 - 16; + +static struct net_device *mpt_landev[MPT_MAX_ADAPTERS+1]; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Fusion MPT LAN external data + */ +extern int mpt_lan_index; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * lan_reply - Handle all data sent from the hardware. + * @ioc: Pointer to MPT_ADAPTER structure + * @mf: Pointer to original MPT request frame (NULL if TurboReply) + * @reply: Pointer to MPT reply frame + * + * Returns 1 indicating original alloc'd request frame ptr + * should be freed, or 0 if it shouldn't. + */ +static int +lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) +{ + struct net_device *dev = mpt_landev[ioc->id]; + int FreeReqFrame = 0; + + dioprintk((KERN_INFO MYNAM ": %s/%s: Got reply.\n", + IOC_AND_NETDEV_NAMES_s_s(dev))); + +// dioprintk((KERN_INFO MYNAM "@lan_reply: mf = %p, reply = %p\n", +// mf, reply)); + + if (mf == NULL) { + u32 tmsg = CAST_PTR_TO_U32(reply); + + dioprintk((KERN_INFO MYNAM ": %s/%s: @lan_reply, tmsg %08x\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + tmsg)); + + switch (GET_LAN_FORM(tmsg)) { + + // NOTE! (Optimization) First case here is now caught in + // mptbase.c::mpt_interrupt() routine and callcack here + // is now skipped for this case! 20001218 -sralston +#if 0 + case LAN_REPLY_FORM_MESSAGE_CONTEXT: +// dioprintk((KERN_INFO MYNAM "/lan_reply: " +// "MessageContext turbo reply received\n")); + FreeReqFrame = 1; + break; +#endif + + case LAN_REPLY_FORM_SEND_SINGLE: +// dioprintk((MYNAM "/lan_reply: " +// "calling mpt_lan_send_reply (turbo)\n")); + + // Potential BUG here? -sralston + // FreeReqFrame = mpt_lan_send_turbo(dev, tmsg); + // If/when mpt_lan_send_turbo would return 1 here, + // calling routine (mptbase.c|mpt_interrupt) + // would Oops because mf has already been set + // to NULL. So after return from this func, + // mpt_interrupt() will attempt to put (NULL) mf ptr + // item back onto it's adapter FreeQ - Oops!:-( + // It's Ok, since mpt_lan_send_turbo() *currently* + // always returns 0, but..., just in case: + + (void) mpt_lan_send_turbo(dev, tmsg); + FreeReqFrame = 0; + + break; + + case LAN_REPLY_FORM_RECEIVE_SINGLE: +// dioprintk((KERN_INFO MYNAM "@lan_reply: " +// "rcv-Turbo = %08x\n", tmsg)); + mpt_lan_receive_post_turbo(dev, tmsg); + break; + + default: + printk (KERN_ERR MYNAM "/lan_reply: Got a turbo reply " + "that I don't know what to do with\n"); + + /* CHECKME! Hmmm... FreeReqFrame is 0 here; is that right? */ + + break; + } + + return FreeReqFrame; + } + +// msg = (u32 *) reply; +// dioprintk((KERN_INFO MYNAM "@lan_reply: msg = %08x %08x %08x %08x\n", +// le32_to_cpu(msg[0]), le32_to_cpu(msg[1]), +// le32_to_cpu(msg[2]), le32_to_cpu(msg[3]))); +// dioprintk((KERN_INFO MYNAM "@lan_reply: Function = %02xh\n", +// reply->u.hdr.Function)); + + switch (reply->u.hdr.Function) { + + case MPI_FUNCTION_LAN_SEND: + { + LANSendReply_t *pSendRep; + + pSendRep = (LANSendReply_t *) reply; + FreeReqFrame = mpt_lan_send_reply(dev, pSendRep); + break; + } + + case MPI_FUNCTION_LAN_RECEIVE: + { + LANReceivePostReply_t *pRecvRep; + + pRecvRep = (LANReceivePostReply_t *) reply; + if (pRecvRep->NumberOfContexts) { + mpt_lan_receive_post_reply(dev, pRecvRep); + if (!(pRecvRep->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) + FreeReqFrame = 1; + } else + dioprintk((KERN_INFO MYNAM "@lan_reply: zero context " + "ReceivePostReply received.\n")); + break; + } + + case MPI_FUNCTION_LAN_RESET: + /* Just a default reply. Might want to check it to + * make sure that everything went ok. + */ + FreeReqFrame = 1; + break; + + case MPI_FUNCTION_EVENT_NOTIFICATION: + case MPI_FUNCTION_EVENT_ACK: + /* UPDATE! 20010120 -sralston + * _EVENT_NOTIFICATION should NOT come down this path any more. + * Should be routed to mpt_lan_event_process(), but just in case... + */ + FreeReqFrame = 1; + break; + + default: + printk (KERN_ERR MYNAM "/lan_reply: Got a non-turbo " + "reply that I don't know what to do with\n"); + + /* CHECKME! Hmmm... FreeReqFrame is 0 here; is that right? */ + FreeReqFrame = 1; + + break; + } + + return FreeReqFrame; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_lan_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) +{ + dprintk((KERN_INFO MYNAM ": MPT event routed to LAN driver!\n")); + + switch (le32_to_cpu(pEvReply->Event)) { + case MPI_EVENT_NONE: /* 00 */ + case MPI_EVENT_LOG_DATA: /* 01 */ + case MPI_EVENT_STATE_CHANGE: /* 02 */ + case MPI_EVENT_UNIT_ATTENTION: /* 03 */ + case MPI_EVENT_IOC_BUS_RESET: /* 04 */ + case MPI_EVENT_EXT_BUS_RESET: /* 05 */ + case MPI_EVENT_RESCAN: /* 06 */ + /* Ok, do we need to do anything here? As far as + I can tell, this is when a new device gets added + to the loop. */ + case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */ + case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */ + case MPI_EVENT_LOGOUT: /* 09 */ + case MPI_EVENT_EVENT_CHANGE: /* 0A */ + default: + break; + } + + /* + * NOTE: pEvent->AckRequired handling now done in mptbase.c; + * Do NOT do it here now! + */ + + return 1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_lan_open(struct net_device *dev) +{ + struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + int i; + + mpt_lan_reset(dev); + + priv->mpt_txfidx = kmalloc(priv->tx_max_out * sizeof(int), GFP_KERNEL); + if (priv->mpt_txfidx == NULL) + goto out; + priv->mpt_txfidx_tail = -1; + + priv->SendCtl = kmalloc(priv->tx_max_out * sizeof(struct BufferControl), + GFP_KERNEL); + if (priv->SendCtl == NULL) + goto out_mpt_txfidx; + for (i = 0; i < priv->tx_max_out; i++) { + memset(&priv->SendCtl[i], 0, sizeof(struct BufferControl)); + priv->mpt_txfidx[++priv->mpt_txfidx_tail] = i; + } + + dprintk((KERN_INFO MYNAM "@lo: Finished initializing SendCtl\n")); + + priv->mpt_rxfidx = kmalloc(priv->max_buckets_out * sizeof(int), + GFP_KERNEL); + if (priv->mpt_rxfidx == NULL) + goto out_SendCtl; + priv->mpt_rxfidx_tail = -1; + + priv->RcvCtl = kmalloc(priv->max_buckets_out * + sizeof(struct BufferControl), + GFP_KERNEL); + if (priv->RcvCtl == NULL) + goto out_mpt_rxfidx; + for (i = 0; i < priv->max_buckets_out; i++) { + memset(&priv->RcvCtl[i], 0, sizeof(struct BufferControl)); + priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i; + } + +/**/ dprintk((KERN_INFO MYNAM "/lo: txfidx contains - ")); +/**/ for (i = 0; i < priv->tx_max_out; i++) +/**/ dprintk((" %xh", priv->mpt_txfidx[i])); +/**/ dprintk(("\n")); + + dprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n")); + + mpt_lan_post_receive_buckets(dev); + printk(KERN_INFO MYNAM ": %s/%s: interface up & active\n", + IOC_AND_NETDEV_NAMES_s_s(dev)); + + if (mpt_event_register(LanCtx, mpt_lan_event_process) != 0) { + /* FIXME! */ + } + + netif_start_queue(dev); + dprintk((KERN_INFO MYNAM "/lo: Done.\n")); + + return 0; +out_mpt_rxfidx: + kfree(priv->mpt_rxfidx); + priv->mpt_rxfidx = NULL; +out_SendCtl: + kfree(priv->SendCtl); + priv->SendCtl = NULL; +out_mpt_txfidx: + kfree(priv->mpt_txfidx); + priv->mpt_txfidx = NULL; +out: return -ENOMEM; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_lan_reset(struct net_device *dev) +{ + MPT_FRAME_HDR *mf; + LANResetRequest_t *pResetReq; + struct mpt_lan_priv *priv = (struct mpt_lan_priv *)dev->priv; + + mf = mpt_get_msg_frame(LanCtx, priv->mpt_dev->id); + + if (mf == NULL) { +/* dprintk((KERN_ERR MYNAM "/reset: Evil funkiness abounds! " + "Unable to allocate a request frame.\n")); +*/ + return -1; + } + + pResetReq = (LANResetRequest_t *) mf; + + pResetReq->Function = MPI_FUNCTION_LAN_RESET; + pResetReq->ChainOffset = 0; + pResetReq->Reserved = 0; + pResetReq->PortNumber = priv->pnum; + pResetReq->MsgFlags = 0; + pResetReq->Reserved2 = 0; + + mpt_put_msg_frame(LanCtx, priv->mpt_dev->id, mf); + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_lan_close(struct net_device *dev) +{ + struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + MPT_ADAPTER *mpt_dev = priv->mpt_dev; + unsigned int timeout; + int i; + + dprintk((KERN_INFO MYNAM ": mpt_lan_close called\n")); + + mpt_event_deregister(LanCtx); + + dprintk((KERN_INFO MYNAM ":lan_close: Posted %d buckets " + "since driver was loaded, %d still out\n", + priv->total_posted,atomic_read(&priv->buckets_out))); + + netif_stop_queue(dev); + + mpt_lan_reset(dev); + + timeout = 2 * HZ; + while (atomic_read(&priv->buckets_out) && --timeout) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + + for (i = 0; i < priv->max_buckets_out; i++) { + if (priv->RcvCtl[i].skb != NULL) { +/**/ dprintk((KERN_INFO MYNAM "/lan_close: bucket %05x " +/**/ "is still out\n", i)); + pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[i].dma, + priv->RcvCtl[i].len, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(priv->RcvCtl[i].skb); + } + } + + kfree (priv->RcvCtl); + kfree (priv->mpt_rxfidx); + + for (i = 0; i < priv->tx_max_out; i++) { + if (priv->SendCtl[i].skb != NULL) { + pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[i].dma, + priv->SendCtl[i].len, + PCI_DMA_TODEVICE); + dev_kfree_skb(priv->SendCtl[i].skb); + } + } + + kfree(priv->SendCtl); + kfree(priv->mpt_txfidx); + + atomic_set(&priv->buckets_out, 0); + + printk(KERN_INFO MYNAM ": %s/%s: interface down & inactive\n", + IOC_AND_NETDEV_NAMES_s_s(dev)); + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static struct net_device_stats * +mpt_lan_get_stats(struct net_device *dev) +{ + struct mpt_lan_priv *priv = (struct mpt_lan_priv *)dev->priv; + + return (struct net_device_stats *) &priv->stats; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_lan_change_mtu(struct net_device *dev, int new_mtu) +{ + if ((new_mtu < MPT_LAN_MIN_MTU) || (new_mtu > MPT_LAN_MAX_MTU)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* Tx timeout handler. */ +static void +mpt_lan_tx_timeout(struct net_device *dev) +{ + netif_wake_queue(dev); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +//static inline int +static int +mpt_lan_send_turbo(struct net_device *dev, u32 tmsg) +{ + struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + MPT_ADAPTER *mpt_dev = priv->mpt_dev; + struct sk_buff *sent; + unsigned long flags; + u32 ctx; + + ctx = GET_LAN_BUFFER_CONTEXT(tmsg); + sent = priv->SendCtl[ctx].skb; + + priv->stats.tx_packets++; + priv->stats.tx_bytes += sent->len; + + dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + __FUNCTION__, sent)); + + priv->SendCtl[ctx].skb = NULL; + pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma, + priv->SendCtl[ctx].len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(sent); + + spin_lock_irqsave(&priv->txfidx_lock, flags); + priv->mpt_txfidx[++priv->mpt_txfidx_tail] = ctx; + spin_unlock_irqrestore(&priv->txfidx_lock, flags); + + netif_wake_queue(dev); + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep) +{ + struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + MPT_ADAPTER *mpt_dev = priv->mpt_dev; + struct sk_buff *sent; + unsigned long flags; + int FreeReqFrame = 0; + u32 *pContext; + u32 ctx; + u8 count; + + count = pSendRep->NumberOfContexts; + + dioprintk((KERN_INFO MYNAM ": send_reply: IOCStatus: %04x\n", + le16_to_cpu(pSendRep->IOCStatus))); + + /* Add check for Loginfo Flag in IOCStatus */ + + switch (le16_to_cpu(pSendRep->IOCStatus)) { + case MPI_IOCSTATUS_SUCCESS: + priv->stats.tx_packets += count; + break; + + case MPI_IOCSTATUS_LAN_CANCELED: + case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: + break; + + case MPI_IOCSTATUS_INVALID_SGL: + priv->stats.tx_errors += count; + printk (KERN_ERR MYNAM ": %s/%s: ERROR - Invalid SGL sent to IOC!\n", + IOC_AND_NETDEV_NAMES_s_s(dev)); + goto out; + + default: + priv->stats.tx_errors += count; + break; + } + + pContext = &pSendRep->BufferContext; + + spin_lock_irqsave(&priv->txfidx_lock, flags); + while (count > 0) { + ctx = GET_LAN_BUFFER_CONTEXT(le32_to_cpu(*pContext)); + + sent = priv->SendCtl[ctx].skb; + priv->stats.tx_bytes += sent->len; + + dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + __FUNCTION__, sent)); + + priv->SendCtl[ctx].skb = NULL; + pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma, + priv->SendCtl[ctx].len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(sent); + + priv->mpt_txfidx[++priv->mpt_txfidx_tail] = ctx; + + pContext++; + count--; + } + spin_unlock_irqrestore(&priv->txfidx_lock, flags); + +out: + if (!(pSendRep->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) + FreeReqFrame = 1; + + netif_wake_queue(dev); + return FreeReqFrame; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) +{ + struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + MPT_ADAPTER *mpt_dev = priv->mpt_dev; + MPT_FRAME_HDR *mf; + LANSendRequest_t *pSendReq; + SGETransaction32_t *pTrans; + SGESimple64_t *pSimple; + dma_addr_t dma; + unsigned long flags; + int ctx; + + dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n", + __FUNCTION__, skb)); + + spin_lock_irqsave(&priv->txfidx_lock, flags); + if (priv->mpt_txfidx_tail < 0) { + netif_stop_queue(dev); + spin_unlock_irqrestore(&priv->txfidx_lock, flags); + + printk (KERN_ERR "%s: no tx context available: %u\n", + __FUNCTION__, priv->mpt_txfidx_tail); + return 1; + } + + mf = mpt_get_msg_frame(LanCtx, mpt_dev->id); + if (mf == NULL) { + netif_stop_queue(dev); + dev_kfree_skb(skb); + spin_unlock_irqrestore(&priv->txfidx_lock, flags); + + printk (KERN_ERR "%s: Unable to alloc request frame\n", + __FUNCTION__); + return 1; + } + + ctx = priv->mpt_txfidx[priv->mpt_txfidx_tail--]; + spin_unlock_irqrestore(&priv->txfidx_lock, flags); + +// dioprintk((KERN_INFO MYNAM ": %s/%s: Creating new msg frame (send).\n", +// IOC_AND_NETDEV_NAMES_s_s(dev))); + + pSendReq = (LANSendRequest_t *) mf; + + /* Set the mac.raw pointer, since this apparently isn't getting + * done before we get the skb. Pull the data pointer past the mac data. + */ + skb->mac.raw = skb->data; + skb_pull(skb, 12); + + dma = pci_map_single(mpt_dev->pcidev, skb->data, skb->len, + PCI_DMA_TODEVICE); + + priv->SendCtl[ctx].skb = skb; + priv->SendCtl[ctx].dma = dma; + priv->SendCtl[ctx].len = skb->len; + + /* Message Header */ + pSendReq->Function = MPI_FUNCTION_LAN_SEND; + pSendReq->ChainOffset = 0; + pSendReq->MsgFlags = 0; + pSendReq->PortNumber = priv->pnum; + + /* Transaction Context Element */ + pTrans = (SGETransaction32_t *) pSendReq->SG_List; + + /* No Flags, 8 bytes of Details, 32bit Context (bloody turbo replies) */ + pTrans->ContextSize = sizeof(u32); + pTrans->DetailsLength = 2 * sizeof(u32); + pTrans->Flags = 0; + pTrans->TransactionContext[0] = cpu_to_le32(ctx); + +// dioprintk((KERN_INFO MYNAM ": %s/%s: BC = %08x, skb = %p, buff = %p\n", +// IOC_AND_NETDEV_NAMES_s_s(dev), +// ctx, skb, skb->data)); + + pTrans->TransactionDetails[0] = cpu_to_le32((0x1000 << 16) | + (skb->mac.raw[0] << 8) | + (skb->mac.raw[1] << 0)); + pTrans->TransactionDetails[1] = cpu_to_le32((skb->mac.raw[2] << 24) | + (skb->mac.raw[3] << 16) | + (skb->mac.raw[4] << 8) | + (skb->mac.raw[5] << 0)); + + pSimple = (SGESimple64_t *) &pTrans->TransactionDetails[2]; + + pSimple->FlagsLength = cpu_to_le32( + ((MPI_SGE_FLAGS_END_OF_BUFFER | + MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_64_BIT_ADDRESSING | + MPI_SGE_FLAGS_END_OF_LIST) << MPI_SGE_FLAGS_SHIFT) | + skb->len); + pSimple->Address.Low = cpu_to_le32((u32) dma); + if (sizeof(dma_addr_t) > sizeof(u32)) + pSimple->Address.High = cpu_to_le32((u32) ((u64) dma >> 32)); + else + pSimple->Address.High = 0; + + mpt_put_msg_frame (LanCtx, mpt_dev->id, mf); + dev->trans_start = jiffies; + + dioprintk((KERN_INFO MYNAM ": %s/%s: Sending packet. FlagsLength = %08x.\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + le32_to_cpu(pSimple->FlagsLength))); + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static inline void +mpt_lan_wake_post_buckets_task(struct net_device *dev) +{ + struct mpt_lan_priv *priv = dev->priv; + + if (test_and_set_bit(0, &priv->post_buckets_active) == 0) { + queue_task(&priv->post_buckets_task, &tq_immediate); + mark_bh(IMMEDIATE_BH); + dioprintk((KERN_INFO MYNAM ": %s/%s: Queued post_buckets task.\n", + IOC_AND_NETDEV_NAMES_s_s(dev) )); + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static inline int +mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb) +{ + struct mpt_lan_priv *priv = dev->priv; + + skb->protocol = mpt_lan_type_trans(skb, dev); + + dioprintk((KERN_INFO MYNAM ": %s/%s: Incoming packet (%d bytes) " + "delivered to upper level.\n", + IOC_AND_NETDEV_NAMES_s_s(dev), skb->len)); + + priv->stats.rx_bytes += skb->len; + priv->stats.rx_packets++; + + skb->dev = dev; + netif_rx(skb); + + dioprintk((MYNAM "/receive_skb: %d buckets remaining\n", + atomic_read(&priv->buckets_out))); + + if (atomic_read(&priv->buckets_out) < priv->bucketthresh) + mpt_lan_wake_post_buckets_task(dev); + + dioprintk((KERN_INFO MYNAM "/receive_post_reply: %d buckets " + "remaining, %d received back since sod\n", + atomic_read(&priv->buckets_out), priv->total_received)); + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +//static inline int +static int +mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg) +{ + struct mpt_lan_priv *priv = dev->priv; + MPT_ADAPTER *mpt_dev = priv->mpt_dev; + struct sk_buff *skb, *old_skb; + unsigned long flags; + u32 ctx, len; + + ctx = GET_LAN_BUCKET_CONTEXT(tmsg); + skb = priv->RcvCtl[ctx].skb; + + len = GET_LAN_PACKET_LENGTH(tmsg); + + if (len < MPT_LAN_RX_COPYBREAK) { + old_skb = skb; + + skb = (struct sk_buff *)dev_alloc_skb(len); + if (!skb) { + printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + __FILE__, __LINE__); + return -ENOMEM; + } + + pci_dma_sync_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); + + memcpy(skb_put(skb, len), old_skb->data, len); + + goto out; + } + + skb_put(skb, len); + + priv->RcvCtl[ctx].skb = NULL; + + pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); + +out: + spin_lock_irqsave(&priv->rxfidx_lock, flags); + priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; + spin_unlock_irqrestore(&priv->rxfidx_lock, flags); + + atomic_dec(&priv->buckets_out); + priv->total_received++; + + return mpt_lan_receive_skb(dev, skb); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_lan_receive_post_free(struct net_device *dev, + LANReceivePostReply_t *pRecvRep) +{ + struct mpt_lan_priv *priv = dev->priv; + MPT_ADAPTER *mpt_dev = priv->mpt_dev; + unsigned long flags; + struct sk_buff *skb; + u32 ctx; + u8 count; + int i; + + count = pRecvRep->NumberOfContexts; + +/**/ dprintk((KERN_INFO MYNAM "/receive_post_reply: " + "IOC returned %d buckets, freeing them...\n", count)); + + spin_lock_irqsave(&priv->rxfidx_lock, flags); + for (i = 0; i < count; i++) { + ctx = le32_to_cpu(pRecvRep->BucketContext[i]); + + skb = priv->RcvCtl[ctx].skb; + +// dprintk((KERN_INFO MYNAM ": %s: dev_name = %s\n", +// IOC_AND_NETDEV_NAMES_s_s(dev))); +// dprintk((KERN_INFO MYNAM "@rpr[2], priv = %p, buckets_out addr = %p", +// priv, &(priv->buckets_out))); +// dprintk((KERN_INFO MYNAM "@rpr[2] TC + 3\n")); + + priv->RcvCtl[ctx].skb = NULL; + pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(skb); + + priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; + } + spin_unlock_irqrestore(&priv->rxfidx_lock, flags); + + atomic_sub(count, &priv->buckets_out); + +// for (i = 0; i < priv->max_buckets_out; i++) +// if (priv->RcvCtl[i].skb != NULL) +// dprintk((KERN_INFO MYNAM "@rpr: bucket %03x " +// "is still out\n", i)); + +/* dprintk((KERN_INFO MYNAM "/receive_post_reply: freed %d buckets\n", + count)); +*/ +/**/ dprintk((KERN_INFO MYNAM "@receive_post_reply: %d buckets " +/**/ "remaining, %d received back since sod.\n", +/**/ atomic_read(&priv->buckets_out), priv->total_received)); + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_lan_receive_post_reply(struct net_device *dev, + LANReceivePostReply_t *pRecvRep) +{ + struct mpt_lan_priv *priv = dev->priv; + MPT_ADAPTER *mpt_dev = priv->mpt_dev; + struct sk_buff *skb, *old_skb; + unsigned long flags; + u32 len, ctx; + u32 offset; + u8 count; + int i, l; + + dioprintk((KERN_INFO MYNAM ": mpt_lan_receive_post_reply called\n")); + dioprintk((KERN_INFO MYNAM ": receive_post_reply: IOCStatus: %04x\n", + le16_to_cpu(pRecvRep->IOCStatus))); + + if (le16_to_cpu(pRecvRep->IOCStatus) & MPI_IOCSTATUS_LAN_CANCELED) + return mpt_lan_receive_post_free(dev, pRecvRep); + + len = le32_to_cpu(pRecvRep->PacketLength); + if (len == 0) { + printk (KERN_ERR MYNAM ": %s/%s: ERROR - Got a non-TURBO " + "ReceivePostReply w/ PacketLength zero!\n", + IOC_AND_NETDEV_NAMES_s_s(dev)); + printk (KERN_ERR MYNAM ": MsgFlags = %02x, IOCStatus = %04x\n", + pRecvRep->MsgFlags, le16_to_cpu(pRecvRep->IOCStatus)); + return -1; + } + + ctx = le32_to_cpu(pRecvRep->BucketContext[0]); + count = pRecvRep->NumberOfContexts; + skb = priv->RcvCtl[ctx].skb; + + offset = le32_to_cpu(pRecvRep->PacketOffset); +// if (offset != 0) { +// printk (KERN_INFO MYNAM ": %s/%s: Got a ReceivePostReply " +// "w/ PacketOffset %u\n", +// IOC_AND_NETDEV_NAMES_s_s(dev), +// offset); +// } + + dioprintk((KERN_INFO MYNAM ": %s/%s: @rpr, offset = %d, len = %d\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + offset, len)); + + if (count > 1) { + int szrem = len; + +// dioprintk((KERN_INFO MYNAM ": %s/%s: Multiple buckets returned " +// "for single packet, concatenating...\n", +// IOC_AND_NETDEV_NAMES_s_s(dev))); + + skb = (struct sk_buff *)dev_alloc_skb(len); + if (!skb) { + printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + __FILE__, __LINE__); + return -ENOMEM; + } + + spin_lock_irqsave(&priv->rxfidx_lock, flags); + for (i = 0; i < count; i++) { + + ctx = le32_to_cpu(pRecvRep->BucketContext[i]); + old_skb = priv->RcvCtl[ctx].skb; + + l = priv->RcvCtl[ctx].len; + if (szrem < l) + l = szrem; + +// dioprintk((KERN_INFO MYNAM ": %s/%s: Buckets = %d, len = %u\n", +// IOC_AND_NETDEV_NAMES_s_s(dev), +// i, l)); + + pci_dma_sync_single(mpt_dev->pcidev, + priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, + PCI_DMA_FROMDEVICE); + memcpy(skb_put(skb, l), old_skb->data, l); + + priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; + szrem -= l; + } + spin_unlock_irqrestore(&priv->rxfidx_lock, flags); + + } else if (len < MPT_LAN_RX_COPYBREAK) { + + old_skb = skb; + + skb = (struct sk_buff *)dev_alloc_skb(len); + if (!skb) { + printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + __FILE__, __LINE__); + return -ENOMEM; + } + + pci_dma_sync_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); + + memcpy(skb_put(skb, len), old_skb->data, len); + + spin_lock_irqsave(&priv->rxfidx_lock, flags); + priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; + spin_unlock_irqrestore(&priv->rxfidx_lock, flags); + + } else { + spin_lock_irqsave(&priv->rxfidx_lock, flags); + + priv->RcvCtl[ctx].skb = NULL; + + pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); + priv->RcvCtl[ctx].dma = 0; + + priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; + spin_unlock_irqrestore(&priv->rxfidx_lock, flags); + + skb_put(skb,len); + } + + atomic_sub(count, &priv->buckets_out); + priv->total_received += count; + + if (priv->mpt_rxfidx_tail >= MPT_LAN_MAX_BUCKETS_OUT) { + printk (KERN_ERR MYNAM ": %s/%s: Yoohoo! mpt_rxfidx_tail = %d, " + "MPT_LAN_MAX_BUCKETS_OUT = %d\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + priv->mpt_rxfidx_tail, + MPT_LAN_MAX_BUCKETS_OUT); + + panic("Damn it Jim! I'm a doctor, not a programmer! " + "Oh, wait a sec, I am a programmer. " + "And, who's Jim?!?!\n" + "Arrgghh! We've done it again!\n"); + } + +#if 0 + { + u32 remaining = le32_to_cpu(pRecvRep->BucketsRemaining); + if (remaining < priv->bucketthresh) + mpt_lan_wake_post_buckets_task(dev); + + if (remaining == 0) + printk (KERN_WARNING MYNAM ": %s/%s: WARNING - IOC out of buckets! " + "(priv->buckets_out = %d)\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + atomic_read(&priv->buckets_out)); + else + printk (KERN_INFO MYNAM ": %s/%s: IOC says %d buckets left. " + "(priv->buckets_out = %d)\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + remaining, atomic_read(&priv->buckets_out)); + } +#endif + + return mpt_lan_receive_skb(dev, skb); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* Simple SGE's only at the moment */ + +static void +mpt_lan_post_receive_buckets(void *dev_id) +{ + struct net_device *dev = dev_id; + struct mpt_lan_priv *priv = dev->priv; + MPT_ADAPTER *mpt_dev = priv->mpt_dev; + MPT_FRAME_HDR *mf; + LANReceivePostRequest_t *pRecvReq; + SGETransaction32_t *pTrans; + SGESimple64_t *pSimple; + struct sk_buff *skb; + dma_addr_t dma; + u32 curr, buckets, count, max; + u32 len = (dev->mtu + dev->hard_header_len + 4); + unsigned long flags; + int i; + + curr = atomic_read(&priv->buckets_out); + buckets = (priv->max_buckets_out - curr); + + dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, Start_buckets = %u, buckets_out = %u\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + __FUNCTION__, buckets, curr)); + + max = (mpt_dev->req_sz - MPT_LAN_RECEIVE_POST_REQUEST_SIZE) / + (MPT_LAN_TRANSACTION32_SIZE + sizeof(SGESimple64_t)); + + while (buckets) { + mf = mpt_get_msg_frame(LanCtx, mpt_dev->id); + if (mf == NULL) { + printk (KERN_ERR "%s: Unable to alloc request frame\n", + __FUNCTION__); + dioprintk((KERN_ERR "%s: %u buckets remaining\n", + __FUNCTION__, buckets)); + goto out; + } + pRecvReq = (LANReceivePostRequest_t *) mf; + + count = buckets; + if (count > max) + count = max; + + pRecvReq->Function = MPI_FUNCTION_LAN_RECEIVE; + pRecvReq->ChainOffset = 0; + pRecvReq->MsgFlags = 0; + pRecvReq->PortNumber = priv->pnum; + + pTrans = (SGETransaction32_t *) pRecvReq->SG_List; + pSimple = NULL; + + for (i = 0; i < count; i++) { + int ctx; + + spin_lock_irqsave(&priv->rxfidx_lock, flags); + if (priv->mpt_rxfidx_tail < 0) { + printk (KERN_ERR "%s: Can't alloc context\n", + __FUNCTION__); + spin_unlock_irqrestore(&priv->rxfidx_lock, + flags); + break; + } + + ctx = priv->mpt_rxfidx[priv->mpt_rxfidx_tail--]; + + skb = priv->RcvCtl[ctx].skb; + if (skb && (priv->RcvCtl[ctx].len != len)) { + pci_unmap_single(mpt_dev->pcidev, + priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(priv->RcvCtl[ctx].skb); + skb = priv->RcvCtl[ctx].skb = NULL; + } + + if (skb == NULL) { + skb = dev_alloc_skb(len); + if (skb == NULL) { +/**/ printk (KERN_WARNING +/**/ MYNAM "/%s: Can't alloc skb\n", +/**/ __FUNCTION__); + priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; + spin_unlock_irqrestore(&priv->rxfidx_lock, flags); + break; + } + + dma = pci_map_single(mpt_dev->pcidev, skb->data, + len, PCI_DMA_FROMDEVICE); + + priv->RcvCtl[ctx].skb = skb; + priv->RcvCtl[ctx].dma = dma; + priv->RcvCtl[ctx].len = len; + } + + spin_unlock_irqrestore(&priv->rxfidx_lock, flags); + + pTrans->ContextSize = sizeof(u32); + pTrans->DetailsLength = 0; + pTrans->Flags = 0; + pTrans->TransactionContext[0] = cpu_to_le32(ctx); + + pSimple = (SGESimple64_t *) pTrans->TransactionDetails; + + pSimple->FlagsLength = cpu_to_le32( + ((MPI_SGE_FLAGS_END_OF_BUFFER | + MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_64_BIT_ADDRESSING) << MPI_SGE_FLAGS_SHIFT) | len); + pSimple->Address.Low = cpu_to_le32((u32) priv->RcvCtl[ctx].dma); + if (sizeof(dma_addr_t) > sizeof(u32)) + pSimple->Address.High = cpu_to_le32((u32) ((u64) priv->RcvCtl[ctx].dma >> 32)); + else + pSimple->Address.High = 0; + + pTrans = (SGETransaction32_t *) (pSimple + 1); + } + + if (pSimple == NULL) { +/**/ printk (KERN_WARNING MYNAM "/%s: No buckets posted\n", +/**/ __FUNCTION__); + mpt_free_msg_frame(LanCtx, mpt_dev->id, mf); + goto out; + } + + pSimple->FlagsLength |= cpu_to_le32(MPI_SGE_FLAGS_END_OF_LIST << MPI_SGE_FLAGS_SHIFT); + + pRecvReq->BucketCount = cpu_to_le32(i); + +/* printk(KERN_INFO MYNAM ": posting buckets\n "); + * for (i = 0; i < j + 2; i ++) + * printk (" %08x", le32_to_cpu(msg[i])); + * printk ("\n"); + */ + + mpt_put_msg_frame(LanCtx, mpt_dev->id, mf); + + priv->total_posted += i; + buckets -= i; + atomic_add(i, &priv->buckets_out); + } + +out: + dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n", + __FUNCTION__, buckets, atomic_read(&priv->buckets_out))); + dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n", + __FUNCTION__, priv->total_posted, priv->total_received)); + + clear_bit(0, &priv->post_buckets_active); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +struct net_device * +mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum) +{ + struct net_device *dev = NULL; + struct mpt_lan_priv *priv = NULL; + u8 HWaddr[FC_ALEN], *a; + + dev = init_fcdev(NULL, sizeof(struct mpt_lan_priv)); + if (!dev) + return (NULL); + dev->mtu = MPT_LAN_MTU; + + priv = (struct mpt_lan_priv *) dev->priv; + + priv->mpt_dev = mpt_dev; + priv->pnum = pnum; + + memset(&priv->post_buckets_task, 0, sizeof(struct tq_struct)); + priv->post_buckets_task.routine = mpt_lan_post_receive_buckets; + priv->post_buckets_task.data = dev; + priv->post_buckets_active = 0; + + dprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n", + __LINE__, dev->mtu + dev->hard_header_len + 4)); + + atomic_set(&priv->buckets_out, 0); + priv->total_posted = 0; + priv->total_received = 0; + priv->max_buckets_out = max_buckets_out; + if (mpt_dev->pfacts0.MaxLanBuckets < max_buckets_out) + priv->max_buckets_out = mpt_dev->pfacts0.MaxLanBuckets; + + dprintk((KERN_INFO MYNAM "@%d: MaxLanBuckets=%d, max_buckets_out/priv=%d/%d\n", + __LINE__, + mpt_dev->pfacts0.MaxLanBuckets, + max_buckets_out, + priv->max_buckets_out)); + + priv->bucketthresh = priv->max_buckets_out * 2 / 3; + priv->txfidx_lock = SPIN_LOCK_UNLOCKED; + priv->rxfidx_lock = SPIN_LOCK_UNLOCKED; + + memset(&priv->stats, 0, sizeof(priv->stats)); + + /* Grab pre-fetched LANPage1 stuff. :-) */ + a = (u8 *) &mpt_dev->lan_cnfg_page1.HardwareAddressLow; + + HWaddr[0] = a[5]; + HWaddr[1] = a[4]; + HWaddr[2] = a[3]; + HWaddr[3] = a[2]; + HWaddr[4] = a[1]; + HWaddr[5] = a[0]; + + dev->addr_len = FC_ALEN; + memcpy(dev->dev_addr, HWaddr, FC_ALEN); + memset(dev->broadcast, 0xff, FC_ALEN); + + /* The Tx queue is 127 deep on the 909. + * Give ourselves some breathing room. + */ + priv->tx_max_out = (tx_max_out_p <= MPT_TX_MAX_OUT_LIM) ? + tx_max_out_p : MPT_TX_MAX_OUT_LIM; + + dev->open = mpt_lan_open; + dev->stop = mpt_lan_close; + dev->get_stats = mpt_lan_get_stats; + dev->set_multicast_list = NULL; + dev->change_mtu = mpt_lan_change_mtu; + dev->hard_start_xmit = mpt_lan_sdu_send; + +/* Not in 2.3.42. Need 2.3.45+ */ + dev->tx_timeout = mpt_lan_tx_timeout; + dev->watchdog_timeo = MPT_LAN_TX_TIMEOUT; + + dprintk((KERN_INFO MYNAM ": Finished registering dev " + "and setting initial values\n")); + + SET_MODULE_OWNER(dev); + + return dev; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +int __init +mpt_lan_init (void) +{ + struct net_device *dev; + MPT_ADAPTER *curadapter; + int i = 0, j; + + show_mptmod_ver(LANAME, LANVER); + + if ((LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER)) < 0) { + printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n"); + return -EBUSY; + } + + /* Set the callback index to be used by driver core for turbo replies */ + mpt_lan_index = LanCtx; + + dprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx)); + + for (j = 0; j < MPT_MAX_ADAPTERS; j++) { + mpt_landev[j] = NULL; + } + j = 0; + + curadapter = mpt_adapter_find_first(); + while (curadapter != NULL) { + for (i = 0; i < curadapter->facts0.NumberOfPorts; i++) { + printk (KERN_INFO MYNAM ": %s: PortNum=%x, ProtocolFlags=%02Xh (%c%c%c%c)\n", + curadapter->name, + curadapter->pfacts0.PortNumber, + curadapter->pfacts0.ProtocolFlags, + MPT_PROTOCOL_FLAGS_c_c_c_c(curadapter->pfacts0.ProtocolFlags)); + + if (curadapter->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { + dev = mpt_register_lan_device (curadapter, i); + if (dev != NULL) { + printk (KERN_INFO MYNAM ": %s: Fusion MPT LAN device registered as '%s'\n", + curadapter->name, dev->name); + printk (KERN_INFO MYNAM ": %s/%s: LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], + dev->dev_addr[4], dev->dev_addr[5]); +// printk (KERN_INFO MYNAM ": %s/%s: Max_TX_outstanding = %d\n", +// IOC_AND_NETDEV_NAMES_s_s(dev), +// NETDEV_TO_LANPRIV_PTR(dev)->tx_max_out); + mpt_landev[j] = dev; + dprintk((KERN_INFO MYNAM "/init: dev_addr=%p, mpt_landev[%d]=%p\n", + dev, j, mpt_landev[j])); + + j++; + } else { + printk (KERN_ERR MYNAM ": %s: Unable to register port%d as a LAN device\n", + curadapter->name, + curadapter->pfacts0.PortNumber); + } + } else { + printk (KERN_INFO MYNAM ": %s: Hmmm... LAN protocol seems to be disabled on this adapter port!\n", + curadapter->name); + } + } + curadapter = mpt_adapter_find_next(curadapter); + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +void __init mpt_lan_exit(void) +{ + int i; + + for (i = 0; mpt_landev[i] != NULL; i++) { + struct net_device *dev = mpt_landev[i]; + + printk (KERN_INFO MYNAM ": %s/%s: Fusion MPT LAN device unregistered\n", + IOC_AND_NETDEV_NAMES_s_s(dev)); + unregister_fcdev(dev); + mpt_landev[i] = (struct net_device *) 0xdeadbeef; /* Debug */ + } + + if (LanCtx >= 0) { + mpt_deregister(LanCtx); + LanCtx = -1; + mpt_lan_index = 0; + } + + /* deregister any send/receive handler structs. I2Oism? */ +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +MODULE_PARM(tx_max_out_p, "i"); +MODULE_PARM(max_buckets_out, "i"); // Debug stuff. FIXME! + +module_init(mpt_lan_init); +module_exit(mpt_lan_exit); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static unsigned short +mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev) +{ + struct mpt_lan_ohdr *fch = (struct mpt_lan_ohdr *)skb->data; + struct fcllc *fcllc; + + skb->mac.raw = skb->data; + skb_pull(skb, sizeof(struct mpt_lan_ohdr)); + + if (fch->dtype == htons(0xffff)) { + u32 *p = (u32 *) fch; + + swab32s(p + 0); + swab32s(p + 1); + swab32s(p + 2); + swab32s(p + 3); + + printk (KERN_WARNING MYNAM ": %s: WARNING - Broadcast swap F/W bug detected!\n", + NETDEV_PTR_TO_IOC_NAME_s(dev)); + printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %02x:%02x:%02x:%02x:%02x:%02x\n", + fch->saddr[0], fch->saddr[1], fch->saddr[2], + fch->saddr[3], fch->saddr[4], fch->saddr[5]); + } + + if (*fch->daddr & 1) { + if (!memcmp(fch->daddr, dev->broadcast, FC_ALEN)) { + skb->pkt_type = PACKET_BROADCAST; + } else { + skb->pkt_type = PACKET_MULTICAST; + } + } else { + if (memcmp(fch->daddr, dev->dev_addr, FC_ALEN)) { + skb->pkt_type = PACKET_OTHERHOST; + } else { + skb->pkt_type = PACKET_HOST; + } + } + + /* Strip the SNAP header from ARP packets since we don't + * pass them through to the 802.2/SNAP layers. + */ + fcllc = (struct fcllc *)skb->data; + + if (fcllc->dsap == EXTENDED_SAP && + (fcllc->ethertype == htons(ETH_P_IP) || + fcllc->ethertype == htons(ETH_P_ARP))) { + skb_pull(skb, sizeof(struct fcllc)); + return fcllc->ethertype; + } + + return htons(ETH_P_802_2); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/mptlan.h linux.ac/drivers/message/fusion/mptlan.h --- linux.vanilla/drivers/message/fusion/mptlan.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/mptlan.h Tue Apr 17 18:12:50 2001 @@ -0,0 +1,72 @@ +/* mptlan.h */ + +#ifndef LINUX_MPTLAN_H_INCLUDED +#define LINUX_MPTLAN_H_INCLUDED +/*****************************************************************************/ + +#if !defined(__GENKSYMS__) +#include <linux/module.h> +#endif + +#include <linux/netdevice.h> +#include <linux/errno.h> +// #include <linux/etherdevice.h> +#include <linux/fcdevice.h> +// #include <linux/fddidevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/miscdevice.h> +#include <linux/spinlock.h> +#include <linux/tqueue.h> +// #include <linux/trdevice.h> + +#include <asm/uaccess.h> +#include <asm/io.h> + + /* Override mptbase.h by pre-defining these! */ + #define MODULEAUTHOR "Noah Romer, Eddie C. Dost" + +#include "mptbase.h" + +/*****************************************************************************/ +#define LANAME "Fusion MPT LAN driver" +#define LANVER MPT_LINUX_VERSION_COMMON + +#ifdef MODULE +MODULE_AUTHOR(MODULEAUTHOR); +MODULE_DESCRIPTION(LANAME); +#endif +/*****************************************************************************/ + +#define MPT_LAN_MAX_BUCKETS_OUT 256 +#define MPT_LAN_BUCKET_THRESH 18 /* 9 buckets in one message */ +#define MPT_LAN_RX_COPYBREAK 200 +#define MPT_LAN_TX_TIMEOUT (1*HZ) +#define MPT_TX_MAX_OUT_LIM 127 + +#define MPT_LAN_MIN_MTU 96 /* RFC2625 */ +#define MPT_LAN_MAX_MTU 65280 /* RFC2625 */ +#define MPT_LAN_MTU 16128 /* be nice to slab allocator */ + +/* MPT LAN Reset and Suspend Resource Flags Defines */ + +#define MPT_LAN_RESOURCE_FLAG_RETURN_POSTED_BUCKETS 0x01 +#define MPT_LAN_RESOURCE_FLAG_RETURN_PEND_TRANSMITS 0x02 + +/*****************************************************************************/ +#ifdef MPT_LAN_IO_DEBUG +#define dioprintk(x) printk x +#else +#define dioprintk(x) +#endif + +#define NETDEV_TO_LANPRIV_PTR(d) ((struct mpt_lan_priv *)(d)->priv) +#define NETDEV_PTR_TO_IOC_NAME_s(d) (NETDEV_TO_LANPRIV_PTR(d)->mpt_dev->name) +#define IOC_AND_NETDEV_NAMES_s_s(d) NETDEV_PTR_TO_IOC_NAME_s(d), (d)->name + +/*****************************************************************************/ +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/mptscsih.c linux.ac/drivers/message/fusion/mptscsih.c --- linux.vanilla/drivers/message/fusion/mptscsih.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/mptscsih.c Tue Apr 3 23:12:52 2001 @@ -0,0 +1,2508 @@ +/* + * linux/drivers/message/fusion/mptscsih.c + * High performance SCSI / Fibre Channel SCSI Host device driver. + * For use with PCI chip/adapter(s): + * LSIFC9xx/LSI409xx Fibre Channel + * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * + * Credits: + * This driver would not exist if not for Alan Cox's development + * of the linux i2o driver. + * + * A huge debt of gratitude is owed to David S. Miller (DaveM) + * for fixing much of the stupid and broken stuff in the early + * driver while porting to sparc64 platform. THANK YOU! + * + * (see mptbase.c) + * + * Copyright (c) 1999-2001 LSI Logic Corporation + * Original author: Steven J. Ralston + * (mailto:Steve.Ralston@lsil.com) + * + * $Id: mptscsih.c,v 1.24 2001/03/22 08:45:08 sralston Exp $ + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + 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. + + NO WARRANTY + THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + solely responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, damage to or loss of data, + programs or equipment, and unavailability or interruption of operations. + + DISCLAIMER OF LIABILITY + NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#include <linux/module.h> +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/kdev_t.h> +#include <linux/blkdev.h> +#include <linux/blk.h> /* for io_request_lock (spinlock) decl */ +#include "../../scsi/scsi.h" +#include "../../scsi/hosts.h" +#include "../../scsi/sd.h" + +#include "mptbase.h" +#include "mptscsih.h" +#include "isense.h" + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#define my_NAME "Fusion MPT SCSI Host driver" +#define my_VERSION MPT_LINUX_VERSION_COMMON +#define MYNAM "mptscsih" + +MODULE_AUTHOR(MODULEAUTHOR); +MODULE_DESCRIPTION(my_NAME); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +typedef struct _BIG_SENSE_BUF { + u8 data[256]; +} BIG_SENSE_BUF; + +typedef struct _MPT_SCSI_HOST { + MPT_ADAPTER *ioc; + int port; + struct scsi_cmnd **ScsiLookup; + u8 *SgHunks; + dma_addr_t SgHunksDMA; + u32 qtag_tick; + FCDEV_TRACKER TargetsQ; +} MPT_SCSI_HOST; + +typedef struct _MPT_SCSI_DEV { + struct _MPT_SCSI_DEV *forw; + struct _MPT_SCSI_DEV *back; + MPT_ADAPTER *ioc; + int sense_sz; + BIG_SENSE_BUF CachedSense; + unsigned long io_cnt; + unsigned long read_cnt; +} MPT_SCSI_DEV; + +/* + * Other private/forward protos... + */ + +static int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); +static void mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq); +static int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); +static int mptscsih_io_direction(Scsi_Cmnd *cmd); +static void copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply); +static u32 SCPNT_TO_MSGCTX(Scsi_Cmnd *sc); + +static int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); + + +static int mpt_scsi_hosts = 0; +static atomic_t queue_depth; + +static int ScsiDoneCtx = -1; +static int ScsiTaskCtx = -1; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28) +static struct proc_dir_entry proc_mpt_scsihost = +{ + low_ino: PROC_SCSI_MPT, + namelen: 8, + name: "mptscsih", + mode: S_IFDIR | S_IRUGO | S_IXUGO, + nlink: 2, +}; +#endif + +#define SNS_LEN(scp) sizeof((scp)->sense_buffer) + +#ifndef MPT_SCSI_USE_NEW_EH +/* + * Stuff to handle single-threading SCSI TaskMgmt + * (abort/reset) requests... + */ +static spinlock_t mpt_scsih_taskQ_lock = SPIN_LOCK_UNLOCKED; +static MPT_Q_TRACKER mpt_scsih_taskQ = { + (MPT_FRAME_HDR*) &mpt_scsih_taskQ, + (MPT_FRAME_HDR*) &mpt_scsih_taskQ +}; +static int mpt_scsih_taskQ_cnt = 0; +static int mpt_scsih_taskQ_bh_active = 0; +static MPT_FRAME_HDR *mpt_scsih_active_taskmgmt_mf = NULL; +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptscsih_io_done - Main SCSI IO callback routine registered to + * Fusion MPT (base) driver + * @ioc: Pointer to MPT_ADAPTER structure + * @mf: Pointer to original MPT request frame + * @r: Pointer to MPT reply frame (NULL if TurboReply) + * + * This routine is called from mpt.c::mpt_interrupt() at the completion + * of any SCSI IO request. + * This routine is registered with the Fusion MPT (base) driver at driver + * load/init time via the mpt_register() API call. + * + * Returns 1 indicating alloc'd request frame ptr should be freed. + */ +static int +mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r) +{ + Scsi_Cmnd *sc; + MPT_SCSI_HOST *hd; + MPT_SCSI_DEV *mpt_sdev = NULL; + u16 req_idx; + + if ((mf == NULL) || + (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { + printk(KERN_ERR MYNAM ": ERROR! NULL or BAD req frame ptr (=%p)!\n", mf); + return 1; + } + + hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; + req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + sc = hd->ScsiLookup[req_idx]; + hd->ScsiLookup[req_idx] = NULL; + + dmfprintk((KERN_INFO MYNAM ": ScsiDone (req:sc:reply=%p:%p:%p)\n", mf, sc, r)); + + atomic_dec(&queue_depth); + + /* + * Check for {1st} {IO} completion to "new" device. + * How do we know it's a new device? + * If we haven't set SDpnt->hostdata I guess... + */ + if (sc && sc->device) { + mpt_sdev = (MPT_SCSI_DEV*)sc->device->hostdata; + if (!mpt_sdev) { + dprintk((KERN_INFO MYNAM ": *NEW* SCSI device (%d:%d:%d)!\n", + sc->device->id, sc->device->lun, sc->device->channel)); + if ((sc->device->hostdata = kmalloc(sizeof(MPT_SCSI_DEV), GFP_ATOMIC)) == NULL) { + printk(KERN_ERR MYNAM ": ERROR: kmalloc(%d) FAILED!\n", (int)sizeof(MPT_SCSI_DEV)); + } else { + memset(sc->device->hostdata, 0, sizeof(MPT_SCSI_DEV)); + mpt_sdev = (MPT_SCSI_DEV *) sc->device->hostdata; + mpt_sdev->ioc = ioc; + } + } else { + if (++mpt_sdev->io_cnt && mptscsih_io_direction(sc) < 0) { + if (++mpt_sdev->read_cnt == 3) { + dprintk((KERN_INFO MYNAM ": 3rd DATA_IN, CDB[0]=%02x\n", + sc->cmnd[0])); + } + } +#if 0 + if (mpt_sdev->sense_sz) { + /* + * Completion of first IO down this path + * *should* invalidate device SenseData... + */ + mpt_sdev->sense_sz = 0; + } +#endif + } + } + +#if 0 +{ + MPT_FRAME_HDR *mf_chk; + + /* This, I imagine, is a costly check, but... + * If abort/reset active, check to see if this is a IO + * that completed while ABORT/RESET for it is waiting + * on our taskQ! + */ + if (! Q_IS_EMPTY(&mpt_scsih_taskQ)) { + /* If ABORT for this IO is queued, zap it! */ + mf_chk = search_taskQ(1,sc,MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK); + if (mf_chk != NULL) { + sc->result = DID_ABORT << 16; + spin_lock_irqsave(&io_request_lock, flags); + sc->scsi_done(sc); + spin_unlock_irqrestore(&io_request_lock, flags); + return 1; + } + } +} +#endif + + if (r != NULL && sc != NULL) { + SCSIIOReply_t *pScsiReply; + SCSIIORequest_t *pScsiReq; + u16 status; + + pScsiReply = (SCSIIOReply_t *) r; + pScsiReq = (SCSIIORequest_t *) mf; + + status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK; + + dprintk((KERN_NOTICE MYNAM ": Uh-Oh! (req:sc:reply=%p:%p:%p)\n", mf, sc, r)); + dprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh" + ", SCSIStatus=%02xh, IOCLogInfo=%08xh\n", + status, pScsiReply->SCSIState, pScsiReply->SCSIStatus, + le32_to_cpu(pScsiReply->IOCLogInfo))); + + /* + * Look for + dump FCP ResponseInfo[]! + */ + if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID) { + dprintk((KERN_NOTICE " FCP_ResponseInfo=%08xh\n", + le32_to_cpu(pScsiReply->ResponseInfo))); + } + + switch(status) { + case MPI_IOCSTATUS_BUSY: /* 0x0002 */ + /*sc->result = DID_BUS_BUSY << 16;*/ /* YIKES! - Seems to + * kill linux interrupt + * handler + */ + sc->result = STS_BUSY; /* Try SCSI BUSY! */ + break; + + case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ + /* Not real sure here... */ + sc->result = DID_OK << 16; + break; + + case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */ + case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */ + sc->result = DID_BAD_TARGET << 16; + break; + + case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ + /* Spoof to SCSI Selection Timeout! */ + sc->result = DID_NO_CONNECT << 16; + break; + + case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ + /* + * YIKES! I just discovered that SCSI IO which + * returns check condition, SenseKey=05 (ILLEGAL REQUEST) + * and ASC/ASCQ=94/01 (LSI Logic RAID vendor specific), + * comes down this path! + * Do upfront check for valid SenseData and give it + * precedence! + */ + if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { + copy_sense_data(sc, hd, mf, pScsiReply); + sc->result = pScsiReply->SCSIStatus; + break; + } + + dprintk((KERN_NOTICE MYNAM ": sc->underflow={report ERR if < %02xh bytes xfer'd}\n", sc->underflow)); + dprintk((KERN_NOTICE MYNAM ": ActBytesXferd=%02xh\n", le32_to_cpu(pScsiReply->TransferCount))); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + sc->resid = sc->request_bufflen - le32_to_cpu(pScsiReply->TransferCount); + dprintk((KERN_NOTICE MYNAM ": SET sc->resid=%02xh\n", sc->resid)); +#endif + +#if 0 + if (sc->underflow && (le32_to_cpu(pScsiReply->TransferCount) < sc->underflow)) { + sc->result = DID_ERROR << 16; + sc->resid = sc->request_bufflen - le32_to_cpu(pScsiReply->TransferCount); + } else { + sc->result = 0; + } +#endif + + /* workaround attempts... */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + if (sc->resid >= 0x200) { + /* GRRRRR... + * //sc->result = DID_SOFT_ERROR << 16; + * Try spoofing to BUSY + */ + sc->result = STS_BUSY; + } else { + sc->result = 0; + } +#else + sc->result = 0; +#endif + break; + + case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ + sc->result = DID_ABORT << 16; + break; + + case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ + case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ + sc->result = DID_RESET << 16; + break; + + case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ + sc->result = pScsiReply->SCSIStatus; + + if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { + copy_sense_data(sc, hd, mf, pScsiReply); + + /* If running agains circa 200003dd 909 MPT f/w, + * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL + * (QUEUE_FULL) returned from device! --> get 0x0000?128 + * and with SenseBytes set to 0. + */ + if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL) + mptscsih_report_queue_full(sc, pScsiReply, pScsiReq); + } + else if (pScsiReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) { + /* + * What to do? + */ + sc->result = DID_SOFT_ERROR << 16; + } + else if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) { + /* Not real sure here either... */ + sc->result = DID_ABORT << 16; + } + + if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL) + mptscsih_report_queue_full(sc, pScsiReply, pScsiReq); + + break; + + case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */ + case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */ + case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */ + case MPI_IOCSTATUS_RESERVED: /* 0x0005 */ + case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */ + case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */ + case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */ + case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */ + case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ + case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ + case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ + case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */ + default: + /* + * What to do? + */ + sc->result = DID_SOFT_ERROR << 16; + break; + + } /* switch(status) */ + + dprintk((KERN_NOTICE MYNAM ": sc->result set to %08xh\n", sc->result)); + } + + if (sc != NULL) { + unsigned long flags; + + /* Unmap the DMA buffers, if any. */ + if (sc->use_sg) { + pci_unmap_sg(ioc->pcidev, + (struct scatterlist *) sc->request_buffer, + sc->use_sg, + scsi_to_pci_dma_dir(sc->sc_data_direction)); + } else if (sc->request_bufflen) { + pci_unmap_single(ioc->pcidev, + (dma_addr_t)((long)sc->SCp.ptr), + sc->request_bufflen, + scsi_to_pci_dma_dir(sc->sc_data_direction)); + } + + spin_lock_irqsave(&io_request_lock, flags); + sc->scsi_done(sc); + spin_unlock_irqrestore(&io_request_lock, flags); + } + + return 1; +} + +#ifndef MPT_SCSI_USE_NEW_EH +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * search_taskQ - Search SCSI task mgmt request queue for specific + * request type + * @remove: (Boolean) Should request be removed if found? + * @sc: Pointer to Scsi_Cmnd structure + * @task_type: Task type to search for + * + * Returns pointer to MPT request frame if found, or %NULL if request + * was not found. + */ +static MPT_FRAME_HDR * +search_taskQ(int remove, Scsi_Cmnd *sc, u8 task_type) +{ + MPT_FRAME_HDR *mf = NULL; + unsigned long flags; + int count = 0; + int list_sz; + + dslprintk((KERN_INFO MYNAM ": spinlock#1\n")); + spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); + list_sz = mpt_scsih_taskQ_cnt; + if (! Q_IS_EMPTY(&mpt_scsih_taskQ)) { + mf = mpt_scsih_taskQ.head; + do { + count++; + if (mf->u.frame.linkage.argp1 == sc && + mf->u.frame.linkage.arg1 == task_type) { + if (remove) { + Q_DEL_ITEM(&mf->u.frame.linkage); + mpt_scsih_taskQ_cnt--; + } + break; + } + } while ((mf = mf->u.frame.linkage.forw) != (MPT_FRAME_HDR*)&mpt_scsih_taskQ); + if (mf == (MPT_FRAME_HDR*)&mpt_scsih_taskQ) { + mf = NULL; + } + } + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + + if (list_sz) { + dprintk((KERN_INFO MYNAM ": search_taskQ(%d,%p,%d) results=%p (%sFOUND%s)!\n", + remove, sc, task_type, + mf, + mf ? "" : "NOT_", + (mf && remove) ? "+REMOVED" : "" )); + dprintk((KERN_INFO MYNAM ": (searched thru %d of %d items on taskQ)\n", + count, + list_sz )); + } + + return mf; +} + +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/* + * Hack! I'd like to report if a device is returning QUEUE_FULL + * but maybe not each and every time... + */ +static long last_queue_full = 0; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptscsih_report_queue_full - Report QUEUE_FULL status returned + * from a SCSI target device. + * @sc: Pointer to Scsi_Cmnd structure + * @pScsiReply: Pointer to SCSIIOReply_t + * @pScsiReq: Pointer to original SCSI request + * + * This routine periodically reports QUEUE_FULL status returned from a + * SCSI target device. It reports this to the console via kernel + * printk() API call, not more than once every 10 seconds. + */ +static void +mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq) +{ + long time = jiffies; + + if (time - last_queue_full > 10 * HZ) { + printk(KERN_WARNING MYNAM ": Device reported QUEUE_FULL! SCSI bus:target:lun = %d:%d:%d\n", + 0, sc->target, sc->lun); + last_queue_full = time; + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int BeenHereDoneThat = 0; + +/* SCSI fops start here... */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_detect - Register MPT adapter(s) as SCSI host(s) with + * linux scsi mid-layer. + * @tpnt: Pointer to Scsi_Host_Template structure + * + * (linux Scsi_Host_Template.detect routine) + * + * Returns number of SCSI host adapters that were successfully + * registered with the linux scsi mid-layer via the scsi_register() + * API call. + */ +int +mptscsih_detect(Scsi_Host_Template *tpnt) +{ + struct Scsi_Host *sh = NULL; + MPT_SCSI_HOST *hd = NULL; + MPT_ADAPTER *this; + unsigned long flags; + int sz; + u8 *mem; + + if (! BeenHereDoneThat++) { + show_mptmod_ver(my_NAME, my_VERSION); + + ScsiDoneCtx = mpt_register(mptscsih_io_done, MPTSCSIH_DRIVER); + ScsiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSCSIH_DRIVER); + +#ifndef MPT_SCSI_USE_NEW_EH + Q_INIT(&mpt_scsih_taskQ, MPT_FRAME_HDR); + spin_lock_init(&mpt_scsih_taskQ_lock); +#endif + + if (mpt_event_register(ScsiDoneCtx, mptscsih_event_process) == 0) { + dprintk((KERN_INFO MYNAM ": Registered for IOC event notifications\n")); + } else { + /* FIXME! */ + } + } + + dprintk((KERN_INFO MYNAM ": mpt_scsih_detect()\n")); + + this = mpt_adapter_find_first(); + while (this != NULL) { + /* FIXME! Multi-port (aka FC929) support... + * for (i = 0; i < this->facts.NumberOfPorts; i++) + */ + + /* 20010215 -sralston + * Added sanity check on SCSI Initiator-mode enabled + * for this MPT adapter. + */ + if (!(this->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) { + printk(KERN_ERR MYNAM ": Skipping %s because SCSI Initiator mode is NOT enabled!\n", + this->name); + this = mpt_adapter_find_next(this); + continue; + } + + /* 20010202 -sralston + * Added sanity check on readiness of the MPT adapter. + */ + if (this->last_state != MPI_IOC_STATE_OPERATIONAL) { + printk(KERN_ERR MYNAM ": ERROR - Skipping %s because it's not operational!\n", + this->name); + this = mpt_adapter_find_next(this); + continue; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) + tpnt->proc_dir = &proc_mpt_scsihost; +#endif + sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST)); + if (sh != NULL) { + save_flags(flags); + cli(); + sh->io_port = 0; + sh->n_io_port = 0; + sh->irq = 0; + + /* Yikes! This is important! + * Otherwise, by default, linux only scans target IDs 0-7! + */ + sh->max_id = this->pfacts0.MaxDevices - 1; + + sh->this_id = this->pfacts0.PortSCSIID; + + restore_flags(flags); + + hd = (MPT_SCSI_HOST *) sh->hostdata; + hd->ioc = this; + hd->port = 0; /* FIXME! */ + + /* SCSI needs Scsi_Cmnd lookup table! + * (with size equal to req_depth*PtrSz!) + */ + sz = hd->ioc->req_depth * sizeof(void *); + mem = kmalloc(sz, GFP_KERNEL); + if (mem == NULL) + return mpt_scsi_hosts; + + memset(mem, 0, sz); + hd->ScsiLookup = (struct scsi_cmnd **) mem; + + dprintk((KERN_INFO MYNAM ": ScsiLookup @ %p, sz=%d\n", + hd->ScsiLookup, sz)); + + /* SCSI also needs SG buckets/hunk management! + * (with size equal to N * req_sz * req_depth!) + * (where N is number of SG buckets per hunk) + */ + sz = MPT_SG_BUCKETS_PER_HUNK * hd->ioc->req_sz * hd->ioc->req_depth; + mem = pci_alloc_consistent(hd->ioc->pcidev, sz, + &hd->SgHunksDMA); + if (mem == NULL) + return mpt_scsi_hosts; + + memset(mem, 0, sz); + hd->SgHunks = (u8*)mem; + + dprintk((KERN_INFO MYNAM ": SgHunks @ %p(%08x), sz=%d\n", + hd->SgHunks, hd->SgHunksDMA, sz)); + + hd->qtag_tick = jiffies; + + this->sh = sh; + mpt_scsi_hosts++; + } + this = mpt_adapter_find_next(this); + } + + return mpt_scsi_hosts; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + static char *info_kbuf = NULL; +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_release - Unregister SCSI host from linux scsi mid-layer + * @host: Pointer to Scsi_Host structure + * + * (linux Scsi_Host_Template.release routine) + * This routine releases all resources associated with the SCSI host + * adapter. + * + * Returns 0 for success. + */ +int +mptscsih_release(struct Scsi_Host *host) +{ + MPT_SCSI_HOST *hd; +#ifndef MPT_SCSI_USE_NEW_EH + unsigned long flags; + + spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); + if (mpt_scsih_taskQ_bh_active) { + int count = 10 * HZ; + + dprintk((KERN_INFO MYNAM ": Info: Zapping TaskMgmt thread!\n")); + + /* Zap the taskQ! */ + Q_INIT(&mpt_scsih_taskQ, MPT_FRAME_HDR); + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + + while(mpt_scsih_taskQ_bh_active && --count) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + if (!count) + printk(KERN_ERR MYNAM ": ERROR! TaskMgmt thread still active!\n"); + } + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); +#endif + + hd = (MPT_SCSI_HOST *) host->hostdata; + if (hd != NULL) { + int sz1, sz2; + + sz1 = sz2 = 0; + if (hd->ScsiLookup != NULL) { + sz1 = hd->ioc->req_depth * sizeof(void *); + kfree(hd->ScsiLookup); + hd->ScsiLookup = NULL; + } + + if (hd->SgHunks != NULL) { + + sz2 = MPT_SG_BUCKETS_PER_HUNK * hd->ioc->req_sz * hd->ioc->req_depth; + pci_free_consistent(hd->ioc->pcidev, sz2, + hd->SgHunks, hd->SgHunksDMA); + hd->SgHunks = NULL; + } + dprintk((KERN_INFO MYNAM ": Free'd ScsiLookup (%d) and SgHunks (%d) memory\n", sz1, sz2)); + } + + if (mpt_scsi_hosts) { + if (--mpt_scsi_hosts == 0) { +#if 0 + mptscsih_flush_pending(); +#endif + mpt_event_deregister(ScsiDoneCtx); + dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n")); + + mpt_deregister(ScsiDoneCtx); + mpt_deregister(ScsiTaskCtx); + + if (info_kbuf != NULL) + kfree(info_kbuf); + } + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_info - Return information about MPT adapter + * @SChost: Pointer to Scsi_Host structure + * + * (linux Scsi_Host_Template.info routine) + * + * Returns pointer to buffer where information was written. + */ +const char * +mptscsih_info(struct Scsi_Host *SChost) +{ + MPT_SCSI_HOST *h; + int size = 0; + + if (info_kbuf == NULL) + if ((info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL) + return info_kbuf; + + h = (MPT_SCSI_HOST *)SChost->hostdata; + info_kbuf[0] = '\0'; + mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0); + info_kbuf[size-1] = '\0'; + + return info_kbuf; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + static int max_qd = 1; +#ifdef MPT_DEBUG + static int max_sges = 0; + static int max_xfer = 0; +#endif +#if 0 + static int max_num_sges = 0; + static int max_sgent_len = 0; +#endif +#if 0 +static int index_log[128]; +static int index_ent = 0; +static __inline__ void ADD_INDEX_LOG(int req_ent) +{ + int i = index_ent++; + + index_log[i & (128 - 1)] = req_ent; +} +#else +#define ADD_INDEX_LOG(req_ent) do { } while(0) +#endif +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine. + * @SCpnt: Pointer to Scsi_Cmnd structure + * @done: Pointer SCSI mid-layer IO completion function + * + * (linux Scsi_Host_Template.queuecommand routine) + * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest + * from a linux Scsi_Cmnd request and send it to the IOC. + * + * Returns 0. (rtn value discarded by linux scsi mid-layer) + */ +int +mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +{ + struct Scsi_Host *host; + MPT_SCSI_HOST *hd; + MPT_FRAME_HDR *mf; + SCSIIORequest_t *pScsiReq; + int datadir; + u32 len; + u32 sgdir; + u32 scsictl; + u32 scsidir; + u32 qtag; + u32 *mptr; + int sge_spill1; + int frm_sz; + int sges_left; + u32 chain_offset; + int my_idx; + int i; + + dmfprintk((KERN_INFO MYNAM "_qcmd: SCpnt=%p, done()=%p\n", + SCpnt, done)); + + host = SCpnt->host; + hd = (MPT_SCSI_HOST *) host->hostdata; + +#if 0 + if (host->host_busy >= 60) { + MPT_ADAPTER *ioc = hd->ioc; + u16 pci_command, pci_status; + + /* The IOC is probably hung, investigate status. */ + printk("MPI: IOC probably hung IOCSTAT[%08x] INTSTAT[%08x] REPLYFIFO[%08x]\n", + readl(&ioc->chip.fc9xx->DoorbellValue), + readl(&ioc->chip.fc9xx->IntStatus), + readl(&ioc->chip.fc9xx->ReplyFifo)); + pci_read_config_word(ioc->pcidev, PCI_COMMAND, &pci_command); + pci_read_config_word(ioc->pcidev, PCI_STATUS, &pci_status); + printk("MPI: PCI command[%04x] status[%04x]\n", pci_command, pci_status); + { + /* DUMP req index logger. */ + int begin, end; + + begin = (index_ent - 65) & (128 - 1); + end = index_ent & (128 - 1); + printk("MPI: REQ_INDEX_HIST["); + while (begin != end) { + printk("(%04x)", index_log[begin]); + begin = (begin + 1) & (128 - 1); + } + printk("\n"); + } + sti(); + while(1) + barrier(); + } +#endif + + SCpnt->scsi_done = done; + + /* 20000617 -sralston + * GRRRRR... Shouldn't have to do this but... + * Do explicit check for REQUEST_SENSE and cached SenseData. + * If yes, return cached SenseData. + */ +#ifdef MPT_SCSI_CACHE_AUTOSENSE + { + MPT_SCSI_DEV *mpt_sdev; + + mpt_sdev = (MPT_SCSI_DEV *) SCpnt->device->hostdata; + if (mpt_sdev && SCpnt->cmnd[0] == REQUEST_SENSE) { + u8 *dest = NULL; + + if (!SCpnt->use_sg) + dest = SCpnt->request_buffer; + else { + struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer; + if (sg) + dest = (u8 *) (unsigned long)sg_dma_address(sg); + } + + if (dest && mpt_sdev->sense_sz) { + memcpy(dest, mpt_sdev->CachedSense.data, mpt_sdev->sense_sz); +#ifdef MPT_DEBUG + { + int i; + u8 *sb; + + sb = mpt_sdev->CachedSense.data; + if (sb && ((sb[0] & 0x70) == 0x70)) { + printk(KERN_WARNING MYNAM ": Returning last cached SCSI (hex) SenseData:\n"); + printk(KERN_WARNING " "); + for (i = 0; i < (8 + sb[7]); i++) + printk("%s%02x", i == 13 ? "-" : " ", sb[i]); + printk("\n"); + } + } +#endif + } + SCpnt->resid = SCpnt->request_bufflen - mpt_sdev->sense_sz; + SCpnt->result = 0; +/* spin_lock(&io_request_lock); */ + SCpnt->scsi_done(SCpnt); +/* spin_unlock(&io_request_lock); */ + return 0; + } + } +#endif + + if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc->id)) == NULL) { +/* SCpnt->result = DID_SOFT_ERROR << 16; */ + SCpnt->result = STS_BUSY; + SCpnt->scsi_done(SCpnt); +/* return 1; */ + return 0; + } + pScsiReq = (SCSIIORequest_t *) mf; + + my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + + ADD_INDEX_LOG(my_idx); + + /* Map the data portion, if any. */ + sges_left = SCpnt->use_sg; + if (sges_left) { + sges_left = pci_map_sg(hd->ioc->pcidev, + (struct scatterlist *) SCpnt->request_buffer, + sges_left, + scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + } else if (SCpnt->request_bufflen) { + dma_addr_t buf_dma_addr; + + buf_dma_addr = pci_map_single(hd->ioc->pcidev, + SCpnt->request_buffer, + SCpnt->request_bufflen, + scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + + /* We hide it here for later unmap. */ + SCpnt->SCp.ptr = (char *)(unsigned long) buf_dma_addr; + } + + /* + * Put together a MPT SCSI request... + */ + + /* Assume SimpleQ, NO DATA XFER for now */ + + len = SCpnt->request_bufflen; + sgdir = 0x00000000; /* SGL IN (host<--ioc) */ + scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER; + + /* + * The scsi layer should be handling this stuff + * (In 2.3.x it does -DaveM) + */ + + /* BUG FIX! 19991030 -sralston + * TUR's being issued with scsictl=0x02000000 (DATA_IN)! + * Seems we may receive a buffer (len>0) even when there + * will be no data transfer! GRRRRR... + */ + datadir = mptscsih_io_direction(SCpnt); + if (datadir < 0) { + scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */ + } else if (datadir > 0) { + sgdir = 0x04000000; /* SGL OUT (host-->ioc) */ + scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */ + } else { + len = 0; + } + + qtag = MPI_SCSIIO_CONTROL_SIMPLEQ; + + /* + * Attach tags to the devices + */ + if (SCpnt->device->tagged_supported) { + /* + * Some drives are too stupid to handle fairness issues + * with tagged queueing. We throw in the odd ordered + * tag to stop them starving themselves. + */ + if ((jiffies - hd->qtag_tick) > (5*HZ)) { + qtag = MPI_SCSIIO_CONTROL_ORDEREDQ; + hd->qtag_tick = jiffies; + +#if 0 + /* These are ALWAYS zero! + * (Because this is a place for the device driver to dynamically + * assign tag numbers any way it sees fit. That's why -DaveM) + */ + dprintk((KERN_DEBUG MYNAM ": sc->device->current_tag = %08x\n", + SCpnt->device->current_tag)); + dprintk((KERN_DEBUG MYNAM ": sc->tag = %08x\n", + SCpnt->tag)); +#endif + } +#if 0 + else { + /* Hmmm... I always see value of 0 here, + * of which {HEAD_OF, ORDERED, SIMPLE} are NOT! -sralston + * (Because this is a place for the device driver to dynamically + * assign tag numbers any way it sees fit. That's why -DaveM) + * + * if (SCpnt->tag == HEAD_OF_QUEUE_TAG) + */ + if (SCpnt->device->current_tag == HEAD_OF_QUEUE_TAG) + qtag = MPI_SCSIIO_CONTROL_HEADOFQ; + else if (SCpnt->tag == ORDERED_QUEUE_TAG) + qtag = MPI_SCSIIO_CONTROL_ORDEREDQ; + } +#endif + } + + scsictl = scsidir | qtag; + + frm_sz = hd->ioc->req_sz; + + /* Ack! + * sge_spill1 = 9; + */ + sge_spill1 = (frm_sz - (sizeof(SCSIIORequest_t) - sizeof(SGEIOUnion_t) + sizeof(SGEChain32_t))) / 8; + /* spill1: for req_sz == 128 (128-48==80, 80/8==10 SGEs max, first time!), --> use 9 + * spill1: for req_sz == 96 ( 96-48==48, 48/8== 6 SGEs max, first time!), --> use 5 + */ + dsgprintk((KERN_INFO MYNAM ": SG: %x spill1 = %d\n", + my_idx, sge_spill1)); + +#ifdef MPT_DEBUG + if (sges_left > max_sges) { + max_sges = sges_left; + dprintk((KERN_INFO MYNAM ": MPT_MaxSges = %d\n", max_sges)); + } +#endif +#if 0 + if (sges_left > max_num_sges) { + max_num_sges = sges_left; + printk(KERN_INFO MYNAM ": MPT_MaxNumSges = %d\n", max_num_sges); + } +#endif + + dsgprintk((KERN_INFO MYNAM ": SG: %x sges_left = %d (initially)\n", + my_idx, sges_left)); + + chain_offset = 0; + if (sges_left > (sge_spill1+1)) { +#if 0 + chain_offset = 0x1E; +#endif + chain_offset = (frm_sz - 8) / 4; + } + + pScsiReq->TargetID = SCpnt->target; + pScsiReq->Bus = hd->port; + pScsiReq->ChainOffset = chain_offset; + pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST; + pScsiReq->CDBLength = SCpnt->cmd_len; + +/* We have 256 bytes alloc'd per IO; let's use it. */ +/* pScsiReq->SenseBufferLength = SNS_LEN(SCpnt); */ + pScsiReq->SenseBufferLength = 255; + + pScsiReq->Reserved = 0; + pScsiReq->MsgFlags = 0; + pScsiReq->LUN[0] = 0; + pScsiReq->LUN[1] = SCpnt->lun; + pScsiReq->LUN[2] = 0; + pScsiReq->LUN[3] = 0; + pScsiReq->LUN[4] = 0; + pScsiReq->LUN[5] = 0; + pScsiReq->LUN[6] = 0; + pScsiReq->LUN[7] = 0; + pScsiReq->Control = cpu_to_le32(scsictl); + + /* + * Write SCSI CDB into the message + */ + for (i = 0; i < 12; i++) + pScsiReq->CDB[i] = SCpnt->cmnd[i]; + for (i = 12; i < 16; i++) + pScsiReq->CDB[i] = 0; + + /* DataLength */ + pScsiReq->DataLength = cpu_to_le32(len); + + /* SenseBuffer low address */ + pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_pool_dma + (my_idx * 256)); + + mptr = (u32 *) &pScsiReq->SGL; + + /* + * Now fill in the SGList... + * NOTES: For 128 byte req_sz, we can hold up to 10 simple SGE's + * in the remaining request frame. We -could- do unlimited chains + * but each chain buffer can only be req_sz bytes in size, and + * we lose one SGE whenever we chain. + * For 128 req_sz, we can hold up to 16 SGE's per chain buffer. + * For practical reasons, limit ourselves to 1 overflow chain buffer; + * giving us 9 + 16 == 25 SGE's max. + * At 4 Kb per SGE, that yields 100 Kb max transfer. + * + * (This code needs to be completely changed when/if 64-bit DMA + * addressing is used, since we will be able to fit much less than + * 10 embedded SG entries. -DaveM) + */ + if (sges_left) { + struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer; + u32 v1, v2; + int sge_spill2; + int sge_cur_spill; + int sgCnt; + u8 *pSgBucket; + int chain_sz; + + len = 0; + + /* sge_spill2 = 15; + * spill2: for req_sz == 128 (128/8==16 SGEs max, first time!), --> use 15 + * spill2: for req_sz == 96 ( 96/8==12 SGEs max, first time!), --> use 11 + */ + sge_spill2 = frm_sz / 8 - 1; + dsgprintk((KERN_INFO MYNAM ": SG: %x spill2 = %d\n", + my_idx, sge_spill2)); + + pSgBucket = NULL; + sgCnt = 0; + sge_cur_spill = sge_spill1; + while (sges_left) { +#if 0 + if (sg_dma_len(sg) > max_sgent_len) { + max_sgent_len = sg_dma_len(sg); + printk(KERN_INFO MYNAM ": MPT_MaxSgentLen = %d\n", max_sgent_len); + } +#endif + /* Write one simple SGE */ + v1 = sgdir | 0x10000000 | sg_dma_len(sg); + len += sg_dma_len(sg); + v2 = sg_dma_address(sg); + dsgprintk((KERN_INFO MYNAM ": SG: %x Writing SGE @%p: %08x %08x, sges_left=%d\n", + my_idx, mptr, v1, v2, sges_left)); + *mptr++ = cpu_to_le32(v1); + *mptr++ = cpu_to_le32(v2); + sg++; + sgCnt++; + + if (--sges_left == 0) { + /* re-write 1st word of previous SGE with SIMPLE, + * LE, EOB, and EOL bits! + */ + v1 = 0xD1000000 | sgdir | sg_dma_len(sg-1); + dsgprintk((KERN_INFO MYNAM ": SG: %x (re)Writing SGE @%p: %08x (VERY LAST SGE!)\n", + my_idx, mptr-2, v1)); + *(mptr - 2) = cpu_to_le32(v1); + } else { + if ((sges_left > 1) && ((sgCnt % sge_cur_spill) == 0)) { + dsgprintk((KERN_INFO MYNAM ": SG: %x SG spill at modulo 0!\n", + my_idx)); + + /* Fixup previous SGE with LE bit! */ + v1 = sgdir | 0x90000000 | sg_dma_len(sg-1); + dsgprintk((KERN_INFO MYNAM ": SG: %x (re)Writing SGE @%p: %08x (LAST BUCKET SGE!)\n", + my_idx, mptr-2, v1)); + *(mptr - 2) = cpu_to_le32(v1); + + chain_offset = 0; + /* Going to need another chain? */ + if (sges_left > (sge_spill2+1)) { +#if 0 + chain_offset = 0x1E; +#endif + chain_offset = (frm_sz - 8) / 4; + chain_sz = frm_sz; + } else { + chain_sz = sges_left * 8; + } + + /* write chain SGE at mptr. */ + v1 = 0x30000000 | chain_offset<<16 | chain_sz; + if (pSgBucket == NULL) { + pSgBucket = hd->SgHunks + + (my_idx * frm_sz * MPT_SG_BUCKETS_PER_HUNK); + } else { + pSgBucket += frm_sz; + } + v2 = (hd->SgHunksDMA + + ((u8 *)pSgBucket - (u8 *)hd->SgHunks)); + dsgprintk((KERN_INFO MYNAM ": SG: %x Writing SGE @%p: %08x %08x (CHAIN!)\n", + my_idx, mptr, v1, v2)); + *(mptr++) = cpu_to_le32(v1); + *(mptr) = cpu_to_le32(v2); + + mptr = (u32 *) pSgBucket; + sgCnt = 0; + sge_cur_spill = sge_spill2; + } + } + } + } else { + dsgprintk((KERN_INFO MYNAM ": SG: non-SG for %p, len=%d\n", + SCpnt, SCpnt->request_bufflen)); + + if (len > 0) { + dma_addr_t buf_dma_addr; + + buf_dma_addr = (dma_addr_t) (unsigned long)SCpnt->SCp.ptr; + *(mptr++) = cpu_to_le32(0xD1000000|sgdir|SCpnt->request_bufflen); + *(mptr++) = cpu_to_le32(buf_dma_addr); + } + } + +#ifdef MPT_DEBUG + /* if (SCpnt->request_bufflen > max_xfer) */ + if (len > max_xfer) { + max_xfer = len; + dprintk((KERN_INFO MYNAM ": MPT_MaxXfer = %d\n", max_xfer)); + } +#endif + + hd->ScsiLookup[my_idx] = SCpnt; + + /* Main banana... */ + mpt_put_msg_frame(ScsiDoneCtx, hd->ioc->id, mf); + + atomic_inc(&queue_depth); + if (atomic_read(&queue_depth) > max_qd) { + max_qd = atomic_read(&queue_depth); + dprintk((KERN_INFO MYNAM ": Queue depth now %d.\n", max_qd)); + } + + mb(); + dmfprintk((KERN_INFO MYNAM ": Issued SCSI cmd (%p)\n", SCpnt)); + + return 0; +} + +#ifdef MPT_SCSI_USE_NEW_EH /* { */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + mptscsih_abort + Returns: 0=SUCCESS, else FAILED +*/ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_abort - Abort linux Scsi_Cmnd routine, new_eh variant + * @SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted + * + * (linux Scsi_Host_Template.eh_abort_handler routine) + * + * Returns SUCCESS or FAILED. + */ +int +mptscsih_abort(Scsi_Cmnd * SCpnt) +{ + MPT_FRAME_HDR *mf; + SCSITaskMgmt_t *pScsiTm; + MPT_SCSI_HOST *hd; + u32 *msg; + u32 ctx2abort; + int i; + + printk(KERN_WARNING MYNAM ": Attempting _ABORT SCSI IO (=%p)\n", SCpnt); + printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); + + hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata; + + if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) { +/* SCpnt->result = DID_SOFT_ERROR << 16; */ + SCpnt->result = STS_BUSY; + SCpnt->scsi_done(SCpnt); + return FAILED; + } + + pScsiTm = (SCSITaskMgmt_t *) mf; + msg = (u32 *) mf; + + pScsiTm->TargetID = SCpnt->target; + pScsiTm->Bus = hd->port; + pScsiTm->ChainOffset = 0; + pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; + + pScsiTm->Reserved = 0; + pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK; + pScsiTm->Reserved1 = 0; + pScsiTm->MsgFlags = 0; + + for (i = 0; i < 8; i++) { + u8 val = 0; + if (i == 1) + val = SCpnt->lun; + pScsiTm->LUN[i] = val; + } + + for (i = 0; i < 7; i++) + pScsiTm->Reserved2[i] = 0; + + /* Most important! Set TaskMsgContext to SCpnt's MsgContext! + * (the IO to be ABORT'd) + * + * NOTE: Since we do not byteswap MsgContext, we do not + * swap it here either. It is an opaque cookie to + * the controller, so it does not matter. -DaveM + */ + ctx2abort = SCPNT_TO_MSGCTX(SCpnt); + dprintk((KERN_INFO MYNAM ":DbG: ctx2abort = %08x\n", ctx2abort)); + pScsiTm->TaskMsgContext = ctx2abort; + + wmb(); + +/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake + mpt_put_msg_frame(hd->ioc->id, mf); +*/ +/* FIXME! Check return status! */ + (void) mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, sizeof(SCSITaskMgmt_t), msg); + + wmb(); + + return SUCCESS; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant + * @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to + * + * (linux Scsi_Host_Template.eh_bus_reset_handler routine) + * + * Returns SUCCESS or FAILED. + */ +int +mptscsih_bus_reset(Scsi_Cmnd * SCpnt) +{ + MPT_FRAME_HDR *mf; + SCSITaskMgmt_t *pScsiTm; + MPT_SCSI_HOST *hd; + u32 *msg; + int i; + + printk(KERN_WARNING MYNAM ": Attempting _BUS_RESET (%p)\n", SCpnt); + printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); + + hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata; + + if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) { +/* SCpnt->result = DID_SOFT_ERROR << 16; */ + SCpnt->result = STS_BUSY; + SCpnt->scsi_done(SCpnt); + return FAILED; + } + + pScsiTm = (SCSITaskMgmt_t *) mf; + msg = (u32 *) mf; + + pScsiTm->TargetID = SCpnt->target; + pScsiTm->Bus = hd->port; + pScsiTm->ChainOffset = 0; + pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; + + pScsiTm->Reserved = 0; + pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS; + pScsiTm->Reserved1 = 0; + pScsiTm->MsgFlags = 0; + + for (i = 0; i < 8; i++) + pScsiTm->LUN[i] = 0; + + /* Control: No data direction, set task mgmt bit? */ + for (i = 0; i < 7; i++) + pScsiTm->Reserved2[i] = 0; + + pScsiTm->TaskMsgContext = cpu_to_le32(0); + + wmb(); + +/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake + mpt_put_msg_frame(hd->ioc->id, mf); +*/ +/* FIXME! Check return status! */ + (void) mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, sizeof(SCSITaskMgmt_t), msg); + + wmb(); + + return SUCCESS; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant + * @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to + * + * (linux Scsi_Host_Template.eh_dev_reset_handler routine) + * + * Returns SUCCESS or FAILED. + */ +int +mptscsih_dev_reset(Scsi_Cmnd * SCpnt) +{ + MPT_FRAME_HDR *mf; + SCSITaskMgmt_t *pScsiTm; + MPT_SCSI_HOST *hd; + u32 *msg; + int i; + + printk(KERN_WARNING MYNAM ": Attempting _TARGET_RESET (%p)\n", SCpnt); + printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); + + hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata; + + if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) { +/* SCpnt->result = DID_SOFT_ERROR << 16; */ + SCpnt->result = STS_BUSY; + SCpnt->scsi_done(SCpnt); + return FAILED; + } + + pScsiTm = (SCSITaskMgmt_t *) mf; + msg = (u32*)mf; + + pScsiTm->TargetID = SCpnt->target; + pScsiTm->Bus = hd->port; + pScsiTm->ChainOffset = 0; + pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; + + pScsiTm->Reserved = 0; + pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET; + pScsiTm->Reserved1 = 0; + pScsiTm->MsgFlags = 0; + + /* _TARGET_RESET goes to LUN 0 always! */ + for (i = 0; i < 8; i++) + pScsiTm->LUN[i] = 0; + + /* Control: No data direction, set task mgmt bit? */ + for (i = 0; i < 7; i++) + pScsiTm->Reserved2[i] = 0; + + pScsiTm->TaskMsgContext = cpu_to_le32(0); + + wmb(); + +/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake + mpt_put_msg_frame(hd->ioc->id, mf); +*/ +/* FIXME! Check return status! */ + (void) mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, sizeof(SCSITaskMgmt_t), msg); + + wmb(); + + return SUCCESS; +} + +#if 0 /* { */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_host_reset - Perform a SCSI host adapter RESET! + * new_eh variant + * @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to + * + * (linux Scsi_Host_Template.eh_host_reset_handler routine) + * + * Returns SUCCESS or FAILED. + */ +int +mptscsih_host_reset(Scsi_Cmnd * SCpnt) +{ + return FAILED; +} +#endif /* } */ + +#else /* MPT_SCSI old EH stuff... */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_old_abort - Abort linux Scsi_Cmnd routine + * @SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted + * + * (linux Scsi_Host_Template.abort routine) + * + * Returns SCSI_ABORT_{SUCCESS,BUSY,PENDING}. + */ +int +mptscsih_old_abort(Scsi_Cmnd *SCpnt) +{ + MPT_SCSI_HOST *hd; + MPT_FRAME_HDR *mf; + struct tq_struct *ptaskfoo; + unsigned long flags; + + printk(KERN_WARNING MYNAM ": Scheduling _ABORT SCSI IO (=%p)\n", SCpnt); + printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); + + if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) { + SCpnt->result = DID_ABORT << 16; + SCpnt->scsi_done(SCpnt); + return SCSI_ABORT_SUCCESS; + } + + /* + * Check to see if there's already an ABORT queued for this guy. + */ + mf = search_taskQ(0,SCpnt,MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK); + if (mf != NULL) { + return SCSI_ABORT_PENDING; + } + + if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) { +/* SCpnt->result = DID_SOFT_ERROR << 16; */ + SCpnt->result = STS_BUSY; + SCpnt->scsi_done(SCpnt); + return SCSI_ABORT_BUSY; + } + + /* + * Add ourselves to (end of) mpt_scsih_taskQ. + * Check to see if our _bh is running. If NOT, schedule it. + */ + dslprintk((KERN_INFO MYNAM ": spinlock#2\n")); + spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); + Q_ADD_TAIL(&mpt_scsih_taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR); + mpt_scsih_taskQ_cnt++; + /* Yikes - linkage! */ +/* SCpnt->host_scribble = (unsigned char *)mf; */ + mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK; + mf->u.frame.linkage.argp1 = SCpnt; + if (! mpt_scsih_taskQ_bh_active) { + mpt_scsih_taskQ_bh_active = 1; + /* + * Oh how cute, no alloc/free/mgmt needed if we use + * (bottom/unused portion of) MPT request frame. + */ + ptaskfoo = (struct tq_struct *) ((u8*)mf + hd->ioc->req_sz - sizeof(*ptaskfoo)); + ptaskfoo->sync = 0; + ptaskfoo->routine = mptscsih_taskmgmt_bh; + ptaskfoo->data = SCpnt; + + SCHEDULE_TASK(ptaskfoo); + } + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + + return SCSI_ABORT_PENDING; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_old_reset - Perform a SCSI BUS_RESET! + * @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to + * @reset_flags: (not used?) + * + * (linux Scsi_Host_Template.reset routine) + * + * Returns SCSI_RESET_{SUCCESS,PUNT,PENDING}. + */ +int +mptscsih_old_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) +{ + MPT_SCSI_HOST *hd; + MPT_FRAME_HDR *mf; + struct tq_struct *ptaskfoo; + unsigned long flags; + + printk(KERN_WARNING MYNAM ": Scheduling _BUS_RESET (=%p)\n", SCpnt); + printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); + + if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) { + SCpnt->result = DID_RESET << 16; + SCpnt->scsi_done(SCpnt); + return SCSI_RESET_SUCCESS; + } + + /* + * Check to see if there's already a BUS_RESET queued for this guy. + */ + mf = search_taskQ(0,SCpnt,MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS); + if (mf != NULL) { + return SCSI_RESET_PENDING; + } + + if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) { +/* SCpnt->result = DID_SOFT_ERROR << 16; */ + SCpnt->result = STS_BUSY; + SCpnt->scsi_done(SCpnt); + return SCSI_RESET_PUNT; + } + + /* + * Add ourselves to (end of) mpt_scsih_taskQ. + * Check to see if our _bh is running. If NOT, schedule it. + */ + dslprintk((KERN_INFO MYNAM ": spinlock#3\n")); + spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); + Q_ADD_TAIL(&mpt_scsih_taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR); + mpt_scsih_taskQ_cnt++; + /* Yikes - linkage! */ +/* SCpnt->host_scribble = (unsigned char *)mf; */ + mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS; + mf->u.frame.linkage.argp1 = SCpnt; + if (! mpt_scsih_taskQ_bh_active) { + mpt_scsih_taskQ_bh_active = 1; + /* + * Oh how cute, no alloc/free/mgmt needed if we use + * (bottom/unused portion of) MPT request frame. + */ + ptaskfoo = (struct tq_struct *) ((u8*)mf + hd->ioc->req_sz - sizeof(*ptaskfoo)); + ptaskfoo->sync = 0; + ptaskfoo->routine = mptscsih_taskmgmt_bh; + ptaskfoo->data = SCpnt; + + SCHEDULE_TASK(ptaskfoo); + } + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + + return SCSI_RESET_PENDING; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptscsih_taskmgmt_bh - SCSI task mgmt bottom half handler + * @sc: (unused) + * + * This routine (thread) is active whenever there are any outstanding + * SCSI task management requests for a SCSI host adapter. + * IMPORTANT! This routine is scheduled therefore should never be + * running in ISR context. i.e., it's safe to sleep here. + */ +void +mptscsih_taskmgmt_bh(void *sc) +{ + Scsi_Cmnd *SCpnt; + MPT_FRAME_HDR *mf; + SCSITaskMgmt_t *pScsiTm; + MPT_SCSI_HOST *hd; + u32 ctx2abort = 0; + int i; + unsigned long flags; + u8 task_type; + + dslprintk((KERN_INFO MYNAM ": spinlock#4\n")); + spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); + mpt_scsih_taskQ_bh_active = 1; + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + + while (1) { + /* + * We MUST remove item from taskQ *before* we format the + * frame as a SCSITaskMgmt request and send it down to the IOC. + */ + dslprintk((KERN_INFO MYNAM ": spinlock#5\n")); + spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); + if (Q_IS_EMPTY(&mpt_scsih_taskQ)) { + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + break; + } + mf = mpt_scsih_taskQ.head; + Q_DEL_ITEM(&mf->u.frame.linkage); + mpt_scsih_taskQ_cnt--; + mpt_scsih_active_taskmgmt_mf = mf; + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + + SCpnt = (Scsi_Cmnd*)mf->u.frame.linkage.argp1; + if (SCpnt == NULL) { + printk(KERN_ERR MYNAM ": ERROR: TaskMgmt has NULL SCpnt! (%p:%p)\n", mf, SCpnt); + continue; + } + pScsiTm = (SCSITaskMgmt_t *) mf; + + for (i = 0; i < 8; i++) { + pScsiTm->LUN[i] = 0; + } + + task_type = mf->u.frame.linkage.arg1; + if (task_type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) + { + printk(KERN_WARNING MYNAM ": Attempting _ABORT SCSI IO! (mf:sc=%p:%p)\n", mf, SCpnt); + + /* Most important! Set TaskMsgContext to SCpnt's MsgContext! + * (the IO to be ABORT'd) + * + * NOTE: Since we do not byteswap MsgContext, we do not + * swap it here either. It is an opaque cookie to + * the controller, so it does not matter. -DaveM + */ + ctx2abort = SCPNT_TO_MSGCTX(SCpnt); + pScsiTm->LUN[1] = SCpnt->lun; + } + else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) + { + printk(KERN_WARNING MYNAM ": Attempting _BUS_RESET! (against SCSI IO mf:sc=%p:%p)\n", mf, SCpnt); + } +#if 0 + else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {} + else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET) {} +#endif + + printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); + + hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata; + + pScsiTm->TargetID = SCpnt->target; + pScsiTm->Bus = hd->port; + pScsiTm->ChainOffset = 0; + pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; + + pScsiTm->Reserved = 0; + pScsiTm->TaskType = task_type; + pScsiTm->Reserved1 = 0; + pScsiTm->MsgFlags = 0; + + for (i = 0; i < 7; i++) + pScsiTm->Reserved2[i] = 0; + + dprintk((KERN_INFO MYNAM ":DbG: ctx2abort = %08x\n", ctx2abort)); + pScsiTm->TaskMsgContext = ctx2abort; + + /* Control: No data direction, set task mgmt bit? */ + + /* + * As of MPI v0.10 this request can NOT be sent (normally) + * via FIFOs. So we can't: + * mpt_put_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); + * SCSITaskMgmt requests MUST be sent ONLY via + * Doorbell/handshake now. :-( + * + * FIXME! Check return status! + */ + (void) mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, sizeof(SCSITaskMgmt_t), (u32*)mf); + + /* Spin-Wait for TaskMgmt complete!!! */ + while (mpt_scsih_active_taskmgmt_mf != NULL) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/2); + } + } + + dslprintk((KERN_INFO MYNAM ": spinlock#6\n")); + spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); + mpt_scsih_taskQ_bh_active = 0; + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + + return; +} + +#endif /* } */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_taskmgmt_complete - Callback routine, gets registered to + * Fusion MPT base driver + * @ioc: Pointer to MPT_ADAPTER structure + * @mf: Pointer to SCSI task mgmt request frame + * @r: Pointer to SCSI task mgmt reply frame + * + * This routine is called from mptbase.c::mpt_interrupt() at the completion + * of any SCSI task management request. + * This routine is registered with the MPT (base) driver at driver + * load/init time via the mpt_register() API call. + * + * Returns 1 indicating alloc'd request frame ptr should be freed. + */ +static int +mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r) +{ + SCSITaskMgmtReply_t *pScsiTmReply; + SCSITaskMgmt_t *pScsiTmReq; + u8 tmType; +#ifndef MPT_SCSI_USE_NEW_EH + unsigned long flags; +#endif + + dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt completed mf=%p, r=%p\n", + mf, r)); + +#ifndef MPT_SCSI_USE_NEW_EH + dslprintk((KERN_INFO MYNAM ": spinlock#7\n")); + spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); + /* It better be the active one! */ + if (mf != mpt_scsih_active_taskmgmt_mf) { + printk(KERN_ERR MYNAM ": ERROR! Non-active TaskMgmt (=%p) completed!\n", mf); + mpt_scsih_active_taskmgmt_mf = NULL; + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + return 1; + } + +#ifdef MPT_DEBUG + if ((mf == NULL) || + (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { + printk(KERN_ERR MYNAM ": ERROR! NULL or BAD TaskMgmt ptr (=%p)!\n", mf); + mpt_scsih_active_taskmgmt_mf = NULL; + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + return 1; + } +#endif + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); +#endif + + if (r != NULL) { + pScsiTmReply = (SCSITaskMgmtReply_t*)r; + pScsiTmReq = (SCSITaskMgmt_t*)mf; + + /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */ + tmType = pScsiTmReq->TaskType; + + dprintk((KERN_INFO MYNAM ": TaskType = %d\n", tmType)); + dprintk((KERN_INFO MYNAM ": TerminationCount = %d\n", + le32_to_cpu(pScsiTmReply->TerminationCount))); + + /* Error? (anything non-zero?) */ + if (*(u32 *)&pScsiTmReply->Reserved2[0]) { + dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt (%d) - Oops!\n", tmType)); + dprintk((KERN_INFO MYNAM ": IOCStatus = %04xh\n", + le16_to_cpu(pScsiTmReply->IOCStatus))); + dprintk((KERN_INFO MYNAM ": IOCLogInfo = %08xh\n", + le32_to_cpu(pScsiTmReply->IOCLogInfo))); + } else { + dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt (%d) SUCCESS!\n", tmType)); + } + } + +#ifndef MPT_SCSI_USE_NEW_EH + /* + * Signal to _bh thread that we finished. + */ + dslprintk((KERN_INFO MYNAM ": spinlock#8\n")); + spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); + mpt_scsih_active_taskmgmt_mf = NULL; + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); +#endif + + return 1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * This is anyones guess quite frankly. + */ + +int +mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip) +{ + int size; + + size = disk->capacity; + ip[0] = 64; /* heads */ + ip[1] = 32; /* sectors */ + if ((ip[2] = size >> 11) > 1024) { /* cylinders, test for big disk */ + ip[0] = 255; /* heads */ + ip[1] = 63; /* sectors */ + ip[2] = size / (255 * 63); /* cylinders */ + } + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Private routines... + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* 19991030 -sralston + * Return absolute SCSI data direction: + * 1 = _DATA_OUT + * 0 = _DIR_NONE + * -1 = _DATA_IN + */ +static int +mptscsih_io_direction(Scsi_Cmnd *cmd) +{ + switch (cmd->cmnd[0]) { + /* _DATA_OUT commands */ + case WRITE_6: case WRITE_10: case WRITE_12: + case WRITE_LONG: case WRITE_SAME: case WRITE_BUFFER: + case WRITE_VERIFY: case WRITE_VERIFY_12: + case COMPARE: case COPY: case COPY_VERIFY: + case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW: + case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12: + case MODE_SELECT: case MODE_SELECT_10: case LOG_SELECT: + case SEND_DIAGNOSTIC: case CHANGE_DEFINITION: case UPDATE_BLOCK: + case SET_WINDOW: case MEDIUM_SCAN: case SEND_VOLUME_TAG: + case REASSIGN_BLOCKS: + case PERSISTENT_RESERVE_OUT: + case 0xea: + return 1; + + /* No data transfer commands */ + case SEEK_6: case SEEK_10: + case RESERVE: case RELEASE: + case TEST_UNIT_READY: + case START_STOP: + case ALLOW_MEDIUM_REMOVAL: + return 0; + + /* Conditional data transfer commands */ + case FORMAT_UNIT: + if (cmd->cmnd[1] & 0x10) /* FmtData (data out phase)? */ + return 1; + else + return 0; + + case VERIFY: + if (cmd->cmnd[1] & 0x02) /* VERIFY:BYTCHK (data out phase)? */ + return 1; + else + return 0; + + case RESERVE_10: + if (cmd->cmnd[1] & 0x03) /* RESERSE:{LongID|Extent} (data out phase)? */ + return 1; + else + return 0; + +#if 0 + case REZERO_UNIT: /* (or REWIND) */ + case SPACE: + case ERASE: case ERASE_10: + case SYNCHRONIZE_CACHE: + case LOCK_UNLOCK_CACHE: +#endif + + /* Must be data _IN! */ + default: + return -1; + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static void +copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply) +{ + MPT_SCSI_DEV *mpt_sdev = NULL; + u32 sense_count = le32_to_cpu(pScsiReply->SenseCount); + char devFoo[32]; + IO_Info_t thisIo; + + if (sc && sc->device) + mpt_sdev = (MPT_SCSI_DEV*) sc->device->hostdata; + + if (sense_count) { + u8 *sense_data; + int req_index; + + /* Copy the sense received into the scsi command block. */ + req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * 256)); + memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc)); + /* Cache SenseData for this SCSI device! */ + if (mpt_sdev) { + memcpy(mpt_sdev->CachedSense.data, sense_data, sense_count); + mpt_sdev->sense_sz = sense_count; + } + } else { + dprintk((KERN_INFO MYNAM ": Hmmm... SenseData len=0! (?)\n")); + } + + + thisIo.cdbPtr = sc->cmnd; + thisIo.sensePtr = sc->sense_buffer; + thisIo.SCSIStatus = pScsiReply->SCSIStatus; + thisIo.DoDisplay = 1; + sprintf(devFoo, "ioc%d,scsi%d:%d", hd->ioc->id, sc->target, sc->lun); + thisIo.DevIDStr = devFoo; +/* fubar */ + thisIo.dataPtr = NULL; + thisIo.inqPtr = NULL; + if (sc->device) { + thisIo.inqPtr = sc->device->vendor-8; /* FIXME!!! */ + } + (void) mpt_ScsiHost_ErrorReport(&thisIo); + + return; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static u32 +SCPNT_TO_MSGCTX(Scsi_Cmnd *sc) +{ + MPT_SCSI_HOST *hd; + MPT_FRAME_HDR *mf; + int i; + + hd = (MPT_SCSI_HOST *) sc->host->hostdata; + + for (i = 0; i < hd->ioc->req_depth; i++) { + if (hd->ScsiLookup[i] == sc) { + mf = MPT_INDEX_2_MFPTR(hd->ioc, i); + return mf->u.frame.hwhdr.msgctxu.MsgContext; + } + } + + return -1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/* see mptscsih.h */ + +#ifdef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS + static Scsi_Host_Template driver_template = MPT_SCSIHOST; +# include "../../scsi/scsi_module.c" +#endif + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) +{ + u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; + + dprintk((KERN_INFO MYNAM ": MPT event (=%02Xh) routed to SCSI host driver!\n", event)); + + switch (event) { + case MPI_EVENT_UNIT_ATTENTION: /* 03 */ + /* FIXME! */ + break; + case MPI_EVENT_IOC_BUS_RESET: /* 04 */ + /* FIXME! */ + break; + case MPI_EVENT_EXT_BUS_RESET: /* 05 */ + /* FIXME! */ + break; + case MPI_EVENT_LOGOUT: /* 09 */ + /* FIXME! */ + break; + + /* + * CHECKME! Don't think we need to do + * anything for these, but... + */ + case MPI_EVENT_RESCAN: /* 06 */ + case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */ + case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */ + /* + * CHECKME! Falling thru... + */ + + case MPI_EVENT_NONE: /* 00 */ + case MPI_EVENT_LOG_DATA: /* 01 */ + case MPI_EVENT_STATE_CHANGE: /* 02 */ + case MPI_EVENT_EVENT_CHANGE: /* 0A */ + default: + dprintk((KERN_INFO MYNAM ": Ignoring event (=%02Xh)\n", event)); + break; + } + + return 1; /* currently means nothing really */ +} + +#if 0 /* { */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * scsiherr.c - Fusion MPT SCSI Host driver error handling/reporting. + * + * drivers/message/fusion/scsiherr.c + */ + +//extern const char **mpt_ScsiOpcodesPtr; /* needed by mptscsih.c */ +//extern ASCQ_Table_t *mpt_ASCQ_TablePtr; +//extern int mpt_ASCQ_TableSz; + +/* Lie! */ +#define MYNAM "mptscsih" + +#endif /* } */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Private data... + */ +static ASCQ_Table_t *mptscsih_ASCQ_TablePtr; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* old symsense.c stuff... */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Private data... + * To protect ourselves against those that would pass us bogus pointers + */ +static u8 dummyInqData[SCSI_STD_INQUIRY_BYTES] + = { 0x1F, 0x00, 0x00, 0x00, + 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static u8 dummySenseData[SCSI_STD_SENSE_BYTES] + = { 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 }; +static u8 dummyCDB[16] + = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static u8 dummyScsiData[16] + = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +#if 0 +static const char *PeripheralDeviceTypeString[32] = { + "Direct-access", /* 00h */ + "Sequential-access", /* 01h */ + "Printer", /* 02h */ + "Processor", /* 03h */ + /*"Write-Once-Read-Multiple",*/ /* 04h */ + "WORM", /* 04h */ + "CD-ROM", /* 05h */ + "Scanner", /* 06h */ + "Optical memory", /* 07h */ + "Media Changer", /* 08h */ + "Communications", /* 09h */ + "(Graphics arts pre-press)", /* 0Ah */ + "(Graphics arts pre-press)", /* 0Bh */ + "Array controller", /* 0Ch */ + "Enclosure services", /* 0Dh */ + "Simplified direct-access", /* 0Eh */ + "Reserved-0Fh", /* 0Fh */ + "Reserved-10h", /* 10h */ + "Reserved-11h", /* 11h */ + "Reserved-12h", /* 12h */ + "Reserved-13h", /* 13h */ + "Reserved-14h", /* 14h */ + "Reserved-15h", /* 15h */ + "Reserved-16h", /* 16h */ + "Reserved-17h", /* 17h */ + "Reserved-18h", /* 18h */ + "Reserved-19h", /* 19h */ + "Reserved-1Ah", /* 1Ah */ + "Reserved-1Bh", /* 1Bh */ + "Reserved-1Ch", /* 1Ch */ + "Reserved-1Dh", /* 1Dh */ + "Reserved-1Eh", /* 1Eh */ + "Unknown" /* 1Fh */ +}; +#endif + +static char *ScsiStatusString[] = { + "GOOD", /* 00h */ + NULL, /* 01h */ + "CHECK CONDITION", /* 02h */ + NULL, /* 03h */ + "CONDITION MET", /* 04h */ + NULL, /* 05h */ + NULL, /* 06h */ + NULL, /* 07h */ + "BUSY", /* 08h */ + NULL, /* 09h */ + NULL, /* 0Ah */ + NULL, /* 0Bh */ + NULL, /* 0Ch */ + NULL, /* 0Dh */ + NULL, /* 0Eh */ + NULL, /* 0Fh */ + "INTERMEDIATE", /* 10h */ + NULL, /* 11h */ + NULL, /* 12h */ + NULL, /* 13h */ + "INTERMEDIATE-CONDITION MET", /* 14h */ + NULL, /* 15h */ + NULL, /* 16h */ + NULL, /* 17h */ + "RESERVATION CONFLICT", /* 18h */ + NULL, /* 19h */ + NULL, /* 1Ah */ + NULL, /* 1Bh */ + NULL, /* 1Ch */ + NULL, /* 1Dh */ + NULL, /* 1Eh */ + NULL, /* 1Fh */ + NULL, /* 20h */ + NULL, /* 21h */ + "COMMAND TERMINATED", /* 22h */ + NULL, /* 23h */ + NULL, /* 24h */ + NULL, /* 25h */ + NULL, /* 26h */ + NULL, /* 27h */ + "TASK SET FULL", /* 28h */ + NULL, /* 29h */ + NULL, /* 2Ah */ + NULL, /* 2Bh */ + NULL, /* 2Ch */ + NULL, /* 2Dh */ + NULL, /* 2Eh */ + NULL, /* 2Fh */ + "ACA ACTIVE", /* 30h */ + NULL +}; + +static const char *ScsiCommonOpString[] = { + "TEST UNIT READY", /* 00h */ + "REZERO UNIT (REWIND)", /* 01h */ + NULL, /* 02h */ + "REQUEST_SENSE", /* 03h */ + "FORMAT UNIT (MEDIUM)", /* 04h */ + "READ BLOCK LIMITS", /* 05h */ + NULL, /* 06h */ + "REASSIGN BLOCKS", /* 07h */ + "READ(6)", /* 08h */ + NULL, /* 09h */ + "WRITE(6)", /* 0Ah */ + "SEEK(6)", /* 0Bh */ + NULL, /* 0Ch */ + NULL, /* 0Dh */ + NULL, /* 0Eh */ + "READ REVERSE", /* 0Fh */ + "WRITE_FILEMARKS", /* 10h */ + "SPACE(6)", /* 11h */ + "INQUIRY", /* 12h */ + NULL +}; + +static const char *SenseKeyString[] = { + "NO SENSE", /* 0h */ + "RECOVERED ERROR", /* 1h */ + "NOT READY", /* 2h */ + "MEDIUM ERROR", /* 3h */ + "HARDWARE ERROR", /* 4h */ + "ILLEGAL REQUEST", /* 5h */ + "UNIT ATTENTION", /* 6h */ + "DATA PROTECT", /* 7h */ + "BLANK CHECK", /* 8h */ + "VENDOR-SPECIFIC", /* 9h */ + "ABORTED COPY", /* Ah */ + "ABORTED COMMAND", /* Bh */ + "EQUAL (obsolete)", /* Ch */ + "VOLUME OVERFLOW", /* Dh */ + "MISCOMPARE", /* Eh */ + "RESERVED", /* Fh */ + NULL +}; + +#define SPECIAL_ASCQ(c,q) \ + (((c) == 0x40 && (q) != 0x00) || ((c) == 0x4D) || ((c) == 0x70)) + +#if 0 +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Sense_Key_Specific() - If Sense_Key_Specific_Valid bit is set, + * then print additional information via + * a call to SDMS_SystemAlert(). + * + * Return: nothing + */ +static void Sense_Key_Specific(IO_Info_t *ioop, char *msg1) +{ + u8 *sd; + u8 BadValue; + u8 SenseKey; + int Offset; + int len = strlen(msg1); + + sd = ioop->sensePtr; + if (SD_Additional_Sense_Length(sd) < 8) + return; + + SenseKey = SD_Sense_Key(sd); + + if (SD_Sense_Key_Specific_Valid(sd)) { + if (SenseKey == SK_ILLEGAL_REQUEST) { + Offset = SD_Bad_Byte(sd); + if (SD_Was_Illegal_Request(sd)) { + BadValue = ioop->cdbPtr[Offset]; + len += sprintf(msg1+len, "\n Illegal CDB value=%02Xh found at CDB ", + BadValue); + } else { + BadValue = ioop->dataPtr[Offset]; + len += sprintf(msg1+len, "\n Illegal DATA value=%02Xh found at DATA ", + BadValue); + } + len += sprintf(msg1+len, "byte=%02Xh", Offset); + if (SD_SKS_Bit_Pointer_Valid(sd)) + len += sprintf(msg1+len, "/bit=%1Xh", SD_SKS_Bit_Pointer(sd)); + } else if ((SenseKey == SK_RECOVERED_ERROR) || + (SenseKey == SK_HARDWARE_ERROR) || + (SenseKey == SK_MEDIUM_ERROR)) { + len += sprintf(msg1+len, "\n Recovery algorithm Actual_Retry_Count=%02Xh", + SD_Actual_Retry_Count(sd)); + } + } +} +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int dump_cdb(char *foo, unsigned char *cdb) +{ + int i, grpCode, cdbLen; + int l = 0; + + grpCode = cdb[0] >> 5; + if (grpCode < 1) + cdbLen = 6; + else if (grpCode < 3) + cdbLen = 10; + else if (grpCode == 5) + cdbLen = 12; + else + cdbLen = 16; + + for (i=0; i < cdbLen; i++) + l += sprintf(foo+l, " %02X", cdb[i]); + + return l; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int dump_sd(char *foo, unsigned char *sd) +{ + int snsLen = 8 + SD_Additional_Sense_Length(sd); + int l = 0; + int i; + + for (i=0; i < MIN(snsLen,18); i++) + l += sprintf(foo+l, " %02X", sd[i]); + l += sprintf(foo+l, "%s", snsLen>18 ? " ..." : ""); + + return l; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* Do ASC/ASCQ lookup/grindage to English readable string(s) */ +static const char * ascq_set_strings_4max( + u8 ASC, u8 ASCQ, + const char **s1, const char **s2, const char **s3, const char **s4) +{ + static const char *asc_04_part1_string = "LOGICAL UNIT "; + static const char *asc_04_part2a_string = "NOT READY, "; + static const char *asc_04_part2b_string = "IS "; + static const char *asc_04_ascq_NN_part3_strings[] = { /* ASC ASCQ (hex) */ + "CAUSE NOT REPORTABLE", /* 04 00 */ + "IN PROCESS OF BECOMING READY", /* 04 01 */ + "INITIALIZING CMD. REQUIRED", /* 04 02 */ + "MANUAL INTERVENTION REQUIRED", /* 04 03 */ + /* Add " IN PROGRESS" to all the following... */ + "FORMAT", /* 04 04 */ + "REBUILD", /* 04 05 */ + "RECALCULATION", /* 04 06 */ + "OPERATION", /* 04 07 */ + "LONG WRITE", /* 04 08 */ + "SELF-TEST", /* 04 09 */ + NULL + }; + static char *asc_04_part4_string = " IN PROGRESS"; + + static char *asc_29_ascq_NN_strings[] = { /* ASC ASCQ (hex) */ + "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED", /* 29 00 */ + "POWER ON OCCURRED", /* 29 01 */ + "SCSI BUS RESET OCCURRED", /* 29 02 */ + "BUS DEVICE RESET FUNCTION OCCURRED", /* 29 03 */ + "DEVICE INTERNAL RESET", /* 29 04 */ + "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED", /* 29 05 */ + "TRANSCEIVER MODE CHANGED TO LVD", /* 29 06 */ + NULL + }; + static char *ascq_vendor_uniq = "(Vendor Unique)"; + static char *ascq_noone = "(no matching ASC/ASCQ description found)"; + int idx; + + *s1 = *s2 = *s3 = *s4 = ""; /* set'em all to the empty "" string */ + + /* CHECKME! Need lock/sem? + * Update and examine for isense module presense. + */ + mptscsih_ASCQ_TablePtr = (ASCQ_Table_t *)mpt_v_ASCQ_TablePtr; + + if (mptscsih_ASCQ_TablePtr == NULL) { + /* 2nd chances... */ + if (ASC == 0x04 && (ASCQ < sizeof(asc_04_ascq_NN_part3_strings)/sizeof(char*)-1)) { + *s1 = asc_04_part1_string; + *s2 = (ASCQ == 0x01) ? asc_04_part2b_string : asc_04_part2a_string; + *s3 = asc_04_ascq_NN_part3_strings[ASCQ]; + /* check for " IN PROGRESS" ones */ + if (ASCQ >= 0x04) + *s4 = asc_04_part4_string; + } else if (ASC == 0x29 && (ASCQ < sizeof(asc_29_ascq_NN_strings)/sizeof(char*)-1)) + *s1 = asc_29_ascq_NN_strings[ASCQ]; + /* + * else { leave all *s[1-4] values pointing to the empty "" string } + */ + return *s1; + } + + /* + * Need to check ASC here; if it is "special," then + * the ASCQ is variable, and indicates failed component number. + * We must treat the ASCQ as a "don't care" while searching the + * mptscsih_ASCQ_Table[] by masking it off, and then restoring it later + * on when we actually need to identify the failed component. + */ + if (SPECIAL_ASCQ(ASC,ASCQ)) + ASCQ = 0xFF; + + /* OK, now search mptscsih_ASCQ_Table[] for a matching entry */ + for (idx = 0; mptscsih_ASCQ_TablePtr && idx < mpt_ASCQ_TableSz; idx++) + if ((ASC == mptscsih_ASCQ_TablePtr[idx].ASC) && (ASCQ == mptscsih_ASCQ_TablePtr[idx].ASCQ)) + return (*s1 = mptscsih_ASCQ_TablePtr[idx].Description); + + if ((ASC >= 0x80) || (ASCQ >= 0x80)) + *s1 = ascq_vendor_uniq; + else + *s1 = ascq_noone; + + return *s1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * SCSI Error Report; desired output format... + *--- +SCSI Error Report =-=-=-=-=-=-=-=-=-=-=-=-=-= (ioc0,scsi0:0) + SCSI_Status=02h (CHECK CONDITION) + Original_CDB[]: 00 00 00 00 00 00 - TestUnitReady + SenseData[12h]: 70 00 06 00 00 00 00 0A 00 00 00 00 29 00 03 00 00 00 + SenseKey=6h (UNIT ATTENTION); FRU=03h + ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED" + *--- + */ + +int mpt_ScsiHost_ErrorReport(IO_Info_t *ioop) +{ + char foo[512]; + char buf2[32]; + char *statstr; + const char *opstr; + int sk = SD_Sense_Key(ioop->sensePtr); + const char *skstr = SenseKeyString[sk]; + unsigned char asc = SD_ASC(ioop->sensePtr); + unsigned char ascq = SD_ASCQ(ioop->sensePtr); + int l; + + /* + * More quiet mode. + * Filter out common, repetitive, warning-type errors... like: + * POWER ON (06,29/00 or 06,29/01), + * SPINNING UP (02,04/01), + * LOGICAL UNIT NOT SUPPORTED (05,25/00), etc. + */ + if ( (sk==SK_UNIT_ATTENTION && asc==0x29 && (ascq==0x00 || ascq==0x01)) + || (sk==SK_NOT_READY && asc==0x04 && ascq==0x01) + || (sk==SK_ILLEGAL_REQUEST && asc==0x25 && ascq==0x00) + ) + { + /* Do nothing! */ + return 0; + } + + /* + * Protect ourselves... + */ + if (ioop->cdbPtr == NULL) + ioop->cdbPtr = dummyCDB; + if (ioop->sensePtr == NULL) + ioop->sensePtr = dummySenseData; + if (ioop->inqPtr == NULL) + ioop->inqPtr = dummyInqData; + if (ioop->dataPtr == NULL) + ioop->dataPtr = dummyScsiData; + + statstr = NULL; + if ((ioop->SCSIStatus >= sizeof(ScsiStatusString)/sizeof(char*)-1) || + ((statstr = (char*)ScsiStatusString[ioop->SCSIStatus]) == NULL)) { + (void) sprintf(buf2, "Bad-Reserved-%02Xh", ioop->SCSIStatus); + statstr = buf2; + } + + opstr = NULL; + if (1+ioop->cdbPtr[0] <= sizeof(ScsiCommonOpString)/sizeof(char*)) + opstr = ScsiCommonOpString[ioop->cdbPtr[0]]; + else if (mpt_ScsiOpcodesPtr) + opstr = mpt_ScsiOpcodesPtr[ioop->cdbPtr[0]]; + + l = sprintf(foo, "SCSI Error Report =-=-= (%s)\n" + " SCSI_Status=%02Xh (%s)\n" + " Original_CDB[]:", + ioop->DevIDStr, + ioop->SCSIStatus, + statstr); + l += dump_cdb(foo+l, ioop->cdbPtr); + if (opstr) + l += sprintf(foo+l, " - \"%s\"", opstr); + l += sprintf(foo+l, "\n SenseData[%02Xh]:", 8+SD_Additional_Sense_Length(ioop->sensePtr)); + l += dump_sd(foo+l, ioop->sensePtr); + l += sprintf(foo+l, "\n SenseKey=%Xh (%s); FRU=%02Xh\n ASC/ASCQ=%02Xh/%02Xh", + sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq ); + + { + const char *x1, *x2, *x3, *x4; + x1 = x2 = x3 = x4 = ""; + x1 = ascq_set_strings_4max(asc, ascq, &x1, &x2, &x3, &x4); + if (x1 != NULL) { + if (x1[0] != '(') + l += sprintf(foo+l, " \"%s%s%s%s\"", x1,x2,x3,x4); + else + l += sprintf(foo+l, " %s%s%s%s", x1,x2,x3,x4); + } + } + +#if 0 + if (SPECIAL_ASCQ(asc,ascq)) + l += sprintf(foo+l, " (%02Xh)", ascq); +#endif + + PrintF(("%s\n", foo)); + + return l; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/mptscsih.h linux.ac/drivers/message/fusion/mptscsih.h --- linux.vanilla/drivers/message/fusion/mptscsih.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/mptscsih.h Sun Apr 15 23:46:56 2001 @@ -0,0 +1,247 @@ +/* + * linux/drivers/message/fusion/mptscsih.h + * High performance SCSI / Fibre Channel SCSI Host device driver. + * For use with PCI chip/adapter(s): + * LSIFC9xx/LSI409xx Fibre Channel + * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * + * Credits: + * This driver would not exist if not for Alan Cox's development + * of the linux i2o driver. + * + * A huge debt of gratitude is owed to David S. Miller (DaveM) + * for fixing much of the stupid and broken stuff in the early + * driver while porting to sparc64 platform. THANK YOU! + * + * (see also mptbase.c) + * + * Copyright (c) 1999-2001 LSI Logic Corporation + * Originally By: Steven J. Ralston + * (mailto:Steve.Ralston@lsil.com) + * + * $Id: mptscsih.h,v 1.7 2001/01/11 16:56:43 sralston Exp $ + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + 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. + + NO WARRANTY + THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + solely responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, damage to or loss of data, + programs or equipment, and unavailability or interruption of operations. + + DISCLAIMER OF LIABILITY + NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + 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 +*/ + +#ifndef SCSIHOST_H_INCLUDED +#define SCSIHOST_H_INCLUDED +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#include "linux/version.h" + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * SCSI Public stuff... + */ + +#ifdef __sparc__ +#define MPT_SCSI_CAN_QUEUE 63 +#define MPT_SCSI_CMD_PER_LUN 63 + /* FIXME! Still investigating qd=64 hang on sparc64... */ +#else +#define MPT_SCSI_CAN_QUEUE 64 +#define MPT_SCSI_CMD_PER_LUN 64 +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Various bits and pieces broke within the lk-2.4.0-testN series:-( + * So here are various HACKS to work around them. + */ + +/* + * Conditionalizing with "#ifdef MODULE/#endif" around: + * static Scsi_Host_Template driver_template = XX; + * #include <../../scsi/scsi_module.c> + * lines was REMOVED @ lk-2.4.0-test9 + * Issue discovered 20001213 by: sshirron + */ +#define MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS 1 +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,0) +# if LINUX_VERSION_CODE == KERNEL_VERSION(2,4,0) + /* + * Super HACK! -by sralston:-( + * (good grief; heaven help me!) + */ +# include <linux/capability.h> +# if !defined(CAP_LEASE) && !defined(MODULE) +# undef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS +# endif +# else +# ifndef MODULE +# undef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS +# endif +# endif +#endif + +/* + * tq_scheduler disappeared @ lk-2.4.0-test12 + * (right when <linux/sched.h> newly defined TQ_ACTIVE) + */ +#define HAVE_TQ_SCHED 1 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +# include <linux/sched.h> +# ifdef TQ_ACTIVE +# undef HAVE_TQ_SCHED +# endif +#endif +#ifdef HAVE_TQ_SCHED +#define SCHEDULE_TASK(x) \ + /*MOD_INC_USE_COUNT*/; \ + (x)->next = NULL; \ + queue_task(x, &tq_scheduler) +#else +#define SCHEDULE_TASK(x) \ + /*MOD_INC_USE_COUNT*/; \ + if (schedule_task(x) == 0) { \ + /*MOD_DEC_USE_COUNT*/; \ + } +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#define x_scsi_detect mptscsih_detect +#define x_scsi_release mptscsih_release +#define x_scsi_info mptscsih_info +#define x_scsi_queuecommand mptscsih_qcmd +#define x_scsi_abort mptscsih_abort +#define x_scsi_bus_reset mptscsih_bus_reset +#define x_scsi_dev_reset mptscsih_dev_reset +#define x_scsi_host_reset mptscsih_host_reset +#define x_scsi_bios_param mptscsih_bios_param + +#define x_scsi_taskmgmt_bh mptscsih_taskmgmt_bh +#define x_scsi_old_abort mptscsih_old_abort +#define x_scsi_old_reset mptscsih_old_reset + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * MPT SCSI Host / Initiator decls... + */ +extern int x_scsi_detect(Scsi_Host_Template *); +extern int x_scsi_release(struct Scsi_Host *host); +extern const char *x_scsi_info(struct Scsi_Host *); +/*extern int x_scsi_command(Scsi_Cmnd *);*/ +extern int x_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +#ifdef MPT_SCSI_USE_NEW_EH +extern int x_scsi_abort(Scsi_Cmnd *); +extern int x_scsi_bus_reset(Scsi_Cmnd *); +extern int x_scsi_dev_reset(Scsi_Cmnd *); +/*extern int x_scsi_host_reset(Scsi_Cmnd *);*/ +#else +extern int x_scsi_old_abort(Scsi_Cmnd *); +extern int x_scsi_old_reset(Scsi_Cmnd *, unsigned int); +#endif +extern int x_scsi_bios_param(Disk *, kdev_t, int *); +extern void x_scsi_taskmgmt_bh(void *); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) +#define PROC_SCSI_DECL +#else +#define PROC_SCSI_DECL proc_name: "mptscsih", +#endif + +#ifdef MPT_SCSI_USE_NEW_EH + +#define MPT_SCSIHOST { \ + next: NULL, \ + PROC_SCSI_DECL \ + name: "MPT SCSI Host", \ + detect: x_scsi_detect, \ + release: x_scsi_release, \ + info: x_scsi_info, \ + command: NULL, \ + queuecommand: x_scsi_queuecommand, \ + eh_strategy_handler: NULL, \ + eh_abort_handler: x_scsi_abort, \ + eh_device_reset_handler: x_scsi_dev_reset, \ + eh_bus_reset_handler: x_scsi_bus_reset, \ + eh_host_reset_handler: NULL, \ + bios_param: x_scsi_bios_param, \ + can_queue: MPT_SCSI_CAN_QUEUE, \ + this_id: -1, \ + sg_tablesize: 25, \ + cmd_per_lun: MPT_SCSI_CMD_PER_LUN, \ + unchecked_isa_dma: 0, \ + use_clustering: ENABLE_CLUSTERING, \ + use_new_eh_code: 1 \ +} + +#else + +#define MPT_SCSIHOST { \ + next: NULL, \ + PROC_SCSI_DECL \ + name: "MPT SCSI Host", \ + detect: x_scsi_detect, \ + release: x_scsi_release, \ + info: x_scsi_info, \ + command: NULL, \ + queuecommand: x_scsi_queuecommand, \ + abort: x_scsi_old_abort, \ + reset: x_scsi_old_reset, \ + bios_param: x_scsi_bios_param, \ + can_queue: MPT_SCSI_CAN_QUEUE, \ + this_id: -1, \ + sg_tablesize: 25, \ + cmd_per_lun: MPT_SCSI_CMD_PER_LUN, \ + unchecked_isa_dma: 0, \ + use_clustering: ENABLE_CLUSTERING \ +} +#endif + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/* include/scsi/scsi.h may not be quite complete... */ +#ifndef RESERVE_10 +#define RESERVE_10 0x56 +#endif +#ifndef RELEASE_10 +#define RELEASE_10 0x57 +#endif +#ifndef PERSISTENT_RESERVE_IN +#define PERSISTENT_RESERVE_IN 0x5e +#endif +#ifndef PERSISTENT_RESERVE_OUT +#define PERSISTENT_RESERVE_OUT 0x5f +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/scsi3.h linux.ac/drivers/message/fusion/scsi3.h --- linux.vanilla/drivers/message/fusion/scsi3.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/scsi3.h Tue Apr 3 18:48:14 2001 @@ -0,0 +1,700 @@ +/* + * linux/drivers/message/fusion/scsi3.h + * SCSI-3 definitions and macros. + * (Ultimately) SCSI-3 definitions; for now, inheriting + * SCSI-2 definitions. + * + * Copyright (c) 1996-2001 Steven J. Ralston + * Written By: Steven J. Ralston (19960517) + * (mailto:Steve.Ralston@lsil.com) + * + * $Id: scsi3.h,v 1.4 2001/01/06 15:54:25 sralston Exp $ + */ + +#ifndef SCSI3_H_INCLUDED +#define SCSI3_H_INCLUDED +/***************************************************************************/ + +/**************************************************************************** + * + * Includes + */ +#ifdef __KERNEL__ +#include <linux/types.h> +#else + #ifndef U_STUFF_DEFINED + #define U_STUFF_DEFINED + typedef unsigned char u8; + typedef unsigned short u16; + typedef unsigned int u32; + #endif +#endif + +/**************************************************************************** + * + * Defines + */ + +/* + * SCSI Commands + */ +#define CMD_TestUnitReady 0x00 +#define CMD_RezeroUnit 0x01 /* direct-access devices */ +#define CMD_Rewind 0x01 /* sequential-access devices */ +#define CMD_RequestSense 0x03 +#define CMD_FormatUnit 0x04 +#define CMD_ReassignBlock 0x07 +#define CMD_Read6 0x08 +#define CMD_Write6 0x0A +#define CMD_WriteFilemark 0x10 +#define CMD_Space 0x11 +#define CMD_Inquiry 0x12 +#define CMD_ModeSelect6 0x15 +#define CMD_ModeSense6 0x1A +#define CMD_Reserve6 0x16 +#define CMD_Release6 0x17 +#define CMD_Erase 0x19 +#define CMD_StartStopUnit 0x1b /* direct-access devices */ +#define CMD_LoadUnload 0x1b /* sequential-access devices */ +#define CMD_ReceiveDiagnostic 0x1C +#define CMD_SendDiagnostic 0x1D +#define CMD_ReadCapacity 0x25 +#define CMD_Read10 0x28 +#define CMD_Write10 0x2A +#define CMD_WriteVerify 0x2E +#define CMD_Verify 0x2F +#define CMD_ReadDefectData 0x37 +#define CMD_LogSelect 0x4C +#define CMD_LogSense 0x4D +#define CMD_ModeSelect10 0x55 +#define CMD_Reserve10 0x56 +#define CMD_Release10 0x57 +#define CMD_ModeSense10 0x5A +#define CMD_ReportLuns 0xA0 + +/* + * Control byte field + */ +#define CONTROL_BYTE_NACA_BIT 0x04 +#define CONTROL_BYTE_Flag_BIT 0x02 +#define CONTROL_BYTE_Link_BIT 0x01 + +/* + * SCSI Messages + */ +#define MSG_COMPLETE 0x00 +#define MSG_EXTENDED 0x01 +#define MSG_SAVE_POINTERS 0x02 +#define MSG_RESTORE_POINTERS 0x03 +#define MSG_DISCONNECT 0x04 +#define MSG_IDERROR 0x05 +#define MSG_ABORT 0x06 +#define MSG_REJECT 0x07 +#define MSG_NOP 0x08 +#define MSG_PARITY_ERROR 0x09 +#define MSG_LINKED_CMD_COMPLETE 0x0a +#define MSG_LCMD_COMPLETE_W_FLG 0x0b +#define MSG_BUS_DEVICE_RESET 0x0c +#define MSG_ABORT_TAG 0x0d +#define MSG_CLEAR_QUEUE 0x0e +#define MSG_INITIATE_RECOVERY 0x0f + +#define MSG_RELEASE_RECOVRY 0x10 +#define MSG_TERMINATE_IO 0x11 + +#define MSG_SIMPLE_QUEUE 0x20 +#define MSG_HEAD_OF_QUEUE 0x21 +#define MSG_ORDERED_QUEUE 0x22 +#define MSG_IGNORE_WIDE_RESIDUE 0x23 + +#define MSG_IDENTIFY 0x80 +#define MSG_IDENTIFY_W_DISC 0xc0 + +/* + * SCSI Phases + */ +#define PHS_DATA_OUT 0x00 +#define PHS_DATA_IN 0x01 +#define PHS_COMMAND 0x02 +#define PHS_STATUS 0x03 +#define PHS_MSG_OUT 0x06 +#define PHS_MSG_IN 0x07 + +/* + * Statuses + */ +#define STS_GOOD 0x00 +#define STS_CHECK_CONDITION 0x02 +#define STS_CONDITION_MET 0x04 +#define STS_BUSY 0x08 +#define STS_INTERMEDIATE 0x10 +#define STS_INTERMEDIATE_CONDITION_MET 0x14 +#define STS_RESERVATION_CONFLICT 0x18 +#define STS_COMMAND_TERMINATED 0x22 +#define STS_TASK_SET_FULL 0x28 +#define STS_QUEUE_FULL 0x28 +#define STS_ACA_ACTIVE 0x30 + +#define STS_VALID_MASK 0x3e + +#define SCSI_STATUS(x) ((x) & STS_VALID_MASK) + +/* + * SCSI QTag Types + */ +#define QTAG_SIMPLE 0x20 +#define QTAG_HEAD_OF_Q 0x21 +#define QTAG_ORDERED 0x22 + +/* + * SCSI Sense Key Definitons + */ +#define SK_NO_SENSE 0x00 +#define SK_RECOVERED_ERROR 0x01 +#define SK_NOT_READY 0x02 +#define SK_MEDIUM_ERROR 0x03 +#define SK_HARDWARE_ERROR 0x04 +#define SK_ILLEGAL_REQUEST 0x05 +#define SK_UNIT_ATTENTION 0x06 +#define SK_DATA_PROTECT 0x07 +#define SK_BLANK_CHECK 0x08 +#define SK_VENDOR_SPECIFIC 0x09 +#define SK_COPY_ABORTED 0x0a +#define SK_ABORTED_COMMAND 0x0b +#define SK_EQUAL 0x0c +#define SK_VOLUME_OVERFLOW 0x0d +#define SK_MISCOMPARE 0x0e +#define SK_RESERVED 0x0f + + + +#define SCSI_MAX_INQUIRY_BYTES 96 +#define SCSI_STD_INQUIRY_BYTES 36 + +#undef USE_SCSI_COMPLETE_INQDATA +/* + * Structure definition for SCSI Inquiry Data + * + * NOTE: The following structure is 96 bytes in size + * iff USE_SCSI_COMPLETE_INQDATA IS defined above (i.e. w/ "#define"). + * If USE_SCSI_COMPLETE_INQDATA is NOT defined above (i.e. w/ "#undef") + * then the following structure is only 36 bytes in size. + * THE CHOICE IS YOURS! + */ +typedef struct SCSI_Inquiry_Data +{ +#ifdef USE_SCSI_COMPLETE_INQDATA + u8 InqByte[SCSI_MAX_INQUIRY_BYTES]; +#else + u8 InqByte[SCSI_STD_INQUIRY_BYTES]; +#endif + +/* + * the following structure works only for little-endian (Intel, + * LSB first (1234) byte order) systems with 4-byte ints. + * + u32 Periph_Device_Type : 5, + Periph_Qualifier : 3, + Device_Type_Modifier : 7, + Removable_Media : 1, + ANSI_Version : 3, + ECMA_Version : 3, + ISO_Version : 2, + Response_Data_Format : 4, + reserved_0 : 3, + AERC : 1 ; + u32 Additional_Length : 8, + reserved_1 :16, + SftReset : 1, + CmdQue : 1, + reserved_2 : 1, + Linked : 1, + Sync : 1, + WBus16 : 1, + WBus32 : 1, + RelAdr : 1 ; + u8 Vendor_ID[8]; + u8 Product_ID[16]; + u8 Revision_Level [4]; +#ifdef USE_SCSI_COMPLETE_INQDATA + u8 Vendor_Specific[20]; + u8 reserved_3[40]; +#endif + * + */ + +} SCSI_Inquiry_Data_t; + +#define INQ_PERIPHINFO_BYTE 0 +#define INQ_Periph_Qualifier_MASK 0xe0 +#define INQ_Periph_Device_Type_MASK 0x1f + +#define INQ_Peripheral_Qualifier(inqp) \ + (int)((*((u8*)(inqp)+INQ_PERIPHINFO_BYTE) & INQ_Periph_Qualifier_MASK) >> 5) +#define INQ_Peripheral_Device_Type(inqp) \ + (int)(*((u8*)(inqp)+INQ_PERIPHINFO_BYTE) & INQ_Periph_Device_Type_MASK) + + +#define INQ_DEVTYPEMOD_BYTE 1 +#define INQ_RMB_BIT 0x80 +#define INQ_Device_Type_Modifier_MASK 0x7f + +#define INQ_Removable_Medium(inqp) \ + (int)(*((u8*)(inqp)+INQ_DEVTYPEMOD_BYTE) & INQ_RMB_BIT) +#define INQ_Device_Type_Modifier(inqp) \ + (int)(*((u8*)(inqp)+INQ_DEVTYPEMOD_BYTE) & INQ_Device_Type_Modifier_MASK) + + +#define INQ_VERSIONINFO_BYTE 2 +#define INQ_ISO_Version_MASK 0xc0 +#define INQ_ECMA_Version_MASK 0x38 +#define INQ_ANSI_Version_MASK 0x07 + +#define INQ_ISO_Version(inqp) \ + (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ISO_Version_MASK) +#define INQ_ECMA_Version(inqp) \ + (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ECMA_Version_MASK) +#define INQ_ANSI_Version(inqp) \ + (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ANSI_Version_MASK) + + +#define INQ_BYTE3 3 +#define INQ_AERC_BIT 0x80 +#define INQ_TrmTsk_BIT 0x40 +#define INQ_NormACA_BIT 0x20 +#define INQ_RDF_MASK 0x0F + +#define INQ_AER_Capable(inqp) \ + (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_AERC_BIT) +#define INQ_TrmTsk(inqp) \ + (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_TrmTsk_BIT) +#define INQ_NormACA(inqp) \ + (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_NormACA_BIT) +#define INQ_Response_Data_Format(inqp) \ + (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_RDF_MASK) + + +#define INQ_CAPABILITY_BYTE 7 +#define INQ_RelAdr_BIT 0x80 +#define INQ_WBus32_BIT 0x40 +#define INQ_WBus16_BIT 0x20 +#define INQ_Sync_BIT 0x10 +#define INQ_Linked_BIT 0x08 + /* INQ_Reserved BIT 0x40 */ +#define INQ_CmdQue_BIT 0x02 +#define INQ_SftRe_BIT 0x01 + +#define IS_RelAdr_DEV(inqp) \ + (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_RelAdr_BIT) +#define IS_WBus32_DEV(inqp) \ + (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_WBus32_BIT) +#define IS_WBus16_DEV(inqp) \ + (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_WBus16_BIT) +#define IS_Sync_DEV(inqp) \ + (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Sync_BIT) +#define IS_Linked_DEV(inqp) \ + (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Linked_BIT) +#define IS_CmdQue_DEV(inqp) \ + (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_CmdQue_BIT) +#define IS_SftRe_DEV(inqp) \ + (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_SftRe_BIT) + +#define INQ_Width_BITS \ + (INQ_WBus32_BIT | INQ_WBus16_BIT) +#define IS_Wide_DEV(inqp) \ + (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Width_BITS) + + +/* + * SCSI peripheral device types + */ +#define SCSI_TYPE_DAD 0x00 /* Direct Access Device */ +#define SCSI_TYPE_SAD 0x01 /* Sequential Access Device */ +#define SCSI_TYPE_TAPE SCSI_TYPE_SAD +#define SCSI_TYPE_PRT 0x02 /* Printer */ +#define SCSI_TYPE_PROC 0x03 /* Processor */ +#define SCSI_TYPE_WORM 0x04 +#define SCSI_TYPE_CDROM 0x05 +#define SCSI_TYPE_SCAN 0x06 /* Scanner */ +#define SCSI_TYPE_OPTICAL 0x07 /* Magneto/Optical */ +#define SCSI_TYPE_CHANGER 0x08 +#define SCSI_TYPE_COMM 0x09 /* Communications device */ +#define SCSI_TYPE_UNKNOWN 0x1f +#define SCSI_TYPE_UNCONFIGURED_LUN 0x7f + +#define SCSI_TYPE_MAX_KNOWN SCSI_TYPE_COMM + +/* + * Peripheral Qualifiers + */ +#define DEVICE_PRESENT 0x00 +#define LUN_NOT_PRESENT 0x01 +#define LUN_NOT_SUPPORTED 0x03 + +/* + * ANSI Versions + */ +#ifndef SCSI_1 +#define SCSI_1 0x01 +#endif +#ifndef SCSI_2 +#define SCSI_2 0x02 +#endif +#ifndef SCSI_3 +#define SCSI_3 0x03 +#endif + + +#define SCSI_MAX_SENSE_BYTES 255 +#define SCSI_STD_SENSE_BYTES 18 +#define SCSI_PAD_SENSE_BYTES (SCSI_MAX_SENSE_BYTES - SCSI_STD_SENSE_BYTES) + +#undef USE_SCSI_COMPLETE_SENSE +/* + * Structure definition for SCSI Sense Data + * + * NOTE: The following structure is 255 bytes in size + * iiff USE_SCSI_COMPLETE_SENSE IS defined above (i.e. w/ "#define"). + * If USE_SCSI_COMPLETE_SENSE is NOT defined above (i.e. w/ "#undef") + * then the following structure is only 19 bytes in size. + * THE CHOICE IS YOURS! + * + */ +typedef struct SCSI_Sense_Data +{ +#ifdef USE_SCSI_COMPLETE_SENSE + u8 SenseByte[SCSI_MAX_SENSE_BYTES]; +#else + u8 SenseByte[SCSI_STD_SENSE_BYTES]; +#endif + +/* + * the following structure works only for little-endian (Intel, + * LSB first (1234) byte order) systems with 4-byte ints. + * + u8 Error_Code :4, // 0x00 + Error_Class :3, + Valid :1 + ; + u8 Segment_Number // 0x01 + ; + u8 Sense_Key :4, // 0x02 + Reserved :1, + Incorrect_Length_Indicator:1, + End_Of_Media :1, + Filemark :1 + ; + u8 Information_MSB; // 0x03 + u8 Information_Byte2; // 0x04 + u8 Information_Byte1; // 0x05 + u8 Information_LSB; // 0x06 + u8 Additional_Length; // 0x07 + + u32 Command_Specific_Information; // 0x08 - 0x0b + + u8 Additional_Sense_Code; // 0x0c + u8 Additional_Sense_Code_Qualifier; // 0x0d + u8 Field_Replaceable_Unit_Code; // 0x0e + u8 Illegal_Req_Bit_Pointer :3, // 0x0f + Illegal_Req_Bit_Valid :1, + Illegal_Req_Reserved :2, + Illegal_Req_Cmd_Data :1, + Sense_Key_Specific_Valid :1 + ; + u16 Sense_Key_Specific_Data; // 0x10 - 0x11 + +#ifdef USE_SCSI_COMPLETE_SENSE + u8 Additional_Sense_Data[SCSI_PAD_SENSE_BYTES]; +#else + u8 Additional_Sense_Data[1]; +#endif + * + */ + +} SCSI_Sense_Data_t; + + +#define SD_ERRCODE_BYTE 0 +#define SD_Valid_BIT 0x80 +#define SD_Error_Code_MASK 0x7f +#define SD_Valid(sdp) \ + (int)(*((u8*)(sdp)+SD_ERRCODE_BYTE) & SD_Valid_BIT) +#define SD_Error_Code(sdp) \ + (int)(*((u8*)(sdp)+SD_ERRCODE_BYTE) & SD_Error_Code_MASK) + + +#define SD_SEGNUM_BYTE 1 +#define SD_Segment_Number(sdp) (int)(*((u8*)(sdp)+SD_SEGNUM_BYTE)) + + +#define SD_SENSEKEY_BYTE 2 +#define SD_Filemark_BIT 0x80 +#define SD_EOM_BIT 0x40 +#define SD_ILI_BIT 0x20 +#define SD_Sense_Key_MASK 0x0f +#define SD_Filemark(sdp) \ + (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_Filemark_BIT) +#define SD_EOM(sdp) \ + (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_EOM_BIT) +#define SD_ILI(sdp) \ + (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_ILI_BIT) +#define SD_Sense_Key(sdp) \ + (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_Sense_Key_MASK) + + +#define SD_INFO3_BYTE 3 +#define SD_INFO2_BYTE 4 +#define SD_INFO1_BYTE 5 +#define SD_INFO0_BYTE 6 +#define SD_Information3(sdp) (int)(*((u8*)(sdp)+SD_INFO3_BYTE)) +#define SD_Information2(sdp) (int)(*((u8*)(sdp)+SD_INFO2_BYTE)) +#define SD_Information1(sdp) (int)(*((u8*)(sdp)+SD_INFO1_BYTE)) +#define SD_Information0(sdp) (int)(*((u8*)(sdp)+SD_INFO0_BYTE)) + + +#define SD_ADDL_LEN_BYTE 7 +#define SD_Additional_Sense_Length(sdp) \ + (int)(*((u8*)(sdp)+SD_ADDL_LEN_BYTE)) +#define SD_Addl_Sense_Len SD_Additional_Sense_Length + + +#define SD_CMD_SPECIFIC3_BYTE 8 +#define SD_CMD_SPECIFIC2_BYTE 9 +#define SD_CMD_SPECIFIC1_BYTE 10 +#define SD_CMD_SPECIFIC0_BYTE 11 +#define SD_Cmd_Specific_Info3(sdp) (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC3_BYTE)) +#define SD_Cmd_Specific_Info2(sdp) (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC2_BYTE)) +#define SD_Cmd_Specific_Info1(sdp) (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC1_BYTE)) +#define SD_Cmd_Specific_Info0(sdp) (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC0_BYTE)) + + +#define SD_ADDL_SENSE_CODE_BYTE 12 +#define SD_Additional_Sense_Code(sdp) \ + (int)(*((u8*)(sdp)+SD_ADDL_SENSE_CODE_BYTE)) +#define SD_Addl_Sense_Code SD_Additional_Sense_Code +#define SD_ASC SD_Additional_Sense_Code + + +#define SD_ADDL_SENSE_CODE_QUAL_BYTE 13 +#define SD_Additional_Sense_Code_Qualifier(sdp) \ + (int)(*((u8*)(sdp)+SD_ADDL_SENSE_CODE_QUAL_BYTE)) +#define SD_Addl_Sense_Code_Qual SD_Additional_Sense_Code_Qualifier +#define SD_ASCQ SD_Additional_Sense_Code_Qualifier + + +#define SD_FIELD_REPL_UNIT_CODE_BYTE 14 +#define SD_Field_Replaceable_Unit_Code(sdp) \ + (int)(*((u8*)(sdp)+SD_FIELD_REPL_UNIT_CODE_BYTE)) +#define SD_Field_Repl_Unit_Code SD_Field_Replaceable_Unit_Code +#define SD_FRUC SD_Field_Replaceable_Unit_Code +#define SD_FRU SD_Field_Replaceable_Unit_Code + + +/* + * Sense-Key Specific offsets and macros. + */ +#define SD_SKS2_BYTE 15 +#define SD_SKS_Valid_BIT 0x80 +#define SD_SKS_Cmd_Data_BIT 0x40 +#define SD_SKS_Bit_Ptr_Valid_BIT 0x08 +#define SD_SKS_Bit_Ptr_MASK 0x07 +#define SD_SKS1_BYTE 16 +#define SD_SKS0_BYTE 17 +#define SD_Sense_Key_Specific_Valid(sdp) \ + (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Valid_BIT) +#define SD_SKS_Valid SD_Sense_Key_Specific_Valid +#define SD_SKS_CDB_Error(sdp) \ + (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Cmd_Data_BIT) +#define SD_Was_Illegal_Request SD_SKS_CDB_Error +#define SD_SKS_Bit_Pointer_Valid(sdp) \ + (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Bit_Ptr_Valid_BIT) +#define SD_SKS_Bit_Pointer(sdp) \ + (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Bit_Ptr_MASK) +#define SD_Field_Pointer(sdp) \ + (int)( ((u16)(*((u8*)(sdp)+SD_SKS1_BYTE)) << 8) \ + + *((u8*)(sdp)+SD_SKS0_BYTE) ) +#define SD_Bad_Byte SD_Field_Pointer +#define SD_Actual_Retry_Count SD_Field_Pointer +#define SD_Progress_Indication SD_Field_Pointer + +/* + * Mode Sense Write Protect Mask + */ +#define WRITE_PROTECT_MASK 0X80 + +/* + * Medium Type Codes + */ +#define OPTICAL_DEFAULT 0x00 +#define OPTICAL_READ_ONLY_MEDIUM 0x01 +#define OPTICAL_WRITE_ONCE_MEDIUM 0x02 +#define OPTICAL_READ_WRITABLE_MEDIUM 0x03 +#define OPTICAL_RO_OR_WO_MEDIUM 0x04 +#define OPTICAL_RO_OR_RW_MEDIUM 0x05 +#define OPTICAL_WO_OR_RW_MEDIUM 0x06 + + + +/* + * Structure definition for READ6, WRITE6 (6-byte CDB) + */ +typedef struct SCSI_RW6_CDB +{ + u32 OpCode :8, + LBA_HI :5, /* 5 MSBit's of the LBA */ + Lun :3, + LBA_MID :8, /* NOTE: total of 21 bits in LBA */ + LBA_LO :8 ; /* Max LBA = 0x001fffff */ + u8 BlockCount; + u8 Control; +} SCSI_RW6_t; + +#define MAX_RW6_LBA ((u32)0x001fffff) + +/* + * Structure definition for READ10, WRITE10 (10-byte CDB) + * + * NOTE: ParityCheck bit is applicable only for VERIFY and WRITE VERIFY for + * the ADP-92 DAC only. In the SCSI2 spec. this same bit is defined as a + * FUA (forced unit access) bit for READs and WRITEs. Since this driver + * does not use the FUA, this bit is defined as it is used by the ADP-92. + * Also, for READ CAPACITY, only the OpCode field is used. + */ +typedef struct SCSI_RW10_CDB +{ + u8 OpCode; + u8 Reserved1; + u32 LBA; + u8 Reserved2; + u16 BlockCount; + u8 Control; +} SCSI_RW10_t; + +#define PARITY_CHECK 0x08 /* parity check bit - byte[1], bit 3 */ + + /* + * Structure definition for data returned by READ CAPACITY cmd; + * READ CAPACITY data + */ + typedef struct READ_CAP_DATA + { + u32 MaxLBA; + u32 BlockBytes; + } SCSI_READ_CAP_DATA_t, *pSCSI_READ_CAP_DATA_t; + + +/* + * Structure definition for FORMAT UNIT CDB (6-byte CDB) + */ +typedef struct _SCSI_FORMAT_UNIT +{ + u8 OpCode; + u8 Reserved1; + u8 VendorSpecific; + u16 Interleave; + u8 Control; +} SCSI_FORMAT_UNIT_t; + +/* + * Structure definition for REQUEST SENSE (6-byte CDB) + */ +typedef struct _SCSI_REQUEST_SENSE +{ + u8 OpCode; + u8 Reserved1; + u8 Reserved2; + u8 Reserved3; + u8 AllocLength; + u8 Control; +} SCSI_REQ_SENSE_t; + +/* + * Structure definition for REPORT LUNS (12-byte CDB) + */ +typedef struct _SCSI_REPORT_LUNS +{ + u8 OpCode; + u8 Reserved1[5]; + u32 AllocationLength; + u8 Reserved2; + u8 Control; +} SCSI_REPORT_LUNS_t, *pSCSI_REPORT_LUNS_t; + + /* + * (per-level) LUN information bytes + */ +/* + * Following doesn't work on ARMCC compiler + * [apparently] because it pads every struct + * to be multiple of 4 bytes! + * So SCSI_LUN_LEVELS_t winds up being 16 + * bytes instead of 8! + * + typedef struct LUN_INFO + { + u8 AddrMethod_plus_LunOrBusNumber; + u8 LunOrTarget; + } SCSI_LUN_INFO_t, *pSCSI_LUN_INFO_t; + + typedef struct LUN_LEVELS + { + SCSI_LUN_INFO_t LUN_0; + SCSI_LUN_INFO_t LUN_1; + SCSI_LUN_INFO_t LUN_2; + SCSI_LUN_INFO_t LUN_3; + } SCSI_LUN_LEVELS_t, *pSCSI_LUN_LEVELS_t; +*/ + /* + * All 4 levels (8 bytes) of LUN information + */ + typedef struct LUN_LEVELS + { + u8 LVL1_AddrMethod_plus_LunOrBusNumber; + u8 LVL1_LunOrTarget; + u8 LVL2_AddrMethod_plus_LunOrBusNumber; + u8 LVL2_LunOrTarget; + u8 LVL3_AddrMethod_plus_LunOrBusNumber; + u8 LVL3_LunOrTarget; + u8 LVL4_AddrMethod_plus_LunOrBusNumber; + u8 LVL4_LunOrTarget; + } SCSI_LUN_LEVELS_t, *pSCSI_LUN_LEVELS_t; + + /* + * Structure definition for data returned by REPORT LUNS cmd; + * LUN reporting parameter list format + */ + typedef struct LUN_REPORT + { + u32 LunListLength; + u32 Reserved; + SCSI_LUN_LEVELS_t LunInfo[1]; + } SCSI_LUN_REPORT_t, *pSCSI_LUN_REPORT_t; + +/**************************************************************************** + * + * Externals + */ + +/**************************************************************************** + * + * Public Typedefs & Related Defines + */ + +/**************************************************************************** + * + * Macros (embedded, above) + */ + +/**************************************************************************** + * + * Public Variables + */ + +/**************************************************************************** + * + * Public Prototypes (module entry points) + */ + + +/***************************************************************************/ +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/scsiops.c linux.ac/drivers/message/fusion/scsiops.c --- linux.vanilla/drivers/message/fusion/scsiops.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/scsiops.c Tue Apr 3 17:54:47 2001 @@ -0,0 +1,309 @@ + +static const char *ScsiOpcodeString[256] = { + "TEST UNIT READY\0\01", /* 00h */ + "REWIND\0\002" + "\001REZERO UNIT", /* 01h */ + "\0\0", /* 02h */ + "REQUEST SENSE\0\01", /* 03h */ + "FORMAT UNIT\0\03" + "\001FORMAT MEDIUM\0" + "\002FORMAT", /* 04h */ + "READ BLOCK LIMITS\0\1", /* 05h */ + "\0\0", /* 06h */ + "REASSIGN BLOCKS\0\02" + "\010INITIALIZE ELEMENT STATUS", /* 07h */ + "READ(06)\0\04" + "\001READ\0" + "\003RECEIVE\0" + "\011GET MESSAGE(06)", /* 08h */ + "\0\0", /* 09h */ + "WRITE(06)\0\05" + "\001WRITE\0" + "\002PRINT\0" + "\003SEND(6)\0" + "\011SEND MESSAGE(06)", /* 0Ah */ + "SEEK(06)\0\02" + "\003SLEW AND PRINT", /* 0Bh */ + "\0\0", /* 0Ch */ + "\0\0", /* 0Dh */ + "\0\0", /* 0Eh */ + "READ REVERSE\0\01", /* 0Fh */ + "WRITE FILEMARKS\0\02" + "\003SYNCRONIZE BUFFER", /* 10h */ + "SPACE(6)\0\01", /* 11h */ + "INQUIRY\0\01", /* 12h */ + "VERIFY\0\01", /* 13h */ + "RECOVER BUFFERED DATA\0\01", /* 14h */ + "MODE SELECT(06)\0\01", /* 15h */ + "RESERVE(06)\0\02" + "\010RESERVE ELEMENT(06)", /* 16h */ + "RELEASE(06)\0\02" + "\010RELEASE ELEMENT(06)", /* 17h */ + "COPY\0\01", /* 18h */ + "ERASE\0\01", /* 19h */ + "MODE SENSE(06)\0\01", /* 1Ah */ + "STOP START UNIT\0\04" + "\001LOAD UNLOAD\0" + "\002STOP PRINT\0" + "\006SCAN\0\002", /* 1Bh */ + "RECEIVE DIAGNOSTIC RESULTS\0\01", /* 1Ch */ + "SEND DIAGNOSTIC\0\01", /* 1Dh */ + "PREVENT ALLOW MEDIUM REMOVAL\0\01", /* 1Eh */ + "\0\0", /* 1Fh */ + "\0\0", /* 20h */ + "\0\0", /* 21h */ + "\0\0", /* 22h */ + "READ FORMAT CAPACITIES\0\01", /* 23h */ + "SET WINDOW\0\01", /* 24h */ + "READ CAPACITY\0\03" + "\006GET WINDOW\0" + "\037FREAD CARD CAPACITY", /* 25h */ + "\0\0", /* 26h */ + "\0\0", /* 27h */ + "READ(10)\0\02" + "\011GET MESSAGE(10)", /* 28h */ + "READ GENERATION\0\01", /* 29h */ + "WRITE(10)\0\03" + "\011SEND(10)\0" + "\011SEND MESSAGE(10)", /* 2Ah */ + "SEEK(10)\0\03" + "LOCATE(10)\0" + "POSITION TO ELEMENT", /* 2Bh */ + "ERASE(10)\0\01", /* 2Ch */ + "READ UPDATED BLOCK\0\01", /* 2Dh */ + "WRITE AND VERIFY(10)\0\01", /* 2Eh */ + "VERIFY(10)\0\01", /* 2Fh */ + "SEARCH DATA HIGH(10)\0\01", /* 30h */ + "SEARCH DATA EQUAL(10)\0\02" + "OBJECT POSITION", /* 31h */ + "SEARCH DATA LOW(10)\0\01", /* 32h */ + "SET LIMITS(10)\0\01", /* 33h */ + "PRE-FETCH(10)\0\03" + "READ POSITION\0" + "GET DATA BUFFER STATUS", /* 34h */ + "SYNCHRONIZE CACHE(10)\0\01", /* 35h */ + "LOCK UNLOCK CACHE(10)\0\01", /* 36h */ + "READ DEFECT DATA(10)\0\01", /* 37h */ + "MEDIUM SCAN\0\01", /* 38h */ + "COMPARE\0\01", /* 39h */ + "COPY AND VERIFY\0\01", /* 3Ah */ + "WRITE BUFFER\0\01", /* 3Bh */ + "READ BUFFER\0\01", /* 3Ch */ + "UPDATE BLOCK\0\01", /* 3Dh */ + "READ LONG\0\01", /* 3Eh */ + "WRITE LONG\0\01", /* 3Fh */ + "CHANGE DEFINITION\0\01", /* 40h */ + "WRITE SAME(10)\0\01", /* 41h */ + "READ SUB-CHANNEL\0\01", /* 42h */ + "READ TOC/PMA/ATIP\0\01", /* 43h */ + "REPORT DENSITY SUPPORT\0\01", /* 44h */ + "READ HEADER\0\01", /* 44h */ + "PLAY AUDIO(10)\0\01", /* 45h */ + "GET CONFIGURATION\0\01", /* 46h */ + "PLAY AUDIO MSF\0\01", /* 47h */ + "PLAY AUDIO TRACK INDEX\0\01", /* 48h */ + "PLAY TRACK RELATIVE(10)\0\01", /* 49h */ + "GET EVENT STATUS NOTIFICATION\0\01", /* 4Ah */ + "PAUSE/RESUME\0\01", /* 4Bh */ + "LOG SELECT\0\01", /* 4Ch */ + "LOG SENSE\0\01", /* 4Dh */ + "STOP PLAY/SCAN\0\01", /* 4Eh */ + "\0\0", /* 4Fh */ + "XDWRITE(10)\0\01", /* 50h */ + "XPWRITE(10)\0\02" + "READ DISC INFORMATION", /* 51h */ + "XDREAD(10)\0\01" + "READ TRACK INFORMATION", /* 52h */ + "RESERVE TRACK\0\01", /* 53h */ + "SEND OPC INFORMATION\0\01", /* 54h */ + "MODE SELECT(10)\0\01", /* 55h */ + "RESERVE(10)\0\02" + "RESERVE ELEMENT(10)", /* 56h */ + "RELEASE(10)\0\02" + "RELEASE ELEMENT(10)", /* 57h */ + "REPAIR TRACK\0\01", /* 58h */ + "READ MASTER CUE\0\01", /* 59h */ + "MODE SENSE(10)\0\01", /* 5Ah */ + "CLOSE TRACK/SESSION\0\01", /* 5Bh */ + "READ BUFFER CAPACITY\0\01", /* 5Ch */ + "SEND CUE SHEET\0\01", /* 5Dh */ + "PERSISTENT RESERVE IN\0\01", /* 5Eh */ + "PERSISTENT RESERVE OUT\0\01", /* 5Fh */ + "\0\0", /* 60h */ + "\0\0", /* 61h */ + "\0\0", /* 62h */ + "\0\0", /* 63h */ + "\0\0", /* 64h */ + "\0\0", /* 65h */ + "\0\0", /* 66h */ + "\0\0", /* 67h */ + "\0\0", /* 68h */ + "\0\0", /* 69h */ + "\0\0", /* 6Ah */ + "\0\0", /* 6Bh */ + "\0\0", /* 6Ch */ + "\0\0", /* 6Dh */ + "\0\0", /* 6Eh */ + "\0\0", /* 6Fh */ + "\0\0", /* 70h */ + "\0\0", /* 71h */ + "\0\0", /* 72h */ + "\0\0", /* 73h */ + "\0\0", /* 74h */ + "\0\0", /* 75h */ + "\0\0", /* 76h */ + "\0\0", /* 77h */ + "\0\0", /* 78h */ + "\0\0", /* 79h */ + "\0\0", /* 7Ah */ + "\0\0", /* 7Bh */ + "\0\0", /* 7Ch */ + "\0\0", /* 7Eh */ + "\0\0", /* 7Eh */ + "\0\0", /* 7Fh */ + "XDWRITE EXTENDED(16)\0\01", /* 80h */ + "REBUILD(16)\0\01", /* 81h */ + "REGENERATE(16)\0\01", /* 82h */ + "EXTENDED COPY\0\01", /* 83h */ + "RECEIVE COPY RESULTS\0\01", /* 84h */ + "ACCESS CONTROL IN [proposed]\0\01", /* 86h */ + "ACCESS CONTROL OUT [proposed]\0\01", /* 87h */ + "READ(16)\0\01", /* 88h */ + "DEVICE LOCKS [proposed]\0\01", /* 89h */ + "WRITE(16)\0\01", /* 8Ah */ + "\0\0", /* 8Bh */ + "READ ATTRIBUTES [proposed]\0\01", /* 8Ch */ + "WRITE ATTRIBUTES [proposed]\0\01", /* 8Dh */ + "WRITE AND VERIFY(16)\0\01", /* 8Eh */ + "VERIFY(16)\0\01", /* 8Fh */ + "PRE-FETCH(16)\0\01", /* 90h */ + "SYNCHRONIZE CACHE(16)\0\02" + "SPACE(16) [1]", /* 91h */ + "LOCK UNLOCK CACHE(16)\0\02" + "LOCATE(16) [1]", /* 92h */ + "WRITE SAME(16)\0\01", /* 93h */ + "[usage proposed by SCSI Socket Services project]\0\01", /* 94h */ + "[usage proposed by SCSI Socket Services project]\0\01", /* 95h */ + "[usage proposed by SCSI Socket Services project]\0\01", /* 96h */ + "[usage proposed by SCSI Socket Services project]\0\01", /* 97h */ + "MARGIN CONTROL [proposed]\0\01", /* 98h */ + "\0\0", /* 99h */ + "\0\0", /* 9Ah */ + "\0\0", /* 9Bh */ + "\0\0", /* 9Ch */ + "\0\0", /* 9Dh */ + "SERVICE ACTION IN [proposed]\0\01", /* 9Eh */ + "SERVICE ACTION OUT [proposed]\0\01", /* 9Fh */ + "REPORT LUNS\0\01", /* A0h */ + "BLANK\0\01", /* A1h */ + "SEND EVENT\0\01", /* A2h */ + "MAINTENANCE (IN)\0\02" + "SEND KEY", /* A3h */ + "MAINTENANCE (OUT)\0\02" + "REPORT KEY", /* A4h */ + "MOVE MEDIUM\0\02" + "PLAY AUDIO(12)", /* A5h */ + "EXCHANGE MEDIUM\0\02" + "LOAD/UNLOAD C/DVD", /* A6h */ + "MOVE MEDIUM ATTACHED\0\02" + "SET READ AHEAD\0\01", /* A7h */ + "READ(12)\0\02" + "GET MESSAGE(12)", /* A8h */ + "PLAY TRACK RELATIVE(12)\0\01", /* A9h */ + "WRITE(12)\0\02" + "SEND MESSAGE(12)", /* AAh */ + "\0\0", /* ABh */ + "ERASE(12)\0\02" + "GET PERFORMANCE", /* ACh */ + "READ DVD STRUCTURE\0\01", /* ADh */ + "WRITE AND VERIFY(12)\0\01", /* AEh */ + "VERIFY(12)\0\01", /* AFh */ + "SEARCH DATA HIGH(12)\0\01", /* B0h */ + "SEARCH DATA EQUAL(12)\0\01", /* B1h */ + "SEARCH DATA LOW(12)\0\01", /* B2h */ + "SET LIMITS(12)\0\01", /* B3h */ + "READ ELEMENT STATUS ATTACHED\0\01", /* B4h */ + "REQUEST VOLUME ELEMENT ADDRESS\0\01", /* B5h */ + "SEND VOLUME TAG\0\02" + "SET STREAMING", /* B6h */ + "READ DEFECT DATA(12)\0\01", /* B7h */ + "READ ELEMENT STATUS\0\01", /* B8h */ + "READ CD MSF\0\01", /* B9h */ + "REDUNDANCY GROUP (IN)\0\02" + "SCAN", /* BAh */ + "REDUNDANCY GROUP (OUT)\0\02" + "SET CD-ROM SPEED", /* BBh */ + "SPARE (IN)\0\02" + "PLAY CD", /* BCh */ + "SPARE (OUT)\0\02" + "MECHANISM STATUS", /* BDh */ + "VOLUME SET (IN)\0\02" + "READ CD", /* BEh */ + "VOLUME SET (OUT)\0\0\02" + "SEND DVD STRUCTURE", /* BFh */ + "\0\0", /* C0h */ + "\0\0", /* C1h */ + "\0\0", /* C2h */ + "\0\0", /* C3h */ + "\0\0", /* C4h */ + "\0\0", /* C5h */ + "\0\0", /* C6h */ + "\0\0", /* C7h */ + "\0\0", /* C8h */ + "\0\0", /* C9h */ + "\0\0", /* CAh */ + "\0\0", /* CBh */ + "\0\0", /* CCh */ + "\0\0", /* CDh */ + "\0\0", /* CEh */ + "\0\0", /* CFh */ + "\0\0", /* D0h */ + "\0\0", /* D1h */ + "\0\0", /* D2h */ + "\0\0", /* D3h */ + "\0\0", /* D4h */ + "\0\0", /* D5h */ + "\0\0", /* D6h */ + "\0\0", /* D7h */ + "\0\0", /* D8h */ + "\0\0", /* D9h */ + "\0\0", /* DAh */ + "\0\0", /* DBh */ + "\0\0", /* DCh */ + "\0\0", /* DEh */ + "\0\0", /* DEh */ + "\0\0", /* DFh */ + "\0\0", /* E0h */ + "\0\0", /* E1h */ + "\0\0", /* E2h */ + "\0\0", /* E3h */ + "\0\0", /* E4h */ + "\0\0", /* E5h */ + "\0\0", /* E6h */ + "\0\0", /* E7h */ + "\0\0", /* E8h */ + "\0\0", /* E9h */ + "\0\0", /* EAh */ + "\0\0", /* EBh */ + "\0\0", /* ECh */ + "\0\0", /* EDh */ + "\0\0", /* EEh */ + "\0\0", /* EFh */ + "\0\0", /* F0h */ + "\0\0", /* F1h */ + "\0\0", /* F2h */ + "\0\0", /* F3h */ + "\0\0", /* F4h */ + "\0\0", /* F5h */ + "\0\0", /* F6h */ + "\0\0", /* F7h */ + "\0\0", /* F8h */ + "\0\0", /* F9h */ + "\0\0", /* FAh */ + "\0\0", /* FBh */ + "\0\0", /* FEh */ + "\0\0", /* FEh */ + "\0\0", /* FEh */ + "\0\0" /* FFh */ +}; + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/t10.org/asc-num.txt linux.ac/drivers/message/fusion/t10.org/asc-num.txt --- linux.vanilla/drivers/message/fusion/t10.org/asc-num.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/t10.org/asc-num.txt Tue Apr 3 17:54:47 2001 @@ -0,0 +1,505 @@ +File: ASC-NUM.TXT + +SCSI ASC/ASCQ Assignments +Numeric Sorted Listing +as of 5/18/00 + + D - DIRECT ACCESS DEVICE (SBC-2) device column key + .T - SEQUENTIAL ACCESS DEVICE (SSC) ------------------- + . L - PRINTER DEVICE (SSC) blank = reserved + . P - PROCESSOR DEVICE (SPC) not blank = allowed + . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC-2) + . . R - CD DEVICE (MMC) + . . S - SCANNER DEVICE (SCSI-2) + . . .O - OPTICAL MEMORY DEVICE (SBC-2) + . . . M - MEDIA CHANGER DEVICE (SMC) + . . . C - COMMUNICATION DEVICE (SCSI-2) + . . . .A - STORAGE ARRAY DEVICE (SCC) + . . . . E - ENCLOSURE SERVICES DEVICE (SES) + . . . . B - SIMPLIFIED DIRECT-ACCESS DEVICE (RBC) + . . . . .K - OPTICAL CARD READER/WRITER DEVICE (OCRW) +ASC/ASCQ DTLPWRSOMCAEBK Description +------- -------------- ---------------------------------------------------- +00h/00h DTLPWRSOMCAEBK NO ADDITIONAL SENSE INFORMATION +00h/01h T FILEMARK DETECTED +00h/02h T S END-OF-PARTITION/MEDIUM DETECTED +00h/03h T SETMARK DETECTED +00h/04h T S BEGINNING-OF-PARTITION/MEDIUM DETECTED +00h/05h TL S END-OF-DATA DETECTED +00h/06h DTLPWRSOMCAEBK I/O PROCESS TERMINATED +00h/11h R AUDIO PLAY OPERATION IN PROGRESS +00h/12h R AUDIO PLAY OPERATION PAUSED +00h/13h R AUDIO PLAY OPERATION SUCCESSFULLY COMPLETED +00h/14h R AUDIO PLAY OPERATION STOPPED DUE TO ERROR +00h/15h R NO CURRENT AUDIO STATUS TO RETURN +00h/16h DTLPWRSOMCAEBK OPERATION IN PROGRESS +00h/17h DTL WRSOM AEBK CLEANING REQUESTED +01h/00h D W O BK NO INDEX/SECTOR SIGNAL +02h/00h D WR OM BK NO SEEK COMPLETE +03h/00h DTL W SO BK PERIPHERAL DEVICE WRITE FAULT +03h/01h T NO WRITE CURRENT +03h/02h T EXCESSIVE WRITE ERRORS +04h/00h DTLPWRSOMCAEBK LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE +04h/01h DTLPWRSOMCAEBK LOGICAL UNIT IS IN PROCESS OF BECOMING READY +04h/02h DTLPWRSOMCAEBK LOGICAL UNIT NOT READY, INITIALIZING CMD. REQUIRED +04h/03h DTLPWRSOMCAEBK LOGICAL UNIT NOT READY, MANUAL INTERVENTION REQUIRED +04h/04h DTL R O B LOGICAL UNIT NOT READY, FORMAT IN PROGRESS +04h/05h DT W OMCA BK LOGICAL UNIT NOT READY, REBUILD IN PROGRESS +04h/06h DT W OMCA BK LOGICAL UNIT NOT READY, RECALCULATION IN PROGRESS +04h/07h DTLPWRSOMCAEBK LOGICAL UNIT NOT READY, OPERATION IN PROGRESS +04h/08h R LOGICAL UNIT NOT READY, LONG WRITE IN PROGRESS +04h/09h DTLPWRSOMCAEBK LOGICAL UNIT NOT READY, SELF-TEST IN PROGRESS +04h/10h auxiliary memory code 2 (99-148) [proposed] +05h/00h DTL WRSOMCAEBK LOGICAL UNIT DOES NOT RESPOND TO SELECTION +06h/00h D WR OM BK NO REFERENCE POSITION FOUND +07h/00h DTL WRSOM BK MULTIPLE PERIPHERAL DEVICES SELECTED +08h/00h DTL WRSOMCAEBK LOGICAL UNIT COMMUNICATION FAILURE +08h/01h DTL WRSOMCAEBK LOGICAL UNIT COMMUNICATION TIME-OUT +08h/02h DTL WRSOMCAEBK LOGICAL UNIT COMMUNICATION PARITY ERROR +08h/03h DT R OM BK LOGICAL UNIT COMMUNICATION CRC ERROR (ULTRA-DMA/32) +08h/04h DTLPWRSO C K UNREACHABLE COPY TARGET +09h/00h DT WR O B TRACK FOLLOWING ERROR +09h/01h WR O K TRACKING SERVO FAILURE +09h/02h WR O K FOCUS SERVO FAILURE +09h/03h WR O SPINDLE SERVO FAILURE +09h/04h DT WR O B HEAD SELECT FAULT +0Ah/00h DTLPWRSOMCAEBK ERROR LOG OVERFLOW +0Bh/00h DTLPWRSOMCAEBK WARNING +0Bh/01h DTLPWRSOMCAEBK WARNING - SPECIFIED TEMPERATURE EXCEEDED +0Bh/02h DTLPWRSOMCAEBK WARNING - ENCLOSURE DEGRADED +0Ch/00h T RS WRITE ERROR +0Ch/01h K WRITE ERROR - RECOVERED WITH AUTO REALLOCATION +0Ch/02h D W O BK WRITE ERROR - AUTO REALLOCATION FAILED +0Ch/03h D W O BK WRITE ERROR - RECOMMEND REASSIGNMENT +0Ch/04h DT W O B COMPRESSION CHECK MISCOMPARE ERROR +0Ch/05h DT W O B DATA EXPANSION OCCURRED DURING COMPRESSION +0Ch/06h DT W O B BLOCK NOT COMPRESSIBLE +0Ch/07h R WRITE ERROR - RECOVERY NEEDED +0Ch/08h R WRITE ERROR - RECOVERY FAILED +0Ch/09h R WRITE ERROR - LOSS OF STREAMING +0Ch/0Ah R WRITE ERROR - PADDING BLOCKS ADDED +0Ch/0Bh auxiliary memory code 4 (99-148) [proposed] +0Dh/00h +0Eh/00h +0Fh/00h +10h/00h D W O BK ID CRC OR ECC ERROR +11h/00h DT WRSO BK UNRECOVERED READ ERROR +11h/01h DT WRSO BK READ RETRIES EXHAUSTED +11h/02h DT WRSO BK ERROR TOO LONG TO CORRECT +11h/03h DT W SO BK MULTIPLE READ ERRORS +11h/04h D W O BK UNRECOVERED READ ERROR - AUTO REALLOCATE FAILED +11h/05h WR O B L-EC UNCORRECTABLE ERROR +11h/06h WR O B CIRC UNRECOVERED ERROR +11h/07h W O B DATA RE-SYNCHRONIZATION ERROR +11h/08h T INCOMPLETE BLOCK READ +11h/09h T NO GAP FOUND +11h/0Ah DT O BK MISCORRECTED ERROR +11h/0Bh D W O BK UNRECOVERED READ ERROR - RECOMMEND REASSIGNMENT +11h/0Ch D W O BK UNRECOVERED READ ERROR - RECOMMEND REWRITE THE DATA +11h/0Dh DT WR O B DE-COMPRESSION CRC ERROR +11h/0Eh DT WR O B CANNOT DECOMPRESS USING DECLARED ALGORITHM +11h/0Fh R ERROR READING UPC/EAN NUMBER +11h/10h R ERROR READING ISRC NUMBER +11h/11h R READ ERROR - LOSS OF STREAMING +11h/12h auxiliary memory code 3 (99-148) [proposed] +12h/00h D W O BK ADDRESS MARK NOT FOUND FOR ID FIELD +13h/00h D W O BK ADDRESS MARK NOT FOUND FOR DATA FIELD +14h/00h DTL WRSO BK RECORDED ENTITY NOT FOUND +14h/01h DT WR O BK RECORD NOT FOUND +14h/02h T FILEMARK OR SETMARK NOT FOUND +14h/03h T END-OF-DATA NOT FOUND +14h/04h T BLOCK SEQUENCE ERROR +14h/05h DT W O BK RECORD NOT FOUND - RECOMMEND REASSIGNMENT +14h/06h DT W O BK RECORD NOT FOUND - DATA AUTO-REALLOCATED +15h/00h DTL WRSOM BK RANDOM POSITIONING ERROR +15h/01h DTL WRSOM BK MECHANICAL POSITIONING ERROR +15h/02h DT WR O BK POSITIONING ERROR DETECTED BY READ OF MEDIUM +16h/00h D W O BK DATA SYNCHRONIZATION MARK ERROR +16h/01h D W O BK DATA SYNC ERROR - DATA REWRITTEN +16h/02h D W O BK DATA SYNC ERROR - RECOMMEND REWRITE +16h/03h D W O BK DATA SYNC ERROR - DATA AUTO-REALLOCATED +16h/04h D W O BK DATA SYNC ERROR - RECOMMEND REASSIGNMENT +17h/00h DT WRSO BK RECOVERED DATA WITH NO ERROR CORRECTION APPLIED +17h/01h DT WRSO BK RECOVERED DATA WITH RETRIES +17h/02h DT WR O BK RECOVERED DATA WITH POSITIVE HEAD OFFSET +17h/03h DT WR O BK RECOVERED DATA WITH NEGATIVE HEAD OFFSET +17h/04h WR O B RECOVERED DATA WITH RETRIES AND/OR CIRC APPLIED +17h/05h D WR O BK RECOVERED DATA USING PREVIOUS SECTOR ID +17h/06h D W O BK RECOVERED DATA WITHOUT ECC - DATA AUTO-REALLOCATED +17h/07h D WR O BK RECOVERED DATA WITHOUT ECC - RECOMMEND REASSIGNMENT +17h/08h D WR O BK RECOVERED DATA WITHOUT ECC - RECOMMEND REWRITE +17h/09h D WR O BK RECOVERED DATA WITHOUT ECC - DATA REWRITTEN +18h/00h DT WR O BK RECOVERED DATA WITH ERROR CORRECTION APPLIED +18h/01h D WR O BK RECOVERED DATA WITH ERROR CORR. & RETRIES APPLIED +18h/02h D WR O BK RECOVERED DATA - DATA AUTO-REALLOCATED +18h/03h R RECOVERED DATA WITH CIRC +18h/04h R RECOVERED DATA WITH L-EC +18h/05h D WR O BK RECOVERED DATA - RECOMMEND REASSIGNMENT +18h/06h D WR O BK RECOVERED DATA - RECOMMEND REWRITE +18h/07h D W O BK RECOVERED DATA WITH ECC - DATA REWRITTEN +19h/00h D O K DEFECT LIST ERROR +19h/01h D O K DEFECT LIST NOT AVAILABLE +19h/02h D O K DEFECT LIST ERROR IN PRIMARY LIST +19h/03h D O K DEFECT LIST ERROR IN GROWN LIST +1Ah/00h DTLPWRSOMCAEBK PARAMETER LIST LENGTH ERROR +1Bh/00h DTLPWRSOMCAEBK SYNCHRONOUS DATA TRANSFER ERROR +1Ch/00h D O BK DEFECT LIST NOT FOUND +1Ch/01h D O BK PRIMARY DEFECT LIST NOT FOUND +1Ch/02h D O BK GROWN DEFECT LIST NOT FOUND +1Dh/00h DT WR O BK MISCOMPARE DURING VERIFY OPERATION +1Eh/00h D W O BK RECOVERED ID WITH ECC CORRECTION +1Fh/00h D O K PARTIAL DEFECT LIST TRANSFER +20h/00h DTLPWRSOMCAEBK INVALID COMMAND OPERATION CODE +20h/01h access controls code 1 (99-314) [proposed] +20h/02h access controls code 2 (99-314) [proposed] +20h/03h access controls code 3 (99-314) [proposed] +21h/00h DT WR OM BK LOGICAL BLOCK ADDRESS OUT OF RANGE +21h/01h DT WR OM BK INVALID ELEMENT ADDRESS +22h/00h D ILLEGAL FUNCTION (USE 20 00, 24 00, OR 26 00) +23h/00h +24h/00h DTLPWRSOMCAEBK INVALID FIELD IN CDB +24h/01h DTLPWRSOMCAEBK CDB DECRYPTION ERROR +25h/00h DTLPWRSOMCAEBK LOGICAL UNIT NOT SUPPORTED +26h/00h DTLPWRSOMCAEBK INVALID FIELD IN PARAMETER LIST +26h/01h DTLPWRSOMCAEBK PARAMETER NOT SUPPORTED +26h/02h DTLPWRSOMCAEBK PARAMETER VALUE INVALID +26h/03h DTLPWRSOMCAE K THRESHOLD PARAMETERS NOT SUPPORTED +26h/04h DTLPWRSOMCAEBK INVALID RELEASE OF PERSISTENT RESERVATION +26h/05h DTLPWRSOMCA BK DATA DECRYPTION ERROR +26h/06h DTLPWRSO C K TOO MANY TARGET DESCRIPTORS +26h/07h DTLPWRSO C K UNSUPPORTED TARGET DESCRIPTOR TYPE CODE +26h/08h DTLPWRSO C K TOO MANY SEGMENT DESCRIPTORS +26h/09h DTLPWRSO C K UNSUPPORTED SEGMENT DESCRIPTOR TYPE CODE +26h/0Ah DTLPWRSO C K UNEXPECTED INEXACT SEGMENT +26h/0Bh DTLPWRSO C K INLINE DATA LENGTH EXCEEDED +26h/0Ch DTLPWRSO C K INVALID OPERATION FOR COPY SOURCE OR DESTINATION +26h/0Dh DTLPWRSO C K COPY SEGMENT GRANULARITY VIOLATION +27h/00h DT WR O BK WRITE PROTECTED +27h/01h DT WR O BK HARDWARE WRITE PROTECTED +27h/02h DT WR O BK LOGICAL UNIT SOFTWARE WRITE PROTECTED +27h/03h T R ASSOCIATED WRITE PROTECT +27h/04h T R PERSISTENT WRITE PROTECT +27h/05h T R PERMANENT WRITE PROTECT +28h/00h DTLPWRSOMCAEBK NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED +28h/01h DT WR OM B IMPORT OR EXPORT ELEMENT ACCESSED +29h/00h DTLPWRSOMCAEBK POWER ON, RESET, OR BUS DEVICE RESET OCCURRED +29h/01h DTLPWRSOMCAEBK POWER ON OCCURRED +29h/02h DTLPWRSOMCAEBK SCSI BUS RESET OCCURRED +29h/03h DTLPWRSOMCAEBK BUS DEVICE RESET FUNCTION OCCURRED +29h/04h DTLPWRSOMCAEBK DEVICE INTERNAL RESET +29h/05h DTLPWRSOMCAEBK TRANSCEIVER MODE CHANGED TO SINGLE-ENDED +29h/06h DTLPWRSOMCAEBK TRANSCEIVER MODE CHANGED TO LVD +2Ah/00h DTL WRSOMCAEBK PARAMETERS CHANGED +2Ah/01h DTL WRSOMCAEBK MODE PARAMETERS CHANGED +2Ah/02h DTL WRSOMCAE K LOG PARAMETERS CHANGED +2Ah/03h DTLPWRSOMCAE K RESERVATIONS PREEMPTED +2Ah/04h DTLPWRSOMCAE RESERVATIONS RELEASED +2Ah/05h DTLPWRSOMCAE REGISTRATIONS PREEMPTED +2Bh/00h DTLPWRSO C K COPY CANNOT EXECUTE SINCE HOST CANNOT DISCONNECT +2Ch/00h DTLPWRSOMCAEBK COMMAND SEQUENCE ERROR +2Ch/01h S TOO MANY WINDOWS SPECIFIED +2Ch/02h S INVALID COMBINATION OF WINDOWS SPECIFIED +2Ch/03h R CURRENT PROGRAM AREA IS NOT EMPTY +2Ch/04h R CURRENT PROGRAM AREA IS EMPTY +2Ch/05h B ILLEGAL POWER CONDITION REQUEST +2Dh/00h T OVERWRITE ERROR ON UPDATE IN PLACE +2Eh/00h DTLPWRSO CA K ERROR DETECTED BY THIRD PARTY TEMPORARY INITIATOR +2Eh/01h DTLPWRSO CA K THIRD PARTY DEVICE FAILURE +2Eh/02h DTLPWRSO CA K COPY TARGET DEVICE NOT REACHABLE +2Eh/03h DTLPWRSO CA K INCORRECT COPY TARGET DEVICE TYPE +2Eh/04h DTLPWRSO CA K COPY TARGET DEVICE DATA UNDERRUN +2Eh/05h DTLPWRSO CA K COPY TARGET DEVICE DATA OVERRUN +2Fh/00h DTLPWRSOMCAEBK COMMANDS CLEARED BY ANOTHER INITIATOR +30h/00h DT WR OM BK INCOMPATIBLE MEDIUM INSTALLED +30h/01h DT WR O BK CANNOT READ MEDIUM - UNKNOWN FORMAT +30h/02h DT WR O BK CANNOT READ MEDIUM - INCOMPATIBLE FORMAT +30h/03h DT R K CLEANING CARTRIDGE INSTALLED +30h/04h DT WR O BK CANNOT WRITE MEDIUM - UNKNOWN FORMAT +30h/05h DT WR O BK CANNOT WRITE MEDIUM - INCOMPATIBLE FORMAT +30h/06h DT WR O B CANNOT FORMAT MEDIUM - INCOMPATIBLE MEDIUM +30h/07h DTL WRSOM AEBK CLEANING FAILURE +30h/08h R CANNOT WRITE - APPLICATION CODE MISMATCH +30h/09h R CURRENT SESSION NOT FIXATED FOR APPEND +31h/00h DT WR O BK MEDIUM FORMAT CORRUPTED +31h/01h D L R O B FORMAT COMMAND FAILED +32h/00h D W O BK NO DEFECT SPARE LOCATION AVAILABLE +32h/01h D W O BK DEFECT LIST UPDATE FAILURE +33h/00h T TAPE LENGTH ERROR +34h/00h DTLPWRSOMCAEBK ENCLOSURE FAILURE +35h/00h DTLPWRSOMCAEBK ENCLOSURE SERVICES FAILURE +35h/01h DTLPWRSOMCAEBK UNSUPPORTED ENCLOSURE FUNCTION +35h/02h DTLPWRSOMCAEBK ENCLOSURE SERVICES UNAVAILABLE +35h/03h DTLPWRSOMCAEBK ENCLOSURE SERVICES TRANSFER FAILURE +35h/04h DTLPWRSOMCAEBK ENCLOSURE SERVICES TRANSFER REFUSED +36h/00h L RIBBON, INK, OR TONER FAILURE +37h/00h DTL WRSOMCAEBK ROUNDED PARAMETER +38h/00h B EVENT STATUS NOTIFICATION +38h/02h B ESN - POWER MANAGEMENT CLASS EVENT +38h/04h B ESN - MEDIA CLASS EVENT +38h/06h B ESN - DEVICE BUSY CLASS EVENT +39h/00h DTL WRSOMCAE K SAVING PARAMETERS NOT SUPPORTED +3Ah/00h DTL WRSOM BK MEDIUM NOT PRESENT +3Ah/01h DT WR OM BK MEDIUM NOT PRESENT - TRAY CLOSED +3Ah/02h DT WR OM BK MEDIUM NOT PRESENT - TRAY OPEN +3Ah/03h DT WR OM B MEDIUM NOT PRESENT - LOADABLE +3Ah/04h DT WR OM B MEDIUM NOT PRESENT - MEDIUM AUXILIARY MEMORY ACCESSIBLE +3Bh/00h TL SEQUENTIAL POSITIONING ERROR +3Bh/01h T TAPE POSITION ERROR AT BEGINNING-OF-MEDIUM +3Bh/02h T TAPE POSITION ERROR AT END-OF-MEDIUM +3Bh/03h L TAPE OR ELECTRONIC VERTICAL FORMS UNIT NOT READY +3Bh/04h L SLEW FAILURE +3Bh/05h L PAPER JAM +3Bh/06h L FAILED TO SENSE TOP-OF-FORM +3Bh/07h L FAILED TO SENSE BOTTOM-OF-FORM +3Bh/08h T REPOSITION ERROR +3Bh/09h S READ PAST END OF MEDIUM +3Bh/0Ah S READ PAST BEGINNING OF MEDIUM +3Bh/0Bh S POSITION PAST END OF MEDIUM +3Bh/0Ch T S POSITION PAST BEGINNING OF MEDIUM +3Bh/0Dh DT WR OM BK MEDIUM DESTINATION ELEMENT FULL +3Bh/0Eh DT WR OM BK MEDIUM SOURCE ELEMENT EMPTY +3Bh/0Fh R END OF MEDIUM REACHED +3Bh/11h DT WR OM BK MEDIUM MAGAZINE NOT ACCESSIBLE +3Bh/12h DT WR OM BK MEDIUM MAGAZINE REMOVED +3Bh/13h DT WR OM BK MEDIUM MAGAZINE INSERTED +3Bh/14h DT WR OM BK MEDIUM MAGAZINE LOCKED +3Bh/15h DT WR OM BK MEDIUM MAGAZINE UNLOCKED +3Bh/16h R MECHANICAL POSITIONING OR CHANGER ERROR +3Ch/00h +3Dh/00h DTLPWRSOMCAE K INVALID BITS IN IDENTIFY MESSAGE +3Eh/00h DTLPWRSOMCAEBK LOGICAL UNIT HAS NOT SELF-CONFIGURED YET +3Eh/01h DTLPWRSOMCAEBK LOGICAL UNIT FAILURE +3Eh/02h DTLPWRSOMCAEBK TIMEOUT ON LOGICAL UNIT +3Eh/03h DTLPWRSOMCAEBK LOGICAL UNIT FAILED SELF-TEST +3Eh/04h DTLPWRSOMCAEBK LOGICAL UNIT UNABLE TO UPDATE SELF-TEST LOG +3Fh/00h DTLPWRSOMCAEBK TARGET OPERATING CONDITIONS HAVE CHANGED +3Fh/01h DTLPWRSOMCAEBK MICROCODE HAS BEEN CHANGED +3Fh/02h DTLPWRSOMC BK CHANGED OPERATING DEFINITION +3Fh/03h DTLPWRSOMCAEBK INQUIRY DATA HAS CHANGED +3Fh/04h DT WR OMCAEBK COMPONENT DEVICE ATTACHED +3Fh/05h DT WR OMCAEBK DEVICE IDENTIFIER CHANGED +3Fh/06h DT WR OMCAEB REDUNDANCY GROUP CREATED OR MODIFIED +3Fh/07h DT WR OMCAEB REDUNDANCY GROUP DELETED +3Fh/08h DT WR OMCAEB SPARE CREATED OR MODIFIED +3Fh/09h DT WR OMCAEB SPARE DELETED +3Fh/0Ah DT WR OMCAEBK VOLUME SET CREATED OR MODIFIED +3Fh/0Bh DT WR OMCAEBK VOLUME SET DELETED +3Fh/0Ch DT WR OMCAEBK VOLUME SET DEASSIGNED +3Fh/0Dh DT WR OMCAEBK VOLUME SET REASSIGNED +3Fh/0Eh DTLPWRSOMCAE REPORTED LUNS DATA HAS CHANGED +3Fh/0Fh DTLPWRSOMCAEBK ECHO BUFFER OVERWRITTEN +3Fh/10h DT WR OM B MEDIUM LOADABLE +3Fh/11h DT WR OM B MEDIUM AUXILIARY MEMORY ACCESSIBLE +40h/00h D RAM FAILURE (SHOULD USE 40 NN) +40h/NNh DTLPWRSOMCAEBK DIAGNOSTIC FAILURE ON COMPONENT NN (80H-FFH) +41h/00h D DATA PATH FAILURE (SHOULD USE 40 NN) +42h/00h D POWER-ON OR SELF-TEST FAILURE (SHOULD USE 40 NN) +43h/00h DTLPWRSOMCAEBK MESSAGE ERROR +44h/00h DTLPWRSOMCAEBK INTERNAL TARGET FAILURE +45h/00h DTLPWRSOMCAEBK SELECT OR RESELECT FAILURE +46h/00h DTLPWRSOMC BK UNSUCCESSFUL SOFT RESET +47h/00h DTLPWRSOMCAEBK SCSI PARITY ERROR +47h/01h DTLPWRSOMCAEBK DATA PHASE CRC ERROR DETECTED +47h/02h DTLPWRSOMCAEBK SCSI PARITY ERROR DETECTED DURING ST DATA PHASE +47h/03h DTLPWRSOMCAEBK INFORMATION UNIT CRC ERROR DETECTED +47h/04h DTLPWRSOMCAEBK ASYNCHRONOUS INFORMATION PROTECTION ERROR DETECTED +48h/00h DTLPWRSOMCAEBK INITIATOR DETECTED ERROR MESSAGE RECEIVED +49h/00h DTLPWRSOMCAEBK INVALID MESSAGE ERROR +4Ah/00h DTLPWRSOMCAEBK COMMAND PHASE ERROR +4Bh/00h DTLPWRSOMCAEBK DATA PHASE ERROR +4Ch/00h DTLPWRSOMCAEBK LOGICAL UNIT FAILED SELF-CONFIGURATION +4Dh/NNh DTLPWRSOMCAEBK TAGGED OVERLAPPED COMMANDS (NN = QUEUE TAG) +4Eh/00h DTLPWRSOMCAEBK OVERLAPPED COMMANDS ATTEMPTED +4Fh/00h +50h/00h T WRITE APPEND ERROR +50h/01h T WRITE APPEND POSITION ERROR +50h/02h T POSITION ERROR RELATED TO TIMING +51h/00h T R O ERASE FAILURE +52h/00h T CARTRIDGE FAULT +53h/00h DTL WRSOM BK MEDIA LOAD OR EJECT FAILED +53h/01h T UNLOAD TAPE FAILURE +53h/02h DT WR OM BK MEDIUM REMOVAL PREVENTED +54h/00h P SCSI TO HOST SYSTEM INTERFACE FAILURE +55h/00h P SYSTEM RESOURCE FAILURE +55h/01h D O BK SYSTEM BUFFER FULL +55h/02h DTLPWRSOM AE K INSUFFICIENT RESERVATION RESOURCES +55h/03h DTLPWRSOMCAE INSUFFICIENT RESOURCES +55h/04h DTLPWRSOM AE INSUFFICIENT REGISTRATION RESOURCES +55h/05h access controls code 4 (99-314) [proposed] +55h/06h auxiliary memory code 1 (99-148) [proposed] +56h/00h +57h/00h R UNABLE TO RECOVER TABLE-OF-CONTENTS +58h/00h O GENERATION DOES NOT EXIST +59h/00h O UPDATED BLOCK READ +5Ah/00h DTLPWRSOM BK OPERATOR REQUEST OR STATE CHANGE INPUT +5Ah/01h DT WR OM BK OPERATOR MEDIUM REMOVAL REQUEST +5Ah/02h DT WR O A BK OPERATOR SELECTED WRITE PROTECT +5Ah/03h DT WR O A BK OPERATOR SELECTED WRITE PERMIT +5Bh/00h DTLPWRSOM K LOG EXCEPTION +5Bh/01h DTLPWRSOM K THRESHOLD CONDITION MET +5Bh/02h DTLPWRSOM K LOG COUNTER AT MAXIMUM +5Bh/03h DTLPWRSOM K LOG LIST CODES EXHAUSTED +5Ch/00h D O RPL STATUS CHANGE +5Ch/01h D O SPINDLES SYNCHRONIZED +5Ch/02h D O SPINDLES NOT SYNCHRONIZED +5Dh/00h DTLPWRSOMCAEBK FAILURE PREDICTION THRESHOLD EXCEEDED +5Dh/01h R B MEDIA FAILURE PREDICTION THRESHOLD EXCEEDED +5Dh/02h R LOGICAL UNIT FAILURE PREDICTION THRESHOLD EXCEEDED +5Dh/10h D B HARDWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE +5Dh/11h D B HARDWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH +5Dh/12h D B HARDWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH +5Dh/13h D B HARDWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH +5Dh/14h D B HARDWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS +5Dh/15h D B HARDWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH +5Dh/16h D B HARDWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH +5Dh/17h D B HARDWARE IMPENDING FAILURE CHANNEL PARAMETRICS +5Dh/18h D B HARDWARE IMPENDING FAILURE CONTROLLER DETECTED +5Dh/19h D B HARDWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE +5Dh/1Ah D B HARDWARE IMPENDING FAILURE SEEK TIME PERFORMANCE +5Dh/1Bh D B HARDWARE IMPENDING FAILURE SPIN-UP RETRY COUNT +5Dh/1Ch D B HARDWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT +5Dh/20h D B CONTROLLER IMPENDING FAILURE GENERAL HARD DRIVE FAILURE +5Dh/21h D B CONTROLLER IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH +5Dh/22h D B CONTROLLER IMPENDING FAILURE DATA ERROR RATE TOO HIGH +5Dh/23h D B CONTROLLER IMPENDING FAILURE SEEK ERROR RATE TOO HIGH +5Dh/24h D B CONTROLLER IMPENDING FAILURE TOO MANY BLOCK REASSIGNS +5Dh/25h D B CONTROLLER IMPENDING FAILURE ACCESS TIMES TOO HIGH +5Dh/26h D B CONTROLLER IMPENDING FAILURE START UNIT TIMES TOO HIGH +5Dh/27h D B CONTROLLER IMPENDING FAILURE CHANNEL PARAMETRICS +5Dh/28h D B CONTROLLER IMPENDING FAILURE CONTROLLER DETECTED +5Dh/29h D B CONTROLLER IMPENDING FAILURE THROUGHPUT PERFORMANCE +5Dh/2Ah D B CONTROLLER IMPENDING FAILURE SEEK TIME PERFORMANCE +5Dh/2Bh D B CONTROLLER IMPENDING FAILURE SPIN-UP RETRY COUNT +5Dh/2Ch D B CONTROLLER IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT +5Dh/30h D B DATA CHANNEL IMPENDING FAILURE GENERAL HARD DRIVE FAILURE +5Dh/31h D B DATA CHANNEL IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH +5Dh/32h D B DATA CHANNEL IMPENDING FAILURE DATA ERROR RATE TOO HIGH +5Dh/33h D B DATA CHANNEL IMPENDING FAILURE SEEK ERROR RATE TOO HIGH +5Dh/34h D B DATA CHANNEL IMPENDING FAILURE TOO MANY BLOCK REASSIGNS +5Dh/35h D B DATA CHANNEL IMPENDING FAILURE ACCESS TIMES TOO HIGH +5Dh/36h D B DATA CHANNEL IMPENDING FAILURE START UNIT TIMES TOO HIGH +5Dh/37h D B DATA CHANNEL IMPENDING FAILURE CHANNEL PARAMETRICS +5Dh/38h D B DATA CHANNEL IMPENDING FAILURE CONTROLLER DETECTED +5Dh/39h D B DATA CHANNEL IMPENDING FAILURE THROUGHPUT PERFORMANCE +5Dh/3Ah D B DATA CHANNEL IMPENDING FAILURE SEEK TIME PERFORMANCE +5Dh/3Bh D B DATA CHANNEL IMPENDING FAILURE SPIN-UP RETRY COUNT +5Dh/3Ch D B DATA CHANNEL IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT +5Dh/40h D B SERVO IMPENDING FAILURE GENERAL HARD DRIVE FAILURE +5Dh/41h D B SERVO IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH +5Dh/42h D B SERVO IMPENDING FAILURE DATA ERROR RATE TOO HIGH +5Dh/43h D B SERVO IMPENDING FAILURE SEEK ERROR RATE TOO HIGH +5Dh/44h D B SERVO IMPENDING FAILURE TOO MANY BLOCK REASSIGNS +5Dh/45h D B SERVO IMPENDING FAILURE ACCESS TIMES TOO HIGH +5Dh/46h D B SERVO IMPENDING FAILURE START UNIT TIMES TOO HIGH +5Dh/47h D B SERVO IMPENDING FAILURE CHANNEL PARAMETRICS +5Dh/48h D B SERVO IMPENDING FAILURE CONTROLLER DETECTED +5Dh/49h D B SERVO IMPENDING FAILURE THROUGHPUT PERFORMANCE +5Dh/4Ah D B SERVO IMPENDING FAILURE SEEK TIME PERFORMANCE +5Dh/4Bh D B SERVO IMPENDING FAILURE SPIN-UP RETRY COUNT +5Dh/4Ch D B SERVO IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT +5Dh/50h D B SPINDLE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE +5Dh/51h D B SPINDLE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH +5Dh/52h D B SPINDLE IMPENDING FAILURE DATA ERROR RATE TOO HIGH +5Dh/53h D B SPINDLE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH +5Dh/54h D B SPINDLE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS +5Dh/55h D B SPINDLE IMPENDING FAILURE ACCESS TIMES TOO HIGH +5Dh/56h D B SPINDLE IMPENDING FAILURE START UNIT TIMES TOO HIGH +5Dh/57h D B SPINDLE IMPENDING FAILURE CHANNEL PARAMETRICS +5Dh/58h D B SPINDLE IMPENDING FAILURE CONTROLLER DETECTED +5Dh/59h D B SPINDLE IMPENDING FAILURE THROUGHPUT PERFORMANCE +5Dh/5Ah D B SPINDLE IMPENDING FAILURE SEEK TIME PERFORMANCE +5Dh/5Bh D B SPINDLE IMPENDING FAILURE SPIN-UP RETRY COUNT +5Dh/5Ch D B SPINDLE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT +5Dh/60h D B FIRMWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE +5Dh/61h D B FIRMWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH +5Dh/62h D B FIRMWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH +5Dh/63h D B FIRMWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH +5Dh/64h D B FIRMWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS +5Dh/65h D B FIRMWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH +5Dh/66h D B FIRMWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH +5Dh/67h D B FIRMWARE IMPENDING FAILURE CHANNEL PARAMETRICS +5Dh/68h D B FIRMWARE IMPENDING FAILURE CONTROLLER DETECTED +5Dh/69h D B FIRMWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE +5Dh/6Ah D B FIRMWARE IMPENDING FAILURE SEEK TIME PERFORMANCE +5Dh/6Bh D B FIRMWARE IMPENDING FAILURE SPIN-UP RETRY COUNT +5Dh/6Ch D B FIRMWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT +5Dh/FFh DTLPWRSOMCAEBK FAILURE PREDICTION THRESHOLD EXCEEDED (FALSE) +5Eh/00h DTLPWRSO CA K LOW POWER CONDITION ON +5Eh/01h DTLPWRSO CA K IDLE CONDITION ACTIVATED BY TIMER +5Eh/02h DTLPWRSO CA K STANDBY CONDITION ACTIVATED BY TIMER +5Eh/03h DTLPWRSO CA K IDLE CONDITION ACTIVATED BY COMMAND +5Eh/04h DTLPWRSO CA K STANDBY CONDITION ACTIVATED BY COMMAND +5Eh/41h B POWER STATE CHANGE TO ACTIVE +5Eh/42h B POWER STATE CHANGE TO IDLE +5Eh/43h B POWER STATE CHANGE TO STANDBY +5Eh/45h B POWER STATE CHANGE TO SLEEP +5Eh/47h BK POWER STATE CHANGE TO DEVICE CONTROL +5Fh/00h +60h/00h S LAMP FAILURE +61h/00h S VIDEO ACQUISITION ERROR +61h/01h S UNABLE TO ACQUIRE VIDEO +61h/02h S OUT OF FOCUS +62h/00h S SCAN HEAD POSITIONING ERROR +63h/00h R END OF USER AREA ENCOUNTERED ON THIS TRACK +63h/01h R PACKET DOES NOT FIT IN AVAILABLE SPACE +64h/00h R ILLEGAL MODE FOR THIS TRACK +64h/01h R INVALID PACKET SIZE +65h/00h DTLPWRSOMCAEBK VOLTAGE FAULT +66h/00h S AUTOMATIC DOCUMENT FEEDER COVER UP +66h/01h S AUTOMATIC DOCUMENT FEEDER LIFT UP +66h/02h S DOCUMENT JAM IN AUTOMATIC DOCUMENT FEEDER +66h/03h S DOCUMENT MISS FEED AUTOMATIC IN DOCUMENT FEEDER +67h/00h A CONFIGURATION FAILURE +67h/01h A CONFIGURATION OF INCAPABLE LOGICAL UNITS FAILED +67h/02h A ADD LOGICAL UNIT FAILED +67h/03h A MODIFICATION OF LOGICAL UNIT FAILED +67h/04h A EXCHANGE OF LOGICAL UNIT FAILED +67h/05h A REMOVE OF LOGICAL UNIT FAILED +67h/06h A ATTACHMENT OF LOGICAL UNIT FAILED +67h/07h A CREATION OF LOGICAL UNIT FAILED +67h/08h A ASSIGN FAILURE OCCURRED +67h/09h A MULTIPLY ASSIGNED LOGICAL UNIT +68h/00h A LOGICAL UNIT NOT CONFIGURED +69h/00h A DATA LOSS ON LOGICAL UNIT +69h/01h A MULTIPLE LOGICAL UNIT FAILURES +69h/02h A PARITY/DATA MISMATCH +6Ah/00h A INFORMATIONAL, REFER TO LOG +6Bh/00h A STATE CHANGE HAS OCCURRED +6Bh/01h A REDUNDANCY LEVEL GOT BETTER +6Bh/02h A REDUNDANCY LEVEL GOT WORSE +6Ch/00h A REBUILD FAILURE OCCURRED +6Dh/00h A RECALCULATE FAILURE OCCURRED +6Eh/00h A COMMAND TO LOGICAL UNIT FAILED +6Fh/00h R COPY PROTECTION KEY EXCHANGE FAILURE - AUTHENTICATION FAILURE +6Fh/01h R COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT PRESENT +6Fh/02h R COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT ESTABLISHED +6Fh/03h R READ OF SCRAMBLED SECTOR WITHOUT AUTHENTICATION +6Fh/04h R MEDIA REGION CODE IS MISMATCHED TO LOGICAL UNIT REGION +6Fh/05h R DRIVE REGION MUST BE PERMANENT/REGION RESET COUNT ERROR +70h/NNh T DECOMPRESSION EXCEPTION SHORT ALGORITHM ID OF NN +71h/00h T DECOMPRESSION EXCEPTION LONG ALGORITHM ID +72h/00h R SESSION FIXATION ERROR +72h/01h R SESSION FIXATION ERROR WRITING LEAD-IN +72h/02h R SESSION FIXATION ERROR WRITING LEAD-OUT +72h/03h R SESSION FIXATION ERROR - INCOMPLETE TRACK IN SESSION +72h/04h R EMPTY OR PARTIALLY WRITTEN RESERVED TRACK +72h/05h R NO MORE TRACK RESERVATIONS ALLOWED +73h/00h R CD CONTROL ERROR +73h/01h R POWER CALIBRATION AREA ALMOST FULL +73h/02h R POWER CALIBRATION AREA IS FULL +73h/03h R POWER CALIBRATION AREA ERROR +73h/04h R PROGRAM MEMORY AREA UPDATE FAILURE +73h/05h R PROGRAM MEMORY AREA IS FULL +73h/06h R RMA/PMA IS FULL +74h/00h +75h/00h +76h/00h +77h/00h +78h/00h +79h/00h +7Ah/00h +7Bh/00h +7Ch/00h +7Dh/00h +7Eh/00h +7Fh/00h diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/t10.org/op-num.txt linux.ac/drivers/message/fusion/t10.org/op-num.txt --- linux.vanilla/drivers/message/fusion/t10.org/op-num.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/t10.org/op-num.txt Tue Apr 3 17:54:47 2001 @@ -0,0 +1,234 @@ +File: OP-NUM.TXT + +SCSI Operation Codes +Numeric Sorted Listing +as of 3/21/00 + + D - DIRECT ACCESS DEVICE (SBC) device column key + .T - SEQUENTIAL ACCESS DEVICE (SSC) ------------------- + . L - PRINTER DEVICE (SSC) M = Mandatory + . P - PROCESSOR DEVICE (SPC) O = Optional + . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC) V = Vendor specific + . . R - CD DEVICE (MMC) Z = Obsolete + . . S - SCANNER DEVICE (SCSI-2) + . . .O - OPTICAL MEMORY DEVICE (SBC) + . . . M - MEDIA CHANGER DEVICE (SMC) + . . . C - COMMUNICATION DEVICE (SCSI-2) + . . . .A - STORAGE ARRAY DEVICE (SCC) + . . . . E - ENCLOSURE SERVICES DEVICE (SES) + . . . . B - SIMPLIFIED DIRECT-ACCESS DEVICE (RBC) + . . . . .K - OPTICAL CARD READER/WRITER DEVICE (OCRW) +OP DTLPWRSOMCAEBK Description +-- -------------- ---------------------------------------------------- +00 MMMMMMMMMMMMMM TEST UNIT READY +01 M REWIND +01 Z V ZZ ZO REZERO UNIT +02 VVVVVV V +03 MMMMMMMMMMMM M REQUEST SENSE +04 M O O FORMAT UNIT +04 O FORMAT MEDIUM +04 O FORMAT +05 VMVVVV V READ BLOCK LIMITS +06 VVVVVV V +07 OVV O OV REASSIGN BLOCKS +07 O INITIALIZE ELEMENT STATUS +08 O V OO OV READ(06) +08 M READ +08 O RECEIVE +08 M GET MESSAGE(06) +09 VVVVVV V +0A O O OV WRITE(06) +0A M WRITE +0A M SEND(06) +0A M SEND MESSAGE(06) +0A M PRINT +0B Z ZO ZV SEEK(06) +0B O SLEW AND PRINT +0C VVVVVV V +0D VVVVVV V +0E VVVVVV V +0F VOVVVV V READ REVERSE +10 VM VVV WRITE FILEMARKS +10 O O SYNCHRONIZE BUFFER +11 VMVVVV SPACE(6) +12 MMMMMMMMMMMMMM INQUIRY +13 V VVVV +13 O VERIFY +14 VOOVVV RECOVER BUFFERED DATA +15 OMO OOOOOOOO O MODE SELECT(06) +16 MMMOMOMM OO O RESERVE(06) +16 M RESERVE ELEMENT(06) +17 MMMOMOMM OO O RELEASE(06) +17 M RELEASE ELEMENT(06) +18 OOOOOOOO O COPY +19 VMVVVV ERASE +1A OMO OOOOOOOO O MODE SENSE(06) +1B O OM O O MO STOP START UNIT +1B O LOAD UNLOAD +1B O SCAN +1B O STOP PRINT +1C OOOOOOOOOOOM O RECEIVE DIAGNOSTIC RESULTS +1D MMMMMMMMMMOM M SEND DIAGNOSTIC +1E OO OM OO O PREVENT ALLOW MEDIUM REMOVAL +1F +20 V VV V V +21 V VV V V +22 V VV V V +23 V V V V +23 O READ FORMAT CAPACITIES +24 V VVM SET WINDOW +25 M MM M READ CAPACITY +25 M READ CARD CAPACITY +25 O GET WINDOW +26 V VV +27 V VV +28 M MMMM MM READ(10) +28 O GET MESSAGE(10) +29 V VV O READ GENERATION +2A M MM M MO WRITE(10) +2A O SEND(10) +2A O SEND MESSAGE(10) +2B O OM O O SEEK(10) +2B O LOCATE(10) +2B O POSITION TO ELEMENT +2C V O O ERASE(10) +2D V O O READ UPDATED BLOCK +2E O OO O MO WRITE AND VERIFY(10) +2F O OO O VERIFY(10) +30 Z ZZ Z SEARCH DATA HIGH(10) +31 Z ZZ Z SEARCH DATA EQUAL(10) +31 O OBJECT POSITION +32 Z ZZ Z SEARCH DATA LOW(10) +33 O OO O SET LIMITS(10) +34 O OO O O PRE-FETCH(10) +34 M READ POSITION +34 O GET DATA BUFFER STATUS +35 O OM O MO SYNCHRONIZE CACHE(10) +36 O OO O O LOCK UNLOCK CACHE(10) +37 O O READ DEFECT DATA(10) +38 O O O MEDIUM SCAN +39 OOOOOOOO O COMPARE +3A OOOOOOOO O COPY AND VERIFY +3B OOOOOOOOOOOOMO WRITE BUFFER +3C OOOOOOOOOOO O READ BUFFER +3D O O UPDATE BLOCK +3E O OO O READ LONG +3F O O O WRITE LONG +40 ZZZZZZZZZZ CHANGE DEFINITION +41 O WRITE SAME(10) +42 M READ SUB-CHANNEL +43 M READ TOC/PMA/ATIP +44 M REPORT DENSITY SUPPORT +44 M READ HEADER +45 O PLAY AUDIO(10) +46 O GET CONFIGURATION +47 O PLAY AUDIO MSF +48 Z PLAY AUDIO TRACK INDEX +49 Z PLAY TRACK RELATIVE(10) +4A O GET EVENT STATUS NOTIFICATION +4B O PAUSE/RESUME +4C OOOOOOOOOOO O LOG SELECT +4D OOOOOOOOOOO O LOG SENSE +4E O STOP PLAY/SCAN +4F +50 O XDWRITE(10) +51 O XPWRITE(10) +51 M READ DISC INFORMATION +52 O XDREAD(10) +52 M READ TRACK INFORMATION +53 M RESERVE TRACK +54 O SEND OPC INFORMATION +55 OOO OOOOOOOOMO MODE SELECT(10) +56 MMMOMMMM OO RESERVE(10) +56 M RESERVE ELEMENT(10) +57 MMMOMMMM OO RELEASE(10) +57 M RELEASE ELEMENT(10) +58 O REPAIR TRACK +59 O READ MASTER CUE +5A OOO OOOOOOOOMO MODE SENSE(10) +5B M CLOSE TRACK/SESSION +5C O READ BUFFER CAPACITY +5D O SEND CUE SHEET +5E OOOOOOOOO OO PERSISTENT RESERVE IN +5F OOOOOOOOO OO PERSISTENT RESERVE OUT +80 O XDWRITE EXTENDED(16) +81 O REBUILD(16) +82 O REGENERATE(16) +83 OOOOOOOO O EXTENDED COPY +84 OOOOOOOO O RECEIVE COPY RESULTS +85 +86 ACCESS CONTROL IN [proposed] +87 ACCESS CONTROL OUT [proposed] +88 O OO O O READ(16) +89 DEVICE LOCKS [proposed] +8A O O O O WRITE(16) +8B +8C READ ATTRIBUTES [proposed] +8D WRITE ATTRIBUTES [proposed] +8E O O O O WRITE AND VERIFY(16) +8F O OO O O VERIFY(16) +90 O OO O O PRE-FETCH(16) +91 O OO O O SYNCHRONIZE CACHE(16) +91 O SPACE(16) [1] +92 O OO O LOCK UNLOCK CACHE(16) +92 O LOCATE(16) [1] +93 O WRITE SAME(16) +94 [usage proposed by SCSI Socket Services project] +95 [usage proposed by SCSI Socket Services project] +96 [usage proposed by SCSI Socket Services project] +97 [usage proposed by SCSI Socket Services project] +98 MARGIN CONTROL [proposed] +99 +9A +9B +9C +9D +9E SERVICE ACTION IN [proposed] +9F SERVICE ACTION OUT [proposed] +A0 OOOOOOOOOOMO O REPORT LUNS +A1 O BLANK +A2 O SEND EVENT +A3 OOO O OOOMO MAINTENANCE (IN) +A3 O SEND KEY +A4 OOO O OOOOO MAINTENANCE (OUT) +A4 O REPORT KEY +A5 O M MOVE MEDIUM +A5 O PLAY AUDIO(12) +A6 O EXCHANGE MEDIUM +A6 O LOAD/UNLOAD C/DVD +A7 OO O OO MOVE MEDIUM ATTACHED +A7 O SET READ AHEAD +A8 OM O READ(12) +A8 O GET MESSAGE(12) +A9 Z PLAY TRACK RELATIVE(12) +AA O O WRITE(12) +AA O SEND MESSAGE(12) +AB +AC O ERASE(12) +AC O GET PERFORMANCE +AD O READ DVD STRUCTURE +AE O O WRITE AND VERIFY(12) +AF OZ O VERIFY(12) +B0 ZZ Z SEARCH DATA HIGH(12) +B1 ZZ Z SEARCH DATA EQUAL(12) +B2 ZZ Z SEARCH DATA LOW(12) +B3 OO O SET LIMITS(12) +B4 OO OZ OO READ ELEMENT STATUS ATTACHED +B5 O REQUEST VOLUME ELEMENT ADDRESS +B6 O SEND VOLUME TAG +B6 O SET STREAMING +B7 O READ DEFECT DATA(12) +B8 O Z M READ ELEMENT STATUS +B9 M READ CD MSF +BA O O OO MO REDUNDANCY GROUP (IN) +BA O SCAN +BB O O OO OO REDUNDANCY GROUP (OUT) +BB O SET CD-ROM SPEED +BC O O OO MO SPARE (IN) +BC O PLAY CD +BD O O OO OO SPARE (OUT) +BD M MECHANISM STATUS +BE O O OO MO VOLUME SET (IN) +BE O READ CD +BF O O OO OO VOLUME SET (OUT) +BF O SEND DVD STRUCTURE diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/t10.org/stds.txt linux.ac/drivers/message/fusion/t10.org/stds.txt --- linux.vanilla/drivers/message/fusion/t10.org/stds.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/t10.org/stds.txt Tue Apr 3 17:54:47 2001 @@ -0,0 +1,120 @@ +File: STDS.TXT + +SCSI Standards Version Descriptor Value Assignments +as of 3/29/00 + +Code Standard +----- ---------------------------------------------------------------- +14BDh ANSI IEEE 1394:1995 +0B20h EPI (no version claimed) +0B3Ch EPI ANSI NCITS TR-23:1999 +0B3Bh EPI T10/1134 revision 16 +0D40h FC-AL (no version claimed) +0D5Ch FC-AL ANSI X3.272:1996 +0D60h FC-AL-2 (no version claimed) +0D61h FC-AL-2 T11/1133 revision 7.0 +1320h FC-FLA (no version claimed) +133Ch FC-FLA ANSI NCITS TR-20:1998 +133Bh FC-FLA T11/1235 revision 7 +0DA0h FC-FS (no version claimed) +0D20h FC-PH (no version claimed) +0D3Bh FC-PH ANSI X3.230:1994 +0D3Ch FC-PH ANSI X3.230:1994 with Amnd 1 ANSI X3.230/AM1:1996 +0D80h FC-PH-3 (no version claimed) +0D9Ch FC-PH-3 ANSI X3.303-1998 +1340h FC-PLDA (no version claimed) +135Ch FC-PLDA ANSI NCITS TR-19:1998 +135Bh FC-PLDA T11/1162 revision 2.1 +1300h FC-Tape (no version claimed) +1301h FC-Tape T11/1315 revision 1.16 +08C0h FCP (no version claimed) +08DCh FCP ANSI X3.269:1996 +08DBh FCP T10/0993 revision 12 +0900h FCP-2 (no version claimed) +0901h FCP-2 T10/1144 revision 4 +0AC0h Fast-20 (no version claimed) +0ADCh Fast-20 ANSI X3.277:1996 +0ADBh Fast-20 T10/1071 revision 06 +14A0h IEEE 1394 (no version claimed) +14C0h IEEE 1394a (no version claimed) +14E0h IEEE 1394b (no version claimed) +0140h MMC (no version claimed) +015Ch MMC ANSI X3.304:1997 +015Bh MMC T10/1048 revision 10a +0240h MMC-2 (no version claimed) +0255h MMC-2 T10/1228 revision 11 +02A0h MMC-3 (no version claimed) +0280h OCRW (no version claimed) +029Eh OCRW ISO/IEC 14776-381 +0220h RBC (no version claimed) +0238h RBC T10/1240 revision 10a +02C0h RMC (no version claimed) +0020h SAM (no version claimed) +003Ch SAM ANSI X3.270:1996 +003Bh SAM T10/0994 revision 18 +0040h SAM-2 (no version claimed) +0180h SBC (no version claimed) +019Ch SBC ANSI NCITS.306:1998 +019Bh SBC T10/0996 revision 08c +0320h SBC-2 (no version claimed) +08E0h SBP-2 (no version claimed) +08FCh SBP-2 ANSI NCITS.325:1999 +08FBh SBP-2 T10/1155 revision 04 +0160h SCC (no version claimed) +017Ch SCC ANSI X3.276:1997 +017Bh SCC T10/1047 revision 06c +01E0h SCC-2 (no version claimed) +01FCh SCC-2 ANSI NCITS.318:1998 +01FBh SCC-2 T10/1125 revision 04 +01C0h SES (no version claimed) +01DCh SES ANSI NCITS.305:1998 +01DBh SES T10/1212 revision 08b +08A0h SIP (no version claimed) +08BCh SIP ANSI X3.292:1997 +08BBh SIP T10/0856 revision 10 +01A0h SMC (no version claimed) +01BCh SMC ANSI NCITS.314:1998 +01BBh SMC T10/0999 revision 10a +02E0h SMC-2 (no version claimed) +0120h SPC (no version claimed) +013Ch SPC ANSI X3.301:1997 +013Bh SPC T10/0995 revision 11a +0260h SPC-2 (no version claimed) +0267h SPC-2 T10/1236 revision 12 +0300h SPC-3 (no version claimed) +0AA0h SPI (no version claimed) +0ABAh SPI ANSI X3.253:1995 +0ABCh SPI ANSI X3.253:1995 with SPI Amnd ANSI X3.253/AM1:1998 +0AB9h SPI T10/0855 revision 15a +0ABBh SPI T10/0855 revision 15a with SPI Amnd revision 3a +0AE0h SPI-2 (no version claimed) +0AFCh SPI-2 ANSI X3.302:1999 +0AFBh SPI-2 T10/1142 revision 20b +0B00h SPI-3 (no version claimed) +0B18h SPI-3 T10/1302-D revision 10 +0B19h SPI-3 T10/1302-D revision 13a +0B40h SPI-4 (no version claimed) +1360h SSA-PH2 (no version claimed) +137Ch SSA-PH2 ANSI X3.293:1996 +137Bh SSA-PH2 T10.1/1145 revision 09c +1380h SSA-PH3 (no version claimed) +139Ch SSA-PH3 ANSI NCITS.307:1998 +139Bh SSA-PH3 T10.1/1146 revision 05b +0880h SSA-S2P (no version claimed) +089Ch SSA-S2P ANSI X3.294:1996 +089Bh SSA-S2P T10.1/1121 revision 07b +0860h SSA-S3P (no version claimed) +087Ch SSA-S3P ANSI NCITS.309:1998 +087Bh SSA-S3P T10.1/1051 revision 05b +0840h SSA-TL1 (no version claimed) +085Ch SSA-TL1 ANSI X3.295:1996 +085Bh SSA-TL1 T10.1/0989 revision 10b +0820h SSA-TL2 (no version claimed) +083Ch SSA-TL2 ANSI NCITS.308:1998 +083Bh SSA-TL2 T10.1/1147 revision 05b +0200h SSC (no version claimed) +0201h SSC T10/0997 revision 17 +0207h SSC T10/0997 revision 22 +0920h SST (no version claimed) +0940h SVP (no version claimed) +0000h Version Descriptor Not Supported or No Standard Identified diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/fusion/t10.org/vendorid.txt linux.ac/drivers/message/fusion/t10.org/vendorid.txt --- linux.vanilla/drivers/message/fusion/t10.org/vendorid.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/fusion/t10.org/vendorid.txt Tue Apr 3 17:54:47 2001 @@ -0,0 +1,340 @@ +This file contains the list of T10 Technical Committee vendor identifications +as of 2000/06/16 at 16:03:08. The purpose of this list is to help avoid redundant +usage of vendor identifications. T10, a subcommittee of the National +Committee on Information Technology Standards (NCITS), maintains an +informal list of vendor identifications currently in use. Please contact +the chairman of T10 prior to using a new vendor identification to avoid +conflicts. + + John Lohmeyer, Chair T10 Technical Committee + LSI Logic Corp. + 4420 ArrowsWest Dr. + Colorado Springs, CO 80907 + Tel: 719-533-7560 + Fax: 719-533-7183 + Email: lohmeyer@t10.org + +When requesting a new vendor ID, please specify your preferred vendor ID +code and your organization name EXACTLY as you would like it to appear in +this list. There are a few simple rules to follow: + + 1. The Vendor ID code shall be 8 or fewer ASCII graphic characters + (codes 21h through 7Eh). Spaces (20h) are added to the right to + make exactly 8 characters. + + 2. The Organization Name shall be 68 or fewer ASCII graphic characters + (codes 20h through 7Eh). + + 3. Please avoid requesting previously assigned vendor IDs. While the + committee list includes both upper and lowercase characters, + vendor IDs that are the same as an existing ID except for case + will not be accepted. + + Vendor ID Organization + --------- --------------------------------------------------------------- + 3M 3M Company + ACL Automated Cartridge Librarys, Inc. + AcuLab AcuLab, Inc. (Tulsa, OK) + ADAPTEC Adaptec + ADIC Advanced Digital Information Corporation + ADSI Adaptive Data Systems, Inc. (a Western Digital subsidiary) + ADTX ADTX Co., Ltd. + AERONICS Aeronics, Inc. + AGFA AGFA + AMCODYNE Amcodyne + ANAMATIC Anamartic Limited (England) + Ancor Ancor Communications, Inc. + ANCOT ANCOT Corp. + ANDATACO Andataco (now nStor) + ANRITSU Anritsu Corporation + APPLE Apple Computer, Inc. + ARCHIVE Archive + ARK ARK Research Corporation + ARTECON Artecon Inc. (Obs. - now Dot Hill) + ASACA ASACA Corp. + ASC Advanced Storage Concepts, Inc. + ASPEN Aspen Peripherals + AST AST Research + ASTK Alcatel STK A/S + AT&T AT&T + ATARI Atari Corporation + ATG CYG ATG Cygnet Inc. + ATTO ATTO Technology Inc. + ATX Alphatronix + AVR Advanced Vision Research + BALLARD Ballard Synergy Corp. + BERGSWD Berg Software Design + BEZIER Bezier Systems, Inc. + BHTi Breece Hill Technologies + BiT BiT Microsystems (obsolete, new ID: BITMICRO) + BITMICRO BiT Microsystems, Inc. + BNCHMARK Benchmark Tape Systems Corporation + BoxHill Box Hill Systems Corporation (Obs. - now Dot Hill) + BREA BREA Technologies, Inc. + BULL Bull Peripherals Corp. + BUSLOGIC BusLogic Inc. + CalComp CalComp, A Lockheed Company + CALIPER Caliper (California Peripheral Corp.) + CAST Advanced Storage Tech + CDC Control Data or MPI + CDP Columbia Data Products + CenData Central Data Corporation + Cereva Cereva Networks Inc. + CHEROKEE Cherokee Data Systems + CHINON Chinon + CIE&YED YE Data, C.Itoh Electric Corp. + CIPHER Cipher Data Products + Ciprico Ciprico, Inc. + CIRRUSL Cirrus Logic Inc. + CMD CMD Technology Inc. + CNGR SFW Congruent Software, Inc. + CNSi Chaparral Network Storage, Inc. + COGITO Cogito + COMPAQ Compaq Computer Corporation + COMPORT Comport Corp. + COMPSIG Computer Signal Corporation + COMPTEX Comptex Pty Limited + CONNER Conner Peripherals + CORE Core International, Inc. + CPL Cross Products Ltd + CPU TECH CPU Technology, Inc. + CREO Creo Products Inc. + CROSFLD Crosfield Electronics (now FujiFilm Electonic Imaging Ltd) + CROSSRDS Crossroads Systems, Inc. + CSM, INC Computer SM, Inc. + Data Com Data Com Information Systems Pty. Ltd. + DATABOOK Databook, Inc. + DATACOPY Datacopy Corp. + DataCore DataCore Software Corporation + DATAPT Datapoint Corp. + DEC Digital Equipment (Obsolete: New products use 'COMPAQ') + DEI Digital Engineering, Inc. + DELL Dell Computer Corporation + DELPHI Delphi Data Div. of Sparks Industries, Inc. + DENON Denon/Nippon Columbia + DenOptix DenOptix, Inc. + DEST DEST Corp. + DGC Data General Corp. + DIGIDATA Digi-Data Corporation + DigiIntl Digi International + Digital Digital Equipment Corporation (Obs: New products use 'COMPAQ') + DILOG Distributed Logic Corp. + DISC Document Imaging Systems Corp. + DotHill Dot Hill Systems Corp. + DPT Distributed Processing Technology + DSI Data Spectrum, Inc. + DSM Deterner Steuerungs- und Maschinenbau GmbH & Co. + DTC QUME Data Technology Qume + DXIMAGIN DX Imaging + ECCS ECCS, Inc. + ECMA European Computer Manufacturers Association + Elms Elms Systems Corporation + EMASS EMASS, Inc. + EMC EMC Corp. + EMTEC EMTEC Magnetics + EMULEX Emulex + EPSON Epson + Eris/RSI RSI Systems, Inc. + EuroLogc Eurologic Systems Limited + EXABYTE Exabyte Corp. + FFEILTD FujiFilm Electonic Imaging Ltd + FILENET FileNet Corp. + FRAMDRV FRAMEDRIVE Corp. + FUJI Fuji Electric Co., Ltd. (Japan) + FUJIFILM Fuji Photo Film, Co., Ltd. + FUJITSU Fujitsu + FUNAI Funai Electric Co., Ltd. + FUTURED Future Domain Corp. + G&D Giesecke & Devrient GmbH + GENSIG General Signal Networks + Gen_Dyn General Dynamics + GIGATAPE GIGATAPE GmbH + GIGATRND GigaTrend Incorporated + Global Global Memory Test Consortium + Goidelic Goidelic Precision, Inc. + GoldStar LG Electronics Inc. + GOULD Gould + HAGIWARA Hagiwara Sys-Com Co., Ltd. + HITACHI Hitachi America Ltd or Nissei Sangyo America Ltd + HONEYWEL Honeywell Inc. + HP Hewlett Packard + i-cubed i-cubed ltd. + IBM International Business Machines + ICL ICL + ICP ICP vortex Computersysteme GmbH + IDE International Data Engineering, Inc. + IGR Intergraph Corp. + IMATION Imation + IMPLTD Integrated Micro Products Ltd. + IMPRIMIS Imprimis Technology Inc. + Indigita Indigita Corporation + INITIO Initio Corporation + INSITE Insite Peripherals + INTEL Intel Corporation + IOC I/O Concepts, Inc. + IOMEGA Iomega + ISi Information Storage inc. + ISO International Standards Organization + ITC International Tapetronics Corporation + JPC Inc. JPC Inc. + JVC JVC Information Products Co. + KENNEDY Kennedy Company + KENWOOD KENWOOD Corporation + KODAK Eastman Kodak + KONAN Konan + KONICA Konica Japan + Kyocera Kyocera Corporation + LAPINE Lapine Technology + LASERDRV LaserDrive Limited + LASERGR Lasergraphics, Inc. + LG LG Electronics Inc. + LGE LG Electronics Inc. + LION Lion Optics Corporation + LMS Laser Magnetic Storage International Company + LSI LSI Logic Corp. + LSILOGIC LSI Logic Storage Systems, Inc. + LTO-CVE Linear Tape - Open, Compliance Verification Entity + MATSHITA Matsushita + MAXELL Hitachi Maxell, Ltd. + MaxOptix Maxoptix Corp. + MAXSTRAT Maximum Strategy, Inc. + MAXTOR Maxtor Corp. + McDATA McDATA Corporation + MDI Micro Design International, Inc. + MEADE Meade Instruments Corporation + MEII Mountain Engineering II, Inc. + MELA Mitsubishi Electronics America + MELCO Mitsubishi Electric (Japan) + MEMREL Memrel Corporation + MEMTECH MemTech Technology + MERIDATA Oy Meridata Finland Ltd + METRUM Metrum, Inc. + MICROBTX Microbotics Inc. + MICROP Micropolis + MICROTEK Microtek Storage Corp + Minitech Minitech (UK) Limited + Minolta Minolta Corporation + MINSCRIB Miniscribe + MITSUMI Mitsumi Electric Co., Ltd. + MOSAID Mosaid Technologies Inc. + MOTOROLA Motorola + MPM Mitsubishi Paper Mills, Ltd. + MST Morning Star Technologies, Inc. + MTNGATE MountainGate Data Systems + NAI North Atlantic Industries + NAKAMICH Nakamichi Corporation + NatInst National Instruments + NatSemi National Semiconductor Corp. + NCITS National Committee for Information Technology Standards + NCL NCL America + NCR NCR Corporation + NEC NEC + NEXSAN Nexsan Technologies, Ltd. + NISCA NISCA Inc. + NKK NKK Corp. + NRC Nakamichi Research Corporation + NSD Nippon Systems Development Co.,Ltd. + NSM NSM Jukebox GmbH + nStor nStor Technologies, Inc. + NT Northern Telecom + OAI Optical Access International + OCE Oce Graphics + OKI OKI Electric Industry Co.,Ltd (Japan) + OMI Optical Media International + OMNIS OMNIS Company (FRANCE) + OPTIMEM Cipher/Optimem + OPTOTECH Optotech + ORANGE Orange Micro, Inc. + ORCA Orca Technology + OSI Optical Storage International + OTL OTL Engineering + PASCOsci Pasco Scientific + PATHLGHT Pathlight Technology, Inc. + PERTEC Pertec Peripherals Corporation + PFTI Performance Technology Inc. + PFU PFU Limited + PICO Packard Instrument Company + PIONEER Pioneer Electronic Corp. + PLASMON Plasmon Data + PRAIRIE PrairieTek + PREPRESS PrePRESS Solutions + PRESOFT PreSoft Architects + PRESTON Preston Scientific + PRIAM Priam + PRIMAGFX Primagraphics Ltd + PROCOM Procom Technology + PTI Peripheral Technology Inc. + QIC Quarter-Inch Cartridge Drive Standards, Inc. + QUALSTAR Qualstar + QUANTEL Quantel Ltd. + QUANTUM Quantum Corp. + R-BYTE R-Byte, Inc. + RACALREC Racal Recorders + RADSTONE Radstone Technology + RGI Raster Graphics, Inc. + RHS Racal-Heim Systems GmbH + RICOH Ricoh + RODIME Rodime + RTI Reference Technology + SAMSUNG Samsung Electronics Co., Ltd. + SAN Storage Area Networks, Ltd. + SANKYO Sankyo Seiki + SANYO SANYO Electric Co., Ltd. + SCInc. Storage Concepts, Inc. + SCREEN Dainippon Screen Mfg. Co., Ltd. + SDI Storage Dimensions, Inc. + SDS Solid Data Systems + SEAGATE Seagate + SEQUOIA Sequoia Advanced Technologies, Inc. + Shinko Shinko Electric Co., Ltd. + SIEMENS Siemens + SII Seiko Instruments Inc. + SMS Scientific Micro Systems/OMTI + SNYSIDE Sunnyside Computing Inc. + SONIC Sonic Solutions + SONY Sony Corporation Japan + SPD Storage Products Distribution, Inc. + SPECIAL Special Computing Co. + SPECTRA Spectra Logic, a Division of Western Automation Labs, Inc. + SPERRY Sperry (now Unisys Corp.) + Sterling Sterling Diagnostic Imaging, Inc. + STK Storage Technology Corporation + STORAPP StorageApps, Inc. + STORM Storm Technology, Inc. + StrmLgc StreamLogic Corp. + SUMITOMO Sumitomo Electric Industries, Ltd. + SUN Sun Microsystems, Inc. + SYMBIOS Symbios Logic Inc. + SyQuest SyQuest Technology, Inc. + SYSGEN Sysgen + T-MITTON Transmitton England + TALARIS Talaris Systems, Inc. + TALLGRAS Tallgrass Technologies + TANDBERG Tandberg Data A/S + TANDON Tandon + TDK TDK Corporation + TEAC TEAC Japan + TECOLOTE Tecolote Designs + TEGRA Tegra Varityper + Tek Tektronix + TENTIME Laura Technologies, Inc. + TI-DSG Texas Instruments + TMS Texas Memory Systems, Inc. + TOSHIBA Toshiba Japan + TRIPACE Tripace + ULTRA UltraStor Corporation + UNISYS Unisys + USCORE Underscore, Inc. + USDC US Design Corp. + VDS Victor Data Systems Co., Ltd. + VERBATIM Verbatim Corporation + VEXCEL VEXCEL IMAGING GmbH + VICOMSL1 Vicom Systems, Inc. + VRC Vermont Research Corp. + WangDAT WangDAT + WANGTEK Wangtek + WDIGTL Western Digital + WEARNES Wearnes Technology Corporation + WSC0001 Wisecom, Inc. + X3 National Committee for Information Technology Standards (NCITS) + XEBEC Xebec Corporation diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/i2o/Config.in linux.ac/drivers/message/i2o/Config.in --- linux.vanilla/drivers/message/i2o/Config.in Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/i2o/Config.in Tue Apr 3 17:54:47 2001 @@ -0,0 +1,16 @@ +mainmenu_option next_comment +comment 'I2O device support' + +tristate 'I2O support' CONFIG_I2O + +if [ "$CONFIG_PCI" = "y" ]; then + dep_tristate ' I2O PCI support' CONFIG_I2O_PCI $CONFIG_I2O +fi +dep_tristate ' I2O Block OSM' CONFIG_I2O_BLOCK $CONFIG_I2O +if [ "$CONFIG_NET" = "y" ]; then + dep_tristate ' I2O LAN OSM' CONFIG_I2O_LAN $CONFIG_I2O +fi +dep_tristate ' I2O SCSI OSM' CONFIG_I2O_SCSI $CONFIG_I2O $CONFIG_SCSI +dep_tristate ' I2O /proc support' CONFIG_I2O_PROC $CONFIG_I2O + +endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/i2o/Makefile linux.ac/drivers/message/i2o/Makefile --- linux.vanilla/drivers/message/i2o/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/i2o/Makefile Tue Apr 3 17:54:47 2001 @@ -0,0 +1,20 @@ +# +# Makefile for the kernel I2O OSM. +# +# Note : at this point, these files are compiled on all systems. +# In the future, some of these should be built conditionally. +# + +O_TARGET := i2o.o + +export-objs := i2o_pci.o i2o_core.o i2o_config.o i2o_block.o i2o_lan.o i2o_scsi.o i2o_proc.o + +obj-$(CONFIG_I2O_PCI) += i2o_pci.o +obj-$(CONFIG_I2O) += i2o_core.o i2o_config.o +obj-$(CONFIG_I2O_BLOCK) += i2o_block.o +obj-$(CONFIG_I2O_LAN) += i2o_lan.o +obj-$(CONFIG_I2O_SCSI) += i2o_scsi.o +obj-$(CONFIG_I2O_PROC) += i2o_proc.o + +include $(TOPDIR)/Rules.make + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/i2o/README linux.ac/drivers/message/i2o/README --- linux.vanilla/drivers/message/i2o/README Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/i2o/README Tue Apr 3 17:54:47 2001 @@ -0,0 +1,98 @@ + + Linux I2O Support (c) Copyright 1999 Red Hat Software + and others. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version + 2 of the License, or (at your option) any later version. + +AUTHORS (so far) + +Alan Cox, Building Number Three Ltd. + Core code, SCSI and Block OSMs + +Steve Ralston, LSI Logic Corp. + Debugging SCSI and Block OSM + +Deepak Saxena, Intel Corp. + Various core/block extensions + /proc interface, bug fixes + Ioctl interfaces for control + Debugging LAN OSM + +Philip Rumpf + Fixed assorted dumb SMP locking bugs + +Juha Sievanen, University of Helsinki Finland + LAN OSM code + /proc interface to LAN class + Bug fixes + Core code extensions + +Auvo Häkkinen, University of Helsinki Finland + LAN OSM code + /Proc interface to LAN class + Bug fixes + Core code extensions + +Taneli Vähäkangas, University of Helsinki Finland + Fixes to i2o_config + +CREDITS + + This work was made possible by + +Red Hat Software + Funding for the Building #3 part of the project + +Symbios Logic (Now LSI) + Host adapters, hints, known to work platforms when I hit + compatibility problems + +BoxHill Corporation + Loan of initial FibreChannel disk array used for development work. + +European Comission + Funding the work done by the University of Helsinki + +SysKonnect + Loan of FDDI and Gigabit Ethernet cards + +ASUSTeK + Loan of I2O motherboard + +STATUS: + +o The core setup works within limits. +o The scsi layer seems to almost work. + I'm still chasing down the hang bug. +o The block OSM is mostly functional +o LAN OSM works with FDDI and Ethernet cards. + +TO DO: + +General: +o Provide hidden address space if asked +o Long term message flow control +o PCI IOP's without interrupts are not supported yet +o Push FAIL handling into the core +o DDM control interfaces for module load etc +o Add I2O 2.0 support (Deffered to 2.5 kernel) + +Block: +o Multiple major numbers +o Read ahead and cache handling stuff. Talk to Ingo and people +o Power management +o Finish Media changers + +SCSI: +o Find the right way to associate drives/luns/busses + +Lan: +o Performance tuning +o Test Fibre Channel code + +Tape: +o Anyone seen anything implementing this ? + (D.S: Will attempt to do so if spare cycles permit) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/i2o/README.ioctl linux.ac/drivers/message/i2o/README.ioctl --- linux.vanilla/drivers/message/i2o/README.ioctl Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/i2o/README.ioctl Tue Apr 3 17:54:47 2001 @@ -0,0 +1,394 @@ + +Linux I2O User Space Interface +rev 0.3 - 04/20/99 + +============================================================================= +Originally written by Deepak Saxena(deepak@plexity.net) +Currently maintained by Deepak Saxena(deepak@plexity.net) +============================================================================= + +I. Introduction + +The Linux I2O subsystem provides a set of ioctl() commands that can be +utilized by user space applications to communicate with IOPs and devices +on individual IOPs. This document defines the specific ioctl() commands +that are available to the user and provides examples of their uses. + +This document assumes the reader is familiar with or has access to the +I2O specification as no I2O message parameters are outlined. For information +on the specification, see http://www.i2osig.org + +This document and the I2O user space interface are currently maintained +by Deepak Saxena. Please send all comments, errata, and bug fixes to +deepak@csociety.purdue.edu + +II. IOP Access + +Access to the I2O subsystem is provided through the device file named +/dev/i2o/ctl. This file is a character file with major number 10 and minor +number 166. It can be created through the following command: + + mknod /dev/i2o/ctl c 10 166 + +III. Determining the IOP Count + + SYNOPSIS + + ioctl(fd, I2OGETIOPS, int *count); + + u8 count[MAX_I2O_CONTROLLERS]; + + DESCRIPTION + + This function returns the system's active IOP table. count should + point to a buffer containing MAX_I2O_CONTROLLERS entries. Upon + returning, each entry will contain a non-zero value if the given + IOP unit is active, and NULL if it is inactive or non-existent. + + RETURN VALUE. + + Returns 0 if no errors occur, and -1 otherwise. If an error occurs, + errno is set appropriately: + + EFAULT Invalid user space pointer was passed + +IV. Getting Hardware Resource Table + + SYNOPSIS + + ioctl(fd, I2OHRTGET, struct i2o_cmd_hrt *hrt); + + struct i2o_cmd_hrtlct + { + u32 iop; /* IOP unit number */ + void *resbuf; /* Buffer for result */ + u32 *reslen; /* Buffer length in bytes */ + }; + + DESCRIPTION + + This function returns the Hardware Resource Table of the IOP specified + by hrt->iop in the buffer pointed to by hrt->resbuf. The actual size of + the data is written into *(hrt->reslen). + + RETURNS + + This function returns 0 if no errors occur. If an error occurs, -1 + is returned and errno is set appropriately: + + EFAULT Invalid user space pointer was passed + ENXIO Invalid IOP number + ENOBUFS Buffer not large enough. If this occurs, the required + buffer length is written into *(hrt->reslen) + +V. Getting Logical Configuration Table + + SYNOPSIS + + ioctl(fd, I2OLCTGET, struct i2o_cmd_lct *lct); + + struct i2o_cmd_hrtlct + { + u32 iop; /* IOP unit number */ + void *resbuf; /* Buffer for result */ + u32 *reslen; /* Buffer length in bytes */ + }; + + DESCRIPTION + + This function returns the Logical Configuration Table of the IOP specified + by lct->iop in the buffer pointed to by lct->resbuf. The actual size of + the data is written into *(lct->reslen). + + RETURNS + + This function returns 0 if no errors occur. If an error occurs, -1 + is returned and errno is set appropriately: + + EFAULT Invalid user space pointer was passed + ENXIO Invalid IOP number + ENOBUFS Buffer not large enough. If this occurs, the required + buffer length is written into *(lct->reslen) + +VI. Settting Parameters + + SYNOPSIS + + ioctl(fd, I2OPARMSET, struct i2o_parm_setget *ops); + + struct i2o_cmd_psetget + { + u32 iop; /* IOP unit number */ + u32 tid; /* Target device TID */ + void *opbuf; /* Operation List buffer */ + u32 oplen; /* Operation List buffer length in bytes */ + void *resbuf; /* Result List buffer */ + u32 *reslen; /* Result List buffer length in bytes */ + }; + + DESCRIPTION + + This function posts a UtilParamsSet message to the device identified + by ops->iop and ops->tid. The operation list for the message is + sent through the ops->opbuf buffer, and the result list is written + into the buffer pointed to by ops->resbuf. The number of bytes + written is placed into *(ops->reslen). + + RETURNS + + The return value is the size in bytes of the data written into + ops->resbuf if no errors occur. If an error occurs, -1 is returned + and errno is set appropriatly: + + EFAULT Invalid user space pointer was passed + ENXIO Invalid IOP number + ENOBUFS Buffer not large enough. If this occurs, the required + buffer length is written into *(ops->reslen) + ETIMEDOUT Timeout waiting for reply message + ENOMEM Kernel memory allocation error + + A return value of 0 does not mean that the value was actually + changed properly on the IOP. The user should check the result + list to determine the specific status of the transaction. + +VII. Getting Parameters + + SYNOPSIS + + ioctl(fd, I2OPARMGET, struct i2o_parm_setget *ops); + + struct i2o_parm_setget + { + u32 iop; /* IOP unit number */ + u32 tid; /* Target device TID */ + void *opbuf; /* Operation List buffer */ + u32 oplen; /* Operation List buffer length in bytes */ + void *resbuf; /* Result List buffer */ + u32 *reslen; /* Result List buffer length in bytes */ + }; + + DESCRIPTION + + This function posts a UtilParamsGet message to the device identified + by ops->iop and ops->tid. The operation list for the message is + sent through the ops->opbuf buffer, and the result list is written + into the buffer pointed to by ops->resbuf. The actual size of data + written is placed into *(ops->reslen). + + RETURNS + + EFAULT Invalid user space pointer was passed + ENXIO Invalid IOP number + ENOBUFS Buffer not large enough. If this occurs, the required + buffer length is written into *(ops->reslen) + ETIMEDOUT Timeout waiting for reply message + ENOMEM Kernel memory allocation error + + A return value of 0 does not mean that the value was actually + properly retreived. The user should check the result list + to determine the specific status of the transaction. + +VIII. Downloading Software + + SYNOPSIS + + ioctl(fd, I2OSWDL, struct i2o_sw_xfer *sw); + + struct i2o_sw_xfer + { + u32 iop; /* IOP unit number */ + u8 flags; /* DownloadFlags field */ + u8 sw_type; /* Software type */ + u32 sw_id; /* Software ID */ + void *buf; /* Pointer to software buffer */ + u32 *swlen; /* Length of software buffer */ + u32 *maxfrag; /* Number of fragments */ + u32 *curfrag; /* Current fragment number */ + }; + + DESCRIPTION + + This function downloads a software fragment pointed by sw->buf + to the iop identified by sw->iop. The DownloadFlags, SwID, SwType + and SwSize fields of the ExecSwDownload message are filled in with + the values of sw->flags, sw->sw_id, sw->sw_type and *(sw->swlen). + + The fragments _must_ be sent in order and be 8K in size. The last + fragment _may_ be shorter, however. The kernel will compute its + size based on information in the sw->swlen field. + + Please note that SW transfers can take a long time. + + RETURNS + + This function returns 0 no errors occur. If an error occurs, -1 + is returned and errno is set appropriatly: + + EFAULT Invalid user space pointer was passed + ENXIO Invalid IOP number + ETIMEDOUT Timeout waiting for reply message + ENOMEM Kernel memory allocation error + +IX. Uploading Software + + SYNOPSIS + + ioctl(fd, I2OSWUL, struct i2o_sw_xfer *sw); + + struct i2o_sw_xfer + { + u32 iop; /* IOP unit number */ + u8 flags; /* UploadFlags */ + u8 sw_type; /* Software type */ + u32 sw_id; /* Software ID */ + void *buf; /* Pointer to software buffer */ + u32 *swlen; /* Length of software buffer */ + u32 *maxfrag; /* Number of fragments */ + u32 *curfrag; /* Current fragment number */ + }; + + DESCRIPTION + + This function uploads a software fragment from the IOP identified + by sw->iop, sw->sw_type, sw->sw_id and optionally sw->swlen fields. + The UploadFlags, SwID, SwType and SwSize fields of the ExecSwUpload + message are filled in with the values of sw->flags, sw->sw_id, + sw->sw_type and *(sw->swlen). + + The fragments _must_ be requested in order and be 8K in size. The + user is responsible for allocating memory pointed by sw->buf. The + last fragment _may_ be shorter. + + Please note that SW transfers can take a long time. + + RETURNS + + This function returns 0 if no errors occur. If an error occurs, -1 + is returned and errno is set appropriatly: + + EFAULT Invalid user space pointer was passed + ENXIO Invalid IOP number + ETIMEDOUT Timeout waiting for reply message + ENOMEM Kernel memory allocation error + +X. Removing Software + + SYNOPSIS + + ioctl(fd, I2OSWDEL, struct i2o_sw_xfer *sw); + + struct i2o_sw_xfer + { + u32 iop; /* IOP unit number */ + u8 flags; /* RemoveFlags */ + u8 sw_type; /* Software type */ + u32 sw_id; /* Software ID */ + void *buf; /* Unused */ + u32 *swlen; /* Length of the software data */ + u32 *maxfrag; /* Unused */ + u32 *curfrag; /* Unused */ + }; + + DESCRIPTION + + This function removes software from the IOP identified by sw->iop. + The RemoveFlags, SwID, SwType and SwSize fields of the ExecSwRemove message + are filled in with the values of sw->flags, sw->sw_id, sw->sw_type and + *(sw->swlen). Give zero in *(sw->len) if the value is unknown. IOP uses + *(sw->swlen) value to verify correct identication of the module to remove. + The actual size of the module is written into *(sw->swlen). + + RETURNS + + This function returns 0 if no errors occur. If an error occurs, -1 + is returned and errno is set appropriatly: + + EFAULT Invalid user space pointer was passed + ENXIO Invalid IOP number + ETIMEDOUT Timeout waiting for reply message + ENOMEM Kernel memory allocation error + +X. Validating Configuration + + SYNOPSIS + + ioctl(fd, I2OVALIDATE, int *iop); + u32 iop; + + DESCRIPTION + + This function posts an ExecConfigValidate message to the controller + identified by iop. This message indicates that the the current + configuration is accepted. The iop changes the status of suspect drivers + to valid and may delete old drivers from its store. + + RETURNS + + This function returns 0 if no erro occur. If an error occurs, -1 is + returned and errno is set appropriatly: + + ETIMEDOUT Timeout waiting for reply message + ENXIO Invalid IOP number + +XI. Configuration Dialog + + SYNOPSIS + + ioctl(fd, I2OHTML, struct i2o_html *htquery); + struct i2o_html + { + u32 iop; /* IOP unit number */ + u32 tid; /* Target device ID */ + u32 page; /* HTML page */ + void *resbuf; /* Buffer for reply HTML page */ + u32 *reslen; /* Length in bytes of reply buffer */ + void *qbuf; /* Pointer to HTTP query string */ + u32 qlen; /* Length in bytes of query string buffer */ + }; + + DESCRIPTION + + This function posts an UtilConfigDialog message to the device identified + by htquery->iop and htquery->tid. The requested HTML page number is + provided by the htquery->page field, and the resultant data is stored + in the buffer pointed to by htquery->resbuf. If there is an HTTP query + string that is to be sent to the device, it should be sent in the buffer + pointed to by htquery->qbuf. If there is no query string, this field + should be set to NULL. The actual size of the reply received is written + into *(htquery->reslen). + + RETURNS + + This function returns 0 if no error occur. If an error occurs, -1 + is returned and errno is set appropriatly: + + EFAULT Invalid user space pointer was passed + ENXIO Invalid IOP number + ENOBUFS Buffer not large enough. If this occurs, the required + buffer length is written into *(ops->reslen) + ETIMEDOUT Timeout waiting for reply message + ENOMEM Kernel memory allocation error + +XII. Events + + In the process of determining this. Current idea is to have use + the select() interface to allow user apps to periodically poll + the /dev/i2o/ctl device for events. When select() notifies the user + that an event is available, the user would call read() to retrieve + a list of all the events that are pending for the specific device. + +============================================================================= +Revision History +============================================================================= + +Rev 0.1 - 04/01/99 +- Initial revision + +Rev 0.2 - 04/06/99 +- Changed return values to match UNIX ioctl() standard. Only return values + are 0 and -1. All errors are reported through errno. +- Added summary of proposed possible event interfaces + +Rev 0.3 - 04/20/99 +- Changed all ioctls() to use pointers to user data instead of actual data +- Updated error values to match the code diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/i2o/i2o_block.c linux.ac/drivers/message/i2o/i2o_block.c --- linux.vanilla/drivers/message/i2o/i2o_block.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/i2o/i2o_block.c Tue Apr 3 23:23:37 2001 @@ -0,0 +1,1878 @@ +/* + * I2O Random Block Storage Class OSM + * + * (C) Copyright 1999 Red Hat Software + * + * Written by Alan Cox, Building Number Three 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 is a beta test release. Most of the good code was taken + * from the nbd driver by Pavel Machek, who in turn took some of it + * from loop.c. Isn't free software great for reusability 8) + * + * Fixes/additions: + * Steve Ralston: + * Multiple device handling error fixes, + * Added a queue depth. + * Alan Cox: + * FC920 has an rmw bug. Dont or in the end marker. + * Removed queue walk, fixed for 64bitness. + * Deepak Saxena: + * Independent queues per IOP + * Support for dynamic device creation/deletion + * Code cleanup + * Support for larger I/Os through merge* functions + * (taken from DAC960 driver) + * Boji T Kannanthanam: + * Set the I2O Block devices to be detected in increasing + * order of TIDs during boot. + * Search and set the I2O block device that we boot off from as + * the first device to be claimed (as /dev/i2o/hda) + * Properly attach/detach I2O gendisk structure from the system + * gendisk list. The I2O block devices now appear in + * /proc/partitions. + * + * To do: + * Serial number scanning to find duplicates for FC multipathing + */ + +#include <linux/major.h> + +#include <linux/module.h> + +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/stat.h> +#include <linux/errno.h> +#include <linux/file.h> +#include <linux/ioctl.h> +#include <linux/i2o.h> +#include <linux/blkdev.h> +#include <linux/blkpg.h> +#include <linux/slab.h> +#include <linux/hdreg.h> + +#include <linux/notifier.h> +#include <linux/reboot.h> + +#include <asm/uaccess.h> +#include <asm/semaphore.h> +#include <asm/io.h> +#include <asm/atomic.h> +#include <linux/smp_lock.h> +#include <linux/wait.h> + +#define MAJOR_NR I2O_MAJOR + +#include <linux/blk.h> + +#define MAX_I2OB 16 + +#define MAX_I2OB_DEPTH 128 +#define MAX_I2OB_RETRIES 4 + +//#define DRIVERDEBUG +#ifdef DRIVERDEBUG +#define DEBUG( s ) +#else +#define DEBUG( s ) printk( s ) +#endif + +/* + * Events that this OSM is interested in + */ +#define I2OB_EVENT_MASK (I2O_EVT_IND_BSA_VOLUME_LOAD | \ + I2O_EVT_IND_BSA_VOLUME_UNLOAD | \ + I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ | \ + I2O_EVT_IND_BSA_CAPACITY_CHANGE | \ + I2O_EVT_IND_BSA_SCSI_SMART ) + + +/* + * I2O Block Error Codes - should be in a header file really... + */ +#define I2O_BSA_DSC_SUCCESS 0x0000 +#define I2O_BSA_DSC_MEDIA_ERROR 0x0001 +#define I2O_BSA_DSC_ACCESS_ERROR 0x0002 +#define I2O_BSA_DSC_DEVICE_FAILURE 0x0003 +#define I2O_BSA_DSC_DEVICE_NOT_READY 0x0004 +#define I2O_BSA_DSC_MEDIA_NOT_PRESENT 0x0005 +#define I2O_BSA_DSC_MEDIA_LOCKED 0x0006 +#define I2O_BSA_DSC_MEDIA_FAILURE 0x0007 +#define I2O_BSA_DSC_PROTOCOL_FAILURE 0x0008 +#define I2O_BSA_DSC_BUS_FAILURE 0x0009 +#define I2O_BSA_DSC_ACCESS_VIOLATION 0x000A +#define I2O_BSA_DSC_WRITE_PROTECTED 0x000B +#define I2O_BSA_DSC_DEVICE_RESET 0x000C +#define I2O_BSA_DSC_VOLUME_CHANGED 0x000D +#define I2O_BSA_DSC_TIMEOUT 0x000E + +/* + * Some of these can be made smaller later + */ + +static int i2ob_blksizes[MAX_I2OB<<4]; +static int i2ob_hardsizes[MAX_I2OB<<4]; +static int i2ob_sizes[MAX_I2OB<<4]; +static int i2ob_media_change_flag[MAX_I2OB]; +static u32 i2ob_max_sectors[MAX_I2OB<<4]; + +static int i2ob_context; + +/* + * I2O Block device descriptor + */ +struct i2ob_device +{ + struct i2o_controller *controller; + struct i2o_device *i2odev; + int unit; + int tid; + int flags; + int refcnt; + struct request *head, *tail; + request_queue_t *req_queue; + int max_segments; + int done_flag; +}; + +/* + * FIXME: + * We should cache align these to avoid ping-ponging lines on SMP + * boxes under heavy I/O load... + */ +struct i2ob_request +{ + struct i2ob_request *next; + struct request *req; + int num; +}; + +/* + * Per IOP requst queue information + * + * We have a separate requeust_queue_t per IOP so that a heavilly + * loaded I2O block device on an IOP does not starve block devices + * across all I2O controllers. + * + */ +struct i2ob_iop_queue +{ + atomic_t queue_depth; + struct i2ob_request request_queue[MAX_I2OB_DEPTH]; + struct i2ob_request *i2ob_qhead; + request_queue_t req_queue; +}; +static struct i2ob_iop_queue *i2ob_queues[MAX_I2O_CONTROLLERS] = {NULL}; + +/* + * Each I2O disk is one of these. + */ + +static struct i2ob_device i2ob_dev[MAX_I2OB<<4]; +static int i2ob_dev_count = 0; +static struct hd_struct i2ob[MAX_I2OB<<4]; +static struct gendisk i2ob_gendisk; /* Declared later */ + +/* + * Mutex and spin lock for event handling synchronization + * evt_msg contains the last event. + */ +static DECLARE_MUTEX_LOCKED(i2ob_evt_sem); +static DECLARE_MUTEX_LOCKED(i2ob_thread_dead); +static spinlock_t i2ob_evt_lock = SPIN_LOCK_UNLOCKED; +static u32 evt_msg[MSG_FRAME_SIZE>>2]; + +static struct timer_list i2ob_timer; +static int i2ob_timer_started = 0; + +static void i2o_block_reply(struct i2o_handler *, struct i2o_controller *, + struct i2o_message *); +static void i2ob_new_device(struct i2o_controller *, struct i2o_device *); +static void i2ob_del_device(struct i2o_controller *, struct i2o_device *); +static void i2ob_reboot_event(void); +static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int); +static void i2ob_end_request(struct request *); +static void i2ob_request(request_queue_t *); +static int i2ob_init_iop(unsigned int); +static request_queue_t* i2ob_get_queue(kdev_t); +static int i2ob_query_device(struct i2ob_device *, int, int, void*, int); +static int do_i2ob_revalidate(kdev_t, int); +static int i2ob_evt(void *); + +static int evt_pid = 0; +static int evt_running = 0; +static int scan_unit = 0; + +/* + * I2O OSM registration structure...keeps getting bigger and bigger :) + */ +static struct i2o_handler i2o_block_handler = +{ + i2o_block_reply, + i2ob_new_device, + i2ob_del_device, + i2ob_reboot_event, + "I2O Block OSM", + 0, + I2O_CLASS_RANDOM_BLOCK_STORAGE +}; + +/* + * Get a message + */ + +static u32 i2ob_get(struct i2ob_device *dev) +{ + struct i2o_controller *c=dev->controller; + return I2O_POST_READ32(c); +} + +/* + * Turn a Linux block request into an I2O block read/write. + */ + +static int i2ob_send(u32 m, struct i2ob_device *dev, struct i2ob_request *ireq, u32 base, int unit) +{ + struct i2o_controller *c = dev->controller; + int tid = dev->tid; + unsigned long msg; + unsigned long mptr; + u64 offset; + struct request *req = ireq->req; + struct buffer_head *bh = req->bh; + int count = req->nr_sectors<<9; + char *last = NULL; + unsigned short size = 0; + + // printk(KERN_INFO "i2ob_send called\n"); + /* Map the message to a virtual address */ + msg = c->mem_offset + m; + + /* + * Build the message based on the request. + */ + __raw_writel(i2ob_context|(unit<<8), msg+8); + __raw_writel(ireq->num, msg+12); + __raw_writel(req->nr_sectors << 9, msg+20); + + /* This can be optimised later - just want to be sure its right for + starters */ + offset = ((u64)(req->sector+base)) << 9; + __raw_writel( offset & 0xFFFFFFFF, msg+24); + __raw_writel(offset>>32, msg+28); + mptr=msg+32; + + if(req->cmd == READ) + { + __raw_writel(I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid, msg+4); + /* We don't yet do cache/readahead and other magic */ + __raw_writel(1<<16, msg+16); + while(bh!=NULL) + { + if(bh->b_data == last) { + size += bh->b_size; + last += bh->b_size; + if(bh->b_reqnext) + __raw_writel(0x14000000|(size), mptr-8); + else + __raw_writel(0xD4000000|(size), mptr-8); + } + else + { + if(bh->b_reqnext) + __raw_writel(0x10000000|(bh->b_size), mptr); + else + __raw_writel(0xD0000000|(bh->b_size), mptr); + __raw_writel(virt_to_bus(bh->b_data), mptr+4); + mptr += 8; + size = bh->b_size; + last = bh->b_data + size; + } + + count -= bh->b_size; + bh = bh->b_reqnext; + } + } + else if(req->cmd == WRITE) + { + __raw_writel(I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid, msg+4); + /* + * Allow replies to come back once data is cached in the controller + * This allows us to handle writes quickly thus giving more of the + * queue to reads. + */ + __raw_writel(0x00000010, msg+16); + while(bh!=NULL) + { + if(bh->b_data == last) { + size += bh->b_size; + last += bh->b_size; + if(bh->b_reqnext) + __raw_writel(0x14000000|(size), mptr-8); + else + __raw_writel(0xD4000000|(size), mptr-8); + } + else + { + if(bh->b_reqnext) + __raw_writel(0x14000000|(bh->b_size), mptr); + else + __raw_writel(0xD4000000|(bh->b_size), mptr); + __raw_writel(virt_to_bus(bh->b_data), mptr+4); + mptr += 8; + size = bh->b_size; + last = bh->b_data + size; + } + + count -= bh->b_size; + bh = bh->b_reqnext; + } + } + __raw_writel(I2O_MESSAGE_SIZE(mptr-msg)>>2 | SGL_OFFSET_8, msg); + + if(req->current_nr_sectors > i2ob_max_sectors[unit]) + printk("Gathered sectors %ld.\n", + req->current_nr_sectors); + + if(count != 0) + { + printk(KERN_ERR "Request count botched by %d.\n", count); + } + + i2o_post_message(c,m); + atomic_inc(&i2ob_queues[c->unit]->queue_depth); + + return 0; +} + +/* + * Remove a request from the _locked_ request list. We update both the + * list chain and if this is the last item the tail pointer. Caller + * must hold the lock. + */ + +static inline void i2ob_unhook_request(struct i2ob_request *ireq, + unsigned int iop) +{ + ireq->next = i2ob_queues[iop]->i2ob_qhead; + i2ob_queues[iop]->i2ob_qhead = ireq; +} + +/* + * Request completion handler + */ + +static inline void i2ob_end_request(struct request *req) +{ + /* + * Loop until all of the buffers that are linked + * to this request have been marked updated and + * unlocked. + */ + + while (end_that_request_first( req, !req->errors, "i2o block" )); + + /* + * It is now ok to complete the request. + */ + end_that_request_last( req ); +} + +/* + * Request merging functions + */ +static inline int i2ob_new_segment(request_queue_t *q, struct request *req, + int __max_segments) +{ + int max_segments = i2ob_dev[MINOR(req->rq_dev)].max_segments; + + if (__max_segments < max_segments) + max_segments = __max_segments; + + if (req->nr_segments < max_segments) { + req->nr_segments++; + return 1; + } + return 0; +} + +static int i2ob_back_merge(request_queue_t *q, struct request *req, + struct buffer_head *bh, int __max_segments) +{ + if (req->bhtail->b_data + req->bhtail->b_size == bh->b_data) + return 1; + return i2ob_new_segment(q, req, __max_segments); +} + +static int i2ob_front_merge(request_queue_t *q, struct request *req, + struct buffer_head *bh, int __max_segments) +{ + if (bh->b_data + bh->b_size == req->bh->b_data) + return 1; + return i2ob_new_segment(q, req, __max_segments); +} + +static int i2ob_merge_requests(request_queue_t *q, + struct request *req, + struct request *next, + int __max_segments) +{ + int max_segments = i2ob_dev[MINOR(req->rq_dev)].max_segments; + int total_segments = req->nr_segments + next->nr_segments; + + if (__max_segments < max_segments) + max_segments = __max_segments; + + if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data) + total_segments--; + + if (total_segments > max_segments) + return 0; + + req->nr_segments = total_segments; + return 1; +} + + +/* + * OSM reply handler. This gets all the message replies + */ + +static void i2o_block_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg) +{ + unsigned long flags; + struct i2ob_request *ireq = NULL; + u8 st; + u32 *m = (u32 *)msg; + u8 unit = (m[2]>>8)&0xF0; /* low 4 bits are partition */ + struct i2ob_device *dev = &i2ob_dev[(unit&0xF0)]; + + /* + * FAILed message + */ + if(m[0] & (1<<13)) + { + /* + * FAILed message from controller + * We increment the error count and abort it + * + * In theory this will never happen. The I2O block class + * speficiation states that block devices never return + * FAILs but instead use the REQ status field...but + * better be on the safe side since no one really follows + * the spec to the book :) + */ + ireq=&i2ob_queues[c->unit]->request_queue[m[3]]; + ireq->req->errors++; + + spin_lock_irqsave(&io_request_lock, flags); + i2ob_unhook_request(ireq, c->unit); + i2ob_end_request(ireq->req); + spin_unlock_irqrestore(&io_request_lock, flags); + + /* Now flush the message by making it a NOP */ + m[0]&=0x00FFFFFF; + m[0]|=(I2O_CMD_UTIL_NOP)<<24; + i2o_post_message(c,virt_to_bus(m)); + + return; + } + + if(msg->function == I2O_CMD_UTIL_EVT_REGISTER) + { + spin_lock(&i2ob_evt_lock); + memcpy(evt_msg, msg, (m[0]>>16)<<2); + spin_unlock(&i2ob_evt_lock); + up(&i2ob_evt_sem); + return; + } + + if(!dev->i2odev) + { + /* + * This is HACK, but Intel Integrated RAID allows user + * to delete a volume that is claimed, locked, and in use + * by the OS. We have to check for a reply from a + * non-existent device and flag it as an error or the system + * goes kaput... + */ + ireq=&i2ob_queues[c->unit]->request_queue[m[3]]; + ireq->req->errors++; + printk(KERN_WARNING "I2O Block: Data transfer to deleted device!\n"); + spin_lock_irqsave(&io_request_lock, flags); + i2ob_unhook_request(ireq, c->unit); + i2ob_end_request(ireq->req); + spin_unlock_irqrestore(&io_request_lock, flags); + return; + } + + /* + * Lets see what is cooking. We stuffed the + * request in the context. + */ + + ireq=&i2ob_queues[c->unit]->request_queue[m[3]]; + st=m[4]>>24; + + if(st!=0) + { + char *bsa_errors[] = + { + "Success", + "Media Error", + "Failure communicating to device", + "Device Failure", + "Device is not ready", + "Media not present", + "Media is locked by another user", + "Media has failed", + "Failure communicating to device", + "Device bus failure", + "Device is locked by another user", + "Device is write protected", + "Device has reset", + "Volume has changed, waiting for acknowledgement" + }; + + printk(KERN_ERR "\n/dev/%s error: %s", dev->i2odev->dev_name, + bsa_errors[m[4]&0XFFFF]); + if(m[4]&0x00FF0000) + printk(" - DDM attempted %d retries", (m[4]>>16)&0x00FF ); + printk("\n"); + + ireq->req->errors++; + } + else + ireq->req->errors = 0; + + /* + * Dequeue the request. We use irqsave locks as one day we + * may be running polled controllers from a BH... + */ + + spin_lock_irqsave(&io_request_lock, flags); + i2ob_unhook_request(ireq, c->unit); + i2ob_end_request(ireq->req); + atomic_dec(&i2ob_queues[c->unit]->queue_depth); + + /* + * We may be able to do more I/O + */ + i2ob_request(dev->req_queue); + + spin_unlock_irqrestore(&io_request_lock, flags); +} + +/* + * Event handler. Needs to be a separate thread b/c we may have + * to do things like scan a partition table, or query parameters + * which cannot be done from an interrupt or from a bottom half. + */ +static int i2ob_evt(void *dummy) +{ + unsigned int evt; + unsigned int flags; + int unit; + int i; + //The only event that has data is the SCSI_SMART event. + struct i2o_reply { + u32 header[4]; + u32 evt_indicator; + u8 ASC; + u8 ASCQ; + u8 data[16]; + } *evt_local; + + lock_kernel(); + daemonize(); + unlock_kernel(); + + strcpy(current->comm, "i2oblock"); + evt_running = 1; + + while(1) + { + if(down_interruptible(&i2ob_evt_sem)) + { + evt_running = 0; + printk("exiting..."); + break; + } + + /* + * Keep another CPU/interrupt from overwriting the + * message while we're reading it + * + * We stuffed the unit in the TxContext and grab the event mask + * None of the BSA we care about events have EventData + */ + spin_lock_irqsave(&i2ob_evt_lock, flags); + evt_local = (struct i2o_reply *)evt_msg; + spin_unlock_irqrestore(&i2ob_evt_lock, flags); + + unit = evt_local->header[3]; + evt = evt_local->evt_indicator; + + switch(evt) + { + /* + * New volume loaded on same TID, so we just re-install. + * The TID/controller don't change as it is the same + * I2O device. It's just new media that we have to + * rescan. + */ + case I2O_EVT_IND_BSA_VOLUME_LOAD: + { + i2ob_install_device(i2ob_dev[unit].i2odev->controller, + i2ob_dev[unit].i2odev, unit); + break; + } + + /* + * No media, so set all parameters to 0 and set the media + * change flag. The I2O device is still valid, just doesn't + * have media, so we don't want to clear the controller or + * device pointer. + */ + case I2O_EVT_IND_BSA_VOLUME_UNLOAD: + { + for(i = unit; i <= unit+15; i++) + { + i2ob_sizes[i] = 0; + i2ob_hardsizes[i] = 0; + i2ob_max_sectors[i] = 0; + i2ob[i].nr_sects = 0; + i2ob_gendisk.part[i].nr_sects = 0; + } + i2ob_media_change_flag[unit] = 1; + break; + } + + case I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ: + printk(KERN_WARNING "%s: Attempt to eject locked media\n", + i2ob_dev[unit].i2odev->dev_name); + break; + + /* + * The capacity has changed and we are going to be + * updating the max_sectors and other information + * about this disk. We try a revalidate first. If + * the block device is in use, we don't want to + * do that as there may be I/Os bound for the disk + * at the moment. In that case we read the size + * from the device and update the information ourselves + * and the user can later force a partition table + * update through an ioctl. + */ + case I2O_EVT_IND_BSA_CAPACITY_CHANGE: + { + u64 size; + + if(do_i2ob_revalidate(MKDEV(MAJOR_NR, unit),0) != -EBUSY) + continue; + + if(i2ob_query_device(&i2ob_dev[unit], 0x0004, 0, &size, 8) !=0 ) + i2ob_query_device(&i2ob_dev[unit], 0x0000, 4, &size, 8); + + spin_lock_irqsave(&io_request_lock, flags); + i2ob_sizes[unit] = (int)(size>>10); + i2ob_gendisk.part[unit].nr_sects = size>>9; + i2ob[unit].nr_sects = (int)(size>>9); + spin_unlock_irqrestore(&io_request_lock, flags); + break; + } + + /* + * We got a SCSI SMART event, we just log the relevant + * information and let the user decide what they want + * to do with the information. + */ + case I2O_EVT_IND_BSA_SCSI_SMART: + { + char buf[16]; + printk(KERN_INFO "I2O Block: %s received a SCSI SMART Event\n",i2ob_dev[unit].i2odev->dev_name); + evt_local->data[16]='\0'; + sprintf(buf,"%s",&evt_local->data[0]); + printk(KERN_INFO " Disk Serial#:%s\n",buf); + printk(KERN_INFO " ASC 0x%02x \n",evt_local->ASC); + printk(KERN_INFO " ASCQ 0x%02x \n",evt_local->ASCQ); + break; + } + + /* + * Non event + */ + + case 0: + break; + + /* + * An event we didn't ask for. Call the card manufacturer + * and tell them to fix their firmware :) + */ + default: + printk(KERN_INFO "%s: Received event %d we didn't register for\n" + KERN_INFO " Blame the I2O card manufacturer 8)\n", + i2ob_dev[unit].i2odev->dev_name, evt); + break; + } + }; + + up_and_exit(&i2ob_thread_dead,0); + return 0; +} + +/* + * The timer handler will attempt to restart requests + * that are queued to the driver. This handler + * currently only gets called if the controller + * had no more room in its inbound fifo. + */ + +static void i2ob_timer_handler(unsigned long q) +{ + unsigned long flags; + + /* + * We cannot touch the request queue or the timer + * flag without holding the io_request_lock. + */ + spin_lock_irqsave(&io_request_lock,flags); + + /* + * Clear the timer started flag so that + * the timer can be queued again. + */ + i2ob_timer_started = 0; + + /* + * Restart any requests. + */ + i2ob_request((request_queue_t*)q); + + /* + * Free the lock. + */ + spin_unlock_irqrestore(&io_request_lock,flags); +} + +/* + * The I2O block driver is listed as one of those that pulls the + * front entry off the queue before processing it. This is important + * to remember here. If we drop the io lock then CURRENT will change + * on us. We must unlink CURRENT in this routine before we return, if + * we use it. + */ +static void i2ob_request(request_queue_t *q) +{ + struct request *req; + struct i2ob_request *ireq; + int unit; + struct i2ob_device *dev; + u32 m; + + // printk(KERN_INFO "i2ob_request() called with queue %p\n", q); + + while (!list_empty(&q->queue_head)) { + /* + * On an IRQ completion if there is an inactive + * request on the queue head it means it isnt yet + * ready to dispatch. + */ + req = blkdev_entry_next_request(&q->queue_head); + + if(req->rq_status == RQ_INACTIVE) + return; + + unit = MINOR(req->rq_dev); + dev = &i2ob_dev[(unit&0xF0)]; + + /* + * Queue depths probably belong with some kind of + * generic IOP commit control. Certainly its not right + * its global! + */ + if(atomic_read(&i2ob_queues[dev->unit]->queue_depth)>=MAX_I2OB_DEPTH) + break; + + /* Get a message */ + m = i2ob_get(dev); + + if(m==0xFFFFFFFF) + { + /* + * See if the timer has already been queued. + */ + if (!i2ob_timer_started) + { + printk(KERN_ERR "i2ob: starting timer\n"); + + /* + * Set the timer_started flag to insure + * that the timer is only queued once. + * Queing it more than once will corrupt + * the timer queue. + */ + i2ob_timer_started = 1; + + /* + * Set up the timer to expire in + * 500ms. + */ + i2ob_timer.expires = jiffies + (HZ >> 1); + i2ob_timer.data = (unsigned int)q; + + /* + * Start it. + */ + + add_timer(&i2ob_timer); + return; + } + } + + /* + * Everything ok, so pull from kernel queue onto our queue + */ + req->errors = 0; + blkdev_dequeue_request(req); + req->sem = NULL; + + ireq = i2ob_queues[dev->unit]->i2ob_qhead; + i2ob_queues[dev->unit]->i2ob_qhead = ireq->next; + ireq->req = req; + + i2ob_send(m, dev, ireq, i2ob[unit].start_sect, (unit&0xF0)); + } +} + + +/* + * SCSI-CAM for ioctl geometry mapping + * Duplicated with SCSI - this should be moved into somewhere common + * perhaps genhd ? + * + * LBA -> CHS mapping table taken from: + * + * "Incorporating the I2O Architecture into BIOS for Intel Architecture + * Platforms" + * + * This is an I2O document that is only available to I2O members, + * not developers. + * + * From my understanding, this is how all the I2O cards do this + * + * Disk Size | Sectors | Heads | Cylinders + * ---------------+---------+-------+------------------- + * 1 < X <= 528M | 63 | 16 | X/(63 * 16 * 512) + * 528M < X <= 1G | 63 | 32 | X/(63 * 32 * 512) + * 1 < X <528M | 63 | 16 | X/(63 * 16 * 512) + * 1 < X <528M | 63 | 16 | X/(63 * 16 * 512) + * + */ +#define BLOCK_SIZE_528M 1081344 +#define BLOCK_SIZE_1G 2097152 +#define BLOCK_SIZE_21G 4403200 +#define BLOCK_SIZE_42G 8806400 +#define BLOCK_SIZE_84G 17612800 + +static void i2o_block_biosparam( + unsigned long capacity, + unsigned short *cyls, + unsigned char *hds, + unsigned char *secs) +{ + unsigned long heads, sectors, cylinders; + + sectors = 63L; /* Maximize sectors per track */ + if(capacity <= BLOCK_SIZE_528M) + heads = 16; + else if(capacity <= BLOCK_SIZE_1G) + heads = 32; + else if(capacity <= BLOCK_SIZE_21G) + heads = 64; + else if(capacity <= BLOCK_SIZE_42G) + heads = 128; + else + heads = 255; + + cylinders = capacity / (heads * sectors); + + *cyls = (unsigned short) cylinders; /* Stuff return values */ + *secs = (unsigned char) sectors; + *hds = (unsigned char) heads; +} + + +/* + * Rescan the partition tables + */ + +static int do_i2ob_revalidate(kdev_t dev, int maxu) +{ + int minor=MINOR(dev); + int i; + + minor&=0xF0; + + i2ob_dev[minor].refcnt++; + if(i2ob_dev[minor].refcnt>maxu+1) + { + i2ob_dev[minor].refcnt--; + return -EBUSY; + } + + for( i = 15; i>=0 ; i--) + { + int m = minor+i; + kdev_t d = MKDEV(MAJOR_NR, m); + struct super_block *sb = get_super(d); + + sync_dev(d); + if(sb) + invalidate_inodes(sb); + invalidate_buffers(d); + i2ob_gendisk.part[m].start_sect = 0; + i2ob_gendisk.part[m].nr_sects = 0; + } + + /* + * Do a physical check and then reconfigure + */ + + i2ob_install_device(i2ob_dev[minor].controller, i2ob_dev[minor].i2odev, + minor); + i2ob_dev[minor].refcnt--; + return 0; +} + +/* + * Issue device specific ioctl calls. + */ + +static int i2ob_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct i2ob_device *dev; + int minor; + + /* Anyone capable of this syscall can do *real bad* things */ + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!inode) + return -EINVAL; + minor = MINOR(inode->i_rdev); + if (minor >= (MAX_I2OB<<4)) + return -ENODEV; + + dev = &i2ob_dev[minor]; + switch (cmd) { + case BLKGETSIZE: + return put_user(i2ob[minor].nr_sects, (long *) arg); + + case HDIO_GETGEO: + { + struct hd_geometry g; + int u=minor&0xF0; + i2o_block_biosparam(i2ob_sizes[u]<<1, + &g.cylinders, &g.heads, &g.sectors); + g.start = i2ob[minor].start_sect; + return copy_to_user((void *)arg,&g, sizeof(g))?-EFAULT:0; + } + + case BLKRRPART: + if(!capable(CAP_SYS_ADMIN)) + return -EACCES; + return do_i2ob_revalidate(inode->i_rdev,1); + + case BLKFLSBUF: + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKPG: + return blk_ioctl(inode->i_rdev, cmd, arg); + + default: + return -EINVAL; + } +} + +/* + * Close the block device down + */ + +static int i2ob_release(struct inode *inode, struct file *file) +{ + struct i2ob_device *dev; + int minor; + + minor = MINOR(inode->i_rdev); + if (minor >= (MAX_I2OB<<4)) + return -ENODEV; + dev = &i2ob_dev[(minor&0xF0)]; + + /* + * This is to deail with the case of an application + * opening a device and then the device dissapears while + * it's in use, and then the application tries to release + * it. ex: Unmounting a deleted RAID volume at reboot. + * If we send messages, it will just cause FAILs since + * the TID no longer exists. + */ + if(!dev->i2odev) + return 0; + + /* Sync the device so we don't get errors */ + fsync_dev(inode->i_rdev); + + if (dev->refcnt <= 0) + printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt); + dev->refcnt--; + if(dev->refcnt==0) + { + /* + * Flush the onboard cache on unmount + */ + u32 msg[5]; + int *query_done = &dev->done_flag; + msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid; + msg[2] = i2ob_context|0x40000000; + msg[3] = (u32)query_done; + msg[4] = 60<<16; + i2o_post_wait(dev->controller, msg, 20, 2); + + /* + * Unlock the media + */ + msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid; + msg[2] = i2ob_context|0x40000000; + msg[3] = (u32)query_done; + msg[4] = -1; + i2o_post_wait(dev->controller, msg, 20, 2); + + /* + * Now unclaim the device. + */ + if (i2o_release_device(dev->i2odev, &i2o_block_handler)) + printk(KERN_ERR "i2ob_release: controller rejected unclaim.\n"); + + } + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * Open the block device. + */ + +static int i2ob_open(struct inode *inode, struct file *file) +{ + int minor; + struct i2ob_device *dev; + + if (!inode) + return -EINVAL; + minor = MINOR(inode->i_rdev); + if (minor >= MAX_I2OB<<4) + return -ENODEV; + dev=&i2ob_dev[(minor&0xF0)]; + + if(!dev->i2odev) + return -ENODEV; + + if(dev->refcnt++==0) + { + u32 msg[6]; + + if(i2o_claim_device(dev->i2odev, &i2o_block_handler)) + { + dev->refcnt--; + printk(KERN_INFO "I2O Block: Could not open device\n"); + return -EBUSY; + } + + /* + * Mount the media if needed. Note that we don't use + * the lock bit. Since we have to issue a lock if it + * refuses a mount (quite possible) then we might as + * well just send two messages out. + */ + msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_BLOCK_MMOUNT<<24|HOST_TID<<12|dev->tid; + msg[4] = -1; + msg[5] = 0; + i2o_post_wait(dev->controller, msg, 24, 2); + + /* + * Lock the media + */ + msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_BLOCK_MLOCK<<24|HOST_TID<<12|dev->tid; + msg[4] = -1; + i2o_post_wait(dev->controller, msg, 20, 2); + } + MOD_INC_USE_COUNT; + return 0; +} + +/* + * Issue a device query + */ + +static int i2ob_query_device(struct i2ob_device *dev, int table, + int field, void *buf, int buflen) +{ + return i2o_query_scalar(dev->controller, dev->tid, + table, field, buf, buflen); +} + + +/* + * Install the I2O block device we found. + */ + +static int i2ob_install_device(struct i2o_controller *c, struct i2o_device *d, int unit) +{ + u64 size; + u32 blocksize; + u32 limit; + u8 type; + u32 flags, status; + struct i2ob_device *dev=&i2ob_dev[unit]; + int i; + + /* + * For logging purposes... + */ + printk(KERN_INFO "i2ob: Installing tid %d device at unit %d\n", + d->lct_data.tid, unit); + + /* + * Ask for the current media data. If that isn't supported + * then we ask for the device capacity data + */ + if(i2ob_query_device(dev, 0x0004, 1, &blocksize, 4) != 0 + || i2ob_query_device(dev, 0x0004, 0, &size, 8) !=0 ) + { + i2ob_query_device(dev, 0x0000, 3, &blocksize, 4); + i2ob_query_device(dev, 0x0000, 4, &size, 8); + } + + i2ob_query_device(dev, 0x0000, 5, &flags, 4); + i2ob_query_device(dev, 0x0000, 6, &status, 4); + i2ob_sizes[unit] = (int)(size>>10); + for(i=unit; i <= unit+15 ; i++) + i2ob_hardsizes[i] = blocksize; + i2ob_gendisk.part[unit].nr_sects = size>>9; + i2ob[unit].nr_sects = (int)(size>>9); + + /* Set limit based on inbound frame size */ + limit = (d->controller->status_block->inbound_frame_size - 8)/2; + limit = limit<<9; + + /* + * Max number of Scatter-Gather Elements + */ + + for(i=unit;i<=unit+15;i++) + { + if(d->controller->type == I2O_TYPE_PCI && d->controller->bus.pci.fc920) + { + i2ob_max_sectors[i] = 8; + i2ob_dev[i].max_segments = 8; + } + else + { + i2ob_max_sectors[i]=MAX_SECTORS; + i2ob_dev[i].max_segments = (d->controller->status_block->inbound_frame_size - 8)/2; + } + } + + printk(KERN_INFO "Max segments set to %d\n", + i2ob_dev[unit].max_segments); + printk(KERN_INFO "Byte limit is %d.\n", limit); + + i2ob_query_device(dev, 0x0000, 0, &type, 1); + + sprintf(d->dev_name, "%s%c", i2ob_gendisk.major_name, 'a' + (unit>>4)); + + printk(KERN_INFO "%s: ", d->dev_name); + switch(type) + { + case 0: printk("Disk Storage");break; + case 4: printk("WORM");break; + case 5: printk("CD-ROM");break; + case 7: printk("Optical device");break; + default: + printk("Type %d", type); + } + if(status&(1<<10)) + printk("(RAID)"); + if(((flags & (1<<3)) && !(status & (1<<3))) || + ((flags & (1<<4)) && !(status & (1<<4)))) + { + printk(KERN_INFO " Not loaded.\n"); + return 1; + } + printk("- %dMb, %d byte sectors", + (int)(size>>20), blocksize); + if(status&(1<<0)) + { + u32 cachesize; + i2ob_query_device(dev, 0x0003, 0, &cachesize, 4); + cachesize>>=10; + if(cachesize>4095) + printk(", %dMb cache", cachesize>>10); + else + printk(", %dKb cache", cachesize); + } + printk(".\n"); + printk(KERN_INFO "%s: Maximum sectors/read set to %d.\n", + d->dev_name, i2ob_max_sectors[unit]); + + /* + * If this is the first I2O block device found on this IOP, + * we need to initialize all the queue data structures + * before any I/O can be performed. If it fails, this + * device is useless. + */ + if(!i2ob_queues[c->unit]) { + if(i2ob_init_iop(c->unit)) + return 1; + } + + /* + * This will save one level of lookup/indirection in critical + * code so that we can directly get the queue ptr from the + * device instead of having to go the IOP data structure. + */ + dev->req_queue = &i2ob_queues[c->unit]->req_queue; + + grok_partitions(&i2ob_gendisk, unit>>4, 1<<4, (long)(size>>9)); + + /* + * Register for the events we're interested in and that the + * device actually supports. + */ + i2o_event_register(c, d->lct_data.tid, i2ob_context, unit, + (I2OB_EVENT_MASK & d->lct_data.event_capabilities)); + + return 0; +} + +/* + * Initialize IOP specific queue structures. This is called + * once for each IOP that has a block device sitting behind it. + */ +static int i2ob_init_iop(unsigned int unit) +{ + int i; + + i2ob_queues[unit] = (struct i2ob_iop_queue*) + kmalloc(sizeof(struct i2ob_iop_queue), GFP_ATOMIC); + if(!i2ob_queues[unit]) + { + printk(KERN_WARNING + "Could not allocate request queue for I2O block device!\n"); + return -1; + } + + for(i = 0; i< MAX_I2OB_DEPTH; i++) + { + i2ob_queues[unit]->request_queue[i].next = + &i2ob_queues[unit]->request_queue[i+1]; + i2ob_queues[unit]->request_queue[i].num = i; + } + + /* Queue is MAX_I2OB + 1... */ + i2ob_queues[unit]->request_queue[i].next = NULL; + i2ob_queues[unit]->i2ob_qhead = &i2ob_queues[unit]->request_queue[0]; + atomic_set(&i2ob_queues[unit]->queue_depth, 0); + + blk_init_queue(&i2ob_queues[unit]->req_queue, i2ob_request); + blk_queue_headactive(&i2ob_queues[unit]->req_queue, 0); + i2ob_queues[unit]->req_queue.back_merge_fn = i2ob_back_merge; + i2ob_queues[unit]->req_queue.front_merge_fn = i2ob_front_merge; + i2ob_queues[unit]->req_queue.merge_requests_fn = i2ob_merge_requests; + i2ob_queues[unit]->req_queue.queuedata = &i2ob_queues[unit]; + + return 0; +} + +/* + * Get the request queue for the given device. + */ +static request_queue_t* i2ob_get_queue(kdev_t dev) +{ + int unit = MINOR(dev)&0xF0; + + return i2ob_dev[unit].req_queue; +} + +/* + * Probe the I2O subsytem for block class devices + */ +static void i2ob_scan(int bios) +{ + int i; + int warned = 0; + + struct i2o_device *d, *b=NULL; + struct i2o_controller *c; + struct i2ob_device *dev; + + for(i=0; i< MAX_I2O_CONTROLLERS; i++) + { + c=i2o_find_controller(i); + + if(c==NULL) + continue; + + /* + * The device list connected to the I2O Controller is doubly linked + * Here we traverse the end of the list , and start claiming devices + * from that end. This assures that within an I2O controller atleast + * the newly created volumes get claimed after the older ones, thus + * mapping to same major/minor (and hence device file name) after + * every reboot. + * The exception being: + * 1. If there was a TID reuse. + * 2. There was more than one I2O controller. + */ + + if(!bios) + { + for (d=c->devices;d!=NULL;d=d->next) + if(d->next == NULL) + b = d; + } + else + b = c->devices; + + while(b != NULL) + { + d=b; + if(bios) + b = b->next; + else + b = b->prev; + + if(d->lct_data.class_id!=I2O_CLASS_RANDOM_BLOCK_STORAGE) + continue; + + if(d->lct_data.user_tid != 0xFFF) + continue; + + if(bios) + { + if(d->lct_data.bios_info != 0x80) + continue; + printk(KERN_INFO "Claiming as Boot device: Controller %d, TID %d\n", c->unit, d->lct_data.tid); + } + else + { + if(d->lct_data.bios_info == 0x80) + continue; /*Already claimed on pass 1 */ + } + + if(i2o_claim_device(d, &i2o_block_handler)) + { + printk(KERN_WARNING "i2o_block: Controller %d, TID %d\n", c->unit, + d->lct_data.tid); + printk(KERN_WARNING "\t%sevice refused claim! Skipping installation\n", bios?"Boot d":"D"); + continue; + } + + if(scan_unit<MAX_I2OB<<4) + { + /* + * Get the device and fill in the + * Tid and controller. + */ + dev=&i2ob_dev[scan_unit]; + dev->i2odev = d; + dev->controller = c; + dev->unit = c->unit; + dev->tid = d->lct_data.tid; + + if(i2ob_install_device(c,d,scan_unit)) + printk(KERN_WARNING "Could not install I2O block device\n"); + else + { + scan_unit+=16; + i2ob_dev_count++; + + /* We want to know when device goes away */ + i2o_device_notify_on(d, &i2o_block_handler); + } + } + else + { + if(!warned++) + printk(KERN_WARNING "i2o_block: too many device, registering only %d.\n", scan_unit>>4); + } + i2o_release_device(d, &i2o_block_handler); + } + i2o_unlock_controller(c); + } +} + +static void i2ob_probe(void) +{ + /* + * Some overhead/redundancy involved here, while trying to + * claim the first boot volume encountered as /dev/i2o/hda + * everytime. All the i2o_controllers are searched and the + * first i2o block device marked as bootable is claimed + * If an I2O block device was booted off , the bios sets + * its bios_info field to 0x80, this what we search for. + * Assuming that the bootable volume is /dev/i2o/hda + * everytime will prevent any kernel panic while mounting + * root partition + */ + + printk(KERN_INFO "i2o_block: Checking for Boot device...\n"); + i2ob_scan(1); + + /* + * Now the remainder. + */ + printk(KERN_INFO "i2o_block: Checking for I2O Block devices...\n"); + i2ob_scan(0); +} + + +/* + * New device notification handler. Called whenever a new + * I2O block storage device is added to the system. + * + * Should we spin lock around this to keep multiple devs from + * getting updated at the same time? + * + */ +void i2ob_new_device(struct i2o_controller *c, struct i2o_device *d) +{ + struct i2ob_device *dev; + int unit = 0; + + printk(KERN_INFO "i2o_block: New device detected\n"); + printk(KERN_INFO " Controller %d Tid %d\n",c->unit, d->lct_data.tid); + + /* Check for available space */ + if(i2ob_dev_count>=MAX_I2OB<<4) + { + printk(KERN_ERR "i2o_block: No more devices allowed!\n"); + return; + } + for(unit = 0; unit < (MAX_I2OB<<4); unit += 16) + { + if(!i2ob_dev[unit].i2odev) + break; + } + + if(i2o_claim_device(d, &i2o_block_handler)) + { + printk(KERN_INFO + "i2o_block: Unable to claim device. Installation aborted\n"); + return; + } + + dev = &i2ob_dev[unit]; + dev->i2odev = d; + dev->controller = c; + dev->tid = d->lct_data.tid; + + if(i2ob_install_device(c,d,unit)) + printk(KERN_ERR "i2o_block: Could not install new device\n"); + else + { + i2ob_dev_count++; + i2o_device_notify_on(d, &i2o_block_handler); + } + + i2o_release_device(d, &i2o_block_handler); + + return; +} + +/* + * Deleted device notification handler. Called when a device we + * are talking to has been deleted by the user or some other + * mysterious fource outside the kernel. + */ +void i2ob_del_device(struct i2o_controller *c, struct i2o_device *d) +{ + int unit = 0; + int i = 0; + int flags; + + spin_lock_irqsave(&io_request_lock, flags); + + /* + * Need to do this...we somtimes get two events from the IRTOS + * in a row and that causes lots of problems. + */ + i2o_device_notify_off(d, &i2o_block_handler); + + printk(KERN_INFO "I2O Block Device Deleted\n"); + + for(unit = 0; unit < MAX_I2OB<<4; unit += 16) + { + if(i2ob_dev[unit].i2odev == d) + { + printk(KERN_INFO " /dev/%s: Controller %d Tid %d\n", + d->dev_name, c->unit, d->lct_data.tid); + break; + } + } + if(unit >= MAX_I2OB<<4) + { + printk(KERN_ERR "i2ob_del_device called, but not in dev table!\n"); + spin_unlock_irqrestore(&io_request_lock, flags); + return; + } + + /* + * This will force errors when i2ob_get_queue() is called + * by the kenrel. + */ + i2ob_dev[unit].req_queue = NULL; + for(i = unit; i <= unit+15; i++) + { + i2ob_dev[i].i2odev = NULL; + i2ob_sizes[i] = 0; + i2ob_hardsizes[i] = 0; + i2ob_max_sectors[i] = 0; + i2ob[i].nr_sects = 0; + i2ob_gendisk.part[i].nr_sects = 0; + } + spin_unlock_irqrestore(&io_request_lock, flags); + + /* + * Sync the device...this will force all outstanding I/Os + * to attempt to complete, thus causing error messages. + * We have to do this as the user could immediatelly create + * a new volume that gets assigned the same minor number. + * If there are still outstanding writes to the device, + * that could cause data corruption on the new volume! + * + * The truth is that deleting a volume that you are currently + * accessing will do _bad things_ to your system. This + * handler will keep it from crashing, but must probably + * you'll have to do a 'reboot' to get the system running + * properly. Deleting disks you are using is dumb. + * Umount them first and all will be good! + * + * It's not this driver's job to protect the system from + * dumb user mistakes :) + */ + if(i2ob_dev[unit].refcnt) + fsync_dev(MKDEV(MAJOR_NR,unit)); + + /* + * Decrease usage count for module + */ + while(i2ob_dev[unit].refcnt--) + MOD_DEC_USE_COUNT; + + i2ob_dev[unit].refcnt = 0; + + i2ob_dev[i].tid = 0; + + /* + * Do we need this? + * The media didn't really change...the device is just gone + */ + i2ob_media_change_flag[unit] = 1; + + i2ob_dev_count--; +} + +/* + * Have we seen a media change ? + */ +static int i2ob_media_change(kdev_t dev) +{ + int i=MINOR(dev); + i>>=4; + if(i2ob_media_change_flag[i]) + { + i2ob_media_change_flag[i]=0; + return 1; + } + return 0; +} + +static int i2ob_revalidate(kdev_t dev) +{ + return do_i2ob_revalidate(dev, 0); +} + +/* + * Reboot notifier. This is called by i2o_core when the system + * shuts down. + */ +static void i2ob_reboot_event(void) +{ + int i; + + for(i=0;i<MAX_I2OB;i++) + { + struct i2ob_device *dev=&i2ob_dev[(i<<4)]; + + if(dev->refcnt!=0) + { + /* + * Flush the onboard cache + */ + u32 msg[5]; + int *query_done = &dev->done_flag; + msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid; + msg[2] = i2ob_context|0x40000000; + msg[3] = (u32)query_done; + msg[4] = 60<<16; + i2o_post_wait(dev->controller, msg, 20, 2); + + /* + * Unlock the media + */ + msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid; + msg[2] = i2ob_context|0x40000000; + msg[3] = (u32)query_done; + msg[4] = -1; + i2o_post_wait(dev->controller, msg, 20, 2); + } + } +} + +static struct block_device_operations i2ob_fops = +{ + open: i2ob_open, + release: i2ob_release, + ioctl: i2ob_ioctl, + check_media_change: i2ob_media_change, + revalidate: i2ob_revalidate, +}; + +static struct gendisk i2ob_gendisk = +{ + MAJOR_NR, + "i2o/hd", + 4, + 1<<4, + i2ob, + i2ob_sizes, + MAX_I2OB, + NULL, + NULL, + &i2ob_fops, +}; + + +/* + * And here should be modules and kernel interface + * (Just smiley confuses emacs :-) + */ + +#ifdef MODULE +#define i2o_block_init init_module +#endif + +int i2o_block_init(void) +{ + int i; + + printk(KERN_INFO "I2O Block Storage OSM v0.9\n"); + printk(KERN_INFO " (c) Copyright 1999, 2000 Red Hat Software.\n"); + + /* + * Register the block device interfaces + */ + + if (register_blkdev(MAJOR_NR, "i2o_block", &i2ob_fops)) { + printk(KERN_ERR "Unable to get major number %d for i2o_block\n", + MAJOR_NR); + return -EIO; + } +#ifdef MODULE + printk(KERN_INFO "i2o_block: registered device at major %d\n", MAJOR_NR); +#endif + + /* + * Now fill in the boiler plate + */ + + blksize_size[MAJOR_NR] = i2ob_blksizes; + hardsect_size[MAJOR_NR] = i2ob_hardsizes; + blk_size[MAJOR_NR] = i2ob_sizes; + max_sectors[MAJOR_NR] = i2ob_max_sectors; + blk_dev[MAJOR_NR].queue = i2ob_get_queue; + + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), i2ob_request); + blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0); + + for (i = 0; i < MAX_I2OB << 4; i++) { + i2ob_dev[i].refcnt = 0; + i2ob_dev[i].flags = 0; + i2ob_dev[i].controller = NULL; + i2ob_dev[i].i2odev = NULL; + i2ob_dev[i].tid = 0; + i2ob_dev[i].head = NULL; + i2ob_dev[i].tail = NULL; + i2ob_blksizes[i] = 1024; + i2ob_max_sectors[i] = 2; + } + + /* + * Set up the queue + */ + for(i = 0; i < MAX_I2O_CONTROLLERS; i++) + { + i2ob_queues[i] = NULL; + } + + /* + * Timers + */ + + init_timer(&i2ob_timer); + i2ob_timer.function = i2ob_timer_handler; + i2ob_timer.data = 0; + + /* + * Register the OSM handler as we will need this to probe for + * drives, geometry and other goodies. + */ + + if(i2o_install_handler(&i2o_block_handler)<0) + { + unregister_blkdev(MAJOR_NR, "i2o_block"); + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + printk(KERN_ERR "i2o_block: unable to register OSM.\n"); + return -EINVAL; + } + i2ob_context = i2o_block_handler.context; + + /* + * Initialize event handling thread + */ + init_MUTEX_LOCKED(&i2ob_evt_sem); + evt_pid = kernel_thread(i2ob_evt, NULL, CLONE_SIGHAND); + if(evt_pid < 0) + { + printk(KERN_ERR + "i2o_block: Could not initialize event thread. Aborting\n"); + i2o_remove_handler(&i2o_block_handler); + return 0; + } + + /* + * Finally see what is actually plugged in to our controllers + */ + for (i = 0; i < MAX_I2OB; i++) + register_disk(&i2ob_gendisk, MKDEV(MAJOR_NR,i<<4), 1<<4, + &i2ob_fops, 0); + i2ob_probe(); + + /* + * Adding i2ob_gendisk into the gendisk list. + */ + i2ob_gendisk.next = gendisk_head; + gendisk_head = &i2ob_gendisk; + + return 0; +} + +#ifdef MODULE + +EXPORT_NO_SYMBOLS; +MODULE_AUTHOR("Red Hat Software"); +MODULE_DESCRIPTION("I2O Block Device OSM"); + +void cleanup_module(void) +{ + struct gendisk *gdp; + int i; + + if(evt_running) { + printk(KERN_INFO "Killing I2O block threads..."); + i = kill_proc(evt_pid, SIGTERM, 1); + if(!i) { + printk("waiting..."); + } + /* Be sure it died */ + down(&i2ob_thread_dead); + printk("done.\n"); + } + + /* + * Unregister for updates from any devices..otherwise we still + * get them and the core jumps to random memory :O + */ + if(i2ob_dev_count) { + struct i2o_device *d; + for(i = 0; i < MAX_I2OB; i++) + if((d=i2ob_dev[i<<4].i2odev)) { + i2o_device_notify_off(d, &i2o_block_handler); + i2o_event_register(d->controller, d->lct_data.tid, + i2ob_context, i<<4, 0); + } + } + + /* + * We may get further callbacks for ourself. The i2o_core + * code handles this case reasonably sanely. The problem here + * is we shouldn't get them .. but a couple of cards feel + * obliged to tell us stuff we dont care about. + * + * This isnt ideal at all but will do for now. + */ + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); + + /* + * Flush the OSM + */ + + i2o_remove_handler(&i2o_block_handler); + + /* + * Return the block device + */ + if (unregister_blkdev(MAJOR_NR, "i2o_block") != 0) + printk("i2o_block: cleanup_module failed\n"); + + /* + * free request queue + */ + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + + /* + * Why isnt register/unregister gendisk in the kernel ??? + */ + + if (gendisk_head == &i2ob_gendisk) { + gendisk_head = i2ob_gendisk.next; + } + else { + for (gdp = gendisk_head; gdp; gdp = gdp->next) + if (gdp->next == &i2ob_gendisk) + { + gdp->next = i2ob_gendisk.next; + break; + } + } +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/i2o/i2o_config.c linux.ac/drivers/message/i2o/i2o_config.c --- linux.vanilla/drivers/message/i2o/i2o_config.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/i2o/i2o_config.c Tue Apr 3 17:54:47 2001 @@ -0,0 +1,971 @@ +/* + * I2O Configuration Interface Driver + * + * (C) Copyright 1999 Red Hat Software + * + * Written by Alan Cox, Building Number Three Ltd + * + * Modified 04/20/1999 by Deepak Saxena + * - Added basic ioctl() support + * Modified 06/07/1999 by Deepak Saxena + * - Added software download ioctl (still testing) + * Modified 09/10/1999 by Auvo Häkkinen + * - Changes to i2o_cfg_reply(), ioctl_parms() + * - Added ioct_validate() + * Modified 09/30/1999 by Taneli Vähäkangas + * - Fixed ioctl_swdl() + * Modified 10/04/1999 by Taneli Vähäkangas + * - Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel() + * Modified 11/18/199 by Deepak Saxena + * - Added event managmenet support + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/i2o.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/miscdevice.h> +#include <linux/mm.h> +#include <linux/spinlock.h> +#include <linux/smp_lock.h> + +#include <asm/uaccess.h> +#include <asm/io.h> + +static int i2o_cfg_context = -1; +static void *page_buf; +static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED; +struct wait_queue *i2o_wait_queue; + +#define MODINC(x,y) (x = x++ % y) + +struct i2o_cfg_info +{ + struct file* fp; + struct fasync_struct *fasync; + struct i2o_evt_info event_q[I2O_EVT_Q_LEN]; + u16 q_in; // Queue head index + u16 q_out; // Queue tail index + u16 q_len; // Queue length + u16 q_lost; // Number of lost events + u32 q_id; // Event queue ID...used as tx_context + struct i2o_cfg_info *next; +}; +static struct i2o_cfg_info *open_files = NULL; +static int i2o_cfg_info_id = 0; + +static int ioctl_getiops(unsigned long); +static int ioctl_gethrt(unsigned long); +static int ioctl_getlct(unsigned long); +static int ioctl_parms(unsigned long, unsigned int); +static int ioctl_html(unsigned long); +static int ioctl_swdl(unsigned long); +static int ioctl_swul(unsigned long); +static int ioctl_swdel(unsigned long); +static int ioctl_validate(unsigned long); +static int ioctl_evt_reg(unsigned long, struct file *); +static int ioctl_evt_get(unsigned long, struct file *); +static int cfg_fasync(int, struct file*, int); + +/* + * This is the callback for any message we have posted. The message itself + * will be returned to the message pool when we return from the IRQ + * + * This runs in irq context so be short and sweet. + */ +static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *m) +{ + u32 *msg = (u32 *)m; + + if (msg[0] & MSG_FAIL) { + u32 *preserved_msg = (u32*)(c->mem_offset + msg[7]); + + printk(KERN_ERR "i2o_config: IOP failed to process the msg.\n"); + + /* Release the preserved msg frame by resubmitting it as a NOP */ + + preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0; + preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0; + preserved_msg[2] = 0; + i2o_post_message(c, msg[7]); + } + + if (msg[4] >> 24) // ReqStatus != SUCCESS + i2o_report_status(KERN_INFO,"i2o_config", msg); + + if(m->function == I2O_CMD_UTIL_EVT_REGISTER) + { + struct i2o_cfg_info *inf; + + for(inf = open_files; inf; inf = inf->next) + if(inf->q_id == msg[3]) + break; + + // + // If this is the case, it means that we're getting + // events for a file descriptor that's been close()'d + // w/o the user unregistering for events first. + // The code currently assumes that the user will + // take care of unregistering for events before closing + // a file. + // + // TODO: + // Should we track event registartion and deregister + // for events when a file is close()'d so this doesn't + // happen? That would get rid of the search through + // the linked list since file->private_data could point + // directly to the i2o_config_info data structure...but + // it would mean having all sorts of tables to track + // what each file is registered for...I think the + // current method is simpler. - DS + // + if(!inf) + return; + + inf->event_q[inf->q_in].id.iop = c->unit; + inf->event_q[inf->q_in].id.tid = m->target_tid; + inf->event_q[inf->q_in].id.evt_mask = msg[4]; + + // + // Data size = msg size - reply header + // + inf->event_q[inf->q_in].data_size = (m->size - 5) * 4; + if(inf->event_q[inf->q_in].data_size) + memcpy(inf->event_q[inf->q_in].evt_data, + (unsigned char *)(msg + 5), + inf->event_q[inf->q_in].data_size); + + spin_lock(&i2o_config_lock); + MODINC(inf->q_in, I2O_EVT_Q_LEN); + if(inf->q_len == I2O_EVT_Q_LEN) + { + MODINC(inf->q_out, I2O_EVT_Q_LEN); + inf->q_lost++; + } + else + { + // Keep I2OEVTGET on another CPU from touching this + inf->q_len++; + } + spin_unlock(&i2o_config_lock); + + +// printk(KERN_INFO "File %p w/id %d has %d events\n", +// inf->fp, inf->q_id, inf->q_len); + + kill_fasync(&inf->fasync, SIGIO, POLL_IN); + } + + return; +} + +/* + * Each of these describes an i2o message handler. They are + * multiplexed by the i2o_core code + */ + +struct i2o_handler cfg_handler= +{ + i2o_cfg_reply, + NULL, + NULL, + NULL, + "Configuration", + 0, + 0xffffffff // All classes +}; + +static long long cfg_llseek(struct file *file, long long offset, int origin) +{ + return -ESPIPE; +} + + +static ssize_t cfg_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + printk(KERN_INFO "i2o_config write not yet supported\n"); + + return 0; +} + + +static ssize_t cfg_read(struct file *file, char *buf, size_t count, loff_t *ptr) +{ + return 0; +} + +/* + * IOCTL Handler + */ +static int cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd, + unsigned long arg) +{ + int ret; + + switch(cmd) + { + case I2OGETIOPS: + ret = ioctl_getiops(arg); + break; + + case I2OHRTGET: + ret = ioctl_gethrt(arg); + break; + + case I2OLCTGET: + ret = ioctl_getlct(arg); + break; + + case I2OPARMSET: + ret = ioctl_parms(arg, I2OPARMSET); + break; + + case I2OPARMGET: + ret = ioctl_parms(arg, I2OPARMGET); + break; + + case I2OSWDL: + ret = ioctl_swdl(arg); + break; + + case I2OSWUL: + ret = ioctl_swul(arg); + break; + + case I2OSWDEL: + ret = ioctl_swdel(arg); + break; + + case I2OVALIDATE: + ret = ioctl_validate(arg); + break; + + case I2OHTML: + ret = ioctl_html(arg); + break; + + case I2OEVTREG: + ret = ioctl_evt_reg(arg, fp); + break; + + case I2OEVTGET: + ret = ioctl_evt_get(arg, fp); + break; + + default: + ret = -EINVAL; + } + + return ret; +} + +int ioctl_getiops(unsigned long arg) +{ + u8 *user_iop_table = (u8*)arg; + struct i2o_controller *c = NULL; + int i; + u8 foo[MAX_I2O_CONTROLLERS]; + + if(!access_ok(VERIFY_WRITE, user_iop_table, MAX_I2O_CONTROLLERS)) + return -EFAULT; + + for(i = 0; i < MAX_I2O_CONTROLLERS; i++) + { + c = i2o_find_controller(i); + if(c) + { + foo[i] = 1; + i2o_unlock_controller(c); + } + else + { + foo[i] = 0; + } + } + + __copy_to_user(user_iop_table, foo, MAX_I2O_CONTROLLERS); + return 0; +} + +int ioctl_gethrt(unsigned long arg) +{ + struct i2o_controller *c; + struct i2o_cmd_hrtlct *cmd = (struct i2o_cmd_hrtlct*)arg; + struct i2o_cmd_hrtlct kcmd; + i2o_hrt *hrt; + int len; + u32 reslen; + int ret = 0; + + if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct))) + return -EFAULT; + + if(get_user(reslen, kcmd.reslen) < 0) + return -EFAULT; + + if(kcmd.resbuf == NULL) + return -EFAULT; + + c = i2o_find_controller(kcmd.iop); + if(!c) + return -ENXIO; + + hrt = (i2o_hrt *)c->hrt; + + i2o_unlock_controller(c); + + len = 8 + ((hrt->entry_len * hrt->num_entries) << 2); + + /* We did a get user...so assuming mem is ok...is this bad? */ + put_user(len, kcmd.reslen); + if(len > reslen) + ret = -ENOBUFS; + if(copy_to_user(kcmd.resbuf, (void*)hrt, len)) + ret = -EFAULT; + + return ret; +} + +int ioctl_getlct(unsigned long arg) +{ + struct i2o_controller *c; + struct i2o_cmd_hrtlct *cmd = (struct i2o_cmd_hrtlct*)arg; + struct i2o_cmd_hrtlct kcmd; + i2o_lct *lct; + int len; + int ret = 0; + u32 reslen; + + if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct))) + return -EFAULT; + + if(get_user(reslen, kcmd.reslen) < 0) + return -EFAULT; + + if(kcmd.resbuf == NULL) + return -EFAULT; + + c = i2o_find_controller(kcmd.iop); + if(!c) + return -ENXIO; + + lct = (i2o_lct *)c->lct; + i2o_unlock_controller(c); + + len = (unsigned int)lct->table_size << 2; + put_user(len, kcmd.reslen); + if(len > reslen) + ret = -ENOBUFS; + else if(copy_to_user(kcmd.resbuf, (void*)lct, len)) + ret = -EFAULT; + + return ret; +} + +static int ioctl_parms(unsigned long arg, unsigned int type) +{ + int ret = 0; + struct i2o_controller *c; + struct i2o_cmd_psetget *cmd = (struct i2o_cmd_psetget*)arg; + struct i2o_cmd_psetget kcmd; + u32 reslen; + u8 *ops; + u8 *res; + int len; + + u32 i2o_cmd = (type == I2OPARMGET ? + I2O_CMD_UTIL_PARAMS_GET : + I2O_CMD_UTIL_PARAMS_SET); + + if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_psetget))) + return -EFAULT; + + if(get_user(reslen, kcmd.reslen)) + return -EFAULT; + + c = i2o_find_controller(kcmd.iop); + if(!c) + return -ENXIO; + + ops = (u8*)kmalloc(kcmd.oplen, GFP_KERNEL); + if(!ops) + { + i2o_unlock_controller(c); + return -ENOMEM; + } + + if(copy_from_user(ops, kcmd.opbuf, kcmd.oplen)) + { + i2o_unlock_controller(c); + kfree(ops); + return -EFAULT; + } + + /* + * It's possible to have a _very_ large table + * and that the user asks for all of it at once... + */ + res = (u8*)kmalloc(65536, GFP_KERNEL); + if(!res) + { + i2o_unlock_controller(c); + kfree(ops); + return -ENOMEM; + } + + len = i2o_issue_params(i2o_cmd, c, kcmd.tid, + ops, kcmd.oplen, res, 65536); + i2o_unlock_controller(c); + kfree(ops); + + if (len < 0) { + kfree(res); + return -EAGAIN; + } + + put_user(len, kcmd.reslen); + if(len > reslen) + ret = -ENOBUFS; + else if(copy_to_user(cmd->resbuf, res, len)) + ret = -EFAULT; + + kfree(res); + + return ret; +} + +int ioctl_html(unsigned long arg) +{ + struct i2o_html *cmd = (struct i2o_html*)arg; + struct i2o_html kcmd; + struct i2o_controller *c; + u8 *res = NULL; + void *query = NULL; + int ret = 0; + int token; + u32 len; + u32 reslen; + u32 msg[MSG_FRAME_SIZE/4]; + + if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_html))) + { + printk(KERN_INFO "i2o_config: can't copy html cmd\n"); + return -EFAULT; + } + + if(get_user(reslen, kcmd.reslen) < 0) + { + printk(KERN_INFO "i2o_config: can't copy html reslen\n"); + return -EFAULT; + } + + if(!kcmd.resbuf) + { + printk(KERN_INFO "i2o_config: NULL html buffer\n"); + return -EFAULT; + } + + c = i2o_find_controller(kcmd.iop); + if(!c) + return -ENXIO; + + if(kcmd.qlen) /* Check for post data */ + { + query = kmalloc(kcmd.qlen, GFP_KERNEL); + if(!query) + { + i2o_unlock_controller(c); + return -ENOMEM; + } + if(copy_from_user(query, kcmd.qbuf, kcmd.qlen)) + { + i2o_unlock_controller(c); + printk(KERN_INFO "i2o_config: could not get query\n"); + kfree(query); + return -EFAULT; + } + } + + res = kmalloc(65536, GFP_KERNEL); + if(!res) + { + i2o_unlock_controller(c); + return -ENOMEM; + } + + msg[1] = (I2O_CMD_UTIL_CONFIG_DIALOG << 24)|HOST_TID<<12|kcmd.tid; + msg[2] = i2o_cfg_context; + msg[3] = 0; + msg[4] = kcmd.page; + msg[5] = 0xD0000000|65536; + msg[6] = virt_to_bus(res); + if(!kcmd.qlen) /* Check for post data */ + msg[0] = SEVEN_WORD_MSG_SIZE|SGL_OFFSET_5; + else + { + msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_5; + msg[5] = 0x50000000|65536; + msg[7] = 0xD4000000|(kcmd.qlen); + msg[8] = virt_to_bus(query); + } + /* + Wait for a considerable time till the Controller + does its job before timing out. The controller might + take more time to process this request if there are + many devices connected to it. + */ + token = i2o_post_wait(c, msg, 9*4, 400); + if(token) + { + printk(KERN_DEBUG "token = %#10x\n", token); + i2o_unlock_controller(c); + kfree(res); + if(kcmd.qlen) kfree(query); + + return -ETIMEDOUT; + } + i2o_unlock_controller(c); + + len = strnlen(res, 65536); + put_user(len, kcmd.reslen); + if(len > reslen) + ret = -ENOMEM; + if(copy_to_user(kcmd.resbuf, res, len)) + ret = -EFAULT; + + kfree(res); + if(kcmd.qlen) + kfree(query); + + return ret; +} + +int ioctl_swdl(unsigned long arg) +{ + struct i2o_sw_xfer kxfer; + struct i2o_sw_xfer *pxfer = (struct i2o_sw_xfer *)arg; + unsigned char maxfrag = 0, curfrag = 1; + unsigned char *buffer; + u32 msg[9]; + unsigned int status = 0, swlen = 0, fragsize = 8192; + struct i2o_controller *c; + + if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) + return -EFAULT; + + if(get_user(swlen, kxfer.swlen) < 0) + return -EFAULT; + + if(get_user(maxfrag, kxfer.maxfrag) < 0) + return -EFAULT; + + if(get_user(curfrag, kxfer.curfrag) < 0) + return -EFAULT; + + if(curfrag==maxfrag) fragsize = swlen-(maxfrag-1)*8192; + + if(!kxfer.buf || !access_ok(VERIFY_READ, kxfer.buf, fragsize)) + return -EFAULT; + + c = i2o_find_controller(kxfer.iop); + if(!c) + return -ENXIO; + + buffer=kmalloc(fragsize, GFP_KERNEL); + if (buffer==NULL) + { + i2o_unlock_controller(c); + return -ENOMEM; + } + __copy_from_user(buffer, kxfer.buf, fragsize); + + msg[0]= NINE_WORD_MSG_SIZE | SGL_OFFSET_7; + msg[1]= I2O_CMD_SW_DOWNLOAD<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2]= (u32)cfg_handler.context; + msg[3]= 0; + msg[4]= (((u32)kxfer.flags)<<24) | (((u32)kxfer.sw_type)<<16) | + (((u32)maxfrag)<<8) | (((u32)curfrag)); + msg[5]= swlen; + msg[6]= kxfer.sw_id; + msg[7]= (0xD0000000 | fragsize); + msg[8]= virt_to_bus(buffer); + +// printk("i2o_config: swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); + status = i2o_post_wait(c, msg, sizeof(msg), 60); + + i2o_unlock_controller(c); + kfree(buffer); + + if (status != I2O_POST_WAIT_OK) + { + // it fails if you try and send frags out of order + // and for some yet unknown reasons too + printk(KERN_INFO "i2o_config: swdl failed, DetailedStatus = %d\n", status); + return -ETIMEDOUT; + } + + return 0; +} + +int ioctl_swul(unsigned long arg) +{ + struct i2o_sw_xfer kxfer; + struct i2o_sw_xfer *pxfer = (struct i2o_sw_xfer *)arg; + unsigned char maxfrag = 0, curfrag = 1; + unsigned char *buffer; + u32 msg[9]; + unsigned int status = 0, swlen = 0, fragsize = 8192; + struct i2o_controller *c; + + if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) + return -EFAULT; + + if(get_user(swlen, kxfer.swlen) < 0) + return -EFAULT; + + if(get_user(maxfrag, kxfer.maxfrag) < 0) + return -EFAULT; + + if(get_user(curfrag, kxfer.curfrag) < 0) + return -EFAULT; + + if(curfrag==maxfrag) fragsize = swlen-(maxfrag-1)*8192; + + if(!kxfer.buf || !access_ok(VERIFY_WRITE, kxfer.buf, fragsize)) + return -EFAULT; + + c = i2o_find_controller(kxfer.iop); + if(!c) + return -ENXIO; + + buffer=kmalloc(fragsize, GFP_KERNEL); + if (buffer==NULL) + { + i2o_unlock_controller(c); + return -ENOMEM; + } + + msg[0]= NINE_WORD_MSG_SIZE | SGL_OFFSET_7; + msg[1]= I2O_CMD_SW_UPLOAD<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2]= (u32)cfg_handler.context; + msg[3]= 0; + msg[4]= (u32)kxfer.flags<<24|(u32)kxfer.sw_type<<16|(u32)maxfrag<<8|(u32)curfrag; + msg[5]= swlen; + msg[6]= kxfer.sw_id; + msg[7]= (0xD0000000 | fragsize); + msg[8]= virt_to_bus(buffer); + +// printk("i2o_config: swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); + status = i2o_post_wait(c, msg, sizeof(msg), 60); + i2o_unlock_controller(c); + + if (status != I2O_POST_WAIT_OK) + { + kfree(buffer); + printk(KERN_INFO "i2o_config: swul failed, DetailedStatus = %d\n", status); + return -ETIMEDOUT; + } + + __copy_to_user(kxfer.buf, buffer, fragsize); + kfree(buffer); + + return 0; +} + +int ioctl_swdel(unsigned long arg) +{ + struct i2o_controller *c; + struct i2o_sw_xfer kxfer, *pxfer = (struct i2o_sw_xfer *)arg; + u32 msg[7]; + unsigned int swlen; + int token; + + if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) + return -EFAULT; + + if (get_user(swlen, kxfer.swlen) < 0) + return -EFAULT; + + c = i2o_find_controller(kxfer.iop); + if (!c) + return -ENXIO; + + msg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0; + msg[1] = I2O_CMD_SW_REMOVE<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2] = (u32)i2o_cfg_context; + msg[3] = 0; + msg[4] = (u32)kxfer.flags<<24 | (u32)kxfer.sw_type<<16; + msg[5] = swlen; + msg[6] = kxfer.sw_id; + + token = i2o_post_wait(c, msg, sizeof(msg), 10); + i2o_unlock_controller(c); + + if (token != I2O_POST_WAIT_OK) + { + printk(KERN_INFO "i2o_config: swdel failed, DetailedStatus = %d\n", token); + return -ETIMEDOUT; + } + + return 0; +} + +int ioctl_validate(unsigned long arg) +{ + int token; + int iop = (int)arg; + u32 msg[4]; + struct i2o_controller *c; + + c=i2o_find_controller(iop); + if (!c) + return -ENXIO; + + msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_CONFIG_VALIDATE<<24 | HOST_TID<<12 | iop; + msg[2] = (u32)i2o_cfg_context; + msg[3] = 0; + + token = i2o_post_wait(c, msg, sizeof(msg), 10); + i2o_unlock_controller(c); + + if (token != I2O_POST_WAIT_OK) + { + printk(KERN_INFO "Can't validate configuration, ErrorStatus = %d\n", + token); + return -ETIMEDOUT; + } + + return 0; +} + +static int ioctl_evt_reg(unsigned long arg, struct file *fp) +{ + u32 msg[5]; + struct i2o_evt_id *pdesc = (struct i2o_evt_id *)arg; + struct i2o_evt_id kdesc; + struct i2o_controller *iop; + struct i2o_device *d; + + if (copy_from_user(&kdesc, pdesc, sizeof(struct i2o_evt_id))) + return -EFAULT; + + /* IOP exists? */ + iop = i2o_find_controller(kdesc.iop); + if(!iop) + return -ENXIO; + i2o_unlock_controller(iop); + + /* Device exists? */ + for(d = iop->devices; d; d = d->next) + if(d->lct_data.tid == kdesc.tid) + break; + + if(!d) + return -ENODEV; + + msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_UTIL_EVT_REGISTER<<24 | HOST_TID<<12 | kdesc.tid; + msg[2] = (u32)i2o_cfg_context; + msg[3] = (u32)fp->private_data; + msg[4] = kdesc.evt_mask; + + i2o_post_this(iop, msg, 20); + + return 0; +} + +static int ioctl_evt_get(unsigned long arg, struct file *fp) +{ + u32 id = (u32)fp->private_data; + struct i2o_cfg_info *p = NULL; + struct i2o_evt_get *uget = (struct i2o_evt_get*)arg; + struct i2o_evt_get kget; + unsigned int flags; + + // access_ok doesn't check for NULL?!?! + if(!arg) + return -EFAULT; + + if(!access_ok(VERIFY_WRITE, uget, sizeof(struct i2o_evt_get))) + return -EFAULT; + + for(p = open_files; p; p = p->next) + if(p->q_id == id) + break; + + if(!p->q_len) + { + return -ENOENT; + return 0; + } + + memcpy(&kget.info, &p->event_q[p->q_out], sizeof(struct i2o_evt_info)); + MODINC(p->q_out, I2O_EVT_Q_LEN); + spin_lock_irqsave(&i2o_config_lock, flags); + p->q_len--; + kget.pending = p->q_len; + kget.lost = p->q_lost; + spin_unlock_irqrestore(&i2o_config_lock, flags); + + __copy_to_user(uget, &kget, sizeof(struct i2o_evt_get)); + + return 0; +} + +static int cfg_open(struct inode *inode, struct file *file) +{ + struct i2o_cfg_info *tmp = + (struct i2o_cfg_info *)kmalloc(sizeof(struct i2o_cfg_info), GFP_KERNEL); + unsigned int flags; + + if(!tmp) + return -ENOMEM; + + file->private_data = (void*)(i2o_cfg_info_id++); + tmp->fp = file; + tmp->fasync = NULL; + tmp->q_id = (u32)file->private_data; + tmp->q_len = 0; + tmp->q_in = 0; + tmp->q_out = 0; + tmp->q_lost = 0; + tmp->next = open_files; + + spin_lock_irqsave(&i2o_config_lock, flags); + open_files = tmp; + spin_unlock_irqrestore(&i2o_config_lock, flags); + + return 0; +} + +static int cfg_release(struct inode *inode, struct file *file) +{ + u32 id = (u32)file->private_data; + struct i2o_cfg_info *p1, *p2; + unsigned int flags; + + lock_kernel(); + p1 = p2 = NULL; + + spin_lock_irqsave(&i2o_config_lock, flags); + for(p1 = open_files; p1; ) + { + if(p1->q_id == id) + { + + if(p1->fasync) + cfg_fasync(-1, file, 0); + if(p2) + p2->next = p1->next; + else + open_files = p1->next; + + kfree(p1); + break; + } + p2 = p1; + p1 = p1->next; + } + spin_unlock_irqrestore(&i2o_config_lock, flags); + unlock_kernel(); + + return 0; +} + +static int cfg_fasync(int fd, struct file *fp, int on) +{ + u32 id = (u32)fp->private_data; + struct i2o_cfg_info *p; + + for(p = open_files; p; p = p->next) + if(p->q_id == id) + break; + + if(!p) + return -EBADF; + + return fasync_helper(fd, fp, on, &p->fasync); +} + +static struct file_operations config_fops = +{ + owner: THIS_MODULE, + llseek: cfg_llseek, + read: cfg_read, + write: cfg_write, + ioctl: cfg_ioctl, + open: cfg_open, + release: cfg_release, + fasync: cfg_fasync, +}; + +static struct miscdevice i2o_miscdev = { + I2O_MINOR, + "i2octl", + &config_fops +}; + +#ifdef MODULE +int init_module(void) +#else +int __init i2o_config_init(void) +#endif +{ + printk(KERN_INFO "I2O configuration manager v 0.04.\n"); + printk(KERN_INFO " (C) Copyright 1999 Red Hat Software\n"); + + if((page_buf = kmalloc(4096, GFP_KERNEL))==NULL) + { + printk(KERN_ERR "i2o_config: no memory for page buffer.\n"); + return -ENOBUFS; + } + if(misc_register(&i2o_miscdev)==-1) + { + printk(KERN_ERR "i2o_config: can't register device.\n"); + kfree(page_buf); + return -EBUSY; + } + /* + * Install our handler + */ + if(i2o_install_handler(&cfg_handler)<0) + { + kfree(page_buf); + printk(KERN_ERR "i2o_config: handler register failed.\n"); + misc_deregister(&i2o_miscdev); + return -EBUSY; + } + /* + * The low 16bits of the transaction context must match this + * for everything we post. Otherwise someone else gets our mail + */ + i2o_cfg_context = cfg_handler.context; + return 0; +} + +#ifdef MODULE + +void cleanup_module(void) +{ + misc_deregister(&i2o_miscdev); + + if(page_buf) + kfree(page_buf); + if(i2o_cfg_context != -1) + i2o_remove_handler(&cfg_handler); +} + +EXPORT_NO_SYMBOLS; +MODULE_AUTHOR("Red Hat Software"); +MODULE_DESCRIPTION("I2O Configuration"); + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/i2o/i2o_core.c linux.ac/drivers/message/i2o/i2o_core.c --- linux.vanilla/drivers/message/i2o/i2o_core.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/i2o/i2o_core.c Tue Apr 3 23:22:13 2001 @@ -0,0 +1,3315 @@ +/* + * Core I2O structure management + * + * (C) Copyright 1999 Red Hat Software + * + * Written by Alan Cox, Building Number Three 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. + * + * A lot of the I2O message side code from this is taken from the + * Red Creek RCPCI45 adapter driver by Red Creek Communications + * + * Fixes by: + * Philipp Rumpf + * Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI> + * Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI> + * Deepak Saxena <deepak@plexity.net> + * Boji T Kannanthanam <boji.t.kannanthanam@intel.com> + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/pci.h> + +#include <linux/i2o.h> + +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/smp_lock.h> + +#include <linux/bitops.h> +#include <linux/wait.h> +#include <linux/delay.h> +#include <linux/timer.h> +#include <linux/tqueue.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <asm/semaphore.h> + +#include <asm/io.h> +#include <linux/reboot.h> + +#include "i2o_lan.h" + +// #define DRIVERDEBUG + +#ifdef DRIVERDEBUG +#define dprintk(s, args...) printk(s, ## args) +#else +#define dprintk(s, args...) +#endif + +/* OSM table */ +static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES] = {NULL}; + +/* Controller list */ +static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS] = {NULL}; +struct i2o_controller *i2o_controller_chain = NULL; +int i2o_num_controllers = 0; + +/* Initiator Context for Core message */ +static int core_context = 0; + +/* Initialization && shutdown functions */ +static void i2o_sys_init(void); +static void i2o_sys_shutdown(void); +static int i2o_reset_controller(struct i2o_controller *); +static int i2o_reboot_event(struct notifier_block *, unsigned long , void *); +static int i2o_online_controller(struct i2o_controller *); +static int i2o_init_outbound_q(struct i2o_controller *); +static int i2o_post_outbound_messages(struct i2o_controller *); + +/* Reply handler */ +static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *, + struct i2o_message *); + +/* Various helper functions */ +static int i2o_lct_get(struct i2o_controller *); +static int i2o_lct_notify(struct i2o_controller *); +static int i2o_hrt_get(struct i2o_controller *); + +static int i2o_build_sys_table(void); +static int i2o_systab_send(struct i2o_controller *c); + +/* I2O core event handler */ +static int i2o_core_evt(void *); +static int evt_pid; +static int evt_running; + +/* Dynamic LCT update handler */ +static int i2o_dyn_lct(void *); + +void i2o_report_controller_unit(struct i2o_controller *, struct i2o_device *); + +/* + * I2O System Table. Contains information about + * all the IOPs in the system. Used to inform IOPs + * about each other's existence. + * + * sys_tbl_ver is the CurrentChangeIndicator that is + * used by IOPs to track changes. + */ +static struct i2o_sys_tbl *sys_tbl = NULL; +static int sys_tbl_ind = 0; +static int sys_tbl_len = 0; + +/* + * This spin lock is used to keep a device from being + * added and deleted concurrently across CPUs or interrupts. + * This can occur when a user creates a device and immediatelly + * deletes it before the new_dev_notify() handler is called. + */ +static spinlock_t i2o_dev_lock = SPIN_LOCK_UNLOCKED; + +#ifdef MODULE +/* + * Function table to send to bus specific layers + * See <include/linux/i2o.h> for explanation of this + */ +static struct i2o_core_func_table i2o_core_functions = +{ + i2o_install_controller, + i2o_activate_controller, + i2o_find_controller, + i2o_unlock_controller, + i2o_run_queue, + i2o_delete_controller +}; + +#ifdef CONFIG_I2O_PCI_MODULE +extern int i2o_pci_core_attach(struct i2o_core_func_table *); +extern void i2o_pci_core_detach(void); +#endif /* CONFIG_I2O_PCI_MODULE */ + +#endif /* MODULE */ + +/* + * Structures and definitions for synchronous message posting. + * See i2o_post_wait() for description. + */ +struct i2o_post_wait_data +{ + int status; + u32 id; + wait_queue_head_t *wq; + struct i2o_post_wait_data *next; +}; +static struct i2o_post_wait_data *post_wait_queue = NULL; +static u32 post_wait_id = 0; // Unique ID for each post_wait +static spinlock_t post_wait_lock = SPIN_LOCK_UNLOCKED; +static void i2o_post_wait_complete(u32, int); + +/* OSM descriptor handler */ +static struct i2o_handler i2o_core_handler = +{ + (void *)i2o_core_reply, + NULL, + NULL, + NULL, + "I2O core layer", + 0, + I2O_CLASS_EXECUTIVE +}; + + +/* + * Used when queing a reply to be handled later + */ +struct reply_info +{ + struct i2o_controller *iop; + u32 msg[MSG_FRAME_SIZE]; +}; +static struct reply_info evt_reply; +static struct reply_info events[I2O_EVT_Q_LEN]; +static int evt_in = 0; +static int evt_out = 0; +static int evt_q_len = 0; +#define MODINC(x,y) ((x) = ((x) + 1) % (y)) + +/* + * I2O configuration spinlock. This isnt a big deal for contention + * so we have one only + */ + +static DECLARE_MUTEX(i2o_configuration_lock); + +/* + * Event spinlock. Used to keep event queue sane and from + * handling multiple events simultaneously. + */ +static spinlock_t i2o_evt_lock = SPIN_LOCK_UNLOCKED; + +/* + * Semaphore used to synchronize event handling thread with + * interrupt handler. + */ + +static DECLARE_MUTEX(evt_sem); +static DECLARE_MUTEX_LOCKED(evt_dead); +DECLARE_WAIT_QUEUE_HEAD(evt_wait); + +static struct notifier_block i2o_reboot_notifier = +{ + i2o_reboot_event, + NULL, + 0 +}; + +/* + * Config options + */ + +static int verbose = 0; +MODULE_PARM(verbose, "i"); + +/* + * I2O Core reply handler + */ +static void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c, + struct i2o_message *m) +{ + u32 *msg=(u32 *)m; + u32 status; + u32 context = msg[2]; + + if (msg[0] & MSG_FAIL) // Fail bit is set + { + u32 *preserved_msg = (u32*)(c->mem_offset + msg[7]); + + i2o_report_status(KERN_INFO, "i2o_core", msg); + i2o_dump_message(preserved_msg); + + /* If the failed request needs special treatment, + * it should be done here. */ + + /* Release the preserved msg by resubmitting it as a NOP */ + + preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0; + preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0; + preserved_msg[2] = 0; + i2o_post_message(c, msg[7]); + + /* If reply to i2o_post_wait failed, return causes a timeout */ + + return; + } + +#ifdef DRIVERDEBUG + i2o_report_status(KERN_INFO, "i2o_core", msg); +#endif + + if(msg[2]&0x80000000) // Post wait message + { + if (msg[4] >> 24) + status = -(msg[4] & 0xFFFF); + else + status = I2O_POST_WAIT_OK; + + i2o_post_wait_complete(context, status); + return; + } + + if(m->function == I2O_CMD_UTIL_EVT_REGISTER) + { + memcpy(events[evt_in].msg, msg, (msg[0]>>16)<<2); + events[evt_in].iop = c; + + spin_lock(&i2o_evt_lock); + MODINC(evt_in, I2O_EVT_Q_LEN); + if(evt_q_len == I2O_EVT_Q_LEN) + MODINC(evt_out, I2O_EVT_Q_LEN); + else + evt_q_len++; + spin_unlock(&i2o_evt_lock); + + up(&evt_sem); + wake_up_interruptible(&evt_wait); + return; + } + + if(m->function == I2O_CMD_LCT_NOTIFY) + { + up(&c->lct_sem); + return; + } + + /* + * If this happens, we want to dump the message to the syslog so + * it can be sent back to the card manufacturer by the end user + * to aid in debugging. + * + */ + printk(KERN_WARNING "%s: Unsolicited message reply sent to core!" + "Message dumped to syslog\n", + c->name); + i2o_dump_message(msg); + + return; +} + +/** + * i2o_install_handler - install a message handler + * @h: Handler structure + * + * Install an I2O handler - these handle the asynchronous messaging + * from the card once it has initialised. If the table of handlers is + * full then -ENOSPC is returned. On a success 0 is returned and the + * context field is set by the function. The structure is part of the + * system from this time onwards. It must not be freed until it has + * been uninstalled + */ + +int i2o_install_handler(struct i2o_handler *h) +{ + int i; + down(&i2o_configuration_lock); + for(i=0;i<MAX_I2O_MODULES;i++) + { + if(i2o_handlers[i]==NULL) + { + h->context = i; + i2o_handlers[i]=h; + up(&i2o_configuration_lock); + return 0; + } + } + up(&i2o_configuration_lock); + return -ENOSPC; +} + +/** + * i2o_remove_handler - remove an i2o message handler + * @h: handler + * + * Remove a message handler previously installed with i2o_install_handler. + * After this function returns the handler object can be freed or re-used + */ + +int i2o_remove_handler(struct i2o_handler *h) +{ + i2o_handlers[h->context]=NULL; + return 0; +} + + +/* + * Each I2O controller has a chain of devices on it. + * Each device has a pointer to it's LCT entry to be used + * for fun purposes. + */ + +/** + * i2o_install_device - attach a device to a controller + * @c: controller + * @d: device + * + * Add a new device to an i2o controller. This can be called from + * non interrupt contexts only. It adds the device and marks it as + * unclaimed. The device memory becomes part of the kernel and must + * be uninstalled before being freed or reused. Zero is returned + * on success. + */ + +int i2o_install_device(struct i2o_controller *c, struct i2o_device *d) +{ + int i; + + down(&i2o_configuration_lock); + d->controller=c; + d->owner=NULL; + d->next=c->devices; + d->prev=NULL; + if (c->devices != NULL) + c->devices->prev=d; + c->devices=d; + *d->dev_name = 0; + + for(i = 0; i < I2O_MAX_MANAGERS; i++) + d->managers[i] = NULL; + + up(&i2o_configuration_lock); + return 0; +} + +/* we need this version to call out of i2o_delete_controller */ + +int __i2o_delete_device(struct i2o_device *d) +{ + struct i2o_device **p; + int i; + + p=&(d->controller->devices); + + /* + * Hey we have a driver! + * Check to see if the driver wants us to notify it of + * device deletion. If it doesn't we assume that it + * is unsafe to delete a device with an owner and + * fail. + */ + if(d->owner) + { + if(d->owner->dev_del_notify) + { + dprintk(KERN_INFO "Device has owner, notifying\n"); + d->owner->dev_del_notify(d->controller, d); + if(d->owner) + { + printk(KERN_WARNING + "Driver \"%s\" did not release device!\n", d->owner->name); + return -EBUSY; + } + } + else + return -EBUSY; + } + + /* + * Tell any other users who are talking to this device + * that it's going away. We assume that everything works. + */ + for(i=0; i < I2O_MAX_MANAGERS; i++) + { + if(d->managers[i] && d->managers[i]->dev_del_notify) + d->managers[i]->dev_del_notify(d->controller, d); + } + + while(*p!=NULL) + { + if(*p==d) + { + /* + * Destroy + */ + *p=d->next; + kfree(d); + return 0; + } + p=&((*p)->next); + } + printk(KERN_ERR "i2o_delete_device: passed invalid device.\n"); + return -EINVAL; +} + +/** + * i2o_delete_device - remove an i2o device + * @d: device to remove + * + * This function unhooks a device from a controller. The device + * will not be unhooked if it has an owner who does not wish to free + * it, or if the owner lacks a dev_del_notify function. In that case + * -EBUSY is returned. On success 0 is returned. Other errors cause + * negative errno values to be returned + */ + +int i2o_delete_device(struct i2o_device *d) +{ + int ret; + + down(&i2o_configuration_lock); + + /* + * Seek, locate + */ + + ret = __i2o_delete_device(d); + + up(&i2o_configuration_lock); + + return ret; +} + +/** + * i2o_install_controller - attach a controller + * @c: controller + * + * Add a new controller to the i2o layer. This can be called from + * non interrupt contexts only. It adds the controller and marks it as + * unused with no devices. If the tables are full or memory allocations + * fail then a negative errno code is returned. On success zero is + * returned and the controller is bound to the system. The structure + * must not be freed or reused until being uninstalled. + */ + +int i2o_install_controller(struct i2o_controller *c) +{ + int i; + down(&i2o_configuration_lock); + for(i=0;i<MAX_I2O_CONTROLLERS;i++) + { + if(i2o_controllers[i]==NULL) + { + c->dlct = (i2o_lct*)kmalloc(8192, GFP_KERNEL); + if(c->dlct==NULL) + { + up(&i2o_configuration_lock); + return -ENOMEM; + } + i2o_controllers[i]=c; + c->devices = NULL; + c->next=i2o_controller_chain; + i2o_controller_chain=c; + c->unit = i; + c->page_frame = NULL; + c->hrt = NULL; + c->lct = NULL; + c->status_block = NULL; + sprintf(c->name, "i2o/iop%d", i); + i2o_num_controllers++; + init_MUTEX_LOCKED(&c->lct_sem); + up(&i2o_configuration_lock); + return 0; + } + } + printk(KERN_ERR "No free i2o controller slots.\n"); + up(&i2o_configuration_lock); + return -EBUSY; +} + +/** + * i2o_delete_controller - delete a controller + * @c: controller + * + * Remove an i2o controller from the system. If the controller or its + * devices are busy then -EBUSY is returned. On a failure a negative + * errno code is returned. On success zero is returned. + */ + +int i2o_delete_controller(struct i2o_controller *c) +{ + struct i2o_controller **p; + int users; + char name[16]; + int stat; + + dprintk(KERN_INFO "Deleting controller %s\n", c->name); + + /* + * Clear event registration as this can cause weird behavior + */ + if(c->status_block->iop_state == ADAPTER_STATE_OPERATIONAL) + i2o_event_register(c, core_context, 0, 0, 0); + + down(&i2o_configuration_lock); + if((users=atomic_read(&c->users))) + { + dprintk(KERN_INFO "I2O: %d users for controller %s\n", users, + c->name); + up(&i2o_configuration_lock); + return -EBUSY; + } + while(c->devices) + { + if(__i2o_delete_device(c->devices)<0) + { + /* Shouldnt happen */ + c->bus_disable(c); + up(&i2o_configuration_lock); + return -EBUSY; + } + } + + /* + * If this is shutdown time, the thread's already been killed + */ + if(c->lct_running) { + stat = kill_proc(c->lct_pid, SIGTERM, 1); + if(!stat) { + int count = 10 * 100; + while(c->lct_running && --count) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + + if(!count) + printk(KERN_ERR + "%s: LCT thread still running!\n", + c->name); + } + } + + p=&i2o_controller_chain; + + while(*p) + { + if(*p==c) + { + /* Ask the IOP to switch to RESET state */ + i2o_reset_controller(c); + + /* Release IRQ */ + c->destructor(c); + + *p=c->next; + up(&i2o_configuration_lock); + + if(c->page_frame) + kfree(c->page_frame); + if(c->hrt) + kfree(c->hrt); + if(c->lct) + kfree(c->lct); + if(c->status_block) + kfree(c->status_block); + if(c->dlct) + kfree(c->dlct); + + i2o_controllers[c->unit]=NULL; + memcpy(name, c->name, strlen(c->name)+1); + kfree(c); + dprintk(KERN_INFO "%s: Deleted from controller chain.\n", name); + + i2o_num_controllers--; + return 0; + } + p=&((*p)->next); + } + up(&i2o_configuration_lock); + printk(KERN_ERR "i2o_delete_controller: bad pointer!\n"); + return -ENOENT; +} + +/** + * i2o_unlock_controller - unlock a controller + * @c: controller to unlock + * + * Take a lock on an i2o controller. This prevents it being deleted. + * i2o controllers are not refcounted so a deletion of an in use device + * will fail, not take affect on the last dereference. + */ + +void i2o_unlock_controller(struct i2o_controller *c) +{ + atomic_dec(&c->users); +} + +/** + * i2o_find_controller - return a locked controller + * @n: controller number + * + * Returns a pointer to the controller object. The controller is locked + * on return. NULL is returned if the controller is not found. + */ + +struct i2o_controller *i2o_find_controller(int n) +{ + struct i2o_controller *c; + + if(n<0 || n>=MAX_I2O_CONTROLLERS) + return NULL; + + down(&i2o_configuration_lock); + c=i2o_controllers[n]; + if(c!=NULL) + atomic_inc(&c->users); + up(&i2o_configuration_lock); + return c; +} + +/** + * i2o_issue_claim - claim or release a device + * @cmd: command + * @c: controller to claim for + * @tid: i2o task id + * @type: type of claim + * + * Issue I2O UTIL_CLAIM and UTIL_RELEASE messages. The message to be sent + * is set by cmd. The tid is the task id of the object to claim and the + * type is the claim type (see the i2o standard) + * + * Zero is returned on success. + */ + +static int i2o_issue_claim(u32 cmd, struct i2o_controller *c, int tid, u32 type) +{ + u32 msg[5]; + + msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; + msg[1] = cmd << 24 | HOST_TID<<12 | tid; + msg[3] = 0; + msg[4] = type; + + return i2o_post_wait(c, msg, sizeof(msg), 60); +} + +/* + * i2o_claim_device - claim a device for use by an OSM + * @d: device to claim + * @h: handler for this device + * + * Do the leg work to assign a device to a given OSM on Linux. The + * kernel updates the internal handler data for the device and then + * performs an I2O claim for the device, attempting to claim the + * device as primary. If the attempt fails a negative errno code + * is returned. On success zero is returned. + */ + +int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h) +{ + down(&i2o_configuration_lock); + if (d->owner) { + printk(KERN_INFO "Device claim called, but dev already owned by %s!", + h->name); + up(&i2o_configuration_lock); + return -EBUSY; + } + d->owner=h; + + if(i2o_issue_claim(I2O_CMD_UTIL_CLAIM ,d->controller,d->lct_data.tid, + I2O_CLAIM_PRIMARY)) + { + d->owner = NULL; + return -EBUSY; + } + up(&i2o_configuration_lock); + return 0; +} + +/** + * i2o_release_device - release a device that the OSM is using + * @d: device to claim + * @h: handler for this device + * + * Drop a claim by an OSM on a given I2O device. The handler is cleared + * and 0 is returned on success. + * + */ + +int i2o_release_device(struct i2o_device *d, struct i2o_handler *h) +{ + int err = 0; + long time; + + down(&i2o_configuration_lock); + if (d->owner != h) { + printk(KERN_INFO "Claim release called, but not owned by %s!", + h->name); + up(&i2o_configuration_lock); + return -ENOENT; + } + + d->owner = NULL; + + if((err=i2o_issue_claim(I2O_CMD_UTIL_RELEASE, d->controller, d->lct_data.tid, I2O_CLAIM_PRIMARY)) ) + { + if(err == -EINTR) + { + /* We were interrupted; wait for a few milli-sec before checking + for LCT updates */ + schedule_timeout(HZ/2); + barrier(); + if( d->lct_data.user_tid == 0xFFF) + err = 0; + else + printk(KERN_INFO "I2O Core: i2o_release device failed\n"); + } + else + { + err = -ENXIO; + d->owner = h; + } + } + + up(&i2o_configuration_lock); + return err; +} + +/* + * Called by OSMs to let the core know that they want to be + * notified if the given device is deleted from the system. + */ +int i2o_device_notify_on(struct i2o_device *d, struct i2o_handler *h) +{ + int i; + + if(d->num_managers == I2O_MAX_MANAGERS) + return -ENOSPC; + + for(i = 0; i < I2O_MAX_MANAGERS; i++) + { + if(!d->managers[i]) + { + d->managers[i] = h; + break; + } + } + + d->num_managers++; + + return 0; +} + +/* + * Called by OSMs to let the core know that they no longer + * are interested in the fate of the given device. + */ +int i2o_device_notify_off(struct i2o_device *d, struct i2o_handler *h) +{ + int i; + + for(i=0; i < I2O_MAX_MANAGERS; i++) + { + if(d->managers[i] == h) + { + d->managers[i] = NULL; + d->num_managers--; + return 0; + } + } + + return -ENOENT; +} + +/* + * Event registration API + */ +int i2o_event_register(struct i2o_controller *c, u32 tid, + u32 init_context, u32 tr_context, u32 evt_mask) +{ + u32 msg[5]; // Not performance critical, so we just + // i2o_post_this it instead of building it + // in IOP memory + + msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_UTIL_EVT_REGISTER<<24 | HOST_TID<<12 | tid; + msg[2] = init_context; + msg[3] = tr_context; + msg[4] = evt_mask; + + return i2o_post_this(c, msg, sizeof(msg)); +} + +/* + * Event ack API + * + * We just take a pointer to the original UTIL_EVENT_REGISTER reply + * message and change the function code since that's what spec + * describes an EventAck message looking like. + */ + +int i2o_event_ack(struct i2o_controller *c, u32 *msg) +{ + struct i2o_message *m = (struct i2o_message *)msg; + + m->function = I2O_CMD_UTIL_EVT_ACK; + + return i2o_post_wait(c, msg, m->size * 4, 2); +} + +/* + * Core event handler. Runs as a separate thread and is woken + * up whenever there is an Executive class event. + */ +static int i2o_core_evt(void *reply_data) +{ + struct reply_info *reply = (struct reply_info *) reply_data; + u32 *msg = reply->msg; + struct i2o_controller *c = NULL; + int flags; + + lock_kernel(); + daemonize(); + unlock_kernel(); + + strcpy(current->comm, "i2oevtd"); + evt_running = 1; + + while(1) + { + if(down_interruptible(&evt_sem)) + { + dprintk(KERN_INFO "I2O event thread dead\n"); + printk("exiting..."); + evt_running = 0; + up_and_exit(&evt_dead, 0); + } + + /* + * Copy the data out of the queue so that we don't have to lock + * around the whole function and just around the qlen update + */ + spin_lock_irqsave(&i2o_evt_lock, flags); + memcpy(reply, &events[evt_out], sizeof(struct reply_info)); + MODINC(evt_out, I2O_EVT_Q_LEN); + evt_q_len--; + spin_unlock_irqrestore(&i2o_evt_lock, flags); + + c = reply->iop; + dprintk(KERN_INFO "I2O IRTOS EVENT: iop%d, event %#10x\n", c->unit, msg[4]); + + /* + * We do not attempt to delete/quiesce/etc. the controller if + * some sort of error indidication occurs. We may want to do + * so in the future, but for now we just let the user deal with + * it. One reason for this is that what to do with an error + * or when to send what ćrror is not really agreed on, so + * we get errors that may not be fatal but just look like they + * are...so let the user deal with it. + */ + switch(msg[4]) + { + case I2O_EVT_IND_EXEC_RESOURCE_LIMITS: + printk(KERN_ERR "%s: Out of resources\n", c->name); + break; + + case I2O_EVT_IND_EXEC_POWER_FAIL: + printk(KERN_ERR "%s: Power failure\n", c->name); + break; + + case I2O_EVT_IND_EXEC_HW_FAIL: + { + char *fail[] = + { + "Unknown Error", + "Power Lost", + "Code Violation", + "Parity Error", + "Code Execution Exception", + "Watchdog Timer Expired" + }; + + if(msg[5] <= 6) + printk(KERN_ERR "%s: Hardware Failure: %s\n", + c->name, fail[msg[5]]); + else + printk(KERN_ERR "%s: Unknown Hardware Failure\n", c->name); + + break; + } + + /* + * New device created + * - Create a new i2o_device entry + * - Inform all interested drivers about this device's existence + */ + case I2O_EVT_IND_EXEC_NEW_LCT_ENTRY: + { + struct i2o_device *d = (struct i2o_device *) + kmalloc(sizeof(struct i2o_device), GFP_KERNEL); + int i; + + if (d == NULL) { + printk(KERN_EMERG "i2oevtd: out of memory\n"); + break; + } + memcpy(&d->lct_data, &msg[5], sizeof(i2o_lct_entry)); + + d->next = NULL; + d->controller = c; + d->flags = 0; + + i2o_report_controller_unit(c, d); + i2o_install_device(c,d); + + for(i = 0; i < MAX_I2O_MODULES; i++) + { + if(i2o_handlers[i] && + i2o_handlers[i]->new_dev_notify && + (i2o_handlers[i]->class&d->lct_data.class_id)) + { + spin_lock(&i2o_dev_lock); + i2o_handlers[i]->new_dev_notify(c,d); + spin_unlock(&i2o_dev_lock); + } + } + + break; + } + + /* + * LCT entry for a device has been modified, so update it + * internally. + */ + case I2O_EVT_IND_EXEC_MODIFIED_LCT: + { + struct i2o_device *d; + i2o_lct_entry *new_lct = (i2o_lct_entry *)&msg[5]; + + for(d = c->devices; d; d = d->next) + { + if(d->lct_data.tid == new_lct->tid) + { + memcpy(&d->lct_data, new_lct, sizeof(i2o_lct_entry)); + break; + } + } + break; + } + + case I2O_EVT_IND_CONFIGURATION_FLAG: + printk(KERN_WARNING "%s requires user configuration\n", c->name); + break; + + case I2O_EVT_IND_GENERAL_WARNING: + printk(KERN_WARNING "%s: Warning notification received!" + "Check configuration for errors!\n", c->name); + break; + + case I2O_EVT_IND_EVT_MASK_MODIFIED: + /* Well I guess that was us hey .. */ + break; + + default: + printk(KERN_WARNING "%s: No handler for event (0x%08x)\n", c->name, msg[4]); + break; + } + } + + return 0; +} + +/* + * Dynamic LCT update. This compares the LCT with the currently + * installed devices to check for device deletions..this needed b/c there + * is no DELETED_LCT_ENTRY EventIndicator for the Executive class so + * we can't just have the event handler do this...annoying + * + * This is a hole in the spec that will hopefully be fixed someday. + */ +static int i2o_dyn_lct(void *foo) +{ + struct i2o_controller *c = (struct i2o_controller *)foo; + struct i2o_device *d = NULL; + struct i2o_device *d1 = NULL; + int i = 0; + int found = 0; + int entries; + void *tmp; + char name[16]; + + lock_kernel(); + daemonize(); + unlock_kernel(); + + sprintf(name, "iop%d_lctd", c->unit); + strcpy(current->comm, name); + + c->lct_running = 1; + + while(1) + { + down_interruptible(&c->lct_sem); + if(signal_pending(current)) + { + dprintk(KERN_ERR "%s: LCT thread dead\n", c->name); + c->lct_running = 0; + return 0; + } + + entries = c->dlct->table_size; + entries -= 3; + entries /= 9; + + dprintk(KERN_INFO "%s: Dynamic LCT Update\n",c->name); + dprintk(KERN_INFO "%s: Dynamic LCT contains %d entries\n", c->name, entries); + + if(!entries) + { + printk(KERN_INFO "%s: Empty LCT???\n", c->name); + continue; + } + + /* + * Loop through all the devices on the IOP looking for their + * LCT data in the LCT. We assume that TIDs are not repeated. + * as that is the only way to really tell. It's been confirmed + * by the IRTOS vendor(s?) that TIDs are not reused until they + * wrap arround(4096), and I doubt a system will up long enough + * to create/delete that many devices. + */ + for(d = c->devices; d; ) + { + found = 0; + d1 = d->next; + + for(i = 0; i < entries; i++) + { + if(d->lct_data.tid == c->dlct->lct_entry[i].tid) + { + found = 1; + break; + } + } + if(!found) + { + dprintk(KERN_INFO "i2o_core: Deleted device!\n"); + spin_lock(&i2o_dev_lock); + i2o_delete_device(d); + spin_unlock(&i2o_dev_lock); + } + d = d1; + } + + /* + * Tell LCT to renotify us next time there is a change + */ + i2o_lct_notify(c); + + /* + * Copy new LCT into public LCT + * + * Possible race if someone is reading LCT while we are copying + * over it. If this happens, we'll fix it then. but I doubt that + * the LCT will get updated often enough or will get read by + * a user often enough to worry. + */ + if(c->lct->table_size < c->dlct->table_size) + { + tmp = c->lct; + c->lct = kmalloc(c->dlct->table_size<<2, GFP_KERNEL); + if(!c->lct) + { + printk(KERN_ERR "%s: No memory for LCT!\n", c->name); + c->lct = tmp; + continue; + } + kfree(tmp); + } + memcpy(c->lct, c->dlct, c->dlct->table_size<<2); + } + + return 0; +} + +/** + * i2o_run_queue - process pending events on a controller + * @c: controller to process + * + * This is called by the bus specific driver layer when an interrupt + * or poll of this card interface is desired. + */ + +void i2o_run_queue(struct i2o_controller *c) +{ + struct i2o_message *m; + u32 mv; + u32 *msg; + + /* + * Old 960 steppings had a bug in the I2O unit that caused + * the queue to appear empty when it wasn't. + */ + if((mv=I2O_REPLY_READ32(c))==0xFFFFFFFF) + mv=I2O_REPLY_READ32(c); + + while(mv!=0xFFFFFFFF) + { + struct i2o_handler *i; + m=(struct i2o_message *)bus_to_virt(mv); + msg=(u32*)m; + + i=i2o_handlers[m->initiator_context&(MAX_I2O_MODULES-1)]; + if(i && i->reply) + i->reply(i,c,m); + else + { + printk(KERN_WARNING "I2O: Spurious reply to handler %d\n", + m->initiator_context&(MAX_I2O_MODULES-1)); + } + i2o_flush_reply(c,mv); + mb(); + + /* That 960 bug again... */ + if((mv=I2O_REPLY_READ32(c))==0xFFFFFFFF) + mv=I2O_REPLY_READ32(c); + } +} + + +/** + * i2o_get_class_name - do i2o class name lookup + * @class: class number + * + * Return a descriptive string for an i2o class + */ + +const char *i2o_get_class_name(int class) +{ + int idx = 16; + static char *i2o_class_name[] = { + "Executive", + "Device Driver Module", + "Block Device", + "Tape Device", + "LAN Interface", + "WAN Interface", + "Fibre Channel Port", + "Fibre Channel Device", + "SCSI Device", + "ATE Port", + "ATE Device", + "Floppy Controller", + "Floppy Device", + "Secondary Bus Port", + "Peer Transport Agent", + "Peer Transport", + "Unknown" + }; + + switch(class&0xFFF) + { + case I2O_CLASS_EXECUTIVE: + idx = 0; break; + case I2O_CLASS_DDM: + idx = 1; break; + case I2O_CLASS_RANDOM_BLOCK_STORAGE: + idx = 2; break; + case I2O_CLASS_SEQUENTIAL_STORAGE: + idx = 3; break; + case I2O_CLASS_LAN: + idx = 4; break; + case I2O_CLASS_WAN: + idx = 5; break; + case I2O_CLASS_FIBRE_CHANNEL_PORT: + idx = 6; break; + case I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL: + idx = 7; break; + case I2O_CLASS_SCSI_PERIPHERAL: + idx = 8; break; + case I2O_CLASS_ATE_PORT: + idx = 9; break; + case I2O_CLASS_ATE_PERIPHERAL: + idx = 10; break; + case I2O_CLASS_FLOPPY_CONTROLLER: + idx = 11; break; + case I2O_CLASS_FLOPPY_DEVICE: + idx = 12; break; + case I2O_CLASS_BUS_ADAPTER_PORT: + idx = 13; break; + case I2O_CLASS_PEER_TRANSPORT_AGENT: + idx = 14; break; + case I2O_CLASS_PEER_TRANSPORT: + idx = 15; break; + } + + return i2o_class_name[idx]; +} + + +/** + * i2o_wait_message + * @c: controller + * @why: explanation + * + * This function waits up to 5 seconds for a message slot to be + * available. If no message is available it prints an error message + * that is expected to be what the message will be used for (eg + * "get_status"). 0xFFFFFFFF is returned on a failure. + * + * On a success the message is returned. This is the physical page + * frame offset address from the read port. (See the i2o spec) + */ + +u32 i2o_wait_message(struct i2o_controller *c, char *why) +{ + long time=jiffies; + u32 m; + while((m=I2O_POST_READ32(c))==0xFFFFFFFF) + { + if((jiffies-time)>=5*HZ) + { + dprintk(KERN_ERR "%s: Timeout waiting for message frame to send %s.\n", + c->name, why); + return 0xFFFFFFFF; + } + schedule(); + barrier(); + } + return m; +} + +/** + * i2o_report_controller_unit - print information about a tid + * @c: controller + * @d: device + * + * Dump an information block associated with a given unit (TID). The + * tables are read and a block of text is output to printk that is + * formatted intended for the user. + */ + +void i2o_report_controller_unit(struct i2o_controller *c, struct i2o_device *d) +{ + char buf[64]; + char str[22]; + int ret; + int unit = d->lct_data.tid; + + if(verbose==0) + return; + + printk(KERN_INFO "Target ID %d.\n", unit); + if((ret=i2o_query_scalar(c, unit, 0xF100, 3, buf, 16))>=0) + { + buf[16]=0; + printk(KERN_INFO " Vendor: %s\n", buf); + } + if((ret=i2o_query_scalar(c, unit, 0xF100, 4, buf, 16))>=0) + { + buf[16]=0; + printk(KERN_INFO " Device: %s\n", buf); + } + if(i2o_query_scalar(c, unit, 0xF100, 5, buf, 16)>=0) + { + buf[16]=0; + printk(KERN_INFO " Description: %s\n", buf); + } + if((ret=i2o_query_scalar(c, unit, 0xF100, 6, buf, 8))>=0) + { + buf[8]=0; + printk(KERN_INFO " Rev: %s\n", buf); + } + + printk(KERN_INFO " Class: "); + sprintf(str, "%-21s", i2o_get_class_name(d->lct_data.class_id)); + printk("%s\n", str); + + printk(KERN_INFO " Subclass: 0x%04X\n", d->lct_data.sub_class); + printk(KERN_INFO " Flags: "); + + if(d->lct_data.device_flags&(1<<0)) + printk("C"); // ConfigDialog requested + if(d->lct_data.device_flags&(1<<1)) + printk("U"); // Multi-user capable + if(!(d->lct_data.device_flags&(1<<4))) + printk("P"); // Peer service enabled! + if(!(d->lct_data.device_flags&(1<<5))) + printk("M"); // Mgmt service enabled! + printk("\n"); + +} + + +/* + * Parse the hardware resource table. Right now we print it out + * and don't do a lot with it. We should collate these and then + * interact with the Linux resource allocation block. + * + * Lets prove we can read it first eh ? + * + * This is full of endianisms! + */ + +static int i2o_parse_hrt(struct i2o_controller *c) +{ +#ifdef DRIVERDEBUG + u32 *rows=(u32*)c->hrt; + u8 *p=(u8 *)c->hrt; + u8 *d; + int count; + int length; + int i; + int state; + + if(p[3]!=0) + { + printk(KERN_ERR "%s: HRT table for controller is too new a version.\n", + c->name); + return -1; + } + + count=p[0]|(p[1]<<8); + length = p[2]; + + printk(KERN_INFO "%s: HRT has %d entries of %d bytes each.\n", + c->name, count, length<<2); + + rows+=2; + + for(i=0;i<count;i++) + { + printk(KERN_INFO "Adapter %08X: ", rows[0]); + p=(u8 *)(rows+1); + d=(u8 *)(rows+2); + state=p[1]<<8|p[0]; + + printk("TID %04X:[", state&0xFFF); + state>>=12; + if(state&(1<<0)) + printk("H"); /* Hidden */ + if(state&(1<<2)) + { + printk("P"); /* Present */ + if(state&(1<<1)) + printk("C"); /* Controlled */ + } + if(state>9) + printk("*"); /* Hard */ + + printk("]:"); + + switch(p[3]&0xFFFF) + { + case 0: + /* Adapter private bus - easy */ + printk("Local bus %d: I/O at 0x%04X Mem 0x%08X", + p[2], d[1]<<8|d[0], *(u32 *)(d+4)); + break; + case 1: + /* ISA bus */ + printk("ISA %d: CSN %d I/O at 0x%04X Mem 0x%08X", + p[2], d[2], d[1]<<8|d[0], *(u32 *)(d+4)); + break; + + case 2: /* EISA bus */ + printk("EISA %d: Slot %d I/O at 0x%04X Mem 0x%08X", + p[2], d[3], d[1]<<8|d[0], *(u32 *)(d+4)); + break; + + case 3: /* MCA bus */ + printk("MCA %d: Slot %d I/O at 0x%04X Mem 0x%08X", + p[2], d[3], d[1]<<8|d[0], *(u32 *)(d+4)); + break; + + case 4: /* PCI bus */ + printk("PCI %d: Bus %d Device %d Function %d", + p[2], d[2], d[1], d[0]); + break; + + case 0x80: /* Other */ + default: + printk("Unsupported bus type."); + break; + } + printk("\n"); + rows+=length; + } +#endif + return 0; +} + +/* + * The logical configuration table tells us what we can talk to + * on the board. Most of the stuff isn't interesting to us. + */ + +static int i2o_parse_lct(struct i2o_controller *c) +{ + int i; + int max; + int tid; + struct i2o_device *d; + i2o_lct *lct = c->lct; + + if (lct == NULL) { + printk(KERN_ERR "%s: LCT is empty???\n", c->name); + return -1; + } + + max = lct->table_size; + max -= 3; + max /= 9; + + printk(KERN_INFO "%s: LCT has %d entries.\n", c->name, max); + + if(lct->iop_flags&(1<<0)) + printk(KERN_WARNING "%s: Configuration dialog desired.\n", c->name); + + for(i=0;i<max;i++) + { + d = (struct i2o_device *)kmalloc(sizeof(struct i2o_device), GFP_KERNEL); + if(d==NULL) + { + printk(KERN_CRIT "i2o_core: Out of memory for I2O device data.\n"); + return -ENOMEM; + } + + d->controller = c; + d->next = NULL; + + memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry)); + + d->flags = 0; + tid = d->lct_data.tid; + + i2o_report_controller_unit(c, d); + + i2o_install_device(c, d); + } + return 0; +} + + +/** + * i2o_quiesce_controller - quiesce controller + * @c: controller + * + * Quiesce an IOP. Causes IOP to make external operation quiescent + * (i2o 'READY' state). Internal operation of the IOP continues normally. + */ + +int i2o_quiesce_controller(struct i2o_controller *c) +{ + u32 msg[4]; + int ret; + + i2o_status_get(c); + + /* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */ + + if ((c->status_block->iop_state != ADAPTER_STATE_READY) && + (c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL)) + { + return 0; + } + + msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID; + msg[3] = 0; + + /* Long timeout needed for quiesce if lots of devices */ + + if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240))) + printk(KERN_INFO "%s: Unable to quiesce (status=%#x).\n", + c->name, -ret); + else + dprintk(KERN_INFO "%s: Quiesced.\n", c->name); + + i2o_status_get(c); // Entered READY state + return ret; +} + +/** + * i2o_enable_controller - move controller from ready to operational + * @c: controller + * + * Enable IOP. This allows the IOP to resume external operations and + * reverses the effect of a quiesce. In the event of an error a negative + * errno code is returned. + */ + +int i2o_enable_controller(struct i2o_controller *c) +{ + u32 msg[4]; + int ret; + + i2o_status_get(c); + + /* Enable only allowed on READY state */ + if(c->status_block->iop_state != ADAPTER_STATE_READY) + return -EINVAL; + + msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID; + + /* How long of a timeout do we need? */ + + if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240))) + printk(KERN_ERR "%s: Could not enable (status=%#x).\n", + c->name, -ret); + else + dprintk(KERN_INFO "%s: Enabled.\n", c->name); + + i2o_status_get(c); // entered OPERATIONAL state + + return ret; +} + +/** + * i2o_clear_controller - clear a controller + * @c: controller + * + * Clear an IOP to HOLD state, ie. terminate external operations, clear all + * input queues and prepare for a system restart. IOP's internal operation + * continues normally and the outbound queue is alive. + * The IOP is not expected to rebuild its LCT. + */ + +int i2o_clear_controller(struct i2o_controller *c) +{ + struct i2o_controller *iop; + u32 msg[4]; + int ret; + + /* Quiesce all IOPs first */ + + for (iop = i2o_controller_chain; iop; iop = iop->next) + i2o_quiesce_controller(iop); + + msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1]=I2O_CMD_ADAPTER_CLEAR<<24|HOST_TID<<12|ADAPTER_TID; + msg[3]=0; + + if ((ret=i2o_post_wait(c, msg, sizeof(msg), 30))) + printk(KERN_INFO "%s: Unable to clear (status=%#x).\n", + c->name, -ret); + else + dprintk(KERN_INFO "%s: Cleared.\n",c->name); + + i2o_status_get(c); + + /* Enable other IOPs */ + + for (iop = i2o_controller_chain; iop; iop = iop->next) + if (iop != c) + i2o_enable_controller(iop); + + return ret; +} + + +/** + * i2o_reset_controller + * @c: controller to reset + * + * Reset the IOP into INIT state and wait until IOP gets into RESET state. + * Terminate all external operations, clear IOP's inbound and outbound + * queues, terminate all DDMs, and reload the IOP's operating environment + * and all local DDMs. The IOP rebuilds its LCT. + */ + +static int i2o_reset_controller(struct i2o_controller *c) +{ + struct i2o_controller *iop; + u32 m; + u8 *status; + u32 *msg; + long time; + + /* Quiesce all IOPs first */ + + for (iop = i2o_controller_chain; iop; iop = iop->next) + i2o_quiesce_controller(iop); + + m=i2o_wait_message(c, "AdapterReset"); + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + msg=(u32 *)(c->mem_offset+m); + + status=(void *)kmalloc(4, GFP_KERNEL); + if(status==NULL) { + printk(KERN_ERR "IOP reset failed - no free memory.\n"); + return -ENOMEM; + } + memset(status, 0, 4); + + msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID; + msg[2]=core_context; + msg[3]=0; + msg[4]=0; + msg[5]=0; + msg[6]=virt_to_bus(status); + msg[7]=0; /* 64bit host FIXME */ + + i2o_post_message(c,m); + + /* Wait for a reply */ + time=jiffies; + while(status[0]==0) + { + if((jiffies-time)>=20*HZ) + { + printk(KERN_ERR "IOP reset timeout.\n"); + kfree(status); + return -ETIMEDOUT; + } + schedule(); + barrier(); + } + + if (status[0]==I2O_CMD_IN_PROGRESS) + { + /* + * Once the reset is sent, the IOP goes into the INIT state + * which is indeterminate. We need to wait until the IOP + * has rebooted before we can let the system talk to + * it. We read the inbound Free_List until a message is + * available. If we can't read one in the given ammount of + * time, we assume the IOP could not reboot properly. + */ + + dprintk(KERN_INFO "%s: Reset in progress, waiting for reboot...\n", + c->name); + + time = jiffies; + m = I2O_POST_READ32(c); + while(m == 0XFFFFFFFF) + { + if((jiffies-time) >= 30*HZ) + { + printk(KERN_ERR "%s: Timeout waiting for IOP reset.\n", + c->name); + return -ETIMEDOUT; + } + schedule(); + barrier(); + m = I2O_POST_READ32(c); + } + i2o_flush_reply(c,m); + } + + /* If IopReset was rejected or didn't perform reset, try IopClear */ + + i2o_status_get(c); + if (status[0] == I2O_CMD_REJECTED || + c->status_block->iop_state != ADAPTER_STATE_RESET) + { + printk(KERN_WARNING "%s: Reset rejected, trying to clear\n",c->name); + i2o_clear_controller(c); + } + else + dprintk(KERN_INFO "%s: Reset completed.\n", c->name); + + /* Enable other IOPs */ + + for (iop = i2o_controller_chain; iop; iop = iop->next) + if (iop != c) + i2o_enable_controller(iop); + + kfree(status); + return 0; +} + + +/** + * i2o_status_get - get the status block for the IOP + * @c: controller + * + * Issue a status query on the controller. This updates the + * attached status_block. If the controller fails to reply or an + * error occurs then a negative errno code is returned. On success + * zero is returned and the status_blok is updated. + */ + +int i2o_status_get(struct i2o_controller *c) +{ + long time; + u32 m; + u32 *msg; + u8 *status_block; + + if (c->status_block == NULL) + { + c->status_block = (i2o_status_block *) + kmalloc(sizeof(i2o_status_block),GFP_KERNEL); + if (c->status_block == NULL) + { + printk(KERN_CRIT "%s: Get Status Block failed; Out of memory.\n", + c->name); + return -ENOMEM; + } + } + + status_block = (u8*)c->status_block; + memset(c->status_block,0,sizeof(i2o_status_block)); + + m=i2o_wait_message(c, "StatusGet"); + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + msg=(u32 *)(c->mem_offset+m); + + msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1]=I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID; + msg[2]=core_context; + msg[3]=0; + msg[4]=0; + msg[5]=0; + msg[6]=virt_to_bus(c->status_block); + msg[7]=0; /* 64bit host FIXME */ + msg[8]=sizeof(i2o_status_block); /* always 88 bytes */ + + i2o_post_message(c,m); + + /* Wait for a reply */ + + time=jiffies; + while(status_block[87]!=0xFF) + { + if((jiffies-time)>=5*HZ) + { + printk(KERN_ERR "%s: Get status timeout.\n",c->name); + return -ETIMEDOUT; + } + schedule(); + barrier(); + } + +#ifdef DRIVERDEBUG + printk(KERN_INFO "%s: State = ", c->name); + switch (c->status_block->iop_state) { + case 0x01: + printk("INIT\n"); + break; + case 0x02: + printk("RESET\n"); + break; + case 0x04: + printk("HOLD\n"); + break; + case 0x05: + printk("READY\n"); + break; + case 0x08: + printk("OPERATIONAL\n"); + break; + case 0x10: + printk("FAILED\n"); + break; + case 0x11: + printk("FAULTED\n"); + break; + default: + printk("%x (unknown !!)\n",c->status_block->iop_state); +} +#endif + + return 0; +} + +/* + * Get the Hardware Resource Table for the device. + * The HRT contains information about possible hidden devices + * but is mostly useless to us + */ +int i2o_hrt_get(struct i2o_controller *c) +{ + u32 msg[6]; + int ret, size = sizeof(i2o_hrt); + + /* Read first just the header to figure out the real size */ + + do { + if (c->hrt == NULL) { + c->hrt=kmalloc(size, GFP_KERNEL); + if (c->hrt == NULL) { + printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", c->name); + return -ENOMEM; + } + } + + msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4; + msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[3]= 0; + msg[4]= (0xD0000000 | size); /* Simple transaction */ + msg[5]= virt_to_bus(c->hrt); /* Dump it here */ + + if ((ret = i2o_post_wait(c, msg, sizeof(msg), 20))) { + printk(KERN_ERR "%s: Unable to get HRT (status=%#x)\n", + c->name, -ret); + return ret; + } + + if (c->hrt->num_entries * c->hrt->entry_len << 2 > size) { + size = c->hrt->num_entries * c->hrt->entry_len << 2; + kfree(c->hrt); + c->hrt = NULL; + } + } while (c->hrt == NULL); + + i2o_parse_hrt(c); // just for debugging + + return 0; +} + +/* + * Send the I2O System Table to the specified IOP + * + * The system table contains information about all the IOPs in the + * system. It is build and then sent to each IOP so that IOPs can + * establish connections between each other. + * + */ +static int i2o_systab_send(struct i2o_controller *iop) +{ + u32 msg[12]; + u32 privmem[2]; + u32 privio[2]; + int ret; + + privmem[0] = iop->status_block->current_mem_base; + privmem[1] = iop->status_block->current_mem_size; + privio[0] = iop->status_block->current_io_base; + privio[1] = iop->status_block->current_io_size; + + msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6; + msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[3] = 0; + msg[4] = (0<<16) | ((iop->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */ + msg[5] = 0; /* Segment 0 */ + + /* + * Provide three SGL-elements: + * System table (SysTab), Private memory space declaration and + * Private i/o space declaration + */ + msg[6] = 0x54000000 | sys_tbl_len; + msg[7] = virt_to_bus(sys_tbl); + msg[8] = 0x54000000 | 0; + msg[9] = virt_to_bus(privmem); + msg[10] = 0xD4000000 | 0; + msg[11] = virt_to_bus(privio); + + if ((ret=i2o_post_wait(iop, msg, sizeof(msg), 120))) + printk(KERN_INFO "%s: Unable to set SysTab (status=%#x).\n", + iop->name, -ret); + else + dprintk(KERN_INFO "%s: SysTab set.\n", iop->name); + + i2o_status_get(iop); // Entered READY state + + return ret; + + } + +/* + * Initialize I2O subsystem. + */ +static void __init i2o_sys_init(void) +{ + struct i2o_controller *iop, *niop = NULL; + + printk(KERN_INFO "Activating I2O controllers...\n"); + printk(KERN_INFO "This may take a few minutes if there are many devices\n"); + + /* In INIT state, Activate IOPs */ + for (iop = i2o_controller_chain; iop; iop = niop) { + dprintk(KERN_INFO "Calling i2o_activate_controller for %s...\n", + iop->name); + niop = iop->next; + if (i2o_activate_controller(iop) < 0) + i2o_delete_controller(iop); + } + + /* Active IOPs in HOLD state */ + +rebuild_sys_tab: + if (i2o_controller_chain == NULL) + return; + + /* + * If build_sys_table fails, we kill everything and bail + * as we can't init the IOPs w/o a system table + */ + dprintk(KERN_INFO "i2o_core: Calling i2o_build_sys_table...\n"); + if (i2o_build_sys_table() < 0) { + i2o_sys_shutdown(); + return; + } + + /* If IOP don't get online, we need to rebuild the System table */ + for (iop = i2o_controller_chain; iop; iop = niop) { + niop = iop->next; + dprintk(KERN_INFO "Calling i2o_online_controller for %s...\n", iop->name); + if (i2o_online_controller(iop) < 0) { + i2o_delete_controller(iop); + goto rebuild_sys_tab; + } + } + + /* Active IOPs now in OPERATIONAL state */ + + /* + * Register for status updates from all IOPs + */ + for(iop = i2o_controller_chain; iop; iop=iop->next) { + + /* Create a kernel thread to deal with dynamic LCT updates */ + iop->lct_pid = kernel_thread(i2o_dyn_lct, iop, CLONE_SIGHAND); + + /* Update change ind on DLCT */ + iop->dlct->change_ind = iop->lct->change_ind; + + /* Start dynamic LCT updates */ + i2o_lct_notify(iop); + + /* Register for all events from IRTOS */ + i2o_event_register(iop, core_context, 0, 0, 0xFFFFFFFF); + } +} + +/** + * i2o_sys_shutdown - shutdown I2O system + * + * Bring down each i2o controller and then return. Each controller + * is taken through an orderly shutdown + */ + +static void i2o_sys_shutdown(void) +{ + struct i2o_controller *iop, *niop; + + /* Delete all IOPs from the controller chain */ + /* that will reset all IOPs too */ + + for (iop = i2o_controller_chain; iop; iop = niop) { + niop = iop->next; + i2o_delete_controller(iop); + } +} + +/** + * i2o_activate_controller - bring controller up to HOLD + * @iop: controller + * + * This function brings an I2O controller into HOLD state. The adapter + * is reset if neccessary and then the queues and resource table + * are read. -1 is returned on a failure, 0 on success. + * + */ + +int i2o_activate_controller(struct i2o_controller *iop) +{ + /* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */ + /* In READY state, Get status */ + + if (i2o_status_get(iop) < 0) { + printk(KERN_INFO "Unable to obtain status of %s, " + "attempting a reset.\n", iop->name); + if (i2o_reset_controller(iop) < 0) + return -1; + } + + if(iop->status_block->iop_state == ADAPTER_STATE_FAULTED) { + printk(KERN_CRIT "%s: hardware fault\n", iop->name); + return -1; + } + + if (iop->status_block->i2o_version > I2OVER15) { + printk(KERN_ERR "%s: Not running vrs. 1.5. of the I2O Specification.\n", + iop->name); + return -1; + } + + if (iop->status_block->iop_state == ADAPTER_STATE_READY || + iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL || + iop->status_block->iop_state == ADAPTER_STATE_HOLD || + iop->status_block->iop_state == ADAPTER_STATE_FAILED) + { + dprintk(KERN_INFO "%s: Already running, trying to reset...\n", + iop->name); + if (i2o_reset_controller(iop) < 0) + return -1; + } + + if (i2o_init_outbound_q(iop) < 0) + return -1; + + if (i2o_post_outbound_messages(iop)) + return -1; + + /* In HOLD state */ + + if (i2o_hrt_get(iop) < 0) + return -1; + + return 0; +} + + +/** + * i2o_init_outbound_queue - setup the outbound queue + * @c: controller + * + * Clear and (re)initialize IOP's outbound queue. Returns 0 on + * success or a negative errno code on a failure. + */ + +int i2o_init_outbound_q(struct i2o_controller *c) +{ + u8 *status; + u32 m; + u32 *msg; + u32 time; + + dprintk(KERN_INFO "%s: Initializing Outbound Queue...\n", c->name); + m=i2o_wait_message(c, "OutboundInit"); + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + msg=(u32 *)(c->mem_offset+m); + + status = kmalloc(4,GFP_KERNEL); + if (status==NULL) { + printk(KERN_ERR "%s: Outbound Queue initialization failed - no free memory.\n", + c->name); + return -ENOMEM; + } + memset(status, 0, 4); + + msg[0]= EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6; + msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2]= core_context; + msg[3]= 0x0106; /* Transaction context */ + msg[4]= 4096; /* Host page frame size */ + /* Frame size is in words. Pick 128, its what everyone elses uses and + other sizes break some adapters. */ + msg[5]= MSG_FRAME_SIZE<<16|0x80; /* Outbound msg frame size and Initcode */ + msg[6]= 0xD0000004; /* Simple SG LE, EOB */ + msg[7]= virt_to_bus(status); + + i2o_post_message(c,m); + + barrier(); + time=jiffies; + while(status[0] < I2O_CMD_REJECTED) + { + if((jiffies-time)>=30*HZ) + { + if(status[0]==0x00) + printk(KERN_ERR "%s: Ignored queue initialize request.\n", + c->name); + else + printk(KERN_ERR "%s: Outbound queue initialize timeout.\n", + c->name); + kfree(status); + return -ETIMEDOUT; + } + schedule(); + barrier(); + } + + if(status[0] != I2O_CMD_COMPLETED) + { + printk(KERN_ERR "%s: IOP outbound initialise failed.\n", c->name); + kfree(status); + return -ETIMEDOUT; + } + + return 0; +} + +/** + * i2o_post_outbound_messages - fill message queue + * @c: controller + * + * Allocate a message frame and load the messages into the IOP. The + * function returns zero on success or a negative errno code on + * failure. + */ + +int i2o_post_outbound_messages(struct i2o_controller *c) +{ + int i; + u32 m; + /* Alloc space for IOP's outbound queue message frames */ + + c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL); + if(c->page_frame==NULL) { + printk(KERN_CRIT "%s: Outbound Q initialize failed; out of memory.\n", + c->name); + return -ENOMEM; + } + m=virt_to_bus(c->page_frame); + + /* Post frames */ + + for(i=0; i< NMBR_MSG_FRAMES; i++) { + I2O_REPLY_WRITE32(c,m); + mb(); + m += MSG_FRAME_SIZE; + } + + return 0; +} + +/* + * Get the IOP's Logical Configuration Table + */ +int i2o_lct_get(struct i2o_controller *c) +{ + u32 msg[8]; + int ret, size = c->status_block->expected_lct_size; + + do { + if (c->lct == NULL) { + c->lct = kmalloc(size, GFP_KERNEL); + if(c->lct == NULL) { + printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n", + c->name); + return -ENOMEM; + } + } + memset(c->lct, 0, size); + + msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6; + msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID; + /* msg[2] filled in i2o_post_wait */ + msg[3] = 0; + msg[4] = 0xFFFFFFFF; /* All devices */ + msg[5] = 0x00000000; /* Report now */ + msg[6] = 0xD0000000|size; + msg[7] = virt_to_bus(c->lct); + + if ((ret=i2o_post_wait(c, msg, sizeof(msg), 120))) { + printk(KERN_ERR "%s: LCT Get failed (status=%#x.\n", + c->name, -ret); + return ret; + } + + if (c->lct->table_size << 2 > size) { + size = c->lct->table_size << 2; + kfree(c->lct); + c->lct = NULL; + } + } while (c->lct == NULL); + + if ((ret=i2o_parse_lct(c)) < 0) + return ret; + + return 0; +} + +/* + * Like above, but used for async notification. The main + * difference is that we keep track of the CurrentChangeIndiicator + * so that we only get updates when it actually changes. + * + */ +int i2o_lct_notify(struct i2o_controller *c) +{ + u32 msg[8]; + + msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6; + msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2] = core_context; + msg[3] = 0xDEADBEEF; + msg[4] = 0xFFFFFFFF; /* All devices */ + msg[5] = c->dlct->change_ind+1; /* Next change */ + msg[6] = 0xD0000000|8192; + msg[7] = virt_to_bus(c->dlct); + + return i2o_post_this(c, msg, sizeof(msg)); +} + +/* + * Bring a controller online into OPERATIONAL state. + */ +int i2o_online_controller(struct i2o_controller *iop) +{ + if (i2o_systab_send(iop) < 0) + return -1; + + /* In READY state */ + + dprintk(KERN_INFO "%s: Attempting to enable...\n", iop->name); + if (i2o_enable_controller(iop) < 0) + return -1; + + /* In OPERATIONAL state */ + + dprintk(KERN_INFO "%s: Attempting to get/parse lct...\n", iop->name); + if (i2o_lct_get(iop) < 0) + return -1; + + return 0; +} + +/* + * Build system table + * + * The system table contains information about all the IOPs in the + * system (duh) and is used by the Executives on the IOPs to establish + * peer2peer connections. We're not supporting peer2peer at the moment, + * but this will be needed down the road for things like lan2lan forwarding. + */ +static int i2o_build_sys_table(void) +{ + struct i2o_controller *iop = NULL; + struct i2o_controller *niop = NULL; + int count = 0; + + sys_tbl_len = sizeof(struct i2o_sys_tbl) + // Header + IOPs + (i2o_num_controllers) * + sizeof(struct i2o_sys_tbl_entry); + + if(sys_tbl) + kfree(sys_tbl); + + sys_tbl = kmalloc(sys_tbl_len, GFP_KERNEL); + if(!sys_tbl) { + printk(KERN_CRIT "SysTab Set failed. Out of memory.\n"); + return -ENOMEM; + } + memset((void*)sys_tbl, 0, sys_tbl_len); + + sys_tbl->num_entries = i2o_num_controllers; + sys_tbl->version = I2OVERSION; /* TODO: Version 2.0 */ + sys_tbl->change_ind = sys_tbl_ind++; + + for(iop = i2o_controller_chain; iop; iop = niop) + { + niop = iop->next; + + /* + * Get updated IOP state so we have the latest information + * + * We should delete the controller at this point if it + * doesn't respond since if it's not on the system table + * it is techninically not part of the I2O subsyßtem... + */ + if(i2o_status_get(iop)) { + printk(KERN_ERR "%s: Deleting b/c could not get status while" + "attempting to build system table\n", iop->name); + i2o_delete_controller(iop); + sys_tbl->num_entries--; + continue; // try the next one + } + + sys_tbl->iops[count].org_id = iop->status_block->org_id; + sys_tbl->iops[count].iop_id = iop->unit + 2; + sys_tbl->iops[count].seg_num = 0; + sys_tbl->iops[count].i2o_version = + iop->status_block->i2o_version; + sys_tbl->iops[count].iop_state = + iop->status_block->iop_state; + sys_tbl->iops[count].msg_type = + iop->status_block->msg_type; + sys_tbl->iops[count].frame_size = + iop->status_block->inbound_frame_size; + sys_tbl->iops[count].last_changed = sys_tbl_ind - 1; // ?? + sys_tbl->iops[count].iop_capabilities = + iop->status_block->iop_capabilities; + sys_tbl->iops[count].inbound_low = + (u32)virt_to_bus(iop->post_port); + sys_tbl->iops[count].inbound_high = 0; // TODO: 64-bit support + + count++; + } + +#ifdef DRIVERDEBUG +{ + u32 *table; + table = (u32*)sys_tbl; + for(count = 0; count < (sys_tbl_len >>2); count++) + printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", count, table[count]); +} +#endif + + return 0; +} + + +/* + * Run time support routines + */ + +/* + * Generic "post and forget" helpers. This is less efficient - we do + * a memcpy for example that isnt strictly needed, but for most uses + * this is simply not worth optimising + */ + +int i2o_post_this(struct i2o_controller *c, u32 *data, int len) +{ + u32 m; + u32 *msg; + unsigned long t=jiffies; + + do + { + mb(); + m = I2O_POST_READ32(c); + } + while(m==0xFFFFFFFF && (jiffies-t)<HZ); + + if(m==0xFFFFFFFF) + { + printk(KERN_ERR "%s: Timeout waiting for message frame!\n", + c->name); + return -ETIMEDOUT; + } + msg = (u32 *)(c->mem_offset + m); + memcpy_toio(msg, data, len); + i2o_post_message(c,m); + return 0; +} + +/* + * This core API allows an OSM to post a message and then be told whether + * or not the system received a successful reply. It is useful when + * the OSM does not want to know the exact 3 + */ +int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout) +{ + DECLARE_WAIT_QUEUE_HEAD(wq_i2o_post); + int status = 0; + int flags = 0; + struct i2o_post_wait_data *p1, *p2; + struct i2o_post_wait_data *wait_data = + kmalloc(sizeof(struct i2o_post_wait_data), GFP_KERNEL); + + if(!wait_data) + return -ENOMEM; + + /* + * The spin locking is needed to keep anyone from playing + * with the queue pointers and id while we do the same + */ + spin_lock_irqsave(&post_wait_lock, flags); + wait_data->next = post_wait_queue; + post_wait_queue = wait_data; + wait_data->id = (++post_wait_id) & 0x7fff; + spin_unlock_irqrestore(&post_wait_lock, flags); + + wait_data->wq = &wq_i2o_post; + wait_data->status = -ETIMEDOUT; + + msg[2] = 0x80000000|(u32)core_context|((u32)wait_data->id<<16); + + if ((status = i2o_post_this(c, msg, len))==0) { + interruptible_sleep_on_timeout(&wq_i2o_post, HZ * timeout); + status = wait_data->status; + } + if(signal_pending(current)) + status = -EINTR; + +#ifdef DRIVERDEBUG + if(status == -ETIMEDOUT) + printk(KERN_INFO "%s: POST WAIT TIMEOUT\n",c->name); +#endif + + /* + * Remove the entry from the queue. + * Since i2o_post_wait() may have been called again by + * a different thread while we were waiting for this + * instance to complete, we're not guaranteed that + * this entry is at the head of the queue anymore, so + * we need to search for it, find it, and delete it. + */ + p2 = NULL; + spin_lock_irqsave(&post_wait_lock, flags); + for(p1 = post_wait_queue; p1; p2 = p1, p1 = p1->next) { + if(p1 == wait_data) { + if(p2) + p2->next = p1->next; + else + post_wait_queue = p1->next; + + break; + } + } + spin_unlock_irqrestore(&post_wait_lock, flags); + + kfree(wait_data); + + return status; +} + +/* + * i2o_post_wait is completed and we want to wake up the + * sleeping proccess. Called by core's reply handler. + */ +static void i2o_post_wait_complete(u32 context, int status) +{ + struct i2o_post_wait_data *p1 = NULL; + + /* + * We need to search through the post_wait + * queue to see if the given message is still + * outstanding. If not, it means that the IOP + * took longer to respond to the message than we + * had allowed and timer has already expired. + * Not much we can do about that except log + * it for debug purposes, increase timeout, and recompile + * + * Lock needed to keep anyone from moving queue pointers + * around while we're looking through them. + */ + spin_lock(&post_wait_lock); + for(p1 = post_wait_queue; p1; p1 = p1->next) { + if(p1->id == ((context >> 16) & 0x7fff)) { + p1->status = status; + wake_up_interruptible(p1->wq); + spin_unlock(&post_wait_lock); + return; + } + } + spin_unlock(&post_wait_lock); + + printk(KERN_DEBUG "i2o_post_wait reply after timeout!\n"); +} + +/* Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET + * + * This function can be used for all UtilParamsGet/Set operations. + * The OperationList is given in oplist-buffer, + * and results are returned in reslist-buffer. + * Note that the minimum sized reslist is 8 bytes and contains + * ResultCount, ErrorInfoSize, BlockStatus and BlockSize. + */ +int i2o_issue_params(int cmd, struct i2o_controller *iop, int tid, + void *oplist, int oplen, void *reslist, int reslen) +{ + u32 msg[9]; + u8 *res = (u8 *)reslist; + u32 *res32 = (u32*)reslist; + u32 *restmp = (u32*)reslist; + int len = 0; + int i = 0; + int wait_status; + + msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5; + msg[1] = cmd << 24 | HOST_TID << 12 | tid; + msg[3] = 0; + msg[4] = 0; + msg[5] = 0x54000000 | oplen; /* OperationList */ + msg[6] = virt_to_bus(oplist); + msg[7] = 0xD0000000 | reslen; /* ResultList */ + msg[8] = virt_to_bus(reslist); + + if((wait_status = i2o_post_wait(iop, msg, sizeof(msg), 10))) + return wait_status; /* -DetailedStatus */ + + /* + * Calculate number of bytes of Result LIST + * We need to loop through each Result BLOCK and grab the length + */ + restmp = res32 + 1; + len = 1; + for(i = 0; i < (res32[0]&0X0000FFFF); i++) + { + if(restmp[0]&0x00FF0000) /* BlockStatus != SUCCESS */ + { + printk(KERN_WARNING "%s - Error:\n ErrorInfoSize = 0x%02x, " + "BlockStatus = 0x%02x, BlockSize = 0x%04x\n", + (cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET" + : "PARAMS_GET", + res32[1]>>24, (res32[1]>>16)&0xFF, res32[1]&0xFFFF); + + /* + * If this is the only request,than we return an error + */ + if((res32[0]&0x0000FFFF) == 1) + return -((res[1] >> 16) & 0xFF); /* -BlockStatus */ + } + + len += restmp[0] & 0x0000FFFF; /* Length of res BLOCK */ + restmp += restmp[0] & 0x0000FFFF; /* Skip to next BLOCK */ + } + + return (len << 2); /* bytes used by result list */ +} + +/* + * Query one scalar group value or a whole scalar group. + */ +int i2o_query_scalar(struct i2o_controller *iop, int tid, + int group, int field, void *buf, int buflen) +{ + u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field }; + u8 resblk[8+buflen]; /* 8 bytes for header */ + int size; + + if (field == -1) /* whole group */ + opblk[4] = -1; + + size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid, + opblk, sizeof(opblk), resblk, sizeof(resblk)); + + if (size < 0) + return size; + + memcpy(buf, resblk+8, buflen); /* cut off header */ + return size; +} + +/* + * Set a scalar group value or a whole group. + */ +int i2o_set_scalar(struct i2o_controller *iop, int tid, + int group, int field, void *buf, int buflen) +{ + u16 *opblk; + u8 resblk[8+buflen]; /* 8 bytes for header */ + int size; + + opblk = kmalloc(buflen+64, GFP_KERNEL); + if (opblk == NULL) + { + printk(KERN_ERR "i2o: no memory for operation buffer.\n"); + return -ENOMEM; + } + + opblk[0] = 1; /* operation count */ + opblk[1] = 0; /* pad */ + opblk[2] = I2O_PARAMS_FIELD_SET; + opblk[3] = group; + + if(field == -1) { /* whole group */ + opblk[4] = -1; + memcpy(opblk+5, buf, buflen); + } + else /* single field */ + { + opblk[4] = 1; + opblk[5] = field; + memcpy(opblk+6, buf, buflen); + } + + size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, + opblk, 12+buflen, resblk, sizeof(resblk)); + + kfree(opblk); + return size; +} + +/* + * if oper == I2O_PARAMS_TABLE_GET, get from all rows + * if fieldcount == -1 return all fields + * ibuf and ibuflen are unused (use NULL, 0) + * else return specific fields + * ibuf contains fieldindexes + * + * if oper == I2O_PARAMS_LIST_GET, get from specific rows + * if fieldcount == -1 return all fields + * ibuf contains rowcount, keyvalues + * else return specific fields + * fieldcount is # of fieldindexes + * ibuf contains fieldindexes, rowcount, keyvalues + * + * You could also use directly function i2o_issue_params(). + */ +int i2o_query_table(int oper, struct i2o_controller *iop, int tid, int group, + int fieldcount, void *ibuf, int ibuflen, + void *resblk, int reslen) +{ + u16 *opblk; + int size; + + opblk = kmalloc(10 + ibuflen, GFP_KERNEL); + if (opblk == NULL) + { + printk(KERN_ERR "i2o: no memory for query buffer.\n"); + return -ENOMEM; + } + + opblk[0] = 1; /* operation count */ + opblk[1] = 0; /* pad */ + opblk[2] = oper; + opblk[3] = group; + opblk[4] = fieldcount; + memcpy(opblk+5, ibuf, ibuflen); /* other params */ + + size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET,iop, tid, + opblk, 10+ibuflen, resblk, reslen); + + kfree(opblk); + return size; +} + +/* + * Clear table group, i.e. delete all rows. + */ +int i2o_clear_table(struct i2o_controller *iop, int tid, int group) +{ + u16 opblk[] = { 1, 0, I2O_PARAMS_TABLE_CLEAR, group }; + u8 resblk[32]; /* min 8 bytes for result header */ + + return i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, + opblk, sizeof(opblk), resblk, sizeof(resblk)); +} + +/* + * Add a new row into a table group. + * + * if fieldcount==-1 then we add whole rows + * buf contains rowcount, keyvalues + * else just specific fields are given, rest use defaults + * buf contains fieldindexes, rowcount, keyvalues + */ +int i2o_row_add_table(struct i2o_controller *iop, int tid, + int group, int fieldcount, void *buf, int buflen) +{ + u16 *opblk; + u8 resblk[32]; /* min 8 bytes for header */ + int size; + + opblk = kmalloc(buflen+64, GFP_KERNEL); + if (opblk == NULL) + { + printk(KERN_ERR "i2o: no memory for operation buffer.\n"); + return -ENOMEM; + } + + opblk[0] = 1; /* operation count */ + opblk[1] = 0; /* pad */ + opblk[2] = I2O_PARAMS_ROW_ADD; + opblk[3] = group; + opblk[4] = fieldcount; + memcpy(opblk+5, buf, buflen); + + size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, + opblk, 10+buflen, resblk, sizeof(resblk)); + + kfree(opblk); + return size; +} + + +/* + * Used for error reporting/debugging purposes. + * Following fail status are common to all classes. + * The preserved message must be handled in the reply handler. + */ +void i2o_report_fail_status(u8 req_status, u32* msg) +{ + static char *FAIL_STATUS[] = { + "0x80", /* not used */ + "SERVICE_SUSPENDED", /* 0x81 */ + "SERVICE_TERMINATED", /* 0x82 */ + "CONGESTION", + "FAILURE", + "STATE_ERROR", + "TIME_OUT", + "ROUTING_FAILURE", + "INVALID_VERSION", + "INVALID_OFFSET", + "INVALID_MSG_FLAGS", + "FRAME_TOO_SMALL", + "FRAME_TOO_LARGE", + "INVALID_TARGET_ID", + "INVALID_INITIATOR_ID", + "INVALID_INITIATOR_CONTEX", /* 0x8F */ + "UNKNOWN_FAILURE" /* 0xFF */ + }; + + if (req_status == I2O_FSC_TRANSPORT_UNKNOWN_FAILURE) + printk("TRANSPORT_UNKNOWN_FAILURE (%0#2x)\n.", req_status); + else + printk("TRANSPORT_%s.\n", FAIL_STATUS[req_status & 0x0F]); + + /* Dump some details */ + + printk(KERN_ERR " InitiatorId = %d, TargetId = %d\n", + (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF); + printk(KERN_ERR " LowestVersion = 0x%02X, HighestVersion = 0x%02X\n", + (msg[4] >> 8) & 0xFF, msg[4] & 0xFF); + printk(KERN_ERR " FailingHostUnit = 0x%04X, FailingIOP = 0x%03X\n", + msg[5] >> 16, msg[5] & 0xFFF); + + printk(KERN_ERR " Severity: 0x%02X ", (msg[4] >> 16) & 0xFF); + if (msg[4] & (1<<16)) + printk("(FormatError), " + "this msg can never be delivered/processed.\n"); + if (msg[4] & (1<<17)) + printk("(PathError), " + "this msg can no longer be delivered/processed.\n"); + if (msg[4] & (1<<18)) + printk("(PathState), " + "the system state does not allow delivery.\n"); + if (msg[4] & (1<<19)) + printk("(Congestion), resources temporarily not available;" + "do not retry immediately.\n"); +} + +/* + * Used for error reporting/debugging purposes. + * Following reply status are common to all classes. + */ +void i2o_report_common_status(u8 req_status) +{ + static char *REPLY_STATUS[] = { + "SUCCESS", + "ABORT_DIRTY", + "ABORT_NO_DATA_TRANSFER", + "ABORT_PARTIAL_TRANSFER", + "ERROR_DIRTY", + "ERROR_NO_DATA_TRANSFER", + "ERROR_PARTIAL_TRANSFER", + "PROCESS_ABORT_DIRTY", + "PROCESS_ABORT_NO_DATA_TRANSFER", + "PROCESS_ABORT_PARTIAL_TRANSFER", + "TRANSACTION_ERROR", + "PROGRESS_REPORT" + }; + + if (req_status > I2O_REPLY_STATUS_PROGRESS_REPORT) + printk("RequestStatus = %0#2x", req_status); + else + printk("%s", REPLY_STATUS[req_status]); +} + +/* + * Used for error reporting/debugging purposes. + * Following detailed status are valid for executive class, + * utility class, DDM class and for transaction error replies. + */ +static void i2o_report_common_dsc(u16 detailed_status) +{ + static char *COMMON_DSC[] = { + "SUCCESS", + "0x01", // not used + "BAD_KEY", + "TCL_ERROR", + "REPLY_BUFFER_FULL", + "NO_SUCH_PAGE", + "INSUFFICIENT_RESOURCE_SOFT", + "INSUFFICIENT_RESOURCE_HARD", + "0x08", // not used + "CHAIN_BUFFER_TOO_LARGE", + "UNSUPPORTED_FUNCTION", + "DEVICE_LOCKED", + "DEVICE_RESET", + "INAPPROPRIATE_FUNCTION", + "INVALID_INITIATOR_ADDRESS", + "INVALID_MESSAGE_FLAGS", + "INVALID_OFFSET", + "INVALID_PARAMETER", + "INVALID_REQUEST", + "INVALID_TARGET_ADDRESS", + "MESSAGE_TOO_LARGE", + "MESSAGE_TOO_SMALL", + "MISSING_PARAMETER", + "TIMEOUT", + "UNKNOWN_ERROR", + "UNKNOWN_FUNCTION", + "UNSUPPORTED_VERSION", + "DEVICE_BUSY", + "DEVICE_NOT_AVAILABLE" + }; + + if (detailed_status > I2O_DSC_DEVICE_NOT_AVAILABLE) + printk(" / DetailedStatus = %0#4x.\n", detailed_status); + else + printk(" / %s.\n", COMMON_DSC[detailed_status]); +} + +/* + * Used for error reporting/debugging purposes + */ +static void i2o_report_lan_dsc(u16 detailed_status) +{ + static char *LAN_DSC[] = { // Lan detailed status code strings + "SUCCESS", + "DEVICE_FAILURE", + "DESTINATION_NOT_FOUND", + "TRANSMIT_ERROR", + "TRANSMIT_ABORTED", + "RECEIVE_ERROR", + "RECEIVE_ABORTED", + "DMA_ERROR", + "BAD_PACKET_DETECTED", + "OUT_OF_MEMORY", + "BUCKET_OVERRUN", + "IOP_INTERNAL_ERROR", + "CANCELED", + "INVALID_TRANSACTION_CONTEXT", + "DEST_ADDRESS_DETECTED", + "DEST_ADDRESS_OMITTED", + "PARTIAL_PACKET_RETURNED", + "TEMP_SUSPENDED_STATE", // last Lan detailed status code + "INVALID_REQUEST" // general detailed status code + }; + + if (detailed_status > I2O_DSC_INVALID_REQUEST) + printk(" / %0#4x.\n", detailed_status); + else + printk(" / %s.\n", LAN_DSC[detailed_status]); +} + +/* + * Used for error reporting/debugging purposes + */ +static void i2o_report_util_cmd(u8 cmd) +{ + switch (cmd) { + case I2O_CMD_UTIL_NOP: + printk("UTIL_NOP, "); + break; + case I2O_CMD_UTIL_ABORT: + printk("UTIL_ABORT, "); + break; + case I2O_CMD_UTIL_CLAIM: + printk("UTIL_CLAIM, "); + break; + case I2O_CMD_UTIL_RELEASE: + printk("UTIL_CLAIM_RELEASE, "); + break; + case I2O_CMD_UTIL_CONFIG_DIALOG: + printk("UTIL_CONFIG_DIALOG, "); + break; + case I2O_CMD_UTIL_DEVICE_RESERVE: + printk("UTIL_DEVICE_RESERVE, "); + break; + case I2O_CMD_UTIL_DEVICE_RELEASE: + printk("UTIL_DEVICE_RELEASE, "); + break; + case I2O_CMD_UTIL_EVT_ACK: + printk("UTIL_EVENT_ACKNOWLEDGE, "); + break; + case I2O_CMD_UTIL_EVT_REGISTER: + printk("UTIL_EVENT_REGISTER, "); + break; + case I2O_CMD_UTIL_LOCK: + printk("UTIL_LOCK, "); + break; + case I2O_CMD_UTIL_LOCK_RELEASE: + printk("UTIL_LOCK_RELEASE, "); + break; + case I2O_CMD_UTIL_PARAMS_GET: + printk("UTIL_PARAMS_GET, "); + break; + case I2O_CMD_UTIL_PARAMS_SET: + printk("UTIL_PARAMS_SET, "); + break; + case I2O_CMD_UTIL_REPLY_FAULT_NOTIFY: + printk("UTIL_REPLY_FAULT_NOTIFY, "); + break; + default: + printk("Cmd = %0#2x, ",cmd); + } +} + +/* + * Used for error reporting/debugging purposes + */ +static void i2o_report_exec_cmd(u8 cmd) +{ + switch (cmd) { + case I2O_CMD_ADAPTER_ASSIGN: + printk("EXEC_ADAPTER_ASSIGN, "); + break; + case I2O_CMD_ADAPTER_READ: + printk("EXEC_ADAPTER_READ, "); + break; + case I2O_CMD_ADAPTER_RELEASE: + printk("EXEC_ADAPTER_RELEASE, "); + break; + case I2O_CMD_BIOS_INFO_SET: + printk("EXEC_BIOS_INFO_SET, "); + break; + case I2O_CMD_BOOT_DEVICE_SET: + printk("EXEC_BOOT_DEVICE_SET, "); + break; + case I2O_CMD_CONFIG_VALIDATE: + printk("EXEC_CONFIG_VALIDATE, "); + break; + case I2O_CMD_CONN_SETUP: + printk("EXEC_CONN_SETUP, "); + break; + case I2O_CMD_DDM_DESTROY: + printk("EXEC_DDM_DESTROY, "); + break; + case I2O_CMD_DDM_ENABLE: + printk("EXEC_DDM_ENABLE, "); + break; + case I2O_CMD_DDM_QUIESCE: + printk("EXEC_DDM_QUIESCE, "); + break; + case I2O_CMD_DDM_RESET: + printk("EXEC_DDM_RESET, "); + break; + case I2O_CMD_DDM_SUSPEND: + printk("EXEC_DDM_SUSPEND, "); + break; + case I2O_CMD_DEVICE_ASSIGN: + printk("EXEC_DEVICE_ASSIGN, "); + break; + case I2O_CMD_DEVICE_RELEASE: + printk("EXEC_DEVICE_RELEASE, "); + break; + case I2O_CMD_HRT_GET: + printk("EXEC_HRT_GET, "); + break; + case I2O_CMD_ADAPTER_CLEAR: + printk("EXEC_IOP_CLEAR, "); + break; + case I2O_CMD_ADAPTER_CONNECT: + printk("EXEC_IOP_CONNECT, "); + break; + case I2O_CMD_ADAPTER_RESET: + printk("EXEC_IOP_RESET, "); + break; + case I2O_CMD_LCT_NOTIFY: + printk("EXEC_LCT_NOTIFY, "); + break; + case I2O_CMD_OUTBOUND_INIT: + printk("EXEC_OUTBOUND_INIT, "); + break; + case I2O_CMD_PATH_ENABLE: + printk("EXEC_PATH_ENABLE, "); + break; + case I2O_CMD_PATH_QUIESCE: + printk("EXEC_PATH_QUIESCE, "); + break; + case I2O_CMD_PATH_RESET: + printk("EXEC_PATH_RESET, "); + break; + case I2O_CMD_STATIC_MF_CREATE: + printk("EXEC_STATIC_MF_CREATE, "); + break; + case I2O_CMD_STATIC_MF_RELEASE: + printk("EXEC_STATIC_MF_RELEASE, "); + break; + case I2O_CMD_STATUS_GET: + printk("EXEC_STATUS_GET, "); + break; + case I2O_CMD_SW_DOWNLOAD: + printk("EXEC_SW_DOWNLOAD, "); + break; + case I2O_CMD_SW_UPLOAD: + printk("EXEC_SW_UPLOAD, "); + break; + case I2O_CMD_SW_REMOVE: + printk("EXEC_SW_REMOVE, "); + break; + case I2O_CMD_SYS_ENABLE: + printk("EXEC_SYS_ENABLE, "); + break; + case I2O_CMD_SYS_MODIFY: + printk("EXEC_SYS_MODIFY, "); + break; + case I2O_CMD_SYS_QUIESCE: + printk("EXEC_SYS_QUIESCE, "); + break; + case I2O_CMD_SYS_TAB_SET: + printk("EXEC_SYS_TAB_SET, "); + break; + default: + printk("Cmd = %#02x, ",cmd); + } +} + +/* + * Used for error reporting/debugging purposes + */ +static void i2o_report_lan_cmd(u8 cmd) +{ + switch (cmd) { + case LAN_PACKET_SEND: + printk("LAN_PACKET_SEND, "); + break; + case LAN_SDU_SEND: + printk("LAN_SDU_SEND, "); + break; + case LAN_RECEIVE_POST: + printk("LAN_RECEIVE_POST, "); + break; + case LAN_RESET: + printk("LAN_RESET, "); + break; + case LAN_SUSPEND: + printk("LAN_SUSPEND, "); + break; + default: + printk("Cmd = %0#2x, ",cmd); + } +} + +/* + * Used for error reporting/debugging purposes. + * Report Cmd name, Request status, Detailed Status. + */ +void i2o_report_status(const char *severity, const char *str, u32 *msg) +{ + u8 cmd = (msg[1]>>24)&0xFF; + u8 req_status = (msg[4]>>24)&0xFF; + u16 detailed_status = msg[4]&0xFFFF; + struct i2o_handler *h = i2o_handlers[msg[2] & (MAX_I2O_MODULES-1)]; + + printk("%s%s: ", severity, str); + + if (cmd < 0x1F) // Utility cmd + i2o_report_util_cmd(cmd); + + else if (cmd >= 0xA0 && cmd <= 0xEF) // Executive cmd + i2o_report_exec_cmd(cmd); + + else if (h->class == I2O_CLASS_LAN && cmd >= 0x30 && cmd <= 0x3F) + i2o_report_lan_cmd(cmd); // LAN cmd + else + printk("Cmd = %0#2x, ", cmd); // Other cmds + + if (msg[0] & MSG_FAIL) { + i2o_report_fail_status(req_status, msg); + return; + } + + i2o_report_common_status(req_status); + + if (cmd < 0x1F || (cmd >= 0xA0 && cmd <= 0xEF)) + i2o_report_common_dsc(detailed_status); + else if (h->class == I2O_CLASS_LAN && cmd >= 0x30 && cmd <= 0x3F) + i2o_report_lan_dsc(detailed_status); + else + printk(" / DetailedStatus = %0#4x.\n", detailed_status); +} + +/* Used to dump a message to syslog during debugging */ +void i2o_dump_message(u32 *msg) +{ +#ifdef DRIVERDEBUG + int i; + printk(KERN_INFO "Dumping I2O message size %d @ %p\n", + msg[0]>>16&0xffff, msg); + for(i = 0; i < ((msg[0]>>16)&0xffff); i++) + printk(KERN_INFO " msg[%d] = %0#10x\n", i, msg[i]); +#endif +} + +/* + * I2O reboot/shutdown notification. + * + * - Call each OSM's reboot notifier (if one exists) + * - Quiesce each IOP in the system + * + * Each IOP has to be quiesced before we can ensure that the system + * can be properly shutdown as a transaction that has already been + * acknowledged still needs to be placed in permanent store on the IOP. + * The SysQuiesce causes the IOP to force all HDMs to complete their + * transactions before returning, so only at that point is it safe + * + */ +static int i2o_reboot_event(struct notifier_block *n, unsigned long code, void +*p) +{ + int i = 0; + struct i2o_controller *c = NULL; + + if(code != SYS_RESTART && code != SYS_HALT && code != SYS_POWER_OFF) + return NOTIFY_DONE; + + printk(KERN_INFO "Shutting down I2O system.\n"); + printk(KERN_INFO + " This could take a few minutes if there are many devices attached\n"); + + for(i = 0; i < MAX_I2O_MODULES; i++) + { + if(i2o_handlers[i] && i2o_handlers[i]->reboot_notify) + i2o_handlers[i]->reboot_notify(); + } + + for(c = i2o_controller_chain; c; c = c->next) + { + if(i2o_quiesce_controller(c)) + { + printk(KERN_WARNING "i2o: Could not quiesce %s." " + Verify setup on next system power up.\n", c->name); + } + } + + printk(KERN_INFO "I2O system down.\n"); + return NOTIFY_DONE; +} + + +EXPORT_SYMBOL(i2o_controller_chain); +EXPORT_SYMBOL(i2o_num_controllers); +EXPORT_SYMBOL(i2o_find_controller); +EXPORT_SYMBOL(i2o_unlock_controller); +EXPORT_SYMBOL(i2o_status_get); + +EXPORT_SYMBOL(i2o_install_handler); +EXPORT_SYMBOL(i2o_remove_handler); + +EXPORT_SYMBOL(i2o_claim_device); +EXPORT_SYMBOL(i2o_release_device); +EXPORT_SYMBOL(i2o_device_notify_on); +EXPORT_SYMBOL(i2o_device_notify_off); + +EXPORT_SYMBOL(i2o_post_this); +EXPORT_SYMBOL(i2o_post_wait); + +EXPORT_SYMBOL(i2o_query_scalar); +EXPORT_SYMBOL(i2o_set_scalar); +EXPORT_SYMBOL(i2o_query_table); +EXPORT_SYMBOL(i2o_clear_table); +EXPORT_SYMBOL(i2o_row_add_table); +EXPORT_SYMBOL(i2o_issue_params); + +EXPORT_SYMBOL(i2o_event_register); +EXPORT_SYMBOL(i2o_event_ack); + +EXPORT_SYMBOL(i2o_report_status); +EXPORT_SYMBOL(i2o_dump_message); + +EXPORT_SYMBOL(i2o_get_class_name); + +#ifdef MODULE + +MODULE_AUTHOR("Red Hat Software"); +MODULE_DESCRIPTION("I2O Core"); + + +int init_module(void) +{ + printk(KERN_INFO "I2O Core - (C) Copyright 1999 Red Hat Software\n"); + if (i2o_install_handler(&i2o_core_handler) < 0) + { + printk(KERN_ERR + "i2o_core: Unable to install core handler.\nI2O stack not loaded!"); + return 0; + } + + core_context = i2o_core_handler.context; + + /* + * Attach core to I2O PCI transport (and others as they are developed) + */ +#ifdef CONFIG_I2O_PCI_MODULE + if(i2o_pci_core_attach(&i2o_core_functions) < 0) + printk(KERN_INFO "i2o: No PCI I2O controllers found\n"); +#endif + + /* + * Initialize event handling thread + */ + init_MUTEX_LOCKED(&evt_sem); + evt_pid = kernel_thread(i2o_core_evt, &evt_reply, CLONE_SIGHAND); + if(evt_pid < 0) + { + printk(KERN_ERR "I2O: Could not create event handler kernel thread\n"); + i2o_remove_handler(&i2o_core_handler); + return 0; + } + else + printk(KERN_INFO "I2O: Event thread created as pid %d\n", evt_pid); + + if(i2o_num_controllers) + i2o_sys_init(); + + register_reboot_notifier(&i2o_reboot_notifier); + + return 0; +} + +void cleanup_module(void) +{ + int stat; + + unregister_reboot_notifier(&i2o_reboot_notifier); + + if(i2o_num_controllers) + i2o_sys_shutdown(); + + /* + * If this is shutdown time, the thread has already been killed + */ + if(evt_running) { + printk("Terminating i2o threads..."); + stat = kill_proc(evt_pid, SIGTERM, 1); + if(!stat) { + printk("waiting..."); + down(&evt_dead); + } + printk("done.\n"); + } + +#ifdef CONFIG_I2O_PCI_MODULE + i2o_pci_core_detach(); +#endif + + i2o_remove_handler(&i2o_core_handler); + + unregister_reboot_notifier(&i2o_reboot_notifier); +} + +#else + +extern int i2o_block_init(void); +extern int i2o_config_init(void); +extern int i2o_lan_init(void); +extern int i2o_pci_init(void); +extern int i2o_proc_init(void); +extern int i2o_scsi_init(void); + +int __init i2o_init(void) +{ + printk(KERN_INFO "Loading I2O Core - (c) Copyright 1999 Red Hat Software\n"); + + if (i2o_install_handler(&i2o_core_handler) < 0) + { + printk(KERN_ERR + "i2o_core: Unable to install core handler.\nI2O stack not loaded!"); + return 0; + } + + core_context = i2o_core_handler.context; + + /* + * Initialize event handling thread + * We may not find any controllers, but still want this as + * down the road we may have hot pluggable controllers that + * need to be dealt with. + */ + init_MUTEX_LOCKED(&evt_sem); + if((evt_pid = kernel_thread(i2o_core_evt, &evt_reply, CLONE_SIGHAND)) < 0) + { + printk(KERN_ERR "I2O: Could not create event handler kernel thread\n"); + i2o_remove_handler(&i2o_core_handler); + return 0; + } + + +#ifdef CONFIG_I2O_PCI + i2o_pci_init(); +#endif + + if(i2o_num_controllers) + i2o_sys_init(); + + register_reboot_notifier(&i2o_reboot_notifier); + + i2o_config_init(); +#ifdef CONFIG_I2O_BLOCK + i2o_block_init(); +#endif +#ifdef CONFIG_I2O_LAN + i2o_lan_init(); +#endif +#ifdef CONFIG_I2O_PROC + i2o_proc_init(); +#endif + return 0; +} + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/i2o/i2o_lan.c linux.ac/drivers/message/i2o/i2o_lan.c --- linux.vanilla/drivers/message/i2o/i2o_lan.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/i2o/i2o_lan.c Tue Apr 3 17:54:47 2001 @@ -0,0 +1,1575 @@ +/* + * drivers/i2o/i2o_lan.c + * + * I2O LAN CLASS OSM May 26th 2000 + * + * (C) Copyright 1999, 2000 University of Helsinki, + * Department of Computer Science + * + * This code is still under development / test. + * + * 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. + * + * Authors: Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI> + * Fixes: Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI> + * Taneli Vähäkangas <Taneli.Vahakangas@cs.Helsinki.FI> + * Deepak Saxena <deepak@plexity.net> + * + * Tested: in FDDI environment (using SysKonnect's DDM) + * in Gigabit Eth environment (using SysKonnect's DDM) + * in Fast Ethernet environment (using Intel 82558 DDM) + * + * TODO: tests for other LAN classes (Token Ring, Fibre Channel) + */ + +#include <linux/config.h> +#include <linux/module.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/fddidevice.h> +#include <linux/trdevice.h> +#include <linux/fcdevice.h> + +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/tqueue.h> +#include <asm/io.h> + +#include <linux/errno.h> + +#include <linux/i2o.h> +#include "i2o_lan.h" + +//#define DRIVERDEBUG +#ifdef DRIVERDEBUG +#define dprintk(s, args...) printk(s, ## args) +#else +#define dprintk(s, args...) +#endif + +/* The following module parameters are used as default values + * for per interface values located in the net_device private area. + * Private values are changed via /proc filesystem. + */ +static u32 max_buckets_out = I2O_LAN_MAX_BUCKETS_OUT; +static u32 bucket_thresh = I2O_LAN_BUCKET_THRESH; +static u32 rx_copybreak = I2O_LAN_RX_COPYBREAK; +static u8 tx_batch_mode = I2O_LAN_TX_BATCH_MODE; +static u32 i2o_event_mask = I2O_LAN_EVENT_MASK; + +#define MAX_LAN_CARDS 16 +static struct net_device *i2o_landevs[MAX_LAN_CARDS+1]; +static int unit = -1; /* device unit number */ + +static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m); +static void i2o_lan_send_post_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m); +static int i2o_lan_receive_post(struct net_device *dev); +static void i2o_lan_receive_post_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m); +static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg); + +static int i2o_lan_reset(struct net_device *dev); +static void i2o_lan_handle_event(struct net_device *dev, u32 *msg); + +/* Structures to register handlers for the incoming replies. */ + +static struct i2o_handler i2o_lan_send_handler = { + i2o_lan_send_post_reply, // For send replies + NULL, + NULL, + NULL, + "I2O LAN OSM send", + -1, + I2O_CLASS_LAN +}; +static int lan_send_context; + +static struct i2o_handler i2o_lan_receive_handler = { + i2o_lan_receive_post_reply, // For receive replies + NULL, + NULL, + NULL, + "I2O LAN OSM receive", + -1, + I2O_CLASS_LAN +}; +static int lan_receive_context; + +static struct i2o_handler i2o_lan_handler = { + i2o_lan_reply, // For other replies + NULL, + NULL, + NULL, + "I2O LAN OSM", + -1, + I2O_CLASS_LAN +}; +static int lan_context; + +DECLARE_TASK_QUEUE(i2o_post_buckets_task); +struct tq_struct run_i2o_post_buckets_task = { + routine: (void (*)(void *)) run_task_queue, + data: (void *) 0 +}; + +/* Functions to handle message failures and transaction errors: +==============================================================*/ + +/* + * i2o_lan_handle_failure(): Fail bit has been set since IOP's message + * layer cannot deliver the request to the target, or the target cannot + * process the request. + */ +static void i2o_lan_handle_failure(struct net_device *dev, u32 *msg) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + + u32 *preserved_msg = (u32*)(iop->mem_offset + msg[7]); + u32 *sgl_elem = &preserved_msg[4]; + struct sk_buff *skb = NULL; + u8 le_flag; + + i2o_report_status(KERN_INFO, dev->name, msg); + + /* If PacketSend failed, free sk_buffs reserved by upper layers */ + + if (msg[1] >> 24 == LAN_PACKET_SEND) { + do { + skb = (struct sk_buff *)(sgl_elem[1]); + dev_kfree_skb_irq(skb); + + atomic_dec(&priv->tx_out); + + le_flag = *sgl_elem >> 31; + sgl_elem +=3; + } while (le_flag == 0); /* Last element flag not set */ + + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + } + + /* If ReceivePost failed, free sk_buffs we have reserved */ + + if (msg[1] >> 24 == LAN_RECEIVE_POST) { + do { + skb = (struct sk_buff *)(sgl_elem[1]); + dev_kfree_skb_irq(skb); + + atomic_dec(&priv->buckets_out); + + le_flag = *sgl_elem >> 31; + sgl_elem +=3; + } while (le_flag == 0); /* Last element flag not set */ + } + + /* Release the preserved msg frame by resubmitting it as a NOP */ + + preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0; + preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0; + preserved_msg[2] = 0; + i2o_post_message(iop, msg[7]); +} +/* + * i2o_lan_handle_transaction_error(): IOP or DDM has rejected the request + * for general cause (format error, bad function code, insufficient resources, + * etc.). We get one transaction_error for each failed transaction. + */ +static void i2o_lan_handle_transaction_error(struct net_device *dev, u32 *msg) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct sk_buff *skb; + + i2o_report_status(KERN_INFO, dev->name, msg); + + /* If PacketSend was rejected, free sk_buff reserved by upper layers */ + + if (msg[1] >> 24 == LAN_PACKET_SEND) { + skb = (struct sk_buff *)(msg[3]); // TransactionContext + dev_kfree_skb_irq(skb); + atomic_dec(&priv->tx_out); + + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + } + + /* If ReceivePost was rejected, free sk_buff we have reserved */ + + if (msg[1] >> 24 == LAN_RECEIVE_POST) { + skb = (struct sk_buff *)(msg[3]); + dev_kfree_skb_irq(skb); + atomic_dec(&priv->buckets_out); + } +} + +/* + * i2o_lan_handle_status(): Common parts of handling a not succeeded request + * (status != SUCCESS). + */ +static int i2o_lan_handle_status(struct net_device *dev, u32 *msg) +{ + /* Fail bit set? */ + + if (msg[0] & MSG_FAIL) { + i2o_lan_handle_failure(dev, msg); + return -1; + } + + /* Message rejected for general cause? */ + + if ((msg[4]>>24) == I2O_REPLY_STATUS_TRANSACTION_ERROR) { + i2o_lan_handle_transaction_error(dev, msg); + return -1; + } + + /* Else have to handle it in the callback function */ + + return 0; +} + +/* Callback functions called from the interrupt routine: +=======================================================*/ + +/* + * i2o_lan_send_post_reply(): Callback function to handle PostSend replies. + */ +static void i2o_lan_send_post_reply(struct i2o_handler *h, + struct i2o_controller *iop, struct i2o_message *m) +{ + u32 *msg = (u32 *)m; + u8 unit = (u8)(msg[2]>>16); // InitiatorContext + struct net_device *dev = i2o_landevs[unit]; + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + u8 trl_count = msg[3] & 0x000000FF; + + if ((msg[4] >> 24) != I2O_REPLY_STATUS_SUCCESS) { + if (i2o_lan_handle_status(dev, msg)) + return; + } + +#ifdef DRIVERDEBUG + i2o_report_status(KERN_INFO, dev->name, msg); +#endif + + /* DDM has handled transmit request(s), free sk_buffs. + * We get similar single transaction reply also in error cases + * (except if msg failure or transaction error). + */ + while (trl_count) { + dev_kfree_skb_irq((struct sk_buff *)msg[4 + trl_count]); + dprintk(KERN_INFO "%s: tx skb freed (trl_count=%d).\n", + dev->name, trl_count); + atomic_dec(&priv->tx_out); + trl_count--; + } + + /* If priv->tx_out had reached tx_max_out, the queue was stopped */ + + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); +} + +/* + * i2o_lan_receive_post_reply(): Callback function to process incoming packets. + */ +static void i2o_lan_receive_post_reply(struct i2o_handler *h, + struct i2o_controller *iop, struct i2o_message *m) +{ + u32 *msg = (u32 *)m; + u8 unit = (u8)(msg[2]>>16); // InitiatorContext + struct net_device *dev = i2o_landevs[unit]; + + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_bucket_descriptor *bucket = (struct i2o_bucket_descriptor *)&msg[6]; + struct i2o_packet_info *packet; + u8 trl_count = msg[3] & 0x000000FF; + struct sk_buff *skb, *old_skb; + unsigned long flags = 0; + + if ((msg[4] >> 24) != I2O_REPLY_STATUS_SUCCESS) { + if (i2o_lan_handle_status(dev, msg)) + return; + + i2o_lan_release_buckets(dev, msg); + return; + } + +#ifdef DRIVERDEBUG + i2o_report_status(KERN_INFO, dev->name, msg); +#endif + + /* Else we are receiving incoming post. */ + + while (trl_count--) { + skb = (struct sk_buff *)bucket->context; + packet = (struct i2o_packet_info *)bucket->packet_info; + atomic_dec(&priv->buckets_out); + + /* Sanity checks: Any weird characteristics in bucket? */ + + if (packet->flags & 0x0f || ! packet->flags & 0x40) { + if (packet->flags & 0x01) + printk(KERN_WARNING "%s: packet with errors, error code=0x%02x.\n", + dev->name, packet->status & 0xff); + + /* The following shouldn't happen, unless parameters in + * LAN_OPERATION group are changed during the run time. + */ + if (packet->flags & 0x0c) + printk(KERN_DEBUG "%s: multi-bucket packets not supported!\n", + dev->name); + + if (! packet->flags & 0x40) + printk(KERN_DEBUG "%s: multiple packets in a bucket not supported!\n", + dev->name); + + dev_kfree_skb_irq(skb); + + bucket++; + continue; + } + + /* Copy short packet to a new skb */ + + if (packet->len < priv->rx_copybreak) { + old_skb = skb; + skb = (struct sk_buff *)dev_alloc_skb(packet->len+2); + if (skb == NULL) { + printk(KERN_ERR "%s: Can't allocate skb.\n", dev->name); + return; + } + skb_reserve(skb, 2); + memcpy(skb_put(skb, packet->len), old_skb->data, packet->len); + + spin_lock_irqsave(&priv->fbl_lock, flags); + if (priv->i2o_fbl_tail < I2O_LAN_MAX_BUCKETS_OUT) + priv->i2o_fbl[++priv->i2o_fbl_tail] = old_skb; + else + dev_kfree_skb_irq(old_skb); + + spin_unlock_irqrestore(&priv->fbl_lock, flags); + } else + skb_put(skb, packet->len); + + /* Deliver to upper layers */ + + skb->dev = dev; + skb->protocol = priv->type_trans(skb, dev); + netif_rx(skb); + + dev->last_rx = jiffies; + + dprintk(KERN_INFO "%s: Incoming packet (%d bytes) delivered " + "to upper level.\n", dev->name, packet->len); + + bucket++; // to next Packet Descriptor Block + } + +#ifdef DRIVERDEBUG + if (msg[5] == 0) + printk(KERN_INFO "%s: DDM out of buckets (priv->count = %d)!\n", + dev->name, atomic_read(&priv->buckets_out)); +#endif + + /* If DDM has already consumed bucket_thresh buckets, post new ones */ + + if (atomic_read(&priv->buckets_out) <= priv->max_buckets_out - priv->bucket_thresh) { + run_i2o_post_buckets_task.data = (void *)dev; + queue_task(&run_i2o_post_buckets_task, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + + return; +} + +/* + * i2o_lan_reply(): Callback function to handle other incoming messages + * except SendPost and ReceivePost. + */ +static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, + struct i2o_message *m) +{ + u32 *msg = (u32 *)m; + u8 unit = (u8)(msg[2]>>16); // InitiatorContext + struct net_device *dev = i2o_landevs[unit]; + + if ((msg[4] >> 24) != I2O_REPLY_STATUS_SUCCESS) { + if (i2o_lan_handle_status(dev, msg)) + return; + + /* In other error cases just report and continue */ + + i2o_report_status(KERN_INFO, dev->name, msg); + } + +#ifdef DRIVERDEBUG + i2o_report_status(KERN_INFO, dev->name, msg); +#endif + switch (msg[1] >> 24) { + case LAN_RESET: + case LAN_SUSPEND: + /* default reply without payload */ + break; + + case I2O_CMD_UTIL_EVT_REGISTER: + case I2O_CMD_UTIL_EVT_ACK: + i2o_lan_handle_event(dev, msg); + break; + + case I2O_CMD_UTIL_PARAMS_SET: + /* default reply, results in ReplyPayload (not examined) */ + switch (msg[3] >> 16) { + case 1: dprintk(KERN_INFO "%s: Reply to set MAC filter mask.\n", + dev->name); + break; + case 2: dprintk(KERN_INFO "%s: Reply to set MAC table.\n", + dev->name); + break; + default: printk(KERN_WARNING "%s: Bad group 0x%04X\n", + dev->name,msg[3] >> 16); + } + break; + + default: + printk(KERN_ERR "%s: No handler for the reply.\n", + dev->name); + i2o_report_status(KERN_INFO, dev->name, msg); + } +} + +/* Functions used by the above callback functions: +=================================================*/ +/* + * i2o_lan_release_buckets(): Free unused buckets (sk_buffs). + */ +static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + u8 trl_elem_size = (u8)(msg[3]>>8 & 0x000000FF); + u8 trl_count = (u8)(msg[3] & 0x000000FF); + u32 *pskb = &msg[6]; + + while (trl_count--) { + dprintk(KERN_DEBUG "%s: Releasing unused rx skb %p (trl_count=%d).\n", + dev->name, (struct sk_buff*)(*pskb),trl_count+1); + dev_kfree_skb_irq((struct sk_buff *)(*pskb)); + pskb += 1 + trl_elem_size; + atomic_dec(&priv->buckets_out); + } +} + +/* + * i2o_lan_event_reply(): Handle events. + */ +static void i2o_lan_handle_event(struct net_device *dev, u32 *msg) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + u32 max_evt_data_size =iop->status_block->inbound_frame_size-5; + struct i2o_reply { + u32 header[4]; + u32 evt_indicator; + u32 data[max_evt_data_size]; + } *evt = (struct i2o_reply *)msg; + int evt_data_len = ((msg[0]>>16) - 5) * 4; /* real size*/ + + printk(KERN_INFO "%s: I2O event - ", dev->name); + + if (msg[1]>>24 == I2O_CMD_UTIL_EVT_ACK) { + printk("Event acknowledgement reply.\n"); + return; + } + + /* Else evt->function == I2O_CMD_UTIL_EVT_REGISTER) */ + + switch (evt->evt_indicator) { + case I2O_EVT_IND_STATE_CHANGE: { + struct state_data { + u16 status; + u8 state; + u8 data; + } *evt_data = (struct state_data *)(evt->data[0]); + + printk("State chance 0x%08x.\n", evt->data[0]); + + /* If the DDM is in error state, recovery may be + * possible if status = Transmit or Receive Control + * Unit Inoperable. + */ + if (evt_data->state==0x05 && evt_data->status==0x0003) + i2o_lan_reset(dev); + break; + } + + case I2O_EVT_IND_FIELD_MODIFIED: { + u16 *work16 = (u16 *)evt->data; + printk("Group 0x%04x, field %d changed.\n", work16[0], work16[1]); + break; + } + + case I2O_EVT_IND_VENDOR_EVT: { + int i; + printk("Vendor event:\n"); + for (i = 0; i < evt_data_len / 4; i++) + printk(" 0x%08x\n", evt->data[i]); + break; + } + + case I2O_EVT_IND_DEVICE_RESET: + /* Spec 2.0 p. 6-121: + * The event of _DEVICE_RESET should also be responded + */ + printk("Device reset.\n"); + if (i2o_event_ack(iop, msg) < 0) + printk("%s: Event Acknowledge timeout.\n", dev->name); + break; + +#if 0 + case I2O_EVT_IND_EVT_MASK_MODIFIED: + printk("Event mask modified, 0x%08x.\n", evt->data[0]); + break; + + case I2O_EVT_IND_GENERAL_WARNING: + printk("General warning 0x%04x.\n", evt->data[0]); + break; + + case I2O_EVT_IND_CONFIGURATION_FLAG: + printk("Configuration requested.\n"); + break; + + case I2O_EVT_IND_CAPABILITY_CHANGE: + printk("Capability change 0x%04x.\n", evt->data[0]); + break; + + case I2O_EVT_IND_DEVICE_STATE: + printk("Device state changed 0x%08x.\n", evt->data[0]); + break; +#endif + case I2O_LAN_EVT_LINK_DOWN: + netif_carrier_off(dev); + printk("Link to the physical device is lost.\n"); + break; + + case I2O_LAN_EVT_LINK_UP: + netif_carrier_on(dev); + printk("Link to the physical device is (re)established.\n"); + break; + + case I2O_LAN_EVT_MEDIA_CHANGE: + printk("Media change.\n"); + break; + default: + printk("0x%08x. No handler.\n", evt->evt_indicator); + } +} + +/* + * i2o_lan_receive_post(): Post buckets to receive packets. + */ +static int i2o_lan_receive_post(struct net_device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + struct sk_buff *skb; + u32 m, *msg; + u32 bucket_len = (dev->mtu + dev->hard_header_len); + u32 total = priv->max_buckets_out - atomic_read(&priv->buckets_out); + u32 bucket_count; + u32 *sgl_elem; + unsigned long flags; + + /* Send (total/bucket_count) separate I2O requests */ + + while (total) { + m = I2O_POST_READ32(iop); + if (m == 0xFFFFFFFF) + return -ETIMEDOUT; + msg = (u32 *)(iop->mem_offset + m); + + bucket_count = (total >= priv->sgl_max) ? priv->sgl_max : total; + total -= bucket_count; + atomic_add(bucket_count, &priv->buckets_out); + + dprintk(KERN_INFO "%s: Sending %d buckets (size %d) to LAN DDM.\n", + dev->name, bucket_count, bucket_len); + + /* Fill in the header */ + + __raw_writel(I2O_MESSAGE_SIZE(4 + 3 * bucket_count) | SGL_OFFSET_4, msg); + __raw_writel(LAN_RECEIVE_POST<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid, msg+1); + __raw_writel(priv->unit << 16 | lan_receive_context, msg+2); + __raw_writel(bucket_count, msg+3); + sgl_elem = &msg[4]; + + /* Fill in the payload - contains bucket_count SGL elements */ + + while (bucket_count--) { + spin_lock_irqsave(&priv->fbl_lock, flags); + if (priv->i2o_fbl_tail >= 0) + skb = priv->i2o_fbl[priv->i2o_fbl_tail--]; + else { + skb = dev_alloc_skb(bucket_len + 2); + if (skb == NULL) { + spin_unlock_irqrestore(&priv->fbl_lock, flags); + return -ENOMEM; + } + skb_reserve(skb, 2); + } + spin_unlock_irqrestore(&priv->fbl_lock, flags); + + __raw_writel(0x51000000 | bucket_len, sgl_elem); + __raw_writel((u32)skb, sgl_elem+1); + __raw_writel(virt_to_bus(skb->data), sgl_elem+2); + sgl_elem += 3; + } + + /* set LE flag and post */ + __raw_writel(__raw_readl(sgl_elem-3) | 0x80000000, (sgl_elem-3)); + i2o_post_message(iop, m); + } + + return 0; +} + +/* Functions called from the network stack, and functions called by them: +========================================================================*/ + +/* + * i2o_lan_reset(): Reset the LAN adapter into the operational state and + * restore it to full operation. + */ +static int i2o_lan_reset(struct net_device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + u32 msg[5]; + + dprintk(KERN_INFO "%s: LAN RESET MESSAGE.\n", dev->name); + msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; + msg[1] = LAN_RESET<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid; + msg[2] = priv->unit << 16 | lan_context; // InitiatorContext + msg[3] = 0; // TransactionContext + msg[4] = 0; // Keep posted buckets + + if (i2o_post_this(iop, msg, sizeof(msg)) < 0) + return -ETIMEDOUT; + + return 0; +} + +/* + * i2o_lan_suspend(): Put LAN adapter into a safe, non-active state. + * IOP replies to any LAN class message with status error_no_data_transfer + * / suspended. + */ +static int i2o_lan_suspend(struct net_device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + u32 msg[5]; + + dprintk(KERN_INFO "%s: LAN SUSPEND MESSAGE.\n", dev->name); + msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; + msg[1] = LAN_SUSPEND<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid; + msg[2] = priv->unit << 16 | lan_context; // InitiatorContext + msg[3] = 0; // TransactionContext + msg[4] = 1 << 16; // return posted buckets + + if (i2o_post_this(iop, msg, sizeof(msg)) < 0) + return -ETIMEDOUT; + + return 0; +} + +/* + * i2o_set_ddm_parameters: + * These settings are done to ensure proper initial values for DDM. + * They can be changed via proc file system or vai configuration utility. + */ +static void i2o_set_ddm_parameters(struct net_device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + u32 val; + + /* + * When PacketOrphanlimit is set to the maximum packet length, + * the packets will never be split into two separate buckets + */ + val = dev->mtu + dev->hard_header_len; + if (i2o_set_scalar(iop, i2o_dev->lct_data.tid, 0x0004, 2, &val, sizeof(val)) < 0) + printk(KERN_WARNING "%s: Unable to set PacketOrphanLimit.\n", + dev->name); + else + dprintk(KERN_INFO "%s: PacketOrphanLimit set to %d.\n", + dev->name, val); + + /* When RxMaxPacketsBucket = 1, DDM puts only one packet into bucket */ + + val = 1; + if (i2o_set_scalar(iop, i2o_dev->lct_data.tid, 0x0008, 4, &val, sizeof(val)) <0) + printk(KERN_WARNING "%s: Unable to set RxMaxPacketsBucket.\n", + dev->name); + else + dprintk(KERN_INFO "%s: RxMaxPacketsBucket set to %d.\n", + dev->name, val); + return; +} + +/* Functions called from the network stack: +==========================================*/ + +/* + * i2o_lan_open(): Open the device to send/receive packets via + * the network device. + */ +static int i2o_lan_open(struct net_device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + u32 mc_addr_group[64]; + + MOD_INC_USE_COUNT; + + if (i2o_claim_device(i2o_dev, &i2o_lan_handler)) { + printk(KERN_WARNING "%s: Unable to claim the I2O LAN device.\n", dev->name); + MOD_DEC_USE_COUNT; + return -EAGAIN; + } + dprintk(KERN_INFO "%s: I2O LAN device (tid=%d) claimed by LAN OSM.\n", + dev->name, i2o_dev->lct_data.tid); + + if (i2o_event_register(iop, i2o_dev->lct_data.tid, + priv->unit << 16 | lan_context, 0, priv->i2o_event_mask) < 0) + printk(KERN_WARNING "%s: Unable to set the event mask.\n", dev->name); + + i2o_lan_reset(dev); + + /* Get the max number of multicast addresses */ + + if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0001, -1, + &mc_addr_group, sizeof(mc_addr_group)) < 0 ) { + printk(KERN_WARNING "%s: Unable to query LAN_MAC_ADDRESS group.\n", dev->name); + MOD_DEC_USE_COUNT; + return -EAGAIN; + } + priv->max_size_mc_table = mc_addr_group[8]; + + /* Malloc space for free bucket list to resuse reveive post buckets */ + + priv->i2o_fbl = kmalloc(priv->max_buckets_out * sizeof(struct sk_buff *), + GFP_KERNEL); + if (priv->i2o_fbl == NULL) { + MOD_DEC_USE_COUNT; + return -ENOMEM; + } + priv->i2o_fbl_tail = -1; + priv->send_active = 0; + + i2o_set_ddm_parameters(dev); + i2o_lan_receive_post(dev); + + netif_start_queue(dev); + + return 0; +} + +/* + * i2o_lan_close(): End the transfering. + */ +static int i2o_lan_close(struct net_device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + int ret = 0; + + netif_stop_queue(dev); + i2o_lan_suspend(dev); + + if (i2o_event_register(iop, i2o_dev->lct_data.tid, + priv->unit << 16 | lan_context, 0, 0) < 0) + printk(KERN_WARNING "%s: Unable to clear the event mask.\n", + dev->name); + + while (priv->i2o_fbl_tail >= 0) + dev_kfree_skb(priv->i2o_fbl[priv->i2o_fbl_tail--]); + + kfree(priv->i2o_fbl); + + if (i2o_release_device(i2o_dev, &i2o_lan_handler)) { + printk(KERN_WARNING "%s: Unable to unclaim I2O LAN device " + "(tid=%d).\n", dev->name, i2o_dev->lct_data.tid); + ret = -EBUSY; + } + + MOD_DEC_USE_COUNT; + + return ret; +} + +/* + * i2o_lan_tx_timeout(): Tx timeout handler. + */ +static void i2o_lan_tx_timeout(struct net_device *dev) +{ + if (!netif_queue_stopped(dev)) + netif_start_queue(dev); +} + +/* + * i2o_lan_batch_send(): Send packets in batch. + * Both i2o_lan_sdu_send and i2o_lan_packet_send use this. + */ +static void i2o_lan_batch_send(struct net_device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_controller *iop = priv->i2o_dev->controller; + + spin_lock_irq(&priv->tx_lock); + if (priv->tx_count != 0) { + dev->trans_start = jiffies; + i2o_post_message(iop, priv->m); + dprintk(KERN_DEBUG "%s: %d packets sent.\n", dev->name, priv->tx_count); + priv->tx_count = 0; + } + priv->send_active = 0; + spin_unlock_irq(&priv->tx_lock); + MOD_DEC_USE_COUNT; +} + +#ifdef CONFIG_NET_FC +/* + * i2o_lan_sdu_send(): Send a packet, MAC header added by the DDM. + * Must be supported by Fibre Channel, optional for Ethernet/802.3, + * Token Ring, FDDI + */ +static int i2o_lan_sdu_send(struct sk_buff *skb, struct net_device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + int tickssofar = jiffies - dev->trans_start; + u32 m, *msg; + u32 *sgl_elem; + + spin_lock_irq(&priv->tx_lock); + + priv->tx_count++; + atomic_inc(&priv->tx_out); + + /* + * If tx_batch_mode = 0x00 forced to immediate mode + * If tx_batch_mode = 0x01 forced to batch mode + * If tx_batch_mode = 0x10 switch automatically, current mode immediate + * If tx_batch_mode = 0x11 switch automatically, current mode batch + * If gap between two packets is > 0 ticks, switch to immediate + */ + if (priv->tx_batch_mode >> 1) // switch automatically + priv->tx_batch_mode = tickssofar ? 0x02 : 0x03; + + if (priv->tx_count == 1) { + m = I2O_POST_READ32(iop); + if (m == 0xFFFFFFFF) { + spin_unlock_irq(&priv->tx_lock); + return 1; + } + msg = (u32 *)(iop->mem_offset + m); + priv->m = m; + + __raw_writel(NINE_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4, msg); + __raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid, msg+1); + __raw_writel(priv->unit << 16 | lan_send_context, msg+2); // InitiatorContext + __raw_writel(1 << 30 | 1 << 3, msg+3); // TransmitControlWord + + __raw_writel(0xD7000000 | skb->len, msg+4); // MAC hdr included + __raw_writel((u32)skb, msg+5); // TransactionContext + __raw_writel(virt_to_bus(skb->data), msg+6); + __raw_writel((u32)skb->mac.raw, msg+7); + __raw_writel((u32)skb->mac.raw+4, msg+8); + + if ((priv->tx_batch_mode & 0x01) && !priv->send_active) { + priv->send_active = 1; + MOD_INC_USE_COUNT; + if (schedule_task(&priv->i2o_batch_send_task) == 0) + MOD_DEC_USE_COUNT; + } + } else { /* Add new SGL element to the previous message frame */ + + msg = (u32 *)(iop->mem_offset + priv->m); + sgl_elem = &msg[priv->tx_count * 5 + 1]; + + __raw_writel(I2O_MESSAGE_SIZE((__raw_readl(msg)>>16) + 5) | 1<<12 | SGL_OFFSET_4, msg); + __raw_writel(__raw_readl(sgl_elem-5) & 0x7FFFFFFF, sgl_elem-5); /* clear LE flag */ + __raw_writel(0xD5000000 | skb->len, sgl_elem); + __raw_writel((u32)skb, sgl_elem+1); + __raw_writel(virt_to_bus(skb->data), sgl_elem+2); + __raw_writel((u32)(skb->mac.raw), sgl_elem+3); + __raw_writel((u32)(skb->mac.raw)+1, sgl_elem+4); + } + + /* If tx not in batch mode or frame is full, send immediatelly */ + + if (!(priv->tx_batch_mode & 0x01) || priv->tx_count == priv->sgl_max) { + dev->trans_start = jiffies; + i2o_post_message(iop, priv->m); + dprintk(KERN_DEBUG "%s: %d packets sent.\n", dev->name, priv->tx_count); + priv->tx_count = 0; + } + + /* If DDMs TxMaxPktOut reached, stop queueing layer to send more */ + + if (atomic_read(&priv->tx_out) >= priv->tx_max_out) + netif_stop_queue(dev); + + spin_unlock_irq(&priv->tx_lock); + return 0; +} +#endif /* CONFIG_NET_FC */ + +/* + * i2o_lan_packet_send(): Send a packet as is, including the MAC header. + * + * Must be supported by Ethernet/802.3, Token Ring, FDDI, optional for + * Fibre Channel + */ +static int i2o_lan_packet_send(struct sk_buff *skb, struct net_device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + int tickssofar = jiffies - dev->trans_start; + u32 m, *msg; + u32 *sgl_elem; + + spin_lock_irq(&priv->tx_lock); + + priv->tx_count++; + atomic_inc(&priv->tx_out); + + /* + * If tx_batch_mode = 0x00 forced to immediate mode + * If tx_batch_mode = 0x01 forced to batch mode + * If tx_batch_mode = 0x10 switch automatically, current mode immediate + * If tx_batch_mode = 0x11 switch automatically, current mode batch + * If gap between two packets is > 0 ticks, switch to immediate + */ + if (priv->tx_batch_mode >> 1) // switch automatically + priv->tx_batch_mode = tickssofar ? 0x02 : 0x03; + + if (priv->tx_count == 1) { + m = I2O_POST_READ32(iop); + if (m == 0xFFFFFFFF) { + spin_unlock_irq(&priv->tx_lock); + return 1; + } + msg = (u32 *)(iop->mem_offset + m); + priv->m = m; + + __raw_writel(SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4, msg); + __raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid, msg+1); + __raw_writel(priv->unit << 16 | lan_send_context, msg+2); // InitiatorContext + __raw_writel(1 << 30 | 1 << 3, msg+3); // TransmitControlWord + // bit 30: reply as soon as transmission attempt is complete + // bit 3: Suppress CRC generation + __raw_writel(0xD5000000 | skb->len, msg+4); // MAC hdr included + __raw_writel((u32)skb, msg+5); // TransactionContext + __raw_writel(virt_to_bus(skb->data), msg+6); + + if ((priv->tx_batch_mode & 0x01) && !priv->send_active) { + priv->send_active = 1; + MOD_INC_USE_COUNT; + if (schedule_task(&priv->i2o_batch_send_task) == 0) + MOD_DEC_USE_COUNT; + } + } else { /* Add new SGL element to the previous message frame */ + + msg = (u32 *)(iop->mem_offset + priv->m); + sgl_elem = &msg[priv->tx_count * 3 + 1]; + + __raw_writel(I2O_MESSAGE_SIZE((__raw_readl(msg)>>16) + 3) | 1<<12 | SGL_OFFSET_4, msg); + __raw_writel(__raw_readl(sgl_elem-3) & 0x7FFFFFFF, sgl_elem-3); /* clear LE flag */ + __raw_writel(0xD5000000 | skb->len, sgl_elem); + __raw_writel((u32)skb, sgl_elem+1); + __raw_writel(virt_to_bus(skb->data), sgl_elem+2); + } + + /* If tx is in immediate mode or frame is full, send now */ + + if (!(priv->tx_batch_mode & 0x01) || priv->tx_count == priv->sgl_max) { + dev->trans_start = jiffies; + i2o_post_message(iop, priv->m); + dprintk(KERN_DEBUG "%s: %d packets sent.\n", dev->name, priv->tx_count); + priv->tx_count = 0; + } + + /* If DDMs TxMaxPktOut reached, stop queueing layer to send more */ + + if (atomic_read(&priv->tx_out) >= priv->tx_max_out) + netif_stop_queue(dev); + + spin_unlock_irq(&priv->tx_lock); + return 0; +} + +/* + * i2o_lan_get_stats(): Fill in the statistics. + */ +static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + u64 val64[16]; + u64 supported_group[4] = { 0, 0, 0, 0 }; + + if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0100, -1, val64, + sizeof(val64)) < 0) + printk(KERN_INFO "%s: Unable to query LAN_HISTORICAL_STATS.\n", dev->name); + else { + dprintk(KERN_DEBUG "%s: LAN_HISTORICAL_STATS queried.\n", dev->name); + priv->stats.tx_packets = val64[0]; + priv->stats.tx_bytes = val64[1]; + priv->stats.rx_packets = val64[2]; + priv->stats.rx_bytes = val64[3]; + priv->stats.tx_errors = val64[4]; + priv->stats.rx_errors = val64[5]; + priv->stats.rx_dropped = val64[6]; + } + + if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0180, -1, + &supported_group, sizeof(supported_group)) < 0) + printk(KERN_INFO "%s: Unable to query LAN_SUPPORTED_OPTIONAL_HISTORICAL_STATS.\n", dev->name); + + if (supported_group[2]) { + if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0183, -1, + val64, sizeof(val64)) < 0) + printk(KERN_INFO "%s: Unable to query LAN_OPTIONAL_RX_HISTORICAL_STATS.\n", dev->name); + else { + dprintk(KERN_DEBUG "%s: LAN_OPTIONAL_RX_HISTORICAL_STATS queried.\n", dev->name); + priv->stats.multicast = val64[4]; + priv->stats.rx_length_errors = val64[10]; + priv->stats.rx_crc_errors = val64[0]; + } + } + + if (i2o_dev->lct_data.sub_class == I2O_LAN_ETHERNET) { + u64 supported_stats = 0; + if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0200, -1, + val64, sizeof(val64)) < 0) + printk(KERN_INFO "%s: Unable to query LAN_802_3_HISTORICAL_STATS.\n", dev->name); + else { + dprintk(KERN_DEBUG "%s: LAN_802_3_HISTORICAL_STATS queried.\n", dev->name); + priv->stats.transmit_collision = val64[1] + val64[2]; + priv->stats.rx_frame_errors = val64[0]; + priv->stats.tx_carrier_errors = val64[6]; + } + + if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0280, -1, + &supported_stats, sizeof(supported_stats)) < 0) + printk(KERN_INFO "%s: Unable to query LAN_SUPPORTED_802_3_HISTORICAL_STATS.\n", dev->name); + + if (supported_stats != 0) { + if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0281, -1, + val64, sizeof(val64)) < 0) + printk(KERN_INFO "%s: Unable to query LAN_OPTIONAL_802_3_HISTORICAL_STATS.\n", dev->name); + else { + dprintk(KERN_DEBUG "%s: LAN_OPTIONAL_802_3_HISTORICAL_STATS queried.\n", dev->name); + if (supported_stats & 0x1) + priv->stats.rx_over_errors = val64[0]; + if (supported_stats & 0x4) + priv->stats.tx_heartbeat_errors = val64[2]; + } + } + } + +#ifdef CONFIG_TR + if (i2o_dev->lct_data.sub_class == I2O_LAN_TR) { + if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0300, -1, + val64, sizeof(val64)) < 0) + printk(KERN_INFO "%s: Unable to query LAN_802_5_HISTORICAL_STATS.\n", dev->name); + else { + struct tr_statistics *stats = + (struct tr_statistics *)&priv->stats; + dprintk(KERN_DEBUG "%s: LAN_802_5_HISTORICAL_STATS queried.\n", dev->name); + + stats->line_errors = val64[0]; + stats->internal_errors = val64[7]; + stats->burst_errors = val64[4]; + stats->A_C_errors = val64[2]; + stats->abort_delimiters = val64[3]; + stats->lost_frames = val64[1]; + /* stats->recv_congest_count = ?; FIXME ??*/ + stats->frame_copied_errors = val64[5]; + stats->frequency_errors = val64[6]; + stats->token_errors = val64[9]; + } + /* Token Ring optional stats not yet defined */ + } +#endif + +#ifdef CONFIG_FDDI + if (i2o_dev->lct_data.sub_class == I2O_LAN_FDDI) { + if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0400, -1, + val64, sizeof(val64)) < 0) + printk(KERN_INFO "%s: Unable to query LAN_FDDI_HISTORICAL_STATS.\n", dev->name); + else { + dprintk(KERN_DEBUG "%s: LAN_FDDI_HISTORICAL_STATS queried.\n", dev->name); + priv->stats.smt_cf_state = val64[0]; + memcpy(priv->stats.mac_upstream_nbr, &val64[1], FDDI_K_ALEN); + memcpy(priv->stats.mac_downstream_nbr, &val64[2], FDDI_K_ALEN); + priv->stats.mac_error_cts = val64[3]; + priv->stats.mac_lost_cts = val64[4]; + priv->stats.mac_rmt_state = val64[5]; + memcpy(priv->stats.port_lct_fail_cts, &val64[6], 8); + memcpy(priv->stats.port_lem_reject_cts, &val64[7], 8); + memcpy(priv->stats.port_lem_cts, &val64[8], 8); + memcpy(priv->stats.port_pcm_state, &val64[9], 8); + } + /* FDDI optional stats not yet defined */ + } +#endif + +#ifdef CONFIG_NET_FC + /* Fibre Channel Statistics not yet defined in 1.53 nor 2.0 */ +#endif + + return (struct net_device_stats *)&priv->stats; +} + +/* + * i2o_lan_set_mc_filter(): Post a request to set multicast filter. + */ +int i2o_lan_set_mc_filter(struct net_device *dev, u32 filter_mask) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + u32 msg[10]; + + msg[0] = TEN_WORD_MSG_SIZE | SGL_OFFSET_5; + msg[1] = I2O_CMD_UTIL_PARAMS_SET << 24 | HOST_TID << 12 | i2o_dev->lct_data.tid; + msg[2] = priv->unit << 16 | lan_context; + msg[3] = 0x0001 << 16 | 3 ; // TransactionContext: group&field + msg[4] = 0; + msg[5] = 0xCC000000 | 16; // Immediate data SGL + msg[6] = 1; // OperationCount + msg[7] = 0x0001<<16 | I2O_PARAMS_FIELD_SET; // Group, Operation + msg[8] = 3 << 16 | 1; // FieldIndex, FieldCount + msg[9] = filter_mask; // Value + + return i2o_post_this(iop, msg, sizeof(msg)); +} + +/* + * i2o_lan_set_mc_table(): Post a request to set LAN_MULTICAST_MAC_ADDRESS table. + */ +int i2o_lan_set_mc_table(struct net_device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + struct dev_mc_list *mc; + u32 msg[10 + 2 * dev->mc_count]; + u8 *work8 = (u8 *)(msg + 10); + + msg[0] = I2O_MESSAGE_SIZE(10 + 2 * dev->mc_count) | SGL_OFFSET_5; + msg[1] = I2O_CMD_UTIL_PARAMS_SET << 24 | HOST_TID << 12 | i2o_dev->lct_data.tid; + msg[2] = priv->unit << 16 | lan_context; // InitiatorContext + msg[3] = 0x0002 << 16 | (u16)-1; // TransactionContext + msg[4] = 0; // OperationFlags + msg[5] = 0xCC000000 | (16 + 8 * dev->mc_count); // Immediate data SGL + msg[6] = 2; // OperationCount + msg[7] = 0x0002 << 16 | I2O_PARAMS_TABLE_CLEAR; // Group, Operation + msg[8] = 0x0002 << 16 | I2O_PARAMS_ROW_ADD; // Group, Operation + msg[9] = dev->mc_count << 16 | (u16)-1; // RowCount, FieldCount + + for (mc = dev->mc_list; mc ; mc = mc->next, work8 += 8) { + memset(work8, 0, 8); + memcpy(work8, mc->dmi_addr, mc->dmi_addrlen); // Values + } + + return i2o_post_this(iop, msg, sizeof(msg)); +} + +/* + * i2o_lan_set_multicast_list(): Enable a network device to receive packets + * not send to the protocol address. + */ +static void i2o_lan_set_multicast_list(struct net_device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + u32 filter_mask; + + if (dev->flags & IFF_PROMISC) { + filter_mask = 0x00000002; + dprintk(KERN_INFO "%s: Enabling promiscuous mode...\n", dev->name); + } else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > priv->max_size_mc_table) { + filter_mask = 0x00000004; + dprintk(KERN_INFO "%s: Enabling all multicast mode...\n", dev->name); + } else if (dev->mc_count) { + filter_mask = 0x00000000; + dprintk(KERN_INFO "%s: Enabling multicast mode...\n", dev->name); + if (i2o_lan_set_mc_table(dev) < 0) + printk(KERN_WARNING "%s: Unable to send MAC table.\n", dev->name); + } else { + filter_mask = 0x00000300; // Broadcast, Multicast disabled + dprintk(KERN_INFO "%s: Enabling unicast mode...\n", dev->name); + } + + /* Finally copy new FilterMask to DDM */ + + if (i2o_lan_set_mc_filter(dev, filter_mask) < 0) + printk(KERN_WARNING "%s: Unable to send MAC FilterMask.\n", dev->name); +} + +/* + * i2o_lan_change_mtu(): Change maximum transfer unit size. + */ +static int i2o_lan_change_mtu(struct net_device *dev, int new_mtu) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + u32 max_pkt_size; + + if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data.tid, + 0x0000, 6, &max_pkt_size, 4) < 0) + return -EFAULT; + + if (new_mtu < 68 || new_mtu > 9000 || new_mtu > max_pkt_size) + return -EINVAL; + + dev->mtu = new_mtu; + + i2o_lan_suspend(dev); // to SUSPENDED state, return buckets + + while (priv->i2o_fbl_tail >= 0) // free buffered buckets + dev_kfree_skb(priv->i2o_fbl[priv->i2o_fbl_tail--]); + + i2o_lan_reset(dev); // to OPERATIONAL state + i2o_set_ddm_parameters(dev); // reset some parameters + i2o_lan_receive_post(dev); // post new buckets (new size) + + return 0; +} + +/* Functions to initialize I2O LAN OSM: +======================================*/ + +/* + * i2o_lan_register_device(): Register LAN class device to kernel. + */ +struct net_device *i2o_lan_register_device(struct i2o_device *i2o_dev) +{ + struct net_device *dev = NULL; + struct i2o_lan_local *priv = NULL; + u8 hw_addr[8]; + u32 tx_max_out = 0; + unsigned short (*type_trans)(struct sk_buff *, struct net_device *); + void (*unregister_dev)(struct net_device *dev); + + switch (i2o_dev->lct_data.sub_class) { + case I2O_LAN_ETHERNET: + dev = init_etherdev(NULL, sizeof(struct i2o_lan_local)); + if (dev == NULL) + return NULL; + type_trans = eth_type_trans; + unregister_dev = unregister_netdev; + break; + +#ifdef CONFIG_ANYLAN + case I2O_LAN_100VG: + printk(KERN_ERR "i2o_lan: 100base VG not yet supported.\n"); + return NULL; + break; +#endif + +#ifdef CONFIG_TR + case I2O_LAN_TR: + dev = init_trdev(NULL, sizeof(struct i2o_lan_local)); + if (dev==NULL) + return NULL; + type_trans = tr_type_trans; + unregister_dev = unregister_trdev; + break; +#endif + +#ifdef CONFIG_FDDI + case I2O_LAN_FDDI: + { + int size = sizeof(struct net_device) + sizeof(struct i2o_lan_local); + + dev = (struct net_device *) kmalloc(size, GFP_KERNEL); + if (dev == NULL) + return NULL; + memset((char *)dev, 0, size); + dev->priv = (void *)(dev + 1); + + if (dev_alloc_name(dev, "fddi%d") < 0) { + printk(KERN_WARNING "i2o_lan: Too many FDDI devices.\n"); + kfree(dev); + return NULL; + } + type_trans = fddi_type_trans; + unregister_dev = (void *)unregister_netdevice; + + fddi_setup(dev); + register_netdev(dev); + } + break; +#endif + +#ifdef CONFIG_NET_FC + case I2O_LAN_FIBRE_CHANNEL: + dev = init_fcdev(NULL, sizeof(struct i2o_lan_local)); + if (dev == NULL) + return NULL; + type_trans = NULL; +/* FIXME: Move fc_type_trans() from drivers/net/fc/iph5526.c to net/802/fc.c + * and export it in include/linux/fcdevice.h + * type_trans = fc_type_trans; + */ + unregister_dev = (void *)unregister_fcdev; + break; +#endif + + case I2O_LAN_UNKNOWN: + default: + printk(KERN_ERR "i2o_lan: LAN type 0x%04x not supported.\n", + i2o_dev->lct_data.sub_class); + return NULL; + } + + priv = (struct i2o_lan_local *)dev->priv; + priv->i2o_dev = i2o_dev; + priv->type_trans = type_trans; + priv->sgl_max = (i2o_dev->controller->status_block->inbound_frame_size - 4) / 3; + atomic_set(&priv->buckets_out, 0); + + /* Set default values for user configurable parameters */ + /* Private values are changed via /proc file system */ + + priv->max_buckets_out = max_buckets_out; + priv->bucket_thresh = bucket_thresh; + priv->rx_copybreak = rx_copybreak; + priv->tx_batch_mode = tx_batch_mode & 0x03; + priv->i2o_event_mask = i2o_event_mask; + + priv->tx_lock = SPIN_LOCK_UNLOCKED; + priv->fbl_lock = SPIN_LOCK_UNLOCKED; + + unit++; + i2o_landevs[unit] = dev; + priv->unit = unit; + + if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data.tid, + 0x0001, 0, &hw_addr, sizeof(hw_addr)) < 0) { + printk(KERN_ERR "%s: Unable to query hardware address.\n", dev->name); + unit--; + unregister_dev(dev); + kfree(dev); + return NULL; + } + dprintk(KERN_DEBUG "%s: hwaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + dev->name, hw_addr[0], hw_addr[1], hw_addr[2], hw_addr[3], + hw_addr[4], hw_addr[5]); + + dev->addr_len = 6; + memcpy(dev->dev_addr, hw_addr, 6); + + if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data.tid, + 0x0007, 2, &tx_max_out, sizeof(tx_max_out)) < 0) { + printk(KERN_ERR "%s: Unable to query max TX queue.\n", dev->name); + unit--; + unregister_dev(dev); + kfree(dev); + return NULL; + } + dprintk(KERN_INFO "%s: Max TX Outstanding = %d.\n", dev->name, tx_max_out); + priv->tx_max_out = tx_max_out; + atomic_set(&priv->tx_out, 0); + priv->tx_count = 0; + + INIT_LIST_HEAD(&priv->i2o_batch_send_task.list); + priv->i2o_batch_send_task.sync = 0; + priv->i2o_batch_send_task.routine = (void *)i2o_lan_batch_send; + priv->i2o_batch_send_task.data = (void *)dev; + + dev->open = i2o_lan_open; + dev->stop = i2o_lan_close; + dev->get_stats = i2o_lan_get_stats; + dev->set_multicast_list = i2o_lan_set_multicast_list; + dev->tx_timeout = i2o_lan_tx_timeout; + dev->watchdog_timeo = I2O_LAN_TX_TIMEOUT; + +#ifdef CONFIG_NET_FC + if (i2o_dev->lct_data.sub_class == I2O_LAN_FIBRE_CHANNEL) + dev->hard_start_xmit = i2o_lan_sdu_send; + else +#endif + dev->hard_start_xmit = i2o_lan_packet_send; + + if (i2o_dev->lct_data.sub_class == I2O_LAN_ETHERNET) + dev->change_mtu = i2o_lan_change_mtu; + + return dev; +} + +#ifdef MODULE +#define i2o_lan_init init_module +#endif + +int __init i2o_lan_init(void) +{ + struct net_device *dev; + int i; + + printk(KERN_INFO "I2O LAN OSM (C) 1999 University of Helsinki.\n"); + + /* Module params are used as global defaults for private values */ + + if (max_buckets_out > I2O_LAN_MAX_BUCKETS_OUT) + max_buckets_out = I2O_LAN_MAX_BUCKETS_OUT; + if (bucket_thresh > max_buckets_out) + bucket_thresh = max_buckets_out; + + /* Install handlers for incoming replies */ + + if (i2o_install_handler(&i2o_lan_send_handler) < 0) { + printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n"); + return -EINVAL; + } + lan_send_context = i2o_lan_send_handler.context; + + if (i2o_install_handler(&i2o_lan_receive_handler) < 0) { + printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n"); + return -EINVAL; + } + lan_receive_context = i2o_lan_receive_handler.context; + + if (i2o_install_handler(&i2o_lan_handler) < 0) { + printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n"); + return -EINVAL; + } + lan_context = i2o_lan_handler.context; + + for(i=0; i <= MAX_LAN_CARDS; i++) + i2o_landevs[i] = NULL; + + for (i=0; i < MAX_I2O_CONTROLLERS; i++) { + struct i2o_controller *iop = i2o_find_controller(i); + struct i2o_device *i2o_dev; + + if (iop==NULL) + continue; + + for (i2o_dev=iop->devices;i2o_dev != NULL;i2o_dev=i2o_dev->next) { + + if (i2o_dev->lct_data.class_id != I2O_CLASS_LAN) + continue; + + /* Make sure device not already claimed by an ISM */ + if (i2o_dev->lct_data.user_tid != 0xFFF) + continue; + + if (unit == MAX_LAN_CARDS) { + i2o_unlock_controller(iop); + printk(KERN_WARNING "i2o_lan: Too many I2O LAN devices.\n"); + return -EINVAL; + } + + dev = i2o_lan_register_device(i2o_dev); + if (dev == NULL) { + printk(KERN_ERR "i2o_lan: Unable to register I2O LAN device 0x%04x.\n", + i2o_dev->lct_data.sub_class); + continue; + } + + printk(KERN_INFO "%s: I2O LAN device registered, " + "subclass = 0x%04x, unit = %d, tid = %d.\n", + dev->name, i2o_dev->lct_data.sub_class, + ((struct i2o_lan_local *)dev->priv)->unit, + i2o_dev->lct_data.tid); + } + + i2o_unlock_controller(iop); + } + + dprintk(KERN_INFO "%d I2O LAN devices found and registered.\n", unit+1); + + return 0; +} + +#ifdef MODULE + +void cleanup_module(void) +{ + int i; + + for (i = 0; i <= unit; i++) { + struct net_device *dev = i2o_landevs[i]; + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + + switch (i2o_dev->lct_data.sub_class) { + case I2O_LAN_ETHERNET: + unregister_netdev(dev); + break; +#ifdef CONFIG_FDDI + case I2O_LAN_FDDI: + unregister_netdevice(dev); + break; +#endif +#ifdef CONFIG_TR + case I2O_LAN_TR: + unregister_trdev(dev); + break; +#endif +#ifdef CONFIG_NET_FC + case I2O_LAN_FIBRE_CHANNEL: + unregister_fcdev(dev); + break; +#endif + default: + printk(KERN_WARNING "%s: Spurious I2O LAN subclass 0x%08x.\n", + dev->name, i2o_dev->lct_data.sub_class); + } + + dprintk(KERN_INFO "%s: I2O LAN device unregistered.\n", + dev->name); + kfree(dev); + } + + i2o_remove_handler(&i2o_lan_handler); + i2o_remove_handler(&i2o_lan_send_handler); + i2o_remove_handler(&i2o_lan_receive_handler); +} + +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("University of Helsinki, Department of Computer Science"); +MODULE_DESCRIPTION("I2O Lan OSM"); + +MODULE_PARM(max_buckets_out, "1-" __MODULE_STRING(I2O_LAN_MAX_BUCKETS_OUT) "i"); +MODULE_PARM_DESC(max_buckets_out, "Total number of buckets to post (1-)"); +MODULE_PARM(bucket_thresh, "1-" __MODULE_STRING(I2O_LAN_MAX_BUCKETS_OUT) "i"); +MODULE_PARM_DESC(bucket_thresh, "Bucket post threshold (1-)"); +MODULE_PARM(rx_copybreak, "1-" "i"); +MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy only small frames (1-)"); +MODULE_PARM(tx_batch_mode, "0-2" "i"); +MODULE_PARM_DESC(tx_batch_mode, "0=Send immediatelly, 1=Send in batches, 2=Switch automatically"); + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/i2o/i2o_lan.h linux.ac/drivers/message/i2o/i2o_lan.h --- linux.vanilla/drivers/message/i2o/i2o_lan.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/i2o/i2o_lan.h Tue Apr 17 18:12:54 2001 @@ -0,0 +1,159 @@ +/* + * i2o_lan.h I2O LAN Class definitions + * + * I2O LAN CLASS OSM May 26th 2000 + * + * (C) Copyright 1999, 2000 University of Helsinki, + * Department of Computer Science + * + * This code is still under development / test. + * + * Author: Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI> + * Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI> + * Taneli Vähäkangas <Taneli.Vahakangas@cs.Helsinki.FI> + */ + +#ifndef _I2O_LAN_H +#define _I2O_LAN_H + +/* Default values for tunable parameters first */ + +#define I2O_LAN_MAX_BUCKETS_OUT 96 +#define I2O_LAN_BUCKET_THRESH 18 /* 9 buckets in one message */ +#define I2O_LAN_RX_COPYBREAK 200 +#define I2O_LAN_TX_TIMEOUT (1*HZ) +#define I2O_LAN_TX_BATCH_MODE 2 /* 2=automatic, 1=on, 0=off */ +#define I2O_LAN_EVENT_MASK 0 /* 0=None, 0xFFC00002=All */ + +/* LAN types */ +#define I2O_LAN_ETHERNET 0x0030 +#define I2O_LAN_100VG 0x0040 +#define I2O_LAN_TR 0x0050 +#define I2O_LAN_FDDI 0x0060 +#define I2O_LAN_FIBRE_CHANNEL 0x0070 +#define I2O_LAN_UNKNOWN 0x00000000 + +/* Connector types */ + +/* Ethernet */ +#define I2O_LAN_AUI (I2O_LAN_ETHERNET << 4) + 0x00000001 +#define I2O_LAN_10BASE5 (I2O_LAN_ETHERNET << 4) + 0x00000002 +#define I2O_LAN_FIORL (I2O_LAN_ETHERNET << 4) + 0x00000003 +#define I2O_LAN_10BASE2 (I2O_LAN_ETHERNET << 4) + 0x00000004 +#define I2O_LAN_10BROAD36 (I2O_LAN_ETHERNET << 4) + 0x00000005 +#define I2O_LAN_10BASE_T (I2O_LAN_ETHERNET << 4) + 0x00000006 +#define I2O_LAN_10BASE_FP (I2O_LAN_ETHERNET << 4) + 0x00000007 +#define I2O_LAN_10BASE_FB (I2O_LAN_ETHERNET << 4) + 0x00000008 +#define I2O_LAN_10BASE_FL (I2O_LAN_ETHERNET << 4) + 0x00000009 +#define I2O_LAN_100BASE_TX (I2O_LAN_ETHERNET << 4) + 0x0000000A +#define I2O_LAN_100BASE_FX (I2O_LAN_ETHERNET << 4) + 0x0000000B +#define I2O_LAN_100BASE_T4 (I2O_LAN_ETHERNET << 4) + 0x0000000C +#define I2O_LAN_1000BASE_SX (I2O_LAN_ETHERNET << 4) + 0x0000000D +#define I2O_LAN_1000BASE_LX (I2O_LAN_ETHERNET << 4) + 0x0000000E +#define I2O_LAN_1000BASE_CX (I2O_LAN_ETHERNET << 4) + 0x0000000F +#define I2O_LAN_1000BASE_T (I2O_LAN_ETHERNET << 4) + 0x00000010 + +/* AnyLAN */ +#define I2O_LAN_100VG_ETHERNET (I2O_LAN_100VG << 4) + 0x00000001 +#define I2O_LAN_100VG_TR (I2O_LAN_100VG << 4) + 0x00000002 + +/* Token Ring */ +#define I2O_LAN_4MBIT (I2O_LAN_TR << 4) + 0x00000001 +#define I2O_LAN_16MBIT (I2O_LAN_TR << 4) + 0x00000002 + +/* FDDI */ +#define I2O_LAN_125MBAUD (I2O_LAN_FDDI << 4) + 0x00000001 + +/* Fibre Channel */ +#define I2O_LAN_POINT_POINT (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000001 +#define I2O_LAN_ARB_LOOP (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000002 +#define I2O_LAN_PUBLIC_LOOP (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000003 +#define I2O_LAN_FABRIC (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000004 + +#define I2O_LAN_EMULATION 0x00000F00 +#define I2O_LAN_OTHER 0x00000F01 +#define I2O_LAN_DEFAULT 0xFFFFFFFF + +/* LAN class functions */ + +#define LAN_PACKET_SEND 0x3B +#define LAN_SDU_SEND 0x3D +#define LAN_RECEIVE_POST 0x3E +#define LAN_RESET 0x35 +#define LAN_SUSPEND 0x37 + +/* LAN DetailedStatusCode defines */ +#define I2O_LAN_DSC_SUCCESS 0x00 +#define I2O_LAN_DSC_DEVICE_FAILURE 0x01 +#define I2O_LAN_DSC_DESTINATION_NOT_FOUND 0x02 +#define I2O_LAN_DSC_TRANSMIT_ERROR 0x03 +#define I2O_LAN_DSC_TRANSMIT_ABORTED 0x04 +#define I2O_LAN_DSC_RECEIVE_ERROR 0x05 +#define I2O_LAN_DSC_RECEIVE_ABORTED 0x06 +#define I2O_LAN_DSC_DMA_ERROR 0x07 +#define I2O_LAN_DSC_BAD_PACKET_DETECTED 0x08 +#define I2O_LAN_DSC_OUT_OF_MEMORY 0x09 +#define I2O_LAN_DSC_BUCKET_OVERRUN 0x0A +#define I2O_LAN_DSC_IOP_INTERNAL_ERROR 0x0B +#define I2O_LAN_DSC_CANCELED 0x0C +#define I2O_LAN_DSC_INVALID_TRANSACTION_CONTEXT 0x0D +#define I2O_LAN_DSC_DEST_ADDRESS_DETECTED 0x0E +#define I2O_LAN_DSC_DEST_ADDRESS_OMITTED 0x0F +#define I2O_LAN_DSC_PARTIAL_PACKET_RETURNED 0x10 +#define I2O_LAN_DSC_SUSPENDED 0x11 + +struct i2o_packet_info { + u32 offset : 24; + u32 flags : 8; + u32 len : 24; + u32 status : 8; +}; + +struct i2o_bucket_descriptor { + u32 context; /* FIXME: 64bit support */ + struct i2o_packet_info packet_info[1]; +}; + +/* Event Indicator Mask Flags for LAN OSM */ + +#define I2O_LAN_EVT_LINK_DOWN 0x01 +#define I2O_LAN_EVT_LINK_UP 0x02 +#define I2O_LAN_EVT_MEDIA_CHANGE 0x04 + +#include <linux/netdevice.h> +#include <linux/fddidevice.h> + +struct i2o_lan_local { + u8 unit; + struct i2o_device *i2o_dev; + + struct fddi_statistics stats; /* see also struct net_device_stats */ + unsigned short (*type_trans)(struct sk_buff *, struct net_device *); + atomic_t buckets_out; /* nbr of unused buckets on DDM */ + atomic_t tx_out; /* outstanding TXes */ + u8 tx_count; /* packets in one TX message frame */ + u16 tx_max_out; /* DDM's Tx queue len */ + u8 sgl_max; /* max SGLs in one message frame */ + u32 m; /* IOP address of the batch msg frame */ + + struct tq_struct i2o_batch_send_task; + int send_active; + struct sk_buff **i2o_fbl; /* Free bucket list (to reuse skbs) */ + int i2o_fbl_tail; + spinlock_t fbl_lock; + + spinlock_t tx_lock; + + u32 max_size_mc_table; /* max number of multicast addresses */ + + /* LAN OSM configurable parameters are here: */ + + u16 max_buckets_out; /* max nbr of buckets to send to DDM */ + u16 bucket_thresh; /* send more when this many used */ + u16 rx_copybreak; + + u8 tx_batch_mode; /* Set when using batch mode sends */ + u32 i2o_event_mask; /* To turn on interesting event flags */ +}; + +#endif /* _I2O_LAN_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/i2o/i2o_pci.c linux.ac/drivers/message/i2o/i2o_pci.c --- linux.vanilla/drivers/message/i2o/i2o_pci.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/i2o/i2o_pci.c Tue Apr 3 17:54:47 2001 @@ -0,0 +1,361 @@ +/* + * Find I2O capable controllers on the PCI bus, and register/install + * them with the I2O layer + * + * (C) Copyright 1999 Red Hat Software + * + * Written by Alan Cox, Building Number Three Ltd + * Modified by Deepak Saxena <deepak@plexity.net> + * Modified by Boji T Kannanthanam <boji.t.kannanthanam@intel.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. + * + * TODO: + * Support polled I2O PCI controllers. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/i2o.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <asm/io.h> + +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif // CONFIG_MTRR + +#ifdef MODULE +/* + * Core function table + * See <include/linux/i2o.h> for an explanation + */ +static struct i2o_core_func_table *core; + +/* Core attach function */ +extern int i2o_pci_core_attach(struct i2o_core_func_table *); +extern void i2o_pci_core_detach(void); +#endif /* MODULE */ + +/* + * Free bus specific resources + */ +static void i2o_pci_dispose(struct i2o_controller *c) +{ + I2O_IRQ_WRITE32(c,0xFFFFFFFF); + if(c->bus.pci.irq > 0) + free_irq(c->bus.pci.irq, c); + iounmap(((u8 *)c->post_port)-0x40); + +#ifdef CONFIG_MTRR + if(c->bus.pci.mtrr_reg0 > 0) + mtrr_del(c->bus.pci.mtrr_reg0, 0, 0); + if(c->bus.pci.mtrr_reg1 > 0) + mtrr_del(c->bus.pci.mtrr_reg1, 0, 0); +#endif +} + +/* + * No real bus specific handling yet (note that later we will + * need to 'steal' PCI devices on i960 mainboards) + */ + +static int i2o_pci_bind(struct i2o_controller *c, struct i2o_device *dev) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static int i2o_pci_unbind(struct i2o_controller *c, struct i2o_device *dev) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * Bus specific enable/disable functions + */ +static void i2o_pci_enable(struct i2o_controller *c) +{ + I2O_IRQ_WRITE32(c, 0); + c->enabled = 1; +} + +static void i2o_pci_disable(struct i2o_controller *c) +{ + I2O_IRQ_WRITE32(c, 0xFFFFFFFF); + c->enabled = 0; +} + +/* + * Bus specific interrupt handler + */ + +static void i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r) +{ + struct i2o_controller *c = dev_id; +#ifdef MODULE + core->run_queue(c); +#else + i2o_run_queue(c); +#endif /* MODULE */ +} + +/* + * Install a PCI (or in theory AGP) i2o controller + * + * TODO: Add support for polled controllers + */ +int __init i2o_pci_install(struct pci_dev *dev) +{ + struct i2o_controller *c=kmalloc(sizeof(struct i2o_controller), + GFP_KERNEL); + u8 *mem; + u32 memptr = 0; + u32 size; + + int i; + + if(c==NULL) + { + printk(KERN_ERR "i2o: Insufficient memory to add controller.\n"); + return -ENOMEM; + } + memset(c, 0, sizeof(*c)); + + for(i=0; i<6; i++) + { + /* Skip I/O spaces */ + if(!(pci_resource_flags(dev, i) & IORESOURCE_IO)) + { + memptr = pci_resource_start(dev, i); + break; + } + } + + if(i==6) + { + printk(KERN_ERR "i2o: I2O controller has no memory regions defined.\n"); + kfree(c); + return -EINVAL; + } + + size = dev->resource[i].end-dev->resource[i].start+1; + /* Map the I2O controller */ + + printk(KERN_INFO "i2o: PCI I2O controller at 0x%08X size=%d\n", memptr, size); + mem = ioremap(memptr, size); + if(mem==NULL) + { + printk(KERN_ERR "i2o: Unable to map controller.\n"); + kfree(c); + return -EINVAL; + } + + c->bus.pci.irq = -1; + c->bus.pci.fc920 = 0; + + c->irq_mask = (volatile u32 *)(mem+0x34); + c->post_port = (volatile u32 *)(mem+0x40); + c->reply_port = (volatile u32 *)(mem+0x44); + + c->mem_phys = memptr; + c->mem_offset = (u32)mem; + c->destructor = i2o_pci_dispose; + + c->bind = i2o_pci_bind; + c->unbind = i2o_pci_unbind; + c->bus_enable = i2o_pci_enable; + c->bus_disable = i2o_pci_disable; + + c->type = I2O_TYPE_PCI; + + /* + * FC920 needs some workarounds + */ + + if(dev->vendor == PCI_VENDOR_ID_NCR && dev->device == 0x0630) + { + c->bus.pci.fc920=1; + printk(KERN_INFO "I2O: Symbios FC920 workarounds activated.\n"); + } + + /* + * Enable Write Combining MTRR for IOP's memory region + */ +#ifdef CONFIG_MTRR + c->bus.pci.mtrr_reg0 = + mtrr_add(c->mem_phys, size, MTRR_TYPE_WRCOMB, 1); +/* +* If it is an INTEL i960 I/O processor then set the first 64K to Uncacheable +* since the region contains the Messaging unit which shouldn't be cached. +*/ + c->bus.pci.mtrr_reg1 = -1; + if(dev->vendor == PCI_VENDOR_ID_INTEL) + { + printk(KERN_INFO "I2O: MTRR workaround for Intel i960 processor\n"); + c->bus.pci.mtrr_reg1 = mtrr_add(c->mem_phys, 65536, MTRR_TYPE_UNCACHABLE, 1); + if(c->bus.pci.mtrr_reg1< 0) + printk(KERN_INFO "i2o_pci: Error in setting MTRR_TYPE_UNCACHABLE\n"); + } + +#endif + + I2O_IRQ_WRITE32(c,0xFFFFFFFF); + +#ifdef MODULE + i = core->install(c); +#else + i = i2o_install_controller(c); +#endif /* MODULE */ + + if(i<0) + { + printk(KERN_ERR "i2o: Unable to install controller.\n"); + kfree(c); + iounmap(mem); + return i; + } + + c->bus.pci.irq = dev->irq; + if(c->bus.pci.irq) + { + i=request_irq(dev->irq, i2o_pci_interrupt, SA_SHIRQ, + c->name, c); + if(i<0) + { + printk(KERN_ERR "%s: unable to allocate interrupt %d.\n", + c->name, dev->irq); + c->bus.pci.irq = -1; +#ifdef MODULE + core->delete(c); +#else + i2o_delete_controller(c); +#endif /* MODULE */ + kfree(c); + iounmap(mem); + return -EBUSY; + } + } + + printk(KERN_INFO "%s: Installed at IRQ%d\n", c->name, dev->irq); + I2O_IRQ_WRITE32(c,0x0); + c->enabled = 1; + return 0; +} + +int __init i2o_pci_scan(void) +{ + struct pci_dev *dev; + int count=0; + + printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n"); + + pci_for_each_dev(dev) + { + if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O) + continue; + if((dev->class&0xFF)>1) + { + printk(KERN_INFO "i2o: I2O Controller found but does not support I2O 1.5 (skipping).\n"); + continue; + } + if (pci_enable_device(dev)) + continue; + printk(KERN_INFO "i2o: I2O controller on bus %d at %d.\n", + dev->bus->number, dev->devfn); + pci_set_master(dev); + if(i2o_pci_install(dev)==0) + count++; + } + if(count) + printk(KERN_INFO "i2o: %d I2O controller%s found and installed.\n", count, + count==1?"":"s"); + return count?count:-ENODEV; +} + +#ifdef I2O_HOTPLUG_SUPPORT +/* + * Activate a newly found PCI I2O controller + * Not used now, but will be needed in future for + * hot plug PCI support + */ +static void i2o_pci_activate(i2o_controller * c) +{ + int i=0; + struct i2o_controller *c; + + if(c->type == I2O_TYPE_PCI) + { + I2O_IRQ_WRITE32(c,0); +#ifdef MODULE + if(core->activate(c)) +#else + if(i2o_activate_controller(c)) +#endif /* MODULE */ + { + printk("%s: Failed to initialize.\n", c->name); +#ifdef MODULE + core->unlock(c); + core->delete(c); +#else + i2o_unlock_controller(c); + i2o_delete_controller(c); +#endif + continue; + } + } +} +#endif // I2O_HOTPLUG_SUPPORT + +#ifdef MODULE + +int i2o_pci_core_attach(struct i2o_core_func_table *table) +{ + MOD_INC_USE_COUNT; + + core = table; + + return i2o_pci_scan(); +} + +void i2o_pci_core_detach(void) +{ + core = NULL; + + MOD_DEC_USE_COUNT; +} + +int init_module(void) +{ + printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n"); + + core = NULL; + + return 0; + +} + +void cleanup_module(void) +{ +} + +EXPORT_SYMBOL(i2o_pci_core_attach); +EXPORT_SYMBOL(i2o_pci_core_detach); + +MODULE_AUTHOR("Red Hat Software"); +MODULE_DESCRIPTION("I2O PCI Interface"); + +#else +void __init i2o_pci_init(void) +{ + printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n"); + i2o_pci_scan(); +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/i2o/i2o_proc.c linux.ac/drivers/message/i2o/i2o_proc.c --- linux.vanilla/drivers/message/i2o/i2o_proc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/i2o/i2o_proc.c Tue Apr 3 17:54:48 2001 @@ -0,0 +1,3372 @@ +/* + * procfs handler for Linux I2O subsystem + * + * (c) Copyright 1999 Deepak Saxena + * + * Originally written by Deepak Saxena(deepak@plexity.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. + * + * This is an initial test release. The code is based on the design + * of the ide procfs system (drivers/block/ide-proc.c). Some code + * taken from i2o-core module by Alan Cox. + * + * DISCLAIMER: This code is still under development/test and may cause + * your system to behave unpredictably. Use at your own discretion. + * + * LAN entries by Juha Sievänen (Juha.Sievanen@cs.Helsinki.FI), + * Auvo Häkkinen (Auvo.Hakkinen@cs.Helsinki.FI) + * University of Helsinki, Department of Computer Science + */ + +/* + * set tabstop=3 + */ + +/* + * TODO List + * + * - Add support for any version 2.0 spec changes once 2.0 IRTOS is + * is available to test with + * - Clean up code to use official structure definitions + */ + +// FIXME! +#define FMT_U64_HEX "0x%08x%08x" +#define U64_VAL(pu64) *((u32*)(pu64)+1), *((u32*)(pu64)) + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/i2o.h> +#include <linux/proc_fs.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/spinlock.h> + +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/byteorder.h> + +#include "i2o_lan.h" + +/* + * Structure used to define /proc entries + */ +typedef struct _i2o_proc_entry_t +{ + char *name; /* entry name */ + mode_t mode; /* mode */ + read_proc_t *read_proc; /* read func */ + write_proc_t *write_proc; /* write func */ +} i2o_proc_entry; + +// #define DRIVERDEBUG + +static int i2o_proc_read_lct(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_hrt(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_status(char *, char **, off_t, int, int *, void *); + +static int i2o_proc_read_hw(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_ddm_table(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_driver_store(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_drivers_stored(char *, char **, off_t, int, int *, void *); + +static int i2o_proc_read_groups(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_phys_device(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_claimed(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_users(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_priv_msgs(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_authorized_users(char *, char **, off_t, int, int *, void *); + +static int i2o_proc_read_dev_name(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_dev_identity(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_ddm_identity(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_uinfo(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_sgl_limits(char *, char **, off_t, int, int *, void *); + +static int i2o_proc_read_sensors(char *, char **, off_t, int, int *, void *); + +static int print_serial_number(char *, int, u8 *, int); + +static int i2o_proc_create_entries(void *, i2o_proc_entry *, + struct proc_dir_entry *); +static void i2o_proc_remove_entries(i2o_proc_entry *, struct proc_dir_entry *); +static int i2o_proc_add_controller(struct i2o_controller *, + struct proc_dir_entry * ); +static void i2o_proc_remove_controller(struct i2o_controller *, + struct proc_dir_entry * ); +static void i2o_proc_add_device(struct i2o_device *, struct proc_dir_entry *); +static void i2o_proc_remove_device(struct i2o_device *); +static int create_i2o_procfs(void); +static int destroy_i2o_procfs(void); +static void i2o_proc_new_dev(struct i2o_controller *, struct i2o_device *); +static void i2o_proc_dev_del(struct i2o_controller *, struct i2o_device *); + +static int i2o_proc_read_lan_dev_info(char *, char **, off_t, int, int *, + void *); +static int i2o_proc_read_lan_mac_addr(char *, char **, off_t, int, int *, + void *); +static int i2o_proc_read_lan_mcast_addr(char *, char **, off_t, int, int *, + void *); +static int i2o_proc_read_lan_batch_control(char *, char **, off_t, int, int *, + void *); +static int i2o_proc_read_lan_operation(char *, char **, off_t, int, int *, + void *); +static int i2o_proc_read_lan_media_operation(char *, char **, off_t, int, + int *, void *); +static int i2o_proc_read_lan_alt_addr(char *, char **, off_t, int, int *, + void *); +static int i2o_proc_read_lan_tx_info(char *, char **, off_t, int, int *, + void *); +static int i2o_proc_read_lan_rx_info(char *, char **, off_t, int, int *, + void *); +static int i2o_proc_read_lan_hist_stats(char *, char **, off_t, int, int *, + void *); +static int i2o_proc_read_lan_eth_stats(char *, char **, off_t, int, + int *, void *); +static int i2o_proc_read_lan_tr_stats(char *, char **, off_t, int, int *, + void *); +static int i2o_proc_read_lan_fddi_stats(char *, char **, off_t, int, int *, + void *); + +static struct proc_dir_entry *i2o_proc_dir_root; + +/* + * I2O OSM descriptor + */ +static struct i2o_handler i2o_proc_handler = +{ + NULL, + i2o_proc_new_dev, + i2o_proc_dev_del, + NULL, + "I2O procfs Layer", + 0, + 0xffffffff // All classes +}; + +/* + * IOP specific entries...write field just in case someone + * ever wants one. + */ +static i2o_proc_entry generic_iop_entries[] = +{ + {"hrt", S_IFREG|S_IRUGO, i2o_proc_read_hrt, NULL}, + {"lct", S_IFREG|S_IRUGO, i2o_proc_read_lct, NULL}, + {"status", S_IFREG|S_IRUGO, i2o_proc_read_status, NULL}, + {"hw", S_IFREG|S_IRUGO, i2o_proc_read_hw, NULL}, + {"ddm_table", S_IFREG|S_IRUGO, i2o_proc_read_ddm_table, NULL}, + {"driver_store", S_IFREG|S_IRUGO, i2o_proc_read_driver_store, NULL}, + {"drivers_stored", S_IFREG|S_IRUGO, i2o_proc_read_drivers_stored, NULL}, + {NULL, 0, NULL, NULL} +}; + +/* + * Device specific entries + */ +static i2o_proc_entry generic_dev_entries[] = +{ + {"groups", S_IFREG|S_IRUGO, i2o_proc_read_groups, NULL}, + {"phys_dev", S_IFREG|S_IRUGO, i2o_proc_read_phys_device, NULL}, + {"claimed", S_IFREG|S_IRUGO, i2o_proc_read_claimed, NULL}, + {"users", S_IFREG|S_IRUGO, i2o_proc_read_users, NULL}, + {"priv_msgs", S_IFREG|S_IRUGO, i2o_proc_read_priv_msgs, NULL}, + {"authorized_users", S_IFREG|S_IRUGO, i2o_proc_read_authorized_users, NULL}, + {"dev_identity", S_IFREG|S_IRUGO, i2o_proc_read_dev_identity, NULL}, + {"ddm_identity", S_IFREG|S_IRUGO, i2o_proc_read_ddm_identity, NULL}, + {"user_info", S_IFREG|S_IRUGO, i2o_proc_read_uinfo, NULL}, + {"sgl_limits", S_IFREG|S_IRUGO, i2o_proc_read_sgl_limits, NULL}, + {"sensors", S_IFREG|S_IRUGO, i2o_proc_read_sensors, NULL}, + {NULL, 0, NULL, NULL} +}; + +/* + * Storage unit specific entries (SCSI Periph, BS) with device names + */ +static i2o_proc_entry rbs_dev_entries[] = +{ + {"dev_name", S_IFREG|S_IRUGO, i2o_proc_read_dev_name, NULL}, + {NULL, 0, NULL, NULL} +}; + +#define SCSI_TABLE_SIZE 13 +static char *scsi_devices[] = +{ + "Direct-Access Read/Write", + "Sequential-Access Storage", + "Printer", + "Processor", + "WORM Device", + "CD-ROM Device", + "Scanner Device", + "Optical Memory Device", + "Medium Changer Device", + "Communications Device", + "Graphics Art Pre-Press Device", + "Graphics Art Pre-Press Device", + "Array Controller Device" +}; + +/* private */ + +/* + * Generic LAN specific entries + * + * Should groups with r/w entries have their own subdirectory? + * + */ +static i2o_proc_entry lan_entries[] = +{ + {"lan_dev_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_dev_info, NULL}, + {"lan_mac_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_mac_addr, NULL}, + {"lan_mcast_addr", S_IFREG|S_IRUGO|S_IWUSR, + i2o_proc_read_lan_mcast_addr, NULL}, + {"lan_batch_ctrl", S_IFREG|S_IRUGO|S_IWUSR, + i2o_proc_read_lan_batch_control, NULL}, + {"lan_operation", S_IFREG|S_IRUGO, i2o_proc_read_lan_operation, NULL}, + {"lan_media_operation", S_IFREG|S_IRUGO, + i2o_proc_read_lan_media_operation, NULL}, + {"lan_alt_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_alt_addr, NULL}, + {"lan_tx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_tx_info, NULL}, + {"lan_rx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_rx_info, NULL}, + + {"lan_hist_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_hist_stats, NULL}, + {NULL, 0, NULL, NULL} +}; + +/* + * Port specific LAN entries + * + */ +static i2o_proc_entry lan_eth_entries[] = +{ + {"lan_eth_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_eth_stats, NULL}, + {NULL, 0, NULL, NULL} +}; + +static i2o_proc_entry lan_tr_entries[] = +{ + {"lan_tr_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_tr_stats, NULL}, + {NULL, 0, NULL, NULL} +}; + +static i2o_proc_entry lan_fddi_entries[] = +{ + {"lan_fddi_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_fddi_stats, NULL}, + {NULL, 0, NULL, NULL} +}; + + +static char *chtostr(u8 *chars, int n) +{ + char tmp[256]; + tmp[0] = 0; + return strncat(tmp, (char *)chars, n); +} + +static int i2o_report_query_status(char *buf, int block_status, char *group) +{ + switch (block_status) + { + case -ETIMEDOUT: + return sprintf(buf, "Timeout reading group %s.\n",group); + case -ENOMEM: + return sprintf(buf, "No free memory to read the table.\n"); + case -I2O_PARAMS_STATUS_INVALID_GROUP_ID: + return sprintf(buf, "Group %s not supported.\n", group); + default: + return sprintf(buf, "Error reading group %s. BlockStatus 0x%02X\n", + group, -block_status); + } +} + +static char* bus_strings[] = +{ + "Local Bus", + "ISA", + "EISA", + "MCA", + "PCI", + "PCMCIA", + "NUBUS", + "CARDBUS" +}; + +static spinlock_t i2o_proc_lock = SPIN_LOCK_UNLOCKED; + +int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_controller *c = (struct i2o_controller *)data; + i2o_hrt *hrt = (i2o_hrt *)c->hrt; + u32 bus; + int count; + int i; + + spin_lock(&i2o_proc_lock); + + len = 0; + + if(hrt->hrt_version) + { + len += sprintf(buf+len, + "HRT table for controller is too new a version.\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + count = hrt->num_entries; + + if((count * hrt->entry_len + 8) > 2048) { + printk(KERN_WARNING "i2o_proc: HRT does not fit into buffer\n"); + len += sprintf(buf+len, + "HRT table too big to fit in buffer.\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf+len, "HRT has %d entries of %d bytes each.\n", + count, hrt->entry_len << 2); + + for(i = 0; i < count; i++) + { + len += sprintf(buf+len, "Entry %d:\n", i); + len += sprintf(buf+len, " Adapter ID: %0#10x\n", + hrt->hrt_entry[i].adapter_id); + len += sprintf(buf+len, " Controlling tid: %0#6x\n", + hrt->hrt_entry[i].parent_tid); + + if(hrt->hrt_entry[i].bus_type != 0x80) + { + bus = hrt->hrt_entry[i].bus_type; + len += sprintf(buf+len, " %s Information\n", bus_strings[bus]); + + switch(bus) + { + case I2O_BUS_LOCAL: + len += sprintf(buf+len, " IOBase: %0#6x,", + hrt->hrt_entry[i].bus.local_bus.LbBaseIOPort); + len += sprintf(buf+len, " MemoryBase: %0#10x\n", + hrt->hrt_entry[i].bus.local_bus.LbBaseMemoryAddress); + break; + + case I2O_BUS_ISA: + len += sprintf(buf+len, " IOBase: %0#6x,", + hrt->hrt_entry[i].bus.isa_bus.IsaBaseIOPort); + len += sprintf(buf+len, " MemoryBase: %0#10x,", + hrt->hrt_entry[i].bus.isa_bus.IsaBaseMemoryAddress); + len += sprintf(buf+len, " CSN: %0#4x,", + hrt->hrt_entry[i].bus.isa_bus.CSN); + break; + + case I2O_BUS_EISA: + len += sprintf(buf+len, " IOBase: %0#6x,", + hrt->hrt_entry[i].bus.eisa_bus.EisaBaseIOPort); + len += sprintf(buf+len, " MemoryBase: %0#10x,", + hrt->hrt_entry[i].bus.eisa_bus.EisaBaseMemoryAddress); + len += sprintf(buf+len, " Slot: %0#4x,", + hrt->hrt_entry[i].bus.eisa_bus.EisaSlotNumber); + break; + + case I2O_BUS_MCA: + len += sprintf(buf+len, " IOBase: %0#6x,", + hrt->hrt_entry[i].bus.mca_bus.McaBaseIOPort); + len += sprintf(buf+len, " MemoryBase: %0#10x,", + hrt->hrt_entry[i].bus.mca_bus.McaBaseMemoryAddress); + len += sprintf(buf+len, " Slot: %0#4x,", + hrt->hrt_entry[i].bus.mca_bus.McaSlotNumber); + break; + + case I2O_BUS_PCI: + len += sprintf(buf+len, " Bus: %0#4x", + hrt->hrt_entry[i].bus.pci_bus.PciBusNumber); + len += sprintf(buf+len, " Dev: %0#4x", + hrt->hrt_entry[i].bus.pci_bus.PciDeviceNumber); + len += sprintf(buf+len, " Func: %0#4x", + hrt->hrt_entry[i].bus.pci_bus.PciFunctionNumber); + len += sprintf(buf+len, " Vendor: %0#6x", + hrt->hrt_entry[i].bus.pci_bus.PciVendorID); + len += sprintf(buf+len, " Device: %0#6x\n", + hrt->hrt_entry[i].bus.pci_bus.PciDeviceID); + break; + + default: + len += sprintf(buf+len, " Unsupported Bus Type\n"); + } + } + else + len += sprintf(buf+len, " Unknown Bus Type\n"); + } + + spin_unlock(&i2o_proc_lock); + + return len; +} + +int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_controller *c = (struct i2o_controller*)data; + i2o_lct *lct = (i2o_lct *)c->lct; + int entries; + int i; + +#define BUS_TABLE_SIZE 3 + static char *bus_ports[] = + { + "Generic Bus", + "SCSI Bus", + "Fibre Channel Bus" + }; + + spin_lock(&i2o_proc_lock); + len = 0; + + entries = (lct->table_size - 3)/9; + + len += sprintf(buf, "LCT contains %d %s\n", entries, + entries == 1 ? "entry" : "entries"); + if(lct->boot_tid) + len += sprintf(buf+len, "Boot Device @ ID %d\n", lct->boot_tid); + + len += + sprintf(buf+len, "Current Change Indicator: %#10x\n", lct->change_ind); + + for(i = 0; i < entries; i++) + { + len += sprintf(buf+len, "Entry %d\n", i); + len += sprintf(buf+len, " Class, SubClass : %s", i2o_get_class_name(lct->lct_entry[i].class_id)); + + /* + * Classes which we'll print subclass info for + */ + switch(lct->lct_entry[i].class_id & 0xFFF) + { + case I2O_CLASS_RANDOM_BLOCK_STORAGE: + switch(lct->lct_entry[i].sub_class) + { + case 0x00: + len += sprintf(buf+len, ", Direct-Access Read/Write"); + break; + + case 0x04: + len += sprintf(buf+len, ", WORM Drive"); + break; + + case 0x05: + len += sprintf(buf+len, ", CD-ROM Drive"); + break; + + case 0x07: + len += sprintf(buf+len, ", Optical Memory Device"); + break; + + default: + len += sprintf(buf+len, ", Unknown (0x%02x)", + lct->lct_entry[i].sub_class); + break; + } + break; + + case I2O_CLASS_LAN: + switch(lct->lct_entry[i].sub_class & 0xFF) + { + case 0x30: + len += sprintf(buf+len, ", Ethernet"); + break; + + case 0x40: + len += sprintf(buf+len, ", 100base VG"); + break; + + case 0x50: + len += sprintf(buf+len, ", IEEE 802.5/Token-Ring"); + break; + + case 0x60: + len += sprintf(buf+len, ", ANSI X3T9.5 FDDI"); + break; + + case 0x70: + len += sprintf(buf+len, ", Fibre Channel"); + break; + + default: + len += sprintf(buf+len, ", Unknown Sub-Class (0x%02x)", + lct->lct_entry[i].sub_class & 0xFF); + break; + } + break; + + case I2O_CLASS_SCSI_PERIPHERAL: + if(lct->lct_entry[i].sub_class < SCSI_TABLE_SIZE) + len += sprintf(buf+len, ", %s", + scsi_devices[lct->lct_entry[i].sub_class]); + else + len += sprintf(buf+len, ", Unknown Device Type"); + break; + + case I2O_CLASS_BUS_ADAPTER_PORT: + if(lct->lct_entry[i].sub_class < BUS_TABLE_SIZE) + len += sprintf(buf+len, ", %s", + bus_ports[lct->lct_entry[i].sub_class]); + else + len += sprintf(buf+len, ", Unknown Bus Type"); + break; + } + len += sprintf(buf+len, "\n"); + + len += sprintf(buf+len, " Local TID : 0x%03x\n", lct->lct_entry[i].tid); + len += sprintf(buf+len, " User TID : 0x%03x\n", lct->lct_entry[i].user_tid); + len += sprintf(buf+len, " Parent TID : 0x%03x\n", + lct->lct_entry[i].parent_tid); + len += sprintf(buf+len, " Identity Tag : 0x%x%x%x%x%x%x%x%x\n", + lct->lct_entry[i].identity_tag[0], + lct->lct_entry[i].identity_tag[1], + lct->lct_entry[i].identity_tag[2], + lct->lct_entry[i].identity_tag[3], + lct->lct_entry[i].identity_tag[4], + lct->lct_entry[i].identity_tag[5], + lct->lct_entry[i].identity_tag[6], + lct->lct_entry[i].identity_tag[7]); + len += sprintf(buf+len, " Change Indicator : %0#10x\n", + lct->lct_entry[i].change_ind); + len += sprintf(buf+len, " Event Capab Mask : %0#10x\n", + lct->lct_entry[i].device_flags); + } + + spin_unlock(&i2o_proc_lock); + return len; +} + +int i2o_proc_read_status(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_controller *c = (struct i2o_controller*)data; + char prodstr[25]; + int version; + + spin_lock(&i2o_proc_lock); + len = 0; + + i2o_status_get(c); // reread the status block + + len += sprintf(buf+len,"Organization ID : %0#6x\n", + c->status_block->org_id); + + version = c->status_block->i2o_version; + +/* FIXME for Spec 2.0 + if (version == 0x02) { + len += sprintf(buf+len,"Lowest I2O version supported: "); + switch(workspace[2]) { + case 0x00: + len += sprintf(buf+len,"1.0\n"); + break; + case 0x01: + len += sprintf(buf+len,"1.5\n"); + break; + case 0x02: + len += sprintf(buf+len,"2.0\n"); + break; + } + + len += sprintf(buf+len, "Highest I2O version supported: "); + switch(workspace[3]) { + case 0x00: + len += sprintf(buf+len,"1.0\n"); + break; + case 0x01: + len += sprintf(buf+len,"1.5\n"); + break; + case 0x02: + len += sprintf(buf+len,"2.0\n"); + break; + } + } +*/ + len += sprintf(buf+len,"IOP ID : %0#5x\n", + c->status_block->iop_id); + len += sprintf(buf+len,"Host Unit ID : %0#6x\n", + c->status_block->host_unit_id); + len += sprintf(buf+len,"Segment Number : %0#5x\n", + c->status_block->segment_number); + + len += sprintf(buf+len, "I2O version : "); + switch (version) { + case 0x00: + len += sprintf(buf+len,"1.0\n"); + break; + case 0x01: + len += sprintf(buf+len,"1.5\n"); + break; + case 0x02: + len += sprintf(buf+len,"2.0\n"); + break; + default: + len += sprintf(buf+len,"Unknown version\n"); + } + + len += sprintf(buf+len, "IOP State : "); + switch (c->status_block->iop_state) { + case 0x01: + len += sprintf(buf+len,"INIT\n"); + break; + + case 0x02: + len += sprintf(buf+len,"RESET\n"); + break; + + case 0x04: + len += sprintf(buf+len,"HOLD\n"); + break; + + case 0x05: + len += sprintf(buf+len,"READY\n"); + break; + + case 0x08: + len += sprintf(buf+len,"OPERATIONAL\n"); + break; + + case 0x10: + len += sprintf(buf+len,"FAILED\n"); + break; + + case 0x11: + len += sprintf(buf+len,"FAULTED\n"); + break; + + default: + len += sprintf(buf+len,"Unknown\n"); + break; + } + + len += sprintf(buf+len,"Messenger Type : "); + switch (c->status_block->msg_type) { + case 0x00: + len += sprintf(buf+len,"Memory mapped\n"); + break; + case 0x01: + len += sprintf(buf+len,"Memory mapped only\n"); + break; + case 0x02: + len += sprintf(buf+len,"Remote only\n"); + break; + case 0x03: + len += sprintf(buf+len,"Memory mapped and remote\n"); + break; + default: + len += sprintf(buf+len,"Unknown\n"); + } + + len += sprintf(buf+len,"Inbound Frame Size : %d bytes\n", + c->status_block->inbound_frame_size<<2); + len += sprintf(buf+len,"Max Inbound Frames : %d\n", + c->status_block->max_inbound_frames); + len += sprintf(buf+len,"Current Inbound Frames : %d\n", + c->status_block->cur_inbound_frames); + len += sprintf(buf+len,"Max Outbound Frames : %d\n", + c->status_block->max_outbound_frames); + + /* Spec doesn't say if NULL terminated or not... */ + memcpy(prodstr, c->status_block->product_id, 24); + prodstr[24] = '\0'; + len += sprintf(buf+len,"Product ID : %s\n", prodstr); + len += sprintf(buf+len,"Expected LCT Size : %d bytes\n", + c->status_block->expected_lct_size); + + len += sprintf(buf+len,"IOP Capabilities\n"); + len += sprintf(buf+len," Context Field Size Support : "); + switch (c->status_block->iop_capabilities & 0x0000003) { + case 0: + len += sprintf(buf+len,"Supports only 32-bit context fields\n"); + break; + case 1: + len += sprintf(buf+len,"Supports only 64-bit context fields\n"); + break; + case 2: + len += sprintf(buf+len,"Supports 32-bit and 64-bit context fields, " + "but not concurrently\n"); + break; + case 3: + len += sprintf(buf+len,"Supports 32-bit and 64-bit context fields " + "concurrently\n"); + break; + default: + len += sprintf(buf+len,"0x%08x\n",c->status_block->iop_capabilities); + } + len += sprintf(buf+len," Current Context Field Size : "); + switch (c->status_block->iop_capabilities & 0x0000000C) { + case 0: + len += sprintf(buf+len,"not configured\n"); + break; + case 4: + len += sprintf(buf+len,"Supports only 32-bit context fields\n"); + break; + case 8: + len += sprintf(buf+len,"Supports only 64-bit context fields\n"); + break; + case 12: + len += sprintf(buf+len,"Supports both 32-bit or 64-bit context fields " + "concurrently\n"); + break; + default: + len += sprintf(buf+len,"\n"); + } + len += sprintf(buf+len," Inbound Peer Support : %s\n", + (c->status_block->iop_capabilities & 0x00000010) ? "Supported" : "Not supported"); + len += sprintf(buf+len," Outbound Peer Support : %s\n", + (c->status_block->iop_capabilities & 0x00000020) ? "Supported" : "Not supported"); + len += sprintf(buf+len," Peer to Peer Support : %s\n", + (c->status_block->iop_capabilities & 0x00000040) ? "Supported" : "Not supported"); + + len += sprintf(buf+len, "Desired private memory size : %d kB\n", + c->status_block->desired_mem_size>>10); + len += sprintf(buf+len, "Allocated private memory size : %d kB\n", + c->status_block->current_mem_size>>10); + len += sprintf(buf+len, "Private memory base address : %0#10x\n", + c->status_block->current_mem_base); + len += sprintf(buf+len, "Desired private I/O size : %d kB\n", + c->status_block->desired_io_size>>10); + len += sprintf(buf+len, "Allocated private I/O size : %d kB\n", + c->status_block->current_io_size>>10); + len += sprintf(buf+len, "Private I/O base address : %0#10x\n", + c->status_block->current_io_base); + + spin_unlock(&i2o_proc_lock); + + return len; +} + +int i2o_proc_read_hw(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_controller *c = (struct i2o_controller*)data; + static u32 work32[5]; + static u8 *work8 = (u8*)work32; + static u16 *work16 = (u16*)work32; + int token; + u32 hwcap; + + static char *cpu_table[] = + { + "Intel 80960 series", + "AMD2900 series", + "Motorola 68000 series", + "ARM series", + "MIPS series", + "Sparc series", + "PowerPC series", + "Intel x86 series" + }; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_scalar(c, ADAPTER_TID, 0x0000, -1, &work32, sizeof(work32)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0x0000 IOP Hardware"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf+len, "I2O Vendor ID : %0#6x\n", work16[0]); + len += sprintf(buf+len, "Product ID : %0#6x\n", work16[1]); + len += sprintf(buf+len, "CPU : "); + if(work8[16] > 8) + len += sprintf(buf+len, "Unknown\n"); + else + len += sprintf(buf+len, "%s\n", cpu_table[work8[16]]); + /* Anyone using ProcessorVersion? */ + + len += sprintf(buf+len, "RAM : %dkB\n", work32[1]>>10); + len += sprintf(buf+len, "Non-Volatile Mem : %dkB\n", work32[2]>>10); + + hwcap = work32[3]; + len += sprintf(buf+len, "Capabilities : 0x%08x\n", hwcap); + len += sprintf(buf+len, " [%s] Self booting\n", + (hwcap&0x00000001) ? "+" : "-"); + len += sprintf(buf+len, " [%s] Upgradable IRTOS\n", + (hwcap&0x00000002) ? "+" : "-"); + len += sprintf(buf+len, " [%s] Supports downloading DDMs\n", + (hwcap&0x00000004) ? "+" : "-"); + len += sprintf(buf+len, " [%s] Supports installing DDMs\n", + (hwcap&0x00000008) ? "+" : "-"); + len += sprintf(buf+len, " [%s] Battery-backed RAM\n", + (hwcap&0x00000010) ? "+" : "-"); + + spin_unlock(&i2o_proc_lock); + + return len; +} + + +/* Executive group 0003h - Executing DDM List (table) */ +int i2o_proc_read_ddm_table(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_controller *c = (struct i2o_controller*)data; + int token; + int i; + + typedef struct _i2o_exec_execute_ddm_table { + u16 ddm_tid; + u8 module_type; + u8 reserved; + u16 i2o_vendor_id; + u16 module_id; + u8 module_name_version[28]; + u32 data_size; + u32 code_size; + } i2o_exec_execute_ddm_table; + + struct + { + u16 result_count; + u16 pad; + u16 block_size; + u8 block_status; + u8 error_info_size; + u16 row_count; + u16 more_flag; + i2o_exec_execute_ddm_table ddm_table[MAX_I2O_MODULES]; + } result; + + i2o_exec_execute_ddm_table ddm_table; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_table(I2O_PARAMS_TABLE_GET, + c, ADAPTER_TID, + 0x0003, -1, + NULL, 0, + &result, sizeof(result)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0x0003 Executing DDM List"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf+len, "Tid Module_type Vendor Mod_id Module_name Vrs Data_size Code_size\n"); + ddm_table=result.ddm_table[0]; + + for(i=0; i < result.row_count; ddm_table=result.ddm_table[++i]) + { + len += sprintf(buf+len, "0x%03x ", ddm_table.ddm_tid & 0xFFF); + + switch(ddm_table.module_type) + { + case 0x01: + len += sprintf(buf+len, "Downloaded DDM "); + break; + case 0x22: + len += sprintf(buf+len, "Embedded DDM "); + break; + default: + len += sprintf(buf+len, " "); + } + + len += sprintf(buf+len, "%-#7x", ddm_table.i2o_vendor_id); + len += sprintf(buf+len, "%-#8x", ddm_table.module_id); + len += sprintf(buf+len, "%-29s", chtostr(ddm_table.module_name_version, 28)); + len += sprintf(buf+len, "%9d ", ddm_table.data_size); + len += sprintf(buf+len, "%8d", ddm_table.code_size); + + len += sprintf(buf+len, "\n"); + } + + spin_unlock(&i2o_proc_lock); + + return len; +} + + +/* Executive group 0004h - Driver Store (scalar) */ +int i2o_proc_read_driver_store(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_controller *c = (struct i2o_controller*)data; + u32 work32[8]; + int token; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_scalar(c, ADAPTER_TID, 0x0004, -1, &work32, sizeof(work32)); + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0x0004 Driver Store"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf+len, "Module limit : %d\n" + "Module count : %d\n" + "Current space : %d kB\n" + "Free space : %d kB\n", + work32[0], work32[1], work32[2]>>10, work32[3]>>10); + + spin_unlock(&i2o_proc_lock); + + return len; +} + + +/* Executive group 0005h - Driver Store Table (table) */ +int i2o_proc_read_drivers_stored(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + typedef struct _i2o_driver_store { + u16 stored_ddm_index; + u8 module_type; + u8 reserved; + u16 i2o_vendor_id; + u16 module_id; + u8 module_name_version[28]; + u8 date[8]; + u32 module_size; + u32 mpb_size; + u32 module_flags; + } i2o_driver_store_table; + + struct i2o_controller *c = (struct i2o_controller*)data; + int token; + int i; + + struct + { + u16 result_count; + u16 pad; + u16 block_size; + u8 block_status; + u8 error_info_size; + u16 row_count; + u16 more_flag; + i2o_driver_store_table dst[MAX_I2O_MODULES]; + } result; + + i2o_driver_store_table dst; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_table(I2O_PARAMS_TABLE_GET, + c, ADAPTER_TID, 0x0005, -1, NULL, 0, + &result, sizeof(result)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0x0005 DRIVER STORE TABLE"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf+len, "# Module_type Vendor Mod_id Module_name Vrs" + "Date Mod_size Par_size Flags\n"); + for(i=0, dst=result.dst[0]; i < result.row_count; dst=result.dst[++i]) + { + len += sprintf(buf+len, "%-3d", dst.stored_ddm_index); + switch(dst.module_type) + { + case 0x01: + len += sprintf(buf+len, "Downloaded DDM "); + break; + case 0x22: + len += sprintf(buf+len, "Embedded DDM "); + break; + default: + len += sprintf(buf+len, " "); + } + +#if 0 + if(c->i2oversion == 0x02) + len += sprintf(buf+len, "%-d", dst.module_state); +#endif + + len += sprintf(buf+len, "%-#7x", dst.i2o_vendor_id); + len += sprintf(buf+len, "%-#8x", dst.module_id); + len += sprintf(buf+len, "%-29s", chtostr(dst.module_name_version,28)); + len += sprintf(buf+len, "%-9s", chtostr(dst.date,8)); + len += sprintf(buf+len, "%8d ", dst.module_size); + len += sprintf(buf+len, "%8d ", dst.mpb_size); + len += sprintf(buf+len, "0x%04x", dst.module_flags); +#if 0 + if(c->i2oversion == 0x02) + len += sprintf(buf+len, "%d", + dst.notification_level); +#endif + len += sprintf(buf+len, "\n"); + } + + spin_unlock(&i2o_proc_lock); + + return len; +} + + +/* Generic group F000h - Params Descriptor (table) */ +int i2o_proc_read_groups(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + int token; + int i; + u8 properties; + + typedef struct _i2o_group_info + { + u16 group_number; + u16 field_count; + u16 row_count; + u8 properties; + u8 reserved; + } i2o_group_info; + + struct + { + u16 result_count; + u16 pad; + u16 block_size; + u8 block_status; + u8 error_info_size; + u16 row_count; + u16 more_flag; + i2o_group_info group[256]; + } result; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_table(I2O_PARAMS_TABLE_GET, + d->controller, d->lct_data.tid, 0xF000, -1, NULL, 0, + &result, sizeof(result)); + + if (token < 0) { + len = i2o_report_query_status(buf+len, token, "0xF000 Params Descriptor"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf+len, "# Group FieldCount RowCount Type Add Del Clear\n"); + + for (i=0; i < result.row_count; i++) + { + len += sprintf(buf+len, "%-3d", i); + len += sprintf(buf+len, "0x%04X ", result.group[i].group_number); + len += sprintf(buf+len, "%10d ", result.group[i].field_count); + len += sprintf(buf+len, "%8d ", result.group[i].row_count); + + properties = result.group[i].properties; + if (properties & 0x1) len += sprintf(buf+len, "Table "); + else len += sprintf(buf+len, "Scalar "); + if (properties & 0x2) len += sprintf(buf+len, " + "); + else len += sprintf(buf+len, " - "); + if (properties & 0x4) len += sprintf(buf+len, " + "); + else len += sprintf(buf+len, " - "); + if (properties & 0x8) len += sprintf(buf+len, " + "); + else len += sprintf(buf+len, " - "); + + len += sprintf(buf+len, "\n"); + } + + if (result.more_flag) + len += sprintf(buf+len, "There is more...\n"); + + spin_unlock(&i2o_proc_lock); + + return len; +} + + +/* Generic group F001h - Physical Device Table (table) */ +int i2o_proc_read_phys_device(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + int token; + int i; + + struct + { + u16 result_count; + u16 pad; + u16 block_size; + u8 block_status; + u8 error_info_size; + u16 row_count; + u16 more_flag; + u32 adapter_id[64]; + } result; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_table(I2O_PARAMS_TABLE_GET, + d->controller, d->lct_data.tid, + 0xF001, -1, NULL, 0, + &result, sizeof(result)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0xF001 Physical Device Table"); + spin_unlock(&i2o_proc_lock); + return len; + } + + if (result.row_count) + len += sprintf(buf+len, "# AdapterId\n"); + + for (i=0; i < result.row_count; i++) + { + len += sprintf(buf+len, "%-2d", i); + len += sprintf(buf+len, "%#7x\n", result.adapter_id[i]); + } + + if (result.more_flag) + len += sprintf(buf+len, "There is more...\n"); + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* Generic group F002h - Claimed Table (table) */ +int i2o_proc_read_claimed(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + int token; + int i; + + struct { + u16 result_count; + u16 pad; + u16 block_size; + u8 block_status; + u8 error_info_size; + u16 row_count; + u16 more_flag; + u16 claimed_tid[64]; + } result; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_table(I2O_PARAMS_TABLE_GET, + d->controller, d->lct_data.tid, + 0xF002, -1, NULL, 0, + &result, sizeof(result)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0xF002 Claimed Table"); + spin_unlock(&i2o_proc_lock); + return len; + } + + if (result.row_count) + len += sprintf(buf+len, "# ClaimedTid\n"); + + for (i=0; i < result.row_count; i++) + { + len += sprintf(buf+len, "%-2d", i); + len += sprintf(buf+len, "%#7x\n", result.claimed_tid[i]); + } + + if (result.more_flag) + len += sprintf(buf+len, "There is more...\n"); + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* Generic group F003h - User Table (table) */ +int i2o_proc_read_users(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + int token; + int i; + + typedef struct _i2o_user_table + { + u16 instance; + u16 user_tid; + u8 claim_type; + u8 reserved1; + u16 reserved2; + } i2o_user_table; + + struct + { + u16 result_count; + u16 pad; + u16 block_size; + u8 block_status; + u8 error_info_size; + u16 row_count; + u16 more_flag; + i2o_user_table user[64]; + } result; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_table(I2O_PARAMS_TABLE_GET, + d->controller, d->lct_data.tid, + 0xF003, -1, NULL, 0, + &result, sizeof(result)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0xF003 User Table"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf+len, "# Instance UserTid ClaimType\n"); + + for(i=0; i < result.row_count; i++) + { + len += sprintf(buf+len, "%-3d", i); + len += sprintf(buf+len, "%#8x ", result.user[i].instance); + len += sprintf(buf+len, "%#7x ", result.user[i].user_tid); + len += sprintf(buf+len, "%#9x\n", result.user[i].claim_type); + } + + if (result.more_flag) + len += sprintf(buf+len, "There is more...\n"); + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* Generic group F005h - Private message extensions (table) (optional) */ +int i2o_proc_read_priv_msgs(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + int token; + int i; + + typedef struct _i2o_private + { + u16 ext_instance; + u16 organization_id; + u16 x_function_code; + } i2o_private; + + struct + { + u16 result_count; + u16 pad; + u16 block_size; + u8 block_status; + u8 error_info_size; + u16 row_count; + u16 more_flag; + i2o_private extension[64]; + } result; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_table(I2O_PARAMS_TABLE_GET, + d->controller, d->lct_data.tid, + 0xF000, -1, + NULL, 0, + &result, sizeof(result)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0xF005 Private Message Extensions (optional)"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf+len, "Instance# OrgId FunctionCode\n"); + + for(i=0; i < result.row_count; i++) + { + len += sprintf(buf+len, "%0#9x ", result.extension[i].ext_instance); + len += sprintf(buf+len, "%0#6x ", result.extension[i].organization_id); + len += sprintf(buf+len, "%0#6x", result.extension[i].x_function_code); + + len += sprintf(buf+len, "\n"); + } + + if(result.more_flag) + len += sprintf(buf+len, "There is more...\n"); + + spin_unlock(&i2o_proc_lock); + + return len; +} + + +/* Generic group F006h - Authorized User Table (table) */ +int i2o_proc_read_authorized_users(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + int token; + int i; + + struct + { + u16 result_count; + u16 pad; + u16 block_size; + u8 block_status; + u8 error_info_size; + u16 row_count; + u16 more_flag; + u32 alternate_tid[64]; + } result; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_table(I2O_PARAMS_TABLE_GET, + d->controller, d->lct_data.tid, + 0xF006, -1, + NULL, 0, + &result, sizeof(result)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0xF006 Autohorized User Table"); + spin_unlock(&i2o_proc_lock); + return len; + } + + if (result.row_count) + len += sprintf(buf+len, "# AlternateTid\n"); + + for(i=0; i < result.row_count; i++) + { + len += sprintf(buf+len, "%-2d", i); + len += sprintf(buf+len, "%#7x ", result.alternate_tid[i]); + } + + if (result.more_flag) + len += sprintf(buf+len, "There is more...\n"); + + spin_unlock(&i2o_proc_lock); + return len; +} + + +/* Generic group F100h - Device Identity (scalar) */ +int i2o_proc_read_dev_identity(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u32 work32[128]; // allow for "stuff" + up to 256 byte (max) serial number + // == (allow) 512d bytes (max) + static u16 *work16 = (u16*)work32; + int token; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0xF100, -1, + &work32, sizeof(work32)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token ,"0xF100 Device Identity"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Device Class : %s\n", i2o_get_class_name(work16[0])); + len += sprintf(buf+len, "Owner TID : %0#5x\n", work16[2]); + len += sprintf(buf+len, "Parent TID : %0#5x\n", work16[3]); + len += sprintf(buf+len, "Vendor info : %s\n", chtostr((u8 *)(work32+2), 16)); + len += sprintf(buf+len, "Product info : %s\n", chtostr((u8 *)(work32+6), 16)); + len += sprintf(buf+len, "Description : %s\n", chtostr((u8 *)(work32+10), 16)); + len += sprintf(buf+len, "Product rev. : %s\n", chtostr((u8 *)(work32+14), 8)); + + len += sprintf(buf+len, "Serial number : "); + len = print_serial_number(buf, len, + (u8*)(work32+16), + /* allow for SNLen plus + * possible trailing '\0' + */ + sizeof(work32)-(16*sizeof(u32))-2 + ); + len += sprintf(buf+len, "\n"); + + spin_unlock(&i2o_proc_lock); + + return len; +} + + +int i2o_proc_read_dev_name(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + + if ( d->dev_name[0] == '\0' ) + return 0; + + len = sprintf(buf, "%s\n", d->dev_name); + + return len; +} + + +/* Generic group F101h - DDM Identity (scalar) */ +int i2o_proc_read_ddm_identity(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + int token; + + struct + { + u16 ddm_tid; + u8 module_name[24]; + u8 module_rev[8]; + u8 sn_format; + u8 serial_number[12]; + u8 pad[256]; // allow up to 256 byte (max) serial number + } result; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0xF101, -1, + &result, sizeof(result)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0xF101 DDM Identity"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Registering DDM TID : 0x%03x\n", result.ddm_tid); + len += sprintf(buf+len, "Module name : %s\n", chtostr(result.module_name, 24)); + len += sprintf(buf+len, "Module revision : %s\n", chtostr(result.module_rev, 8)); + + len += sprintf(buf+len, "Serial number : "); + len = print_serial_number(buf, len, result.serial_number, sizeof(result)-36); + /* allow for SNLen plus possible trailing '\0' */ + + len += sprintf(buf+len, "\n"); + + spin_unlock(&i2o_proc_lock); + + return len; +} + +/* Generic group F102h - User Information (scalar) */ +int i2o_proc_read_uinfo(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + int token; + + struct + { + u8 device_name[64]; + u8 service_name[64]; + u8 physical_location[64]; + u8 instance_number[4]; + } result; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0xF102, -1, + &result, sizeof(result)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0xF102 User Information"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Device name : %s\n", chtostr(result.device_name, 64)); + len += sprintf(buf+len, "Service name : %s\n", chtostr(result.service_name, 64)); + len += sprintf(buf+len, "Physical name : %s\n", chtostr(result.physical_location, 64)); + len += sprintf(buf+len, "Instance number : %s\n", chtostr(result.instance_number, 4)); + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* Generic group F103h - SGL Operating Limits (scalar) */ +int i2o_proc_read_sgl_limits(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u32 work32[12]; + static u16 *work16 = (u16 *)work32; + static u8 *work8 = (u8 *)work32; + int token; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0xF103, -1, + &work32, sizeof(work32)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0xF103 SGL Operating Limits"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "SGL chain size : %d\n", work32[0]); + len += sprintf(buf+len, "Max SGL chain size : %d\n", work32[1]); + len += sprintf(buf+len, "SGL chain size target : %d\n", work32[2]); + len += sprintf(buf+len, "SGL frag count : %d\n", work16[6]); + len += sprintf(buf+len, "Max SGL frag count : %d\n", work16[7]); + len += sprintf(buf+len, "SGL frag count target : %d\n", work16[8]); + + if (d->i2oversion == 0x02) + { + len += sprintf(buf+len, "SGL data alignment : %d\n", work16[8]); + len += sprintf(buf+len, "SGL addr limit : %d\n", work8[20]); + len += sprintf(buf+len, "SGL addr sizes supported : "); + if (work8[21] & 0x01) + len += sprintf(buf+len, "32 bit "); + if (work8[21] & 0x02) + len += sprintf(buf+len, "64 bit "); + if (work8[21] & 0x04) + len += sprintf(buf+len, "96 bit "); + if (work8[21] & 0x08) + len += sprintf(buf+len, "128 bit "); + len += sprintf(buf+len, "\n"); + } + + spin_unlock(&i2o_proc_lock); + + return len; +} + +/* Generic group F200h - Sensors (scalar) */ +int i2o_proc_read_sensors(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + int token; + + struct + { + u16 sensor_instance; + u8 component; + u16 component_instance; + u8 sensor_class; + u8 sensor_type; + u8 scaling_exponent; + u32 actual_reading; + u32 minimum_reading; + u32 low2lowcat_treshold; + u32 lowcat2low_treshold; + u32 lowwarn2low_treshold; + u32 low2lowwarn_treshold; + u32 norm2lowwarn_treshold; + u32 lowwarn2norm_treshold; + u32 nominal_reading; + u32 hiwarn2norm_treshold; + u32 norm2hiwarn_treshold; + u32 high2hiwarn_treshold; + u32 hiwarn2high_treshold; + u32 hicat2high_treshold; + u32 hi2hicat_treshold; + u32 maximum_reading; + u8 sensor_state; + u16 event_enable; + } result; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0xF200, -1, + &result, sizeof(result)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0xF200 Sensors (optional)"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf+len, "Sensor instance : %d\n", result.sensor_instance); + + len += sprintf(buf+len, "Component : %d = ", result.component); + switch (result.component) + { + case 0: len += sprintf(buf+len, "Other"); + break; + case 1: len += sprintf(buf+len, "Planar logic Board"); + break; + case 2: len += sprintf(buf+len, "CPU"); + break; + case 3: len += sprintf(buf+len, "Chassis"); + break; + case 4: len += sprintf(buf+len, "Power Supply"); + break; + case 5: len += sprintf(buf+len, "Storage"); + break; + case 6: len += sprintf(buf+len, "External"); + break; + } + len += sprintf(buf+len,"\n"); + + len += sprintf(buf+len, "Component instance : %d\n", result.component_instance); + len += sprintf(buf+len, "Sensor class : %s\n", + result.sensor_class ? "Analog" : "Digital"); + + len += sprintf(buf+len, "Sensor type : %d = ",result.sensor_type); + switch (result.sensor_type) + { + case 0: len += sprintf(buf+len, "Other\n"); + break; + case 1: len += sprintf(buf+len, "Thermal\n"); + break; + case 2: len += sprintf(buf+len, "DC voltage (DC volts)\n"); + break; + case 3: len += sprintf(buf+len, "AC voltage (AC volts)\n"); + break; + case 4: len += sprintf(buf+len, "DC current (DC amps)\n"); + break; + case 5: len += sprintf(buf+len, "AC current (AC volts)\n"); + break; + case 6: len += sprintf(buf+len, "Door open\n"); + break; + case 7: len += sprintf(buf+len, "Fan operational\n"); + break; + } + + len += sprintf(buf+len, "Scaling exponent : %d\n", result.scaling_exponent); + len += sprintf(buf+len, "Actual reading : %d\n", result.actual_reading); + len += sprintf(buf+len, "Minimum reading : %d\n", result.minimum_reading); + len += sprintf(buf+len, "Low2LowCat treshold : %d\n", result.low2lowcat_treshold); + len += sprintf(buf+len, "LowCat2Low treshold : %d\n", result.lowcat2low_treshold); + len += sprintf(buf+len, "LowWarn2Low treshold : %d\n", result.lowwarn2low_treshold); + len += sprintf(buf+len, "Low2LowWarn treshold : %d\n", result.low2lowwarn_treshold); + len += sprintf(buf+len, "Norm2LowWarn treshold : %d\n", result.norm2lowwarn_treshold); + len += sprintf(buf+len, "LowWarn2Norm treshold : %d\n", result.lowwarn2norm_treshold); + len += sprintf(buf+len, "Nominal reading : %d\n", result.nominal_reading); + len += sprintf(buf+len, "HiWarn2Norm treshold : %d\n", result.hiwarn2norm_treshold); + len += sprintf(buf+len, "Norm2HiWarn treshold : %d\n", result.norm2hiwarn_treshold); + len += sprintf(buf+len, "High2HiWarn treshold : %d\n", result.high2hiwarn_treshold); + len += sprintf(buf+len, "HiWarn2High treshold : %d\n", result.hiwarn2high_treshold); + len += sprintf(buf+len, "HiCat2High treshold : %d\n", result.hicat2high_treshold); + len += sprintf(buf+len, "High2HiCat treshold : %d\n", result.hi2hicat_treshold); + len += sprintf(buf+len, "Maximum reading : %d\n", result.maximum_reading); + + len += sprintf(buf+len, "Sensor state : %d = ", result.sensor_state); + switch (result.sensor_state) + { + case 0: len += sprintf(buf+len, "Normal\n"); + break; + case 1: len += sprintf(buf+len, "Abnormal\n"); + break; + case 2: len += sprintf(buf+len, "Unknown\n"); + break; + case 3: len += sprintf(buf+len, "Low Catastrophic (LoCat)\n"); + break; + case 4: len += sprintf(buf+len, "Low (Low)\n"); + break; + case 5: len += sprintf(buf+len, "Low Warning (LoWarn)\n"); + break; + case 6: len += sprintf(buf+len, "High Warning (HiWarn)\n"); + break; + case 7: len += sprintf(buf+len, "High (High)\n"); + break; + case 8: len += sprintf(buf+len, "High Catastrophic (HiCat)\n"); + break; + } + + len += sprintf(buf+len, "Event_enable : 0x%02X\n", result.event_enable); + len += sprintf(buf+len, " [%s] Operational state change. \n", + (result.event_enable & 0x01) ? "+" : "-" ); + len += sprintf(buf+len, " [%s] Low catastrophic. \n", + (result.event_enable & 0x02) ? "+" : "-" ); + len += sprintf(buf+len, " [%s] Low reading. \n", + (result.event_enable & 0x04) ? "+" : "-" ); + len += sprintf(buf+len, " [%s] Low warning. \n", + (result.event_enable & 0x08) ? "+" : "-" ); + len += sprintf(buf+len, " [%s] Change back to normal from out of range state. \n", + (result.event_enable & 0x10) ? "+" : "-" ); + len += sprintf(buf+len, " [%s] High warning. \n", + (result.event_enable & 0x20) ? "+" : "-" ); + len += sprintf(buf+len, " [%s] High reading. \n", + (result.event_enable & 0x40) ? "+" : "-" ); + len += sprintf(buf+len, " [%s] High catastrophic. \n", + (result.event_enable & 0x80) ? "+" : "-" ); + + spin_unlock(&i2o_proc_lock); + return len; +} + + +static int print_serial_number(char *buff, int pos, u8 *serialno, int max_len) +{ + int i; + + /* 19990419 -sralston + * The I2O v1.5 (and v2.0 so far) "official specification" + * got serial numbers WRONG! + * Apparently, and despite what Section 3.4.4 says and + * Figure 3-35 shows (pg 3-39 in the pdf doc), + * the convention / consensus seems to be: + * + First byte is SNFormat + * + Second byte is SNLen (but only if SNFormat==7 (?)) + * + (v2.0) SCSI+BS may use IEEE Registered (64 or 128 bit) format + */ + switch(serialno[0]) + { + case I2O_SNFORMAT_BINARY: /* Binary */ + pos += sprintf(buff+pos, "0x"); + for(i = 0; i < serialno[1]; i++) + { + pos += sprintf(buff+pos, "%02X", serialno[2+i]); + } + break; + + case I2O_SNFORMAT_ASCII: /* ASCII */ + if ( serialno[1] < ' ' ) /* printable or SNLen? */ + { + /* sanity */ + max_len = (max_len < serialno[1]) ? max_len : serialno[1]; + serialno[1+max_len] = '\0'; + + /* just print it */ + pos += sprintf(buff+pos, "%s", &serialno[2]); + } + else + { + /* print chars for specified length */ + for(i = 0; i < serialno[1]; i++) + { + pos += sprintf(buff+pos, "%c", serialno[2+i]); + } + } + break; + + case I2O_SNFORMAT_UNICODE: /* UNICODE */ + pos += sprintf(buff+pos, "UNICODE Format. Can't Display\n"); + break; + + case I2O_SNFORMAT_LAN48_MAC: /* LAN-48 MAC Address */ + pos += sprintf(buff+pos, + "LAN-48 MAC address @ %02X:%02X:%02X:%02X:%02X:%02X", + serialno[2], serialno[3], + serialno[4], serialno[5], + serialno[6], serialno[7]); + break; + + case I2O_SNFORMAT_WAN: /* WAN MAC Address */ + /* FIXME: Figure out what a WAN access address looks like?? */ + pos += sprintf(buff+pos, "WAN Access Address"); + break; + +/* plus new in v2.0 */ + case I2O_SNFORMAT_LAN64_MAC: /* LAN-64 MAC Address */ + /* FIXME: Figure out what a LAN-64 address really looks like?? */ + pos += sprintf(buff+pos, + "LAN-64 MAC address @ [?:%02X:%02X:?] %02X:%02X:%02X:%02X:%02X:%02X", + serialno[8], serialno[9], + serialno[2], serialno[3], + serialno[4], serialno[5], + serialno[6], serialno[7]); + break; + + + case I2O_SNFORMAT_DDM: /* I2O DDM */ + pos += sprintf(buff+pos, + "DDM: Tid=%03Xh, Rsvd=%04Xh, OrgId=%04Xh", + *(u16*)&serialno[2], + *(u16*)&serialno[4], + *(u16*)&serialno[6]); + break; + + case I2O_SNFORMAT_IEEE_REG64: /* IEEE Registered (64-bit) */ + case I2O_SNFORMAT_IEEE_REG128: /* IEEE Registered (128-bit) */ + /* FIXME: Figure if this is even close?? */ + pos += sprintf(buff+pos, + "IEEE NodeName(hi,lo)=(%08Xh:%08Xh), PortName(hi,lo)=(%08Xh:%08Xh)\n", + *(u32*)&serialno[2], + *(u32*)&serialno[6], + *(u32*)&serialno[10], + *(u32*)&serialno[14]); + break; + + + case I2O_SNFORMAT_UNKNOWN: /* Unknown 0 */ + case I2O_SNFORMAT_UNKNOWN2: /* Unknown 0xff */ + default: + pos += sprintf(buff+pos, "Unknown data format (0x%02x)", + serialno[0]); + break; + } + + return pos; +} + +const char * i2o_get_connector_type(int conn) +{ + int idx = 16; + static char *i2o_connector_type[] = { + "OTHER", + "UNKNOWN", + "AUI", + "UTP", + "BNC", + "RJ45", + "STP DB9", + "FIBER MIC", + "APPLE AUI", + "MII", + "DB9", + "HSSDC", + "DUPLEX SC FIBER", + "DUPLEX ST FIBER", + "TNC/BNC", + "HW DEFAULT" + }; + + switch(conn) + { + case 0x00000000: + idx = 0; + break; + case 0x00000001: + idx = 1; + break; + case 0x00000002: + idx = 2; + break; + case 0x00000003: + idx = 3; + break; + case 0x00000004: + idx = 4; + break; + case 0x00000005: + idx = 5; + break; + case 0x00000006: + idx = 6; + break; + case 0x00000007: + idx = 7; + break; + case 0x00000008: + idx = 8; + break; + case 0x00000009: + idx = 9; + break; + case 0x0000000A: + idx = 10; + break; + case 0x0000000B: + idx = 11; + break; + case 0x0000000C: + idx = 12; + break; + case 0x0000000D: + idx = 13; + break; + case 0x0000000E: + idx = 14; + break; + case 0xFFFFFFFF: + idx = 15; + break; + } + + return i2o_connector_type[idx]; +} + + +const char * i2o_get_connection_type(int conn) +{ + int idx = 0; + static char *i2o_connection_type[] = { + "Unknown", + "AUI", + "10BASE5", + "FIORL", + "10BASE2", + "10BROAD36", + "10BASE-T", + "10BASE-FP", + "10BASE-FB", + "10BASE-FL", + "100BASE-TX", + "100BASE-FX", + "100BASE-T4", + "1000BASE-SX", + "1000BASE-LX", + "1000BASE-CX", + "1000BASE-T", + "100VG-ETHERNET", + "100VG-TOKEN RING", + "4MBIT TOKEN RING", + "16 Mb Token Ring", + "125 MBAUD FDDI", + "Point-to-point", + "Arbitrated loop", + "Public loop", + "Fabric", + "Emulation", + "Other", + "HW default" + }; + + switch(conn) + { + case I2O_LAN_UNKNOWN: + idx = 0; + break; + case I2O_LAN_AUI: + idx = 1; + break; + case I2O_LAN_10BASE5: + idx = 2; + break; + case I2O_LAN_FIORL: + idx = 3; + break; + case I2O_LAN_10BASE2: + idx = 4; + break; + case I2O_LAN_10BROAD36: + idx = 5; + break; + case I2O_LAN_10BASE_T: + idx = 6; + break; + case I2O_LAN_10BASE_FP: + idx = 7; + break; + case I2O_LAN_10BASE_FB: + idx = 8; + break; + case I2O_LAN_10BASE_FL: + idx = 9; + break; + case I2O_LAN_100BASE_TX: + idx = 10; + break; + case I2O_LAN_100BASE_FX: + idx = 11; + break; + case I2O_LAN_100BASE_T4: + idx = 12; + break; + case I2O_LAN_1000BASE_SX: + idx = 13; + break; + case I2O_LAN_1000BASE_LX: + idx = 14; + break; + case I2O_LAN_1000BASE_CX: + idx = 15; + break; + case I2O_LAN_1000BASE_T: + idx = 16; + break; + case I2O_LAN_100VG_ETHERNET: + idx = 17; + break; + case I2O_LAN_100VG_TR: + idx = 18; + break; + case I2O_LAN_4MBIT: + idx = 19; + break; + case I2O_LAN_16MBIT: + idx = 20; + break; + case I2O_LAN_125MBAUD: + idx = 21; + break; + case I2O_LAN_POINT_POINT: + idx = 22; + break; + case I2O_LAN_ARB_LOOP: + idx = 23; + break; + case I2O_LAN_PUBLIC_LOOP: + idx = 24; + break; + case I2O_LAN_FABRIC: + idx = 25; + break; + case I2O_LAN_EMULATION: + idx = 26; + break; + case I2O_LAN_OTHER: + idx = 27; + break; + case I2O_LAN_DEFAULT: + idx = 28; + break; + } + + return i2o_connection_type[idx]; +} + + +/* LAN group 0000h - Device info (scalar) */ +int i2o_proc_read_lan_dev_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u32 work32[56]; + static u8 *work8 = (u8*)work32; + static u16 *work16 = (u16*)work32; + static u64 *work64 = (u64*)work32; + int token; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0x0000, -1, &work32, 56*4); + if (token < 0) { + len += i2o_report_query_status(buf+len, token, "0x0000 LAN Device Info"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "LAN Type : "); + switch (work16[0]) + { + case 0x0030: + len += sprintf(buf+len, "Ethernet, "); + break; + case 0x0040: + len += sprintf(buf+len, "100Base VG, "); + break; + case 0x0050: + len += sprintf(buf+len, "Token Ring, "); + break; + case 0x0060: + len += sprintf(buf+len, "FDDI, "); + break; + case 0x0070: + len += sprintf(buf+len, "Fibre Channel, "); + break; + default: + len += sprintf(buf+len, "Unknown type (0x%04x), ", work16[0]); + break; + } + + if (work16[1]&0x00000001) + len += sprintf(buf+len, "emulated LAN, "); + else + len += sprintf(buf+len, "physical LAN port, "); + + if (work16[1]&0x00000002) + len += sprintf(buf+len, "full duplex\n"); + else + len += sprintf(buf+len, "simplex\n"); + + len += sprintf(buf+len, "Address format : "); + switch(work8[4]) { + case 0x00: + len += sprintf(buf+len, "IEEE 48bit\n"); + break; + case 0x01: + len += sprintf(buf+len, "FC IEEE\n"); + break; + default: + len += sprintf(buf+len, "Unknown (0x%02x)\n", work8[4]); + break; + } + + len += sprintf(buf+len, "State : "); + switch(work8[5]) + { + case 0x00: + len += sprintf(buf+len, "Unknown\n"); + break; + case 0x01: + len += sprintf(buf+len, "Unclaimed\n"); + break; + case 0x02: + len += sprintf(buf+len, "Operational\n"); + break; + case 0x03: + len += sprintf(buf+len, "Suspended\n"); + break; + case 0x04: + len += sprintf(buf+len, "Resetting\n"); + break; + case 0x05: + len += sprintf(buf+len, "ERROR: "); + if(work16[3]&0x0001) + len += sprintf(buf+len, "TxCU inoperative "); + if(work16[3]&0x0002) + len += sprintf(buf+len, "RxCU inoperative "); + if(work16[3]&0x0004) + len += sprintf(buf+len, "Local mem alloc "); + len += sprintf(buf+len, "\n"); + break; + case 0x06: + len += sprintf(buf+len, "Operational no Rx\n"); + break; + case 0x07: + len += sprintf(buf+len, "Suspended no Rx\n"); + break; + default: + len += sprintf(buf+len, "Unspecified\n"); + break; + } + + len += sprintf(buf+len, "Min packet size : %d\n", work32[2]); + len += sprintf(buf+len, "Max packet size : %d\n", work32[3]); + len += sprintf(buf+len, "HW address : " + "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + work8[16],work8[17],work8[18],work8[19], + work8[20],work8[21],work8[22],work8[23]); + + len += sprintf(buf+len, "Max Tx wire speed : %d bps\n", (int)work64[3]); + len += sprintf(buf+len, "Max Rx wire speed : %d bps\n", (int)work64[4]); + + len += sprintf(buf+len, "Min SDU packet size : 0x%08x\n", work32[10]); + len += sprintf(buf+len, "Max SDU packet size : 0x%08x\n", work32[11]); + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* LAN group 0001h - MAC address table (scalar) */ +int i2o_proc_read_lan_mac_addr(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u32 work32[48]; + static u8 *work8 = (u8*)work32; + int token; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0x0001, -1, &work32, 48*4); + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0x0001 LAN MAC Address"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Active address : " + "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + work8[0],work8[1],work8[2],work8[3], + work8[4],work8[5],work8[6],work8[7]); + len += sprintf(buf+len, "Current address : " + "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + work8[8],work8[9],work8[10],work8[11], + work8[12],work8[13],work8[14],work8[15]); + len += sprintf(buf+len, "Functional address mask : " + "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + work8[16],work8[17],work8[18],work8[19], + work8[20],work8[21],work8[22],work8[23]); + + len += sprintf(buf+len,"HW/DDM capabilities : 0x%08x\n", work32[7]); + len += sprintf(buf+len," [%s] Unicast packets supported\n", + (work32[7]&0x00000001)?"+":"-"); + len += sprintf(buf+len," [%s] Promiscuous mode supported\n", + (work32[7]&0x00000002)?"+":"-"); + len += sprintf(buf+len," [%s] Promiscuous multicast mode supported\n", + (work32[7]&0x00000004)?"+":"-"); + len += sprintf(buf+len," [%s] Broadcast reception disabling supported\n", + (work32[7]&0x00000100)?"+":"-"); + len += sprintf(buf+len," [%s] Multicast reception disabling supported\n", + (work32[7]&0x00000200)?"+":"-"); + len += sprintf(buf+len," [%s] Functional address disabling supported\n", + (work32[7]&0x00000400)?"+":"-"); + len += sprintf(buf+len," [%s] MAC reporting supported\n", + (work32[7]&0x00000800)?"+":"-"); + + len += sprintf(buf+len,"Filter mask : 0x%08x\n", work32[6]); + len += sprintf(buf+len," [%s] Unicast packets disable\n", + (work32[6]&0x00000001)?"+":"-"); + len += sprintf(buf+len," [%s] Promiscuous mode enable\n", + (work32[6]&0x00000002)?"+":"-"); + len += sprintf(buf+len," [%s] Promiscuous multicast mode enable\n", + (work32[6]&0x00000004)?"+":"-"); + len += sprintf(buf+len," [%s] Broadcast packets disable\n", + (work32[6]&0x00000100)?"+":"-"); + len += sprintf(buf+len," [%s] Multicast packets disable\n", + (work32[6]&0x00000200)?"+":"-"); + len += sprintf(buf+len," [%s] Functional address disable\n", + (work32[6]&0x00000400)?"+":"-"); + + if (work32[7]&0x00000800) { + len += sprintf(buf+len, " MAC reporting mode : "); + if (work32[6]&0x00000800) + len += sprintf(buf+len, "Pass only priority MAC packets to user\n"); + else if (work32[6]&0x00001000) + len += sprintf(buf+len, "Pass all MAC packets to user\n"); + else if (work32[6]&0x00001800) + len += sprintf(buf+len, "Pass all MAC packets (promiscuous) to user\n"); + else + len += sprintf(buf+len, "Do not pass MAC packets to user\n"); + } + len += sprintf(buf+len, "Number of multicast addresses : %d\n", work32[8]); + len += sprintf(buf+len, "Perfect filtering for max %d multicast addresses\n", + work32[9]); + len += sprintf(buf+len, "Imperfect filtering for max %d multicast addresses\n", + work32[10]); + + spin_unlock(&i2o_proc_lock); + + return len; +} + +/* LAN group 0002h - Multicast MAC address table (table) */ +int i2o_proc_read_lan_mcast_addr(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + int token; + int i; + u8 mc_addr[8]; + + struct + { + u16 result_count; + u16 pad; + u16 block_size; + u8 block_status; + u8 error_info_size; + u16 row_count; + u16 more_flag; + u8 mc_addr[256][8]; + } result; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_table(I2O_PARAMS_TABLE_GET, + d->controller, d->lct_data.tid, 0x0002, -1, + NULL, 0, &result, sizeof(result)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0x002 LAN Multicast MAC Address"); + spin_unlock(&i2o_proc_lock); + return len; + } + + for (i = 0; i < result.row_count; i++) + { + memcpy(mc_addr, result.mc_addr[i], 8); + + len += sprintf(buf+len, "MC MAC address[%d]: " + "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + i, mc_addr[0], mc_addr[1], mc_addr[2], + mc_addr[3], mc_addr[4], mc_addr[5], + mc_addr[6], mc_addr[7]); + } + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* LAN group 0003h - Batch Control (scalar) */ +int i2o_proc_read_lan_batch_control(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u32 work32[9]; + int token; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0x0003, -1, &work32, 9*4); + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0x0003 LAN Batch Control"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Batch mode "); + if (work32[0]&0x00000001) + len += sprintf(buf+len, "disabled"); + else + len += sprintf(buf+len, "enabled"); + if (work32[0]&0x00000002) + len += sprintf(buf+len, " (current setting)"); + if (work32[0]&0x00000004) + len += sprintf(buf+len, ", forced"); + else + len += sprintf(buf+len, ", toggle"); + len += sprintf(buf+len, "\n"); + + len += sprintf(buf+len, "Max Rx batch count : %d\n", work32[5]); + len += sprintf(buf+len, "Max Rx batch delay : %d\n", work32[6]); + len += sprintf(buf+len, "Max Tx batch delay : %d\n", work32[7]); + len += sprintf(buf+len, "Max Tx batch count : %d\n", work32[8]); + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* LAN group 0004h - LAN Operation (scalar) */ +int i2o_proc_read_lan_operation(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u32 work32[5]; + int token; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0x0004, -1, &work32, 20); + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0x0004 LAN Operation"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Packet prepadding (32b words) : %d\n", work32[0]); + len += sprintf(buf+len, "Transmission error reporting : %s\n", + (work32[1]&1)?"on":"off"); + len += sprintf(buf+len, "Bad packet handling : %s\n", + (work32[1]&0x2)?"by host":"by DDM"); + len += sprintf(buf+len, "Packet orphan limit : %d\n", work32[2]); + + len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[3]); + len += sprintf(buf+len, " [%s] HW CRC suppression\n", + (work32[3]&0x00000004) ? "+" : "-"); + len += sprintf(buf+len, " [%s] HW IPv4 checksum\n", + (work32[3]&0x00000100) ? "+" : "-"); + len += sprintf(buf+len, " [%s] HW TCP checksum\n", + (work32[3]&0x00000200) ? "+" : "-"); + len += sprintf(buf+len, " [%s] HW UDP checksum\n", + (work32[3]&0x00000400) ? "+" : "-"); + len += sprintf(buf+len, " [%s] HW RSVP checksum\n", + (work32[3]&0x00000800) ? "+" : "-"); + len += sprintf(buf+len, " [%s] HW ICMP checksum\n", + (work32[3]&0x00001000) ? "+" : "-"); + len += sprintf(buf+len, " [%s] Loopback suppression enable\n", + (work32[3]&0x00002000) ? "+" : "-"); + + len += sprintf(buf+len, "Rx modes : 0x%08x\n", work32[4]); + len += sprintf(buf+len, " [%s] FCS in payload\n", + (work32[4]&0x00000004) ? "+" : "-"); + len += sprintf(buf+len, " [%s] HW IPv4 checksum validation\n", + (work32[4]&0x00000100) ? "+" : "-"); + len += sprintf(buf+len, " [%s] HW TCP checksum validation\n", + (work32[4]&0x00000200) ? "+" : "-"); + len += sprintf(buf+len, " [%s] HW UDP checksum validation\n", + (work32[4]&0x00000400) ? "+" : "-"); + len += sprintf(buf+len, " [%s] HW RSVP checksum validation\n", + (work32[4]&0x00000800) ? "+" : "-"); + len += sprintf(buf+len, " [%s] HW ICMP checksum validation\n", + (work32[4]&0x00001000) ? "+" : "-"); + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* LAN group 0005h - Media operation (scalar) */ +int i2o_proc_read_lan_media_operation(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + int token; + + struct + { + u32 connector_type; + u32 connection_type; + u64 current_tx_wire_speed; + u64 current_rx_wire_speed; + u8 duplex_mode; + u8 link_status; + u8 reserved; + u8 duplex_mode_target; + u32 connector_type_target; + u32 connection_type_target; + } result; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0x0005, -1, &result, sizeof(result)); + if (token < 0) { + len += i2o_report_query_status(buf+len, token, "0x0005 LAN Media Operation"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Connector type : %s\n", + i2o_get_connector_type(result.connector_type)); + len += sprintf(buf+len, "Connection type : %s\n", + i2o_get_connection_type(result.connection_type)); + + len += sprintf(buf+len, "Current Tx wire speed : %d bps\n", (int)result.current_tx_wire_speed); + len += sprintf(buf+len, "Current Rx wire speed : %d bps\n", (int)result.current_rx_wire_speed); + len += sprintf(buf+len, "Duplex mode : %s duplex\n", + (result.duplex_mode)?"Full":"Half"); + + len += sprintf(buf+len, "Link status : "); + switch (result.link_status) + { + case 0x00: + len += sprintf(buf+len, "Unknown\n"); + break; + case 0x01: + len += sprintf(buf+len, "Normal\n"); + break; + case 0x02: + len += sprintf(buf+len, "Failure\n"); + break; + case 0x03: + len += sprintf(buf+len, "Reset\n"); + break; + default: + len += sprintf(buf+len, "Unspecified\n"); + } + + len += sprintf(buf+len, "Duplex mode target : "); + switch (result.duplex_mode_target){ + case 0: + len += sprintf(buf+len, "Half duplex\n"); + break; + case 1: + len += sprintf(buf+len, "Full duplex\n"); + break; + default: + len += sprintf(buf+len, "\n"); + } + + len += sprintf(buf+len, "Connector type target : %s\n", + i2o_get_connector_type(result.connector_type_target)); + len += sprintf(buf+len, "Connection type target : %s\n", + i2o_get_connection_type(result.connection_type_target)); + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* LAN group 0006h - Alternate address (table) (optional) */ +int i2o_proc_read_lan_alt_addr(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + int token; + int i; + u8 alt_addr[8]; + struct + { + u16 result_count; + u16 pad; + u16 block_size; + u8 block_status; + u8 error_info_size; + u16 row_count; + u16 more_flag; + u8 alt_addr[256][8]; + } result; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_table(I2O_PARAMS_TABLE_GET, + d->controller, d->lct_data.tid, + 0x0006, -1, NULL, 0, &result, sizeof(result)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token, "0x0006 LAN Alternate Address (optional)"); + spin_unlock(&i2o_proc_lock); + return len; + } + + for (i=0; i < result.row_count; i++) + { + memcpy(alt_addr,result.alt_addr[i],8); + len += sprintf(buf+len, "Alternate address[%d]: " + "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + i, alt_addr[0], alt_addr[1], alt_addr[2], + alt_addr[3], alt_addr[4], alt_addr[5], + alt_addr[6], alt_addr[7]); + } + + spin_unlock(&i2o_proc_lock); + return len; +} + + +/* LAN group 0007h - Transmit info (scalar) */ +int i2o_proc_read_lan_tx_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u32 work32[8]; + int token; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0x0007, -1, &work32, 8*4); + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0x0007 LAN Transmit Info"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Tx Max SG elements per packet : %d\n", work32[0]); + len += sprintf(buf+len, "Tx Max SG elements per chain : %d\n", work32[1]); + len += sprintf(buf+len, "Tx Max outstanding packets : %d\n", work32[2]); + len += sprintf(buf+len, "Tx Max packets per request : %d\n", work32[3]); + + len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[4]); + len += sprintf(buf+len, " [%s] No DA in SGL\n", + (work32[4]&0x00000002) ? "+" : "-"); + len += sprintf(buf+len, " [%s] CRC suppression\n", + (work32[4]&0x00000004) ? "+" : "-"); + len += sprintf(buf+len, " [%s] MAC insertion\n", + (work32[4]&0x00000010) ? "+" : "-"); + len += sprintf(buf+len, " [%s] RIF insertion\n", + (work32[4]&0x00000020) ? "+" : "-"); + len += sprintf(buf+len, " [%s] IPv4 checksum generation\n", + (work32[4]&0x00000100) ? "+" : "-"); + len += sprintf(buf+len, " [%s] TCP checksum generation\n", + (work32[4]&0x00000200) ? "+" : "-"); + len += sprintf(buf+len, " [%s] UDP checksum generation\n", + (work32[4]&0x00000400) ? "+" : "-"); + len += sprintf(buf+len, " [%s] RSVP checksum generation\n", + (work32[4]&0x00000800) ? "+" : "-"); + len += sprintf(buf+len, " [%s] ICMP checksum generation\n", + (work32[4]&0x00001000) ? "+" : "-"); + len += sprintf(buf+len, " [%s] Loopback enabled\n", + (work32[4]&0x00010000) ? "+" : "-"); + len += sprintf(buf+len, " [%s] Loopback suppression enabled\n", + (work32[4]&0x00020000) ? "+" : "-"); + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* LAN group 0008h - Receive info (scalar) */ +int i2o_proc_read_lan_rx_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u32 work32[8]; + int token; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0x0008, -1, &work32, 8*4); + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0x0008 LAN Receive Info"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf ,"Rx Max size of chain element : %d\n", work32[0]); + len += sprintf(buf+len, "Rx Max Buckets : %d\n", work32[1]); + len += sprintf(buf+len, "Rx Max Buckets in Reply : %d\n", work32[3]); + len += sprintf(buf+len, "Rx Max Packets in Bucket : %d\n", work32[4]); + len += sprintf(buf+len, "Rx Max Buckets in Post : %d\n", work32[5]); + + len += sprintf(buf+len, "Rx Modes : 0x%08x\n", work32[2]); + len += sprintf(buf+len, " [%s] FCS reception\n", + (work32[2]&0x00000004) ? "+" : "-"); + len += sprintf(buf+len, " [%s] IPv4 checksum validation \n", + (work32[2]&0x00000100) ? "+" : "-"); + len += sprintf(buf+len, " [%s] TCP checksum validation \n", + (work32[2]&0x00000200) ? "+" : "-"); + len += sprintf(buf+len, " [%s] UDP checksum validation \n", + (work32[2]&0x00000400) ? "+" : "-"); + len += sprintf(buf+len, " [%s] RSVP checksum validation \n", + (work32[2]&0x00000800) ? "+" : "-"); + len += sprintf(buf+len, " [%s] ICMP checksum validation \n", + (work32[2]&0x00001000) ? "+" : "-"); + + spin_unlock(&i2o_proc_lock); + return len; +} + +static int i2o_report_opt_field(char *buf, char *field_name, + int field_nbr, int supp_fields, u64 *value) +{ + if (supp_fields & (1 << field_nbr)) + return sprintf(buf, "%-24s : " FMT_U64_HEX "\n", field_name, U64_VAL(value)); + else + return sprintf(buf, "%-24s : Not supported\n", field_name); +} + +/* LAN group 0100h - LAN Historical statistics (scalar) */ +/* LAN group 0180h - Supported Optional Historical Statistics (scalar) */ +/* LAN group 0182h - Optional Non Media Specific Transmit Historical Statistics (scalar) */ +/* LAN group 0183h - Optional Non Media Specific Receive Historical Statistics (scalar) */ + +int i2o_proc_read_lan_hist_stats(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + int token; + + struct + { + u64 tx_packets; + u64 tx_bytes; + u64 rx_packets; + u64 rx_bytes; + u64 tx_errors; + u64 rx_errors; + u64 rx_dropped; + u64 adapter_resets; + u64 adapter_suspends; + } stats; // 0x0100 + + static u64 supp_groups[4]; // 0x0180 + + struct + { + u64 tx_retries; + u64 tx_directed_bytes; + u64 tx_directed_packets; + u64 tx_multicast_bytes; + u64 tx_multicast_packets; + u64 tx_broadcast_bytes; + u64 tx_broadcast_packets; + u64 tx_group_addr_packets; + u64 tx_short_packets; + } tx_stats; // 0x0182 + + struct + { + u64 rx_crc_errors; + u64 rx_directed_bytes; + u64 rx_directed_packets; + u64 rx_multicast_bytes; + u64 rx_multicast_packets; + u64 rx_broadcast_bytes; + u64 rx_broadcast_packets; + u64 rx_group_addr_packets; + u64 rx_short_packets; + u64 rx_long_packets; + u64 rx_runt_packets; + } rx_stats; // 0x0183 + + struct + { + u64 ipv4_generate; + u64 ipv4_validate_success; + u64 ipv4_validate_errors; + u64 tcp_generate; + u64 tcp_validate_success; + u64 tcp_validate_errors; + u64 udp_generate; + u64 udp_validate_success; + u64 udp_validate_errors; + u64 rsvp_generate; + u64 rsvp_validate_success; + u64 rsvp_validate_errors; + u64 icmp_generate; + u64 icmp_validate_success; + u64 icmp_validate_errors; + } chksum_stats; // 0x0184 + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0x0100, -1, &stats, sizeof(stats)); + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0x100 LAN Statistics"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf+len, "Tx packets : " FMT_U64_HEX "\n", + U64_VAL(&stats.tx_packets)); + len += sprintf(buf+len, "Tx bytes : " FMT_U64_HEX "\n", + U64_VAL(&stats.tx_bytes)); + len += sprintf(buf+len, "Rx packets : " FMT_U64_HEX "\n", + U64_VAL(&stats.rx_packets)); + len += sprintf(buf+len, "Rx bytes : " FMT_U64_HEX "\n", + U64_VAL(&stats.rx_bytes)); + len += sprintf(buf+len, "Tx errors : " FMT_U64_HEX "\n", + U64_VAL(&stats.tx_errors)); + len += sprintf(buf+len, "Rx errors : " FMT_U64_HEX "\n", + U64_VAL(&stats.rx_errors)); + len += sprintf(buf+len, "Rx dropped : " FMT_U64_HEX "\n", + U64_VAL(&stats.rx_dropped)); + len += sprintf(buf+len, "Adapter resets : " FMT_U64_HEX "\n", + U64_VAL(&stats.adapter_resets)); + len += sprintf(buf+len, "Adapter suspends : " FMT_U64_HEX "\n", + U64_VAL(&stats.adapter_suspends)); + + /* Optional statistics follows */ + /* Get 0x0180 to see which optional groups/fields are supported */ + + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0x0180, -1, &supp_groups, sizeof(supp_groups)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token, "0x180 LAN Supported Optional Statistics"); + spin_unlock(&i2o_proc_lock); + return len; + } + + if (supp_groups[1]) /* 0x0182 */ + { + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0x0182, -1, &tx_stats, sizeof(tx_stats)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0x182 LAN Optional Tx Historical Statistics"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf+len, "==== Optional TX statistics (group 0182h)\n"); + + len += i2o_report_opt_field(buf+len, "Tx RetryCount", + 0, supp_groups[1], &tx_stats.tx_retries); + len += i2o_report_opt_field(buf+len, "Tx DirectedBytes", + 1, supp_groups[1], &tx_stats.tx_directed_bytes); + len += i2o_report_opt_field(buf+len, "Tx DirectedPackets", + 2, supp_groups[1], &tx_stats.tx_directed_packets); + len += i2o_report_opt_field(buf+len, "Tx MulticastBytes", + 3, supp_groups[1], &tx_stats.tx_multicast_bytes); + len += i2o_report_opt_field(buf+len, "Tx MulticastPackets", + 4, supp_groups[1], &tx_stats.tx_multicast_packets); + len += i2o_report_opt_field(buf+len, "Tx BroadcastBytes", + 5, supp_groups[1], &tx_stats.tx_broadcast_bytes); + len += i2o_report_opt_field(buf+len, "Tx BroadcastPackets", + 6, supp_groups[1], &tx_stats.tx_broadcast_packets); + len += i2o_report_opt_field(buf+len, "Tx TotalGroupAddrPackets", + 7, supp_groups[1], &tx_stats.tx_group_addr_packets); + len += i2o_report_opt_field(buf+len, "Tx TotalPacketsTooShort", + 8, supp_groups[1], &tx_stats.tx_short_packets); + } + + if (supp_groups[2]) /* 0x0183 */ + { + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0x0183, -1, &rx_stats, sizeof(rx_stats)); + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0x183 LAN Optional Rx Historical Stats"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf+len, "==== Optional RX statistics (group 0183h)\n"); + + len += i2o_report_opt_field(buf+len, "Rx CRCErrorCount", + 0, supp_groups[2], &rx_stats.rx_crc_errors); + len += i2o_report_opt_field(buf+len, "Rx DirectedBytes", + 1, supp_groups[2], &rx_stats.rx_directed_bytes); + len += i2o_report_opt_field(buf+len, "Rx DirectedPackets", + 2, supp_groups[2], &rx_stats.rx_directed_packets); + len += i2o_report_opt_field(buf+len, "Rx MulticastBytes", + 3, supp_groups[2], &rx_stats.rx_multicast_bytes); + len += i2o_report_opt_field(buf+len, "Rx MulticastPackets", + 4, supp_groups[2], &rx_stats.rx_multicast_packets); + len += i2o_report_opt_field(buf+len, "Rx BroadcastBytes", + 5, supp_groups[2], &rx_stats.rx_broadcast_bytes); + len += i2o_report_opt_field(buf+len, "Rx BroadcastPackets", + 6, supp_groups[2], &rx_stats.rx_broadcast_packets); + len += i2o_report_opt_field(buf+len, "Rx TotalGroupAddrPackets", + 7, supp_groups[2], &rx_stats.rx_group_addr_packets); + len += i2o_report_opt_field(buf+len, "Rx TotalPacketsTooShort", + 8, supp_groups[2], &rx_stats.rx_short_packets); + len += i2o_report_opt_field(buf+len, "Rx TotalPacketsTooLong", + 9, supp_groups[2], &rx_stats.rx_long_packets); + len += i2o_report_opt_field(buf+len, "Rx TotalPacketsRunt", + 10, supp_groups[2], &rx_stats.rx_runt_packets); + } + + if (supp_groups[3]) /* 0x0184 */ + { + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0x0184, -1, &chksum_stats, sizeof(chksum_stats)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0x184 LAN Optional Chksum Historical Stats"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf+len, "==== Optional CHKSUM statistics (group 0x0184)\n"); + + len += i2o_report_opt_field(buf+len, "IPv4 Generate", + 0, supp_groups[3], &chksum_stats.ipv4_generate); + len += i2o_report_opt_field(buf+len, "IPv4 ValidateSuccess", + 1, supp_groups[3], &chksum_stats.ipv4_validate_success); + len += i2o_report_opt_field(buf+len, "IPv4 ValidateError", + 2, supp_groups[3], &chksum_stats.ipv4_validate_errors); + len += i2o_report_opt_field(buf+len, "TCP Generate", + 3, supp_groups[3], &chksum_stats.tcp_generate); + len += i2o_report_opt_field(buf+len, "TCP ValidateSuccess", + 4, supp_groups[3], &chksum_stats.tcp_validate_success); + len += i2o_report_opt_field(buf+len, "TCP ValidateError", + 5, supp_groups[3], &chksum_stats.tcp_validate_errors); + len += i2o_report_opt_field(buf+len, "UDP Generate", + 6, supp_groups[3], &chksum_stats.udp_generate); + len += i2o_report_opt_field(buf+len, "UDP ValidateSuccess", + 7, supp_groups[3], &chksum_stats.udp_validate_success); + len += i2o_report_opt_field(buf+len, "UDP ValidateError", + 8, supp_groups[3], &chksum_stats.udp_validate_errors); + len += i2o_report_opt_field(buf+len, "RSVP Generate", + 9, supp_groups[3], &chksum_stats.rsvp_generate); + len += i2o_report_opt_field(buf+len, "RSVP ValidateSuccess", + 10, supp_groups[3], &chksum_stats.rsvp_validate_success); + len += i2o_report_opt_field(buf+len, "RSVP ValidateError", + 11, supp_groups[3], &chksum_stats.rsvp_validate_errors); + len += i2o_report_opt_field(buf+len, "ICMP Generate", + 12, supp_groups[3], &chksum_stats.icmp_generate); + len += i2o_report_opt_field(buf+len, "ICMP ValidateSuccess", + 13, supp_groups[3], &chksum_stats.icmp_validate_success); + len += i2o_report_opt_field(buf+len, "ICMP ValidateError", + 14, supp_groups[3], &chksum_stats.icmp_validate_errors); + } + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* LAN group 0200h - Required Ethernet Statistics (scalar) */ +/* LAN group 0280h - Optional Ethernet Statistics Supported (scalar) */ +/* LAN group 0281h - Optional Ethernet Historical Statistics (scalar) */ +int i2o_proc_read_lan_eth_stats(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + int token; + + struct + { + u64 rx_align_errors; + u64 tx_one_collisions; + u64 tx_multiple_collisions; + u64 tx_deferred; + u64 tx_late_collisions; + u64 tx_max_collisions; + u64 tx_carrier_lost; + u64 tx_excessive_deferrals; + } stats; + + static u64 supp_fields; + struct + { + u64 rx_overrun; + u64 tx_underrun; + u64 tx_heartbeat_failure; + } hist_stats; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0x0200, -1, &stats, sizeof(stats)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0x0200 LAN Ethernet Statistics"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf+len, "Rx alignment errors : " FMT_U64_HEX "\n", + U64_VAL(&stats.rx_align_errors)); + len += sprintf(buf+len, "Tx one collisions : " FMT_U64_HEX "\n", + U64_VAL(&stats.tx_one_collisions)); + len += sprintf(buf+len, "Tx multicollisions : " FMT_U64_HEX "\n", + U64_VAL(&stats.tx_multiple_collisions)); + len += sprintf(buf+len, "Tx deferred : " FMT_U64_HEX "\n", + U64_VAL(&stats.tx_deferred)); + len += sprintf(buf+len, "Tx late collisions : " FMT_U64_HEX "\n", + U64_VAL(&stats.tx_late_collisions)); + len += sprintf(buf+len, "Tx max collisions : " FMT_U64_HEX "\n", + U64_VAL(&stats.tx_max_collisions)); + len += sprintf(buf+len, "Tx carrier lost : " FMT_U64_HEX "\n", + U64_VAL(&stats.tx_carrier_lost)); + len += sprintf(buf+len, "Tx excessive deferrals : " FMT_U64_HEX "\n", + U64_VAL(&stats.tx_excessive_deferrals)); + + /* Optional Ethernet statistics follows */ + /* Get 0x0280 to see which optional fields are supported */ + + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0x0280, -1, &supp_fields, sizeof(supp_fields)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0x0280 LAN Supported Optional Ethernet Statistics"); + spin_unlock(&i2o_proc_lock); + return len; + } + + if (supp_fields) /* 0x0281 */ + { + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0x0281, -1, &stats, sizeof(stats)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0x0281 LAN Optional Ethernet Statistics"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf+len, "==== Optional ETHERNET statistics (group 0x0281)\n"); + + len += i2o_report_opt_field(buf+len, "Rx Overrun", + 0, supp_fields, &hist_stats.rx_overrun); + len += i2o_report_opt_field(buf+len, "Tx Underrun", + 1, supp_fields, &hist_stats.tx_underrun); + len += i2o_report_opt_field(buf+len, "Tx HeartbeatFailure", + 2, supp_fields, &hist_stats.tx_heartbeat_failure); + } + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* LAN group 0300h - Required Token Ring Statistics (scalar) */ +/* LAN group 0380h, 0381h - Optional Statistics not yet defined (TODO) */ +int i2o_proc_read_lan_tr_stats(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u64 work64[13]; + int token; + + static char *ring_status[] = + { + "", + "", + "", + "", + "", + "Ring Recovery", + "Single Station", + "Counter Overflow", + "Remove Received", + "", + "Auto-Removal Error 1", + "Lobe Wire Fault", + "Transmit Beacon", + "Soft Error", + "Hard Error", + "Signal Loss" + }; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0x0300, -1, &work64, sizeof(work64)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0x0300 Token Ring Statistics"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "LineErrors : " FMT_U64_HEX "\n", + U64_VAL(&work64[0])); + len += sprintf(buf+len, "LostFrames : " FMT_U64_HEX "\n", + U64_VAL(&work64[1])); + len += sprintf(buf+len, "ACError : " FMT_U64_HEX "\n", + U64_VAL(&work64[2])); + len += sprintf(buf+len, "TxAbortDelimiter : " FMT_U64_HEX "\n", + U64_VAL(&work64[3])); + len += sprintf(buf+len, "BursErrors : " FMT_U64_HEX "\n", + U64_VAL(&work64[4])); + len += sprintf(buf+len, "FrameCopiedErrors : " FMT_U64_HEX "\n", + U64_VAL(&work64[5])); + len += sprintf(buf+len, "FrequencyErrors : " FMT_U64_HEX "\n", + U64_VAL(&work64[6])); + len += sprintf(buf+len, "InternalErrors : " FMT_U64_HEX "\n", + U64_VAL(&work64[7])); + len += sprintf(buf+len, "LastRingStatus : %s\n", ring_status[work64[8]]); + len += sprintf(buf+len, "TokenError : " FMT_U64_HEX "\n", + U64_VAL(&work64[9])); + len += sprintf(buf+len, "UpstreamNodeAddress : " FMT_U64_HEX "\n", + U64_VAL(&work64[10])); + len += sprintf(buf+len, "LastRingID : " FMT_U64_HEX "\n", + U64_VAL(&work64[11])); + len += sprintf(buf+len, "LastBeaconType : " FMT_U64_HEX "\n", + U64_VAL(&work64[12])); + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* LAN group 0400h - Required FDDI Statistics (scalar) */ +/* LAN group 0480h, 0481h - Optional Statistics, not yet defined (TODO) */ +int i2o_proc_read_lan_fddi_stats(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u64 work64[11]; + int token; + + static char *conf_state[] = + { + "Isolated", + "Local a", + "Local b", + "Local ab", + "Local s", + "Wrap a", + "Wrap b", + "Wrap ab", + "Wrap s", + "C-Wrap a", + "C-Wrap b", + "C-Wrap s", + "Through", + }; + + static char *ring_state[] = + { + "Isolated", + "Non-op", + "Rind-op", + "Detect", + "Non-op-Dup", + "Ring-op-Dup", + "Directed", + "Trace" + }; + + static char *link_state[] = + { + "Off", + "Break", + "Trace", + "Connect", + "Next", + "Signal", + "Join", + "Verify", + "Active", + "Maintenance" + }; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->lct_data.tid, + 0x0400, -1, &work64, sizeof(work64)); + + if (token < 0) { + len += i2o_report_query_status(buf+len, token,"0x0400 FDDI Required Statistics"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf+len, "ConfigurationState : %s\n", conf_state[work64[0]]); + len += sprintf(buf+len, "UpstreamNode : " FMT_U64_HEX "\n", + U64_VAL(&work64[1])); + len += sprintf(buf+len, "DownStreamNode : " FMT_U64_HEX "\n", + U64_VAL(&work64[2])); + len += sprintf(buf+len, "FrameErrors : " FMT_U64_HEX "\n", + U64_VAL(&work64[3])); + len += sprintf(buf+len, "FramesLost : " FMT_U64_HEX "\n", + U64_VAL(&work64[4])); + len += sprintf(buf+len, "RingMgmtState : %s\n", ring_state[work64[5]]); + len += sprintf(buf+len, "LCTFailures : " FMT_U64_HEX "\n", + U64_VAL(&work64[6])); + len += sprintf(buf+len, "LEMRejects : " FMT_U64_HEX "\n", + U64_VAL(&work64[7])); + len += sprintf(buf+len, "LEMCount : " FMT_U64_HEX "\n", + U64_VAL(&work64[8])); + len += sprintf(buf+len, "LConnectionState : %s\n", + link_state[work64[9]]); + + spin_unlock(&i2o_proc_lock); + return len; +} + +static int i2o_proc_create_entries(void *data, i2o_proc_entry *pentry, + struct proc_dir_entry *parent) +{ + struct proc_dir_entry *ent; + + while(pentry->name != NULL) + { + ent = create_proc_entry(pentry->name, pentry->mode, parent); + if(!ent) return -1; + + ent->data = data; + ent->read_proc = pentry->read_proc; + ent->write_proc = pentry->write_proc; + ent->nlink = 1; + + pentry++; + } + + return 0; +} + +static void i2o_proc_remove_entries(i2o_proc_entry *pentry, + struct proc_dir_entry *parent) +{ + while(pentry->name != NULL) + { + remove_proc_entry(pentry->name, parent); + pentry++; + } +} + +static int i2o_proc_add_controller(struct i2o_controller *pctrl, + struct proc_dir_entry *root ) +{ + struct proc_dir_entry *dir, *dir1; + struct i2o_device *dev; + char buff[10]; + + sprintf(buff, "iop%d", pctrl->unit); + + dir = proc_mkdir(buff, root); + if(!dir) + return -1; + + pctrl->proc_entry = dir; + + i2o_proc_create_entries(pctrl, generic_iop_entries, dir); + + for(dev = pctrl->devices; dev; dev = dev->next) + { + sprintf(buff, "%0#5x", dev->lct_data.tid); + + dir1 = proc_mkdir(buff, dir); + dev->proc_entry = dir1; + + if(!dir1) + printk(KERN_INFO "i2o_proc: Could not allocate proc dir\n"); + + i2o_proc_add_device(dev, dir1); + } + + return 0; +} + +void i2o_proc_new_dev(struct i2o_controller *c, struct i2o_device *d) +{ + char buff[10]; + +#ifdef DRIVERDEBUG + printk(KERN_INFO "Adding new device to /proc/i2o/iop%d\n", c->unit); +#endif + sprintf(buff, "%0#5x", d->lct_data.tid); + + d->proc_entry = proc_mkdir(buff, c->proc_entry); + + if(!d->proc_entry) + { + printk(KERN_WARNING "i2o: Could not allocate procdir!\n"); + return; + } + + i2o_proc_add_device(d, d->proc_entry); +} + +void i2o_proc_add_device(struct i2o_device *dev, struct proc_dir_entry *dir) +{ + i2o_proc_create_entries(dev, generic_dev_entries, dir); + + /* Inform core that we want updates about this device's status */ + i2o_device_notify_on(dev, &i2o_proc_handler); + switch(dev->lct_data.class_id) + { + case I2O_CLASS_SCSI_PERIPHERAL: + case I2O_CLASS_RANDOM_BLOCK_STORAGE: + i2o_proc_create_entries(dev, rbs_dev_entries, dir); + break; + case I2O_CLASS_LAN: + i2o_proc_create_entries(dev, lan_entries, dir); + switch(dev->lct_data.sub_class) + { + case I2O_LAN_ETHERNET: + i2o_proc_create_entries(dev, lan_eth_entries, dir); + break; + case I2O_LAN_FDDI: + i2o_proc_create_entries(dev, lan_fddi_entries, dir); + break; + case I2O_LAN_TR: + i2o_proc_create_entries(dev, lan_tr_entries, dir); + break; + default: + break; + } + break; + default: + break; + } +} + +static void i2o_proc_remove_controller(struct i2o_controller *pctrl, + struct proc_dir_entry *parent) +{ + char buff[10]; + struct i2o_device *dev; + + /* Remove unused device entries */ + for(dev=pctrl->devices; dev; dev=dev->next) + i2o_proc_remove_device(dev); + + if(!atomic_read(&pctrl->proc_entry->count)) + { + sprintf(buff, "iop%d", pctrl->unit); + + i2o_proc_remove_entries(generic_iop_entries, pctrl->proc_entry); + + remove_proc_entry(buff, parent); + pctrl->proc_entry = NULL; + } +} + +void i2o_proc_remove_device(struct i2o_device *dev) +{ + struct proc_dir_entry *de=dev->proc_entry; + char dev_id[10]; + + sprintf(dev_id, "%0#5x", dev->lct_data.tid); + + i2o_device_notify_off(dev, &i2o_proc_handler); + /* Would it be safe to remove _files_ even if they are in use? */ + if((de) && (!atomic_read(&de->count))) + { + i2o_proc_remove_entries(generic_dev_entries, de); + switch(dev->lct_data.class_id) + { + case I2O_CLASS_SCSI_PERIPHERAL: + case I2O_CLASS_RANDOM_BLOCK_STORAGE: + i2o_proc_remove_entries(rbs_dev_entries, de); + break; + case I2O_CLASS_LAN: + { + i2o_proc_remove_entries(lan_entries, de); + switch(dev->lct_data.sub_class) + { + case I2O_LAN_ETHERNET: + i2o_proc_remove_entries(lan_eth_entries, de); + break; + case I2O_LAN_FDDI: + i2o_proc_remove_entries(lan_fddi_entries, de); + break; + case I2O_LAN_TR: + i2o_proc_remove_entries(lan_tr_entries, de); + break; + } + } + remove_proc_entry(dev_id, dev->controller->proc_entry); + } + } +} + +void i2o_proc_dev_del(struct i2o_controller *c, struct i2o_device *d) +{ +#ifdef DRIVERDEBUG + printk(KERN_INFO, "Deleting device %d from iop%d\n", + d->lct_data.tid, c->unit); +#endif + + i2o_proc_remove_device(d); +} + +static int create_i2o_procfs(void) +{ + struct i2o_controller *pctrl = NULL; + int i; + + i2o_proc_dir_root = proc_mkdir("i2o", 0); + if(!i2o_proc_dir_root) + return -1; + + for(i = 0; i < MAX_I2O_CONTROLLERS; i++) + { + pctrl = i2o_find_controller(i); + if(pctrl) + { + i2o_proc_add_controller(pctrl, i2o_proc_dir_root); + i2o_unlock_controller(pctrl); + } + }; + + return 0; +} + +static int __exit destroy_i2o_procfs(void) +{ + struct i2o_controller *pctrl = NULL; + int i; + + for(i = 0; i < MAX_I2O_CONTROLLERS; i++) + { + pctrl = i2o_find_controller(i); + if(pctrl) + { + i2o_proc_remove_controller(pctrl, i2o_proc_dir_root); + i2o_unlock_controller(pctrl); + } + } + + if(!atomic_read(&i2o_proc_dir_root->count)) + remove_proc_entry("i2o", 0); + else + return -1; + + return 0; +} + +int __init i2o_proc_init(void) +{ + if (i2o_install_handler(&i2o_proc_handler) < 0) + { + printk(KERN_ERR "i2o_proc: Unable to install PROC handler.\n"); + return 0; + } + + if(create_i2o_procfs()) + return -EBUSY; + + return 0; +} + +MODULE_AUTHOR("Deepak Saxena"); +MODULE_DESCRIPTION("I2O procfs Handler"); + +static void __exit i2o_proc_exit(void) +{ + destroy_i2o_procfs(); + i2o_remove_handler(&i2o_proc_handler); +} + +#ifdef MODULE +module_init(i2o_proc_init); +#endif +module_exit(i2o_proc_exit); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/i2o/i2o_scsi.c linux.ac/drivers/message/i2o/i2o_scsi.c --- linux.vanilla/drivers/message/i2o/i2o_scsi.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/i2o/i2o_scsi.c Tue Apr 3 17:54:48 2001 @@ -0,0 +1,911 @@ +/* + * 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. + * + * Complications for I2O scsi + * + * o Each (bus,lun) is a logical device in I2O. We keep a map + * table. We spoof failed selection for unmapped units + * o Request sense buffers can come back for free. + * o Scatter gather is a bit dynamic. We have to investigate at + * setup time. + * o Some of our resources are dynamically shared. The i2o core + * needs a message reservation protocol to avoid swap v net + * deadlocking. We need to back off queue requests. + * + * In general the firmware wants to help. Where its help isn't performance + * useful we just ignore the aid. Its not worth the code in truth. + * + * Fixes: + * Steve Ralston : Scatter gather now works + * + * To Do + * 64bit cleanups + * Fix the resource management problems. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/string.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/proc_fs.h> +#include <asm/dma.h> +#include <asm/system.h> +#include <asm/io.h> +#include <asm/atomic.h> +#include <linux/blk.h> +#include <linux/version.h> +#include <linux/i2o.h> +#include "../../scsi/scsi.h" +#include "../../scsi/hosts.h" +#include "../../scsi/sd.h" +#include "i2o_scsi.h" + +#define VERSION_STRING "Version 0.0.1" + +#define dprintk(x) + +#define MAXHOSTS 32 + +struct i2o_scsi_host +{ + struct i2o_controller *controller; + s16 task[16][8]; /* Allow 16 devices for now */ + unsigned long tagclock[16][8]; /* Tag clock for queueing */ + s16 bus_task; /* The adapter TID */ +}; + +static int scsi_context; +static int lun_done; +static int i2o_scsi_hosts; + +static u32 *retry[32]; +static struct i2o_controller *retry_ctrl[32]; +static struct timer_list retry_timer; +static int retry_ct = 0; + +static atomic_t queue_depth; + +/* + * SG Chain buffer support... + */ + +#define SG_MAX_FRAGS 64 + +/* + * FIXME: we should allocate one of these per bus we find as we + * locate them not in a lump at boot. + */ + +typedef struct _chain_buf +{ + u32 sg_flags_cnt[SG_MAX_FRAGS]; + u32 sg_buf[SG_MAX_FRAGS]; +} chain_buf; + +#define SG_CHAIN_BUF_SZ sizeof(chain_buf) + +#define SG_MAX_BUFS (i2o_num_controllers * I2O_SCSI_CAN_QUEUE) +#define SG_CHAIN_POOL_SZ (SG_MAX_BUFS * SG_CHAIN_BUF_SZ) + +static int max_sg_len = 0; +static chain_buf *sg_chain_pool = NULL; +static int sg_chain_tag = 0; +static int sg_max_frags = SG_MAX_FRAGS; + +/* + * Retry congested frames. This actually needs pushing down into + * i2o core. We should only bother the OSM with this when we can't + * queue and retry the frame. Or perhaps we should call the OSM + * and its default handler should be this in the core, and this + * call a 2nd "I give up" handler in the OSM ? + */ + +static void i2o_retry_run(unsigned long f) +{ + int i; + unsigned long flags; + + save_flags(flags); + cli(); + + for(i=0;i<retry_ct;i++) + i2o_post_message(retry_ctrl[i], virt_to_bus(retry[i])); + retry_ct=0; + + restore_flags(flags); +} + +static void flush_pending(void) +{ + int i; + unsigned long flags; + + save_flags(flags); + cli(); + + for(i=0;i<retry_ct;i++) + { + retry[i][0]&=~0xFFFFFF; + retry[i][0]|=I2O_CMD_UTIL_NOP<<24; + i2o_post_message(retry_ctrl[i],virt_to_bus(retry[i])); + } + retry_ct=0; + + restore_flags(flags); +} + +static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg) +{ + Scsi_Cmnd *current_command; + u32 *m = (u32 *)msg; + u8 as,ds,st; + + if(m[0] & (1<<13)) + { + printk("IOP fail.\n"); + printk("From %d To %d Cmd %d.\n", + (m[1]>>12)&0xFFF, + m[1]&0xFFF, + m[1]>>24); + printk("Failure Code %d.\n", m[4]>>24); + if(m[4]&(1<<16)) + printk("Format error.\n"); + if(m[4]&(1<<17)) + printk("Path error.\n"); + if(m[4]&(1<<18)) + printk("Path State.\n"); + if(m[4]&(1<<18)) + printk("Congestion.\n"); + + m=(u32 *)bus_to_virt(m[7]); + printk("Failing message is %p.\n", m); + + if((m[4]&(1<<18)) && retry_ct < 32) + { + retry_ctrl[retry_ct]=c; + retry[retry_ct]=m; + if(!retry_ct++) + { + retry_timer.expires=jiffies+1; + add_timer(&retry_timer); + } + } + else + { + /* Create a scsi error for this */ + current_command = (Scsi_Cmnd *)m[3]; + printk("Aborted %ld\n", current_command->serial_number); + + spin_lock_irq(&io_request_lock); + current_command->result = DID_ERROR << 16; + current_command->scsi_done(current_command); + spin_unlock_irq(&io_request_lock); + + /* Now flush the message by making it a NOP */ + m[0]&=0x00FFFFFF; + m[0]|=(I2O_CMD_UTIL_NOP)<<24; + i2o_post_message(c,virt_to_bus(m)); + } + return; + } + + + /* + * Low byte is device status, next is adapter status, + * (then one byte reserved), then request status. + */ + ds=(u8)m[4]; + as=(u8)(m[4]>>8); + st=(u8)(m[4]>>24); + + dprintk(("i2o got a scsi reply %08X: ", m[0])); + dprintk(("m[2]=%08X: ", m[2])); + dprintk(("m[4]=%08X\n", m[4])); + + if(m[2]&0x80000000) + { + if(m[2]&0x40000000) + { + dprintk(("Event.\n")); + lun_done=1; + return; + } + printk(KERN_ERR "i2o_scsi: bus reset reply.\n"); + return; + } + + current_command = (Scsi_Cmnd *)m[3]; + + /* + * Is this a control request coming back - eg an abort ? + */ + + if(current_command==NULL) + { + if(st) + dprintk(("SCSI abort: %08X", m[4])); + dprintk(("SCSI abort completed.\n")); + return; + } + + dprintk(("Completed %ld\n", current_command->serial_number)); + + atomic_dec(&queue_depth); + + if(st == 0x06) + { + if(m[5] < current_command->underflow) + { + int i; + printk(KERN_ERR "SCSI: underflow 0x%08X 0x%08X\n", + m[5], current_command->underflow); + printk("Cmd: "); + for(i=0;i<15;i++) + printk("%02X ", current_command->cmnd[i]); + printk(".\n"); + } + else st=0; + } + + if(st) + { + /* An error has occurred */ + + dprintk((KERN_DEBUG "SCSI error %08X", m[4])); + + if (as == 0x0E) + /* SCSI Reset */ + current_command->result = DID_RESET << 16; + else if (as == 0x0F) + current_command->result = DID_PARITY << 16; + else + current_command->result = DID_ERROR << 16; + } + else + /* + * It worked maybe ? + */ + current_command->result = DID_OK << 16 | ds; + spin_lock(&io_request_lock); + current_command->scsi_done(current_command); + spin_unlock(&io_request_lock); + return; +} + +struct i2o_handler i2o_scsi_handler= +{ + i2o_scsi_reply, + NULL, + NULL, + NULL, + "I2O SCSI OSM", + 0, + I2O_CLASS_SCSI_PERIPHERAL +}; + +static int i2o_find_lun(struct i2o_controller *c, struct i2o_device *d, int *target, int *lun) +{ + u8 reply[8]; + + if(i2o_query_scalar(c, d->lct_data.tid, 0, 3, reply, 4)<0) + return -1; + + *target=reply[0]; + + if(i2o_query_scalar(c, d->lct_data.tid, 0, 4, reply, 8)<0) + return -1; + + *lun=reply[1]; + + dprintk(("SCSI (%d,%d)\n", *target, *lun)); + return 0; +} + +void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt) +{ + struct i2o_device *unit; + struct i2o_scsi_host *h =(struct i2o_scsi_host *)shpnt->hostdata; + int lun; + int target; + + h->controller=c; + h->bus_task=d->lct_data.tid; + + for(target=0;target<16;target++) + for(lun=0;lun<8;lun++) + h->task[target][lun] = -1; + + for(unit=c->devices;unit!=NULL;unit=unit->next) + { + dprintk(("Class %03X, parent %d, want %d.\n", + unit->lct_data.class_id, unit->lct_data.parent_tid, d->lct_data.tid)); + + /* Only look at scsi and fc devices */ + if ( (unit->lct_data.class_id != I2O_CLASS_SCSI_PERIPHERAL) + && (unit->lct_data.class_id != I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL) + ) + continue; + + /* On our bus ? */ + dprintk(("Found a disk (%d).\n", unit->lct_data.tid)); + if ((unit->lct_data.parent_tid == d->lct_data.tid) + || (unit->lct_data.parent_tid == d->lct_data.parent_tid) + ) + { + u16 limit; + dprintk(("Its ours.\n")); + if(i2o_find_lun(c, unit, &target, &lun)==-1) + { + printk(KERN_ERR "i2o_scsi: Unable to get lun for tid %d.\n", unit->lct_data.tid); + continue; + } + dprintk(("Found disk %d %d.\n", target, lun)); + h->task[target][lun]=unit->lct_data.tid; + h->tagclock[target][lun]=jiffies; + + /* Get the max fragments/request */ + i2o_query_scalar(c, d->lct_data.tid, 0xF103, 3, &limit, 2); + + /* sanity */ + if ( limit == 0 ) + { + printk(KERN_WARNING "i2o_scsi: Ignoring unreasonable SG limit of 0 from IOP!\n"); + limit = 1; + } + + shpnt->sg_tablesize = limit; + + dprintk(("i2o_scsi: set scatter-gather to %d.\n", + shpnt->sg_tablesize)); + } + } +} + +int i2o_scsi_detect(Scsi_Host_Template * tpnt) +{ + unsigned long flags; + struct Scsi_Host *shpnt = NULL; + int i; + int count; + + printk("i2o_scsi.c: %s\n", VERSION_STRING); + + if(i2o_install_handler(&i2o_scsi_handler)<0) + { + printk(KERN_ERR "i2o_scsi: Unable to install OSM handler.\n"); + return 0; + } + scsi_context = i2o_scsi_handler.context; + + if((sg_chain_pool = kmalloc(SG_CHAIN_POOL_SZ, GFP_KERNEL)) == NULL) + { + printk("i2o_scsi: Unable to alloc %d byte SG chain buffer pool.\n", SG_CHAIN_POOL_SZ); + printk("i2o_scsi: SG chaining DISABLED!\n"); + sg_max_frags = 11; + } + else + { + printk(" chain_pool: %d bytes @ %p\n", SG_CHAIN_POOL_SZ, sg_chain_pool); + printk(" (%d byte buffers X %d can_queue X %d i2o controllers)\n", + SG_CHAIN_BUF_SZ, I2O_SCSI_CAN_QUEUE, i2o_num_controllers); + sg_max_frags = SG_MAX_FRAGS; // 64 + } + + init_timer(&retry_timer); + retry_timer.data = 0UL; + retry_timer.function = i2o_retry_run; + +// printk("SCSI OSM at %d.\n", scsi_context); + + for (count = 0, i = 0; i < MAX_I2O_CONTROLLERS; i++) + { + struct i2o_controller *c=i2o_find_controller(i); + struct i2o_device *d; + /* + * This controller doesn't exist. + */ + + if(c==NULL) + continue; + + /* + * Fixme - we need some altered device locking. This + * is racing with device addition in theory. Easy to fix. + */ + + for(d=c->devices;d!=NULL;d=d->next) + { + /* + * bus_adapter, SCSI (obsolete), or FibreChannel busses only + */ + if( (d->lct_data.class_id!=I2O_CLASS_BUS_ADAPTER_PORT) // bus_adapter +// && (d->lct_data.class_id!=I2O_CLASS_FIBRE_CHANNEL_PORT) // FC_PORT + ) + continue; + + shpnt = scsi_register(tpnt, sizeof(struct i2o_scsi_host)); + if(shpnt==NULL) + continue; + save_flags(flags); + cli(); + shpnt->unique_id = (u32)d; + shpnt->io_port = 0; + shpnt->n_io_port = 0; + shpnt->irq = 0; + shpnt->this_id = /* Good question */15; + restore_flags(flags); + i2o_scsi_init(c, d, shpnt); + count++; + } + } + i2o_scsi_hosts = count; + + if(count==0) + { + if(sg_chain_pool!=NULL) + { + kfree(sg_chain_pool); + sg_chain_pool = NULL; + } + flush_pending(); + del_timer(&retry_timer); + i2o_remove_handler(&i2o_scsi_handler); + } + + return count; +} + +int i2o_scsi_release(struct Scsi_Host *host) +{ + if(--i2o_scsi_hosts==0) + { + if(sg_chain_pool!=NULL) + { + kfree(sg_chain_pool); + sg_chain_pool = NULL; + } + flush_pending(); + del_timer(&retry_timer); + i2o_remove_handler(&i2o_scsi_handler); + } + return 0; +} + + +const char *i2o_scsi_info(struct Scsi_Host *SChost) +{ + struct i2o_scsi_host *hostdata; + + hostdata = (struct i2o_scsi_host *)SChost->hostdata; + + return(&hostdata->controller->name[0]); +} + + +/* + * From the wd93 driver: + * Returns true if there will be a DATA_OUT phase with this command, + * false otherwise. + * (Thanks to Joerg Dorchain for the research and suggestion.) + * + */ +static int is_dir_out(Scsi_Cmnd *cmd) +{ + switch (cmd->cmnd[0]) + { + case WRITE_6: case WRITE_10: case WRITE_12: + case WRITE_LONG: case WRITE_SAME: case WRITE_BUFFER: + case WRITE_VERIFY: case WRITE_VERIFY_12: + case COMPARE: case COPY: case COPY_VERIFY: + case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW: + case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12: + case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE: + case MODE_SELECT: case MODE_SELECT_10: case LOG_SELECT: + case SEND_DIAGNOSTIC: case CHANGE_DEFINITION: case UPDATE_BLOCK: + case SET_WINDOW: case MEDIUM_SCAN: case SEND_VOLUME_TAG: + case 0xea: + return 1; + default: + return 0; + } +} + +int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) +{ + int i; + int tid; + struct i2o_controller *c; + Scsi_Cmnd *current_command; + struct Scsi_Host *host; + struct i2o_scsi_host *hostdata; + u32 *msg, *mptr; + u32 m; + u32 *lenptr; + int direction; + int scsidir; + u32 len; + u32 reqlen; + u32 tag; + + static int max_qd = 1; + + /* + * Do the incoming paperwork + */ + + host = SCpnt->host; + hostdata = (struct i2o_scsi_host *)host->hostdata; + SCpnt->scsi_done = done; + + if(SCpnt->target > 15) + { + printk(KERN_ERR "i2o_scsi: Wild target %d.\n", SCpnt->target); + return -1; + } + + tid = hostdata->task[SCpnt->target][SCpnt->lun]; + + dprintk(("qcmd: Tid = %d\n", tid)); + + current_command = SCpnt; /* set current command */ + current_command->scsi_done = done; /* set ptr to done function */ + + /* We don't have such a device. Pretend we did the command + and that selection timed out */ + + if(tid == -1) + { + SCpnt->result = DID_NO_CONNECT << 16; + done(SCpnt); + return 0; + } + + dprintk(("Real scsi messages.\n")); + + c = hostdata->controller; + + /* + * Obtain an I2O message. Right now we _have_ to obtain one + * until the scsi layer stuff is cleaned up. + */ + + do + { + mb(); + m = I2O_POST_READ32(c); + } + while(m==0xFFFFFFFF); + msg = (u32 *)(c->mem_offset + m); + + /* + * Put together a scsi execscb message + */ + + len = SCpnt->request_bufflen; + direction = 0x00000000; // SGL IN (osm<--iop) + + /* + * The scsi layer should be handling this stuff + */ + + scsidir = 0x00000000; // DATA NO XFER + if(len) + { + if(is_dir_out(SCpnt)) + { + direction=0x04000000; // SGL OUT (osm-->iop) + scsidir =0x80000000; // DATA OUT (iop-->dev) + } + else + { + scsidir =0x40000000; // DATA IN (iop<--dev) + } + } + + __raw_writel(I2O_CMD_SCSI_EXEC<<24|HOST_TID<<12|tid, &msg[1]); + __raw_writel(scsi_context, &msg[2]); /* So the I2O layer passes to us */ + /* Sorry 64bit folks. FIXME */ + __raw_writel((u32)SCpnt, &msg[3]); /* We want the SCSI control block back */ + + /* LSI_920_PCI_QUIRK + * + * Intermittant observations of msg frame word data corruption + * observed on msg[4] after: + * WRITE, READ-MODIFY-WRITE + * operations. 19990606 -sralston + * + * (Hence we build this word via tag. Its good practice anyway + * we don't want fetches over PCI needlessly) + */ + + tag=0; + + /* + * Attach tags to the devices + */ + if(SCpnt->device->tagged_supported) + { + /* + * Some drives are too stupid to handle fairness issues + * with tagged queueing. We throw in the odd ordered + * tag to stop them starving themselves. + */ + if((jiffies - hostdata->tagclock[SCpnt->target][SCpnt->lun]) > (5*HZ)) + { + tag=0x01800000; /* ORDERED! */ + hostdata->tagclock[SCpnt->target][SCpnt->lun]=jiffies; + } + else + { + /* Hmmm... I always see value of 0 here, + * of which {HEAD_OF, ORDERED, SIMPLE} are NOT! -sralston + */ + if(SCpnt->tag == HEAD_OF_QUEUE_TAG) + tag=0x01000000; + else if(SCpnt->tag == ORDERED_QUEUE_TAG) + tag=0x01800000; + } + } + + /* Direction, disconnect ok, tag, CDBLen */ + __raw_writel(scsidir|0x20000000|SCpnt->cmd_len|tag, &msg[4]); + + mptr=msg+5; + + /* + * Write SCSI command into the message - always 16 byte block + */ + + memcpy_toio(mptr, SCpnt->cmnd, 16); + mptr+=4; + lenptr=mptr++; /* Remember me - fill in when we know */ + + reqlen = 12; // SINGLE SGE + + /* + * Now fill in the SGList and command + * + * FIXME: we need to set the sglist limits according to the + * message size of the I2O controller. We might only have room + * for 6 or so worst case + */ + + if(SCpnt->use_sg) + { + struct scatterlist *sg = (struct scatterlist *)SCpnt->request_buffer; + int chain = 0; + + len = 0; + + if((sg_max_frags > 11) && (SCpnt->use_sg > 11)) + { + chain = 1; + /* + * Need to chain! + */ + __raw_writel(direction|0xB0000000|(SCpnt->use_sg*2*4), mptr++); + __raw_writel(virt_to_bus(sg_chain_pool + sg_chain_tag), mptr); + mptr = (u32*)(sg_chain_pool + sg_chain_tag); + if (SCpnt->use_sg > max_sg_len) + { + max_sg_len = SCpnt->use_sg; + printk("i2o_scsi: Chain SG! SCpnt=%p, SG_FragCnt=%d, SG_idx=%d\n", + SCpnt, SCpnt->use_sg, sg_chain_tag); + } + if ( ++sg_chain_tag == SG_MAX_BUFS ) + sg_chain_tag = 0; + for(i = 0 ; i < SCpnt->use_sg; i++) + { + *mptr++=direction|0x10000000|sg->length; + len+=sg->length; + *mptr++=virt_to_bus(sg->address); + sg++; + } + mptr[-2]=direction|0xD0000000|(sg-1)->length; + } + else + { + for(i = 0 ; i < SCpnt->use_sg; i++) + { + __raw_writel(direction|0x10000000|sg->length, mptr++); + len+=sg->length; + __raw_writel(virt_to_bus(sg->address), mptr++); + sg++; + } + + /* Make this an end of list. Again evade the 920 bug and + unwanted PCI read traffic */ + + __raw_writel(direction|0xD0000000|(sg-1)->length, &mptr[-2]); + } + + if(!chain) + reqlen = mptr - msg; + + __raw_writel(len, lenptr); + + if(len != SCpnt->underflow) + printk("Cmd len %08X Cmd underflow %08X\n", + len, SCpnt->underflow); + } + else + { + dprintk(("non sg for %p, %d\n", SCpnt->request_buffer, + SCpnt->request_bufflen)); + __raw_writel(len = SCpnt->request_bufflen, lenptr); + if(len == 0) + { + reqlen = 9; + } + else + { + __raw_writel(0xD0000000|direction|SCpnt->request_bufflen, mptr++); + __raw_writel(virt_to_bus(SCpnt->request_buffer), mptr++); + } + } + + /* + * Stick the headers on + */ + + __raw_writel(reqlen<<16 | SGL_OFFSET_10, msg); + + /* Queue the message */ + i2o_post_message(c,m); + + atomic_inc(&queue_depth); + + if(atomic_read(&queue_depth)> max_qd) + { + max_qd=atomic_read(&queue_depth); + printk("Queue depth now %d.\n", max_qd); + } + + mb(); + dprintk(("Issued %ld\n", current_command->serial_number)); + + return 0; +} + +static void internal_done(Scsi_Cmnd * SCpnt) +{ + SCpnt->SCp.Status++; +} + +int i2o_scsi_command(Scsi_Cmnd * SCpnt) +{ + i2o_scsi_queuecommand(SCpnt, internal_done); + SCpnt->SCp.Status = 0; + while (!SCpnt->SCp.Status) + barrier(); + return SCpnt->result; +} + +int i2o_scsi_abort(Scsi_Cmnd * SCpnt) +{ + struct i2o_controller *c; + struct Scsi_Host *host; + struct i2o_scsi_host *hostdata; + u32 *msg; + u32 m; + int tid; + + printk("i2o_scsi: Aborting command block.\n"); + + host = SCpnt->host; + hostdata = (struct i2o_scsi_host *)host->hostdata; + tid = hostdata->task[SCpnt->target][SCpnt->lun]; + if(tid==-1) + { + printk(KERN_ERR "impossible command to abort.\n"); + return SCSI_ABORT_NOT_RUNNING; + } + c = hostdata->controller; + + /* + * Obtain an I2O message. Right now we _have_ to obtain one + * until the scsi layer stuff is cleaned up. + */ + + do + { + mb(); + m = I2O_POST_READ32(c); + } + while(m==0xFFFFFFFF); + msg = bus_to_virt(c->mem_offset + m); + + __raw_writel(FIVE_WORD_MSG_SIZE, &msg[0]); + __raw_writel(I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|tid, &msg[1]); + __raw_writel(scsi_context, &msg[2]); + __raw_writel(0, &msg[3]); /* Not needed for an abort */ + __raw_writel((u32)SCpnt, &msg[4]); + wmb(); + i2o_post_message(c,m); + wmb(); + return SCSI_ABORT_PENDING; +} + +int i2o_scsi_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) +{ + int tid; + struct i2o_controller *c; + struct Scsi_Host *host; + struct i2o_scsi_host *hostdata; + u32 m; + u32 *msg; + + /* + * Find the TID for the bus + */ + + printk("i2o_scsi: Attempting to reset the bus.\n"); + + host = SCpnt->host; + hostdata = (struct i2o_scsi_host *)host->hostdata; + tid = hostdata->bus_task; + c = hostdata->controller; + + /* + * Now send a SCSI reset request. Any remaining commands + * will be aborted by the IOP. We need to catch the reply + * possibly ? + */ + + m = I2O_POST_READ32(c); + + /* + * No free messages, try again next time - no big deal + */ + + if(m == 0xFFFFFFFF) + return SCSI_RESET_PUNT; + + msg = bus_to_virt(c->mem_offset + m); + __raw_writel(FOUR_WORD_MSG_SIZE|SGL_OFFSET_0, &msg[0]); + __raw_writel(I2O_CMD_SCSI_BUSRESET<<24|HOST_TID<<12|tid, &msg[1]); + __raw_writel(scsi_context|0x80000000, &msg[2]); + /* We use the top bit to split controller and unit transactions */ + /* Now store unit,tid so we can tie the completion back to a specific device */ + __raw_writel(c->unit << 16 | tid, &msg[3]); + i2o_post_message(c,m); + return SCSI_RESET_PENDING; +} + +/* + * This is anyones guess quite frankly. + */ + +int i2o_scsi_bios_param(Disk * disk, kdev_t dev, int *ip) +{ + int size; + + size = disk->capacity; + ip[0] = 64; /* heads */ + ip[1] = 32; /* sectors */ + if ((ip[2] = size >> 11) > 1024) { /* cylinders, test for big disk */ + ip[0] = 255; /* heads */ + ip[1] = 63; /* sectors */ + ip[2] = size / (255 * 63); /* cylinders */ + } + return 0; +} + +MODULE_AUTHOR("Red Hat Software"); + +static Scsi_Host_Template driver_template = I2OSCSI; + +#include "../../scsi/scsi_module.c" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/message/i2o/i2o_scsi.h linux.ac/drivers/message/i2o/i2o_scsi.h --- linux.vanilla/drivers/message/i2o/i2o_scsi.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/message/i2o/i2o_scsi.h Sat Apr 14 15:39:28 2001 @@ -0,0 +1,47 @@ +#ifndef _I2O_SCSI_H +#define _I2O_SCSI_H + +#if !defined(LINUX_VERSION_CODE) +#include <linux/version.h> +#endif + +#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) + +#include <linux/types.h> +#include <linux/kdev_t.h> + +#define I2O_SCSI_ID 15 +#define I2O_SCSI_CAN_QUEUE 4 +#define I2O_SCSI_CMD_PER_LUN 6 + +extern int i2o_scsi_detect(Scsi_Host_Template *); +extern const char *i2o_scsi_info(struct Scsi_Host *); +extern int i2o_scsi_command(Scsi_Cmnd *); +extern int i2o_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +extern int i2o_scsi_abort(Scsi_Cmnd *); +extern int i2o_scsi_reset(Scsi_Cmnd *, unsigned int); +extern int i2o_scsi_bios_param(Disk *, kdev_t, int *); +extern void i2o_scsi_setup(char *str, int *ints); +extern int i2o_scsi_release(struct Scsi_Host *host); + +#define I2OSCSI { \ + next: NULL, \ + proc_name: "i2o_scsi", \ + name: "I2O SCSI Layer", \ + detect: i2o_scsi_detect, \ + release: i2o_scsi_release, \ + info: i2o_scsi_info, \ + command: i2o_scsi_command, \ + queuecommand: i2o_scsi_queuecommand, \ + abort: i2o_scsi_abort, \ + reset: i2o_scsi_reset, \ + bios_param: i2o_scsi_bios_param, \ + can_queue: I2O_SCSI_CAN_QUEUE, \ + this_id: I2O_SCSI_ID, \ + sg_tablesize: 8, \ + cmd_per_lun: I2O_SCSI_CMD_PER_LUN, \ + unchecked_isa_dma: 0, \ + use_clustering: ENABLE_CLUSTERING \ + } + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/mtd/pmc551.c linux.ac/drivers/mtd/pmc551.c --- linux.vanilla/drivers/mtd/pmc551.c Sat Feb 17 00:02:36 2001 +++ linux.ac/drivers/mtd/pmc551.c Tue Apr 10 18:15:13 2001 @@ -13,17 +13,17 @@ * * Description: * This driver is intended to support the PMC551 PCI Ram device from - * Ramix Inc. The PMC551 is a PMC Mezzanine module for cPCI embeded + * Ramix Inc. The PMC551 is a PMC Mezzanine module for cPCI embedded * systems. The device contains a single SROM that initally programs the * V370PDC chipset onboard the device, and various banks of DRAM/SDRAM * onboard. This driver implements this PCI Ram device as an MTD (Memory * Technologies Device) so that it can be used to hold a filesystem, or - * for added swap space in embeded systems. Since the memory on this + * for added swap space in embedded systems. Since the memory on this * board isn't as fast as main memory we do not try to hook it into main * memeory as that would simply reduce performance on the system. Using * it as a block device allows us to use it as high speed swap or for a - * high speed disk device of some sort. Which becomes very usefull on - * diskless systems in the embeded market I might add. + * high speed disk device of some sort. Which becomes very useful on + * diskless systems in the embedded market I might add. * * Notes: * Due to what I assume is more buggy SROM, the 64M PMC551 I have diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/3c505.c linux.ac/drivers/net/3c505.c --- linux.vanilla/drivers/net/3c505.c Tue Apr 3 17:32:08 2001 +++ linux.ac/drivers/net/3c505.c Sat Apr 14 01:22:29 2001 @@ -149,7 +149,7 @@ #ifdef ELP_DEBUG static const int elp_debug = ELP_DEBUG; #else -static const int elp_debug = 0; +static const int elp_debug; #endif /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/3c507.c linux.ac/drivers/net/3c507.c --- linux.vanilla/drivers/net/3c507.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/3c507.c Sat Apr 14 01:22:29 2001 @@ -323,7 +323,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) { - static unsigned char init_ID_done = 0, version_printed = 0; + static unsigned char init_ID_done, version_printed; int i, irq, irqval, retval; struct net_local *lp; @@ -858,7 +858,7 @@ #ifdef MODULE static struct net_device dev_3c507; static int io = 0x300; -static int irq = 0; +static int irq; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/3c509.c linux.ac/drivers/net/3c509.c --- linux.vanilla/drivers/net/3c509.c Tue Apr 3 17:32:08 2001 +++ linux.ac/drivers/net/3c509.c Sat Apr 14 01:22:29 2001 @@ -144,7 +144,7 @@ char mca_slot; }; static int id_port __initdata = 0x110; /* Start with 0x110 to avoid new sound cards.*/ -static struct net_device *el3_root_dev = NULL; +static struct net_device *el3_root_dev; static ushort id_read_eeprom(int index); static ushort read_eeprom(int ioaddr, int index); @@ -209,10 +209,10 @@ short lrs_state = 0xff, i; int ioaddr, irq, if_port; u16 phys_addr[3]; - static int current_tag = 0; + static int current_tag; int mca_slot = -1; #ifdef CONFIG_ISAPNP - static int pnp_cards = 0; + static int pnp_cards; #endif /* CONFIG_ISAPNP */ if (dev) SET_MODULE_OWNER(dev); @@ -942,7 +942,7 @@ int ioaddr = dev->base_addr; if (el3_debug > 1) { - static int old = 0; + static int old; if (old != dev->mc_count) { old = dev->mc_count; printk("%s: Setting Rx mode to %d addresses.\n", dev->name, dev->mc_count); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/3c515.c linux.ac/drivers/net/3c515.c --- linux.vanilla/drivers/net/3c515.c Tue Apr 3 17:32:08 2001 +++ linux.ac/drivers/net/3c515.c Sat Apr 14 01:22:36 2001 @@ -16,8 +16,6 @@ Cleaned up for 2.3.x/softnet by Jeff Garzik and Alan Cox. */ -static char *version = "3c515.c:v0.99-sn 2000/02/12 becker@cesdis.gsfc.nasa.gov and others\n"; - #define CORKSCREW 1 /* "Knobs" that adjust features and parameters. */ @@ -61,6 +59,7 @@ #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/timer.h> +#include <linux/init.h> #include <asm/bitops.h> #include <asm/io.h> #include <asm/dma.h> @@ -78,6 +77,8 @@ #define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n, instance) #define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs) +static char *version __initdata = "3c515.c:v0.99-sn 2000/02/12 becker@cesdis.gsfc.nasa.gov and others\n"; + MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>"); MODULE_DESCRIPTION("3Com 3c515 Corkscrew driver"); MODULE_PARM(debug, "i"); @@ -353,7 +354,7 @@ }; #ifdef CONFIG_ISAPNP -static struct isapnp_device_id corkscrew_isapnp_adapters[] = { +static struct isapnp_device_id corkscrew_isapnp_adapters[] __initdata = { { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5051), (long) "3Com Fast EtherLink ISA" }, @@ -407,7 +408,7 @@ #ifdef MODULE static int debug = -1; /* A list of all installed Vortex devices, for removing the driver module. */ -static struct net_device *root_corkscrew_dev = NULL; +static struct net_device *root_corkscrew_dev; int init_module(void) { @@ -424,7 +425,7 @@ } #else -int tc515_probe(struct net_device *dev) +int __init tc515_probe(struct net_device *dev) { int cards_found = 0; @@ -439,13 +440,13 @@ } #endif /* not MODULE */ -static int corkscrew_scan(struct net_device *dev) +static int __init corkscrew_scan(struct net_device *dev) { int cards_found = 0; static int ioaddr; #ifdef CONFIG_ISAPNP short i; - static int pnp_cards = 0; + static int pnp_cards; #endif #ifdef CONFIG_ISAPNP @@ -550,7 +551,7 @@ return cards_found; } -static struct net_device *corkscrew_found_device(struct net_device *dev, +static struct net_device * __init corkscrew_found_device(struct net_device *dev, int ioaddr, int irq, int product_index, int options) @@ -626,7 +627,7 @@ return dev; } -static int corkscrew_probe1(struct net_device *dev) +static int __init corkscrew_probe1(struct net_device *dev) { int ioaddr = dev->base_addr; struct corkscrew_private *vp = @@ -1166,7 +1167,7 @@ printk("%s: interrupt, status %4.4x, timer %d.\n", dev->name, status, latency); if ((status & 0xE000) != 0xE000) { - static int donedidthis = 0; + static int donedidthis; /* Some interrupt controllers store a bogus interrupt from boot-time. Ignore a single early interrupt, but don't hang the machine for other interrupt problems. */ @@ -1234,7 +1235,7 @@ outw(AckIntr | RxEarly, ioaddr + EL3_CMD); } if (status & StatsFull) { /* Empty statistics. */ - static int DoneDidThat = 0; + static int DoneDidThat; if (corkscrew_debug > 4) printk("%s: Updating stats.\n", dev->name); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/3c523.c linux.ac/drivers/net/3c523.c --- linux.vanilla/drivers/net/3c523.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/3c523.c Sat Apr 14 01:22:36 2001 @@ -404,7 +404,7 @@ int __init elmc_probe(struct net_device *dev) { - static int slot = 0; + static int slot; int base_addr = dev->base_addr; int irq = dev->irq; u_char status = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/3c527.c linux.ac/drivers/net/3c527.c --- linux.vanilla/drivers/net/3c527.c Tue Apr 3 17:32:08 2001 +++ linux.ac/drivers/net/3c527.c Sat Apr 14 01:22:36 2001 @@ -270,7 +270,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) { - static unsigned version_printed = 0; + static unsigned version_printed; int i, err; u8 POS; u32 base; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/3c59x.c linux.ac/drivers/net/3c59x.c --- linux.vanilla/drivers/net/3c59x.c Tue Apr 3 17:32:08 2001 +++ linux.ac/drivers/net/3c59x.c Sat Apr 14 01:22:47 2001 @@ -92,7 +92,7 @@ - Ignore request_region() return value - already reserved if Cardbus. - Merged some additional Cardbus flags from Don's 0.99Qk - Some fixes for 3c556 (Fred Maciel) - - Fix for EISA initialisation (Jan Rkorajski) + - Fix for EISA initialisation (Jan Rekorajski) - Renamed MII_XCVR_PWR and EEPROM_230 to align with 3c575_cb and D. Becker's drivers - Fixed MII_XCVR_PWR for 3CCFE575CT - Added INVERT_LED_PWR, used it. @@ -192,6 +192,7 @@ #error You must compile this driver with "-O". #endif +#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> @@ -399,7 +400,7 @@ #define EISA_TBL_OFFSET 0 /* Offset of this entry for vortex_eisa_init */ {"3c590 Vortex 10Mbps", PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, - {"3c592 EISA 10mbps Demon/Vortex", /* AKPM: from Don's 3c59x_cb.c 0.49H */ + {"3c592 EISA 10Mbps Demon/Vortex", /* AKPM: from Don's 3c59x_cb.c 0.49H */ PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, {"3c597 EISA Fast Demon/Vortex", /* AKPM: from Don's 3c59x_cb.c 0.49H */ PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/8139too.c linux.ac/drivers/net/8139too.c --- linux.vanilla/drivers/net/8139too.c Tue Apr 3 17:32:08 2001 +++ linux.ac/drivers/net/8139too.c Sun Apr 15 23:12:09 2001 @@ -149,7 +149,7 @@ #include <asm/io.h> -#define RTL8139_VERSION "0.9.15c" +#define RTL8139_VERSION "0.9.16" #define MODNAME "8139too" #define RTL8139_DRIVER_NAME MODNAME " Fast Ethernet driver " RTL8139_VERSION #define PFX MODNAME ": " @@ -204,6 +204,7 @@ #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) +#define RX_EARLY_THRESH 2 /* Number of Tx descriptor registers. */ #define NUM_TX_DESC 4 @@ -220,8 +221,8 @@ #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 RX_FIFO_THRESH 7 /* Rx buffer level before first PCI xfer. */ +#define RX_DMA_BURST 7 /* Maximum PCI burst, '6' is 1024 */ #define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ @@ -491,7 +492,7 @@ } chip_t; enum chip_flags { - HasPwrDn = (1 << 0), + HasHltClk = (1 << 0), HasLWake = (1 << 1), }; @@ -506,19 +507,19 @@ { "RTL-8139", 0x40, 0xf0fe0040, /* XXX copied from RTL8139A, verify */ - HasPwrDn, + HasHltClk, }, { "RTL-8139 rev K", 0x60, 0xf0fe0040, - HasPwrDn, + HasHltClk, }, { "RTL-8139A", 0x70, 0xf0fe0040, - 0, + HasHltClk, /* XXX undocumented? */ }, { "RTL-8139B", @@ -572,6 +573,7 @@ pid_t thr_pid; wait_queue_head_t thr_wait; struct semaphore thr_exited; + u32 rx_config; }; MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>"); @@ -633,6 +635,7 @@ #define RTL_W32_F(reg, val32) do { writel ((val32), ioaddr + (reg)); readl (ioaddr + (reg)); } while (0) +#define MMIO_FLUSH_AUDIT_COMPLETE 1 #if MMIO_FLUSH_AUDIT_COMPLETE /* write MMIO register */ @@ -662,7 +665,7 @@ TxErr | TxOK | RxErr | RxOK; static const unsigned int rtl8139_rx_config = - RxCfgEarlyRxNone | RxCfgRcv32K | RxNoWrap | + (RX_EARLY_THRESH << RxCfgEarlyRxShift) | RxCfgRcv32K | RxNoWrap | (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); @@ -700,6 +703,23 @@ } +static void rtl8139_chip_reset (void *ioaddr) +{ + int i; + + /* Soft reset the chip. */ + RTL_W8 (ChipCmd, CmdReset); + + /* Check that the chip has finished the reset. */ + for (i = 1000; i > 0; i--) { + barrier(); + if ((RTL_R8 (ChipCmd) & CmdReset) == 0) + break; + udelay (10); + } +} + + static int __devinit rtl8139_init_board (struct pci_dev *pdev, struct net_device **dev_out) { @@ -707,7 +727,8 @@ struct net_device *dev; struct rtl8139_private *tp; u8 tmp8; - int rc, i; + int rc; + unsigned int i, have_pci_pm = 1; u32 pio_start, pio_end, pio_flags, pio_len; unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; u32 tmp; @@ -748,30 +769,37 @@ * 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; + /* ugly hueristic, but it's a chicken-and-egg problem */ + if (pio_len < RTL8139B_IO_SIZE) + have_pci_pm = 0; + +#ifdef USE_IO_OPS /* make sure PCI base addr 0 is PIO */ if (!(pio_flags & IORESOURCE_IO)) { printk (KERN_ERR PFX "%s: region #0 not a PIO resource, aborting\n", pdev->slot_name); rc = -ENODEV; goto err_out; } - + /* check for weird/broken PCI region reporting */ + if (pio_len < RTL_MIN_IO_SIZE) { + printk (KERN_ERR PFX "%s: Invalid PCI I/O region size(s), aborting\n", pdev->slot_name); + rc = -ENODEV; + goto err_out; + } +#else /* make sure PCI base addr 1 is MMIO */ if (!(mmio_flags & IORESOURCE_MEM)) { printk (KERN_ERR PFX "%s: region #1 not an MMIO resource, aborting\n", pdev->slot_name); rc = -ENODEV; goto err_out; } - - /* check for weird/broken PCI region reporting */ - if ((pio_len < RTL_MIN_IO_SIZE) || - (mmio_len < RTL_MIN_IO_SIZE)) { - printk (KERN_ERR PFX "%s: Invalid PCI region size(s), aborting\n", pdev->slot_name); + if (mmio_len < RTL_MIN_IO_SIZE) { + printk (KERN_ERR PFX "%s: Invalid PCI mem region size(s), aborting\n", pdev->slot_name); rc = -ENODEV; goto err_out; } +#endif rc = pci_request_regions (pdev, "8139too"); if (rc) @@ -795,61 +823,43 @@ tp->mmio_addr = ioaddr; #endif /* USE_IO_OPS */ - /* Bring the chip out of low-power mode. */ - if (rtl_chip_info[tp->chipset].flags & HasPwrDn) { - tmp8 = RTL_R8 (Config1); - if (tmp8 & (SLEEP|PWRDN)) { - RTL_W8_F (Cfg9346, Cfg9346_Unlock); - RTL_W8 (Config1, tmp8 & ~(SLEEP|PWRDN)); - RTL_W8_F (Cfg9346, Cfg9346_Lock); - } - } else { + /* Bring old chips out of low-power mode. */ + if (have_pci_pm) { u8 new_tmp8 = tmp8 = RTL_R8 (Config1); if ((rtl_chip_info[tp->chipset].flags & HasLWake) && (tmp8 & LWAKE)) new_tmp8 &= ~LWAKE; new_tmp8 |= Cfg1_PM_Enable; if (new_tmp8 != tmp8) { - RTL_W8_F (Cfg9346, Cfg9346_Unlock); + RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, tmp8); - RTL_W8_F (Cfg9346, Cfg9346_Lock); + RTL_W8 (Cfg9346, Cfg9346_Lock); } if (rtl_chip_info[tp->chipset].flags & HasLWake) { tmp8 = RTL_R8 (Config4); if (tmp8 & LWPTN) RTL_W8 (Config4, tmp8 & ~LWPTN); } + } else { + RTL_W8 (HltClk, 'R'); + tmp8 = RTL_R8 (Config1); + tmp8 &= ~(SLEEP | PWRDN); + RTL_W8 (Config1, tmp8); } - /* Soft reset the chip. */ - RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset); - - /* Check that the chip has finished the reset. */ - for (i = 1000; i > 0; i--) { - barrier(); - udelay (10); - if ((RTL_R8 (ChipCmd) & CmdReset) == 0) - break; - } + rtl8139_chip_reset (ioaddr); - /* make sure chip thinks PIO and MMIO are enabled */ - tmp8 = RTL_R8 (Config1); - if ((tmp8 & Cfg1_PIO) == 0) { - printk (KERN_ERR PFX "%s: PIO not enabled, Cfg1=%02X, aborting\n", - pdev->slot_name, tmp8); - rc = -EIO; - goto err_out; - } - if ((tmp8 & Cfg1_MMIO) == 0) { - printk (KERN_ERR PFX "%s: MMIO not enabled, Cfg1=%02X, aborting\n", - pdev->slot_name, tmp8); + /* check for missing/broken hardware */ + if (RTL_R32 (TxConfig) == 0xFFFFFFFF) { + printk (KERN_ERR PFX "%s: Chip not responding, ignoring board\n", + pdev->slot_name); rc = -EIO; goto err_out; } /* identify chip attached to board */ tmp = RTL_R8 (ChipVersion); - for (i = ARRAY_SIZE (rtl_chip_info) - 1; i >= 0; i--) + for (i = 0; i < ARRAY_SIZE (rtl_chip_info); i++) if (tmp == rtl_chip_info[i].version) { tp->chipset = i; goto match; @@ -886,7 +896,6 @@ int i, addr_len, option; void *ioaddr; static int board_idx = -1; - static int printed_version; DPRINTK ("ENTER\n"); @@ -895,10 +904,16 @@ board_idx++; - if (!printed_version) { - printk (KERN_INFO RTL8139_DRIVER_NAME " loaded\n"); - printed_version = 1; + /* when we're built into the kernel, the driver version message + * is only printed if at least one 8139 board has been found + */ +#ifndef MODULE + { + static int printed_version; + if (!printed_version++) + printk (KERN_INFO RTL8139_DRIVER_NAME "\n"); } +#endif i = rtl8139_init_board (pdev, &dev); if (i < 0) { @@ -987,14 +1002,6 @@ #endif tp->phys[0] = 32; - /* Put the chip into low-power mode. */ - if (rtl_chip_info[tp->chipset].flags & HasPwrDn) { - RTL_W8_F (Cfg9346, Cfg9346_Unlock); - RTL_W8_F (Config1, RTL_R8 (Config1) | PWRDN); - RTL_W8_F (HltClk, 'H'); /* 'R' would leave the clock running. */ - RTL_W8_F (Cfg9346, Cfg9346_Lock); - } - /* The lower four bits are the media type. */ option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx]; if (option > 0) { @@ -1020,6 +1027,10 @@ ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */ } + /* Put the chip into low-power mode. */ + if (rtl_chip_info[tp->chipset].flags & HasHltClk) + RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ + DPRINTK ("EXIT - returning 0\n"); return 0; @@ -1215,11 +1226,11 @@ if (phy_id > 31) { /* Really a 8139. Use internal registers. */ void *ioaddr = tp->mmio_addr; if (location == 0) { - RTL_W8_F (Cfg9346, Cfg9346_Unlock); - RTL_W16_F (BasicModeCtrl, value); - RTL_W8_F (Cfg9346, Cfg9346_Lock); + RTL_W8 (Cfg9346, Cfg9346_Unlock); + RTL_W16 (BasicModeCtrl, value); + RTL_W8 (Cfg9346, Cfg9346_Lock); } else if (location < 8 && mii_2_8139_map[location]) - RTL_W16_F (mii_2_8139_map[location], value); + RTL_W16 (mii_2_8139_map[location], value); return; } @@ -1314,33 +1325,30 @@ DPRINTK ("ENTER\n"); - /* Soft reset the chip. */ - RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset); - udelay (100); + /* Bring old chips out of low-power mode. */ + if (rtl_chip_info[tp->chipset].flags & HasHltClk) + RTL_W8 (HltClk, 'R'); - /* Check that the chip has finished the reset. */ - for (i = 1000; i > 0; i--) - if ((RTL_R8 (ChipCmd) & CmdReset) == 0) - break; + rtl8139_chip_reset (ioaddr); /* unlock Config[01234] and BMCR register writes */ - RTL_W8_F (Cfg9346, Cfg9346_Unlock); + RTL_W8 (Cfg9346, Cfg9346_Unlock); /* 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))); + RTL_W32 (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); + RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); - i = rtl8139_rx_config | - (RTL_R32 (RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); - RTL_W32_F (RxConfig, i); + tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys; + RTL_W32 (RxConfig, rtl8139_rx_config); /* Check this value: the documentation for IFG contradicts ifself. */ RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift)); tp->cur_rx = 0; + + DPRINTK("check_duplex"); /* This is check_duplex() */ if (tp->phys[0] >= 0 || (tp->drv_flags & HAS_MII_XCVR)) { @@ -1357,8 +1365,6 @@ tp->full_duplex ? "full" : "half", mii_reg5); } - RTL_W8 (Config1, RTL_R8 (Config1) | Cfg1_Driver_Load); - if (tp->chipset >= CH_8139B) { tmp = RTL_R8 (Config4) & ~(1<<2); /* chip will clear Rx FIFO overflow automatically */ @@ -1370,9 +1376,10 @@ RTL_W8 (Config3, RTL_R8 (Config3) & ~(1<<5)); } + DPRINTK("init buffer addresses\n"); + /* Lock Config[01234] and BMCR register writes */ - RTL_W8_F (Cfg9346, Cfg9346_Lock); - udelay (10); + RTL_W8 (Cfg9346, Cfg9346_Lock); /* init Rx ring buffer DMA address */ RTL_W32_F (RxBuf, tp->rx_ring_dma); @@ -1381,7 +1388,7 @@ 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); + RTL_W32 (RxMissed, 0); rtl8139_set_rx_mode (dev); @@ -1389,11 +1396,12 @@ RTL_W16 (MultiIntr, RTL_R16 (MultiIntr) & MultiIntrClear); /* make sure RxTx has started */ - RTL_W8_F (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | - CmdRxEnb | CmdTxEnb); + tmp = RTL_R8 (ChipCmd); + if ((!(tmp & CmdRxEnb)) || (!(tmp & CmdTxEnb))) + RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); /* Enable all known interrupts by setting the interrupt mask. */ - RTL_W16_F (IntrMask, rtl8139_intr_mask); + RTL_W16 (IntrMask, rtl8139_intr_mask); netif_start_queue (dev); @@ -1627,6 +1635,7 @@ void *ioaddr = tp->mmio_addr; int i; u8 tmp8; + unsigned long flags; DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x " "media %2.2x.\n", dev->name, @@ -1637,7 +1646,7 @@ /* disable Tx ASAP, if not already */ tmp8 = RTL_R8 (ChipCmd); if (tmp8 & CmdTxEnb) - RTL_W8 (ChipCmd, tmp8 & ~CmdTxEnb); + RTL_W8 (ChipCmd, CmdRxEnb); /* Disable interrupts by clearing the interrupt mask. */ RTL_W16 (IntrMask, 0x0000); @@ -1652,9 +1661,9 @@ " (queue head)" : ""); /* Stop a shared interrupt from scavenging while we are. */ - spin_lock_irq (&tp->lock); + spin_lock_irqsave (&tp->lock, flags); rtl8139_tx_clear (tp); - spin_unlock_irq (&tp->lock); + spin_unlock_irqrestore (&tp->lock, flags); /* ...and finally, reset everything */ rtl8139_hw_start (dev); @@ -1668,7 +1677,8 @@ { struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; - int entry; + unsigned int entry; + unsigned long flags; /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % NUM_TX_DESC; @@ -1695,13 +1705,13 @@ dev->trans_start = jiffies; - spin_lock_irq (&tp->lock); + spin_lock_irqsave (&tp->lock, flags); tp->cur_tx++; if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) netif_stop_queue (dev); - spin_unlock_irq (&tp->lock); + spin_unlock_irqrestore (&tp->lock, flags); DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n", dev->name, skb->data, skb->len, entry); @@ -1774,6 +1784,7 @@ dirty_tx++; tx_left--; + barrier(); } #ifndef RTL8139_NDEBUG @@ -1818,8 +1829,7 @@ tp->cur_rx = 0; /* disable receive */ - tmp8 = RTL_R8 (ChipCmd) & ChipCmdClear; - RTL_W8_F (ChipCmd, tmp8 | CmdTxEnb); + RTL_W8 (ChipCmd, CmdTxEnb); /* A.C.: Reset the multicast list. */ rtl8139_set_rx_mode (dev); @@ -1827,11 +1837,11 @@ /* XXX potentially temporary hack to * restart hung receiver */ while (--tmp_work > 0) { + barrier(); tmp8 = RTL_R8 (ChipCmd); if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb)) break; - RTL_W8_F (ChipCmd, - (tmp8 & ChipCmdClear) | CmdRxEnb | CmdTxEnb); + RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); } /* G.S.: Re-enable receiver */ @@ -1843,13 +1853,12 @@ } -/* 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 net_device *dev, - struct rtl8139_private *tp, void *ioaddr) + struct rtl8139_private *tp, void *ioaddr, + u16 status) { unsigned char *rx_ring; - u16 cur_rx; + u16 cur_rx, ackstat; assert (dev != NULL); assert (tp != NULL); @@ -1863,6 +1872,11 @@ RTL_R16 (RxBufAddr), RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); + if (status & RxFIFOOver) + status = RxOverflow | RxOK; + else + status = RxOK; + while ((RTL_R8 (ChipCmd) & RxBufEmpty) == 0) { int ring_offset = cur_rx % RX_BUF_LEN; u32 rx_status; @@ -1870,6 +1884,8 @@ unsigned int pkt_size; struct sk_buff *skb; + mb(); + /* read size+status of next frame from DMA ring buffer */ rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset)); rx_size = rx_status >> 16; @@ -1889,16 +1905,7 @@ } #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) + if (rx_size == 0xfff0) /* Early Rx in progress */ break; /* If Rx err or invalid rx_size/rx_status received @@ -1907,6 +1914,7 @@ * Rx processing. */ if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) || + (rx_size < 8) || (!(rx_status & RxStatusOK))) { rtl8139_rx_err (rx_status, dev, tp, ioaddr); return; @@ -1942,7 +1950,11 @@ } cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; - RTL_W16_F (RxBufPtr, cur_rx - 16); + RTL_W16 (RxBufPtr, cur_rx - 16); + + ackstat = RTL_R16 (IntrStatus) & status; + if (ackstat) + RTL_W16 (IntrStatus, ackstat); } DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x," @@ -1951,6 +1963,12 @@ RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); tp->cur_rx = cur_rx; + + if (RTL_R8 (ChipCmd) & RxBufEmpty) { + ackstat = RTL_R16 (IntrStatus) & status; + if (ackstat) + RTL_W16_F (IntrStatus, ackstat); + } } @@ -1996,11 +2014,6 @@ 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); @@ -2020,7 +2033,8 @@ struct rtl8139_private *tp = dev->priv; int boguscnt = max_interrupt_work; void *ioaddr = tp->mmio_addr; - int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */ + int ackstat, status; + int link_changed = 0; /* avoid bogus "uninit" warning */ do { status = RTL_R16 (IntrStatus); @@ -2053,17 +2067,21 @@ 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 transferred */ - RTL_W16_F (IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status); + ackstat = status & ~(RxFIFOOver | RxOverflow | RxOK); + RTL_W16 (IntrStatus, ackstat); - DPRINTK ("%s: interrupt status=%#4.4x new intstat=%#4.4x.\n", - dev->name, status, - RTL_R16 (IntrStatus)); + DPRINTK ("%s: interrupt status=%#4.4x ackstat=%#4.4x new intstat=%#4.4x.\n", + dev->name, ackstat, status, RTL_R16 (IntrStatus)); if ((status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0) break; + if (netif_running (dev) && + status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */ + rtl8139_rx_interrupt (dev, tp, ioaddr, status); + /* Check uncommon events with one test. */ if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | RxErr)) @@ -2071,10 +2089,6 @@ status, link_changed); if (netif_running (dev) && - status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */ - rtl8139_rx_interrupt (dev, tp, ioaddr); - - if (netif_running (dev) && status & (TxOK | TxErr)) { spin_lock (&tp->lock); rtl8139_tx_interrupt (dev, tp, ioaddr); @@ -2104,6 +2118,7 @@ struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; int ret = 0; + unsigned long flags; DPRINTK ("ENTER\n"); @@ -2121,19 +2136,19 @@ DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n", dev->name, RTL_R16 (IntrStatus)); - spin_lock_irq (&tp->lock); + spin_lock_irqsave (&tp->lock, flags); /* Stop the chip's Tx and Rx DMA processes. */ - RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear)); + RTL_W8 (ChipCmd, 0); /* Disable interrupts by clearing the interrupt mask. */ - RTL_W16 (IntrMask, 0x0000); + RTL_W16 (IntrMask, 0); /* Update the error counts. */ tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); - spin_unlock_irq (&tp->lock); + spin_unlock_irqrestore (&tp->lock, flags); synchronize_irq (); free_irq (dev->irq, dev); @@ -2150,10 +2165,8 @@ /* Green! Put the chip in low-power mode. */ RTL_W8 (Cfg9346, Cfg9346_Unlock); - if (rtl_chip_info[tp->chipset].flags & HasPwrDn) { - RTL_W8 (Config1, 0x03); + if (rtl_chip_info[tp->chipset].flags & HasHltClk) RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ - } DPRINTK ("EXIT\n"); return 0; @@ -2212,14 +2225,15 @@ { struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; + unsigned long flags; DPRINTK ("ENTER\n"); if (netif_running(dev)) { - spin_lock_irq (&tp->lock); + spin_lock_irqsave (&tp->lock, flags); tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); - spin_unlock_irq (&tp->lock); + spin_unlock_irqrestore (&tp->lock, flags); } DPRINTK ("EXIT\n"); @@ -2279,22 +2293,26 @@ mc_filter[1] = mc_filter[0] = 0xffffffff; } else { struct dev_mc_list *mclist; - rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + rx_mode = AcceptBroadcast | AcceptMyPhys; mc_filter[1] = mc_filter[0] = 0; for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) + i++, mclist = mclist->next) { set_bit (ether_crc (ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter); + rx_mode |= AcceptMulticast; + } } spin_lock_irqsave (&tp->lock, flags); /* 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); + tmp = rtl8139_rx_config | rx_mode; + if (tp->rx_config != tmp) { + RTL_W32 (RxConfig, tmp); + tp->rx_config = tmp; + } RTL_W32_F (MAR0 + 0, mc_filter[0]); - RTL_W32_F (MAR0 + 4, mc_filter[1]); + RTL_W32 (MAR0 + 4, mc_filter[1]); spin_unlock_irqrestore (&tp->lock, flags); @@ -2317,8 +2335,8 @@ spin_lock_irqsave (&tp->lock, flags); /* Disable interrupts, stop Tx and Rx. */ - RTL_W16 (IntrMask, 0x0000); - RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear)); + RTL_W16 (IntrMask, 0); + RTL_W8 (ChipCmd, 0); /* Update the error counts. */ tp->stats.rx_missed_errors += RTL_R32 (RxMissed); @@ -2351,6 +2369,13 @@ static int __init rtl8139_init_module (void) { + /* when we're a module, we always print a version message, + * even if no 8139 board is found. + */ +#ifdef MODULE + printk (KERN_INFO RTL8139_DRIVER_NAME "\n"); +#endif + return pci_module_init (&rtl8139_pci_driver); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/82596.c linux.ac/drivers/net/82596.c --- linux.vanilla/drivers/net/82596.c Tue Apr 3 17:32:09 2001 +++ linux.ac/drivers/net/82596.c Sat Apr 14 01:22:46 2001 @@ -1095,7 +1095,7 @@ int i; struct i596_private *lp; char eth_addr[8]; - static int probed = 0; + static int probed; if (probed) return -ENODEV; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/8390.c linux.ac/drivers/net/8390.c --- linux.vanilla/drivers/net/8390.c Sun Feb 4 18:05:30 2001 +++ linux.ac/drivers/net/8390.c Thu Apr 12 17:46:42 2001 @@ -453,6 +453,8 @@ { if (!netif_running(dev)) { printk(KERN_WARNING "%s: interrupt from stopped card\n", dev->name); + /* rmk - acknowledge the interrupts */ + outb_p(interrupts, e8390_base + EN0_ISR); interrupts = 0; break; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/8390.h linux.ac/drivers/net/8390.h --- linux.vanilla/drivers/net/8390.h Thu Feb 22 00:11:10 2001 +++ linux.ac/drivers/net/8390.h Tue Apr 17 18:23:03 2001 @@ -116,7 +116,8 @@ #if defined(CONFIG_MAC) || defined(CONFIG_AMIGA_PCMCIA) || \ defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE) || \ - defined(CONFIG_HYDRA) || defined(CONFIG_HYDRA_MODULE) + defined(CONFIG_HYDRA) || defined(CONFIG_HYDRA_MODULE) || \ + defined(CONFIG_ARM_ETHERH) || defined(CONFIG_ARM_ETHERH_MODULE) #define EI_SHIFT(x) (ei_local->reg_offset[x]) #else #define EI_SHIFT(x) (x) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/Config.in linux.ac/drivers/net/Config.in --- linux.vanilla/drivers/net/Config.in Tue Apr 3 17:32:09 2001 +++ linux.ac/drivers/net/Config.in Tue Apr 10 00:12:26 2001 @@ -27,9 +27,10 @@ bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET if [ "$CONFIG_NET_ETHERNET" = "y" ]; then if [ "$CONFIG_ARM" = "y" ]; then - if [ "$CONFIG_ARCH_ACORN" != "y" ]; then + if [ "$CONFIG_ARCH_EBSA110" = "y" ]; then tristate ' AM79C961A support' CONFIG_ARM_AM79C961A - else + fi + if [ "$CONFIG_ARCH_ACORN" = "y" ]; then source drivers/acorn/net/Config.in fi fi @@ -37,7 +38,6 @@ tristate ' MACE (Power Mac ethernet) support' CONFIG_MACE tristate ' BMAC (G3 ethernet) support' CONFIG_BMAC tristate ' GMAC (G4/iBook ethernet) support' CONFIG_GMAC - tristate ' Symbios 53c885 (Synergy ethernet) support' CONFIG_NCR885E tristate ' National DP83902AV (Oak ethernet) support' CONFIG_OAKNET fi if [ "$CONFIG_ZORRO" = "y" ]; then @@ -49,6 +49,9 @@ if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then tristate ' MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC fi + if [ "$CONFIG_MIPS_GT96100" = "y" ]; then + bool ' MIPS GT96100 Ethernet support' CONFIG_MIPS_GT96100ETH + fi if [ "$CONFIG_SGI_IP27" = "y" ]; then bool ' SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH fi @@ -163,6 +166,9 @@ dep_tristate ' Sun Happy Meal 10/100baseT PCI support' CONFIG_HAPPYMEAL $CONFIG_PCI if [ "$CONFIG_OBSOLETE" = "y" ]; then bool ' Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET + fi + if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ORION" = "y" ]; then + bool ' Philips SAA9730 Ethernet support (EXPERIMENTAL)' CONFIG_LAN_SAA9730 fi fi bool ' Pocket and portable adapters' CONFIG_NET_POCKET diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/Makefile linux.ac/drivers/net/Makefile --- linux.vanilla/drivers/net/Makefile Tue Apr 3 17:32:09 2001 +++ linux.ac/drivers/net/Makefile Tue Apr 3 17:58:20 2001 @@ -15,9 +15,8 @@ # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. -export-objs := 8390.o arlan.o aironet4500_core.o aironet4500_card.o \ - ppp_async.o ppp_generic.o slhc.o pppox.o auto_irq.o \ - net_init.o +export-objs := 8390.o arlan.o aironet4500_core.o aironet4500_card.o ppp_async.o \ + ppp_generic.o slhc.o pppox.o auto_irq.o net_init.o ifeq ($(CONFIG_TULIP),y) obj-y += tulip/tulip.o @@ -55,7 +54,6 @@ obj-$(CONFIG_MACE) += mace.o obj-$(CONFIG_BMAC) += bmac.o obj-$(CONFIG_GMAC) += gmac.o -obj-$(CONFIG_NCR885E) += ncr885e.o obj-$(CONFIG_OAKNET) += oaknet.o 8390.o @@ -169,6 +167,7 @@ obj-$(CONFIG_WAVELAN) += wavelan.o obj-$(CONFIG_ARLAN) += arlan.o arlan-proc.o obj-$(CONFIG_ZNET) += znet.o +obj-$(CONFIG_LAN_SAA9730) += saa9730.o obj-$(CONFIG_DEPCA) += depca.o obj-$(CONFIG_EWRK3) += ewrk3.o obj-$(CONFIG_ATP) += atp.o @@ -187,6 +186,7 @@ obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o obj-$(CONFIG_EQUALIZER) += eql.o obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o +obj-$(CONFIG_MIPS_GT96100ETH) += gt96100eth.o obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o obj-$(CONFIG_BAGETLANCE) += bagetlance.o obj-$(CONFIG_DECLANCE) += declance.o @@ -201,12 +201,21 @@ obj-$(CONFIG_MACMACE) += macmace.o obj-$(CONFIG_MAC89x0) += mac89x0.o obj-$(CONFIG_TUN) += tun.o + +ifeq ($(CONFIG_ARCH_ACORN),y) +mod-subdirs += ../acorn/net +subdir-y += ../acorn/net +obj-y += ../acorn/net/acorn-net.o +endif + # # HIPPI adapters # ifneq ($(ARCH),s390) +ifneq ($(ARCH),s390x) obj-y += auto_irq.o +endif endif include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/a2065.c linux.ac/drivers/net/a2065.c --- linux.vanilla/drivers/net/a2065.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/a2065.c Sat Apr 14 01:22:46 2001 @@ -137,7 +137,7 @@ }; #ifdef MODULE -static struct lance_private *root_a2065_dev = NULL; +static struct lance_private *root_a2065_dev; #endif #define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/acenic.c linux.ac/drivers/net/acenic.c --- linux.vanilla/drivers/net/acenic.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/acenic.c Sat Apr 14 01:23:05 2001 @@ -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, <jes@linuxcare.com>. + * Copyright 1998-2001 by Jes Sorensen, <jes@linuxcare.com>. * * Thanks to Alteon and 3Com for providing hardware and documentation * enabling me to write this driver. @@ -62,6 +62,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/mm.h> +#include <linux/highmem.h> #include <linux/sockios.h> #ifdef SIOCETHTOOL @@ -282,6 +283,10 @@ #include "acenic_firmware.h" +#ifndef tigon2FwReleaseLocal +#define tigon2FwReleaseLocal 0 +#endif + /* * This driver currently supports Tigon I and Tigon II based cards * including the Alteon AceNIC, the 3Com 3C985[B] and NetGear @@ -464,7 +469,7 @@ * Jumbo frames are enabled, the user wants optimal tuning for that case. */ #define DEF_TX_COAL 400 /* 996 */ -#define DEF_TX_MAX_DESC 40 +#define DEF_TX_MAX_DESC 60 /* was 40 */ #define DEF_RX_COAL 120 /* 1000 */ #define DEF_RX_MAX_DESC 25 #define DEF_TX_RATIO 21 /* 24 */ @@ -475,10 +480,26 @@ #define DEF_JUMBO_RX_MAX_DESC 6 #define DEF_JUMBO_TX_RATIO 21 -#define TX_COAL_INTS_ONLY 0 /* seems not worth it */ +#if tigon2FwReleaseLocal < 20001118 +/* + * Standard firmware and early modifications duplicate + * IRQ load without this flag (coal timer is never reset). + * Note that with this flag tx_coal should be less than + * time to xmit full tx ring. + * 400usec is not so bad for tx ring size of 128. + */ +#define TX_COAL_INTS_ONLY 1 /* worth it */ +#else +/* + * With modified firmware, this is not necessary, but still useful. + */ +#define TX_COAL_INTS_ONLY 1 +#endif + #define DEF_TRACE 0 #define DEF_STAT (2 * TICKS_PER_SEC) + static int link[ACE_MAX_MOD_PARMS]; static int trace[ACE_MAX_MOD_PARMS]; static int tx_coal_tick[ACE_MAX_MOD_PARMS]; @@ -489,7 +510,7 @@ static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1}; static char version[] __initdata = - "acenic.c: v0.50 02/02/2001 Jes Sorensen, linux-acenic@SunSITE.dk\n" + "acenic.c: v0.80 03/08/2001 Jes Sorensen, linux-acenic@SunSITE.dk\n" " http://home.cern.ch/~jes/gige/acenic.html\n"; static struct net_device *root_dev; @@ -560,6 +581,12 @@ dev->irq = pdev->irq; dev->open = &ace_open; dev->hard_start_xmit = &ace_start_xmit; + dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HIGHDMA; + if (1) { + static void ace_watchdog(struct net_device *dev); + dev->tx_timeout = &ace_watchdog; + dev->watchdog_timeo = 5*HZ; + } dev->stop = &ace_close; dev->get_stats = &ace_get_stats; dev->set_multicast_list = &ace_set_multicast_list; @@ -762,15 +789,17 @@ struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb; if (skb) { +#ifndef DUMMY_PCI_UNMAP dma_addr_t mapping; mapping = ap->skb->rx_std_skbuff[i].mapping; - - ap->rx_std_ring[i].size = 0; - ap->skb->rx_std_skbuff[i].skb = NULL; pci_unmap_single(ap->pdev, mapping, ACE_STD_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); +#endif + + ap->rx_std_ring[i].size = 0; + ap->skb->rx_std_skbuff[i].skb = NULL; dev_kfree_skb(skb); } } @@ -779,14 +808,16 @@ struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb; if (skb) { +#ifndef DUMMY_PCI_UNMAP dma_addr_t mapping; mapping = ap->skb->rx_mini_skbuff[i].mapping; - ap->rx_mini_ring[i].size = 0; - ap->skb->rx_mini_skbuff[i].skb = NULL; pci_unmap_single(ap->pdev, mapping, ACE_MINI_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); +#endif + ap->rx_mini_ring[i].size = 0; + ap->skb->rx_mini_skbuff[i].skb = NULL; dev_kfree_skb(skb); } } @@ -794,15 +825,17 @@ for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) { struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb; if (skb) { +#ifndef DUMMY_PCI_UNMAP dma_addr_t mapping; mapping = ap->skb->rx_jumbo_skbuff[i].mapping; - - ap->rx_jumbo_ring[i].size = 0; - ap->skb->rx_jumbo_skbuff[i].skb = NULL; pci_unmap_single(ap->pdev, mapping, ACE_JUMBO_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); +#endif + + ap->rx_jumbo_ring[i].size = 0; + ap->skb->rx_jumbo_skbuff[i].skb = NULL; dev_kfree_skb(skb); } } @@ -1177,10 +1210,21 @@ printk(KERN_INFO " Disabling PCI memory " "write and invalidate\n"); } +#ifdef __alpha__ + /* This maximizes throughput on my alpha. */ + tmp |= DMA_WRITE_MAX_128; +#endif } else if (ap->pci_command & PCI_COMMAND_INVALIDATE) { printk(KERN_INFO " PCI memory write & invalidate " "enabled by BIOS, enabling counter measures\n"); +#ifdef __alpha__ + /* All the docs sy MUST NOT. Well, I did. + * Nothing terrible happens, if we load wrong size. + * Bit w&i still works better! + */ + tmp |= DMA_WRITE_MAX_128; +#else switch(SMP_CACHE_BYTES) { case 16: tmp |= DMA_WRITE_MAX_16; @@ -1199,6 +1243,7 @@ pci_write_config_word(ap->pdev, PCI_COMMAND, ap->pci_command); } +#endif } } @@ -1218,6 +1263,9 @@ tmp |= DMA_READ_MAX_64; tmp |= DMA_WRITE_MAX_64; #endif +#ifdef __alpha__ + tmp |= DMA_READ_MAX_128; +#endif writel(tmp, ®s->PciState); #if 0 @@ -1313,7 +1361,7 @@ set_aceaddr(&info->rx_std_ctrl.rngptr, ap->rx_ring_base_dma); info->rx_std_ctrl.max_len = ACE_STD_MTU + ETH_HLEN + 4; - info->rx_std_ctrl.flags = RCB_FLG_TCP_UDP_SUM; + info->rx_std_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR; memset(ap->rx_std_ring, 0, RX_STD_RING_ENTRIES * sizeof(struct rx_desc)); @@ -1328,7 +1376,7 @@ (ap->rx_ring_base_dma + (sizeof(struct rx_desc) * RX_STD_RING_ENTRIES))); info->rx_jumbo_ctrl.max_len = 0; - info->rx_jumbo_ctrl.flags = RCB_FLG_TCP_UDP_SUM; + info->rx_jumbo_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR; memset(ap->rx_jumbo_ring, 0, RX_JUMBO_RING_ENTRIES * sizeof(struct rx_desc)); @@ -1349,7 +1397,7 @@ (RX_STD_RING_ENTRIES + RX_JUMBO_RING_ENTRIES)))); info->rx_mini_ctrl.max_len = ACE_MINI_SIZE; - info->rx_mini_ctrl.flags = RCB_FLG_TCP_UDP_SUM; + info->rx_mini_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR; for (i = 0; i < RX_MINI_RING_ENTRIES; i++) ap->rx_mini_ring[i].flags = @@ -1384,13 +1432,10 @@ set_aceaddr(&info->tx_ctrl.rngptr, ap->tx_ring_dma); info->tx_ctrl.max_len = TX_RING_ENTRIES; - - tmp = 0; + tmp = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR|RCB_FLG_TX_HOST_RING; #if TX_COAL_INTS_ONLY tmp |= RCB_FLG_COAL_INT_ONLY; #endif - tmp |= RCB_FLG_TX_HOST_RING; - info->tx_ctrl.flags = tmp; set_aceaddr(&info->tx_csm_ptr, ap->tx_csm_dma); @@ -1398,8 +1443,13 @@ /* * Potential item for tuning parameter */ +#if 0 /* NO */ + writel(DMA_THRESH_16W, ®s->DmaReadCfg); + writel(DMA_THRESH_16W, ®s->DmaWriteCfg); +#else writel(DMA_THRESH_8W, ®s->DmaReadCfg); writel(DMA_THRESH_8W, ®s->DmaWriteCfg); +#endif writel(0, ®s->MaskInt); writel(1, ®s->IfIdx); @@ -1430,7 +1480,7 @@ if (trace[board_idx]) writel(trace[board_idx], ®s->TuneTrace); - if ((tx_ratio[board_idx] >= 0) && (tx_ratio[board_idx] < 64)) + if ((tx_ratio[board_idx] > 0) && (tx_ratio[board_idx] < 64)) writel(tx_ratio[board_idx], ®s->TxBufRat); } @@ -1501,7 +1551,6 @@ * tx ints before we are up and running, which may cause a null * pointer access in the int handler. */ - ap->tx_full = 0; ap->cur_rx = 0; ap->tx_prd = *(ap->tx_csm) = ap->tx_ret_csm = 0; @@ -1510,6 +1559,11 @@ writel(0, ®s->RxRetCsm); /* + * Zero the stats before starting the interface + */ + memset(&ap->stats, 0, sizeof(ap->stats)); + + /* * Start the NIC CPU */ writel(readl(®s->CpuCtrl) & ~(CPU_HALT|CPU_TRACE), ®s->CpuCtrl); @@ -1611,12 +1665,9 @@ } -/* - * Monitor the card to detect hangs. - */ -static void ace_timer(unsigned long data) +static void ace_watchdog(struct net_device *data) { - struct net_device *dev = (struct net_device *)data; + struct net_device *dev = data; struct ace_private *ap = dev->priv; struct ace_regs *regs = ap->regs; @@ -1628,13 +1679,13 @@ if (*ap->tx_csm != ap->tx_ret_csm) { printk(KERN_WARNING "%s: Transmitter is stuck, %08x\n", dev->name, (unsigned int)readl(®s->HostCtrl)); + /* This can happen due to ieee flow control. */ + } else { + printk(KERN_DEBUG "%s: BUG... transmitter died. Kicking it.\n", dev->name); + netif_wake_queue(dev); } - - ap->timer.expires = jiffies + (5/2*HZ); - add_timer(&ap->timer); } - static void ace_tasklet(unsigned long dev) { struct ace_private *ap = ((struct net_device *)dev)->priv; @@ -1719,7 +1770,9 @@ ACE_STD_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); ap->skb->rx_std_skbuff[idx].skb = skb; +#ifndef DUMMY_PCI_UNMAP ap->skb->rx_std_skbuff[idx].mapping = mapping; +#endif rd = &ap->rx_std_ring[idx]; set_aceaddr(&rd->addr, mapping); @@ -1781,7 +1834,9 @@ ACE_MINI_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); ap->skb->rx_mini_skbuff[idx].skb = skb; +#ifndef DUMMY_PCI_UNMAP ap->skb->rx_mini_skbuff[idx].mapping = mapping; +#endif rd = &ap->rx_mini_ring[idx]; set_aceaddr(&rd->addr, mapping); @@ -1840,7 +1895,9 @@ ACE_JUMBO_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); ap->skb->rx_jumbo_skbuff[idx].skb = skb; +#ifndef DUMMY_PCI_UNMAP ap->skb->rx_jumbo_skbuff[idx].mapping = mapping; +#endif rd = &ap->rx_jumbo_ring[idx]; set_aceaddr(&rd->addr, mapping); @@ -1870,8 +1927,9 @@ clear_bit(0, &ap->jumbo_refill_busy); return; error_out: - printk(KERN_INFO "Out of memory when allocating " - "jumbo receive buffers\n"); + if (net_ratelimit()) + printk(KERN_INFO "Out of memory when allocating " + "jumbo receive buffers\n"); goto out; } @@ -1902,9 +1960,16 @@ u16 code = ap->evt_ring[evtcsm].code; switch (code) { case E_C_LINK_UP: - printk(KERN_WARNING "%s: Optical link UP\n", - dev->name); + { + u32 state = readl(&ap->regs->GigLnkState); + printk(KERN_WARNING "%s: Optical link UP " + "(%s Duplex, Flow Control: %s%s)\n", + dev->name, + state & LNK_FULL_DUPLEX ? "Full":"Half", + state & LNK_TX_FLOW_CTL_Y ? "TX " : "", + state & LNK_RX_FLOW_CTL_Y ? "RX" : ""); break; + } case E_C_LINK_DOWN: printk(KERN_WARNING "%s: Optical link DOWN\n", dev->name); @@ -1965,8 +2030,6 @@ ap->rx_jumbo_skbprd = 0; printk(KERN_INFO "%s: Jumbo ring flushed\n", dev->name); - if (!ap->tx_full) - netif_wake_queue(dev); clear_bit(0, &ap->jumbo_refill_busy); break; } @@ -1994,12 +2057,13 @@ struct sk_buff *skb; struct rx_desc *rxdesc, *retdesc; u32 skbidx; - int desc_type, mapsize; + int bd_flags, desc_type, mapsize; u16 csum; retdesc = &ap->rx_return_ring[idx]; skbidx = retdesc->idx; - desc_type = retdesc->flags & (BD_FLG_JUMBO | BD_FLG_MINI); + bd_flags = retdesc->flags; + desc_type = bd_flags & (BD_FLG_JUMBO | BD_FLG_MINI); switch(desc_type) { /* @@ -2036,8 +2100,10 @@ skb = rip->skb; rip->skb = NULL; +#ifndef DUMMY_PCI_UNMAP pci_unmap_single(ap->pdev, rip->mapping, mapsize, PCI_DMA_FROMDEVICE); +#endif skb_put(skb, retdesc->size); #if 0 /* unncessary */ @@ -2053,15 +2119,15 @@ skb->protocol = eth_type_trans(skb, dev); /* - * If the checksum is correct and this is not a - * fragment, tell the stack that the data is correct. + * Instead of forcing the poor tigon mips cpu to calculate + * pseudo hdr checksum, we do this ourselves. */ - if(!(csum ^ 0xffff) && - (!(((struct iphdr *)skb->data)->frag_off & - __constant_htons(IP_MF|IP_OFFSET)))) - skb->ip_summed = CHECKSUM_UNNECESSARY; - else + if (bd_flags & BD_FLG_TCP_UDP_SUM) { + skb->csum = htons(csum); + skb->ip_summed = CHECKSUM_HW; + } else { skb->ip_summed = CHECKSUM_NONE; + } netif_rx(skb); /* send it up */ @@ -2094,6 +2160,75 @@ } +static inline void ace_tx_int(struct net_device *dev, + u32 txcsm, u32 idx) +{ + struct ace_private *ap = dev->priv; + + do { + struct sk_buff *skb; +#ifndef DUMMY_PCI_UNMAP + dma_addr_t mapping; +#endif + struct tx_ring_info *info; + + info = ap->skb->tx_skbuff + idx; + skb = info->skb; +#ifndef DUMMY_PCI_UNMAP + mapping = info->mapping; + + if (mapping) { + pci_unmap_single(ap->pdev, mapping, info->maplen, + PCI_DMA_TODEVICE); + info->mapping = 0; + } +#endif + if (skb) { + ap->stats.tx_packets++; + ap->stats.tx_bytes += skb->len; + dev_kfree_skb_irq(skb); + info->skb = NULL; + } + + idx = (idx + 1) % TX_RING_ENTRIES; + } while (idx != txcsm); + + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + + wmb(); + ap->tx_ret_csm = txcsm; + + /* So... tx_ret_csm is advanced _after_ check for device wakeup. + * + * We could try to make it before. In this case we would get + * the following race condition: hard_start_xmit on other cpu + * enters after we advanced tx_ret_csm and fills space, + * which we have just freed, so that we make illegal device wakeup. + * There is no good way to workaround this (at entry + * to ace_start_xmit detects this condition and prevents + * ring corruption, but it is not a good workaround.) + * + * When tx_ret_csm is advanced after, we wake up device _only_ + * if we really have some space in ring (though the core doing + * hard_start_xmit can see full ring for some period and has to + * synchronize.) Superb. + * BUT! We get another subtle race condition. hard_start_xmit + * may think that ring is full between wakeup and advancing + * tx_ret_csm and will stop device instantly! It is not so bad. + * We are guaranteed that there is something in ring, so that + * the next irq will resume transmission. To speedup this we could + * mark descriptor, which closes ring with BD_FLG_COAL_NOW + * (see ace_start_xmit). + * + * Well, this dilemma exists in all lock-free devices. + * We, following scheme used in drivers by Donald Becker, + * select the least dangerous. + * --ANK + */ +} + + static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) { struct ace_private *ap; @@ -2115,9 +2250,14 @@ return; /* - * Tell the card not to generate interrupts while we are in here. + * ACK intr now. Otherwise we will lose updates to rx_ret_prd, + * which happened _after_ rxretprd = *ap->rx_ret_prd; but before + * writel(0, ®s->Mb0Lo). + * + * "IRQ avoidance" recommended in docs applies to IRQs served + * threads and it is wrong even for that case. */ - writel(1, ®s->Mb0Lo); + writel(0, ®s->Mb0Lo); /* * There is no conflict between transmit handling in @@ -2136,75 +2276,15 @@ idx = ap->tx_ret_csm; if (txcsm != idx) { - do { - 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; - - mapping = ap->skb->tx_skbuff[idx].mapping; - - ap->stats.tx_packets++; - ap->stats.tx_bytes += skb->len; - pci_unmap_single(ap->pdev, mapping, skb->len, - PCI_DMA_TODEVICE); - dev_kfree_skb_irq(skb); - - ap->skb->tx_skbuff[idx].skb = NULL; - } - - /* - * Question here is whether one should not skip - * these writes - I have never seen any errors - * caused by the NIC actually trying to access - * these incorrectly. - */ -#ifdef ACE_64BIT_PTR - ap->tx_ring[idx].addr.addrhi = 0; -#endif - ap->tx_ring[idx].addr.addrlo = 0; - ap->tx_ring[idx].flagsize = 0; - - idx = (idx + 1) % TX_RING_ENTRIES; - } while (idx != txcsm); - /* - * Once we actually get to this point the tx ring has - * already been trimmed thus it cannot be full! - * Ie. skip the comparison of the tx producer vs. the - * consumer. + * If each skb takes only one descriptor this check degenerates + * to identity, because new space has just been opened. + * But if skbs are fragmented we must check that this index + * update releases enough of space, otherwise we just + * wait for device to make more work. */ - if (netif_queue_stopped(dev) && xchg(&ap->tx_full, 0)) { - /* - * This does not need to be atomic (and expensive), - * I've seen cases where it would fail otherwise ;-( - */ - netif_wake_queue(dev); - ace_mark_net_bh(); - - /* - * TX ring is no longer full, aka the - * transmitter is working fine - kill timer. - */ - del_timer(&ap->timer); - } - - ap->tx_ret_csm = txcsm; - wmb(); + if (!tx_ring_full(txcsm, ap->tx_prd)) + ace_tx_int(dev, txcsm, idx); } evtcsm = readl(®s->EvtCsm); @@ -2272,11 +2352,6 @@ tasklet_schedule(&ap->ace_tasklet); } } - - /* - * Allow the card to generate interrupts again - */ - writel(0, ®s->Mb0Lo); } @@ -2296,11 +2371,6 @@ writel(dev->mtu + ETH_HLEN + 4, ®s->IfMtu); - /* - * Zero the stats when restarting the interface... - */ - memset(&ap->stats, 0, sizeof(ap->stats)); - cmd.evt = C_CLEAR_STATS; cmd.code = 0; cmd.idx = 0; @@ -2338,13 +2408,6 @@ ACE_MOD_INC_USE_COUNT; /* - * Setup the timer - */ - init_timer(&ap->timer); - ap->timer.data = (unsigned long)dev; - ap->timer.function = ace_timer; - - /* * Setup the bottom half rx ring refill handler */ tasklet_init(&ap->ace_tasklet, ace_tasklet, (unsigned long)dev); @@ -2361,13 +2424,17 @@ short i; ace_if_down(dev); + + /* + * Without (or before) releasing irq and stopping hardware, this + * is an absolute non-sense, by the way. It will be reset instantly + * by the first irq. + */ netif_stop_queue(dev); ap = dev->priv; regs = ap->regs; - del_timer(&ap->timer); - if (ap->promisc) { cmd.evt = C_SET_PROMISC_MODE; cmd.code = C_C_PROMISC_DISABLE; @@ -2392,16 +2459,26 @@ for (i = 0; i < TX_RING_ENTRIES; i++) { struct sk_buff *skb; +#ifndef DUMMY_PCI_UNMAP dma_addr_t mapping; +#endif + struct tx_ring_info *info; - skb = ap->skb->tx_skbuff[i].skb; - mapping = ap->skb->tx_skbuff[i].mapping; - if (skb) { - memset(&ap->tx_ring[i].addr, 0, sizeof(struct tx_desc)); - pci_unmap_single(ap->pdev, mapping, skb->len, + info = ap->skb->tx_skbuff + i; + skb = info->skb; +#ifndef DUMMY_PCI_UNMAP + mapping = info->mapping; + + if (mapping) { + memset(ap->tx_ring+i, 0, sizeof(struct tx_desc)); + pci_unmap_single(ap->pdev, mapping, info->maplen, PCI_DMA_TODEVICE); + info->mapping = 0; + } +#endif + if (skb) { dev_kfree_skb(skb); - ap->skb->tx_skbuff[i].skb = NULL; + info->skb = NULL; } } @@ -2419,85 +2496,216 @@ } +/* + * Following below should be (in more clean form!) in arch/ARCH/kernel/pci_*. + * For now, let it stay here. + */ +#if defined(CONFIG_HIGHMEM) && MAX_SKB_FRAGS +#ifndef DUMMY_PCI_UNMAP +#error Sorry, cannot DMA from high memory on this architecture. +#endif + +#if defined(CONFIG_X86) +#define DMAADDR_OFFSET 0 +typedef unsigned long long dmaaddr_high_t; +#elif defined(CONFIG_PPC) +#define DMAADDR_OFFSET PCI_DRAM_OFFSET +typedef unsigned long dmaaddr_high_t; +#endif + + +static inline dmaaddr_high_t +pci_map_single_high(struct pci_dev *hwdev, struct page *page, + int offset, size_t size, int dir) +{ + dmaaddr_high_t phys; + + phys = (page-mem_map) * (dmaaddr_high_t) PAGE_SIZE + offset; + + return (phys + DMAADDR_OFFSET); +} + +#else + +typedef unsigned long dmaaddr_high_t; + +static inline dmaaddr_high_t +pci_map_single_high(struct pci_dev *hwdev, struct page *page, + int offset, size_t size, int dir) +{ + return pci_map_single(hwdev, page_address(page) + offset, size, dir); +} + +#endif + + +static inline dmaaddr_high_t +ace_map_tx_skb(struct ace_private *ap, struct sk_buff *skb, + struct sk_buff *tail, u32 idx) +{ + unsigned long addr; + struct tx_ring_info *info; + + addr = pci_map_single(ap->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + + info = ap->skb->tx_skbuff + idx; + info->skb = tail; +#ifndef DUMMY_PCI_UNMAP + info->mapping = addr; + info->maplen = skb->len; +#endif + return addr; +} + + +static inline void +ace_load_tx_bd(struct tx_desc *desc, dmaaddr_high_t addr, u32 flagsize) +{ +#if !USE_TX_COAL_NOW + flagsize &= ~BD_FLG_COAL_NOW; +#endif + +#ifdef ACE_64BIT_PTR + desc->addr.addrhi = addr >> 32; +#endif + desc->addr.addrlo = addr; + desc->flagsize = flagsize; +} + + static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ace_private *ap = dev->priv; struct ace_regs *regs = ap->regs; - unsigned long addr; + struct tx_desc *desc; u32 idx, flagsize; - /* + /* * This only happens with pre-softnet, ie. 2.2.x kernels. - */ + */ if (early_stop_netif_stop_queue(dev)) - return 1; + return 1; + +restart: idx = ap->tx_prd; - if ((idx + 1) % TX_RING_ENTRIES == ap->tx_ret_csm) { - ap->tx_full = 1; -#if DEBUG - printk("%s: trying to transmit while the tx ring is full " - "- this should not happen!\n", dev->name); + if (tx_ring_full(ap->tx_ret_csm, idx)) + goto overflow; + +#if MAX_SKB_FRAGS + if (!skb_shinfo(skb)->nr_frags) #endif - return 1; - } + { + unsigned long addr; - ap->skb->tx_skbuff[idx].skb = skb; - ap->skb->tx_skbuff[idx].mapping = - pci_map_single(ap->pdev, skb->data, skb->len, - PCI_DMA_TODEVICE); - addr = (unsigned long) ap->skb->tx_skbuff[idx].mapping; - flagsize = (skb->len << 16) | (BD_FLG_END) ; - set_aceaddr(&ap->tx_ring[idx].addr, addr); - ap->tx_ring[idx].flagsize = flagsize; - wmb(); - idx = (idx + 1) % TX_RING_ENTRIES; + addr = ace_map_tx_skb(ap, skb, skb, idx); + flagsize = (skb->len << 16) | (BD_FLG_END); + if (skb->ip_summed == CHECKSUM_HW) + flagsize |= BD_FLG_TCP_UDP_SUM; + desc = ap->tx_ring + idx; + idx = (idx + 1) % TX_RING_ENTRIES; + + /* Look at ace_tx_int for explanations. */ + if (tx_ring_full(ap->tx_ret_csm, idx)) + flagsize |= BD_FLG_COAL_NOW; + + ace_load_tx_bd(desc, addr, flagsize); + } +#if MAX_SKB_FRAGS + else { + unsigned long addr; + int i, len = 0; + + addr = ace_map_tx_skb(ap, skb, NULL, idx); + flagsize = ((skb->len - skb->data_len) << 16); + if (skb->ip_summed == CHECKSUM_HW) + flagsize |= BD_FLG_TCP_UDP_SUM; + + ace_load_tx_bd(ap->tx_ring + idx, addr, flagsize); + + idx = (idx + 1) % TX_RING_ENTRIES; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + struct tx_ring_info *info; + dmaaddr_high_t phys; + + len += frag->size; + info = ap->skb->tx_skbuff + idx; + desc = ap->tx_ring + idx; + + phys = pci_map_single_high(ap->pdev, frag->page, + frag->page_offset, + frag->size, + PCI_DMA_TODEVICE); + + flagsize = (frag->size << 16); + if (skb->ip_summed == CHECKSUM_HW) + flagsize |= BD_FLG_TCP_UDP_SUM; + idx = (idx + 1) % TX_RING_ENTRIES; - ap->tx_prd = idx; - ace_set_txprd(regs, ap, idx); + if (i == skb_shinfo(skb)->nr_frags-1) { + flagsize |= BD_FLG_END; + if (tx_ring_full(ap->tx_ret_csm, idx)) + flagsize |= BD_FLG_COAL_NOW; + + /* + * Only the last fragment frees + * the skb! + */ + info->skb = skb; + } else { + info->skb = NULL; + } +#ifndef DUMMY_PCI_UNMAP + info->mapping = phys; + info->maplen = frag->size; +#endif + ace_load_tx_bd(desc, phys, flagsize); + } + } +#endif - /* - * tx_csm is set by the NIC whereas we set tx_ret_csm which - * is always trying to catch tx_csm - */ - if ((idx + 2) % TX_RING_ENTRIES == ap->tx_ret_csm) { - ap->tx_full = 1; - /* - * Queue is full, add timer to detect whether the - * transmitter is stuck. Use mod_timer as we can get - * into the situation where we risk adding several - * timers. - */ - mod_timer(&ap->timer, jiffies + (3 * HZ)); + wmb(); + ap->tx_prd = idx; + ace_set_txprd(regs, ap, idx); + + if (flagsize & BD_FLG_COAL_NOW) { + netif_stop_queue(dev); /* - * The following check will fix a race between the interrupt - * handler increasing the tx_ret_csm and testing for tx_full - * and this tx routine's testing the tx_ret_csm and setting - * the tx_full; note that this fix makes assumptions on the - * ordering of writes (sequential consistency will fly; TSO - * processor order would work too) but that's what lock-less - * programming is all about + * A TX-descriptor producer (an IRQ) might have gotten + * inbetween, making the ring free again. Since xmit is + * serialized, this is the only situation we have to + * re-test. */ - if (((idx + 2) % TX_RING_ENTRIES != ap->tx_ret_csm) - && xchg(&ap->tx_full, 0)) { - del_timer(&ap->timer); - /* - * We may not need this one in the post softnet era - * in this case this can be changed to a - * early_stop_netif_wake_queue(dev); - */ + if (!tx_ring_full(ap->tx_ret_csm, idx)) netif_wake_queue(dev); - } else { - late_stop_netif_stop_queue(dev); - } - } else { - early_stop_netif_wake_queue(dev); } dev->trans_start = jiffies; return 0; + +overflow: + /* + * This race condition is unavoidable with lock-free drivers. + * We wake up the queue _before_ tx_prd is advanced, so that we can + * enter hard_start_xmit too early, while tx ring still looks closed. + * This happens ~1-4 times per 100000 packets, so that we can allow + * to loop syncing to other CPU. Probably, we need an additional + * wmb() in ace_tx_intr as well. + * + * Note that this race is relieved by reserving one more entry + * in tx ring than it is necessary (see original non-SG driver). + * However, with SG we need to reserve 2*MAX_SKB_FRAGS+1, which + * is already overkill. + * + * Alternative is to return with 1 not throttling queue. In this + * case loop becomes longer, no more useful effects. + */ + barrier(); + goto restart; } @@ -2522,7 +2730,6 @@ ace_set_rxtx_parms(dev, 1); } } else { - netif_stop_queue(dev); while (test_and_set_bit(0, &ap->jumbo_refill_busy)); synchronize_irq(); ace_set_rxtx_parms(dev, 0); @@ -2542,27 +2749,12 @@ static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { -#ifdef SIOCETHTOOL struct ace_private *ap = dev->priv; struct ace_regs *regs = ap->regs; +#ifdef SIOCETHTOOL struct ethtool_cmd ecmd; u32 link, speed; -#ifdef SPIN_DEBUG - if (cmd == (SIOCDEVPRIVATE+0x0e)) { - printk(KERN_NOTICE "%s: dumping debug info\n", dev->name); - printk(KERN_NOTICE "%s: tbusy %li, tx_ret_csm %i, " - "tx_prd %i\n", dev->name, dev->tbusy, - ap->tx_ret_csm, ap->tx_prd); - printk(KERN_NOTICE "%s: cur_rx %i, std_refill %li, " - "mini_rx %i, mini_refill %li\n", dev->name, - atomic_read(&ap->cur_rx_bufs), ap->std_refill_busy, - atomic_read(&ap->cur_mini_bufs), ap->mini_refill_busy); - printk(KERN_NOTICE "%s: CpuCtrl %08x\n", - dev->name, readl(®s->CpuCtrl)); - return 0; - } -#endif if (cmd != SIOCETHTOOL) return -EOPNOTSUPP; if (copy_from_user(&ecmd, ifr->ifr_data, sizeof(ecmd))) @@ -2699,7 +2891,8 @@ regs = ((struct ace_private *)dev->priv)->regs; writel(da[0] << 8 | da[1], ®s->MacAddrHi); - writel((da[2] << 24) | (da[3] << 16) | (da[4] << 8) | da[5] , ®s->MacAddrLo); + writel((da[2] << 24) | (da[3] << 16) | (da[4] << 8) | da[5], + ®s->MacAddrLo); cmd.evt = C_SET_MAC_ADDR; cmd.code = 0; @@ -2774,11 +2967,12 @@ ap->stats.multicast = readl(&mac_stats->kept_mc); ap->stats.collisions = readl(&mac_stats->coll); - return(&ap->stats); + return &ap->stats; } -static void __init ace_copy(struct ace_regs *regs, void *src, u32 dest, int size) +static void __init ace_copy(struct ace_regs *regs, void *src, + u32 dest, int size) { unsigned long tdest; u32 *wsrc; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/acenic.h linux.ac/drivers/net/acenic.h --- linux.vanilla/drivers/net/acenic.h Sat Dec 30 19:23:13 2000 +++ linux.ac/drivers/net/acenic.h Sat Apr 14 01:23:34 2001 @@ -1,6 +1,19 @@ #ifndef _ACENIC_H_ #define _ACENIC_H_ + +/* + * Generate TX index update each time, when TX ring is closed. + * Normally, this is not useful, because results in more dma (and irqs + * without TX_COAL_INTS_ONLY). + */ +#define USE_TX_COAL_NOW 0 + +#ifndef MAX_SKB_FRAGS +#define MAX_SKB_FRAGS 0 +#endif + + /* * Addressing: * @@ -258,7 +271,12 @@ * DMA config */ +#define DMA_THRESH_1W 0x10 +#define DMA_THRESH_2W 0x20 +#define DMA_THRESH_4W 0x40 #define DMA_THRESH_8W 0x80 +#define DMA_THRESH_16W 0x100 +#define DMA_THRESH_32W 0x0 /* not described in doc, but exists. */ /* @@ -399,6 +417,7 @@ #define BD_FLG_IP_SUM 0x02 #define BD_FLG_END 0x04 #define BD_FLG_JUMBO 0x10 +#define BD_FLG_COAL_NOW 0x800 #define BD_FLG_MINI 0x1000 @@ -407,6 +426,7 @@ */ #define RCB_FLG_TCP_UDP_SUM 0x01 #define RCB_FLG_IP_SUM 0x02 +#define RCB_FLG_NO_PSEUDO_HDR 0x08 #define RCB_FLG_VLAN_ASSIST 0x10 #define RCB_FLG_COAL_INT_ONLY 0x20 #define RCB_FLG_TX_HOST_RING 0x40 @@ -561,12 +581,29 @@ aceaddr stats2_ptr; }; +#if defined(CONFIG_X86) || defined(CONFIG_PPC) +/* Intel has null pci_unmap_single, no reasons to remember mapping. */ +#define DUMMY_PCI_UNMAP +#endif struct ring_info { struct sk_buff *skb; +#ifndef DUMMY_PCI_UNMAP dma_addr_t mapping; +#endif }; +/* Funny... As soon as we add maplen on alpha, it starts to work + * much slower. Hmm... is it because struct does not fit to one cacheline? + * So, split tx_ring_info. + */ +struct tx_ring_info { + struct sk_buff *skb; +#ifndef DUMMY_PCI_UNMAP + dma_addr_t mapping; + int maplen; +#endif +}; /* * struct ace_skb holding the rings of skb's. This is an awful lot of @@ -575,7 +612,7 @@ */ struct ace_skb { - struct ring_info tx_skbuff[TX_RING_ENTRIES]; + struct tx_ring_info tx_skbuff[TX_RING_ENTRIES]; struct ring_info rx_std_skbuff[RX_STD_RING_ENTRIES]; struct ring_info rx_mini_skbuff[RX_MINI_RING_ENTRIES]; struct ring_info rx_jumbo_skbuff[RX_JUMBO_RING_ENTRIES]; @@ -605,11 +642,10 @@ /* * TX elements */ - struct tx_desc *tx_ring - __attribute__ ((aligned (SMP_CACHE_BYTES))); - struct timer_list timer; /* used by TX handling only */ + struct tx_desc *tx_ring; u32 tx_prd; - volatile u32 tx_full, tx_ret_csm; + volatile u32 tx_ret_csm; + struct timer_list timer; /* * RX elements @@ -657,6 +693,22 @@ }; +#define TX_RESERVED MAX_SKB_FRAGS + +static inline int tx_space (u32 csm, u32 prd) +{ + return (csm - prd - 1) & (TX_RING_ENTRIES - 1); +} + +#define tx_free(ap) tx_space((ap)->tx_ret_csm, (ap)->tx_prd) + +#if MAX_SKB_FRAGS +#define tx_ring_full(csm, prd) (tx_space(csm, prd) <= TX_RESERVED) +#else +#define tx_ring_full 0 +#endif + + static inline void set_aceaddr(aceaddr *aa, dma_addr_t addr) { unsigned long baddr = (unsigned long) addr; @@ -717,14 +769,10 @@ static int ace_open(struct net_device *dev); static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev); static int ace_close(struct net_device *dev); -static void ace_timer(unsigned long data); static void ace_tasklet(unsigned long dev); static void ace_dump_trace(struct ace_private *ap); static void ace_set_multicast_list(struct net_device *dev); static int ace_change_mtu(struct net_device *dev, int new_mtu); -#ifdef SKB_RECYCLE -extern int ace_recycle(struct sk_buff *skb); -#endif static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static int ace_set_mac_addr(struct net_device *dev, void *p); static void ace_set_rxtx_parms(struct net_device *dev, int jumbo); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/aironet4500.h linux.ac/drivers/net/aironet4500.h --- linux.vanilla/drivers/net/aironet4500.h Mon Dec 11 21:00:51 2000 +++ linux.ac/drivers/net/aironet4500.h Sat Apr 14 15:40:56 2001 @@ -1538,7 +1538,6 @@ extern int awc_start_xmit(struct sk_buff *, struct net_device *); extern void awc_interrupt(int irq, void *dev_id, struct pt_regs *regs); extern struct net_device_stats * awc_get_stats(struct net_device *dev); -extern int awc_rx(struct net_device *dev, struct awc_fid * rx_fid); extern void awc_set_multicast_list(struct net_device *dev); extern int awc_change_mtu(struct net_device *dev, int new_mtu); extern int awc_close(struct net_device *dev); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/aironet4500_card.c linux.ac/drivers/net/aironet4500_card.c --- linux.vanilla/drivers/net/aironet4500_card.c Tue Apr 3 17:32:09 2001 +++ linux.ac/drivers/net/aironet4500_card.c Tue Apr 3 17:54:49 2001 @@ -38,6 +38,7 @@ #include <linux/if_arp.h> #include <linux/ioport.h> #include <linux/delay.h> +#include <linux/init.h> #include "aironet4500.h" @@ -59,6 +60,13 @@ #include <linux/pci.h> +static struct pci_device_id aironet4500_card_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_AIRONET, PCI_DEVICE_AIRONET_4800_1, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_AIRONET, PCI_DEVICE_AIRONET_4800, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_AIRONET, PCI_DEVICE_AIRONET_4500, PCI_ANY_ID, PCI_ANY_ID, }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, aironet4500_card_pci_tbl); static int reverse_probe; @@ -492,6 +500,14 @@ } + +static struct isapnp_device_id id_table[] = { + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('A','W','L'), ISAPNP_DEVICE(1), 0 }, + {0} +}; + +MODULE_DEVICE_TABLE(isapnp, id_table); #endif //MODULE #endif /* CONFIG_AIRONET4500_PNP */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/aironet4500_core.c linux.ac/drivers/net/aironet4500_core.c --- linux.vanilla/drivers/net/aironet4500_core.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/aironet4500_core.c Tue Apr 3 17:54:50 2001 @@ -2594,7 +2594,6 @@ EXPORT_SYMBOL(awc_private_init); EXPORT_SYMBOL(awc_tx_timeout); EXPORT_SYMBOL(awc_start_xmit); -//EXPORT_SYMBOL(awc_rx); EXPORT_SYMBOL(awc_interrupt); EXPORT_SYMBOL(awc_get_stats); EXPORT_SYMBOL(awc_change_mtu); @@ -3066,31 +3065,7 @@ return retval; } -inline int awc_rx(struct net_device *dev, struct awc_fid * rx_fid) { - -// struct awc_private *lp = (struct awc_private *)dev->priv; - - DEBUG(3, "%s: in rx_packet \n",dev->name); - - if (!rx_fid ){ - DEBUG(3, "%s: not rx_buff in rx_packet \n",dev->name); - return -1; - }; - if ( !rx_fid->skb){ - DEBUG(3, "%s: not rx_buff->skb in rx_packet \n",dev->name); - return -1; - }; - - - rx_fid->skb->protocol = eth_type_trans(rx_fid->skb,dev); - netif_rx(rx_fid->skb); - rx_fid = NULL; - - return 0; -} - - - void awc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +void awc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; struct awc_private *priv; @@ -3109,8 +3084,6 @@ awc_interrupt_process(dev); my_spin_unlock_irqrestore(&priv->interrupt_spinlock, flags); - - return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/am79c961a.c linux.ac/drivers/net/am79c961a.c --- linux.vanilla/drivers/net/am79c961a.c Tue Feb 13 21:15:04 2001 +++ linux.ac/drivers/net/am79c961a.c Sat Apr 14 01:23:46 2001 @@ -637,7 +637,7 @@ static void __init am79c961_banner(void) { - static unsigned version_printed = 0; + static unsigned version_printed; if (net_debug && version_printed++ == 0) printk(KERN_INFO "%s", version); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/apne.c linux.ac/drivers/net/apne.c --- linux.vanilla/drivers/net/apne.c Tue Nov 28 01:11:26 2000 +++ linux.ac/drivers/net/apne.c Sat Apr 14 01:23:46 2001 @@ -119,7 +119,7 @@ static const char *version = "apne.c:v1.1 7/10/98 Alain Malek (Alain.Malek@cryogen.ch)\n"; -static int apne_owned = 0; /* signal if card already owned */ +static int apne_owned; /* signal if card already owned */ int __init apne_probe(struct net_device *dev) { @@ -173,7 +173,7 @@ #ifndef MANUAL_HWADDR0 int neX000, ctron; #endif - static unsigned version_printed = 0; + static unsigned version_printed; static u32 pcmcia_offsets[16]={ 0, 1+GAYLE_ODD, 2, 3+GAYLE_ODD, 4, 5+GAYLE_ODD, 6, 7+GAYLE_ODD, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/appletalk/ipddp.c linux.ac/drivers/net/appletalk/ipddp.c --- linux.vanilla/drivers/net/appletalk/ipddp.c Mon Dec 4 01:45:22 2000 +++ linux.ac/drivers/net/appletalk/ipddp.c Tue Apr 3 17:54:50 2001 @@ -20,12 +20,9 @@ * Director, National Security Agency. * * This software may be used and distributed according to the terms - * of the GNU Public License, incorporated herein by reference. + * of the GNU General Public License, incorporated herein by reference. */ -static const char *version = - "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n"; - #include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> @@ -39,7 +36,9 @@ #include "ipddp.h" /* Our stuff */ -static struct ipddp_route *ipddp_route_list = NULL; +static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n"; + +static struct ipddp_route *ipddp_route_list; #ifdef CONFIG_IPDDP_ENCAP static int ipddp_mode = IPDDP_ENCAP; @@ -47,12 +46,6 @@ static int ipddp_mode = IPDDP_DECAP; #endif -/* Use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */ -#ifndef IPDDP_DEBUG -#define IPDDP_DEBUG 1 -#endif -static unsigned int ipddp_debug = IPDDP_DEBUG; - /* Index to functions, as function prototypes. */ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev); static struct net_device_stats *ipddp_get_stats(struct net_device *dev); @@ -64,12 +57,12 @@ static int __init ipddp_init(struct net_device *dev) { - static unsigned version_printed = 0; + static unsigned version_printed; SET_MODULE_OWNER(dev); - if (ipddp_debug && version_printed++ == 0) - printk("%s", version); + if (version_printed++ == 0) + printk(version); /* Let the user now what mode we are in */ if(ipddp_mode == IPDDP_ENCAP) @@ -193,25 +186,23 @@ static int ipddp_create(struct ipddp_route *new_rt) { struct ipddp_route *rt =(struct ipddp_route*) kmalloc(sizeof(*rt), GFP_KERNEL); - struct ipddp_route *test; - if(rt == NULL) + if (rt == NULL) return -ENOMEM; rt->ip = new_rt->ip; rt->at = new_rt->at; rt->next = NULL; - rt->dev = atrtr_get_dev(&rt->at); - if(rt->dev == NULL) - { - kfree(rt); - return (-ENETUNREACH); + if ((rt->dev = atrtr_get_dev(&rt->at)) == NULL) { + kfree(rt); + return -ENETUNREACH; } - test = ipddp_find_route(rt); - if(test != NULL) - return (-EEXIST); - + if (ipddp_find_route(rt)) { + kfree(rt); + return -EEXIST; + } + rt->next = ipddp_route_list; ipddp_route_list = rt; @@ -307,11 +298,16 @@ static void __exit ipddp_cleanup_module(void) { + struct ipddp_route *p; + unregister_netdev(&dev_ipddp); kfree(dev_ipddp.priv); - memset(&dev_ipddp, 0, sizeof(dev_ipddp)); - dev_ipddp.init = ipddp_init; + while (ipddp_route_list) { + p = ipddp_route_list->next; + kfree(ipddp_route_list); + ipddp_route_list = p; + } } module_init(ipddp_init_module); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/arcnet/arcnet.c linux.ac/drivers/net/arcnet/arcnet.c --- linux.vanilla/drivers/net/arcnet/arcnet.c Tue Apr 3 17:32:09 2001 +++ linux.ac/drivers/net/arcnet/arcnet.c Tue Apr 3 17:54:50 2001 @@ -528,7 +528,7 @@ struct arcnet_local *lp = (struct arcnet_local *) dev->priv; int status = 0; /* default is failure */ unsigned short type; - uint8_t daddr; + uint8_t daddr=0; if (skb->nh.raw - skb->mac.raw != 2) { BUGMSG(D_NORMAL, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/ariadne.c linux.ac/drivers/net/ariadne.c --- linux.vanilla/drivers/net/ariadne.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/ariadne.c Sat Apr 14 01:23:46 2001 @@ -121,7 +121,7 @@ }; #ifdef MODULE -static struct ariadne_private *root_ariadne_dev = NULL; +static struct ariadne_private *root_ariadne_dev; #endif static int ariadne_open(struct net_device *dev); @@ -160,24 +160,29 @@ unsigned long board = z->resource.start; unsigned long base_addr = board+ARIADNE_LANCE; unsigned long mem_start = board+ARIADNE_RAM; + struct resource *r1, *r2; - if (!request_mem_region(base_addr, sizeof(struct Am79C960), - "Am79C960")) - continue; - if (!request_mem_region(mem_start, ARIADNE_RAM_SIZE, "RAM")) { - release_mem_region(base_addr, sizeof(struct Am79C960)); + r1 = request_mem_region(base_addr, sizeof(struct Am79C960), + "Am79C960"); + if (!r1) continue; + r2 = request_mem_region(mem_start, ARIADNE_RAM_SIZE, "RAM"); + if (!r2) { + release_resource(r1); continue; } dev = init_etherdev(NULL, sizeof(struct ariadne_private)); if (dev == NULL) { - release_mem_region(base_addr, sizeof(struct Am79C960)); - release_mem_region(mem_start, ARIADNE_RAM_SIZE); + release_resource(r1); + release_resource(r2); return -ENOMEM; } - priv = (struct ariadne_private *)dev->priv; - memset(priv, 0, sizeof(struct ariadne_private)); + SET_MODULE_OWNER(dev); + priv = dev->priv; + + r1->name = dev->name; + r2->name = dev->name; priv->dev = dev; dev->dev_addr[0] = 0x00; @@ -218,6 +223,7 @@ volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; u_short in; u_long version; + int i; /* Reset the LANCE */ in = lance->Reset; @@ -307,15 +313,13 @@ netif_start_queue(dev); - if (request_irq(IRQ_AMIGA_PORTS, ariadne_interrupt, SA_SHIRQ, - "Ariadne Ethernet", dev)) - return -EAGAIN; + i = request_irq(IRQ_AMIGA_PORTS, ariadne_interrupt, SA_SHIRQ, + dev->name, dev); + if (i) return i; lance->RAP = CSR0; /* PCnet-ISA Controller Status */ lance->RDP = INEA|STRT; - MOD_INC_USE_COUNT; - return 0; } @@ -388,8 +392,6 @@ lance->RDP = STOP; free_irq(IRQ_AMIGA_PORTS, dev); - - MOD_DEC_USE_COUNT; return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/ariadne2.c linux.ac/drivers/net/ariadne2.c --- linux.vanilla/drivers/net/ariadne2.c Thu Jan 4 21:00:55 2001 +++ linux.ac/drivers/net/ariadne2.c Sat Apr 14 01:23:46 2001 @@ -62,7 +62,7 @@ #define WORDSWAP(a) ((((a)>>8)&0xff) | ((a)<<8)) #ifdef MODULE -static struct net_device *root_ariadne2_dev = NULL; +static struct net_device *root_ariadne2_dev; #endif static const struct card_info { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/arlan-proc.c linux.ac/drivers/net/arlan-proc.c --- linux.vanilla/drivers/net/arlan-proc.c Tue Apr 3 17:32:09 2001 +++ linux.ac/drivers/net/arlan-proc.c Sat Apr 14 01:23:46 2001 @@ -1031,7 +1031,7 @@ -static struct ctl_table_header *arlan_device_sysctl_header = NULL; +static struct ctl_table_header *arlan_device_sysctl_header; int init_arlan_proc(void) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/atari_bionet.c linux.ac/drivers/net/atari_bionet.c --- linux.vanilla/drivers/net/atari_bionet.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/atari_bionet.c Sat Apr 14 01:23:46 2001 @@ -327,8 +327,8 @@ int __init bionet_probe(struct net_device *dev){ unsigned char station_addr[6]; - static unsigned version_printed = 0; - static int no_more_found = 0; /* avoid "Probing for..." printed 4 times */ + static unsigned version_printed; + static int no_more_found; /* avoid "Probing for..." printed 4 times */ int i; if (!MACH_IS_ATARI || no_more_found) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/atari_pamsnet.c linux.ac/drivers/net/atari_pamsnet.c --- linux.vanilla/drivers/net/atari_pamsnet.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/atari_pamsnet.c Sat Apr 14 01:23:53 2001 @@ -569,9 +569,9 @@ HADDR *hwaddr; unsigned char station_addr[6]; - static unsigned version_printed = 0; + static unsigned version_printed; /* avoid "Probing for..." printed 4 times - the driver is supporting only one adapter now! */ - static int no_more_found = 0; + static int no_more_found; if (no_more_found) return -ENODEV; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/atp.c linux.ac/drivers/net/atp.c --- linux.vanilla/drivers/net/atp.c Tue Apr 3 17:32:10 2001 +++ linux.ac/drivers/net/atp.c Sat Apr 14 01:23:53 2001 @@ -209,7 +209,7 @@ /* A list of all installed ATP devices, for removing the driver module. */ -static struct net_device *root_atp_dev = NULL; +static struct net_device *root_atp_dev; /* Check for a network adapter of this type, and return '0' iff one exists. If dev->base_addr == 0, probe all likely locations. @@ -584,7 +584,7 @@ struct net_device *dev = (struct net_device *)dev_instance; struct net_local *lp; long ioaddr; - static int num_tx_since_rx = 0; + static int num_tx_since_rx; int boguscount = max_interrupt_work; if (dev == NULL) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/bagetlance.c linux.ac/drivers/net/bagetlance.c --- linux.vanilla/drivers/net/bagetlance.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/bagetlance.c Sat Apr 14 01:23:53 2001 @@ -471,7 +471,7 @@ int __init bagetlance_probe( struct net_device *dev ) { int i; - static int found = 0; + static int found; SET_MODULE_OWNER(dev); @@ -519,7 +519,7 @@ struct lance_private *lp; struct lance_ioreg *IO; int i; - static int did_version = 0; + static int did_version; unsigned short save1, save2; PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n", diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/bmac.c linux.ac/drivers/net/bmac.c --- linux.vanilla/drivers/net/bmac.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/bmac.c Tue Apr 3 23:36:56 2001 @@ -6,6 +6,8 @@ * * May 1999, Al Viro: proper release of /proc/net/bmac entry, switched to * dynamic procfs inode. + * Jan 2001, Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * restore_flags on failure in bmac_reset_and_enable */ #include <linux/config.h> #include <linux/module.h> @@ -76,9 +78,6 @@ struct net_device_stats stats; struct timer_list tx_timeout; int timeout_active; - int reset_and_enabled; - int rx_allocated; - int tx_allocated; unsigned short hash_use_count[64]; unsigned short hash_table_mask[4]; struct net_device *next_bmac; @@ -126,6 +125,7 @@ }; static struct net_device *bmac_devs; +static unsigned char *bmac_emergency_rxbuf; #ifdef CONFIG_PMAC_PBOOK static int bmac_sleep_notify(struct pmu_sleep_notifier *self, int when); @@ -151,9 +151,9 @@ static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev); static struct net_device_stats *bmac_stats(struct net_device *dev); static void bmac_set_multicast(struct net_device *dev); -static int bmac_reset_and_enable(struct net_device *dev, int enable); +static void bmac_reset_and_enable(struct net_device *dev); static void bmac_start_chip(struct net_device *dev); -static int bmac_init_chip(struct net_device *dev); +static void bmac_init_chip(struct net_device *dev); static void bmac_init_registers(struct net_device *dev); static void bmac_reset_chip(struct net_device *dev); static int bmac_set_address(struct net_device *dev, void *addr); @@ -184,6 +184,7 @@ return swap; } +#ifdef notused static void dbdma_stop(volatile struct dbdma_regs *dmap) { @@ -194,6 +195,7 @@ while (dbdma_ld32((volatile unsigned long *)&dmap->status) & (ACTIVE|FLUSH)) eieio(); } +#endif /* notused */ static void dbdma_continue(volatile struct dbdma_regs *dmap) @@ -467,12 +469,11 @@ } } -static int +static void bmac_init_chip(struct net_device *dev) { bmac_init_phy(dev); bmac_init_registers(dev); - return 1; } #ifdef CONFIG_PMAC_PBOOK @@ -503,7 +504,7 @@ break; case PBOOK_WAKE: /* see if this is enough */ - bmac_reset_and_enable(bmac_devs, 1); + bmac_reset_and_enable(bmac_devs); enable_irq(bmac_devs->irq); enable_irq(bp->tx_dma_intr); enable_irq(bp->rx_dma_intr); @@ -569,9 +570,12 @@ } static void -bmac_construct_rxbuff(unsigned char *addr, volatile struct dbdma_cmd *cp) +bmac_construct_rxbuff(struct sk_buff *skb, volatile struct dbdma_cmd *cp) { - dbdma_setcmd(cp, (INPUT_LAST | INTR_ALWAYS), RX_BUFLEN, virt_to_bus(addr), 0); + unsigned char *addr = skb? skb->data: bmac_emergency_rxbuf; + + dbdma_setcmd(cp, (INPUT_LAST | INTR_ALWAYS), RX_BUFLEN, + virt_to_bus(addr), 0); } /* Bit-reverse one byte of an ethernet hardware address. */ @@ -586,7 +590,7 @@ } -static int +static void bmac_init_tx_ring(struct bmac_data *bp) { volatile struct dbdma_regs *td = bp->tx_dma; @@ -605,9 +609,6 @@ dbdma_reset(td); out_le32(&td->wait_sel, 0x00200020); out_le32(&td->cmdptr, virt_to_bus(bp->tx_cmds)); - - return 1; - } static int @@ -615,22 +616,20 @@ { volatile struct dbdma_regs *rd = bp->rx_dma; int i; + struct sk_buff *skb; /* initialize list of sk_buffs for receiving and set up recv dma */ - if (!bp->rx_allocated) { - for (i = 0; i < N_RX_RING; i++) { - bp->rx_bufs[i] = dev_alloc_skb(RX_BUFLEN+2); - if (bp->rx_bufs[i] == NULL) - return 0; - skb_reserve(bp->rx_bufs[i], 2); + memset((char *)bp->rx_cmds, 0, + (N_RX_RING + 1) * sizeof(struct dbdma_cmd)); + for (i = 0; i < N_RX_RING; i++) { + if ((skb = bp->rx_bufs[i]) == NULL) { + bp->rx_bufs[i] = skb = dev_alloc_skb(RX_BUFLEN+2); + if (skb != NULL) + skb_reserve(skb, 2); } - bp->rx_allocated = 1; + bmac_construct_rxbuff(skb, &bp->rx_cmds[i]); } - memset((char *)bp->rx_cmds, 0, (N_RX_RING+1) * sizeof(struct dbdma_cmd)); - for (i = 0; i < N_RX_RING; i++) - bmac_construct_rxbuff(bp->rx_bufs[i]->data, &bp->rx_cmds[i]); - bp->rx_empty = 0; bp->rx_fill = i; @@ -706,27 +705,35 @@ cp = &bp->rx_cmds[i]; stat = ld_le16(&cp->xfer_status); residual = ld_le16(&cp->res_count); - if ((stat & ACTIVE) == 0) break; + if ((stat & ACTIVE) == 0) + break; nb = RX_BUFLEN - residual - 2; if (nb < (ETHERMINPACKET - ETHERCRC)) { skb = NULL; bp->stats.rx_length_errors++; bp->stats.rx_errors++; - } else skb = bp->rx_bufs[i]; + } else { + skb = bp->rx_bufs[i]; + bp->rx_bufs[i] = NULL; + } if (skb != NULL) { nb -= ETHERCRC; skb_put(skb, nb); skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - bp->rx_bufs[i] = dev_alloc_skb(RX_BUFLEN+2); - skb_reserve(bp->rx_bufs[i], 2); - bmac_construct_rxbuff(bp->rx_bufs[i]->data, &bp->rx_cmds[i]); ++bp->stats.rx_packets; bp->stats.rx_bytes += nb; } else { ++bp->stats.rx_dropped; } + dev->last_rx = jiffies; + if ((skb = bp->rx_bufs[i]) == NULL) { + bp->rx_bufs[i] = skb = dev_alloc_skb(RX_BUFLEN+2); + if (skb != NULL) + skb_reserve(bp->rx_bufs[i], 2); + } + bmac_construct_rxbuff(skb, &bp->rx_cmds[i]); st_le16(&cp->res_count, 0); st_le16(&cp->xfer_status, 0); last = i; @@ -772,7 +779,13 @@ if (txintcount < 10) { XXDEBUG(("bmac_txdma_xfer_stat=%#0x\n", stat)); } - if (!(stat & ACTIVE)) break; + if (!(stat & ACTIVE)) { + /* + * status field might not have been filled by DBDMA + */ + if (cp == bus_to_virt(in_le32(&bp->tx_dma->cmdptr))) + break; + } if (bp->tx_bufs[bp->tx_empty]) { ++bp->stats.tx_packets; @@ -1215,7 +1228,7 @@ } } -static int bmac_reset_and_enable(struct net_device *dev, int enable) +static void bmac_reset_and_enable(struct net_device *dev) { struct bmac_data *bp = dev->priv; unsigned long flags; @@ -1223,22 +1236,19 @@ unsigned char *data; save_flags(flags); cli(); - bp->reset_and_enabled = 0; bmac_reset_chip(dev); - if (enable) { - if (!bmac_init_tx_ring(bp) || !bmac_init_rx_ring(bp)) - return 0; - if (!bmac_init_chip(dev)) - return 0; - bmac_start_chip(dev); - bmwrite(dev, INTDISABLE, EnableNormal); - bp->reset_and_enabled = 1; - - /* - * It seems that the bmac can't receive until it's transmitted - * a packet. So we give it a dummy packet to transmit. - */ - skb = dev_alloc_skb(ETHERMINPACKET); + bmac_init_tx_ring(bp); + bmac_init_rx_ring(bp); + bmac_init_chip(dev); + bmac_start_chip(dev); + bmwrite(dev, INTDISABLE, EnableNormal); + + /* + * It seems that the bmac can't receive until it's transmitted + * a packet. So we give it a dummy packet to transmit. + */ + skb = dev_alloc_skb(ETHERMINPACKET); + if (skb != NULL) { data = skb_put(skb, ETHERMINPACKET); memset(data, 0, ETHERMINPACKET); memcpy(data, dev->dev_addr, 6); @@ -1247,12 +1257,20 @@ } restore_flags(flags); return 1; + +out_free: + kfree_skb(skb); +out: + restore_flags(flags); + return 0; } static int __init bmac_probe(void) { struct device_node *bmac; + MOD_INC_USE_COUNT; + for (bmac = find_devices("bmac"); bmac != 0; bmac = bmac->next) bmac_probe1(bmac, 0); for (bmac = find_compatible_devices("network", "bmac+"); bmac != 0; @@ -1265,7 +1283,10 @@ pmu_register_sleep_notifier(&bmac_sleep_notifier); #endif } - return 0; + + MOD_DEC_USE_COUNT; + + return bmac_devs? 0: -ENODEV; } static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus) @@ -1290,6 +1311,14 @@ } } + if (bmac_emergency_rxbuf == NULL) { + bmac_emergency_rxbuf = kmalloc(RX_BUFLEN, GFP_KERNEL); + if (bmac_emergency_rxbuf == NULL) { + printk(KERN_ERR "BMAC: can't allocate emergency RX buffer\n"); + return; + } + } + dev = init_etherdev(NULL, PRIV_BYTES); if (!dev) { printk(KERN_ERR "init_etherdev failed, out of memory for BMAC %s\n", @@ -1390,9 +1419,7 @@ { /* XXDEBUG(("bmac: enter open\n")); */ /* reset the chip */ - if (!bmac_reset_and_enable(dev, 1)) - return -ENOMEM; - + bmac_reset_and_enable(dev); dev->flags |= IFF_RUNNING; return 0; } @@ -1428,7 +1455,6 @@ bp->rx_bufs[i] = NULL; } } - bp->rx_allocated = 0; XXDEBUG(("bmac: free tx bufs\n")); for (i = 0; i<N_TX_RING; i++) { if (bp->tx_bufs[i] != NULL) { @@ -1436,7 +1462,6 @@ bp->tx_bufs[i] = NULL; } } - bp->reset_and_enabled = 0; XXDEBUG(("bmac: all bufs freed\n")); return 0; @@ -1607,6 +1632,11 @@ { struct bmac_data *bp; struct net_device *dev; + + if (bmac_emergency_rxbuf != NULL) { + kfree(bmac_emergency_rxbuf); + bmac_emergency_rxbuf = NULL; + } if (bmac_devs == 0) return; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/bsd_comp.c linux.ac/drivers/net/bsd_comp.c --- linux.vanilla/drivers/net/bsd_comp.c Tue Feb 13 21:15:04 2001 +++ linux.ac/drivers/net/bsd_comp.c Tue Apr 3 17:54:50 2001 @@ -185,7 +185,7 @@ static int bsd_decompress (void *state, unsigned char *ibuf, int isize, unsigned char *obuf, int osize); -/* These are in ppp.c */ +/* These are in ppp_generic.c */ extern int ppp_register_compressor (struct compressor *cp); extern void ppp_unregister_compressor (struct compressor *cp); @@ -1158,7 +1158,7 @@ * Module support routines *************************************************************/ -int bsdcomp_init(void) +int __init bsdcomp_init(void) { int answer = ppp_register_compressor(&ppp_bsd_compress); if (answer == 0) @@ -1166,7 +1166,7 @@ return answer; } -void bsdcomp_cleanup(void) +void __exit bsdcomp_cleanup(void) { ppp_unregister_compressor(&ppp_bsd_compress); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/cs89x0.c linux.ac/drivers/net/cs89x0.c --- linux.vanilla/drivers/net/cs89x0.c Tue Apr 3 17:32:10 2001 +++ linux.ac/drivers/net/cs89x0.c Sat Apr 14 01:24:03 2001 @@ -130,7 +130,6 @@ #include <asm/dma.h> #endif #include <linux/errno.h> -#include <linux/init.h> #include <linux/spinlock.h> #include <linux/netdevice.h> @@ -361,7 +360,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr) { struct net_local *lp; - static unsigned version_printed = 0; + static unsigned version_printed; int i; unsigned rev_type = 0; int eeprom_buff[CHKSUM_LEN]; @@ -1590,14 +1589,14 @@ * avoid breaking someone's startup scripts */ -static int io=0; -static int irq=0; -static int debug=0; +static int io; +static int irq; +static int debug; static char media[8]; static int duplex=-1; -static int use_dma = 0; /* These generate unused var warnings if ALLOW_DMA = 0 */ -static int dma=0; +static int use_dma; /* These generate unused var warnings if ALLOW_DMA = 0 */ +static int dma; static int dmasize=16; /* or 64 */ MODULE_PARM(io, "i"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/daynaport.c linux.ac/drivers/net/daynaport.c --- linux.vanilla/drivers/net/daynaport.c Tue Apr 3 17:32:10 2001 +++ linux.ac/drivers/net/daynaport.c Sat Apr 14 01:24:17 2001 @@ -250,12 +250,12 @@ int __init mac8390_probe(struct net_device *dev) { - static int slots = 0; + static int slots; volatile unsigned short *i; volatile unsigned char *p; int plen; int id; - static struct nubus_dev* ndev = NULL; + static struct nubus_dev* ndev; /* Find the first card that hasn't already been seen */ while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/de4x5.c linux.ac/drivers/net/de4x5.c --- linux.vanilla/drivers/net/de4x5.c Tue Apr 3 17:32:10 2001 +++ linux.ac/drivers/net/de4x5.c Sat Apr 14 01:24:17 2001 @@ -429,11 +429,17 @@ <mporter@eng.mcd.mot.com> Remove double checking for DEBUG_RX in de4x5_dbg_rx() from report by <geert@linux-m68k.org> - + 0.546 22-Feb-01 Fixes Alpha XP1000 oops. The srom_search function + was causing a page fault when initializing the + variable 'pb', on a non de4x5 PCI device, in this + case a PCI bridge (DEC chip 21152). The value of + 'pb' is now only initialized if a de4x5 chip is + present. + <france@handhelds.org> ========================================================================= */ -static const char *version = "de4x5.c:V0.545 1999/11/28 davies@maniac.ultranet.com\n"; +static const char *version = "de4x5.c:V0.546 2001/02/22 davies@maniac.ultranet.com\n"; #include <linux/config.h> #include <linux/module.h> @@ -585,7 +591,7 @@ #ifdef DE4X5_PARM static char *args = DE4X5_PARM; #else -static char *args = NULL; +static char *args; #endif struct parameters { @@ -666,7 +672,7 @@ #define DESC_ALIGN #ifndef DEC_ONLY /* See README.de4x5 for using this */ -static int dec_only = 0; +static int dec_only; #else static int dec_only = 1; #endif @@ -1039,24 +1045,24 @@ MODULE_PARM(dec_only, "i"); MODULE_PARM(args, "s"); # else -static int loading_module = 0; +static int loading_module; #endif /* MODULE */ static char name[DE4X5_NAME_LENGTH + 1]; #if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__) static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST; -static int lastEISA = 0; +static int lastEISA; # ifdef DE4X5_FORCE_EISA /* Force an EISA bus probe or not */ static int forceEISA = 1; # else -static int forceEISA = 0; +static int forceEISA; # endif #endif -static int num_de4x5s = 0; -static int cfrv = 0, useSROM = 0; +static int num_de4x5s; +static int cfrv, useSROM; static int lastPCI = -1; -static struct net_device *lastModule = NULL; -static struct pci_dev *pdev = NULL; +static struct net_device *lastModule; +static struct pci_dev *pdev; /* ** List the SROM infoleaf functions and chipsets @@ -2304,12 +2310,12 @@ /* Skip the pci_bus list entry */ if (list_entry(walk, struct pci_bus, devices) == dev->bus) continue; - pb = this_dev->bus->number; vendor = this_dev->vendor; device = this_dev->device << 8; if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue; /* Get the chip configuration revision register */ + pb = this_dev->bus->number; pcibios_read_config_dword(pb, this_dev->devfn, PCI_REVISION_ID, &cfrv); /* Set the device number information */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/de600.c linux.ac/drivers/net/de600.c --- linux.vanilla/drivers/net/de600.c Tue Apr 3 17:32:10 2001 +++ linux.ac/drivers/net/de600.c Sat Apr 14 01:24:24 2001 @@ -265,14 +265,14 @@ /* * D-Link driver variables: */ -static volatile int rx_page = 0; +static volatile int rx_page; #define TX_PAGES 2 static volatile int tx_fifo[TX_PAGES]; -static volatile int tx_fifo_in = 0; -static volatile int tx_fifo_out = 0; +static volatile int tx_fifo_in; +static volatile int tx_fifo_out; static volatile int free_tx_pages = TX_PAGES; -static int was_down = 0; +static int was_down; /* * Convenience macros/functions for D-Link adapter @@ -597,7 +597,6 @@ } skb = dev_alloc_skb(size+2); - restore_flags(flags); if (skb == NULL) { printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, size); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/de620.c linux.ac/drivers/net/de620.c --- linux.vanilla/drivers/net/de620.c Tue Apr 3 17:32:10 2001 +++ linux.ac/drivers/net/de620.c Sat Apr 14 01:24:24 2001 @@ -183,8 +183,8 @@ * Make a clone skip the Ethernet-address range check: * insmod de620.o clone=1 */ -static int bnc = 0; -static int utp = 0; +static int bnc; +static int utp; static int io = DE620_IO; static int irq = DE620_IRQ; static int clone = DE620_CLONE; @@ -690,7 +690,6 @@ else { /* Yep! Go get it! */ skb_reserve(skb,2); /* Align */ skb->dev = dev; - skb->used = 0; /* skb->data points to the start of sk_buff data area */ buffer = skb_put(skb,size); /* copy the packet into the buffer */ @@ -722,7 +721,7 @@ static int adapter_init(struct net_device *dev) { int i; - static int was_down = 0; + static int was_down; if ((nic_data.Model == 3) || (nic_data.Model == 0)) { /* CT */ EIPRegister = NCTL0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/declance.c linux.ac/drivers/net/declance.c --- linux.vanilla/drivers/net/declance.c Tue Apr 3 17:32:10 2001 +++ linux.ac/drivers/net/declance.c Sat Apr 14 01:24:24 2001 @@ -1217,7 +1217,7 @@ /* Find all the lance cards on the system and initialize them */ static int __init dec_lance_probe(void) { - static int called = 0; + static int called; #ifdef MODULE root_lance_dev = NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/depca.c linux.ac/drivers/net/depca.c --- linux.vanilla/drivers/net/depca.c Tue Apr 3 17:32:10 2001 +++ linux.ac/drivers/net/depca.c Tue Apr 3 17:54:50 2001 @@ -1818,9 +1818,7 @@ ManCode[5]='\0'; for (i=0;(*signatures[i] != '\0') && (*name == '\0');i++) { - const char * volatile lhs = ManCode; - const char * volatile rhs = signatures[i]; /* egcs-1.1.2 bug */ - if (strstr(lhs, rhs) != NULL) { + if (strstr(ManCode, signatures[i]) != NULL) { strcpy(name,ManCode); status = 1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/dgrs.c linux.ac/drivers/net/dgrs.c --- linux.vanilla/drivers/net/dgrs.c Tue Apr 3 17:32:10 2001 +++ linux.ac/drivers/net/dgrs.c Sat Apr 14 01:24:24 2001 @@ -174,7 +174,7 @@ static uchar dgrs_ipaddr[4] = { 0xff, 0xff, 0xff, 0xff}; static uchar dgrs_iptrap[4] = { 0xff, 0xff, 0xff, 0xff}; static __u32 dgrs_ipxnet = -1; -static int dgrs_nicmode = 0; +static int dgrs_nicmode; /* * Chain of device structures diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/e2100.c linux.ac/drivers/net/e2100.c --- linux.vanilla/drivers/net/e2100.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/e2100.c Sat Apr 14 01:24:24 2001 @@ -140,7 +140,7 @@ { int i, status, retval; unsigned char *station_addr = dev->dev_addr; - static unsigned version_printed = 0; + static unsigned version_printed; if (!request_region(ioaddr, E21_IO_EXTENT, dev->name)) return -EBUSY; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/eepro100.c linux.ac/drivers/net/eepro100.c --- linux.vanilla/drivers/net/eepro100.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/eepro100.c Tue Apr 3 17:54:50 2001 @@ -38,12 +38,12 @@ static int txfifo = 8; /* Tx FIFO threshold in 4 byte units, 0-15 */ static int rxfifo = 8; /* 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 */; +static int txdmaccount = 128; +static int rxdmaccount /* = 0 */; /* Set the copy breakpoint for the copy-only-tiny-buffer Rx method. Lower values use more memory, but are faster. */ -#if defined(__alpha__) || defined(__sparc__) +#if defined(__alpha__) || defined(__sparc__) || defined(__mips__) static int rx_copybreak = 1518; #else static int rx_copybreak = 200; @@ -96,7 +96,7 @@ #include <linux/string.h> #include <linux/errno.h> #include <linux/ioport.h> -#include <linux/slab.h> +#include <linux/malloc.h> #include <linux/interrupt.h> #include <linux/timer.h> #include <linux/pci.h> @@ -119,8 +119,8 @@ MODULE_PARM(congenb, "i"); MODULE_PARM(txfifo, "i"); MODULE_PARM(rxfifo, "i"); -MODULE_PARM(txdmacount, "i"); -MODULE_PARM(rxdmacount, "i"); +MODULE_PARM(txdmaccount, "i"); +MODULE_PARM(rxdmaccount, "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(multicast_filter_limit, "i"); @@ -549,7 +549,7 @@ const struct pci_device_id *ent) { unsigned long ioaddr; - int irq; + int irq, i; int acpi_idle_state = 0, pm; static int cards_found /* = 0 */; @@ -557,6 +557,17 @@ if (speedo_debug > 0 && did_version++ == 0) printk(version); + /* save power state b4 pci_enable_device overwrites it */ + pm = pci_find_capability(pdev, PCI_CAP_ID_PM); + if (pm) { + u16 pwr_command; + pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pwr_command); + acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK; + } + + i = pci_enable_device(pdev); + if (i) return i; + if (!request_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1), "eepro100")) { printk (KERN_ERR "eepro100: cannot reserve I/O ports\n"); @@ -587,17 +598,6 @@ pci_resource_start(pdev, 0), irq); #endif - /* save power state b4 pci_enable_device overwrites it */ - pm = pci_find_capability(pdev, PCI_CAP_ID_PM); - if (pm) { - u16 pwr_command; - pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pwr_command); - acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK; - } - - if (pci_enable_device(pdev)) - goto err_out_free_mmio_region; - pci_set_master(pdev); if (speedo_found1(pdev, ioaddr, cards_found, acpi_idle_state) == 0) @@ -1285,6 +1285,7 @@ del_timer_sync(&sp->timer); /* Reset the Tx and Rx units. */ outl(PortReset, ioaddr + SCBPort); + inl(ioaddr + SCBPort); /* We may get spurious interrupts here. But I don't think that they may do much harm. 1999/12/09 SAW */ udelay(10); @@ -1983,8 +1984,8 @@ /* Construct a full CmdConfig frame. */ memcpy(config_cmd_data, i82558_config_cmd, CONFIG_DATA_SIZE); config_cmd_data[1] = (txfifo << 4) | rxfifo; - config_cmd_data[4] = rxdmacount; - config_cmd_data[5] = txdmacount + 0x80; + config_cmd_data[4] = rxdmaccount; + config_cmd_data[5] = txdmaccount + 0x80; config_cmd_data[15] |= (new_rx_mode & 2) ? 1 : 0; /* 0x80 doesn't disable FC 0x84 does. Disable Flow control since we are not ACK-ing any FC interrupts diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/ethertap.c linux.ac/drivers/net/ethertap.c --- linux.vanilla/drivers/net/ethertap.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/ethertap.c Sat Apr 14 01:24:35 2001 @@ -43,7 +43,7 @@ static void set_multicast_list(struct net_device *dev); #endif -static int ethertap_debug = 0; +static int ethertap_debug; static struct net_device *tap_map[32]; /* Returns the tap device for a given netlink */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/ewrk3.c linux.ac/drivers/net/ewrk3.c --- linux.vanilla/drivers/net/ewrk3.c Tue Apr 3 17:32:11 2001 +++ linux.ac/drivers/net/ewrk3.c Sat Apr 14 01:24:35 2001 @@ -330,12 +330,12 @@ #else static u_char irq[] = {5, 0, 10, 3, 11, 9, 15, 12}; -static int autoprobed = 0, loading_module = 0; +static int autoprobed, loading_module; #endif /* MODULE */ static char name[EWRK3_STRLEN + 1]; -static int num_ewrk3s = 0, num_eth = 0; +static int num_ewrk3s, num_eth; /* ** Miscellaneous defines... diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/gmac.c linux.ac/drivers/net/gmac.c --- linux.vanilla/drivers/net/gmac.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/gmac.c Tue Apr 3 23:38:11 2001 @@ -9,7 +9,7 @@ * Changes: * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/06/2000 * - check init_etherdev return in gmac_probe1 - * BenH <bh40@calva.net> - 03/09/2000 + * BenH <benh@kernel.crashing.org> - 03/09/2000 * - Add support for new PHYs * - Add some PowerBook sleep code * @@ -47,10 +47,11 @@ #define DEBUG_PHY /* Driver version 1.3, kernel 2.4.x */ -#define GMAC_VERSION "v1.3k4" +#define GMAC_VERSION "v1.4k4" -static unsigned char dummy_buf[RX_BUF_ALLOC_SIZE + RX_OFFSET + GMAC_BUFFER_ALIGN]; -static struct net_device *gmacs = NULL; +#define DUMMY_BUF_LEN RX_BUF_ALLOC_SIZE + RX_OFFSET + GMAC_BUFFER_ALIGN +static unsigned char *dummy_buf; +static struct net_device *gmacs; /* Prototypes */ static int mii_read(struct gmac *gm, int phy, int r); @@ -211,10 +212,12 @@ int link_100 = 0; int gigabit = 0; #ifdef DEBUG_PHY - printk("Link state change, phy_status: 0x%04x\n", phy_status); + printk("%s: Link state change, phy_status: 0x%04x\n", + gm->dev->name, phy_status); #endif gm->phy_status = phy_status; + /* Should we enable that in generic mode ? */ lpar_ability = mii_read(gm, gm->phy_addr, MII_ANLPA); if (lpar_ability & MII_ANLPA_PAUS) GM_BIS(GM_MAC_CTRL_CONFIG, GM_MAC_CTRL_CONF_SND_PAUSE_EN); @@ -249,6 +252,9 @@ #endif full_duplex = ((stat2 & MII_LXT971_STATUS2_FULLDUPLEX) != 0); link_100 = ((stat2 & MII_LXT971_STATUS2_SPEED) != 0); + } else { + full_duplex = (lpar_ability & MII_ANLPA_FDAM) != 0; + link_100 = (lpar_ability & MII_ANLPA_100M) != 0; } #ifdef DEBUG_PHY printk(" full_duplex: %d, speed: %s\n", full_duplex, @@ -274,6 +280,144 @@ } } +/* Power management: stop PHY chip for suspend mode + */ +static void +gmac_suspend(struct gmac* gm) +{ + int data, timeout; + unsigned long flags; + + gm->sleeping = 1; + netif_stop_queue(gm->dev); + + + spin_lock_irqsave(&gm->lock, flags); + if (gm->opened) { + disable_irq(gm->dev->irq); + /* Stop polling PHY */ + mii_poll_stop(gm); + } + /* Mask out all chips interrupts */ + GM_OUT(GM_IRQ_MASK, 0xffffffff); + spin_unlock_irqrestore(&gm->lock, flags); + + if (gm->opened) { + int i; + /* Empty Tx ring of any remaining gremlins */ + gmac_tx_cleanup(gm->dev, 1); + + /* Empty Rx ring of any remaining gremlins */ + for (i = 0; i < NRX; ++i) { + if (gm->rx_buff[i] != 0) { + dev_kfree_skb_irq(gm->rx_buff[i]); + gm->rx_buff[i] = 0; + } + } + } + + /* Clear interrupts on 5201 */ + if (gm->phy_type == PHY_B5201) + mii_write(gm, gm->phy_addr, MII_BCM5201_INTERRUPT, 0); + + /* Drive MDIO high */ + GM_OUT(GM_MIF_CFG, 0); + + /* Unchanged, don't ask me why */ + data = mii_read(gm, gm->phy_addr, MII_ANLPA); + mii_write(gm, gm->phy_addr, MII_ANLPA, data); + + /* Put MDIO in sane state */ + GM_OUT(GM_MIF_CFG, GM_MIF_CFGBB); + GM_OUT(GM_MIF_BB_CLOCK, 0); + GM_OUT(GM_MIF_BB_DATA, 0); + GM_OUT(GM_MIF_BB_OUT_ENABLE, 0); + + /* Stop everything */ + GM_OUT(GM_MAC_RX_CONFIG, 0); + GM_OUT(GM_MAC_TX_CONFIG, 0); + GM_OUT(GM_MAC_XIF_CONFIG, 0); + GM_OUT(GM_TX_CONF, 0); + GM_OUT(GM_RX_CONF, 0); + + /* Set reset state */ + GM_OUT(GM_RESET, GM_RESET_TX | GM_RESET_RX); + for (timeout = 100; timeout > 0; --timeout) { + mdelay(10); + if ((GM_IN(GM_RESET) & (GM_RESET_TX | GM_RESET_RX)) == 0) + break; + } + GM_OUT(GM_MAC_TX_RESET, GM_MAC_TX_RESET_NOW); + GM_OUT(GM_MAC_RX_RESET, GM_MAC_RX_RESET_NOW); + + /* Superisolate PHY */ + if (gm->phy_type == PHY_B5201) + mii_write(gm, gm->phy_addr, MII_BCM5201_MULTIPHY, + MII_BCM5201_MULTIPHY_SUPERISOLATE); + + /* Unclock chip */ + gmac_set_power(gm, 0); +} + +static void +gmac_resume(struct gmac *gm) +{ + int data; + + if (gmac_powerup_and_reset(gm->dev)) { + printk(KERN_ERR "%s: Couldn't revive gmac ethernet !\n", gm->dev->name); + return; + } + + gm->sleeping = 0; + + if (gm->opened) { + /* Create fresh rings */ + gmac_init_rings(gm, 1); + /* re-initialize the MAC */ + gmac_mac_init(gm, gm->dev->dev_addr); + /* re-initialize the multicast tables & promisc mode if any */ + gmac_set_multicast(gm->dev); + } + + /* Early enable Tx and Rx so that we are clocked */ + GM_BIS(GM_TX_CONF, GM_TX_CONF_DMA_EN); + mdelay(20); + GM_BIS(GM_RX_CONF, GM_RX_CONF_DMA_EN); + mdelay(20); + GM_BIS(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_ENABLE); + mdelay(20); + GM_BIS(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_ENABLE); + mdelay(20); + if (gm->phy_type == PHY_B5201) { + data = mii_read(gm, gm->phy_addr, MII_BCM5201_MULTIPHY); + mii_write(gm, gm->phy_addr, MII_BCM5201_MULTIPHY, + data & ~MII_BCM5201_MULTIPHY_SUPERISOLATE); + } + mdelay(1); + + if (gm->opened) { + /* restart polling PHY */ + mii_interrupt(gm); + /* restart DMA operations */ + gmac_start_dma(gm); + netif_start_queue(gm->dev); + enable_irq(gm->dev->irq); + } else { + /* Driver not opened, just leave things off. Note that + * we could be smart and superisolate the PHY when the + * driver is closed, but I won't do that unless I have + * a better understanding of some electrical issues with + * this PHY chip --BenH + */ + GM_OUT(GM_MAC_RX_CONFIG, 0); + GM_OUT(GM_MAC_TX_CONFIG, 0); + GM_OUT(GM_MAC_XIF_CONFIG, 0); + GM_OUT(GM_TX_CONF, 0); + GM_OUT(GM_RX_CONF, 0); + } +} + static int mii_do_reset_phy(struct gmac *gm, int phy_addr) { @@ -374,7 +518,7 @@ 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", + printk(KERN_ERR "%s: Warning ! Unknown PHY ID 0x%08x, using generic mode...\n", gm->dev->name, gm->phy_id); } @@ -448,8 +592,6 @@ PCI_CACHE_LINE_SIZE, 8); } } else { - /* FIXME: Add PHY power down */ - gm->phy_type = 0; feature_set_gmac_power(gm->of_node, 0); } } @@ -472,11 +614,14 @@ if ((GM_IN(GM_RESET) & (GM_RESET_TX | GM_RESET_RX)) == 0) { /* Mask out all chips interrupts */ GM_OUT(GM_IRQ_MASK, 0xffffffff); + GM_OUT(GM_MAC_TX_RESET, GM_MAC_TX_RESET_NOW); + GM_OUT(GM_MAC_RX_RESET, GM_MAC_RX_RESET_NOW); return 0; } } printk(KERN_ERR "%s reset failed!\n", dev->name); gmac_set_power(gm, 0); + gm->phy_type = 0; return -1; } @@ -747,7 +892,9 @@ int multicast_hash = 0; int multicast_all = 0; int promisc = 0; - + + if (gm->sleeping) + return; /* Lock out others. */ netif_stop_queue(dev); @@ -881,6 +1028,7 @@ /* Shut down chip */ gmac_set_power(gm, 0); + gm->phy_type = 0; /* Empty rings of any remaining gremlins */ for (i = 0; i < NRX; ++i) { @@ -904,7 +1052,6 @@ gmac_sleep_notify(struct pmu_sleep_notifier *self, int when) { struct gmac *gm; - int i; /* XXX should handle more than one */ if (gmacs == NULL) @@ -920,38 +1067,10 @@ case PBOOK_SLEEP_REJECT: break; case PBOOK_SLEEP_NOW: - disable_irq(gm->dev->irq); - netif_stop_queue(gm->dev); - 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; - } - } + gmac_suspend(gm); 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); - netif_start_queue(gm->dev); - enable_irq(gm->dev->irq); + gmac_resume(gm); break; } return PBOOK_SLEEP_OK; @@ -967,7 +1086,10 @@ struct gmac *gm = (struct gmac *) dev->priv; int i, timeout; unsigned long flags; - + + if (gm->sleeping) + return; + printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name); spin_lock_irqsave(&gm->lock, flags); @@ -990,6 +1112,8 @@ if ((GM_IN(GM_RESET) & (GM_RESET_TX | GM_RESET_RX)) == 0) { /* Mask out all chips interrupts */ GM_OUT(GM_IRQ_MASK, 0xffffffff); + GM_OUT(GM_MAC_TX_RESET, GM_MAC_TX_RESET_NOW); + GM_OUT(GM_MAC_RX_RESET, GM_MAC_RX_RESET_NOW); break; } } @@ -1022,6 +1146,9 @@ unsigned long flags; int i; + if (gm->sleeping) + return 1; + spin_lock_irqsave(&gm->lock, flags); i = gm->next_tx; @@ -1274,7 +1401,7 @@ struct gmac *gm = (struct gmac *) dev->priv; struct net_device_stats *stats = &gm->stats; - if (gm && gm->opened) { + if (gm && gm->opened && !gm->sleeping) { stats->rx_crc_errors += GM_IN(GM_MAC_RX_CRC_ERR_CTR); GM_OUT(GM_MAC_RX_CRC_ERR_CTR, 0); @@ -1318,7 +1445,7 @@ MOD_DEC_USE_COUNT; - return 0; + return gmacs? 0: -ENODEV; } static void @@ -1343,6 +1470,22 @@ return; } + if (dummy_buf == NULL) { + dummy_buf = kmalloc(DUMMY_BUF_LEN, GFP_KERNEL); + if (dummy_buf == NULL) { + printk(KERN_ERR "GMAC: failed to allocated dummy buffer\n"); + return; + } + } + + if (dummy_buf == NULL) { + dummy_buf = kmalloc(DUMMY_BUF_LEN, GFP_KERNEL); + if (dummy_buf == NULL) { + printk(KERN_ERR "GMAC: failed to allocated dummy buffer\n"); + return; + } + } + tx_descpage = get_free_page(GFP_KERNEL); if (tx_descpage == 0) { printk(KERN_ERR "GMAC: can't get a page for tx descriptors\n"); @@ -1351,17 +1494,13 @@ rx_descpage = get_free_page(GFP_KERNEL); if (rx_descpage == 0) { printk(KERN_ERR "GMAC: can't get a page for rx descriptors\n"); - free_page(tx_descpage); - return; + goto out_txdesc; } dev = init_etherdev(NULL, sizeof(struct gmac)); - if (!dev) { printk(KERN_ERR "GMAC: init_etherdev failed, out of memory\n"); - free_page(tx_descpage); - free_page(rx_descpage); - return; + goto out_rxdesc; } SET_MODULE_OWNER(dev); @@ -1369,6 +1508,10 @@ dev->base_addr = gmac->addrs[0].address; gm->regs = (volatile unsigned int *) ioremap(gmac->addrs[0].address, 0x10000); + if (!gm->regs) { + printk(KERN_ERR "GMAC: unable to map I/O registers\n"); + goto out_unreg; + } dev->irq = gmac->intrs[0].line; gm->dev = dev; gm->of_node = gmac; @@ -1394,6 +1537,7 @@ gm->phy_addr = 0; gm->opened = 0; + gm->sleeping = 0; dev->open = gmac_open; dev->stop = gmac_close; @@ -1404,13 +1548,22 @@ dev->watchdog_timeo = 5*HZ; ether_setup(dev); - + gm->next_gmac = gmacs; gmacs = dev; #ifdef CONFIG_PMAC_PBOOK pmu_register_sleep_notifier(&gmac_sleep_notifier); #endif + return; + +out_unreg: + unregister_netdev(dev); + kfree(dev); +out_rxdesc: + free_page(rx_descpage); +out_txdesc: + free_page(tx_descpage); } MODULE_AUTHOR("Paul Mackerras/Ben Herrenschmidt"); @@ -1424,13 +1577,17 @@ while ((dev = gmacs) != NULL) { gm = (struct gmac *) dev->priv; unregister_netdev(dev); + iounmap(gm->regs); free_page(gm->tx_desc_page); free_page(gm->rx_desc_page); gmacs = gm->next_gmac; kfree(dev); } + if (dummy_buf != NULL) { + kfree(dummy_buf); + dummy_buf = NULL; + } } module_init(gmac_probe); module_exit(gmac_cleanup_module); - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/gmac.h linux.ac/drivers/net/gmac.h --- linux.vanilla/drivers/net/gmac.h Sun Sep 17 17:48:05 2000 +++ linux.ac/drivers/net/gmac.h Tue Apr 3 23:33:43 2001 @@ -722,6 +722,13 @@ #define MII_ANLPA_CSMA 0x0001 /* CSMA-CD Capable */ #define MII_ANLPA_PAUS 0x0400 +/* Generic PHYs + * + * These GENERIC values assumes that the PHY devices follow 802.3u and + * allow parallel detection to set the link partner ability register. + * Detection of 100Base-TX [H/F Duplex] and 100Base-T4 is supported. + */ + /* * Model-specific PHY registers * @@ -791,7 +798,6 @@ #define MII_LXT971_STATUS2_AUTONEG_COMPLETE 0x0080 - /* * DMA descriptors */ @@ -877,6 +883,7 @@ u8 pci_devfn; spinlock_t lock; int opened; + int sleeping; struct net_device *next_gmac; }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/gt96100eth.c linux.ac/drivers/net/gt96100eth.c --- linux.vanilla/drivers/net/gt96100eth.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/gt96100eth.c Tue Apr 3 17:54:51 2001 @@ -0,0 +1,1253 @@ +/* + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * stevel@mvista.com or support@mvista.com + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + * + * Ethernet driver for the MIPS GT96100 Advanced Communication Controller. + * + */ + +#ifndef __mips__ +#error This driver only works with MIPS architectures! +#endif + + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/errno.h> +#include <linux/in.h> +#include <linux/ioport.h> +#include <linux/malloc.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/delay.h> +#include <asm/irq.h> +#include <asm/bitops.h> +#include <asm/io.h> + +#include "gt96100eth.h" + +#ifdef GT96100_DEBUG +static int gt96100_debug = GT96100_DEBUG; +#else +static int gt96100_debug = 3; +#endif + +// prototypes +static void *dmaalloc(size_t size, dma_addr_t * dma_handle); +static void dmafree(size_t size, void *vaddr); +static int gt96100_add_hash_entry(struct net_device *dev, + unsigned char *addr); +static void read_mib_counters(struct gt96100_private *gp); +static int read_MII(struct net_device *dev, u32 reg); +static int write_MII(struct net_device *dev, u32 reg, u16 data); +static void dump_MII(struct net_device *dev); +static void update_stats(struct gt96100_private *gp); +static void abort(struct net_device *dev, u32 abort_bits); +static void hard_stop(struct net_device *dev); +static void enable_ether_irq(struct net_device *dev); +static void disable_ether_irq(struct net_device *dev); +static int __init gt96100_probe1(struct net_device *dev, long ioaddr, + int irq, int port_num); +static int gt96100_init(struct net_device *dev); +static int gt96100_open(struct net_device *dev); +static int gt96100_close(struct net_device *dev); +static int gt96100_tx(struct sk_buff *skb, struct net_device *dev); +static int gt96100_rx(struct net_device *dev, u32 status); +static void gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void gt96100_tx_timeout(struct net_device *dev); +static void gt96100_set_rx_mode(struct net_device *dev); +static struct net_device_stats *gt96100_get_stats(struct net_device *dev); + +static char version[] __devinitdata = + "gt96100eth.c:0.1 stevel@mvista.com\n"; + +// FIX! Need real Ethernet addresses +static unsigned char gt96100_station_addr[2][6] __devinitdata = + { {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, +{0x01, 0x02, 0x03, 0x04, 0x05, 0x07} +}; + +#define nibswap(x) ((((x) >> 4) & 0x0f) | (((x) << 4) & 0xf0)) + +#define RUN_AT(x) (jiffies + (x)) + +// For reading/writing 32-bit words from/to DMA memory +#define cpu_to_dma32 cpu_to_be32 +#define dma32_to_cpu be32_to_cpu + +/* + * Base address and interupt of the GT96100 ethernet controllers + */ +static struct { + unsigned int port; + int irq; +} gt96100_iflist[NUM_INTERFACES] = { + { + GT96100_ETH0_BASE, GT96100_ETHER0_IRQ}, { + GT96100_ETH1_BASE, GT96100_ETHER1_IRQ} +}; + +/* + DMA memory allocation, derived from pci_alloc_consistent. +*/ +static void *dmaalloc(size_t size, dma_addr_t * dma_handle) +{ + void *ret; + + ret = + (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, + get_order(size)); + + if (ret != NULL) { + dma_cache_inv((unsigned long) ret, size); + if (dma_handle != NULL) + *dma_handle = virt_to_phys(ret); + + /* bump virtual address up to non-cached area */ + ret = KSEG1ADDR(ret); + } + + return ret; +} + +static void dmafree(size_t size, void *vaddr) +{ + vaddr = KSEG0ADDR(vaddr); + free_pages((unsigned long) vaddr, get_order(size)); +} + + +static int read_MII(struct net_device *dev, u32 reg) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + int timedout = 20; + u32 smir = smirOpCode | (gp->phy_addr << smirPhyAdBit) | + (reg << smirRegAdBit); + + // wait for last operation to complete + while (GT96100_READ(GT96100_ETH_SMI_REG) & smirBusy) { + // snooze for 1 msec and check again +#if 0 + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(10 * HZ / 10000); +#else + mdelay(1); +#endif + + if (--timedout == 0) { + printk(KERN_ERR "%s: read_MII busy timeout!!\n", + dev->name); + return -1; + } + } + + GT96100_WRITE(GT96100_ETH_SMI_REG, smir); + + timedout = 20; + // wait for read to complete + while (!(smir = GT96100_READ(GT96100_ETH_SMI_REG) & smirReadValid)) { + // snooze for 1 msec and check again +#if 0 + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(10 * HZ / 10000); +#else + mdelay(1); +#endif + + if (--timedout == 0) { + printk(KERN_ERR "%s: read_MII timeout!!\n", + dev->name); + return -1; + } + } + + return (int) (smir & smirDataMask); +} + +static int write_MII(struct net_device *dev, u32 reg, u16 data) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + int timedout = 20; + u32 smir = + (gp->phy_addr << smirPhyAdBit) | (reg << smirRegAdBit) | data; + + // wait for last operation to complete + while (GT96100_READ(GT96100_ETH_SMI_REG) & smirBusy) { + // snooze for 1 msec and check again +#if 0 + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(10 * HZ / 10000); +#else + mdelay(1); +#endif + + if (--timedout == 0) { + printk(KERN_ERR "%s: write_MII busy timeout!!\n", + dev->name); + return -1; + } + } + + GT96100_WRITE(GT96100_ETH_SMI_REG, smir); + return 0; +} + + +static void dump_MII(struct net_device *dev) +{ + int i, val; + + for (i = 0; i < 7; i++) { + if ((val = read_MII(dev, i)) >= 0) + printk("%s: MII Reg %d=%x\n", dev->name, i, val); + } + for (i = 16; i < 21; i++) { + if ((val = read_MII(dev, i)) >= 0) + printk("%s: MII Reg %d=%x\n", dev->name, i, val); + } +} + + +static int +gt96100_add_hash_entry(struct net_device *dev, unsigned char *addr) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + u16 hashResult, stmp; + unsigned char ctmp, hash_ea[6]; + u32 tblEntry, *tblEntryAddr; + int i; + + for (i = 0; i < 6; i++) { + // nibble swap + ctmp = nibswap(addr[i]); + // invert every nibble + hash_ea[i] = ((ctmp & 1) << 3) | ((ctmp & 8) >> 3) | + ((ctmp & 2) << 1) | ((ctmp & 4) >> 1); + hash_ea[i] |= ((ctmp & 0x10) << 3) | ((ctmp & 0x80) >> 3) | + ((ctmp & 0x20) << 1) | ((ctmp & 0x40) >> 1); + } + + if (gp->hash_mode == 0) { + hashResult = ((u16) hash_ea[0] & 0xfc) << 7; + stmp = + ((u16) hash_ea[0] & 0x03) | (((u16) hash_ea[1] & 0x7f) + << 2); + stmp ^= + (((u16) hash_ea[1] >> 7) & 0x01) | ((u16) hash_ea[2] << + 1); + stmp ^= (u16) hash_ea[3] | (((u16) hash_ea[4] & 1) << 8); + hashResult |= stmp; + } else { + return -1; // don't support hash mode 1 + } + + tblEntryAddr = + (u32 *) (&gp->hash_table[((u32) hashResult & 0x7ff) << 3]); + + for (i = 0; i < HASH_HOP_NUMBER; i++) { + if ((*tblEntryAddr & hteValid) + && !(*tblEntryAddr & hteSkip)) { + // This entry is already occupied, go to next entry + tblEntryAddr += 2; + } else { + memset(tblEntryAddr, 0, 8); + tblEntry = hteValid | hteRD; + tblEntry |= (u32) addr[5] << 3; + tblEntry |= (u32) addr[4] << 11; + tblEntry |= (u32) addr[3] << 19; + tblEntry |= ((u32) addr[2] & 0x1f) << 27; + *(tblEntryAddr + 1) = cpu_to_dma32(tblEntry); + tblEntry = ((u32) addr[2] >> 5) & 0x07; + tblEntry |= (u32) addr[1] << 3; + tblEntry |= (u32) addr[0] << 11; + *tblEntryAddr = cpu_to_dma32(tblEntry); + break; + } + } + + if (i >= HASH_HOP_NUMBER) { + printk(KERN_ERR "%s: gt96100_add_hash_entry expired!\n", + dev->name); + return -1; // Couldn't find an unused entry + } + + return 0; +} + + +static void read_mib_counters(struct gt96100_private *gp) +{ + u32 *mib_regs = (u32 *) & gp->mib; + int i; + + for (i = 0; i < sizeof(mib_counters_t) / sizeof(u32); i++) + mib_regs[i] = + GT96100ETH_READ(gp, + GT96100_ETH_MIB_COUNT_BASE + + i * sizeof(u32)); +} + + +static void update_stats(struct gt96100_private *gp) +{ + mib_counters_t *mib = &gp->mib; + struct net_device_stats *stats = &gp->stats; + + read_mib_counters(gp); + + stats->rx_packets = mib->totalFramesReceived; + stats->tx_packets = mib->framesSent; + stats->rx_bytes = mib->totalByteReceived; + stats->tx_bytes = mib->byteSent; + stats->rx_errors = mib->totalFramesReceived - mib->framesReceived; + //the tx error counters are incremented by the ISR + //rx_dropped incremented by gt96100_rx + //tx_dropped incremented by gt96100_tx + stats->multicast = mib->multicastFramesReceived; + // Tx collisions incremented by ISR, so add in MIB Rx collisions + stats->collisions += mib->collision + mib->lateCollision; + stats->rx_length_errors = mib->oversizeFrames + mib->fragments; + // The RxError condition means the Rx DMA encountered a + // CPU owned descriptor, which, if things are working as + // they should, means the Rx ring has overflowed. + stats->rx_over_errors = mib->macRxError; + stats->rx_crc_errors = mib->cRCError; +} + +static void abort(struct net_device *dev, u32 abort_bits) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + int timedout = 100; // wait up to 100 msec for hard stop to complete + + if (gt96100_debug > 2) + printk(KERN_INFO "%s: abort\n", dev->name); + + // Return if neither Rx or Tx abort bits are set + if (!(abort_bits & (sdcmrAR | sdcmrAT))) + return; + + // make sure only the Rx/Tx abort bits are set + abort_bits &= (sdcmrAR | sdcmrAT); + + spin_lock(&gp->lock); + + // abort any Rx/Tx DMA immediately + GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, abort_bits); + + if (gt96100_debug > 2) + printk(KERN_INFO "%s: abort: SDMA comm = %x\n", + dev->name, GT96100ETH_READ(gp, + GT96100_ETH_SDMA_COMM)); + + // wait for abort to complete + while (GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM) & abort_bits) { + // snooze for 20 msec and check again +#if 0 + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(10 * HZ / 10000); +#else + mdelay(1); +#endif + + if (--timedout == 0) { + printk(KERN_ERR "%s: abort timeout!!\n", + dev->name); + break; + } + } + + if (gt96100_debug > 2) + printk(KERN_INFO "%s: abort: timedout=%d\n", dev->name, + timedout); + + spin_unlock(&gp->lock); +} + + +static void hard_stop(struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + + if (gt96100_debug > 2) + printk(KERN_INFO "%s: hard stop\n", dev->name); + + disable_ether_irq(dev); + + abort(dev, sdcmrAR | sdcmrAT); + + // disable port + GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, 0); +} + + +static void enable_ether_irq(struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + u32 intMask; + + // unmask interrupts + GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK, + icrRxBuffer | icrTxBufferLow | icrTxEndLow | + icrRxError | icrTxErrorLow | icrRxOVR | + icrTxUdr | icrRxBufferQ0 | icrRxErrorQ0 | + icrMIIPhySTC); + + // now route ethernet interrupts to GT Int0 (eth0 and eth1 will be + // sharing it). + // FIX! The kernel's irq code should do this + intMask = GT96100_READ(GT96100_INT0_HIGH_MASK); + intMask |= 1 << gp->port_num; + GT96100_WRITE(GT96100_INT0_HIGH_MASK, intMask); +} + +static void disable_ether_irq(struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + u32 intMask; + + // FIX! The kernel's irq code should do this + intMask = GT96100_READ(GT96100_INT0_HIGH_MASK); + intMask &= ~(1 << gp->port_num); + GT96100_WRITE(GT96100_INT0_HIGH_MASK, intMask); + + GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK, 0); +} + + +/* + * Probe for a GT96100 ethernet controller. + */ +int __init gt96100_probe(struct net_device *dev) +{ + unsigned int base_addr = dev ? dev->base_addr : 0; + int i; + +#ifndef CONFIG_MIPS_GT96100ETH + return -ENODEV; +#endif + + if (gt96100_debug > 2) + printk(KERN_INFO "%s: gt96100_probe\n", dev->name); + + if (base_addr >= KSEG0) /* Check a single specified location. */ + return gt96100_probe1(dev, base_addr, dev->irq, 0); + else if (base_addr != 0) /* Don't probe at all. */ + return -ENXIO; + +// for (i = 0; i<NUM_INTERFACES; i++) { + for (i = NUM_INTERFACES - 1; i >= 0; i--) { + int base_addr = gt96100_iflist[i].port; +#if 0 + if (check_region(base_addr, GT96100_ETH_IO_SIZE)) { + printk(KERN_ERR + "%s: gt96100_probe: ioaddr 0x%lx taken?\n", + dev->name, base_addr); + continue; + } +#endif + if (gt96100_probe1 + (dev, base_addr, gt96100_iflist[i].irq, i) == 0) + return 0; + } + return -ENODEV; +} + + + +static int __init +gt96100_probe1(struct net_device *dev, long ioaddr, int irq, int port_num) +{ + static unsigned version_printed = 0; + struct gt96100_private *gp = NULL; + int i, retval; + u32 cpuConfig; + + // FIX! probe for GT96100 by reading a suitable register + + if (gt96100_debug > 2) + printk(KERN_INFO "gt96100_probe1: ioaddr 0x%lx, irq %d\n", + ioaddr, irq); + + request_region(ioaddr, GT96100_ETH_IO_SIZE, "GT96100ETH"); + + cpuConfig = GT96100_READ(GT96100_CPU_INTERF_CONFIG); + if (cpuConfig & (1 << 12)) { + printk(KERN_ERR + "gt96100_probe1: must be in Big Endian mode!\n"); + retval = -ENODEV; + goto free_region; + } + + if (gt96100_debug > 2) + printk(KERN_INFO + "gt96100_probe1: chip in Big Endian mode - cool\n"); + + /* Allocate a new 'dev' if needed. */ + if (dev == NULL) + dev = init_etherdev(0, sizeof(struct gt96100_private)); + + if (gt96100_debug && version_printed++ == 0) + printk(version); + + if (irq < 0) { + printk(KERN_ERR + "gt96100_probe1: irq unknown - probing not supported\n"); + retval = -ENODEV; + goto free_region; + } + + printk(KERN_INFO "%s: GT-96100 ethernet found at 0x%lx, irq %d\n", + dev->name, ioaddr, irq); + + /* private struct aligned and zeroed by init_etherdev */ + /* Fill in the 'dev' fields. */ + dev->base_addr = ioaddr; + dev->irq = irq; + memcpy(dev->dev_addr, gt96100_station_addr[port_num], + sizeof(dev->dev_addr)); + + printk(KERN_INFO "%s: HW Address ", dev->name); + for (i = 0; i < sizeof(dev->dev_addr); i++) { + printk("%2.2x", dev->dev_addr[i]); + printk(i < 5 ? ":" : "\n"); + } + + /* Initialize our private structure. */ + if (dev->priv == NULL) { + + gp = + (struct gt96100_private *) kmalloc(sizeof(*gp), + GFP_KERNEL); + if (gp == NULL) { + retval = -ENOMEM; + goto free_region; + } + + dev->priv = gp; + } + + gp = dev->priv; + + memset(gp, 0, sizeof(*gp)); // clear it + + gp->port_num = port_num; + gp->io_size = GT96100_ETH_IO_SIZE; + gp->port_offset = port_num * GT96100_ETH_IO_SIZE; + gp->phy_addr = port_num + 1; + + if (gt96100_debug > 2) + printk(KERN_INFO "%s: gt96100_probe1, port %d\n", + dev->name, gp->port_num); + + // Allocate Rx and Tx descriptor rings + if (gp->rx_ring == NULL) { + // All descriptors in ring must be 16-byte aligned + gp->rx_ring = dmaalloc(sizeof(gt96100_rd_t) * RX_RING_SIZE + + + sizeof(gt96100_td_t) * TX_RING_SIZE, + &gp->rx_ring_dma); + if (gp->rx_ring == NULL) { + retval = -ENOMEM; + goto free_region; + } + + gp->tx_ring = + (gt96100_td_t *) (gp->rx_ring + RX_RING_SIZE); + gp->tx_ring_dma = + gp->rx_ring_dma + sizeof(gt96100_rd_t) * RX_RING_SIZE; + } + + if (gt96100_debug > 2) + printk(KERN_INFO + "%s: gt96100_probe1, rx_ring=%p, tx_ring=%p\n", + dev->name, gp->rx_ring, gp->tx_ring); + + // Allocate Rx Hash Table + if (gp->hash_table == NULL) { + gp->hash_table = (char *) dmaalloc(RX_HASH_TABLE_SIZE, + &gp->hash_table_dma); + if (gp->hash_table == NULL) { + dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE + + sizeof(gt96100_td_t) * TX_RING_SIZE, + gp->rx_ring); + retval = -ENOMEM; + goto free_region; + } + } + + if (gt96100_debug > 2) + printk(KERN_INFO "%s: gt96100_probe1, hash=%p\n", + dev->name, gp->hash_table); + + spin_lock_init(&gp->lock); + + dev->open = gt96100_open; + dev->hard_start_xmit = gt96100_tx; + dev->stop = gt96100_close; + dev->get_stats = gt96100_get_stats; + //dev->do_ioctl = gt96100_ioctl; + dev->set_multicast_list = gt96100_set_rx_mode; + dev->tx_timeout = gt96100_tx_timeout; + dev->watchdog_timeo = GT96100ETH_TX_TIMEOUT; + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); + return 0; + + free_region: + release_region(ioaddr, gp->io_size); + unregister_netdev(dev); + if (dev->priv != NULL) + kfree(dev->priv); + kfree(dev); + printk(KERN_ERR "%s: gt96100_probe1 failed. Returns %d\n", + dev->name, retval); + return retval; +} + + +static int gt96100_init(struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + unsigned long flags; + u32 phyAD, ciu; + int i; + + if (gt96100_debug > 2) + printk("%s: gt96100_init: dev=%p\n", dev->name, dev); + + // Stop and disable Port + hard_stop(dev); + + spin_lock_irqsave(&gp->lock, flags); + + // First things first, set-up hash table + memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE); // clear it + gp->hash_mode = 0; + // Add a single entry to hash table - our ethernet address + gt96100_add_hash_entry(dev, dev->dev_addr); + // Set-up DMA ptr to hash table + GT96100ETH_WRITE(gp, GT96100_ETH_HASH_TBL_PTR, gp->hash_table_dma); + if (gt96100_debug > 2) + printk("%s: gt96100_init: Hash Tbl Ptr=%x\n", dev->name, + GT96100ETH_READ(gp, GT96100_ETH_HASH_TBL_PTR)); + + // Setup Tx descriptor ring + for (i = 0; i < TX_RING_SIZE; i++) { + gp->tx_ring[i].cmdstat = 0; // CPU owns + gp->tx_ring[i].byte_cnt = 0; + gp->tx_ring[i].buff_ptr = 0; + gp->tx_ring[i].next = + cpu_to_dma32(gp->tx_ring_dma + + sizeof(gt96100_td_t) * (i + 1)); + } + /* Wrap the ring. */ + gp->tx_ring[i - 1].next = cpu_to_dma32(gp->tx_ring_dma); + + // setup only the lowest priority TxCDP reg + GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR0, + gp->tx_ring_dma); + GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR1, 0); + if (gt96100_debug > 2) + printk("%s: gt96100_init: Curr Tx Desc Ptr0=%x\n", + dev->name, GT96100ETH_READ(gp, + GT96100_ETH_CURR_TX_DESC_PTR0)); + + // Setup Rx descriptor ring + for (i = 0; i < RX_RING_SIZE; i++) { + dma_addr_t rx_buff_dma; + gp->rx_ring[i].next = + cpu_to_dma32(gp->rx_ring_dma + + sizeof(gt96100_rd_t) * (i + 1)); + if (gp->rx_buff[i] == NULL) + gp->rx_buff[i] = + dmaalloc(PKT_BUF_SZ, &rx_buff_dma); + else + rx_buff_dma = virt_to_phys(gp->rx_buff[i]); + if (gp->rx_buff[i] == NULL) + break; + gp->rx_ring[i].buff_ptr = cpu_to_dma32(rx_buff_dma); + gp->rx_ring[i].buff_cnt_sz = + cpu_to_dma32(PKT_BUF_SZ << rdBuffSzBit); + // Give ownership to device, enable interrupt + gp->rx_ring[i].cmdstat = + cpu_to_dma32((u32) (rxOwn | rxEI)); + } + + if (i != RX_RING_SIZE) { + int j; + for (j = 0; j < RX_RING_SIZE; j++) { + if (gp->rx_buff[j]) { + dmafree(PKT_BUF_SZ, gp->rx_buff[j]); + gp->rx_buff[j] = NULL; + } + } + printk(KERN_ERR "%s: Rx ring allocation failed.\n", + dev->name); + spin_unlock_irqrestore(&gp->lock, flags); + return -ENOMEM; + } + + /* Wrap the ring. */ + gp->rx_ring[i - 1].next = cpu_to_dma32(gp->rx_ring_dma); + + // Set our MII PHY device address + phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG); + phyAD &= ~(0x1f << (gp->port_num * 5)); + phyAD |= gp->phy_addr << (gp->port_num * 5); + GT96100_WRITE(GT96100_ETH_PHY_ADDR_REG, phyAD); + + if (gt96100_debug > 2) + printk("%s: gt96100_init: PhyAD=%x\n", dev->name, + GT96100_READ(GT96100_ETH_PHY_ADDR_REG)); + + // Clear all the RxFDP and RXCDP regs... + for (i = 0; i < 4; i++) { + GT96100ETH_WRITE(gp, GT96100_ETH_1ST_RX_DESC_PTR0 + i * 4, + 0); + GT96100ETH_WRITE(gp, GT96100_ETH_CURR_RX_DESC_PTR0 + i * 4, + 0); + } + // and setup only the lowest priority RxFDP and RxCDP regs + GT96100ETH_WRITE(gp, GT96100_ETH_1ST_RX_DESC_PTR0, + gp->rx_ring_dma); + GT96100ETH_WRITE(gp, GT96100_ETH_CURR_RX_DESC_PTR0, + gp->rx_ring_dma); + if (gt96100_debug > 2) + printk("%s: gt96100_init: 1st/Curr Rx Desc Ptr0=%x/%x\n", + dev->name, GT96100ETH_READ(gp, + GT96100_ETH_1ST_RX_DESC_PTR0), + GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0)); + + // init Rx/Tx indeces and pkt counters + gp->rx_next_out = gp->tx_next_in = gp->tx_next_out = 0; + gp->tx_count = 0; + + // setup DMA + + // FIX! this should be done by Kernel setup code + ciu = GT96100_READ(GT96100_CIU_ARBITER_CONFIG); + ciu |= (0x0c << (gp->port_num * 2)); // set Ether DMA req priority to high + // FIX! setting the following bit causes the EV96100 board to hang!!! + //ciu |= (1 << (24+gp->port_num)); // pull Ethernet port out of Reset??? + // FIX! endian mode??? + ciu &= ~(1 << 31); // set desc endianess to Big + GT96100_WRITE(GT96100_CIU_ARBITER_CONFIG, ciu); + if (gt96100_debug > 2) + printk("%s: gt96100_init: CIU Config=%x/%x\n", dev->name, + ciu, GT96100_READ(GT96100_CIU_ARBITER_CONFIG)); + + // We want the Rx/Tx DMA to write/read data to/from memory in + // Big Endian mode. Also set DMA Burst Size to 8 64Bit words. + // FIX! endian mode??? + GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_CONFIG, + //sdcrBLMR | sdcrBLMT | + (0xf << sdcrRCBit) | sdcrRIFB | (3 << sdcrBSZBit)); + if (gt96100_debug > 2) + printk("%s: gt96100_init: SDMA Config=%x\n", dev->name, + GT96100ETH_READ(gp, GT96100_ETH_SDMA_CONFIG)); + + // start Rx DMA + GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD); + if (gt96100_debug > 2) + printk("%s: gt96100_init: SDMA Comm=%x\n", dev->name, + GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM)); + + // enable interrupts + enable_ether_irq(dev); + + /* + * Disable all Type-of-Service queueing. All Rx packets will be + * treated normally and will be sent to the lowest priority + * queue. + * + * Disable flow-control for now. FIX! support flow control? + */ + // clear all the MIB ctr regs + // Enable reg clear on read. FIX! desc of this bit is inconsistent + // in the GT-96100A datasheet. + GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT, + pcxrFCTL | pcxrFCTLen | pcxrFLP); + read_mib_counters(gp); + GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT, + pcxrFCTL | pcxrFCTLen | pcxrFLP | pcxrMIBclrMode); + + if (gt96100_debug > 2) + printk("%s: gt96100_init: Port Config Ext=%x\n", dev->name, + GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG_EXT)); + + // enable this port (set hash size to 1/2K) + GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, pcrEN | pcrHS); + if (gt96100_debug > 2) + printk("%s: gt96100_init: Port Config=%x\n", dev->name, + GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG)); + + // we should now be receiving frames + if (gt96100_debug > 2) + dump_MII(dev); + + spin_unlock_irqrestore(&gp->lock, flags); + return 0; +} + + +static int gt96100_open(struct net_device *dev) +{ + int retval; + + MOD_INC_USE_COUNT; + + if (gt96100_debug > 2) + printk("%s: gt96100_open: dev=%p\n", dev->name, dev); + + if ((retval = request_irq(dev->irq, >96100_interrupt, + SA_SHIRQ, dev->name, dev))) { + printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, + dev->irq); + MOD_DEC_USE_COUNT; + return retval; + } + // Initialize and startup the GT-96100 ethernet port + if ((retval = gt96100_init(dev))) { + printk(KERN_ERR "%s: error in gt96100_init\n", dev->name); + free_irq(dev->irq, dev); + MOD_DEC_USE_COUNT; + return retval; + } + + netif_start_queue(dev); + + if (gt96100_debug > 2) + printk("%s: gt96100_open: Initialization done.\n", + dev->name); + + return 0; +} + +static int gt96100_close(struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + int i; + + if (gt96100_debug > 2) + printk("%s: gt96100_close: dev=%p\n", dev->name, dev); + + // stop the device + if (netif_device_present(dev)) { + netif_stop_queue(dev); + hard_stop(dev); + } + // free the Rx DMA buffers + for (i = 0; i < RX_RING_SIZE; i++) { + if (gp->rx_buff[i]) { + dmafree(PKT_BUF_SZ, gp->rx_buff[i]); + gp->rx_buff[i] = NULL; + } + } + + free_irq(dev->irq, dev); + + MOD_DEC_USE_COUNT; + return 0; +} + + +static int gt96100_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + unsigned long flags; + int nextIn; + + if (gt96100_debug > 2) + printk("%s: gt96100_tx: skb->len=%d, skb->data=%p\n", + dev->name, skb->len, skb->data); + + spin_lock_irqsave(&gp->lock, flags); + + if (gp->tx_count >= TX_RING_SIZE) { + printk(KERN_WARNING + "%s: Tx Ring full, refusing to send buffer.\n", + dev->name); + gp->stats.tx_dropped++; + spin_unlock_irqrestore(&gp->lock, flags); + return 1; + } + // Prepare the Descriptor at tx_next_in + nextIn = gp->tx_next_in; + + if (dma32_to_cpu(gp->tx_ring[nextIn].cmdstat) & txOwn) { + printk(KERN_ERR "%s: gt96100_tx: TxOwn bit wrong!!\n", + dev->name); + } + + gp->tx_skbuff[nextIn] = skb; + gp->tx_ring[nextIn].byte_cnt = + cpu_to_dma32(skb->len << tdByteCntBit); + gp->tx_ring[nextIn].buff_ptr = + cpu_to_dma32(virt_to_phys(skb->data)); + // Give ownership to device, set first and last desc, enable interrupt + // Setting of ownership bit must be *last*! + gp->tx_ring[nextIn].cmdstat = + cpu_to_dma32((u32) (txOwn | txEI | txFirst | txLast)); + + // increment tx_next_in with wrap + gp->tx_next_in = (nextIn + 1) % TX_RING_SIZE; + // If count is zero, DMA should be stopped, so restart + if (gp->tx_count == 0) { + if (GT96100ETH_READ(gp, GT96100_ETH_PORT_STATUS) & + psrTxLow) printk(KERN_WARNING + "%s: Tx count zero but Tx queue running!\n", + dev->name); + GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, + sdcmrERD | sdcmrTXDL); + } + // increment count and stop queue if full + if (++gp->tx_count == TX_RING_SIZE) + netif_stop_queue(dev); + + dev->trans_start = jiffies; + spin_unlock_irqrestore(&gp->lock, flags); + + return 0; +} + + +static int gt96100_rx(struct net_device *dev, u32 status) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + struct sk_buff *skb; + int pkt_len, nextOut; + gt96100_rd_t *rd; + u32 cmdstat; + + if (gt96100_debug > 2) + printk("%s: gt96100_rx: dev=%p, status = %x\n", + dev->name, dev, status); + + // Continue until we reach the current descriptor pointer + for (nextOut = gp->rx_next_out; + nextOut != + (GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0) - + gp->rx_ring_dma) / sizeof(gt96100_rd_t); + nextOut = (nextOut + 1) % RX_RING_SIZE) { + + rd = &gp->rx_ring[nextOut]; + cmdstat = dma32_to_cpu(rd->cmdstat); + + if (cmdstat & (u32) rxOwn) { + cmdstat &= ~((u32) rxOwn); + rd->cmdstat = cpu_to_dma32(cmdstat); + printk(KERN_ERR + "%s: gt96100_rx: ownership bit wrong!\n", + dev->name); + } + // must be first and last (ie only) buffer of packet + if (!(cmdstat & (u32) rxFirst) + || !(cmdstat & (u32) rxLast)) { + printk(KERN_ERR + "%s: gt96100_rx: desc not first and last!\n", + dev->name); + continue; + } + // drop this received pkt if there were any errors + if ((cmdstat & (u32) rxErrorSummary) + || (status & icrRxErrorQ0)) { + // update the detailed rx error counters that are not covered + // by the MIB counters. + if (cmdstat & (u32) rxOverrun) + gp->stats.rx_fifo_errors++; + continue; + } + + pkt_len = dma32_to_cpu(rd->buff_cnt_sz) & rdByteCntMask; + + /* Create new skb. */ + skb = dev_alloc_skb(pkt_len + 2); + if (skb == NULL) { + printk(KERN_ERR + "%s: Memory squeeze, dropping packet.\n", + dev->name); + gp->stats.rx_dropped++; + continue; + } + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte IP header align */ + skb_put(skb, pkt_len); /* Make room */ + eth_copy_and_sum(skb, gp->rx_buff[nextOut], pkt_len, 0); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); /* pass the packet to upper layers */ + + // now we can release ownership of this desc back to device + cmdstat |= (u32) rxOwn; + rd->cmdstat = cpu_to_dma32(cmdstat); + + dev->last_rx = jiffies; + } + + gp->rx_next_out = nextOut; + return 0; +} + + +static void gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + u32 status; + + if (dev == NULL) { + printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name); + return; + } + + status = GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE); + // ACK interrupts +#if 0 + GT96100ETH_CLRBIT(gp, GT96100_ETH_INT_CAUSE, + icrEtherIntSum | icrRxBufferQ1 | icrRxBufferQ2 | + icrRxBufferQ3 | icrRxBufferQ0 | icrTxBufferHigh | + icrTxEndHigh | icrTxBufferLow | icrTxEndLow | + icrTxErrorHigh | icrTxErrorLow | icrTxUdr); +#else + GT96100ETH_WRITE(gp, GT96100_ETH_INT_CAUSE, 0); +#endif + + if ((status & icrEtherIntSum) == 0) { + // not our interrupt + //printk("%s: isr: no ints? icr=%x,cp0_cause=%x\n", + // dev->name, status, read_32bit_cp0_register(CP0_CAUSE)); + return; + } + + if (gt96100_debug > 3) + printk("%s: isr: entry, icr=%x\n", dev->name, status); + + if (status & (icrRxBufferQ1 | icrRxBufferQ2 | icrRxBufferQ3)) { + printk(KERN_ERR "%s: isr: Rx intr in unused queues!?\n", + dev->name); + } + + if (status & icrRxBufferQ0) { + gt96100_rx(dev, status); + } + + if (status & (icrTxBufferHigh | icrTxEndHigh)) { + printk(KERN_ERR "%s: isr: Tx intr in unused queue!?\n", + dev->name); + } + + if (status & icrMIIPhySTC) { + u32 psr = GT96100ETH_READ(gp, GT96100_ETH_PORT_STATUS); + printk("%s: port status:\n", dev->name); + printk + ("%s: %s MBit/s, %s-duplex, flow-control %s, link is %s,\n", + dev->name, psr & psrSpeed ? "100" : "10", + psr & psrDuplex ? "full" : "half", + psr & psrFctl ? "disabled" : "enabled", + psr & psrLink ? "up" : "down"); + printk + ("%s: TxLowQ is %s, TxHighQ is %s, Transmitter is %s\n", + dev->name, psr & psrTxLow ? "running" : "stopped", + psr & psrTxHigh ? "running" : "stopped", + psr & psrTxInProg ? "on" : "off"); + gp->last_psr = psr; + } + + if (status & (icrTxBufferLow | icrTxEndLow)) { + int nextOut; + gt96100_td_t *td; + u32 cmdstat; + + // Continue until we reach the current descriptor pointer + for (nextOut = gp->tx_next_out; + nextOut != + (GT96100ETH_READ(gp, GT96100_ETH_CURR_TX_DESC_PTR0) - + gp->tx_ring_dma) / sizeof(gt96100_td_t); + nextOut = (nextOut + 1) % TX_RING_SIZE) { + + td = &gp->tx_ring[nextOut]; + cmdstat = dma32_to_cpu(td->cmdstat); + + if (gt96100_debug > 2) + printk("%s: isr: Tx desc cmdstat=%x\n", + dev->name, cmdstat); + + if (cmdstat & (u32) txOwn) { + cmdstat &= ~((u32) txOwn); + td->cmdstat = cpu_to_dma32(cmdstat); + printk(KERN_ERR + "%s: isr: Tx ownership bit wrong!\n", + dev->name); + } + // increment Tx error stats + if (cmdstat & (u32) txErrorSummary) { + if (gt96100_debug > 2) + printk + ("%s: gt96100_interrupt: Tx error, cmdstat = %x\n", + dev->name, cmdstat); + gp->stats.tx_errors++; + if (cmdstat & (u32) txReTxLimit) + gp->stats.collisions++; + if (cmdstat & (u32) txUnderrun) + gp->stats.tx_fifo_errors++; + if (cmdstat & (u32) txLateCollision) + gp->stats.tx_window_errors++; + } + // Wake the queue if the ring was full + if (gp->tx_count == TX_RING_SIZE) + netif_wake_queue(dev); + + // decrement tx ring buffer count + if (gp->tx_count) + gp->tx_count--; + + // free the skb + if (gp->tx_skbuff[nextOut]) { + if (gt96100_debug > 2) + printk + ("%s: isr: good Tx, skb=%p\n", + dev->name, + gp->tx_skbuff[nextOut]); + dev_kfree_skb_irq(gp->tx_skbuff[nextOut]); + gp->tx_skbuff[nextOut] = NULL; + } else { + printk(KERN_ERR "%s: isr: no skb!\n", + dev->name); + } + } + + if (gp->tx_count == 0 && nextOut != gp->tx_next_in) { + // FIX! this should probably be a panic + printk(KERN_ERR + "%s: isr: warning! Tx queue inconsistent\n", + dev->name); + } + + gp->tx_next_out = nextOut; + + if ((status & icrTxEndLow) && gp->tx_count != 0) { + // we must restart the DMA + if (gt96100_debug > 2) + printk("%s: isr: Restarting Tx DMA\n", + dev->name); + GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, + sdcmrERD | sdcmrTXDL); + } + } + // Now check TX errors (RX errors were handled in gt96100_rx) + + if (status & icrTxErrorHigh) { + printk(KERN_ERR + "%s: isr: Tx resource error in unused queue!?\n", + dev->name); + } + + if (status & icrTxErrorLow) { + printk(KERN_ERR "%s: isr: Tx resource error\n", dev->name); + } + + if (status & icrTxUdr) { + printk(KERN_ERR "%s: isr: Tx underrun error\n", dev->name); + } + + if (gt96100_debug > 3) + printk("%s: isr: exit, icr=%x\n", + dev->name, GT96100ETH_READ(gp, + GT96100_ETH_INT_CAUSE)); +} + + +/* + * The Tx ring has been full longer than the watchdog timeout + * value, meaning that the interrupt routine has not been freeing + * up space in the Tx ring buffer. + */ +static void gt96100_tx_timeout(struct net_device *dev) +{ +// struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + + printk(KERN_ERR "%s: gt96100_tx_timeout: dev=%p\n", dev->name, + dev); + + // FIX! do something, like reset the device +} + + +static void gt96100_set_rx_mode(struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + unsigned long flags; + struct dev_mc_list *mcptr; + + if (gt96100_debug > 2) + printk("%s: gt96100_set_rx_mode: dev=%p, flags=%x\n", + dev->name, dev, dev->flags); + + // stop the Receiver DMA + abort(dev, sdcmrAR); + + spin_lock_irqsave(&gp->lock, flags); + + if (dev->flags & IFF_PROMISC) + GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, + pcrEN | pcrHS | pcrPM); + + memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE); // clear hash table + // Add our ethernet address + gt96100_add_hash_entry(dev, dev->dev_addr); + + if (dev->mc_count) { + for (mcptr = dev->mc_list; mcptr; mcptr = mcptr->next) { + gt96100_add_hash_entry(dev, mcptr->dmi_addr); + } + } + // restart Rx DMA + GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD); + + spin_unlock_irqrestore(&gp->lock, flags); +} + +static struct net_device_stats *gt96100_get_stats(struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + unsigned long flags; + + if (gt96100_debug > 2) + printk("%s: gt96100_get_stats: dev=%p\n", dev->name, dev); + + if (netif_device_present(dev)) { + spin_lock_irqsave(&gp->lock, flags); + update_stats(gp); + spin_unlock_irqrestore(&gp->lock, flags); + } + + return &gp->stats; +} + +module_init(gt96100_probe); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/gt96100eth.h linux.ac/drivers/net/gt96100eth.h --- linux.vanilla/drivers/net/gt96100eth.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/gt96100eth.h Tue Apr 3 17:54:51 2001 @@ -0,0 +1,326 @@ +/* + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * stevel@mvista.com or support@mvista.com + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + * + * Ethernet driver definitions for the MIPS GT96100 Advanced + * Communication Controller. + * + */ +#ifndef _GT96100ETH_H +#define _GT96100ETH_H + +#include <linux/config.h> +#include <asm/galileo-boards/gt96100.h> + +/* Keep the ring sizes a power of two for efficiency. */ +#define TX_RING_SIZE 16 +#define RX_RING_SIZE 32 +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ + +#define RX_HASH_TABLE_SIZE 16384 +#define HASH_HOP_NUMBER 12 + +#define NUM_INTERFACES 2 + +#define GT96100ETH_TX_TIMEOUT HZ + +#define GT96100_ETH0_BASE (MIPS_GT96100_BASE + GT96100_ETH_PORT_CONFIG) +#define GT96100_ETH1_BASE (GT96100_ETH0_BASE + GT96100_ETH_IO_SIZE) + +#ifdef CONFIG_MIPS_EV96100 +#define GT96100_ETHER0_IRQ 4 +#define GT96100_ETHER1_IRQ 4 +#else +#define GT96100_ETHER0_IRQ -1 +#define GT96100_ETHER1_IRQ -1 +#endif + +#define GT96100ETH_READ(gp, offset) \ + GT96100_READ((gp->port_offset + offset)) + +#define GT96100ETH_WRITE(gp, offset, data) \ + GT96100_WRITE((gp->port_offset + offset), data) + +#define GT96100ETH_SETBIT(gp, offset, bits) {\ + u32 val = GT96100ETH_READ(gp, offset); val |= (u32)(bits); \ + GT96100ETH_WRITE(gp, offset, val); } + +#define GT96100ETH_CLRBIT(gp, offset, bits) {\ + u32 val = GT96100ETH_READ(gp, offset); val &= (u32)(~(bits)); \ + GT96100ETH_WRITE(gp, offset, val); } + + +/* Bit definitions of the SMI Reg */ +enum { + smirDataMask = 0xffff, + smirPhyAdMask = 0x1f << 16, + smirPhyAdBit = 16, + smirRegAdMask = 0x1f << 21, + smirRegAdBit = 21, + smirOpCode = 1 << 26, + smirReadValid = 1 << 27, + smirBusy = 1 << 28 +}; + +/* Bit definitions of the Port Config Reg */ +enum pcr_bits { + pcrPM = 1, + pcrRBM = 2, + pcrPBF = 4, + pcrEN = 1 << 7, + pcrLPBKMask = 0x3 << 8, + pcrLPBKBit = 8, + pcrFC = 1 << 10, + pcrHS = 1 << 12, + pcrHM = 1 << 13, + pcrHDM = 1 << 14, + pcrHD = 1 << 15, + pcrISLMask = 0x7 << 28, + pcrISLBit = 28, + pcrACCS = 1 << 31 +}; + +/* Bit definitions of the Port Config Extend Reg */ +enum pcxr_bits { + pcxrIGMP = 1, + pcxrSPAN = 2, + pcxrPAR = 4, + pcxrPRIOtxMask = 0x7 << 3, + pcxrPRIOtxBit = 3, + pcxrPRIOrxMask = 0x3 << 6, + pcxrPRIOrxBit = 6, + pcxrPRIOrxOverride = 1 << 8, + pcxrDPLXen = 1 << 9, + pcxrFCTLen = 1 << 10, + pcxrFLP = 1 << 11, + pcxrFCTL = 1 << 12, + pcxrMFLMask = 0x3 << 14, + pcxrMFLBit = 14, + pcxrMIBclrMode = 1 << 16, + pcxrSpeed = 1 << 18, + pcxrSpeeden = 1 << 19, + pcxrRMIIen = 1 << 20, + pcxrDSCPen = 1 << 21 +}; + +/* Bit definitions of the Port Command Reg */ +enum pcmr_bits { + pcmrFJ = 1 << 15 +}; + + +/* Bit definitions of the Port Status Reg */ +enum psr_bits { + psrSpeed = 1, + psrDuplex = 2, + psrFctl = 4, + psrLink = 8, + psrPause = 1 << 4, + psrTxLow = 1 << 5, + psrTxHigh = 1 << 6, + psrTxInProg = 1 << 7 +}; + +/* Bit definitions of the SDMA Config Reg */ +enum sdcr_bits { + sdcrRCMask = 0xf << 2, + sdcrRCBit = 2, + sdcrBLMR = 1 << 6, + sdcrBLMT = 1 << 7, + sdcrPOVR = 1 << 8, + sdcrRIFB = 1 << 9, + sdcrBSZMask = 0x3 << 12, + sdcrBSZBit = 12 +}; + +/* Bit definitions of the SDMA Command Reg */ +enum sdcmr_bits { + sdcmrERD = 1 << 7, + sdcmrAR = 1 << 15, + sdcmrSTDH = 1 << 16, + sdcmrSTDL = 1 << 17, + sdcmrTXDH = 1 << 23, + sdcmrTXDL = 1 << 24, + sdcmrAT = 1 << 31 +}; + +/* Bit definitions of the Interrupt Cause Reg */ +enum icr_bits { + icrRxBuffer = 1, + icrTxBufferHigh = 1 << 2, + icrTxBufferLow = 1 << 3, + icrTxEndHigh = 1 << 6, + icrTxEndLow = 1 << 7, + icrRxError = 1 << 8, + icrTxErrorHigh = 1 << 10, + icrTxErrorLow = 1 << 11, + icrRxOVR = 1 << 12, + icrTxUdr = 1 << 13, + icrRxBufferQ0 = 1 << 16, + icrRxBufferQ1 = 1 << 17, + icrRxBufferQ2 = 1 << 18, + icrRxBufferQ3 = 1 << 19, + icrRxErrorQ0 = 1 << 20, + icrRxErrorQ1 = 1 << 21, + icrRxErrorQ2 = 1 << 22, + icrRxErrorQ3 = 1 << 23, + icrMIIPhySTC = 1 << 28, + icrSMIdone = 1 << 29, + icrEtherIntSum = 1 << 31 +}; + + +/* The Rx and Tx descriptor lists. */ + +typedef struct { + u32 cmdstat; + u32 byte_cnt; + u32 buff_ptr; + u32 next; +} gt96100_td_t; + +#define tdByteCntBit 16 + +typedef struct { + u32 cmdstat; + u32 buff_cnt_sz; + u32 buff_ptr; + u32 next; +} gt96100_rd_t; + +#define rdBuffSzBit 16 +#define rdByteCntMask 0xffff + + +/* Values for the Tx command-status descriptor entry. */ +enum td_cmdstat { + txOwn = 1 << 31, + txAutoMode = 1 << 30, + txEI = 1 << 23, + txGenCRC = 1 << 22, + txPad = 1 << 18, + txFirst = 1 << 17, + txLast = 1 << 16, + txErrorSummary = 1 << 15, + txReTxCntMask = 0x0f << 10, + txReTxCntBit = 10, + txCollision = 1 << 9, + txReTxLimit = 1 << 8, + txUnderrun = 1 << 6, + txLateCollision = 1 << 5 +}; + +#define TxReTxCntBit 10 + +/* Values for the Rx command-status descriptor entry. */ +enum rd_cmdstat { + rxOwn = 1 << 31, + rxAutoMode = 1 << 30, + rxEI = 1 << 23, + rxFirst = 1 << 17, + rxLast = 1 << 16, + rxErrorSummary = 1 << 15, + rxIGMP = 1 << 14, + rxHashExpired = 1 << 13, + rxMissedFrame = 1 << 12, + rxFrameType = 1 << 11, + rxShortFrame = 1 << 8, + rxMaxFrameLen = 1 << 7, + rxOverrun = 1 << 6, + rxCollision = 1 << 4, + rxCRCError = 1 +}; + +/* Bit fields of a Hash Table Entry */ +enum hash_table_entry { + hteValid = 1, + hteSkip = 2, + hteRD = 4 +}; + +// The MIB counters +typedef struct { + u32 byteReceived; + u32 byteSent; + u32 framesReceived; + u32 framesSent; + u32 totalByteReceived; + u32 totalFramesReceived; + u32 broadcastFramesReceived; + u32 multicastFramesReceived; + u32 cRCError; + u32 oversizeFrames; + u32 fragments; + u32 jabber; + u32 collision; + u32 lateCollision; + u32 frames64; + u32 frames65_127; + u32 frames128_255; + u32 frames256_511; + u32 frames512_1023; + u32 frames1024_MaxSize; + u32 macRxError; + u32 droppedFrames; + u32 outMulticastFrames; + u32 outBroadcastFrames; + u32 undersizeFrames; +} mib_counters_t; + + +struct gt96100_private { + gt96100_rd_t *rx_ring; + gt96100_td_t *tx_ring; + // The Rx and Tx rings must be 16-byte aligned + dma_addr_t rx_ring_dma; + dma_addr_t tx_ring_dma; + char *hash_table; + // The Hash Table must be 8-byte aligned + dma_addr_t hash_table_dma; + int hash_mode; + + // The Rx buffers must be 8-byte aligned + char *rx_buff[RX_RING_SIZE]; + // Tx buffers (tx_skbuff[i]->data) with less than 8 bytes + // of payload must be 8-byte aligned + struct sk_buff *tx_skbuff[TX_RING_SIZE]; + int rx_next_out; /* The next free ring entry to receive */ + int tx_next_in; /* The next free ring entry to send */ + int tx_next_out; /* The last ring entry the ISR processed */ + int tx_count; /* current # of pkts waiting to be sent in Tx ring */ + + mib_counters_t mib; + struct net_device_stats stats; + + int io_size; + int port_num; // 0 or 1 + u32 port_offset; + + int phy_addr; // PHY address + u32 last_psr; // last value of the port status register + + int options; /* User-settable misc. driver options. */ + int drv_flags; + unsigned char phys[2]; /* MII device addresses. */ + spinlock_t lock; /* Serialise access to device */ +}; + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/hamachi.c linux.ac/drivers/net/hamachi.c --- linux.vanilla/drivers/net/hamachi.c Tue Apr 3 17:32:11 2001 +++ linux.ac/drivers/net/hamachi.c Sat Apr 14 01:24:35 2001 @@ -44,7 +44,7 @@ #define hamachi_debug debug /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 40; -static int mtu = 0; +static int mtu; /* Default values selected by testing on a dual processor PIII-450 */ /* These six interrupt control parameters may be set directly when loading the * module, or through the rx_params and tx_params variables @@ -60,13 +60,13 @@ -Setting to > 1518 causes all frames to be copied -Setting to 0 disables copies */ -static int rx_copybreak = 0; +static int rx_copybreak; /* An override for the hardware detection of bus width. Set to 1 to force 32 bit PCI bus detection. Set to 4 to force 64 bit. Add 2 to disable parity detection. */ -static int force32 = 0; +static int force32; /* Used to pass the media type, etc. @@ -548,13 +548,13 @@ static int __init hamachi_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { - static int did_version = 0; /* Already printed version info. */ + static int did_version; /* Already printed version info. */ struct hamachi_private *hmp; int option, i, rx_int_var, tx_int_var, boguscnt; int chip_id = ent->driver_data; int irq; long ioaddr; - static int card_idx = 0; + static int card_idx; struct net_device *dev; if (hamachi_debug > 0 && did_version++ == 0) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/hamradio/6pack.c linux.ac/drivers/net/hamradio/6pack.c --- linux.vanilla/drivers/net/hamradio/6pack.c Fri Feb 9 00:32:44 2001 +++ linux.ac/drivers/net/hamradio/6pack.c Tue Apr 3 17:54:51 2001 @@ -711,10 +711,6 @@ /* Do sanity checks on maximum device parameter. */ if (sixpack_maxdev < 4) sixpack_maxdev = 4; - if (sixpack_maxdev * sizeof(void*) >= KMALLOC_MAXSIZE) { - printk(msg_invparm); - return -ENFILE; - } printk(msg_banner, sixpack_maxdev); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/hplance.c linux.ac/drivers/net/hplance.c --- linux.vanilla/drivers/net/hplance.c Tue Feb 13 21:15:04 2001 +++ linux.ac/drivers/net/hplance.c Sat Apr 14 01:24:35 2001 @@ -63,7 +63,7 @@ static unsigned short hplance_readrdp(struct hplance_private *lp); #ifdef MODULE -static struct hplance_private *root_hplance_dev = NULL; +static struct hplance_private *root_hplance_dev; #endif /* Find all the HP Lance boards and initialise them... */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/hydra.c linux.ac/drivers/net/hydra.c --- linux.vanilla/drivers/net/hydra.c Tue Feb 13 21:15:04 2001 +++ linux.ac/drivers/net/hydra.c Sat Apr 14 01:24:35 2001 @@ -60,7 +60,7 @@ #define WORDSWAP(a) ((((a)>>8)&0xff) | ((a)<<8)) #ifdef MODULE -static struct net_device *root_hydra_dev = NULL; +static struct net_device *root_hydra_dev; #endif static int __init hydra_probe(void); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/irda/Config.in linux.ac/drivers/net/irda/Config.in --- linux.vanilla/drivers/net/irda/Config.in Sat Jan 29 03:36:22 2000 +++ linux.ac/drivers/net/irda/Config.in Tue Apr 3 17:54:52 2001 @@ -5,14 +5,6 @@ dep_tristate 'IrTTY (uses Linux serial driver)' CONFIG_IRTTY_SIR $CONFIG_IRDA dep_tristate 'IrPORT (IrDA serial driver)' CONFIG_IRPORT_SIR $CONFIG_IRDA -comment 'FIR device drivers' -dep_tristate 'NSC PC87108/PC87338' CONFIG_NSC_FIR $CONFIG_IRDA -dep_tristate 'Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA -dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA -if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then -dep_tristate 'SMC IrCC (Experimental)' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA -fi - comment 'Dongle support' bool 'Serial dongle support' CONFIG_DONGLE if [ "$CONFIG_DONGLE" != "n" ]; then @@ -22,6 +14,15 @@ dep_tristate ' Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRDA dep_tristate ' Parallax LiteLink dongle' CONFIG_LITELINK_DONGLE $CONFIG_IRDA dep_tristate ' Old Belkin dongle' CONFIG_OLD_BELKIN_DONGLE $CONFIG_IRDA +fi + +comment 'FIR device drivers' +dep_tristate 'IrDA USB dongles (Experimental)' CONFIG_USB_IRDA $CONFIG_IRDA $CONFIG_USB $CONFIG_EXPERIMENTAL +dep_tristate 'NSC PC87108/PC87338' CONFIG_NSC_FIR $CONFIG_IRDA +dep_tristate 'Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA +dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA +if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then +dep_tristate 'SMC IrCC (Experimental)' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA fi endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/irda/Makefile linux.ac/drivers/net/irda/Makefile --- linux.vanilla/drivers/net/irda/Makefile Fri Dec 29 22:07:22 2000 +++ linux.ac/drivers/net/irda/Makefile Tue Apr 3 17:54:52 2001 @@ -12,6 +12,7 @@ obj-$(CONFIG_IRTTY_SIR) += irtty.o obj-$(CONFIG_IRPORT_SIR) += irport.o +obj-$(CONFIG_USB_IRDA) += irda-usb.o obj-$(CONFIG_NSC_FIR) += nsc-ircc.o obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o obj-$(CONFIG_TOSHIBA_FIR) += toshoboe.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/irda/irda-usb.c linux.ac/drivers/net/irda/irda-usb.c --- linux.vanilla/drivers/net/irda/irda-usb.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/irda/irda-usb.c Tue Apr 17 15:29:13 2001 @@ -0,0 +1,1176 @@ +/***************************************************************************** + * + * Filename: irda-usb.c + * Version: 0.9 + * Description: IrDA-USB Driver + * Status: Experimental + * Author: Dag Brattli <dag@brattli.net> + * + * Copyright (C) 2001, Dag Brattli <dag@brattli.net> + * Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com> + * Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at> + * + * 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 <linux/module.h> + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/malloc.h> +#include <linux/rtnetlink.h> +#include <linux/usb.h> + +#include <net/irda/irda.h> +#include <net/irda/irlap.h> +#include <net/irda/irda_device.h> +#include <net/irda/wrapper.h> + +#include <net/irda/irda-usb.h> + +static u32 min_turn_times[] = { 10000, 5000, 1000, 500, 100, 50, 10, 0 }; /* us */ +static int qos_mtt_bits = 0; + +static void irda_usb_dump_class_desc(struct irda_class_desc *desc); +static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum); +static void irda_usb_disconnect(struct usb_device *dev, void *ptr); +static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self); +static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev); +static int irda_usb_open(struct irda_usb_cb *self); +static int irda_usb_close(struct irda_usb_cb *self); +static void irda_usb_write_bulk(struct irda_usb_cb *self, purb_t purb); +static void write_bulk_callback(purb_t purb); +static void irda_usb_receive(purb_t purb); +static int irda_usb_net_init(struct net_device *dev); +static int irda_usb_net_open(struct net_device *dev); +static int irda_usb_net_close(struct net_device *dev); +static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static void irda_usb_net_timeout(struct net_device *dev); +static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev); + +/* Master instance for each hardware found */ +#define NIRUSB 4 /* Max number of USB-IrDA dongles */ +static struct irda_usb_cb irda_instance[NIRUSB]; + +/* These are the currently known IrDA USB dongles. Add new dongles here */ +static struct usb_device_id dongles[] = { + /* ACTiSYS Corp, ACT-IR2000U FIR-USB Adapter */ + { USB_DEVICE(0x9c4, 0x011), driver_info: IUC_SPEED_BUG | IUC_NO_WINDOW }, + /* KC Technology Inc., KC-180 USB IrDA Device */ + { USB_DEVICE(0x50f, 0x180), driver_info: IUC_SPEED_BUG | IUC_NO_WINDOW }, + /* Extended Systems, Inc., XTNDAccess IrDA USB (ESI-9685) */ + { USB_DEVICE(0x8e9, 0x100), driver_info: IUC_SPEED_BUG | IUC_NO_WINDOW }, + { match_flags: USB_DEVICE_ID_MATCH_INT_CLASS, + bInterfaceClass: USB_CLASS_APP_SPEC, + bInterfaceSubClass: USB_CLASS_IRDA, + driver_info: IUC_DEFAULT, }, + { }, /* The end */ +}; + +MODULE_DEVICE_TABLE(usb, dongles); + +/* + * This routine is called by the USB subsystem for each new device + * in the system. We need to check if the device is ours, and in + * this case start handling it. + * Note : it might be worth protecting this function by a global + * spinlock... + */ +static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum, + const struct usb_device_id *id) +{ + struct irda_usb_cb *self = NULL; + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + struct irda_class_desc *irda_desc; + int capability = id->driver_info; + int ret; + int ep; + int i; + + IRDA_DEBUG(0, "Vendor: %x, Product: %x\n", dev->descriptor.idVendor, dev->descriptor.idProduct); + + MESSAGE("IRDA-USB found at address %d\n", dev->devnum); + + /* Try to cleanup all instance that have a pending disconnect + * Instance will be in this state is the disconnect() occurs + * before the net_close(). + * Jean II */ + for (i = 0; i < NIRUSB; i++) { + struct irda_usb_cb *irda = &irda_instance[i]; + if ((irda->usbdev != NULL) && + (irda->present == 0) && + (irda->netopen == 0)) { + IRDA_DEBUG(0, __FUNCTION__ "(), found a zombie instance !!!\n"); + irda_usb_disconnect(irda->usbdev, (void *) irda); + } + } + + /* Find an free instance to handle this new device... */ + self = NULL; + for (i = 0; i < NIRUSB; i++) { + if(irda_instance[i].usbdev == NULL) { + self = &irda_instance[i]; + break; + } + } + if (self == NULL) { + IRDA_DEBUG(0, "Too many USB IrDA devices !!! (max = %d)\n", + NIRUSB); + return NULL; + } + + /* Reset the instance */ + self->present = 0; + self->netopen = 0; + + /* Is this really necessary? */ + if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) { + err("set_configuration failed"); + return NULL; + } + + /* Is this really necessary? */ + ret = usb_set_interface(dev, ifnum, 0); + IRDA_DEBUG(0, "usb-irda: set interface result %d\n", ret); + switch (ret) { + case USB_ST_NOERROR: /* 0 */ + break; + case USB_ST_STALL: /* -EPIPE = -32 */ + usb_clear_halt(dev, usb_sndctrlpipe(dev, 0)); + IRDA_DEBUG(0, __FUNCTION__ "(), Clearing stall on control interface\n" ); + break; + default: + IRDA_DEBUG(0, __FUNCTION__ "(), Unknown error %d\n", ret); + return NULL; + break; + } + + /* Find our endpoints */ + interface = &dev->actconfig->interface[ifnum].altsetting[0]; + endpoint = interface->endpoint; + ep = endpoint[0].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + if ((endpoint[0].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) + self->bulk_in_ep = ep; + else { + self->bulk_out_ep = ep; + self->bulk_out_mtu = endpoint[0].wMaxPacketSize; + } + + ep = endpoint[1].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + if ((endpoint[1].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) + self->bulk_in_ep = ep; + else { + self->bulk_out_ep = ep; + self->bulk_out_mtu = endpoint[1].wMaxPacketSize; + } + + if (self->bulk_out_ep == 0 || self->bulk_in_ep == 0 || + endpoint [0].bmAttributes != USB_ENDPOINT_XFER_BULK || + endpoint [1].bmAttributes != USB_ENDPOINT_XFER_BULK) + { + ERROR(__FUNCTION__ "(), Bogus endpoints"); + return NULL; + } + + /* Find IrDA class descriptor */ + irda_desc = irda_usb_find_class_desc(dev, ifnum); + if (irda_desc == NULL) + return NULL; + + self->irda_desc = irda_desc; + self->present = 1; + self->netopen = 0; + self->capability = capability; + self->usbdev = dev; + ret = irda_usb_open(self); + if (ret) + return NULL; + + return self; +} + +/* + * Function irda_usb_find_class_desc(dev, ifnum) + * + * Returns instance of IrDA class descriptor, or NULL if not found + * + */ +static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum) +{ + struct usb_interface_descriptor *interface; + struct irda_class_desc *desc, *ptr; + int ret; + + desc = kmalloc(sizeof (struct irda_class_desc), GFP_KERNEL); + if (desc == NULL) + return NULL; + memset(desc, 0, sizeof(struct irda_class_desc)); + + ret = usb_get_class_descriptor(dev, ifnum, USB_DT_IRDA, 0, (void *) desc, sizeof(struct irda_class_desc)); + IRDA_DEBUG(0, __FUNCTION__ "(), ret=%d\n", ret); + if (ret) { + WARNING("usb-irda: usb_get_class_descriptor failed (0x%x)\n", ret); + } + + /* Check if we found it? */ + if (desc->bDescriptorType == USB_DT_IRDA) + return desc; + + IRDA_DEBUG(0, __FUNCTION__ "(), parsing extra descriptors ...\n"); + + /* Check if the class descriptor is interleaved with standard descriptors */ + interface = &dev->actconfig->interface[ifnum].altsetting[0]; + ret = usb_get_extra_descriptor(interface, USB_DT_IRDA, &ptr); + if (ret) { + kfree(desc); + return NULL; + } + *desc = *ptr; +#if 0 + irda_usb_dump_class_desc(desc); +#endif + return desc; +} + +/* + * Function usb_irda_dump_class_desc(desc) + * + * Prints out the contents of the IrDA class descriptor + * + */ +static void irda_usb_dump_class_desc(struct irda_class_desc *desc) +{ + printk("bLength=%x\n", desc->bLength); + printk("bDescriptorType=%x\n", desc->bDescriptorType); + printk("bcdSpecRevision=%x\n", desc->bcdSpecRevision); + printk("bmDataSize=%x\n", desc->bmDataSize); + printk("bmWindowSize=%x\n", desc->bmWindowSize); + printk("bmMinTurnaroundTime=%d\n", desc->bmMinTurnaroundTime); + printk("wBaudRate=%x\n", desc->wBaudRate); + printk("bmAdditionalBOFs=%x\n", desc->bmAdditionalBOFs); + printk("bIrdaRateSniff=%x\n", desc->bIrdaRateSniff); + printk("bMaxUnicastList=%x\n", desc->bMaxUnicastList); +} + +static void irda_usb_disconnect(struct usb_device *dev, void *ptr) +{ + struct irda_usb_cb *self = (struct irda_usb_cb *) ptr; + int i; + + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + /* Oups ! We are not there any more */ + self->present = 0; + + /* Hum... Check if networking is still active */ + if (self->netopen) { + /* Accept no more transmissions */ + /*netif_device_detach(self->netdev);*/ + netif_stop_queue(self->netdev); + /* Stop all the receive URBs */ + for (i = 0; i < IU_MAX_RX_URBS; i++) + usb_unlink_urb(&(self->rx_urb[i])); + /* Cancel Tx and speed URB */ + usb_unlink_urb(&(self->tx_urb)); + usb_unlink_urb(&(self->speed_urb)); + + IRDA_DEBUG(0, __FUNCTION__ "(), postponing disconnect, network is still active...\n"); + /* better not do anything just yet, usb_irda_cleanup() + * will do whats needed */ + return; + } + + /* Cleanup the device stuff */ + irda_usb_close(self); + /* No longer attached to USB bus */ + self->usbdev = NULL; + IRDA_DEBUG(0, __FUNCTION__ "(), USB IrDA Disconnected\n"); +} + +static struct usb_driver irda_driver = { + name: "irda-usb", + probe: irda_usb_probe, + disconnect: irda_usb_disconnect, + id_table: dongles, +}; + +static void irda_usb_init_qos(struct irda_usb_cb *self) +{ + struct irda_class_desc *desc; + + desc = self->irda_desc; + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&self->qos); + + self->qos.baud_rate.bits = desc->wBaudRate; + self->qos.min_turn_time.bits = desc->bmMinTurnaroundTime; + self->qos.additional_bofs.bits = desc->bmAdditionalBOFs; + self->qos.window_size.bits = desc->bmWindowSize; + self->qos.data_size.bits = desc->bmDataSize; + + IRDA_DEBUG(0, __FUNCTION__ "(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n", self->qos.baud_rate.bits, self->qos.data_size.bits, self->qos.window_size.bits, self->qos.additional_bofs.bits, self->qos.min_turn_time.bits); + + /* Don't always trust what the dongle tell us */ + if (self->capability & IUC_SIR_ONLY) + self->qos.baud_rate.bits &= 0xff; + if (self->capability & IUC_SMALL_PKT) + self->qos.data_size.bits = 0x07; + if (self->capability & IUC_NO_WINDOW) + self->qos.window_size.bits = 0x01; + if (self->capability & IUC_MAX_WINDOW) + self->qos.window_size.bits = 0x7f; + if (self->capability & IUC_MAX_XBOFS) + self->qos.additional_bofs.bits = 0x01; + +#if 1 + /* Module parameter can override the rx window size */ + if (qos_mtt_bits) + self->qos.min_turn_time.bits = qos_mtt_bits; +#endif + /* + * Note : most of those values apply only for the receive path, + * the transmit path will be set differently - Jean II + */ + irda_qos_bits_to_value(&self->qos); + + self->flags |= IFF_SIR; + if (self->qos.baud_rate.value > 115200) + self->flags |= IFF_MIR; + if (self->qos.baud_rate.value > 1152000) + self->flags |= IFF_FIR; + if (self->qos.baud_rate.value > 4000000) + self->flags |= IFF_VFIR; +} + +static int irda_usb_open(struct irda_usb_cb *self) +{ + struct net_device *netdev; + int err; + + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + spin_lock_init(&self->lock); + + irda_usb_init_qos(self); + + self->tx_list = hashbin_new(HB_GLOBAL); + + /* Create a network device for us */ + if (!(netdev = dev_alloc("irda%d", &err))) { + ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); + return -1; + } + self->netdev = netdev; + netdev->priv = (void *) self; + + /* Override the network functions we need to use */ + netdev->init = irda_usb_net_init; + netdev->hard_start_xmit = irda_usb_hard_xmit; + netdev->tx_timeout = irda_usb_net_timeout; + netdev->watchdog_timeo = 110*HZ/1000; /* 110 ms > USB timeout */ + netdev->open = irda_usb_net_open; + netdev->stop = irda_usb_net_close; + netdev->get_stats = irda_usb_net_get_stats; + netdev->do_ioctl = irda_usb_net_ioctl; + + rtnl_lock(); + err = register_netdevice(netdev); + rtnl_unlock(); + if (err) { + ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); + return -1; + } + MESSAGE("IrDA: Registered device %s\n", netdev->name); + + return 0; +} + +static int irda_usb_close(struct irda_usb_cb *self) +{ + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + ASSERT(self != NULL, return -1;); + + /* Remove netdevice */ + if (self->netdev) { + rtnl_lock(); + unregister_netdevice(self->netdev); + self->netdev = NULL; + rtnl_unlock(); + } + hashbin_delete(self->tx_list, (FREE_FUNC) &dev_kfree_skb_any); + + return 0; +} + +/* + * Function irda_usb_build_header(self, skb, header) + * + * Builds USB-IrDA outbound header + * + * Important note : the USB-IrDA spec 1.0 say very clearly in chapter 5.4.2.2 + * that the setting of the link speed and xbof number in this outbound header + * should be applied *AFTER* the frame has been sent. + * Unfortunately, some devices are not compliant with that... It seems that + * reading the spec is far too difficult... + * Jean II + */ +static void irda_usb_build_header(struct irda_usb_cb *self, u8 *header, + int force) +{ + /* Set the negotiated link speed */ + if (self->new_speed != -1) { + /* Hum... Ugly hack :-( + * Some device are not compliant with the spec and change + * parameters *before* sending the frame. - Jean II + */ + if ((self->capability & IUC_SPEED_BUG) && + (!force) && (self->speed != -1)) + { + /* No speed and xbofs change here + * (we'll do it later in the write callback) */ + IRDA_DEBUG(2, __FUNCTION__ "(), not changing speed yet\n"); + *header = 0; + return; + } + + IRDA_DEBUG(2, __FUNCTION__ "(), changing speed to %d\n", self->new_speed); + self->speed = self->new_speed; + self->new_speed = -1; + + switch (self->speed) { + case 2400: + *header = SPEED_2400; + break; + default: + case 9600: + *header = SPEED_9600; + break; + case 19200: + *header = SPEED_19200; + break; + case 38400: + *header = SPEED_38400; + break; + case 57600: + *header = SPEED_57600; + break; + case 115200: + *header = SPEED_115200; + break; + case 576000: + *header = SPEED_576000; + break; + case 1152000: + *header = SPEED_1152000; + break; + case 4000000: + *header = SPEED_4000000; + self->new_xbofs = 0; + break; + } + } else + /* No change */ + *header = 0; + + /* Set the negotiated additional XBOFS */ + if (self->new_xbofs != -1) { + IRDA_DEBUG(0, __FUNCTION__ "(), changing xbofs to %d\n", self->new_xbofs); + self->xbofs = self->new_xbofs; + self->new_xbofs = -1; + + switch (self->xbofs) { + case 48: + *header |= 0x10; + break; + case 28: + case 24: /* USB spec 1.0 says 24 */ + *header |= 0x20; + break; + default: + case 12: + *header |= 0x30; + break; + case 5: /* Bug in IrLAP spec? (should be 6) */ + case 6: + *header |= 0x40; + break; + case 3: + *header |= 0x50; + break; + case 2: + *header |= 0x60; + break; + case 1: + *header |= 0x70; + break; + case 0: + *header |= 0x80; + break; + } + } +} + +static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self) +{ + struct sk_buff *skb; + unsigned long flags; + purb_t purb; + int ret; + + IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, xbofs=%d\n", + self->new_speed, self->new_xbofs); + + purb = &self->speed_urb; + if (purb->status != USB_ST_NOERROR) { + WARNING(__FUNCTION__ "(), URB still in use!\n"); + return; + } + spin_lock_irqsave(&self->lock, flags); + + /* Allocate the fake frame */ + skb = dev_alloc_skb(IRDA_USB_SPEED_MTU); + if (!skb) + return; + ((struct irda_skb_cb *)skb->cb)->context = self; + + /* Set the new speed and xbofs in this fake frame */ + irda_usb_build_header(self, skb_put(skb, USB_IRDA_HEADER), 1); + + /* Submit the 0 length IrDA frame to trigger new speed settings */ + FILL_BULK_URB(purb, self->usbdev, + usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), + skb->data, IRDA_USB_MAX_MTU, + write_bulk_callback, skb); + purb->transfer_buffer_length = skb->len; + purb->transfer_flags |= USB_QUEUE_BULK; + purb->timeout = MSECS_TO_JIFFIES(100); + + if ((ret = usb_submit_urb(purb))) { + IRDA_DEBUG(0, __FUNCTION__ "(), failed Speed URB\n"); + } + spin_unlock_irqrestore(&self->lock, flags); +} + +static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct irda_usb_cb *self = netdev->priv; + purb_t purb = &self->tx_urb; + unsigned long flags; + s32 speed; + s16 xbofs; + int mtt; + + /* Check if the device is still there */ + if ((!self) || (!self->present)) { + IRDA_DEBUG(0, __FUNCTION__ "(), Device is gone...\n"); + return 1; /* Failed */ + } + + netif_stop_queue(netdev); + + /* Check if we need to change the number of xbofs */ + xbofs = irda_get_next_xbofs(skb); + if ((xbofs != self->xbofs) && (xbofs != -1)) { + self->new_xbofs = xbofs; + } + + /* Check if we need to change the speed */ + speed = irda_get_next_speed(skb); + if ((speed != self->speed) && (speed != -1)) { + /* Set the desired speed */ + self->new_speed = speed; + + /* Check for empty frame */ + if (!skb->len) { + /* IrLAP send us an empty frame to make us change the + * speed. Changing speed with the USB adapter is in + * fact sending an empty frame to the adapter, so we + * could just let the present function do its job. + * However, we would wait for min turn time, + * do an extra memcpy and increment packet counters... + * Jean II */ + irda_usb_change_speed_xbofs(self); + netdev->trans_start = jiffies; + dev_kfree_skb(skb); + /* Will netif_wake_queue() in callback */ + return 0; + } + } + + if (purb->status != USB_ST_NOERROR) { + WARNING(__FUNCTION__ "(), URB still in use!\n"); + dev_kfree_skb(skb); + return 0; + } + + /* Make room for IrDA-USB header */ + if (skb_cow(skb, USB_IRDA_HEADER)) { + dev_kfree_skb(skb); + return 0; + } + + spin_lock_irqsave(&self->lock, flags); + + /* Change setting for next frame */ + irda_usb_build_header(self, skb_push(skb, USB_IRDA_HEADER), 0); + + /* FIXME: Make macro out of this one */ + ((struct irda_skb_cb *)skb->cb)->context = self; + + FILL_BULK_URB(purb, self->usbdev, + usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), + skb->data, IRDA_USB_MAX_MTU, + write_bulk_callback, skb); + purb->transfer_buffer_length = skb->len; + purb->transfer_flags |= USB_QUEUE_BULK; + purb->timeout = MSECS_TO_JIFFIES(100); + + /* Generate min turn time */ + mtt = irda_get_mtt(skb); + if (mtt) { + int diff; + get_fast_time(&self->now); + diff = self->now.tv_usec - self->stamp.tv_usec; + if (diff < 0) + diff += 1000000; + + /* Check if the mtt is larger than the time we have + * already used by all the protocol processing + */ + if (mtt > diff) { + mtt -= diff; + if (mtt > 1000) { + /* + * FIXME: can we do better than this? Maybe call + * a function which sends a frame to a non + * existing device, or change the speed to the + * current one a number of times just to burn + * time a better way. + */ + mdelay(mtt/1000); + irda_usb_write_bulk(self, purb); + goto out; + } else + udelay(mtt); + } + } + irda_usb_write_bulk(self, purb); +out: + spin_unlock_irqrestore(&self->lock, flags); + + return 0; +} + +static void irda_usb_write_bulk(struct irda_usb_cb *self, purb_t purb) +{ + int len = purb->transfer_buffer_length; + int res; + + if ((res = usb_submit_urb(purb))) { + IRDA_DEBUG(0, __FUNCTION__ "(), failed Tx URB\n"); + self->stats.tx_errors++; + netif_start_queue(self->netdev); + + return; + } + self->stats.tx_packets++; + self->stats.tx_bytes += len; + self->netdev->trans_start = jiffies; + + /* Send empty frame if size if a multiple of the USB max packet size */ + ASSERT(self->bulk_out_mtu == 64, return;); + if ((len % self->bulk_out_mtu) == 0) { + /* Borrow speed urb */ + purb = &self->speed_urb; + FILL_BULK_URB(purb, self->usbdev, + usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), + self, /* Anything not on the stack will do */ + IRDA_USB_MAX_MTU, NULL, NULL); + purb->transfer_buffer_length = 0; + purb->transfer_flags |= USB_QUEUE_BULK; + res = usb_submit_urb(purb); + } +} + +/* + * Note : this function will be called with both tx_urb and speed_urb... + */ +static void write_bulk_callback(purb_t purb) +{ + struct sk_buff *skb = purb->context; + struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context; + + /* We should always have a context */ + if (self == NULL) { + IRDA_DEBUG(0, __FUNCTION__ "(), Bug : self == NULL\n"); + return; + } + + /* urb is now available */ + purb->status = USB_ST_NOERROR; + + dev_kfree_skb_any(skb); + purb->context = NULL; + + /* Check for timeout and other USB nasties */ + if (purb->status != USB_ST_NOERROR) { + /* I get a lot of -ECONNABORTED = -103 here - Jean II */ + WARNING(__FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", + purb->status, purb->transfer_flags); + /* Don't do anything here, that might confuse the USB layer, + * and we could go in recursion and blow the kernel stack... + * Instead, we will wait for irda_usb_net_timeout(), the + * network layer watchdog, to fix the situation. + * Jean II */ + /* A reset of the dongle might be welcomed here - Jean II */ + return; + } + + + /* URB is now available */ + purb->status = USB_ST_NOERROR; + + /* If the network is closed, stop everything */ + if ((!self->netopen) || (!self->present)) { + IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone...\n"); + return; + } + + /* If we need to change the speed or xbofs, do it now */ + if ((self->new_speed != -1) || (self->new_xbofs != -1)) { + IRDA_DEBUG(0, __FUNCTION__ "(), Changing speed now...\n"); + irda_usb_change_speed_xbofs(self); + } else { + /* Otherwise, allow the stack to send more packets */ + netif_wake_queue(self->netdev); + } +} + +static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, purb_t purb) +{ + struct irda_skb_cb *cb; + int ret; + + IRDA_DEBUG(2, __FUNCTION__ "()\n"); + + /* Check that we have an urb */ + if (!purb) { + IRDA_DEBUG(0, __FUNCTION__ "(), Bug : purb == NULL\n"); + return; + } + + /* Allocate new skb if it has not been recycled */ + if (!skb) { + skb = dev_alloc_skb(IRDA_USB_MAX_MTU + 1); + if (!skb) { + /* If this ever happen, we are in deep s***. + * Basically, the Rx path will stop... */ + IRDA_DEBUG(0, __FUNCTION__ "(), Failed to allocate Rx skb\n"); + return; + } + } else { + /* Reset recycled skb */ + skb->data = skb->tail = skb->head; + skb->len = 0; + } + /* Make sure IP header get aligned (IrDA header is 5 bytes ) */ + skb_reserve(skb, 1); + + /* Save ourselves */ + cb = (struct irda_skb_cb *) skb->cb; + cb->context = self; + + /* Reinitialize URB */ + FILL_BULK_URB(purb, self->usbdev, + usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep), + skb->data, skb->truesize, + irda_usb_receive, skb); + purb->transfer_flags |= USB_QUEUE_BULK; + purb->status = USB_ST_NOERROR; + purb->next = NULL; /* Make sure we don't auto resubmit */ + + ret = usb_submit_urb(purb); + if (ret) { + /* If this ever happen, we are in deep s***. + * Basically, the Rx path will stop... */ + IRDA_DEBUG(0, __FUNCTION__ "(), Failed to submit Rx URB %d\n", ret); + } +} + +/* + * Function irda_usb_receive(purb) + * + * Called by the USB subsystem when a frame has been received + * + */ +static void irda_usb_receive(purb_t purb) +{ + struct sk_buff *skb = (struct sk_buff *) purb->context; + struct irda_usb_cb *self; + struct irda_skb_cb *cb; + struct sk_buff *new; + + /* Find ourselves */ + cb = (struct irda_skb_cb *) skb->cb; + ASSERT(cb != NULL, return;); + self = (struct irda_usb_cb *) cb->context; + ASSERT(self != NULL, return;); + + /* If the network is closed or the device gone, stop everything */ + if ((!self->netopen) || (!self->present)) { + IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone!\n"); + /* Don't re-submit the URB : will stall the Rx path */ + return; + } + + /* Check the status */ + if (purb->status != USB_ST_NOERROR) { + switch (purb->status) { + case USB_ST_CRC: /* -EILSEQ */ + self->stats.rx_errors++; + self->stats.rx_crc_errors++; + break; + case -ECONNRESET: + WARNING(__FUNCTION__ "(), Connection Reset !!!\n"); + /* uhci_cleanup_unlink() is going to kill the Rx + * URB just after we return. No problem, at this + * point the URB will be idle ;-) - Jean II */ + break; + default: + WARNING(__FUNCTION__ "(), RX status %d\n", purb->status); + break; + } + goto done; + } + + /* Check for empty frames */ + if (purb->actual_length <= USB_IRDA_HEADER) { + WARNING(__FUNCTION__ "(), empty frame!\n"); + goto done; + } + + /* + * Remember the time we received this frame, so we can + * reduce the min turn time a bit since we will know + * how much time we have used for protocol processing + */ + get_fast_time(&self->stamp); + + /* Fix skb, and remove USB-IrDA header */ + skb_put(skb, purb->actual_length); + skb_pull(skb, USB_IRDA_HEADER); + + /* Don't waste a lot of memory on small IrDA frames */ + if (skb->len < RX_COPY_THRESHOLD) { + new = dev_alloc_skb(skb->len+1); + if (!new) { + self->stats.rx_dropped++; + goto done; + } + + /* Make sure IP header get aligned (IrDA header is 5 bytes) */ + skb_reserve(new, 1); + + /* Copy packet, so we can recycle the original */ + memcpy(skb_put(new, skb->len), skb->data, skb->len); + /* We will cleanup the skb in irda_usb_submit */ + } else { + /* Deliver the original skb */ + new = skb; + skb = NULL; + } + + self->stats.rx_bytes += new->len; + self->stats.rx_packets++; + + /* Ask the networking layer to queue the packet for the IrDA stack */ + new->dev = self->netdev; + new->mac.raw = new->data; + new->protocol = htons(ETH_P_IRDA); + netif_rx(new); +done: + /* Recycle Rx URB (and possible the skb as well) */ + irda_usb_submit(self, skb, self->rx_idle_urb); + + /* Recycle Rx URB : Now, the idle URB is the present one */ + self->rx_idle_urb = purb; + purb->context = NULL; + /* Prevent the USB layer playing games with our URBs */ + purb->status = -ENOENT; +} + +static int irda_usb_net_init(struct net_device *dev) +{ + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + /* Set up to be a normal IrDA network device driver */ + irda_device_setup(dev); + + /* Insert overrides below this line! */ + + return 0; +} + +/* + * Function irda_usb_net_open (dev) + * + * Network device is taken up. Usually this is done by "ifconfig irda0 up" + * + * Note : don't mess with self->netopen - Jean II + */ +static int irda_usb_net_open(struct net_device *netdev) +{ + struct irda_usb_cb *self; + int i; + + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + ASSERT(netdev != NULL, return -1;); + self = (struct irda_usb_cb *) netdev->priv; + ASSERT(self != NULL, return -1;); + + /* Can only open the device if it's there */ + if(!self->present) { + WARNING(__FUNCTION__ "(), device not present!\n"); + return -1; + } + + /* Initialise default speed and xbofs value + * (IrLAP will change that soon) */ + self->speed = -1; + self->xbofs = -1; + self->new_speed = -1; + self->new_xbofs = -1; + + /* To do *before* submitting Rx urbs and starting net Tx queue + * Jean II */ + self->netopen = 1; + + /* + * Now that everything should be initialized properly, + * Open new IrLAP layer instance to take care of us... + * Note : will send immediately a speed change... + */ + self->irlap = irlap_open(netdev, &self->qos); + ASSERT(self->irlap != NULL, return -1;); + + /* Allow IrLAP to send data to us */ + netif_start_queue(netdev); + + /* Now that we can pass data to IrLAP, allow the USB layer + * to send us some data... */ + for (i = 0; i < IU_MAX_ACTIVE_RX_URBS; i++) + irda_usb_submit(self, NULL, &(self->rx_urb[i])); + /* Note : we submit all the Rx URB except for one - Jean II */ + self->rx_idle_urb = &(self->rx_urb[IU_MAX_ACTIVE_RX_URBS]); + self->rx_idle_urb->context = NULL; + + /* Ready to play !!! */ + MOD_INC_USE_COUNT; + return 0; +} + +/* + * Function irda_usb_net_close (self) + * + * Network device is taken down. Usually this is done by + * "ifconfig irda0 down" + */ +static int irda_usb_net_close(struct net_device *netdev) +{ + struct irda_usb_cb *self; + int i; + + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + ASSERT(netdev != NULL, return -1;); + self = (struct irda_usb_cb *) netdev->priv; + ASSERT(self != NULL, return -1;); + + /* Clear this flag *before* unlinking the urbs and *before* + * stopping the network Tx queue - Jean II */ + self->netopen = 0; + + /* Stop network Tx queue */ + netif_stop_queue(netdev); + + /* Deallocate all the Rx path buffers (URBs and skb) */ + for (i = 0; i < IU_MAX_RX_URBS; i++) { + purb_t purb = &(self->rx_urb[i]); + struct sk_buff *skb = (struct sk_buff *) purb->context; + /* Cancel the receive command */ + usb_unlink_urb(purb); + /* The skb is ours, free it */ + if (skb) { + dev_kfree_skb(skb); + purb->context = NULL; + } + } + /* Cancel Tx and speed URB */ + usb_unlink_urb(&self->tx_urb); + usb_unlink_urb(&self->speed_urb); + + /* Stop and remove instance of IrLAP */ + if (self->irlap) + irlap_close(self->irlap); + self->irlap = NULL; + + MOD_DEC_USE_COUNT; + + return 0; +} + +static void irda_usb_net_timeout(struct net_device *netdev) +{ + struct irda_usb_cb *self = netdev->priv; + int done = 0; /* If we have made any progress */ + purb_t purb; + + IRDA_DEBUG(0, __FUNCTION__ "(), Network layer thinks we timed out!\n"); + + if (!self || !self->present) { + WARNING(__FUNCTION__ "(), device not present!\n"); + netif_stop_queue(netdev); + return; + } + WARNING("%s: Tx timed out\n", netdev->name); + + /* Check Tx URB */ + purb = &self->tx_urb; + switch (purb->status) { + case -ECONNABORTED: /* Can't find proper USB_ST_* code */ + purb->status = USB_ST_NOERROR; + netif_wake_queue(self->netdev); + done = 1; + break; + case USB_ST_URB_PENDING: /* -EINPROGRESS == -115 */ + usb_unlink_urb(purb); + done = 1; + break; + default: + break; + } + /* Check speed URB */ + purb = &self->speed_urb; + switch (purb->status) { + case -ECONNABORTED: /* Can't find proper USB_ST_* code */ + purb->status = USB_ST_NOERROR; + netif_wake_queue(self->netdev); + done = 1; + break; + case USB_ST_URB_PENDING: /* -EINPROGRESS */ + usb_unlink_urb(purb); + done = 1; + break; + default: + break; + } + /* Maybe we need a reset */ + /* if(done == 0) */ +} + +static int irda_usb_is_receiving(struct irda_usb_cb *self) +{ + return 0; /* For now */ +} + +static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *) rq; + struct irda_usb_cb *self; + int ret = 0; + + ASSERT(dev != NULL, return -1;); + self = dev->priv; + ASSERT(self != NULL, return -1;); + + IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd); + + /* Check if the device is still there */ + if (!self->present) + return -EFAULT; + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + /* Set the desired speed */ + self->new_speed = irq->ifr_baudrate; + irda_usb_change_speed_xbofs(self); + /* Note : will spinlock in above function */ + break; + case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + irda_device_set_media_busy(self->netdev, TRUE); + break; + case SIOCGRECEIVING: /* Check if we are receiving right now */ + irq->ifr_receiving = irda_usb_is_receiving(self); + break; + default: + ret = -EOPNOTSUPP; + } + return ret; +} + +static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev) +{ + struct irda_usb_cb *self = dev->priv; + return &self->stats; +} + +int __init usb_irda_init(void) +{ + if (usb_register(&irda_driver) < 0) + return -1; + + MESSAGE("USB IrDA support registered\n"); + return 0; +} +module_init(usb_irda_init); + +void __exit usb_irda_cleanup(void) +{ + struct irda_usb_cb *irda = NULL; + int i; + + /* Find zombie instances and kill them... */ + for (i = 0; i < NIRUSB; i++) { + irda = &irda_instance[i]; + /* If the Device is zombie */ + if((irda->usbdev != NULL) && (irda->present == 0)) { + IRDA_DEBUG(0, __FUNCTION__ "(), disconnect zombie now !\n"); + irda_usb_disconnect(irda->usbdev, (void *) irda); + } + } + /* Deregister the driver and remove all pending instances */ + usb_deregister(&irda_driver); +} +module_exit(usb_irda_cleanup); + +MODULE_PARM(qos_mtt_bits, "i"); +MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); +MODULE_AUTHOR("Roman Weissgaerber <weissg@vienna.at>, Dag Brattli <dag@brattli.net> and Jean Tourrilhes <jt@hpl.hp.com>"); +MODULE_DESCRIPTION("IrDA-USB Dongle Driver"); + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/irda/nsc-ircc.c linux.ac/drivers/net/irda/nsc-ircc.c --- linux.vanilla/drivers/net/irda/nsc-ircc.c Tue Apr 3 17:32:11 2001 +++ linux.ac/drivers/net/irda/nsc-ircc.c Tue Apr 3 17:54:52 2001 @@ -251,9 +251,14 @@ IRDA_DEBUG(2, __FUNCTION__ "()\n"); + MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, + info->cfg_base); + if ((nsc_ircc_setup(info)) == -1) return -1; + MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name); + /* Allocate new instance of the driver */ self = kmalloc(sizeof(struct nsc_ircc_cb), GFP_KERNEL); if (self == NULL) { @@ -315,8 +320,8 @@ self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, GFP_KERNEL|GFP_DMA); if (self->tx_buff.head == NULL) { - kfree(self); kfree(self->rx_buff.head); + kfree(self); return -ENOMEM; } memset(self->tx_buff.head, 0, self->tx_buff.truesize); @@ -699,8 +704,6 @@ ERROR("%s, Wrong chip version %02x\n", driver_name, version); return -1; } - MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, - info->cfg_base); /* Switch to advanced mode */ switch_bank(iobase, BANK2); @@ -729,8 +732,6 @@ outb(0x0d, iobase+2); /* Set SIR pulse width to 1.6us */ outb(0x2a, iobase+4); /* Set beginning frag, and preamble length */ - MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name); - /* Enable receive interrupts */ switch_bank(iobase, BANK0); outb(IER_RXHDL_IE, iobase+IER); @@ -1858,7 +1859,7 @@ if (request_dma(self->io.dma, dev->name)) { WARNING("%s, unable to allocate dma=%d\n", driver_name, self->io.dma); - free_irq(self->io.irq, self); + free_irq(self->io.irq, dev); return -EAGAIN; } @@ -2008,18 +2009,10 @@ static void nsc_ircc_wakeup(struct nsc_ircc_cb *self) { - int iobase; - if (!self->io.suspended) return; - iobase = self->io.fir_base; - - /* Switch to advanced mode */ - switch_bank(iobase, BANK2); - outb(ECR1_EXT_SL, iobase+ECR1); - switch_bank(iobase, BANK0); - + nsc_ircc_setup(&self->io); nsc_ircc_net_open(self->netdev); MESSAGE("%s, Waking up\n", driver_name); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/irda/toshoboe.c linux.ac/drivers/net/irda/toshoboe.c --- linux.vanilla/drivers/net/irda/toshoboe.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/irda/toshoboe.c Tue Apr 3 17:54:52 2001 @@ -81,10 +81,18 @@ #include <net/irda/toshoboe.h> -static char *driver_name = "toshoboe"; +#define PCI_DEVICE_ID_FIR701b 0x0d01 -static struct toshoboe_cb *dev_self[NSELFS + 1] = -{NULL, NULL, NULL, NULL, NULL}; +static struct pci_device_id toshoboe_pci_tbl[] __initdata = { + { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIR701, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIR701b, PCI_ANY_ID, PCI_ANY_ID, }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, toshoboe_pci_tbl); + +static const char *driver_name = "toshoboe"; + +static struct toshoboe_cb *dev_self[NSELFS + 1]; static int max_baud = 4000000; @@ -191,8 +199,8 @@ outb_p (OBOE_NTR_VAL, OBOE_NTR); outb_p (0xf0, OBOE_REG_D); outb_p (0xff, OBOE_ISR); - outb_p (0x0f, OBOE_REG_1A); - outb_p (0xff, OBOE_REG_1B); + outb_p (0x0f, OBOE_REG_1B); + outb_p (0xff, OBOE_REG_1A); physaddr = virt_to_bus (self->taskfile); @@ -608,18 +616,21 @@ /* Disable interrupts & save flags */ save_flags(flags); cli(); - switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + goto out; + } /* toshoboe_setbaud(self, irq->ifr_baudrate); */ /* Just change speed once - inserted by Paul Bristow */ self->new_speed = irq->ifr_baudrate; break; case SIOCSMEDIABUSY: /* Set media busy */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + goto out; + } irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ @@ -628,9 +639,8 @@ default: ret = -EOPNOTSUPP; } - +out: restore_flags(flags); - return ret; } @@ -898,7 +908,7 @@ /*FIXME: can't sleep here wait one second */ while ((i--) && (self->txpending)) - mdelay (100); + udelay (100); toshoboe_stopchip (self); toshoboe_disablebm (self); @@ -978,6 +988,24 @@ } while (pci_dev); + + if (!found) do + { + pci_dev = pci_find_device (PCI_VENDOR_ID_TOSHIBA, + PCI_DEVICE_ID_FIR701b, pci_dev); + if (pci_dev) + { + printk (KERN_WARNING "ToshOboe: Found 701b chip at 0x%0lx irq %d\n", + pci_dev->resource[0].start, + pci_dev->irq); + + if (!toshoboe_open (pci_dev)) + found++; + } + + } + while (pci_dev); + if (found) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/isa-skeleton.c linux.ac/drivers/net/isa-skeleton.c --- linux.vanilla/drivers/net/isa-skeleton.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/isa-skeleton.c Sat Apr 14 01:24:35 2001 @@ -163,7 +163,7 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr) { struct net_local *np; - static unsigned version_printed = 0; + static unsigned version_printed; int i; /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/jazzsonic.c linux.ac/drivers/net/jazzsonic.c --- linux.vanilla/drivers/net/jazzsonic.c Tue Apr 3 17:32:11 2001 +++ linux.ac/drivers/net/jazzsonic.c Sat Apr 14 01:24:41 2001 @@ -118,7 +118,7 @@ static int __init sonic_probe1(struct net_device *dev, unsigned int base_addr, unsigned int irq) { - static unsigned version_printed = 0; + static unsigned version_printed; unsigned int silicon_revision; unsigned int val; struct sonic_local *lp; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/lance.c linux.ac/drivers/net/lance.c --- linux.vanilla/drivers/net/lance.c Tue Apr 3 17:32:11 2001 +++ linux.ac/drivers/net/lance.c Sat Apr 14 01:24:41 2001 @@ -389,9 +389,9 @@ int i, reset_val, lance_version; const char *chipname; /* Flags for specific chips or boards. */ - unsigned char hpJ2405A = 0; /* HP ISA adaptor */ - int hp_builtin = 0; /* HP on-board ethernet. */ - static int did_version = 0; /* Already printed version info. */ + unsigned char hpJ2405A = 0; /* HP ISA adaptor */ + int hp_builtin = 0; /* HP on-board ethernet. */ + static int did_version; /* Already printed version info. */ unsigned long flags; /* First we look for special cases. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/lasi_82596.c linux.ac/drivers/net/lasi_82596.c --- linux.vanilla/drivers/net/lasi_82596.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/lasi_82596.c Tue Apr 3 17:54:52 2001 @@ -1009,8 +1009,6 @@ netif_start_queue(dev); - MOD_INC_USE_COUNT; - /* Initialize the 82596 memory */ if (init_i596_mem(dev)) { res = -EAGAIN; @@ -1195,6 +1193,7 @@ DEB(DEB_PROBE,printk(version)); /* The 82596-specific entries in the device structure. */ + SET_MODULE_OWNER(dev); dev->open = i596_open; dev->stop = i596_close; dev->hard_start_xmit = i596_start_xmit; @@ -1423,8 +1422,6 @@ remove_rx_bufs(dev); release_region(dev->base_addr, 12); - - MOD_DEC_USE_COUNT; return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/loopback.c linux.ac/drivers/net/loopback.c --- linux.vanilla/drivers/net/loopback.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/loopback.c Sat Apr 14 01:24:49 2001 @@ -105,7 +105,7 @@ /* Initialize the rest of the LOOPBACK device. */ int __init loopback_init(struct net_device *dev) { - dev->mtu = PAGE_SIZE - LOOPBACK_OVERHEAD; + dev->mtu = (16 * 1024) + 20 + 20 + 12; dev->hard_start_xmit = loopback_xmit; dev->hard_header = eth_header; dev->hard_header_cache = eth_header_cache; @@ -116,14 +116,12 @@ dev->type = ARPHRD_LOOPBACK; /* 0x0001 */ dev->rebuild_header = eth_rebuild_header; dev->flags = IFF_LOOPBACK; + dev->features = NETIF_F_SG|NETIF_F_FRAGLIST|NETIF_F_NO_CSUM|NETIF_F_HIGHDMA; dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; memset(dev->priv, 0, sizeof(struct net_device_stats)); dev->get_stats = get_stats; - - if (num_physpages >= ((128*1024*1024)>>PAGE_SHIFT)) - dev->mtu = 4096*4 - LOOPBACK_OVERHEAD; /* * Fill in the generic fields of the device structure. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/mace.c linux.ac/drivers/net/mace.c --- linux.vanilla/drivers/net/mace.c Tue Apr 3 17:32:11 2001 +++ linux.ac/drivers/net/mace.c Sat Apr 14 01:24:57 2001 @@ -20,7 +20,7 @@ #include <asm/pgtable.h> #include "mace.h" -static struct net_device *mace_devs = NULL; +static struct net_device *mace_devs; #define N_RX_RING 8 #define N_TX_RING 6 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/macmace.c linux.ac/drivers/net/macmace.c --- linux.vanilla/drivers/net/macmace.c Tue Apr 3 17:32:12 2001 +++ linux.ac/drivers/net/macmace.c Sat Apr 14 01:24:57 2001 @@ -200,7 +200,7 @@ int mace68k_probe(struct net_device *unused) { int j; - static int once=0; + static int once; struct mace68k_data *mp; unsigned char *addr; struct net_device *dev; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/macsonic.c linux.ac/drivers/net/macsonic.c --- linux.vanilla/drivers/net/macsonic.c Tue Apr 3 17:32:12 2001 +++ linux.ac/drivers/net/macsonic.c Tue Apr 3 17:54:52 2001 @@ -167,6 +167,8 @@ 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); + kfree(lp->sonic_desc); + lp->sonic_desc = NULL; return -ENOMEM; } @@ -321,7 +323,7 @@ /* methinks this will always be true but better safe than sorry */ if (dev->priv == NULL) { dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL); - if (!dev->priv) /* FIXME: kfree dev if necessary */ + if (!dev->priv) return -ENOMEM; } } else { @@ -517,9 +519,14 @@ if (dev) { dev = init_etherdev(dev, sizeof(struct sonic_local)); + if (!dev) + return -ENOMEM; /* methinks this will always be true but better safe than sorry */ - if (dev->priv == NULL) + if (dev->priv == NULL) { dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL); + if (!dev->priv) /* FIXME: kfree dev if necessary */ + return -ENOMEM; + } } else { dev = init_etherdev(NULL, sizeof(struct sonic_local)); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/mvme147.c linux.ac/drivers/net/mvme147.c --- linux.vanilla/drivers/net/mvme147.c Tue Feb 13 21:15:04 2001 +++ linux.ac/drivers/net/mvme147.c Sat Apr 14 01:24:57 2001 @@ -66,13 +66,13 @@ typedef unsigned short (*readrdp_t)(void *); #ifdef MODULE -static struct m147lance_private *root_m147lance_dev = NULL; +static struct m147lance_private *root_m147lance_dev; #endif /* Initialise the one and only on-board 7990 */ int __init mvme147lance_probe(struct net_device *dev) { - static int called = 0; + static int called; static const char name[] = "MVME147 LANCE"; struct m147lance_private *lp; u_long *addr; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/myri_sbus.c linux.ac/drivers/net/myri_sbus.c --- linux.vanilla/drivers/net/myri_sbus.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/myri_sbus.c Sat Apr 14 01:24:57 2001 @@ -89,7 +89,7 @@ #endif #ifdef MODULE -static struct myri_eth *root_myri_dev = NULL; +static struct myri_eth *root_myri_dev; #endif static void myri_reset_off(unsigned long lp, unsigned long cregs) @@ -886,7 +886,7 @@ static int __init myri_ether_init(struct net_device *dev, struct sbus_dev *sdev, int num) { - static unsigned version_printed = 0; + static unsigned version_printed; struct myri_eth *mp; unsigned char prop_buf[32]; int i; @@ -1109,7 +1109,7 @@ struct net_device *dev = NULL; struct sbus_bus *bus; struct sbus_dev *sdev = 0; - static int called = 0; + static int called; int cards = 0, v; #ifdef MODULE diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/natsemi.c linux.ac/drivers/net/natsemi.c --- linux.vanilla/drivers/net/natsemi.c Tue Apr 3 17:32:12 2001 +++ linux.ac/drivers/net/natsemi.c Sat Apr 14 01:24:57 2001 @@ -64,14 +64,14 @@ static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 20; -static int mtu = 0; +static int mtu; /* Maximum number of multicast addresses to filter (vs. rx-all-multicast). This chip uses a 512 element hash table based on the Ethernet CRC. */ static int multicast_filter_limit = 100; /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1518 effectively disables this feature. */ -static int rx_copybreak = 0; +static int rx_copybreak; /* Used to pass the media type, etc. Both 'options[]' and 'full_duplex[]' should exist for driver diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/ncr885_debug.h linux.ac/drivers/net/ncr885_debug.h --- linux.vanilla/drivers/net/ncr885_debug.h Mon Oct 11 18:13:24 1999 +++ linux.ac/drivers/net/ncr885_debug.h Thu Jan 1 01:00:00 1970 @@ -1,54 +0,0 @@ -#ifndef _H_NCR885_DEBUG -#define _H_NCR885_DEBUG - -struct ncr885e_regs { - unsigned long tx_status; - unsigned long rx_status; - unsigned long mac_config; - unsigned long tx_control; - unsigned long rx_control; - unsigned long tx_cmd_ptr; - unsigned long rx_cmd_ptr; - unsigned long int_status; -}; - -#ifndef __KERNEL__ - -struct ncr885e_private { - - struct dbdma_cmd *head; - struct dbdma_cmd *tx_cmds; - struct dbdma_cmd *rx_cmds; - struct dbdma_cmd *stop_cmd; - - struct sk_buff *tx_skbufs[NR_TX_RING]; - struct sk_buff *rx_skbufs[NR_RX_RING]; - - int rx_current; - int rx_dirty; - - int tx_dirty; - int tx_current; - - unsigned short tx_status[NR_TX_RING]; - - unsigned char tx_fullup; - unsigned char tx_active; - - struct net_device_stats stats; - - struct device *dev; - - struct timer_list tx_timeout; - int timeout_active; - - spinlock_t lock; -}; - -#endif /* __KERNEL__ */ - - -#define NCR885E_GET_PRIV _IOR('N',1,sizeof( struct ncr885e_private )) -#define NCR885E_GET_REGS _IOR('N',2,sizeof( struct ncr885e_regs )) - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/ncr885e.c linux.ac/drivers/net/ncr885e.c --- linux.vanilla/drivers/net/ncr885e.c Sun Dec 31 02:16:13 2000 +++ linux.ac/drivers/net/ncr885e.c Thu Jan 1 01:00:00 1970 @@ -1,1361 +0,0 @@ -/* - * An Ethernet driver for the dual-function NCR 53C885 SCSI/Ethernet - * controller. - * - * - * 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. - * - */ - -static const char *version = -"ncr885e.c:v1.0 02/10/00 dan@synergymicro.com, cort@fsmlabs.com\n"; - -#include <linux/module.h> -#include <linux/version.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/timer.h> -#include <linux/ptrace.h> -#include <linux/malloc.h> -#include <linux/netdevice.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <asm/io.h> -#include <asm/dbdma.h> -#include <asm/uaccess.h> - -#include <linux/etherdevice.h> -#include <linux/skbuff.h> - -#include "ncr885e.h" -#include "ncr885_debug.h" - -static const char *chipname = "ncr885e"; - -#define NCR885E_DEBUG 0 - -/* The 885's Ethernet PCI device id. */ -#ifndef PCI_DEVICE_ID_NCR_53C885_ETHERNET -#define PCI_DEVICE_ID_NCR_53C885_ETHERNET 0x0701 -#endif - -#define NR_RX_RING 8 -#define NR_TX_RING 8 -#define MAX_TX_ACTIVE (NR_TX_RING-1) -#define NCMDS_TX NR_TX_RING - -#define RX_BUFLEN (ETH_FRAME_LEN + 8) -#define TX_TIMEOUT 5*HZ - -#define NCR885E_TOTAL_SIZE 0xe0 - -#define TXSR (1<<6) /* tx: xfer status written */ -#define TXABORT (1<<7) /* tx: abort */ -#define EOP (1<<7) /* rx: end of packet written to buffer */ - -int ncr885e_debug = NCR885E_DEBUG; -static int print_version = 0; - -struct ncr885e_private { - - /* preserve a 1-1 marking with buffs */ - struct dbdma_cmd *head; - struct dbdma_cmd *tx_cmds; - struct dbdma_cmd *rx_cmds; - struct dbdma_cmd *stop_cmd; - - struct sk_buff *tx_skbufs[NR_TX_RING]; - struct sk_buff *rx_skbufs[NR_RX_RING]; - - int rx_current; - int rx_dirty; - - int tx_dirty; - int tx_current; - - unsigned short tx_status[NR_TX_RING]; - - unsigned char tx_fullup; - unsigned char tx_active; - - struct net_device_stats stats; - - struct net_device *dev; - - struct timer_list tx_timeout; - int timeout_active; - - spinlock_t lock; -}; - -static struct net_device *root_dev = NULL; - -static int ncr885e_open( struct net_device *dev ); -static int ncr885e_close( struct net_device *dev ); -static void ncr885e_rx( struct net_device *dev ); -static void ncr885e_tx( struct net_device *dev ); -static int ncr885e_probe1( unsigned long ioaddr, unsigned char irq ); -static int ncr885e_xmit_start( struct sk_buff *skb, struct net_device *dev ); -static struct net_device_stats *ncr885e_stats( struct net_device *dev ); -static void ncr885e_set_multicast( struct net_device *dev ); -static void ncr885e_config( struct net_device *dev ); -static int ncr885e_set_address( struct net_device *dev, void *addr ); -static void ncr885e_interrupt( int irq, void *dev_id, struct pt_regs *regs ); -static void show_dbdma_cmd( volatile struct dbdma_cmd *cmd ); -#if 0 -static int read_eeprom( unsigned int ioadddr, int location ); -#endif - -#ifdef NCR885E_DEBUG_MII -static void show_mii( unsigned long ioaddr ); -static int read_mii( unsigned long ioaddr, int reg ); -static void write_mii( unsigned long ioaddr, int reg, int data ); -#endif /* NCR885E_DEBUG_MII */ - -#define TX_RESET_FLAGS (TX_CHANNEL_RUN|TX_CHANNEL_PAUSE|TX_CHANNEL_WAKE) -#define RX_RESET_FLAGS (RX_CHANNEL_RUN|RX_CHANNEL_PAUSE|RX_CHANNEL_WAKE) - - -static struct pci_device_id ncr885e_pci_tbl[] __initdata = { - { PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C885_ETHERNET, PCI_ANY_ID, PCI_ANY_ID, }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, ncr885e_pci_tbl); - -#if 0 -static int -debug_ioctl( struct net_device *dev, struct ifreq *req, int cmd ) -{ - unsigned long ioaddr = dev->base_addr; - struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv; - struct ncr885e_private *data; - struct ncr885e_regs *regs; - unsigned long flags; - - union { - struct ncr885e_regs dump; - struct ncr885e_private priv; - } temp; - - switch( cmd ) { - - /* dump the rx ring status */ - case NCR885E_GET_PRIV: - - data = (struct ncr885e_private *) &req->ifr_data; - - if ( verify_area(VERIFY_WRITE, &req->ifr_data, - sizeof( struct ncr885e_private ))) - return -EFAULT; - - memcpy((char *) &temp.priv, sp, sizeof( struct ncr885e_private )); - copy_to_user( data, (char *) &temp.priv, sizeof( struct ncr885e_private)); - break; - - case NCR885E_GET_REGS: - - regs = (struct ncr885e_regs *) &req->ifr_data; - - if ( verify_area( VERIFY_WRITE, &req->ifr_data, - sizeof( struct ncr885e_regs ))) - return -EFAULT; - - spin_lock_irqsave( &sp->lock, flags ); - - temp.dump.tx_status = inl( ioaddr + TX_CHANNEL_STATUS ); - temp.dump.rx_status = inl( ioaddr + RX_CHANNEL_STATUS ); - temp.dump.mac_config = inl( ioaddr + MAC_CONFIG ); - temp.dump.tx_control = inl( ioaddr + TX_CHANNEL_CONTROL ); - temp.dump.rx_control = inl( ioaddr + RX_CHANNEL_CONTROL ); - temp.dump.tx_cmd_ptr = inl( ioaddr + TX_CMD_PTR_LO ); - temp.dump.rx_cmd_ptr = inl( ioaddr + RX_CMD_PTR_LO ); - temp.dump.int_status = inl( ioaddr + INTERRUPT_STATUS_REG ); - - spin_unlock_irqrestore( &sp->lock, flags ); - copy_to_user( regs, (char *) &temp.dump, sizeof( struct ncr885e_regs )); - - break; - - default: - return -EOPNOTSUPP; - } - return 0; -} -#endif - -/* Enable interrupts on the 53C885 */ -static inline void -ncr885e_enable( struct net_device *dev ) - -{ - unsigned long ioaddr = dev->base_addr; - unsigned short reg; - - reg = inw(ioaddr + INTERRUPT_ENABLE); - outw(reg | INTERRUPT_INTE, ioaddr + INTERRUPT_ENABLE); -} - -/* Disable interrupts on the 53c885 */ -static inline void -ncr885e_disable( struct net_device *dev ) - -{ - unsigned long ioaddr = dev->base_addr; - unsigned short reg; - - reg = inw( ioaddr + INTERRUPT_ENABLE ); - outw( reg & ~INTERRUPT_INTE, ioaddr + INTERRUPT_ENABLE ); -} - - -static inline void -ncr885e_reset( struct net_device *dev ) - -{ - unsigned short reg; - unsigned long cntl; - int i; - unsigned long ioaddr = dev->base_addr; - - if (ncr885e_debug > 1) - printk( KERN_INFO "%s: Resetting 53C885...\n", dev->name ); - - /* disable interrupts on the 53C885 */ - ncr885e_disable( dev ); - - /* disable rx in the MAC */ - reg = inw( ioaddr + MAC_CONFIG ); - outw( reg & ~MAC_CONFIG_RXEN, ioaddr + MAC_CONFIG ); - - for( i=0; i < 100; i++ ) { - - if ( !(inw( ioaddr + MAC_CONFIG ) & MAC_CONFIG_RXEN )) - break; - udelay( 10 ); - } - - reg = inw( ioaddr + MAC_CONFIG ); - outw( reg | MAC_CONFIG_SRST, ioaddr + MAC_CONFIG ); - outw( reg, ioaddr + MAC_CONFIG ); - - /* disable both rx and tx DBDMA channels */ - outl( TX_DBDMA_ENABLE << 16, ioaddr + TX_CHANNEL_CONTROL ); - outl( RX_DBDMA_ENABLE << 16, ioaddr + RX_CHANNEL_CONTROL ); - - for( i=0; i < 100; i++ ) { - - if ( !(inw( ioaddr + TX_CHANNEL_STATUS ) & TX_DBDMA_ENABLE ) && - !(inw( ioaddr + RX_CHANNEL_STATUS ) & RX_DBDMA_ENABLE )) - break; - udelay( 10 ); - } - - /* perform a "software reset" */ - cntl = inl( ioaddr + DBDMA_CONTROL ); - outl( cntl | DBDMA_SRST, ioaddr + DBDMA_CONTROL ); - - for( i=0; i < 100; i++ ) { - - if ( !(inl( ioaddr + DBDMA_CONTROL ) & DBDMA_SRST )) - break; - udelay( 10 ); - } - - /* books says that a software reset should be done to the MAC, as - well. This true??? */ - - if (ncr885e_debug > 3) - printk( KERN_INFO "%s: reset complete\n", dev->name ); - -} - - -/* configure the 53C885 chip. - - The DBDMA command descriptors on the 53C885 can be programmed to - branch, interrupt or pause conditionally or always by using the - interrupt, branch and wait select registers. */ - -static void -ncr885e_config( struct net_device *dev ) - -{ - unsigned long ioaddr = dev->base_addr; - - if (ncr885e_debug > 3) - printk( KERN_INFO "%s: Configuring 53C885.\n", dev->name ); - - ncr885e_reset( dev ); - - /* The 53C885 can be programmed to perform conditional DBDMA - branches, interrupts or waits. - - Neither channel makes use of "wait", as it requires that the - DBDMA engine to be restarted. Don't go there. The rx channel - will branch upon the successful reception of a packet ('EOP' in - the xfer_status field). The branch address is to the STOP - DBDMA command descriptor, which shuts down the rx channel until - the interrupt is serviced. */ - - /* cause tx channel to stop after "status received" */ - outl( 0, ioaddr + TX_INT_SELECT ); - outl( (TX_WAIT_STAT_RECV << 16) | TX_WAIT_STAT_RECV, - ioaddr + TX_WAIT_SELECT ); - outl( 0, ioaddr + TX_BRANCH_SELECT ); - - /* cause rx channel to branch to the STOP descriptor on "End-of-Packet" */ -#if 0 - outl( (RX_INT_SELECT_EOP << 16) | RX_INT_SELECT_EOP, - ioaddr + RX_INT_SELECT ); -#else - outl( 0, ioaddr + RX_INT_SELECT ); -#endif -#if 0 - outl( 0, ioaddr + RX_WAIT_SELECT ); -#else - outl( (RX_WAIT_SELECT_EOP << 16) | RX_WAIT_SELECT_EOP, - ioaddr + RX_WAIT_SELECT ); -#endif -#if 1 - outl( 0, ioaddr + RX_BRANCH_SELECT ); -#else - outl( (RX_BRANCH_SELECT_EOP << 16) | RX_BRANCH_SELECT_EOP, - ioaddr + RX_BRANCH_SELECT ); -#endif - - /* configure DBDMA */ - outl( (DBDMA_BE | DBDMA_DPMRLE | DBDMA_TDPCE | - DBDMA_DDPE | DBDMA_TDPE | - (DBDMA_BURST_4 << DBDMA_TX_BST_SHIFT) | - (DBDMA_BURST_4 << DBDMA_RX_BST_SHIFT) | - (DBDMA_TX_ARBITRATION_DEFAULT) | - (DBDMA_RX_ARBITRATION_DEFAULT)), ioaddr + DBDMA_CONTROL ); - - outl( 0, ioaddr + TX_THRESHOLD ); - - /* disable MAC loopback */ - outl( (MAC_CONFIG_ITXA | MAC_CONFIG_RXEN | MAC_CONFIG_RETRYL | - MAC_CONFIG_PADEN | (0x18 << 16)), - ioaddr + MAC_CONFIG ); - - /* configure MAC */ - outl( (MAC_CONFIG_ITXA | MAC_CONFIG_RXEN | MAC_CONFIG_RETRYL | - MAC_CONFIG_PADEN | ( 0x18 << 16)), ioaddr + MAC_CONFIG ); - - outw( (0x1018), ioaddr + NBTOB_INTP_GAP ); - - /* clear and enable interrupts */ - inw( ioaddr + INTERRUPT_CLEAR ); - ncr885e_enable( dev ); - - /* and enable them in the chip */ - outl( (INTERRUPT_INTE|INTERRUPT_TX_MASK|INTERRUPT_RX_MASK)<<16, - ioaddr + INTERRUPT_ENABLE - 2); - - if (ncr885e_debug > 3) - printk( KERN_INFO "%s: 53C885 config complete.\n", dev->name ); - - return; -} - - - -/* - transmit interrupt */ - -static void -ncr885e_tx( struct net_device *dev ) - -{ - struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv; - volatile struct dbdma_cmd *cp, *dp; - unsigned short txbits, xfer; - int i; - - del_timer( &sp->tx_timeout ); - - if (ncr885e_debug > 3) - printk( KERN_INFO "%s: ncr885e_tx: active=%d, dirty=%d, current=%d\n", - dev->name, sp->tx_active, sp->tx_dirty, sp->tx_current ); - - sp->timeout_active = 0; - - i = sp->tx_dirty; - cp = sp->tx_cmds + (i*3); - dp = cp+1; - sp->tx_active--; - - xfer = inw( &dp->xfer_status ); - txbits = inw( &sp->tx_status[i] ); - - if (ncr885e_debug > 4) { - show_dbdma_cmd( cp ); - show_dbdma_cmd( dp ); - } - - /* get xmit result */ - txbits = inw( &sp->tx_status[i] ); - - if (ncr885e_debug > 3) - printk( KERN_INFO "%s: tx xfer=%04x, txbits=%04x\n", dev->name, - xfer, txbits ); - - /* look for any channel status (?) */ - if ( xfer ) { - - dev_kfree_skb_irq( sp->tx_skbufs[i] ); - - if ( txbits & TX_STATUS_TXOK ) { - sp->stats.tx_packets++; - sp->stats.tx_bytes += inw( &cp->req_count ); - } - - /* dropped packets */ - if ( txbits & (TX_STATUS_TDLC|TX_STATUS_TDEC) ) { - sp->stats.tx_dropped++; - } - - /* add the collisions */ - sp->stats.collisions += ( txbits & 0x04 ); - - } - - netif_start_queue(dev); - - return; -} - -/* rx interrupt handling */ -static void -ncr885e_rx( struct net_device *dev ) - -{ - struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv; - volatile struct dbdma_cmd *cp; - struct sk_buff *skb; - int i, nb; - unsigned short status; - unsigned char *data, *stats; - unsigned long rxbits, ioaddr = dev->base_addr; - - i = sp->rx_current; - cp = sp->rx_cmds + (i*2); - - if (ncr885e_debug > 3) - printk( KERN_INFO "%s: ncr885e_rx dirty=%d, current=%d (cp@%p)\n", - dev->name, sp->rx_dirty, sp->rx_current, cp ); - - nb = inw( &cp->req_count ) - inw( &cp->res_count ); - status = inw( &cp->xfer_status ); - - if (ncr885e_debug > 3) - printk( KERN_INFO "%s: (rx %d) bytes=%d, xfer_status=%04x\n", - dev->name, i, nb, status ); - - if ( status ) { - - skb = sp->rx_skbufs[i]; - data = skb->data; - stats = data + nb - 3; - rxbits = (stats[0]|stats[1]<<8|stats[2]<<16); - - if (ncr885e_debug > 3) - printk( KERN_INFO " rx_bits=%06lx\n", rxbits ); - - skb->dev = dev; - skb_put( skb, nb-3 ); - skb->protocol = eth_type_trans( skb, dev ); - netif_rx( skb ); - sp->rx_skbufs[i] = 0; - - if ( rxbits & RX_STATUS_RXOK ) { - sp->stats.rx_packets++; - sp->stats.rx_bytes += nb; - } - - if ( rxbits & RX_STATUS_MCAST ) - sp->stats.multicast++; - - } - - sp->rx_dirty = sp->rx_current; - - if ( ++sp->rx_current >= NR_RX_RING ) - sp->rx_current = 0; - - /* fix up the one we just trashed */ - cp = sp->rx_cmds + (sp->rx_dirty * 2); - - skb = dev_alloc_skb( RX_BUFLEN + 2 ); - if ( skb != 0 ) { - skb_reserve( skb, 2 ); - sp->rx_skbufs[sp->rx_dirty] = skb; - } - - if (ncr885e_debug > 2) - printk( KERN_INFO "%s: ncr885e_rx: using ring index %d, filling cp @ %p\n", - dev->name, sp->rx_current, cp ); - - outw( RX_BUFLEN, &cp->req_count ); - outw( 0, &cp->res_count ); - data = skb->data; - outl( virt_to_bus( data ), &cp->phy_addr ); - outw( 0, &cp->xfer_status ); - - cp = sp->rx_cmds + (sp->rx_current * 2); - - /* restart rx DMA */ - outl( virt_to_bus( cp ), ioaddr + RX_CMD_PTR_LO ); - outl( (RX_DBDMA_ENABLE << 16)|RX_CHANNEL_RUN, - ioaddr + RX_CHANNEL_CONTROL ); - - return; -} - -static void -ncr885e_misc_ints( struct net_device *dev, unsigned short status ) - -{ - struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv; - struct dbdma_cmd *cp; - unsigned long ioaddr = dev->base_addr; - - if (ncr885e_debug > 1) - printk( KERN_INFO "miscellaneous interrupt handled; status=%02x\n", - status ); - - /* various transmit errors */ - if ( status & - (INTERRUPT_PPET | INTERRUPT_PBFT | INTERRUPT_IIDT) ) { - - /* illegal instruction in tx dma */ - if ( status & INTERRUPT_IIDT ) { - - cp = (struct dbdma_cmd *) bus_to_virt( inl( ioaddr + TX_CMD_PTR_LO )); - printk( KERN_INFO "%s: tx illegal insn:\n", dev->name ); - printk( KERN_INFO " tx DBDMA - cmd = %p, status = %04x\n", - cp, inw( ioaddr + TX_CHANNEL_STATUS )); - printk( KERN_INFO " command = %04x, phy_addr=%08x, req_count=%04x\n", - inw( &cp->command ), inw( &cp->phy_addr ), inw( &cp->req_count )); - } - - if ( status & INTERRUPT_PPET ) - printk( KERN_INFO "%s: tx PCI parity error\n", dev->name ); - - if ( status & INTERRUPT_PBFT ) - printk( KERN_INFO "%s: tx PCI bus fault\n", dev->name ); - } - - /* look for rx errors */ - if ( status & - (INTERRUPT_PPER | INTERRUPT_PBFR | INTERRUPT_IIDR)) { - - /* illegal instruction in rx dma */ - if ( status & INTERRUPT_IIDR ) { -#if 0 - cmd = inl( ioaddr + RX_CMD_PTR_LO ); -#endif - printk( KERN_ERR "%s: rx illegal DMA instruction:\n", dev->name ); - printk( KERN_ERR " channel status=%04x,\n", - inl( ioaddr + RX_CHANNEL_STATUS )); -#if 0 - show_dbdma_cmd( bus_to_virt( inl( ioaddr + RX_CMD_PTR_LO ))); - printk( KERN_ERR " instr (%08x) %08x %08x %08x\n", - (int) cmd, cmd[0], cmd[1], cmd[2] ); -#endif - } - - /* PCI parity error */ - if ( status & INTERRUPT_PPER ) - printk( KERN_INFO "%s: rx PCI parity error\n", dev->name ); - - if ( status & INTERRUPT_PBFR ) - printk( KERN_INFO "%s: rx PCI bus fault\n", dev->name ); - - sp->stats.rx_errors++; - } - - if ( status & INTERRUPT_WI ) { - printk( KERN_INFO "%s: link pulse\n", dev->name ); - } - - /* bump any counters */ - - - return; -} - -static void -ncr885e_interrupt( int irq, void *dev_id, struct pt_regs *regs ) - -{ - struct net_device *dev = (struct net_device *) dev_id; - struct ncr885e_private *sp; - unsigned short status; - int ioaddr; - - if ( dev == NULL ) { - printk( KERN_ERR "symba: Interrupt IRQ %d for unknown device\n", irq ); - return; - } - - ioaddr = dev->base_addr; - sp = (struct ncr885e_private *) dev->priv; - spin_lock( &sp->lock ); - - status = inw( ioaddr + INTERRUPT_CLEAR ); - - if (ncr885e_debug > 2) - printk( KERN_INFO "%s: 53C885 interrupt 0x%02x\n", dev->name, status ); - - /* handle non-tx and rx interrupts first */ - if ( status & ~(INTERRUPT_DIT|INTERRUPT_DIR)) - ncr885e_misc_ints( dev, status ); - - /* look for tx interrupt: more to transmit, DBDMA stopped, or tx done */ - if ( ( status & INTERRUPT_DIT ) ) { - - if (ncr885e_debug > 2) - printk( KERN_INFO "%s: tx int; int=%02x, chan stat=%02x\n", - dev->name, status, inw( ioaddr + TX_CHANNEL_STATUS )); - - /* turn off timer */ - del_timer( &sp->tx_timeout ); - sp->timeout_active = 0; - - /* stop DMA */ - outl( TX_DBDMA_ENABLE << 16, ioaddr + TX_CHANNEL_CONTROL ); - - ncr885e_tx( dev ); - } - - if ( status & INTERRUPT_DIR ) { - - if ( ncr885e_debug > 2 ) - printk( KERN_INFO "%s: rx interrupt; int=%02x, rx channel stat=%02x\n", - dev->name, status, inw( ioaddr + RX_CHANNEL_STATUS )); - - /* stop DMA */ - outl( RX_DBDMA_ENABLE << 16, ioaddr + RX_CHANNEL_CONTROL ); - - /* and handle the interrupt */ - ncr885e_rx( dev ); - } - - spin_unlock( &sp->lock ); - - return; -} - - -/* doesn't set the address permanently, however... */ -static int -ncr885e_set_address( struct net_device *dev, void *addr ) - -{ - struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv; - struct sockaddr *saddr = addr; - unsigned long flags; - unsigned short reg[3]; - unsigned char *ioaddr, *p; - int i; - - memcpy( dev->dev_addr, saddr->sa_data, dev->addr_len ); - - p = (unsigned char *) dev->dev_addr; - printk( KERN_INFO "%s: setting new MAC address - ", dev->name ); -#if 0 - for( p = (unsigned char *) dev->dev_addr, i=0; i < 6; i++, p++ ) - printk("%c%2.2x", i ? ':' : ' ', *p ); -#endif - - - p = (unsigned char *) ® - for( i=0; i < 6; i++ ) - p[i] = dev->dev_addr[i]; - -#if 0 - printk("%s: Setting new mac address - ", dev->name ); - for( i=0; i < 6; i++ ) { - printk("%02x", i ? ':' : ' ', p[i] ); - } - - printk("\n"); -#endif - - /* stop rx for the change */ - outl( RX_DBDMA_ENABLE << 16, ioaddr + RX_CHANNEL_CONTROL ); - - spin_lock_irqsave( &sp->lock, flags ); - - ioaddr = (unsigned char *) dev->base_addr; - - for( i = 0; i < 3; i++ ) { - reg[i] = ((reg[i] & 0xff) << 8) | ((reg[i] >> 8) & 0xff); - printk("%04x ", reg[i] ); - outw( reg[i], ioaddr + STATION_ADDRESS_0 + (i*2)); - } - printk("\n"); - - spin_unlock_irqrestore( &sp->lock, flags ); - - /* restart rx */ - outl((RX_DBDMA_ENABLE << 16)|RX_CHANNEL_RUN, - ioaddr + RX_CHANNEL_CONTROL ); - - return 0; -} - -static void -ncr885e_tx_timeout( unsigned long data ) - -{ - struct net_device *dev = (struct net_device *) data; - struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv; - unsigned long flags, ioaddr; - int i; - - save_flags( flags ); - cli(); - - ioaddr = dev->base_addr; - sp->timeout_active = 0; - i = sp->tx_dirty; - - /* if we weren't active, bail... */ - if ( sp->tx_active == 0 ) { - printk( KERN_INFO "%s: ncr885e_timeout...tx not active!\n", dev->name ); - goto out; - } - - printk( KERN_ERR "%s: 53C885 timed out. Resetting...\n", dev->name ); - - /* disable rx and tx DMA */ - outl( (TX_DBDMA_ENABLE << 16), ioaddr + TX_CHANNEL_CONTROL ); - outl( (RX_DBDMA_ENABLE << 16), ioaddr + RX_CHANNEL_CONTROL ); - - /* reset the chip */ - ncr885e_config( dev ); - ncr885e_enable( dev ); - - /* clear the wedged skb in the tx ring */ - sp->tx_active = 0; - ++sp->stats.tx_errors; - - if ( sp->tx_skbufs[i] ) { - dev_kfree_skb( sp->tx_skbufs[i] ); - sp->tx_skbufs[i] = 0; - } - - /* start anew from the beginning of the ring buffer (why not?) */ - sp->tx_current = 0; - netif_wake_queue(dev); - - /* restart rx dma */ - outl( (RX_DBDMA_ENABLE << 16) | RX_CHANNEL_RUN, - ioaddr + RX_CHANNEL_CONTROL ); - out: - - restore_flags( flags ); -} - -static inline void -ncr885e_set_timeout( struct net_device *dev ) - -{ - struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv; - unsigned long flags; - - save_flags(flags); - cli(); - - if ( sp->timeout_active ) - del_timer( &sp->tx_timeout ); - - sp->tx_timeout.expires = jiffies + TX_TIMEOUT; - sp->tx_timeout.function = ncr885e_tx_timeout; - sp->tx_timeout.data = (unsigned long) dev; - add_timer( &sp->tx_timeout ); - sp->timeout_active = 1; - restore_flags( flags ); -} - - -/* - * The goal is to set up DBDMA such that the rx ring contains only - * one DMA descriptor per ring element and the tx ring has two (using - * the cool features of branch- and wait-select. However, I'm not sure - * if it's possible. For now, we plod through it with 3 descriptors - * for tx, and two for rx. - */ - -static int -ncr885e_open( struct net_device *dev ) - -{ - struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv; - unsigned long ioaddr = dev->base_addr; - struct sk_buff *skb; - int i, size; - char *data; - struct dbdma_cmd *cp; - unsigned long flags; - - /* allocate enough space for the tx and rx rings and a STOP descriptor */ - size = (sizeof( struct dbdma_cmd ) * - ((NR_TX_RING * 3) + (NR_RX_RING * 2) + 1)); - - cp = kmalloc( size, GFP_KERNEL ); - - if ( cp == 0 ) { - printk( KERN_ERR "Insufficient memory (%d bytes) for DBDMA\n", size ); - return -ENOMEM; - } - - spin_lock_init( &sp->lock ); - spin_lock_irqsave( &sp->lock, flags ); - - memset((char *) cp, 0, size ); - sp->head = cp; - - sp->stop_cmd = cp; - outl( DBDMA_STOP, &cp->command ); - - sp->rx_cmds = ++cp; - - for( i = 0; i < NR_RX_RING; i++ ) { - - cp = sp->rx_cmds + (i*2); - skb = dev_alloc_skb( RX_BUFLEN + 2 ); - - /* if there is insufficient memory, make this last ring use a - static buffer and leave the loop with that skb as final one */ - if ( skb == 0 ) { - printk( KERN_ERR "%s: insufficient memory for rx ring buffer\n", - dev->name ); - break; - } - - skb_reserve( skb, 2 ); - sp->rx_skbufs[i] = skb; - data = skb->data; - - /* The DMA commands here are done such that an EOP is the only - way that we should get an interrupt. This means that we could - fill more than one skbuff before getting the interrupt at EOP. */ - - /* Handle rx DMA such that it always interrupts.... */ - outw( (INPUT_MORE|INTR_ALWAYS), &cp->command ); - outw( RX_BUFLEN, &cp->req_count ); - outw( 0, &cp->res_count ); - outl( virt_to_bus( data ), &cp->phy_addr ); - outl( virt_to_bus( sp->stop_cmd ), &cp->cmd_dep ); - outw( 0, &cp->xfer_status ); -#if 0 - printk( KERN_INFO "rx at %p\n", cp ); - show_dbdma_cmd( cp ); -#endif - ++cp; - - outw( DBDMA_STOP, &cp->command ); - - } - - /* initialize to all rx buffers are available, fill limit is the end */ - sp->rx_dirty = 0; - sp->rx_current = 0; - - /* fill the tx ring */ - sp->tx_cmds = cp+1; - - for( i = 0; i < NR_TX_RING; i++ ) { - - /* minimal setup for tx command */ - cp = sp->tx_cmds + (i*3); - outw( OUTPUT_LAST, &cp->command ); - if (ncr885e_debug > 3) { - printk( KERN_INFO "tx OUTPUT_LAST at %p\n", cp ); - show_dbdma_cmd( cp ); - } - - /* full setup for the status cmd */ - cp++; - outw( INPUT_LAST|INTR_ALWAYS|WAIT_IFCLR, &cp->command ); - outl( virt_to_bus( &sp->tx_status[i] ), &cp->phy_addr ); - outw( 2, &cp->req_count ); - if ( ncr885e_debug > 3) { - printk( KERN_INFO "tx INPUT_LAST cmd at %p\n", cp ); - show_dbdma_cmd( cp ); - } - - ++cp; - outw( DBDMA_STOP, &cp->command ); - - } -#if 0 - /* chain the last tx DMA command to the STOP cmd */ - outw((INPUT_LAST|INTR_ALWAYS|BR_ALWAYS), &cp->command ); - outl( virt_to_bus( sp->stop_cmd ), &cp->cmd_dep ); -#endif - sp->tx_active = 0; - sp->tx_current = 0; - sp->tx_dirty = 0; - - spin_unlock_irqrestore( &sp->lock, flags ); - - /* the order seems important here for some reason. If the MPIC isn't - enabled before the ethernet chip is enabled, shrapnel from the - bootloader causes us to receive interrupts even though we've not - yet enabled the tx channel. Go figure. It'd be better to configure - the chip in the probe1() routine, but then we don't see interrupts - at all. Everything looks all right on the logic analyzer, but... */ - - ncr885e_config( dev ); - - /* enable ethernet interrupts */ - if ( request_irq( dev->irq, &ncr885e_interrupt, SA_SHIRQ, chipname, dev )) { - printk( KERN_ERR "%s: can't get irq %d\n", dev->name, dev->irq ); - return -EAGAIN; - } - - (void) inw( ioaddr + INTERRUPT_CLEAR ); - - ncr885e_enable( dev ); - - /* start rx DBDMA */ - outl( virt_to_bus( sp->rx_cmds ), ioaddr + RX_CMD_PTR_LO ); - outl( (RX_DBDMA_ENABLE << 16)|RX_CHANNEL_RUN, - ioaddr + RX_CHANNEL_CONTROL ); - - netif_start_queue(dev); - - return 0; -} - -static int -ncr885e_xmit_start( struct sk_buff *skb, struct net_device *dev ) - -{ - struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv; - volatile struct dbdma_cmd *cp, *dp; - unsigned long flags, ioaddr = dev->base_addr; - int len, next, fill, entry; - - if ( ncr885e_debug > 3) - printk( KERN_INFO "%s: xmit_start len=%d, dirty=%d, current=%d, active=%d\n", - dev->name, skb->len, sp->tx_dirty, sp->tx_current, sp->tx_active ); - - spin_lock_irqsave( &sp->lock, flags ); - - /* find the free slot in the ring buffer */ - fill = sp->tx_current; - next = fill + 1; - - if ( next >= NR_TX_RING ) - next = 0; -#if 0 - /* mark ourselves as busy, even if we have too many packets waiting */ - netif_stop_queue(dev); -#endif - - /* see if it's necessary to defer this packet */ - if ( sp->tx_active >= MAX_TX_ACTIVE ) { - spin_unlock_irqrestore( &sp->lock, flags ); - return -1; - } - - sp->tx_active++; /* bump "active tx" count */ - sp->tx_current = next; /* and show that we've used this buffer */ - sp->tx_dirty = fill; /* and mark this one to get picked up */ - - len = skb->len; - - if ( len > ETH_FRAME_LEN ) { - printk( KERN_DEBUG "%s: xmit frame too long (%d)\n", dev->name, len ); - len = ETH_FRAME_LEN; - } - - /* get index into the tx DBDMA chain */ - entry = fill * 3; - sp->tx_skbufs[fill] = skb; - cp = sp->tx_cmds + entry; - dp = cp + 1; - - /* update the rest of the OUTPUT_MORE descriptor */ - outw( len, &cp->req_count ); - outl( virt_to_bus( skb->data ), &cp->phy_addr ); - outw( 0, &cp->xfer_status ); - outw( 0, &cp->res_count ); - - /* and finish off the INPUT_MORE */ - outw( 0, &dp->xfer_status ); - outw( 0, &dp->res_count ); - sp->tx_status[fill] = 0; - outl( virt_to_bus( &sp->tx_status[fill] ), &dp->phy_addr ); - - if ( ncr885e_debug > 2 ) - printk(KERN_INFO "%s: xmit_start: active %d, tx_current %d, tx_dirty %d\n", - dev->name, sp->tx_active, sp->tx_current, sp->tx_dirty ); - - if ( ncr885e_debug > 4 ) { - show_dbdma_cmd( cp ); - show_dbdma_cmd( dp ); - } - - - /* restart the tx DMA engine */ - outl( virt_to_bus( cp ), ioaddr + TX_CMD_PTR_LO ); - outl( (TX_DBDMA_ENABLE << 16)|TX_CHANNEL_RUN, - ioaddr + TX_CHANNEL_CONTROL ); - - ncr885e_set_timeout( dev ); - - spin_unlock_irqrestore( &sp->lock, flags ); - dev->trans_start = jiffies; - - return 0; -} - -static int -ncr885e_close(struct net_device *dev) - -{ - int i; - struct ncr885e_private *np = (struct ncr885e_private *) dev->priv; - unsigned long ioaddr = dev->base_addr; - - netif_stop_queue(dev); - - spin_lock( &np->lock ); - - printk(KERN_INFO "%s: NCR885E Ethernet closing...\n", dev->name ); - - if (ncr885e_debug > 1) - printk(KERN_DEBUG "%s: Shutting down Ethernet chip\n", dev->name); - - ncr885e_disable(dev); - - del_timer(&np->tx_timeout); - - /* flip off rx and tx */ - outl( (RX_DBDMA_ENABLE << 16), ioaddr + RX_CHANNEL_CONTROL ); - outl( (TX_DBDMA_ENABLE << 16), ioaddr + TX_CHANNEL_CONTROL ); - - /* free up the IRQ */ - free_irq( dev->irq, dev ); - - for( i = 0; i < NR_RX_RING; i++ ) { - if (np->rx_skbufs[i]) - dev_kfree_skb( np->rx_skbufs[i] ); - np->rx_skbufs[i] = 0; - } -#if 0 - for (i = 0; i < NR_TX_RING; i++) { - if (np->tx_skbufs[i]) - dev_kfree_skb(np->tx_skbufs[i]); - np->tx_skbufs[i] = 0; - } -#endif - spin_unlock( &np->lock ); - - kfree( np->head ); - - return 0; -} - - -/* - * multicast promiscuous mode isn't used here. Allow code in the - * IP stack to determine which multicast packets are good or bad.... - * (this avoids having to use the hash table registers) - */ -static void -ncr885e_set_multicast( struct net_device *dev ) - -{ - int ioaddr = dev->base_addr; - - if ( ncr885e_debug > 3 ) - printk("%s: set_multicast: dev->flags = %x, AF=%04x\n", - dev->name, dev->flags, inw( ioaddr + ADDRESS_FILTER )); - - if ( dev->flags & IFF_PROMISC ) { - printk( KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name ); - outw( ADDRESS_RPPRO, ioaddr + ADDRESS_FILTER ); - } - - /* accept all multicast packets without checking the mc_list. */ - else if ( dev->flags & IFF_ALLMULTI ) { - printk( KERN_INFO "%s: Enabling all multicast packets.\n", - dev->name ); - outw( ADDRESS_RPPRM, ioaddr + ADDRESS_FILTER ); - } - - /* enable broadcast rx */ - else { - outw( ADDRESS_RPABC, ioaddr + ADDRESS_FILTER ); - } -} - -static struct net_device_stats * -ncr885e_stats( struct net_device *dev ) - -{ - struct ncr885e_private *np = (struct ncr885e_private *) dev->priv; - - return &np->stats; -} - -/* By this function, we're certain that we have a 885 Ethernet controller - * so we finish setting it up and wrap up all the required Linux ethernet - * configuration. - */ - -static int __init ncr885e_probe1(unsigned long ioaddr, unsigned char irq ) - -{ - struct net_device *dev; - struct ncr885e_private *sp; - unsigned short station_addr[3], val; - unsigned char *p; - int i; - - dev = init_etherdev( NULL, sizeof( struct ncr885e_private ) ); - if (!dev) - return -ENOMEM; - SET_MODULE_OWNER(dev); - - sp = dev->priv; - - /* snag the station address and display it */ - for( i = 0; i < 3; i++ ) { - val = inw( ioaddr + STATION_ADDRESS_0 + (i*2)); - station_addr[i] = ((val >> 8) & 0xff) | ((val << 8) & 0xff00); - } - - printk( KERN_INFO "%s: %s at %08lx,", dev->name, chipname, ioaddr ); - - p = (unsigned char *) &station_addr; - - for( i=0; i < 6; i++ ) { - dev->dev_addr[i] = *p; - printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i] ); - p++; - } - - printk(", IRQ %d.\n", irq ); - - /* set up a timer */ - init_timer( &sp->tx_timeout ); - sp->timeout_active = 0; - - dev->base_addr = ioaddr; - dev->irq = irq; - - ether_setup( dev ); - - /* everything else */ - dev->open = ncr885e_open; - dev->stop = ncr885e_close; - dev->get_stats = ncr885e_stats; - dev->hard_start_xmit = ncr885e_xmit_start; - dev->set_multicast_list = ncr885e_set_multicast; - dev->set_mac_address = ncr885e_set_address; - - root_dev = dev; - - return 0; -} - -/* Since the NCR 53C885 is a multi-function chip, I'm not worrying about - * trying to get the the device(s) in slot order. For our (Synergy's) - * purpose, there's just a single 53C885 on the board and we don't - * worry about the rest. - */ - -static int __init ncr885e_probe(void) -{ - struct pci_dev *pdev = NULL; - unsigned int ioaddr, ret; - unsigned char irq; - - /* use 'if' not 'while' where because driver only supports one device */ - if (( pdev = pci_find_device( PCI_VENDOR_ID_NCR, - PCI_DEVICE_ID_NCR_53C885_ETHERNET, - pdev )) != NULL ) { - - if ( !print_version ) { - print_version++; - printk( KERN_INFO "%s", version ); - } - - if (pci_enable_device(pdev)) - return -ENODEV; - - /* Use I/O space */ - ioaddr = pci_resource_start (pdev, 0); - irq = pdev->irq; - - if ( !request_region( ioaddr, NCR885E_TOTAL_SIZE, "ncr885e" )) - return -ENOMEM; - - /* finish off the probe */ - ret = ncr885e_probe1(ioaddr, irq); - if (ret) - release_region(ioaddr, NCR885E_TOTAL_SIZE); - else - pci_set_master(pdev); - } - - return ret; -} - -/* debugging to peek at dma descriptors */ -static void -show_dbdma_cmd( volatile struct dbdma_cmd *cmd ) - -{ - printk( KERN_INFO " cmd %04x, physaddr %08x, req_count %04x\n", - inw( &cmd->command ), inl( &cmd->phy_addr ), inw( &cmd->req_count )); - printk( KERN_INFO " res_count %04x, xfer_status %04x, branch %08x\n", - inw( &cmd->res_count ), inw( &cmd->xfer_status ),inl( &cmd->cmd_dep )); -} - -#if 0 -static int -read_eeprom( unsigned int ioaddr, int location ) - -{ - int loop; - unsigned char val; - - outb( (location & 0xff), ioaddr + EE_WORD_ADDR ); - - /* take spillover from location in control reg */ - outb(EE_CONTROL_RND_READB | (location & (0x7<<8)), ioaddr + EE_CONTROL); - - loop = 1000; - while( (inb( ioaddr + EE_STATUS) & EE_SEB) && - (loop > 0) ) { - udelay( 10 ); - loop--; - } - - if ( inb( ioaddr + EE_STATUS ) & EE_SEE ) { - printk("%s: Serial EEPROM read error\n", chipname); - val = 0xff; - } - - else - val = inb( ioaddr + EE_READ_DATA ); - - return (int) val; -} -#endif - -#ifdef NCR885E_DEBUG_MII -static void -show_mii( unsigned long ioaddr ) - -{ - int phyctrl, phystat, phyadvert, phypartner, phyexpan; - - phyctrl = read_mii( ioaddr, MII_AUTO_NEGOTIATION_CONTROL ); - phystat = read_mii( ioaddr, MII_AUTO_NEGOTIATION_STATUS ); - phyadvert = read_mii( ioaddr, MII_AUTO_NEGOTIATION_ADVERTISEMENT ); - phypartner = read_mii( ioaddr, MII_AUTO_NEGOTIATION_LINK_PARTNER ); - phyexpan = read_mii( ioaddr, MII_AUTO_NEGOTIATION_EXPANSION ); - - printk( KERN_INFO "PHY: advert=%d %s, partner=%s %s, link=%d, %s%s\n", - (phyadvert & MANATECH_100BASETX_FULL_DUPLEX ? 100 : 10), - (phyctrl & MANC_AUTO_NEGOTIATION_ENABLE ? "auto" : "fixed"), - (phypartner & MANLP_ACKNOWLEDGE ? - (phypartner & MANATECH_100BASETX_FULL_DUPLEX ? "100" : "10") : - "?"), - (phyexpan & MANE_LINK_PARTNER_AUTO_ABLE ? "auto" : "fixed"), - (phyctrl & MANC_PHY_SPEED_100 ? 100 : 10), - (phystat & MANS_LINK_STATUS ? "up" : "down"), - (phyexpan & MANE_PARALLEL_DETECTION_FAULT ? " PD-fault" : "" )); - return; -} - - -static int -read_mii( unsigned long ioaddr, int reg ) - -{ - int timeout; - - - timeout = 100000; - - while( inw( ioaddr + MII_INDICATOR ) & MII_BUSY ) { - - if ( timeout-- < 0 ) { - printk( KERN_INFO "Timed out waiting for MII\n" ); - return -1; - } - } - - outw( (1<<8) + reg, ioaddr + MII_ADDRESS ); - outw( MIIM_RSTAT, ioaddr + MIIM_COMMAND ); - - timeout = 100000; - while( inw( ioaddr + MII_INDICATOR ) & MII_BUSY ) { - if ( timeout-- < 0 ) { - printk( KERN_INFO "Timed out waiting for MII\n" ); - return -1; - } - } - - return( inw( ioaddr + MII_READ_DATA )); -} - -static void -write_mii( unsigned long ioaddr, int reg, int data ) - -{ - int timeout=100000; - - printk( KERN_INFO "MII indicator: %02x\n", inw( ioaddr + MII_INDICATOR )); - - while( inw( ioaddr + MII_INDICATOR ) & MII_BUSY ) { - if ( timeout-- <= 0 ) { - printk( KERN_INFO "Timeout waiting to write to MII\n" ); - return; - } - udelay( 10 ); - } - - outw( (1<<8) + reg, ioaddr + MII_ADDRESS ); - outw( data, ioaddr + MII_WRITE_DATA ); - - return; -} - -#endif /* NCR885E_DEBUG_MII */ - -static void __exit ncr885e_cleanup(void) -{ - if ( root_dev ) { - unregister_netdev( root_dev ); - release_region( root_dev->base_addr, NCR885E_TOTAL_SIZE ); - kfree( root_dev ); - root_dev = NULL; - } -} - -module_init(ncr885e_probe); -module_exit(ncr885e_cleanup); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/ncr885e.h linux.ac/drivers/net/ncr885e.h --- linux.vanilla/drivers/net/ncr885e.h Sun Dec 31 02:16:13 2000 +++ linux.ac/drivers/net/ncr885e.h Thu Jan 1 01:00:00 1970 @@ -1,367 +0,0 @@ -#ifndef _NET_H_SYMBA -#define _NET_H_SYMBA - -/* transmit status bit definitions */ -#define TX_STATUS_TXOK (1<<13) /* success */ -#define TX_STATUS_TDLC (1<<12) /* dropped for late colls */ -#define TX_STATUS_TCXSDFR (1<<11) /* excessive deferral */ -#define TX_STATUS_TDEC (1<<10) /* excessive collisions */ -#define TX_STATUS_TAUR (1<<9) /* abort on underrun/"jumbo" */ -#define TX_STATUS_PDFRD (1<<8) /* packet deferred */ -#define TX_STATUS_BCAST (1<<7) /* broadcast ok */ -#define TX_STATUS_MCAST (1<<6) /* multicast ok */ -#define TX_STATUS_CRCERR (1<<5) /* CRC error */ -#define TX_STATUS_LC (1<<4) /* late collision */ -#define TX_STATUS_CCNT_MASK 0xf /* collision count */ - -#define T_TXOK (1<<13) -#define T_TDLC (1<<12) -#define T_TCXSDFR (1<<11) -#define T_TDEC (1<<10) -#define T_TAUR (1<<9) -#define T_PDFRD (1<<8) -#define T_BCAST (1<<7) -#define T_MCAST (1<<6) -#define T_LC (1<<4) -#define T_CCNT_MASK 0xf - -/* receive status bit definitions */ -#define RX_STATUS_RXOVRN (1<<23) /* overrun */ -#define RX_STATUS_CEPS (1<<22) /* carrier event already seen */ -#define RX_STATUS_RXOK (1<<21) /* success */ -#define RX_STATUS_BCAST (1<<20) /* broadcast ok */ -#define RX_STATUS_MCAST (1<<19) /* multicast ok */ -#define RX_STATUS_CRCERR (1<<18) /* CRC error */ -#define RX_STATUS_DR (1<<17) /* dribble nibble */ -#define RX_STATUS_RCV (1<<16) /* rx code violation */ -#define RX_STATUS_PTL (1<<15) /* pkt > 1518 bytes */ -#define RX_STATUS_PTS (1<<14) /* pkt < 64 bytes */ -#define RX_STATUS_LEN_MASK 0x1fff /* length mask */ - -#define EEPROM_LENGTH 100 - - -/* Serial EEPROM interface */ -#define EE_STATUS 0xf0 -#define EE_CONTROL 0xf1 -#define EE_WORD_ADDR 0xf2 -#define EE_READ_DATA 0xf3 -#define EE_WRITE_DATA 0xf4 -#define EE_FEATURE_ENB 0xf5 - -/* Use on EE_STATUS */ -#define EE_SEB (1<<8) -#define EE_SEE 1 - -/* Serial EEPROM commands */ -#define EE_CONTROL_SEQ_READB (1<<4) -#define EE_CONTROL_RND_WRITEB (1<<5) -#define EE_CONTROL_RND_READB ((1<<4)|(1<<5)) - -/* Enable writing to serial EEPROM */ -#define EE_WRITE_ENB 1 - -/* The 885 configuration register */ -#define MAC_CONFIG 0xa0 -#define MAC_CONFIG_SRST 1<<15 -#define MAC_CONFIG_ITXA 1<<13 -#define MAC_CONFIG_RXEN 1<<12 -#define MAC_CONFIG_INTLB 1<<10 -#define MAC_CONFIG_MODE_MASK (1<<8|1<<9) -#define MAC_CONFIG_MODE_TP 1<<8 -#define MAC_CONFIG_HUGEN 1<<5 -#define MAC_CONFIG_RETRYL 1<<4 -#define MAC_CONFIG_CRCEN 1<<3 -#define MAC_CONFIG_PADEN 1<<2 -#define MAC_CONFIG_FULLD 1<<1 -#define MAC_CONFIG_NOCFR 1<<0 - - - - - -#define TX_WAIT_SELECT 0x18 -#define RX_CHANNEL_CONTROL 0x40 - -/* Tx channel status */ -#define TX_DBDMA_REG 0x00 -#define TX_CHANNEL_CONTROL 0x00 -#define TX_CHANNEL_STATUS 0x04 -#define TX_STATUS_RUN 1<<15 -#define TX_STATUS_PAUSE 1<<14 -#define TX_STATUS_WAKE 1<<12 -#define TX_STATUS_DEAD 1<<11 -#define TX_STATUS_ACTIVE 1<<10 -#define TX_STATUS_BT 1<<8 -#define TX_STATUS_TXABORT 1<<7 -#define TX_STATUS_TXSR 1<<6 - -#define TX_CHANNEL_RUN TX_STATUS_RUN -#define TX_CHANNEL_PAUSE TX_STATUS_PAUSE -#define TX_CHANNEL_WAKE TX_STATUS_WAKE -#define TX_CHANNEL_DEAD TX_STATUS_DEAD -#define TX_CHANNEL_ACTIVE TX_STATUS_ACTIVE -#define TX_CHANNEL_BT TX_STATUS_BT -#define TX_CHANNEL_TXABORT TX_STATUS_TXABORT -#define TX_CHANNEL_TXSR TX_STATUS_TXSR - -#define TX_DBDMA_ENABLE (TX_CHANNEL_WAKE | TX_CHANNEL_PAUSE | \ - TX_CHANNEL_RUN ) - -/* Transmit command ptr lo register */ -#define TX_CMD_PTR_LO 0x0c - -/* Transmit interrupt select register */ -#define TX_INT_SELECT 0x10 - -/* Transmit branch select register */ -#define TX_BRANCH_SELECT 0x14 - -/* Transmit wait select register */ -#define TX_WAIT_SELECT 0x18 -#define TX_WAIT_STAT_RECV 0x40 - -/* Rx channel status */ -#define RX_DBDMA_REG 0x40 -#define RX_CHANNEL_CONTROL 0x40 -#define RX_CHANNEL_STATUS 0x44 -#define RX_STATUS_RUN 1<<15 -#define RX_STATUS_PAUSE 1<<14 -#define RX_STATUS_WAKE 1<<12 -#define RX_STATUS_DEAD 1<<11 -#define RX_STATUS_ACTIVE 1<<10 -#define RX_STATUS_BT 1<<8 -#define RX_STATUS_EOP 1<<6 - -#define RX_CHANNEL_RUN RX_STATUS_RUN -#define RX_CHANNEL_PAUSE RX_STATUS_PAUSE -#define RX_CHANNEL_WAKE RX_STATUS_WAKE -#define RX_CHANNEL_DEAD RX_STATUS_DEAD -#define RX_CHANNEL_ACTIVE RX_STATUS_ACTIVE -#define RX_CHANNEL_BT RX_STATUS_BT -#define RX_CHANNEL_EOP RX_STATUS_EOP - -#define RX_DBDMA_ENABLE (RX_CHANNEL_WAKE | RX_CHANNEL_PAUSE | \ - RX_CHANNEL_RUN) - -/* Receive command ptr lo */ -#define RX_CMD_PTR_LO 0x4c - -/* Receive interrupt select register */ -#define RX_INT_SELECT 0x50 -#define RX_INT_SELECT_EOP 0x40 - -/* Receive branch select */ -#define RX_BRANCH_SELECT 0x54 -#define RX_BRANCH_SELECT_EOP 0x40 - -/* Receive wait select */ -#define RX_WAIT_SELECT 0x58 -#define RX_WAIT_SELECT_EOP 0x40 - -/* Event status register */ -#define EVENT_STATUS 0x80 -#define EVENT_TXSR 1<<2 -#define EVENT_EOP 1<<1 -#define EVENT_TXABORT 1<<0 - -/* Interrupt enable register */ -#define INTERRUPT_ENABLE 0x82 - -/* Interrupt clear register */ -#define INTERRUPT_CLEAR 0x84 - -/* Interrupt status register */ -#define INTERRUPT_STATUS_REG 0x86 - -/* 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 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 */ -#define INTERRUPT_DIT 1<<4 /* DBDMA Tx interrupt */ -#define INTERRUPT_PPER 1<<3 /* PCI Rx parity error */ -#define INTERRUPT_PBFR 1<<2 /* PCI Rx bus fault */ -#define INTERRUPT_IIDR 1<<1 /* illegal instruction Rx */ -#define INTERRUPT_DIR 1<<0 /* DBDMA Rx interrupt */ - -#define INTERRUPT_TX_MASK (INTERRUPT_PBFT|INTERRUPT_IIDT| \ - INTERRUPT_PPET|INTERRUPT_DIT) -#define INTERRUPT_RX_MASK (INTERRUPT_PBFR|INTERRUPT_IIDR| \ - INTERRUPT_PPER|INTERRUPT_DIR) - -/* chip revision register */ -#define CHIP_REVISION_REG 0x8c -#define CHIP_PCIREV_MASK (0xf<<16) -#define CHIP_PCIDEV_MASK 0xff - -/* Tx threshold register */ -#define TX_THRESHOLD 0x94 - -/* General purpose register */ -#define GEN_PURPOSE_REG 0x9e - -/* General purpose pin control reg */ -#define GEN_PIN_CONTROL_REG 0x9f - -/* DBDMA control register */ -#define DBDMA_CONTROL 0x90 -#define DBDMA_SRST 1<<31 -#define DBDMA_TDPCE 1<<23 -#define DBDMA_BE 1<<22 -#define DBDMA_TAP_MASK (1<<19|1<<20|1<<21) -#define DBDMA_RAP_MASK (1<<16|1<<17|1<<18) -#define DBDMA_DPMRLE 1<<15 -#define DBDMA_WIE 1<<14 -#define DBDMA_MP 1<<13 -#define DBDMA_SME 1<<12 -#define DBDMA_CME 1<<11 -#define DBDMA_DDPE 1<<10 -#define DBDMA_TDPE 1<<9 -#define DBDMA_EXTE 1<<8 -#define DBDMA_BST_MASK (1<<4|1<<5|1<<6) -#define DBDMA_BSR_MASK (1<<0|1<<1|1<<2) - -#define DBDMA_BURST_1 (0x00) -#define DBDMA_BURST_2 (0x01) -#define DBDMA_BURST_4 (0x02) -#define DBDMA_BURST_8 (0x03) -#define DBDMA_BURST_16 (0x04) -#define DBDMA_BURST_32 (0x05) -#define DBDMA_BURST_64 (0x06) -#define DBDMA_BURST_128 (0x07) - -#define DBDMA_TX_BST_SHIFT (4) -#define DBDMA_RX_BST_SHIFT (0) - -#define DBDMA_TX_ARBITRATION_DEFAULT ( 1 << 19 ) -#define DBDMA_RX_ARBITRATION_DEFAULT ( 2 << 16 ) - - -/* Back-to-back interpacket gap register */ -#define BTOB_INTP_GAP 0xa2 -#define BTOB_INTP_DEFAULT 0x18 - -/* Non-back-to-back interpacket gap register */ -#define NBTOB_INTP_GAP 0xa4 - -/* MIIM command register */ -#define MIIM_COMMAND 0xa6 -#define MIIM_SCAN 1<<1 -#define MIIM_RSTAT 1<<0 - -/* MII address register */ -#define MII_ADDRESS 0xa8 -#define MII_FIAD_MASK (1<<8|1<<9|1<<10|1<<11|1<<12) -#define MII_RGAD_MASK (1<<0|1<<1|1<<2|1<<3|1<<4) - -#define TPPMD_CONTROL_REG 0xa8 -#define TPPMD_FO 1<<1 -#define TPPMD_LB 1<<0 - -/* MII read and write registers */ -#define MII_WRITE_DATA 0xaa -#define MII_READ_DATA 0xac - -/* MII indicators */ -#define MII_INDICATOR 0xae -#define MII_NVALID 1<<2 -#define MII_SCAN 1<<1 -#define MII_BUSY 1<<0 - -/* Address filter */ -#define ADDRESS_FILTER 0xd0 -#define ADDRESS_RPPRM 1<<3 /* multicast promis. mode */ -#define ADDRESS_RPPRO 1<<2 /* promiscuous mode */ -#define ADDRESS_RPAMC 1<<1 /* accept multicasts */ -#define ADDRESS_RPABC 1<<0 /* accept broadcasts */ - -/* Station addresses - - Note that if the serial EEPROM is disabled, these values are all - zero. If, like us, you get the chips when they're fresh, they're - also zero and you have to initialize the address */ -#define STATION_ADDRESS_0 0xd2 -#define STATION_ADDRESS_1 0xd4 -#define STATION_ADDRESS_2 0xd6 - -/* Hash tables */ -#define HASH_TABLE_0 0xd8 -#define HASH_TABLE_1 0xda -#define HASH_TABLE_2 0xdc -#define HASH_TABLE_3 0xde - -/* PHY indentifiers */ -#define PHY_IDENTIFIER_0 0xe4 -#define PHY_IDENTIFIER_1 0xe6 - -/* MII Auto-negotiation register definitions */ - -#define MII_AUTO_NEGOTIATION_CONTROL (0x0000) -#define MANC_PHY_RESET (0x8000) -#define MANC_PHY_LOOPBACK_ENABLE (0x4000) -#define MANC_PHY_LOOPBACK_DISABLE (0x0000) -#define MANC_PHY_SPEED_100 (0x2000) -#define MANC_PHY_SPEED_10 (0x0000) -#define MANC_AUTO_NEGOTIATION_ENABLE (0x1000) -#define MANC_AUTO_NEGOTIATION_DISABLE (0x0000) -#define MANC_PHY_POWER_DOWN (0x0800) -#define MANC_PHY_POWER_UP (0x0000) -#define MANC_ISOLATE_ENABLE (0x0400) -#define MANC_ISOLATE_DISABLE (0x0000) -#define MANC_RESTART_AUTO_NEGOTIATION (0x0200) -#define MANC_FULL_DUPLEX (0x0100) -#define MANC_HALF_DUPLEX (0x0000) - -#define MII_AUTO_NEGOTIATION_STATUS (0x0001) -#define MANS_100BASE_T4_HALF_DUPLEX (0x8000) -#define MANS_100BASE_X_FULL_DUPLEX (0x4000) -#define MANS_100BASE_X_HALF_DUPLEX (0x2000) -#define MANS_10MBS_FULL_DUPLEX (0x1000) -#define MANS_10MBS_HALF_DUPLEX (0x0800) -#define MANS_AUTO_NEGOTIATION_COMPLETE (0x0020) -#define MANS_REMOTE_FAULT (0x0010) -#define MANS_AUTO_NEGOTIATION_ABILITY (0x0008) -#define MANS_LINK_STATUS (0x0004) -#define MANS_JABBER_DETECT (0x0002) -#define MANS_EXTENDED_CAPABILITY (0x0001) - -#define MII_PHY_IDENTIFIER_1 (0x0002) -#define MII_PHY_IDENTIFIER_2 (0x0003) - -#define MII_AUTO_NEGOTIATION_ADVERTISEMENT (0x0004) -#define MANA_NEXT_PAGE (0x8000) -#define MANA_REMOTE_FAULT (0x2000) -#define MANA_TECHNOLOGY_ABILITY_MASK (0x1FE0) -#define MANATECH_10BASET_HALF_DUPLEX (0x0020) -#define MANATECH_10BASET_FULL_DUPLEX (0x0040) -#define MANATECH_100BASETX_HALF_DUPLEX (0x0080) -#define MANATECH_100BASETX_FULL_DUPLEX (0x0100) -#define MANATECH_100BASET4 (0x0200) -#define MANA_SELECTOR_MASK (0x001F) -#define MANASELECTOR_802_3 (0x0001) - -#define MII_AUTO_NEGOTIATION_LINK_PARTNER (0x0005) -#define MANLP_NEXT_PAGE (0x8000) -#define MANLP_ACKNOWLEDGE (0x4000) -#define MANLP_REMOTE_FAULT (0x2000) -#define MANLP_TECHNOLOGY_ABILITY_MASK (0x1FE0) -#define MANLP_SELECTOR_MASK (0x001F) - -#define MII_AUTO_NEGOTIATION_EXPANSION (0x0006) -#define MANE_PARALLEL_DETECTION_FAULT (0x0010) -#define MANE_LINK_PARTNER_NEXT_PAGE_ABLE (0x0008) -#define MANE_NEXT_PAGE_ABLE (0x0004) -#define MANE_PAGE_RECEIVED (0x0002) -#define MANE_LINK_PARTNER_AUTO_ABLE (0x0001) - -#define MII_AUTO_NEGOTIATION_NEXT_PAGE_TRANSMIT (0x0007) -#define MANNPT_NEXT_PAGE (0x8000) -#define MANNPT_MESSAGE_PAGE (0x2000) -#define MANNPT_ACKNOWLEDGE_2 (0x1000) -#define MANNPT_TOGGLE (0x0800) -#define MANNPT_MESSAGE_FIELD_MASK (0x07FF) - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/ne.c linux.ac/drivers/net/ne.c --- linux.vanilla/drivers/net/ne.c Tue Apr 3 17:32:12 2001 +++ linux.ac/drivers/net/ne.c Sat Apr 14 01:25:04 2001 @@ -238,7 +238,7 @@ int start_page, stop_page; int neX000, ctron, copam, bad_card; int reg0, ret; - static unsigned version_printed = 0; + static unsigned version_printed; if (!request_region(ioaddr, NE_IO_EXTENT, dev->name)) return -EBUSY; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/net_init.c linux.ac/drivers/net/net_init.c --- linux.vanilla/drivers/net/net_init.c Tue Apr 3 17:32:12 2001 +++ linux.ac/drivers/net/net_init.c Sat Apr 14 01:25:04 2001 @@ -171,6 +171,7 @@ return dev; } +#if defined(CONFIG_HIPPI) || defined(CONFIG_TR) || defined(CONFIG_NET_FC) static int __register_netdev(struct net_device *dev) { dev_init_buffers(dev); @@ -181,6 +182,7 @@ } return 0; } +#endif /** * init_etherdev - Register ethernet device diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/ni5010.c linux.ac/drivers/net/ni5010.c --- linux.vanilla/drivers/net/ni5010.c Tue Apr 3 17:32:12 2001 +++ linux.ac/drivers/net/ni5010.c Sat Apr 14 01:25:04 2001 @@ -74,7 +74,7 @@ "ni5010.c: v1.00 06/23/97 Jan-Pascal van Best and Andreas Mohr\n"; /* bufsize_rcv == 0 means autoprobing */ -static unsigned int bufsize_rcv = 0; +static unsigned int bufsize_rcv; #define jumpered_interrupts /* IRQ line jumpered on board */ #undef jumpered_dma /* No DMA used */ @@ -186,7 +186,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr) { - static unsigned version_printed = 0; + static unsigned version_printed; int i; unsigned int data = 0; int boguscount = 40; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/ni52.c linux.ac/drivers/net/ni52.c --- linux.vanilla/drivers/net/ni52.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/ni52.c Sat Apr 14 01:25:04 2001 @@ -99,9 +99,9 @@ * < 30.Sep.93: first versions */ -static int debuglevel = 0; /* debug-printk 0: off 1: a few 2: more */ -static int automatic_resume = 0; /* experimental .. better should be zero */ -static int rfdadd = 0; /* rfdadd=1 may be better for 8K MEM cards */ +static int debuglevel; /* debug-printk 0: off 1: a few 2: more */ +static int automatic_resume; /* experimental .. better should be zero */ +static int rfdadd; /* rfdadd=1 may be better for 8K MEM cards */ static int fifo=0x8; /* don't change */ /* #define REALLY_SLOW_IO */ @@ -1289,8 +1289,8 @@ /* set: io,irq,memstart,memend or set it when calling insmod */ static int irq=9; static int io=0x300; -static long memstart=0; /* e.g 0xd0000 */ -static long memend=0; /* e.g 0xd4000 */ +static long memstart; /* e.g 0xd0000 */ +static long memend; /* e.g 0xd4000 */ MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/pci-skeleton.c linux.ac/drivers/net/pci-skeleton.c --- linux.vanilla/drivers/net/pci-skeleton.c Tue Apr 3 17:32:12 2001 +++ linux.ac/drivers/net/pci-skeleton.c Sat Apr 14 01:25:04 2001 @@ -36,7 +36,7 @@ -----<snip>----- This software may be used and distributed according to the terms - of the GNU Public License, incorporated herein by reference. + of the GNU General Public License, incorporated herein by reference. ----------------------------------------------------------------------------- @@ -740,7 +740,7 @@ int i, addr_len, option; void *ioaddr = NULL; static int board_idx = -1; - static int printed_version = 0; + static int printed_version; u8 tmp; DPRINTK ("ENTER\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/pcmcia/Config.in linux.ac/drivers/net/pcmcia/Config.in --- linux.vanilla/drivers/net/pcmcia/Config.in Tue Apr 3 17:32:12 2001 +++ linux.ac/drivers/net/pcmcia/Config.in Tue Apr 3 17:54:52 2001 @@ -20,7 +20,8 @@ fi if [ "$CONFIG_CARDBUS" = "y" ]; then - tristate ' Xircom Tulip-like CardBus support' CONFIG_PCMCIA_XIRTULIP + tristate ' Xircom CardBus support (new driver)' CONFIG_PCMCIA_XIRCOM + tristate ' Xircom Tulip-like CardBus support (old driver)' CONFIG_PCMCIA_XIRTULIP fi bool ' Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/pcmcia/Makefile linux.ac/drivers/net/pcmcia/Makefile --- linux.vanilla/drivers/net/pcmcia/Makefile Tue Apr 3 17:32:12 2001 +++ linux.ac/drivers/net/pcmcia/Makefile Tue Apr 3 17:54:52 2001 @@ -33,6 +33,7 @@ # Cardbus client drivers obj-$(CONFIG_PCMCIA_XIRTULIP) += xircom_tulip_cb.o +obj-$(CONFIG_PCMCIA_XIRCOM) += xircom_cb.o obj-$(CONFIG_PCMCIA_IBMTR) += ibmtr_cs.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/pcmcia/aironet4500_cs.c linux.ac/drivers/net/pcmcia/aironet4500_cs.c --- linux.vanilla/drivers/net/pcmcia/aironet4500_cs.c Tue Apr 3 17:32:12 2001 +++ linux.ac/drivers/net/pcmcia/aironet4500_cs.c Tue Apr 3 17:54:52 2001 @@ -179,12 +179,14 @@ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); if (!link) return NULL; + memset(link, 0, sizeof(struct dev_link_t)); + link->dev = kmalloc(sizeof(struct dev_node_t), GFP_KERNEL); if (!link->dev) { kfree(link); return NULL; } - memset(link, 0, sizeof(struct dev_link_t)); + memset(link->dev, 0, sizeof(struct dev_node_t)); link->release.function = &awc_release; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/pcmcia/hermes.c linux.ac/drivers/net/pcmcia/hermes.c --- linux.vanilla/drivers/net/pcmcia/hermes.c Tue Apr 3 17:32:12 2001 +++ linux.ac/drivers/net/pcmcia/hermes.c Sat Apr 14 01:25:09 2001 @@ -19,7 +19,6 @@ static const char *version = "hermes.c: 12 Dec 2000 David Gibson <hermes@gibson.dropbear.id.au>"; -#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> #include <linux/smp.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/pcmcia/hermes.h linux.ac/drivers/net/pcmcia/hermes.h --- linux.vanilla/drivers/net/pcmcia/hermes.h Tue Apr 3 17:32:12 2001 +++ linux.ac/drivers/net/pcmcia/hermes.h Tue Apr 3 18:54:49 2001 @@ -196,6 +196,9 @@ #define HERMES_RID_CURRENT_BSSID ((uint16_t)0xfd42) #define HERMES_RID_COMMSQUALITY ((uint16_t)0xfd43) #define HERMES_RID_CURRENT_TX_RATE ((uint16_t)0xfd44) +#define HERMES_RID_SHORT_RETRY_LIMIT ((uint16_t)0xfd48) +#define HERMES_RID_LONG_RETRY_LIMIT ((uint16_t)0xfd49) +#define HERMES_RID_MAX_TX_LIFETIME ((uint16_t)0xfd4A) #define HERMES_RID_WEP_AVAIL ((uint16_t)0xfd4f) #define HERMES_RID_CURRENT_CHANNEL ((uint16_t)0xfdc1) #define HERMES_RID_DATARATES ((uint16_t)0xfdc6) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/pcmcia/netwave_cs.c linux.ac/drivers/net/pcmcia/netwave_cs.c --- linux.vanilla/drivers/net/pcmcia/netwave_cs.c Tue Apr 3 17:32:12 2001 +++ linux.ac/drivers/net/pcmcia/netwave_cs.c Tue Apr 3 17:54:53 2001 @@ -710,8 +710,17 @@ if(wrq->u.data.pointer != (caddr_t) 0) { struct iw_range range; - /* Set the length (useless : its constant...) */ + /* Set the length (very important for backward compatibility) */ wrq->u.data.length = sizeof(struct iw_range); + + /* Set all the info we don't care or don't know about to zero */ + memset(&range, 0, sizeof(range)); + +#if WIRELESS_EXT > 10 + /* Set the Wireless Extension versions */ + range.we_version_compiled = WIRELESS_EXT; + range.we_version_source = 9; /* Nothing for us in v10 and v11 */ +#endif /* WIRELESS_EXT > 10 */ /* Set information in the range struct */ range.throughput = 450 * 1000; /* don't argue on this ! */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/pcmcia/orinoco_cs.c linux.ac/drivers/net/pcmcia/orinoco_cs.c --- linux.vanilla/drivers/net/pcmcia/orinoco_cs.c Tue Apr 3 17:32:12 2001 +++ linux.ac/drivers/net/pcmcia/orinoco_cs.c Tue Apr 3 17:54:53 2001 @@ -239,6 +239,7 @@ int has_wep, has_big_wep; int has_mwo; int has_pm; + int has_retry; int broken_reset, broken_allocate; uint16_t channel_mask; @@ -254,6 +255,7 @@ uint16_t ap_density, rts_thresh; uint16_t tx_rate_ctrl; uint16_t pm_on, pm_mcast, pm_period, pm_timeout; + uint16_t retry_short, retry_long, retry_time; int promiscuous, allmulti, mc_count; @@ -645,6 +647,24 @@ goto out; } + /* Set retry settings - will fail on lot's of firmwares */ + if (priv->has_retry) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, + priv->retry_short); + if (err) { + printk(KERN_WARNING "%s: Can't set retry limit!\n", dev->name); + goto out; + } + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, + priv->retry_long); + if (err) + goto out; + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, + priv->retry_time); + if (err) + goto out; + } + /* Set promiscuity / multicast*/ priv->promiscuous = 0; priv->allmulti = 0; @@ -1267,6 +1287,7 @@ Gold cards from the others? */ priv->has_mwo = (firmver >= 0x60000); priv->has_pm = (firmver >= 0x40020); + priv->has_retry = 0; /* Tested with Lucent firmware : * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 => Jean II * Tested CableTron firmware : 4.32 => Anton */ @@ -1285,6 +1306,7 @@ priv->has_big_wep = 1; priv->has_mwo = 0; priv->has_pm = (firmver >= 0x20000); + priv->has_retry = 0; /* Tested with Intel firmware : 1.01 => Jean II */ /* Note : firmware 1.01 is *seriously* broken */ break; @@ -1301,6 +1323,7 @@ priv->has_big_wep = 0; /* FIXME */ priv->has_mwo = 0; priv->has_pm = (firmver >= 0x20000); /* FIXME */ + priv->has_retry = 0; break; case 0x6: vendor_str = "LinkSys/D-Link"; @@ -1315,6 +1338,7 @@ priv->has_big_wep = 0; priv->has_mwo = 0; priv->has_pm = (firmver >= 0x20000); /* FIXME */ + priv->has_retry = 0; break; #if 0 case 0x???: /* Could someone help here ??? */ @@ -1330,6 +1354,7 @@ priv->has_big_wep = 1; /* Probably RID_SYMBOL_KEY_LENGTH */ priv->has_mwo = 0; priv->has_pm = (firmver >= 0x20000); + priv->has_retry = 0; break; #endif default: @@ -1344,6 +1369,7 @@ priv->has_big_wep = 0; priv->has_mwo = 0; priv->has_pm = 0; + priv->has_retry = 0; } printk(KERN_INFO "%s: Firmware ID %02X vendor 0x%x (%s) version %d.%02d\n", @@ -1453,6 +1479,21 @@ } } + /* Retry setup */ + if (priv->has_retry) { + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, &priv->retry_short); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, &priv->retry_long); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, &priv->retry_time); + if (err) + goto out; + } + /* Set up the default configuration */ priv->iw_mode = IW_MODE_INFRA; /* By default use IEEE/IBSS ad-hoc mode if we have it */ @@ -1802,6 +1843,11 @@ /* Much of this shamelessly taken from wvlan_cs.c. No idea * what it all means -dgibson */ +#if WIRELESS_EXT > 10 + range.we_version_compiled = WIRELESS_EXT; + range.we_version_source = 11; +#endif /* WIRELESS_EXT > 10 */ + range.min_nwid = range.max_nwid = 0; /* We don't use nwids */ /* Set available channels/frequencies */ @@ -1881,6 +1927,16 @@ range.txpower[0] = 15; /* 15dBm */ range.txpower_capa = IW_TXPOW_DBM; +#if WIRELESS_EXT > 10 + range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; + range.retry_flags = IW_RETRY_LIMIT; + range.r_time_flags = IW_RETRY_LIFETIME; + range.min_retry = 0; + range.max_retry = 65535; /* ??? */ + range.min_r_time = 0; + range.max_r_time = 65535 * 1000; /* ??? */ +#endif /* WIRELESS_EXT > 10 */ + if (copy_to_user(rrq->pointer, &range, sizeof(range))) return -EFAULT; @@ -2520,6 +2576,92 @@ return err; } +#if WIRELESS_EXT > 10 +static int dldwd_ioctl_setretry(struct net_device *dev, struct iw_param *rrq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + + + dldwd_lock(priv); + + if ((rrq->disabled) || (!priv->has_retry)){ + err = -EOPNOTSUPP; + goto out; + } else { + if (rrq->flags & IW_RETRY_LIMIT) { + if (rrq->flags & IW_RETRY_MAX) + priv->retry_long = rrq->value; + else if (rrq->flags & IW_RETRY_MIN) + priv->retry_short = rrq->value; + else { + /* No modifier : set both */ + priv->retry_long = rrq->value; + priv->retry_short = rrq->value; + } + } + if (rrq->flags & IW_RETRY_LIFETIME) { + priv->retry_time = rrq->value / 1000; + } + if ((rrq->flags & IW_RETRY_TYPE) == 0) { + err = -EINVAL; + goto out; + } + } + + out: + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t short_limit, long_limit, lifetime; + + dldwd_lock(priv); + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, &short_limit); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, &long_limit); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, &lifetime); + if (err) + goto out; + + rrq->disabled = 0; /* Can't be disabled */ + + /* Note : by default, display the retry number */ + if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { + rrq->flags = IW_RETRY_LIFETIME; + rrq->value = lifetime * 1000; /* ??? */ + } else { + /* By default, display the min number */ + if ((rrq->flags & IW_RETRY_MAX)) { + rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + rrq->value = long_limit; + } else { + rrq->flags = IW_RETRY_LIMIT; + rrq->value = short_limit; + if(short_limit != long_limit) + rrq->flags |= IW_RETRY_MIN; + } + } + + out: + dldwd_unlock(priv); + + return err; +} +#endif /* WIRELESS_EXT > 10 */ + static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq) { dldwd_priv_t *priv = dev->priv; @@ -2857,6 +2999,20 @@ wrq->u.txpower.disabled = 0; wrq->u.txpower.flags = IW_TXPOW_DBM; break; + +#if WIRELESS_EXT > 10 + case SIOCSIWRETRY: + DEBUG(1, "%s: SIOCSIWRETRY\n", dev->name); + err = dldwd_ioctl_setretry(dev, &wrq->u.retry); + if (! err) + changed = 1; + break; + + case SIOCGIWRETRY: + DEBUG(1, "%s: SIOCGIWRETRY\n", dev->name); + err = dldwd_ioctl_getretry(dev, &wrq->u.retry); + break; +#endif /* WIRELESS_EXT > 10 */ case SIOCSIWSPY: DEBUG(1, "%s: SIOCSIWSPY\n", dev->name); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/pcmcia/pcnet_cs.c linux.ac/drivers/net/pcmcia/pcnet_cs.c --- linux.vanilla/drivers/net/pcmcia/pcnet_cs.c Tue Apr 3 17:32:12 2001 +++ linux.ac/drivers/net/pcmcia/pcnet_cs.c Thu Apr 12 17:46:42 2001 @@ -195,6 +195,7 @@ { /* SCM Ethernet */ 0x0ff0, 0x00, 0x20, 0xcb, 0 }, { /* Socket EA */ 0x4000, 0x00, 0xc0, 0x1b, DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF }, + { /* Socket LP-E CF+ */ 0x01c0, 0x00, 0xc0, 0x1b, 0 }, { /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 }, { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 }, { /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 }, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/pcmcia/ray_cs.c linux.ac/drivers/net/pcmcia/ray_cs.c --- linux.vanilla/drivers/net/pcmcia/ray_cs.c Tue Apr 3 17:32:12 2001 +++ linux.ac/drivers/net/pcmcia/ray_cs.c Tue Apr 3 17:54:53 2001 @@ -1332,8 +1332,14 @@ struct iw_range range; memset((char *) &range, 0, sizeof(struct iw_range)); - /* Set the length (useless : its constant...) */ + /* Set the length (very important for backward compatibility) */ wrq->u.data.length = sizeof(struct iw_range); + +#if WIRELESS_EXT > 10 + /* Set the Wireless Extension versions */ + range.we_version_compiled = WIRELESS_EXT; + range.we_version_source = 9; +#endif /* WIRELESS_EXT > 10 */ /* Set information in the range struct */ range.throughput = 1.1 * 1000 * 1000; /* Put the right number here */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/pcmcia/wavelan_cs.c linux.ac/drivers/net/pcmcia/wavelan_cs.c --- linux.vanilla/drivers/net/pcmcia/wavelan_cs.c Tue Apr 3 17:32:12 2001 +++ linux.ac/drivers/net/pcmcia/wavelan_cs.c Tue Apr 3 17:54:53 2001 @@ -2239,8 +2239,15 @@ { struct iw_range range; - /* Set the length (useless : its constant...) */ + /* Set the length (very important for backward compatibility) */ wrq->u.data.length = sizeof(struct iw_range); + + /* Set all the info we don't care or don't know about to zero */ + memset(&range, 0, sizeof(range)); + + /* Set the Wireless Extension versions */ + range.we_version_compiled = WIRELESS_EXT; + range.we_version_source = 9; /* Nothing for us in v10 and v11 */ /* Set information in the range struct */ range.throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/pcmcia/xircom_cb.c linux.ac/drivers/net/pcmcia/xircom_cb.c --- linux.vanilla/drivers/net/pcmcia/xircom_cb.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/pcmcia/xircom_cb.c Tue Apr 3 17:54:53 2001 @@ -0,0 +1,1244 @@ +/* + * xircom_cb: A driver for the (tulip-like) Xircom Cardbus ethernet cards + * + * This software is (C) by the respective authors, and licensed under the GPL + * License. + * + * Written by Arjan van de Ven for Red Hat, Inc. + * Based on work by Jeff Garzik, Doug Ledford and Donald Becker + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + * + * $Id: xircom_cb.c,v 1.33 2001/03/19 14:02:07 arjanv Exp $ + */ + + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <asm/bitops.h> +#include <asm/io.h> + + + +#ifdef DEBUG +#define enter(x) printk("Enter: %s, %s line %i\n",x,__FILE__,__LINE__) +#define leave(x) printk("Leave: %s, %s line %i\n",x,__FILE__,__LINE__) +#else +#define enter(x) do {} while (0) +#define leave(x) do {} while (0) +#endif + + +MODULE_DESCRIPTION("Xircom Cardbus ethernet driver"); +MODULE_AUTHOR("Arjan van de Ven <arjanv@redhat.com>"); + + + +/* IO registers on the card, offsets */ +#define CSR0 0x00 +#define CSR1 0x08 +#define CSR2 0x10 +#define CSR3 0x18 +#define CSR4 0x20 +#define CSR5 0x28 +#define CSR6 0x30 +#define CSR7 0x38 +#define CSR8 0x40 +#define CSR9 0x48 +#define CSR10 0x50 +#define CSR11 0x58 +#define CSR12 0x60 +#define CSR13 0x68 +#define CSR14 0x70 +#define CSR15 0x78 +#define CSR16 0x80 + +/* PCI registers */ +#define PCI_POWERMGMT 0x40 + +/* Offsets of the buffers within the descriptor pages, in bytes */ + +#define NUMDESCRIPTORS 4 + +static int bufferoffsets[NUMDESCRIPTORS] = {128,2048,4096,6144}; + + +struct xircom_private { + /* Send and receive buffers, kernel-addressable and dma addressable forms */ + + unsigned int *rx_buffer; + unsigned int *tx_buffer; + + dma_addr_t rx_dma_handle; + dma_addr_t tx_dma_handle; + + struct sk_buff *tx_skb[4]; + + unsigned long io_port; + int open; + + /* transmit_used is the rotating counter that indicates which transmit + descriptor has to be used next */ + int transmit_used; + + /* Spinlock to serialize register operations. + It must be helt while manipulating the following registers: + CSR0, CSR6, CSR7, CSR9, CSR10, CSR15 + */ + spinlock_t lock; + + + struct pci_dev *pdev; + struct net_device *dev; + struct net_device_stats stats; +}; + + +/* Function prototypes */ +static int xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id); +static void xircom_remove(struct pci_dev *pdev); +static void xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int xircom_open(struct net_device *dev); +static int xircom_close(struct net_device *dev); +static void xircom_up(struct xircom_private *card); +static struct net_device_stats *xircom_get_stats(struct net_device *dev); + +static void investigate_read_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset); +static void investigate_write_descriptor(struct net_device *dev, struct xircom_private *card, int descnr, unsigned int bufferoffset); +static void read_mac_address(struct xircom_private *card); +static void tranceiver_voodoo(struct xircom_private *card); +static void initialize_card(struct xircom_private *card); +static void trigger_transmit(struct xircom_private *card); +static void trigger_receive(struct xircom_private *card); +static void setup_descriptors(struct xircom_private *card); +static void remove_descriptors(struct xircom_private *card); +static int link_status_changed(struct xircom_private *card); +static void activate_receiver(struct xircom_private *card); +static void deactivate_receiver(struct xircom_private *card); +static void activate_transmitter(struct xircom_private *card); +static void deactivate_transmitter(struct xircom_private *card); +static void enable_transmit_interrupt(struct xircom_private *card); +static void enable_receive_interrupt(struct xircom_private *card); +static void enable_link_interrupt(struct xircom_private *card); +static void disable_all_interrupts(struct xircom_private *card); +static int link_status(struct xircom_private *card); + + + +static struct pci_device_id xircom_pci_table[] __devinitdata = { + {0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID,}, + {0,}, +}; +MODULE_DEVICE_TABLE(pci, xircom_pci_table); + +static struct pci_driver xircom_ops = { + name: "xircom_cb", + id_table: xircom_pci_table, + probe: xircom_probe, + remove: xircom_remove, + suspend:NULL, + resume:NULL +}; + + +#ifdef DEBUG +static void print_binary(unsigned int number) +{ + int i,i2; + char buffer[64]; + memset(buffer,0,64); + i2=0; + for (i=31;i>=0;i--) { + if (number & (1<<i)) + buffer[i2++]='1'; + else + buffer[i2++]='0'; + if ((i&3)==0) + buffer[i2++]=' '; + } + printk("%s\n",buffer); +} +#endif + +/* xircom_probe is the code that gets called on device insertion. + it sets up the hardware and registers the device to the networklayer. + + TODO: Send 1 or 2 "dummy" packets here as the card seems to discard the + first two packets that get send, and pump hates that. + + */ +static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct net_device *dev = NULL; + struct xircom_private *private; + unsigned char chip_rev; + unsigned long flags; + unsigned short tmp16; + enter("xircom_probe"); + + /* First do the PCI initialisation */ + + if (pci_enable_device(pdev)) + return -ENODEV; + + /* disable all powermanagement */ + pci_write_config_dword(pdev, PCI_POWERMGMT, 0x0000); + + pci_set_master(pdev); /* Why isn't this done by pci_enable_device ?*/ + + /* clear PCI status, if any */ + pci_read_config_word (pdev,PCI_STATUS, &tmp16); + pci_write_config_word (pdev, PCI_STATUS,tmp16); + + pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev); + + if (!request_region(pci_resource_start(pdev, 0), 128, "xircom_cb")) { + printk(KERN_ERR "xircom_probe: failed to allocate io-region\n"); + return -ENODEV; + } + + + /* + Before changing the hardware, allocate the memory. + This way, we can fail gracefully if not enough memory + is available. + */ + private = kmalloc(sizeof(*private),GFP_KERNEL); + memset(private, 0, sizeof(struct xircom_private)); + + /* Allocate the send/receive buffers */ + private->rx_buffer = pci_alloc_consistent(pdev,8192,&private->rx_dma_handle); + + if (private->rx_buffer == NULL) { + printk(KERN_ERR "xircom_probe: no memory for rx buffer \n"); + kfree(private); + return -ENODEV; + } + private->tx_buffer = pci_alloc_consistent(pdev,8192,&private->tx_dma_handle); + if (private->tx_buffer == NULL) { + printk(KERN_ERR "xircom_probe: no memory for tx buffer \n"); + kfree(private->rx_buffer); + kfree(private); + return -ENODEV; + } + dev = init_etherdev(dev, 0); + if (dev == NULL) { + printk(KERN_ERR "xircom_probe: failed to allocate etherdev\n"); + kfree(private->rx_buffer); + kfree(private->tx_buffer); + kfree(private); + return -ENODEV; + } + SET_MODULE_OWNER(dev); + printk(KERN_INFO "%s: Xircom cardbus revision %i at irq %i \n", dev->name, chip_rev, pdev->irq); + + private->dev = dev; + private->pdev = pdev; + private->io_port = pci_resource_start(pdev, 0); + private->lock = SPIN_LOCK_UNLOCKED; + dev->irq = pdev->irq; + dev->base_addr = private->io_port; + + + initialize_card(private); + read_mac_address(private); + setup_descriptors(private); + + dev->open = &xircom_open; + dev->hard_start_xmit = &xircom_start_xmit; + dev->stop = &xircom_close; + dev->get_stats = &xircom_get_stats; + dev->priv = private; + pdev->driver_data = dev; + + + /* start the transmitter to get a heartbeat */ + /* TODO: send 2 dummy packets here */ + tranceiver_voodoo(private); + + spin_lock_irqsave(&private->lock,flags); + activate_transmitter(private); + activate_receiver(private); + spin_unlock_irqrestore(&private->lock,flags); + + trigger_receive(private); + + leave("xircom_probe"); + return 0; +} + + +/* + xircom_remove is called on module-unload or on device-eject. + it unregisters the irq, io-region and network device. + Interrupts and such are already stopped in the "ifconfig ethX down" + code. + */ +static void __devexit xircom_remove(struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + struct xircom_private *card; + enter("xircom_remove"); + if (dev!=NULL) { + card=dev->priv; + if (card!=NULL) { + if (card->rx_buffer!=NULL) + pci_free_consistent(pdev,8192,card->rx_buffer,card->rx_dma_handle); + card->rx_buffer = NULL; + if (card->tx_buffer!=NULL) + pci_free_consistent(pdev,8192,card->tx_buffer,card->tx_dma_handle); + card->tx_buffer = NULL; + } + kfree(card); + } + release_region(dev->base_addr, 128); + unregister_netdev(dev); + kfree(dev); + leave("xircom_remove"); +} + +static void xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_instance; + struct xircom_private *card = (struct xircom_private *) dev->priv; + unsigned int status; + int i; + + enter("xircom_interrupt\n"); + + spin_lock(&card->lock); + status = inl(card->io_port+CSR5); + +#if DEBUG + print_binary(status); + printk("tx status 0x%08x 0x%08x \n",card->tx_buffer[0],card->tx_buffer[4]); + printk("rx status 0x%08x 0x%08x \n",card->rx_buffer[0],card->rx_buffer[4]); +#endif + + if (link_status_changed(card)) { + int newlink; + printk(KERN_DEBUG "xircom_cb: Link status has changed \n"); + newlink = link_status(card); + printk(KERN_INFO "xircom_cb: Link is %i mbit \n",newlink); + if (newlink) + netif_carrier_on(dev); + else + netif_carrier_off(dev); + + } + + /* Clear all remaining interrupts */ + status |= 0xffffffff; /* FIXME: make this clear only the + real existing bits */ + outl(status,card->io_port+CSR5); + + + for (i=0;i<NUMDESCRIPTORS;i++) + investigate_write_descriptor(dev,card,i,bufferoffsets[i]); + for (i=0;i<NUMDESCRIPTORS;i++) + investigate_read_descriptor(dev,card,i,bufferoffsets[i]); + + + spin_unlock(&card->lock); + leave("xircom_interrupt"); +} + +static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct xircom_private *card; + unsigned long flags; + int nextdescriptor; + int desc; + enter("xircom_start_xmit"); + + card = (struct xircom_private*)dev->priv; + spin_lock_irqsave(&card->lock,flags); + + /* First see if we can free some descriptors */ + for (desc=0;desc<NUMDESCRIPTORS;desc++) + investigate_write_descriptor(dev,card,desc,bufferoffsets[desc]); + + + nextdescriptor = (card->transmit_used +1) % (NUMDESCRIPTORS); + desc = card->transmit_used; + + /* only send the packet if the descriptor is free */ + if (card->tx_buffer[4*desc]==0) { + /* Copy the packet data; zero the memory first as the card + sometimes sends more than you ask it to. */ + + memset(&card->tx_buffer[bufferoffsets[desc]/4],0,1536); + memcpy(&(card->tx_buffer[bufferoffsets[desc]/4]),skb->data,skb->len); + + + /* FIXME: The specification tells us that the length we send HAS to be a multiple of + 4 bytes. */ + + card->tx_buffer[4*desc+1] = skb->len; + if (desc == NUMDESCRIPTORS-1) + card->tx_buffer[4*desc+1] |= (1<<25); /* bit 25: last descriptor of the ring */ + + card->tx_buffer[4*desc+1] |= 0xF0000000; + /* 0xF0... means want interrupts*/ + card->tx_skb[desc] = skb; + + wmb(); + /* This gives the descriptor to the card */ + card->tx_buffer[4*desc] = 0x80000000; + trigger_transmit(card); + if (((int)card->tx_buffer[nextdescriptor*4])<0) { /* next descriptor is occupied... */ + netif_stop_queue(dev); + } + card->transmit_used = nextdescriptor; + leave("xircom-start_xmit - sent"); + spin_unlock_irqrestore(&card->lock,flags); + return 0; + } + + + + /* Uh oh... no free descriptor... drop the packet */ + netif_stop_queue(dev); + spin_unlock_irqrestore(&card->lock,flags); + trigger_transmit(card); + + return -EIO; +} + + + + +static int xircom_open(struct net_device *dev) +{ + struct xircom_private *xp = (struct xircom_private *) dev->priv; + int retval; + enter("xircom_open"); + printk(KERN_INFO "xircom cardbus adaptor found, registering as %s, using irq %i \n",dev->name,dev->irq); + retval = request_irq(dev->irq, &xircom_interrupt, SA_SHIRQ, dev->name, dev); + if (retval) { + leave("xircom_open - No IRQ"); + return retval; + } + + xircom_up(xp); + xp->open = 1; + leave("xircom_open"); + return 0; +} + +static int xircom_close(struct net_device *dev) +{ + struct xircom_private *card; + unsigned long flags; + + enter("xircom_close"); + card = dev->priv; + netif_stop_queue(dev); /* we don't want new packets */ + + + spin_lock_irqsave(&card->lock,flags); + + disable_all_interrupts(card); +#if 0 + /* We can enable this again once we send dummy packets on ifconfig ethX up */ + deactivate_receiver(card); + deactivate_transmitter(card); +#endif + remove_descriptors(card); + + spin_unlock_irqrestore(&card->lock,flags); + + card->open = 0; + free_irq(dev->irq,dev); + + leave("xircom_close"); + + return 0; + +} + + + +static struct net_device_stats *xircom_get_stats(struct net_device *dev) +{ + struct xircom_private *card = (struct xircom_private *)dev->priv; + return &card->stats; +} + + + + +static void initialize_card(struct xircom_private *card) +{ + unsigned int val; + unsigned long flags; + enter("initialize_card"); + + + spin_lock_irqsave(&card->lock, flags); + + /* First: reset the card */ + val = inl(card->io_port + CSR0); + val |= 0x01; /* Software reset */ + outl(val, card->io_port + CSR0); + + udelay(100); /* give the card some time to reset */ + + val = inl(card->io_port + CSR0); + val &= ~0x01; /* disable Software reset */ + outl(val, card->io_port + CSR0); + + + val = 0; /* Value 0x00 is a safe and conservative value + for the PCI configuration settings */ + outl(val, card->io_port + CSR0); + + + disable_all_interrupts(card); + deactivate_receiver(card); + deactivate_transmitter(card); + + spin_unlock_irqrestore(&card->lock, flags); + + leave("initialize_card"); +} + +/* +trigger_transmit causes the card to check for frames to be transmitted. +This is accomplished by writing to the CSR1 port. The documentation +claims that the act of writing is sufficient and that the value is +ignored; I chose zero. +*/ +static void trigger_transmit(struct xircom_private *card) +{ + unsigned int val; + enter("trigger_transmit"); + + val = 0; + outl(val, card->io_port + CSR1); + + leave("trigger_transmit"); +} + +/* +trigger_receive causes the card to check for empty frames in the +descriptor list in which packets can be received. +This is accomplished by writing to the CSR2 port. The documentation +claims that the act of writing is sufficient and that the value is +ignored; I chose zero. +*/ +static void trigger_receive(struct xircom_private *card) +{ + unsigned int val; + enter("trigger_receive"); + + val = 0; + outl(val, card->io_port + CSR2); + + leave("trigger_receive"); +} + +/* +setup_descriptors initializes the send and receive buffers to be valid +descriptors and programs the addresses into the card. +*/ +static void setup_descriptors(struct xircom_private *card) +{ + unsigned int val; + unsigned int address; + int i; + enter("setup_descriptors"); + + + if (card->rx_buffer == NULL) + BUG(); + if (card->tx_buffer == NULL) + BUG(); + + /* Receive descriptors */ + memset(card->rx_buffer, 0, 128); /* clear the descriptors */ + for (i=0;i<NUMDESCRIPTORS;i++ ) { + + /* Rx Descr0: It's empty, let the card own it, no errors -> 0x80000000 */ + card->rx_buffer[i*4 + 0] = 0x80000000; + /* Rx Descr1: buffer 1 is 1536 bytes, buffer 2 is 0 bytes */ + card->rx_buffer[i*4 + 1] = 1536; + if (i==NUMDESCRIPTORS-1) + card->rx_buffer[i*4 + 1] |= (1 << 25); /* bit 25 is "last descriptor" */ + + /* Rx Descr2: address of the buffer + we store the buffer at the 2nd half of the page */ + + address = (unsigned long) card->rx_dma_handle; + card->rx_buffer[i*4 + 2] = cpu_to_le32(address + bufferoffsets[i]); + /* Rx Desc3: address of 2nd buffer -> 0 */ + card->rx_buffer[i*4 + 3] = 0; + } + + wmb(); + /* Write the receive descriptor ring address to the card */ + address = (unsigned long) card->rx_dma_handle; + val = cpu_to_le32(address); + outl(val, card->io_port + CSR3); /* Receive descr list address */ + + + /* transmit descriptors */ + memset(card->tx_buffer, 0, 128); /* clear the descriptors */ + + for (i=0;i<NUMDESCRIPTORS;i++ ) { + /* Tx Descr0: Empty, we own it, no errors -> 0x00000000 */ + card->tx_buffer[i*4 + 0] = 0x00000000; + /* Tx Descr1: buffer 1 is 1536 bytes, buffer 2 is 0 bytes */ + card->tx_buffer[i*4 + 1] = 1536; + if (i==NUMDESCRIPTORS-1) + card->tx_buffer[i*4 + 1] |= (1 << 25); /* bit 25 is "last descriptor" */ + + /* Tx Descr2: address of the buffer + we store the buffer at the 2nd half of the page */ + address = (unsigned long) card->tx_dma_handle; + card->tx_buffer[i*4 + 2] = cpu_to_le32(address + bufferoffsets[i]); + /* Tx Desc3: address of 2nd buffer -> 0 */ + card->tx_buffer[i*4 + 3] = 0; + } + + wmb(); + /* wite the transmit descriptor ring to the card */ + address = (unsigned long) card->tx_dma_handle; + val =cpu_to_le32(address); + outl(val, card->io_port + CSR4); /* xmit descr list address */ + + leave("setup_descriptors"); +} + +/* +remove_descriptors informs the card the descriptors are no longer +valid by setting the address in the card to 0x00. +*/ +static void remove_descriptors(struct xircom_private *card) +{ + unsigned int val; + enter("remove_descriptors"); + + val = 0; + outl(val, card->io_port + CSR3); /* Receive descriptor address */ + outl(val, card->io_port + CSR4); /* Send descriptor address */ + + leave("remove_descriptors"); +} + +/* +link_status_changed returns 1 if the card has indicated that +the link status has changed. The new link status has to be read from CSR12. + +This function also clears the status-bit. +*/ +static int link_status_changed(struct xircom_private *card) +{ + unsigned int val; + enter("link_status_changed"); + + val = inl(card->io_port + CSR5); /* Status register */ + + if ((val & (1 << 27)) == 0) { /* no change */ + leave("link_status_changed - nochange"); + return 0; + } + + /* clear the event by writing a 1 to the bit in the + status register. */ + val = (1 << 27); + outl(val, card->io_port + CSR5); + + leave("link_status_changed - changed"); + return 1; +} + + +/* +transmit_active returns 1 if the transmitter on the card is +in a non-stopped state. +*/ +static int transmit_active(struct xircom_private *card) +{ + unsigned int val; + enter("transmit_active"); + + val = inl(card->io_port + CSR5); /* Status register */ + + if ((val & (7 << 20)) == 0) { /* transmitter disabled */ + leave("transmit_active - inactive"); + return 0; + } + + leave("transmit_active - active"); + return 1; +} + +/* +receive_active returns 1 if the receiver on the card is +in a non-stopped state. +*/ +static int receive_active(struct xircom_private *card) +{ + unsigned int val; + enter("receive_active"); + + + val = inl(card->io_port + CSR5); /* Status register */ + + if ((val & (7 << 17)) == 0) { /* receiver disabled */ + leave("receive_active - inactive"); + return 0; + } + + leave("receive_active - active"); + return 1; +} + +/* +activate_receiver enables the receiver on the card. +Before being allowed to active the receiver, the receiver +must be completely de-activated. To achieve this, +this code actually disables the receiver first; then it waits for the +receiver to become inactive, then it activates the receiver and then +it waits for the receiver to be active. + +must be called with the lock held and interrupts disabled. +*/ +static void activate_receiver(struct xircom_private *card) +{ + unsigned int val; + int counter; + enter("activate_receiver"); + + + val = inl(card->io_port + CSR6); /* Operation mode */ + + /* If the "active" bit is set and the receiver is already + active, no need to do the expensive thing */ + if ((val&2) && (receive_active(card))) + return; + + + val = val & ~2; /* disable the receiver */ + outl(val, card->io_port + CSR6); + + counter = 10; + while (counter > 0) { + if (!receive_active(card)) + break; + /* wait a while */ + udelay(50); + counter--; + if (counter <= 0) + printk(KERN_ERR "xircom_cb: Receiver failed to deactivate\n"); + } + + /* enable the receiver */ + val = inl(card->io_port + CSR6); /* Operation mode */ + val = val | 2; /* enable the receiver */ + outl(val, card->io_port + CSR6); + + /* now wait for the card to activate again */ + counter = 10; + while (counter > 0) { + if (receive_active(card)) + break; + /* wait a while */ + udelay(50); + counter--; + if (counter <= 0) + printk(KERN_ERR "xircom_cb: Receiver failed to re-activate\n"); + } + + leave("activate_receiver"); +} + +/* +deactivate_receiver disables the receiver on the card. +To achieve this this code disables the receiver first; +then it waits for the receiver to become inactive. + +must be called with the lock held and interrupts disabled. +*/ +static void deactivate_receiver(struct xircom_private *card) +{ + unsigned int val; + int counter; + enter("deactivate_receiver"); + + val = inl(card->io_port + CSR6); /* Operation mode */ + val = val & ~2; /* disable the receiver */ + outl(val, card->io_port + CSR6); + + counter = 10; + while (counter > 0) { + if (!receive_active(card)) + break; + /* wait a while */ + udelay(50); + counter--; + if (counter <= 0) + printk(KERN_ERR "xircom_cb: Receiver failed to deactivate\n"); + } + + + leave("deactivate_receiver"); +} + + +/* +activate_transmitter enables the transmitter on the card. +Before being allowed to active the transmitter, the transmitter +must be completely de-activated. To achieve this, +this code actually disables the transmitter first; then it waits for the +transmitter to become inactive, then it activates the transmitter and then +it waits for the transmitter to be active again. + +must be called with the lock held and interrupts disabled. +*/ +static void activate_transmitter(struct xircom_private *card) +{ + unsigned int val; + int counter; + enter("activate_transmitter"); + + + val = inl(card->io_port + CSR6); /* Operation mode */ + + /* If the "active" bit is set and the receiver is already + active, no need to do the expensive thing */ + if ((val&(1<<13)) && (transmit_active(card))) + return; + + val = val & ~(1 << 13); /* disable the transmitter */ + outl(val, card->io_port + CSR6); + + counter = 10; + while (counter > 0) { + if (!transmit_active(card)) + break; + /* wait a while */ + udelay(50); + counter--; + if (counter <= 0) + printk(KERN_ERR "xircom_cb: Transmitter failed to deactivate\n"); + } + + /* enable the transmitter */ + val = inl(card->io_port + CSR6); /* Operation mode */ + val = val | (1 << 13); /* enable the transmitter */ + outl(val, card->io_port + CSR6); + + /* now wait for the card to activate again */ + counter = 10; + while (counter > 0) { + if (transmit_active(card)) + break; + /* wait a while */ + udelay(50); + counter--; + if (counter <= 0) + printk(KERN_ERR "xircom_cb: Transmitter failed to re-activate\n"); + } + + leave("activate_transmitter"); +} + +/* +deactivate_transmitter disables the transmitter on the card. +To achieve this this code disables the transmitter first; +then it waits for the transmitter to become inactive. + +must be called with the lock held and interrupts disabled. +*/ +static void deactivate_transmitter(struct xircom_private *card) +{ + unsigned int val; + int counter; + enter("deactivate_transmitter"); + + val = inl(card->io_port + CSR6); /* Operation mode */ + val = val & ~2; /* disable the transmitter */ + outl(val, card->io_port + CSR6); + + counter = 20; + while (counter > 0) { + if (!transmit_active(card)) + break; + /* wait a while */ + udelay(50); + counter--; + if (counter <= 0) + printk(KERN_ERR "xircom_cb: Transmitter failed to deactivate\n"); + } + + + leave("deactivate_transmitter"); +} + + +/* +enable_transmit_interrupt enables the transmit interrupt + +must be called with the lock held and interrupts disabled. +*/ +static void enable_transmit_interrupt(struct xircom_private *card) +{ + unsigned int val; + enter("enable_transmit_interrupt"); + + val = inl(card->io_port + CSR7); /* Interrupt enable register */ + val |= 1; /* enable the transmit interrupt */ + outl(val, card->io_port + CSR7); + + leave("enable_transmit_interrupt"); +} + + +/* +enable_receive_interrupt enables the receive interrupt + +must be called with the lock held and interrupts disabled. +*/ +static void enable_receive_interrupt(struct xircom_private *card) +{ + unsigned int val; + enter("enable_receive_interrupt"); + + val = inl(card->io_port + CSR7); /* Interrupt enable register */ + val = val | (1 << 6); /* enable the receive interrupt */ + outl(val, card->io_port + CSR7); + + leave("enable_receive_interrupt"); +} + +/* +enable_link_interrupt enables the link status change interrupt + +must be called with the lock held and interrupts disabled. +*/ +static void enable_link_interrupt(struct xircom_private *card) +{ + unsigned int val; + enter("enable_link_interrupt"); + + val = inl(card->io_port + CSR7); /* Interrupt enable register */ + val = val | (1 << 27); /* enable the link status chage interrupt */ + outl(val, card->io_port + CSR7); + + leave("enable_link_interrupt"); +} + + + +/* +disable_all_interrupts disables all interrupts + +must be called with the lock held and interrupts disabled. +*/ +static void disable_all_interrupts(struct xircom_private *card) +{ + unsigned int val; + enter("enable_all_interrupts"); + + val = 0; /* disable all interrupts */ + outl(val, card->io_port + CSR7); + + leave("disable_all_interrupts"); +} + +/* +enable_common_interrupts enables several weird interrupts + +must be called with the lock held and interrupts disabled. +*/ +static void enable_common_interrupts(struct xircom_private *card) +{ + unsigned int val; + enter("enable_link_interrupt"); + + val = inl(card->io_port + CSR7); /* Interrupt enable register */ + val |= (1<<16); /* Normal Interrupt Summary */ + val |= (1<<15); /* Abnormal Interrupt Summary */ + val |= (1<<13); /* Fatal bus error */ + val |= (1<<8); /* Receive Process Stopped */ + val |= (1<<7); /* Receive Buffer Unavailable */ + val |= (1<<5); /* Transmit Underflow */ + val |= (1<<2); /* Transmit Buffer Unavailable */ + val |= (1<<1); /* Transmit Process Stopped */ + outl(val, card->io_port + CSR7); + + leave("enable_link_interrupt"); +} + +/* +enable_promisc starts promisc mode + +must be called with the lock held and interrupts disabled. +*/ +static int enable_promisc(struct xircom_private *card) +{ + unsigned int val; + enter("enable_promisc"); + + val = inl(card->io_port + CSR6); + val = val | (1 << 6); + outl(val, card->io_port + CSR6); + + leave("enable_promisc"); + return 1; +} + + + + +/* +link_status() checks the the links status and will return 0 for no link, 10 for 10mbit link and 100 for.. guess what. + +Must be called in locked state with interrupts disabled +*/ +static int link_status(struct xircom_private *card) +{ + unsigned int val; + enter("link_status"); + + val = inb(card->io_port + CSR12); + + if (!(val&(1<<2))) /* bit 2 is 0 for 10mbit link, 1 for not an 10mbit link */ + return 10; + if (!(val&(1<<1))) /* bit 1 is 0 for 100mbit link, 1 for not an 100mbit link */ + return 100; + + /* If we get here -> no link at all */ + + leave("link_status"); + return 0; +} + + + + + +/* + read_mac_address() reads the MAC address from the NIC and stores it in the "dev" structure. + + This function will take the spinlock itself and can, as a result, not be called with the lock helt. + */ +static void read_mac_address(struct xircom_private *card) +{ + unsigned char j, tuple, link, data_id, data_count; + unsigned long flags; + int i; + + enter("read_mac_address"); + + spin_lock_irqsave(&card->lock, flags); + + outl(1 << 12, card->io_port + CSR9); /* enable boot rom access */ + for (i = 0x100; i < 0x1f7; i += link + 2) { + outl(i, card->io_port + CSR10); + tuple = inl(card->io_port + CSR9) & 0xff; + outl(i + 1, card->io_port + CSR10); + link = inl(card->io_port + CSR9) & 0xff; + outl(i + 2, card->io_port + CSR10); + data_id = inl(card->io_port + CSR9) & 0xff; + outl(i + 3, card->io_port + CSR10); + data_count = inl(card->io_port + CSR9) & 0xff; + if ((tuple == 0x22) && (data_id == 0x04) && (data_count == 0x06)) { + /* + * This is it. We have the data we want. + */ + for (j = 0; j < 6; j++) { + outl(i + j + 4, card->io_port + CSR10); + card->dev->dev_addr[j] = inl(card->io_port + CSR9) & 0xff; + } + break; + } else if (link == 0) { + break; + } + } + spin_unlock_irqrestore(&card->lock, flags); +#ifdef DEBUG + for (i = 0; i < 6; i++) + printk("%c%2.2X", i ? ':' : ' ', card->dev->dev_addr[i]); + printk("\n"); +#endif + leave("read_mac_address"); +} + + +/* + tranceiver_voodoo() enables the external UTP plug thingy. + it's called voodoo as I stole this code and cannot cross-reference + it with the specification. + */ +static void tranceiver_voodoo(struct xircom_private *card) +{ + unsigned long flags; + + enter("tranceiver_voodoo"); + + /* disable all powermanagement */ + pci_write_config_dword(card->pdev, PCI_POWERMGMT, 0x0000); + + setup_descriptors(card); + + spin_lock_irqsave(&card->lock, flags); + + outl(0x0008, card->io_port + CSR15); + udelay(25); + outl(0xa8050000, card->io_port + CSR15); + udelay(25); + outl(0xa00f0000, card->io_port + CSR15); + udelay(25); + + spin_unlock_irqrestore(&card->lock, flags); + + netif_start_queue(card->dev); + leave("tranceiver_voodoo"); +} + + +static void xircom_up(struct xircom_private *card) +{ + unsigned long flags; + int i; + + enter("xircom_up"); + + /* disable all powermanagement */ + pci_write_config_dword(card->pdev, PCI_POWERMGMT, 0x0000); + + setup_descriptors(card); + + spin_lock_irqsave(&card->lock, flags); + + + enable_link_interrupt(card); + enable_transmit_interrupt(card); + enable_receive_interrupt(card); + enable_common_interrupts(card); + enable_promisc(card); + + /* The card can have received packets already, read them away now */ + for (i=0;i<NUMDESCRIPTORS;i++) + investigate_read_descriptor(card->dev,card,i,bufferoffsets[i]); + + + spin_unlock_irqrestore(&card->lock, flags); + trigger_receive(card); + trigger_transmit(card); + netif_start_queue(card->dev); + leave("xircom_up"); +} + +/* Bufferoffset is in BYTES */ +static void investigate_read_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset) +{ + int status; + + enter("investigate_read_descriptor"); + status = card->rx_buffer[4*descnr]; + + if ((status > 0)) { /* packet received */ + + /* TODO: discard error packets */ + + short pkt_len = ((status >> 16) & 0x7ff) - 4; /* minus 4, we don't want the CRC */ + struct sk_buff *skb; + + if (pkt_len > 1518) { + printk(KERN_ERR "xircom_cb: Packet length %i is bogus \n",pkt_len); + pkt_len = 1518; + } + + skb = dev_alloc_skb(pkt_len + 2); + if (skb == NULL) { + card->stats.rx_dropped++; + goto out; + } + skb->dev = dev; + skb_reserve(skb, 2); + eth_copy_and_sum(skb, (unsigned char*)&card->rx_buffer[bufferoffset / 4], pkt_len, 0); + skb_put(skb, pkt_len); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + dev->last_rx = jiffies; + card->stats.rx_packets++; + card->stats.rx_bytes += pkt_len; + + out: + /* give the buffer back to the card */ + card->rx_buffer[4*descnr] = 0x80000000; + trigger_receive(card); + } + + leave("investigate_read_descriptor"); + +} + + +/* Bufferoffset is in BYTES */ +static void investigate_write_descriptor(struct net_device *dev, struct xircom_private *card, int descnr, unsigned int bufferoffset) +{ + int status; + + enter("investigate_write_descriptor"); + + status = card->tx_buffer[4*descnr]; +#if 0 + if (status & 0x8000) { /* Major error */ + printk(KERN_ERR "Major transmit error status %x \n", status); + card->tx_buffer[4*descnr] = 0; + netif_wake_queue (dev); + } +#endif + if (status > 0) { /* bit 31 is 0 when done */ + if (card->tx_skb[descnr]!=NULL) { + card->stats.tx_bytes += card->tx_skb[descnr]->len; + dev_kfree_skb_irq(card->tx_skb[descnr]); + } + card->tx_skb[descnr] = NULL; + /* Bit 8 in the status field is 1 if there was a collision */ + if (status&(1<<8)) + card->stats.collisions++; + card->tx_buffer[4*descnr] = 0; /* descriptor is free again */ + netif_wake_queue (dev); + card->stats.tx_packets++; + } + + leave("investigate_write_descriptor"); + +} + + +static int __init xircom_init(void) +{ + pci_register_driver(&xircom_ops); + return 0; +} + +static void __exit xircom_exit(void) +{ + pci_unregister_driver(&xircom_ops); +} + +module_init(xircom_init); +module_exit(xircom_exit); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/pcmcia/xircom_cb.h linux.ac/drivers/net/pcmcia/xircom_cb.h --- linux.vanilla/drivers/net/pcmcia/xircom_cb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/pcmcia/xircom_cb.h Tue Apr 3 17:54:53 2001 @@ -0,0 +1,45 @@ +#ifndef _INCLUDE_GUARD_XIRCOM_CB_H_ +#define _INCLUDE_GUARD_XIRCOM_CB_H_ + +static int xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id); +static void xircom_remove(struct pci_dev *pdev); +static void xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int xircom_open(struct net_device *dev); +static int xircom_close(struct net_device *dev); +static struct net_device_stats *xircom_get_stats(struct net_device *dev); + + + + +static void investigate_read_descriptor(struct net_device *dev,int number, int descnr, unsigned int bufferoffset); +static void investigate_write_descriptor(struct net_device *dev,int number, int descnr, unsigned int bufferoffset); + + +static void xircom_up(int number); +static void read_mac_address(int number); +static void tranceiver_voodoo(int number); +static void initialize_card(int number); +static void trigger_transmit(int number); +static void trigger_receive(int number); +static void setup_descriptors(int number); +static void remove_descriptors(int number); +static int link_status_changed(int number); +static int packed_is_received(int number); +static int packed_is_sent(int number); +static int transmit_active(int number); +static int receive_active(int number); +static int activate_receiver(int number); +static int deactivate_receiver(int number); +static int activate_transmitter(int number); +static int deactivate_transmitter(int number); +static int enable_transmit_interrupt(int number); +static int disable_transmit_interrupt(int number); +static int disable_receive_interrupt(int number); +static int enable_receive_interrupt(int number); +static int enable_link_interrupt(int number); +static int disable_link_interrupt(int number); +static int disable_all_interrupts(int number); +static int link_status(int number); + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/pcnet32.c linux.ac/drivers/net/pcnet32.c --- linux.vanilla/drivers/net/pcnet32.c Tue Apr 3 17:32:13 2001 +++ linux.ac/drivers/net/pcnet32.c Wed Apr 4 18:27:14 2001 @@ -535,13 +535,12 @@ pcnet32_dwio_reset(ioaddr); pcnet32_wio_reset(ioaddr); - /* Important to do the check for dwio mode first. */ - if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) { - a = &pcnet32_dwio; + /* NOTE: 16-bit check is first, otherwise some older PCnet chips fail */ + if (pcnet32_wio_read_csr (ioaddr, 0) == 4 && pcnet32_wio_check (ioaddr)) { + a = &pcnet32_wio; } else { - if (pcnet32_wio_read_csr(ioaddr, 0) == 4 && - pcnet32_wio_check(ioaddr)) { - a = &pcnet32_wio; + if (pcnet32_dwio_read_csr (ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) { + a = &pcnet32_dwio; } else return -ENODEV; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/plip.c linux.ac/drivers/net/plip.c --- linux.vanilla/drivers/net/plip.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/plip.c Sat Apr 14 01:25:16 2001 @@ -1293,7 +1293,7 @@ } static int parport[PLIP_MAX] = { [0 ... PLIP_MAX-1] = -1 }; -static int timid = 0; +static int timid; MODULE_PARM(parport, "1-" __MODULE_STRING(PLIP_MAX) "i"); MODULE_PARM(timid, "1i"); @@ -1314,7 +1314,7 @@ * available to use. */ static void plip_attach (struct parport *port) { - static int i = 0; + static int i; if ((parport[0] == -1 && (!timid || !port->devices)) || plip_searchfor(parport, port->number)) { @@ -1377,7 +1377,7 @@ #ifndef MODULE -static int parport_ptr = 0; +static int parport_ptr; static int __init plip_setup(char *str) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/ppp_async.c linux.ac/drivers/net/ppp_async.c --- linux.vanilla/drivers/net/ppp_async.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/ppp_async.c Tue Apr 3 17:54:53 2001 @@ -95,7 +95,7 @@ static void async_lcp_peek(struct asyncppp *ap, unsigned char *data, int len, int inbound); -struct ppp_channel_ops async_ops = { +static struct ppp_channel_ops async_ops = { ppp_async_send, ppp_async_ioctl }; @@ -312,7 +312,7 @@ write_wakeup: ppp_asynctty_wakeup, }; -int +static int __init ppp_async_init(void) { int err; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/ppp_deflate.c linux.ac/drivers/net/ppp_deflate.c --- linux.vanilla/drivers/net/ppp_deflate.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/ppp_deflate.c Tue Apr 3 17:54:53 2001 @@ -598,7 +598,7 @@ * Module interface table *************************************************************/ -/* These are in ppp.c */ +/* These are in ppp_generic.c */ extern int ppp_register_compressor (struct compressor *cp); extern void ppp_unregister_compressor (struct compressor *cp); @@ -639,7 +639,7 @@ z_comp_stats, /* decomp_stat */ }; -int deflate_init(void) +int __init deflate_init(void) { int answer = ppp_register_compressor(&ppp_deflate); if (answer == 0) @@ -649,7 +649,7 @@ return answer; } -void deflate_cleanup(void) +void __exit deflate_cleanup(void) { ppp_unregister_compressor(&ppp_deflate); ppp_unregister_compressor(&ppp_deflate_draft); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/ppp_generic.c linux.ac/drivers/net/ppp_generic.c --- linux.vanilla/drivers/net/ppp_generic.c Sun Feb 4 18:05:30 2001 +++ linux.ac/drivers/net/ppp_generic.c Tue Apr 3 17:54:53 2001 @@ -836,7 +836,7 @@ return err; } -int +static int ppp_net_init(struct net_device *dev) { dev->hard_header_len = PPP_HDRLEN; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/ppp_synctty.c linux.ac/drivers/net/ppp_synctty.c --- linux.vanilla/drivers/net/ppp_synctty.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/ppp_synctty.c Tue Apr 3 17:54:53 2001 @@ -96,7 +96,7 @@ static void ppp_sync_input(struct syncppp *ap, const unsigned char *buf, char *flags, int count); -struct ppp_channel_ops sync_ops = { +static struct ppp_channel_ops sync_ops = { ppp_sync_send, ppp_sync_ioctl }; @@ -404,7 +404,7 @@ write_wakeup: ppp_sync_wakeup, }; -int +static int __init ppp_sync_init(void) { int err; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/pppoe.c linux.ac/drivers/net/pppoe.c --- linux.vanilla/drivers/net/pppoe.c Tue Apr 3 17:32:13 2001 +++ linux.ac/drivers/net/pppoe.c Tue Apr 3 17:54:53 2001 @@ -65,11 +65,11 @@ #define PPPOE_HASH_BITS 4 #define PPPOE_HASH_SIZE (1<<PPPOE_HASH_BITS) -int pppoe_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); -int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb); -int __pppoe_xmit(struct sock *sk, struct sk_buff *skb); +static int pppoe_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); +static int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb); +static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb); -struct proto_ops pppoe_ops; +static struct proto_ops pppoe_ops; #if 0 @@ -303,7 +303,7 @@ * Do the real work of receiving a PPPoE Session frame. * ***********************************************************************/ -int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb){ +static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb){ struct pppox_opt *po=sk->protinfo.pppox; struct pppox_opt *relay_po = NULL; @@ -382,7 +382,7 @@ * Receive wrapper called in process context. * ***********************************************************************/ -int pppoe_backlog_rcv(struct sock *sk, struct sk_buff *skb) +static int pppoe_backlog_rcv(struct sock *sk, struct sk_buff *skb) { lock_sock(sk); pppoe_rcv_core(sk, skb); @@ -428,7 +428,7 @@ -struct packet_type pppoes_ptype = { +static struct packet_type pppoes_ptype = { __constant_htons(ETH_P_PPP_SES), NULL, pppoe_rcv, @@ -436,7 +436,7 @@ NULL }; -struct packet_type pppoed_ptype = { +static struct packet_type pppoed_ptype = { __constant_htons(ETH_P_PPP_DISC), NULL, pppoe_disc_rcv, @@ -449,7 +449,7 @@ * Really kill the socket. (Called from sock_put if refcnt == 0.) * **********************************************************************/ -void pppoe_sock_destruct(struct sock *sk) +static void pppoe_sock_destruct(struct sock *sk) { if (sk->protinfo.destruct_hook) kfree(sk->protinfo.destruct_hook); @@ -508,7 +508,7 @@ return error; } -int pppoe_release(struct socket *sock) +static int pppoe_release(struct socket *sock) { struct sock *sk = sock->sk; struct pppox_opt *po; @@ -542,7 +542,7 @@ } -int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, +static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, int sockaddr_len, int flags) { struct sock *sk = sock->sk; @@ -622,7 +622,7 @@ } -int pppoe_getname(struct socket *sock, struct sockaddr *uaddr, +static int pppoe_getname(struct socket *sock, struct sockaddr *uaddr, int *usockaddr_len, int peer) { int len = sizeof(struct sockaddr_pppox); @@ -641,7 +641,7 @@ } -int pppoe_ioctl(struct socket *sock, unsigned int cmd, +static int pppoe_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; @@ -744,7 +744,7 @@ } -int pppoe_sendmsg(struct socket *sock, struct msghdr *m, +static int pppoe_sendmsg(struct socket *sock, struct msghdr *m, int total_len, struct scm_cookie *scm) { struct sk_buff *skb = NULL; @@ -821,7 +821,7 @@ * xmit function for internal use. * ***********************************************************************/ -int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) +static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) { struct net_device *dev = sk->protinfo.pppox->pppoe_dev; struct pppoe_hdr hdr; @@ -889,7 +889,7 @@ * sends PPP frame over PPPoE socket * ***********************************************************************/ -int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb) +static int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb) { struct sock *sk = (struct sock *) chan->private; return __pppoe_xmit(sk, skb); @@ -898,7 +898,7 @@ struct ppp_channel_ops pppoe_chan_ops = { pppoe_xmit , NULL }; -int pppoe_rcvmsg(struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm) +static int pppoe_rcvmsg(struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm) { struct sock *sk = sock->sk; struct sk_buff *skb = NULL; @@ -937,7 +937,7 @@ return error; } -int pppoe_proc_info(char *buffer, char **start, off_t offset, int length) +static int pppoe_proc_info(char *buffer, char **start, off_t offset, int length) { struct pppox_opt *po; int len = 0; @@ -995,7 +995,7 @@ } -struct proto_ops pppoe_ops = { +static struct proto_ops pppoe_ops = { family: AF_PPPOX, release: pppoe_release, bind: sock_no_bind, @@ -1014,13 +1014,13 @@ mmap: sock_no_mmap }; -struct pppox_proto pppoe_proto = { +static struct pppox_proto pppoe_proto = { create: pppoe_create, ioctl: pppoe_ioctl }; -int __init pppoe_init(void) +static int __init pppoe_init(void) { int err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto); @@ -1035,7 +1035,7 @@ return err; } -void __exit pppoe_exit(void) +static void __exit pppoe_exit(void) { unregister_pppox_proto(PX_PROTO_OE); dev_remove_pack(&pppoes_ptype); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/ptifddi.c linux.ac/drivers/net/ptifddi.c --- linux.vanilla/drivers/net/ptifddi.c Tue Jul 11 23:46:08 2000 +++ linux.ac/drivers/net/ptifddi.c Sat Apr 14 01:25:16 2001 @@ -16,7 +16,7 @@ #include "ptifddi_asm.h" #ifdef MODULE -static struct ptifddi *root_pti_dev = NULL; +static struct ptifddi *root_pti_dev; #endif static inline void pti_reset(struct ptifddi *pp) @@ -151,7 +151,7 @@ static inline int pti_fddi_init(struct net_device *dev, struct sbus_dev *sdev, int num) { - static unsigned version_printed = 0; + static unsigned version_printed; struct ptifddi *pp; int i; @@ -208,7 +208,7 @@ { struct sbus_bus *bus; struct sbus_dev *sdev = 0; - static int called = 0; + static int called; int cards = 0, v; if(called) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/rcpci45.c linux.ac/drivers/net/rcpci45.c --- linux.vanilla/drivers/net/rcpci45.c Tue Apr 3 17:32:13 2001 +++ linux.ac/drivers/net/rcpci45.c Sat Apr 14 01:25:16 2001 @@ -91,7 +91,7 @@ #define DEFAULT_RECV_INIT_CONTEXT 0xA17 -static U32 DriverControlWord = 0; +static U32 DriverControlWord; static void rc_timer(unsigned long); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/rrunner.c linux.ac/drivers/net/rrunner.c --- linux.vanilla/drivers/net/rrunner.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/rrunner.c Tue Apr 3 17:54:53 2001 @@ -117,6 +117,14 @@ static int probed __initdata = 0; +#if LINUX_VERSION_CODE >= 0x20400 +static struct pci_device_id rrunner_pci_tbl[] __initdata = { + { PCI_VENDOR_ID_ESSENTIAL, PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER, PCI_ANY_ID, PCI_ANY_ID, }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, rrunner_pci_tbl); +#endif /* LINUX_VERSION_CODE >= 0x20400 */ + #ifdef NEW_NETINIT int __init rr_hippi_probe (void) #else @@ -137,9 +145,6 @@ return -ENODEV; probed++; - if (!pci_present()) /* is PCI BIOS even present? */ - return -ENODEV; - version_disp = 0; while((pdev = pci_find_device(PCI_VENDOR_ID_ESSENTIAL, @@ -176,6 +181,7 @@ sprintf(rrpriv->name, "RoadRunner serial HIPPI"); dev->irq = pdev->irq; + SET_MODULE_OWNER(dev); dev->open = &rr_open; dev->hard_start_xmit = &rr_start_xmit; dev->stop = &rr_close; @@ -1183,7 +1189,6 @@ netif_start_queue(dev); - MOD_INC_USE_COUNT; return ecode; error: @@ -1348,7 +1353,6 @@ free_irq(dev->irq, dev); spin_unlock(&rrpriv->lock); - MOD_DEC_USE_COUNT; return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/saa9730.c linux.ac/drivers/net/saa9730.c --- linux.vanilla/drivers/net/saa9730.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/saa9730.c Tue Apr 3 17:54:53 2001 @@ -0,0 +1,1082 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + * + * SAA9730 ethernet driver. + * + */ + +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/delay.h> +#include <linux/etherdevice.h> +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/pci.h> + +#include <asm/addrspace.h> +#include <asm/mips-boards/prom.h> + +#include "saa9730.h" + +#ifdef LAN_SAA9730_DEBUG +int lan_saa9730_debug = LAN_SAA9730_DEBUG; +#else +int lan_saa9730_debug; +#endif + + +/* Non-zero only if the current card is a PCI with BIOS-set IRQ. */ +static unsigned int pci_irq_line = 0; + +#define INL(a) inl((unsigned long)a) +#define OUTL(x,a) outl(x,(unsigned long)a) + +static void evm_saa9730_enable_lan_int(struct lan_saa9730_private *lp) +{ + OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT, + &lp->evm_saa9730_regs->InterruptBlock1); + OUTL(INL(&lp->evm_saa9730_regs->InterruptStatus1) | EVM_LAN_INT, + &lp->evm_saa9730_regs->InterruptStatus1); + OUTL(INL(&lp->evm_saa9730_regs->InterruptEnable1) | EVM_LAN_INT | + EVM_MASTER_EN, &lp->evm_saa9730_regs->InterruptEnable1); +} +static void evm_saa9730_disable_lan_int(struct lan_saa9730_private *lp) +{ + OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT, + &lp->evm_saa9730_regs->InterruptBlock1); + OUTL(INL(&lp->evm_saa9730_regs->InterruptEnable1) & ~EVM_LAN_INT, + &lp->evm_saa9730_regs->InterruptEnable1); +} + +static void evm_saa9730_clear_lan_int(struct lan_saa9730_private *lp) +{ + OUTL(EVM_LAN_INT, &lp->evm_saa9730_regs->InterruptStatus1); +} + +static void evm_saa9730_block_lan_int(struct lan_saa9730_private *lp) +{ + OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT, + &lp->evm_saa9730_regs->InterruptBlock1); +} + +static void evm_saa9730_unblock_lan_int(struct lan_saa9730_private *lp) +{ + OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT, + &lp->evm_saa9730_regs->InterruptBlock1); +} + +static void show_saa9730_regs(struct lan_saa9730_private *lp) +{ + int i, j; + printk("TxmBufferA = %x\n", lp->TxmBuffer[0][0]); + printk("TxmBufferB = %x\n", lp->TxmBuffer[1][0]); + printk("RcvBufferA = %x\n", lp->RcvBuffer[0][0]); + printk("RcvBufferB = %x\n", lp->RcvBuffer[1][0]); + for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { + for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) { + printk("TxmBuffer[%d][%d] = %x\n", i, j, + le32_to_cpu(*(unsigned int *) + lp->TxmBuffer[i][j])); + } + } + for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { + for (j = 0; j < LAN_SAA9730_RCV_Q_SIZE; j++) { + printk("RcvBuffer[%d][%d] = %x\n", i, j, + le32_to_cpu(*(unsigned int *) + lp->RcvBuffer[i][j])); + } + } + printk("lp->evm_saa9730_regs->InterruptBlock1 = %x\n", + INL(&lp->evm_saa9730_regs->InterruptBlock1)); + printk("lp->evm_saa9730_regs->InterruptStatus1 = %x\n", + INL(&lp->evm_saa9730_regs->InterruptStatus1)); + printk("lp->evm_saa9730_regs->InterruptEnable1 = %x\n", + INL(&lp->evm_saa9730_regs->InterruptEnable1)); + printk("lp->lan_saa9730_regs->Ok2Use = %x\n", + INL(&lp->lan_saa9730_regs->Ok2Use)); + printk("lp->NextTxmBufferIndex = %x\n", lp->NextTxmBufferIndex); + printk("lp->NextTxmPacketIndex = %x\n", lp->NextTxmPacketIndex); + printk("lp->PendingTxmBufferIndex = %x\n", + lp->PendingTxmBufferIndex); + printk("lp->PendingTxmPacketIndex = %x\n", + lp->PendingTxmPacketIndex); + printk("lp->lan_saa9730_regs->LanDmaCtl = %x\n", + INL(&lp->lan_saa9730_regs->LanDmaCtl)); + printk("lp->lan_saa9730_regs->DmaStatus = %x\n", + INL(&lp->lan_saa9730_regs->DmaStatus)); + printk("lp->lan_saa9730_regs->CamCtl = %x\n", + INL(&lp->lan_saa9730_regs->CamCtl)); + printk("lp->lan_saa9730_regs->TxCtl = %x\n", + INL(&lp->lan_saa9730_regs->TxCtl)); + printk("lp->lan_saa9730_regs->TxStatus = %x\n", + INL(&lp->lan_saa9730_regs->TxStatus)); + printk("lp->lan_saa9730_regs->RxCtl = %x\n", + INL(&lp->lan_saa9730_regs->RxCtl)); + printk("lp->lan_saa9730_regs->RxStatus = %x\n", + INL(&lp->lan_saa9730_regs->RxStatus)); + for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) { + OUTL(i, &lp->lan_saa9730_regs->CamAddress); + printk("lp->lan_saa9730_regs->CamData = %x\n", + INL(&lp->lan_saa9730_regs->CamData)); + } + printk("lp->stats.tx_packets = %lx\n", lp->stats.tx_packets); + printk("lp->stats.tx_errors = %lx\n", lp->stats.tx_errors); + printk("lp->stats.tx_aborted_errors = %lx\n", + lp->stats.tx_aborted_errors); + printk("lp->stats.tx_window_errors = %lx\n", + lp->stats.tx_window_errors); + printk("lp->stats.tx_carrier_errors = %lx\n", + lp->stats.tx_carrier_errors); + printk("lp->stats.tx_fifo_errors = %lx\n", + lp->stats.tx_fifo_errors); + printk("lp->stats.tx_heartbeat_errors = %lx\n", + lp->stats.tx_heartbeat_errors); + printk("lp->stats.collisions = %lx\n", lp->stats.collisions); + + printk("lp->stats.rx_packets = %lx\n", lp->stats.rx_packets); + printk("lp->stats.rx_errors = %lx\n", lp->stats.rx_errors); + printk("lp->stats.rx_dropped = %lx\n", lp->stats.rx_dropped); + printk("lp->stats.rx_crc_errors = %lx\n", lp->stats.rx_crc_errors); + printk("lp->stats.rx_frame_errors = %lx\n", + lp->stats.rx_frame_errors); + printk("lp->stats.rx_fifo_errors = %lx\n", + lp->stats.rx_fifo_errors); + printk("lp->stats.rx_length_errors = %lx\n", + lp->stats.rx_length_errors); + + printk("lp->lan_saa9730_regs->DebugPCIMasterAddr = %x\n", + INL(&lp->lan_saa9730_regs->DebugPCIMasterAddr)); + printk("lp->lan_saa9730_regs->DebugLanTxStateMachine = %x\n", + INL(&lp->lan_saa9730_regs->DebugLanTxStateMachine)); + printk("lp->lan_saa9730_regs->DebugLanRxStateMachine = %x\n", + INL(&lp->lan_saa9730_regs->DebugLanRxStateMachine)); + printk("lp->lan_saa9730_regs->DebugLanTxFifoPointers = %x\n", + INL(&lp->lan_saa9730_regs->DebugLanTxFifoPointers)); + printk("lp->lan_saa9730_regs->DebugLanRxFifoPointers = %x\n", + INL(&lp->lan_saa9730_regs->DebugLanRxFifoPointers)); + printk("lp->lan_saa9730_regs->DebugLanCtlStateMachine = %x\n", + INL(&lp->lan_saa9730_regs->DebugLanCtlStateMachine)); +} + +static void lan_saa9730_buffer_init(struct lan_saa9730_private *lp) +{ + int i, j; + + /* Init RX buffers */ + for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { + for (j = 0; j < LAN_SAA9730_RCV_Q_SIZE; j++) { + *(unsigned int *) lp->RcvBuffer[i][j] = + cpu_to_le32(RXSF_READY << + RX_STAT_CTL_OWNER_SHF); + } + } + + /* Init TX buffers */ + for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { + for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) { + *(unsigned int *) lp->TxmBuffer[i][j] = + cpu_to_le32(TXSF_EMPTY << + TX_STAT_CTL_OWNER_SHF); + } + } +} + +static int lan_saa9730_allocate_buffers(struct lan_saa9730_private *lp) +{ + unsigned int mem_size; + void *Pa; + unsigned int i, j, RcvBufferSize, TxmBufferSize; + unsigned int buffer_start; + + /* + * Allocate all RX and TX packets in one chunk. + * The Rx and Tx packets must be PACKET_SIZE aligned. + */ + mem_size = ((LAN_SAA9730_RCV_Q_SIZE + LAN_SAA9730_TXM_Q_SIZE) * + LAN_SAA9730_PACKET_SIZE * LAN_SAA9730_BUFFERS) + + LAN_SAA9730_PACKET_SIZE; + buffer_start = + (unsigned int) kmalloc(mem_size, GFP_DMA | GFP_KERNEL); + + /* + * Set DMA buffer to kseg1 (uncached). + * Make sure to flush before using it uncached. + */ + Pa = (void *) KSEG1ADDR((buffer_start + LAN_SAA9730_PACKET_SIZE) & + ~(LAN_SAA9730_PACKET_SIZE - 1)); + dma_cache_wback_inv((unsigned long) Pa, mem_size); + + /* Initialize buffer space */ + RcvBufferSize = LAN_SAA9730_PACKET_SIZE; + TxmBufferSize = LAN_SAA9730_PACKET_SIZE; + lp->DmaRcvPackets = LAN_SAA9730_RCV_Q_SIZE; + lp->DmaTxmPackets = LAN_SAA9730_TXM_Q_SIZE; + + /* Init RX buffers */ + for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { + for (j = 0; j < LAN_SAA9730_RCV_Q_SIZE; j++) { + *(unsigned int *) Pa = + cpu_to_le32(RXSF_READY << + RX_STAT_CTL_OWNER_SHF); + lp->RcvBuffer[i][j] = (unsigned int) Pa; + Pa += RcvBufferSize; + } + } + + /* Init TX buffers */ + for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { + for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) { + *(unsigned int *) Pa = + cpu_to_le32(TXSF_EMPTY << + TX_STAT_CTL_OWNER_SHF); + lp->TxmBuffer[i][j] = (unsigned int) Pa; + Pa += TxmBufferSize; + } + } + + /* + * Set rx buffer A and rx buffer B to point to the first two buffer + * spaces. + */ + OUTL(PHYSADDR(lp->RcvBuffer[0][0]), + &lp->lan_saa9730_regs->RxBuffA); + OUTL(PHYSADDR(lp->RcvBuffer[1][0]), + &lp->lan_saa9730_regs->RxBuffB); + + /* Initialize Buffer Index */ + lp->NextRcvPacketIndex = 0; + lp->NextRcvToUseIsA = 1; + + /* Set current buffer index & next availble packet index */ + lp->NextTxmPacketIndex = 0; + lp->NextTxmBufferIndex = 0; + lp->PendingTxmPacketIndex = 0; + lp->PendingTxmBufferIndex = 0; + + /* + * Set txm_buf_a and txm_buf_b to point to the first two buffer + * space + */ + OUTL(PHYSADDR(lp->TxmBuffer[0][0]), + &lp->lan_saa9730_regs->TxBuffA); + OUTL(PHYSADDR(lp->TxmBuffer[1][0]), + &lp->lan_saa9730_regs->TxBuffB); + + /* Set packet number */ + OUTL((lp->DmaRcvPackets << PK_COUNT_RX_A_SHF) | + (lp->DmaRcvPackets << PK_COUNT_RX_B_SHF) | + (lp->DmaTxmPackets << PK_COUNT_TX_A_SHF) | + (lp->DmaTxmPackets << PK_COUNT_TX_B_SHF), + &lp->lan_saa9730_regs->PacketCount); + + return 0; +} + +static int lan_saa9730_cam_load(struct lan_saa9730_private *lp) +{ + unsigned int i; + unsigned char *NetworkAddress; + + NetworkAddress = (unsigned char *) &lp->PhysicalAddress[0][0]; + + for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) { + /* First set address to where data is written */ + OUTL(i, &lp->lan_saa9730_regs->CamAddress); + OUTL((NetworkAddress[0] << 24) | (NetworkAddress[1] << 16) + | (NetworkAddress[2] << 8) | NetworkAddress[3], + &lp->lan_saa9730_regs->CamData); + NetworkAddress += 4; + } + return 0; +} + +static int lan_saa9730_cam_init(struct net_device *dev) +{ + struct lan_saa9730_private *lp = + (struct lan_saa9730_private *) dev->priv; + unsigned int i; + + /* Copy MAC-address into all entries. */ + for (i = 0; i < LAN_SAA9730_CAM_ENTRIES; i++) { + memcpy((unsigned char *) lp->PhysicalAddress[i], + (unsigned char *) dev->dev_addr, 6); + } + + return 0; +} + +static int lan_saa9730_mii_init(struct lan_saa9730_private *lp) +{ + int i, l; + + /* Check link status, spin here till station is not busy. */ + i = 0; + while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) { + i++; + if (i > 100) { + printk("Error: lan_saa9730_mii_init: timeout\n"); + return -1; + } + udelay(1000); /* wait 1 ms. */ + } + + /* Now set the control and address register. */ + OUTL(MD_CA_BUSY | PHY_STATUS | PHY_ADDRESS << MD_CA_PHY_SHF, + &lp->lan_saa9730_regs->StationMgmtCtl); + + /* check link status, spin here till station is not busy */ + i = 0; + while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) { + i++; + if (i > 100) { + printk("Error: lan_saa9730_mii_init: timeout\n"); + return -1; + } + udelay(1000); /* wait 1 ms. */ + } + + /* Wait for 1 ms. */ + udelay(1000); + + /* Check the link status. */ + if (INL(&lp->lan_saa9730_regs->StationMgmtData) & + PHY_STATUS_LINK_UP) { + /* Link is up. */ + return 0; + } else { + /* Link is down, reset the PHY first. */ + + /* set PHY address = 'CONTROL' */ + OUTL(PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR | PHY_CONTROL, + &lp->lan_saa9730_regs->StationMgmtCtl); + + /* Wait for 1 ms. */ + udelay(1000); + + /* set 'CONTROL' = force reset and renegotiate */ + OUTL(PHY_CONTROL_RESET | PHY_CONTROL_AUTO_NEG | + PHY_CONTROL_RESTART_AUTO_NEG, + &lp->lan_saa9730_regs->StationMgmtData); + + /* Wait for 50 ms. */ + udelay(50 * 1000); + + /* set 'BUSY' to start operation */ + OUTL(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR | + PHY_CONTROL, &lp->lan_saa9730_regs->StationMgmtCtl); + + /* await completion */ + i = 0; + while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) & + MD_CA_BUSY) { + i++; + if (i > 100) { + printk + ("Error: lan_saa9730_mii_init: timeout\n"); + return -1; + } + udelay(1000); /* wait 1 ms. */ + } + + /* Wait for 1 ms. */ + udelay(1000); + + for (l = 0; l < 2; l++) { + /* set PHY address = 'STATUS' */ + OUTL(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF | + PHY_STATUS, + &lp->lan_saa9730_regs->StationMgmtCtl); + + /* await completion */ + i = 0; + while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) & + MD_CA_BUSY) { + i++; + if (i > 100) { + printk + ("Error: lan_saa9730_mii_init: timeout\n"); + return -1; + } + udelay(1000); /* wait 1 ms. */ + } + + /* wait for 3 sec. */ + udelay(3000 * 1000); + + /* check the link status */ + if (INL(&lp->lan_saa9730_regs->StationMgmtData) & + PHY_STATUS_LINK_UP) { + /* link is up */ + break; + } + } + } + + return 0; +} + +static int lan_saa9730_control_init(struct lan_saa9730_private *lp) +{ + /* Initialize DMA control register. */ + OUTL((LANMB_ANY << DMA_CTL_MAX_XFER_SHF) | + (LANEND_LITTLE << DMA_CTL_ENDIAN_SHF) | + (LAN_SAA9730_RCV_Q_INT_THRESHOLD << DMA_CTL_RX_INT_COUNT_SHF) + | DMA_CTL_RX_INT_TO_EN | DMA_CTL_RX_INT_EN | + DMA_CTL_MAC_RX_INT_EN | DMA_CTL_MAC_TX_INT_EN, + &lp->lan_saa9730_regs->LanDmaCtl); + + /* Initial MAC control register. */ + OUTL((MACCM_MII << MAC_CONTROL_CONN_SHF) | MAC_CONTROL_FULL_DUP, + &lp->lan_saa9730_regs->MacCtl); + + /* Initialize CAM control register. */ + OUTL(CAM_CONTROL_COMP_EN | CAM_CONTROL_BROAD_ACC, + &lp->lan_saa9730_regs->CamCtl); + + /* + * Initialize CAM enable register, only turn on first entry, should + * contain own addr. + */ + OUTL(0x0001, &lp->lan_saa9730_regs->CamEnable); + + /* Initialize Tx control register */ + OUTL(TX_CTL_EN_COMP, &lp->lan_saa9730_regs->TxCtl); + + /* Initialize Rcv control register */ + OUTL(RX_CTL_STRIP_CRC, &lp->lan_saa9730_regs->RxCtl); + + /* Reset DMA engine */ + OUTL(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest); + + return 0; +} + +static int lan_saa9730_stop(struct lan_saa9730_private *lp) +{ + int i; + + /* Stop DMA first */ + OUTL(INL(&lp->lan_saa9730_regs->LanDmaCtl) & + ~(DMA_CTL_EN_TX_DMA | DMA_CTL_EN_RX_DMA), + &lp->lan_saa9730_regs->LanDmaCtl); + + /* Set the SW Reset bits in DMA and MAC control registers */ + OUTL(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest); + OUTL(INL(&lp->lan_saa9730_regs->MacCtl) | MAC_CONTROL_RESET, + &lp->lan_saa9730_regs->MacCtl); + + /* + * Wait for MAC reset to have finished. The reset bit is auto cleared + * when the reset is done. + */ + i = 0; + while (INL(&lp->lan_saa9730_regs->MacCtl) & MAC_CONTROL_RESET) { + i++; + if (i > 100) { + printk + ("Error: lan_sa9730_stop: MAC reset timeout\n"); + return -1; + } + udelay(1000); /* wait 1 ms. */ + } + + return 0; +} + +static int lan_saa9730_dma_init(struct lan_saa9730_private *lp) +{ + /* Stop lan controller. */ + lan_saa9730_stop(lp); + + OUTL(LAN_SAA9730_DEFAULT_TIME_OUT_CNT, + &lp->lan_saa9730_regs->Timeout); + + return 0; +} + +static int lan_saa9730_start(struct lan_saa9730_private *lp) +{ + lan_saa9730_buffer_init(lp); + + /* Initialize Rx Buffer Index */ + lp->NextRcvPacketIndex = 0; + lp->NextRcvToUseIsA = 1; + + /* Set current buffer index & next availble packet index */ + lp->NextTxmPacketIndex = 0; + lp->NextTxmBufferIndex = 0; + lp->PendingTxmPacketIndex = 0; + lp->PendingTxmBufferIndex = 0; + + OUTL(INL(&lp->lan_saa9730_regs->LanDmaCtl) | DMA_CTL_EN_TX_DMA | + DMA_CTL_EN_RX_DMA, &lp->lan_saa9730_regs->LanDmaCtl); + + /* For Tx, turn on MAC then DMA */ + OUTL(INL(&lp->lan_saa9730_regs->TxCtl) | TX_CTL_TX_EN, + &lp->lan_saa9730_regs->TxCtl); + + /* For Rx, turn on DMA then MAC */ + OUTL(INL(&lp->lan_saa9730_regs->RxCtl) | RX_CTL_RX_EN, + &lp->lan_saa9730_regs->RxCtl); + + /* Set Ok2Use to let hardware owns the buffers */ + OUTL(OK2USE_RX_A | OK2USE_RX_B | OK2USE_TX_A | OK2USE_TX_B, + &lp->lan_saa9730_regs->Ok2Use); + + return 0; +} + +static int lan_saa9730_restart(struct lan_saa9730_private *lp) +{ + lan_saa9730_stop(lp); + lan_saa9730_start(lp); + + return 0; +} + +static int lan_saa9730_tx(struct net_device *dev) +{ + struct lan_saa9730_private *lp = + (struct lan_saa9730_private *) dev->priv; + unsigned int *pPacket; + unsigned int tx_status; + + if (lan_saa9730_debug > 5) + printk("lan_saa9730_tx interrupt\n"); + + /* Clear interrupt. */ + OUTL(DMA_STATUS_MAC_TX_INT, &lp->lan_saa9730_regs->DmaStatus); + + while (1) { + pPacket = + (unsigned int *) lp->TxmBuffer[lp-> + PendingTxmBufferIndex] + [lp->PendingTxmPacketIndex]; + + /* Get status of first packet transmitted. */ + tx_status = le32_to_cpu(*pPacket); + + /* Check ownership. */ + if ((tx_status & TX_STAT_CTL_OWNER_MSK) != + (TXSF_HWDONE << TX_STAT_CTL_OWNER_SHF)) break; + + /* Check for error. */ + if (tx_status & TX_STAT_CTL_ERROR_MSK) { + if (lan_saa9730_debug > 1) + printk("lan_saa9730_tx: tx error = %x\n", + tx_status); + + lp->stats.tx_errors++; + if (tx_status & + (TX_STATUS_EX_COLL << TX_STAT_CTL_STATUS_SHF)) + lp->stats.tx_aborted_errors++; + if (tx_status & + (TX_STATUS_LATE_COLL << + TX_STAT_CTL_STATUS_SHF)) lp->stats. + tx_window_errors++; + if (tx_status & + (TX_STATUS_L_CARR << TX_STAT_CTL_STATUS_SHF)) + lp->stats.tx_carrier_errors++; + if (tx_status & + (TX_STATUS_UNDER << TX_STAT_CTL_STATUS_SHF)) + lp->stats.tx_fifo_errors++; + if (tx_status & + (TX_STATUS_SQ_ERR << TX_STAT_CTL_STATUS_SHF)) + lp->stats.tx_heartbeat_errors++; + + lp->stats.collisions += + tx_status & TX_STATUS_TX_COLL_MSK; + } + + /* Free buffer. */ + *pPacket = + cpu_to_le32(TXSF_EMPTY << TX_STAT_CTL_OWNER_SHF); + + /* Update pending index pointer. */ + lp->PendingTxmPacketIndex++; + if (lp->PendingTxmPacketIndex >= LAN_SAA9730_TXM_Q_SIZE) { + lp->PendingTxmPacketIndex = 0; + lp->PendingTxmBufferIndex ^= 1; + } + } + + /* Make sure A and B are available to hardware. */ + OUTL(OK2USE_TX_A | OK2USE_TX_B, &lp->lan_saa9730_regs->Ok2Use); + + if (netif_queue_stopped(dev)) { + /* The tx buffer is no longer full. */ + netif_wake_queue(dev); + } + + return 0; +} + +static int lan_saa9730_rx(struct net_device *dev) +{ + struct lan_saa9730_private *lp = + (struct lan_saa9730_private *) dev->priv; + int len = 0; + struct sk_buff *skb = 0; + unsigned int rx_status; + int BufferIndex; + int PacketIndex; + unsigned int *pPacket; + unsigned char *pData; + + if (lan_saa9730_debug > 5) + printk("lan_saa9730_rx interrupt\n"); + + /* Clear receive interrupts. */ + OUTL(DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT | + DMA_STATUS_RX_TO_INT, &lp->lan_saa9730_regs->DmaStatus); + + /* Address next packet */ + if (lp->NextRcvToUseIsA) + BufferIndex = 0; + else + BufferIndex = 1; + PacketIndex = lp->NextRcvPacketIndex; + pPacket = (unsigned int *) lp->RcvBuffer[BufferIndex][PacketIndex]; + rx_status = le32_to_cpu(*pPacket); + + /* Process each packet. */ + while ((rx_status & RX_STAT_CTL_OWNER_MSK) == + (RXSF_HWDONE << RX_STAT_CTL_OWNER_SHF)) { + /* Check the rx status. */ + if (rx_status & (RX_STATUS_GOOD << RX_STAT_CTL_STATUS_SHF)) { + /* Received packet is good. */ + len = (rx_status & RX_STAT_CTL_LENGTH_MSK) >> + RX_STAT_CTL_LENGTH_SHF; + + pData = (unsigned char *) pPacket; + pData += 4; + skb = dev_alloc_skb(len + 2); + if (skb == 0) { + printk + ("%s: Memory squeeze, deferring packet.\n", + dev->name); + lp->stats.rx_dropped++; + } else { + lp->stats.rx_bytes += len; + lp->stats.rx_packets++; + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align */ + skb_put(skb, len); /* make room */ + eth_copy_and_sum(skb, + (unsigned char *) pData, + len, 0); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + } + } else { + /* We got an error packet. */ + if (lan_saa9730_debug > 2) + printk + ("lan_saa9730_rx: We got an error packet = %x\n", + rx_status); + + lp->stats.rx_errors++; + if (rx_status & + (RX_STATUS_CRC_ERR << RX_STAT_CTL_STATUS_SHF)) + lp->stats.rx_crc_errors++; + if (rx_status & + (RX_STATUS_ALIGN_ERR << + RX_STAT_CTL_STATUS_SHF)) lp->stats. + rx_frame_errors++; + if (rx_status & + (RX_STATUS_OVERFLOW << RX_STAT_CTL_STATUS_SHF)) + lp->stats.rx_fifo_errors++; + if (rx_status & + (RX_STATUS_LONG_ERR << RX_STAT_CTL_STATUS_SHF)) + lp->stats.rx_length_errors++; + } + + /* Indicate we have processed the buffer. */ + *pPacket = + cpu_to_le32(RXSF_READY << RX_STAT_CTL_OWNER_SHF); + + /* Go to next packet in sequence. */ + lp->NextRcvPacketIndex++; + if (lp->NextRcvPacketIndex >= LAN_SAA9730_RCV_Q_SIZE) { + lp->NextRcvPacketIndex = 0; + if (BufferIndex) { + lp->NextRcvToUseIsA = 1; + } else { + lp->NextRcvToUseIsA = 0; + } + } + OUTL(OK2USE_RX_A | OK2USE_RX_B, + &lp->lan_saa9730_regs->Ok2Use); + + /* Address next packet */ + if (lp->NextRcvToUseIsA) + BufferIndex = 0; + else + BufferIndex = 1; + PacketIndex = lp->NextRcvPacketIndex; + pPacket = + (unsigned int *) lp-> + RcvBuffer[BufferIndex][PacketIndex]; + rx_status = le32_to_cpu(*pPacket); + } + + /* Make sure A and B are available to hardware. */ + OUTL(OK2USE_RX_A | OK2USE_RX_B, &lp->lan_saa9730_regs->Ok2Use); + + return 0; +} + +static void lan_saa9730_interrupt(const int irq, void *dev_id, + struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct lan_saa9730_private *lp = + (struct lan_saa9730_private *) dev->priv; + + if (lan_saa9730_debug > 5) + printk("lan_saa9730_interrupt\n"); + + /* Disable the EVM LAN interrupt. */ + evm_saa9730_block_lan_int(lp); + + /* Clear the EVM LAN interrupt. */ + evm_saa9730_clear_lan_int(lp); + + /* Service pending transmit interrupts. */ + if (INL(&lp->lan_saa9730_regs->DmaStatus) & DMA_STATUS_MAC_TX_INT) + lan_saa9730_tx(dev); + + /* Service pending receive interrupts. */ + if (INL(&lp->lan_saa9730_regs->DmaStatus) & + (DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT | + DMA_STATUS_RX_TO_INT)) lan_saa9730_rx(dev); + + /* Enable the EVM LAN interrupt. */ + evm_saa9730_unblock_lan_int(lp); + + return; +} + +static int lan_saa9730_open_fail(struct net_device *dev) +{ + return -ENODEV; +} + +static int lan_saa9730_open(struct net_device *dev) +{ + struct lan_saa9730_private *lp = + (struct lan_saa9730_private *) dev->priv; + + /* Associate IRQ with lan_saa9730_interrupt */ + if (request_irq(dev->irq, &lan_saa9730_interrupt, 0, "SAA9730 Eth", + dev)) { + printk("lan_saa9730_open: Can't get irq %d\n", dev->irq); + return -EAGAIN; + } + + /* Enable the Lan interrupt in the event manager. */ + evm_saa9730_enable_lan_int(lp); + + /* Start the LAN controller */ + if (lan_saa9730_start(lp)) + return -1; + + netif_start_queue(dev); + + return 0; +} + +static int lan_saa9730_write(struct lan_saa9730_private *lp, + struct sk_buff *skb, int skblen) +{ + unsigned char *pbData = skb->data; + unsigned int len = skblen; + unsigned char *pbPacketData; + unsigned int tx_status; + int BufferIndex; + int PacketIndex; + + if (lan_saa9730_debug > 5) + printk("lan_saa9730_write: skb=%08x\n", + (unsigned int) skb); + + BufferIndex = lp->NextTxmBufferIndex; + PacketIndex = lp->NextTxmPacketIndex; + + tx_status = + le32_to_cpu(*(unsigned int *) lp-> + TxmBuffer[BufferIndex][PacketIndex]); + if ((tx_status & TX_STAT_CTL_OWNER_MSK) != + (TXSF_EMPTY << TX_STAT_CTL_OWNER_SHF)) { + if (lan_saa9730_debug > 4) + printk + ("lan_saa9730_write: Tx buffer not available: tx_status = %x\n", + tx_status); + return -1; + } + + lp->NextTxmPacketIndex++; + if (lp->NextTxmPacketIndex >= LAN_SAA9730_TXM_Q_SIZE) { + lp->NextTxmPacketIndex = 0; + lp->NextTxmBufferIndex ^= 1; + } + + pbPacketData = + (unsigned char *) lp->TxmBuffer[BufferIndex][PacketIndex]; + pbPacketData += 4; + + /* copy the bits */ + memcpy(pbPacketData, pbData, len); + + /* Set transmit status for hardware */ + *(unsigned int *) lp->TxmBuffer[BufferIndex][PacketIndex] = + cpu_to_le32((TXSF_READY << TX_STAT_CTL_OWNER_SHF) | + (TX_STAT_CTL_INT_AFTER_TX << TX_STAT_CTL_FRAME_SHF) + | (len << TX_STAT_CTL_LENGTH_SHF)); + + /* Set hardware tx buffer. */ + OUTL(OK2USE_TX_A | OK2USE_TX_B, &lp->lan_saa9730_regs->Ok2Use); + + return 0; +} + +static void lan_saa9730_tx_timeout(struct net_device *dev) +{ + struct lan_saa9730_private *lp = + (struct lan_saa9730_private *) dev->priv; + + /* Transmitter timeout, serious problems */ + lp->stats.tx_errors++; + printk("%s: transmit timed out, reset\n", dev->name); + /*show_saa9730_regs(lp); */ + lan_saa9730_restart(lp); + + dev->trans_start = jiffies; + netif_start_queue(dev); +} + +static int lan_saa9730_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct lan_saa9730_private *lp = + (struct lan_saa9730_private *) dev->priv; + unsigned long flags; + int skblen; + int len; + + if (lan_saa9730_debug > 4) + printk("Send packet: skb=%08x\n", (unsigned int) skb); + + skblen = skb->len; + save_and_cli(flags); + len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; + + if (lan_saa9730_write(lp, skb, skblen)) { + restore_flags(flags); + printk + ("Error when writing packet to controller: skb=%08x\n", + (unsigned int) skb); + netif_stop_queue(dev); + return -1; + } + + lp->stats.tx_bytes += len; + lp->stats.tx_packets++; + + dev->trans_start = jiffies; + netif_start_queue(dev); + dev_kfree_skb(skb); + + restore_flags(flags); + + return 0; +} + +static int lan_saa9730_close(struct net_device *dev) +{ + struct lan_saa9730_private *lp = + (struct lan_saa9730_private *) dev->priv; + + if (lan_saa9730_debug > 1) + printk("lan_saa9730_close:\n"); + + netif_stop_queue(dev); + + /* Disable the Lan interrupt in the event manager. */ + evm_saa9730_disable_lan_int(lp); + + /* Stop the controller */ + if (lan_saa9730_stop(lp)) + return -1; + + free_irq(dev->irq, (void *) dev); + + return 0; +} + +static struct net_device_stats *lan_saa9730_get_stats(struct net_device + *dev) +{ + struct lan_saa9730_private *lp = + (struct lan_saa9730_private *) dev->priv; + + return &lp->stats; +} + +static void lan_saa9730_set_multicast(struct net_device *dev) +{ + struct lan_saa9730_private *lp = + (struct lan_saa9730_private *) dev->priv; + + /* Stop the controller */ + lan_saa9730_stop(lp); + + if (dev->flags & IFF_PROMISC) { + /* accept all packets */ + OUTL(CAM_CONTROL_COMP_EN | CAM_CONTROL_STATION_ACC | + CAM_CONTROL_GROUP_ACC | CAM_CONTROL_BROAD_ACC, + &lp->lan_saa9730_regs->CamCtl); + } else { + if (dev->flags & IFF_ALLMULTI) { + /* accept all multicast packets */ + OUTL(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC | + CAM_CONTROL_BROAD_ACC, + &lp->lan_saa9730_regs->CamCtl); + } else { + /* + * Will handle the multicast stuff later. -carstenl + */ + } + } + + lan_saa9730_restart(lp); +} + +static int lan_saa9730_init(struct net_device *dev, int ioaddr, int irq) +{ + struct lan_saa9730_private *lp; + unsigned char ethernet_addr[6]; + + dev = init_etherdev(dev, 0); + + dev->open = lan_saa9730_open_fail; + if (get_ethernet_addr(ethernet_addr)) + return -1; + + memcpy(dev->dev_addr, ethernet_addr, 6); + dev->base_addr = ioaddr; + dev->irq = irq; + + /* + * Make certain the data structures used by the controller are aligned + * and DMAble. + */ + lp = (struct lan_saa9730_private *) (((unsigned long) + kmalloc(sizeof(*lp) + 7, + GFP_DMA | GFP_KERNEL) + + 7) & ~7); + + dev->priv = lp; + memset(lp, 0, sizeof(*lp)); + + /* Set SAA9730 LAN base address. */ + lp->lan_saa9730_regs = (t_lan_saa9730_regmap *) (ioaddr + + SAA9730_LAN_REGS_ADDR); + + /* Set SAA9730 EVM base address. */ + lp->evm_saa9730_regs = (t_evm_saa9730_regmap *) (ioaddr + + SAA9730_EVM_REGS_ADDR); + + /* Allocate LAN RX/TX frame buffer space. */ + if (lan_saa9730_allocate_buffers(lp)) + return -1; + + /* Stop LAN controller. */ + if (lan_saa9730_stop(lp)) + return -1; + + /* Initialize CAM registers. */ + if (lan_saa9730_cam_init(dev)) + return -1; + + /* Initialize MII registers. */ + if (lan_saa9730_mii_init(lp)) + return -1; + + /* Initialize control registers. */ + if (lan_saa9730_control_init(lp)) + return -1; + + /* Load CAM registers. */ + if (lan_saa9730_cam_load(lp)) + return -1; + + /* Initialize DMA context registers. */ + if (lan_saa9730_dma_init(lp)) + return -1; + + dev->open = lan_saa9730_open; + dev->hard_start_xmit = lan_saa9730_start_xmit; + dev->stop = lan_saa9730_close; + dev->get_stats = lan_saa9730_get_stats; + dev->set_multicast_list = lan_saa9730_set_multicast; + dev->tx_timeout = lan_saa9730_tx_timeout; + dev->watchdog_timeo = (HZ >> 1); + dev->dma = 0; + + return 0; +} + + +static int __init saa9730_probe(void) +{ + struct net_device *dev = NULL; + + if (pci_present()) { + struct pci_dev *pdev = NULL; + if (lan_saa9730_debug > 1) + printk + ("saa9730.c: PCI bios is present, checking for devices...\n"); + + while ((pdev = pci_find_device(PCI_VENDOR_ID_PHILIPS, + PCI_DEVICE_ID_PHILIPS_SAA9730, + pdev))) { + unsigned int pci_ioaddr; + + pci_irq_line = pdev->irq; + /* LAN base address in located at BAR 1. */ + + pci_ioaddr = pci_resource_start(pdev, 1); + pci_set_master(pdev); + + printk("Found SAA9730 (PCI) at %#x, irq %d.\n", + pci_ioaddr, pci_irq_line); + if (!lan_saa9730_init + (dev, pci_ioaddr, pci_irq_line)) return 0; + else + printk("Lan init failed.\n"); + } + } + + return -ENODEV; +} + +module_init(saa9730_probe); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/saa9730.h linux.ac/drivers/net/saa9730.h --- linux.vanilla/drivers/net/saa9730.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/saa9730.h Tue Apr 3 17:54:53 2001 @@ -0,0 +1,370 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + * + * SAA9730 ethernet driver description. + * + */ +#ifndef _SAA9730_H +#define _SAA9730_H + + +/* Number of 6-byte entries in the CAM. */ +#define LAN_SAA9730_CAM_ENTRIES 10 +#define LAN_SAA9730_CAM_DWORDS ((LAN_SAA9730_CAM_ENTRIES*6)/4) + +/* TX and RX packet size: fixed to 2048 bytes, according to HW requirements. */ +#define LAN_SAA9730_PACKET_SIZE 2048 + +/* + * Number of TX buffers = number of RX buffers = 2, which is fixed according + * to HW requirements. + */ +#define LAN_SAA9730_BUFFERS 2 + +/* Number of RX packets per RX buffer. */ +#define LAN_SAA9730_RCV_Q_SIZE 15 + +/* Number of TX packets per TX buffer. */ +#define LAN_SAA9730_TXM_Q_SIZE 15 + +/* + * We get an interrupt for each LAN_SAA9730_DEFAULT_RCV_Q_INT_THRESHOLD + * packets received. + * If however we receive less than LAN_SAA9730_DEFAULT_RCV_Q_INT_THRESHOLD + * packets, the hardware can timeout after a certain time and still tell + * us packets have arrived. + * The timeout value in unit of 32 PCI clocks (33Mhz). + * The value 200 approximates 0.0002 seconds. + */ +#define LAN_SAA9730_RCV_Q_INT_THRESHOLD 1 +#define LAN_SAA9730_DEFAULT_TIME_OUT_CNT 10 + +#define RXSF_NDIS 0 +#define RXSF_READY 2 +#define RXSF_HWDONE 3 + +#define TXSF_EMPTY 0 +#define TXSF_READY 2 +#define TXSF_HWDONE 3 + +#define LANEND_LITTLE 0 +#define LANEND_BIG_2143 1 +#define LANEND_BIG_4321 2 + +#define LANMB_ANY 0 +#define LANMB_8 1 +#define LANMB_32 2 +#define LANMB_64 3 + +#define MACCM_AUTOMATIC 0 +#define MACCM_10MB 1 +#define MACCM_MII 2 + +/* + * PHY definitions for Basic registers of QS6612 (used on MIPS ATLAS board) + */ +#define PHY_CONTROL 0x0 +#define PHY_STATUS 0x1 +#define PHY_STATUS_LINK_UP 0x4 +#define PHY_CONTROL_RESET 0x8000 +#define PHY_CONTROL_AUTO_NEG 0x1000 +#define PHY_CONTROL_RESTART_AUTO_NEG 0x0200 +#define PHY_ADDRESS 0x0 + +/* PK_COUNT register. */ +#define PK_COUNT_TX_A_SHF 24 +#define PK_COUNT_TX_A_MSK (0xff << PK_COUNT_TX_A_SHF) +#define PK_COUNT_TX_B_SHF 16 +#define PK_COUNT_TX_B_MSK (0xff << PK_COUNT_TX_B_SHF) +#define PK_COUNT_RX_A_SHF 8 +#define PK_COUNT_RX_A_MSK (0xff << PK_COUNT_RX_A_SHF) +#define PK_COUNT_RX_B_SHF 0 +#define PK_COUNT_RX_B_MSK (0xff << PK_COUNT_RX_B_SHF) + +/* OK2USE register. */ +#define OK2USE_TX_A 0x8 +#define OK2USE_TX_B 0x4 +#define OK2USE_RX_A 0x2 +#define OK2USE_RX_B 0x1 + +/* LAN DMA CONTROL register. */ +#define DMA_CTL_BLK_INT 0x80000000 +#define DMA_CTL_MAX_XFER_SHF 18 +#define DMA_CTL_MAX_XFER_MSK (0x3 << LAN_DMA_CTL_MAX_XFER_SHF) +#define DMA_CTL_ENDIAN_SHF 16 +#define DMA_CTL_ENDIAN_MSK (0x3 << LAN_DMA_CTL_ENDIAN_SHF) +#define DMA_CTL_RX_INT_COUNT_SHF 8 +#define DMA_CTL_RX_INT_COUNT_MSK (0xff << LAN_DMA_CTL_RX_INT_COUNT_SHF) +#define DMA_CTL_EN_TX_DMA 0x00000080 +#define DMA_CTL_EN_RX_DMA 0x00000040 +#define DMA_CTL_RX_INT_BUFFUL_EN 0x00000020 +#define DMA_CTL_RX_INT_TO_EN 0x00000010 +#define DMA_CTL_RX_INT_EN 0x00000008 +#define DMA_CTL_TX_INT_EN 0x00000004 +#define DMA_CTL_MAC_TX_INT_EN 0x00000002 +#define DMA_CTL_MAC_RX_INT_EN 0x00000001 + +/* DMA STATUS register. */ +#define DMA_STATUS_BAD_ADDR_SHF 16 +#define DMA_STATUS_BAD_ADDR_MSK (0xf << DMA_STATUS_BAD_ADDR_SHF) +#define DMA_STATUS_RX_PKTS_RECEIVED_SHF 8 +#define DMA_STATUS_RX_PKTS_RECEIVED_MSK (0xff << DMA_STATUS_RX_PKTS_RECEIVED_SHF) +#define DMA_STATUS_TX_EN_SYNC 0x00000080 +#define DMA_STATUS_RX_BUF_A_FUL 0x00000040 +#define DMA_STATUS_RX_BUF_B_FUL 0x00000020 +#define DMA_STATUS_RX_TO_INT 0x00000010 +#define DMA_STATUS_RX_INT 0x00000008 +#define DMA_STATUS_TX_INT 0x00000004 +#define DMA_STATUS_MAC_TX_INT 0x00000002 +#define DMA_STATUS_MAC_RX_INT 0x00000001 + +/* DMA TEST/PANIC SWITHES register. */ +#define DMA_TEST_LOOPBACK 0x01000000 +#define DMA_TEST_SW_RESET 0x00000001 + +/* MAC CONTROL register. */ +#define MAC_CONTROL_EN_MISS_ROLL 0x00002000 +#define MAC_CONTROL_MISS_ROLL 0x00000400 +#define MAC_CONTROL_LOOP10 0x00000080 +#define MAC_CONTROL_CONN_SHF 5 +#define MAC_CONTROL_CONN_MSK (0x3 << MAC_CONTROL_CONN_SHF) +#define MAC_CONTROL_MAC_LOOP 0x00000010 +#define MAC_CONTROL_FULL_DUP 0x00000008 +#define MAC_CONTROL_RESET 0x00000004 +#define MAC_CONTROL_HALT_IMM 0x00000002 +#define MAC_CONTROL_HALT_REQ 0x00000001 + +/* CAM CONTROL register. */ +#define CAM_CONTROL_COMP_EN 0x00000010 +#define CAM_CONTROL_NEG_CAM 0x00000008 +#define CAM_CONTROL_BROAD_ACC 0x00000004 +#define CAM_CONTROL_GROUP_ACC 0x00000002 +#define CAM_CONTROL_STATION_ACC 0x00000001 + +/* TRANSMIT CONTROL register. */ +#define TX_CTL_EN_COMP 0x00004000 +#define TX_CTL_EN_TX_PAR 0x00002000 +#define TX_CTL_EN_LATE_COLL 0x00001000 +#define TX_CTL_EN_EX_COLL 0x00000800 +#define TX_CTL_EN_L_CARR 0x00000400 +#define TX_CTL_EN_EX_DEFER 0x00000200 +#define TX_CTL_EN_UNDER 0x00000100 +#define TX_CTL_MII10 0x00000080 +#define TX_CTL_SD_PAUSE 0x00000040 +#define TX_CTL_NO_EX_DEF0 0x00000020 +#define TX_CTL_F_BACK 0x00000010 +#define TX_CTL_NO_CRC 0x00000008 +#define TX_CTL_NO_PAD 0x00000004 +#define TX_CTL_TX_HALT 0x00000002 +#define TX_CTL_TX_EN 0x00000001 + +/* TRANSMIT STATUS register. */ +#define TX_STATUS_SQ_ERR 0x00010000 +#define TX_STATUS_TX_HALTED 0x00008000 +#define TX_STATUS_COMP 0x00004000 +#define TX_STATUS_TX_PAR 0x00002000 +#define TX_STATUS_LATE_COLL 0x00001000 +#define TX_STATUS_TX10_STAT 0x00000800 +#define TX_STATUS_L_CARR 0x00000400 +#define TX_STATUS_EX_DEFER 0x00000200 +#define TX_STATUS_UNDER 0x00000100 +#define TX_STATUS_IN_TX 0x00000080 +#define TX_STATUS_PAUSED 0x00000040 +#define TX_STATUS_TX_DEFERRED 0x00000020 +#define TX_STATUS_EX_COLL 0x00000010 +#define TX_STATUS_TX_COLL_SHF 0 +#define TX_STATUS_TX_COLL_MSK (0xf << TX_STATUS_TX_COLL_SHF) + +/* RECEIVE CONTROL register. */ +#define RX_CTL_EN_GOOD 0x00004000 +#define RX_CTL_EN_RX_PAR 0x00002000 +#define RX_CTL_EN_LONG_ERR 0x00000800 +#define RX_CTL_EN_OVER 0x00000400 +#define RX_CTL_EN_CRC_ERR 0x00000200 +#define RX_CTL_EN_ALIGN 0x00000100 +#define RX_CTL_IGNORE_CRC 0x00000040 +#define RX_CTL_PASS_CTL 0x00000020 +#define RX_CTL_STRIP_CRC 0x00000010 +#define RX_CTL_SHORT_EN 0x00000008 +#define RX_CTL_LONG_EN 0x00000004 +#define RX_CTL_RX_HALT 0x00000002 +#define RX_CTL_RX_EN 0x00000001 + +/* RECEIVE STATUS register. */ +#define RX_STATUS_RX_HALTED 0x00008000 +#define RX_STATUS_GOOD 0x00004000 +#define RX_STATUS_RX_PAR 0x00002000 +#define RX_STATUS_LONG_ERR 0x00000800 +#define RX_STATUS_OVERFLOW 0x00000400 +#define RX_STATUS_CRC_ERR 0x00000200 +#define RX_STATUS_ALIGN_ERR 0x00000100 +#define RX_STATUS_RX10_STAT 0x00000080 +#define RX_STATUS_INT_RX 0x00000040 +#define RX_STATUS_CTL_RECD 0x00000020 + +/* MD_CA register. */ +#define MD_CA_PRE_SUP 0x00001000 +#define MD_CA_BUSY 0x00000800 +#define MD_CA_WR 0x00000400 +#define MD_CA_PHY_SHF 5 +#define MD_CA_PHY_MSK (0x1f << MD_CA_PHY_SHF) +#define MD_CA_ADDR_SHF 0 +#define MD_CA_ADDR_MSK (0x1f << MD_CA_ADDR_SHF) + +/* Tx Status/Control. */ +#define TX_STAT_CTL_OWNER_SHF 30 +#define TX_STAT_CTL_OWNER_MSK (0x3 << TX_STAT_CTL_OWNER_SHF) +#define TX_STAT_CTL_FRAME_SHF 27 +#define TX_STAT_CTL_FRAME_MSK (0x7 << TX_STAT_CTL_FRAME_SHF) +#define TX_STAT_CTL_STATUS_SHF 11 +#define TX_STAT_CTL_STATUS_MSK (0x1ffff << TX_STAT_CTL_STATUS_SHF) +#define TX_STAT_CTL_LENGTH_SHF 0 +#define TX_STAT_CTL_LENGTH_MSK (0x7ff << TX_STAT_CTL_LENGTH_SHF) + +#define TX_STAT_CTL_ERROR_MSK ((TX_STATUS_SQ_ERR | \ + TX_STATUS_TX_HALTED | \ + TX_STATUS_TX_PAR | \ + TX_STATUS_LATE_COLL | \ + TX_STATUS_L_CARR | \ + TX_STATUS_EX_DEFER | \ + TX_STATUS_UNDER | \ + TX_STATUS_PAUSED | \ + TX_STATUS_TX_DEFERRED | \ + TX_STATUS_EX_COLL | \ + TX_STATUS_TX_COLL_MSK) \ + << TX_STAT_CTL_STATUS_SHF) +#define TX_STAT_CTL_INT_AFTER_TX 0x4 + +/* Rx Status/Control. */ +#define RX_STAT_CTL_OWNER_SHF 30 +#define RX_STAT_CTL_OWNER_MSK (0x3 << RX_STAT_CTL_OWNER_SHF) +#define RX_STAT_CTL_STATUS_SHF 11 +#define RX_STAT_CTL_STATUS_MSK (0xffff << RX_STAT_CTL_STATUS_SHF) +#define RX_STAT_CTL_LENGTH_SHF 0 +#define RX_STAT_CTL_LENGTH_MSK (0x7ff << RX_STAT_CTL_LENGTH_SHF) + + + +/* The SAA9730 (LAN) controller register map, as seen via the PCI-bus. */ +#define SAA9730_LAN_REGS_ADDR 0x20400 + +struct lan_saa9730_regmap { + volatile unsigned int TxBuffA; /* 0x20400 */ + volatile unsigned int TxBuffB; /* 0x20404 */ + volatile unsigned int RxBuffA; /* 0x20408 */ + volatile unsigned int RxBuffB; /* 0x2040c */ + volatile unsigned int PacketCount; /* 0x20410 */ + volatile unsigned int Ok2Use; /* 0x20414 */ + volatile unsigned int LanDmaCtl; /* 0x20418 */ + volatile unsigned int Timeout; /* 0x2041c */ + volatile unsigned int DmaStatus; /* 0x20420 */ + volatile unsigned int DmaTest; /* 0x20424 */ + volatile unsigned char filler20428[0x20430 - 0x20428]; + volatile unsigned int PauseCount; /* 0x20430 */ + volatile unsigned int RemotePauseCount; /* 0x20434 */ + volatile unsigned char filler20438[0x20440 - 0x20438]; + volatile unsigned int MacCtl; /* 0x20440 */ + volatile unsigned int CamCtl; /* 0x20444 */ + volatile unsigned int TxCtl; /* 0x20448 */ + volatile unsigned int TxStatus; /* 0x2044c */ + volatile unsigned int RxCtl; /* 0x20450 */ + volatile unsigned int RxStatus; /* 0x20454 */ + volatile unsigned int StationMgmtData; /* 0x20458 */ + volatile unsigned int StationMgmtCtl; /* 0x2045c */ + volatile unsigned int CamAddress; /* 0x20460 */ + volatile unsigned int CamData; /* 0x20464 */ + volatile unsigned int CamEnable; /* 0x20468 */ + volatile unsigned char filler2046c[0x20500 - 0x2046c]; + volatile unsigned int DebugPCIMasterAddr; /* 0x20500 */ + volatile unsigned int DebugLanTxStateMachine; /* 0x20504 */ + volatile unsigned int DebugLanRxStateMachine; /* 0x20508 */ + volatile unsigned int DebugLanTxFifoPointers; /* 0x2050c */ + volatile unsigned int DebugLanRxFifoPointers; /* 0x20510 */ + volatile unsigned int DebugLanCtlStateMachine; /* 0x20514 */ +}; +typedef volatile struct lan_saa9730_regmap t_lan_saa9730_regmap; + + +/* EVM interrupt control registers. */ +#define EVM_LAN_INT 0x00010000 +#define EVM_MASTER_EN 0x00000001 + +/* The SAA9730 (EVM) controller register map, as seen via the PCI-bus. */ +#define SAA9730_EVM_REGS_ADDR 0x02000 + +struct evm_saa9730_regmap { + volatile unsigned int InterruptStatus1; /* 0x2000 */ + volatile unsigned int InterruptEnable1; /* 0x2004 */ + volatile unsigned int InterruptMonitor1; /* 0x2008 */ + volatile unsigned int Counter; /* 0x200c */ + volatile unsigned int CounterThreshold; /* 0x2010 */ + volatile unsigned int CounterControl; /* 0x2014 */ + volatile unsigned int GpioControl1; /* 0x2018 */ + volatile unsigned int InterruptStatus2; /* 0x201c */ + volatile unsigned int InterruptEnable2; /* 0x2020 */ + volatile unsigned int InterruptMonitor2; /* 0x2024 */ + volatile unsigned int GpioControl2; /* 0x2028 */ + volatile unsigned int InterruptBlock1; /* 0x202c */ + volatile unsigned int InterruptBlock2; /* 0x2030 */ +}; +typedef volatile struct evm_saa9730_regmap t_evm_saa9730_regmap; + + +struct lan_saa9730_private { + /* Pointer for the SAA9730 LAN controller register set. */ + t_lan_saa9730_regmap *lan_saa9730_regs; + + /* Pointer to the SAA9730 EVM register. */ + t_evm_saa9730_regmap *evm_saa9730_regs; + + /* TRUE if the next buffer to write is RxBuffA, FALSE if RxBuffB. */ + unsigned char NextRcvToUseIsA; + /* Rcv buffer Index. */ + unsigned char NextRcvPacketIndex; + + /* Index of next packet to use in that buffer. */ + unsigned char NextTxmPacketIndex; + /* Next buffer index. */ + unsigned char NextTxmBufferIndex; + + /* Index of first pending packet ready to send. */ + unsigned char PendingTxmPacketIndex; + /* Pending buffer index. */ + unsigned char PendingTxmBufferIndex; + + unsigned char DmaRcvPackets; + unsigned char DmaTxmPackets; + + unsigned char RcvAIndex; /* index into RcvBufferSpace[] for Blk A */ + unsigned char RcvBIndex; /* index into RcvBufferSpace[] for Blk B */ + + unsigned int + TxmBuffer[LAN_SAA9730_BUFFERS][LAN_SAA9730_TXM_Q_SIZE]; + unsigned int + RcvBuffer[LAN_SAA9730_BUFFERS][LAN_SAA9730_RCV_Q_SIZE]; + unsigned int TxBufferFree[LAN_SAA9730_BUFFERS]; + + unsigned char PhysicalAddress[LAN_SAA9730_CAM_ENTRIES][6]; + + struct net_device_stats stats; +}; + +#endif /* _SAA9730_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/sb1000.c linux.ac/drivers/net/sb1000.c --- linux.vanilla/drivers/net/sb1000.c Tue Apr 3 17:32:13 2001 +++ linux.ac/drivers/net/sb1000.c Sun Apr 15 23:00:44 2001 @@ -191,7 +191,7 @@ ioaddr[0]=idev->resource[0].start; ioaddr[1]=idev->resource[1].start; - irq = idev->irq; + irq = idev->irq_resource[0].start; /* check I/O base and IRQ */ if (dev->base_addr != 0 && dev->base_addr != ioaddr[0]) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/setup.c linux.ac/drivers/net/setup.c --- linux.vanilla/drivers/net/setup.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/setup.c Mon Apr 9 23:25:02 2001 @@ -10,7 +10,6 @@ #include <linux/netlink.h> extern int slip_init_ctrl_dev(void); -extern int strip_init_ctrl_dev(void); extern int x25_asy_init_ctrl_dev(void); extern int dmascc_init(void); @@ -23,13 +22,13 @@ extern int scc_enet_init(void); extern int fec_enet_init(void); extern int dlci_setup(void); -extern int lapbeth_init(void); extern int sdla_setup(void); extern int sdla_c_setup(void); extern int comx_init(void); extern int lmc_setup(void); extern int madgemc_probe(void); +extern int uml_net_probe(void); /* Pad device name to IFNAMSIZ=16. F.e. __PAD6 is string of 9 zeros. */ #define __PAD6 "\0\0\0\0\0\0\0\0\0" @@ -64,9 +63,6 @@ #if defined(CONFIG_SDLA) {sdla_c_setup, 0}, #endif -#if defined(CONFIG_LAPBETHER) - {lapbeth_init, 0}, -#endif #if defined(CONFIG_ARCNET) {arcnet_init, 0}, #endif @@ -107,6 +103,10 @@ #ifdef CONFIG_MADGEMC {madgemc_probe, 0}, #endif +#ifdef CONFIG_NET_UM_ETH + {uml_net_probe, 0}, +#endif + {NULL, 0}, }; @@ -139,9 +139,6 @@ #endif #if defined(CONFIG_X25_ASY) x25_asy_init_ctrl_dev(); -#endif -#if defined(CONFIG_STRIP) - strip_init_ctrl_dev(); #endif } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/sgiseeq.c linux.ac/drivers/net/sgiseeq.c --- linux.vanilla/drivers/net/sgiseeq.c Tue Apr 3 17:32:13 2001 +++ linux.ac/drivers/net/sgiseeq.c Sat Apr 14 01:25:16 2001 @@ -206,7 +206,7 @@ void sgiseeq_dump_rings(void) { - static int once = 0; + static int once; struct sgiseeq_rx_desc *r = gpriv->srings.rx_desc; struct sgiseeq_tx_desc *t = gpriv->srings.tx_desc; volatile struct hpc3_ethregs *hregs = gpriv->hregs; @@ -611,7 +611,7 @@ int sgiseeq_init(struct net_device *dev, struct sgiseeq_regs *sregs, struct hpc3_ethregs *hregs, int irq) { - static unsigned version_printed = 0; + static unsigned version_printed; int i; struct sgiseeq_private *sp; @@ -704,7 +704,7 @@ int sgiseeq_probe(struct net_device *dev) { - static int initialized = 0; + static int initialized; char *ep; if (initialized) /* Already initialized? */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/sis900.c linux.ac/drivers/net/sis900.c --- linux.vanilla/drivers/net/sis900.c Tue Apr 3 17:32:13 2001 +++ linux.ac/drivers/net/sis900.c Mon Apr 16 15:57:42 2001 @@ -1,6 +1,6 @@ /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux. Copyright 1999 Silicon Integrated System Corporation - Revision: 1.07.08 Jan. 8 2001 + Revision: 1.07.11 Apr. 10 2001 Modified from the driver which is originally written by Donald Becker. @@ -18,6 +18,8 @@ preliminary Rev. 1.0 Jan. 18, 1998 http://www.sis.com.tw/support/databook.htm + Rev 1.07.11 Apr. 2 2001 Hui-Fen Hsu updates PCI drivers to use the new pci_set_dma_mask for kernel 2.4.3 + Rev 1.07.10 Mar. 1 2001 Hui-Fen Hsu <hfhsu@sis.com.tw> some bug fix & 635M/B support Rev 1.07.09 Feb. 9 2001 Dave Jones <davej@suse.de> PCI enable cleanup Rev 1.07.08 Jan. 8 2001 Lei-Chun Chang added RTL8201 PHY support Rev 1.07.07 Nov. 29 2000 Lei-Chun Chang added kernel-doc extractable documentation and 630 workaround fix @@ -45,7 +47,7 @@ #include <linux/timer.h> #include <linux/errno.h> #include <linux/ioport.h> -#include <linux/slab.h> +#include <linux/malloc.h> #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/netdevice.h> @@ -61,9 +63,9 @@ #include "sis900.h" static const char *version = -"sis900.c: v1.07.09 2/9/2001\n"; +"sis900.c: v1.07.11 4/10/2001\n"; -static int max_interrupt_work = 20; +static int max_interrupt_work = 40; static int multicast_filter_limit = 128; #define sis900_debug debug @@ -91,31 +93,33 @@ }; MODULE_DEVICE_TABLE (pci, sis900_pci_tbl); -static void sis900_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex); -static void amd79c901_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex); -static void ics1893_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex); -static void rtl8201_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex); +static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex); static struct mii_chip_info { const char * name; u16 phy_id0; u16 phy_id1; - void (*read_mode) (struct net_device *net_dev, int phy_addr, int *speed, int *duplex); + u8 phy_types; +#define HOME 0x0001 +#define LAN 0x0002 +#define MIX 0x0003 } mii_chip_table[] = { - {"SiS 900 Internal MII PHY", 0x001d, 0x8000, sis900_read_mode}, - {"SiS 7014 Physical Layer Solution", 0x0016, 0xf830,sis900_read_mode}, - {"AMD 79C901 10BASE-T PHY", 0x0000, 0x35b9, amd79c901_read_mode}, - {"AMD 79C901 HomePNA PHY", 0x0000, 0x35c8, amd79c901_read_mode}, - {"ICS 1893 Integrated PHYceiver" , 0x0015, 0xf441,ics1893_read_mode}, - {"RTL 8201 10/100Mbps Phyceiver" , 0x0000, 0x8201,rtl8201_read_mode}, + { "SiS 900 Internal MII PHY", 0x001d, 0x8000, LAN }, + { "SiS 7014 Physical Layer Solution", 0x0016, 0xf830, LAN }, + { "AMD 79C901 10BASE-T PHY", 0x0000, 0x6B70, LAN }, + { "AMD 79C901 HomePNA PHY", 0x0000, 0x6B90, HOME}, + { "ICS LAN PHY", 0x0015, 0xF440, LAN }, + { "NS 83851 PHY", 0x2000, 0x5C20, MIX }, {0,}, }; struct mii_phy { struct mii_phy * next; - struct mii_chip_info * chip_info; int phy_addr; + u16 phy_id0; + u16 phy_id1; u16 status; + u8 phy_types; }; typedef struct _BufferDesc { @@ -131,11 +135,13 @@ spinlock_t lock; struct mii_phy * mii; + struct mii_phy * first_mii; /* record the first mii structure */ unsigned int cur_phy; - struct timer_list timer; /* Link status detection timer. */ + struct timer_list timer; /* Link status detection timer. */ + u8 autong_complete; /* 1: auto-negotiate complete */ - unsigned int cur_rx, dirty_rx; /* producer/comsumer pointers for Tx/Rx ring */ + 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 */ @@ -171,11 +177,16 @@ static int sis900_close(struct net_device *net_dev); static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd); static struct net_device_stats *sis900_get_stats(struct net_device *net_dev); -static u16 sis900_compute_hashtable_index(u8 *addr); +static u16 sis900_compute_hashtable_index(u8 *addr, u8 revision); static void set_rx_mode(struct net_device *net_dev); static void sis900_reset(struct net_device *net_dev); static void sis630_set_eq(struct net_device *net_dev, u8 revision); static int sis900_set_config(struct net_device *dev, struct ifmap *map); +static u16 sis900_default_phy(struct net_device * net_dev); +static void sis900_set_capability( struct net_device *net_dev ,struct mii_phy *phy); +static u16 sis900_reset_phy(struct net_device *net_dev, int phy_addr); +static void sis900_auto_negotiate(struct net_device *net_dev, int phy_addr); +static void sis900_set_mode (long ioaddr, int speed, int duplex); /** * sis900_get_mac_addr: - Get MAC address for stand alone SiS900 model @@ -239,6 +250,44 @@ return 1; } + +/** + * sis635_get_mac_addr: - Get MAC address for SIS635 model + * @pci_dev: the sis900 pci device + * @net_dev: the net device to get address for + * + * SiS635 model, set MAC Reload Bit to load Mac address from APC + * to rfdr. rfdr is accessed through rfcr. MAC address is read into + * @net_dev->dev_addr. + */ + +static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev) +{ + long ioaddr = net_dev->base_addr; + u32 rfcrSave; + u32 i; + + rfcrSave = inl(rfcr + ioaddr); + + outl(rfcrSave | RELOAD, ioaddr + cr); + outl(0, ioaddr + cr); + + /* disable packet filtering before setting filter */ + outl(rfcrSave & ~RFEN, rfcr + ioaddr); + + /* load MAC addr to filter data register */ + for (i = 0 ; i < 3 ; i++) { + outl((i << RFADDR_shift), ioaddr + rfcr); + *( ((u16 *)net_dev->dev_addr) + i) = inw(ioaddr + rfdr); + } + + /* enable packet filitering */ + outl(rfcrSave | RFEN, rfcr + ioaddr); + + return 1; +} + + /** * sis900_probe: - Probe for sis900 device * @pci_dev: the sis900 pci device @@ -253,64 +302,41 @@ static int __devinit sis900_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { struct sis900_private *sis_priv; - long ioaddr; struct net_device *net_dev; - int irq; + long ioaddr; int i, ret; u8 revision; char *card_name = card_names[pci_id->driver_data]; /* setup various bits in PCI command register */ - ret = pci_enable_device (pci_dev); - if (ret) return ret; - + ret = pci_enable_device(pci_dev); + if(ret) return ret; + i = pci_set_dma_mask(pci_dev, SIS900_DMA_MASK); - if (i) { - printk(KERN_ERR "sis900.c: architecture does not support " - "32bit PCI busmaster DMA\n"); + if(i){ + printk(KERN_ERR "sis900.c: architecture does not support" + "32bit PCI busmaster DMA\n"); return i; } - + pci_set_master(pci_dev); - - irq = pci_dev->irq; - ioaddr = pci_resource_start(pci_dev, 0); - + net_dev = alloc_etherdev(sizeof(struct sis900_private)); if (!net_dev) return -ENOMEM; SET_MODULE_OWNER(net_dev); + /* We do a request_region() to register /proc/ioports info. */ + ioaddr = pci_resource_start(pci_dev, 0); ret = pci_request_regions(pci_dev, "sis900"); if (ret) goto err_out; - pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision); - if (revision == SIS630E_900_REV || revision == SIS630EA1_900_REV) - ret = sis630e_get_mac_addr(pci_dev, net_dev); - else if (revision == SIS630S_900_REV) - ret = sis630e_get_mac_addr(pci_dev, net_dev); - else - ret = sis900_get_mac_addr(pci_dev, net_dev); - - if (ret == 0) { - ret = -ENODEV; - goto err_out_region; - } - sis_priv = net_dev->priv; - - /* We do a request_region() to register /proc/ioports info. */ net_dev->base_addr = ioaddr; - net_dev->irq = irq; + net_dev->irq = pci_dev->irq; sis_priv->pci_dev = pci_dev; spin_lock_init(&sis_priv->lock); - - /* probe for mii transciver */ - if (sis900_mii_probe(net_dev) == 0) { - ret = -ENODEV; - goto err_out_region; - } pci_set_drvdata(pci_dev, net_dev); @@ -324,25 +350,47 @@ net_dev->do_ioctl = &mii_ioctl; net_dev->tx_timeout = sis900_tx_timeout; net_dev->watchdog_timeo = TX_TIMEOUT; - + ret = register_netdev(net_dev); if (ret) goto err_out_cleardev; + + /* Get Mac address according to the chip revision */ + pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision); + ret = 0; + + if (revision == SIS630E_900_REV) + ret = sis630e_get_mac_addr(pci_dev, net_dev); + else if ((revision > 0x81) && (revision <= 0x90) ) + ret = sis635_get_mac_addr(pci_dev, net_dev); + else + ret = sis900_get_mac_addr(pci_dev, net_dev); + + if (ret == 0) { + ret = -ENODEV; + goto err_out_region; + } + + /* probe for mii transciver */ + if (sis900_mii_probe(net_dev) == 0) { + ret = -ENODEV; + goto err_out_region; + } /* print some information about our NIC */ printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, - card_name, ioaddr, irq); + card_name, ioaddr, net_dev->irq); for (i = 0; i < 5; i++) printk("%2.2x:", (u8)net_dev->dev_addr[i]); printk("%2.2x.\n", net_dev->dev_addr[i]); return 0; -err_out_cleardev: - pci_set_drvdata(pci_dev, NULL); -err_out_region: + err_out_cleardev: + pci_set_drvdata(pci_dev, NULL); + err_out_region: pci_release_regions(pci_dev); -err_out: + err_out: kfree(net_dev); return ret; } @@ -350,7 +398,7 @@ /** * sis900_mii_probe: - Probe MII PHY for sis900 * @net_dev: the net device to probe for - * + * * Search for total of 32 possible mii phy addresses. * Identify and set current phy if found one, * return error if it failed to found. @@ -359,59 +407,83 @@ static int __init sis900_mii_probe (struct net_device * net_dev) { struct sis900_private * sis_priv = net_dev->priv; + u16 poll_bit = MII_STAT_LINK, status = 0; + unsigned int timeout = jiffies + 5 * HZ; 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++) { + for (phy_addr = 0; phy_addr < 32; phy_addr++) { + struct mii_phy * mii_phy = NULL; u16 mii_status; - u16 phy_id0, phy_id1; int i; - mii_status = mdio_read(net_dev, phy_addr, MII_STATUS); + mii_phy = NULL; + for(i = 0; i < 2; 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; + + if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) == NULL) { + printk(KERN_INFO "Cannot allocate mem for struct mii_phy\n"); + return 0; + } + + mii_phy->phy_id0 = mdio_read(net_dev, phy_addr, MII_PHY_ID0); + mii_phy->phy_id1 = mdio_read(net_dev, phy_addr, MII_PHY_ID1); + mii_phy->phy_addr = phy_addr; + mii_phy->status = mii_status; + mii_phy->next = sis_priv->mii; + sis_priv->mii = mii_phy; + sis_priv->first_mii = mii_phy; - 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 && - phy_id1 == mii_chip_table[i].phy_id1) { - struct mii_phy * mii_phy; - - printk(KERN_INFO - "%s: %s transceiver found at address %d.\n", - 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_STATUS); - mii_phy->next = sis_priv->mii; - sis_priv->mii = mii_phy; - } - /* the current mii is on our mii_info_table, - try next address */ + if ((mii_phy->phy_id0 == mii_chip_table[i].phy_id0 ) && + ((mii_phy->phy_id1 & 0xFFF0) == mii_chip_table[i].phy_id1)){ + mii_phy->phy_types = mii_chip_table[i].phy_types; + if (mii_chip_table[i].phy_types == MIX) + mii_phy->phy_types = + (mii_status & (MII_STAT_CAN_TX_FDX | MII_STAT_CAN_TX)) ? LAN : HOME; + printk(KERN_INFO "%s: %s transceiver found at address %d.\n", + net_dev->name, mii_chip_table[i].name, phy_addr); break; } + + if( !mii_chip_table[i].phy_id1 ) + printk(KERN_INFO "%s: Unknown PHY transceiver found at address %d.\n", + net_dev->name, phy_addr); } - + if (sis_priv->mii == NULL) { printk(KERN_INFO "%s: No MII transceivers found!\n", net_dev->name); return 0; } - /* 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); + /* select default PHY for mac */ + sis_priv->mii = NULL; + sis900_default_phy( net_dev ); + + /* Reset phy if default phy is internal sis900 */ + if ((sis_priv->mii->phy_id0 == 0x001D) && + ((sis_priv->mii->phy_id1&0xFFF0) == 0x8000)) + status = sis900_reset_phy(net_dev, sis_priv->cur_phy); + + if(status & MII_STAT_LINK){ + while (poll_bit) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(0); + poll_bit ^= (mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS) & poll_bit); + if (jiffies >= timeout) { + printk(KERN_WARNING "%s: reset phy and link down now\n", net_dev->name); + return -ETIME; + } + } + } pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); if (revision == SIS630E_900_REV) { @@ -420,7 +492,7 @@ 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); + //mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, 0x1000); } if (sis_priv->mii->status & MII_STAT_LINK) @@ -431,6 +503,86 @@ return 1; } +/** + * sis900_default_phy: - Select default PHY for sis900 mac. + * @net_dev: the net device to probe for + * + * Select first detected PHY with link as default. + * If no one is link on, select PHY whose types is HOME as default. + * If HOME doesn't exist, select LAN. + */ + +static u16 sis900_default_phy(struct net_device * net_dev) +{ + struct sis900_private * sis_priv = net_dev->priv; + struct mii_phy *phy = NULL, *phy_home = NULL, *default_phy = NULL; + u16 status; + + for( phy=sis_priv->first_mii; phy; phy=phy->next ){ + status = mdio_read(net_dev, phy->phy_addr, MII_STATUS); + status = mdio_read(net_dev, phy->phy_addr, MII_STATUS); + + /* Link ON & Not select deafalut PHY */ + if ( (status & MII_STAT_LINK) && !(default_phy) ) + default_phy = phy; + else{ + status = mdio_read(net_dev, phy->phy_addr, MII_CONTROL); + mdio_write(net_dev, phy->phy_addr, MII_CONTROL, + status | MII_CNTL_AUTO | MII_CNTL_ISOLATE); + if( phy->phy_types == HOME ) + phy_home = phy; + } + } + + if( (!default_phy) && phy_home ) + default_phy = phy_home; + else if(!default_phy) + default_phy = sis_priv->first_mii; + + if( sis_priv->mii != default_phy ){ + sis_priv->mii = default_phy; + sis_priv->cur_phy = default_phy->phy_addr; + printk(KERN_INFO "%s: Using transceiver found at address %d as default\n", net_dev->name,sis_priv->cur_phy); + } + + status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL); + status &= (~MII_CNTL_ISOLATE); + + mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, status); + status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS); + status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS); + + return status; +} + + +/** + * sis900_set_capability: - set the media capability of network adapter. + * @net_dev : the net device to probe for + * @mii_phy : default PHY + * + * Set the media capability of network adapter according to + * mii status register. It's necessary before auto-negotiate. + */ + +static void sis900_set_capability( struct net_device *net_dev , struct mii_phy *phy ) +{ + u16 cap; + u16 status; + + status = mdio_read(net_dev, phy->phy_addr, MII_STATUS); + status = mdio_read(net_dev, phy->phy_addr, MII_STATUS); + + cap = MII_NWAY_CSMA_CD | + ((phy->status & MII_STAT_CAN_TX_FDX)? MII_NWAY_TX_FDX:0) | + ((phy->status & MII_STAT_CAN_TX) ? MII_NWAY_TX:0) | + ((phy->status & MII_STAT_CAN_T_FDX) ? MII_NWAY_T_FDX:0)| + ((phy->status & MII_STAT_CAN_T) ? MII_NWAY_T:0); + + mdio_write(net_dev, phy->phy_addr, MII_ANADV, cap); +} + + /* Delay between EEPROM clock transitions. */ #define eeprom_delay() inl(ee_addr) @@ -605,6 +757,30 @@ return; } + +/** + * sis900_reset_phy: - reset sis900 mii phy. + * @net_dev: the net device to write + * @phy_addr: default phy address + * + * Some specific phy can't work properly without reset. + * This function will be called during initialization and + * link status change from ON to DOWN. + */ + +static u16 sis900_reset_phy(struct net_device *net_dev, int phy_addr) +{ + int i = 0; + u16 status; + + while (i++ < 2) + status = mdio_read(net_dev, phy_addr, MII_STATUS); + + mdio_write( net_dev, phy_addr, MII_CONTROL, MII_CNTL_RESET ); + + return status; +} + /** * sis900_open: - open sis900 device * @net_dev: the net device to open @@ -626,9 +802,7 @@ /* Equalizer workaround Rule */ pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); - if (revision == SIS630E_900_REV || revision == SIS630EA1_900_REV || - revision == SIS630A_900_REV) - sis630_set_eq(net_dev,revision); + sis630_set_eq(net_dev, revision); ret = request_irq(net_dev->irq, &sis900_interrupt, SA_SHIRQ, net_dev->name, net_dev); if (ret) @@ -679,7 +853,7 @@ rfcrSave = inl(rfcr + ioaddr); /* disable packet filtering before setting filter */ - outl(rfcrSave & ~RFEN, rfcr); + outl(rfcrSave & ~RFEN, rfcr + ioaddr); /* load MAC addr to filter data register */ for (i = 0 ; i < 3 ; i++) { @@ -820,7 +994,11 @@ int i, maxcount=10; struct pci_dev *dev=NULL; - if ((dev = pci_find_device(SIS630_DEVICE_ID, SIS630_VENDOR_ID, dev))) + if ( !(revision == SIS630E_900_REV || revision == SIS630EA1_900_REV || + revision == SIS630A_900_REV) ) + return; + + if ((dev = pci_find_device(SIS630_VENDOR_ID, SIS630_DEVICE_ID, dev))) pci_read_config_byte(dev, PCI_CLASS_REVISION, &host_bridge_rev); if (netif_carrier_ok(net_dev)) { @@ -842,13 +1020,6 @@ else if (max_value >= 15) eq_value=(max_value == min_value) ? max_value+6 : max_value+5; } - /* 630A0 rule to determine the equalizer value */ - if (revision == SIS630A_900_REV && host_bridge_rev == SIS630A0) { - if (max_value < 5) - eq_value=max_value+3; - else if (max_value >= 5) - eq_value=max_value+5; - } /* 630B0&B1 rule to determine the equalizer value */ if (revision == SIS630A_900_REV && (host_bridge_rev == SIS630B0 || host_bridge_rev == SIS630B1)) { @@ -865,7 +1036,11 @@ } 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); + if (revision == SIS630A_900_REV && + (host_bridge_rev == SIS630B0 || host_bridge_rev == SIS630B1)) + mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (reg14h | 0x2200) & 0xBFFF); + else + mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (reg14h | 0x2000) & 0xBFFF); } return; } @@ -887,60 +1062,52 @@ 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); + if (!sis_priv->autong_complete){ + int speed, duplex = 0; - /* current mii phy is failed to link, try another one */ - while (!(status & MII_STAT_LINK)) { - if (mii_phy->next == NULL) { - if (netif_carrier_ok(net_dev)) { - /* link stat change from ON to OFF */ - next_tick = HZ; - netif_carrier_off(net_dev); - - /* Equalizer workaround Rule */ - pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); - if (revision == SIS630E_900_REV || revision == SIS630EA1_900_REV || - revision == SIS630A_900_REV) - sis630_set_eq(net_dev, revision); - - printk(KERN_INFO "%s: Media Link Off\n", - net_dev->name); - } - sis_priv->timer.expires = jiffies + next_tick; - add_timer(&sis_priv->timer); - return; + sis900_read_mode(net_dev, &speed, &duplex); + if (duplex){ + sis900_set_mode(net_dev->base_addr, speed, duplex); + pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); + sis630_set_eq(net_dev, revision); } - mii_phy = mii_phy->next; - status = mdio_read(net_dev, mii_phy->phy_addr, MII_STATUS); - } - if (!netif_carrier_ok(net_dev)) { - /* link stat change forn OFF to ON, read and report link mode */ - netif_carrier_on(net_dev); - next_tick = 5*HZ; + sis_priv->timer.expires = jiffies + HZ; + add_timer(&sis_priv->timer); + return; + } - /* Equalizer workaround Rule */ - pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); - if (revision == SIS630E_900_REV || revision == SIS630EA1_900_REV || - revision == SIS630A_900_REV) - sis630_set_eq(net_dev, revision); + status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS); + status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS); - /* 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); - /* disable previous PHY */ - status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL); - 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, - MII_CONTROL, status & ~MII_CNTL_ISOLATE); - sis_priv->cur_phy = mii_phy->phy_addr; + /* Link OFF -> ON */ + if (!netif_carrier_ok(net_dev)) { + LookForLink: + /* Search for new PHY */ + status = sis900_default_phy(net_dev); + mii_phy = sis_priv->mii; + + if (status & MII_STAT_LINK){ + sis900_check_mode(net_dev, mii_phy); + netif_carrier_on(net_dev); } - sis900_check_mode(net_dev, mii_phy); + } + /* Link ON -> OFF */ + else { + if (!(status & MII_STAT_LINK)){ + netif_carrier_off(net_dev); + printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); + + /* Change mode issue */ + if ((mii_phy->phy_id0 == 0x001D) && + ((mii_phy->phy_id1 & 0xFFF0) == 0x8000)) + sis900_reset_phy(net_dev, sis_priv->cur_phy); + + pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); + sis630_set_eq(net_dev, revision); + + goto LookForLink; + } } sis_priv->timer.expires = jiffies + next_tick; @@ -952,8 +1119,11 @@ * @net_dev: the net device to be checked * @mii_phy: the mii phy * - * call mii_phy->chip_info->read_mode function - * to check the speed and duplex mode for sis900 + * Older driver gets the media mode from mii status output + * register. Now we set our media capability and auto-negotiate + * to get the upper bound of speed and duplex between two ends. + * If the types of mii phy is HOME, it doesn't need to auto-negotiate + * and autong_complete should be set to 1. */ static void sis900_check_mode (struct net_device *net_dev, struct mii_phy *mii_phy) @@ -961,12 +1131,44 @@ struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; int speed, duplex; - u32 tx_flags = 0, rx_flags = 0; - mii_phy->chip_info->read_mode(net_dev, sis_priv->cur_phy, &speed, &duplex); + if( mii_phy->phy_types == LAN ){ + outl( ~EXD & inl( ioaddr + cfg ), ioaddr + cfg); + sis900_set_capability(net_dev , mii_phy); + sis900_auto_negotiate(net_dev, sis_priv->cur_phy); + }else{ + outl(EXD | inl( ioaddr + cfg ), ioaddr + cfg); + speed = HW_SPEED_HOME; + duplex = FDX_CAPABLE_HALF_SELECTED; + sis900_set_mode(ioaddr, speed, duplex); + sis_priv->autong_complete = 1; + } +} - tx_flags = TxATP | (TX_DMA_BURST << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift); - rx_flags = RX_DMA_BURST << RxMXDMA_shift; +/** + * sis900_set_mode: - Set the media mode of mac register. + * @speed : the transmit speed to be determined + * @duplex: the duplex mode to be determined + * + * Set the media mode of mac register txcfg/rxcfg according to + * speed and duplex of phy. Bit EDB_MASTER_EN indicates the EDB + * bus is used instead of PCI bus. When this bit is set 1, the + * Max DMA Burst Size for TX/RX DMA should be no larger than 16 + * double words. + */ + +static void sis900_set_mode (long ioaddr, int speed, int duplex) +{ + u32 tx_flags = 0, rx_flags = 0; + + if( inl(ioaddr + cfg) & EDB_MASTER_EN ){ + tx_flags = TxATP | (DMA_BURST_64 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift); + rx_flags = DMA_BURST_64 << RxMXDMA_shift; + } + else{ + tx_flags = TxATP | (DMA_BURST_512 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift); + rx_flags = DMA_BURST_512 << RxMXDMA_shift; + } if (speed == HW_SPEED_HOME || speed == HW_SPEED_10_MBPS ) { rx_flags |= (RxDRNT_10 << RxDRNT_shift); @@ -987,184 +1189,86 @@ } /** - * sis900_read_mode: - read media mode for sis900 internal phy + * sis900_auto_negotiate: Set the Auto-Negotiation Enable/Reset bit. * @net_dev: the net device to read mode for * @phy_addr: mii phy address - * @speed: the transmit speed to be determined - * @duplex: the duplex mode to be determined * - * read MII_STSOUT register from sis900 internal phy - * to determine the speed and duplex mode for sis900 + * If the adapter is link-on, set the auto-negotiate enable/reset bit. + * autong_complete should be set to 0 when starting auto-negotiation. + * autong_complete should be set to 1 if we didn't start auto-negotiation. + * sis900_timer will wait for link on again if autong_complete = 0. */ -static void sis900_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex) +static void sis900_auto_negotiate(struct net_device *net_dev, int phy_addr) { + struct sis900_private *sis_priv = net_dev->priv; 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); - - if (status & MII_STSOUT_SPD) - *speed = HW_SPEED_100_MBPS; - else - *speed = HW_SPEED_10_MBPS; - - if (status & MII_STSOUT_DPLX) - *duplex = FDX_CAPABLE_FULL_SELECTED; - else - *duplex = FDX_CAPABLE_HALF_SELECTED; + status = mdio_read(net_dev, phy_addr, MII_STATUS); - if (status & MII_STSOUT_LINK_FAIL) + if (!(status & MII_STAT_LINK)){ printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); - else - printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", - net_dev->name, - *speed == HW_SPEED_100_MBPS ? - "100mbps" : "10mbps", - *duplex == FDX_CAPABLE_FULL_SELECTED ? - "full" : "half"); + sis_priv->autong_complete = 1; + netif_carrier_off(net_dev); + return; + } + + /* (Re)start AutoNegotiate */ + mdio_write(net_dev, phy_addr, MII_CONTROL, + MII_CNTL_AUTO | MII_CNTL_RST_AUTO); + sis_priv->autong_complete = 0; } + /** - * amd79c901_read_mode: - read media mode for amd79c901 phy + * sis900_read_mode: - read media mode for sis900 internal phy * @net_dev: the net device to read mode for - * @phy_addr: mii phy address - * @speed: the transmit speed to be determined - * @duplex: the duplex mode to be determined + * @speed : the transmit speed to be determined + * @duplex : the duplex mode to be determined * - * read MII_STATUS register from amd79c901 phy - * to determine the speed and duplex mode for sis900 + * The capability of remote end will be put in mii register autorec + * after auto-negotiation. Use AND operation to get the upper bound + * of speed and duplex between two ends. */ -static void amd79c901_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex) +static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex) { - int i; - u16 status; + struct sis900_private *sis_priv = net_dev->priv; + int phy_addr = sis_priv->cur_phy; + u32 status; + u16 autoadv, autorec; + int i = 0; - for (i = 0; i < 2; i++) + while (i++ < 2) status = mdio_read(net_dev, phy_addr, MII_STATUS); - if (status & MII_STAT_CAN_AUTO) { - /* 10BASE-T PHY */ - for (i = 0; i < 2; i++) - status = mdio_read(net_dev, phy_addr, MII_STATUS_SUMMARY); - if (status & MII_STSSUM_SPD) - *speed = HW_SPEED_100_MBPS; - else - *speed = HW_SPEED_10_MBPS; - if (status & MII_STSSUM_DPLX) - *duplex = FDX_CAPABLE_FULL_SELECTED; - else - *duplex = FDX_CAPABLE_HALF_SELECTED; + if (!(status & MII_STAT_LINK)) + return; - if (status & MII_STSSUM_LINK) - printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", - net_dev->name, - *speed == HW_SPEED_100_MBPS ? - "100mbps" : "10mbps", - *duplex == FDX_CAPABLE_FULL_SELECTED ? - "full" : "half"); - else - printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); - } - else { - /* HomePNA */ - *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", - net_dev->name); - else - printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); - } -} - -/** - * ics1893_read_mode: - read media mode for ICS1893 PHY - * @net_dev: the net device to read mode for - * @phy_addr: mii phy address - * @speed: the transmit speed to be determined - * @duplex: the duplex mode to be determined - * - * ICS1893 PHY use Quick Poll Detailed Status register - * to determine the speed and duplex mode for sis900 - */ + /* AutoNegotiate completed */ + autoadv = mdio_read(net_dev, phy_addr, MII_ANADV); + autorec = mdio_read(net_dev, phy_addr, MII_ANLPAR); + status = autoadv & autorec; -static void ics1893_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex) -{ - int i = 0; - u32 status; - - /* MII_QPDSTS is Latched, read twice in succession will reflect the current state */ - for (i = 0; i < 2; i++) - status = mdio_read(net_dev, phy_addr, MII_QPDSTS); - - if (status & MII_STSICS_SPD) + if (status & (MII_NWAY_TX | MII_NWAY_TX_FDX)) *speed = HW_SPEED_100_MBPS; else *speed = HW_SPEED_10_MBPS; - - if (status & MII_STSICS_DPLX) + if (status & ( MII_NWAY_TX_FDX | MII_NWAY_T_FDX)) *duplex = FDX_CAPABLE_FULL_SELECTED; else *duplex = FDX_CAPABLE_HALF_SELECTED; - if (status & MII_STSICS_LINKSTS) - printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", - net_dev->name, - *speed == HW_SPEED_100_MBPS ? - "100mbps" : "10mbps", - *duplex == FDX_CAPABLE_FULL_SELECTED ? - "full" : "half"); - else - printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); -} - -/** - * rtl8201_read_mode: - read media mode for rtl8201 phy - * @net_dev: the net device to read mode for - * @phy_addr: mii phy address - * @speed: the transmit speed to be determined - * @duplex: the duplex mode to be determined - * - * read MII_STATUS register from rtl8201 phy - * to determine the speed and duplex mode for sis900 - */ - -static void rtl8201_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex) -{ - u32 status; - - status = mdio_read(net_dev, phy_addr, MII_STATUS); - - if (status & MII_STAT_CAN_TX_FDX) { - *speed = HW_SPEED_100_MBPS; - *duplex = FDX_CAPABLE_FULL_SELECTED; - } - else if (status & MII_STAT_CAN_TX) { - *speed = HW_SPEED_100_MBPS; - *duplex = FDX_CAPABLE_HALF_SELECTED; - } - else if (status & MII_STAT_CAN_T_FDX) { - *speed = HW_SPEED_10_MBPS; - *duplex = FDX_CAPABLE_FULL_SELECTED; - } - else if (status & MII_STAT_CAN_T) { - *speed = HW_SPEED_10_MBPS; - *duplex = FDX_CAPABLE_HALF_SELECTED; - } - - if (status & MII_STAT_LINK) - printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", - net_dev->name, - *speed == HW_SPEED_100_MBPS ? - "100mbps" : "10mbps", - *duplex == FDX_CAPABLE_FULL_SELECTED ? - "full" : "half"); - else - printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); + sis_priv->autong_complete = 1; + + printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", + net_dev->name, + *speed == HW_SPEED_100_MBPS ? + "100mbps" : "10mbps", + *duplex == FDX_CAPABLE_FULL_SELECTED ? + "full" : "half"); } /** @@ -1628,83 +1732,81 @@ u16 status; - /* - )*/ if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { - /* we switch on the ifmap->port field. I couldn't find anything - like a definition or standard for the values of that field. - I think the meaning of those values is device specific. But - since I would like to change the media type via the ifconfig - command I use the definition from linux/netdevice.h - (which seems to be different from the ifport(pcmcia) definition) - */ + /* we switch on the ifmap->port field. I couldn't find anything + like a definition or standard for the values of that field. + I think the meaning of those values is device specific. But + since I would like to change the media type via the ifconfig + command I use the definition from linux/netdevice.h + (which seems to be different from the ifport(pcmcia) definition) + */ switch(map->port){ - case IF_PORT_UNKNOWN: /* use auto here */ - dev->if_port = map->port; - /* we are going to change the media type, so the Link will - be temporary down and we need to reflect that here. When - the Link comes up again, it will be sensed by the sis_timer - procedure, which also does all the rest for us */ - netif_carrier_off(dev); + case IF_PORT_UNKNOWN: /* use auto here */ + dev->if_port = map->port; + /* we are going to change the media type, so the Link will + be temporary down and we need to reflect that here. When + the Link comes up again, it will be sensed by the sis_timer + procedure, which also does all the rest for us */ + netif_carrier_off(dev); - /* read current state */ - status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL); + /* read current state */ + status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL); - /* enable auto negotiation and reset the negotioation - (I dont really know what the auto negatiotiation reset - really means, but it sounds for me right to do one here)*/ - mdio_write(dev, mii_phy->phy_addr, - MII_CONTROL, status | MII_CNTL_AUTO | MII_CNTL_RST_AUTO); + /* enable auto negotiation and reset the negotioation + (I dont really know what the auto negatiotiation reset + really means, but it sounds for me right to do one here)*/ + mdio_write(dev, mii_phy->phy_addr, + MII_CONTROL, status | MII_CNTL_AUTO | MII_CNTL_RST_AUTO); - break; + break; - case IF_PORT_10BASET: /* 10BaseT */ - dev->if_port = map->port; + case IF_PORT_10BASET: /* 10BaseT */ + dev->if_port = map->port; - /* we are going to change the media type, so the Link will - be temporary down and we need to reflect that here. When - the Link comes up again, it will be sensed by the sis_timer - procedure, which also does all the rest for us */ - netif_carrier_off(dev); + /* we are going to change the media type, so the Link will + be temporary down and we need to reflect that here. When + the Link comes up again, it will be sensed by the sis_timer + procedure, which also does all the rest for us */ + netif_carrier_off(dev); - /* set Speed to 10Mbps */ - /* read current state */ - status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL); + /* set Speed to 10Mbps */ + /* read current state */ + status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL); - /* disable auto negotiation and force 10MBit mode*/ - mdio_write(dev, mii_phy->phy_addr, - MII_CONTROL, status & ~(MII_CNTL_SPEED | MII_CNTL_AUTO)); - break; + /* disable auto negotiation and force 10MBit mode*/ + mdio_write(dev, mii_phy->phy_addr, + MII_CONTROL, status & ~(MII_CNTL_SPEED | MII_CNTL_AUTO)); + break; - case IF_PORT_100BASET: /* 100BaseT */ - case IF_PORT_100BASETX: /* 100BaseTx */ - dev->if_port = map->port; + case IF_PORT_100BASET: /* 100BaseT */ + case IF_PORT_100BASETX: /* 100BaseTx */ + dev->if_port = map->port; - /* we are going to change the media type, so the Link will - be temporary down and we need to reflect that here. When - the Link comes up again, it will be sensed by the sis_timer - procedure, which also does all the rest for us */ - netif_carrier_off(dev); + /* we are going to change the media type, so the Link will + be temporary down and we need to reflect that here. When + the Link comes up again, it will be sensed by the sis_timer + procedure, which also does all the rest for us */ + netif_carrier_off(dev); - /* set Speed to 100Mbps */ - /* disable auto negotiation and enable 100MBit Mode */ - status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL); - mdio_write(dev, mii_phy->phy_addr, - MII_CONTROL, (status & ~MII_CNTL_SPEED) | MII_CNTL_SPEED); + /* set Speed to 100Mbps */ + /* disable auto negotiation and enable 100MBit Mode */ + status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL); + mdio_write(dev, mii_phy->phy_addr, + MII_CONTROL, (status & ~MII_CNTL_SPEED) | MII_CNTL_SPEED); - break; + break; - case IF_PORT_10BASE2: /* 10Base2 */ - case IF_PORT_AUI: /* AUI */ - case IF_PORT_100BASEFX: /* 100BaseFx */ + case IF_PORT_10BASE2: /* 10Base2 */ + case IF_PORT_AUI: /* AUI */ + case IF_PORT_100BASEFX: /* 100BaseFx */ /* These Modes are not supported (are they?)*/ - printk(KERN_INFO "Not supported"); - return -EOPNOTSUPP; - break; + printk(KERN_INFO "Not supported"); + return -EOPNOTSUPP; + break; - default: - printk(KERN_INFO "Invalid"); - return -EINVAL; + default: + printk(KERN_INFO "Invalid"); + return -EINVAL; } } return 0; @@ -1713,12 +1815,15 @@ /** * sis900_compute_hashtable_index: - compute hashtable index * @addr: multicast address + * @revision: revision id of chip * * SiS 900 uses the most sigificant 7 bits to index a 128 bits multicast * hash table, which makes this function a little bit different from other drivers + * SiS 900 B0 & 635 M/B uses the most significat 8 bits to index 256 bits + * multicast hash table. */ -static u16 sis900_compute_hashtable_index(u8 *addr) +static u16 sis900_compute_hashtable_index(u8 *addr, u8 revision) { /* what is the correct value of the POLYNOMIAL ?? @@ -1741,51 +1846,63 @@ byte >>= 1; } } - /* leave 7 most siginifant bits */ - return ((int)(crc >> 25)); + + /* leave 8 or 7 most siginifant bits */ + if ((revision == SIS635A_900_REV) || (revision == SIS900B_900_REV)) + return ((int)(crc >> 24)); + else + return ((int)(crc >> 25)); } /** * set_rx_mode: - Set SiS900 receive mode * @net_dev: the net device to be set * - * Set SiS900 receive mode for promiscuous, multicast, or broadcast mode. + * Set SiS900 receive mode for promiscuous, multicast, or broadcast mode. * And set the appropriate multicast filter. + * Multicast hash table changes from 128 to 256 bits for 635M/B & 900B0. */ static void set_rx_mode(struct net_device *net_dev) { long ioaddr = net_dev->base_addr; - u16 mc_filter[8]; /* 128 bits multicast hash table */ - int i; + struct sis900_private * sis_priv = net_dev->priv; + u16 mc_filter[16] = {0}; /* 256/128 bits multicast hash table */ + int i, table_entries; u32 rx_mode; + u8 revision; + + /* 635 Hash Table entires = 256(2^16) */ + pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); + if((revision == SIS635A_900_REV) || (revision == SIS900B_900_REV)) + table_entries = 16; + else + table_entries = 8; if (net_dev->flags & IFF_PROMISC) { /* Accept any kinds of packets */ rx_mode = RFPromiscuous; - for (i = 0; i < 8; i++) + for (i = 0; i < table_entries; 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 packet */ rx_mode = RFAAB | RFAAM; - for (i = 0; i < 8; i++) + for (i = 0; i < table_entries; i++) mc_filter[i] = 0xffff; } else { /* Accept Broadcast packet, destination address matchs our MAC address, use Receive Filter to reject unwanted MCAST packet */ 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, revision), mc_filter); } /* update Multicast Hash Table in Receive Filter */ - for (i = 0; i < 8; i++) { + for (i = 0; i < table_entries; 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); @@ -1804,7 +1921,7 @@ outl(inl(ioaddr + rxcfg) | RxATX, ioaddr + rxcfg); /* restore cr */ outl(cr_saved, ioaddr + cr); - } + } return; } @@ -1815,13 +1932,16 @@ * * reset sis900 MAC and wait until finished * reset through command register + * change backoff algorithm for 900B0 & 635 M/B */ static void sis900_reset(struct net_device *net_dev) { + struct sis900_private * sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; int i = 0; u32 status = TxRCMP | RxRCMP; + u8 revision; outl(0, ioaddr + ier); outl(0, ioaddr + imr); @@ -1834,7 +1954,11 @@ status ^= (inl(isr + ioaddr) & status); } - outl(PESEL, ioaddr + cfg); + pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); + if( (revision == SIS635A_900_REV) || (revision == SIS900B_900_REV) ) + outl(PESEL | RND_CNT, ioaddr + cfg); + else + outl(PESEL, ioaddr + cfg); } /** @@ -1847,7 +1971,15 @@ static void __devexit sis900_remove(struct pci_dev *pci_dev) { struct net_device *net_dev = pci_get_drvdata(pci_dev); - + struct sis900_private * sis_priv = net_dev->priv; + struct mii_phy *phy = NULL; + + while (sis_priv->first_mii) { + phy = sis_priv->first_mii; + sis_priv->first_mii = phy->next; + kfree(phy); + } + unregister_netdev(net_dev); kfree(net_dev); pci_release_regions(pci_dev); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/sis900.h linux.ac/drivers/net/sis900.h --- linux.vanilla/drivers/net/sis900.h Fri Dec 29 22:07:22 2000 +++ linux.ac/drivers/net/sis900.h Sat Apr 14 01:25:16 2001 @@ -50,7 +50,10 @@ enum sis900_configuration_register_bits { DESCRFMT = 0x00000100 /* 7016 specific */, REQALG = 0x00000080, SB = 0x00000040, POW = 0x00000020, EXD = 0x00000010, - PESEL = 0x00000008, LPM = 0x00000004, BEM = 0x00000001 + PESEL = 0x00000008, LPM = 0x00000004, BEM = 0x00000001, + /* 635 & 900B Specific */ + RND_CNT = 0x00000400, FAIR_BACKOFF = 0x00000200, + EDB_MASTER_EN = 0x00002000 }; enum sis900_eeprom_access_reigster_bits { @@ -78,8 +81,10 @@ #define MAX_DMA_RANGE 7 /* actually 0 means MAXIMUM !! */ #define TxMXDMA_shift 20 #define RxMXDMA_shift 20 -#define TX_DMA_BURST 0 -#define RX_DMA_BURST 0 + +enum sis900_tx_rx_dma{ + DMA_BURST_512 = 0, DMA_BURST_64 = 5 +}; /* transmit FIFO threshholds */ #define TX_FILL_THRESH 16 /* 1/4 FIFO size */ @@ -233,7 +238,8 @@ enum sis900_revision_id { SIS630A_900_REV = 0x80, SIS630E_900_REV = 0x81, - SIS630S_900_REV = 0x82, SIS630EA1_900_REV = 0x83 + SIS630S_900_REV = 0x82, SIS630EA1_900_REV = 0x83, + SIS635A_900_REV = 0x90, SIS900B_900_REV = 0x03 }; enum sis630_revision_id { @@ -263,8 +269,8 @@ /* PCI stuff, should be move to pic.h */ #define PCI_DEVICE_ID_SI_900 0x900 #define PCI_DEVICE_ID_SI_7016 0x7016 -#define SIS630_VENDOR_ID 0x0630 -#define SIS630_DEVICE_ID 0x1039 +#define SIS630_VENDOR_ID 0x1039 +#define SIS630_DEVICE_ID 0x0630 /* ioctl for accessing MII transceiver */ #define SIOCGMIIPHY (SIOCDEVPRIVATE) /* Get the PHY in use. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/starfire.c linux.ac/drivers/net/starfire.c --- linux.vanilla/drivers/net/starfire.c Fri Aug 11 23:57:58 2000 +++ linux.ac/drivers/net/starfire.c Sat Apr 14 02:49:24 2001 @@ -97,9 +97,6 @@ /* Include files, designed to support most kernel versions 2.0.0 and later. */ #include <linux/version.h> #include <linux/module.h> -#if LINUX_VERSION_CODE < 0x20300 && defined(MODVERSIONS) -#include <linux/modversions.h> -#endif #include <linux/kernel.h> #include <linux/string.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/starfire_firmware.pl linux.ac/drivers/net/starfire_firmware.pl --- linux.vanilla/drivers/net/starfire_firmware.pl Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/starfire_firmware.pl Tue Apr 3 17:54:54 2001 @@ -0,0 +1,31 @@ +#!/usr/bin/perl + +# This script can be used to generate a new starfire_firmware.h +# from GFP_RX.DAT and GFP_TX.DAT, files included with the DDK +# and also with the Novell drivers. + +open FW, "GFP_RX.DAT" || die; +open FWH, ">starfire_firmware.h" || die; + +printf(FWH "static u32 firmware_rx[] = {\n"); +$counter = 0; +while ($foo = <FW>) { + chomp; + printf(FWH " 0x%s, 0x0000%s,\n", substr($foo, 4, 8), substr($foo, 0, 4)); + $counter++; +} + +close FW; +open FW, "GFP_TX.DAT" || die; + +printf(FWH "};\t/* %d Rx instructions */\n#define FIRMWARE_RX_SIZE %d\n\nstatic u32 firmware_tx[] = {\n", $counter, $counter); +$counter = 0; +while ($foo = <FW>) { + chomp; + printf(FWH " 0x%s, 0x0000%s,\n", substr($foo, 4, 8), substr($foo, 0, 4)); + $counter++; +} + +close FW; +printf(FWH "};\t/* %d Tx instructions */\n#define FIRMWARE_TX_SIZE %d\n", $counter, $counter); +close(FWH); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/stnic.c linux.ac/drivers/net/stnic.c --- linux.vanilla/drivers/net/stnic.c Sat Dec 30 19:23:14 2000 +++ linux.ac/drivers/net/stnic.c Sat Apr 14 01:25:23 2001 @@ -7,6 +7,7 @@ * Copyright (C) 1999 kaz Kojima */ +#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> @@ -21,6 +22,9 @@ #include <asm/io.h> #include <asm/hitachi_se.h> #include <asm/machvec.h> +#ifdef CONFIG_SH_STANDARD_BIOS +#include <asm/sh_bios.h> +#endif #include "8390.h" @@ -74,6 +78,7 @@ vword trash; trash = *(vword *) 0xa0000000; trash = *(vword *) 0xa0000000; + trash = *(vword *) 0xa0000000; } static inline byte @@ -112,10 +117,13 @@ /* Allocate dev->priv and fill in 8390 specific dev fields. */ if (ethdev_init (dev)) { - printk ("Unable to get memory for dev->priv.\n"); + printk (KERN_EMERG "Unable to get memory for dev->priv.\n"); return -ENOMEM; } +#ifdef CONFIG_SH_STANDARD_BIOS + sh_bios_get_node_addr (stnic_eadr); +#endif for (i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = stnic_eadr[i]; @@ -129,7 +137,7 @@ share and the board will usually be enabled. */ i = request_irq (dev->irq, ei_interrupt, 0, dev->name, dev); if (i) { - printk (" unable to get IRQ %d.\n", dev->irq); + printk (KERN_EMERG " unable to get IRQ %d.\n", dev->irq); unregister_netdev(dev); kfree(dev->priv); kfree(dev); @@ -157,7 +165,7 @@ stnic_open (struct net_device *dev) { #if 0 - printk ("stnic open\n"); + printk (KERN_DEBUG "stnic open\n"); #endif ei_open (dev); return 0; @@ -176,7 +184,7 @@ *(vhalf *) PA_83902_RST = 0; udelay (5); if (ei_debug > 1) - printk("8390 reset done (%ld).\n", jiffies); + printk (KERN_WARNING "8390 reset done (%ld).\n", jiffies); *(vhalf *) PA_83902_RST = ~0; udelay (5); } @@ -206,7 +214,7 @@ #endif if (ei_debug > 1) - printk ("ring %x status %02x next %02x count %04x.\n", + printk (KERN_DEBUG "ring %x status %02x next %02x count %04x.\n", ring_page, hdr->status, hdr->next, hdr->count); STNIC_WRITE (STNIC_CR, CR_RDMA | CR_PG0 | CR_STA); @@ -254,22 +262,14 @@ stnic_block_output (struct net_device *dev, int length, const unsigned char *buf, int output_page) { -#if 0 - STNIC_WRITE (PG0_RBCR0, 1); - STNIC_WRITE (STNIC_CR, CR_RRD | CR_PG0 | CR_STA); -#else /* XXX: I don't know why but this works. -- gniibe */ - STNIC_WRITE (PG0_RBCR0, 0x42); - STNIC_WRITE (PG0_RBCR1, 0x00); - STNIC_WRITE (PG0_RBCR0, 0x42); - STNIC_WRITE (PG0_RBCR1, 0x00); + STNIC_WRITE (PG0_RBCR0, 1); /* Write non-zero value */ STNIC_WRITE (STNIC_CR, CR_RRD | CR_PG0 | CR_STA); STNIC_DELAY (); -#endif - STNIC_WRITE (PG0_RSAR0, 0); - STNIC_WRITE (PG0_RSAR1, output_page); STNIC_WRITE (PG0_RBCR0, length & 0xff); STNIC_WRITE (PG0_RBCR1, length >> 8); + STNIC_WRITE (PG0_RSAR0, 0); + STNIC_WRITE (PG0_RSAR1, output_page); STNIC_WRITE (STNIC_CR, CR_RWR | CR_PG0 | CR_STA); if (length & 1) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/sundance.c linux.ac/drivers/net/sundance.c --- linux.vanilla/drivers/net/sundance.c Tue Apr 3 17:32:14 2001 +++ linux.ac/drivers/net/sundance.c Tue Apr 10 18:15:26 2001 @@ -1239,7 +1239,7 @@ struct net_device *dev = pci_get_drvdata(pdev); /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (dev) { + if (dev) { unregister_netdev(dev); pci_release_regions(pdev); #ifndef USE_IO_OPS diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/sungem.c linux.ac/drivers/net/sungem.c --- linux.vanilla/drivers/net/sungem.c Tue Apr 3 17:32:14 2001 +++ linux.ac/drivers/net/sungem.c Sat Apr 14 01:25:23 2001 @@ -1,4 +1,4 @@ -/* $Id: sungem.c,v 1.8 2001/03/22 22:48:51 davem Exp $ +/* $Id: sungem.c,v 1.11 2001/04/04 14:49:40 davem Exp $ * sungem.c: Sun GEM ethernet driver. * * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) @@ -159,13 +159,20 @@ dev->name); } - if (pcs_miistat & PCS_MIISTAT_LS) + if (pcs_miistat & PCS_MIISTAT_LS) { printk(KERN_INFO "%s: PCS link is now up.\n", dev->name); - else + } else { printk(KERN_INFO "%s: PCS link is now down.\n", dev->name); + /* If this happens and the link timer is not running, + * reset so we re-negotiate. + */ + if (!timer_pending(&gp->link_timer)) + return 1; + } + return 0; } @@ -441,7 +448,7 @@ struct gem_rxd *rxd = &gp->init_block->rxd[cluster_start]; for (;;) { - rxd->status_word = cpu_to_le64(RXDCTRL_FRESH); + rxd->status_word = cpu_to_le64(RXDCTRL_FRESH(gp)); rxd++; cluster_start = NEXT_RX(cluster_start); if (cluster_start == curr) @@ -491,19 +498,19 @@ if (len > RX_COPY_THRESHOLD) { struct sk_buff *new_skb; - new_skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); + new_skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE(gp), GFP_ATOMIC); if (new_skb == NULL) { drops++; goto drop_it; } pci_unmap_single(gp->pdev, dma_addr, - RX_BUF_ALLOC_SIZE, PCI_DMA_FROMDEVICE); + RX_BUF_ALLOC_SIZE(gp), PCI_DMA_FROMDEVICE); gp->rx_skbs[entry] = new_skb; new_skb->dev = gp->dev; skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET)); rxd->buffer = cpu_to_le64(pci_map_single(gp->pdev, new_skb->data, - RX_BUF_ALLOC_SIZE, + RX_BUF_ALLOC_SIZE(gp), PCI_DMA_FROMDEVICE)); skb_reserve(new_skb, RX_OFFSET); @@ -527,6 +534,8 @@ skb = copy_skb; } + skb->csum = ((status & RXDCTRL_TCPCSUM) ^ 0xffff); + skb->ip_summed = CHECKSUM_HW; skb->protocol = eth_type_trans(skb, gp->dev); netif_rx(skb); @@ -548,8 +557,8 @@ static void gem_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct net_device *dev = (struct net_device *) dev_id; - struct gem *gp = (struct gem *) dev->priv; + struct net_device *dev = dev_id; + struct gem *gp = dev->priv; u32 gem_status = readl(gp->regs + GREG_STAT); spin_lock(&gp->lock); @@ -567,9 +576,36 @@ spin_unlock(&gp->lock); } +static void gem_tx_timeout(struct net_device *dev) +{ + struct gem *gp = dev->priv; + + printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); + printk(KERN_ERR "%s: TX_STATE[%08x:%08x:%08x]\n", + dev->name, + readl(gp->regs + TXDMA_CFG), + readl(gp->regs + MAC_TXSTAT), + readl(gp->regs + MAC_TXCFG)); + printk(KERN_ERR "%s: RX_STATE[%08x:%08x:%08x]\n", + dev->name, + readl(gp->regs + RXDMA_CFG), + readl(gp->regs + MAC_RXSTAT), + readl(gp->regs + MAC_RXCFG)); + + spin_lock_irq(&gp->lock); + + gem_stop(gp, gp->regs); + gem_init_rings(gp, 1); + gem_init_hw(gp); + + spin_unlock_irq(&gp->lock); + + netif_wake_queue(dev); +} + static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct gem *gp = (struct gem *) dev->priv; + struct gem *gp = dev->priv; long len; int entry, avail; u32 mapping; @@ -602,6 +638,30 @@ return 0; } +/* Jumbo-grams don't seem to work :-( */ +#if 1 +#define MAX_MTU 1500 +#else +#define MAX_MTU 9000 +#endif + +static int gem_change_mtu(struct net_device *dev, int new_mtu) +{ + struct gem *gp = dev->priv; + + if (new_mtu < 0 || new_mtu > MAX_MTU) + return -EINVAL; + + spin_lock_irq(&gp->lock); + gem_stop(gp, gp->regs); + dev->mtu = new_mtu; + gem_init_rings(gp, 1); + gem_init_hw(gp); + spin_unlock_irq(&gp->lock); + + return 0; +} + #define STOP_TRIES 32 static void gem_stop(struct gem *gp, unsigned long regs) @@ -676,8 +736,29 @@ } else if (full_duplex) { val |= MAC_XIFCFG_FLED; } + + if (speed == 1000) + val |= (MAC_XIFCFG_GMII); + writel(val, gp->regs + MAC_XIFCFG); + /* If gigabit and half-duplex, enable carrier extension + * mode. Else, disable it. + */ + if (speed == 1000 && !full_duplex) { + val = readl(gp->regs + MAC_TXCFG); + writel(val | MAC_TXCFG_TCE, gp->regs + MAC_TXCFG); + + val = readl(gp->regs + MAC_RXCFG); + writel(val | MAC_RXCFG_RCE, gp->regs + MAC_RXCFG); + } else { + val = readl(gp->regs + MAC_TXCFG); + writel(val & ~MAC_TXCFG_TCE, gp->regs + MAC_TXCFG); + + val = readl(gp->regs + MAC_RXCFG); + writel(val & ~MAC_RXCFG_RCE, gp->regs + MAC_RXCFG); + } + if (gp->phy_type == phy_serialink || gp->phy_type == phy_serdes) { u32 pcs_lpa = readl(gp->regs + PCS_MIILP); @@ -689,10 +770,6 @@ val &= ~(MAC_MCCFG_SPE | MAC_MCCFG_RPE); writel(val, gp->regs + MAC_MCCFG); - /* XXX Set up PCS MII Control and Serialink Control - * XXX registers. - */ - if (!full_duplex) writel(512, gp->regs + MAC_STIME); else @@ -767,7 +844,16 @@ restart_timer = gem_mdio_link_not_up(gp); } } else { - /* XXX Code PCS support... XXX */ + u32 val = readl(gp->regs + PCS_MIISTAT); + + if (!(val & PCS_MIISTAT_LS)) + val = readl(gp->regs + PCS_MIISTAT); + + if ((val & PCS_MIISTAT_LS) == 0) { + restart_timer = 1; + } else { + gem_set_link_modes(gp); + } } if (restart_timer) { @@ -792,7 +878,7 @@ skb = gp->rx_skbs[i]; dma_addr = (u32) le64_to_cpu(rxd->buffer); pci_unmap_single(gp->pdev, dma_addr, - RX_BUF_ALLOC_SIZE, + RX_BUF_ALLOC_SIZE(gp), PCI_DMA_FROMDEVICE); dev_kfree_skb_any(skb); gp->rx_skbs[i] = NULL; @@ -834,7 +920,7 @@ struct sk_buff *skb; struct gem_rxd *rxd = &gb->rxd[i]; - skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags); + skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE(gp), gfp_flags); if (!skb) { rxd->buffer = 0; rxd->status_word = 0; @@ -845,10 +931,10 @@ skb->dev = dev; skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET)); dma_addr = pci_map_single(gp->pdev, skb->data, - RX_BUF_ALLOC_SIZE, + RX_BUF_ALLOC_SIZE(gp), PCI_DMA_FROMDEVICE); rxd->buffer = cpu_to_le64(dma_addr); - rxd->status_word = cpu_to_le64(RXDCTRL_FRESH); + rxd->status_word = cpu_to_le64(RXDCTRL_FRESH(gp)); skb_reserve(skb, RX_OFFSET); } @@ -863,15 +949,19 @@ static void gem_init_phy(struct gem *gp) { if (gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) { + u32 val; + /* Init datapath mode register. */ if (gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) { - writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE); + val = PCS_DMODE_MGM; } else if (gp->phy_type == phy_serialink) { - writel(PCS_DMODE_SM, gp->regs + PCS_DMODE); + val = PCS_DMODE_SM | PCS_DMODE_GMOE; } else { - writel(PCS_DMODE_ESM, gp->regs + PCS_DMODE); + val = PCS_DMODE_ESM; } + + writel(val, gp->regs + PCS_DMODE); } if (gp->phy_type == phy_mii_mdio0 || @@ -899,7 +989,59 @@ val |= (PHY_CTRL_ANRES | PHY_CTRL_ANENAB); phy_write(gp, PHY_CTRL, val); } else { - /* XXX Implement me XXX */ + u32 val; + int limit; + + /* Reset PCS unit. */ + val = readl(gp->regs + PCS_MIICTRL); + val |= PCS_MIICTRL_RST; + writeb(val, gp->regs + PCS_MIICTRL); + + limit = 32; + while (readl(gp->regs + PCS_MIICTRL) & PCS_MIICTRL_RST) { + udelay(100); + if (limit-- <= 0) + break; + } + if (limit <= 0) + printk(KERN_WARNING "%s: PCS reset bit would not clear.\n", + gp->dev->name); + + /* Make sure PCS is disabled while changing advertisement + * configuration. + */ + val = readl(gp->regs + PCS_CFG); + val &= ~(PCS_CFG_ENABLE | PCS_CFG_TO); + writel(val, gp->regs + PCS_CFG); + + /* Advertise all capabilities. */ + val = readl(gp->regs + PCS_MIIADV); + val |= (PCS_MIIADV_FD | PCS_MIIADV_HD | + PCS_MIIADV_SP | PCS_MIIADV_AP); + writel(val, gp->regs + PCS_MIIADV); + + /* Enable and restart auto-negotiation, disable wrapback/loopback, + * and re-enable PCS. + */ + val = readl(gp->regs + PCS_MIICTRL); + val |= (PCS_MIICTRL_RAN | PCS_MIICTRL_ANE); + val &= ~PCS_MIICTRL_WB; + writel(val, gp->regs + PCS_MIICTRL); + + val = readl(gp->regs + PCS_CFG); + val |= PCS_CFG_ENABLE; + writel(val, gp->regs + PCS_CFG); + + /* Make sure serialink loopback is off. The meaning + * of this bit is logically inverted based upon whether + * you are in Serialink or SERDES mode. + */ + val = readl(gp->regs + PCS_SCTRL); + if (gp->phy_type == phy_serialink) + val &= ~PCS_SCTRL_LOOP; + else + val |= PCS_SCTRL_LOOP; + writel(val, gp->regs + PCS_SCTRL); } } @@ -907,7 +1049,7 @@ { u32 val; - val = (TXDMA_CFG_BASE | (0x4ff << 10) | TXDMA_CFG_PMODE); + val = (TXDMA_CFG_BASE | (0x7ff << 10) | TXDMA_CFG_PMODE); writel(val, gp->regs + TXDMA_CFG); writel(0, gp->regs + TXDMA_DBHI); @@ -916,7 +1058,7 @@ writel(0, gp->regs + TXDMA_KICK); val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) | - ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128); + ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_512); writel(val, gp->regs + RXDMA_CFG); writel(0, gp->regs + RXDMA_DBHI); @@ -931,12 +1073,12 @@ writel(val, gp->regs + RXDMA_PTHRESH); if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN) - writel(((5 & RXDMA_BLANK_IPKTS) | - ((8 << 12) & RXDMA_BLANK_ITIME)), + writel(((6 & RXDMA_BLANK_IPKTS) | + ((4 << 12) & RXDMA_BLANK_ITIME)), gp->regs + RXDMA_BLANK); else - writel(((5 & RXDMA_BLANK_IPKTS) | - ((4 << 12) & RXDMA_BLANK_ITIME)), + writel(((6 & RXDMA_BLANK_IPKTS) | + ((2 << 12) & RXDMA_BLANK_ITIME)), gp->regs + RXDMA_BLANK); } @@ -955,7 +1097,7 @@ writel(0x04, gp->regs + MAC_IPG2); writel(0x40, gp->regs + MAC_STIME); writel(0x40, gp->regs + MAC_MINFSZ); - writel(0x5ee, gp->regs + MAC_MAXFSZ); + writel(0x20000000 | (gp->dev->mtu + 18), gp->regs + MAC_MAXFSZ); writel(0x07, gp->regs + MAC_PASIZE); writel(0x04, gp->regs + MAC_JAMSIZE); writel(0x10, gp->regs + MAC_ATTLIM); @@ -1097,7 +1239,7 @@ static int gem_open(struct net_device *dev) { - struct gem *gp = (struct gem *) dev->priv; + struct gem *gp = dev->priv; unsigned long regs = gp->regs; del_timer(&gp->link_timer); @@ -1117,6 +1259,9 @@ { struct gem *gp = dev->priv; + del_timer(&gp->link_timer); + gem_stop(gp, gp->regs); + gem_clean_rings(gp); free_irq(gp->pdev->irq, (void *)dev); return 0; } @@ -1263,13 +1408,17 @@ /* Determine initial PHY interface type guess. MDIO1 is the * external PHY and thus takes precedence over MDIO0. */ - if (mif_cfg & MIF_CFG_MDI1) + if (mif_cfg & MIF_CFG_MDI1) { gp->phy_type = phy_mii_mdio1; - else if (mif_cfg & MIF_CFG_MDI0) + mif_cfg |= MIF_CFG_PSELECT; + writel(mif_cfg, gp->regs + MIF_CFG); + } else if (mif_cfg & MIF_CFG_MDI0) { gp->phy_type = phy_mii_mdio0; - else + mif_cfg &= ~MIF_CFG_PSELECT; + writel(mif_cfg, gp->regs + MIF_CFG); + } else { gp->phy_type = phy_serialink; - + } if (gp->phy_type == phy_mii_mdio1 || gp->phy_type == phy_mii_mdio0) { int i; @@ -1279,6 +1428,13 @@ if (phy_read(gp, PHY_CTRL) != 0xffff) break; } + if (i == 32) { + if (pdev->device != PCI_DEVICE_ID_SUN_GEM) { + printk(KERN_ERR PFX "RIO MII phy will not respond.\n"); + return -1; + } + gp->phy_type = phy_serdes; + } } /* Fetch the FIFO configurations now too. */ @@ -1309,23 +1465,50 @@ if (gp->rx_fifo_sz <= (2 * 1024)) { gp->rx_pause_off = gp->rx_pause_on = gp->rx_fifo_sz; } else { - int off = ((gp->rx_fifo_sz * 3) / 4); - int on = off - (1 * 1024); + int off = (gp->rx_fifo_sz - (5 * 1024)); + int on = off - 1024; gp->rx_pause_off = off; gp->rx_pause_on = on; } { - u32 bifcfg = readl(gp->regs + GREG_BIFCFG); + u32 cfg = readl(gp->regs + GREG_BIFCFG); + + cfg |= GREG_BIFCFG_B64DIS; + writel(cfg, gp->regs + GREG_BIFCFG); - bifcfg |= GREG_BIFCFG_B64DIS; - writel(bifcfg, gp->regs + GREG_BIFCFG); + cfg = GREG_CFG_IBURST; + cfg |= ((31 << 1) & GREG_CFG_TXDMALIM); + cfg |= ((31 << 6) & GREG_CFG_RXDMALIM); + writel(cfg, gp->regs + GREG_CFG); } return 0; } +static void __devinit gem_get_device_address(struct gem *gp) +{ + struct net_device *dev = gp->dev; + struct pci_dev *pdev = gp->pdev; + +#ifdef __sparc__ + struct pcidev_cookie *pcp = pdev->sysdata; + int node = -1; + + if (pcp != NULL) { + node = pcp->prom_node; + if (prom_getproplen(node, "local-mac-address") == 6) + prom_getproperty(node, "local-mac-address", + dev->dev_addr, 6); + else + node = -1; + } + if (node == -1) + memcpy(dev->dev_addr, idprom->id_ethaddr, 6); +#endif +} + static int __devinit gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1352,6 +1535,7 @@ printk(KERN_ERR PFX "Etherdev init failed, aborting.\n"); return -ENOMEM; } + SET_MODULE_OWNER(dev); if (!request_mem_region(gemreg_base, gemreg_len, dev->name)) { printk(KERN_ERR PFX "MMIO resource (0x%lx@0x%lx) unavailable, " @@ -1372,6 +1556,7 @@ gp->pdev = pdev; dev->base_addr = (long) pdev; + gp->dev = dev; spin_lock_init(&gp->lock); @@ -1402,9 +1587,7 @@ printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ", dev->name); -#ifdef __sparc__ - memcpy(dev->dev_addr, idprom->id_ethaddr, 6); -#endif + gem_get_device_address(gp); for (i = 0; i < 6; i++) printk("%2.2x%c", dev->dev_addr[i], @@ -1415,13 +1598,15 @@ gp->link_timer.function = gem_link_timer; gp->link_timer.data = (unsigned long) gp; - gp->dev = dev; dev->open = gem_open; dev->stop = gem_close; dev->hard_start_xmit = gem_start_xmit; dev->get_stats = gem_get_stats; dev->set_multicast_list = gem_set_multicast; dev->do_ioctl = gem_ioctl; + dev->tx_timeout = gem_tx_timeout; + dev->watchdog_timeo = 5 * HZ; + dev->change_mtu = gem_change_mtu; dev->irq = pdev->irq; dev->dma = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/sungem.h linux.ac/drivers/net/sungem.h --- linux.vanilla/drivers/net/sungem.h Tue Apr 3 17:32:14 2001 +++ linux.ac/drivers/net/sungem.h Sat Apr 14 01:25:23 2001 @@ -1,4 +1,4 @@ -/* $Id: sungem.h,v 1.5 2001/03/21 23:02:04 davem Exp $ +/* $Id: sungem.h,v 1.7 2001/04/04 14:49:40 davem Exp $ * sungem.h: Definitions for Sun GEM ethernet driver. * * Copyright (C) 2000 David S. Miller (davem@redhat.com) @@ -727,7 +727,10 @@ #define PCS_DMODE_MGM 0x00000004 /* MII/GMII mode */ #define PCS_DMODE_GMOE 0x00000008 /* GMII Output Enable */ -/* Serialink Control Register. */ +/* Serialink Control Register. + * + * NOTE: When in SERDES mode, the loopback bit has inverse logic. + */ #define PCS_SCTRL_LOOP 0x00000001 /* Loopback enable */ #define PCS_SCTRL_ESCD 0x00000002 /* Enable sync char detection */ #define PCS_SCTRL_LOCK 0x00000004 /* Lock to reference clock */ @@ -837,8 +840,8 @@ #define RXDCTRL_ALTMAC 0x2000000000000000 /* Matched ALT MAC */ #define RXDCTRL_BAD 0x4000000000000000 /* Frame has bad CRC */ -#define RXDCTRL_FRESH \ - ((((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16) & RXDCTRL_BUFSZ) | \ +#define RXDCTRL_FRESH(gp) \ + ((((RX_BUF_ALLOC_SIZE(gp) - RX_OFFSET) << 16) & RXDCTRL_BUFSZ) | \ RXDCTRL_OWN) #define TX_RING_SIZE 128 @@ -897,7 +900,7 @@ (GP)->tx_old - (GP)->tx_new - 1) #define RX_OFFSET 2 -#define RX_BUF_ALLOC_SIZE (1546 + RX_OFFSET + 64) +#define RX_BUF_ALLOC_SIZE(gp) ((gp)->dev->mtu + 46 + RX_OFFSET + 64) #define RX_COPY_THRESHOLD 256 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/sunhme.c linux.ac/drivers/net/sunhme.c --- linux.vanilla/drivers/net/sunhme.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/sunhme.c Sat Apr 14 01:26:31 2001 @@ -1,4 +1,4 @@ -/* $Id: sunhme.c,v 1.105 2000/12/05 02:00:36 anton Exp $ +/* $Id: sunhme.c,v 1.115 2001/03/29 06:37:09 davem Exp $ * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching, * auto carrier detecting ethernet driver. Also known as the * "Happy Meal Ethernet" found on SunSwift SBUS cards. @@ -1277,12 +1277,23 @@ struct sk_buff *skb = hp->tx_skbs[i]; struct happy_meal_txd *txd; u32 dma_addr; + int frag; - txd = &hp->happy_block->happy_meal_txd[i]; - dma_addr = hme_read_desc32(hp, &txd->tx_addr); - hme_dma_unmap(hp, dma_addr, skb->len, DMA_TODEVICE); - dev_kfree_skb_any(skb); hp->tx_skbs[i] = NULL; + + for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) { + txd = &hp->happy_block->happy_meal_txd[i]; + dma_addr = hme_read_desc32(hp, &txd->tx_addr); + hme_dma_unmap(hp, dma_addr, + (hme_read_desc32(hp, &txd->tx_flags) + & TXFLAG_SIZE), + DMA_TODEVICE); + + if (frag != skb_shinfo(skb)->nr_frags) + i++; + } + + dev_kfree_skb_any(skb); } } } @@ -1842,7 +1853,7 @@ if (status & GREG_STAT_NORXD) { /* This is harmless, it just means the system is - * quite loaded and the incomming packet rate was + * quite loaded and the incoming packet rate was * faster than the interrupt handler could keep up * with. */ @@ -1958,19 +1969,40 @@ TXD(("TX<")); while (elem != hp->tx_new) { struct sk_buff *skb; - u32 flags, dma_addr; + u32 flags, dma_addr, dma_len; + int frag; TXD(("[%d]", elem)); this = &txbase[elem]; flags = hme_read_desc32(hp, &this->tx_flags); if (flags & TXFLAG_OWN) break; - dma_addr = hme_read_desc32(hp, &this->tx_addr); skb = hp->tx_skbs[elem]; - hme_dma_unmap(hp, dma_addr, skb->len, DMA_TODEVICE); + if (skb_shinfo(skb)->nr_frags) { + int last; + + last = elem + skb_shinfo(skb)->nr_frags; + last &= (TX_RING_SIZE - 1); + flags = hme_read_desc32(hp, &txbase[last].tx_flags); + if (flags & TXFLAG_OWN) + break; + } hp->tx_skbs[elem] = NULL; hp->net_stats.tx_bytes += skb->len; + for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) { + dma_addr = hme_read_desc32(hp, &this->tx_addr); + dma_len = hme_read_desc32(hp, &this->tx_flags); + + dma_len &= TXFLAG_SIZE; + hme_dma_unmap(hp, dma_addr, dma_len, DMA_TODEVICE); + + if (frag != skb_shinfo(skb)->nr_frags) { + elem = NEXT_TX(elem); + this = &txbase[elem]; + } + } + dev_kfree_skb_irq(skb); hp->net_stats.tx_packets++; @@ -2079,10 +2111,8 @@ } /* This card is _fucking_ hot... */ - if (!(csum ^ 0xffff)) - skb->ip_summed = CHECKSUM_UNNECESSARY; - else - skb->ip_summed = CHECKSUM_NONE; + skb->csum = (csum ^ 0xffff); + skb->ip_summed = CHECKSUM_HW; RXD(("len=%d csum=%4x]", len, csum)); skb->protocol = eth_type_trans(skb, dev); @@ -2104,7 +2134,7 @@ static void happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct happy_meal *hp = (struct happy_meal *) dev->priv; + struct happy_meal *hp = dev->priv; u32 happy_status = hme_read32(hp, hp->gregs + GREG_STAT); HMD(("happy_meal_interrupt: status=%08x ", happy_status)); @@ -2141,7 +2171,7 @@ for (i = 0; i < 4; i++) { struct net_device *dev = qp->happy_meals[i]; - struct happy_meal *hp = (struct happy_meal *) dev->priv; + struct happy_meal *hp = dev->priv; u32 happy_status = hme_read32(hp, hp->gregs + GREG_STAT); HMD(("quattro_interrupt: status=%08x ", happy_status)); @@ -2179,8 +2209,7 @@ static int happy_meal_open(struct net_device *dev) { - struct happy_meal *hp = (struct happy_meal *) dev->priv; - int res; + struct happy_meal *hp = dev->priv; HMD(("happy_meal_open: ")); @@ -2204,16 +2233,12 @@ } HMD(("to happy_meal_init\n")); - res = happy_meal_init(hp, 0); - if (!res) { - MOD_INC_USE_COUNT; - } - return res; + return happy_meal_init(hp, 0); } static int happy_meal_close(struct net_device *dev) { - struct happy_meal *hp = (struct happy_meal *) dev->priv; + struct happy_meal *hp = dev->priv; happy_meal_stop(hp, hp->gregs); happy_meal_clean_rings(hp); @@ -2226,9 +2251,8 @@ * time and never unregister. */ if ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO) - free_irq(dev->irq, (void *)dev); + free_irq(dev->irq, dev); - MOD_DEC_USE_COUNT; return 0; } @@ -2241,7 +2265,7 @@ #ifdef CONFIG_SBUS static void happy_meal_tx_timeout(struct net_device *dev) { - struct happy_meal *hp = (struct happy_meal *) dev->priv; + struct happy_meal *hp = dev->priv; printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name); tx_dump_log(); @@ -2256,22 +2280,79 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct happy_meal *hp = (struct happy_meal *) dev->priv; - int len, entry; - u32 mapping; - - len = skb->len; - mapping = hme_dma_map(hp, skb->data, len, DMA_TODEVICE); + struct happy_meal *hp = dev->priv; + int entry; + u32 tx_flags; + + tx_flags = TXFLAG_OWN; + if (skb->ip_summed == CHECKSUM_HW) { + u32 csum_start_off, csum_stuff_off; + + csum_start_off = (u32) (skb->h.raw - skb->data); + csum_stuff_off = (u32) ((skb->h.raw + skb->csum) - skb->data); + + tx_flags = (TXFLAG_OWN | TXFLAG_CSENABLE | + ((csum_start_off << 14) & TXFLAG_CSBUFBEGIN) | + ((csum_stuff_off << 20) & TXFLAG_CSLOCATION)); + } spin_lock_irq(&hp->happy_lock); + if (TX_BUFFS_AVAIL(hp) <= (skb_shinfo(skb)->nr_frags + 1)) { + netif_stop_queue(dev); + spin_unlock_irq(&hp->happy_lock); + return 1; + } + entry = hp->tx_new; SXD(("SX<l[%d]e[%d]>", len, entry)); hp->tx_skbs[entry] = skb; - hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry], - (TXFLAG_OWN | TXFLAG_SOP | TXFLAG_EOP | (len & TXFLAG_SIZE)), - mapping); - hp->tx_new = NEXT_TX(entry); + + if (skb_shinfo(skb)->nr_frags == 0) { + u32 mapping, len; + + len = skb->len; + mapping = hme_dma_map(hp, skb->data, len, DMA_TODEVICE); + tx_flags |= (TXFLAG_SOP | TXFLAG_EOP); + hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry], + (tx_flags | (len & TXFLAG_SIZE)), + mapping); + entry = NEXT_TX(entry); + } else { + u32 first_len, first_mapping; + int frag, first_entry = entry; + + /* We must give this initial chunk to the device last. + * Otherwise we could race with the device. + */ + first_len = skb->len - skb->data_len; + first_mapping = hme_dma_map(hp, skb->data, first_len, DMA_TODEVICE); + entry = NEXT_TX(entry); + + for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { + skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag]; + u32 len, mapping, this_txflags; + + len = this_frag->size; + mapping = hme_dma_map(hp, + ((void *) page_address(this_frag->page) + + this_frag->page_offset), + len, DMA_TODEVICE); + this_txflags = tx_flags; + if (frag == skb_shinfo(skb)->nr_frags - 1) + this_txflags |= TXFLAG_EOP; + hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry], + (this_txflags | (len & TXFLAG_SIZE)), + mapping); + entry = NEXT_TX(entry); + } + hme_write_txd(hp, &hp->happy_block->happy_meal_txd[first_entry], + (tx_flags | TXFLAG_SOP | (first_len & TXFLAG_SIZE)), + first_mapping); + } + + hp->tx_new = entry; + if (TX_BUFFS_AVAIL(hp) <= 0) netif_stop_queue(dev); @@ -2288,7 +2369,7 @@ static struct net_device_stats *happy_meal_get_stats(struct net_device *dev) { - struct happy_meal *hp = (struct happy_meal *) dev->priv; + struct happy_meal *hp = dev->priv; happy_meal_get_counters(hp, hp->bigmacregs); return &hp->net_stats; @@ -2296,7 +2377,7 @@ static void happy_meal_set_multicast(struct net_device *dev) { - struct happy_meal *hp = (struct happy_meal *) dev->priv; + struct happy_meal *hp = dev->priv; unsigned long bregs = hp->bigmacregs; struct dev_mc_list *dmi = dev->mc_list; char *addrs; @@ -2355,7 +2436,7 @@ static int happy_meal_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct happy_meal *hp = (struct happy_meal *) dev->priv; + struct happy_meal *hp = dev->priv; struct ethtool_cmd *ep_user = (struct ethtool_cmd *) rq->ifr_data; struct ethtool_cmd ecmd; @@ -2480,27 +2561,23 @@ struct sbus_bus *sbus; struct sbus_dev *sdev; struct quattro *qp; + int i; if (qfe_sbus_list == NULL) goto found; for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) { - for (sdev = qp->quattro_dev; - sdev != NULL; - sdev = sdev->next) { + for (i = 0, sdev = qp->quattro_dev; + (sdev != NULL) && (i < 4); + sdev = sdev->next, i++) { if (sdev == goal_sdev) return qp; } } for_each_sbus(sbus) { for_each_sbusdev(sdev, sbus) { - if (sdev->child != NULL) { - struct sbus_dev *p; - - for (p = sdev->child; p != NULL; p = p->next) - if (p == goal_sdev) - goto found; - } + if (sdev == goal_sdev) + goto found; } } @@ -2578,12 +2655,11 @@ #endif /* CONFIG_PCI */ #ifdef CONFIG_SBUS -static int __init happy_meal_sbus_init(struct net_device *dev, - struct sbus_dev *sdev, - int is_qfe) +static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe) { struct quattro *qp = NULL; struct happy_meal *hp; + struct net_device *dev; int i, qfe_slot = -1; if (is_qfe) { @@ -2596,13 +2672,12 @@ if (qfe_slot == 4) return -ENODEV; } - if (dev == NULL) { - dev = init_etherdev(0, sizeof(struct happy_meal)); - } else { - dev->priv = kmalloc(sizeof(struct happy_meal), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - } + + dev = init_etherdev(NULL, sizeof(struct happy_meal)); + if (!dev) + return -ENOMEM; + SET_MODULE_OWNER(dev); + if (hme_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -2637,7 +2712,7 @@ dev->dev_addr[i], i == 5 ? ' ' : ':'); printk("\n"); - hp = (struct happy_meal *) dev->priv; + hp = dev->priv; memset(hp, 0, sizeof(*hp)); hp->happy_dev = sdev; @@ -2733,6 +2808,9 @@ dev->watchdog_timeo = 5*HZ; dev->do_ioctl = &happy_meal_ioctl; + /* Happy Meal can do it all... */ + dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + dev->irq = sdev->irqs[0]; #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) @@ -2766,7 +2844,7 @@ #endif #ifdef CONFIG_PCI -static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pdev) +static int __init happy_meal_pci_init(struct pci_dev *pdev) { struct quattro *qp = NULL; #ifdef __sparc__ @@ -2774,6 +2852,7 @@ int node; #endif struct happy_meal *hp; + struct net_device *dev; unsigned long hpreg_base; int i, qfe_slot = -1; char prom_name[64]; @@ -2803,13 +2882,12 @@ if (qfe_slot == 4) return -ENODEV; } - if (dev == NULL) { - dev = init_etherdev(0, sizeof(struct happy_meal)); - } else { - dev->priv = kmalloc(sizeof(struct happy_meal), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - } + + dev = init_etherdev(NULL, sizeof(struct happy_meal)); + if (!dev) + return -ENOMEM; + SET_MODULE_OWNER(dev); + if (hme_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -2856,7 +2934,10 @@ printk(KERN_ERR "happymeal(PCI): Cannot find proper PCI device base address.\n"); return -ENODEV; } - hpreg_base = (unsigned long) ioremap(hpreg_base, 0x8000); + if ((hpreg_base = (unsigned long) ioremap(hpreg_base, 0x8000)) == 0) { + printk(KERN_ERR "happymeal(PCI): Unable to remap card memory.\n"); + return -ENODEV; + } for (i = 0; i < 6; i++) { if (macaddr[i] != 0) @@ -2941,6 +3022,9 @@ dev->irq = pdev->irq; dev->dma = 0; + /* Happy Meal can do it all... */ + dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) /* Hook up PCI register/dma accessors. */ hp->read_desc32 = pci_hme_read_desc32; @@ -2972,25 +3056,29 @@ #endif #ifdef CONFIG_SBUS -static int __init happy_meal_sbus_probe(struct net_device *dev) +static int __init happy_meal_sbus_probe(void) { struct sbus_bus *sbus; struct sbus_dev *sdev; int cards = 0; + char model[128]; for_each_sbus(sbus) { for_each_sbusdev(sdev, sbus) { char *name = sdev->prom_name; - if (cards) - dev = NULL; if (!strcmp(name, "SUNW,hme")) { cards++; - happy_meal_sbus_init(dev, sdev, 0); + prom_getstring(sdev->prom_node, "model", + model, sizeof(model)); + if (!strcmp(model, "SUNW,sbus-qfe")) + happy_meal_sbus_init(sdev, 1); + else + happy_meal_sbus_init(sdev, 0); } else if (!strcmp(name, "qfe") || !strcmp(name, "SUNW,qfe")) { cards++; - happy_meal_sbus_init(dev, sdev, 1); + happy_meal_sbus_init(sdev, 1); } } } @@ -3001,7 +3089,7 @@ #endif #ifdef CONFIG_PCI -static int __init happy_meal_pci_probe(struct net_device *dev) +static int __init happy_meal_pci_probe(void) { struct pci_dev *pdev = NULL; int cards = 0; @@ -3010,10 +3098,8 @@ PCI_DEVICE_ID_SUN_HAPPYMEAL, pdev)) != NULL) { if (pci_enable_device(pdev)) continue; - if (cards) - dev = NULL; cards++; - happy_meal_pci_init(dev, pdev); + happy_meal_pci_init(pdev); } return cards; } @@ -3021,7 +3107,6 @@ static int __init happy_meal_probe(void) { - struct net_device *dev = NULL; static int called = 0; int cards; @@ -3033,12 +3118,10 @@ cards = 0; #ifdef CONFIG_SBUS - cards += happy_meal_sbus_probe(dev); - if (cards != 0) - dev = NULL; + cards += happy_meal_sbus_probe(); #endif #ifdef CONFIG_PCI - cards += happy_meal_pci_probe(dev); + cards += happy_meal_pci_probe(); #endif if (!cards) return -ENODEV; @@ -3048,12 +3131,23 @@ static void __exit happy_meal_cleanup_module(void) { +#ifdef CONFIG_SBUS + struct quattro *last_seen_qfe = NULL; +#endif + while (root_happy_dev) { struct happy_meal *hp = root_happy_dev; struct happy_meal *next = root_happy_dev->next_module; #ifdef CONFIG_SBUS if (!(hp->happy_flags & HFLAG_PCI)) { + if (hp->happy_flags & HFLAG_QUATTRO) { + if (hp->qfe_parent != last_seen_qfe) { + free_irq(hp->dev->irq, hp->qfe_parent); + last_seen_qfe = hp->qfe_parent; + } + } + sbus_iounmap(hp->gregs, GREG_REG_SIZE); sbus_iounmap(hp->etxregs, ETX_REG_SIZE); sbus_iounmap(hp->erxregs, ERX_REG_SIZE); @@ -3071,6 +3165,7 @@ PAGE_SIZE, hp->happy_block, hp->hblock_dvma); + iounmap((void *)hp->gregs); } #endif unregister_netdev(hp->dev); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/sunhme.h linux.ac/drivers/net/sunhme.h --- linux.vanilla/drivers/net/sunhme.h Mon Dec 11 21:01:05 2000 +++ linux.ac/drivers/net/sunhme.h Tue Apr 17 18:22:49 2001 @@ -1,4 +1,4 @@ -/* $Id: sunhme.h,v 1.31 2000/11/12 10:23:30 davem Exp $ +/* $Id: sunhme.h,v 1.32 2000/12/13 18:31:47 davem Exp $ * sunhme.h: Definitions for Sparc HME/BigMac 10/100baseT ethernet driver. * Also known as the "Happy Meal". * @@ -151,7 +151,8 @@ #define ERX_CFG_SIZE128 0x00000400 /* Receive ring size == 128 */ #define ERX_CFG_SIZE256 0x00000600 /* Receive ring size == 256 */ #define ERX_CFG_RESV3 0x0000f800 /* Unused... */ -#define ERX_CFG_CSUMSTART 0x007f0000 /* Offset of checksum start */ +#define ERX_CFG_CSUMSTART 0x007f0000 /* Offset of checksum start, + * in halfwords. */ /* I'd like a Big Mac, small fries, small coke, and SparcLinux please. */ #define BMAC_XIFCFG 0x0000UL /* XIF config register */ @@ -445,14 +446,31 @@ #define TX_RING_SIZE 32 /* Must be >16 and <255, multiple of 16 */ #define RX_RING_SIZE 32 /* see ERX_CFG_SIZE* for possible values */ +#if (TX_RING_SIZE < 16 || TX_RING_SIZE > 256 || (TX_RING_SIZE % 16) != 0) +#error TX_RING_SIZE holds illegal value +#endif + #define TX_RING_MAXSIZE 256 #define RX_RING_MAXSIZE 256 -/* 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) - */ -#define ERX_CFG_DEFAULT(off) (ERX_CFG_DMAENABLE|((off)<<3)|ERX_CFG_SIZE32|(0x22<<16)) +/* We use a 14 byte offset for checksum computation. */ +#if (RX_RING_SIZE == 32) +#define ERX_CFG_DEFAULT(off) (ERX_CFG_DMAENABLE|((off)<<3)|ERX_CFG_SIZE32|((14/2)<<16)) +#else +#if (RX_RING_SIZE == 64) +#define ERX_CFG_DEFAULT(off) (ERX_CFG_DMAENABLE|((off)<<3)|ERX_CFG_SIZE64|((14/2)<<16)) +#else +#if (RX_RING_SIZE == 128) +#define ERX_CFG_DEFAULT(off) (ERX_CFG_DMAENABLE|((off)<<3)|ERX_CFG_SIZE128|((14/2)<<16)) +#else +#if (RX_RING_SIZE == 256) +#define ERX_CFG_DEFAULT(off) (ERX_CFG_DMAENABLE|((off)<<3)|ERX_CFG_SIZE256|((14/2)<<16)) +#else +#error RX_RING_SIZE holds illegal value +#endif +#endif +#endif +#endif #define NEXT_RX(num) (((num) + 1) & (RX_RING_SIZE - 1)) #define NEXT_TX(num) (((num) + 1) & (TX_RING_SIZE - 1)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/tokenring/smctr.c linux.ac/drivers/net/tokenring/smctr.c --- linux.vanilla/drivers/net/tokenring/smctr.c Tue Apr 3 17:32:15 2001 +++ linux.ac/drivers/net/tokenring/smctr.c Tue Apr 3 17:54:55 2001 @@ -5269,7 +5269,7 @@ return (POSITIVE_ACK); } -/* Reset the ring speed to the oposite of what it was. This auto-pilot +/* Reset the ring speed to the opposite of what it was. This auto-pilot * mode requires a complete reset and re-init of the adapter. */ static int smctr_set_ring_speed(struct net_device *dev) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/tulip/21142.c linux.ac/drivers/net/tulip/21142.c --- linux.vanilla/drivers/net/tulip/21142.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/tulip/21142.c Tue Apr 10 18:15:32 2001 @@ -2,14 +2,15 @@ drivers/net/tulip/21142.c Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> - Copyright 2000 The Linux Kernel Team - Written/copyright 1994-1999 by Donald Becker. + Copyright 2000,2001 The Linux Kernel Team + Written/copyright 1994-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/networking/tulip.txt for more - information on this driver. + Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + for more information on this driver, or visit the project + Web page at http://sourceforge.net/projects/tulip/ */ @@ -107,16 +108,17 @@ dev->if_port = 0; tp->nway = tp->mediasense = 1; tp->nwayset = tp->lpar = 0; + if (tp->chip_id == PNIC2) { + tp->csr6 = 0x01000000 | (tp->to_advertise & 0x0040 ? FullDuplex : 0); + return; + } if (tulip_debug > 1) printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, csr14=%8.8x.\n", dev->name, csr14); outl(0x0001, ioaddr + CSR13); udelay(100); outl(csr14, ioaddr + CSR14); - if (tp->chip_id == PNIC2) - tp->csr6 = 0x01a80000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0); - else - tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0); + tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? FullDuplex : 0); tulip_outl_csr(tp, tp->csr6, CSR6); if (tp->mtable && tp->mtable->csr15dir) { outl(tp->mtable->csr15dir, ioaddr + CSR15); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/tulip/ChangeLog linux.ac/drivers/net/tulip/ChangeLog --- linux.vanilla/drivers/net/tulip/ChangeLog Tue Apr 3 17:32:15 2001 +++ linux.ac/drivers/net/tulip/ChangeLog Tue Apr 10 18:15:44 2001 @@ -1,3 +1,80 @@ +2001-04-03 Jeff Garzik <jgarzik@mandrakesoft.com> + + * tulip_core.c: Remove code that existed when one or more of + the following defines existed. These defines were never used + by normal users in practice: TULIP_FULL_DUPLEX, + TULIP_DEFAULT_MEDIA, and TULIP_NO_MEDIA_SWITCH. + + * tulip.h, eeprom.c: Move EE_* constants from tulip.h to eeprom.c. + * tulip.h, media.c: Move MDIO_* constants from tulip.h to media.c. + + * media.c: Add barrier() to mdio_read/write's PNIC status check + loops. + +2001-04-03 Jeff Garzik <jgarzik@mandrakesoft.com> + + Merged from Becker's tulip.c 0.92t: + + * tulip.h: Add MEDIA_MASK constant for bounding medianame[] + array lookups. + * eeprom.c, media.c, timer.c, tulip_core.c: Use it. + + * media.c, tulip_core.c: mdio_{read,write} cleanup. Since this + is called [pretty much] directly from ioctl, we mask + read/write arguments to limit the values passed. + Added mii_lock. Added comet_miireg2offset and better + Comet-specific mdio_read/write code. Pay closer attention + to the bits we set in ioctl. Remove spinlocks from ioctl, + they are in mdio_read/write now. Use mask to limit + phy number in tulip_init_one's MII scan. + +2001-04-03 Jeff Garzik <jgarzik@mandrakesoft.com> + + Merged from Becker's tulip.c 0.92t: + + * 21142.c, tulip_core.c: PNIC2 MAC address and NWay fixes. + * tulip.h: Add FullDuplex constant, used in above change. + +2001-04-03 Jeff Garzik <jgarzik@mandrakesoft.com> + + * timer.c: Do not call netif_carrier_{on,off}, it is not used in + the main tree. Leave code in, disabled, as markers for future + carrier notification. + +2001-04-03 Jeff Garzik <jgarzik@mandrakesoft.com> + + Merged from Becker's tulip.c 0.92t, except for the tulip.h + whitespace cleanup: + + * interrupt.c: If Rx stops, make sure to update the + multicast filter before restarting. + * tulip.h: Add COMET_MAC_ADDR feature flag, clean up flags. + Add Accept* Rx mode bit constants. + Add mc_filter[] to driver private struct. + * tulip_core.c: Add new Comet PCI id 0x1113:0x9511. + Add COMET_MAC_ADDR feature flag to comet entry in board info array. + Prefer to test COMET_MAC_ADDR flag to testing chip_id for COMET, + when dealing with the Comet's MAC address. + Enable Tx underrun recovery for Comet chips. + Use new Accept* constants in set_rx_mode. + Prefer COMET_MAC_ADDR flag test to chip_id test in set_rx_mode. + Store built mc_filter for later use in intr handler by Comets. + +2001-04-03 Jeff Garzik <jgarzik@mandrakesoft.com> + + * tulip_core.c: Use tp->cur_tx when building the + setup frame, instead of assuming that the setup + frame is always built in slot zero. This case is + hit during PM resume. + +2001-04-03 Jeff Garzik <jgarzik@mandrakesoft.com> + + * *.c: Update file headers (copyright, urls, etc.) + * Makefile: re-order to that chip-specific modules on own line + * eeprom.c: BSS/zero-init cleanup (Andrey Panin) + * tulip_core.c: merge medianame[] update from tulip.c. + Additional arch-specific rx_copybreak, csr0 values. (various) + 2001-02-20 Jeff Garzik <jgarzik@mandrakesoft.com> * media.c (tulip_select_media): No need to initialize diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/tulip/Makefile linux.ac/drivers/net/tulip/Makefile --- linux.vanilla/drivers/net/tulip/Makefile Fri Dec 29 22:07:22 2000 +++ linux.ac/drivers/net/tulip/Makefile Tue Apr 10 18:15:44 2001 @@ -9,7 +9,9 @@ O_TARGET := tulip.o -obj-y := 21142.o eeprom.o interrupt.o media.o pnic.o timer.o tulip_core.o +obj-y := eeprom.o interrupt.o media.o \ + timer.o tulip_core.o \ + 21142.o pnic.o obj-m := $(O_TARGET) include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/tulip/eeprom.c linux.ac/drivers/net/tulip/eeprom.c --- linux.vanilla/drivers/net/tulip/eeprom.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/tulip/eeprom.c Tue Apr 10 18:15:44 2001 @@ -2,14 +2,15 @@ drivers/net/tulip/eeprom.c Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> - Copyright 2000 The Linux Kernel Team - Written/copyright 1994-1999 by Donald Becker. + Copyright 2000,2001 The Linux Kernel Team + Written/copyright 1994-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/networking/tulip.txt for more - information on this driver. + Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + for more information on this driver, or visit the project + Web page at http://sourceforge.net/projects/tulip/ */ @@ -77,9 +78,9 @@ void __devinit tulip_parse_eeprom(struct net_device *dev) { /* The last media info list parsed, for multiport boards. */ - static struct mediatable *last_mediatable = NULL; - static unsigned char *last_ee_data = NULL; - static int controller_index = 0; + static struct mediatable *last_mediatable; + static unsigned char *last_ee_data; + static int controller_index; struct tulip_private *tp = (struct tulip_private *)dev->priv; unsigned char *ee_data = tp->eeprom; int i; @@ -143,9 +144,10 @@ printk(KERN_INFO "%s: 21041 Media table, default media %4.4x (%s).\n", dev->name, media, - media & 0x0800 ? "Autosense" : medianame[media & 15]); + media & 0x0800 ? "Autosense" : medianame[media & MEDIA_MASK]); for (i = 0; i < count; i++) { - unsigned char media_code = *p++; + unsigned char media_block = *p++; + int media_code = media_block & MEDIA_MASK; if (media_code & 0x40) p += 6; printk(KERN_INFO "%s: 21041 media #%d, %s.\n", @@ -182,7 +184,7 @@ mtable->csr15dir = mtable->csr15val = 0; printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name, - media & 0x0800 ? "Autosense" : medianame[media & 15]); + media & 0x0800 ? "Autosense" : medianame[media & MEDIA_MASK]); for (i = 0; i < count; i++) { struct medialeaf *leaf = &mtable->mleaf[i]; @@ -216,7 +218,7 @@ new_advertise |= get_u16(&p[7+gpr_len+reset_len]); } else { mtable->has_nonmii = 1; - leaf->media = p[2] & 0x0f; + leaf->media = p[2] & MEDIA_MASK; /* Davicom's media number for 100BaseTX is strange */ if (tp->chip_id == DM910X && leaf->media == 1) leaf->media = 3; @@ -261,6 +263,23 @@ } } /* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/ + +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ +#define EE_CS 0x01 /* EEPROM chip select. */ +#define EE_DATA_WRITE 0x04 /* Data from the Tulip to EEPROM. */ +#define EE_WRITE_0 0x01 +#define EE_WRITE_1 0x05 +#define EE_DATA_READ 0x08 /* Data from the EEPROM chip. */ +#define EE_ENB (0x4800 | EE_CS) + +/* Delay between EEPROM clock transitions. + Even at 33Mhz current PCI implementations don't overrun the EEPROM clock. + We add a bus turn-around to insure that this remains true. */ +#define eeprom_delay() inl(ee_addr) + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_READ_CMD (6) /* Note: this routine returns extra data bits for size detection. */ int __devinit tulip_read_eeprom(long ioaddr, int location, int addr_len) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/tulip/interrupt.c linux.ac/drivers/net/tulip/interrupt.c --- linux.vanilla/drivers/net/tulip/interrupt.c Tue Apr 3 17:32:15 2001 +++ linux.ac/drivers/net/tulip/interrupt.c Thu Apr 12 17:46:42 2001 @@ -2,14 +2,15 @@ drivers/net/tulip/interrupt.c Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> - Copyright 2000 The Linux Kernel Team - Written/copyright 1994-1999 by Donald Becker. + Copyright 2000,2001 The Linux Kernel Team + Written/copyright 1994-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/networking/tulip.txt for more - information on this driver. + Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + for more information on this driver, or visit the project + Web page at http://sourceforge.net/projects/tulip/ */ @@ -300,6 +301,12 @@ tulip_restart_rxtx(tp, tp->csr6); outl(0, ioaddr + CSR1); } + if (csr5 & (RxDied | RxNoBuf)) { + if (tp->flags & COMET_MAC_ADDR) { + outl(tp->mc_filter[0], ioaddr + 0xAC); + outl(tp->mc_filter[1], ioaddr + 0xB0); + } + } if (csr5 & RxDied) { /* Missed a Rx frame. */ tp->stats.rx_errors++; tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; @@ -314,7 +321,19 @@ (tp->link_change)(dev, csr5); } if (csr5 & SytemError) { - printk(KERN_ERR "%s: (%lu) System Error occured\n", dev->name, tp->nir); + int error = (csr5 >> 23) & 7; + /* oops, we hit a PCI error. The code produced corresponds + * to the reason: + * 0 - parity error + * 1 - master abort + * 2 - target abort + * Note that on parity error, we should do a software reset + * of the chip to get it back into a sane state (according + * to the 21142/3 docs that is). + * -- rmk + */ + printk(KERN_ERR "%s: (%lu) System Error occured (%d)\n", + dev->name, tp->nir, error); } /* Clear all error sources, included undocumented ones! */ outl(0x0800f7ba, ioaddr + CSR5); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/tulip/media.c linux.ac/drivers/net/tulip/media.c --- linux.vanilla/drivers/net/tulip/media.c Tue Apr 3 17:32:15 2001 +++ linux.ac/drivers/net/tulip/media.c Tue Apr 10 18:15:44 2001 @@ -2,14 +2,15 @@ drivers/net/tulip/media.c Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> - Copyright 2000 The Linux Kernel Team - Written/copyright 1994-1999 by Donald Becker. + Copyright 2000,2001 The Linux Kernel Team + Written/copyright 1994-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/networking/tulip.txt for more - information on this driver. + Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + for more information on this driver, or visit the project + Web page at http://sourceforge.net/projects/tulip/ */ @@ -22,6 +23,25 @@ 10base2(!) packets trigger a full-duplex-request interrupt. */ #define FULL_DUPLEX_MAGIC 0x6969 +/* 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 or future 66Mhz PCI. */ +#define mdio_delay() inl(mdio_addr) + +/* Read and write the MII registers using software-generated serial + MDIO protocol. It is just different enough from the EEPROM protocol + to not share code. The maxium data clock rate is 2.5 Mhz. */ +#define MDIO_SHIFT_CLK 0x10000 +#define MDIO_DATA_WRITE0 0x00000 +#define MDIO_DATA_WRITE1 0x20000 +#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */ +#define MDIO_ENB_IN 0x40000 +#define MDIO_DATA_READ 0x80000 + +static const unsigned char comet_miireg2offset[32] = { + 0xB4, 0xB8, 0xBC, 0xC0, 0xC4, 0xC8, 0xCC, 0, 0,0,0,0, 0,0,0,0, + 0,0xD0,0,0, 0,0,0,0, 0,0,0,0, 0, 0xD4, 0xD8, 0xDC, }; + /* MII transceiver control section. Read and write the MII registers using software-generated serial @@ -32,32 +52,34 @@ { struct tulip_private *tp = (struct tulip_private *)dev->priv; int i; - int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; + int read_cmd = (0xf6 << 10) | ((phy_id & 0x1f) << 5) | location; int retval = 0; long ioaddr = dev->base_addr; long mdio_addr = ioaddr + CSR9; + unsigned long flags; + + if (location & ~0x1f) + return 0xffff; + + if (tp->chip_id == COMET && phy_id == 30) { + if (comet_miireg2offset[location]) + return inl(ioaddr + comet_miireg2offset[location]); + return 0xffff; + } + spin_lock_irqsave(&tp->mii_lock, flags); if (tp->chip_id == LC82C168) { int i = 1000; outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0); inl(ioaddr + 0xA0); inl(ioaddr + 0xA0); - while (--i > 0) + while (--i > 0) { + barrier(); if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) - return retval & 0xffff; - return 0xffff; - } - - if (tp->chip_id == COMET) { - if (phy_id == 1) { - if (location < 7) - return inl(ioaddr + 0xB4 + (location<<2)); - else if (location == 17) - return inl(ioaddr + 0xD0); - else if (location >= 29 && location <= 31) - return inl(ioaddr + 0xD4 + ((location-29)<<2)); + break; } - return 0xffff; + spin_unlock_irqrestore(&tp->mii_lock, flags); + return retval & 0xffff; } /* Establish sync by sending at least 32 logic ones. */ @@ -84,36 +106,39 @@ outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } + + spin_unlock_irqrestore(&tp->mii_lock, flags); return (retval>>1) & 0xffff; } -void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int value) +void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int val) { struct tulip_private *tp = (struct tulip_private *)dev->priv; int i; - int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; + int cmd = (0x5002 << 16) | ((phy_id & 0x1f) << 23) | (location<<18) | (val & 0xffff); long ioaddr = dev->base_addr; long mdio_addr = ioaddr + CSR9; + unsigned long flags; + + if (location & ~0x1f) + return; + + if (tp->chip_id == COMET && phy_id == 30) { + if (comet_miireg2offset[location]) + outl(val, ioaddr + comet_miireg2offset[location]); + return; + } + spin_lock_irqsave(&tp->mii_lock, flags); if (tp->chip_id == LC82C168) { int i = 1000; outl(cmd, ioaddr + 0xA0); - do + do { + barrier(); if ( ! (inl(ioaddr + 0xA0) & 0x80000000)) break; - while (--i > 0); - return; - } - - if (tp->chip_id == COMET) { - if (phy_id != 1) - return; - if (location < 7) - outl(value, ioaddr + 0xB4 + (location<<2)); - else if (location == 17) - outl(value, ioaddr + 0xD0); - else if (location >= 29 && location <= 31) - outl(value, ioaddr + 0xD4 + ((location-29)<<2)); + } while (--i > 0); + spin_unlock_irqrestore(&tp->mii_lock, flags); return; } @@ -139,6 +164,8 @@ outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } + + spin_unlock_irqrestore(&tp->mii_lock, flags); } @@ -172,7 +199,7 @@ for (i = 0; i < 5; i++) setup[i] = get_u16(&p[i*2 + 1]); - dev->if_port = p[0] & 15; + dev->if_port = p[0] & MEDIA_MASK; if (tulip_media_cap[dev->if_port] & MediaAlwaysFD) tp->full_duplex = 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/tulip/pnic.c linux.ac/drivers/net/tulip/pnic.c --- linux.vanilla/drivers/net/tulip/pnic.c Tue Apr 3 17:32:15 2001 +++ linux.ac/drivers/net/tulip/pnic.c Tue Apr 10 18:15:44 2001 @@ -2,14 +2,15 @@ drivers/net/tulip/pnic.c Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> - Copyright 2000 The Linux Kernel Team - Written/copyright 1994-1999 by Donald Becker. + Copyright 2000,2001 The Linux Kernel Team + Written/copyright 1994-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/networking/tulip.txt for more - information on this driver. + Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + for more information on this driver, or visit the project + Web page at http://sourceforge.net/projects/tulip/ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/tulip/timer.c linux.ac/drivers/net/tulip/timer.c --- linux.vanilla/drivers/net/tulip/timer.c Tue Feb 13 21:15:05 2001 +++ linux.ac/drivers/net/tulip/timer.c Tue Apr 10 18:15:44 2001 @@ -2,14 +2,15 @@ drivers/net/tulip/timer.c Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> - Copyright 2000 The Linux Kernel Team - Written/copyright 1994-1999 by Donald Becker. + Copyright 2000,2001 The Linux Kernel Team + Written/copyright 1994-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/networking/tulip.txt for more - information on this driver. + Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + for more information on this driver, or visit the project + Web page at http://sourceforge.net/projects/tulip/ */ @@ -133,13 +134,13 @@ ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) { if (tulip_debug > 2) printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name, - medianame[mleaf->media]); + medianame[mleaf->media & MEDIA_MASK]); if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */ goto actually_mii; - netif_carrier_on(dev); + /* netif_carrier_on(dev); */ break; } - netif_carrier_off(dev); + /* netif_carrier_off(dev); */ if (tp->medialock) break; select_next_media: @@ -152,9 +153,9 @@ goto select_next_media; /* Skip FD entries. */ if (tulip_debug > 1) printk(KERN_DEBUG "%s: No link beat on media %s," - " trying transceiver type %s.\n", - dev->name, medianame[mleaf->media & 15], - medianame[tp->mtable->mleaf[tp->cur_index].media]); + " trying transceiver type %s.\n", + dev->name, medianame[mleaf->media & MEDIA_MASK], + medianame[tp->mtable->mleaf[tp->cur_index].media]); tulip_select_media(dev, 0); /* Restart the transmit process. */ tulip_restart_rxtx(tp, tp->csr6); @@ -164,9 +165,9 @@ case 1: case 3: /* 21140, 21142 MII */ actually_mii: if (tulip_check_duplex(dev) < 0) - netif_carrier_off(dev); + { /* netif_carrier_off(dev); */ } else - netif_carrier_on(dev); + { /* netif_carrier_on(dev); */ } next_tick = 60*HZ; break; case 2: /* 21142 serial block has no link beat. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/tulip/tulip.h linux.ac/drivers/net/tulip/tulip.h --- linux.vanilla/drivers/net/tulip/tulip.h Tue Apr 3 17:32:15 2001 +++ linux.ac/drivers/net/tulip/tulip.h Tue Apr 17 18:30:42 2001 @@ -1,12 +1,16 @@ /* drivers/net/tulip/tulip.h - Copyright 2000 The Linux Kernel Team - Written/copyright 1994-1999 by Donald Becker. + Copyright 2000,2001 The Linux Kernel Team + Written/copyright 1994-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. + Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + for more information on this driver, or visit the project + Web page at http://sourceforge.net/projects/tulip/ + */ #ifndef __NET_TULIP_H__ @@ -46,17 +50,18 @@ enum tbl_flag { - HAS_MII = 1, - HAS_MEDIA_TABLE = 2, - CSR12_IN_SROM = 4, - ALWAYS_CHECK_MII = 8, - HAS_ACPI = 0x10, - MC_HASH_ONLY = 0x20, /* Hash-only multicast filter. */ - HAS_PNICNWAY = 0x80, - HAS_NWAY = 0x40, /* Uses internal NWay xcvr. */ - HAS_INTR_MITIGATION = 0x100, - IS_ASIX = 0x200, - HAS_8023X = 0x400, + HAS_MII = 0x0001, + HAS_MEDIA_TABLE = 0x0002, + CSR12_IN_SROM = 0x0004, + ALWAYS_CHECK_MII = 0x0008, + HAS_ACPI = 0x0010, + MC_HASH_ONLY = 0x0020, /* Hash-only multicast filter. */ + HAS_PNICNWAY = 0x0080, + HAS_NWAY = 0x0040, /* Uses internal NWay xcvr. */ + HAS_INTR_MITIGATION = 0x0100, + IS_ASIX = 0x0200, + HAS_8023X = 0x0400, + COMET_MAC_ADDR = 0x0800, }; @@ -139,6 +144,15 @@ }; +enum tulip_rx_modes { + FullDuplex = 0x0200, + AcceptBroadcast = 0x0100, + AcceptAllMulticast = 0x0080, + AcceptAllPhys = 0x0040, + AcceptRunt = 0x0008, +}; + + /* The Tulip Rx and Tx buffer descriptors. */ struct tulip_rx_desc { s32 status; @@ -236,6 +250,7 @@ #define TX_RING_SIZE 16 #define RX_RING_SIZE 32 +#define MEDIA_MASK 31 #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ @@ -251,45 +266,11 @@ #define DESC_RING_WRAP 0x02000000 -/* EEPROM_Ctrl bits. */ -#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ -#define EE_CS 0x01 /* EEPROM chip select. */ -#define EE_DATA_WRITE 0x04 /* Data from the Tulip to EEPROM. */ -#define EE_WRITE_0 0x01 -#define EE_WRITE_1 0x05 -#define EE_DATA_READ 0x08 /* Data from the EEPROM chip. */ -#define EE_ENB (0x4800 | EE_CS) - -/* Delay between EEPROM clock transitions. - Even at 33Mhz current PCI implementations don't overrun the EEPROM clock. - We add a bus turn-around to insure that this remains true. */ -#define eeprom_delay() inl(ee_addr) - -/* The EEPROM commands include the alway-set leading bit. */ -#define EE_READ_CMD (6) - #define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */ -/* 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 or future 66Mhz PCI. */ -#define mdio_delay() inl(mdio_addr) - -/* Read and write the MII registers using software-generated serial - MDIO protocol. It is just different enough from the EEPROM protocol - to not share code. The maxium data clock rate is 2.5 Mhz. */ -#define MDIO_SHIFT_CLK 0x10000 -#define MDIO_DATA_WRITE0 0x00000 -#define MDIO_DATA_WRITE1 0x20000 -#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */ -#define MDIO_ENB_IN 0x40000 -#define MDIO_DATA_READ 0x80000 - - #define RUN_AT(x) (jiffies + (x)) - #if defined(__i386__) /* AKA get_unaligned() */ #define get_u16(ptr) (*(u16 *)(ptr)) #else @@ -346,7 +327,9 @@ int flags; struct net_device_stats stats; struct timer_list timer; /* Media selection timer. */ + u32 mc_filter[2]; spinlock_t lock; + spinlock_t mii_lock; unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/tulip/tulip_core.c linux.ac/drivers/net/tulip/tulip_core.c --- linux.vanilla/drivers/net/tulip/tulip_core.c Tue Apr 3 17:32:15 2001 +++ linux.ac/drivers/net/tulip/tulip_core.c Tue Apr 10 18:15:44 2001 @@ -2,20 +2,15 @@ /* Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> - Copyright 2000 The Linux Kernel Team - Written/copyright 1994-1999 by Donald Becker. + Copyright 2000,2001 The Linux Kernel Team + Written/copyright 1994-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please read Documentation/networking/tulip.txt for more - information. - - For this specific driver variant please use linux-kernel for - bug reports. - - Additional information available at - http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html + Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + for more information on this driver, or visit the project + Web page at http://sourceforge.net/projects/tulip/ */ @@ -28,7 +23,7 @@ #include <asm/unaligned.h> static char version[] __devinitdata = - "Linux Tulip driver version 0.9.14 (February 20, 2001)\n"; + "Linux Tulip driver version 0.9.14d (April 3, 2001)\n"; /* A few user-configurable values. */ @@ -43,16 +38,19 @@ static int mtu[MAX_UNITS]; /* Jumbo MTU for interfaces. */ /* The possible media types that can be set in options[] are: */ -const char * const medianame[] = { +const char * const medianame[32] = { "10baseT", "10base2", "AUI", "100baseTx", - "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx", - "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII", - "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4", + "10baseT-FDX", "100baseTx-FDX", "100baseT4", "100baseFx", + "100baseFx-FDX", "MII 10baseT", "MII 10baseT-FDX", "MII", + "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FDX", "MII 100baseT4", + "MII 100baseFx-HDX", "MII 100baseFx-FDX", "Home-PNA 1Mbps", "Invalid-19", + "","","","", "","","","", "","","","Transceiver reset", }; /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ #if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \ - || defined(__sparc_) || defined(__ia64__) + || defined(__sparc_) || defined(__ia64__) \ + || defined(__sh__) || defined(__mips__) static int rx_copybreak = 1518; #else static int rx_copybreak = 100; @@ -81,7 +79,7 @@ * any more than that. */ static int csr0 = 0x01A00000 | 0x9000; -#elif defined(__arm__) +#elif defined(__arm__) || defined(__sh__) static int csr0 = 0x01A00000 | 0x4800; #else #warning Processor architecture undefined! @@ -162,7 +160,7 @@ /* COMET */ { "ADMtek Comet", 256, 0x0001abef, - MC_HASH_ONLY, comet_timer }, + MC_HASH_ONLY | COMET_MAC_ADDR, comet_timer }, /* COMPEX9881 */ { "Compex 9881 PMAC", 128, 0x0001ebef, @@ -204,14 +202,15 @@ { 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X }, { 0x1113, 0x1216, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x1113, 0x1217, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 }, + { 0x1113, 0x9511, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, {0, } }; MODULE_DEVICE_TABLE(pci, tulip_pci_tbl); /* A full-duplex map for media types. */ -const char tulip_media_cap[] = -{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 }; +const char tulip_media_cap[32] = +{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20, 28,31,0,0, }; u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0}; /* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/ @@ -286,6 +285,14 @@ if (tulip_debug > 1) printk(KERN_DEBUG "%s: tulip_up(), irq==%d.\n", dev->name, dev->irq); + if (tp->chip_id == PNIC2) { + u32 addr_high = (dev->dev_addr[1]<<8) + (dev->dev_addr[0]<<0); + /* This address setting does not appear to impact chip operation?? */ + outl((dev->dev_addr[5]<<8) + dev->dev_addr[4] + + (dev->dev_addr[3]<<24) + (dev->dev_addr[2]<<16), + ioaddr + 0xB0); + outl(addr_high + (addr_high<<16), ioaddr + 0xB8); + } if (tp->flags & MC_HASH_ONLY) { u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr)); u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4))); @@ -294,7 +301,7 @@ outl(addr_low, ioaddr + CSR14); outl(1, ioaddr + CSR13); outl(addr_high, ioaddr + CSR14); - } else if (tp->chip_id == COMET) { + } else if (tp->flags & COMET_MAC_ADDR) { outl(addr_low, ioaddr + 0xA4); outl(addr_high, ioaddr + 0xA8); outl(0, ioaddr + 0xAC); @@ -316,13 +323,13 @@ mapping = pci_map_single(tp->pdev, tp->setup_frame, sizeof(tp->setup_frame), PCI_DMA_TODEVICE); - tp->tx_buffers[0].skb = NULL; - tp->tx_buffers[0].mapping = mapping; + tp->tx_buffers[tp->cur_tx].skb = NULL; + tp->tx_buffers[tp->cur_tx].mapping = mapping; /* Put the setup frame on the Tx list. */ - tp->tx_ring[0].length = cpu_to_le32(0x08000000 | 192); - tp->tx_ring[0].buffer1 = cpu_to_le32(mapping); - tp->tx_ring[0].status = cpu_to_le32(DescOwned); + tp->tx_ring[tp->cur_tx].length = cpu_to_le32(0x08000000 | 192); + tp->tx_ring[tp->cur_tx].buffer1 = cpu_to_le32(mapping); + tp->tx_ring[tp->cur_tx].status = cpu_to_le32(DescOwned); tp->cur_tx++; } @@ -349,7 +356,7 @@ } } if ((tp->mtable->defaultmedia & 0x0800) == 0) { - int looking_for = tp->mtable->defaultmedia & 15; + int looking_for = tp->mtable->defaultmedia & MEDIA_MASK; for (i = 0; i < tp->mtable->leafcount; i++) if (tp->mtable->mleaf[i].media == looking_for) { printk(KERN_INFO "%s: Using EEPROM-set media %s.\n", @@ -418,7 +425,9 @@ outl(0x0000, ioaddr + CSR14); outl(0x0008, ioaddr + CSR15); } else if (tp->chip_id == COMET) { - dev->if_port = 0; + /* Enable automatic Tx underrun recovery. */ + outl(inl(ioaddr + 0x88) | 1, ioaddr + 0x88); + dev->if_port = tp->mii_cnt ? 11 : 0; tp->csr6 = 0x00040000; } else if (tp->chip_id == AX88140) { tp->csr6 = tp->mii_cnt ? 0x00040100 : 0x00000100; @@ -789,16 +798,16 @@ /* Provide ioctl() calls to examine the MII xcvr state. */ -static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = dev->priv; long ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_data; + u16 *data = (u16 *) & rq->ifr_data; int phy = tp->phys[0] & 0x1f; - long flags; + unsigned int regnum = data[1]; - switch(cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + switch (cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ if (tp->mii_cnt) data[0] = phy; else if (tp->flags & HAS_NWAY) @@ -807,42 +816,64 @@ data[0] = 1; else return -ENODEV; - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - if (data[0] == 32 && (tp->flags & HAS_NWAY)) { - int csr12 = inl(ioaddr + CSR12); - int csr14 = inl(ioaddr + CSR14); - switch (data[1]) { - case 0: { - data[3] = (csr14<<5) & 0x1000; - break; } + case SIOCDEVPRIVATE + 1: /* Read the specified MII register. */ + if (data[0] == 32 && (tp->flags & HAS_NWAY)) { + int csr12 = inl (ioaddr + CSR12); + int csr14 = inl (ioaddr + CSR14); + switch (regnum) { + case 0: + data[3] = (csr14 << 5) & 0x1000; + break; case 1: - data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0) - + (csr12&0x06 ? 0x04 : 0); + data[3] = + 0x7848 + + ((csr12 & 0x7000) == 0x5000 ? 0x20 : 0) + + (csr12 & 0x06 ? 0x04 : 0); break; - case 4: { - data[3] = ((csr14>>9)&0x07C0) + - ((inl(ioaddr + CSR6)>>3)&0x0040) + ((csr14>>1)&0x20) + 1; + case 4: + data[3] = + ((csr14 >> 9) & 0x07C0) + + ((inl (ioaddr + CSR6) >> 3) & 0x0040) + + ((csr14 >> 1) & 0x20) + 1; + break; + case 5: + data[3] = csr12 >> 16; + break; + default: + data[3] = 0; break; - } - case 5: data[3] = csr12 >> 16; break; - default: data[3] = 0; break; } } else { - spin_lock_irqsave (&tp->lock, flags); - data[3] = tulip_mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); - spin_unlock_irqrestore (&tp->lock, flags); + data[3] = tulip_mdio_read (dev, data[0] & 0x1f, regnum); } return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!capable(CAP_NET_ADMIN)) + case SIOCDEVPRIVATE + 2: /* Write the specified MII register */ + if (!capable (CAP_NET_ADMIN)) return -EPERM; - if (data[0] == 32 && (tp->flags & HAS_NWAY)) { - if (data[1] == 5) + if (regnum & ~0x1f) + return -EINVAL; + if (data[0] == phy) { + u16 value = data[2]; + switch (regnum) { + case 0: /* Check for autonegotiation on or reset. */ + tp->full_duplex_lock = (value & 0x9000) ? 0 : 1; + if (tp->full_duplex_lock) + tp->full_duplex = (value & 0x0100) ? 1 : 0; + break; + case 4: tp->to_advertise = data[2]; + break; + } + } + if (data[0] == 32 && (tp->flags & HAS_NWAY)) { + u16 value = data[2]; + if (regnum == 0) { + if ((value & 0x1200) == 0x1200) + t21142_start_nway (dev); + } else if (regnum == 4) + tp->to_advertise = value; } else { - spin_lock_irqsave (&tp->lock, flags); - tulip_mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); - spin_unlock_irqrestore(&tp->lock, flags); + tulip_mdio_write (dev, data[0] & 0x1f, regnum, data[2]); } return 0; default: @@ -967,38 +998,56 @@ tp->csr6 &= ~0x00D5; if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ - tp->csr6 |= 0x00C0; - csr6 |= 0x00C0; + tp->csr6 |= AcceptAllMulticast | AcceptAllPhys; + csr6 |= AcceptAllMulticast | AcceptAllPhys; /* Unconditionally log net taps. */ printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter well -- accept all multicasts. */ - tp->csr6 |= 0x0080; - csr6 |= 0x0080; + tp->csr6 |= AcceptAllMulticast; + csr6 |= AcceptAllMulticast; } else if (tp->flags & MC_HASH_ONLY) { /* Some work-alikes have only a 64-entry hash filter table. */ /* Should verify correctness on big-endian/__powerpc__ */ struct dev_mc_list *mclist; int i; - u32 mc_filter[2]; /* Multicast hash filter */ if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */ - tp->csr6 |= 0x0080; - csr6 |= 0x0080; + tp->csr6 |= AcceptAllMulticast; + csr6 |= AcceptAllMulticast; } else { - mc_filter[1] = mc_filter[0] = 0; + u32 mc_filter[2] = {0, 0}; /* Multicast hash filter */ + int filterbit; 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); - - if (tp->chip_id == AX88140) { + i++, mclist = mclist->next) { + if (tp->flags & COMET_MAC_ADDR) + filterbit = ether_crc_le(ETH_ALEN, mclist->dmi_addr); + else + filterbit = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; + filterbit &= 0x3f; + set_bit(filterbit, mc_filter); + if (tulip_debug > 2) { + printk(KERN_INFO "%s: Added filter for %2.2x:%2.2x:%2.2x:" + "%2.2x:%2.2x:%2.2x %8.8x bit %d.\n", dev->name, + mclist->dmi_addr[0], mclist->dmi_addr[1], + mclist->dmi_addr[2], mclist->dmi_addr[3], + mclist->dmi_addr[4], mclist->dmi_addr[5], + ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit); + } + } + if (mc_filter[0] == tp->mc_filter[0] && + mc_filter[1] == tp->mc_filter[1]) + ; /* No change. */ + else if (tp->flags & IS_ASIX) { outl(2, ioaddr + CSR13); outl(mc_filter[0], ioaddr + CSR14); outl(3, ioaddr + CSR13); outl(mc_filter[1], ioaddr + CSR14); - } else if (tp->chip_id == COMET) { /* Has a simple hash filter. */ + } else if (tp->flags & COMET_MAC_ADDR) { outl(mc_filter[0], ioaddr + 0xAC); outl(mc_filter[1], ioaddr + 0xB0); } + tp->mc_filter[0] = mc_filter[0]; + tp->mc_filter[1] = mc_filter[1]; } } else { unsigned long flags; @@ -1204,22 +1253,12 @@ tp->revision = chip_rev; tp->csr0 = csr0; spin_lock_init(&tp->lock); + spin_lock_init(&tp->mii_lock); dev->base_addr = ioaddr; dev->irq = irq; pci_set_drvdata(pdev, dev); -#ifdef TULIP_FULL_DUPLEX - tp->full_duplex = 1; - tp->full_duplex_lock = 1; -#endif -#ifdef TULIP_DEFAULT_MEDIA - tp->default_port = TULIP_DEFAULT_MEDIA; -#endif -#ifdef TULIP_NO_MEDIA_SWITCH - tp->medialock = 1; -#endif - printk(KERN_INFO "%s: %s rev %d at %#3lx,", dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); @@ -1332,15 +1371,18 @@ /* The lower four bits are the media type. */ if (board_idx >= 0 && board_idx < MAX_UNITS) { - tp->default_port = options[board_idx] & 15; - if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0) + if (options[board_idx] & MEDIA_MASK) + tp->default_port = options[board_idx] & MEDIA_MASK; + if ((options[board_idx] & FullDuplex) || full_duplex[board_idx] > 0) tp->full_duplex = 1; if (mtu[board_idx] > 0) dev->mtu = mtu[board_idx]; } - if (dev->mem_start) - tp->default_port = dev->mem_start; + if (dev->mem_start & MEDIA_MASK) + tp->default_port = dev->mem_start & MEDIA_MASK; if (tp->default_port) { + printk(KERN_INFO "%s: Transceiver selection forced to %s.\n", + dev->name, medianame[tp->default_port & MEDIA_MASK]); tp->medialock = 1; if (tulip_media_cap[tp->default_port] & MediaAlwaysFD) tp->full_duplex = 1; @@ -1365,7 +1407,7 @@ if ((tp->flags & ALWAYS_CHECK_MII) || (tp->mtable && tp->mtable->has_mii) || ( ! tp->mtable && (tp->flags & HAS_MII))) { - int phy, phy_idx; + int phyn, phy_idx = 0; if (tp->mtable && tp->mtable->has_mii) { for (i = 0; i < tp->mtable->leafcount; i++) if (tp->mtable->mleaf[i].media == 11) { @@ -1379,8 +1421,8 @@ /* Find the connected MII xcvrs. Doing this in open() would allow detecting external xcvrs later, but takes much time. */ - for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); - phy++) { + for (phyn = 1; phyn <= 32 && phy_idx < sizeof(tp->phys); phyn++) { + int phy = phyn & 0x1f; int mii_status = tulip_mdio_read(dev, phy, 1); if ((mii_status & 0x8301) == 0x8001 || ((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/wan/Config.in linux.ac/drivers/net/wan/Config.in --- linux.vanilla/drivers/net/wan/Config.in Tue Apr 3 17:32:15 2001 +++ linux.ac/drivers/net/wan/Config.in Sat Apr 14 01:28:20 2001 @@ -75,15 +75,13 @@ if [ "$CONFIG_WAN_ROUTER" != "n" ]; then bool ' WAN router drivers' CONFIG_WAN_ROUTER_DRIVERS if [ "$CONFIG_WAN_ROUTER_DRIVERS" = "y" ]; then - dep_tristate ' Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_ROUTER_DRIVERS + dep_tristate ' Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_ROUTER if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then - int ' Maximum number of cards' CONFIG_WANPIPE_CARDS 1 bool ' WANPIPE Cisco HDLC support' CONFIG_WANPIPE_CHDLC - if [ "$CONFIG_OBSOLETE" = "y" ]; then - bool ' WANPIPE Frame Relay support (OBSOLETE)' CONFIG_WANPIPE_FR - bool ' WANPIPE X.25 support (OBSOLETE)' CONFIG_WANPIPE_X25 - fi + bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR + bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP + bool ' WANPIPE Multi-Port PPP support' CONFIG_WANPIPE_MULTPPP fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' Cyclom 2X(tm) cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_ROUTER_DRIVERS diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/wan/Makefile linux.ac/drivers/net/wan/Makefile --- linux.vanilla/drivers/net/wan/Makefile Tue Apr 3 17:32:15 2001 +++ linux.ac/drivers/net/wan/Makefile Sat Apr 14 01:28:20 2001 @@ -12,11 +12,12 @@ export-objs = z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o hdlc.o list-multi = wanpipe.o cyclomx.o -wanpipe-objs = sdlamain.o $(wanpipe-y) +wanpipe-objs = sdlamain.o sdla_ft1.o $(wanpipe-y) wanpipe-$(CONFIG_WANPIPE_X25) += sdla_x25.o wanpipe-$(CONFIG_WANPIPE_FR) += sdla_fr.o wanpipe-$(CONFIG_WANPIPE_CHDLC) += sdla_chdlc.o wanpipe-$(CONFIG_WANPIPE_PPP) += sdla_ppp.o +wanpipe-$(CONFIG_WANPIPE_MULTPPP) += wanpipe_multppp.o cyclomx-objs = cycx_main.o $(cyclomx-y) cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o @@ -45,7 +46,11 @@ obj-$(CONFIG_DLCI) += dlci.o obj-$(CONFIG_SDLA) += sdla.o -obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o +ifeq ($(CONFIG_WANPIPE_MULTPPP),y) + obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o syncppp.o +else + obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o +endif obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o obj-$(CONFIG_LAPBETHER) += lapbether.o obj-$(CONFIG_SBNI) += sbni.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/wan/sdla_chdlc.c linux.ac/drivers/net/wan/sdla_chdlc.c --- linux.vanilla/drivers/net/wan/sdla_chdlc.c Tue Apr 3 17:32:16 2001 +++ linux.ac/drivers/net/wan/sdla_chdlc.c Mon Apr 16 15:13:13 2001 @@ -4,14 +4,40 @@ * Authors: Nenad Corbic <ncorbic@sangoma.com> * Gideon Hack * -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* Copyright: (c) 1995-2001 Sangoma Technologies Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ -* Feb 28, 2000 Jeff Garzik softnet updates +* Feb 28, 2001 Nenad Corbic Updated if_tx_timeout() routine for +* 2.4.X kernels. +* Jan 25, 2001 Nenad Corbic Added a TTY Sync serial driver over the +* HDLC streaming protocol +* Added a TTY Async serial driver over the +* Async protocol. +* Dec 15, 2000 Nenad Corbic Updated for 2.4.X Kernel support +* Nov 13, 2000 Nenad Corbic Added true interface type encoding option. +* Tcpdump doesn't support CHDLC inteface +* types, to fix this "true type" option will set +* the interface type to RAW IP mode. +* Nov 07, 2000 Nenad Corbic Added security features for UDP debugging: +* Deny all and specify allowed requests. +* Jun 20, 2000 Nenad Corbic Fixed the API IP ERROR bug. Caused by the +* latest update. +* May 09, 2000 Nenad Corbic Option to bring down an interface +* upon disconnect. +* Mar 23, 2000 Nenad Corbic Improved task queue, bh handling. +* Mar 16, 2000 Nenad Corbic Fixed the SLARP Dynamic IP addressing. +* Mar 06, 2000 Nenad Corbic Bug Fix: corrupted mbox recovery. +* Feb 10, 2000 Gideon Hack Added ASYNC support. +* Feb 09, 2000 Nenad Corbic Fixed two shutdown bugs in update() and +* if_stats() functions. +* Jan 24, 2000 Nenad Corbic Fixed a startup wanpipe state racing, +* condition between if_open and isr. +* Jan 10, 2000 Nenad Corbic Added new socket API support. +* Dev 15, 1999 Nenad Corbic Fixed up header files for 2.0.X kernels * Nov 20, 1999 Nenad Corbic Fixed zero length API bug. * Sep 30, 1999 Nenad Corbic Fixed dynamic IP and route setup. * Sep 23, 1999 Nenad Corbic Added SMP support, fixed tracing @@ -22,18 +48,26 @@ * Aug 07, 1998 David Fong Initial version. *****************************************************************************/ -#include <linux/config.h> #include <linux/version.h> #include <linux/kernel.h> /* printk(), and other useful stuff */ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ #include <linux/string.h> /* inline memset(), etc. */ -#include <linux/slab.h> /* kmalloc(), kfree() */ +#include <linux/malloc.h> /* kmalloc(), kfree() */ #include <linux/wanrouter.h> /* WAN router definitions */ #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ #include <linux/if_arp.h> /* ARPHRD_* defines */ -#include <linux/inetdevice.h> -#include <asm/uaccess.h> + + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + #include <asm/uaccess.h> + #include <linux/inetdevice.h> + #include <linux/netdevice.h> +#else + #include <asm/segment.h> + #include <net/route.h> /* Adding new route entries : 2.0.X kernels */ +#endif + #include <linux/in.h> /* sockaddr_in */ #include <linux/inet.h> #include <linux/if.h> @@ -42,32 +76,42 @@ #include <asm/io.h> #include <linux/sdla_chdlc.h> /* CHDLC firmware API definitions */ +#include <linux/sdla_asy.h> /* CHDLC (async) API definitions */ -/****** Defines & Macros ****************************************************/ +#include <linux/if_wanpipe_common.h> /* Socket Driver common area */ +#include <linux/if_wanpipe.h> + +/* TTY Includes */ +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/serial.h> -#ifdef _DEBUG_ -#define STATIC -#else -#define STATIC static -#endif + +/****** Defines & Macros ****************************************************/ /* reasons for enabling the timer interrupt on the adapter */ -#define TMR_INT_ENABLED_UDP 0x0001 -#define TMR_INT_ENABLED_UPDATE 0x0002 - +#define TMR_INT_ENABLED_UDP 0x01 +#define TMR_INT_ENABLED_UPDATE 0x02 +#define TMR_INT_ENABLED_CONFIG 0x10 + +#define MAX_IP_ERRORS 10 + +#define TTY_CHDLC_MAX_MTU 2000 #define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ #define CHDLC_HDR_LEN 1 -#define IFF_POINTTOPOINT 0x10 - -#define WANPIPE 0x00 -#define API 0x01 #define CHDLC_API 0x01 #define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) +#define MAX_BH_BUFF 10 + +//#define PRINT_DEBUG +#ifdef PRINT_DEBUG +#define dbg_printk(format, a...) printk(format, ## a) +#else +#define dbg_printk(format, a...) +#endif -#define TX_TIMEOUT (5*HZ) - /******Data Structures*****************************************************/ /* This structure is placed in the private data area of the device structure. @@ -77,9 +121,7 @@ typedef struct chdlc_private_area { - /* This member must be first. */ - struct net_device *slave; /* WAN slave */ - + wanpipe_common_t common; sdla_t *card; int TracingEnabled; /* For enabling Tracing */ unsigned long curr_trace_addr; /* Used for Tracing */ @@ -96,12 +138,38 @@ unsigned long router_up_time; u32 IP_address; /* IP addressing */ u32 IP_netmask; + u32 ip_local; + u32 ip_remote; + u32 ip_local_tmp; + u32 ip_remote_tmp; + u8 ip_error; + u8 config_chdlc; + u8 config_chdlc_timeout; unsigned char mc; /* Mulitcast support on/off */ unsigned short udp_pkt_lgth; /* udp packet processing */ char udp_pkt_src; char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; unsigned short timer_int_enabled; char update_comms_stats; /* updating comms stats */ + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + bh_data_t *bh_head; /* Circular buffer for chdlc_bh */ + unsigned long tq_working; + volatile int bh_write; + volatile int bh_read; + atomic_t bh_buff_used; +#endif + + unsigned char interface_down; + + /* Polling task queue. Each interface + * has its own task queue, which is used + * to defer events from the interrupt */ + struct tq_struct poll_task; + struct timer_list poll_delay_timer; + + u8 gateway; + u8 true_if_encoding; //FIXME: add driver stats as per frame relay! } chdlc_private_area_t; @@ -125,41 +193,47 @@ /****** Function Prototypes *************************************************/ /* WAN link driver entry points. These are called by the WAN router module. */ static int update (wan_device_t* wandev); -static int new_if (wan_device_t* wandev, struct net_device* dev, +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf); -static int del_if (wan_device_t* wandev, struct net_device* dev); /* Network device interface */ -static int if_init (struct net_device* dev); -static int if_open (struct net_device* dev); -static int if_close (struct net_device* dev); -static void if_tx_timeout (struct net_device *dev); -static int if_header (struct sk_buff* skb, struct net_device* dev, +static int if_init (netdevice_t* dev); +static int if_open (netdevice_t* dev); +static int if_close (netdevice_t* dev); +static int if_header (struct sk_buff* skb, netdevice_t* dev, unsigned short type, void* daddr, void* saddr, unsigned len); -#ifdef LINUX_2_1 -static int if_rebuild_hdr (struct sk_buff *skb); + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + static int if_rebuild_hdr (struct sk_buff *skb); + static struct net_device_stats* if_stats (netdevice_t* dev); + #else -static int if_rebuild_hdr (void* hdr, struct net_device* dev, unsigned long raddr, + static int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr, struct sk_buff* skb); + static struct enet_statistics* if_stats (netdevice_t* dev); #endif -static int if_send (struct sk_buff* skb, struct net_device* dev); -static struct net_device_stats* if_stats (struct net_device* dev); + +static int if_send (struct sk_buff* skb, netdevice_t* dev); /* CHDLC Firmware interface functions */ static int chdlc_configure (sdla_t* card, void* data); static int chdlc_comm_enable (sdla_t* card); -static int chdlc_comm_disable (sdla_t* card); static int chdlc_read_version (sdla_t* card, char* str); static int chdlc_set_intr_mode (sdla_t* card, unsigned mode); static int chdlc_send (sdla_t* card, void* data, unsigned len); static int chdlc_read_comm_err_stats (sdla_t* card); static int chdlc_read_op_stats (sdla_t* card); +static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); + +static int chdlc_disable_comm_shutdown (sdla_t *card); +#ifdef LINUX_2_4 + static void if_tx_timeout (netdevice_t *dev); +#endif /* Miscellaneous CHDLC Functions */ static int set_chdlc_config (sdla_t* card); -static void init_chdlc_tx_rx_buff( sdla_t* card, struct net_device *dev ); -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); +static void init_chdlc_tx_rx_buff( sdla_t* card); static int process_chdlc_exception(sdla_t *card); static int process_global_exception(sdla_t *card); static int update_comms_stats(sdla_t* card, @@ -168,23 +242,40 @@ static int unconfigure_ip (sdla_t* card); static void process_route(sdla_t *card); static void port_set_state (sdla_t *card, int); +static int config_chdlc (sdla_t *card); +static void disable_comm (sdla_t *card); + +static void trigger_chdlc_poll (netdevice_t *); +static void chdlc_poll (netdevice_t *); +static void chdlc_poll_delay (unsigned long dev_ptr); + +/* Miscellaneous asynchronous interface Functions */ +static int set_asy_config (sdla_t* card); +static int asy_comm_enable (sdla_t* card); /* Interrupt handlers */ static void wpc_isr (sdla_t* card); static void rx_intr (sdla_t* card); static void timer_intr(sdla_t *); +#if defined(LINUX_2_1) || defined(LINUX_2_4) + /* Bottom half handlers */ + static void chdlc_bh (netdevice_t *); + static int chdlc_bh_cleanup (netdevice_t *); + static int bh_enqueue (netdevice_t *, struct sk_buff *); +#endif + /* Miscellaneous functions */ -static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev, +static int chk_bcast_mcast_addr(sdla_t* card, netdevice_t* dev, struct sk_buff *skb); static int reply_udp( unsigned char *data, unsigned int mbox_len ); -static int intr_test( sdla_t* card, struct net_device *dev ); +static int intr_test( sdla_t* card); static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, + struct sk_buff *skb, netdevice_t* dev, chdlc_private_area_t* chdlc_priv_area); -static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, chdlc_private_area_t* chdlc_priv_area); static unsigned short calc_checksum (char *, int); static void s508_lock (sdla_t *card, unsigned long *smp_flags); @@ -192,6 +283,46 @@ static int Intr_test_counter; + +/* TTY Global Definitions */ + +#if defined(LINUX_2_4) || defined(LINUX_2_1) + +#define NR_PORTS 4 +#define WAN_TTY_MAJOR 226 +#define WAN_TTY_MINOR 0 + +#define WAN_CARD(port) (tty_card_map[port]) +#define MIN_PORT 0 +#define MAX_PORT NR_PORTS-1 + +#define CRC_LENGTH 2 + +static int wanpipe_tty_init(sdla_t *card); +static void wanpipe_tty_receive(sdla_t *, unsigned, unsigned int); +static void wanpipe_tty_trigger_poll(sdla_t *card); + +static struct tty_driver serial_driver, callout_driver; +static int serial_refcount=1; +static int tty_init_cnt=0; + +static struct serial_state 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]; + +static char tty_driver_mode=WANOPT_TTY_SYNC; + +static char *opt_decode[] = {"NONE","CRTSCTS","XONXOFF-RX", + "CRTSCTS XONXOFF-RX","XONXOFF-TX", + "CRTSCTS XONXOFF-TX","CRTSCTS XONXOFF"}; +static char *p_decode[] = {"NONE","ODD","EVEN"}; + +static void* tty_card_map[NR_PORTS] = {NULL,NULL,NULL,NULL}; + +#endif + + /****** Public Functions ****************************************************/ /*============================================================================ @@ -211,6 +342,7 @@ unsigned char port_num; int err; unsigned long max_permitted_baud = 0; + SHARED_MEMORY_INFO_STRUCT *flags; union { @@ -234,7 +366,7 @@ if (conf->comm_port != card->next->u.c.comm_port){ card->u.c.comm_port = conf->comm_port; }else{ - printk(KERN_ERR "%s: ERROR - %s port used!\n", + printk(KERN_INFO "%s: ERROR - %s port used!\n", card->wandev.name, PORT(conf->comm_port)); return -EINVAL; } @@ -242,7 +374,7 @@ card->u.c.comm_port = conf->comm_port; } }else{ - printk(KERN_ERR "%s: ERROR - Invalid Port Selected!\n", + printk(KERN_INFO "%s: ERROR - Invalid Port Selected!\n", card->wandev.name); return -EINVAL; } @@ -305,15 +437,11 @@ card->exec = NULL; card->wandev.update = &update; card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.state = WAN_DUALPORT; + card->wandev.del_if = NULL; card->wandev.udp_port = conf->udp_port; - + card->disable_comm = &disable_comm; card->wandev.new_if_cnt = 0; - /* This is for the ports link state */ - card->u.c.state = WAN_DISCONNECTED; - /* reset the number of times the 'update()' proc has been called */ card->u.c.update_call_count = 0; @@ -331,18 +459,27 @@ port_num = card->u.c.comm_port; + /* in API mode, we can configure for "receive only" buffering */ + if(card->hw.type == SDLA_S514) { + card->u.c.receive_only = conf->receive_only; + if(conf->receive_only) { + printk(KERN_INFO + "%s: Configured for 'receive only' mode\n", + card->devname); + } + } + /* Setup Port Bps */ if(card->wandev.clocking) { - - if(port_num == WANOPT_PRI) { + if((port_num == WANOPT_PRI) || card->u.c.receive_only) { /* For Primary Port 0 */ max_permitted_baud = (card->hw.type == SDLA_S514) ? PRI_MAX_BAUD_RATE_S514 : PRI_MAX_BAUD_RATE_S508; - } - else if(port_num == WANOPT_SEC) { + + }else if(port_num == WANOPT_SEC) { /* For Secondary Port 1 */ max_permitted_baud = (card->hw.type == SDLA_S514) ? @@ -357,14 +494,14 @@ printk(KERN_INFO "%s: Baud rate set to %lu bps\n", card->wandev.name, max_permitted_baud); } - card->wandev.bps = conf->bps; }else{ card->wandev.bps = 0; } /* Setup the Port MTU */ - if(port_num == WANOPT_PRI) { + if((port_num == WANOPT_PRI) || card->u.c.receive_only) { + /* For Primary Port 0 */ card->wandev.mtu = (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? @@ -387,8 +524,6 @@ mb1->command = READ_CHDLC_CONFIGURATION; err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; if(err != COMMAND_OK) { - clear_bit(1, (void*)&card->wandev.critical); - if(card->hw.type != SDLA_S514) enable_irq(card->hw.irq); @@ -406,6 +541,72 @@ ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); } + flags = card->u.c.flags; + + /* This is for the ports link state */ + card->wandev.state = WAN_DUALPORT; + card->u.c.state = WAN_DISCONNECTED; + + + if (!card->wandev.piggyback){ + int err; + + /* Perform interrupt testing */ + err = intr_test(card); + + if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { + printk(KERN_INFO "%s: Interrupt test failed (%i)\n", + card->devname, Intr_test_counter); + printk(KERN_INFO "%s: Please choose another interrupt\n", + card->devname); + return -EIO; + } + + printk(KERN_INFO "%s: Interrupt test passed (%i)\n", + card->devname, Intr_test_counter); + card->configured = 1; + } + + if ((card->tty_opt=conf->tty) == WANOPT_YES){ +#if defined(LINUX_2_4) || defined(LINUX_2_1) + int err; + card->tty_minor = conf->tty_minor; + + /* On ASYNC connections internal clocking + * is mandatory */ + if ((card->u.c.async_mode = conf->tty_mode)){ + card->wandev.clocking = 1; + } + err=wanpipe_tty_init(card); + if (err){ + return err; + } +#else + printk(KERN_INFO "%s: Error: TTY driver is not supported on 2.0.X kernels!\n", + card->devname); + return -EINVAL; +#endif + }else{ + + + if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){ + printk (KERN_INFO "%s: + Failed to set interrupt triggers!\n", + card->devname); + return -EIO; + } + + /* Mask the Timer interrupt */ + flags->interrupt_info_struct.interrupt_permission &= + ~APP_INT_ON_TIMER; + } + + /* If we are using CHDLC in backup mode, this flag will + * indicate not to look for IP addresses in config_chdlc()*/ + card->u.c.backup = conf->backup; + + printk(KERN_INFO "\n"); + return 0; } @@ -427,8 +628,8 @@ static int update (wan_device_t* wandev) { sdla_t* card = wandev->private; - struct net_device* dev = card->wandev.dev; - volatile chdlc_private_area_t* chdlc_priv_area = dev->priv; + netdevice_t* dev; + volatile chdlc_private_area_t* chdlc_priv_area; SHARED_MEMORY_INFO_STRUCT *flags; unsigned long timeout; @@ -442,10 +643,14 @@ /* more sanity checks */ if(!card->u.c.flags) return -ENODEV; - if(test_bit(1, (void*)&card->wandev.critical)) + + if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) return -EAGAIN; - if(!netif_running(dev)) + if((dev=card->wandev.dev) == NULL) + return -ENODEV; + + if((chdlc_priv_area=dev->priv) == NULL) return -ENODEV; flags = card->u.c.flags; @@ -488,13 +693,17 @@ * Return: 0 o.k. * < 0 failure (channel will not be created) */ -static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf) +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) { sdla_t* card = wandev->private; chdlc_private_area_t* chdlc_priv_area; + + printk(KERN_INFO "%s: Configuring Interface: %s\n", + card->devname, conf->name); + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { - printk(KERN_INFO "%s: invalid interface name!\n", + printk(KERN_INFO "%s: Invalid interface name!\n", card->devname); return -EINVAL; } @@ -506,9 +715,11 @@ return -ENOMEM; memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); - + chdlc_priv_area->card = card; - + chdlc_priv_area->common.sk = NULL; + chdlc_priv_area->common.func = NULL; + /* initialize data */ strcpy(card->u.c.if_name, conf->name); @@ -523,110 +734,216 @@ chdlc_priv_area->route_status = NO_ROUTE; chdlc_priv_area->route_removed = 0; - /* Setup protocol options */ - - card->u.c.protocol_options = 0; - - if (conf->ignore_dcd == WANOPT_YES){ - card->u.c.protocol_options |= IGNORE_DCD_FOR_LINK_STAT; - } + card->u.c.async_mode = conf->async_mode; + + /* setup for asynchronous mode */ + if(conf->async_mode) { + printk(KERN_INFO "%s: Configuring for asynchronous mode\n", + wandev->name); - if (conf->ignore_cts == WANOPT_YES){ - card->u.c.protocol_options |= IGNORE_CTS_FOR_LINK_STAT; - } + if(card->u.c.comm_port == WANOPT_PRI) { + printk(KERN_INFO + "%s:Asynchronous mode on secondary port only\n", + wandev->name); + kfree(chdlc_priv_area); + return -EINVAL; + } - if (conf->ignore_keepalive == WANOPT_YES) { - card->u.c.protocol_options |= IGNORE_KPALV_FOR_LINK_STAT; - card->u.c.kpalv_tx = MIN_Tx_KPALV_TIMER; - card->u.c.kpalv_rx = MIN_Rx_KPALV_TIMER; - card->u.c.kpalv_err = MIN_KPALV_ERR_TOL; + if(strcmp(conf->usedby, "WANPIPE") == 0) { + printk(KERN_INFO + "%s: Running in WANIPE Async Mode\n", wandev->name); + card->u.c.usedby = WANPIPE; + }else{ + card->u.c.usedby = API; + } - } else { /* Do not ignore keepalives */ + if(!card->wandev.clocking) { + printk(KERN_INFO + "%s: Asynch. clocking must be 'Internal'\n", + wandev->name); + kfree(chdlc_priv_area); + return -EINVAL; + } - card->u.c.kpalv_tx = - (conf->keepalive_tx_tmr - MIN_Tx_KPALV_TIMER) >= 0 ? - min (conf->keepalive_tx_tmr, MAX_Tx_KPALV_TIMER) : - DEFAULT_Tx_KPALV_TIMER; + if((card->wandev.bps < MIN_ASY_BAUD_RATE) || + (card->wandev.bps > MAX_ASY_BAUD_RATE)) { + printk(KERN_INFO "%s: Selected baud rate is invalid.\n", + wandev->name); + printk(KERN_INFO "Must be between %u and %u bps.\n", + MIN_ASY_BAUD_RATE, MAX_ASY_BAUD_RATE); + kfree(chdlc_priv_area); + return -EINVAL; + } - card->u.c.kpalv_rx = - (conf->keepalive_rx_tmr - MIN_Rx_KPALV_TIMER) >= 0 ? - min (conf->keepalive_rx_tmr, MAX_Rx_KPALV_TIMER) : - DEFAULT_Rx_KPALV_TIMER; + card->u.c.api_options = 0; + if (conf->asy_data_trans == WANOPT_YES) { + card->u.c.api_options |= ASY_RX_DATA_TRANSPARENT; + } + + card->u.c.protocol_options = 0; + if (conf->rts_hs_for_receive == WANOPT_YES) { + card->u.c.protocol_options |= ASY_RTS_HS_FOR_RX; + } + if (conf->xon_xoff_hs_for_receive == WANOPT_YES) { + card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_RX; + } + if (conf->xon_xoff_hs_for_transmit == WANOPT_YES) { + card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_TX; + } + if (conf->dcd_hs_for_transmit == WANOPT_YES) { + card->u.c.protocol_options |= ASY_DCD_HS_FOR_TX; + } + if (conf->cts_hs_for_transmit == WANOPT_YES) { + card->u.c.protocol_options |= ASY_CTS_HS_FOR_TX; + } - card->u.c.kpalv_err = - (conf->keepalive_err_margin - MIN_KPALV_ERR_TOL) >= 0 ? - min (conf->keepalive_err_margin, MAX_KPALV_ERR_TOL) : - DEFAULT_KPALV_ERR_TOL; - } + card->u.c.tx_bits_per_char = conf->tx_bits_per_char; + card->u.c.rx_bits_per_char = conf->rx_bits_per_char; + card->u.c.stop_bits = conf->stop_bits; + card->u.c.parity = conf->parity; + card->u.c.break_timer = conf->break_timer; + card->u.c.inter_char_timer = conf->inter_char_timer; + card->u.c.rx_complete_length = conf->rx_complete_length; + card->u.c.xon_char = conf->xon_char; + + } else { /* setup for synchronous mode */ + + card->u.c.protocol_options = 0; + if (conf->ignore_dcd == WANOPT_YES){ + card->u.c.protocol_options |= IGNORE_DCD_FOR_LINK_STAT; + } + if (conf->ignore_cts == WANOPT_YES){ + card->u.c.protocol_options |= IGNORE_CTS_FOR_LINK_STAT; + } + if (conf->ignore_keepalive == WANOPT_YES) { + card->u.c.protocol_options |= + IGNORE_KPALV_FOR_LINK_STAT; + card->u.c.kpalv_tx = MIN_Tx_KPALV_TIMER; + card->u.c.kpalv_rx = MIN_Rx_KPALV_TIMER; + card->u.c.kpalv_err = MIN_KPALV_ERR_TOL; + + } else { /* Do not ignore keepalives */ + card->u.c.kpalv_tx = + ((conf->keepalive_tx_tmr - MIN_Tx_KPALV_TIMER) + >= 0) ? + min(conf->keepalive_tx_tmr,MAX_Tx_KPALV_TIMER) : + DEFAULT_Tx_KPALV_TIMER; + + card->u.c.kpalv_rx = + ((conf->keepalive_rx_tmr - MIN_Rx_KPALV_TIMER) + >= 0) ? + min(conf->keepalive_rx_tmr,MAX_Rx_KPALV_TIMER) : + DEFAULT_Rx_KPALV_TIMER; + + card->u.c.kpalv_err = + ((conf->keepalive_err_margin-MIN_KPALV_ERR_TOL) + >= 0) ? + min(conf->keepalive_err_margin, + MAX_KPALV_ERR_TOL) : + DEFAULT_KPALV_ERR_TOL; + } - /* Setup slarp timer to control delay between slarps - */ - card->u.c.slarp_timer = - (conf->slarp_timer - MIN_SLARP_REQ_TIMER) >=0 ? - min (conf->slarp_timer, MAX_SLARP_REQ_TIMER) : - DEFAULT_SLARP_REQ_TIMER; + /* Setup slarp timer to control delay between slarps */ + card->u.c.slarp_timer = + ((conf->slarp_timer - MIN_SLARP_REQ_TIMER) >= 0) ? + min (conf->slarp_timer, MAX_SLARP_REQ_TIMER) : + DEFAULT_SLARP_REQ_TIMER; + +#ifdef LINUX_2_0 + if (card->u.c.slarp_timer){ + printk(KERN_INFO + "%s: Error: Dynamic IP support not available for 2.0.X kernels\n", + card->devname); + printk(KERN_INFO "%s: Defaulting to Static IP addressing\n", + card->devname); + } + card->u.c.slarp_timer=0; +#endif - /* If HDLC_STRAMING is enabled then IGNORE DCD, CTS and KEEPALIVES - * are automatically ignored - */ - if (conf->hdlc_streaming == WANOPT_YES) { - printk(KERN_INFO "%s: Enabling HDLC STREAMING Mode\n", - wandev->name); - card->u.c.protocol_options = HDLC_STREAMING_MODE; - } + if (conf->hdlc_streaming == WANOPT_YES) { + printk(KERN_INFO "%s: Enabling HDLC STREAMING Mode\n", + wandev->name); + card->u.c.protocol_options = HDLC_STREAMING_MODE; + } + if ((chdlc_priv_area->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){ + printk(KERN_INFO + "%s: Enabling, true interface type encoding.\n", + card->devname); + } + + /* Setup wanpipe as a router (WANPIPE) or as an API */ + if( strcmp(conf->usedby, "WANPIPE") == 0) { - /* Setup wanpipe as a router (WANPIPE) or as an API */ - if( strcmp(conf->usedby, "WANPIPE") == 0) { - printk(KERN_INFO "%s: Running in WANPIPE mode !\n",wandev->name); - card->u.c.usedby = WANPIPE; - - } else if( strcmp(conf->usedby, "API") == 0){ - -#ifdef CHDLC_API - card->u.c.usedby = API; - printk(KERN_INFO "%s: Running in API mode !\n",wandev->name); + printk(KERN_INFO "%s: Running in WANPIPE mode!\n", + wandev->name); + card->u.c.usedby = WANPIPE; + + /* Option to bring down the interface when + * the link goes down */ + if (conf->if_down){ + set_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down); + printk(KERN_INFO + "%s: Dynamic interface configuration enabled\n", + card->devname); + } + + } else if( strcmp(conf->usedby, "API") == 0) { +#if defined(LINUX_2_1) || defined(LINUX_2_4) + card->u.c.usedby = API; + printk(KERN_INFO "%s: Running in API mode !\n", + wandev->name); #else - printk(KERN_INFO "%s: API Mode is not supported!\n", - wandev->name); - printk(KERN_INFO "%s: Chdlc API patch can be obtained from Sangoma Tech.\n", - wandev->name); - kfree(chdlc_priv_area); - return -EINVAL; + printk(KERN_INFO "%s: API Mode is not supported for kernels lower than 2.2.X!\n", + wandev->name); + printk(KERN_INFO "%s: Please upgrade to a 2.2.X kernel fro the API support\n", + wandev->name); + kfree(chdlc_priv_area); + return -EINVAL; #endif + } } +#if defined(LINUX_2_1) || defined(LINUX_2_4) + /* Tells us that if this interface is a + * gateway or not */ + if ((chdlc_priv_area->gateway = conf->gateway) == WANOPT_YES){ + printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", + card->devname,card->u.c.if_name); + } +#endif /* Get Multicast Information */ chdlc_priv_area->mc = conf->mc; /* prepare network device data space for registration */ - strcpy(dev->name, card->u.c.if_name); +#ifdef LINUX_2_4 + strcpy(dev->name,card->u.c.if_name); +#else + dev->name = (char *)kmalloc(strlen(card->u.c.if_name) + 2, GFP_KERNEL); + sprintf(dev->name, "%s", card->u.c.if_name); +#endif + dev->init = &if_init; dev->priv = chdlc_priv_area; - return 0; -} - -/*============================================================================ - * Delete logical channel. - */ -static int del_if (wan_device_t* wandev, struct net_device* dev) -{ - -/* FIXME: This code generates kernel panic during - router stop!. Investigate futher. - (Error is dereferencing a NULL pointer) - - if(dev->priv){ - - kfree(dev->priv); - dev->priv = NULL; + /* Initialize the polling task routine */ +#ifndef LINUX_2_4 + chdlc_priv_area->poll_task.next = NULL; +#endif + chdlc_priv_area->poll_task.sync=0; + chdlc_priv_area->poll_task.routine = (void*)(void*)chdlc_poll; + chdlc_priv_area->poll_task.data = dev; + + /* Initialize the polling delay timer */ + init_timer(&chdlc_priv_area->poll_delay_timer); + chdlc_priv_area->poll_delay_timer.data = (unsigned long)dev; + chdlc_priv_area->poll_delay_timer.function = chdlc_poll_delay; + + printk(KERN_INFO "\n"); - } -*/ return 0; } @@ -640,12 +957,12 @@ * interface registration. Returning anything but zero will fail interface * registration. */ -static int if_init (struct net_device* dev) +static int if_init (netdevice_t* dev) { chdlc_private_area_t* chdlc_priv_area = dev->priv; sdla_t* card = chdlc_priv_area->card; wan_device_t* wandev = &card->wandev; -#ifndef LINUX_2_1 +#ifdef LINUX_2_0 int i; #endif @@ -656,22 +973,41 @@ dev->rebuild_header = &if_rebuild_hdr; dev->hard_start_xmit = &if_send; dev->get_stats = &if_stats; +#ifdef LINUX_2_4 dev->tx_timeout = &if_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#endif + /* Initialize media-specific parameters */ - dev->flags |= IFF_POINTTOPOINT; + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; /* Enable Mulitcasting if user selected */ if (chdlc_priv_area->mc == WANOPT_YES){ dev->flags |= IFF_MULTICAST; } - -#ifndef LINUX_2_1 + +#ifdef LINUX_2_0 dev->family = AF_INET; #endif - dev->type = ARPHRD_PPP; /* ARP hw type -- dummy value */ + + if (chdlc_priv_area->true_if_encoding){ +#if defined(LINUX_2_1) || defined(LINUX_2_4) + dev->type = ARPHRD_HDLC; /* This breaks the tcpdump */ +#else + dev->type = ARPHRD_PPP; +#endif + }else{ + dev->type = ARPHRD_PPP; + } + dev->mtu = card->wandev.mtu; + /* for API usage, add the API header size to the requested MTU size */ + if(card->u.c.usedby == API) { + dev->mtu += sizeof(api_tx_hdr_t); + } + dev->hard_header_len = CHDLC_HDR_LEN; /* Initialize hardware parameters */ @@ -688,13 +1024,12 @@ dev->tx_queue_len = 100; /* Initialize socket buffers */ -#ifdef LINUX_2_1 +#if defined(LINUX_2_1) || defined(LINUX_2_4) dev_init_buffers(dev); #else for (i = 0; i < DEV_NUMBUFFS; ++i) skb_queue_head_init(&dev->buffs[i]); #endif - return 0; } @@ -705,85 +1040,63 @@ * * Return 0 if O.k. or errno. */ -static int if_open (struct net_device* dev) +static int if_open (netdevice_t* dev) { chdlc_private_area_t* chdlc_priv_area = dev->priv; sdla_t* card = chdlc_priv_area->card; - SHARED_MEMORY_INFO_STRUCT* flags = card->u.c.flags; struct timeval tv; int err = 0; /* Only one open per interface is allowed */ - if(netif_running(dev)) + if (is_dev_running(dev)) return -EBUSY; - - if(test_and_set_bit(1, (void*)&card->wandev.critical)) { - return -EAGAIN; - } - - /* Setup the Board for CHDLC */ - if (set_chdlc_config(card)) { - clear_bit(1, (void*)&card->wandev.critical); - return -EIO; - } - - if (!card->configured && !card->wandev.piggyback){ - /* Perform interrupt testing */ - err = intr_test(card, dev); - - if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { - printk(KERN_ERR "%s: Interrupt test failed (%i)\n", - card->devname, Intr_test_counter); - printk(KERN_ERR "%s: Please choose another interrupt\n", - card->devname); - clear_bit(1, (void*)&card->wandev.critical); - return -EIO; - } - - printk(KERN_INFO "%s: Interrupt test passed (%i)\n", - card->devname, Intr_test_counter); - card->configured = 1; - }else{ - printk(KERN_INFO "%s: Card configured, skip interrupt test\n", - card->devname); - } - - /* Initialize Rx/Tx buffer control fields */ - init_chdlc_tx_rx_buff(card, dev); - - /* Set interrupt mode and mask */ - if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | - APP_INT_ON_GLOBAL_EXCEP_COND | - APP_INT_ON_TX_FRAME | - APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ - - clear_bit(1, (void*)&card->wandev.critical); - return -EIO; - } - - - /* Mask the Transmit and Timer interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); - - - /* Enable communications */ - if (chdlc_comm_enable(card)) { - clear_bit(1, (void*)&card->wandev.critical); - return -EIO; - } - clear_bit(1, (void*)&card->wandev.critical); +#if defined(LINUX_2_1) || defined(LINUX_2_4) + /* Initialize the task queue */ + chdlc_priv_area->tq_working=0; - port_set_state(card, WAN_CONNECTING); +#ifndef LINUX_2_4 + chdlc_priv_area->common.wanpipe_task.next = NULL; +#endif + chdlc_priv_area->common.wanpipe_task.sync = 0; + chdlc_priv_area->common.wanpipe_task.routine = (void *)(void *)chdlc_bh; + chdlc_priv_area->common.wanpipe_task.data = dev; + + /* Allocate and initialize BH circular buffer */ + /* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */ + chdlc_priv_area->bh_head = kmalloc((sizeof(bh_data_t)*(MAX_BH_BUFF+1)),GFP_ATOMIC); + memset(chdlc_priv_area->bh_head,0,(sizeof(bh_data_t)*(MAX_BH_BUFF+1))); + atomic_set(&chdlc_priv_area->bh_buff_used, 0); +#endif + do_gettimeofday(&tv); chdlc_priv_area->router_start_time = tv.tv_sec; - + +#ifdef LINUX_2_4 netif_start_queue(dev); - dev->flags |= IFF_POINTTOPOINT; +#else + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; +#endif + wanpipe_open(card); + /* TTY is configured during wanpipe_set_termios + * call, not here */ + if (card->tty_opt) + return err; + + set_bit(0,&chdlc_priv_area->config_chdlc); + chdlc_priv_area->config_chdlc_timeout=jiffies; + del_timer(&chdlc_priv_area->poll_delay_timer); + + /* Start the CHDLC configuration after 1sec delay. + * This will give the interface initilization time + * to finish its configuration */ + chdlc_priv_area->poll_delay_timer.expires=jiffies+HZ; + add_timer(&chdlc_priv_area->poll_delay_timer); return err; } @@ -792,25 +1105,76 @@ * o if this is the last close, then disable communications and interrupts. * o reset flags. */ -static int if_close (struct net_device* dev) +static int if_close (netdevice_t* dev) { chdlc_private_area_t* chdlc_priv_area = dev->priv; sdla_t* card = chdlc_priv_area->card; - if(test_and_set_bit(1, (void*)&card->wandev.critical)) - return -EAGAIN; +#if defined(LINUX_2_1) || defined(LINUX_2_4) - netif_stop_queue(dev); + if (chdlc_priv_area->bh_head){ + int i; + struct sk_buff *skb; + + for (i=0; i<(MAX_BH_BUFF+1); i++){ + skb = ((bh_data_t *)&chdlc_priv_area->bh_head[i])->skb; + if (skb != NULL){ + wan_dev_kfree_skb(skb, FREE_READ); + } + } + kfree(chdlc_priv_area->bh_head); + chdlc_priv_area->bh_head=NULL; + } +#endif + + stop_net_queue(dev); +#ifndef LINUX_2_4 + dev->start=0; +#endif wanpipe_close(card); - port_set_state(card, WAN_DISCONNECTED); - chdlc_set_intr_mode(card, 0); - chdlc_comm_disable(card); + del_timer(&chdlc_priv_area->poll_delay_timer); + return 0; +} - clear_bit(1, (void*)&card->wandev.critical); +static void disable_comm (sdla_t *card) +{ + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + + if (card->u.c.comm_enabled){ + chdlc_disable_comm_shutdown (card); + }else{ + flags->interrupt_info_struct.interrupt_permission = 0; + } - return 0; +#if defined(LINUX_2_4) || defined(LINUX_2_1) + if (!tty_init_cnt) + return; + + if (card->tty_opt){ + struct serial_state * state; + if (!(--tty_init_cnt)){ + int e1,e2; + *serial_driver.refcount=0; + + if ((e1 = tty_unregister_driver(&serial_driver))) + printk("SERIAL: failed to unregister serial driver (%d)\n", + e1); + if ((e2 = tty_unregister_driver(&callout_driver))) + printk("SERIAL: failed to unregister callout driver (%d)\n", + e2); + printk(KERN_INFO "%s: Unregistering TTY Driver, Major %i\n", + card->devname,WAN_TTY_MAJOR); + } + card->tty=NULL; + tty_card_map[card->tty_minor]=NULL; + state = &rs_table[card->tty_minor]; + memset(state,0,sizeof(state)); + } +#endif + return; } + /*============================================================================ * Build media header. * @@ -820,7 +1184,7 @@ * * Return: media header length. */ -static int if_header (struct sk_buff* skb, struct net_device* dev, +static int if_header (struct sk_buff* skb, netdevice_t* dev, unsigned short type, void* daddr, void* saddr, unsigned len) { skb->protocol = htons(type); @@ -828,49 +1192,50 @@ return CHDLC_HDR_LEN; } + +#ifdef LINUX_2_4 /*============================================================================ - * Re-build media header. + * Handle transmit timeout event from netif watchdog + */ +static void if_tx_timeout (netdevice_t *dev) +{ + chdlc_private_area_t* chan = dev->priv; + sdla_t *card = chan->card; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++card->wandev.stats.collisions; + + printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); + netif_wake_queue (dev); +} +#endif + + + +/*============================================================================ + * Re-build media header. * * Return: 1 physical address resolved. * 0 physical address not resolved */ -#ifdef LINUX_2_1 +#if defined(LINUX_2_1) || defined(LINUX_2_4) static int if_rebuild_hdr (struct sk_buff *skb) { return 1; } #else -static int if_rebuild_hdr (void* hdr, struct net_device* dev, unsigned long raddr, +static int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr, struct sk_buff* skb) { return 1; } #endif - -/*============================================================================ - * Handle transmit timeout event from netif watchdog - */ -static void if_tx_timeout (struct net_device *dev) -{ - chdlc_private_area_t *chdlc_priv_area = dev->priv; - sdla_t *card = chdlc_priv_area->card; - - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this - * is only used as a last resort. - */ - ++card->wandev.stats.collisions; - - printk (KERN_INFO "%s: Transmit timeout !\n", - card->devname); - - /* unbusy the interface */ - netif_wake_queue (dev); -} - - /*============================================================================ * Send a packet on a network interface. * o set tbusy flag (marks start of the transmission) to block a timer-based @@ -888,7 +1253,7 @@ * 2. Setting tbusy flag will inhibit further transmit requests from the * protocol stack and can be used for flow control with protocol layer. */ -static int if_send (struct sk_buff* skb, struct net_device* dev) +static int if_send (struct sk_buff* skb, netdevice_t* dev) { chdlc_private_area_t *chdlc_priv_area = dev->priv; sdla_t *card = chdlc_priv_area->card; @@ -896,33 +1261,68 @@ INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; int udp_type = 0; unsigned long smp_flags; + int err=0; - if(skb == NULL) { +#ifdef LINUX_2_4 + netif_stop_queue(dev); +#endif + + if (skb == NULL){ /* If we get here, some higher layer thinks we've missed an * tx-done interrupt. */ printk(KERN_INFO "%s: interface %s got kicked!\n", card->devname, dev->name); - netif_wake_queue(dev); + + wake_net_dev(dev); return 0; } - if(ntohs(skb->protocol) != 0x16) { +#ifndef LINUX_2_4 + if (dev->tbusy){ + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + ++card->wandev.stats.collisions; + if((jiffies - chdlc_priv_area->tick_counter) < (5 * HZ)) { + return 1; + } + + printk (KERN_INFO "%s: Transmit timeout !\n", + card->devname); + + /* unbusy the interface */ + clear_bit(0,&dev->tbusy); + } +#endif + + if (ntohs(skb->protocol) != htons(PVC_PROT)){ /* check the udp packet type */ + udp_type = udp_pkt_type(skb, card); - if(udp_type == UDP_CPIPE_TYPE) { + + if (udp_type == UDP_CPIPE_TYPE){ if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, - chdlc_priv_area)) + chdlc_priv_area)){ chdlc_int->interrupt_permission |= APP_INT_ON_TIMER; + } + start_net_queue(dev); return 0; } /* check to see if the source IP address is a broadcast or */ /* multicast IP address */ - if(chk_bcast_mcast_addr(card, dev, skb)) - return 0; + if(chk_bcast_mcast_addr(card, dev, skb)){ + ++card->wandev.stats.tx_dropped; + wan_dev_kfree_skb(skb,FREE_WRITE); + start_net_queue(dev); + return 0; + } } /* Lock the 508 Card: SMP is supported */ @@ -930,29 +1330,24 @@ s508_lock(card,&smp_flags); } - if(test_and_set_bit(0, (void*)&card->wandev.critical)) { + if(test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { printk(KERN_INFO "%s: Critical in if_send: %lx\n", card->wandev.name,card->wandev.critical); ++card->wandev.stats.tx_dropped; -#ifdef LINUX_2_1 - dev_kfree_skb(skb); -#else - dev_kfree_skb(skb, FREE_WRITE); -#endif - if(card->hw.type != SDLA_S514){ - s508_unlock(card,&smp_flags); - } - return 0; + start_net_queue(dev); + goto if_send_exit_crit; } - if(card->u.c.state != WAN_CONNECTED) + if(card->u.c.state != WAN_CONNECTED){ ++card->wandev.stats.tx_dropped; - - else if(!skb->protocol) + start_net_queue(dev); + + }else if(!skb->protocol){ ++card->wandev.stats.tx_errors; - - else { + start_net_queue(dev); + + }else { void* data = skb->data; unsigned len = skb->len; unsigned char attr; @@ -964,18 +1359,14 @@ if (card->u.c.usedby == API){ api_tx_hdr_t* api_tx_hdr; - if (len <= sizeof(api_tx_hdr_t)){ -#ifdef LINUX_2_1 - dev_kfree_skb(skb); -#else - dev_kfree_skb(skb, FREE_WRITE); -#endif + /* discard the frame if we are configured for */ + /* 'receive only' mode or if there is no data */ + if (card->u.c.receive_only || + (len <= sizeof(api_tx_hdr_t))) { + ++card->wandev.stats.tx_dropped; - clear_bit(0, (void*)&card->wandev.critical); - if(card->hw.type != SDLA_S514){ - s508_unlock(card,&smp_flags); - } - return 0; + start_net_queue(dev); + goto if_send_exit_crit; } api_tx_hdr = (api_tx_hdr_t *)data; @@ -985,24 +1376,36 @@ } if(chdlc_send(card, data, len)) { - netif_stop_queue(dev); - chdlc_priv_area->tick_counter = jiffies; - chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; - } - else { + stop_net_queue(dev); + }else{ ++card->wandev.stats.tx_packets; +#if defined(LINUX_2_1) || defined(LINUX_2_4) card->wandev.stats.tx_bytes += len; +#endif + + start_net_queue(dev); + +#ifdef LINUX_2_4 + dev->trans_start = jiffies; +#endif } } - if (!netif_queue_stopped(dev)) - dev_kfree_skb(skb); +if_send_exit_crit: + + if (!(err=is_queue_stopped(dev))) { + wan_dev_kfree_skb(skb, FREE_WRITE); + }else{ + chdlc_priv_area->tick_counter = jiffies; + chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; + } - clear_bit(0, (void*)&card->wandev.critical); + clear_bit(SEND_CRIT, (void*)&card->wandev.critical); if(card->hw.type != SDLA_S514){ s508_unlock(card,&smp_flags); } - return netif_queue_stopped(dev); + + return err; } @@ -1011,19 +1414,19 @@ * multicast source IP address. */ -static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, +static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev, struct sk_buff *skb) { u32 src_ip_addr; u32 broadcast_ip_addr = 0; -#ifdef LINUX_2_1 +#if defined(LINUX_2_1) || defined(LINUX_2_4) struct in_device *in_dev; #endif /* read the IP source address from the outgoing packet */ src_ip_addr = *(u32 *)(skb->data + 12); /* read the IP broadcast address for the device */ -#ifdef LINUX_2_1 +#if defined(LINUX_2_1) || defined(LINUX_2_4) in_dev = dev->ip_ptr; if(in_dev != NULL) { struct in_ifaddr *ifa= in_dev->ifa_list; @@ -1040,12 +1443,6 @@ if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", card->devname); -#ifdef LINUX_2_1 - dev_kfree_skb(skb); -#else - dev_kfree_skb(skb, FREE_WRITE); -#endif - ++card->wandev.stats.tx_dropped; return 1; } @@ -1054,12 +1451,6 @@ (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", card->devname); -#ifdef LINUX_2_1 - dev_kfree_skb(skb); -#else - dev_kfree_skb(skb, FREE_WRITE); -#endif - ++card->wandev.stats.tx_dropped; return 1; } @@ -1169,23 +1560,29 @@ /*============================================================================ * Get ethernet-style interface statistics. - * Return a pointer to struct net_device_stats. + * Return a pointer to struct enet_statistics. */ -#ifdef LINUX_2_1 -static struct net_device_stats* if_stats (struct net_device* dev) +#if defined(LINUX_2_1) || defined(LINUX_2_4) +static struct net_device_stats* if_stats (netdevice_t* dev) { sdla_t *my_card; - chdlc_private_area_t* chdlc_priv_area = dev->priv; + chdlc_private_area_t* chdlc_priv_area; + + if ((chdlc_priv_area=dev->priv) == NULL) + return NULL; my_card = chdlc_priv_area->card; return &my_card->wandev.stats; } #else -static struct net_device_stats* if_stats (struct net_device* dev) +static struct enet_statistics* if_stats (netdevice_t* dev) { sdla_t *my_card; chdlc_private_area_t* chdlc_priv_area = dev->priv; + if ((chdlc_priv_area=dev->priv) == NULL) + return NULL; + my_card = chdlc_priv_area->card; return &my_card->wandev.stats; } @@ -1261,44 +1658,63 @@ } -/*============================================================================ - * Enable communications. - */ +/*=========================================================== + * chdlc_disable_comm_shutdown + * + * Shutdown() disables the communications. We must + * have a sparate functions, because we must not + * call chdlc_error() hander since the private + * area has already been replaced */ -static int chdlc_comm_enable (sdla_t* card) +static int chdlc_disable_comm_shutdown (sdla_t *card) { - int err; CHDLC_MAILBOX_STRUCT* mb = card->mbox; + CHDLC_INT_TRIGGERS_STRUCT* int_data = + (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; + int err; + + /* Disable Interrutps */ + int_data->CHDLC_interrupt_triggers = 0; + int_data->IRQ = card->hw.irq; + int_data->interrupt_timer = 1; + + mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); + mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + /* Disable Communications */ + if (card->u.c.async_mode) { + mb->command = DISABLE_ASY_COMMUNICATIONS; + }else{ + mb->command = DISABLE_CHDLC_COMMUNICATIONS; + } + mb->buffer_length = 0; - mb->command = ENABLE_CHDLC_COMMUNICATIONS; err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card, err, mb); - return err; + + card->u.c.comm_enabled = 0; + + return 0; } /*============================================================================ - * Disable communications and Drop the Modem lines (DCD and RTS). + * Enable communications. */ -static int chdlc_comm_disable (sdla_t* card) + +static int chdlc_comm_enable (sdla_t* card) { int err; CHDLC_MAILBOX_STRUCT* mb = card->mbox; mb->buffer_length = 0; - mb->command = DISABLE_CHDLC_COMMUNICATIONS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card,err,mb); - - mb->command = SET_MODEM_STATUS; - mb->buffer_length = 1; - mb->data[0] = 0; + mb->command = ENABLE_CHDLC_COMMUNICATIONS; err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; if (err != COMMAND_OK) - chdlc_error(card,err,mb); - + chdlc_error(card, err, mb); + else + card->u.c.comm_enabled = 1; + return err; } @@ -1397,10 +1813,10 @@ /* Update transmit buffer control fields */ card->u.c.txbuf = ++txbuf; - + if ((void*)txbuf > card->u.c.txbuf_last) card->u.c.txbuf = card->u.c.txbuf_base; - + return 0; } @@ -1420,7 +1836,7 @@ switch (err) { case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", + printk(KERN_INFO "%s: command 0x%02X timed out!\n", card->devname, cmd); break; @@ -1440,17 +1856,112 @@ return 0; } +#if defined(LINUX_2_1) || defined(LINUX_2_4) +/********** Bottom Half Handlers ********************************************/ + +/* NOTE: There is no API, BH support for Kernels lower than 2.2.X. + * DO NOT INSERT ANY CODE HERE, NOTICE THE + * PREPROCESSOR STATEMENT ABOVE, UNLESS YOU KNOW WHAT YOU ARE + * DOING */ + +static void chdlc_bh (netdevice_t * dev) +{ + chdlc_private_area_t* chan = dev->priv; + sdla_t *card = chan->card; + struct sk_buff *skb; + + if (atomic_read(&chan->bh_buff_used) == 0){ + clear_bit(0, &chan->tq_working); + return; + } + + while (atomic_read(&chan->bh_buff_used)){ + + skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; + + if (skb != NULL){ + + if (chan->common.sk == NULL || chan->common.func == NULL){ + ++card->wandev.stats.rx_dropped; + wan_dev_kfree_skb(skb, FREE_READ); + chdlc_bh_cleanup(dev); + continue; + } + + if (chan->common.func(skb,dev,chan->common.sk) != 0){ + /* Sock full cannot send, queue us for another + * try */ + atomic_set(&chan->common.receive_block,1); + return; + }else{ + chdlc_bh_cleanup(dev); + } + }else{ + chdlc_bh_cleanup(dev); + } + } + clear_bit(0, &chan->tq_working); + + return; +} + +static int chdlc_bh_cleanup (netdevice_t *dev) +{ + chdlc_private_area_t* chan = dev->priv; + + ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; + + if (chan->bh_read == MAX_BH_BUFF){ + chan->bh_read=0; + }else{ + ++chan->bh_read; + } + + atomic_dec(&chan->bh_buff_used); + return 0; +} + + + +static int bh_enqueue (netdevice_t *dev, struct sk_buff *skb) +{ + /* Check for full */ + chdlc_private_area_t* chan = dev->priv; + sdla_t *card = chan->card; + + if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ + ++card->wandev.stats.rx_dropped; + wan_dev_kfree_skb(skb, FREE_READ); + return 1; + } + + ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; + + if (chan->bh_write == MAX_BH_BUFF){ + chan->bh_write=0; + }else{ + ++chan->bh_write; + } + + atomic_inc(&chan->bh_buff_used); + + return 0; +} + +/* END OF API BH Support */ + +#endif + /****** Interrupt Handlers **************************************************/ /*============================================================================ * Cisco HDLC interrupt service routine. */ -STATIC void wpc_isr (sdla_t* card) +static void wpc_isr (sdla_t* card) { - struct net_device* dev; - chdlc_private_area_t* chdlc_priv_area; + netdevice_t* dev; SHARED_MEMORY_INFO_STRUCT* flags = NULL; - int i, interrupt_serviced = 0; + int i; sdla_t *my_card; @@ -1462,95 +1973,97 @@ flags = card->u.c.flags; if (!flags->interrupt_info_struct.interrupt_type){ /* Check for a second port (piggybacking) */ - if((my_card = card->next)){ + if ((my_card = card->next)){ flags = my_card->u.c.flags; if (flags->interrupt_info_struct.interrupt_type){ card = my_card; + card->isr(card); + return; } } } + flags = card->u.c.flags; + card->in_isr = 1; dev = card->wandev.dev; - card->in_isr = 1; + /* If we get an interrupt with no network device, stop the interrupts + * and issue an error */ + if (!card->tty_opt && !dev && + flags->interrupt_info_struct.interrupt_type != + COMMAND_COMPLETE_APP_INT_PEND){ + + goto isr_done; + } /* if critical due to peripheral operations * ie. update() or getstats() then reset the interrupt and * wait for the board to retrigger. */ - if(test_bit(1, (void*)&card->wandev.critical)) { - if(card->u.c.flags != NULL) { - flags = card->u.c.flags; - if(flags->interrupt_info_struct. - interrupt_type) { - flags->interrupt_info_struct. - interrupt_type = 0; - } - } - card->in_isr = 0; - return; + if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { + printk(KERN_INFO "ISR CRIT TO PERI\n"); + goto isr_done; } - /* On a 508 Card, if critical due to if_send - * Major Error !!! - */ + * Major Error !!! */ if(card->hw.type != SDLA_S514) { - if(test_and_set_bit(0, (void*)&card->wandev.critical)) { + if(test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { printk(KERN_INFO "%s: Critical while in ISR: %lx\n", card->devname, card->wandev.critical); card->in_isr = 0; + flags->interrupt_info_struct.interrupt_type = 0; return; } } - /* FIXME: Take this check out later in the future */ - if(card->u.c.flags != NULL) { - - flags = card->u.c.flags; + switch(flags->interrupt_info_struct.interrupt_type) { - switch(flags->interrupt_info_struct.interrupt_type) { + case RX_APP_INT_PEND: /* 0x01: receive interrupt */ + rx_intr(card); + break; - case RX_APP_INT_PEND: /* 0x01: receive interrupt */ - interrupt_serviced = 1; - rx_intr(card); - break; + case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ + flags->interrupt_info_struct.interrupt_permission &= + ~APP_INT_ON_TX_FRAME; - case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ - interrupt_serviced = 1; - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TX_FRAME; +#if defined(LINUX_2_1) || defined(LINUX_2_4) - chdlc_priv_area = dev->priv; - netif_wake_queue(dev); + if (card->tty_opt){ + wanpipe_tty_trigger_poll(card); break; + } - case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ - interrupt_serviced = 1; - ++ Intr_test_counter; - break; + if (dev && is_queue_stopped(dev)){ + if (card->u.c.usedby == API){ + start_net_queue(dev); + wakeup_sk_bh(dev); + }else{ + wake_net_dev(dev); + } + } +#else + wake_net_dev(dev); +#endif + break; - case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ - interrupt_serviced = 1; - process_chdlc_exception(card); - break; + case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ + ++ Intr_test_counter; + break; - case GLOBAL_EXCEP_COND_APP_INT_PEND: - interrupt_serviced = 1; - process_global_exception(card); - break; + case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ + process_chdlc_exception(card); + break; - case TIMER_APP_INT_PEND: - interrupt_serviced = 1; - timer_intr(card); - break; + case GLOBAL_EXCEP_COND_APP_INT_PEND: + process_global_exception(card); + break; - default: - break; - } - } + case TIMER_APP_INT_PEND: + timer_intr(card); + break; - if(!interrupt_serviced) { + default: printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", card->devname, flags->interrupt_info_struct.interrupt_type); @@ -1563,14 +2076,14 @@ printk(KERN_INFO "%c", flags->global_info_struct.codeversion[i]); printk(KERN_INFO "\n"); + break; } +isr_done: + card->in_isr = 0; flags->interrupt_info_struct.interrupt_type = 0; - if(card->hw.type != SDLA_S514){ - clear_bit(0, (void*)&card->wandev.critical); - } - + return; } /*============================================================================ @@ -1578,15 +2091,16 @@ */ static void rx_intr (sdla_t* card) { - struct net_device *dev; - chdlc_private_area_t *chdlc_priv_area; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb; - struct sk_buff *skb; - unsigned len; - void *buf; - int i,udp_type; - + netdevice_t *dev; + chdlc_private_area_t *chdlc_priv_area; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb; + struct sk_buff *skb; + unsigned len; + unsigned addr = rxbuf->ptr_data_bfr; + void *buf; + int i,udp_type; + if (rxbuf->opp_flag != 0x01) { printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", @@ -1600,90 +2114,132 @@ printk(KERN_INFO "%c", flags->global_info_struct.codeversion[i]); printk(KERN_INFO "\n"); + + + /* Bug Fix: Mar 6 2000 + * If we get a corrupted mailbox, it measn that driver + * is out of sync with the firmware. There is no recovery. + * If we don't turn off all interrupts for this card + * the machine will crash. + */ + printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); + printk(KERN_INFO "Please contact Sangoma Technologies !\n"); + chdlc_set_intr_mode(card,0); return; } + len = rxbuf->frame_length; + +#if defined(LINUX_2_4) || defined(LINUX_2_1) + if (card->tty_opt){ + + if (rxbuf->error_flag){ + goto rx_exit; + } + + if (len <= CRC_LENGTH){ + goto rx_exit; + } + + if (!card->u.c.async_mode){ + len -= CRC_LENGTH; + } + + wanpipe_tty_receive(card,addr,len); + goto rx_exit; + } +#endif + dev = card->wandev.dev; - chdlc_priv_area = dev->priv; - if(dev && netif_running(dev)) { + if (!dev){ + goto rx_exit; + } - len = rxbuf->frame_length; + if (!is_dev_running(dev)) + goto rx_exit; - /* Allocate socket buffer */ - skb = dev_alloc_skb(len); + chdlc_priv_area = dev->priv; - if (skb != NULL) { - /* Copy data to the socket buffer */ - unsigned addr = rxbuf->ptr_data_bfr; - - if((addr + len) > - card->u.c.rx_top + 1) { - unsigned tmp = - card->u.c.rx_top - addr + 1; - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, addr, buf, tmp); - addr = card->u.c.rx_base; - len -= tmp; - } + + /* Allocate socket buffer */ + skb = dev_alloc_skb(len); + + if (skb == NULL) { + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + ++card->wandev.stats.rx_dropped; + goto rx_exit; + } + + /* Copy data to the socket buffer */ + if((addr + len) > card->u.c.rx_top + 1) { + unsigned tmp = card->u.c.rx_top - addr + 1; + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, addr, buf, tmp); + addr = card->u.c.rx_base; + len -= tmp; + } - buf = skb_put(skb, len); - sdla_peek(&card->hw, addr, buf, len); + buf = skb_put(skb, len); + sdla_peek(&card->hw, addr, buf, len); - /* Decapsulate packet */ - skb->protocol = htons(ETH_P_IP); + skb->protocol = htons(ETH_P_IP); - card->wandev.stats.rx_packets ++; -#ifdef LINUX_2_1 - card->wandev.stats.rx_bytes += skb->len; + card->wandev.stats.rx_packets ++; +#if defined(LINUX_2_1) || defined(LINUX_2_4) + card->wandev.stats.rx_bytes += skb->len; #endif - udp_type = udp_pkt_type( skb, card ); + udp_type = udp_pkt_type( skb, card ); - if(udp_type == UDP_CPIPE_TYPE) { - if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, - card, skb, dev, chdlc_priv_area)) { - flags->interrupt_info_struct. + if(udp_type == UDP_CPIPE_TYPE) { + if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, + card, skb, dev, chdlc_priv_area)) { + flags->interrupt_info_struct. interrupt_permission |= APP_INT_ON_TIMER; - } - - } else { - - if(card->u.c.usedby == API) { - api_rx_hdr_t* api_rx_hdr; - skb_push(skb, sizeof(api_rx_hdr_t)); - api_rx_hdr = - (api_rx_hdr_t*)&skb->data[0x00]; - api_rx_hdr->error_flag = - rxbuf->error_flag; - api_rx_hdr->time_stamp = - rxbuf->time_stamp; - skb->protocol = htons(0x16); - skb->pkt_type = PACKET_HOST; - } - -/* FIXME: we should check to see if the received packet is a multicast packet so that we can increment the multicast statistic - ++ chdlc_priv_area->if_stats.multicast; -*/ - /* Pass it up the protocol stack */ - skb->dev = dev; - skb->mac.raw = skb->data; - netif_rx(skb); - } - - } else { - printk(KERN_INFO - "%s: no socket buffers available!\n", - card->devname); - ++card->wandev.stats.rx_dropped; } - } +#if defined(LINUX_2_1) || defined(LINUX_2_4) + } else if(card->u.c.usedby == API) { - /* Release buffer element and calculate a pointer to the next one */ - rxbuf->opp_flag = 0x00; - card->u.c.rxmb = ++ rxbuf; - if((void*)rxbuf > card->u.c.rxbuf_last) + api_rx_hdr_t* api_rx_hdr; + skb_push(skb, sizeof(api_rx_hdr_t)); + api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; + api_rx_hdr->error_flag = rxbuf->error_flag; + api_rx_hdr->time_stamp = rxbuf->time_stamp; + + skb->protocol = htons(PVC_PROT); + skb->mac.raw = skb->data; + skb->dev = dev; + skb->pkt_type = WAN_PACKET_DATA; + + bh_enqueue(dev, skb); + + if (!test_and_set_bit(0,&chdlc_priv_area->tq_working)){ + wanpipe_queue_tq(&chdlc_priv_area->common.wanpipe_task); + wanpipe_mark_bh(); + } +#endif + }else{ + /* FIXME: we should check to see if the received packet is a + multicast packet so that we can increment the multicast + statistic + ++ chdlc_priv_area->if_stats.multicast; + */ + /* Pass it up the protocol stack */ + + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); + } + +rx_exit: + /* Release buffer element and calculate a pointer to the next one */ + rxbuf->opp_flag = 0x00; + card->u.c.rxmb = ++ rxbuf; + if((void*)rxbuf > card->u.c.rxbuf_last){ card->u.c.rxmb = card->u.c.rxbuf_base; + } } /*============================================================================ @@ -1694,13 +2250,25 @@ */ void timer_intr(sdla_t *card) { - struct net_device* dev; + netdevice_t* dev; chdlc_private_area_t* chdlc_priv_area = NULL; SHARED_MEMORY_INFO_STRUCT* flags = NULL; - dev = card->wandev.dev; + if ((dev = card->wandev.dev)==NULL){ + flags = card->u.c.flags; + flags->interrupt_info_struct.interrupt_permission &= + ~APP_INT_ON_TIMER; + return; + } + chdlc_priv_area = dev->priv; + if (chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG) { + if (!config_chdlc(card)){ + chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; + } + } + /* process a udp call if pending */ if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) { process_udp_mgmt_pkt(card, dev, @@ -1733,16 +2301,14 @@ static int set_chdlc_config(sdla_t* card) { - - struct net_device * dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area = dev->priv; CHDLC_CONFIGURATION_STRUCT cfg; memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); - if(card->wandev.clocking) + if(card->wandev.clocking){ cfg.baud_rate = card->wandev.bps; - + } + cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; @@ -1750,9 +2316,18 @@ cfg.modem_status_timer = 100; cfg.CHDLC_protocol_options = card->u.c.protocol_options; - cfg.percent_data_buffer_for_Tx = 50; + + if (card->tty_opt){ + cfg.CHDLC_API_options = DISCARD_RX_ERROR_FRAMES; + } + + cfg.percent_data_buffer_for_Tx = (card->u.c.receive_only) ? 0 : 50; cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | CHDLC_RX_DATA_BYTE_COUNT_STAT); + + if (card->tty_opt){ + card->wandev.mtu = TTY_CHDLC_MAX_MTU; + } cfg.max_CHDLC_data_field_length = card->wandev.mtu; cfg.transmit_keepalive_timer = card->u.c.kpalv_tx; cfg.receive_keepalive_timer = card->u.c.kpalv_rx; @@ -1762,9 +2337,12 @@ if (cfg.SLARP_request_timer) { cfg.IP_address = 0; cfg.IP_netmask = 0; - } - else { -#ifdef LINUX_2_1 + + }else if (card->wandev.dev){ + netdevice_t * dev = card->wandev.dev; + chdlc_private_area_t *chdlc_priv_area = dev->priv; + +#if defined(LINUX_2_1) || defined(LINUX_2_4) struct in_device *in_dev = dev->ip_ptr; if(in_dev != NULL) { @@ -1773,10 +2351,8 @@ if (ifa != NULL ) { cfg.IP_address = ntohl(ifa->ifa_local); cfg.IP_netmask = ntohl(ifa->ifa_mask); - chdlc_priv_area->IP_address = - ntohl(ifa->ifa_local); - chdlc_priv_area->IP_netmask = - ntohl(ifa->ifa_mask); + chdlc_priv_area->IP_address = ntohl(ifa->ifa_local); + chdlc_priv_area->IP_netmask = ntohl(ifa->ifa_mask); } } #else @@ -1803,6 +2379,70 @@ } +/*----------------------------------------------------------------------------- + set_asy_config() used to set asynchronous configuration options on the board +------------------------------------------------------------------------------*/ + +static int set_asy_config(sdla_t* card) +{ + + ASY_CONFIGURATION_STRUCT cfg; + CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; + int err; + + memset(&cfg, 0, sizeof(ASY_CONFIGURATION_STRUCT)); + + if(card->wandev.clocking) + cfg.baud_rate = card->wandev.bps; + + cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? + INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; + + cfg.modem_config_options = 0; + cfg.asy_API_options = card->u.c.api_options; + cfg.asy_protocol_options = card->u.c.protocol_options; + cfg.Tx_bits_per_char = card->u.c.tx_bits_per_char; + cfg.Rx_bits_per_char = card->u.c.rx_bits_per_char; + cfg.stop_bits = card->u.c.stop_bits; + cfg.parity = card->u.c.parity; + cfg.break_timer = card->u.c.break_timer; + cfg.asy_Rx_inter_char_timer = card->u.c.inter_char_timer; + cfg.asy_Rx_complete_length = card->u.c.rx_complete_length; + cfg.XON_char = card->u.c.xon_char; + cfg.XOFF_char = card->u.c.xoff_char; + cfg.asy_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | + CHDLC_RX_DATA_BYTE_COUNT_STAT); + + mailbox->buffer_length = sizeof(ASY_CONFIGURATION_STRUCT); + memcpy(mailbox->data, &cfg, mailbox->buffer_length); + mailbox->command = SET_ASY_CONFIGURATION; + err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) + chdlc_error (card, err, mailbox); + return err; +} + +/*============================================================================ + * Enable asynchronous communications. + */ + +static int asy_comm_enable (sdla_t* card) +{ + + int err; + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + + mb->buffer_length = 0; + mb->command = ENABLE_ASY_COMMUNICATIONS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK && card->wandev.dev) + chdlc_error(card, err, mb); + + if (!err) + card->u.c.comm_enabled = 1; + + return err; +} /*============================================================================ * Process global exception condition @@ -1830,7 +2470,8 @@ printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); break; case (CTS_HIGH): - printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); break; + printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); + break; case ((DCD_HIGH | CTS_HIGH)): printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); break; @@ -1850,6 +2491,19 @@ card->devname); break; + case 0x17: + if (card->tty_opt){ + if (card->tty && card->tty_open){ + printk(KERN_INFO + "%s: Modem Hangup Exception: Hanging Up!\n", + card->devname); + tty_hangup(card->tty); + } + break; + } + + /* If TTY is not used just drop throught */ + default: printk(KERN_INFO "%s: Global exception %x\n", card->devname, mbox->return_code); @@ -1877,11 +2531,13 @@ case EXCEP_LINK_ACTIVE: port_set_state(card, WAN_CONNECTED); + trigger_chdlc_poll(card->wandev.dev); break; case EXCEP_LINK_INACTIVE_MODEM: port_set_state(card, WAN_DISCONNECTED); unconfigure_ip(card); + trigger_chdlc_poll(card->wandev.dev); break; case EXCEP_LINK_INACTIVE_KPALV: @@ -1889,6 +2545,7 @@ printk(KERN_INFO "%s: Keepalive timer expired.\n", card->devname); unconfigure_ip(card); + trigger_chdlc_poll(card->wandev.dev); break; case EXCEP_IP_ADDRESS_DISCOVERED: @@ -1919,10 +2576,16 @@ static int configure_ip (sdla_t* card) { - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area = dev->priv; + netdevice_t *dev = card->wandev.dev; + chdlc_private_area_t *chdlc_priv_area; char err; + if (!dev) + return 0; + + chdlc_priv_area = dev->priv; + + /* set to discover */ if(card->u.c.slarp_timer != 0x00) { CHDLC_MAILBOX_STRUCT* mb = card->mbox; @@ -1940,14 +2603,14 @@ cfg = (CHDLC_CONFIGURATION_STRUCT *)mb->data; chdlc_priv_area->IP_address = cfg->IP_address; chdlc_priv_area->IP_netmask = cfg->IP_netmask; - } - /* Set flag to add route */ - chdlc_priv_area->route_status = ADD_ROUTE; + /* Set flag to add route */ + chdlc_priv_area->route_status = ADD_ROUTE; - /* The idea here is to add the route in the poll routine. - This way, we aren't in interrupt context when adding routes */ - card->poll = process_route; + /* The idea here is to add the route in the poll routine. + This way, we aren't in interrupt context when adding routes */ + trigger_chdlc_poll(dev); + } return 0; } @@ -1960,17 +2623,23 @@ static int unconfigure_ip (sdla_t* card) { - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area= dev->priv; + netdevice_t *dev = card->wandev.dev; + chdlc_private_area_t *chdlc_priv_area; + + if (!dev) + return 0; + chdlc_priv_area= dev->priv; + if (chdlc_priv_area->route_status == ROUTE_ADDED) { - chdlc_priv_area->route_status = REMOVE_ROUTE; - /* The idea here is to delete the route in - * the poll routine. - * This way, we aren't in interrupt context - * when adding routes + + /* Note: If this function is called, the + * port state has been DISCONNECTED. This state + * change will trigger a poll_disconnected + * function, that will check for this condition. */ - card->poll = process_route; + chdlc_priv_area->route_status = REMOVE_ROUTE; + } return 0; } @@ -1982,14 +2651,14 @@ static void process_route (sdla_t *card) { - struct net_device *dev = card->wandev.dev; + netdevice_t *dev = card->wandev.dev; unsigned char port_num; chdlc_private_area_t *chdlc_priv_area = NULL; u32 local_IP_addr = 0; u32 remote_IP_addr = 0; u32 IP_netmask, IP_addr; int err = 0; -#ifdef LINUX_2_1 +#if defined(LINUX_2_1) || defined(LINUX_2_4) struct in_device *in_dev; mm_segment_t fs; struct ifreq if_info; @@ -2002,16 +2671,25 @@ chdlc_priv_area = dev->priv; port_num = card->u.c.comm_port; + /* Bug Fix Mar 16 2000 + * AND the IP address to the Mask before checking + * the last two bits. */ + if((chdlc_priv_area->route_status == ADD_ROUTE) && - ((chdlc_priv_area->IP_address & 0x000000FF) > 2)) { + ((chdlc_priv_area->IP_address & ~chdlc_priv_area->IP_netmask) > 2)) { + printk(KERN_INFO "%s: Dynamic route failure.\n",card->devname); + if(card->u.c.slarp_timer) { + printk(KERN_INFO "%s: Bad IP address %s received\n", card->devname, in_ntoa(ntohl(chdlc_priv_area->IP_address))); printk(KERN_INFO "%s: from remote station.\n", card->devname); + }else{ + printk(KERN_INFO "%s: Bad IP address %s issued\n", card->devname, in_ntoa(ntohl(chdlc_priv_area->IP_address))); @@ -2033,11 +2711,10 @@ /* do not remove a bad route that has already been removed */ if(chdlc_priv_area->route_removed) { - card->poll = NULL; return; } -#ifdef LINUX_2_1 +#if defined(LINUX_2_1) || defined(LINUX_2_4) in_dev = dev->ip_ptr; if(in_dev != NULL) { @@ -2058,7 +2735,17 @@ */ IP_netmask = ntohl(chdlc_priv_area->IP_netmask); remote_IP_addr = ntohl(chdlc_priv_area->IP_address); - local_IP_addr = (remote_IP_addr & ntohl(0xFFFFFF00)) + + + + /* If Netmask is 255.255.255.255 the local address + * calculation will fail. Default it back to 255.255.255.0 */ + if (IP_netmask == 0xffffffff) + IP_netmask &= 0x00ffffff; + + /* Bug Fix Mar 16 2000 + * AND the Remote IP address with IP netmask, instead + * of static netmask of 255.255.255.0 */ + local_IP_addr = (remote_IP_addr & IP_netmask) + (~remote_IP_addr & ntohl(0x0003)); if(!card->u.c.slarp_timer) { @@ -2071,7 +2758,7 @@ fs = get_fs(); /* Save file system */ set_fs(get_ds()); /* Get user space block */ -#ifdef LINUX_2_1 +#if defined(LINUX_2_1) || defined(LINUX_2_4) /* Setup a structure for adding/removing routes */ memset(&if_info, 0, sizeof(if_info)); strcpy(if_info.ifr_name, dev->name); @@ -2099,7 +2786,7 @@ case ADD_ROUTE: if(!card->u.c.slarp_timer) { -#ifdef LINUX_2_1 +#if defined(LINUX_2_1) || defined(LINUX_2_4) if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; if_data2->sin_addr.s_addr = remote_IP_addr; if_data2->sin_family = AF_INET; @@ -2108,7 +2795,7 @@ err = ip_rt_new(&route); #endif } else { -#ifdef LINUX_2_1 +#if defined(LINUX_2_1) || defined(LINUX_2_4) if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; if_data1->sin_addr.s_addr = local_IP_addr; if_data1->sin_family = AF_INET; @@ -2141,7 +2828,7 @@ case REMOVE_ROUTE: -#ifdef LINUX_2_1 +#if defined(LINUX_2_1) || defined(LINUX_2_4) /* Change the local ip address of the interface to 0. * This will also delete the destination route. */ @@ -2179,9 +2866,6 @@ set_fs(fs); /* Restore file system */ - /* Once we've processed the route, stop polling */ - card->poll = NULL; - } @@ -2190,7 +2874,7 @@ */ static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, + struct sk_buff *skb, netdevice_t* dev, chdlc_private_area_t* chdlc_priv_area ) { int udp_pkt_stored = 0; @@ -2204,15 +2888,12 @@ udp_pkt_stored = 1; } -#ifdef LINUX_2_1 - dev_kfree_skb(skb); -#else - if(udp_pkt_src == UDP_PKT_FRM_STACK) - dev_kfree_skb(skb, FREE_WRITE); - else - dev_kfree_skb(skb, FREE_READ); -#endif - + if(udp_pkt_src == UDP_PKT_FRM_STACK){ + wan_dev_kfree_skb(skb, FREE_WRITE); + }else{ + wan_dev_kfree_skb(skb, FREE_READ); + } + return(udp_pkt_stored); } @@ -2221,7 +2902,7 @@ * Process UDP management packet. */ -static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, chdlc_private_area_t* chdlc_priv_area ) { unsigned char *buf; @@ -2240,22 +2921,30 @@ chdlc_udp_pkt = (chdlc_udp_pkt_t *) chdlc_priv_area->udp_pkt_data; - switch(chdlc_udp_pkt->cblock.command) { + if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ - case FT1_MONITOR_STATUS_CTRL: - case CPIPE_ENABLE_TRACING: - case CPIPE_DISABLE_TRACING: - case CPIPE_GET_TRACE_INFO: - case SET_FT1_MODE: - if(chdlc_priv_area->udp_pkt_src == - UDP_PKT_FRM_NETWORK) { - udp_mgmt_req_valid = 0; - } - break; - - default: - break; - } + /* Only these commands are support for remote debugging. + * All others are not */ + switch(chdlc_udp_pkt->cblock.command) { + + case READ_GLOBAL_STATISTICS: + case READ_MODEM_STATUS: + case READ_CHDLC_LINK_STATUS: + case CPIPE_ROUTER_UP_TIME: + case READ_COMMS_ERROR_STATS: + case READ_CHDLC_OPERATIONAL_STATS: + + /* These two commands are executed for + * each request */ + case READ_CHDLC_CONFIGURATION: + case READ_CHDLC_CODE_VERSION: + udp_mgmt_req_valid = 1; + break; + default: + udp_mgmt_req_valid = 0; + break; + } + } if(!udp_mgmt_req_valid) { @@ -2265,6 +2954,12 @@ /* set return code */ chdlc_udp_pkt->cblock.return_code = 0xCD; + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,chdlc_udp_pkt->cblock.command); + } + } else { unsigned long trace_status_cfg_addr = 0; TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct; @@ -2488,11 +3183,12 @@ ((unsigned char *)chdlc_udp_pkt->data )[1] = flags->FT1_info_struct.parallel_port_B_input; - + chdlc_udp_pkt->cblock.return_code = COMMAND_OK; + chdlc_udp_pkt->cblock.buffer_length = 2; mb->buffer_length = 2; break; - + case CPIPE_ROUTER_UP_TIME: do_gettimeofday( &tv ); chdlc_priv_area->router_up_time = tv.tv_sec - @@ -2500,6 +3196,8 @@ *(unsigned long *)&chdlc_udp_pkt->data = chdlc_priv_area->router_up_time; mb->buffer_length = sizeof(unsigned long); + chdlc_udp_pkt->cblock.buffer_length = sizeof(unsigned long); + chdlc_udp_pkt->cblock.return_code = COMMAND_OK; break; case FT1_MONITOR_STATUS_CTRL: @@ -2525,8 +3223,10 @@ break; } } - + goto dflt_1; + default: +dflt_1: /* it's a board command */ mb->command = chdlc_udp_pkt->cblock.command; mb->buffer_length = chdlc_udp_pkt->cblock.buffer_length; @@ -2556,12 +3256,19 @@ len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->buffer_length); - if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { - if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) { - ++ card->wandev.stats.tx_packets; -#ifdef LINUX_2_1 - card->wandev.stats.tx_bytes += len; + + if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ + + /* Must check if we interrupted if_send() routine. The + * tx buffers might be used. If so drop the packet */ + if (!test_bit(SEND_CRIT,&card->wandev.critical)) { + + if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) { + ++ card->wandev.stats.tx_packets; +#if defined(LINUX_2_1) || defined(LINUX_2_4) + card->wandev.stats.tx_bytes += len; #endif + } } } else { @@ -2595,7 +3302,7 @@ * Initialize Receive and Transmit Buffers. */ -static void init_chdlc_tx_rx_buff( sdla_t* card, struct net_device *dev ) +static void init_chdlc_tx_rx_buff( sdla_t* card) { CHDLC_MAILBOX_STRUCT* mb = card->mbox; CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config; @@ -2607,7 +3314,9 @@ err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; if(err != COMMAND_OK) { - chdlc_error(card,err,mb); + if (card->wandev.dev){ + chdlc_error(card,err,mb); + } return; } @@ -2678,19 +3387,13 @@ * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR * _TEST_COUNTER times. */ -static int intr_test( sdla_t* card, struct net_device *dev ) +static int intr_test( sdla_t* card) { CHDLC_MAILBOX_STRUCT* mb = card->mbox; int err,i; Intr_test_counter = 0; - - /* The critical flag is unset because during intialization (if_open) - * we want the interrupts to be enabled so that when the wpc_isr is - * called it does not exit due to critical flag set. - */ - - clear_bit(1, (void*)&card->wandev.critical); + err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); if (err == CMD_OK) { @@ -2707,8 +3410,6 @@ } err = chdlc_set_intr_mode(card, 0); - set_bit(1, (void*)&card->wandev.critical); - if (err != CMD_OK) return err; @@ -2723,13 +3424,33 @@ { chdlc_udp_pkt_t *chdlc_udp_pkt = (chdlc_udp_pkt_t *)skb->data; +#ifdef _WAN_UDP_DEBUG + printk(KERN_INFO "SIG %s = %s\n\ + UPP %x = %x\n\ + PRT %x = %x\n\ + REQ %i = %i\n\ + 36 th = %x 37th = %x\n", + chdlc_udp_pkt->wp_mgmt.signature, + UDPMGMT_SIGNATURE, + chdlc_udp_pkt->udp_pkt.udp_dst_port, + ntohs(card->wandev.udp_port), + chdlc_udp_pkt->ip_pkt.protocol, + UDPMGMT_UDP_PROTOCOL, + chdlc_udp_pkt->wp_mgmt.request_reply, + UDPMGMT_REQUEST, + skb->data[36], skb->data[37]); +#endif + if (!strncmp(chdlc_udp_pkt->wp_mgmt.signature,UDPMGMT_SIGNATURE,8) && (chdlc_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && (chdlc_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && (chdlc_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { + return UDP_CPIPE_TYPE; + + }else{ + return UDP_INVALID_TYPE; } - else return UDP_INVALID_TYPE; } /*============================================================================ @@ -2744,7 +3465,7 @@ case WAN_CONNECTED: printk (KERN_INFO "%s: Link connected!\n", card->devname); - break; + break; case WAN_CONNECTING: printk (KERN_INFO "%s: Link connecting...\n", @@ -2758,31 +3479,1268 @@ } card->wandev.state = card->u.c.state = state; + if (card->wandev.dev){ + netdevice_t *dev = card->wandev.dev; + chdlc_private_area_t *chdlc_priv_area = dev->priv; + chdlc_priv_area->common.state = state; + } } } -void s508_lock (sdla_t *card, unsigned long *smp_flags) +/*=========================================================================== + * config_chdlc + * + * Configure the chdlc protocol and enable communications. + * + * The if_open() function binds this function to the poll routine. + * Therefore, this function will run every time the chdlc interface + * is brought up. We cannot run this function from the if_open + * because if_open does not have access to the remote IP address. + * + * If the communications are not enabled, proceed to configure + * the card and enable communications. + * + * If the communications are enabled, it means that the interface + * was shutdown by ether the user or driver. In this case, we + * have to check that the IP addresses have not changed. If + * the IP addresses have changed, we have to reconfigure the firmware + * and update the changed IP addresses. Otherwise, just exit. + * + */ + +static int config_chdlc (sdla_t *card) { -#ifdef CONFIG_SMP - spin_lock_irqsave(&card->lock, *smp_flags); - if (card->next){ - spin_lock(&card->next->lock); - } -#else - disable_irq(card->hw.irq); -#endif + netdevice_t *dev = card->wandev.dev; + chdlc_private_area_t *chdlc_priv_area = dev->priv; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + + if (card->u.c.comm_enabled){ + + /* Jun 20. 2000: NC + * IP addresses are not used in the API mode */ + + if ((chdlc_priv_area->ip_local_tmp != chdlc_priv_area->ip_local || + chdlc_priv_area->ip_remote_tmp != chdlc_priv_area->ip_remote) && + card->u.c.usedby == WANPIPE) { + + /* The IP addersses have changed, we must + * stop the communications and reconfigure + * the card. Reason: the firmware must know + * the local and remote IP addresses. */ + disable_comm(card); + port_set_state(card, WAN_DISCONNECTED); + printk(KERN_INFO + "%s: IP addresses changed!\n", + card->devname); + printk(KERN_INFO + "%s: Restarting communications ...\n", + card->devname); + }else{ + /* IP addresses are the same and the link is up, + * we dont have to do anything here. Therefore, exit */ + return 0; + } + } + + chdlc_priv_area->ip_local = chdlc_priv_area->ip_local_tmp; + chdlc_priv_area->ip_remote = chdlc_priv_area->ip_remote_tmp; + + + /* Setup the Board for asynchronous mode */ + if (card->u.c.async_mode){ + + if (set_asy_config(card)) { + printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n", + card->devname); + return 0; + } + }else{ + /* Setup the Board for CHDLC */ + if (set_chdlc_config(card)) { + printk (KERN_INFO "%s: Failed CHDLC configuration!\n", + card->devname); + return 0; + } + } + + /* Set interrupt mode and mask */ + if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_TX_FRAME | + APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ + printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", + card->devname); + return 0; + } + + + /* Mask the Transmit and Timer interrupt */ + flags->interrupt_info_struct.interrupt_permission &= + ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); + + /* In TTY mode, receive interrupt will be enabled during + * wanpipe_tty_open() operation */ + if (card->tty_opt){ + flags->interrupt_info_struct.interrupt_permission &= ~APP_INT_ON_RX_FRAME; + } + + /* Enable communications */ + if (card->u.c.async_mode){ + if (asy_comm_enable(card) != 0) { + printk(KERN_INFO "%s: Failed to enable async commnunication!\n", + card->devname); + flags->interrupt_info_struct.interrupt_permission = 0; + card->u.c.comm_enabled=0; + chdlc_set_intr_mode(card,0); + return 0; + } + }else{ + if (chdlc_comm_enable(card) != 0) { + printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", + card->devname); + flags->interrupt_info_struct.interrupt_permission = 0; + card->u.c.comm_enabled=0; + chdlc_set_intr_mode(card,0); + return 0; + } + } + + /* Initialize Rx/Tx buffer control fields */ + init_chdlc_tx_rx_buff(card); + port_set_state(card, WAN_CONNECTING); + return 0; } -void s508_unlock (sdla_t *card, unsigned long *smp_flags) + +/*============================================================ + * chdlc_poll + * + * Rationale: + * We cannot manipulate the routing tables, or + * ip addresses withing the interrupt. Therefore + * we must perform such actons outside an interrupt + * at a later time. + * + * Description: + * CHDLC polling routine, responsible for + * shutting down interfaces upon disconnect + * and adding/removing routes. + * + * Usage: + * This function is executed for each CHDLC + * interface through a tq_schedule bottom half. + * + * trigger_chdlc_poll() function is used to kick + * the chldc_poll routine. + */ + +static void chdlc_poll (netdevice_t *dev) { -#ifdef CONFIG_SMP - if (card->next){ - spin_unlock(&card->next->lock); - } - spin_unlock_irqrestore(&card->lock, *smp_flags); -#else - enable_irq(card->hw.irq); -#endif -} + chdlc_private_area_t *chdlc_priv_area; + sdla_t *card; + u8 check_gateway=0; + SHARED_MEMORY_INFO_STRUCT* flags; + + + if (!dev || (chdlc_priv_area=dev->priv) == NULL) + return; + + card = chdlc_priv_area->card; + flags = card->u.c.flags; + + /* (Re)Configuraiton is in progress, stop what you are + * doing and get out */ + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + clear_bit(POLL_CRIT,&card->wandev.critical); + return; + } + + /* if_open() function has triggered the polling routine + * to determine the configured IP addresses. Once the + * addresses are found, trigger the chdlc configuration */ + if (test_bit(0,&chdlc_priv_area->config_chdlc)){ + + chdlc_priv_area->ip_local_tmp = get_ip_address(dev,WAN_LOCAL_IP); + chdlc_priv_area->ip_remote_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); + + /* Jun 20. 2000 Bug Fix + * Only perform this check in WANPIPE mode, since + * IP addresses are not used in the API mode. */ + + if (chdlc_priv_area->ip_local_tmp == chdlc_priv_area->ip_remote_tmp && + card->u.c.slarp_timer == 0x00 && + !card->u.c.backup && + card->u.c.usedby == WANPIPE){ + + if (++chdlc_priv_area->ip_error > MAX_IP_ERRORS){ + printk(KERN_INFO "\n%s: --- WARNING ---\n", + card->devname); + printk(KERN_INFO + "%s: The local IP address is the same as the\n", + card->devname); + printk(KERN_INFO + "%s: Point-to-Point IP address.\n", + card->devname); + printk(KERN_INFO "%s: --- WARNING ---\n\n", + card->devname); + }else{ + clear_bit(POLL_CRIT,&card->wandev.critical); + chdlc_priv_area->poll_delay_timer.expires = jiffies+HZ; + add_timer(&chdlc_priv_area->poll_delay_timer); + return; + } + } + + clear_bit(0,&chdlc_priv_area->config_chdlc); + clear_bit(POLL_CRIT,&card->wandev.critical); + + chdlc_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; + flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; + return; + } + /* Dynamic interface implementation, as well as dynamic + * routing. */ + + switch (card->u.c.state){ + + case WAN_DISCONNECTED: + + /* If the dynamic interface configuration is on, and interface + * is up, then bring down the netowrk interface */ + + if (test_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down) && + !test_bit(DEV_DOWN, &chdlc_priv_area->interface_down) && + card->wandev.dev->flags & IFF_UP){ + + printk(KERN_INFO "%s: Interface %s down.\n", + card->devname,card->wandev.dev->name); + change_dev_flags(card->wandev.dev,(card->wandev.dev->flags&~IFF_UP)); + set_bit(DEV_DOWN,&chdlc_priv_area->interface_down); + chdlc_priv_area->route_status = NO_ROUTE; + + }else{ + /* We need to check if the local IP address is + * zero. If it is, we shouldn't try to remove it. + */ + + if (card->wandev.dev->flags & IFF_UP && + get_ip_address(card->wandev.dev,WAN_LOCAL_IP) && + chdlc_priv_area->route_status != NO_ROUTE && + card->u.c.slarp_timer){ + + process_route(card); + } + } + break; + + case WAN_CONNECTED: + + /* In SMP machine this code can execute before the interface + * comes up. In this case, we must make sure that we do not + * try to bring up the interface before dev_open() is finished */ + + + /* DEV_DOWN will be set only when we bring down the interface + * for the very first time. This way we know that it was us + * that brought the interface down */ + + if (test_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down) && + test_bit(DEV_DOWN, &chdlc_priv_area->interface_down) && + !(card->wandev.dev->flags & IFF_UP)){ + + printk(KERN_INFO "%s: Interface %s up.\n", + card->devname,card->wandev.dev->name); + change_dev_flags(card->wandev.dev,(card->wandev.dev->flags|IFF_UP)); + clear_bit(DEV_DOWN,&chdlc_priv_area->interface_down); + check_gateway=1; + } + + if (chdlc_priv_area->route_status == ADD_ROUTE && + card->u.c.slarp_timer){ + + process_route(card); + check_gateway=1; + } + + if (chdlc_priv_area->gateway && check_gateway) + add_gateway(card,dev); + + break; + } + + clear_bit(POLL_CRIT,&card->wandev.critical); +} + +/*============================================================ + * trigger_chdlc_poll + * + * Description: + * Add a chdlc_poll() task into a tq_scheduler bh handler + * for a specific dlci/interface. This will kick + * the fr_poll() routine at a later time. + * + * Usage: + * Interrupts use this to defer a taks to + * a polling routine. + * + */ +static void trigger_chdlc_poll (netdevice_t *dev) +{ + chdlc_private_area_t *chdlc_priv_area; + sdla_t *card; + + if (!dev) + return; + + if ((chdlc_priv_area = dev->priv)==NULL) + return; + + card = chdlc_priv_area->card; + + if (test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ + return; + } + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + return; + } +#ifdef LINUX_2_4 + schedule_task(&chdlc_priv_area->poll_task); +#else + queue_task(&chdlc_priv_area->poll_task, &tq_scheduler); +#endif + return; +} + + +static void chdlc_poll_delay (unsigned long dev_ptr) +{ + netdevice_t *dev = (netdevice_t *)dev_ptr; + trigger_chdlc_poll(dev); +} + + +void s508_lock (sdla_t *card, unsigned long *smp_flags) +{ +#if defined(__SMP__) || defined(LINUX_2_4) + spin_lock_irqsave(&card->wandev.lock, *smp_flags); + if (card->next){ + spin_lock(&card->next->wandev.lock); + } +#else + disable_irq(card->hw.irq); +#endif +} + +void s508_unlock (sdla_t *card, unsigned long *smp_flags) +{ +#if defined(__SMP__) || defined(LINUX_2_4) + if (card->next){ + spin_unlock(&card->next->wandev.lock); + } + spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); +#else + enable_irq(card->hw.irq); +#endif +} + +//*********** TTY SECTION **************** +#if defined(LINUX_2_4) || defined(LINUX_2_1) + +static void wanpipe_tty_trigger_tx_irq(sdla_t *card) +{ + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; + chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; +} + +static void wanpipe_tty_trigger_poll(sdla_t *card) +{ +#ifdef LINUX_2_4 + schedule_task(&card->tty_task_queue); +#else + queue_task(&card->tty_task_queue, &tq_scheduler); +#endif +} + +static void tty_poll_task (void* data) +{ + sdla_t *card = (sdla_t*)data; + struct tty_struct *tty; + + if ((tty=card->tty)==NULL) + return; + + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup){ + (tty->ldisc.write_wakeup)(tty); + } + wake_up_interruptible(&tty->write_wait); +#if defined(SERIAL_HAVE_POLL_WAIT) || \ + (defined LINUX_2_1 && LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15)) + wake_up_interruptible(&tty->poll_wait); +#endif + return; +} + +static void wanpipe_tty_close(struct tty_struct *tty, struct file * filp) +{ + sdla_t *card; + unsigned long smp_flags; + + if (!tty || !tty->driver_data){ + return; + } + + card = (sdla_t*)tty->driver_data; + + if (!card) + return; + + printk(KERN_INFO "%s: Closing TTY Driver!\n", + card->devname); + + /* Sanity Check */ + if (!card->tty_open) + return; + + wanpipe_close(card); + if (--card->tty_open == 0){ + + lock_adapter_irq(&card->wandev.lock,&smp_flags); + card->tty=NULL; + chdlc_disable_comm_shutdown(card); + unlock_adapter_irq(&card->wandev.lock,&smp_flags); + + if (card->tty_buf){ + kfree(card->tty_buf); + card->tty_buf=NULL; + } + + if (card->tty_rx){ + kfree(card->tty_rx); + card->tty_rx=NULL; + } + } + return; +} +static int wanpipe_tty_open(struct tty_struct *tty, struct file * filp) +{ + unsigned long smp_flags; + sdla_t *card; + + if (!tty){ + return -ENODEV; + } + + if (!tty->driver_data){ + int port; + port = MINOR(tty->device) - tty->driver.minor_start; + if ((port < 0) || (port >= NR_PORTS)) + return -ENODEV; + + tty->driver_data = WAN_CARD(port); + if (!tty->driver_data) + return -ENODEV; + } + + card = (sdla_t*)tty->driver_data; + + if (!card){ + lock_adapter_irq(&card->wandev.lock,&smp_flags); + card->tty=NULL; + unlock_adapter_irq(&card->wandev.lock,&smp_flags); + return -ENODEV; + } + + printk(KERN_INFO "%s: Opening TTY Driver!\n", + card->devname); + + if (card->tty_open == 0){ + lock_adapter_irq(&card->wandev.lock,&smp_flags); + card->tty=tty; + unlock_adapter_irq(&card->wandev.lock,&smp_flags); + + if (!card->tty_buf){ + card->tty_buf = kmalloc(TTY_CHDLC_MAX_MTU, GFP_KERNEL); + if (!card->tty_buf){ + card->tty_buf=NULL; + card->tty=NULL; + return -ENOMEM; + } + } + + if (!card->tty_rx){ + card->tty_rx = kmalloc(TTY_CHDLC_MAX_MTU, GFP_KERNEL); + if (!card->tty_rx){ + /* Free the buffer above */ + kfree(card->tty_buf); + card->tty_buf=NULL; + card->tty=NULL; + return -ENOMEM; + } + } + } + + ++card->tty_open; + wanpipe_open(card); + return 0; +} + +static int wanpipe_tty_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + unsigned long smp_flags=0; + sdla_t *card=NULL; + + if (!tty){ + dbg_printk(KERN_INFO "NO TTY in Write\n"); + return -ENODEV; + } + + card = (sdla_t *)tty->driver_data; + + if (!card){ + dbg_printk(KERN_INFO "No Card in TTY Write\n"); + return -ENODEV; + } + + if (count > card->wandev.mtu){ + dbg_printk(KERN_INFO "Frame too big in Write %i Max: %i\n", + count,card->wandev.mtu); + return -EINVAL; + } + + if (card->wandev.state != WAN_CONNECTED){ + dbg_printk(KERN_INFO "Card not connected in TTY Write\n"); + return -EINVAL; + } + + /* Lock the 508 Card: SMP is supported */ + if(card->hw.type != SDLA_S514){ + s508_lock(card,&smp_flags); + } + + if (test_and_set_bit(SEND_CRIT,(void*)&card->wandev.critical)){ + printk(KERN_INFO "%s: Critical in TTY Write\n", + card->devname); + + /* Lock the 508 Card: SMP is supported */ + if(card->hw.type != SDLA_S514) + s508_unlock(card,&smp_flags); + + return -EINVAL; + } + + if (from_user) { + + unsigned char *tmp_buf; + + if ((tmp_buf=card->tty_buf)==NULL){ + dbg_printk(KERN_INFO "No TTY BUF in Write\n"); + + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + + if(card->hw.type != SDLA_S514) + s508_unlock(card,&smp_flags); + + return -ENOMEM; + } + + if (copy_from_user(tmp_buf,buf,count)){ + dbg_printk(KERN_INFO "%s: Failed to copy from user!\n", + card->devname); + + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + + if(card->hw.type != SDLA_S514) + s508_unlock(card,&smp_flags); + + return -EINVAL; + } + + if (chdlc_send(card,(void*)tmp_buf,count)){ + dbg_printk(KERN_INFO "%s: Failed to send, retry later: user!\n", + card->devname); + + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + + wanpipe_tty_trigger_tx_irq(card); + + if(card->hw.type != SDLA_S514) + s508_unlock(card,&smp_flags); + return 0; + } + + }else{ + if (chdlc_send(card,(void*)buf,count)){ + dbg_printk(KERN_INFO "%s: Failed to send, retry later: kernel!\n", + card->devname); + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + + wanpipe_tty_trigger_tx_irq(card); + + if(card->hw.type != SDLA_S514) + s508_unlock(card,&smp_flags); + return 0; + } + } + dbg_printk(KERN_INFO "%s: Packet sent OK: %i\n",card->devname,count); + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + + if(card->hw.type != SDLA_S514) + s508_unlock(card,&smp_flags); + + return count; +} + +static void wanpipe_tty_receive(sdla_t *card, unsigned addr, unsigned int len) +{ + unsigned offset=0; + unsigned olen=len; + char fp=0; + struct tty_struct *tty; + int i; + + if (!card->tty_open){ + dbg_printk(KERN_INFO "%s: TTY not open during receive\n", + card->devname); + return; + } + + if ((tty=card->tty) == NULL){ + dbg_printk(KERN_INFO "%s: No TTY on receive\n", + card->devname); + return; + } + + if (!tty->driver_data){ + dbg_printk(KERN_INFO "%s: No Driver Data, or Flip on receive\n", + card->devname); + return; + } + + + if (card->u.c.async_mode){ + if ((tty->flip.count+len) >= TTY_FLIPBUF_SIZE){ + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Received packet size too big: %i bytes, Max: %i!\n", + card->devname,len,TTY_FLIPBUF_SIZE); + } + return; + } + + + if((addr + len) > card->u.c.rx_top + 1) { + offset = card->u.c.rx_top - addr + 1; + + sdla_peek(&card->hw, addr, tty->flip.char_buf_ptr, offset); + + addr = card->u.c.rx_base; + len -= offset; + + tty->flip.char_buf_ptr+=offset; + tty->flip.count+=offset; + for (i=0;i<offset;i++){ + *tty->flip.flag_buf_ptr = 0; + tty->flip.flag_buf_ptr++; + } + } + + sdla_peek(&card->hw, addr, tty->flip.char_buf_ptr, len); + + tty->flip.char_buf_ptr+=len; + card->tty->flip.count+=len; + for (i=0;i<len;i++){ + *tty->flip.flag_buf_ptr = 0; + tty->flip.flag_buf_ptr++; + } + + tty->low_latency=1; + tty_flip_buffer_push(tty); + }else{ + if (!card->tty_rx){ + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Receive sync buffer not available!\n", + card->devname); + } + return; + } + + if (len > TTY_CHDLC_MAX_MTU){ + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Received packet size too big: %i bytes, Max: %i!\n", + card->devname,len,TTY_FLIPBUF_SIZE); + } + return; + } + + + if((addr + len) > card->u.c.rx_top + 1) { + offset = card->u.c.rx_top - addr + 1; + + sdla_peek(&card->hw, addr, card->tty_rx, offset); + + addr = card->u.c.rx_base; + len -= offset; + } + sdla_peek(&card->hw, addr, card->tty_rx+offset, len); + if (tty->ldisc.receive_buf){ + tty->ldisc.receive_buf(tty,card->tty_rx,&fp,olen); + }else{ + if (net_ratelimit()){ + printk(KERN_INFO + "%s: NO TTY Sync line discipline!\n", + card->devname); + } + } + } + + dbg_printk(KERN_INFO "%s: Received Data %i\n",card->devname,olen); + return; +} + +#if 0 +static int wanpipe_tty_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + return -ENOIOCTLCMD; +} +#endif + +static void wanpipe_tty_stop(struct tty_struct *tty) +{ + return; +} + +static void wanpipe_tty_start(struct tty_struct *tty) +{ + return; +} + +static int config_tty (sdla_t *card) +{ + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + + /* Setup the Board for asynchronous mode */ + if (card->u.c.async_mode){ + + if (set_asy_config(card)) { + printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n", + card->devname); + return -EINVAL; + } + }else{ + /* Setup the Board for CHDLC */ + if (set_chdlc_config(card)) { + printk (KERN_INFO "%s: Failed CHDLC configuration!\n", + card->devname); + return -EINVAL; + } + } + + /* Set interrupt mode and mask */ + if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_TX_FRAME | + APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ + printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", + card->devname); + return -EINVAL; + } + + + /* Mask the Transmit and Timer interrupt */ + flags->interrupt_info_struct.interrupt_permission &= + ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); + + + /* Enable communications */ + if (card->u.c.async_mode){ + if (asy_comm_enable(card) != 0) { + printk(KERN_INFO "%s: Failed to enable async commnunication!\n", + card->devname); + flags->interrupt_info_struct.interrupt_permission = 0; + card->u.c.comm_enabled=0; + chdlc_set_intr_mode(card,0); + return -EINVAL; + } + }else{ + if (chdlc_comm_enable(card) != 0) { + printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", + card->devname); + flags->interrupt_info_struct.interrupt_permission = 0; + card->u.c.comm_enabled=0; + chdlc_set_intr_mode(card,0); + return -EINVAL; + } + } + + /* Initialize Rx/Tx buffer control fields */ + init_chdlc_tx_rx_buff(card); + port_set_state(card, WAN_CONNECTING); + return 0; +} + + +static int change_speed(sdla_t *card, struct tty_struct *tty, + struct termios *old_termios) +{ + int baud, ret=0; + unsigned cflag; + int dbits,sbits,parity,handshaking; + + cflag = tty->termios->c_cflag; + + /* There is always one stop bit */ + sbits=WANOPT_ONE; + + /* Parity is defaulted to NONE */ + parity = WANOPT_NONE; + + handshaking=0; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: dbits = 5; break; + case CS6: dbits = 6; break; + case CS7: dbits = 7; break; + case CS8: dbits = 8; break; + /* Never happens, but GCC is too dumb to figure it out */ + default: dbits = 8; break; + } + + /* One more stop bit should be supported, thus increment + * the number of stop bits Max=2 */ + if (cflag & CSTOPB) { + sbits = WANOPT_TWO; + } + if (cflag & PARENB) { + parity = WANOPT_EVEN; + } + if (cflag & PARODD){ + parity = WANOPT_ODD; + } + + /* Determine divisor based on baud rate */ + baud = tty_get_baud_rate(tty); + + if (!baud) + baud = 9600; /* B0 transition handled in rs_set_termios */ + + if (cflag & CRTSCTS) { + handshaking|=ASY_RTS_HS_FOR_RX; + } + + if (I_IGNPAR(tty)) + parity = WANOPT_NONE; + + if (I_IXOFF(tty)){ + handshaking|=ASY_XON_XOFF_HS_FOR_RX; + handshaking|=ASY_XON_XOFF_HS_FOR_TX; + } + + if (I_IXON(tty)){ + handshaking|=ASY_XON_XOFF_HS_FOR_RX; + handshaking|=ASY_XON_XOFF_HS_FOR_TX; + } + + if (card->u.c.async_mode){ + if (card->wandev.bps != baud) + ret=1; + card->wandev.bps = baud; + } + + if (card->u.c.async_mode){ + if (card->u.c.protocol_options != handshaking) + ret=1; + card->u.c.protocol_options = handshaking; + + if (card->u.c.tx_bits_per_char != dbits) + ret=1; + card->u.c.tx_bits_per_char = dbits; + + if (card->u.c.rx_bits_per_char != dbits) + ret=1; + card->u.c.rx_bits_per_char = dbits; + + if (card->u.c.stop_bits != sbits) + ret=1; + card->u.c.stop_bits = sbits; + + if (card->u.c.parity != parity) + ret=1; + card->u.c.parity = parity; + + card->u.c.break_timer = 50; + card->u.c.inter_char_timer = 10; + card->u.c.rx_complete_length = 100; + card->u.c.xon_char = 0xFE; + }else{ + card->u.c.protocol_options = HDLC_STREAMING_MODE; + } + + return ret; +} + + +static void wanpipe_tty_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + sdla_t *card; + int err=1; + + if (!tty){ + return; + } + + card = (sdla_t *)tty->driver_data; + + if (!card) + return; + + if (change_speed(card, tty, old_termios) || !card->u.c.comm_enabled){ + unsigned long smp_flags; + + if (card->u.c.comm_enabled){ + lock_adapter_irq(&card->wandev.lock,&smp_flags); + chdlc_disable_comm_shutdown(card); + unlock_adapter_irq(&card->wandev.lock,&smp_flags); + } + lock_adapter_irq(&card->wandev.lock,&smp_flags); + err = config_tty(card); + unlock_adapter_irq(&card->wandev.lock,&smp_flags); + if (card->u.c.async_mode){ + printk(KERN_INFO "%s: TTY Async Configuration:\n" + " Baud =%i\n" + " Handshaking =%s\n" + " Tx Dbits =%i\n" + " Rx Dbits =%i\n" + " Parity =%s\n" + " Stop Bits =%i\n", + card->devname, + card->wandev.bps, + opt_decode[card->u.c.protocol_options], + card->u.c.tx_bits_per_char, + card->u.c.rx_bits_per_char, + p_decode[card->u.c.parity] , + card->u.c.stop_bits); + }else{ + printk(KERN_INFO "%s: TTY Sync Configuration:\n" + " Baud =%i\n" + " Protocol =HDLC_STREAMING\n", + card->devname,card->wandev.bps); + } + if (!err){ + port_set_state(card,WAN_CONNECTED); + }else{ + port_set_state(card,WAN_DISCONNECTED); + } + } + return; +} + +static void wanpipe_tty_put_char(struct tty_struct *tty, unsigned char ch) +{ + sdla_t *card; + unsigned long smp_flags=0; + + if (!tty){ + return; + } + + card = (sdla_t *)tty->driver_data; + + if (!card) + return; + + if (card->wandev.state != WAN_CONNECTED) + return; + + if(card->hw.type != SDLA_S514) + s508_lock(card,&smp_flags); + + if (test_and_set_bit(SEND_CRIT,(void*)&card->wandev.critical)){ + + wanpipe_tty_trigger_tx_irq(card); + + if(card->hw.type != SDLA_S514) + s508_unlock(card,&smp_flags); + return; + } + + if (chdlc_send(card,(void*)&ch,1)){ + wanpipe_tty_trigger_tx_irq(card); + dbg_printk("%s: Failed to TX char!\n",card->devname); + } + + dbg_printk("%s: Char TX OK\n",card->devname); + + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + + if(card->hw.type != SDLA_S514) + s508_unlock(card,&smp_flags); + + return; +} + +static void wanpipe_tty_flush_chars(struct tty_struct *tty) +{ + return; +} + +static void wanpipe_tty_flush_buffer(struct tty_struct *tty) +{ + if (!tty) + return; + + wake_up_interruptible(&tty->write_wait); +#if defined(SERIAL_HAVE_POLL_WAIT) || \ + (defined LINUX_2_1 && LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15)) + wake_up_interruptible(&tty->poll_wait); +#endif + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + + return; +} + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + */ +static void wanpipe_tty_send_xchar(struct tty_struct *tty, char ch) +{ + return; +} + + +static int wanpipe_tty_chars_in_buffer(struct tty_struct *tty) +{ + return 0; +} + + +static int wanpipe_tty_write_room(struct tty_struct *tty) +{ + sdla_t *card; + + printk(KERN_INFO "TTY Write Room\n"); + + if (!tty){ + return 0; + } + + card = (sdla_t *)tty->driver_data; + if (!card) + return 0; + + if (card->wandev.state != WAN_CONNECTED) + return 0; + + return SEC_MAX_NO_DATA_BYTES_IN_FRAME; +} + + +static int set_modem_status(sdla_t *card, unsigned char data) +{ + CHDLC_MAILBOX_STRUCT *mb = card->mbox; + int err; + + mb->buffer_length=1; + mb->command=SET_MODEM_STATUS; + mb->data[0]=data; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) + chdlc_error (card, err, mb); + + return err; +} + +static void wanpipe_tty_hangup(struct tty_struct *tty) +{ + sdla_t *card; + unsigned long smp_flags; + + printk(KERN_INFO "TTY Hangup!\n"); + + if (!tty){ + return; + } + + card = (sdla_t *)tty->driver_data; + if (!card) + return; + + lock_adapter_irq(&card->wandev.lock,&smp_flags); + set_modem_status(card,0); + unlock_adapter_irq(&card->wandev.lock,&smp_flags); + return; +} + +static void wanpipe_tty_break(struct tty_struct *tty, int break_state) +{ + return; +} + +static void wanpipe_tty_wait_until_sent(struct tty_struct *tty, int timeout) +{ + return; +} + +static void wanpipe_tty_throttle(struct tty_struct * tty) +{ + return; +} + +static void wanpipe_tty_unthrottle(struct tty_struct * tty) +{ + return; +} + +int wanpipe_tty_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + return 0; +} + +/* + * The serial driver boot-time initialization code! + */ +int wanpipe_tty_init(sdla_t *card) +{ + struct serial_state * state; + + /* Initialize the tty_driver structure */ + + if (card->tty_minor < 0 || card->tty_minor > NR_PORTS){ + printk(KERN_INFO "%s: Illegal Minor TTY number (0-4): %i\n", + card->devname,card->tty_minor); + return -EINVAL; + } + + if (WAN_CARD(card->tty_minor)){ + printk(KERN_INFO "%s: TTY Minor %i, already in use\n", + card->devname,card->tty_minor); + return -EBUSY; + } + + if (tty_init_cnt==0){ + + printk(KERN_INFO "%s: TTY %s Driver Init: Major %i, Minor Range %i-%i\n", + card->devname, + card->u.c.async_mode ? "ASYNC" : "SYNC", + WAN_TTY_MAJOR,MIN_PORT,MAX_PORT); + + tty_driver_mode = card->u.c.async_mode; + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.driver_name = "wanpipe_tty"; + serial_driver.name = "ttyW"; + serial_driver.major = WAN_TTY_MAJOR; + serial_driver.minor_start = WAN_TTY_MINOR; + 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 = wanpipe_tty_open; + serial_driver.close = wanpipe_tty_close; + serial_driver.write = wanpipe_tty_write; + + serial_driver.put_char = wanpipe_tty_put_char; + serial_driver.flush_chars = wanpipe_tty_flush_chars; + serial_driver.write_room = wanpipe_tty_write_room; + serial_driver.chars_in_buffer = wanpipe_tty_chars_in_buffer; + serial_driver.flush_buffer = wanpipe_tty_flush_buffer; + //serial_driver.ioctl = wanpipe_tty_ioctl; + serial_driver.throttle = wanpipe_tty_throttle; + serial_driver.unthrottle = wanpipe_tty_unthrottle; + serial_driver.send_xchar = wanpipe_tty_send_xchar; + serial_driver.set_termios = wanpipe_tty_set_termios; + serial_driver.stop = wanpipe_tty_stop; + serial_driver.start = wanpipe_tty_start; + serial_driver.hangup = wanpipe_tty_hangup; + serial_driver.break_ctl = wanpipe_tty_break; + serial_driver.wait_until_sent = wanpipe_tty_wait_until_sent; + serial_driver.read_proc = wanpipe_tty_read_proc; + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; + callout_driver.name = "cuw"; + callout_driver.major = TTYAUX_MAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; + callout_driver.read_proc = 0; + callout_driver.proc_entry = 0; + + if (tty_register_driver(&serial_driver)){ + printk(KERN_INFO "%s: Failed to register serial driver!\n", + card->devname); + } + + if (tty_register_driver(&callout_driver)){ + printk(KERN_INFO "%s: Failed to register callout driver!\n", + card->devname); + } + + } + + + /* The subsequent ports must comply to the initial configuration */ + if (tty_driver_mode != card->u.c.async_mode){ + printk(KERN_INFO "%s: Error: TTY Driver operation mode mismatch!\n", + card->devname); + printk(KERN_INFO "%s: The TTY driver is configured for %s!\n", + card->devname, tty_driver_mode ? "ASYNC" : "SYNC"); + return -EINVAL; + } + + tty_init_cnt++; + + printk(KERN_INFO "%s: Initializing TTY %s Driver Minor %i\n", + card->devname, + tty_driver_mode ? "ASYNC" : "SYNC", + card->tty_minor); + + tty_card_map[card->tty_minor] = card; + state = &rs_table[card->tty_minor]; + + state->magic = SSTATE_MAGIC; + state->line = 0; + state->type = PORT_UNKNOWN; + state->custom_divisor = 0; + state->close_delay = 5*HZ/10; + state->closing_wait = 30*HZ; + state->callout_termios = callout_driver.init_termios; + state->normal_termios = serial_driver.init_termios; + state->icount.cts = state->icount.dsr = + state->icount.rng = state->icount.dcd = 0; + state->icount.rx = state->icount.tx = 0; + state->icount.frame = state->icount.parity = 0; + state->icount.overrun = state->icount.brk = 0; + state->irq = card->wandev.irq; + + card->tty_task_queue.routine = tty_poll_task; + card->tty_task_queue.data = (void*)card; + return 0; +} + +#endif + /****** End ****************************************************************/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/wan/sdla_fr.c linux.ac/drivers/net/wan/sdla_fr.c --- linux.vanilla/drivers/net/wan/sdla_fr.c Tue Apr 3 17:32:16 2001 +++ linux.ac/drivers/net/wan/sdla_fr.c Mon Apr 16 15:06:58 2001 @@ -4,14 +4,43 @@ * Author(s): Nenad Corbic <ncorbic@sangoma.com> * Gideon Hack * -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* Copyright: (c) 1995-2001 Sangoma Technologies Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ -* Feb 28, 2000 Jeff Garzik o softnet updates +* Nov 23, 2000 Nenad Corbic o Added support for 2.4.X kernels +* Nov 15, 2000 David Rokavarg +* Nenad Corbic o Added frame relay bridging support. +* Original code from Mark Wells and Kristian Hoffmann has +* been integrated into the frame relay driver. +* Nov 13, 2000 Nenad Corbic o Added true interface type encoding option. +* Tcpdump doesn't support Frame Relay inteface +* types, to fix this true type option will set +* the interface type to RAW IP mode. +* Nov 07, 2000 Nenad Corbic o Added security features for UDP debugging: +* Deny all and specify allowed requests. +* Nov 06, 2000 Nenad Corbic o Wanpipe interfaces conform to raw packet interfaces. +* Moved the if_header into the if_send() routine. +* The if_header() was breaking the libpcap +* support. i.e. support for tcpdump, ethereal ... +* Oct 12. 2000 Nenad Corbic o Added error message in fr_configure +* Jul 31, 2000 Nenad Corbic o Fixed the Router UP Time. +* Apr 28, 2000 Nenad Corbic o Added the option to shutdown an interface +* when the channel gets disconnected. +* Apr 28, 2000 Nenad Corbic o Added M.Grants patch: disallow duplicate +* interface setups. +* Apr 25, 2000 Nenad Corbic o Added M.Grants patch: dynamically add/remove +* new dlcis/interfaces. +* Mar 23, 2000 Nenad Corbic o Improved task queue, bh handling. +* Mar 16, 2000 Nenad Corbic o Added Inverse ARP support +* Mar 13, 2000 Nenad Corbic o Added new socket API support. +* Mar 06, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. +* Feb 24, 2000 Nenad Corbic o Fixed up FT1 UDP debugging problem. +* Dev 15, 1999 Nenad Corbic o Fixed up header files for 2.0.X kernels +* * Nov 08, 1999 Nenad Corbic o Combined all debug UDP calls into one function * o Removed the ARP support. This has to be done * in the next version. @@ -109,12 +138,12 @@ * Jan 02, 1997 Gene Kozin Initial version. *****************************************************************************/ -#include <linux/config.h> +#include <linux/version.h> #include <linux/kernel.h> /* printk(), and other useful stuff */ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ #include <linux/string.h> /* inline memset(), etc. */ -#include <linux/slab.h> /* kmalloc(), kfree() */ +#include <linux/malloc.h> /* kmalloc(), kfree() */ #include <linux/wanrouter.h> /* WAN router definitions */ #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ #include <linux/if_arp.h> /* ARPHRD_* defines */ @@ -123,14 +152,29 @@ #include <linux/time.h> /* for do_gettimeofday */ #include <linux/in.h> /* sockaddr_in */ #include <linux/inet.h> /* in_ntoa(), etc... */ -#include <asm/uaccess.h> -#include <linux/inetdevice.h> +#include <asm/errno.h> + #include <linux/ip.h> -#include <net/route.h> /* Dynamic Route Creation */ #include <linux/if.h> -#include <linux/sdla_fr.h> /* frame relay firmware API definitions */ - +#include <linux/if_wanpipe_common.h> /* Wanpipe Socket */ +#include <linux/if_wanpipe.h> + +#include <linux/sdla_fr.h> /* frame relay firmware API definitions */ + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + #include <asm/uaccess.h> + #include <linux/inetdevice.h> + #include <linux/netdevice.h> + +#else + #include <asm/segment.h> +#endif + +#include <net/route.h> /* Dynamic Route Creation */ +#include <linux/etherdevice.h> /* eth_type_trans() used for bridging */ +#include <linux/random.h> + /****** Defines & Macros ****************************************************/ #define MAX_CMD_RETRY 10 /* max number of firmware retries */ @@ -151,25 +195,20 @@ #define CIR_ENABLED 0x00 #define CIR_DISABLED 0x01 -#define WANPIPE 0x00 -#define API 0x01 #define FRAME_RELAY_API 1 - -#define TX_TIMEOUT (5*HZ) +#define MAX_BH_BUFF 10 /* For handle_IPXWAN() */ #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) /****** Data Structures *****************************************************/ -/* This is an extention of the 'struct net_device' we create for each network +/* This is an extention of the 'struct device' we create for each network * interface to keep the rest of channel-specific data. */ typedef struct fr_channel { - /* This member must be first. */ - struct net_device *slave; /* WAN slave */ - + wanpipe_common_t common; char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ unsigned dlci_configured ; /* check whether configured or not */ unsigned cir_status; /* check whether CIR enabled or not */ @@ -183,7 +222,6 @@ unsigned long router_start_time;/* Router start time in seconds */ unsigned long tick_counter; /* counter for transmit time out */ char dev_pending_devtint; /* interface pending dev_tint() */ - char state; /* channel state */ void *dlci_int_interface; /* pointer to the DLCI Interface */ unsigned long IB_addr; /* physical address of Interface Byte */ unsigned long state_tick; /* time of the last state change */ @@ -192,19 +230,52 @@ sdla_t *card; /* -> owner */ unsigned route_flag; /* Add/Rem dest addr in route tables */ unsigned inarp; /* Inverse Arp Request status */ + unsigned char inarp_ready; /* Ready to send requests */ int inarp_interval; /* Time between InArp Requests */ unsigned long inarp_tick; /* InArp jiffies tick counter */ + unsigned char interface_down; /* Bring interface down on disconnect */ + #if defined(LINUX_2_1) || defined(LINUX_2_4) struct net_device_stats ifstats; /* interface statistics */ + #else + struct enet_statistics ifstats; + #endif if_send_stat_t drvstats_if_send; rx_intr_stat_t drvstats_rx_intr; pipe_mgmt_stat_t drvstats_gen; - - unsigned char usedby; /* Used by WANPIPE or API */ - unsigned long router_up_time; unsigned short transmit_length; - char transmit_buffer[FR_MAX_NO_DATA_BYTES_IN_FRAME]; + struct sk_buff *delay_skb; + + + #if defined(LINUX_2_1) || defined(LINUX_2_4) + bh_data_t *bh_head; /* Circular buffer for chdlc_bh */ + unsigned long tq_working; + volatile int bh_write; + volatile int bh_read; + atomic_t bh_buff_used; + #endif + + /* Polling task queue. Each interface + * has its own task queue, which is used + * to defer events from the interrupt */ + struct tq_struct fr_poll_task; + struct timer_list fr_arp_timer; + + u32 ip_local; + u32 ip_remote; + u8 config_dlci; + u32 unconfig_dlci; + + /* Whether this interface should be setup as a gateway. + * Used by dynamic route setup code */ + u8 gateway; + + /* True interface type */ + u8 true_if_encoding; + u8 fr_header[FR_HEADER_LEN]; + char fr_header_len; + } fr_channel_t; /* Route Flag options */ @@ -212,6 +283,7 @@ #define ADD_ROUTE 0x01 #define ROUTE_ADDED 0x02 #define REMOVE_ROUTE 0x03 +#define ARP_REQ 0x04 /* inarp options */ #define INARP_NONE 0x00 @@ -221,6 +293,10 @@ /* reasons for enabling the timer interrupt on the adapter */ #define TMR_INT_ENABLED_UDP 0x01 #define TMR_INT_ENABLED_UPDATE 0x02 +#define TMR_INT_ENABLED_ARP 0x04 +#define TMR_INT_ENABLED_UPDATE_STATE 0x08 +#define TMR_INT_ENABLED_CONFIG 0x10 +#define TMR_INT_ENABLED_UNCONFIG 0x20 typedef struct dlci_status @@ -248,7 +324,6 @@ /* variable for keeping track of enabling/disabling FT1 monitor status */ static int rCount = 0; -extern int ip_rt_ioctl(unsigned int, void *); extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); @@ -256,27 +331,43 @@ * interrupt test routine */ static int Intr_test_counter; + /****** Function Prototypes *************************************************/ /* WAN link driver entry points. These are called by the WAN router module. */ static int update(wan_device_t *wandev); -static int new_if(wan_device_t *wandev, struct net_device *dev, wanif_conf_t *conf); -static int del_if(wan_device_t *wandev, struct net_device *dev); +static int new_if(wan_device_t *wandev, netdevice_t *dev, wanif_conf_t *conf); +static int del_if(wan_device_t *wandev, netdevice_t *dev); +static void disable_comm (sdla_t *card); /* WANPIPE-specific entry points */ static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data); /* Network device interface */ -static int if_init(struct net_device *dev); -static int if_open(struct net_device *dev); -static int if_close(struct net_device *dev); -static int if_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len); -static int if_rebuild_hdr(struct sk_buff *skb); -static int if_send(struct sk_buff *skb, struct net_device *dev); -static void if_tx_timeout (struct net_device *dev); -static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, +static int if_init(netdevice_t *dev); +static int if_open(netdevice_t *dev); +static int if_close(netdevice_t *dev); + + +#ifdef LINUX_2_4 +static void if_tx_timeout (netdevice_t *dev); +#endif + +#if defined(LINUX_2_1) || defined(LINUX_2_4) +static int if_rebuild_hdr (struct sk_buff *skb); +#else +static int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr, + struct sk_buff* skb); +#endif + +static int if_send(struct sk_buff *skb, netdevice_t *dev); +static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev, struct sk_buff *skb); -static struct net_device_stats *if_stats(struct net_device *dev); +#if defined(LINUX_2_1) || defined(LINUX_2_4) +static struct net_device_stats *if_stats(netdevice_t *dev); +#else +static struct enet_statistics* if_stats (netdevice_t* dev); +#endif /* Interrupt handlers */ static void fr_isr(sdla_t *card); @@ -292,7 +383,7 @@ static int fr_init_dlci (sdla_t *card, fr_channel_t *chan); static int fr_set_intr_mode (sdla_t *card, unsigned mode, unsigned mtu, unsigned short timeout); static int fr_comm_enable(sdla_t *card); -static int fr_comm_disable(sdla_t *card); +static void fr_comm_disable(sdla_t *card); static int fr_get_err_stats(sdla_t *card); static int fr_get_stats(sdla_t *card); static int fr_add_dlci(sdla_t *card, int dlci); @@ -301,6 +392,13 @@ static int fr_issue_isf(sdla_t *card, int isf); static int fr_send(sdla_t *card, int dlci, unsigned char attr, int len, void *buf); +static int fr_send_data_header(sdla_t *card, int dlci, unsigned char attr, int len, + void *buf,unsigned char hdr_len); +static unsigned int fr_send_hdr(sdla_t *card, int dlci, unsigned int offset); + +static int check_dlci_config (sdla_t *card, fr_channel_t *chan); +static void initialize_rx_tx_buffers (sdla_t *card); + /* Firmware asynchronous event handlers */ static int fr_event(sdla_t *card, int event, fr_mbox_t *mbox); @@ -308,9 +406,9 @@ static int fr_dlci_change(sdla_t *card, fr_mbox_t *mbox); /* Miscellaneous functions */ -static int update_chan_state(struct net_device *dev); -static void set_chan_state(struct net_device *dev, int state); -static struct net_device *find_channel(sdla_t *card, unsigned dlci); +static int update_chan_state(netdevice_t *dev); +static void set_chan_state(netdevice_t *dev, int state); +static netdevice_t *find_channel(sdla_t *card, unsigned dlci); static int is_tx_ready(sdla_t *card, fr_channel_t *chan); static unsigned int dec_to_uint(unsigned char *str, int len); static int reply_udp( unsigned char *data, unsigned int mbox_len ); @@ -319,14 +417,38 @@ static void init_chan_statistics( fr_channel_t* chan ); static void init_global_statistics( sdla_t* card ); static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ); -static void setup_for_delayed_transmit(struct net_device* dev, void* buf, - unsigned len); +static int setup_for_delayed_transmit(netdevice_t* dev, struct sk_buff *skb); + +netdevice_t * move_dev_to_next (sdla_t *, netdevice_t *); +static int check_tx_status(sdla_t *, netdevice_t *); + +#if defined(LINUX_2_1) || defined(LINUX_2_4) +/* Frame Relay Socket API */ +static void trigger_fr_bh (fr_channel_t *); +static void fr_bh (netdevice_t *); +static int fr_bh_cleanup (netdevice_t *); +static int bh_enqueue (netdevice_t *, struct sk_buff *); +#endif + +static void trigger_fr_poll (netdevice_t *); +static void fr_poll (netdevice_t *); +//static void add_gateway (netdevice_t *); + +static void trigger_unconfig_fr (netdevice_t *dev); +static void unconfig_fr (sdla_t *); + +static void trigger_config_fr (sdla_t *); +static void config_fr (sdla_t *); /* Inverse ARP and Dynamic routing functions */ -int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device *dev); +int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, netdevice_t *dev); int is_arp(void *buf); -int send_inarp_request(sdla_t *card, struct net_device *dev); +int send_inarp_request(sdla_t *card, netdevice_t *dev); + +static void trigger_fr_arp (netdevice_t *); +static void fr_arp (unsigned long data); + /* Udp management functions */ static int process_udp_mgmt_pkt(sdla_t *card); @@ -346,6 +468,7 @@ void s508_s514_lock(sdla_t *card, unsigned long *smp_flags); unsigned short calc_checksum (char *, int); +static int setup_fr_header(struct sk_buff** skb, netdevice_t* dev, char op_mode); /****** Public Functions ****************************************************/ @@ -366,15 +489,20 @@ { int err; + fr508_flags_t* flags; union { char str[80]; fr_conf_t cfg; } u; + fr_buf_info_t* buf_info; int i; + + printk(KERN_INFO "\n"); + /* Verify configuration ID */ if (conf->config_id != WANCONFIG_FR) { @@ -403,6 +531,8 @@ return -EINVAL; } + flags = card->flags; + /* Read firmware version. Note that when adapter initializes, it * clears the mailbox, so it may appear that the first command was * executed successfully when in fact it was merely erased. To work @@ -429,7 +559,7 @@ memset(card->u.f.dlci_to_dev_map, 0, sizeof(card->u.f.dlci_to_dev_map)); /* Configure adapter firmware */ - + u.cfg.mtu = conf->mtu; u.cfg.kbps = conf->bps / 1000; @@ -546,9 +676,7 @@ (void*)(buf_info->rse_base + (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) + card->hw.dpmbase); - } - - else { + }else{ buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS); card->rxmb = (void*)(buf_info->rse_next - @@ -582,6 +710,8 @@ card->wandev.state = WAN_DISCONNECTED; card->wandev.ttl = conf->ttl; card->wandev.udp_port = conf->udp_port; + card->disable_comm = &disable_comm; + card->u.f.arp_dev = NULL; /* Intialize global statistics for a card */ init_global_statistics( card ); @@ -593,11 +723,13 @@ card->intr_mode = INTR_TEST_MODE; err = intr_test( card ); + printk(KERN_INFO "%s: End of Interrupt Test rc=0x%x count=%i\n", + card->devname,err,Intr_test_counter); + if (err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { - printk( - "%s: Interrupt Test Failed, Counter: %i\n", + printk(KERN_ERR "%s: Interrupt Test Failed, Counter: %i\n", card->devname, Intr_test_counter); - printk( "Please choose another interrupt\n"); + printk(KERN_ERR "Please choose another interrupt\n"); err = -EIO; return err; } @@ -606,6 +738,32 @@ card->devname, Intr_test_counter); + /* Apr 28 2000. Nenad Corbic + * Enable commnunications here, not in if_open or new_if, since + * interfaces come down when the link is disconnected. + */ + + /* If you enable comms and then set ints, you get a Tx int as you + * perform the SET_INT_TRIGGERS command. So, we only set int + * triggers and then adjust the interrupt mask (to disable Tx ints) + * before enabling comms. + */ + if (fr_set_intr_mode(card, (FR_INTR_RXRDY | FR_INTR_TXRDY | + FR_INTR_DLC | FR_INTR_TIMER | FR_INTR_TX_MULT_DLCIs) , + card->wandev.mtu, 0)) { + return -EIO; + } + + flags->imask &= ~(FR_INTR_TXRDY | FR_INTR_TIMER); + + if (fr_comm_enable(card)) { + return -EIO; + } + wanpipe_set_state(card, WAN_CONNECTED); + spin_lock_init(&card->u.f.if_send_lock); + + printk(KERN_INFO "\n"); + return 0; } @@ -627,9 +785,6 @@ if (wandev->state == WAN_UNCONFIGURED) return -ENODEV; - if (test_bit(1, (void*)&wandev->critical)) - return -EAGAIN; - card = wandev->private; flags = card->flags; @@ -646,6 +801,7 @@ return -EAGAIN; } } + return 0; } @@ -661,16 +817,17 @@ * Return: 0 o.k. * < 0 failure (channel will not be created) */ -static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf) +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) { sdla_t* card = wandev->private; fr_channel_t* chan; int dlci = 0; int err = 0; + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { - printk(KERN_INFO "%s: invalid interface name!\n", + printk(KERN_INFO "%s: Invalid interface name!\n", card->devname); return -EINVAL; } @@ -684,7 +841,7 @@ memset(chan, 0, sizeof(fr_channel_t)); strcpy(chan->name, conf->name); chan->card = card; - + /* verify media address */ if (is_digit(conf->addr[0])) { @@ -697,36 +854,89 @@ } else { printk(KERN_ERR - "%s: invalid DLCI %u on interface %s!\n", + "%s: Invalid DLCI %u on interface %s!\n", wandev->name, dlci, chan->name); err = -EINVAL; } } else { printk(KERN_ERR - "%s: invalid media address on interface %s!\n", + "%s: Invalid media address on interface %s!\n", wandev->name, chan->name); err = -EINVAL; } - /* Setup wanpipe as a router (WANPIPE) or as an API */ - if(strcmp(conf->usedby, "WANPIPE") == 0){ - printk(KERN_INFO "%s: Running in WANPIPE mode %s\n", - wandev->name, chan->name); - chan->usedby = WANPIPE; + if ((chan->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){ + printk(KERN_INFO + "%s: Enabling, true interface type encoding.\n", + card->devname); + } + - } else if(strcmp(conf->usedby, "API") == 0){ -#ifdef FRAME_RELAY_API - chan->usedby = API; - printk(KERN_INFO "%s: Running in API mode %s\n", - wandev->name, chan->name); + /* Setup wanpipe as a router (WANPIPE) even if it is + * a bridged DLCI, or as an API + */ + if (strcmp(conf->usedby, "WANPIPE") == 0 || + strcmp(conf->usedby, "BRIDGE") == 0 || + strcmp(conf->usedby, "BRIDGE_N") == 0){ + + if(strcmp(conf->usedby, "WANPIPE") == 0){ + chan->common.usedby = WANPIPE; + + printk(KERN_INFO "%s: Running in WANPIPE mode.\n", + card->devname); + + }else if(strcmp(conf->usedby, "BRIDGE") == 0){ + + chan->common.usedby = BRIDGE; + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE) mode.\n", + card->devname); +#else + printk(KERN_INFO "%s: WANPIPE Bridging mode not supported in 2.0.X kernels.\n", + card->devname); + err = -EPROTONOSUPPORT; +#endif + }else if( strcmp(conf->usedby, "BRIDGE_N") == 0 ){ + + chan->common.usedby = BRIDGE_NODE; + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE_NODE) mode.\n", + card->devname); #else - printk(KERN_INFO "%s: API Mode is not supported !\n", + printk(KERN_INFO "%s: WANPIPE Bridging mode not supported in 2.0.X kernels.\n", + card->devname); + err = -EPROTONOSUPPORT; +#endif + } + + if (!err){ + /* Dynamic interface configuration option. + * On disconnect, if the options is selected, + * the interface will be brought down */ + if (conf->if_down == WANOPT_YES){ + set_bit(DYN_OPT_ON,&chan->interface_down); + printk(KERN_INFO + "%s: Dynamic interface configuration enabled.\n", + card->devname); + } + } + + } else if(strcmp(conf->usedby, "API") == 0){ + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + chan->common.usedby = API; + printk(KERN_INFO "%s: Running in API mode.\n", wandev->name); - printk(KERN_INFO - "%s: API patch can be obtained from Sangoma Tech.\n", - wandev->name); +#else + printk(KERN_INFO "%s: The API Mode is not supported for" + "kernels lower than 2.2.X !\n", + wandev->name); + printk(KERN_INFO "%s: Please upgrade to a 2.2.X kernel for the API support\n", + wandev->name); err = -EINVAL; #endif } @@ -737,8 +947,6 @@ return err; } - card->u.f.dlci_to_dev_map[dlci] = dev; - /* place cir,be,bc and other channel specific information into the * chan structure */ @@ -774,20 +982,24 @@ chan->mc = conf->mc; - /* FIXME: ARP is not supported by this frame relay verson */ if (conf->inarp == WANOPT_YES){ - printk(KERN_INFO "%s: ERROR - This version of WANPIPE doesn't support ARPs\n", +#if defined(LINUX_2_1) || defined(LINUX_2_4) + printk(KERN_INFO "%s: Inverse ARP Support Enabled\n",card->devname); + chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE; + chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10; +#else + printk(KERN_INFO "%s: Warning, Inverse ARP Support not available for 2.0.X kernels!\n", card->devname); - - //chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE; - //chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10; - kfree(chan); - return -EINVAL; + chan->inarp = INARP_NONE; + chan->inarp_interval = 10; +#endif }else{ + printk(KERN_INFO "%s: Inverse ARP Support Disabled\n",card->devname); chan->inarp = INARP_NONE; chan->inarp_interval = 10; } + chan->dlci_configured = DLCI_NOT_CONFIGURED; @@ -814,64 +1026,107 @@ chan->transmit_length = 0; /* prepare network device data space for registration */ - strcpy(dev->name, chan->name); +#ifdef LINUX_2_4 + strcpy(dev->name,chan->name); +#else + dev->name = (char *)kmalloc(strlen(chan->name) + 2, GFP_KERNEL); + if(dev->name == NULL) + { + kfree(chan); + return -ENOMEM; + } + sprintf(dev->name, "%s", chan->name); +#endif + dev->init = &if_init; dev->priv = chan; - - /* Enable Interrupts and Communications */ - if (!wandev->new_if_cnt){ - fr508_flags_t* flags = card->flags; - - wandev->new_if_cnt++; - - /* - If you enable comms and then set ints, you get a Tx int as you - perform the SET_INT_TRIGGERS command. So, we only set int - triggers and then adjust the interrupt mask (to disable Tx ints) - before enabling comms. - */ - if (fr_set_intr_mode(card, (FR_INTR_RXRDY | FR_INTR_TXRDY | - FR_INTR_DLC | FR_INTR_TIMER | FR_INTR_TX_MULT_DLCIs) , - card->wandev.mtu, 0)) { - kfree(chan); - return -EIO; - } - - flags->imask &= ~(FR_INTR_TXRDY | FR_INTR_TIMER); - - if (fr_comm_enable(card)) { - kfree(chan); - return -EIO; - } - wanpipe_set_state(card, WAN_CONNECTED); + /* Initialize FR Polling Task Queue + * We need a poll routine for each network + * interface. + */ +#ifndef LINUX_2_4 + chan->fr_poll_task.next = NULL; +#endif + chan->fr_poll_task.sync = 0; + chan->fr_poll_task.routine = (void *)(void *)fr_poll; + chan->fr_poll_task.data = dev; + + init_timer(&chan->fr_arp_timer); + chan->fr_arp_timer.data=(unsigned long)dev; + chan->fr_arp_timer.function = fr_arp; + + wandev->new_if_cnt++; + + /* Tells us that if this interface is a + * gateway or not */ + if ((chan->gateway = conf->gateway) == WANOPT_YES){ + printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", + card->devname,dev->name); + } + + /* M. Grant Patch Apr 28 2000 + * Disallow duplicate dlci configurations. */ + if (card->u.f.dlci_to_dev_map[chan->dlci] != NULL) { + kfree(chan); + return -EBUSY; } + /* Configure this dlci at a later date, when + * the interface comes up. i.e. when if_open() + * executes */ + set_bit(0,&chan->config_dlci); + + printk(KERN_INFO "\n"); + return 0; } /*============================================================================ * Delete logical channel. */ -static int del_if (wan_device_t* wandev, struct net_device* dev) +static int del_if (wan_device_t* wandev, netdevice_t* dev) { - sdla_t *card = wandev->private; + fr_channel_t* chan = dev->priv; + unsigned long smp_flags=0; - /* Execute shutdown very first time we enter del_if */ + /* This interface is dead, make sure the + * ARP timer is stopped */ + del_timer(&chan->fr_arp_timer); + + /* If we are a NODE, we must unconfigure this DLCI + * Trigger an unconfigure command that will + * be executed in timer interrupt. We must wait + * for the command to complete. */ + trigger_unconfig_fr(dev); + + lock_adapter_irq(&wandev->lock, &smp_flags); + wandev->new_if_cnt--; + unlock_adapter_irq(&wandev->lock, &smp_flags); - if (!wandev->del_if_cnt) { - wandev->del_if_cnt++; - wanpipe_set_state(card, WAN_DISCONNECTED); - fr_set_intr_mode(card, 0, 0, 0); - fr_comm_disable(card); - } + return 0; +} - if (dev->priv) { - kfree(dev->priv); - dev->priv = NULL; - } - return 0; +/*===================================================================== + * disable_comm + * + * Description: + * Disable communications. + * This code runs in shutdown (sdlamain.c) + * under critical flag. Therefore it is not + * necessary to set a critical flag here + * + * Usage: + * Commnunications are disabled only on a card + * shutdown. + */ + +static void disable_comm (sdla_t *card) +{ + printk(KERN_INFO "%s: Disabling Communications!\n", + card->devname); + fr_comm_disable(card); } /****** WANPIPE-specific entry points ***************************************/ @@ -886,6 +1141,8 @@ int err, len; fr_cmd_t cmd; +#if defined(LINUX_2_1) || defined(LINUX_2_4) + if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) return -EFAULT; @@ -916,6 +1173,43 @@ return -EFAULT; return 0; +#else + if (!u_cmd || verify_area(VERIFY_WRITE, u_cmd, sizeof(fr_cmd_t))) + return -EFAULT; + + memcpy_fromfs((void*)&cmd, u_cmd, sizeof(cmd)); + + if (cmd.length) { + + if (!u_data || verify_area(VERIFY_READ, u_data, cmd.length)) + return -EFAULT; + } + + /* execute command */ + do + { + memcpy(&mbox->cmd, &cmd, sizeof(cmd)); + + if (cmd.length) + memcpy_fromfs((void*)&mbox->data, u_data, cmd.length); + + if (sdla_exec(mbox)) + err = mbox->cmd.result; + + else return -EIO; + } while (err && retry-- && fr_event(card, err, mbox)); + + /* return result */ + memcpy_tofs(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t)); + len = mbox->cmd.length; + + if (len && u_data && !verify_area(VERIFY_WRITE, u_data, len)) + memcpy_tofs(u_data, (void*)&mbox->data, len); + + return 0; + +#endif + } /****** Network Device Interface ********************************************/ @@ -927,44 +1221,81 @@ * interface registration. Returning anything but zero will fail interface * registration. */ -static int if_init (struct net_device* dev) +static int if_init (netdevice_t* dev) { fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; wan_device_t* wandev = &card->wandev; +#ifdef LINUX_2_0 + int i; +#endif /* Initialize device driver entry points */ dev->open = &if_open; dev->stop = &if_close; - dev->hard_header = &if_header; + dev->hard_header = NULL; dev->rebuild_header = &if_rebuild_hdr; dev->hard_start_xmit = &if_send; dev->get_stats = &if_stats; +#ifdef LINUX_2_4 dev->tx_timeout = &if_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#endif + + if (chan->common.usedby == WANPIPE || chan->common.usedby == API){ +#ifdef LINUX_2_0 + dev->family = AF_INET; +#endif + /* Initialize media-specific parameters */ + if (chan->true_if_encoding){ + dev->type = ARPHRD_DLCI; /* This breaks tcpdump */ + }else{ + dev->type = ARPHRD_PPP; /* ARP h/w type */ + } + + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; - /* Initialize media-specific parameters */ - dev->type = ARPHRD_DLCI; /* ARP h/w type */ - dev->flags |= IFF_POINTOPOINT; - - /* Enable Multicast addressing */ - if (chan->mc == WANOPT_YES){ - dev->flags |= IFF_MULTICAST; - } + /* Enable Multicast addressing */ + if (chan->mc == WANOPT_YES){ + dev->flags |= IFF_MULTICAST; + } - dev->mtu = wandev->mtu - FR_HEADER_LEN; - /* For an API, the maximum number of bytes that the stack will pass - to the driver is (dev->mtu + dev->hard_header_len). So, adjust the - mtu so that a frame of maximum size can be transmitted by the API. - */ - if(chan->usedby == API) { - dev->mtu += (sizeof(api_tx_hdr_t) - FR_HEADER_LEN); - } - - dev->hard_header_len = FR_HEADER_LEN;/* media header length */ - dev->addr_len = 2; /* hardware address length */ - *(unsigned short*)dev->dev_addr = htons(chan->dlci); + dev->mtu = wandev->mtu - FR_HEADER_LEN; + /* For an API, the maximum number of bytes that the stack will pass + to the driver is (dev->mtu + dev->hard_header_len). So, adjust the + mtu so that a frame of maximum size can be transmitted by the API. + */ + if(chan->common.usedby == API) { + dev->mtu += (sizeof(api_tx_hdr_t) - FR_HEADER_LEN); + } + + dev->hard_header_len = FR_HEADER_LEN;/* media header length */ + dev->addr_len = 2; /* hardware address length */ + *(unsigned short*)dev->dev_addr = htons(chan->dlci); + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 100; + + /* Initialize socket buffers */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) + dev_init_buffers(dev); +#else + for (i = 0; i < DEV_NUMBUFFS; ++i) + skb_queue_head_init(&dev->buffs[i]); +#endif + }else{ + /* Setup the interface for Bridging */ + int hw_addr=0; + ether_setup(dev); + + /* Use a random number to generate the MAC address */ + memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6); + get_random_bytes(&hw_addr, sizeof(hw_addr)); + *(int *)(dev->dev_addr + 2) += hw_addr; + } + /* Initialize hardware parameters (just for reference) */ dev->irq = wandev->irq; dev->dma = wandev->dma; @@ -972,13 +1303,6 @@ dev->mem_start = wandev->maddr; dev->mem_end = wandev->maddr + wandev->msize - 1; - /* Set transmit buffer queue length */ - dev->tx_queue_len = 100; - - /* Initialize socket buffers */ - dev_init_buffers(dev); - - set_chan_state(dev, WAN_DISCONNECTED); return 0; } @@ -989,60 +1313,51 @@ * * Return 0 if O.k. or errno. */ -static int if_open (struct net_device* dev) +static int if_open (netdevice_t* dev) { fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; int err = 0; struct timeval tv; - if (netif_running(dev)) - return -EBUSY; /* only one open is allowed */ - - if (test_and_set_bit(1, (void*)&card->wandev.critical)) - return -EAGAIN; + if (is_dev_running(dev)) + return -EBUSY; +#if defined(LINUX_2_1) || defined(LINUX_2_4) + /* Initialize the task queue */ + chan->tq_working=0; - /* If signalling is set to NO, then setup - * DLCI addresses right away. Don't have to wait for - * link to connect. - */ - if (card->wandev.signalling == WANOPT_NO){ - printk(KERN_INFO "%s: Signalling set to NO: Mapping DLCI's\n", - card->wandev.name); - if (fr_init_dlci(card,chan)){ - return -EAGAIN; - } - } - - if (card->wandev.station == WANOPT_CPE) { - - /* CPE: issue full status enquiry */ - fr_issue_isf(card, FR_ISF_FSE); - - } else { /* FR switch: activate DLCI(s) */ - - /* For Switch emulation we have to ADD and ACTIVATE - * the DLCI(s) that were configured with the SET_DLCI_ - * CONFIGURATION command. Add and Activate will fail if - * DLCI specified is not included in the list. - * - * Also If_open is called once for each interface. But - * it does not get in here for all the interface. So - * we have to pass the entire list of DLCI(s) to add - * activate routines. - */ - - fr_add_dlci(card, chan->dlci); - fr_activate_dlci(card, chan->dlci); - } +#ifndef LINUX_2_4 + chan->common.wanpipe_task.next = NULL; +#endif + chan->common.wanpipe_task.sync = 0; + chan->common.wanpipe_task.routine = (void *)(void *)fr_bh; + chan->common.wanpipe_task.data = dev; + + /* Allocate and initialize BH circular buffer */ + chan->bh_head = kmalloc((sizeof(bh_data_t)*MAX_BH_BUFF),GFP_ATOMIC); + memset(chan->bh_head,0,(sizeof(bh_data_t)*MAX_BH_BUFF)); + atomic_set(&chan->bh_buff_used, 0); +#endif +#ifdef LINUX_2_4 netif_start_queue(dev); +#else + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; +#endif + wanpipe_open(card); - update_chan_state(dev); do_gettimeofday( &tv ); chan->router_start_time = tv.tv_sec; - clear_bit(1, (void*)&card->wandev.critical); + + if (test_bit(0,&chan->config_dlci)){ + trigger_config_fr (card); + }else if (chan->inarp == INARP_REQUEST){ + trigger_fr_arp(dev); + } + return err; } @@ -1051,61 +1366,42 @@ * o if this is the last open, then disable communications and interrupts. * o reset flags. */ -static int if_close (struct net_device* dev) +static int if_close (netdevice_t* dev) { fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; - if (test_and_set_bit(1, (void*)&card->wandev.critical)) - return -EAGAIN; + if (chan->inarp == INARP_CONFIGURED) { + chan->inarp = INARP_REQUEST; + } - netif_stop_queue(dev); + stop_net_queue(dev); +#ifndef LINUX_2_4 + dev->start=0; +#endif wanpipe_close(card); - if (card->wandev.station == WANOPT_NODE) { - fr_delete_dlci (card,chan->dlci); - } - clear_bit(1, (void*)&card->wandev.critical); return 0; } /*============================================================================ - * Build media header. - * o encapsulate packet according to encapsulation type. - * - * The trick here is to put packet type (Ethertype) into 'protocol' field of - * the socket buffer, so that we don't forget it. If encapsulation fails, - * set skb->protocol to 0 and discard packet later. - * - * Return: media header length. - */ -static int if_header (struct sk_buff* skb, struct net_device* dev, - unsigned short type, void* daddr, void* saddr, unsigned len) -{ - int hdr_len = 0; - - skb->protocol = type; - hdr_len = wanrouter_encapsulate(skb, dev); - - if (hdr_len < 0) { - hdr_len = 0; - skb->protocol = 0; - } - skb_push(skb, 1); - skb->data[0] = Q922_UI; - ++hdr_len; - return hdr_len; -} - -/*============================================================================ * Re-build media header. * * Return: 1 physical address resolved. * 0 physical address not resolved */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) static int if_rebuild_hdr (struct sk_buff* skb) { - struct net_device *dev = skb->dev; +#else +static int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr, + struct sk_buff* skb) +{ +#endif + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + netdevice_t *dev = skb->dev; +#endif fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; @@ -1114,13 +1410,14 @@ return 1; } - +#ifdef LINUX_2_4 /*============================================================================ * Handle transmit timeout event from netif watchdog */ -static void if_tx_timeout (struct net_device *dev) +static void if_tx_timeout (netdevice_t *dev) { fr_channel_t* chan = dev->priv; + sdla_t *card = chan->card; /* If our device stays busy for at least 5 seconds then we will * kick start the device by making dev->tbusy = 0. We expect @@ -1131,12 +1428,13 @@ chan->drvstats_if_send.if_send_tbusy++; ++chan->ifstats.collisions; - printk (KERN_INFO "%s: Transmit timed out\n", chan->name); + printk (KERN_INFO "%s: Transmit timed out on %s\n", + card->devname, dev->name); chan->drvstats_if_send.if_send_tbusy_timeout++; netif_wake_queue (dev); } - +#endif /*============================================================================ * Send a packet on a network interface. @@ -1154,23 +1452,28 @@ * Notes: * 1. This routine is called either by the protocol stack or by the "net * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. + * + * 2. Using the start_net_queue() and stop_net_queue() MACROS + * will inhibit further transmit requests from the protocol stack + * and can be used for flow control with protocol layer. */ -static int if_send (struct sk_buff* skb, struct net_device* dev) +static int if_send (struct sk_buff* skb, netdevice_t* dev) { fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; int err; unsigned char *sendpacket; fr508_flags_t* adptr_flags = card->flags; - int udp_type, send_data; + int udp_type, delay_tx_queued=0; unsigned long smp_flags=0; - void* data; - unsigned len; + unsigned char attr = 0; chan->drvstats_if_send.if_send_entry++; +#ifdef LINUX_2_4 + netif_stop_queue(dev); +#endif + if (skb == NULL) { /* if we get here, some higher layer thinks we've missed an * tx-done interrupt. @@ -1178,7 +1481,19 @@ printk(KERN_INFO "%s: interface %s got kicked!\n", card->devname, dev->name); chan->drvstats_if_send.if_send_skb_null ++; - netif_wake_queue(dev); + + wake_net_dev(dev); + return 0; + } + + /* If a peripheral task is running just drop packets */ + if (test_bit(PERI_CRIT, &card->wandev.critical)){ + + printk(KERN_INFO "%s: Critical in if_send(): Peripheral running!\n", + card->devname); + + wan_dev_kfree_skb(skb,FREE_WRITE); + start_net_queue(dev); return 0; } @@ -1187,23 +1502,58 @@ ensure that the transmit interrupt does not reset the 'tbusy' flag just before we set it, as this will result in a "transmit timeout". */ - set_bit(2, (void*)&card->wandev.critical); + set_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); if(chan->transmit_length) { - netif_stop_queue(dev); - chan->tick_counter = jiffies; - clear_bit(2, (void*)&card->wandev.critical); + stop_net_queue(dev); + chan->tick_counter = jiffies; + clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); return 1; } - clear_bit(2, (void*)&card->wandev.critical); - - data = skb->data; + clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); + +#ifndef LINUX_2_4 + if (dev->tbusy) { + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + chan->drvstats_if_send.if_send_tbusy++; + ++chan->ifstats.collisions; + + if ((jiffies - chan->tick_counter) < (5 * HZ)) { + return 1; + } + + printk(KERN_INFO "%s: Transmit timed out on %s\n", + card->devname, chan->name); + chan->drvstats_if_send.if_send_tbusy_timeout ++; + dev->tbusy = 0; + } +#endif + + + /* Move the if_header() code to here. By inserting frame + * relay header in if_header() we would break the + * tcpdump and other packet sniffers */ + chan->fr_header_len = setup_fr_header(&skb,dev,chan->common.usedby); + if (chan->fr_header_len < 0 ){ + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + + wan_dev_kfree_skb(skb,FREE_WRITE); + start_net_queue(dev); + return 0; + } + sendpacket = skb->data; - len = skb->len; udp_type = udp_pkt_type(skb, card); if(udp_type != UDP_INVALID_TYPE) { - if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, skb, + if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, skb, chan->dlci)) { adptr_flags->imask |= FR_INTR_TIMER; if (udp_type == UDP_FPIPE_TYPE){ @@ -1211,61 +1561,92 @@ if_send_PIPE_request ++; } } + start_net_queue(dev); return 0; } - if((chan->usedby == API) && (len <= sizeof(api_tx_hdr_t))) { - //FIXME: increment some error statistic - dev_kfree_skb(skb); - return 0; - } - //FIXME: can we do better than sendpacket[2]? - if ((chan->usedby == WANPIPE) && (sendpacket[2] == 0x45)) { + if ((chan->common.usedby == WANPIPE) && (sendpacket[2] == 0x45)) { + /* check to see if the source IP address is a broadcast or */ /* multicast IP address */ - if(chk_bcast_mcast_addr(card, dev, skb)) - return 0; + if(chk_bcast_mcast_addr(card, dev, skb)){ + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + wan_dev_kfree_skb(skb, FREE_WRITE); + start_net_queue(dev); + return 0; + } } - /* Lock the 508 card: SMP Supported */ + + /* Lock the S514/S508 card: SMP Supported */ s508_s514_lock(card,&smp_flags); - if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { + chan->drvstats_if_send.if_send_critical_non_ISR ++; chan->ifstats.tx_dropped ++; - printk(KERN_INFO "%s Critical in IF_SEND %02X\n", - card->devname, card->wandev.critical); - dev_kfree_skb(skb); - /* Unlock the 508 card */ - s508_s514_unlock(card,&smp_flags); - return 0; + printk(KERN_INFO "%s Critical in IF_SEND: if_send() already running!\n", + card->devname); + goto if_send_start_and_exit; } - - if (card->wandev.state != WAN_CONNECTED) { - chan->drvstats_if_send.if_send_wan_disconnected ++; - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - } else if (chan->state != WAN_CONNECTED) { - chan->drvstats_if_send.if_send_dlci_disconnected ++; - /* Critical area on 514, since disabl_irq is not used - * thus, interrupt would execute a command at - * the same time as if_send. - */ - set_bit(1, (void*)&card->wandev.critical); - update_chan_state(dev); - clear_bit(1, (void*)&card->wandev.critical); - ++chan->ifstats.tx_dropped; + /* API packet check: minimum packet size must be greater than + * 16 byte API header */ + if((chan->common.usedby == API) && (skb->len <= sizeof(api_tx_hdr_t))) { + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + + + goto if_send_start_and_exit; + + }else{ + /* During API transmission, get rid of the API header */ + if (chan->common.usedby == API) { + api_tx_hdr_t* api_tx_hdr; + api_tx_hdr = (api_tx_hdr_t*)&skb->data[0x00]; + attr = api_tx_hdr->attr; + skb_pull(skb,sizeof(api_tx_hdr_t)); + } + } + + if (card->wandev.state != WAN_CONNECTED) { + chan->drvstats_if_send.if_send_wan_disconnected ++; + ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; + + } else if (chan->common.state != WAN_CONNECTED) { + chan->drvstats_if_send.if_send_dlci_disconnected ++; + + /* Update the DLCI state in timer interrupt */ + card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE_STATE; + adptr_flags->imask |= FR_INTR_TIMER; + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + } else if (!is_tx_ready(card, chan)) { - setup_for_delayed_transmit(dev, data, len); + /* No tx buffers available, store for delayed transmit */ + if (!setup_for_delayed_transmit(dev, skb)){ + set_bit(1,&delay_tx_queued); + } chan->drvstats_if_send.if_send_no_bfrs++; - } else { - send_data = 1; + + } else if (!skb->protocol) { + /* No protocols drop packet */ + chan->drvstats_if_send.if_send_protocol_error ++; + ++card->wandev.stats.tx_errors; + + } else if (test_bit(ARP_CRIT,&card->wandev.critical)){ + /* We are trying to send an ARP Packet, block IP data until + * ARP is sent */ + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + + } else { //FIXME: IPX is not implemented in this version of Frame Relay ? - if((chan->usedby == WANPIPE) && + if((chan->common.usedby == WANPIPE) && sendpacket[1] == 0x00 && sendpacket[2] == 0x80 && sendpacket[6] == 0x81 && @@ -1279,32 +1660,28 @@ printk(KERN_INFO "%s: WARNING: Unsupported IPX data in send, packet dropped\n", card->devname); - send_data = 0; - } - } - - if (send_data) { - unsigned char attr = 0; - - /* For an API transmission, get rid of the API header */ - if (chan->usedby == API) { - api_tx_hdr_t* api_tx_hdr; - api_tx_hdr = (api_tx_hdr_t*)&skb->data[0x00]; - attr = api_tx_hdr->attr; - data += sizeof(api_tx_hdr_t); - len -= sizeof(api_tx_hdr_t); } - - err = fr_send(card, chan->dlci, attr, len, data); + + }else{ + err = fr_send_data_header(card, chan->dlci, attr, skb->len, skb->data, chan->fr_header_len); if (err) { switch(err) { case FRRES_CIR_OVERFLOW: case FRRES_BUFFER_OVERFLOW: - setup_for_delayed_transmit(dev, data, - len); + if (!setup_for_delayed_transmit(dev, skb)){ + set_bit(1,&delay_tx_queued); + } chan->drvstats_if_send. if_send_adptr_bfrs_full ++; - break; + break; + + case FRRES_TOO_LONG: + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Error: Frame too long, transmission failed %i\n", + card->devname, (unsigned int)skb->len); + } + /* Drop down to default */ default: chan->drvstats_if_send. if_send_dlci_disconnected ++; @@ -1317,20 +1694,37 @@ if_send_bfr_passed_to_adptr++; ++chan->ifstats.tx_packets; ++card->wandev.stats.tx_packets; - chan->ifstats.tx_bytes += len; - card->wandev.stats.tx_bytes += len; + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + chan->ifstats.tx_bytes += skb->len; + card->wandev.stats.tx_bytes += skb->len; +#endif +#ifdef LINUX_2_4 + dev->trans_start = jiffies; +#endif } } } - if (!netif_queue_stopped(dev)) - dev_kfree_skb(skb); +if_send_start_and_exit: + + start_net_queue(dev); + + /* If we queued the packet for transmission, we must not + * deallocate it. The packet is unlinked from the IP stack + * not copied. Therefore, we must keep the original packet */ + if (!test_bit(1,&delay_tx_queued)) { + wan_dev_kfree_skb(skb, FREE_WRITE); + }else{ + adptr_flags->imask |= FR_INTR_TXRDY; + card->u.f.tx_interrupts_pending ++; + } - clear_bit(0, (void*)&card->wandev.critical); + clear_bit(SEND_CRIT, (void*)&card->wandev.critical); s508_s514_unlock(card,&smp_flags); - return (netif_queue_stopped(dev)); + return 0; } @@ -1339,33 +1733,49 @@ * Setup so that a frame can be transmitted on the occurence of a transmit * interrupt. */ -static void setup_for_delayed_transmit (struct net_device* dev, void* buf, - unsigned len) +static int setup_for_delayed_transmit (netdevice_t* dev, struct sk_buff *skb) { fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; - fr508_flags_t* adptr_flags = card->flags; - fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface; + fr_dlci_interface_t* dlci_interface; + int len = skb->len; + + /* Check that the dlci is properly configured, + * before using tx interrupt */ + if (!chan->dlci_int_interface){ + if (net_ratelimit()){ + printk(KERN_INFO + "%s: ERROR on DLCI %i: Not configured properly !\n", + card->devname, chan->dlci); + printk(KERN_INFO "%s: Please contact Sangoma Technologies\n", + card->devname); + } + return 1; + } + + dlci_interface = chan->dlci_int_interface; if(chan->transmit_length) { printk(KERN_INFO "%s: Big mess in setup_for_del...\n", card->devname); - return; + return 1; } if(len > FR_MAX_NO_DATA_BYTES_IN_FRAME) { //FIXME: increment some statistic */ - return; + return 1; } + skb_unlink(skb); + chan->transmit_length = len; - memcpy(chan->transmit_buffer, buf, len); - + chan->delay_skb = skb; + dlci_interface->gen_interrupt |= FR_INTR_TXRDY; dlci_interface->packet_length = len; - adptr_flags->imask |= FR_INTR_TXRDY; - card->u.f.tx_interrupts_pending ++; + /* Turn on TX interrupt at the end of if_send */ + return 0; } @@ -1375,18 +1785,21 @@ * Return 0 if not broadcast/multicast address, otherwise return 1. */ -static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, +static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev, struct sk_buff *skb) { u32 src_ip_addr; u32 broadcast_ip_addr = 0; +#if defined(LINUX_2_1) || defined(LINUX_2_4) struct in_device *in_dev; +#endif fr_channel_t* chan = dev->priv; /* read the IP source address from the outgoing packet */ src_ip_addr = *(u32 *)(skb->data + 14); /* read the IP broadcast address for the device */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) in_dev = dev->ip_ptr; if(in_dev != NULL) { struct in_ifaddr *ifa= in_dev->ifa_list; @@ -1395,13 +1808,15 @@ else return 0; } +#else + broadcast_ip_addr = dev->pa_brdaddr; +#endif /* check if the IP Source Address is a Broadcast address */ - if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { printk(KERN_INFO + if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { + printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", card->devname); - dev_kfree_skb(skb); - ++ chan->ifstats.tx_dropped; return 1; } @@ -1411,8 +1826,6 @@ printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", card->devname); - dev_kfree_skb(skb); - ++ chan->ifstats.tx_dropped; return 1; } @@ -1433,7 +1846,7 @@ fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)data; /* Set length of packet */ - len = sizeof(fr_encap_hdr_t)+ + len = //sizeof(fr_encap_hdr_t)+ sizeof(ip_pkt_t)+ sizeof(udp_pkt_t)+ sizeof(wp_mgmt_t)+ @@ -1481,7 +1894,7 @@ fr_udp_pkt->udp_pkt.udp_checksum = 0; fr_udp_pkt->udp_pkt.udp_checksum = - calc_checksum(&data[UDP_OFFSET+sizeof(fr_encap_hdr_t)], + calc_checksum(&data[UDP_OFFSET/*+sizeof(fr_encap_hdr_t)*/], udp_length+UDP_OFFSET); /* fill in IP length */ @@ -1499,7 +1912,7 @@ /* fill in IP checksum */ fr_udp_pkt->ip_pkt.hdr_checksum = 0; fr_udp_pkt->ip_pkt.hdr_checksum = - calc_checksum(&data[sizeof(fr_encap_hdr_t)], + calc_checksum(&data[/*sizeof(fr_encap_hdr_t)*/0], sizeof(ip_pkt_t)); return len; @@ -1588,9 +2001,13 @@ /*============================================================================ * Get ethernet-style interface statistics. - * Return a pointer to struct net_device_stats. + * Return a pointer to struct enet_statistics. */ -static struct net_device_stats* if_stats (struct net_device* dev) +#if defined(LINUX_2_1) || defined(LINUX_2_4) +static struct net_device_stats *if_stats(netdevice_t *dev) +#else +static struct enet_statistics* if_stats (netdevice_t* dev) +#endif { fr_channel_t* chan = dev->priv; @@ -1603,7 +2020,12 @@ /****** Interrupt Handlers **************************************************/ /*============================================================================ - * S508 frame relay interrupt service routine. + * fr_isr: S508 frame relay interrupt service routine. + * + * Description: + * Frame relay main interrupt service route. This + * function check the interrupt type and takes + * the appropriate action. */ static void fr_isr (sdla_t* card) { @@ -1613,26 +2035,25 @@ fr_mbox_t* mbox = card->mbox; /* This flag prevents nesting of interrupts. See sdla_isr() routine - * in sdlamain.c. - */ + * in sdlamain.c. */ card->in_isr = 1; ++card->statistics.isr_entry; - if(test_bit(1, (void*)&card->wandev.critical)) { - card->wandev.critical = 0; - flags->iflag = 0; - card->in_isr = 0; - return; - } + /* All peripheral (configuraiton, re-configuration) events + * take presidence over the ISR. Thus, retrigger */ + if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { + ++card->statistics.isr_already_critical; + goto fr_isr_exit; + } + if(card->hw.type != SDLA_S514) { - if (test_and_set_bit(0, (void*)&card->wandev.critical)) { - printk(KERN_INFO "%s: Critical while in ISR (0x%02X)\n", - card->devname, card->wandev.critical); + if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { + printk(KERN_INFO "%s: Critical while in ISR: If Send Running!\n", + card->devname); ++card->statistics.isr_already_critical; - card->in_isr = 0; - return; + goto fr_isr_exit; } } @@ -1649,12 +2070,12 @@ tx_intr(card); break; - case FR_INTR_READY: + case FR_INTR_READY: Intr_test_counter++; ++card->statistics.isr_intr_test; break; - case FR_INTR_DLC: /* Event interrupt occurred */ + case FR_INTR_DLC: /* Event interrupt occured */ mbox->cmd.command = FR_READ_STATUS; mbox->cmd.length = 0; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; @@ -1680,27 +2101,31 @@ break; } +fr_isr_exit: + card->in_isr = 0; flags->iflag = 0; - if(card->hw.type != SDLA_S514) - clear_bit(0, (void*)&card->wandev.critical); + return; } -/*============================================================================ - * Receive interrupt handler. - * When a receive interrupt occurs do the following: - * 1- Find the structure for the dlci that the interrupt occurred on - * 2- If it doesn't exist then print appropriate msg and goto step 8. - * 3- If it exist then copy data to a skb. - * 4- If skb contains Sangoma UDP data then process them - * 5- If skb contains IPXWAN data then send IPXWAN reply packets - * 6- If skb contains Inverse Arp data then send Inv Arp replies - * 7- If skb contains any other data then decapsulate the packet and - * send it to the stack. - * 8- Release the receive element and update receive pointers on the board +/*=========================================================== + * rx_intr Receive interrupt handler. + * + * Description + * Upon receiveing an interrupt: + * 1. Check that the firmware is in sync with + * the driver. + * 2. Find an appropriate network interface + * based on the received dlci number. + * 3. Check that the netowrk interface exists + * and that it's setup properly. + * 4. Copy the data into an skb buffer. + * 5. Check the packet type and take + * appropriate acton: UPD, API, ARP or Data. */ + static void rx_intr (sdla_t* card) { fr_rx_buf_ctl_t* frbuf = card->rxmb; @@ -1708,11 +2133,13 @@ fr_channel_t* chan; char *ptr = &flags->iflag; struct sk_buff* skb; - struct net_device* dev; + netdevice_t* dev; void* buf; unsigned dlci, len, offs, len_incl_hdr; int i, udp_type; + + /* Check that firmware buffers are in sync */ if (frbuf->flag != 0x01) { printk(KERN_INFO @@ -1725,6 +2152,16 @@ printk(KERN_INFO "\n"); ++card->statistics.rx_intr_corrupt_rx_bfr; + + /* Bug Fix: Mar 6 2000 + * If we get a corrupted mailbox, it means that driver + * is out of sync with the firmware. There is no recovery. + * If we don't turn off all interrupts for this card + * the machine will crash. + */ + printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); + printk(KERN_INFO "Please contact Sangoma Technologies !\n"); + fr_set_intr_mode(card, 0, 0, 0); return; } @@ -1732,134 +2169,206 @@ dlci = frbuf->dlci; offs = frbuf->offset; - /* Find network interface for this packet */ + /* Find the network interface for this packet */ dev = find_channel(card, dlci); - - if (dev == NULL) { + - /* unconfigured DLCI, so discard packet */ - printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n", + /* Check that the network interface is active and + * properly setup */ + if (dev == NULL) { + if( net_ratelimit()) { + printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n", card->devname, dlci); + } ++card->statistics.rx_intr_on_orphaned_DLCI; + ++card->wandev.stats.rx_dropped; + goto rx_done; + } - } else { - chan = dev->priv; + if ((chan = dev->priv) == NULL){ + if( net_ratelimit()) { + printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n", + card->devname, dlci); + } + ++card->statistics.rx_intr_on_orphaned_DLCI; + ++card->wandev.stats.rx_dropped; + goto rx_done; + } - skb = dev_alloc_skb(len); + skb = dev_alloc_skb(len); - if (!netif_running(dev) || (skb == NULL)) { - ++chan->ifstats.rx_dropped; - - if(netif_running(dev)) { + if (!is_dev_running(dev) || (skb == NULL)){ + ++chan->ifstats.rx_dropped; + + if(skb == NULL) { + if (net_ratelimit()) { printk(KERN_INFO - "%s: no socket buffers available!\n", - card->devname); - chan->drvstats_rx_intr.rx_intr_no_socket ++; - - } else - chan->drvstats_rx_intr. - rx_intr_dev_not_started ++; - } else { - /* Copy data to the socket buffer */ - if ((offs + len) > card->u.f.rx_top + 1) { - unsigned tmp = card->u.f.rx_top - offs + 1; - - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, offs, buf, tmp); - offs = card->u.f.rx_base; - len -= tmp; - } - - buf = skb_put(skb, len); - sdla_peek(&card->hw, offs, buf, len); - - udp_type = udp_pkt_type( skb, card ); - - if(udp_type != UDP_INVALID_TYPE) { - if(store_udp_mgmt_pkt(udp_type, - UDP_PKT_FRM_NETWORK, card, skb, dlci)) { - flags->imask |= FR_INTR_TIMER; - if (udp_type == UDP_FPIPE_TYPE){ - chan->drvstats_rx_intr. - rx_intr_PIPE_request ++; - } - } + "%s: no socket buffers available!\n", + card->devname); } + chan->drvstats_rx_intr.rx_intr_no_socket ++; + } - else if (chan->usedby == API) { - api_rx_hdr_t* api_rx_hdr; - chan->drvstats_rx_intr. - rx_intr_bfr_passed_to_stack ++; - chan->ifstats.rx_packets ++; - card->wandev.stats.rx_packets ++; - chan->ifstats.rx_bytes += skb->len; - card->wandev.stats.rx_bytes += skb->len; - - skb_push(skb, sizeof(api_rx_hdr_t)); - api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; - api_rx_hdr->attr = frbuf->attr; - api_rx_hdr->time_stamp = frbuf->tmstamp; - skb->protocol = htons(0x16); - skb->pkt_type = PACKET_HOST; - /* Pass it up the protocol stack */ - skb->dev = dev; - skb->mac.raw = skb->data; - netif_rx(skb); - - } else if (handle_IPXWAN(skb->data,chan->name, - chan->enable_IPX, chan->network_number)) { - if (chan->enable_IPX) { - fr_send(card, dlci, 0, skb->len, - skb->data); - } - dev_kfree_skb(skb); + if (!is_dev_running(dev)){ + chan->drvstats_rx_intr. + rx_intr_dev_not_started ++; + if (skb){ + wan_dev_kfree_skb(skb, FREE_READ); + } + } + goto rx_done; + } -/*FIXME: Fix the ARPS in next release + /* Copy data from the board into the socket buffer */ + if ((offs + len) > card->u.f.rx_top + 1) { + unsigned tmp = card->u.f.rx_top - offs + 1; - } else if (is_arp(skb->data)) { - if (process_ARP((arphdr_1490_t *)skb->data, card, dev)) { - printk (KERN_INFO "%s: Error processing ARP Packet.\n", card->devname); - } - dev_kfree_skb(skb); -*/ + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, offs, buf, tmp); + offs = card->u.f.rx_base; + len -= tmp; + } - } else if ( skb->data[0] != 0x03) { - printk(KERN_INFO "%s: Non IETF packet discarded.\n", card->devname); - dev_kfree_skb(skb); + buf = skb_put(skb, len); + sdla_peek(&card->hw, offs, buf, len); - } else { - len_incl_hdr = skb->len; - /* Decapsulate packet and pass it up the - protocol stack */ - skb->dev = dev; + /* We got the packet from the bard. + * Check the packet type and take appropriate action */ - /* remove hardware header */ - buf = skb_pull(skb, 1); + udp_type = udp_pkt_type( skb, card ); - if (!wanrouter_type_trans(skb, dev)) { - - /* can't decapsulate packet */ - dev_kfree_skb(skb); - chan->drvstats_rx_intr. - rx_intr_bfr_not_passed_to_stack ++; - ++ chan->ifstats.rx_errors; - ++ card->wandev.stats.rx_errors; - - } else { - netif_rx(skb); - chan->drvstats_rx_intr. - rx_intr_bfr_passed_to_stack ++; - ++ chan->ifstats.rx_packets; - ++ card->wandev.stats.rx_packets; - chan->ifstats.rx_bytes += len_incl_hdr; - card->wandev.stats.rx_bytes += - len_incl_hdr; + if(udp_type != UDP_INVALID_TYPE) { + + /* UDP Debug packet received, store the + * packet and handle it in timer interrupt */ + + skb_pull(skb, 1); + if (wanrouter_type_trans(skb, dev)){ + if(store_udp_mgmt_pkt(udp_type,UDP_PKT_FRM_NETWORK,card,skb,dlci)){ + + flags->imask |= FR_INTR_TIMER; + + if (udp_type == UDP_FPIPE_TYPE){ + ++chan->drvstats_rx_intr.rx_intr_PIPE_request; } - } - } - } + } + } + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + }else if (chan->common.usedby == API) { + + /* We are in API mode. + * Add an API header to the RAW packet + * and queue it into a circular buffer. + * Then kick the fr_bh() bottom half handler */ + + api_rx_hdr_t* api_rx_hdr; + chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack ++; + chan->ifstats.rx_packets ++; + card->wandev.stats.rx_packets ++; + + chan->ifstats.rx_bytes += skb->len; + card->wandev.stats.rx_bytes += skb->len; + + skb_push(skb, sizeof(api_rx_hdr_t)); + api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; + api_rx_hdr->attr = frbuf->attr; + api_rx_hdr->time_stamp = frbuf->tmstamp; + + skb->protocol = htons(ETH_P_IP); + skb->mac.raw = skb->data; + skb->dev = dev; + skb->pkt_type = WAN_PACKET_DATA; + + bh_enqueue(dev, skb); + + trigger_fr_bh(chan); + #endif + + }else if (handle_IPXWAN(skb->data,chan->name,chan->enable_IPX, chan->network_number)){ + + //FIXME: Frame Relay IPX is not supported, Yet ! + //if (chan->enable_IPX) { + // fr_send(card, dlci, 0, skb->len,skb->data); + //} + wan_dev_kfree_skb(skb, FREE_READ); + + } else if (is_arp(skb->data)) { + + /* ARP support enabled Mar 16 2000 + * Process incoming ARP reply/request, setup + * dynamic routes. */ + + if (process_ARP((arphdr_1490_t *)skb->data, card, dev)) { + if (net_ratelimit()){ + printk (KERN_INFO + "%s: Error processing ARP Packet.\n", + card->devname); + } + } + wan_dev_kfree_skb(skb, FREE_READ); + + } else if (skb->data[0] != 0x03) { + + if (net_ratelimit()) { + printk(KERN_INFO "%s: Non IETF packet discarded.\n", + card->devname); + } + wan_dev_kfree_skb(skb, FREE_READ); + + } else { + + len_incl_hdr = skb->len; + /* Decapsulate packet and pass it up the + protocol stack */ + skb->dev = dev; + + if (chan->common.usedby == BRIDGE || chan->common.usedby == BRIDGE_NODE){ + + /* Make sure it's an Ethernet frame, otherwise drop it */ + if (!memcmp(skb->data, "\x03\x00\x80\x00\x80\xC2\x00\x07", 8)) { + skb_pull(skb, 8); + skb->protocol=eth_type_trans(skb,dev); + }else{ + ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack; + ++chan->ifstats.rx_errors; + ++card->wandev.stats.rx_errors; + goto rx_done; + } + }else{ + + /* remove hardware header */ + buf = skb_pull(skb, 1); + + if (!wanrouter_type_trans(skb, dev)) { + + /* can't decapsulate packet */ + wan_dev_kfree_skb(skb, FREE_READ); + + ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack; + ++chan->ifstats.rx_errors; + ++card->wandev.stats.rx_errors; + goto rx_done; + } + skb->mac.raw = skb->data; + } + + + /* Send a packed up the IP stack */ + netif_rx(skb); + ++chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack; + ++chan->ifstats.rx_packets; + ++card->wandev.stats.rx_packets; + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + chan->ifstats.rx_bytes += len_incl_hdr; + card->wandev.stats.rx_bytes += len_incl_hdr; +#endif + } + +rx_done: /* Release buffer element and calculate a pointer to the next one */ frbuf->flag = 0; @@ -1869,14 +2378,36 @@ } -/*============================================================================ - * Transmit interrupt handler. +/*================================================================== + * tx_intr: Transmit interrupt handler. + * + * Rationale: + * If the board is busy transmitting, if_send() will + * buffers a single packet and turn on + * the tx interrupt. Tx interrupt will be called + * by the board, once the firmware can send more + * data. Thus, no polling is required. + * + * Description: + * Tx interrupt is called for each + * configured dlci channel. Thus: + * 1. Obtain the netowrk interface based on the + * dlci number. + * 2. Check that network interface is up and + * properly setup. + * 3. Check for a buffered packed. + * 4. Transmit the packed. + * 5. If we are in WANPIPE mode, mark the + * NET_BH handler. + * 6. If we are in API mode, kick + * the AF_WANPIPE socket for more data. + * */ static void tx_intr(sdla_t *card) { fr508_flags_t* flags = card->flags; fr_tx_buf_ctl_t* bctl; - struct net_device* dev = card->wandev.dev; + netdevice_t* dev; fr_channel_t* chan; if(card->hw.type == SDLA_S514){ @@ -1888,61 +2419,112 @@ /* Find the structure and make it unbusy */ dev = find_channel(card, flags->dlci); - chan = dev->priv; + if (dev == NULL){ + printk(KERN_INFO "NO DEV IN TX Interrupt\n"); + goto end_of_tx_intr; + } + + if ((chan = dev->priv) == NULL){ + printk(KERN_INFO "NO CHAN IN TX Interrupt\n"); + goto end_of_tx_intr; + } - if(!chan->transmit_length) { + if(!chan->transmit_length || !chan->delay_skb) { printk(KERN_INFO "%s: tx int error - transmit length zero\n", card->wandev.name); - return; + goto end_of_tx_intr; } /* If the 'if_send()' procedure is currently checking the 'tbusy' status, then we cannot transmit. Instead, we configure the microcode so as to re-issue this transmit interrupt at a later stage. */ - if (test_bit(2, (void*)&card->wandev.critical)) { + if (test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) { + fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface; bctl->flag = 0xA0; dlci_interface->gen_interrupt |= FR_INTR_TXRDY; - printk(KERN_INFO "%s: TX Interrupt Detected busy if_send\n",card->devname); + return; - } else { + }else{ bctl->dlci = flags->dlci; - bctl->length = chan->transmit_length; - sdla_poke(&card->hw, bctl->offset, chan->transmit_buffer, - chan->transmit_length); + bctl->length = chan->transmit_length+chan->fr_header_len; + sdla_poke(&card->hw, + fr_send_hdr(card,bctl->dlci,bctl->offset), + chan->delay_skb->data, + chan->delay_skb->len); bctl->flag = 0xC0; ++chan->ifstats.tx_packets; ++card->wandev.stats.tx_packets; +#if defined(LINUX_2_1) || defined(LINUX_2_4) chan->ifstats.tx_bytes += chan->transmit_length; card->wandev.stats.tx_bytes += chan->transmit_length; +#endif + + /* We must free an sk buffer, which we used + * for delayed transmission; Otherwise, the sock + * will run out of memory */ + wan_dev_kfree_skb(chan->delay_skb, FREE_WRITE); + + chan->delay_skb = NULL; chan->transmit_length = 0; - /* if any other interfaces have transmit interrupts pending, */ - /* do not disable the global transmit interrupt */ - if(!(-- card->u.f.tx_interrupts_pending)) - flags->imask &= ~FR_INTR_TXRDY; +#ifdef LINUX_2_4 + dev->trans_start = jiffies; +#endif - netif_wake_queue (dev); +#ifdef LINUX_2_0 + wake_net_dev(dev); +#else + if (is_queue_stopped(dev)){ + /* If using API, than wakeup socket BH handler */ + if (chan->common.usedby == API){ + start_net_queue(dev); + wakeup_sk_bh(dev); + }else{ + wake_net_dev(dev); + } + } +#endif } + +end_of_tx_intr: + + /* if any other interfaces have transmit interrupts pending, + * do not disable the global transmit interrupt */ + if(!(-- card->u.f.tx_interrupts_pending)) + flags->imask &= ~FR_INTR_TXRDY; + + } /*============================================================================ - * Timer interrupt handler. - FIXME: update comments as we modify the code - * The timer interrupt is used for three purposes: - * 1) Processing udp calls from 'fpipemon'. - * 2) Processing update calls from /proc file system - * 2) Reading board-level statistics for updating the proc file system. - * 3) Sending inverse ARP request packets. + * timer_intr: Timer interrupt handler. + * + * Rationale: + * All commans must be executed within the timer + * interrupt since no two commands should execute + * at the same time. + * + * Description: + * The timer interrupt is used to: + * 1. Processing udp calls from 'fpipemon'. + * 2. Processing update calls from /proc file system + * 3. Reading board-level statistics for + * updating the proc file system. + * 4. Sending inverse ARP request packets. + * 5. Configure a dlci/channel. + * 6. Unconfigure a dlci/channel. (Node only) */ + static void timer_intr(sdla_t *card) { fr508_flags_t* flags = card->flags; - if(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UDP) { + /* UDP Debuging: fpipemon call */ + if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UDP) { if(card->u.f.udp_type == UDP_FPIPE_TYPE) { if(process_udp_mgmt_pkt(card)) { card->u.f.timer_int_enabled &= @@ -1951,81 +2533,132 @@ } } - if(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE) { + /* /proc update call : triggered from update() */ + if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE) { fr_get_err_stats(card); fr_get_stats(card); card->u.f.update_comms_stats = 0; card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; } + /* Update the channel state call. This is call is + * triggered by if_send() function */ + if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE_STATE){ + netdevice_t *dev; + if (card->wandev.state == WAN_CONNECTED){ + for (dev=card->wandev.dev; dev; dev = *((netdevice_t **)dev->priv)){ + fr_channel_t *chan = dev->priv; + if (chan->common.state != WAN_CONNECTED){ + update_chan_state(dev); + } + } + } + card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE_STATE; + } + + /* configure a dlci/channel */ + if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_CONFIG){ + config_fr(card); + card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; + } -//FIXME: Fix the dynamic IP addressing -/* -goto L4; + /* unconfigure a dlci/channel */ + if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG){ + unconfig_fr(card); + card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG; + } - // Used to send inarp request at given interval - if (card->wandev.state == WAN_CONNECTED) { - int num_remaining = 0; - - dev = card->wandev.dev; - while (dev) { - fr_channel_t *chan = dev->priv; - - if (chan->inarp == INARP_REQUEST && - chan->state == WAN_CONNECTED) { - num_remaining++; - - if ((jiffies - chan->inarp_tick) > (chan->inarp_interval * HZ)) { - send_inarp_request(card,dev); - chan->inarp_tick = jiffies; - } + + /* Transmit ARP packets */ + if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_ARP){ + int i=0; + netdevice_t *dev; + + if (card->u.f.arp_dev == NULL) + card->u.f.arp_dev = card->wandev.dev; + + dev = card->u.f.arp_dev; + + for (;;){ + + fr_channel_t *chan = dev->priv; + + /* If the interface is brought down cancel sending In-ARPs */ + if (!(dev->flags&IFF_UP)){ + clear_bit(0,&chan->inarp_ready); + } + + if (test_bit(0,&chan->inarp_ready)){ + + if (check_tx_status(card,dev)){ + set_bit(ARP_CRIT,&card->wandev.critical); + break; + } + + if (!send_inarp_request(card,dev)){ + trigger_fr_arp(dev); + chan->inarp_tick = jiffies; + } + + clear_bit(0,&chan->inarp_ready); + dev = move_dev_to_next(card,dev); + break; + } + dev = move_dev_to_next(card,dev); + + if (++i == card->wandev.new_if_cnt){ + card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_ARP; + break; } - dev = chan->slave; - } - if (!num_remaining) { // no more to process - flags->imask &= ~FR_INTR_TIMER; } + card->u.f.arp_dev = dev; } -L4: - ; -*/ + if(!card->u.f.timer_int_enabled) flags->imask &= ~FR_INTR_TIMER; } /*============================================================================ - * Spurious interrupt handler. - * o print a warning - * o + * spur_intr: Spurious interrupt handler. + * + * Description: + * We don't know this interrupt. + * Print a warning. */ + static void spur_intr (sdla_t* card) { - printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); + if (net_ratelimit()){ + printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); + } } + //FIXME: Fix the IPX in next version /*=========================================================================== * Return 0 for non-IPXWAN packet * 1 for IPXWAN packet or IPX is not enabled! * FIXME: Use a IPX structure here not offsets */ -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number) +static int handle_IPXWAN(unsigned char *sendpacket, + char *devname, unsigned char enable_IPX, + unsigned long network_number) { int i; - if( sendpacket[1] == 0x00 && - sendpacket[2] == 0x80 && - sendpacket[6] == 0x81 && - sendpacket[7] == 0x37) { + if( sendpacket[1] == 0x00 && sendpacket[2] == 0x80 && + sendpacket[6] == 0x81 && sendpacket[7] == 0x37) { /* It's an IPX packet */ - if(!enable_IPX) { + if (!enable_IPX){ /* Return 1 so we don't pass it up the stack. */ //FIXME: Take this out when IPX is fixed - printk (KERN_INFO + if (net_ratelimit()){ + printk (KERN_INFO "%s: WARNING: Unsupported IPX packet received and dropped\n", devname); + } return 1; } } else { @@ -2033,39 +2666,33 @@ return 0; } - if( sendpacket[24] == 0x90 && - sendpacket[25] == 0x04) - { + if( sendpacket[24] == 0x90 && sendpacket[25] == 0x04){ /* It's IPXWAN */ - if( sendpacket[10] == 0x02 && - sendpacket[42] == 0x00) - { + if( sendpacket[10] == 0x02 && sendpacket[42] == 0x00){ + /* It's a timer request packet */ - printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); + printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", + devname); /* Go through the routing options and answer no to every * option except Unnumbered RIP/SAP */ - for(i = 49; sendpacket[i] == 0x00; i += 5) - { + for(i = 49; sendpacket[i] == 0x00; i += 5){ /* 0x02 is the option for Unnumbered RIP/SAP */ - if( sendpacket[i + 4] != 0x02) - { + if( sendpacket[i + 4] != 0x02){ sendpacket[i + 1] = 0; } } /* Skip over the extended Node ID option */ - if( sendpacket[i] == 0x04 ) - { + if( sendpacket[i] == 0x04 ){ i += 8; } /* We also want to turn off all header compression opt. */ - for(; sendpacket[i] == 0x80 ;) - { + for(; sendpacket[i] == 0x80 ;){ sendpacket[i + 1] = 0; i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; } @@ -2073,12 +2700,15 @@ /* Set the packet type to timer response */ sendpacket[42] = 0x01; - printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); - } - else if( sendpacket[42] == 0x02 ) - { + printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", + devname); + + } else if( sendpacket[42] == 0x02 ){ + /* This is an information request packet */ - printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); + printk(KERN_INFO + "%s: Received IPXWAN Information Request packet\n", + devname); /* Set the packet type to information response */ sendpacket[42] = 0x03; @@ -2103,10 +2733,10 @@ sendpacket[i] = 0; } - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); - } - else - { + printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", + devname); + } else { + printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); return 0; } @@ -2128,101 +2758,181 @@ return 0; } /*============================================================================ - * Process Route. - * This routine is called as a polling routine to dynamically add/delete routes - * negotiated by inverse ARP. It is in this "task" because we don't want routes - * to be added while in interrupt context. -*/ + * process_route + * + * Rationale: + * If the interface goes down, or we receive an ARP request, + * we have to change the network interface ip addresses. + * This cannot be done within the interrupt. + * + * Description: + * + * This routine is called as a polling routine to dynamically + * add/delete routes negotiated by inverse ARP. It is in this + * "task" because we don't want routes to be added while in + * interrupt context. + * + * Usage: + * This function is called by fr_poll() polling funtion. + */ -static void process_route (sdla_t* card) +static void process_route (netdevice_t *dev) { - struct net_device* dev; - struct in_device *in_dev; - struct rtentry route; - int err = 0; - mm_segment_t fs; + fr_channel_t *chan = dev->priv; + sdla_t *card = chan->card; +#if defined(LINUX_2_1) || defined(LINUX_2_4) - /* Dynamic Route adding/removing */ - dev = card->wandev.dev; - while (dev) { - fr_channel_t *chan = dev->priv; - - if (chan->route_flag == ADD_ROUTE || - chan->route_flag == REMOVE_ROUTE ) { - fs = get_fs(); - - in_dev = dev->ip_ptr; - - if( in_dev != NULL && in_dev->ifa_list != NULL) { - memset(&route, 0, sizeof(route)); - route.rt_dev = dev->name; - route.rt_flags = 0; - - ((struct sockaddr_in *) &(route.rt_dst)) -> - sin_addr.s_addr=in_dev->ifa_list->ifa_address; - ((struct sockaddr_in *) &(route.rt_dst)) -> - sin_family = AF_INET; - ((struct sockaddr_in *) &(route.rt_genmask)) -> - sin_addr.s_addr = 0xFFFFFFFF; - ((struct sockaddr_in *) &(route.rt_genmask)) -> - sin_family = AF_INET; - - switch(chan->route_flag) { - - case ADD_ROUTE: - set_fs(get_ds()); /* get user space block */ - err = ip_rt_ioctl( SIOCADDRT, &route); - set_fs(fs); /* restore old block */ - - if (err) { - printk(KERN_INFO "%s: Adding of route failed. Error: %d\n", card->devname,err); - printk(KERN_INFO "%s: Address: %s\n", - chan->name, - in_ntoa(in_dev->ifa_list->ifa_address) ); - } else { - chan->route_flag = ROUTE_ADDED; - } - break; + struct ifreq if_info; + struct sockaddr_in *if_data; + mm_segment_t fs = get_fs(); + u32 ip_tmp; + int err; - case REMOVE_ROUTE: - set_fs(get_ds()); /* get user space block */ - err = ip_rt_ioctl( SIOCDELRT, &route); - set_fs(fs); /* restore old block */ - - if (err) { - printk(KERN_INFO "%s: Deleting of route failed. Error: %d\n", card->devname,err); - printk(KERN_INFO "%s: Address: %s\n", - dev->name,in_ntoa(in_dev->ifa_list->ifa_address) ); - } else { - printk(KERN_INFO "%s: Removed route.\n", - chan->name); - chan->route_flag = NO_ROUTE; - } - break; - } /* Case Statement */ - } - } /* If ADD/DELETE ROUTE */ - dev = chan->slave; - } /* Device 'While' Loop */ + switch(chan->route_flag){ - card->poll = NULL; -} + case ADD_ROUTE: + + /* Set remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + set_fs(get_ds()); /* get user space block */ + + if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data->sin_addr.s_addr = chan->ip_remote; + if_data->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + set_fs(fs); /* restore old block */ -/****** Frame Relay Firmware-Specific Functions *****************************/ + if (err) { -/*============================================================================ - * Read firmware code version. - * o fill string str with firmware version info. - */ -static int fr_read_version (sdla_t* card, char* str) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; + printk(KERN_INFO + "%s: Route Add failed. Error: %d\n", + card->devname,err); + printk(KERN_INFO "%s: Address: %s\n", + chan->name, in_ntoa(chan->ip_remote)); + + }else { + printk(KERN_INFO "%s: Route Added Successfully: %s\n", + card->devname,in_ntoa(chan->ip_remote)); + chan->route_flag = ROUTE_ADDED; + } + break; + + case REMOVE_ROUTE: + + /* Set remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + ip_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); + + set_fs(get_ds()); /* get user space block */ + + if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data->sin_addr.s_addr = 0; + if_data->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); + + if (err) { + + printk(KERN_INFO + "%s: Deleting of route failed. Error: %d\n", + card->devname,err); + printk(KERN_INFO "%s: Address: %s\n", + dev->name,in_ntoa(chan->ip_remote) ); + + } else { + + printk(KERN_INFO "%s: Route Removed Sucessfuly: %s\n", + card->devname,in_ntoa(ip_tmp)); + chan->route_flag = NO_ROUTE; + } + break; + + } /* Case Statement */ + +#else + /* Dynamic Route adding/removing */ + struct rtentry route; + int err = 0; + unsigned long fs = get_fs(); + + memset(&route, 0, sizeof(route)); + route.rt_dev = dev->name; + route.rt_flags = 0; + + ((struct sockaddr_in *) &(route.rt_dst)) -> + sin_addr.s_addr=dev->pa_dstaddr; + ((struct sockaddr_in *) &(route.rt_dst)) -> + sin_family = AF_INET; + ((struct sockaddr_in *) &(route.rt_genmask)) -> + sin_addr.s_addr = 0xFFFFFFFF; + ((struct sockaddr_in *) &(route.rt_genmask)) -> + sin_family = AF_INET; + switch(chan->route_flag) { + + case ADD_ROUTE: + + set_fs(get_ds()); /* get user space block */ + err = ip_rt_new(&route); + set_fs(fs); /* restore old block */ + + if (err) { + printk(KERN_INFO "%s: Adding of route failed. Error: %d\n", + card->devname,err); + printk(KERN_INFO "%s: Address: %s\n", + chan->name, in_ntoa(dev->pa_dstaddr) ); + } + else { + chan->route_flag = ROUTE_ADDED; + } + break; + + case REMOVE_ROUTE: + + set_fs(get_ds()); /* get user space block */ + err = ip_rt_kill(&route); + set_fs(fs); /* restore old block */ + + if (err) { + + printk(KERN_INFO "%s: Deleting of route failed. Error: %d\n", + card->devname,err); + printk(KERN_INFO "%s: Address: %s\n", + dev->name,in_ntoa(dev->pa_dstaddr) ); + } else { + + printk(KERN_INFO "%s: Removed route.\n", + ((fr_channel_t*)dev->priv)->name); + chan->route_flag = NO_ROUTE; + + } + break; + } + +#endif + +} + + + +/****** Frame Relay Firmware-Specific Functions *****************************/ + +/*============================================================================ + * Read firmware code version. + * o fill string str with firmware version info. + */ +static int fr_read_version (sdla_t* card, char* str) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; do { @@ -2264,6 +2974,12 @@ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && fr_event(card, err, mbox)); + + /*NC Oct 12 2000 */ + if (err != CMD_OK){ + printk(KERN_ERR "%s: Frame Relay Configuration Failed: rc=0x%x\n", + card->devname,err); + } return err; } @@ -2338,33 +3054,39 @@ } /*============================================================================ - * Disable communications. + * fr_comm_disable + * + * Warning: This functin is called by the shutdown() procedure. It is void + * since dev->priv are has already been deallocated and no + * error checking is possible using fr_event() function. */ -static int fr_comm_disable (sdla_t* card) +static void fr_comm_disable (sdla_t* card) { fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - do - { - mbox->cmd.command = FR_COMM_DISABLE; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - retry = MAX_CMD_RETRY; - do { mbox->cmd.command = FR_SET_MODEM_STATUS; mbox->cmd.length = 1; mbox->data[0] = 0; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); + } while (err && retry--); - return err; + retry = MAX_CMD_RETRY; + + do + { + mbox->cmd.command = FR_COMM_DISABLE; + mbox->cmd.length = 0; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry--); + + return; } + + /*============================================================================ * Get communications error statistics. */ @@ -2518,9 +3240,58 @@ return err; } + +static unsigned int fr_send_hdr (sdla_t*card, int dlci, unsigned int offset) +{ + netdevice_t *dev = find_channel(card,dlci); + fr_channel_t *chan; + + if (!dev || !(chan=dev->priv)) + return offset; + + if (chan->fr_header_len){ + sdla_poke(&card->hw, offset, chan->fr_header, chan->fr_header_len); + } + + return offset+chan->fr_header_len; +} + /*============================================================================ * Send a frame on a selected DLCI. */ +static int fr_send_data_header (sdla_t* card, int dlci, unsigned char attr, int len, + void *buf, unsigned char hdr_len) +{ + fr_mbox_t* mbox = card->mbox + 0x800; + int retry = MAX_CMD_RETRY; + int err; + + do + { + mbox->cmd.dlci = dlci; + mbox->cmd.attr = attr; + mbox->cmd.length = len+hdr_len; + mbox->cmd.command = FR_WRITE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) { + fr_tx_buf_ctl_t* frbuf; + + if(card->hw.type == SDLA_S514) + frbuf = (void*)(*(unsigned long*)mbox->data + + card->hw.dpmbase); + else + frbuf = (void*)(*(unsigned long*)mbox->data - + FR_MB_VECTOR + card->hw.dpmbase); + + sdla_poke(&card->hw, fr_send_hdr(card,dlci,frbuf->offset), buf, len); + frbuf->flag = 0x01; + } + + return err; +} + static int fr_send (sdla_t* card, int dlci, unsigned char attr, int len, void *buf) { @@ -2538,7 +3309,6 @@ } while (err && retry-- && fr_event(card, err, mbox)); if (!err) { - fr_tx_buf_ctl_t* frbuf; if(card->hw.type == SDLA_S514) @@ -2555,6 +3325,7 @@ return err; } + /****** Firmware Asynchronous Event Handlers ********************************/ /*============================================================================ @@ -2577,46 +3348,41 @@ case FRRES_CHANNEL_DOWN: { - struct net_device *dev; + netdevice_t *dev; /* Remove all routes from associated DLCI's */ - dev = card->wandev.dev; - while (dev) { + for (dev = card->wandev.dev; dev; dev = *((netdevice_t **)dev->priv)) { fr_channel_t *chan = dev->priv; if (chan->route_flag == ROUTE_ADDED) { chan->route_flag = REMOVE_ROUTE; - card->poll = &process_route; } if (chan->inarp == INARP_CONFIGURED) { chan->inarp = INARP_REQUEST; } - dev = chan->slave; + /* If the link becomes disconnected then, + * all channels will be disconnected + * as well. + */ + set_chan_state(dev,WAN_DISCONNECTED); } - + wanpipe_set_state(card, WAN_DISCONNECTED); return 1; } case FRRES_CHANNEL_UP: { - struct net_device *dev; - int num_requests = 0; + netdevice_t *dev; - /* Remove all routes from associated DLCI's */ - dev = card->wandev.dev; - while (dev) { - fr_channel_t *chan = dev->priv; - if( chan->inarp == INARP_REQUEST ){ - num_requests++; - chan->inarp_tick = jiffies; - } - dev = chan->slave; + /* FIXME: Only startup devices that are on the list */ + + for (dev = card->wandev.dev; dev; dev = *((netdevice_t **)dev->priv)) { + + set_chan_state(dev,WAN_CONNECTED); } - /* Allow timer interrupts */ - if (num_requests) flags->imask |= 0x20; wanpipe_set_state(card, WAN_CONNECTED); return 1; } @@ -2644,8 +3410,10 @@ case FRRES_CIR_OVERFLOW: break; + case FRRES_BUFFER_OVERFLOW: break; + default: printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" , card->devname, mbox->cmd.command, event); @@ -2684,13 +3452,13 @@ dlci_status_t* status = (void*)mbox->data; int cnt = mbox->cmd.length / sizeof(dlci_status_t); fr_channel_t *chan; - struct net_device* dev2; + netdevice_t* dev2; for (; cnt; --cnt, ++status) { unsigned short dlci= status->dlci; - struct net_device* dev = find_channel(card, dlci); + netdevice_t* dev = find_channel(card, dlci); if (dev == NULL){ printk(KERN_INFO @@ -2707,7 +3475,7 @@ "%s: DLCI %u is inactive!\n", card->devname, dlci); - if (dev && netif_running(dev)) + if (dev && is_dev_running(dev)) set_chan_state(dev, WAN_DISCONNECTED); } @@ -2717,12 +3485,14 @@ "%s: DLCI %u has been deleted!\n", card->devname, dlci); - if (dev && netif_running(dev)) { + if (dev && is_dev_running(dev)){ + fr_channel_t *chan = dev->priv; if (chan->route_flag == ROUTE_ADDED) { chan->route_flag = REMOVE_ROUTE; - card->poll = &process_route; + /* The state change will trigger + * the fr polling routine */ } if (chan->inarp == INARP_CONFIGURED) { @@ -2740,16 +3510,15 @@ DLCI(s) when they become active. */ chan->dlci_configured = DLCI_CONFIG_PENDING; - - if (dev && netif_running(dev)) - set_chan_state(dev, WAN_CONNECTED); + + set_chan_state(dev, WAN_CONNECTED); } } } - dev2 = card->wandev.dev; - while (dev2) { + for (dev2 =card->wandev.dev; dev2; dev2 = *((netdevice_t **)dev2->priv)){ + chan = dev2->priv; if (chan->dlci_configured == DLCI_CONFIG_PENDING) { @@ -2758,7 +3527,6 @@ } } - dev2 = chan->slave; } return 1; } @@ -2767,8 +3535,7 @@ static int fr_init_dlci (sdla_t *card, fr_channel_t *chan) { fr_dlc_conf_t cfg; - fr508_flags_t* flags = card->flags; - + memset(&cfg, 0, sizeof(cfg)); if ( chan->cir_status == CIR_DISABLED) { @@ -2786,22 +3553,16 @@ } if (fr_dlci_configure( card, &cfg , chan->dlci)){ - printk(KERN_INFO - "%s: DLCI Configure failed for %d\n", - card->devname, chan->dlci); + printk(KERN_INFO + "%s: DLCI Configure failed for %d\n", + card->devname, chan->dlci); return 1; } chan->dlci_configured = DLCI_CONFIGURED; - /* Allow timer interrupts */ - if( chan->inarp == INARP_REQUEST && card->wandev.state == WAN_CONNECTED) { - chan->inarp_tick = jiffies; - flags->imask |= 0x20; - } - /* Read the interface byte mapping into the channel - structure. + * structure. */ read_DLCI_IB_mapping( card, chan ); @@ -2812,7 +3573,7 @@ /*============================================================================ * Update channel state. */ -static int update_chan_state (struct net_device* dev) +static int update_chan_state (netdevice_t* dev) { fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; @@ -2828,14 +3589,25 @@ } while (err && retry-- && fr_event(card, err, mbox)); if (!err) { - + unsigned short* list = (void*)mbox->data; int cnt = mbox->cmd.length / sizeof(short); - + + err=1; + for (; cnt; --cnt, ++list) { if (*list == chan->dlci) { set_chan_state(dev, WAN_CONNECTED); + + + /* May 23 2000. NC + * When a dlci is added or restarted, + * the dlci_int_interface pointer must + * be reinitialized. */ + if (!chan->dlci_int_interface){ + err=fr_init_dlci (card,chan); + } break; } } @@ -2847,16 +3619,12 @@ /*============================================================================ * Set channel state. */ -static void set_chan_state (struct net_device* dev, int state) +static void set_chan_state (netdevice_t* dev, int state) { fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; - unsigned long flags; - save_flags(flags); - cli(); - - if (chan->state != state) { + if (chan->common.state != state) { switch (state) { @@ -2864,6 +3632,12 @@ printk(KERN_INFO "%s: Interface %s: DLCI %d connected\n", card->devname, dev->name, chan->dlci); + + /* If the interface was previoulsy down, + * bring it up, since the channel is active */ + + trigger_fr_poll (dev); + trigger_fr_arp (dev); break; case WAN_CONNECTING: @@ -2876,20 +3650,29 @@ printk (KERN_INFO "%s: Interface %s: DLCI %d disconnected!\n", card->devname, dev->name, chan->dlci); + + /* If the interface is up, bring it down, + * since the channel is now disconnected */ + trigger_fr_poll (dev); break; } - chan->state = state; + chan->common.state = state; } chan->state_tick = jiffies; - restore_flags(flags); } /*============================================================================ * Find network device by its channel number. + * + * We need this critical flag because we change + * the dlci_to_dev_map outside the interrupt. + * + * NOTE: del_if() functions updates this array, it uses + * the spin locks to avoid corruption. */ -static struct net_device* find_channel (sdla_t* card, unsigned dlci) +static netdevice_t* find_channel (sdla_t* card, unsigned dlci) { if(dlci > HIGHEST_VALID_DLCI) return NULL; @@ -2945,9 +3728,15 @@ struct sk_buff *skb, int dlci) { int udp_pkt_stored = 0; - - if(!card->u.f.udp_pkt_lgth &&(skb->len <= MAX_LGTH_UDP_MGNT_PKT)){ - card->u.f.udp_pkt_lgth = skb->len; + + netdevice_t *dev=find_channel(card,dlci); + fr_channel_t *chan; + + if (!dev || !(chan=dev->priv)) + return 1; + + if(!card->u.f.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){ + card->u.f.udp_pkt_lgth = skb->len + chan->fr_header_len; card->u.f.udp_type = udp_type; card->u.f.udp_pkt_src = udp_pkt_src; card->u.f.udp_dlci = dlci; @@ -2960,8 +3749,12 @@ dlci); } - dev_kfree_skb(skb); - + if(udp_pkt_src == UDP_PKT_FRM_STACK){ + wan_dev_kfree_skb(skb, FREE_WRITE); + }else{ + wan_dev_kfree_skb(skb, FREE_READ); + } + return(udp_pkt_stored); } @@ -2982,7 +3775,7 @@ int err; struct timeval tv; int udp_mgmt_req_valid = 1; - struct net_device* dev; + netdevice_t* dev; fr_channel_t* chan; fr_udp_pkt_t *fr_udp_pkt; unsigned short num_trc_els; @@ -2995,7 +3788,14 @@ /* Find network interface for this packet */ dev = find_channel(card, dlci); - chan = dev->priv; + if (!dev){ + card->u.f.udp_pkt_lgth = 0; + return 1; + } + if ((chan = dev->priv) == NULL){ + card->u.f.udp_pkt_lgth = 0; + return 1; + } /* If the UDP packet is from the network, we are going to have to transmit a response. Before doing so, we must check to see that @@ -3003,39 +3803,49 @@ that we are not already in a 'delayed transmit' state. */ if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { - if (test_bit(0, (void*)&card->wandev.critical) || - test_bit(2, (void*)&card->wandev.critical)) { - return 0; - } - if((netif_queue_stopped(dev)) || (card->u.f.tx_interrupts_pending)) { - return 0; + if (check_tx_status(card,dev)){ + card->u.f.udp_pkt_lgth = 0; + return 1; } } fr_udp_pkt = (fr_udp_pkt_t *)card->u.f.udp_pkt_data; - switch(fr_udp_pkt->cblock.command) { + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + switch(fr_udp_pkt->cblock.command) { - case FPIPE_ENABLE_TRACING: - case FPIPE_DISABLE_TRACING: - case FPIPE_GET_TRACE_INFO: - case FR_SET_FT1_MODE: - if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { - chan->drvstats_gen. - UDP_PIPE_mgmt_direction_err ++; + case FR_READ_MODEM_STATUS: + case FR_READ_STATUS: + case FPIPE_ROUTER_UP_TIME: + case FR_READ_ERROR_STATS: + case FPIPE_DRIVER_STAT_GEN: + case FR_READ_STATISTICS: + case FR_READ_ADD_DLC_STATS: + case FR_READ_CONFIG: + case FR_READ_CODE_VERSION: + udp_mgmt_req_valid = 1; + break; + default: udp_mgmt_req_valid = 0; break; - } - - default: - break; - } + } + } if(!udp_mgmt_req_valid) { /* set length to 0 */ fr_udp_pkt->cblock.length = 0; /* set return code */ fr_udp_pkt->cblock.result = 0xCD; + + chan->drvstats_gen.UDP_PIPE_mgmt_direction_err ++; + + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,fr_udp_pkt->cblock.command); + } + } else { switch(fr_udp_pkt->cblock.command) { @@ -3074,7 +3884,7 @@ /* Calculate the maximum trace data area in */ /* the UDP packet */ card->u.f.trc_bfr_space=(MAX_LGTH_UDP_MGNT_PKT - - sizeof(fr_encap_hdr_t) - + //sizeof(fr_encap_hdr_t) - sizeof(ip_pkt_t) - sizeof(udp_pkt_t) - sizeof(wp_mgmt_t) - @@ -3204,7 +4014,7 @@ case FPIPE_FT1_READ_STATUS: sdla_peek(&card->hw, 0xF020, &fr_udp_pkt->data[0x00] , 2); - fr_udp_pkt->cblock.length = 2; + fr_udp_pkt->cblock.length = mbox->cmd.length = 2; fr_udp_pkt->cblock.result = 0; break; @@ -3220,44 +4030,32 @@ chan->router_start_time; *(unsigned long *)&fr_udp_pkt->data = chan->router_up_time; - mbox->cmd.length = 4; + mbox->cmd.length = fr_udp_pkt->cblock.length = 4; + fr_udp_pkt->cblock.result = 0; break; - - case FR_FT1_STATUS_CTRL: - if(fr_udp_pkt->data[0] == 1) { - if(rCount++ != 0 ){ - fr_udp_pkt->cblock.result = 0; - mbox->cmd.length = 1; - break; - } - } - - /* Disable FT1 MONITOR STATUS */ - if(fr_udp_pkt->data[0] == 0) { - if( --rCount != 0) { - fr_udp_pkt->cblock.result = 0; - mbox->cmd.length = 1; - break; - } - } - case FPIPE_DRIVER_STAT_IFSEND: memcpy(fr_udp_pkt->data, &chan->drvstats_if_send.if_send_entry, sizeof(if_send_stat_t)); - mbox->cmd.length = sizeof(if_send_stat_t); + mbox->cmd.length = fr_udp_pkt->cblock.length =sizeof(if_send_stat_t); + fr_udp_pkt->cblock.result = 0; break; case FPIPE_DRIVER_STAT_INTR: + memcpy(fr_udp_pkt->data, &card->statistics.isr_entry, sizeof(global_stats_t)); + memcpy(&fr_udp_pkt->data[sizeof(global_stats_t)], &chan->drvstats_rx_intr.rx_intr_no_socket, sizeof(rx_intr_stat_t)); - mbox->cmd.length = sizeof(global_stats_t) + + + mbox->cmd.length = fr_udp_pkt->cblock.length = + sizeof(global_stats_t) + sizeof(rx_intr_stat_t); + fr_udp_pkt->cblock.result = 0; break; case FPIPE_DRIVER_STAT_GEN: @@ -3268,13 +4066,34 @@ memcpy(&fr_udp_pkt->data[sizeof(pipe_mgmt_stat_t)], &card->statistics, sizeof(global_stats_t)); - fr_udp_pkt->cblock.result = 0; - fr_udp_pkt->cblock.length = sizeof(global_stats_t)+ + mbox->cmd.length = fr_udp_pkt->cblock.length = sizeof(global_stats_t)+ sizeof(rx_intr_stat_t); - mbox->cmd.length = fr_udp_pkt->cblock.length; + fr_udp_pkt->cblock.result = 0; break; - + + + case FR_FT1_STATUS_CTRL: + if(fr_udp_pkt->data[0] == 1) { + if(rCount++ != 0 ){ + fr_udp_pkt->cblock.result = 0; + mbox->cmd.length = 1; + break; + } + } + + /* Disable FT1 MONITOR STATUS */ + if(fr_udp_pkt->data[0] == 0) { + if( --rCount != 0) { + fr_udp_pkt->cblock.result = 0; + mbox->cmd.length = 1; + break; + } + } + goto udp_mgmt_dflt; + + default: +udp_mgmt_dflt: do { memcpy(&mbox->cmd, &fr_udp_pkt->cblock.command, @@ -3312,12 +4131,19 @@ len = reply_udp(card->u.f.udp_pkt_data, mbox->cmd.length); if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - err = fr_send(card, dlci, 0, len, card->u.f.udp_pkt_data); - if (err) + + chan->fr_header_len=2; + chan->fr_header[0]=Q922_UI; + chan->fr_header[1]=NLPID_IP; + + err = fr_send_data_header(card, dlci, 0, len, + card->u.f.udp_pkt_data,chan->fr_header_len); + if (err){ chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_passed ++; - else + }else{ chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_failed ++; + } + } else { /* Allocate socket buffer */ if((new_skb = dev_alloc_skb(len)) != NULL) { @@ -3326,22 +4152,12 @@ buf = skb_put(new_skb, len); memcpy(buf, card->u.f.udp_pkt_data, len); - /* Decapsulate packet and pass it up the protocol - stack */ + chan->drvstats_gen. + UDP_PIPE_mgmt_passed_to_stack ++; new_skb->dev = dev; - buf = skb_pull(new_skb, 1); /* remove hardware header*/ - - if(!wanrouter_type_trans(new_skb, dev)) { - - chan->drvstats_gen. - UDP_PIPE_mgmt_not_passed_to_stack ++; - /* can't decapsulate packet */ - dev_kfree_skb(new_skb); - } else { - chan->drvstats_gen. - UDP_PIPE_mgmt_passed_to_stack ++; - netif_rx(new_skb); - } + new_skb->protocol = htons(ETH_P_IP); + new_skb->mac.raw = new_skb->data; + netif_rx(new_skb); } else { chan->drvstats_gen.UDP_PIPE_mgmt_no_socket ++; @@ -3360,15 +4176,19 @@ * Send Inverse ARP Request */ -int send_inarp_request(sdla_t *card, struct net_device *dev) +int send_inarp_request(sdla_t *card, netdevice_t *dev) { + int err=0; + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + arphdr_1490_t *ArpPacket; arphdr_fr_t *arphdr; fr_channel_t *chan = dev->priv; struct in_device *in_dev; in_dev = dev->ip_ptr; - + if(in_dev != NULL ) { ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC); @@ -3396,18 +4216,68 @@ arphdr->ar_tha = 0; /* dst HW DLCI - Doesn't matter */ arphdr->ar_tip = 0; /* Remote Address -- what we want */ - printk(KERN_INFO "%s: Sending InARP request on DLCI %d.\n", card->devname, chan->dlci); - fr_send(card, chan->dlci, 0, - sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), - (void *)ArpPacket); + err = fr_send(card, chan->dlci, 0, sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), + (void *)ArpPacket); + + if (!err){ + printk(KERN_INFO "\n%s: Sending InARP request on DLCI %d.\n", + card->devname, chan->dlci); + clear_bit(ARP_CRIT,&card->wandev.critical); + } + kfree(ArpPacket); + }else{ + printk(KERN_INFO "%s: INARP ERROR: %s doesn't have a local IP address!\n", + card->devname,dev->name); + return 1; } - return 1; -} - +#else + arphdr_1490_t *ArpPacket; + arphdr_fr_t *arphdr; + fr_channel_t *chan = dev->priv; + + ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC); + /* SNAP Header indicating ARP */ + ArpPacket->control = 0x03; + ArpPacket->pad = 0x00; + ArpPacket->NLPID = 0x80; + ArpPacket->OUI[0] = 0; + ArpPacket->OUI[1] = 0; + ArpPacket->OUI[2] = 0; + ArpPacket->PID = 0x0608; + + arphdr = (arphdr_fr_t *)(ArpPacket + 1); // Go to ARP Packet + /* InARP request */ + arphdr->ar_hrd = 0x0F00; /* Frame Relay HW type */ + arphdr->ar_pro = 0x0008; /* IP Protocol */ + arphdr->ar_hln = 2; /* HW addr length */ + arphdr->ar_pln = 4; /* IP addr length */ + arphdr->ar_op = htons(0x08); /* InARP Request */ + arphdr->ar_sha = 0; /* src HW DLCI - Doesn't matter */ + arphdr->ar_sip = dev->pa_addr; /* Local Address */ + arphdr->ar_tha = 0; /* dst HW DLCI - Doesn't matter */ + arphdr->ar_tip = 0; /* Remote Address -- what we want */ + + printk(KERN_INFO "%s: Sending InARP request on DLCI %d.\n", card->devname, chan->dlci); + err = fr_send(card, chan->dlci, 0, + sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), + (void *)ArpPacket); + + if (!err){ + printk(KERN_INFO "\n%s: Sending InARP request on DLCI %d.\n", + card->devname, chan->dlci); + clear_bit(ARP_CRIT,&card->wandev.critical); + } -/*============================================================================== + kfree(ArpPacket); +#endif + + return 0; +} + + +/*============================================================================== * Check packet for ARP Type */ @@ -3426,123 +4296,289 @@ * Process ARP Packet Type */ -int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device* dev) +int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, netdevice_t* dev) { + +#if defined(LINUX_2_1) || defined(LINUX_2_4) arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */ fr_rx_buf_ctl_t* frbuf = card->rxmb; struct in_device *in_dev; + fr_channel_t *chan = dev->priv; +#else + arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */ + fr_rx_buf_ctl_t* frbuf = card->rxmb; +#endif + + /* Before we transmit ARP packet, we must check + * to see that we are not currently transmitting a + * frame (in 'if_send()') and that we are not + * already in a 'delayed transmit' state. */ + if (check_tx_status(card,dev)){ + if (net_ratelimit()){ + printk(KERN_INFO "%s: Disabling comminication to process ARP\n", + card->devname); + } + set_bit(ARP_CRIT,&card->wandev.critical); + return 0; + } +#if defined(LINUX_2_1) || defined(LINUX_2_4) in_dev = dev->ip_ptr; - if( in_dev != NULL && in_dev->ifa_list != NULL) { - switch (ntohs(arphdr->ar_op)) { - case 0x08: // Inverse ARP request -- Send Reply, add route. + /* Check that IP addresses exist for our network address */ + if (in_dev == NULL || in_dev->ifa_list == NULL) + return -1; + + switch (ntohs(arphdr->ar_op)) { + + case 0x08: // Inverse ARP request -- Send Reply, add route. - /* Check for valid Address */ - printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Req\n", ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip)); + /* Check for valid Address */ + printk(KERN_INFO "%s: Recvd PtP addr -InArp Req: %s\n", + card->devname, in_ntoa(arphdr->ar_sip)); - if ((in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { - printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", card->devname); - printk(KERN_INFO "mask %X\n", in_dev->ifa_list->ifa_mask); - printk(KERN_INFO "local %X\n", in_dev->ifa_list->ifa_local); - return -1; - } - - if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { - printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", card->devname); - return -1; - } + + /* Check that the network address is the same as ours, only + * if the netowrk mask is not 255.255.255.255. Otherwise + * this check would not make sense */ + + if (in_dev->ifa_list->ifa_mask != 0xFFFFFFFF && + (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != + (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)){ + + printk(KERN_INFO + "%s: Invalid PtP address. %s InARP ignored.\n", + card->devname,in_ntoa(arphdr->ar_sip)); + + printk(KERN_INFO "%s: mask %s\n", + card->devname, in_ntoa(in_dev->ifa_list->ifa_mask)); + printk(KERN_INFO "%s: local %s\n", + card->devname,in_ntoa(in_dev->ifa_list->ifa_local)); + return -1; + } + + if (in_dev->ifa_list->ifa_local == arphdr->ar_sip){ + printk(KERN_INFO + "%s: Local addr = PtP addr. InARP ignored.\n", + card->devname); + return -1; + } - arphdr->ar_op = htons(0x09); /* InARP Reply */ + arphdr->ar_op = htons(0x09); /* InARP Reply */ - /* Set addresses */ - arphdr->ar_tip = arphdr->ar_sip; - arphdr->ar_sip = in_dev->ifa_list->ifa_local; + /* Set addresses */ + arphdr->ar_tip = arphdr->ar_sip; + arphdr->ar_sip = in_dev->ifa_list->ifa_local; - fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket); + chan->ip_local = in_dev->ifa_list->ifa_local; + chan->ip_remote = arphdr->ar_sip; - /* Modify Point-to-Point Address */ - { - struct ifreq if_info; - struct sockaddr_in *if_data; - mm_segment_t fs = get_fs(); - int err; - - /* Set remote addresses */ - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); - - set_fs(get_ds()); /* get user space block */ - - if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data->sin_addr.s_addr = arphdr->ar_tip; - if_data->sin_family = AF_INET; - err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket); - set_fs(fs); /* restore old block */ + if (test_bit(ARP_CRIT,&card->wandev.critical)){ + if (net_ratelimit()){ + printk(KERN_INFO "%s: ARP Processed Enabling Communication!\n", + card->devname); } - - /* Add Route Flag */ - /* The route will be added in the polling routine so - that it is not interrupt context. */ + } + clear_bit(ARP_CRIT,&card->wandev.critical); + + chan->ip_local = in_dev->ifa_list->ifa_local; + chan->ip_remote = arphdr->ar_sip; - ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE; - card->poll = &process_route; + /* Add Route Flag */ + /* The route will be added in the polling routine so + that it is not interrupt context. */ - break; + chan->route_flag = ADD_ROUTE; + trigger_fr_poll (dev); - case 0x09: // Inverse ARP reply + break; - /* Check for valid Address */ - printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Reply\n", ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip)); + case 0x09: // Inverse ARP reply - if ((in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { - printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", card->devname); - return -1; - } + /* Check for valid Address */ + printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Reply\n", + card->devname, in_ntoa(arphdr->ar_sip)); - if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { - printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", card->devname); - return -1; - } - /* Modify Point-to-Point Address */ - { - struct ifreq if_info; - struct sockaddr_in *if_data; - mm_segment_t fs = get_fs(); - int err; + /* Compare network addresses, only if network mask + * is not 255.255.255.255 It would not make sense + * to perform this test if the mask was all 1's */ - /* Set remote addresses */ - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); + if (in_dev->ifa_list->ifa_mask != 0xffffffff && + (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != + (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { - set_fs(get_ds()); /* get user space block */ - - if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data->sin_addr.s_addr = arphdr->ar_sip; - if_data->sin_family = AF_INET; - err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", + card->devname); + return -1; + } - set_fs(fs); /* restore old block */ - } + /* Make sure that the received IP address is not + * the same as our own local address */ + if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { + printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", + card->devname); + return -1; + } - /* Add Route Flag */ - /* The route will be added in the polling routine so - that it is not interrupt context. */ + chan->ip_local = in_dev->ifa_list->ifa_local; + chan->ip_remote = arphdr->ar_sip; - ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE; - ((fr_channel_t *) dev->priv)->inarp = INARP_CONFIGURED; - card->poll = &process_route; - - break; - default: // ARP's and RARP's -- Shouldn't happen. - } + /* Add Route Flag */ + /* The route will be added in the polling routine so + that it is not interrupt context. */ + + chan->route_flag = ADD_ROUTE; + chan->inarp = INARP_CONFIGURED; + trigger_fr_poll(dev); + + break; + default: // ARP's and RARP's -- Shouldn't happen. } return 0; +#else + + switch (ntohs(arphdr->ar_op)) { + + case 0x08: // Inverse ARP request -- Send Reply, add route. + + /* Check for valid Address */ + printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Req\n", + ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip)); + + + if (dev->pa_mask != 0xFFFFFFFF){ + + if ((dev->pa_mask & arphdr->ar_sip) != (dev->pa_mask & dev->pa_addr)) { + printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", + card->devname); + return -1; + } + } + + if (dev->pa_addr == arphdr->ar_sip) { + printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", + card->devname); + return -1; + } + + arphdr->ar_op = htons(0x09); /* InARP Reply */ + + /* Set addresses */ + arphdr->ar_tip = arphdr->ar_sip; + arphdr->ar_sip = dev->pa_addr; + + fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket); + + clear_bit(ARP_CRIT,&card->wandev.critical); + + /* Modify Point-to-Point Address */ + dev->pa_dstaddr = arphdr->ar_tip; + + /* Add Route Flag */ + /* The route will be added in the polling routine so + that it is not interrupt context. */ + ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE; + trigger_fr_poll(dev); + + break; + case 0x09: // Inverse ARP reply + + /* Check for valid Address */ + printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Reply\n", + ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip)); + + if ((dev->pa_mask & arphdr->ar_sip) != (dev->pa_mask & dev->pa_addr)) { + printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", + card->devname); + return -1; + } + + if (dev->pa_addr == arphdr->ar_sip) { + printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", + card->devname); + return -1; + } + + /* Modify Point-to-Point Address */ + dev->pa_dstaddr = arphdr->ar_sip; + /* Add Route Flag */ + /* The route will be added in the polling routine so + that it is not interrupt context. */ + + ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE; + ((fr_channel_t *) dev->priv)->inarp = INARP_CONFIGURED; + trigger_fr_poll(dev); + + break; + default: // ARP's and RARP's -- Shouldn't happen. + } + + return 0; + +#endif +} + + +/*============================================================ + * trigger_fr_arp + * + * Description: + * Add an fr_arp() task into a arp + * timer handler for a specific dlci/interface. + * This will kick the fr_arp() routine + * within the specified time interval. + * + * Usage: + * This timer is used to send ARP requests at + * certain time intervals. + * Called by an interrupt to request an action + * at a later date. + */ + +static void trigger_fr_arp (netdevice_t *dev) +{ + fr_channel_t* chan = dev->priv; + + del_timer(&chan->fr_arp_timer); + chan->fr_arp_timer.expires = jiffies + (chan->inarp_interval * HZ); + add_timer(&chan->fr_arp_timer); + return; +} + + + +/*============================================================================== + * ARP Request Action + * + * This funciton is called by timer interrupt to send an arp request + * to the remote end. + */ + +static void fr_arp (unsigned long data) +{ + netdevice_t *dev = (netdevice_t *)data; + fr_channel_t *chan = dev->priv; + volatile sdla_t *card = chan->card; + fr508_flags_t* flags = card->flags; + + /* Send ARP packets for all devs' until + * ARP state changes to CONFIGURED */ + + if (chan->inarp == INARP_REQUEST && + chan->common.state == WAN_CONNECTED && + card->wandev.state == WAN_CONNECTED){ + set_bit(0,&chan->inarp_ready); + card->u.f.timer_int_enabled |= TMR_INT_ENABLED_ARP; + flags->imask |= FR_INTR_TIMER; + } + + return; } @@ -3555,11 +4591,6 @@ fr_mbox_t* mb = card->mbox; int err,i; - /* The critical flag is unset here because we want to get into the - ISR without the flag already set. The If_open sets the flag. - */ - clear_bit(1, (void*)&card->wandev.critical); - err = fr_set_intr_mode(card, FR_INTR_READY, card->wandev.mtu, 0 ); if (err == CMD_OK) { @@ -3582,7 +4613,6 @@ if( err != CMD_OK ) return err; - set_bit(1, (void*)&card->wandev.critical); return 0; } @@ -3593,6 +4623,9 @@ { fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)skb->data; + /* Quick HACK */ + + if((fr_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && (fr_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) && (fr_udp_pkt->udp_pkt.udp_dst_port == @@ -3600,10 +4633,10 @@ (fr_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { if(!strncmp(fr_udp_pkt->wp_mgmt.signature, - UDPMGMT_FPIPE_SIGNATURE, 8)) + UDPMGMT_FPIPE_SIGNATURE, 8)){ return UDP_FPIPE_TYPE; + } } - return UDP_INVALID_TYPE; } @@ -3674,38 +4707,772 @@ card->devname, chan->dlci); } + + void s508_s514_lock(sdla_t *card, unsigned long *smp_flags) { - if (card->hw.type != SDLA_S514){ -#ifdef CONFIG_SMP - spin_lock_irqsave(&card->lock, *smp_flags); + +#if defined(__SMP__) || defined(LINUX_2_4) + spin_lock_irqsave(&card->wandev.lock, *smp_flags); #else - disable_irq(card->hw.irq); + disable_irq(card->hw.irq); #endif - } -#ifdef CONFIG_SMP - else{ - spin_lock(&card->lock); - } + }else{ +#if defined(__SMP__) || defined(LINUX_2_4) + spin_lock(&card->u.f.if_send_lock); #endif + } + return; } + void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags) { if (card->hw.type != SDLA_S514){ -#ifdef CONFIG_SMP - spin_unlock_irqrestore(&card->lock, *smp_flags); + +#if defined(__SMP__) || defined(LINUX_2_4) + spin_unlock_irqrestore (&card->wandev.lock, *smp_flags); #else - enable_irq(card->hw.irq); + enable_irq(card->hw.irq); #endif + }else{ +#if defined(__SMP__) || defined(LINUX_2_4) + spin_unlock(&card->u.f.if_send_lock); +#endif + } + return; +} + + + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + +/*---------------------------------------------------------------------- + RECEIVE INTERRUPT: BOTTOM HALF HANDLERS + ----------------------------------------------------------------------*/ + + +/*======================================================== + * bh_enqueue + * + * Description: + * Insert a received packed into a circular + * rx queue. This packed will be picked up + * by fr_bh() and sent up the stack to the + * user. + * + * Usage: + * This function is called by rx interrupt, + * in API mode. + * + */ + +static int bh_enqueue (netdevice_t *dev, struct sk_buff *skb) +{ + /* Check for full */ + fr_channel_t* chan = dev->priv; + sdla_t *card = chan->card; + + + if (atomic_read(&chan->bh_buff_used) == MAX_BH_BUFF){ + ++card->wandev.stats.rx_dropped; + wan_dev_kfree_skb(skb, FREE_READ); + return 1; } -#ifdef CONFIG_SMP - else{ - spin_unlock(&card->lock); + + ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; + + if (chan->bh_write == (MAX_BH_BUFF-1)){ + chan->bh_write=0; + }else{ + ++chan->bh_write; + } + + atomic_inc(&chan->bh_buff_used); + + return 0; +} + + +/*======================================================== + * trigger_fr_bh + * + * Description: + * Kick the fr_bh() handler + * + * Usage: + * rx interrupt calls this function during + * the API mode. + */ + +static void trigger_fr_bh (fr_channel_t *chan) +{ + if (!test_and_set_bit(0,&chan->tq_working)){ + wanpipe_queue_tq(&chan->common.wanpipe_task); + wanpipe_mark_bh(); + } +} + + +/*======================================================== + * fr_bh + * + * Description: + * Frame relay receive BH handler. + * Dequeue data from the BH circular + * buffer and pass it up the API sock. + * + * Rationale: + * This fuction is used to offload the + * rx_interrupt during API operation mode. + * The fr_bh() function executes for each + * dlci/interface. + * + * Once receive interrupt copies data from the + * card into an skb buffer, the skb buffer + * is appended to a circular BH buffer. + * Then the interrupt kicks fr_bh() to finish the + * job at a later time (no within the interrupt). + * + * Usage: + * Interrupts use this to defer a taks to + * a polling routine. + * + */ + +static void fr_bh (netdevice_t * dev) +{ + fr_channel_t* chan = dev->priv; + sdla_t *card = chan->card; + struct sk_buff *skb; + + if (atomic_read(&chan->bh_buff_used) == 0){ + clear_bit(0, &chan->tq_working); + return; + } + + while (atomic_read(&chan->bh_buff_used)){ + + if (chan->common.sk == NULL || chan->common.func == NULL){ + clear_bit(0, &chan->tq_working); + return; + } + + skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; + + if (skb != NULL){ + + if (chan->common.sk == NULL || chan->common.func == NULL){ + ++card->wandev.stats.rx_dropped; + ++chan->ifstats.rx_dropped; + wan_dev_kfree_skb(skb, FREE_READ); + fr_bh_cleanup(dev); + continue; + } + + if (chan->common.func(skb,dev,chan->common.sk) != 0){ + /* Sock full cannot send, queue us for + * another try */ + atomic_set(&chan->common.receive_block,1); + return; + }else{ + fr_bh_cleanup(dev); + } + }else{ + fr_bh_cleanup(dev); + } } + clear_bit(0, &chan->tq_working); + + return; +} + +static int fr_bh_cleanup (netdevice_t *dev) +{ + fr_channel_t* chan = dev->priv; + + ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; + + if (chan->bh_read == (MAX_BH_BUFF-1)){ + chan->bh_read=0; + }else{ + ++chan->bh_read; + } + + atomic_dec(&chan->bh_buff_used); + return 0; +} #endif + +/*---------------------------------------------------------------------- + POLL BH HANDLERS AND KICK ROUTINES + ----------------------------------------------------------------------*/ + +/*============================================================ + * trigger_fr_poll + * + * Description: + * Add a fr_poll() task into a tq_scheduler bh handler + * for a specific dlci/interface. This will kick + * the fr_poll() routine at a later time. + * + * Usage: + * Interrupts use this to defer a taks to + * a polling routine. + * + */ +static void trigger_fr_poll (netdevice_t *dev) +{ + fr_channel_t* chan = dev->priv; +#ifdef LINUX_2_4 + schedule_task(&chan->fr_poll_task); +#else + queue_task(&chan->fr_poll_task, &tq_scheduler); +#endif + return; } + + +/*============================================================ + * fr_poll + * + * Rationale: + * We cannot manipulate the routing tables, or + * ip addresses withing the interrupt. Therefore + * we must perform such actons outside an interrupt + * at a later time. + * + * Description: + * Frame relay polling routine, responsible for + * shutting down interfaces upon disconnect + * and adding/removing routes. + * + * Usage: + * This function is executed for each frame relay + * dlci/interface through a tq_schedule bottom half. + * + * trigger_fr_poll() function is used to kick + * the fr_poll routine. + */ + +static void fr_poll (netdevice_t *dev) +{ + + fr_channel_t* chan; + sdla_t *card; + u8 check_gateway=0; + + if (!dev || (chan = dev->priv) == NULL) + return; + + card = chan->card; + + /* (Re)Configuraiton is in progress, stop what you are + * doing and get out */ + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + return; + } + + switch (chan->common.state){ + + case WAN_DISCONNECTED: + + if (test_bit(DYN_OPT_ON,&chan->interface_down) && + !test_bit(DEV_DOWN, &chan->interface_down) && + dev->flags&IFF_UP){ + + printk(KERN_INFO "%s: Interface %s is Down.\n", + card->devname,dev->name); + change_dev_flags(dev,dev->flags&~IFF_UP); + set_bit(DEV_DOWN, &chan->interface_down); + chan->route_flag = NO_ROUTE; + + }else{ + if (chan->inarp != INARP_NONE) + process_route(dev); + } + break; + + case WAN_CONNECTED: + + if (test_bit(DYN_OPT_ON,&chan->interface_down) && + test_bit(DEV_DOWN, &chan->interface_down) && + !(dev->flags&IFF_UP)){ + + printk(KERN_INFO "%s: Interface %s is Up.\n", + card->devname,dev->name); + + change_dev_flags(dev,dev->flags|IFF_UP); + clear_bit(DEV_DOWN, &chan->interface_down); + check_gateway=1; + } + + if (chan->inarp != INARP_NONE){ + process_route(dev); + check_gateway=1; + } + + if (chan->gateway && check_gateway) + add_gateway(card,dev); + + break; + + } + + return; +} + +/*============================================================== + * check_tx_status + * + * Rationale: + * We cannot transmit from an interrupt while + * the if_send is transmitting data. Therefore, + * we must check whether the tx buffers are + * begin used, before we transmit from an + * interrupt. + * + * Description: + * Checks whether it's safe to use the transmit + * buffers. + * + * Usage: + * ARP and UDP handling routines use this function + * because, they need to transmit data during + * an interrupt. + */ + +static int check_tx_status(sdla_t *card, netdevice_t *dev) +{ + + if (card->hw.type == SDLA_S514){ + if (test_bit(SEND_CRIT, (void*)&card->wandev.critical) || + test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) { + return 1; + } + } + + if (is_queue_stopped(dev) || (card->u.f.tx_interrupts_pending)) + return 1; + + return 0; +} + +/*=============================================================== + * move_dev_to_next + * + * Description: + * Move the dev pointer to the next location in the + * link list. Check if we are at the end of the + * list, if so start from the begining. + * + * Usage: + * Timer interrupt uses this function to efficiently + * step through the devices that need to send ARP data. + * + */ + +netdevice_t * move_dev_to_next (sdla_t *card, netdevice_t *dev) +{ + if (card->wandev.new_if_cnt != 1){ + if (*((netdevice_t **)dev->priv) == NULL){ + return card->wandev.dev; + }else{ + return *((netdevice_t **)dev->priv); + } + } + return dev; +} + +/*============================================================== + * trigger_config_fr + * + * Rationale: + * All commands must be performed inside of a + * interrupt. + * + * Description: + * Kick the config_fr() routine throught the + * timer interrupt. + */ + + +static void trigger_config_fr (sdla_t *card) +{ + fr508_flags_t* flags = card->flags; + + card->u.f.timer_int_enabled |= TMR_INT_ENABLED_CONFIG; + flags->imask |= FR_INTR_TIMER; +} + + +/*============================================================== + * config_fr + * + * Rationale: + * All commands must be performed inside of a + * interrupt. + & + * Description: + * Configure a DLCI. This function is executed + * by a timer_interrupt. The if_open() function + * triggers it. + * + * Usage: + * new_if() collects all data necessary to + * configure the DLCI. It sets the chan->dlci_ready + * bit. When the if_open() function is executed + * it checks this bit, and if its set it triggers + * the timer interrupt to execute the config_fr() + * function. + */ + +static void config_fr (sdla_t *card) +{ + netdevice_t *dev; + fr_channel_t *chan; + + for (dev=card->wandev.dev; dev; dev=*((netdevice_t **)dev->priv)){ + + if ((chan=dev->priv) == NULL) + continue; + + if (!test_bit(0,&chan->config_dlci)) + continue; + + clear_bit(0,&chan->config_dlci); + + /* If signalling is set to NO, then setup + * DLCI addresses right away. Don't have to wait for + * link to connect. + */ + if (card->wandev.signalling == WANOPT_NO){ + printk(KERN_INFO "%s: Signalling set to NO: Mapping DLCI's\n", + card->wandev.name); + if (fr_init_dlci(card,chan)){ + printk(KERN_INFO "%s: ERROR: Failed to configure DLCI %i !\n", + card->devname, chan->dlci); + return; + } + } + + if (card->wandev.station == WANOPT_CPE) { + + update_chan_state(dev); + + /* CPE: issue full status enquiry */ + fr_issue_isf(card, FR_ISF_FSE); + + } else { + /* FR switch: activate DLCI(s) */ + + /* For Switch emulation we have to ADD and ACTIVATE + * the DLCI(s) that were configured with the SET_DLCI_ + * CONFIGURATION command. Add and Activate will fail if + * DLCI specified is not included in the list. + * + * Also If_open is called once for each interface. But + * it does not get in here for all the interface. So + * we have to pass the entire list of DLCI(s) to add + * activate routines. + */ + + if (!check_dlci_config (card, chan)){ + fr_add_dlci(card, chan->dlci); + fr_activate_dlci(card, chan->dlci); + } + } + + card->u.f.dlci_to_dev_map[chan->dlci] = dev; + } + return; +} + + +/*============================================================== + * config_fr + * + * Rationale: + * All commands must be executed during an interrupt. + * + * Description: + * Trigger uncofig_fr() function through + * the timer interrupt. + * + */ + +static void trigger_unconfig_fr (netdevice_t *dev) +{ + fr_channel_t *chan = dev->priv; + volatile sdla_t *card = chan->card; + u32 timeout; + fr508_flags_t* flags = card->flags; + int reset_critical=0; + + if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){ + clear_bit(PERI_CRIT,(void*)&card->wandev.critical); + reset_critical=1; + } + + /* run unconfig_dlci() function + * throught the timer interrupt */ + set_bit(0,(void*)&chan->unconfig_dlci); + card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UNCONFIG; + flags->imask |= FR_INTR_TIMER; + + /* Wait for the command to complete */ + timeout = jiffies; + for(;;) { + + if(!(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG)) + break; + + if ((jiffies - timeout) > (1 * HZ)){ + card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG; + printk(KERN_INFO "%s: Failed to delete DLCI %i\n", + card->devname,chan->dlci); + break; + } + } + + if (reset_critical){ + set_bit(PERI_CRIT,(void*)&card->wandev.critical); + } +} + +/*============================================================== + * unconfig_fr + * + * Rationale: + * All commands must be executed during an interrupt. + * + * Description: + * Remove the dlci from firmware. + * This funciton is used in NODE shutdown. + */ + +static void unconfig_fr (sdla_t *card) +{ + netdevice_t *dev; + fr_channel_t *chan; + + for (dev=card->wandev.dev; dev; dev=*((netdevice_t **)dev->priv)){ + + if ((chan=dev->priv) == NULL) + continue; + + if (!test_bit(0,&chan->unconfig_dlci)) + continue; + + clear_bit(0,&chan->unconfig_dlci); + + if (card->wandev.station == WANOPT_NODE){ + printk(KERN_INFO "%s: Unconfiguring DLCI %i\n", + card->devname,chan->dlci); + fr_delete_dlci(card,chan->dlci); + } + card->u.f.dlci_to_dev_map[chan->dlci] = NULL; + } +} + +static int setup_fr_header(struct sk_buff ** skb_orig, netdevice_t* dev, char op_mode) +{ + struct sk_buff *skb = *skb_orig; + fr_channel_t *chan=dev->priv; + + if (op_mode == WANPIPE){ + + chan->fr_header[0]=Q922_UI; + + switch (htons(skb->protocol)){ + + case ETH_P_IP: + chan->fr_header[1]=NLPID_IP; + break; + default: + return -EINVAL; + } + + return 2; + } + + /* If we are in bridging mode, we must apply + * an Ethernet header */ + if (op_mode == BRIDGE || op_mode == BRIDGE_NODE){ + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + + /* Encapsulate the packet as a bridged Ethernet frame. */ +#ifdef DEBUG + printk(KERN_INFO "%s: encapsulating skb for frame relay\n", + dev->name); +#endif + + chan->fr_header[0] = 0x03; + chan->fr_header[1] = 0x00; + chan->fr_header[2] = 0x80; + chan->fr_header[3] = 0x00; + chan->fr_header[4] = 0x80; + chan->fr_header[5] = 0xC2; + chan->fr_header[6] = 0x00; + chan->fr_header[7] = 0x07; + + /* Yuck. */ + skb->protocol = ETH_P_802_3; + return 8; + +#else + + /* BRIDGING is not supported in 2.0.X */ + return -EINVAL; + +#endif + } + + return 0; +} + + +static int check_dlci_config (sdla_t *card, fr_channel_t *chan) +{ + fr_mbox_t* mbox = card->mbox; + int err=0; + fr_conf_t *conf=NULL; + unsigned short dlci_num = chan->dlci; + int dlci_offset=0; + netdevice_t *dev=NULL; + + mbox->cmd.command = FR_READ_CONFIG; + mbox->cmd.length = 0; + mbox->cmd.dlci = dlci_num; + + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + + if (err == CMD_OK){ + return 0; + } + + for (dev=card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){ + set_chan_state(dev,WAN_DISCONNECTED); + } + + printk(KERN_INFO "DLCI %i Not configured, configuring\n",dlci_num); + + mbox->cmd.command = FR_COMM_DISABLE; + mbox->cmd.length = 0; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK){ + fr_event(card, err, mbox); + return 2; + } + + printk(KERN_INFO "Disabled Communications \n"); + + mbox->cmd.command = FR_READ_CONFIG; + mbox->cmd.length = 0; + mbox->cmd.dlci = 0; + + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK){ + fr_event(card, err, mbox); + return 2; + } + + conf = (fr_conf_t *)mbox->data; + + dlci_offset=0; + for (dev=card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){ + fr_channel_t *chan_tmp = dev->priv; + conf->dlci[dlci_offset] = chan_tmp->dlci; + dlci_offset++; + } + + printk(KERN_INFO "Got Fr configuration Buffer Length is %x Dlci %i Dlci Off %i\n", + mbox->cmd.length, + mbox->cmd.length > 0x20 ? conf->dlci[0] : -1, + dlci_offset ); + + mbox->cmd.length = 0x20 + dlci_offset*2; + + mbox->cmd.command = FR_SET_CONFIG; + mbox->cmd.dlci = 0; + + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK){ + fr_event(card, err, mbox); + return 2; + } + + initialize_rx_tx_buffers (card); + + + printk(KERN_INFO "Configuraiton Succeded for new DLCI %i\n",dlci_num); + + if (fr_comm_enable (card)){ + return 2; + } + + printk(KERN_INFO "Enabling Communications \n"); + + for (dev=card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){ + fr_channel_t *chan_tmp = dev->priv; + fr_init_dlci(card,chan_tmp); + fr_add_dlci(card, chan_tmp->dlci); + fr_activate_dlci(card, chan_tmp->dlci); + } + + printk(KERN_INFO "END OF CONFIGURAITON %i\n",dlci_num); + + return 1; +} + +static void initialize_rx_tx_buffers (sdla_t *card) +{ + fr_buf_info_t* buf_info; + + if (card->hw.type == SDLA_S514) { + + buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR + + FR508_RXBC_OFFS); + + card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase); + + card->u.f.rxmb_base = + (void*)(buf_info->rse_base + card->hw.dpmbase); + + card->u.f.rxmb_last = + (void*)(buf_info->rse_base + + (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) + + card->hw.dpmbase); + }else{ + buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS); + + card->rxmb = (void*)(buf_info->rse_next - + FR_MB_VECTOR + card->hw.dpmbase); + + card->u.f.rxmb_base = + (void*)(buf_info->rse_base - + FR_MB_VECTOR + card->hw.dpmbase); + + card->u.f.rxmb_last = + (void*)(buf_info->rse_base + + (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) - + FR_MB_VECTOR + card->hw.dpmbase); + } + + card->u.f.rx_base = buf_info->buf_base; + card->u.f.rx_top = buf_info->buf_top; + + card->u.f.tx_interrupts_pending = 0; + + return; +} + + + /****** End *****************************************************************/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/wan/sdla_ft1.c linux.ac/drivers/net/wan/sdla_ft1.c --- linux.vanilla/drivers/net/wan/sdla_ft1.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/wan/sdla_ft1.c Sat Apr 14 01:28:20 2001 @@ -0,0 +1,386 @@ +/***************************************************************************** +* sdla_chdlc.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module. +* +* Authors: Nenad Corbic <ncorbic@sangoma.com> +* Gideon Hack +* +* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Sep 30, 1999 Nenad Corbic Fixed dynamic IP and route setup. +* Sep 23, 1999 Nenad Corbic Added SMP support, fixed tracing +* Sep 13, 1999 Nenad Corbic Split up Port 0 and 1 into separate devices. +* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. +* Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING). +* Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC. +* Aug 07, 1998 David Fong Initial version. +*****************************************************************************/ + +#include <linux/version.h> +#include <linux/kernel.h> /* printk(), and other useful stuff */ +#include <linux/stddef.h> /* offsetof(), etc. */ +#include <linux/errno.h> /* return codes */ +#include <linux/string.h> /* inline memset(), etc. */ +#include <linux/malloc.h> /* kmalloc(), kfree() */ +#include <linux/wanrouter.h> /* WAN router definitions */ +#include <linux/wanpipe.h> /* WANPIPE common user API definitions */ +#include <linux/if_arp.h> /* ARPHRD_* defines */ + +#if defined(LINUX_2_4) + #include <linux/inetdevice.h> + #include <asm/uaccess.h> + +#elif defined(LINUX_2_1) + #include <linux/inetdevice.h> + #include <asm/uaccess.h> + +#else + #include <net/route.h> /* Adding new route entries */ + #include <asm/segment.h> + #define test_and_set_bit set_bit +#endif + +#include <linux/in.h> /* sockaddr_in */ +#include <linux/inet.h> +#include <linux/if.h> +#include <asm/byteorder.h> /* htons(), etc. */ +#include <linux/sdlapci.h> +#include <asm/io.h> + +#include <linux/sdla_chdlc.h> /* CHDLC firmware API definitions */ + +/****** Defines & Macros ****************************************************/ + +/* reasons for enabling the timer interrupt on the adapter */ +#define TMR_INT_ENABLED_UDP 0x0001 +#define TMR_INT_ENABLED_UPDATE 0x0002 + +#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ +#define CHDLC_HDR_LEN 1 + +#define IFF_POINTTOPOINT 0x10 + +#define WANPIPE 0x00 +#define API 0x01 +#define CHDLC_API 0x01 + +#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) + + +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with CHDLC specific data + */ + +typedef struct chdlc_private_area +{ + netdevice_t *slave; + sdla_t *card; + int TracingEnabled; /* For enabling Tracing */ + unsigned long curr_trace_addr; /* Used for Tracing */ + unsigned long start_trace_addr; + unsigned long end_trace_addr; + unsigned long base_addr_trace_buffer; + unsigned long end_addr_trace_buffer; + unsigned short number_trace_elements; + unsigned available_buffer_space; + unsigned long router_start_time; + unsigned char route_status; + unsigned char route_removed; + unsigned long tick_counter; /* For 5s timeout counter */ + unsigned long router_up_time; + u32 IP_address; /* IP addressing */ + u32 IP_netmask; + unsigned char mc; /* Mulitcast support on/off */ + unsigned short udp_pkt_lgth; /* udp packet processing */ + char udp_pkt_src; + char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; + unsigned short timer_int_enabled; + char update_comms_stats; /* updating comms stats */ + //FIXME: add driver stats as per frame relay! + +} chdlc_private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + + +/****** Function Prototypes *************************************************/ +/* WAN link driver entry points. These are called by the WAN router module. */ +static int wpft1_exec (struct sdla *card, void *u_cmd, void *u_data); +static int chdlc_read_version (sdla_t* card, char* str); +static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * Cisco HDLC protocol initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wpft1_init (sdla_t* card, wandev_conf_t* conf) +{ + unsigned char port_num; + int err; + + union + { + char str[80]; + } u; + volatile CHDLC_MAILBOX_STRUCT* mb; + CHDLC_MAILBOX_STRUCT* mb1; + unsigned long timeout; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_CHDLC) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + + /* Use primary port */ + card->u.c.comm_port = 0; + + + /* Initialize protocol-specific fields */ + if(card->hw.type != SDLA_S514){ + card->mbox = (void *) card->hw.dpmbase; + }else{ + card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; + } + + mb = mb1 = card->mbox; + + if (!card->configured){ + + /* The board will place an 'I' in the return code to indicate that it is + ready to accept commands. We expect this to be completed in less + than 1 second. */ + + timeout = jiffies; + while (mb->return_code != 'I') /* Wait 1s for board to initialize */ + if ((jiffies - timeout) > 1*HZ) break; + + if (mb->return_code != 'I') { + printk(KERN_INFO + "%s: Initialization not completed by adapter\n", + card->devname); + printk(KERN_INFO "Please contact Sangoma representative.\n"); + return -EIO; + } + } + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + + if (chdlc_read_version(card, u.str)) + return -EIO; + + printk(KERN_INFO "%s: Running FT1 Configuration firmware v%s\n", + card->devname, u.str); + + card->isr = NULL; + card->poll = NULL; + card->exec = &wpft1_exec; + card->wandev.update = NULL; + card->wandev.new_if = NULL; + card->wandev.del_if = NULL; + card->wandev.state = WAN_DUALPORT; + card->wandev.udp_port = conf->udp_port; + + card->wandev.new_if_cnt = 0; + + /* This is for the ports link state */ + card->u.c.state = WAN_DISCONNECTED; + + /* reset the number of times the 'update()' proc has been called */ + card->u.c.update_call_count = 0; + + card->wandev.ttl = 0x7F; + card->wandev.interface = 0; + + card->wandev.clocking = 0; + + port_num = card->u.c.comm_port; + + /* Setup Port Bps */ + + card->wandev.bps = 0; + + card->wandev.mtu = MIN_LGTH_CHDLC_DATA_CFG; + + /* Set up the interrupt status area */ + /* Read the CHDLC Configuration and obtain: + * Ptr to shared memory infor struct + * Use this pointer to calculate the value of card->u.c.flags ! + */ + mb1->buffer_length = 0; + mb1->command = READ_CHDLC_CONFIGURATION; + err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; + if(err != COMMAND_OK) { + chdlc_error(card, err, mb1); + return -EIO; + } + + if(card->hw.type == SDLA_S514){ + card->u.c.flags = (void *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> + ptr_shared_mem_info_struct)); + }else{ + card->u.c.flags = (void *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> + ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); + } + + card->wandev.state = WAN_FT1_READY; + printk(KERN_INFO "%s: FT1 Config Ready !\n",card->devname); + + return 0; +} + +static int wpft1_exec(sdla_t *card, void *u_cmd, void *u_data) +{ + CHDLC_MAILBOX_STRUCT* mbox = card->mbox; + int len; + + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + if (copy_from_user((void*)&mbox->command, u_cmd, sizeof(ft1_exec_cmd_t))){ + return -EFAULT; + } + + len = mbox->buffer_length; + + if (len) { + if( copy_from_user((void*)&mbox->data, u_data, len)){ + return -EFAULT; + } + } + + /* execute command */ + if (!sdla_exec(mbox)){ + return -EIO; + } + + /* return result */ + if( copy_to_user(u_cmd, (void*)&mbox->command, sizeof(ft1_exec_cmd_t))){ + return -EFAULT; + } + + len = mbox->buffer_length; + + if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)){ + return -EFAULT; + } + +#else + + if (!u_cmd || verify_area(VERIFY_WRITE, u_cmd, sizeof(ft1_exec_cmd_t))){ + return -EFAULT; + } + + memcpy_fromfs((void*)&mbox->command, u_cmd, sizeof(ft1_exec_cmd_t)); + + len = mbox->buffer_length; + + if (len) { + if (!u_data || verify_area(VERIFY_READ, u_data, len)) + return -EFAULT; + memcpy_fromfs((void*)&mbox->data, u_data, len); + } + + /* execute command */ + if (!sdla_exec(mbox)) + return -EIO; + + /* return result */ + memcpy_tofs(u_cmd, (void*)&mbox->command, sizeof(ft1_exec_cmd_t)); + len = mbox->buffer_length; + + if (len && u_data && !verify_area(VERIFY_WRITE, u_data, len)){ + memcpy_tofs(u_data, (void*)&mbox->data, len); + } + +#endif + + return 0; + +} + +/*============================================================================ + * Read firmware code version. + * Put code version as ASCII string in str. + */ +static int chdlc_read_version (sdla_t* card, char* str) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + int len; + char err; + mb->buffer_length = 0; + mb->command = READ_CHDLC_CODE_VERSION; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + } + else if (str) { /* is not null */ + len = mb->buffer_length; + memcpy(str, mb->data, len); + str[len] = '\0'; + } + return (err); +} + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb) +{ + unsigned cmd = mb->command; + + switch (err) { + + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + case S514_BOTH_PORTS_SAME_CLK_MODE: + if(cmd == SET_CHDLC_CONFIGURATION) { + printk(KERN_INFO + "%s: Configure both ports for the same clock source\n", + card->devname); + break; + } + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err); + } + + return 0; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/wan/sdla_ppp.c linux.ac/drivers/net/wan/sdla_ppp.c --- linux.vanilla/drivers/net/wan/sdla_ppp.c Tue Apr 3 17:32:16 2001 +++ linux.ac/drivers/net/wan/sdla_ppp.c Mon Apr 16 15:17:17 2001 @@ -3,14 +3,30 @@ * * Author: Nenad Corbic <ncorbic@sangoma.com> * -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* Copyright: (c) 1995-2001 Sangoma Technologies Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ -* +* Feb 28, 2001 Nenad Corbic o Updated if_tx_timeout() routine for +* 2.4.X kernels. +* Nov 29, 2000 Nenad Corbic o Added the 2.4.x kernel support: +* get_ip_address() function has moved +* into the ppp_poll() routine. It cannot +* be called from an interrupt. +* Nov 07, 2000 Nenad Corbic o Added security features for UDP debugging: +* Deny all and specify allowed requests. +* May 02, 2000 Nenad Corbic o Added the dynamic interface shutdown +* option. When the link goes down, the +* network interface IFF_UP flag is reset. +* Mar 06, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. +* Feb 25, 2000 Nenad Corbic o Fixed the FT1 UDP debugger problem. +* Feb 09, 2000 Nenad Coribc o Shutdown bug fix. update() was called +* with NULL dev pointer: no check. +* Jan 24, 2000 Nenad Corbic o Disabled use of CMD complete inter. +* Dev 15, 1999 Nenad Corbic o Fixed up header files for 2.0.X kernels * Oct 25, 1999 Nenad Corbic o Support for 2.0.X kernels * Moved dynamic route processing into * a polling routine. @@ -74,13 +90,12 @@ * Jan 06, 1997 Gene Kozin Initial version. *****************************************************************************/ -#include <linux/config.h> #include <linux/version.h> #include <linux/kernel.h> /* printk(), and other useful stuff */ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ #include <linux/string.h> /* inline memset(), etc. */ -#include <linux/slab.h> /* kmalloc(), kfree() */ +#include <linux/malloc.h> /* kmalloc(), kfree() */ #include <linux/wanrouter.h> /* WAN router definitions */ #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ #include <linux/if_arp.h> /* ARPHRD_* defines */ @@ -88,24 +103,29 @@ #include <linux/in.h> /* sockaddr_in */ #include <linux/inet.h> /* in_aton(), in_ntoa() prototypes */ -#include <linux/inetdevice.h> -#include <asm/uaccess.h> + +/* ---- 2.4.X KERNEL SUPPORT -----------------------*/ +#if defined(LINUX_2_1) || defined(LINUX_2_4) + #include <asm/uaccess.h> + #include <linux/inetdevice.h> + #include <linux/netdevice.h> +#else + #include <asm/segment.h> + #include <net/route.h> /* Adding new route entries : 2.0.X kernels */ +#endif #include <linux/if.h> +#include <linux/wanpipe.h> #include <linux/sdla_ppp.h> /* PPP firmware API definitions */ #include <linux/sdlasfm.h> /* S514 Type Definition */ /****** Defines & Macros ****************************************************/ -#ifdef _DEBUG_ -#define STATIC -#else -#define STATIC static -#endif - #define PPP_DFLT_MTU 1500 /* default MTU */ #define PPP_MAX_MTU 4000 /* maximum MTU */ #define PPP_HDR_LEN 1 +#define MAX_IP_ERRORS 100 + #define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ #define HOLD_DOWN_TIME (5*HZ) /* link hold down time : Changed from 30 to 5 */ @@ -125,9 +145,10 @@ #define LCP(a) ( a == 0x09 ? "OPEN" : "CLOSED" ) #define IP(a) ( a == 0x09 ? "ENABLED" : "DISABLED" ) -#define TMR_INT_ENABLED_UPDATE 1 -#define TMR_INT_ENABLED_PPP_EVENT 2 -#define TMR_INT_ENABLED_UDP 4 +#define TMR_INT_ENABLED_UPDATE 0x01 +#define TMR_INT_ENABLED_PPP_EVENT 0x02 +#define TMR_INT_ENABLED_UDP 0x04 +#define TMR_INT_ENABLED_CONFIG 0x20 /* Set Configuraton Command Definitions */ #define PERCENT_TX_BUFF 60 @@ -143,8 +164,11 @@ #define NUM_AUTH_REQ_WITHOUT_REPLY 10 #define END_OFFSET 0x1F0 +#if LINUX_VERSION_CODE < 0x020125 +#define test_and_set_bit set_bit +#define net_ratelimit() 1 +#endif -#define TX_TIMEOUT (5*HZ) /******Data Structures*****************************************************/ @@ -155,9 +179,7 @@ typedef struct ppp_private_area { - /* This member must be first. */ - struct net_device *slave; /* WAN slave */ - + netdevice_t *slave; sdla_t* card; unsigned long router_start_time; /*router start time in sec */ unsigned long tick_counter; /*used for 5 second counter*/ @@ -173,12 +195,20 @@ u32 ip_local; /* Local IP Address */ u32 ip_remote; /* remote IP Address */ + u32 ip_local_tmp; + u32 ip_remote_tmp; + unsigned char timer_int_enabled; /* Who enabled the timer inter*/ unsigned char update_comms_stats; /* Used by update function */ unsigned long curr_trace_addr; /* Trace information */ unsigned long start_trace_addr; unsigned long end_trace_addr; + unsigned char interface_down; /* Brind down interface when channel + goes down */ + unsigned long config_wait_timeout; /* After if_open() if in dynamic if mode, + wait a few seconds before configuring */ + unsigned short udp_pkt_lgth; char udp_pkt_src; char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; @@ -191,6 +221,16 @@ unsigned long router_up_time; + /* Polling task queue. Each interface + * has its own task queue, which is used + * to defer events from the interrupt */ + struct tq_struct poll_task; + struct timer_list poll_delay_timer; + + u8 gateway; + u8 config_ppp; + u8 ip_error; + }ppp_private_area_t; /* variable for keeping track of enabling/disabling FT1 monitor status */ @@ -203,22 +243,32 @@ /* WAN link driver entry points. These are called by the WAN router module. */ static int update(wan_device_t *wandev); -static int new_if(wan_device_t *wandev, struct net_device *dev, wanif_conf_t *conf); -static int del_if(wan_device_t *wandev, struct net_device *dev); +static int new_if(wan_device_t *wandev, netdevice_t *dev, wanif_conf_t *conf); +static int del_if(wan_device_t *wandev, netdevice_t *dev); /* WANPIPE-specific entry points */ static int wpp_exec (struct sdla *card, void *u_cmd, void *u_data); /* Network device interface */ -static int if_init(struct net_device *dev); -static int if_open(struct net_device *dev); -static int if_close(struct net_device *dev); -static void if_tx_timeout (struct net_device *dev); -static int if_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, +static int if_init(netdevice_t *dev); +static int if_open(netdevice_t *dev); +static int if_close(netdevice_t *dev); +static int if_header(struct sk_buff *skb, netdevice_t *dev, unsigned short type, void *daddr, void *saddr, unsigned len); + +#ifdef LINUX_2_4 +static void if_tx_timeout (netdevice_t *dev); +#endif + +#if defined(LINUX_2_1) || defined(LINUX_2_4) static int if_rebuild_hdr(struct sk_buff *skb); -static struct net_device_stats *if_stats(struct net_device *dev); -static int if_send(struct sk_buff *skb, struct net_device *dev); +static struct net_device_stats *if_stats(netdevice_t *dev); +#else +static struct enet_statistics *if_stats(netdevice_t *dev); +static int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr, + struct sk_buff* skb); +#endif +static int if_send(struct sk_buff *skb, netdevice_t *dev); /* PPP firmware interface functions */ @@ -229,27 +279,28 @@ static int ppp_set_intr_mode(sdla_t *card, unsigned char mode); static int ppp_comm_enable(sdla_t *card); static int ppp_comm_disable(sdla_t *card); +static int ppp_comm_disable_shutdown(sdla_t *card); static int ppp_get_err_stats(sdla_t *card); static int ppp_send(sdla_t *card, void *data, unsigned len, unsigned proto); static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb); -STATIC void wpp_isr(sdla_t *card); +static void wpp_isr(sdla_t *card); static void rx_intr(sdla_t *card); static void event_intr(sdla_t *card); static void timer_intr(sdla_t *card); /* Background polling routines */ static void process_route(sdla_t *card); -static void poll_disconnected(sdla_t *card); +static void retrigger_comm(sdla_t *card); /* Miscellaneous functions */ static int read_info( sdla_t *card ); static int read_connection_info (sdla_t *card); -static int remove_route( sdla_t *card ); -static int config508(ppp_private_area_t *ppp_priv_area, sdla_t *card); +static void remove_route( sdla_t *card ); +static int config508(netdevice_t *dev, sdla_t *card); static void show_disc_cause(sdla_t * card, unsigned cause); static int reply_udp( unsigned char *data, unsigned int mbox_len ); -static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, +static void process_udp_mgmt_pkt(sdla_t *card, netdevice_t *dev, ppp_private_area_t *ppp_priv_area); static void init_ppp_tx_rx_buff( sdla_t *card ); static int intr_test( sdla_t *card ); @@ -258,12 +309,20 @@ static void init_global_statistics( sdla_t *card ); static int tokenize(char *str, char **tokens); static char* strstrip(char *str, char *s); -static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev, +static int chk_bcast_mcast_addr(sdla_t* card, netdevice_t* dev, struct sk_buff *skb); + +static int config_ppp (sdla_t *); +static void ppp_poll(netdevice_t *); +static void trigger_ppp_poll(netdevice_t *); +static void ppp_poll_delay (unsigned long dev_ptr); + + static int Read_connection_info; static int Intr_test_counter; static unsigned short available_buffer_space; + /* IPX functions */ static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); @@ -275,12 +334,11 @@ static void s508_unlock (sdla_t *card, unsigned long *smp_flags); static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, + struct sk_buff *skb, netdevice_t* dev, ppp_private_area_t* ppp_priv_area ); static unsigned short calc_checksum (char *data, int len); - - - +static void disable_comm (sdla_t *card); +static int detect_and_fix_tx_bug (sdla_t *card); /****** Public Functions ****************************************************/ @@ -298,6 +356,7 @@ */ int wpp_init(sdla_t *card, wandev_conf_t *conf) { + ppp_flags_t *flags; union { char str[80]; @@ -329,6 +388,7 @@ return -EINVAL; } + flags = card->flags; /* Read firmware version. Note that when adapter initializes, it * clears the mailbox, so it may appear that the first command was @@ -353,9 +413,10 @@ card->wandev.update = &update; card->wandev.new_if = &new_if; card->wandev.del_if = &del_if; - card->wandev.state = WAN_DISCONNECTED; card->wandev.udp_port = conf->udp_port; card->wandev.ttl = conf->ttl; + card->wandev.state = WAN_DISCONNECTED; + card->disable_comm = &disable_comm; card->irq_dis_if_send_count = 0; card->irq_dis_poll_count = 0; card->u.p.authenticator = conf->u.ppp.authenticator; @@ -367,6 +428,33 @@ /* initialize global statistics */ init_global_statistics( card ); + + + if (!card->configured){ + int err; + + Intr_test_counter = 0; + err = intr_test(card); + + if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { + printk("%s: Interrupt Test Failed, Counter: %i\n", + card->devname, Intr_test_counter); + printk( "%s: Please choose another interrupt\n",card->devname); + return -EIO; + } + + printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", + card->devname, Intr_test_counter); + card->configured = 1; + } + + ppp_set_intr_mode(card, PPP_INTR_TIMER); + + /* Turn off the transmit and timer interrupt */ + flags->imask &= ~PPP_INTR_TIMER; + + printk(KERN_INFO "\n"); + return 0; } @@ -378,8 +466,8 @@ static int update(wan_device_t *wandev) { sdla_t* card = wandev->private; - struct net_device* dev = card->wandev.dev; - volatile ppp_private_area_t *ppp_priv_area = dev->priv; + netdevice_t* dev; + volatile ppp_private_area_t *ppp_priv_area; ppp_flags_t *flags = card->flags; unsigned long timeout; @@ -390,9 +478,17 @@ if (wandev->state == WAN_UNCONFIGURED) return -ENODEV; - //FIXME: Do we need this - if (test_bit(0, (void*)&wandev->critical)) - return -EAGAIN; + /* Shutdown bug fix. This function can be + * called with NULL dev pointer during + * shutdown + */ + if ((dev=card->wandev.dev) == NULL){ + return -ENODEV; + } + + if ((ppp_priv_area=dev->priv) == NULL){ + return -ENODEV; + } ppp_priv_area->update_comms_stats = 2; ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UPDATE; @@ -427,17 +523,21 @@ * Return: 0 o.k. * < 0 failure (channel will not be created) */ -static int new_if(wan_device_t *wandev, struct net_device *dev, wanif_conf_t *conf) +static int new_if(wan_device_t *wandev, netdevice_t *dev, wanif_conf_t *conf) { sdla_t *card = wandev->private; ppp_private_area_t *ppp_priv_area; - + if (wandev->ndev) return -EEXIST; + + printk(KERN_INFO "%s: Configuring Interface: %s\n", + card->devname, conf->name); + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { - printk(KERN_INFO "%s: invalid interface name!\n", + printk(KERN_INFO "%s: Invalid interface name!\n", card->devname); return -EINVAL; @@ -464,6 +564,14 @@ ppp_priv_area->pap = conf->pap; ppp_priv_area->chap = conf->chap; + /* Option to bring down the interface when + * the link goes down */ + if (conf->if_down){ + set_bit(DYN_OPT_ON,&ppp_priv_area->interface_down); + printk("%s: Dynamic interface configuration enabled\n", + card->devname); + } + /* If no user ids are specified */ if(!strlen(conf->userid) && (ppp_priv_area->pap||ppp_priv_area->chap)){ kfree(ppp_priv_area); @@ -494,16 +602,53 @@ ppp_priv_area->enable_IPX = conf->enable_IPX; - if (conf->network_number) + if (conf->network_number){ ppp_priv_area->network_number = conf->network_number; - else + }else{ ppp_priv_area->network_number = 0xDEADBEEF; + } + /* Tells us that if this interface is a + * gateway or not */ + if ((ppp_priv_area->gateway = conf->gateway) == WANOPT_YES){ + printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", + card->devname,card->u.p.if_name); + } /* prepare network device data space for registration */ - strcpy(dev->name, card->u.p.if_name); +#ifdef LINUX_2_4 + strcpy(dev->name,card->u.p.if_name); +#else + dev->name = (char *)kmalloc(strlen(card->u.p.if_name) + 2, GFP_KERNEL); + if(dev->name == NULL) + { + kfree(ppp_priv_area); + return -ENOMEM; + } + sprintf(dev->name, "%s", card->u.p.if_name); +#endif + dev->init = &if_init; dev->priv = ppp_priv_area; + dev->mtu = min(dev->mtu, card->wandev.mtu); + + /* Initialize the polling task routine */ +#ifndef LINUX_2_4 + ppp_priv_area->poll_task.next = NULL; +#endif + ppp_priv_area->poll_task.sync=0; + ppp_priv_area->poll_task.routine = (void*)(void*)ppp_poll; + ppp_priv_area->poll_task.data = dev; + + /* Initialize the polling delay timer */ + init_timer(&ppp_priv_area->poll_delay_timer); + ppp_priv_area->poll_delay_timer.data = (unsigned long)dev; + ppp_priv_area->poll_delay_timer.function = ppp_poll_delay; + + + /* Since we start with dummy IP addresses we can say + * that route exists */ + printk(KERN_INFO "\n"); return 0; } @@ -511,17 +656,17 @@ /*============================================================================ * Delete logical channel. */ -static int del_if(wan_device_t *wandev, struct net_device *dev) +static int del_if(wan_device_t *wandev, netdevice_t *dev) { - if (dev->priv) { - - kfree(dev->priv); - dev->priv = NULL; - } - return 0; } +static void disable_comm (sdla_t *card) +{ + ppp_comm_disable_shutdown(card); + return; +} + /****** WANPIPE-specific entry points ***************************************/ /*============================================================================ @@ -534,6 +679,7 @@ ppp_mbox_t *mbox = card->mbox; int len; +#if defined(LINUX_2_1) || defined(LINUX_2_4) if (copy_from_user((void*)&mbox->cmd, u_cmd, sizeof(ppp_cmd_t))) return -EFAULT; @@ -558,6 +704,35 @@ if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)) return -EFAULT; +#else + + if (!u_cmd || verify_area(VERIFY_WRITE, u_cmd, sizeof(ppp_cmd_t))) + return -EFAULT; + + memcpy_fromfs((void*)&mbox->cmd, u_cmd, sizeof(ppp_cmd_t)); + + len = mbox->cmd.length; + + if (len) { + + if (!u_data || verify_area(VERIFY_READ, u_data, len)) + return -EFAULT; + } + + /* execute command */ + if (!sdla_exec(mbox)) + return -EIO; + + /* return result */ + memcpy_tofs(u_cmd, (void*)&mbox->cmd, sizeof(ppp_cmd_t)); + len = mbox->cmd.length; + + if (len && u_data && !verify_area(VERIFY_WRITE, u_data, len)) + memcpy_tofs(u_data, (void*)&mbox->data, len); + + +#endif + return 0; } @@ -570,12 +745,12 @@ * interface registration. Returning anything but zero will fail interface * registration. */ -static int if_init(struct net_device *dev) +static int if_init(netdevice_t *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; wan_device_t *wandev = &card->wandev; -#ifndef LINUX_2_1 +#ifdef LINUX_2_0 int i; #endif @@ -586,19 +761,22 @@ dev->rebuild_header = &if_rebuild_hdr; dev->hard_start_xmit = &if_send; dev->get_stats = &if_stats; +#ifdef LINUX_2_4 dev->tx_timeout = &if_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#endif /* Initialize media-specific parameters */ dev->type = ARPHRD_PPP; /* ARP h/w type */ - dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; /* Enable Mulitcasting if specified by user*/ if (ppp_priv_area->mc == WANOPT_YES){ - dev->flags |= IFF_MULTICAST; + dev->flags |= IFF_MULTICAST; } -#ifndef LINUX_2_1 +#ifdef LINUX_2_0 dev->family = AF_INET; #endif dev->mtu = wandev->mtu; @@ -615,7 +793,13 @@ dev->tx_queue_len = 100; /* Initialize socket buffers */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) dev_init_buffers(dev); +#else + for (i = 0; i < DEV_NUMBUFFS; ++i) + skb_queue_head_init(&dev->buffs[i]); + #endif + return 0; } @@ -626,105 +810,44 @@ * * Return 0 if O.k. or errno. */ -static int if_open(struct net_device *dev) +static int if_open (netdevice_t *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; - ppp_flags_t *flags = card->flags; struct timeval tv; - int err = 0; - - if (netif_running(dev)) - return -EBUSY; /* only one open is allowed */ - - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - return -EAGAIN; - - if (!card->configured){ - - if (config508(ppp_priv_area, card)){ - - err = -EIO; - card->wandev.critical = 0; - return err; - } - - Intr_test_counter = 0; - err = intr_test( card ); - - if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { - printk("%s: Interrupt Test Failed, Counter: %i\n", - card->devname, Intr_test_counter); - printk( "%s: Please choose another interrupt\n",card->devname); - err = -EIO; - card->wandev.critical = 0; - return err; - } - - printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", - card->devname, Intr_test_counter); - card->configured = 1; - - } - - /* Initialize Rx/Tx buffer control fields */ - init_ppp_tx_rx_buff( card ); - - if (ppp_set_intr_mode(card, PPP_INTR_RXRDY| - PPP_INTR_TXRDY| - PPP_INTR_MODEM| - PPP_INTR_CMD | - PPP_INTR_DISC | - PPP_INTR_OPEN | - PPP_INTR_DROP_DTR | - PPP_INTR_TIMER)) { - - err = -EIO; - card->wandev.critical = 0; - return err; - - } + //unsigned long smp_flags; - /* Turn off the transmit and timer interrupt */ - flags->imask &= ~(PPP_INTR_TXRDY | PPP_INTR_TIMER) ; + if (is_dev_running(dev)) + return -EBUSY; - /* If you are not the authenticator and any one of the protocol is - * enabled then we call the set_out_bound_authentication. - */ - if ( !card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) { - if ( ppp_set_outbnd_auth(card, ppp_priv_area) ){ - err = -EIO; - card->wandev.critical = 0; - return err; - } - } - - /* If you are the authenticator and any one of the protocol is enabled - * then we call the set_in_bound_authentication. - */ - if ( card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) { - if ( ppp_set_inbnd_auth(card, ppp_priv_area) ){ - err = -EIO; - card->wandev.critical = 0; - return err; - } - } + wanpipe_open(card); - if (ppp_comm_enable(card)) { - err = -EIO; - card->wandev.critical = 0; - return err; - } +#ifdef LINUX_2_4 + netif_start_queue(dev); +#else + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; +#endif - wanpipe_set_state(card, WAN_CONNECTING); - wanpipe_open(card); - dev->mtu = min(dev->mtu, card->wandev.mtu); - netif_start_queue(dev); do_gettimeofday( &tv ); ppp_priv_area->router_start_time = tv.tv_sec; - card->wandev.critical = 0; - return err; + /* We cannot configure the card here because we don't + * have access to the interface IP addresses. + * Once the interface initilization is complete, we will be + * able to access the IP addresses. Therefore, + * configure the ppp link in the poll routine */ + set_bit(0,&ppp_priv_area->config_ppp); + ppp_priv_area->config_wait_timeout=jiffies; + + /* Start the PPP configuration after 1sec delay. + * This will give the interface initilization time + * to finish its configuration */ + del_timer(&ppp_priv_area->poll_delay_timer); + ppp_priv_area->poll_delay_timer.expires = jiffies+HZ; + add_timer(&ppp_priv_area->poll_delay_timer); + return 0; } /*============================================================================ @@ -732,20 +855,18 @@ * o if this is the last open, then disable communications and interrupts. * o reset flags. */ -static int if_close(struct net_device *dev) +static int if_close(netdevice_t *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - return -EAGAIN; - - netif_stop_queue(dev); + stop_net_queue(dev); +#ifndef LINUX_2_4 + dev->start=0; +#endif wanpipe_close(card); - wanpipe_set_state(card, WAN_DISCONNECTED); - ppp_set_intr_mode(card, 0); - ppp_comm_disable(card); - card->wandev.critical = 0; + + del_timer (&ppp_priv_area->poll_delay_timer); return 0; } @@ -758,13 +879,12 @@ * * Return: media header length. */ -static int if_header(struct sk_buff *skb, struct net_device *dev, +static int if_header(struct sk_buff *skb, netdevice_t *dev, unsigned short type, void *daddr, void *saddr, unsigned len) { switch (type) { case ETH_P_IP: - case ETH_P_IPX: skb->protocol = htons(type); break; @@ -782,10 +902,10 @@ * Return: 1 physical address resolved. * 0 physical address not resolved */ - +#if defined(LINUX_2_1) || defined(LINUX_2_4) static int if_rebuild_hdr (struct sk_buff *skb) { - struct net_device *dev = skb->dev; + netdevice_t *dev = skb->dev; ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; @@ -794,33 +914,39 @@ return 1; } +#else +static int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr, + struct sk_buff* skb) +{ + return 1; + +} +#endif +#ifdef LINUX_2_4 /*============================================================================ - * Handle transmit timeout from netif watchdog + * Handle transmit timeout event from netif watchdog */ -static void if_tx_timeout (struct net_device *dev) +static void if_tx_timeout (netdevice_t *dev) { - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - - + ppp_private_area_t* chan = dev->priv; + sdla_t *card = chan->card; + /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this - * is only used as a last resort. + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. */ - ++ppp_priv_area->if_send_stat.if_send_tbusy; + ++ chan->if_send_stat.if_send_tbusy; ++card->wandev.stats.collisions; - printk (KERN_INFO "%s: Transmit times out\n", card->devname); - - ++ppp_priv_area->if_send_stat.if_send_tbusy_timeout; - ++card->wandev.stats.collisions; - - /* unbusy the card (because only one interface per card) */ - netif_wake_queue(dev); + printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); + ++chan->if_send_stat.if_send_tbusy_timeout; + netif_wake_queue (dev); } +#endif + /*============================================================================ @@ -840,19 +966,22 @@ * 2. Setting tbusy flag will inhibit further transmit requests from the * protocol stack and can be used for flow control with protocol layer. */ -static int if_send (struct sk_buff *skb, struct net_device *dev) +static int if_send (struct sk_buff *skb, netdevice_t *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; unsigned char *sendpacket; unsigned long smp_flags; ppp_flags_t *flags = card->flags; - int retry = 0; int udp_type; - + int err=0; ++ppp_priv_area->if_send_stat.if_send_entry; +#ifdef LINUX_2_4 + netif_stop_queue(dev); +#endif + if (skb == NULL) { /* If we get here, some higher layer thinks we've missed an @@ -862,12 +991,37 @@ card->devname, dev->name); ++ppp_priv_area->if_send_stat.if_send_skb_null; - - netif_wake_queue(dev); + + wake_net_dev(dev); return 0; - } +#ifndef LINUX_2_4 + if (dev->tbusy) { + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++ppp_priv_area->if_send_stat.if_send_tbusy; + ++card->wandev.stats.collisions; + + if ((jiffies - ppp_priv_area->tick_counter) < (5*HZ)) { + return 1; + } + + printk (KERN_INFO "%s: Transmit times out on %s\n",card->devname,dev->name); + + ++ppp_priv_area->if_send_stat.if_send_tbusy_timeout; + ++card->wandev.stats.collisions; + + /* unbusy the card (because only one interface per card)*/ + dev->tbusy = 0; + } +#endif + sendpacket = skb->data; udp_type = udp_pkt_type( skb, card ); @@ -879,15 +1033,18 @@ flags->imask |= PPP_INTR_TIMER; } ++ppp_priv_area->if_send_stat.if_send_PIPE_request; + start_net_queue(dev); return 0; - } /* Check for broadcast and multicast addresses * If found, drop (deallocate) a packet and return. */ if(chk_bcast_mcast_addr(card, dev, skb)){ - return 0; + ++card->wandev.stats.tx_dropped; + wan_dev_kfree_skb(skb,FREE_WRITE); + start_net_queue(dev); + return 0; } @@ -895,31 +1052,28 @@ s508_lock(card,&smp_flags); } - if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { printk(KERN_INFO "%s: Critical in if_send: %lx\n", card->wandev.name,card->wandev.critical); - dev_kfree_skb(skb); - + ++card->wandev.stats.tx_dropped; ++ppp_priv_area->if_send_stat.if_send_critical_non_ISR; - - if(card->hw.type != SDLA_S514){ - s508_unlock(card,&smp_flags); - } - - return 0; + start_net_queue(dev); + goto if_send_exit_crit; } if (card->wandev.state != WAN_CONNECTED) { ++ppp_priv_area->if_send_stat.if_send_wan_disconnected; ++card->wandev.stats.tx_dropped; - + start_net_queue(dev); + } else if (!skb->protocol) { ++ppp_priv_area->if_send_stat.if_send_protocol_error; ++card->wandev.stats.tx_errors; - + start_net_queue(dev); + } else { /*If it's IPX change the network numbers to 0 if they're ours.*/ @@ -929,37 +1083,43 @@ ppp_priv_area->network_number, 0); } else { ++card->wandev.stats.tx_dropped; - goto tx_done; + start_net_queue(dev); + goto if_send_exit_crit; } } if (ppp_send(card, skb->data, skb->len, skb->protocol)) { - retry = 1; - netif_stop_queue(dev); + stop_net_queue(dev); ++ppp_priv_area->if_send_stat.if_send_adptr_bfrs_full; ++ppp_priv_area->if_send_stat.if_send_tx_int_enabled; - ppp_priv_area->tick_counter = jiffies; - flags->imask |= 0x02; /* unmask Tx interrupts */ } else { ++ppp_priv_area->if_send_stat.if_send_bfr_passed_to_adptr; ++card->wandev.stats.tx_packets; +#if defined(LINUX_2_1) || defined(LINUX_2_4) card->wandev.stats.tx_bytes += skb->len; +#endif + start_net_queue(dev); +#ifdef LINUX_2_4 + dev->trans_start = jiffies; +#endif } } -tx_done: - if (!retry){ - dev_kfree_skb(skb); +if_send_exit_crit: + + if (!(err=is_queue_stopped(dev))){ + wan_dev_kfree_skb(skb, FREE_WRITE); + }else{ + ppp_priv_area->tick_counter = jiffies; + flags->imask |= PPP_INTR_TXRDY; /* unmask Tx interrupts */ } - - card->wandev.critical = 0; + clear_bit(SEND_CRIT,&card->wandev.critical); if(card->hw.type != SDLA_S514){ s508_unlock(card,&smp_flags); } - - return retry; + return err; } @@ -968,7 +1128,7 @@ */ static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, + struct sk_buff *skb, netdevice_t* dev, ppp_private_area_t* ppp_priv_area ) { int udp_pkt_stored = 0; @@ -982,8 +1142,13 @@ udp_pkt_stored = 1; }else{ if (skb->len > MAX_LGTH_UDP_MGNT_PKT){ +#if defined(LINUX_2_1) || defined(LINUX_2_4) printk(KERN_INFO "%s: PIPEMON UDP request too long : %i\n", card->devname, skb->len); +#else + printk(KERN_INFO "%s: PIPEMON UDP request too long : %li\n", + card->devname, skb->len); +#endif }else{ printk(KERN_INFO "%s: PIPEMON UPD request already pending\n", card->devname); @@ -991,7 +1156,12 @@ ppp_priv_area->udp_pkt_lgth = 0; } - dev_kfree_skb(skb); + if(udp_pkt_src == UDP_PKT_FRM_STACK){ + wan_dev_kfree_skb(skb, FREE_WRITE); + }else{ + wan_dev_kfree_skb(skb, FREE_READ); + } + return(udp_pkt_stored); } @@ -1157,7 +1327,11 @@ * Get ethernet-style interface statistics. * Return a pointer to struct net_device_stats. */ -static struct net_device_stats *if_stats(struct net_device *dev) +#if defined(LINUX_2_1) || defined(LINUX_2_4) +static struct net_device_stats *if_stats(netdevice_t *dev) +#else +static struct enet_statistics *if_stats(netdevice_t *dev) +#endif { ppp_private_area_t *ppp_priv_area = dev->priv; @@ -1354,7 +1528,7 @@ /* If timer has been enabled, set the timer delay to 1sec */ if (mode & 0x80){ - ppp_intr_data->timer_len = 5;//100; //250; + ppp_intr_data->timer_len = 250; //5;//100; //250; mb->cmd.length = 4; } @@ -1382,7 +1556,9 @@ if (err != CMD_OK) ppp_error(card, err, mb); - + else + card->u.p.comm_enabled = 1; + return err; } @@ -1399,10 +1575,46 @@ err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; if (err != CMD_OK) ppp_error(card, err, mb); + else + card->u.p.comm_enabled = 0; return err; } +static int ppp_comm_disable_shutdown(sdla_t *card) +{ + ppp_mbox_t *mb = card->mbox; + ppp_intr_info_t *ppp_intr_data; + int err; + + if (!mb){ + return 1; + } + + ppp_intr_data = (ppp_intr_info_t *) &mb->data[0]; + + /* Disable all interrupts */ + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + ppp_intr_data->i_enable = 0; + + ppp_intr_data->irq = card->hw.irq; + mb->cmd.length = 2; + + mb->cmd.command = PPP_SET_INTR_FLAGS; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + + /* Disable communicatinons */ + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + mb->cmd.command = PPP_COMM_DISABLE; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + + card->u.p.comm_enabled = 0; + + return 0; +} + + + /*============================================================================ * Get communications error statistics. */ @@ -1495,36 +1707,40 @@ /*============================================================================ * PPP interrupt service routine. */ -STATIC void wpp_isr(sdla_t *card) +static void wpp_isr (sdla_t *card) { ppp_flags_t *flags = card->flags; char *ptr = &flags->iflag; - struct net_device *dev = card->wandev.dev; - - + netdevice_t *dev = card->wandev.dev; int i; card->in_isr = 1; - ++card->statistics.isr_entry; - //FIXME: Do we need this - card->force_enable_irq = 0; - + if (!dev && flags->iflag != PPP_INTR_CMD){ + card->in_isr = 0; + flags->iflag = 0; + return; + } + + if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { + card->in_isr = 0; + flags->iflag = 0; + return; + } + + if(card->hw.type != SDLA_S514){ - if (test_and_set_bit(0, (void*)&card->wandev.critical)) { - + if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { ++card->statistics.isr_already_critical; printk (KERN_INFO "%s: Critical while in ISR!\n", card->devname); card->in_isr = 0; + flags->iflag = 0; return; - } } - card->buff_int_mode_unbusy = 0; - switch (flags->iflag) { case PPP_INTR_RXRDY: /* receive interrupt 0x01 (bit 0)*/ @@ -1535,8 +1751,7 @@ case PPP_INTR_TXRDY: /* transmit interrupt 0x02 (bit 1)*/ ++card->statistics.isr_tx; flags->imask &= ~PPP_INTR_TXRDY; - netif_wake_queue (dev); - card->buff_int_mode_unbusy = 1; + wake_net_dev(dev); break; case PPP_INTR_CMD: /* interface command completed */ @@ -1567,10 +1782,7 @@ card->in_isr = 0; flags->iflag = 0; - card->wandev.critical = 0; - - if(card->buff_int_mode_unbusy) - netif_wake_queue(dev); + return; } /*============================================================================ @@ -1579,7 +1791,7 @@ static void rx_intr(sdla_t *card) { ppp_buf_ctl_t *rxbuf = card->rxmb; - struct net_device *dev = card->wandev.dev; + netdevice_t *dev = card->wandev.dev; ppp_private_area_t *ppp_priv_area; struct sk_buff *skb; unsigned len; @@ -1603,11 +1815,21 @@ printk(KERN_INFO "\n"); ++card->statistics.rx_intr_corrupt_rx_bfr; - return; - } - if (dev && netif_running(dev)) { + /* Bug Fix: Mar 6 2000 + * If we get a corrupted mailbox, it means that driver + * is out of sync with the firmware. There is no recovery. + * If we don't turn off all interrupts for this card + * the machine will crash. + */ + printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); + printk(KERN_INFO "Please contact Sangoma Technologies !\n"); + ppp_set_intr_mode(card,0); + return; + } + + if (dev && is_dev_running(dev) && dev->priv){ len = rxbuf->length; ppp_priv_area = dev->priv; @@ -1662,9 +1884,12 @@ /* Handle an IPXWAN packet */ if( ppp_priv_area->enable_IPX) { - ppp_send(card, skb->data, skb->len, htons(ETH_P_IPX)); - dev_kfree_skb(skb); - + + /* Make sure we are not already sending */ + if (!test_bit(SEND_CRIT, &card->wandev.critical)){ + ppp_send(card, skb->data, skb->len, htons(ETH_P_IPX)); + } + wan_dev_kfree_skb(skb,FREE_READ); } else { ++card->wandev.stats.rx_dropped; @@ -1675,15 +1900,19 @@ skb->mac.raw = skb->data; ++card->wandev.stats.rx_packets; +#if defined(LINUX_2_1) || defined(LINUX_2_4) card->wandev.stats.rx_bytes += skb->len; +#endif ++ppp_priv_area->rx_intr_stat.rx_intr_bfr_passed_to_stack; netif_rx(skb); } } else { - - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); + + if (net_ratelimit()){ + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + } ++card->wandev.stats.rx_dropped; ++ppp_priv_area->rx_intr_stat.rx_intr_no_socket; } @@ -1703,16 +1932,18 @@ void event_intr (sdla_t *card) { - struct net_device* dev = card->wandev.dev; + netdevice_t* dev = card->wandev.dev; ppp_private_area_t* ppp_priv_area = dev->priv; volatile ppp_flags_t *flags = card->flags; switch (flags->iflag){ case PPP_INTR_MODEM: /* modem status change (DCD, CTS) 0x04 (bit 2)*/ - printk (KERN_INFO "%s: Modem status: DCD=%s CTS=%s\n", - card->devname, DCD(flags->mstatus), CTS(flags->mstatus)); + if (net_ratelimit()){ + printk (KERN_INFO "%s: Modem status: DCD=%s CTS=%s\n", + card->devname, DCD(flags->mstatus), CTS(flags->mstatus)); + } break; case PPP_INTR_DISC: /* Data link disconnected 0x10 (bit 4)*/ @@ -1723,15 +1954,16 @@ if (flags->disc_cause & (PPP_LOCAL_TERMINATION | PPP_DCD_CTS_DROP | PPP_REMOTE_TERMINATION)) { + if (card->u.p.ip_mode == WANOPT_PPP_PEER) { - Read_connection_info = 1; - remove_route (card); + set_bit(0,&Read_connection_info); } wanpipe_set_state(card, WAN_DISCONNECTED); + show_disc_cause(card, flags->disc_cause); - ppp_priv_area->timer_int_enabled |= - TMR_INT_ENABLED_PPP_EVENT; + ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; flags->imask |= PPP_INTR_TIMER; + trigger_ppp_poll(dev); } break; @@ -1743,30 +1975,68 @@ if (flags->lcp_state == 0x09 && (flags->ip_state == 0x09 || flags->ipx_state == 0x09)){ + /* Initialize the polling timer and set the state - * to WAN_CONNNECTED - */ - card->state_tick = jiffies; - wanpipe_set_state(card, WAN_CONNECTED); - ppp_priv_area->timer_int_enabled |= + * to WAN_CONNNECTED */ + + + /* BUG FIX: When the protocol restarts, during heavy + * traffic, board tx buffers and driver tx buffers + * can go out of sync. This checks the condition + * and if the tx buffers are out of sync, the + * protocols are restarted. + * I don't know why the board tx buffer is out + * of sync. It could be that a packets is tx + * while the link is down, but that is not + * possible. The other possiblility is that the + * firmware doesn't reinitialize properly. + * FIXME: A better fix should be found. + */ + if (detect_and_fix_tx_bug(card)){ + + ppp_comm_disable(card); + + wanpipe_set_state(card, WAN_DISCONNECTED); + + ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; + flags->imask |= PPP_INTR_TIMER; + break; + } + + card->state_tick = jiffies; + wanpipe_set_state(card, WAN_CONNECTED); + + NEX_PRINTK(KERN_INFO "CON: L Tx: %lx B Tx: %lx || L Rx %lx B Rx %lx\n", + (unsigned long)card->u.p.txbuf, *card->u.p.txbuf_next, + (unsigned long)card->rxmb, *card->u.p.rxbuf_next); + + /* Tell timer interrupt that PPP event occured */ + ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; flags->imask |= PPP_INTR_TIMER; + /* If we are in PEER mode, we must first obtain the + * IP information and then go into the poll routine */ + if (card->u.p.ip_mode != WANOPT_PPP_PEER){ + trigger_ppp_poll(dev); + } } break; case PPP_INTR_DROP_DTR: /* DTR drop timeout expired 0x40 bit 6 */ NEX_PRINTK(KERN_INFO "DTR Drop Timeout Interrrupt \n"); + if (card->u.p.ip_mode == WANOPT_PPP_PEER) { - Read_connection_info = 1; - remove_route (card); + set_bit(0,&Read_connection_info); } + wanpipe_set_state(card, WAN_DISCONNECTED); + show_disc_cause(card, flags->disc_cause); - ppp_priv_area->timer_int_enabled |= - TMR_INT_ENABLED_PPP_EVENT; + ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; flags->imask |= PPP_INTR_TIMER; + trigger_ppp_poll(dev); break; default: @@ -1781,10 +2051,18 @@ void timer_intr (sdla_t *card) { - struct net_device* dev = card->wandev.dev; + netdevice_t* dev = card->wandev.dev; ppp_private_area_t* ppp_priv_area = dev->priv; ppp_flags_t *flags = card->flags; + + if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG){ + if (!config_ppp(card)){ + ppp_priv_area->timer_int_enabled &= + ~TMR_INT_ENABLED_CONFIG; + } + } + /* Update statistics */ if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE){ ppp_get_err_stats(card); @@ -1801,12 +2079,11 @@ ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; } - /* PPP Event */ if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_PPP_EVENT){ if (card->wandev.state == WAN_DISCONNECTED){ - poll_disconnected(card); + retrigger_comm(card); } /* If the state is CONNECTING, it means that communicatins were @@ -1823,21 +2100,22 @@ * poll for an IP address which will be provided by remote end. */ else if ((card->wandev.state == WAN_CONNECTED && - card->u.p.ip_mode == WANOPT_PPP_PEER) && - Read_connection_info){ + card->u.p.ip_mode == WANOPT_PPP_PEER) && + test_bit(0,&Read_connection_info)){ card->state_tick = jiffies; - if (!read_connection_info (card)){ - card->poll = &process_route; + if (read_connection_info (card)){ + printk(KERN_INFO "%s: Failed to read PEER IP Addresses\n", + card->devname); + }else{ + clear_bit(0,&Read_connection_info); + set_bit(1,&Read_connection_info); + trigger_ppp_poll(dev); } - }else{ - /* If we are using Static IP,no need to poll for - * an IP address. - */ - NEX_PRINTK(KERN_INFO "Turning off TIMER \n"); + //FIXME Put the comment back int ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT; - } + } }/* End of PPP_EVENT */ @@ -1970,32 +2248,62 @@ static void process_route (sdla_t *card) { ppp_flags_t *flags = card->flags; - struct net_device *dev = card->wandev.dev; - struct in_device *in_dev = dev->ip_ptr; + netdevice_t *dev = card->wandev.dev; + ppp_private_area_t *ppp_priv_area = dev->priv; - if (in_dev != NULL ) { - if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && - (Read_connection_info && flags->ip_state == 0x09)){ - - printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname); - if (read_info( card )) { - printk(KERN_INFO - "%s: An error occurred in IP assignment.\n", - card->devname); - } else { +#if defined(LINUX_2_1) || defined(LINUX_2_4) + + if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && + (flags->ip_state == 0x09)){ + + /* We get ip_local from the firmware in PEER mode. + * Therefore, if ip_local is 0, we failed to obtain + * the remote IP address. */ + if (ppp_priv_area->ip_local == 0) + return; + + printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname); + if (read_info( card )) { + printk(KERN_INFO + "%s: An error occurred in IP assignment.\n", + card->devname); + } else { + struct in_device *in_dev = dev->ip_ptr; + if (in_dev != NULL ) { struct in_ifaddr *ifa = in_dev->ifa_list; printk(KERN_INFO "%s: Assigned Lcl. Addr: %s\n", - card->devname, in_ntoa(ifa->ifa_local)); + card->devname, in_ntoa(ifa->ifa_local)); printk(KERN_INFO "%s: Assigned Rmt. Addr: %s\n", card->devname, in_ntoa(ifa->ifa_address)); + }else{ + printk(KERN_INFO + "%s: Error: Failed to add a route for PPP interface %s\n", + card->devname,dev->name); } - Read_connection_info = 0; } - }else{ - printk(KERN_INFO "%s: Error: Null pointer in Poll Active\n", + } +#else + + if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && + (flags->ip_state == 0x09)){ + + if (ppp_priv_area->ip_local == 0) + return; + + printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname); + if (read_info( card )) { + printk(KERN_INFO + "%s: An error occurred in IP assignment.\n", card->devname); + } else { + printk(KERN_INFO "%s: Assigned Lcl. Addr: %s\n", + card->devname, in_ntoa(dev->pa_addr)); + printk(KERN_INFO "%s: Assigned Rmt. Addr: %s\n", + card->devname, in_ntoa(dev->pa_dstaddr)); + } } - card->poll = NULL; + +#endif } @@ -2004,19 +2312,17 @@ * o if interface is up and the hold-down timeout has expired, then retry * connection. */ -static void poll_disconnected(sdla_t *card) +static void retrigger_comm(sdla_t *card) { - struct net_device *dev = card->wandev.dev; + netdevice_t *dev = card->wandev.dev; + + if (dev && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) { - if (dev && netif_running(dev) && - ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) { - wanpipe_set_state(card, WAN_CONNECTING); - + if(ppp_comm_enable(card) == CMD_OK){ init_ppp_tx_rx_buff( card ); } - } } @@ -2025,12 +2331,14 @@ /*============================================================================ * Configure S508 adapter. */ -static int config508(ppp_private_area_t *ppp_priv_area, sdla_t *card) +static int config508(netdevice_t *dev, sdla_t *card) { ppp508_conf_t cfg; - struct net_device *dev = card->wandev.dev; +#if defined(LINUX_2_1) || defined(LINUX_2_4) struct in_device *in_dev = dev->ip_ptr; - +#endif + ppp_private_area_t *ppp_priv_area = dev->priv; + /* Prepare PPP configuration structure */ memset(&cfg, 0, sizeof(ppp508_conf_t)); @@ -2040,6 +2348,7 @@ if (card->wandev.interface == WANOPT_RS232) cfg.conf_flags |= INTERFACE_LEVEL_RS232; + cfg.conf_flags |= DONT_TERMINATE_LNK_MAX_CONFIG; /*send Configure-Request packets forever*/ cfg.txbuf_percent = PERCENT_TX_BUFF; /* % of Tx bufs */ cfg.mtu_local = card->wandev.mtu; @@ -2065,6 +2374,7 @@ card->devname); cfg.auth_options = INBOUND_AUTH; } + if( ppp_priv_area->pap == WANOPT_YES){ cfg.auth_options |=PAP_AUTH; printk(KERN_INFO "%s: Pap enabled\n", card->devname); @@ -2076,6 +2386,7 @@ if (ppp_priv_area->enable_IPX == WANOPT_YES){ + printk(KERN_INFO "%s: Enabling IPX Protocol\n",card->devname); cfg.ipx_options = ENABLE_IPX | ROUTING_PROT_DEFAULT; }else{ cfg.ipx_options = DISABLE_IPX; @@ -2085,25 +2396,92 @@ case WANOPT_PPP_STATIC: + printk(KERN_INFO "%s: PPP IP Mode: STATIC\n",card->devname); cfg.ip_options = L_AND_R_IP_NO_ASSIG | ENABLE_IP; +#if defined(LINUX_2_1) || defined(LINUX_2_4) cfg.ip_local = in_dev->ifa_list->ifa_local; cfg.ip_remote = in_dev->ifa_list->ifa_address; +#else + cfg.ip_local = dev->pa_addr; + cfg.ip_remote = dev->pa_dstaddr; +#endif + + /* Debugging code used to check that IP addresses + * obtained from the kernel are correct */ + + { + char laddr[20]; + char raddr[20]; + strcpy(laddr,in_ntoa(cfg.ip_local)); + strcpy(raddr,in_ntoa(cfg.ip_remote)); + NEX_PRINTK(KERN_INFO "Local %s Remote %s Name %s\n", - in_ntoa(cfg.ip_local), - in_ntoa(cfg.ip_remote), - dev->name); + laddr,raddr, dev->name); + + } + break; + + case WANOPT_PPP_HOST: + + printk(KERN_INFO "%s: PPP IP Mode: HOST\n",card->devname); + cfg.ip_options = L_IP_LOCAL_ASSIG | + R_IP_LOCAL_ASSIG | + ENABLE_IP; +#if defined(LINUX_2_1) || defined(LINUX_2_4) + cfg.ip_local = in_dev->ifa_list->ifa_local; + cfg.ip_remote = in_dev->ifa_list->ifa_address; +#else + cfg.ip_local = dev->pa_addr; + cfg.ip_remote = dev->pa_dstaddr; +#endif + + /* Debugging code used to check that IP addresses + * obtained from the kernel are correct */ + { + char laddr[20]; + char raddr[20]; + strcpy(laddr,in_ntoa(cfg.ip_local)); + strcpy(raddr,in_ntoa(cfg.ip_remote)); + + NEX_PRINTK (KERN_INFO "Local %s Remote %s Name %s\n", + laddr,raddr, dev->name); + + } + + break; case WANOPT_PPP_PEER: + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + + printk(KERN_INFO "%s: PPP IP Mode: PEER\n",card->devname); cfg.ip_options = L_IP_REMOTE_ASSIG | R_IP_REMOTE_ASSIG | ENABLE_IP; cfg.ip_local = 0x00; cfg.ip_remote = 0x00; break; - + +#else + + /* No PEER support for 2.0.X kernels, drop down to default + * condition */ + + printk(KERN_INFO "%s: ERROR, PEER mode is not supported in 2.0.X kernels\n", + card->devname); + +#endif + + default: + printk(KERN_INFO "%s: ERROR: Unsuported PPP Mode Selected\n", + card->devname); + printk(KERN_INFO "%s: PPP IP Modes: STATIC, PEER or HOST\n", + card->devname); + return 1; } + return ppp_configure(card, &cfg); } @@ -2168,7 +2546,7 @@ /*============================================================================= * Process UDP call of type PTPIPEAB. */ -static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, +static void process_udp_mgmt_pkt(sdla_t *card, netdevice_t *dev, ppp_private_area_t *ppp_priv_area ) { unsigned char buf2[5]; @@ -2186,33 +2564,31 @@ memcpy(&buf2, &card->wandev.udp_port, 2 ); - switch(ppp_udp_pkt->cblock.command) { + if(ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { - /* FT1 MONITOR STATUS */ - case FT1_MONITOR_STATUS_CTRL: - - /* PPIPE_ENABLE_TRACING */ - case PPIPE_ENABLE_TRACING: - - /* PPIPE_DISABLE_TRACING */ - case PPIPE_DISABLE_TRACING: - - /* PPIPE_GET_TRACE_INFO */ - case PPIPE_GET_TRACE_INFO: - - /* SET FT1 MODE */ - case SET_FT1_MODE: - if(ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - ++ppp_priv_area->pipe_mgmt_stat. - UDP_PIPE_mgmt_direction_err; + switch(ppp_udp_pkt->cblock.command) { + + case PPIPE_GET_IBA_DATA: + case PPP_READ_CONFIG: + case PPP_GET_CONNECTION_INFO: + case PPIPE_ROUTER_UP_TIME: + case PPP_READ_STATISTICS: + case PPP_READ_ERROR_STATS: + case PPP_READ_PACKET_STATS: + case PPP_READ_LCP_STATS: + case PPP_READ_IPCP_STATS: + case PPP_READ_IPXCP_STATS: + case PPP_READ_PAP_STATS: + case PPP_READ_CHAP_STATS: + case PPP_READ_CODE_VERSION: + udp_mgmt_req_valid = 1; + break; + + default: udp_mgmt_req_valid = 0; - } - break; - - default: - break; - } + break; + } + } if(!udp_mgmt_req_valid) { @@ -2221,7 +2597,13 @@ /* set return code */ ppp_udp_pkt->cblock.result = 0xCD; - + ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err; + + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,ppp_udp_pkt->cblock.command); + } } else { /* Initialize the trace element */ trace_element_t trace_element; @@ -2422,27 +2804,24 @@ /* set return code */ ppp_udp_pkt->cblock.result = 0x00; - - break; - - /* PPIPE_KILL_BOARD */ - case PPIPE_KILL_BOARD: + ppp_udp_pkt->cblock.result = 0; break; /* PPIPE_FT1_READ_STATUS */ case PPIPE_FT1_READ_STATUS: - sdla_peek(&card->hw, 0xF020, &ppp_udp_pkt->data, 2); - ppp_udp_pkt->cblock.length = 2; + sdla_peek(&card->hw, 0xF020, &ppp_udp_pkt->data[0], 2); + ppp_udp_pkt->cblock.length = mbox->cmd.length = 2; ppp_udp_pkt->cblock.result = 0; - mbox->cmd.length = 2; break; case PPIPE_FLUSH_DRIVER_STATS: init_ppp_priv_struct( ppp_priv_area ); init_global_statistics( card ); mbox->cmd.length = 0; + ppp_udp_pkt->cblock.result = 0; break; + case PPIPE_ROUTER_UP_TIME: do_gettimeofday( &tv ); @@ -2450,34 +2829,11 @@ ppp_priv_area->router_start_time; *(unsigned long *)&ppp_udp_pkt->data = ppp_priv_area->router_up_time; mbox->cmd.length = 4; + ppp_udp_pkt->cblock.result = 0; break; - /* FT1 MONITOR STATUS */ - case FT1_MONITOR_STATUS_CTRL: - - /* Enable FT1 MONITOR STATUS */ - if( ppp_udp_pkt->data[0] == 1) { - - if( rCount++ != 0 ) { - ppp_udp_pkt->cblock.result = 0; - mbox->cmd.length = 1; - break; - } - } - - /* Disable FT1 MONITOR STATUS */ - if( ppp_udp_pkt->data[0] == 0) { - - if( --rCount != 0) { - ppp_udp_pkt->cblock.result = 0; - mbox->cmd.length = 1; - break; - } - } - - /* PPIPE_DRIVER_STATISTICS */ + /* PPIPE_DRIVER_STATISTICS */ case PPIPE_DRIVER_STAT_IFSEND: - printk(KERN_INFO "Getting IF_SEND Drivers Statistics\n"); memcpy(&ppp_udp_pkt->data, &ppp_priv_area->if_send_stat, sizeof(if_send_stat_t)); @@ -2515,8 +2871,38 @@ mbox->cmd.length = ppp_udp_pkt->cblock.length; break; + + /* FT1 MONITOR STATUS */ + case FT1_MONITOR_STATUS_CTRL: + /* Enable FT1 MONITOR STATUS */ + if( ppp_udp_pkt->data[0] == 1) { + + if( rCount++ != 0 ) { + ppp_udp_pkt->cblock.result = 0; + mbox->cmd.length = 1; + break; + } + } + + /* Disable FT1 MONITOR STATUS */ + if( ppp_udp_pkt->data[0] == 0) { + + if( --rCount != 0) { + ppp_udp_pkt->cblock.result = 0; + mbox->cmd.length = 1; + break; + } + } + goto udp_dflt_cmd; + + /* WARNING: FIXME: This should be fixed. + * The FT1 Status Ctrl doesn't have a break + * statment. Thus, no code must be inserted + * HERE: between default and above case statement */ + default: +udp_dflt_cmd: /* it's a board command */ mbox->cmd.command = ppp_udp_pkt->cblock.command; @@ -2555,9 +2941,12 @@ len = reply_udp(ppp_priv_area->udp_pkt_data, mbox->cmd.length); if (ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_adptr; - ppp_send(card,ppp_priv_area->udp_pkt_data,len,ppp_priv_area->protocol); + + /* Make sure we are not already sending */ + if (!test_bit(SEND_CRIT,&card->wandev.critical)){ + ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_adptr; + ppp_send(card,ppp_priv_area->udp_pkt_data,len,ppp_priv_area->protocol); + } } else { @@ -2587,6 +2976,8 @@ } ppp_priv_area->udp_pkt_lgth = 0; + + return; } /*============================================================================= @@ -2648,9 +3039,12 @@ (info->rxb_num - 1); } + card->u.p.txbuf_next = (unsigned long*)&info->txb_nxt; + card->u.p.rxbuf_next = (unsigned long*)&info->rxb1_ptr; + card->u.p.rx_base = info->rxb_base; card->u.p.rx_top = info->rxb_end; - + card->u.p.txbuf = card->u.p.txbuf_base; card->rxmb = card->u.p.rxbuf_base; @@ -2662,21 +3056,32 @@ */ static int read_info( sdla_t *card ) { - struct net_device *dev = card->wandev.dev; + netdevice_t *dev = card->wandev.dev; ppp_private_area_t *ppp_priv_area = dev->priv; int err; + +#if defined(LINUX_2_1) || defined(LINUX_2_4) struct ifreq if_info; struct sockaddr_in *if_data1, *if_data2; mm_segment_t fs; +#else +#ifdef _DYNAMIC_ROUTE_20X_SUPPORT_ + struct rtentry route; +#endif +#endif + + + +#if defined(LINUX_2_1) || defined(LINUX_2_4) /* Set Local and remote addresses */ memset(&if_info, 0, sizeof(if_info)); strcpy(if_info.ifr_name, dev->name); + fs = get_fs(); set_fs(get_ds()); /* get user space block */ - /* Change the local and remote ip address of the interface. * This will also add in the destination route. */ @@ -2690,11 +3095,43 @@ err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); set_fs(fs); /* restore old block */ + +#else + /* FIXME: Dynamic Routing in 2.0.X kernels is not + * supported. Sorry ! I'll come back to it when I get + * a chance. */ + + printk(KERN_INFO "%s: ERROR, Dynamic routing is not supported in 2.0.X kernels\n", + card->devname); + printk(KERN_INFO "%s: Please use the STATIC IP mode!\n", + card->devname); + + err = 0; + +#ifdef _DYNAMIC_ROUTE_20X_SUPPORT_ + dev->pa_dstaddr = ppp_priv_area->ip_remote; + dev->pa_addr = ppp_priv_area->ip_local; + + memset(&route, 0, sizeof(route)); + route.rt_dev = dev->name; + route.rt_flags = 0; + ((struct sockaddr_in *)&(route.rt_dst))->sin_addr.s_addr = + dev->pa_dstaddr; + ((struct sockaddr_in *)&(route.rt_dst))->sin_family = AF_INET; + ((struct sockaddr_in *)&(route.rt_genmask))->sin_addr.s_addr = + 0xFFFFFFFF; + ((struct sockaddr_in *)&(route.rt_genmask))->sin_family = + AF_INET; + + err = ip_rt_new(&route); + +#endif +#endif if (err) { - printk (KERN_INFO "%s: Adding of route failed:\n", - card->devname); + printk (KERN_INFO "%s: Adding of route failed: %i\n", + card->devname,err); printk (KERN_INFO "%s: Local : %s\n", card->devname,in_ntoa(ppp_priv_area->ip_local)); printk (KERN_INFO "%s: Remote: %s\n", @@ -2708,31 +3145,39 @@ * Called when ppp interface disconnected. */ -static int remove_route( sdla_t *card ) +static void remove_route( sdla_t *card ) { - struct net_device *dev = card->wandev.dev; + netdevice_t *dev = card->wandev.dev; long ip_addr; int err; +#if defined(LINUX_2_1) || defined(LINUX_2_4) mm_segment_t fs; struct ifreq if_info; struct sockaddr_in *if_data1; struct in_device *in_dev = dev->ip_ptr; struct in_ifaddr *ifa = in_dev->ifa_list; +#else + unsigned long fs = 0; + struct rtentry route; +#endif +#if defined(LINUX_2_1) || defined(LINUX_2_4) ip_addr = ifa->ifa_local; /* Set Local and remote addresses */ memset(&if_info, 0, sizeof(if_info)); strcpy(if_info.ifr_name, dev->name); +#endif fs = get_fs(); set_fs(get_ds()); /* get user space block */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) /* Change the local ip address of the interface to 0. * This will also delete the destination route. */ @@ -2740,6 +3185,26 @@ if_data1->sin_addr.s_addr = 0; if_data1->sin_family = AF_INET; err = devinet_ioctl( SIOCSIFADDR, &if_info ); +#else + + ip_addr = dev->pa_addr; + dev->pa_dstaddr = 0; + + memset(&route, 0, sizeof(route)); + route.rt_dev = dev->name; + route.rt_flags = 0; + ((struct sockaddr_in *)&(route.rt_dst))->sin_addr.s_addr = + dev->pa_dstaddr; + ((struct sockaddr_in *)&(route.rt_dst))->sin_family = AF_INET; + ((struct sockaddr_in *)&(route.rt_genmask))->sin_addr.s_addr = + 0xFFFFFFFF; + ((struct sockaddr_in *)&(route.rt_genmask))->sin_family = + AF_INET; + + + err = ip_rt_kill(&route); + +#endif set_fs(fs); /* restore old block */ @@ -2747,13 +3212,12 @@ if (err) { printk (KERN_INFO "%s: Deleting dynamic route failed %d!\n", card->devname, err); - return err; - }else - printk (KERN_INFO "%s: PPP Deleting dynamic route %s successfully\n", + return; + }else{ + printk (KERN_INFO "%s: PPP Deleting dynamic route %s successfuly\n", card->devname, in_ntoa(ip_addr)); - - - return 0; + } + return; } /*============================================================================= @@ -2765,13 +3229,6 @@ ppp_mbox_t *mb = card->mbox; int err,i; - /* The critical flag is unset because during intialization (if_open) - * we want the interrupts to be enabled so that when the wpp_isr is - * called it does not exit due to critical flag set. - */ - - card->wandev.critical = 0; - err = ppp_set_intr_mode( card, 0x08 ); if (err == CMD_OK) { @@ -2792,7 +3249,6 @@ if (err != CMD_OK) return err; - card->wandev.critical = 1; return 0; } @@ -2803,7 +3259,6 @@ { unsigned char *sendpacket; unsigned char buf2[5]; - //FIXME: Use the structure ppp_udp_pkt_t *ppp_udp_pkt = (ppp_udp_pkt_t *)skb->data; sendpacket = skb->data; @@ -2850,16 +3305,19 @@ * multicast source IP address. */ -static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, +static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev, struct sk_buff *skb) { u32 src_ip_addr; u32 broadcast_ip_addr = 0; +#if defined(LINUX_2_1) || defined(LINUX_2_4) struct in_device *in_dev; +#endif /* read the IP source address from the outgoing packet */ src_ip_addr = *(u32 *)(skb->data + 12); /* read the IP broadcast address for the device */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) in_dev = dev->ip_ptr; if(in_dev != NULL) { struct in_ifaddr *ifa= in_dev->ifa_list; @@ -2868,13 +3326,14 @@ else return 0; } +#else + broadcast_ip_addr = dev->pa_brdaddr; +#endif /* check if the IP Source Address is a Broadcast address */ if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", card->devname); - dev_kfree_skb(skb); - ++card->wandev.stats.tx_dropped; return 1; } @@ -2883,8 +3342,6 @@ (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", card->devname); - dev_kfree_skb(skb); - ++card->wandev.stats.tx_dropped; return 1; } @@ -2893,8 +3350,8 @@ void s508_lock (sdla_t *card, unsigned long *smp_flags) { -#ifdef CONFIG_SMP - spin_lock_irqsave(&card->lock, *smp_flags); +#if defined(__SMP__) || defined(LINUX_2_4) + spin_lock_irqsave(&card->wandev.lock, *smp_flags); #else disable_irq(card->hw.irq); #endif @@ -2902,8 +3359,8 @@ void s508_unlock (sdla_t *card, unsigned long *smp_flags) { -#ifdef CONFIG_SMP - spin_unlock_irqrestore(&card->lock, *smp_flags); +#if defined(__SMP__) || defined(LINUX_2_4) + spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); #else enable_irq(card->hw.irq); #endif @@ -2912,7 +3369,7 @@ static int read_connection_info (sdla_t *card) { ppp_mbox_t *mb = card->mbox; - struct net_device *dev = card->wandev.dev; + netdevice_t *dev = card->wandev.dev; ppp_private_area_t *ppp_priv_area = dev->priv; ppp508_connect_info_t *ppp508_connect_info; int err; @@ -2924,15 +3381,347 @@ if (err != CMD_OK) { ppp_error(card, err, mb); + ppp_priv_area->ip_remote = 0; + ppp_priv_area->ip_local = 0; } else { ppp508_connect_info = (ppp508_connect_info_t *)mb->data; - ppp_priv_area->ip_remote = ppp508_connect_info->ip_remote; ppp_priv_area->ip_local = ppp508_connect_info->ip_local; + + NEX_PRINTK(KERN_INFO "READ CONNECTION GOT IP ADDRESS %x, %x\n", + ppp_priv_area->ip_remote, + ppp_priv_area->ip_local); } return err; } + +/*=============================================================================== + * config_ppp + * + * Configure the ppp protocol and enable communications. + * + * The if_open function binds this function to the poll routine. + * Therefore, this function will run every time the ppp interface + * is brought up. + * + * If the communications are not enabled, proceed to configure + * the card and enable communications. + * + * If the communications are enabled, it means that the interface + * was shutdown by ether the user or driver. In this case, we + * have to check that the IP addresses have not changed. If + * the IP addresses changed, we have to reconfigure the firmware + * and update the changed IP addresses. Otherwise, just exit. + */ +static int config_ppp (sdla_t *card) +{ + + netdevice_t *dev = card->wandev.dev; + ppp_flags_t *flags = card->flags; + ppp_private_area_t *ppp_priv_area = dev->priv; + + if (card->u.p.comm_enabled){ + + if (ppp_priv_area->ip_local_tmp != ppp_priv_area->ip_local || + ppp_priv_area->ip_remote_tmp != ppp_priv_area->ip_remote){ + + /* The IP addersses have changed, we must + * stop the communications and reconfigure + * the card. Reason: the firmware must know + * the local and remote IP addresses. */ + disable_comm(card); + wanpipe_set_state(card, WAN_DISCONNECTED); + printk(KERN_INFO + "%s: IP addresses changed!\n", + card->devname); + printk(KERN_INFO "%s: Restarting communications ...\n", + card->devname); + }else{ + /* IP addresses are the same and the link is up, + * we dont have to do anything here. Therefore, exit */ + return 0; + } + } + + /* Record the new IP addreses */ + ppp_priv_area->ip_local = ppp_priv_area->ip_local_tmp; + ppp_priv_area->ip_remote = ppp_priv_area->ip_remote_tmp; + + if (config508(dev, card)){ + printk(KERN_INFO "%s: Failed to configure PPP device\n", + card->devname); + return 0; + } + + if (ppp_set_intr_mode(card, PPP_INTR_RXRDY| + PPP_INTR_TXRDY| + PPP_INTR_MODEM| + PPP_INTR_DISC | + PPP_INTR_OPEN | + PPP_INTR_DROP_DTR | + PPP_INTR_TIMER)) { + + printk(KERN_INFO "%s: Failed to configure board interrupts !\n", + card->devname); + return 0; + } + + /* Turn off the transmit and timer interrupt */ + flags->imask &= ~(PPP_INTR_TXRDY | PPP_INTR_TIMER) ; + + + /* If you are not the authenticator and any one of the protocol is + * enabled then we call the set_out_bound_authentication. + */ + if ( !card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) { + if ( ppp_set_outbnd_auth(card, ppp_priv_area) ){ + printk(KERN_INFO "%s: Outbound authentication failed !\n", + card->devname); + return 0; + } + } + + /* If you are the authenticator and any one of the protocol is enabled + * then we call the set_in_bound_authentication. + */ + if (card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)){ + if (ppp_set_inbnd_auth(card, ppp_priv_area)){ + printk(KERN_INFO "%s: Inbound authentication failed !\n", + card->devname); + return 0; + } + } + + /* If we fail to enable communications here it's OK, + * since the DTR timer will cause a disconnected, which + * will retrigger communication in timer_intr() */ + if (ppp_comm_enable(card) == CMD_OK) { + wanpipe_set_state(card, WAN_CONNECTING); + init_ppp_tx_rx_buff(card); + } + + return 0; +} + +/*============================================================ + * ppp_poll + * + * Rationale: + * We cannot manipulate the routing tables, or + * ip addresses withing the interrupt. Therefore + * we must perform such actons outside an interrupt + * at a later time. + * + * Description: + * PPP polling routine, responsible for + * shutting down interfaces upon disconnect + * and adding/removing routes. + * + * Usage: + * This function is executed for each ppp + * interface through a tq_schedule bottom half. + * + * trigger_ppp_poll() function is used to kick + * the ppp_poll routine. + */ +static void ppp_poll (netdevice_t *dev) +{ + ppp_private_area_t *ppp_priv_area; + sdla_t *card; + u8 check_gateway=0; + ppp_flags_t *flags; + + if (!dev || (ppp_priv_area = dev->priv) == NULL) + return; + + card = ppp_priv_area->card; + flags = card->flags; + + /* Shutdown is in progress, stop what you are + * doing and get out */ + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + clear_bit(POLL_CRIT,&card->wandev.critical); + return; + } + + /* if_open() function has triggered the polling routine + * to determine the configured IP addresses. Once the + * addresses are found, trigger the chdlc configuration */ + if (test_bit(0,&ppp_priv_area->config_ppp)){ + + ppp_priv_area->ip_local_tmp = get_ip_address(dev,WAN_LOCAL_IP); + ppp_priv_area->ip_remote_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); + + if (ppp_priv_area->ip_local_tmp == ppp_priv_area->ip_remote_tmp && + card->u.p.ip_mode == WANOPT_PPP_HOST){ + + if (++ppp_priv_area->ip_error > MAX_IP_ERRORS){ + printk(KERN_INFO "\n%s: --- WARNING ---\n", + card->devname); + printk(KERN_INFO "%s: The local IP address is the same as the\n", + card->devname); + printk(KERN_INFO "%s: Point-to-Point IP address.\n", + card->devname); + printk(KERN_INFO "%s: --- WARNING ---\n\n", + card->devname); + }else{ + clear_bit(POLL_CRIT,&card->wandev.critical); + ppp_priv_area->poll_delay_timer.expires = jiffies+HZ; + add_timer(&ppp_priv_area->poll_delay_timer); + return; + } + } + + ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; + flags->imask |= PPP_INTR_TIMER; + ppp_priv_area->ip_error=0; + + clear_bit(0,&ppp_priv_area->config_ppp); + clear_bit(POLL_CRIT,&card->wandev.critical); + return; + } + + /* Dynamic interface implementation, as well as dynamic + * routing. */ + + switch (card->wandev.state) { + + case WAN_DISCONNECTED: + + /* If the dynamic interface configuration is on, and interface + * is up, then bring down the netowrk interface */ + + if (test_bit(DYN_OPT_ON,&ppp_priv_area->interface_down) && + !test_bit(DEV_DOWN,&ppp_priv_area->interface_down) && + card->wandev.dev->flags & IFF_UP){ + + printk(KERN_INFO "%s: Interface %s down.\n", + card->devname,card->wandev.dev->name); + change_dev_flags(card->wandev.dev, + (card->wandev.dev->flags&~IFF_UP)); + set_bit(DEV_DOWN,&ppp_priv_area->interface_down); + }else{ + /* We need to check if the local IP address is + * zero. If it is, we shouldn't try to remove it. + * For some reason the kernel crashes badly if + * we try to remove the route twice */ + + if (card->wandev.dev->flags & IFF_UP && + get_ip_address(card->wandev.dev,WAN_LOCAL_IP) && + card->u.p.ip_mode == WANOPT_PPP_PEER){ + + remove_route(card); + } + } + break; + + case WAN_CONNECTED: + + /* In SMP machine this code can execute before the interface + * comes up. In this case, we must make sure that we do not + * try to bring up the interface before dev_open() is finished */ + + + /* DEV_DOWN will be set only when we bring down the interface + * for the very first time. This way we know that it was us + * that brought the interface down */ + + if (test_bit(DYN_OPT_ON,&ppp_priv_area->interface_down) && + test_bit(DEV_DOWN, &ppp_priv_area->interface_down) && + !(card->wandev.dev->flags & IFF_UP)){ + + printk(KERN_INFO "%s: Interface %s up.\n", + card->devname,card->wandev.dev->name); + + change_dev_flags(card->wandev.dev,(card->wandev.dev->flags|IFF_UP)); + clear_bit(DEV_DOWN,&ppp_priv_area->interface_down); + check_gateway=1; + } + + if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && + test_bit(1,&Read_connection_info)) { + + process_route(card); + clear_bit(1,&Read_connection_info); + check_gateway=1; + } + + if (ppp_priv_area->gateway && check_gateway) + add_gateway(card,dev); + + break; + } + clear_bit(POLL_CRIT,&card->wandev.critical); + return; +} + +/*============================================================ + * trigger_ppp_poll + * + * Description: + * Add a ppp_poll() task into a tq_scheduler bh handler + * for a specific interface. This will kick + * the ppp_poll() routine at a later time. + * + * Usage: + * Interrupts use this to defer a taks to + * a polling routine. + * + */ + +static void trigger_ppp_poll (netdevice_t *dev) +{ + ppp_private_area_t *ppp_priv_area; + if ((ppp_priv_area=dev->priv) != NULL){ + + sdla_t *card = ppp_priv_area->card; + + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + return; + } + + if (test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ + return; + } + +#ifdef LINUX_2_4 + schedule_task(&ppp_priv_area->poll_task); +#else + queue_task(&ppp_priv_area->poll_task, &tq_scheduler); +#endif + } + return; +} + +static void ppp_poll_delay (unsigned long dev_ptr) +{ + netdevice_t *dev = (netdevice_t *)dev_ptr; + trigger_ppp_poll(dev); +} + +/*============================================================ + * detect_and_fix_tx_bug + * + * Description: + * On connect, if the board tx buffer ptr is not the same + * as the driver tx buffer ptr, we found a firmware bug. + * Report the bug to the above layer. To fix the + * error restart communications again. + * + * Usage: + * + */ + +static int detect_and_fix_tx_bug (sdla_t *card) +{ + if (((unsigned long)card->u.p.txbuf_base&0xFFF) != ((*card->u.p.txbuf_next)&0xFFF)){ + NEX_PRINTK(KERN_INFO "Major Error, Fix the bug\n"); + return 1; + } + return 0; +} + /****** End *****************************************************************/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/wan/sdla_x25.c linux.ac/drivers/net/wan/sdla_x25.c --- linux.vanilla/drivers/net/wan/sdla_x25.c Tue Apr 3 17:32:16 2001 +++ linux.ac/drivers/net/wan/sdla_x25.c Mon Apr 16 15:19:23 2001 @@ -1,16 +1,55 @@ /***************************************************************************** * sdla_x25.c WANPIPE(tm) Multiprotocol WAN Link Driver. X.25 module. * -* Author: Gene Kozin <genek@compuserve.com> +* Author: Nenad Corbic <ncorbic@sangoma.com> * -* Copyright: (c) 1995-1997 Sangoma Technologies Inc. +* Copyright: (c) 1995-2001 Sangoma Technologies Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ -* Mar 15, 1998 Alan Cox o 2.1.x porting +* Apr 03, 2001 Nenad Corbic o Fixed the rx_skb=NULL bug in x25 in rx_intr(). +* Dec 26, 2000 Nenad Corbic o Added a new polling routine, that uses +* a kernel timer (more efficient). +* Dec 25, 2000 Nenad Corbic o Updated for 2.4.X kernel +* Jul 26, 2000 Nenad Corbic o Increased the local packet buffering +* for API to 4096+header_size. +* Jul 17, 2000 Nenad Corbic o Fixed the x25 startup bug. Enable +* communications only after all interfaces +* come up. HIGH SVC/PVC is used to calculate +* the number of channels. +* Enable protocol only after all interfaces +* are enabled. +* Jul 10, 2000 Nenad Corbic o Fixed the M_BIT bug. +* Apr 25, 2000 Nenad Corbic o Pass Modem messages to the API. +* Disable idle timeout in X25 API. +* Apr 14, 2000 Nenad Corbic o Fixed: Large LCN number support. +* Maximum LCN number is 4095. +* Maximum number of X25 channels is 255. +* Apr 06, 2000 Nenad Corbic o Added SMP Support. +* Mar 29, 2000 Nenad Corbic o Added support for S514 PCI Card +* Mar 23, 2000 Nenad Corbic o Improved task queue, BH handling. +* Mar 14, 2000 Nenad Corbic o Updated Protocol Violation handling +* routines. Bug Fix. +* Mar 10, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. +* Mar 09, 2000 Nenad Corbic o Fixed the auto HDLC bug. +* Mar 08, 2000 Nenad Corbic o Fixed LAPB HDLC startup problems. +* Application must bring the link up +* before tx/rx, and bring the +* link down on close(). +* Mar 06, 2000 Nenad Corbic o Added an option for logging call setup +* information. +* Feb 29, 2000 Nenad Corbic o Added support for LAPB HDLC API +* Feb 25, 2000 Nenad Corbic o Fixed the modem failure handling. +* No Modem OOB message will be passed +* to the user. +* Feb 21, 2000 Nenad Corbic o Added Xpipemon Debug Support +* Dec 30, 1999 Nenad Corbic o Socket based X25API +* Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X kernel +* Mar 15, 1998 Alan Cox o 2.1.x porting +* Dec 19, 1997 Jaspreet Singh o Added multi-channel IPX support * Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs * when they are disabled. * Nov 17, 1997 Farhan Thawar o Added IPX support @@ -38,21 +77,41 @@ * Jan 07, 1997 Gene Kozin Initial version. *****************************************************************************/ +/*====================================================== + * Includes + *=====================================================*/ +#include <linux/version.h> #include <linux/kernel.h> /* printk(), and other useful stuff */ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ #include <linux/string.h> /* inline memset(), etc. */ -#include <linux/slab.h> /* kmalloc(), kfree() */ +#include <linux/ctype.h> +#include <linux/malloc.h> /* kmalloc(), kfree() */ #include <linux/wanrouter.h> /* WAN router definitions */ #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ #include <asm/byteorder.h> /* htons(), etc. */ -#include <asm/uaccess.h> +#include <asm/atomic.h> +#include <linux/delay.h> /* Experimental delay */ -#define _GNUC_ +#if defined(LINUX_2_1) || defined(LINUX_2_4) + #include <asm/uaccess.h> +#else + #include <asm/segment.h> + #include <net/route.h> +#endif + +#include <linux/if.h> +#include <linux/if_arp.h> #include <linux/sdla_x25.h> /* X.25 firmware API definitions */ +#include <linux/if_wanpipe_common.h> +#include <linux/if_wanpipe.h> + + +/*====================================================== + * Defines & Macros + *=====================================================*/ -/****** Defines & Macros ****************************************************/ #define CMD_OK 0 /* normal firmware return code */ #define CMD_TIMEOUT 0xFF /* firmware command timed out */ @@ -64,27 +123,141 @@ #define X25_RECON_TMOUT (10*HZ) /* link connection timeout */ #define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ #define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ +#define MAX_BH_BUFF 10 +#define M_BIT 0x01 + +//#define PRINT_DEBUG 1 +#ifdef PRINT_DEBUG +#define DBG_PRINTK(format, a...) printk(format, ## a) +#else +#define DBG_PRINTK(format, a...) +#endif + +#define TMR_INT_ENABLED_POLL_ACTIVE 0x01 +#define TMR_INT_ENABLED_POLL_CONNECT_ON 0x02 +#define TMR_INT_ENABLED_POLL_CONNECT_OFF 0x04 +#define TMR_INT_ENABLED_POLL_DISCONNECT 0x08 +#define TMR_INT_ENABLED_CMD_EXEC 0x10 +#define TMR_INT_ENABLED_UPDATE 0x20 +#define TMR_INT_ENABLED_UDP_PKT 0x40 + +#define MAX_X25_ADDR_SIZE 16 +#define MAX_X25_DATA_SIZE 129 +#define MAX_X25_FACL_SIZE 110 + +#define TRY_CMD_AGAIN 2 +#define DELAY_RESULT 1 +#define RETURN_RESULT 0 + +#define DCD(x) (x & 0x03 ? "HIGH" : "LOW") +#define CTS(x) (x & 0x05 ? "HIGH" : "LOW") + + +/* Driver will not write log messages about + * modem status if defined.*/ +#define MODEM_NOT_LOG 1 + +/*==================================================== + * For IPXWAN + *===================================================*/ -/* For IPXWAN */ #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) -/****** Data Structures *****************************************************/ -/* This is an extention of the 'struct net_device' we create for each network - * interface to keep the rest of X.25 channel-specific data. +/*==================================================== + * MEMORY DEBUGGING FUNCTION + *==================================================== + +#define KMEM_SAFETYZONE 8 + +static void * dbg_kmalloc(unsigned int size, int prio, int line) { + int i = 0; + void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); + char * c1 = v; + c1 += sizeof(unsigned int); + *((unsigned int *)v) = size; + + for (i = 0; i < KMEM_SAFETYZONE; i++) { + c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; + c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; + c1 += 8; + } + c1 += size; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; + c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; + c1 += 8; + } + v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; + printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); + return v; +} +static void dbg_kfree(void * v, int line) { + unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); + unsigned int size = *sp; + char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; + int i = 0; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' + || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { + printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); + printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, + c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); + } + c1 += 8; + } + c1 += size; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' + || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' + ) { + printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); + printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, + c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); + } + c1 += 8; + } + printk(KERN_INFO "line %d kfree(%p)\n",line,v); + v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); + kfree(v); +} + +#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) +#define kfree(x) dbg_kfree(x,__LINE__) + +==============================================================*/ + + + +/*=============================================== + * Data Structures + *===============================================*/ + + +/*======================================================== + * Name: x25_channel + * + * Purpose: To hold private informaton for each + * logical channel. + * + * Rationale: Per-channel debugging is possible if each + * channel has its own private area. + * + * Assumptions: + * + * Description: This is an extention of the 'netdevice_t' + * we create for each network interface to keep + * the rest of X.25 channel-specific data. + * + * Construct: Typedef */ typedef struct x25_channel { - /* This member must be first. */ - struct net_device *slave; /* WAN slave */ - + wanpipe_common_t common; /* common area for x25api and socket */ char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ - unsigned lcn; /* logical channel number */ unsigned tx_pkt_size; unsigned short protocol; /* ethertype, 0 - multiplexed */ - char svc; /* 0 - permanent, 1 - switched */ - char state; /* channel state */ char drop_sequence; /* mark sequence for dropping */ unsigned long state_tick; /* time of the last state change */ unsigned idle_timeout; /* sec, before disconnecting */ @@ -94,63 +267,144 @@ char devtint; /* Weather we should dev_tint() */ struct sk_buff* rx_skb; /* receive socket buffer */ struct sk_buff* tx_skb; /* transmit socket buffer */ + + bh_data_t *bh_head; /* Circular buffer for x25api_bh */ + unsigned long tq_working; + volatile int bh_write; + volatile int bh_read; + atomic_t bh_buff_used; + sdla_t* card; /* -> owner */ + netdevice_t *dev; /* -> bound devce */ + int ch_idx; + unsigned char enable_IPX; + unsigned long network_number; +#if defined(LINUX_2_1) || defined(LINUX_2_4) struct net_device_stats ifstats; /* interface statistics */ +#else + struct enet_statistics ifstats; +#endif + unsigned short transmit_length; + unsigned short tx_offset; + char transmit_buffer[X25_CHAN_MTU+sizeof(x25api_hdr_t)]; + + if_send_stat_t if_send_stat; + rx_intr_stat_t rx_intr_stat; + pipe_mgmt_stat_t pipe_mgmt_stat; + + unsigned long router_start_time; /* Router start time in seconds */ + unsigned long router_up_time; + } x25_channel_t; +/* FIXME Take this out */ + +#ifdef NEX_OLD_CALL_INFO typedef struct x25_call_info { - char dest[17]; /* ASCIIZ destination address */ - char src[17]; /* ASCIIZ source address */ - char nuser; /* number of user data bytes */ - unsigned char user[127]; /* user data */ - char nfacil; /* number of facilities */ + char dest[17]; PACKED;/* ASCIIZ destination address */ + char src[17]; PACKED;/* ASCIIZ source address */ + char nuser; PACKED;/* number of user data bytes */ + unsigned char user[127]; PACKED;/* user data */ + char nfacil; PACKED;/* number of facilities */ struct { - unsigned char code; - unsigned char parm; - } facil[64]; /* facilities */ + unsigned char code; PACKED; + unsigned char parm; PACKED; + } facil[64]; /* facilities */ +} x25_call_info_t; +#else +typedef struct x25_call_info +{ + char dest[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ destination address */ + char src[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ source address */ + unsigned char nuser PACKED; + unsigned char user[MAX_X25_DATA_SIZE] PACKED;/* user data */ + unsigned char nfacil PACKED; + unsigned char facil[MAX_X25_FACL_SIZE] PACKED; + unsigned short lcn PACKED; } x25_call_info_t; +#endif + -/****** Function Prototypes *************************************************/ + +/*=============================================== + * Private Function Prototypes + *==============================================*/ -/* WAN link driver entry points. These are called by the WAN router module. */ + +/*================================================= + * WAN link driver entry points. These are + * called by the WAN router module. + */ static int update (wan_device_t* wandev); -static int new_if (wan_device_t* wandev, struct net_device* dev, +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf); -static int del_if (wan_device_t* wandev, struct net_device* dev); +static int del_if (wan_device_t* wandev, netdevice_t* dev); +static void disable_comm (sdla_t* card); +static void disable_comm_shutdown(sdla_t *card); -/* WANPIPE-specific entry points */ + + +/*================================================= + * WANPIPE-specific entry points + */ static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data); +static void x25api_bh (netdevice_t *); +static int x25api_bh_cleanup (netdevice_t *); +static int bh_enqueue (netdevice_t *, struct sk_buff *); + -/* Network device interface */ -static int if_init (struct net_device* dev); -static int if_open (struct net_device* dev); -static int if_close (struct net_device* dev); -static int if_header (struct sk_buff* skb, struct net_device* dev, +/*================================================= + * Network device interface + */ +static int if_init (netdevice_t* dev); +static int if_open (netdevice_t* dev); +static int if_close (netdevice_t* dev); +static int if_header (struct sk_buff* skb, netdevice_t* dev, unsigned short type, void* daddr, void* saddr, unsigned len); static int if_rebuild_hdr (struct sk_buff* skb); -static int if_send (struct sk_buff* skb, struct net_device* dev); -static struct net_device_stats * if_stats (struct net_device* dev); +static int if_send (struct sk_buff* skb, netdevice_t* dev); +static struct net_device_stats *if_stats (netdevice_t* dev); -/* Interrupt handlers */ -static void wpx_isr (sdla_t* card); -static void rx_intr (sdla_t* card); -static void tx_intr (sdla_t* card); -static void status_intr (sdla_t* card); -static void event_intr (sdla_t* card); -static void spur_intr (sdla_t* card); +#ifdef LINUX_2_4 +static void if_tx_timeout (netdevice_t *dev); +#endif + +/*================================================= + * Interrupt handlers + */ +static void wpx_isr (sdla_t *); +static void rx_intr (sdla_t *); +static void tx_intr (sdla_t *); +static void status_intr (sdla_t *); +static void event_intr (sdla_t *); +static void spur_intr (sdla_t *); +static void timer_intr (sdla_t *); -/* Background polling routines */ +static int tx_intr_send(sdla_t *, netdevice_t *); +static netdevice_t * move_dev_to_next (sdla_t *, netdevice_t *); + +/*================================================= + * Background polling routines + */ static void wpx_poll (sdla_t* card); static void poll_disconnected (sdla_t* card); static void poll_connecting (sdla_t* card); static void poll_active (sdla_t* card); +static void trigger_x25_poll(sdla_t *card); +static void x25_timer_routine(unsigned long data); + + -/* X.25 firmware interface functions */ +/*================================================= + * X.25 firmware interface functions + */ static int x25_get_version (sdla_t* card, char* str); static int x25_configure (sdla_t* card, TX25Config* conf); +static int hdlc_configure (sdla_t* card, TX25Config* conf); +static int set_hdlc_level (sdla_t* card); static int x25_get_err_stats (sdla_t* card); static int x25_get_stats (sdla_t* card); static int x25_set_intr_mode (sdla_t* card, int mode); @@ -166,62 +420,136 @@ static int x25_fetch_events (sdla_t* card); static int x25_error (sdla_t* card, int err, int cmd, int lcn); -/* X.25 asynchronous event handlers */ +/*================================================= + * X.25 asynchronous event handlers + */ static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); -/* Miscellaneous functions */ + +/*================================================= + * Miscellaneous functions + */ static int connect (sdla_t* card); static int disconnect (sdla_t* card); -static struct net_device* get_dev_by_lcn(wan_device_t* wandev, unsigned lcn); -static int chan_connect (struct net_device* dev); -static int chan_disc (struct net_device* dev); -static void set_chan_state (struct net_device* dev, int state); -static int chan_send (struct net_device* dev, struct sk_buff* skb); +static netdevice_t* get_dev_by_lcn(wan_device_t* wandev, unsigned lcn); +static int chan_connect (netdevice_t* dev); +static int chan_disc (netdevice_t* dev); +static void set_chan_state (netdevice_t* dev, int state); +static int chan_send (netdevice_t* , void* , unsigned, unsigned char); static unsigned char bps_to_speed_code (unsigned long bps); static unsigned int dec_to_uint (unsigned char* str, int len); -static unsigned int hex_to_uint (unsigned char* str, int len); -static void parse_call_info (unsigned char* str, x25_call_info_t* info); +static unsigned int hex_to_uint (unsigned char*, int); +static void parse_call_info (unsigned char*, x25_call_info_t*); +static netdevice_t * find_channel(sdla_t *, unsigned); +static void bind_lcn_to_dev (sdla_t *, netdevice_t *,unsigned); +static void setup_for_delayed_transmit (netdevice_t*, void*, unsigned); + + +/*================================================= + * X25 API Functions + */ +static int wanpipe_pull_data_in_skb (sdla_t *, netdevice_t *, struct sk_buff **); +static void timer_intr_exec(sdla_t *, unsigned char); +static int execute_delayed_cmd (sdla_t*, netdevice_t *, mbox_cmd_t *,char); +static int api_incoming_call (sdla_t*, TX25Mbox *, int); +static int alloc_and_init_skb_buf (sdla_t *,struct sk_buff **, int); +static void send_delayed_cmd_result(sdla_t *, netdevice_t *dev, TX25Mbox*); +static int clear_confirm_event (sdla_t *, TX25Mbox*); +static void send_oob_msg (sdla_t *, netdevice_t *, TX25Mbox *); +static int timer_intr_cmd_exec(sdla_t *card); +static void api_oob_event (sdla_t *card,TX25Mbox *mbox); +static int check_bad_command (sdla_t *, netdevice_t *); +static int channel_disconnect (sdla_t*, netdevice_t *); +static void hdlc_link_down (sdla_t*); + +/*================================================= + * XPIPEMON Functions + */ +static int process_udp_mgmt_pkt(sdla_t *); +static int udp_pkt_type( struct sk_buff *, sdla_t*); +static int reply_udp( unsigned char *, unsigned int); +static void init_x25_channel_struct( x25_channel_t *); +static void init_global_statistics( sdla_t *); +static int store_udp_mgmt_pkt(int, char, sdla_t*, netdevice_t *, struct sk_buff *, int); +static unsigned short calc_checksum (char *, int); -/* IPX functions */ -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto); + + +/*================================================= + * IPX functions + */ +static void switch_net_numbers(unsigned char *, unsigned long, unsigned char); +static int handle_IPXWAN(unsigned char *, char *, unsigned char , + unsigned long , unsigned short ); extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); -/****** Global Data ********************************************************** - * Note: All data must be explicitly initialized!!! - */ +static void S508_S514_lock(sdla_t *, unsigned long *); +static void S508_S514_unlock(sdla_t *, unsigned long *); -/****** Public Functions ****************************************************/ -/*============================================================================ - * X.25 Protocol Initialization routine. +/*================================================= + * Global Variables + *=================================================*/ + + + +/*================================================= + * Public Functions + *=================================================*/ + + + + +/*=================================================================== + * wpx_init: X.25 Protocol Initialization routine. + * + * Purpose: To initialize the protocol/firmware. + * + * Rationale: This function is called by setup() function, in + * sdlamain.c, to dynamically setup the x25 protocol. + * This is the first protocol specific function, which + * executes once on startup. + * + * Description: This procedure initializes the x25 firmware and + * sets up the mailbox, transmit and receive buffer + * pointers. It also initializes all debugging structures + * and sets up the X25 environment. * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and X.25 firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. + * Sets up hardware options defined by user in [wanpipe#] + * section of wanpipe#.conf configuration file. * - * Return: 0 o.k. - * < 0 failure. + * At this point adapter is completely initialized + * and X.25 firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the + * adapter data space. + * + * Called by: setup() function in sdlamain.c + * + * Assumptions: None + * + * Warnings: None + * + * Return: 0 o.k. + * < 0 failure. */ + int wpx_init (sdla_t* card, wandev_conf_t* conf) { - union - { + union{ char str[80]; TX25Config cfg; } u; /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_X25) - { + if (conf->config_id != WANCONFIG_X25){ printk(KERN_INFO "%s: invalid configuration ID %u!\n", card->devname, conf->config_id) ; @@ -233,23 +561,43 @@ card->rxmb = (void*)(card->hw.dpmbase + X25_RXMBOX_OFFS); card->flags = (void*)(card->hw.dpmbase + X25_STATUS_OFFS); + /* Initialize for S514 Card */ + if(card->hw.type == SDLA_S514) { + card->mbox += X25_MB_VECTOR; + card->flags += X25_MB_VECTOR; + card->rxmb += X25_MB_VECTOR; + } + + /* Read firmware version. Note that when adapter initializes, it * clears the mailbox, so it may appear that the first command was * executed successfully when in fact it was merely erased. To work * around this, we execute the first command twice. */ if (x25_get_version(card, NULL) || x25_get_version(card, u.str)) - return -EIO - ; - printk(KERN_INFO "%s: running X.25 firmware v%s\n", - card->devname, u.str) - ; + return -EIO; + + + /* X25 firmware can run ether in X25 or LAPB HDLC mode. + * Check the user defined option and configure accordingly */ + if (conf->u.x25.LAPB_hdlc_only == WANOPT_YES){ + if (set_hdlc_level(card) != CMD_OK){ + return -EIO; + }else{ + printk(KERN_INFO "%s: running LAP_B HDLC firmware v%s\n", + card->devname, u.str); + } + card->u.x.LAPB_hdlc = 1; + }else{ + printk(KERN_INFO "%s: running X.25 firmware v%s\n", + card->devname, u.str); + card->u.x.LAPB_hdlc = 0; + } /* Configure adapter. Here we set resonable defaults, then parse * device configuration structure and set configuration options. * Most configuration options are verified and corrected (if - * necessary) since we can't rely on the adapter to do so and don't - * want it to fail either. + * necessary) since we can't rely on the adapter to do so. */ memset(&u.cfg, 0, sizeof(u.cfg)); u.cfg.t1 = 3; @@ -258,7 +606,7 @@ u.cfg.hdlcWindow = 7; u.cfg.pktWindow = 2; u.cfg.station = 1; /* DTE */ - u.cfg.options = 0x00B0; /* disable D-bit pragmatics */ + u.cfg.options = 0x0090; /* disable D-bit pragmatics */ u.cfg.ccittCompat = 1988; u.cfg.t10t20 = 30; u.cfg.t11t21 = 30; @@ -271,71 +619,120 @@ u.cfg.r13r23 = 5; u.cfg.responseOpt = 1; /* RR's after every packet */ + if (card->u.x.LAPB_hdlc){ + u.cfg.hdlcMTU = 1027; + } + + if (conf->u.x25.x25_conf_opt){ + u.cfg.options = conf->u.x25.x25_conf_opt; + } + if (conf->clocking != WANOPT_EXTERNAL) - u.cfg.baudRate = bps_to_speed_code(conf->bps) - ; - if (conf->station != WANOPT_DTE) - { + u.cfg.baudRate = bps_to_speed_code(conf->bps); + + if (conf->station != WANOPT_DTE){ u.cfg.station = 0; /* DCE mode */ } - if (conf->interface != WANOPT_RS232 ) { + + if (conf->interface != WANOPT_RS232 ){ u.cfg.hdlcOptions |= 0x80; /* V35 mode */ } + /* adjust MTU */ if (!conf->mtu || (conf->mtu >= 1024)) - card->wandev.mtu = 1024 - ; + card->wandev.mtu = 1024; else if (conf->mtu >= 512) - card->wandev.mtu = 512 - ; + card->wandev.mtu = 512; else if (conf->mtu >= 256) - card->wandev.mtu = 256 - ; + card->wandev.mtu = 256; else if (conf->mtu >= 128) - card->wandev.mtu = 128 - ; - else card->wandev.mtu = 64; + card->wandev.mtu = 128; + else + card->wandev.mtu = 64; + u.cfg.defPktSize = u.cfg.pktMTU = card->wandev.mtu; - if (conf->u.x25.hi_pvc) - { - card->u.x.hi_pvc = min(conf->u.x25.hi_pvc, 4095); + if (conf->u.x25.hi_pvc){ + card->u.x.hi_pvc = min(conf->u.x25.hi_pvc, MAX_LCN_NUM); card->u.x.lo_pvc = min(conf->u.x25.lo_pvc, card->u.x.hi_pvc); } - if (conf->u.x25.hi_svc) - { - card->u.x.hi_svc = min(conf->u.x25.hi_svc, 4095); + + if (conf->u.x25.hi_svc){ + card->u.x.hi_svc = min(conf->u.x25.hi_svc, MAX_LCN_NUM); card->u.x.lo_svc = min(conf->u.x25.lo_svc, card->u.x.hi_svc); } - u.cfg.loPVC = card->u.x.lo_pvc; - u.cfg.hiPVC = card->u.x.hi_pvc; + + /* Figure out the total number of channels to configure */ + card->u.x.num_of_ch = 0; + if (card->u.x.hi_svc != 0){ + card->u.x.num_of_ch = (card->u.x.hi_svc - card->u.x.lo_svc) + 1; + } + if (card->u.x.hi_pvc != 0){ + card->u.x.num_of_ch += (card->u.x.hi_pvc - card->u.x.lo_pvc) + 1; + } + + if (card->u.x.num_of_ch == 0){ + printk(KERN_INFO "%s: ERROR, Minimum number of PVC/SVC channels is 1 !\n" + "%s: Please set the Lowest/Highest PVC/SVC values !\n", + card->devname,card->devname); + return -ECHRNG; + } + + u.cfg.loPVC = card->u.x.lo_pvc; + u.cfg.hiPVC = card->u.x.hi_pvc; u.cfg.loTwoWaySVC = card->u.x.lo_svc; u.cfg.hiTwoWaySVC = card->u.x.hi_svc; if (conf->u.x25.hdlc_window) - u.cfg.hdlcWindow = min(conf->u.x25.hdlc_window, 7) - ; + u.cfg.hdlcWindow = min(conf->u.x25.hdlc_window, 7); if (conf->u.x25.pkt_window) - u.cfg.pktWindow = min(conf->u.x25.pkt_window, 7) - ; + u.cfg.pktWindow = min(conf->u.x25.pkt_window, 7); + if (conf->u.x25.t1) - u.cfg.t1 = min(conf->u.x25.t1, 30) - ; - u.cfg.t2 = min(conf->u.x25.t2, 29); - u.cfg.t4 = min(conf->u.x25.t4, 240); + u.cfg.t1 = min(conf->u.x25.t1, 30); + if (conf->u.x25.t2) + u.cfg.t2 = min(conf->u.x25.t2, 29); + if (conf->u.x25.t4) + u.cfg.t4 = min(conf->u.x25.t4, 240); if (conf->u.x25.n2) - u.cfg.n2 = min(conf->u.x25.n2, 30) - ; + u.cfg.n2 = min(conf->u.x25.n2, 30); + + if (conf->u.x25.t10_t20) + u.cfg.t10t20 = min(conf->u.x25.t10_t20,255); + if (conf->u.x25.t11_t21) + u.cfg.t11t21 = min(conf->u.x25.t11_t21,255); + if (conf->u.x25.t12_t22) + u.cfg.t12t22 = min(conf->u.x25.t12_t22,255); + if (conf->u.x25.t13_t23) + u.cfg.t13t23 = min(conf->u.x25.t13_t23,255); + if (conf->u.x25.t16_t26) + u.cfg.t16t26 = min(conf->u.x25.t16_t26, 255); + if (conf->u.x25.t28) + u.cfg.t28 = min(conf->u.x25.t28, 255); + + if (conf->u.x25.r10_r20) + u.cfg.r10r20 = min(conf->u.x25.r10_r20,250); + if (conf->u.x25.r12_r22) + u.cfg.r12r22 = min(conf->u.x25.r12_r22,250); + if (conf->u.x25.r13_r23) + u.cfg.r13r23 = min(conf->u.x25.r13_r23,250); + + if (conf->u.x25.ccitt_compat) - u.cfg.ccittCompat = conf->u.x25.ccitt_compat - ; + u.cfg.ccittCompat = conf->u.x25.ccitt_compat; /* initialize adapter */ - if ((x25_configure(card, &u.cfg) != CMD_OK) || - (x25_close_hdlc(card) != CMD_OK) || /* close HDLC link */ + if (card->u.x.LAPB_hdlc){ + if (hdlc_configure(card, &u.cfg) != CMD_OK) + return -EIO; + }else{ + if (x25_configure(card, &u.cfg) != CMD_OK) + return -EIO; + } + + if ((x25_close_hdlc(card) != CMD_OK) || /* close HDLC link */ (x25_set_dtr(card, 0) != CMD_OK)) /* drop DTR */ - return -EIO - ; + return -EIO; /* Initialize protocol-specific fields of adapter data space */ card->wandev.bps = conf->bps; @@ -343,202 +740,392 @@ card->wandev.clocking = conf->clocking; card->wandev.station = conf->station; card->isr = &wpx_isr; - card->poll = &wpx_poll; + card->poll = NULL; //&wpx_poll; + card->disable_comm = &disable_comm; card->exec = &wpx_exec; card->wandev.update = &update; card->wandev.new_if = &new_if; card->wandev.del_if = &del_if; + + /* WARNING: This function cannot exit with an error + * after the change of state */ card->wandev.state = WAN_DISCONNECTED; + card->wandev.enable_tx_int = 0; card->irq_dis_if_send_count = 0; card->irq_dis_poll_count = 0; - card->wandev.enable_IPX = conf->enable_IPX; + card->u.x.tx_dev = NULL; + card->u.x.no_dev = 0; + + + /* Configure for S514 PCI Card */ + if (card->hw.type == SDLA_S514) { + card->u.x.hdlc_buf_status = + (volatile unsigned char *) + (card->hw.dpmbase + X25_MB_VECTOR+ X25_MISC_HDLC_BITS); + }else{ + card->u.x.hdlc_buf_status = + (volatile unsigned char *)(card->hw.dpmbase + X25_MISC_HDLC_BITS); + } + + card->u.x.poll_device=NULL; + card->wandev.udp_port = conf->udp_port; + + /* Enable or disable call setup logging */ + if (conf->u.x25.logging == WANOPT_YES){ + printk(KERN_INFO "%s: Enabling Call Logging.\n", + card->devname); + card->u.x.logging = 1; + }else{ + card->u.x.logging = 0; + } + + /* Enable or disable modem status reporting */ + if (conf->u.x25.oob_on_modem == WANOPT_YES){ + printk(KERN_INFO "%s: Enabling OOB on Modem change.\n", + card->devname); + card->u.x.oob_on_modem = 1; + }else{ + card->u.x.oob_on_modem = 0; + } + + init_global_statistics(card); + +#ifndef LINUX_2_4 + card->u.x.x25_poll_task.next = NULL; +#endif + card->u.x.x25_poll_task.sync=0; + card->u.x.x25_poll_task.routine = (void*)(void*)wpx_poll; + card->u.x.x25_poll_task.data = card; + + init_timer(&card->u.x.x25_timer); + card->u.x.x25_timer.data = (unsigned long)card; + card->u.x.x25_timer.function = x25_timer_routine; - if (conf->network_number) - card->wandev.network_number = conf->network_number; - else - card->wandev.network_number = 0xDEADBEEF; return 0; } -/******* WAN Device Driver Entry Points *************************************/ +/*========================================================= + * WAN Device Driver Entry Points + *========================================================*/ -/*============================================================================ - * Update device status & statistics. +/*============================================================ + * Name: update(), Update device status & statistics. + * + * Purpose: To provide debugging and statitical + * information to the /proc file system. + * /proc/net/wanrouter/wanpipe# + * + * Rationale: The /proc file system is used to collect + * information about the kernel and drivers. + * Using the /proc file system the user + * can see exactly what the sangoma drivers are + * doing. And in what state they are in. + * + * Description: Collect all driver statistical information + * and pass it to the top laywer. + * + * Since we have to execute a debugging command, + * to obtain firmware statitics, we trigger a + * UPDATE function within the timer interrtup. + * We wait until the timer update is complete. + * Once complete return the appropriate return + * code to indicate that the update was successful. + * + * Called by: device_stat() in wanmain.c + * + * Assumptions: + * + * Warnings: This function will degrade the performance + * of the router, since it uses the mailbox. + * + * Return: 0 OK + * <0 Failed (or busy). */ + static int update (wan_device_t* wandev) { - sdla_t* card; + volatile sdla_t* card; + TX25Status* status; + unsigned long timeout; /* sanity checks */ if ((wandev == NULL) || (wandev->private == NULL)) return -EFAULT; + if (wandev->state == WAN_UNCONFIGURED) return -ENODEV; - if (test_and_set_bit(0, (void*)&wandev->critical)) + + if (test_bit(SEND_CRIT, (void*)&wandev->critical)) return -EAGAIN; + + if (!wandev->dev) + return -ENODEV; + card = wandev->private; + status = card->flags; - x25_get_err_stats(card); - x25_get_stats(card); - wandev->critical = 0; + card->u.x.timer_int_enabled |= TMR_INT_ENABLED_UPDATE; + status->imask |= INTR_ON_TIMER; + timeout = jiffies; + + for (;;){ + if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE)){ + break; + } + if ((jiffies-timeout) > 1*HZ){ + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; + return -EAGAIN; + } + } return 0; } -/*============================================================================ - * Create new logical channel. - * This routine is called by the router when ROUTER_IFNEW IOCTL is being - * handled. - * o parse media- and hardware-specific configuration - * o make sure that a new channel can be created - * o allocate resources, if necessary - * o prepare network device structure for registaration. + +/*=================================================================== + * Name: new_if + * + * Purpose: To allocate and initialize resources for a + * new logical channel. + * + * Rationale: A new channel can be added dynamically via + * ioctl call. + * + * Description: Allocate a private channel structure, x25_channel_t. + * Parse the user interface options from wanpipe#.conf + * configuration file. + * Bind the private are into the network device private + * area pointer (dev->priv). + * Prepare the network device structure for registration. + * + * Called by: ROUTER_IFNEW Ioctl call, from wanrouter_ioctl() + * (wanmain.c) + * + * Assumptions: None * - * Return: 0 o.k. - * < 0 failure (channel will not be created) + * Warnings: None + * + * Return: 0 Ok + * <0 Failed (channel will not be created) */ -static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf) +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) { sdla_t* card = wandev->private; x25_channel_t* chan; int err = 0; - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) - { + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)){ printk(KERN_INFO "%s: invalid interface name!\n", - card->devname) - ; + card->devname); return -EINVAL; } + if(card->wandev.new_if_cnt++ > 0 && card->u.x.LAPB_hdlc) { + printk(KERN_INFO "%s: Error: Running LAPB HDLC Mode !\n", + card->devname); + printk(KERN_INFO + "%s: Maximum number of network interfaces must be one !\n", + card->devname); + return -EEXIST; + } + /* allocate and initialize private data */ - chan = kmalloc(sizeof(x25_channel_t), GFP_KERNEL); - if (chan == NULL) - return -ENOMEM - ; + chan = kmalloc(sizeof(x25_channel_t), GFP_ATOMIC); + if (chan == NULL){ + return -ENOMEM; + } + memset(chan, 0, sizeof(x25_channel_t)); + + /* Bug Fix: Seg Err on PVC startup + * It must be here since bind_lcn_to_dev expects + * it bellow */ + dev->priv = chan; + strcpy(chan->name, conf->name); chan->card = card; - chan->protocol = ETH_P_IP; + chan->dev = dev; + chan->common.sk = NULL; + chan->common.func = NULL; + chan->common.rw_bind = 0; chan->tx_skb = chan->rx_skb = NULL; /* verify media address */ - if (conf->addr[0] == '@') /* SVC */ - { - chan->svc = 1; + if (conf->addr[0] == '@'){ /* SVC */ + chan->common.svc = 1; strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ); /* Set channel timeouts (default if not specified) */ - chan->idle_timeout = (conf->idle_timeout) ? conf->idle_timeout : 90; - chan->hold_timeout = (conf->hold_timeout) ? conf->hold_timeout : 10; - } - else if (is_digit(conf->addr[0])) /* PVC */ - { + chan->idle_timeout = (conf->idle_timeout) ? + conf->idle_timeout : 90; + chan->hold_timeout = (conf->hold_timeout) ? + conf->hold_timeout : 10; + + }else if (is_digit(conf->addr[0])){ /* PVC */ int lcn = dec_to_uint(conf->addr, 0); - if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc)) - { - chan->lcn = lcn; - } - else - { + if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc)){ + bind_lcn_to_dev (card, dev, lcn); + }else{ printk(KERN_ERR "%s: PVC %u is out of range on interface %s!\n", - wandev->name, lcn, chan->name) - ; + wandev->name, lcn, chan->name); err = -EINVAL; } - } - else - { + }else{ printk(KERN_ERR "%s: invalid media address on interface %s!\n", - wandev->name, chan->name) - ; + wandev->name, chan->name); err = -EINVAL; } - if (err) - { + + if(strcmp(conf->usedby, "WANPIPE") == 0){ + printk(KERN_INFO "%s: Running in WANPIPE mode %s\n", + wandev->name, chan->name); + chan->common.usedby = WANPIPE; + chan->protocol = htons(ETH_P_IP); + + }else if(strcmp(conf->usedby, "API") == 0){ + chan->common.usedby = API; + printk(KERN_INFO "%s: Running in API mode %s\n", + wandev->name, chan->name); + chan->protocol = htons(X25_PROT); + } + + + if (err){ kfree(chan); + dev->priv = NULL; return err; } + + chan->enable_IPX = conf->enable_IPX; + + if (chan->enable_IPX) + chan->protocol = htons(ETH_P_IPX); + + if (conf->network_number) + chan->network_number = conf->network_number; + else + chan->network_number = 0xDEADBEEF; /* prepare network device data space for registration */ - strcpy(dev->name, chan->name); +#ifdef LINUX_2_4 + strcpy(dev->name,chan->name); +#else + dev->name = (char *)kmalloc(strlen(chan->name) + 2, GFP_KERNEL); + if(dev->name == NULL) + { + kfree(chan); + dev->priv = NULL; + return -ENOMEM; + } + sprintf(dev->name, "%s", chan->name); +#endif dev->init = &if_init; - dev->priv = chan; + + init_x25_channel_struct(chan); + return 0; } -/*============================================================================ - * Delete logical channel. +/*=================================================================== + * Name: del_if(), Remove a logical channel. + * + * Purpose: To dynamically remove a logical channel. + * + * Rationale: Each logical channel should be dynamically + * removable. This functin is called by an + * IOCTL_IFDEL ioctl call or shutdown(). + * + * Description: Do nothing. + * + * Called by: IOCTL_IFDEL : wanrouter_ioctl() from wanmain.c + * shutdown() from sdlamain.c + * + * Assumptions: + * + * Warnings: + * + * Return: 0 Ok. Void function. */ -static int del_if (wan_device_t* wandev, struct net_device* dev) + +//FIXME Del IF Should be taken out now. + +static int del_if (wan_device_t* wandev, netdevice_t* dev) { - if (dev->priv) - { - kfree(dev->priv); - dev->priv = NULL; - } return 0; } -/****** WANPIPE-specific entry points ***************************************/ -/*============================================================================ - * Execute adapter interface command. - */ +/*============================================================ + * Name: wpx_exec + * + * Description: Execute adapter interface command. + * This option is currently dissabled. + *===========================================================*/ static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data) { - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err, len; - TX25Cmd cmd; - - if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) - return -EFAULT; - - /* execute command */ + return 0; +} - do - { - memcpy(&mbox->cmd, &cmd, sizeof(cmd)); - if (cmd.length) - { - if(copy_from_user((void*)&mbox->data, u_data, cmd.length)) - return-EFAULT; - } - if (sdla_exec(mbox)) - err = mbox->cmd.result - ; - else return -EIO; - } - while (err && retry-- && x25_error(card, err, cmd.command, cmd.lcn)); +/*============================================================ + * Name: disable_comm + * + * Description: Disable communications during shutdown. + * Dont check return code because there is + * nothing we can do about it. + * + * Warning: Dev and private areas are gone at this point. + *===========================================================*/ - /* return result */ - if(copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(TX25Cmd))) - return -EFAULT; - len = mbox->cmd.length; - if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)) - return -EFAULT; - return 0; +static void disable_comm(sdla_t* card) +{ + disable_comm_shutdown(card); + del_timer(&card->u.x.x25_timer); + return; } -/****** Network Device Interface ********************************************/ -/*============================================================================ - * Initialize Linux network interface. +/*============================================================ + * Network Device Interface + *===========================================================*/ + +/*=================================================================== + * Name: if_init(), Netowrk Interface Initialization * - * This routine is called only once for each interface, during Linux network - * interface registration. Returning anything but zero will fail interface - * registration. + * Purpose: To initialize a network interface device structure. + * + * Rationale: During network interface startup, the if_init + * is called by the kernel to initialize the + * netowrk device structure. Thus a driver + * can customze a network device. + * + * Description: Initialize the netowrk device call back + * routines. This is where we tell the kernel + * which function to use when it wants to send + * via our interface. + * Furthermore, we initialize the device flags, + * MTU and physical address of the board. + * + * Called by: Kernel (/usr/src/linux/net/core/dev.c) + * (dev->init()) + * + * Assumptions: None + * + * Warnings: None + * + * Return: 0 Ok : Void function. */ -static int if_init (struct net_device* dev) +static int if_init (netdevice_t* dev) { x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; wan_device_t* wandev = &card->wandev; +#ifdef LINUX_2_0 + int i; +#endif /* Initialize device driver entry points */ dev->open = &if_open; @@ -548,127 +1135,268 @@ dev->hard_start_xmit = &if_send; dev->get_stats = &if_stats; +#ifdef LINUX_2_4 + dev->tx_timeout = &if_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; +#endif + /* Initialize media-specific parameters */ - dev->type = 30; /* ARP h/w type */ - dev->mtu = X25_CHAN_MTU; +#if defined(LINUX_2_1) || defined(LINUX_2_4) + dev->type = ARPHRD_PPP; /* ARP h/w type */ +#else + dev->family = AF_INET; /* address family */ + dev->type = ARPHRD_PPP; /* no x25 type */ +#endif + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + + if (chan->common.usedby == API){ + dev->mtu = X25_CHAN_MTU+sizeof(x25api_hdr_t); + }else{ + dev->mtu = card->wandev.mtu; + } + dev->hard_header_len = X25_HRDHDR_SZ; /* media header length */ dev->addr_len = 2; /* hardware address length */ - if (!chan->svc) - *(unsigned short*)dev->dev_addr = htons(chan->lcn); - + + if (!chan->common.svc){ + *(unsigned short*)dev->dev_addr = htons(chan->common.lcn); + } + /* Initialize hardware parameters (just for reference) */ dev->irq = wandev->irq; dev->dma = wandev->dma; dev->base_addr = wandev->ioport; dev->mem_start = (unsigned long)wandev->maddr; - dev->mem_end = dev->mem_end + wandev->msize - 1; + dev->mem_end = wandev->maddr + wandev->msize - 1; /* Set transmit buffer queue length */ - dev->tx_queue_len = 10; + dev->tx_queue_len = 100; /* Initialize socket buffers */ - - dev_init_buffers(dev); +#if defined(LINUX_2_1) || defined(LINUX_2_4) + dev_init_buffers(dev); +#else + for (i = 0; i < DEV_NUMBUFFS; ++i) + skb_queue_head_init(&dev->buffs[i]); +#endif + /* FIXME Why are we doing this */ set_chan_state(dev, WAN_DISCONNECTED); return 0; } -/*============================================================================ - * Open network interface. - * o prevent module from unloading by incrementing use count - * o if link is disconnected then initiate connection + +/*=================================================================== + * Name: if_open(), Open/Bring up the Netowrk Interface + * + * Purpose: To bring up a network interface. + * + * Rationale: + * + * Description: Open network interface. + * o prevent module from unloading by incrementing use count + * o if link is disconnected then initiate connection + * + * Called by: Kernel (/usr/src/linux/net/core/dev.c) + * (dev->open()) * - * Return 0 if O.k. or errno. + * Assumptions: None + * + * Warnings: None + * + * Return: 0 Ok + * <0 Failur: Interface will not come up. */ -static int if_open (struct net_device* dev) + +static int if_open (netdevice_t* dev) { x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; + struct timeval tv; + unsigned long smp_flags; + + if (is_dev_running(dev)) + return -EBUSY; + + chan->tq_working = 0; + + /* Initialize the task queue */ +#ifndef LINUX_2_4 + chan->common.wanpipe_task.next = NULL; +#endif + chan->common.wanpipe_task.sync = 0; + chan->common.wanpipe_task.routine = (void *)(void *)x25api_bh; + chan->common.wanpipe_task.data = dev; + + /* Allocate and initialize BH circular buffer */ + /* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */ + chan->bh_head = kmalloc((sizeof(bh_data_t)*(MAX_BH_BUFF+1)),GFP_ATOMIC); + + if (chan->bh_head == NULL){ + printk(KERN_INFO "%s: ERROR, failed to allocate memory ! BH_BUFFERS !\n", + card->devname); + + return -ENOBUFS; + } + memset(chan->bh_head,0,(sizeof(bh_data_t)*(MAX_BH_BUFF+1))); + atomic_set(&chan->bh_buff_used, 0); - if (dev->start) - return -EBUSY; /* only one open is allowed */ + /* Increment the number of interfaces */ + ++card->u.x.no_dev; - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - return -EAGAIN; + wanpipe_open(card); + /* LAPB protocol only uses one interface, thus + * start the protocol after it comes up. */ + if (card->u.x.LAPB_hdlc){ + if (card->open_cnt == 1){ + TX25Status* status = card->flags; + S508_S514_lock(card, &smp_flags); + x25_set_intr_mode(card, INTR_ON_TIMER); + status->imask &= ~INTR_ON_TIMER; + S508_S514_unlock(card, &smp_flags); + } + }else{ + /* X25 can have multiple interfaces thus, start the + * protocol once all interfaces are up */ + + //FIXME: There is a bug here. If interface is + //brought down and up, it will try to enable comm. + if (card->open_cnt == card->u.x.num_of_ch){ + + S508_S514_lock(card, &smp_flags); + connect(card); + S508_S514_unlock(card, &smp_flags); + + del_timer(&card->u.x.x25_timer); + card->u.x.x25_timer.expires=jiffies+HZ; + add_timer(&card->u.x.x25_timer); + } + } + /* Device is not up untill the we are in connected state */ + do_gettimeofday( &tv ); + chan->router_start_time = tv.tv_sec; + +#ifdef LINUX_2_4 + netif_start_queue(dev); +#else dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; - wanpipe_open(card); - - /* If this is the first open, initiate physical connection */ - if (card->open_cnt == 1) - connect(card); - card->wandev.critical = 0; +#endif return 0; } -/*============================================================================ - * Close network interface. - * o reset flags. - * o if there's no more open channels then disconnect physical link. +/*=================================================================== + * Name: if_close(), Close/Bring down the Netowrk Interface + * + * Purpose: To bring down a network interface. + * + * Rationale: + * + * Description: Close network interface. + * o decrement use module use count + * + * Called by: Kernel (/usr/src/linux/net/core/dev.c) + * (dev->close()) + * ifconfig <name> down: will trigger the kernel + * which will call this function. + * + * Assumptions: None + * + * Warnings: None + * + * Return: 0 Ok + * <0 Failure: Interface will not exit properly. */ -static int if_close (struct net_device* dev) +static int if_close (netdevice_t* dev) { x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; - - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - return -EAGAIN; - - dev->start = 0; - if ((chan->state == WAN_CONNECTED) || (chan->state == WAN_CONNECTING)) + unsigned long smp_flags; + + stop_net_queue(dev); +#ifndef LINUX_2_4 + dev->start=0; +#endif + + if ((chan->common.state == WAN_CONNECTED) || + (chan->common.state == WAN_CONNECTING)){ + S508_S514_lock(card, &smp_flags); chan_disc(dev); - + S508_S514_unlock(card, &smp_flags); + } + wanpipe_close(card); - /* If this is the last close, disconnect physical link */ - if (!card->open_cnt) - disconnect(card); - - card->wandev.critical = 0; + S508_S514_lock(card, &smp_flags); + if (chan->bh_head){ + int i; + struct sk_buff *skb; + + for (i=0; i<(MAX_BH_BUFF+1); i++){ + skb = ((bh_data_t *)&chan->bh_head[i])->skb; + if (skb != NULL){ + wan_dev_kfree_skb(skb, FREE_READ); + } + } + kfree(chan->bh_head); + chan->bh_head=NULL; + } + S508_S514_unlock(card, &smp_flags); + + /* If this is the last close, disconnect physical link */ + if (!card->open_cnt){ + S508_S514_lock(card, &smp_flags); + disconnect(card); + x25_set_intr_mode(card, 0); + S508_S514_unlock(card, &smp_flags); + } + + /* Decrement the number of interfaces */ + --card->u.x.no_dev; return 0; } -/*============================================================================ - * Build media header. - * o encapsulate packet according to encapsulation type. +/*====================================================================== + * Build media header. + * o encapsulate packet according to encapsulation type. * - * The trick here is to put packet type (Ethertype) into 'protocol' field of - * the socket buffer, so that we don't forget it. If encapsulation fails, - * set skb->protocol to 0 and discard packet later. + * The trick here is to put packet type (Ethertype) into 'protocol' + * field of the socket buffer, so that we don't forget it. + * If encapsulation fails, set skb->protocol to 0 and discard + * packet later. * - * Return: media header length. - */ -static int if_header (struct sk_buff* skb, struct net_device* dev, + * Return: media header length. + *======================================================================*/ + +static int if_header (struct sk_buff* skb, netdevice_t* dev, unsigned short type, void* daddr, void* saddr, unsigned len) { x25_channel_t* chan = dev->priv; int hdr_len = dev->hard_header_len; - - skb->protocol = type; - if (!chan->protocol) - { - hdr_len = wanrouter_encapsulate(skb, dev); - if (hdr_len < 0) - { + + skb->protocol = htons(type); + if (!chan->protocol){ + hdr_len = wanrouter_encapsulate(skb, dev, type); + if (hdr_len < 0){ hdr_len = 0; - skb->protocol = 0; + skb->protocol = htons(0); } } return hdr_len; } -/*============================================================================ - * Re-build media header. +/*=============================================================== + * Re-build media header. * - * Return: 1 physical address resolved. - * 0 physical address not resolved - */ - + * Return: 1 physical address resolved. + * 0 physical address not resolved + *==============================================================*/ + static int if_rebuild_hdr (struct sk_buff* skb) { - struct net_device *dev=skb->dev; + netdevice_t *dev = skb->dev; x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; @@ -677,185 +1405,294 @@ return 1; } + +#ifdef LINUX_2_4 /*============================================================================ - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission). - * o check link state. If link is not up, then drop the packet. - * o check channel status. If it's down then initiate a call. - * o pass a packet to corresponding WAN device. - * o free socket buffer + * Handle transmit timeout event from netif watchdog + */ +static void if_tx_timeout (netdevice_t *dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t *card = chan->card; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++chan->if_send_stat.if_send_tbusy_timeout; + printk (KERN_INFO "%s: Transmit timed out on %s\n", + card->devname, dev->name); + netif_wake_queue (dev); +} +#endif + + +/*========================================================================= + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission). + * o check link state. If link is not up, then drop the packet. + * o check channel status. If it's down then initiate a call. + * o pass a packet to corresponding WAN device. + * o free socket buffer * - * Return: 0 complete (socket buffer must be freed) + * Return: 0 complete (socket buffer must be freed) * non-0 packet may be re-transmitted (tbusy must be set) * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. - */ + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + * + *========================================================================*/ -static int if_send (struct sk_buff* skb, struct net_device* dev) +static int if_send (struct sk_buff* skb, netdevice_t* dev) { x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; - struct net_device *dev2; TX25Status* status = card->flags; - unsigned long host_cpu_flags; + int udp_type; + unsigned long smp_flags=0; - if (dev->tbusy) - { - ++chan->ifstats.rx_dropped; - if ((jiffies - chan->tick_counter) < (5*HZ)) - { - return dev->tbusy; + ++chan->if_send_stat.if_send_entry; + +#ifdef LINUX_2_4 + netif_stop_queue(dev); +#endif + + /* No need to check frame length, since socket code + * will perform the check for us */ + +#ifndef LINUX_2_4 + if (dev->tbusy){ + netdevice_t *dev2; + + ++chan->if_send_stat.if_send_tbusy; + if ((jiffies - chan->tick_counter) < (5*HZ)){ + return 1; } printk(KERN_INFO "%s: Transmit time out %s!\n", - card->devname, dev->name); + card->devname, dev->name); + + for( dev2 = card->wandev.dev; dev2; + dev2 = *((netdevice_t**)dev2->priv)){ - dev2 = card->wandev.dev; - while (dev2) { - x25_channel_t *chan2 = dev2->priv; dev2->tbusy = 0; - dev2 = chan2->slave; } + ++chan->if_send_stat.if_send_tbusy_timeout; } +#endif + chan->tick_counter = jiffies; + + /* Critical region starts here */ + S508_S514_lock(card, &smp_flags); + + if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ + printk(KERN_INFO "Hit critical in if_send()! %lx\n",card->wandev.critical); + goto if_send_crit_exit; + } + + udp_type = udp_pkt_type(skb, card); - disable_irq(card->hw.irq); - ++card->irq_dis_if_send_count; + if(udp_type != UDP_INVALID_TYPE) { - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - { - printk(KERN_INFO "Hit critical in if_send()!\n"); - if (card->wandev.critical == CRITICAL_IN_ISR) - { - card->wandev.enable_tx_int = 1; - dev->tbusy = 1; - - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - - return dev->tbusy; - } - dev_kfree_skb(skb); - - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, dev, skb, + chan->common.lcn)) { - return dev->tbusy; + status->imask |= INTR_ON_TIMER; + if (udp_type == UDP_XPIPE_TYPE){ + chan->if_send_stat.if_send_PIPE_request++; + } + } + start_net_queue(dev); + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + S508_S514_unlock(card, &smp_flags); + return 0; } - /* Below is only until we have per-channel IPX going.... */ - if(!(chan->svc)) - chan->protocol = skb->protocol; + if (chan->transmit_length){ + //FIXME: This check doesn't make sense any more + if (chan->common.state != WAN_CONNECTED){ + chan->transmit_length=0; + atomic_set(&chan->common.driver_busy,0); + }else{ + stop_net_queue(dev); + ++card->u.x.tx_interrupts_pending; + status->imask |= INTR_ON_TX_FRAME; + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + S508_S514_unlock(card, &smp_flags); + return 1; + } + } - if (card->wandev.state != WAN_CONNECTED) + if (card->wandev.state != WAN_CONNECTED){ ++chan->ifstats.tx_dropped; - - /* Below is only until we have per-channel IPX going.... */ - else if ( (chan->svc) && (chan->protocol && (chan->protocol != skb->protocol))) - { + ++card->wandev.stats.tx_dropped; + ++chan->if_send_stat.if_send_wan_disconnected; + + }else if ( chan->protocol && (chan->protocol != skb->protocol)){ printk(KERN_INFO "%s: unsupported Ethertype 0x%04X on interface %s!\n", - card->devname, skb->protocol, dev->name); + chan->name, htons(skb->protocol), dev->name); + + printk(KERN_INFO "PROTO %Xn", htons(chan->protocol)); ++chan->ifstats.tx_errors; - } - else switch (chan->state) - { + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + ++chan->if_send_stat.if_send_protocol_error; + + }else switch (chan->common.state){ + case WAN_DISCONNECTED: /* Try to establish connection. If succeded, then start * transmission, else drop a packet. */ - if (chan_connect(dev) != 0) - { + if (chan->common.usedby == API){ ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; break; + }else{ + if (chan_connect(dev) != 0){ + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + break; + } } /* fall through */ case WAN_CONNECTED: - if( skb->protocol == ETH_P_IPX ) - { - if(card->wandev.enable_IPX) - { + if( skb->protocol == htons(ETH_P_IPX)) { + if(chan->enable_IPX) { switch_net_numbers( skb->data, - card->wandev.network_number, 0); - } - else - { + chan->network_number, 0); + } else { ++card->wandev.stats.tx_dropped; ++chan->ifstats.tx_dropped; - goto tx_done; + ++chan->if_send_stat.if_send_protocol_error; + goto if_send_crit_exit; } } - dev->trans_start = jiffies; - if(chan_send(dev, skb)) - { - dev->tbusy = 1; - status->imask |= 0x2; - } + /* We never drop here, if cannot send than, copy + * a packet into a transmit buffer + */ + chan_send(dev, skb->data, skb->len, 0); break; default: ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; + break; } -tx_done: - if (!dev->tbusy) - dev_kfree_skb(skb); - - card->wandev.critical = 0; - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return dev->tbusy; + + +if_send_crit_exit: + + wan_dev_kfree_skb(skb, FREE_WRITE); + + start_net_queue(dev); + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + S508_S514_unlock(card, &smp_flags); + return 0; } /*============================================================================ - * Get Ethernet-style interface statistics. - * Return a pointer to struct net_device_stats - */ - -static struct net_device_stats* if_stats (struct net_device* dev) + * Setup so that a frame can be transmitted on the occurence of a transmit + * interrupt. + *===========================================================================*/ + +static void setup_for_delayed_transmit (netdevice_t* dev, void* buf, + unsigned len) { - x25_channel_t* chan = dev->priv; - if(chan==NULL) + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + TX25Status* status = card->flags; + + ++chan->if_send_stat.if_send_adptr_bfrs_full; + + if(chan->transmit_length) { + printk(KERN_INFO "%s: Error, transmit length set in delayed transmit!\n", + card->devname); + return; + } + + if (chan->common.usedby == API){ + if (len > X25_CHAN_MTU+sizeof(x25api_hdr_t)) { + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + printk(KERN_INFO "%s: Length is too big for delayed transmit\n", + card->devname); + return; + } + }else{ + if (len > X25_MAX_DATA) { + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + printk(KERN_INFO "%s: Length is too big for delayed transmit\n", + card->devname); + return; + } + } + + chan->transmit_length = len; + atomic_set(&chan->common.driver_busy,1); + memcpy(chan->transmit_buffer, buf, len); + + ++chan->if_send_stat.if_send_tx_int_enabled; + + /* Enable Transmit Interrupt */ + ++card->u.x.tx_interrupts_pending; + status->imask |= INTR_ON_TX_FRAME; +} + + +/*=============================================================== + * net_device_stats + * + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + * + *==============================================================*/ +static struct net_device_stats *if_stats (netdevice_t* dev) +{ + x25_channel_t *chan = dev->priv; + + if(chan == NULL) return NULL; + return &chan->ifstats; } -/****** Interrupt Handlers **************************************************/ -/*============================================================================ +/* + * Interrupt Handlers + */ + +/* * X.25 Interrupt Service Routine. */ - + static void wpx_isr (sdla_t* card) { TX25Status* status = card->flags; - struct net_device *dev; - unsigned long host_cpu_flags; card->in_isr = 1; - card->buff_int_mode_unbusy = 0; + ++card->statistics.isr_entry; - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - { + if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){ + card->in_isr=0; + status->iflags = 0; + return; + } + + if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)){ - printk(KERN_INFO "wpx_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, status->iflags); + printk(KERN_INFO "%s: wpx_isr: wandev.critical set to 0x%02lx, int type = 0x%02x\n", + card->devname, card->wandev.critical, status->iflags); card->in_isr = 0; + status->iflags = 0; return; } @@ -863,92 +1700,62 @@ * If the if_send routine is called with this flag set it will set * the enable transmit flag to 1. (for a delayed interrupt) */ - card->wandev.critical = CRITICAL_IN_ISR; + switch (status->iflags){ - switch (status->iflags) - { - case 0x01: /* receive interrupt */ + case RX_INTR_PENDING: /* receive interrupt */ rx_intr(card); break; - case 0x02: /* transmit interrupt */ + case TX_INTR_PENDING: /* transmit interrupt */ tx_intr(card); - card->buff_int_mode_unbusy = 1; - status->imask &= ~0x2; break; - case 0x04: /* modem status interrupt */ + case MODEM_INTR_PENDING: /* modem status interrupt */ status_intr(card); break; - case 0x10: /* network event interrupt */ + case X25_ASY_TRANS_INTR_PENDING: /* network event interrupt */ event_intr(card); break; + case TIMER_INTR_PENDING: + timer_intr(card); + break; + default: /* unwanted interrupt */ spur_intr(card); } - card->wandev.critical = CRITICAL_INTR_HANDLED; - if( card->wandev.enable_tx_int) - { - card->wandev.enable_tx_int = 0; - status->imask |= 0x2; - } - save_flags(host_cpu_flags); - cli(); + card->in_isr = 0; status->iflags = 0; /* clear interrupt condition */ - card->wandev.critical = 0; - restore_flags(host_cpu_flags); - - if(card->buff_int_mode_unbusy) - { - x25_channel_t *chan; - - dev = card->wandev.dev; - while (dev) { - chan = dev->priv; - if(chan->devtint) { - mark_bh(NET_BH); - return; - } - - dev = chan->slave; - } - } } -/*============================================================================ - * Receive interrupt handler. - * This routine handles fragmented IP packets using M-bit according to the - * RFC1356. - * o map ligical channel number to network interface. - * o allocate socket buffer or append received packet to the existing one. - * o if M-bit is reset (i.e. it's the last packet in a sequence) then - * decapsulate packet and pass socket buffer to the protocol stack. - * - * Notes: - * 1. When allocating a socket buffer, if M-bit is set then more data is - * coming and we have to allocate buffer for the maximum IP packet size - * expected on this channel. - * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no - * socket buffers available) the whole packet sequence must be discarded. +/* + * Receive interrupt handler. + * This routine handles fragmented IP packets using M-bit according to the + * RFC1356. + * o map ligical channel number to network interface. + * o allocate socket buffer or append received packet to the existing one. + * o if M-bit is reset (i.e. it's the last packet in a sequence) then + * decapsulate packet and pass socket buffer to the protocol stack. + * + * Notes: + * 1. When allocating a socket buffer, if M-bit is set then more data is + * coming and we have to allocate buffer for the maximum IP packet size + * expected on this channel. + * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no + * socket buffers available) the whole packet sequence must be discarded. */ static void rx_intr (sdla_t* card) { TX25Mbox* rxmb = card->rxmb; - unsigned lcn = rxmb->cmd.lcn; /* logical channel number */ - unsigned len = rxmb->cmd.length; /* packet length */ - unsigned qdm = rxmb->cmd.qdm; /* Q,D and M bits */ - wan_device_t* wandev = &card->wandev; - struct net_device* dev = get_dev_by_lcn(wandev, lcn); + unsigned lcn = rxmb->cmd.lcn; + netdevice_t* dev = find_channel(card,lcn); x25_channel_t* chan; - struct sk_buff* skb; - void* bufptr; + struct sk_buff* skb=NULL; - if (dev == NULL) - { + if (dev == NULL){ /* Invalid channel, discard packet */ printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n", card->devname, lcn); @@ -957,171 +1764,565 @@ chan = dev->priv; chan->i_timeout_sofar = jiffies; - if (chan->drop_sequence) - { - if (!(qdm & 0x01)) chan->drop_sequence = 0; + + + /* Copy the data from the board, into an + * skb buffer + */ + if (wanpipe_pull_data_in_skb(card,dev,&skb)){ + ++chan->ifstats.rx_dropped; + ++card->wandev.stats.rx_dropped; + ++chan->rx_intr_stat.rx_intr_no_socket; + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; return; } - skb = chan->rx_skb; - if (skb == NULL) - { - /* Allocate new socket buffer */ - int bufsize = (qdm & 0x01) ? dev->mtu : len; + dev->last_rx = jiffies; /* timestamp */ - skb = dev_alloc_skb(bufsize + dev->hard_header_len); - if (skb == NULL) - { - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - chan->drop_sequence = 1; /* set flag */ + + /* ------------ API ----------------*/ + + if (chan->common.usedby == API){ + + if (bh_enqueue(dev, skb)){ ++chan->ifstats.rx_dropped; + ++card->wandev.stats.rx_dropped; + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; + wan_dev_kfree_skb(skb, FREE_READ); return; - } - skb->dev = dev; - skb->protocol = htons(chan->protocol); - chan->rx_skb = skb; - } + } - if (skb_tailroom(skb) < len) - { - /* No room for the packet. Call off the whole thing! */ - dev_kfree_skb(skb); - chan->rx_skb = NULL; - if (qdm & 0x01) chan->drop_sequence = 1; + ++chan->ifstats.rx_packets; +#if defined(LINUX_2_1) || defined(LINUX_2_4) + chan->ifstats.rx_bytes += skb->len; +#endif + - printk(KERN_INFO "%s: unexpectedly long packet sequence " - "on interface %s!\n", card->devname, dev->name); - ++chan->ifstats.rx_length_errors; + chan->rx_skb = NULL; + if (!test_and_set_bit(0, &chan->tq_working)){ + wanpipe_queue_tq(&chan->common.wanpipe_task); + wanpipe_mark_bh(); + } return; } - /* Append packet to the socket buffer */ - bufptr = skb_put(skb, len); - memcpy(bufptr, rxmb->data, len); - - if (qdm & 0x01) - return; /* more data is coming */ - - dev->last_rx = jiffies; /* timestamp */ - chan->rx_skb = NULL; /* dequeue packet */ + /* ------------- WANPIPE -------------------*/ + + /* set rx_skb to NULL so we won't access it later when kernel already owns it */ + chan->rx_skb=NULL; + /* Decapsulate packet, if necessary */ - if (!skb->protocol && !wanrouter_type_trans(skb, dev)) - { + if (!skb->protocol && !wanrouter_type_trans(skb, dev)){ /* can't decapsulate packet */ - dev_kfree_skb(skb); + wan_dev_kfree_skb(skb, FREE_READ); ++chan->ifstats.rx_errors; - } - else - { - if( handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) - { - if( card->wandev.enable_IPX ) - { - if(chan_send(dev, skb)) - { + ++chan->ifstats.rx_dropped; + ++card->wandev.stats.rx_dropped; + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; + + }else{ + if( handle_IPXWAN(skb->data, chan->name, + chan->enable_IPX, chan->network_number, + skb->protocol)){ + + if( chan->enable_IPX ){ + if(chan_send(dev, skb->data, skb->len,0)){ chan->tx_skb = skb; + }else{ + wan_dev_kfree_skb(skb, FREE_WRITE); + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; } - else - { - dev_kfree_skb(skb); - } + }else{ + /* increment IPX packet dropped statistic */ + ++chan->ifstats.rx_dropped; + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; } - else - { - /* FIXME: increment IPX packet dropped statistic */ - } - } - else - { - netif_rx(skb); - ++chan->ifstats.rx_packets; + }else{ + skb->mac.raw = skb->data; +#if defined(LINUX_2_1) || defined(LINUX_2_4) chan->ifstats.rx_bytes += skb->len; +#endif + ++chan->ifstats.rx_packets; + ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack; + netif_rx(skb); } } + + return; } -/*============================================================================ - * Transmit interrupt handler. - * o Release socket buffer - * o Clear 'tbusy' flag - */ -static void tx_intr (sdla_t* card) +static int wanpipe_pull_data_in_skb (sdla_t *card, netdevice_t *dev, struct sk_buff **skb) { - struct net_device *dev; - x25_channel_t *chan; + void *bufptr; + TX25Mbox* rxmb = card->rxmb; + unsigned len = rxmb->cmd.length; /* packet length */ + unsigned qdm = rxmb->cmd.qdm; /* Q,D and M bits */ + x25_channel_t *chan = dev->priv; + struct sk_buff *new_skb = *skb; + + if (chan->common.usedby == WANPIPE){ + if (chan->drop_sequence){ + if (!(qdm & 0x01)){ + chan->drop_sequence = 0; + } + return 1; + } + new_skb = chan->rx_skb; + }else{ + /* Add on the API header to the received + * data + */ + len += sizeof(x25api_hdr_t); + } - /* unbusy all devices and then dev_tint(); */ - dev = card->wandev.dev; - while (dev) { - chan->devtint = dev->tbusy; - dev->tbusy = 0; + if (new_skb == NULL){ + int bufsize; - dev = chan->slave; + if (chan->common.usedby == WANPIPE){ + bufsize = (qdm & 0x01) ? dev->mtu : len; + }else{ + bufsize = len; + } + + /* Allocate new socket buffer */ + new_skb = dev_alloc_skb(bufsize + dev->hard_header_len); + if (new_skb == NULL){ + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + chan->drop_sequence = 1; /* set flag */ + ++chan->ifstats.rx_dropped; + return 1; + } } -} + if (skb_tailroom(new_skb) < len){ + /* No room for the packet. Call off the whole thing! */ + wan_dev_kfree_skb(new_skb, FREE_READ); + if (chan->common.usedby == WANPIPE){ + chan->rx_skb = NULL; + if (qdm & 0x01){ + chan->drop_sequence = 1; + } + } -/*============================================================================ - * Modem status interrupt handler. - */ -static void status_intr (sdla_t* card) -{ -} + printk(KERN_INFO "%s: unexpectedly long packet sequence " + "on interface %s!\n", card->devname, dev->name); + ++chan->ifstats.rx_length_errors; + return 1; + } -/*============================================================================ - * Network event interrupt handler. - */ -static void event_intr (sdla_t* card) -{ -} + bufptr = skb_put(new_skb,len); -/*============================================================================ - * Spurious interrupt handler. - * o print a warning - * o - * If number of spurious interrupts exceeded some limit, then ??? - */ -static void spur_intr (sdla_t* card) -{ - printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); -} -/****** Background Polling Routines ****************************************/ + if (chan->common.usedby == API){ + /* Fill in the x25api header + */ + x25api_t * api_data = (x25api_t*)bufptr; + api_data->hdr.qdm = rxmb->cmd.qdm; + api_data->hdr.cause = rxmb->cmd.cause; + api_data->hdr.diagn = rxmb->cmd.diagn; + api_data->hdr.length = rxmb->cmd.length; + memcpy(api_data->data, rxmb->data, rxmb->cmd.length); + }else{ + memcpy(bufptr, rxmb->data, len); + } + + new_skb->dev = dev; + + if (chan->common.usedby == API){ + new_skb->mac.raw = new_skb->data; + new_skb->protocol = htons(X25_PROT); + new_skb->pkt_type = WAN_PACKET_DATA; + }else{ + new_skb->protocol = chan->protocol; + chan->rx_skb = new_skb; + } + + /* If qdm bit is set, more data is coming + * thus, exit and wait for more data before + * sending the packet up. (Used by router only) + */ + if ((qdm & 0x01) && (chan->common.usedby == WANPIPE)) + return 1; + + *skb = new_skb; -/*============================================================================ - * Main polling routine. - * This routine is repeatedly called by the WANPIPE 'thread' to allow for - * time-dependent housekeeping work. + return 0; +} + +/*=============================================================== + * tx_intr + * + * Transmit interrupt handler. + * For each dev, check that there is something to send. + * If data available, transmit. * - * Notes: - * 1. This routine may be called on interrupt context with all interrupts - * enabled. Beware! - */ + *===============================================================*/ -static void wpx_poll (sdla_t* card) +static void tx_intr (sdla_t* card) { - unsigned long host_cpu_flags; - - disable_irq(card->hw.irq); - ++card->irq_dis_poll_count; + netdevice_t *dev; + TX25Status* status = card->flags; + unsigned char more_to_tx=0; + x25_channel_t *chan=NULL; + int i=0; - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - { - printk(KERN_INFO "%s: critical in polling!\n",card->devname); - save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && - (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return; + if (card->u.x.tx_dev == NULL){ + card->u.x.tx_dev = card->wandev.dev; } - switch(card->wandev.state) - { + dev = card->u.x.tx_dev; + + for (;;){ + + chan = dev->priv; + if (chan->transmit_length){ + /* Device was set to transmit, check if the TX + * buffers are available + */ + if (chan->common.state != WAN_CONNECTED){ + chan->transmit_length = 0; + atomic_set(&chan->common.driver_busy,0); + chan->tx_offset=0; + if (is_queue_stopped(dev)){ + if (chan->common.usedby == API){ + start_net_queue(dev); + wakeup_sk_bh(dev); + }else{ + wake_net_dev(dev); + } + } + dev = move_dev_to_next(card,dev); + break; + } + + if ((status->cflags[chan->ch_idx] & 0x40 || card->u.x.LAPB_hdlc) && + (*card->u.x.hdlc_buf_status & 0x40) ){ + /* Tx buffer available, we can send */ + + if (tx_intr_send(card, dev)){ + more_to_tx=1; + } + + /* If more than one interface present, move the + * device pointer to the next interface, so on the + * next TX interrupt we will try sending from it. + */ + dev = move_dev_to_next(card,dev); + break; + }else{ + /* Tx buffers not available, but device set + * the TX interrupt. Set more_to_tx and try + * to transmit for other devices. + */ + more_to_tx=1; + dev = move_dev_to_next(card,dev); + } + + }else{ + /* This device was not set to transmit, + * go to next + */ + dev = move_dev_to_next(card,dev); + } + + if (++i == card->u.x.no_dev){ + if (!more_to_tx){ + DBG_PRINTK(KERN_INFO "%s: Nothing to Send in TX INTR\n", + card->devname); + } + break; + } + + } //End of FOR + + card->u.x.tx_dev = dev; + + if (!more_to_tx){ + /* if any other interfaces have transmit interrupts pending, */ + /* do not disable the global transmit interrupt */ + if (!(--card->u.x.tx_interrupts_pending)){ + status->imask &= ~INTR_ON_TX_FRAME; + } + } + return; +} + +/*=============================================================== + * move_dev_to_next + * + * + *===============================================================*/ + + +netdevice_t * move_dev_to_next (sdla_t *card, netdevice_t *dev) +{ + if (card->u.x.no_dev != 1){ + if (*((netdevice_t**)dev->priv) == NULL){ + return card->wandev.dev; + }else{ + return *((netdevice_t**)dev->priv); + } + } + return dev; +} + +/*=============================================================== + * tx_intr_send + * + * + *===============================================================*/ + +static int tx_intr_send(sdla_t *card, netdevice_t *dev) +{ + x25_channel_t* chan = dev->priv; + + if (chan_send (dev,chan->transmit_buffer,chan->transmit_length,1)){ + + /* Packet was split up due to its size, do not disable + * tx_intr + */ + return 1; + } + + chan->transmit_length=0; + atomic_set(&chan->common.driver_busy,0); + chan->tx_offset=0; + + /* If we are in API mode, wakeup the + * sock BH handler, not the NET_BH */ + if (is_queue_stopped(dev)){ + if (chan->common.usedby == API){ + start_net_queue(dev); + wakeup_sk_bh(dev); + }else{ + wake_net_dev(dev); + } + } + return 0; +} + + +/*=============================================================== + * timer_intr + * + * Timer interrupt handler. + * Check who called the timer interrupt and perform + * action accordingly. + * + *===============================================================*/ + +static void timer_intr (sdla_t *card) +{ + TX25Status* status = card->flags; + + if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC){ + + if (timer_intr_cmd_exec(card) == 0){ + card->u.x.timer_int_enabled &= + ~TMR_INT_ENABLED_CMD_EXEC; + } + + }else if(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UDP_PKT) { + + if ((*card->u.x.hdlc_buf_status & 0x40) && + card->u.x.udp_type == UDP_XPIPE_TYPE){ + + if(process_udp_mgmt_pkt(card)) { + card->u.x.timer_int_enabled &= + ~TMR_INT_ENABLED_UDP_PKT; + } + } + + }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_ACTIVE) { + + netdevice_t *dev = card->u.x.poll_device; + x25_channel_t *chan = NULL; + + if (!dev){ + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE; + return; + } + chan = dev->priv; + + printk(KERN_INFO + "%s: Closing down Idle link %s on LCN %d\n", + card->devname,chan->name,chan->common.lcn); + chan->i_timeout_sofar = jiffies; + chan_disc(dev); + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE; + card->u.x.poll_device=NULL; + + }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_ON) { + + wanpipe_set_state(card, WAN_CONNECTED); + if (card->u.x.LAPB_hdlc){ + netdevice_t *dev = card->wandev.dev; + set_chan_state(dev,WAN_CONNECTED); + send_delayed_cmd_result(card,dev,card->mbox); + } + + /* 0x8F enable all interrupts */ + x25_set_intr_mode(card, INTR_ON_RX_FRAME| + INTR_ON_TX_FRAME| + INTR_ON_MODEM_STATUS_CHANGE| + //INTR_ON_COMMAND_COMPLETE| + X25_ASY_TRANS_INTR_PENDING | + INTR_ON_TIMER | + DIRECT_RX_INTR_USAGE + ); + + status->imask &= ~INTR_ON_TX_FRAME; /* mask Tx interrupts */ + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_ON; + + }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_OFF) { + + //printk(KERN_INFO "Poll connect, Turning OFF\n"); + disconnect(card); + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_OFF; + + }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_DISCONNECT) { + + //printk(KERN_INFO "POll disconnect, trying to connect\n"); + connect(card); + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_DISCONNECT; + + }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE){ + + if (*card->u.x.hdlc_buf_status & 0x40){ + x25_get_err_stats(card); + x25_get_stats(card); + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; + } + } + + if(!card->u.x.timer_int_enabled){ + //printk(KERN_INFO "Turning Timer Off \n"); + status->imask &= ~INTR_ON_TIMER; + } +} + +/*==================================================================== + * Modem status interrupt handler. + *===================================================================*/ +static void status_intr (sdla_t* card) +{ + + /* Added to avoid Modem status message flooding */ + static TX25ModemStatus last_stat; + + TX25Mbox* mbox = card->mbox; + TX25ModemStatus *modem_status; + netdevice_t *dev; + x25_channel_t *chan; + int err; + + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.command = X25_READ_MODEM_STATUS; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err){ + x25_error(card, err, X25_READ_MODEM_STATUS, 0); + }else{ + + modem_status = (TX25ModemStatus*)mbox->data; + + /* Check if the last status was the same + * if it was, do NOT print message again */ + + if (last_stat.status != modem_status->status){ + + printk(KERN_INFO "%s: Modem Status Change: DCD=%s, CTS=%s\n", + card->devname,DCD(modem_status->status),CTS(modem_status->status)); + + last_stat.status = modem_status->status; + + if (card->u.x.oob_on_modem){ + + mbox->cmd.pktType = mbox->cmd.command; + mbox->cmd.result = 0x08; + + /* Send a OOB to all connected sockets */ + for (dev = card->wandev.dev; dev; dev = *((netdevice_t**)dev->priv)){ + chan=dev->priv; + if (chan->common.usedby == API){ + send_oob_msg(card,dev,mbox); + } + } + + /* The modem OOB message will probably kill the + * the link. If we don't clear the flag here, + * a deadlock could occur */ + if (atomic_read(&card->u.x.command_busy)){ + atomic_set(&card->u.x.command_busy,0); + } + } + } + } + + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.command = X25_HDLC_LINK_STATUS; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err){ + x25_error(card, err, X25_HDLC_LINK_STATUS, 0); + } + +} + +/*==================================================================== + * Network event interrupt handler. + *===================================================================*/ +static void event_intr (sdla_t* card) +{ + x25_fetch_events(card); +} + +/*==================================================================== + * Spurious interrupt handler. + * o print a warning + * o + *====================================================================*/ + +static void spur_intr (sdla_t* card) +{ + printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); +} + + +/* + * Background Polling Routines + */ + +/*==================================================================== + * Main polling routine. + * This routine is repeatedly called by the WANPIPE 'thead' to allow for + * time-dependent housekeeping work. + * + * Notes: + * 1. This routine may be called on interrupt context with all interrupts + * enabled. Beware! + *====================================================================*/ + +static void wpx_poll (sdla_t *card) +{ + if (!card->wandev.dev){ + goto wpx_poll_exit; + } + + if (card->open_cnt != card->u.x.num_of_ch){ + goto wpx_poll_exit; + } + + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + goto wpx_poll_exit; + } + + if (test_bit(SEND_CRIT,&card->wandev.critical)){ + goto wpx_poll_exit; + } + + switch(card->wandev.state){ case WAN_CONNECTED: poll_active(card); break; @@ -1132,104 +2333,172 @@ case WAN_DISCONNECTED: poll_disconnected(card); + break; } - card->wandev.critical = 0; - save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + +wpx_poll_exit: + clear_bit(POLL_CRIT,&card->wandev.critical); + return; } -/*============================================================================ - * Handle physical link establishment phase. - * o if connection timed out, disconnect the link. - */ +static void trigger_x25_poll(sdla_t *card) +{ +#ifdef LINUX_2_4 + schedule_task(&card->u.x.x25_poll_task); +#else + queue_task(&card->u.x.x25_poll_task, &tq_scheduler); +#endif +} + +/*==================================================================== + * Handle physical link establishment phase. + * o if connection timed out, disconnect the link. + *===================================================================*/ + static void poll_connecting (sdla_t* card) { - TX25Status* status = card->flags; + volatile TX25Status* status = card->flags; + + if (status->gflags & X25_HDLC_ABM){ + + timer_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_ON); + + }else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT){ + + timer_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_OFF); - if (status->gflags & X25_HDLC_ABM) - { - wanpipe_set_state(card, WAN_CONNECTED); - x25_set_intr_mode(card, 0x83); /* enable Rx interrupts */ - status->imask &= ~0x2; /* mask Tx interrupts */ } - else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT) - disconnect(card); } -/*============================================================================ - * Handle physical link disconnected phase. - * o if hold-down timeout has expired and there are open interfaces, connect - * link. - */ +/*==================================================================== + * Handle physical link disconnected phase. + * o if hold-down timeout has expired and there are open interfaces, + * connect link. + *===================================================================*/ + static void poll_disconnected (sdla_t* card) { - if (card->open_cnt && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) - connect(card); + netdevice_t *dev; + x25_channel_t *chan; + TX25Status* status = card->flags; + + if (!card->u.x.LAPB_hdlc && card->open_cnt && + ((jiffies - card->state_tick) > HOLD_DOWN_TIME)){ + timer_intr_exec(card, TMR_INT_ENABLED_POLL_DISCONNECT); + } + + + if ((dev=card->wandev.dev) == NULL) + return; + + if ((chan=dev->priv) == NULL) + return; + + if (chan->common.usedby == API && + atomic_read(&chan->common.command) && + card->u.x.LAPB_hdlc){ + + if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) + card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; + + if (!(status->imask & INTR_ON_TIMER)) + status->imask |= INTR_ON_TIMER; + } + } -/*============================================================================ - * Handle active link phase. - * o fetch X.25 asynchronous events. - * o kick off transmission on all interfaces. - */ +/*==================================================================== + * Handle active link phase. + * o fetch X.25 asynchronous events. + * o kick off transmission on all interfaces. + *===================================================================*/ + static void poll_active (sdla_t* card) { - struct net_device* dev; - - /* Fetch X.25 asynchronous events */ - x25_fetch_events(card); + netdevice_t* dev; + TX25Status* status = card->flags; - dev = card->wandev.dev; - while (dev) { + for (dev = card->wandev.dev; dev; dev = *((netdevice_t**)dev->priv)){ x25_channel_t* chan = dev->priv; - struct sk_buff* skb = chan->tx_skb; - - /* If there is a packet queued for transmission then kick - * the channel's send routine. When transmission is complete - * or if error has occurred, release socket buffer and reset - * 'tbusy' flag. - */ - if (skb && (chan_send(dev, skb) == 0)) - { - chan->tx_skb = NULL; - dev->tbusy = 0; - dev_kfree_skb(skb); - } /* If SVC has been idle long enough, close virtual circuit */ - - if(( chan->svc )&&( chan->state == WAN_CONNECTED )) - { - if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout ) - { + if ( chan->common.svc && + chan->common.state == WAN_CONNECTED && + chan->common.usedby == WANPIPE ){ + + if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout ){ /* Close svc */ - printk(KERN_INFO "%s: Closing down Idle link %s on LCN %d\n",card->devname,chan->name,chan->lcn); - chan->i_timeout_sofar = jiffies; - chan_disc(dev); + card->u.x.poll_device=dev; + timer_intr_exec (card, TMR_INT_ENABLED_POLL_ACTIVE); } } - dev = chan->slave; +#ifdef PRINT_DEBUG + chan->ifstats.tx_compressed = atomic_read(&chan->common.command); + chan->ifstats.tx_errors = chan->common.state; + chan->ifstats.rx_fifo_errors = atomic_read(&card->u.x.command_busy); + ++chan->ifstats.tx_bytes; + + chan->ifstats.rx_fifo_errors=atomic_read(&chan->common.disconnect); + chan->ifstats.multicast=atomic_read(&chan->bh_buff_used); + chan->ifstats.rx_length_errors=*card->u.x.hdlc_buf_status; +#endif + + if (chan->common.usedby == API && + atomic_read(&chan->common.command) && + !card->u.x.LAPB_hdlc){ + + if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) + card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; + + if (!(status->imask & INTR_ON_TIMER)) + status->imask |= INTR_ON_TIMER; + } + + if ((chan->common.usedby == API) && + atomic_read(&chan->common.disconnect)){ + + if (chan->common.state == WAN_DISCONNECTED){ + atomic_set(&chan->common.disconnect,0); + return; + } + + atomic_set(&chan->common.command,X25_CLEAR_CALL); + if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) + card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; + + if (!(status->imask & INTR_ON_TIMER)) + status->imask |= INTR_ON_TIMER; + } } } -/****** SDLA Firmware-Specific Functions ************************************* - * Almost all X.25 commands can unexpetedly fail due to so called 'X.25 - * asynchronous events' such as restart, interrupt, incoming call request, - * call clear request, etc. They can't be ignored and have to be dealt with - * immediately. To tackle with this problem we execute each interface command - * in a loop until good return code is received or maximum number of retries - * is reached. Each interface command returns non-zero return code, an - * asynchronous event/error handler x25_error() is called. - */ +static void timer_intr_exec(sdla_t *card, unsigned char TYPE) +{ + TX25Status* status = card->flags; + card->u.x.timer_int_enabled |= TYPE; + if (!(status->imask & INTR_ON_TIMER)) + status->imask |= INTR_ON_TIMER; +} + + +/*==================================================================== + * SDLA Firmware-Specific Functions + * + * Almost all X.25 commands can unexpetedly fail due to so called 'X.25 + * asynchronous events' such as restart, interrupt, incoming call request, + * call clear request, etc. They can't be ignored and have to be delt with + * immediately. To tackle with this problem we execute each interface + * command in a loop until good return code is received or maximum number + * of retries is reached. Each interface command returns non-zero return + * code, an asynchronous event/error handler x25_error() is called. + *====================================================================*/ + +/*==================================================================== + * Read X.25 firmware version. + * Put code version as ASCII string in str. + *===================================================================*/ -/*============================================================================ - * Read X.25 firmware version. - * Put code version as ASCII string in str. - */ static int x25_get_version (sdla_t* card, char* str) { TX25Mbox* mbox = card->mbox; @@ -1247,15 +2516,16 @@ if (!err && str) { int len = mbox->cmd.length; + memcpy(str, mbox->data, len); str[len] = '\0'; } return err; } -/*============================================================================ - * Configure adapter. - */ +/*==================================================================== + * Configure adapter. + *===================================================================*/ static int x25_configure (sdla_t* card, TX25Config* conf) { @@ -1263,8 +2533,7 @@ int retry = MAX_CMD_RETRY; int err; - do - { + do{ memset(&mbox->cmd, 0, sizeof(TX25Cmd)); memcpy(mbox->data, (void*)conf, sizeof(TX25Config)); mbox->cmd.length = sizeof(TX25Config); @@ -1274,9 +2543,51 @@ return err; } -/*============================================================================ +/*==================================================================== + * Configure adapter for HDLC only. + *===================================================================*/ + +static int hdlc_configure (sdla_t* card, TX25Config* conf) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do{ + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + memcpy(mbox->data, (void*)conf, sizeof(TX25Config)); + mbox->cmd.length = sizeof(TX25Config); + mbox->cmd.command = X25_HDLC_SET_CONFIG; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0)); + + return err; +} + +static int set_hdlc_level (sdla_t* card) +{ + + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do{ + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.command = SET_PROTOCOL_LEVEL; + mbox->cmd.length = 1; + mbox->data[0] = HDLC_LEVEL; //| DO_HDLC_LEVEL_ERROR_CHECKING; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && x25_error(card, err, SET_PROTOCOL_LEVEL, 0)); + + return err; +} + + + +/*==================================================================== * Get communications error statistics. - */ + *====================================================================*/ + static int x25_get_err_stats (sdla_t* card) { TX25Mbox* mbox = card->mbox; @@ -1289,7 +2600,7 @@ mbox->cmd.command = X25_HDLC_READ_COMM_ERR; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0)); - + if (!err) { THdlcCommErr* stats = (void*)mbox->data; @@ -1302,9 +2613,10 @@ return err; } -/*============================================================================ - * Get protocol statistics. - */ +/*==================================================================== + * Get protocol statistics. + *===================================================================*/ + static int x25_get_stats (sdla_t* card) { TX25Mbox* mbox = card->mbox; @@ -1316,21 +2628,22 @@ memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->cmd.command = X25_READ_STATISTICS; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0)); + } while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0)) ; if (!err) { TX25Stats* stats = (void*)mbox->data; card->wandev.stats.rx_packets = stats->rxData; - card->wandev.stats.tx_packets = stats->rxData; + card->wandev.stats.tx_packets = stats->txData; } return err; } -/*============================================================================ - * Close HDLC link. - */ +/*==================================================================== + * Close HDLC link. + *===================================================================*/ + static int x25_close_hdlc (sdla_t* card) { TX25Mbox* mbox = card->mbox; @@ -1343,13 +2656,15 @@ mbox->cmd.command = X25_HDLC_LINK_CLOSE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_CLOSE, 0)); - + return err; } -/*============================================================================ - * Open HDLC link. - */ + +/*==================================================================== + * Open HDLC link. + *===================================================================*/ + static int x25_open_hdlc (sdla_t* card) { TX25Mbox* mbox = card->mbox; @@ -1362,13 +2677,13 @@ mbox->cmd.command = X25_HDLC_LINK_OPEN; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_OPEN, 0)); - + return err; } -/*============================================================================ +/*===================================================================== * Setup HDLC link. - */ + *====================================================================*/ static int x25_setup_hdlc (sdla_t* card) { TX25Mbox* mbox = card->mbox; @@ -1385,9 +2700,10 @@ return err; } -/*============================================================================ +/*==================================================================== * Set (raise/drop) DTR. - */ + *===================================================================*/ + static int x25_set_dtr (sdla_t* card, int dtr) { TX25Mbox* mbox = card->mbox; @@ -1404,13 +2720,14 @@ mbox->cmd.command = X25_SET_GLOBAL_VARS; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_SET_GLOBAL_VARS, 0)); - + return err; } -/*============================================================================ - * Set interrupt mode. - */ +/*==================================================================== + * Set interrupt mode. + *===================================================================*/ + static int x25_set_intr_mode (sdla_t* card, int mode) { TX25Mbox* mbox = card->mbox; @@ -1421,30 +2738,32 @@ { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->data[0] = mode; - if (card->hw.fwid == SFID_X25_508) - { + if (card->hw.fwid == SFID_X25_508){ mbox->data[1] = card->hw.irq; - mbox->cmd.length = 2; + mbox->data[2] = 2; + mbox->cmd.length = 3; + }else { + mbox->cmd.length = 1; } - else mbox->cmd.length = 1; mbox->cmd.command = X25_SET_INTERRUPT_MODE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)) ; + } while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)); + return err; } -/*============================================================================ - * Read X.25 channel configuration. - */ +/*==================================================================== + * Read X.25 channel configuration. + *===================================================================*/ + static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan) { TX25Mbox* mbox = card->mbox; int retry = MAX_CMD_RETRY; - int lcn = chan->lcn; + int lcn = chan->common.lcn; int err; - do - { + do{ memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->cmd.lcn = lcn; mbox->cmd.command = X25_READ_CHANNEL_CONFIG; @@ -1456,19 +2775,25 @@ TX25Status* status = card->flags; /* calculate an offset into the array of status bytes */ - if (card->u.x.hi_svc <= 255) + if (card->u.x.hi_svc <= X25_MAX_CHAN){ + chan->ch_idx = lcn - 1; - else - { + + }else{ int offset; - switch (mbox->data[0] && 0x1F) + /* FIX: Apr 14 2000 : Nenad Corbic + * The data field was being compared to 0x1F using + * '&&' instead of '&'. + * This caused X25API to fail for LCNs greater than 255. + */ + switch (mbox->data[0] & 0x1F) { - case 0x01: + case 0x01: offset = status->pvc_map; break; - case 0x03: + case 0x03: offset = status->icc_map; break; - case 0x07: + case 0x07: offset = status->twc_map; break; case 0x0B: offset = status->ogc_map; break; @@ -1481,37 +2806,38 @@ /* get actual transmit packet size on this channel */ switch(mbox->data[1] & 0x38) { - case 0x00: - chan->tx_pkt_size = 16; + case 0x00: + chan->tx_pkt_size = 16; break; - case 0x08: - chan->tx_pkt_size = 32; + case 0x08: + chan->tx_pkt_size = 32; break; - case 0x10: - chan->tx_pkt_size = 64; + case 0x10: + chan->tx_pkt_size = 64; break; - case 0x18: - chan->tx_pkt_size = 128; + case 0x18: + chan->tx_pkt_size = 128; break; - case 0x20: - chan->tx_pkt_size = 256; + case 0x20: + chan->tx_pkt_size = 256; break; - case 0x28: - chan->tx_pkt_size = 512; + case 0x28: + chan->tx_pkt_size = 512; break; - case 0x30: - chan->tx_pkt_size = 1024; + case 0x30: + chan->tx_pkt_size = 1024; break; } - printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n", - card->devname, lcn, chan->tx_pkt_size); + if (card->u.x.logging) + printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n", + card->devname, lcn, chan->tx_pkt_size); } return err; } -/*============================================================================ - * Place X.25 call. - */ +/*==================================================================== + * Place X.25 call. + *====================================================================*/ static int x25_place_call (sdla_t* card, x25_channel_t* chan) { @@ -1520,7 +2846,15 @@ int err; char str[64]; - sprintf(str, "-d%s -uCC", chan->addr); + + if (chan->protocol == htons(ETH_P_IP)){ + sprintf(str, "-d%s -uCC", chan->addr); + + }else if (chan->protocol == htons(ETH_P_IPX)){ + sprintf(str, "-d%s -u800000008137", chan->addr); + + } + do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); @@ -1530,17 +2864,15 @@ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_PLACE_CALL, 0)); - if (!err) - { - chan->lcn = mbox->cmd.lcn; - chan->protocol = ETH_P_IP; + if (!err){ + bind_lcn_to_dev (card, chan->dev, mbox->cmd.lcn); } return err; } -/*============================================================================ - * Accept X.25 call. - */ +/*==================================================================== + * Accept X.25 call. + *====================================================================*/ static int x25_accept_call (sdla_t* card, int lcn, int qdm) { @@ -1556,13 +2888,14 @@ mbox->cmd.command = X25_ACCEPT_CALL; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_ACCEPT_CALL, lcn)); - + return err; } -/*============================================================================ - * Clear X.25 call. - */ +/*==================================================================== + * Clear X.25 call. + *====================================================================*/ + static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn) { TX25Mbox* mbox = card->mbox; @@ -1578,35 +2911,59 @@ mbox->cmd.command = X25_CLEAR_CALL; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_CLEAR_CALL, lcn)); - + return err; } -/*============================================================================ - * Send X.25 data packet. - */ +/*==================================================================== + * Send X.25 data packet. + *====================================================================*/ + static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf) { TX25Mbox* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - + unsigned char cmd; + + if (card->u.x.LAPB_hdlc) + cmd = X25_HDLC_WRITE; + else + cmd = X25_WRITE; + do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); memcpy(mbox->data, buf, len); mbox->cmd.length = len; mbox->cmd.lcn = lcn; - mbox->cmd.qdm = qdm; - mbox->cmd.command = X25_WRITE; + + if (card->u.x.LAPB_hdlc){ + mbox->cmd.pf = qdm; + }else{ + mbox->cmd.qdm = qdm; + } + + mbox->cmd.command = cmd; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_WRITE, lcn)); + } while (err && retry-- && x25_error(card, err, cmd , lcn)); + + + /* If buffers are busy the return code for LAPB HDLC is + * 1. The above functions are looking for return code + * of X25RES_NOT_READY if busy. */ + + if (card->u.x.LAPB_hdlc && err == 1){ + err = X25RES_NOT_READY; + } + return err; } -/*============================================================================ - * Fetch X.25 asynchronous events. - */ +/*==================================================================== + * Fetch X.25 asynchronous events. + *===================================================================*/ + static int x25_fetch_events (sdla_t* card) { TX25Status* status = card->flags; @@ -1618,25 +2975,26 @@ memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->cmd.command = X25_IS_DATA_AVAILABLE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - x25_error(card, err, X25_IS_DATA_AVAILABLE, 0); + if (err) x25_error(card, err, X25_IS_DATA_AVAILABLE, 0); } return err; } -/*============================================================================ - * X.25 asynchronous event/error handler. - * This routine is called each time interface command returns non-zero - * return code to handle X.25 asynchronous events and common errors. - * Return non-zero to repeat command or zero to cancel it. - * - * Notes: - * 1. This function may be called recursively, as handling some of the - * asynchronous events (e.g. call request) requires execution of the - * interface command(s) that, in turn, may also return asynchronous - * events. To avoid re-entrancy problems we copy mailbox to dynamically - * allocated memory before processing events. - */ +/*==================================================================== + * X.25 asynchronous event/error handler. + * This routine is called each time interface command returns + * non-zero return code to handle X.25 asynchronous events and + * common errors. Return non-zero to repeat command or zero to + * cancel it. + * + * Notes: + * 1. This function may be called recursively, as handling some of the + * asynchronous events (e.g. call request) requires execution of the + * interface command(s) that, in turn, may also return asynchronous + * events. To avoid re-entrancy problems we copy mailbox to dynamically + * allocated memory before processing events. + *====================================================================*/ + static int x25_error (sdla_t* card, int err, int cmd, int lcn) { int retry = 1; @@ -1651,138 +3009,212 @@ return 0; } memcpy(mb, card->mbox, sizeof(TX25Mbox) + dlen); - switch (err) - { - case 0x40: /* X.25 asynchronous packet was received */ - mb->data[dlen] = '\0'; - switch (mb->cmd.pktType & 0x7F) - { - case 0x30: /* incoming call */ - retry = incoming_call(card, cmd, lcn, mb); - break; - - case 0x31: /* connected */ - retry = call_accepted(card, cmd, lcn, mb); - break; + switch (err){ - case 0x02: /* call clear request */ - retry = call_cleared(card, cmd, lcn, mb); - break; + case X25RES_ASYNC_PACKET: /* X.25 asynchronous packet was received */ - case 0x04: /* reset request */ - printk(KERN_INFO "%s: X.25 reset request on LCN %d! " - "Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.lcn, mb->cmd.cause, - mb->cmd.diagn); - break; + mb->data[dlen] = '\0'; - case 0x08: /* restart request */ - retry = restart_event(card, cmd, lcn, mb); - break; + switch (mb->cmd.pktType & 0x7F){ - default: - printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! " - "Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.pktType, - mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn); - } + case ASE_CALL_RQST: /* incoming call */ + retry = incoming_call(card, cmd, lcn, mb); break; - case 0x41: /* X.25 protocol violation indication */ - printk(KERN_INFO - "%s: X.25 protocol violation on LCN %d! " - "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.lcn, - mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn); + case ASE_CALL_ACCEPTED: /* connected */ + retry = call_accepted(card, cmd, lcn, mb); break; - case 0x42: /* X.25 timeout */ - retry = timeout_event(card, cmd, lcn, mb); + case ASE_CLEAR_RQST: /* call clear request */ + retry = call_cleared(card, cmd, lcn, mb); break; - case 0x43: /* X.25 retry limit exceeded */ - printk(KERN_INFO - "%s: exceeded X.25 retry limit on LCN %d! " - "Packet:0x%02X Diagn:0x%02X\n", card->devname, - mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn); + case ASE_RESET_RQST: /* reset request */ + printk(KERN_INFO "%s: X.25 reset request on LCN %d! " + "Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.lcn, mb->cmd.cause, + mb->cmd.diagn); + api_oob_event (card,mb); break; - case 0x08: /* modem failure */ - printk(KERN_INFO "%s: modem failure!\n", card->devname); + case ASE_RESTART_RQST: /* restart request */ + retry = restart_event(card, cmd, lcn, mb); break; - case 0x09: /* N2 retry limit */ - printk(KERN_INFO "%s: exceeded HDLC retry limit!\n", - card->devname); + case ASE_CLEAR_CONFRM: + if (clear_confirm_event (card,mb)) + break; + + /* I use the goto statement here so if + * somebody inserts code between the + * case and default, we will not have + * ghost problems */ + + goto dflt_1; + + default: +dflt_1: + printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! " + "Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.pktType, + mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn); + } + break; + + case X25RES_PROTO_VIOLATION: /* X.25 protocol violation indication */ + + /* Bug Fix: Mar 14 2000 + * The Protocol violation error conditions were + * not handeled previously */ + + switch (mb->cmd.pktType & 0x7F){ + + case PVE_CLEAR_RQST: /* Clear request */ + retry = call_cleared(card, cmd, lcn, mb); + break; + + case PVE_RESET_RQST: /* Reset request */ + printk(KERN_INFO "%s: X.25 reset request on LCN %d! " + "Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.lcn, mb->cmd.cause, + mb->cmd.diagn); + api_oob_event (card,mb); break; - case 0x06: /* unnumbered frame was received while in ABM */ - printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n", - card->devname, mb->data[0]); + case PVE_RESTART_RQST: /* Restart request */ + retry = restart_event(card, cmd, lcn, mb); break; - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd); - retry = 0; /* abort command */ + default : + printk(KERN_INFO + "%s: X.25 protocol violation on LCN %d! " + "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.lcn, + mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn); + api_oob_event(card,mb); + } + break; + + case 0x42: /* X.25 timeout */ + retry = timeout_event(card, cmd, lcn, mb); + break; + + case 0x43: /* X.25 retry limit exceeded */ + printk(KERN_INFO + "%s: exceeded X.25 retry limit on LCN %d! " + "Packet:0x%02X Diagn:0x%02X\n", card->devname, + mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn) + ; + break; + + case 0x08: /* modem failure */ +#ifndef MODEM_NOT_LOG + printk(KERN_INFO "%s: modem failure!\n", card->devname); +#endif MODEM_NOT_LOG + api_oob_event(card,mb); + break; + + case 0x09: /* N2 retry limit */ + printk(KERN_INFO "%s: exceeded HDLC retry limit!\n", + card->devname); + api_oob_event(card,mb); + break; + + case 0x06: /* unnumbered frame was received while in ABM */ + printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n", + card->devname, mb->data[0]); + api_oob_event(card,mb); + break; + + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, cmd) + ; + retry = 0; /* abort command */ + break; + + case X25RES_NOT_READY: + retry = 1; + break; + + case 0x01: + if (card->u.x.LAPB_hdlc) break; - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", - card->devname, cmd, err); - retry = 0; /* abort command */ + if (mb->cmd.command == 0x16) + break; + /* I use the goto statement here so if + * somebody inserts code between the + * case and default, we will not have + * ghost problems */ + goto dflt_2; + + default: +dflt_2: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X! Lcn %i\n", + card->devname, cmd, err, mb->cmd.lcn) + ; + retry = 0; /* abort command */ } kfree(mb); return retry; } -/****** X.25 Asynchronous Event Handlers ************************************* - * These functions are called by the x25_error() and should return 0, if - * the command resulting in the asynchronous event must be aborted. - */ +/*==================================================================== + * X.25 Asynchronous Event Handlers + * These functions are called by the x25_error() and should return 0, if + * the command resulting in the asynchronous event must be aborted. + *====================================================================*/ -/*============================================================================ - * Handle X.25 incoming call request. + + +/*==================================================================== + *Handle X.25 incoming call request. * RFC 1356 establishes the following rules: * 1. The first octet in the Call User Data (CUD) field of the call - * request packet contains NLPID identifying protocol encapsulation. - * 2. Calls MUST NOT be accepted unless router supports requested - * protocol encapsulation. - * 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used when - * clearing a call because protocol encapsulation is not supported. - * 4. If an incoming call is received while a call request is pending - * (i.e. call collision has occurred), the incoming call shall be - * rejected and call request shall be retried. - */ + * request packet contains NLPID identifying protocol encapsulation + * 2. Calls MUST NOT be accepted unless router supports requested + * protocol encapsulation. + * 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used + * when clearing a call because protocol encapsulation is not + * supported. + * 4. If an incoming call is received while a call request is + * pending (i.e. call collision has occured), the incoming call + * shall be rejected and call request shall be retried. + *====================================================================*/ static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) { wan_device_t* wandev = &card->wandev; int new_lcn = mb->cmd.lcn; - struct net_device* dev = get_dev_by_lcn(wandev, new_lcn); + netdevice_t* dev = get_dev_by_lcn(wandev, new_lcn); x25_channel_t* chan = NULL; int accept = 0; /* set to '1' if o.k. to accept call */ + unsigned int user_data; x25_call_info_t* info; - + /* Make sure there is no call collision */ if (dev != NULL) { printk(KERN_INFO "%s: X.25 incoming call collision on LCN %d!\n", card->devname, new_lcn); + x25_clear_call(card, new_lcn, 0, 0); return 1; } /* Make sure D bit is not set in call request */ - if (mb->cmd.qdm & 0x02) - { - printk(KERN_INFO - "%s: X.25 incoming call on LCN %d with D-bit set!\n", - card->devname, new_lcn); - x25_clear_call(card, new_lcn, 0, 0); - return 1; - } +//FIXME: THIS IS NOT TURE !!!! TAKE IT OUT +// if (mb->cmd.qdm & 0x02) +// { +// printk(KERN_INFO +// "%s: X.25 incoming call on LCN %d with D-bit set!\n", +// card->devname, new_lcn); +// +// x25_clear_call(card, new_lcn, 0, 0); +// return 1; +// } /* Parse call request data */ info = kmalloc(sizeof(x25_call_info_t), GFP_ATOMIC); @@ -1794,90 +3226,120 @@ x25_clear_call(card, new_lcn, 0, 0); return 1; } + parse_call_info(mb->data, info); - printk(KERN_INFO "%s: X.25 incoming call on LCN %d! Call data: %s\n", - card->devname, new_lcn, mb->data); + + if (card->u.x.logging) + printk(KERN_INFO "\n%s: X.25 incoming call on LCN %d!\n", + card->devname, new_lcn); + + /* Conver the first two ASCII characters into an + * interger. Used to check the incoming protocol + */ + user_data = hex_to_uint(info->user,2); /* Find available channel */ - dev = wandev->dev; - while (dev) { + for (dev = wandev->dev; dev; dev = *((netdevice_t**)dev->priv)){ chan = dev->priv; - if (!chan->svc || (chan->state != WAN_DISCONNECTED)) + if (chan->common.usedby == API) + continue; + + if (!chan->common.svc || (chan->common.state != WAN_DISCONNECTED)) + continue; + + if (user_data == NLPID_IP && chan->protocol != htons(ETH_P_IP)){ + printk(KERN_INFO "IP packet but configured for IPX : %x, %x\n", + htons(chan->protocol), info->user[0]); + continue; + } + + if (user_data == NLPID_SNAP && chan->protocol != htons(ETH_P_IPX)){ + printk(KERN_INFO "IPX packet but configured for IP: %x\n", + htons(chan->protocol)); continue; + } if (strcmp(info->src, chan->addr) == 0) break; + /* If just an '@' is specified, accept all incoming calls */ if (strcmp(chan->addr, "") == 0) break; - - dev = chan->slave; } - if (dev == NULL) - { - printk(KERN_INFO "%s: no channels available!\n", - card->devname); - x25_clear_call(card, new_lcn, 0, 0); - } + if (dev == NULL){ + + /* If the call is not for any WANPIPE interfaces + * check to see if there is an API listening queue + * waiting for data. If there is send the packet + * up the stack. + */ + if (card->sk != NULL && card->func != NULL){ + if (api_incoming_call(card,mb,new_lcn)){ + x25_clear_call(card, new_lcn, 0, 0); + } + accept = 0; + }else{ + printk(KERN_INFO "%s: no channels available!\n", + card->devname); + + x25_clear_call(card, new_lcn, 0, 0); + } + + }else if (info->nuser == 0){ - /* Check requested protocol encapsulation */ - else if (info->nuser == 0) - { printk(KERN_INFO "%s: no user data in incoming call on LCN %d!\n", - card->devname, new_lcn); + card->devname, new_lcn) + ; x25_clear_call(card, new_lcn, 0, 0); - } - else switch (info->user[0]) - { + + }else switch (info->user[0]){ + case 0: /* multiplexed */ - chan->protocol = 0; + chan->protocol = htons(0); accept = 1; break; case NLPID_IP: /* IP datagrams */ - chan->protocol = ETH_P_IP; accept = 1; break; case NLPID_SNAP: /* IPX datagrams */ - chan->protocol = ETH_P_IPX; accept = 1; break; + default: printk(KERN_INFO "%s: unsupported NLPID 0x%02X in incoming call " "on LCN %d!\n", card->devname, info->user[0], new_lcn); x25_clear_call(card, new_lcn, 0, 249); } + + if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK)){ - if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK)) - { - chan->lcn = new_lcn; + bind_lcn_to_dev (card, chan->dev, new_lcn); + if (x25_get_chan_conf(card, chan) == CMD_OK) set_chan_state(dev, WAN_CONNECTED); - else + else x25_clear_call(card, new_lcn, 0, 0); } kfree(info); return 1; } -/*============================================================================ - * Handle accepted call. - */ +/*==================================================================== + * Handle accepted call. + *====================================================================*/ static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) { unsigned new_lcn = mb->cmd.lcn; - struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn); + netdevice_t* dev = find_channel(card, new_lcn); x25_channel_t* chan; - printk(KERN_INFO "%s: X.25 call accepted on LCN %d!\n", - card->devname, new_lcn); - if (dev == NULL) - { + if (dev == NULL){ printk(KERN_INFO "%s: clearing orphaned connection on LCN %d!\n", card->devname, new_lcn); @@ -1885,6 +3347,10 @@ return 1; } + if (card->u.x.logging) + printk(KERN_INFO "%s: X.25 call accepted on Dev %s and LCN %d!\n", + card->devname, dev->name, new_lcn); + /* Get channel configuration and notify router */ chan = dev->priv; if (x25_get_chan_conf(card, chan) != CMD_OK) @@ -1892,178 +3358,256 @@ x25_clear_call(card, new_lcn, 0, 0); return 1; } + set_chan_state(dev, WAN_CONNECTED); + + if (chan->common.usedby == API){ + send_delayed_cmd_result(card,dev,mb); + bind_lcn_to_dev (card, dev, new_lcn); + } + return 1; } -/*============================================================================ - * Handle cleared call. - */ +/*==================================================================== + * Handle cleared call. + *====================================================================*/ static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) { unsigned new_lcn = mb->cmd.lcn; - struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn); + netdevice_t* dev = find_channel(card, new_lcn); + x25_channel_t *chan; + unsigned char old_state; - printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X " + if (card->u.x.logging){ + printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X " "Diagn:0x%02X\n", card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn); - if (dev == NULL) + } + + if (dev == NULL){ + printk(KERN_INFO "%s: X.25 clear request : No device for clear\n", + card->devname); return 1; + } + + chan=dev->priv; + + old_state = chan->common.state; + set_chan_state(dev, WAN_DISCONNECTED); + + if (chan->common.usedby == API){ + + switch (old_state){ + + case WAN_CONNECTING: + send_delayed_cmd_result(card,dev,mb); + break; + case WAN_CONNECTED: + send_oob_msg(card,dev,mb); + break; + } + } + return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1; } -/*============================================================================ - * Handle X.25 restart event. - */ - +/*==================================================================== + * Handle X.25 restart event. + *====================================================================*/ + static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) { wan_device_t* wandev = &card->wandev; - struct net_device* dev; + netdevice_t* dev; + x25_channel_t *chan; + unsigned char old_state; printk(KERN_INFO "%s: X.25 restart request! Cause:0x%02X Diagn:0x%02X\n", card->devname, mb->cmd.cause, mb->cmd.diagn); /* down all logical channels */ - dev = wandev->dev; - while (dev) { - x25_channel_t *chan = dev->priv; + for (dev = wandev->dev; dev; dev = *((netdevice_t**)dev->priv)){ + chan=dev->priv; + old_state = chan->common.state; set_chan_state(dev, WAN_DISCONNECTED); - dev = chan->slave; - } + if (chan->common.usedby == API){ + switch (old_state){ + + case WAN_CONNECTING: + send_delayed_cmd_result(card,dev,mb); + break; + case WAN_CONNECTED: + send_oob_msg(card,dev,mb); + break; + } + } + } return (cmd == X25_WRITE) ? 0 : 1; } -/*============================================================================ +/*==================================================================== * Handle timeout event. - */ + *====================================================================*/ + static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) { unsigned new_lcn = mb->cmd.lcn; if (mb->cmd.pktType == 0x05) /* call request time out */ { - struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn); + netdevice_t* dev = find_channel(card,new_lcn); printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n", card->devname, new_lcn); - if (dev) + + if (dev){ + x25_channel_t *chan = dev->priv; set_chan_state(dev, WAN_DISCONNECTED); - } - else printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n", + + if (chan->common.usedby == API){ + send_delayed_cmd_result(card,dev,card->mbox); + } + } + }else{ + printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n", card->devname, mb->cmd.pktType, new_lcn); + } return 1; } -/******* Miscellaneous ******************************************************/ +/* + * Miscellaneous + */ -/*============================================================================ - * Establish physical connection. - * o open HDLC and raise DTR +/*==================================================================== + * Establish physical connection. + * o open HDLC and raise DTR * - * Return: 0 connection established - * 1 connection is in progress - * <0 error - */ + * Return: 0 connection established + * 1 connection is in progress + * <0 error + *===================================================================*/ + static int connect (sdla_t* card) { + TX25Status* status = card->flags; + if (x25_open_hdlc(card) || x25_setup_hdlc(card)) return -EIO; + wanpipe_set_state(card, WAN_CONNECTING); + + x25_set_intr_mode(card, INTR_ON_TIMER); + status->imask &= ~INTR_ON_TIMER; + return 1; } -/*============================================================================ - * Tear down physical connection. - * o close HDLC link - * o drop DTR +/* + * Tear down physical connection. + * o close HDLC link + * o drop DTR * - * Return: 0 - * <0 error + * Return: 0 + * <0 error */ + static int disconnect (sdla_t* card) { wanpipe_set_state(card, WAN_DISCONNECTED); - x25_set_intr_mode(card, 0); /* disable interrupt generation */ - x25_close_hdlc(card); /* close HDLC link */ - x25_set_dtr(card, 0); /* drop DTR */ + x25_set_intr_mode(card, INTR_ON_TIMER); /* disable all interrupt except timer */ + x25_close_hdlc(card); /* close HDLC link */ + x25_set_dtr(card, 0); /* drop DTR */ return 0; } -/*============================================================================ +/* * Find network device by its channel number. */ -static struct net_device* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn) + +static netdevice_t* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn) { - struct net_device* dev; - x25_channel_t *chan; + netdevice_t* dev; - dev = wandev->dev; - while (dev) { - if (chan->lcn == lcn) + for (dev = wandev->dev; dev; dev = *((netdevice_t**)dev->priv)) + if (((x25_channel_t*)dev->priv)->common.lcn == lcn) break; - dev = chan->slave; - } return dev; } -/*============================================================================ - * Initiate connection on the logical channel. - * o for PVC we just get channel configuration - * o for SVCs place an X.25 call - * - * Return: 0 connected - * >0 connection in progress - * <0 failure +/* + * Initiate connection on the logical channel. + * o for PVC we just get channel configuration + * o for SVCs place an X.25 call + * + * Return: 0 connected + * >0 connection in progress + * <0 failure */ -static int chan_connect (struct net_device* dev) + +static int chan_connect (netdevice_t* dev) { x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; - if (chan->svc) - { - if (!chan->addr[0]) + if (chan->common.svc && chan->common.usedby == WANPIPE){ + if (!chan->addr[0]){ + printk(KERN_INFO "%s: No Destination Address\n", + card->devname); return -EINVAL; /* no destination address */ + } printk(KERN_INFO "%s: placing X.25 call to %s ...\n", card->devname, chan->addr); + if (x25_place_call(card, chan) != CMD_OK) return -EIO; + set_chan_state(dev, WAN_CONNECTING); return 1; - } - else - { + }else{ if (x25_get_chan_conf(card, chan) != CMD_OK) return -EIO; + set_chan_state(dev, WAN_CONNECTED); } return 0; } -/*============================================================================ - * Disconnect logical channel. - * o if SVC then clear X.25 call +/* + * Disconnect logical channel. + * o if SVC then clear X.25 call */ -static int chan_disc (struct net_device* dev) + +static int chan_disc (netdevice_t* dev) { x25_channel_t* chan = dev->priv; - if (chan->svc) - x25_clear_call(chan->card, chan->lcn, 0, 0); + if (chan->common.svc){ + x25_clear_call(chan->card, chan->common.lcn, 0, 0); + + /* For API we disconnect on clear + * confirmation. + */ + if (chan->common.usedby == API) + return 0; + } + set_chan_state(dev, WAN_DISCONNECTED); + return 0; } -/*============================================================================ - * Set logical channel state. +/* + * Set logical channel state. */ -static void set_chan_state (struct net_device* dev, int state) + +static void set_chan_state (netdevice_t* dev, int state) { x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; @@ -2071,99 +3615,257 @@ save_flags(flags); cli(); - if (chan->state != state) + if (chan->common.state != state) { switch (state) { case WAN_CONNECTED: - printk (KERN_INFO "%s: interface %s connected!\n", - card->devname, dev->name); - *(unsigned short*)dev->dev_addr = htons(chan->lcn); + if (card->u.x.logging){ + printk (KERN_INFO + "%s: interface %s connected, lcn %i !\n", + card->devname, dev->name,chan->common.lcn); + } + *(unsigned short*)dev->dev_addr = htons(chan->common.lcn); chan->i_timeout_sofar = jiffies; + + /* LAPB is PVC Based */ + if (card->u.x.LAPB_hdlc) + chan->common.svc=0; break; case WAN_CONNECTING: - printk (KERN_INFO "%s: interface %s connecting...\n", - card->devname, dev->name); + if (card->u.x.logging){ + printk (KERN_INFO + "%s: interface %s connecting, lcn %i ...\n", + card->devname, dev->name, chan->common.lcn); + } break; case WAN_DISCONNECTED: - printk (KERN_INFO "%s: interface %s disconnected!\n", - card->devname, dev->name); - if (chan->svc) - { + if (card->u.x.logging){ + printk (KERN_INFO + "%s: interface %s disconnected, lcn %i !\n", + card->devname, dev->name,chan->common.lcn); + } + atomic_set(&chan->common.disconnect,0); + + if (chan->common.svc) { *(unsigned short*)dev->dev_addr = 0; - chan->lcn = 0; + card->u.x.svc_to_dev_map[(chan->common.lcn%X25_MAX_CHAN)]=NULL; + chan->common.lcn = 0; } + + if (chan->transmit_length){ + chan->transmit_length=0; + atomic_set(&chan->common.driver_busy,0); + chan->tx_offset=0; + if (is_queue_stopped(dev)){ + wake_net_dev(dev); + } + } + atomic_set(&chan->common.command,0); break; - } - chan->state = state; - } + + case WAN_DISCONNECTING: + if (card->u.x.logging){ + printk (KERN_INFO + "\n%s: interface %s disconnecting, lcn %i ...\n", + card->devname, dev->name,chan->common.lcn); + } + atomic_set(&chan->common.disconnect,0); + break; + } + chan->common.state = state; + } chan->state_tick = jiffies; restore_flags(flags); } -/*============================================================================ - * Send packet on a logical channel. - * When this function is called, tx_skb field of the channel data space - * points to the transmit socket buffer. When transmission is complete, - * release socket buffer and reset 'tbusy' flag. - * - * Return: 0 - transmission complete - * 1 - busy - * - * Notes: - * 1. If packet length is greater than MTU for this channel, we'll fragment - * the packet into 'complete sequence' using M-bit. - * 2. When transmission is complete, an event notification should be issued - * to the router. +/* + * Send packet on a logical channel. + * When this function is called, tx_skb field of the channel data + * space points to the transmit socket buffer. When transmission + * is complete, release socket buffer and reset 'tbusy' flag. + * + * Return: 0 - transmission complete + * 1 - busy + * + * Notes: + * 1. If packet length is greater than MTU for this channel, we'll fragment + * the packet into 'complete sequence' using M-bit. + * 2. When transmission is complete, an event notification should be issued + * to the router. */ -static int chan_send (struct net_device* dev, struct sk_buff* skb) + +static int chan_send (netdevice_t* dev, void* buff, unsigned data_len, unsigned char tx_intr) { x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; TX25Status* status = card->flags; - unsigned len, qdm; + unsigned len=0, qdm=0, res=0, orig_len = 0; + void *data; /* Check to see if channel is ready */ - if (!(status->cflags[chan->ch_idx] & 0x40)) - return 1; - - if (skb->len > chan->tx_pkt_size) - { - len = chan->tx_pkt_size; - qdm = 0x01; /* set M-bit (more data) */ + if ((!(status->cflags[chan->ch_idx] & 0x40) && !card->u.x.LAPB_hdlc) || + !(*card->u.x.hdlc_buf_status & 0x40)){ + + if (!tx_intr){ + setup_for_delayed_transmit (dev, buff, data_len); + return 0; + }else{ + /* By returning 0 to tx_intr the packet will be dropped */ + ++card->wandev.stats.tx_dropped; + ++chan->ifstats.tx_dropped; + printk(KERN_INFO "%s: ERROR, Tx intr could not send, dropping %s:\n", + card->devname,dev->name); + ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; + return 0; + } } - else /* final packet */ - { - len = skb->len; - qdm = 0; + + if (chan->common.usedby == API){ + /* Remove the API Header */ + x25api_hdr_t *api_data = (x25api_hdr_t *)buff; + + /* Set the qdm bits from the packet header + * User has the option to set the qdm bits + */ + qdm = api_data->qdm; + + orig_len = len = data_len - sizeof(x25api_hdr_t); + data = (unsigned char*)buff + sizeof(x25api_hdr_t); + }else{ + data = buff; + orig_len = len = data_len; + } + + if (tx_intr){ + /* We are in tx_intr, minus the tx_offset from + * the total length. The tx_offset part of the + * data has already been sent. Also, move the + * data pointer to proper offset location. + */ + len -= chan->tx_offset; + data = (unsigned char*)data + chan->tx_offset; } - switch(x25_send(card, chan->lcn, qdm, len, skb->data)) - { + + /* Check if the packet length is greater than MTU + * If YES: Cut the len to MTU and set the M bit + */ + if (len > chan->tx_pkt_size && !card->u.x.LAPB_hdlc){ + len = chan->tx_pkt_size; + qdm |= M_BIT; + } + + + /* Pass only first three bits of the qdm byte to the send + * routine. In case user sets any other bit which might + * cause errors. + */ + + switch(x25_send(card, chan->common.lcn, (qdm&0x07), len, data)){ case 0x00: /* success */ chan->i_timeout_sofar = jiffies; - if (qdm) - { - skb_pull(skb, len); - return 1; + +#ifdef LINUX_2_4 + dev->trans_start=jiffies; +#endif + + if ((qdm & M_BIT) && !card->u.x.LAPB_hdlc){ + if (!tx_intr){ + /* The M bit was set, which means that part of the + * packet has been sent. Copy the packet into a buffer + * and set the offset to len, so on next tx_inter + * the packet will be sent using the below offset. + */ + chan->tx_offset += len; + + ++chan->ifstats.tx_packets; +#if defined(LINUX_2_1) || defined(LINUX_2_4) + chan->ifstats.tx_bytes += len; +#endif + + if (chan->tx_offset < orig_len){ + setup_for_delayed_transmit (dev, buff, data_len); + } + res=0; + }else{ + /* We are already in tx_inter, thus data is already + * in the buffer. Update the offset and wait for + * next tx_intr. We add on to the offset, since data can + * be X number of times larger than max data size. + */ + ++chan->ifstats.tx_packets; +#if defined(LINUX_2_1) || defined(LINUX_2_4) + chan->ifstats.tx_bytes += len; +#endif + + ++chan->if_send_stat.if_send_bfr_passed_to_adptr; + chan->tx_offset += len; + + /* The user can set the qdm bit as well. + * If the entire packet was sent and qdm is still + * set, than it's the user who has set the M bit. In that, + * case indicate that the packet was send by returning + * 0 and wait for a new packet. Otherwise, wait for next + * tx interrupt to send the rest of the packet */ + + if (chan->tx_offset < orig_len){ + res=1; + }else{ + res=0; + } + } + }else{ + ++chan->ifstats.tx_packets; +#if defined(LINUX_2_1) || defined(LINUX_2_4) + chan->ifstats.tx_bytes += len; +#endif + ++chan->if_send_stat.if_send_bfr_passed_to_adptr; + res=0; } - ++chan->ifstats.tx_packets; - chan->ifstats.tx_bytes += skb->len; break; case 0x33: /* Tx busy */ - return 1; + if (tx_intr){ + printk(KERN_INFO "%s: Tx_intr: Big Error dropping packet %s\n", + card->devname,dev->name); + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; + res=0; + }else{ + DBG_PRINTK(KERN_INFO + "%s: Send: Big Error should have tx: storring %s\n", + card->devname,dev->name); + setup_for_delayed_transmit (dev, buff, data_len); + res=1; + } + break; default: /* failure */ ++chan->ifstats.tx_errors; -/* return 1; */ + if (tx_intr){ + printk(KERN_INFO "%s: Tx_intr: Failure to send, dropping %s\n", + card->devname,dev->name); + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; + res=0; + }else{ + DBG_PRINTK(KERN_INFO "%s: Send: Failure to send !!!, storing %s\n", + card->devname,dev->name); + setup_for_delayed_transmit (dev, buff, data_len); + res=1; + } + break; } - return 0; + return res; } -/*============================================================================ - * Parse X.25 call request data and fill x25_call_info_t structure. + +/* + * Parse X.25 call request data and fill x25_call_info_t structure. */ static void parse_call_info (unsigned char* str, x25_call_info_t* info) @@ -2172,54 +3874,45 @@ for (; *str; ++str) { int i; - unsigned ch; + unsigned char ch; + + if (*str == '-') switch (str[1]) { + + /* Take minus 2 off the maximum size so that + * last byte is 0. This way we can use string + * manipulaton functions on call information. + */ - if (*str == '-') switch (str[1]) - { case 'd': /* destination address */ - for (i = 0; i < 16; ++i) - { + for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){ ch = str[2+i]; - if (!is_digit(ch)) - break; + if (isspace(ch)) break; info->dest[i] = ch; } break; - + case 's': /* source address */ - for (i = 0; i < 16; ++i) - { + for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){ ch = str[2+i]; - if (!is_digit(ch)) - break; + if (isspace(ch)) break; info->src[i] = ch; } break; case 'u': /* user data */ - for (i = 0; i < 127; ++i) - { - ch = str[2+2*i]; - if (!is_hex_digit(ch)) - break; - info->user[i] = hex_to_uint(&str[2+2*i], 2); + for (i = 0; i < (MAX_X25_DATA_SIZE-2); ++i){ + ch = str[2+i]; + if (isspace(ch)) break; + info->user[i] = ch; } info->nuser = i; break; case 'f': /* facilities */ - for (i = 0; i < 64; ++i) - { - ch = str[2+4*i]; - if (!is_hex_digit(ch)) - break; - info->facil[i].code = - hex_to_uint(&str[2+4*i], 2); - ch = str[4+4*i]; - if (!is_hex_digit(ch)) - break; - info->facil[i].parm = - hex_to_uint(&str[4+4*i], 2); + for (i = 0; i < (MAX_X25_FACL_SIZE-2); ++i){ + ch = str[2+i]; + if (isspace(ch)) break; + info->facil[i] = ch; } info->nfacil = i; break; @@ -2227,14 +3920,15 @@ } } -/*============================================================================ - * Convert line speed in bps to a number used by S502 code. +/* + * Convert line speed in bps to a number used by S502 code. */ + static unsigned char bps_to_speed_code (unsigned long bps) { unsigned char number; - if (bps <= 1200) number = 0x01 ; + if (bps <= 1200) number = 0x01; else if (bps <= 2400) number = 0x02; else if (bps <= 4800) number = 0x03; else if (bps <= 9600) number = 0x04; @@ -2251,29 +3945,36 @@ return number; } -/*============================================================================ - * Convert decimal string to unsigned integer. - * If len != 0 then only 'len' characters of the string are converted. +/* + * Convert decimal string to unsigned integer. + * If len != 0 then only 'len' characters of the string are converted. */ + static unsigned int dec_to_uint (unsigned char* str, int len) { unsigned val; - if (!len) len = strlen(str); + if (!len) + len = strlen(str); + for (val = 0; len && is_digit(*str); ++str, --len) val = (val * 10) + (*str - (unsigned)'0'); + return val; } -/*============================================================================ - * Convert hex string to unsigned integer. - * If len != 0 then only 'len' characters of the string are conferted. +/* + * Convert hex string to unsigned integer. + * If len != 0 then only 'len' characters of the string are conferted. */ + static unsigned int hex_to_uint (unsigned char* str, int len) { unsigned val, ch; - if (!len) len = strlen(str); + if (!len) + len = strlen(str); + for (val = 0; len; ++str, --len) { ch = *str; @@ -2281,8 +3982,7 @@ val = (val << 4) + (ch - (unsigned)'0'); else if (is_hex_digit(ch)) val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10); - else - break; + else break; } return val; } @@ -2292,21 +3992,21 @@ { int i; - if( proto == htons(ETH_P_IPX) ) { + if( proto == ETH_P_IPX) { /* It's an IPX packet */ if(!enable_IPX) { /* Return 1 so we don't pass it up the stack. */ return 1; } } else { - /* It's not IPX so pass it up the stack. */ + /* It's not IPX so pass it up the stack.*/ return 0; } if( sendpacket[16] == 0x90 && sendpacket[17] == 0x04) { - /* It's IPXWAN */ + /* It's IPXWAN */ if( sendpacket[2] == 0x02 && sendpacket[34] == 0x00) @@ -2315,19 +4015,24 @@ printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); /* Go through the routing options and answer no to every - * option except Unnumbered RIP/SAP */ + * option except Unnumbered RIP/SAP + */ for(i = 41; sendpacket[i] == 0x00; i += 5) { /* 0x02 is the option for Unnumbered RIP/SAP */ if( sendpacket[i + 4] != 0x02) + { sendpacket[i + 1] = 0; + } } /* Skip over the extended Node ID option */ if( sendpacket[i] == 0x04 ) + { i += 8; + } - /* We also want to turn off all header compression opt. */ + /* We also want to turn off all header compression opt. */ for(; sendpacket[i] == 0x80 ;) { sendpacket[i + 1] = 0; @@ -2364,7 +4069,9 @@ sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); for(i = 66; i < 99; i+= 1) + { sendpacket[i] = 0; + } printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); } @@ -2382,18 +4089,18 @@ return 1; } else { - /* If we get here its an IPX-data packet, so it'll get passed up the stack. - switch the network numbers */ + /*If we get here its an IPX-data packet, so it'll get passed up the stack. + */ + /* switch the network numbers */ switch_net_numbers(sendpacket, network_number, 1); return 0; } } /* - If incoming is 0 (outgoing)- if the net numbers is ours make it 0 - if incoming is 1 - if the net number is 0 make it ours - -*/ + * If incoming is 0 (outgoing)- if the net numbers is ours make it 0 + * if incoming is 1 - if the net number is 0 make it ours + */ static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) { @@ -2402,21 +4109,17 @@ pnetwork_number = (unsigned long)((sendpacket[6] << 24) + (sendpacket[7] << 16) + (sendpacket[8] << 8) + sendpacket[9]); + - if (!incoming) - { - /* If the destination network number is ours, make it 0 */ - if( pnetwork_number == network_number) - { + if (!incoming) { + /*If the destination network number is ours, make it 0 */ + if( pnetwork_number == network_number) { sendpacket[6] = sendpacket[7] = sendpacket[8] = sendpacket[9] = 0x00; } - } - else - { + } else { /* If the incoming network is 0, make it ours */ - if( pnetwork_number == 0) - { + if( pnetwork_number == 0) { sendpacket[6] = (unsigned char)(network_number >> 24); sendpacket[7] = (unsigned char)((network_number & 0x00FF0000) >> 16); @@ -2431,21 +4134,17 @@ pnetwork_number = (unsigned long)((sendpacket[18] << 24) + (sendpacket[19] << 16) + (sendpacket[20] << 8) + sendpacket[21]); - - if( !incoming ) - { + + + if( !incoming ) { /* If the source network is ours, make it 0 */ - if( pnetwork_number == network_number) - { + if( pnetwork_number == network_number) { sendpacket[18] = sendpacket[19] = sendpacket[20] = - sendpacket[21] = 0x00; + sendpacket[21] = 0x00; } - } - else - { + } else { /* If the source network is 0, make it ours */ - if( pnetwork_number == 0 ) - { + if( pnetwork_number == 0 ) { sendpacket[18] = (unsigned char)(network_number >> 24); sendpacket[19] = (unsigned char)((network_number & 0x00FF0000) >> 16); @@ -2457,5 +4156,1419 @@ } } /* switch_net_numbers */ + + + +/********************* X25API SPECIFIC FUNCTIONS ****************/ + + +/*=============================================================== + * find_channel + * + * Manages the lcn to device map. It increases performance + * because it eliminates the need to search through the link + * list for a device which is bounded to a specific lcn. + * + *===============================================================*/ + + +netdevice_t * find_channel(sdla_t *card, unsigned lcn) +{ + if (card->u.x.LAPB_hdlc){ + + return card->wandev.dev; + + }else{ + /* We don't know whether the incoming lcn + * is a PVC or an SVC channel. But we do know that + * the lcn cannot be for both the PVC and the SVC + * channel. + + * If the lcn number is greater or equal to 255, + * take the modulo 255 of that number. We only have + * 255 locations, thus higher numbers must be mapped + * to a number between 0 and 245. + + * We must separate pvc's and svc's since two don't + * have to be contiguous. Meaning pvc's can start + * from 1 to 10 and svc's can start from 256 to 266. + * But 256%255 is 1, i.e. CONFLICT. + */ + + + /* Highest LCN number must be less or equal to 4096 */ + if ((lcn <= MAX_LCN_NUM) && (lcn > 0)){ + + if (lcn < X25_MAX_CHAN){ + if (card->u.x.svc_to_dev_map[lcn]) + return card->u.x.svc_to_dev_map[lcn]; + + if (card->u.x.pvc_to_dev_map[lcn]) + return card->u.x.pvc_to_dev_map[lcn]; + + }else{ + int new_lcn = lcn%X25_MAX_CHAN; + if (card->u.x.svc_to_dev_map[new_lcn]) + return card->u.x.svc_to_dev_map[new_lcn]; + + if (card->u.x.pvc_to_dev_map[new_lcn]) + return card->u.x.pvc_to_dev_map[new_lcn]; + } + } + return NULL; + } +} + +void bind_lcn_to_dev (sdla_t *card, netdevice_t *dev,unsigned lcn) +{ + x25_channel_t *chan = dev->priv; + + /* Modulo the lcn number by X25_MAX_CHAN (255) + * because the lcn number can be greater than 255 + * + * We need to split svc and pvc since they don't have + * to be contigous. + */ + + if (chan->common.svc){ + card->u.x.svc_to_dev_map[(lcn % X25_MAX_CHAN)] = dev; + }else{ + card->u.x.pvc_to_dev_map[(lcn % X25_MAX_CHAN)] = dev; + } + chan->common.lcn = lcn; +} + + + +/*=============================================================== + * x25api_bh + * + * + *==============================================================*/ + +static void x25api_bh (netdevice_t * dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + struct sk_buff *skb; + + if (atomic_read(&chan->bh_buff_used) == 0){ + printk(KERN_INFO "%s: BH Buffer Empty in BH\n", + card->devname); + clear_bit(0, &chan->tq_working); + return; + } + + while (atomic_read(&chan->bh_buff_used)){ + + /* If the sock is in the process of unlinking the + * driver from the socket, we must get out. + * This never happends but is a sanity check. */ + if (test_bit(0,&chan->common.common_critical)){ + clear_bit(0, &chan->tq_working); + return; + } + + /* If LAPB HDLC, do not drop packets if socket is + * not connected. Let the buffer fill up and + * turn off rx interrupt */ + if (card->u.x.LAPB_hdlc){ + if (chan->common.sk == NULL || chan->common.func == NULL){ + clear_bit(0, &chan->tq_working); + return; + } + } + + skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; + + if (skb == NULL){ + printk(KERN_INFO "%s: BH Skb empty for read %i\n", + card->devname,chan->bh_read); + }else{ + + if (chan->common.sk == NULL || chan->common.func == NULL){ + printk(KERN_INFO "%s: BH: Socket disconnected, dropping\n", + card->devname); + wan_dev_kfree_skb(skb, FREE_READ); + x25api_bh_cleanup(dev); + ++chan->ifstats.rx_dropped; + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; + continue; + } + + + if (chan->common.func(skb,dev,chan->common.sk) != 0){ + /* Sock full cannot send, queue us for another + * try + */ + printk(KERN_INFO "%s: BH: !!! Packet failed to send !!!!! \n", + card->devname); + atomic_set(&chan->common.receive_block,1); + return; + }else{ + x25api_bh_cleanup(dev); + ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack; + } + } + } + clear_bit(0, &chan->tq_working); + + return; +} + +/*=============================================================== + * x25api_bh_cleanup + * + * + *==============================================================*/ + +static int x25api_bh_cleanup (netdevice_t *dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t *card = chan->card; + TX25Status* status = card->flags; + + + ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; + + if (chan->bh_read == MAX_BH_BUFF){ + chan->bh_read=0; + }else{ + ++chan->bh_read; + } + + /* If the Receive interrupt was off, it means + * that we filled up our circular buffer. Check + * that we have space in the buffer. If so + * turn the RX interrupt back on. + */ + if (!(status->imask & INTR_ON_RX_FRAME)){ + if (atomic_read(&chan->bh_buff_used) < (MAX_BH_BUFF+1)){ + printk(KERN_INFO "%s: BH: Turning on the interrupt\n", + card->devname); + status->imask |= INTR_ON_RX_FRAME; + } + } + + atomic_dec(&chan->bh_buff_used); + return 0; +} + + +/*=============================================================== + * bh_enqueue + * + * + *==============================================================*/ + +static int bh_enqueue (netdevice_t *dev, struct sk_buff *skb) +{ + x25_channel_t* chan = dev->priv; + sdla_t *card = chan->card; + TX25Status* status = card->flags; + + if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ + printk(KERN_INFO "%s: Bottom half buffer FULL\n", + card->devname); + return 1; + } + + ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; + + if (chan->bh_write == MAX_BH_BUFF){ + chan->bh_write=0; + }else{ + ++chan->bh_write; + } + + atomic_inc(&chan->bh_buff_used); + + if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ + printk(KERN_INFO "%s: Buffer is now full, Turning off RX Intr\n", + card->devname); + status->imask &= ~INTR_ON_RX_FRAME; + } + + return 0; +} + + +/*=============================================================== + * timer_intr_cmd_exec + * + * Called by timer interrupt to execute a command + *===============================================================*/ + +static int timer_intr_cmd_exec (sdla_t* card) +{ + netdevice_t *dev; + unsigned char more_to_exec=0; + volatile x25_channel_t *chan=NULL; + int i=0,bad_cmd=0,err=0; + + if (card->u.x.cmd_dev == NULL){ + card->u.x.cmd_dev = card->wandev.dev; + } + + dev = card->u.x.cmd_dev; + + for (;;){ + + chan = dev->priv; + + if (atomic_read(&chan->common.command)){ + + bad_cmd = check_bad_command(card,dev); + + if ((!chan->common.mbox || atomic_read(&chan->common.disconnect)) && + !bad_cmd){ + + /* Socket has died or exited, We must bring the + * channel down before anybody else tries to + * use it */ + err = channel_disconnect(card,dev); + }else{ + err = execute_delayed_cmd(card, dev, + (mbox_cmd_t*)chan->common.mbox, + bad_cmd); + } + + switch (err){ + + case RETURN_RESULT: + + /* Return the result to the socket without + * delay. NO_WAIT Command */ + atomic_set(&chan->common.command,0); + if (atomic_read(&card->u.x.command_busy)) + atomic_set(&card->u.x.command_busy,0); + + send_delayed_cmd_result(card,dev,card->mbox); + + more_to_exec=0; + break; + case DELAY_RESULT: + + /* Wait for the remote to respond, before + * sending the result up to the socket. + * WAIT command */ + if (atomic_read(&card->u.x.command_busy)) + atomic_set(&card->u.x.command_busy,0); + + atomic_set(&chan->common.command,0); + more_to_exec=0; + break; + default: + + /* If command could not be executed for + * some reason (i.e return code 0x33 busy) + * set the more_to_exec bit which will + * indicate that this command must be exectued + * again during next timer interrupt + */ + more_to_exec=1; + if (atomic_read(&card->u.x.command_busy) == 0) + atomic_set(&card->u.x.command_busy,1); + break; + } + + bad_cmd=0; + + /* If flags is set, there are no hdlc buffers, + * thus, wait for the next pass and try the + * same command again. Otherwise, start searching + * from next device on the next pass. + */ + if (!more_to_exec){ + dev = move_dev_to_next(card,dev); + } + break; + }else{ + /* This device has nothing to execute, + * go to next. + */ + if (atomic_read(&card->u.x.command_busy)) + atomic_set(&card->u.x.command_busy,0); + dev = move_dev_to_next(card,dev); + } + + if (++i == card->u.x.no_dev){ + if (!more_to_exec){ + DBG_PRINTK(KERN_INFO "%s: Nothing to execute in Timer\n", + card->devname); + if (atomic_read(&card->u.x.command_busy)){ + atomic_set(&card->u.x.command_busy,0); + } + } + break; + } + + } //End of FOR + + card->u.x.cmd_dev = dev; + + if (more_to_exec){ + /* If more commands are pending, do not turn off timer + * interrupt */ + return 1; + }else{ + /* No more commands, turn off timer interrupt */ + return 0; + } +} + +/*=============================================================== + * execute_delayed_cmd + * + * Execute an API command which was passed down from the + * sock. Sock is very limited in which commands it can + * execute. Wait and No Wait commands are supported. + * Place Call, Clear Call and Reset wait commands, where + * Accept Call is a no_wait command. + * + *===============================================================*/ + +static int execute_delayed_cmd (sdla_t* card, netdevice_t *dev, mbox_cmd_t *usr_cmd,char bad_cmd) +{ + TX25Mbox* mbox = card->mbox; + int err; + x25_channel_t *chan = dev->priv; + int delay=RETURN_RESULT; + + if (!(*card->u.x.hdlc_buf_status & 0x40) && !bad_cmd){ + return TRY_CMD_AGAIN; + } + + /* This way a command is guaranteed to be executed for + * a specific lcn, the network interface is bound to. */ + usr_cmd->cmd.lcn = chan->common.lcn; + + + /* If channel is pvc, instead of place call + * run x25_channel configuration. If running LAPB HDLC + * enable communications. + */ + if ((!chan->common.svc) && (usr_cmd->cmd.command == X25_PLACE_CALL)){ + + if (card->u.x.LAPB_hdlc){ + DBG_PRINTK(KERN_INFO "LAPB: Connecting\n"); + connect(card); + set_chan_state(dev,WAN_CONNECTING); + return DELAY_RESULT; + }else{ + DBG_PRINTK(KERN_INFO "%s: PVC is CONNECTING\n",card->devname); + if (x25_get_chan_conf(card, chan) == CMD_OK){ + set_chan_state(dev, WAN_CONNECTED); + }else{ + set_chan_state(dev, WAN_DISCONNECTED); + } + return RETURN_RESULT; + } + } + + /* Copy the socket mbox command onto the board */ + + memcpy(&mbox->cmd, &usr_cmd->cmd, sizeof(TX25Cmd)); + if (usr_cmd->cmd.length){ + memcpy(mbox->data, usr_cmd->data, usr_cmd->cmd.length); + } + + /* Check if command is bad. We need to copy the cmd into + * the buffer regardless since we return the, mbox to + * the user */ + if (bad_cmd){ + mbox->cmd.result=0x01; + return RETURN_RESULT; + } + + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK && err != X25RES_NOT_READY) + x25_error(card, err, usr_cmd->cmd.command, usr_cmd->cmd.lcn); + + if (mbox->cmd.result == X25RES_NOT_READY){ + return TRY_CMD_AGAIN; + } + + switch (mbox->cmd.command){ + + case X25_PLACE_CALL: + + switch (mbox->cmd.result){ + + case CMD_OK: + + /* Check if Place call is a wait command or a + * no wait command */ + if (atomic_read(&chan->common.command) & 0x80) + delay=RETURN_RESULT; + else + delay=DELAY_RESULT; + + + DBG_PRINTK(KERN_INFO "\n%s: PLACE CALL Binding dev %s to lcn %i\n", + card->devname,dev->name, mbox->cmd.lcn); + + bind_lcn_to_dev (card, dev, mbox->cmd.lcn); + set_chan_state(dev, WAN_CONNECTING); + break; + + + default: + delay=RETURN_RESULT; + set_chan_state(dev, WAN_DISCONNECTED); + break; + } + break; + + case X25_ACCEPT_CALL: + + switch (mbox->cmd.result){ + + case CMD_OK: + + DBG_PRINTK(KERN_INFO "\n%s: ACCEPT Binding dev %s to lcn %i\n", + card->devname,dev->name,mbox->cmd.lcn); + + bind_lcn_to_dev (card, dev, mbox->cmd.lcn); + + if (x25_get_chan_conf(card, chan) == CMD_OK){ + + set_chan_state(dev, WAN_CONNECTED); + delay=RETURN_RESULT; + + }else{ + if (x25_clear_call(card, usr_cmd->cmd.lcn, 0, 0) == CMD_OK){ + /* if clear is successful, wait for clear confirm + */ + delay=DELAY_RESULT; + }else{ + /* Do not change the state here. If we fail + * the accept the return code is send up + *the stack, which will ether retry + * or clear the call + */ + DBG_PRINTK(KERN_INFO + "%s: ACCEPT: STATE MAY BE CURRUPTED 2 !!!!!\n", + card->devname); + delay=RETURN_RESULT; + } + } + break; + + + case X25RES_ASYNC_PACKET: + delay=TRY_CMD_AGAIN; + break; + + default: + DBG_PRINTK(KERN_INFO "%s: ACCEPT FAILED\n",card->devname); + if (x25_clear_call(card, usr_cmd->cmd.lcn, 0, 0) == CMD_OK){ + delay=DELAY_RESULT; + }else{ + /* Do not change the state here. If we fail the accept. The + * return code is send up the stack, which will ether retry + * or clear the call */ + DBG_PRINTK(KERN_INFO + "%s: ACCEPT: STATE MAY BE CORRUPTED 1 !!!!!\n", + card->devname); + delay=RETURN_RESULT; + } + } + break; + + case X25_CLEAR_CALL: + + switch (mbox->cmd.result){ + + case CMD_OK: + DBG_PRINTK(KERN_INFO + "CALL CLEAR OK: Dev %s Mbox Lcn %i Chan Lcn %i\n", + dev->name,mbox->cmd.lcn,chan->common.lcn); + set_chan_state(dev, WAN_DISCONNECTING); + delay = DELAY_RESULT; + break; + + case X25RES_CHANNEL_IN_USE: + case X25RES_ASYNC_PACKET: + delay = TRY_CMD_AGAIN; + break; + + case X25RES_LINK_NOT_IN_ABM: + case X25RES_INVAL_LCN: + case X25RES_INVAL_STATE: + set_chan_state(dev, WAN_DISCONNECTED); + delay = RETURN_RESULT; + break; + + default: + /* If command did not execute because of user + * fault, do not change the state. This will + * signal the socket that clear command failed. + * User can retry or close the socket. + * When socket gets killed, it will set the + * chan->disconnect which will signal + * driver to clear the call */ + printk(KERN_INFO "%s: Clear Command Failed, Rc %x\n", + card->devname,mbox->cmd.command); + delay = RETURN_RESULT; + } + break; + } + + return delay; +} + +/*=============================================================== + * api_incoming_call + * + * Pass an incoming call request up the the listening + * sock. If the API sock is not listening reject the + * call. + * + *===============================================================*/ + +static int api_incoming_call (sdla_t* card, TX25Mbox *mbox, int lcn) +{ + struct sk_buff *skb; + int len = sizeof(TX25Cmd)+mbox->cmd.length; + + if (alloc_and_init_skb_buf(card, &skb, len)){ + printk(KERN_INFO "%s: API incoming call, no memory\n",card->devname); + return 1; + } + + memcpy(skb_put(skb,len),&mbox->cmd,len); + + skb->mac.raw = skb->data; + skb->protocol = htons(X25_PROT); + skb->pkt_type = WAN_PACKET_ASYNC; + + if (card->func(skb,card->sk) < 0){ + printk(KERN_INFO "%s: MAJOR ERROR: Failed to send up place call \n",card->devname); + wan_dev_kfree_skb(skb, FREE_READ); + return 1; + } + + return 0; +} + +/*=============================================================== + * send_delayed_cmd_result + * + * Wait commands like PLEACE CALL or CLEAR CALL must wait + * untill the result arrivers. This function passes + * the result to a waiting sock. + * + *===============================================================*/ +static void send_delayed_cmd_result(sdla_t *card, netdevice_t *dev, TX25Mbox* mbox) +{ + x25_channel_t *chan = dev->priv; + mbox_cmd_t *usr_cmd = (mbox_cmd_t *)chan->common.mbox; + struct sk_buff *skb; + int len=sizeof(unsigned char); + + atomic_set(&chan->common.command,0); + + /* If the sock is in the process of unlinking the + * driver from the socket, we must get out. + * This never happends but is a sanity check. */ + if (test_bit(0,&chan->common.common_critical)){ + return; + } + + if (!usr_cmd || !chan->common.sk || !chan->common.func){ + DBG_PRINTK(KERN_INFO "Delay result: Sock not bounded sk: %u, func: %u, mbox: %u\n", + (unsigned int)chan->common.sk, + (unsigned int)chan->common.func, + (unsigned int)usr_cmd); + return; + } + + memcpy(&usr_cmd->cmd, &mbox->cmd, sizeof(TX25Cmd)); + if (mbox->cmd.length > 0){ + memcpy(usr_cmd->data, mbox->data, mbox->cmd.length); + } + + if (alloc_and_init_skb_buf(card,&skb,len)){ + printk(KERN_INFO "Delay result: No sock buffers\n"); + return; + } + + memcpy(skb_put(skb,len),&mbox->cmd.command,len); + + skb->mac.raw = skb->data; + skb->pkt_type = WAN_PACKET_CMD; + + chan->common.func(skb,dev,chan->common.sk); +} + +/*=============================================================== + * clear_confirm_event + * + * Pass the clear confirmation event up the sock. The + * API will disconnect only after the clear confirmation + * has been received. + * + * Depending on the state, clear confirmation could + * be an OOB event, or a result of an API command. + *===============================================================*/ + +static int clear_confirm_event (sdla_t *card, TX25Mbox* mb) +{ + netdevice_t *dev; + x25_channel_t *chan; + unsigned char old_state; + + dev = find_channel(card,mb->cmd.lcn); + if (!dev){ + DBG_PRINTK(KERN_INFO "%s: *** GOT CLEAR BUT NO DEV %i\n", + card->devname,mb->cmd.lcn); + return 0; + } + + chan=dev->priv; + DBG_PRINTK(KERN_INFO "%s: GOT CLEAR CONFIRM %s: Mbox lcn %i Chan lcn %i\n", + card->devname, dev->name, mb->cmd.lcn, chan->common.lcn); + + /* If not API fall through to default. + * If API, send the result to a waiting + * socket. + */ + + old_state = chan->common.state; + set_chan_state(dev, WAN_DISCONNECTED); + + if (chan->common.usedby == API){ + switch (old_state) { + + case WAN_DISCONNECTING: + case WAN_CONNECTING: + send_delayed_cmd_result(card,dev,mb); + break; + case WAN_CONNECTED: + send_oob_msg(card,dev,mb); + break; + } + return 1; + } + + return 0; +} + +/*=============================================================== + * send_oob_msg + * + * Construct an NEM Message and pass it up the connected + * sock. If the sock is not bounded discard the NEM. + * + *===============================================================*/ + +static void send_oob_msg (sdla_t *card, netdevice_t *dev, TX25Mbox *mbox) +{ + x25_channel_t *chan = dev->priv; + mbox_cmd_t *usr_cmd = (mbox_cmd_t *)chan->common.mbox; + struct sk_buff *skb; + int len=sizeof(x25api_hdr_t)+mbox->cmd.length; + x25api_t *api_hdr; + + /* If the sock is in the process of unlinking the + * driver from the socket, we must get out. + * This never happends but is a sanity check. */ + if (test_bit(0,&chan->common.common_critical)){ + return; + } + + if (!usr_cmd || !chan->common.sk || !chan->common.func){ + DBG_PRINTK(KERN_INFO "OOB MSG: Sock not bounded\n"); + return; + } + + memcpy(&usr_cmd->cmd, &mbox->cmd, sizeof(TX25Cmd)); + if (mbox->cmd.length > 0){ + memcpy(usr_cmd->data, mbox->data, mbox->cmd.length); + } + + if (alloc_and_init_skb_buf(card,&skb,len)){ + printk(KERN_INFO "%s: OOB MSG: No sock buffers\n",card->devname); + return; + } + + api_hdr = (x25api_t*)skb_put(skb,len); + api_hdr->hdr.pktType = mbox->cmd.pktType & 0x7F; + api_hdr->hdr.qdm = mbox->cmd.qdm; + api_hdr->hdr.cause = mbox->cmd.cause; + api_hdr->hdr.diagn = mbox->cmd.diagn; + api_hdr->hdr.length = mbox->cmd.length; + api_hdr->hdr.result = mbox->cmd.result; + api_hdr->hdr.lcn = mbox->cmd.lcn; + + if (mbox->cmd.length > 0){ + memcpy(api_hdr->data,mbox->data,mbox->cmd.length); + } + + skb->mac.raw = skb->data; + skb->pkt_type = WAN_PACKET_ERR; + + if (chan->common.func(skb,dev,chan->common.sk) < 0){ + if (bh_enqueue(dev,skb)){ + printk(KERN_INFO "%s: Dropping OOB MSG\n",card->devname); + wan_dev_kfree_skb(skb, FREE_READ); + } + } + + DBG_PRINTK(KERN_INFO "%s: OOB MSG OK, %s, lcn %i\n", + card->devname, dev->name, mbox->cmd.lcn); +} + +/*=============================================================== + * alloc_and_init_skb_buf + * + * Allocate and initialize an skb buffer. + * + *===============================================================*/ + +static int alloc_and_init_skb_buf (sdla_t *card, struct sk_buff **skb, int len) +{ + struct sk_buff *new_skb = *skb; + + new_skb = dev_alloc_skb(len + X25_HRDHDR_SZ); + if (new_skb == NULL){ + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + return 1; + } + + if (skb_tailroom(new_skb) < len){ + /* No room for the packet. Call off the whole thing! */ + wan_dev_kfree_skb(new_skb, FREE_READ); + printk(KERN_INFO "%s: Listen: unexpectedly long packet sequence\n" + ,card->devname); + *skb = NULL; + return 1; + } + + *skb = new_skb; + return 0; + +} + +/*=============================================================== + * api_oob_event + * + * Send an OOB event up to the sock + * + *===============================================================*/ + +static void api_oob_event (sdla_t *card,TX25Mbox *mbox) +{ + netdevice_t *dev = find_channel(card,mbox->cmd.lcn); + x25_channel_t *chan; + + if (!dev) + return; + + chan=dev->priv; + + if (chan->common.usedby == API) + send_oob_msg(card,dev,mbox); + +} + + + + +static int channel_disconnect (sdla_t* card, netdevice_t *dev) +{ + + int err; + x25_channel_t *chan = dev->priv; + + DBG_PRINTK(KERN_INFO "%s: TIMER: %s, Device down disconnecting\n", + card->devname,dev->name); + + if (chan->common.svc){ + err = x25_clear_call(card,chan->common.lcn,0,0); + }else{ + /* If channel is PVC or LAPB HDLC, there is no call + * to be cleared, thus drop down to the default + * area + */ + err = 1; + } + + switch (err){ + + case X25RES_CHANNEL_IN_USE: + case X25RES_NOT_READY: + err = TRY_CMD_AGAIN; + break; + case CMD_OK: + DBG_PRINTK(KERN_INFO "CALL CLEAR OK: Dev %s Chan Lcn %i\n", + dev->name,chan->common.lcn); + + set_chan_state(dev,WAN_DISCONNECTING); + atomic_set(&chan->common.command,0); + err = DELAY_RESULT; + break; + default: + /* If LAPB HDLC protocol, bring the whole link down + * once the application terminates + */ + + set_chan_state(dev,WAN_DISCONNECTED); + + if (card->u.x.LAPB_hdlc){ + DBG_PRINTK(KERN_INFO "LAPB: Disconnecting Link\n"); + hdlc_link_down (card); + } + atomic_set(&chan->common.command,0); + err = RETURN_RESULT; + break; + } + + return err; +} + +static void hdlc_link_down (sdla_t *card) +{ + TX25Mbox* mbox = card->mbox; + int retry = 5; + int err=0; + + do { + memset(mbox,0,sizeof(TX25Mbox)); + mbox->cmd.command = X25_HDLC_LINK_DISC; + mbox->cmd.length = 1; + mbox->data[0]=0; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + + } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_DISC, 0)); + + if (err) + printk(KERN_INFO "%s: Hdlc Link Down Failed %x\n",card->devname,err); + + disconnect (card); + +} + +static int check_bad_command (sdla_t* card, netdevice_t *dev) +{ + x25_channel_t *chan = dev->priv; + int bad_cmd = 0; + + switch (atomic_read(&chan->common.command)&0x7F){ + + case X25_PLACE_CALL: + if (chan->common.state != WAN_DISCONNECTED) + bad_cmd=1; + break; + case X25_CLEAR_CALL: + if (chan->common.state == WAN_DISCONNECTED) + bad_cmd=1; + break; + case X25_ACCEPT_CALL: + if (chan->common.state != WAN_CONNECTING) + bad_cmd=1; + break; + case X25_RESET: + if (chan->common.state != WAN_CONNECTED) + bad_cmd=1; + break; + default: + bad_cmd=1; + break; + } + + if (bad_cmd){ + printk(KERN_INFO "%s: Invalid State, BAD Command %x, dev %s, lcn %i, st %i\n", + card->devname,atomic_read(&chan->common.command),dev->name, + chan->common.lcn, chan->common.state); + } + + return bad_cmd; +} + + + +/*************************** XPIPEMON FUNCTIONS **************************/ + +/*============================================================================== + * Process UDP call of type XPIPE + */ + +static int process_udp_mgmt_pkt(sdla_t *card) +{ + int c_retry = MAX_CMD_RETRY; + unsigned int len; + struct sk_buff *new_skb; + TX25Mbox *mbox = card->mbox; + int err; + int udp_mgmt_req_valid = 1; + netdevice_t *dev; + x25_channel_t *chan; + unsigned short lcn; + struct timeval tv; + + + x25_udp_pkt_t *x25_udp_pkt; + x25_udp_pkt = (x25_udp_pkt_t *)card->u.x.udp_pkt_data; + + dev = card->u.x.udp_dev; + chan = dev->priv; + lcn = chan->common.lcn; + + switch(x25_udp_pkt->cblock.command) { + + /* XPIPE_ENABLE_TRACE */ + case XPIPE_ENABLE_TRACING: + + /* XPIPE_GET_TRACE_INFO */ + case XPIPE_GET_TRACE_INFO: + + /* SET FT1 MODE */ + case XPIPE_SET_FT1_MODE: + + if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) { + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err; + udp_mgmt_req_valid = 0; + break; + } + + /* XPIPE_FT1_READ_STATUS */ + case XPIPE_FT1_READ_STATUS: + + /* FT1 MONITOR STATUS */ + case XPIPE_FT1_STATUS_CTRL: + if(card->hw.fwid != SFID_X25_508) { + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_type_err; + udp_mgmt_req_valid = 0; + break; + } + default: + break; + } + + if(!udp_mgmt_req_valid) { + /* set length to 0 */ + x25_udp_pkt->cblock.length = 0; + /* set return code */ + x25_udp_pkt->cblock.result = (card->hw.fwid != SFID_X25_508) ? 0x1F : 0xCD; + + } else { + + switch (x25_udp_pkt->cblock.command) { + + + case XPIPE_FLUSH_DRIVER_STATS: + init_x25_channel_struct(chan); + init_global_statistics(card); + mbox->cmd.length = 0; + break; + + + case XPIPE_DRIVER_STAT_IFSEND: + memcpy(x25_udp_pkt->data, &chan->if_send_stat, sizeof(if_send_stat_t)); + mbox->cmd.length = sizeof(if_send_stat_t); + x25_udp_pkt->cblock.length = mbox->cmd.length; + break; + + case XPIPE_DRIVER_STAT_INTR: + memcpy(&x25_udp_pkt->data[0], &card->statistics, sizeof(global_stats_t)); + memcpy(&x25_udp_pkt->data[sizeof(global_stats_t)], + &chan->rx_intr_stat, sizeof(rx_intr_stat_t)); + + mbox->cmd.length = sizeof(global_stats_t) + + sizeof(rx_intr_stat_t); + x25_udp_pkt->cblock.length = mbox->cmd.length; + break; + + case XPIPE_DRIVER_STAT_GEN: + memcpy(x25_udp_pkt->data, + &chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err, + sizeof(pipe_mgmt_stat_t)); + + memcpy(&x25_udp_pkt->data[sizeof(pipe_mgmt_stat_t)], + &card->statistics, sizeof(global_stats_t)); + + x25_udp_pkt->cblock.result = 0; + x25_udp_pkt->cblock.length = sizeof(global_stats_t)+ + sizeof(rx_intr_stat_t); + mbox->cmd.length = x25_udp_pkt->cblock.length; + break; + + case XPIPE_ROUTER_UP_TIME: + do_gettimeofday(&tv); + chan->router_up_time = tv.tv_sec - chan->router_start_time; + *(unsigned long *)&x25_udp_pkt->data = chan->router_up_time; + x25_udp_pkt->cblock.length = mbox->cmd.length = 4; + x25_udp_pkt->cblock.result = 0; + break; + + default : + + do { + memcpy(&mbox->cmd, &x25_udp_pkt->cblock.command, sizeof(TX25Cmd)); + if(mbox->cmd.length){ + memcpy(&mbox->data, + (char *)x25_udp_pkt->data, + mbox->cmd.length); + } + + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && c_retry-- && x25_error(card, err, mbox->cmd.command, 0)); + + + if ( err == CMD_OK || + (err == 1 && + (mbox->cmd.command == 0x06 || + mbox->cmd.command == 0x16) ) ){ + + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_OK; + } else { + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_timeout; + } + + /* copy the result back to our buffer */ + memcpy(&x25_udp_pkt->cblock.command, &mbox->cmd, sizeof(TX25Cmd)); + + if(mbox->cmd.length) { + memcpy(&x25_udp_pkt->data, &mbox->data, mbox->cmd.length); + } + break; + + } //switch + + } + + /* Fill UDP TTL */ + + x25_udp_pkt->ip_pkt.ttl = card->wandev.ttl; + len = reply_udp(card->u.x.udp_pkt_data, mbox->cmd.length); + + + if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + err = x25_send(card, lcn, 0, len, card->u.x.udp_pkt_data); + if (!err) + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_passed; + else + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_failed; + + } else { + + /* Allocate socket buffer */ + if((new_skb = dev_alloc_skb(len)) != NULL) { + void *buf; + + /* copy data into new_skb */ + buf = skb_put(new_skb, len); + memcpy(buf, card->u.x.udp_pkt_data, len); + + /* Decapsulate packet and pass it up the protocol + stack */ + new_skb->dev = dev; + + if (chan->common.usedby == API) + new_skb->protocol = htons(X25_PROT); + else + new_skb->protocol = htons(ETH_P_IP); + + new_skb->mac.raw = new_skb->data; + + netif_rx(new_skb); + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_stack; + + } else { + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_no_socket; + printk(KERN_INFO + "%s: UDP mgmt cmnd, no socket buffers available!\n", + card->devname); + } + } + + card->u.x.udp_pkt_lgth = 0; + + return 1; +} + + +/*============================================================================== + * Determine what type of UDP call it is. DRVSTATS or XPIPE8ND ? + */ +static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) +{ + x25_udp_pkt_t *x25_udp_pkt = (x25_udp_pkt_t *)skb->data; + + if((x25_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && + (x25_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) && + (x25_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && + (x25_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { + + if(!strncmp(x25_udp_pkt->wp_mgmt.signature, + UDPMGMT_XPIPE_SIGNATURE, 8)){ + return UDP_XPIPE_TYPE; + }else{ + printk(KERN_INFO "%s: UDP Packet, Failed Signature !\n", + card->devname); + } + } + + return UDP_INVALID_TYPE; +} + + +/*============================================================================ + * Reply to UDP Management system. + * Return nothing. + */ +static int reply_udp( unsigned char *data, unsigned int mbox_len ) +{ + unsigned short len, udp_length, temp, ip_length; + unsigned long ip_temp; + int even_bound = 0; + + + x25_udp_pkt_t *x25_udp_pkt = (x25_udp_pkt_t *)data; + + /* Set length of packet */ + len = sizeof(ip_pkt_t)+ + sizeof(udp_pkt_t)+ + sizeof(wp_mgmt_t)+ + sizeof(cblock_t)+ + mbox_len; + + + /* fill in UDP reply */ + x25_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; + + /* fill in UDP length */ + udp_length = sizeof(udp_pkt_t)+ + sizeof(wp_mgmt_t)+ + sizeof(cblock_t)+ + mbox_len; + + + /* put it on an even boundary */ + if ( udp_length & 0x0001 ) { + udp_length += 1; + len += 1; + even_bound = 1; + } + + temp = (udp_length<<8)|(udp_length>>8); + x25_udp_pkt->udp_pkt.udp_length = temp; + + /* swap UDP ports */ + temp = x25_udp_pkt->udp_pkt.udp_src_port; + x25_udp_pkt->udp_pkt.udp_src_port = + x25_udp_pkt->udp_pkt.udp_dst_port; + x25_udp_pkt->udp_pkt.udp_dst_port = temp; + + + + /* add UDP pseudo header */ + temp = 0x1100; + *((unsigned short *) + (x25_udp_pkt->data+mbox_len+even_bound)) = temp; + temp = (udp_length<<8)|(udp_length>>8); + *((unsigned short *) + (x25_udp_pkt->data+mbox_len+even_bound+2)) = temp; + + /* calculate UDP checksum */ + x25_udp_pkt->udp_pkt.udp_checksum = 0; + + x25_udp_pkt->udp_pkt.udp_checksum = + calc_checksum(&data[UDP_OFFSET], udp_length+UDP_OFFSET); + + /* fill in IP length */ + ip_length = len; + temp = (ip_length<<8)|(ip_length>>8); + x25_udp_pkt->ip_pkt.total_length = temp; + + /* swap IP addresses */ + ip_temp = x25_udp_pkt->ip_pkt.ip_src_address; + x25_udp_pkt->ip_pkt.ip_src_address = + x25_udp_pkt->ip_pkt.ip_dst_address; + x25_udp_pkt->ip_pkt.ip_dst_address = ip_temp; + + + /* fill in IP checksum */ + x25_udp_pkt->ip_pkt.hdr_checksum = 0; + x25_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data, sizeof(ip_pkt_t)); + + return len; +} /* reply_udp */ + +unsigned short calc_checksum (char *data, int len) +{ + unsigned short temp; + unsigned long sum=0; + int i; + + for( i = 0; i <len; i+=2 ) { + memcpy(&temp,&data[i],2); + sum += (unsigned long)temp; + } + + while (sum >> 16 ) { + sum = (sum & 0xffffUL) + (sum >> 16); + } + + temp = (unsigned short)sum; + temp = ~temp; + + if( temp == 0 ) + temp = 0xffff; + + return temp; +} + +/*============================================================================= + * Store a UDP management packet for later processing. + */ + +static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, + netdevice_t *dev, struct sk_buff *skb, int lcn) +{ + int udp_pkt_stored = 0; + + if(!card->u.x.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){ + card->u.x.udp_pkt_lgth = skb->len; + card->u.x.udp_type = udp_type; + card->u.x.udp_pkt_src = udp_pkt_src; + card->u.x.udp_lcn = lcn; + card->u.x.udp_dev = dev; + memcpy(card->u.x.udp_pkt_data, skb->data, skb->len); + card->u.x.timer_int_enabled |= TMR_INT_ENABLED_UDP_PKT; + udp_pkt_stored = 1; + + }else{ + printk(KERN_INFO "%s: ERROR: UDP packet not stored for LCN %d\n", + card->devname,lcn); + } + + if(udp_pkt_src == UDP_PKT_FRM_STACK){ + wan_dev_kfree_skb(skb, FREE_WRITE); + }else{ + wan_dev_kfree_skb(skb, FREE_READ); + } + + return(udp_pkt_stored); +} + + + +/*============================================================================= + * Initial the ppp_private_area structure. + */ +static void init_x25_channel_struct( x25_channel_t *chan ) +{ + memset(&chan->if_send_stat.if_send_entry,0,sizeof(if_send_stat_t)); + memset(&chan->rx_intr_stat.rx_intr_no_socket,0,sizeof(rx_intr_stat_t)); + memset(&chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err,0,sizeof(pipe_mgmt_stat_t)); +} + +/*============================================================================ + * Initialize Global Statistics + */ +static void init_global_statistics( sdla_t *card ) +{ + memset(&card->statistics.isr_entry,0,sizeof(global_stats_t)); +} + + +/*=============================================================== + * SMP Support + * ==============================================================*/ + +static void S508_S514_lock(sdla_t *card, unsigned long *smp_flags) +{ + spin_lock_irqsave(&card->wandev.lock, *smp_flags); +} +static void S508_S514_unlock(sdla_t *card, unsigned long *smp_flags) +{ + spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); +} + +/*=============================================================== + * x25_timer_routine + * + * A more efficient polling routine. Each half a second + * queue a polling task. We want to do the polling in a + * task not timer, because timer runs in interrupt time. + * + * FIXME Polling should be rethinked. + *==============================================================*/ + +static void x25_timer_routine(unsigned long data) +{ + sdla_t *card = (sdla_t*)data; + + if (!card->wandev.dev){ + printk(KERN_INFO "%s: Stopping the X25 Poll Timer: No Dev.\n", + card->devname); + return; + } + + if (card->open_cnt != card->u.x.num_of_ch){ + printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Interface down.\n", + card->devname); + return; + } + + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Shutting down.\n", + card->devname); + return; + } + + if (!test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ + trigger_x25_poll(card); + } + + card->u.x.x25_timer.expires=jiffies+(HZ>>1); + add_timer(&card->u.x.x25_timer); + return; +} + +void disable_comm_shutdown(sdla_t *card) +{ + TX25Mbox* mbox = card->mbox; + int err; + + /* Turn of interrutps */ + mbox->data[0] = 0; + if (card->hw.fwid == SFID_X25_508){ + mbox->data[1] = card->hw.irq; + mbox->data[2] = 2; + mbox->cmd.length = 3; + }else { + mbox->cmd.length = 1; + } + mbox->cmd.command = X25_SET_INTERRUPT_MODE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err) + printk(KERN_INFO "INTERRUPT OFF FAIED %x\n",err); + + /* Bring down HDLC */ + mbox->cmd.command = X25_HDLC_LINK_CLOSE; + mbox->cmd.length = 0; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err) + printk(KERN_INFO "LINK CLOSED FAILED %x\n",err); + + + /* Brind down DTR */ + mbox->data[0] = 0; + mbox->data[2] = 0; + mbox->data[1] = 0x01; + mbox->cmd.length = 3; + mbox->cmd.command = X25_SET_GLOBAL_VARS; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err) + printk(KERN_INFO "DTR DOWN FAILED %x\n",err); + +} /****** End *****************************************************************/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/wan/sdladrv.c linux.ac/drivers/net/wan/sdladrv.c --- linux.vanilla/drivers/net/wan/sdladrv.c Tue Apr 3 17:32:16 2001 +++ linux.ac/drivers/net/wan/sdladrv.c Sat Apr 14 01:28:20 2001 @@ -6,13 +6,19 @@ * * Author: Gideon Hack * -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* Copyright: (c) 1995-2000 Sangoma Technologies Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Mar 20, 2001 Nenad Corbic Added the auto_pci_cfg filed, to support +* the PCISLOT #0. +* Apr 04, 2000 Nenad Corbic Fixed the auto memory detection code. +* The memory test at address 0xC8000. +* Mar 09, 2000 Nenad Corbic Added Gideon's Bug Fix: clear pci +* interrupt flags on initial load. * Jun 02, 1999 Gideon Hack Added support for the S514 adapter. * Updates for Linux 2.2.X kernels. * Sep 17, 1998 Jaspreet Singh Updates for linux 2.2.X kernels @@ -84,7 +90,6 @@ #if defined(_LINUX_) /****** Linux *******************************/ -#include <linux/config.h> #include <linux/version.h> #include <linux/kernel.h> /* printk(), and other useful stuff */ #include <linux/stddef.h> /* offsetof(), etc. */ @@ -102,7 +107,16 @@ #define _OUTB(port, byte) (outb((byte),(port))) #define SYSTEM_TICK jiffies -#include <linux/init.h> + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + #include <linux/init.h> +#else + #include <linux/bios32.h>/* BIOS32, PCI BIOS functions and definitions */ + #define ioremap vremap + #define iounmap vfree + extern void * vremap (unsigned long offset, unsigned long size); + extern void vfree (void *addr); +#endif #elif defined(_SCO_UNIX_) /****** SCO Unix ****************************/ @@ -190,16 +204,21 @@ static unsigned check_memregion (void* ptr, unsigned len); static unsigned test_memregion (void* ptr, unsigned len); static unsigned short checksum (unsigned char* buf, unsigned len); +static int init_pci_slot(sdlahw_t *); + +static int pci_probe(sdlahw_t *hw); /****** Global Data ********************************************************** * Note: All data must be explicitly initialized!!! */ +#ifdef LINUX_2_4 static struct pci_device_id sdladrv_pci_tbl[] __initdata = { { V3_VENDOR_ID, V3_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, sdladrv_pci_tbl); +#endif /* private data */ static char modname[] = "sdladrv"; @@ -298,6 +317,8 @@ 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0 }; +static int pci_slot_ar[MAX_S514_CARDS]; + /******* Kernel Loadable Module Entry Points ********************************/ /*============================================================================ @@ -314,15 +335,24 @@ #ifdef MODULE int init_module (void) #else -int __init wanpipe_init(void) +int sdladrv_init(void) #endif { + int i=0; + printk(KERN_INFO "%s v%u.%u %s\n", fullname, MOD_VERSION, MOD_RELEASE, copyright); exec_idle = calibrate_delay(EXEC_DELAY); #ifdef WANDEBUG printk(KERN_DEBUG "%s: exec_idle = %d\n", modname, exec_idle); #endif + + /* Initialize the PCI Card array, which + * will store flags, used to mark + * card initialization state */ + for (i=0; i<MAX_S514_CARDS; i++) + pci_slot_ar[i] = 0xFF; + return 0; } @@ -350,7 +380,9 @@ * < 0 error */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(sdla_setup); +#endif int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len) { @@ -361,7 +393,7 @@ if (sdla_detect(hw)) { if(hw->type != SDLA_S514) - printk(KERN_ERR "%s: no SDLA card found at port 0x%X\n", + printk(KERN_INFO "%s: no SDLA card found at port 0x%X\n", modname, hw->port); return -EINVAL; } @@ -410,7 +442,7 @@ /* Verify IRQ configuration options */ if (!get_option_index(irq_opt, hw->irq)) { - printk(KERN_ERR "%s: IRQ %d is illegal!\n", + printk(KERN_INFO "%s: IRQ %d is illegal!\n", modname, hw->irq); return -EINVAL; } @@ -420,7 +452,7 @@ hw->pclk = pclk_opt[1]; /* use default */ else if (!get_option_index(pclk_opt, hw->pclk)) { - printk(KERN_ERR "%s: CPU clock %u is illegal!\n", + printk(KERN_INFO "%s: CPU clock %u is illegal!\n", modname, hw->pclk); return -EINVAL; } @@ -431,7 +463,7 @@ if (hw->dpmbase == 0) { err = sdla_autodpm(hw); if (err) { - printk(KERN_ERR + printk(KERN_INFO "%s: can't find available memory region!\n", modname); return err; @@ -439,13 +471,13 @@ } else if (!get_option_index(dpmbase_opt, virt_to_phys(hw->dpmbase))) { - printk(KERN_ERR + printk(KERN_INFO "%s: memory address 0x%lX is illegal!\n", modname, virt_to_phys(hw->dpmbase)); return -EINVAL; } else if (sdla_setdpm(hw)) { - printk(KERN_ERR + printk(KERN_INFO "%s: 8K memory region at 0x%lX is not available!\n", modname, virt_to_phys(hw->dpmbase)); return -EINVAL; @@ -453,13 +485,27 @@ printk(KERN_INFO "%s: dual-port memory window is set at 0x%lX.\n", modname, virt_to_phys(hw->dpmbase)); + + + /* If we find memory in 0xE**** Memory region, + * warn the user to disable the SHADOW RAM. + * Since memory corruption can occur if SHADOW is + * enabled. This can causes random crashes ! */ + if (virt_to_phys(hw->dpmbase) >= 0xE0000){ + printk(KERN_WARNING "\n%s: !!!!!!!! WARNING !!!!!!!!\n",modname); + printk(KERN_WARNING "%s: WANPIPE is using 0x%lX memory region !!!\n", + modname, virt_to_phys(hw->dpmbase)); + printk(KERN_WARNING " Please disable the SHADOW RAM, otherwise\n"); + printk(KERN_WARNING " your system might crash randomly from time to time !\n"); + printk(KERN_WARNING "%s: !!!!!!!! WARNING !!!!!!!!\n\n",modname); + } } else { hw->memory = test_memregion((void*)hw->dpmbase, MAX_SIZEOF_S514_MEMORY); if(hw->memory < (256 * 1024)) { - printk(KERN_ERR + printk(KERN_INFO "%s: error in testing S514 memory (0x%lX)\n", modname, hw->memory); sdla_down(hw); @@ -481,7 +527,9 @@ * Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(sdla_down); +#endif int sdla_down (sdlahw_t* hw) { @@ -523,9 +571,10 @@ *(char *)hw->vector = S514_CPU_HALT; CPU_no = hw->S514_cpu_no[0]; +#if defined(LINUX_2_1) || defined(LINUX_2_4) /* disable the PCI IRQ and disable memory access */ pci_read_config_dword(hw->pci_dev, PCI_INT_CONFIG, &int_config); - int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A : ~PCI_DISABLE_IRQ_CPU_B; + int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A : ~PCI_DISABLE_IRQ_CPU_B; pci_write_config_dword(hw->pci_dev, PCI_INT_CONFIG, int_config); read_S514_int_stat(hw, &int_status); S514_intack(hw, int_status); @@ -535,6 +584,22 @@ else pci_write_config_dword(hw->pci_dev, PCI_MAP1_DWORD, PCI_CPU_B_MEM_DISABLE); +#else + /* disable the PCI IRQ and disable memory access */ + pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func, + PCI_INT_CONFIG, &int_config); + int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A : ~PCI_DISABLE_IRQ_CPU_B; + pcibios_write_config_dword(hw->pci_bus, hw->pci_dev_func, + PCI_INT_CONFIG, int_config); + read_S514_int_stat(hw, &int_status); + S514_intack(hw, int_status); + // disable PCI memory access + if(CPU_no == S514_CPU_A) + pcibios_write_config_dword(hw->pci_bus,hw->pci_dev_func, + PCI_MAP0_DWORD, PCI_CPU_A_MEM_DISABLE); + else + pcibios_write_config_dword(hw->pci_bus,hw->pci_dev_func, PCI_MAP1_DWORD, PCI_CPU_B_MEM_DISABLE); +#endif /* free up the allocated virtual memory */ iounmap((void *)hw->dpmbase); @@ -552,7 +617,9 @@ * Map shared memory window into SDLA address space. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(sdla_mapmem); +#endif int sdla_mapmem (sdlahw_t* hw, unsigned long addr) { @@ -613,7 +680,9 @@ * Enable interrupt generation. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(sdla_inten); +#endif int sdla_inten (sdlahw_t* hw) { @@ -669,7 +738,9 @@ * Disable interrupt generation. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(sdla_intde); +#endif int sdla_intde (sdlahw_t* hw) { @@ -724,7 +795,9 @@ * Acknowledge SDLA hardware interrupt. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(sdla_intack); +#endif int sdla_intack (sdlahw_t* hw) { @@ -774,11 +847,18 @@ * Acknowledge S514 hardware interrupt. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(S514_intack); +#endif void S514_intack (sdlahw_t* hw, u32 int_status) { +#if defined(LINUX_2_1) || defined(LINUX_2_4) pci_write_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status); +#else + pcibios_write_config_dword(hw->pci_bus, hw->pci_dev_func, + PCI_INT_STATUS, int_status); +#endif } @@ -786,11 +866,18 @@ * Read the S514 hardware interrupt status. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(read_S514_int_stat); +#endif void read_S514_int_stat (sdlahw_t* hw, u32* int_status) { +#if defined(LINUX_2_1) || defined(LINUX_2_4) pci_read_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status); +#else + pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func, PCI_INT_STATUS, + int_status); +#endif } @@ -798,7 +885,9 @@ * Generate an interrupt to adapter's CPU. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(sdla_intr); +#endif int sdla_intr (sdlahw_t* hw) { @@ -842,7 +931,9 @@ * o Return number of loops made, or 0 if command timed out. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(sdla_exec); +#endif int sdla_exec (void* opflag) { @@ -878,7 +969,9 @@ * interrupt routines are accessing adapter shared memory. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(sdla_peek); +#endif int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) { @@ -960,7 +1053,9 @@ * interrupt routines are accessing adapter shared memory. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(sdla_poke); +#endif int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) { @@ -1124,7 +1219,11 @@ return -EINVAL; } - for (i = opt[0]; i && err; --i) { + /* Start testing from 8th position, address + * 0xC8000 from the 508 address table. + * We don't want to test A**** addresses, since + * they are usually used for Video */ + for (i = 8; i <= opt[0] && err; i++) { hw->dpmbase = phys_to_virt(opt[i]); err = sdla_setdpm(hw); } @@ -1176,14 +1275,14 @@ /* Verify firmware signature */ if (strcmp(sfm->signature, SFM_SIGNATURE)) { - printk(KERN_ERR "%s: not SDLA firmware!\n", + printk(KERN_INFO "%s: not SDLA firmware!\n", modname); return -EINVAL; } /* Verify firmware module format version */ if (sfm->version != SFM_VERSION) { - printk(KERN_ERR + printk(KERN_INFO "%s: firmware format %u rejected! Expecting %u.\n", modname, sfm->version, SFM_VERSION); return -EINVAL; @@ -1193,7 +1292,7 @@ if ((len - offsetof(sfm_t, image) != sfm->info.codesize) || (checksum((void*)&sfm->info, sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum)) { - printk(KERN_ERR "%s: firmware corrupted!\n", modname); + printk(KERN_INFO "%s: firmware corrupted!\n", modname); return -EINVAL; } @@ -1211,19 +1310,18 @@ */ for (i = 0; (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type); - ++i) - ; + ++i); + if (i == SFM_MAX_SDLA) { - printk(KERN_ERR "%s: firmware is not compatible with S%u!\n", + printk(KERN_INFO "%s: firmware is not compatible with S%u!\n", modname, hw->type); - ; return -EINVAL; } /* Make sure there is enough on-board memory */ if (hw->memory < sfm->info.memsize) { - printk(KERN_ERR + printk(KERN_INFO "%s: firmware needs %lu bytes of on-board memory!\n", modname, sfm->info.memsize); return -EINVAL; @@ -1231,7 +1329,7 @@ /* Move code onto adapter */ if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize)) { - printk(KERN_ERR "%s: failed to load code segment!\n", + printk(KERN_INFO "%s: failed to load code segment!\n", modname); return -EIO; } @@ -1239,14 +1337,14 @@ /* Prepare boot-time configuration data and kick-off CPU */ sdla_bootcfg(hw, &sfm->info); if (sdla_start(hw, sfm->info.startoffs)) { - printk(KERN_ERR "%s: Damn... Adapter won't start!\n", + printk(KERN_INFO "%s: Damn... Adapter won't start!\n", modname); return -EIO; } /* position DPM window over the mailbox and enable interrupts */ if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw)) { - printk(KERN_ERR "%s: adapter hardware failure!\n", + printk(KERN_INFO "%s: adapter hardware failure!\n", modname); return -EIO; } @@ -1858,22 +1956,30 @@ */ static int detect_s514 (sdlahw_t* hw) { - unsigned char CPU_no, slot_no; + unsigned char CPU_no, slot_no, auto_slot_cfg; int number_S514_cards = 0; u32 S514_mem_base_addr = 0; u32 ut_u32; +#if defined(LINUX_2_1) || defined(LINUX_2_4) struct pci_dev *pci_dev; +#else + u8 ut_u8; +#endif #ifdef CONFIG_PCI +#if defined(LINUX_2_1) || defined(LINUX_2_4) if(!pci_present()) +#else + if(!pcibios_present()) +#endif { - printk(KERN_ERR "%s: PCI BIOS not present!\n", modname); + printk(KERN_INFO "%s: PCI BIOS not present!\n", modname); return 0; } #else - printk(KERN_ERR "%s: Linux not compiled for PCI usage!\n", modname); + printk(KERN_INFO "%s: Linux not compiled for PCI usage!\n", modname); return 0; #endif @@ -1883,10 +1989,17 @@ */ CPU_no = hw->S514_cpu_no[0]; slot_no = hw->S514_slot_no; - - printk(KERN_INFO "%s: detecting S514 card, CPU %c, slot #%d\n", - modname, CPU_no, slot_no); + auto_slot_cfg = hw->auto_pci_cfg; + if (auto_slot_cfg){ + printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot=Auto\n", + modname, CPU_no); + + }else{ + printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot #%d\n", + modname, CPU_no, slot_no); + } + /* check to see that CPU A or B has been selected in 'router.conf' */ switch(CPU_no) { case S514_CPU_A: @@ -1894,9 +2007,9 @@ break; default: - printk(KERN_ERR "%s: S514 CPU definition invalid.\n", + printk(KERN_INFO "%s: S514 CPU definition invalid.\n", modname); - printk(KERN_ERR "Must be 'A' or 'B'\n"); + printk(KERN_INFO "Must be 'A' or 'B'\n"); return 0; } @@ -1904,50 +2017,110 @@ if(!number_S514_cards) return 0; - /* we are using a single S514 adapter with a slot of 0 so re-read the */ /* location of this adapter */ - if((number_S514_cards == 1) && !slot_no) { + /* we are using a single S514 adapter with a slot of 0 so re-read the */ + /* location of this adapter */ + if((number_S514_cards == 1) && auto_slot_cfg) { number_S514_cards = find_s514_adapter(hw, 1); if(!number_S514_cards) { - printk(KERN_ERR "%s: Error finding PCI card\n", + printk(KERN_INFO "%s: Error finding PCI card\n", modname); return 0; } } + #if defined(LINUX_2_4) pci_dev = hw->pci_dev; /* read the physical memory base address */ S514_mem_base_addr = (CPU_no == S514_CPU_A) ? (pci_dev->resource[1].start) : (pci_dev->resource[2].start); + + #elif defined (LINUX_2_1) + pci_dev = hw->pci_dev; + /* read the physical memory base address */ + S514_mem_base_addr = (CPU_no == S514_CPU_A) ? + (pci_dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK) : + (pci_dev->base_address[2] & PCI_BASE_ADDRESS_MEM_MASK); + + #else + pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func, + (CPU_no == S514_CPU_A) ? PCI_MEM_BASE0_DWORD : + PCI_MEM_BASE1_DWORD, &S514_mem_base_addr); + #endif printk(KERN_INFO "%s: S514 PCI memory at 0x%X\n", modname, S514_mem_base_addr); if(!S514_mem_base_addr) { if(CPU_no == S514_CPU_B) - printk(KERN_ERR "%s: CPU #B not present on the card\n", modname); + printk(KERN_INFO "%s: CPU #B not present on the card\n", modname); else - printk(KERN_ERR "%s: No PCI memory allocated to card\n", modname); + printk(KERN_INFO "%s: No PCI memory allocated to card\n", modname); return 0; } /* enable the PCI memory */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) pci_read_config_dword(pci_dev, (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, &ut_u32); pci_write_config_dword(pci_dev, (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, (ut_u32 | PCI_MEMORY_ENABLE)); +#else + pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func, + (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, + &ut_u32); + pcibios_write_config_dword(hw->pci_bus, hw->pci_dev_func, + (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, + (ut_u32 | PCI_MEMORY_ENABLE)); +#endif /* check the IRQ allocated and enable IRQ usage */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) if(!(hw->irq = pci_dev->irq)) { - printk(KERN_ERR "%s: IRQ not allocated to S514 adapter\n", + printk(KERN_INFO "%s: IRQ not allocated to S514 adapter\n", modname); return 0; } + + /* BUG FIX : Mar 6 2000 + * On a initial loading of the card, we must check + * and clear PCI interrupt bits, due to a reset + * problem on some other boards. i.e. An interrupt + * might be pending, even after system bootup, + * in which case, when starting wanrouter the machine + * would crash. + */ + if (init_pci_slot(hw)) + return 0; + pci_read_config_dword(pci_dev, PCI_INT_CONFIG, &ut_u32); ut_u32 |= (CPU_no == S514_CPU_A) ? PCI_ENABLE_IRQ_CPU_A : PCI_ENABLE_IRQ_CPU_B; pci_write_config_dword(pci_dev, PCI_INT_CONFIG, ut_u32); +#else + /* the INTPIN must not be 0 - if it is, then the S514 adapter is not */ + /* configured for IRQ usage */ + pcibios_read_config_byte(hw->pci_bus, hw->pci_dev_func, + PCI_INT_PIN_BYTE, &ut_u8); + if(!ut_u8) { + printk(KERN_INFO "%s: invalid setting for INTPIN on S514 card\n", modname); + printk(KERN_INFO "Please contact your Sangoma representative\n"); + return 0; + } + pcibios_read_config_byte(hw->pci_bus, hw->pci_dev_func, + PCI_INT_LINE_BYTE, (unsigned char *)&hw->irq); + if(hw->irq == PCI_IRQ_NOT_ALLOCATED) { + printk(KERN_INFO "%s: IRQ not allocated to S514 adapter\n", + modname); + return 0; + } + pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func, PCI_INT_CONFIG, &ut_u32); + ut_u32 |= (CPU_no == S514_CPU_A) ? + PCI_ENABLE_IRQ_CPU_A : PCI_ENABLE_IRQ_CPU_B; + pcibios_write_config_dword(hw->pci_bus, hw->pci_dev_func, + PCI_INT_CONFIG, ut_u32); +#endif printk(KERN_INFO "%s: IRQ %d allocated to the S514 card\n", modname, hw->irq); @@ -1961,7 +2134,7 @@ (unsigned long)16); if(!hw->dpmbase || !hw->vector) { - printk(KERN_ERR "%s: PCI virtual memory allocation failed\n", + printk(KERN_INFO "%s: PCI virtual memory allocation failed\n", modname); return 0; } @@ -1983,49 +2156,99 @@ char S514_found_in_slot = 0; u16 PCI_subsys_vendor; +#if defined(LINUX_2_1) || defined(LINUX_2_4) struct pci_dev *pci_dev = NULL; +#else + int pci_index; +#endif slot_no = hw->S514_slot_no; +#if defined(LINUX_2_1) || defined(LINUX_2_4) while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev)) != NULL) { - if (pci_enable_device(pci_dev)) - continue; - PCI_subsys_vendor = pci_dev->subsystem_vendor; - if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) + + pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD, + &PCI_subsys_vendor); + + if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) continue; - hw->pci_dev = pci_dev; + + hw->pci_dev = pci_dev; + if(find_first_S514_card) return(1); + number_S514_cards ++; - printk(KERN_INFO + + printk(KERN_INFO "%s: S514 card found, slot #%d (devfn 0x%X)\n", modname, ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), pci_dev->devfn); - if(slot_no && (((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK) == - slot_no)) { + + if (hw->auto_pci_cfg){ + hw->S514_slot_no = ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK); + slot_no = hw->S514_slot_no; + + }else if (((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK) == slot_no){ + S514_found_in_slot = 1; + break; + } + } + +#else + //LINUX VERSION 2.0.X + for (pci_index = 0; pci_index < MAX_S514_CARDS; pci_index ++) { + if (pcibios_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_index, + &hw->pci_bus, &hw->pci_dev_func)!=PCIBIOS_SUCCESSFUL) { + break; + } + + pcibios_read_config_word(hw->pci_bus, hw->pci_dev_func, + PCI_SUBSYS_VENDOR_WORD, &PCI_subsys_vendor); + + if (PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) + continue; + + if (find_first_S514_card) + return(1); + + number_S514_cards ++; + + printk(KERN_INFO "%s: S514 card found, bus #%d, slot #%d\n", + modname, hw->pci_bus, + ((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK)); + + if (hw->auto_pci_cfg){ + hw->S514_slot_no = ((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK) + slot_no = hw->S514_slot_no; + + }else if (((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK) == slot_no) { S514_found_in_slot = 1; break; } } +#endif /* if no S514 adapter has been found, then exit */ - if(!number_S514_cards) { - printk(KERN_ERR "%s: no S514 adapters found\n", modname); + if (!number_S514_cards) { + printk(KERN_INFO "%s: Error, no S514 adapters found\n", modname); return 0; } /* if more than one S514 card has been found, then the user must have */ /* defined a slot number so that the correct adapter is used */ - else if((number_S514_cards > 1) && !slot_no) { - printk(KERN_ERR "%s: More than one S514 adapter found\n", - modname); - printk(KERN_ERR "Define a PCI slot number for this adapter\n"); + else if ((number_S514_cards > 1) && hw->auto_pci_cfg) { + printk(KERN_INFO "%s: Error, PCI Slot autodetect Failed! \n" + "%s: More than one S514 adapter found.\n" + "%s: Disable the Autodetect feature and supply\n" + "%s: the PCISLOT numbers for each card.\n", + modname,modname,modname,modname); return 0; } /* if the user has specified a slot number and the S514 adapter has */ /* not been found in that slot, then exit */ - else if (slot_no && !S514_found_in_slot) { - printk(KERN_ERR - "%s: S514 card not found in specified slot #%d\n", + else if (!hw->auto_pci_cfg && !S514_found_in_slot) { + printk(KERN_INFO + "%s: Error, S514 card not found in specified slot #%d\n", modname, slot_no); return 0; } @@ -2138,5 +2361,170 @@ return crc; } +static int init_pci_slot(sdlahw_t *hw) +{ + + u32 int_status; + int volatile found=0; + int i=0; + + /* Check if this is a very first load for a specific + * pci card. If it is, clear the interrput bits, and + * set the flag indicating that this card was initialized. + */ + + for (i=0; (i<MAX_S514_CARDS) && !found; i++){ + if (pci_slot_ar[i] == hw->S514_slot_no){ + found=1; + break; + } + if (pci_slot_ar[i] == 0xFF){ + break; + } + } + + if (!found){ + read_S514_int_stat(hw,&int_status); + S514_intack(hw,int_status); + if (i == MAX_S514_CARDS){ + printk(KERN_INFO "%s: Critical Error !!!\n",modname); + printk(KERN_INFO + "%s: Number of Sangoma PCI cards exceeded maximum limit.\n", + modname); + printk(KERN_INFO "Please contact Sangoma Technologies\n"); + return 1; + } + pci_slot_ar[i] = hw->S514_slot_no; + } + return 0; +} + +static int pci_probe(sdlahw_t *hw) +{ + + unsigned char slot_no; + int number_S514_cards = 0; + u16 PCI_subsys_vendor; + u16 PCI_card_type; + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + struct pci_dev *pci_dev = NULL; + struct pci_bus *bus = NULL; +#else + int pci_index; + u8 irq; +#endif + + slot_no = 0; + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev)) + != NULL) { + + pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD, + &PCI_subsys_vendor); + + if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) + continue; + + pci_read_config_word(pci_dev, PCI_CARD_TYPE, + &PCI_card_type); + + bus = pci_dev->bus; + + /* A dual cpu card can support up to 4 physical connections, + * where a single cpu card can support up to 2 physical + * connections. The FT1 card can only support a single + * connection, however we cannot distinguish between a Single + * CPU card and an FT1 card. */ + if (PCI_card_type == S514_DUAL_CPU){ + number_S514_cards += 4; + printk(KERN_INFO + "wanpipe: S514-PCI card found, cpu(s) 2, bus #%d, slot #%d, irq #%d\n", + bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), + pci_dev->irq); + }else{ + number_S514_cards += 2; + printk(KERN_INFO + "wanpipe: S514-PCI card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n", + bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), + pci_dev->irq); + } + } + +#else + for (pci_index = 0; pci_index < MAX_S514_CARDS; pci_index ++) { + + if(pcibios_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_index, + &hw->pci_bus, &hw->pci_dev_func)!=PCIBIOS_SUCCESSFUL) { + break; + } + pcibios_read_config_word(hw->pci_bus, hw->pci_dev_func, + PCI_SUBSYS_VENDOR_WORD, &PCI_subsys_vendor); + if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) + continue; + + pcibios_read_config_word(hw->pci_bus,hw->pci_dev_func,PCI_CARD_TYPE, + &PCI_card_type); + + pcibios_read_config_byte(hw->pci_bus, hw->pci_dev_func, + PCI_INT_LINE_BYTE, &irq); + + /* A dual cpu card can support up to 4 physical connections, + * where a single cpu card can support up to 2 physical + * connections. The FT1 card can only support a single + * connection, however we cannot distinguish between a Single + * CPU card and an FT1 card. */ + if (PCI_card_type == S514_DUAL_CPU){ + number_S514_cards += 4; + printk(KERN_INFO "%s: S514-PCI card found, cpu(s) 2, bus #%d, slot #%d, irq #%d\n", + modname, hw->pci_bus, + ((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK),irq); + }else{ + printk(KERN_INFO "%s: S514-PCI card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n", + modname, hw->pci_bus, + ((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK),irq); + number_S514_cards += 2; + } + } +#endif + + return number_S514_cards; + +} + + + +#if defined(LINUX_2_1) || defined(LINUX_2_4) +EXPORT_SYMBOL(wanpipe_hw_probe); +#endif + +unsigned wanpipe_hw_probe(void) +{ + sdlahw_t hw; + unsigned* opt = s508_port_options; + unsigned cardno=0; + int i; + + memset(&hw, 0, sizeof(hw)); + + for (i = 1; i <= opt[0]; i++) { + if (detect_s508(opt[i])){ + /* S508 card can support up to two physical links */ + cardno+=2; + printk(KERN_INFO "wanpipe: S508-ISA card found, port 0x%x\n",opt[i]); + } + } + + #ifdef CONFIG_PCI + hw.S514_slot_no = 0; + cardno += pci_probe(&hw); + #else + printk(KERN_INFO "wanpipe: Warning, Kernel not compiled for PCI support!\n"); + printk(KERN_INFO "wanpipe: PCI Hardware Probe Failed!\n"); + #endif + + return cardno; +} /****** End *****************************************************************/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/wan/sdlamain.c linux.ac/drivers/net/wan/sdlamain.c --- linux.vanilla/drivers/net/wan/sdlamain.c Tue Apr 3 17:32:16 2001 +++ linux.ac/drivers/net/wan/sdlamain.c Mon Apr 16 15:02:17 2001 @@ -1,16 +1,28 @@ -/***************************************************************************** +/**************************************************************************** * sdlamain.c WANPIPE(tm) Multiprotocol WAN Link Driver. Main module. * * Author: Nenad Corbic <ncorbic@sangoma.com> * Gideon Hack * -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* Copyright: (c) 1995-2000 Sangoma Technologies Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Dec 22, 2000 Nenad Corbic Updated for 2.4.X kernels. +* Removed the polling routine. +* Nov 13, 2000 Nenad Corbic Added hw probing on module load and dynamic +* device allocation. +* Nov 7, 2000 Nenad Corbic Fixed the Multi-Port PPP for kernels +* 2.2.16 and above. +* Aug 2, 2000 Nenad Corbic Block the Multi-Port PPP from running on +* kernels 2.2.16 or greater. The SyncPPP +* has changed. +* Jul 25, 2000 Nenad Corbic Updated the Piggiback support for MultPPPP. +* Jul 13, 2000 Nenad Corbic Added Multi-PPP support. +* Feb 02, 2000 Nenad Corbic Fixed up piggyback probing and selection. * Sep 23, 1999 Nenad Corbic Added support for SMP * Sep 13, 1999 Nenad Corbic Each port is treated as a separate device. * Jun 02, 1999 Gideon Hack Added support for the S514 adapter. @@ -39,17 +51,125 @@ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ #include <linux/string.h> /* inline memset(), etc. */ -#include <linux/slab.h> /* kmalloc(), kfree() */ +#include <linux/malloc.h> /* kmalloc(), kfree() */ #include <linux/kernel.h> /* printk(), and other useful stuff */ #include <linux/module.h> /* support for loadable modules */ #include <linux/ioport.h> /* request_region(), release_region() */ -#include <linux/tqueue.h> /* for kernel task queues */ #include <linux/wanrouter.h> /* WAN router definitions */ #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ -#include <asm/uaccess.h> /* kernel <-> user copy */ + +#include <linux/in.h> #include <asm/io.h> /* phys_to_virt() */ #include <linux/pci.h> #include <linux/sdlapci.h> +#include <linux/if_wanpipe_common.h> + +#if defined(LINUX_2_4) + + #include <asm/uaccess.h> /* kernel <-> user copy */ + #include <linux/inetdevice.h> + #define netdevice_t struct net_device + +#elif defined(LINUX_2_1) + + #include <asm/uaccess.h> /* kernel <-> user copy */ + #include <linux/inetdevice.h> + #define netdevice_t struct device + +#else + + #include <asm/segment.h> + #define devinet_ioctl(x,y) dev_ioctl(x,y) + #define netdevice_t struct device + #define test_and_set_bit set_bit + typedef unsigned long mm_segment_t; +#endif + +#include <linux/ip.h> +#include <net/route.h> + +#define KMEM_SAFETYZONE 8 + + +#ifndef CONFIG_WANPIPE_FR + #define wpf_init(a,b) (-EPROTONOSUPPORT) +#endif + +#ifndef CONFIG_WANPIPE_CHDLC + #define wpc_init(a,b) (-EPROTONOSUPPORT) +#endif + +#ifndef CONFIG_WANPIPE_X25 + #define wpx_init(a,b) (-EPROTONOSUPPORT) +#endif + +#ifndef CONFIG_WANPIPE_PPP + #define wpp_init(a,b) (-EPROTONOSUPPORT) +#endif + +#ifndef CONFIG_WANPIPE_MULTPPP + #define wsppp_init(a,b) (-EPROTONOSUPPORT) +#endif + + +/***********FOR DEBUGGING PURPOSES********************************************* +static void * dbg_kmalloc(unsigned int size, int prio, int line) { + int i = 0; + void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); + char * c1 = v; + c1 += sizeof(unsigned int); + *((unsigned int *)v) = size; + + for (i = 0; i < KMEM_SAFETYZONE; i++) { + c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; + c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; + c1 += 8; + } + c1 += size; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; + c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; + c1 += 8; + } + v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; + printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); + return v; +} +static void dbg_kfree(void * v, int line) { + unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); + unsigned int size = *sp; + char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; + int i = 0; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' + || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { + printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); + printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, + c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); + } + c1 += 8; + } + c1 += size; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' + || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' + ) { + printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); + printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, + c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); + } + c1 += 8; + } + printk(KERN_INFO "line %d kfree(%p)\n",line,v); + v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); + kfree(v); +} + +#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) +#define kfree(x) dbg_kfree(x,__LINE__) +******************************************************************************/ + + /****** Defines & Macros ****************************************************/ @@ -61,7 +181,7 @@ #define DRV_VERSION 5 /* version number */ #define DRV_RELEASE 0 /* release (minor version) number */ -#define MAX_CARDS 8 /* max number of adapters */ +#define MAX_CARDS 16 /* max number of adapters */ #ifndef CONFIG_WANPIPE_CARDS /* configurable option */ #define CONFIG_WANPIPE_CARDS 1 @@ -86,12 +206,16 @@ /* IOCTL handlers */ static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump); -static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec); +static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec, int); /* Miscellaneous functions */ STATIC void sdla_isr (int irq, void* dev_id, struct pt_regs *regs); -STATIC void sdla_poll (void* data); static void release_hw (sdla_t *card); +static void run_wanpipe_tq (unsigned long); + +static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int*); +static int check_s514_conflicts (sdla_t* card,wandev_conf_t* conf, int*); + /****** Global Data ********************************************************** * Note: All data must be explicitly initialized!!! @@ -100,13 +224,41 @@ /* private data */ static char drvname[] = "wanpipe"; static char fullname[] = "WANPIPE(tm) Multiprotocol Driver"; -static char copyright[] = "(c) 1995-1999 Sangoma Technologies Inc."; -static int ncards = CONFIG_WANPIPE_CARDS; -static int active; /* number of active cards */ -static sdla_t* card_array; /* adapter data space */ +static char copyright[] = "(c) 1995-2000 Sangoma Technologies Inc."; +static int ncards = 0; +static sdla_t* card_array = NULL; /* adapter data space */ + +/* Wanpipe's own task queue, used for all API's. + * All protocol specific tasks will be instered + * into "wanpipe_tq_custom" task_queue. + + * On each rx_interrupt, the whole task queue + * (wanpipe_tq_custom) will be queued into + * IMMEDIATE_BH via wanpipe_mark_bh() call. + + * The IMMEDIATE_BH will execute run_wanpipe_tq() + * function, which will execute all pending, + * tasks in wanpipe_tq_custom queue */ + +#ifdef LINUX_2_4 +DECLARE_TASK_QUEUE(wanpipe_tq_custom); +static struct tq_struct wanpipe_tq_task = +{ + routine: (void (*)(void *)) run_wanpipe_tq, + data: &wanpipe_tq_custom +}; +#else +static struct tq_struct *wanpipe_tq_custom = NULL; +static struct tq_struct wanpipe_tq_task = +{ + NULL, + 0, + (void *)(void *) run_wanpipe_tq, + &wanpipe_tq_custom +}; +#endif -/* Task queue element for creating a 'thread' */ -static struct tq_struct sdla_tq = { routine: sdla_poll }; +static int wanpipe_bh_critical=0; /******* Kernel Loadable Module Entry Points ********************************/ @@ -126,7 +278,7 @@ #ifdef MODULE int init_module (void) #else -int wanpipe_init2(void) +int wanpipe_init(void) #endif { int cnt, err = 0; @@ -134,9 +286,17 @@ printk(KERN_INFO "%s v%u.%u %s\n", fullname, DRV_VERSION, DRV_RELEASE, copyright); + /* Probe for wanpipe cards and return the number found */ + printk(KERN_INFO "wanpipe: Probing for WANPIPE hardware.\n"); + ncards = wanpipe_hw_probe(); + if (ncards){ + printk(KERN_INFO "wanpipe: Allocating maximum %i devices: wanpipe%i - wanpipe%i.\n",ncards,1,ncards); + }else{ + printk(KERN_INFO "wanpipe: No S514/S508 cards found, unloading modules!\n"); + return -ENODEV; + } + /* Verify number of cards and allocate adapter data space */ - ncards = min(ncards, MAX_CARDS); - ncards = max(ncards, 1); card_array = kmalloc(sizeof(sdla_t) * ncards, GFP_KERNEL); if (card_array == NULL) return -ENOMEM; @@ -159,7 +319,7 @@ wandev->ioctl = &ioctl; err = register_wan_device(wandev); if (err) { - printk(KERN_ERR + printk(KERN_INFO "%s: %s registration failed with error %d!\n", drvname, card->devname, err); break; @@ -172,6 +332,7 @@ printk(KERN_INFO "IN Init Module: NO Cards registered\n"); err = -ENODEV; } + return err; } @@ -185,11 +346,16 @@ { int i; + if (!ncards) + return; + for (i = 0; i < ncards; ++i) { sdla_t* card = &card_array[i]; unregister_wan_device(card->devname); } kfree(card_array); + + printk(KERN_INFO "\nwanpipe: WANPIPE Modules Unloaded.\n"); } #endif @@ -218,15 +384,25 @@ sdla_t* card; int err = 0; int irq=0; - int i; /* Sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL)) + if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL)){ + printk(KERN_INFO + "%s: Failed Sdlamain Setup wandev %u, card %u, conf %u !\n", + wandev->name, + (unsigned int)wandev,(unsigned int)wandev->private, + (unsigned int)conf); return -EFAULT; - + } + + printk(KERN_INFO "%s: Starting WAN Setup\n", wandev->name); + card = wandev->private; - if (wandev->state != WAN_UNCONFIGURED) + if (wandev->state != WAN_UNCONFIGURED){ + printk(KERN_INFO "%s: failed sdlamain setup, busy!\n", + wandev->name); return -EBUSY; /* already configured */ + } printk(KERN_INFO "\nProcessing WAN device %s...\n", wandev->name); @@ -239,84 +415,21 @@ wandev->config_id = conf->config_id; if (!conf->data_size || (conf->data == NULL)) { - printk(KERN_ERR + printk(KERN_INFO "%s: firmware not found in configuration data!\n", wandev->name); return -EINVAL; } - /* only check I/O port and IRQ if not an S514 adapter */ + /* Check for resource conflicts and setup the + * card for piggibacking if necessary */ if(!conf->S514_CPU_no[0]) { - - if (conf->ioport <= 0) { - printk(KERN_ERR - "%s: can't configure without I/O port address!\n", - wandev->name); - return -EINVAL; - } - - if (conf->irq <= 0) { - printk(KERN_ERR "%s: can't configure without IRQ!\n", - wandev->name); - return -EINVAL; - } - - /* Check for already loaded card with the same IO port and IRQ - * If found, copy its hardware configuration and use its - * resources (i.e. piggybacking) - */ - if (!card->configured){ - for (i = 0; i < ncards; i ++) { - sdla_t *nxt_card = &card_array[i]; - if (nxt_card->hw.port == conf->ioport && - nxt_card != card && - conf->config_id == WANCONFIG_CHDLC && - nxt_card->wandev.config_id == WANCONFIG_CHDLC){ - irq = nxt_card->hw.irq; - memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); - nxt_card->next = card; - card->next = nxt_card; - card->wandev.piggyback = WANOPT_YES; - } - } - - - /* Make sure I/O port region is available */ - if (check_region(conf->ioport, SDLA_MAXIORANGE) && - !card->wandev.piggyback) { - printk(KERN_ERR - "%s: I/O region 0x%X - 0x%X is in use!\n", - wandev->name, conf->ioport, - conf->ioport + SDLA_MAXIORANGE); - return -EINVAL; - } + if ((err=check_s508_conflicts(card,conf,&irq)) != 0){ + return err; } - } - - /* - For a S514 adapter, check for a possible configuration error in that - we are loading an adapter in the same slot as a previously loaded S514 - card. - */ - else { - if (!card->configured){ - for (i = 0; i < ncards; i ++) { - sdla_t* nxt_card = &card_array[i]; - if(nxt_card == card) - continue; - if((nxt_card->hw.type == SDLA_S514) && - (nxt_card->hw.S514_slot_no == conf->PCI_slot_no) && - (nxt_card->hw.S514_cpu_no[0] == conf->S514_CPU_no[0])&& - (conf->config_id == WANCONFIG_CHDLC)&& - (nxt_card->wandev.config_id == WANCONFIG_CHDLC)){ - - irq = nxt_card->hw.irq; - memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); - nxt_card->next = card; - card->next = nxt_card; - card->wandev.piggyback = WANOPT_YES; - } - } + }else { + if ((err=check_s514_conflicts(card,conf,&irq)) != 0){ + return err; } } @@ -336,8 +449,15 @@ card->hw.S514_cpu_no[0] = conf->S514_CPU_no[0]; card->hw.S514_slot_no = conf->PCI_slot_no; - printk(KERN_INFO "Setting CPU to %c and Slot to %i\n", - card->hw.S514_cpu_no[0], card->hw.S514_slot_no); + card->hw.auto_pci_cfg = conf->auto_pci_cfg; + + if (card->hw.auto_pci_cfg == WANOPT_YES){ + printk(KERN_INFO "%s: Setting CPU to %c and Slot to Auto\n", + card->devname, card->hw.S514_cpu_no[0]); + }else{ + printk(KERN_INFO "%s: Setting CPU to %c and Slot to %i\n", + card->devname, card->hw.S514_cpu_no[0], card->hw.S514_slot_no); + } }else{ /* 508 Card io port and irq initialization */ @@ -347,18 +467,22 @@ /* Compute the virtual address of the card in kernel space */ - if(conf->maddr) + if(conf->maddr){ card->hw.dpmbase = phys_to_virt(conf->maddr); - else /* But 0 means NULL */ + }else{ card->hw.dpmbase = (void *)conf->maddr; - + } + card->hw.dpmsize = SDLA_WINDOWSIZE; + /* set the adapter type if using an S514 adapter */ card->hw.type = (conf->S514_CPU_no[0]) ? SDLA_S514 : conf->hw_opt[0]; card->hw.pclk = conf->hw_opt[1]; err = sdla_setup(&card->hw, conf->data, conf->data_size); if (err){ + printk(KERN_INFO "%s: Hardware setup Failed %i\n", + card->devname,err); return err; } @@ -369,10 +493,12 @@ /* request an interrupt vector - note that interrupts may be shared */ /* when using the S514 PCI adapter */ + if(request_irq(irq, sdla_isr, - (card->hw.type == SDLA_S514) ? SA_SHIRQ : 0, wandev->name, card)){ + (card->hw.type == SDLA_S514) ? SA_SHIRQ : 0, + wandev->name, card)){ - printk(KERN_ERR "%s: Can't reserve IRQ %d!\n", wandev->name, irq); + printk(KERN_INFO "%s: Can't reserve IRQ %d!\n", wandev->name, irq); return -EINVAL; } @@ -384,11 +510,16 @@ if (!card->configured){ - #ifdef CONFIG_SMP /* Initialize the Spin lock */ - printk(KERN_INFO "%s: Initializing SMP\n",wandev->name); - spin_lock_init(&card->lock); - #endif +#if defined(__SMP__) || defined(LINUX_2_4) + printk(KERN_INFO "%s: Initializing for SMP\n",wandev->name); +#endif + + /* Piggyback spin lock has already been initialized, + * in check_s514/s508_conflicts() */ + if (!card->wandev.piggyback){ + spin_lock_init(&card->wandev.lock); + } /* Intialize WAN device data space */ wandev->irq = irq; @@ -409,63 +540,65 @@ /* Protocol-specific initialization */ switch (card->hw.fwid) { -#ifdef CONFIG_WANPIPE_X25 + case SFID_X25_502: case SFID_X25_508: + printk(KERN_INFO "%s: Starting X.25 Protocol Init.\n", + card->devname); err = wpx_init(card, conf); break; -#endif - -#ifdef CONFIG_WANPIPE_FR case SFID_FR502: case SFID_FR508: + printk(KERN_INFO "%s: Starting Frame Relay Protocol Init.\n", + card->devname); err = wpf_init(card, conf); break; -#endif - -#ifdef CONFIG_WANPIPE_PPP case SFID_PPP502: case SFID_PPP508: + printk(KERN_INFO "%s: Starting PPP Protocol Init.\n", + card->devname); err = wpp_init(card, conf); break; -#endif - -#ifdef CONFIG_WANPIPE_CHDLC + case SFID_CHDLC508: case SFID_CHDLC514: -// if (conf->ft1){ -// printk(KERN_INFO "%s: Starting FT1 Configurator\n", -// card->devname); -// err = wpft1_init(card, conf); -// }else{ - err = wpc_init(card, conf); -// } - break; -#endif - -#ifdef CONFIG_WANPIPE_BSTRM - case SFID_BSC502: - err = bsc_init(card, conf); - break; -#endif - -#ifdef CONFIG_WANPIPE_HDLC - case SFID_HDLC508: - err = hdlc_init(card, conf); - break; -#endif + if (conf->ft1){ + printk(KERN_INFO "%s: Starting FT1 CSU/DSU Config Driver.\n", + card->devname); + err = wpft1_init(card, conf); + break; + + }else if (conf->config_id == WANCONFIG_MPPP){ + printk(KERN_INFO "%s: Starting Multi-Port PPP Protocol Init.\n", + card->devname); + err = wsppp_init(card,conf); + break; + }else{ + printk(KERN_INFO "%s: Starting CHDLC Protocol Init.\n", + card->devname); + err = wpc_init(card, conf); + break; + } default: - printk(KERN_ERR "%s: this firmware is not supported %X %X!\n", + printk(KERN_INFO "%s: Error, Firmware is not supported %X %X!\n", wandev->name,card->hw.fwid,SFID_CHDLC508); - err = -EINVAL; + err = -EPROTONOSUPPORT; } - - if (err){ + if (err != 0){ + if (err == -EPROTONOSUPPORT){ + printk(KERN_INFO + "%s: Error, Protocol selected has not been compiled!\n", + card->devname); + printk(KERN_INFO + "%s: Re-configure the kernel and re-build the modules!\n", + card->devname); + } + release_hw(card); + wandev->state = WAN_UNCONFIGURED; return err; - } @@ -473,16 +606,194 @@ if(card->hw.type != SDLA_S514 && !card->wandev.piggyback) request_region(card->hw.port, card->hw.io_range, wandev->name); - if (++active == 1) { - MOD_INC_USE_COUNT; - if (schedule_task(&sdla_tq) == 0) - MOD_DEC_USE_COUNT; + /* Only use the polling routine for the X25 protocol */ + + card->wandev.critical=0; + return 0; +} + +/*================================================================== + * configure_s508_card + * + * For a S508 adapter, check for a possible configuration error in that + * we are loading an adapter in the same IO port as a previously loaded S508 + * card. + */ + +static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int *irq) +{ + unsigned long smp_flags; + int i; + + if (conf->ioport <= 0) { + printk(KERN_INFO + "%s: can't configure without I/O port address!\n", + card->wandev.name); + return -EINVAL; + } + + if (conf->irq <= 0) { + printk(KERN_INFO "%s: can't configure without IRQ!\n", + card->wandev.name); + return -EINVAL; } + + if (test_bit(0,&card->configured)) + return 0; + + + /* Check for already loaded card with the same IO port and IRQ + * If found, copy its hardware configuration and use its + * resources (i.e. piggybacking) + */ + + for (i = 0; i < ncards; i++) { + sdla_t *nxt_card = &card_array[i]; + + /* Skip the current card ptr */ + if (nxt_card == card) + continue; + + + /* Find a card that is already configured with the + * same IO Port */ + if ((nxt_card->hw.type == SDLA_S508) && + (nxt_card->hw.port == conf->ioport) && + (nxt_card->next == NULL)){ + + /* We found a card the card that has same configuration + * as us. This means, that we must setup this card in + * piggibacking mode. However, only CHDLC and MPPP protocol + * support this setup */ + + if ((conf->config_id == WANCONFIG_CHDLC || + conf->config_id == WANCONFIG_MPPP) && + (nxt_card->wandev.config_id == WANCONFIG_CHDLC || + nxt_card->wandev.config_id == WANCONFIG_MPPP)){ + + *irq = nxt_card->hw.irq; + memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); + + /* The master could already be running, we must + * set this as a critical area */ + lock_adapter_irq(&nxt_card->wandev.lock, &smp_flags); + + nxt_card->next = card; + card->next = nxt_card; + + card->wandev.piggyback = WANOPT_YES; + + /* We must initialise the piggiback spin lock here + * since isr will try to lock card->next if it + * exists */ + spin_lock_init(&card->wandev.lock); + + unlock_adapter_irq(&nxt_card->wandev.lock, &smp_flags); + break; + }else{ + /* Trying to run piggibacking with a wrong protocol */ + printk(KERN_INFO "%s: ERROR: Resource busy, ioport: 0x%x\n" + "%s: This protocol doesn't support\n" + "%s: multi-port operation!\n", + card->devname,nxt_card->hw.port, + card->devname,card->devname); + return -EEXIST; + } + } + } + + + /* Make sure I/O port region is available only if we are the + * master device. If we are running in piggibacking mode, + * we will use the resources of the master card */ + if (check_region(conf->ioport, SDLA_MAXIORANGE) && + !card->wandev.piggyback) { + printk(KERN_INFO + "%s: I/O region 0x%X - 0x%X is in use!\n", + card->wandev.name, conf->ioport, + conf->ioport + SDLA_MAXIORANGE); + return -EINVAL; + } + + return 0; +} + +/*================================================================== + * configure_s514_card + * + * For a S514 adapter, check for a possible configuration error in that + * we are loading an adapter in the same slot as a previously loaded S514 + * card. + */ + + +static int check_s514_conflicts(sdla_t* card,wandev_conf_t* conf, int *irq) +{ + unsigned long smp_flags; + int i; + + if (test_bit(0,&card->configured)) + return 0; + + + /* Check for already loaded card with the same IO port and IRQ + * If found, copy its hardware configuration and use its + * resources (i.e. piggybacking) + */ + + for (i = 0; i < ncards; i ++) { + + sdla_t* nxt_card = &card_array[i]; + if(nxt_card == card) + continue; - wandev->critical = 0; + if((nxt_card->hw.type == SDLA_S514) && + (nxt_card->hw.S514_slot_no == conf->PCI_slot_no) && + (nxt_card->hw.S514_cpu_no[0] == conf->S514_CPU_no[0])&& + (nxt_card->next == NULL)){ + + + if ((conf->config_id == WANCONFIG_CHDLC || + conf->config_id == WANCONFIG_MPPP) && + (nxt_card->wandev.config_id == WANCONFIG_CHDLC || + nxt_card->wandev.config_id == WANCONFIG_MPPP)){ + + *irq = nxt_card->hw.irq; + memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); + + /* The master could already be running, we must + * set this as a critical area */ + lock_adapter_irq(&nxt_card->wandev.lock,&smp_flags); + nxt_card->next = card; + card->next = nxt_card; + + card->wandev.piggyback = WANOPT_YES; + + /* We must initialise the piggiback spin lock here + * since isr will try to lock card->next if it + * exists */ + spin_lock_init(&card->wandev.lock); + + unlock_adapter_irq(&nxt_card->wandev.lock,&smp_flags); + + }else{ + /* Trying to run piggibacking with a wrong protocol */ + printk(KERN_INFO "%s: ERROR: Resource busy: CPU %c PCISLOT %i\n" + "%s: This protocol doesn't support\n" + "%s: multi-port operation!\n", + card->devname, + conf->S514_CPU_no[0],conf->PCI_slot_no, + card->devname,card->devname); + return -EEXIST; + } + } + } + return 0; } + + /*============================================================================ * Shut down WAN link driver. * o shut down adapter hardware @@ -494,23 +805,39 @@ static int shutdown (wan_device_t* wandev) { sdla_t *card; - + int err=0; + /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)) + if ((wandev == NULL) || (wandev->private == NULL)){ return -EFAULT; + } - if (wandev->state == WAN_UNCONFIGURED) + if (wandev->state == WAN_UNCONFIGURED){ return 0; - - /* If we are in a critical section we lose */ - if (test_and_set_bit(0, (void*)&wandev->critical)) - return -EAGAIN; - + } + card = wandev->private; + + if (card->tty_opt){ + if (card->tty_open){ + printk(KERN_INFO + "%s: Shutdown Failed: TTY is still open\n", + card->devname); + return -EBUSY; + } + } + wandev->state = WAN_UNCONFIGURED; - if (--active == 0) - schedule(); /* stop background thread */ + set_bit(PERI_CRIT,(void*)&wandev->critical); + + /* In case of piggibacking, make sure that + * we never try to shutdown both devices at the same + * time, because they depend on one another */ + + if (card->disable_comm){ + card->disable_comm(card); + } /* Release Resources */ release_hw(card); @@ -526,15 +853,17 @@ memset(&card->next->hw, 0, sizeof(sdlahw_t)); } } + - wandev->critical = 0; - return 0; + clear_bit(PERI_CRIT,(void*)&wandev->critical); + return err; } static void release_hw (sdla_t *card) { sdla_t *nxt_card; + /* Check if next device exists */ if (card->next){ nxt_card = card->next; @@ -559,8 +888,9 @@ card->next->configured = 0; } }else{ - printk(KERN_INFO "%s: Device still running\n", - nxt_card->devname); + printk(KERN_INFO "%s: Device still running %i\n", + nxt_card->devname,nxt_card->wandev.state); + card->configured = 1; } }else{ @@ -569,6 +899,7 @@ free_irq(card->wandev.irq, card); card->configured = 0; } + return; } @@ -597,10 +928,7 @@ disable_irq(card->hw.irq); } - if (test_and_set_bit(0, (void*)&wandev->critical)) { - if(card->hw.type != SDLA_S514){ - enable_irq(card->hw.irq); - } + if (test_bit(SEND_CRIT, (void*)&wandev->critical)) { return -EAGAIN; } @@ -610,18 +938,12 @@ break; case WANPIPE_EXEC: - err = ioctl_exec(wandev->private, (void*)arg); + err = ioctl_exec(wandev->private, (void*)arg, cmd); break; - default: err = -EINVAL; } - clear_bit(0, (void*)&wandev->critical); - if(card->hw.type != SDLA_S514){ - enable_irq(card->hw.irq); - } - return err; } @@ -635,7 +957,7 @@ * o verify user buffer * o copy adapter memory image to user buffer * - * Note: when dumping memory, this routine switches current dual-port memory + * Note: when dumping memory, this routine switches curent dual-port memory * vector, so care must be taken to avoid racing conditions. */ static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump) @@ -643,21 +965,35 @@ sdla_dump_t dump; unsigned winsize; unsigned long oldvec; /* DPM window vector */ - unsigned long flags; + unsigned long smp_flags; int err = 0; + #if defined(LINUX_2_1) || defined(LINUX_2_4) if(copy_from_user((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t))) return -EFAULT; + #else + if ((u_dump == NULL) || + verify_area(VERIFY_READ, u_dump, sizeof(sdla_dump_t))) + return -EFAULT; + memcpy_fromfs((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t)); + #endif if ((dump.magic != WANPIPE_MAGIC) || (dump.offset + dump.length > card->hw.memory)) return -EINVAL; + #ifdef LINUX_2_0 + if ((dump.ptr == NULL) || + verify_area(VERIFY_WRITE, dump.ptr, dump.length)) + return -EFAULT; + #endif + winsize = card->hw.dpmsize; - save_flags(flags); - cli(); /* >>> critical section start <<< */ if(card->hw.type != SDLA_S514) { + + lock_adapter_irq(&card->wandev.lock, &smp_flags); + oldvec = card->hw.vector; while (dump.length) { /* current offset */ @@ -671,29 +1007,39 @@ err = -EIO; break; } - /* FIXME::: COPY TO KERNEL BUFFER FIRST ?? */ - sti(); /* Not ideal but tough we have to do this */ + + #if defined(LINUX_2_1) || defined(LINUX_2_4) if(copy_to_user((void *)dump.ptr, - (u8 *)card->hw.dpmbase + pos, len)) - return -EFAULT; - cli(); + (u8 *)card->hw.dpmbase + pos, len)){ + + unlock_adapter_irq(&card->wandev.lock, &smp_flags); + return -EFAULT; + } + #else + memcpy_tofs((void*)(dump.ptr), + (void*)(card->hw.dpmbase + pos), len); + #endif dump.length -= len; dump.offset += len; (char*)dump.ptr += len; } + sdla_mapmem(&card->hw, oldvec);/* restore DPM window position */ - } - - else { - /* FIXME::: COPY TO KERNEL BUFFER FIRST ?? */ - sti(); /* Not ideal but tough we have to do this */ + unlock_adapter_irq(&card->wandev.lock, &smp_flags); + + }else { + + #if defined(LINUX_2_1) || defined(LINUX_2_4) if(copy_to_user((void *)dump.ptr, - (u8 *)card->hw.dpmbase + dump.offset, dump.length)) - return -EFAULT; - cli(); + (u8 *)card->hw.dpmbase + dump.offset, dump.length)){ + return -EFAULT; + } + #else + memcpy_tofs((void*)(dump.ptr), + (void*)(card->hw.dpmbase + dump.offset), dump.length); + #endif } - restore_flags(flags); /* >>> critical section end <<< */ return err; } @@ -703,19 +1049,34 @@ * o copy request structure to kernel data space * o call protocol-specific 'exec' function */ -static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec) +static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec, int cmd) { sdla_exec_t exec; + int err=0; - if (card->exec == NULL) + if (card->exec == NULL && cmd == WANPIPE_EXEC){ return -ENODEV; - + } + + #if defined(LINUX_2_1) || defined(LINUX_2_4) if(copy_from_user((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t))) return -EFAULT; + #else + if ((u_exec == NULL) || + verify_area(VERIFY_READ, u_exec, sizeof(sdla_exec_t))) + return -EFAULT; + memcpy_fromfs((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t)); + #endif if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL)) return -EINVAL; - return card->exec(card, exec.cmd, exec.data); + + switch (cmd) { + case WANPIPE_EXEC: + err = card->exec(card, exec.cmd, exec.data); + break; + } + return err; } /******* Miscellaneous ******************************************************/ @@ -795,11 +1156,20 @@ return; } + spin_lock(&card->wandev.lock); + if (card->next){ + spin_lock(&card->next->wandev.lock); + } + S514_intack(&card->hw, int_status); - if (card->isr) card->isr(card); + if (card->next){ + spin_unlock(&card->next->wandev.lock); + } + spin_unlock(&card->wandev.lock); + /* handle a maximum of two interrupts (one for each */ /* CPU on the adapter) before returning */ if((++ IRQ_count) == 2) @@ -819,17 +1189,19 @@ return; } - /* Use spin lock only for S508 */ - -#ifdef CONFIG_SMP - spin_lock(&card->lock); -#endif + spin_lock(&card->wandev.lock); + if (card->next){ + spin_lock(&card->next->wandev.lock); + } + sdla_intack(&card->hw); if (card->isr) card->isr(card); -#ifdef CONFIG_SMP - spin_unlock(&card->lock); -#endif + + if (card->next){ + spin_unlock(&card->next->wandev.lock); + } + spin_unlock(&card->wandev.lock); } @@ -837,33 +1209,6 @@ } /*============================================================================ - * SDLA polling routine. - * This routine simulates kernel thread to perform various housekeeping job. - * - * o for each configured device call its poll() routine - * o if there is at least one active card, then reschedule itself once again - */ -STATIC void sdla_poll (void* data) -{ - int i; - - for (i = 0; i < ncards; ++i) { - sdla_t* card = &card_array[i]; - - if ((card->wandev.state != WAN_UNCONFIGURED) && card->poll && - !card->wandev.critical) { - card->poll(card); - } - } - if (active) { - MOD_INC_USE_COUNT; - if (schedule_task(&sdla_tq) == 0) /* Surely not? */ - MOD_DEC_USE_COUNT; - } - MOD_DEC_USE_COUNT; -} - -/*============================================================================ * This routine is called by the protocol-specific modules when network * interface is being open. The only reason we need this, is because we * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's @@ -892,10 +1237,6 @@ */ void wanpipe_set_state (sdla_t* card, int state) { - unsigned long flags; - - save_flags(flags); - cli(); if (card->wandev.state != state) { switch (state) { case WAN_CONNECTED: @@ -916,7 +1257,187 @@ card->wandev.state = state; } card->state_tick = jiffies; - restore_flags(flags); } -/****** End *****************************************************************/ +sdla_t * wanpipe_find_card (char *name) +{ + int cnt; + for (cnt = 0; cnt < ncards; ++ cnt) { + sdla_t* card = &card_array[cnt]; + if (!strcmp(card->devname,name)) + return card; + } + return NULL; +} +sdla_t * wanpipe_find_card_num (int num) +{ + if (num < 1 || num > ncards) + return NULL; + num--; + return &card_array[num]; +} + + +static void run_wanpipe_tq (unsigned long data) +{ + task_queue *tq_queue = (task_queue *)data; + if (test_and_set_bit(2,(void*)&wanpipe_bh_critical)) + printk(KERN_INFO "CRITICAL IN RUNNING TASK QUEUE\n"); + run_task_queue (tq_queue); + clear_bit(2,(void*)&wanpipe_bh_critical); + +} + +void wanpipe_queue_tq (struct tq_struct *bh_pointer) +{ + if (test_and_set_bit(1,(void*)&wanpipe_bh_critical)) + printk(KERN_INFO "CRITICAL IN QUEUING TASK\n"); + + queue_task(bh_pointer,&wanpipe_tq_custom); + clear_bit(1,(void*)&wanpipe_bh_critical); +} + +void wanpipe_mark_bh (void) +{ + if (!test_and_set_bit(0,(void*)&wanpipe_bh_critical)){ + queue_task(&wanpipe_tq_task,&tq_immediate); + mark_bh(IMMEDIATE_BH); + clear_bit(0,(void*)&wanpipe_bh_critical); + } +} + +void wakeup_sk_bh (netdevice_t *dev) +{ + wanpipe_common_t *chan = dev->priv; + + if (test_bit(0,&chan->common_critical)) + return; + + if (chan->sk && chan->tx_timer){ + chan->tx_timer->expires=jiffies+1; + add_timer(chan->tx_timer); + } +} + +int change_dev_flags (netdevice_t *dev, unsigned flags) +{ + struct ifreq if_info; + mm_segment_t fs = get_fs(); + int err; + + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + if_info.ifr_flags = flags; + + set_fs(get_ds()); /* get user space block */ + err = devinet_ioctl(SIOCSIFFLAGS, &if_info); + set_fs(fs); + + return err; +} + +unsigned long get_ip_address (netdevice_t *dev, int option) +{ + + #ifdef LINUX_2_4 + struct in_ifaddr *ifaddr; + struct in_device *in_dev; + + if ((in_dev = __in_dev_get(dev)) == NULL){ + return 0; + } + #elif defined(LINUX_2_1) + struct in_ifaddr *ifaddr; + struct in_device *in_dev; + + if ((in_dev = dev->ip_ptr) == NULL){ + return 0; + } + #endif + + #if defined(LINUX_2_1) || defined(LINUX_2_4) + if ((ifaddr = in_dev->ifa_list)== NULL ){ + return 0; + } + #endif + + switch (option){ + + case WAN_LOCAL_IP: + #ifdef LINUX_2_0 + return dev->pa_addr; + #else + return ifaddr->ifa_local; + #endif + break; + + case WAN_POINTOPOINT_IP: + #ifdef LINUX_2_0 + return dev->pa_dstaddr; + #else + return ifaddr->ifa_address; + #endif + break; + + case WAN_NETMASK_IP: + #ifdef LINUX_2_0 + return dev->pa_mask; + #else + return ifaddr->ifa_mask; + #endif + break; + + case WAN_BROADCAST_IP: + #ifdef LINUX_2_0 + return dev->pa_brdaddr; + #else + return ifaddr->ifa_broadcast; + #endif + break; + default: + return 0; + } + + return 0; +} + +void add_gateway(sdla_t *card, netdevice_t *dev) +{ + mm_segment_t oldfs; + struct rtentry route; + int res; + + memset((char*)&route,0,sizeof(struct rtentry)); + + ((struct sockaddr_in *) + &(route.rt_dst))->sin_addr.s_addr = 0; + ((struct sockaddr_in *) + &(route.rt_dst))->sin_family = AF_INET; + + ((struct sockaddr_in *) + &(route.rt_genmask))->sin_addr.s_addr = 0; + ((struct sockaddr_in *) + &(route.rt_genmask)) ->sin_family = AF_INET; + + + route.rt_flags = 0; + route.rt_dev = dev->name; + + oldfs = get_fs(); + set_fs(get_ds()); + #if defined(LINUX_2_1) || defined(LINUX_2_4) + res = ip_rt_ioctl(SIOCADDRT,&route); + #else + res = ip_rt_new(&route); + #endif + set_fs(oldfs); + + if (res == 0){ + printk(KERN_INFO "%s: Gateway added for %s\n", + card->devname,dev->name); + } + + return; +} + +/****** End *********************************************************/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/wan/wanpipe_multppp.c linux.ac/drivers/net/wan/wanpipe_multppp.c --- linux.vanilla/drivers/net/wan/wanpipe_multppp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/wan/wanpipe_multppp.c Sat Apr 14 01:28:20 2001 @@ -0,0 +1,2473 @@ +/***************************************************************************** +* wanpipe_multppp.c Multi-Port PPP driver module. +* +* Authors: Nenad Corbic <ncorbic@sangoma.com> +* +* Copyright: (c) 1995-2001 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Dec 15 2000 Updated for 2.4.X kernel +* Nov 15 2000 Fixed the SyncPPP support for kernels 2.2.16 and higher. +* The pppstruct has changed. +* Jul 13 2000 Using the kernel Syncppp module on top of RAW Wanpipe CHDLC +* module. +*****************************************************************************/ + +#include <linux/version.h> +#include <linux/kernel.h> /* printk(), and other useful stuff */ +#include <linux/stddef.h> /* offsetof(), etc. */ +#include <linux/errno.h> /* return codes */ +#include <linux/string.h> /* inline memset(), etc. */ +#include <linux/malloc.h> /* kmalloc(), kfree() */ +#include <linux/wanrouter.h> /* WAN router definitions */ +#include <linux/wanpipe.h> /* WANPIPE common user API definitions */ +#include <linux/if_arp.h> /* ARPHRD_* defines */ + +#include <linux/in.h> /* sockaddr_in */ +#include <linux/inet.h> +#include <linux/if.h> +#include <asm/byteorder.h> /* htons(), etc. */ +#include <linux/sdlapci.h> +#include <asm/io.h> + +#include <linux/sdla_chdlc.h> /* CHDLC firmware API definitions */ +#include <linux/sdla_asy.h> /* CHDLC (async) API definitions */ + +#include <linux/if_wanpipe_common.h> /* Socket Driver common area */ +#include <linux/if_wanpipe.h> + + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + #include <linux/inetdevice.h> + #include <asm/uaccess.h> + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3) + #include <net/syncppp.h> +#else + #include "syncppp.h" +#endif + +#else + #include <net/route.h> /* Adding new route entries */ +#endif + +/****** Defines & Macros ****************************************************/ + +#ifdef _DEBUG_ +#define STATIC +#else +#define STATIC static +#endif + +/* reasons for enabling the timer interrupt on the adapter */ +#define TMR_INT_ENABLED_UDP 0x01 +#define TMR_INT_ENABLED_UPDATE 0x02 +#define TMR_INT_ENABLED_CONFIG 0x04 + +#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ +#define CHDLC_HDR_LEN 1 + +#define IFF_POINTTOPOINT 0x10 + +#define CHDLC_API 0x01 + +#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) +#define MAX_BH_BUFF 10 + +#define CRC_LENGTH 2 +#define PPP_HEADER_LEN 4 + +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with CHDLC specific data + */ + +typedef struct chdlc_private_area +{ + void *if_ptr; /* General Pointer used by SPPP */ + wanpipe_common_t common; + sdla_t *card; + int TracingEnabled; /* For enabling Tracing */ + unsigned long curr_trace_addr; /* Used for Tracing */ + unsigned long start_trace_addr; + unsigned long end_trace_addr; + unsigned long base_addr_trace_buffer; + unsigned long end_addr_trace_buffer; + unsigned short number_trace_elements; + unsigned available_buffer_space; + unsigned long router_start_time; + unsigned char route_status; + unsigned char route_removed; + unsigned long tick_counter; /* For 5s timeout counter */ + unsigned long router_up_time; + u32 IP_address; /* IP addressing */ + u32 IP_netmask; + unsigned char mc; /* Mulitcast support on/off */ + unsigned short udp_pkt_lgth; /* udp packet processing */ + char udp_pkt_src; + char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; + unsigned short timer_int_enabled; + char update_comms_stats; /* updating comms stats */ + + //FIXME: add driver stats as per frame relay! + +} chdlc_private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + + +/* variable for keeping track of enabling/disabling FT1 monitor status */ +static int rCount = 0; + +/* variable for tracking how many interfaces to open for WANPIPE on the + two ports */ + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/****** Function Prototypes *************************************************/ +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, netdevice_t* dev, + wanif_conf_t* conf); +static int del_if (wan_device_t* wandev, netdevice_t* dev); + +/* Network device interface */ +static int if_init (netdevice_t* dev); +static int if_open (netdevice_t* dev); +static int if_close (netdevice_t* dev); +static int if_send (struct sk_buff* skb, netdevice_t* dev); +#if defined(LINUX_2_1) || defined(LINUX_2_4) +static struct net_device_stats* if_stats (netdevice_t* dev); +#else +static struct enet_statistics* if_stats (netdevice_t* dev); +#endif + +#ifdef LINUX_2_4 +static void if_tx_timeout (netdevice_t *dev); +#endif + +/* CHDLC Firmware interface functions */ +static int chdlc_configure (sdla_t* card, void* data); +static int chdlc_comm_enable (sdla_t* card); +static int chdlc_comm_disable (sdla_t* card); +static int chdlc_read_version (sdla_t* card, char* str); +static int chdlc_set_intr_mode (sdla_t* card, unsigned mode); +static int chdlc_send (sdla_t* card, void* data, unsigned len); +static int chdlc_read_comm_err_stats (sdla_t* card); +static int chdlc_read_op_stats (sdla_t* card); +static int config_chdlc (sdla_t *card); + + +/* Miscellaneous CHDLC Functions */ +static int set_chdlc_config (sdla_t* card); +static void init_chdlc_tx_rx_buff( sdla_t* card, netdevice_t *dev ); +static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); +static int process_chdlc_exception(sdla_t *card); +static int process_global_exception(sdla_t *card); +static int update_comms_stats(sdla_t* card, + chdlc_private_area_t* chdlc_priv_area); +static void port_set_state (sdla_t *card, int); + +/* Interrupt handlers */ +static void wsppp_isr (sdla_t* card); +static void rx_intr (sdla_t* card); +static void timer_intr(sdla_t *); + +/* Miscellaneous functions */ +static int reply_udp( unsigned char *data, unsigned int mbox_len ); +static int intr_test( sdla_t* card); +static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); +static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, netdevice_t* dev, + chdlc_private_area_t* chdlc_priv_area); +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + chdlc_private_area_t* chdlc_priv_area); +static unsigned short calc_checksum (char *, int); +static void s508_lock (sdla_t *card, unsigned long *smp_flags); +static void s508_unlock (sdla_t *card, unsigned long *smp_flags); +static void send_ppp_term_request (netdevice_t*); + + +static int Intr_test_counter; +/****** Public Functions ****************************************************/ + +/*============================================================================ + * Cisco HDLC protocol initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wsppp_init (sdla_t* card, wandev_conf_t* conf) +{ + unsigned char port_num; + int err; + unsigned long max_permitted_baud = 0; + SHARED_MEMORY_INFO_STRUCT *flags; + + union + { + char str[80]; + } u; + volatile CHDLC_MAILBOX_STRUCT* mb; + CHDLC_MAILBOX_STRUCT* mb1; + unsigned long timeout; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_MPPP) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + + /* Find out which Port to use */ + if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){ + if (card->next){ + + if (conf->comm_port != card->next->u.c.comm_port){ + card->u.c.comm_port = conf->comm_port; + }else{ + printk(KERN_ERR "%s: ERROR - %s port used!\n", + card->wandev.name, PORT(conf->comm_port)); + return -EINVAL; + } + }else{ + card->u.c.comm_port = conf->comm_port; + } + }else{ + printk(KERN_ERR "%s: ERROR - Invalid Port Selected!\n", + card->wandev.name); + return -EINVAL; + } + + + /* Initialize protocol-specific fields */ + if(card->hw.type != SDLA_S514){ + + if (card->u.c.comm_port == WANOPT_PRI){ + card->mbox = (void *) card->hw.dpmbase; + }else{ + card->mbox = (void *) card->hw.dpmbase + + SEC_BASE_ADDR_MB_STRUCT - PRI_BASE_ADDR_MB_STRUCT; + } + }else{ + /* for a S514 adapter, set a pointer to the actual mailbox in the */ + /* allocated virtual memory area */ + if (card->u.c.comm_port == WANOPT_PRI){ + card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; + }else{ + card->mbox = (void *) card->hw.dpmbase + SEC_BASE_ADDR_MB_STRUCT; + } + } + + mb = mb1 = card->mbox; + + if (!card->configured){ + + /* The board will place an 'I' in the return code to indicate that it is + ready to accept commands. We expect this to be completed in less + than 1 second. */ + + timeout = jiffies; + while (mb->return_code != 'I') /* Wait 1s for board to initialize */ + if ((jiffies - timeout) > 1*HZ) break; + + if (mb->return_code != 'I') { + printk(KERN_INFO + "%s: Initialization not completed by adapter\n", + card->devname); + printk(KERN_INFO "Please contact Sangoma representative.\n"); + return -EIO; + } + } + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + + if (chdlc_read_version(card, u.str)) + return -EIO; + + printk(KERN_INFO "%s: Running Raw CHDLC firmware v%s\n" + "%s: for Multi-Port PPP protocol.\n", + card->devname,u.str,card->devname); + + card->isr = &wsppp_isr; + card->poll = NULL; + card->exec = NULL; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.udp_port = conf->udp_port; + + card->wandev.new_if_cnt = 0; + + /* reset the number of times the 'update()' proc has been called */ + card->u.c.update_call_count = 0; + + card->wandev.ttl = conf->ttl; + card->wandev.interface = conf->interface; + + if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&& + card->hw.type != SDLA_S514){ + printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n", + card->devname, PORT(card->u.c.comm_port)); + return -EIO; + } + + + card->wandev.clocking = conf->clocking; + + port_num = card->u.c.comm_port; + + /* Setup Port Bps */ + + if(card->wandev.clocking) { + if((port_num == WANOPT_PRI) || card->u.c.receive_only) { + /* For Primary Port 0 */ + max_permitted_baud = + (card->hw.type == SDLA_S514) ? + PRI_MAX_BAUD_RATE_S514 : + PRI_MAX_BAUD_RATE_S508; + } + else if(port_num == WANOPT_SEC) { + /* For Secondary Port 1 */ + max_permitted_baud = + (card->hw.type == SDLA_S514) ? + SEC_MAX_BAUD_RATE_S514 : + SEC_MAX_BAUD_RATE_S508; + } + + if(conf->bps > max_permitted_baud) { + conf->bps = max_permitted_baud; + printk(KERN_INFO "%s: Baud too high!\n", + card->wandev.name); + printk(KERN_INFO "%s: Baud rate set to %lu bps\n", + card->wandev.name, max_permitted_baud); + } + + card->wandev.bps = conf->bps; + }else{ + card->wandev.bps = 0; + } + + /* Setup the Port MTU */ + if((port_num == WANOPT_PRI) || card->u.c.receive_only) { + + /* For Primary Port 0 */ + card->wandev.mtu = + (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? + min(conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) : + CHDLC_DFLT_DATA_LEN; + } else if(port_num == WANOPT_SEC) { + /* For Secondary Port 1 */ + card->wandev.mtu = + (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? + min(conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) : + CHDLC_DFLT_DATA_LEN; + } + + /* Add on a PPP Header */ + card->wandev.mtu += PPP_HEADER_LEN; + + /* Set up the interrupt status area */ + /* Read the CHDLC Configuration and obtain: + * Ptr to shared memory infor struct + * Use this pointer to calculate the value of card->u.c.flags ! + */ + mb1->buffer_length = 0; + mb1->command = READ_CHDLC_CONFIGURATION; + err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; + if(err != COMMAND_OK) { + clear_bit(1, (void*)&card->wandev.critical); + + if(card->hw.type != SDLA_S514) + enable_irq(card->hw.irq); + + chdlc_error(card, err, mb1); + return -EIO; + } + + if(card->hw.type == SDLA_S514){ + card->u.c.flags = (void *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> + ptr_shared_mem_info_struct)); + }else{ + card->u.c.flags = (void *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> + ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); + } + + flags = card->u.c.flags; + + /* This is for the ports link state */ + card->wandev.state = WAN_DUALPORT; + card->u.c.state = WAN_DISCONNECTED; + + + if (!card->wandev.piggyback){ + err = intr_test(card); + + if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { + printk(KERN_ERR "%s: Interrupt test failed (%i)\n", + card->devname, Intr_test_counter); + printk(KERN_ERR "%s: Please choose another interrupt\n", + card->devname); + return -EIO; + } + + printk(KERN_INFO "%s: Interrupt test passed (%i)\n", + card->devname, Intr_test_counter); + } + + + if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){ + printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", + card->devname); + return -EIO; + } + + /* Mask the Timer interrupt */ + flags->interrupt_info_struct.interrupt_permission &= + ~APP_INT_ON_TIMER; + + printk(KERN_INFO "\n"); + + return 0; +} + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * Update device status & statistics + * This procedure is called when updating the PROC file system and returns + * various communications statistics. These statistics are accumulated from 3 + * different locations: + * 1) The 'if_stats' recorded for the device. + * 2) Communication error statistics on the adapter. + * 3) CHDLC operational statistics on the adapter. + * The board level statistics are read during a timer interrupt. Note that we + * read the error and operational statistics during consecitive timer ticks so + * as to minimize the time that we are inside the interrupt handler. + * + */ +static int update (wan_device_t* wandev) +{ + sdla_t* card = wandev->private; + netdevice_t* dev; + volatile chdlc_private_area_t* chdlc_priv_area; + SHARED_MEMORY_INFO_STRUCT *flags; + unsigned long timeout; + + /* sanity checks */ + if((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if(wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + /* more sanity checks */ + if(!card->u.c.flags) + return -ENODEV; + + if((dev=card->wandev.dev) == NULL) + return -ENODEV; + + if((chdlc_priv_area=dev->priv) == NULL) + return -ENODEV; + + flags = card->u.c.flags; + + if(chdlc_priv_area->update_comms_stats){ + return -EAGAIN; + } + + /* we will need 2 timer interrupts to complete the */ + /* reading of the statistics */ + chdlc_priv_area->update_comms_stats = 2; + flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; + chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UPDATE; + + /* wait a maximum of 1 second for the statistics to be updated */ + timeout = jiffies; + for(;;) { + if(chdlc_priv_area->update_comms_stats == 0) + break; + if ((jiffies - timeout) > (1 * HZ)){ + chdlc_priv_area->update_comms_stats = 0; + chdlc_priv_area->timer_int_enabled &= + ~TMR_INT_ENABLED_UPDATE; + return -EAGAIN; + } + } + + return 0; +} + + +/*============================================================================ + * Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, netdevice_t* pdev, wanif_conf_t* conf) +{ + + struct ppp_device *pppdev = (struct ppp_device *)pdev; + netdevice_t *dev=NULL; + struct sppp *sp; + sdla_t* card = wandev->private; + chdlc_private_area_t* chdlc_priv_area; + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + printk(KERN_INFO "%s: invalid interface name!\n", + card->devname); + return -EINVAL; + } + + /* allocate and initialize private data */ + chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL); + + if(chdlc_priv_area == NULL) + return -ENOMEM; + + memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); + + chdlc_priv_area->card = card; + + /* initialize data */ + strcpy(card->u.c.if_name, conf->name); + + if(card->wandev.new_if_cnt > 0) { + kfree(chdlc_priv_area); + return -EEXIST; + } + + card->wandev.new_if_cnt++; + + chdlc_priv_area->TracingEnabled = 0; + + //We don't need this any more + chdlc_priv_area->route_status = NO_ROUTE; + chdlc_priv_area->route_removed = 0; + + printk(KERN_INFO "%s: Firmware running in HDLC STREAMING Mode\n", + wandev->name); + + /* Setup wanpipe as a router (WANPIPE) or as an API */ + if( strcmp(conf->usedby, "WANPIPE") == 0) { + printk(KERN_INFO "%s: Driver running in WANPIPE mode!\n", + wandev->name); + card->u.c.usedby = WANPIPE; + } else { + printk(KERN_INFO + "%s: API Mode is not supported for SyncPPP!\n", + wandev->name); + kfree(chdlc_priv_area); + return -EINVAL; + } + + /* Get Multicast Information */ + chdlc_priv_area->mc = conf->mc; + + + chdlc_priv_area->if_ptr = pppdev; + + /* prepare network device data space for registration */ + + /* Attach PPP protocol layer to pppdev + * The sppp_attach() will initilize the dev structure + * and setup ppp layer protocols. + * All we have to do is to bind in: + * if_open(), if_close(), if_send() and get_stats() functions. + */ + sppp_attach(pppdev); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16) + dev = pppdev->dev; + #else + dev = &pppdev->dev; + #endif + sp = &pppdev->sppp; + + /* Enable PPP Debugging */ + // FIXME Fix this up somehow + //sp->pp_flags |= PP_DEBUG; + sp->pp_flags &= ~PP_CISCO; + + #ifdef LINUX_2_4 + strcpy(dev->name,card->u.c.if_name); + #else + dev->name = (char *)kmalloc(strlen(card->u.c.if_name) + 2, GFP_KERNEL); + sprintf(dev->name, "%s", card->u.c.if_name); + #endif + + dev->init = &if_init; + dev->priv = chdlc_priv_area; + + return 0; +} + + + + +/*============================================================================ + * Delete logical channel. + */ +static int del_if (wan_device_t* wandev, netdevice_t* dev) +{ + chdlc_private_area_t *chdlc_priv_area = dev->priv; + sdla_t *card = chdlc_priv_area->card; + unsigned long smp_lock; + + /* Detach the PPP layer */ + printk(KERN_INFO "%s: Detaching SyncPPP Module from %s\n", + wandev->name,dev->name); + + lock_adapter_irq(&wandev->lock,&smp_lock); + + sppp_detach(dev); + chdlc_priv_area->if_ptr=NULL; + + chdlc_set_intr_mode(card, 0); + if (card->u.c.comm_enabled) + chdlc_comm_disable(card); + unlock_adapter_irq(&wandev->lock,&smp_lock); + + port_set_state(card, WAN_DISCONNECTED); + + return 0; +} + + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ +static int if_init (netdevice_t* dev) + { + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + wan_device_t* wandev = &card->wandev; + #ifdef LINUX_2_0 + int i; + #endif + + /* NOTE: Most of the dev initialization was + * done in sppp_attach(), called by new_if() + * function. All we have to do here is + * to link four major routines below. + */ + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + #ifdef LINUX_2_4 + dev->tx_timeout = &if_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + #endif + + + #ifdef LINUX_2_0 + dev->family = AF_INET; + #endif + + /* Initialize hardware parameters */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = wandev->maddr; + dev->mem_end = wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length + * If we over fill this queue the packets will + * be droped by the kernel. + * sppp_attach() sets this to 10, but + * 100 will give us more room at low speeds. + */ + dev->tx_queue_len = 100; + + /* Initialize socket buffers */ + #if defined(LINUX_2_1) || defined(LINUX_2_4) + dev_init_buffers(dev); + #else + for (i = 0; i < DEV_NUMBUFFS; ++i) + skb_queue_head_init(&dev->buffs[i]); + #endif + + return 0; +} + + +#ifdef LINUX_2_4 +/*============================================================================ + * Handle transmit timeout event from netif watchdog + */ +static void if_tx_timeout (netdevice_t *dev) +{ + chdlc_private_area_t* chan = dev->priv; + sdla_t *card = chan->card; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++card->wandev.stats.collisions; + + printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); + netif_wake_queue (dev); +} +#endif + + + +/*============================================================================ + * Open network interface. + * o enable communications and interrupts. + * o prevent module from unloading by incrementing use count + * + * Return 0 if O.k. or errno. + */ +static int if_open (netdevice_t* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + struct timeval tv; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + + /* Only one open per interface is allowed */ + + #ifdef LINUX_2_4 + if (netif_running(dev)) + return -EBUSY; + #else + if (dev->start) + return -EBUSY; /* only one open is allowed */ + #endif + + /* Start PPP Layer */ + if (sppp_open(dev)){ + return -EIO; + } + + do_gettimeofday(&tv); + chdlc_priv_area->router_start_time = tv.tv_sec; + + #ifdef LINUX_2_4 + netif_start_queue(dev); + #else + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + #endif + + wanpipe_open(card); + + chdlc_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; + flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; + return 0; +} + +/*============================================================================ + * Close network interface. + * o if this is the last close, then disable communications and interrupts. + * o reset flags. + */ +static int if_close (netdevice_t* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + + /* Stop the PPP Layer */ + sppp_close(dev); + stop_net_queue(dev); + + #ifndef LINUX_2_4 + dev->start=0; + #endif + + wanpipe_close(card); + + return 0; +} + +/*============================================================================ + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission) to block a timer-based + * transmit from overlapping. + * o check link state. If link is not up, then drop the packet. + * o execute adapter send command. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + */ +static int if_send (struct sk_buff* skb, netdevice_t* dev) +{ + chdlc_private_area_t *chdlc_priv_area = dev->priv; + sdla_t *card = chdlc_priv_area->card; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; + int udp_type = 0; + unsigned long smp_flags; + int err=0; + + #ifdef LINUX_2_4 + netif_stop_queue(dev); + #endif + + + if (skb == NULL){ + /* If we get here, some higher layer thinks we've missed an + * tx-done interrupt. + */ + printk(KERN_INFO "%s: Received NULL skb buffer! interface %s got kicked!\n", + card->devname, dev->name); + + wake_net_dev(dev); + return 0; + } + + #ifndef LINUX_2_4 + if (dev->tbusy){ + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + ++card->wandev.stats.collisions; + + if((jiffies - chdlc_priv_area->tick_counter) < (5 * HZ)) { + return 1; + } + + printk (KERN_INFO "%s: Transmit (tbusy) timeout !\n", + card->devname); + + /* unbusy the interface */ + dev->tbusy = 0; + } + #endif + + if (ntohs(skb->protocol) != htons(PVC_PROT)){ + /* check the udp packet type */ + + udp_type = udp_pkt_type(skb, card); + if (udp_type == UDP_CPIPE_TYPE){ + if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, + chdlc_priv_area)){ + chdlc_int->interrupt_permission |= + APP_INT_ON_TIMER; + } + start_net_queue(dev); + return 0; + } + } + + /* Lock the 508 Card: SMP is supported */ + if(card->hw.type != SDLA_S514){ + s508_lock(card,&smp_flags); + } + + if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ + + printk(KERN_INFO "%s: Critical in if_send: %lx\n", + card->wandev.name,card->wandev.critical); + ++card->wandev.stats.tx_dropped; + start_net_queue(dev); + goto if_send_crit_exit; + } + + if (card->wandev.state != WAN_CONNECTED){ + ++card->wandev.stats.tx_dropped; + start_net_queue(dev); + goto if_send_crit_exit; + } + + if (chdlc_send(card, skb->data, skb->len)){ + stop_net_queue(dev); + + }else{ + ++card->wandev.stats.tx_packets; + #if defined(LINUX_2_1) || defined(LINUX_2_4) + card->wandev.stats.tx_bytes += skb->len; + #endif + #ifdef LINUX_2_4 + dev->trans_start = jiffies; + #endif + start_net_queue(dev); + } + +if_send_crit_exit: + if (!(err=is_queue_stopped(dev))){ + wan_dev_kfree_skb(skb, FREE_WRITE); + }else{ + chdlc_priv_area->tick_counter = jiffies; + chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; + } + + clear_bit(SEND_CRIT, (void*)&card->wandev.critical); + if(card->hw.type != SDLA_S514){ + s508_unlock(card,&smp_flags); + } + + return err; +} + + +/*============================================================================ + * Reply to UDP Management system. + * Return length of reply. + */ +static int reply_udp( unsigned char *data, unsigned int mbox_len ) +{ + + unsigned short len, udp_length, temp, ip_length; + unsigned long ip_temp; + int even_bound = 0; + chdlc_udp_pkt_t *c_udp_pkt = (chdlc_udp_pkt_t *)data; + + /* Set length of packet */ + len = sizeof(ip_pkt_t)+ + sizeof(udp_pkt_t)+ + sizeof(wp_mgmt_t)+ + sizeof(cblock_t)+ + sizeof(trace_info_t)+ + mbox_len; + + /* fill in UDP reply */ + c_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; + + /* fill in UDP length */ + udp_length = sizeof(udp_pkt_t)+ + sizeof(wp_mgmt_t)+ + sizeof(cblock_t)+ + sizeof(trace_info_t)+ + mbox_len; + + /* put it on an even boundary */ + if ( udp_length & 0x0001 ) { + udp_length += 1; + len += 1; + even_bound = 1; + } + + temp = (udp_length<<8)|(udp_length>>8); + c_udp_pkt->udp_pkt.udp_length = temp; + + /* swap UDP ports */ + temp = c_udp_pkt->udp_pkt.udp_src_port; + c_udp_pkt->udp_pkt.udp_src_port = + c_udp_pkt->udp_pkt.udp_dst_port; + c_udp_pkt->udp_pkt.udp_dst_port = temp; + + /* add UDP pseudo header */ + temp = 0x1100; + *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound)) = temp; + temp = (udp_length<<8)|(udp_length>>8); + *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound+2)) = temp; + + + /* calculate UDP checksum */ + c_udp_pkt->udp_pkt.udp_checksum = 0; + c_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); + + /* fill in IP length */ + ip_length = len; + temp = (ip_length<<8)|(ip_length>>8); + c_udp_pkt->ip_pkt.total_length = temp; + + /* swap IP addresses */ + ip_temp = c_udp_pkt->ip_pkt.ip_src_address; + c_udp_pkt->ip_pkt.ip_src_address = c_udp_pkt->ip_pkt.ip_dst_address; + c_udp_pkt->ip_pkt.ip_dst_address = ip_temp; + + /* fill in IP checksum */ + c_udp_pkt->ip_pkt.hdr_checksum = 0; + c_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t)); + + return len; + +} /* reply_udp */ + +unsigned short calc_checksum (char *data, int len) +{ + unsigned short temp; + unsigned long sum=0; + int i; + + for( i = 0; i <len; i+=2 ) { + memcpy(&temp,&data[i],2); + sum += (unsigned long)temp; + } + + while (sum >> 16 ) { + sum = (sum & 0xffffUL) + (sum >> 16); + } + + temp = (unsigned short)sum; + temp = ~temp; + + if( temp == 0 ) + temp = 0xffff; + + return temp; +} + + +/*============================================================================ + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) +static struct net_device_stats* if_stats (netdevice_t* dev) +{ + sdla_t *my_card; + chdlc_private_area_t* chdlc_priv_area; + + /* Shutdown bug fix. In del_if() we kill + * dev->priv pointer. This function, gets + * called after del_if(), thus check + * if pointer has been deleted */ + if ((chdlc_priv_area=dev->priv) == NULL) + return NULL; + + my_card = chdlc_priv_area->card; + return &my_card->wandev.stats; +} +#else +static struct enet_statistics* if_stats (netdevice_t* dev) +{ + sdla_t *my_card; + chdlc_private_area_t* chdlc_priv_area = dev->priv; + + /* Shutdown bug fix. In del_if() we kill + * dev->priv pointer. This function, gets + * called after del_if(), thus check + * if pointer has been deleted */ + if ((chdlc_priv_area=dev->priv) == NULL) + return NULL; + + my_card = chdlc_priv_area->card; + return &my_card->wandev.stats; +} +#endif + +/****** Cisco HDLC Firmware Interface Functions *******************************/ + +/*============================================================================ + * Read firmware code version. + * Put code version as ASCII string in str. + */ +static int chdlc_read_version (sdla_t* card, char* str) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + int len; + char err; + mb->buffer_length = 0; + mb->command = READ_CHDLC_CODE_VERSION; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + } + else if (str) { /* is not null */ + len = mb->buffer_length; + memcpy(str, mb->data, len); + str[len] = '\0'; + } + return (err); +} + +/*----------------------------------------------------------------------------- + * Configure CHDLC firmware. + */ +static int chdlc_configure (sdla_t* card, void* data) +{ + int err; + CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; + int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); + + mailbox->buffer_length = data_length; + memcpy(mailbox->data, data, data_length); + mailbox->command = SET_CHDLC_CONFIGURATION; + err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) chdlc_error (card, err, mailbox); + + return err; +} + + +/*============================================================================ + * Set interrupt mode -- HDLC Version. + */ + +static int chdlc_set_intr_mode (sdla_t* card, unsigned mode) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + CHDLC_INT_TRIGGERS_STRUCT* int_data = + (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; + int err; + + int_data->CHDLC_interrupt_triggers = mode; + int_data->IRQ = card->hw.irq; + int_data->interrupt_timer = 1; + + mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); + mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) + chdlc_error (card, err, mb); + return err; +} + + +/*============================================================================ + * Enable communications. + */ + +static int chdlc_comm_enable (sdla_t* card) +{ + int err; + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + + mb->buffer_length = 0; + mb->command = ENABLE_CHDLC_COMMUNICATIONS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) + chdlc_error(card, err, mb); + else + card->u.c.comm_enabled=1; + + return err; +} + +/*============================================================================ + * Disable communications and Drop the Modem lines (DCD and RTS). + */ +static int chdlc_comm_disable (sdla_t* card) +{ + int err; + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + + mb->buffer_length = 0; + mb->command = DISABLE_CHDLC_COMMUNICATIONS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) + chdlc_error(card,err,mb); + + return err; +} + +/*============================================================================ + * Read communication error statistics. + */ +static int chdlc_read_comm_err_stats (sdla_t* card) +{ + int err; + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + + mb->buffer_length = 0; + mb->command = READ_COMMS_ERROR_STATS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) + chdlc_error(card,err,mb); + return err; +} + + +/*============================================================================ + * Read CHDLC operational statistics. + */ +static int chdlc_read_op_stats (sdla_t* card) +{ + int err; + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + + mb->buffer_length = 0; + mb->command = READ_CHDLC_OPERATIONAL_STATS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) + chdlc_error(card,err,mb); + return err; +} + + +/*============================================================================ + * Update communications error and general packet statistics. + */ +static int update_comms_stats(sdla_t* card, + chdlc_private_area_t* chdlc_priv_area) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + COMMS_ERROR_STATS_STRUCT* err_stats; + CHDLC_OPERATIONAL_STATS_STRUCT *op_stats; + + /* on the first timer interrupt, read the comms error statistics */ + if(chdlc_priv_area->update_comms_stats == 2) { + if(chdlc_read_comm_err_stats(card)) + return 1; + err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->data; + card->wandev.stats.rx_over_errors = + err_stats->Rx_overrun_err_count; + card->wandev.stats.rx_crc_errors = + err_stats->CRC_err_count; + card->wandev.stats.rx_frame_errors = + err_stats->Rx_abort_count; + card->wandev.stats.rx_fifo_errors = + err_stats->Rx_dis_pri_bfrs_full_count; + card->wandev.stats.rx_missed_errors = + card->wandev.stats.rx_fifo_errors; + card->wandev.stats.tx_aborted_errors = + err_stats->sec_Tx_abort_count; + } + + /* on the second timer interrupt, read the operational statistics */ + else { + if(chdlc_read_op_stats(card)) + return 1; + op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->data; + card->wandev.stats.rx_length_errors = + (op_stats->Rx_Data_discard_short_count + + op_stats->Rx_Data_discard_long_count); + } + + return 0; +} + +/*============================================================================ + * Send packet. + * Return: 0 - o.k. + * 1 - no transmit buffers available + */ +static int chdlc_send (sdla_t* card, void* data, unsigned len) +{ + CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf; + + if (txbuf->opp_flag) + return 1; + + sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len); + + txbuf->frame_length = len; + txbuf->opp_flag = 1; /* start transmission */ + + /* Update transmit buffer control fields */ + card->u.c.txbuf = ++txbuf; + + if ((void*)txbuf > card->u.c.txbuf_last) + card->u.c.txbuf = card->u.c.txbuf_base; + + return 0; +} + +/****** Firmware Error Handler **********************************************/ + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb) +{ + unsigned cmd = mb->command; + + switch (err) { + + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + case S514_BOTH_PORTS_SAME_CLK_MODE: + if(cmd == SET_CHDLC_CONFIGURATION) { + printk(KERN_INFO + "%s: Configure both ports for the same clock source\n", + card->devname); + break; + } + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err); + } + + return 0; +} + +/****** Interrupt Handlers **************************************************/ + +/*============================================================================ + * Cisco HDLC interrupt service routine. + */ +STATIC void wsppp_isr (sdla_t* card) +{ + netdevice_t* dev; + SHARED_MEMORY_INFO_STRUCT* flags = NULL; + int i; + sdla_t *my_card; + + + /* Check for which port the interrupt has been generated + * Since Secondary Port is piggybacking on the Primary + * the check must be done here. + */ + + flags = card->u.c.flags; + if (!flags->interrupt_info_struct.interrupt_type){ + /* Check for a second port (piggybacking) */ + if((my_card = card->next)){ + flags = my_card->u.c.flags; + if (flags->interrupt_info_struct.interrupt_type){ + card = my_card; + card->isr(card); + return; + } + } + } + + dev = card->wandev.dev; + card->in_isr = 1; + flags = card->u.c.flags; + + /* If we get an interrupt with no network device, stop the interrupts + * and issue an error */ + if ((!dev || !dev->priv) && flags->interrupt_info_struct.interrupt_type != + COMMAND_COMPLETE_APP_INT_PEND){ + goto isr_done; + } + + + /* if critical due to peripheral operations + * ie. update() or getstats() then reset the interrupt and + * wait for the board to retrigger. + */ + if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { + flags->interrupt_info_struct. + interrupt_type = 0; + goto isr_done; + } + + + /* On a 508 Card, if critical due to if_send + * Major Error !!! + */ + if(card->hw.type != SDLA_S514) { + if(test_bit(0, (void*)&card->wandev.critical)) { + printk(KERN_INFO "%s: Critical while in ISR: %lx\n", + card->devname, card->wandev.critical); + goto isr_done; + } + } + + switch(flags->interrupt_info_struct.interrupt_type) { + + case RX_APP_INT_PEND: /* 0x01: receive interrupt */ + rx_intr(card); + break; + + case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ + flags->interrupt_info_struct.interrupt_permission &= + ~APP_INT_ON_TX_FRAME; + + wake_net_dev(dev); + break; + + case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ + ++ Intr_test_counter; + break; + + case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ + process_chdlc_exception(card); + break; + + case GLOBAL_EXCEP_COND_APP_INT_PEND: + process_global_exception(card); + break; + + case TIMER_APP_INT_PEND: + timer_intr(card); + break; + + default: + printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", + card->devname, + flags->interrupt_info_struct.interrupt_type); + printk(KERN_INFO "Code name: "); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c", + flags->global_info_struct.codename[i]); + printk(KERN_INFO "\nCode version: "); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c", + flags->global_info_struct.codeversion[i]); + printk(KERN_INFO "\n"); + break; + } + +isr_done: + card->in_isr = 0; + flags->interrupt_info_struct.interrupt_type = 0; +} + +/*============================================================================ + * Receive interrupt handler. + */ +static void rx_intr (sdla_t* card) +{ + netdevice_t *dev; + chdlc_private_area_t *chdlc_priv_area; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb; + struct sk_buff *skb; + unsigned len; + unsigned addr = rxbuf->ptr_data_bfr; + void *buf; + int i,udp_type; + + if (rxbuf->opp_flag != 0x01) { + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", + card->devname, (unsigned)rxbuf, rxbuf->opp_flag); + printk(KERN_INFO "Code name: "); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c", + flags->global_info_struct.codename[i]); + printk(KERN_INFO "\nCode version: "); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c", + flags->global_info_struct.codeversion[i]); + printk(KERN_INFO "\n"); + + + /* Bug Fix: Mar 6 2000 + * If we get a corrupted mailbox, it measn that driver + * is out of sync with the firmware. There is no recovery. + * If we don't turn off all interrupts for this card + * the machine will crash. + */ + printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); + printk(KERN_INFO "Please contact Sangoma Technologies !\n"); + chdlc_set_intr_mode(card,0); + return; + } + + dev = card->wandev.dev; + + if (!dev){ + goto rx_exit; + } + + #ifdef LINUX_2_4 + if (!netif_running(dev)){ + goto rx_exit; + } + #else + if (!dev->start){ + goto rx_exit; + } + #endif + + chdlc_priv_area = dev->priv; + + if (rxbuf->error_flag){ + goto rx_exit; + } + /* Take off two CRC bytes */ + + if (rxbuf->frame_length < 7 || rxbuf->frame_length > 1506 ){ + goto rx_exit; + } + + len = rxbuf->frame_length - CRC_LENGTH; + + /* Allocate socket buffer */ + skb = dev_alloc_skb(len); + + if (skb == NULL) { + if (net_ratelimit()){ + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + } + ++card->wandev.stats.rx_dropped; + goto rx_exit; + } + + /* Copy data to the socket buffer */ + if((addr + len) > card->u.c.rx_top + 1) { + unsigned tmp = card->u.c.rx_top - addr + 1; + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, addr, buf, tmp); + addr = card->u.c.rx_base; + len -= tmp; + } + + buf = skb_put(skb, len); + sdla_peek(&card->hw, addr, buf, len); + + skb->protocol = htons(ETH_P_WAN_PPP); + + card->wandev.stats.rx_packets ++; +#if defined(LINUX_2_1) || defined(LINUX_2_4) + card->wandev.stats.rx_bytes += skb->len; +#endif + udp_type = udp_pkt_type( skb, card ); + + if(udp_type == UDP_CPIPE_TYPE) { + if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, + card, skb, dev, chdlc_priv_area)) { + flags->interrupt_info_struct. + interrupt_permission |= + APP_INT_ON_TIMER; + } + }else{ + /* Pass it up the protocol stack */ + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); + } + +rx_exit: + /* Release buffer element and calculate a pointer to the next one */ + rxbuf->opp_flag = 0x00; + card->u.c.rxmb = ++ rxbuf; + if((void*)rxbuf > card->u.c.rxbuf_last){ + card->u.c.rxmb = card->u.c.rxbuf_base; + } +} + +/*============================================================================ + * Timer interrupt handler. + * The timer interrupt is used for two purposes: + * 1) Processing udp calls from 'cpipemon'. + * 2) Reading board-level statistics for updating the proc file system. + */ +void timer_intr(sdla_t *card) +{ + netdevice_t* dev; + chdlc_private_area_t* chdlc_priv_area = NULL; + SHARED_MEMORY_INFO_STRUCT* flags = NULL; + + dev = card->wandev.dev; + chdlc_priv_area = dev->priv; + + if (chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG) { + if (!config_chdlc(card)){ + chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; + } + } + + /* process a udp call if pending */ + if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) { + process_udp_mgmt_pkt(card, dev, + chdlc_priv_area); + chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; + } + + + /* read the communications statistics if required */ + if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE) { + update_comms_stats(card, chdlc_priv_area); + if(!(-- chdlc_priv_area->update_comms_stats)) { + chdlc_priv_area->timer_int_enabled &= + ~TMR_INT_ENABLED_UPDATE; + } + } + + /* only disable the timer interrupt if there are no udp or statistic */ + /* updates pending */ + if(!chdlc_priv_area->timer_int_enabled) { + flags = card->u.c.flags; + flags->interrupt_info_struct.interrupt_permission &= + ~APP_INT_ON_TIMER; + } +} + +/*------------------------------------------------------------------------------ + Miscellaneous Functions + - set_chdlc_config() used to set configuration options on the board +------------------------------------------------------------------------------*/ + +static int set_chdlc_config(sdla_t* card) +{ + + CHDLC_CONFIGURATION_STRUCT cfg; + + memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); + + if(card->wandev.clocking) + cfg.baud_rate = card->wandev.bps; + + cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? + INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; + + cfg.modem_config_options = 0; + //API OPTIONS + cfg.CHDLC_API_options = DISCARD_RX_ERROR_FRAMES; + cfg.modem_status_timer = 100; + cfg.CHDLC_protocol_options = HDLC_STREAMING_MODE; + cfg.percent_data_buffer_for_Tx = 50; + cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | + CHDLC_RX_DATA_BYTE_COUNT_STAT); + cfg.max_CHDLC_data_field_length = card->wandev.mtu; + + cfg.transmit_keepalive_timer = 0; + cfg.receive_keepalive_timer = 0; + cfg.keepalive_error_tolerance = 0; + cfg.SLARP_request_timer = 0; + + cfg.IP_address = 0; + cfg.IP_netmask = 0; + + return chdlc_configure(card, &cfg); +} + +/*============================================================================ + * Process global exception condition + */ +static int process_global_exception(sdla_t *card) +{ + CHDLC_MAILBOX_STRUCT* mbox = card->mbox; + int err; + + mbox->buffer_length = 0; + mbox->command = READ_GLOBAL_EXCEPTION_CONDITION; + err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; + + if(err != CMD_TIMEOUT ){ + + switch(mbox->return_code) { + + case EXCEP_MODEM_STATUS_CHANGE: + + printk(KERN_INFO "%s: Modem status change\n", + card->devname); + + switch(mbox->data[0] & (DCD_HIGH | CTS_HIGH)) { + case (DCD_HIGH): + printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); + break; + case (CTS_HIGH): + printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); + break; + case ((DCD_HIGH | CTS_HIGH)): + printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); + break; + default: + printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname); + break; + } + + if (!(mbox->data[0] & DCD_HIGH) || !(mbox->data[0] & DCD_HIGH)){ + //printk(KERN_INFO "Sending TERM Request Manually !\n"); + send_ppp_term_request(card->wandev.dev); + } + break; + + case EXCEP_TRC_DISABLED: + printk(KERN_INFO "%s: Line trace disabled\n", + card->devname); + break; + + case EXCEP_IRQ_TIMEOUT: + printk(KERN_INFO "%s: IRQ timeout occurred\n", + card->devname); + break; + + default: + printk(KERN_INFO "%s: Global exception %x\n", + card->devname, mbox->return_code); + break; + } + } + return 0; +} + + +/*============================================================================ + * Process chdlc exception condition + */ +static int process_chdlc_exception(sdla_t *card) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + int err; + + mb->buffer_length = 0; + mb->command = READ_CHDLC_EXCEPTION_CONDITION; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if(err != CMD_TIMEOUT) { + + switch (err) { + + case EXCEP_LINK_ACTIVE: + port_set_state(card, WAN_CONNECTED); + break; + + case EXCEP_LINK_INACTIVE_MODEM: + port_set_state(card, WAN_DISCONNECTED); + break; + + case EXCEP_LOOPBACK_CONDITION: + printk(KERN_INFO "%s: Loopback Condition Detected.\n", + card->devname); + break; + + case NO_CHDLC_EXCEP_COND_TO_REPORT: + printk(KERN_INFO "%s: No exceptions reported.\n", + card->devname); + break; + default: + printk(KERN_INFO "%s: Exception Condition %x!\n", + card->devname,err); + break; + } + + } + return 0; +} + + +/*============================================================================= + * Store a UDP management packet for later processing. + */ + +static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, netdevice_t* dev, + chdlc_private_area_t* chdlc_priv_area ) +{ + int udp_pkt_stored = 0; + + if(!chdlc_priv_area->udp_pkt_lgth && + (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) { + chdlc_priv_area->udp_pkt_lgth = skb->len; + chdlc_priv_area->udp_pkt_src = udp_pkt_src; + memcpy(chdlc_priv_area->udp_pkt_data, skb->data, skb->len); + chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UDP; + udp_pkt_stored = 1; + } + + if(udp_pkt_src == UDP_PKT_FRM_STACK) + wan_dev_kfree_skb(skb, FREE_WRITE); + else + wan_dev_kfree_skb(skb, FREE_READ); + + return(udp_pkt_stored); +} + + +/*============================================================================= + * Process UDP management packet. + */ + +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + chdlc_private_area_t* chdlc_priv_area ) +{ + unsigned char *buf; + unsigned int frames, len; + struct sk_buff *new_skb; + unsigned short buffer_length, real_len; + unsigned long data_ptr; + unsigned data_length; + int udp_mgmt_req_valid = 1; + CHDLC_MAILBOX_STRUCT *mb = card->mbox; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + chdlc_udp_pkt_t *chdlc_udp_pkt; + struct timeval tv; + int err; + char ut_char; + + chdlc_udp_pkt = (chdlc_udp_pkt_t *) chdlc_priv_area->udp_pkt_data; + + if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + switch(chdlc_udp_pkt->cblock.command) { + case READ_GLOBAL_STATISTICS: + case READ_MODEM_STATUS: + case READ_CHDLC_LINK_STATUS: + case CPIPE_ROUTER_UP_TIME: + case READ_COMMS_ERROR_STATS: + case READ_CHDLC_OPERATIONAL_STATS: + + /* These two commands are executed for + * each request */ + case READ_CHDLC_CONFIGURATION: + case READ_CHDLC_CODE_VERSION: + udp_mgmt_req_valid = 1; + break; + default: + udp_mgmt_req_valid = 0; + break; + } + } + + if(!udp_mgmt_req_valid) { + + /* set length to 0 */ + chdlc_udp_pkt->cblock.buffer_length = 0; + + /* set return code */ + chdlc_udp_pkt->cblock.return_code = 0xCD; + + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,chdlc_udp_pkt->cblock.command); + } + + } else { + unsigned long trace_status_cfg_addr = 0; + TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct; + TRACE_STATUS_ELEMENT_STRUCT trace_element_struct; + + switch(chdlc_udp_pkt->cblock.command) { + + case CPIPE_ENABLE_TRACING: + if (!chdlc_priv_area->TracingEnabled) { + + /* OPERATE_DATALINE_MONITOR */ + + mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); + mb->command = SET_TRACE_CONFIGURATION; + + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> + trace_config = TRACE_ACTIVE; + /* Trace delay mode is not used because it slows + down transfer and results in a standoff situation + when there is a lot of data */ + + /* Configure the Trace based on user inputs */ + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->trace_config |= + chdlc_udp_pkt->data[0]; + + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> + trace_deactivation_timer = 4000; + + + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) { + chdlc_error(card,err,mb); + card->TracingEnabled = 0; + chdlc_udp_pkt->cblock.return_code = err; + mb->buffer_length = 0; + break; + } + + /* Get the base address of the trace element list */ + mb->buffer_length = 0; + mb->command = READ_TRACE_CONFIGURATION; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) { + chdlc_error(card,err,mb); + chdlc_priv_area->TracingEnabled = 0; + chdlc_udp_pkt->cblock.return_code = err; + mb->buffer_length = 0; + break; + } + + trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *) + mb->data) -> ptr_trace_stat_el_cfg_struct; + + sdla_peek(&card->hw, trace_status_cfg_addr, + &trace_cfg_struct, sizeof(trace_cfg_struct)); + + chdlc_priv_area->start_trace_addr = trace_cfg_struct. + base_addr_trace_status_elements; + + chdlc_priv_area->number_trace_elements = + trace_cfg_struct.number_trace_status_elements; + + chdlc_priv_area->end_trace_addr = (unsigned long) + ((TRACE_STATUS_ELEMENT_STRUCT *) + chdlc_priv_area->start_trace_addr + + (chdlc_priv_area->number_trace_elements - 1)); + + chdlc_priv_area->base_addr_trace_buffer = + trace_cfg_struct.base_addr_trace_buffer; + + chdlc_priv_area->end_addr_trace_buffer = + trace_cfg_struct.end_addr_trace_buffer; + + chdlc_priv_area->curr_trace_addr = + trace_cfg_struct.next_trace_element_to_use; + + chdlc_priv_area->available_buffer_space = 2000 - + sizeof(ip_pkt_t) - + sizeof(udp_pkt_t) - + sizeof(wp_mgmt_t) - + sizeof(cblock_t) - + sizeof(trace_info_t); + } + chdlc_udp_pkt->cblock.return_code = COMMAND_OK; + mb->buffer_length = 0; + chdlc_priv_area->TracingEnabled = 1; + break; + + + case CPIPE_DISABLE_TRACING: + if (chdlc_priv_area->TracingEnabled) { + + /* OPERATE_DATALINE_MONITOR */ + mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); + mb->command = SET_TRACE_CONFIGURATION; + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> + trace_config = TRACE_INACTIVE; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + } + + chdlc_priv_area->TracingEnabled = 0; + chdlc_udp_pkt->cblock.return_code = COMMAND_OK; + mb->buffer_length = 0; + break; + + + case CPIPE_GET_TRACE_INFO: + + if (!chdlc_priv_area->TracingEnabled) { + chdlc_udp_pkt->cblock.return_code = 1; + mb->buffer_length = 0; + break; + } + + chdlc_udp_pkt->trace_info.ismoredata = 0x00; + buffer_length = 0; /* offset of packet already occupied */ + + for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++){ + + trace_pkt_t *trace_pkt = (trace_pkt_t *) + &chdlc_udp_pkt->data[buffer_length]; + + sdla_peek(&card->hw, chdlc_priv_area->curr_trace_addr, + (unsigned char *)&trace_element_struct, + sizeof(TRACE_STATUS_ELEMENT_STRUCT)); + + if (trace_element_struct.opp_flag == 0x00) { + break; + } + + /* get pointer to real data */ + data_ptr = trace_element_struct.ptr_data_bfr; + + /* See if there is actual data on the trace buffer */ + if (data_ptr){ + data_length = trace_element_struct.trace_length; + }else{ + data_length = 0; + chdlc_udp_pkt->trace_info.ismoredata = 0x01; + } + + if( (chdlc_priv_area->available_buffer_space - buffer_length) + < ( sizeof(trace_pkt_t) + data_length) ) { + + /* indicate there are more frames on board & exit */ + chdlc_udp_pkt->trace_info.ismoredata = 0x01; + break; + } + + trace_pkt->status = trace_element_struct.trace_type; + + trace_pkt->time_stamp = + trace_element_struct.trace_time_stamp; + + trace_pkt->real_length = + trace_element_struct.trace_length; + + /* see if we can fit the frame into the user buffer */ + real_len = trace_pkt->real_length; + + if (data_ptr == 0) { + trace_pkt->data_avail = 0x00; + } else { + unsigned tmp = 0; + + /* get the data from circular buffer + must check for end of buffer */ + trace_pkt->data_avail = 0x01; + + if ((data_ptr + real_len) > + chdlc_priv_area->end_addr_trace_buffer + 1){ + + tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1; + sdla_peek(&card->hw, data_ptr, + trace_pkt->data,tmp); + data_ptr = chdlc_priv_area->base_addr_trace_buffer; + } + + sdla_peek(&card->hw, data_ptr, + &trace_pkt->data[tmp], real_len - tmp); + } + + /* zero the opp flag to show we got the frame */ + ut_char = 0x00; + sdla_poke(&card->hw, chdlc_priv_area->curr_trace_addr, &ut_char, 1); + + /* now move onto the next frame */ + chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT); + + /* check if we went over the last address */ + if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) { + chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr; + } + + if(trace_pkt->data_avail == 0x01) { + buffer_length += real_len - 1; + } + + /* for the header */ + buffer_length += sizeof(trace_pkt_t); + + } /* For Loop */ + + if (frames == chdlc_priv_area->number_trace_elements){ + chdlc_udp_pkt->trace_info.ismoredata = 0x01; + } + chdlc_udp_pkt->trace_info.num_frames = frames; + + mb->buffer_length = buffer_length; + chdlc_udp_pkt->cblock.buffer_length = buffer_length; + + chdlc_udp_pkt->cblock.return_code = COMMAND_OK; + + break; + + + case CPIPE_FT1_READ_STATUS: + ((unsigned char *)chdlc_udp_pkt->data )[0] = + flags->FT1_info_struct.parallel_port_A_input; + + ((unsigned char *)chdlc_udp_pkt->data )[1] = + flags->FT1_info_struct.parallel_port_B_input; + + chdlc_udp_pkt->cblock.return_code = COMMAND_OK; + mb->buffer_length = 2; + break; + + case CPIPE_ROUTER_UP_TIME: + do_gettimeofday( &tv ); + chdlc_priv_area->router_up_time = tv.tv_sec - + chdlc_priv_area->router_start_time; + *(unsigned long *)&chdlc_udp_pkt->data = + chdlc_priv_area->router_up_time; + mb->buffer_length = sizeof(unsigned long); + break; + + case FT1_MONITOR_STATUS_CTRL: + /* Enable FT1 MONITOR STATUS */ + if ((chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_STATUS) || + (chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_OP_STATS)) { + + if( rCount++ != 0 ) { + chdlc_udp_pkt->cblock. + return_code = COMMAND_OK; + mb->buffer_length = 1; + break; + } + } + + /* Disable FT1 MONITOR STATUS */ + if( chdlc_udp_pkt->data[0] == 0) { + + if( --rCount != 0) { + chdlc_udp_pkt->cblock. + return_code = COMMAND_OK; + mb->buffer_length = 1; + break; + } + } + + default: + /* it's a board command */ + mb->command = chdlc_udp_pkt->cblock.command; + mb->buffer_length = chdlc_udp_pkt->cblock.buffer_length; + if (mb->buffer_length) { + memcpy(&mb->data, (unsigned char *) chdlc_udp_pkt-> + data, mb->buffer_length); + } + /* run the command on the board */ + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) { + break; + } + + /* copy the result back to our buffer */ + memcpy(&chdlc_udp_pkt->cblock, mb, sizeof(cblock_t)); + + if (mb->buffer_length) { + memcpy(&chdlc_udp_pkt->data, &mb->data, + mb->buffer_length); + } + + } /* end of switch */ + } /* end of else */ + + /* Fill UDP TTL */ + chdlc_udp_pkt->ip_pkt.ttl = card->wandev.ttl; + + len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->buffer_length); + + if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { + if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) { + ++ card->wandev.stats.tx_packets; +#if defined(LINUX_2_1) || defined(LINUX_2_4) + card->wandev.stats.tx_bytes += len; +#endif + } + } else { + + /* Pass it up the stack + Allocate socket buffer */ + if ((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ + + buf = skb_put(new_skb, len); + memcpy(buf, chdlc_priv_area->udp_pkt_data, len); + + /* Decapsulate pkt and pass it up the protocol stack */ + new_skb->protocol = htons(ETH_P_IP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; + + netif_rx(new_skb); + } else { + + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + } + } + + chdlc_priv_area->udp_pkt_lgth = 0; + + return 0; +} + +/*============================================================================ + * Initialize Receive and Transmit Buffers. + */ + +static void init_chdlc_tx_rx_buff( sdla_t* card, netdevice_t *dev ) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config; + CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_config; + char err; + + mb->buffer_length = 0; + mb->command = READ_CHDLC_CONFIGURATION; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + return; + } + + if(card->hw.type == SDLA_S514) { + tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> + ptr_CHDLC_Tx_stat_el_cfg_struct)); + rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> + ptr_CHDLC_Rx_stat_el_cfg_struct)); + + /* Setup Head and Tails for buffers */ + card->u.c.txbuf_base = (void *)(card->hw.dpmbase + + tx_config->base_addr_Tx_status_elements); + card->u.c.txbuf_last = + (CHDLC_DATA_TX_STATUS_EL_STRUCT *) + card->u.c.txbuf_base + + (tx_config->number_Tx_status_elements - 1); + + card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + + rx_config->base_addr_Rx_status_elements); + card->u.c.rxbuf_last = + (CHDLC_DATA_RX_STATUS_EL_STRUCT *) + card->u.c.rxbuf_base + + (rx_config->number_Rx_status_elements - 1); + + /* Set up next pointer to be used */ + card->u.c.txbuf = (void *)(card->hw.dpmbase + + tx_config->next_Tx_status_element_to_use); + card->u.c.rxmb = (void *)(card->hw.dpmbase + + rx_config->next_Rx_status_element_to_use); + } + else { + tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> + ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); + + rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> + ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); + + /* Setup Head and Tails for buffers */ + card->u.c.txbuf_base = (void *)(card->hw.dpmbase + + (tx_config->base_addr_Tx_status_elements % SDLA_WINDOWSIZE)); + card->u.c.txbuf_last = + (CHDLC_DATA_TX_STATUS_EL_STRUCT *)card->u.c.txbuf_base + + (tx_config->number_Tx_status_elements - 1); + card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + + (rx_config->base_addr_Rx_status_elements % SDLA_WINDOWSIZE)); + card->u.c.rxbuf_last = + (CHDLC_DATA_RX_STATUS_EL_STRUCT *)card->u.c.rxbuf_base + + (rx_config->number_Rx_status_elements - 1); + + /* Set up next pointer to be used */ + card->u.c.txbuf = (void *)(card->hw.dpmbase + + (tx_config->next_Tx_status_element_to_use % SDLA_WINDOWSIZE)); + card->u.c.rxmb = (void *)(card->hw.dpmbase + + (rx_config->next_Rx_status_element_to_use % SDLA_WINDOWSIZE)); + } + + /* Setup Actual Buffer Start and end addresses */ + card->u.c.rx_base = rx_config->base_addr_Rx_buffer; + card->u.c.rx_top = rx_config->end_addr_Rx_buffer; + +} + +/*============================================================================= + * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR + * _TEST_COUNTER times. + */ +static int intr_test( sdla_t* card) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + int err,i; + + Intr_test_counter = 0; + + /* The critical flag is unset because during intialization (if_open) + * we want the interrupts to be enabled so that when the wpc_isr is + * called it does not exit due to critical flag set. + */ + + err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); + + if (err == CMD_OK) { + for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { + mb->buffer_length = 0; + mb->command = READ_CHDLC_CODE_VERSION; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + } + } + else { + return err; + } + + err = chdlc_set_intr_mode(card, 0); + + if (err != CMD_OK) + return err; + + return 0; +} + +/*============================================================================== + * Determine what type of UDP call it is. CPIPEAB ? + */ +static int udp_pkt_type(struct sk_buff *skb, sdla_t* card) +{ + chdlc_udp_pkt_t *chdlc_udp_pkt = (chdlc_udp_pkt_t *)skb->data; + + if (!strncmp(chdlc_udp_pkt->wp_mgmt.signature,UDPMGMT_SIGNATURE,8) && + (chdlc_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && + (chdlc_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && + (chdlc_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { + return UDP_CPIPE_TYPE; + } + else return UDP_INVALID_TYPE; +} + +/*============================================================================ + * Set PORT state. + */ +static void port_set_state (sdla_t *card, int state) +{ + netdevice_t *dev = card->wandev.dev; + chdlc_private_area_t *chdlc_priv_area = dev->priv; + + if (card->u.c.state != state) + { + switch (state) + { + case WAN_CONNECTED: + printk (KERN_INFO "%s: HDLC link connected!\n", + card->devname); + break; + + case WAN_CONNECTING: + printk (KERN_INFO "%s: HDLC link connecting...\n", + card->devname); + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO "%s: HDLC link disconnected!\n", + card->devname); + break; + } + + card->wandev.state = card->u.c.state = state; + chdlc_priv_area->common.state = state; + } +} + +void s508_lock (sdla_t *card, unsigned long *smp_flags) +{ + #if defined(__SMP__) || defined(LINUX_2_4) + spin_lock_irqsave(&card->wandev.lock, *smp_flags); + if (card->next){ + /* It is ok to use spin_lock here, since we + * already turned off interrupts */ + spin_lock(&card->next->wandev.lock); + } + #else + disable_irq(card->hw.irq); + #endif +} + +void s508_unlock (sdla_t *card, unsigned long *smp_flags) +{ + #if defined(__SMP__) || defined(LINUX_2_4) + if (card->next){ + spin_unlock(&card->next->wandev.lock); + } + spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); + #else + enable_irq(card->hw.irq); + #endif +} + + + +/*=========================================================================== + * config_chdlc + * + * Configure the chdlc protocol and enable communications. + * + * The if_open() function binds this function to the poll routine. + * Therefore, this function will run every time the chdlc interface + * is brought up. We cannot run this function from the if_open + * because if_open does not have access to the remote IP address. + * + * If the communications are not enabled, proceed to configure + * the card and enable communications. + * + * If the communications are enabled, it means that the interface + * was shutdown by ether the user or driver. In this case, we + * have to check that the IP addresses have not changed. If + * the IP addresses have changed, we have to reconfigure the firmware + * and update the changed IP addresses. Otherwise, just exit. + * + */ + +static int config_chdlc (sdla_t *card) +{ + netdevice_t *dev = card->wandev.dev; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + + if (card->u.c.comm_enabled){ + chdlc_comm_disable(card); + port_set_state(card, WAN_DISCONNECTED); + } + + if (set_chdlc_config(card)) { + printk(KERN_INFO "%s: CHDLC Configuration Failed!\n", + card->devname); + return 0; + } + init_chdlc_tx_rx_buff(card, dev); + + /* Set interrupt mode and mask */ + if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_TX_FRAME | + APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ + printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", + card->devname); + return 0; + } + + + /* Mask the Transmit and Timer interrupt */ + flags->interrupt_info_struct.interrupt_permission &= + ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); + + + if (chdlc_comm_enable(card) != 0) { + printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", + card->devname); + flags->interrupt_info_struct.interrupt_permission = 0; + card->u.c.comm_enabled=0; + chdlc_set_intr_mode(card,0); + return 0; + } + + /* Initialize Rx/Tx buffer control fields */ + port_set_state(card, WAN_CONNECTING); + return 0; +} + + +static void send_ppp_term_request (netdevice_t *dev) +{ + struct sk_buff *new_skb; + unsigned char *buf; + + if ((new_skb = dev_alloc_skb(8)) != NULL) { + /* copy data into new_skb */ + + buf = skb_put(new_skb, 8); + sprintf(buf,"%c%c%c%c%c%c%c%c", 0xFF,0x03,0xC0,0x21,0x05,0x98,0x00,0x07); + + /* Decapsulate pkt and pass it up the protocol stack */ + new_skb->protocol = htons(ETH_P_WAN_PPP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; + + netif_rx(new_skb); + } +} + + +/****** End ****************************************************************/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/wavelan.c linux.ac/drivers/net/wavelan.c --- linux.vanilla/drivers/net/wavelan.c Tue Apr 3 17:32:16 2001 +++ linux.ac/drivers/net/wavelan.c Tue Apr 3 17:54:56 2001 @@ -1545,8 +1545,7 @@ /* Setting by channel (same as wfreqsel) */ /* Warning: each channel is 22 MHz wide, so some of the channels * will interfere. */ - if ((frequency->e == 0) && - (frequency->m >= 0) && (frequency->m < BAND_NUM)) { + if ((frequency->e == 0) && (frequency->m < BAND_NUM)) { /* Get frequency offset. */ freq = channel_bands[frequency->m] >> 1; } @@ -2028,8 +2027,17 @@ if (wrq->u.data.pointer != (caddr_t) 0) { struct iw_range range; - /* Set the length (useless: it's constant). */ + /* Set the length (very important for backward + * compatibility) */ wrq->u.data.length = sizeof(struct iw_range); + + /* Set all the info we don't care or don't know + * about to zero */ + memset(&range, 0, sizeof(range)); + + /* Set the Wireless Extension versions */ + range.we_version_compiled = WIRELESS_EXT; + range.we_version_source = 9; /* Set information in the range struct. */ range.throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/parport/ChangeLog linux.ac/drivers/parport/ChangeLog --- linux.vanilla/drivers/parport/ChangeLog Tue Apr 3 17:32:16 2001 +++ linux.ac/drivers/parport/ChangeLog Sun Apr 15 22:58:12 2001 @@ -1,3 +1,20 @@ +2001-04-08 Tim Waugh <twaugh@redhat.com> + + * parport_pc.c (parport_pc_save_state): Read from the soft copy of + the control port. + (parport_pc_restore_state): Update the soft copy of the control + port. + +2001-03-26 Tim Waugh <twaugh@redhat.com> + + * share.c (parport_find_number, parport_find_base): Trigger + a lowlevel driver load if there are no ports yet. + +2001-03-26 Tim Waugh <twaugh@redhat.com> + + * parport_pc.c (parport_ECP_supported): Remove the IRQ conflict + check since it seems totally unreliable. + 2001-03-02 Tim Waugh <twaugh@redhat.com> * ieee1284_ops.c (parport_ieee1284_read_nibble): Reset nAutoFd diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/parport/Config.in linux.ac/drivers/parport/Config.in --- linux.vanilla/drivers/parport/Config.in Sat Feb 3 20:43:52 2001 +++ linux.ac/drivers/parport/Config.in Tue Apr 3 17:54:57 2001 @@ -17,12 +17,8 @@ bool ' SuperIO chipset support (EXPERIMENTAL)' CONFIG_PARPORT_PC_SUPERIO fi fi - if [ "$CONFIG_PARPORT_PC" = "y" ]; then - # Don't bother with this if parport_pc is a module; it only affects - # the presence or not of some __init's, which are no-ops for modules. - if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then - bool ' Support for PCMCIA management for PC-style ports' CONFIG_PARPORT_PC_PCMCIA - fi + if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then + dep_tristate ' Support for PCMCIA management for PC-style ports' CONFIG_PARPORT_PC_PCMCIA $CONFIG_PCMCIA fi if [ "$CONFIG_ARM" = "y" ]; then dep_tristate ' Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT @@ -41,6 +37,12 @@ else define_tristate CONFIG_PARPORT_ATARI n fi + if [ "$CONFIG_GSC_LASI" = "y" ]; then + dep_tristate ' LASI/ASP builtin parallel-port' CONFIG_PARPORT_GSC $CONFIG_PARPORT + else + define_tristate CONFIG_PARPORT_GSC n + fi + if [ "$CONFIG_SBUS" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' Sparc hardware (EXPERIMENTAL)' CONFIG_PARPORT_SUNBPP $CONFIG_PARPORT else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/parport/Makefile linux.ac/drivers/parport/Makefile --- linux.vanilla/drivers/parport/Makefile Fri Dec 29 22:07:22 2000 +++ linux.ac/drivers/parport/Makefile Tue Apr 3 17:54:57 2001 @@ -22,6 +22,7 @@ obj-$(CONFIG_PARPORT) += parport.o obj-$(CONFIG_PARPORT_PC) += parport_pc.o +obj-$(CONFIG_PARPORT_PC_PCMCIA)+= parport_cs.o obj-$(CONFIG_PARPORT_AMIGA) += parport_amiga.o obj-$(CONFIG_PARPORT_MFC3) += parport_mfc3.o obj-$(CONFIG_PARPORT_ATARI) += parport_atari.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/parport/parport_cs.c linux.ac/drivers/parport/parport_cs.c --- linux.vanilla/drivers/parport/parport_cs.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/parport/parport_cs.c Tue Apr 3 17:54:57 2001 @@ -0,0 +1,482 @@ +/*====================================================================== + + A driver for PCMCIA parallel port adapters + + (specifically, for the Quatech SPP-100 EPP card: other cards will + probably require driver tweaks) + + parport_cs.c 1.20 2000/11/02 23:15:05 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + <dahinds@users.sourceforge.net>. Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + + +#include <linux/kernel.h> +#include <linux/version.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/malloc.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/ioport.h> + +#include <linux/parport.h> +#include <linux/parport_pc.h> + +#include <pcmcia/version.h> +#include <pcmcia/cs_types.h> +#include <pcmcia/cs.h> +#include <pcmcia/cistpl.h> +#include <pcmcia/ds.h> +#include <pcmcia/cisreg.h> +#include <pcmcia/ciscode.h> + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"parport_cs.c 1.20 2000/11/02 23:15:05 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif + +#ifndef VERSION +#define VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#endif + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* Bit map of interrupts to choose from */ +static u_int irq_mask = 0xdeb8; +static int irq_list[4] = { -1 }; +static int epp_mode = 1; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM(epp_mode, "i"); + +/*====================================================================*/ + +#define FORCE_EPP_MODE 0x08 + +typedef struct parport_info_t { + dev_link_t link; + int ndev; + dev_node_t node; + struct parport *port; +} parport_info_t; + +static dev_link_t *parport_attach(void); +static void parport_detach(dev_link_t *); +static void parport_config(dev_link_t *link); +static void parport_cs_release(u_long arg); +static int parport_event(event_t event, int priority, + event_callback_args_t *args); + +static dev_info_t dev_info = "parport_cs"; +static dev_link_t *dev_list = NULL; + +extern struct parport_operations parport_pc_ops; +static struct parport_operations parport_cs_ops; + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================== + + parport_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + +======================================================================*/ + +static dev_link_t *parport_attach(void) +{ + parport_info_t *info; + dev_link_t *link; + client_reg_t client_reg; + int i, ret; + + DEBUG(0, "parport_attach()\n"); + + /* Create new parport device */ + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) return NULL; + memset(info, 0, sizeof(*info)); + link = &info->link; link->priv = info; + + link->release.function = &parport_cs_release; + link->release.data = (u_long)link; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &parport_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + parport_detach(link); + return NULL; + } + + return link; +} /* parport_attach */ + +/*====================================================================== + + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + +======================================================================*/ + +static void parport_detach(dev_link_t *link) +{ + dev_link_t **linkp; + int ret; + + DEBUG(0, "parport_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + del_timer(&link->release); + if (link->state & DEV_CONFIG) + parport_cs_release((u_long)link); + + if (link->handle) { + ret = CardServices(DeregisterClient, link->handle); + if (ret != CS_SUCCESS) + cs_error(link->handle, DeregisterClient, ret); + } + + /* Unlink, free device structure */ + *linkp = link->next; + kfree(link->priv); + +} /* parport_detach */ + +/*====================================================================== + + parport_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + parport device available to the system. + +======================================================================*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed + +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry + +static struct { u_int flag; char *name; } mode[] = { + { PARPORT_MODE_TRISTATE, "PS2" }, + { PARPORT_MODE_EPP, "EPP" }, + { PARPORT_MODE_ECP, "ECP" }, +}; + +void parport_config(dev_link_t *link) +{ + client_handle_t handle = link->handle; + parport_info_t *info = link->priv; + tuple_t tuple; + u_short buf[128]; + cisparse_t parse; + config_info_t conf; + cistpl_cftable_entry_t *cfg = &parse.cftable_entry; + cistpl_cftable_entry_t dflt = { 0 }; + struct parport *p; + int i, last_ret, last_fn; + + DEBUG(0, "parport_config(0x%p)\n", link); + + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; tuple.TupleDataMax = 255; + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + /* Not sure if this is right... look up the current Vcc */ + CS_CHECK(GetConfigurationInfo, handle, &conf); + + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + tuple.Attributes = 0; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + + if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; + link->conf.ConfigIndex = cfg->index; + if (epp_mode) + link->conf.ConfigIndex |= FORCE_EPP_MODE; + link->io.BasePort1 = io->win[0].base; + link->io.NumPorts1 = io->win[0].len; + link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; + if (io->nwin == 2) { + link->io.BasePort2 = io->win[1].base; + link->io.NumPorts2 = io->win[1].len; + } + CFG_CHECK(RequestIO, link->handle, &link->io); + /* If we've got this far, we're done */ + break; + } + + next_entry: + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; + CS_CHECK(GetNextTuple, handle, &tuple); + } + + CS_CHECK(RequestIRQ, handle, &link->irq); + CS_CHECK(RequestConfiguration, handle, &link->conf); + + p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2, + link->irq.AssignedIRQ, PARPORT_DMA_NONE, + NULL); + if (p == NULL) { + printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at " + "0x%3x, irq %u failed\n", link->io.BasePort1, + link->irq.AssignedIRQ); + goto failed; + } + +#if (LINUX_VERSION_CODE < VERSION(2,3,6)) +#if (LINUX_VERSION_CODE >= VERSION(2,2,8)) + p->private_data = kmalloc(sizeof(struct parport_pc_private), + GFP_KERNEL); + ((struct parport_pc_private *)(p->private_data))->ctr = 0x0c; +#endif + parport_proc_register(p); + p->flags |= PARPORT_FLAG_COMA; + parport_pc_write_econtrol(p, 0x00); + parport_pc_write_control(p, 0x0c); + parport_pc_write_data(p, 0x00); +#endif + + p->modes |= PARPORT_MODE_PCSPP; + if (epp_mode) + p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP; + info->ndev = 1; + info->node.major = LP_MAJOR; + info->node.minor = p->number; + info->port = p; + strcpy(info->node.dev_name, p->name); + link->dev = &info->node; + printk(KERN_INFO "%s: PC-style PCMCIA at %#x", p->name, + link->io.BasePort1); + if (link->io.NumPorts2) + printk(" & %#x", link->io.BasePort2); + printk(", irq %u [SPP", link->irq.AssignedIRQ); + for (i = 0; i < 5; i++) + if (p->modes & mode[i].flag) printk(",%s", mode[i].name); + printk("]\n"); + + link->state &= ~DEV_CONFIG_PENDING; + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); +failed: + parport_cs_release((u_long)link); + +} /* parport_config */ + +/*====================================================================== + + After a card is removed, parport_cs_release() will unregister the + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + +======================================================================*/ + +void parport_cs_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + parport_info_t *info = link->priv; + + DEBUG(0, "parport_release(0x%p)\n", link); + + if (info->ndev) { + struct parport *p = info->port; +#if (LINUX_VERSION_CODE < VERSION(2,3,6)) + if (!(p->flags & PARPORT_FLAG_COMA)) + parport_quiesce(p); +#endif + parport_proc_unregister(p); +#if (LINUX_VERSION_CODE >= VERSION(2,2,8)) + kfree(p->private_data); +#endif + parport_unregister_port(p); + } + info->ndev = 0; + link->dev = NULL; + + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~DEV_CONFIG; + +} /* parport_cs_release */ + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. + +======================================================================*/ + +int parport_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + + DEBUG(1, "parport_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) + mod_timer(&link->release, jiffies + HZ/20); + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + parport_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (DEV_OK(link)) + CardServices(RequestConfiguration, link->handle, &link->conf); + break; + } + return 0; +} /* parport_event */ + +/*====================================================================*/ + +#if (LINUX_VERSION_CODE < VERSION(2,3,6)) + +static void inc_use_count(void) +{ + MOD_INC_USE_COUNT; + parport_pc_ops.inc_use_count(); +} + +static void dec_use_count(void) +{ + MOD_DEC_USE_COUNT; + parport_pc_ops.dec_use_count(); +} + +#endif + +/*====================================================================*/ + +static int __init init_parport_cs(void) +{ + servinfo_t serv; + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "parport_cs: Card Services release " + "does not match!\n"); + return -1; + } + +#if (LINUX_VERSION_CODE < VERSION(2,3,6)) + /* This is to protect against unloading modules out of order */ + parport_cs_ops = parport_pc_ops; + parport_cs_ops.inc_use_count = &inc_use_count; + parport_cs_ops.dec_use_count = &dec_use_count; +#endif + + register_pccard_driver(&dev_info, &parport_attach, &parport_detach); + return 0; +} + +static void __exit exit_parport_cs(void) +{ + DEBUG(0, "parport_cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + parport_detach(dev_list); +} + +module_init(init_parport_cs); +module_exit(exit_parport_cs); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/parport/parport_mfc3.c linux.ac/drivers/parport/parport_mfc3.c --- linux.vanilla/drivers/parport/parport_mfc3.c Tue Nov 28 01:11:26 2000 +++ linux.ac/drivers/parport/parport_mfc3.c Tue Apr 3 17:54:57 2001 @@ -91,7 +91,7 @@ static unsigned char mfc3_read_data(struct parport *p) { - /* clears interupt bit. Triggers also /STROBE. */ + /* clears interrupt bit. Triggers also /STROBE. */ return pia(p)->pprb; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/parport/parport_pc.c linux.ac/drivers/parport/parport_pc.c --- linux.vanilla/drivers/parport/parport_pc.c Tue Apr 3 17:32:17 2001 +++ linux.ac/drivers/parport/parport_pc.c Tue Apr 17 16:06:41 2001 @@ -60,6 +60,10 @@ #include <linux/parport_pc.h> #include <asm/parport.h> +#if defined (CONFIG_PNPBIOS) || defined (CONFIG_PNPBIOS_MODULE) +#include <linux/pnp_bios.h> +#endif + #define PARPORT_PC_MAX_PORTS PARPORT_MAX /* ECR modes */ @@ -347,15 +351,16 @@ void parport_pc_save_state(struct parport *p, struct parport_state *s) { const struct parport_pc_private *priv = p->physport->private_data; - s->u.pc.ctr = inb (CONTROL (p)); + s->u.pc.ctr = priv->ctr; if (priv->ecr) s->u.pc.ecr = inb (ECONTROL (p)); } void parport_pc_restore_state(struct parport *p, struct parport_state *s) { - const struct parport_pc_private *priv = p->physport->private_data; + struct parport_pc_private *priv = p->physport->private_data; outb (s->u.pc.ctr, CONTROL (p)); + priv->ctr = s->u.pc.ctr; if (priv->ecr) outb (s->u.pc.ecr, ECONTROL (p)); } @@ -939,13 +944,11 @@ /* Can't yield the port. */ schedule (); - /* At this point, the FIFO may already be full. - * Ideally, we'd be able to tell the port to hold on - * for a second while we empty the FIFO, and we'd be - * able to ensure that no data is lost. I'm not sure - * that's the case. :-( It might be that you can play - * games with STB, as in the forward case; someone should - * look at a datasheet. */ + /* At this point, the FIFO may already be full. In + * that case ECP is already holding back the + * peripheral (assuming proper design) with a delayed + * handshake. Work fast to avoid a peripheral + * timeout. */ if (ecrval & 0x01) { /* FIFO is empty. Wait for interrupt. */ @@ -977,6 +980,10 @@ goto false_alarm; } + /* Depending on how the FIFO threshold was + * set, how long interrupt service took, and + * how fast the peripheral is, we might be + * lucky and have a just filled FIFO. */ continue; } @@ -988,6 +995,9 @@ continue; } + /* FIFO not filled. We will cycle this loop for a while + * and either the peripheral will fill it faster, + * tripping a fast empty with insb, or we empty it. */ *bufp++ = inb (fifo); left--; } @@ -1396,6 +1406,22 @@ } #endif /* CONFIG_PARPORT_PC_SUPERIO */ +static void __devinit set_superio_hint(int io,int irq,int dma) +{ int i=0; + + while((superios[i].io!= 0) && (i<NR_SUPERIOS)) + i++; + if(i==NR_SUPERIOS) { + printk("Super-IO: too many chips!\n"); + return; + } + superios[i].io = io; + superios[i].irq = irq; + superios[i].dma = dma; +} + + + static int __devinit get_superio_dma (struct parport *p) { int i=0; @@ -1422,7 +1448,7 @@ /* * Checks for port existence, all ports support SPP MODE * Returns: - * 0 : No parallel port at this adress + * 0 : No parallel port at this address * PARPORT_MODE_PCSPP : SPP port detected * (if the user specified an ioport himself, * this shall always be the case!) @@ -2179,7 +2205,8 @@ /* Via support maintained by Jeff Garzik <jgarzik@mandrakesoft.com> */ -static int __devinit sio_via_686a_probe (struct pci_dev *pdev) +static int __devinit sio_via_686a_probe (struct pci_dev *pdev, int autoirq, + int autodma) { u8 tmp; int dma, irq; @@ -2259,6 +2286,14 @@ if (!have_eppecp) dma = PARPORT_DMA_NONE; + /* Let the user (or defaults) steer us away from interrupts and DMA */ + if (autoirq != PARPORT_IRQ_AUTO) { + irq = PARPORT_IRQ_NONE; + dma = PARPORT_DMA_NONE; + } + if (autodma != PARPORT_DMA_AUTO) + dma = PARPORT_DMA_NONE; + /* finally, do the probe with values obtained */ if (parport_pc_probe_port (port1, port2, irq, dma, NULL)) { printk (KERN_INFO @@ -2284,7 +2319,7 @@ /* each element directly indexed from enum list, above */ static struct parport_pc_superio { - int (*probe) (struct pci_dev *pdev); + int (*probe) (struct pci_dev *pdev, int autoirq, int autodma); } parport_pc_superio_info[] __devinitdata = { { sio_via_686a_probe, }, }; @@ -2541,9 +2576,8 @@ probe: parport_pc_pci_probe, }; -static int __init parport_pc_init_superio (void) +static int __init parport_pc_init_superio (int autoirq, int autodma) { -#ifdef CONFIG_PCI const struct pci_device_id *id; struct pci_dev *pdev; @@ -2552,9 +2586,9 @@ if (id == NULL || id->driver_data >= last_sio) continue; - return parport_pc_superio_info[id->driver_data].probe (pdev); + return parport_pc_superio_info[id->driver_data].probe + (pdev, autoirq, autodma); } -#endif /* CONFIG_PCI */ return 0; /* zero devices found */ } @@ -2575,6 +2609,27 @@ return count; } +#if defined (CONFIG_PNPBIOS) || defined (CONFIG_PNPBIOS_MODULE) + +int init_pnp040x(struct pci_dev *dev) +{ int io,iohi,irq,dma; + + io=dev->resource[0].start; + iohi=dev->resource[1].start; + irq=dev->irq_resource[0].start; + dma=dev->dma_resource[0].start; + + if(dma==0) dma=-1; + + printk(KERN_INFO "PnPBIOS: Parport found %s %s at io=%04x,%04x irq=%d dma=%d\n", + dev->name,dev->slot_name,io,iohi,irq,dma); + if (parport_pc_probe_port(io,iohi,irq,dma,NULL)) + return 1; + return 0; +} + +#endif + /* This function is called by parport_pc_init if the user didn't * specify any ports to probe. Its job is to find some ports. Order * is important here -- we want ISA ports to be registered first, @@ -2588,14 +2643,24 @@ static int __init parport_pc_find_ports (int autoirq, int autodma) { int count = 0, r; + struct pci_dev *dev; #ifdef CONFIG_PARPORT_PC_SUPERIO detect_and_report_winbond (); detect_and_report_smsc (); #endif +#if defined(CONFIG_PNPBIOS) || defined(CONFIG_PNPBIOS_MODULE) + dev=NULL; + while ((dev=pnpbios_find_device("PNP0400",dev))) + count+=init_pnp040x(dev); + dev=NULL; + while ((dev=pnpbios_find_device("PNP0401",dev))) + count+=init_pnp040x(dev); +#endif + /* Onboard SuperIO chipsets that show themselves on the PCI bus. */ - count += parport_pc_init_superio (); + count += parport_pc_init_superio (autoirq, autodma); /* ISA ports and whatever (see asm/parport.h). */ count += parport_pc_find_nonpci_ports (autoirq, autodma); @@ -2630,7 +2695,7 @@ } /* Exported symbols. */ -#ifdef CONFIG_PARPORT_PC_PCMCIA +#ifdef CONFIG_PARPORT_PC_PCMCIA_MODULE /* parport_cs needs this in order to dyncamically get us to find ports. */ EXPORT_SYMBOL (parport_pc_probe_port); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/pci/Makefile linux.ac/drivers/pci/Makefile --- linux.vanilla/drivers/pci/Makefile Fri Dec 29 22:07:22 2000 +++ linux.ac/drivers/pci/Makefile Tue Apr 3 17:54:57 2001 @@ -21,6 +21,7 @@ # obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o +obj-$(CONFIG_ALL_PPC) += setup-bus.o ifndef CONFIG_X86 obj-y += syscall.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/pci/pci.c linux.ac/drivers/pci/pci.c --- linux.vanilla/drivers/pci/pci.c Tue Apr 3 17:32:17 2001 +++ linux.ac/drivers/pci/pci.c Sun Apr 15 22:58:39 2001 @@ -286,12 +286,33 @@ { int err; + pci_set_power_state(dev, 0); if ((err = pcibios_enable_device(dev)) < 0) return err; - pci_set_power_state(dev, 0); return 0; } +/** + * pci_disable_device - Disable PCI device after use + * @dev: PCI device to be disabled + * + * Signal to the system that the PCI device is not in use by the system + * anymore. Currently this only involves disabling PCI busmastering, + * if active. + */ + +void +pci_disable_device(struct pci_dev *dev) +{ + u16 pci_command; + + pci_read_config_word(dev, PCI_COMMAND, &pci_command); + if (pci_command & PCI_COMMAND_MASTER) { + pci_command &= ~PCI_COMMAND_MASTER; + pci_write_config_word(dev, PCI_COMMAND, pci_command); + } +} + int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge) { @@ -1381,6 +1402,7 @@ EXPORT_SYMBOL(pci_devices); EXPORT_SYMBOL(pci_root_buses); EXPORT_SYMBOL(pci_enable_device); +EXPORT_SYMBOL(pci_disable_device); EXPORT_SYMBOL(pci_find_capability); EXPORT_SYMBOL(pci_release_regions); EXPORT_SYMBOL(pci_request_regions); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/pci/pci.ids linux.ac/drivers/pci/pci.ids --- linux.vanilla/drivers/pci/pci.ids Tue Apr 3 17:32:17 2001 +++ linux.ac/drivers/pci/pci.ids Tue Apr 3 17:54:57 2001 @@ -2448,7 +2448,9 @@ 1221 82C092G 119c Information Technology Inst. 119d Bug, Inc. Sapporo Japan -119e Fujitsu Microelectronics Ltd. +119e Fujitsu Microelectronics Europe GMBH + 0001 FireStream 155 + 0003 FireStream 50 119f Bull HN Information Systems 11a0 Convex Computer Corporation 11a1 Hamamatsu Photonics K.K. @@ -2995,13 +2997,14 @@ 8086 5643 ES1371, ES1373 AudioPCI On Motherboard Vancouver 8086 5753 ES1371, ES1373 AudioPCI On Motherboard WS440BX 5000 ES1370 [AudioPCI] - 5880 5880 AudioPCI + 4942 4c4c Creative Sound Blaster AudioPCI128 + 5880 CT5880 [AudioPCI] 1274 2000 Creative Sound Blaster AudioPCI128 1274 5880 Creative Sound Blaster AudioPCI128 - 1462 6880 5880 AudioPCI On Motherboard MS-6188 1.00 - 270f 2001 5880 AudioPCI On Motherboard 6CTR - 270f 2200 5880 AudioPCI On Motherboard 6WTX - 270f 7040 5880 AudioPCI On Motherboard 6ATA4 + 1462 6880 CT5880 AudioPCI On Motherboard MS-6188 1.00 + 270f 2001 CT5880 AudioPCI On Motherboard 6CTR + 270f 2200 CT5880 AudioPCI On Motherboard 6WTX + 270f 7040 CT5880 AudioPCI On Motherboard 6ATA4 1275 Network Appliance Corporation 1276 Switched Network Technologies, Inc. 1277 Comstream diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/pci/quirks.c linux.ac/drivers/pci/quirks.c --- linux.vanilla/drivers/pci/quirks.c Sat Dec 30 19:23:13 2000 +++ linux.ac/drivers/pci/quirks.c Sun Apr 15 22:46:54 2001 @@ -85,6 +85,29 @@ } /* + * VIA Apollo KT133 needs PCI latency patch + * Made according to a windows driver based patch by George E. Breese + * see PCI Latency Adjust on http://www.viahardware.com/download/viatweak.shtm + */ +static void __init quirk_vialatency(struct pci_dev *dev) +{ + u8 r70; + + printk(KERN_INFO "Applying VIA PCI latency patch.\n"); + /* + * In register 0x70, mask off bit 2 (PCI Master read caching) + * and 1 (Delay Transaction) + */ + pci_read_config_byte(dev, 0x70, &r70); + r70 &= 0xf9; + pci_write_config_byte(dev, 0x70, r70); + /* + * Turn off PCI Latency timeout (set to 0 clocks) + */ + pci_write_config_byte(dev, 0x75, 0x80); +} + +/* * VIA Apollo VP3 needs ETBF on BT848/878 */ @@ -261,6 +284,7 @@ { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, quirk_isa_dma_hangs }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, quirk_isa_dma_hangs }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, quirk_isa_dma_hangs }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, quirk_triton }, @@ -275,6 +299,7 @@ { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, quirk_natoma }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_viaetbf }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt82c598_id }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi }, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/pci/setup-res.c linux.ac/drivers/pci/setup-res.c --- linux.vanilla/drivers/pci/setup-res.c Mon Dec 11 21:46:26 2000 +++ linux.ac/drivers/pci/setup-res.c Tue Apr 10 18:15:51 2001 @@ -163,6 +163,10 @@ size = ln->res->end - ln->res->start; if (r_size > size) { tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) { + printk("pdev_sort_resources(): kmalloc() failed!\n"); + continue; + } tmp->next = ln; tmp->res = r; tmp->dev = dev; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/pcmcia/bulkmem.c linux.ac/drivers/pcmcia/bulkmem.c --- linux.vanilla/drivers/pcmcia/bulkmem.c Tue Apr 3 17:32:17 2001 +++ linux.ac/drivers/pcmcia/bulkmem.c Tue Apr 3 17:54:57 2001 @@ -211,7 +211,7 @@ retry_erase((erase_busy_t *)arg, MTD_REQ_TIMEOUT); } -static void setup_erase_request(client_handle_t handle, eraseq_entry_t *erase) +static int setup_erase_request(client_handle_t handle, eraseq_entry_t *erase) { erase_busy_t *busy; region_info_t *info; @@ -229,6 +229,8 @@ else { erase->State = 1; busy = kmalloc(sizeof(erase_busy_t), GFP_KERNEL); + if (!busy) + return CS_GENERAL_FAILURE; busy->erase = erase; busy->client = handle; init_timer(&busy->timeout); @@ -238,6 +240,7 @@ retry_erase(busy, 0); } } + return CS_SUCCESS; } /* setup_erase_request */ /*====================================================================== @@ -322,7 +325,7 @@ ======================================================================*/ -static void setup_regions(client_handle_t handle, int attr, +static int setup_regions(client_handle_t handle, int attr, memory_handle_t *list) { int i, code, has_jedec, has_geo; @@ -337,7 +340,7 @@ code = (attr) ? CISTPL_DEVICE_A : CISTPL_DEVICE; if (read_tuple(handle, code, &device) != CS_SUCCESS) - return; + return CS_GENERAL_FAILURE; code = (attr) ? CISTPL_JEDEC_A : CISTPL_JEDEC_C; has_jedec = (read_tuple(handle, code, &jedec) == CS_SUCCESS); if (has_jedec && (device.ndev != jedec.nid)) { @@ -360,6 +363,8 @@ if ((device.dev[i].type != CISTPL_DTYPE_NULL) && (device.dev[i].size != 0)) { r = kmalloc(sizeof(*r), GFP_KERNEL); + if (!r) + return CS_GENERAL_FAILURE; r->region_magic = REGION_MAGIC; r->state = 0; r->dev_info[0] = '\0'; @@ -384,6 +389,7 @@ } offset += device.dev[i].size; } + return CS_SUCCESS; } /* setup_regions */ /*====================================================================== @@ -417,8 +423,10 @@ if ((handle->Attributes & INFO_MASTER_CLIENT) && (!(s->state & SOCKET_REGION_INFO))) { - setup_regions(handle, 0, &s->c_region); - setup_regions(handle, 1, &s->a_region); + if (setup_regions(handle, 0, &s->c_region) != CS_SUCCESS) + return CS_GENERAL_FAILURE; + if (setup_regions(handle, 1, &s->a_region) != CS_SUCCESS) + return CS_GENERAL_FAILURE; s->state |= SOCKET_REGION_INFO; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/pcmcia/cs.c linux.ac/drivers/pcmcia/cs.c --- linux.vanilla/drivers/pcmcia/cs.c Sat Feb 17 00:02:36 2001 +++ linux.ac/drivers/pcmcia/cs.c Tue Apr 3 17:54:57 2001 @@ -1458,7 +1458,7 @@ s->functions = 1; s->config = kmalloc(sizeof(config_t) * s->functions, GFP_KERNEL); - if (!s->config) + if (!s->config) return CS_OUT_OF_RESOURCE; memset(s->config, 0, sizeof(config_t) * s->functions); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/pcmcia/ds.c linux.ac/drivers/pcmcia/ds.c --- linux.vanilla/drivers/pcmcia/ds.c Sat Feb 17 00:02:36 2001 +++ linux.ac/drivers/pcmcia/ds.c Tue Apr 3 17:54:57 2001 @@ -383,7 +383,8 @@ break; if (driver == NULL) { driver = kmalloc(sizeof(driver_info_t), GFP_KERNEL); - if (!driver) return -ENOMEM; + if (!driver) + return -ENOMEM; strncpy(driver->dev_info, bind_info->dev_info, DEV_NAME_LEN); driver->use_count = 0; driver->next = root_driver; @@ -415,7 +416,10 @@ driver->use_count++; b = kmalloc(sizeof(socket_bind_t), GFP_KERNEL); if (!b) - return -ENOMEM; + { + driver->use_count--; + return -ENOMEM; + } b->driver = driver; b->function = bind_info->function; b->instance = NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/pcmcia/hd64465_ss.c linux.ac/drivers/pcmcia/hd64465_ss.c --- linux.vanilla/drivers/pcmcia/hd64465_ss.c Sat Feb 17 00:02:36 2001 +++ linux.ac/drivers/pcmcia/hd64465_ss.c Sat Apr 14 01:28:51 2001 @@ -30,7 +30,6 @@ #include <linux/types.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/config.h> #include <linux/string.h> #include <linux/kernel.h> #include <linux/ioport.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/pcmcia/i82365.c linux.ac/drivers/pcmcia/i82365.c --- linux.vanilla/drivers/pcmcia/i82365.c Tue Apr 3 17:32:17 2001 +++ linux.ac/drivers/pcmcia/i82365.c Tue Apr 3 17:54:57 2001 @@ -257,23 +257,31 @@ /*====================================================================*/ +static spinlock_t bus_lock = SPIN_LOCK_UNLOCKED; + static u_char i365_get(u_short sock, u_short reg) { + unsigned long flags; + spin_lock_irqsave(&bus_lock,flags); { ioaddr_t port = socket[sock].ioaddr; u_char val; reg = I365_REG(socket[sock].psock, reg); outb(reg, port); val = inb(port+1); + spin_unlock_irqrestore(&bus_lock,flags); return val; } } static void i365_set(u_short sock, u_short reg, u_char data) { + unsigned long flags; + spin_lock_irqsave(&bus_lock,flags); { ioaddr_t port = socket[sock].ioaddr; u_char val = I365_REG(socket[sock].psock, reg); outb(val, port); outb(data, port+1); + spin_unlock_irqrestore(&bus_lock,flags); } } @@ -872,6 +880,13 @@ events = pending_events[i]; pending_events[i] = 0; spin_unlock_irq(&pending_event_lock); + /* + SS_DETECT events need a small delay here. The reason for this is that + the "is there a card" electronics need time to see the card after the + "we have a card coming in" electronics have seen it. + */ + if (events & SS_DETECT) + mdelay(2); if (socket[i].handler) socket[i].handler(socket[i].info, events); } @@ -881,6 +896,8 @@ routine: pcic_bh }; +static unsigned long last_detect_jiffies; + static void pcic_interrupt(int irq, void *dev, struct pt_regs *regs) { @@ -906,6 +923,20 @@ continue; } events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0; + + + /* Several sockets will send multiple "new card detected" + events in rapid succession. However, the rest of the pcmcia expects + only one such event. We just ignore these events by having a + timeout */ + + if (events) { + if ((jiffies - last_detect_jiffies)<(HZ/20)) + events = 0; + last_detect_jiffies = jiffies; + + } + if (i365_get(i, I365_INTCTL) & I365_PC_IOCARD) events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0; else { @@ -970,6 +1001,7 @@ status = i365_get(sock, I365_STATUS); *value = ((status & I365_CS_DETECT) == I365_CS_DETECT) ? SS_DETECT : 0; + if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) *value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG; else { @@ -1247,7 +1279,7 @@ i = i365_get_pair(sock, base+I365_W_START); mem->flags |= (i & I365_MEM_16BIT) ? MAP_16BIT : 0; mem->flags |= (i & I365_MEM_0WS) ? MAP_0WS : 0; - mem->sys_start += ((u_long)(i & 0x0fff) << 12); + mem->sys_start = ((u_long)(i & 0x0fff) << 12); i = i365_get_pair(sock, base+I365_W_STOP); mem->speed = (i & I365_MEM_WS0) ? 1 : 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/pcmcia/pci_socket.c linux.ac/drivers/pcmcia/pci_socket.c --- linux.vanilla/drivers/pcmcia/pci_socket.c Fri Nov 17 00:38:16 2000 +++ linux.ac/drivers/pcmcia/pci_socket.c Tue Apr 10 18:15:58 2001 @@ -172,13 +172,20 @@ static int __devinit add_pci_socket(int nr, struct pci_dev *dev, struct pci_socket_ops *ops) { pci_socket_t *socket = nr + pci_socket_array; - + int err; + memset(socket, 0, sizeof(*socket)); socket->dev = dev; socket->op = ops; dev->driver_data = socket; spin_lock_init(&socket->event_lock); - return socket->op->open(socket); + err = socket->op->open(socket); + if(err) + { + socket->dev = NULL; + dev->driver_data = NULL; + } + return err; } void cardbus_register(pci_socket_t *socket) @@ -195,8 +202,7 @@ for (s = 0; s < MAX_SOCKETS; s++) { if (pci_socket_array [s].dev == 0) { - add_pci_socket (s, dev, ¥ta_operations); - return 0; + return add_pci_socket (s, dev, ¥ta_operations); } } return -ENODEV; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/pcmcia/rsrc_mgr.c linux.ac/drivers/pcmcia/rsrc_mgr.c --- linux.vanilla/drivers/pcmcia/rsrc_mgr.c Tue Apr 3 17:32:17 2001 +++ linux.ac/drivers/pcmcia/rsrc_mgr.c Tue Apr 3 17:54:57 2001 @@ -246,7 +246,7 @@ static int do_mem_probe(u_long base, u_long num, int (*is_valid)(u_long), int (*do_cksum)(u_long)) { - u_long i, j, bad, fail, step; + u_long i, j=0, bad, fail, step; printk(KERN_INFO "cs: memory probe 0x%06lx-0x%06lx:", base, base+num-1); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/pcmcia/yenta.c linux.ac/drivers/pcmcia/yenta.c --- linux.vanilla/drivers/pcmcia/yenta.c Fri Nov 17 02:25:16 2000 +++ linux.ac/drivers/pcmcia/yenta.c Tue Apr 10 18:15:58 2001 @@ -755,6 +755,9 @@ */ static void yenta_close(pci_socket_t *sock) { + /* Disable all events so we don't die in an IRQ storm */ + cb_writel(sock, CB_SOCKET_MASK, 0x0); + if (sock->cb_irq) free_irq(sock->cb_irq, sock); else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/pnp/Config.in linux.ac/drivers/pnp/Config.in --- linux.vanilla/drivers/pnp/Config.in Mon Oct 11 18:13:24 1999 +++ linux.ac/drivers/pnp/Config.in Tue Apr 17 16:09:31 2001 @@ -8,4 +8,8 @@ dep_tristate ' ISA Plug and Play support' CONFIG_ISAPNP $CONFIG_PNP +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_bool ' PNPBIOS support (EXPERIMENTAL)' CONFIG_PNPBIOS $CONFIG_PNP +fi + endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/pnp/Makefile linux.ac/drivers/pnp/Makefile --- linux.vanilla/drivers/pnp/Makefile Tue Apr 3 17:32:17 2001 +++ linux.ac/drivers/pnp/Makefile Tue Apr 17 16:01:39 2001 @@ -8,17 +8,24 @@ # Note 2! The CFLAGS definitions are now inherited from the # parent makes.. -O_TARGET := pnp.o +O_TARGET := pnp.o -export-objs := isapnp.o -list-multi := isa-pnp.o +export-objs := isapnp.o pnp_bios.o +multi-objs := isa-pnp.o pnpbios.o proc-$(CONFIG_PROC_FS) = isapnp_proc.o isa-pnp-objs := isapnp.o quirks.o $(proc-y) +procpnp-$(CONFIG_PROC_FS) = pnp_proc.o +pnpbios-objs := pnp_bios.o $(procpnp-y) + obj-$(CONFIG_ISAPNP) += isa-pnp.o +obj-$(CONFIG_PNPBIOS) += pnpbios.o include $(TOPDIR)/Rules.make -isa-pnp.o: $(isa-pnp-objs) - $(LD) $(LD_RFLAG) -r -o $@ $(isa-pnp-objs) +isa-pnp.o: $(isa-pnp-objs) + $(LD) $(LD_RFLAG) -r -o $@ $(isa-pnp-objs) + +pnpbios.o: $(pnpbios-objs) + $(LD) $(LD_RFLAG) -r -o $@ $(pnpbios-objs) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/pnp/isapnp.c linux.ac/drivers/pnp/isapnp.c --- linux.vanilla/drivers/pnp/isapnp.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/pnp/isapnp.c Tue Apr 3 17:54:57 2001 @@ -55,7 +55,7 @@ struct resource *isapnp_rdp_res; int isapnp_disable; /* Disable ISA PnP */ -int isapnp_rdp; /* Read Data Port */ +int isapnp_rdp; /* Read Data Port */ int isapnp_reset = 1; /* reset all PnP cards (deactivate) */ int isapnp_skip_pci_scan; /* skip PCI resource scanning */ int isapnp_verbose = 1; /* verbose mode */ @@ -993,10 +993,15 @@ header[4], header[5], header[6], header[7], header[8]); printk("checksum = 0x%x\n", checksum); #endif - if (checksum == 0x00 || checksum != header[8]) /* not valid CSN */ + /* Don't be strict on the checksum, here ! + e.g. 'SCM SwapBox Plug and Play' has header[8]==0 (should be: b7)*/ + if (header[8] == 0) + ; + else if (checksum == 0x00 || checksum != header[8]) /* not valid CSN */ continue; if ((card = isapnp_alloc(sizeof(struct pci_bus))) == NULL) continue; + card->number = csn; card->vendor = (header[1] << 8) | header[0]; card->device = (header[3] << 8) | header[2]; @@ -2197,7 +2202,7 @@ * so let the user know where. */ - printk("isapnp: Scanning for Pnp cards...\n"); + printk("isapnp: Scanning for PnP cards...\n"); if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff) { isapnp_rdp |= 3; isapnp_rdp_res=request_region(isapnp_rdp, 1, "isapnp read"); @@ -2258,5 +2263,86 @@ if (isapnp_detected) isapnp_free_all_resources(); } + +#else + +/* format is: noisapnp */ + +static int __init isapnp_setup_disable(char *str) +{ + isapnp_disable = 1; + return 1; +} + +__setup("noisapnp", isapnp_setup_disable); + +/* format is: isapnp=rdp,reset,skip_pci_scan,verbose */ + +static int __init isapnp_setup_isapnp(char *str) +{ + (void)((get_option(&str,&isapnp_rdp) == 2) && + (get_option(&str,&isapnp_reset) == 2) && + (get_option(&str,&isapnp_skip_pci_scan) == 2) && + (get_option(&str,&isapnp_verbose) == 2)); + return 1; +} + +__setup("isapnp=", isapnp_setup_isapnp); + +/* format is: isapnp_reserve_irq=irq1[,irq2] .... */ + +static int __init isapnp_setup_reserve_irq(char *str) +{ + int i; + + for (i = 0; i < 16; i++) + if (get_option(&str,&isapnp_reserve_irq[i]) != 2) + break; + return 1; +} + +__setup("isapnp_reserve_irq=", isapnp_setup_reserve_irq); + +/* format is: isapnp_reserve_dma=dma1[,dma2] .... */ + +static int __init isapnp_setup_reserve_dma(char *str) +{ + int i; + + for (i = 0; i < 8; i++) + if (get_option(&str,&isapnp_reserve_dma[i]) != 2) + break; + return 1; +} + +__setup("isapnp_reserve_dma=", isapnp_setup_reserve_dma); + +/* format is: isapnp_reserve_io=io1,size1[,io2,size2] .... */ + +static int __init isapnp_setup_reserve_io(char *str) +{ + int i; + + for (i = 0; i < 16; i++) + if (get_option(&str,&isapnp_reserve_io[i]) != 2) + break; + return 1; +} + +__setup("isapnp_reserve_io=", isapnp_setup_reserve_io); + +/* format is: isapnp_reserve_mem=mem1,size1[,mem2,size2] .... */ + +static int __init isapnp_setup_reserve_mem(char *str) +{ + int i; + + for (i = 0; i < 16; i++) + if (get_option(&str,&isapnp_reserve_mem[i]) != 2) + break; + return 1; +} + +__setup("isapnp_reserve_mem=", isapnp_setup_reserve_mem); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/pnp/pnp_bios.c linux.ac/drivers/pnp/pnp_bios.c --- linux.vanilla/drivers/pnp/pnp_bios.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/pnp/pnp_bios.c Tue Apr 17 16:14:44 2001 @@ -0,0 +1,646 @@ +/* + * PnP bios services + * + * Originally (C) 1998 Christian Schmidt (chr.schmidt@tu-bs.de) + * Modifications (c) 1998 Tom Lees <tom@lpsg.demon.co.uk> + * Minor reorganizations by David Hinds <dahinds@users.sourceforge.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, 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 + * + * Reference: + * Compaq Computer Corporation, Phoenix Technologies Ltd., Intel + * Corporation. + * Plug and Play BIOS Specification, Version 1.0A, May 5, 1994 + * Plug and Play BIOS Clarification Paper, October 6, 1994 + * + */ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/module.h> +#include <linux/linkage.h> +#include <linux/kernel.h> +#include <linux/pnp_bios.h> +#include <asm/page.h> +#include <asm/system.h> +#include <linux/mm.h> +#include <linux/smp.h> +#include <asm/desc.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/pci.h> + +/* PnP bios signature: "$PnP" */ +#define PNP_SIGNATURE (('$' << 0) + ('P' << 8) + ('n' << 16) + ('P' << 24)) + +void pnp_proc_init(void); + +/* + * This is the standard structure used to identify the entry point + * to the Plug and Play bios + */ +#pragma pack(1) +union pnpbios { + struct { + u32 signature; /* "$PnP" */ + u8 version; /* in BCD */ + u8 length; /* length in bytes, currently 21h */ + u16 control; /* system capabilities */ + u8 checksum; /* all bytes must add up to 0 */ + + u32 eventflag; /* phys. address of the event flag */ + u16 rmoffset; /* real mode entry point */ + u16 rmcseg; + u16 pm16offset; /* 16 bit protected mode entry */ + u32 pm16cseg; + u32 deviceID; /* EISA encoded system ID or 0 */ + u16 rmdseg; /* real mode data segment */ + u32 pm16dseg; /* 16 bit pm data segment base */ + } fields; + char chars[0x21]; /* To calculate the checksum */ +}; +#pragma pack() + +/* + * Local Variables + */ +static struct { + u32 offset; + u16 segment; +} pnp_bios_callpoint; + +static union pnpbios * pnp_bios_inst_struc = NULL; + +/* The PnP entries in the GDT */ +#define PNP_GDT 0x0060 +#define PNP_CS32 (PNP_GDT+0x00) /* segment for calling fn */ +#define PNP_CS16 (PNP_GDT+0x08) /* code segment for bios */ +#define PNP_DS (PNP_GDT+0x10) /* data segment for bios */ +#define PNP_TS1 (PNP_GDT+0x18) /* transfer data segment */ +#define PNP_TS2 (PNP_GDT+0x20) /* another data segment */ + +static struct desc_struct pnp_gdt[] = { + { 0, 0x00c09a00 }, /* 32-bit code */ + { 0, 0x00809a00 }, /* 16-bit code */ + { 0, 0x00809200 }, /* 16-bit data */ + { 0, 0x00809200 }, /* 16-bit data */ + { 0, 0x00809200 } /* 16-bit data */ +}; + +static void set_pnp_gdt(void) +{ + memcpy(saved_gdt, &gdt[PNP_GDT >> 3], sizeof(saved_gdt)); + memcpy(&gdt[PNP_GDT >> 3], pnp_gdt, sizeof(pnp_gdt)); +} + +/* + * These are some opcodes for a "static asmlinkage" + * As this code is *not* executed inside the linux kernel segment, but in a + * alias at offset 0, we need a far return that can not be compiled by + * default (please, prove me wrong! this is *really* ugly!) + * This is the only way to get the bios to return into the kernel code, + * because the bios code runs in 16 bit protected mode and therefore can only + * return to the caller if the call is within the first 64kB, and the linux + * kernel begins at offset 1MB... + */ +static u8 pnp_bios_callfunc[] = +{ + 0x52, /* push edx */ + 0x51, /* push ecx */ + 0x53, /* push ebx */ + 0x50, /* push eax */ + 0x66, 0x9a, 0, 0, /* call far pnp_cs16:0, offset */ + (PNP_CS16) & 0xff, (PNP_CS16) >> 8, /* becomes fixed up later */ + 0x83, 0xc4, 0x10, /* add esp, 16 */ + 0xcb}; /* retf */ + +#define Q_SET_SEL(selname, address, size) \ +set_base (gdt [(selname) >> 3], __va((u32)(address))); \ +set_limit (gdt [(selname) >> 3], size) + +#define Q2_SET_SEL(selname, address, size) \ +set_base (gdt [(selname) >> 3], (u32)(address)); \ +set_limit (gdt [(selname) >> 3], size) + +/* + * Callable Functions + */ +#define PNP_GET_NUM_SYS_DEV_NODES 0x00 +#define PNP_GET_SYS_DEV_NODE 0x01 +#define PNP_SET_SYS_DEV_NODE 0x02 +#define PNP_GET_EVENT 0x03 +#define PNP_SEND_MESSAGE 0x04 +#define PNP_GET_DOCKING_STATION_INFORMATION 0x05 +#define PNP_SET_STATIC_ALLOCED_RES_INFO 0x09 +#define PNP_GET_STATIC_ALLOCED_RES_INFO 0x0a +#define PNP_GET_APM_ID_TABLE 0x0b +#define PNP_GET_PNP_ISA_CONFIG_STRUC 0x40 +#define PNP_GET_ESCD_INFO 0x41 +#define PNP_READ_ESCD 0x42 +#define PNP_WRITE_ESCD 0x43 + +/* + * Call pnp bios with function 0x00, "get number of system device nodes" + */ + +int pnp_bios_dev_node_info(struct pnp_dev_node_info *data) +{ + u16 status; + if (!pnp_bios_present ()) + return PNP_FUNCTION_NOT_SUPPORTED; + Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_dev_node_info)); + __asm__ __volatile__ + ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t" + :"=a"(status) + :"a"(PNP_GET_NUM_SYS_DEV_NODES), + "b"((2 << 16) | PNP_TS1), + "c"((PNP_DS << 16) | PNP_TS1) + :"memory"); + data->no_nodes &= 0xff; + return status; +} + +/* + * Call pnp bios with function 0x01, "get system device node" + * Input: *nodenum=desired node, + * static=1: config (dynamic) config, else boot (static) config, + * Output: *nodenum=next node or 0xff if no more nodes + */ + +int pnp_bios_get_dev_node(u8 *nodenum, char config, struct pnp_bios_node *data) +{ + u16 status; + if (!pnp_bios_present ()) + return PNP_FUNCTION_NOT_SUPPORTED; + Q2_SET_SEL(PNP_TS1, nodenum, sizeof(char)); + Q2_SET_SEL(PNP_TS2, data, 64 * 1024); + __asm__ __volatile__ + ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t" + :"=a"(status) + :"a"(PNP_GET_SYS_DEV_NODE), + "b"(PNP_TS1), + "c"(((config ? 1 : 2) <<16) | PNP_TS2), + "d"(PNP_DS) + :"memory"); + return status; +} + +/* + * Call pnp bios with function 0x02, "set system device node" + * Input: nodenum=desired node, + * static=1: config (dynamic) config, else boot (static) config, + */ + +static int pnp_bios_set_dev_node(u8 nodenum, char config, struct pnp_bios_node *data) +{ + u16 status; + if (!pnp_bios_present ()) + return PNP_FUNCTION_NOT_SUPPORTED; + Q2_SET_SEL(PNP_TS1, data, /* *((u16 *) data)*/ 65536); + __asm__ __volatile__ + ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t" + :"=a"(status) + :"a"(((u32) nodenum << 16) | PNP_SET_SYS_DEV_NODE), + "b"(PNP_TS1 << 16), + "c"((PNP_DS << 16) | (config ? 1 : 2)) + :"memory"); + return status; +} + +/* + * Call pnp bios with function 0x03, "get event" + */ +#if needed + +static int pnp_bios_get_event(u16 *event) +{ + u16 status; + if (!pnp_bios_present ()) + return PNP_FUNCTION_NOT_SUPPORTED; + Q2_SET_SEL(PNP_TS1, event, sizeof(u16)); + __asm__ __volatile__ + ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t" + :"=a"(status) + :"a"(PNP_GET_EVENT), + "b"((PNP_DS << 16) | PNP_TS1) + :"memory"); + return status; +} +#endif + +/* + * Call pnp bios with function 0x04, "send message" + */ +#if needed +static int pnp_bios_send_message(u16 message) +{ + u16 status; + if (!pnp_bios_present ()) + return PNP_FUNCTION_NOT_SUPPORTED; + __asm__ __volatile__ + ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t" + :"=a"(status) + :"a"(((u32) message << 16) | PNP_SEND_MESSAGE), + "b"(PNP_DS) + :"memory"); + return status; +} +#endif + +/* + * Call pnp bios with function 0x05, "get docking station information" + */ +#if needed +static int pnp_bios_dock_station_info(struct pnp_docking_station_info *data) +{ + u16 status; + if (!pnp_bios_present ()) + return PNP_FUNCTION_NOT_SUPPORTED; + Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_docking_station_info)); + __asm__ __volatile__ + ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t" + :"=a"(status) + :"a"(PNP_GET_DOCKING_STATION_INFORMATION), + "b"((PNP_TS1 << 16) | PNP_DS) + :"memory"); + return status; +} +#endif + +/* + * Call pnp bios with function 0x09, "set statically allocated resource + * information" + */ +#if needed +static int pnp_bios_set_stat_res(char *info) +{ + u16 status; + if (!pnp_bios_present ()) + return PNP_FUNCTION_NOT_SUPPORTED; + Q2_SET_SEL(PNP_TS1, info, *((u16 *) info)); + __asm__ __volatile__ + ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t" + :"=a"(status) + :"a"(PNP_SET_STATIC_ALLOCED_RES_INFO), + "b"((PNP_TS1 << 16) | PNP_DS) + :"memory"); + return status; +} +#endif + +/* + * Call pnp bios with function 0x0a, "get statically allocated resource + * information" + */ +#if needed +static int pnp_bios_get_stat_res(char *info) +{ + u16 status; + if (!pnp_bios_present ()) + return PNP_FUNCTION_NOT_SUPPORTED; + Q2_SET_SEL(PNP_TS1, info, 64 * 1024); + __asm__ __volatile__ + ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t" + :"=a"(status) + :"a"(PNP_GET_STATIC_ALLOCED_RES_INFO), + "b"((PNP_TS1 << 16) | PNP_DS) + :"memory"); + return status; +} +#endif + +/* + * Call pnp bios with function 0x0b, "get APM id table" + */ +#if needed +static int pnp_bios_apm_id_table(char *table, u16 *size) +{ + u16 status; + if (!pnp_bios_present ()) + return PNP_FUNCTION_NOT_SUPPORTED; + Q2_SET_SEL(PNP_TS1, table, *size); + Q2_SET_SEL(PNP_TS2, size, sizeof(u16)); + __asm__ __volatile__ + ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t" + :"=a"(status) + :"a"(PNP_GET_APM_ID_TABLE), + "b"(PNP_TS2), + "c"((PNP_DS << 16) | PNP_TS1) + :"memory"); + return status; +} +#endif + +/* + * Call pnp bios with function 0x40, "get isa pnp configuration structure" + */ +#if needed +static int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data) +{ + u16 status; + if (!pnp_bios_present ()) + return PNP_FUNCTION_NOT_SUPPORTED; + Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_isa_config_struc)); + __asm__ __volatile__ + ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t" + :"=a"(status) + :"a"(PNP_GET_PNP_ISA_CONFIG_STRUC), + "b"((PNP_DS << 16) | PNP_TS1) + :"memory"); + return status; +} +#endif + +/* + * Call pnp bios with function 0x41, "get ESCD info" + */ +#if needed +static int pnp_bios_escd_info(struct escd_info_struc *data) +{ + u16 status; + if (!pnp_bios_present ()) + return ESCD_FUNCTION_NOT_SUPPORTED; + Q2_SET_SEL(PNP_TS1, data, sizeof(struct escd_info_struc)); + __asm__ __volatile__ + ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t" + :"=a"(status) + :"a"(PNP_GET_ESCD_INFO), + "b"((2 << 16) | PNP_TS1), + "c"((4 << 16) | PNP_TS1), + "d"((PNP_DS << 16) | PNP_TS1) + :"memory"); + return status; +} +#endif + +/* + * Call pnp bios function 0x42, "read ESCD" + * nvram_base is determined by calling escd_info + */ +#if needed +static int pnp_bios_read_escd(char *data, u32 nvram_base) +{ + u16 status; + if (!pnp_bios_present ()) + return ESCD_FUNCTION_NOT_SUPPORTED; + Q2_SET_SEL(PNP_TS1, data, 64 * 1024); + set_base(gdt[PNP_TS2 >> 3], nvram_base); + set_limit(gdt[PNP_TS2 >> 3], 64 * 1024); + __asm__ __volatile__ + ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t" + :"=a"(status) + :"a"(PNP_READ_ESCD), + "b"((PNP_TS2 << 16) | PNP_TS1), + "c"(PNP_DS) + :"memory"); + return status; +} +#endif + +/* + * Call pnp bios function 0x43, "write ESCD" + */ +#if needed +static int pnp_bios_write_escd(char *data, u32 nvram_base) +{ + u16 status; + if (!pnp_bios_present ()) + return ESCD_FUNCTION_NOT_SUPPORTED; + Q2_SET_SEL(PNP_TS1, data, 64 * 1024); + set_base(gdt[PNP_TS2 >> 3], nvram_base); + set_limit(gdt[PNP_TS2 >> 3], 64 * 1024); + __asm__ __volatile__ + ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t" + :"=a"(status) + :"a"(PNP_WRITE_ESCD), + "b"((PNP_TS2 << 16) | PNP_TS1), + "c"(PNP_DS) + :"memory"); + return status; +} +#endif + +int pnp_bios_present(void) +{ + return (pnp_bios_inst_struc != NULL); +} + +/* + * Searches the defined area (0xf0000-0xffff0) for a valid PnP BIOS + * structure and, if found one, sets up the selectors and entry points + */ + +void pnp_bios_init(void) +{ + union pnpbios *check; + u8 sum; + int i, length; + + for (check = (union pnpbios *) __va(0xf0000); + check < (union pnpbios *) __va(0xffff0); + ((void *) (check)) += 16) { + if (check->fields.signature != PNP_SIGNATURE) + continue; + length = check->fields.length; + if (!length) + continue; + for (sum = 0, i = 0; i < length; i++) + sum += check->chars[i]; + if (sum) + continue; + if (check->fields.version < 0x10) { + printk(KERN_WARNING "PnP: unsupported version %d.%d", + check->fields.version >> 4, + check->fields.version & 15); + continue; + } + printk(KERN_INFO "PnP: PNP BIOS installation structure at 0x%p\n", + check); + printk(KERN_INFO "PnP: PNP BIOS version %d.%d, entry at %x:%x, dseg at %x\n", + check->fields.version >> 4, check->fields.version & 15, + check->fields.pm16cseg, check->fields.pm16offset, + check->fields.pm16dseg); + Q2_SET_SEL(PNP_CS32, &pnp_bios_callfunc, + sizeof(pnp_bios_callfunc)); + Q_SET_SEL(PNP_CS16, check->fields.pm16cseg, 64 * 1024); + Q_SET_SEL(PNP_DS, check->fields.pm16dseg, 64 * 1024); + set_pnp_gdt(); + pnp_bios_callfunc[6] = check->fields.pm16offset & 0xff; + pnp_bios_callfunc[7] = check->fields.pm16offset >> 8; + pnp_bios_callpoint.offset = 0; + pnp_bios_callpoint.segment = PNP_CS32; + pnp_bios_inst_struc = check; + break; + } + pnp_proc_init(); +} + +#ifdef MODULE + +int init_module(void) +{ + pnp_bios_init(); + return(0); +} + +#endif + +EXPORT_SYMBOL(pnp_bios_get_dev_node); +EXPORT_SYMBOL(pnp_bios_present); +EXPORT_SYMBOL(pnp_bios_dev_node_info); + +EXPORT_SYMBOL(pnpbios_find_device); + +/* parse PNPBIOS "Allocated Resources Block" and fill IO,IRQ,DMA into pci_dev */ +static void pnpbios_rawdata_2_pci_dev(struct pnp_bios_node *node, struct pci_dev *pci_dev) +{ + unsigned char *p = node->data, *lastp=NULL; + int mask,i,io,irq=0,len,dma=-1; + + while ( (char *)p < ((char *)node->data + node->size )) { + if(p==lastp) break; + + if( p[0] & 0x80 ) {// large item + lastp = p+3; + p = p + p[1] + p[2]*256 + 3; + continue; + } + if ((p[0]>>3) == 0x0f) // end tag + break; + switch (p[0]>>3) { + case 0x04: // irq + mask= p[1] + p[2]*256; + for (i=0;i<16;i++, mask=mask>>1) + if(mask &0x01) irq=i; + i=0; + while(pci_dev->irq_resource[i].start && i<DEVICE_COUNT_IRQ) + i++; + if(i<DEVICE_COUNT_IRQ) + pci_dev->irq_resource[i].start=irq; + break; + case 0x05: // dma + mask = p[1]; + for (i=0;i<8;i++, mask = mask>>1) + if(mask&0x01) dma=i; + i=0; + while(pci_dev->dma_resource[i].start && i<DEVICE_COUNT_DMA) + i++; + if(i<DEVICE_COUNT_DMA) + pci_dev->dma_resource[i].start=dma; + + break; + case 0x08: // io + io= p[2] + p[3] *256; + len= p[6] + p[7] *256; + i=0; + while(pci_dev->resource[i].start && i<DEVICE_COUNT_RESOURCE) + i++; + if(i<DEVICE_COUNT_RESOURCE) { + pci_dev->resource[i].start=io; + pci_dev->resource[i].end=io+len; + pci_dev->resource[i].flags=IORESOURCE_IO; + } + + break; + } + lastp=p+1; + p = p + (p[0] & 0x07) + 1; + + } +} + +static int ascii_to_hex(char a) +{ + if(a>='0' && a<='9') + return a-0x30; + if(a>= 'A' && a <= 'F') + return a-0x40 + 9; + return 0; +} + +/* Compress 7char EISA ID to 32bit, e.g. "PNP0401" -> 0x0104d041 */ +static int pnpid_to_pnpid32(char *pnpid) +{ + int i,letter1,letter2,letter3,hex[4]; + + letter1=(pnpid[0]-0x40) & 0x1f; + letter2=(pnpid[1]-0x40) & 0x1f; + letter3=(pnpid[2]-0x40) & 0x1f; + + for(i=0;i<4;i++) + hex[i]=ascii_to_hex(pnpid[i+3]); + + return ( letter1<<2 | (letter2&0x18)>>3 | + ((letter2 & 0x07) << 5 | letter3) << 8 | + ((hex[0]<<4 | hex[1]) << 16 ) | + ((hex[2]<<4 | hex[3]) << 24 )); +} + +/* + * The public interface to PnP BIOS enumeration + */ + +struct pci_dev *pnpbios_find_device(char *pnpid, struct pci_dev *prev) +{ + struct pnp_bios_node *node; + struct pnp_dev_node_info node_info; + struct pci_dev *dev; + int pnpid32; + int num; + + + if (!pnp_bios_present ()) + return NULL; + + if (pnp_bios_dev_node_info(&node_info) != 0) + return NULL; + + + node = kmalloc(node_info.max_node_size, GFP_KERNEL); + if (!node) + return NULL; + + + dev = kmalloc(sizeof (struct pci_dev), GFP_KERNEL); + if (!dev) { + kfree(node); + return NULL; + } + memset(dev,0, sizeof (struct pci_dev)); + + pnpid32=pnpid_to_pnpid32(pnpid); + + + if(prev==NULL) + num=0; /* Start from beginning */ + else + num=prev->devfn; /* Encode node number here */ + + for (; num != 0xff; ) { + pnp_bios_get_dev_node((u8 *)&num, (char )0 , node); + + if(node->eisa_id == pnpid32) { + pnpbios_rawdata_2_pci_dev(node,dev); + dev->devfn=num; + memcpy(dev->name,"PNPBIOS",8); + memcpy(dev->slot_name,pnpid,7); + kfree(node); + return dev; + } + } + kfree(dev); + kfree(node); + return NULL; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/pnp/pnp_proc.c linux.ac/drivers/pnp/pnp_proc.c --- linux.vanilla/drivers/pnp/pnp_proc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/pnp/pnp_proc.c Tue Apr 17 16:01:39 2001 @@ -0,0 +1,142 @@ +/* + * pnp_proc.c: /proc/bus/pnp interface for Plug and Play devices + * + * Written by David Hinds, dahinds@users.sourceforge.net + */ + +//#include <pcmcia/config.h> +#define __NO_VERSION__ +//#include <pcmcia/k_compat.h> + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/malloc.h> +#include <linux/types.h> +#include <linux/proc_fs.h> +#include <linux/pnp_bios.h> + +static struct proc_dir_entry *proc_pnp = NULL; +static struct proc_dir_entry *proc_pnp_boot = NULL; +static struct pnp_dev_node_info node_info; + +static int proc_read_devices(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + struct pnp_bios_node *node; + u8 num; + char *p = buf; + + if (pos != 0) { + *eof = 1; + return 0; + } + node = kmalloc(node_info.max_node_size, GFP_KERNEL); + if (!node) return -ENOMEM; + for (num = 0; num != 0xff; ) { + pnp_bios_get_dev_node(&num, 0, node); + p += sprintf(p, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n", + node->handle, node->eisa_id, + node->type_code[0], node->type_code[1], + node->type_code[2], node->flags); + } + kfree(node); + return (p-buf); +} + +static int proc_read_node(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + struct pnp_bios_node *node; + int boot = (long)data >> 8; + u8 num = (long)data; + int len; + + if (pos != 0) { + *eof = 1; + return 0; + } + node = kmalloc(node_info.max_node_size, GFP_KERNEL); + if (!node) return -ENOMEM; + pnp_bios_get_dev_node(&num, boot, node); + len = node->size - sizeof(struct pnp_bios_node); + memcpy(buf, node->data, len); + kfree(node); + return len; +} + +static int proc_write_node(struct file *file, const char *buf, + unsigned long count, void *data) +{ + struct pnp_bios_node *node; + int boot = (long)data >> 8; + u8 num = (long)data; + + node = kmalloc(node_info.max_node_size, GFP_KERNEL); + if (!node) return -ENOMEM; + pnp_bios_get_dev_node(&num, boot, node); + if (count != node->size - sizeof(struct pnp_bios_node)) + return -EINVAL; + memcpy(node->data, buf, count); + if (pnp_bios_set_dev_node(node->handle, boot, node) != 0) + return -EINVAL; + kfree(node); + return count; +} + +void pnp_proc_init(void) +{ + struct pnp_bios_node *node; + struct proc_dir_entry *ent; + char name[3]; + u8 num; + + if (!pnp_bios_present()) return; + if (pnp_bios_dev_node_info(&node_info) != 0) + return; + + proc_pnp = proc_mkdir("pnp", proc_bus); + if (!proc_pnp) return; + proc_pnp_boot = proc_mkdir("boot", proc_pnp); + if (!proc_pnp_boot) return; + create_proc_read_entry("devices", 0, proc_pnp, + proc_read_devices, NULL); + + node = kmalloc(node_info.max_node_size, GFP_KERNEL); + if (!node) return; + for (num = 0; num != 0xff; ) { + //sprintf(name, "%02x", num); + if (pnp_bios_get_dev_node(&num, 0, node) != 0) + break; + sprintf(name, "%02x", node->handle); + ent = create_proc_entry(name, 0, proc_pnp); + if (ent) { + ent->read_proc = proc_read_node; + ent->write_proc = proc_write_node; + ent->data = (void *)(long)(node->handle); + } + ent = create_proc_entry(name, 0, proc_pnp_boot); + if (ent) { + ent->read_proc = proc_read_node; + ent->write_proc = proc_write_node; + ent->data = (void *)(long)(node->handle+0x100); + } + } + kfree(node); +} + +void pnp_proc_done(void) +{ + u8 num; + char name[3]; + + if (!proc_pnp) return; + for (num = 0; num != 0xff; num++) { + sprintf(name, "%02x", num); + remove_proc_entry(name, proc_pnp); + remove_proc_entry(name, proc_pnp_boot); + } + remove_proc_entry("boot", proc_pnp); + remove_proc_entry("devices", proc_pnp); + remove_proc_entry("pnp", proc_bus); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/Config.in linux.ac/drivers/s390/Config.in --- linux.vanilla/drivers/s390/Config.in Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/Config.in Thu Apr 12 12:03:49 2001 @@ -7,7 +7,7 @@ if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 24576 fi -dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD +dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM tristate 'XPRAM disk support' CONFIG_BLK_DEV_XPRAM comment 'S/390 block device drivers' @@ -18,7 +18,7 @@ bool ' Support for FBA Disks' CONFIG_DASD_FBA # bool ' Support for CKD Disks' CONFIG_DASD_CKD if [ "$CONFIG_ARCH_S390" = "y" ]; then - bool ' Support for DIAG access to CMS reserved Disks' CONFIG_DASD_MDSK + bool ' Support for DIAG access to CMS reserved Disks' CONFIG_DASD_DIAG fi; fi @@ -35,9 +35,15 @@ comment 'S/390 character device drivers' -bool 'Support for 3215 line mode terminal' CONFIG_3215 -if [ "$CONFIG_3215" = "y" ]; then - bool 'Support for console on 3215 line mode terminal' CONFIG_3215_CONSOLE +tristate 'Support for locally attached 3270 tubes' CONFIG_3270 +if [ "$CONFIG_3270" = "y" ]; then + bool 'Support for console on 3270 line mode terminal' CONFIG_3270_CONSOLE +fi +if [ "$CONFIG_3270_CONSOLE" != "y" ]; then + bool 'Support for 3215 line mode terminal' CONFIG_3215 + if [ "$CONFIG_3215" = "y" ]; then + bool 'Support for console on 3215 line mode terminal' CONFIG_3215_CONSOLE + fi fi bool 'Support for HWC line mode terminal' CONFIG_HWC if [ "$CONFIG_HWC" = "y" ]; then diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/Makefile linux.ac/drivers/s390/Makefile --- linux.vanilla/drivers/s390/Makefile Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/Makefile Thu Apr 12 12:03:49 2001 @@ -1,39 +1,14 @@ # -# Makefile for the linux i386-specific parts of the memory manager. +# Makefile for the S/390 specific device drivers # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definition is now in the main makefile... - -all: io.o -CFLAGS += O_TARGET := io.o -obj-y := s390io.o s390mach.o s390dyn.o idals.o ccwcache.o - subdir-y := block char misc net subdir-m := $(subdir-y) +obj-y := $(foreach dir,$(subdir-y),$(dir)/s390-$(dir).o) -obj-y += block/s390-block.o \ - char/s390-char.o \ - misc/s390-misc.o \ - net/s390-net.o - -io.o: $(obj-y) - -block/s390-block.o: dummy - $(MAKE) -C block - -char/s390-char.o: dummy - $(MAKE) -C char - -misc/s390-misc.o: dummy - $(MAKE) -C misc - -net/s390-net.o: dummy - $(MAKE) -C net +obj-y += s390io.o s390mach.o s390dyn.o idals.o ccwcache.o +export-objs += ccwcache.o idals.o s390dyn.o s390io.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/Makefile linux.ac/drivers/s390/block/Makefile --- linux.vanilla/drivers/s390/block/Makefile Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/block/Makefile Thu Apr 12 12:03:49 2001 @@ -1,34 +1,22 @@ -all: s390-block.o +# +# S/390 block devices +# -CFLAGS += O_TARGET := s390-block.o -DASD_OBJS := dasd.o - ifeq ($(CONFIG_DASD_ECKD),y) - DASD_OBJS += dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o - endif - ifeq ($(CONFIG_DASD_FBA),y) - DASD_OBJS += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o - endif - ifeq ($(CONFIG_DASD_MDSK),y) - DASD_OBJS += dasd_mdsk.o - endif -# ifeq ($(CONFIG_DASD_CKD),y) -# DASD_OBJS += dasd_ckd.o -# endif - -ifeq ($(CONFIG_DASD),y) - obj-y += $(DASD_OBJS) -else - ifeq ($(CONFIG_DASD),m) - obj-m += dasd_mod.o - D_OBJS += $(DASD_OBJS) - endif -endif +list-multi := dasd_mod.o +export-objs := dasd.o -obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o +dasd_mod-$(CONFIG_DASD_ECKD) += dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o +dasd_mod-$(CONFIG_DASD_FBA) += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o +dasd_mod-$(CONFIG_DASD_DIAG) += dasd_diag.o +dasd_mod-objs := dasd.o $(dasd_mod-y) -dasd_mod.o: $(D_OBJS) - $(LD) $(LD_RFLAG) -r -o $@ $(D_OBJS) +obj-$(CONFIG_DASD) += dasd_mod.o +obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o include $(TOPDIR)/Rules.make + +dasd_mod.o: $(dasd_mod-objs) + $(LD) -r -o $@ $(dasd_mod-objs) + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd.c linux.ac/drivers/s390/block/dasd.c --- linux.vanilla/drivers/s390/block/dasd.c Sat Feb 17 00:02:36 2001 +++ linux.ac/drivers/s390/block/dasd.c Thu Apr 12 12:03:49 2001 @@ -2,13 +2,27 @@ * File...........: linux/drivers/s390/block/dasd.c * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> * Horst Hummel <Horst.Hummel@de.ibm.com> + * Carsten Otte <Cotte@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * * History of changes (starts July 2000) * 11/09/00 complete redesign after code review + * 02/01/01 removed some warnings + * 02/01/01 added dynamic registration of ioctls + * fixed bug in registration of new majors + * fixed handling of request during dasd_end_request + * fixed handling of plugged queues + * fixed partition handling and HDIO_GETGEO + * fixed traditional naming scheme for devices beyond 702 + * fixed some race conditions related to modules + * added devfs suupport + * 03/06/01 refined dynamic attach/detach for leaving devices which are online. + * 06/09/01 refined dynamic modifiaction of devices + * renewed debug feature exploitation */ +#include <linux/module.h> #include <linux/config.h> #include <linux/version.h> #include <linux/init.h> @@ -17,7 +31,7 @@ #include <linux/kernel.h> #include <linux/tqueue.h> #include <linux/timer.h> -#include <linux/slab.h> +#include <linux/malloc.h> #include <linux/genhd.h> #include <linux/hdreg.h> #include <linux/interrupt.h> @@ -25,13 +39,9 @@ #ifdef CONFIG_PROC_FS #include <linux/proc_fs.h> #endif /* CONFIG_PROC_FS */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) #include <linux/spinlock.h> #include <linux/devfs_fs_kernel.h> #include <linux/blkpg.h> -#else -#include <asm/spinlock.h> -#endif #include <asm/ccwcache.h> #include <asm/dasd.h> @@ -54,17 +64,10 @@ #ifdef CONFIG_DASD_FBA #include "dasd_fba.h" #endif /* CONFIG_DASD_FBA */ -#ifdef CONFIG_DASD_MDSK +#ifdef CONFIG_DASD_DIAG #include "dasd_diag.h" -#endif /* CONFIG_DASD_MDSK */ - -static struct block_device_operations dasd_device_operations; +#endif /* CONFIG_DASD_DIAG */ -#ifdef MODULE -#define EXPORT_SYMTAB -#include <linux/module.h> - -EXPORT_NO_SYMBOLS; MODULE_AUTHOR ("Holger Smolinski <Holger.Smolinski@de.ibm.com>"); MODULE_DESCRIPTION ("Linux on S/390 DASD device driver," " Copyright 2000 IBM Corporation"); @@ -76,11 +79,10 @@ EXPORT_SYMBOL (dasd_int_handler); EXPORT_SYMBOL (dasd_alloc_request); EXPORT_SYMBOL (dasd_free_request); - -#endif /* MODULE */ +EXPORT_SYMBOL(dasd_ioctl_no_register); +EXPORT_SYMBOL(dasd_ioctl_no_unregister); /* SECTION: Constant definitions to be used within this file */ -#undef ERP_DEBUG #define PRINTK_HEADER DASD_NAME": " @@ -89,20 +91,28 @@ #undef CONFIG_DYNAMIC_QUEUE_MIN_SIZE #define DASD_CHANQ_MAX_SIZE 6 - /* SECTION: prototypes for static functions of dasd.c */ static request_fn_proc do_dasd_request; -void dasd_schedule_bh (dasd_device_t *); static int dasd_set_device_level (unsigned int, int, dasd_discipline_t *, int); static request_queue_t *dasd_get_queue (kdev_t kdev); +static void cleanup_dasd (void); +int dasd_fillgeo(int kdev,struct hd_geometry *geo); static struct block_device_operations dasd_device_operations; +/* SECTION: static variables of dasd.c */ + +static devfs_handle_t dasd_devfs_handle; + +/* SECTION: exported variables of dasd.c */ + +debug_info_t *dasd_debug_area; + #ifdef CONFIG_DASD_DYNAMIC /* SECTION: managing dynamic configuration of dasd_driver */ -static dasd_devreg_t *dasd_devreg_head = NULL; +static struct list_head dasd_devreg_head = LIST_HEAD_INIT(dasd_devreg_head); /* * function: dasd_create_devreg @@ -149,6 +159,7 @@ static dasd_range_t *dasd_range_head = NULL; /* anchor for list of ranges */ static spinlock_t range_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t dasd_open_count_lock; /* * function: dasd_create_range @@ -240,15 +251,14 @@ * appends it to the list of ranges * additionally a devreg_t is created and added to the list of devregs */ -static inline void +static inline dasd_range_t* dasd_add_range (int from, int to) { dasd_range_t *range; range = dasd_create_range (from, to); - if (range) - dasd_append_range (range); - else - return; + if (!range) return NULL; + + dasd_append_range (range); #ifdef CONFIG_DASD_DYNAMIC /* allocate and chain devreg infos for the devnos... */ { @@ -256,11 +266,11 @@ for (i = range->from; i <= range->to; i++) { dasd_devreg_t *reg = dasd_create_devreg (i); s390_device_register (®->devreg); - reg->next = dasd_devreg_head; - dasd_devreg_head = reg; + list_add(®->list,&dasd_devreg_head); } } #endif /* CONFIG_DASD_DYNAMIC */ + return range; } /* @@ -277,28 +287,25 @@ { int i; for (i = range->from; i <= range->to; i++) { - dasd_devreg_t *reg, *prev = NULL; - for (reg = dasd_devreg_head; reg; reg = reg->next) { + struct list_head *l; + dasd_devreg_t *reg = NULL; + list_for_each (l, &dasd_devreg_head) { + reg = list_entry(l,dasd_devreg_t,list); if (reg->devreg.flag == DEVREG_TYPE_DEVNO && - reg->devreg.devno == i && + reg->devreg.ci.devno == i && reg->devreg.oper_func == dasd_oper_handler) break; - prev = reg; } - if (!reg) + if (l == &dasd_devreg_head) BUG (); - if (prev) { - prev->next = reg->next; - } else { - dasd_devreg_head = reg->next; - } + list_del(®->list); s390_device_unregister (®->devreg); dasd_destroy_devreg (reg); } } +#endif /* CONFIG_DASD_DYNAMIC */ dasd_dechain_range (range); dasd_destroy_range (range); -#endif /* CONFIG_DASD_DYNAMIC */ } /* @@ -475,13 +482,18 @@ /* SECTION: Dealing with devices registered to multiple major numbers */ static spinlock_t dasd_major_lock = SPIN_LOCK_UNLOCKED; + static major_info_t dasd_major_info[] = { { - next:NULL, + list: LIST_HEAD_INIT(dasd_major_info[1].list ) + }, + { + list: LIST_HEAD_INIT(dasd_major_info[0].list ), gendisk: { INIT_GENDISK(94,DASD_NAME,DASD_PARTN_BITS,DASD_PER_MAJOR) - } + }, + flags : DASD_MAJOR_INFO_IS_STATIC } }; @@ -489,26 +501,16 @@ get_new_major_info (void) { major_info_t *major_info = NULL; - unsigned long flags; major_info = kmalloc (sizeof (major_info_t), GFP_KERNEL); if (major_info) { - major_info_t *temp = dasd_major_info; - static major_info_t temp_major_info[] = - { - { - next:NULL, - gendisk: { - INIT_GENDISK(0,DASD_NAME,DASD_PARTN_BITS,DASD_PER_MAJOR) - } - } - }; - spin_lock_irqsave (&dasd_major_lock, flags); - while (temp->next) - temp = temp->next; - temp->next = major_info; - spin_unlock_irqrestore (&dasd_major_lock, flags); - memcpy (major_info, temp_major_info, sizeof (major_info_t)); + static major_info_t temp_major_info = + { + gendisk: { + INIT_GENDISK(0,DASD_NAME,DASD_PARTN_BITS,DASD_PER_MAJOR) + } + }; + memcpy (major_info, &temp_major_info, sizeof (major_info_t)); } return major_info; } @@ -518,6 +520,7 @@ { int rc = 0; int major; + unsigned long flags; if (major_info == NULL) { major_info = get_new_major_info (); @@ -531,12 +534,27 @@ } } major = major_info->gendisk.major; + major_info->gendisk.de_arr = (devfs_handle_t*) + kmalloc(DASD_PER_MAJOR * sizeof(devfs_handle_t), GFP_KERNEL); + memset(major_info->gendisk.de_arr,0,DASD_PER_MAJOR * sizeof(devfs_handle_t)); + major_info->gendisk.flags = (char*) + kmalloc(DASD_PER_MAJOR * sizeof(char), GFP_KERNEL); + memset(major_info->gendisk.flags,0,DASD_PER_MAJOR * sizeof(char)); + rc = devfs_register_blkdev (major, DASD_NAME, &dasd_device_operations); if (rc < 0) { printk (KERN_WARNING PRINTK_HEADER "Cannot register to major no %d, rc = %d\n", major, rc); return rc; + } else { + major_info->flags |= DASD_MAJOR_INFO_REGISTERED; } + /* Insert the new major info into dasd_major_info if needed */ + if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC) ){ + spin_lock_irqsave (&dasd_major_lock, flags); + list_add_tail(&major_info->list,&dasd_major_info[0].list); + spin_unlock_irqrestore (&dasd_major_lock, flags); + } if (major == 0) { major = rc; rc = 0; @@ -604,6 +622,7 @@ int rc = 0; int major; struct gendisk *dd, *prev = NULL; + unsigned long flags; if (major_info == NULL) { return -EINVAL; @@ -629,6 +648,8 @@ if (dd == NULL) { return -ENOENT; } + kfree (major_info->gendisk.de_arr); + kfree (major_info->gendisk.flags); kfree (major_info->dasd_device); kfree (blk_size[major]); kfree (blksize_size[major]); @@ -641,9 +662,16 @@ printk (KERN_WARNING PRINTK_HEADER "Cannot unregister from major no %d, rc = %d\n", major, rc); return rc; + } else { + major_info->flags &= ~DASD_MAJOR_INFO_REGISTERED; } - if (major_info->gendisk.major > 128) + /* Delete the new major info from dasd_major_info if needed */ + if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) { + spin_lock_irqsave (&dasd_major_lock, flags); + list_del(&major_info->list); + spin_unlock_irqrestore (&dasd_major_lock, flags); kfree (major_info); + } return rc; } @@ -655,16 +683,18 @@ static inline dasd_device_t * dasd_device_from_kdev (kdev_t kdev) { - major_info_t *major_info = dasd_major_info; + major_info_t *major_info = NULL; + struct list_head *l; unsigned long flags; spin_lock_irqsave (&dasd_major_lock, flags); - while (major_info && - major_info->gendisk.major != MAJOR (kdev)) { - major_info = major_info->next; + list_for_each(l,&dasd_major_info[0].list) { + major_info = list_entry(l,major_info_t,list); + if ( major_info->gendisk.major == MAJOR(kdev) ) + break; } spin_unlock_irqrestore (&dasd_major_lock, flags); - if (major_info) + if (major_info != &dasd_major_info[0]) return major_info->dasd_device[MINOR (kdev) >> DASD_PARTN_BITS]; return NULL; } @@ -678,13 +708,14 @@ static inline dasd_device_t ** dasd_device_from_devno (int devno) { - major_info_t *major_info = dasd_major_info; + major_info_t *major_info; + struct list_head *l; int devindex = dasd_devindex_from_devno (devno); unsigned long flags; spin_lock_irqsave (&dasd_major_lock, flags); - for (major_info = dasd_major_info; major_info; - major_info = major_info->next) { + list_for_each(l,&dasd_major_info[0].list) { + major_info = list_entry(l,major_info_t,list); if (devindex < DASD_PER_MAJOR) { spin_unlock_irqrestore (&dasd_major_lock, flags); return &major_info->dasd_device[devindex]; @@ -867,7 +898,7 @@ ccw_req_t *prev; if (cqr == NULL) - BUG (); + BUG (); if (cqr == q->head) { q->head = cqr->next; @@ -1111,20 +1142,11 @@ static inline void dasd_end_request (struct request *req, int uptodate) { - struct buffer_head *bh; - while ((bh = req->bh) != NULL) { - int nsect = bh->b_size >> 9; - blk_finished_io (nsect); - req->bh = bh->b_reqnext; - bh->b_reqnext = NULL; - bh->b_end_io (bh, uptodate); - } - if (!end_that_request_first (req, uptodate, DASD_NAME)) { + while (end_that_request_first (req, uptodate, DASD_NAME)) {} #ifndef DEVICE_NO_RANDOM - add_blkdev_randomness (MAJOR (req->rq_dev)); + add_blkdev_randomness (MAJOR (req->rq_dev)); #endif - end_that_request_last (req); - } + end_that_request_last (req); return; } @@ -1151,9 +1173,10 @@ int rc = 0; asm volatile ("STCK %0":"=m" (now)); - if ( cqr->expires + cqr->startclk < now) { + if ( cqr->expires && + cqr->expires + cqr->startclk < now) { DASD_MESSAGE (KERN_ERR, ((dasd_device_t*)cqr->device), - "IO timeout 0x%08lx%08lx usecs with req %p\n", + "IO timeout 0x%08lx%08lx usecs in req %p\n", (long) (cqr->expires >> 44), (long) (cqr->expires >> 12), cqr); cqr->expires <<=1; @@ -1170,7 +1193,6 @@ dasd_finalize_request (ccw_req_t * cqr) { dasd_device_t *device = cqr->device; - dasd_discipline_t *discipline = device->discipline; asm volatile ("STCK %0":"=m" (cqr->endclk)); if (cqr->req) { @@ -1225,9 +1247,11 @@ CQR_STATUS_FAILED); continue; } else { - dasd_chanq_enq_head (qp, erp_cqr); + if (erp_cqr != qp->head){ + dasd_chanq_enq_head (qp, erp_cqr); + } /* chain of completed requests is now broken */ - break; + continue; } } else if ( qp -> head -> refers ) { /* we deal with an ERP */ char *uptodatestr; @@ -1266,7 +1290,8 @@ for (temp = cqr; temp != NULL ;temp=temp-> next ) if ( temp ->status == CQR_STATUS_QUEUED) chanq_max_size --; - while ( (! list_empty(&queue->queue_head)) && + while ( (! queue->plugged) && + (! list_empty(&queue->queue_head)) && (req=dasd_next_request(queue)) != NULL) { /* queue empty or certain critera fulfilled -> transfer */ if ( qp -> head == NULL || @@ -1307,6 +1332,10 @@ /* to be filled with MIH */ } break; + + case CQR_STATUS_PENDING: + /* just wait */ + break; default: BUG(); } @@ -1390,8 +1419,54 @@ } #endif /* LINUX_IS_24 */ +/* + * DASD_HANDLE_STATE_CHANGE_PENDING + * + * DESCRIPTION + * Handles the state change pending interrupt. + * Search for the device related request queue and check if the first + * cqr in queue in in status 'CQR_STATUE_PENDING'. + * If so the status is set to 'CQR_STATUS_QUEUED' to reactivate + * the device. + * + * PARAMETER + * stat device status of state change pending interrupt. + */ +void +dasd_handle_state_change_pending (devstat_t *stat) +{ + dasd_device_t **device_addr; + ccw_req_t *cqr; + + device_addr = dasd_device_from_devno (stat->devno); + + if (device_addr == NULL) { + printk (KERN_INFO PRINTK_HEADER + "unable to find device for state change pending " + "interrupt: devno%04X\n", + stat->devno); + } else { + /* re-activate first request in queue */ + cqr = (*device_addr)->queue.head; + + if (cqr->status == CQR_STATUS_PENDING) { + + DASD_MESSAGE (KERN_INFO, (*device_addr), + "%s", + "device request queue restarted by " + "state change pending interrupt\n"); + + del_timer(&(*device_addr)->timer); + + check_then_set(&cqr->status, + CQR_STATUS_PENDING, + CQR_STATUS_QUEUED); + dasd_schedule_bh(*device_addr); + } + } +} /* end dasd_handle_state_change_pending */ /* * function dasd_int_handler @@ -1406,7 +1481,7 @@ dasd_device_t *device; unsigned long long now; #ifdef ERP_DEBUG - static int counter; + static int counter = 0; #endif dasd_era_t era = dasd_era_none; /* default is everything is okay */ devstat_t *stat = (devstat_t *)ds; @@ -1415,6 +1490,16 @@ if (stat == NULL) { BUG(); } + + /* first of all check for state change pending interrupt */ + if (stat->dstat & (DEV_STAT_ATTENTION | + DEV_STAT_DEV_END | + DEV_STAT_UNIT_EXCEP )) { + + dasd_handle_state_change_pending (stat); + //return; /* TBD */ + } + ip = stat->intparm; if (!ip) { /* no intparm: unsolicited interrupt */ printk (KERN_INFO PRINTK_HEADER @@ -1441,11 +1526,35 @@ BUG(); } #ifdef ERP_DEBUG - counter++; - if ( counter % 137 == 0 ) { - stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL; - stat->cstat = 0x00; - stat->dstat = 0x02; + if ((++counter % 937 >= 0) && + ( counter % 937 <= 10) && + ( counter < 5000 ) && + ( counter > 2000 ) ){ + static int fake_count = 0; + printk ( KERN_INFO PRINTK_HEADER "***********************************************\n"); + printk ( KERN_INFO PRINTK_HEADER "Faking I/O error to recover from; cntr=%i / %02X\n",counter,++fake_count); + printk ( KERN_INFO PRINTK_HEADER "***********************************************\n"); + era = dasd_era_recover; + stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL; + stat->dstat |= 0x02; +// sense 32 + { + char *sense = stat->ii.sense.data; + sense [25] = 0x1D; + sense [27] = 0x00; + //sense [25] = (fake_count % 256); //0x1B; + //sense [27] = 0x00; + } +// sense 24 +// { +// char *sense = stat->ii.sense.data; +// sense [0] = (counter % 0xFF); //0x1B; +// sense [1] = ((counter * 7) % 0xFF); //0x1B; +// sense [2] = (fake_count % 0xFF); //0x1B; +// sense [27] = 0x80; +// } + +/* memset(stat->ii.sense.data,0,32); stat->ii.sense.data[2] = 0x06; stat->ii.sense.data[4] = 0x04; @@ -1464,6 +1573,7 @@ stat->ii.sense.data[24] = 0x04; stat->ii.sense.data[25] = 0x10; stat->ii.sense.data[26] = 0x4e; +*/ } #endif /* first of all lets try to find out the appropriate era_action */ @@ -1545,13 +1655,13 @@ ccw_req_t * default_erp_action (ccw_req_t * cqr) { - ccw_req_t *erp = ccw_alloc_request ((char *) &cqr->magic, 1, 0); + ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0); printk (KERN_WARNING PRINTK_HEADER "Default ERP called... \n"); - if (!erp) - return NULL; + if (erp == NULL) + return NULL; erp->cpaddr->cmd_code = CCW_CMD_TIC; erp->cpaddr->cda = (__u32)(void *)cqr->cpaddr; @@ -1562,6 +1672,7 @@ erp->retries = 16; erp->status = CQR_STATUS_FILLED; + return erp; } @@ -1582,8 +1693,8 @@ ccw_req_t * default_erp_postaction (ccw_req_t * erp) { + ccw_req_t *cqr = NULL, *free_erp = NULL; dasd_device_t *device = NULL; - ccw_req_t *free_erp; int success; device = (dasd_device_t *) (erp->device); @@ -1593,6 +1704,24 @@ else success = 0; +#ifdef ERP_DEBUG + + /* print current erp_chain */ + printk (KERN_WARNING PRINTK_HEADER + "default ERP postaction called for erp chain:\n"); + { + ccw_req_t *temp_erp = NULL; + for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers){ + printk(KERN_WARNING PRINTK_HEADER + " erp %p refers to %p with erp function %p\n", + temp_erp, + temp_erp->refers, + temp_erp->function ); + } + } + +#endif /* ERP_DEBUG*/ + if (erp->refers == NULL || erp->function == NULL) { BUG(); } @@ -1606,39 +1735,46 @@ while (erp->refers != NULL) { free_erp = erp; erp = erp->refers; + /* remove the request from the device queue */ dasd_chanq_deq (&device->queue, free_erp); + /* free the finished erp request */ dasd_free_request (free_erp); } /* save ptr to original cqr */ + cqr = erp; + +#ifdef ERP_DEBUG + printk (KERN_INFO PRINTK_HEADER + "default_erp_postaction - left original request = %p \n",cqr); +#endif /* ERP_DEBUG */ - /* - * printk (KERN_INFO PRINTK_HEADER - * "default_erp_postaction - left original request = %p \n",erp); - */ /* set corresponding status to original cqr */ if (success) { - check_then_set (&erp->status, CQR_STATUS_ERROR, + check_then_set (&cqr->status, + CQR_STATUS_ERROR, CQR_STATUS_DONE); } else { - check_then_set (&erp->status, CQR_STATUS_ERROR, + check_then_set (&cqr->status, + CQR_STATUS_ERROR, CQR_STATUS_FAILED); } - + +#ifdef ERP_DEBUG /* print current erp_chain */ -#if 0 printk (KERN_WARNING PRINTK_HEADER "default ERP postaction finished with remaining chain:\n"); { ccw_req_t *temp_erp = NULL; - for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers) { + for (temp_erp = cqr; temp_erp != NULL; temp_erp = temp_erp->refers) { printk (KERN_WARNING PRINTK_HEADER " erp %p refers to %p \n", temp_erp, temp_erp->refers); } } -#endif - return erp; +#endif /* ERP_DEBUG */ + + return cqr; } /* end default_erp_postaction */ /* SECTION: The helpers of the struct file_operations */ @@ -1655,6 +1791,7 @@ dasd_format (dasd_device_t * device, format_data_t * fdata) { int rc = 0; + int format_done = 0; ccw_req_t *req = NULL; format_data_t temp = { @@ -1663,29 +1800,41 @@ fdata->blksize, fdata->intensity }; - + + spin_lock (&dasd_open_count_lock); if (device->open_count != 1) { DASD_MESSAGE (KERN_INFO, device, "device is already open %d times", device->open_count); + spin_unlock(&dasd_open_count_lock); return -EINVAL; } if (!device->discipline->format_device) { + spin_unlock(&dasd_open_count_lock); return -EINVAL; } + device->open_count = -1; + spin_unlock (&dasd_open_count_lock); /* downgrade state of the device */ dasd_set_device_level (device->devinfo.irq, DASD_DEVICE_LEVEL_RECOGNIZED, device->discipline, 0); - DASD_MESSAGE (KERN_INFO, device, "Starting format from %d to %d (%d B blocks flags %d",fdata->start_unit,fdata->stop_unit,fdata->blksize,fdata->intensity); + DASD_MESSAGE (KERN_INFO, device, + "Starting format from %d to %d (%d B blocks flags %d", + fdata->start_unit, + fdata->stop_unit, + fdata->blksize, + fdata->intensity); /* Invalidate first track */ if (fdata->start_unit == DASD_FORMAT_DEFAULT_START_UNIT && - fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT && - fdata->intensity == DASD_FORMAT_DEFAULT_INTENSITY ) { + fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT && + fdata->intensity == DASD_FORMAT_DEFAULT_INTENSITY ) { format_data_t temp2 = - {0, 0, DASD_FORMAT_DEFAULT_BLOCKSIZE, 0x04}; - DASD_MESSAGE (KERN_INFO, device, "%s", "Invalidating first track..."); + {0, 0, fdata->blksize, 0x04}; + DASD_MESSAGE (KERN_INFO, device, + "%s", + "Invalidating first track..."); req = device->discipline->format_device (device, &temp2); if (req) { rc = sleep_on_req (req); @@ -1694,32 +1843,43 @@ rc = -EINVAL; } if (rc) { - printk (KERN_WARNING PRINTK_HEADER "Can't invalidate Track 0\n"); - } + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Can't invalidate Track 0\n"); + } else { + DASD_MESSAGE (KERN_INFO, device, + "%s", + "...Invalidation complete"); + } temp.start_unit++; - DASD_MESSAGE (KERN_INFO, device, "%s", "...Invalidation complete"); } /* format remainnig tracks of device */ - while (!rc && - ((req = device->discipline->format_device (device, &temp)) != - NULL)) { + while (!rc && + ((req = device->discipline->format_device (device, &temp)) != NULL) ) { + format_done=1; if ((rc = sleep_on_req (req)) != 0) { + + DASD_MESSAGE (KERN_WARNING, device, " Formatting failed with rc = %d\n", rc); break; } + dasd_free_request (req); /* request is no longer used */ temp.start_unit++; } - if (!rc && - req == NULL) { + + if (!rc && + req == NULL ) { if (fdata->start_unit == DASD_FORMAT_DEFAULT_START_UNIT && - fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT && - fdata->intensity == DASD_FORMAT_DEFAULT_INTENSITY ) { + fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT && + fdata->intensity == DASD_FORMAT_DEFAULT_INTENSITY ) { format_data_t temp2 = {0, 0, fdata->blksize, fdata->intensity}; - DASD_MESSAGE (KERN_INFO, device, "%s", "Revalidating first track..."); + DASD_MESSAGE (KERN_INFO, device, + "%s", + "Revalidating first track..."); req = device->discipline->format_device (device, &temp2); if (req) { rc = sleep_on_req (req); @@ -1728,12 +1888,22 @@ rc = -EINVAL; } if (rc) { - printk (KERN_WARNING PRINTK_HEADER - "Can't revalidate Track 0\n"); - } - DASD_MESSAGE (KERN_INFO, device, "%s", "...Revalidation complete"); + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Can't revalidate Track 0\n"); + } else { + DASD_MESSAGE (KERN_INFO, device, + "%s", + "...Revalidation complete"); + } } } /* end if no more requests */ + + /* check if at least one format cp was build in discipline */ + if (!format_done) { + rc = -EINVAL; + } + if (rc) DASD_MESSAGE (KERN_WARNING, device, "%s", " Formatting finished unsuccessfully"); @@ -1741,22 +1911,75 @@ DASD_MESSAGE (KERN_INFO, device, "%s", " Formatting finished successfully"); - /* re-activate device even if formatting was unsuccessful */ - /* Horst Hummel - 17/10/00 - ITPM PL020062RSC */ - dasd_set_device_level (device->devinfo.irq, - DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, - device->discipline, - 0); - udelay (1500000); - - dasd_set_device_level (device->devinfo.irq, - DASD_DEVICE_LEVEL_ANALYSED, - device->discipline, - 0); - + /* + * re-analyse device + */ + dasd_set_device_level (device->devinfo.irq, + DASD_DEVICE_LEVEL_ONLINE, + device->discipline, + 0); + udelay (1500000); + + dasd_set_device_level (device->devinfo.irq, + DASD_DEVICE_LEVEL_ONLINE, + device->discipline, + 0); + + spin_lock (&dasd_open_count_lock); + device->open_count=1; + spin_unlock (&dasd_open_count_lock); return rc; } /* end dasd_format */ +static struct list_head dasd_ioctls = LIST_HEAD_INIT(dasd_ioctls); + +static dasd_ioctl_list_t * +dasd_find_ioctl( int no ) +{ + struct list_head *curr; + list_for_each(curr,&dasd_ioctls){ + if (list_entry(curr,dasd_ioctl_list_t,list)->no == no ){ + return list_entry(curr,dasd_ioctl_list_t,list); + } + } + return NULL; +} + +int +dasd_ioctl_no_register ( int no, dasd_ioctl_fn_t handler ) +{ + dasd_ioctl_list_t *new; + if (dasd_find_ioctl(no)) + return -EBUSY; + new = kmalloc(sizeof(dasd_ioctl_list_t),GFP_KERNEL); + if ( new == NULL ) + return -ENOMEM; + new -> no = no; + new -> handler = handler; + list_add(&new->list,&dasd_ioctls); +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + return 0; +} + +int +dasd_ioctl_no_unregister ( int no, dasd_ioctl_fn_t handler ) +{ + dasd_ioctl_list_t *old = dasd_find_ioctl(no); + if ( old == NULL ) + return -ENOENT; + if ( old->no != no || + old->handler != handler ) + return -EINVAL; + list_del(&old->list); + kfree(old); +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + return 0; +} + static int do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data) { @@ -1809,10 +2032,11 @@ break; } case HDIO_GETGEO:{ - struct hd_geometry geo = - {0,}; - if (device->discipline->fill_geometry) - device->discipline->fill_geometry (device, &geo); + struct hd_geometry geo = {0,}; + rc = dasd_fillgeo(inp->i_rdev, &geo); + if (rc) + break; + rc = copy_to_user ((struct hd_geometry *) data, &geo, sizeof (struct hd_geometry)); if (rc) @@ -1944,17 +2168,23 @@ break; } default:{ - DASD_MESSAGE (KERN_INFO, device, - "ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx\n", - no, - _IOC_DIR (no) == _IOC_NONE ? "0" : - _IOC_DIR (no) == _IOC_READ ? "r" : - _IOC_DIR (no) == _IOC_WRITE ? "w" : - _IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ? - "rw" : "u", - _IOC_TYPE (no), _IOC_NR (no), _IOC_SIZE (no), - data); - rc = -EINVAL; + + dasd_ioctl_list_t *old = dasd_find_ioctl(no); + if ( old ) { + rc = old->handler(inp,no,data); + } else { + DASD_MESSAGE (KERN_INFO, device, + "ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx\n", + no, + _IOC_DIR (no) == _IOC_NONE ? "0" : + _IOC_DIR (no) == _IOC_READ ? "r" : + _IOC_DIR (no) == _IOC_WRITE ? "w" : + _IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ? + "rw" : "u", + _IOC_TYPE (no), _IOC_NR (no), _IOC_SIZE (no), + data); + rc = -EINVAL; + } break; } } @@ -2000,10 +2230,16 @@ " %s", " Cannot open unrecognized device\n"); return -EINVAL; } + spin_lock(&dasd_open_count_lock); + if (device->open_count == -1) { + spin_unlock (&dasd_open_count_lock); + return -EBUSY; + } #ifdef MODULE MOD_INC_USE_COUNT; #endif /* MODULE */ device->open_count++; + spin_unlock (&dasd_open_count_lock); return rc; } @@ -2023,6 +2259,7 @@ MAJOR (inp->i_rdev), MINOR (inp->i_rdev)); return -EINVAL; } + spin_lock(&dasd_open_count_lock); if (device->open_count--) { #ifdef MODULE MOD_DEC_USE_COUNT; @@ -2031,6 +2268,7 @@ fsync_dev(inp->i_rdev); /* sync the device */ if (device->open_count == 0) /* finally invalidate buffers */ invalidate_buffers(inp->i_rdev); + spin_unlock(&dasd_open_count_lock); return rc; } @@ -2048,6 +2286,26 @@ }; /* SECTION: Management of device list */ +int +dasd_fillgeo(int kdev,struct hd_geometry *geo) +{ + dasd_device_t *device = dasd_device_from_kdev (kdev); + if (!device->discipline->fill_geometry) + return -EINVAL; + + device->discipline->fill_geometry (device, geo); + geo->start = device->major_info-> + gendisk.part[MINOR(kdev)].start_sect; + + /* This is a hack. dasdfmt and ibm.c expect geo.start + to contain the block number of the label block when + it calls HDIO_GETGEO on the first partition. */ + if (geo->start == 0) + geo->start = device->sizes.pt_block; + + return 0; +} + /* This one is needed for naming 18000+ possible dasd devices */ int @@ -2057,27 +2315,30 @@ char first, second, third; if (hd) { - major_info_t *major_info; - for (major_info = dasd_major_info; major_info; major_info = major_info->next) { + major_info_t *major_info=NULL; + struct list_head *l; + + list_for_each(l,&dasd_major_info[0].list) { + major_info = list_entry(l,major_info_t,list); if (&major_info->gendisk == hd) { break; } index += DASD_PER_MAJOR; } - if (major_info == NULL) { + if (major_info == &dasd_major_info[0]) { return -EINVAL; } } third = index % 26; - second = (index / 26) % 27; - first = ((index / 26) / 27) % 27; + second = ((index-26) / 26) % 26; + first = (((index-702) / 26) / 26) % 26; len = sprintf (str, "dasd"); - if (first) { - len += sprintf (str + len, "%c", first + 'a' - 1); + if (index>701) { + len += sprintf (str + len, "%c", first + 'a'); } - if (second) { - len += sprintf (str + len, "%c", second + 'a' - 1); + if (index>25) { + len += sprintf (str + len, "%c", second + 'a'); } len += sprintf (str + len, "%c", third + 'a'); if (partition) { @@ -2093,13 +2354,28 @@ #ifdef CONFIG_DASD_DYNAMIC static void +dasd_plug_device (dasd_device_t *device) +{ + device->request_queue.plugged = 1; /* inhibit further calls of request_fn */ +} + +static void +dasd_unplug_device (dasd_device_t *device) +{ + generic_unplug_device(&device->request_queue); +} + +static void dasd_not_oper_handler (int irq, int status) { dasd_device_t *device = NULL; - major_info_t *major_info; + major_info_t *major_info = NULL; + struct list_head *l; int i, devno = -ENODEV; - for (major_info = dasd_major_info; major_info != NULL; major_info = major_info->next) { + /* find out devno of leaving device: CIO has already deleted this information ! */ + list_for_each(l,&dasd_major_info[0].list) { + major_info=list_entry(l, major_info_t,list); for (i = 0; i < DASD_PER_MAJOR; i++) { device = major_info->dasd_device[i]; if (device && @@ -2116,20 +2392,24 @@ "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); + 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); + DASD_MESSAGE(KERN_ALERT,device,"%s", + "open device has gone. please repair!"); + dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED, + NULL, 0); + } else { + DASD_MESSAGE(KERN_INFO,device,"%s","device has gone"); + 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_PREPARED, + dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, NULL, 0); printk (KERN_INFO PRINTK_HEADER "waiting for response...\n"); { @@ -2137,8 +2417,7 @@ init_waitqueue_head (&wait_queue); interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) >> 1); } - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED, - NULL, 0); + dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, NULL, 0); return rc; } @@ -2148,12 +2427,13 @@ int devno; int rc; devno = get_devno_by_irq (irq); - if (devno == -ENODEV) + printk (KERN_WARNING PRINTK_HEADER "Oper handler called\n"); + if (devno == -ENODEV) { + printk (KERN_WARNING PRINTK_HEADER "NODEV\n"); return -ENODEV; + } if (dasd_autodetect) { dasd_add_range (devno, 0); - } else { - return -ENODEV; } rc = dasd_enable_single_volume (irq); return rc; @@ -2172,14 +2452,26 @@ dasd_device_t **device_addr, *device; int current_level; major_info_t *major_info = NULL; + struct list_head *l; int i, minor, major; ccw_req_t *cqr = NULL; struct gendisk *dd; devno = get_devno_by_irq (irq); - if (devno < 0) { - printk (KERN_WARNING PRINTK_HEADER " no device appears to be connected to SCH %d\n", irq); - return -ENODEV; + if (devno < 0) { /* e.g. when device has been detached before */ + /* search in device list */ + list_for_each(l,&dasd_major_info[0].list) { + major_info = list_entry(l,major_info_t,list); + 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) + return -ENODEV; + } } if (dasd_devindex_from_devno (devno) < 0) { return -ENODEV; @@ -2204,8 +2496,9 @@ memset (device, 0, sizeof (dasd_device_t)); *device_addr = device; } - for (major_info = dasd_major_info; major_info; major_info = major_info->next) { + list_for_each(l,&dasd_major_info[0].list) { int i; + major_info = list_entry(l,major_info_t,list); for (i = 0; i < DASD_PER_MAJOR; i++) { if (major_info->dasd_device[i] == device) { device->kdev = MKDEV (major_info->gendisk.major, i << DASD_PARTN_BITS); @@ -2215,21 +2508,21 @@ if (i < DASD_PER_MAJOR) break; } - if (major_info == NULL) { + if (major_info == &dasd_major_info[0]) { return -ENODEV; } - device->major_info = major_info; - dasd_device_name (device->name, - ((long) device_addr - - (long) device->major_info->dasd_device) / - sizeof (dasd_device_t *), - 0, &major_info->gendisk); minor = MINOR (device->kdev); major = MAJOR (device->kdev); current_level = device->level; if (desired_level > current_level) { switch (current_level) { case DASD_DEVICE_LEVEL_UNKNOWN: /* Find a discipline */ + device->major_info = major_info; + dasd_device_name (device->name, + ((long) device_addr - + (long) device->major_info->dasd_device) / + sizeof (dasd_device_t *), + 0, &major_info->gendisk); rc = get_dev_info_by_irq (irq, &device->devinfo); if (rc < 0) { break; @@ -2242,6 +2535,9 @@ break; } device->discipline = discipline; + device->debug_area = debug_register(device->name,0,2,3*sizeof(long)); + debug_register_view(device->debug_area,&debug_sprintf_view); + debug_register_view(device->debug_area,&debug_hex_ascii_view); if (device->discipline->int_handler) { #ifdef CONFIG_DASD_DYNAMIC s390_request_irq_special (irq, @@ -2276,8 +2572,6 @@ } } init_waitqueue_head (&device->wait_q); - blk_init_queue (&device->request_queue, do_dasd_request); - blk_queue_headactive (&device->request_queue, 0); check_then_set (&device->level, DASD_DEVICE_LEVEL_UNKNOWN, DASD_DEVICE_LEVEL_RECOGNIZED); @@ -2325,9 +2619,12 @@ return -EMEDIUMTYPE; } } + blk_init_queue (&device->request_queue, do_dasd_request); + blk_queue_headactive (&device->request_queue, 0); + elevator_init(&device->request_queue.elevator, ELEVATOR_NOOP); for (i = 0; i < (1 << DASD_PARTN_BITS); i++) { - if (i == 0) - blk_size[major][minor] = (device->sizes.blocks << device->sizes.s2b_shift) >> 1; + if (i == 0) + blk_size[major][minor] = (device->sizes.blocks << device->sizes.s2b_shift) >> 1; else blk_size[major][minor + i] = 0; hardsect_size[major][minor + i] = device->sizes.bp_block; @@ -2336,7 +2633,7 @@ blksize_size[major][minor + i] = 1024; max_sectors[major][minor + i] = - 255 << device->sizes.s2b_shift; + device->discipline->max_blocks << device->sizes.s2b_shift; } check_then_set (&device->level, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, @@ -2344,6 +2641,12 @@ dd = &major_info->gendisk; dd->sizes[minor] = (device->sizes.blocks << device->sizes.s2b_shift) >> 1; + dd->part[minor].start_sect = 0; + { + char buffer[5]; + sprintf(buffer,"%04X",device->devinfo.devno); + dd->de_arr[minor>>DASD_PARTN_BITS] = devfs_mk_dir(dasd_devfs_handle,buffer,NULL); + } #if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) #ifndef MODULE if (flags & 0x80) @@ -2353,8 +2656,15 @@ if (desired_level == DASD_DEVICE_LEVEL_ANALYSED) break; case DASD_DEVICE_LEVEL_ANALYSED: /* Fallthrough ?? */ - - break; + dasd_unplug_device(device); + check_then_set (&device->level, + DASD_DEVICE_LEVEL_ANALYSED, + DASD_DEVICE_LEVEL_ONLINE); + + if (desired_level == DASD_DEVICE_LEVEL_ONLINE) + break; + case DASD_DEVICE_LEVEL_ONLINE: + break; default: printk (KERN_WARNING PRINTK_HEADER "Internal error in " __FILE__ " on line %d." @@ -2368,20 +2678,29 @@ } } else if (desired_level < current_level) { /* donwgrade device status */ switch (current_level) { - case DASD_DEVICE_LEVEL_ANALYSED: /* Fallthrough ?? */ + case DASD_DEVICE_LEVEL_ONLINE: /* Fallthrough ?? */ + dasd_plug_device(device); check_then_set (&device->level, - DASD_DEVICE_LEVEL_ANALYSED, - DASD_DEVICE_LEVEL_ANALYSIS_PREPARED); - if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PREPARED) - break; - case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED: + DASD_DEVICE_LEVEL_ONLINE, + DASD_DEVICE_LEVEL_ANALYSED); + if (desired_level == DASD_DEVICE_LEVEL_ANALYSED) + break; + case DASD_DEVICE_LEVEL_ANALYSED: /* Fallthrough ?? */ for (i = 0; i < (1 << DASD_PARTN_BITS); i++) { - blk_size[major][minor] = 0; + __invalidate_buffers(MKDEV(major,minor),1); + blk_size[major][minor] = 0; hardsect_size[major][minor + i] = 0; blksize_size[major][minor + i] = 0; max_sectors[major][minor + i] = 0; } memset (&device->sizes, 0, sizeof (dasd_sizes_t)); + blk_cleanup_queue (&device->request_queue); + check_then_set (&device->level, + DASD_DEVICE_LEVEL_ANALYSED, + DASD_DEVICE_LEVEL_ANALYSIS_PREPARED); + if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PREPARED) + break; + case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED: check_then_set (&device->level, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, DASD_DEVICE_LEVEL_ANALYSIS_PENDING); @@ -2398,10 +2717,12 @@ free_irq (irq, &device->dev_status); } device->discipline = NULL; - blk_cleanup_queue (&device->request_queue); + debug_unregister(device->debug_area); check_then_set (&device->level, DASD_DEVICE_LEVEL_RECOGNIZED, DASD_DEVICE_LEVEL_UNKNOWN); + *device_addr = NULL; + kfree(device); if (desired_level == DASD_DEVICE_LEVEL_UNKNOWN) break; case DASD_DEVICE_LEVEL_UNKNOWN: @@ -2433,6 +2754,13 @@ int len; } tempinfo_t; +void dasd_fill_inode (struct inode* inode, int fill) { + if (fill) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) static struct proc_dir_entry *dasd_proc_root_entry = NULL; #else @@ -2445,7 +2773,8 @@ nlink:1, uid:0, gid:0, - size:0 + size:0, + fill_inode:dasd_fill_inode }; #endif /* KERNEL_VERSION */ static struct proc_dir_entry *dasd_devices_entry; @@ -2458,7 +2787,9 @@ int size = 1; int len = 0; major_info_t *temp = dasd_major_info; + struct list_head *l; tempinfo_t *info; + int i; info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t)); if (info == NULL) { @@ -2467,15 +2798,14 @@ } else { file->private_data = (void *) info; } - while (temp) { - int i; + list_for_each(l,&dasd_major_info[0].list) { + temp = list_entry(l,major_info_t,list); for (i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i++) { dasd_device_t *device = temp->dasd_device[i]; if (device) { size += 128; } } - temp = temp->next; } temp = dasd_major_info; info->data = (char *) vmalloc (size); /* FIXME! determine space needed in a better way */ @@ -2484,8 +2814,8 @@ vfree (info); return -ENOMEM; } - while (temp) { - int i; + list_for_each(l,&dasd_major_info[0].list) { + temp = list_entry(l,major_info_t,list); for (i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i++) { dasd_device_t *device = temp->dasd_device[i]; if (device) { @@ -2519,15 +2849,24 @@ device->sizes.blocks, ((device->sizes.bp_block >> 9) * device->sizes.blocks) >> 11); break; + case DASD_DEVICE_LEVEL_ONLINE: + len += sprintf (info->data + len, "active "); + len += sprintf (info->data + len, " at blocksize: %d, %ld blocks, %ld MB\n", + device->sizes.bp_block, + device->sizes.blocks, + ((device->sizes.bp_block >> 9) * device->sizes.blocks) >> 11); + break; default: len += sprintf (info->data + len, "no stat\n"); break; } } } - temp = temp->next; } info->len = len; +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif return rc; } @@ -2554,6 +2893,11 @@ dasd_devices_write (struct file *file, const char *user_buf, size_t user_len, loff_t * offset) { char *buffer = vmalloc (user_len); + int off = 0; + char *temp; + int irq; + int j,target; + dasd_range_t *rptr, range; if (buffer == NULL) return -ENOMEM; @@ -2563,17 +2907,68 @@ } 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); + if (strncmp ( buffer, "set ",4) && + strncmp ( buffer, "add ",4)){ + printk (KERN_WARNING PRINTK_HEADER + "/proc/dasd/devices: only 'set' and 'add' are supported verbs"); + return -EINVAL; + } + off += 4; + while (!isalnum(buffer[off])) off++; + if (!strncmp (buffer + off, "device", strlen ("device"))) { + off += strlen("device"); + while (!isalnum(buffer[off])) off++; + } + if (!strncmp (buffer + off, "range=", strlen ("range="))) { + off += strlen("range="); + while (!isalnum(buffer[off])) off++; + } + temp = buffer+off; + range.from = dasd_strtoul (temp, &temp); + range.to = range.from; + if (*temp == '-') { + temp++; + range.to = dasd_strtoul (temp, &temp); + } + off = (long)temp - (long)buffer; + if ( !strncmp ( buffer, "add",strlen("add"))) { + rptr = dasd_add_range (range.from, range.to); + } else { + rptr = ⦥ + } + while (!isalnum(buffer[off])) off++; + printk (KERN_INFO PRINTK_HEADER + "varying device range %04X-%04X\n", rptr->from, rptr->to); + if ( !strncmp ( buffer, "add",strlen("add")) || + !strncmp ( buffer+off, "on",strlen("on")) ) { + target = DASD_DEVICE_LEVEL_ONLINE; + for (j = rptr->from; j <= rptr->to; j++) { + irq = get_irq_by_devno (j); + if (irq >= 0) { + dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, NULL, 0); + } + } + printk (KERN_INFO PRINTK_HEADER "waiting for responses...\n"); + { + static wait_queue_head_t wait_queue; + init_waitqueue_head (&wait_queue); + interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) ); + } + } else if ( !strncmp ( buffer+off, "off",strlen("off"))) { + target = DASD_DEVICE_LEVEL_UNKNOWN; + } else { + printk (KERN_WARNING PRINTK_HEADER + "/proc/dasd/devices: parse error in '%s'", buffer); + vfree (buffer); + return -EINVAL; + + } + for (j = rptr->from; j <= rptr->to; j++) { + irq = get_irq_by_devno (j); + if (irq >= 0) { + dasd_set_device_level (irq, target, NULL, 0); + } + } return user_len; } @@ -2587,6 +2982,9 @@ vfree (p_info->data); vfree (p_info); } +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif return rc; } @@ -2693,6 +3091,9 @@ } len += sprintf (info->data + len, "\n"); info->len = len; +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif return rc; } @@ -2779,26 +3180,44 @@ } /* SECTION: Initializing the driver */ - int __init dasd_init (void) { int rc = 0; int irq; int j; - major_info_t *major_info; + major_info_t *major_info=NULL; + struct list_head *l; dasd_range_t *range; printk (KERN_INFO PRINTK_HEADER "initializing...\n"); - for (major_info = dasd_major_info; major_info; major_info = major_info->next) { + dasd_debug_area = debug_register(DASD_NAME,0,2,3*sizeof(long)); + debug_register_view(dasd_debug_area,&debug_sprintf_view); + debug_register_view(dasd_debug_area,&debug_hex_ascii_view); + + if ( dasd_debug_area == NULL ) { + goto failed; + } + DASD_DRIVER_DEBUG_EVENT(0,dasd_init,"%s","ENTRY"); + dasd_devfs_handle = devfs_mk_dir(NULL,DASD_NAME,NULL); + if ( dasd_devfs_handle < 0 ) { + DASD_DRIVER_DEBUG_EVENT(1,dasd_init,"%s","no devfs"); + goto failed; + } + list_for_each(l,&dasd_major_info[0].list) { + major_info=list_entry(l,major_info_t,list); if ((rc = dasd_register_major (major_info)) > 0) { + DASD_DRIVER_DEBUG_EVENT(1,dasd_init, + "major %d: success",major_info->gendisk.major); printk (KERN_INFO PRINTK_HEADER "Registered successfully to major no %u\n", major_info->gendisk.major); } else { + DASD_DRIVER_DEBUG_EVENT(1,dasd_init, + "major %d: failed",major_info->gendisk.major); 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; + goto failed; } } #ifndef MODULE @@ -2809,57 +3228,77 @@ rc = dasd_proc_init (); if (rc) { - goto proc_failed; + DASD_DRIVER_DEBUG_EVENT(1,dasd_init, + "%s","no proc-FS"); + goto failed; } genhd_dasd_name = dasd_device_name; + genhd_dasd_fillgeo = dasd_fillgeo; #ifdef CONFIG_DASD_ECKD rc = dasd_eckd_init (); if (rc == 0) { + DASD_DRIVER_DEBUG_EVENT(1,dasd_init, + "ECKD discipline %s","success"); printk (KERN_INFO PRINTK_HEADER "Registered ECKD discipline successfully\n"); } else { - goto eckd_failed; + DASD_DRIVER_DEBUG_EVENT(1,dasd_init, + "ECKD discipline %s","failed"); + goto failed; } #endif /* CONFIG_DASD_ECKD */ #ifdef CONFIG_DASD_FBA rc = dasd_fba_init (); if (rc == 0) { + DASD_DRIVER_DEBUG_EVENT(1,dasd_init, + "FBA discipline %s","success"); + printk (KERN_INFO PRINTK_HEADER "Registered FBA discipline successfully\n"); } else { - goto fba_failed; + DASD_DRIVER_DEBUG_EVENT(1,dasd_init, + "FBA discipline %s","failed"); + goto failed; } #endif /* CONFIG_DASD_FBA */ -#ifdef CONFIG_DASD_MDSK +#ifdef CONFIG_DASD_DIAG if (MACHINE_IS_VM) { rc = dasd_diag_init (); if (rc == 0) { + DASD_DRIVER_DEBUG_EVENT(1,dasd_init, + "DIAG discipline %s","success"); printk (KERN_INFO PRINTK_HEADER - "Registered MDSK discipline successfully\n"); + "Registered DIAG discipline successfully\n"); } else { - goto mdsk_failed; + DASD_DRIVER_DEBUG_EVENT(1,dasd_init, + "DIAG discipline %s","failed"); + goto failed; } } -#endif /* CONFIG_DASD_MDSK */ +#endif /* CONFIG_DASD_DIAG */ 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_PREPARED, - NULL, 0); - } - } - if (dasd_autodetect) { - for (irq = get_irq_first (); irq != -ENODEV; irq = get_irq_next (irq)) { + if (dasd_autodetect) { /* update device range to all devices */ + for (irq = get_irq_first (); irq != -ENODEV; + irq = get_irq_next (irq)) { int devno = get_devno_by_irq (irq); int index = dasd_devindex_from_devno (devno); if (index == -ENODEV) { /* not included in ranges */ + DASD_DRIVER_DEBUG_EVENT(2,dasd_init, + "add %04X to range", + devno); dasd_add_range (devno, 0); - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, - NULL, 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_DRIVER_DEBUG_EVENT(2,dasd_init, + "1st step in initialization irq 0x%x",irq); + dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, + NULL, 0); } } printk (KERN_INFO PRINTK_HEADER "waiting for responses...\n"); @@ -2873,99 +3312,117 @@ 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, + DASD_DRIVER_DEBUG_EVENT(2,dasd_init, + "2nd step in initialization irq 0x%x",irq); + dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, NULL, 0); } } } - 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:{ - major_info_t * temp; - for (temp = dasd_major_info; - temp && (temp != major_info); - temp = temp->next) { - dasd_unregister_major (temp); - } - } - dasd_cleanup_emergency_req (); + goto out; + failed: printk (KERN_INFO PRINTK_HEADER "initialization not performed due to errors\n"); - out: + cleanup_dasd(); + out: + DASD_DRIVER_DEBUG_EVENT(0,dasd_init,"%s","LEAVE"); printk (KERN_INFO PRINTK_HEADER "initialization finished\n"); return rc; } -void +static void cleanup_dasd (void) { - int j, rc = 0; + int i,j,rc; int irq; - major_info_t *major_info; + major_info_t *major_info=NULL; + struct list_head *l; dasd_range_t *range, *next; printk (KERN_INFO PRINTK_HEADER "shutting down\n"); - - dasd_proc_cleanup (); - + DASD_DRIVER_DEBUG_EVENT(0,"cleanup_dasd","%s","ENTRY"); 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_DRIVER_DEBUG_EVENT(2,"cleanup_dasd", + "shutdown irq 0x%x",irq); dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN, NULL, 0); } } } - for (major_info = dasd_major_info; major_info; major_info = major_info->next) { - int i; +#ifdef CONFIG_DASD_DIAG + if (MACHINE_IS_VM) { + dasd_diag_cleanup (); + DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd", + "DIAG discipline %s","success"); + printk (KERN_INFO PRINTK_HEADER + "De-Registered DIAG discipline successfully\n"); + } +#endif /* CONFIG_DASD_DIAG */ +#ifdef CONFIG_DASD_FBA + dasd_fba_cleanup (); + DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd", + "FBA discipline %s","success"); + printk (KERN_INFO PRINTK_HEADER + "De-Registered FBA discipline successfully\n"); +#endif /* CONFIG_DASD_FBA */ +#ifdef CONFIG_DASD_ECKD + dasd_eckd_cleanup (); + DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd", + "ECKD discipline %s","success"); + printk (KERN_INFO PRINTK_HEADER + "De-Registered ECKD discipline successfully\n"); +#endif /* CONFIG_DASD_ECKD */ + + dasd_proc_cleanup (); + dasd_cleanup_emergency_req (); + + list_for_each(l,&dasd_major_info[0].list) { + major_info=list_entry(l,major_info_t,list); for (i = 0; i < DASD_PER_MAJOR; i++) { kfree (major_info->dasd_device[i]); } - if ((rc = dasd_unregister_major (major_info)) == 0) { + if ((major_info -> flags & DASD_MAJOR_INFO_REGISTERED) && + (rc = dasd_unregister_major (major_info)) == 0) { + DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd", + "major %d: success",major_info->gendisk.major); printk (KERN_INFO PRINTK_HEADER "Unregistered successfully from major no %u\n", major_info->gendisk.major); } else { + DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd", + "major %d: failed",major_info->gendisk.major); printk (KERN_WARNING PRINTK_HEADER "Couldn't unregister successfully from major no %d rc = %d\n", major_info->gendisk.major, rc); } } - dasd_cleanup_emergency_req (); + range = dasd_range_head; while (range) { next = range->next; - kfree (range); + dasd_remove_range (range); if (next == NULL) break; else range = next; } dasd_range_head = NULL; + +#ifndef MODULE + for( j = 0; j < 256; j++ ) + if ( dasd[j] ) { + kfree(dasd[j]); + dasd[j] = NULL; + } +#endif /* MODULE */ + if (dasd_devfs_handle) + devfs_unregister(dasd_devfs_handle); + if (dasd_debug_area != NULL ) + debug_unregister(dasd_debug_area); -#ifdef CONFIG_DASD_DYNAMIC - { - dasd_devreg_t *reg; - while (dasd_devreg_head) { - reg = dasd_devreg_head->next; - kfree (dasd_devreg_head); - dasd_devreg_head = reg; - } - } -#endif /* CONFIG_DASD_DYNAMIC */ printk (KERN_INFO PRINTK_HEADER "shutdown completed\n"); + DASD_DRIVER_DEBUG_EVENT(0,"cleanup_dasd","%s","LEAVE"); } #ifdef MODULE diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd_3990_erp.c linux.ac/drivers/s390/block/dasd_3990_erp.c --- linux.vanilla/drivers/s390/block/dasd_3990_erp.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/block/dasd_3990_erp.c Thu Apr 12 12:03:49 2001 @@ -1,46 +1,196 @@ /* * File...........: linux/drivers/s390/block/dasd_3990_erp.c - * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> - * Horst Hummel <Horst.Hummel@de.ibm.com> + * Author(s)......: Horst Hummel <Horst.Hummel@de.ibm.com> + * Holger Smolinski <Holger.Smolinski@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> - * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001 */ #include <asm/ccwcache.h> +#include <asm/idals.h> #include <asm/dasd.h> +#include <asm/s390io.h> +#include <linux/timer.h> +#include "dasd_eckd.h" +#include "dasd_3990_erp.h" #ifdef PRINTK_HEADER #undef PRINTK_HEADER -#define PRINTK_HEADER "dasd_erp(3990)" -#endif /* PRINTK_HEADER */ +#endif /* PRINTK_HEADER */ +#define PRINTK_HEADER "dasd_erp(3990): " /* - * DASD_3990_ERP_EXAMINE_32 - * - * DESCRIPTION - * Checks only for fatal/no/recoverable error. - * A detailed examination of the sense data is done later outside - * the interrupt handler. - * - * RETURN VALUES - * dasd_era_none no error - * dasd_era_fatal for all fatal (unrecoverable errors) - * dasd_era_recover for recoverable others. + ***************************************************************************** + * SECTION DEBUG ROUTINES + ***************************************************************************** */ -dasd_era_t -dasd_3990_erp_examine_32 (char *sense) +#ifdef ERP_DEBUG +void +log_erp_chain (ccw_req_t *cqr, + int caller, + __u32 cpa) { - switch (sense[25]) { - case 0x00: - return dasd_era_none; - case 0x01: - return dasd_era_fatal; - default: - return dasd_era_recover; - } + ccw_req_t *loop_cqr = cqr; + dasd_device_t *device = cqr->device; -} /* end dasd_3990_erp_examine_32 */ + char *page = (char *)get_free_page(GFP_ATOMIC); + int len = 0; + int i; + char *nl, + *end_cqr, + *begin, + *end; + + if ( page == NULL ) { + printk (KERN_WARNING PRINTK_HEADER + "No memory to dump ERP chain\n"); + return; + } + + while (loop_cqr != NULL) { + + memset (page, 0, 4096); + len = 0; + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "device %04X on irq %d: (%s) ERP chain report for req: %p\n", + device->devinfo.devno, + device->devinfo.irq, + caller == 0 ? "EXAMINE" : "ACTION", + loop_cqr); + + nl = (char *) loop_cqr; + end_cqr = nl + sizeof (ccw_req_t); + + while (nl < end_cqr) { + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "%p: %02x%02x%02x%02x %02x%02x%02x%02x " + "%02x%02x%02x%02x %02x%02x%02x%02x\n", + nl, + nl[0], nl[1], nl[2], nl[3], + nl[4], nl[5], nl[6], nl[7], + nl[8], nl[9], nl[10], nl[11], + nl[12], nl[13], nl[14], nl[15]); + nl +=16; + } + + nl = (char *) loop_cqr->cpaddr; + + if (loop_cqr->cplength > 40 ) { /* log only parts of the CP */ + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "Start of channel program:\n"); + + for (i = 0; i < 20; i += 2) { + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "%p: %02x%02x%02x%02x %02x%02x%02x%02x " + "%02x%02x%02x%02x %02x%02x%02x%02x\n", + nl, + nl[0], nl[1], nl[2], nl[3], + nl[4], nl[5], nl[6], nl[7], + nl[8], nl[9], nl[10], nl[11], + nl[12], nl[13], nl[14], nl[15]); + + nl += 16; + } + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "End of channel program:\n"); + + nl = (char *) loop_cqr->cpaddr; + nl += ((loop_cqr->cplength - 10) * 8); + + for (i = 0; i < 20; i += 2) { + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "%p: %02x%02x%02x%02x %02x%02x%02x%02x " + "%02x%02x%02x%02x %02x%02x%02x%02x\n", + nl, + nl[0], nl[1], nl[2], nl[3], + nl[4], nl[5], nl[6], nl[7], + nl[8], nl[9], nl[10], nl[11], + nl[12], nl[13], nl[14], nl[15]); + + nl += 16; + } + + } else { /* log the whole CP */ + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "Channel program (complete):\n"); + + for (i = 0; i < (loop_cqr->cplength + 4); i += 2) { + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "%p: %02x%02x%02x%02x %02x%02x%02x%02x " + "%02x%02x%02x%02x %02x%02x%02x%02x\n", + nl, + nl[0], nl[1], nl[2], nl[3], + nl[4], nl[5], nl[6], nl[7], + nl[8], nl[9], nl[10], nl[11], + nl[12], nl[13], nl[14], nl[15]); + + nl += 16; + } + } + + /* log bytes arround failed CCW if not already done */ + begin = (char *) loop_cqr->cpaddr; + end = begin + ((loop_cqr->cplength+4) * 8); + nl = (void *)cpa; + + if (loop_cqr == cqr) { /* log only once */ + + if ((loop_cqr->cplength > 40) || /* not whole CP was logged or */ + ((nl < begin ) && /* CCW is outside logged CP */ + (nl > end ) ) ) { + + nl -= 10*8; /* start some bytes before */ + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "Failed CCW (%p) (area):\n", + (void *)cpa); + + for (i = 0; i < 20; i += 2) { + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "%p: %02x%02x%02x%02x %02x%02x%02x%02x " + "%02x%02x%02x%02x %02x%02x%02x%02x\n", + nl, + nl[0], nl[1], nl[2], nl[3], + nl[4], nl[5], nl[6], nl[7], + nl[8], nl[9], nl[10], nl[11], + nl[12], nl[13], nl[14], nl[15]); + + nl += 16; + } + + } else { + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "Failed CCW (%p) already logged\n", + (void *)cpa); + } + } + + printk ("%s", page); + loop_cqr = loop_cqr->refers; + } + + free_page ((unsigned long) page); + +} /* end log_erp_chain */ +#endif /* ERP_DEBUG */ + + +/* + ***************************************************************************** + * SECTION ERP EXAMINATION + ***************************************************************************** + */ /* * DASD_3990_ERP_EXAMINE_24 @@ -52,7 +202,7 @@ * * Each bit configuration leading to an action code 2 (Exit with * programming error or unusual condition indication) - * and 10 (disabled interface) are handled as fatal error´s. + * are handled as fatal error´s. * * All other configurations are handled as recoverable errors. * @@ -64,31 +214,58 @@ dasd_3990_erp_examine_24 (char *sense) { - /* check for 'Command Recejct' whithout environmental data present */ - if (sense[0] & 0x80) { - 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) { - if (sense[2] &0x10){ - return dasd_era_recover; - } else { - return dasd_era_fatal; - } + /* check for 'Command Recejct' which is always a fatal error */ + if (sense[0] & SNS0_CMD_REJECT) { + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + return dasd_era_recover; + } else { + return dasd_era_fatal; + } + } + /* check for 'Invalid Track Format' */ + if (sense[1] & SNS1_INV_TRACK_FORMAT) { + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + return dasd_era_recover; + } else { + return dasd_era_fatal; + } } /* check for 'No Record Found' */ - if (sense[1] & 0x08) { - return dasd_era_fatal; + if (sense[1] & SNS1_NO_REC_FOUND) { + return dasd_era_fatal; } /* return recoverable for all others */ return dasd_era_recover; -} /* END dasd_3990_erp_examine_24 */ +} /* END dasd_3990_erp_examine_24 */ + +/* + * DASD_3990_ERP_EXAMINE_32 + * + * DESCRIPTION + * Checks only for fatal/no/recoverable error. + * A detailed examination of the sense data is done later outside + * the interrupt handler. + * + * RETURN VALUES + * dasd_era_none no error + * dasd_era_fatal for all fatal (unrecoverable errors) + * dasd_era_recover for recoverable others. + */ +dasd_era_t +dasd_3990_erp_examine_32 (char *sense) +{ + + switch (sense[25]) { + case 0x00: + return dasd_era_none; + case 0x01: + return dasd_era_fatal; + default: + return dasd_era_recover; + } + +} /* end dasd_3990_erp_examine_32 */ /* * DASD_3990_ERP_EXAMINE @@ -107,10 +284,12 @@ * dasd_era_recover for all others. */ dasd_era_t -dasd_3990_erp_examine (ccw_req_t * cqr, devstat_t * stat) +dasd_3990_erp_examine (ccw_req_t *cqr, + devstat_t *stat) { - char *sense = stat->ii.sense.data; + char *sense = stat->ii.sense.data; + dasd_era_t era = dasd_era_recover; /* check for successful execution first */ if (stat->cstat == 0x00 && @@ -118,19 +297,2821 @@ return dasd_era_none; /* distinguish between 24 and 32 byte sense data */ - if (sense[27] & 0x80) { + if (sense[27] & DASD_SENSE_BIT_0) { + + /* examine the 24 byte sense data */ + era = dasd_3990_erp_examine_24 (sense); + + } else { /* examine the 32 byte sense data */ - return dasd_3990_erp_examine_32 (sense); + era = dasd_3990_erp_examine_32 (sense); + + } /* end distinguish between 24 and 32 byte sense data */ + +#ifdef ERP_DEBUG + if (era == dasd_era_fatal) { + + log_erp_chain (cqr, + 0, + stat->cpa); + } +#endif /* ERP_DEBUG */ + + return era; + +} /* END dasd_3990_erp_examine */ + +/* + ***************************************************************************** + * SECTION ERP HANDLING + ***************************************************************************** + */ +/* + ***************************************************************************** + * 24 and 32 byte sense ERP functions + ***************************************************************************** + */ + +/* + * DASD_3990_ERP_BLOCK_QUEUE + * + * DESCRIPTION + * Block the given device request queue to prevent from further + * processing until the started timer has expired or an related + * interrupt was received. + * + * PARAMETER + * erp request to be blocked + * expires time to wait until restart (in seconds) + * + * RETURN VALUES + * void + */ +void +dasd_3990_erp_block_queue (ccw_req_t *erp, + unsigned long expires) +{ + + dasd_device_t *device = erp->device; + + DASD_MESSAGE (KERN_INFO, device, + "blocking request queue for %is", + (int) expires); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_PENDING); + + /* restart queue after some time */ + device->timer.function = dasd_3990_erp_restart_queue; + device->timer.data = (unsigned long) erp; + device->timer.expires = jiffies + (expires * HZ); + add_timer(&device->timer); + +} /* end dasd_3990_erp_block_queue */ + +/* + * DASD_3990_ERP_RESTART_QUEUE + * + * DESCRIPTION + * Restarts request currently in status PENDING. + * This has to be done if either an related interrupt has received, or + * a timer has expired. + * + * + * PARAMETER + * erp pointer to the PENDING ERP + * + * RETURN VALUES + * void + * + */ +void +dasd_3990_erp_restart_queue (unsigned long erp) +{ + ccw_req_t *cqr = (void *) erp; + dasd_device_t *device = cqr->device; + unsigned long flags; + + /* get the needed locks to modify the request queue */ + s390irq_spin_lock_irqsave (device->devinfo.irq, + flags); + + /* 'restart' the device queue */ + if (cqr->status == CQR_STATUS_PENDING){ + + DASD_MESSAGE (KERN_INFO, device, + "%s", + "request queue restarted by MIH"); + + check_then_set (&cqr->status, + CQR_STATUS_PENDING, + CQR_STATUS_QUEUED); + } + + /* release the lock */ + s390irq_spin_unlock_irqrestore (device->devinfo.irq, + flags); + + dasd_schedule_bh(device); + +} /* end dasd_3990_erp_restart_queue */ + +#ifdef ERP_FULL_ERP +/* + * DASD_3990_ERP_INT_REQ + * + * DESCRIPTION + * Handles 'Intervention Required' error. + * This means either device offline or not installed. + * + * PARAMETER + * erp current erp + * RETURN VALUES + * erp modified erp + */ +ccw_req_t * +dasd_3990_erp_int_req (ccw_req_t *erp) +{ + dasd_device_t *device = erp->device; + /* first time set initial retry counter and erp_function */ + if (erp->function != dasd_3990_erp_int_req) { + erp->retries = 256; + erp->function = dasd_3990_erp_int_req; + } + + /* issue a message and wait for 'device ready' interrupt */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "is offline or not installed - " + "INTERVENTION REQUIRED!!\n"); + + dasd_3990_erp_block_queue (erp, + 60); + + return erp; + +} /* end dasd_3990_erp_int_req */ +#endif /* ERP_FULL_ERP */ + +/* + * DASD_3990_ERP_ALTERNATE_PATH + * + * DESCRIPTION + * Repeat the operation on a different channel path. + * If all alternate paths have been tried, the request is posted with a + * permanent error. + * + * PARAMETER + * erp pointer to the current ERP + * + * RETURN VALUES + * erp modified pointer to the ERP + * + */ +void +dasd_3990_erp_alternate_path (ccw_req_t *erp) +{ + + dasd_device_t *device = erp->device; + int irq = device->devinfo.irq; + + /* dissable current channel path - this causes the use of an other + channel path if there is one.. */ + + DASD_MESSAGE (KERN_WARNING, device, + "disable lpu %x", + erp->dstat->lpum); + + /* try alternate valid path */ + erp->lpm &= ~(erp->dstat->lpum); + erp->options |= DOIO_VALID_LPM; /* use LPM for DO_IO */ + + if ((erp->lpm & ioinfo[irq]->opm) != 0x00) { + + DASD_MESSAGE (KERN_WARNING, device, + "try alternate lpm %x", + erp->lpm); + + /* reset status to queued to handle the request again... */ + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + + erp->retries = 1; + } else { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "No alternate channel path left -> " + "permanent error"); + + /* post request with permanent error */ + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); - /* examine the 24 byte sense data */ - return dasd_3990_erp_examine_24 (sense); + } + +} /* end dasd_3990_erp_alternate_path */ + +#ifdef ERP_FULL_ERP +/* + * DASD_3990_ERP_DCTL + * + * DESCRIPTION + * Setup cqr to do the Diagnostic Control (DCTL) command with an + * Inhibit Write subcommand (0x20) and the given modifier. + * + * PARAMETER + * erp pointer to the current ERP + * modifier subcommand modifier + * + * RETURN VALUES + * dctl_cqr pointer to NEW dctl_cqr + * + */ +ccw_req_t * +dasd_3990_erp_DCTL (ccw_req_t *erp, + char modifier) +{ + DCTL_data_t *DCTL_data; + ccw1_t *ccw; + ccw_req_t *dctl_cqr = dasd_alloc_request ((char *) &erp->magic, + 1, + sizeof(DCTL_data_t)); + + if (dctl_cqr == NULL) { + BUG(); + } + + DCTL_data = dctl_cqr->data; + + DCTL_data->subcommand = 0x02; /* Inhibit Write */ + DCTL_data->modifier = modifier; + + ccw = dctl_cqr->cpaddr; + memset (ccw, 0, sizeof (ccw1_t)); + ccw->cmd_code = CCW_CMD_DCTL; + ccw->count = 4; + set_normalized_cda(ccw, __pa (DCTL_data)); + + dctl_cqr->function = dasd_3990_erp_DCTL; + dctl_cqr->refers = erp; + dctl_cqr->device = erp->device; + dctl_cqr->magic = erp->magic; + dctl_cqr->lpm = LPM_ANYPATH; + dctl_cqr->expires = 5 * TOD_MIN; + dctl_cqr->retries = 2; + asm volatile ("STCK %0":"=m" (dctl_cqr->buildclk)); + + dctl_cqr->status = CQR_STATUS_FILLED; + + return dctl_cqr; + +} /* end dasd_3990_erp_DCTL */ +#endif /* ERP_FULL_ERP */ + +/* + * DASD_3990_ERP_ACTION_1 + * + * DESCRIPTION + * Setup ERP to do the ERP action 1 (see Reference manual). + * Repeat the operation on a different channel path. + * If all alternate paths have been tried, the request is posted with a + * permanent error. + * Note: duplex handling is not implemented (yet). + * + * PARAMETER + * erp pointer to the current ERP + * + * RETURN VALUES + * erp pointer to the ERP + * + */ +ccw_req_t * +dasd_3990_erp_action_1 (ccw_req_t *erp) +{ + erp->function = dasd_3990_erp_action_1; + + dasd_3990_erp_alternate_path (erp); + + return erp; + +} /* end dasd_3990_erp_action_1 */ + +/* + * DASD_3990_ERP_ACTION_4 + * + * DESCRIPTION + * Setup ERP to do the ERP action 4 (see Reference manual). + * Set the current request to PENDING to block the CQR queue for that device + * until the state change interrupt appears. + * Use a timer (20 seconds) to retry the cqr if the interrupt is still missing. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the current ERP + * + * RETURN VALUES + * erp pointer to the ERP + * + */ +ccw_req_t * +dasd_3990_erp_action_4 (ccw_req_t *erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + /* first time set initial retry counter and erp_function */ + /* and retry once without waiting for state change pending */ + /* interrupt (this enables easier enqueing of the cqr) */ + if (erp->function != dasd_3990_erp_action_4) { + erp->retries = 255; + erp->function = dasd_3990_erp_action_4; + + } else { + + if (sense[25] & 0x1D) { /* state change pending */ + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "waiting for state change pending " + "int"); + + dasd_3990_erp_block_queue (erp, + 30); + + } else { + /* no state change pending - retry */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "no state change pending - retry"); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + } + } + + return erp; + +} /* end dasd_3990_erp_action_4 */ + +/* + ***************************************************************************** + * 24 byte sense ERP functions (only) + ***************************************************************************** + */ + +#ifdef ERP_FULL_ERP +/* + * DASD_3990_ERP_ACTION_5 + * + * DESCRIPTION + * Setup ERP to do the ERP action 5 (see Reference manual). + * + * PARAMETER + * erp pointer to the current ERP + * + * RETURN VALUES + * erp pointer to the ERP + * + */ +ccw_req_t * +dasd_3990_erp_action_5 (ccw_req_t *erp) +{ + /* first of all retry */ + erp->retries = 10; + erp->function = dasd_3990_erp_action_5; + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + + /* further handling is done in xxx_further_erp after the retries */ + + return erp; + +} /* end dasd_3990_erp_action_5 */ + +/* + * DASD_3990_HANDLE_ENV_DATA + * + * DESCRIPTION + * Handles 24 byte 'Enviromental data present'. + * Does a analysis of the sense data (message Format) + * and prints the error messages. + * + * PARAMETER + * sense current sense data + * + * RETURN VALUES + * void + */ +void +dasd_3990_handle_env_data (char *sense) +{ + /* check bytes 7-23 for further information */ + + char msg_format = (sense[7] & 0xF0); + char msg_no = (sense[7] & 0x0F); + + switch (msg_format) { + case 0x00: /* Format 0 - Program or System Checks */ + + if (sense[1] & 0x10) { /* check message to operator bit */ + + switch (msg_no) { + case 0x00: /* No Message */ + break; + case 0x01: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Invalid Command\n"); + break; + case 0x02: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Invalid Command Sequence\n"); + break; + case 0x03: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - CCW Count less than " + "required\n"); + break; + case 0x04: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Invalid Parameter\n"); + break; + case 0x05: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Diagnostic of Sepecial " + "Command Violates File Mask\n"); + break; + case 0x07: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Channel Returned with " + "Incorrect retry CCW\n"); + break; + case 0x08: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Reset Notification\n"); + break; + case 0x09: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Storage Path Restart\n"); + break; + case 0x0A: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Channel requested ... %02x\n", + sense[8]); + break; + case 0x0B: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Invalid Defective/Alternate " + "Track Pointer\n"); + break; + case 0x0C: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - DPS Installation Check\n"); + break; + case 0x0E: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Command Invalid on Secondary " + "Address\n"); + break; + case 0x0F: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Status Not As Required: " + "reason %02x\n", + sense[8]); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Reseved\n"); + } + } else { + switch (msg_no) { + case 0x00: /* No Message */ + break; + case 0x01: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Device Error Source\n"); + break; + case 0x02: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Reserved\n"); + break; + case 0x03: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Device Fenced - device = " + "%02x\n", + sense[4]); + break; + case 0x04: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Data Pinned for Device\n"); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Reserved\n"); + } + } + break; + + case 0x10: /* Format 1 - Device Equipment Checks */ + switch (msg_no) { + case 0x00: /* No Message */ + break; + case 0x01: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Device Status 1 not as " + "expected\n"); + break; + case 0x03: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Index missing\n"); + break; + case 0x04: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Interruption cannot be reset\n"); + break; + case 0x05: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Device did not respond to " + "selection\n"); + break; + case 0x06: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Device check-2 error or Set " + "Sector is not complete\n"); + break; + case 0x07: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Head address does not compare\n"); + break; + case 0x08: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Device status 1 not valid\n"); + break; + case 0x09: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Device not ready\n"); + break; + case 0x0A: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Track physical address did " + "not compare\n"); + break; + case 0x0B: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Missing device address bit\n"); + break; + case 0x0C: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Drive motor switch is off\n"); + break; + case 0x0D: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Seek incomplete\n"); + break; + case 0x0E: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Cylinder address did not " + "compare\n"); + break; + case 0x0F: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Offset active cannot be reset\n"); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Reserved\n"); + } + break; + + case 0x20: /* Format 2 - 3990 Equipment Checks */ + switch (msg_no) { + case 0x08: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 2 - 3990 check-2 error\n"); + break; + case 0x0E: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 2 - Support facility errors\n"); + break; + case 0x0F: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 2 - Microcode detected error %02x\n", + sense[8]); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 2 - Reserved\n"); + } + break; + + case 0x30: /* Format 3 - 3990 Control Checks */ + switch (msg_no) { + case 0x0F: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 3 - Allegiance terminated\n"); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 3 - Reserved\n"); + } + break; + + case 0x40: /* Format 4 - Data Checks */ + switch (msg_no) { + case 0x00: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - Home address area error\n"); + break; + case 0x01: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - Count area error\n"); + break; + case 0x02: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - Key area error\n"); + break; + case 0x03: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - Data area error\n"); + break; + case 0x04: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - No sync byte in home address area\n"); + break; + case 0x05: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - No syn byte in count address area\n"); + break; + case 0x06: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - No sync byte in key area\n"); + break; + case 0x07: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - No syn byte in data area\n"); + break; + case 0x08: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - Home address area error; " + "offset active\n"); + break; + case 0x09: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - Count area error; offset active\n"); + break; + case 0x0A: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - Key area error; offset active\n"); + break; + case 0x0B: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - Data area error; offset active\n"); + break; + case 0x0C: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - No sync byte in home address area; " + "offset active\n"); + break; + case 0x0D: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - No syn byte in count address area; " + "offset active\n"); + break; + case 0x0E: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - No sync byte in key area; " + "offset active\n"); + break; + case 0x0F: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - No syn byte in data area; " + "offset active\n"); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - Reserved\n"); + } + break; + + case 0x50: /* Format 5 - Data Check with displacement information */ + switch (msg_no) { + case 0x00: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 5 - Data Check in the home address area\n"); + break; + case 0x01: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 5 - Data Check in the count area\n"); + break; + case 0x02: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 5 - Data Check in the key area\n"); + break; + case 0x03: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 5 - Data Check in the data area\n"); + break; + case 0x08: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 5 - Data Check in the home address area; " + "offset active\n"); + break; + case 0x09: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 5 - Data Check in the count area; " + "offset active\n"); + break; + case 0x0A: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 5 - Data Check in the key area; " + "offset active\n"); + break; + case 0x0B: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 5 - Data Check in the data area; " + "offset active\n"); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 5 - Reserved\n"); + } + break; + + case 0x60: /* Format 6 - Usage Statistics/Overrun Errors */ + switch (msg_no) { + case 0x00: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 6 - Overrun on channel A\n"); + break; + case 0x01: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 6 - Overrun on channel B\n"); + break; + case 0x02: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 6 - Overrun on channel C\n"); + break; + case 0x03: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 6 - Overrun on channel D\n"); + break; + case 0x04: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 6 - Overrun on channel E\n"); + break; + case 0x05: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 6 - Overrun on channel F\n"); + break; + case 0x06: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 6 - Overrun on channel G\n"); + break; + case 0x07: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 6 - Overrun on channel H\n"); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 6 - Reserved\n"); + } + break; + + case 0x70: /* Format 7 - Device Connection Control Checks */ + switch (msg_no) { + case 0x00: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - RCC initiated by a connection " + "check alert\n"); + break; + case 0x01: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - RCC 1 sequence not successful\n"); + break; + case 0x02: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - RCC 1 and RCC 2 sequences not " + "successful\n"); + break; + case 0x03: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - Invalid tag-in during selection " + "sequence\n"); + break; + case 0x04: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - extra RCC required\n"); + break; + case 0x05: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - Invalid DCC selection response " + "or timeout\n"); + break; + case 0x06: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - Missing end operation; device " + "transfer complete\n"); + break; + case 0x07: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - Missing end operation; device " + "transfer incomplete\n"); + break; + case 0x08: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - Invalid tag-in for an immediate " + "command sequence\n"); + break; + case 0x09: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - Invalid tag-in for an extended " + "command sequence\n"); + break; + case 0x0A: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - 3990 microcode time out when " + "stopping selection\n"); + break; + case 0x0B: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - No response to selection after " + "a poll interruption\n"); + break; + case 0x0C: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - Permanent path error (DASD " + "controller not available)\n"); + break; + case 0x0D: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - DASD controller not available on " + "disconnected command chain\n"); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - Reserved\n"); + } + break; + + case 0x80: /* Format 8 - Additional Device Equipment Checks */ + switch (msg_no) { + case 0x00: /* No Message */ + case 0x01: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 8 - Error correction code hardware " + "fault\n"); + break; + case 0x03: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 8 - Unexpected end operation response " + "code\n"); + break; + case 0x04: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 8 - End operation with transfer count " + "not zero\n"); + break; + case 0x05: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 8 - End operation with transfer " + "count zero\n"); + break; + case 0x06: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 8 - DPS checks after a system reset or " + "selective reset\n"); + break; + case 0x07: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 8 - DPS cannot be filled\n"); + break; + case 0x08: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 8 - Short busy time-out during device " + "selection\n"); + break; + case 0x09: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 8 - DASD controller failed to set or " + "reset the long busy latch\n"); + break; + case 0x0A: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 8 - No interruption from device during " + "a command chain\n"); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 8 - Reserved\n"); + } + break; + + case 0x90: /* Format 9 - Device Read, Write, and Seek Checks */ + switch (msg_no) { + case 0x00: + break; /* No Message */ + case 0x06: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 9 - Device check-2 error\n"); + break; + case 0x07: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 9 - Head address did not compare\n"); + break; + case 0x0A: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 9 - Track physical address did not " + "compare while oriented\n"); + break; + case 0x0E: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 9 - Cylinder address did not compare\n"); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 9 - Reserved\n"); + } + break; + + case 0xF0: /* Format F - Cache Storage Checks */ + switch (msg_no) { + case 0x00: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Operation Terminated\n"); + break; + case 0x01: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Subsystem Processing Error\n"); + break; + case 0x02: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Cache or nonvolatile storage " + "equipment failure\n"); + break; + case 0x04: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Caching terminated\n"); + break; + case 0x06: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Cache fast write access not " + "authorized\n"); + break; + case 0x07: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Track format incorrect\n"); + break; + case 0x09: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Caching reinitiated\n"); + break; + case 0x0A: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Nonvolatile storage terminated\n"); + break; + case 0x0B: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Volume is suspended duplex\n"); + break; + case 0x0C: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Subsystem status connot be " + "determined\n"); + break; + case 0x0D: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Caching status reset to default\n"); + break; + case 0x0E: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - DASD Fast Write inhibited\n"); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT D - Reserved\n"); + } + break; + + default: /* unknown message format - should not happen */ + + } /* end switch message format */ + +} /* end dasd_3990_handle_env_data */ + +/* + * DASD_3990_ERP_COM_REJ + * + * DESCRIPTION + * Handles 24 byte 'Command Reject' error. + * + * PARAMETER + * erp current erp_head + * sense current sense data + * + * RETURN VALUES + * erp 'new' erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_com_rej (ccw_req_t *erp, + char *sense) +{ + dasd_device_t *device = erp->device; + ccw_req_t *cqr = NULL; + + erp->function = dasd_3990_erp_com_rej; + + /* env data present (ACTION 10 - retry should work) */ + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Command Reject - environmental data present\n"); + + dasd_3990_handle_env_data (sense); + + erp->retries = 5; + + } else { + /* fatal error - set status to FAILED */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Command Reject - Fatal error\n"); + + cqr = erp->refers; + + dasd_free_request (erp); + + erp = cqr; + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + + } + + return erp; + +} /* end dasd_3990_erp_com_rej */ + +/* + * DASD_3990_ERP_BUS_OUT + * + * DESCRIPTION + * Handles 24 byte 'Bus Out Parity Check' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_bus_out (ccw_req_t *erp) +{ + dasd_device_t *device = erp->device; + + /* first time set initial retry counter and erp_function */ + if (erp->function != dasd_3990_erp_bus_out) { + erp->retries = 256; + erp->function = dasd_3990_erp_bus_out; + } + + /* issue a message and wait for 'device ready' interrupt */ + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "bus out parity error or BOPC requested by channel\n"); + + dasd_3990_erp_block_queue (erp, + 60); + + return erp; + +} /* end dasd_3990_erp_bus_out */ +#endif /* ERP_FULL_ERP */ + +/* + * DASD_3990_ERP_EQUIP_CHECK + * + * DESCRIPTION + * Handles 24 byte 'Equipment Check' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_equip_check (ccw_req_t *erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_equip_check; + +#ifdef ERP_FULL_ERP + if (sense[1] & SNS1_WRITE_INHIBITED) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Write inhibited path encountered"); + + /* vary path offline */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Path should be varied off-line. " + "This is not implemented yet \n - please report to " + "linux390@de.ibm.com"); + + erp = dasd_3990_erp_action_1 (erp); + + } else +#endif /* ERP_FULL_ERP */ + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Equipment Check - " + "environmental data present"); +#ifdef ERP_FULL_ERP + dasd_3990_handle_env_data (sense); +#endif /* ERP_FULL_ERP */ + + erp = dasd_3990_erp_action_4 (erp, + sense); + +#ifdef ERP_FULL_ERP + } else if (sense[1] & SNS1_PERM_ERR) { + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Equipment Check - retry exhausted or " + "undesirable\n"); + + erp = dasd_3990_erp_action_1 (erp); + + } else { + /* all other equipment checks - Action 5 */ + /* rest is done when retries == 0 */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Equipment check or processing error\n"); + + erp = dasd_3990_erp_action_5 (erp); +#endif /* ERP_FULL_ERP */ + } + + return erp; + +} /* end dasd_3990_erp_equip_check */ + +/* + * DASD_3990_ERP_DATA_CHECK + * + * DESCRIPTION + * Handles 24 byte 'Data Check' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_data_check (ccw_req_t *erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_data_check; + +#ifdef ERP_FULL_ERP + if (sense[2] & SNS2_CORRECTABLE) { /* correctable data check */ + + /* issue message that the data has been corrected */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Data recovered during retry with PCI " + "fetch mode active\n"); + + /* not possible to handle this situation in Linux */ + panic("No way to inform appliction about the possibly " + "incorret data"); + + } else if (sense[2] & SNS2_ENV_DATA_PRESENT) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Uncorrectable data check recovered secondary " + "addr of duplex pair"); + + erp = dasd_3990_erp_action_4 (erp, + sense); + + } else if (sense[1] & SNS1_PERM_ERR) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Uncorrectable data check with internal " + "retry exhausted\n"); + + erp = dasd_3990_erp_action_1 (erp); + + } else { + /* all other data checks */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Uncorrectable data check with retry count " + "exhausted...\n"); + + erp = dasd_3990_erp_action_5 (erp); + } + +#else + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Uncorrectable data check recovered secondary " + "addr of duplex pair"); + + erp = dasd_3990_erp_action_4 (erp, + sense); + } +#endif /* ERP_FULL_ERP */ + + return erp; + +} /* end dasd_3990_erp_data_check */ + +#ifdef ERP_FULL_ERP +/* + * DASD_3990_ERP_OVERRUN + * + * DESCRIPTION + * Handles 24 byte 'Overrun' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_overrun (ccw_req_t *erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_overrun; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Overrun - service overrun or overrun" + " error requested by channel\n"); + + erp = dasd_3990_erp_action_5 (erp); + + return erp; + +} /* end dasd_3990_erp_overrun */ +#endif /* ERP_FULL_ERP */ + +/* + * DASD_3990_ERP_INV_FORMAT + * + * DESCRIPTION + * Handles 24 byte 'Invalid Track Format' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_inv_format (ccw_req_t *erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_inv_format; + + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Track format error when destaging or " + "staging data"); + +#ifdef ERP_FULL_ERP + dasd_3990_handle_env_data (sense); + + erp = dasd_3990_erp_action_4 (erp, + sense); + + } else { + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Invalid Track Format - Fatal error should have " + "been handled within the interrupt handler\n"); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + } +#else + erp = dasd_3990_erp_action_4 (erp, + sense); + } +#endif /* ERP_FULL_ERP */ + + return erp; + +} /* end dasd_3990_erp_inv_format */ + +#ifdef ERP_FULL_ERP +/* + * DASD_3990_ERP_EOC + * + * DESCRIPTION + * Handles 24 byte 'End-of-Cylinder' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_EOC (ccw_req_t *erp, + char *sense) +{ + + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_EOC; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "End-of-Cylinder - must never happen\n"); + + /* implement action 7 */ + BUG(); + + return erp; + +} /* end dasd_3990_erp_EOC */ +#endif /* ERP_FULL_ERP */ + +/* + * DASD_3990_ERP_ENV_DATA + * + * DESCRIPTION + * Handles 24 byte 'Environmental-Data Present' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_env_data (ccw_req_t *erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_env_data; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Environmental data present"); +#ifdef ERP_FULL_ERP + dasd_3990_handle_env_data (sense); +#endif /* ERP_FULL_ERP */ + + erp = dasd_3990_erp_action_4 (erp, + sense); + + return erp; + +} /* end dasd_3990_erp_env_data */ + +#ifdef ERP_FULL_ERP +/* + * DASD_3990_ERP_NO_REC + * + * DESCRIPTION + * Handles 24 byte 'No Record Found' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_no_rec (ccw_req_t *erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_no_rec; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "No Record Found - Fatal error should " + "have been handled within the interrupt handler\n"); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + + return erp; + +} /* end dasd_3990_erp_no_rec */ + +/* + * DASD_3990_ERP_FILE_PROT + * + * DESCRIPTION + * Handles 24 byte 'File Protected' error. + * Note: Seek related recovery is not implemented because + * wee don't use the seek command yet. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_file_prot (ccw_req_t *erp) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_file_prot; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "File Protected\n"); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + + return erp; + +} /* end dasd_3990_erp_file_prot */ +#endif /* ERP_FULL_ERP */ + +/* + * DASD_3990_ERP_INSPECT_24 + * + * DESCRIPTION + * Does a detailed inspection of the 24 byte sense data + * and sets up a related error recovery action. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the currently created default ERP + * + * RETURN VALUES + * erp pointer to the (addtitional) ERP + */ +ccw_req_t * +dasd_3990_erp_inspect_24 ( ccw_req_t *erp, + char *sense) +{ + ccw_req_t *erp_filled = NULL; + dasd_device_t *device = erp->device; + + /* Check sense for .... */ +#ifdef ERP_FULL_ERP + /* 'Command Reject' */ + if ((erp_filled == NULL) && + (sense[0] & SNS0_CMD_REJECT)) { + erp_filled = dasd_3990_erp_com_rej (erp, + sense); + } + /* 'Intervention Required' */ + if ((erp_filled == NULL) && + (sense[0] & SNS0_INTERVENTION_REQ)) { + erp_filled = dasd_3990_erp_int_req (erp); + } + /* 'Bus Out Parity Check' */ + if ((erp_filled == NULL) && + (sense[0] & SNS0_BUS_OUT_CHECK)) { + erp_filled = dasd_3990_erp_bus_out (erp); + } +#endif /* ERP_FULL_ERP */ + /* 'Equipment Check' */ + if ((erp_filled == NULL) && + (sense[0] & SNS0_EQUIPMENT_CHECK)) { + erp_filled = dasd_3990_erp_equip_check (erp, + sense); + } + /* 'Data Check' */ + if ((erp_filled == NULL) && + (sense[0] & SNS0_DATA_CHECK)) { + erp_filled = dasd_3990_erp_data_check (erp, + sense); + } +#ifdef ERP_FULL_ERP + /* 'Overrun' */ + if ((erp_filled == NULL) && + (sense[0] & SNS0_OVERRUN)) { + erp_filled = dasd_3990_erp_overrun (erp, + sense); + } +#endif /* ERP_FULL_ERP */ + /* 'Invalid Track Format' */ + if ((erp_filled == NULL) && + (sense[1] & SNS1_INV_TRACK_FORMAT)) { + erp_filled = dasd_3990_erp_inv_format (erp, + sense); + } +#ifdef ERP_FULL_ERP + /* 'End-of-Cylinder' */ + if ((erp_filled == NULL) && + (sense[1] & SNS1_EOC)) { + erp_filled = dasd_3990_erp_EOC (erp, + sense); + } +#endif /* ERP_FULL_ERP */ + /* 'Environmental Data' */ + if ((erp_filled == NULL) && + (sense[2] & SNS2_ENV_DATA_PRESENT)) { + erp_filled = dasd_3990_erp_env_data (erp, + sense); + } +#ifdef ERP_FULL_ERP + /* 'No Record Found' */ + if ((erp_filled == NULL) && + (sense[1] & SNS1_NO_REC_FOUND)) { + erp_filled = dasd_3990_erp_no_rec (erp, + sense); + } + /* 'File Protected' */ + if ((erp_filled == NULL) && + (sense[1] & SNS1_FILE_PROTECTED)) { + erp_filled = dasd_3990_erp_file_prot (erp); + } +#endif /* ERP_FULL_ERP */ + + /* other (unknown) error - do default ERP */ + if (erp_filled == NULL) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "default ERP taken"); + + erp_filled = erp; + } + + return erp_filled; + +} /* END dasd_3990_erp_inspect_24 */ + +/* + ***************************************************************************** + * 32 byte sense ERP functions (only) + ***************************************************************************** + */ + +#ifdef ERP_FULL_ERP +/* + * DASD_3990_ERPACTION_10_32 + * + * DESCRIPTION + * Handles 32 byte 'Action 10' of Single Program Action Codes. + * Just retry and if retry doesn't work, return with error. + * + * PARAMETER + * erp current erp_head + * sense current sense data + * RETURN VALUES + * erp modified erp_head + */ +ccw_req_t * +dasd_3990_erp_action_10_32 (ccw_req_t *erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->retries = 256; + erp->function = dasd_3990_erp_action_10_32; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Perform logging requested\n"); + + return erp; + +} /* end dasd_3990_erp_action_10_32 */ +#endif /* ERP_FULL_ERP */ + +/* + * DASD_3990_ERP_ACTION_1B_32 + * + * DESCRIPTION + * Handles 32 byte 'Action 1B' of Single Program Action Codes. + * A write operation could not be finished because of an unexpected + * condition. + * The already created 'default erp' is used to get the link to + * the erp chain, but it can not be used for this recovery + * action because it contains no DE/LO data space. + * + * PARAMETER + * default_erp already created default erp. + * sense current sense data + * RETURN VALUES + * erp new erp or + * default_erp in case of imprecise ending or error + */ +ccw_req_t * +dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp, + char *sense) +{ + dasd_device_t *device = default_erp->device; + __u32 cpa = 0; + ccw_req_t *cqr; + ccw_req_t *erp; + DE_eckd_data_t *DE_data; + char *LO_data; /* LO_eckd_data_t */ + ccw1_t *ccw; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Write not finsihed because of unexpected condition"); + + default_erp->function = dasd_3990_erp_action_1B_32; + + /* determine the original cqr */ + cqr = default_erp; + while (cqr->refers != NULL){ + cqr = cqr->refers; + } + + /* for imprecise ending just do default erp */ + if (sense[1] & 0x01) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Imprecise ending is set - just retry"); + + return default_erp; + } + + /* determine the address of the CCW to be restarted */ + /* Imprecise ending is not set -> addr from IRB-SCSW */ + cpa = default_erp->refers->dstat->cpa; + + if (cpa == 0) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Unable to determine address of the CCW " + "to be restarted"); + + check_then_set (&default_erp->status, + CQR_STATUS_FILLED, + CQR_STATUS_FAILED); + + return default_erp; + } + + /* Build new ERP request including DE/LO */ + erp = dasd_alloc_request ((char *) &cqr->magic, + 2 + 1, /* DE/LO + TIC */ + sizeof (DE_eckd_data_t) + + sizeof (LO_eckd_data_t)); + + if ( !erp ) { + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Unable to allocate ERP"); + + check_then_set (&default_erp->status, + CQR_STATUS_FILLED, + CQR_STATUS_FAILED); + + return default_erp; + } + + /* use original DE */ + DE_data = erp->data; + memcpy (DE_data, + cqr->data, + sizeof (DE_eckd_data_t)); + + /* create LO */ + LO_data = erp->data + sizeof (DE_eckd_data_t); + + if ((sense[3] == 0x01) && + (LO_data[1] & 0x01) ){ + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "BUG - this should not happen"); + //BUG(); /* check for read count suffixing n.a. */ + } + + if ((sense[7] & 0x3F) == 0x01) { + /* operation code is WRITE DATA -> data area orientation */ + LO_data[0] = 0x81; + + } else if ((sense[7] & 0x3F) == 0x03) { + /* operation code is FORMAT WRITE -> index orientation */ + LO_data[0] = 0xC3; + + } else { + LO_data[0] = sense[7]; /* operation */ + } + + LO_data[1] = sense[8]; /* auxiliary */ + LO_data[2] = sense[9]; + LO_data[3] = sense[3]; /* count */ + LO_data[4] = sense[29]; /* seek_addr.cyl */ + LO_data[5] = sense[30]; /* seek_addr.cyl 2nd byte */ + LO_data[7] = sense[31]; /* seek_addr.head 2nd byte */ + + memcpy (&(LO_data[8]), &(sense[11]), 8); + + /* create DE ccw */ + ccw = erp->cpaddr; + memset (ccw, 0, sizeof (ccw1_t)); + ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT; + ccw->flags = CCW_FLAG_CC; + ccw->count = 16; + set_normalized_cda (ccw, __pa (DE_data)); + + /* create LO ccw */ + ccw++; + memset (ccw, 0, sizeof (ccw1_t)); + ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD; + ccw->flags = CCW_FLAG_CC; + ccw->count = 16; + set_normalized_cda (ccw, __pa (LO_data)); + + /* TIC to the failed ccw */ + ccw++; + ccw->cmd_code = CCW_CMD_TIC; + ccw->cda = cpa; + + /* fill erp related fields */ + erp->function = dasd_3990_erp_action_1B_32; + erp->refers = default_erp->refers; + erp->device = device; + erp->magic = default_erp->magic; + erp->lpm = 0xFF; + erp->expires = 0; + erp->retries = 255; + erp->status = CQR_STATUS_FILLED; + + /* remove the default erp */ + dasd_free_request (default_erp); + + return erp; + +} /* end dasd_3990_erp_action_1B_32 */ + +/* + * DASD_3990_UPDATE_1B + * + * DESCRIPTION + * Handles the update to the 32 byte 'Action 1B' of Single Program + * Action Codes in case the first action was not successful. + * The already created 'previous_erp' is the currently not successful + * ERP. + * + * PARAMETER + * previous_erp already created previous erp. + * sense current sense data + * RETURN VALUES + * erp modified erp + */ +ccw_req_t * +dasd_3990_update_1B (ccw_req_t *previous_erp, + char *sense) +{ + dasd_device_t *device = previous_erp->device; + __u32 cpa = 0; + ccw_req_t *cqr; + ccw_req_t *erp; + char *LO_data; /* LO_eckd_data_t */ + ccw1_t *ccw; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Write not finsihed because of unexpected condition" + " - follow on"); + + /* determine the original cqr */ + cqr = previous_erp; + while (cqr->refers != NULL){ + cqr = cqr->refers; + } + + /* for imprecise ending just do default erp */ + if (sense[1] & 0x01) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Imprecise ending is set - just retry"); + + check_then_set (&previous_erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + + return previous_erp; + } + + /* determine the address of the CCW to be restarted */ + /* Imprecise ending is not set -> addr from IRB-SCSW */ + cpa = previous_erp->dstat->cpa; + + if (cpa == 0) { + ccw = cqr->cpaddr; /* addr of first data transfer */ + ccw++; /* command in domain */ + ccw++; + cpa = (__u32) ccw; + } + + if (cpa == 0) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Unable to determine address of the CCW " + "to be restarted"); + + check_then_set (&previous_erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + + return previous_erp; + } + + erp = previous_erp; + + /* update the LO with the new returned sense data */ + LO_data = erp->data + sizeof (DE_eckd_data_t); + + if ((sense[3] == 0x01) && + (LO_data[1] & 0x01) ){ + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "BUG - this should not happen"); + //BUG(); /* check for read count suffixing n.a. */ + } + + if ((sense[7] & 0x3F) == 0x01) { + /* operation code is WRITE DATA -> data area orientation */ + LO_data[0] = 0x81; + + } else if ((sense[7] & 0x3F) == 0x03) { + /* operation code is FORMAT WRITE -> index orientation */ + LO_data[0] = 0xC3; + + } else { + LO_data[0] = sense[7]; /* operation */ + } + + LO_data[1] = sense[8]; /* auxiliary */ + LO_data[2] = sense[9]; + LO_data[3] = sense[3]; /* count */ + LO_data[4] = sense[29]; /* seek_addr.cyl */ + LO_data[5] = sense[30]; /* seek_addr.cyl 2nd byte */ + LO_data[7] = sense[31]; /* seek_addr.head 2nd byte */ + + memcpy (&(LO_data[8]), &(sense[11]), 8); + + /* TIC to the failed ccw */ + ccw = erp->cpaddr; /* addr of DE ccw */ + ccw++; /* addr of LE ccw */ + ccw++; /* addr of TIC ccw */ + ccw->cda = cpa; + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + + return erp; + +} /* end dasd_3990_update_1B */ + +#ifdef ERP_FULL_ERP +/* + * DASD_3990_ERP_COMPOUND_RETRY + * + * DESCRIPTION + * Handles the compound ERP action retry code. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the currently created ERP + * + * RETURN VALUES + * erp modified ERP pointer + * + */ +void +dasd_3990_erp_compound_retry (ccw_req_t *erp, + char *sense) +{ + switch (sense[25] & 0x03) { + case 0x00: /* no not retry */ + erp->retries = 0; + break; + + case 0x01: /* retry 2 times */ + erp->retries = 2; + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + break; + + case 0x02: /* retry 10 times */ + erp->retries = 10; + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + break; + + case 0x03: /* retry 255 times */ + erp->retries = 255; + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + break; + + default: + BUG(); + } + + erp->function = dasd_3990_erp_compound_retry; + +} /* end dasd_3990_erp_compound_retry */ + +/* + * DASD_3990_ERP_COMPOUND_PATH + * + * DESCRIPTION + * Handles the compound ERP action for retry on alternate + * channel path. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the currently created ERP + * + * RETURN VALUES + * erp modified ERP pointer + * + */ +void +dasd_3990_erp_compound_path (ccw_req_t *erp, + char *sense) +{ + + if (sense[25] & DASD_SENSE_BIT_3) { + dasd_3990_erp_alternate_path (erp); + + if (erp->status == CQR_STATUS_FAILED) { + /* reset the lpm and the status to be able to + * try further actions. */ + + erp->lpm = LPM_ANYPATH; + + check_then_set (&erp->status, + CQR_STATUS_FAILED, + CQR_STATUS_ERROR); + + } + } + + erp->function = dasd_3990_erp_compound_path; + +} /* end dasd_3990_erp_compound_path */ + +/* + * DASD_3990_ERP_COMPOUND_CODE + * + * DESCRIPTION + * Handles the compound ERP action for retry code. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the currently created ERP + * + * RETURN VALUES + * erp NEW ERP pointer + * + */ +ccw_req_t * +dasd_3990_erp_compound_code (ccw_req_t *erp, + char *sense) +{ + + + if (sense[25] & DASD_SENSE_BIT_2) { + + switch (sense[28]) { + case 0x17: + /* issue a Diagnostic Control command with an + * Inhibit Write subcommand and controler modifier */ + erp = dasd_3990_erp_DCTL (erp, + 0x20); + break; + + case 0x25: + /* wait for 5 seconds and retry again */ + erp->retries = 1; + + dasd_3990_erp_block_queue (erp, + 5); + break; + + default: + BUG(); + } + } + + erp->function = dasd_3990_erp_compound_code; + + return erp; + +} /* end dasd_3990_erp_compound_code */ + +/* + * DASD_3990_ERP_COMPOUND_CONFIG + * + * DESCRIPTION + * Handles the compound ERP action for configruation + * dependent error. + * Note: duplex handling is not implemented (yet). + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the currently created ERP + * + * RETURN VALUES + * erp modified ERP pointer + * + */ +void +dasd_3990_erp_compound_config (ccw_req_t *erp, + char *sense) +{ + if ((sense[25] & DASD_SENSE_BIT_1) && + (sense[26] & DASD_SENSE_BIT_2) ) { + + /* set to suspended duplex state then restart */ + dasd_device_t *device = erp->device; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Set device to suspended duplex state should be done!\n" + "This is not implemented yet (for compound ERP)\n" + " - please report to linux390@de.ibm.com"); + + } + + erp->function = dasd_3990_erp_compound_config; + +} /* end dasd_3990_erp_compound_config */ + +/* + * DASD_3990_ERP_COMPOUND + * + * DESCRIPTION + * Does a detailed inspection of the 32 byte sense data + * and sets up a related error recovery action. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the currently created ERP + * + * RETURN VALUES + * erp (additional) ERP pointer + * + */ +ccw_req_t * +dasd_3990_erp_compound (ccw_req_t *erp, + char *sense) +{ + if ((erp->function != dasd_3990_erp_compound_retry ) && + (erp->function != dasd_3990_erp_compound_path ) && + (erp->function != dasd_3990_erp_compound_code ) && + (erp->function != dasd_3990_erp_compound_config) ) { + + /* called first time */ + dasd_3990_erp_compound_retry (erp, + sense); + } + + /* do further action if no retry is specified / left */ + if ((erp->function == dasd_3990_erp_compound_retry) && + (erp->status == CQR_STATUS_ERROR ) ){ + + dasd_3990_erp_compound_path (erp, + sense); + } + + if ((erp->function == dasd_3990_erp_compound_path) && + (erp->status == CQR_STATUS_ERROR ) ){ + + erp = dasd_3990_erp_compound_code (erp, + sense); + } + + if ((erp->function == dasd_3990_erp_compound_code) && + (erp->status == CQR_STATUS_ERROR ) ){ + + dasd_3990_erp_compound_config (erp, + sense); + } + + /* if no compound action ERP specified, the request failed */ + if (erp->status == CQR_STATUS_ERROR) { + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + } + + return erp; + +} /* end dasd_3990_erp_compound */ +#endif /* ERP_FULL_ERP */ + +/* + * DASD_3990_ERP_INSPECT_32 + * + * DESCRIPTION + * Does a detailed inspection of the 32 byte sense data + * and sets up a related error recovery action. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the currently created default ERP + * + * RETURN VALUES + * erp_filled pointer to the ERP + * + */ +ccw_req_t * +dasd_3990_erp_inspect_32 ( ccw_req_t *erp, + char *sense ) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_inspect_32; + + if (sense[25] & DASD_SENSE_BIT_0) { + + /* compound program action codes (byte25 bit 0 == '1') */ +#ifdef ERP_FULL_ERP + erp = dasd_3990_erp_compound (erp, + sense); +#else + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "default ERP taken"); +#endif /* ERP_FULL_ERP */ + + } else { + + /* single program action codes (byte25 bit 0 == '0') */ + switch (sense[25]) { +#ifdef ERP_FULL_ERP + case 0x00: /* success */ + DASD_MESSAGE (KERN_WARNING, device, + "ERP called for successful request %p" + " - NO ERP necessary", + erp); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_DONE); + break; + + case 0x01: /* fatal error */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Fatal error should " + "have been handled within the interrupt handler\n"); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + break; + + case 0x02: /* intervention required */ + case 0x03: /* intervention required during dual copy */ + erp = dasd_3990_erp_int_req (erp); + break; + + case 0x0F: /* length mismatch during update write command */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "update write command error - should not happen; " + "Please send this message together with the above " + "sense data to linux390@de.ibm.com\n"); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + break; + + case 0x10: /* logging required for other channel program */ + erp = dasd_3990_erp_action_10_32 (erp, + sense); + break; + + case 0x15: /* next track outside defined extend */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "next track outside defined extend - should not happen; " + "Please send this message together with the above " + "sense data to linux390@de.ibm.com\n"); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + break; +#endif /* ERP_FULL_ERP */ + + case 0x1B: /* unexpected condition during write */ + + erp = dasd_3990_erp_action_1B_32 (erp, + sense); + break; + +#ifdef ERP_FULL_ERP + case 0x1C: /* invalid data */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Data recovered during retry with PCI " + "fetch mode active\n"); + + /* not possible to handle this situation in Linux */ + panic("No way to inform appliction about the possibly " + "incorret data"); + break; +#endif /* ERP_FULL_ERP */ + + case 0x1D: /* state-change pending */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "A State change pending condition exists " + "for the subsystem or device"); + + erp = dasd_3990_erp_action_4 (erp, + sense); + break; + + default: /* all others errors */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "default ERP taken"); + } + } + + return erp; + +} /* end dasd_3990_erp_inspect_32 */ + +/* + ***************************************************************************** + * main ERP control fuctions (24 and 32 byte sense) + ***************************************************************************** + */ + +/* + * DASD_3990_ERP_INSPECT + * + * DESCRIPTION + * Does a detailed inspection for sense data by calling either + * the 24-byte or the 32-byte inspection routine. + * + * PARAMETER + * erp pointer to the currently created default ERP + * RETURN VALUES + * erp_new contens was possibly modified + */ +ccw_req_t * +dasd_3990_erp_inspect (ccw_req_t *erp) +{ + ccw_req_t *erp_new = NULL; + /* sense data are located in the refers record of the */ + /* already set up new ERP ! */ + char *sense = erp->refers->dstat->ii.sense.data; + + /* distinguish between 24 and 32 byte sense data */ + if (sense[27] & DASD_SENSE_BIT_0) { + + /* inspect the 24 byte sense data */ + erp_new = dasd_3990_erp_inspect_24 (erp, + sense); + + } else { + + /* inspect the 32 byte sense data */ + erp_new = dasd_3990_erp_inspect_32 (erp, + sense); + + } /* end distinguish between 24 and 32 byte sense data */ + + return erp_new; + +} /* END dasd_3990_erp_inspect */ + +/* + * DASD_3990_ERP_ADD_ERP + * + * DESCRIPTION + * This funtion adds an additional request block (ERP) to the head of + * the given cqr (or erp). + * This erp is initialized as an default erp (retry TIC) + * + * PARAMETER + * cqr head of the current ERP-chain (or single cqr if + * first error) + * RETURN VALUES + * erp pointer to new ERP-chain head + */ +ccw_req_t * +dasd_3990_erp_add_erp (ccw_req_t *cqr) +{ + /* allocate additional request block */ + ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0); + if ( !erp ) { + printk( KERN_WARNING PRINTK_HEADER + "unable to allocate ERP request\n" ); + return NULL; + } + + /* initialize request with default TIC to current ERP/CQR */ + erp->cpaddr->cmd_code = CCW_CMD_TIC; + erp->cpaddr->cda = ((__u32) cqr->cpaddr); + erp->function = dasd_3990_erp_add_erp; + erp->refers = cqr; + erp->device = cqr->device; + erp->magic = cqr->magic; + erp->lpm = 0xFF; + erp->expires = 0; + erp->retries = 255; + + erp->status = CQR_STATUS_FILLED; + + return erp; +} + +/* + * DASD_3990_ERP_ADDITIONAL_ERP + * + * DESCRIPTION + * An additional ERP is needed to handle the current error. + * Add ERP to the head of the ERP-chain containing the ERP processing + * determined based on the sense data. + * + * PARAMETER + * cqr head of the current ERP-chain (or single cqr if + * first error) + * + * RETURN VALUES + * erp pointer to new ERP-chain head + */ +ccw_req_t * +dasd_3990_erp_additional_erp (ccw_req_t *cqr) +{ + + ccw_req_t *erp = NULL; + + /* add erp and initialize with default TIC */ + erp = dasd_3990_erp_add_erp (cqr); + + /* inspect sense, determine specific ERP if possible */ + if (erp != NULL) { + erp = dasd_3990_erp_inspect (erp); + } + + return erp; + +} /* end dasd_3990_erp_additional_erp */ + +/* + * DASD_3990_ERP_ERROR_MATCH + * + * DESCRIPTION + * check if the the device status of the given cqr is the same. + * This means that the failed CCW and the relevant sense data + * must match. + * I don't distinguish between 24 and 32 byte sense becaus in case of + * 24 byte sense byte 25 and 27 is set as well. + * + * PARAMETER + * cqr1 first cqr, which will be compared with the + * cqr2 second cqr. + * + * RETURN VALUES + * match 'boolean' for match found + * returns 1 if match found, otherwise 0. + */ +int +dasd_3990_erp_error_match (ccw_req_t *cqr1, + ccw_req_t *cqr2) +{ + /* check failed CCW */ + if (cqr1->dstat->cpa != + cqr2->dstat->cpa) { + // return 0; /* CCW doesn't match */ + printk(KERN_WARNING PRINTK_HEADER + "_error_match: CCW doesn't match -> ignore\n"); + } + /* check sense data; byte 0-2,25,27 */ + if (!((strncmp (cqr1->dstat->ii.sense.data, + cqr2->dstat->ii.sense.data, + 3) == 0) && + (cqr1->dstat->ii.sense.data[27] == + cqr2->dstat->ii.sense.data[27] ) && + (cqr1->dstat->ii.sense.data[25] == + cqr2->dstat->ii.sense.data[25] ) )) { + + return 0; /* sense doesn't match */ + } + return 1; /* match */ + +} /* end dasd_3990_erp_error_match */ + +/* + * DASD_3990_ERP_IN_ERP + * + * DESCRIPTION + * check if the current error already happened before. + * quick exit if current cqr is not an ERP (cqr->refers=NULL) + * + * PARAMETER + * cqr failed cqr (either original cqr or already an erp) + * + * RETURN VALUES + * erp erp-pointer to the already defined error recovery procedure OR + * NULL if a 'new' error occurred. + */ +ccw_req_t * +dasd_3990_erp_in_erp (ccw_req_t *cqr) +{ + ccw_req_t *erp_head = cqr, /* save erp chain head */ + *erp_match = NULL; /* save erp chain head */ + int match = 0; /* 'boolean' for matching error found */ + + if (cqr->refers == NULL) { /* return if not in erp */ + return NULL; + } + /* check the erp/cqr chain for current error */ + do { + match = dasd_3990_erp_error_match (erp_head, + cqr->refers); + erp_match = cqr; /* save possible matching erp */ + cqr = cqr->refers; /* check next erp/cqr in queue */ + } while ((cqr->refers != NULL) && + (match == 0)); + + if (match) { + return erp_match; /* return address of matching erp */ + } else { + return NULL; /* return NULL to indicate that no match + was found */ + } + +} /* END dasd_3990_erp_in_erp */ + +/* + * DASD_3990_ERP_FURTHER_ERP (24 & 32 byte sense) + * + * DESCRIPTION + * No retry is left for the current ERP. Check what has to be done + * with the ERP. + * - do further defined ERP action or + * - wait for interrupt or + * - exit with permanent error + * + * PARAMETER + * erp ERP which is in progress wiht no retry left + * + * RETURN VALUES + * erp modified/additional ERP + */ +ccw_req_t * +dasd_3990_erp_further_erp (ccw_req_t *erp) +{ + dasd_device_t *device = erp->device; + +#ifdef ERP_FULL_ERP + /* check for 24 byte sense ERP */ + if ((erp->function == dasd_3990_erp_bus_out ) || + (erp->function == dasd_3990_erp_action_1) || + (erp->function == dasd_3990_erp_action_4) ){ + + erp = dasd_3990_erp_action_1 (erp); + + } else if (erp->function == dasd_3990_erp_action_5) { + + /* retries have not been successful */ + char *sense = erp->dstat->ii.sense.data; + + /* prepare erp for retry on different channel path */ + erp = dasd_3990_erp_action_1 (erp); + + if (!(sense[ 2] & DASD_SENSE_BIT_0)) { + + /* issue a Diagnostic Control command with an + * Inhibit Write subcommand */ + + switch (sense[25]) { + case 0x17: + case 0x57: { /* controller */ + erp = dasd_3990_erp_DCTL (erp, + 0x20); + break; + } + case 0x18: + case 0x58: { /* channel path */ + erp = dasd_3990_erp_DCTL (erp, + 0x40); + break; + } + case 0x19: + case 0x59: { /* storage director */ + erp = dasd_3990_erp_DCTL (erp, + 0x80); + break; + } + default: + DASD_MESSAGE (KERN_WARNING, device, + "invalid subcommand modifier 0x%x for " + "Diagnostic Control Command", + sense[25]); + } + } + +// /* check for 32 byte sense ERP */ +// } else if ((erp->function == dasd_3990_erp_xxx){ +#else + /* check for 24 byte sense ERP */ + if ((erp->function == dasd_3990_erp_action_1) || + (erp->function == dasd_3990_erp_action_4) ){ + + erp = dasd_3990_erp_action_1 (erp); +#endif /* ERP_FULL_ERP */ + + } else { + /* no retry left and no additional special handling necessary */ + DASD_MESSAGE (KERN_WARNING, device, + "no retries left for erp %p - " + "set status to FAILED", + erp); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + } + + return erp; + +} /* end dasd_3990_erp_further_erp */ + +/* + * DASD_3990_ERP_HANDLE_MATCH_ERP + * + * DESCRIPTION + * An error occurred again and an ERP has been detected which is already + * used to handle this error (e.g. retries). + * All prior ERP's are set to status DONE and the retry counter is + * decremented. + * If retry counter is already 0, it has to checked if further action + * is needed (besides retry) or if the ERP has failed. + * + * PARAMETER + * erp_head first ERP in ERP-chain + * erp_match ERP that handles the actual error. + * + * RETURN VALUES + * none + */ +void +dasd_3990_erp_handle_match_erp (ccw_req_t *erp_head, + ccw_req_t *erp_match) +{ + + dasd_device_t *device = erp_head->device; + ccw_req_t *erp_done = erp_head; + ccw_req_t *erp_free = NULL; /* req to be freed */ + + /* loop over successful ERPs and remove them from chanq */ + while ((erp_done != erp_match) && + (erp_done != NULL)) { + +#ifdef ERP_DEBUG + DASD_MESSAGE (KERN_WARNING, device, + "successful ERP - dequeue and free request %p", + (void *) erp_done); +#endif /* ERP_DEBUG */ + + check_then_set (&erp_done->status, + CQR_STATUS_ERROR, + CQR_STATUS_DONE); + + /* remove the request from the device queue */ + dasd_chanq_deq (&device->queue, + erp_done); + + erp_free = erp_done; + erp_done = erp_done->refers; + + /* free the finished erp request */ + dasd_free_request (erp_free); + + } + + if (erp_done == NULL) /* erp_done should never be NULL! */ + panic (PRINTK_HEADER "Programming error in ERP! The original " + "request was lost\n"); + +#ifdef ERP_DEBUG + /* handle matching ERP */ + DASD_MESSAGE (KERN_WARNING, device, + "handle matching erp %p", + (void *) erp_done); +#endif + + if (erp_done->retries > 0) { + + /* check for special retries */ + if (erp_done->function == dasd_3990_erp_action_4) { + char *sense = erp_done->dstat->ii.sense.data; + erp_done = dasd_3990_erp_action_4 (erp_done, + sense); + + } else if (erp_done->function == dasd_3990_erp_action_1B_32) { + char *sense = erp_done->dstat->ii.sense.data; + erp_done = dasd_3990_update_1B (erp_done, + sense); + +#ifdef ERP_FULL_ERP + } else if (erp_done->function == dasd_3990_erp_int_req) { + erp_done = dasd_3990_erp_int_req (erp_done); +#endif /* ERP_FULL_ERP */ + + } else { + /* simple retry */ + DASD_MESSAGE (KERN_WARNING, device, + "%i retries left for erp %p", + erp_done->retries, + (void *) erp_done); + + /* handle the request again... */ + check_then_set (&erp_done->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + } + } else { + /* no retry left - check for further necessary action */ + /* if no further actions, handle rest as permanent error */ + erp_done = dasd_3990_erp_further_erp (erp_done); + } + + erp_head = erp_done; + +} /* end dasd_3990_erp_handle_match_erp */ + +/* + * DASD_3990_ERP_ACTION + * + * DESCRIPTION + * controll routine for 3990 erp actions. + * Has to be called with the queue lock (namely the s390_irq_lock) acquired. + * + * PARAMETER + * cqr failed cqr (either original cqr or already an erp) + * + * RETURN VALUES + * erp erp-pointer to the head of the ERP action chain. + * This means: + * - either a ptr to an additional ERP cqr or + * - the original given cqr (which's status might be modified) + */ +ccw_req_t * +dasd_3990_erp_action (ccw_req_t *cqr) +{ + ccw_req_t *erp = NULL; + dasd_device_t *device = cqr->device; + +#ifdef ERP_DEBUG + __u32 cpa = cqr->dstat->cpa; +#endif /* ERP_DEBUG */ + +#ifdef ERP_DEBUG + + printk (KERN_WARNING PRINTK_HEADER + "entering 3990 ERP for " + "0x%04X on sch %d = /dev/%s \n", + device->devinfo.devno, + device->devinfo.irq, + device->name); + + /* print current erp_chain */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "ERP chain at BEGINNING of ERP-ACTION"); + { + ccw_req_t *temp_erp = NULL; + for (temp_erp = cqr; + temp_erp != NULL; + temp_erp = temp_erp->refers){ + + DASD_MESSAGE (KERN_WARNING, device, + " erp %p refers to %p \n", + temp_erp, + temp_erp->refers); + } + } +#endif + + /* double-check if current erp/cqr was successfull */ + if ((cqr->dstat->cstat == 0x00) && + (cqr->dstat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) { + DASD_MESSAGE (KERN_WARNING, device, + "ERP called for successful request %p" + " - NO ERP necessary", + cqr); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_DONE); + + return cqr; + } + /* check if sense data are available */ + if (!cqr->dstat->ii.sense.data) { + DASD_MESSAGE (KERN_WARNING, device, + "ERP called witout sense data avail ..." + "request %p - NO ERP possible", + cqr); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + + return cqr; + + } + + /* check if error happened before */ + erp = dasd_3990_erp_in_erp (cqr); + + if (erp == NULL) { + /* no matching erp found - set up erp */ + erp = dasd_3990_erp_additional_erp (cqr); + } else { + /* matching erp found - set all leading erp's to DONE */ + dasd_3990_erp_handle_match_erp (cqr, erp); + erp = cqr; + } + +#ifdef ERP_DEBUG + /* print current erp_chain */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "ERP chain at END of ERP-ACTION"); + { + ccw_req_t *temp_erp = NULL; + for (temp_erp = erp; + temp_erp != NULL; + temp_erp = temp_erp->refers){ + + DASD_MESSAGE (KERN_WARNING, device, + " erp %p refers to %p \n", + temp_erp, + temp_erp->refers); + } + } +#endif /* ERP_DEBUG */ + +#ifdef ERP_DEBUG + if (erp->status == CQR_STATUS_FAILED) { + log_erp_chain (erp, 1, cpa); + } +#endif /* ERP_DEBUG */ - } /* end distinguish between 24 and 32 byte sense data */ + return erp; -} /* END dasd_3990_erp_examine */ +} /* end dasd_3990_erp_action */ /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd_3990_erp.h linux.ac/drivers/s390/block/dasd_3990_erp.h --- linux.vanilla/drivers/s390/block/dasd_3990_erp.h Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/block/dasd_3990_erp.h Thu Apr 12 12:03:49 2001 @@ -1,17 +1,28 @@ -ccw_req_t *dasd_3990_erp_com_rej (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_int_req (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_bus_out (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_equip_check (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_data_check (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_overrun (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_inv_format (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_EOC (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_env_data (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_no_rec (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_file_prot (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_perm (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_first_log (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_add_erp (ccw_req_t *, devstat_t *); /* tbd - delete */ +/* + * File...........: linux/drivers/s390/block/dasd_3990_erp.h + * Author(s)......: Horst Hummel <Horst Hummel@de.ibm.com> + * Bugreports.to..: <Linux390@de.ibm.com> + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 + * + * History of changes (starts July 2000) + */ + +#ifndef DASD_3990_ERP_H +#define DASD_3990_ERP_H + + +dasd_era_t dasd_3990_erp_examine (ccw_req_t *, devstat_t *); ccw_req_t *dasd_3990_erp_action (ccw_req_t *); ccw_req_t *dasd_2105_erp_action (ccw_req_t *); + +void dasd_3990_erp_restart_queue (unsigned long); + +typedef struct DCTL_data_t { + unsigned char subcommand; /* e.g Inhibit Write, Enable Write,... */ + unsigned char modifier; /* Subcommand modifier */ + unsigned short res; /* reserved */ +} __attribute__ ((packed)) DCTL_data_t; + + +#endif /* DASD_3990_ERP_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd_9343_erp.h linux.ac/drivers/s390/block/dasd_9343_erp.h --- linux.vanilla/drivers/s390/block/dasd_9343_erp.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/s390/block/dasd_9343_erp.h Thu Apr 12 12:03:49 2001 @@ -0,0 +1,18 @@ +/* + * File...........: linux/drivers/s390/block/dasd_9343_erp.h + * Author(s)......: Horst Hummel <Horst Hummel@de.ibm.com> + * Bugreports.to..: <Linux390@de.ibm.com> + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 + * + * History of changes (starts July 2000) + */ + +#ifndef DASD_9343_ERP_H +#define DASD_9343_ERP_H + + +dasd_era_t dasd_9343_erp_examine (ccw_req_t *, devstat_t *); + +ccw_req_t *dasd_9343_erp_action (ccw_req_t *); + +#endif /* DASD_9343_ERP_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd_diag.c linux.ac/drivers/s390/block/dasd_diag.c --- linux.vanilla/drivers/s390/block/dasd_diag.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/block/dasd_diag.c Thu Apr 12 12:03:49 2001 @@ -10,6 +10,8 @@ * 07/13/00 Added fixup sections for diagnoses ans saved some registers * 07/14/00 fixed constraints in newly generated inline asm * 10/05/00 adapted to 'new' DASD driver + * fixed return codes of dia250() + * fixed partition handling and HDIO_GETGEO */ #include <linux/stddef.h> @@ -73,10 +75,11 @@ static __inline__ int dia250 (void *iob, int cmd) { - int rc; - - __asm__ __volatile__ (" lr 1,%1\n" - " diag 1,%2,0x250\n" + __asm__ __volatile__ (" lr 0,%1\n" + " diag 0,%0,0x250\n" + "0: ipm %0\n" + " srl %0,28\n" + " or %0,1\n" "1:\n" ".section .fixup,\"ax\"\n" "2: lhi %0,3\n" @@ -87,12 +90,12 @@ ".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; + " .long 0b,2b\n" + ".previous\n" + : "+d" (cmd) + : "d" ((void *) __pa (iob)) + : "0", "1", "cc" ); + return cmd; } static __inline__ int @@ -112,7 +115,7 @@ rc = dia250 (iib, INIT_BIO); - return rc; + return rc&3; } static __inline__ int @@ -125,7 +128,7 @@ memset (iib, 0, sizeof (diag_init_io_t)); iib->dev_nr = device->devinfo.devno; rc = dia250 (iib, TERM_BIO); - return rc; + return rc&3; } int @@ -153,7 +156,12 @@ check_then_set (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_ERROR); - } else { + } else if (rc == 0 ) { + check_then_set(&cqr->status, + CQR_STATUS_QUEUED, + CQR_STATUS_DONE); + dasd_schedule_bh(device); + } else { if (cqr->expires) { cqr->expires += cqr->startclk; } @@ -250,13 +258,14 @@ "Null device pointer passed to characteristics checker\n"); return -ENODEV; } - if (device->private == NULL) { - device->private = kmalloc (sizeof (dasd_diag_private_t), GFP_KERNEL); - if (device->private == NULL) { - printk (KERN_WARNING PRINTK_HEADER - "memory allocation failed for private data\n"); - return -ENOMEM; - } + if (device->private != NULL) { + kfree (device->private); + } + device->private = kmalloc (sizeof (dasd_diag_private_t), GFP_KERNEL); + if (device->private == NULL) { + printk (KERN_WARNING PRINTK_HEADER + "memory allocation failed for private data\n"); + return -ENOMEM; } private = (dasd_diag_private_t *) device->private; rdc_data = (void *) &(private->rdc_data); @@ -304,7 +313,7 @@ if (cqr == NULL) { printk (KERN_WARNING PRINTK_HEADER "No memory to allocate initialization request\n"); - free_page(private->label); + free_page((long)private->label); kfree(private); device->private = NULL; return -ENOMEM; @@ -319,7 +328,7 @@ memset (iob, 0, sizeof (diag_rw_io_t)); iob->dev_nr = rdc_data->dev_nr; iob->block_count = 1; - iob->interrupt_params = cqr; + iob->interrupt_params = (u32)cqr; iob->bio_list = __pa (bio); rc = dia250 (iob, RW_BIO); if (rc == 0) { @@ -354,19 +363,26 @@ static int dasd_diag_do_analysis (struct dasd_device_t *device) { - int sb; dasd_diag_private_t *private = (dasd_diag_private_t *) device->private; long *label = private->label; /* real size of the volume */ device->sizes.blocks = label[7]; + if (private->rdc_data.vdev_class == DEV_CLASS_FBA) { + device->sizes.pt_block = 1; + } else if (private->rdc_data.vdev_class == DEV_CLASS_ECKD || + private->rdc_data.vdev_class == DEV_CLASS_CKD) { + device->sizes.pt_block = 2; + } else { + return -EINVAL; + } printk (KERN_INFO PRINTK_HEADER "/dev/%s (%04X): capacity (%dkB blks): %ldkB\n", device->name, device->devinfo.devno, (device->sizes.bp_block >> 10), (device->sizes.blocks << device->sizes.s2b_shift) >> 1); - free_page(private->label); + free_page((long)private->label); return 0; } @@ -393,14 +409,6 @@ geo->cylinders = cyls; geo->heads = 16; geo->sectors = 128 >> device->sizes.s2b_shift; - if (private->rdc_data.vdev_class == DEV_CLASS_FBA) { - geo->start = 1; - } else if (private->rdc_data.vdev_class == DEV_CLASS_ECKD || - private->rdc_data.vdev_class == DEV_CLASS_CKD) { - geo->start = 2; - } else { - return -EINVAL; - } return rc; } @@ -482,7 +490,7 @@ } } rw_cp->device = device; - rw_cp->expires = 5 * 0xf424000; /* 5 seconds */ + rw_cp->expires = 50 * TOD_SEC; /* 50 seconds */ rw_cp->req = req; check_then_set (&rw_cp->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED); return rw_cp; @@ -507,6 +515,7 @@ { name:"DIAG", ebcname:"DIAG", + max_blocks:PAGE_SIZE/sizeof(diag_bio_t), check_characteristics:dasd_diag_check_characteristics, do_analysis:dasd_diag_do_analysis, fill_geometry:dasd_diag_fill_geometry, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd_eckd.c linux.ac/drivers/s390/block/dasd_eckd.c --- linux.vanilla/drivers/s390/block/dasd_eckd.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/block/dasd_eckd.c Thu Apr 12 12:03:49 2001 @@ -15,6 +15,8 @@ * 10/10/00 reverted last change according to ESS exploitation * 10/10/00 now dequeuing init_cqr before freeing *ouch* * 26/10/00 fixed ITPM20144ASC (problems when accesing a device formatted by VIF) + * 01/23/01 fixed kmalloc statement in dump_sense to be GFP_ATOMIC + * fixed partition handling and HDIO_GETGEO */ #include <linux/config.h> @@ -40,6 +42,8 @@ #undef PRINTK_HEADER #endif /* PRINTK_HEADER */ #define PRINTK_HEADER DASD_NAME"(eckd): " +#undef DASD_CDL // Support compatible disk layout +#undef CDL_PRINTK #define ECKD_C0(i) (i->home_bytes) #define ECKD_F(i) (i->formula) @@ -52,36 +56,21 @@ #define ECKD_F7(i) (i->factor7) #define ECKD_F8(i) (i->factor8) -#define DASD_ECKD_CCW_WRITE 0x05 -#define DASD_ECKD_CCW_READ 0x06 -#define DASD_ECKD_CCW_WRITE_HOME_ADDRESS 0x09 -#define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a -#define DASD_ECKD_CCW_WRITE_KD 0x0d -#define DASD_ECKD_CCW_READ_KD 0x0e -#define DASD_ECKD_CCW_READ_COUNT 0x12 -#define DASD_ECKD_CCW_WRITE_RECORD_ZERO 0x15 -#define DASD_ECKD_CCW_READ_RECORD_ZERO 0x16 -#define DASD_ECKD_CCW_WRITE_CKD 0x1d -#define DASD_ECKD_CCW_READ_CKD 0x1e -#define DASD_ECKD_CCW_LOCATE_RECORD 0x47 -#define DASD_ECKD_CCW_DEFINE_EXTENT 0x63 -#define DASD_ECKD_CCW_WRITE_MT 0x85 -#define DASD_ECKD_CCW_READ_MT 0x86 -#define DASD_ECKD_CCW_WRITE_KD_MT 0x8d -#define DASD_ECKD_CCW_READ_KD_MT 0x8e -#define DASD_ECKD_CCW_RELEASE 0x94 -#define DASD_ECKD_CCW_READ_CKD_MT 0x9e -#define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d -#define DASD_ECKD_CCW_RESERVE 0xB4 - dasd_discipline_t dasd_eckd_discipline; typedef struct dasd_eckd_private_t { dasd_eckd_characteristics_t rdc_data; dasd_eckd_confdata_t conf_data; +#ifdef DASD_CDL + eckd_count_t count_area[5]; +#else eckd_count_t count_area; +#endif ccw_req_t *init_cqr; +#ifdef DASD_CDL + int uses_cdl; +#endif } dasd_eckd_private_t; #ifdef CONFIG_DASD_DYNAMIC @@ -91,27 +80,38 @@ { ci: {hc: - {ctype:0x3990, dtype:0x3390}}, - flag:DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE, + {ctype:0x3990}}, + flag: (DEVREG_MATCH_CU_TYPE | + DEVREG_NO_DEV_INFO| + DEVREG_TYPE_DEVCHARS), oper_func:dasd_oper_handler }, { ci: {hc: - {ctype:0x3990, dtype:0x3380}}, - flag:DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE, + {ctype:0x2105}}, + flag:(DEVREG_MATCH_CU_TYPE | + DEVREG_NO_DEV_INFO| + DEVREG_TYPE_DEVCHARS), oper_func:dasd_oper_handler }, { ci: {hc: - {ctype:0x9343, dtype:0x9345}}, - flag:DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE, + {ctype:0x9343}}, + flag:(DEVREG_MATCH_CU_TYPE | + DEVREG_NO_DEV_INFO| + DEVREG_TYPE_DEVCHARS), oper_func:dasd_oper_handler } }; #endif +#ifdef DASD_CDL +int sizes_trk0[]={28,148,84}; +#define LABEL_SIZE 140 +#endif + static inline unsigned int round_up_multiple (unsigned int no, unsigned int mult) { @@ -210,6 +210,7 @@ return rpt; } + static inline void define_extent (ccw1_t * de_ccw, DE_eckd_data_t * data, @@ -269,7 +270,11 @@ break; } data->attributes.mode = 0x3; - if (private->rdc_data.cu_type == 0x2105) { + if (private->rdc_data.cu_type == 0x2105 +#ifdef DASD_CDL + && !(private->uses_cdl && trk < 2) +#endif + ) { data->reserved |= 0x40; } data->beg_ext.cyl = beg.cyl; @@ -296,6 +301,9 @@ {trk / (geo.head), trk % (geo.head)}; int sector; +#ifdef CDL_PRINTK + printk ("Locate: trk %d, rec %d, no_rec %d, cmd %d, reclen %d\n",trk,rec_on_trk,no_rec,cmd,reclen); +#endif memset (lo_ccw, 0, sizeof (ccw1_t)); lo_ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD; lo_ccw->count = 16; @@ -411,13 +419,14 @@ "Null device pointer passed to characteristics checker\n"); return -ENODEV; } + if (device->private != NULL) { + kfree(device->private); + } + device->private = kmalloc (sizeof (dasd_eckd_private_t), GFP_KERNEL); if (device->private == NULL) { - device->private = kmalloc (sizeof (dasd_eckd_private_t), GFP_KERNEL); - if (device->private == NULL) { - printk (KERN_WARNING PRINTK_HEADER - "memory allocation failed for private data\n"); - return -ENOMEM; - } + printk (KERN_WARNING PRINTK_HEADER + "memory allocation failed for private data\n"); + return -ENOMEM; } private = (dasd_eckd_private_t *) device->private; rdc_data = (void *) &(private->rdc_data); @@ -468,6 +477,22 @@ return 0; } +#ifdef DASD_CDL +static inline int +dasd_eckd_cdl_reclen (dasd_device_t* device,int recid) { + dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private; + int byt_per_blk = device->sizes.bp_block; + int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk); + if (recid < 3) + return sizes_trk0[recid]; + if (recid < blk_per_trk) + return byt_per_blk; + if (recid < 2*blk_per_trk ) + return LABEL_SIZE; + return byt_per_blk; +} +#endif + static ccw_req_t * dasd_eckd_init_analysis (struct dasd_device_t *device) { @@ -476,9 +501,20 @@ DE_eckd_data_t *DE_data; LO_eckd_data_t *LO_data; dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private; +#ifdef DASD_CDL + eckd_count_t *count_data = private->count_area; +#else eckd_count_t *count_data = &(private->count_area); - - cqr = ccw_alloc_request (dasd_eckd_discipline.name, 3 + 1, sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t)); +#endif +#ifdef DASD_CDL + cqr = ccw_alloc_request (dasd_eckd_discipline.name, 8 + 1, + sizeof (DE_eckd_data_t) + + 2*sizeof (LO_eckd_data_t)); +#else + cqr = ccw_alloc_request (dasd_eckd_discipline.name, 3 + 1, + sizeof (DE_eckd_data_t) + + sizeof (LO_eckd_data_t)); +#endif if (cqr == NULL) { printk (KERN_WARNING PRINTK_HEADER "No memory to allocate initialization request\n"); @@ -489,72 +525,159 @@ DE_data = cqr->data; LO_data = cqr->data + sizeof (DE_eckd_data_t); ccw = cqr->cpaddr; +#ifdef DASD_CDL + define_extent (ccw, DE_data, 0, 2, DASD_ECKD_CCW_READ_COUNT, device); +#else define_extent (ccw, DE_data, 0, 0, DASD_ECKD_CCW_READ_COUNT, device); +#endif ccw->flags |= CCW_FLAG_CC; ccw++; +#ifdef DASD_CDL + locate_record (ccw, LO_data++, 0, 0, 4, DASD_ECKD_CCW_READ_COUNT, device, 0); +#else locate_record (ccw, LO_data, 0, 0, 1, DASD_ECKD_CCW_READ_COUNT, device, 0); +#endif +#ifdef DASD_CDL ccw->flags |= CCW_FLAG_CC; ccw++; ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; ccw->count = 8; - set_normalized_cda (ccw, __pa (count_data)); + set_normalized_cda (ccw, __pa (count_data++)); + ccw->flags |= CCW_FLAG_CC; + ccw++; + ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; + ccw->count = 8; + set_normalized_cda (ccw, __pa (count_data++)); + ccw->flags |= CCW_FLAG_CC; + ccw++; + ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; + ccw->count = 8; + set_normalized_cda (ccw, __pa (count_data++)); + ccw->flags |= CCW_FLAG_CC; + ccw++; + ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; + ccw->count = 8; + set_normalized_cda (ccw, __pa (count_data++)); + ccw->flags |= CCW_FLAG_CC; + ccw++; + locate_record (ccw, LO_data++, 2, 0, 1, DASD_ECKD_CCW_READ_COUNT, device, 0); +#endif + ccw->flags |= CCW_FLAG_CC; + ccw++; + ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; + ccw->count = 8; + set_normalized_cda (ccw, __pa (count_data)); cqr->device = device; cqr->retries = 0; cqr->status = CQR_STATUS_FILLED; - return cqr; } static int dasd_eckd_do_analysis (struct dasd_device_t *device) { - int rc = 0; int sb, rpt; dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private; - int bs = private->count_area.dl; - + eckd_count_t *count_area = NULL; + char *cdl_msg; +#ifdef DASD_CDL /* BAD HACK SO FIX ME UP */ + int i; + private -> uses_cdl = 1; + + /* Free the cqr and cleanup device->sizes */ + dasd_chanq_deq (&device->queue, private->init_cqr); + ccw_free_request (private->init_cqr); + private->init_cqr = NULL; + memset (&(device->sizes), 0, sizeof (dasd_sizes_t)); + /* Check Track 0 for Compatible Disk Layout */ + for (i = 0; i < 3; i++) { + if ((i < 3) && + ((private->count_area[i].kl != 4) || + (private->count_area[i].dl != + dasd_eckd_cdl_reclen (device,i) - 4))) { + private -> uses_cdl = 0; + break; + } + } + if ( i == 3 ) { + count_area = &private->count_area[4]; + } + if (private->uses_cdl == 0) { + for (i = 0; i < 5; i++) { + if ((private->count_area[i].kl != 0) || + (private->count_area[i].dl != + private->count_area[0].dl)) { + break; + } + } + if ( i == 5 ) { + count_area = &private->count_area[0]; + } + } else { + if (private->count_area[3].record == 1) { + DASD_MESSAGE(KERN_WARNING,device,"%s", + "Trk 0: no records after VTOC!"); + } + } + if (count_area != NULL && /* we found notthing violating our disk layout */ + count_area ->kl == 0) { + /* find out blocksize */ + switch (count_area->dl) { + case 512: + case 1024: + case 2048: + case 4096: + device->sizes.bp_block = count_area->dl; + break; + } + } +#else dasd_chanq_deq (&device->queue, private->init_cqr); ccw_free_request (private->init_cqr); private->init_cqr = NULL; memset (&(device->sizes), 0, sizeof (dasd_sizes_t)); - switch (bs) { + switch (private->count_area.dl) { case 512: case 1024: case 2048: case 4096: - device->sizes.bp_block = bs; + device->sizes.bp_block = private->count_area.dl; break; - default: - printk (KERN_INFO PRINTK_HEADER - "/dev/%s (%04X): invalid blocksize %d\n" - KERN_INFO PRINTK_HEADER - "/dev/%s (%04X): capacity (at 4kB blks): %dkB at %dkB/trk\n", - device->name, device->devinfo.devno, bs, - device->name, device->devinfo.devno, - (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl * - recs_per_track (&private->rdc_data, 0, 4096)), - recs_per_track (&private->rdc_data, 0, 4096)); - return -EMEDIUMTYPE; } +#endif + if ( device->sizes.bp_block == 0 ) { + DASD_MESSAGE(KERN_WARNING, device,"%s\n", + "Volume has incompatible disk layout"); + return -EMEDIUMTYPE; + } device->sizes.s2b_shift = 0; /* bits to shift 512 to get a block */ - for (sb = 512; sb < bs; sb = sb << 1) + device->sizes.pt_block = 2; + for (sb = 512; sb < device->sizes.bp_block; sb = sb << 1) device->sizes.s2b_shift++; rpt = recs_per_track (&private->rdc_data, 0, device->sizes.bp_block); - device->sizes.blocks = (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl * - recs_per_track (&private->rdc_data, 0, device->sizes.bp_block)); - - printk (KERN_INFO PRINTK_HEADER - "/dev/%s (%04X): capacity (%dkB blks): %dkB at %dkB/trk\n", - device->name, device->devinfo.devno, - (device->sizes.bp_block >> 10), - (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl * - recs_per_track (&private->rdc_data, 0, device->sizes.bp_block) * - (device->sizes.bp_block >> 9)) >> 1, - (recs_per_track (&private->rdc_data, 0, device->sizes.bp_block) * device->sizes.bp_block) >> 10); + device->sizes.blocks = (private->rdc_data.no_cyl * + private->rdc_data.trk_per_cyl * + recs_per_track (&private->rdc_data, 0, + device->sizes.bp_block)); +#ifdef DASD_CDL + cdl_msg = private->uses_cdl?"compatible disk layout":"classic disk layout"; +#else + cdl_msg = "classic disk layout"; +#endif + + DASD_MESSAGE(KERN_INFO,device,"(%dkB blks): %dkB at %dkB/trk %s", + (device->sizes.bp_block >> 10), + (private->rdc_data.no_cyl * + private->rdc_data.trk_per_cyl * + recs_per_track (&private->rdc_data, 0, + device->sizes.bp_block) * + (device->sizes.bp_block >> 9)) >> 1, + (recs_per_track (&private->rdc_data, 0, + device->sizes.bp_block) * + device->sizes.bp_block) >> 10, + cdl_msg); return 0; - - return rc; } static int @@ -574,7 +697,6 @@ geo->cylinders = private->rdc_data.no_cyl; geo->heads = private->rdc_data.trk_per_cyl; geo->sectors = recs_per_track (&(private->rdc_data), 0, device->sizes.bp_block); - geo->start = 2; return rc; } @@ -600,6 +722,9 @@ int head = trk % private->rdc_data.trk_per_cyl; int wrccws = rpt; int datasize = sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t); +#ifdef DASD_CDL + int formatCDL=0; +#endif if (((fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT) && trk >= (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl)) || @@ -623,7 +748,15 @@ case 0x01: case 0x03: case 0x04: /* make track invalid */ + break; +#ifdef DASD_CDL /* Format compatible disk Layout */ + case 0x08: + case 0x09: + case 0x0b: + case 0x0c: + formatCDL=1; break; +#endif default: printk (KERN_WARNING PRINTK_HEADER "Invalid flags 0x%x...terminating!\n", flags); return NULL; @@ -678,6 +811,7 @@ switch (flags) { case 0x03: + case 0x0b: define_extent (last_ccw, DE_data, trk, trk, DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device); last_ccw->flags |= CCW_FLAG_CC; @@ -688,6 +822,7 @@ last_ccw++; break; case 0x01: + case 0x09: define_extent (last_ccw, DE_data, trk, trk, DASD_ECKD_CCW_WRITE_RECORD_ZERO, device); last_ccw->flags |= CCW_FLAG_CC; @@ -699,6 +834,7 @@ memset (r0_data, 0, sizeof (eckd_count_t)); break; case 0x00: + case 0x08: define_extent (last_ccw, DE_data, trk, trk, DASD_ECKD_CCW_WRITE_CKD, device); last_ccw->flags |= CCW_FLAG_CC; @@ -710,6 +846,7 @@ last_ccw++; break; case 0x04: + case 0x0c: define_extent (last_ccw, DE_data, trk, trk, DASD_ECKD_CCW_WRITE_CKD, device); last_ccw->flags |= CCW_FLAG_CC; @@ -747,7 +884,29 @@ (ct_data + i)->head = head; (ct_data + i)->record = i + 1; (ct_data + i)->kl = 0; - (ct_data + i)->dl = bs; +#ifdef DASD_CDL + if (formatCDL) { + // special handling when formatting CDL + switch (trk) { + case 0: + if (i<3) { + (ct_data + i)->kl = 4; + (ct_data + i)->dl = sizes_trk0[i]-4; + } else + (ct_data + i)->dl = bs; + break; + case 1: + (ct_data + i)->kl = 44; + (ct_data + i)->dl = LABEL_SIZE-44; + break; + default: + (ct_data + i)->dl = bs; + break; + } + } + else +#endif + (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; @@ -791,7 +950,7 @@ switch (device->devinfo.sid_data.cu_type) { case 0x3990: case 0x2105: - /* return dasd_3990_erp_action; */ + return dasd_3990_erp_action; case 0x9343: /* Return dasd_9343_erp_action; */ default: @@ -802,13 +961,42 @@ static dasd_erp_postaction_fn_t dasd_eckd_erp_postaction (ccw_req_t * cqr) { - if (cqr->function != default_erp_action) - printk (KERN_WARNING PRINTK_HEADER - "unknown ERP action [<%p>]\n", - cqr->function); return default_erp_postaction; } + +#ifdef DASD_CDL +inline unsigned char +dasd_eckd_cdl_cmd(dasd_device_t *device,int recid,int cmd) { + dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private; + int byt_per_blk = device->sizes.bp_block; + int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk); + switch (cmd) { + case READ: + if (recid < 3) + return DASD_ECKD_CCW_READ_KD_MT; + if (recid < blk_per_trk) + return DASD_ECKD_CCW_READ_MT; + if (recid < 2*blk_per_trk) + return DASD_ECKD_CCW_READ_KD_MT; + return DASD_ECKD_CCW_READ_MT; + break; + case WRITE: + if (recid < 3) + return DASD_ECKD_CCW_WRITE_KD_MT; + if (recid < blk_per_trk) + return DASD_ECKD_CCW_WRITE_MT; + if (recid < 2*blk_per_trk) + return DASD_ECKD_CCW_WRITE_KD_MT; + return DASD_ECKD_CCW_WRITE_MT; + break; + default: + BUG(); + } + return 0; // never executed +} +#endif + static ccw_req_t * dasd_eckd_build_cp_from_req (dasd_device_t * device, struct request *req) { @@ -826,6 +1014,11 @@ int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk); int btrk = (req->sector >> shift) / blk_per_trk; int etrk = ((req->sector + req->nr_sectors - 1) >> shift) / blk_per_trk; +#ifdef DASD_CDL + int recid = req->sector >> shift; + int locate4k_set=0; + int nlocs=0; +#endif if (req->cmd == READ) { rw_cmd = DASD_ECKD_CCW_READ_MT; @@ -845,43 +1038,123 @@ else bhct++; } - +#ifndef DASD_CDL rw_cp = dasd_alloc_request (dasd_eckd_discipline.name, 2 + bhct + 1, sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t)); +#else + if (btrk<2 && private->uses_cdl) { + nlocs+= 2*blk_per_trk-recid; + if (etrk<2) + nlocs-=2*blk_per_trk-((req->sector + req->nr_sectors - 1) >> shift); + } + rw_cp = dasd_alloc_request (dasd_eckd_discipline.name, + 2 + nlocs + bhct + 1, + sizeof (DE_eckd_data_t) + + (1+nlocs)*sizeof (LO_eckd_data_t)); +#endif if (!rw_cp) { return NULL; } DE_data = rw_cp->data; LO_data = rw_cp->data + sizeof (DE_eckd_data_t); ccw = rw_cp->cpaddr; - define_extent (ccw, DE_data, btrk, etrk, rw_cmd, device); ccw->flags |= CCW_FLAG_CC; +#ifndef DASD_CDL ccw++; - locate_record (ccw, LO_data, btrk, (req->sector >> shift) % blk_per_trk + 1, - req->nr_sectors >> shift, rw_cmd, device, device->sizes.bp_block); + locate_record (ccw, LO_data, btrk, (req->sector >> shift) % blk_per_trk + 1, + req->nr_sectors >> shift, rw_cmd, device, device->sizes.bp_block); ccw->flags |= CCW_FLAG_CC; +#endif for (bh = req->bh; bh != NULL;) { if (bh->b_size > byt_per_blk) { for (size = 0; size < bh->b_size; size += byt_per_blk) { +#ifdef DASD_CDL + if (!locate4k_set) { + // we need to chain a locate record before our rw-ccw + ccw++; + if ((recid/blk_per_trk)<2 && private->uses_cdl) { + /* Do a locate record for our special blocks */ + locate_record (ccw, LO_data++, recid/blk_per_trk, + recid % blk_per_trk + 1, 1, + dasd_eckd_cdl_cmd(device,recid,req->cmd), + device, + dasd_eckd_cdl_reclen(device,recid)); + } else { + // Do a locate record for standard blocks */ + locate_record (ccw, LO_data++, recid/blk_per_trk, + recid % blk_per_trk + 1, + (((req->sector + req->nr_sectors) >> shift)-recid), + rw_cmd,device, device->sizes.bp_block); + locate4k_set=1; + } + ccw->flags |= CCW_FLAG_CC; + } +#endif ccw++; +#ifndef DASD_CDL ccw->flags |= CCW_FLAG_CC; - ccw->cmd_code = rw_cmd; - ccw->count = byt_per_blk; - set_normalized_cda (ccw, __pa (bh->b_data + size)); + ccw->cmd_code= rw_cmd; + ccw->count = bh->b_size; +#else + ccw->flags |= CCW_FLAG_CC; + ccw->cmd_code=locate4k_set?rw_cmd: + dasd_eckd_cdl_cmd(device,recid,req->cmd); + ccw->count =locate4k_set?bh->b_size: + dasd_eckd_cdl_reclen(device,recid); +#endif + set_normalized_cda (ccw, __pa (bh->b_data)); + size += bh->b_size; + bh = bh->b_reqnext; +#ifdef DASD_CDL + recid++; +#endif } bh = bh->b_reqnext; } else { /* group N bhs to fit into byt_per_blk */ for (size = 0; bh != NULL && size < byt_per_blk;) { +#ifdef DASD_CDL + if (!locate4k_set) { + // we need to chain a locate record before our rw-ccw + ccw++; + if ((recid/blk_per_trk)<2 && private->uses_cdl) { + /* Do a locate record for our special blocks */ + locate_record (ccw, LO_data++, recid/blk_per_trk, + recid % blk_per_trk + 1, 1, + dasd_eckd_cdl_cmd(device,recid,req->cmd), + device, + dasd_eckd_cdl_reclen(device,recid)); + } else { + // Do a locate record for standard blocks */ + locate_record (ccw, LO_data++, recid/blk_per_trk, + recid % blk_per_trk + 1, + (((req->sector + req->nr_sectors) >> shift)-recid), + rw_cmd,device, device->sizes.bp_block); + locate4k_set=1; + } + ccw->flags |= CCW_FLAG_CC; + } +#endif ccw++; +#ifndef DASD_CDL ccw->flags |= CCW_FLAG_DC; - ccw->cmd_code = rw_cmd; + ccw->cmd_code= rw_cmd; ccw->count = bh->b_size; +#else + ccw->flags |= locate4k_set?CCW_FLAG_DC:CCW_FLAG_CC; + ccw->cmd_code=locate4k_set?rw_cmd: + dasd_eckd_cdl_cmd(device,recid,req->cmd); + ccw->count =locate4k_set?bh->b_size: + dasd_eckd_cdl_reclen(device,recid); +#endif set_normalized_cda (ccw, __pa (bh->b_data)); size += bh->b_size; bh = bh->b_reqnext; +#ifdef DASD_CDL + recid++; +#endif } if (size != byt_per_blk) { PRINT_WARN ("Cannot fulfill small request %ld vs. %d (%ld sects)\n", @@ -1000,14 +1273,13 @@ ccw_req_t * dasd_eckd_merge_cp ( dasd_device_t *device ) { - ccw_req_t * cqr; return NULL; } static char * dasd_eckd_dump_sense (struct dasd_device_t *device, ccw_req_t * req) { - char *page = (char *) get_free_page (GFP_KERNEL); + char *page = (char *) get_free_page (GFP_ATOMIC); devstat_t *stat = &device->dev_status; char *sense = stat->ii.sense.data; int len, sl, sct; @@ -1027,13 +1299,13 @@ ccw1_t *act = req -> cpaddr; int i = req -> cplength; do { -#if 0 +#ifdef ERP_DEBUB printk ( KERN_INFO "CCW %p: %08X %08X\n", act,((int*)act)[0],((int*)act)[1]); printk ( KERN_INFO "DAT: %08X %08X %08X %08X\n", ((int*)act->cda)[0],((int*)act->cda)[1], ((int*)act->cda)[2],((int*)act->cda)[3]); -#endif +#endif /* ERP_DEBUG */ act ++; } while ( --i ); } @@ -1071,6 +1343,7 @@ { name:"ECKD", ebcname:"ECKD", + max_blocks:255, id_check:dasd_eckd_id_check, check_characteristics:dasd_eckd_check_characteristics, init_analysis:dasd_eckd_init_analysis, @@ -1101,14 +1374,12 @@ { int i; for (i = 0; i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t); i++) { - printk (KERN_INFO PRINTK_HEADER - "We are interested in: CU %04X/%02x DEV: %04X/%02Xi\n", + printk (KERN_INFO PRINTK_HEADER + "We are interested in: CU %04X/%02x\n", dasd_eckd_known_devices[i].ci.hc.ctype, - dasd_eckd_known_devices[i].ci.hc.cmode, - dasd_eckd_known_devices[i].ci.hc.dtype, - dasd_eckd_known_devices[i].ci.hc.dmode); + dasd_eckd_known_devices[i].ci.hc.cmode); s390_device_register (&dasd_eckd_known_devices[i]); - } + } } #endif /* CONFIG_DASD_DYNAMIC */ return rc; @@ -1123,12 +1394,10 @@ int i; for ( i=0; i<sizeof(dasd_eckd_known_devices)/sizeof(devreg_t); i++) { printk (KERN_INFO PRINTK_HEADER - "We are interested in: CU %04X/%02x DEV: %04X/%02Xi\n", + "We were interested in: CU %04X/%02x\n", dasd_eckd_known_devices[i].ci.hc.ctype, - dasd_eckd_known_devices[i].ci.hc.cmode, - dasd_eckd_known_devices[i].ci.hc.dtype, - dasd_eckd_known_devices[i].ci.hc.dmode); - s390_device_register(&dasd_eckd_known_devices[i]); + dasd_eckd_known_devices[i].ci.hc.cmode); + s390_device_unregister(&dasd_eckd_known_devices[i]); } } #endif /* CONFIG_DASD_DYNAMIC */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd_eckd.h linux.ac/drivers/s390/block/dasd_eckd.h --- linux.vanilla/drivers/s390/block/dasd_eckd.h Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/block/dasd_eckd.h Thu Apr 12 12:03:49 2001 @@ -2,8 +2,32 @@ #define DASD_ECKD_H #include "dasd_3990_erp.h" +#include "dasd_9343_erp.h" -typedef +#define DASD_ECKD_CCW_WRITE 0x05 +#define DASD_ECKD_CCW_READ 0x06 +#define DASD_ECKD_CCW_WRITE_HOME_ADDRESS 0x09 +#define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a +#define DASD_ECKD_CCW_WRITE_KD 0x0d +#define DASD_ECKD_CCW_READ_KD 0x0e +#define DASD_ECKD_CCW_READ_COUNT 0x12 +#define DASD_ECKD_CCW_WRITE_RECORD_ZERO 0x15 +#define DASD_ECKD_CCW_READ_RECORD_ZERO 0x16 +#define DASD_ECKD_CCW_WRITE_CKD 0x1d +#define DASD_ECKD_CCW_READ_CKD 0x1e +#define DASD_ECKD_CCW_LOCATE_RECORD 0x47 +#define DASD_ECKD_CCW_DEFINE_EXTENT 0x63 +#define DASD_ECKD_CCW_WRITE_MT 0x85 +#define DASD_ECKD_CCW_READ_MT 0x86 +#define DASD_ECKD_CCW_WRITE_KD_MT 0x8d +#define DASD_ECKD_CCW_READ_KD_MT 0x8e +#define DASD_ECKD_CCW_RELEASE 0x94 +#define DASD_ECKD_CCW_READ_CKD_MT 0x9e +#define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d +#define DASD_ECKD_CCW_RESERVE 0xB4 + + +typedef struct eckd_count_t { __u16 cyl; __u16 head; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd_fba.c linux.ac/drivers/s390/block/dasd_fba.c --- linux.vanilla/drivers/s390/block/dasd_fba.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/block/dasd_fba.c Thu Apr 12 12:03:49 2001 @@ -4,6 +4,7 @@ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 + * fixed partition handling and HDIO_GETGEO */ #include <linux/config.h> @@ -49,15 +50,21 @@ { ci: {hc: - {ctype:0x6310, dtype:0x9336}}, - flag:DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE, + {ctype:0x6310, + dtype:0x9336}}, + flag:(DEVREG_MATCH_CU_TYPE | + DEVREG_MATCH_DEV_TYPE| + DEVREG_TYPE_DEVCHARS), oper_func:dasd_oper_handler }, { ci: {hc: - {ctype:0x3880, dtype:0x3370}}, - flag:DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE, + {ctype:0x3880, + dtype:0x3370}}, + flag:(DEVREG_MATCH_CU_TYPE | + DEVREG_MATCH_DEV_TYPE| + DEVREG_TYPE_DEVCHARS), oper_func:dasd_oper_handler } }; @@ -123,13 +130,14 @@ "Null device pointer passed to characteristics checker\n"); return -ENODEV; } + if ( device->private != NULL ) { + kfree(device->private); + } + device->private = kmalloc (sizeof (dasd_fba_private_t), GFP_KERNEL); if (device->private == NULL) { - device->private = kmalloc (sizeof (dasd_fba_private_t), GFP_KERNEL); - if (device->private == NULL) { - printk (KERN_WARNING PRINTK_HEADER - "memory allocation failed for private data\n"); - return -ENOMEM; - } + printk (KERN_WARNING PRINTK_HEADER + "memory allocation failed for private data\n"); + return -ENOMEM; } private = (dasd_fba_private_t *) device->private; rdc_data = (void *) &(private->rdc_data); @@ -179,6 +187,7 @@ device->sizes.s2b_shift++; device->sizes.blocks = (private->rdc_data.blk_bdsa); + device->sizes.pt_block = 1; return rc; } @@ -203,7 +212,6 @@ geo->cylinders = cyls; geo->heads = 16; geo->sectors = 128 >> device->sizes.s2b_shift; - geo->start = 1; return rc; } @@ -247,7 +255,7 @@ { ccw_req_t *rw_cp = NULL; int rw_cmd; - int bhct; + int bhct, i; long size; ccw1_t *ccw; DE_fba_data_t *DE_data; @@ -276,9 +284,9 @@ } rw_cp = dasd_alloc_request (dasd_fba_discipline.name, - 2 + bhct, + 1 + 2*bhct, sizeof (DE_fba_data_t) + - sizeof (LO_fba_data_t)); + bhct*sizeof (LO_fba_data_t)); if (!rw_cp) { return NULL; } @@ -289,29 +297,30 @@ define_extent (ccw, DE_data, req->cmd, byt_per_blk, req->sector, req->nr_sectors); ccw->flags |= CCW_FLAG_CC; - ccw++; - locate_record (ccw, LO_data, req->cmd, 0, req->nr_sectors); - ccw->flags |= CCW_FLAG_CC; - for (bh = req->bh; bh;) { + for (i = 0, bh = req->bh; bh;) { if (bh->b_size > byt_per_blk) { for (size = 0; size < bh->b_size; size += byt_per_blk) { + ccw++; + locate_record (ccw, LO_data, req->cmd, i, 1); + ccw->flags |= CCW_FLAG_CC; ccw++; - if (private->rdc_data.mode.bits.data_chain) { - ccw->flags |= CCW_FLAG_DC; - } else { - ccw->flags |= CCW_FLAG_CC; - } + ccw->flags |= CCW_FLAG_CC|CCW_FLAG_SLI; ccw->cmd_code = rw_cmd; ccw->count = byt_per_blk; set_normalized_cda (ccw, __pa (bh->b_data + size)); + i++; + LO_data++; } bh = bh->b_reqnext; } else { /* group N bhs to fit into byt_per_blk */ for (size = 0; bh != NULL && size < byt_per_blk;) { + ccw++; + locate_record (ccw, LO_data, req->cmd, i, 1); + ccw->flags |= CCW_FLAG_CC; ccw++; if (private->rdc_data.mode.bits.data_chain) { - ccw->flags |= CCW_FLAG_DC; + ccw->flags |= CCW_FLAG_DC|CCW_FLAG_SLI; } else { PRINT_WARN ("Cannot chain chunks smaller than one block\n"); ccw_free_request (rw_cp); @@ -322,9 +331,11 @@ set_normalized_cda (ccw, __pa (bh->b_data)); size += bh->b_size; bh = bh->b_reqnext; + i++; + LO_data++; } ccw->flags &= ~CCW_FLAG_DC; - ccw->flags |= CCW_FLAG_CC; + ccw->flags |= CCW_FLAG_CC|CCW_FLAG_SLI; if (size != byt_per_blk) { PRINT_WARN ("Cannot fulfill request smaller than block\n"); ccw_free_request (rw_cp); @@ -360,6 +371,7 @@ { name:"FBA ", ebcname:"FBA ", + max_blocks:((PAGE_SIZE >> 1)/sizeof(ccw1_t)-1), id_check:dasd_fba_id_check, check_characteristics:dasd_fba_check_characteristics, do_analysis:dasd_fba_do_analysis, @@ -387,11 +399,9 @@ int i; for (i = 0; i < sizeof (dasd_fba_known_devices) / sizeof (devreg_t); i++) { printk (KERN_INFO PRINTK_HEADER - "We are interested in: CU %04X/%02x DEV: %04X/%02Xi\n", + "We are interested in: CU %04X/%02x\n", dasd_fba_known_devices[i].ci.hc.ctype, - dasd_fba_known_devices[i].ci.hc.cmode, - dasd_fba_known_devices[i].ci.hc.dtype, - dasd_fba_known_devices[i].ci.hc.dmode); + dasd_fba_known_devices[i].ci.hc.cmode); s390_device_register (&dasd_fba_known_devices[i]); } } @@ -408,12 +418,10 @@ int i; for ( i=0; i<sizeof(dasd_fba_known_devices)/sizeof(devreg_t); i++) { printk (KERN_INFO PRINTK_HEADER - "We are interested in: CU %04X/%02x DEV: %04X/%02Xi\n", + "We were interested in: CU %04X/%02x\n", dasd_fba_known_devices[i].ci.hc.ctype, - dasd_fba_known_devices[i].ci.hc.cmode, - dasd_fba_known_devices[i].ci.hc.dtype, - dasd_fba_known_devices[i].ci.hc.dmode); - s390_device_register(&dasd_fba_known_devices[i]); + dasd_fba_known_devices[i].ci.hc.cmode); + s390_device_unregister(&dasd_fba_known_devices[i]); } } #endif /* CONFIG_DASD_DYNAMIC */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/xpram.c linux.ac/drivers/s390/block/xpram.c --- linux.vanilla/drivers/s390/block/xpram.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/block/xpram.c Thu Apr 12 12:03:49 2001 @@ -658,7 +658,7 @@ case BLKFLSBUF: /* flush, 0x1261 */ fsync_dev(inode->i_rdev); - if ( suser() )invalidate_buffers(inode->i_rdev); + if ( capable(CAP_SYS_ADMIN) )invalidate_buffers(inode->i_rdev); return 0; case BLKRAGET: /* return the readahead value, 0x1263 */ @@ -671,7 +671,7 @@ return 0; case BLKRASET: /* set the readahead value, 0x1262 */ - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (arg > 0xff) return -EINVAL; /* limit it */ read_ahead[MAJOR(inode->i_rdev)] = arg; atomic_eieio(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/ccwcache.c linux.ac/drivers/s390/ccwcache.c --- linux.vanilla/drivers/s390/ccwcache.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/ccwcache.c Thu Apr 12 12:03:49 2001 @@ -9,6 +9,7 @@ * 11/14/00 redesign by Martin Schwidefsky */ +#include <linux/module.h> #include <linux/malloc.h> #include <linux/version.h> @@ -31,9 +32,7 @@ #define kmem_cache_destroy(x) do {} while(0) #endif -#ifdef PRINTK_HEADER #undef PRINTK_HEADER -#endif #define PRINTK_HEADER "ccwcache" /* pointer to list of allocated requests */ @@ -300,4 +299,7 @@ } debug_unregister( debug_area ); } + +EXPORT_SYMBOL(ccw_alloc_request); +EXPORT_SYMBOL(ccw_free_request); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/Makefile linux.ac/drivers/s390/char/Makefile --- linux.vanilla/drivers/s390/char/Makefile Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/char/Makefile Thu Apr 12 12:03:49 2001 @@ -1,33 +1,42 @@ -all: s390-char.o +# Makefile for the S/390 supported character devices +# +# 4 January 2001 Richard Hitt +# Modeled after similar files of Michael Elizabeth Chastain +# Rewritten to use lists instead of if-statements. -CFLAFS += -O_TARGET := s390-char.o +O_TARGET := s390-char.o -obj-$(CONFIG_3215_CONSOLE) += con3215.o +export-objs := +list-multi := tub3270.o tape390.o -obj-$(CONFIG_HWC) += hwc_con.o hwc_rw.o hwc_tty.o +obj-y := +obj-m := +obj-n := +obj- := -# stuff for building tape390.o -T390_OBJS = tape.o -ifeq ($(CONFIG_S390_TAPE_CHAR),y) - T390_OBJS += tapechar.o -endif -ifeq ($(CONFIG_S390_TAPE_BLOCK),y) - T390_OBJS += tapeblock.o -endif -ifeq ($(CONFIG_S390_TAPE_3480),y) - T390_OBJS += tape3480.o - CONFIG_S390_TAPE_NEED_34xx = y -endif -ifeq ($(CONFIG_S390_TAPE_3490),y) - T390_OBJS += tape3490.o - CONFIG_S390_TAPE_NEED_34xx = y -endif -ifeq ($(CONFIG_S390_TAPE_NEED_34xx),y) - T390_OBJS += tape34xx.o -endif -obj-$(CONFIG_S390_TAPE) += tape390.o +tub3270-objs := tuball.o tubfs.o tubtty.o \ + tubttyaid.o tubttybld.o tubttyrcl.o \ + tubttyscl.o tubttysiz.o + +obj-y += ctrlchar.o +obj-$(CONFIG_3215_CONSOLE) += con3215.o +obj-$(CONFIG_HWC) += hwc_con.o hwc_rw.o hwc_tty.o +obj-$(CONFIG_3270) += tub3270.o + +tape-y := tape.o +tape-$(CONFIG_S390_TAPE_CHAR) += tapechar.o +tape-$(CONFIG_S390_TAPE_BLOCK) += tapeblock.o +tape-$(CONFIG_S390_TAPE_3480) += tape3480.o tape34xx.o +tape-$(CONFIG_S390_TAPE_3490) += tape3490.o tape34xx.o +tape390-objs := $(sort $(tape-y)) +obj-$(CONFIG_S390_TAPE) += tape390.o + +# Hand off to Rules.make. -tape390.o: $(T390_OBJS) - $(LD) -r -o $@ $(T390_OBJS) include $(TOPDIR)/Rules.make + +tub3270.o: $(tub3270-objs) + $(LD) -r -o $@ $(tub3270-objs) + +tape390.o: $(tape390-objs) + $(LD) -r -o $@ $(tape390-objs) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/con3215.c linux.ac/drivers/s390/char/con3215.c --- linux.vanilla/drivers/s390/char/con3215.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/char/con3215.c Thu Apr 12 12:03:49 2001 @@ -22,14 +22,17 @@ #include <linux/slab.h> #include <linux/bootmem.h> +#include <linux/devfs_fs_kernel.h> + #include <asm/io.h> #include <asm/ebcdic.h> #include <asm/uaccess.h> #include <asm/delay.h> - -#include "../../../arch/s390/kernel/cpcmd.h" +#include <asm/cpcmd.h> #include <asm/irq.h> +#include "ctrlchar.h" + #define NR_3215 1 #define NR_3215_REQ (4*NR_3215) #define RAW3215_BUFFER_SIZE 65536 /* output buffer size */ @@ -116,7 +119,7 @@ { int vdev; - vdev = simple_strtoul(str,&str,16); + vdev = simple_strtoul(str,&str,0); if (vdev >= 0 && vdev < 65536) raw3215_condevice = vdev; return 1; @@ -470,6 +473,8 @@ if ((raw = req->info) == NULL) return; /* That shouldn't happen ... */ if (req->type == RAW3215_READ && raw->tty != NULL) { + char *cchar; + tty = raw->tty; count = 160 - req->residual; if (MACHINE_IS_P390) { @@ -480,33 +485,12 @@ if (count >= TTY_FLIPBUF_SIZE - tty->flip.count) count = TTY_FLIPBUF_SIZE - tty->flip.count - 1; EBCASC(raw->inbuf, count); - if (count == 2 && ( - /* hat is 0xb0 in codepage 037 (US etc.) and thus */ - /* converted to 0x5e in ascii ('^') */ - strncmp(raw->inbuf, "^c", 2) == 0 || - /* hat is 0xb0 in several other codepages (German,*/ - /* UK, ...) and thus converted to ascii octal 252 */ - strncmp(raw->inbuf, "\252c", 2) == 0) ) { - /* emulate a control C = break */ - tty->flip.count++; - *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = INTR_CHAR(tty); - tty_flip_buffer_push(raw->tty); - } else if (count == 2 && ( - strncmp(raw->inbuf, "^d", 2) == 0 || - strncmp(raw->inbuf, "\252d", 2) == 0) ) { - /* emulate a control D = end of file */ + if ((cchar = ctrlchar_handle(raw->inbuf, count, tty))) { + if (cchar == (char *)-1) + goto in_out; tty->flip.count++; *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = EOF_CHAR(tty); - tty_flip_buffer_push(raw->tty); - } else if (count == 2 && ( - strncmp(raw->inbuf, "^z", 2) == 0 || - strncmp(raw->inbuf, "\252z", 2) == 0) ) { - /* emulate a control Z = suspend */ - tty->flip.count++; - *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = SUSP_CHAR(tty); + *tty->flip.char_buf_ptr++ = *cchar; tty_flip_buffer_push(raw->tty); } else { memcpy(tty->flip.char_buf_ptr, @@ -530,6 +514,7 @@ raw->count -= req->len; raw->written -= req->len; } +in_out: raw->flags &= ~RAW3215_WORKING; raw3215_free_req(req); /* check for empty wait */ @@ -794,22 +779,6 @@ #ifdef CONFIG_3215_CONSOLE /* - * Try to request the console IRQ. Called from init/main.c - */ -int con3215_activate(void) -{ - raw3215_info *raw; - - if (!MACHINE_IS_VM && !MACHINE_IS_P390) - return 0; - raw = raw3215[0]; /* 3215 console is the first one */ - if (raw == NULL || raw->irq == -1) - /* console device not found in con3215_init */ - return -1; - return raw3215_startup(raw); -} - -/* * Write a string to the 3215 console */ static void @@ -1092,12 +1061,10 @@ } } + /* - * 3215 console driver boottime initialization code. - * Register console. We can't request the IRQ here, because - * it's too early (kmalloc isn't working yet). We'll have to - * buffer all the console requests until we can request the - * irq. For this purpose we use some pages of fixed memory. + * 3215 console initialization code called from console_init(). + * NOTE: This is called before kmalloc is available. */ void __init con3215_init(void) { @@ -1121,6 +1088,8 @@ raw3215_freelist = req; } + ctrlchar_init(); + #ifdef CONFIG_3215_CONSOLE raw3215[0] = raw = (raw3215_info *) alloc_bootmem_low(sizeof(raw3215_info)); @@ -1135,6 +1104,10 @@ raw->tqueue.data = raw; init_waitqueue_head(&raw->empty_wait); + /* Request the console irq */ + if ( raw3215_startup(raw) != 0 ) + raw->irq = -1; + if (raw->irq != -1) { register_console(&con3215); } else { @@ -1145,7 +1118,16 @@ printk("Couldn't find a 3215 console device\n"); } #endif +} +/* + * 3215 tty registration code called from tty_init(). + * Most kernel services (incl. kmalloc) are available at this poimt. + */ +void __init tty3215_init(void) +{ + if (!MACHINE_IS_VM && !MACHINE_IS_P390) + return; /* * Initialize the tty_driver structure * Entries in tty3215_driver that are NOT initialized: @@ -1166,7 +1148,7 @@ tty3215_driver.init_termios.c_iflag = IGNBRK | IGNPAR; tty3215_driver.init_termios.c_oflag = ONLCR | XTABS; tty3215_driver.init_termios.c_lflag = ISIG; - tty3215_driver.flags = TTY_DRIVER_REAL_RAW; + tty3215_driver.flags = TTY_DRIVER_REAL_RAW; tty3215_driver.refcount = &tty3215_refcount; tty3215_driver.table = tty3215_table; tty3215_driver.termios = tty3215_termios; @@ -1194,5 +1176,4 @@ if (tty_register_driver(&tty3215_driver)) panic("Couldn't register tty3215 driver\n"); - } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/ctrlchar.c linux.ac/drivers/s390/char/ctrlchar.c --- linux.vanilla/drivers/s390/char/ctrlchar.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/s390/char/ctrlchar.c Thu Apr 12 12:03:49 2001 @@ -0,0 +1,96 @@ +/* + * drivers/s390/char/controlchar.c + * Unified handling of special chars. + * + * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Fritz Elfert <felfert@millenux.com> <elfert@de.ibm.com> + * + */ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/tty.h> +#include <linux/interrupt.h> + +#include <linux/sysrq.h> + +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/delay.h> +#include <asm/cpcmd.h> +#include <asm/irq.h> + +#ifdef CONFIG_MAGIC_SYSRQ +static int ctrlchar_sysrq_key; +static struct tq_struct ctrlchar_tq; + +static void +ctrlchar_handle_sysrq(struct tty_struct *tty) { + handle_sysrq(ctrlchar_sysrq_key, NULL, NULL, tty); +} +#endif + +void ctrlchar_init(void) { +#ifdef CONFIG_MAGIC_SYSRQ + static int init_done = 0; + + if (init_done++) + return; + INIT_LIST_HEAD(&ctrlchar_tq.list); + ctrlchar_tq.sync = 0; + ctrlchar_tq.routine = ctrlchar_handle_sysrq; +#endif +} + +/** + * Check for special chars at start of input. + * + * @param buf Console input buffer. + * @param len Length of valid data in buffer. + * @param tty The tty struct for this console. + * @return NULL, if nothing matched, (char *)-1, if buffer contents + * should be ignored, otherwise pointer to char to be inserted. + */ +char *ctrlchar_handle(const char *buf, int len, struct tty_struct *tty) { + + static char ret; + + if ((len < 2) || (len > 3)) + return NULL; + /* hat is 0xb1 in codepage 037 (US etc.) and thus */ + /* converted to 0x5e in ascii ('^') */ + if ((buf[0] != '^') && (buf[0] != '\252')) + return NULL; + switch (buf[1]) { +#ifdef CONFIG_MAGIC_SYSRQ + case '-': + if (len == 3) { + ctrlchar_sysrq_key = buf[2]; + ctrlchar_tq.data = tty; + queue_task(&ctrlchar_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + return (char *)-1; + } + break; +#endif + case 'c': + if (len == 2) { + ret = INTR_CHAR(tty); + return &ret; + } + break; + case 'd': + if (len == 2) { + ret = EOF_CHAR(tty); + return &ret; + } + break; + case 'z': + if (len == 2) { + ret = SUSP_CHAR(tty); + return &ret; + } + break; + } + return NULL; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/ctrlchar.h linux.ac/drivers/s390/char/ctrlchar.h --- linux.vanilla/drivers/s390/char/ctrlchar.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/s390/char/ctrlchar.h Sat Apr 14 01:28:50 2001 @@ -0,0 +1,14 @@ +/* + * drivers/s390/char/controlchar.c + * Unified handling of special chars. + * + * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Fritz Elfert <felfert@millenux.com> <elfert@de.ibm.com> + * + */ + +#include <linux/types.h> +#include <linux/tty.h> + +extern void ctrlchar_init(void); +extern char *ctrlchar_handle(const char *buf, int len, struct tty_struct *tty); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/hwc.h linux.ac/drivers/s390/char/hwc.h --- linux.vanilla/drivers/s390/char/hwc.h Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/char/hwc.h Thu Apr 12 12:03:49 2001 @@ -39,6 +39,8 @@ #define HWC_BUSY 2 #define HWC_NOT_OPERATIONAL 3 +#define hwc_cmdw_t u32; + #define HWC_CMDW_READDATA 0x00770005 #define HWC_CMDW_WRITEDATA 0x00760005 @@ -207,9 +209,25 @@ 0x0000, 0x0000, sizeof (_hwcb_mask_t), - ET_OpCmd_Mask | ET_PMsgCmd_Mask, - ET_Msg_Mask + ET_OpCmd_Mask | ET_PMsgCmd_Mask | ET_StateChange_Mask, + ET_Msg_Mask | ET_PMsgCmd_Mask }; + +typedef struct { + _EBUF_HEADER + u8 validity_hwc_active_facility_mask:1; + u8 validity_hwc_receive_mask:1; + u8 validity_hwc_send_mask:1; + u8 validity_read_data_function_mask:1; + u16 _zeros:12; + u16 mask_length; + u64 hwc_active_facility_mask; + _hwcb_mask_t hwc_receive_mask; + _hwcb_mask_t hwc_send_mask; + u32 read_data_function_mask; +} __attribute__ ((packed)) + +statechangebuf_t; #define _GDS_VECTOR_HEADER u16 length; \ u16 gds_id; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/hwc_con.c linux.ac/drivers/s390/char/hwc_con.c --- linux.vanilla/drivers/s390/char/hwc_con.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/char/hwc_con.c Thu Apr 12 12:03:49 2001 @@ -17,14 +17,13 @@ #include <linux/fs.h> #include <linux/init.h> +#include "ctrlchar.h" #include "hwc_rw.h" -extern void hwc_tty_init (void); - #ifdef CONFIG_HWC_CONSOLE #define hwc_console_major 4 -#define hwc_console_minor 0 +#define hwc_console_minor 64 #define hwc_console_name "console" void hwc_console_write (struct console *, const char *, unsigned int); @@ -84,17 +83,16 @@ hwc_console_init (void) { -#ifdef CONFIG_3215 +#if defined(CONFIG_3215_CONSOLE) || defined(CONFIG_3270_CONSOLE) if (MACHINE_IS_VM) return; #endif if (MACHINE_IS_P390) return; + ctrlchar_init (); + if (hwc_init () == 0) { - - hwc_tty_init (); - #ifdef CONFIG_HWC_CONSOLE register_console (&hwc_console); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/hwc_rw.c linux.ac/drivers/s390/char/hwc_rw.c --- linux.vanilla/drivers/s390/char/hwc_rw.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/char/hwc_rw.c Thu Apr 12 12:03:49 2001 @@ -30,9 +30,13 @@ #include <asm/s390_ext.h> #ifndef MIN -#define MIN(a,b) ((a<b) ? a : b) +#define MIN(a,b) (((a<b) ? a : b)) #endif +#define HWC_ASCEBC(x) ((MACHINE_IS_VM ? _ascebc[x] : _ascebc_500[x])) + +#define HWC_EBCASC_STR(s,c) ((MACHINE_IS_VM ? EBCASC(s,c) : EBCASC_500(s,c))) + #define HWC_RW_PRINT_HEADER "hwc low level driver: " #define USE_VM_DETECTION @@ -118,16 +122,16 @@ static unsigned char _page[PAGE_SIZE] __attribute__ ((aligned (PAGE_SIZE))); -/* pedantic: long because we use set_bit on it --RR */ -typedef long kmem_pages_t; +typedef unsigned long kmem_pages_t; #define MAX_KMEM_PAGES (sizeof(kmem_pages_t) << 3) -#define HWC_TIMER_RUNS 1 -#define HWC_FLUSH 2 -#define HWC_INIT 4 -#define HWC_BROKEN 8 -#define HWC_INTERRUPT 16 +#define HWC_WTIMER_RUNS 1 +#define HWC_FLUSH 2 +#define HWC_INIT 4 +#define HWC_BROKEN 8 +#define HWC_INTERRUPT 16 +#define HWC_PTIMER_RUNS 32 static struct { @@ -169,6 +173,7 @@ unsigned char write_prio:1; unsigned char read_nonprio:1; unsigned char read_prio:1; + unsigned char read_statechange:1; unsigned char flags; @@ -177,6 +182,8 @@ spinlock_t lock; struct timer_list write_timer; + + struct timer_list poll_timer; } hwc_data = { { @@ -186,7 +193,7 @@ 0, 80, 1, - 50, + MAX_KMEM_PAGES, MAX_KMEM_PAGES, 0, @@ -214,6 +221,7 @@ 0, 0, 0, + 0, NULL }; @@ -345,9 +353,6 @@ memcpy (hwcb, &write_hwcb_template, sizeof (write_hwcb_t)); - if (!hwc_data.write_nonprio && hwc_data.write_prio) - hwcb->msgbuf.type = ET_PMsgCmd; - return 0; } @@ -647,25 +652,58 @@ return count; } +static int write_event_data_1 (void); + +static void +do_poll_hwc (unsigned long data) +{ + unsigned long flags; + + spin_lock_irqsave (&hwc_data.lock, flags); + + write_event_data_1 (); + + spin_unlock_irqrestore (&hwc_data.lock, flags); +} + +void +start_poll_hwc (void) +{ + init_timer (&hwc_data.poll_timer); + hwc_data.poll_timer.function = do_poll_hwc; + hwc_data.poll_timer.data = (unsigned long) NULL; + hwc_data.poll_timer.expires = jiffies + 2 * HZ; + add_timer (&hwc_data.poll_timer); + hwc_data.flags |= HWC_PTIMER_RUNS; +} + static int write_event_data_1 (void) { unsigned short int condition_code; int retval; + write_hwcb_t *hwcb = (write_hwcb_t *) OUT_HWCB; - if ((!hwc_data.write_prio) && (!hwc_data.write_nonprio)) - return -EPERM; + if ((!hwc_data.write_prio) && + (!hwc_data.write_nonprio) && + hwc_data.read_statechange) + return -EOPNOTSUPP; if (hwc_data.current_servc) return -EBUSY; retval = sane_write_hwcb (); if (retval < 0) - return retval; + return -EIO; if (!OUT_HWCB_MTO) return -ENODATA; + if (!hwc_data.write_nonprio && hwc_data.write_prio) + hwcb->msgbuf.type = ET_PMsgCmd; + else + hwcb->msgbuf.type = ET_Msg; + condition_code = service_call (HWC_CMDW_WRITEDATA, OUT_HWCB); #ifdef DUMP_HWC_WRITE_ERROR @@ -688,6 +726,8 @@ case HWC_BUSY: retval = -EBUSY; break; + case HWC_NOT_OPERATIONAL: + start_poll_hwc (); default: retval = -EIO; } @@ -710,7 +750,7 @@ write_event_data_2 (void) { write_hwcb_t *hwcb; - int retval; + int retval = 0; #ifdef DUMP_HWC_WRITE_ERROR unsigned char *param; @@ -765,11 +805,22 @@ } #endif - if (hwcb->response_code == 0x0020) { + switch (hwcb->response_code) { + case 0x0020: retval = OUT_HWCB_CHAR; release_write_hwcb (); - } else { + break; + case 0x0040: + case 0x0340: + case 0x40F0: + if (!hwc_data.read_statechange) { + hwcb->response_code = 0; + start_poll_hwc (); + } + retval = -EIO; + break; + default: internal_print ( DELAYED_WRITE, HWC_RW_PRINT_HEADER @@ -782,6 +833,13 @@ retval = -EIO; } + if (retval == -EIO) { + + hwcb->control_mask[0] = 0; + hwcb->control_mask[1] = 0; + hwcb->control_mask[2] = 0; + hwcb->response_code = 0; + } hwc_data.current_servc = 0; hwc_data.current_hwcb = NULL; @@ -826,9 +884,9 @@ unsigned short count) { - if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_TIMER_RUNS)) { + if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_WTIMER_RUNS)) { del_timer (&hwc_data.write_timer); - hwc_data.flags &= ~HWC_TIMER_RUNS; + hwc_data.flags &= ~HWC_WTIMER_RUNS; } hwc_data.obuf_start += count; @@ -937,7 +995,7 @@ if (obuf_cursor < obuf_columns) { hwc_data.obuf[hwc_data.obuf_start + obuf_cursor] - = 0x20; + = HWC_ASCEBC (' '); obuf_cursor++; } else break; @@ -955,7 +1013,7 @@ while (spaces) { hwc_data.obuf[hwc_data.obuf_start + obuf_cursor - spaces] - = 0x20; + = HWC_ASCEBC (' '); spaces--; } @@ -985,9 +1043,7 @@ if (isprint (ch)) hwc_data.obuf[hwc_data.obuf_start + obuf_cursor++] - = (MACHINE_IS_VM) ? - _ascebc[ch] : - _ascebc_500[ch]; + = HWC_ASCEBC (ch); } if (obuf_cursor > obuf_count) obuf_count = obuf_cursor; @@ -1006,11 +1062,10 @@ if (hwc_data.ioctls.final_nl > 0) { - if (hwc_data.flags & HWC_TIMER_RUNS) { + if (hwc_data.flags & HWC_WTIMER_RUNS) { - hwc_data.write_timer.expires = - jiffies + - hwc_data.ioctls.final_nl * HZ / 10; + mod_timer (&hwc_data.write_timer, + jiffies + hwc_data.ioctls.final_nl * HZ / 10); } else { init_timer (&hwc_data.write_timer); @@ -1022,7 +1077,7 @@ jiffies + hwc_data.ioctls.final_nl * HZ / 10; add_timer (&hwc_data.write_timer); - hwc_data.flags |= HWC_TIMER_RUNS; + hwc_data.flags |= HWC_WTIMER_RUNS; } } else; @@ -1306,14 +1361,11 @@ if (hwc_data.ioctls.delim) count = seperate_cases (start, count); - if (MACHINE_IS_VM) - EBCASC (start, count); - else - EBCASC_500 (start, count); + HWC_EBCASC_STR (start, count); - if (hwc_data.ioctls.echo) { + if (hwc_data.ioctls.echo) do_hwc_write (0, start, count, IMMEDIATE_WRITE); - } + if (hwc_data.calls != NULL) if (hwc_data.calls->move_input != NULL) (hwc_data.calls->move_input) (start, count); @@ -1416,7 +1468,7 @@ return retval; } -inline static int +static int eval_evbuf (gds_vector_t * start, void *end) { gds_vector_t *vec; @@ -1434,6 +1486,128 @@ return retval; } +static inline int +eval_hwc_receive_mask (_hwcb_mask_t mask) +{ + + hwc_data.write_nonprio + = ((mask & ET_Msg_Mask) == ET_Msg_Mask); + + hwc_data.write_prio + = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask); + + if (hwc_data.write_prio || hwc_data.write_nonprio) { + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can write messages\n"); + return 0; + } else { + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can not write messages\n"); + return -1; + } +} + +static inline int +eval_hwc_send_mask (_hwcb_mask_t mask) +{ + + hwc_data.read_statechange + = ((mask & ET_StateChange_Mask) == ET_StateChange_Mask); + if (hwc_data.read_statechange) + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can read state change notifications\n"); + else + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can not read state change notifications\n"); + + hwc_data.read_nonprio + = ((mask & ET_OpCmd_Mask) == ET_OpCmd_Mask); + if (hwc_data.read_nonprio) + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can read commands\n"); + + hwc_data.read_prio + = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask); + if (hwc_data.read_prio) + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can read priority commands\n"); + + if (hwc_data.read_prio || hwc_data.read_nonprio) { + return 0; + } else { + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can not read commands from operator\n"); + return -1; + } +} + +static int +eval_statechangebuf (statechangebuf_t * scbuf) +{ + int retval = 0; + + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "HWC state change detected\n"); + + if (scbuf->validity_hwc_active_facility_mask) { + + } + if (scbuf->validity_hwc_receive_mask) { + + if (scbuf->mask_length != 4) { +#ifdef DUMP_HWC_INIT_ERROR + __asm__ ("LHI 1,0xe50\n\t" + "LRA 2,0(%0)\n\t" + "J .+0 \n\t" + : + : "a" (scbuf) + : "1", "2"); +#endif + } else { + + retval += eval_hwc_receive_mask + (scbuf->hwc_receive_mask); + } + } + if (scbuf->validity_hwc_send_mask) { + + if (scbuf->mask_length != 4) { +#ifdef DUMP_HWC_INIT_ERROR + __asm__ ("LHI 1,0xe51\n\t" + "LRA 2,0(%0)\n\t" + "J .+0 \n\t" + : + : "a" (scbuf) + : "1", "2"); +#endif + } else { + + retval += eval_hwc_send_mask + (scbuf->hwc_send_mask); + } + } + if (scbuf->validity_read_data_function_mask) { + + } + return retval; +} + static int process_evbufs (void *start, void *end) { @@ -1466,17 +1640,17 @@ retval += eval_evbuf (evbuf_data, evbuf_end); break; case ET_StateChange: - - retval = -ENOSYS; + retval += eval_statechangebuf + ((statechangebuf_t *) evbuf); break; default: - printk ( - KERN_WARNING - HWC_RW_PRINT_HEADER - "unconditional read: " - "unknown event buffer found, " - "type 0x%x", - evbuf->type); + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "unconditional read: " + "unknown event buffer found, " + "type 0x%x", + evbuf->type); retval = -ENOSYS; } evbuf = (evbuf_t *) evbuf_end; @@ -1491,11 +1665,14 @@ read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page; int retval; +#if 0 + if ((!hwc_data.read_prio) && (!hwc_data.read_nonprio)) return -EOPNOTSUPP; if (hwc_data.current_servc) return -EBUSY; +#endif memset (hwcb, 0x00, PAGE_SIZE); memcpy (hwcb, &read_hwcb_template, sizeof (read_hwcb_t)); @@ -1601,26 +1778,21 @@ 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"); + "unconditional read: invalid function code\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"); + "unconditional read: invalid selection mask\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"); + "unconditional read: HWC equipment check\n"); return -EIO; default: @@ -1677,27 +1849,7 @@ init_hwcb_t *hwcb = (init_hwcb_t *) hwc_data.page; int retval = 0; - 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 - "capable of receipt of commands\n"); - hwc_data.read_nonprio = 1; - } - if (hwcb->hwc_send_mask & ET_PMsgCmd_Mask) { - internal_print (DELAYED_WRITE, - HWC_RW_PRINT_HEADER - "capable of receipt of priority commands\n"); - hwc_data.read_nonprio = 1; - } - if ((hwcb->response_code != 0x0020) || - (!hwc_data.write_nonprio) || - ((!hwc_data.read_nonprio) && (!hwc_data.read_prio))) + if (hwcb->response_code != 0x0020) { #ifdef DUMP_HWC_INIT_ERROR __asm__ ("LHI 1,0xe11\n\t" "LRA 2,0(%0)\n\t" @@ -1707,8 +1859,24 @@ : "a" (hwcb), "a" (&(hwcb->response_code)) : "1", "2", "3"); #else - retval = -EIO; + retval = -1; #endif + } else { + if (hwcb->mask_length != 4) { +#ifdef DUMP_HWC_INIT_ERROR + __asm__ ("LHI 1,0xe52\n\t" + "LRA 2,0(%0)\n\t" + "J .+0 \n\t" + : + : "a" (hwcb) + : "1", "2"); +#endif + } else { + retval += eval_hwc_receive_mask + (hwcb->hwc_receive_mask); + retval += eval_hwc_send_mask (hwcb->hwc_send_mask); + } + } hwc_data.current_servc = 0; hwc_data.current_hwcb = NULL; @@ -1934,6 +2102,10 @@ } else { spin_lock (&hwc_data.lock); + if (hwc_data.flags & HWC_PTIMER_RUNS) { + del_timer (&hwc_data.poll_timer); + hwc_data.flags &= ~HWC_PTIMER_RUNS; + } if (!hwc_data.current_servc) { unconditional_read_1 (); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/hwc_tty.c linux.ac/drivers/s390/char/hwc_tty.c --- linux.vanilla/drivers/s390/char/hwc_tty.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/char/hwc_tty.c Sat Apr 14 01:28:50 2001 @@ -9,12 +9,15 @@ * Thanks to Martin Schwidefsky. */ +#include <linux/config.h> #include <linux/major.h> #include <linux/termios.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/devfs_fs_kernel.h> +#include <linux/init.h> #include <asm/uaccess.h> @@ -184,29 +187,13 @@ struct tty_struct *tty = hwc_tty_data.tty; if (tty != NULL) { - - if (count == 2 && ( - /* hat is 0xb0 in codepage 037 (US etc.) and thus */ - /* converted to 0x5e in ascii ('^') */ - strncmp (buf, "^c", 2) == 0 || - /* hat is 0xb0 in several other codepages (German, */ - /* UK, ...) and thus converted to ascii octal 252 */ - strncmp (buf, "\0252c", 2) == 0)) { - tty->flip.count++; - *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *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); - } else if (count == 2 && ( - strncmp (buf, "^z", 2) == 0 || - strncmp (buf, "\0252z", 2) == 0)) { + char *cchar; + if ((cchar = ctrlchar_handle (buf, count, tty))) { + if (cchar == (char *) -1) + return; tty->flip.count++; *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = SUSP_CHAR (tty); + *tty->flip.char_buf_ptr++ = *cchar; } else { memcpy (tty->flip.char_buf_ptr, buf, count); @@ -230,6 +217,13 @@ void hwc_tty_init (void) { +#ifdef CONFIG_3215 + if (MACHINE_IS_VM) + return; +#endif + if (MACHINE_IS_P390) + return; + 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; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tape.c linux.ac/drivers/s390/char/tape.c --- linux.vanilla/drivers/s390/char/tape.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/char/tape.c Thu Apr 12 12:03:49 2001 @@ -1,14 +1,13 @@ /*********************************************************************** * drivers/s390/char/tape.c - * tape device driver for S/390 tapes. + * tape device driver for S/390 and zSeries tapes. * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> * - * UNDER CONSTRUCTION: Work in progress... :-) *********************************************************************** */ @@ -34,9 +33,21 @@ #include <asm/s390dyn.h> #endif #include "tape.h" +#ifdef CONFIG_S390_TAPE_3490 #include "tape3490.h" +#endif +#ifdef CONFIG_S390_TAPE_3480 #include "tape3480.h" - +#endif +#ifdef CONFIG_S390_TAPE_BLOCK +#include "tapeblock.h" +#endif +#ifdef CONFIG_S390_TAPE_CHAR +#include "tapechar.h" +#endif +#ifdef CONFIG_PROC_FS +#include <linux/vmalloc.h> +#endif #define PRINTK_HEADER "T390:" /* state handling routines */ @@ -91,29 +102,118 @@ char* event_verbose[TE_SIZE]= { "TE_START", "TE_DONE", "TE_FAILED", "TE_ERROR", "TE_OTHER"}; -#ifdef CONFIG_PROC_FS /* don't waste space if unused */ -/* - * The proc filesystem: function to read and entry - */ -int -tape_read_procmem (char *buf, char **start, off_t offset, - int len, int unused) +/* our root devfs handle */ +#ifdef CONFIG_DEVFS_FS +devfs_handle_t tape_devfs_root_entry; + +inline void +tape_mkdevfsroots (tape_info_t* tape) +{ + char devno [5]; + sprintf (devno,"%04X",tape->devinfo.devno); + tape->devfs_dir=devfs_mk_dir (tape_devfs_root_entry, devno, tape); +} + +inline void +tape_rmdevfsroots (tape_info_t* tape) +{ + devfs_unregister (tape->devfs_dir); +} +#endif + +#ifdef CONFIG_PROC_FS +/* our proc tapedevices entry */ +static struct proc_dir_entry *tape_devices_entry; + +typedef struct { + char *data; + int len; +} tempinfo_t; + + +static int +tape_devices_open (struct inode *inode, struct file *file) +{ + int size=80; + tape_info_t* tape; + tempinfo_t* tempinfo; + char* data; + int pos=0; + tempinfo = kmalloc (sizeof(tempinfo_t),GFP_KERNEL); + if (!tempinfo) + return -ENOMEM; + for (tape=first_tape_info;tape!=NULL;tape=tape->next) + size+=80; // FIXME: Guess better! + data=vmalloc(size); + if (!data) { + kfree (tempinfo); + return -ENOMEM; + } + pos+=sprintf(data+pos,"TapeNo\tDevNo\tCuType\tCuModel\tDevType\tDevModel\tState\n"); + for (tape=first_tape_info;tape!=NULL;tape=tape->next) { + pos+=sprintf(data+pos,"%d\t%04X\t%04X\t%02X\t%04X\t%02X\t\t%s\n",tape->rew_minor/2, + tape->devinfo.devno,tape->devinfo.sid_data.cu_type, + tape->devinfo.sid_data.cu_model,tape->devinfo.sid_data.dev_type, + tape->devinfo.sid_data.dev_model,((tapestate_get(tape) >= 0) && + (tapestate_get(tape) < TS_SIZE)) ? + state_verbose[tapestate_get (tape)] : "TS UNKNOWN"); + } + tempinfo->len=pos; + tempinfo->data=data; + file->private_data= (void*) tempinfo; +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + return 0; +} + +static ssize_t +tape_devices_read (struct file *file, char *user_buf, size_t user_len, loff_t * offset) +{ + loff_t len; + tempinfo_t *p_info = (tempinfo_t *) file->private_data; + + if (*offset >= p_info->len) { + return 0; /* EOF */ + } else { + len = user_len<(p_info->len - *offset)?user_len:(p_info->len - *offset); + if (copy_to_user (user_buf, &(p_info->data[*offset]), len)) + return -EFAULT; + (*offset) += len; + return len; /* number of bytes "read" */ + } +} + +static int +tape_devices_release (struct inode *inode, struct file *file) { - tape_info_t *tape = first_tape_info; - len = sprintf (buf, "minor\tstate\n"); - do { - if (len >= PAGE_SIZE - 80) - len += sprintf (buf + len, "terminated...\n"); - len += sprintf (buf + len, - "%d\t%s\n", tape->rew_minor, - ((tapestate_get (tape) >= 0) && (tapestate_get (tape) < TS_SIZE)) ? - state_verbose[tapestate_get (tape)] : - "UNKNOWN STATE"); - } while ((tape = (tape_info_t *) (tape->next)) != NULL); - return len; + int rc = 0; + tempinfo_t *p_info = (tempinfo_t *) file->private_data; + if (p_info) { + if (p_info->data) + vfree (p_info->data); + kfree (p_info); + } +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + return rc; } -#endif /* CONFIG_PROC_FS */ +static struct file_operations tape_devices_file_ops = +{ + read:tape_devices_read, /* read */ + open:tape_devices_open, /* open */ + release:tape_devices_release, /* close */ +}; + +static struct inode_operations tape_devices_inode_ops = +{ +#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) + default_file_ops:&tape_devices_file_ops /* file ops */ +#endif /* LINUX_IS_24 */ +}; +#endif /* CONFIG_PROC_FS */ /* SECTION: Managing wrappers for ccwcache */ @@ -258,7 +358,11 @@ int rc,tape_num,retries=0; s390_dev_info_t dinfo; tape_discipline_t* disc; +#ifdef CONFIG_DEVFS_FS + tape_frontend_t* frontend; +#endif long lockflags; + PRINT_WARN ("oper handler was called\n"); while ((tape!=NULL) && (tape->devinfo.irq!=irq)) tape=tape->next; if (tape!=NULL) { @@ -270,13 +374,19 @@ rc = get_dev_info_by_irq (irq, &dinfo); if (rc == -ENODEV) { retries++; - if (retries > 5) + rc = get_dev_info_by_irq (irq, &dinfo); + if (retries > 5) { + PRINT_WARN ("No device information for new dev. could be retrieved.\n"); return -ENODEV; + } } disc = first_discipline; while ((disc != NULL) && (disc->cu_type != dinfo.sid_data.cu_type)) disc = (tape_discipline_t *) (disc->next); - + if (disc == NULL) + PRINT_WARN ("No matching discipline for cu_type %x found\n",dinfo.sid_data.cu_type); + if (rc == -ENODEV) + PRINT_WARN ("No device information for new dev. could be retrieved.\n"); if ((disc == NULL) || (rc == -ENODEV)) return -ENODEV; @@ -287,6 +397,7 @@ "tape info structure\n"); return -ENOBUFS; } + memset(tape,0,sizeof(tape_info_t)); tape->discipline = disc; disc->tape = tape; tape_num=0; @@ -306,6 +417,10 @@ kfree (tape); return -ENOBUFS; } +#ifdef CONFIG_DEVFS_FS + for (frontend=first_frontend;frontend!=NULL;frontend=frontend->next) + frontend->mkdevfstree(tape); +#endif s390irq_spin_lock_irqsave (irq,lockflags); if (first_tape_info == NULL) { first_tape_info = tape; @@ -324,41 +439,61 @@ tape_noper_handler ( int irq, int status ) { tape_info_t *ti=first_tape_info; tape_info_t *lastti; +#ifdef CONFIG_DEVFS_FS + tape_frontend_t *frontend; +#endif long lockflags; s390irq_spin_lock_irqsave(irq,lockflags); - while (ti!=NULL) { - if (ti->devinfo.irq==irq) { - tapestate_set(ti,TS_NOT_OPER); - if (tapestate_get(ti)!=TS_UNUSED) { - // device is in use! - PRINT_WARN ("Tape #%d was detached while it was busy. Expect errors!",ti->blk_minor); - ti->rc=-ENXIO; - wake_up_interruptible(&ti->wq); - } else { - // device is unused! - if (ti==first_tape_info) { - first_tape_info=ti->next; - } else { - lastti=first_tape_info; - while (lastti->next!=ti) lastti=lastti->next; - lastti->next=ti->next; - } - kfree(ti); - } - s390irq_spin_unlock_irqrestore(irq,lockflags); - return; + while (ti!=NULL && ti->devinfo.irq!=irq) ti=ti->next; + if (ti==NULL) return; + if (tapestate_get(ti)!=TS_UNUSED) { + // device is in use! + PRINT_WARN ("Tape #%d was detached while it was busy. Expect errors!",ti->blk_minor/2); + tapestate_set(ti,TS_NOT_OPER); + ti->rc=-ENODEV; + ti->wanna_wakeup=1; + switch (tapestate_get(ti)) { + case TS_REW_RELEASE_INIT: + tapestate_set(ti,TS_NOT_OPER); + wake_up (&ti->wq); + break; +#ifdef CONFIG_S390_TAPE_BLOCK + case TS_BLOCK_INIT: + tapestate_set(ti,TS_NOT_OPER); + schedule_tapeblock_exec_IO(ti); + break; +#endif + default: + tapestate_set(ti,TS_NOT_OPER); + wake_up_interruptible (&ti->wq); + } + } else { + // device is unused! + PRINT_WARN ("Tape #%d was detached.\n",ti->blk_minor/2); + if (ti==first_tape_info) { + first_tape_info=ti->next; + } else { + lastti=first_tape_info; + while (lastti->next!=ti) lastti=lastti->next; + lastti->next=ti->next; } - ti=ti->next; +#ifdef CONFIG_DEVFS_FS + for (frontend=first_frontend;frontend!=NULL;frontend=frontend->next) + frontend->rmdevfstree(ti); + tape_rmdevfsroots(ti); +#endif + kfree(ti); } s390irq_spin_unlock_irqrestore(irq,lockflags); - PRINT_WARN ("Tape not found for irq %d. Device is detached.",irq); + return; } void tape_dump_sense (devstat_t * stat) { - int sl, sct; + int sl; +#if 0 PRINT_WARN ("------------I/O resulted in unit check:-----------\n"); for (sl = 0; sl < 4; sl++) { PRINT_WARN ("Sense:"); @@ -388,6 +523,7 @@ stat->ii.sense.data[26], stat->ii.sense.data[27], stat->ii.sense.data[28], stat->ii.sense.data[29], stat->ii.sense.data[30], stat->ii.sense.data[31]); +#endif #ifdef TAPE_DEBUG debug_text_event (tape_debug_area,3,"SENSE:"); for (sl=0;sl<31;sl++) { @@ -413,6 +549,9 @@ ti->rew_minor = minor; ti->nor_minor = minor + 1; ti->blk_minor = minor; +#ifdef CONFIG_DEVFS_FS + tape_mkdevfsroots(ti); +#endif /* Register IRQ */ #ifdef CONFIG_S390_TAPE_DYNAMIC rc = s390_request_irq_special (irq, tape_irq, tape_noper_handler,0, "tape", &(ti->devstat)); @@ -424,7 +563,7 @@ if (rc) { PRINT_WARN ("Cannot register irq %d, rc=%d\n", irq, rc); } else - PRINT_WARN ("Register irq %d for using with discipline %x\n", irq, ti->discipline->cu_type); + PRINT_WARN ("Register irq %d for using with discipline %x dev #%d\n", irq, ti->discipline->cu_type,ti->blk_minor/2); init_waitqueue_head (&ti->wq); ti->kernbuf = ti->userbuf = ti->discdata = NULL; tapestate_set (ti, TS_UNUSED); @@ -460,7 +599,7 @@ #endif /* TAPE_DEBUG */ /* print banner */ - PRINT_WARN ("IBM S/390 Tape Device Driver (ALPHA).\n"); + PRINT_WARN ("IBM S/390 Tape Device Driver (BETA).\n"); PRINT_WARN ("(C) IBM Deutschland Entwicklung GmbH, 2000\n"); opt_char=opt_block=opt_3480=opt_3490="not present"; #ifdef CONFIG_S390_TAPE_CHAR @@ -496,6 +635,9 @@ ((tape_discipline_t*) (first_discipline->next))->next=NULL; } #endif +#ifdef CONFIG_DEVFS_FS + tape_devfs_root_entry=devfs_mk_dir (NULL, "tape", NULL); +#endif CONFIG_DEVFS_FS #ifdef TAPE_DEBUG debug_text_event (tape_debug_area,3,"dev detect"); @@ -558,17 +700,40 @@ /* Allocate local buffer for the ccwcache */ tape_init_emergency_req (); - -#if 0 // need to register s.th. for proc? FIXME! - if (proc_register_dynamic (&proc_root, &proc_root_tape)) - PRINT_INFO (KERN_ERR "tape: registering " - "/proc/tape failed\n"); +#ifdef CONFIG_PROC_FS +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) + tape_devices_entry = create_proc_entry ("tapedevices", + S_IFREG | S_IRUGO | S_IWUSR, + &proc_root); + tape_devices_entry->proc_fops = &tape_devices_file_ops; + tape_devices_entry->proc_iops = &tape_devices_inode_ops; +#else + tape_devices_entry = (struct proc_dir_entry *) kmalloc + (sizeof (struct proc_dir_entry), GFP_ATOMIC); + if (tape_devices_entry) { + memset (tape_devices_entry, 0, sizeof (struct proc_dir_entry)); + tape_devices_entry->name = "tapedevices"; + tape_devices_entry->namelen = strlen ("tapedevices"); + tape_devices_entry->low_ino = 0; + tape_devices_entry->mode = (S_IFREG | S_IRUGO | S_IWUSR); + tape_devices_entry->nlink = 1; + tape_devices_entry->uid = 0; + tape_devices_entry->gid = 0; + tape_devices_entry->size = 0; + tape_devices_entry->get_info = NULL; + tape_devices_entry->ops = &tape_devices_inode_ops; + proc_register (&proc_root, tape_devices_entry); + } #endif +#endif /* CONFIG_PROC_FS */ return 0; } #ifdef MODULE +MODULE_AUTHOR("(C) 2001 IBM Deutschland Entwicklung GmbH by Carsten Otte (cotte@de.ibm.com)"); +MODULE_DESCRIPTION("Linux for S/390 channel attached tape device driver"); + int init_module (void) { @@ -578,7 +743,7 @@ #ifdef CONFIG_S390_TAPE_BLOCK tapeblock_init (); #endif - return 0; + return 0; } void @@ -591,10 +756,6 @@ debug_text_event (tape_debug_area,6,"cleaup mod"); #endif /* TAPE_DEBUG */ -#if 0 /* FIXME: Do we need to register s.th? */ - proc_unregister (&proc_root, proc_root_tape.low_ino); -#endif - tape = first_tape_info; while (tape != NULL) { temp = tape; @@ -607,13 +768,25 @@ free_irq (temp->devinfo.irq, &(temp->devstat)); if (temp->discdata) kfree (temp->discdata); if (temp->kernbuf) kfree (temp->kernbuf); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) // COMPAT:FIXME -#else - kfree (temp->wq); -#endif if (temp->cqr) tape_free_request(temp->cqr); +#ifdef CONFIG_DEVFS_FS + for (frontend=first_frontend;frontend!=NULL;frontend=frontend->next) + frontend->rmdevfstree(temp); + tape_rmdevfsroots(temp); +#endif kfree (temp); } +#ifdef CONFIG_DEVFS_FS + devfs_unregister (tape_devfs_root_entry); +#endif CONFIG_DEVFS_FS +#ifdef CONFIG_PROC_FS +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) + remove_proc_entry ("devices", &proc_root); +#else + proc_unregister (&proc_root, tape_devices_entry->low_ino); + kfree (tape_devices_entry); +#endif /* LINUX_IS_24 */ +#endif #ifdef CONFIG_S390_TAPE_CHAR tapechar_uninit(); #endif @@ -689,18 +862,22 @@ state_verbose[tapestate_get (tape)] : "TS UNKNOWN"); #endif /* TAPE_DEBUG */ - if ((event >= 0) && - (event < TE_SIZE) && - (tapestate_get (tape) >= 0) && - (tapestate_get (tape) < TS_SIZE) && - ((*(tape->discipline->event_table))[tapestate_get (tape)][event] != NULL)) + if (event == TE_ERROR) { + tape->discipline->error_recovery(tape); + } else { + if ((event >= 0) && + (event < TE_SIZE) && + (tapestate_get (tape) >= 0) && + (tapestate_get (tape) < TS_SIZE) && + ((*(tape->discipline->event_table))[tapestate_get (tape)][event] != NULL)) ((*(tape->discipline->event_table))[tapestate_get (tape)][event]) (tape); - else { + else { #ifdef TAPE_DEBUG debug_text_exception (tape_debug_area,3,"TE UNEXPEC"); #endif /* TAPE_DEBUG */ tape->discipline->default_handler (tape); - } + } + } } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tape.h linux.ac/drivers/s390/char/tape.h --- linux.vanilla/drivers/s390/char/tape.h Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/char/tape.h Thu Apr 12 12:03:49 2001 @@ -1,15 +1,13 @@ - /*************************************************************************** * * drivers/s390/char/tape.h * tape device driver for 3480/3490E tapes. * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> * - * UNDER CONSTRUCTION: Work in progress...:-) **************************************************************************** */ @@ -71,10 +69,14 @@ typedef ccw_req_t* (*tape_rwblock_t)(const char* data,size_t count,struct _tape_info_t* tape); typedef void (*tape_freeblock_t)(ccw_req_t* cqr,struct _tape_info_t* tape); typedef void (*tape_setup_assist_t) (struct _tape_info_t*); +#ifdef CONFIG_DEVFS_FS +typedef void (*tape_devfs_handler_t) (struct _tape_info_t*); +#endif typedef tape_event_handler_t tape_event_table_t[TS_SIZE][TE_SIZE]; typedef struct _tape_discipline_t { unsigned int cu_type; tape_setup_assist_t setup_assist; + tape_event_handler_t error_recovery; tape_reqgen_t bread; tape_freeblock_t free_bread; tape_rwblock_t write_block; @@ -115,6 +117,10 @@ typedef struct _tape_frontend_t { tape_setup_assist_t device_setup; +#ifdef CONFIG_DEVFS_FS + tape_devfs_handler_t mkdevfstree; + tape_devfs_handler_t rmdevfstree; +#endif void* next; } tape_frontend_t __attribute__ ((aligned(8))); @@ -142,6 +148,14 @@ ccw_req_t* cqr; atomic_t bh_scheduled; struct tq_struct bh_tq; +#ifdef CONFIG_DEVFS_FS + devfs_handle_t devfs_dir; /* devfs handle for tape/DEVNO directory */ + devfs_handle_t devfs_char_dir; /* devfs handle for tape/DEVNO/char directory */ + devfs_handle_t devfs_block_dir; /* devfs handle for tape/DEVNO/block directory */ + devfs_handle_t devfs_nonrewinding; /* devfs handle for tape/DEVNO/char/nonrewinding device */ + devfs_handle_t devfs_rewinding; /* devfs handle for tape/DEVNO/char/rewinding device */ + devfs_handle_t devfs_disc; /* devfs handle for tape/DEVNO/block/disc device */ +#endif void* discdata; void* kernbuf; void* userbuf; @@ -167,6 +181,7 @@ /* functions for handling the status of a device */ inline void tapestate_set (tape_info_t * tape, int newstate); inline int tapestate_get (tape_info_t * tape); +void tapestate_event (tape_info_t * tape, int event); extern char* state_verbose[TS_SIZE]; extern char* event_verbose[TE_SIZE]; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tape3480.c linux.ac/drivers/s390/char/tape3480.c --- linux.vanilla/drivers/s390/char/tape3480.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/char/tape3480.c Thu Apr 12 12:03:49 2001 @@ -3,12 +3,11 @@ * drivers/s390/char/tape3480.c * tape device discipline for 3480 tapes. * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> - * - * UNDER CONSTRUCTION: Work in progress...:-) + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> + * **************************************************************************** */ @@ -25,31 +24,31 @@ tape_event_handler_t tape3480_event_handler_table[TS_SIZE][TE_SIZE] = { /* {START , DONE, FAILED, ERROR, OTHER } */ - {NULL, tape34xx_unused_done, NULL, tape34xx_unused_error, NULL}, /* TS_UNUSED */ - {NULL, tape34xx_idle_done, NULL, tape34xx_idle_error, NULL}, /* TS_IDLE */ + {NULL, tape34xx_unused_done, NULL, NULL, NULL}, /* TS_UNUSED */ + {NULL, tape34xx_idle_done, NULL, NULL, NULL}, /* TS_IDLE */ {NULL, NULL, NULL, NULL, NULL}, /* TS_DONE */ {NULL, NULL, NULL, NULL, NULL}, /* TS_FAILED */ - {NULL, tape34xx_block_done, NULL, tape34xx_block_error, NULL}, /* TS_BLOCK_INIT */ + {NULL, tape34xx_block_done, NULL, NULL, NULL}, /* TS_BLOCK_INIT */ {NULL, tape34xx_bsb_init_done, NULL, NULL, NULL}, /* TS_BSB_INIT */ {NULL, tape34xx_bsf_init_done, NULL, NULL, NULL}, /* TS_BSF_INIT */ {NULL, tape34xx_dse_init_done, NULL, NULL, NULL}, /* TS_DSE_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_EGA_INIT */ {NULL, tape34xx_fsb_init_done, NULL, NULL, NULL}, /* TS_FSB_INIT */ - {NULL, tape34xx_fsf_init_done, NULL, tape34xx_fsf_init_error, NULL}, /* TS_FSF_INIT */ + {NULL, tape34xx_fsf_init_done, NULL, NULL, NULL}, /* TS_FSF_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_LDI_INIT */ - {NULL, tape34xx_lbl_init_done, NULL, tape34xx_lbl_init_error, NULL}, /* TS_LBL_INIT */ + {NULL, tape34xx_lbl_init_done, NULL, NULL, NULL}, /* TS_LBL_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_MSE_INIT */ {NULL, tape34xx_nop_init_done, NULL, NULL, NULL}, /* TS_NOP_INIT */ - {NULL, NULL, NULL, NULL, NULL}, /* TS_RBA_INIT */ + {NULL, tape34xx_rfo_init_done, NULL, NULL, NULL}, /* TS_RBA_INIT */ {NULL, tape34xx_rbi_init_done, NULL, NULL, NULL}, /* TS_RBI_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RBU_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RBL_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RDC_INIT */ - {NULL, tape34xx_rfo_init_done, NULL, tape34xx_rfo_init_error, NULL}, /* TS_RFO_INIT */ + {NULL, tape34xx_rfo_init_done, NULL, NULL, NULL}, /* TS_RFO_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RSD_INIT */ - {NULL, tape34xx_rew_init_done, NULL, tape34xx_rew_init_error, NULL}, /* TS_REW_INIT */ - {NULL, tape34xx_rew_release_init_done, NULL, tape34xx_rew_release_init_error, NULL}, /* TS_REW_RELEASE_IMIT */ - {NULL, tape34xx_run_init_done, NULL, tape34xx_run_init_error, NULL}, /* TS_RUN_INIT */ + {NULL, tape34xx_rew_init_done, NULL, NULL, NULL}, /* TS_REW_INIT */ + {NULL, tape34xx_rew_release_init_done, NULL, NULL, NULL}, /* TS_REW_RELEASE_IMIT */ + {NULL, tape34xx_run_init_done, NULL, NULL, NULL}, /* TS_RUN_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_SEN_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_SID_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_SNP_INIT */ @@ -59,14 +58,16 @@ {NULL, NULL, NULL, NULL, NULL}, /* TS_SYN_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_TIO_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_UNA_INIT */ - {NULL, tape34xx_wri_init_done, NULL, tape34xx_wri_init_error, NULL}, /* TS_WRI_INIT */ - {NULL, tape34xx_wtm_init_done, NULL, tape34xx_wtm_init_error, NULL}, /* TS_WTM_INIT */ + {NULL, tape34xx_wri_init_done, NULL, NULL, NULL}, /* TS_WRI_INIT */ + {NULL, tape34xx_wtm_init_done, NULL, NULL, NULL}, /* TS_WTM_INIT */ {NULL, NULL, NULL, NULL, NULL}}; /* TS_NOT_OPER */ devreg_t tape3480_devreg = { - ci : { hc: { ctype: 0x3480, dtype: 0x3480 } }, - flag: DEVREG_MATCH_CU_TYPE, - oper_func: tape_oper_handler + ci: + {hc: + {ctype:0x3480}}, + flag:DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS, + oper_func:tape_oper_handler }; @@ -101,6 +102,7 @@ } disc->cu_type = 0x3480; disc->setup_assist = tape3480_setup_assist; + disc->error_recovery = tape34xx_error_recovery; disc->write_block = tape34xx_write_block; disc->free_write_block = tape34xx_free_write_block; disc->read_block = tape34xx_read_block; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tape3480.h linux.ac/drivers/s390/char/tape3480.h --- linux.vanilla/drivers/s390/char/tape3480.h Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/char/tape3480.h Thu Apr 12 12:03:49 2001 @@ -1,15 +1,13 @@ - /*************************************************************************** * * drivers/s390/char/tape3480.h * tape device discipline for 3480 tapes. * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> * - * UNDER CONSTRUCTION: Work in progress...:-) **************************************************************************** */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tape3490.c linux.ac/drivers/s390/char/tape3490.c --- linux.vanilla/drivers/s390/char/tape3490.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/char/tape3490.c Thu Apr 12 12:03:49 2001 @@ -3,12 +3,11 @@ * drivers/s390/char/tape3490.c * tape device discipline for 3490E tapes. * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> * - * UNDER CONSTRUCTION: Work in progress...:-) **************************************************************************** */ @@ -25,31 +24,31 @@ tape_event_handler_t tape3490_event_handler_table[TS_SIZE][TE_SIZE] = { /* {START , DONE, FAILED, ERROR, OTHER } */ - {NULL, tape34xx_unused_done, NULL, tape34xx_unused_error, NULL}, /* TS_UNUSED */ - {NULL, tape34xx_idle_done, NULL, tape34xx_idle_error, NULL}, /* TS_IDLE */ + {NULL, tape34xx_unused_done, NULL, NULL, NULL}, /* TS_UNUSED */ + {NULL, tape34xx_idle_done, NULL, NULL, NULL}, /* TS_IDLE */ {NULL, NULL, NULL, NULL, NULL}, /* TS_DONE */ {NULL, NULL, NULL, NULL, NULL}, /* TS_FAILED */ - {NULL, tape34xx_block_done, NULL, tape34xx_block_error, NULL}, /* TS_BLOCK_INIT */ + {NULL, tape34xx_block_done, NULL, NULL, NULL}, /* TS_BLOCK_INIT */ {NULL, tape34xx_bsb_init_done, NULL, NULL, NULL}, /* TS_BSB_INIT */ {NULL, tape34xx_bsf_init_done, NULL, NULL, NULL}, /* TS_BSF_INIT */ {NULL, tape34xx_dse_init_done, NULL, NULL, NULL}, /* TS_DSE_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_EGA_INIT */ {NULL, tape34xx_fsb_init_done, NULL, NULL, NULL}, /* TS_FSB_INIT */ - {NULL, tape34xx_fsf_init_done, NULL, tape34xx_fsf_init_error, NULL}, /* TS_FSF_INIT */ + {NULL, tape34xx_fsf_init_done, NULL, NULL, NULL}, /* TS_FSF_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_LDI_INIT */ - {NULL, tape34xx_lbl_init_done, NULL, tape34xx_lbl_init_error, NULL}, /* TS_LBL_INIT */ + {NULL, tape34xx_lbl_init_done, NULL, NULL, NULL}, /* TS_LBL_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_MSE_INIT */ {NULL, tape34xx_nop_init_done, NULL, NULL, NULL}, /* TS_NOP_INIT */ - {NULL, NULL, NULL, NULL, NULL}, /* TS_RBA_INIT */ + {NULL, tape34xx_rfo_init_done, NULL, NULL, NULL}, /* TS_RBA_INIT */ {NULL, tape34xx_rbi_init_done, NULL, NULL, NULL}, /* TS_RBI_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RBU_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RBL_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RDC_INIT */ - {NULL, tape34xx_rfo_init_done, NULL, tape34xx_rfo_init_error, NULL}, /* TS_RFO_INIT */ + {NULL, tape34xx_rfo_init_done, NULL, NULL, NULL}, /* TS_RFO_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RSD_INIT */ - {NULL, tape34xx_rew_init_done, NULL, tape34xx_rew_init_error, NULL}, /* TS_REW_INIT */ - {NULL, tape34xx_rew_release_init_done, NULL, tape34xx_rew_release_init_error, NULL}, /* TS_REW_RELEASE_IMIT */ - {NULL, tape34xx_run_init_done, NULL, tape34xx_run_init_error, NULL}, /* TS_RUN_INIT */ + {NULL, tape34xx_rew_init_done, NULL, NULL, NULL}, /* TS_REW_INIT */ + {NULL, tape34xx_rew_release_init_done, NULL, NULL, NULL}, /* TS_REW_RELEASE_IMIT */ + {NULL, tape34xx_run_init_done, NULL, NULL, NULL}, /* TS_RUN_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_SEN_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_SID_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_SNP_INIT */ @@ -59,14 +58,16 @@ {NULL, NULL, NULL, NULL, NULL}, /* TS_SYN_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_TIO_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_UNA_INIT */ - {NULL, tape34xx_wri_init_done, NULL, tape34xx_wri_init_error, NULL}, /* TS_WRI_INIT */ - {NULL, tape34xx_wtm_init_done, NULL, tape34xx_wtm_init_error, NULL}, /* TS_WTM_INIT */ + {NULL, tape34xx_wri_init_done, NULL, NULL, NULL}, /* TS_WRI_INIT */ + {NULL, tape34xx_wtm_init_done, NULL, NULL, NULL}, /* TS_WTM_INIT */ {NULL, NULL, NULL, NULL, NULL}}; /* TS_NOT_OPER */ devreg_t tape3490_devreg = { - ci : { hc: { ctype: 0x3490, dtype: 0x3490 } }, - flag: DEVREG_MATCH_CU_TYPE, - oper_func: tape_oper_handler + ci: + {hc: + {ctype:0x3490}}, + flag:DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS, + oper_func:tape_oper_handler }; void @@ -100,6 +101,7 @@ } disc->cu_type = 0x3490; disc->setup_assist = tape3490_setup_assist; + disc->error_recovery = tape34xx_error_recovery; disc->write_block = tape34xx_write_block; disc->free_write_block = tape34xx_free_write_block; disc->read_block = tape34xx_read_block; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tape3490.h linux.ac/drivers/s390/char/tape3490.h --- linux.vanilla/drivers/s390/char/tape3490.h Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/char/tape3490.h Thu Apr 12 12:03:49 2001 @@ -4,12 +4,11 @@ * drivers/s390/char/tape3490.h * tape device discipline for 3490E tapes. * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> * - * UNDER CONSTRUCTION: Work in progress...:-) **************************************************************************** */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tape34xx.c linux.ac/drivers/s390/char/tape34xx.c --- linux.vanilla/drivers/s390/char/tape34xx.c Tue Apr 3 17:32:17 2001 +++ linux.ac/drivers/s390/char/tape34xx.c Thu Apr 12 12:03:49 2001 @@ -3,12 +3,11 @@ * drivers/s390/char/tape34xx.c * common tape device discipline for 34xx tapes. * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> * - * UNDER CONSTRUCTION: Work in progress...:-) **************************************************************************** */ @@ -36,19 +35,19 @@ tape_event_handler_t tape34xx_event_handler_table[TS_SIZE][TE_SIZE] = { /* {START , DONE, FAILED, ERROR, OTHER } */ - {NULL, tape34xx_unused_done, NULL, tape34xx_unused_error, NULL}, /* TS_UNUSED */ - {NULL, tape34xx_idle_done, NULL, tape34xx_idle_error, NULL}, /* TS_IDLE */ + {NULL, tape34xx_unused_done, NULL, NULL, NULL}, /* TS_UNUSED */ + {NULL, tape34xx_idle_done, NULL, NULL, NULL}, /* TS_IDLE */ {NULL, NULL, NULL, NULL, NULL}, /* TS_DONE */ {NULL, NULL, NULL, NULL, NULL}, /* TS_FAILED */ - {NULL, tape34xx_block_done, NULL, tape34xx_block_error, NULL}, /* TS_BLOCK_INIT */ + {NULL, tape34xx_block_done, NULL, NULL, NULL}, /* TS_BLOCK_INIT */ {NULL, tape34xx_bsb_init_done, NULL, NULL, NULL}, /* TS_BSB_INIT */ {NULL, tape34xx_bsf_init_done, NULL, NULL, NULL}, /* TS_BSF_INIT */ {NULL, tape34xx_dse_init_done, NULL, NULL, NULL}, /* TS_DSE_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_EGA_INIT */ {NULL, tape34xx_fsb_init_done, NULL, NULL, NULL}, /* TS_FSB_INIT */ - {NULL, tape34xx_fsf_init_done, NULL, tape34xx_fsf_init_error, NULL}, /* TS_FSF_INIT */ + {NULL, tape34xx_fsf_init_done, NULL, NULL, NULL}, /* TS_FSF_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_LDI_INIT */ - {NULL, tape34xx_lbl_init_done, NULL, tape34xx_lbl_init_error, NULL}, /* TS_LBL_INIT */ + {NULL, tape34xx_lbl_init_done, NULL, NULL, NULL}, /* TS_LBL_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_MSE_INIT */ {NULL, tape34xx_nop_init_done, NULL, NULL, NULL}, /* TS_NOP_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RBA_INIT */ @@ -56,11 +55,11 @@ {NULL, NULL, NULL, NULL, NULL}, /* TS_RBU_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RBL_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RDC_INIT */ - {NULL, tape34xx_rfo_init_done, NULL, tape34xx_rfo_init_error, NULL}, /* TS_RFO_INIT */ + {NULL, tape34xx_rfo_init_done, NULL, NULL, NULL}, /* TS_RFO_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RSD_INIT */ - {NULL, tape34xx_rew_init_done, NULL, tape34xx_rew_init_error, NULL}, /* TS_REW_INIT */ - {NULL, tape34xx_rew_release_init_done, NULL, tape34xx_rew_release_init_error, NULL}, /* TS_REW_RELEASE_IMIT */ - {NULL, tape34xx_run_init_done, NULL, tape34xx_run_init_error, NULL}, /* TS_RUN_INIT */ + {NULL, tape34xx_rew_init_done, NULL, NULL, NULL}, /* TS_REW_INIT */ + {NULL, tape34xx_rew_release_init_done, NULL, NULL, NULL}, /* TS_REW_RELEASE_IMIT */ + {NULL, tape34xx_run_init_done, NULL, NULL, NULL}, /* TS_RUN_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_SEN_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_SID_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_SNP_INIT */ @@ -70,8 +69,8 @@ {NULL, NULL, NULL, NULL, NULL}, /* TS_SYN_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_TIO_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_UNA_INIT */ - {NULL, tape34xx_wri_init_done, NULL, tape34xx_wri_init_error, NULL}, /* TS_WRI_INIT */ - {NULL, tape34xx_wtm_init_done, NULL, tape34xx_wtm_init_error, NULL}, /* TS_WTM_INIT */ + {NULL, tape34xx_wri_init_done, NULL, NULL, NULL}, /* TS_WRI_INIT */ + {NULL, tape34xx_wtm_init_done, NULL, NULL, NULL}, /* TS_WTM_INIT */ {NULL, NULL, NULL, NULL, NULL}}; /* TS_NOT_OPER */ @@ -205,6 +204,59 @@ #endif /* TAPE_DEBUG */ return cqr; } +ccw_req_t * +tape34xx_read_opposite (tape_info_t * tape,int novalue) +{ + ccw_req_t *cqr; + ccw1_t *ccw; + size_t count; + // first, retrieve the count from the old cqr. + cqr = tape->cqr; + ccw = cqr->cpaddr; + ccw++; + count=ccw->count; + // free old cqr. + clear_normalized_cda (ccw); + tape_free_request (cqr); + // build new cqr + cqr = tape_alloc_ccw_req (tape, 3, 0); + if (!cqr) { +#ifdef TAPE_DEBUG + debug_text_exception (tape_debug_area,6,"xrop nomem"); +#endif /* TAPE_DEBUG */ + return NULL; + } + ccw = cqr->cpaddr; + ccw->cmd_code = MODE_SET_DB; + ccw->flags = CCW_FLAG_CC; + ccw->count = 1; + set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte))); + ccw++; + + ccw->cmd_code = READ_BACKWARD; + ccw->flags = CCW_FLAG_CC; + ccw->count = count; + set_normalized_cda (ccw, (unsigned long) tape->kernbuf); + if ((ccw->cda) == 0) { + tape_free_request (cqr); + return NULL; + } + ccw++; + ccw->cmd_code = FORSPACEBLOCK; + ccw->flags = CCW_FLAG_CC; + ccw->count = 1; + ccw->cda = (unsigned long)ccw; + ccw++; + ccw->cmd_code = NOP; + ccw->flags = 0; + ccw->count = 1; + ccw->cda = (unsigned long)ccw; + tapestate_set (tape, TS_RBA_INIT); +#ifdef TAPE_DEBUG + debug_text_event (tape_debug_area,6,"xrop ccwg"); +#endif /* TAPE_DEBUG */ + return cqr; +} void tape34xx_free_read_block (ccw_req_t * cqr, tape_info_t * tape) @@ -233,7 +285,6 @@ #endif /* TAPE_DEBUG */ } - /* * The IOCTL interface is implemented in the following section, * excepted the MTRESET, MTSETBLK which are handled by tapechar.c @@ -1329,7 +1380,7 @@ else bhct++; } - if ((data = kmalloc (4 * sizeof (__u8), GFP_KERNEL)) == NULL) { + if ((data = kmalloc (4 * sizeof (__u8), GFP_ATOMIC)) == NULL) { #ifdef TAPE_DEBUG debug_text_exception (tape_debug_area,3,"xBREDnomem"); #endif /* TAPE_DEBUG */ @@ -1395,9 +1446,8 @@ size, blksize_size[tapeblock_major][tape->blk_minor], req->nr_sectors); - - tape_free_request (cqr); kfree(data); + tape_free_request (cqr); return NULL; } } @@ -1506,17 +1556,6 @@ } } -void -tape34xx_unused_error (tape_info_t * tape) -{ -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"unsol.irq!"); - debug_text_event (tape_debug_area,3,"unit chk!"); - debug_int_exception (tape_debug_area,3,tape->devinfo.irq); -#endif /* TAPE_DEBUG */ - PRINT_WARN ("Unsolicited IRQ (Unit Check) caught in unused state.\n"); - tape_dump_sense (&tape->devstat); -} void tape34xx_idle_done (tape_info_t * tape) @@ -1531,18 +1570,6 @@ } void -tape34xx_idle_error (tape_info_t * tape) -{ -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"unsol.irq!"); - debug_text_event (tape_debug_area,3,"unit chk!"); - debug_int_exception (tape_debug_area,3,tape->devinfo.irq); -#endif /* TAPE_DEBUG */ - PRINT_WARN ("Unsolicited IRQ (Unit Check) caught in idle state.\n"); - tape_dump_sense (&tape->devstat); -} - -void tape34xx_block_done (tape_info_t * tape) { #ifdef TAPE_DEBUG @@ -1553,16 +1580,6 @@ } void -tape34xx_block_error (tape_info_t * tape) -{ -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"x:xREQfail"); -#endif /* TAPE_DEBUG */ - tapestate_set(tape,TS_FAILED); - schedule_tapeblock_exec_IO(tape); -} - -void tape34xx_bsf_init_done (tape_info_t * tape) { #ifdef TAPE_DEBUG @@ -1599,27 +1616,6 @@ } void -tape34xx_fsf_init_error (tape_info_t * tape) -{ - if (((tape->devstat.ii.sense.data[0] == 0x08) || // sense.data[0]=08 -> first time - (tape->devstat.ii.sense.data[0] == 0x10) || // an alternate one... - (tape->devstat.ii.sense.data[0] == 0x12)) && // sense.data[1]=12 -> repeated message - (tape->devstat.ii.sense.data[1] == 0x40)) { - // end of recorded area! -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"fsf fail"); - debug_text_exception (tape_debug_area,3,"eoRecArea"); -#endif /* TAPE_DEBUG */ - tape->rc = -EIO; - tapestate_set (tape, TS_FAILED); - tape->wanna_wakeup=1; - wake_up_interruptible (&tape->wq); - } else { - tape34xx_unexpect_uchk_handler (tape); - } -} - -void tape34xx_fsb_init_done (tape_info_t * tape) { #ifdef TAPE_DEBUG @@ -1657,29 +1653,6 @@ } void -tape34xx_lbl_init_error (tape_info_t * tape) -{ - if (((tape->devstat.ii.sense.data[0] == 0x00) || // sense.data[0]=00 -> first time - (tape->devstat.ii.sense.data[0] == 0x08) || // an alternate one... - (tape->devstat.ii.sense.data[0] == 0x10) || // alternate, too - (tape->devstat.ii.sense.data[0] == 0x12)) && // sense.data[1]=12 -> repeated message - ((tape->devstat.ii.sense.data[1] == 0x40) || - (tape->devstat.ii.sense.data[1] == 0xc0))) { - // block not found! -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"lbl fail"); - debug_text_exception (tape_debug_area,3,"blk nfound"); -#endif /* TAPE_DEBUG */ - tape->rc = -EIO; - tapestate_set (tape, TS_FAILED); - tape->wanna_wakeup=1; - wake_up_interruptible (&tape->wq); - } else { - tape34xx_unexpect_uchk_handler (tape); - } -} - -void tape34xx_nop_init_done (tape_info_t * tape) { #ifdef TAPE_DEBUG @@ -1699,11 +1672,8 @@ #ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"rfo done"); #endif - //BH: use irqsave - //s390irq_spin_lock(tape->devinfo.irq); tapestate_set (tape, TS_DONE); tape->rc = 0; - //s390irq_spin_unlock(tape->devinfo.irq); tape->wanna_wakeup=1; wake_up_interruptible (&tape->wq); } @@ -1729,50 +1699,6 @@ } void -tape34xx_rfo_init_error (tape_info_t * tape) -{ - if (((tape->devstat.ii.sense.data[0] == 0x08) || // sense.data[0]=08 -> first time - (tape->devstat.ii.sense.data[0] == 0x10) || // an alternate one... - (tape->devstat.ii.sense.data[0] == 0x12)) && // sense.data[1]=12 -> repeated message - (tape->devstat.ii.sense.data[1] == 0x40)) { - // end of recorded area! -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"rfo fail"); - debug_text_exception (tape_debug_area,3,"eoRecArea"); -#endif /* TAPE_DEBUG */ - tape->rc = 0; - tapestate_set (tape, TS_FAILED); - tape->wanna_wakeup=1; - wake_up_interruptible (&tape->wq); - } else { - switch (tape->devstat.ii.sense.data[3]) { - case 0x48: -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"rfo fail"); - debug_text_exception (tape_debug_area,3,"recov x48"); -#endif /* TAPE_DEBUG */ - //s390irq_spin_lock(tape->devinfo.irq); - do_IO (tape->devinfo.irq, tape->cqr->cpaddr, (unsigned long) (tape->cqr), 0x00, tape->cqr->options); - //s390irq_spin_unlock(tape->devinfo.irq); - break; - case 0x2c: - PRINT_ERR ("TAPE: Permanent Unit Check. Please check your hardware!"); -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"rfo fail"); - debug_text_exception (tape_debug_area,3,"Perm UCK"); -#endif - tape->rc = -EIO; - tapestate_set (tape, TS_FAILED); - tape->wanna_wakeup=1; - wake_up_interruptible (&tape->wq); - break; - default: - tape34xx_unexpect_uchk_handler (tape); - } - } -} - -void tape34xx_rew_init_done (tape_info_t * tape) { #ifdef TAPE_DEBUG @@ -1788,44 +1714,6 @@ } void -tape34xx_rew_release_init_error (tape_info_t * tape) -{ - if ((tape->devstat.ii.sense.data[0] == 0x40) && - (tape->devstat.ii.sense.data[1] == 0x40) && - (tape->devstat.ii.sense.data[3] == 0x43)) { - // no tape in the drive - PRINT_INFO ("Drive %d not ready. No volume loaded.\n", tape->rew_minor / 2); -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"rewR fail"); - debug_text_exception (tape_debug_area,3,"no medium"); -#endif - tapestate_set (tape, TS_FAILED); - tape->rc = -ENOMEDIUM; - tape->wanna_wakeup=1; - wake_up (&tape->wq); - } else { - PRINT_ERR ("TAPE34XX: An unexpected Unit Check occurred.\n"); - PRINT_ERR ("TAPE34XX: Please send the following 20 lines of output to cotte@de.ibm.com\n"); - PRINT_ERR ("TAPE34XX: Current state is: %s", - (((tapestate_get (tape) < TS_SIZE) && (tapestate_get (tape) >= 0)) ? - state_verbose[tapestate_get (tape)] : "->UNKNOWN STATE<-")); - tapestate_set (tape, TS_FAILED); -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"rewR unexp"); - debug_text_event (tape_debug_area,3,"state:"); - debug_text_event (tape_debug_area,3,((tapestate_get (tape) < TS_SIZE) && - (tapestate_get (tape) >= 0)) ? - state_verbose[tapestate_get (tape)] : - "TS UNKNOWN"); -#endif /* TAPE_DEBUG */ - tape_dump_sense (&tape->devstat); - tape->rc = -EIO; - tape->wanna_wakeup=1; - wake_up (&tape->wq); - } -} - -void tape34xx_rew_release_init_done (tape_info_t * tape) { #ifdef TAPE_DEBUG @@ -1839,12 +1727,6 @@ } void -tape34xx_rew_init_error (tape_info_t * tape) -{ - tape34xx_unexpect_uchk_handler (tape); -} - -void tape34xx_run_init_done (tape_info_t * tape) { #ifdef TAPE_DEBUG @@ -1857,27 +1739,6 @@ } void -tape34xx_run_init_error (tape_info_t * tape) -{ - - switch (tape->devstat.ii.sense.data[3]) { - case 0x52: - // This error is fine for rewind and unload - // It reports that no volume is loaded... -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,6,"run done"); -#endif /* TAPE_DEBUG */ - tapestate_set (tape, TS_DONE); - tape->rc = 0; - tape->wanna_wakeup=1; - wake_up_interruptible (&tape->wq); - break; - default: - tape34xx_unexpect_uchk_handler (tape); - } -} - -void tape34xx_wri_init_done (tape_info_t * tape) { #ifdef TAPE_DEBUG @@ -1893,72 +1754,632 @@ } void -tape34xx_wri_init_error (tape_info_t * tape) +tape34xx_wtm_init_done (tape_info_t * tape) { - if ((tape->devstat.ii.sense.data[0]==0x80)&&(tape->devstat.ii.sense.data[1]==0x4a)) { - // tape is write protected #ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"wri fail"); - debug_text_exception (tape_debug_area,3,"writProte"); -#endif /* TAPE_DEBUG */ - tape->rc = -EACCES; - tapestate_set (tape, TS_FAILED); + debug_text_event (tape_debug_area,3,"wtm done"); +#endif + tapestate_set (tape, TS_DONE); + tape->rc = 0; tape->wanna_wakeup=1; wake_up_interruptible (&tape->wq); - } else { - switch (tape->devstat.ii.sense.data[3]) { - case 0x48: -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"wri fail"); - debug_text_exception (tape_debug_area,3,"recov x48"); -#endif /* TAPE_DEBUG */ - //s390irq_spin_lock(tape->devinfo.irq); - do_IO (tape->devinfo.irq, tape->cqr->cpaddr, (unsigned long) (tape->cqr), 0x00, tape->cqr->options); - //s390irq_spin_unlock(tape->devinfo.irq); - break; - case 0x2c: - PRINT_ERR ("TAPE: Permanent Unit Check. Please check your hardware!\n"); -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"wri fail"); - debug_text_exception (tape_debug_area,3,"Perm UCK"); -#endif - tape->rc = -EIO; - tapestate_set (tape, TS_FAILED); - tape->wanna_wakeup=1; - wake_up_interruptible (&tape->wq); - break; - case 0x38: //end of tape -#ifdef TAPE_DEBUG - PRINT_WARN ("TAPE: End of Tape reached.\n"); - debug_text_event (tape_debug_area,3,"wri fail"); - debug_text_exception (tape_debug_area,3,"EOT!"); -#endif - tape->rc = tape->devstat.rescnt; - tapestate_set (tape, TS_FAILED); - tape->wanna_wakeup=1; - wake_up_interruptible (&tape->wq); - break; +} + +/* This function analyses the tape's sense-data in case of a unit-check. If possible, + it tries to recover from the error. Else the user is informed about the problem. */ +void +tape34xx_error_recovery (tape_info_t* tape) +{ + __u8* sense=tape->devstat.ii.sense.data; + int inhibit_cu_recovery=0; + int cu_type=tape->discipline->cu_type; + if ((((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)&0x80) inhibit_cu_recovery=1; + if (tapestate_get(tape)==TS_BLOCK_INIT) { + // no recovery for block device, bottom half will retry... + tape34xx_error_recovery_has_failed(tape,EIO); + return; + } + if (sense[0]&SENSE_COMMAND_REJECT) + switch (tapestate_get(tape)) { + case TS_BLOCK_INIT: + case TS_DSE_INIT: + case TS_EGA_INIT: + case TS_WRI_INIT: + case TS_WTM_INIT: + if (sense[1]&SENSE_WRITE_PROTECT) { + // trying to write, but medium is write protected + tape34xx_error_recovery_has_failed(tape,EACCES); + return; + } default: - tape34xx_unexpect_uchk_handler (tape); + tape34xx_error_recovery_HWBUG(tape,1); + return; + } + // special cases for various tape-states when reaching end of recorded area + if (((sense[0]==0x08) || (sense[0]==0x10) || (sense[0]==0x12)) && + ((sense[1]==0x40) || (sense[1]==0x0c))) + switch (tapestate_get(tape)) { + case TS_FSF_INIT: + // Trying to seek beyond end of recorded area + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case TS_LBL_INIT: + // Block could not be located. + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case TS_RFO_INIT: + // Try to read beyond end of recorded area -> 0 bytes read + tape34xx_error_recovery_has_failed(tape,0); + return; + } + // Sensing special bits + if (sense[0]&SENSE_BUS_OUT_CHECK) { + tape34xx_error_recovery_do_retry(tape); + return; + } + if (sense[0]&SENSE_DATA_CHECK) { + // hardware failure, damaged tape or improper operating conditions + switch (sense[3]) { + case 0x23: + // a read data check occurred + if ((sense[2]&SENSE_TAPE_SYNC_MODE) || + (inhibit_cu_recovery)) { + // data check is not permanent, may be recovered. + // We always use async-mode with cu-recovery, so this should *never* happen. + tape34xx_error_recovery_HWBUG(tape,2); + return; + } else { + // data check is permanent, CU recovery has failed + PRINT_WARN("Permanent read error, recovery failed!\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + } + case 0x25: + // a write data check occurred + if ((sense[2]&SENSE_TAPE_SYNC_MODE) || + (inhibit_cu_recovery)) { + // data check is not permanent, may be recovered. + // We always use async-mode with cu-recovery, so this should *never* happen. + tape34xx_error_recovery_HWBUG(tape,3); + return; + } else { + // data check is permanent, cu-recovery has failed + PRINT_WARN("Permanent write error, recovery failed!\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + } + case 0x26: + // Data Check (read opposite) occurred. We'll recover this. + tape34xx_error_recovery_read_opposite(tape); + return; + case 0x28: + // The ID-Mark at the beginning of the tape could not be written. This is fatal, we'll report and exit. + PRINT_WARN("ID-Mark could not be written. Check your hardware!\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x31: + // Tape void. Tried to read beyond end of device. We'll report and exit. + PRINT_WARN("Try to read beyond end of recorded area!\n"); + tape34xx_error_recovery_has_failed(tape,ENOSPC); + return; + case 0x41: + // Record sequence error. cu detected incorrect block-id sequence on tape. We'll report and exit. + PRINT_WARN("Illegal block-id sequence found!\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + default: + // well, all data checks for 3480 should result in one of the above erpa-codes. if not -> bug + // On 3490, other data-check conditions do exist. + if (cu_type==0x3480) { + tape34xx_error_recovery_HWBUG(tape,4); + return; + } } } + if (sense[0]&SENSE_OVERRUN) { + // A data overrun between cu and drive occurred. The channel speed is to slow! We'll report this and exit! + switch (sense[3]) { + case 0x40: // overrun error + PRINT_WARN ("Data overrun error between control-unit and drive. Use a faster channel connection, if possible! \n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + default: + // Overrun bit is set, but erpa does not show overrun error. This is a bug. + tape34xx_error_recovery_HWBUG(tape,5); + return; + } + } + if (sense[1]&SENSE_RECORD_SEQUENCE_ERR) { + switch (sense[3]) { + case 0x41: + // Record sequence error. cu detected incorrect block-id sequence on tape. We'll report and exit. + PRINT_WARN("Illegal block-id sequence found!\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + default: + // Record sequence error bit is set, but erpa does not show record sequence error. This is a bug. + tape34xx_error_recovery_HWBUG(tape,6); + return; + } + } + // Sensing erpa codes + switch (sense[3]) { + case 0x00: + // Everything is fine, but we got a unit check. Report and ignore! + PRINT_WARN ("Non-error sense was found. Unit-check will be ignored, expect errors...\n"); + return; + case 0x21: + // Data streaming not operational. Cu switches to interlock mode, we reissue the command. + PRINT_WARN ("Data streaming not operational. Switching to interlock-mode! \n"); + tape34xx_error_recovery_do_retry(tape); + return; + case 0x22: + // Path equipment check. Might be drive adapter error, buffer error on the lower interface, internal path not useable, or error during cartridge load. + // All of the above are not recoverable + PRINT_WARN ("A path equipment check occurred. One of the following conditions occurred:\n"); + PRINT_WARN ("drive adapter error,buffer error on the lower interface, internal path not useable, error during cartridge load.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x23: + // Read data check. Should have been be covered earlier -> Bug! + tape34xx_error_recovery_HWBUG(tape,7); + return; + case 0x24: + // Load display check. Load display was command was issued, but the drive is displaying a drive check message. Can be threated as "device end". + tape34xx_error_recovery_succeded(tape); + return; + case 0x25: + // Write data check. Should have been covered earlier -> Bug! + tape34xx_error_recovery_HWBUG(tape,8); + return; + case 0x26: + // Data check (read opposite). Should have been covered earlier -> Bug! + tape34xx_error_recovery_HWBUG(tape,9); + return; + case 0x27: + // Command reject. May indicate illegal channel program or buffer over/underrun. + // Since all channel programms are issued by this driver and ought be correct, + // we assume a over/underrun situaltion and retry the channel program. + tape34xx_error_recovery_do_retry(tape); + return; + case 0x28: + // Write id mark check. Should have beed covered earlier -> bug! + tape34xx_error_recovery_HWBUG(tape,10); + return; + case 0x29: + // Function incompatible. Either idrc is on but hardware not capable doing idrc + // or a perform subsystem func is issued and the cu is not online. Anyway, this + // cannot be recovered and is an I/O error. + PRINT_WARN ("Function incompatible. Try to switch off idrc! \n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x2a: + // Unsolicited environmental data. An internal counter overflows, we can ignore + // this and reissue the cmd. + tape34xx_error_recovery_do_retry(tape); + return; + case 0x2b: + // Environmental data present. Indicates either unload completed ok or read buffered + // log command completed ok. + if (tapestate_get(tape)==TS_RUN_INIT) { + // Rewind unload completed ok. + tape34xx_error_recovery_succeded(tape); + return; + } + // Since we do not issue read buffered log commands, this should never occur -> bug. + tape34xx_error_recovery_HWBUG(tape,11); + return; + case 0x2c: + // Permanent equipment check. cu has tried recovery, but did not succeed. This is an + // I/O error. + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x2d: + // Data security erase failure. + if (tapestate_get(tape)==TS_DSE_INIT) { + // report an I/O error + tape34xx_error_recovery_has_failed(tape,EIO); + return; + } + // Data security erase failure, but no such command issued. This is a bug. + tape34xx_error_recovery_HWBUG(tape,12); + return; + case 0x2e: + // Not capable. This indicates either that the drive fails reading the format id mark + // or that that format specified is not supported by the drive. We write a message and + // return an I/O error. + PRINT_WARN("Drive not capable processing the tape format!"); + tape34xx_error_recovery_has_failed(tape,EMEDIUMTYPE); + return; + case 0x2f: + // This erpa is reserved. This is a bug. + tape34xx_error_recovery_HWBUG(tape,13); + return; + case 0x30: + // The medium is write protected, while trying to write on it. We'll report this. + PRINT_WARN("Medium is write protected!\n"); + tape34xx_error_recovery_has_failed(tape,EACCES); + return; + case 0x31: + // Tape void. Should have beed covered ealier -> bug + tape34xx_error_recovery_HWBUG(tape,14); + return; + case 0x32: + // Tension loss. We cannot recover this, it's an I/O error. + PRINT_WARN("The drive lost tape tension.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x33: + // Load Failure. The catridge was not inserted correctly or the tape is not threaded + // correctly. We cannot recover this, the user has to reload the catridge. + PRINT_WARN("Cartridge load failure. Reload the cartridge and try again.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x34: + // Unload failure. The drive cannot maintain tape tension and control tape movement + // during an unload operation. + PRINT_WARN("Failure during cartridge unload. Please try manually.\n"); + if (tapestate_get(tape)!=TS_RUN_INIT) { + tape34xx_error_recovery_HWBUG(tape,15); + return; + } + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x35: + // Drive equipment check. One of the following: + // - cu cannot recover from a drive detected error + // - a check code message is displayed on drive message/load displays + // - the cartridge loader does not respond correctly + // - a failure occurs during an index, load, or unload cycle + PRINT_WARN("Equipment check! Please check the drive and the cartridge loader.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x36: + switch (cu_type) { + case 0x3480: + // This erpa is reserved for 3480 -> BUG + tape34xx_error_recovery_HWBUG(tape,16); + return; + case 0x3490: + // End of data. This is a permanent I/O error, which cannot be recovered. + // A read-type command has reached the end-of-data mark. + tape34xx_error_recovery_has_failed(tape,EIO); + return; + } + case 0x37: + // Tape length error. The tape is shorter than reported in the beginning-of-tape data. + PRINT_WARN("Tape length error.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x38: + // Physical end of tape. A read/write operation reached the physical end of tape. + if (tapestate_get(tape)==TS_WRI_INIT) { + tape34xx_error_recovery_has_failed(tape,ENOSPC); + } + return; + case 0x39: + // Backward at BOT. The drive is at BOT and is requestet to move backward. + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x3a: + // Drive switched not ready, but the command needs the drive to be ready. + PRINT_WARN("Drive not ready. Turn the ready/not ready switch to ready position and try again.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x3b: + // Manual rewind or unload. This causes an I/O error. + PRINT_WARN("Medium is rewinded or unloaded manually.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x3c: + case 0x3d: + case 0x3e: + case 0x3f: + // These erpas are reserved -> BUG + tape34xx_error_recovery_HWBUG(tape,17); + return; + case 0x40: + // Overrun error. This should have been covered earlier -> bug. + tape34xx_error_recovery_HWBUG(tape,18); + return; + case 0x41: + // Record sequence error. This should have been covered earlier -> bug. + tape34xx_error_recovery_HWBUG(tape,19); + return; + case 0x42: + // Degraded mode. A condition that can cause degraded performace is detected. + PRINT_WARN("Subsystem is running in degraded mode. This may compromise your performace.\n"); + tape34xx_error_recovery_do_retry(tape); + return; + case 0x43: + // Drive not ready. Probably swith the ready/not ready switch to ready? + PRINT_WARN("The drive is not ready. Maybe no medium in?\n"); + tape34xx_error_recovery_has_failed(tape,ENOMEDIUM); + return; + case 0x44: + // Locate Block unsuccessfull. We'll report this. + if ((tapestate_get(tape)!=TS_BLOCK_INIT) && + (tapestate_get(tape)!=TS_LBL_INIT)) { + tape34xx_error_recovery_HWBUG(tape,20); // No locate block was issued... + return; + } + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x45: + // The drive is assigned elsewhere [to a different channel path/computer]. + PRINT_WARN("The drive is assigned elsewhere.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x46: + // Drive not online. Drive may be switched offline, the power supply may be switched off + // or the drive address may not be set correctly. + PRINT_WARN("The drive is not online."); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x47: + // Volume fenced. cu reports volume integrity is lost! + PRINT_WARN("Volume fenced. The volume integrity is lost! \n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x48: + // Log sense data and retry request. We'll do so... + tape34xx_error_recovery_do_retry(tape); + return; + case 0x49: + // Bus out check. A parity check error on the bus was found. PRINT_WARN("Bus out check. A data transfer over the bus was corrupted.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x4a: + // Control unit erp failed. We'll report this. + PRINT_WARN("The control unit failed recovering an I/O error.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x4b: + // Cu and drive incompatible. The drive requests micro-program patches, which are not available on the cu. + PRINT_WARN("The drive needs microprogram patches from the control unit, which are not available.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x4c: + // Recovered Check-One failure. Cu develops a hardware error, but is able to recover. We'll reissue the command. + tape34xx_error_recovery_do_retry(tape); + return; + case 0x4d: + switch (cu_type) { + case 0x3480: + // This erpa is reserved for 3480 -> bug + tape34xx_error_recovery_HWBUG(tape,21); + return; + case 0x3490: + // Resetting event recieved. Since the driver does not support resetting event recovery + // (which has to be handled by the I/O Layer), we'll report and retry our command. + tape34xx_error_recovery_do_retry(tape); + return; + } + case 0x4e: + switch (cu_type) { + case 0x3480: + // This erpa is reserved for 3480 -> bug. + tape34xx_error_recovery_HWBUG(tape,22); + return; + case 0x3490: + // Maximum block size exeeded. This indicates, that the block to be written is larger + // than allowed for buffered mode. We'll report this... + PRINT_WARN("Maximum block size for buffered mode exceeded.\n"); + tape34xx_error_recovery_has_failed(tape,ENOBUFS); + return; + } + case 0x4f: + // These erpas are reserved -> bug + tape34xx_error_recovery_HWBUG(tape,23); + return; + case 0x50: + // Read buffered log (Overflow). Cu is running in extended beffered log mode, and a counter overflows. + // This should never happen, since we're never running in extended buffered log mode -> bug. + tape34xx_error_recovery_do_retry(tape); + return; + case 0x51: + // Read buffered log (EOV). EOF processing occurs while the cu is in extended buffered log mode. + // This should never happen, since we're never running in extended buffered log mode -> bug. + tape34xx_error_recovery_do_retry(tape); + return; + case 0x52: + // End of Volume complete. Rewind unload completed ok. We'll report to the user... + if (tapestate_get(tape)!=TS_RUN_INIT) { + tape34xx_error_recovery_HWBUG(tape,24); + return; + } + tape34xx_error_recovery_succeded(tape); + return; + case 0x53: + // Global command intercept. We'll have to reissue our command. + tape34xx_error_recovery_do_retry(tape); + return; + case 0x54: + // Channel interface recovery (temporary). This can be recovered by reissuing the command. + tape34xx_error_recovery_do_retry(tape); + return; + case 0x55: + // Channel interface recovery (permanent). This cannot be recovered, we'll inform the user. + PRINT_WARN("A permanent channel interface error occurred.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x56: + // Channel protocol error. This cannot be recovered. + PRINT_WARN("A channel protocol error occurred.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x57: + switch (cu_type) { + case 0x3480: + // Attention intercept. We have to reissue the command. + PRINT_WARN("An attention intercept occurred, which will be recovered.\n"); + tape34xx_error_recovery_do_retry(tape); + return; + case 0x3490: + // Global status intercept. We have to reissue the command. + PRINT_WARN("An global status intercept was recieved, which will be recovered.\n"); + tape34xx_error_recovery_do_retry(tape); + return; + } + case 0x58: + case 0x59: + // These erpas are reserved -> bug. + tape34xx_error_recovery_HWBUG(tape,25); + return; + case 0x5a: + // Tape length incompatible. The tape inserted is too long, + // which could cause damage to the tape or the drive. + PRINT_WARN("Tape length incompatible [should be IBM Cartridge System Tape]. May cause damage to drive or tape.n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x5b: + // Format 3480 XF incompatible + if (sense[1]&SENSE_BEGINNING_OF_TAPE) { + // Everything is fine. The tape will be overwritten in a different format. + tape34xx_error_recovery_do_retry(tape); + return; + } + PRINT_WARN("Tape format is incompatible to the drive, which writes 3480-2 XF.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x5c: + // Format 3480-2 XF incompatible + PRINT_WARN("Tape format is incompatible to the drive. The drive cannot access 3480-2 XF volumes.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x5d: + // Tape length violation. + PRINT_WARN("Tape length violation [should be IBM Enhanced Capacity Cartridge System Tape]. May cause damage to drive or tape.\n"); + tape34xx_error_recovery_has_failed(tape,EMEDIUMTYPE); + return; + case 0x5e: + // Compaction algorithm incompatible. + PRINT_WARN("The volume is recorded using an incompatible compaction algorith, which is not supported by the control unit.\n"); + tape34xx_error_recovery_has_failed(tape,EMEDIUMTYPE); + return; + default: + // Reserved erpas -> bug + tape34xx_error_recovery_HWBUG(tape,26); + return; + } } -void -tape34xx_wtm_init_done (tape_info_t * tape) -{ +void tape34xx_error_recovery_has_failed (tape_info_t* tape,int error_id) { #ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"wtm done"); + debug_text_event (tape_debug_area,3,"xerp fail"); + debug_text_event (tape_debug_area,3,(((tapestate_get (tape) < TS_SIZE) && + (tapestate_get (tape) >= 0)) ? + state_verbose[tapestate_get (tape)] : "UNKNOWN")); #endif - tapestate_set (tape, TS_DONE); - tape->rc = 0; + if ((tapestate_get(tape)!=TS_UNUSED) && (tapestate_get(tape)!=TS_IDLE)) { + tape_dump_sense(&tape->devstat); + tape->rc = -error_id; tape->wanna_wakeup=1; - wake_up_interruptible (&tape->wq); + switch (tapestate_get(tape)) { + case TS_REW_RELEASE_INIT: + tapestate_set(tape,TS_FAILED); + wake_up (&tape->wq); + break; + case TS_BLOCK_INIT: + tapestate_set(tape,TS_FAILED); + schedule_tapeblock_exec_IO(tape); + break; + default: + tapestate_set(tape,TS_FAILED); + wake_up_interruptible (&tape->wq); + } + } else { + PRINT_WARN("Recieved an unsolicited IRQ.\n"); + tape_dump_sense(&tape->devstat); + } +} + +void tape34xx_error_recovery_succeded(tape_info_t* tape) { +#ifdef TAPE_DEBUG + debug_text_event (tape_debug_area,3,"xerp done"); + debug_text_event (tape_debug_area,3,(((tapestate_get (tape) < TS_SIZE) && + (tapestate_get (tape) >= 0)) ? + state_verbose[tapestate_get (tape)] : "UNKNOWN")); +#endif + if ((tapestate_get(tape)!=TS_UNUSED) && (tapestate_get(tape)!=TS_DONE)) { + tapestate_event (tape, TE_DONE); + } else { + PRINT_WARN("Recieved an unsolicited IRQ.\n"); + tape_dump_sense(&tape->devstat); + } } -void -tape34xx_wtm_init_error (tape_info_t * tape) -{ - tape34xx_unexpect_uchk_handler (tape); +void tape34xx_error_recovery_do_retry(tape_info_t* tape) { +#ifdef TAPE_DEBUG + debug_text_event (tape_debug_area,3,"xerp retr"); + debug_text_event (tape_debug_area,3,(((tapestate_get (tape) < TS_SIZE) && + (tapestate_get (tape) >= 0)) ? + state_verbose[tapestate_get (tape)] : "UNKNOWN")); +#endif + if ((tapestate_get(tape)!=TS_UNUSED) && (tapestate_get(tape)!=TS_IDLE)) { + tape_dump_sense(&tape->devstat); + while (do_IO (tape->devinfo.irq, tape->cqr->cpaddr, (unsigned long) tape->cqr, 0x00, tape->cqr->options)); + } else { + PRINT_WARN("Recieved an unsolicited IRQ.\n"); + tape_dump_sense(&tape->devstat); + } +} +void +tape34xx_error_recovery_read_opposite (tape_info_t* tape) { + switch (tapestate_get(tape)) { + case TS_RFO_INIT: + // We did read forward, but the data could not be read *correctly*. + // We will read backward and then skip forward again. + tape->cqr=tape34xx_read_opposite(tape,0); + if (tape->cqr==NULL) + tape34xx_error_recovery_has_failed(tape,EIO); + else + tape34xx_error_recovery_do_retry(tape); + break; + case TS_RBA_INIT: + // We tried to read forward and backward, but hat no success -> failed. + tape34xx_error_recovery_has_failed(tape,EIO); + break; + case TS_BLOCK_INIT: + tape34xx_error_recovery_do_retry(tape); + break; + default: + PRINT_WARN("read_opposite_recovery_called_with_state:%s\n", + (((tapestate_get (tape) < TS_SIZE) && + (tapestate_get (tape) >= 0)) ? + state_verbose[tapestate_get (tape)] : "UNKNOWN")); + } +} + +void +tape34xx_error_recovery_HWBUG (tape_info_t* tape,int condno) { + devstat_t* stat=&tape->devstat; + PRINT_WARN("An unexpected condition #%d was caught in tape error recovery.\n",condno); + PRINT_WARN("Please report this incident.\n"); + PRINT_WARN("State of the tape:%s\n", + (((tapestate_get (tape) < TS_SIZE) && + (tapestate_get (tape) >= 0)) ? + state_verbose[tapestate_get (tape)] : "UNKNOWN")); + PRINT_INFO ("Sense data: %02X%02X%02X%02X %02X%02X%02X%02X " + " %02X%02X%02X%02X %02X%02X%02X%02X \n", + stat->ii.sense.data[0], stat->ii.sense.data[1], + stat->ii.sense.data[2], stat->ii.sense.data[3], + stat->ii.sense.data[4], stat->ii.sense.data[5], + stat->ii.sense.data[6], stat->ii.sense.data[7], + stat->ii.sense.data[8], stat->ii.sense.data[9], + stat->ii.sense.data[10], stat->ii.sense.data[11], + stat->ii.sense.data[12], stat->ii.sense.data[13], + stat->ii.sense.data[14], stat->ii.sense.data[15]); + PRINT_INFO ("Sense data: %02X%02X%02X%02X %02X%02X%02X%02X " + " %02X%02X%02X%02X %02X%02X%02X%02X \n", + stat->ii.sense.data[16], stat->ii.sense.data[17], + stat->ii.sense.data[18], stat->ii.sense.data[19], + stat->ii.sense.data[20], stat->ii.sense.data[21], + stat->ii.sense.data[22], stat->ii.sense.data[23], + stat->ii.sense.data[24], stat->ii.sense.data[25], + stat->ii.sense.data[26], stat->ii.sense.data[27], + stat->ii.sense.data[28], stat->ii.sense.data[29], + stat->ii.sense.data[30], stat->ii.sense.data[31]); + tape34xx_error_recovery_has_failed(tape,EIO); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tape34xx.h linux.ac/drivers/s390/char/tape34xx.h --- linux.vanilla/drivers/s390/char/tape34xx.h Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/char/tape34xx.h Thu Apr 12 12:03:49 2001 @@ -4,12 +4,11 @@ * drivers/s390/char/tape34xx.h * common tape device discipline for 34xx tapes. * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> * - * UNDER CONSTRUCTION: Work in progress...:-) **************************************************************************** */ @@ -85,6 +84,31 @@ #define CONTROL_UNIT_END DEV_STAT_CU_END /* redefine from irq.h */ #define INCORR_LEN SCHN_STAT_INCORR_LEN /* redefine from irq.h */ +#define SENSE_COMMAND_REJECT 0x80 +#define SENSE_INTERVENTION_REQUIRED 0x40 +#define SENSE_BUS_OUT_CHECK 0x20 +#define SENSE_EQUIPMENT_CHECK 0x10 +#define SENSE_DATA_CHECK 0x08 +#define SENSE_OVERRUN 0x04 +#define SENSE_DEFERRED_UNIT_CHECK 0x02 +#define SENSE_ASSIGNED_ELSEWHERE 0x01 + +#define SENSE_LOCATE_FAILURE 0x80 +#define SENSE_DRIVE_ONLINE 0x40 +#define SENSE_RESERVED 0x20 +#define SENSE_RECORD_SEQUENCE_ERR 0x10 +#define SENSE_BEGINNING_OF_TAPE 0x08 +#define SENSE_WRITE_MODE 0x04 +#define SENSE_WRITE_PROTECT 0x02 +#define SENSE_NOT_CAPABLE 0x01 + +#define SENSE_CHANNEL_ADAPTER_CODE 0xE0 +#define SENSE_CHANNEL_ADAPTER_LOC 0x10 +#define SENSE_REPORTING_CU 0x08 +#define SENSE_AUTOMATIC_LOADER 0x04 +#define SENSE_TAPE_SYNC_MODE 0x02 +#define SENSE_TAPE_POSITIONING 0x01 + typedef struct _tape34xx_disc_data_t { __u8 modeset_byte; } tape34xx_disc_data_t __attribute__ ((packed, aligned(8))); @@ -130,33 +154,30 @@ void tape34xx_default_handler (tape_info_t * tape); void tape34xx_unexpect_uchk_handler (tape_info_t * tape); void tape34xx_unused_done(tape_info_t* tape); -void tape34xx_unused_error(tape_info_t* tape); void tape34xx_idle_done(tape_info_t* tape); -void tape34xx_idle_error(tape_info_t* tape); void tape34xx_block_done(tape_info_t* tape); -void tape34xx_block_error(tape_info_t* tape); void tape34xx_bsf_init_done(tape_info_t* tape); void tape34xx_dse_init_done(tape_info_t* tape); void tape34xx_fsf_init_done(tape_info_t* tape); -void tape34xx_fsf_init_error(tape_info_t* tape); void tape34xx_bsb_init_done(tape_info_t* tape); void tape34xx_fsb_init_done(tape_info_t* tape); void tape34xx_lbl_init_done(tape_info_t* tape); -void tape34xx_lbl_init_error(tape_info_t* tape); void tape34xx_nop_init_done(tape_info_t* tape); void tape34xx_rfo_init_done(tape_info_t* tape); -void tape34xx_rfo_init_error(tape_info_t* tape); void tape34xx_rbi_init_done(tape_info_t* tape); void tape34xx_rew_init_done(tape_info_t* tape); -void tape34xx_rew_init_error(tape_info_t* tape); void tape34xx_rew_release_init_done(tape_info_t* tape); -void tape34xx_rew_release_init_error(tape_info_t* tape); void tape34xx_run_init_done(tape_info_t* tape); -void tape34xx_run_init_error(tape_info_t* tape); void tape34xx_wri_init_done(tape_info_t* tape); -void tape34xx_wri_init_error(tape_info_t* tape); void tape34xx_wtm_init_done(tape_info_t* tape); -void tape34xx_wtm_init_error(tape_info_t* tape); extern void schedule_tapeblock_exec_IO (tape_info_t *tape); + +// the error recovery stuff: +void tape34xx_error_recovery (tape_info_t* tape); +void tape34xx_error_recovery_has_failed (tape_info_t* tape,int error_id); +void tape34xx_error_recovery_succeded(tape_info_t* tape); +void tape34xx_error_recovery_do_retry(tape_info_t* tape); +void tape34xx_error_recovery_read_opposite (tape_info_t* tape); +void tape34xx_error_recovery_HWBUG (tape_info_t* tape,int condno); #endif // _TAPE34XX_H diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tapeblock.c linux.ac/drivers/s390/char/tapeblock.c --- linux.vanilla/drivers/s390/char/tapeblock.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/char/tapeblock.c Sat Apr 14 01:28:59 2001 @@ -4,15 +4,17 @@ * drivers/s390/char/tapeblock.c * block device frontend for tape device driver * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> + * * - * UNDER CONSTRUCTION: Work in progress...:-) **************************************************************************** */ #include "tapedefs.h" +#include <linux/config.h> #include <linux/blkdev.h> #include <linux/blk.h> #include <linux/version.h> @@ -22,6 +24,7 @@ #include <asm/s390dyn.h> #include <linux/compatmac.h> #ifdef MODULE +#define __NO_VERSION__ #include <linux/module.h> #endif #include "tape.h" @@ -51,6 +54,21 @@ static request_queue_t* tapeblock_getqueue (kdev_t kdev); +#ifdef CONFIG_DEVFS_FS +void +tapeblock_mkdevfstree (tape_info_t* tape) { + tape->devfs_block_dir=devfs_mk_dir (tape->devfs_dir, "block", tape); + tape->devfs_disc=devfs_register(tape->devfs_block_dir, "disc",DEVFS_FL_DEFAULT, + tapeblock_major, tape->blk_minor, + TAPEBLOCK_DEFAULTMODE, &tapeblock_fops, tape); +} + +void +tapeblock_rmdevfstree (tape_info_t* tape) { + devfs_unregister(tape->devfs_disc); + devfs_unregister(tape->devfs_block_dir); +} +#endif void tapeblock_setup(tape_info_t* tape) { @@ -59,9 +77,12 @@ hardsect_size[tapeblock_major][tape->blk_minor]=512; blk_init_queue (&tape->request_queue, tape_request_fn); blk_queue_headactive (&tape->request_queue, 0); +#ifdef CONFIG_DEVFS_FS + tapeblock_mkdevfstree(tape); +#endif } -void +int tapeblock_init(void) { int result; tape_frontend_t* blkfront,*temp; @@ -69,7 +90,11 @@ tape_init(); /* Register the tape major number to the kernel */ +#ifdef CONFIG_DEVFS_FS + result = devfs_register_blkdev(tapeblock_major, "tBLK", &tapeblock_fops); +#else result = register_blkdev(tapeblock_major, "tBLK", &tapeblock_fops); +#endif if (result < 0) { PRINT_WARN(KERN_ERR "tape: can't get major %d for block device\n", tapeblock_major); panic ("cannot get major number for tape block device"); @@ -89,6 +114,10 @@ blkfront = kmalloc(sizeof(tape_frontend_t),GFP_KERNEL); if (blkfront==NULL) panic ("no mem for tape block device structure"); blkfront->device_setup=tapeblock_setup; +#ifdef CONFIG_DEVFS_FS + blkfront->mkdevfstree = tapeblock_mkdevfstree; + blkfront->rmdevfstree = tapeblock_rmdevfstree; +#endif blkfront->next=NULL; if (first_frontend==NULL) { first_frontend=blkfront; @@ -103,6 +132,7 @@ tapeblock_setup(tape); tape=tape->next; } + return 0; } @@ -111,7 +141,7 @@ unregister_blkdev(tapeblock_major, "tBLK"); } -static int +int tapeblock_open(struct inode *inode, struct file *filp) { tape_info_t *ti; kdev_t dev; @@ -140,7 +170,7 @@ ti->position=-1; s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags); - rc=tapeblock_mediumdetect(ti); + rc=tapeblock_mediumdetect(ti); if (rc) return rc; // in case of errors, we don't have a size of the medium dev = MKDEV (tapeblock_major, MINOR (inode->i_rdev)); /* Get the device */ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags); @@ -155,12 +185,10 @@ return 0; } -static int +int tapeblock_release(struct inode *inode, struct file *filp) { long lockflags; tape_info_t *ti,*lastti; - - inode = filp->f_dentry->d_inode; ti = first_tape_info; while ((ti != NULL) && (ti->blk_minor != MINOR (inode->i_rdev))) ti = (tape_info_t *) ti->next; @@ -177,7 +205,7 @@ } if ((ti == NULL) || (tapestate_get (ti) != TS_IDLE)) { #ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,6,"b:notidle!"); + debug_text_event (tape_debug_area,3,"b:notidle!"); #endif return -ENXIO; /* error in tape_release */ } @@ -191,6 +219,7 @@ #ifdef MODULE MOD_DEC_USE_COUNT; #endif /* MODULE */ + invalidate_buffers(inode->i_rdev); return 0; } @@ -226,7 +255,7 @@ tape->discipline->free_bread(tape->cqr,tape); tape->cqr=NULL; tape->current_request=NULL; - tapestate_set(tape,TS_IDLE); + if (tapestate_get(tape)!=TS_NOT_OPER) tapestate_set(tape,TS_IDLE); return; } @@ -258,7 +287,17 @@ tapeblock_end_request (tape); // check state, inform user, free mem, dev=idl } if (tape->cqr!=NULL) BUG(); // tape should be idle now, request should be freed! - if (list_empty(&tape->request_queue.queue_head)) { // nothing more to do ;) + if (tapestate_get (tape) == TS_NOT_OPER) { + tape->blk_minor=tape->rew_minor=tape->nor_minor=-1; + tape->devinfo.irq=-1; + return; + } +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) + if (list_empty (&tape->request_queue.queue_head)) { +#else + if (tape->request_queue==NULL) { +#endif + // nothing more to do or device has dissapeared;) #ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"b:Qempty"); #endif @@ -342,8 +381,9 @@ if (atomic_compare_and_swap(0,1,&tape->bh_scheduled)) { return; } - +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) INIT_LIST_HEAD(&tape->bh_tq.list); +#endif tape->bh_tq.sync = 0; tape->bh_tq.routine = (void *) (void *) run_tapeblock_exec_IO; tape->bh_tq.data = tape; @@ -376,13 +416,14 @@ return NULL; } -static int tapeblock_mediumdetect(tape_info_t* tape) { - ccw_req_t* cqr; +int tapeblock_mediumdetect(tape_info_t* tape) { + ccw_req_t* cqr; int losize=1,hisize=1,rc; long lockflags; #ifdef TAPE_DEBUG debug_text_event (tape_debug_area,3,"b:medDet"); #endif + PRINT_WARN("Detecting media size. This will take _long_, so get yourself a coffee...\n"); while (1) { //is interruped by break hisize=hisize << 1; // try twice the size tested before cqr=tape->discipline->mtseek (tape, hisize); @@ -415,6 +456,12 @@ s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); break; } + if (tapestate_get (tape) == TS_NOT_OPER) { + tape->blk_minor=tape->rew_minor=tape->nor_minor=-1; + tape->devinfo.irq=-1; + s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags); + return -ENODEV; + } if (tapestate_get (tape) != TS_DONE) { tapestate_set (tape, TS_IDLE); s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); @@ -449,6 +496,12 @@ s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); return -EIO; } + if (tapestate_get (tape) == TS_NOT_OPER) { + tape->blk_minor=tape->rew_minor=tape->nor_minor=-1; + tape->devinfo.irq=-1; + s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags); + return -ENODEV; + } if (tapestate_get (tape) != TS_DONE) { tapestate_set (tape, TS_IDLE); s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); @@ -482,6 +535,12 @@ return -ERESTARTSYS; } s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags); + if (tapestate_get (tape) == TS_NOT_OPER) { + tape->blk_minor=tape->rew_minor=tape->nor_minor=-1; + tape->devinfo.irq=-1; + s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags); + return -ENODEV; + } if (tapestate_get (tape) == TS_FAILED) { tapestate_set (tape, TS_IDLE); s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tapeblock.h linux.ac/drivers/s390/char/tapeblock.h --- linux.vanilla/drivers/s390/char/tapeblock.h Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/char/tapeblock.h Sat Apr 14 01:28:59 2001 @@ -4,23 +4,33 @@ * drivers/s390/char/tapechar.h * character device frontend for tape device driver * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> + * * - * UNDER CONSTRUCTION: Work in progress...:-) **************************************************************************** */ #ifndef TAPEBLOCK_H #define TAPEBLOCK_H +#include <linux/config.h> #define PARTN_BITS 0 #define TAPEBLOCK_READAHEAD 30 #define TAPEBLOCK_MAJOR 0 -static int tapeblock_open(struct inode *, struct file *); -static int tapeblock_release(struct inode *, struct file *); + +#define TAPEBLOCK_DEFAULTMODE 0060644 + +int tapeblock_open(struct inode *, struct file *); +int tapeblock_release(struct inode *, struct file *); void tapeblock_setup(tape_info_t* tape); void schedule_tapeblock_exec_IO (tape_info_t *tape); -static int tapeblock_mediumdetect(tape_info_t* tape); +int tapeblock_mediumdetect(tape_info_t* tape); +#ifdef CONFIG_DEVFS_FS +void tapeblock_mkdevfstree (tape_info_t* tape); +#endif +int tapeblock_init (void); +void tapeblock_uninit (void); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tapechar.c linux.ac/drivers/s390/char/tapechar.c --- linux.vanilla/drivers/s390/char/tapechar.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/char/tapechar.c Sat Apr 14 01:28:59 2001 @@ -4,16 +4,17 @@ * drivers/s390/char/tapechar.c * character device frontend for tape device driver * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> + * * - * UNDER CONSTRUCTION: Work in progress...:-) **************************************************************************** */ #include "tapedefs.h" +#include <linux/config.h> #include <linux/version.h> #include <linux/types.h> #include <linux/proc_fs.h> @@ -24,6 +25,7 @@ #include <asm/uaccess.h> #include <linux/compatmac.h> #ifdef MODULE +#define __NO_VERSION__ #include <linux/module.h> #endif #include "tape.h" @@ -54,10 +56,33 @@ int tape_major = TAPE_MAJOR; +#ifdef CONFIG_DEVFS_FS +void +tapechar_mkdevfstree (tape_info_t* tape) { + tape->devfs_char_dir=devfs_mk_dir (tape->devfs_dir, "char", tape); + tape->devfs_nonrewinding=devfs_register(tape->devfs_char_dir, "nonrewinding", + DEVFS_FL_DEFAULT,tape_major, + tape->nor_minor, TAPECHAR_DEFAULTMODE, + &tape_fops, tape); + tape->devfs_rewinding=devfs_register(tape->devfs_char_dir, "rewinding", + DEVFS_FL_DEFAULT, tape_major, tape->rew_minor, + TAPECHAR_DEFAULTMODE, &tape_fops, tape); +} + +void +tapechar_rmdevfstree (tape_info_t* tape) { + devfs_unregister(tape->devfs_nonrewinding); + devfs_unregister(tape->devfs_rewinding); + devfs_unregister(tape->devfs_char_dir); +} +#endif + void tapechar_setup (tape_info_t * tape) { - // nothing to do +#ifdef CONFIG_DEVFS_FS + tapechar_mkdevfstree(tape); +#endif } void @@ -70,7 +95,11 @@ tape_init(); /* Register the tape major number to the kernel */ +#ifdef CONFIG_DEVFS_FS + result = devfs_register_chrdev (tape_major, "tape", &tape_fops); +#else result = register_chrdev (tape_major, "tape", &tape_fops); +#endif if (result < 0) { PRINT_WARN (KERN_ERR "tape: can't get major %d\n", tape_major); @@ -92,6 +121,10 @@ panic ("no major number available for tape char device"); } charfront->device_setup = tapechar_setup; +#ifdef CONFIG_DEVFS_FS + charfront->mkdevfstree = tapechar_mkdevfstree; + charfront->rmdevfstree = tapechar_rmdevfstree; +#endif #ifdef TAPE_DEBUG debug_text_event (tape_debug_area,3,"c:init ok"); #endif /* TAPE_DEBUG */ @@ -120,7 +153,7 @@ /* * Tape device read function */ -static ssize_t +ssize_t tape_read (struct file *filp, char *data, size_t count, loff_t * ppos) { long lockflags; @@ -184,6 +217,12 @@ s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); return tape->rc; } + if (tapestate_get (tape) == TS_NOT_OPER) { + tape->blk_minor=tape->rew_minor=tape->nor_minor=-1; + tape->devinfo.irq=-1; + s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags); + return -ENODEV; + } if (tapestate_get (tape) != TS_DONE) { tapestate_set (tape, TS_IDLE); s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); @@ -202,7 +241,7 @@ /* * Tape device write function */ -static ssize_t +ssize_t tape_write (struct file *filp, const char *data, size_t count, loff_t * ppos) { long lockflags; @@ -262,8 +301,16 @@ if (tapestate_get (tape) == TS_FAILED) { tapestate_set (tape, TS_IDLE); s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); + if ((tape->rc==-ENOSPC) && (i!=0)) + return i*block_size; return tape->rc; } + if (tapestate_get (tape) == TS_NOT_OPER) { + tape->blk_minor=tape->rew_minor=tape->nor_minor=-1; + tape->devinfo.irq=-1; + s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags); + return -ENODEV; + } if (tapestate_get (tape) != TS_DONE) { tapestate_set (tape, TS_IDLE); s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); @@ -446,6 +493,12 @@ s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); return tape->rc; } + if (tapestate_get (tape) == TS_NOT_OPER) { + tape->blk_minor=tape->rew_minor=tape->nor_minor=-1; + tape->devinfo.irq=-1; + s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags); + return -ENODEV; + } if (tapestate_get (tape) != TS_DONE) { tapestate_set (tape, TS_IDLE); s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); @@ -473,7 +526,7 @@ /* * Tape device io controls. */ -static int +int tape_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -589,7 +642,7 @@ /* * Tape device open function. */ -static int +int tape_open (struct inode *inode, struct file *filp) { tape_info_t *ti; @@ -637,7 +690,7 @@ /* * Tape device release function. */ -static int +int tape_release (struct inode *inode, struct file *filp) { long lockflags; @@ -645,7 +698,6 @@ ccw_req_t *cqr = NULL; int rc; - inode = filp->f_dentry->d_inode; ti = first_tape_info; while ((ti != NULL) && (ti->rew_minor != MINOR (inode->i_rdev)) && (ti->nor_minor != MINOR (inode->i_rdev))) ti = (tape_info_t *) ti->next; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tapechar.h linux.ac/drivers/s390/char/tapechar.h --- linux.vanilla/drivers/s390/char/tapechar.h Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/char/tapechar.h Sat Apr 14 01:28:59 2001 @@ -4,24 +4,31 @@ * drivers/s390/char/tapechar.h * character device frontend for tape device driver * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> + * * - * UNDER CONSTRUCTION: Work in progress...:-) **************************************************************************** */ #ifndef TAPECHAR_H #define TAPECHAR_H +#include <linux/config.h> +#define TAPECHAR_DEFAULTMODE 0020644 #define TAPE_MAJOR 0 /* get dynamic major since no major officialy defined for tape */ /* * Prototypes for tape_fops */ -static ssize_t tape_read(struct file *, char *, size_t, loff_t *); -static ssize_t tape_write(struct file *, const char *, size_t, loff_t *); -static int tape_ioctl(struct inode *,struct file *,unsigned int,unsigned long); -static int tape_open (struct inode *,struct file *); -static int tape_release (struct inode *,struct file *); +ssize_t tape_read(struct file *, char *, size_t, loff_t *); +ssize_t tape_write(struct file *, const char *, size_t, loff_t *); +int tape_ioctl(struct inode *,struct file *,unsigned int,unsigned long); +int tape_open (struct inode *,struct file *); +int tape_release (struct inode *,struct file *); +#ifdef CONFIG_DEVFS_FS +void tapechar_mkdevfstree (tape_info_t* tape); +#endif +void tapechar_init (void); +void tapechar_uninit (void); #endif /* TAPECHAR_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tapedefs.h linux.ac/drivers/s390/char/tapedefs.h --- linux.vanilla/drivers/s390/char/tapedefs.h Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/char/tapedefs.h Thu Apr 12 12:03:49 2001 @@ -1,19 +1,19 @@ /*********************************************************************** * drivers/s390/char/tapedefs.h - * tape device driver for S/390 tapes. + * tape device driver for S/390 and zSeries tapes. + * + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> * - * UNDER CONSTRUCTION: Work in progress... :-) *********************************************************************** */ -#define TAPE_DEBUG -#define CONFIG_S390_TAPE_DYNAMIC //use dyn. dev. attach/detach -#define TAPEBLOCK_RETRIES 20 +#define TAPE_DEBUG // use s390 debug feature +#define CONFIG_S390_TAPE_DYNAMIC // allow devices to be attached or detached on the fly +#define TAPEBLOCK_RETRIES 20 // number of retries, when a block-dev request fails. /* Kernel Version Compatibility section */ @@ -36,8 +36,11 @@ blkdev_dequeue_request (req); } #else +#define s390_dev_info_t dev_info_t typedef struct request *request_queue_t; +#ifndef init_waitqueue_head #define init_waitqueue_head(x) do { *x = NULL; } while(0) +#endif #define blk_init_queue(x,y) do {} while(0) #define blk_queue_headactive(x,y) do {} while(0) #define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tuball.c linux.ac/drivers/s390/char/tuball.c --- linux.vanilla/drivers/s390/char/tuball.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/s390/char/tuball.c Sun Apr 15 23:09:21 2001 @@ -0,0 +1,625 @@ +/* + * IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC + * + * tuball.c -- Initialization, termination, irq lookup + * + * + * + * + * + * Author: Richard Hitt + */ +#include <linux/config.h> +#include "tubio.h" +#ifndef MODULE +#include <linux/init.h> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) +#include <asm/cpcmd.h> +#include <linux/bootmem.h> +#else +#include "../../../../arch/s390/kernel/cpcmd.h" +#endif +#endif + +/* Module parameters */ +int tubdebug; +int tubscrolltime; +int tubscrollparm; +int tubxcorrect = 1; /* Do correct ebc<->asc tables */ +#ifdef MODULE +MODULE_PARM(tubdebug, "i"); +MODULE_PARM(tubscrolltime, "i"); +MODULE_PARM(tubxcorrect, "i"); +#endif +/* + * Values for tubdebug and their effects: + * 1 - print in hex on console the first 16 bytes received + * 2 - print address at which array tubminors is allocated + * 4 - attempt to register tty3270_driver + */ +int tubnummins; +tub_t *(*tubminors)[TUBMAXMINS]; +tub_t *(*(*tubirqs)[256])[256]; +unsigned char tub_ascebc[256]; +unsigned char tub_ebcasc[256]; +int tubinitminors(void); +void tubfiniminors(void); +void tubint(int, void *, struct pt_regs *); + +/* Lookup-by-irq functions */ +int tubaddbyirq(tub_t *, int); +tub_t *tubfindbyirq(int); +void tubdelbyirq(tub_t *, int); +void tubfiniirqs(void); + +extern int fs3270_init(void); +extern void fs3270_fini(void); +extern int tty3270_init(void); +extern void tty3270_fini(void); + +unsigned char tub_ebcgraf[64] = + { 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f }; + +static int tub3270_init(void); + +#ifndef MODULE + +/* + * Can't have this driver a module & support console at the same time + */ +#ifdef CONFIG_3270_CONSOLE +static kdev_t tub3270_con_device(struct console *); +static void tub3270_con_unblank(void); +static void tub3270_con_write(struct console *, const char *, + unsigned int); + +static struct console tub3270_con = { + "tub3270", /* name */ + tub3270_con_write, /* write */ + NULL, /* read */ + tub3270_con_device, /* device */ + NULL, /* wait_key */ + tub3270_con_unblank, /* unblank */ + NULL, /* setup */ + CON_PRINTBUFFER, /* flags */ + 0, /* index */ + 0, /* cflag */ + NULL /* next */ +}; + +int tub3270_con_devno = -1; /* set by tub3270_con_setup() */ +bcb_t tub3270_con_bcb; /* Buffer that receives con writes */ +spinlock_t tub3270_con_bcblock; /* Lock for the buffer */ +int tub3270_con_irq = -1; /* set nonneg by _activate() */ +tub_t *tub3270_con_tubp; /* set nonzero by _activate() */ +struct tty_driver tty3270_con_driver; /* for /dev/console at 4, 64 */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) +__initfunc(void tub3270_con_setup(char *str, int *ints)) +#else +static int __init tub3270_con_setup(char *str) +#endif +{ + int vdev; + + vdev = simple_strtoul(str, 0, 16); + if (vdev >= 0 && vdev < 65536) + tub3270_con_devno = vdev; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) + return; +#else + return 1; +#endif +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) +__setup("condev=", tub3270_con_setup); +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) +__initfunc (long tub3270_con_init(long kmem_start, long kmem_end)) +#else +void __init tub3270_con_init(void) +#endif +{ + tub3270_con_bcb.bc_len = 65536; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) + if (!MACHINE_IS_VM && !MACHINE_IS_P390) + return kmem_start; + tub3270_con_bcb.bc_buf = (void *)kmem_start; + kmem_start += tub3270_con_bcb.bc_len; + register_console(&tub3270_con); + return kmem_start; +#else + if (!MACHINE_IS_VM && !MACHINE_IS_P390) + return; + tub3270_con_bcb.bc_buf = (void *)alloc_bootmem_low( + tub3270_con_bcb.bc_len); + register_console(&tub3270_con); +#endif +} + +static kdev_t +tub3270_con_device(struct console *conp) +{ + return MKDEV(IBM_TTY3270_MAJOR, conp->index); +} + +static void +tub3270_con_unblank(void) +{ + /* flush everything: panic has occurred */ +} + +int tub3270_con_write_deadlock_ct; +int tub3270_con_write_deadlock_bytes; +static void +tub3270_con_write(struct console *conp, + const char *buf, unsigned int count) +{ + int flags; + tub_t *tubp = tub3270_con_tubp; + void tty3270_sched_bh(tub_t *); + int rc; + bcb_t obcb; + + obcb.bc_buf = (char *)buf; + obcb.bc_len = obcb.bc_cnt = obcb.bc_wr = + MIN(count, tub3270_con_bcb.bc_len); + obcb.bc_rd = 0; + + spin_lock_irqsave(&tub3270_con_bcblock, flags); + rc = tub3270_movedata(&obcb, &tub3270_con_bcb); + spin_unlock_irqrestore(&tub3270_con_bcblock, flags); + + if (tubp && rc && TUBTRYLOCK(tubp->irq, flags)) { + tty3270_sched_bh(tubp); + TUBUNLOCK(tubp->irq, flags); + } +} + +int tub3270_con_copy(tub_t *tubp) +{ + int flags; + int rc; + + spin_lock_irqsave(&tub3270_con_bcblock, flags); + rc = tub3270_movedata(&tub3270_con_bcb, &tubp->tty_bcb); + spin_unlock_irqrestore(&tub3270_con_bcblock, flags); + return rc; +} +#endif /* CONFIG_3270_CONSOLE */ + + + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) +__initfunc(void tub3270_initfunc(void)) +#else +void __init tub3270_initfunc(void) +#endif +{ + tub3270_init(); +} +#else /* If generated as a MODULE */ +/* + * module init: find tubes; get a major nbr + */ +int +init_module(void) +{ + if (tubnummins != 0) { + printk(KERN_ERR "EEEK!! Tube driver cobbigling!!\n"); + return -1; + } + return tub3270_init(); +} + +/* + * remove driver: unregister the major number + */ +void +cleanup_module(void) +{ + fs3270_fini(); + tty3270_fini(); + tubfiniminors(); +} +#endif /* Not a MODULE or a MODULE */ + +void +tub_inc_use_count(void) +{ + MOD_INC_USE_COUNT; +} + +void +tub_dec_use_count(void) +{ + MOD_DEC_USE_COUNT; +} + +/* + * tub3270_init() called by kernel or module initialization + */ +static int +tub3270_init(void) +{ + s390_dev_info_t d; + int i, rc; + + /* + * Initialize default scrolltime to either -1 or the + * module parameter tubscrolltime. + */ + if (tubscrolltime) + tubscrollparm = tubscrolltime; + else + tubscrollparm = -1; + + /* + * Copy and correct ebcdic - ascii translate tables + */ + memcpy(tub_ascebc, _ascebc, sizeof tub_ascebc); + memcpy(tub_ebcasc, _ebcasc, sizeof tub_ebcasc); + if (tubxcorrect) { + /* correct brackets and circumflex */ + tub_ascebc['['] = 0xad; + tub_ascebc[']'] = 0xbd; + tub_ebcasc[0xad] = '['; + tub_ebcasc[0xbd] = ']'; + tub_ascebc['^'] = 0xb0; + tub_ebcasc[0x5f] = '^'; + } + + rc = tubinitminors(); + if (rc != 0) + return rc; + + for (i = get_irq_first(); i >= 0; i = get_irq_next(i)) { + if ((rc = get_dev_info_by_irq(i, &d))) + continue; + if (d.status) + continue; +#ifdef CONFIG_3270_CONSOLE + if (d.sid_data.cu_type == 0x3215 && MACHINE_IS_VM) { + cpcmd("TERM CONMODE 3270", NULL, 0); + d.sid_data.cu_type = 0x3270; + } +#endif /* CONFIG_3270_CONSOLE */ + if ((d.sid_data.cu_type & 0xfff0) != 0x3270) + continue; + + rc = tubmakemin(i, &d); + if (rc < 0) { + if (tubnummins == 1) { /* if first time */ + tubfiniminors(); + printk(KERN_ERR "No kernel memory available" + " for 3270 tube devices.\n"); + return rc; + } + printk(KERN_WARNING "3270 tube registration ran out of memory" + " after %d devices\n", tubnummins - 1); + break; + } else { + printk(KERN_INFO "3270: %.4x on sch %d, minor %d\n", + d.devno, d.irq, rc); + } + } + + if (fs3270_init() || tty3270_init()) { + printk(KERN_ERR "fs3270_init() or tty3270_init() failed\n"); + fs3270_fini(); + tty3270_fini(); + tubfiniminors(); + return -1; + } + + return 0; +} + +/* + * tub3270_movedata(bcb_t *, bcb_t *) -- Move data stream + */ +int +tub3270_movedata(bcb_t *ib, bcb_t *ob) +{ + int count; /* Total move length */ + int rc; + + rc = count = MIN(ib->bc_cnt, ob->bc_len - ob->bc_cnt); + while (count > 0) { + int len1; /* Contig bytes avail in ib */ + + if (ib->bc_wr > ib->bc_rd) + len1 = ib->bc_wr - ib->bc_rd; + else + len1 = ib->bc_len - ib->bc_rd; + if (len1 > count) + len1 = count; + + while (len1 > 0) { + int len2; /* Contig space avail in ob */ + + if (ob->bc_rd > ob->bc_wr) + len2 = ob->bc_rd - ob->bc_wr; + else + len2 = ob->bc_len - ob->bc_wr; + if (len2 > len1) + len2 = len1; + + memcpy(ob->bc_buf + ob->bc_wr, + ib->bc_buf + ib->bc_rd, + len2); + + ib->bc_rd += len2; + if (ib->bc_rd == ib->bc_len) + ib->bc_rd = 0; + ib->bc_cnt -= len2; + + ob->bc_wr += len2; + if (ob->bc_wr == ob->bc_len) + ob->bc_wr = 0; + ob->bc_cnt += len2; + + len1 -= len2; + count -= len2; + } + } + return rc; +} + +/* + * receive an interrupt + */ +void +tubint(int irq, void *ipp, struct pt_regs *prp) +{ + devstat_t *dsp = ipp; + tub_t *tubp; + + if ((tubp = IRQ2TUB(irq)) && (tubp->intv)) + (tubp->intv)(tubp, dsp); +} + +/* + * Initialize array of pointers to minor structures tub_t. + * Returns 0 or -ENOMEM. + */ +int +tubinitminors(void) +{ + tubminors = (tub_t *(*)[TUBMAXMINS])kmalloc(sizeof *tubminors, + GFP_KERNEL); + if (tubminors == NULL) + return -ENOMEM; + memset(tubminors, 0, sizeof *tubminors); + return 0; +} + +/* + * Add a minor 327x device. Argument is an irq value. + * + * Point elements of two arrays to the newly created tub_t: + * 1. (*tubminors)[minor] + * 2. (*(*tubirqs)[irqhi])[irqlo] + * The first looks up from minor number at context time; the second + * looks up from irq at interrupt time. + */ +int +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) +tubmakemin(int irq, dev_info_t *dp) +#else +tubmakemin(int irq, s390_dev_info_t *dp) +#endif +{ + tub_t *tubp; + int minor; + int flags; + + if ((minor = ++tubnummins) == TUBMAXMINS) + return -ENODEV; + + tubp = kmalloc(sizeof(tub_t), GFP_KERNEL); + if (tubp == NULL) { + return -ENOMEM; + } + if (tubaddbyirq(tubp, irq) != 0) { + kfree(tubp); + return -ENOMEM; + } + memset(tubp, 0, sizeof(tub_t)); + tubp->minor = minor; + tubp->irq = irq; + TUBLOCK(tubp->irq, flags); + tubp->devno = dp->devno; + tubp->geom_rows = _GEOM_ROWS; + tubp->geom_cols = _GEOM_COLS; + init_waitqueue_head(&tubp->waitq); + + tubp->tty_bcb.bc_len = TTY_OUTPUT_SIZE; + tubp->tty_bcb.bc_buf = (void *)kmalloc(tubp->tty_bcb.bc_len, + GFP_KERNEL); + if (tubp->tty_bcb.bc_buf == NULL) { + TUBUNLOCK(tubp->irq, flags); + tubdelbyirq(tubp, irq); + kfree(tubp); + return -ENOMEM; + } + tubp->tty_bcb.bc_cnt = 0; + tubp->tty_bcb.bc_wr = 0; + tubp->tty_bcb.bc_rd = 0; + (*tubminors)[minor] = tubp; +#ifdef CONFIG_3270_CONSOLE + if (tub3270_con_tubp == NULL && tub3270_con_bcb.bc_buf != NULL && + (tub3270_con_devno == -1 || + tub3270_con_devno == dp->devno)) { + extern void tty3270_int(tub_t *, devstat_t *); + + tubp->cmd = TBC_CONOPEN; + tubp->flags |= TUB_OPEN_STET; + tty3270_size(tubp, &flags); + tty3270_aid_init(tubp); + tty3270_scl_init(tubp); + tub3270_con_irq = tubp->irq; + tub3270_con_tubp = tubp; + tubp->intv = tty3270_int; + tubp->cmd = TBC_UPDSTAT; + tty3270_build(tubp); + } +#endif /* CONFIG_3270_CONSOLE */ + TUBUNLOCK(tubp->irq, flags); + return minor; +} + +/* + * Release array of pointers to minor structures tub_t, but first + * release any storage pointed to by them. + */ +void +tubfiniminors(void) +{ + int i; + tub_t **tubpp, *tubp; + + if (tubminors == NULL) + return; + + for (i = 0; i < TUBMAXMINS; i++) { + tubpp = &(*tubminors)[i]; + if ((tubp = *tubpp)) { + tubdelbyirq(tubp, tubp->irq); + tty3270_rcl_fini(tubp); + kfree(tubp->tty_bcb.bc_buf); + tubp->tty_bcb.bc_buf = NULL; + tubp->ttyscreen = NULL; + kfree(tubp); + *tubpp = NULL; + } + } + kfree(tubminors); + tubminors = NULL; + tubfiniirqs(); +} + +/* + * tubaddbyirq() -- Add tub_t for irq lookup in tubint() + */ +int +tubaddbyirq(tub_t *tubp, int irq) +{ + int irqhi = (irq >> 8) & 255; + int irqlo = irq & 255; + tub_t *(*itubpp)[256]; + + /* Allocate array (*tubirqs)[] if first time */ + if (tubirqs == NULL) { + tubirqs = (tub_t *(*(*)[256])[256]) + kmalloc(sizeof *tubirqs, GFP_KERNEL); + if (tubirqs == NULL) + return -ENOMEM; + memset(tubirqs, 0, sizeof *tubirqs); + } + + /* Allocate subarray (*(*tubirqs)[])[] if first use */ + if ((itubpp = (*tubirqs)[irqhi]) == NULL) { + itubpp = (tub_t *(*)[256]) + kmalloc(sizeof(*itubpp), GFP_KERNEL); + if (itubpp == NULL) { + if (tubnummins == 1) { /* if first time */ + kfree(tubirqs); + tubirqs = NULL; + } + return -ENOMEM; + } else { + memset(itubpp, 0, sizeof(*itubpp)); + (*tubirqs)[irqhi] = itubpp; + } + } + + /* Request interrupt service */ + if ((tubp->irqrc = request_irq(irq, tubint, SA_INTERRUPT, + "3270 tube driver", &tubp->devstat)) != 0) + return tubp->irqrc; + + /* Fill in the proper subarray element */ + (*itubpp)[irqlo] = tubp; + return 0; +} + +/* + * tubfindbyirq(irq) + */ +tub_t * +tubfindbyirq(int irq) +{ + int irqhi = (irq >> 8) & 255; + int irqlo = irq & 255; + tub_t *tubp; + + if (tubirqs == NULL) + return NULL; + if ((*tubirqs)[irqhi] == NULL) + return NULL; + tubp = (*(*tubirqs)[irqhi])[irqlo]; + if (tubp->irq == irq) + return tubp; + return NULL; +} + +/* + * tubdelbyirq(tub_t*, irq) + */ +void +tubdelbyirq(tub_t *tubp, int irq) +{ + int irqhi = (irq >> 8) & 255; + int irqlo = irq & 255; + tub_t *(*itubpp)[256], *itubp; + + if (tubirqs == NULL) { + printk(KERN_ERR "tubirqs is NULL\n"); + return; + } + itubpp = (*tubirqs)[irqhi]; + if (itubpp == NULL) { + printk(KERN_ERR "tubirqs[%d] is NULL\n", irqhi); + return; + } + itubp = (*itubpp)[irqlo]; + if (itubp == NULL) { + printk(KERN_ERR "tubirqs[%d][%d] is NULL\n", irqhi, irqlo); + return; + } + if (itubp->irqrc == 0) + free_irq(irq, &itubp->devstat); + (*itubpp)[irqlo] = NULL; +} + +/* + * tubfiniirqs() -- clean up storage in tub_t *(*(*tubirqs)[256])[256] + */ +void +tubfiniirqs(void) +{ + int i; + tub_t *(*itubpp)[256]; + + if (tubirqs != NULL) { + for (i = 0; i < 256; i++) { + if ((itubpp = (*tubirqs)[i])) { + kfree(itubpp); + (*tubirqs)[i] = NULL; + } + } + kfree(tubirqs); + tubirqs = NULL; + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tubfs.c linux.ac/drivers/s390/char/tubfs.c --- linux.vanilla/drivers/s390/char/tubfs.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/s390/char/tubfs.c Thu Apr 12 12:03:49 2001 @@ -0,0 +1,404 @@ +/* + * IBM/3270 Driver -- Copyright (C) UTS Global LLC + * + * tubfs.c -- Fullscreen driver + * + * + * + * + * + * Author: Richard Hitt + */ +#include "tubio.h" + +int fs3270_major = -1; /* init to impossible -1 */ + +static int fs3270_open(struct inode *, struct file *); +static int fs3270_close(struct inode *, struct file *); +static int fs3270_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +static int fs3270_read(struct file *, char *, size_t, loff_t *); +static int fs3270_write(struct file *, const char *, size_t, loff_t *); +static int fs3270_wait(tub_t *, int *); +static void fs3270_int(tub_t *tubp, devstat_t *dsp); +extern void tty3270_refresh(tub_t *); + +static struct file_operations fs3270_fops = { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) + owner: THIS_MODULE, /* owner */ +#endif + read: fs3270_read, /* read */ + write: fs3270_write, /* write */ + ioctl: fs3270_ioctl, /* ioctl */ + open: fs3270_open, /* open */ + release:fs3270_close, /* release */ +}; + +/* + * fs3270_init() -- Initialize fullscreen tubes + */ +int +fs3270_init(void) +{ + int rc; + + rc = register_chrdev(IBM_FS3270_MAJOR, "fs3270", &fs3270_fops); + if (rc) { + printk(KERN_ERR "tubmod can't get major nbr %d: error %d\n", + IBM_FS3270_MAJOR, rc); + return -1; + } else { + fs3270_major = IBM_FS3270_MAJOR; + return 0; + } +} + +/* + * fs3270_fini() -- Uninitialize fullscreen tubes + */ +void +fs3270_fini(void) +{ + if (fs3270_major != -1) { + unregister_chrdev(fs3270_major, "fs3270"); + fs3270_major = -1; + } +} + +/* + * fs3270_open + */ +static int +fs3270_open(struct inode *ip, struct file *fp) +{ + tub_t *tubp; + int flags; + + /* See INODE2TUB(ip) for handling of "/dev/3270/tub" */ + if ((tubp = INODE2TUB(ip)) == NULL) + return -ENOENT; + + TUBLOCK(tubp->irq, flags); + if (tubp->mode == TBM_FS || tubp->mode == TBM_FSLN) { + TUBUNLOCK(tubp->irq, flags); + return -EBUSY; + } + + tub_inc_use_count(); + fp->private_data = ip; + tubp->mode = TBM_FS; + tubp->intv = fs3270_int; + tubp->dstat = 0; + tubp->fs_pid = current->pid; + tubp->fsopen = 1; + TUBUNLOCK(tubp->irq, flags); + return 0; +} + +/* + * fs3270_close aka release: free the irq + */ +static int +fs3270_close(struct inode *ip, struct file *fp) +{ + tub_t *tubp; + int flags; + + if ((tubp = INODE2TUB(ip)) == NULL) + return -ENODEV; + + fs3270_wait(tubp, &flags); + tubp->fsopen = 0; + tubp->fs_pid = 0; + tub_dec_use_count(); + tubp->intv = NULL; + tubp->mode = 0; + tty3270_refresh(tubp); + TUBUNLOCK(tubp->irq, flags); + return 0; +} + +/* + * fs3270_release() called from tty3270_hangup() + */ +void +fs3270_release(tub_t *tubp) +{ + int flags; + + if (tubp->mode != TBM_FS) + return; + fs3270_wait(tubp, &flags); + tubp->fsopen = 0; + tubp->fs_pid = 0; + tub_dec_use_count(); + tubp->intv = NULL; + tubp->mode = 0; + /*tty3270_refresh(tubp);*/ + TUBUNLOCK(tubp->irq, flags); +} + +/* + * fs3270_wait(tub_t *tubp, int *flags) -- Wait to use tube + * Entered without irq lock + * On return: + * * Lock is held + * * Value is 0 or -ERESTARTSYS + */ +static int +fs3270_wait(tub_t *tubp, int *flags) +{ + DECLARE_WAITQUEUE(wait, current); + + TUBLOCK(tubp->irq, *flags); + add_wait_queue(&tubp->waitq, &wait); + while (!signal_pending(current) && + ((tubp->mode != TBM_FS) || + (tubp->flags & (TUB_WORKING | TUB_RDPENDING)) != 0)) { + current->state = TASK_INTERRUPTIBLE; + TUBUNLOCK(tubp->irq, *flags); + schedule(); + current->state = TASK_RUNNING; + TUBLOCK(tubp->irq, *flags); + } + remove_wait_queue(&tubp->waitq, &wait); + return signal_pending(current)? -ERESTARTSYS: 0; +} + +/* + * fs3270_io(tubp, ccw1_t*) -- start I/O on the tube + * Entered with irq lock held, WORKING off + */ +static int +fs3270_io(tub_t *tubp, ccw1_t *ccwp) +{ + int rc; + + rc = do_IO(tubp->irq, ccwp, tubp->irq, 0, 0); + tubp->flags |= TUB_WORKING; + tubp->dstat = 0; + return rc; +} + +/* + * fs3270_bh(tubp) -- Perform back-half processing + */ +static void +fs3270_bh(void *data) +{ + int flags; + tub_t *tubp; + + tubp = data; + TUBLOCK(tubp->irq, flags); + tubp->flags &= ~TUB_BHPENDING; + + if (tubp->wbuf) { /* if we were writing */ + kfree(tubp->wbuf); + tubp->wbuf = NULL; + } + + if ((tubp->flags & (TUB_ATTN | TUB_RDPENDING)) == + (TUB_ATTN | TUB_RDPENDING)) { + fs3270_io(tubp, &tubp->rccw); + tubp->flags &= ~(TUB_ATTN | TUB_RDPENDING); + } + + if ((tubp->flags & TUB_WORKING) == 0) + wake_up_interruptible(&tubp->waitq); + + TUBUNLOCK(tubp->irq, flags); +} + +/* + * fs3270_sched_bh(tubp) -- Schedule the back half + * Irq lock must be held on entry and remains held on exit. + */ +static void +fs3270_sched_bh(tub_t *tubp) +{ + if (tubp->flags & TUB_BHPENDING) + return; + tubp->flags |= TUB_BHPENDING; + tubp->tqueue.routine = fs3270_bh; + tubp->tqueue.data = tubp; + queue_task(&tubp->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +/* + * fs3270_int(tubp, prp) -- Process interrupt from tube in FS mode + * This routine is entered with irq lock held (see do_IRQ in s390io.c) + */ +static void +fs3270_int(tub_t *tubp, devstat_t *dsp) +{ +#define DEV_UE_BUSY \ + (DEV_STAT_CHN_END | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP) + + tubp->dstat = dsp->dstat; + +#ifdef RBHNOTYET + /* XXX needs more work; must save 2d arg to fs370_io() */ + /* Handle CE-DE-UE and subsequent UDE */ + if (dsp->dstat == DEV_UE_BUSY) { + tubp->flags |= TUB_UE_BUSY; + return; + } else if (tubp->flags & TUB_UE_BUSY) { + tubp->flags &= ~TUB_UE_BUSY; + if (dsp->dstat == DEV_STAT_DEV_END && + (tubp->flags & TUB_WORKING) != 0) { + fs3270_io(tubp); + return; + } + } +#endif + + /* Handle ATTN */ + if (dsp->dstat & DEV_STAT_ATTENTION) + tubp->flags |= TUB_ATTN; + + if (dsp->dstat & DEV_STAT_CHN_END) { + tubp->cswl = dsp->rescnt; + if ((dsp->dstat & DEV_STAT_DEV_END) == 0) + tubp->flags |= TUB_EXPECT_DE; + else + tubp->flags &= ~TUB_EXPECT_DE; + } else if (dsp->dstat & DEV_STAT_DEV_END) { + if ((tubp->flags & TUB_EXPECT_DE) == 0) + tubp->flags |= TUB_UNSOL_DE; + tubp->flags &= ~TUB_EXPECT_DE; + } + if (dsp->dstat & DEV_STAT_DEV_END) + tubp->flags &= ~TUB_WORKING; + + if ((tubp->flags & TUB_WORKING) == 0) + fs3270_sched_bh(tubp); +} + +/* + * process ioctl commands for the tube driver + */ +static int +fs3270_ioctl(struct inode *ip, struct file *fp, + unsigned int cmd, unsigned long arg) +{ + tub_t *tubp; + int rc = 0, flags; + + if ((tubp = INODE2TUB(ip)) == NULL) + return -ENODEV; + if ((rc = fs3270_wait(tubp, &flags))) { + TUBUNLOCK(tubp->irq, flags); + return rc; + } + + switch(cmd) { + case TUBICMD: tubp->icmd = arg; break; + case TUBOCMD: tubp->ocmd = arg; break; + case TUBGETI: put_user(tubp->icmd, (char *)arg); break; + case TUBGETO: put_user(tubp->ocmd, (char *)arg); break; + case TUBGETMOD: + if (copy_to_user((char *)arg, &tubp->tubiocb, + sizeof tubp->tubiocb)) + rc = -EFAULT; + break; + } + TUBUNLOCK(tubp->irq, flags); + return rc; +} + +/* + * process read commands for the tube driver + */ +static int +fs3270_read(struct file *fp, char *dp, size_t len, loff_t *off) +{ + tub_t *tubp; + char *kp; + ccw1_t *cp; + int rc, flags; + + if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL) + return -ENODEV; + if ((rc = fs3270_wait(tubp, &flags)) != 0) { + TUBUNLOCK(tubp->irq, flags); + return rc; + } + + kp = kmalloc(len, GFP_KERNEL); + if (kp == NULL) { + TUBUNLOCK(tubp->irq, flags); + return -ENOMEM; + } + + cp = &tubp->rccw; + if (tubp->icmd == 0 && tubp->ocmd != 0) tubp->icmd = 6; + cp->cmd_code = tubp->icmd?:2; + cp->flags = CCW_FLAG_SLI; + cp->count = len; + cp->cda = virt_to_phys(kp); + tubp->flags |= TUB_RDPENDING; + TUBUNLOCK(tubp->irq, flags); + + if ((rc = fs3270_wait(tubp, &flags)) != 0) { + tubp->flags &= ~TUB_RDPENDING; + TUBUNLOCK(tubp->irq, flags); + kfree(kp); + return rc; + } + + len -= tubp->cswl; + TUBUNLOCK(tubp->irq, flags); + if (tubdebug & 1) + printk(KERN_DEBUG "minor %d: %.8x %.8x %.8x %.8x\n", + tubp->minor, + *(int*)((int)kp + 0), + *(int*)((int)kp + 4), + *(int*)((int)kp + 8), + *(int*)((int)kp + 12)); + copy_to_user(dp, kp, len); + kfree(kp); + return len; +} + +/* + * process write commands for the tube driver + */ +static int +fs3270_write(struct file *fp, const char *dp, size_t len, loff_t *off) +{ + tub_t *tubp; + ccw1_t *cp; + int rc, flags; + void *kb; + + /* Locate the tube */ + if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL) + return -ENODEV; + + /* Copy data to write from user address space */ + if ((kb = kmalloc(len, GFP_KERNEL)) == NULL) + return -ENOMEM; + if (copy_from_user(kb, dp, len) != 0) { + kfree(kb); + return -EFAULT; + } + + /* Wait till tube's not working or signal is pending */ + if ((rc = fs3270_wait(tubp, &flags))) { + TUBUNLOCK(tubp->irq, flags); + kfree(kb); + return rc; + } + + /* Make CCW and start I/O. Back end will free buffer. */ + tubp->wbuf = kb; + cp = &tubp->wccw; + cp->cmd_code = tubp->ocmd? tubp->ocmd == 5? 13: tubp->ocmd: 1; + cp->flags = CCW_FLAG_SLI; + cp->count = len; + cp->cda = virt_to_phys(tubp->wbuf); + fs3270_io(tubp, cp); + TUBUNLOCK(tubp->irq, flags); + return len; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tubio.h linux.ac/drivers/s390/char/tubio.h --- linux.vanilla/drivers/s390/char/tubio.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/s390/char/tubio.h Thu Apr 12 12:03:49 2001 @@ -0,0 +1,432 @@ +/* + * IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC + * + * tubio.h -- All-Purpose header file + * + * + * + * + * + * Author: Richard Hitt + */ +#include <linux/config.h> + +#include <linux/module.h> +#include <linux/version.h> + +#include <linux/major.h> +#ifndef IBM_TTY3270_MAJOR +# define IBM_TTY3270_MAJOR 212 +#endif /* IBM_TTY3270_MAJOR */ +#ifndef IBM_FS3270_MAJOR +# define IBM_FS3270_MAJOR 213 +#endif /* IBM_FS3270_MAJOR */ + + +#include <linux/malloc.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <linux/console.h> +#include <linux/interrupt.h> +#include <asm/ebcdic.h> +#include <asm/uaccess.h> +#include <linux/proc_fs.h> + +#define TUB(x) (('3'<<8)|(x)) +#define TUBICMD TUB(3) +#define TUBOCMD TUB(4) +#define TUBGETI TUB(7) +#define TUBGETO TUB(8) +#define TUBSETMOD TUB(12) +#define TUBGETMOD TUB(13) +#define TIOPOLL TUB(32) +#define TIOPOKE TUB(33) +#define TIONPOKE TUB(34) +#define TIOTNORM TUB(35) + +/* Local Channel Commands */ +#define TC_WRITE 0x01 +#define TC_EWRITE 0x05 +#define TC_READMOD 0x06 +#define TC_EWRITEA 0x0d +#define TC_WRITESF 0x11 + +/* Buffer Control Orders */ +#define TO_SF 0x1d +#define TO_SBA 0x11 +#define TO_IC 0x13 +#define TO_PT 0x05 +#define TO_RA 0x3c +#define TO_SFE 0x29 +#define TO_EUA 0x12 +#define TO_MF 0x2c +#define TO_SA 0x28 + +/* Field Attribute Bytes */ +#define TF_INPUT 0x40 /* Visible input */ +#define TF_INPUTN 0x4c /* Invisible input */ +#define TF_INMDT 0xc1 /* Visible, Set-MDT */ +#define TF_LOG 0x60 +#define TF_STAT 0x60 + +/* Character Attribute Bytes */ +#define TAT_RESET 0x00 +#define TAT_FIELD 0xc0 +#define TAT_EXTHI 0x41 +#define TAT_COLOR 0x42 +#define TAT_CHARS 0x43 +#define TAT_TRANS 0x46 + +/* Reset value */ +#define TAR_RESET 0x00 + +/* Color values */ +#define TAC_BLUE 0xf1 +#define TAC_RED 0xf2 +#define TAC_PINK 0xf3 +#define TAC_GREEN 0xf4 +#define TAC_TURQ 0xf5 +#define TAC_YELLOW 0xf6 +#define TAC_WHITE 0xf7 +#define TAC_DEFAULT 0x00 + +/* Write Control Characters */ +#define TW_NONE 0x40 /* No particular action */ +#define TW_KR 0xc2 /* Keyboard restore */ +#define TW_PLUSALARM 0x04 /* Add this bit for alarm */ + +/* Attention-ID (AID) Characters */ +#define TA_CLEAR 0x6d +#define TA_PA2 0x6e +#define TA_ENTER 0x7d +/* more to come */ + +#define MIN(a, b) ((a) < (b)? (a): (b)) + +#define TUB_BUFADR(adr, cpp) \ + tty3270_tub_bufadr(tubp, adr, cpp) + +#define TUB_EBCASC(addr, nr) codepage_convert(tub_ebcasc, addr, nr) +#define TUB_ASCEBC(addr, nr) codepage_convert(tub_ascebc, addr, nr) + +/* + * + * General global values for the tube driver + * + */ +enum tubmode { + TBM_LN, /* Line mode */ + TBM_FS, /* Fullscreen mode */ + TBM_FSLN /* Line mode shelled out of fullscreen */ +}; +enum tubstat { /* normal-mode status */ + TBS_RUNNING, /* none of the following */ + TBS_MORE, /* timed "MORE..." in status */ + TBS_HOLD /* untimed "HOLDING" in status */ +}; +enum tubcmd { /* normal-mode actions to do */ + TBC_CONOPEN, /* Erase-write the console */ + TBC_OPEN, /* Open the tty screen */ + TBC_UPDATE, /* Add lines to the log, clear cmdline */ + TBC_UPDLOG, /* Add lines to log */ + TBC_KRUPDLOG, /* Add lines to log, reset kbd */ + TBC_CLEAR, /* Build screen from scratch */ + TBC_CLRUPDLOG, /* Do log & status, not cmdline */ + TBC_UPDSTAT, /* Do status update only */ + TBC_CLRINPUT, /* Clear input area only */ + TBC_UPDINPUT /* Update input area only */ +}; +enum tubwhat { /* echo what= proc actions */ + TW_BOGUS, /* Nothing at all */ + TW_CONFIG /* Output configuration info */ +}; + + + + + +#define TUBMAXMINS 256 +#define TUB_DEV MKDEV(IBM_FS3270_MAJ, 0) /* Generic /dev/3270/tub */ +#define _GEOM_ROWS 24 +#define _GEOM_COLS 80 +#define GEOM_ROWS (tubp->geom_rows) +#define GEOM_COLS (tubp->geom_cols) +#define GEOM_MAXROWS 127 +#define GEOM_MAXCOLS 132 +#define GEOM_INPLEN (GEOM_COLS * 2 - 20) +#define GEOM_MAXINPLEN (GEOM_MAXCOLS * 2 - 20) +#define GEOM_INPUT (GEOM_COLS * (GEOM_ROWS - 2) - 1) /* input atr posn */ +#define GEOM_STAT (GEOM_INPUT + 1 + GEOM_INPLEN) +#define GEOM_LOG (GEOM_COLS * GEOM_ROWS - 1) /* log atr posn */ +#define TS_RUNNING "Linux Running " +#define TS_MORE "Linux More... " +#define DEFAULT_SCROLLTIME 5 +#define TS_HOLD "Linux Holding " +/* data length used by tty3270_set_status_area: SBA (3), SF (2), data */ +#define TS_LENGTH (sizeof TS_RUNNING + 3 + 2) + +typedef struct { + int aid; /* What-to-do flags */ + char *string; /* Optional input string */ +} aid_t; +#define AIDENTRY(ch, tubp) (&((tubp)->tty_aid[(ch) & 0x3f])) + +/* For TUBGETMOD and TUBSETMOD. Should include. */ +typedef struct tubiocb { + short model; + short line_cnt; + short col_cnt; + short pf_cnt; + short re_cnt; + short map; +} tubiocb_t; + +/* Flags that go in int aid, above */ +#define TA_CLEARKEY 0x01 /* Key does hardware CLEAR */ +#define TA_SHORTREAD 0x02 /* Key does hardware shortread */ +/* If both are off, key does hardware Read Modified. */ +#define TA_DOENTER 0x04 /* Treat key like ENTER */ +#define TA_DOSTRING 0x08 /* Use string and ENTER */ +#define TA_DOSTRINGD 0x10 /* Display string & set MDT */ +#define TA_CLEARLOG 0x20 /* Make key cause clear of log */ + +/* + * Tube driver buffer control block + */ +typedef struct bcb_s { + char *bc_buf; /* Pointer to buffer */ + int bc_len; /* Length of buffer */ + int bc_cnt; /* Count of bytes buffered */ + int bc_wr; /* Posn to write next byte into */ + int bc_rd; /* Posn to read next byte from */ +} bcb_t; + +typedef struct tub_s { + int minor; + int irq; + int irqrc; + int devno; + int geom_rows; + int geom_cols; + tubiocb_t tubiocb; + int lnopen; + int fsopen; + int icmd; + int ocmd; + devstat_t devstat; + ccw1_t rccw; + ccw1_t wccw; + void *wbuf; + int cswl; + void (*intv)(struct tub_s *, devstat_t *); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) + struct wait_queue *waitq; +#else + wait_queue_head_t waitq; +#endif + int dstat; + sense_t sense; + enum tubmode mode; + enum tubstat stat; + enum tubcmd cmd; + int flags; /* See below for values */ + struct tq_struct tqueue; + + /* Stuff for fs-driver support */ + pid_t fs_pid; /* Pid if TBM_FS */ + + + /* Stuff for tty-driver support */ + struct tty_struct *tty; + char tty_input[GEOM_MAXINPLEN]; /* tty input area */ + int tty_inattr; /* input-area field attribute */ +#define TTY_OUTPUT_SIZE 1024 + bcb_t tty_bcb; /* Output buffer control info */ + int tty_oucol; /* Kludge */ + int tty_nextlogx; /* next screen-log position */ + int tty_scrolltime; /* scrollforward wait time, sec */ + struct timer_list tty_stimer; /* timer for scrolltime */ + aid_t tty_aid[64]; /* Aid descriptors */ + int tty_aidinit; /* Boolean */ + int tty_showaidx; /* Last aid x to set_aid */ + int tty_14bitadr; /* 14-bit bufadrs okay */ +#define MAX_TTY_ESCA 24 /* Set-Attribute-Order array */ + char tty_esca[MAX_TTY_ESCA]; /* SA array */ + int tty_escx; /* Current index within it */ + + /* For command recall --- */ + char *(*tty_rclbufs)[]; /* Array of ptrs to recall bufs */ + int tty_rclk; /* Size of array tty_rclbufs */ + int tty_rclp; /* Index for most-recent cmd */ + int tty_rclb; /* Index for backscrolling */ + + /* Work area to contain the hardware write stream */ + char (*ttyscreen)[]; /* ptr to data stream area */ + int ttyscreenl; /* its length */ + ccw1_t ttyccw; +} tub_t; + +/* values for flags: */ +#define TUB_WORKING 0x0001 +#define TUB_BHPENDING 0x0002 +#define TUB_RDPENDING 0x0004 +#define TUB_ALARM 0x0008 +#define TUB_SCROLLTIMING 0x0010 +#define TUB_ATTN 0x0020 +#define TUB_IACTIVE 0x0040 +#define TUB_SIZED 0x0080 +#define TUB_EXPECT_DE 0x0100 +#define TUB_UNSOL_DE 0x0200 +#define TUB_OPEN_STET 0x0400 /* No screen clear on open */ +#define TUB_UE_BUSY 0x0800 + +#ifdef CONFIG_3270_CONSOLE +/* + * Extra stuff for 3270 console support + */ +#define S390_CONSOLE_DEV MKDEV(TTY_MAJOR, 64) +extern int tub3270_con_devno; +extern char (*tub3270_con_output)[]; +extern int tub3270_con_outputl; +extern int tub3270_con_ouwr; +extern int tub3270_con_oucount; +extern int tub3270_con_irq; +extern tub_t *tub3270_con_tubp; +extern struct tty_driver tty3270_con_driver; +#endif /* CONFIG_3270_CONSOLE */ + +extern int tubnummins; +extern tub_t *(*tubminors)[TUBMAXMINS]; +extern tub_t *(*(*tubirqs)[256])[256]; +extern unsigned char tub_ascebc[256]; +extern unsigned char tub_ebcasc[256]; +extern unsigned char tub_ebcgraf[64]; +extern int tubdebug; +extern int fs3270_major; +extern int tty3270_major; +extern int tty3270_proc_misc; +extern enum tubwhat tty3270_proc_what; + +#ifndef spin_trylock_irqsave +#define spin_trylock_irqsave(lock, flags) \ +({ \ + int success; \ + __save_flags(flags); \ + __cli(); \ + success = spin_trylock(lock); \ + if (success == 0) \ + __restore_flags(flags); \ + success; \ +}) +#endif /* if not spin_trylock_irqsave */ + +#ifndef s390irq_spin_trylock_irqsave +#define s390irq_spin_trylock_irqsave(irq, flags) \ + spin_trylock_irqsave(&(ioinfo[irq]->irq_lock), flags) +#endif /* if not s390irq_spin_trylock_irqsave */ + +#define TUBLOCK(irq, flags) \ + s390irq_spin_lock_irqsave(irq, flags) + +#define TUBTRYLOCK(irq, flags) \ + s390irq_spin_trylock_irqsave(irq, flags) + +#define TUBUNLOCK(irq, flags) \ + s390irq_spin_unlock_irqrestore(irq, flags) + +/* + * Find tub_t * given fullscreen device's irq (subchannel number) + */ +extern tub_t *tubfindbyirq(int); +#define IRQ2TUB(irq) tubfindbyirq(irq) +/* + * Find tub_t * given fullscreen device's inode pointer + * This algorithm takes into account /dev/3270/tub. + */ +#ifdef CONFIG_3270_CONSOLE +#define INODE2TUB(ip) \ +({ \ + unsigned int minor; \ + tub_t *tubp = NULL; \ + minor = MINOR((ip)->i_rdev); \ + if (minor == 0 && current->tty != NULL) { \ + if (tub3270_con_tubp != NULL && \ + current->tty->device == S390_CONSOLE_DEV) \ + minor = tub3270_con_tubp->minor; \ + else if (MAJOR(current->tty->device) == IBM_TTY3270_MAJOR) \ + minor = MINOR(current->tty->device); \ + } \ + if (minor <= tubnummins && minor > 0) \ + tubp = (*tubminors)[minor]; \ + tubp; \ +}) +#else /* not CONFIG_3270_CONSOLE */ +#define INODE2TUB(ip) \ +({ \ + unsigned int minor; \ + tub_t *tubp = NULL; \ + minor = MINOR((ip)->i_rdev); \ + if (minor == 0 && current->tty != NULL && \ + MAJOR(current->tty->device) == IBM_TTY3270_MAJOR) \ + minor = MINOR(current->tty->device); \ + if (minor <= tubnummins && minor > 0) \ + tubp = (*tubminors)[minor]; \ + tubp; \ +}) +#endif /* CONFIG_3270_CONSOLE or not */ +/* + * Find tub_t * given non-fullscreen (tty) device's tty_struct pointer + */ +#ifdef CONFIG_3270_CONSOLE +#define TTY2TUB(tty) \ +({ \ + unsigned int minor; \ + tub_t *tubp = NULL; \ + minor = MINOR(tty->device); \ + if (tty->device == S390_CONSOLE_DEV) \ + tubp = tub3270_con_tubp; \ + else if (minor <= tubnummins && minor > 0) \ + tubp = (*tubminors)[minor]; \ + tubp; \ +}) +#else /* if not CONFIG_3270_CONSOLE */ +#define TTY2TUB(tty) \ +({ \ + unsigned int minor; \ + tub_t *tubp = NULL; \ + minor = MINOR(tty->device); \ + if (minor <= tubnummins && minor > 0) \ + tubp = (*tubminors)[minor]; \ + tubp; \ +}) +#endif /* CONFIG_3270_CONSOLE or not */ + +extern void tub_inc_use_count(void); +extern void tub_dec_use_count(void); +extern int tub3270_movedata(bcb_t *, bcb_t *); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) +extern int tubmakemin(int, dev_info_t *); +#else +extern int tubmakemin(int, s390_dev_info_t *); +#endif +extern int tub3270_con_copy(tub_t *); +extern int tty3270_rcl_init(tub_t *); +extern int tty3270_rcl_set(tub_t *, char *, int); +extern void tty3270_rcl_fini(tub_t *); +extern int tty3270_rcl_get(tub_t *, char *, int, int); +extern void tty3270_rcl_put(tub_t *, char *, int); +extern void tty3270_rcl_sync(tub_t *); +extern void tty3270_rcl_purge(tub_t *); +extern int tty3270_rcl_resize(tub_t *, int); +extern int tty3270_size(tub_t *, int *); +extern int tty3270_aid_init(tub_t *); +extern void tty3270_aid_fini(tub_t *); +extern void tty3270_aid_reinit(tub_t *); +extern int tty3270_aid_get(tub_t *, int, int *, char **); +extern int tty3270_aid_set(tub_t *, char *, int); +extern int tty3270_build(tub_t *); +extern void tty3270_scl_settimer(tub_t *); +extern void tty3270_scl_resettimer(tub_t *); +extern int tty3270_scl_set(tub_t *, char *, int); +extern int tty3270_scl_init(tub_t *tubp); +extern void tty3270_scl_fini(tub_t *tubp); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tubtty.c linux.ac/drivers/s390/char/tubtty.c --- linux.vanilla/drivers/s390/char/tubtty.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/s390/char/tubtty.c Thu Apr 12 12:03:49 2001 @@ -0,0 +1,1001 @@ +/* + * IBM/3270 Driver -- Copyright (C) 2000, 2001 UTS Global LLC + * + * tubtty.c -- Linemode tty driver + * + * + * + * + * + * Author: Richard Hitt + */ +#include <linux/config.h> +#include "tubio.h" + +/* Initialization & uninitialization for tubtty */ +int tty3270_init(void); +void tty3270_fini(void); + +/* Interface routines from the upper tty layer to the tty driver */ +static int tty3270_open(struct tty_struct *, struct file *); +static void tty3270_close(struct tty_struct *, struct file *); +static int tty3270_write(struct tty_struct *, int, + const unsigned char *, int); +static void tty3270_put_char(struct tty_struct *, unsigned char); +static void tty3270_flush_chars(struct tty_struct *); +static int tty3270_write_room(struct tty_struct *); +static int tty3270_chars_in_buffer(struct tty_struct *); +static int tty3270_ioctl(struct tty_struct *, struct file *, + unsigned int cmd, unsigned long arg); +static void tty3270_set_termios(struct tty_struct *, struct termios *); +static void tty3270_hangup(struct tty_struct *); +static void tty3270_flush_buffer(struct tty_struct *); +static int tty3270_read_proc(char *, char **, off_t, int, int *, void *); +static int tty3270_write_proc(struct file *, const char *, + unsigned long, void *); + +/* tty3270 utility functions */ +static void tty3270_bh(void *); + void tty3270_sched_bh(tub_t *); +static int tty3270_wait(tub_t *, int *); + void tty3270_int(tub_t *, devstat_t *); + int tty3270_try_logging(tub_t *); +static void tty3270_start_input(tub_t *); +static void tty3270_do_input(tub_t *); +static void tty3270_do_enter(tub_t *, char *, int); +static void tty3270_do_showi(tub_t *, char *, int); + int tty3270_io(tub_t *); +static int tty3270_show_tube(int, char *, int); + +int tty3270_major = -1; +char tty3270_major_string[16]; +struct tty_driver tty3270_driver; +int tty3270_refcount; +struct tty_struct *tty3270_table[TUBMAXMINS]; +struct termios *tty3270_termios[TUBMAXMINS]; +struct termios *tty3270_termios_locked[TUBMAXMINS]; +#ifdef CONFIG_3270_CONSOLE +int con3270_major = -1; +struct tty_driver con3270_driver; +int con3270_refcount; +struct tty_struct *con3270_table[1]; +struct termios *con3270_termios[1]; +struct termios *con3270_termios_locked[1]; +#endif /* CONFIG_3270_CONSOLE */ + +int tty3270_proc_index; +int tty3270_proc_data; +int tty3270_proc_misc; +enum tubwhat tty3270_proc_what; + +/* + * tty3270_init() -- Register the tty3270 driver + */ +int +tty3270_init(void) +{ + struct tty_driver *td = &tty3270_driver; + int rc; + + /* Initialize for tty driver */ + td->magic = TTY_DRIVER_MAGIC; + td->driver_name = "tty3270"; + td->name = "tty3270"; + td->major = IBM_TTY3270_MAJOR; + td->minor_start = 0; + td->num = TUBMAXMINS; + td->type = TTY_DRIVER_TYPE_SYSTEM; + td->subtype = SYSTEM_TYPE_TTY; + td->init_termios = tty_std_termios; + td->flags = TTY_DRIVER_RESET_TERMIOS; + td->refcount = &tty3270_refcount; + td->table = tty3270_table; + td->termios = tty3270_termios; + td->termios_locked = tty3270_termios_locked; + + td->open = tty3270_open; + td->close = tty3270_close; + td->write = tty3270_write; + td->put_char = tty3270_put_char; + td->flush_chars = tty3270_flush_chars; + td->write_room = tty3270_write_room; + td->chars_in_buffer = tty3270_chars_in_buffer; + td->ioctl = tty3270_ioctl; + td->ioctl = NULL; + td->set_termios = tty3270_set_termios; + td->throttle = NULL; + td->unthrottle = NULL; + td->stop = NULL; + td->start = NULL; + td->hangup = tty3270_hangup; + td->break_ctl = NULL; + td->flush_buffer = tty3270_flush_buffer; + td->set_ldisc = NULL; + td->wait_until_sent = NULL; + td->send_xchar = NULL; + td->read_proc = tty3270_read_proc; + td->write_proc = tty3270_write_proc; + + rc = tty_register_driver(td); + if (rc) { + printk(KERN_ERR "tty3270 registration failed with %d\n", rc); + } else { + tty3270_major = IBM_TTY3270_MAJOR; + sprintf(tty3270_major_string, "%d", tty3270_major); + if (td->proc_entry != NULL) + td->proc_entry->mode = S_IRUGO | S_IWUGO; + } +#ifdef CONFIG_3270_CONSOLE + tty3270_con_driver = *td; + td = &tty3270_con_driver; + td->driver_name = "con3270"; + td->name = "con3270"; + td->major = MAJOR(S390_CONSOLE_DEV); + td->minor_start = MINOR(S390_CONSOLE_DEV); + td->num = 1; + td->refcount = &con3270_refcount; + td->table = con3270_table; + td->termios = con3270_termios; + td->termios_locked = con3270_termios_locked; + + rc = tty_register_driver(td); + if (rc) { + printk(KERN_ERR "con3270 registration failed with %d\n", rc); + } else { + con3270_major = MAJOR(S390_CONSOLE_DEV); + if (td->proc_entry != NULL) + td->proc_entry->mode = S_IRUGO | S_IWUGO; + } +#endif /* if CONFIG_3270_CONSOLE */ + + return rc; +} + +/* + * tty3270_fini() -- Uninitialize linemode tubes + */ +void +tty3270_fini(void) +{ + if (tty3270_major != -1) { + tty_unregister_driver(&tty3270_driver); + tty3270_major = -1; + } +#ifdef CONFIG_3270_CONSOLE + if (con3270_major != -1) { + tty_unregister_driver(&con3270_driver); + con3270_major = -1; + } +#endif +} + +static int +tty3270_open(struct tty_struct *tty, struct file *filp) +{ + tub_t *tubp; + int flags; + int rc; + int cmd; + + if ((tubp = TTY2TUB(tty)) == NULL) { + return -ENODEV; + } + + tub_inc_use_count(); + if ((rc = tty3270_wait(tubp, &flags)) != 0) + goto do_fail; + if (tubp->lnopen > 0) { + tubp->lnopen++; + TUBUNLOCK(tubp->irq, flags); + return 0; + } + if (tubp->flags & TUB_OPEN_STET) { + cmd = TBC_UPDLOG; + } else { + cmd = TBC_OPEN; + tubp->flags &= ~TUB_SIZED; + } + if ((rc = tty3270_size(tubp, &flags)) != 0) + goto do_fail; + if ((rc = tty3270_rcl_init(tubp)) != 0) + goto do_fail; + if ((rc = tty3270_aid_init(tubp)) != 0) + goto do_fail; + if ((rc = tty3270_scl_init(tubp)) != 0) + goto do_fail; + tubp->mode = TBM_LN; + tubp->intv = tty3270_int; + tubp->tty = tty; + tubp->lnopen = 1; + tty->driver_data = tubp; + tty->winsize.ws_row = tubp->geom_rows; + tty->winsize.ws_col = tubp->geom_cols; + tubp->tty_inattr = TF_INPUT; + tubp->cmd = cmd; + tty3270_build(tubp); + TUBUNLOCK(tubp->irq, flags); + return 0; + +do_fail: + tty3270_scl_fini(tubp); + tty3270_aid_fini(tubp); + tty3270_rcl_fini(tubp); + TUBUNLOCK(tubp->irq, flags); + tub_dec_use_count(); + return rc; +} + +static void +tty3270_close(struct tty_struct *tty, struct file *filp) +{ + tub_t *tubp; + int flags; + + if ((tubp = tty->driver_data) == NULL) + return; + + tty3270_wait(tubp, &flags); + if (--tubp->lnopen > 0) + goto do_return; + tubp->tty = NULL; + tty->driver_data = NULL; + tty3270_aid_fini(tubp); + tty3270_rcl_fini(tubp); + tty3270_scl_fini(tubp); +do_return: + tub_dec_use_count(); + TUBUNLOCK(tubp->irq, flags); +} + +static int +tty3270_write(struct tty_struct *tty, int fromuser, + const unsigned char *buf, int count) +{ + tub_t *tubp; + int flags; + bcb_t obcb; + int rc = 0; + + if ((tubp = tty->driver_data) == NULL) + return -1; + +#ifdef CONFIG_3270_CONSOLE + if (tub3270_con_tubp == tubp) + tub3270_con_copy(tubp); +#endif /* CONFIG_3270_CONSOLE */ + + obcb.bc_buf = (char *)buf; + obcb.bc_len = obcb.bc_cnt = obcb.bc_wr = count; + obcb.bc_rd = 0; + + TUBLOCK(tubp->irq, flags); + rc = tub3270_movedata(&obcb, &tubp->tty_bcb); + tty3270_try_logging(tubp); + TUBUNLOCK(tubp->irq, flags); + return rc; +} + +static void +tty3270_put_char(struct tty_struct *tty, unsigned char ch) +{ + int flags; + tub_t *tubp; + bcb_t *ob; + + if ((tubp = tty->driver_data) == NULL) + return; + + TUBLOCK(tubp->irq, flags); + ob = &tubp->tty_bcb; + if (ob->bc_cnt < ob->bc_len) { + ob->bc_buf[ob->bc_wr++] = ch; + if (ob->bc_wr == ob->bc_len) + ob->bc_wr = 0; + ob->bc_cnt++; + } + tty3270_try_logging(tubp); + TUBUNLOCK(tubp->irq, flags); +} + +static void +tty3270_flush_chars(struct tty_struct *tty) +{ + tub_t *tubp; + int flags; + + if ((tubp = tty->driver_data) == NULL) + return; + + TUBLOCK(tubp->irq, flags); + tty3270_try_logging(tubp); + TUBUNLOCK(tubp->irq, flags); +} + +static int +tty3270_write_room(struct tty_struct *tty) +{ + tub_t *tubp; + bcb_t *ob; + + if ((tubp = tty->driver_data) == NULL) + return -1; + + ob = &tubp->tty_bcb; + return ob->bc_len - ob->bc_cnt; +} + +static int +tty3270_chars_in_buffer(struct tty_struct *tty) +{ + tub_t *tubp; + bcb_t *ob; + + if ((tubp = tty->driver_data) == NULL) + return -1; + + ob = &tubp->tty_bcb; + return ob->bc_cnt; +} + +static int +tty3270_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + tub_t *tubp; + int flags; + int ret = 0; + struct termios termios; + + if ((tubp = tty->driver_data) == NULL) + return -ENODEV; + + TUBLOCK(tubp->irq, flags); + if (tty->flags * (1 << TTY_IO_ERROR)) { + ret = -EIO; + goto do_return; + } + switch(cmd) { + case TCGETS: + ret = -ENOIOCTLCMD; + goto do_return; + case TCFLSH: /* arg: 2 or 0 */ + ret = -ENOIOCTLCMD; + goto do_return; + case TCSETSF: + if (user_termios_to_kernel_termios(&termios, + (struct termios *)arg)) { + ret = -EFAULT; + goto do_return; + } + ret = -ENOIOCTLCMD; + goto do_return; + case TCGETA: + ret = -ENOIOCTLCMD; + goto do_return; + case TCSETA: + if (user_termio_to_kernel_termios(&termios, + (struct termio *)arg)) { + ret = -EFAULT; + goto do_return; + } + ret = -ENOIOCTLCMD; + goto do_return; + default: + ret = -ENOIOCTLCMD; + break; + } + +do_return: + TUBUNLOCK(tubp->irq, flags); + return ret; +} + +static void +tty3270_set_termios(struct tty_struct *tty, struct termios *old) +{ + tub_t *tubp; + int flags; + int new; + + if ((tubp = tty->driver_data) == NULL) + return; + + if (tty3270_wait(tubp, &flags) != 0) { + TUBUNLOCK(tubp->irq, flags); + return; + } + new = L_ICANON(tty)? L_ECHO(tty)? TF_INPUT: TF_INPUTN: + tubp->tty_inattr; + if (new != tubp->tty_inattr) { + tubp->tty_inattr = new; + tubp->cmd = TBC_CLRINPUT; + tty3270_build(tubp); + } + + TUBUNLOCK(tubp->irq, flags); +} + +static void +tty3270_flush_buffer(struct tty_struct *tty) +{ + tub_t *tubp; + bcb_t *ob; + int flags; + + if ((tubp = tty->driver_data) == NULL) + return; + + if (tubp->mode == TBM_FS && tubp->fs_pid != 0) { + kill_proc(tubp->fs_pid, SIGHUP, 1); + } + + if ((tubp->flags & TUB_OPEN_STET) == 0) { + ob = &tubp->tty_bcb; + TUBLOCK(tubp->irq, flags); + ob->bc_rd = 0; + ob->bc_wr = 0; + ob->bc_cnt = 0; + TUBUNLOCK(tubp->irq, flags); + } + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +static int +tty3270_read_proc(char *buf, char **start, off_t off, int count, + int *eof, void *data) +{ + tub_t *tubp; + int begin = 0; + int i; + int rc; + int len = 0; + char *majstr; + + if (tty3270_proc_what == TW_CONFIG) { + /* + * Describe the 3270 configuration in ascii lines. + * Line 1: 0 <fsmajor> 0 + * Console line: <devnum> CONSOLE <minor> + * Other lines: <devnum> <ttymajor> <minor> + */ + len += sprintf(buf + len, "0 %d 0\n", fs3270_major); + for (i = 1; i <= tubnummins; i++) { + tubp = (*tubminors)[i]; + majstr = tty3270_major_string; +#ifdef CONFIG_3270_CONSOLE + if (tubp == tub3270_con_tubp) + majstr = "CONSOLE"; +#endif /* CONFIG_3270_CONSOLE */ + len += sprintf(buf + len, "%.3x %s %d\n", + tubp->devno, majstr, i); + if (begin + len > off + count) + break; + if (begin + len < off) { + begin += len; + len = 0; + } + } + if (i > tubnummins) + *eof = 1; + if (off >= begin + len) { + rc = 0; + } else { + *start = buf + off - begin; + rc = MIN(count, begin + len - off); + } + if (*eof && rc == 0) + tty3270_proc_what = TW_BOGUS; + return rc; + } + + len += sprintf(buf, "There are %d devices. fs major is %d, " + "tty major is %d.\n", tubnummins, fs3270_major, + tty3270_major); + len += sprintf(buf+len, " index=%d data=%d misc=%d\n", + tty3270_proc_index, + tty3270_proc_data, + tty3270_proc_misc); + + /* + * Display info for the tube with minor nr in index + */ + len += tty3270_show_tube(tty3270_proc_index, buf+len, count-len); + + *eof = 1; + if (off >= begin + len) + return 0; + *start = buf + off - begin; + return MIN(count, begin + len - off); +} + +static int +tty3270_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char mybuf[GEOM_MAXINPLEN]; + int mycount; + tub_t *tubp; + struct tty_struct *tty; + kdev_t device; + int rc; + + mycount = MIN(count, sizeof mybuf - 1); + if (copy_from_user(mybuf, buffer, mycount) != 0) + return -EFAULT; + mybuf[mycount] = '\0'; + + /* + * User-mode settings affect only the current tty --- + */ + tubp = NULL; + tty = current->tty; + device = tty? tty->device: 0; + if (device) { + if (MAJOR(device) == IBM_TTY3270_MAJOR) + tubp = (*tubminors)[MINOR(device)]; +#ifdef CONFIG_3270_CONSOLE + if (device == S390_CONSOLE_DEV) + tubp = tub3270_con_tubp; +#endif /* CONFIG_3270_CONSOLE */ + } + if (tubp) { + if ((rc = tty3270_aid_set(tubp, mybuf, mycount + 1))) + return rc > 0? count: rc; + if ((rc = tty3270_rcl_set(tubp, mybuf, mycount + 1))) + return rc > 0? count: rc; + if ((rc = tty3270_scl_set(tubp, mybuf, mycount + 1))) + return rc > 0? count: rc; + } + + /* + * Superuser-mode settings affect the driver overall --- + */ + if (!suser()) { + return -EPERM; + } else if (strncmp(mybuf, "index=", 6) == 0) { + tty3270_proc_index = simple_strtoul(mybuf + 6, 0,0); + return count; + } else if (strncmp(mybuf, "data=", 5) == 0) { + tty3270_proc_data = simple_strtoul(mybuf + 5, 0, 0); + return count; + } else if (strncmp(mybuf, "misc=", 5) == 0) { + tty3270_proc_misc = simple_strtoul(mybuf + 5, 0, 0); + return count; + } else if (strncmp(mybuf, "what=", 5) == 0) { + if (strcmp(mybuf+5, "bogus") == 0) + tty3270_proc_what = 0; + else if (strncmp(mybuf+5, "config", 6) == 0) + tty3270_proc_what = TW_CONFIG; + return count; + } else { + return -EINVAL; + } +} + +static void +tty3270_hangup(struct tty_struct *tty) +{ + tub_t *tubp; + extern void fs3270_release(tub_t *); + + if ((tubp = tty->driver_data) == NULL) + return; + tty3270_rcl_purge(tubp); + tty3270_aid_reinit(tubp); + fs3270_release(tubp); +} + + +/* + * tty3270_bh(tubp) -- Perform back-half processing + */ +static void +tty3270_bh(void *data) +{ + int flags; + tub_t *tubp; + struct tty_struct *tty; + + tubp = data; + TUBLOCK(tubp->irq, flags); + tubp->flags &= ~TUB_BHPENDING; + tty = tubp->tty; + + if (tubp->flags & TUB_UNSOL_DE) { + tubp->flags &= ~TUB_UNSOL_DE; + if (tty != NULL) { + tty_hangup(tty); + wake_up_interruptible(&tubp->waitq); + goto do_unlock; + } + } + + if (tubp->flags & TUB_IACTIVE) { /* If read ended, */ + tty3270_do_input(tubp); + tubp->flags &= ~TUB_IACTIVE; + } + + if ((tubp->flags & TUB_WORKING) == 0) { + if (tubp->flags & TUB_ATTN) { + tty3270_start_input(tubp); + tubp->flags &= ~TUB_ATTN; + } else if (tty3270_try_logging(tubp) == 0) { + wake_up_interruptible(&tubp->waitq); + } + } + + if (tty != NULL) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup != NULL) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } +do_unlock: + TUBUNLOCK(tubp->irq, flags); +} + +/* + * tty3270_sched_bh(tubp) -- Schedule the back half + * Irq lock must be held on entry and remains held on exit. + */ +void +tty3270_sched_bh(tub_t *tubp) +{ + if (tubp->flags & TUB_BHPENDING) + return; + tubp->flags |= TUB_BHPENDING; + tubp->tqueue.routine = tty3270_bh; + tubp->tqueue.data = tubp; + queue_task(&tubp->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +/* + * tty3270_io() -- Perform line-mode reads and writes here + */ +int +tty3270_io(tub_t *tubp) +{ + int rc; + ccw1_t *ccwp; + + tubp->flags |= TUB_WORKING; + tubp->dstat = 0; + ccwp = &tubp->ttyccw; + + rc = do_IO(tubp->irq, ccwp, tubp->irq, 0, 0); + return rc; +} + +/* + * tty3270_wait(tubp) -- Wait until TUB_WORKING is off + * On entry the lock must not be held; on exit it is held. + */ +static int +tty3270_wait(tub_t *tubp, int *flags) +{ + DECLARE_WAITQUEUE(wait, current); + + TUBLOCK(tubp->irq, *flags); + add_wait_queue(&tubp->waitq, &wait); + while (!signal_pending(current) && + (tubp->flags & TUB_WORKING) != 0) { + current->state = TASK_INTERRUPTIBLE; + TUBUNLOCK(tubp->irq, *flags); + schedule(); + current->state = TASK_RUNNING; + TUBLOCK(tubp->irq, *flags); + } + remove_wait_queue(&tubp->waitq, &wait); + return signal_pending(current)? -ERESTARTSYS: 0; +} + +void +tty3270_int(tub_t *tubp, devstat_t *dsp) +{ +#define DEV_UE_BUSY \ + (DEV_STAT_CHN_END | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP) +#define DEV_NOT_WORKING \ + (DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_CHECK) + + tubp->dstat = dsp->dstat; + + /* Handle CE-DE-UE and subsequent UDE */ + if (dsp->dstat == DEV_UE_BUSY) { + tubp->flags |= TUB_UE_BUSY; + return; + } else if (tubp->flags & TUB_UE_BUSY) { + tubp->flags &= ~TUB_UE_BUSY; + if (dsp->dstat == DEV_STAT_DEV_END && + (tubp->flags & TUB_WORKING) != 0) { + tty3270_io(tubp); + return; + } + } + + /* Handle ATTN */ + if (dsp->dstat & DEV_STAT_ATTENTION) + tubp->flags |= TUB_ATTN; + + if (dsp->dstat & DEV_STAT_CHN_END) { + tubp->cswl = dsp->rescnt; + if ((dsp->dstat & DEV_STAT_DEV_END) == 0) + tubp->flags |= TUB_EXPECT_DE; + else + tubp->flags &= ~TUB_EXPECT_DE; + } else if (dsp->dstat & DEV_STAT_DEV_END) { + if ((tubp->flags & TUB_EXPECT_DE) == 0) + tubp->flags |= TUB_UNSOL_DE; + tubp->flags &= ~TUB_EXPECT_DE; + } + if (dsp->dstat & DEV_NOT_WORKING) + tubp->flags &= ~TUB_WORKING; + if (dsp->dstat & DEV_STAT_UNIT_CHECK) + tubp->sense = dsp->ii.sense; + if ((tubp->flags & TUB_WORKING) == 0) + tty3270_sched_bh(tubp); +} + +/* + * tty3270_refresh(), called by fs3270_close() when tubp->fsopen == 0. + * On entry, lock is held. + */ +void +tty3270_refresh(tub_t *tubp) +{ + if (tubp->lnopen) { + tubp->mode = TBM_LN; + tubp->intv = tty3270_int; + tty3270_scl_resettimer(tubp); + tubp->cmd = TBC_UPDATE; + tty3270_build(tubp); + } +} + +int +tty3270_try_logging(tub_t *tubp) +{ + if (tubp->flags & TUB_WORKING) + return 0; + if (tubp->mode == TBM_FS) + return 0; + if (tubp->stat == TBS_HOLD) + return 0; + if (tubp->stat == TBS_MORE) + return 0; +#ifdef CONFIG_3270_CONSOLE + if (tub3270_con_tubp == tubp) + tub3270_con_copy(tubp); +#endif /* CONFIG_3270_CONSOLE */ + if (tubp->tty_bcb.bc_cnt == 0) + return 0; + if (tubp->intv != tty3270_int) + return 0; + tubp->cmd = TBC_UPDLOG; + return tty3270_build(tubp); +} + +/* tty3270 utility functions */ + +static void +tty3270_start_input(tub_t *tubp) +{ + tubp->ttyccw.cda = virt_to_phys(&tubp->tty_input); + tubp->ttyccw.cmd_code = TC_READMOD; + tubp->ttyccw.count = GEOM_INPLEN; + tubp->ttyccw.flags = CCW_FLAG_SLI; + tty3270_io(tubp); + tubp->flags |= TUB_IACTIVE; +} + +static void +tty3270_do_input(tub_t *tubp) +{ + int count; + char *in; + int aidflags; + char *aidstring; + + count = GEOM_INPLEN - tubp->cswl; + in = tubp->tty_input; + tty3270_aid_get(tubp, in[0], &aidflags, &aidstring); + + if (aidflags & TA_CLEARKEY) { + tubp->stat = TBS_RUNNING; + tty3270_scl_resettimer(tubp); + tubp->cmd = TBC_UPDATE; + } else if (aidflags & TA_CLEARLOG) { + tubp->stat = TBS_RUNNING; + tty3270_scl_resettimer(tubp); + tubp->cmd = TBC_CLRUPDLOG; + } else if (aidflags & TA_DOENTER) { + if (count <= 6) { + switch(tubp->stat) { + case TBS_MORE: + tubp->stat = TBS_HOLD; + tty3270_scl_resettimer(tubp); + break; + case TBS_HOLD: + tubp->stat = TBS_MORE; + tty3270_scl_settimer(tubp); + break; + case TBS_RUNNING: + tty3270_do_enter(tubp, in + 6, 0); + break; + } + tubp->cmd = TBC_UPDSTAT; + goto do_build; + } + in += 6; + count -= 6; + TUB_EBCASC(in, count); + tubp->cmd = TBC_CLRINPUT; + tty3270_do_enter(tubp, in, count); + } else if ((aidflags & TA_DOSTRING) != 0 && aidstring != NULL) { + tubp->cmd = TBC_KRUPDLOG; + tty3270_do_enter(tubp, aidstring, strlen(aidstring)); + } else if ((aidflags & TA_DOSTRINGD) != 0 && aidstring != NULL) { + tty3270_do_showi(tubp, aidstring, strlen(aidstring)); + tubp->cmd = TBC_UPDINPUT; + } else { + if (in[0] != 0x60) + tubp->flags |= TUB_ALARM; + tubp->cmd = TBC_KRUPDLOG; + } +do_build: + tty3270_build(tubp); +} + +static void +tty3270_do_enter(tub_t *tubp, char *cp, int count) +{ + struct tty_struct *tty; + int func = -1; + + if ((tty = tubp->tty) == NULL) + return; + if (count < 0) + return; + if (count == 2 && (cp[0] == '^' || cp[0] == '\252')) { + switch(cp[1]) { + case 'c': case 'C': + func = INTR_CHAR(tty); + break; + case 'd': case 'D': + func = EOF_CHAR(tty); + break; + case 'z': case 'Z': + func = SUSP_CHAR(tty); + break; + } + } else if (count == 2 && cp[0] == 0x1b) { /* if ESC */ + int inc = 0; + char buf[GEOM_INPLEN + 1]; + int len; + + switch(cp[1]) { + case 'k': case 'K': + inc = -1; + break; + case 'j': case 'J': + inc = 1; + break; + } + if (inc == 0) + goto not_rcl; + len = tty3270_rcl_get(tubp, buf, sizeof buf, inc); + if (len == 0) { + tubp->flags |= TUB_ALARM; + return; + } + tty3270_do_showi(tubp, buf, len); + tubp->cmd = TBC_UPDINPUT; + return; + } +not_rcl: + if (func != -1) { + *tty->flip.flag_buf_ptr++ = TTY_NORMAL; + *tty->flip.char_buf_ptr++ = func; + tty->flip.count++; + } else { + tty3270_rcl_put(tubp, cp, count); + memcpy(tty->flip.char_buf_ptr, cp, count); + /* Add newline unless line ends with "^n" */ + if (count < 2 || cp[count - 1] != 'n' || + (cp[count - 2] != '^' && cp[count - 2] != '\252')) { + tty->flip.char_buf_ptr[count] = '\n'; + count++; + } else { + count -= 2; /* Lop trailing "^n" from text */ + } + 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); +} + +static void +tty3270_do_showi(tub_t *tubp, char *cp, int cl) +{ + if (cl > GEOM_INPLEN) + cl = GEOM_INPLEN; + memset(tubp->tty_input, 0, GEOM_INPLEN); + memcpy(tubp->tty_input, cp, cl); + TUB_ASCEBC(tubp->tty_input, cl); +} + + + +/* Debugging routine */ +static int +tty3270_show_tube(int minor, char *buf, int count) +{ + tub_t *tubp; + struct tty_struct *tty; + struct termios *mp; + int len; + +/*012345678901234567890123456789012345678901234567890123456789 */ +/*Info for tub_t[dd] at xxxxxxxx: */ +/* geom: rows=dd cols=dd model=d */ +/* lnopen=dd fsopen=dd waitq=xxxxxxxx */ +/* dstat=xx mode=dd stat=dd flags=xxxx */ +/* oucount=dddd ourd=ddddd ouwr=ddddd nextlogx=ddddd */ +/* tty=xxxxxxxx */ +/* write_wait=xxxxxxxx read_wait=xxxxxxxx */ +/* iflag=xxxxxxxx oflag=xxxxxxxx cflag=xxxxxxxx lflag=xxxxxxxx */ + + if (minor < 0 || minor > tubnummins || + (tubp = (*tubminors)[minor]) == NULL) + return sprintf(buf, "No tube at index=%d\n", minor); + + tty = tubp->tty; + len = 0; + + len += sprintf(buf+len, +"Info for tub_t[%d] at %.8x:\n", + minor, (int)tubp); + + len += sprintf(buf+len, "inattr is at %.8x\n", + (int)&tubp->tty_inattr); + + + len += sprintf(buf+len, +" geom: rows=%.2d cols=%.2d model=%.1d\n", + tubp->geom_rows, tubp->geom_cols, tubp->tubiocb.model); + + len += sprintf(buf+len, +" lnopen=%-2d fsopen=%-2d waitq=%.8x\n", + tubp->lnopen, tubp->fsopen, (int)&tubp->waitq); + + len += sprintf(buf+len, +" dstat=%.2x mode=%-2d stat=%-2d flags=%-4x\n", + tubp->dstat, tubp->mode, tubp->stat, tubp->flags); + +#ifdef RBH_FIXTHIS + len += sprintf(buf+len, +" oucount=%-4d ourd=%-5d ouwr=%-5d nextlogx=%-5d\n", + tubp->tty_oucount, tubp->tty_ourd, tubp->tty_ouwr, + tubp->tty_nextlogx); +#endif + + len += sprintf(buf+len, +" tty=%.8x\n", + (int)tubp->tty); + + if (tty) len += sprintf(buf+len, +" write_wait=%.8x read_wait=%.8x\n", + (int)&tty->write_wait, (int)&tty->read_wait); + + if (tty && ((mp = tty->termios))) len += sprintf(buf+len, +" iflag=%.8x oflag=%.8x cflag=%.8x lflag=%.8x\n", + mp->c_iflag, mp->c_oflag, mp->c_cflag, mp->c_lflag); + + + return len; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tubttyaid.c linux.ac/drivers/s390/char/tubttyaid.c --- linux.vanilla/drivers/s390/char/tubttyaid.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/s390/char/tubttyaid.c Thu Apr 12 12:03:49 2001 @@ -0,0 +1,205 @@ +/* + * IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC + * + * tubttyaid.c -- Linemode Attention-ID functionality + * + * + * + * + * + * Author: Richard Hitt + */ +#include "tubio.h" + +#define PA1_STR "^C" +#define PF3_STR "^D" +#define PF9_STR "\033j" +#define PF10_STR "\033k" +#define PF11_STR "\033j" +/* other AID-key default strings */ + +aid_t aidtab[64] = { +/* 00 */ { 0, 0 }, +/* C1 = PF13 */ { TA_DOSTRING, 0 }, +/* C2 = PF14 */ { TA_DOSTRING, 0 }, +/* C3 = PF15 */ { TA_DOSTRING, 0 }, +/* C4 = PF16 */ { TA_DOSTRING, 0 }, +/* C5 = PF17 */ { TA_DOSTRING, 0 }, +/* C6 = PF18 */ { TA_DOSTRING, 0 }, +/* C7 = PF19 */ { TA_DOSTRING, 0 }, +/* C8 = PF20 */ { TA_DOSTRING, 0 }, +/* C9 = PF21 */ { TA_DOSTRING, 0 }, +/* 4A = PF22 */ { TA_DOSTRING, 0 }, +/* 4B = PF23 */ { TA_DOSTRING, 0 }, +/* 4C = PF24 */ { TA_DOSTRING, 0 }, +/* 0D */ { 0, 0 }, +/* 0E */ { 0, 0 }, +/* 0F */ { 0, 0 }, +/* 10 */ { 0, 0 }, +/* 11 */ { 0, 0 }, +/* 12 */ { 0, 0 }, +/* 13 */ { 0, 0 }, +/* 14 */ { 0, 0 }, +/* 15 */ { 0, 0 }, +/* 16 */ { 0, 0 }, +/* 17 */ { 0, 0 }, +/* 18 */ { 0, 0 }, +/* 19 */ { 0, 0 }, +/* 1A */ { 0, 0 }, +/* 1B */ { 0, 0 }, +/* 1C */ { 0, 0 }, +/* 1D */ { 0, 0 }, +/* 1E */ { 0, 0 }, +/* 1F */ { 0, 0 }, +/* 60 = NoAID */ { 0, 0 }, +/* 21 */ { 0, 0 }, +/* 22 */ { 0, 0 }, +/* 23 */ { 0, 0 }, +/* 24 */ { 0, 0 }, +/* 25 */ { 0, 0 }, +/* E6 = OpRdr */ { 0, 0 }, +/* E7 = MSRdr */ { 0, 0 }, +/* E8 = NoAID */ { 0, 0 }, +/* 29 */ { 0, 0 }, +/* 2A */ { 0, 0 }, +/* 6B = PA3 */ { TA_SHORTREAD, 0 }, +/* 6C = PA1 */ { TA_SHORTREAD | TA_DOSTRING, PA1_STR }, +/* 6D = CLEAR */ { TA_SHORTREAD | TA_CLEARKEY, 0 }, +/* 6E = PA2 */ { TA_SHORTREAD | TA_CLEARLOG, 0 }, +/* 2F */ { 0, 0 }, +/* F0 = TstRq */ { 0, 0 }, +/* F1 = PF1 */ { TA_DOSTRING, 0 }, +/* F2 = PF2 */ { TA_DOSTRING, 0 }, +/* F3 = PF3 */ { TA_DOSTRING, PF3_STR }, +/* F4 = PF4 */ { TA_DOSTRING, 0 }, +/* F5 = PF5 */ { TA_DOSTRING, 0 }, +/* F6 = PF6 */ { TA_DOSTRING, 0 }, +/* F7 = PF7 */ { TA_DOSTRING, 0 }, +/* F8 = PF8 */ { TA_DOSTRING, 0 }, +/* F9 = PF9 */ { TA_DOSTRING, PF9_STR }, +/* 7A = PF10 */ { TA_DOSTRING, PF10_STR }, +/* 7B = PF11 */ { TA_DOSTRING, PF11_STR }, +/* 7C = PF12 */ { TA_DOSTRING, 0 }, +/* 7D = ENTER */ { TA_DOENTER, 0 }, +/* 7E = Pen */ { 0, 0 }, +/* 3F */ { 0, 0 }, +}; + +int +tty3270_aid_init(tub_t *tubp) +{ + memcpy(tubp->tty_aid, aidtab, sizeof aidtab); + tubp->tty_aidinit = 1; + return 0; +} + +void +tty3270_aid_fini(tub_t *tubp) +{ + int i; + char *sp; + + if (tubp->tty_aidinit == 0) + return; + for (i = 0; i < 64; i++) { + if ((sp = tubp->tty_aid[i].string) == NULL) + continue; + if (sp == aidtab[i].string) + continue; + kfree(sp); + } + tubp->tty_aidinit = 0; +} + +void +tty3270_aid_reinit(tub_t *tubp) +{ + tty3270_aid_fini(tubp); + tty3270_aid_init(tubp); +} + +int +tty3270_aid_get(tub_t *tubp, int aid, int *aidflags, char **aidstring) +{ + aid_t *ap; + + ap = AIDENTRY(aid, tubp); + *aidflags = ap->aid; + *aidstring = ap->string; + return 0; +} + +/* + * tty3270_aid_set() -- write_proc extension + * Parse written string as an AID name. Return 0 if it's not. + * Otherwise absorb the string and return count or -error. + */ +int +tty3270_aid_set(tub_t *tubp, char *buf, int count) +{ + char name[8]; + char *sp; + int aidn, aidx; + aid_t *ap; + int len; + char *pfp; + + if (tubp->tty_aidinit == 0) + return 0; + if (count < 3) /* If AID-key name too short */ + return 0; + name[0] = buf[0] < 0x60? buf[0]: (buf[0] & 0x5f); + name[1] = buf[1] < 0x60? buf[1]: (buf[1] & 0x5f); + if (name[0] == 'P' && name[1] == 'F') { + aidn = simple_strtoul(buf+2, &sp, 10); + if (aidn < 1 || aidn > 24) + return 0; + aidx = aidn > 12? aidn - 12: aidn + 0x30; + ap = &tubp->tty_aid[aidx]; + } else if (name[0] == 'P' && name[1] == 'A') { + aidn = simple_strtoul(buf+2, &sp, 10); + if (aidn < 1 || aidn > 3) + return 0; + switch(aidn) { + case 1: aidx = 0x2c; break; + case 2: aidx = 0x2e; break; + case 3: aidx = 0x2b; break; + default: aidx = 0; break; + } + ap = &tubp->tty_aid[aidx]; + } else { + return 0; + } + + if (*sp == '\0') { + tubp->tty_showaidx = ap - tubp->tty_aid; + return count; + } else if (*sp == '=') { + len = strlen(++sp); + if (len == 0) { + if (ap->string != NULL && + ap->string != aidtab[aidx].string) + kfree(ap->string); + ap->string = aidtab[aidx].string; + ap->aid = aidtab[aidx].aid; + return count; + } + if ((pfp = kmalloc(len + 1, GFP_KERNEL)) == NULL) + return -ENOMEM; + if (ap->string != NULL && + ap->string != aidtab[aidx].string) + kfree(ap->string); + if (sp[len - 1] == '\n') { + ap->aid = TA_DOSTRING; + sp[len - 1] = '\0'; + len--; + } else { + ap->aid = TA_DOSTRINGD; + } + memcpy(pfp, sp, len + 1); + ap->string = pfp; + return count; + } else { + return -EINVAL; + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tubttybld.c linux.ac/drivers/s390/char/tubttybld.c --- linux.vanilla/drivers/s390/char/tubttybld.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/s390/char/tubttybld.c Thu Apr 12 12:03:49 2001 @@ -0,0 +1,448 @@ +/* + * IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC + * + * tubttybld.c -- Linemode tty driver screen-building functions + * + * + * + * + * + * Author: Richard Hitt + */ + +#include "tubio.h" + +extern int tty3270_io(tub_t *); +static void tty3270_set_status_area(tub_t *, char **); +static int tty3270_next_char(tub_t *); +static void tty3270_update_log_area(tub_t *, char **); +static void tty3270_update_log_area_esc(tub_t *, char **); +static void tty3270_clear_log_area(tub_t *, char **); +static void tty3270_tub_bufadr(tub_t *, int, char **); + +/* + * tty3270_clear_log_area(tub_t *tubp, char **cpp) + */ +static void +tty3270_clear_log_area(tub_t *tubp, char **cpp) +{ + *(*cpp)++ = TO_SBA; + TUB_BUFADR(GEOM_LOG, cpp); + *(*cpp)++ = TO_SF; + *(*cpp)++ = TF_LOG; + *(*cpp)++ = TO_RA; + TUB_BUFADR(GEOM_INPUT, cpp); + *(*cpp)++ = '\0'; + tubp->tty_oucol = tubp->tty_nextlogx = 0; +} + +static void +tty3270_update_log_area(tub_t *tubp, char **cpp) +{ + int lastx = GEOM_INPUT; + int c; + int next, fill, i; + int sba_needed = 1; + char *overrun = &(*tubp->ttyscreen)[tubp->ttyscreenl - TS_LENGTH]; + + /* Place characters */ + while (tubp->tty_bcb.bc_cnt != 0) { + if (tubp->tty_nextlogx >= lastx) { + if (sba_needed == 0 || tubp->stat == TBS_RUNNING) { + tubp->stat = TBS_MORE; + tty3270_set_status_area(tubp, cpp); + tty3270_scl_settimer(tubp); + } + break; + } + + /* Check for room for another char + possible ESCs */ + if (&(*cpp)[tubp->tty_escx + 1] >= overrun) + break; + + /* Fetch a character */ + if ((c = tty3270_next_char(tubp)) == -1) + break; + + /* Add a Set-Buffer-Address Order if we haven't */ + if (sba_needed) { + sba_needed = 0; + *(*cpp)++ = TO_SBA; + TUB_BUFADR(tubp->tty_nextlogx, cpp); + } + + switch(c) { + default: + if (c < ' ') /* Blank it if we don't know it */ + c = ' '; + for (i = 0; i < tubp->tty_escx; i++) + *(*cpp)++ = tubp->tty_esca[i]; + tubp->tty_escx = 0; + *(*cpp)++ = tub_ascebc[(int)c]; + tubp->tty_nextlogx++; + tubp->tty_oucol++; + break; + case 0x1b: /* ESC */ + tty3270_update_log_area_esc(tubp, cpp); + break; + case '\r': + break; /* completely ignore 0x0d = CR. */ + case '\n': + if (tubp->tty_oucol == GEOM_COLS) { + tubp->tty_oucol = 0; + break; + } + next = (tubp->tty_nextlogx + GEOM_COLS) / + GEOM_COLS * GEOM_COLS; + next = MIN(next, lastx); + fill = next - tubp->tty_nextlogx; + if (fill < 5) { + for (i = 0; i < fill; i++) + *(*cpp)++ = tub_ascebc[' ']; + } else { + *(*cpp)++ = TO_RA; + TUB_BUFADR(next, cpp); + *(*cpp)++ = tub_ascebc[' ']; + } + tubp->tty_nextlogx = next; + tubp->tty_oucol = 0; + break; + case '\t': + fill = (tubp->tty_nextlogx % GEOM_COLS) % 8; + for (; fill < 8; fill++) { + if (tubp->tty_nextlogx >= lastx) + break; + *(*cpp)++ = tub_ascebc[' ']; + tubp->tty_nextlogx++; + tubp->tty_oucol++; + } + break; + case '\a': + tubp->flags |= TUB_ALARM; + break; + case '\f': + tty3270_clear_log_area(tubp, cpp); + break; + } + } +} + +#define NUMQUANT 8 +static void +tty3270_update_log_area_esc(tub_t *tubp, char **cpp) +{ + int lastx = GEOM_INPUT; + int c; + int i; + int start, next, fill; + int quant[NUMQUANT]; + + if ((c = tty3270_next_char(tubp)) != '[') { + return; + } + + /* + * Parse potentially empty string "nn;nn;nn..." + */ + i = -1; + c = ';'; + do { + if (c == ';') { + if (++i == NUMQUANT) + break; + quant[i] = 0; + } else if (c < '0' || c > '9') { + break; + } else { + quant[i] = quant[i] * 10 + c - '0'; + } + } while ((c = tty3270_next_char(tubp)) != -1); + if (c == -1) { + return; + } + if (i >= NUMQUANT) { + return; + } + switch(c) { + case -1: + return; + case 'm': /* Set Attribute */ + for (next = 0; next <= i; next++) { + int type = -1, value = 0; + + if (tubp->tty_escx + 3 > MAX_TTY_ESCA) + break; + switch(quant[next]) { + case 0: /* Reset */ + tubp->tty_esca[tubp->tty_escx++] = TO_SA; + tubp->tty_esca[tubp->tty_escx++] = TAT_RESET; + tubp->tty_esca[tubp->tty_escx++] = TAR_RESET; + break; + case 1: /* Bright */ + case 2: /* Dim */ + case 4: /* Underscore */ + case 5: /* Blink */ + case 7: /* Reverse */ + case 8: /* Hidden */ + break; /* For now ... */ + /* Foreground Colors */ + case 30: /* Black */ + type = TAT_COLOR; value = TAC_DEFAULT; + break; + case 31: /* Red */ + type = TAT_COLOR; value = TAC_RED; + break; + case 32: /* Green */ + type = TAT_COLOR; value = TAC_GREEN; + break; + case 33: /* Yellow */ + type = TAT_COLOR; value = TAC_YELLOW; + break; + case 34: /* Blue */ + type = TAT_COLOR; value = TAC_BLUE; + break; + case 35: /* Magenta */ + type = TAT_COLOR; value = TAC_PINK; + break; + case 36: /* Cyan */ + type = TAT_COLOR; value = TAC_TURQ; + break; + case 37: /* White */ + type = TAT_COLOR; value = TAC_WHITE; + break; + case 39: /* Black */ + type = TAT_COLOR; value = TAC_DEFAULT; + break; + /* Background Colors */ + case 40: /* Black */ + case 41: /* Red */ + case 42: /* Green */ + case 43: /* Yellow */ + case 44: /* Blue */ + case 45: /* Magenta */ + case 46: /* Cyan */ + case 47: /* White */ + break; /* For now ... */ + /* Oops */ + default: + break; + } + if (type != -1) { + tubp->tty_esca[tubp->tty_escx++] = TO_SA; + tubp->tty_esca[tubp->tty_escx++] = type; + tubp->tty_esca[tubp->tty_escx++] = value; + } + } + break; + case 'H': /* Cursor Home */ + case 'f': /* Force Cursor Position */ + return; + case 'A': /* Cursor Up */ + return; + case 'B': /* Cursor Down */ + return; + case 'C': /* Cursor Forward */ + next = tubp->tty_nextlogx % GEOM_COLS; + start = tubp->tty_nextlogx - next; + next = start + MIN(next + quant[i], GEOM_COLS - 1); + next = MIN(next, lastx); +do_fill: + fill = next - tubp->tty_nextlogx; + if (fill < 5) { + for (i = 0; i < fill; i++) + *(*cpp)++ = tub_ascebc[' ']; + } else { + *(*cpp)++ = TO_RA; + TUB_BUFADR(next, cpp); + *(*cpp)++ = tub_ascebc[' ']; + } + tubp->tty_nextlogx = next; + tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS; + break; + case 'D': /* Cursor Backward */ + next = MIN(quant[i], tubp->tty_nextlogx % GEOM_COLS); + tubp->tty_nextlogx -= next; + tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS; + *(*cpp)++ = TO_SBA; + TUB_BUFADR(tubp->tty_nextlogx, cpp); + break; + case 'G': + start = tubp->tty_nextlogx / GEOM_COLS * GEOM_COLS; + next = MIN(quant[i], GEOM_COLS - 1) + start; + next = MIN(next, lastx); + goto do_fill; + } +} + + +static int +tty3270_next_char(tub_t *tubp) +{ + int c; + bcb_t *ib; + + ib = &tubp->tty_bcb; + if (ib->bc_cnt == 0) + return -1; + c = ib->bc_buf[ib->bc_rd++]; + if (ib->bc_rd == ib->bc_len) + ib->bc_rd = 0; + ib->bc_cnt--; + return c; +} + + +static void +tty3270_clear_input_area(tub_t *tubp, char **cpp) +{ + *(*cpp)++ = TO_SBA; + TUB_BUFADR(GEOM_INPUT, cpp); + *(*cpp)++ = TO_SF; + *(*cpp)++ = tubp->tty_inattr; + *(*cpp)++ = TO_IC; + *(*cpp)++ = TO_RA; + TUB_BUFADR(GEOM_STAT, cpp); + *(*cpp)++ = '\0'; +} + +static void +tty3270_update_input_area(tub_t *tubp, char **cpp) +{ + int len; + + *(*cpp)++ = TO_SBA; + TUB_BUFADR(GEOM_INPUT, cpp); + *(*cpp)++ = TO_SF; + *(*cpp)++ = TF_INMDT; + len = strlen(tubp->tty_input); + memcpy(*cpp, tubp->tty_input, len); + *cpp += len; + *(*cpp)++ = TO_IC; + len = GEOM_INPLEN - len; + if (len > 4) { + *(*cpp)++ = TO_RA; + TUB_BUFADR(GEOM_STAT, cpp); + *(*cpp)++ = '\0'; + } else { + for (; len > 0; len--) + *(*cpp)++ = '\0'; + } +} + +/* + * tty3270_set_status_area(tub_t *tubp, char **cpp) + */ +static void +tty3270_set_status_area(tub_t *tubp, char **cpp) +{ + char *sp; + + if (tubp->stat == TBS_RUNNING) + sp = TS_RUNNING; + else if (tubp->stat == TBS_MORE) + sp = TS_MORE; + else if (tubp->stat == TBS_HOLD) + sp = TS_HOLD; + else + sp = "Linux Whatstat"; + + *(*cpp)++ = TO_SBA; + TUB_BUFADR(GEOM_STAT, cpp); + *(*cpp)++ = TO_SF; + *(*cpp)++ = TF_STAT; + memcpy(*cpp, sp, sizeof TS_RUNNING); + TUB_ASCEBC(*cpp, sizeof TS_RUNNING); + *cpp += sizeof TS_RUNNING; +} + +/* + * tty3270_build() -- build an output stream + */ +int +tty3270_build(tub_t *tubp) +{ + char *cp, *startcp; + int chancmd; + int writecc = TW_KR; + int force = 0; + + if (tubp->mode == TBM_FS) + return 0; + + cp = startcp = *tubp->ttyscreen + 1; + + switch(tubp->cmd) { + default: + printk(KERN_WARNING "tty3270_build unknown command %d\n", tubp->cmd); + return 0; + case TBC_OPEN: + chancmd = TC_EWRITEA; + tty3270_clear_input_area(tubp, &cp); + tty3270_set_status_area(tubp, &cp); + tty3270_clear_log_area(tubp, &cp); + break; + case TBC_UPDLOG: + chancmd = TC_WRITE; + writecc = TW_NONE; + tty3270_update_log_area(tubp, &cp); + break; + case TBC_KRUPDLOG: + chancmd = TC_WRITE; + force = 1; + tty3270_update_log_area(tubp, &cp); + break; + case TBC_CLRUPDLOG: + chancmd = TC_WRITE; + tty3270_set_status_area(tubp, &cp); + tty3270_clear_log_area(tubp, &cp); + tty3270_update_log_area(tubp, &cp); + break; + case TBC_UPDATE: + chancmd = TC_EWRITEA; + tubp->tty_oucol = tubp->tty_nextlogx = 0; + tty3270_clear_input_area(tubp, &cp); + tty3270_set_status_area(tubp, &cp); + tty3270_update_log_area(tubp, &cp); + break; + case TBC_UPDSTAT: + chancmd = TC_WRITE; + tty3270_set_status_area(tubp, &cp); + break; + case TBC_CLRINPUT: + chancmd = TC_WRITE; + tty3270_clear_input_area(tubp, &cp); + break; + case TBC_UPDINPUT: + chancmd = TC_WRITE; + tty3270_update_input_area(tubp, &cp); + break; + } + + /* Set Write Control Character and start I/O */ + if (force == 0 && cp == startcp && + (tubp->flags & TUB_ALARM) == 0) + return 0; + if (tubp->flags & TUB_ALARM) { + tubp->flags &= ~TUB_ALARM; + writecc |= TW_PLUSALARM; + } + **tubp->ttyscreen = writecc; + tubp->ttyccw.cmd_code = chancmd; + tubp->ttyccw.flags = CCW_FLAG_SLI; + tubp->ttyccw.cda = virt_to_phys(*tubp->ttyscreen); + tubp->ttyccw.count = cp - *tubp->ttyscreen; + tty3270_io(tubp); + return 1; +} + +static void +tty3270_tub_bufadr(tub_t *tubp, int adr, char **cpp) +{ + if (tubp->tty_14bitadr) { + *(*cpp)++ = (adr >> 8) & 0x3f; + *(*cpp)++ = adr & 0xff; + } else { + *(*cpp)++ = tub_ebcgraf[(adr >> 6) & 0x3f]; + *(*cpp)++ = tub_ebcgraf[adr & 0x3f]; + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tubttyrcl.c linux.ac/drivers/s390/char/tubttyrcl.c --- linux.vanilla/drivers/s390/char/tubttyrcl.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/s390/char/tubttyrcl.c Thu Apr 12 12:03:49 2001 @@ -0,0 +1,199 @@ +/* + * IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC + * + * tubttyrcl.c -- Linemode Command-recall functionality + * + * + * + * + * + * Author: Richard Hitt + */ +#include "tubio.h" + +int +tty3270_rcl_init(tub_t *tubp) +{ + return tty3270_rcl_resize(tubp, 20); +} + +int +tty3270_rcl_resize(tub_t *tubp, int newrclk) +{ + char *(*newrclb)[]; + + if (newrclk > 1000) + return -EINVAL; + if (newrclk <= 0) { + tty3270_rcl_purge(tubp), + kfree(tubp->tty_rclbufs); + tubp->tty_rclbufs = NULL; + return 0; + } + if ((newrclb = (char *(*)[])kmalloc( + newrclk * sizeof (char *), GFP_KERNEL)) == NULL) + return -ENOMEM; + memset(newrclb, 0, newrclk * sizeof (char *)); + if (tubp->tty_rclbufs != NULL) { + int i, j, k; + char *data; + + i = tubp->tty_rclp; + j = newrclk; + k = tubp->tty_rclk; + while (j-- && k--) { + if ((data = (*tubp->tty_rclbufs)[i]) == NULL) + break; + (*newrclb)[j] = data; + (*tubp->tty_rclbufs)[i] = NULL; + if (--i < 0) + i = tubp->tty_rclk - 1; + } + tty3270_rcl_purge(tubp); + kfree(tubp->tty_rclbufs); + } + tubp->tty_rclbufs = newrclb; + tubp->tty_rclk = newrclk; + tubp->tty_rclp = newrclk - 1; + tty3270_rcl_sync(tubp); + return 0; +} + +int +tty3270_rcl_set(tub_t *tubp, char *buf, int count) +{ +#define RCL_SIZ "recallsize=" +#define L_RCL_SIZ (strlen(RCL_SIZ)) + int newsize; + int len; + int rc; + char *rcl_siz = RCL_SIZ; + int l_rcl_siz = L_RCL_SIZ; + + if (count < l_rcl_siz || strncmp(buf, rcl_siz, l_rcl_siz) != 0) + return 0; + if ((len = count - l_rcl_siz) == 0) + return count; + newsize = simple_strtoul(buf + l_rcl_siz, 0, 0); + rc = tty3270_rcl_resize(tubp, newsize); + return rc < 0? rc: count; +} + +void +tty3270_rcl_fini(tub_t *tubp) +{ + if (tubp->tty_rclbufs != NULL) { + tty3270_rcl_purge(tubp); + kfree(tubp->tty_rclbufs); + tubp->tty_rclbufs = NULL; + } +} + +void +tty3270_rcl_purge(tub_t *tubp) +{ + int i; + char *buf; + + if (tubp->tty_rclbufs == NULL) + return; + for (i = 0; i < tubp->tty_rclk; i++) { + if ((buf = (*tubp->tty_rclbufs)[i]) == NULL) + continue; + kfree(buf); + (*tubp->tty_rclbufs)[i] = NULL; + } +} + +int +tty3270_rcl_get(tub_t *tubp, char *buf, int len, int inc) +{ + int iter; + int i; + char *data; + + if (tubp->tty_rclbufs == NULL) + return 0; + if (tubp->tty_rclk <= 0) /* overcautious */ + return 0; + if (inc != 1 && inc != -1) /* overcautious */ + return 0; + + if ((i = tubp->tty_rclb) == -1) { + i = tubp->tty_rclp; + if (inc == 1) + i++; + } else { + i += inc; + } + for (iter = tubp->tty_rclk; iter; iter--, i += inc) { + if (i < 0) + i = tubp->tty_rclk - 1; + else if (i >= tubp->tty_rclk) + i = 0; + if ((*tubp->tty_rclbufs)[i] != NULL) + break; + } + if (iter < 0 || (data = (*tubp->tty_rclbufs)[i]) == NULL) + return 0; + tubp->tty_rclb = i; + if ((len = MIN(len - 1, strlen(data))) <= 0) + return 0; + memcpy(buf, data, len); + buf[len] = '\0'; + return len; +} + +void +tty3270_rcl_put(tub_t *tubp, char *data, int len) +{ + char *buf, **bufp; + int i; + + if (tubp->tty_rclbufs == NULL) + return; + + if (tubp->tty_rclk <= 0) /* overcautious */ + return; + + /* If input area is invisible, don't log */ + if (tubp->tty_inattr == TF_INPUTN) + return; + + /* If this & most recent cmd text match, don't log */ + if ((buf = (*tubp->tty_rclbufs)[tubp->tty_rclp]) != NULL && + strlen(buf) == len && memcmp(buf, data, len) == 0) { + tty3270_rcl_sync(tubp); + return; + } + + /* Don't stack zero-length commands */ + if (len == 0) { + tty3270_rcl_sync(tubp); + return; + } + + i = tubp->tty_rclp; + if (++i == tubp->tty_rclk) + i = 0; + bufp = &(*tubp->tty_rclbufs)[i]; + if (*bufp == NULL || strlen(*bufp) < len + 1) { + if (*bufp) { + kfree(*bufp); + *bufp = NULL; + } + if ((*bufp = kmalloc(len + 1, GFP_ATOMIC)) == NULL) + return; + } + memcpy(*bufp, data, len); + (*bufp)[len] = '\0'; + tubp->tty_rclp = i; + tty3270_rcl_sync(tubp); +} + +void +tty3270_rcl_sync(tub_t *tubp) +{ + tubp->tty_rclb = -1; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tubttyscl.c linux.ac/drivers/s390/char/tubttyscl.c --- linux.vanilla/drivers/s390/char/tubttyscl.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/s390/char/tubttyscl.c Thu Apr 12 12:03:49 2001 @@ -0,0 +1,88 @@ +/* + * IBM/3270 Driver -- Copyright (C) 2000, 2001 UTS Global LLC + * + * tubttyscl.c -- Linemode tty driver scroll-timing functions + * + * + * + * + * + * Author: Richard Hitt + */ +#include "tubio.h" + void tty3270_scl_settimer(tub_t *); + void tty3270_scl_resettimer(tub_t *); +static void tty3270_scl_timeout(unsigned long); + +void +tty3270_scl_settimer(tub_t *tubp) +{ + struct timer_list *tp = &tubp->tty_stimer; + + if (tubp->flags & TUB_SCROLLTIMING) + return; + if (tubp->tty_scrolltime == 0) + return; + + init_timer(tp); + tp->expires = jiffies + HZ * tubp->tty_scrolltime; + tp->data = (unsigned long)tubp; + tp->function = tty3270_scl_timeout; + add_timer(tp); + tubp->flags |= TUB_SCROLLTIMING; +} + +void +tty3270_scl_resettimer(tub_t *tubp) +{ + struct timer_list *tp = &tubp->tty_stimer; + + if ((tubp->flags & TUB_SCROLLTIMING) == 0) + return; + + del_timer(tp); + tubp->flags &= ~TUB_SCROLLTIMING; +} + +static void +tty3270_scl_timeout(unsigned long data) +{ + tub_t *tubp = (void *)data; + int flags; + + TUBLOCK(tubp->irq, flags); + tubp->stat = TBS_RUNNING; + tty3270_scl_resettimer(tubp); + tubp->cmd = TBC_CLRUPDLOG; + tty3270_build(tubp); + TUBUNLOCK(tubp->irq, flags); +} + +int +tty3270_scl_set(tub_t *tubp, char *buf, int count) +{ + if (strncmp(buf, "scrolltime=", 11) == 0) { + tubp->tty_scrolltime = + simple_strtoul(buf + 11, 0, 0); + return count; + } + return 0; +} + +int +tty3270_scl_init(tub_t *tubp) +{ + extern int tubscrollparm; + + tubp->tty_scrolltime = tubscrollparm; + if (tubp->tty_scrolltime < 0) + tubp->tty_scrolltime = DEFAULT_SCROLLTIME; + return 0; +} + +void +tty3270_scl_fini(tub_t *tubp) +{ + if ((tubp->flags & TUB_OPEN_STET) == 0) + tty3270_scl_resettimer(tubp); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/tubttysiz.c linux.ac/drivers/s390/char/tubttysiz.c --- linux.vanilla/drivers/s390/char/tubttysiz.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/s390/char/tubttysiz.c Thu Apr 12 12:03:49 2001 @@ -0,0 +1,304 @@ +/* + * IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC + * + * tubttysiz.c -- Linemode screen-size determiner + * + * + * + * + * + * Author: Richard Hitt + */ +#include "tubio.h" +static int tty3270_size_io(tub_t *tubp); +static void tty3270_size_int(tub_t *tubp, devstat_t *dsp); +static int tty3270_size_wait(tub_t *tubp, int *flags, int stat); + +/* + * Structure representing Usable Area Query Reply Base + */ +typedef struct { + short l; /* Length of this structured field */ + char sfid; /* 0x81 if Query Reply */ + char qcode; /* 0x81 if Usable Area */ +#define QCODE_UA 0x81 + char flags0; +#define FLAGS0_ADDR 0x0f +#define FLAGS0_ADDR_12_14 1 /* 12/14-bit adrs ok */ +#define FLAGS0_ADDR_12_14_16 3 /* 12/14/16-bit adrs ok */ + char flags1; + short w; /* Width of usable area */ + short h; /* Heigth of usavle area */ + char units; /* 0x00:in; 0x01:mm */ + int xr; + int yr; + char aw; + char ah; + short buffsz; /* Character buffer size, bytes */ + char xmin; + char ymin; + char xmax; + char ymax; +} __attribute__ ((packed)) uab_t; + +/* + * Structure representing Alternate Usable Area Self-Defining Parameter + */ +typedef struct { + char l; /* Length of this Self-Defining Parm */ + char sdpid; /* 0x02 if Alternate Usable Area */ +#define SDPID_AUA 0x02 + char res; + char auaid; /* 0x01 is Id for the A U A */ + short wauai; /* Width of AUAi */ + short hauai; /* Height of AUAi */ + char auaunits; /* 0x00:in, 0x01:mm */ + int auaxr; + int auayr; + char awauai; + char ahauai; +} __attribute__ ((packed)) aua_t; + +/* + * Structure representing one followed by the other + */ +typedef struct { + uab_t uab; + aua_t aua; +} __attribute__ ((packed)) ua_t; + +/* + * Try to determine screen size using Read Partition (Query) + */ +int +tty3270_size(tub_t *tubp, int *flags) +{ + char wbuf[7] = { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 }; + int rc = 0; + int count; + unsigned char *cp; + ua_t *uap; + char miniscreen[256]; + char (*screen)[]; + int screenl; + int geom_rows, geom_cols, fourteenbitadr; + void (*oldint)(struct tub_s *, devstat_t *); + + if (tubp->flags & TUB_SIZED) + return 0; + fourteenbitadr = 0; + geom_rows = tubp->geom_rows; + geom_cols = tubp->geom_cols; + + oldint = tubp->intv; + tubp->intv = tty3270_size_int; + + if (tubp->cmd == TBC_CONOPEN) { + tubp->ttyccw.cmd_code = TC_EWRITEA; + cp = miniscreen; + *cp++ = TW_KR; + /* more? */ + tubp->ttyccw.flags = CCW_FLAG_SLI; + tubp->ttyccw.cda = virt_to_phys(miniscreen); + tubp->ttyccw.count = (char *)cp - miniscreen; + rc = tty3270_size_io(tubp); + rc = tty3270_size_wait(tubp, flags, 0); + } + + tubp->ttyccw.cmd_code = TC_WRITESF; + tubp->ttyccw.flags = CCW_FLAG_SLI; + tubp->ttyccw.cda = virt_to_phys(wbuf); + tubp->ttyccw.count = sizeof wbuf; + +try_again: + rc = tty3270_size_io(tubp); + if (rc) + printk("tty3270_size_io returned %d\n", rc); + + rc = tty3270_size_wait(tubp, flags, 0); + if (rc != 0) { + goto do_return; + } + + /* + * Unit-Check Processing: + * Expect Command Reject or Intervention Required. + * For Command Reject assume old hdwe/software and + * set a default size of 80x24. + * For Intervention Required, wait for signal pending + * or Unsolicited Device End; if the latter, retry. + */ + if (tubp->dstat & DEV_STAT_UNIT_CHECK) { + if (tubp->sense.data[0] & SNS0_CMD_REJECT) { + goto use_diag210; /* perhaps it's tn3270 */ + } else if (tubp->sense.data[0] & SNS0_INTERVENTION_REQ) { + if ((rc = tty3270_size_wait(tubp, flags, + DEV_STAT_DEV_END))) + goto do_return; + goto try_again; + } else { + printk("tty3270_size(): unkn sense %.2x\n", + tubp->sense.data[0]); + goto do_return; + } + } + if ((rc = tty3270_size_wait(tubp, flags, DEV_STAT_ATTENTION))) + goto do_return; + + /* Set up a read ccw and issue it */ + tubp->ttyccw.cmd_code = TC_READMOD; + tubp->ttyccw.flags = CCW_FLAG_SLI; + tubp->ttyccw.cda = virt_to_phys(miniscreen); + tubp->ttyccw.count = sizeof miniscreen; + tty3270_size_io(tubp); + rc = tty3270_size_wait(tubp, flags, 0); + if (rc != 0) + goto do_return; + + count = sizeof miniscreen - tubp->cswl; + cp = miniscreen; + if (*cp++ != 0x88) + goto do_return; + uap = (void *)cp; + if (uap->uab.qcode != QCODE_UA) + goto do_return; + geom_rows = uap->uab.h; + geom_cols = uap->uab.w; + if ((uap->uab.flags0 & FLAGS0_ADDR) == FLAGS0_ADDR_12_14 || + (uap->uab.flags0 & FLAGS0_ADDR) == FLAGS0_ADDR_12_14_16) + fourteenbitadr = 1; + if (uap->uab.l <= sizeof uap->uab) + goto do_return; + if (uap->aua.sdpid != SDPID_AUA) { + printk("AUA sdpid was 0x%.2x, expecting 0x%.2x\n", + uap->aua.sdpid, SDPID_AUA); + goto do_return; + } + geom_rows = uap->aua.hauai; + geom_cols = uap->aua.wauai; + goto do_return; + +use_diag210: + if (MACHINE_IS_VM) { + diag210_t d210; + + d210.vrdcdvno = tubp->devno; + d210.vrdclen = sizeof d210; + rc = diag210(&d210); + if (rc) { + printk("tty3270_size: diag210 for 0x%.4x " + "returned %d\n", tubp->devno, rc); + goto do_return; + } + switch(d210.vrdccrmd) { + case 2: + geom_rows = 24; + geom_cols = 80; + goto do_return; + case 3: + geom_rows = 32; + geom_cols = 80; + goto do_return; + case 4: + geom_rows = 43; + geom_cols = 80; + goto do_return; + case 5: + geom_rows = 27; + geom_cols = 132; + goto do_return; + default: + printk("vrdccrmd is 0x%.8x\n", d210.vrdccrmd); + } + } + +do_return: + if (geom_rows == 0) { + geom_rows = _GEOM_ROWS; + geom_cols = _GEOM_COLS; + } + tubp->tubiocb.pf_cnt = 24; + tubp->tubiocb.re_cnt = 20; + tubp->tubiocb.map = 0; + + screenl = geom_rows * geom_cols + 100; + screen = (char (*)[])kmalloc(screenl, GFP_KERNEL); + if (screen == NULL) { + printk("ttyscreen size %d unavailable\n", screenl); + } else { + if (tubp->ttyscreen) + kfree(tubp->ttyscreen); + tubp->tubiocb.line_cnt = tubp->geom_rows = geom_rows; + tubp->tubiocb.col_cnt = tubp->geom_cols = geom_cols; + tubp->tty_14bitadr = fourteenbitadr; + tubp->ttyscreen = screen; + tubp->ttyscreenl = screenl; + if (geom_rows == 24 && geom_cols == 80) + tubp->tubiocb.model = 2; + else if (geom_rows == 32 && geom_cols == 80) + tubp->tubiocb.model = 3; + else if (geom_rows == 43 && geom_cols == 80) + tubp->tubiocb.model = 4; + else if (geom_rows == 27 && geom_cols == 132) + tubp->tubiocb.model = 5; + else + tubp->tubiocb.model = 0; + tubp->flags |= TUB_SIZED; + } + if (rc == 0 && tubp->ttyscreen == NULL) + rc = -ENOMEM; + tubp->intv = oldint; + return rc; +} + +static int +tty3270_size_io(tub_t *tubp) +{ + tubp->flags |= TUB_WORKING; + tubp->dstat = 0; + + return do_IO(tubp->irq, &tubp->ttyccw, tubp->irq, 0, 0); +} + +static void +tty3270_size_int(tub_t *tubp, devstat_t *dsp) +{ +#define DEV_NOT_WORKING \ + (DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_CHECK) + + tubp->dstat = dsp->dstat; + if (dsp->dstat & DEV_STAT_CHN_END) + tubp->cswl = dsp->rescnt; + if (dsp->dstat & DEV_NOT_WORKING) + tubp->flags &= ~TUB_WORKING; + if (dsp->dstat & DEV_STAT_UNIT_CHECK) + tubp->sense = dsp->ii.sense; + + wake_up_interruptible(&tubp->waitq); +} + +/* + * Wait for something. If the third arg is zero, wait until + * tty3270_size_int() turns off TUB_WORKING. If the third arg + * is not zero, it is a device-status bit; wait until dstat + * has the bit turned on. Never wait if signal is pending. + * Return 0 unless signal pending, in which case -ERESTARTSYS. + */ +static int +tty3270_size_wait(tub_t *tubp, int *flags, int stat) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&tubp->waitq, &wait); + while (!signal_pending(current) && + (stat? (tubp->dstat & stat) == 0: + (tubp->flags & TUB_WORKING) != 0)) { + current->state = TASK_INTERRUPTIBLE; + TUBUNLOCK(tubp->irq, *flags); + schedule(); + current->state = TASK_RUNNING; + TUBLOCK(tubp->irq, *flags); + } + remove_wait_queue(&tubp->waitq, &wait); + return signal_pending(current)? -ERESTARTSYS: 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/idals.c linux.ac/drivers/s390/idals.c --- linux.vanilla/drivers/s390/idals.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/idals.c Thu Apr 12 12:03:49 2001 @@ -9,6 +9,7 @@ * 12/13/00 changed IDALs to 4kByte-IDALs */ +#include <linux/module.h> #include <linux/config.h> #include <linux/malloc.h> @@ -16,6 +17,8 @@ #include <asm/idals.h> #ifdef CONFIG_ARCH_S390X +#define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */ +#define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG) void set_normalized_cda ( ccw1_t * cp, unsigned long address ) { @@ -25,11 +28,12 @@ if (cp->flags & CCW_FLAG_IDA) BUG(); - if (((address + count) >> 31) == 0) { /* do we really need '+count'? */ + if (((address + count) >> 31) == 0) { cp -> cda = address; return; } - nridaws = ((address & 4095L) + count + 4095L) >> 12; + nridaws = ((address & (IDA_BLOCK_SIZE-1)) + count + + (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG; idal = idal_alloc(nridaws); if ( idal == NULL ) { /* probably we should have a fallback here */ @@ -39,9 +43,12 @@ cp->cda = (__u32)(unsigned long)(idaw_t *)idal; do { *idal++ = address; - address = (address & -4096L) + 4096; + address = (address & -(IDA_BLOCK_SIZE)) + (IDA_BLOCK_SIZE); nridaws --; } while ( nridaws > 0 ); return; } + +EXPORT_SYMBOL (set_normalized_cda); + #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/misc/Makefile linux.ac/drivers/s390/misc/Makefile --- linux.vanilla/drivers/s390/misc/Makefile Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/misc/Makefile Thu Apr 12 12:03:49 2001 @@ -1,9 +1,10 @@ -all: s390-misc.o +# +# S/390 miscellaneous devices +# -CFLAFS += O_TARGET := s390-misc.o obj-$(CONFIG_CHANDEV) += chandev.o +export-objs += chandev.o include $(TOPDIR)/Rules.make - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/misc/chandev.c linux.ac/drivers/s390/misc/chandev.c --- linux.vanilla/drivers/s390/misc/chandev.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/misc/chandev.c Thu Apr 12 12:03:49 2001 @@ -6,7 +6,10 @@ * * Generic channel device initialisation support. */ +#define TRUE 1 +#define FALSE 0 #define __KERNEL_SYSCALLS__ +#include <linux/module.h> #include <linux/config.h> #include <linux/types.h> #include <linux/ctype.h> @@ -20,6 +23,7 @@ #include <linux/vmalloc.h> #include <asm/s390dyn.h> #include <asm/queue.h> +#include <linux/kmod.h> typedef struct chandev_model_info chandev_model_info; struct chandev_model_info @@ -229,6 +233,7 @@ static long chandev_lock_owner; static int chandev_lock_cnt; static spinlock_t chandev_spinlock; +void *chandev_firstlock_addr,*chandev_lastlock_addr; typedef struct chandev_not_oper_struct chandev_not_oper_struct; @@ -256,24 +261,6 @@ for((variable)=(head);(variable)!=NULL;(variable)=(variable)->next) -#define CHANDEV_USE_KERNEL_THREADS (LINUX_VERSION_CODE<KERNEL_VERSION(2,4,0)) - -#if CHANDEV_USE_KERNEL_THREADS -static void chandev_start_msck_thread(void *unused); -#if LINUX_VERSION_CODE<KERNEL_VERSION(2,3,0) -#define chandev_daemonize(name,mask,use_init_fs) s390_daemonize(name,mask) -#else -#define chandev_daemonize(args...) s390_daemonize(args) -#endif -typedef int chandev_task_retval; -#define chandev_task_return(val) return(val) -#else -#define chandev_daemonize(noargs...) -#define chandev_task_retval void -#define chandev_task_return(val) return -#endif - - static void chandev_lock(void) { chandev_interrupt_check(); @@ -283,18 +270,33 @@ spin_lock(&chandev_spinlock); chandev_lock_cnt=1; chandev_lock_owner=(long)current; + chandev_firstlock_addr=__builtin_return_address(0); } else + { chandev_lock_cnt++; + chandev_lastlock_addr=__builtin_return_address(0); + } if(chandev_lock_cnt<0||chandev_lock_cnt>100) - panic("odd lock_cnt in lcs %d lcs_chan_lock",chandev_lock_cnt); + { + printk("odd lock_cnt %d lcs_chan_lock",chandev_lock_cnt); + chandev_lock_cnt=1; + } } +static int chandev_full_unlock(void) +{ + int ret_lock_cnt=chandev_lock_cnt; + chandev_lock_cnt=0; + chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER; + spin_unlock(&chandev_spinlock); + return(ret_lock_cnt); +} static void chandev_unlock(void) { if(chandev_lock_owner!=(long)current) - panic("chandev_unlock: current=%lx" + printk("chandev_unlock: current=%lx" " chandev_lock_owner=%lx chandev_lock_cnt=%d\n", (long)current, chandev_lock_owner, @@ -305,19 +307,20 @@ spin_unlock(&chandev_spinlock); } if(chandev_lock_cnt<0) - panic("odd lock_cnt in lcs %d lcs_chan_unlock",chandev_lock_cnt); -} + { + printk("odd lock_cnt=%d in chan_unlock",chandev_lock_cnt); + chandev_full_unlock(); + } -int chandev_full_unlock(void) -{ - int ret_lock_cnt=chandev_lock_cnt; - chandev_lock_cnt=0; - chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER; - spin_unlock(&chandev_spinlock); - return(ret_lock_cnt); } +void chandev_relock(int saved_lock_cnt) +{ + + chandev_lock(); + chandev_lock_cnt=saved_lock_cnt; +} void *chandev_alloc(size_t size) @@ -405,145 +408,8 @@ } -struct files_struct *chandev_new_files_struct(void) -{ - struct files_struct *newf = kmem_cache_alloc(files_cachep, SLAB_KERNEL); - if (!newf) - return(NULL); - memset(newf,0,sizeof(struct files_struct)); - atomic_set(&newf->count, 1); - newf->file_lock = RW_LOCK_UNLOCKED; - newf->next_fd = 0; - newf->max_fds = NR_OPEN_DEFAULT; - newf->max_fdset = __FD_SETSIZE; - newf->close_on_exec = &newf->close_on_exec_init; - newf->open_fds = &newf->open_fds_init; - newf->fd = &newf->fd_array[0]; - return(newf); -} -/* - * Mostly robbed from kmod.c - */ -static inline void -use_init_fs_context(void) -{ - struct fs_struct *our_fs, *init_fs; - struct dentry *root, *pwd; - struct vfsmount *rootmnt, *pwdmnt; - - /* - * Make modprobe's fs context be a copy of init's. - * - * We cannot use the user's fs context, because it - * may have a different root than init. - * Since init was created with CLONE_FS, we can grab - * its fs context from "init_task". - * - * The fs context has to be a copy. If it is shared - * with init, then any chdir() call in modprobe will - * also affect init and the other threads sharing - * init_task's fs context. - * - * We created the exec_modprobe thread without CLONE_FS, - * so we can update the fields in our fs context freely. - */ - - init_fs = init_task.fs; - read_lock(&init_fs->lock); - rootmnt = mntget(init_fs->rootmnt); - root = dget(init_fs->root); - pwdmnt = mntget(init_fs->pwdmnt); - pwd = dget(init_fs->pwd); - read_unlock(&init_fs->lock); - - /* FIXME - unsafe ->fs access */ - our_fs = current->fs; - our_fs->umask = init_fs->umask; - set_fs_root(our_fs, rootmnt, root); - set_fs_pwd(our_fs, pwdmnt, pwd); - write_lock(&our_fs->lock); - if (our_fs->altroot) { - struct vfsmount *mnt = our_fs->altrootmnt; - struct dentry *dentry = our_fs->altroot; - our_fs->altrootmnt = NULL; - our_fs->altroot = NULL; - write_unlock(&our_fs->lock); - dput(dentry); - mntput(mnt); - } else - write_unlock(&our_fs->lock); - dput(root); - mntput(rootmnt); - dput(pwd); - mntput(pwdmnt); -} - - -static int exec_usermodehelper(char *program_path, char *argv[], char *envp[]) -{ - int err; - wait_queue_head_t wait; - - - current->session = 1; - current->pgrp = 1; - - /* We copy this off init & can't go until this is set up */ - init_waitqueue_head(&wait); - while(init_task.fs->root==NULL) - { - sleep_on_timeout(&wait,HZ); - } - use_init_fs_context(); - - /* Prevent parent user process from sending signals to child. - Otherwise, if the modprobe program does not exist, it might - be possible to get a user defined signal handler to execute - as the super user right after the execve fails if you time - the signal just right. - */ - spin_lock_irq(¤t->sigmask_lock); - flush_signals(current); - flush_signal_handlers(current); - spin_unlock_irq(¤t->sigmask_lock); - /* current->files sometimes was null this means we need */ - /* to build our own */ - exit_files(current); - if((current->files=chandev_new_files_struct())==NULL) - { - printk("chandev_new_files_struct allocation failed\n"); - return(0); - } - - /* Drop the "current user" thing */ - { - struct user_struct *user = current->user; - current->user = INIT_USER; - atomic_inc(&INIT_USER->__count); - atomic_inc(&INIT_USER->processes); - atomic_dec(&user->processes); - free_uid(user); - } - - /* Take all effective privileges.. */ - current->uid = current->euid = current->fsuid = 0; - cap_set_full(current->cap_effective); - /* Allow execve & open args to be in kernel space. */ - set_fs(KERNEL_DS); - /* We need stdin out & err for scripts */ - if (open("/dev/console", O_RDWR, 0)< 0) - printk("chandev exec_usermode_helper unable to open an initial console.\n"); - (void) dup(0); - (void) dup(0); - - - /* Go, go, go... */ - err=execve(program_path, argv, envp); - return err; -} - -static int exec_start_script(void *unused) +static int chandev_exec_start_script(void *unused) { char **argv,*tempname; @@ -555,7 +421,8 @@ static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; init_waitqueue_head(&wait); - s390_daemonize("chandev_script",0,FALSE); + strcpy(current->comm,"chandev_script"); + for(loopcnt=0;loopcnt<10&&(jiffies-chandev_last_startmsck_list_update)<HZ;loopcnt++) { sleep_on_timeout(&wait,HZ); @@ -612,6 +479,12 @@ chandev_free_all_list((list **)&startlist_head); chandev_free_all_list((list **)&mscklist_head); chandev_unlock(); + + /* We need to wait till there is a root filesystem */ + while(init_task.fs->root==NULL) + { + sleep_on_timeout(&wait,HZ); + } /* We are basically execve'ing here there normally is no */ /* return */ retval=exec_usermodehelper(exec_script, argv, envp); @@ -623,7 +496,7 @@ Fail2: /* We don't really need to report /bin/chandev not existing */ if(retval!=-ENOENT) - printk("exec_start_script failed retval=%d\n",retval); + printk("chandev_exec_start_script failed retval=%d\n",retval); return(0); } @@ -643,7 +516,6 @@ static int chandev_add_to_startmsck_list(chandev_startmsck_list **listhead,char *devname, chandev_msck_status pre_recovery_action_status,chandev_msck_status post_recovery_action_status) { - int retval; chandev_startmsck_list *member; int pid; @@ -664,14 +536,11 @@ add_to_list((list **)listhead,(list *)member); chandev_last_startmsck_list_update=jiffies; chandev_unlock(); - /* We do CLONE_FILES so we can exit_files to get rid of it */ - /* cheaply & allocate a new one we need current->files & */ - /* some tasks have current->files==NULL */ - pid = kernel_thread(exec_start_script,NULL,CLONE_FILES|SIGCHLD); + pid = kernel_thread(chandev_exec_start_script,NULL,SIGCHLD); if(pid<0) { - printk("error making kernel thread for exec_start_script\n"); - retval=pid; + printk("error making kernel thread for chandev_exec_start_script\n"); + return(pid); } else return(0); @@ -679,11 +548,10 @@ } else { + chandev_unlock(); printk("chandev_add_to_startmscklist memory allocation failed devname=%s\n",devname); - retval=-ENOMEM; + return(-ENOMEM); } - chandev_unlock(); - return(retval); } @@ -695,11 +563,7 @@ chandev_last_machine_check=jiffies; if(atomic_dec_and_test(&chandev_msck_thread_lock)) { -#if CHANDEV_USE_KERNEL_THREADS - queue_task(&chandev_msck_task_tq,&tq_scheduler); -#else schedule_task(&chandev_msck_task_tq); -#endif } atomic_set(&chandev_new_msck,TRUE); return(0); @@ -719,11 +583,7 @@ spin_unlock(&chandev_not_oper_spinlock); if(atomic_dec_and_test(&chandev_msck_thread_lock)) { -#if CHANDEV_USE_KERNEL_THREADS - queue_task(&chandev_msck_task_tq,&tq_scheduler); -#else schedule_task(&chandev_msck_task_tq); -#endif } } else @@ -767,6 +627,18 @@ } +void chandev_remove_irqinfo_by_irq(unsigned int irq) +{ + chandev_irqinfo *remove_irqinfo; + + chandev_lock(); + /* remove any orphan irqinfo left lying around. */ + if((remove_irqinfo=chandev_get_irqinfo_by_irq(irq))) + chandev_remove_from_list((list **)&chandev_irqinfo_head, + (list *)remove_irqinfo); + chandev_unlock(); + +} int chandev_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), @@ -790,9 +662,7 @@ return(-EPERM); } /* remove any orphan irqinfo left lying around. */ - if((new_irqinfo=chandev_get_irqinfo_by_irq(irq))) - chandev_remove_from_list((list **)chandev_irqinfo_head, - (list *)new_irqinfo); + chandev_remove_irqinfo_by_irq(irq); chandev_unlock(); if((new_irqinfo=chandev_allocstr(devname,offsetof(chandev_irqinfo,devname)))) { @@ -819,6 +689,12 @@ return(retval); } +void chandev_free_irq(unsigned int irq, void *dev_id) +{ + /* remove any orphan irqinfo left lying around. */ + chandev_remove_irqinfo_by_irq(irq); + free_irq(irq,dev_id); +} void chandev_sprint_type_model(char *buff,s32 type,s16 model) @@ -1148,6 +1024,7 @@ void chandev_shutdown(chandev_activelist *curr_device) { + int saved_lock_cnt; chandev_lock(); if(curr_device->category==network_device) @@ -1155,12 +1032,16 @@ /* unregister_netdev calls the dev->close so we shouldn't do this */ /* this otherwise we crash */ if(curr_device->unreg_dev) - curr_device->unreg_dev(curr_device->dev_ptr); + { + saved_lock_cnt=chandev_full_unlock(); + curr_device->unreg_dev(curr_device->dev_ptr); + chandev_relock(saved_lock_cnt); + } } + saved_lock_cnt=chandev_full_unlock(); curr_device->shutdownfunc(curr_device->dev_ptr); + chandev_relock(saved_lock_cnt); kfree(curr_device->dev_ptr); - chandev_free_listmember((list **)&chandev_irqinfo_head,(list *)curr_device->read_irqinfo); - chandev_free_listmember((list **)&chandev_irqinfo_head,(list *)curr_device->write_irqinfo); chandev_free_listmember((list **)&chandev_activelist_head, (list *)curr_device); chandev_unlock(); @@ -1492,8 +1373,7 @@ /* as probefunctions can call schedule & */ /* reenter to do a kernel thread & we may deadlock */ rc=probefunc(&probeinfo); - chandev_lock(); - chandev_lock_cnt=saved_lock_cnt; + chandev_relock(saved_lock_cnt); if(rc==0) { newdevice=probeinfo.newdevice; @@ -1619,9 +1499,13 @@ if(curr_irqinfo->msck_status==good&&prevstatus!=good) { if(curr_device->reoperfunc) + { + int saved_lock_cnt=chandev_full_unlock(); curr_device->reoperfunc(curr_device->dev_ptr, (curr_device->read_irqinfo==curr_irqinfo), prevstatus); + chandev_relock(saved_lock_cnt); + } if(curr_device->category==network_device&& curr_device->write_irqinfo==curr_irqinfo) { @@ -1743,13 +1627,12 @@ } -static chandev_task_retval chandev_msck_task(void *unused) +static void chandev_msck_task(void *unused) { int loopcnt,not_oper_probe_required=FALSE; wait_queue_head_t wait; chandev_not_oper_struct *new_not_oper; - chandev_daemonize("chandev_msck_kernel_thread",0,TRUE); /* This loop exists because machine checks tend to come in groups & we have to wait for the other devnos to appear also */ init_waitqueue_head(&wait); @@ -1780,21 +1663,10 @@ } if(not_oper_probe_required) chandev_probe(); - chandev_task_return(0); } -#if CHANDEV_USE_KERNEL_THREADS -static void chandev_start_msck_thread(void *unused) -{ - /* tq_scheduler sometimes leaves interrupts disabled from do bottom half */ - __sti(); - kernel_thread((int (*)(void *))chandev_msck_task, - (void*)NULL,0); -} -#endif - static char *argstrs[]= @@ -1953,6 +1825,7 @@ chandev_type chan_type; char *str,*currstr,*interpretstr=NULL; int cnt,strcnt; + int retval=0; #define CHANDEV_MAX_EXTRA_INTS 8 chandev_int ints[CHANDEV_MAX_EXTRA_INTS+1]; memset(ints,0,sizeof(ints)); @@ -2182,17 +2055,29 @@ else goto BadArgs; } - return(1); + retval=1; BadArgs: - printk("chandev_setup bad argument %s",instr); - if(errstr) + if(!retval) { - printk("%s %d interpreted as %s",errstr,lineno,interpretstr); - if(strcnt>1) - printk(" before semicolon no %d",cnt); + printk("chandev_setup bad argument %s",instr); + if(errstr) + { + printk("%s %d interpreted as %s",errstr,lineno,interpretstr); + if(strcnt>1) + printk(" before semicolon no %d",cnt); + } + printk(".\n Type man chandev for more info.\n\n"); } - printk(".\n Type man chandev for more info.\n\n"); - return(0); + eieio(); + if(chandev_lock_owner==(long)current) + { + printk("chandev_setup bug chandev_lock_cnt=%d lock_owner=%lx\n" + "firstlock_retaddr=%p last_lock_returnaddr=%p\n", + chandev_lock_cnt,chandev_lock_owner,chandev_firstlock_addr, + chandev_lastlock_addr); + chandev_full_unlock(); + } + return(retval); } #define CHANDEV_KEYWORD "chandev=" static int chandev_setup_bootargs(char *str,int paramno) @@ -2608,11 +2493,7 @@ chandev_create_proc(); #endif chandev_msck_task_tq.routine= -#if CHANDEV_USE_KERNEL_THREADS - chandev_start_msck_thread; -#else chandev_msck_task; -#endif #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0) INIT_LIST_HEAD(&chandev_msck_task_tq.list); chandev_msck_task_tq.sync=0; @@ -2684,4 +2565,13 @@ } chandev_unlock(); } + +EXPORT_SYMBOL(chandev_register_and_probe); +EXPORT_SYMBOL(chandev_request_irq); +EXPORT_SYMBOL(chandev_free_irq); +EXPORT_SYMBOL(chandev_unregister); +EXPORT_SYMBOL(chandev_initdevice); +EXPORT_SYMBOL(chandev_initnetdevice); + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/net/Makefile linux.ac/drivers/s390/net/Makefile --- linux.vanilla/drivers/s390/net/Makefile Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/net/Makefile Thu Apr 12 12:03:49 2001 @@ -1,20 +1,20 @@ -all: s390-net.o +# +# S/390 network devices +# -CFLAGS += O_TARGET := s390-net.o -obj-y := iucv.o +list-multi := ctc.o +export-objs := iucv.o -ifeq ($(CONFIG_CTC),y) - obj-y += ctcmain.o fsm.o -else - ifeq ($(CONFIG_CTC),m) - obj-m += ctc.o -ctc.o: ctcmain.o fsm.o - $(LD) -r ctcmain.o fsm.o -o $@ - endif -endif +ctc-objs := ctcmain.o ctctty.o fsm.o -obj-$(CONFIG_IUCV) += iucv.o netiucv.o +obj-y += iucv.o +obj-$(CONFIG_CTC) += ctc.o +obj-$(CONFIG_IUCV) += netiucv.o include $(TOPDIR)/Rules.make + +ctc.o: $(ctc-objs) + $(LD) -r -o $@ $(ctc-objs) + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/net/ctc.c linux.ac/drivers/s390/net/ctc.c --- linux.vanilla/drivers/s390/net/ctc.c Tue Apr 3 17:32:17 2001 +++ linux.ac/drivers/s390/net/ctc.c Thu Jan 1 01:00:00 1970 @@ -1,1582 +0,0 @@ -/* - * drivers/s390/net/ctc.c - * CTC / ESCON network driver - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * 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) - * - * - * Description of the Kernel Parameter - * Normally the CTC driver selects the channels in order (automatic channel - * selection). If your installation needs to use the channels in a different - * 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 - * - * 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). - * - * 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 - * - * 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 supperssed - 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 - */ -#include <linux/version.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/timer.h> -#include <linux/sched.h> - -#include <linux/signal.h> -#include <linux/string.h> - -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ip.h> -#include <linux/if_arp.h> -#include <linux/tcp.h> -#include <linux/skbuff.h> - -#include <asm/io.h> -#include <asm/bitops.h> - -#include <asm/irq.h> - - -//#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 -//#undef DEBUG - -#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 */ - -/* 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 - - -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_t; - - - -/* - * Structures needed in the initial phase - * - */ - -/* long req'd by set_bit --RR */ -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 */ -}; - -static struct { - struct devicelist list[MAX_CHANNEL_DEVICES]; - int count; - int left; -} channel[CHANNEL_MEDIA]; - - - -static int ctc_no_auto = 0; - -struct adapterlist{ - unsigned int devno[2]; - __u16 protocol; -}; - -static struct adapterlist ctc_adapter[CHANNEL_MEDIA][MAX_ADAPTERS]; /* 0 = CTC / 1 = ESCON */ - - -/* - * Structure used after the initial phase - * - */ - -struct buffer { - 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 */ - 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 ctc_priv { - struct net_device_stats stats; -#if LINUX_VERSION_CODE>=0x02032D - int tbusy; -#endif - struct channel channel[2]; - __u16 protocol; -}; - -/* - * This structure works as shuttle between two systems - * - A block can contain one or more packets - */ - -#define PACKET_HEADER_LENGTH 6 -struct packet { - __u16 length; - __u16 type; - __u16 unused; - __u8 data; -}; - -#define BLOCK_HEADER_LENGTH 2 -struct block { - __u16 length; - struct packet data; -}; - -#if LINUX_VERSION_CODE>=0x02032D -#define ctc_protect_busy(dev) \ -s390irq_spin_lock(((struct ctc_priv *)dev->priv)->channel[WRITE].irq) -#define ctc_unprotect_busy(dev) \ -s390irq_spin_unlock(((struct ctc_priv *)dev->priv)->channel[WRITE].irq) - -#define ctc_protect_busy_irqsave(dev,flags) \ -s390irq_spin_lock_irqsave(((struct ctc_priv *)dev->priv)->channel[WRITE].irq,flags) -#define ctc_unprotect_busy_irqrestore(dev,flags) \ -s390irq_spin_unlock_irqrestore(((struct ctc_priv *)dev->priv)->channel[WRITE].irq,flags) - -static __inline__ void ctc_set_busy(net_device *dev) -{ - ((struct ctc_priv *)dev->priv)->tbusy=1; - netif_stop_queue(dev); -} - -static __inline__ void ctc_clear_busy(net_device *dev) -{ - ((struct ctc_priv *)dev->priv)->tbusy=0; - netif_start_queue(dev); -} - -static __inline__ int ctc_check_busy(net_device *dev) -{ - eieio(); - return(((struct ctc_priv *)dev->priv)->tbusy); -} - - -static __inline__ void ctc_setbit_busy(int nr,net_device *dev) -{ - set_bit(nr,&(((struct ctc_priv *)dev->priv)->tbusy)); - netif_stop_queue(dev); -} - -static __inline__ void ctc_clearbit_busy(int nr,net_device *dev) -{ - clear_bit(nr,&(((struct ctc_priv *)dev->priv)->tbusy)); - if(((struct ctc_priv *)dev->priv)->tbusy==0) - netif_start_queue(dev); -} - -static __inline__ int ctc_test_and_setbit_busy(int nr,net_device *dev) -{ - netif_stop_queue(dev); - return(test_and_set_bit(nr,&((struct ctc_priv *)dev->priv)->tbusy)); -} -#else - -#define ctc_protect_busy(dev) -#define ctc_unprotect_busy(dev) -#define ctc_protect_busy_irqsave(dev,flags) -#define ctc_unprotect_busy_irqrestore(dev,flags) - -static __inline__ void ctc_set_busy(net_device *dev) -{ - dev->tbusy=1; - eieio(); -} - -static __inline__ void ctc_clear_busy(net_device *dev) -{ - dev->tbusy=0; - eieio(); -} - -static __inline__ int ctc_check_busy(net_device *dev) -{ - eieio(); - return(dev->tbusy); -} - - -static __inline__ void ctc_setbit_busy(int nr,net_device *dev) -{ - set_bit(nr,(void *)&dev->tbusy); -} - -static __inline__ void ctc_clearbit_busy(int nr,net_device *dev) -{ - clear_bit(nr,(void *)&dev->tbusy); -} - -static __inline__ int ctc_test_and_setbit_busy(int nr,net_device *dev) -{ - return(test_and_set_bit(nr,(void *)&dev->tbusy)); -} -#endif - - - - - -/* 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); - - -/* Functions for the DEV methods */ -int ctc_probe(net_device *dev); - - -static int ctc_open(net_device *dev); -static void ctc_timer (struct channel *ctc); -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); -struct net_device_stats* ctc_stats(net_device *dev); - - -/* - * Channel Routines - * - */ - -static void channel_init(void); -static void channel_scan(void); -static int channel_get(int media, int devno); -static int channel_get_next(int media); -static int channel_free(int media, int devno); -static channel_type_t channel_check_for_type (senseid_t *id); -static void channel_sort(struct devicelist list[], int n); - - -/* - * initialize the channel[].list - */ -static void channel_init(void) -{ - int m; -#ifdef DEBUG - 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); -#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); - } - } -#endif - } -} - - -/* -* scan for all channels and put the device numbers into the channel[].list -*/ -static void channel_scan(void) -{ - int m; - int c; - int irq; - s390_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++; - - } - } - } -} - - -/* - * free specific channel from the channel[].list - */ -static int channel_free(int media, int devno) -{ - 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; -} - - -/* - * get specific channel from the channel[].list - */ -static int channel_get(int media, int devno) -{ - 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; - -} - - -/* - * get the next free channel from the channel[].list - */ -static int channel_get_next(int media) -{ - int i; - - 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); -#endif - channel[media].list[i].flag |= CHANNEL_IN_USE; - return channel[media].list[i].devno; - } - } - return -ENODEV; -} - - -/* - * picks the next free channel from the channel[].list - */ -static int channel_left(int media) -{ - return channel[media].left; -} - - -/* - * defines all devices which are channels - */ -static channel_type_t channel_check_for_type (senseid_t *id) - { - channel_type_t type; - - 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; - - 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; - - } - return type; -} - - -/* - * sort the channel[].list - */ -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; - } - } - } -} - - -/* - * General routines - * - */ - -static int inline extract_channel_id(char *name) -{ - if (name[0] == 'c') - return (name[3]-'0'); - else - return (name[5]-'0'); -} - - -static int inline extract_channel_media(char *name) -{ - 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; - } -} - - -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; - } - } - - 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; - - - 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; -} - - -static int inline ctc_buffer_swap(struct buffer **from, struct buffer **to) { - - 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; -} - - -/* - * 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 - */ -#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; -#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 -#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; - -} -#if LINUX_VERSION_CODE>=0x020300 -__setup("ctc=", ctc_setup); -#endif - -/* - * ctc_probe - * 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; - - return 0; -} - - -/* - * Interrupt processing - * - */ - -static void inline ccw_check_return_code (net_device *dev, int return_code) -{ - 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); - } - } -} - - -static void inline ccw_check_unit_check (net_device *dev, char sense) -{ -#ifdef DEBUG - printk(KERN_INFO "%s: Unit Check with sense code: %02x\n", - dev->name, sense); -#endif - - 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 occurred (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); - } - -} - - -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}}; - - devstat_t *devstat = ((devstat_t *)initparm); - - /* Bypass all 'unsolited interrupts' */ - if (devstat->intparm == 0) { -#ifdef DEBUG - printk(KERN_DEBUG "ctc: unsolited interrupt for device: %04x received c-%02x d-%02x f-%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; - -#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); -#endif - - /* Check for good subchannel return code, otherwise error message */ - if (devstat->cstat) { - printk(KERN_WARNING "%s: subchannel check for device: %04x - %02x\n", - dev->name, ctc->devno, devstat->cstat); - 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]); - - - /* State machine to bring the connection up / down and to restart */ - - ctc->last_dstat = devstat->dstat; - - 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_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_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_SELECT: - if (!ctc->flag & CTC_WRITE) { - ctc->state = CTC_START_READ_TEST; - 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->ccw[1].count = 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); - } - 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); -#ifdef DEBUG - 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++; - /* 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_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; - } - - 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); - - if (ctc->free_anchor != NULL) { - 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: - 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; - } - } - - clear_bit(0, (void *)&ctc->IO_active); /* set by ctc_tx or ctc_bh */ - return; - - - default: - printk(KERN_WARNING "%s: wrong selection code - irq\n",dev->name); - return; - } -} - - -static void ctc_irq_bh (struct channel *ctc) -{ - 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; - - 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); -#endif - - while (ctc->proc_anchor != NULL) { - - 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\n",dev->name); - } - (__u8 *)lp += lp->length; - } - - s390irq_spin_lock_irqsave(ctc->irq, saveflags); - ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor); - - if (test_and_set_bit(0, (void *)&ctc->IO_active) == 0) { -#ifdef DEBUG - printk(KERN_DEBUG "%s: HOT READ started in bh routine\n" ,dev->name); -#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; -} - - -static void ctc_read_retry (struct channel *ctc) -{ - int rc = 0; - __u32 parm; - __u8 flags = 0x00; - __u32 saveflags; - net_device *dev; - - dev = (net_device *) ctc->dev; - -#ifdef DEBUG - printk(KERN_DEBUG "%s: read retry - state-%02x\n" ,dev->name, ctc->state); -#endif - s390irq_spin_lock_irqsave(ctc->irq, saveflags); - 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; -} - - -static void ctc_write_retry (struct channel *ctc) -{ - int rc = 0; - __u32 parm; - __u8 flags = 0x00; - __u32 saveflags; - net_device *dev; - - dev = (net_device *) ctc->dev; - -#ifdef DEBUG - printk(KERN_DEBUG "%s: write retry - state-%02x\n" ,dev->name, ctc->state); -#endif - s390irq_spin_lock_irqsave(ctc->irq, saveflags); - ctc->ccw[1].count = 0; - 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; -} - - - -/* - * ctc_open - * - */ -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); - INIT_LIST_HEAD(&privptr->channel[i].tq.list); - 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 + 150*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)) { -#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); -#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; -} - - -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; -} - -/* - * ctc_release - * - */ -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); - 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; - } - - return 0; -} - - -/* - * ctc_tx - * - * - */ -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; - - - 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; - goto Done; - } - - 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) { -#ifdef DEBUG - 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; - 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); -Done2: - ctc_clearbit_busy(TB_TX,dev); -Done: - s390irq_spin_unlock_irqrestore(privptr->channel[WRITE].irq, saveflags); - return(rc); -} - - -/* - * ctc_change_mtu - * - * S/390 can handle MTU sizes from 576 to 32760 for VM, VSE - * 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; -} - - -/* - * ctc_stats - * - */ -struct net_device_stats *ctc_stats(net_device *dev) -{ - struct ctc_priv *privptr; - - 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); - -*/ -/* --- This is the END my friend --- */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/net/ctcmain.c linux.ac/drivers/s390/net/ctcmain.c --- linux.vanilla/drivers/s390/net/ctcmain.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/net/ctcmain.c Thu Apr 12 12:03:49 2001 @@ -1,12 +1,12 @@ /* - * $Id: ctcmain.c,v 1.11 2000/12/15 19:34:54 bird Exp $ + * $Id: ctcmain.c,v 1.17 2001/01/23 14:23:51 felfert Exp $ * * CTC / ESCON network driver * - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) * Fixes by : Jochen Röhrig (roehrig@de.ibm.com) - * Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * Arnaldo Carvalho de Melo <acme@conectiva.com.br> * * Documentation used: * - Principles of Operation (IBM doc#: SA22-7201-06) @@ -36,6 +36,26 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: ctcmain.c,v $ + * Revision 1.17 2001/01/23 14:23:51 felfert + * Added ctc based tty. + * + * Revision 1.16 2001/01/18 16:10:53 felfert + * Added fixes by acme@conectiva.com.br. + * + * Revision 1.15 2001/01/12 15:40:11 felfert + * Fixed ITPM# PL030052IME (Unitchecks when using real escon). + * + * Revision 1.14 2001/01/11 17:43:52 felfert + * Fixed ITPM# PL030051IME (Initialization of escon). + * + * Revision 1.13 2001/01/11 16:40:26 smolinsk + * resolved name space conflict with LVM and renamed + * dev_info_t to s390_dev_info_t + * worked around a bug in OSA microcode by stepping back to 2k IDALS in idals.c + * + * Revision 1.12 2000/12/27 09:40:45 tonn + * upgrade to test12 + * * Revision 1.11 2000/12/15 19:34:54 bird * struct ctc_priv_t: set type of tbusy to "unsigned long" * @@ -89,8 +109,6 @@ #include <linux/string.h> #include <linux/proc_fs.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> #include <linux/ip.h> #include <linux/if_arp.h> #include <linux/tcp.h> @@ -112,6 +130,7 @@ #include <asm/irq.h> +#include "ctctty.h" #include "fsm.h" #ifdef MODULE @@ -142,7 +161,8 @@ #define CTC_PROTO_S390 0 #define CTC_PROTO_LINUX 1 -#define CTC_PROTO_MAX 1 +#define CTC_PROTO_LINUX_TTY 2 +#define CTC_PROTO_MAX 2 #define CTC_BUFSIZE_LIMIT 65535 #define CTC_BUFSIZE_DEFAULT 32768 @@ -186,19 +206,13 @@ typedef enum channel_types channel_type_t; -static int ctc_no_auto; +static int ctc_no_auto = 0; /** * If running on 64 bit, this must be changed. XXX Why? (bird) */ typedef unsigned long intparm_t; -#if LINUX_VERSION_CODE < 0x020300 -typedef struct device net_device; -#else -typedef struct net_device net_device; -#endif - /** * Definition of a per device parameter block */ @@ -211,7 +225,7 @@ char name[MAX_PARAM_NAME_LEN]; } param; -static param *params; +static param *params = NULL; typedef struct { unsigned long maxmulti; @@ -248,7 +262,7 @@ __u32 flags; /** - * The protocol of this channel (currently always 0) + * The protocol of this channel */ __u16 protocol; @@ -342,7 +356,7 @@ /** * Linked list of all detected channels. */ -static channel *channels; +static channel *channels = NULL; typedef struct ctc_priv_t { struct net_device_stats stats; @@ -353,6 +367,10 @@ * The finite state machine of this interface. */ fsm_instance *fsm; + /** + * The protocol of this device + */ + __u16 protocol; channel *channel[2]; struct proc_dir_entry *proc_dentry; struct proc_dir_entry *proc_stat_entry; @@ -406,8 +424,8 @@ * Print Banner. */ static void print_banner(void) { - static int printed; - char vbuf[] = "$Revision: 1.11 $"; + static int printed = 0; + char vbuf[] = "$Revision: 1.17 $"; char *version = vbuf; if (printed) @@ -796,7 +814,10 @@ dev_kfree_skb(skb); goto again; } - netif_rx(skb2); + if (ch->protocol == CTC_PROTO_LINUX_TTY) + ctc_tty_netif_rx(skb2); + else + netif_rx(skb2); privptr->stats.rx_packets++; privptr->stats.rx_bytes += skb2->len; /** @@ -805,7 +826,10 @@ skb_pull(skb, header->length); skb_put(skb, LL_HEADER_LENGTH); } else { - netif_rx(skb); + if (ch->protocol == CTC_PROTO_LINUX_TTY) + ctc_tty_netif_rx(skb); + else + netif_rx(skb); privptr->stats.rx_packets++; privptr->stats.rx_bytes += skb->len; } @@ -892,8 +916,10 @@ ch->devno); fsm_event(ch->fsm, CH_EVENT_UC_TXPARITY, ch); } + } else if (sense & SNS0_CMD_REJECT) { + printk(KERN_WARNING "ch-%04x: Command reject\n", ch->devno); } else if (sense == 0) { - printk(KERN_DEBUG "ch-%04x: Unit check\n", ch->devno); + printk(KERN_DEBUG "ch-%04x: Unit check ZERO\n", ch->devno); fsm_event(ch->fsm, CH_EVENT_UC_ZERO, ch); } else { printk(KERN_WARNING @@ -1078,15 +1104,15 @@ fsm_deltimer(&ch->timer); if (len < 8) { - printk(KERN_WARNING "%s: got packet with length < 8\n", - dev->name); + printk(KERN_WARNING "%s: got packet with length %d < 8\n", + dev->name, len); privptr->stats.rx_dropped++; privptr->stats.rx_length_errors++; goto again; } if (len > ch->max_bufsize) { - printk(KERN_WARNING "%s: got packet with length > %d\n", - dev->name, ch->max_bufsize); + printk(KERN_WARNING "%s: got packet with length %d > %d\n", + dev->name, len, ch->max_bufsize); privptr->stats.rx_dropped++; privptr->stats.rx_length_errors++; goto again; @@ -1764,14 +1790,18 @@ channel **c = &channels; channel *ch; char name[10]; - int ret = -1; - if ((ch = (channel *)kmalloc(sizeof(channel), GFP_KERNEL)) == NULL) - goto out; + if ((ch = (channel *)kmalloc(sizeof(channel), GFP_KERNEL)) == NULL) { + printk(KERN_WARNING "ctc: Out of memory in add_channel\n"); + return -1; + } memset(ch, 0, sizeof(channel)); if ((ch->ccw = (ccw1_t *)kmalloc(sizeof(ccw1_t) * 5, - GFP_KERNEL|GFP_DMA)) == NULL) - goto out_ch; + GFP_KERNEL|GFP_DMA)) == NULL) { + kfree(ch); + printk(KERN_WARNING "ctc: Out of memory in add_channel\n"); + return -1; + } /** * "static" ccws are used in the following way: @@ -1804,12 +1834,19 @@ ch->fsm = init_fsm(name, ch_state_names, ch_event_names, NR_CH_STATES, NR_CH_EVENTS, ch_fsm, CH_FSM_LEN, GFP_KERNEL); - if (ch->fsm == NULL) - goto out_ccw; + if (ch->fsm == NULL) { + printk(KERN_WARNING "ctc: Could not create FSM in add_channel\n"); + kfree(ch); + return -1; + } fsm_newstate(ch->fsm, CH_STATE_IDLE); if ((ch->devstat = (devstat_t*)kmalloc(sizeof(devstat_t), GFP_KERNEL)) - == NULL) - goto out_ccw; + == NULL) { + printk(KERN_WARNING "ctc: Out of memory in add_channel\n"); + kfree_fsm(ch->fsm); + kfree(ch); + return -1; + } memset(ch->devstat, 0, sizeof(devstat_t)); while (*c && ((*c)->devno < devno)) c = &(*c)->next; @@ -1817,8 +1854,10 @@ printk(KERN_DEBUG "ctc: add_channel: device %04x already in list\n", (*c)->devno); - ret = 0; - goto out_devstat; + kfree(ch->devstat); + kfree_fsm(ch->fsm); + kfree(ch); + return 0; } fsm_settimer(ch->fsm, &ch->timer); skb_queue_head_init(&ch->io_queue); @@ -1826,16 +1865,6 @@ ch->next = *c; *c = ch; return 0; -out_devstat: - kfree(ch->devstat); -out_ccw: - kfree(ch->ccw); -out_ch: - kfree(ch); -out: - if (ret) - printk(KERN_WARNING "ctc: Out of memory in add_channel\n"); - return ret; } /** @@ -1846,9 +1875,9 @@ */ static void channel_scan(int print_result) { - int irq; - int nr_escon = 0; - int nr_ctca = 0; + int irq; + int nr_escon = 0; + int nr_ctca = 0; s390_dev_info_t di; for (irq = 0; irq < NR_IRQS; irq++) { @@ -2284,6 +2313,8 @@ if (fsm_getstate(ch->fsm) != CH_STATE_TXIDLE) { int l = skb->len + LL_HEADER_LENGTH; + if (ch->type == channel_type_escon) + return -EBUSY; spin_lock_irqsave(&ch->collect_lock, saveflags); if (ch->collect_len + l > ch->max_bufsize - 2) rc = -EBUSY; @@ -3141,7 +3172,7 @@ * * @param dev Pointer to net_device to be initialized. * - * @return 0 on success, !0 on failure. + * @returns 0 on success, !0 on failure. */ int ctc_probe(net_device *dev) { @@ -3190,6 +3221,7 @@ return -ENOMEM; memset(dev->priv, 0, sizeof(ctc_priv)); privptr = (ctc_priv *)dev->priv; + privptr->protocol = proto; privptr->proc_dentry = (struct proc_dir_entry *) (((char *)privptr) + sizeof(ctc_priv)); privptr->proc_stat_entry = (struct proc_dir_entry *) @@ -3295,6 +3327,7 @@ void cleanup_module(void) { channel *c = channels; + ctc_tty_cleanup(); /* we are called if all interfaces are down only, so no need * to bother around with locking stuff */ @@ -3313,7 +3346,10 @@ privptr->channel[WRITE]->devstat); kfree_fsm(privptr->channel[READ]->fsm); kfree_fsm(privptr->channel[WRITE]->fsm); - unregister_netdev(nd); + if (privptr->protocol != CTC_PROTO_LINUX_TTY) + unregister_netdev(nd); + else + ctc_tty_unregister_netdev(nd); kfree_fsm(privptr->fsm); privptr->channel[READ]->netdev = NULL; privptr->channel[WRITE]->netdev = NULL; @@ -3345,6 +3381,7 @@ int cnt[2]; int itype; int activated; + int ret = 0; param *par; print_banner(); @@ -3359,10 +3396,11 @@ #endif activated = 0; par = params; + ctc_tty_init(); for (itype = 0; itype < 2; itype++) { net_device *dev = NULL; char *bname = (itype) ? "escon" : "ctc"; - int nlen = strlen(bname); + cnt[itype] = 0; do { dev = kmalloc(sizeof(net_device) @@ -3370,8 +3408,10 @@ + 11 /* name + zero */ #endif , GFP_KERNEL); - if (!dev) - return -ENOMEM; + if (!dev) { + ret = -ENOMEM; + break; + } memset(dev, 0, sizeof(net_device)); #if LINUX_VERSION_CODE < 0x020300 dev->name = (unsigned char *)dev + sizeof(net_device); @@ -3386,10 +3426,10 @@ if (isdigit(*p)) break; if (p && *p) { + int it = (strncmp(dev->name, "escon", 5)) ? 1 : 0; n = simple_strtoul(p, NULL, 0); - if (n >= cnt[itype] && - (!strncmp(par->name, bname, nlen))) - cnt[itype] = n + 1; + if (n >= cnt[it]) + cnt[it] = n + 1; } } else { if (ctc_no_auto) { @@ -3406,6 +3446,7 @@ __FUNCTION__, dev->name); #endif if (ctc_probe(dev) == 0) { + ctc_priv *privptr = (ctc_priv *)dev->priv; #ifdef DEBUG printk(KERN_DEBUG "ctc: %s(): probing succeeded\n", @@ -3413,28 +3454,49 @@ printk(KERN_DEBUG "ctc: %s(): registering device %s\n", __FUNCTION__, dev->name); +#endif + if (privptr->protocol != CTC_PROTO_LINUX_TTY) { + if (register_netdev(dev) != 0) { + printk(KERN_WARNING + "ctc: Couldn't register netdev %s\n", + dev->name); + free_irq(privptr->channel[READ]->irq, + privptr->channel[READ]->devstat); + free_irq(privptr->channel[WRITE]->irq, + privptr->channel[WRITE]->devstat); + channel_free(privptr->channel[READ]); + channel_free(privptr->channel[WRITE]); + kfree(dev->priv); + kfree(dev); + } else { +#ifdef DEBUG + printk(KERN_DEBUG + "ctc: %s(): register succeed\n", + __FUNCTION__); #endif - if (register_netdev(dev) != 0) { - ctc_priv *privptr = - (ctc_priv *)dev->priv; - printk(KERN_WARNING - "ctc: Couldn't register %s\n", - dev->name); - free_irq(privptr->channel[READ]->irq, - privptr->channel[READ]->devstat); - free_irq(privptr->channel[WRITE]->irq, - privptr->channel[WRITE]->devstat); - channel_free(privptr->channel[READ]); - channel_free(privptr->channel[WRITE]); - kfree(dev->priv); - kfree(dev); + activated++; + } } else { + if (ctc_tty_register_netdev(dev) != 0) { + printk(KERN_WARNING + "ctc: Couldn't register ttydev %s\n", + dev->name); + free_irq(privptr->channel[READ]->irq, + privptr->channel[READ]->devstat); + free_irq(privptr->channel[WRITE]->irq, + privptr->channel[WRITE]->devstat); + channel_free(privptr->channel[READ]); + channel_free(privptr->channel[WRITE]); + kfree(dev->priv); + kfree(dev); + } else { #ifdef DEBUG - printk(KERN_DEBUG - "ctc: %s(): register succeed\n", - __FUNCTION__); + printk(KERN_DEBUG + "ctc: %s(): register succeed\n", + __FUNCTION__); #endif - activated++; + activated++; + } } } else { @@ -3446,13 +3508,15 @@ kfree(dev); dev = NULL; } - } while (dev); + } while (dev && (ret == 0)); } if (!activated) { printk(KERN_WARNING "ctc: No devices registered\n"); - return -ENODEV; + ret = -ENODEV; } - return 0; + if (ret) + ctc_tty_cleanup(); + return ret; } #ifndef MODULE diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/net/ctctty.c linux.ac/drivers/s390/net/ctctty.c --- linux.vanilla/drivers/s390/net/ctctty.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/s390/net/ctctty.c Thu Apr 12 12:03:49 2001 @@ -0,0 +1,1139 @@ +/* + * $Id: ctctty.c,v 1.1 2001/01/23 14:23:51 felfert Exp $ + * + * CTC / ESCON network driver, tty interface. + * + * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.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, 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 __NO_VERSION__ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/tty.h> +#include <linux/serial_reg.h> +#include <linux/interrupt.h> +#include <asm/uaccess.h> +#ifdef CONFIG_DEVFS_FS +# include <linux/devfs_fs_kernel.h> +#endif +#include "ctctty.h" +#include <net/dst.h> + +#define CTC_TTY_MAJOR 43 +#define CTC_TTY_MAX_DEVICES 64 + +#define CTC_ASYNC_MAGIC 0x49344C01 /* for paranoia-checking */ +#define CTC_ASYNC_INITIALIZED 0x80000000 /* port was initialized */ +#define CTC_ASYNC_NORMAL_ACTIVE 0x20000000 /* Normal device active */ +#define CTC_ASYNC_CLOSING 0x08000000 /* Serial port is closing */ +#define CTC_ASYNC_CTS_FLOW 0x04000000 /* Do CTS flow control */ +#define CTC_ASYNC_CHECK_CD 0x02000000 /* i.e., CLOCAL */ +#define CTC_ASYNC_HUP_NOTIFY 0x0001 /* Notify tty on hangups/closes */ +#define CTC_ASYNC_SPLIT_TERMIOS 0x0008 /* Sep. termios for dialin/out */ +#define CTC_TTY_XMIT_SIZE 1024 /* Default bufsize for write */ +#define CTC_SERIAL_XMIT_MAX 4000 /* Maximum bufsize for write */ +#define CTC_SERIAL_TYPE_NORMAL 1 + +/* Private data (similar to async_struct in <linux/serial.h>) */ +typedef struct { + int magic; + int flags; /* defined in tty.h */ + int x_char; /* xon/xoff character */ + int mcr; /* Modem control register */ + int msr; /* Modem status register */ + int lsr; /* Line status register */ + int line; + int count; /* # of fd on device */ + int blocked_open; /* # of blocked opens */ + net_device *netdev; + struct sk_buff_head tx_queue; /* transmit queue */ + struct sk_buff_head rx_queue; /* receive queue */ + struct tty_struct *tty; /* Pointer to corresponding tty */ + struct termios normal_termios; /* For saving termios structs */ + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + struct semaphore write_sem; + struct tq_struct tq; +} ctc_tty_info; + +/* Description of one CTC-tty */ +typedef struct { + int refcount; /* Number of opens */ + struct tty_driver ctc_tty_device; /* tty-device */ + struct tty_struct *modem_table[CTC_TTY_MAX_DEVICES]; + struct termios *modem_termios[CTC_TTY_MAX_DEVICES]; + struct termios *modem_termios_locked[CTC_TTY_MAX_DEVICES]; + ctc_tty_info info[CTC_TTY_MAX_DEVICES]; /* Private data */ +} ctc_tty_driver; + +static ctc_tty_driver *driver; + +/* Leave this unchanged unless you know what you do! */ +#define MODEM_PARANOIA_CHECK +#define MODEM_DO_RESTART + +#define CTC_TTY_NAME "ttyZ" + +#ifdef CONFIG_DEVFS_FS +static char *ctc_ttyname = "ctc/" CTC_TTY_NAME "%d"; +#else +static char *ctc_ttyname = CTC_TTY_NAME; +#endif + +char *ctc_tty_revision = "$Revision: 1.1 $"; + +/* ctc_tty_try_read() is called from within ctc_tty_rcv_skb() + * to stuff incoming data directly into a tty's flip-buffer. If the + * flip buffer is full, the packet gets queued up. + * + * Return: + * 1 = Success + * 0 = Failure, data has to be buffered and later processed by + * ctc_tty_readmodem(). + */ +static int +ctc_tty_try_read(ctc_tty_info * info, struct sk_buff *skb) +{ + int c; + int len; + struct tty_struct *tty; + + if ((tty = info->tty)) { + if (info->mcr & UART_MCR_RTS) { + c = TTY_FLIPBUF_SIZE - tty->flip.count; + len = skb->len; + if (c >= len) { + memcpy(tty->flip.char_buf_ptr, skb->data, len); + tty->flip.count += len; + tty->flip.char_buf_ptr += len; + memset(tty->flip.flag_buf_ptr, 0, len); + tty->flip.flag_buf_ptr += len; + queue_task(&tty->flip.tqueue, &tq_timer); + kfree_skb(skb); + return 1; + } + } + } + return 0; +} + +/* ctc_tty_readmodem() is called periodically from within timer-interrupt. + * It tries getting received data from the receive queue an stuff it into + * the tty's flip-buffer. + */ +static int +ctc_tty_readmodem(ctc_tty_info *info) +{ + int ret = 0; + struct tty_struct *tty; + + if ((tty = info->tty)) { + if (info->mcr & UART_MCR_RTS) { + int c = TTY_FLIPBUF_SIZE - tty->flip.count; + struct sk_buff *skb; + + if ((c > 0) && (skb = skb_dequeue(&info->rx_queue))) { + int len = skb->len; + if (len > c) + len = c; + memcpy(tty->flip.char_buf_ptr, skb_pull(skb, len), len); + tty->flip.count += len; + memset(tty->flip.flag_buf_ptr, 0, len); + tty->flip.flag_buf_ptr += len; + queue_task(&tty->flip.tqueue, &tq_timer); + if (skb->len) { + skb_queue_head(&info->rx_queue, skb); + ret = 1; + } else + kfree_skb(skb); + } + } + } + return ret; +} + +void +ctc_tty_netif_rx(struct sk_buff *skb) +{ + int i; + ctc_tty_info *info = NULL; + + if (!skb) + return; + if (!skb->dev) { + dev_kfree_skb(skb); + return; + } + for (i = 0; i < CTC_TTY_MAX_DEVICES; i++) + if (driver->info[i].netdev == skb->dev) { + info = &driver->info[i]; + break; + } + if (!info) { + dev_kfree_skb(skb); + return; + } + skb_pull(skb, sizeof(int)); + /* Try to deliver directly via tty-flip-buf if queue is empty */ + if (skb_queue_empty(&info->rx_queue)) + if (ctc_tty_try_read(info, skb)) + return; + /* Direct deliver failed or queue wasn't empty. + * Queue up for later dequeueing via timer-irq. + */ + skb_queue_tail(&info->rx_queue, skb); + /* Schedule dequeuing */ + queue_task(&info->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +static void +ctc_tty_dstfail(struct sk_buff *skb) { + if (!skb) + return; + dev_kfree_skb(skb); + return; +} + +static struct dst_entry dst_e; +static struct dst_ops dst_o; + +static int +ctc_tty_tint(ctc_tty_info * info) +{ + struct sk_buff *skb = skb_dequeue(&info->tx_queue); + int rc; + int l; + char c; + + if (!skb) + return 0; + if (!info->netdev) { + kfree(skb); + return 0; + } + skb->dst = &dst_e; + l = skb->len; + c = *(skb->data); + rc = info->netdev->hard_start_xmit(skb, info->netdev); +printk(KERN_DEBUG "xmit: l=%d rc=%d '%02x'\n", l, rc, c); + if (rc) { + skb_queue_head(&info->tx_queue, skb); + return 1; + } else { + struct tty_struct *tty = info->tty; + info->lsr |= UART_LSR_TEMT; + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } + return (skb_queue_empty(&info->tx_queue) ? 0 : 1); +} + +/************************************************************ + * + * Modem-functions + * + * mostly "stolen" from original Linux-serial.c and friends. + * + ************************************************************/ + +static inline int +ctc_tty_paranoia_check(ctc_tty_info * info, kdev_t device, const char *routine) +{ +#ifdef MODEM_PARANOIA_CHECK + if (!info) { + printk(KERN_WARNING "ctc_tty: null info_struct for (%d, %d) in %s\n", + MAJOR(device), MINOR(device), routine); + return 1; + } + if (info->magic != CTC_ASYNC_MAGIC) { + printk(KERN_WARNING "ctc_tty: bad magic for info struct (%d, %d) in %s\n", + MAJOR(device), MINOR(device), routine); + return 1; + } +#endif + return 0; +} + +static void +ctc_tty_change_speed(ctc_tty_info * info) +{ + unsigned int cflag; + unsigned int quot; + int i; + + if (!info->tty || !info->tty->termios) + return; + cflag = info->tty->termios->c_cflag; + + quot = i = cflag & CBAUD; + if (i & CBAUDEX) { + i &= ~CBAUDEX; + if (i < 1 || i > 2) + info->tty->termios->c_cflag &= ~CBAUDEX; + else + i += 15; + } + if (quot) { + info->mcr |= UART_MCR_DTR; + } else { + info->mcr &= ~UART_MCR_DTR; + return; + } + + /* CTS flow control flag and modem status interrupts */ + if (cflag & CRTSCTS) { + info->flags |= CTC_ASYNC_CTS_FLOW; + } else + info->flags &= ~CTC_ASYNC_CTS_FLOW; + if (cflag & CLOCAL) + info->flags &= ~CTC_ASYNC_CHECK_CD; + else { + info->flags |= CTC_ASYNC_CHECK_CD; + } +} + +static int +ctc_tty_startup(ctc_tty_info * info) +{ + if (info->flags & CTC_ASYNC_INITIALIZED) + return 0; +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "starting up %s%d ...\n", CTC_TTY_NAME, info->line); +#endif + /* + * Now, initialize the UART + */ + info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + /* + * and set the speed of the serial port + */ + ctc_tty_change_speed(info); + + info->flags |= CTC_ASYNC_INITIALIZED; + info->msr |= (UART_MSR_DSR | UART_MSR_CTS); + info->netdev->open(info->netdev); + 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 +ctc_tty_shutdown(ctc_tty_info * info) +{ + if (!(info->flags & CTC_ASYNC_INITIALIZED)) + return; +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "Shutting down %s%d ....\n", CTC_TTY_NAME, info->line); +#endif + info->msr &= ~UART_MSR_RI; + if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { + info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS); + } + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + info->netdev->stop(info->netdev); + skb_queue_purge(&info->tx_queue); + skb_queue_purge(&info->rx_queue); + info->flags &= ~CTC_ASYNC_INITIALIZED; +} + +/* ctc_tty_write() is the main send-routine. It is called from the upper + * levels within the kernel to perform sending data. Depending on the + * online-flag it either directs output to the at-command-interpreter or + * to the lower level. Additional tasks done here: + * - If online, check for escape-sequence (+++) + * - If sending audio-data, call ctc_tty_DLEdown() to parse DLE-codes. + * - If receiving audio-data, call ctc_tty_end_vrx() to abort if needed. + * - If dialing, abort dial. + */ +static int +ctc_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int count) +{ + int c; + int total = 0; + ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; + + if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_write")) + return 0; + if (!tty) + return 0; + if (!info->netdev) + return -ENODEV; + if (from_user) + down(&info->write_sem); + while (1) { + struct sk_buff *skb; + int skb_res; + + c = (count < CTC_TTY_XMIT_SIZE) ? count : CTC_TTY_XMIT_SIZE; + if (c <= 0) + break; + + skb_res = info->netdev->hard_header_len + sizeof(int); + skb = dev_alloc_skb(skb_res + c); + if (!skb) { + printk(KERN_WARNING + "ctc_tty: Out of memory in %s%d write\n", + CTC_TTY_NAME, info->line); + break; + } + skb_reserve(skb, skb_res); + if (from_user) + copy_from_user(skb_put(skb, c), buf, c); + else + memcpy(skb_put(skb, c), buf, c); + skb_queue_tail(&info->tx_queue, skb); + buf += c; + total += c; + count -= c; + } + if (skb_queue_len(&info->tx_queue)) { + queue_task(&info->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + if (from_user) + up(&info->write_sem); + return total; +} + +static int +ctc_tty_write_room(struct tty_struct *tty) +{ + ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; + + if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_write_room")) + return 0; + return CTC_TTY_XMIT_SIZE; +} + +static int +ctc_tty_chars_in_buffer(struct tty_struct *tty) +{ + ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; + + if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_chars_in_buffer")) + return 0; + return 0; +} + +static void +ctc_tty_flush_buffer(struct tty_struct *tty) +{ + ctc_tty_info *info; + unsigned long flags; + + save_flags(flags); + cli(); + if (!tty) { + restore_flags(flags); + return; + } + info = (ctc_tty_info *) tty->driver_data; + if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_flush_buffer")) { + restore_flags(flags); + return; + } + skb_queue_purge(&info->tx_queue); + restore_flags(flags); + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup) (tty); +} + +static void +ctc_tty_flush_chars(struct tty_struct *tty) +{ + ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; + + if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_flush_chars")) + return; + if (skb_queue_len(&info->tx_queue)) { + queue_task(&info->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } +} + +/* + * ------------------------------------------------------------ + * ctc_tty_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void +ctc_tty_throttle(struct tty_struct *tty) +{ + ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; + + if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_throttle")) + return; + if (I_IXOFF(tty)) + info->x_char = STOP_CHAR(tty); + info->mcr &= ~UART_MCR_RTS; +} + +static void +ctc_tty_unthrottle(struct tty_struct *tty) +{ + ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; + + if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_unthrottle")) + return; + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + info->x_char = START_CHAR(tty); + } + info->mcr |= UART_MCR_RTS; +} + +/* + * ------------------------------------------------------------ + * ctc_tty_ioctl() and friends + * ------------------------------------------------------------ + */ + +/* + * ctc_tty_get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows RS485 driver to be written in user space. + */ +static int +ctc_tty_get_lsr_info(ctc_tty_info * info, uint * value) +{ + u_char status; + uint result; + ulong flags; + + save_flags(flags); + cli(); + status = info->lsr; + restore_flags(flags); + result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); + put_user(result, (uint *) value); + return 0; +} + + +static int +ctc_tty_get_ctc_tty_info(ctc_tty_info * info, uint * value) +{ + u_char control, + status; + uint result; + ulong flags; + + control = info->mcr; + save_flags(flags); + cli(); + status = info->msr; + restore_flags(flags); + result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) + | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) + | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) + | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) + | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) + | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); + put_user(result, (uint *) value); + return 0; +} + +static int +ctc_tty_set_ctc_tty_info(ctc_tty_info * info, uint cmd, uint * value) +{ + uint arg; + + get_user(arg, (uint *) value); + switch (cmd) { + case TIOCMBIS: +#ifdef CTC_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "%s%d ioctl TIOCMBIS\n", CTC_TTY_NAME, + info->line); +#endif + if (arg & TIOCM_RTS) { + info->mcr |= UART_MCR_RTS; + } + if (arg & TIOCM_DTR) { + info->mcr |= UART_MCR_DTR; + } + break; + case TIOCMBIC: +#ifdef CTC_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "%s%d ioctl TIOCMBIC\n", CTC_TTY_NAME, + info->line); +#endif + if (arg & TIOCM_RTS) { + info->mcr &= ~UART_MCR_RTS; + } + if (arg & TIOCM_DTR) { + info->mcr &= ~UART_MCR_DTR; + } + break; + case TIOCMSET: +#ifdef CTC_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "%s%d ioctl TIOCMSET\n", CTC_TTY_NAME, + info->line); +#endif + info->mcr = ((info->mcr & ~(UART_MCR_RTS | UART_MCR_DTR)) + | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) + | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); + break; + default: + return -EINVAL; + } + return 0; +} + +static int +ctc_tty_ioctl(struct tty_struct *tty, struct file *file, + uint cmd, ulong arg) +{ + ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; + int error; + int retval; + + if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_ioctl")) + return -ENODEV; + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + switch (cmd) { + case TCSBRK: /* SVID version: non-zero arg --> no break */ +#ifdef CTC_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "%s%d ioctl TCSBRK\n", CTC_TTY_NAME, info->line); +#endif + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ +#ifdef CTC_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "%s%d ioctl TCSBRKP\n", CTC_TTY_NAME, info->line); +#endif + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + return 0; + case TIOCGSOFTCAR: +#ifdef CTC_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "%s%d ioctl TIOCGSOFTCAR\n", CTC_TTY_NAME, + info->line); +#endif + error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long)); + if (error) + return error; + put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg); + return 0; + case TIOCSSOFTCAR: +#ifdef CTC_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "%s%d ioctl TIOCSSOFTCAR\n", CTC_TTY_NAME, + info->line); +#endif + error = verify_area(VERIFY_READ, (void *) arg, sizeof(long)); + if (error) + return error; + get_user(arg, (ulong *) arg); + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + return 0; + case TIOCMGET: +#ifdef CTC_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "%s%d ioctl TIOCMGET\n", CTC_TTY_NAME, + info->line); +#endif + error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint)); + if (error) + return error; + return ctc_tty_get_ctc_tty_info(info, (uint *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + error = verify_area(VERIFY_READ, (void *) arg, sizeof(uint)); + if (error) + return error; + return ctc_tty_set_ctc_tty_info(info, cmd, (uint *) arg); + case TIOCSERGETLSR: /* Get line status register */ +#ifdef CTC_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "%s%d ioctl TIOCSERGETLSR\n", CTC_TTY_NAME, + info->line); +#endif + error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint)); + if (error) + return error; + else + return ctc_tty_get_lsr_info(info, (uint *) arg); + default: +#ifdef CTC_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on %s%d\n", cmd, + CTC_TTY_NAME, info->line); +#endif + return -ENOIOCTLCMD; + } + return 0; +} + +static void +ctc_tty_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; + + if (!old_termios) + ctc_tty_change_speed(info); + else { + if (tty->termios->c_cflag == old_termios->c_cflag) + return; + ctc_tty_change_speed(info); + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + } + } +} + +/* + * ------------------------------------------------------------ + * ctc_tty_open() and friends + * ------------------------------------------------------------ + */ +static int +ctc_tty_block_til_ready(struct tty_struct *tty, struct file *filp, ctc_tty_info *info) +{ + DECLARE_WAITQUEUE(wait, NULL); + int do_clocal = 0; + unsigned long flags; + int retval; + + /* + * 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 & CTC_ASYNC_CLOSING)) { + if (info->flags & CTC_ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef MODEM_DO_RESTART + if (info->flags & CTC_ASYNC_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; +#else + return -EAGAIN; +#endif + } + /* + * If non-blocking mode is set, then make the check up front + * and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + info->flags |= CTC_ASYNC_NORMAL_ACTIVE; + return 0; + } + 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 + * ctc_tty_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 CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "ctc_tty_block_til_ready before block: %s%d, count = %d\n", + CTC_TTY_NAME, 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) { + set_current_state(TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp) || + !(info->flags & CTC_ASYNC_INITIALIZED)) { +#ifdef MODEM_DO_RESTART + if (info->flags & CTC_ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & CTC_ASYNC_CLOSING) && + (do_clocal || (info->msr & UART_MSR_DCD))) { + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "ctc_tty_block_til_ready blocking: %s%d, count = %d\n", + CTC_TTY_NAME, 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 CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "ctc_tty_block_til_ready after blocking: %s%d, count = %d\n", + CTC_TTY_NAME, info->line, info->count); +#endif + if (retval) + return retval; + info->flags |= CTC_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 +ctc_tty_open(struct tty_struct *tty, struct file *filp) +{ + ctc_tty_info *info; + int retval, + line; + + line = MINOR(tty->device) - tty->driver.minor_start; + if (line < 0 || line > CTC_TTY_MAX_DEVICES) + return -ENODEV; + info = &driver->info[line]; + if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_open")) + return -ENODEV; + if (!info->netdev) + return -ENODEV; +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "ctc_tty_open %s%d, count = %d\n", tty->driver.name, + info->line, info->count); +#endif + info->count++; + tty->driver_data = info; + info->tty = tty; + /* + * Start up serial port + */ + retval = ctc_tty_startup(info); + if (retval) { +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "ctc_tty_open return after startup\n"); +#endif + return retval; + } + retval = ctc_tty_block_til_ready(tty, filp, info); + if (retval) { +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "ctc_tty_open return after ctc_tty_block_til_ready \n"); +#endif + return retval; + } + if ((info->count == 1) && (info->flags & CTC_ASYNC_SPLIT_TERMIOS)) { + *tty->termios = info->normal_termios; + ctc_tty_change_speed(info); + } +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "ctc_tty_open %s%d successful...\n", CTC_TTY_NAME, info->line); +#endif + return 0; +} + +static void +ctc_tty_close(struct tty_struct *tty, struct file *filp) +{ + ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; + ulong flags; + ulong timeout; + + if (!info || ctc_tty_paranoia_check(info, tty->device, "ctc_tty_close")) + return; + save_flags(flags); + cli(); + if (tty_hung_up_p(filp)) { + restore_flags(flags); +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "ctc_tty_close return after tty_hung_up_p\n"); +#endif + return; + } + if ((tty->count == 1) && (info->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk(KERN_ERR "ctc_tty_close: bad port count; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } + if (--info->count < 0) { + printk(KERN_ERR "ctc_tty_close: bad port count for %s%d: %d\n", + CTC_TTY_NAME, info->line, info->count); + info->count = 0; + } + if (info->count) { + restore_flags(flags); +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "ctc_tty_close after info->count != 0\n"); +#endif + return; + } + info->flags |= CTC_ASYNC_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & CTC_ASYNC_NORMAL_ACTIVE) + info->normal_termios = *tty->termios; + + tty->closing = 1; + /* + * 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 & CTC_ASYNC_INITIALIZED) { + tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ + /* + * 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->lsr & UART_LSR_TEMT)) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(20); + if (time_after(jiffies,timeout)) + break; + } + } + ctc_tty_shutdown(info); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + info->tty = 0; + tty->closing = 0; + if (info->blocked_open) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(50); + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(CTC_ASYNC_NORMAL_ACTIVE | CTC_ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + restore_flags(flags); +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "ctc_tty_close normal exit\n"); +#endif +} + +/* + * ctc_tty_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +static void +ctc_tty_hangup(struct tty_struct *tty) +{ + ctc_tty_info *info = (ctc_tty_info *)tty->driver_data; + + if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_hangup")) + return; + ctc_tty_shutdown(info); + info->count = 0; + info->flags &= ~CTC_ASYNC_NORMAL_ACTIVE; + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + + +/* + * For all online tty's, try sending data to + * the lower levels. + */ +static void +ctc_tty_task(ctc_tty_info *info) +{ + int again; + + again = ctc_tty_tint(info); + again |= ctc_tty_readmodem(info); + if (again) { + queue_task(&info->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } +} + +int +ctc_tty_init(void) +{ + int i; + ctc_tty_info *info; + struct tty_driver *device; + + dst_e.ops = &dst_o; + dst_o.link_failure = ctc_tty_dstfail; + driver = kmalloc(sizeof(ctc_tty_driver), GFP_KERNEL); + if (driver == NULL) { + printk(KERN_WARNING "Out of memory in ctc_tty_modem_init\n"); + return -ENOMEM; + } + memset(driver, 0, sizeof(ctc_tty_driver)); + device = &driver->ctc_tty_device; + + device->magic = TTY_DRIVER_MAGIC; + device->name = ctc_ttyname; + device->major = CTC_TTY_MAJOR; + device->minor_start = 0; + device->num = CTC_TTY_MAX_DEVICES; + device->type = TTY_DRIVER_TYPE_SERIAL; + device->subtype = CTC_SERIAL_TYPE_NORMAL; + device->init_termios = tty_std_termios; + device->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + device->flags = TTY_DRIVER_REAL_RAW; + device->refcount = &driver->refcount; + device->table = driver->modem_table; + device->termios = driver->modem_termios; + device->termios_locked = driver->modem_termios_locked; + device->open = ctc_tty_open; + device->close = ctc_tty_close; + device->write = ctc_tty_write; + device->put_char = NULL; + device->flush_chars = ctc_tty_flush_chars; + device->write_room = ctc_tty_write_room; + device->chars_in_buffer = ctc_tty_chars_in_buffer; + device->flush_buffer = ctc_tty_flush_buffer; + device->ioctl = ctc_tty_ioctl; + device->throttle = ctc_tty_throttle; + device->unthrottle = ctc_tty_unthrottle; + device->set_termios = ctc_tty_set_termios; + device->stop = NULL; + device->start = NULL; + device->hangup = ctc_tty_hangup; + device->driver_name = "ctc_tty"; + + if (tty_register_driver(device)) { + printk(KERN_WARNING "ctc_tty: Couldn't register serial-device\n"); + kfree(driver); + return -1; + } + for (i = 0; i < CTC_TTY_MAX_DEVICES; i++) { + info = &driver->info[i]; + init_MUTEX(&info->write_sem); + INIT_LIST_HEAD(&info->tq.list); + info->tq.sync = 0; + info->tq.routine = (void *)(void *)ctc_tty_task; + info->tq.data = info; + info->magic = CTC_ASYNC_MAGIC; + info->line = i; + info->tty = 0; + info->x_char = 0; + info->count = 0; + info->blocked_open = 0; + info->normal_termios = device->init_termios; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + skb_queue_head_init(&info->tx_queue); + skb_queue_head_init(&info->rx_queue); + } + return 0; +} + +int +ctc_tty_register_netdev(net_device *dev) { + int ttynum; + char *err; + char *p; + + if ((!dev) || (!dev->name)) { + printk(KERN_WARNING + "ctc_tty_register_netdev called " + "with NULL dev or NULL dev-name\n"); + return -1; + } + for (p = dev->name; p && ((*p < '0') || (*p > '9')); p++); + ttynum = simple_strtoul(p, &err, 0); + if ((ttynum < 0) || (ttynum >= CTC_TTY_MAX_DEVICES) || + (err && *err)) { + printk(KERN_WARNING + "ctc_tty_register_netdev called " + "with number in name '%s'\n", dev->name); + return -1; + } + if (driver->info[ttynum].netdev) { + printk(KERN_WARNING + "ctc_tty_register_netdev called " + "for already registered device '%s'\n", + dev->name); + return -1; + } + driver->info[ttynum].netdev = dev; + return 0; +} + +void +ctc_tty_unregister_netdev(net_device *dev) { + int i; + ctc_tty_info *info = NULL; + + for (i = 0; i < CTC_TTY_MAX_DEVICES; i++) + if (driver->info[i].netdev == dev) { + info = &driver->info[i]; + break; + } + if (info) { + info->netdev = NULL; + skb_queue_purge(&info->tx_queue); + skb_queue_purge(&info->rx_queue); + } +} + +void +ctc_tty_cleanup(void) { + tty_unregister_driver(&driver->ctc_tty_device); + kfree(driver); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/net/ctctty.h linux.ac/drivers/s390/net/ctctty.h --- linux.vanilla/drivers/s390/net/ctctty.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/s390/net/ctctty.h Thu Apr 12 12:03:49 2001 @@ -0,0 +1,43 @@ +/* + * $Id: ctctty.h,v 1.2 2001/01/30 22:09:28 uweigand Exp $ + * + * CTC / ESCON network driver, tty interface. + * + * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.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, 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 _CTCTTY_H_ +#define _CTCTTY_H_ + +#include <linux/version.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> + +#if LINUX_VERSION_CODE < 0x020300 +typedef struct device net_device; +#else +typedef struct net_device net_device; +#endif + +extern int ctc_tty_register_netdev(net_device *dev); +extern void ctc_tty_unregister_netdev(net_device *dev); +extern void ctc_tty_netif_rx(struct sk_buff *skb); +extern int ctc_tty_init(void); +extern void ctc_tty_cleanup(void); + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/net/iucv.c linux.ac/drivers/s390/net/iucv.c --- linux.vanilla/drivers/s390/net/iucv.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/net/iucv.c Sat Apr 14 01:28:59 2001 @@ -9,7 +9,7 @@ * Alan Altmark (Alan_Altmark@us.ibm.com) */ -#include <linux/config.h> +#include <linux/module.h> #include <linux/version.h> #include <linux/spinlock.h> #include <linux/kernel.h> @@ -29,10 +29,6 @@ //#define DEBUG /* Turns Printk's on */ //#define DEBUG2 /* This prints the parameter list before and */ /* after the b2f0 call to cp */ -#ifdef CONFIG_MODULES -#define EXPORT_SYMTAB -#include <linux/module.h> -#endif #undef NULL #define NULL 0 #define ADDED_STOR 64 /* ADDITIONAL STORAGE FOR PATHID @'S */ @@ -2021,7 +2017,6 @@ return 0; } -#ifdef CONFIG_MODULES EXPORT_SYMBOL (iucv_accept); EXPORT_SYMBOL (iucv_connect); EXPORT_SYMBOL (iucv_purge); @@ -2046,5 +2041,4 @@ EXPORT_SYMBOL (iucv_sever); EXPORT_SYMBOL (iucv_register_program); EXPORT_SYMBOL (iucv_unregister); -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/net/netiucv.c linux.ac/drivers/s390/net/netiucv.c --- linux.vanilla/drivers/s390/net/netiucv.c Tue Apr 3 17:32:17 2001 +++ linux.ac/drivers/s390/net/netiucv.c Thu Apr 12 12:03:49 2001 @@ -489,7 +489,7 @@ pr_debug ("message_pending: ID=%p Length=%u\n", (void *) mpi->ipmsgid, buffer_length); - buffer = kmalloc (buffer_length, GFP_KERNEL | GFP_DMA); + buffer = kmalloc (buffer_length, GFP_ATOMIC | GFP_DMA); if (buffer == NULL) { p->stats.rx_dropped++; return; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/s390dyn.c linux.ac/drivers/s390/s390dyn.c --- linux.vanilla/drivers/s390/s390dyn.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/s390dyn.c Thu Apr 12 12:03:49 2001 @@ -7,6 +7,7 @@ * Author(s): Ingo Adlung (adlung@de.ibm.com) */ +#include <linux/module.h> #include <linux/init.h> #include <linux/smp_lock.h> @@ -14,200 +15,149 @@ #include <asm/s390io.h> #include <asm/s390dyn.h> -static devreg_t *devreg_anchor = NULL; -static spinlock_t dyn_lock = SPIN_LOCK_UNLOCKED; +static struct list_head devreg_anchor = LIST_HEAD_INIT(devreg_anchor); +static spinlock_t dyn_lock = SPIN_LOCK_UNLOCKED; - -int s390_device_register( devreg_t *drinfo ) +static inline int s390_device_register_internal(devreg_t *drinfo) { - unsigned long flags; - int pdevflag,drflag; - - int ret = 0; - devreg_t *pdevreg = devreg_anchor; - - if ( drinfo == NULL ) - return( -EINVAL ); + struct list_head *p; - drflag = drinfo->flag; - - if ( (drflag & DEVREG_TYPE_DEVNO) == (drflag & DEVREG_TYPE_DEVCHARS) ) - return( -EINVAL ); - - spin_lock_irqsave( &dyn_lock, flags ); - - while ( (pdevreg != NULL) && (ret ==0) ) - { - if ( pdevreg == drinfo ) - { - ret = -EINVAL; - } - else - { - pdevflag = pdevreg->flag; - - /* - * we don't allow multiple drivers to register - * for the same device number - */ - if ( ( (pdevflag & DEVREG_TYPE_DEVNO) - && (pdevreg->ci.devno ) ) - && ( (drflag & DEVREG_TYPE_DEVNO ) - && (drinfo->ci.devno ) ) ) - { - ret = -EBUSY; - } - else if ( drflag == ( DEVREG_TYPE_DEVCHARS - | DEVREG_EXACT_MATCH )) - { - if ( !memcmp(&drinfo->ci.hc, - &pdevreg->ci.hc, - sizeof(devreg_hc_t))) - ret=-EBUSY; - } /* endif */ - - } /* endif */ - - pdevreg = pdevreg->next; + list_for_each(p, &devreg_anchor) { + devreg_t *pdevreg = list_entry(p, devreg_t, list); + + if (pdevreg == drinfo) + return -EINVAL; + /* + * We don't allow multiple drivers to register + * for the same device number + */ + if (pdevreg->ci.devno == drinfo->ci.devno && + (pdevreg->flag & DEVREG_TYPE_DEVNO) && + (drinfo->flag & DEVREG_TYPE_DEVNO)) + return -EBUSY; + + if (drinfo->flag == (DEVREG_TYPE_DEVCHARS | + DEVREG_EXACT_MATCH) && + !memcmp(&drinfo->ci.hc, &pdevreg->ci.hc, + sizeof(devreg_hc_t))) + return -EBUSY; + } + + /* + * no collision found, enqueue + */ + list_add (&drinfo->list, &devreg_anchor); - } /* endwhile */ + return 0; +} - /* - * only enqueue if no collision was found ... - */ - if(ret==0) - { - drinfo->next = devreg_anchor; - drinfo->prev = NULL; - - if ( devreg_anchor != NULL ) - { - devreg_anchor->prev = drinfo; - - } /* endif */ - - devreg_anchor=drinfo; +int s390_device_register( devreg_t *drinfo ) +{ + unsigned long flags; + int ret; - } /* endif */ + if (drinfo == NULL || + !(drinfo->flag & (DEVREG_TYPE_DEVNO | DEVREG_TYPE_DEVCHARS))) + return -EINVAL; + spin_lock_irqsave (&dyn_lock, flags); + ret = s390_device_register_internal(drinfo); spin_unlock_irqrestore( &dyn_lock, flags ); - return( ret); + return ret; } - -int s390_device_unregister( devreg_t *dreg ) +static inline int s390_device_unregister_internal(devreg_t *dreg) { - unsigned long flags; - - int ret = -EINVAL; - devreg_t *pdevreg = devreg_anchor; + struct list_head *p; - if ( dreg == NULL ) - return( -EINVAL ); + list_for_each(p, &devreg_anchor) { + devreg_t *pdevreg = list_entry(p, devreg_t, list); - spin_lock_irqsave( &dyn_lock, flags ); - - while ( (pdevreg != NULL ) - && ( ret != 0 ) ) - { - if ( pdevreg == dreg ) - { - devreg_t *dprev = pdevreg->prev; - devreg_t *dnext = pdevreg->next; - - if ( (dprev != NULL) && (dnext != NULL) ) - { - dnext->prev = dprev; - dprev->next = dnext; - } - if ( (dprev != NULL) && (dnext == NULL) ) - { - dprev->next = NULL; - } - if ( (dprev == NULL) && (dnext != NULL) ) - { - dnext->prev = NULL; - - } /* else */ - - ret = 0; + if (pdevreg == dreg) { + list_del (&dreg->list); + return 0; } - else - { - pdevreg = pdevreg->next; + } + return -EINVAL; +} - } /* endif */ +int s390_device_unregister(devreg_t *dreg) +{ + unsigned long flags; + int ret; - } /* endwhile */ + if (dreg == NULL) + return -EINVAL; - spin_unlock_irqrestore( &dyn_lock, flags ); + spin_lock_irqsave(&dyn_lock, flags); + ret = s390_device_unregister_internal(dreg); + spin_unlock_irqrestore(&dyn_lock, flags); - return( ret); + return ret; } +static inline devreg_t *s390_search_devreg_internal(ioinfo_t *ioinfo) +{ + struct list_head *p; + + list_for_each(p, &devreg_anchor) { + devreg_t *pdevreg = list_entry(p, devreg_t, list); + senseid_t *sid; + int flag; + + flag = pdevreg->flag; + sid = &ioinfo->senseid; + if (flag & DEVREG_TYPE_DEVNO) { + if (ioinfo->ui.flags.dval != 1 || + ioinfo->devno != pdevreg->ci.devno) + continue; + } else if ((flag & DEVREG_TYPE_DEVCHARS) && + (flag & DEVREG_EXACT_MATCH)) { + if (pdevreg->ci.hc.ctype != sid->cu_type || + pdevreg->ci.hc.cmode != sid->cu_model || + pdevreg->ci.hc.dtype != sid->dev_type || + pdevreg->ci.hc.dmode != sid->dev_model) + continue; + } else if (flag & DEVREG_TYPE_DEVCHARS) { + if (!(flag & DEVREG_NO_CU_INFO) && + pdevreg->ci.hc.ctype != sid->cu_type) + continue; + + if (!(flag & DEVREG_NO_CU_INFO) && + !(flag & DEVREG_MATCH_CU_TYPE) && + pdevreg->ci.hc.cmode != sid->cu_model) + continue; + + if (!(flag & DEVREG_NO_DEV_INFO) && + pdevreg->ci.hc.dtype != sid->dev_type) + continue; + + if (!(flag & DEVREG_NO_DEV_INFO) && + !(flag & DEVREG_MATCH_DEV_TYPE) && + pdevreg->ci.hc.dmode != sid->dev_model) + continue; + } + return pdevreg; + } + return NULL; +} devreg_t * s390_search_devreg( ioinfo_t *ioinfo ) { unsigned long flags; - devreg_hc_t match; - devreg_t *pdevreg = devreg_anchor; - - if ( ioinfo == NULL ) - return( NULL ); - - spin_lock_irqsave( &dyn_lock, flags ); + devreg_t *pdevreg; - while ( pdevreg != NULL ) - { - int flag = pdevreg->flag; - - if ( (flag & DEVREG_TYPE_DEVNO ) - && (ioinfo->ui.flags.dval == 1 ) - && (ioinfo->devno == pdevreg->ci.devno) ) - { - break; - } - else if (flag & DEVREG_TYPE_DEVCHARS ) - { - if ( flag & DEVREG_EXACT_MATCH ) - { - if ( !memcmp( &pdevreg->ci.hc, - &ioinfo->senseid.cu_type, - sizeof(devreg_hc_t))) - break; - } - else - { - memcpy( &match, &ioinfo->senseid.cu_type, - sizeof(match)); - - if( flag & DEVREG_NO_CU_INFO ) - { - match.ctype = pdevreg->ci.hc.ctype; - match.cmode = pdevreg->ci.hc.cmode; - } - if( flag & DEVREG_NO_DEV_INFO ) - { - match.dtype = pdevreg->ci.hc.dtype; - match.dmode = pdevreg->ci.hc.dmode; - } - if ( flag & DEVREG_MATCH_CU_TYPE ) - match.cmode = pdevreg->ci.hc.cmode; - if( flag & DEVREG_MATCH_DEV_TYPE) - match.dmode = pdevreg->ci.hc.dmode; - if ( !memcmp( &pdevreg->ci.hc, - &match, sizeof(match))) - break; - } /* endif */ - } /* endif */ + if (ioinfo == NULL) + return NULL; - pdevreg = pdevreg->next; - - } /* endwhile */ - - spin_unlock_irqrestore( &dyn_lock, flags ); + spin_lock_irqsave(&dyn_lock, flags); + pdevreg = s390_search_devreg_internal(ioinfo); + spin_unlock_irqrestore(&dyn_lock, flags); - return( pdevreg); + return pdevreg; } + +EXPORT_SYMBOL(s390_device_register); +EXPORT_SYMBOL(s390_device_unregister); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/s390io.c linux.ac/drivers/s390/s390io.c --- linux.vanilla/drivers/s390/s390io.c Tue Feb 13 22:13:44 2001 +++ linux.ac/drivers/s390/s390io.c Thu Apr 12 12:03:49 2001 @@ -8,8 +8,16 @@ * Author(s): Ingo Adlung (adlung@de.ibm.com) * ChangeLog: 01/04/2001 Holger Smolinski (smolinsk@de.ibm.com) * Fixed lost interrupts and do_adapter_IO + * xx/xx/xxxx nnn multiple changes not reflected + * 03/12/2001 Ingo Adlung blacklist= - changed to cio_ignore= + * 03/14/2001 Ingo Adlung disable interrupts before start_IO + * in Path Group processing + * decrease retry2 on busy while + * disabling sync_isc; reset isc_cnt + * on io error during sync_isc enablement */ +#include <linux/module.h> #include <linux/config.h> #include <linux/errno.h> #include <linux/kernel_stat.h> @@ -23,7 +31,9 @@ #include <linux/smp_lock.h> #include <linux/init.h> #include <linux/bootmem.h> - +#ifdef CONFIG_PROC_FS +#include <linux/proc_fs.h> +#endif #include <asm/system.h> #include <asm/io.h> #include <asm/irq.h> @@ -34,6 +44,7 @@ #include <asm/processor.h> #include <asm/lowcore.h> #include <asm/idals.h> +#include <asm/uaccess.h> #include <asm/s390io.h> #include <asm/s390dyn.h> @@ -47,9 +58,6 @@ #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; @@ -58,7 +66,8 @@ }; static atomic_t sync_isc = ATOMIC_INIT(-1); - // synchronous irq processing lock +static int sync_isc_cnt = 0; // synchronous irq processing lock + static spinlock_t adapter_lock = SPIN_LOCK_UNLOCKED; // adapter interrupt lock static psw_t io_sync_wait; // wait PSW for sync IO, prot. by sync_isc @@ -70,22 +79,7 @@ static __u64 irq_IPL_TOD; static adapter_int_handler_t adapter_handler = NULL; -/* - * Dummy controller type for unused interrupts - */ -int do_none(unsigned int irq, int cpu, struct pt_regs * regs) { return 0;} -int enable_none(unsigned int irq) { return(-ENODEV); } -int disable_none(unsigned int irq) { return(-ENODEV); } - -struct hw_interrupt_type no_irq_type = { - "none", - do_none, - enable_none, - disable_none -}; - static void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs); -static int s390_setup_irq(unsigned int irq, struct s390_irqaction * new); static void s390_process_subchannels( void); static void s390_device_recognition_all( void); static void s390_device_recognition_irq( int irq); @@ -94,8 +88,11 @@ static int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid); static int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid); static int s390_process_IRQ( unsigned int irq ); +static int enable_subchannel( unsigned int irq); static int disable_subchannel( unsigned int irq); +void chan_proc_init( void ); + static inline void do_adapter_IO( __u32 intparm ); int s390_DevicePathVerification( int irq, __u8 domask ); @@ -108,6 +105,305 @@ asmlinkage void do_IRQ( struct pt_regs regs ); + +/* + * "Blacklisting" of certain devices: + * Device numbers given in the commandline as blacklist=... won't be known to Linux + * These can be single devices or ranges of devices + * + * Introduced by Cornelia Huck <cohuck@de.ibm.com> + * Most of it shamelessly taken from dasd.c + */ + +typedef struct dev_blacklist_range_t { + unsigned int from; /* beginning of range */ + unsigned int to; /* end of range */ + struct dev_blacklist_range_t *next; /* next range in list */ +} dev_blacklist_range_t; + +static dev_blacklist_range_t *dev_blacklist_range_head = NULL; /* Anchor for list of ranges */ +static spinlock_t blacklist_lock = SPIN_LOCK_UNLOCKED; + +/* Handling of the blacklist ranges */ + +/* + * Function: blacklist_range_create + * Creates a range from the given parameters + */ +static inline dev_blacklist_range_t *blacklist_range_create( int from, int to) +{ + dev_blacklist_range_t *range = NULL; + range = ( dev_blacklist_range_t *) alloc_bootmem( sizeof( dev_blacklist_range_t ) ); + if (range == NULL) + return NULL; + memset( range, 0, sizeof( dev_blacklist_range_t )); + range->from = from; + if (to == 0) { /* only a single device is given */ + range->to = from; + } else { + range->to = to; + } + return range; +} + +/* + * Function: blacklist_range_destroy + * Free the given range + */ + +static inline void blacklist_range_destroy( dev_blacklist_range_t *range ) +{ + kfree( range ); +} + +/* + * Function: blacklist_range_append + * Append a range to the list of blacklisted ranges anchored at dev_blacklist_range_head + */ + +static inline void blacklist_range_append( dev_blacklist_range_t *range ) +{ + dev_blacklist_range_t *temp; + long flags; + + spin_lock_irqsave( &blacklist_lock, flags ); + if (dev_blacklist_range_head == NULL) { + dev_blacklist_range_head = range; + } else { + for ( temp = dev_blacklist_range_head; + temp && temp->next; + temp = temp->next ); + temp->next = range; + } + spin_unlock_irqrestore( &blacklist_lock, flags ); +} + +/* + * Function: blacklist_range_dechain + * Remove a range from the list of blacklisted ranges + */ + +static inline void blacklist_range_dechain( dev_blacklist_range_t *range ) +{ + dev_blacklist_range_t *temp, *prev = NULL; + long flags; + + spin_lock_irqsave( &blacklist_lock, flags ); + for ( temp = dev_blacklist_range_head; temp != NULL; temp = temp->next ) { + if ( temp == range ) + break; + prev = temp; + } + if (!temp) + BUG(); + if (prev) { + prev->next = range->next; + } else { + dev_blacklist_range_head = range->next; + } + spin_unlock_irqrestore( &blacklist_lock, flags ); +} + +/* + * Function: blacklist_range_add + * Creates a range from the specified arguments and appends it to the list of + * blacklisted devices + */ + +static inline dev_blacklist_range_t *blacklist_range_add( int from, int to ) +{ + dev_blacklist_range_t *temp; + + temp = blacklist_range_create( from, to ); + if (!temp) + return NULL; + blacklist_range_append( temp ); + return temp; +} + +/* + * Function: blacklist_range_remove + * Removes a range from the blacklist chain + */ + +static inline void blacklist_range_remove( int from, int to ) +{ + dev_blacklist_range_t *temp; + + for ( temp = dev_blacklist_range_head; + (temp->from != from) && (temp->to != to); + temp = temp->next ); + blacklist_range_dechain( temp ); + blacklist_range_destroy( temp ); +} + +/* Parsing the commandline for blacklist parameters */ + +/* + * Variable to hold the blacklisted devices given by the parameter line + * blacklist=... + */ +char *blacklist[256] = {NULL, }; + +/* + * Get the blacklist=... items from the parameter line + */ + +static void blacklist_split_parm_string (char *str) +{ + char *tmp = str; + int count = 0; + do { + char *end; + int len; + end = strchr (tmp, ','); + if (end == NULL) { + len = strlen (tmp) + 1; + } else { + len = (long) end - (long) tmp + 1; + *end = '\0'; + end++; + } + blacklist[count] = alloc_bootmem (len * sizeof (char) ); + if (blacklist == NULL) { + printk (KERN_WARNING "can't store blacklist= parameter no %d\n", count + 1); + break; + } + memset (blacklist[count], 0, len * sizeof (char)); + memcpy (blacklist[count], tmp, len * sizeof (char)); + count++; + tmp = end; + } while (tmp != NULL && *tmp != '\0'); +} + +/* + * The blacklist parameters as one concatenated string + */ + +static char blacklist_parm_string[1024] __initdata = {0,}; + + +/* + * function: blacklist_strtoul + * Strip leading '0x' and interpret the values as Hex + */ +static inline int blacklist_strtoul (char *str, char **stra) +{ + char *temp = str; + int val; + if (*temp == '0') { + temp++; /* strip leading zero */ + if (*temp == 'x') + temp++; /* strip leading x */ + } + val = simple_strtoul (temp, &temp, 16); /* interpret anything as hex */ + *stra = temp; + return val; +} + +/* + * Function: blacklist_parse + * Parse the parameters given to blacklist=... + * Add the blacklisted devices to the blacklist chain + */ + +static inline void blacklist_parse( char **str ) +{ + char *temp; + int from, to; + + while (*str) { + temp = *str; + from = 0; + to = 0; + + from = blacklist_strtoul( temp, &temp ); + if (*temp == '-') { + temp++; + to = blacklist_strtoul( temp, &temp ); + } + if (!blacklist_range_add( from, to )) { + printk( KERN_WARNING "Blacklisting range from %X to %X failed!\n", from, to); + } +#ifdef CONFIG_DEBUG_IO + printk( "Blacklisted range from %X to %X\n", from, to ); +#endif + str++; + } +} + + +/* + * Initialisation of blacklist + */ + +void __init blacklist_init( void ) +{ +#ifdef CONFIG_DEBUG_IO + printk( "Reading blacklist...\n"); +#endif + blacklist_split_parm_string( blacklist_parm_string ); + blacklist_parse( blacklist ); +} + + +/* + * Get all the blacklist parameters from parameter line + */ + +void __init blacklist_setup (char *str, int *ints) +{ + int len = strlen (blacklist_parm_string); + if (len != 0) { + strcat (blacklist_parm_string, ","); + } + strcat (blacklist_parm_string, str); +} + +int __init blacklist_call_setup (char *str) +{ + int dummy; +#ifdef CONFIG_DEBUG_IO + printk( "Reading blacklist parameters...\n" ); +#endif + blacklist_setup(str,&dummy); + + blacklist_init(); /* Blacklist ranges must be ready when device recognition starts */ + + return 1; +} + +__setup ("cio_ignore=", blacklist_call_setup); + +/* Checking if devices are blacklisted */ + +/* + * Function: is_blacklisted + * Returns 1 if the given devicenumber can be found in the blacklist, otherwise 0. + */ + +static inline int is_blacklisted( int devno ) +{ + dev_blacklist_range_t *temp; + + if (dev_blacklist_range_head == NULL) { + /* no blacklist */ + return 0; + } + + temp = dev_blacklist_range_head; + while (temp) { + if ((temp->from <= devno) && (temp->to >= devno)) { + return 1; /* Deviceno is blacklisted */ + } + temp = temp->next; + } + return 0; +} + +/* End of blacklist handling */ + + void s390_displayhex(char *str,void *ptr,s32 cnt); void s390_displayhex(char *str,void *ptr,s32 cnt) @@ -129,7 +425,7 @@ } } -static int __init cio_setup( char *parm, int *ints) +static int __init cio_setup( char *parm ) { if ( !strcmp( parm, "yes") ) { @@ -219,8 +515,8 @@ const char *devname, void *dev_id) { - int retval; - struct s390_irqaction *action; + int retval = 0; + unsigned long flags; if (irq >= __MAX_SUBCHANNELS) return -EINVAL; @@ -228,52 +524,42 @@ if ( !io_handler || !dev_id ) return -EINVAL; + if ( ioinfo[irq] == INVALID_STORAGE_AREA ) + return -ENODEV; + + /* - * during init_IRQ() processing we don't have memory - * management yet, thus need to use a statically - * allocated irqaction control block + * The following block of code has to be executed atomically */ - if ( init_IRQ_complete ) + s390irq_spin_lock_irqsave( irq, flags); + + if ( !ioinfo[irq]->ui.flags.ready ) { - action = (struct s390_irqaction *) - kmalloc( sizeof(struct s390_irqaction), - GFP_KERNEL); + ioinfo[irq]->irq_desc.handler = io_handler; + ioinfo[irq]->irq_desc.name = devname; + ioinfo[irq]->irq_desc.dev_id = dev_id; + ioinfo[irq]->ui.flags.ready = 1; + + enable_subchannel(irq); } else { - action = &init_IRQ_action; - - } /* endif */ - - if (!action) - { - return -ENOMEM; + /* + * interrupt already owned, and shared interrupts + * aren't supported on S/390. + */ + retval = -EBUSY; } /* endif */ - action->handler = io_handler; - action->flags = irqflags; - action->name = devname; - action->dev_id = dev_id; - - retval = s390_setup_irq( irq, action); - - if ( init_IRQ_complete ) - { - if ( !retval ) - { - s390_DevicePathVerification( irq, 0 ); - } - else - { - kfree(action); + s390irq_spin_unlock_irqrestore(irq,flags); - } /* endif */ - } /* endif */ if ( retval == 0 ) { + s390_DevicePathVerification( irq, 0 ); + ioinfo[irq]->ui.flags.newreq = 1; ioinfo[irq]->nopfunc = not_oper_handler; } @@ -333,10 +619,9 @@ * disable the device and reset all IRQ info if * the IRQ is actually owned by the handler ... */ - if ( ioinfo[irq]->irq_desc.action ) + if ( ioinfo[irq]->ui.flags.ready ) { - if ( (dev_id == ioinfo[irq]->irq_desc.action->dev_id ) - || (dev_id == (devstat_t *)REIPL_DEVID_MAGIC) ) + if ( dev_id == ioinfo[irq]->irq_desc.dev_id ) { /* start deregister */ ioinfo[irq]->ui.flags.unready = 1; @@ -413,14 +698,8 @@ } while ( ret == -EBUSY ); - 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.handler->enable = enable_none; - ioinfo[irq]->irq_desc.handler->disable = disable_none; - ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */ + ioinfo[irq]->ui.flags.ready = 0; + ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */ ioinfo[irq]->nopfunc = NULL; @@ -458,14 +737,11 @@ if ( ioinfo[irq] == INVALID_STORAGE_AREA ) return( -ENODEV); - s390irq_spin_lock_irqsave(irq, flags); + if ( !ioinfo[irq]->ui.flags.ready ) + return -ENODEV; - /* - * At this point we may actually have a pending interrupt being active - * on another CPU. So don't touch the IRQ_INPROGRESS bit.. - */ - ioinfo[irq]->irq_desc.status |= IRQ_DISABLED; - ret = ioinfo[irq]->irq_desc.handler->disable(irq); + s390irq_spin_lock_irqsave(irq, flags); + ret = disable_subchannel(irq); s390irq_spin_unlock_irqrestore(irq, flags); synchronize_irq(); @@ -481,11 +757,11 @@ if ( ioinfo[irq] == INVALID_STORAGE_AREA ) return( -ENODEV); - s390irq_spin_lock_irqsave(irq, flags); - - ioinfo[irq]->irq_desc.status = 0; - ret = ioinfo[irq]->irq_desc.handler->enable(irq); + if ( !ioinfo[irq]->ui.flags.ready ) + return -ENODEV; + s390irq_spin_lock_irqsave(irq, flags); + ret = enable_subchannel(irq); s390irq_spin_unlock_irqrestore(irq, flags); return(ret); @@ -717,48 +993,6 @@ } -int s390_setup_irq( unsigned int irq, struct s390_irqaction * new) -{ - unsigned long flags; - int rc = 0; - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - - /* - * The following block of code has to be executed atomically - */ - s390irq_spin_lock_irqsave( irq, flags); - - if ( ioinfo[irq]->irq_desc.action == NULL ) - { - ioinfo[irq]->irq_desc.action = new; - ioinfo[irq]->irq_desc.status = 0; - ioinfo[irq]->irq_desc.handler->enable = enable_subchannel; - ioinfo[irq]->irq_desc.handler->disable = disable_subchannel; - ioinfo[irq]->irq_desc.handler->handle = handle_IRQ_event; - - ioinfo[irq]->ui.flags.ready = 1; - - ioinfo[irq]->irq_desc.handler->enable(irq); - } - else - { - /* - * interrupt already owned, and shared interrupts - * aren't supported on S/390. - */ - rc = -EBUSY; - - } /* endif */ - - s390irq_spin_unlock_irqrestore(irq,flags); - - return( rc); -} - void s390_init_IRQ( void ) { unsigned long flags; /* PSW flags */ @@ -776,7 +1010,8 @@ p_init_schib = alloc_bootmem_low( sizeof(schib_t)); p_init_irb = alloc_bootmem_low( sizeof(irb_t)); - + + /* * As we don't know about the calling environment * we assure running disabled. Before leaving the @@ -844,7 +1079,7 @@ /* * setup ORB */ - ioinfo[irq]->orb.intparm = (__u32)(__u64)&ioinfo[irq]->u_intparm; + ioinfo[irq]->orb.intparm = (__u32)(long)&ioinfo[irq]->u_intparm; ioinfo[irq]->orb.fmt = 1; ioinfo[irq]->orb.pfch = !(flag & DOIO_DENY_PREFETCH); @@ -864,13 +1099,10 @@ #ifdef CONFIG_ARCH_S390X /* - * for 64 bit we always support 64 bit IDAWs with 2k page - * size only - * FIXTHEM: OSA microcode currently has problems with 4k - * we would like to use 4k. + * for 64 bit we always support 64 bit IDAWs with 4k page size only */ ioinfo[irq]->orb.c64 = 1; - ioinfo[irq]->orb.i2k = 1; + ioinfo[irq]->orb.i2k = 0; #endif ioinfo[irq]->orb.cpa = (__u32)virt_to_phys( cpa); @@ -912,7 +1144,7 @@ * * Note : don´t clear saved irb info in case of sense ! */ - memset( &((devstat_t *)ioinfo[irq]->irq_desc.action->dev_id)->ii.irb, + memset( &((devstat_t *)ioinfo[irq]->irq_desc.dev_id)->ii.irb, '\0', sizeof( irb_t) ); } /* endif */ @@ -1086,7 +1318,7 @@ /* * initialize the device driver specific devstat irb area */ - memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb, + memset( &((devstat_t *) ioinfo[irq]->irq_desc.dev_id)->ii.irb, '\0', sizeof( irb_t) ); /* @@ -1178,8 +1410,8 @@ ioinfo[irq]->devstat.devno ); s390_displayhex( buffer, - ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->ii.sense.data, - ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->rescnt); + ioinfo[irq]->irq_desc.dev_id->ii.sense.data, + ioinfo[irq]->irq_desc.dev_id->rescnt); } /* endif */ } @@ -1221,7 +1453,7 @@ ret = -ENODEV; - memcpy( ioinfo[irq]->irq_desc.action->dev_id, + memcpy( ioinfo[irq]->irq_desc.dev_id, &(ioinfo[irq]->devstat), sizeof( devstat_t) ); @@ -1579,7 +1811,7 @@ /* * initialize the device driver specific devstat irb area */ - memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb, + memset( &ioinfo[irq]->irq_desc.dev_id->ii.irb, '\0', sizeof( irb_t) ); /* @@ -1840,7 +2072,7 @@ /* * initialize the device driver specific devstat irb area */ - memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb, + memset( &ioinfo[irq]->irq_desc.dev_id->ii.irb, '\0', sizeof( irb_t) ); /* @@ -2007,7 +2239,6 @@ unsigned int fctl; /* function control */ unsigned int stctl; /* status control */ unsigned int actl; /* activity control */ - struct s390_irqaction *action; struct pt_regs regs; /* for interface compatibility only */ int issense = 0; @@ -2015,6 +2246,7 @@ int allow4handler = 1; int chnchk = 0; devstat_t *dp; + devstat_t *udp; #if 0 int cpu = smp_processor_id(); @@ -2029,8 +2261,8 @@ } /* endif */ - action = ioinfo[irq]->irq_desc.action; - dp = &ioinfo[irq]->devstat; + dp = &ioinfo[irq]->devstat; + udp = ioinfo[irq]->irq_desc.dev_id; #ifdef CONFIG_DEBUG_IO @@ -2040,7 +2272,7 @@ * 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.ready ) { if ( !ioinfo[irq]->ui.flags.d_disable ) { @@ -2151,7 +2383,11 @@ } /* endif */ - if ( (dp->ii.irb.scsw.stctl == SCSW_STCTL_STATUS_PEND) + if( dp->ii.irb.scsw.ectl==0) + { + issense=0; + } + else if ( (dp->ii.irb.scsw.stctl == SCSW_STCTL_STATUS_PEND) && (dp->ii.irb.scsw.eswf == 0 )) { issense = 0; @@ -2262,7 +2498,7 @@ /* * take fast exit if no handler is available */ - if ( !action ) + if ( !ioinfo[irq]->ui.flags.ready ) return( ending_status ); /* @@ -2291,9 +2527,7 @@ * sensing. When finally calling the IRQ handler we must not overlay * the original device status but copy the sense data only. */ - memcpy( action->dev_id, - dp, - sizeof( devstat_t) ); + memcpy( udp, dp, sizeof( devstat_t) ); s_ccw->cmd_code = CCW_CMD_BASIC_SENSE; s_ccw->cda = (__u32)virt_to_phys( ioinfo[irq]->sense_data ); @@ -2405,14 +2639,14 @@ "BASIC SENSE bytes avail %d\n", irq, sense_count ); #endif - ioinfo[irq]->ui.flags.w4sense = 0; - ((devstat_t *)(action->dev_id))->flag |= DEVSTAT_FLAG_SENSE_AVAIL; - ((devstat_t *)(action->dev_id))->scnt = sense_count; + ioinfo[irq]->ui.flags.w4sense = 0; + udp->flag |= DEVSTAT_FLAG_SENSE_AVAIL; + udp->scnt = sense_count; if ( sense_count >= 0 ) { - memcpy( ((devstat_t *)(action->dev_id))->ii.sense.data, - &(ioinfo[irq]->sense_data), + memcpy( udp->ii.sense.data, + ioinfo[irq]->sense_data, sense_count); } else @@ -2430,7 +2664,7 @@ } else { - memcpy( action->dev_id, dp, sdevstat ); + memcpy( udp, dp, sdevstat ); } /* endif */ @@ -2456,8 +2690,8 @@ ioinfo[irq]->ui.flags.repall = 0; ioinfo[irq]->ui.flags.w4final = 0; - dp->flag |= DEVSTAT_FINAL_STATUS; - action->dev_id->flag |= DEVSTAT_FINAL_STATUS; + dp->flag |= DEVSTAT_FINAL_STATUS; + udp->flag |= DEVSTAT_FINAL_STATUS; } /* endif */ @@ -2486,10 +2720,10 @@ ioinfo[irq]->ui.flags.repall = 0; ioinfo[irq]->ui.flags.w4final = 0; - dp->flag |= DEVSTAT_FINAL_STATUS; - action->dev_id->flag |= DEVSTAT_FINAL_STATUS; + dp->flag |= DEVSTAT_FINAL_STATUS; + udp->flag |= DEVSTAT_FINAL_STATUS; - action->handler( irq, action->dev_id, ®s ); + ioinfo[irq]->irq_desc.handler( irq, udp, ®s ); // // reset intparm after final status or we will badly present unsolicited @@ -2521,7 +2755,7 @@ */ if ( ret ) { - action->handler( irq, action->dev_id, ®s ); + ioinfo[irq]->irq_desc.handler( irq, udp, ®s ); } /* endif */ @@ -2539,17 +2773,17 @@ */ if ( dp->cstat & SCHN_STAT_PCI ) { - action->dev_id->flag |= DEVSTAT_PCI; - dp->cstat &= ~SCHN_STAT_PCI; + udp->flag |= DEVSTAT_PCI; + dp->cstat &= ~SCHN_STAT_PCI; } if ( actl & SCSW_ACTL_SUSPENDED ) { - action->dev_id->flag |= DEVSTAT_SUSPENDED; + udp->flag |= DEVSTAT_SUSPENDED; } /* endif */ - action->handler( irq, action->dev_id, ®s ); + ioinfo[irq]->irq_desc.handler( irq, udp, ®s ); } /* endif */ @@ -2623,16 +2857,16 @@ /* * take fast exit if no handler is available */ - if ( !action ) + if ( !ioinfo[irq]->ui.flags.ready ) return( ending_status ); - memcpy( action->dev_id, &(ioinfo[irq]->devstat), sdevstat ); + memcpy( udp, &(ioinfo[irq]->devstat), sdevstat ); ioinfo[irq]->devstat.intparm = 0; if ( !ioinfo[irq]->ui.flags.s_pend ) { - action->handler( irq, action->dev_id, ®s ); + ioinfo[irq]->irq_desc.handler( irq, udp, ®s ); } /* endif */ @@ -2856,9 +3090,9 @@ if ( atomic_read( &sync_isc ) != irq ) atomic_compare_and_swap_spin( -1, irq, &sync_isc ); - ioinfo[irq]->syncnt++; + sync_isc_cnt++; - if ( ioinfo[irq]->syncnt > 255 ) /* fixme : magic number */ + if ( sync_isc_cnt > 255 ) /* fixme : magic number */ { panic("Too many recursive calls to enable_sync_isc"); @@ -2866,7 +3100,7 @@ /* * we only run the STSCH/MSCH path for the first enablement */ - else if ( ioinfo[irq]->syncnt == 1) + else if ( sync_isc_cnt == 1 ) { ioinfo[irq]->ui.flags.syncio = 1; @@ -2931,9 +3165,16 @@ } /* endif */ } /* endif */ + + if ( rc ) // can only happen if stsch/msch fails + sync_isc_cnt = 0; } else { +#ifdef CONFIG_SYNC_ISC_PARANOIA + panic( "enable_sync_isc: called with invalid %x\n", irq ); +#endif + rc = -EINVAL; } /* endif */ @@ -2960,7 +3201,14 @@ * msch() processing we may face another pending * status we have to process recursively (sync). */ - if ( (ioinfo[irq]->syncnt-1) == 0 ) + +#ifdef CONFIG_SYNC_ISC_PARANOIA + if ( atomic_read( &sync_isc ) != irq ) + panic( "disable_sync_isc: called for %x while %x locked\n", + irq, atomic_read( &sync_isc ) ); +#endif + + if ( sync_isc_cnt == 1 ) { ccode = stsch( irq, &(ioinfo[irq]->schib) ); @@ -2989,6 +3237,8 @@ retry2--; break; case 2: + retry2--; + udelay( 100); // give it time break; default: retry2 = 0; @@ -3011,20 +3261,26 @@ } while ( retry1 && ccode ); - ioinfo[irq]->syncnt = 0; ioinfo[irq]->ui.flags.syncio = 0; - + + sync_isc_cnt = 0; atomic_set( &sync_isc, -1); } else { - ioinfo[irq]->syncnt--; + sync_isc_cnt--; - } /* endif */ + } /* endif */ } else { +#ifdef CONFIG_SYNC_ISC_PARANOIA + if ( atomic_read( &sync_isc ) != -1 ) + panic( "disable_sync_isc: called with invalid %x while %x locked\n", + irq, atomic_read( &sync_isc ) ); +#endif + rc = -EINVAL; } /* endif */ @@ -3446,7 +3702,7 @@ rdc_ccw->flags = CCW_FLAG_SLI; set_normalized_cda( rdc_ccw, (unsigned long)rdc_buf ); - memset( (devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id), + memset( ioinfo[irq]->irq_desc.dev_id, '\0', sizeof( devstat_t)); @@ -3457,7 +3713,7 @@ DOIO_WAIT_FOR_INTERRUPT | DOIO_DONT_CALL_INTHDLR ); retry--; - devflag = ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->flag; + devflag = ioinfo[irq]->irq_desc.dev_id->flag; clear_normalized_cda( rdc_ccw); @@ -3579,7 +3835,7 @@ } else { - pdevstat = ioinfo[irq]->irq_desc.action->dev_id; + pdevstat = ioinfo[irq]->irq_desc.dev_id; } /* endif */ @@ -3998,7 +4254,6 @@ void s390_device_recognition_irq( int irq ) { int ret; - unsigned long psw_flags; /* * We issue the SenseID command on I/O subchannels we think are @@ -4194,7 +4449,17 @@ if ( p_schib->pmcw.dnv ) { - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) + if ( is_blacklisted( p_schib->pmcw.dev )) { + /* + * This device must not be known to Linux. So we simply say that + * there is no device and return ENODEV. + */ +#ifdef CONFIG_DEBUG_IO + printk( "Blacklisted device detected at devno %04X\n", p_schib->pmcw.dev ); +#endif + ret = -ENODEV; + } else { + if ( ioinfo[irq] == INVALID_STORAGE_AREA ) { if ( !init_IRQ_complete ) { @@ -4213,8 +4478,6 @@ memcpy( &ioinfo[irq]->schib, p_init_schib, 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 @@ -4438,6 +4701,7 @@ ret = -ENODEV; } /* endif */ + } } else { @@ -4520,7 +4784,7 @@ { inlreq = 0; irq_ret = 0; - pdevstat = ioinfo[irq]->irq_desc.action->dev_id; + pdevstat = ioinfo[irq]->irq_desc.dev_id; } /* endif */ @@ -5045,6 +5309,8 @@ ccw1_t *spid_ccw; /* ccw area for SPID command */ devstat_t devstat; /* required by request_irq() */ devstat_t *pdevstat = &devstat; + unsigned long flags; + int irq_ret = 0; /* return code */ int retry = 5; /* retry count */ @@ -5087,13 +5353,13 @@ } else { - pdevstat = ioinfo[irq]->irq_desc.action->dev_id; + pdevstat = ioinfo[irq]->irq_desc.dev_id; } /* endif */ if ( irq_ret == 0 ) { - s390irq_spin_lock( irq); + s390irq_spin_lock_irqsave( irq, flags); if ( init_IRQ_complete ) { @@ -5233,7 +5499,7 @@ } /* endif */ - s390irq_spin_unlock( irq); + s390irq_spin_unlock_irqrestore( irq, flags); /* * If we installed the irq action handler we have to @@ -5301,7 +5567,7 @@ } else { - pdevstat = ioinfo[irq]->irq_desc.action->dev_id; + pdevstat = ioinfo[irq]->irq_desc.dev_id; } /* endif */ @@ -5547,7 +5813,7 @@ && ( nopfunc != NULL ) ) { - free_irq( irq,ioinfo[irq]->irq_desc.action->dev_id ); + free_irq( irq,ioinfo[irq]->irq_desc.dev_id ); nopfunc( irq,DEVSTAT_DEVICE_GONE ); } /* endif */ @@ -5659,10 +5925,170 @@ reipl ( int sch ) { int i; + s390_dev_info_t dev_info; - for ( i = 0; i < highest_subchannel; i ++ ) { - free_irq ( i, (void*)REIPL_DEVID_MAGIC ); + for ( i = 0; i <= highest_subchannel; i ++ ) + { + if ( get_dev_info_by_irq( i, &dev_info ) == 0 + && (dev_info.status & DEVSTAT_DEVICE_OWNED) ) + { + free_irq ( i, ioinfo[i]->irq_desc.dev_id ); + } } + do_reipl( 0x10000 | sch ); } +/* Display info on subchannels in /proc/subchannels. * + * Adapted from procfs stuff in dasd.c by Cornelia Huck, 02/28/01. */ + +typedef struct { + char *data; + int len; +} tempinfo_t; + +#define MIN(a,b) ((a)<(b)?(a):(b)) + +static struct proc_dir_entry *chan_subch_entry; + +static int chan_subch_open( struct inode *inode, struct file *file) +{ + int rc = 0; + int size = 1; + int len = 0; + int i = 0; + int j = 0; + tempinfo_t *info; + + info = (tempinfo_t *) vmalloc( sizeof (tempinfo_t)); + if (info == NULL) { + printk( KERN_WARNING "No memory available for data\n"); + return -ENOMEM; + } else { + file->private_data = ( void * ) info; + } + + size += (highest_subchannel+1) * 128; + info->data = (char *) vmalloc( size ); + + if (size && info->data == NULL) { + printk (KERN_WARNING "No memory available for data\n"); + vfree (info); + return -ENOMEM; + } + + len += sprintf( info->data+len, + "Device sch. Dev Type/Model CU in use PIM PAM POM LPUM CHPIDs\n"); + len += sprintf( info->data+len, + "--------------------------------------------------------------------------\n"); + + for ( i=0; i <= highest_subchannel; i++) { + if ( !((ioinfo[i] == NULL) || (ioinfo[i] == INVALID_STORAGE_AREA) || !(ioinfo[i]->ui.flags.oper)) ) { + len += sprintf( info->data+len, + "%04X %04X ", + ioinfo[i]->schib.pmcw.dev, + i ); + if ( ioinfo[i]->senseid.dev_type != 0 ) { + len += sprintf( info->data+len, + "%04X/%02X %04X/%02X", + ioinfo[i]->senseid.dev_type, + ioinfo[i]->senseid.dev_model, + ioinfo[i]->senseid.cu_type, + ioinfo[i]->senseid.cu_model ); + } else { + len += sprintf( info->data+len, + "%04X/%02X ", + ioinfo[i]->senseid.cu_type, + ioinfo[i]->senseid.cu_model ); + } + if (ioinfo[i]->ui.flags.ready) { + len += sprintf( info->data+len, " yes " ); + } else { + len += sprintf( info->data+len, " " ); + } + len += sprintf( info->data+len, + " %02X %02X %02X %02X ", + ioinfo[i]->schib.pmcw.pim, + ioinfo[i]->schib.pmcw.pam, + ioinfo[i]->schib.pmcw.pom, + ioinfo[i]->schib.pmcw.lpum ); + for ( j=0; j < 8; j++ ) { + len += sprintf( info->data+len, + "%02X", + ioinfo[i]->schib.pmcw.chpid[j] ); + if (j==3) { + len += sprintf( info->data+len, " " ); + } + } + len += sprintf( info->data+len, "\n" ); + } + } + info->len = len; + + return rc; +} + +static int chan_subch_close( struct inode *inode, struct file *file) +{ + 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; +} + +static ssize_t chan_subch_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset) +{ + loff_t len; + tempinfo_t *p_info = (tempinfo_t *) file->private_data; + + if ( *offset>=p_info->len) { + return 0; + } else { + len = MIN(user_len, (p_info->len - *offset)); + if (copy_to_user( user_buf, &(p_info->data[*offset]), len)) + return -EFAULT; + (* offset) += len; + return len; + } +} + +static struct file_operations chan_subch_file_ops = +{ + read:chan_subch_read, + open:chan_subch_open, + release:chan_subch_close, +}; + +void chan_proc_init( void ) +{ + chan_subch_entry = create_proc_entry( "subchannels", S_IFREG|S_IRUGO, &proc_root); + chan_subch_entry->proc_fops = &chan_subch_file_ops; +} + +__initcall(chan_proc_init); + +void chan_proc_cleanup( void ) +{ + remove_proc_entry( "subchannels", &proc_root); +} + +EXPORT_SYMBOL(halt_IO); +EXPORT_SYMBOL(clear_IO); +EXPORT_SYMBOL(do_IO); +EXPORT_SYMBOL(resume_IO); +EXPORT_SYMBOL(ioinfo); +EXPORT_SYMBOL(get_dev_info_by_irq); +EXPORT_SYMBOL(get_dev_info_by_devno); +EXPORT_SYMBOL(get_irq_by_devno); +EXPORT_SYMBOL(get_devno_by_irq); +EXPORT_SYMBOL(get_irq_first); +EXPORT_SYMBOL(get_irq_next); +EXPORT_SYMBOL(read_conf_data); +EXPORT_SYMBOL(read_dev_chars); +EXPORT_SYMBOL(s390_request_irq_special); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sbus/char/Makefile linux.ac/drivers/sbus/char/Makefile --- linux.vanilla/drivers/sbus/char/Makefile Tue Apr 3 17:32:17 2001 +++ linux.ac/drivers/sbus/char/Makefile Sat Apr 14 01:28:59 2001 @@ -9,10 +9,11 @@ O_TARGET := sunchar.o -export-objs := su.o +export-objs := su.o bbc_i2c.o obj-y := sunkbd.o sunkbdmap.o sunmouse.o sunserial.o zs.o vfc-objs := vfc_dev.o vfc_i2c.o +bbc-objs := bbc_i2c.o bbc_envctrl.o obj-$(CONFIG_PCI) += su.o pcikbd.o @@ -29,6 +30,7 @@ obj-$(CONFIG_SUN_AURORA) += aurora.o obj-$(CONFIG_TADPOLE_TS102_UCTRL) += uctrl.o obj-$(CONFIG_SUN_JSFLASH) += jsflash.o +obj-$(CONFIG_BBC_I2C) += bbc.o include $(TOPDIR)/Rules.make @@ -36,3 +38,6 @@ vfc.o: $(vfc-objs) $(LD) -r -o $@ $(vfc-objs) + +bbc.o: $(bbc-objs) + $(LD) -r -o $@ $(bbc-objs) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sbus/char/bbc_envctrl.c linux.ac/drivers/sbus/char/bbc_envctrl.c --- linux.vanilla/drivers/sbus/char/bbc_envctrl.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sbus/char/bbc_envctrl.c Sat Apr 14 01:29:06 2001 @@ -0,0 +1,646 @@ +/* $Id: bbc_envctrl.c,v 1.4 2001/04/06 16:48:08 davem Exp $ + * bbc_envctrl.c: UltraSPARC-III environment control driver. + * + * Copyright (C) 2001 David S. Miller (davem@redhat.com) + */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <asm/oplib.h> +#include <asm/ebus.h> +#define __KERNEL_SYSCALLS__ +static int errno; +#include <asm/unistd.h> + +#include "bbc_i2c.h" +#include "max1617.h" + +#undef ENVCTRL_TRACE + +/* WARNING: Making changes to this driver is very dangerous. + * If you misprogram the sensor chips they can + * cut the power on you instantly. + */ + +/* Two temperature sensors exist in the SunBLADE-1000 enclosure. + * Both are implemented using max1617 i2c devices. Each max1617 + * monitors 2 temperatures, one for one of the cpu dies and the other + * for the ambient temperature. + * + * The max1617 is capable of being programmed with power-off + * temperature values, one low limit and one high limit. These + * can be controlled independantly for the cpu or ambient temperature. + * If a limit is violated, the power is simply shut off. The frequency + * with which the max1617 does temperature sampling can be controlled + * as well. + * + * Three fans exist inside the machine, all three are controlled with + * an i2c digital to analog converter. There is a fan directed at the + * two processor slots, another for the rest of the enclosure, and the + * third is for the power supply. The first two fans may be speed + * controlled by changing the voltage fed to them. The third fan may + * only be completely off or on. The third fan is meant to only be + * disabled/enabled when entering/exiting the lowest power-saving + * mode of the machine. + * + * An environmental control kernel thread periodically monitors all + * temperature sensors. Based upon the samples it will adjust the + * fan speeds to try and keep the system within a certain temperature + * range (the goal being to make the fans as quiet as possible without + * allowing the system to get too hot). + * + * If the temperature begins to rise/fall outside of the acceptable + * operating range, a periodic warning will be sent to the kernel log. + * The fans will be put on full blast to attempt to deal with this + * situation. After exceeding the acceptable operating range by a + * certain threshold, the kernel thread will shut down the system. + * Here, the thread is attempting to shut the machine down cleanly + * before the hardware based power-off event is triggered. + */ + +/* These settings are in celcius. We use these defaults only + * if we cannot interrogate the cpu-fru SEEPROM. + */ +struct temp_limits { + s8 high_pwroff, high_shutdown, high_warn; + s8 low_warn, low_shutdown, low_pwroff; +}; + +static struct temp_limits cpu_temp_limits[2] = { + { 100, 85, 80, 5, -5, -10 }, + { 100, 85, 80, 5, -5, -10 }, +}; + +static struct temp_limits amb_temp_limits[2] = { + { 65, 55, 40, 5, -5, -10 }, + { 65, 55, 40, 5, -5, -10 }, +}; + +enum fan_action { FAN_SLOWER, FAN_SAME, FAN_FASTER, FAN_FULLBLAST, FAN_STATE_MAX }; + +struct bbc_cpu_temperature { + struct bbc_cpu_temperature *next; + + struct bbc_i2c_client *client; + int index; + + /* Current readings, and history. */ + s8 curr_cpu_temp; + s8 curr_amb_temp; + s8 prev_cpu_temp; + s8 prev_amb_temp; + s8 avg_cpu_temp; + s8 avg_amb_temp; + + int sample_tick; + + enum fan_action fan_todo[2]; +#define FAN_AMBIENT 0 +#define FAN_CPU 1 +}; + +struct bbc_cpu_temperature *all_bbc_temps; + +struct bbc_fan_control { + struct bbc_fan_control *next; + + struct bbc_i2c_client *client; + int index; + + int psupply_fan_on; + int cpu_fan_speed; + int system_fan_speed; +}; + +struct bbc_fan_control *all_bbc_fans; + +#define CPU_FAN_REG 0xf0 +#define SYS_FAN_REG 0xf2 +#define PSUPPLY_FAN_REG 0xf4 + +#define FAN_SPEED_MIN 0x0c +#define FAN_SPEED_MAX 0x3f + +#define PSUPPLY_FAN_ON 0x1f +#define PSUPPLY_FAN_OFF 0x00 + +static void set_fan_speeds(struct bbc_fan_control *fp) +{ + /* Put temperatures into range so we don't mis-program + * the hardware. + */ + if (fp->cpu_fan_speed < FAN_SPEED_MIN) + fp->cpu_fan_speed = FAN_SPEED_MIN; + if (fp->cpu_fan_speed > FAN_SPEED_MAX) + fp->cpu_fan_speed = FAN_SPEED_MAX; + if (fp->system_fan_speed < FAN_SPEED_MIN) + fp->system_fan_speed = FAN_SPEED_MIN; + if (fp->system_fan_speed > FAN_SPEED_MAX) + fp->system_fan_speed = FAN_SPEED_MAX; +#ifdef ENVCTRL_TRACE + printk("fan%d: Changed fan speed to cpu(%02x) sys(%02x)\n", + fp->index, + fp->cpu_fan_speed, fp->system_fan_speed); +#endif + + bbc_i2c_writeb(fp->client, fp->cpu_fan_speed, CPU_FAN_REG); + bbc_i2c_writeb(fp->client, fp->system_fan_speed, SYS_FAN_REG); + bbc_i2c_writeb(fp->client, + (fp->psupply_fan_on ? + PSUPPLY_FAN_ON : PSUPPLY_FAN_OFF), + PSUPPLY_FAN_REG); +} + +static void get_current_temps(struct bbc_cpu_temperature *tp) +{ + tp->prev_amb_temp = tp->curr_amb_temp; + bbc_i2c_readb(tp->client, + (unsigned char *) &tp->curr_amb_temp, + MAX1617_AMB_TEMP); + tp->prev_cpu_temp = tp->curr_cpu_temp; + bbc_i2c_readb(tp->client, + (unsigned char *) &tp->curr_cpu_temp, + MAX1617_CPU_TEMP); +#ifdef ENVCTRL_TRACE + printk("temp%d: cpu(%d C) amb(%d C)\n", + tp->index, + (int) tp->curr_cpu_temp, (int) tp->curr_amb_temp); +#endif +} + + +static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp) +{ + static int shutting_down = 0; + static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; + char *argv[] = { "/sbin/shutdown", "-h", "now", NULL }; + char *type = "???"; + s8 val = -1; + + if (shutting_down != 0) + return; + + if (tp->curr_amb_temp >= amb_temp_limits[tp->index].high_shutdown || + tp->curr_amb_temp < amb_temp_limits[tp->index].low_shutdown) { + type = "ambient"; + val = tp->curr_amb_temp; + } else if (tp->curr_cpu_temp >= cpu_temp_limits[tp->index].high_shutdown || + tp->curr_cpu_temp < cpu_temp_limits[tp->index].low_shutdown) { + type = "CPU"; + val = tp->curr_cpu_temp; + } + + printk(KERN_CRIT "temp%d: Outside of safe %s " + "operating temperature, %d C.\n", + tp->index, type, val); + + printk(KERN_CRIT "kenvctrld: Shutting down the system now.\n"); + + shutting_down = 1; + if (execve("/sbin/shutdown", argv, envp) < 0) + printk(KERN_CRIT "envctrl: shutdown execution failed\n"); +} + +#define WARN_INTERVAL (30 * HZ) + +static void analyze_ambient_temp(struct bbc_cpu_temperature *tp, unsigned long *last_warn, int tick) +{ + int ret = 0; + + if (time_after(jiffies, (*last_warn + WARN_INTERVAL))) { + if (tp->curr_amb_temp >= + amb_temp_limits[tp->index].high_warn) { + printk(KERN_WARNING "temp%d: " + "Above safe ambient operating temperature, %d C.\n", + tp->index, (int) tp->curr_amb_temp); + ret = 1; + } else if (tp->curr_amb_temp < + amb_temp_limits[tp->index].low_warn) { + printk(KERN_WARNING "temp%d: " + "Below safe ambient operating temperature, %d C.\n", + tp->index, (int) tp->curr_amb_temp); + ret = 1; + } + if (ret) + *last_warn = jiffies; + } else if (tp->curr_amb_temp >= amb_temp_limits[tp->index].high_warn || + tp->curr_amb_temp < amb_temp_limits[tp->index].low_warn) + ret = 1; + + /* Now check the shutdown limits. */ + if (tp->curr_amb_temp >= amb_temp_limits[tp->index].high_shutdown || + tp->curr_amb_temp < amb_temp_limits[tp->index].low_shutdown) { + do_envctrl_shutdown(tp); + ret = 1; + } + + if (ret) { + tp->fan_todo[FAN_AMBIENT] = FAN_FULLBLAST; + } else if ((tick & (8 - 1)) == 0) { + s8 amb_goal_hi = amb_temp_limits[tp->index].high_warn - 10; + s8 amb_goal_lo; + + amb_goal_lo = amb_goal_hi - 3; + + /* We do not try to avoid 'too cold' events. Basically we + * only try to deal with over-heating and fan noise reduction. + */ + if (tp->avg_amb_temp < amb_goal_hi) { + if (tp->avg_amb_temp >= amb_goal_lo) + tp->fan_todo[FAN_AMBIENT] = FAN_SAME; + else + tp->fan_todo[FAN_AMBIENT] = FAN_SLOWER; + } else { + tp->fan_todo[FAN_AMBIENT] = FAN_FASTER; + } + } else { + tp->fan_todo[FAN_AMBIENT] = FAN_SAME; + } +} + +static void analyze_cpu_temp(struct bbc_cpu_temperature *tp, unsigned long *last_warn, int tick) +{ + int ret = 0; + + if (time_after(jiffies, (*last_warn + WARN_INTERVAL))) { + if (tp->curr_cpu_temp >= + cpu_temp_limits[tp->index].high_warn) { + printk(KERN_WARNING "temp%d: " + "Above safe CPU operating temperature, %d C.\n", + tp->index, (int) tp->curr_cpu_temp); + ret = 1; + } else if (tp->curr_cpu_temp < + cpu_temp_limits[tp->index].low_warn) { + printk(KERN_WARNING "temp%d: " + "Below safe CPU operating temperature, %d C.\n", + tp->index, (int) tp->curr_cpu_temp); + ret = 1; + } + if (ret) + *last_warn = jiffies; + } else if (tp->curr_cpu_temp >= cpu_temp_limits[tp->index].high_warn || + tp->curr_cpu_temp < cpu_temp_limits[tp->index].low_warn) + ret = 1; + + /* Now check the shutdown limits. */ + if (tp->curr_cpu_temp >= cpu_temp_limits[tp->index].high_shutdown || + tp->curr_cpu_temp < cpu_temp_limits[tp->index].low_shutdown) { + do_envctrl_shutdown(tp); + ret = 1; + } + + if (ret) { + tp->fan_todo[FAN_CPU] = FAN_FULLBLAST; + } else if ((tick & (8 - 1)) == 0) { + s8 cpu_goal_hi = cpu_temp_limits[tp->index].high_warn - 10; + s8 cpu_goal_lo; + + cpu_goal_lo = cpu_goal_hi - 3; + + /* We do not try to avoid 'too cold' events. Basically we + * only try to deal with over-heating and fan noise reduction. + */ + if (tp->avg_cpu_temp < cpu_goal_hi) { + if (tp->avg_cpu_temp >= cpu_goal_lo) + tp->fan_todo[FAN_CPU] = FAN_SAME; + else + tp->fan_todo[FAN_CPU] = FAN_SLOWER; + } else { + tp->fan_todo[FAN_CPU] = FAN_FASTER; + } + } else { + tp->fan_todo[FAN_CPU] = FAN_SAME; + } +} + +static void analyze_temps(struct bbc_cpu_temperature *tp, unsigned long *last_warn) +{ + tp->avg_amb_temp = (s8)((int)((int)tp->avg_amb_temp + (int)tp->curr_amb_temp) / 2); + tp->avg_cpu_temp = (s8)((int)((int)tp->avg_cpu_temp + (int)tp->curr_cpu_temp) / 2); + + analyze_ambient_temp(tp, last_warn, tp->sample_tick); + analyze_cpu_temp(tp, last_warn, tp->sample_tick); + + tp->sample_tick++; +} + +static enum fan_action prioritize_fan_action(int which_fan) +{ + struct bbc_cpu_temperature *tp; + enum fan_action decision = FAN_STATE_MAX; + + /* Basically, prioritize what the temperature sensors + * recommend we do, and perform that action on all the + * fans. + */ + for (tp = all_bbc_temps; tp; tp = tp->next) { + if (tp->fan_todo[which_fan] == FAN_FULLBLAST) { + decision = FAN_FULLBLAST; + break; + } + if (tp->fan_todo[which_fan] == FAN_SAME && + decision != FAN_FASTER) + decision = FAN_SAME; + else if (tp->fan_todo[which_fan] == FAN_FASTER) + decision = FAN_FASTER; + else if (decision != FAN_FASTER && + decision != FAN_SAME && + tp->fan_todo[which_fan] == FAN_SLOWER) + decision = FAN_SLOWER; + } + if (decision == FAN_STATE_MAX) + decision = FAN_SAME; + + return decision; +} + +static int maybe_new_ambient_fan_speed(struct bbc_fan_control *fp) +{ + enum fan_action decision = prioritize_fan_action(FAN_AMBIENT); + int ret; + + if (decision == FAN_SAME) + return 0; + + ret = 1; + if (decision == FAN_FULLBLAST) { + if (fp->system_fan_speed >= FAN_SPEED_MAX) + ret = 0; + else + fp->system_fan_speed = FAN_SPEED_MAX; + } else { + if (decision == FAN_FASTER) { + if (fp->system_fan_speed >= FAN_SPEED_MAX) + ret = 0; + else + fp->system_fan_speed += 2; + } else { + int orig_speed = fp->system_fan_speed; + + if (orig_speed <= FAN_SPEED_MIN || + orig_speed <= (fp->cpu_fan_speed - 3)) + ret = 0; + else + fp->system_fan_speed -= 1; + } + } + + return ret; +} + +static int maybe_new_cpu_fan_speed(struct bbc_fan_control *fp) +{ + enum fan_action decision = prioritize_fan_action(FAN_CPU); + int ret; + + if (decision == FAN_SAME) + return 0; + + ret = 1; + if (decision == FAN_FULLBLAST) { + if (fp->cpu_fan_speed >= FAN_SPEED_MAX) + ret = 0; + else + fp->cpu_fan_speed = FAN_SPEED_MAX; + } else { + if (decision == FAN_FASTER) { + if (fp->cpu_fan_speed >= FAN_SPEED_MAX) + ret = 0; + else { + fp->cpu_fan_speed += 2; + if (fp->system_fan_speed < + (fp->cpu_fan_speed - 3)) + fp->system_fan_speed = + fp->cpu_fan_speed - 3; + } + } else { + if (fp->cpu_fan_speed <= FAN_SPEED_MIN) + ret = 0; + else + fp->cpu_fan_speed -= 1; + } + } + + return ret; +} + +static void maybe_new_fan_speeds(struct bbc_fan_control *fp) +{ + int new; + + new = maybe_new_ambient_fan_speed(fp); + new |= maybe_new_cpu_fan_speed(fp); + + if (new) + set_fan_speeds(fp); +} + +static void fans_full_blast(void) +{ + struct bbc_fan_control *fp; + + /* Since we will not be monitoring things anymore, put + * the fans on full blast. + */ + for (fp = all_bbc_fans; fp; fp = fp->next) { + fp->cpu_fan_speed = FAN_SPEED_MAX; + fp->system_fan_speed = FAN_SPEED_MAX; + fp->psupply_fan_on = 1; + set_fan_speeds(fp); + } +} + +#define POLL_INTERVAL (5 * HZ) +static unsigned long last_warning_jiffies; +static struct task_struct *kenvctrld_task; + +static int kenvctrld(void *__unused) +{ + daemonize(); + strcpy(current->comm, "kenvctrld"); + kenvctrld_task = current; + + printk(KERN_INFO "bbc_envctrl: kenvctrld starting...\n"); + last_warning_jiffies = jiffies - WARN_INTERVAL; + for (;;) { + struct bbc_cpu_temperature *tp; + struct bbc_fan_control *fp; + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(POLL_INTERVAL); + current->state = TASK_RUNNING; + if (signal_pending(current)) + break; + + for (tp = all_bbc_temps; tp; tp = tp->next) { + get_current_temps(tp); + analyze_temps(tp, &last_warning_jiffies); + } + for (fp = all_bbc_fans; fp; fp = fp->next) + maybe_new_fan_speeds(fp); + } + printk(KERN_INFO "bbc_envctrl: kenvctrld exiting...\n"); + + fans_full_blast(); + + return 0; +} + +static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx) +{ + struct bbc_cpu_temperature *tp = kmalloc(sizeof(*tp), GFP_KERNEL); + + if (!tp) + return; + memset(tp, 0, sizeof(*tp)); + tp->client = bbc_i2c_attach(echild); + if (!tp->client) { + kfree(tp); + return; + } + + tp->index = temp_idx; + { + struct bbc_cpu_temperature **tpp = &all_bbc_temps; + while (*tpp) + tpp = &((*tpp)->next); + tp->next = NULL; + *tpp = tp; + } + + /* Tell it to convert once every 5 seconds, clear all cfg + * bits. + */ + bbc_i2c_writeb(tp->client, 0x00, MAX1617_WR_CFG_BYTE); + bbc_i2c_writeb(tp->client, 0x02, MAX1617_WR_CVRATE_BYTE); + + /* Program the hard temperature limits into the chip. */ + bbc_i2c_writeb(tp->client, amb_temp_limits[tp->index].high_pwroff, + MAX1617_WR_AMB_HIGHLIM); + bbc_i2c_writeb(tp->client, amb_temp_limits[tp->index].low_pwroff, + MAX1617_WR_AMB_LOWLIM); + bbc_i2c_writeb(tp->client, cpu_temp_limits[tp->index].high_pwroff, + MAX1617_WR_CPU_HIGHLIM); + bbc_i2c_writeb(tp->client, cpu_temp_limits[tp->index].low_pwroff, + MAX1617_WR_CPU_LOWLIM); + + get_current_temps(tp); + tp->prev_cpu_temp = tp->avg_cpu_temp = tp->curr_cpu_temp; + tp->prev_amb_temp = tp->avg_amb_temp = tp->curr_amb_temp; + + tp->fan_todo[FAN_AMBIENT] = FAN_SAME; + tp->fan_todo[FAN_CPU] = FAN_SAME; +} + +static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx) +{ + struct bbc_fan_control *fp = kmalloc(sizeof(*fp), GFP_KERNEL); + + if (!fp) + return; + memset(fp, 0, sizeof(*fp)); + fp->client = bbc_i2c_attach(echild); + if (!fp->client) { + kfree(fp); + return; + } + + fp->index = fan_idx; + + { + struct bbc_fan_control **fpp = &all_bbc_fans; + while (*fpp) + fpp = &((*fpp)->next); + fp->next = NULL; + *fpp = fp; + } + + /* The i2c device controlling the fans is write-only. + * So the only way to keep track of the current power + * level fed to the fans is via software. Choose half + * power for cpu/system and 'on' fo the powersupply fan + * and set it now. + */ + fp->psupply_fan_on = 1; + fp->cpu_fan_speed = (FAN_SPEED_MAX - FAN_SPEED_MIN) / 2; + fp->cpu_fan_speed += FAN_SPEED_MIN; + fp->system_fan_speed = (FAN_SPEED_MAX - FAN_SPEED_MIN) / 2; + fp->system_fan_speed += FAN_SPEED_MIN; + + set_fan_speeds(fp); +} + +void bbc_envctrl_init(void) +{ + struct linux_ebus_child *echild; + int temp_index = 0; + int fan_index = 0; + int devidx = 0; + + while ((echild = bbc_i2c_getdev(devidx++)) != NULL) { + if (!strcmp(echild->prom_name, "temperature")) + attach_one_temp(echild, temp_index++); + if (!strcmp(echild->prom_name, "fan-control")) + attach_one_fan(echild, fan_index++); + } + if (temp_index != 0 && fan_index != 0) + kernel_thread(kenvctrld, NULL, CLONE_FS | CLONE_FILES); +} + +static void destroy_one_temp(struct bbc_cpu_temperature *tp) +{ + bbc_i2c_detach(tp->client); + kfree(tp); +} + +static void destroy_one_fan(struct bbc_fan_control *fp) +{ + bbc_i2c_detach(fp->client); + kfree(fp); +} + +void bbc_envctrl_cleanup(void) +{ + struct bbc_cpu_temperature *tp; + struct bbc_fan_control *fp; + + if (kenvctrld_task != NULL) { + force_sig(SIGKILL, kenvctrld_task); + for (;;) { + struct task_struct *p; + int found = 0; + + read_lock(&tasklist_lock); + for_each_task(p) { + if (p == kenvctrld_task) { + found = 1; + break; + } + } + read_unlock(&tasklist_lock); + if (!found) + break; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ); + current->state = TASK_RUNNING; + } + kenvctrld_task = NULL; + } + + tp = all_bbc_temps; + while (tp != NULL) { + struct bbc_cpu_temperature *next = tp->next; + destroy_one_temp(tp); + tp = next; + } + all_bbc_temps = NULL; + + fp = all_bbc_fans; + while (fp != NULL) { + struct bbc_fan_control *next = fp->next; + destroy_one_fan(fp); + fp = next; + } + all_bbc_fans = NULL; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sbus/char/bbc_i2c.c linux.ac/drivers/sbus/char/bbc_i2c.c --- linux.vanilla/drivers/sbus/char/bbc_i2c.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sbus/char/bbc_i2c.c Sat Apr 14 01:29:06 2001 @@ -0,0 +1,482 @@ +/* $Id: bbc_i2c.c,v 1.2 2001/04/02 09:59:08 davem Exp $ + * bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III + * platforms. + * + * Copyright (C) 2001 David S. Miller (davem@redhat.com) + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/wait.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <asm/oplib.h> +#include <asm/ebus.h> +#include <asm/spitfire.h> +#include <asm/bbc.h> + +#include "bbc_i2c.h" + +/* Convert this driver to use i2c bus layer someday... */ +#define I2C_PCF_PIN 0x80 +#define I2C_PCF_ESO 0x40 +#define I2C_PCF_ES1 0x20 +#define I2C_PCF_ES2 0x10 +#define I2C_PCF_ENI 0x08 +#define I2C_PCF_STA 0x04 +#define I2C_PCF_STO 0x02 +#define I2C_PCF_ACK 0x01 + +#define I2C_PCF_START (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ENI | I2C_PCF_STA | I2C_PCF_ACK) +#define I2C_PCF_STOP (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK) +#define I2C_PCF_REPSTART ( I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK) +#define I2C_PCF_IDLE (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ACK) + +#define I2C_PCF_INI 0x40 /* 1 if not initialized */ +#define I2C_PCF_STS 0x20 +#define I2C_PCF_BER 0x10 +#define I2C_PCF_AD0 0x08 +#define I2C_PCF_LRB 0x08 +#define I2C_PCF_AAS 0x04 +#define I2C_PCF_LAB 0x02 +#define I2C_PCF_BB 0x01 + +/* The BBC devices have two I2C controllers. The first I2C controller + * connects mainly to configuration proms (NVRAM, cpu configuration, + * dimm types, etc.). Whereas the second I2C controller connects to + * environmental control devices such as fans and temperature sensors. + * The second controller also connects to the smartcard reader, if present. + */ + +#define NUM_CHILDREN 8 +struct bbc_i2c_bus { + struct bbc_i2c_bus *next; + int index; + spinlock_t lock; + void *i2c_bussel_reg; + void *i2c_control_regs; + unsigned char own, clock; + + wait_queue_head_t wq; + volatile int waiting; + + struct linux_ebus_device *bus_edev; + struct { + struct linux_ebus_child *device; + int client_claimed; + } devs[NUM_CHILDREN]; +}; + +static struct bbc_i2c_bus *all_bbc_i2c; + +struct bbc_i2c_client { + struct bbc_i2c_bus *bp; + struct linux_ebus_child *echild; + int bus; + int address; +}; + +static int find_device(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild) +{ + int i; + + for (i = 0; i < NUM_CHILDREN; i++) { + if (bp->devs[i].device == echild) { + if (bp->devs[i].client_claimed) + return 0; + return 1; + } + } + return 0; +} + +static void set_device_claimage(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild, int val) +{ + int i; + + for (i = 0; i < NUM_CHILDREN; i++) { + if (bp->devs[i].device == echild) { + bp->devs[i].client_claimed = val; + return; + } + } +} + +#define claim_device(BP,ECHILD) set_device_claimage(BP,ECHILD,1) +#define release_device(BP,ECHILD) set_device_claimage(BP,ECHILD,0) + +static struct bbc_i2c_bus *find_bus_for_device(struct linux_ebus_child *echild) +{ + struct bbc_i2c_bus *bp = all_bbc_i2c; + + while (bp != NULL) { + if (find_device(bp, echild) != 0) + break; + bp = bp->next; + } + + return bp; +} + +struct linux_ebus_child *bbc_i2c_getdev(int index) +{ + struct bbc_i2c_bus *bp = all_bbc_i2c; + struct linux_ebus_child *echild = NULL; + int curidx = 0; + + while (bp != NULL) { + struct bbc_i2c_bus *next = bp->next; + int i; + + for (i = 0; i < NUM_CHILDREN; i++) { + if (!(echild = bp->devs[i].device)) + break; + if (curidx == index) + goto out; + echild = NULL; + curidx++; + } + bp = next; + } +out: + if (curidx == index) + return echild; + return NULL; +} + +struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild) +{ + struct bbc_i2c_bus *bp = find_bus_for_device(echild); + struct bbc_i2c_client *client; + + if (!bp) + return NULL; + client = kmalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return NULL; + memset(client, 0, sizeof(*client)); + client->bp = bp; + client->echild = echild; + client->bus = echild->resource[0].start; + client->address = echild->resource[1].start; + + claim_device(bp, echild); + + return client; +} + +void bbc_i2c_detach(struct bbc_i2c_client *client) +{ + struct bbc_i2c_bus *bp = client->bp; + struct linux_ebus_child *echild = client->echild; + + release_device(bp, echild); + kfree(client); +} + +static int wait_for_pin(struct bbc_i2c_bus *bp, u8 *status) +{ + DECLARE_WAITQUEUE(wait, current); + int limit = 32; + int ret = 1; + + bp->waiting = 1; + add_wait_queue(&bp->wq, &wait); + while (limit-- > 0) { + u8 val; + + current->state = TASK_INTERRUPTIBLE; + *status = val = readb(bp->i2c_control_regs + 0); + if ((val & I2C_PCF_PIN) == 0) { + ret = 0; + break; + } + schedule_timeout(HZ/4); + } + remove_wait_queue(&bp->wq, &wait); + bp->waiting = 0; + current->state = TASK_RUNNING; + + return ret; +} + +int bbc_i2c_writeb(struct bbc_i2c_client *client, unsigned char val, int off) +{ + struct bbc_i2c_bus *bp = client->bp; + int address = client->address; + u8 status; + int ret = -1; + + if (bp->i2c_bussel_reg != NULL) + writeb(client->bus, bp->i2c_bussel_reg); + + writeb(address, bp->i2c_control_regs + 0x1); + writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0); + if (wait_for_pin(bp, &status)) + goto out; + + writeb(off, bp->i2c_control_regs + 0x1); + if (wait_for_pin(bp, &status) || + (status & I2C_PCF_LRB) != 0) + goto out; + + writeb(val, bp->i2c_control_regs + 0x1); + if (wait_for_pin(bp, &status)) + goto out; + + ret = 0; + +out: + writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0); + return ret; +} + +int bbc_i2c_readb(struct bbc_i2c_client *client, unsigned char *byte, int off) +{ + struct bbc_i2c_bus *bp = client->bp; + unsigned char address = client->address, status; + int ret = -1; + + if (bp->i2c_bussel_reg != NULL) + writeb(client->bus, bp->i2c_bussel_reg); + + writeb(address, bp->i2c_control_regs + 0x1); + writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0); + if (wait_for_pin(bp, &status)) + goto out; + + writeb(off, bp->i2c_control_regs + 0x1); + if (wait_for_pin(bp, &status) || + (status & I2C_PCF_LRB) != 0) + goto out; + + writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0); + + address |= 0x1; /* READ */ + + writeb(address, bp->i2c_control_regs + 0x1); + writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0); + if (wait_for_pin(bp, &status)) + goto out; + + /* Set PIN back to one so the device sends the first + * byte. + */ + (void) readb(bp->i2c_control_regs + 0x1); + if (wait_for_pin(bp, &status)) + goto out; + + writeb(I2C_PCF_ESO | I2C_PCF_ENI, bp->i2c_control_regs + 0x0); + *byte = readb(bp->i2c_control_regs + 0x1); + if (wait_for_pin(bp, &status)) + goto out; + + ret = 0; + +out: + writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0); + (void) readb(bp->i2c_control_regs + 0x1); + + return ret; +} + +int bbc_i2c_write_buf(struct bbc_i2c_client *client, + char *buf, int len, int off) +{ + int ret = 0; + + while (len > 0) { + int err = bbc_i2c_writeb(client, *buf, off); + + if (err < 0) { + ret = err; + break; + } + + len--; + buf++; + off++; + } + return ret; +} + +int bbc_i2c_read_buf(struct bbc_i2c_client *client, + char *buf, int len, int off) +{ + int ret = 0; + + while (len > 0) { + int err = bbc_i2c_readb(client, buf, off); + if (err < 0) { + ret = err; + break; + } + len--; + buf++; + off++; + } + + return ret; +} + +EXPORT_SYMBOL(bbc_i2c_getdev); +EXPORT_SYMBOL(bbc_i2c_attach); +EXPORT_SYMBOL(bbc_i2c_detach); +EXPORT_SYMBOL(bbc_i2c_writeb); +EXPORT_SYMBOL(bbc_i2c_readb); +EXPORT_SYMBOL(bbc_i2c_write_buf); +EXPORT_SYMBOL(bbc_i2c_read_buf); + +static void bbc_i2c_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct bbc_i2c_bus *bp = dev_id; + + /* PIN going from set to clear is the only event which + * makes the i2c assert an interrupt. + */ + if (bp->waiting && + !(readb(bp->i2c_control_regs + 0x0) & I2C_PCF_PIN)) + wake_up(&bp->wq); +} + +static void __init reset_one_i2c(struct bbc_i2c_bus *bp) +{ + writeb(I2C_PCF_PIN, bp->i2c_control_regs + 0x0); + writeb(bp->own, bp->i2c_control_regs + 0x1); + writeb(I2C_PCF_PIN | I2C_PCF_ES1, bp->i2c_control_regs + 0x0); + writeb(bp->clock, bp->i2c_control_regs + 0x1); + writeb(I2C_PCF_IDLE, bp->i2c_control_regs + 0x0); +} + +static int __init attach_one_i2c(struct linux_ebus_device *edev, int index) +{ + struct bbc_i2c_bus *bp = kmalloc(sizeof(*bp), GFP_KERNEL); + struct linux_ebus_child *echild; + int entry; + + if (!bp) + return -ENOMEM; + memset(bp, 0, sizeof(*bp)); + + bp->i2c_control_regs = ioremap(edev->resource[0].start, 0x2); + if (!bp->i2c_control_regs) + goto fail; + + if (edev->num_addrs == 2) { + bp->i2c_bussel_reg = ioremap(edev->resource[1].start, 0x1); + if (!bp->i2c_bussel_reg) + goto fail; + } + + bp->waiting = 0; + init_waitqueue_head(&bp->wq); + if (request_irq(edev->irqs[0], bbc_i2c_interrupt, + SA_SHIRQ, "bbc_i2c", bp)) + goto fail; + + bp->index = index; + bp->bus_edev = edev; + + spin_lock_init(&bp->lock); + bp->next = all_bbc_i2c; + all_bbc_i2c = bp; + + entry = 0; + for (echild = edev->children; + echild && entry < 8; + echild = echild->next, entry++) { + bp->devs[entry].device = echild; + bp->devs[entry].client_claimed = 0; + } + + writeb(I2C_PCF_PIN, bp->i2c_control_regs + 0x0); + bp->own = readb(bp->i2c_control_regs + 0x01); + writeb(I2C_PCF_PIN | I2C_PCF_ES1, bp->i2c_control_regs + 0x0); + bp->clock = readb(bp->i2c_control_regs + 0x01); + + printk(KERN_INFO "i2c-%d: Regs at %p, %d devices, own %02x, clock %02x.\n", + bp->index, bp->i2c_control_regs, entry, bp->own, bp->clock); + + reset_one_i2c(bp); + + return 0; + +fail: + if (bp->i2c_bussel_reg) + iounmap(bp->i2c_bussel_reg); + if (bp->i2c_control_regs) + iounmap(bp->i2c_control_regs); + kfree(bp); + return -EINVAL; +} + +static int __init bbc_present(void) +{ + struct linux_ebus *ebus = NULL; + struct linux_ebus_device *edev = NULL; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_name, "bbc")) + return 1; + } + } + return 0; +} + +extern void bbc_envctrl_init(void); +extern void bbc_envctrl_cleanup(void); + +static int __init bbc_i2c_init(void) +{ + struct linux_ebus *ebus = NULL; + struct linux_ebus_device *edev = NULL; + int index = 0; + + if (tlb_type != cheetah || !bbc_present()) + return -ENODEV; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_name, "i2c")) { + if (!attach_one_i2c(edev, index)) + index++; + } + } + } + + if (!index) + return -ENODEV; + + bbc_envctrl_init(); + return 0; +} + +static void __exit bbc_i2c_cleanup(void) +{ + struct bbc_i2c_bus *bp = all_bbc_i2c; + + bbc_envctrl_cleanup(); + + while (bp != NULL) { + struct bbc_i2c_bus *next = bp->next; + + free_irq(bp->bus_edev->irqs[0], bp); + + if (bp->i2c_bussel_reg) + iounmap(bp->i2c_bussel_reg); + if (bp->i2c_control_regs) + iounmap(bp->i2c_control_regs); + + kfree(bp); + + bp = next; + } + all_bbc_i2c = NULL; +} + +module_init(bbc_i2c_init); +module_exit(bbc_i2c_cleanup); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sbus/char/bbc_i2c.h linux.ac/drivers/sbus/char/bbc_i2c.h --- linux.vanilla/drivers/sbus/char/bbc_i2c.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sbus/char/bbc_i2c.h Sat Apr 14 01:29:06 2001 @@ -0,0 +1,20 @@ +/* $Id: bbc_i2c.h,v 1.2 2001/04/02 09:59:25 davem Exp $ */ +#ifndef _BBC_I2C_H +#define _BBC_I2C_H + +#include <asm/ebus.h> + +struct bbc_i2c_client; + +/* Probing and attachment. */ +extern struct linux_ebus_child *bbc_i2c_getdev(int); +extern struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *); +extern void bbc_i2c_detach(struct bbc_i2c_client *); + +/* Register read/write. NOTE: Blocking! */ +extern int bbc_i2c_writeb(struct bbc_i2c_client *, unsigned char val, int off); +extern int bbc_i2c_readb(struct bbc_i2c_client *, unsigned char *byte, int off); +extern int bbc_i2c_write_buf(struct bbc_i2c_client *, char *buf, int len, int off); +extern int bbc_i2c_read_buf(struct bbc_i2c_client *, char *buf, int len, int off); + +#endif /* _BBC_I2C_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sbus/char/cpwatchdog.c linux.ac/drivers/sbus/char/cpwatchdog.c --- linux.vanilla/drivers/sbus/char/cpwatchdog.c Tue Apr 3 17:32:17 2001 +++ linux.ac/drivers/sbus/char/cpwatchdog.c Sat Apr 14 01:29:06 2001 @@ -199,7 +199,9 @@ /* Forward declarations of internal methods */ +#ifdef WD_DEBUG static void wd_dumpregs(void); +#endif static void wd_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void wd_toggleintr(struct wd_timer* pTimer, int enable); static void wd_pingtimer(struct wd_timer* pTimer); @@ -471,6 +473,7 @@ static struct miscdevice wd1_miscdev = { WD1_MINOR, WD1_DEVNAME, &wd_fops }; static struct miscdevice wd2_miscdev = { WD2_MINOR, WD2_DEVNAME, &wd_fops }; +#ifdef WD_DEBUG static void wd_dumpregs(void) { /* Reading from downcounters initiates watchdog countdown-- @@ -507,6 +510,7 @@ (unsigned long)(&wd_dev.regs->pld_regs.status), readb(&wd_dev.regs->pld_regs.status)); } +#endif /* Enable or disable watchdog interrupts * Because of the CP1400 defect this should only be diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sbus/char/max1617.h linux.ac/drivers/sbus/char/max1617.h --- linux.vanilla/drivers/sbus/char/max1617.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sbus/char/max1617.h Sat Apr 14 01:29:06 2001 @@ -0,0 +1,27 @@ +/* $Id: max1617.h,v 1.1 2001/04/02 09:59:08 davem Exp $ */ +#ifndef _MAX1617_H +#define _MAX1617_H + +#define MAX1617_AMB_TEMP 0x00 /* Ambient temp in C */ +#define MAX1617_CPU_TEMP 0x01 /* Processor die temp in C */ +#define MAX1617_STATUS 0x02 /* Chip status bits */ + +/* Read-only versions of changable registers. */ +#define MAX1617_RD_CFG_BYTE 0x03 /* Config register */ +#define MAX1617_RD_CVRATE_BYTE 0x04 /* Temp conversion rate */ +#define MAX1617_RD_AMB_HIGHLIM 0x05 /* Ambient high limit */ +#define MAX1617_RD_AMB_LOWLIM 0x06 /* Ambient low limit */ +#define MAX1617_RD_CPU_HIGHLIM 0x07 /* Processor high limit */ +#define MAX1617_RD_CPU_LOWLIM 0x08 /* Processor low limit */ + +/* Write-only versions of the same. */ +#define MAX1617_WR_CFG_BYTE 0x09 +#define MAX1617_WR_CVRATE_BYTE 0x0a +#define MAX1617_WR_AMB_HIGHLIM 0x0b +#define MAX1617_WR_AMB_LOWLIM 0x0c +#define MAX1617_WR_CPU_HIGHLIM 0x0d +#define MAX1617_WR_CPU_LOWLIM 0x0e + +#define MAX1617_ONESHOT 0x0f + +#endif /* _MAX1617_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sbus/char/riowatchdog.c linux.ac/drivers/sbus/char/riowatchdog.c --- linux.vanilla/drivers/sbus/char/riowatchdog.c Tue Apr 3 17:32:17 2001 +++ linux.ac/drivers/sbus/char/riowatchdog.c Sat Apr 14 01:29:06 2001 @@ -1,4 +1,4 @@ -/* $Id: riowatchdog.c,v 1.1 2001/03/24 06:04:24 davem Exp $ +/* $Id: riowatchdog.c,v 1.2 2001/03/26 23:47:18 davem Exp $ * riowatchdog.c - driver for hw watchdog inside Super I/O of RIO * * Copyright (C) 2001 David S. Miller (davem@redhat.com) @@ -24,10 +24,9 @@ * as its' watchdog. * * When the watchdog triggers, it asserts a line to the BBC (Boot Bus - * Controller) of the machine. The BBC can be configured to treat the - * assertion of this signal in different ways. It can trigger an XIR - * (external CPU reset) to all the processors or it can trigger a true - * power-on reset which triggers the RST signal of all devices in the machine. + * Controller) of the machine. The BBC can only be configured to + * trigger a power-on reset when the signal is asserted. The BBC + * can be configured to ignore the signal entirely as well. * * The only Super I/O device register we care about is at index * 0x05 (WDTO_INDEX) which is the watchdog time-out in minutes (1-255). @@ -54,15 +53,13 @@ static spinlock_t riowd_lock = SPIN_LOCK_UNLOCKED; +static void *bbc_regs; static void *riowd_regs; #define WDTO_INDEX 0x05 static int riowd_timeout = 1; /* in minutes */ -static int riowd_xir = 1; /* watchdog generates XIR? */ MODULE_PARM(riowd_timeout,"i"); MODULE_PARM_DESC(riowd_timeout, "Watchdog timeout in minutes"); -MODULE_PARM(riowd_xir,"i"); -MODULE_PARM_DESC(riowd_xir, "Watchdog generates XIR reset if non-zero"); #if 0 /* Currently unused. */ static u8 riowd_readreg(int index) @@ -96,12 +93,24 @@ static void riowd_stoptimer(void) { + u8 val; + riowd_writereg(0, WDTO_INDEX); + + val = readb(bbc_regs + BBC_WDACTION); + val &= ~BBC_WDACTION_RST; + writeb(val, bbc_regs + BBC_WDACTION); } static void riowd_starttimer(void) { + u8 val; + riowd_writereg(riowd_timeout, WDTO_INDEX); + + val = readb(bbc_regs + BBC_WDACTION); + val |= BBC_WDACTION_RST; + writeb(val, bbc_regs + BBC_WDACTION); } static int riowd_open(struct inode *inode, struct file *filp) @@ -189,7 +198,6 @@ { struct linux_ebus *ebus = NULL; struct linux_ebus_device *edev = NULL; - void *bbc_regs; u8 val; for_each_ebus(ebus) { @@ -206,14 +214,11 @@ if (!bbc_regs) return -ENODEV; + /* Turn it off. */ val = readb(bbc_regs + BBC_WDACTION); - if (riowd_xir != 0) - val &= ~BBC_WDACTION_RST; - else - val |= BBC_WDACTION_RST; + val &= ~BBC_WDACTION_RST; writeb(val, bbc_regs + BBC_WDACTION); - iounmap(bbc_regs); return 0; } @@ -249,10 +254,8 @@ goto fail; } - printk(KERN_INFO "pmc: Hardware watchdog [%i minutes, %s reset], " - "regs at %p\n", - riowd_timeout, (riowd_xir ? "XIR" : "POR"), - riowd_regs); + printk(KERN_INFO "pmc: Hardware watchdog [%i minutes], " + "regs at %p\n", riowd_timeout, riowd_regs); return 0; @@ -261,6 +264,10 @@ iounmap(riowd_regs); riowd_regs = NULL; } + if (bbc_regs) { + iounmap(bbc_regs); + bbc_regs = NULL; + } return -ENODEV; } @@ -269,6 +276,8 @@ misc_deregister(&riowd_miscdev); iounmap(riowd_regs); riowd_regs = NULL; + iounmap(bbc_regs); + bbc_regs = NULL; } module_init(riowd_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sbus/char/sunkbd.c linux.ac/drivers/sbus/char/sunkbd.c --- linux.vanilla/drivers/sbus/char/sunkbd.c Mon Jan 22 21:30:20 2001 +++ linux.ac/drivers/sbus/char/sunkbd.c Tue Apr 3 17:54:59 2001 @@ -514,7 +514,7 @@ } do_poke_blanked_console = 1; - tasklet_schedule(&console_tasklet); + schedule_console_callback(); add_keyboard_randomness(keycode); tty = ttytab? ttytab[fg_console]: NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/53c7,8xx.c linux.ac/drivers/scsi/53c7,8xx.c --- linux.vanilla/drivers/scsi/53c7,8xx.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/scsi/53c7,8xx.c Thu Apr 12 12:04:02 2001 @@ -175,7 +175,7 @@ * Architecture : * This driver is built around a Linux queue of commands waiting to * be executed, and a shared Linux/NCR array of commands to start. Commands - * are transfered to the array by the run_process_issue_queue() function + * are transferred to the array by the run_process_issue_queue() function * which is called whenever a command completes. * * As commands are completed, the interrupt routine is triggered, @@ -1899,7 +1899,6 @@ hostdata->script, start); printk ("scsi%d : DSPS = 0x%x\n", host->host_no, NCR53c7x0_read32(DSPS_REG)); - restore_flags(flags); return -1; } hostdata->test_running = 0; @@ -5272,7 +5271,7 @@ * chances of this happening, and handle it if it occurs anyway. * * Simply continue with what we were doing, and control should - * be transfered to the schedule routine which will ultimately + * be transferred to the schedule routine which will ultimately * pass control onto the reselection or selection (not yet) * code. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/53c7,8xx.h linux.ac/drivers/scsi/53c7,8xx.h --- linux.vanilla/drivers/scsi/53c7,8xx.h Mon Dec 11 21:19:31 2000 +++ linux.ac/drivers/scsi/53c7,8xx.h Thu Apr 12 12:04:02 2001 @@ -1515,11 +1515,11 @@ /* Patch field in dsa structure (assignment should be +=?) */ #define patch_dsa_32(dsa, symbol, word, value) \ { \ - (dsa)[(hostdata->##symbol - hostdata->dsa_start) / sizeof(u32) \ + (dsa)[(hostdata->symbol - hostdata->dsa_start) / sizeof(u32) \ + (word)] = (value); \ if (hostdata->options & OPTION_DEBUG_DSA) \ printk("scsi : dsa %s symbol %s(%d) word %d now 0x%x\n", \ - #dsa, #symbol, hostdata->##symbol, \ + #dsa, #symbol, hostdata->symbol, \ (word), (u32) le32_to_cpu(value)); \ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/53c7xx.c linux.ac/drivers/scsi/53c7xx.c --- linux.vanilla/drivers/scsi/53c7xx.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/scsi/53c7xx.c Tue Apr 3 17:54:59 2001 @@ -198,7 +198,7 @@ * Architecture : * This driver is built around a Linux queue of commands waiting to * be executed, and a shared Linux/NCR array of commands to start. Commands - * are transfered to the array by the run_process_issue_queue() function + * are transferred to the array by the run_process_issue_queue() function * which is called whenever a command completes. * * As commands are completed, the interrupt routine is triggered, @@ -1077,19 +1077,18 @@ { printk("scsi%d : IRQ%d not free, detaching\n", host->host_no, host->irq); - scsi_unregister (host); - return -1; + goto err_unregister; } if ((hostdata->run_tests && hostdata->run_tests(host) == -1) || (hostdata->options & OPTION_DEBUG_TESTS_ONLY)) { /* XXX Should disable interrupts, etc. here */ - scsi_unregister (host); - return -1; + goto err_free_irq; } else { if (host->io_port) { host->n_io_port = 128; - request_region (host->io_port, host->n_io_port, "ncr53c7xx"); + if (!request_region (host->io_port, host->n_io_port, "ncr53c7xx")) + goto err_free_irq; } } @@ -1098,6 +1097,12 @@ hard_reset (host); } return 0; + + err_free_irq: + free_irq(host->irq, NCR53c7x0_intr); + err_unregister: + scsi_unregister(host); + return -1; } /* @@ -1206,8 +1211,11 @@ size += 256; #endif /* Size should be < 8K, so we can fit it in two pages. */ - if (size > 8192) - panic("53c7xx: hostdata > 8K"); + if (size > 8192) { + printk(KERN_ERR "53c7xx: hostdata > 8K\n"); + return -1; + } + instance = scsi_register (tpnt, 4); if (!instance) { @@ -3091,8 +3099,10 @@ #endif /* FIXME: for ISA bus '7xx chips, we need to or GFP_DMA in here */ - if (size > 4096) - panic ("53c7xx: allocate_cmd size > 4K"); + if (size > 4096) { + printk (KERN_ERR "53c7xx: allocate_cmd size > 4K\n"); + return NULL; + } real = get_free_page(GFP_ATOMIC); if (real == 0) return NULL; @@ -3272,7 +3282,7 @@ /* * The saved data pointer is set up so that a RESTORE POINTERS message - * will start the data transfer over at the begining. + * will start the data transfer over at the beginning. */ tmp->saved_data_pointer = virt_to_bus (hostdata->script) + @@ -4965,7 +4975,7 @@ * chances of this happening, and handle it if it occurs anyway. * * Simply continue with what we were doing, and control should - * be transfered to the schedule routine which will ultimately + * be transferred to the schedule routine which will ultimately * pass control onto the reselection or selection (not yet) * code. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/53c7xx.scr linux.ac/drivers/scsi/53c7xx.scr --- linux.vanilla/drivers/scsi/53c7xx.scr Sat Mar 21 19:09:47 1998 +++ linux.ac/drivers/scsi/53c7xx.scr Tue Apr 3 17:54:59 2001 @@ -1136,7 +1136,7 @@ #if (CHIP == 710) #if defined(MVME16x_INTFLY) ; For MVME16x (ie CHIP=710) we will force an INTFLY by triggering a software -; interupt (SW7). We can use SCRATCH, as we are about to jump to +; interrupt (SW7). We can use SCRATCH, as we are about to jump to ; schedule, which corrupts it anyway. Will probably remove this later, ; but want to check performance effects first. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/BusLogic.c linux.ac/drivers/scsi/BusLogic.c --- linux.vanilla/drivers/scsi/BusLogic.c Sun Nov 12 03:01:11 2000 +++ linux.ac/drivers/scsi/BusLogic.c Tue Apr 3 17:54:59 2001 @@ -770,15 +770,19 @@ BusLogic_ModifyIOAddressRequest_T ModifyIOAddressRequest; unsigned char Bus = PCI_Device->bus->number; unsigned char Device = PCI_Device->devfn >> 3; - unsigned int IRQ_Channel = PCI_Device->irq; - unsigned long BaseAddress0 = pci_resource_start(PCI_Device, 0); - unsigned long BaseAddress1 = pci_resource_start(PCI_Device, 1); - BusLogic_IO_Address_T IO_Address = BaseAddress0; - BusLogic_PCI_Address_T PCI_Address = BaseAddress1; + unsigned int IRQ_Channel; + unsigned long BaseAddress0; + unsigned long BaseAddress1; + BusLogic_IO_Address_T IO_Address; + BusLogic_PCI_Address_T PCI_Address; if (pci_enable_device(PCI_Device)) continue; + IRQ_Channel = PCI_Device->irq; + IO_Address = BaseAddress0 = pci_resource_start(PCI_Device, 0); + PCI_Address = BaseAddress1 = pci_resource_start(PCI_Device, 1); + if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM) { BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for " @@ -2547,7 +2551,7 @@ int SynchronousTransferRate = 0; if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { - boolean WideTransfersActive; + unsigned char WideTransfersActive; FlashPoint_InquireTargetInfo( HostAdapter->CardHandle, TargetID, &HostAdapter->SynchronousPeriod[TargetID], diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/BusLogic.h linux.ac/drivers/scsi/BusLogic.h --- linux.vanilla/drivers/scsi/BusLogic.h Mon Dec 11 21:18:58 2000 +++ linux.ac/drivers/scsi/BusLogic.h Tue Apr 3 18:15:45 2001 @@ -78,6 +78,7 @@ reset: BusLogic_ResetCommand, /* Reset Command Function */ \ bios_param: BusLogic_BIOSDiskParameters, /* BIOS Disk Parameters */ \ unchecked_isa_dma: 1, /* Default Initial Value */ \ + max_sectors: 128, /* I/O queue len limit */ \ use_clustering: ENABLE_CLUSTERING } /* Enable Clustering */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/ChangeLog.ncr53c8xx linux.ac/drivers/scsi/ChangeLog.ncr53c8xx --- linux.vanilla/drivers/scsi/ChangeLog.ncr53c8xx Tue Apr 3 17:32:18 2001 +++ linux.ac/drivers/scsi/ChangeLog.ncr53c8xx Tue Apr 3 17:54:59 2001 @@ -238,7 +238,7 @@ - Changes from Eddie Dost for Sparc and Alpha: ioremap/iounmap support for Sparc. pcivtophys changed to bus_dvma_to_phys. - - Add the 53c876 description to the chip table. This is only usefull + - Add the 53c876 description to the chip table. This is only useful for printing the right name of the controller. - DEL-441 Item 2 work-around for the 53c876 rev <= 5 (0x15). - Add additionnal checking of INQUIRY data: @@ -304,7 +304,7 @@ Sat Jun 20 20:00 1998 Gerard Roudier (groudier@club-internet.fr) * revision 3.0c - Add a boot setup option that allows to set up device queue depths - at boot-up. This option is very usefull since Linux does not + at boot-up. This option is very useful since Linux does not allow to change scsi device queue depth once the system has been booted up. @@ -333,7 +333,7 @@ kernel version >= 2.1.105. - Replace all printf(s) by printk(s). After all, the ncr53c8xx is a driver for Linux. - - Perform auto-sense on COMMAND TERMINATED. Not sure it is usefull. + - Perform auto-sense on COMMAND TERMINATED. Not sure it is useful. - Some other minor changes. Tue Jun 4 23:00 1998 Gerard Roudier (groudier@club-internet.fr) @@ -341,7 +341,7 @@ - Code cleanup and simplification: Remove kernel 1.2.X and 1.3.X support. Remove the _old_ target capabilities table. - Remove the error recovery code that have'nt been really usefull. + Remove the error recovery code that have'nt been really useful. Use a single alignment boundary (CACHE_LINE_SIZE) for data structures. - Several aggressive SCRIPTS optimizations and changes: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/ChangeLog.sym53c8xx linux.ac/drivers/scsi/ChangeLog.sym53c8xx --- linux.vanilla/drivers/scsi/ChangeLog.sym53c8xx Tue Apr 3 17:32:18 2001 +++ linux.ac/drivers/scsi/ChangeLog.sym53c8xx Mon Apr 9 23:31:27 2001 @@ -1,3 +1,13 @@ +Sat Apr 7 19:30 2001 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.7.3b + - Fix an unaligned LOAD from scripts (was used as dummy read). + - In ncr_soft_reset(), only try to ABORT the current operation + for chips that support SRUN bit in ISTAT1 and if SCRIPTS are + currently running, as 896 and 1010 manuals suggest. + - In the CCB abort path, donnot assume that the CCB is currently + queued to SCRIPTS. This is not always true, notably after a + QUEUE FULL status or when using untagged commands. + Sun Mar 4 18:30 2001 Gerard Roudier (groudier@club-internet.fr) * version sym53c8xx-1.7.3a - Fix an issue in the ncr_int_udc() (unexpected disconnect) @@ -338,7 +348,7 @@ Tue Apr 15 10:00 1999 Gerard Roudier (groudier@club-internet.fr) * version sym53c8xx-1.3e - Support for any number of LUNs (64) (SPI2-compliant). - (Btw, this may only be ever usefull under linux-2.2 ;-)) + (Btw, this may only be ever useful under linux-2.2 ;-)) Sun Apr 11 10:00 1999 Gerard Roudier (groudier@club-internet.fr) * version sym53c8xx-1.3d diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/Config.in linux.ac/drivers/scsi/Config.in --- linux.vanilla/drivers/scsi/Config.in Tue Apr 3 17:32:18 2001 +++ linux.ac/drivers/scsi/Config.in Tue Apr 3 17:54:59 2001 @@ -100,8 +100,8 @@ bool ' Reset SCSI-devices at boottime' CONFIG_IBMMCA_SCSI_DEV_RESET fi fi -if [ "$CONFIG_X86" = "y" ]; then - dep_tristate 'IBM ServeRAID support' CONFIG_SCSI_IPS $CONFIG_SCSI +if [ "$CONFIG_X86" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate 'IBM ServeRAID support' CONFIG_SCSI_IPS $CONFIG_SCSI $CONFIG_PCI fi dep_tristate 'Initio 9100U(W) support' CONFIG_SCSI_INITIO $CONFIG_SCSI $CONFIG_PCI dep_tristate 'Initio INI-A100U2W support' CONFIG_SCSI_INIA100 $CONFIG_SCSI $CONFIG_PCI @@ -196,6 +196,30 @@ fi if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then bool 'MIPS JAZZ FAS216 SCSI support' CONFIG_JAZZ_ESP +fi + +if [ "$CONFIG_AMIGA" = "y" ]; then + dep_tristate 'A3000 WD33C93A support' CONFIG_A3000_SCSI $CONFIG_SCSI + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'A4000T SCSI support (EXPERIMENTAL)' CONFIG_A4000T_SCSI + fi +fi +if [ "$CONFIG_ZORRO" = "y" ]; then + dep_tristate 'A2091/A590 WD33C93A support' CONFIG_A2091_SCSI $CONFIG_SCSI + dep_tristate 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI $CONFIG_SCSI + dep_tristate 'CyberStorm SCSI support' CONFIG_CYBERSTORM_SCSI $CONFIG_SCSI + dep_tristate 'CyberStorm Mk II SCSI support' CONFIG_CYBERSTORMII_SCSI $CONFIG_SCSI + dep_tristate 'Blizzard 2060 SCSI support' CONFIG_BLZ2060_SCSI $CONFIG_SCSI + dep_tristate 'Blizzard 1230IV/1260 SCSI support' CONFIG_BLZ1230_SCSI $CONFIG_SCSI + dep_tristate 'Fastlane SCSI support' CONFIG_FASTLANE_SCSI $CONFIG_SCSI + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'A4091 SCSI support (EXPERIMENTAL)' CONFIG_A4091_SCSI + bool 'WarpEngine SCSI support (EXPERIMENTAL)' CONFIG_WARPENGINE_SCSI + bool 'Blizzard PowerUP 603e+ SCSI (EXPERIMENTAL)' CONFIG_BLZ603EPLUS_SCSI + dep_tristate 'BSC Oktagon SCSI support (EXPERIMENTAL)' CONFIG_OKTAGON_SCSI $CONFIG_SCSI +# bool 'Cyberstorm Mk III SCSI support (EXPERIMENTAL)' CONFIG_CYBERSTORMIII_SCSI +# bool 'GVP Turbo 040/060 SCSI support (EXPERIMENTAL)' CONFIG_GVP_TURBO_SCSI + fi fi endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/FlashPoint.c linux.ac/drivers/scsi/FlashPoint.c --- linux.vanilla/drivers/scsi/FlashPoint.c Mon Aug 17 09:01:01 1998 +++ linux.ac/drivers/scsi/FlashPoint.c Tue Apr 3 17:54:59 2001 @@ -629,7 +629,7 @@ #if (FW_TYPE==_UCB_MGR_) #define HBA_AUTO_SENSE_FAIL 0x1B #define HBA_TQ_REJECTED 0x1C - #define HBA_UNSUPORTED_MSG 0x1D + #define HBA_UNSUPPORTED_MSG 0x1D #define HBA_HW_ERROR 0x20 #define HBA_ATN_NOT_RESPONDED 0x21 #define HBA_SCSI_RESET_BY_ADAPTER 0x22 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/Makefile linux.ac/drivers/scsi/Makefile --- linux.vanilla/drivers/scsi/Makefile Tue Apr 3 17:32:18 2001 +++ linux.ac/drivers/scsi/Makefile Thu Apr 12 17:50:05 2001 @@ -6,6 +6,12 @@ # # 20 Sep 2000, Torben Mathiasen <tmm@image.dk> # Changed link order to reflect new scsi initialization. +# +# *!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*! +# The link order must be, SCSI Core, SCSI HBA drivers, and +# lastly SCSI peripheral drivers (disk/tape/cdrom/etc.) to +# satisfy certain initialization assumptions in the SCSI layer. +# *!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*! O_TARGET := scsidrv.o @@ -64,6 +70,9 @@ obj-$(CONFIG_SCSI_AHA152X) += aha152x.o obj-$(CONFIG_SCSI_AHA1542) += aha1542.o obj-$(CONFIG_SCSI_AHA1740) += aha1740.o +ifeq ($(CONFIG_SCSI_AIC7XXX),y) +obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx/aic7xxx_drv.o +endif obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o obj-$(CONFIG_SCSI_IPS) += ips.o obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/README.aic7xxx linux.ac/drivers/scsi/README.aic7xxx --- linux.vanilla/drivers/scsi/README.aic7xxx Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/scsi/README.aic7xxx Tue Apr 3 17:54:59 2001 @@ -0,0 +1,477 @@ + AIC7xxx Driver for Linux + +Introduction +---------------------------- +The AIC7xxx SCSI driver adds support for Adaptec (http://www.adaptec.com) +SCSI controllers and chipsets. Major portions of the driver and driver +development are shared between both Linux and FreeBSD. Support for the +AIC-7xxx chipsets have been in the default Linux kernel since approximately +linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD +2.1.0 or later. + + Supported cards/chipsets + ---------------------------- + Adaptec Cards + ---------------------------- + AHA-274x + AHA-274xT + AHA-274xW + AHA-284x + AHA-284xW + All PCI based cards using any of the chipsets listed under motherboard + chipsets. In general, this means *all* of the Adaptec SCSI controllers + except the ones specifically excluded later on in this document. + + Motherboard Chipsets + ---------------------------- + AIC-777x + AIC-785x + AIC-786x + AIC-787x + AIC-788x + AIC-789x + AIC-3860 + + Bus Types + ---------------------------- + W - Wide SCSI, SCSI-3, 16bit bus, 68pin connector, will also support + SCSI-1/SCSI-2 50pin devices, transfer rates up to 20MB/s. + U - Ultra SCSI, transfer rates up to 40MB/s. + U2- Ultra 2 SCSI, transfer rates up to 80MB/s. + U3- Ultra 3 SCSI, transfer rates up to 160MB/s. + D - Differential SCSI. + T - Twin Channel SCSI. Up to 14 SCSI devices. + + AHA-274x - EISA SCSI controller + AHA-284x - VLB SCSI controller + AHA-29xx - PCI SCSI controller + AHA-39xx - PCI controllers with multiple separate SCSI channels on-board. + + Not Supported Devices + ------------------------------ + Adaptec Cards + ---------------------------- + AHA-2920 (Only the cards that use the Future Domain chipset are not + supported, any 2920 cards based on Adaptec AIC chipsets, + such as the 2920C, are supported) + AAA-13x Raid Adapters + AAA-113x Raid Port Card + + Motherboard Chipsets + ---------------------------- + AIC-781x + + Bus Types + ---------------------------- + R - Raid Port busses are not supported. + + The hardware RAID devices sold by Adaptec are *NOT* supported by this + driver (and will people please stop emailing me about them, they are + a totally separate beast from the bare SCSI controllers and this driver + can not be retrofitted in any sane manner to support the hardware RAID + features on those cards - Doug Ledford). + + + People + ------------------------------ + Justin T Gibbs gibbs@plutotech.com + (BSD Driver Author) + Dan Eischen deischen@iworks.InterWorks.org + (Original Linux Driver Co-maintainer) + Dean Gehnert deang@teleport.com + (Original Linux FTP/patch maintainer) + Jess Johnson jester@frenzy.com + (AIC7xxx FAQ author) + Doug Ledford dledford@redhat.com + (Current Linux aic7xxx-5.x.x Driver/Patch/FTP maintainer) + + Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original + author of the driver. John has since retired from the project. Thanks + again for all his work! + + Mailing list + ------------------------------ + There is a mailing list available for users who want to track development + and converse with other users and developers. This list is for both + FreeBSD and Linux support of the AIC7xxx chipsets. + + To subscribe to the AIC7xxx mailing list send mail to the list server, + with "subscribe AIC7xxx" in the body (no Subject: required): + To: majordomo@FreeBSD.ORG + --- + subscribe AIC7xxx + + To unsubscribe from the list, send mail to the list server with: + To: majordomo@FreeBSD.ORG + --- + unsubscribe AIC7xxx + + Send regular messages and replies to: AIC7xxx@FreeBSD.ORG + + Boot Command line options + ------------------------------ + "aic7xxx=no_reset" - Eliminate the SCSI bus reset during startup. + Some SCSI devices need the initial reset that this option disables + in order to work. If you have problems at bootup, please make sure + you aren't using this option. + + "aic7xxx=reverse_scan" - Certain PCI motherboards scan for devices at + bootup by scanning from the highest numbered PCI device to the + lowest numbered PCI device, others do just the opposite and scan + from lowest to highest numbered PCI device. There is no reliable + way to autodetect this ordering. So, we default to the most common + order, which is lowest to highest. Then, in case your motherboard + scans from highest to lowest, we have this option. If your BIOS + finds the drives on controller A before controller B but the linux + kernel finds your drives on controller B before A, then you should + use this option. + + "aic7xxx=extended" - Force the driver to detect extended drive translation + on your controller. This helps those people who have cards without + a SEEPROM make sure that linux and all other operating systems think + the same way about your hard drives. + + "aic7xxx=scbram" - Some cards have external SCB RAM that can be used to + give the card more hardware SCB slots. This allows the driver to use + that SCB RAM. Without this option, the driver won't touch the SCB + RAM because it is known to cause problems on a few cards out there + (such as 3985 class cards). + + "aic7xxx=irq_trigger:x" - Replace x with either 0 or 1 to force the kernel + to use the correct IRQ type for your card. This only applies to EISA + based controllers. On these controllers, 0 is for Edge triggered + interrupts, and 1 is for Level triggered interrupts. If you aren't + sure or don't know which IRQ trigger type your EISA card uses, then + let the kernel autodetect the trigger type. + + "aic7xxx=verbose" - This option can be used in one of two ways. If you + simply specify aic7xxx=verbose, then the kernel will automatically + pick the default set of verbose messages for you to see. + Alternatively, you can specify the command as + "aic7xxx=verbose:0xXXXX" where the X entries are replaced with + hexadecimal digits. This option is a bit field type option. For + a full listing of the available options, search for the + #define VERBOSE_xxxxxx lines in the aic7xxx.c file. If you want + verbose messages, then it is recommended that you simply use the + aic7xxx=verbose variant of this command. + + "aic7xxx=pci_parity:x" - This option controls whether or not the driver + enables PCI parity error checking on the PCI bus. By default, this + checking is disabled. To enable the checks, simply specify pci_parity + with no value afterwords. To reverse the parity from even to odd, + supply any number other than 0 or 255. In short: + pci_parity - Even parity checking (even is the normal PCI parity) + pci_parity:x - Where x > 0, Odd parity checking + pci_parity:0 - No check (default) + NOTE: In order to get Even PCI parity checking, you must use the + version of the option that does not include the : and a number at + the end (unless you want to enter exactly 2^32 - 1 as the number). + + "aic7xxx=no_probe" - This option will disable the probing for any VLB + based 2842 controllers and any EISA based controllers. This is + needed on certain newer motherboards where the normal EISA I/O ranges + have been claimed by other PCI devices. Probing on those machines + will often result in the machine crashing or spontaneously rebooting + during startup. Examples of machines that need this are the + Dell PowerEdge 6300 machines. + + "aic7xxx=seltime:2" - This option controls how long the card waits + during a device selection sequence for the device to respond. + The original SCSI spec says that this "should be" 256ms. This + is generally not required with modern devices. However, some + very old SCSI I devices need the full 256ms. Most modern devices + can run fine with only 64ms. The default for this option is + 64ms. If you need to change this option, then use the following + table to set the proper value in the example above: + 0 - 256ms + 1 - 128ms + 2 - 64ms + 3 - 32ms + + "aic7xxx=panic_on_abort" - This option is for debugging and will cause + the driver to panic the linux kernel and freeze the system the first + time the drivers abort or reset routines are called. This is most + helpful when some problem causes infinite reset loops that scroll too + fast to see. By using this option, you can write down what the errors + actually are and send that information to me so it can be fixed. + + "aic7xxx=dump_card" - This option will print out the *entire* set of + configuration registers on the card during the init sequence. This + is a debugging aid used to see exactly what state the card is in + when we finally finish our initialization routines. If you don't + have documentation on the chipsets, this will do you absolutely + no good unless you are simply trying to write all the information + down in order to send it to me. + + "aic7xxx=dump_sequencer" - This is the same as the above options except + that instead of dumping the register contents on the card, this + option dumps the contents of the sequencer program RAM. This gives + the ability to verify that the instructions downloaded to the + card's sequencer are indeed what they are suppossed to be. Again, + unless you have documentation to tell you how to interpret these + numbers, then it is totally useless. + + "aic7xxx=override_term:0xffffffff" - This option is used to force the + termination on your SCSI controllers to a particular setting. This + is a bit mask variable that applies for up to 8 aic7xxx SCSI channels. + Each channel gets 4 bits, divided as follows: + bit 3 2 1 0 + | | | Enable/Disable Single Ended Low Byte Termination + | | En/Disable Single Ended High Byte Termination + | En/Disable Low Byte LVD Termination + En/Disable High Byte LVD Termination + + The upper 2 bits that deal with LVD termination only apply to Ultra2 + controllers. Futhermore, due to the current Ultra2 controller + designs, these bits are tied together such that setting either bit + enables both low and high byte LVD termination. It is not possible + to only set high or low byte LVD termination in this manner. This is + an artifact of the BIOS definition on Ultra2 controllers. For other + controllers, the only important bits are the two lowest bits. Setting + the higher bits on non-Ultra2 controllers has no effect. A few + examples of how to use this option: + + Enable low and high byte termination on a non-ultra2 controller that + is the first aic7xxx controller (the correct bits are 0011), + aic7xxx=override_term:0x3 + + Enable all termination on the third aic7xxx controller, high byte + termination on the second aic7xxx controller, and low and high byte + SE termination on the first aic7xxx controller + (bits are 1111 0010 0011), + aic7xxx=override_term:0xf23 + + No attempt has been made to make this option non-cryptic. It really + shouldn't be used except in dire circumstances, and if that happens, + I'm probably going to be telling you what to set this to anyway :) + + "aic7xxx=stpwlev:0xffffffff" - This option is used to control the STPWLEV + bit in the DEVCONFIG PCI register. Currently, this is one of the + very few registers that we have absolutely *no* way of detecting + what the variable should be. It depends entirely on how the chipset + and external terminators were coupled by the card/motherboard maker. + Further, a chip reset (at power up) always sets this bit to 0. If + there is no BIOS to run on the chipset/card (such as with a 2910C + or a motherboard controller with the BIOS totally disabled) then + the variable may not get set properly. Of course, if the proper + setting was 0, then that's what it would be after the reset, but if + the proper setting is actually 1.....you get the picture. Now, since + we can't detect this at all, I've added this option to force the + setting. If you have a BIOS on your controller then you should never + need to use this option. However, if you are having lots of SCSI + reset problems and can't seem to get them knocked out, this may help. + + Here's a test to know for certain if you need this option. Make + a boot floppy that you can use to boot your computer up and that + will detect the aic7xxx controller. Next, power down your computer. + While it's down, unplug all SCSI cables from your Adaptec SCSI + controller. Boot the system back up to the Adaptec EZ-SCSI BIOS + and then make sure that termination is enabled on your adapter (if + you have an Adaptec BIOS of course). Next, boot up the floppy you + made and wait for it to detect the aic7xxx controller. If the kernel + finds the controller fine, says scsi : x hosts and then tries to + detect your devices like normal, up to the point where it fails to + mount your root file system and panics, then you're fine. If, on + the other hand, the system goes into an infinite reset loop, then + you need to use this option and/or the previous option to force the + proper termination settings on your controller. If this happens, + then you next need to figure out what your settings should be. + + To find the correct settings, power your machine back down, connect + back up the SCSI cables, and boot back into your machine like normal. + However, boot with the aic7xxx=verbose:0x39 option. Record the + initial DEVCONFIG values for each of your aic7xxx controllers as + they are listed, and also record what the machine is detecting as + the proper termination on your controllers. NOTE: the order in + which the initial DEVCONFIG values are printed out is not gauranteed + to be the same order as the SCSI controllers are registered. The + above option and this option both work on the order of the SCSI + controllers as they are registered, so make sure you match the right + DEVCONFIG values with the right controllers if you have more than + one aic7xxx controller. + + Once you have the detected termination settings and the initial + DEVCONFIG values for each controller, then figure out what the + termination on each of the controllers *should* be. Hopefully, that + part is correct, but it could possibly be wrong if there is + bogus cable detection logic on your controller or something similar. + If all the controllers have the correct termination settings, then + don't set the aic7xxx=override_term variable at all, leave it alone. + Next, on any controllers that go into an infinite reset loop when + you unplug all the SCSI cables, get the starting DEVCONFIG value. + If the initial DEVCONFIG value is divisible by 2, then the correct + setting for that controller is 0. If it's an odd number, then + the correct setting for that controller is 1. For any other + controllers that didn't have an infinite reset problem, then reverse + the above options. If DEVCONFIG was even, then the correct setting + is 1, if not then the correct setting is 0. + + Now that you know what the correct setting was for each controller, + we need to encode that into the aic7xxx=stpwlev:0x... variable. + This variable is a bit field encoded variable. Bit 0 is for the first + aic7xxx controller, bit 1 for the next, etc. Put all these bits + together and you get a number. For example, if the third aic7xxx + needed a 1, but the second and first both needed a 0, then the bits + would be 100 in binary. This then translates to 0x04. You would + therefore set aic7xxx=stpwlev:0x04. This is fairly standard binary + to hexadecimal conversions here. If you aren't up to speed on the + binary->hex conversion then send an email to the aic7xxx mailing + list and someone can help you out. + + "aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to disable + or enable Tagged Command Queueing (TCQ) on specific devices. As of + driver version 5.1.11, TCQ is now either on or off by default + according to the setting you choose during the make config process. + In order to en/disable TCQ for certian devices at boot time, a user + may use this boot param. The driver will then parse this message out + and en/disable the specific device entries that are present based upon + the value given. The param line is parsed in the following manner: + + { - first instance indicates the start of this parameter values + second instance is the start of entries for a particular + device entry + } - end the entries for a particular host adapter, or end the entire + set of parameter entries + , - move to next entry. Inside of a set of device entries, this + moves us to the next device on the list. Outside of device + entries, this moves us to the next host adapter + . - Same effect as , but is safe to use with insmod. + x - the number to enter into the array at this position. + 0 = Enable tagged queueing on this device and use the default + queue depth + 1-254 = Enable tagged queueing on this device and use this + number as the queue depth + 255 = Disable tagged queueing on this device. + Note: anything above 32 for an actual queue depth is wasteful + and not recommended. + + A few examples of how this can be used: + + tag_info:{{8,12,,0,,255,4}} + This line will only effect the first aic7xxx card registered. It + will set scsi id 0 to a queue depth of 8, id 1 to 12, leave id 2 + at the default, set id 3 to tagged queueing enabled and use the + default queue depth, id 4 default, id 5 disabled, and id 6 to 4. + Any not specified entries stay at the default value, repeated + commas with no value specified will simply increment to the next id + without changing anything for the missing values. + + tag_info:{,,,{,,,255}} + First, second, and third adapters at default values. Fourth + adapter, id 3 is disabled. Notice that leading commas simply + increment what the first number effects, and there are no need + for trailing commas. When you close out an adapter, or the + entire entry, anything not explicitly set stays at the default + value. + + A final note on this option. The scanner I used for this isn't + perfect or highly robust. If you mess the line up, the worst that + should happen is that the line will get ignored. If you don't + close out the entire entry with the final bracket, then any other + aic7xxx options after this will get ignored. So, in general, be + sure of what you are entering, and after you have it right, just + add it to the lilo.conf file so there won't be any mistakes. As + a means of checking this parser, the entire tag_info array for + each card is now printed out in the /proc/scsi/aic7xxx/x file. You + can use that to verify that your options were parsed correctly. + + Boot command line options may be combined to form the proper set of options + a user might need. For example, the following is valid: + + aic7xxx=verbose,extended,irq_trigger:1 + + The only requirement is that individual options be separated by a comma or + a period on the command line. + + Module Loading command options + ------------------------------ + When loading the aic7xxx driver as a module, the exact same options are + available to the user. However, the syntax to specify the options changes + slightly. For insmod, you need to wrap the aic7xxx= argument in quotes + and replace all ',' with '.'. So, for example, a valid insmod line + would be: + + insmod aic7xxx aic7xxx='verbose.irq_trigger:1.extended' + + This line should result in the *exact* same behaviour as if you typed + it in at the lilo prompt and the driver was compiled into the kernel + instead of being a module. The reason for the single quote is so that + the shell won't try to interpret anything in the line, such as {. + Insmod assumes any options starting with a letter instead of a number + is a character string (which is what we want) and by switching all of + the commas to periods, insmod won't interpret this as more than one + string and write junk into our binary image. I consider it a bug in + the insmod program that even if you wrap your string in quotes (quotes + that pass the shell mind you and that insmod sees) it still treates + a comma inside of those quotes as starting a new variable, resulting + in memory scribbles if you don't switch the commas to periods. + + + Kernel Compile options + ------------------------------ + The various kernel compile time options for this driver are now fairly + well documented in the file Documentation/Configure.help. In order to + see this documentation, you need to use one of the advanced configuration + programs (menuconfig and xconfig). If you are using the "make menuconfig" + method of configuring your kernel, then you would simply highlight the + option in question and hit the ? key. If you are using the "make xconfig" + method of configuring your kernel, then simply click on the help button + next to the option you have questions about. The help information from + the Configure.help file will then get automatically displayed. + + /proc support + ------------------------------ + The /proc support for the AIC7xxx can be found in the /proc/scsi/aic7xxx/ + directory. That directory contains a file for each SCSI controller in + the system. Each file presents the current configuration and transfer + statistics (enabled with #define in aic7xxx.c) for each controller. + + Thanks to Michael Neuffer for his upper-level SCSI help, and + Matthew Jacob for statistics support. + + Debugging the driver + ------------------------------ + Should you have problems with this driver, and would like some help in + getting them solved, there are a couple debugging items built into + the driver to facilitate getting the needed information from the system. + In general, I need a complete description of the problem, with as many + logs as possible concerning what happens. To help with this, there is + a command option aic7xxx=panic_on_abort. This option, when set, forces + the driver to panic the kernel on the first SCSI abort issued by the + mid level SCSI code. If your system is going to reset loops and you + can't read the screen, then this is what you need. Not only will it + stop the system, but it also prints out a large amount of state + information in the process. Second, if you specify the option + "aic7xxx=verbose:0x1ffff", the system will print out *SOOOO* much + information as it runs that you won't be able to see anything. + However, this can actually be very useful if your machine simply + locks up when trying to boot, since it will pin-point what was last + happening (in regards to the aic7xxx driver) immediately prior to + the lockup. This is really only useful if your machine simply can + not boot up successfully. If you can get your machine to run, then + this will produce far too much information. + + FTP sites + ------------------------------ + ftp://ftp.redhat.com/pub/aic/ + - Out of date. I used to keep stuff here, but too many people + complained about having a hard time getting into Red Hat's ftp + server. So use the web site below instead. + ftp://ftp.pcnet.com/users/eischen/Linux/ + - Dan Eischen's driver distribution area + ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/ + - European Linux mirror of Teleport site + + Web sites + ------------------------------ + http://people.redhat.com/dledford/ + - My web site, also the primary aic7xxx site with several related + pages. + +Dean W. Gehnert +deang@teleport.com + +$Revision: 3.0 $ + +Modified by Doug Ledford 1998-2000 + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/README.ibmmca linux.ac/drivers/scsi/README.ibmmca --- linux.vanilla/drivers/scsi/README.ibmmca Thu Jan 4 20:37:14 2001 +++ linux.ac/drivers/scsi/README.ibmmca Tue Apr 3 17:54:59 2001 @@ -736,7 +736,7 @@ Feb 20, 1999 (v3.1e) 1) I took the warning from the Linux Kernel Hackers Guide serious and - checked the cmd->result return value to the done-function very carefuly. + checked the cmd->result return value to the done-function very carefully. It is obvious, that the IBM SCSI only delivers the tsb.dev_status, if some error appeared, else it is undefined. Now, this is fixed. Before any SCB command gets queued, the tsb.dev_status is set to 0, so the @@ -1382,7 +1382,7 @@ 9 Disclaimer ------------ - Beside the GNU public license and the dependant disclaimers and disclaimers + Beside the GNU General 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, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/README.ncr53c8xx linux.ac/drivers/scsi/README.ncr53c8xx --- linux.vanilla/drivers/scsi/README.ncr53c8xx Tue Jun 20 01:59:41 2000 +++ linux.ac/drivers/scsi/README.ncr53c8xx Tue Apr 3 17:54:59 2001 @@ -508,7 +508,7 @@ clearprof The profile counters are automatically cleared when the amount of - data transfered reaches 1000 GB in order to avoid overflow. + data transferred reaches 1000 GB in order to avoid overflow. The "clearprof" command allows you to clear these counters at any time. @@ -1042,7 +1042,7 @@ The use of IARB needs the SCSI_NCR_IARB_SUPPORT option to have been defined at compile time and the 'iarb' boot option to have been set to a non zero -value at boot time. It is not that usefull for real work, but can be used +value at boot time. It is not that useful for real work, but can be used to stress SCSI devices or for some applications that can gain advantage of it. By the way, if you experience badnesses like 'unexpected disconnections', 'bad reselections', etc... when using IARB on heavy IO load, you should not @@ -1350,7 +1350,7 @@ Bit 0x04 : UDC Undexpected Disconnection Indicates that the device released the SCSI BUS when the chip was not expecting this to happen. A device may behave so to - indicate the SCSI initiator that an error condition not reportable using the SCSI protocol has occured. + indicate the SCSI initiator that an error condition not reportable using the SCSI protocol has occurred. Bit 0x02 : RST SCSI BUS Reset Generally SCSI targets donnot reset the SCSI BUS, although any device on the BUS can reset it at any time. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/advansys.c linux.ac/drivers/scsi/advansys.c --- linux.vanilla/drivers/scsi/advansys.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/scsi/advansys.c Sat Apr 14 01:29:11 2001 @@ -1,10 +1,10 @@ -/* $Id: advansys.c,v 1.69 1999/11/29 18:37:53 bobf Exp bobf $ */ -#define ASC_VERSION "3.2M" /* AdvanSys Driver Version */ +#define ASC_VERSION "3.3G" /* AdvanSys Driver Version */ /* * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters - * - * Copyright (c) 1995-1999 Advanced System Products, Inc. + * + * Copyright (c) 1995-2000 Advanced System Products, Inc. + * Copyright (c) 2000-2001 ConnectCom Solutions, Inc. * All Rights Reserved. * * Redistribution and use in source and binary forms, with or without @@ -12,52 +12,51 @@ * code retain the above copyright notice and this comment without * modification. * + * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys) + * changed its name to ConnectCom Solutions, Inc. + * * There is an AdvanSys Linux WWW page at: + * http://www.connectcom.net/downloads/software/os/linux.html * http://www.advansys.com/linux.html * - * The latest version of the AdvanSys driver is available at: + * The latest released version of the AdvanSys driver is available at: * ftp://ftp.advansys.com/pub/linux/linux.tgz + * ftp://ftp.connectcom.net/pub/linux/linux.tgz * * Please send questions, comments, bug reports to: - * linux@advansys.com + * support@connectcom.net */ /* Documentation for the AdvanSys Driver - A. Linux Kernel Testing + A. Linux Kernels Supported by this Driver B. Adapters Supported by this Driver - C. Linux v1.2.X - Directions for Adding the AdvanSys Driver - D. Linux v1.3.1 - v1.3.57 - Directions for Adding the AdvanSys Driver - E. Linux v1.3.58 and Newer - Upgrading the AdvanSys Driver - F. Source Comments - G. Driver Compile Time Options and Debugging - H. Driver LILO Option - I. Release History - J. Known Problems/Fix List - K. Credits - L. AdvanSys Contact Information - - A. Linux Kernel Testing - - This driver has been tested in the following Linux kernels: v1.2.13, - v1.3.57, v2.0.38, v2.2.13, and v2.3.28. These kernel versions are major - releases of Linux or the latest Linux kernel versions available when - this version of the driver was released. The driver should also work - in earlier versions of the Linux kernel. Beginning with v1.3.58 the - AdvanSys driver is included with all Linux kernels. Please refer to - sections C, D, and E for instructions on adding or upgrading the - AdvanSys driver. The driver is supported for x86 and alpha systems. + C. Linux source files modified by AdvanSys Driver + D. Source Comments + E. Driver Compile Time Options and Debugging + F. Driver LILO Option + G. Tests to run before releasing new driver + H. Release History + I. Known Problems/Fix List + J. Credits (Chronological Order) + K. ConnectCom (AdvanSys) Contact Information + + A. Linux Kernels Supported by this Driver + + This driver has been tested in the following Linux kernels: v2.2.18 + v2.4.0. The driver is supported on v2.2 and v2.4 kernels and on x86, + alpha, and PowerPC platforms. B. Adapters Supported by this Driver - + AdvanSys (Advanced System Products, Inc.) manufactures the following RISC-based, Bus-Mastering, Fast (10 Mhz) and Ultra (20 Mhz) Narrow (8-bit transfer) SCSI Host Adapters for the ISA, EISA, VL, and PCI buses and RISC-based, Bus-Mastering, Ultra (20 Mhz) Wide (16-bit transfer) SCSI Host Adapters for the PCI bus. - + The CDB counts below indicate the number of SCSI CDB (Command Descriptor Block) requests that can be stored in the RISC chip cache and board LRAM. A CDB is a single SCSI command. The driver @@ -65,6 +64,9 @@ adapter detected. The number of CDBs used by the driver can be lowered in the BIOS by changing the 'Host Queue Size' adapter setting. + Laptop Products: + ABP-480 - Bus-Master CardBus (16 CDB) (2.4 kernel and greater) + Connectivity Products: ABP510/5150 - Bus-Master ISA (240 CDB) ABP5140 - Bus-Master ISA PnP (16 CDB) @@ -80,7 +82,7 @@ ABP930UA - Bus-Master PCI Ultra (16 CDB) ABP960 - Bus-Master PCI MAC/PC (16 CDB) ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB) - + Single Channel Products: ABP542 - Bus-Master ISA with floppy (240 CDB) ABP742 - Bus-Master EISA (240 CDB) @@ -94,7 +96,7 @@ ABP940UW/3940UW - Bus-Master PCI Ultra-Wide (253 CDB) ABP970UW - Bus-Master PCI MAC/PC Ultra-Wide (253 CDB) ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB) - + Multi-Channel Products: ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel) ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel) @@ -104,37 +106,33 @@ ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel) ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.) ABP3950U2W - Bus-Master PCI LVD/Ultra2-Wide and Ultra-Wide (253 CDB) - - C. Linux v1.2.X - Directions for Adding the AdvanSys Driver + ABP3950U3W - Bus-Master PCI Dual LVD2/Ultra3-Wide (253 CDB) + + C. Linux source files modified by AdvanSys Driver + + This section for historical purposes documents the changes + originally made to the Linux kernel source to add the advansys + driver. As Linux has changed some of these files have also + been modified. + + 1. linux/arch/i386/config.in: - These directions apply to v1.2.13. For versions that follow v1.2.13. - but precede v1.3.57 some of the changes for Linux v1.3.X listed - below may need to be modified or included. A patch is available - for v1.2.13 from the AdvanSys WWW and FTP sites. - - There are two source files: advansys.h and advansys.c. Copy - both of these files to the directory /usr/src/linux/drivers/scsi. - - 1. Add the following line to /usr/src/linux/arch/i386/config.in - after "comment 'SCSI low-level drivers'": - bool 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS y - - 2. Add the following lines to /usr/src/linux/drivers/scsi/hosts.c - after "#include "hosts.h"": - + + 2. linux/drivers/scsi/hosts.c: + #ifdef CONFIG_SCSI_ADVANSYS #include "advansys.h" #endif - + and after "static Scsi_Host_Template builtin_scsi_hosts[] =": - + #ifdef CONFIG_SCSI_ADVANSYS ADVANSYS, #endif - - 3. Add the following lines to /usr/src/linux/drivers/scsi/Makefile: - + + 3. linux/drivers/scsi/Makefile: + ifdef CONFIG_SCSI_ADVANSYS SCSI_SRCS := $(SCSI_SRCS) advansys.c SCSI_OBJS := $(SCSI_OBJS) advansys.o @@ -142,12 +140,7 @@ SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) advansys.o endif - 4. (Optional) If you would like to enable the LILO command line - and /etc/lilo.conf 'advansys' option, make the following changes. - This option can be used to disable I/O port scanning or to limit - I/O port scanning to specific addresses. Refer to the 'Driver - LILO Option' section below. Add the following lines to - /usr/src/linux/init/main.c in the prototype section: + 4. linux/init/main.c: extern void advansys_setup(char *str, int *ints); @@ -157,118 +150,19 @@ { "advansys=", advansys_setup }, #endif - 5. If you have the HP 4020i CD-R driver and Linux v1.2.X you should - add a fix to the CD-ROM target driver. This fix will allow - you to mount CDs with the iso9660 file system. Linux v1.3.X - already has this fix. In the file /usr/src/linux/drivers/scsi/sr.c - and function get_sectorsize() after the line: - - if(scsi_CDs[i].sector_size == 0) scsi_CDs[i].sector_size = 2048; - - add the following line: - - if(scsi_CDs[i].sector_size == 2340) scsi_CDs[i].sector_size = 2048; - - 6. In the directory /usr/src/linux run 'make config' to configure - the AdvanSys driver, then run 'make vmlinux' or 'make zlilo' to - make the kernel. If the AdvanSys driver is not configured, then - a loadable module can be built by running 'make modules' and - 'make modules_install'. Use 'insmod' and 'rmmod' to install - and remove advansys.o. - - D. Linux v1.3.1 - v1.3.57 - Directions for Adding the AdvanSys Driver - - These directions apply to v1.3.57. For versions that precede v1.3.57 - some of these changes may need to be modified or eliminated. A patch - is available for v1.3.57 from the AdvanSys WWW and FTP sites. - Beginning with v1.3.58 this driver is included with the Linux - distribution eliminating the need for making any changes. - - There are two source files: advansys.h and advansys.c. Copy - both of these files to the directory /usr/src/linux/drivers/scsi. - - 1. Add the following line to /usr/src/linux/drivers/scsi/Config.in - after "comment 'SCSI low-level drivers'": - - dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI - - 2. Add the following lines to /usr/src/linux/drivers/scsi/hosts.c - after "#include "hosts.h"": - - #ifdef CONFIG_SCSI_ADVANSYS - #include "advansys.h" - #endif - - and after "static Scsi_Host_Template builtin_scsi_hosts[] =": - - #ifdef CONFIG_SCSI_ADVANSYS - ADVANSYS, - #endif - - 3. Add the following lines to /usr/src/linux/drivers/scsi/Makefile: - - ifeq ($(CONFIG_SCSI_ADVANSYS),y) - L_OBJS += advansys.o - else - ifeq ($(CONFIG_SCSI_ADVANSYS),m) - M_OBJS += advansys.o - endif - endif - - 4. Add the following line to /usr/src/linux/include/linux/proc_fs.h - in the enum scsi_directory_inos array: - - PROC_SCSI_ADVANSYS, - - 5. (Optional) If you would like to enable the LILO command line - and /etc/lilo.conf 'advansys' option, make the following changes. - This option can be used to disable I/O port scanning or to limit - I/O port scanning to specific addresses. Refer to the 'Driver - LILO Option' section below. Add the following lines to - /usr/src/linux/init/main.c in the prototype section: - - extern void advansys_setup(char *str, int *ints); - - and add the following lines to the bootsetups[] array. - - #ifdef CONFIG_SCSI_ADVANSYS - { "advansys=", advansys_setup }, - #endif - - 6. In the directory /usr/src/linux run 'make config' to configure - the AdvanSys driver, then run 'make vmlinux' or 'make zlilo' to - make the kernel. If the AdvanSys driver is not configured, then - a loadable module can be built by running 'make modules' and - 'make modules_install'. Use 'insmod' and 'rmmod' to install - and remove advansys.o. - - E. Linux v1.3.58 and Newer - Upgrading the AdvanSys Driver - - To upgrade the AdvanSys driver in a Linux v1.3.58 and newer - kernel, first check the version of the current driver. The - version is defined by the manifest constant ASC_VERSION at - the beginning of advansys.c. The new driver should have a - ASC_VERSION value greater than the current version. To install - the new driver rename advansys.c and advansys.h in the Linux - kernel source tree drivers/scsi directory to different names - or save them to a different directory in case you want to revert - to the old version of the driver. After the old driver is saved - copy the new advansys.c and advansys.h to drivers/scsi, rebuild - the kernel, and install the new kernel. No other changes are needed. + D. Source Comments - F. Source Comments - 1. Use tab stops set to 4 for the source files. For vi use 'se tabstops=4'. - + 2. This driver should be maintained in multiple files. But to make it easier to include with Linux and to follow Linux conventions, the whole driver is maintained in the source files advansys.h and advansys.c. In this file logical sections of the driver begin with a comment that contains '---'. The following are the logical sections of the driver below. - + --- Linux Version - --- Linux Include Files + --- Linux Include File --- Driver Options --- Debugging Header --- Asc Library Constants and Macros @@ -285,27 +179,27 @@ --- Tracing and Debugging Functions --- Asc Library Functions --- Adv Library Functions - + 3. The string 'XXX' is used to flag code that needs to be re-written or that contains a problem that needs to be addressed. - + 4. I have stripped comments from and reformatted the source for the Asc Library and Adv Library to reduce the size of this file. This source can be found under the following headings. The Asc Library is used to support Narrow Boards. The Adv Library is used to support Wide Boards. - + --- Asc Library Constants and Macros --- Adv Library Constants and Macros --- Asc Library Functions --- Adv Library Functions - - G. Driver Compile Time Options and Debugging - + + E. Driver Compile Time Options and Debugging + In this source file the following constants can be defined. They are defined in the source below. Both of these options are enabled by default. - + 1. ADVANSYS_ASSERT - Enable driver assertions (Def: Enabled) Enabling this option adds assertion logic statements to the @@ -325,11 +219,11 @@ the kernel name space. This option is very useful for debugging the driver, but it will add to the size of the driver execution image and add overhead to the execution of the driver. - + The amount of debugging output can be controlled with the global variable 'asc_dbglvl'. The higher the number the more output. By default the debug level is 0. - + If the driver is loaded at boot time and the LILO Driver Option is included in the system, the debug level can be changed by specifying a 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port. The @@ -343,28 +237,44 @@ If the driver is built as a loadable module this variable can be defined when the driver is loaded. The following insmod command will set the debug level to one. - + insmod advansys.o asc_dbglvl=1 - + Debugging Message Levels: 0: Errors Only 1: High-Level Tracing 2-N: Verbose Tracing - - I don't know the approved way for turning on printk()s to the - console. Here's a program I use to do this. Debug output is - logged in /var/adm/messages. - + + To enable debug output to console, please make sure that: + + a. System and kernel logging is enabled (syslogd, klogd running). + b. Kernel messages are routed to console output. Check + /etc/syslog.conf for an entry similar to this: + + kern.* /dev/console + + c. klogd is started with the appropriate -c parameter + (e.g. klogd -c 8) + + This will cause printk() messages to be be displayed on the + current console. Refer to the klogd(8) and syslogd(8) man pages + for details. + + Alternatively you can enable printk() to console with this + program. However, this is not the 'official' way to do this. + Debug output is logged in /var/log/messages. + main() { syscall(103, 7, 0, 0); } - - I found that increasing LOG_BUF_LEN to 40960 in kernel/printk.c - prevents most level 1 debug messages from being lost. + + Increasing LOG_BUF_LEN in kernel/printk.c to something like + 40960 allows more debug messages to be buffered in the kernel + and written to the console or log file. 3. ADVANSYS_STATS - Enable statistics (Def: Enabled >= v1.3.0) - + Enabling this option adds statistics collection and display through /proc to the driver. The information is useful for monitoring driver and device performance. It will add to the @@ -387,8 +297,8 @@ When ADVANSYS_STATS is not defined the AdvanSys /proc files only contain adapter and device configuration information. - H. Driver LILO Option - + F. Driver LILO Option + If init/main.c is modified as described in the 'Directions for Adding the AdvanSys Driver to Linux' section (B.4.) above, the driver will recognize the 'advansys' LILO command line and /etc/lilo.conf option. @@ -418,9 +328,24 @@ the 'Driver Compile Time Options and Debugging' section above for more information. - I. Release History + G. Tests to run before releasing new driver + + 1. In the supported kernels verify there are no warning or compile + errors when the kernel is built as both a driver and as a module + and with the following options: + + ADVANSYS_DEBUG - enabled and disabled + CONFIG_SMP - enabled and disabled + CONFIG_PROC_FS - enabled and disabled + + 2. Run tests on an x86, alpha, and PowerPC with at least one narrow + card and one wide card attached to a hard disk and CD-ROM drive: + fdisk, mkfs, fsck, bonnie, copy/compare test from the + CD-ROM to the hard drive. + + H. Release History - BETA-1.0 (12/23/95): + BETA-1.0 (12/23/95): First Release BETA-1.1 (12/28/95): @@ -454,7 +379,7 @@ 4. Remove reset request loop problem from the "Known Problems or Issues" section. This problem was isolated and fixed in the mid-level SCSI driver. - + 1.5 (8/8/96): 1. Add support for ABP-940U (PCI Ultra) adapter. 2. Add support for IRQ sharing by setting the SA_SHIRQ flag for @@ -677,7 +602,75 @@ 1. Really fix bug in adv_get_sglist(). 2. Incorporate v2.3.29 changes into driver. - J. Known Problems/Fix List (XXX) + 3.2N (4/1/00): + 1. Add CONFIG_ISA ifdef code. + 2. Include advansys_interrupts_enabled name change patch. + 3. For >= v2.3.28 use new SCSI error handling with new function + advansys_eh_bus_reset(). Don't include an abort function + because of base library limitations. + 4. For >= v2.3.28 use per board lock instead of io_request_lock. + 5. For >= v2.3.28 eliminate advansys_command() and + advansys_command_done(). + 6. Add some changes for PowerPC (Big Endian) support, but it isn't + working yet. + 7. Fix "nonexistent resource free" problem that occurred on a module + unload for boards with an I/O space >= 255. The 'n_io_port' field + is only one byte and can not be used to hold an ioport length more + than 255. + + 3.3A (4/4/00): + 1. Update to Adv Library 5.8. + 2. For wide cards add support for CDBs up to 16 bytes. + 3. Eliminate warnings when CONFIG_PROC_FS is not defined. + + 3.3B (5/1/00): + 1. Support for PowerPC (Big Endian) wide cards. Narrow cards + still need work. + 2. Change bitfields to shift and mask access for endian + portability. + + 3.3C (10/13/00): + 1. Update for latest 2.4 kernel. + 2. Test ABP-480 CardBus support in 2.4 kernel - works! + 3. Update to Asc Library S123. + 4. Update to Adv Library 5.12. + + 3.3D (11/22/00): + 1. Update for latest 2.4 kernel. + 2. Create patches for 2.2 and 2.4 kernels. + + 3.3E (1/9/01): + 1. Now that 2.4 is released remove ifdef code for kernel versions + less than 2.2. The driver is now only supported in kernels 2.2, + 2.4, and greater. + 2. Add code to release and acquire the io_request_lock in + the driver entrypoint functions: advansys_detect and + advansys_queuecommand. In kernel 2.4 the SCSI mid-level driver + still holds the io_request_lock on entry to SCSI low-level drivers. + This was supposed to be removed before 2.4 was released but never + happened. When the mid-level SCSI driver is changed all references + to the io_request_lock should be removed from the driver. + 3. Simplify error handling by removing advansys_abort(), + AscAbortSRB(), AscResetDevice(). SCSI bus reset requests are + now handled by resetting the SCSI bus and fully re-initializing + the chip. This simple method of error recovery has proven to work + most reliably after attempts at different methods. Also now only + support the "new" error handling method and remove the obsolete + error handling interface. + 4. Fix debug build errors. + + 3.3F (1/24/01): + 1. Merge with ConnectCom version from Andy Kellner which + updates Adv Library to 5.14. + 2. Make PowerPC (Big Endian) work for narrow cards and + fix problems writing EEPROM for wide cards. + 3. Remove interrupts_enabled assertion function. + + 3.3G (2/16/01): + 1. Return an error from narrow boards if passed a 16 byte + CDB. The wide board can already handle 16 byte CDBs. + + I. Known Problems/Fix List (XXX) 1. Need to add memory mapping workaround. Test the memory mapping. If it doesn't work revert to I/O port access. Can a test be done @@ -687,12 +680,12 @@ has not occurred then print a message and run in polled mode. 3. Allow bus type scanning order to be changed. 4. Need to add support for target mode commands, cf. CAM XPT. - 5 Need to add support for new Linux SCSI error handling method. - 6. Need to fix sti/cli code in Asc Library. - 7. Need to fix abort code in Adv Library. - 8. Reduce io_request_lock hold time. - K. Credits + J. Credits (Chronological Order) + + Bob Frey <bfrey@turbolinux.com.cn> wrote the AdvanSys SCSI driver + and maintained it up to 3.3F. He continues to answer questions + and help maintain the driver. Nathan Hartwell <mage@cdc3.cdc.net> provided the directions and basis for the Linux v1.3.X changes which were included in the @@ -712,22 +705,47 @@ support in the 3.1A driver. Doug Gilbert <dgilbert@interlog.com> has made changes and - suggestions to improve the driver and done testing. + suggestions to improve the driver and done a lot of testing. Ken Mort <ken@mort.net> reported a DEBUG compile bug fixed in 3.2K. - L. AdvanSys Contact Information - - Mail: Advanced System Products, Inc. + Tom Rini <trini@kernel.crashing.org> provided the CONFIG_ISA + patch and helped with PowerPC wide and narrow board support. + + Philip Blundell <philip.blundell@pobox.com> provided an + advansys_interrupts_enabled patch. + + Dave Jones <dave@denial.force9.co.uk> reported the compiler + warnings generated when CONFIG_PROC_FS was not defined in + the 3.2M driver. + + Jerry Quinn <jlquinn@us.ibm.com> fixed PowerPC support (endian + problems) for wide cards. + + Bryan Henderson <bryanh@giraffe-data.com> helped debug narrow + card error handling. + + Manuel Veloso <veloso@pobox.com> worked hard on PowerPC narrow + board support and fixed a bug in AscGetEEPConfig(). + + Arnaldo Carvalho de Melo <acme@conectiva.com.br> made + save_flags/restore_flags changes. + + Andy Kellner <AKellner@connectcom.net> continues the Advansys SCSI + driver development for ConnectCom (Version > 3.3F). + + K. ConnectCom (AdvanSys) Contact Information + + Mail: ConnectCom Solutions, Inc. 1150 Ringwood Court San Jose, CA 95131 Operator/Sales: 1-408-383-9400 FAX: 1-408-383-9612 Tech Support: 1-408-467-2930 - Tech Support E-Mail: support@advansys.com - FTP Site: ftp.advansys.com (login: anonymous) - Web Site: http://www.advansys.com + Tech Support E-Mail: linux@connectcom.net + FTP Site: ftp.connectcom.net (login: anonymous) + Web Site: http://www.connectcom.net */ @@ -736,78 +754,62 @@ * --- Linux Version */ -/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */ -#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) - #ifndef LINUX_VERSION_CODE #include <linux/version.h> #endif /* LINUX_VERSION_CODE */ +/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */ +#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) +#define ASC_LINUX_KERNEL22 (LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,4,0)) +#define ASC_LINUX_KERNEL24 (LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,4,0)) + +/* Driver supported only in version 2.2 and version >= 2.4. */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,2,0) || \ + (LINUX_VERSION_CODE > ASC_LINUX_VERSION(2,3,0) && \ + LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,4,0)) +#error "AdvanSys driver supported only in 2.2 and 2.4 or greater kernels." +#endif /* - * --- Linux Include Files + * --- Linux Include Files */ #include <linux/config.h> -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) #ifdef MODULE #include <linux/module.h> #endif /* MODULE */ -#endif /* version >= v1.3.0 */ + +#if defined(CONFIG_X86) && !defined(CONFIG_ISA) +#define CONFIG_ISA +#endif /* CONFIG_X86 && !CONFIG_ISA */ + #include <linux/string.h> #include <linux/sched.h> #include <linux/kernel.h> -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) -#include <linux/head.h> -#endif /* verions < v2.1.0 */ #include <linux/types.h> #include <linux/ioport.h> #include <linux/delay.h> -#include <linux/slab.h> +#include <linux/malloc.h> #include <linux/mm.h> -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) #include <linux/proc_fs.h> -#endif /* version >= v1.3.0 */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,23) #include <linux/init.h> -#endif /* version >= v2.1.23 */ #include <asm/io.h> #include <asm/system.h> #include <asm/dma.h> -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) -#include "../block/blk.h" -#else /* version >= v1.3.0 */ #include <linux/blk.h> #include <linux/stat.h> -#endif /* version >= v1.3.0 */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,18) +#if ASC_LINUX_KERNEL24 #include <linux/spinlock.h> -#elif LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,95) +#elif ASC_LINUX_KERNEL22 #include <asm/spinlock.h> -#endif /* version >= 2.1.95 */ +#endif #include "scsi.h" #include "hosts.h" #include "sd.h" #include "advansys.h" -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,93) #ifdef CONFIG_PCI #include <linux/pci.h> #endif /* CONFIG_PCI */ -#else /* version < v2.1.93 */ -/* - * For earlier than v2.1.93 the driver has its own PCI configuration. - * If PCI is not needed in a kernel before v2.1.93 this define can be - * turned-off to make the driver object smaller. - */ -#define ASC_CONFIG_PCI -#endif /* version < v2.1.93 */ - -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) -#define cpu_to_le16(word) (word) -#define le16_to_cpu(word) (word) -#define cpu_to_le32(dword) (dword) -#define le32_to_cpu(dword) (dword) -#endif /* version < v2.1.0 */ /* @@ -817,19 +819,12 @@ /* Enable driver assertions. */ #define ADVANSYS_ASSERT +/* Enable driver /proc statistics. */ +#define ADVANSYS_STATS + /* Enable driver tracing. */ /* #define ADVANSYS_DEBUG */ -/* - * Because of no /proc to display them, statistics are disabled - * for versions prior to v1.3.0. - */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) -#undef ADVANSYS_STATS /* Disable statistics */ -#else /* version >= v1.3.0 */ -#define ADVANSYS_STATS /* Enable statistics. */ -#endif /* version >= v1.3.0 */ - /* * --- Debugging Header @@ -848,7 +843,7 @@ #define ASC_LIB_VERSION_MAJOR 1 #define ASC_LIB_VERSION_MINOR 24 -#define ASC_LIB_SERIAL_NUMBER 121 +#define ASC_LIB_SERIAL_NUMBER 123 /* * Portable Data Types @@ -858,7 +853,7 @@ * types must be used. In Linux the char, short, and int types * are all consistent at 8, 16, and 32 bits respectively. Pointers * and long types are 64 bits on Alpha and UltraSPARC. - */ + */ #define ASC_PADDR __u32 /* Physical/Bus address data type. */ #define ASC_VADDR __u32 /* Virtual address data type. */ #define ASC_DCNT __u32 /* Unsigned Data count type. */ @@ -907,7 +902,7 @@ #define ASC_PCI_VENDORID 0x10CD #define ASC_PCI_DEVICEID_1200A 0x1100 #define ASC_PCI_DEVICEID_1200B 0x1200 -#define ASC_PCI_DEVICEID_ULTRA 0x1300 +#define ASC_PCI_DEVICEID_ULTRA 0x1300 #define ASC_PCI_REVISION_3150 0x02 #define ASC_PCI_REVISION_3050 0x03 @@ -924,13 +919,13 @@ #define CC_VERY_LONG_SG_LIST 0 #define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr) -#define PortAddr unsigned short /* port address size */ -#define inp(port) inb(port) -#define inpw(port) inw(port) -#define inpl(port) inl(port) -#define outp(port, byte) outb((byte), (port)) -#define outpw(port, word) outw((word), (port)) -#define outpl(port, dword) outl((dword), (port)) +#define PortAddr unsigned short /* port address size */ +#define inp(port) inb(port) +#define outp(port, byte) outb((byte), (port)) + +#define inpw(port) inw(port) +#define outpw(port, word) outw((word), (port)) + #define ASC_MAX_SG_QUEUE 7 #define ASC_MAX_SG_LIST 255 @@ -977,12 +972,7 @@ #define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL) #define ASC_MAX_EISA_DMA_ADDR (0x07FFFFFFL) #define ASC_MAX_EISA_DMA_COUNT (0x07FFFFFFL) -#ifndef inpw_noswap -#define inpw_noswap(port) inpw(port) -#endif -#ifndef outpw_noswap -#define outpw_noswap(port, data) outpw(port, data) -#endif + #define ASC_SCSI_ID_BITS 3 #define ASC_SCSI_TIX_TYPE uchar #define ASC_ALL_DEVICE_BIT_SET 0xFF @@ -1024,6 +1014,8 @@ #define SCSICMD_ReadHeader 0x44 #define SCSICMD_ModeSelect10 0x55 #define SCSICMD_ModeSense10 0x5A + +/* Inquiry Data Peripheral Device Types */ #define SCSI_TYPE_DASD 0x00 #define SCSI_TYPE_SASD 0x01 #define SCSI_TYPE_PRN 0x02 @@ -1035,10 +1027,20 @@ #define SCSI_TYPE_MED_CHG 0x08 #define SCSI_TYPE_COMM 0x09 #define SCSI_TYPE_UNKNOWN 0x1F -#define SCSI_TYPE_NO_DVC 0xFF -#define INQ_CLOCKING_ST_ONLY 0x0 -#define INQ_CLOCKING_DT_ONLY 0x1 -#define INQ_CLOCKING_ST_AND_DT 0x3 + +#define ADV_INQ_CLOCKING_ST_ONLY 0x0 +#define ADV_INQ_CLOCKING_DT_ONLY 0x1 +#define ADV_INQ_CLOCKING_ST_AND_DT 0x3 + +/* + * Inquiry SPC-2 SPI Byte 1 EVPD (Enable Vital Product Data) + * and CmdDt (Command Support Data) field bit definitions. + */ +#define ADV_INQ_RTN_VPD_AND_CMDDT 0x3 +#define ADV_INQ_RTN_CMDDT_FOR_OP_CODE 0x2 +#define ADV_INQ_RTN_VPD_FOR_PG_CODE 0x1 +#define ADV_INQ_RTN_STD_INQUIRY_DATA 0x0 + #define ASC_SCSIDIR_NOCHK 0x00 #define ASC_SCSIDIR_T2H 0x08 #define ASC_SCSIDIR_H2T 0x10 @@ -1102,77 +1104,49 @@ #define M2_QTAG_MSG_ORDERED 0x22 #define M2_IGNORE_WIDE_RESIDUE 0x23 -typedef struct { - uchar peri_dvc_type:5; - uchar peri_qualifier:3; -} ASC_SCSI_INQ0; - -typedef struct { - uchar dvc_type_modifier:7; - uchar rmb:1; -} ASC_SCSI_INQ1; - -typedef struct { - uchar ansi_apr_ver:3; - uchar ecma_ver:3; - uchar iso_ver:2; -} ASC_SCSI_INQ2; - -typedef struct { - uchar rsp_data_fmt:4; - uchar res:2; - uchar TemIOP:1; - uchar aenc:1; -} ASC_SCSI_INQ3; - -typedef struct { - uchar StfRe:1; - uchar CmdQue:1; - uchar Reserved:1; - uchar Linked:1; - uchar Sync:1; - uchar WBus16:1; - uchar WBus32:1; - uchar RelAdr:1; -} ASC_SCSI_INQ7; +/* + * Inquiry data structure and bitfield macros + * + * Only quantities of more than 1 bit are shifted, since the others are + * just tested for true or false. C bitfields aren't portable between big + * and little-endian platforms so they are not used. + */ + +#define ASC_INQ_DVC_TYPE(inq) ((inq)->periph & 0x1f) +#define ASC_INQ_QUALIFIER(inq) (((inq)->periph & 0xe0) >> 5) +#define ASC_INQ_DVC_TYPE_MOD(inq) ((inq)->devtype & 0x7f) +#define ASC_INQ_REMOVABLE(inq) ((inq)->devtype & 0x80) +#define ASC_INQ_ANSI_VER(inq) ((inq)->ver & 0x07) +#define ASC_INQ_ECMA_VER(inq) (((inq)->ver & 0x38) >> 3) +#define ASC_INQ_ISO_VER(inq) (((inq)->ver & 0xc0) >> 6) +#define ASC_INQ_RESPONSE_FMT(inq) ((inq)->byte3 & 0x0f) +#define ASC_INQ_TERM_IO(inq) ((inq)->byte3 & 0x40) +#define ASC_INQ_ASYNC_NOTIF(inq) ((inq)->byte3 & 0x80) +#define ASC_INQ_SOFT_RESET(inq) ((inq)->flags & 0x01) +#define ASC_INQ_CMD_QUEUE(inq) ((inq)->flags & 0x02) +#define ASC_INQ_LINK_CMD(inq) ((inq)->flags & 0x08) +#define ASC_INQ_SYNC(inq) ((inq)->flags & 0x10) +#define ASC_INQ_WIDE16(inq) ((inq)->flags & 0x20) +#define ASC_INQ_WIDE32(inq) ((inq)->flags & 0x40) +#define ASC_INQ_REL_ADDR(inq) ((inq)->flags & 0x80) +#define ASC_INQ_INFO_UNIT(inq) ((inq)->info & 0x01) +#define ASC_INQ_QUICK_ARB(inq) ((inq)->info & 0x02) +#define ASC_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2) typedef struct { - ASC_SCSI_INQ0 byte0; - ASC_SCSI_INQ1 byte1; - ASC_SCSI_INQ2 byte2; - ASC_SCSI_INQ3 byte3; + uchar periph; + uchar devtype; + uchar ver; + uchar byte3; uchar add_len; uchar res1; uchar res2; - ASC_SCSI_INQ7 byte7; + uchar flags; uchar vendor_id[8]; uchar product_id[16]; uchar product_rev_level[4]; } ASC_SCSI_INQUIRY; -typedef struct asc_req_sense { - uchar err_code:7; - uchar info_valid:1; - uchar segment_no; - uchar sense_key:4; - uchar reserved_bit:1; - uchar sense_ILI:1; - uchar sense_EOM:1; - uchar file_mark:1; - uchar info1[4]; - uchar add_sense_len; - uchar cmd_sp_info[4]; - uchar asc; - uchar ascq; - uchar fruc; - uchar sks_byte0:7; - uchar sks_valid:1; - uchar sks_bytes[2]; - uchar notused[2]; - uchar ex_sense_code; - uchar info2[4]; -} ASC_REQ_SENSE; - #define ASC_SG_LIST_PER_Q 7 #define QS_FREE 0x00 #define QS_READY 0x01 @@ -1286,7 +1260,7 @@ #define ASC_TIX_TO_LUN(tix) (((tix) >> ASC_SCSI_ID_BITS) & ASC_MAX_LUN) #define ASC_QNO_TO_QADDR(q_no) ((ASC_QADR_BEG)+((int)(q_no) << 6)) -typedef struct asc_scisq_1 { +typedef struct asc_scsiq_1 { uchar status; uchar q_no; uchar cntl; @@ -1300,7 +1274,7 @@ uchar extra_bytes; } ASC_SCSIQ_1; -typedef struct asc_scisq_2 { +typedef struct asc_scsiq_2 { ASC_VADDR srb_ptr; uchar target_ix; uchar flag; @@ -1378,8 +1352,8 @@ typedef struct asc_scsi_req_q { ASC_SCSIQ_1 r1; ASC_SCSIQ_2 r2; - uchar *cdbptr; - ASC_SG_HEAD *sg_head; + uchar *cdbptr; + ASC_SG_HEAD *sg_head; uchar *sense_ptr; ASC_SCSIQ_3 r3; uchar cdb[ASC_MAX_CDB_LEN]; @@ -1461,6 +1435,10 @@ #define ASCQ_ERR_SEND_SCSI_Q 0x22 #define ASCQ_ERR_HOST_REQ_RISC_HALT 0x23 #define ASCQ_ERR_RESET_SDTR 0x24 + +/* + * Warning code values are set in ASC_DVC_VAR 'warn_code'. + */ #define ASC_WARN_NO_ERROR 0x0000 #define ASC_WARN_IO_PORT_ROTATE 0x0001 #define ASC_WARN_EEPROM_CHKSUM 0x0002 @@ -1470,6 +1448,10 @@ #define ASC_WARN_EEPROM_RECOVER 0x0020 #define ASC_WARN_CFG_MSW_RECOVER 0x0040 #define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 + +/* + * Error code values are set in ASC_DVC_VAR 'err_code'. + */ #define ASC_IERR_WRITE_EEPROM 0x0001 #define ASC_IERR_MCODE_CHKSUM 0x0002 #define ASC_IERR_SET_PC_ADDR 0x0004 @@ -1484,6 +1466,7 @@ #define ASC_IERR_SCAM 0x0800 #define ASC_IERR_SET_SDTR 0x1000 #define ASC_IERR_RW_LRAM 0x8000 + #define ASC_DEF_IRQ_NO 10 #define ASC_MAX_IRQ_NO 15 #define ASC_MIN_IRQ_NO 10 @@ -1578,8 +1561,8 @@ ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled; ASC_SCSI_BIT_ID_TYPE disc_enable; ASC_SCSI_BIT_ID_TYPE sdtr_enable; - uchar chip_scsi_id:4; - uchar isa_dma_speed:4; + uchar chip_scsi_id; + uchar isa_dma_speed; uchar isa_dma_channel; uchar chip_version; ushort pci_device_id; @@ -1703,6 +1686,20 @@ #define ASC_MAX_INIT_BUSY_RETRY 8 #define ASC_EEP_ISA_PNP_WSIZE 16 +/* + * These macros keep the chip SCSI id and ISA DMA speed + * bitfields in board order. C bitfields aren't portable + * between big and little-endian platforms so they are + * not used. + */ + +#define ASC_EEP_GET_CHIP_ID(cfg) ((cfg)->id_speed & 0x0f) +#define ASC_EEP_GET_DMA_SPD(cfg) (((cfg)->id_speed & 0xf0) >> 4) +#define ASC_EEP_SET_CHIP_ID(cfg, sid) \ + ((cfg)->id_speed = ((cfg)->id_speed & 0xf0) | ((sid) & ASC_MAX_TID)) +#define ASC_EEP_SET_DMA_SPD(cfg, spd) \ + ((cfg)->id_speed = ((cfg)->id_speed & 0x0f) | ((spd) & 0x0f) << 4) + typedef struct asceep_config { ushort cfg_lsw; ushort cfg_msw; @@ -1715,8 +1712,8 @@ uchar bios_scan; uchar power_up_wait; uchar no_scam; - uchar chip_scsi_id:4; - uchar isa_dma_speed:4; + uchar id_speed; /* low order 4 bits is chip scsi id */ + /* high order 4 bits is isa dma speed */ uchar dos_int13_table[ASC_MAX_TID + 1]; uchar adapter_info[6]; ushort cntl; @@ -1962,8 +1959,6 @@ #define AscSetChipLramAddr(port, addr) outpw((PortAddr)((port)+IOP_RAM_ADDR), addr) #define AscGetChipLramData(port) (ushort)inpw((port)+IOP_RAM_DATA) #define AscSetChipLramData(port, data) outpw((port)+IOP_RAM_DATA, data) -#define AscGetChipLramDataNoSwap(port) (ushort)inpw_noswap((port)+IOP_RAM_DATA) -#define AscSetChipLramDataNoSwap(port, data) outpw_noswap((port)+IOP_RAM_DATA, data) #define AscGetChipIFC(port) (uchar)inp((port)+IOP_REG_IFC) #define AscSetChipIFC(port, data) outp((port)+IOP_REG_IFC, data) #define AscGetChipStatus(port) (ASC_CS_TYPE)inpw((port)+IOP_STATUS) @@ -2021,21 +2016,24 @@ STATIC void AscEnableInterrupt(PortAddr); STATIC void AscSetBank(PortAddr, uchar); STATIC int AscResetChipAndScsiBus(ASC_DVC_VAR *); +#ifdef CONFIG_ISA STATIC ushort AscGetIsaDmaChannel(PortAddr); STATIC ushort AscSetIsaDmaChannel(PortAddr, ushort); STATIC uchar AscSetIsaDmaSpeed(PortAddr, uchar); STATIC uchar AscGetIsaDmaSpeed(PortAddr); +#endif /* CONFIG_ISA */ STATIC uchar AscReadLramByte(PortAddr, ushort); STATIC ushort AscReadLramWord(PortAddr, ushort); +#if CC_VERY_LONG_SG_LIST STATIC ASC_DCNT AscReadLramDWord(PortAddr, ushort); +#endif /* CC_VERY_LONG_SG_LIST */ STATIC void AscWriteLramWord(PortAddr, ushort, ushort); -STATIC void AscWriteLramDWord(PortAddr, ushort, ASC_DCNT); STATIC void AscWriteLramByte(PortAddr, ushort, uchar); STATIC ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int); STATIC void AscMemWordSetLram(PortAddr, ushort, ushort, int); -STATIC void AscMemWordCopyToLram(PortAddr, ushort, ushort *, int); -STATIC void AscMemDWordCopyToLram(PortAddr, ushort, ASC_DCNT *, int); -STATIC void AscMemWordCopyFromLram(PortAddr, ushort, ushort *, int); +STATIC void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int); +STATIC void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int); +STATIC void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int); STATIC ushort AscInitAscDvcVar(ASC_DVC_VAR *); STATIC ushort AscInitFromEEP(ASC_DVC_VAR *); STATIC ushort AscInitFromAscDvcVar(ASC_DVC_VAR *); @@ -2047,21 +2045,8 @@ STATIC uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar); STATIC uchar AscAllocFreeQueue(PortAddr, uchar); STATIC uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar); -STATIC int AscRiscHaltedAbortSRB(ASC_DVC_VAR *, ASC_DCNT); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -STATIC int AscRiscHaltedAbortTIX(ASC_DVC_VAR *, uchar); -#endif /* version >= v1.3.89 */ STATIC int AscHostReqRiscHalt(PortAddr); STATIC int AscStopQueueExe(PortAddr); -STATIC int AscStartQueueExe(PortAddr); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -STATIC int AscCleanUpDiscQueue(PortAddr); -#endif /* version >= v1.3.89 */ -STATIC int AscCleanUpBusyQueue(PortAddr); -STATIC int AscWaitTixISRDone(ASC_DVC_VAR *, uchar); -STATIC int AscWaitISRDone(ASC_DVC_VAR *); -STATIC ASC_PADDR AscGetOnePhyAddr(ASC_DVC_VAR *, uchar *, - ASC_DCNT); STATIC int AscSendScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q * scsiq, uchar n_q_required); @@ -2072,48 +2057,43 @@ STATIC int AscSetChipSynRegAtID(PortAddr, uchar, uchar); STATIC int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar); STATIC ushort AscInitLram(ASC_DVC_VAR *); -STATIC int AscReInitLram(ASC_DVC_VAR *); STATIC ushort AscInitQLinkVar(ASC_DVC_VAR *); STATIC int AscSetLibErrorCode(ASC_DVC_VAR *, ushort); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -STATIC int _AscWaitQDone(PortAddr, ASC_SCSI_Q *); -#endif /* version >= v1.3.89 */ STATIC int AscIsrChipHalted(ASC_DVC_VAR *); STATIC uchar _AscCopyLramScsiDoneQ(PortAddr, ushort, ASC_QDONE_INFO *, ASC_DCNT); STATIC int AscIsrQDone(ASC_DVC_VAR *); STATIC int AscCompareString(uchar *, uchar *, int); +#ifdef CONFIG_ISA STATIC ushort AscGetEisaChipCfg(PortAddr); STATIC ASC_DCNT AscGetEisaProductID(PortAddr); STATIC PortAddr AscSearchIOPortAddrEISA(PortAddr); +STATIC PortAddr AscSearchIOPortAddr11(PortAddr); +STATIC PortAddr AscSearchIOPortAddr(PortAddr, ushort); +STATIC void AscSetISAPNPWaitForKey(void); +#endif /* CONFIG_ISA */ STATIC uchar AscGetChipScsiCtrl(PortAddr); STATIC uchar AscSetChipScsiID(PortAddr, uchar); STATIC uchar AscGetChipVersion(PortAddr, ushort); STATIC ushort AscGetChipBusType(PortAddr); -STATIC ASC_DCNT AscLoadMicroCode(PortAddr, ushort, ushort *, ushort); +STATIC ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort); STATIC int AscFindSignature(PortAddr); -STATIC PortAddr AscSearchIOPortAddr11(PortAddr); STATIC void AscToggleIRQAct(PortAddr); -STATIC void AscSetISAPNPWaitForKey(void); STATIC uchar AscGetChipIRQ(PortAddr, ushort); STATIC uchar AscSetChipIRQ(PortAddr, uchar, ushort); STATIC ushort AscGetChipBiosAddress(PortAddr, ushort); -STATIC int DvcEnterCritical(void); -STATIC void DvcLeaveCritical(int); -STATIC void DvcInPortWords(PortAddr, ushort *, int); -STATIC void DvcOutPortWords(PortAddr, ushort *, int); -STATIC void DvcOutPortDWords(PortAddr, ASC_DCNT *, int); +STATIC inline ulong DvcEnterCritical(void); +STATIC inline void DvcLeaveCritical(ulong); +#ifdef CONFIG_PCI STATIC uchar DvcReadPCIConfigByte(ASC_DVC_VAR *, ushort); STATIC void DvcWritePCIConfigByte(ASC_DVC_VAR *, ushort, uchar); +#endif /* CONFIG_PCI */ STATIC ushort AscGetChipBiosAddress(PortAddr, ushort); STATIC void DvcSleepMilliSecond(ASC_DCNT); STATIC void DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT); -STATIC ASC_DCNT DvcGetSGList(ASC_DVC_VAR *, uchar *, - ASC_DCNT, ASC_SG_HEAD *); -STATIC void DvcPutScsiQ(PortAddr, ushort, ushort *, int); -STATIC void DvcGetQinfo(PortAddr, ushort, ushort *, int); -STATIC PortAddr AscSearchIOPortAddr(PortAddr, ushort); +STATIC void DvcPutScsiQ(PortAddr, ushort, uchar *, int); +STATIC void DvcGetQinfo(PortAddr, ushort, uchar *, int); STATIC ushort AscInitGetConfig(ASC_DVC_VAR *); STATIC ushort AscInitSetConfig(ASC_DVC_VAR *); STATIC ushort AscInitAsc1000Driver(ASC_DVC_VAR *); @@ -2127,12 +2107,9 @@ STATIC uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar); STATIC int AscSgListToQueue(int); -STATIC int AscAbortSRB(ASC_DVC_VAR *, ASC_VADDR); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -STATIC int AscResetDevice(ASC_DVC_VAR *, uchar); -#endif /* version >= v1.3.89 */ -STATIC int AscResetSB(ASC_DVC_VAR *); +#ifdef CONFIG_ISA STATIC void AscEnableIsaDma(uchar); +#endif /* CONFIG_ISA */ STATIC ASC_DCNT AscGetMaxDmaCount(ushort); @@ -2141,7 +2118,7 @@ */ #define ADV_LIB_VERSION_MAJOR 5 -#define ADV_LIB_VERSION_MINOR 5 +#define ADV_LIB_VERSION_MINOR 14 /* d_os_dep.h */ #define ADV_OS_LINUX @@ -2158,7 +2135,7 @@ * types must be used. In Linux the char, short, and int types * are all consistent at 8, 16, and 32 bits respectively. Pointers * and long types are 64 bits on Alpha and UltraSPARC. - */ + */ #define ADV_PADDR __u32 /* Physical address data type. */ #define ADV_VADDR __u32 /* Virtual address data type. */ #define ADV_DCNT __u32 /* Unsigned Data count type. */ @@ -2175,11 +2152,7 @@ #define ADV_VADDR_TO_U32 virt_to_bus #define ADV_U32_TO_VADDR bus_to_virt -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) -#define AdvPortAddr unsigned short /* I/O Port address size */ -#else /* version >= v1,3,0 */ #define AdvPortAddr ulong /* Virtual memory address size */ -#endif /* version >= v1,3,0 */ /* * Define Adv Library required memory access macros. @@ -2188,16 +2161,15 @@ #define ADV_MEM_READW(addr) readw(addr) #define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr) #define ADV_MEM_WRITEW(addr, word) writew(word, addr) +#define ADV_MEM_WRITEDW(addr, dword) writel(dword, addr) + +#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15) /* - * The I/O memory mapping function names changed in 2.1.X. + * For wide boards a CDB length maximum of 16 bytes + * is supported. */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) -#define ioremap vremap -#define iounmap vfree -#endif /* version < v2.1.0 */ - -#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15) +#define ADV_MAX_CDB_LEN 16 /* * Define total number of simultaneous maximum element scatter-gather @@ -2207,7 +2179,7 @@ * elements. Allow each command to have at least one ADV_SG_BLOCK structure. * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK * structures or 255 scatter-gather elements. - * + * */ #define ADV_TOT_SG_BLOCK ASC_DEF_MAX_HOST_QNG @@ -2225,10 +2197,10 @@ #define ADV_SG_TOTAL_MEM_SIZE \ (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK) -#define ASC_PAGE_SIZE PAGE_SIZE +#define ADV_PAGE_SIZE PAGE_SIZE #define ADV_NUM_PAGE_CROSSING \ - ((ADV_SG_TOTAL_MEM_SIZE + (ASC_PAGE_SIZE - 1))/ASC_PAGE_SIZE) + ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE) /* a_condor.h */ #define ADV_PCI_VENDOR_ID 0x10CD @@ -2236,12 +2208,12 @@ #define ADV_PCI_DEVID_38C0800_REV1 0x2500 #define ADV_PCI_DEVID_38C1600_REV1 0x2700 -#define ASC_EEP_DVC_CFG_BEGIN (0x00) -#define ASC_EEP_DVC_CFG_END (0x15) -#define ASC_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */ -#define ASC_EEP_MAX_WORD_ADDR (0x1E) +#define ADV_EEP_DVC_CFG_BEGIN (0x00) +#define ADV_EEP_DVC_CFG_END (0x15) +#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */ +#define ADV_EEP_MAX_WORD_ADDR (0x1E) -#define ASC_EEP_DELAY_MS 100 +#define ADV_EEP_DELAY_MS 100 #define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */ #define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */ @@ -2252,6 +2224,18 @@ */ #define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */ #define ADV_EEPROM_CIS_LD 0x2000 /* EEPROM Bit 13 */ +/* + * ASC38C1600 Bit 11 + * + * If EEPROM Bit 11 is 0 for Function 0, then Function 0 will specify + * INT A in the PCI Configuration Space Int Pin field. If it is 1, then + * Function 0 will specify INT B. + * + * If EEPROM Bit 11 is 0 for Function 1, then Function 1 will specify + * INT B in the PCI Configuration Space Int Pin field. If it is 1, then + * Function 1 will specify INT A. + */ +#define ADV_EEPROM_INTAB 0x0800 /* EEPROM Bit 11 */ typedef struct adveep_3550_config { @@ -2262,20 +2246,20 @@ /* bit 14 set - BIOS Enable */ /* bit 15 set - Big Endian Mode */ ushort cfg_msw; /* 01 unused */ - ushort disc_enable; /* 02 disconnect enable */ + ushort disc_enable; /* 02 disconnect enable */ ushort wdtr_able; /* 03 Wide DTR able */ ushort sdtr_able; /* 04 Synchronous DTR able */ - ushort start_motor; /* 05 send start up motor */ + ushort start_motor; /* 05 send start up motor */ ushort tagqng_able; /* 06 tag queuing able */ - ushort bios_scan; /* 07 BIOS device control */ - ushort scam_tolerant; /* 08 no scam */ - + ushort bios_scan; /* 07 BIOS device control */ + ushort scam_tolerant; /* 08 no scam */ + uchar adapter_scsi_id; /* 09 Host Adapter ID */ uchar bios_boot_delay; /* power up wait */ - + uchar scsi_reset_delay; /* 10 reset delay */ uchar bios_id_lun; /* first boot device scsi id & lun */ - /* high nibble is lun */ + /* high nibble is lun */ /* low nibble is scsi id */ uchar termination; /* 11 0 - automatic */ @@ -2284,33 +2268,33 @@ /* 3 - low on / high on */ /* There is no low on / high off */ - uchar reserved1; /* reserved byte (not used) */ + uchar reserved1; /* reserved byte (not used) */ ushort bios_ctrl; /* 12 BIOS control bits */ - /* bit 0 set: BIOS don't act as initiator. */ - /* bit 1 set: BIOS > 1 GB support */ - /* bit 2 set: BIOS > 2 Disk Support */ - /* bit 3 set: BIOS don't support removables */ - /* bit 4 set: BIOS support bootable CD */ - /* bit 5 set: */ - /* bit 6 set: BIOS support multiple LUNs */ - /* bit 7 set: BIOS display of message */ - /* bit 8 set: */ - /* bit 9 set: Reset SCSI bus during init. */ - /* bit 10 set: */ - /* bit 11 set: No verbose initialization. */ - /* bit 12 set: SCSI parity enabled */ - /* bit 13 set: */ - /* bit 14 set: */ - /* bit 15 set: */ - ushort ultra_able; /* 13 ULTRA speed able */ + /* bit 0 BIOS don't act as initiator. */ + /* bit 1 BIOS > 1 GB support */ + /* bit 2 BIOS > 2 Disk Support */ + /* bit 3 BIOS don't support removables */ + /* bit 4 BIOS support bootable CD */ + /* bit 5 BIOS scan enabled */ + /* bit 6 BIOS support multiple LUNs */ + /* bit 7 BIOS display of message */ + /* bit 8 SCAM disabled */ + /* bit 9 Reset SCSI bus during init. */ + /* bit 10 */ + /* bit 11 No verbose initialization. */ + /* bit 12 SCSI parity enabled */ + /* bit 13 */ + /* bit 14 */ + /* bit 15 */ + ushort ultra_able; /* 13 ULTRA speed able */ ushort reserved2; /* 14 reserved */ uchar max_host_qng; /* 15 maximum host queuing */ uchar max_dvc_qng; /* maximum per device queuing */ ushort dvc_cntl; /* 16 control bit for driver */ ushort bug_fix; /* 17 control bit for bug fix */ - ushort serial_number_word1; /* 18 Board serial number word 1 */ - ushort serial_number_word2; /* 19 Board serial number word 2 */ + ushort serial_number_word1; /* 18 Board serial number word 1 */ + ushort serial_number_word2; /* 19 Board serial number word 2 */ ushort serial_number_word3; /* 20 Board serial number word 3 */ ushort check_sum; /* 21 EEP check sum */ uchar oem_name[16]; /* 22 OEM name */ @@ -2319,9 +2303,9 @@ ushort adv_err_addr; /* 32 last uc error address */ ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */ ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */ - ushort saved_adv_err_addr; /* 35 saved last uc error address */ + ushort saved_adv_err_addr; /* 35 saved last uc error address */ ushort num_of_err; /* 36 number of error */ -} ADVEEP_3550_CONFIG; +} ADVEEP_3550_CONFIG; typedef struct adveep_38C0800_config { @@ -2361,22 +2345,22 @@ /* There is no low on / high off */ ushort bios_ctrl; /* 12 BIOS control bits */ - /* bit 0 set: BIOS don't act as initiator. */ - /* bit 1 set: BIOS > 1 GB support */ - /* bit 2 set: BIOS > 2 Disk Support */ - /* bit 3 set: BIOS don't support removables */ - /* bit 4 set: BIOS support bootable CD */ - /* bit 5 set: BIOS scan enabled */ - /* bit 6 set: BIOS support multiple LUNs */ - /* bit 7 set: BIOS display of message */ - /* bit 8 set: */ - /* bit 9 set: Reset SCSI bus during init. */ - /* bit 10 set: */ - /* bit 11 set: No verbose initialization. */ - /* bit 12 set: SCSI parity enabled */ - /* bit 13 set: */ - /* bit 14 set: */ - /* bit 15 set: */ + /* bit 0 BIOS don't act as initiator. */ + /* bit 1 BIOS > 1 GB support */ + /* bit 2 BIOS > 2 Disk Support */ + /* bit 3 BIOS don't support removables */ + /* bit 4 BIOS support bootable CD */ + /* bit 5 BIOS scan enabled */ + /* bit 6 BIOS support multiple LUNs */ + /* bit 7 BIOS display of message */ + /* bit 8 SCAM disabled */ + /* bit 9 Reset SCSI bus during init. */ + /* bit 10 */ + /* bit 11 No verbose initialization. */ + /* bit 12 SCSI parity enabled */ + /* bit 13 */ + /* bit 14 */ + /* bit 15 */ ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */ ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */ uchar max_host_qng; /* 15 maximum host queueing */ @@ -2424,6 +2408,109 @@ ushort reserved63; /* 63 reserved */ } ADVEEP_38C0800_CONFIG; +typedef struct adveep_38C1600_config +{ + /* Word Offset, Description */ + + ushort cfg_lsw; /* 00 power up initialization */ + /* bit 11 set - Func. 0 INTB, Func. 1 INTA */ + /* clear - Func. 0 INTA, Func. 1 INTB */ + /* bit 13 set - Load CIS */ + /* bit 14 set - BIOS Enable */ + /* bit 15 set - Big Endian Mode */ + ushort cfg_msw; /* 01 unused */ + ushort disc_enable; /* 02 disconnect enable */ + ushort wdtr_able; /* 03 Wide DTR able */ + ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */ + ushort start_motor; /* 05 send start up motor */ + ushort tagqng_able; /* 06 tag queuing able */ + ushort bios_scan; /* 07 BIOS device control */ + ushort scam_tolerant; /* 08 no scam */ + + uchar adapter_scsi_id; /* 09 Host Adapter ID */ + uchar bios_boot_delay; /* power up wait */ + + uchar scsi_reset_delay; /* 10 reset delay */ + uchar bios_id_lun; /* first boot device scsi id & lun */ + /* high nibble is lun */ + /* low nibble is scsi id */ + + uchar termination_se; /* 11 0 - automatic */ + /* 1 - low off / high off */ + /* 2 - low off / high on */ + /* 3 - low on / high on */ + /* There is no low on / high off */ + + uchar termination_lvd; /* 11 0 - automatic */ + /* 1 - low off / high off */ + /* 2 - low off / high on */ + /* 3 - low on / high on */ + /* There is no low on / high off */ + + ushort bios_ctrl; /* 12 BIOS control bits */ + /* bit 0 BIOS don't act as initiator. */ + /* bit 1 BIOS > 1 GB support */ + /* bit 2 BIOS > 2 Disk Support */ + /* bit 3 BIOS don't support removables */ + /* bit 4 BIOS support bootable CD */ + /* bit 5 BIOS scan enabled */ + /* bit 6 BIOS support multiple LUNs */ + /* bit 7 BIOS display of message */ + /* bit 8 SCAM disabled */ + /* bit 9 Reset SCSI bus during init. */ + /* bit 10 Basic Integrity Checking disabled */ + /* bit 11 No verbose initialization. */ + /* bit 12 SCSI parity enabled */ + /* bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */ + /* bit 14 */ + /* bit 15 */ + ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */ + ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */ + uchar max_host_qng; /* 15 maximum host queueing */ + uchar max_dvc_qng; /* maximum per device queuing */ + ushort dvc_cntl; /* 16 control bit for driver */ + ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */ + ushort serial_number_word1; /* 18 Board serial number word 1 */ + ushort serial_number_word2; /* 19 Board serial number word 2 */ + ushort serial_number_word3; /* 20 Board serial number word 3 */ + ushort check_sum; /* 21 EEP check sum */ + uchar oem_name[16]; /* 22 OEM name */ + ushort dvc_err_code; /* 30 last device driver error code */ + ushort adv_err_code; /* 31 last uc and Adv Lib error code */ + ushort adv_err_addr; /* 32 last uc error address */ + ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */ + ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */ + ushort saved_adv_err_addr; /* 35 saved last uc error address */ + ushort reserved36; /* 36 reserved */ + ushort reserved37; /* 37 reserved */ + ushort reserved38; /* 38 reserved */ + ushort reserved39; /* 39 reserved */ + ushort reserved40; /* 40 reserved */ + ushort reserved41; /* 41 reserved */ + ushort reserved42; /* 42 reserved */ + ushort reserved43; /* 43 reserved */ + ushort reserved44; /* 44 reserved */ + ushort reserved45; /* 45 reserved */ + ushort reserved46; /* 46 reserved */ + ushort reserved47; /* 47 reserved */ + ushort reserved48; /* 48 reserved */ + ushort reserved49; /* 49 reserved */ + ushort reserved50; /* 50 reserved */ + ushort reserved51; /* 51 reserved */ + ushort reserved52; /* 52 reserved */ + ushort reserved53; /* 53 reserved */ + ushort reserved54; /* 54 reserved */ + ushort reserved55; /* 55 reserved */ + ushort cisptr_lsw; /* 56 CIS PTR LSW */ + ushort cisprt_msw; /* 57 CIS PTR MSW */ + ushort subsysvid; /* 58 SubSystem Vendor ID */ + ushort subsysid; /* 59 SubSystem ID */ + ushort reserved60; /* 60 reserved */ + ushort reserved61; /* 61 reserved */ + ushort reserved62; /* 62 reserved */ + ushort reserved63; /* 63 reserved */ +} ADVEEP_38C1600_CONFIG; + /* * EEPROM Commands */ @@ -2445,6 +2532,7 @@ #define BIOS_CTRL_RESET_SCSI_BUS 0x0200 #define BIOS_CTRL_INIT_VERBOSE 0x0800 #define BIOS_CTRL_SCSI_PARITY 0x1000 +#define BIOS_CTRL_AIPP_DIS 0x2000 #define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */ #define ADV_3550_IOLEN 0x40 /* I/O Port Range in bytes */ @@ -2452,7 +2540,14 @@ #define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */ #define ADV_38C0800_IOLEN 0x100 /* I/O Port Range in bytes */ -#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */ +/* + * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is + * a special 16K Adv Library and Microcode version. After the issue is + * resolved, should restore 32K support. + * + * #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory * + */ +#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */ #define ADV_38C1600_IOLEN 0x100 /* I/O Port Range 256 bytes */ #define ADV_38C1600_MEMLEN 0x1000 /* Memory Range 4KB bytes */ @@ -2653,8 +2748,8 @@ #define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */ #define FILTER_SEL 0x0C00 /* Filter Period Selection */ #define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */ -#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */ -#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */ +#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */ +#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */ #define ACTIVE_DBL 0x0200 /* Disable Active Negation */ #define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */ #define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */ @@ -2666,6 +2761,14 @@ /* * Addendum for ASC-38C0800 Chip + * + * The ASC-38C1600 Chip uses the same definitions except that the + * bus mode override bits [12:10] have been moved to byte register + * offset 0xE (IOPB_SOFT_OVER_WR) bits [12:10]. The [12:10] bits in + * SCSI_CFG1 are read-only and always available. Bit 14 (DIS_TERM_DRV) + * is not needed. The [12:10] bits in IOPB_SOFT_OVER_WR are write-only. + * Also each ASC-38C1600 function or channel uses only cable bits [5:4] + * and [1:0]. Bits [14], [7:6], [3:2] are unused. */ #define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */ #define HVD_LVD_SE 0x1C00 /* Device Detect Bits */ @@ -2745,6 +2848,33 @@ #define PRE_TEST_VALUE 0x05 #define NORMAL_VALUE 0x00 +/* + * ASC38C1600 Definitions + * + * IOPB_PCI_INT_CFG Bit Field Definitions + */ + +#define INTAB_LD 0x80 /* Value loaded from EEPROM Bit 11. */ + +/* + * Bit 1 can be set to change the interrupt for the Function to operate in + * Totem Pole mode. By default Bit 1 is 0 and the interrupt operates in + * Open Drain mode. Both functions of the ASC38C1600 must be set to the same + * mode, otherwise the operating mode is undefined. + */ +#define TOTEMPOLE 0x02 + +/* + * Bit 0 can be used to change the Int Pin for the Function. The value is + * 0 by default for both Functions with Function 0 using INT A and Function + * B using INT B. For Function 0 if set, INT B is used. For Function 1 if set, + * INT A is used. + * + * EEPROM Word 0 Bit 11 for each Function may change the initial Int Pin + * value specified in the PCI Configuration Space. + */ +#define INTAB 0x01 + /* a_advlib.h */ /* @@ -2759,7 +2889,7 @@ /* - * ASC_DVC_VAR 'warn_code' values + * ADV_DVC_VAR 'warn_code' values */ #define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */ #define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */ @@ -2770,11 +2900,8 @@ #define ADV_MAX_TID 15 /* max. target identifier */ #define ADV_MAX_LUN 7 /* max. logical unit number */ - /* - * AscInitGetConfig() and AscInitAsc1000Driver() Definitions - * - * Error code values are set in ASC_DVC_VAR 'err_code'. + * Error code values are set in ADV_DVC_VAR 'err_code'. */ #define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */ #define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */ @@ -2829,6 +2956,7 @@ #define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */ #define ASC_MC_ICQ 0x0160 #define ASC_MC_IRQ 0x0164 +#define ASC_MC_PPR_ABLE 0x017A /* * BIOS LRAM variable absolute offsets. @@ -2845,6 +2973,7 @@ * and handled by the microcode. */ #define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */ +#define CONTROL_FLAG_ENABLE_AIPP 0x0002 /* Enabled AIPP checking. */ /* * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format @@ -2876,6 +3005,10 @@ #define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */ #define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */ +/* + * All fields here are accessed by the board microcode and need to be + * little-endian. + */ typedef struct adv_carr_t { ADV_VADDR carr_va; /* Carrier Virtual Address */ @@ -2896,12 +3029,11 @@ #define ASC_NEXT_VPA_MASK 0xFFFFFFF0 #define ASC_RQ_DONE 0x00000001 +#define ASC_RQ_GOOD 0x00000002 #define ASC_CQ_STOPPER 0x00000000 #define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK) -#define ADV_PAGE_SIZE 4096 /* Assume 4KB page size. */ - #define ADV_CARRIER_NUM_PAGE_CROSSING \ (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \ (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE) @@ -2929,7 +3061,7 @@ * This structure can be discarded after initialization. Don't add * fields here needed after initialization. * - * Field naming convention: + * Field naming convention: * * *_enable indicates the field enables or disables a feature. The * value of the field is never reset. @@ -2949,7 +3081,7 @@ ushort serial1; /* EEPROM serial number word 1 */ ushort serial2; /* EEPROM serial number word 2 */ ushort serial3; /* EEPROM serial number word 3 */ -} ADV_DVC_CFG; +} ADV_DVC_CFG; struct adv_dvc_var; struct adv_scsi_req_q; @@ -2965,7 +3097,7 @@ * * One structure is required per host adapter. * - * Field naming convention: + * Field naming convention: * * *_able indicates both whether a feature should be enabled or disabled * and whether a device isi capable of the feature. At initialization @@ -2986,6 +3118,7 @@ ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */ ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */ ushort tagqng_able; /* try tagged queuing with a device */ + ushort ppr_able; /* PPR message capable per TID bitmask. */ uchar max_dvc_qng; /* maximum number of tagged commands per device */ ushort start_motor; /* start motor command allowed */ uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */ @@ -3007,13 +3140,13 @@ * driver may discard the buffer after initialization is done. */ ADV_DVC_CFG *cfg; /* temporary configuration structure */ -} ADV_DVC_VAR; +} ADV_DVC_VAR; #define NO_OF_SG_PER_BLOCK 15 typedef struct asc_sg_block { - uchar reserved1; - uchar reserved2; + uchar reserved1; + uchar reserved2; uchar reserved3; uchar sg_cnt; /* Valid entries in block. */ ADV_PADDR sg_ptr; /* Pointer to next sg block. */ @@ -3030,6 +3163,9 @@ * The microcode makes assumptions about the size and ordering of fields * in this structure. Do not change the structure definition here without * coordinating the change with the microcode. + * + * All fields accessed by microcode must be maintained in little_endian + * order. */ typedef struct adv_scsi_req_q { uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */ @@ -3042,16 +3178,16 @@ ADV_PADDR carr_pa; uchar mflag; uchar sense_len; - uchar cdb_len; /* SCSI CDB length. */ + uchar cdb_len; /* SCSI CDB length. Must <= 16 bytes. */ uchar scsi_cntl; uchar done_status; /* Completion status. */ uchar scsi_status; /* SCSI status byte. */ uchar host_status; /* Ucode host status. */ uchar sg_working_ix; - uchar cdb[12]; /* SCSI command block. */ + uchar cdb[12]; /* SCSI CDB bytes 0-11. */ ADV_PADDR sg_real_addr; /* SG list physical address. */ ADV_PADDR scsiq_rptr; - ADV_DCNT sg_working_data_cnt; + uchar cdb16[4]; /* SCSI CDB bytes 12-15. */ ADV_VADDR scsiq_ptr; ADV_VADDR carr_va; /* @@ -3062,6 +3198,7 @@ ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */ char *vdata_addr; /* Data buffer virtual address. */ uchar a_flag; + uchar pad[2]; /* Pad out to a word boundary. */ } ADV_SCSI_REQ_Q; /* @@ -3097,14 +3234,16 @@ #define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */ #define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */ #define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */ +#define ADV_RDMA_IN_CARR_AND_Q_INVALID 0x04 /* RDMAed-in data invalid. */ + #define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */ /* * Device drivers must define the following functions. */ -STATIC int DvcEnterCritical(void); -STATIC void DvcLeaveCritical(int); +STATIC inline ulong DvcEnterCritical(void); +STATIC inline void DvcLeaveCritical(ulong); STATIC void DvcSleepMilliSecond(ADV_DCNT); STATIC uchar DvcAdvReadPCIConfigByte(ADV_DVC_VAR *, ushort); STATIC void DvcAdvWritePCIConfigByte(ADV_DVC_VAR *, ushort, uchar); @@ -3120,6 +3259,7 @@ STATIC int AdvInitGetConfig(ADV_DVC_VAR *); STATIC int AdvInitAsc3550Driver(ADV_DVC_VAR *); STATIC int AdvInitAsc38C0800Driver(ADV_DVC_VAR *); +STATIC int AdvInitAsc38C1600Driver(ADV_DVC_VAR *); STATIC int AdvResetChipAndSB(ADV_DVC_VAR *); STATIC int AdvResetSB(ADV_DVC_VAR *asc_dvc); @@ -3130,10 +3270,13 @@ STATIC void AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *); STATIC int AdvInitFrom3550EEP(ADV_DVC_VAR *); STATIC int AdvInitFrom38C0800EEP(ADV_DVC_VAR *); +STATIC int AdvInitFrom38C1600EEP(ADV_DVC_VAR *); STATIC ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *); STATIC void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *); STATIC ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *); STATIC void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *); +STATIC ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *); +STATIC void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *); STATIC void AdvWaitEEPCmd(AdvPortAddr); STATIC ushort AdvReadEEPWord(AdvPortAddr, int); @@ -3143,71 +3286,9 @@ #define AscPCICmdRegBits_BusMastering 0x0007 #define AscPCICmdRegBits_ParErrRespCtrl 0x0040 -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) - /* Read byte from a register. */ #define AdvReadByteRegister(iop_base, reg_off) \ - (inp((iop_base) + (reg_off))) - -/* Write byte to a register. */ -#define AdvWriteByteRegister(iop_base, reg_off, byte) \ - (outp((iop_base) + (reg_off), (byte))) - -/* Read word (2 bytes) from a register. */ -#define AdvReadWordRegister(iop_base, reg_off) \ - (le16_to_cpu(inpw((iop_base) + (reg_off)))) - -/* Write word (2 bytes) to a register. */ -#define AdvWriteWordRegister(iop_base, reg_off, word) \ - (outpw((iop_base) + (reg_off), cpu_to_le16(word))) - -/* Read byte from LRAM. */ -#define AdvReadByteLram(iop_base, addr, byte) \ -do { \ - outpw((iop_base) + IOPW_RAM_ADDR, (addr)); \ - (byte) = inp((iop_base) + IOPB_RAM_DATA); \ -} while (0) - -/* Write byte to LRAM. */ -#define AdvWriteByteLram(iop_base, addr, byte) \ - (outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \ - outp((iop_base) + IOPB_RAM_DATA, (byte))) - -/* Read word (2 bytes) from LRAM. */ -#define AdvReadWordLram(iop_base, addr, word) \ -do { \ - outpw((iop_base) + IOPW_RAM_ADDR, (addr)); \ - (word) = le16_to_cpu(inpw((iop_base) + IOPW_RAM_DATA)); \ -} while (0) - -/* Write word (2 bytes) to LRAM. */ -#define AdvWriteWordLram(iop_base, addr, word) \ - (outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \ - outpw((iop_base) + IOPW_RAM_DATA, cpu_to_le16(word))) - -/* Write double word (4 bytes) to LRAM */ -/* Because of unspecified C language ordering don't use auto-increment. */ -#define AdvWriteDWordLram(iop_base, addr, dword) \ - ((outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \ - outpw((iop_base) + IOPW_RAM_DATA, \ - cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \ - (outpw((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \ - outpw((iop_base) + IOPW_RAM_DATA, \ - cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF))))) - -/* Read word (2 bytes) from LRAM assuming that the address is already set. */ -#define AdvReadWordAutoIncLram(iop_base) \ - (le16_to_cpu(inpw((iop_base) + IOPW_RAM_DATA))) - -/* Write word (2 bytes) to LRAM assuming that the address is already set. */ -#define AdvWriteWordAutoIncLram(iop_base, word) \ - (outpw((iop_base) + IOPW_RAM_DATA, cpu_to_le16(word))) - -#else /* version >= v1,3,0 */ - -/* Read byte from a register. */ -#define AdvReadByteRegister(iop_base, reg_off) \ - (ADV_MEM_READB((iop_base) + (reg_off))) + (ADV_MEM_READB((iop_base) + (reg_off))) /* Write byte to a register. */ #define AdvWriteByteRegister(iop_base, reg_off, byte) \ @@ -3215,11 +3296,15 @@ /* Read word (2 bytes) from a register. */ #define AdvReadWordRegister(iop_base, reg_off) \ - le16_to_cpu(ADV_MEM_READW((iop_base) + (reg_off))) + (ADV_MEM_READW((iop_base) + (reg_off))) /* Write word (2 bytes) to a register. */ #define AdvWriteWordRegister(iop_base, reg_off, word) \ - (ADV_MEM_WRITEW((iop_base) + (reg_off), cpu_to_le16(word))) + (ADV_MEM_WRITEW((iop_base) + (reg_off), (word))) + +/* Write dword (4 bytes) to a register. */ +#define AdvWriteDWordRegister(iop_base, reg_off, dword) \ + (ADV_MEM_WRITEDW((iop_base) + (reg_off), (dword))) /* Read byte from LRAM. */ #define AdvReadByteLram(iop_base, addr, byte) \ @@ -3237,17 +3322,17 @@ #define AdvReadWordLram(iop_base, addr, word) \ do { \ ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \ - (word) = le16_to_cpu(ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \ + (word) = (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \ } while (0) /* Write word (2 bytes) to LRAM. */ #define AdvWriteWordLram(iop_base, addr, word) \ (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \ - ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, cpu_to_le16(word))) + ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word))) -/* Write double word (4 bytes) to LRAM */ +/* Write little-endian double word (4 bytes) to LRAM */ /* Because of unspecified C language ordering don't use auto-increment. */ -#define AdvWriteDWordLram(iop_base, addr, dword) \ +#define AdvWriteDWordLramNoSwap(iop_base, addr, dword) \ ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \ ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \ cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \ @@ -3257,13 +3342,12 @@ /* Read word (2 bytes) from LRAM assuming that the address is already set. */ #define AdvReadWordAutoIncLram(iop_base) \ - le16_to_cpu(ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)) + (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)) /* Write word (2 bytes) to LRAM assuming that the address is already set. */ #define AdvWriteWordAutoIncLram(iop_base, word) \ - (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, cpu_to_le16(word))) + (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word))) -#endif /* version >= v1,3,0 */ /* * Define macro to check for Condor signature. @@ -3288,7 +3372,7 @@ /* * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must * match the ASC_SCSI_REQ_Q 'srb_ptr' field. - * + * * If the request has not yet been sent to the device it will simply be * aborted from RISC memory. If the request is disconnected it will be * aborted on reselection by sending an Abort Message to the target ID. @@ -3376,6 +3460,7 @@ */ extern ADVEEP_3550_CONFIG Default_3550_EEPROM_Config; extern ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config; +extern ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config; /* * DvcGetPhyAddr() flag arguments @@ -3388,8 +3473,9 @@ #define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */ /* Return the address that is aligned at the next doubleword >= to 'addr'. */ -#define ADV_DWALIGN(addr) (((ulong) (addr) + 0x3) & ~0x3) +#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7) #define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF) +#define ADV_32BALIGN(addr) (((ulong) (addr) + 0x1F) & ~0x1F) /* * Total contiguous memory needed for driver SG blocks. @@ -3399,50 +3485,76 @@ * single request. */ -#ifndef ADV_MAX_SG_LIST -Forced Error: Driver must define ADV_MAX_SG_LIST. -#endif /* ADV_MAX_SG_LIST */ - #define ADV_SG_LIST_MAX_BYTE_SIZE \ (sizeof(ADV_SG_BLOCK) * \ ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)) +/* + * Inquiry data structure and bitfield macros + * + * Using bitfields to access the subchar data isn't portable across + * endianness, so instead mask and shift. Only quantities of more + * than 1 bit are shifted, since the others are just tested for true + * or false. + */ + +#define ADV_INQ_DVC_TYPE(inq) ((inq)->periph & 0x1f) +#define ADV_INQ_QUALIFIER(inq) (((inq)->periph & 0xe0) >> 5) +#define ADV_INQ_DVC_TYPE_MOD(inq) ((inq)->devtype & 0x7f) +#define ADV_INQ_REMOVABLE(inq) ((inq)->devtype & 0x80) +#define ADV_INQ_ANSI_VER(inq) ((inq)->ver & 0x07) +#define ADV_INQ_ECMA_VER(inq) (((inq)->ver & 0x38) >> 3) +#define ADV_INQ_ISO_VER(inq) (((inq)->ver & 0xc0) >> 6) +#define ADV_INQ_RESPONSE_FMT(inq) ((inq)->byte3 & 0x0f) +#define ADV_INQ_TERM_IO(inq) ((inq)->byte3 & 0x40) +#define ADV_INQ_ASYNC_NOTIF(inq) ((inq)->byte3 & 0x80) +#define ADV_INQ_SOFT_RESET(inq) ((inq)->flags & 0x01) +#define ADV_INQ_CMD_QUEUE(inq) ((inq)->flags & 0x02) +#define ADV_INQ_LINK_CMD(inq) ((inq)->flags & 0x08) +#define ADV_INQ_SYNC(inq) ((inq)->flags & 0x10) +#define ADV_INQ_WIDE16(inq) ((inq)->flags & 0x20) +#define ADV_INQ_WIDE32(inq) ((inq)->flags & 0x40) +#define ADV_INQ_REL_ADDR(inq) ((inq)->flags & 0x80) +#define ADV_INQ_INFO_UNIT(inq) ((inq)->info & 0x01) +#define ADV_INQ_QUICK_ARB(inq) ((inq)->info & 0x02) +#define ADV_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2) + typedef struct { - uchar peri_dvc_type : 5; /* peripheral device type */ - uchar peri_qualifier : 3; /* peripheral qualifier */ - uchar dvc_type_modifier : 7; /* device type modifier (for SCSI I) */ - uchar rmb : 1; /* RMB - removable medium bit */ - uchar ansi_apr_ver : 3; /* ANSI approved version */ - uchar ecma_ver : 3; /* ECMA version */ - uchar iso_ver : 2; /* ISO version */ - uchar rsp_data_fmt : 4; /* response data format */ + uchar periph; /* peripheral device type [0:4] */ + /* peripheral qualifier [5:7] */ + uchar devtype; /* device type modifier (for SCSI I) [0:6] */ + /* RMB - removable medium bit [7] */ + uchar ver; /* ANSI approved version [0:2] */ + /* ECMA version [3:5] */ + /* ISO version [6:7] */ + uchar byte3; /* response data format [0:3] */ /* 0 SCSI 1 */ /* 1 CCS */ /* 2 SCSI-2 */ /* 3-F reserved */ - uchar res1 : 2; /* reserved */ - uchar TemIOP : 1; /* terminate I/O process bit (see 5.6.22) */ - uchar aenc : 1; /* asynch. event notification (processor) */ + /* reserved [4:5] */ + /* terminate I/O process bit (see 5.6.22) [6] */ + /* asynch. event notification (processor) [7] */ uchar add_len; /* additional length */ + uchar res1; /* reserved */ uchar res2; /* reserved */ - uchar res3; /* reserved */ - uchar StfRe : 1; /* soft reset implemented */ - uchar CmdQue : 1; /* command queuing */ - uchar res4 : 1; /* reserved */ - uchar Linked : 1; /* linked command for this logical unit */ - uchar Sync : 1; /* synchronous data transfer */ - uchar WBus16 : 1; /* wide bus 16 bit data transfer */ - uchar WBus32 : 1; /* wide bus 32 bit data transfer */ - uchar RelAdr : 1; /* relative addressing mode */ + uchar flags; /* soft reset implemented [0] */ + /* command queuing [1] */ + /* reserved [2] */ + /* linked command for this logical unit [3] */ + /* synchronous data transfer [4] */ + /* wide bus 16 bit data transfer [5] */ + /* wide bus 32 bit data transfer [6] */ + /* relative addressing mode [7] */ uchar vendor_id[8]; /* vendor identification */ uchar product_id[16]; /* product identification */ uchar product_rev_level[4]; /* product revision level */ uchar vendor_specific[20]; /* vendor specific */ - uchar IUS : 1; /* information unit supported */ - uchar QAS : 1; /* quick arbitrate supported */ - uchar Clocking : 2; /* clocking field */ - uchar res5 : 4; /* reserved */ - uchar res6; /* reserved */ + uchar info; /* information unit supported [0] */ + /* quick arbitrate supported [1] */ + /* clocking field [2:3] */ + /* reserved [4:7] */ + uchar res3; /* reserved */ } ADV_SCSI_INQUIRY; /* 58 bytes */ @@ -3459,7 +3571,6 @@ /* asc_board_t flags */ #define ASC_HOST_IN_RESET 0x01 -#define ASC_HOST_IN_ABORT 0x02 #define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */ #define ASC_SELECT_QUEUE_DEPTHS 0x08 @@ -3473,22 +3584,17 @@ * and data after loading, define macros for this purpose. These macros * are not used when the driver is built as a module, cf. linux/init.h. */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,23) -#define ASC_INITFUNC(type, func) type func -#define ASC_INITDATA -#define ASC_INIT -#else /* version >= v2.1.23 */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,16) -#define ASC_INITFUNC(type, func) __initfunc(type func) -#else /* version >= v2.3.16 */ +#if ASC_LINUX_KERNEL24 #define ASC_INITFUNC(type, func) type __init func -#endif /* version >= v2.3.16 */ +#elif ASC_LINUX_KERNEL22 +#define ASC_INITFUNC(type, func) __initfunc(type func) +#endif #define ASC_INITDATA __initdata #define ASC_INIT __init -#endif /* version >= v2.1.23 */ #define ASC_INFO_SIZE 128 /* advansys_info() line size */ +#ifdef CONFIG_PROC_FS /* /proc/scsi/advansys/[0...] related definitions */ #define ASC_PRTBUF_SIZE 2048 #define ASC_PRTLINE_SIZE 160 @@ -3504,6 +3610,37 @@ } #define ASC_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif /* CONFIG_PROC_FS */ + +/* + * XXX - Release and acquire the io_request_lock. These macros are needed + * because the 2.4 kernel SCSI mid-level driver holds the 'io_request_lock' + * on entry to SCSI low-level drivers. + * + * These definitions and all code that uses code should be removed when the + * SCSI mid-level driver no longer holds the 'io_request_lock' on entry to + * SCSI low-level driver detect, queuecommand, and reset entrypoints. + * + * The interrupt flags values doesn't matter in the macros because the + * SCSI mid-level will save and restore the flags values before and after + * calling advansys_detect, advansys_queuecommand, and advansys_reset where + * these macros are used. We do want interrupts enabled after the lock is + * released so an explicit sti() is done. The driver only needs interrupts + * disabled when it acquires the per board lock. + */ +#define ASC_UNLOCK_IO_REQUEST_LOCK \ + { \ + ulong flags; /* flags value not needed, cf. comment above. */ \ + save_flags(flags); \ + spin_unlock_irqrestore(&io_request_lock, flags); \ + sti(); /* enable interrupts */ \ + } + +#define ASC_LOCK_IO_REQUEST_LOCK \ + { \ + ulong flags; /* flags value not needed, cf. comment above. */ \ + spin_lock_irqsave(&io_request_lock, flags); \ + } /* Asc Library return codes */ #define ASC_TRUE 1 @@ -3627,12 +3764,13 @@ #define PCI_MAX_BUS 0xFF #define PCI_IOADDRESS_MASK 0xFFFE #define ASC_PCI_VENDORID 0x10CD -#define ASC_PCI_DEVICE_ID_CNT 5 /* PCI Device ID count. */ +#define ASC_PCI_DEVICE_ID_CNT 6 /* PCI Device ID count. */ #define ASC_PCI_DEVICE_ID_1100 0x1100 #define ASC_PCI_DEVICE_ID_1200 0x1200 #define ASC_PCI_DEVICE_ID_1300 0x1300 #define ASC_PCI_DEVICE_ID_2300 0x2300 /* ASC-3550 */ #define ASC_PCI_DEVICE_ID_2500 0x2500 /* ASC-38C0800 */ +#define ASC_PCI_DEVICE_ID_2700 0x2700 /* ASC-38C1600 */ /* PCI IO Port Addresses to generate special cycle */ @@ -3843,10 +3981,8 @@ /* Per board statistics structure */ struct asc_stats { /* Driver Entrypoint Statistics */ - ADV_DCNT command; /* # calls to advansys_command() */ ADV_DCNT queuecommand; /* # calls to advansys_queuecommand() */ - ADV_DCNT abort; /* # calls to advansys_abort() */ - ADV_DCNT reset; /* # calls to advansys_reset() */ + ADV_DCNT reset; /* # calls to advansys_eh_bus_reset() */ ADV_DCNT biosparam; /* # calls to advansys_biosparam() */ ADV_DCNT interrupt; /* # advansys_interrupt() calls */ ADV_DCNT callback; /* # calls to asc/adv_isr_callback() */ @@ -3899,16 +4035,18 @@ * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux * up to 255 scatter-gather elements may be used per request or * ADV_SCSI_REQ_Q. + * + * Both structures must be 32 byte aligned. */ typedef struct adv_sgblk { - ADV_SG_BLOCK sg_block; /* Sgblock structure. */ - uchar align2[4]; /* Sgblock structure padding. */ - struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */ + ADV_SG_BLOCK sg_block; /* Sgblock structure. */ + uchar align[32]; /* Sgblock structure padding. */ + struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */ } adv_sgblk_t; typedef struct adv_req { ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */ - uchar align1[4]; /* Request structure padding. */ + uchar align[32]; /* Request structure padding. */ Scsi_Cmnd *cmndp; /* Mid-Level SCSI command pointer. */ adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */ struct adv_req *next_reqp; /* Next Request Structure. */ @@ -3932,6 +4070,7 @@ ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */ ADV_DVC_CFG adv_dvc_cfg; /* Wide board */ } dvc_cfg; + ushort asc_n_io_port; /* Number I/O ports. */ asc_queue_t active; /* Active command queue */ asc_queue_t waiting; /* Waiting command queue */ asc_queue_t done; /* Done command queue */ @@ -3944,12 +4083,14 @@ ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */ ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */ ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */ + ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */ } eep_config; ulong last_reset; /* Saved last reset time */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + spinlock_t lock; /* Board spinlock */ +#ifdef CONFIG_PROC_FS /* /proc/scsi/advansys/[0...] */ - char *prtbuf; /* Statistics Print Buffer */ -#endif /* version >= v1.3.0 */ + char *prtbuf; /* /proc print buffer */ +#endif /* CONFIG_PROC_FS */ #ifdef ADVANSYS_STATS struct asc_stats asc_stats; /* Board statistics */ #endif /* ADVANSYS_STATS */ @@ -4032,8 +4173,8 @@ /* Note: All driver global data should be initialized. */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28) && \ - LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +#if ASC_LINUX_KERNEL22 +#ifdef CONFIG_PROC_FS struct proc_dir_entry proc_scsi_advansys = { PROC_SCSI_ADVANSYS, /* unsigned short low_ino */ @@ -4042,13 +4183,14 @@ S_IFDIR | S_IRUGO | S_IXUGO, /* mode_t mode */ 2 /* nlink_t nlink */ }; -#endif /* v2.3.28 > version >= v1.3.0 */ +#endif /* CONFIG_PROC_FS */ +#endif /* ASC_LINUX_KERNEL22 */ /* Number of boards detected in system. */ STATIC int asc_board_count = 0; STATIC struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { 0 }; -/* Overrun buffer shared between all boards. */ +/* Overrun buffer used by all narrow boards. */ STATIC uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 }; /* @@ -4065,12 +4207,6 @@ ASC_IS_PCI, }; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI -STATIC int pci_scan_method ASC_INITDATA = -1; -#endif /* ASC_CONFIG_PCI */ -#endif /* version < v2.1.93 */ - /* * Used with the LILO 'advansys' option to eliminate or * limit I/O port probing at boot time, cf. advansys_setup(). @@ -4078,19 +4214,6 @@ STATIC int asc_iopflag = ASC_FALSE; STATIC int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 }; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) -/* - * In kernels earlier than v1.3.0, kmalloc() does not work - * during driver initialization. Therefore statically declare - * 16 elements of each structure. v1.3.0 kernels will probably - * not need any more than this number. - */ -uchar adv_carr_buf[20 * sizeof(ADV_CARR_T)] = { 0 }; -uchar adv_req_buf[16 * sizeof(adv_req_t)] = { 0 }; -#define ADV_SGBLK_BUF_CNT 32 -uchar adv_sgblk_buf[ADV_SGBLK_BUF_CNT * sizeof(adv_sgblk_t)] = { 0 }; -#endif /* version >= v1,3,0 */ - #ifdef ADVANSYS_DEBUG STATIC char * asc_bus_name[ASC_NUM_BUS] = { @@ -4100,7 +4223,7 @@ "ASC_IS_PCI", }; -STATIC int asc_dbglvl = 2; +STATIC int asc_dbglvl = 3; #endif /* ADVANSYS_DEBUG */ /* Declaration for Asc Library internal data referenced by driver. */ @@ -4113,19 +4236,9 @@ * advansys.h contains function prototypes for functions global to Linux. */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) -STATIC int asc_proc_copy(off_t, off_t, char *, int , char *, int); -#endif /* version >= v1.3.0 */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) -STATIC void advansys_interrupt(int, struct pt_regs *); -#else /* version >= v1.3.70 */ -STATIC void advansys_interrupt(int, void *, struct pt_regs *); -#endif /* version >= v1.3.70 */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -STATIC void advansys_select_queue_depths(struct Scsi_Host *, - Scsi_Device *); -#endif /* version >= v1.3.89 */ -STATIC void advansys_command_done(Scsi_Cmnd *); +STATIC void advansys_interrupt(int, void *, struct pt_regs *); +STATIC void advansys_select_queue_depths(struct Scsi_Host *, + Scsi_Device *); STATIC void asc_scsi_done_list(Scsi_Cmnd *); STATIC int asc_execute_scsi_cmnd(Scsi_Cmnd *); STATIC int asc_build_req(asc_board_t *, Scsi_Cmnd *); @@ -4134,24 +4247,13 @@ STATIC void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *); STATIC void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *); STATIC void adv_async_callback(ADV_DVC_VAR *, uchar); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI -STATIC int asc_srch_pci_dev(PCI_DEVICE *); -STATIC uchar asc_scan_method(void); -STATIC int asc_pci_find_dev(PCI_DEVICE *); -STATIC void asc_get_pci_cfg(PCI_DEVICE *, PCI_CONFIG_SPACE *); -STATIC ushort asc_get_cfg_word(PCI_DATA *); -STATIC uchar asc_get_cfg_byte(PCI_DATA *); -STATIC void asc_put_cfg_byte(PCI_DATA *, uchar); -#endif /* ASC_CONFIG_PCI */ -#endif /* version < v2.1.93 */ STATIC void asc_enqueue(asc_queue_t *, REQP, int); STATIC REQP asc_dequeue(asc_queue_t *, int); STATIC REQP asc_dequeue_list(asc_queue_t *, REQP *, int); STATIC int asc_rmqueue(asc_queue_t *, REQP); -STATIC int asc_isqueued(asc_queue_t *, REQP); STATIC void asc_execute_queue(asc_queue_t *); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +#ifdef CONFIG_PROC_FS +STATIC int asc_proc_copy(off_t, off_t, char *, int , char *, int); STATIC int asc_prt_board_devices(struct Scsi_Host *, char *, int); STATIC int asc_prt_adv_bios(struct Scsi_Host *, char *, int); STATIC int asc_get_eeprom_string(ushort *serialnum, uchar *cp); @@ -4161,16 +4263,21 @@ STATIC int asc_prt_asc_board_info(struct Scsi_Host *, char *, int); STATIC int asc_prt_adv_board_info(struct Scsi_Host *, char *, int); STATIC int asc_prt_line(char *, int, char *fmt, ...); -#endif /* version >= v1.3.0 */ +#endif /* CONFIG_PROC_FS */ /* Declaration for Asc Library internal functions referenced by driver. */ STATIC int AscFindSignature(PortAddr); STATIC ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort); +/* Statistics function prototypes. */ #ifdef ADVANSYS_STATS +#ifdef CONFIG_PROC_FS STATIC int asc_prt_board_stats(struct Scsi_Host *, char *, int); +STATIC int asc_prt_target_stats(struct Scsi_Host *, int, char *, int); +#endif /* CONFIG_PROC_FS */ #endif /* ADVANSYS_STATS */ +/* Debug function prototypes. */ #ifdef ADVANSYS_DEBUG STATIC void asc_prt_scsi_host(struct Scsi_Host *); STATIC void asc_prt_scsi_cmnd(Scsi_Cmnd *); @@ -4185,16 +4292,12 @@ STATIC void asc_prt_hex(char *f, uchar *, int); #endif /* ADVANSYS_DEBUG */ -#ifdef ADVANSYS_ASSERT -STATIC int advansys_interrupts_enabled(void); -#endif /* ADVANSYS_ASSERT */ - /* * --- Linux 'Scsi_Host_Template' and advansys_setup() Functions */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +#ifdef CONFIG_PROC_FS /* * advansys_proc_info() - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)] * @@ -4216,10 +4319,9 @@ * user just won't get all the available statistics. */ int -advansys_proc_info(char *buffer, char **start, off_t offset, int length, +advansys_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) { -#ifdef CONFIG_PROC_FS struct Scsi_Host *shp; asc_board_t *boardp; int i; @@ -4231,6 +4333,9 @@ char *curbuf; off_t advoffset; Scsi_Device *scd; +#ifdef ADVANSYS_STATS + int tgt_id; +#endif /* ADVANSYS_STATS */ ASC_DBG(1, "advansys_proc_info: begin\n"); @@ -4322,11 +4427,7 @@ * Display target driver information for each device attached * to the board. */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,75) - for (scd = scsi_devices; scd; scd = scd->next) -#else /* version >= v2.1.75 */ for (scd = shp->host_queue; scd; scd = scd->next) -#endif /* version >= v2.1.75 */ { if (scd->host == shp) { cp = boardp->prtbuf; @@ -4347,7 +4448,7 @@ curbuf += cnt; } } - + /* * Display EEPROM configuration for the board. */ @@ -4390,7 +4491,7 @@ */ cp = boardp->prtbuf; cplen = asc_prt_board_stats(shp, cp, ASC_PRTBUF_SIZE); - ASC_ASSERT(cplen < ASC_PRTBUF_SIZE); + ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE); cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); totcnt += cnt; leftlen -= cnt; @@ -4400,6 +4501,24 @@ } advoffset += cplen; curbuf += cnt; + + /* + * Display driver statistics for each target. + */ + for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) { + cp = boardp->prtbuf; + cplen = asc_prt_target_stats(shp, tgt_id, cp, ASC_PRTBUF_SIZE); + ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE); + cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); + totcnt += cnt; + leftlen -= cnt; + if (leftlen == 0) { + ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); + return totcnt; + } + advoffset += cplen; + curbuf += cnt; + } #endif /* ADVANSYS_STATS */ /* @@ -4426,11 +4545,8 @@ ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); return totcnt; -#else /* CONFIG_PROC_FS */ - return 0; -#endif /* CONFIG_PROC_FS */ } -#endif /* version >= v1.3.0 */ +#endif /* CONFIG_PROC_FS */ /* * advansys_detect() @@ -4461,19 +4577,6 @@ int ioport = 0; int share_irq = FALSE; int iolen = 0; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - int pci_init_search = 0; - PCI_DEVICE pci_device[ASC_NUM_BOARD_SUPPORTED]; - int pci_card_cnt_max = 0; - int pci_card_cnt = 0; - PCI_DEVICE pciDevice; - PCI_CONFIG_SPACE pciConfig; -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) - ADV_PADDR pci_memory_address; -#endif /* version >= v1,3,0 */ -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ #ifdef CONFIG_PCI int pci_init_search = 0; struct pci_dev *pci_devicep[ASC_NUM_BOARD_SUPPORTED]; @@ -4486,11 +4589,11 @@ ASC_PCI_DEVICE_ID_1200, ASC_PCI_DEVICE_ID_1300, ASC_PCI_DEVICE_ID_2300, - ASC_PCI_DEVICE_ID_2500 + ASC_PCI_DEVICE_ID_2500, + ASC_PCI_DEVICE_ID_2700 }; ADV_PADDR pci_memory_address; #endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ int warn_code, err_code; int ret; @@ -4503,11 +4606,18 @@ ASC_DBG(1, "advansys_detect: begin\n"); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,28) + /* + * XXX - Remove this comment and the next line when SCSI mid-level + * no longer acquires 'io_request_lock' before calling the SCSI + * low-level detect entrypoint. + */ + ASC_UNLOCK_IO_REQUEST_LOCK + +#if ASC_LINUX_KERNEL24 tpnt->proc_name = "advansys"; -#elif LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +#elif ASC_LINUX_KERNEL22 tpnt->proc_dir = &proc_scsi_advansys; -#endif /* version >= v1.3.0 */ +#endif asc_board_count = 0; @@ -4517,7 +4627,7 @@ */ if (asc_iopflag == ASC_TRUE) { for (ioport = 0; ioport < ASC_NUM_IOPORT_PROBE; ioport++) { - ASC_DBG2(1, "advansys_detect: asc_ioport[%d] %x\n", + ASC_DBG2(1, "advansys_detect: asc_ioport[%d] 0x%x\n", ioport, asc_ioport[ioport]); if (asc_ioport[ioport] != 0) { for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX; iop++) { @@ -4536,15 +4646,6 @@ ioport = 0; } -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - memset(&pciDevice, 0, sizeof(PCI_DEVICE)); - memset(&pciConfig, 0, sizeof(PCI_CONFIG_SPACE)); - pciDevice.maxBusNumber = PCI_MAX_BUS; - pciDevice.endSlot = PCI_MAX_SLOT; -#endif /* ASC_CONFIG_PCI */ -#endif /* version < v2.1.93 */ - for (bus = 0; bus < ASC_NUM_BUS; bus++) { ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n", @@ -4559,6 +4660,7 @@ switch (asc_bus[bus]) { case ASC_IS_ISA: case ASC_IS_VL: +#ifdef CONFIG_ISA if (asc_iopflag == ASC_FALSE) { iop = AscSearchIOPortAddr(iop, asc_bus[bus]); } else { @@ -4577,7 +4679,8 @@ } } if (iop) { - ASC_DBG1(1, "advansys_detect: probing I/O port %x...\n", + ASC_DBG1(1, + "advansys_detect: probing I/O port 0x%x...\n", iop); if (check_region(iop, ASC_IOADR_GAP) != 0) { printk( @@ -4618,74 +4721,16 @@ asc_ioport[ioport++] = 0; } } +#endif /* CONFIG_ISA */ break; case ASC_IS_EISA: +#ifdef CONFIG_ISA iop = AscSearchIOPortAddr(iop, asc_bus[bus]); +#endif /* CONFIG_ISA */ break; case ASC_IS_PCI: -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - if (pci_init_search == 0) { - int i, j; - - pci_init_search = 1; - - /* Find all PCI cards. */ - while (asc_srch_pci_dev(&pciDevice) == PCI_DEVICE_FOUND) { - pci_device[pci_card_cnt_max++] = pciDevice; - } - - /* - * Sort PCI cards in ascending order by PCI Bus, Slot, - * and Device Number. - */ - for (i = 0; i < pci_card_cnt_max - 1; i++) - { - for (j = i + 1; j < pci_card_cnt_max; j++) { - if ((pci_device[j].busNumber < - pci_device[i].busNumber) || - ((pci_device[j].busNumber == - pci_device[i].busNumber) && - (pci_device[j].slotNumber < - pci_device[i].slotNumber)) || - ((pci_device[j].busNumber == - pci_device[i].busNumber) && - (pci_device[j].slotNumber == - pci_device[i].slotNumber) && - (pci_device[j].devFunc < - pci_device[i].devFunc))) { - pciDevice = pci_device[i]; - pci_device[i] = pci_device[j]; - pci_device[j] = pciDevice; - } - } - } - - pci_card_cnt = 0; - } else { - pci_card_cnt++; - } - - if (pci_card_cnt == pci_card_cnt_max) { - iop = 0; - } else { - pciDevice = pci_device[pci_card_cnt]; - ASC_DBG2(2, - "advansys_detect: slotFound %d, busNumber %d\n", - pciDevice.slotFound, pciDevice.busNumber); - asc_get_pci_cfg(&pciDevice, &pciConfig); - iop = pciConfig.baseAddress[0] & PCI_IOADDRESS_MASK; - ASC_DBG2(1, - "advansys_detect: vendorID %X, deviceID %X\n", - pciConfig.vendorID, pciConfig.deviceID); - ASC_DBG2(2, "advansys_detect: iop %X, irqLine %d\n", - iop, pciConfig.irqLine); - } - break; -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ #ifdef CONFIG_PCI if (pci_init_search == 0) { int i, j; @@ -4699,8 +4744,13 @@ NULL) { pci_device_id_cnt++; } else { - if (pci_enable_device(pci_devp) == 0) - pci_devicep[pci_card_cnt_max++] = pci_devp; +#if ASC_LINUX_KERNEL24 + if (pci_enable_device(pci_devp) == 0) { + pci_devicep[pci_card_cnt_max++] = pci_devp; + } +#elif ASC_LINUX_KERNEL22 + pci_devicep[pci_card_cnt_max++] = pci_devp; +#endif } } @@ -4737,11 +4787,11 @@ ASC_DBG2(2, "advansys_detect: devfn %d, bus number %d\n", pci_devp->devfn, pci_devp->bus->number); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,13) - iop = pci_devp->base_address[0] & PCI_IOADDRESS_MASK; -#else /* version >= v2.3.13 */ +#if ASC_LINUX_KERNEL24 iop = pci_resource_start(pci_devp, 0); -#endif /* version >= v2.3.13 */ +#elif ASC_LINUX_KERNEL22 + iop = pci_devp->base_address[0] & PCI_IOADDRESS_MASK; +#endif ASC_DBG2(1, "advansys_detect: vendorID %X, deviceID %X\n", pci_devp->vendor, pci_devp->device); @@ -4749,7 +4799,6 @@ iop, pci_devp->irq); } #endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ break; default: @@ -4757,7 +4806,7 @@ asc_bus[bus]); break; } - ASC_DBG1(1, "advansys_detect: iop %x\n", iop); + ASC_DBG1(1, "advansys_detect: iop 0x%x\n", iop); /* * Adapter not found, try next bus type. @@ -4774,9 +4823,10 @@ */ ASC_DBG(2, "advansys_detect: scsi_register()\n"); shp = scsi_register(tpnt, sizeof(asc_board_t)); - - if(shp==NULL) - continue; + + if (shp == NULL) { + continue; + } /* Save a pointer to the Scsi_host of each board found. */ asc_host[asc_board_count++] = shp; @@ -4786,6 +4836,9 @@ memset(boardp, 0, sizeof(asc_board_t)); boardp->id = asc_board_count - 1; + /* Initialize spinlock. */ + boardp->lock = SPIN_LOCK_UNLOCKED; + /* * Handle both narrow and wide boards. * @@ -4793,25 +4846,15 @@ * wide board flag. Set-up the board structure based on * the board type. */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - if (asc_bus[bus] == ASC_IS_PCI && - (pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300 || - pciConfig.deviceID == ASC_PCI_DEVICE_ID_2500)) - { - boardp->flags |= ASC_IS_WIDE_BOARD; - } -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ #ifdef CONFIG_PCI if (asc_bus[bus] == ASC_IS_PCI && (pci_devp->device == ASC_PCI_DEVICE_ID_2300 || - pci_devp->device == ASC_PCI_DEVICE_ID_2500)) + pci_devp->device == ASC_PCI_DEVICE_ID_2500 || + pci_devp->device == ASC_PCI_DEVICE_ID_2700)) { boardp->flags |= ASC_IS_WIDE_BOARD; } #endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ if (ASC_NARROW_BOARD(boardp)) { ASC_DBG(1, "advansys_detect: narrow board\n"); @@ -4829,36 +4872,22 @@ adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg; adv_dvc_varp->isr_callback = adv_isr_callback; adv_dvc_varp->async_callback = adv_async_callback; - -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - if (pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300) - { - ASC_DBG(1, "advansys_detect: ASC-3550\n"); - adv_dvc_varp->chip_type = ADV_CHIP_ASC3550; - } else - { - ASC_DBG(1, "advansys_detect: ASC-38C0800\n"); - adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800; - } -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ #ifdef CONFIG_PCI if (pci_devp->device == ASC_PCI_DEVICE_ID_2300) { ASC_DBG(1, "advansys_detect: ASC-3550\n"); adv_dvc_varp->chip_type = ADV_CHIP_ASC3550; - } else + } else if (pci_devp->device == ASC_PCI_DEVICE_ID_2500) { ASC_DBG(1, "advansys_detect: ASC-38C0800\n"); adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800; + } else + { + ASC_DBG(1, "advansys_detect: ASC-38C1600\n"); + adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600; } #endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) - adv_dvc_varp->iop_base = iop; -#else /* version >= v1,3,0 */ /* * Map the board's registers into virtual memory for * PCI slave access. Only memory accesses are used to @@ -4873,76 +4902,53 @@ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { iolen = ADV_3550_IOLEN; - } else { + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) + { iolen = ADV_38C0800_IOLEN; + } else + { + iolen = ADV_38C1600_IOLEN; } -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - pci_memory_address = pciConfig.baseAddress[1]; - ASC_DBG1(1, "advansys_detect: pci_memory_address: %lu\n", - (ulong) pci_memory_address); - if ((boardp->ioremap_addr = - ioremap(pci_memory_address & PAGE_MASK, - PAGE_SIZE)) == 0) { - ASC_PRINT3( -"advansys_detect: board %d: ioremap(%lu, %x) returned NULL\n", - boardp->id, (ulong) pci_memory_address, iolen); - scsi_unregister(shp); - asc_board_count--; - continue; - } - ASC_DBG1(1, "advansys_detect: ioremap_addr: %lx\n", - (ulong) boardp->ioremap_addr); - adv_dvc_varp->iop_base = (AdvPortAddr) - (boardp->ioremap_addr + - (pci_memory_address - (pci_memory_address & PAGE_MASK))); - ASC_DBG1(1, "advansys_detect: iop_base: %lx\n", - adv_dvc_varp->iop_base); -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ #ifdef CONFIG_PCI -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,13) - pci_memory_address = pci_devp->base_address[1]; -#else /* version >= v2.3.13 */ +#if ASC_LINUX_KERNEL24 pci_memory_address = pci_resource_start(pci_devp, 1); -#endif /* version >= v2.3.13 */ - ASC_DBG1(1, "advansys_detect: pci_memory_address: %x\n", - pci_memory_address); +#elif ASC_LINUX_KERNEL22 + pci_memory_address = pci_devp->base_address[1]; +#endif + ASC_DBG1(1, "advansys_detect: pci_memory_address: 0x%lx\n", + (ulong) pci_memory_address); if ((boardp->ioremap_addr = ioremap(pci_memory_address & PAGE_MASK, PAGE_SIZE)) == 0) { ASC_PRINT3( "advansys_detect: board %d: ioremap(%x, %d) returned NULL\n", - boardp->id, pci_memory_address, iolen); + boardp->id, pci_memory_address, iolen); scsi_unregister(shp); asc_board_count--; continue; } - ASC_DBG1(1, "advansys_detect: ioremap_addr: %lx\n", + ASC_DBG1(1, "advansys_detect: ioremap_addr: 0x%lx\n", (ulong) boardp->ioremap_addr); adv_dvc_varp->iop_base = (AdvPortAddr) (boardp->ioremap_addr + (pci_memory_address - (pci_memory_address & PAGE_MASK))); - ASC_DBG1(1, "advansys_detect: iop_base: %lx\n", + ASC_DBG1(1, "advansys_detect: iop_base: 0x%lx\n", adv_dvc_varp->iop_base); #endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ -#endif /* version >= v1,3,0 */ /* - * Even though it isn't used to access the board in - * kernels greater than or equal to v1.3.0, save - * the I/O Port address so that it can be reported and - * displayed. + * Even though it isn't used to access wide boards, other + * than for the debug line below, save I/O Port address so + * that it can be reported. */ boardp->ioport = iop; ASC_DBG2(1, - "advansys_detect: iopb_chip_id_1 %x, iopw_chip_id_0 %x\n", +"advansys_detect: iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n", (ushort) inp(iop + 1), (ushort) inpw(iop)); } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +#ifdef CONFIG_PROC_FS /* * Allocate buffer for printing information from * /proc/scsi/advansys/[0...]. @@ -4956,7 +4962,7 @@ asc_board_count--; continue; } -#endif /* version >= v1.3.0 */ +#endif /* CONFIG_PROC_FS */ if (ASC_NARROW_BOARD(boardp)) { /* @@ -4964,6 +4970,7 @@ * calling AscInitGetConfig(). */ switch (asc_dvc_varp->bus_type) { +#ifdef CONFIG_ISA case ASC_IS_ISA: shp->unchecked_isa_dma = TRUE; share_irq = FALSE; @@ -4976,20 +4983,7 @@ shp->unchecked_isa_dma = FALSE; share_irq = TRUE; break; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - case ASC_IS_PCI: - shp->irq = asc_dvc_varp->irq_no = pciConfig.irqLine; - asc_dvc_varp->cfg->pci_device_id = pciConfig.deviceID; - asc_dvc_varp->cfg->pci_slot_info = - ASC_PCI_MKID(pciDevice.busNumber, - pciDevice.slotFound, - pciDevice.devFunc); - shp->unchecked_isa_dma = FALSE; - share_irq = TRUE; - break; -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ +#endif /* CONFIG_ISA */ #ifdef CONFIG_PCI case ASC_IS_PCI: shp->irq = asc_dvc_varp->irq_no = pci_devp->irq; @@ -5002,7 +4996,6 @@ share_irq = TRUE; break; #endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ default: ASC_PRINT2( "advansys_detect: board %d: unknown adapter type: %d\n", @@ -5016,18 +5009,6 @@ * For Wide boards set PCI information before calling * AdvInitGetConfig(). */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - shp->irq = adv_dvc_varp->irq_no = pciConfig.irqLine; - adv_dvc_varp->cfg->pci_device_id = pciConfig.deviceID; - adv_dvc_varp->cfg->pci_slot_info = - ASC_PCI_MKID(pciDevice.busNumber, - pciDevice.slotFound, - pciDevice.devFunc); - shp->unchecked_isa_dma = FALSE; - share_irq = TRUE; -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ #ifdef CONFIG_PCI shp->irq = adv_dvc_varp->irq_no = pci_devp->irq; adv_dvc_varp->cfg->pci_device_id = pci_devp->device; @@ -5038,7 +5019,6 @@ shp->unchecked_isa_dma = FALSE; share_irq = TRUE; #endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ } /* @@ -5082,33 +5062,33 @@ break; default: ASC_PRINT2( -"AscInitGetConfig: board %d: unknown warning: %x\n", +"AscInitGetConfig: board %d: unknown warning: 0x%x\n", boardp->id, ret); break; } if ((err_code = asc_dvc_varp->err_code) != 0) { ASC_PRINT3( -"AscInitGetConfig: board %d error: init_state %x, err_code %x\n", +"AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n", boardp->id, asc_dvc_varp->init_state, asc_dvc_varp->err_code); } } else { ASC_DBG(2, "advansys_detect: AdvInitGetConfig()\n"); if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) { - ASC_PRINT2("AdvInitGetConfig: board %d: warning: %x\n", + ASC_PRINT2("AdvInitGetConfig: board %d: warning: 0x%x\n", boardp->id, ret); } if ((err_code = adv_dvc_varp->err_code) != 0) { ASC_PRINT2( -"AdvInitGetConfig: board %d error: err_code %x\n", +"AdvInitGetConfig: board %d error: err_code 0x%x\n", boardp->id, adv_dvc_varp->err_code); } } - + if (err_code != 0) { -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +#ifdef CONFIG_PROC_FS kfree(boardp->prtbuf); -#endif /* version >= v1.3.0 */ +#endif /* CONFIG_PROC_FS */ scsi_unregister(shp); asc_board_count--; continue; @@ -5136,12 +5116,12 @@ ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable; ep->disc_enable = asc_dvc_varp->cfg->disc_enable; ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled; - ep->isa_dma_speed = asc_dvc_varp->cfg->isa_dma_speed; + ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed); ep->start_motor = asc_dvc_varp->start_motor; ep->cntl = asc_dvc_varp->dvc_cntl; ep->no_scam = asc_dvc_varp->no_scam; ep->max_total_qng = asc_dvc_varp->max_total_qng; - ep->chip_scsi_id = asc_dvc_varp->cfg->chip_scsi_id; + ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id); /* 'max_tag_qng' is set to the same value for every device. */ ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0]; ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0]; @@ -5186,18 +5166,18 @@ break; default: ASC_PRINT2( -"AscInitSetConfig: board %d: unknown warning: %x\n", +"AscInitSetConfig: board %d: unknown warning: 0x%x\n", boardp->id, ret); break; } if (asc_dvc_varp->err_code != 0) { ASC_PRINT3( -"AscInitSetConfig: board %d error: init_state %x, err_code %x\n", +"AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n", boardp->id, asc_dvc_varp->init_state, asc_dvc_varp->err_code); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +#ifdef CONFIG_PROC_FS kfree(boardp->prtbuf); -#endif /* version >= v1.3.0 */ +#endif /* CONFIG_PROC_FS */ scsi_unregister(shp); asc_board_count--; continue; @@ -5213,6 +5193,7 @@ } else { ADVEEP_3550_CONFIG *ep_3550; ADVEEP_38C0800_CONFIG *ep_38C0800; + ADVEEP_38C1600_CONFIG *ep_38C1600; /* * Save Wide EEP Configuration Information. @@ -5239,7 +5220,7 @@ adv_dvc_varp->cfg->serial2; ep_3550->serial_number_word3 = adv_dvc_varp->cfg->serial3; - } else + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { ep_38C0800 = &boardp->eep_config.adv_38C0800_eep; @@ -5266,6 +5247,33 @@ adv_dvc_varp->cfg->serial2; ep_38C0800->serial_number_word3 = adv_dvc_varp->cfg->serial3; + } else + { + ep_38C1600 = &boardp->eep_config.adv_38C1600_eep; + + ep_38C1600->adapter_scsi_id = adv_dvc_varp->chip_scsi_id; + ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng; + ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng; + ep_38C1600->termination_lvd = + adv_dvc_varp->cfg->termination; + ep_38C1600->disc_enable = adv_dvc_varp->cfg->disc_enable; + ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl; + ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able; + ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able; + ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1; + ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2; + ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3; + ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4; + ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able; + ep_38C1600->start_motor = adv_dvc_varp->start_motor; + ep_38C1600->scsi_reset_delay = + adv_dvc_varp->scsi_reset_wait; + ep_38C1600->serial_number_word1 = + adv_dvc_varp->cfg->serial1; + ep_38C1600->serial_number_word2 = + adv_dvc_varp->cfg->serial2; + ep_38C1600->serial_number_word3 = + adv_dvc_varp->cfg->serial3; } /* @@ -5280,20 +5288,18 @@ shp->irq = adv_dvc_varp->irq_no; } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) /* - * Channels are numbered beginning with 0. For AdvanSys One host + * Channels are numbered beginning with 0. For AdvanSys one host * structure supports one channel. Multi-channel boards have a - * separate host structure for each channel. + * separate host structure for each channel. */ shp->max_channel = 0; -#endif /* version >= v1.3.89 */ if (ASC_NARROW_BOARD(boardp)) { shp->max_id = ASC_MAX_TID + 1; shp->max_lun = ASC_MAX_LUN + 1; shp->io_port = asc_dvc_varp->iop_base; - shp->n_io_port = ASC_IOADR_GAP; + boardp->asc_n_io_port = ASC_IOADR_GAP; shp->this_id = asc_dvc_varp->cfg->chip_scsi_id; /* Set maximum number of queues the adapter can handle. */ @@ -5303,13 +5309,13 @@ shp->max_lun = ADV_MAX_LUN + 1; /* - * Save the I/O Port address and length even though the - * in v1.3.0 and greater kernels the region is not used - * by a Wide board. Instead the board is accessed with - * Memory Mapped I/O. + * Save the I/O Port address and length even though + * I/O ports are not used to access Wide boards. + * Instead the Wide boards are accessed with + * PCI Memory Mapped I/O. */ shp->io_port = iop; - shp->n_io_port = iolen; + boardp->asc_n_io_port = iolen; shp->this_id = adv_dvc_varp->chip_scsi_id; @@ -5317,18 +5323,15 @@ shp->can_queue = adv_dvc_varp->max_host_qng; } -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) /* - * In old kernels without tag queuing support and with memory - * allocation problems set a conservative 'cmd_per_lun' value. + * 'n_io_port' currently is one byte. + * + * Set a value to 'n_io_port', but never referenced it because + * it may be truncated. */ -#ifdef MODULE - shp->cmd_per_lun = 1; -#else /* MODULE */ - shp->cmd_per_lun = 4; -#endif /* MODULE */ - ASC_DBG1(1, "advansys_detect: cmd_per_lun: %d\n", shp->cmd_per_lun); -#else /* version >= v1.3.89 */ + shp->n_io_port = boardp->asc_n_io_port <= 255 ? + boardp->asc_n_io_port : 255; + /* * Following v1.3.89, 'cmd_per_lun' is no longer needed * and should be set to zero. @@ -5348,7 +5351,6 @@ * the number of commands to queue per device. */ shp->select_queue_depths = advansys_select_queue_depths; -#endif /* version >= v1.3.89 */ /* * Set the maximum number of scatter-gather elements the @@ -5368,20 +5370,6 @@ shp->sg_tablesize = ADV_MAX_SG_LIST; } -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) -#ifdef MODULE - /* - * If the driver is compiled as a module, set a limit on the - * 'sg_tablesize' value to prevent memory allocation failures. - * Memory allocation errors are more likely to occur at module - * load time, then at driver initialization time. - */ - if (shp->sg_tablesize > 64) { - shp->sg_tablesize = 64; - } -#endif /* MODULE */ -#endif /* version < v2.0.0 */ - /* * The value of 'sg_tablesize' can not exceed the SCSI * mid-level driver definition of SG_ALL. SG_ALL also @@ -5397,11 +5385,11 @@ /* BIOS start address. */ if (ASC_NARROW_BOARD(boardp)) { -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,29) +#if ASC_LINUX_KERNEL24 shp->base = -#else /* version >= v2.3.29 */ +#elif ASC_LINUX_KERNEL22 shp->base = (char *) -#endif /* version < v2.3.29 */ +#endif ((ulong) AscGetChipBiosAddress( asc_dvc_varp->iop_base, asc_dvc_varp->bus_type)); @@ -5420,11 +5408,11 @@ boardp->bios_codelen); ASC_DBG2(1, - "advansys_detect: bios_signature %x, bios_version %x\n", + "advansys_detect: bios_signature 0x%x, bios_version 0x%x\n", boardp->bios_signature, boardp->bios_version); ASC_DBG2(1, - "advansys_detect: bios_codeseg %x, bios_codelen %x\n", + "advansys_detect: bios_codeseg 0x%x, bios_codelen 0x%x\n", boardp->bios_codeseg, boardp->bios_codelen); /* @@ -5436,11 +5424,10 @@ * Convert x86 realmode code segment to a linear * address by shifting left 4. */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,29) shp->base = -#else /* version >= v2.3.29 */ - shp->base = (char *) -#endif /* version < v2.3.29 */ +#if ASC_LINUX_KERNEL22 + (char *) +#endif ((ulong) boardp->bios_codeseg << 4); } else { shp->base = 0; @@ -5451,12 +5438,37 @@ * Register Board Resources - I/O Port, DMA, IRQ */ - /* Register I/O port range. */ - ASC_DBG(2, "advansys_detect: request_region()\n"); - request_region(shp->io_port, shp->n_io_port, "advansys"); + /* + * Register I/O port range. + * + * For Wide boards the I/O ports are not used to access + * the board, but request the region anyway. + * + * 'shp->n_io_port' is not referenced, because it may be truncated. + */ + ASC_DBG2(2, + "advansys_detect: request_region port 0x%lx, len 0x%x\n", + (ulong) shp->io_port, boardp->asc_n_io_port); +#if ASC_LINUX_KERNEL24 + if (request_region(shp->io_port, boardp->asc_n_io_port, + "advansys") == NULL) { + ASC_PRINT3( +"advansys_detect: board %d: request_region() failed, port 0x%lx, len 0x%x\n", + boardp->id, (ulong) shp->io_port, boardp->asc_n_io_port); +#ifdef CONFIG_PROC_FS + kfree(boardp->prtbuf); +#endif /* CONFIG_PROC_FS */ + scsi_unregister(shp); + asc_board_count--; + continue; + } +#elif ASC_LINUX_KERNEL22 + request_region(shp->io_port, boardp->asc_n_io_port, "advansys"); +#endif /* Register DMA Channel for Narrow boards. */ shp->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */ +#ifdef CONFIG_ISA if (ASC_NARROW_BOARD(boardp)) { /* Register DMA channel for ISA bus. */ if (asc_dvc_varp->bus_type & ASC_IS_ISA) { @@ -5466,10 +5478,10 @@ ASC_PRINT3( "advansys_detect: board %d: request_dma() %d failed %d\n", boardp->id, shp->dma_channel, ret); - release_region(shp->io_port, shp->n_io_port); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + release_region(shp->io_port, boardp->asc_n_io_port); +#ifdef CONFIG_PROC_FS kfree(boardp->prtbuf); -#endif /* version >= v1.3.0 */ +#endif /* CONFIG_PROC_FS */ scsi_unregister(shp); asc_board_count--; continue; @@ -5477,13 +5489,10 @@ AscEnableIsaDma(shp->dma_channel); } } +#endif /* CONFIG_ISA */ /* Register IRQ Number. */ ASC_DBG1(2, "advansys_detect: request_irq() %d\n", shp->irq); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) - if ((ret = request_irq(shp->irq, advansys_interrupt, - SA_INTERRUPT, "advansys")) != 0) -#else /* version >= v1.3.70 */ /* * If request_irq() fails with the SA_INTERRUPT flag set, * then try again without the SA_INTERRUPT flag set. This @@ -5499,31 +5508,28 @@ ((ret = request_irq(shp->irq, advansys_interrupt, (share_irq == TRUE ? SA_SHIRQ : 0), "advansys", boardp)) != 0)) -#endif /* version >= v1.3.70 */ { if (ret == -EBUSY) { ASC_PRINT2( -"advansys_detect: board %d: request_irq(): IRQ %d already in use.\n", +"advansys_detect: board %d: request_irq(): IRQ 0x%x already in use.\n", boardp->id, shp->irq); } else if (ret == -EINVAL) { ASC_PRINT2( -"advansys_detect: board %d: request_irq(): IRQ %d not valid.\n", +"advansys_detect: board %d: request_irq(): IRQ 0x%x not valid.\n", boardp->id, shp->irq); } else { ASC_PRINT3( -"advansys_detect: board %d: request_irq(): IRQ %d failed with %d\n", +"advansys_detect: board %d: request_irq(): IRQ 0x%x failed with %d\n", boardp->id, shp->irq, ret); } - release_region(shp->io_port, shp->n_io_port); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + release_region(shp->io_port, boardp->asc_n_io_port); iounmap(boardp->ioremap_addr); -#endif /* version >= v1,3,0 */ if (shp->dma_channel != NO_ISA_DMA) { free_dma(shp->dma_channel); } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +#ifdef CONFIG_PROC_FS kfree(boardp->prtbuf); -#endif /* version >= v1.3.0 */ +#endif /* CONFIG_PROC_FS */ scsi_unregister(shp); asc_board_count--; continue; @@ -5539,7 +5545,7 @@ if (warn_code || err_code) { ASC_PRINT4( -"AscInitAsc1000Driver: board %d: error: init_state %x, warn %x error %x\n", +"advansys_detect: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n", boardp->id, asc_dvc_varp->init_state, warn_code, err_code); } @@ -5549,25 +5555,13 @@ adv_req_t *reqp = NULL; int sg_cnt = 0; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) - carrp = (ADV_CARR_T *) &adv_carr_buf[0]; - req_cnt = sizeof(adv_req_buf)/sizeof(adv_req_t); - sg_cnt = sizeof(adv_sgblk_buf)/sizeof(adv_sgblk_t); - reqp = (adv_req_t *) &adv_req_buf[0]; - boardp->adv_sgblkp = NULL; - for (sg_cnt = 0; sg_cnt < ADV_SGBLK_BUF_CNT; sg_cnt++) { - sgp = (adv_sgblk_t *) &adv_sgblk_buf[sg_cnt]; - sgp->next_sgblkp = boardp->adv_sgblkp; - boardp->adv_sgblkp = sgp; - } -#else /* version >= v1.3.0 */ /* * Allocate buffer carrier structures. The total size * is about 4 KB, so allocate all at once. */ carrp = (ADV_CARR_T *) kmalloc(ADV_CARRIER_BUFSIZE, GFP_ATOMIC); - ASC_DBG1(1, "advansys_detect: carrp %lx\n", (ulong) carrp); + ASC_DBG1(1, "advansys_detect: carrp 0x%lx\n", (ulong) carrp); if (carrp == NULL) { goto kmalloc_error; @@ -5586,7 +5580,7 @@ kmalloc(sizeof(adv_req_t) * req_cnt, GFP_ATOMIC); ASC_DBG3(1, - "advansys_detect: reqp %lx, req_cnt %d, bytes %lu\n", + "advansys_detect: reqp 0x%lx, req_cnt %d, bytes %lu\n", (ulong) reqp, req_cnt, (ulong) sizeof(adv_req_t) * req_cnt); @@ -5631,24 +5625,24 @@ if (carrp == NULL) { ASC_PRINT1( -"advansys_detect: board %d: error: failed to kmalloc() carrier buffer.\n", +"advansys_detect: board %d error: failed to kmalloc() carrier buffer.\n", boardp->id); err_code = ADV_ERROR; } else if (reqp == NULL) { kfree(carrp); ASC_PRINT1( -"advansys_detect: board %d: error: failed to kmalloc() adv_req_t buffer.\n", +"advansys_detect: board %d error: failed to kmalloc() adv_req_t buffer.\n", boardp->id); err_code = ADV_ERROR; } else if (boardp->adv_sgblkp == NULL) { kfree(carrp); kfree(reqp); ASC_PRINT1( -"advansys_detect: board %d: error: failed to kmalloc() adv_sgblk_t buffers.\n", +"advansys_detect: board %d error: failed to kmalloc() adv_sgblk_t buffers.\n", boardp->id); err_code = ADV_ERROR; } else { - + /* Save carrier buffer pointer. */ boardp->orig_carrp = carrp; @@ -5657,7 +5651,6 @@ * driver is built as a module and can be unloaded. */ boardp->orig_reqp = reqp; -#endif /* version >= v1.3.0 */ adv_dvc_varp->carrier_buf = carrp; @@ -5677,26 +5670,27 @@ ASC_DBG(2, "advansys_detect: AdvInitAsc3550Driver()\n"); warn_code = AdvInitAsc3550Driver(adv_dvc_varp); - } else { + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { ASC_DBG(2, "advansys_detect: AdvInitAsc38C0800Driver()\n"); warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp); + } else { + ASC_DBG(2, + "advansys_detect: AdvInitAsc38C1600Driver()\n"); + warn_code = AdvInitAsc38C1600Driver(adv_dvc_varp); } err_code = adv_dvc_varp->err_code; if (warn_code || err_code) { ASC_PRINT3( -"AdvInitAsc3550/38C0800Driver: board %d: error: warn %x, error %x\n", +"advansys_detect: board %d error: warn 0x%x, error 0x%x\n", boardp->id, warn_code, err_code); } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) } -#endif /* version >= v1,3,0 */ } if (err_code != 0) { - release_region(shp->io_port, shp->n_io_port); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + release_region(shp->io_port, boardp->asc_n_io_port); if (ASC_WIDE_BOARD(boardp)) { iounmap(boardp->ioremap_addr); if (boardp->orig_carrp) { @@ -5713,18 +5707,13 @@ kfree(sgp); } } -#endif /* version >= v1,3,0 */ if (shp->dma_channel != NO_ISA_DMA) { free_dma(shp->dma_channel); } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +#ifdef CONFIG_PROC_FS kfree(boardp->prtbuf); -#endif /* version >= v1.3.0 */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) - free_irq(shp->irq); -#else /* version >= v1.3.70 */ +#endif /* CONFIG_PROC_FS */ free_irq(shp->irq, boardp); -#endif /* version >= v1.3.70 */ scsi_unregister(shp); asc_board_count--; continue; @@ -5732,6 +5721,14 @@ ASC_DBG_PRT_SCSI_HOST(2, shp); } } + + /* + * XXX - Remove this comment and the next line when SCSI mid-level + * no longer acquires 'io_request_lock' before calling the SCSI + * low-level detect entrypoint. + */ + ASC_LOCK_IO_REQUEST_LOCK + ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n", asc_board_count); return asc_board_count; } @@ -5748,17 +5745,12 @@ ASC_DBG(1, "advansys_release: begin\n"); boardp = ASC_BOARDP(shp); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) - free_irq(shp->irq); -#else /* version >= v1.3.70 */ free_irq(shp->irq, boardp); -#endif /* version >= v1.3.70 */ if (shp->dma_channel != NO_ISA_DMA) { ASC_DBG(1, "advansys_release: free_dma()\n"); free_dma(shp->dma_channel); } - release_region(shp->io_port, shp->n_io_port); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + release_region(shp->io_port, boardp->asc_n_io_port); if (ASC_WIDE_BOARD(boardp)) { adv_sgblk_t *sgp = NULL; @@ -5777,9 +5769,10 @@ kfree(sgp); } } +#ifdef CONFIG_PROC_FS ASC_ASSERT(boardp->prtbuf != NULL); kfree(boardp->prtbuf); -#endif /* version >= v1.3.0 */ +#endif /* CONFIG_PROC_FS */ scsi_unregister(shp); ASC_DBG(1, "advansys_release: end\n"); return 0; @@ -5815,51 +5808,37 @@ } else { busname = "ISA"; } + /* Don't reference 'shp->n_io_port'; It may be truncated. */ sprintf(info, -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,92) -"AdvanSys SCSI %s: %s %u CDB: BIOS %lX, IO %lX/%X, IRQ %u, DMA %u", -#else /* version >= v2.1.92 */ -"AdvanSys SCSI %s: %s %u CDB: BIOS %lX, IO %lX/%X, IRQ %u, DMA %u", -#endif /* version >= v2.1.92 */ - ASC_VERSION, busname, asc_dvc_varp->max_total_qng, - (ulong) shp->base, - (ulong) shp->io_port, shp->n_io_port - 1, +"AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X", + ASC_VERSION, busname, + (ulong) shp->io_port, + (ulong) shp->io_port + boardp->asc_n_io_port - 1, shp->irq, shp->dma_channel); - } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) { - if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA) - == ASC_IS_PCI_ULTRA) { - busname = "PCI Ultra"; - } else { - busname = "PCI"; - } - sprintf(info, -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,92) - "AdvanSys SCSI %s: %s %u CDB: IO %X/%X, IRQ %u", -#else /* version >= v2.1.92 */ - "AdvanSys SCSI %s: %s %u CDB: IO %lX/%X, IRQ %u", -#endif /* version >= v2.1.92 */ - ASC_VERSION, busname, asc_dvc_varp->max_total_qng, - shp->io_port, shp->n_io_port - 1, shp->irq); } else { if (asc_dvc_varp->bus_type & ASC_IS_VL) { busname = "VL"; } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) { busname = "EISA"; + } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) { + if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA) + == ASC_IS_PCI_ULTRA) { + busname = "PCI Ultra"; + } else { + busname = "PCI"; + } } else { busname = "?"; - ASC_PRINT2( - "advansys_info: board %d: unknown bus type %d\n", + ASC_PRINT2( "advansys_info: board %d: unknown bus type %d\n", boardp->id, asc_dvc_varp->bus_type); } + /* Don't reference 'shp->n_io_port'; It may be truncated. */ sprintf(info, -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,92) - "AdvanSys SCSI %s: %s %u CDB: BIOS %lX, IO %X/%X, IRQ %u", -#else /* version >= v2.1.92 */ - "AdvanSys SCSI %s: %s %u CDB: BIOS %lX, IO %lX/%X, IRQ %u", -#endif /* version >= v2.1.92 */ - ASC_VERSION, busname, asc_dvc_varp->max_total_qng, - (ulong) shp->base, shp->io_port - 1, - shp->n_io_port, shp->irq); + "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X", + ASC_VERSION, busname, + (ulong) shp->io_port, + (ulong) shp->io_port + boardp->asc_n_io_port - 1, + shp->irq); } } else { /* @@ -5874,29 +5853,21 @@ { iolen = ADV_3550_IOLEN; widename = "Ultra-Wide"; - } else { + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) + { iolen = ADV_38C0800_IOLEN; widename = "Ultra2-Wide"; + } else + { + iolen = ADV_38C1600_IOLEN; + widename = "Ultra3-Wide"; } - if (boardp->bios_signature == 0x55AA) { - sprintf(info, -"AdvanSys SCSI %s: PCI %s: BIOS %X/%X, IO %X/%X, IRQ %u", - ASC_VERSION, - widename, - boardp->bios_codeseg << 4, - boardp->bios_codelen > 0 ? - (boardp->bios_codelen << 9) - 1 : 0, - (unsigned) boardp->ioport, iolen - 1, - shp->irq); - } else { - sprintf(info, -"AdvanSys SCSI %s: PCI %s: IO %X/%X, IRQ %u", - ASC_VERSION, - widename, - (unsigned) boardp->ioport, - (iolen - 1), - shp->irq); - } + sprintf(info, "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X", + ASC_VERSION, + widename, + (ulong) adv_dvc_varp->iop_base, + (ulong) adv_dvc_varp->iop_base + iolen - 1, + shp->irq); } ASC_ASSERT(strlen(info) < ASC_INFO_SIZE); ASC_DBG(1, "advansys_info: end\n"); @@ -5904,30 +5875,6 @@ } /* - * advansys_command() - polled I/O entrypoint. - * - * Apparently host drivers shouldn't return until the command - * is finished. - * - * Note: This is an old interface that is no longer used by the SCSI - * mid-level driver. The new interface, advansys_queuecommand(), - * currently handles all requests. - */ -int -advansys_command(Scsi_Cmnd *scp) -{ - ASC_DBG1(1, "advansys_command: scp %lx\n", (ulong) scp); - ASC_STATS(scp->host, command); - scp->SCp.Status = 0; /* Set to a known state */ - advansys_queuecommand(scp, advansys_command_done); - while (scp->SCp.Status == 0) { - continue; - } - ASC_DBG1(1, "advansys_command: result %x\n", scp->result); - return scp->result; -} - -/* * advansys_queuecommand() - interrupt-driven I/O entrypoint. * * This function always returns 0. Command return status is saved @@ -5938,7 +5885,7 @@ { struct Scsi_Host *shp; asc_board_t *boardp; - int flags; + ulong flags; Scsi_Cmnd *done_scp; shp = scp->host; @@ -5946,28 +5893,22 @@ ASC_STATS(shp, queuecommand); /* - * Disable interrupts to preserve request ordering and provide - * mutually exclusive access to global structures used to initiate - * a request. + * XXX - Remove this comment and the next line when SCSI mid-level + * no longer acquires 'io_request_lock' before calling the SCSI + * low-level queuecommand entrypoint. */ - save_flags(flags); - cli(); + ASC_UNLOCK_IO_REQUEST_LOCK + + spin_lock_irqsave(&boardp->lock, flags); /* * Block new commands while handling a reset or abort request. */ - if (boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) { - if (boardp->flags & ASC_HOST_IN_RESET) { - ASC_DBG1(1, - "advansys_queuecommand: scp %lx blocked for reset request\n", - (ulong) scp); - scp->result = HOST_BYTE(DID_RESET); - } else { - ASC_DBG1(1, - "advansys_queuecommand: scp %lx blocked for abort request\n", - (ulong) scp); - scp->result = HOST_BYTE(DID_ABORT); - } + if (boardp->flags & ASC_HOST_IN_RESET) { + ASC_DBG1(1, + "advansys_queuecommand: scp 0x%lx blocked for reset request\n", + (ulong) scp); + scp->result = HOST_BYTE(DID_RESET); /* * Add blocked requests to the board's 'done' queue. The queued @@ -5975,7 +5916,7 @@ * handling. */ asc_enqueue(&boardp->done, scp, ASC_BACK); - restore_flags(flags); + spin_unlock_irqrestore(&boardp->lock, flags); return 0; } @@ -5992,13 +5933,15 @@ * Save the function pointer to Linux mid-level 'done' function * and attempt to execute the command. * - * If ASC_ERROR is returned the request has been added to the + * If ASC_NOERROR is returned the request has been added to the * board's 'active' queue and will be completed by the interrupt * handler. * * If ASC_BUSY is returned add the request to the board's per - * target waiting list. - * + * target waiting list. This is the first time the request has + * been tried. Add it to the back of the waiting list. It will be + * retried later. + * * If an error occurred, the request will have been placed on the * board's 'done' queue and must be completed before returning. */ @@ -6017,645 +5960,223 @@ break; } - restore_flags(flags); - return 0; -} - -/* - * advansys_abort() - * - * Abort the command specified by 'scp'. - */ -int -advansys_abort(Scsi_Cmnd *scp) -{ - struct Scsi_Host *shp; - asc_board_t *boardp; - ASC_DVC_VAR *asc_dvc_varp; - ADV_DVC_VAR *adv_dvc_varp; - int flags; - int do_scsi_done; - int scp_found; - Scsi_Cmnd *done_scp = NULL; - int ret; - - /* Save current flags and disable interrupts. */ - save_flags(flags); - cli(); - - ASC_DBG1(1, "advansys_abort: scp %lx\n", (ulong) scp); - -#ifdef ADVANSYS_STATS - if (scp->host != NULL) { - ASC_STATS(scp->host, abort); - } -#endif /* ADVANSYS_STATS */ - -#ifdef ADVANSYS_ASSERT - do_scsi_done = ASC_ERROR; - scp_found = ASC_ERROR; - ret = ASC_ERROR; -#endif /* ADVANSYS_ASSERT */ - -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - if (scp->serial_number != scp->serial_number_at_timeout) { - ASC_PRINT1( -"advansys_abort: timeout serial number changed for request %lx\n", - (ulong) scp); - do_scsi_done = ASC_FALSE; - scp_found = ASC_FALSE; - ret = SCSI_ABORT_NOT_RUNNING; - } else -#endif /* version >= v1.3.89 */ - if ((shp = scp->host) == NULL) { - scp->result = HOST_BYTE(DID_ERROR); - do_scsi_done = ASC_TRUE; - scp_found = ASC_FALSE; - ret = SCSI_ABORT_ERROR; - } else if ((boardp = ASC_BOARDP(shp))->flags & - (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) { - ASC_PRINT2( -"advansys_abort: board %d: Nested host reset or abort, flags 0x%x\n", - boardp->id, boardp->flags); - do_scsi_done = ASC_TRUE; - if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) || - (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) { - scp_found = ASC_TRUE; - } else { - scp_found = ASC_FALSE; - } - scp->result = HOST_BYTE(DID_ERROR); - ret = SCSI_ABORT_ERROR; - } else { - /* Set abort flag to avoid nested reset or abort requests. */ - boardp->flags |= ASC_HOST_IN_ABORT; - - do_scsi_done = ASC_TRUE; - if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) { - /* - * If asc_rmqueue() found the command on the waiting - * queue, it had not been sent to the device. After - * the queue is removed, no other handling is required. - */ - ASC_DBG1(1, "advansys_abort: scp %lx found on waiting queue\n", - (ulong) scp); - scp_found = ASC_TRUE; - scp->result = HOST_BYTE(DID_ABORT); - ret = SCSI_ABORT_SUCCESS; - } else if (asc_isqueued(&boardp->active, scp) == ASC_TRUE) { - /* - * If asc_isqueued() found the command on the active - * queue, it has been sent to the device. The command - * will be returned through the interrupt handler after - * it has been aborted. - */ - - if (ASC_NARROW_BOARD(boardp)) { - /* - * Narrow Board - */ - asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; - scp->result = HOST_BYTE(DID_ABORT); - - /* sti(); XXX */ /* Enable interrupts for AscAbortSRB(). */ - ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %lx\n", - (ulong) scp); - /* XXX */ - switch (AscAbortSRB(asc_dvc_varp, ASC_VADDR_TO_U32(scp))) { - case ASC_TRUE: - /* asc_isr_callback() will be called */ - ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n"); - ret = SCSI_ABORT_PENDING; - break; - case ASC_FALSE: - /* Request has apparently already completed. */ - ASC_DBG(1, "advansys_abort: AscAbortSRB() FALSE\n"); - ret = SCSI_ABORT_NOT_RUNNING; - break; - case ASC_ERROR: - default: - ASC_DBG(1, "advansys_abort: AscAbortSRB() ERROR\n"); - ret = SCSI_ABORT_ERROR; - break; - } - cli(); - } else { - /* - * Wide Board - */ - adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; - scp->result = HOST_BYTE(DID_ABORT); - - ASC_DBG1(1, - "advansys_abort: before AdvAbortQueue(), scp %lx\n", - (ulong) scp); -#if 0 /* XXX */ - switch (AdvAbortQueue(adv_dvc_varp, (ADV_VADDR) XXX)) { - case ASC_TRUE: - /* asc_isr_callback() will be called */ - ASC_DBG(1, "advansys_abort: AdvAbortQueue() TRUE\n"); - ret = SCSI_ABORT_PENDING; - break; - case ASC_FALSE: - /* Request has apparently already completed. */ - ASC_DBG(1, "advansys_abort: AdvAbortQueue() FALSE\n"); - ret = SCSI_ABORT_NOT_RUNNING; - break; - case ASC_ERROR: - default: - ASC_DBG(1, "advansys_abort: AdvAbortQueue() ERROR\n"); - ret = SCSI_ABORT_ERROR; - break; - } - /* - * Ensure all requests completed by the microcode have - * been processed by calling AdvISR(). - */ - (void) AdvISR(adv_dvc_varp); -#else /* XXX */ - (void) AdvResetChipAndSB(adv_dvc_varp); - ret = SCSI_ABORT_SUCCESS; -#endif /* XXX */ - } - - /* - * The request will either still be on the active queue - * or have been added to the board's done queue. - */ - if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) { - scp->result = HOST_BYTE(DID_ABORT); - scp_found = ASC_TRUE; - } else { - scp_found = asc_rmqueue(&boardp->done, scp); - ASC_ASSERT(scp_found == ASC_TRUE); - } - } else { - /* - * The command was not found on the active or waiting queues. - */ - do_scsi_done = ASC_TRUE; - scp_found = ASC_FALSE; - ret = SCSI_ABORT_NOT_RUNNING; - } - - /* Clear abort flag. */ - boardp->flags &= ~ASC_HOST_IN_ABORT; - - /* - * Because the ASC_HOST_IN_ABORT flag causes both - * 'advansys_interrupt' and 'asc_isr_callback' to - * queue requests to the board's 'done' queue and - * prevents waiting commands from being executed, - * these queued requests must be handled here. - */ - done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL); - - /* - * Start any waiting commands for the board. - */ - if (!ASC_QUEUE_EMPTY(&boardp->waiting)) { - ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n"); - asc_execute_queue(&boardp->waiting); - } - } - - /* Interrupts could be enabled here. */ - - /* - * Complete the request to be aborted, unless it has been - * restarted as detected above, even if it was not found on - * the device active or waiting queues. - */ - ASC_ASSERT(do_scsi_done != ASC_ERROR); - ASC_ASSERT(scp_found != ASC_ERROR); - if (do_scsi_done == ASC_TRUE) { - if (scp->scsi_done == NULL) { - ASC_PRINT1( -"advansys_abort: aborted request scsi_done() is NULL, %lx\n", - (ulong) scp); - } else { - if (scp_found == ASC_FALSE) { - ASC_PRINT1( -"advansys_abort: abort request not active or waiting, completing anyway %lx\n", - (ulong) scp); - } - ASC_STATS(scp->host, done); - scp->scsi_done(scp); - } - } + spin_unlock_irqrestore(&boardp->lock, flags); /* - * It is possible for the request done function to re-enable - * interrupts without confusing the driver. But here interrupts - * aren't enabled until all requests have been completed. + * XXX - Remove this comment and the next line when SCSI mid-level + * no longer acquires 'io_request_lock' before calling the SCSI + * low-level queuecommand entrypoint. */ - if (done_scp != NULL) { - asc_scsi_done_list(done_scp); - } - - ASC_DBG1(1, "advansys_abort: ret %d\n", ret); - - /* Re-enable interrupts, if they were enabled on entry. */ - restore_flags(flags); + ASC_LOCK_IO_REQUEST_LOCK - ASC_ASSERT(ret != ASC_ERROR); - return ret; + return 0; } /* * advansys_reset() * - * Reset the device associated with the command 'scp'. + * Reset the bus associated with the command 'scp'. + * + * This function runs its own thread. Interrupts must be blocked but + * sleeping is allowed and no locking other than for host structures is + * required. Returns SUCCESS or FAILED. */ int -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) advansys_reset(Scsi_Cmnd *scp) -#else /* version >= v1.3.89 */ -advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags) -#endif /* version >= v1.3.89 */ { struct Scsi_Host *shp; asc_board_t *boardp; ASC_DVC_VAR *asc_dvc_varp; ADV_DVC_VAR *adv_dvc_varp; - int flags; + ulong flags; Scsi_Cmnd *done_scp = NULL, *last_scp = NULL; Scsi_Cmnd *tscp, *new_last_scp; - int do_scsi_done; - int scp_found; int status; - int target; - int ret; - int device_reset = ASC_FALSE; - - /* Save current flags and disable interrupts. */ - save_flags(flags); - cli(); + int ret = SUCCESS; - ASC_DBG1(1, "advansys_reset: %lx\n", (ulong) scp); + ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong) scp); #ifdef ADVANSYS_STATS if (scp->host != NULL) { ASC_STATS(scp->host, reset); - } + } #endif /* ADVANSYS_STATS */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - if ((reset_flags & SCSI_RESET_ASYNCHRONOUS) && - (scp->serial_number != scp->serial_number_at_timeout)) { - ASC_PRINT1( -"advansys_reset: timeout serial number changed for request %lx\n", - (ulong) scp); - do_scsi_done = ASC_FALSE; - scp_found = ASC_FALSE; - ret = SCSI_RESET_NOT_RUNNING; - } else -#endif /* version >= v1.3.89 */ if ((shp = scp->host) == NULL) { scp->result = HOST_BYTE(DID_ERROR); - do_scsi_done = ASC_TRUE; - scp_found = ASC_FALSE; - ret = SCSI_RESET_ERROR; - } else if ((boardp = ASC_BOARDP(shp))->flags & - (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) { - ASC_PRINT2( -"advansys_reset: board %d: Nested host reset or abort, flags 0x%x\n", - boardp->id, boardp->flags); - do_scsi_done = ASC_TRUE; - if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) || - (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) { - scp_found = ASC_TRUE; - } else { - scp_found = ASC_FALSE; - } - scp->result = HOST_BYTE(DID_ERROR); - ret = SCSI_RESET_ERROR; -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0) - } else if (time_after_eq(jiffies, boardp->last_reset) && - time_before(jiffies, boardp->last_reset + (10 * HZ))) { -#else /* version < v2.1.0 */ - } else if (jiffies >= boardp->last_reset && - jiffies < (boardp->last_reset + (10 * HZ))) { -#endif /* version < v2.1.0 */ - /* - * Don't allow a reset to be attempted within 10 seconds - * of the last reset. - * - * If 'jiffies' wrapping occurs, the reset request will go - * through, because a wrapped 'jiffies' would not pass the - * test above. - */ - ASC_DBG(1, - "advansys_reset: reset within 10 sec of last reset ignored\n"); - do_scsi_done = ASC_TRUE; - if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) || - (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) { - scp_found = ASC_TRUE; - } else { - scp_found = ASC_FALSE; - } - scp->result = HOST_BYTE(DID_ERROR); - ret = SCSI_RESET_ERROR; - } else { - do_scsi_done = ASC_TRUE; - - /* Set reset flag to avoid nested reset or abort requests. */ - boardp->flags |= ASC_HOST_IN_RESET; + return FAILED; + } - /* - * If the request is on the target waiting or active queue - * or the board done queue, then remove it and note that it - * was found. - */ - if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) { - ASC_DBG(1, "advansys_reset: active scp_found = TRUE\n"); - scp_found = ASC_TRUE; - } else if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) { - ASC_DBG(1, "advansys_reset: waiting scp_found = TRUE\n"); - scp_found = ASC_TRUE; - } else if (asc_rmqueue(&boardp->done, scp) == ASC_TRUE) { - scp_found = ASC_TRUE; - } else { - scp_found = ASC_FALSE; - } + boardp = ASC_BOARDP(shp); + ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n", + boardp->id); + /* + * Check for re-entrancy. + */ + spin_lock_irqsave(&boardp->lock, flags); + if (boardp->flags & ASC_HOST_IN_RESET) { + spin_unlock_irqrestore(&boardp->lock, flags); + return FAILED; + } + boardp->flags |= ASC_HOST_IN_RESET; + spin_unlock_irqrestore(&boardp->lock, flags); - if (ASC_NARROW_BOARD(boardp)) { - /* - * Narrow Board - * - * If the suggest reset bus flags are set, then reset the bus. - * Otherwise only reset the device. - */ - asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - if (reset_flags & - (SCSI_RESET_SUGGEST_BUS_RESET | - SCSI_RESET_SUGGEST_HOST_RESET)) { -#endif /* version >= v1.3.89 */ + /* + * XXX - Remove this comment and the next line when SCSI mid-level + * no longer acquires 'io_request_lock' before calling the SCSI + * low-level reset entrypoint. + */ + ASC_UNLOCK_IO_REQUEST_LOCK - /* - * Reset the target's SCSI bus. - */ - ASC_DBG(1, "advansys_reset: before AscResetSB()\n"); - /* sti(); XXX */ /* Enable interrupts for AscResetSB(). */ - status = AscResetSB(asc_dvc_varp); - /* cli(); XXX */ - switch (status) { - case ASC_TRUE: - ASC_DBG(1, "advansys_reset: AscResetSB() success\n"); - ret = SCSI_RESET_SUCCESS; - break; - case ASC_ERROR: - default: - ASC_DBG(1, "advansys_reset: AscResetSB() failed\n"); - ret = SCSI_RESET_ERROR; - break; - } + if (ASC_NARROW_BOARD(boardp)) { + /* + * Narrow Board + */ + asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - } else { - /* - * Reset the specified device. If the device reset fails, - * then reset the SCSI bus. - */ + /* + * Reset the chip and SCSI bus. + */ + ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n"); + status = AscInitAsc1000Driver(asc_dvc_varp); - ASC_DBG1(1, - "advansys_reset: before AscResetDevice(), target %d\n", - scp->target); - /* sti(); XXX */ /* Enable interrupts for AscResetDevice(). */ - status = AscResetDevice(asc_dvc_varp, scp->target); - /* cli(); XXX */ - - switch (status) { - case ASC_TRUE: - ASC_DBG(1, "advansys_reset: AscResetDevice() success\n"); - device_reset = ASC_TRUE; - ret = SCSI_RESET_SUCCESS; - break; - case ASC_ERROR: - default: - ASC_DBG(1, -"advansys_reset: AscResetDevice() failed; Calling AscResetSB()\n"); - /* sti(); XXX */ /* Enable interrupts for AscResetSB(). */ - status = AscResetSB(asc_dvc_varp); - /* cli(); XXX */ - switch (status) { - case ASC_TRUE: - ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n"); - ret = SCSI_RESET_SUCCESS; - break; - case ASC_ERROR: - default: - ASC_DBG(1, "advansys_reset: AscResetSB() ERROR\n"); - ret = SCSI_RESET_ERROR; - break; - } - break; - } - } -#endif /* version >= v1.3.89 */ + /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */ + if (asc_dvc_varp->err_code) { + ASC_PRINT2( + "advansys_reset: board %d: SCSI bus reset error: 0x%x\n", + boardp->id, asc_dvc_varp->err_code); + ret = FAILED; + } else if (status) { + ASC_PRINT2( + "advansys_reset: board %d: SCSI bus reset warning: 0x%x\n", + boardp->id, status); } else { - /* - * Wide Board - * - * If the suggest reset bus flags are set, then reset the bus. - * Otherwise only reset the device. - */ - adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - if (reset_flags & - (SCSI_RESET_SUGGEST_BUS_RESET | - SCSI_RESET_SUGGEST_HOST_RESET)) { -#endif /* version >= v1.3.89 */ - - /* - * Reset the target's SCSI bus. - */ - ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n"); - switch (AdvResetChipAndSB(adv_dvc_varp)) { - case ASC_TRUE: - ASC_DBG(1, - "advansys_reset: AdvResetChipAndSB() success\n"); - ret = SCSI_RESET_SUCCESS; - break; - case ASC_FALSE: - default: - ASC_DBG(1, "advansys_reset: AdvResetChipAndSB() failed\n"); - ret = SCSI_RESET_ERROR; - break; - } - /* - * Ensure all requests completed by the microcode have - * been processed by calling AdvISR(). - */ - (void) AdvISR(adv_dvc_varp); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - } else { - /* - * Reset the specified device. If the device reset fails, - * then reset the SCSI bus. - */ - - ASC_DBG1(1, - "advansys_reset: before AdvResetDevice(), target %d\n", - scp->target); - - switch (AdvResetDevice(adv_dvc_varp, scp->target)) { - case ASC_TRUE: - ASC_DBG(1, "advansys_reset: AdvResetDevice() success\n"); - device_reset = ASC_TRUE; - ret = SCSI_RESET_SUCCESS; - break; - case ASC_FALSE: - default: - ASC_DBG(1, -"advansys_reset: AdvResetDevice() failed; Calling AdvResetChipAndSB()\n"); - - switch (AdvResetChipAndSB(adv_dvc_varp)) { - case ASC_TRUE: - ASC_DBG(1, - "advansys_reset: AdvResetChipAndSB() TRUE\n"); - ret = SCSI_RESET_SUCCESS; - break; - case ASC_FALSE: - default: - ASC_DBG(1, - "advansys_reset: AdvResetChipAndSB() ERROR\n"); - ret = SCSI_RESET_ERROR; - break; - } - break; - } - /* - * Ensure all requests completed by the microcode have - * been processed by calling AdvISR(). - */ - (void) AdvISR(adv_dvc_varp); - } -#endif /* version >= v1.3.89 */ + ASC_PRINT1( + "advansys_reset: board %d: SCSI bus reset successful.\n", + boardp->id); } + ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n"); + /* - * Because the ASC_HOST_IN_RESET flag causes both - * 'advansys_interrupt' and 'asc_isr_callback' to - * queue requests to the board's 'done' queue and - * prevents waiting commands from being executed, - * these queued requests must be handled here. + * Acquire the board lock. */ - done_scp = asc_dequeue_list(&boardp->done, &last_scp, - ASC_TID_ALL); + spin_lock_irqsave(&boardp->lock, flags); + } else { /* - * If a device reset was performed dequeue all waiting - * and active requests for the device and set the request - * status to DID_RESET. + * Wide Board * - * If a SCSI bus reset was performed dequeue all waiting - * and active requests for all devices and set the request - * status to DID_RESET. + * If the suggest reset bus flags are set, then reset the bus. + * Otherwise only reset the device. */ - if (device_reset == ASC_TRUE) { - target = scp->target; - } else { - target = ASC_TID_ALL; - } + adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; /* - * Add active requests to 'done_scp' and set the request status - * to DID_RESET. + * Reset the target's SCSI bus. */ - if (done_scp == NULL) { - done_scp = asc_dequeue_list(&boardp->active, &last_scp, target); - for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) { - tscp->result = HOST_BYTE(DID_RESET); - } - } else { - ASC_ASSERT(last_scp != NULL); - REQPNEXT(last_scp) = asc_dequeue_list(&boardp->active, - &new_last_scp, target); - if (new_last_scp != NULL) { - ASC_ASSERT(REQPNEXT(last_scp) != NULL); - for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) { - tscp->result = HOST_BYTE(DID_RESET); - } - last_scp = new_last_scp; - } + ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n"); + switch (AdvResetChipAndSB(adv_dvc_varp)) { + case ASC_TRUE: + ASC_PRINT1("advansys_reset: board %d: SCSI bus reset successful.\n", + boardp->id); + break; + case ASC_FALSE: + default: + ASC_PRINT1("advansys_reset: board %d: SCSI bus reset error.\n", + boardp->id); + ret = FAILED; + break; } - /* - * Add waiting requests to 'done_scp' and set the request status - * to DID_RESET. + * Acquire the board lock and ensure all requests completed by the + * microcode have been processed by calling AdvISR(). */ - if (done_scp == NULL) { - done_scp = asc_dequeue_list(&boardp->waiting, &last_scp, target); - for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) { - tscp->result = HOST_BYTE(DID_RESET); - } - } else { - ASC_ASSERT(last_scp != NULL); - REQPNEXT(last_scp) = asc_dequeue_list(&boardp->waiting, - &new_last_scp, target); - if (new_last_scp != NULL) { - ASC_ASSERT(REQPNEXT(last_scp) != NULL); - for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) { - tscp->result = HOST_BYTE(DID_RESET); - } - last_scp = new_last_scp; - } - } + spin_lock_irqsave(&boardp->lock, flags); + (void) AdvISR(adv_dvc_varp); + } - /* Save the time of the most recently completed reset. */ - boardp->last_reset = jiffies; + /* Board lock is held. */ - /* Clear reset flag. */ - boardp->flags &= ~ASC_HOST_IN_RESET; + /* + * Dequeue all board 'done' requests. A pointer to the last request + * is returned in 'last_scp'. + */ + done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL); - /* - * Start any waiting commands for the board. - */ - if (!ASC_QUEUE_EMPTY(&boardp->waiting)) { - ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n"); - asc_execute_queue(&boardp->waiting); + /* + * Dequeue all board 'active' requests for all devices and set + * the request status to DID_RESET. A pointer to the last request + * is returned in 'last_scp'. + */ + if (done_scp == NULL) { + done_scp = asc_dequeue_list(&boardp->active, &last_scp, ASC_TID_ALL); + for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) { + tscp->result = HOST_BYTE(DID_RESET); + } + } else { + /* Append to 'done_scp' at the end with 'last_scp'. */ + ASC_ASSERT(last_scp != NULL); + REQPNEXT(last_scp) = asc_dequeue_list(&boardp->active, + &new_last_scp, ASC_TID_ALL); + if (new_last_scp != NULL) { + ASC_ASSERT(REQPNEXT(last_scp) != NULL); + for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) { + tscp->result = HOST_BYTE(DID_RESET); + } + last_scp = new_last_scp; } - ret = SCSI_RESET_SUCCESS; } - /* Interrupts could be enabled here. */ - - ASC_ASSERT(do_scsi_done != ASC_ERROR); - ASC_ASSERT(scp_found != ASC_ERROR); - if (do_scsi_done == ASC_TRUE) { - if (scp->scsi_done == NULL) { - ASC_PRINT1( -"advansys_reset: reset request scsi_done() is NULL, %lx\n", - (ulong) scp); - } else { - if (scp_found == ASC_FALSE) { - ASC_PRINT1( -"advansys_reset: reset request not active or waiting, completing anyway %lx\n", - (ulong) scp); + /* + * Dequeue all 'waiting' requests and set the request status + * to DID_RESET. + */ + if (done_scp == NULL) { + done_scp = asc_dequeue_list(&boardp->waiting, &last_scp, ASC_TID_ALL); + for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) { + tscp->result = HOST_BYTE(DID_RESET); + } + } else { + /* Append to 'done_scp' at the end with 'last_scp'. */ + ASC_ASSERT(last_scp != NULL); + REQPNEXT(last_scp) = asc_dequeue_list(&boardp->waiting, + &new_last_scp, ASC_TID_ALL); + if (new_last_scp != NULL) { + ASC_ASSERT(REQPNEXT(last_scp) != NULL); + for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) { + tscp->result = HOST_BYTE(DID_RESET); } - ASC_STATS(scp->host, done); - scp->scsi_done(scp); + last_scp = new_last_scp; } } + /* Save the time of the most recently completed reset. */ + boardp->last_reset = jiffies; + + /* Clear reset flag. */ + boardp->flags &= ~ASC_HOST_IN_RESET; + + /* Release the board. */ + spin_unlock_irqrestore(&boardp->lock, flags); + /* - * It is possible for the request done function to re-enable - * interrupts without confusing the driver. But here interrupts - * aren't enabled until requests have been completed. + * Complete all the 'done_scp' requests. */ if (done_scp != NULL) { asc_scsi_done_list(done_scp); } - ASC_DBG1(1, "advansys_reset: ret %d\n", ret); + /* + * XXX - Remove this comment and the next line when SCSI mid-level + * no longer acquires 'io_request_lock' before calling the SCSI + * low-level reset entrypoint. + */ + ASC_LOCK_IO_REQUEST_LOCK - /* Re-enable interrupts, if they were enabled on entry. */ - restore_flags(flags); + ASC_DBG1(1, "advansys_reset: ret %d\n", ret); - ASC_ASSERT(ret != ASC_ERROR); return ret; } @@ -6671,11 +6192,7 @@ * ip[2]: cylinders */ int -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) -advansys_biosparam(Disk *dp, int dep, int ip[]) -#else /* version >= v1.3.0 */ advansys_biosparam(Disk *dp, kdev_t dep, int ip[]) -#endif /* version >= v1.3.0 */ { asc_board_t *boardp; @@ -6771,14 +6288,14 @@ #ifdef ADVANSYS_DEBUG ASC_DBG1(1, "advansys_setup: ints[0] %d\n", ints[0]); for (i = 1; i < ints[0]; i++) { - ASC_DBG2(1, " ints[%d] %x", i, ints[i]); + ASC_DBG2(1, " ints[%d] 0x%x", i, ints[i]); } ASC_DBG(1, "\n"); #endif /* ADVANSYS_DEBUG */ for (i = 1; i <= ints[0] && i <= ASC_NUM_IOPORT_PROBE; i++) { asc_ioport[i-1] = ints[i]; - ASC_DBG2(1, "advansys_setup: asc_ioport[%d] %x\n", + ASC_DBG2(1, "advansys_setup: asc_ioport[%d] 0x%x\n", i - 1, asc_ioport[i-1]); } } @@ -6788,8 +6305,13 @@ * --- Loadable Driver Support */ -static Scsi_Host_Template driver_template = ADVANSYS; +#if ASC_LINUX_KERNEL24 +static +#endif +#if ASC_LINUX_KERNEL24 || (ASC_LINUX_KERNEL22 && defined(MODULE)) +Scsi_Host_Template driver_template = ADVANSYS; # include "scsi_module.c" +#endif /* @@ -6799,42 +6321,22 @@ /* * First-level interrupt handler. * - * For versions > v1.3.70, 'dev_id' is a pointer to the interrupting - * adapter's asc_board_t. Because all boards are currently checked - * for interrupts on each interrupt, 'dev_id' is not referenced. 'dev_id' - * could be used to identify an interrupt passed to the AdvanSys driver, - * which is for a device sharing an interrupt with an AdvanSys adapter. + * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because + * all boards are currently checked for interrupts on each interrupt, 'dev_id' + * is not referenced. 'dev_id' could be used to identify an interrupt passed + * to the AdvanSys driver which is for a device sharing an interrupt with + * an AdvanSys adapter. */ STATIC void -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) -advansys_interrupt(int irq, struct pt_regs *regs) -#else /* version >= v1.3.70 */ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs) -#endif /* version >= v1.3.70 */ { -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,95) - int flags; -#else /* version >= v2.1.95 */ - unsigned long flags; -#endif /* version >= v2.1.95 */ + ulong flags; int i; asc_board_t *boardp; Scsi_Cmnd *done_scp = NULL, *last_scp = NULL; Scsi_Cmnd *new_last_scp; - -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,95) - /* Disable interrupts, if they aren't already disabled. */ - save_flags(flags); - cli(); -#else /* version >= v2.1.95 */ - /* - * Disable interrupts, if they aren't already disabled and acquire - * the I/O spinlock. - */ - spin_lock_irqsave(&io_request_lock, flags); -#endif /* version >= v2.1.95 */ - - ASC_DBG(1, "advansys_interrupt: begin\n"); + + ASC_DBG(1, "advansys_interrupt: begin\n"); /* * Check for interrupts on all boards. @@ -6842,8 +6344,9 @@ */ for (i = 0; i < asc_board_count; i++) { boardp = ASC_BOARDP(asc_host[i]); - ASC_DBG2(2, "advansys_interrupt: i %d, boardp %lx\n", - i, (ulong) boardp) + ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n", + i, (ulong) boardp); + spin_lock_irqsave(&boardp->lock, flags); if (ASC_NARROW_BOARD(boardp)) { /* * Narrow Board @@ -6865,13 +6368,12 @@ /* * Start waiting requests and create a list of completed requests. - * - * If a reset or abort request is being performed for the board, - * the reset or abort handler will complete pending requests after - * it has completed. + * + * If a reset request is being performed for the board, the reset + * handler will complete pending requests after it has completed. */ - if ((boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) == 0) { - ASC_DBG2(1, "advansys_interrupt: done_scp %lx, last_scp %lx\n", + if ((boardp->flags & ASC_HOST_IN_RESET) == 0) { + ASC_DBG2(1, "advansys_interrupt: done_scp 0x%lx, last_scp 0x%lx\n", (ulong) done_scp, (ulong) last_scp); /* Start any waiting commands for the board. */ @@ -6900,38 +6402,21 @@ } } } + spin_unlock_irqrestore(&boardp->lock, flags); } - /* Interrupts could be enabled here. */ - /* - * It is possible for the request done function to re-enable - * interrupts without confusing the driver. But here the - * original flags aren't restored until all requests have been - * completed. + * If interrupts were enabled on entry, then they + * are now enabled here. + * + * Complete all requests on the done list. */ asc_scsi_done_list(done_scp); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,95) - /* - * Restore the original flags which will enable interrupts - * if and only if they were enabled on entry. - */ - restore_flags(flags); -#else /* version >= v2.1.95 */ - /* - * Release the I/O spinlock and restore the original flags - * which will enable interrupts if and only if they were - * enabled on entry. - */ - spin_unlock_irqrestore(&io_request_lock, flags); -#endif /* version >= v2.1.95 */ - ASC_DBG(1, "advansys_interrupt: end\n"); return; } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) /* * Set the number of commands to queue per device for the * specified host adapter. @@ -6960,22 +6445,11 @@ device->queue_depth = boardp->dvc_var.adv_dvc_var.max_dvc_qng; } - ASC_DBG3(1, "advansys_select_queue_depths: shp %lx, id %d, depth %d\n", + ASC_DBG3(1, + "advansys_select_queue_depths: shp 0x%lx, id %d, depth %d\n", (ulong) shp, device->id, device->queue_depth); } } -#endif /* version >= v1.3.89 */ - -/* - * Function used only with polled I/O requests that are initiated by - * advansys_command(). - */ -STATIC void -advansys_command_done(Scsi_Cmnd *scp) -{ - ASC_DBG1(1, "advansys_command_done: scp %lx\n", (ulong) scp); - scp->SCp.Status = 1; -} /* * Complete all requests on the singly linked list pointed @@ -6990,7 +6464,7 @@ ASC_DBG(2, "asc_scsi_done_list: begin\n"); while (scp != NULL) { - ASC_DBG1(3, "asc_scsi_done_list: scp %lx\n", (ulong) scp); + ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong) scp); tscp = REQPNEXT(scp); REQPNEXT(scp) = NULL; ASC_STATS(scp->host, done); @@ -7038,12 +6512,15 @@ * scsi_done - used to save caller's done function * host_scribble - used for pointer to another Scsi_Cmnd * - * If this function returns ASC_NOERROR or ASC_ERROR the request - * has been enqueued on the board's 'done' queue and must be - * completed by the caller. + * If this function returns ASC_NOERROR the request has been enqueued + * on the board's 'active' queue and will be completed from the + * interrupt handler. + * + * If this function returns ASC_NOERROR the request has been enqueued + * on the board's 'done' queue and must be completed by the caller. * - * If ASC_BUSY is returned the request must be enqueued by the - * caller and re-tried later. + * If ASC_BUSY is returned the request will be enqueued by the + * caller on the target's waiting queue and re-tried later. */ STATIC int asc_execute_scsi_cmnd(Scsi_Cmnd *scp) @@ -7055,8 +6532,7 @@ Scsi_Device *device; int ret; - ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); - ASC_DBG2(1, "asc_execute_scsi_cmnd: scp %lx, done %lx\n", + ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n", (ulong) scp, (ulong) scp->scsi_done); boardp = ASC_BOARDP(scp->host); @@ -7073,6 +6549,10 @@ * Build Asc Library request structure using the * global structures 'asc_scsi_req' and 'asc_sg_head'. * + * If an error is returned, then the request has been + * queued on the board done queue. It will be completed + * by the caller. + * * asc_build_req() can not return ASC_BUSY. */ if (asc_build_req(boardp, scp) == ASC_ERROR) { @@ -7092,18 +6572,20 @@ * request counter. Wrapping doesn't matter. */ boardp->reqcnt[scp->target]++; - asc_enqueue(&boardp->active, scp, ASC_BACK); ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n"); break; case ASC_BUSY: - /* Caller must enqueue request and retry later. */ + /* + * Caller will enqueue request on the target's waiting queue + * and retry later. + */ ASC_STATS(scp->host, exe_busy); break; case ASC_ERROR: ASC_PRINT2( -"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n", +"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n", boardp->id, asc_dvc_varp->err_code); ASC_STATS(scp->host, exe_error); scp->result = HOST_BYTE(DID_ERROR); @@ -7111,7 +6593,7 @@ break; default: ASC_PRINT2( -"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code %x\n", +"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code 0x%x\n", boardp->id, asc_dvc_varp->err_code); ASC_STATS(scp->host, exe_unknown); scp->result = HOST_BYTE(DID_ERROR); @@ -7127,7 +6609,7 @@ /* * Build and get a pointer to an Adv Library request structure. * - * If the request is successfully built then send it below, + * If the request is successfully built then send it below, * otherwise return with an error. */ switch (adv_build_req(boardp, scp, &adv_scsiqp)) { @@ -7136,14 +6618,28 @@ break; case ASC_BUSY: ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n"); + /* + * If busy is returned the request has not been enqueued. + * It will be enqueued by the caller on the target's waiting + * queue and retried later. + * + * The asc_stats fields 'adv_build_noreq' and 'adv_build_nosg' + * count wide board busy conditions. They are updated in + * adv_build_req and adv_get_sglist, respectively. + */ return ASC_BUSY; case ASC_ERROR: + /* + * If an error is returned, then the request has been + * queued on the board done queue. It will be completed + * by the caller. + */ default: ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n"); ASC_STATS(scp->host, build_error); return ASC_ERROR; } - + /* * Execute the command. If there is no error, add the command * to the active queue. @@ -7161,12 +6657,15 @@ "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n"); break; case ASC_BUSY: - /* Caller must enqueue request and retry later. */ + /* + * Caller will enqueue request on the target's waiting queue + * and retry later. + */ ASC_STATS(scp->host, exe_busy); break; case ASC_ERROR: ASC_PRINT2( -"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code %x\n", +"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n", boardp->id, adv_dvc_varp->err_code); ASC_STATS(scp->host, exe_error); scp->result = HOST_BYTE(DID_ERROR); @@ -7174,7 +6673,7 @@ break; default: ASC_PRINT2( -"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code %x\n", +"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code 0x%x\n", boardp->id, adv_dvc_varp->err_code); ASC_STATS(scp->host, exe_unknown); scp->result = HOST_BYTE(DID_ERROR); @@ -7184,7 +6683,6 @@ } ASC_DBG(1, "asc_execute_scsi_cmnd: end\n"); - ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); return ret; } @@ -7194,7 +6692,8 @@ * The global structures 'asc_scsi_q' and 'asc_sg_head' are * used to build the request. * - * If an error occurs, then return ASC_ERROR. + * If an error occurs, then queue the request on the board done + * queue and return ASC_ERROR. */ STATIC int asc_build_req(asc_board_t *boardp, Scsi_Cmnd *scp) @@ -7212,21 +6711,24 @@ /* * Build the ASC_SCSI_Q request. + * + * For narrow boards a CDB length maximum of 12 bytes + * is supported. */ - ASC_ASSERT(scp->cmd_len <= ASC_MAX_CDB_LEN); if (scp->cmd_len > ASC_MAX_CDB_LEN) { - scp->cmd_len = ASC_MAX_CDB_LEN; + ASC_PRINT3( +"asc_build_req: board %d: cmd_len %d > ASC_MAX_CDB_LEN %d\n", + boardp->id, scp->cmd_len, ASC_MAX_CDB_LEN); + scp->result = HOST_BYTE(DID_ERROR); + asc_enqueue(&boardp->done, scp, ASC_BACK); + return ASC_ERROR; } asc_scsi_q.cdbptr = &scp->cmnd[0]; asc_scsi_q.q2.cdb_len = scp->cmd_len; asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target); asc_scsi_q.q1.target_lun = scp->lun; asc_scsi_q.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - asc_scsi_q.q1.sense_addr = (ADV_PADDR) &scp->sense_buffer[0]; -#else /* version >= v2.0.0 */ asc_scsi_q.q1.sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0])); -#endif /* version >= v2.0.0 */ asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer); /* @@ -7238,7 +6740,7 @@ * * The request count is incremented below for every successfully * started request. - * + * */ if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->target] > 0) && (boardp->reqcnt[scp->target] % 255) == 0) { @@ -7256,13 +6758,9 @@ * CDB request of single contiguous buffer. */ ASC_STATS(scp->host, cont_cnt); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - asc_scsi_q.q1.data_addr = (ADV_PADDR) scp->request_buffer; -#else /* version >= v2.0.0 */ asc_scsi_q.q1.data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer)); -#endif /* version >= v2.0.0 */ - asc_scsi_q.q1.data_cnt = scp->request_bufflen; + asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen); ASC_STATS_ADD(scp->host, cont_xfer, ASC_CEILING(scp->request_bufflen, 512)); asc_scsi_q.q1.sg_queue_cnt = 0; @@ -7295,6 +6793,7 @@ asc_scsi_q.sg_head = &asc_sg_head; asc_scsi_q.q1.data_cnt = 0; asc_scsi_q.q1.data_addr = 0; + /* This is a byte value, otherwise it would need to be swapped. */ asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = scp->use_sg; ASC_STATS_ADD(scp->host, sg_elem, asc_sg_head.entry_cnt); @@ -7303,12 +6802,8 @@ */ slp = (struct scatterlist *) scp->request_buffer; for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) { -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - asc_sg_head.sg_list[sgcnt].addr = (ADV_PADDR) slp->address; -#else /* version >= v2.0.0 */ asc_sg_head.sg_list[sgcnt].addr = cpu_to_le32(virt_to_bus(slp->address)); -#endif /* version >= v2.0.0 */ asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(slp->length); ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512)); } @@ -7354,9 +6849,9 @@ } /* - * Get 4-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers. + * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers. */ - scsiqp = (ADV_SCSI_REQ_Q *) ADV_DWALIGN(&reqp->scsi_req_q); + scsiqp = (ADV_SCSI_REQ_Q *) ADV_32BALIGN(&reqp->scsi_req_q); /* * Initialize the structure. @@ -7379,24 +6874,31 @@ /* * Set CDB length and copy it to the request structure. + * For wide boards a CDB length maximum of 16 bytes + * is supported. */ - ASC_ASSERT(scp->cmd_len <= ASC_MAX_CDB_LEN); - if (scp->cmd_len > ASC_MAX_CDB_LEN) { - scp->cmd_len = ASC_MAX_CDB_LEN; + if (scp->cmd_len > ADV_MAX_CDB_LEN) { + ASC_PRINT3( +"adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n", + boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN); + scp->result = HOST_BYTE(DID_ERROR); + asc_enqueue(&boardp->done, scp, ASC_BACK); + return ASC_ERROR; } scsiqp->cdb_len = scp->cmd_len; - for (i = 0; i < scp->cmd_len; i++) { + /* Copy first 12 CDB bytes to cdb[]. */ + for (i = 0; i < scp->cmd_len && i < 12; i++) { scsiqp->cdb[i] = scp->cmnd[i]; } + /* Copy last 4 CDB bytes, if present, to cdb16[]. */ + for (; i < scp->cmd_len; i++) { + scsiqp->cdb16[i - 12] = scp->cmnd[i]; + } scsiqp->target_id = scp->target; scsiqp->target_lun = scp->lun; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - scsiqp->sense_addr = (ADV_PADDR) &scp->sense_buffer[0]; -#else /* version >= v2.0.0 */ scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0])); -#endif /* version >= v2.0.0 */ scsiqp->sense_len = sizeof(scp->sense_buffer); /* @@ -7405,11 +6907,7 @@ */ scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen); scsiqp->vdata_addr = scp->request_buffer; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - scsiqp->data_addr = (ADV_PADDR) scp->request_buffer; -#else /* version >= v2.0.0 */ scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer)); -#endif /* version >= v2.0.0 */ if (scp->use_sg == 0) { /* @@ -7488,7 +6986,7 @@ ADV_PADDR sg_block_paddr; int i; - scsiqp = (ADV_SCSI_REQ_Q *) ADV_DWALIGN(&reqp->scsi_req_q); + scsiqp = (ADV_SCSI_REQ_Q *) ADV_32BALIGN(&reqp->scsi_req_q); slp = (struct scatterlist *) scp->request_buffer; sg_elem_cnt = scp->use_sg; prev_sg_block = NULL; @@ -7525,16 +7023,11 @@ sgblkp->next_sgblkp = NULL; /* - * Get 4 byte aligned virtual and physical addresses for + * Get 8 byte aligned virtual and physical addresses for * the allocated ADV_SG_BLOCK structure. */ - sg_block = (ADV_SG_BLOCK *) ADV_DWALIGN(&sgblkp->sg_block); - sg_block_paddr = -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - (ADV_PADDR) sg_block; -#else /* version >= v2.0.0 */ - virt_to_bus(sg_block); -#endif /* version >= v2.0.0 */ + sg_block = (ADV_SG_BLOCK *) ADV_8BALIGN(&sgblkp->sg_block); + sg_block_paddr = virt_to_bus(sg_block); /* * Check if this is the first 'adv_sgblk_t' for the request. @@ -7568,11 +7061,7 @@ for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) { sg_block->sg_list[i].sg_addr = -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - (ADV_PADDR) slp->address; -#else /* version >= v2.0.0 */ cpu_to_le32(virt_to_bus(slp->address)); -#endif /* version >= v2.0.0 */ sg_block->sg_list[i].sg_count = cpu_to_le32(slp->length); ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512)); @@ -7604,8 +7093,7 @@ struct Scsi_Host *shp; int i; - ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); - ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp %lx, qdonep %lx\n", + ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n", (ulong) asc_dvc_varp, (ulong) qdonep); ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep); @@ -7614,7 +7102,7 @@ * command that has been completed. */ scp = (Scsi_Cmnd *) ASC_U32_TO_VADDR(qdonep->d2.srb_ptr); - ASC_DBG1(1, "asc_isr_callback: scp %lx\n", (ulong) scp); + ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong) scp); if (scp == NULL) { ASC_PRINT("asc_isr_callback: scp is NULL\n"); @@ -7634,24 +7122,24 @@ } if (i == asc_board_count) { ASC_PRINT2( - "asc_isr_callback: scp %lx has bad host pointer, host %lx\n", + "asc_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n", (ulong) scp, (ulong) shp); return; } ASC_STATS(shp, callback); - ASC_DBG1(1, "asc_isr_callback: shp %lx\n", (ulong) shp); + ASC_DBG1(1, "asc_isr_callback: shp 0x%lx\n", (ulong) shp); /* * If the request isn't found on the active queue, it may - * have been removed to handle a reset or abort request. + * have been removed to handle a reset request. * Display a message and return. */ boardp = ASC_BOARDP(shp); ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var); if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) { ASC_PRINT2( - "asc_isr_callback: board %d: scp %lx not on active queue\n", + "asc_isr_callback: board %d: scp 0x%lx not on active queue\n", boardp->id, (ulong) scp); return; } @@ -7675,20 +7163,20 @@ (ASC_SCSI_INQUIRY *) scp->request_buffer); } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,19) +#if ASC_LINUX_KERNEL24 /* * Check for an underrun condition. * * If there was no error and an underrun condition, then * then return the number of underrun bytes. */ - if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 && + if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 && qdonep->remain_bytes <= scp->request_bufflen != 0) { ASC_DBG1(1, "asc_isr_callback: underrun condition %u bytes\n", (unsigned) qdonep->remain_bytes); scp->resid = qdonep->remain_bytes; } -#endif /* version >= v2.3.19 */ +#endif break; case QD_WITH_ERROR: @@ -7710,15 +7198,15 @@ * byte as it is defined by SCSI. */ scp->result = DRIVER_BYTE(DRIVER_SENSE) | - STATUS_BYTE(qdonep->d3.scsi_stat); + STATUS_BYTE(qdonep->d3.scsi_stat); } else { - scp->result = STATUS_BYTE(qdonep->d3.scsi_stat); + scp->result = STATUS_BYTE(qdonep->d3.scsi_stat); } break; default: /* QHSTA error occurred */ - ASC_DBG1(1, "asc_isr_callback: host_stat %x\n", + ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n", qdonep->d3.host_stat); scp->result = HOST_BYTE(DID_BAD_TARGET); break; @@ -7732,7 +7220,7 @@ break; default: - ASC_DBG1(1, "asc_isr_callback: done_stat %x\n", qdonep->d3.done_stat); + ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n", qdonep->d3.done_stat); scp->result = HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.scsi_msg) | STATUS_BYTE(qdonep->d3.scsi_stat); break; @@ -7749,7 +7237,7 @@ boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->target); } - /* + /* * Because interrupts may be enabled by the 'Scsi_Cmnd' done * function, add the command to the end of the board's done queue. * The done function for the command will be called from @@ -7774,9 +7262,12 @@ Scsi_Cmnd *scp; struct Scsi_Host *shp; int i; +#if ASC_LINUX_KERNEL24 + ADV_DCNT resid_cnt; +#endif - ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); - ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp %lx, scsiqp %lx\n", + + ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n", (ulong) adv_dvc_varp, (ulong) scsiqp); ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp); @@ -7786,7 +7277,7 @@ * completed ADV_SCSI_REQ_Q structure. */ reqp = (adv_req_t *) ADV_U32_TO_VADDR(scsiqp->srb_ptr); - ASC_DBG1(1, "adv_isr_callback: reqp %lx\n", (ulong) reqp); + ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong) reqp); if (reqp == NULL) { ASC_PRINT("adv_isr_callback: reqp is NULL\n"); return; @@ -7801,7 +7292,7 @@ * determined. */ scp = reqp->cmndp; - ASC_DBG1(1, "adv_isr_callback: scp %lx\n", (ulong) scp); + ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong) scp); if (scp == NULL) { ASC_PRINT("adv_isr_callback: scp is NULL; adv_req_t dropped.\n"); return; @@ -7824,18 +7315,17 @@ */ if (i == asc_board_count) { ASC_PRINT2( - "adv_isr_callback: scp %lx has bad host pointer, host %lx\n", + "adv_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n", (ulong) scp, (ulong) shp); return; } ASC_STATS(shp, callback); - ASC_DBG1(1, "adv_isr_callback: shp %lx\n", (ulong) shp); + ASC_DBG1(1, "adv_isr_callback: shp 0x%lx\n", (ulong) shp); /* * If the request isn't found on the active queue, it may have been - * removed to handle a reset or abort request. Display a message and - * return. + * removed to handle a reset request. Display a message and return. * * Note: Because the structure may still be in use don't attempt * to free the adv_req_t and adv_sgblk_t, if any, structures. @@ -7844,7 +7334,7 @@ ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var); if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) { ASC_PRINT2( - "adv_isr_callback: board %d: scp %lx not on active queue\n", + "adv_isr_callback: board %d: scp 0x%lx not on active queue\n", boardp->id, (ulong) scp); return; } @@ -7857,20 +7347,21 @@ ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n"); scp->result = 0; -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,19) +#if ASC_LINUX_KERNEL24 /* * Check for an underrun condition. * * If there was no error and an underrun condition, then * then return the number of underrun bytes. */ - if (scp->request_bufflen != 0 && scsiqp->data_cnt != 0 && - scsiqp->data_cnt <= scp->request_bufflen) { + resid_cnt = le32_to_cpu(scsiqp->data_cnt); + if (scp->request_bufflen != 0 && resid_cnt != 0 && + resid_cnt <= scp->request_bufflen) { ASC_DBG1(1, "adv_isr_callback: underrun condition %lu bytes\n", - (ulong) scsiqp->data_cnt); - scp->resid = scsiqp->data_cnt; + (ulong) resid_cnt); + scp->resid = resid_cnt; } -#endif /* version >= v2.3.19 */ +#endif break; case QD_WITH_ERROR: @@ -7900,7 +7391,7 @@ default: /* Some other QHSTA error occurred. */ - ASC_DBG1(1, "adv_isr_callback: host_status %x\n", + ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n", scsiqp->host_status); scp->result = HOST_BYTE(DID_BAD_TARGET); break; @@ -7913,7 +7404,7 @@ break; default: - ASC_DBG1(1, "adv_isr_callback: done_status %x\n", scsiqp->done_status); + ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n", scsiqp->done_status); scp->result = HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status); break; } @@ -7929,7 +7420,7 @@ boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->target); } - /* + /* * Because interrupts may be enabled by the 'Scsi_Cmnd' done * function, add the command to the end of the board's done queue. * The done function for the command will be called from @@ -8000,415 +7491,6 @@ } } -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI -/* - * Search for an AdvanSys PCI device in the PCI configuration space. - */ -ASC_INITFUNC( -STATIC int, -asc_srch_pci_dev(PCI_DEVICE *pciDevice) -) -{ - int ret = PCI_DEVICE_NOT_FOUND; - - ASC_DBG(2, "asc_srch_pci_dev: begin\n"); - - if (pci_scan_method == -1) { - pci_scan_method = asc_scan_method(); - } - pciDevice->type = pci_scan_method; - ASC_DBG1(2, "asc_srch_pci_dev: type %d\n", pciDevice->type); - - ret = asc_pci_find_dev(pciDevice); - ASC_DBG1(2, "asc_srch_pci_dev: asc_pci_find_dev() return %d\n", ret); - if (ret == PCI_DEVICE_FOUND) { - pciDevice->slotNumber = pciDevice->slotFound + 1; - pciDevice->startSlot = pciDevice->slotFound + 1; - } else { - if (pciDevice->bridge > pciDevice->busNumber) { - ASC_DBG2(2, "asc_srch_pci_dev: bridge %x, busNumber %x\n", - pciDevice->bridge, pciDevice->busNumber); - pciDevice->busNumber++; - pciDevice->slotNumber = 0; - pciDevice->startSlot = 0; - pciDevice->endSlot = 0x0f; - ret = asc_srch_pci_dev(pciDevice); - ASC_DBG1(2, "asc_srch_pci_dev: recursive call return %d\n", ret); - } - } - - ASC_DBG1(2, "asc_srch_pci_dev: return %d\n", ret); - return ret; -} - -/* - * Determine the access method to be used for 'pciDevice'. - */ -ASC_INITFUNC( -STATIC uchar, -asc_scan_method(void) -) -{ - ushort data; - PCI_DATA pciData; - uchar type; - uchar slot; - - ASC_DBG(2, "asc_scan_method: begin\n"); - memset(&pciData, 0, sizeof(pciData)); - for (type = 1; type < 3; type++) { - pciData.type = type; - for (slot = 0; slot < PCI_MAX_SLOT; slot++) { - pciData.slot = slot; - data = asc_get_cfg_word(&pciData); - if ((data != 0xFFFF) && (data != 0x0000)) { - ASC_DBG2(4, "asc_scan_method: data %x, type %d\n", data, type); - return (type); - } - } - } - ASC_DBG1(4, "asc_scan_method: type %d\n", type); - return (type); -} - -/* - * Check for an AdvanSys PCI device in 'pciDevice'. - * - * Return PCI_DEVICE_FOUND if found, otherwise return PCI_DEVICE_NOT_FOUND. - */ -ASC_INITFUNC( -STATIC int, -asc_pci_find_dev(PCI_DEVICE *pciDevice) -) -{ - PCI_DATA pciData; - ushort vendorid, deviceid; - uchar classcode, subclass; - uchar lslot; - - ASC_DBG(3, "asc_pci_find_dev: begin\n"); - pciData.type = pciDevice->type; - pciData.bus = pciDevice->busNumber; - pciData.func = pciDevice->devFunc; - lslot = pciDevice->startSlot; - for (; lslot < pciDevice->endSlot; lslot++) { - pciData.slot = lslot; - pciData.offset = VENDORID_OFFSET; - vendorid = asc_get_cfg_word(&pciData); - ASC_DBG1(3, "asc_pci_find_dev: vendorid %x\n", vendorid); - if (vendorid != 0xffff) { - pciData.offset = DEVICEID_OFFSET; - deviceid = asc_get_cfg_word(&pciData); - ASC_DBG1(3, "asc_pci_find_dev: deviceid %x\n", deviceid); - if ((vendorid == ASC_PCI_VENDORID) && - ((deviceid == ASC_PCI_DEVICE_ID_1100) || - (deviceid == ASC_PCI_DEVICE_ID_1200) || - (deviceid == ASC_PCI_DEVICE_ID_1300) || - (deviceid == ASC_PCI_DEVICE_ID_2300) || - (deviceid == ASC_PCI_DEVICE_ID_2500))) { - pciDevice->slotFound = lslot; - ASC_DBG(3, "asc_pci_find_dev: PCI_DEVICE_FOUND\n"); - return PCI_DEVICE_FOUND; - } else { - pciData.offset = SUBCLASS_OFFSET; - subclass = asc_get_cfg_byte(&pciData); - pciData.offset = CLASSCODE_OFFSET; - classcode = asc_get_cfg_byte(&pciData); - if ((classcode & PCI_BASE_CLASS_BRIDGE_DEVICE) && - (subclass & PCI_SUB_CLASS_PCI_TO_PCI_BRIDGE_CONTROLLER)) { - pciDevice->bridge++; - } - ASC_DBG2(3, "asc_pci_find_dev: subclass %x, classcode %x\n", - subclass, classcode); - } - } - } - return PCI_DEVICE_NOT_FOUND; -} - -/* - * Read PCI configuration data into 'pciConfig'. - */ -ASC_INITFUNC( -STATIC void, -asc_get_pci_cfg(PCI_DEVICE *pciDevice, PCI_CONFIG_SPACE *pciConfig) -) -{ - PCI_DATA pciData; - uchar counter; - uchar *localConfig; - - ASC_DBG1(4, "asc_get_pci_cfg: slotFound %d\n ", - pciDevice->slotFound); - - pciData.type = pciDevice->type; - pciData.bus = pciDevice->busNumber; - pciData.slot = pciDevice->slotFound; - pciData.func = pciDevice->devFunc; - localConfig = (uchar *) pciConfig; - - for (counter = 0; counter < sizeof(PCI_CONFIG_SPACE); counter++) { - pciData.offset = counter; - *localConfig = asc_get_cfg_byte(&pciData); - ASC_DBG1(4, "asc_get_pci_cfg: byte %x\n", *localConfig); - localConfig++; - } - ASC_DBG1(4, "asc_get_pci_cfg: counter %d\n", counter); -} - -/* - * Read a word (16 bits) from the PCI configuration space. - * - * The configuration mechanism is checked for the correct access method. - */ -ASC_INITFUNC( -STATIC ushort, -asc_get_cfg_word(PCI_DATA *pciData) -) -{ - ushort tmp; - ADV_DCNT address; - ADV_DCNT lbus = pciData->bus; - ADV_DCNT lslot = pciData->slot; - ADV_DCNT lfunc = pciData->func; - uchar t2CFA, t2CF8; - ADV_DCNT t1CF8, t1CFC; - - ASC_DBG4(4, "asc_get_cfg_word: type %d, bus %u, slot %u, func %u\n", - pciData->type, (unsigned) lbus, (unsigned) lslot, (unsigned) lfunc); - - /* - * Check type of configuration mechanism. - */ - if (pciData->type == 2) { - /* - * Save registers to be restored later. - */ - t2CFA = inp(0xCFA); /* save PCI bus register */ - t2CF8 = inp(0xCF8); /* save config space enable register */ - - /* - * Write the bus and enable registers. - */ - /* set for type 1 cycle, if needed */ - outp(0xCFA, pciData->bus); - /* set the function number */ - outp(0xCF8, 0x10 | (pciData->func << 1)); - - /* - * Read the configuration space type 2 locations. - */ - tmp = (ushort) inpw(0xC000 | ((pciData->slot << 8) + pciData->offset)); - - outp(0xCFA, t2CFA); /* save PCI bus register */ - outp(0xCF8, t2CF8); /* save config space enable register */ - } else { - /* - * Type 1 or 3 configuration mechanism. - * - * Save the CONFIG_ADDRESS and CONFIG_DATA register values. - */ - t1CF8 = inpl(0xCF8); - t1CFC = inpl(0xCFC); - - /* - * enable <31>, bus = <23:16>, slot = <15:11>, - * func = <10:8>, reg = <7:2> - */ - address = (ADV_DCNT) ((lbus << 16) | (lslot << 11) | - (lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L); - - /* - * Write out the address to CONFIG_ADDRESS. - */ - outpl(0xCF8, address); - - /* - * Read in word from CONFIG_DATA. - */ - tmp = (ushort) ((inpl(0xCFC) >> - ((pciData->offset & 2) * 8)) & 0xFFFF); - - /* - * Restore registers. - */ - outpl(0xCF8, t1CF8); - outpl(0xCFC, t1CFC); - } - ASC_DBG1(4, "asc_get_cfg_word: config data: %x\n", tmp); - return tmp; -} - -/* - * Reads a byte from the PCI configuration space. - * - * The configuration mechanism is checked for the correct access method. - */ -ASC_INITFUNC( -STATIC uchar, -asc_get_cfg_byte(PCI_DATA *pciData) -) -{ - uchar tmp; - ADV_DCNT address; - ADV_DCNT lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func; - ADV_DCNT t2CFA, t2CF8; - ADV_DCNT t1CF8, t1CFC; - - ASC_DBG1(4, "asc_get_cfg_byte: type: %d\n", pciData->type); - - /* - * Check type of configuration mechanism. - */ - if (pciData->type == 2) { - /* - * Save registers to be restored later. - */ - t2CFA = inp(0xCFA); /* save PCI bus register */ - t2CF8 = inp(0xCF8); /* save config space enable register */ - - /* - * Write the bus and enable registers. - */ - /* set for type 1 cycle, if needed */ - outp(0xCFA, pciData->bus); - /* set the function number */ - outp(0xCF8, 0x10 | (pciData->func << 1)); - - /* - * Read configuration space type 2 locations. - */ - tmp = inp(0xC000 | ((pciData->slot << 8) + pciData->offset)); - - /* - * Restore registers. - */ - outp(0xCF8, t2CF8); /* restore the enable register */ - outp(0xCFA, t2CFA); /* restore PCI bus register */ - } else { - /* - * Type 1 or 3 configuration mechanism. - * - * Save CONFIG_ADDRESS and CONFIG_DATA register values. - */ - t1CF8 = inpl(0xCF8); - t1CFC = inpl(0xCFC); - - /* - * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>, - * reg = <7:2> - */ - address = (ADV_DCNT) ((lbus << 16) | (lslot << 11) | - (lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L); - - /* - * Write out address to CONFIG_ADDRESS. - */ - outpl(0xCF8, address); - - /* - * Read in word from CONFIG_DATA. - */ - tmp = (uchar) ((inpl(0xCFC) >> ((pciData->offset & 3) * 8)) & 0xFF); - - /* - * Restore registers. - */ - outpl(0xCF8, t1CF8); - outpl(0xCFC, t1CFC); - } - ASC_DBG1(4, "asc_get_cfg_byte: config data: %x\n", tmp); - return tmp; -} - -/* - * Write a byte to the PCI configuration space. - */ -ASC_INITFUNC( -STATIC void, -asc_put_cfg_byte(PCI_DATA *pciData, uchar byte_data) -) -{ - ADV_DCNT tmpl; - ADV_DCNT address; - ADV_DCNT lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func; - uchar t2CFA, t2CF8; - ADV_DCNT t1CF8, t1CFC; - - ASC_DBG2(4, "asc_put_cfg_byte: type: %d, byte_data %x\n", - pciData->type, byte_data); - - /* - * Check type of configuration mechanism. - */ - if (pciData->type == 2) { - - /* - * Save registers to be restored later. - */ - t2CFA = inp(0xCFA); /* save PCI bus register */ - t2CF8 = inp(0xCF8); /* save config space enable register */ - - /* - * Write bus and enable registers. - */ - outp(0xCFA, pciData->bus); - - /* - * Set the function number. - */ - outp(0xCF8, 0x10 | (pciData->func << 1)); - - /* - * Write the configuration space type 2 locations. - */ - outp(0xC000 | ((pciData->slot << 8) + pciData->offset), byte_data); - - /* - * Restore registers. - */ - outp(0xCF8, t2CF8); /* restore the enable register */ - outp(0xCFA, t2CFA); /* restore PCI bus register */ - } else { - - /* - * Type 1 or 3 configuration mechanism. - * - * Save the CONFIG_ADDRESS and CONFIG_DATA register values. - */ - t1CF8 = inpl(0xCF8); - t1CFC = inpl(0xCFC); - - /* - * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>, - * reg = <7:2> - */ - address = (ADV_DCNT) ((lbus << 16) | (lslot << 11) | (lfunc << 8) | - (pciData->offset & 0xFC) | 0x80000000L); - /* - * Write out address to CONFIG_ADDRESS. - */ - outpl(0xCF8, address); - - /* - * Write double word to CONFIG_DATA preserving the bytes - * in the double not written. - */ - tmpl = inpl(0xCFC) & ~(0xFF << ((pciData->offset & 3) * 8)); - outpl(0xCFC, tmpl | (byte_data << ((pciData->offset & 3) * 8))); - - /* - * Restore registers. - */ - outpl(0xCF8, t1CF8); - outpl(0xCFC, t1CFC); - } - ASC_DBG(4, "asc_put_cfg_byte: end\n"); -} -#endif /* ASC_CONFIG_PCI */ -#endif /* version < v2.1.93 */ - /* * Add a 'REQP' to the end of specified queue. Set 'tidmask' * to indicate a command is queued for the device. @@ -8422,9 +7504,8 @@ { int tid; - ASC_DBG3(3, "asc_enqueue: ascq %lx, reqp %lx, flag %d\n", + ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n", (ulong) ascq, (ulong) reqp, flag); - ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); ASC_ASSERT(reqp != NULL); ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK); tid = REQPTID(reqp); @@ -8460,7 +7541,7 @@ } REQPTIME(reqp) = REQTIMESTAMP(); #endif /* ADVANSYS_STATS */ - ASC_DBG1(3, "asc_enqueue: reqp %lx\n", (ulong) reqp); + ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong) reqp); return; } @@ -8476,8 +7557,7 @@ { REQP reqp; - ASC_DBG2(3, "asc_dequeue: ascq %lx, tid %d\n", (ulong) ascq, tid); - ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); + ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong) ascq, tid); ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID); if ((reqp = ascq->q_first[tid]) != NULL) { ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)); @@ -8495,7 +7575,7 @@ REQTIMESTAT("asc_dequeue", ascq, reqp, tid); #endif /* ADVANSYS_STATS */ } - ASC_DBG1(3, "asc_dequeue: reqp %lx\n", (ulong) reqp); + ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong) reqp); return reqp; } @@ -8503,7 +7583,7 @@ * Return a pointer to a singly linked list of all the requests queued * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'. * - * If 'lastpp' is not NULL, '*lastpp' will be set to point to the + * If 'lastpp' is not NULL, '*lastpp' will be set to point to the * the last request returned in the singly linked list. * * 'tid' should either be a valid target id or if it is ASC_TID_ALL, @@ -8525,8 +7605,7 @@ REQP firstp, lastp; int i; - ASC_DBG2(3, "asc_dequeue_list: ascq %lx, tid %d\n", (ulong) ascq, tid); - ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); + ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong) ascq, tid); ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID)); /* @@ -8586,7 +7665,7 @@ if (lastpp) { *lastpp = lastp; } - ASC_DBG1(3, "asc_dequeue_list: firstp %lx\n", (ulong) firstp); + ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong) firstp); return firstp; } @@ -8607,9 +7686,8 @@ int tid; int ret = ASC_FALSE; - ASC_DBG2(3, "asc_rmqueue: ascq %lx, reqp %lx\n", + ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n", (ulong) ascq, (ulong) reqp); - ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); ASC_ASSERT(reqp != NULL); tid = REQPTID(reqp); @@ -8660,37 +7738,7 @@ } ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0); #endif /* ADVANSYS_STATS */ - ASC_DBG2(3, "asc_rmqueue: reqp %lx, ret %d\n", (ulong) reqp, ret); - return ret; -} - -/* - * If the specified 'REQP' is queued on the specified queue for - * the specified target device, return ASC_TRUE. - */ -STATIC int -asc_isqueued(asc_queue_t *ascq, REQP reqp) -{ - REQP treqp; - int tid; - int ret = ASC_FALSE; - - ASC_DBG2(3, "asc_isqueued: ascq %lx, reqp %lx\n", - (ulong) ascq, (ulong) reqp); - ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); - ASC_ASSERT(reqp != NULL); - - tid = REQPTID(reqp); - ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID); - - for (treqp = ascq->q_first[tid]; treqp; treqp = REQPNEXT(treqp)) { - ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)); - if (treqp == reqp) { - ret = ASC_TRUE; - break; - } - } - ASC_DBG1(3, "asc_isqueued: ret %x\n", ret); + ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong) reqp, ret); return ret; } @@ -8706,8 +7754,7 @@ REQP reqp; int i; - ASC_DBG1(1, "asc_execute_queue: ascq %lx\n", (ulong) ascq); - ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); + ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong) ascq); /* * Execute queued commands for devices attached to * the current board in round-robin fashion. @@ -8721,7 +7768,10 @@ } else if (asc_execute_scsi_cmnd((Scsi_Cmnd *) reqp) == ASC_BUSY) { scan_tidmask &= ~ADV_TID_TO_TIDMASK(i); - /* Put the request back at front of the list. */ + /* + * The request returned ASC_BUSY. Enqueue at the front of + * target's waiting list to maintain correct ordering. + */ asc_enqueue(ascq, reqp, ASC_FRONT); } } @@ -8730,7 +7780,7 @@ return; } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +#ifdef CONFIG_PROC_FS /* * asc_prt_board_devices() * @@ -8810,7 +7860,7 @@ "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n"); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -"can be found at the AdvanSys FTP site: ftp://ftp.advansys.com/pub\n"); +"can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n"); ASC_PRT_NEXT(); } else { major = (boardp->bios_version >> 12) & 0xF; @@ -8829,10 +7879,10 @@ if (major < 3 || (major <= 3 && minor < 1) || (major <= 3 && minor <= 1 && letter < ('I'- 'A'))) { len = asc_prt_line(cp, leftlen, -"Newer version of ROM BIOS is available at the AdvanSys FTP site:\n"); +"Newer version of ROM BIOS is available at the ConnectCom FTP site:\n"); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -"ftp://ftp.advansys.com/pub\n"); +"ftp://ftp.connectcom.net/pub\n"); ASC_PRT_NEXT(); } } @@ -8960,7 +8010,9 @@ int len; ASCEEP_CONFIG *ep; int i; +#ifdef CONFIG_ISA int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 }; +#endif /* CONFIG_ISA */ uchar serialstr[13]; boardp = ASC_BOARDP(shp); @@ -8992,11 +8044,11 @@ len = asc_prt_line(cp, leftlen, " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n", - ep->chip_scsi_id, ep->max_total_qng, ep->max_tag_qng); + ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng, ep->max_tag_qng); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" cntl %x, no_scam %x\n", +" cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam); ASC_PRT_NEXT(); @@ -9054,12 +8106,14 @@ len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); +#ifdef CONFIG_ISA if (asc_dvc_varp->bus_type & ASC_IS_ISA) { len = asc_prt_line(cp, leftlen, " Host ISA DMA speed: %d MB/S\n", - isa_dma_speed[ep->isa_dma_speed]); + isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]); ASC_PRT_NEXT(); } +#endif /* CONFIG_ISA */ return totlen; } @@ -9088,6 +8142,7 @@ uchar serialstr[13]; ADVEEP_3550_CONFIG *ep_3550 = NULL; ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL; + ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL; ushort word; ushort *wordp; ushort sdtr_speed = 0; @@ -9097,9 +8152,12 @@ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { ep_3550 = &boardp->eep_config.adv_3550_eep; - } else + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { ep_38C0800 = &boardp->eep_config.adv_38C0800_eep; + } else + { + ep_38C1600 = &boardp->eep_config.adv_38C1600_eep; } leftlen = cplen; @@ -9112,9 +8170,12 @@ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { wordp = &ep_3550->serial_number_word1; - } else + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { wordp = &ep_38C0800->serial_number_word1; + } else + { + wordp = &ep_38C1600->serial_number_word1; } if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) { @@ -9133,20 +8194,30 @@ ep_3550->adapter_scsi_id, ep_3550->max_host_qng, ep_3550->max_dvc_qng); ASC_PRT_NEXT(); - } else + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { len = asc_prt_line(cp, leftlen, " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n", ep_38C0800->adapter_scsi_id, ep_38C0800->max_host_qng, ep_38C0800->max_dvc_qng); ASC_PRT_NEXT(); - } - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) - { - word = ep_3550->termination; } else { + len = asc_prt_line(cp, leftlen, +" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n", + ep_38C1600->adapter_scsi_id, ep_38C1600->max_host_qng, + ep_38C1600->max_dvc_qng); + ASC_PRT_NEXT(); + } + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) + { + word = ep_3550->termination; + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) + { word = ep_38C0800->termination_lvd; + } else + { + word = ep_38C1600->termination_lvd; } switch (word) { case 1: @@ -9167,15 +8238,21 @@ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { len = asc_prt_line(cp, leftlen, -" termination: %u (%s), bios_ctrl: %x\n", +" termination: %u (%s), bios_ctrl: 0x%x\n", ep_3550->termination, termstr, ep_3550->bios_ctrl); ASC_PRT_NEXT(); - } else + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { len = asc_prt_line(cp, leftlen, -" termination: %u (%s), bios_ctrl: %x\n", +" termination: %u (%s), bios_ctrl: 0x%x\n", ep_38C0800->termination_lvd, termstr, ep_38C0800->bios_ctrl); ASC_PRT_NEXT(); + } else + { + len = asc_prt_line(cp, leftlen, +" termination: %u (%s), bios_ctrl: 0x%x\n", + ep_38C1600->termination_lvd, termstr, ep_38C1600->bios_ctrl); + ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, @@ -9191,9 +8268,12 @@ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { word = ep_3550->disc_enable; - } else + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { word = ep_38C0800->disc_enable; + } else + { + word = ep_38C1600->disc_enable; } len = asc_prt_line(cp, leftlen, " Disconnects: "); @@ -9209,9 +8289,12 @@ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { word = ep_3550->tagqng_able; - } else + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { word = ep_38C0800->tagqng_able; + } else + { + word = ep_38C1600->tagqng_able; } len = asc_prt_line(cp, leftlen, " Command Queuing: "); @@ -9227,9 +8310,12 @@ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { word = ep_3550->start_motor; - } else + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { word = ep_38C0800->start_motor; + } else + { + word = ep_38C1600->start_motor; } len = asc_prt_line(cp, leftlen, " Start Motor: "); @@ -9273,9 +8359,12 @@ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { word = ep_3550->wdtr_able; - } else + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { word = ep_38C0800->wdtr_able; + } else + { + word = ep_38C1600->wdtr_able; } len = asc_prt_line(cp, leftlen, " Wide Transfer: "); @@ -9288,7 +8377,8 @@ len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 || + adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) { len = asc_prt_line(cp, leftlen, " Synchronous Transfer Speed (Mhz):\n "); @@ -9352,9 +8442,7 @@ int totlen; int len; int chip_scsi_id; -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) int i; -#endif /* version >= v1.3.89 */ boardp = ASC_BOARDP(shp); @@ -9367,39 +8455,31 @@ ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) -" host_busy %u, last_reset %u, max_id %u, max_lun %u\n", - shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun); -#else /* version >= v1.3.89 */ " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n", shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun, shp->max_channel); -#endif /* version >= v1.3.89 */ ASC_PRT_NEXT(); - + len = asc_prt_line(cp, leftlen, -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,57) -" can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n", - shp->can_queue, shp->this_id, shp->sg_tablesize, shp->cmd_per_lun); -#else /* version >= v1.3.57 */ " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n", shp->unique_id, shp->can_queue, shp->this_id, shp->sg_tablesize, shp->cmd_per_lun); -#endif /* version >= v1.3.57 */ ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,57) -" unchecked_isa_dma %d, loaded_as_module %d\n", - shp->unchecked_isa_dma, shp->loaded_as_module); -#else /* version >= v1.3.57 */ " unchecked_isa_dma %d, use_clustering %d, loaded_as_module %d\n", shp->unchecked_isa_dma, shp->use_clustering, shp->loaded_as_module); -#endif /* version >= v1.3.57 */ ASC_PRT_NEXT(); - len = asc_prt_line(cp, leftlen, " flags %x, last_reset %x, jiffies %x\n", - boardp->flags, boardp->last_reset, jiffies); + len = asc_prt_line(cp, leftlen, +" flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n", + boardp->flags, boardp->last_reset, jiffies, boardp->asc_n_io_port); + ASC_PRT_NEXT(); + + /* 'shp->n_io_port' may be truncated because it is only one byte. */ + len = asc_prt_line(cp, leftlen, +" io_port 0x%x, n_io_port 0x%x\n", + shp->io_port, shp->n_io_port); ASC_PRT_NEXT(); if (ASC_NARROW_BOARD(boardp)) { @@ -9408,7 +8488,6 @@ chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id; } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) if (boardp->flags & ASC_SELECT_QUEUE_DEPTHS) { len = asc_prt_line(cp, leftlen, " queue_depth:"); ASC_PRT_NEXT(); @@ -9427,7 +8506,6 @@ len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); } -#endif /* version >= v1.3.89 */ return totlen; } @@ -9470,12 +8548,12 @@ ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" chip_version %u, lib_version %x, lib_serial_no %u, mcode_date %x\n", +" chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n", c->chip_version, c->lib_version, c->lib_serial_no, c->mcode_date); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" mcode_version %x, err_code %u\n", +" mcode_version 0x%x, err_code %u\n", c->mcode_version, v->err_code); ASC_PRT_NEXT(); @@ -9663,14 +8741,14 @@ ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" iop_base %lx, cable_detect: %X, err_code %u\n", +" iop_base 0x%lx, cable_detect: %X, err_code %u\n", v->iop_base, AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1) & CABLE_DETECT, v->err_code); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" chip_version %u, lib_version %x, mcode_date %x, mcode_version %x\n", +" chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n", c->chip_version, c->lib_version, c->mcode_date, c->mcode_version); ASC_PRT_NEXT(); @@ -9862,7 +8940,7 @@ } /* - * asc_proc_copy() + * asc_proc_copy() * * Copy proc information to a read buffer taking into account the current * read offset in the file and the remaining space in the read buffer. @@ -9872,13 +8950,13 @@ char *cp, int cplen) { int cnt = 0; - + ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n", (unsigned) offset, (unsigned) advoffset, cplen); if (offset <= advoffset) { /* Read offset below current offset, copy everything. */ cnt = ASC_MIN(cplen, leftlen); - ASC_DBG3(2, "asc_proc_copy: curbuf %lx, cp %lx, cnt %d\n", + ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n", (ulong) curbuf, (ulong) cp, cnt); memcpy(curbuf, cp, cnt); } else if (offset < advoffset + cplen) { @@ -9886,7 +8964,7 @@ cnt = (advoffset + cplen) - offset; cp = (cp + cplen) - cnt; cnt = ASC_MIN(cnt, leftlen); - ASC_DBG3(2, "asc_proc_copy: curbuf %lx, cp %lx, cnt %d\n", + ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n", (ulong) curbuf, (ulong) cp, cnt); memcpy(curbuf, cp, cnt); } @@ -9924,7 +9002,7 @@ va_end(args); return ret; } -#endif /* version >= v1.3.0 */ +#endif /* CONFIG_PROC_FS */ /* @@ -9940,56 +9018,33 @@ STATIC void DvcSleepMilliSecond(ADV_DCNT n) { -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) - ADV_DCNT i; -#endif /* version < v2.1.0 */ - ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong) n); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0) mdelay(n); -#else /* version < v2.1.0 */ - for (i = 0; i < n; i++) { - udelay(1000); - } -#endif /* version < v2.1.0 */ } -STATIC int +/* + * Currently and inline noop but leave as a placeholder. + * Leave DvcEnterCritical() as a noop placeholder. + */ +STATIC inline ulong DvcEnterCritical(void) { - int flags; - - save_flags(flags); - cli(); - return flags; + return 0; } -STATIC void -DvcLeaveCritical(int flags) +/* + * Critical sections are all protected by the board spinlock. + * Leave DvcLeaveCritical() as a noop placeholder. + */ +STATIC inline void +DvcLeaveCritical(ulong flags) { - restore_flags(flags); -} - -STATIC ADV_DCNT -DvcGetSGList(ASC_DVC_VAR *asc_dvc_sg, uchar *buf_addr, ADV_DCNT buf_len, - ASC_SG_HEAD *asc_sg_head_ptr) -{ - ADV_DCNT buf_size; - - buf_size = buf_len; - asc_sg_head_ptr->entry_cnt = 1; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - asc_sg_head_ptr->sg_list[0].addr = (ADV_PADDR) buf_addr; -#else /* version >= v2.0.0 */ - asc_sg_head_ptr->sg_list[0].addr = virt_to_bus(buf_addr); -#endif /* version >= v2.0.0 */ - asc_sg_head_ptr->sg_list[0].bytes = buf_size; - return buf_size; + return; } /* * void - * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, ushort *outbuf, int words) + * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words) * * Calling/Exit State: * none @@ -9998,23 +9053,24 @@ * Output an ASC_SCSI_Q structure to the chip */ STATIC void -DvcPutScsiQ(PortAddr iop_base, ushort s_addr, ushort *outbuf, int words) +DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words) { int i; - ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", (uchar *) outbuf, 2 * words); + ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words); AscSetChipLramAddr(iop_base, s_addr); - for (i = 0; i < words; i++, outbuf++) { - if (i == 2 || i == 10) { + for (i = 0; i < 2 * words; i += 2) { + if (i == 4 || i == 20) { continue; } - AscSetChipLramDataNoSwap(iop_base, *outbuf); + outpw(iop_base + IOP_RAM_DATA, + ((ushort) outbuf[i + 1] << 8) | outbuf[i]); } } /* * void - * DvcGetQinfo(PortAddr iop_base, ushort s_addr, ushort *inbuf, int words) + * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words) * * Calling/Exit State: * none @@ -10023,79 +9079,21 @@ * Input an ASC_QDONE_INFO structure from the chip */ STATIC void -DvcGetQinfo(PortAddr iop_base, ushort s_addr, ushort *inbuf, int words) +DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words) { int i; + ushort word; AscSetChipLramAddr(iop_base, s_addr); - for (i = 0; i < words; i++, inbuf++) { - if (i == 5) { + for (i = 0; i < 2 * words; i += 2) { + if (i == 10) { continue; } - *inbuf = AscGetChipLramDataNoSwap(iop_base); - } - ASC_DBG_PRT_HEX(2, "DvcGetQinfo", (uchar *) inbuf, 2 * words); -} - -/* - * void DvcOutPortWords(ushort iop_base, ushort &outbuf, int words) - * - * Calling/Exit State: - * none - * - * Description: - * output a buffer to an i/o port address - */ -STATIC void -DvcOutPortWords(ushort iop_base, ushort *outbuf, int words) -{ - int i; - - for (i = 0; i < words; i++, outbuf++) - outpw(iop_base, *outbuf); -} - -/* - * void DvcInPortWords(ushort iop_base, ushort &outbuf, int words) - * - * Calling/Exit State: - * none - * - * Description: - * input a buffer from an i/o port address - */ -STATIC void -DvcInPortWords(ushort iop_base, ushort *inbuf, int words) -{ - int i; - - for (i = 0; i < words; i++, inbuf++) - *inbuf = inpw(iop_base); -} - -/* - * void DvcOutPortDWords(PortAddr port, ADV_DCNT *pdw, int dwords) - * - * Calling/Exit State: - * none - * - * Description: - * output a buffer of 32-bit integers to an i/o port address in - * 16 bit integer units - */ -STATIC void -DvcOutPortDWords(PortAddr port, ADV_DCNT *pdw, int dwords) -{ - int i; - int words; - ushort *pw; - - pw = (ushort *) pdw; - words = dwords << 1; - for(i = 0; i < words; i++, pw++) { - outpw(port, *pw); + word = inpw(iop_base + IOP_RAM_DATA); + inbuf[i] = word & 0xff; + inbuf[i + 1] = (word >> 8) & 0xff; } - return; + ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words); } /* @@ -10104,24 +9102,10 @@ ASC_INITFUNC( STATIC uchar, DvcReadPCIConfigByte( - ASC_DVC_VAR *asc_dvc, + ASC_DVC_VAR *asc_dvc, ushort offset) ) { -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - PCI_DATA pciData; - - pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info); - pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info); - pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info); - pciData.offset = offset; - pciData.type = pci_scan_method; - return asc_get_cfg_byte(&pciData); -#else /* ASC_CONFIG_PCI */ - return 0; -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ #ifdef CONFIG_PCI uchar byte_data; pcibios_read_config_byte(ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info), @@ -10129,10 +9113,9 @@ ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info)), offset, &byte_data); return byte_data; -#else /* CONFIG_PCI */ +#else /* !defined(CONFIG_PCI) */ return 0; -#endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ +#endif /* !defined(CONFIG_PCI) */ } /* @@ -10141,30 +9124,17 @@ ASC_INITFUNC( STATIC void, DvcWritePCIConfigByte( - ASC_DVC_VAR *asc_dvc, - ushort offset, + ASC_DVC_VAR *asc_dvc, + ushort offset, uchar byte_data) ) { -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - PCI_DATA pciData; - - pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info); - pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info); - pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info); - pciData.offset = offset; - pciData.type = pci_scan_method; - asc_put_cfg_byte(&pciData, byte_data); -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ #ifdef CONFIG_PCI pcibios_write_config_byte(ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info), PCI_DEVFN(ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info), ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info)), offset, byte_data); #endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ } /* @@ -10192,6 +9162,7 @@ return(0); } +#ifdef CONFIG_ISA if((bus_type & ASC_IS_EISA) != 0) { cfg_lsw = AscGetEisaChipCfg(iop_base); @@ -10200,6 +9171,7 @@ (cfg_lsw * ASC_BIOS_BANK_SIZE)); return(bios_addr); }/* if */ +#endif /* CONFIG_ISA */ cfg_lsw = AscGetChipCfgLsw(iop_base); @@ -10238,14 +9210,10 @@ { ADV_PADDR paddr; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - paddr = (ADV_PADDR) vaddr; -#else /* version >= v2.0.0 */ paddr = virt_to_bus(vaddr); -#endif /* version >= v2.0.0 */ ASC_DBG4(4, - "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n", + "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n", (ulong) vaddr, (ulong) lenp, (ulong) *((ulong *) lenp), (ulong) paddr); return paddr; @@ -10257,24 +9225,10 @@ ASC_INITFUNC( STATIC uchar, DvcAdvReadPCIConfigByte( - ADV_DVC_VAR *asc_dvc, + ADV_DVC_VAR *asc_dvc, ushort offset) ) { -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - PCI_DATA pciData; - - pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info); - pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info); - pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info); - pciData.offset = offset; - pciData.type = pci_scan_method; - return asc_get_cfg_byte(&pciData); -#else /* ASC_CONFIG_PCI */ - return 0; -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ #ifdef CONFIG_PCI uchar byte_data; pcibios_read_config_byte(ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info), @@ -10285,7 +9239,6 @@ #else /* CONFIG_PCI */ return 0; #endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ } /* @@ -10294,30 +9247,19 @@ ASC_INITFUNC( STATIC void, DvcAdvWritePCIConfigByte( - ADV_DVC_VAR *asc_dvc, - ushort offset, + ADV_DVC_VAR *asc_dvc, + ushort offset, uchar byte_data) ) { -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - PCI_DATA pciData; - - pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info); - pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info); - pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info); - pciData.offset = offset; - pciData.type = pci_scan_method; - asc_put_cfg_byte(&pciData, byte_data); -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ #ifdef CONFIG_PCI pcibios_write_config_byte(ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info), PCI_DEVFN(ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info), ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info)), offset, byte_data); +#else /* CONFIG_PCI */ + return 0; #endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ } /* @@ -10325,6 +9267,7 @@ */ #ifdef ADVANSYS_STATS +#ifdef CONFIG_PROC_FS /* * asc_prt_board_stats() * @@ -10341,11 +9284,7 @@ int totlen; int len; struct asc_stats *s; - int i; - ushort chip_scsi_id; asc_board_t *boardp; - asc_queue_t *active; - asc_queue_t *waiting; leftlen = cplen; totlen = len = 0; @@ -10356,15 +9295,16 @@ len = asc_prt_line(cp, leftlen, "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n", shp->host_no); ASC_PRT_NEXT(); - + len = asc_prt_line(cp, leftlen, -" command %lu, queuecommand %lu, abort %lu, reset %lu, biosparam %lu\n", - s->command, s->queuecommand, s->abort, s->reset, s->biosparam); +" queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n", + s->queuecommand, s->reset, s->biosparam, s->interrupt); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" interrupt %lu, callback %lu, done %lu\n", - s->interrupt, s->callback, s->done); +" callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n", + s->callback, s->done, s->build_error, s->adv_build_noreq, + s->adv_build_nosg); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, @@ -10372,17 +9312,6 @@ s->exe_noerror, s->exe_busy, s->exe_error, s->exe_unknown); ASC_PRT_NEXT(); - if (ASC_NARROW_BOARD(boardp)) { - len = asc_prt_line(cp, leftlen, -" build_error %lu\n", - s->build_error); - } else { - len = asc_prt_line(cp, leftlen, -" build_error %lu, build_noreq %lu, build_nosg %lu\n", - s->build_error, s->adv_build_noreq, s->adv_build_nosg); - } - ASC_PRT_NEXT(); - /* * Display data transfer statistics. */ @@ -10437,6 +9366,40 @@ " Active and Waiting Request Queues (Time Unit: %d HZ):\n", HZ); ASC_PRT_NEXT(); + + return totlen; +} + +/* + * asc_prt_target_stats() + * + * Note: no single line should be greater than ASC_PRTLINE_SIZE, + * cf. asc_prt_line(). + * + * This is separated from asc_prt_board_stats because a full set + * of targets will overflow ASC_PRTBUF_SIZE. + * + * Return the number of characters copied into 'cp'. No more than + * 'cplen' characters will be copied to 'cp'. + */ +STATIC int +asc_prt_target_stats(struct Scsi_Host *shp, int tgt_id, char *cp, int cplen) +{ + int leftlen; + int totlen; + int len; + struct asc_stats *s; + ushort chip_scsi_id; + asc_board_t *boardp; + asc_queue_t *active; + asc_queue_t *waiting; + + leftlen = cplen; + totlen = len = 0; + + boardp = ASC_BOARDP(shp); + s = &boardp->asc_stats; + active = &ASC_BOARDP(shp)->active; waiting = &ASC_BOARDP(shp)->waiting; @@ -10446,70 +9409,77 @@ chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id; } - for (i = 0; i <= ADV_MAX_TID; i++) { - - if ((chip_scsi_id == i) || - ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { - continue; - } + if ((chip_scsi_id == tgt_id) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) { + return 0; + } - if (active->q_tot_cnt[i] > 0 || waiting->q_tot_cnt[i] > 0) { - len = asc_prt_line(cp, leftlen, " target %d\n", i); + do { + if (active->q_tot_cnt[tgt_id] > 0 || waiting->q_tot_cnt[tgt_id] > 0) { + len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n", - active->q_cur_cnt[i], active->q_max_cnt[i], - active->q_tot_cnt[i], - active->q_min_tim[i], active->q_max_tim[i], - (active->q_tot_cnt[i] == 0) ? 0 : - (active->q_tot_tim[i]/active->q_tot_cnt[i]), - (active->q_tot_cnt[i] == 0) ? 0 : - ASC_TENTHS(active->q_tot_tim[i], active->q_tot_cnt[i])); - ASC_PRT_NEXT(); + active->q_cur_cnt[tgt_id], active->q_max_cnt[tgt_id], + active->q_tot_cnt[tgt_id], + active->q_min_tim[tgt_id], active->q_max_tim[tgt_id], + (active->q_tot_cnt[tgt_id] == 0) ? 0 : + (active->q_tot_tim[tgt_id]/active->q_tot_cnt[tgt_id]), + (active->q_tot_cnt[tgt_id] == 0) ? 0 : + ASC_TENTHS(active->q_tot_tim[tgt_id], + active->q_tot_cnt[tgt_id])); + ASC_PRT_NEXT(); - len = asc_prt_line(cp, leftlen, + len = asc_prt_line(cp, leftlen, " waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n", - waiting->q_cur_cnt[i], waiting->q_max_cnt[i], - waiting->q_tot_cnt[i], - waiting->q_min_tim[i], waiting->q_max_tim[i], - (waiting->q_tot_cnt[i] == 0) ? 0 : - (waiting->q_tot_tim[i]/waiting->q_tot_cnt[i]), - (waiting->q_tot_cnt[i] == 0) ? 0 : - ASC_TENTHS(waiting->q_tot_tim[i], waiting->q_tot_cnt[i])); - ASC_PRT_NEXT(); + waiting->q_cur_cnt[tgt_id], waiting->q_max_cnt[tgt_id], + waiting->q_tot_cnt[tgt_id], + waiting->q_min_tim[tgt_id], waiting->q_max_tim[tgt_id], + (waiting->q_tot_cnt[tgt_id] == 0) ? 0 : + (waiting->q_tot_tim[tgt_id]/waiting->q_tot_cnt[tgt_id]), + (waiting->q_tot_cnt[tgt_id] == 0) ? 0 : + ASC_TENTHS(waiting->q_tot_tim[tgt_id], + waiting->q_tot_cnt[tgt_id])); + ASC_PRT_NEXT(); } - } + } while (0); return totlen; } +#endif /* CONFIG_PROC_FS */ #endif /* ADVANSYS_STATS */ #ifdef ADVANSYS_DEBUG /* * asc_prt_scsi_host() */ -STATIC void +STATIC void asc_prt_scsi_host(struct Scsi_Host *s) { asc_board_t *boardp; boardp = ASC_BOARDP(s); - printk("Scsi_Host at addr %lx\n", (ulong) s); + printk("Scsi_Host at addr 0x%lx\n", (ulong) s); printk( -" next %lx, extra_bytes %u, host_busy %u, host_no %d, last_reset %d,\n", +" next 0x%lx, extra_bytes %u, host_busy %u, host_no %d, last_reset %d,\n", (ulong) s->next, s->extra_bytes, s->host_busy, s->host_no, (unsigned) s->last_reset); +#if ASC_LINUX_KERNEL24 + printk( +" host_queue 0x%lx, hostt 0x%lx\n", + (ulong) s->host_queue, (ulong) s->hostt); +#elif ASC_LINUX_KERNEL22 printk( -" host_queue %lx, hostt %lx, block %lx,\n", +" host_queue 0x%lx, hostt 0x%lx, block 0x%lx,\n", (ulong) s->host_queue, (ulong) s->hostt, (ulong) s->block); +#endif printk( -" base %lu, io_port %lu, n_io_port %u, irq %d,\n", - (ulong) s->base, (ulong) s->io_port, s->n_io_port, - s->irq); +" base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n", + (ulong) s->base, (ulong) s->io_port, s->n_io_port, s->irq); printk( " dma_channel %d, this_id %d, can_queue %d,\n", @@ -10532,49 +9502,49 @@ /* * asc_prt_scsi_cmnd() */ -STATIC void +STATIC void asc_prt_scsi_cmnd(Scsi_Cmnd *s) { - printk("Scsi_Cmnd at addr %lx\n", (ulong) s); + printk("Scsi_Cmnd at addr 0x%lx\n", (ulong) s); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) printk( -" host %x, device %x, target %u, lun %u\n", - (unsigned) s->host, (unsigned) s->device, s->target, s->lun); -#else /* version >= v1.3.0 */ - printk( -" host %lx, device %lx, target %u, lun %u, channel %u,\n", +" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n", (ulong) s->host, (ulong) s->device, s->target, s->lun, s->channel); -#endif /* version >= v1.3.0 */ asc_prt_hex(" CDB", s->cmnd, s->cmd_len); +#if ASC_LINUX_KERNEL24 + printk ( +"sc_data_direction %u, resid %d\n", + s->sc_data_direction, s->resid); +#endif + printk( -" use_sg %u, sglist_len %u, abort_reason %x\n", +" use_sg %u, sglist_len %u, abort_reason 0x%x\n", s->use_sg, s->sglist_len, s->abort_reason); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) - printk( -" retries %d, allowed %d\n", - s->retries, s->allowed); -#else /* version >= v1.3.89 */ printk( -" serial_number %x, serial_number_at_timeout %x, retries %d, allowed %d\n", +" serial_number 0x%x, serial_number_at_timeout 0x%x, retries %d, allowed %d\n", (unsigned) s->serial_number, (unsigned) s->serial_number_at_timeout, s->retries, s->allowed); -#endif /* version >= v1.3.89 */ printk( " timeout_per_command %d, timeout_total %d, timeout %d\n", s->timeout_per_command, s->timeout_total, s->timeout); +#if ASC_LINUX_KERNEL24 + printk( +" internal_timeout %u, flags %u\n", + s->internal_timeout, s->flags); +#elif ASC_LINUX_KERNEL22 printk( " internal_timeout %u, flags %u, this_count %d\n", - s->internal_timeout, s->flags, s->this_count); + s->internal_timeout, s->flags,s->this_count); +#endif printk( -" scsi_done %lx, done %lx, host_scribble %lx, result %x\n", +" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n", (ulong) s->scsi_done, (ulong) s->done, (ulong) s->host_scribble, s->result); @@ -10586,57 +9556,59 @@ /* * asc_prt_asc_dvc_var() */ -STATIC void +STATIC void asc_prt_asc_dvc_var(ASC_DVC_VAR *h) { - printk("ASC_DVC_VAR at addr %lx\n", (ulong) h); + printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong) h); printk( -" iop_base %x, err_code %x, dvc_cntl %x, bug_fix_cntl %d,\n", +" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl %d,\n", h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl); printk( -" bus_type %d, isr_callback %lx, exe_callback %lx, init_sdtr %x,\n", +" bus_type %d, isr_callback 0x%lx, exe_callback 0x%lx, init_sdtr 0x%x,\n", h->bus_type, (ulong) h->isr_callback, (ulong) h->exe_callback, (unsigned) h->init_sdtr); printk( -" sdtr_done %x, use_tagged_qng %x, unit_not_ready %x, chip_no %x,\n", +" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, chip_no 0x%x,\n", (unsigned) h->sdtr_done, (unsigned) h->use_tagged_qng, (unsigned) h->unit_not_ready, (unsigned) h->chip_no); - + printk( -" queue_full_or_busy %x, start_motor %x, scsi_reset_wait %x, irq_no %x,\n", +" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait %u,\n", (unsigned) h->queue_full_or_busy, (unsigned) h->start_motor, - (unsigned) h->scsi_reset_wait, (unsigned) h->irq_no); + (unsigned) h->scsi_reset_wait); printk( -" is_in_int %x, max_total_qng %x, cur_total_qng %x, in_critical_cnt %x,\n", +" is_in_int %u, max_total_qng %u, cur_total_qng %u, in_critical_cnt %u,\n", (unsigned) h->is_in_int, (unsigned) h->max_total_qng, (unsigned) h->cur_total_qng, (unsigned) h->in_critical_cnt); printk( -" last_q_shortage %x, init_state %x, no_scam %x, pci_fix_asyn_xfer %x,\n", +" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, pci_fix_asyn_xfer 0x%x,\n", (unsigned) h->last_q_shortage, (unsigned) h->init_state, (unsigned) h->no_scam, (unsigned) h->pci_fix_asyn_xfer); printk( -" cfg %lx\n", - (ulong) h->cfg); +" cfg 0x%lx, irq_no 0x%x\n", + (ulong) h->cfg, (unsigned) h->irq_no); } /* * asc_prt_asc_dvc_cfg() */ -STATIC void +STATIC void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h) { - printk("ASC_DVC_CFG at addr %lx\n", (ulong) h); + printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong) h); printk( -" can_tagged_qng %x, cmd_qng_enabled %x, disc_enable %x, sdtr_enable %x,\n", - h->can_tagged_qng, h->cmd_qng_enabled, h->disc_enable, - h->sdtr_enable); +" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n", + h->can_tagged_qng, h->cmd_qng_enabled); + printk( +" disc_enable 0x%x, sdtr_enable 0x%x,\n", + h->disc_enable, h->sdtr_enable); printk( " chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n", @@ -10644,48 +9616,49 @@ h->chip_version); printk( -" pci_device_id %d, lib_serial_no %x, lib_version %x, mcode_date %x,\n", +" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n", h->pci_device_id, h->lib_serial_no, h->lib_version, h->mcode_date); printk( -" mcode_version %d, overrun_buf %lx\n", +" mcode_version %d, overrun_buf 0x%lx\n", h->mcode_version, (ulong) h->overrun_buf); } /* * asc_prt_asc_scsi_q() */ -STATIC void +STATIC void asc_prt_asc_scsi_q(ASC_SCSI_Q *q) { ASC_SG_HEAD *sgp; int i; - printk("ASC_SCSI_Q at addr %lx\n", (ulong) q); + printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong) q); printk( -" target_ix %u, target_lun %u, srb_ptr %x, tag_code %u,\n", +" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n", q->q2.target_ix, q->q1.target_lun, - (unsigned) q->q2.srb_ptr, q->q2.tag_code); + (ulong) q->q2.srb_ptr, q->q2.tag_code); printk( -" data_addr %lx, data_cnt %lu, sense_addr %lx, sense_len %u,\n", - (ulong) q->q1.data_addr, (ulong) q->q1.data_cnt, - (ulong) q->q1.sense_addr, q->q1.sense_len); +" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n", + (ulong) le32_to_cpu(q->q1.data_addr), + (ulong) le32_to_cpu(q->q1.data_cnt), + (ulong) le32_to_cpu(q->q1.sense_addr), q->q1.sense_len); printk( -" cdbptr %lx, cdb_len %u, sg_head %lx, sg_queue_cnt %u\n", +" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n", (ulong) q->cdbptr, q->q2.cdb_len, (ulong) q->sg_head, q->q1.sg_queue_cnt); if (q->sg_head) { sgp = q->sg_head; - printk("ASC_SG_HEAD at addr %lx\n", (ulong) sgp); + printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong) sgp); printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt, sgp->queue_cnt); for (i = 0; i < sgp->entry_cnt; i++) { - printk(" [%u]: addr %lx, bytes %lu\n", - i, (ulong) sgp->sg_list[i].addr, - (ulong) sgp->sg_list[i].bytes); + printk(" [%u]: addr 0x%lx, bytes %lu\n", + i, (ulong) le32_to_cpu(sgp->sg_list[i].addr), + (ulong) le32_to_cpu(sgp->sg_list[i].bytes)); } } @@ -10694,17 +9667,17 @@ /* * asc_prt_asc_qdone_info() */ -STATIC void +STATIC void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q) { - printk("ASC_QDONE_INFO at addr %lx\n", (ulong) q); + printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong) q); printk( -" srb_ptr %x, target_ix %u, cdb_len %u, tag_code %u, done_stat %x\n", - (unsigned) q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len, - q->d2.tag_code, q->d3.done_stat); +" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n", + (ulong) q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len, + q->d2.tag_code); printk( -" host_stat %x, scsi_stat %x, scsi_msg %x\n", - q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg); +" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n", + q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg); } /* @@ -10712,7 +9685,7 @@ * * Display an ADV_DVC_VAR structure. */ -STATIC void +STATIC void asc_prt_adv_dvc_var(ADV_DVC_VAR *h) { printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong) h); @@ -10723,8 +9696,8 @@ printk( " isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n", - (ulong) h->isr_callback, (unsigned) h->wdtr_able, - (unsigned) h->sdtr_able); + (ulong) h->isr_callback, (unsigned) h->sdtr_able, + (unsigned) h->wdtr_able); printk( " start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n", @@ -10732,12 +9705,12 @@ (unsigned) h->scsi_reset_wait, (unsigned) h->irq_no); printk( -" max_host_qng %x, max_dvc_qng %x, carr_freelist %lxn\n", +" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n", (unsigned) h->max_host_qng, (unsigned) h->max_dvc_qng, (ulong) h->carr_freelist); printk( -" icq_sp %lx, irq_sp %lx\n", +" icq_sp 0x%lx, irq_sp 0x%lx\n", (ulong) h->icq_sp, (ulong) h->irq_sp); printk( @@ -10745,7 +9718,7 @@ (unsigned) h->no_scam, (unsigned) h->tagqng_able); printk( -" chip_scsi_id 0x%x, cfg %lx\n", +" chip_scsi_id 0x%x, cfg 0x%lx\n", (unsigned) h->chip_scsi_id, (ulong) h->cfg); } @@ -10754,7 +9727,7 @@ * * Display an ADV_DVC_CFG structure. */ -STATIC void +STATIC void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h) { printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong) h); @@ -10768,7 +9741,7 @@ h->chip_version, h->mcode_date); printk( -" mcode_version 0x%x, pci_device_id 0x%x, lib_version 0x%x\n", +" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n", h->mcode_version, h->pci_device_id, h->lib_version); printk( @@ -10781,37 +9754,38 @@ * * Display an ADV_SCSI_REQ_Q structure. */ -STATIC void +STATIC void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q) { int sg_blk_cnt; struct asc_sg_block *sg_ptr; - printk("ADV_SCSI_REQ_Q at addr %lx\n", (ulong) q); + printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong) q); printk( " target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n", q->target_id, q->target_lun, (ulong) q->srb_ptr, q->a_flag); printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n", - q->cntl, (ulong) q->data_addr, (ulong) q->vdata_addr); + q->cntl, (ulong) le32_to_cpu(q->data_addr), (ulong) q->vdata_addr); printk( " data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n", - (ulong) q->data_cnt, (ulong) q->sense_addr, q->sense_len); + (ulong) le32_to_cpu(q->data_cnt), + (ulong) le32_to_cpu(q->sense_addr), q->sense_len); printk( " cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n", q->cdb_len, q->done_status, q->host_status, q->scsi_status); printk( -" sg_working_ix %x, sg_working_data_cnt %lx, target_cmd %u\n", - q->sg_working_ix, (ulong) q->sg_working_data_cnt, q->target_cmd); +" sg_working_ix 0x%x, target_cmd %u\n", + q->sg_working_ix, q->target_cmd); printk( -" scsiq_rptr %lx, sg_real_addr %lx, sg_list_ptr %lx\n", - (ulong) q->scsiq_rptr, (ulong) q->sg_real_addr, - (ulong) q->sg_list_ptr); +" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n", + (ulong) le32_to_cpu(q->scsiq_rptr), + (ulong) le32_to_cpu(q->sg_real_addr), (ulong) q->sg_list_ptr); /* Display the request's ADV_SG_BLOCK structures. */ if (q->sg_list_ptr != NULL) @@ -10846,17 +9820,17 @@ { int i; - printk(" ASC_SG_BLOCK at addr %lx (sgblockno %d)\n", + printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n", (ulong) b, sgblockno); - printk(" sg_cnt %u, sg_ptr %lx\n", - b->sg_cnt, (ulong) b->sg_ptr); + printk(" sg_cnt %u, sg_ptr 0x%lx\n", + b->sg_cnt, (ulong) le32_to_cpu(b->sg_ptr)); ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK); if (b->sg_ptr != 0) { ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK); } for (i = 0; i < b->sg_cnt; i++) { - printk(" [%u]: sg_addr %lx, sg_count %lx\n", + printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n", i, (ulong) b->sg_list[i].sg_addr, (ulong) b->sg_list[i].sg_count); } } @@ -10864,10 +9838,10 @@ /* * asc_prt_hex() * - * Print hexadecimal output in 4 byte groupings 32 bytes + * Print hexadecimal output in 4 byte groupings 32 bytes * or 8 double-words per line. */ -STATIC void +STATIC void asc_prt_hex(char *f, uchar *s, int l) { int i; @@ -10878,7 +9852,7 @@ printk("%s: (%d bytes)\n", f, l); for (i = 0; i < l; i += 32) { - + /* Display a maximum of 8 double-words per line. */ if ((k = (l - i) / 4) >= 8) { k = 8; @@ -10919,27 +9893,6 @@ } #endif /* ADVANSYS_DEBUG */ -#ifdef ADVANSYS_ASSERT -/* - * advansys_interrupts_enabled() - * - * Return 1 if interrupts are enabled, otherwise return 0. - */ -STATIC int -advansys_interrupts_enabled(void) -{ - int flags; - - save_flags(flags); - if (flags & 0x0200) { - return ASC_TRUE; - } else { - return ASC_FALSE; - } -} -#endif /* ADVANSYS_ASSERT */ - - /* * --- Asc Library Functions */ @@ -11047,42 +10000,47 @@ return (0); } -ASC_INITFUNC( -STATIC ASC_DCNT, +STATIC ASC_DCNT AscLoadMicroCode( PortAddr iop_base, ushort s_addr, - ushort *mcode_buf, + uchar *mcode_buf, ushort mcode_size ) -) { ASC_DCNT chksum; ushort mcode_word_size; ushort mcode_chksum; + /* Write the microcode buffer starting at LRAM address 0. */ mcode_word_size = (ushort) (mcode_size >> 1); AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size); - AscMemWordCopyToLram(iop_base, s_addr, mcode_buf, mcode_word_size); + AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size); + chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size); + ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong) chksum); mcode_chksum = (ushort) AscMemSumLramWord(iop_base, - (ushort) ASC_CODE_SEC_BEG, + (ushort) ASC_CODE_SEC_BEG, (ushort) ((mcode_size - s_addr - (ushort) ASC_CODE_SEC_BEG) / 2)); + ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n", + (ulong) mcode_chksum); AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum); AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size); return (chksum); } -ASC_INITFUNC( -STATIC int, +STATIC int AscFindSignature( PortAddr iop_base ) -) { ushort sig_word; + ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n", + iop_base, AscGetChipSignatureByte(iop_base)); if (AscGetChipSignatureByte(iop_base) == (uchar) ASC_1000_ID1B) { + ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n", + iop_base, AscGetChipSignatureWord(iop_base)); sig_word = AscGetChipSignatureWord(iop_base); if ((sig_word == (ushort) ASC_1000_ID0W) || (sig_word == (ushort) ASC_1000_ID0W_FIX)) { @@ -11092,13 +10050,15 @@ return (0); } -STATIC uchar _isa_pnp_inited ASC_INITDATA = 0; STATIC PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] ASC_INITDATA = { 0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4, ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8 }; +#ifdef CONFIG_ISA +STATIC uchar _isa_pnp_inited ASC_INITDATA = 0; + ASC_INITFUNC( STATIC PortAddr, AscSearchIOPortAddr( @@ -11155,11 +10115,11 @@ iop_base = _asc_def_iop_base[i]; if (check_region(iop_base, ASC_IOADR_GAP) != 0) { ASC_DBG1(1, - "AscSearchIOPortAddr11: check_region() failed I/O port %x\n", + "AscSearchIOPortAddr11: check_region() failed I/O port 0x%x\n", iop_base); continue; } - ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port %x\n", iop_base); + ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port 0x%x\n", iop_base); if (AscFindSignature(iop_base)) { return (iop_base); } @@ -11169,24 +10129,25 @@ ASC_INITFUNC( STATIC void, -AscToggleIRQAct( - PortAddr iop_base -) +AscSetISAPNPWaitForKey( + void) ) { - AscSetChipStatus(iop_base, CIW_IRQ_ACT); - AscSetChipStatus(iop_base, 0); + outp(ASC_ISA_PNP_PORT_ADDR, 0x02); + outp(ASC_ISA_PNP_PORT_WRITE, 0x02); return; } +#endif /* CONFIG_ISA */ ASC_INITFUNC( STATIC void, -AscSetISAPNPWaitForKey( - void) +AscToggleIRQAct( + PortAddr iop_base +) ) { - outp(ASC_ISA_PNP_PORT_ADDR, 0x02); - outp(ASC_ISA_PNP_PORT_WRITE, 0x02); + AscSetChipStatus(iop_base, CIW_IRQ_ACT); + AscSetChipStatus(iop_base, 0); return; } @@ -11267,6 +10228,7 @@ return (0); } +#ifdef CONFIG_ISA ASC_INITFUNC( STATIC void, AscEnableIsaDma( @@ -11283,8 +10245,9 @@ } return; } +#endif /* CONFIG_ISA */ -STATIC int +STATIC int AscIsrChipHalted( ASC_DVC_VAR *asc_dvc ) @@ -11343,10 +10306,10 @@ return (0); } else if (int_halt_code == ASC_HALT_EXTMSG_IN) { - AscMemWordCopyFromLram(iop_base, + AscMemWordCopyPtrFromLram(iop_base, ASCV_MSGIN_BEG, - (ushort *) & ext_msg, - (ushort) (sizeof (EXT_MSG) >> 1)); + (uchar *) &ext_msg, + sizeof(EXT_MSG) >> 1); if (ext_msg.msg_type == MS_EXTEND && ext_msg.msg_req == MS_SDTR_CODE && @@ -11420,10 +10383,10 @@ ext_msg.msg_len == MS_WDTR_LEN) { ext_msg.wdtr_width = 0; - AscMemWordCopyToLram(iop_base, + AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG, - (ushort *) & ext_msg, - (ushort) (sizeof (EXT_MSG) >> 1)); + (uchar *) &ext_msg, + sizeof(EXT_MSG) >> 1); q_cntl |= QC_MSG_OUT; AscWriteLramByte(iop_base, (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), @@ -11433,10 +10396,10 @@ } else { ext_msg.msg_type = M1_MSG_REJECT; - AscMemWordCopyToLram(iop_base, + AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG, - (ushort *) & ext_msg, - (ushort) (sizeof (EXT_MSG) >> 1)); + (uchar *) &ext_msg, + sizeof(EXT_MSG) >> 1); q_cntl |= QC_MSG_OUT; AscWriteLramByte(iop_base, (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), @@ -11496,10 +10459,10 @@ return (0); } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) { - AscMemWordCopyFromLram(iop_base, + AscMemWordCopyPtrFromLram(iop_base, ASCV_MSGOUT_BEG, - (ushort *) & out_msg, - (ushort) (sizeof (EXT_MSG) >> 1)); + (uchar *) &out_msg, + sizeof(EXT_MSG) >> 1); if ((out_msg.msg_type == MS_EXTEND) && (out_msg.msg_len == MS_SDTR_LEN) && @@ -11554,7 +10517,9 @@ } AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); return (0); - } else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) + } +#if CC_VERY_LONG_SG_LIST + else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) { uchar q_no; ushort q_addr; @@ -11678,16 +10643,15 @@ } scsi_sg_q.q_no = next_qp; - AscMemWordCopyToLram(iop_base, - (ushort) (q_addr+ASC_SCSIQ_SGHD_CPY_BEG), - (ushort *) &scsi_sg_q, - (ushort) (sizeof(ASC_SG_LIST_Q) >> 1)); - - AscMemDWordCopyToLram( iop_base, - (ushort) (q_addr+ASC_SGQ_LIST_BEG ), - (ADV_PADDR *) - &sg_head->sg_list[scsiq->next_sg_index], - (ushort) sg_list_dwords); + AscMemWordCopyPtrToLram(iop_base, + q_addr + ASC_SCSIQ_SGHD_CPY_BEG, + (uchar *) &scsi_sg_q, + sizeof(ASC_SG_LIST_Q) >> 1); + + AscMemDWordCopyPtrToLram(iop_base, + q_addr + ASC_SGQ_LIST_BEG, + (uchar *) &sg_head->sg_list[scsiq->next_sg_index], + sg_list_dwords); scsiq->next_sg_index += ASC_SG_LIST_PER_Q; @@ -11713,6 +10677,7 @@ AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); return(0); } +#endif /* CC_VERY_LONG_SG_LIST */ return (0); } @@ -11728,9 +10693,10 @@ uchar sg_queue_cnt; DvcGetQinfo(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_DONE_INFO_BEG), - (ushort *) scsiq, - (ushort) ((sizeof (ASC_SCSIQ_2) + sizeof (ASC_SCSIQ_3)) / 2)); + q_addr + ASC_SCSIQ_DONE_INFO_BEG, + (uchar *) scsiq, + (sizeof (ASC_SCSIQ_2) + sizeof (ASC_SCSIQ_3)) / 2); + _val = AscReadLramWord(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS)); scsiq->q_status = (uchar) _val; @@ -11994,7 +10960,8 @@ return (int_pending); } -STATIC uchar _asc_mcode_buf[] ASC_INITDATA = +/* Microcode buffer is kept after initialization for error recovery. */ +STATIC uchar _asc_mcode_buf[] = { 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -12142,8 +11109,8 @@ 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xE6, 0x84, }; -STATIC ushort _asc_mcode_size ASC_INITDATA = sizeof(_asc_mcode_buf); -STATIC ADV_DCNT _asc_mcode_chksum ASC_INITDATA = 0x012C453FUL; +STATIC ushort _asc_mcode_size = sizeof(_asc_mcode_buf); +STATIC ADV_DCNT _asc_mcode_chksum = 0x012C453FUL; #define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16 STATIC uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = @@ -12173,7 +11140,7 @@ ) { PortAddr iop_base; - int last_int_level; + ulong last_int_level; int sta; int n_q_required; int disable_syn_offset_one_fix; @@ -12235,6 +11202,8 @@ #if !CC_VERY_LONG_SG_LIST if (sg_entry_cnt > ASC_MAX_SG_LIST) { + asc_dvc->in_critical_cnt--; + DvcLeaveCritical(last_int_level); return(ERR); } #endif /* !CC_VERY_LONG_SG_LIST */ @@ -12252,10 +11221,10 @@ if (scsiq->q1.cntl & QC_SG_HEAD) { data_cnt = 0; for (i = 0; i < sg_entry_cnt; i++) { - data_cnt += (ADV_DCNT) sg_head->sg_list[i].bytes; + data_cnt += (ADV_DCNT) le32_to_cpu(sg_head->sg_list[i].bytes); } } else { - data_cnt = scsiq->q1.data_cnt; + data_cnt = le32_to_cpu(scsiq->q1.data_cnt); } if (data_cnt != 0UL) { if (data_cnt < 512UL) { @@ -12279,7 +11248,7 @@ scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX | ASC_TAG_FLAG_DISABLE_DISCONNECT); } else { - scsiq->q2.tag_code &= 0x23; + scsiq->q2.tag_code &= 0x27; } if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) { if (asc_dvc->bug_fix_cntl) { @@ -12287,23 +11256,27 @@ if ((scsi_cmd == SCSICMD_Read6) || (scsi_cmd == SCSICMD_Read10)) { addr = - (ADV_PADDR) - sg_head->sg_list[sg_entry_cnt_minus_one].addr + - (ADV_DCNT) - sg_head->sg_list[sg_entry_cnt_minus_one].bytes; + (ADV_PADDR) le32_to_cpu( + sg_head->sg_list[sg_entry_cnt_minus_one].addr) + + (ADV_DCNT) le32_to_cpu( + sg_head->sg_list[sg_entry_cnt_minus_one].bytes); extra_bytes = (uchar) ((ushort) addr & 0x0003); if ((extra_bytes != 0) && ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0)) { scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES; scsiq->q1.extra_bytes = extra_bytes; - sg_head->sg_list[sg_entry_cnt_minus_one].bytes -= - (ASC_DCNT) extra_bytes; + data_cnt = le32_to_cpu( + sg_head->sg_list[sg_entry_cnt_minus_one].bytes); + data_cnt -= (ASC_DCNT) extra_bytes; + sg_head->sg_list[sg_entry_cnt_minus_one].bytes = + cpu_to_le32(data_cnt); } } } } sg_head->entry_to_copy = sg_head->entry_cnt; +#if CC_VERY_LONG_SG_LIST /* * Set the sg_entry_cnt to the maximum possible. The rest of * the SG elements will be copied when the RISC completes the @@ -12313,6 +11286,7 @@ { sg_entry_cnt = ASC_MAX_SG_LIST; } +#endif /* CC_VERY_LONG_SG_LIST */ n_q_required = AscSgListToQueue(sg_entry_cnt); if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >= (uint) n_q_required) || ((scsiq->q1.cntl & QC_URGENT) != 0)) { @@ -12331,14 +11305,17 @@ if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) { if ((scsi_cmd == SCSICMD_Read6) || (scsi_cmd == SCSICMD_Read10)) { - addr = scsiq->q1.data_addr + scsiq->q1.data_cnt; + addr = le32_to_cpu(scsiq->q1.data_addr) + + le32_to_cpu(scsiq->q1.data_cnt); extra_bytes = (uchar) ((ushort) addr & 0x0003); if ((extra_bytes != 0) && ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0)) { - if (((ushort) scsiq->q1.data_cnt & 0x01FF) == 0) { + data_cnt = le32_to_cpu(scsiq->q1.data_cnt); + if (((ushort) data_cnt & 0x01FF) == 0) { scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES; - scsiq->q1.data_cnt -= (ASC_DCNT) extra_bytes; + data_cnt -= (ASC_DCNT) extra_bytes; + scsiq->q1.data_cnt = cpu_to_le32(data_cnt); scsiq->q1.extra_bytes = extra_bytes; } } @@ -12501,14 +11478,15 @@ scsiq->q2.tag_code &= ~M2_QTAG_MSG_SIMPLE; } scsiq->q1.status = QS_FREE; - AscMemWordCopyToLram(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG), - (ushort *) scsiq->cdbptr, - (ushort) ((ushort) scsiq->q2.cdb_len >> 1)); + AscMemWordCopyPtrToLram(iop_base, + q_addr + ASC_SCSIQ_CDB_BEG, + (uchar *) scsiq->cdbptr, + scsiq->q2.cdb_len >> 1); + DvcPutScsiQ(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_CPY_BEG), - (ushort *) & scsiq->q1.cntl, - (ushort) ((((sizeof (ASC_SCSIQ_1) + sizeof (ASC_SCSIQ_2)) / 2) - 1))); + q_addr + ASC_SCSIQ_CPY_BEG, + (uchar *) &scsiq->q1.cntl, + ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1); AscWriteLramWord(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), (ushort) (((ushort) scsiq->q1.q_no << 8) | (ushort) QS_READY)); @@ -12541,6 +11519,7 @@ saved_data_cnt = scsiq->q1.data_cnt; scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr; scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes; +#if CC_VERY_LONG_SG_LIST /* * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST * then not all SG elements will fit in the allocated queues. @@ -12551,10 +11530,10 @@ { /* * Set sg_entry_cnt to be the number of SG elements that - * will fit in the allocated SG queues. It is minus 1 because - * first SG element handled above. ASC_MAX_SG_LIST is already - * inflated by 1 to account for this. For example it may - * be 50 which is 1 + 7 queues * 7 SG elements. + * will fit in the allocated SG queues. It is minus 1, because + * the first SG element is handled above. ASC_MAX_SG_LIST is + * already inflated by 1 to account for this. For example it + * may be 50 which is 1 + 7 queues * 7 SG elements. */ sg_entry_cnt = ASC_MAX_SG_LIST - 1; @@ -12565,13 +11544,16 @@ scsiq->remain_sg_entry_cnt = sg_head->entry_cnt - ASC_MAX_SG_LIST; } else { +#endif /* CC_VERY_LONG_SG_LIST */ /* * Set sg_entry_cnt to be the number of SG elements that - * will fit in the allocated SG queues. Refer to comment - * above regarding why it is - 1. + * will fit in the allocated SG queues. It is minus 1, because + * the first SG element is handled above. */ sg_entry_cnt = sg_head->entry_cnt - 1; +#if CC_VERY_LONG_SG_LIST } +#endif /* CC_VERY_LONG_SG_LIST */ if (sg_entry_cnt != 0) { scsiq->q1.cntl |= QC_SG_HEAD; q_addr = ASC_QNO_TO_QADDR(q_no); @@ -12592,6 +11574,7 @@ scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1; } } else { +#if CC_VERY_LONG_SG_LIST /* * This is the last SG queue in the list of * allocated SG queues. If there are more @@ -12603,8 +11586,11 @@ scsi_sg_q.cntl |= QCSG_SG_XFER_MORE; } else { +#endif /* CC_VERY_LONG_SG_LIST */ scsi_sg_q.cntl |= QCSG_SG_XFER_END; +#if CC_VERY_LONG_SG_LIST } +#endif /* CC_VERY_LONG_SG_LIST */ sg_list_dwords = sg_entry_cnt << 1; if (i == 0) { scsi_sg_q.sg_list_cnt = sg_entry_cnt; @@ -12619,14 +11605,14 @@ (ushort) (q_addr + ASC_SCSIQ_B_FWD)); scsi_sg_q.q_no = next_qp; q_addr = ASC_QNO_TO_QADDR(next_qp); - AscMemWordCopyToLram(iop_base, - (ushort) (q_addr + ASC_SCSIQ_SGHD_CPY_BEG), - (ushort *) & scsi_sg_q, - (ushort) (sizeof (ASC_SG_LIST_Q) >> 1)); - AscMemDWordCopyToLram(iop_base, - (ushort) (q_addr + ASC_SGQ_LIST_BEG), - (ADV_PADDR *) &sg_head->sg_list[sg_index], - (ushort) sg_list_dwords); + AscMemWordCopyPtrToLram(iop_base, + q_addr + ASC_SCSIQ_SGHD_CPY_BEG, + (uchar *) &scsi_sg_q, + sizeof(ASC_SG_LIST_Q) >> 1); + AscMemDWordCopyPtrToLram(iop_base, + q_addr + ASC_SGQ_LIST_BEG, + (uchar *) &sg_head->sg_list[sg_index], + sg_list_dwords); sg_index += ASC_SG_LIST_PER_Q; scsiq->next_sg_index = sg_index; } @@ -12640,171 +11626,30 @@ } STATIC int -AscAbortSRB( - ASC_DVC_VAR *asc_dvc, - ADV_VADDR srb_ptr +AscSetRunChipSynRegAtID( + PortAddr iop_base, + uchar tid_no, + uchar sdtr_data ) { - int sta; - ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready; - PortAddr iop_base; + int sta = FALSE; - iop_base = asc_dvc->iop_base; - sta = ERR; - saved_unit_not_ready = asc_dvc->unit_not_ready; - asc_dvc->unit_not_ready = 0xFF; - AscWaitISRDone(asc_dvc); - if (AscStopQueueExe(iop_base) == 1) { - if (AscRiscHaltedAbortSRB(asc_dvc, srb_ptr) == 1) { - sta = 1; - AscCleanUpBusyQueue(iop_base); - AscStartQueueExe(iop_base); - } else { - sta = 0; - AscStartQueueExe(iop_base); - } + if (AscHostReqRiscHalt(iop_base)) { + sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data); + AscStartChip(iop_base); + return (sta); } - asc_dvc->unit_not_ready = saved_unit_not_ready; return (sta); } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) STATIC int -AscResetDevice( - ASC_DVC_VAR *asc_dvc, - uchar target_ix +AscSetChipSynRegAtID( + PortAddr iop_base, + uchar id, + uchar sdtr_data ) { - PortAddr iop_base; - int sta; - uchar tid_no; - - ASC_SCSI_BIT_ID_TYPE target_id; - int i; - ASC_SCSI_REQ_Q scsiq_buf; - ASC_SCSI_REQ_Q *scsiq; - uchar *buf; - ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready; - iop_base = asc_dvc->iop_base; - tid_no = ASC_TIX_TO_TID(target_ix); - target_id = ASC_TID_TO_TARGET_ID(tid_no); - saved_unit_not_ready = asc_dvc->unit_not_ready; - asc_dvc->unit_not_ready = target_id; - sta = ERR; - AscWaitTixISRDone(asc_dvc, target_ix); - if (AscStopQueueExe(iop_base) == 1) { - if (AscRiscHaltedAbortTIX(asc_dvc, target_ix) == 1) { - AscCleanUpBusyQueue(iop_base); - AscStartQueueExe(iop_base); - AscWaitTixISRDone(asc_dvc, target_ix); - sta = TRUE; - scsiq = (ASC_SCSI_REQ_Q *) & scsiq_buf; - buf = (uchar *) & scsiq_buf; - for (i = 0; i < sizeof (ASC_SCSI_REQ_Q); i++) { - *buf++ = 0x00; - } - scsiq->r1.status = (uchar) QS_READY; - scsiq->r2.cdb_len = 6; - scsiq->r2.tag_code = M2_QTAG_MSG_SIMPLE; - scsiq->r1.target_id = target_id; - scsiq->r2.target_ix = ASC_TIDLUN_TO_IX(tid_no, 0); - scsiq->cdbptr = (uchar *) scsiq->cdb; - scsiq->r1.cntl = QC_NO_CALLBACK | QC_MSG_OUT | QC_URGENT; - AscWriteLramByte(asc_dvc->iop_base, ASCV_MSGOUT_BEG, - M1_BUS_DVC_RESET); - asc_dvc->unit_not_ready &= ~target_id; - asc_dvc->sdtr_done |= target_id; - if (AscExeScsiQueue(asc_dvc, (ASC_SCSI_Q *) scsiq) - == 1) { - asc_dvc->unit_not_ready = target_id; - DvcSleepMilliSecond(1000); - _AscWaitQDone(iop_base, (ASC_SCSI_Q *) scsiq); - if (AscStopQueueExe(iop_base) == 1) { - AscCleanUpDiscQueue(iop_base); - AscStartQueueExe(iop_base); - if (asc_dvc->pci_fix_asyn_xfer & target_id) { - AscSetRunChipSynRegAtID(iop_base, tid_no, - ASYN_SDTR_DATA_FIX_PCI_REV_AB); - } - AscWaitTixISRDone(asc_dvc, target_ix); - } - } else { - sta = 0; - } - asc_dvc->sdtr_done &= ~target_id; - } else { - sta = ERR; - AscStartQueueExe(iop_base); - } - } - asc_dvc->unit_not_ready = saved_unit_not_ready; - return (sta); -} -#endif /* version >= v1.3.89 */ - -STATIC int -AscResetSB( - ASC_DVC_VAR *asc_dvc -) -{ - int sta; - int i; - PortAddr iop_base; - - iop_base = asc_dvc->iop_base; - asc_dvc->unit_not_ready = 0xFF; - sta = TRUE; - AscWaitISRDone(asc_dvc); - AscStopQueueExe(iop_base); - asc_dvc->sdtr_done = 0; - AscResetChipAndScsiBus(asc_dvc); - DvcSleepMilliSecond((ASC_DCNT) ((ushort) asc_dvc->scsi_reset_wait * 1000)); - AscReInitLram(asc_dvc); - for (i = 0; i <= ASC_MAX_TID; i++) { - asc_dvc->cur_dvc_qng[i] = 0; - if (asc_dvc->pci_fix_asyn_xfer & (ASC_SCSI_BIT_ID_TYPE) (0x01 << i)) { - AscSetChipSynRegAtID(iop_base, i, ASYN_SDTR_DATA_FIX_PCI_REV_AB); - } - } - asc_dvc->err_code = 0; - AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); - if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { - sta = ERR; - } - if (AscStartChip(iop_base) == 0) { - sta = ERR; - } - AscStartQueueExe(iop_base); - asc_dvc->unit_not_ready = 0; - asc_dvc->queue_full_or_busy = 0; - return (sta); -} - -STATIC int -AscSetRunChipSynRegAtID( - PortAddr iop_base, - uchar tid_no, - uchar sdtr_data -) -{ - int sta = FALSE; - - if (AscHostReqRiscHalt(iop_base)) { - sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data); - AscStartChip(iop_base); - return (sta); - } - return (sta); -} - -STATIC int -AscSetChipSynRegAtID( - PortAddr iop_base, - uchar id, - uchar sdtr_data -) -{ - ASC_SCSI_BIT_ID_TYPE org_id; + ASC_SCSI_BIT_ID_TYPE org_id; int i; int sta = TRUE; @@ -12831,16 +11676,6 @@ return (sta); } -STATIC int -AscReInitLram( - ASC_DVC_VAR *asc_dvc -) -{ - AscInitLram(asc_dvc); - AscInitQLinkVar(asc_dvc); - return (0); -} - STATIC ushort AscInitLram( ASC_DVC_VAR *asc_dvc @@ -12942,31 +11777,7 @@ } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -STATIC int -_AscWaitQDone( - PortAddr iop_base, - ASC_SCSI_Q * scsiq -) -{ - ushort q_addr; - uchar q_status; - int count = 0; - - while (scsiq->q1.q_no == 0); - q_addr = ASC_QNO_TO_QADDR(scsiq->q1.q_no); - do { - q_status = AscReadLramByte(iop_base, q_addr + ASC_SCSIQ_B_STATUS); - DvcSleepMilliSecond(100L); - if (count++ > 30) { - return (0); - } - } while ((q_status & QS_READY) != 0); - return (1); -} -#endif /* version >= v1.3.89 */ - -STATIC uchar +STATIC uchar AscMsgOutSDTR( ASC_DVC_VAR *asc_dvc, uchar sdtr_period, @@ -12987,18 +11798,18 @@ if ((sdtr_period_index = AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <= asc_dvc->max_sdtr_index) { - AscMemWordCopyToLram(iop_base, + AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG, - (ushort *) & sdtr_buf, - (ushort) (sizeof (EXT_MSG) >> 1)); + (uchar *) &sdtr_buf, + sizeof (EXT_MSG) >> 1); return ((sdtr_period_index << 4) | sdtr_offset); } else { sdtr_buf.req_ack_offset = 0; - AscMemWordCopyToLram(iop_base, + AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG, - (ushort *) & sdtr_buf, - (ushort) (sizeof (EXT_MSG) >> 1)); + (uchar *) &sdtr_buf, + sizeof (EXT_MSG) >> 1); return (0); } } @@ -13101,95 +11912,6 @@ } STATIC int -AscRiscHaltedAbortSRB( - ASC_DVC_VAR *asc_dvc, - ASC_VADDR srb_ptr -) -{ - PortAddr iop_base; - ushort q_addr; - uchar q_no; - ASC_QDONE_INFO scsiq_buf; - ASC_QDONE_INFO *scsiq; - ASC_ISR_CALLBACK asc_isr_callback; - int last_int_level; - - iop_base = asc_dvc->iop_base; - asc_isr_callback = asc_dvc->isr_callback; - last_int_level = DvcEnterCritical(); - scsiq = (ASC_QDONE_INFO *) & scsiq_buf; - for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng; - q_no++) { - q_addr = ASC_QNO_TO_QADDR(q_no); - scsiq->d2.srb_ptr = AscReadLramDWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR)); - if (scsiq->d2.srb_ptr == srb_ptr) { - _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count); - if (((scsiq->q_status & QS_READY) != 0) - && ((scsiq->q_status & QS_ABORTED) == 0) - && ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)) { - scsiq->q_status |= QS_ABORTED; - scsiq->d3.done_stat = QD_ABORTED_BY_HOST; - AscWriteLramDWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR), - 0L); - AscWriteLramByte(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), - scsiq->q_status); - (*asc_isr_callback) (asc_dvc, scsiq); - return (1); - } - } - } - DvcLeaveCritical(last_int_level); - return (0); -} - -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -STATIC int -AscRiscHaltedAbortTIX( - ASC_DVC_VAR *asc_dvc, - uchar target_ix -) -{ - PortAddr iop_base; - ushort q_addr; - uchar q_no; - ASC_QDONE_INFO scsiq_buf; - ASC_QDONE_INFO *scsiq; - ASC_ISR_CALLBACK asc_isr_callback; - int last_int_level; - - iop_base = asc_dvc->iop_base; - asc_isr_callback = asc_dvc->isr_callback; - last_int_level = DvcEnterCritical(); - scsiq = (ASC_QDONE_INFO *) & scsiq_buf; - for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng; - q_no++) { - q_addr = ASC_QNO_TO_QADDR(q_no); - _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count); - if (((scsiq->q_status & QS_READY) != 0) && - ((scsiq->q_status & QS_ABORTED) == 0) && - ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)) { - if (scsiq->d2.target_ix == target_ix) { - scsiq->q_status |= QS_ABORTED; - scsiq->d3.done_stat = QD_ABORTED_BY_HOST; - AscWriteLramDWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR), - 0L); - AscWriteLramByte(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), - scsiq->q_status); - (*asc_isr_callback) (asc_dvc, scsiq); - } - } - } - DvcLeaveCritical(last_int_level); - return (1); -} -#endif /* version >= v1.3.89 */ - -STATIC int AscHostReqRiscHalt( PortAddr iop_base ) @@ -13237,119 +11959,6 @@ return (0); } -STATIC int -AscStartQueueExe( - PortAddr iop_base -) -{ - if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0); - } - return (1); -} - -STATIC int -AscCleanUpBusyQueue( - PortAddr iop_base -) -{ - int count; - uchar stop_code; - - count = 0; - if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, - ASC_STOP_CLEAN_UP_BUSY_Q); - do { - stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B); - if ((stop_code & ASC_STOP_CLEAN_UP_BUSY_Q) == 0) - break; - DvcSleepMilliSecond(100); - } while (count++ < 20); - } - return (1); -} - -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -STATIC int -AscCleanUpDiscQueue( - PortAddr iop_base -) -{ - int count; - uchar stop_code; - - count = 0; - if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, - ASC_STOP_CLEAN_UP_DISC_Q); - do { - stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B); - if ((stop_code & ASC_STOP_CLEAN_UP_DISC_Q) == 0) - break; - DvcSleepMilliSecond(100); - } while (count++ < 20); - } - return (1); -} -#endif /* version >= v1.3.89 */ - -STATIC int -AscWaitTixISRDone( - ASC_DVC_VAR *asc_dvc, - uchar target_ix -) -{ - uchar cur_req; - uchar tid_no; - int i = 0; - - tid_no = ASC_TIX_TO_TID(target_ix); - while (i++ < 10) { - if ((cur_req = asc_dvc->cur_dvc_qng[tid_no]) == 0) { - break; - } - DvcSleepMilliSecond(1000L); - if (asc_dvc->cur_dvc_qng[tid_no] == cur_req) { - break; - } - } - return (1); -} - -STATIC int -AscWaitISRDone( - ASC_DVC_VAR *asc_dvc -) -{ - int tid; - - for (tid = 0; tid <= ASC_MAX_TID; tid++) { - AscWaitTixISRDone(asc_dvc, ASC_TID_TO_TIX(tid)); - } - return (1); -} - -STATIC ASC_PADDR -AscGetOnePhyAddr( - ASC_DVC_VAR *asc_dvc, - uchar * buf_addr, - ASC_DCNT buf_size -) -{ - ASC_MIN_SG_HEAD sg_head; - - sg_head.entry_cnt = ASC_MIN_SG_LIST; - if (DvcGetSGList(asc_dvc, (uchar *) buf_addr, - buf_size, (ASC_SG_HEAD *) &sg_head) != buf_size) { - return (0L); - } - if (sg_head.entry_cnt > 1) { - return (0L); - } - return ((ASC_PADDR) sg_head.sg_list[0].addr); -} - STATIC void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec) { @@ -13362,6 +11971,7 @@ udelay((nano_sec + 999)/1000); } +#ifdef CONFIG_ISA ASC_INITFUNC( STATIC ASC_DCNT, AscGetEisaProductID( @@ -13420,6 +12030,7 @@ } return (0); } +#endif /* CONFIG_ISA */ STATIC int AscStartChip( @@ -13593,6 +12204,7 @@ return (ASC_MAX_PCI_DMA_COUNT); } +#ifdef CONFIG_ISA ASC_INITFUNC( STATIC ushort, AscGetIsaDmaChannel( @@ -13664,6 +12276,7 @@ AscSetBank(iop_base, 0); return (speed_value); } +#endif /* CONFIG_ISA */ ASC_INITFUNC( STATIC ushort, @@ -13841,19 +12454,19 @@ asc_dvc->cfg->chip_scsi_id) { asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID; } +#ifdef CONFIG_ISA if (asc_dvc->bus_type & ASC_IS_ISA) { AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel); AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed); } +#endif /* CONFIG_ISA */ return (warn_code); } -ASC_INITFUNC( -STATIC ushort, +STATIC ushort AscInitAsc1000Driver( ASC_DVC_VAR *asc_dvc ) -) { ushort warn_code; PortAddr iop_base; @@ -13877,7 +12490,9 @@ warn_code |= AscInitLram(asc_dvc); if (asc_dvc->err_code != 0) return (UW_ERR); - if (AscLoadMicroCode(iop_base, 0, (ushort *) _asc_mcode_buf, + ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n", + (ulong) _asc_mcode_chksum); + if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf, _asc_mcode_size) != _asc_mcode_chksum) { asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; return (warn_code); @@ -13912,7 +12527,7 @@ asc_dvc->bug_fix_cntl = 0; asc_dvc->pci_fix_asyn_xfer = 0; asc_dvc->pci_fix_asyn_xfer_always = 0; - asc_dvc->init_state = 0; + /* asc_dvc->init_state initalized in AscInitGetConfig(). */ asc_dvc->sdtr_done = 0; asc_dvc->cur_total_qng = 0; asc_dvc->is_in_int = 0; @@ -13988,9 +12603,11 @@ AscSetChipIFC(iop_base, IFC_INIT_DEFAULT); asc_dvc->bus_type = ASC_IS_ISAPNP; } +#ifdef CONFIG_ISA if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) { asc_dvc->cfg->isa_dma_channel = (uchar) AscGetIsaDmaChannel(iop_base); } +#endif /* CONFIG_ISA */ for (i = 0; i <= ASC_MAX_TID; i++) { asc_dvc->cur_dvc_qng[i] = 0; asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG; @@ -14037,7 +12654,7 @@ asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR; return (warn_code); } - eep_config = (ASCEEP_CONFIG *) & eep_config_buf; + eep_config = (ASCEEP_CONFIG *) &eep_config_buf; cfg_msw = AscGetChipCfgMsw(iop_base); cfg_lsw = AscGetChipCfgLsw(iop_base); if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) { @@ -14046,6 +12663,7 @@ AscSetChipCfgMsw(iop_base, cfg_msw); } chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type); + ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum); if (chksum == 0) { chksum = 0xaa55; } @@ -14064,10 +12682,14 @@ } eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK; eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON; + ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n", + eep_config->chksum); if (chksum != eep_config->chksum) { if (AscGetChipVersion(iop_base, asc_dvc->bus_type) == ASC_CHIP_VER_PCI_ULTRA_3050 ) { + ASC_DBG(1, +"AscInitFromEEP: chksum error ignored; EEPROM-less board\n"); eep_config->init_sdtr = 0xFF; eep_config->disc_enable = 0xFF; eep_config->start_motor = 0xFF; @@ -14075,7 +12697,7 @@ eep_config->max_total_qng = 0xF0; eep_config->max_tag_qng = 0x20; eep_config->cntl = 0xBFFF; - eep_config->chip_scsi_id = 7; + ASC_EEP_SET_CHIP_ID(eep_config, 7); eep_config->no_scam = 0; eep_config->adapter_info[0] = 0; eep_config->adapter_info[1] = 0; @@ -14085,6 +12707,8 @@ /* Indicate EEPROM-less board. */ eep_config->adapter_info[5] = 0xBB; } else { + ASC_PRINT( +"AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n"); write_eep = 1; warn_code |= ASC_WARN_EEPROM_CHKSUM; } @@ -14092,7 +12716,7 @@ asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr; asc_dvc->cfg->disc_enable = eep_config->disc_enable; asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng; - asc_dvc->cfg->isa_dma_speed = eep_config->isa_dma_speed; + asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config); asc_dvc->start_motor = eep_config->start_motor; asc_dvc->dvc_cntl = eep_config->cntl; asc_dvc->no_scam = eep_config->no_scam; @@ -14136,8 +12760,8 @@ if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) { asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type); } - eep_config->chip_scsi_id &= ASC_MAX_TID; - asc_dvc->cfg->chip_scsi_id = eep_config->chip_scsi_id; + ASC_EEP_SET_CHIP_ID(eep_config, ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID); + asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config); if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) && !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) { asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX; @@ -14152,22 +12776,27 @@ } eep_config->cfg_msw = AscGetChipCfgMsw(iop_base); if (write_eep) { - (void) AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type); + if ((i = AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type)) != + 0) { + ASC_PRINT1( +"AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n", i); + } else { + ASC_PRINT("AscInitFromEEP: Succesfully re-wrote EEPROM."); + } } return (warn_code); } -ASC_INITFUNC( -STATIC ushort, +STATIC ushort AscInitMicroCodeVar( ASC_DVC_VAR *asc_dvc ) -) { int i; ushort warn_code; PortAddr iop_base; ASC_PADDR phy_addr; + ASC_DCNT phy_size; iop_base = asc_dvc->iop_base; warn_code = 0; @@ -14176,26 +12805,27 @@ asc_dvc->cfg->sdtr_period_offset[i] ); } + AscInitQLinkVar(asc_dvc); AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B, asc_dvc->cfg->disc_enable); AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B, ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id)); - if ((phy_addr = AscGetOnePhyAddr(asc_dvc, - (uchar *) asc_dvc->cfg->overrun_buf, - ASC_OVERRUN_BSIZE)) == 0L) { - asc_dvc->err_code |= ASC_IERR_GET_PHY_ADDR; - } else { - /* Align on an 8 byte boundary. */ - phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7); - AscWriteLramDWord(iop_base, ASCV_OVERRUN_PADDR_D, phy_addr); - AscWriteLramDWord(iop_base, ASCV_OVERRUN_BSIZE_D, - ASC_OVERRUN_BSIZE - 8); - } - asc_dvc->cfg->mcode_date = AscReadLramWord(iop_base, - (ushort) ASCV_MC_DATE_W); - asc_dvc->cfg->mcode_version = AscReadLramWord(iop_base, - (ushort) ASCV_MC_VER_W); + + /* Align overrun buffer on an 8 byte boundary. */ + phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf); + phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7); + AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D, + (uchar *) &phy_addr, 1); + phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8); + AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D, + (uchar *) &phy_size, 1); + + asc_dvc->cfg->mcode_date = + AscReadLramWord(iop_base, (ushort) ASCV_MC_DATE_W); + asc_dvc->cfg->mcode_version = + AscReadLramWord(iop_base, (ushort) ASCV_MC_VER_W); + AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR; @@ -14205,6 +12835,7 @@ asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP; return (warn_code); } + return (warn_code); } @@ -14368,16 +12999,15 @@ ushort *wbuf; int cfg_beg; int cfg_end; + int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2; int s_addr; - int isa_pnp_wsize; wbuf = (ushort *) cfg_buf; sum = 0; - isa_pnp_wsize = 0; - for (s_addr = 0; s_addr < (2 + isa_pnp_wsize); s_addr++, wbuf++) { - wval = AscReadEEPWord(iop_base, (uchar) s_addr); - sum += wval; - *wbuf = wval; + /* Read two config words; Byte-swapping done by AscReadEEPWord(). */ + for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { + *wbuf = AscReadEEPWord(iop_base, (uchar) s_addr); + sum += *wbuf; } if (bus_type & ASC_IS_VL) { cfg_beg = ASC_EEP_DVC_CFG_BEG_VL; @@ -14386,12 +13016,24 @@ cfg_beg = ASC_EEP_DVC_CFG_BEG; cfg_end = ASC_EEP_MAX_DVC_ADDR; } - for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); - s_addr++, wbuf++) { - wval = AscReadEEPWord(iop_base, (uchar) s_addr); - sum += wval; - *wbuf = wval; + for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { + wval = AscReadEEPWord( iop_base, ( uchar )s_addr ) ; + if (s_addr <= uchar_end_in_config) { + /* + * Swap all char fields - must unswap bytes already swapped + * by AscReadEEPWord(). + */ + *wbuf = le16_to_cpu(wval); + } else { + /* Don't swap word field at the end - cntl field. */ + *wbuf = wval; + } + sum += wval; /* Checksum treats all EEPROM data as words. */ } + /* + * Read the checksum word which will be compared against 'sum' + * by the caller. Word field already swapped. + */ *wbuf = AscReadEEPWord(iop_base, (uchar) s_addr); return (sum); } @@ -14405,15 +13047,19 @@ ) { int n_error; - ushort *wbuf; + ushort *wbuf; + ushort word; ushort sum; int s_addr; int cfg_beg; int cfg_end; + int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2; + wbuf = (ushort *) cfg_buf; n_error = 0; sum = 0; + /* Write two config words; AscWriteEEPWord() will swap bytes. */ for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { sum += *wbuf; if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) { @@ -14427,29 +13073,66 @@ cfg_beg = ASC_EEP_DVC_CFG_BEG; cfg_end = ASC_EEP_MAX_DVC_ADDR; } - for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); - s_addr++, wbuf++) { - sum += *wbuf; - if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) { - n_error++; + for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { + if (s_addr <= uchar_end_in_config) { + /* + * This is a char field. Swap char fields before they are + * swapped again by AscWriteEEPWord(). + */ + word = cpu_to_le16(*wbuf); + if (word != AscWriteEEPWord( iop_base, (uchar) s_addr, word)) { + n_error++; + } + } else { + /* Don't swap word field at the end - cntl field. */ + if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) { + n_error++; + } } + sum += *wbuf; /* Checksum calculated from word values. */ } + /* Write checksum word. It will be swapped by AscWriteEEPWord(). */ *wbuf = sum; if (sum != AscWriteEEPWord(iop_base, (uchar) s_addr, sum)) { n_error++; } + + /* Read EEPROM back again. */ wbuf = (ushort *) cfg_buf; + /* + * Read two config words; Byte-swapping done by AscReadEEPWord(). + */ for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) { n_error++; } } - for (s_addr = cfg_beg; s_addr <= cfg_end; - s_addr++, wbuf++) { - if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) { + if (bus_type & ASC_IS_VL) { + cfg_beg = ASC_EEP_DVC_CFG_BEG_VL; + cfg_end = ASC_EEP_MAX_DVC_ADDR_VL; + } else { + cfg_beg = ASC_EEP_DVC_CFG_BEG; + cfg_end = ASC_EEP_MAX_DVC_ADDR; + } + for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { + if (s_addr <= uchar_end_in_config) { + /* + * Swap all char fields. Must unswap bytes already swapped + * by AscReadEEPWord(). + */ + word = le16_to_cpu(AscReadEEPWord(iop_base, (uchar) s_addr)); + } else { + /* Don't swap word field at the end - cntl field. */ + word = AscReadEEPWord(iop_base, (uchar) s_addr); + } + if (*wbuf != word) { n_error++; } } + /* Read checksum; Byte swapping not needed. */ + if (AscReadEEPWord(iop_base, (uchar) s_addr) != sum) { + n_error++; + } return (n_error); } @@ -14486,7 +13169,7 @@ uchar dvc_type; ASC_SCSI_BIT_ID_TYPE tid_bits; - dvc_type = inq->byte0.peri_dvc_type; + dvc_type = ASC_INQ_DVC_TYPE(inq); tid_bits = ASC_TIX_TO_TARGET_ID(tid_no); if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) @@ -14546,11 +13229,12 @@ asc_dvc->cfg->can_tagged_qng &= ~tid_bit; asc_dvc->use_tagged_qng &= ~tid_bit; - if (inq->byte3.rsp_data_fmt >= 2 || inq->byte2.ansi_apr_ver >= 2) { - if ((asc_dvc->cfg->sdtr_enable & tid_bit) && inq->byte7.Sync) { + if (ASC_INQ_RESPONSE_FMT(inq) >= 2 || ASC_INQ_ANSI_VER(inq) >= 2) { + if ((asc_dvc->cfg->sdtr_enable & tid_bit) && ASC_INQ_SYNC(inq)) { asc_dvc->init_sdtr |= tid_bit; } - if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) && inq->byte7.CmdQue) { + if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) && + ASC_INQ_CMD_QUEUE(inq)) { if (AscTagQueuingSafe(inq)) { asc_dvc->use_tagged_qng |= tid_bit; asc_dvc->cfg->can_tagged_qng |= tid_bit; @@ -14615,7 +13299,6 @@ } return (byte_data); } - STATIC ushort AscReadLramWord( PortAddr iop_base, @@ -14629,6 +13312,7 @@ return (word_data); } +#if CC_VERY_LONG_SG_LIST STATIC ASC_DCNT AscReadLramDWord( PortAddr iop_base, @@ -14644,6 +13328,7 @@ dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low; return (dword_data); } +#endif /* CC_VERY_LONG_SG_LIST */ STATIC void AscWriteLramWord( @@ -14658,30 +13343,13 @@ } STATIC void -AscWriteLramDWord( - PortAddr iop_base, - ushort addr, - ASC_DCNT dword_val +AscWriteLramByte( + PortAddr iop_base, + ushort addr, + uchar byte_val ) { - ushort word_val; - - AscSetChipLramAddr(iop_base, addr); - word_val = (ushort) dword_val; - AscSetChipLramData(iop_base, word_val); - word_val = (ushort) (dword_val >> 16); - AscSetChipLramData(iop_base, word_val); - return; -} - -STATIC void -AscWriteLramByte( - PortAddr iop_base, - ushort addr, - uchar byte_val -) -{ - ushort word_data; + ushort word_data; if (isodd_word(addr)) { addr--; @@ -14697,42 +13365,87 @@ return; } +/* + * Copy 2 bytes to LRAM. + * + * The source data is assumed to be in little-endian order in memory + * and is maintained in little-endian order when written to LRAM. + */ STATIC void -AscMemWordCopyToLram( +AscMemWordCopyPtrToLram( PortAddr iop_base, ushort s_addr, - ushort * s_buffer, + uchar *s_buffer, int words ) { + int i; + AscSetChipLramAddr(iop_base, s_addr); - DvcOutPortWords(iop_base + IOP_RAM_DATA, s_buffer, words); + for (i = 0; i < 2 * words; i += 2) { + /* + * On a little-endian system the second argument below + * produces a little-endian ushort which is written to + * LRAM in little-endian order. On a big-endian system + * the second argument produces a big-endian ushort which + * is "transparently" byte-swapped by outpw() and written + * in little-endian order to LRAM. + */ + outpw(iop_base + IOP_RAM_DATA, + ((ushort) s_buffer[i + 1] << 8) | s_buffer[i]); + } return; } +/* + * Copy 4 bytes to LRAM. + * + * The source data is assumed to be in little-endian order in memory + * and is maintained in little-endian order when writen to LRAM. + */ STATIC void -AscMemDWordCopyToLram( +AscMemDWordCopyPtrToLram( PortAddr iop_base, ushort s_addr, - ASC_DCNT *s_buffer, + uchar *s_buffer, int dwords ) { + int i; + AscSetChipLramAddr(iop_base, s_addr); - DvcOutPortDWords(iop_base + IOP_RAM_DATA, s_buffer, dwords); + for (i = 0; i < 4 * dwords; i += 4) { + outpw(iop_base + IOP_RAM_DATA, + ((ushort) s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */ + outpw(iop_base + IOP_RAM_DATA, + ((ushort) s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */ + } return; } +/* + * Copy 2 bytes from LRAM. + * + * The source data is assumed to be in little-endian order in LRAM + * and is maintained in little-endian order when written to memory. + */ STATIC void -AscMemWordCopyFromLram( +AscMemWordCopyPtrFromLram( PortAddr iop_base, ushort s_addr, - ushort * d_buffer, + uchar *d_buffer, int words ) { + int i; + ushort word; + AscSetChipLramAddr(iop_base, s_addr); - DvcInPortWords(iop_base + IOP_RAM_DATA, d_buffer, words); + for (i = 0; i < 2 * words; i += 2) { + word = inpw(iop_base + IOP_RAM_DATA); + d_buffer[i] = word & 0xff; + d_buffer[i + 1] = (word >> 8) & 0xff; + } return; } @@ -14776,676 +13489,1078 @@ */ /* a_mcode.h */ + +/* Microcode buffer is kept after initialization for error recovery. */ STATIC unsigned char _adv_asc3550_buf[] = { - 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x00, 0xfc, 0x48, 0xe4, 0x01, 0x00, 0x18, 0xe4, - 0x00, 0xf6, 0x01, 0xf6, 0x18, 0x80, 0x48, 0x19, 0x02, 0x00, 0xff, 0xff, 0x03, 0xf6, 0x00, 0xfa, - 0xff, 0x00, 0x82, 0xe7, 0x01, 0xfa, 0x9e, 0xe7, 0x09, 0xe7, 0x3a, 0x0e, 0x00, 0xea, 0x01, 0xe6, - 0x55, 0xf0, 0x03, 0x00, 0x08, 0x00, 0x18, 0xf4, 0x3e, 0x01, 0x3e, 0x57, 0x04, 0x00, 0x85, 0xf0, - 0x00, 0xe6, 0x00, 0xec, 0x1e, 0xf0, 0x32, 0xf0, 0x34, 0x19, 0x86, 0xf0, 0xd0, 0x01, 0xd5, 0xf0, - 0xde, 0x0c, 0x98, 0x57, 0xbc, 0x00, 0x0c, 0x1c, 0x0e, 0x13, 0x38, 0x54, 0xb1, 0xf0, 0xb4, 0x00, - 0x01, 0xfc, 0x03, 0xfc, 0xd8, 0x0c, 0x00, 0x57, 0x01, 0xf0, 0x02, 0x13, 0x03, 0xe6, 0x10, 0x00, - 0x18, 0x40, 0x3e, 0x1c, 0x6c, 0x01, 0x6e, 0x01, 0xbd, 0x00, 0xe0, 0x00, 0x02, 0x48, 0x02, 0x80, - 0x08, 0x12, 0x30, 0xe4, 0x3c, 0x00, 0x4e, 0x01, 0x64, 0x12, 0x80, 0x00, 0x9c, 0x15, 0xbb, 0x00, - 0x00, 0x4e, 0x01, 0x01, 0x01, 0xea, 0x04, 0x12, 0x9e, 0x0f, 0xb6, 0x00, 0xb9, 0x54, 0xe2, 0x0f, - 0x00, 0x80, 0x06, 0xf7, 0x10, 0x44, 0x24, 0x01, 0x28, 0x01, 0x32, 0x00, 0x3c, 0x01, 0x3c, 0x56, - 0x3e, 0x00, 0x4b, 0xe4, 0x4c, 0x1c, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, - 0x76, 0x01, 0x78, 0x01, 0xe2, 0x0c, 0x00, 0x01, 0x02, 0xee, 0x02, 0xfc, 0x03, 0x58, 0x03, 0xf7, - 0x04, 0x80, 0x05, 0xfc, 0x08, 0x44, 0x09, 0xf0, 0x0f, 0x00, 0x1b, 0x80, 0x20, 0x01, 0x38, 0x1c, - 0x40, 0x00, 0x40, 0x15, 0x4b, 0xf4, 0x4e, 0x1c, 0x5b, 0xf0, 0x5d, 0xf0, 0xaa, 0x00, 0xbb, 0x55, - 0xbe, 0x00, 0xc0, 0x00, 0xe0, 0x08, 0xe0, 0x14, 0xec, 0x0f, 0x00, 0x4c, 0x00, 0xdc, 0x02, 0x4a, - 0x05, 0x00, 0x05, 0xf0, 0x05, 0xf8, 0x06, 0x13, 0x08, 0x13, 0x0c, 0x00, 0x0e, 0x47, 0x0e, 0xf7, - 0x19, 0x00, 0x20, 0x00, 0x2a, 0x01, 0x30, 0x0e, 0x32, 0x1c, 0x36, 0x00, 0x45, 0x5a, 0x59, 0xf0, - 0x62, 0x0a, 0x69, 0x08, 0x72, 0x0b, 0x83, 0x59, 0xb8, 0xf0, 0xbd, 0x56, 0xcc, 0x12, 0xec, 0x17, - 0xee, 0x0f, 0xf0, 0x00, 0xf8, 0x17, 0x01, 0x48, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0x10, 0x04, 0xea, - 0x04, 0xf6, 0x04, 0xfc, 0x05, 0x80, 0x05, 0xe6, 0x06, 0x00, 0x06, 0x12, 0x0a, 0x10, 0x0b, 0xf0, - 0x0c, 0x10, 0x0c, 0xf0, 0x12, 0x10, 0x26, 0x0e, 0x30, 0x1c, 0x33, 0x00, 0x34, 0x00, 0x38, 0x44, - 0x40, 0x5c, 0x4a, 0xe4, 0x62, 0x1a, 0x68, 0x08, 0x68, 0x54, 0x83, 0x55, 0x83, 0x5a, 0x8c, 0x14, - 0x8e, 0x0a, 0x90, 0x14, 0x91, 0x44, 0xa4, 0x00, 0xb0, 0x57, 0xb5, 0x00, 0xba, 0x00, 0xce, 0x45, - 0xd0, 0x00, 0xd8, 0x16, 0xe1, 0x00, 0xe7, 0x00, 0x00, 0x54, 0x01, 0x58, 0x02, 0x10, 0x02, 0xe6, - 0x03, 0xa1, 0x04, 0x13, 0x06, 0x83, 0x06, 0xf0, 0x07, 0x00, 0x0a, 0x00, 0x0a, 0x12, 0x0a, 0xf0, - 0x0c, 0x04, 0x0c, 0x12, 0x0c, 0x90, 0x10, 0x10, 0x10, 0x13, 0x12, 0x1c, 0x17, 0x00, 0x19, 0xe4, - 0x1a, 0x10, 0x1c, 0x00, 0x1c, 0x12, 0x1d, 0xf7, 0x1e, 0x13, 0x20, 0x1c, 0x20, 0xe7, 0x22, 0x01, - 0x26, 0x01, 0x2a, 0x12, 0x30, 0xe7, 0x34, 0x1c, 0x36, 0x1c, 0x38, 0x12, 0x41, 0x58, 0x43, 0x48, - 0x44, 0x55, 0x46, 0x1c, 0x4c, 0x0e, 0x4e, 0xe4, 0x52, 0x14, 0x5c, 0xf0, 0x72, 0x02, 0x74, 0x03, - 0x77, 0x57, 0x89, 0x48, 0x8e, 0x90, 0x99, 0x00, 0x9b, 0x00, 0x9c, 0x32, 0x9e, 0x00, 0xa8, 0x00, - 0xb9, 0x00, 0xba, 0x06, 0xbc, 0x12, 0xbf, 0x57, 0xc0, 0x01, 0xfe, 0x9c, 0xf0, 0x26, 0x02, 0xfe, - 0x00, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xfe, 0xc2, 0x01, 0xfe, 0x56, 0x19, 0x00, 0xfc, 0xfe, 0x80, - 0x01, 0xff, 0x03, 0x00, 0x00, 0xfe, 0x6a, 0x13, 0xfe, 0x05, 0x05, 0xff, 0x40, 0x00, 0x00, 0x0d, - 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x10, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, - 0xff, 0x10, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, - 0x00, 0x00, 0xfe, 0x04, 0xf7, 0xfc, 0x2b, 0x51, 0x0c, 0x01, 0xfe, 0xea, 0x0e, 0xfe, 0x04, 0xf7, - 0xfc, 0x51, 0x0c, 0x1d, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x20, 0xf0, 0xd0, 0x04, - 0x56, 0x4b, 0x02, 0xfe, 0x1c, 0x0d, 0x01, 0xfe, 0x7c, 0x0d, 0xfe, 0xe9, 0x12, 0x02, 0xfe, 0x04, - 0x03, 0xfe, 0x28, 0x1c, 0x04, 0xfe, 0xa6, 0x00, 0xfe, 0xdd, 0x12, 0x4e, 0x12, 0xfe, 0xa6, 0x00, - 0xc5, 0xfe, 0x48, 0xf0, 0xfe, 0x7c, 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0x96, 0x02, 0xfe, 0x4a, 0xf0, - 0xfe, 0xb4, 0x02, 0xfe, 0x46, 0xf0, 0xfe, 0x46, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x4c, 0x02, 0xfe, - 0x43, 0xf0, 0xfe, 0x3a, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x3e, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x42, - 0x02, 0x09, 0x0c, 0x9e, 0x09, 0x06, 0x12, 0xbb, 0x02, 0x26, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, - 0xfe, 0x02, 0x1c, 0xfe, 0xed, 0x10, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x4c, 0x17, - 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xf7, 0x0e, 0x78, 0x01, 0xab, 0x02, 0x26, 0x17, 0x55, 0x4a, - 0xbd, 0x01, 0xfe, 0x60, 0x0f, 0x0e, 0x78, 0x01, 0x8b, 0xfe, 0xbd, 0x10, 0x0e, 0x78, 0x01, 0x8b, - 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, 0x58, 0x1c, 0x09, 0x06, 0x12, 0xbb, 0x2b, 0x22, 0x26, - 0xfe, 0x3d, 0xf0, 0xfe, 0xf8, 0x01, 0x27, 0xfe, 0x8a, 0x02, 0xfe, 0x5a, 0x1c, 0xd5, 0xfe, 0x14, - 0x1c, 0x17, 0xfe, 0x30, 0x00, 0x4a, 0xbd, 0x01, 0xfe, 0x50, 0x0f, 0x09, 0x06, 0x12, 0xbb, 0x02, - 0xfe, 0xc2, 0x01, 0x21, 0x2a, 0x05, 0x10, 0x35, 0xfe, 0x69, 0x10, 0x09, 0x06, 0x12, 0xbb, 0xfe, - 0x04, 0xec, 0x2a, 0x08, 0x2a, 0x09, 0x3c, 0x1d, 0x01, 0x46, 0x7f, 0xfe, 0x05, 0xf6, 0xf7, 0x01, - 0xfe, 0x76, 0x16, 0x0a, 0x41, 0x89, 0x38, 0x11, 0x47, 0x1d, 0xca, 0x08, 0x1c, 0x09, 0x43, 0x01, - 0x71, 0x02, 0x26, 0x0e, 0x3d, 0x01, 0x15, 0x05, 0x10, 0x2c, 0x08, 0x1c, 0x09, 0x43, 0x01, 0x7b, - 0xfe, 0x28, 0x10, 0x0e, 0xc0, 0x01, 0x15, 0xe6, 0x0e, 0x79, 0x01, 0x15, 0xfe, 0x49, 0x54, 0x74, - 0xfe, 0x12, 0x03, 0x08, 0x1c, 0x09, 0x43, 0x01, 0x71, 0x02, 0x26, 0x2b, 0x7f, 0xfe, 0x02, 0xe8, - 0x2f, 0xfb, 0xfe, 0x9e, 0x43, 0xf0, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xd0, 0xfe, 0x40, 0x1c, - 0x22, 0xef, 0xfe, 0x26, 0xf0, 0xfe, 0x70, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x5e, 0x03, 0xfe, 0x11, - 0xf0, 0xd0, 0xfe, 0x0e, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x7e, 0x03, 0xe9, 0x13, 0xfe, 0x11, 0x00, - 0x02, 0x62, 0x2b, 0xfe, 0x48, 0x1c, 0xe9, 0x22, 0xef, 0x34, 0xef, 0xfe, 0x82, 0xf0, 0xfe, 0x84, - 0x03, 0x2d, 0x21, 0xbe, 0x6a, 0x16, 0xbe, 0x0e, 0x79, 0x01, 0x15, 0x6a, 0x7d, 0x08, 0x1c, 0x09, - 0x43, 0x01, 0x46, 0x11, 0x3d, 0x08, 0x3d, 0x09, 0x99, 0x01, 0x71, 0xf5, 0x11, 0xfe, 0xe4, 0x00, - 0x2e, 0xfe, 0xca, 0x03, 0x22, 0x32, 0x1f, 0xfe, 0xda, 0x03, 0x01, 0x4c, 0xcb, 0xfe, 0xea, 0x03, - 0x6b, 0x92, 0xcf, 0xfe, 0xaa, 0x06, 0x02, 0x28, 0x04, 0x78, 0x29, 0x18, 0xfe, 0x1c, 0x05, 0x17, - 0x85, 0x01, 0x44, 0x01, 0x97, 0x01, 0x9a, 0x34, 0xfe, 0x5c, 0x02, 0x02, 0xee, 0xe9, 0x2b, 0x51, - 0x19, 0xfe, 0x67, 0x1b, 0xfb, 0xf0, 0xfe, 0x48, 0x1c, 0x8c, 0x01, 0xfa, 0xac, 0xfe, 0x96, 0xf0, - 0xfe, 0x24, 0x04, 0x2e, 0xfe, 0x28, 0x04, 0x34, 0x26, 0x0e, 0x3d, 0x01, 0x15, 0x05, 0x10, 0x18, - 0xfe, 0x08, 0x05, 0x3e, 0x90, 0x9f, 0x2f, 0x82, 0x6e, 0x22, 0x32, 0x1f, 0x28, 0x04, 0x78, 0x29, - 0xfe, 0x10, 0x12, 0x17, 0x85, 0x01, 0x44, 0x34, 0xfe, 0x5c, 0x02, 0x02, 0xee, 0x31, 0xfe, 0xa0, - 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x5e, 0x12, 0x0a, 0x07, 0x06, 0xfe, 0x56, 0x12, 0x23, 0x24, 0x91, - 0x01, 0x0b, 0x82, 0x6e, 0x1f, 0xfe, 0xd8, 0x04, 0x23, 0x24, 0x91, 0x01, 0x0b, 0x1f, 0x28, 0x23, - 0x24, 0xb3, 0xfe, 0x4c, 0x44, 0xfe, 0x32, 0x12, 0x57, 0xfe, 0x44, 0x48, 0x08, 0xd6, 0xfe, 0x4c, - 0x54, 0x74, 0xfe, 0x08, 0x05, 0x7f, 0x9f, 0x2f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x48, - 0x13, 0x3f, 0x05, 0xfe, 0xcc, 0x00, 0xfe, 0x40, 0x13, 0x0a, 0x07, 0x06, 0xe5, 0xfe, 0x06, 0x10, - 0x23, 0x24, 0xb3, 0x0a, 0x07, 0x37, 0xda, 0x17, 0xa4, 0x0a, 0x07, 0x06, 0x4b, 0x17, 0xfe, 0x0d, - 0x00, 0x01, 0x44, 0x34, 0xfe, 0xc0, 0x0c, 0x02, 0x28, 0x39, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, - 0x90, 0xb0, 0x03, 0x17, 0xa4, 0x01, 0x44, 0x34, 0x26, 0x22, 0x26, 0x02, 0xfe, 0x10, 0x05, 0xfe, - 0x42, 0x5b, 0x51, 0x19, 0xfe, 0x46, 0x59, 0xfb, 0xf0, 0x17, 0x45, 0xfe, 0x07, 0x80, 0xfe, 0x31, - 0x44, 0x0a, 0x07, 0x0c, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x05, 0x19, 0xfe, 0x70, 0x12, 0x6d, - 0x07, 0x06, 0xfe, 0x60, 0x13, 0x04, 0xfe, 0xa2, 0x00, 0x29, 0x18, 0xfe, 0xa8, 0x05, 0xfe, 0x31, - 0xe4, 0x70, 0x6d, 0x07, 0x0c, 0xfe, 0x4a, 0x13, 0x04, 0xfe, 0xa0, 0x00, 0x29, 0xfe, 0x42, 0x12, - 0x5a, 0x2e, 0xfe, 0x68, 0x05, 0x22, 0x32, 0xf1, 0x01, 0x0b, 0x25, 0xfe, 0xc0, 0x05, 0x11, 0xfe, - 0xe3, 0x00, 0x2d, 0x6d, 0xfe, 0x4a, 0xf0, 0xfe, 0x92, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0x8c, 0x05, - 0xa8, 0x20, 0xfe, 0x21, 0x00, 0xa6, 0x20, 0xfe, 0x22, 0x00, 0x9e, 0x20, 0x89, 0xfe, 0x09, 0x48, - 0x01, 0x0b, 0x25, 0xfe, 0xc0, 0x05, 0xfe, 0xe2, 0x08, 0x6d, 0x07, 0xd9, 0x4b, 0x01, 0x96, 0x20, - 0x06, 0x16, 0xe0, 0x4a, 0xfe, 0x27, 0x01, 0x0a, 0x07, 0x37, 0xe1, 0x4e, 0x01, 0xb9, 0x17, 0xa4, - 0x0a, 0x07, 0x06, 0x4b, 0x17, 0xfe, 0x0d, 0x00, 0x01, 0x44, 0x01, 0x97, 0x01, 0x9a, 0x34, 0xfe, - 0xc0, 0x0c, 0x02, 0x28, 0x04, 0xfe, 0x9c, 0x00, 0x29, 0xfe, 0x3e, 0x12, 0x04, 0x53, 0x29, 0xfe, - 0x36, 0x13, 0x4e, 0x01, 0xb9, 0x25, 0xfe, 0x38, 0x06, 0x0e, 0x06, 0x6d, 0x07, 0x1a, 0xfe, 0x02, - 0x12, 0x77, 0x01, 0xfe, 0x26, 0x14, 0x1f, 0xfe, 0x2e, 0x06, 0x11, 0xc2, 0x01, 0x4c, 0x11, 0xfe, - 0xe5, 0x00, 0x04, 0x53, 0xbc, 0x0f, 0x53, 0x04, 0xf6, 0x29, 0xfe, 0x62, 0x12, 0x04, 0x4d, 0x29, - 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x9e, 0x18, 0x01, 0xfe, 0xf0, 0x18, 0xe7, 0xa3, 0x1a, 0x08, 0x63, - 0xff, 0x02, 0x00, 0x57, 0x66, 0x7e, 0x1b, 0x50, 0xc9, 0xa3, 0x6c, 0x4e, 0x01, 0xb9, 0x25, 0xfe, - 0xa2, 0x06, 0x6d, 0x07, 0x1e, 0xa5, 0x95, 0x0e, 0x55, 0x01, 0xfe, 0x54, 0x14, 0x1f, 0xfe, 0x98, - 0x06, 0x11, 0xc2, 0x01, 0x4c, 0x11, 0xfe, 0xe5, 0x00, 0x04, 0x4d, 0xbc, 0x0f, 0x4d, 0x09, 0x06, - 0x01, 0xb9, 0xf5, 0x73, 0x8c, 0x01, 0xfa, 0xac, 0x11, 0xfe, 0xe2, 0x00, 0x2e, 0xf9, 0x22, 0x32, - 0xcf, 0xfe, 0xd6, 0x06, 0x81, 0xfe, 0x74, 0x07, 0xcb, 0xfe, 0x7c, 0x07, 0x6b, 0x92, 0x02, 0x28, - 0x0a, 0x07, 0x0c, 0xfe, 0x2e, 0x12, 0x14, 0x19, 0x01, 0x0b, 0x14, 0x00, 0x01, 0x0b, 0x14, 0x00, - 0x01, 0x0b, 0x14, 0x00, 0x01, 0x0b, 0xfe, 0x99, 0xa4, 0x01, 0x0b, 0x14, 0x00, 0x02, 0xfe, 0x4c, - 0x08, 0x68, 0x07, 0x1e, 0xe5, 0x0a, 0x07, 0x1e, 0xfe, 0x30, 0x13, 0x14, 0xfe, 0x1b, 0x00, 0x01, - 0x0b, 0x14, 0x00, 0x01, 0x0b, 0x14, 0x00, 0x01, 0x0b, 0x14, 0x00, 0x01, 0x0b, 0x14, 0x06, 0x01, - 0x0b, 0x14, 0x00, 0x02, 0xfe, 0x2a, 0x0b, 0x77, 0xfe, 0x9a, 0x81, 0x67, 0x89, 0xfe, 0x09, 0x6f, - 0xfe, 0x93, 0x45, 0x18, 0xfe, 0x84, 0x07, 0x2e, 0xfe, 0x5c, 0x07, 0x22, 0x32, 0xcf, 0xfe, 0x54, - 0x07, 0x6b, 0x92, 0x81, 0xfe, 0x74, 0x07, 0x02, 0x28, 0x01, 0x4c, 0x02, 0xf9, 0x14, 0x1a, 0x02, - 0xf9, 0xfe, 0x9c, 0xf7, 0xfe, 0xec, 0x07, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x75, 0xfe, 0xd2, - 0x07, 0x0f, 0x5d, 0x12, 0x5e, 0x0a, 0x41, 0x70, 0x38, 0x01, 0xfe, 0x34, 0x18, 0x05, 0x10, 0x83, - 0xfe, 0x83, 0xe7, 0x88, 0xa6, 0xfe, 0x03, 0x40, 0x0a, 0x41, 0x45, 0x38, 0x01, 0xc1, 0xaf, 0xfe, - 0x1f, 0x40, 0x16, 0x61, 0x01, 0xfe, 0xde, 0x12, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x34, - 0x51, 0xfe, 0xb6, 0x51, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0f, 0x5b, 0x12, 0x5c, 0xd2, 0xf2, - 0x0f, 0x3a, 0x12, 0x3b, 0xfe, 0x60, 0x10, 0x0a, 0x07, 0x70, 0xe1, 0xfe, 0x2c, 0x90, 0xfe, 0xae, - 0x90, 0x0f, 0x5d, 0x12, 0x5e, 0x0a, 0x07, 0x45, 0xc9, 0x01, 0xc1, 0xfe, 0x1f, 0x80, 0x16, 0x61, - 0xfe, 0x34, 0x90, 0xfe, 0xb6, 0x90, 0x0f, 0x5f, 0x12, 0x60, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, - 0x0f, 0x5b, 0x12, 0x5c, 0xa2, 0x07, 0x45, 0x2c, 0xd2, 0xf2, 0x0f, 0x3a, 0x12, 0x3b, 0xa8, 0xfe, - 0x28, 0x90, 0xfe, 0xaa, 0x90, 0x0f, 0x3a, 0x12, 0x3b, 0x0f, 0x42, 0x12, 0x58, 0x0a, 0x41, 0x1a, - 0x38, 0x2b, 0x08, 0x80, 0x2e, 0xfe, 0x62, 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x76, 0x08, 0x9b, 0x18, - 0x32, 0x2b, 0x52, 0xfe, 0xed, 0x10, 0xa7, 0xfe, 0x9a, 0x08, 0xa9, 0xfe, 0xb6, 0x08, 0x81, 0xfe, - 0x8e, 0x08, 0xcb, 0xfe, 0x94, 0x08, 0x6b, 0x92, 0x02, 0x28, 0x01, 0x4c, 0xfe, 0xc9, 0x10, 0x14, - 0x1a, 0xfe, 0xc9, 0x10, 0x68, 0x07, 0x06, 0xfe, 0x10, 0x12, 0x68, 0x07, 0x0c, 0x40, 0x0a, 0x07, - 0x0c, 0xfe, 0x7e, 0x12, 0xfe, 0x2e, 0x1c, 0xaa, 0x68, 0x07, 0x06, 0x40, 0x68, 0x07, 0x0c, 0xfe, - 0x6a, 0x12, 0xfe, 0x2c, 0x1c, 0xa2, 0x07, 0x45, 0xd4, 0xa2, 0x41, 0x45, 0xfe, 0x05, 0x40, 0xd2, - 0xf2, 0xfe, 0x28, 0x50, 0xfe, 0xaa, 0x50, 0xfe, 0xaa, 0xf0, 0xfe, 0x4e, 0x09, 0xfe, 0xac, 0xf0, - 0xfe, 0xee, 0x08, 0xfe, 0x92, 0x10, 0xe3, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xfa, 0x08, - 0x02, 0xfe, 0x5c, 0x0a, 0xe4, 0xfe, 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0xb8, 0xfe, 0x6b, 0x18, 0x1b, - 0xfe, 0x00, 0xfe, 0xda, 0xc5, 0xfe, 0xd2, 0xf0, 0xb8, 0xfe, 0x76, 0x18, 0x1b, 0x19, 0x18, 0xb8, - 0x04, 0xdf, 0x1b, 0x06, 0x18, 0xb8, 0xa7, 0x7a, 0xa9, 0x7a, 0xe3, 0xe4, 0xfe, 0xb1, 0x10, 0x8c, - 0x5a, 0x39, 0x17, 0xa4, 0x01, 0x44, 0x13, 0xfe, 0x35, 0x00, 0x34, 0x62, 0x13, 0x8d, 0x02, 0x62, - 0xfe, 0x74, 0x18, 0x1b, 0xfe, 0x00, 0xf8, 0x18, 0x7a, 0x51, 0x1e, 0x01, 0xfe, 0x7c, 0x0d, 0xd1, - 0x08, 0x1c, 0x09, 0x43, 0x01, 0x71, 0x21, 0x2f, 0x3e, 0x51, 0x19, 0x02, 0x7a, 0xfe, 0x98, 0x80, - 0xd7, 0x0c, 0x27, 0xfe, 0x3e, 0x0a, 0x0a, 0x07, 0x70, 0xfe, 0x82, 0x12, 0x0a, 0x07, 0x1a, 0xfe, - 0x66, 0x13, 0x21, 0x61, 0x6a, 0xc8, 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, - 0x04, 0x91, 0xfe, 0x86, 0x91, 0x64, 0x2f, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x75, 0xfe, 0xea, - 0x08, 0x04, 0x5d, 0x30, 0x5e, 0x0f, 0xae, 0x12, 0x8d, 0x9c, 0x5d, 0x9d, 0x5e, 0x01, 0xc1, 0xaf, - 0x64, 0x2f, 0x16, 0x61, 0xa1, 0x42, 0x69, 0x58, 0x65, 0x5f, 0x31, 0x60, 0xe8, 0xfe, 0xe5, 0x55, - 0xfe, 0x04, 0xfa, 0x42, 0xfe, 0x05, 0xfa, 0x58, 0x01, 0xfe, 0xde, 0x12, 0xfe, 0x36, 0x10, 0x2d, - 0x0f, 0xae, 0x0f, 0x8d, 0x65, 0x5f, 0x31, 0x60, 0xaa, 0x0a, 0x07, 0x1a, 0x18, 0xfe, 0xea, 0x08, - 0x65, 0x3a, 0x31, 0x3b, 0x0a, 0x07, 0xfe, 0xf7, 0x00, 0x38, 0x04, 0x5b, 0x30, 0x5c, 0xfe, 0x10, - 0x58, 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x7a, 0x0a, 0x07, 0x1a, 0x18, - 0xfe, 0xea, 0x08, 0x0a, 0x07, 0xfe, 0xf7, 0x00, 0x38, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x77, - 0xfe, 0x10, 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x3f, 0x05, 0xc3, 0x18, 0xfe, 0xf6, 0x08, - 0x11, 0xc3, 0xfe, 0x98, 0x80, 0xd7, 0x0c, 0xfe, 0x14, 0x13, 0x04, 0x3a, 0x30, 0x3b, 0x75, 0xfe, - 0xf6, 0x08, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x7a, 0x2d, 0x4e, 0xfe, 0x19, 0x80, 0xfe, - 0xf1, 0x10, 0x0a, 0x07, 0x0c, 0xa5, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xfe, 0x8e, 0x10, 0xfe, - 0x6c, 0x19, 0x9c, 0x3a, 0xfe, 0xed, 0x19, 0x9d, 0x3b, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xfe, - 0x6b, 0x18, 0x1b, 0xfe, 0x00, 0xff, 0x35, 0xfe, 0x74, 0x10, 0xc5, 0xfe, 0xd2, 0xf0, 0xfe, 0xd6, - 0x0a, 0xfe, 0x76, 0x18, 0x1b, 0x19, 0xce, 0x04, 0xdf, 0x1b, 0x06, 0x84, 0x13, 0xfe, 0x16, 0x00, - 0x02, 0x62, 0xfe, 0xd1, 0xf0, 0xfe, 0xe8, 0x0a, 0x17, 0x80, 0x01, 0x44, 0x13, 0xd6, 0xfe, 0x42, - 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xee, 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xfa, 0x0a, - 0x13, 0xfe, 0x22, 0x00, 0x02, 0x62, 0xfe, 0xcb, 0xf0, 0xfe, 0x06, 0x0b, 0x13, 0xfe, 0x24, 0x00, - 0x02, 0x62, 0xfe, 0xd0, 0xf0, 0xfe, 0x10, 0x0b, 0x13, 0x88, 0xd8, 0xfe, 0xcf, 0xf0, 0xfe, 0x1a, - 0x0b, 0x13, 0x89, 0xd3, 0xfe, 0xcc, 0xf0, 0xfe, 0x2a, 0x0b, 0xfe, 0x84, 0x80, 0xd7, 0x1a, 0x4b, - 0x13, 0xfe, 0x12, 0x00, 0x2b, 0x08, 0x80, 0x2e, 0xfe, 0x30, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x44, - 0x0b, 0x9b, 0x18, 0x32, 0x2b, 0x52, 0xfe, 0xed, 0x10, 0xa7, 0x28, 0xa9, 0x28, 0x2b, 0xf5, 0x2e, - 0xfe, 0x50, 0x0b, 0x22, 0x32, 0x81, 0xfe, 0x6c, 0x0b, 0x6b, 0x92, 0xa7, 0xfe, 0xec, 0x07, 0xa9, - 0xfe, 0xec, 0x07, 0x02, 0x28, 0x01, 0x4c, 0xfe, 0xdb, 0x10, 0x11, 0xfe, 0xe8, 0x00, 0xe3, 0xe4, - 0x8c, 0x82, 0x6e, 0xfe, 0x89, 0xf0, 0x28, 0x23, 0x24, 0xfe, 0xe9, 0x09, 0x01, 0x0b, 0x82, 0x6e, - 0x1f, 0x28, 0x23, 0x24, 0x91, 0x34, 0xfe, 0xa8, 0x0b, 0x22, 0x32, 0x02, 0xfe, 0x9c, 0x0b, 0x9b, - 0x40, 0x13, 0xfe, 0x42, 0x00, 0x02, 0x62, 0xa0, 0x06, 0xfe, 0x81, 0x49, 0x96, 0x0a, 0x07, 0x0c, - 0xfe, 0x5a, 0x13, 0x13, 0x00, 0x59, 0x0c, 0xfe, 0x6a, 0x12, 0x59, 0xfe, 0x28, 0x00, 0x27, 0xfe, - 0xee, 0x0c, 0x0e, 0x79, 0x01, 0x15, 0x05, 0x00, 0x84, 0x36, 0xfe, 0x28, 0x00, 0x02, 0xfe, 0xee, - 0x0c, 0x01, 0x97, 0x01, 0x9a, 0x0e, 0xc0, 0x01, 0xfe, 0x44, 0x0e, 0xb2, 0x08, 0x3d, 0x09, 0x99, - 0x01, 0x46, 0x11, 0x47, 0x08, 0x1c, 0x09, 0x43, 0x01, 0x7b, 0x02, 0x26, 0x13, 0xfe, 0x44, 0x00, - 0x59, 0x0c, 0xa5, 0x36, 0x0c, 0xfe, 0xc0, 0x10, 0x01, 0x96, 0x36, 0x0c, 0xfe, 0xb6, 0x10, 0x01, - 0x96, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xfe, 0x0a, 0x13, 0x36, 0x0c, 0x13, 0xfe, 0x43, 0x00, - 0xfe, 0xa2, 0x10, 0x0a, 0x41, 0x0c, 0x38, 0x01, 0x97, 0x01, 0x9a, 0xb2, 0x08, 0x3d, 0x09, 0x99, - 0x01, 0x46, 0x11, 0x47, 0x08, 0x1c, 0x09, 0x43, 0x01, 0x7b, 0x51, 0x0c, 0xb2, 0x1d, 0xca, 0x02, - 0xfe, 0x48, 0x03, 0x0a, 0x07, 0x0c, 0xce, 0x36, 0x0c, 0x13, 0x00, 0xfe, 0x54, 0x10, 0x68, 0x07, - 0x1e, 0xfe, 0x50, 0x12, 0x0a, 0x07, 0x1e, 0xfe, 0x48, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, - 0xfe, 0xac, 0x0c, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0xb2, 0x0c, 0x0a, 0x41, 0x1e, 0x38, - 0xfe, 0x95, 0x10, 0x13, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0c, 0x77, 0xfe, 0x26, 0x10, 0x13, - 0xfe, 0x13, 0x00, 0xd3, 0x13, 0xfe, 0x47, 0x00, 0xa6, 0x13, 0xfe, 0x41, 0x00, 0x9e, 0x13, 0xfe, - 0x24, 0x00, 0x04, 0x78, 0x29, 0x27, 0xee, 0x77, 0xfe, 0x04, 0xe6, 0x1e, 0xfe, 0x9d, 0x41, 0xfe, - 0x1c, 0x42, 0xb2, 0x01, 0xea, 0x02, 0x26, 0xd5, 0x17, 0x0c, 0x4a, 0xf4, 0xdd, 0x17, 0xfe, 0x31, - 0x00, 0x4a, 0xbd, 0x01, 0xfe, 0x50, 0x0f, 0x02, 0xfe, 0xc2, 0x01, 0x1d, 0xfe, 0x06, 0xec, 0xf8, - 0x86, 0x36, 0x37, 0xbf, 0x35, 0x1d, 0xfe, 0x06, 0xea, 0xf8, 0xfe, 0x47, 0x4b, 0x95, 0xfe, 0x75, - 0x57, 0x04, 0x56, 0xfe, 0x98, 0x56, 0xfe, 0x28, 0x12, 0x0e, 0x79, 0xfe, 0xf4, 0x14, 0x4e, 0xe6, - 0x0e, 0xc0, 0xfe, 0xea, 0x14, 0xfe, 0x49, 0x54, 0x8f, 0xfe, 0x62, 0x0d, 0x0e, 0x1c, 0xfe, 0xde, - 0x14, 0xfe, 0x44, 0x48, 0x02, 0xfe, 0x48, 0x03, 0x0e, 0x56, 0xfe, 0xc8, 0x14, 0x86, 0x36, 0x37, - 0xbf, 0x35, 0x1d, 0xfe, 0xce, 0x47, 0xfe, 0xbd, 0x13, 0x02, 0x26, 0x21, 0x2a, 0x05, 0x10, 0xfe, - 0x78, 0x12, 0x2d, 0x16, 0x55, 0x16, 0xad, 0x21, 0x47, 0x4e, 0x4a, 0x47, 0x9b, 0xfe, 0x0c, 0x13, - 0xfe, 0xbc, 0xf0, 0xfe, 0xfe, 0x0d, 0x08, 0x06, 0x16, 0x55, 0x01, 0xfe, 0x06, 0x16, 0x04, 0xfe, - 0x38, 0x01, 0x30, 0xfe, 0x3a, 0x01, 0x75, 0xfe, 0x02, 0x0e, 0x04, 0xfe, 0x38, 0x01, 0x1b, 0xfe, - 0xf0, 0xff, 0x0f, 0xfe, 0x60, 0x01, 0x04, 0xfe, 0x3a, 0x01, 0x0f, 0xfe, 0x62, 0x01, 0x20, 0x06, - 0x16, 0x47, 0xfe, 0x04, 0xec, 0x2a, 0x08, 0x2a, 0x09, 0x3c, 0x1d, 0x01, 0x46, 0x7f, 0xfe, 0x05, - 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x76, 0x16, 0x11, 0x47, 0xca, 0x08, 0x06, 0x03, 0x2d, 0x03, - 0x21, 0x55, 0xfe, 0xf7, 0x12, 0x21, 0xad, 0x6a, 0x16, 0xad, 0x05, 0x80, 0xfe, 0x93, 0x13, 0xfe, - 0x24, 0x1c, 0x17, 0x19, 0x4a, 0xf4, 0xdd, 0xfe, 0xd9, 0x10, 0x93, 0xfe, 0x03, 0xdc, 0xfe, 0x73, - 0x57, 0xfe, 0x80, 0x5d, 0x03, 0x93, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x03, - 0xfe, 0x03, 0x57, 0x93, 0x2d, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0x93, 0x7d, 0x03, 0x01, - 0xfe, 0xae, 0x16, 0x3f, 0x05, 0x47, 0xfe, 0x0a, 0x13, 0x08, 0x1c, 0x09, 0x43, 0xd3, 0x01, 0x97, - 0x01, 0x9a, 0x08, 0x3d, 0x09, 0x99, 0x01, 0x46, 0x11, 0xfe, 0xe9, 0x00, 0x0a, 0x07, 0x89, 0xfe, - 0x52, 0x13, 0x01, 0xfe, 0x38, 0x16, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0x0f, 0xfe, 0x64, 0x01, - 0xfe, 0x16, 0x90, 0x0f, 0xfe, 0x66, 0x01, 0x0a, 0x07, 0x45, 0xe5, 0xfe, 0x03, 0x80, 0x52, 0x3e, - 0x11, 0x76, 0x08, 0x2a, 0x09, 0x3c, 0x1d, 0x90, 0x01, 0x71, 0xfe, 0x62, 0x08, 0x6a, 0x3e, 0x11, - 0x76, 0x08, 0x2a, 0x09, 0x3c, 0x1d, 0x90, 0x01, 0x71, 0x64, 0x2f, 0x11, 0x76, 0x08, 0x2a, 0x09, - 0x3c, 0x1d, 0x90, 0x01, 0x7b, 0x03, 0xfe, 0x08, 0x1c, 0x04, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, - 0x04, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x04, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x04, 0xfe, - 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x20, 0x6c, 0x16, 0xf8, 0x2d, 0x0f, 0x53, 0x0f, - 0x4d, 0x20, 0x10, 0x16, 0x2a, 0x16, 0x3c, 0x57, 0xa0, 0xd6, 0x08, 0x2a, 0x09, 0x3c, 0x1d, 0x01, - 0x7b, 0x7f, 0x11, 0x76, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x2a, 0x0f, 0xd5, 0x8c, 0xfe, - 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x1d, 0xfe, 0x0c, 0x14, 0x86, 0xfe, 0x07, - 0xe6, 0x37, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x96, 0x0e, 0x3d, 0x01, 0x15, 0x05, - 0x10, 0x2c, 0x0e, 0x1c, 0x01, 0x15, 0x05, 0x10, 0xda, 0xfe, 0x44, 0x58, 0x3e, 0xfe, 0x01, 0xec, - 0xbd, 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1e, 0x9f, 0x2f, 0x01, 0xea, - 0xfe, 0xc9, 0x10, 0x03, 0x2b, 0x82, 0x6e, 0x23, 0x24, 0xb3, 0x05, 0x1e, 0xfe, 0x48, 0x12, 0x05, - 0x0c, 0xfe, 0x4c, 0x12, 0x05, 0x19, 0xfe, 0x30, 0x12, 0x05, 0xcc, 0x18, 0xfe, 0xf4, 0x10, 0x05, - 0xfe, 0x23, 0x00, 0x18, 0xfe, 0x00, 0x11, 0x05, 0x06, 0x18, 0xfe, 0x5e, 0x11, 0x05, 0x1a, 0xfe, - 0x12, 0x12, 0x05, 0x00, 0x18, 0x28, 0x17, 0xcc, 0x01, 0x44, 0xc6, 0x39, 0x01, 0x0b, 0x81, 0x4c, - 0x03, 0x39, 0x11, 0xfe, 0xcc, 0x00, 0x02, 0x26, 0x39, 0x3f, 0x05, 0xc3, 0xfe, 0xe3, 0x13, 0x65, - 0x3a, 0x31, 0x3b, 0x75, 0xfe, 0xb2, 0x10, 0x0a, 0x07, 0x70, 0xfe, 0x72, 0x12, 0xa1, 0x42, 0x69, - 0x58, 0xe8, 0xfe, 0xe5, 0x55, 0x8f, 0xfe, 0x7c, 0x10, 0x21, 0x61, 0xfe, 0x26, 0x13, 0x04, 0xae, - 0x30, 0x8d, 0x75, 0xfe, 0xd2, 0x0c, 0x0f, 0x5d, 0x12, 0x5e, 0x2d, 0x0f, 0xae, 0x0f, 0x8d, 0x01, - 0xc1, 0x20, 0x6c, 0x52, 0x16, 0x61, 0x01, 0xfe, 0xde, 0x12, 0xa1, 0x42, 0x69, 0x58, 0xfe, 0x04, - 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x42, 0xfe, 0x05, 0xfa, 0x58, 0xfe, 0x91, 0x10, 0x04, - 0x5f, 0x30, 0x60, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0f, 0x5f, 0x12, 0x60, 0xa8, 0xa1, 0x42, - 0x69, 0x58, 0xe8, 0xfe, 0xe5, 0x55, 0x04, 0x5b, 0x30, 0x5c, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, - 0x0f, 0x5b, 0x12, 0x5c, 0x0a, 0x07, 0x70, 0xfe, 0x1e, 0x12, 0x21, 0x61, 0xfe, 0x1f, 0x40, 0x04, - 0x5d, 0x30, 0x5e, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x04, 0x5f, 0x30, 0x60, 0xfe, 0x34, 0x50, - 0xfe, 0xb6, 0x50, 0x04, 0x5b, 0x30, 0x5c, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x04, 0x3a, 0x30, - 0x3b, 0xfe, 0x28, 0x50, 0xfe, 0xaa, 0x50, 0x02, 0x98, 0x20, 0x06, 0x16, 0xf3, 0x02, 0x7c, 0x39, - 0x01, 0x0b, 0x1f, 0x4f, 0x23, 0x24, 0xb3, 0x05, 0x06, 0x27, 0x4f, 0x3f, 0x05, 0xc3, 0x27, 0x7c, - 0x01, 0xfa, 0x1b, 0x50, 0x18, 0x4f, 0x0a, 0x07, 0x0c, 0xdc, 0x65, 0x3a, 0x31, 0x3b, 0xfe, 0x0a, - 0x55, 0x35, 0xfe, 0x8b, 0x55, 0x9c, 0x3a, 0x9d, 0x3b, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x02, - 0x7c, 0xfe, 0x19, 0x81, 0xfe, 0x0a, 0x45, 0xfe, 0x19, 0x41, 0x02, 0x7c, 0x39, 0x01, 0x0b, 0x1f, - 0xfe, 0xf6, 0x0f, 0x23, 0x24, 0xfe, 0xe9, 0x09, 0x59, 0x19, 0xfe, 0x94, 0x12, 0x59, 0x0c, 0x4b, - 0x02, 0x4f, 0x2e, 0xfe, 0x7e, 0x11, 0x22, 0x32, 0x1f, 0xfe, 0xf6, 0x0f, 0x23, 0x24, 0x91, 0x05, - 0x19, 0x27, 0x4f, 0x01, 0x0b, 0x1f, 0xfe, 0xf6, 0x0f, 0x23, 0x24, 0xfe, 0xe8, 0x09, 0x57, 0x04, - 0xfe, 0x9c, 0x00, 0x29, 0x35, 0xfe, 0xbb, 0x45, 0x59, 0x00, 0x40, 0x36, 0x06, 0xa0, 0x50, 0xfe, - 0xc0, 0x14, 0xfe, 0xf8, 0x14, 0xac, 0x3f, 0x05, 0xc2, 0xfe, 0x16, 0x13, 0x04, 0xf6, 0x29, 0xce, - 0x04, 0x4d, 0x29, 0x35, 0x5a, 0x02, 0x7c, 0xfe, 0xc0, 0x5d, 0xfe, 0xe4, 0x14, 0xfe, 0x03, 0x17, - 0x04, 0x53, 0xbc, 0x0f, 0x53, 0x5a, 0x39, 0x01, 0x0b, 0x25, 0x98, 0x01, 0xfe, 0x26, 0x14, 0x02, - 0x98, 0x2e, 0x40, 0x22, 0x32, 0x1f, 0x4f, 0x23, 0x24, 0x91, 0x05, 0x06, 0x27, 0x4f, 0xfe, 0xf6, - 0x14, 0xfe, 0x42, 0x58, 0xfe, 0x70, 0x14, 0xfe, 0x92, 0x14, 0xac, 0xfe, 0x4a, 0xf4, 0x0c, 0x18, - 0x4f, 0xfe, 0x4a, 0xf4, 0x06, 0xd1, 0x3f, 0x05, 0xc2, 0xc9, 0x02, 0x7c, 0x04, 0x4d, 0xbc, 0x0f, - 0x4d, 0x5a, 0x39, 0x01, 0x0b, 0x25, 0x98, 0x01, 0xfe, 0x54, 0x14, 0x02, 0x98, 0x25, 0xfe, 0x70, - 0x12, 0x73, 0xf1, 0x73, 0x03, 0x34, 0xfe, 0x6c, 0x12, 0x6b, 0xfe, 0x6c, 0x12, 0x5a, 0x39, 0x01, - 0x0b, 0xfe, 0xe3, 0x10, 0x08, 0x63, 0xff, 0x02, 0x00, 0x57, 0x66, 0x7e, 0x1b, 0xfe, 0xff, 0x7f, - 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x08, 0x63, 0xff, 0x02, 0x00, 0x57, 0x66, 0x7e, 0x1b, - 0x50, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x08, 0x63, 0xff, 0x02, 0x00, 0x57, 0x66, 0x7e, - 0x03, 0x08, 0x63, 0xff, 0x02, 0x00, 0x57, 0x66, 0x7e, 0xfe, 0x0b, 0x58, 0x03, 0x0e, 0x53, 0x01, - 0x8b, 0x0e, 0x4d, 0x01, 0x8b, 0x03, 0xc8, 0x1b, 0x10, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, - 0x1a, 0x66, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x64, 0x2f, - 0x0f, 0x5b, 0x12, 0x5c, 0x9c, 0x5f, 0x9d, 0x60, 0x03, 0xfe, 0x62, 0x18, 0xfe, 0x82, 0x5a, 0xfe, - 0xe1, 0x1a, 0xb6, 0xfe, 0x02, 0x58, 0x03, 0x01, 0xfe, 0x9e, 0x18, 0xfe, 0x42, 0x48, 0x77, 0x57, - 0x95, 0x01, 0x0b, 0x1f, 0xfe, 0x1e, 0x14, 0x23, 0x24, 0xfe, 0xe9, 0x09, 0xfe, 0xc1, 0x59, 0x01, - 0x0b, 0x1f, 0xfe, 0x1e, 0x14, 0x23, 0x24, 0xfe, 0xe8, 0x0a, 0x04, 0xf6, 0x29, 0xfe, 0xc4, 0x12, - 0x2d, 0xb1, 0x1e, 0xdc, 0x59, 0xcd, 0x74, 0xfe, 0x6c, 0x13, 0x4b, 0x08, 0x06, 0x09, 0xcd, 0xa0, - 0xfe, 0x00, 0x10, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xa6, 0xff, 0x02, 0x83, 0x55, 0xb1, - 0x19, 0xfe, 0x12, 0x13, 0x72, 0xfe, 0x30, 0x00, 0x8f, 0xfe, 0xc6, 0x13, 0x09, 0x85, 0x08, 0x06, - 0xfe, 0x56, 0x10, 0xb1, 0x0c, 0xfe, 0x16, 0x13, 0x72, 0xfe, 0x64, 0x00, 0x8f, 0xfe, 0xc6, 0x13, - 0x0e, 0xfe, 0x64, 0x00, 0x09, 0x88, 0x08, 0x06, 0xfe, 0x28, 0x10, 0xb1, 0x06, 0xfe, 0x60, 0x13, - 0x72, 0xfe, 0xc8, 0x00, 0x8f, 0xfe, 0xc6, 0x13, 0x0e, 0xfe, 0xc8, 0x00, 0x09, 0x55, 0x08, 0x06, - 0xa8, 0x72, 0xfe, 0x90, 0x01, 0xed, 0xfe, 0xd2, 0x13, 0x95, 0xaa, 0xfe, 0x43, 0xf4, 0xad, 0xfe, - 0x56, 0xf0, 0xfe, 0xe4, 0x13, 0xfe, 0x04, 0xf4, 0x63, 0xfe, 0x43, 0xf4, 0x88, 0xfe, 0xf3, 0x10, - 0xb0, 0x01, 0xfe, 0xae, 0x12, 0x1b, 0x50, 0xd4, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x6c, 0xed, - 0xfe, 0x18, 0x14, 0xa3, 0x6c, 0xfe, 0x14, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x1a, 0xed, - 0xfe, 0x18, 0x14, 0xa3, 0x1a, 0x9e, 0x57, 0x95, 0x08, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, - 0x03, 0x57, 0x08, 0x0c, 0x03, 0x14, 0x06, 0x01, 0x0b, 0x25, 0xec, 0x14, 0x0c, 0x01, 0x0b, 0x25, - 0xec, 0x14, 0x19, 0x01, 0x0b, 0x25, 0xec, 0x73, 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x03, 0x14, 0x06, - 0x01, 0x0b, 0x25, 0xb7, 0x14, 0x19, 0x01, 0x0b, 0x25, 0xb7, 0x14, 0x06, 0x01, 0x0b, 0x25, 0xb7, - 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x25, 0xb7, 0x73, 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x03, 0x57, 0x03, - 0x21, 0xe0, 0x05, 0x06, 0xfe, 0x44, 0x13, 0xaf, 0x16, 0xe0, 0xfe, 0x49, 0xf4, 0x00, 0x4b, 0x73, - 0xc6, 0x5a, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01, 0x0b, 0x3f, 0x05, 0xfe, 0xe3, 0x00, - 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0xd6, 0x14, 0x2d, 0x16, 0xf3, 0x01, 0x4c, 0x21, 0xf3, 0x05, 0x06, - 0x40, 0x0a, 0x41, 0x06, 0x38, 0x03, 0x0f, 0x54, 0x12, 0x8a, 0xfe, 0x43, 0x58, 0x01, 0x15, 0x05, - 0x10, 0xfe, 0x1e, 0x12, 0x48, 0xe7, 0x8e, 0x01, 0x2c, 0xfe, 0x90, 0x4d, 0xde, 0x10, 0xfe, 0xc5, - 0x59, 0x01, 0x2c, 0xfe, 0x8d, 0x56, 0xb6, 0x48, 0x03, 0x48, 0x31, 0x8a, 0x01, 0x15, 0x48, 0x8e, - 0x01, 0x2c, 0xe2, 0x10, 0xde, 0x10, 0x31, 0x54, 0x72, 0x1c, 0x84, 0x0e, 0x56, 0x01, 0xab, 0x03, - 0x0f, 0x54, 0x12, 0x8a, 0xfe, 0xc3, 0x58, 0x01, 0x15, 0x05, 0x10, 0xfe, 0x1a, 0x12, 0x48, 0xe7, - 0x8e, 0x01, 0x2c, 0xe2, 0x10, 0xfe, 0x80, 0x4d, 0xfe, 0xc5, 0x59, 0x01, 0x2c, 0x48, 0x03, 0x48, - 0x31, 0x54, 0x01, 0x15, 0x48, 0x8e, 0x01, 0x2c, 0xe2, 0x10, 0xde, 0x10, 0x31, 0x54, 0x72, 0x1c, - 0x84, 0x0e, 0x56, 0x01, 0xab, 0x03, 0x0f, 0x54, 0x12, 0x8a, 0xfe, 0x43, 0x58, 0x01, 0x15, 0xfe, - 0x42, 0x48, 0x8e, 0x01, 0x2c, 0xfe, 0xc0, 0x5a, 0xb0, 0xfe, 0x00, 0xcd, 0xfe, 0x01, 0xcc, 0xfe, - 0x4a, 0x46, 0xdc, 0x93, 0x7d, 0x05, 0x10, 0xfe, 0x2e, 0x13, 0x69, 0x54, 0xfe, 0x4d, 0xf4, 0x1c, - 0xfe, 0x1c, 0x13, 0x0e, 0x56, 0x01, 0x8b, 0xaa, 0xfe, 0x40, 0x4c, 0xfe, 0xc5, 0x58, 0x01, 0x2c, - 0xfe, 0x00, 0x07, 0x7d, 0x05, 0x10, 0x84, 0x69, 0x8a, 0xfe, 0x05, 0x57, 0xfe, 0x08, 0x10, 0xfe, - 0x45, 0x58, 0x01, 0x2c, 0xfe, 0x8d, 0x56, 0xb6, 0xfe, 0x80, 0x4c, 0xfe, 0x05, 0x17, 0x03, 0x09, - 0x10, 0x6f, 0x67, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xdb, - 0x37, 0x94, 0xfe, 0x1a, 0x16, 0x01, 0xfe, 0x28, 0x17, 0xfe, 0x0c, 0x13, 0x87, 0x37, 0x67, 0xfe, - 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xba, 0x27, 0xfe, 0x0a, 0x16, 0xfe, 0xe2, 0x10, 0x09, 0x10, - 0x6f, 0x04, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1a, 0xfe, 0x18, 0x58, 0x04, 0xfe, 0x66, 0x01, - 0xfe, 0x19, 0x58, 0x87, 0x1a, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x67, - 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1a, 0x94, 0xfe, 0x64, 0x16, 0xfe, 0xbe, - 0x14, 0x35, 0x03, 0xba, 0x27, 0xfe, 0x3c, 0x16, 0xfe, 0xa4, 0x10, 0x09, 0x10, 0x6f, 0xb6, 0xfe, - 0x18, 0xdf, 0xfe, 0x19, 0xdf, 0xdb, 0x42, 0x94, 0xfe, 0x86, 0x16, 0xfe, 0x9c, 0x14, 0xfe, 0x18, - 0x13, 0x87, 0x42, 0x67, 0x1e, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0xa2, 0x07, 0xfe, 0x7f, - 0x00, 0xfe, 0x05, 0x40, 0x03, 0xba, 0x27, 0xfe, 0x7a, 0x16, 0xfe, 0x6c, 0x10, 0x09, 0x10, 0x6f, - 0xfe, 0x30, 0xbc, 0xfe, 0xb2, 0xbc, 0x87, 0xd9, 0x67, 0x1e, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, - 0xd9, 0x94, 0xfe, 0xc6, 0x16, 0xfe, 0x5c, 0x14, 0x35, 0x03, 0xba, 0x27, 0xfe, 0xb2, 0x16, 0xfe, - 0x42, 0x10, 0xfe, 0x02, 0xf6, 0x10, 0x6f, 0xfe, 0x18, 0xfe, 0x5d, 0xfe, 0x19, 0xfe, 0x5e, 0xc8, - 0xdb, 0x45, 0x94, 0xfe, 0xec, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x87, 0x45, 0x4e, 0xfe, - 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11, 0xfe, 0xdd, - 0x00, 0x64, 0x2f, 0x03, 0x64, 0x2f, 0xfe, 0x12, 0x45, 0x27, 0xfe, 0xdc, 0x16, 0x17, 0x06, 0x4a, - 0xf4, 0xdd, 0x02, 0x26, 0xfe, 0x39, 0xf0, 0xfe, 0x30, 0x17, 0x2d, 0x03, 0xfe, 0x7e, 0x18, 0x1b, - 0x19, 0x83, 0x08, 0x0d, 0x03, 0x6f, 0x04, 0xdf, 0x1b, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, - 0x1d, 0x0e, 0x1c, 0x01, 0x15, 0x05, 0x10, 0x40, 0x3e, 0xfe, 0x78, 0x14, 0xfe, 0x34, 0x12, 0x50, - 0x86, 0x36, 0x37, 0xbf, 0xfe, 0xe9, 0x13, 0x1d, 0x0e, 0x3d, 0x01, 0x15, 0x05, 0x10, 0x40, 0x3e, - 0xfe, 0x56, 0x14, 0xe1, 0x50, 0x86, 0x36, 0x37, 0xbf, 0xfe, 0xe9, 0x13, 0x09, 0x0c, 0x03, 0xfe, - 0x9c, 0xe7, 0x0c, 0x13, 0xfe, 0x15, 0x00, 0x90, 0x9f, 0x2f, 0x01, 0xea, 0x09, 0x06, 0x03, 0x0a, - 0x41, 0x37, 0x38, 0x08, 0x3d, 0x09, 0x99, 0x01, 0x46, 0x11, 0x47, 0x08, 0x1c, 0x09, 0x43, 0x01, - 0x7b, 0x09, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x65, 0xf7, 0x31, 0x76, 0xfe, 0x48, - 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x03, 0x21, 0xbe, 0x52, 0x16, 0xbe, 0x03, 0x0e, 0xc0, 0x01, 0x15, - 0xe6, 0x0e, 0x79, 0x01, 0x15, 0xfe, 0x49, 0x44, 0x27, 0xfe, 0x26, 0x18, 0x0e, 0x1c, 0x01, 0x15, - 0x05, 0x10, 0x40, 0x0e, 0x56, 0x01, 0xab, 0x0e, 0x79, 0x01, 0x15, 0x52, 0x7d, 0x03, 0xfe, 0x40, - 0x5e, 0xfe, 0xe2, 0x08, 0xfe, 0xc0, 0x4c, 0x21, 0x3c, 0x05, 0x10, 0xfe, 0x52, 0x12, 0x3e, 0x05, - 0x00, 0xfe, 0x18, 0x12, 0xfe, 0xe1, 0x18, 0xfe, 0x19, 0xf4, 0xfe, 0x7f, 0x00, 0xd4, 0xfe, 0xe2, - 0x08, 0x52, 0x3e, 0x3f, 0x05, 0x76, 0xa5, 0xfe, 0x82, 0x48, 0xfe, 0x01, 0x80, 0xfe, 0xd7, 0x10, - 0xfe, 0xc4, 0x48, 0x08, 0x2a, 0x09, 0x3c, 0xfe, 0x40, 0x5f, 0x1d, 0x01, 0x46, 0x11, 0xfe, 0xdd, - 0x00, 0xfe, 0x14, 0x46, 0x08, 0x2a, 0x09, 0x3c, 0x01, 0x46, 0x11, 0xfe, 0xdd, 0x00, 0xfe, 0x40, - 0x4a, 0x6a, 0xfe, 0x06, 0x17, 0xfe, 0x01, 0x07, 0xfe, 0x82, 0x48, 0xfe, 0x04, 0x17, 0x03, 0xeb, - 0x19, 0x74, 0xfe, 0xae, 0x18, 0x04, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xeb, - 0xcc, 0x74, 0xfe, 0xc0, 0x18, 0x04, 0xfe, 0x92, 0x00, 0xc7, 0x1e, 0xd8, 0xeb, 0xfe, 0x0b, 0x00, - 0x74, 0xfe, 0xd2, 0x18, 0x04, 0xfe, 0x94, 0x00, 0xc7, 0x1a, 0xfe, 0x08, 0x10, 0x04, 0xfe, 0x96, - 0x00, 0xc7, 0x85, 0xfe, 0x4e, 0x45, 0xd1, 0xfe, 0x0a, 0x45, 0xff, 0x04, 0x68, 0x54, 0xfe, 0xf1, - 0x10, 0x1b, 0x6c, 0x03, 0x05, 0x80, 0xfe, 0x5a, 0xf0, 0xfe, 0xfe, 0x18, 0x20, 0xfe, 0x09, 0x00, - 0xfe, 0x34, 0x10, 0x05, 0x1e, 0xfe, 0x5a, 0xf0, 0xfe, 0x0c, 0x19, 0x20, 0xcd, 0xfe, 0x26, 0x10, - 0x05, 0x19, 0x83, 0x20, 0x85, 0xd8, 0x05, 0x0c, 0x83, 0x20, 0x88, 0xfe, 0x0e, 0x10, 0x05, 0x06, - 0x83, 0x20, 0x55, 0xc6, 0xaf, 0x03, 0x17, 0xfe, 0x09, 0x00, 0x01, 0x44, 0x2e, 0xfe, 0x3c, 0x19, - 0x04, 0x6e, 0xb0, 0x03, 0x22, 0xfe, 0x54, 0x19, 0xfe, 0x14, 0xf0, 0x0b, 0x2e, 0xfe, 0x50, 0x19, - 0x03, 0xff, 0x15, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc, 0x01, 0x00, 0x48, 0xe4, + 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff, 0x28, 0x0e, 0x9e, 0xe7, + 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0, 0x01, 0xf6, + 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00, 0x00, 0xec, 0x85, 0xf0, + 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0, 0x86, 0xf0, 0xb4, 0x00, + 0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00, 0xaa, 0x18, 0x02, 0x80, + 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40, 0x00, 0x57, 0x01, 0xea, + 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, + 0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12, 0x02, 0x4a, 0xb9, 0x54, + 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00, 0x3e, 0x00, 0x80, 0x00, + 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01, + 0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13, 0x4c, 0x1c, 0xbb, 0x55, + 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0, 0x03, 0xf7, 0x06, 0xf7, + 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08, 0x30, 0x13, 0x64, 0x15, + 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c, 0x04, 0xea, 0x5d, 0xf0, + 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, + 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13, 0x40, 0x13, 0x30, 0x1c, + 0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xa7, 0xf0, + 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, + 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a, 0x14, 0x0e, 0x02, 0x10, + 0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13, 0x10, 0x15, 0x14, 0x15, + 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, + 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, + 0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, + 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x9e, 0x00, 0xa8, 0x00, + 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7a, 0x01, 0xc0, 0x01, + 0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08, 0x69, 0x08, 0xba, 0x08, + 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10, 0xf1, 0x10, 0x06, 0x12, + 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14, 0x8a, 0x15, 0xc6, 0x17, + 0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0x48, 0x47, + 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55, 0x14, 0x56, 0x77, 0x57, + 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c, 0xf0, 0x29, 0x02, 0xfe, + 0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf, 0xfe, 0x80, 0x01, 0xff, + 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00, 0x00, 0xfe, 0x57, 0x24, + 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, + 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x0f, + 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, 0xfe, 0x04, 0xf7, 0xcf, + 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67, 0x0b, 0x3c, 0x2a, 0xfe, + 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, + 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b, 0x02, 0xfe, 0xd4, 0x0c, + 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x05, 0xfe, 0xa6, + 0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48, 0xf0, 0xfe, 0x86, 0x02, + 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02, 0xfe, 0x46, 0xf0, 0xfe, + 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x44, 0x02, 0xfe, 0x44, + 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b, 0xa0, 0x17, 0x06, 0x18, + 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9, + 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7, 0x0a, 0x6b, 0x01, 0x9e, + 0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xbd, + 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, 0x58, 0x1c, 0x17, 0x06, + 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21, 0xfe, 0x94, 0x02, 0xfe, + 0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97, 0x01, 0xfe, 0x54, 0x0f, + 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe, 0x69, 0x10, 0x17, 0x06, + 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05, 0xf6, 0xc7, 0x01, 0xfe, + 0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6, 0x02, 0x29, 0x0a, 0x40, + 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0x99, 0x01, + 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29, 0x2a, 0x46, 0xfe, 0x02, + 0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc, 0x01, 0xfe, 0x07, 0x4b, + 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0, 0xfe, 0x56, 0x03, 0xfe, + 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, + 0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48, 0x1c, 0xeb, 0x09, 0x04, + 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40, 0x01, 0x0e, 0xac, 0x75, + 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2, 0xfe, 0x82, 0xf0, 0xfe, + 0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25, 0x32, 0x1f, 0xfe, 0xb4, + 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe, 0x0a, 0xf0, 0xfe, 0x7a, + 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe, + 0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8, 0xf7, 0xfe, 0x48, 0x1c, + 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3, 0x0a, 0xca, 0x01, 0x0e, + 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14, 0x2c, 0x01, 0x33, 0x8f, + 0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65, 0xfe, 0x3c, 0x04, 0x1f, + 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2b, 0xff, 0x02, + 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd5, + 0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64, + 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d, 0xfe, 0x2a, 0x13, 0x2f, + 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64, 0xd3, 0xfa, 0xef, 0x86, + 0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04, 0x1d, 0xfe, 0x1c, 0x12, + 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c, 0x02, 0x22, + 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92, 0x01, 0x33, 0x02, 0x29, + 0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4, + 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a, 0xfe, 0x70, 0x12, 0x49, + 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe, 0x80, 0x05, 0xfe, 0x31, + 0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x42, 0x12, + 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05, 0x11, 0xfe, 0xe3, 0x00, + 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0x64, 0x05, 0x83, 0x24, + 0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe, 0x09, 0x48, 0x01, 0x08, + 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01, 0x86, 0x24, 0x06, 0x12, + 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47, 0x01, 0xa7, 0x14, 0x92, + 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c, 0x02, 0x22, 0x05, 0xfe, + 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13, 0x47, 0x01, 0xa7, 0x26, + 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f, 0x01, 0xfe, 0xaa, 0x14, + 0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x50, 0xb4, 0x0c, + 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x14, + 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, + 0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe, 0x72, 0x06, 0x49, 0x04, + 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68, 0x06, 0x11, 0x9a, 0x01, + 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06, 0x01, 0xa7, 0xec, 0x72, + 0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0, 0xfe, + 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07, 0x8d, 0x81, 0x02, 0x22, + 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, + 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15, 0x00, 0x02, 0xfe, 0x32, + 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15, 0xfe, 0x1b, 0x00, 0x01, + 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x06, 0x01, + 0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe, 0x9a, 0x81, 0x4b, 0x1d, + 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, + 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0, 0xfe, 0x32, 0x07, 0x8d, + 0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a, 0x06, 0x15, 0x19, 0x02, + 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x77, 0xfe, 0xca, + 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07, 0x10, 0xfe, 0x0e, 0x12, + 0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe, 0x83, 0xe7, 0xc4, 0xa1, + 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f, 0x40, 0x12, 0x58, 0x01, + 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0x83, 0xfb, 0xfe, + 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, + 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a, 0xfe, 0x2a, 0x12, 0xfe, + 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f, 0x85, 0x01, 0xa8, 0xfe, + 0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56, 0x18, 0x57, 0xfb, 0xfe, + 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x39, 0x18, 0x3a, + 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x48, + 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0xfe, 0x80, + 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x7a, 0x08, 0x8d, + 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9, 0x10, 0x61, 0x04, 0x06, + 0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68, 0x12, 0xfe, 0x2e, 0x1c, + 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe, 0x52, 0x12, 0xfe, 0x2c, + 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe, 0x08, 0xfe, 0x8a, 0x10, + 0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe, 0x24, 0x0a, 0xab, 0xfe, + 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xb5, 0xfe, + 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb, 0x1c, 0x06, 0x16, 0x9d, + 0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b, 0x14, 0x92, 0x01, 0x33, + 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a, 0xfe, 0x74, 0x18, 0x1c, + 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b, 0x01, 0xe6, 0x1e, 0x27, + 0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a, 0x09, 0x04, 0x6a, 0xfe, + 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc, 0xfe, 0x83, 0x80, 0xfe, + 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63, 0x27, 0xfe, 0x40, 0x59, + 0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18, 0x7c, 0xbe, 0x54, 0xbf, + 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e, 0x79, 0x56, 0x68, 0x57, + 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5, 0xa2, 0x23, 0x0c, 0x7b, + 0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x79, 0x39, + 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x10, 0x58, 0xfe, + 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x09, + 0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f, 0xfe, 0x10, 0x90, 0xfe, + 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08, 0x11, 0x9b, 0x09, 0x04, + 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08, 0xfe, 0x0c, 0x58, 0xfe, + 0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04, 0x0b, 0xfe, 0x1a, 0x12, + 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9, 0x14, 0x7a, 0x01, 0x33, + 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39, 0xfe, 0xed, 0x19, 0xbf, + 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff, 0x34, 0xfe, 0x74, 0x10, + 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x84, 0x05, 0xcb, 0x1c, + 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1, 0xf0, 0xfe, 0xc4, 0x0a, + 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xca, + 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe, 0x22, 0x00, 0x02, 0x5a, + 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a, 0xfe, 0xd0, 0xf0, 0xfe, + 0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f, 0x4c, 0xfe, 0x10, 0x10, + 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00, 0x2a, 0x13, 0xfe, 0x4e, + 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1, 0x16, 0x32, 0x2a, 0x73, + 0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25, 0x32, 0x8c, 0xfe, 0x48, + 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xdb, 0x10, 0x11, 0xfe, + 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0, 0x22, 0x30, 0x2e, 0xd8, + 0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1, 0x45, 0x0f, 0xfe, 0x42, + 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c, 0x09, 0x04, 0x0b, 0xfe, + 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28, 0x00, 0x21, 0xfe, 0xa6, + 0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01, + 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d, 0x01, 0x6f, 0x02, 0x29, + 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10, 0x01, 0x86, 0x3e, 0x0b, + 0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3, 0x3e, 0x0b, 0x0f, 0xfe, + 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01, 0xe8, 0x59, 0x11, 0x2d, + 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09, 0x04, 0x0b, 0x84, 0x3e, + 0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12, 0x09, 0x04, 0x1b, 0xfe, + 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, + 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f, 0xfe, 0x15, 0x00, 0xfe, + 0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x0f, 0xfe, 0x47, 0x00, + 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa, 0xab, 0x70, 0x05, 0x6b, + 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x59, 0x01, + 0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31, 0x00, 0x37, 0x97, 0x01, + 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e, 0x1d, 0xfe, 0xce, 0x45, + 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75, 0x57, 0x05, 0x51, 0xfe, + 0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48, 0x46, 0x09, 0x04, 0x1d, + 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a, 0x99, 0x01, 0x0e, 0xfe, + 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51, 0xfe, 0xee, 0x14, 0xee, + 0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x29, 0x1e, + 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12, 0xce, 0x1e, 0x2d, 0x47, + 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06, 0x12, 0x4d, 0x01, 0xfe, + 0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe, 0xf0, 0x0d, 0xfe, 0x02, + 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, + 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13, 0xaf, 0xfe, 0x02, 0xea, + 0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c, 0x05, 0xfe, 0x38, 0x01, + 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, + 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06, 0x03, 0x23, 0x03, 0x1e, + 0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe, 0x71, 0x13, 0xfe, 0x24, + 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, + 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xfe, + 0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x75, 0x03, 0x09, 0x04, + 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xe1, + 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xa3, 0xfe, 0x3c, + 0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82, 0x16, 0x2f, 0x07, 0x2d, + 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01, 0xe8, 0x11, 0xfe, 0xe9, + 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, + 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01, 0x09, 0x04, 0x4f, 0xfe, + 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80, 0x40, 0x12, 0x20, 0x63, + 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08, 0x1c, 0x05, 0xfe, 0xac, + 0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05, 0xfe, 0xb0, 0x00, 0xfe, + 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x24, 0x69, 0x12, 0xc9, + 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe, 0x90, 0x4d, 0xfe, 0x91, + 0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c, 0xfe, 0x90, 0x4d, 0xfe, + 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c, 0x46, 0x1e, 0x20, 0xed, + 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea, 0x70, 0xfe, 0x14, 0x1c, + 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee, 0xfe, 0x07, 0xe6, 0x1d, + 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46, 0xfa, 0xef, 0xfe, 0x42, + 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x36, 0x12, 0xf0, + 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, + 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e, 0x10, 0x07, 0x7e, 0x45, + 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74, 0xfe, 0x01, 0xec, 0x97, + 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76, 0x27, 0x01, 0xda, 0xfe, + 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b, 0xfe, 0x48, 0x12, 0x07, + 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16, 0xfe, 0x3e, 0x11, 0x07, + 0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8, 0x11, 0x07, 0x19, 0xfe, + 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b, 0x01, 0x08, 0x8c, 0x43, + 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11, 0x7e, 0x02, 0x29, 0x2b, + 0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe, 0xfc, 0x10, 0x09, 0x04, + 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe, 0xc6, 0x10, 0x1e, 0x58, + 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c, 0x54, 0x18, 0x55, 0x23, + 0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01, 0xa5, 0xc0, 0x38, 0xc1, + 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0xfe, + 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x56, 0x18, 0x57, + 0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x00, 0x56, 0xfe, 0xa1, + 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e, 0x58, 0xfe, 0x1f, 0x40, + 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x44, + 0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x05, 0x39, + 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06, 0x12, 0xcd, 0x02, 0x5b, + 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44, 0x2f, 0x07, 0x9b, 0x21, + 0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79, 0x39, 0x68, 0x3a, 0xfe, + 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, + 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x25, 0x32, + 0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b, 0x3b, 0x02, 0x44, 0x01, + 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44, 0x01, 0x08, 0x1f, 0xa2, + 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c, 0x00, 0x28, 0x84, 0x49, + 0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06, 0x78, 0x3d, 0xfe, 0xda, + 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1, 0x05, 0xc6, 0x28, 0x84, + 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17, + 0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe, 0xaa, 0x14, 0x02, + 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06, 0x21, 0x44, 0x01, 0xfe, + 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87, 0xfe, 0x4a, 0xf4, 0x0b, + 0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a, 0x85, 0x02, 0x5b, 0x05, + 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe, 0xd8, 0x14, 0x02, 0x5c, + 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1, 0x01, 0x08, 0x23, 0x72, + 0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca, 0x12, 0x5e, 0x2b, 0x01, + 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0xfe, 0xff, 0x7f, + 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, + 0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, + 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58, 0x03, 0x0a, 0x50, 0x01, + 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, + 0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x63, 0x27, + 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, + 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe, 0x42, 0x48, 0x5f, 0x60, + 0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, + 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe, 0xcc, 0x12, 0x49, 0x04, + 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe, 0xe8, 0x13, 0x3b, 0x13, + 0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xa1, 0xff, 0x02, 0x83, + 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c, 0x13, 0x06, 0xfe, 0x56, + 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe, 0x64, 0x00, 0x17, 0x93, + 0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe, 0xc8, 0x00, 0x8e, 0xe4, + 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90, 0x01, 0xba, 0xfe, 0x4e, + 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0, 0xfe, 0x60, 0x14, 0xfe, + 0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01, 0xfe, 0x22, 0x13, 0x1c, + 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba, 0xfe, 0x9c, 0x14, 0xb7, + 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba, 0xfe, 0x9c, 0x14, 0xb7, + 0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06, 0xfe, 0xb4, 0x56, 0xfe, + 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26, 0xe5, 0x15, 0x0b, 0x01, + 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x03, + 0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x06, 0x01, 0x08, + 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89, 0x4a, 0x01, 0x08, 0x03, + 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc, 0xfe, 0x49, 0xf4, 0x00, + 0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01, 0x08, 0x2f, 0x07, 0xfe, + 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd, 0x01, 0x43, 0x1e, 0xcd, + 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e, 0xed, 0x88, 0x07, 0x10, + 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x80, 0x01, 0x0e, 0x88, + 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3, 0x88, 0x03, 0x0a, 0x42, + 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x80, 0x80, 0xf2, + 0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51, 0x01, 0x82, 0x03, 0x17, + 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xfe, + 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0, 0x91, 0x1d, 0x66, 0xfe, + 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe, 0xda, 0x10, 0x17, 0x10, + 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58, 0x05, 0xfe, 0x66, 0x01, + 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x66, + 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe, 0x40, 0x16, 0xfe, 0xb6, + 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17, 0x10, 0x71, 0xfe, 0x83, + 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90, 0xfe, 0x62, 0x16, 0xfe, + 0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, + 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71, 0xfe, 0x30, 0xbc, 0xfe, + 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0xc5, 0x90, 0xfe, 0x9a, + 0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe, 0x42, 0x10, 0xfe, 0x02, + 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc, 0xfe, 0x1d, 0xf7, 0x4f, + 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f, 0x47, 0xfe, 0x83, 0x58, + 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11, 0xfe, 0xdd, 0x00, 0x63, + 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14, 0x06, 0x37, 0x95, 0xa9, + 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e, 0x18, 0x1c, 0x1a, 0x5d, + 0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x78, 0x2c, + 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x3c, 0x8a, 0x0a, + 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, + 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x01, 0x6f, + 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, 0xf6, 0xfe, 0xd6, 0xf0, + 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe, 0x15, 0x00, 0x59, 0x76, + 0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35, 0x11, 0x2d, 0x01, 0x6f, + 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68, 0xc8, 0xfe, 0x48, 0x55, + 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a, 0x99, 0x01, 0x0e, 0xf0, + 0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73, 0x75, 0x03, 0x0a, 0x42, + 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01, 0x0e, 0x73, 0x75, 0x03, + 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0x5b, + 0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1b, + 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05, 0xfe, 0x94, 0x00, 0xfe, + 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x2c, 0xfe, 0x4e, + 0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69, 0x03, 0x07, 0x7a, 0xfe, + 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10, 0x07, 0x1b, 0xfe, 0x5a, + 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d, 0x24, 0x2c, 0xdc, 0x07, + 0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d, 0x9f, 0xad, 0x03, 0x14, + 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9, 0x03, 0x25, 0xfe, 0xca, + 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a, 0x00, 0x00, }; STATIC unsigned short _adv_asc3550_size = - sizeof(_adv_asc3550_buf); /* 0x13E5 */ + sizeof(_adv_asc3550_buf); /* 0x13AD */ STATIC ADV_DCNT _adv_asc3550_chksum = - 0x04FFFF0E; /* Expanded checksum. */ + 0x04D52DDDUL; /* Expanded little-endian checksum. */ +/* Microcode buffer is kept after initialization for error recovery. */ STATIC unsigned char _adv_asc38C0800_buf[] = { - 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x00, 0xfc, 0x48, 0xe4, 0x01, 0x00, 0x18, 0xe4, - 0x00, 0xf6, 0x01, 0xf6, 0x18, 0x80, 0x02, 0x00, 0x40, 0x1a, 0x00, 0xfa, 0xff, 0xff, 0x03, 0xf6, - 0xff, 0x00, 0x82, 0xe7, 0x01, 0xfa, 0x9e, 0xe7, 0x09, 0xe7, 0x1a, 0x0f, 0x00, 0xea, 0x01, 0xe6, - 0x03, 0x00, 0x55, 0xf0, 0x18, 0xf4, 0x1e, 0xf0, 0x3e, 0x57, 0x04, 0x00, 0x3e, 0x01, 0x85, 0xf0, - 0x00, 0xe6, 0x03, 0xfc, 0x08, 0x00, 0x2c, 0x1a, 0x32, 0xf0, 0x86, 0xf0, 0xbe, 0x0d, 0xd4, 0x01, - 0xd5, 0xf0, 0x00, 0xec, 0x01, 0xfc, 0x38, 0x54, 0x98, 0x57, 0xbc, 0x00, 0x0c, 0x1c, 0xb1, 0xf0, - 0x3c, 0x00, 0xb4, 0x00, 0xb8, 0x0d, 0x00, 0x57, 0x01, 0xf0, 0x02, 0x13, 0x02, 0xfc, 0x03, 0xe6, - 0x10, 0x00, 0x18, 0x40, 0x3e, 0x1c, 0x44, 0x13, 0x6c, 0x01, 0x6e, 0x01, 0xbd, 0x00, 0xe0, 0x00, - 0x02, 0x80, 0x30, 0xe4, 0x3e, 0x00, 0x74, 0x01, 0x76, 0x01, 0x7c, 0x16, 0x80, 0x00, 0xb9, 0x54, - 0xbb, 0x00, 0xee, 0x13, 0x00, 0x4e, 0x01, 0x01, 0x01, 0xea, 0x02, 0x48, 0x02, 0xfa, 0x04, 0x12, - 0x08, 0x12, 0x3c, 0x56, 0x4e, 0x01, 0x5d, 0xf0, 0x7a, 0x01, 0x7e, 0x10, 0xb6, 0x00, 0xc2, 0x10, - 0xee, 0x08, 0x00, 0x80, 0x05, 0xfc, 0x10, 0x44, 0x24, 0x01, 0x28, 0x01, 0x32, 0x00, 0x3c, 0x01, - 0x40, 0x00, 0x4b, 0xe4, 0x4b, 0xf4, 0x4c, 0x1c, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, - 0x78, 0x01, 0x7c, 0x01, 0xbb, 0x55, 0xc2, 0x0d, 0x00, 0x01, 0x02, 0xee, 0x03, 0x58, 0x03, 0xf7, - 0x03, 0xfa, 0x04, 0x80, 0x08, 0x44, 0x09, 0xf0, 0x0f, 0x00, 0x1b, 0x80, 0x20, 0x01, 0x38, 0x1c, - 0x4e, 0x1c, 0x5b, 0xf0, 0x62, 0x0a, 0xaa, 0x00, 0xbe, 0x00, 0xc0, 0x00, 0xc0, 0x15, 0xcc, 0x10, - 0x00, 0x4c, 0x00, 0xdc, 0x02, 0x4a, 0x04, 0xfc, 0x05, 0x00, 0x05, 0xf0, 0x05, 0xf8, 0x06, 0x13, - 0x06, 0xf7, 0x08, 0x13, 0x0a, 0x10, 0x0c, 0x00, 0x0e, 0x47, 0x0e, 0xf7, 0x10, 0x0f, 0x20, 0x00, - 0x20, 0x16, 0x2a, 0x01, 0x32, 0x1c, 0x36, 0x00, 0x42, 0x54, 0x44, 0x55, 0x45, 0x5a, 0x52, 0x0c, - 0x59, 0xf0, 0x5c, 0xf0, 0x69, 0x08, 0x6e, 0x0b, 0x83, 0x59, 0xb8, 0xf0, 0xbd, 0x56, 0xcc, 0x18, - 0xce, 0x10, 0xd8, 0x18, 0xf0, 0x00, 0x01, 0x48, 0x04, 0x10, 0x04, 0xea, 0x04, 0xf6, 0x05, 0x80, - 0x05, 0xe6, 0x06, 0x00, 0x06, 0x0f, 0x06, 0x12, 0x0b, 0xf0, 0x0c, 0x10, 0x0c, 0xf0, 0x10, 0x13, - 0x12, 0x10, 0x19, 0x00, 0x19, 0xe4, 0x30, 0x1c, 0x33, 0x00, 0x34, 0x00, 0x38, 0x44, 0x40, 0x5c, - 0x4a, 0xe4, 0x62, 0x1a, 0x68, 0x08, 0x68, 0x54, 0x6c, 0x15, 0x70, 0x15, 0x83, 0x55, 0x83, 0x5a, - 0x91, 0x44, 0xa4, 0x00, 0xac, 0x13, 0xb0, 0x57, 0xb5, 0x00, 0xb8, 0x17, 0xba, 0x00, 0xce, 0x45, - 0xd0, 0x00, 0xe1, 0x00, 0xe5, 0x55, 0xe7, 0x00, 0x00, 0x54, 0x01, 0x58, 0x02, 0x10, 0x02, 0xe6, - 0x03, 0xa1, 0x04, 0x13, 0x06, 0x83, 0x06, 0xf0, 0x07, 0x00, 0x0a, 0x00, 0x0a, 0x12, 0x0a, 0xf0, - 0x0c, 0x12, 0x0c, 0x13, 0x0c, 0x90, 0x0e, 0x13, 0x10, 0x04, 0x10, 0x10, 0x12, 0x1c, 0x19, 0x81, - 0x1a, 0x10, 0x1c, 0x00, 0x1c, 0x12, 0x1d, 0xf7, 0x1e, 0x13, 0x20, 0x1c, 0x20, 0xe7, 0x22, 0x01, - 0x26, 0x01, 0x2a, 0x12, 0x2c, 0x0f, 0x30, 0xe7, 0x32, 0x15, 0x34, 0x1c, 0x36, 0x1c, 0x38, 0x12, - 0x3a, 0x55, 0x3f, 0x00, 0x41, 0x58, 0x43, 0x48, 0x46, 0x1c, 0x4e, 0xe4, 0x76, 0x02, 0x77, 0x57, - 0x78, 0x03, 0x89, 0x48, 0x8e, 0x90, 0x98, 0x80, 0x99, 0x00, 0xfe, 0x9c, 0xf0, 0x27, 0x02, 0xfe, - 0xe0, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xfe, 0xc6, 0x01, 0xfe, 0x56, 0x1a, 0x00, 0xfe, 0xc4, 0x01, - 0xfe, 0x84, 0x01, 0xff, 0x03, 0x00, 0x00, 0xfe, 0x6a, 0x13, 0xfe, 0x05, 0x05, 0xff, 0x40, 0x00, - 0x00, 0x0e, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x10, 0xff, 0xff, 0xff, 0x1f, - 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x11, 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, - 0xff, 0x21, 0x00, 0x00, 0xfe, 0x04, 0xf7, 0xfe, 0xc4, 0x01, 0x2e, 0x88, 0x0b, 0x01, 0xfe, 0xca, - 0x0f, 0xfe, 0x04, 0xf7, 0xfe, 0xc4, 0x01, 0x88, 0x0b, 0x1c, 0x2e, 0xfe, 0x3d, 0xf0, 0xfe, 0xfc, - 0x01, 0xfe, 0x20, 0xf0, 0xdc, 0x04, 0x5f, 0x4f, 0x02, 0xfe, 0xfc, 0x0d, 0x01, 0xfe, 0x5c, 0x0e, - 0xfe, 0xe9, 0x12, 0x02, 0xfe, 0x08, 0x03, 0xfe, 0x28, 0x1c, 0x04, 0xfe, 0xa6, 0x00, 0xfe, 0xdd, - 0x12, 0x47, 0x12, 0xfe, 0xa6, 0x00, 0xcd, 0xfe, 0x48, 0xf0, 0xfe, 0x80, 0x02, 0xfe, 0x49, 0xf0, - 0xfe, 0x9a, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xb8, 0x02, 0xfe, 0x46, 0xf0, 0xfe, 0x4a, 0x02, 0xfe, - 0x47, 0xf0, 0xfe, 0x50, 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x3e, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x42, - 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x46, 0x02, 0x09, 0x0b, 0xa4, 0x09, 0x06, 0x12, 0xc1, 0x02, 0x27, - 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02, 0x1c, 0xfe, 0xed, 0x10, 0xfe, 0x1e, 0x1c, 0xfe, - 0xe9, 0x10, 0x01, 0xfe, 0x2c, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xfe, 0xa8, 0x00, 0x0f, - 0x7c, 0x01, 0xaa, 0x02, 0x27, 0x17, 0x5e, 0x4c, 0xc4, 0x01, 0xfe, 0x40, 0x10, 0x0f, 0x7c, 0x01, - 0x8e, 0xfe, 0xbd, 0x10, 0x0f, 0x7c, 0x01, 0x8e, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, 0x58, - 0x1c, 0x09, 0x06, 0x12, 0xc1, 0x2e, 0x1b, 0x27, 0xfe, 0x3d, 0xf0, 0xfe, 0xfc, 0x01, 0x28, 0xfe, - 0x8e, 0x02, 0xfe, 0x5a, 0x1c, 0xde, 0xfe, 0x14, 0x1c, 0x17, 0xfe, 0x30, 0x00, 0x4c, 0xc4, 0x01, - 0xfe, 0x30, 0x10, 0x09, 0x06, 0x12, 0xc1, 0x02, 0xfe, 0xc6, 0x01, 0x29, 0x2d, 0x05, 0x10, 0x35, - 0xfe, 0x69, 0x10, 0x09, 0x06, 0x12, 0xc1, 0xfe, 0x04, 0xec, 0x2d, 0x08, 0x2d, 0x09, 0x3e, 0x1c, - 0x01, 0x45, 0x82, 0xfe, 0x05, 0xf6, 0xfe, 0xa8, 0x00, 0x01, 0xfe, 0x56, 0x17, 0x0a, 0x41, 0x8f, - 0x39, 0x11, 0x48, 0x1c, 0xd2, 0x08, 0x1e, 0x09, 0x52, 0x01, 0x90, 0x02, 0x27, 0x0f, 0x3f, 0x01, - 0x15, 0x05, 0x10, 0xdb, 0x08, 0x1e, 0x09, 0x52, 0x01, 0x7e, 0xfe, 0x28, 0x10, 0x0f, 0xc8, 0x01, - 0x15, 0xf2, 0x0f, 0x7d, 0x01, 0x15, 0xfe, 0x49, 0x54, 0x79, 0xfe, 0x16, 0x03, 0x08, 0x1e, 0x09, - 0x52, 0x01, 0x90, 0x02, 0x27, 0x2e, 0x82, 0xfe, 0x02, 0xe8, 0x31, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, - 0x43, 0xf7, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xdc, 0xfe, 0x40, 0x1c, 0x1b, 0xf8, 0xfe, 0x26, - 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x62, 0x03, 0xfe, 0x11, 0xf0, 0xdc, 0xfe, 0x0e, - 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x82, 0x03, 0xf4, 0x13, 0xfe, 0x11, 0x00, 0x02, 0x6b, 0x2e, 0xfe, - 0x48, 0x1c, 0xf4, 0x1b, 0xf8, 0x34, 0xf8, 0xfe, 0x82, 0xf0, 0xfe, 0x88, 0x03, 0x2b, 0x29, 0xc6, - 0x72, 0x16, 0xc6, 0x0f, 0x7d, 0x01, 0x15, 0x72, 0x80, 0x08, 0x1e, 0x09, 0x52, 0x01, 0x45, 0x11, - 0x3f, 0x08, 0x3f, 0x09, 0xa2, 0x01, 0x90, 0xfe, 0x9c, 0x32, 0x11, 0xfe, 0xe4, 0x00, 0x2f, 0xfe, - 0xce, 0x03, 0x1b, 0x32, 0x1f, 0xfe, 0xde, 0x03, 0x01, 0x55, 0xd3, 0xfe, 0xee, 0x03, 0x73, 0x97, - 0xd7, 0xfe, 0xae, 0x06, 0x02, 0x26, 0x04, 0x7c, 0x2c, 0x19, 0xfe, 0x20, 0x05, 0x17, 0x8b, 0x01, - 0x3b, 0x01, 0x9f, 0x01, 0xa1, 0x34, 0xfe, 0x60, 0x02, 0x02, 0xf6, 0xf4, 0x2e, 0x88, 0x18, 0xfe, - 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xf7, 0xfe, 0x48, 0x1c, 0x92, 0x01, 0xfe, 0x9c, 0x13, 0xb3, 0xfe, - 0x96, 0xf0, 0xfe, 0x28, 0x04, 0x2f, 0xfe, 0x2c, 0x04, 0x34, 0x27, 0x0f, 0x3f, 0x01, 0x15, 0x05, - 0x10, 0x19, 0xfe, 0x0c, 0x05, 0x4d, 0x7a, 0xa5, 0x31, 0x86, 0x76, 0x1b, 0x32, 0x1f, 0x26, 0x04, - 0x7c, 0x2c, 0xfe, 0x10, 0x12, 0x17, 0x8b, 0x01, 0x3b, 0x34, 0xfe, 0x60, 0x02, 0x02, 0xf6, 0x21, - 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x5e, 0x12, 0x0a, 0x07, 0x06, 0xfe, 0x56, 0x12, 0x24, - 0x23, 0x9a, 0x01, 0x0c, 0x86, 0x76, 0x1f, 0xfe, 0xdc, 0x04, 0x24, 0x23, 0x9a, 0x01, 0x0c, 0x1f, - 0x26, 0x24, 0x23, 0xba, 0xfe, 0x4c, 0x44, 0xfe, 0x32, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x08, 0xfe, - 0x93, 0x00, 0xfe, 0x4c, 0x54, 0x79, 0xfe, 0x0c, 0x05, 0x82, 0xa5, 0x31, 0xfe, 0x06, 0x80, 0xfe, - 0x48, 0x47, 0xfe, 0x48, 0x13, 0x40, 0x05, 0xfe, 0xcc, 0x00, 0xfe, 0x40, 0x13, 0x0a, 0x07, 0x06, - 0xef, 0xfe, 0x06, 0x10, 0x24, 0x23, 0xba, 0x0a, 0x07, 0x38, 0xe2, 0x17, 0xa9, 0x0a, 0x07, 0x06, - 0x4f, 0x17, 0xfe, 0x0d, 0x00, 0x01, 0x3b, 0x34, 0xfe, 0xa0, 0x0d, 0x02, 0x26, 0x3a, 0x11, 0xfe, - 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xb7, 0x03, 0x17, 0xa9, 0x01, 0x3b, 0x34, 0x27, 0x1b, 0x27, 0x02, - 0xfe, 0x14, 0x05, 0xfe, 0x42, 0x5b, 0x88, 0x18, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xf7, 0x17, - 0x46, 0xfe, 0x07, 0x80, 0xfe, 0x31, 0x44, 0x0a, 0x07, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, - 0x05, 0x18, 0xfe, 0x70, 0x12, 0x75, 0x07, 0x06, 0xfe, 0x60, 0x13, 0x04, 0xfe, 0xa2, 0x00, 0x2c, - 0x19, 0xfe, 0xac, 0x05, 0xfe, 0x31, 0xe4, 0x60, 0x75, 0x07, 0x0b, 0xfe, 0x4a, 0x13, 0x04, 0xfe, - 0xa0, 0x00, 0x2c, 0xfe, 0x42, 0x12, 0x63, 0x2f, 0xfe, 0x6c, 0x05, 0x1b, 0x32, 0xf9, 0x01, 0x0c, - 0x25, 0xfe, 0xc4, 0x05, 0x11, 0xfe, 0xe3, 0x00, 0x2b, 0x75, 0xfe, 0x4a, 0xf0, 0xfe, 0x96, 0x05, - 0xfe, 0x49, 0xf0, 0xfe, 0x90, 0x05, 0xad, 0x20, 0xfe, 0x21, 0x00, 0x8a, 0x20, 0xfe, 0x22, 0x00, - 0xa4, 0x20, 0x8f, 0xfe, 0x09, 0x48, 0x01, 0x0c, 0x25, 0xfe, 0xc4, 0x05, 0xfe, 0xe2, 0x08, 0x75, - 0x07, 0xe1, 0x4f, 0x01, 0xc2, 0x20, 0x06, 0x16, 0xe8, 0x4c, 0xfe, 0x27, 0x01, 0x0a, 0x07, 0x38, - 0xe9, 0x47, 0x01, 0xbd, 0x17, 0xa9, 0x0a, 0x07, 0x06, 0x4f, 0x17, 0xfe, 0x0d, 0x00, 0x01, 0x3b, - 0x01, 0x9f, 0x01, 0xa1, 0x34, 0xfe, 0xa0, 0x0d, 0x02, 0x26, 0x04, 0xfe, 0x9c, 0x00, 0x2c, 0xfe, - 0x3e, 0x12, 0x04, 0x5c, 0x2c, 0xfe, 0x36, 0x13, 0x47, 0x01, 0xbd, 0x25, 0xfe, 0x3c, 0x06, 0x0f, - 0x06, 0x75, 0x07, 0x22, 0xfe, 0x02, 0x12, 0x6a, 0x01, 0xfe, 0x06, 0x15, 0x1f, 0xfe, 0x32, 0x06, - 0x11, 0xc9, 0x01, 0x55, 0x11, 0xfe, 0xe5, 0x00, 0x04, 0x5c, 0xc3, 0x0d, 0x5c, 0x04, 0xfe, 0x9e, - 0x00, 0x2c, 0xfe, 0x62, 0x12, 0x04, 0x56, 0x2c, 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x7e, 0x19, 0x01, - 0xfe, 0xe8, 0x19, 0xf3, 0xa8, 0xf1, 0x08, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x6e, 0x81, 0x1a, 0x59, - 0xd1, 0xa8, 0x74, 0x47, 0x01, 0xbd, 0x25, 0xfe, 0xa6, 0x06, 0x75, 0x07, 0x1d, 0xab, 0x9e, 0x0f, - 0x5e, 0x01, 0xfe, 0x34, 0x15, 0x1f, 0xfe, 0x9c, 0x06, 0x11, 0xc9, 0x01, 0x55, 0x11, 0xfe, 0xe5, - 0x00, 0x04, 0x56, 0xc3, 0x0d, 0x56, 0x09, 0x06, 0x01, 0xbd, 0xfe, 0x9c, 0x32, 0x78, 0x92, 0x01, - 0xfe, 0x9c, 0x13, 0xb3, 0x11, 0xfe, 0xe2, 0x00, 0x2f, 0xfe, 0xbe, 0x06, 0x1b, 0x32, 0xd7, 0xfe, - 0xda, 0x06, 0x85, 0xfe, 0x78, 0x07, 0xd3, 0xfe, 0x80, 0x07, 0x73, 0x97, 0x02, 0x26, 0x0a, 0x07, - 0x0b, 0xfe, 0x2e, 0x12, 0x14, 0x18, 0x01, 0x0c, 0x14, 0x00, 0x01, 0x0c, 0x14, 0x00, 0x01, 0x0c, - 0x14, 0x00, 0x01, 0x0c, 0xfe, 0x99, 0xa4, 0x01, 0x0c, 0x14, 0x00, 0x02, 0xfe, 0x50, 0x08, 0x71, - 0x07, 0x1d, 0xef, 0x0a, 0x07, 0x1d, 0xfe, 0x30, 0x13, 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x0c, 0x14, - 0x00, 0x01, 0x0c, 0x14, 0x00, 0x01, 0x0c, 0x14, 0x00, 0x01, 0x0c, 0x14, 0x06, 0x01, 0x0c, 0x14, - 0x00, 0x02, 0xfe, 0x0a, 0x0c, 0x6a, 0xfe, 0x9a, 0x81, 0x6f, 0x8f, 0xfe, 0x09, 0x6f, 0xfe, 0x93, - 0x45, 0x19, 0xfe, 0x88, 0x07, 0x2f, 0xfe, 0x60, 0x07, 0x1b, 0x32, 0xd7, 0xfe, 0x58, 0x07, 0x73, - 0x97, 0x85, 0xfe, 0x78, 0x07, 0x02, 0x26, 0x01, 0x55, 0x02, 0xfe, 0xbe, 0x06, 0x14, 0x22, 0x02, - 0xfe, 0xbe, 0x06, 0xfe, 0x9c, 0xf7, 0xfe, 0xf0, 0x07, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x53, - 0xfe, 0xd6, 0x07, 0x0d, 0x66, 0x12, 0x67, 0x0a, 0x41, 0x60, 0x39, 0x01, 0xfe, 0x14, 0x19, 0x05, - 0x10, 0x87, 0xfe, 0x83, 0xe7, 0xfe, 0x95, 0x00, 0x8a, 0xfe, 0x03, 0x40, 0x0a, 0x41, 0x46, 0x39, - 0x01, 0xc5, 0xb6, 0xfe, 0x1f, 0x40, 0x16, 0x68, 0x01, 0xfe, 0xbe, 0x13, 0xfe, 0x08, 0x50, 0xfe, - 0x8a, 0x50, 0xfe, 0x34, 0x51, 0xfe, 0xb6, 0x51, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0d, 0x64, - 0x12, 0x65, 0xda, 0xfa, 0x0d, 0x3c, 0x12, 0x3d, 0xfe, 0x60, 0x10, 0x0a, 0x07, 0x60, 0xe9, 0xfe, - 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0d, 0x66, 0x12, 0x67, 0x0a, 0x07, 0x46, 0xd1, 0x01, 0xc5, 0xfe, - 0x1f, 0x80, 0x16, 0x68, 0xfe, 0x34, 0x90, 0xfe, 0xb6, 0x90, 0x0d, 0x43, 0x12, 0x44, 0xfe, 0x08, - 0x90, 0xfe, 0x8a, 0x90, 0x0d, 0x64, 0x12, 0x65, 0xa7, 0x07, 0x46, 0xdb, 0xda, 0xfa, 0x0d, 0x3c, - 0x12, 0x3d, 0xad, 0xfe, 0x28, 0x90, 0xfe, 0xaa, 0x90, 0x0d, 0x3c, 0x12, 0x3d, 0x0d, 0x30, 0x12, - 0x42, 0x2b, 0x0d, 0x54, 0x0d, 0x69, 0x0a, 0x41, 0x22, 0x39, 0x2e, 0x08, 0x84, 0x2f, 0xfe, 0x70, - 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x84, 0x08, 0xa3, 0x19, 0x32, 0x2e, 0x5b, 0xfe, 0xed, 0x10, 0xac, - 0xfe, 0xa8, 0x08, 0xae, 0xfe, 0xc4, 0x08, 0x85, 0xfe, 0x9c, 0x08, 0xd3, 0xfe, 0xa2, 0x08, 0x73, - 0x97, 0x02, 0x26, 0x01, 0x55, 0xfe, 0xc9, 0x10, 0x14, 0x22, 0xfe, 0xc9, 0x10, 0x71, 0x07, 0x06, - 0xfe, 0x10, 0x12, 0x71, 0x07, 0x0b, 0x50, 0x0a, 0x07, 0x0b, 0xfe, 0xa6, 0x12, 0xfe, 0x2e, 0x1c, - 0xb0, 0x71, 0x07, 0x06, 0x50, 0x71, 0x07, 0x0b, 0xfe, 0x92, 0x12, 0xfe, 0x2c, 0x1c, 0xa7, 0x07, - 0x46, 0xaf, 0xa7, 0x41, 0x46, 0xfe, 0x05, 0x40, 0xda, 0xfa, 0xfe, 0x28, 0x50, 0xfe, 0xaa, 0x50, - 0xfe, 0xaa, 0xf0, 0xfe, 0xf6, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x24, 0x09, 0x02, 0xfe, 0x02, 0x0a, - 0xfe, 0xb7, 0xf0, 0xfe, 0x20, 0x09, 0xfe, 0x02, 0xf6, 0x1d, 0x6a, 0xfe, 0x70, 0x18, 0xfe, 0xf1, - 0x18, 0xfe, 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, - 0xfe, 0x95, 0x59, 0x1b, 0x9b, 0xfe, 0x8c, 0xf0, 0xfe, 0x20, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x14, - 0x09, 0xed, 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x30, 0x09, 0x02, 0xfe, 0x3c, 0x0b, 0xee, - 0xfe, 0xbf, 0x10, 0xfe, 0x2b, 0xf0, 0x9b, 0xfe, 0x6b, 0x18, 0x1a, 0xfe, 0x00, 0xfe, 0xe2, 0xcd, - 0xfe, 0xd2, 0xf0, 0x9b, 0xfe, 0x76, 0x18, 0x1a, 0x18, 0x19, 0x9b, 0x04, 0xe7, 0x1a, 0x06, 0x19, - 0x9b, 0xac, 0x58, 0xae, 0x58, 0xed, 0xee, 0xfe, 0x89, 0x10, 0x92, 0x63, 0x3a, 0x17, 0xa9, 0x01, - 0x3b, 0x13, 0xfe, 0x35, 0x00, 0x34, 0x6b, 0x13, 0x93, 0x02, 0x6b, 0xfb, 0xb2, 0x0b, 0xfe, 0x1a, - 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18, 0xfe, 0x44, 0x54, 0xf0, 0xdf, 0xfe, 0x74, 0x18, - 0x94, 0x95, 0x19, 0xfe, 0xf2, 0x08, 0x02, 0x58, 0x0a, 0x07, 0x60, 0xaf, 0x04, 0x30, 0x2a, 0x42, - 0x0d, 0x43, 0x12, 0x44, 0x83, 0x30, 0x5a, 0x42, 0xfe, 0x6c, 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, - 0x54, 0xfe, 0xe5, 0x54, 0x36, 0x43, 0x21, 0x44, 0x04, 0x54, 0x2a, 0x69, 0x94, 0xfe, 0xe3, 0x54, - 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18, 0x94, 0xfe, 0xe3, 0x54, 0x95, 0xca, 0x53, 0xfe, 0xf2, 0x08, - 0x02, 0x58, 0xfe, 0x37, 0xf0, 0xfe, 0xfe, 0x09, 0xfe, 0x8b, 0xf0, 0xfe, 0x84, 0x09, 0x02, 0x58, - 0xfb, 0xb2, 0x0b, 0x28, 0xfe, 0x1e, 0x0b, 0x36, 0x54, 0x21, 0x69, 0x53, 0x7a, 0x08, 0xfe, 0xc0, - 0x07, 0x47, 0x62, 0x00, 0xd9, 0xfe, 0x01, 0x59, 0xfe, 0x52, 0xf0, 0xfe, 0x30, 0x0a, 0x94, 0x99, - 0xfe, 0x48, 0x0a, 0x36, 0x54, 0x94, 0xfe, 0xe3, 0x54, 0x4e, 0x54, 0x70, 0x69, 0xfe, 0x14, 0x58, - 0xfe, 0x95, 0x58, 0x02, 0x58, 0x36, 0x54, 0x21, 0x69, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xf0, - 0x4e, 0x54, 0x4e, 0x69, 0x02, 0x58, 0x0a, 0x07, 0x60, 0xfe, 0x82, 0x12, 0x0a, 0x07, 0x22, 0xfe, - 0x66, 0x13, 0x29, 0x68, 0x72, 0xd0, 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, - 0x04, 0x91, 0xfe, 0x86, 0x91, 0x6d, 0x31, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x53, 0xfe, 0xfa, - 0x08, 0x04, 0x66, 0x2a, 0x67, 0x0d, 0xb5, 0x12, 0x93, 0x4e, 0x66, 0x70, 0x67, 0x01, 0xc5, 0xb6, - 0x6d, 0x31, 0x16, 0x68, 0x83, 0x30, 0x5a, 0x42, 0x36, 0x43, 0x21, 0x44, 0x95, 0xca, 0xfe, 0x04, - 0xfa, 0x30, 0xfe, 0x05, 0xfa, 0x42, 0x01, 0xfe, 0xbe, 0x13, 0xfe, 0x36, 0x10, 0x2b, 0x0d, 0xb5, - 0x0d, 0x93, 0x36, 0x43, 0x21, 0x44, 0xb0, 0x0a, 0x07, 0x22, 0x19, 0xfe, 0xfa, 0x08, 0x36, 0x3c, - 0x21, 0x3d, 0x0a, 0x07, 0xfe, 0xf7, 0x00, 0x39, 0x04, 0x64, 0x2a, 0x65, 0xfe, 0x10, 0x58, 0xfe, - 0x91, 0x58, 0x4e, 0x54, 0x70, 0x69, 0x02, 0xfe, 0x18, 0x0a, 0x0a, 0x07, 0x22, 0x19, 0xfe, 0xfa, - 0x08, 0x0a, 0x07, 0xfe, 0xf7, 0x00, 0x39, 0xf0, 0xdf, 0x6a, 0xfe, 0x10, 0x90, 0xfe, 0x92, 0x90, - 0xfe, 0xd3, 0x10, 0x40, 0x05, 0xcb, 0x19, 0xfe, 0x2c, 0x09, 0x11, 0xcb, 0xfb, 0xb2, 0x0b, 0xfe, - 0x14, 0x13, 0x04, 0x3c, 0x2a, 0x3d, 0x53, 0xfe, 0x2c, 0x09, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, - 0x02, 0x58, 0x2b, 0x47, 0xfe, 0x19, 0x80, 0xfe, 0xf1, 0x10, 0x0a, 0x07, 0x0b, 0xab, 0xfe, 0x6c, - 0x19, 0xfe, 0x19, 0x41, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0x4e, 0x3c, 0xfe, 0xed, 0x19, 0x70, - 0x3d, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x1a, 0xfe, 0x00, 0xff, 0x35, 0xfe, - 0x74, 0x10, 0xcd, 0xfe, 0xd2, 0xf0, 0xfe, 0xb6, 0x0b, 0xfe, 0x76, 0x18, 0x1a, 0x18, 0xd6, 0x04, - 0xe7, 0x1a, 0x06, 0x89, 0x13, 0xfe, 0x16, 0x00, 0x02, 0x6b, 0xfe, 0xd1, 0xf0, 0xfe, 0xc8, 0x0b, - 0x17, 0x84, 0x01, 0x3b, 0x13, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xce, - 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xda, 0x0b, 0x13, 0xfe, 0x22, 0x00, 0x02, 0x6b, - 0xfe, 0xcb, 0xf0, 0xfe, 0xe6, 0x0b, 0x13, 0xfe, 0x24, 0x00, 0x02, 0x6b, 0xfe, 0xd0, 0xf0, 0xfe, - 0xf0, 0x0b, 0x13, 0xb1, 0xe0, 0xfe, 0xcf, 0xf0, 0xfe, 0xfa, 0x0b, 0x13, 0x8f, 0xdd, 0xfe, 0xcc, - 0xf0, 0xfe, 0x0a, 0x0c, 0xfe, 0x84, 0x80, 0xb2, 0x22, 0x4f, 0x13, 0xfe, 0x12, 0x00, 0x2e, 0x08, - 0x84, 0x2f, 0xfe, 0x10, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x24, 0x0c, 0xa3, 0x19, 0x32, 0x2e, 0x5b, - 0xfe, 0xed, 0x10, 0xac, 0x26, 0xae, 0x26, 0x2e, 0xfe, 0x9c, 0x32, 0x2f, 0xfe, 0x30, 0x0c, 0x1b, - 0x32, 0x85, 0xfe, 0x4c, 0x0c, 0x73, 0x97, 0xac, 0xfe, 0xf0, 0x07, 0xae, 0xfe, 0xf0, 0x07, 0x02, - 0x26, 0x01, 0x55, 0xfe, 0xdb, 0x10, 0x11, 0xfe, 0xe8, 0x00, 0xed, 0xee, 0x92, 0x86, 0x76, 0xfe, - 0x89, 0xf0, 0x26, 0x24, 0x23, 0xfe, 0xe9, 0x09, 0x01, 0x0c, 0x86, 0x76, 0x1f, 0x26, 0x24, 0x23, - 0x9a, 0x34, 0xfe, 0x88, 0x0c, 0x1b, 0x32, 0x02, 0xfe, 0x7c, 0x0c, 0xa3, 0x50, 0x13, 0xfe, 0x42, - 0x00, 0x02, 0x6b, 0xa6, 0x06, 0xfe, 0x81, 0x49, 0xfe, 0xcc, 0x12, 0x0a, 0x07, 0x0b, 0xfe, 0x5a, - 0x13, 0x13, 0x00, 0x61, 0x0b, 0xfe, 0x6a, 0x12, 0x61, 0xfe, 0x28, 0x00, 0x28, 0xfe, 0xce, 0x0d, - 0x0f, 0x7d, 0x01, 0x15, 0x05, 0x00, 0x89, 0x37, 0xfe, 0x28, 0x00, 0x02, 0xfe, 0xce, 0x0d, 0x01, - 0x9f, 0x01, 0xa1, 0x0f, 0xc8, 0x01, 0xfe, 0x24, 0x0f, 0xb9, 0x08, 0x3f, 0x09, 0xa2, 0x01, 0x45, - 0x11, 0x48, 0x08, 0x1e, 0x09, 0x52, 0x01, 0x7e, 0x02, 0x27, 0x13, 0xfe, 0x44, 0x00, 0x61, 0x0b, - 0xab, 0x37, 0x0b, 0xfe, 0xc0, 0x10, 0x01, 0xc2, 0x37, 0x0b, 0xfe, 0xb6, 0x10, 0x01, 0xc2, 0xfe, - 0x19, 0x82, 0xfe, 0x34, 0x46, 0xfe, 0x0a, 0x13, 0x37, 0x0b, 0x13, 0xfe, 0x43, 0x00, 0xfe, 0xa2, - 0x10, 0x0a, 0x41, 0x0b, 0x39, 0x01, 0x9f, 0x01, 0xa1, 0xb9, 0x08, 0x3f, 0x09, 0xa2, 0x01, 0x45, - 0x11, 0x48, 0x08, 0x1e, 0x09, 0x52, 0x01, 0x7e, 0x88, 0x0b, 0xb9, 0x1c, 0xd2, 0x02, 0xfe, 0x4c, - 0x03, 0x0a, 0x07, 0x0b, 0xd6, 0x37, 0x0b, 0x13, 0x00, 0xfe, 0x54, 0x10, 0x71, 0x07, 0x1d, 0xfe, - 0x50, 0x12, 0x0a, 0x07, 0x1d, 0xfe, 0x48, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x8c, - 0x0d, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x92, 0x0d, 0x0a, 0x41, 0x1d, 0x39, 0xfe, 0x95, - 0x10, 0x13, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0b, 0x6a, 0xfe, 0x26, 0x10, 0x13, 0xfe, 0x13, - 0x00, 0xdd, 0x13, 0xfe, 0x47, 0x00, 0x8a, 0x13, 0xfe, 0x41, 0x00, 0xa4, 0x13, 0xfe, 0x24, 0x00, - 0x04, 0x7c, 0x2c, 0x28, 0xf6, 0x6a, 0xfe, 0x04, 0xe6, 0x1d, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, - 0xb9, 0x01, 0xea, 0x02, 0x27, 0xde, 0x17, 0x0b, 0x4c, 0xfe, 0x9b, 0x00, 0xe5, 0x17, 0xfe, 0x31, - 0x00, 0x4c, 0xc4, 0x01, 0xfe, 0x30, 0x10, 0x02, 0xfe, 0xc6, 0x01, 0x1c, 0xfe, 0x06, 0xec, 0xfe, - 0xb9, 0x00, 0x8c, 0x37, 0x38, 0xc7, 0x35, 0x1c, 0xfe, 0x06, 0xea, 0xfe, 0xb9, 0x00, 0xfe, 0x47, - 0x4b, 0x9e, 0xfe, 0x75, 0x57, 0x04, 0x5f, 0xfe, 0x98, 0x56, 0xfe, 0x28, 0x12, 0x0f, 0x7d, 0xfe, - 0xf4, 0x14, 0x47, 0xf2, 0x0f, 0xc8, 0xfe, 0xea, 0x14, 0xfe, 0x49, 0x54, 0x98, 0xfe, 0x42, 0x0e, - 0x0f, 0x1e, 0xfe, 0xde, 0x14, 0xfe, 0x44, 0x48, 0x02, 0xfe, 0x4c, 0x03, 0x0f, 0x5f, 0xfe, 0xc8, - 0x14, 0x8c, 0x37, 0x38, 0xc7, 0x35, 0x1c, 0xfe, 0xce, 0x47, 0xfe, 0xbd, 0x13, 0x02, 0x27, 0x29, - 0x2d, 0x05, 0x10, 0xfe, 0x78, 0x12, 0x2b, 0x16, 0x5e, 0x16, 0xb4, 0x29, 0x48, 0x47, 0x4c, 0x48, - 0xa3, 0xd9, 0xfe, 0xbc, 0xf0, 0xfe, 0xde, 0x0e, 0x08, 0x06, 0x16, 0x5e, 0x01, 0xfe, 0xe6, 0x16, - 0x04, 0xfe, 0x38, 0x01, 0x2a, 0xfe, 0x3a, 0x01, 0x53, 0xfe, 0xe2, 0x0e, 0x04, 0xfe, 0x38, 0x01, - 0x1a, 0xfe, 0xf0, 0xff, 0x0d, 0xfe, 0x60, 0x01, 0x04, 0xfe, 0x3a, 0x01, 0x0d, 0xfe, 0x62, 0x01, - 0x20, 0x06, 0x16, 0x48, 0xfe, 0x04, 0xec, 0x2d, 0x08, 0x2d, 0x09, 0x3e, 0x1c, 0x01, 0x45, 0x82, - 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x56, 0x17, 0x11, 0x48, 0xd2, 0x08, 0x06, 0x03, - 0x2b, 0x03, 0x29, 0x5e, 0xfe, 0xf7, 0x12, 0x29, 0xb4, 0x72, 0x16, 0xb4, 0x05, 0x84, 0xfe, 0x93, - 0x13, 0xfe, 0x24, 0x1c, 0x17, 0x18, 0x4c, 0xfe, 0x9b, 0x00, 0xe5, 0xfe, 0xd9, 0x10, 0x9c, 0xfe, - 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0x9c, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, - 0xfe, 0x80, 0x5d, 0x03, 0xfe, 0x03, 0x57, 0x9c, 0x2b, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, - 0x9c, 0x80, 0x03, 0x01, 0xfe, 0x8e, 0x17, 0x40, 0x05, 0x48, 0xfe, 0x0a, 0x13, 0x08, 0x1e, 0x09, - 0x52, 0xdd, 0x01, 0x9f, 0x01, 0xa1, 0x08, 0x3f, 0x09, 0xa2, 0x01, 0x45, 0x11, 0xfe, 0xe9, 0x00, - 0x0a, 0x07, 0x8f, 0xfe, 0x52, 0x13, 0x01, 0xfe, 0x18, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, - 0x0d, 0xfe, 0x64, 0x01, 0xfe, 0x16, 0x90, 0x0d, 0xfe, 0x66, 0x01, 0x0a, 0x07, 0x46, 0xef, 0xfe, - 0x03, 0x80, 0x5b, 0x4d, 0x11, 0x7b, 0x08, 0x2d, 0x09, 0x3e, 0x1c, 0x7a, 0x01, 0x90, 0xfe, 0x62, - 0x08, 0x72, 0x4d, 0x11, 0x7b, 0x08, 0x2d, 0x09, 0x3e, 0x1c, 0x7a, 0x01, 0x90, 0x6d, 0x31, 0x11, - 0x7b, 0x08, 0x2d, 0x09, 0x3e, 0x1c, 0x7a, 0x01, 0x7e, 0x03, 0xfe, 0x08, 0x1c, 0x04, 0xfe, 0xac, - 0x00, 0xfe, 0x06, 0x58, 0x04, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x04, 0xfe, 0xb0, 0x00, 0xfe, - 0x08, 0x58, 0x04, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x20, 0x74, 0x16, 0xfe, - 0xb9, 0x00, 0x2b, 0x0d, 0x5c, 0x0d, 0x56, 0x20, 0x10, 0x16, 0x2d, 0x16, 0x3e, 0x51, 0xa6, 0xfe, - 0x93, 0x00, 0x08, 0x2d, 0x09, 0x3e, 0x1c, 0x01, 0x7e, 0x82, 0x11, 0x7b, 0xfe, 0x14, 0x56, 0xfe, - 0xd6, 0xf0, 0x8a, 0xde, 0x92, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x1c, - 0xfe, 0x0c, 0x14, 0x8c, 0xfe, 0x07, 0xe6, 0x38, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, - 0xc2, 0x0f, 0x3f, 0x01, 0x15, 0x05, 0x10, 0xdb, 0x0f, 0x1e, 0x01, 0x15, 0x05, 0x10, 0xe2, 0xfe, - 0x44, 0x58, 0x4d, 0xfe, 0x01, 0xec, 0xc4, 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, - 0xe7, 0x1d, 0xa5, 0x31, 0x01, 0xea, 0xfe, 0xc9, 0x10, 0x03, 0x2e, 0x86, 0x76, 0x24, 0x23, 0xba, - 0x05, 0x1d, 0xfe, 0x48, 0x12, 0x05, 0x0b, 0xfe, 0x4c, 0x12, 0x05, 0x18, 0xfe, 0x30, 0x12, 0x05, - 0xd4, 0x19, 0xfe, 0xd4, 0x11, 0x05, 0xfe, 0x23, 0x00, 0x19, 0xfe, 0xe0, 0x11, 0x05, 0x06, 0x19, - 0xfe, 0x3e, 0x12, 0x05, 0x22, 0xfe, 0x12, 0x12, 0x05, 0x00, 0x19, 0x26, 0x17, 0xd4, 0x01, 0x3b, - 0xce, 0x3a, 0x01, 0x0c, 0x85, 0x55, 0x03, 0x3a, 0x11, 0xfe, 0xcc, 0x00, 0x02, 0x27, 0x3a, 0x40, - 0x05, 0xcb, 0xfe, 0xe3, 0x13, 0x36, 0x3c, 0x21, 0x3d, 0x53, 0xfe, 0x92, 0x11, 0x0a, 0x07, 0x60, - 0xfe, 0x72, 0x12, 0x83, 0x30, 0x5a, 0x42, 0x95, 0xca, 0x98, 0xfe, 0x5c, 0x11, 0x29, 0x68, 0xfe, - 0x26, 0x13, 0x04, 0xb5, 0x2a, 0x93, 0x53, 0xfe, 0xb2, 0x0d, 0x0d, 0x66, 0x12, 0x67, 0x2b, 0x0d, - 0xb5, 0x0d, 0x93, 0x01, 0xc5, 0x20, 0x74, 0x5b, 0x16, 0x68, 0x01, 0xfe, 0xbe, 0x13, 0x83, 0x30, - 0x5a, 0x42, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x30, 0xfe, 0x05, 0xfa, 0x42, - 0xfe, 0x91, 0x10, 0x04, 0x43, 0x2a, 0x44, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0d, 0x43, 0x12, - 0x44, 0xad, 0x83, 0x30, 0x5a, 0x42, 0x95, 0xca, 0x04, 0x64, 0x2a, 0x65, 0xfe, 0x00, 0x56, 0xfe, - 0xa1, 0x56, 0x0d, 0x64, 0x12, 0x65, 0x0a, 0x07, 0x60, 0xfe, 0x1e, 0x12, 0x29, 0x68, 0xfe, 0x1f, - 0x40, 0x04, 0x66, 0x2a, 0x67, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x04, 0x43, 0x2a, 0x44, 0xfe, - 0x34, 0x50, 0xfe, 0xb6, 0x50, 0x04, 0x64, 0x2a, 0x65, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x04, - 0x3c, 0x2a, 0x3d, 0xfe, 0x28, 0x50, 0xfe, 0xaa, 0x50, 0x02, 0xa0, 0x20, 0x06, 0x16, 0xfc, 0x02, - 0x7f, 0x3a, 0x01, 0x0c, 0x1f, 0x57, 0x24, 0x23, 0xba, 0x05, 0x06, 0x28, 0x57, 0x40, 0x05, 0xcb, - 0x28, 0x7f, 0x01, 0xfe, 0x9c, 0x13, 0x1a, 0x59, 0x19, 0x57, 0x0a, 0x07, 0x0b, 0xe4, 0x36, 0x3c, - 0x21, 0x3d, 0xfe, 0x0a, 0x55, 0x35, 0xfe, 0x8b, 0x55, 0x4e, 0x3c, 0x70, 0x3d, 0xfe, 0x0c, 0x51, - 0xfe, 0x8e, 0x51, 0x02, 0x7f, 0xdf, 0xfe, 0x0a, 0x45, 0xfe, 0x19, 0x41, 0x02, 0x7f, 0x3a, 0x01, - 0x0c, 0x1f, 0xfe, 0xd6, 0x10, 0x24, 0x23, 0xfe, 0xe9, 0x09, 0x61, 0x18, 0xfe, 0x94, 0x12, 0x61, - 0x0b, 0x4f, 0x02, 0x57, 0x2f, 0xfe, 0x5e, 0x12, 0x1b, 0x32, 0x1f, 0xfe, 0xd6, 0x10, 0x24, 0x23, - 0x9a, 0x05, 0x18, 0x28, 0x57, 0x01, 0x0c, 0x1f, 0xfe, 0xd6, 0x10, 0x24, 0x23, 0xfe, 0xe8, 0x09, - 0x51, 0x04, 0xfe, 0x9c, 0x00, 0x2c, 0x35, 0xfe, 0xbb, 0x45, 0x61, 0x00, 0x50, 0x37, 0x06, 0xa6, - 0x59, 0xfe, 0xc0, 0x14, 0xfe, 0xf8, 0x14, 0xb3, 0x40, 0x05, 0xc9, 0xfe, 0x16, 0x13, 0x04, 0xfe, - 0x9e, 0x00, 0x2c, 0xd6, 0x04, 0x56, 0x2c, 0x35, 0x63, 0x02, 0x7f, 0xfe, 0xc0, 0x5d, 0xfe, 0xe4, - 0x14, 0xfe, 0x03, 0x17, 0x04, 0x5c, 0xc3, 0x0d, 0x5c, 0x63, 0x3a, 0x01, 0x0c, 0x25, 0xa0, 0x01, - 0xfe, 0x06, 0x15, 0x02, 0xa0, 0x2f, 0xfe, 0xe8, 0x12, 0x1b, 0x32, 0x1f, 0x57, 0x24, 0x23, 0x9a, - 0x05, 0x06, 0x28, 0x57, 0xfe, 0xf6, 0x14, 0xfe, 0x42, 0x58, 0xfe, 0x70, 0x14, 0xfe, 0x92, 0x14, - 0xb3, 0xfe, 0x4a, 0xf4, 0x0b, 0x19, 0x57, 0xfe, 0x4a, 0xf4, 0x06, 0xd8, 0x40, 0x05, 0xc9, 0xd1, - 0x02, 0x7f, 0x04, 0x56, 0xc3, 0x0d, 0x56, 0x63, 0x3a, 0x01, 0x0c, 0x25, 0xa0, 0x01, 0xfe, 0x34, - 0x15, 0x02, 0xa0, 0x25, 0xfe, 0x50, 0x13, 0x78, 0xf9, 0x78, 0x03, 0x34, 0xfe, 0x4c, 0x13, 0x73, - 0xfe, 0x4c, 0x13, 0x63, 0x3a, 0x01, 0x0c, 0xfe, 0xe3, 0x10, 0x08, 0x6c, 0xff, 0x02, 0x00, 0x57, - 0x6e, 0x81, 0x1a, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x08, 0x6c, 0xff, - 0x02, 0x00, 0x57, 0x6e, 0x81, 0x1a, 0x59, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x08, 0x6c, - 0xff, 0x02, 0x00, 0x57, 0x6e, 0x81, 0x03, 0x08, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x6e, 0x81, 0xfe, - 0x0b, 0x58, 0x03, 0x0f, 0x5c, 0x01, 0x8e, 0x0f, 0x56, 0x01, 0x8e, 0x03, 0xd0, 0x1a, 0x10, 0xff, - 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x22, 0x6e, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, - 0x7d, 0xfe, 0x03, 0x7c, 0x6d, 0x31, 0x0d, 0x64, 0x12, 0x65, 0x4e, 0x43, 0x70, 0x44, 0x03, 0xfe, - 0x62, 0x18, 0xfe, 0x82, 0x5a, 0xfe, 0xe1, 0x1a, 0xbf, 0xfe, 0x02, 0x58, 0x03, 0x01, 0xfe, 0x7e, - 0x19, 0xfe, 0x42, 0x48, 0x6a, 0x51, 0x9e, 0x01, 0x0c, 0x1f, 0xfe, 0xfe, 0x14, 0x24, 0x23, 0xfe, - 0xe9, 0x09, 0xfe, 0xc1, 0x59, 0x01, 0x0c, 0x1f, 0xfe, 0xfe, 0x14, 0x24, 0x23, 0xfe, 0xe8, 0x0a, - 0x04, 0xfe, 0x9e, 0x00, 0x2c, 0xfe, 0xc4, 0x12, 0x2b, 0xb8, 0x1d, 0xe4, 0x61, 0xd5, 0x79, 0xfe, - 0x4c, 0x14, 0x4f, 0x08, 0x06, 0x09, 0xd5, 0xa6, 0xfe, 0x00, 0x10, 0xfe, 0x78, 0x10, 0xff, 0x02, - 0x83, 0x55, 0x8a, 0xff, 0x02, 0x83, 0x55, 0xb8, 0x18, 0xfe, 0x12, 0x13, 0x62, 0xfe, 0x30, 0x00, - 0x98, 0xfe, 0xa6, 0x14, 0x09, 0x8b, 0x08, 0x06, 0xfe, 0x56, 0x10, 0xb8, 0x0b, 0xfe, 0x16, 0x13, - 0x62, 0xfe, 0x64, 0x00, 0x98, 0xfe, 0xa6, 0x14, 0x0f, 0xfe, 0x64, 0x00, 0x09, 0xb1, 0x08, 0x06, - 0xfe, 0x28, 0x10, 0xb8, 0x06, 0xfe, 0x60, 0x13, 0x62, 0xfe, 0xc8, 0x00, 0x98, 0xfe, 0xa6, 0x14, - 0x0f, 0xfe, 0xc8, 0x00, 0x09, 0x5e, 0x08, 0x06, 0xad, 0x62, 0xfe, 0x90, 0x01, 0x99, 0xfe, 0xb2, - 0x14, 0x9e, 0xb0, 0xfe, 0x43, 0xf4, 0xb4, 0xfe, 0x56, 0xf0, 0xfe, 0xc4, 0x14, 0xfe, 0x04, 0xf4, - 0x6c, 0xfe, 0x43, 0xf4, 0xb1, 0xfe, 0xf3, 0x10, 0xb7, 0x01, 0xfe, 0x8e, 0x13, 0x1a, 0x59, 0xaf, - 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x74, 0x99, 0xfe, 0xf8, 0x14, 0xa8, 0x74, 0xfe, 0x14, 0x10, - 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0xf1, 0x99, 0xfe, 0xf8, 0x14, 0xa8, 0xf1, 0xa4, 0x51, 0x9e, - 0x08, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x03, 0x51, 0x08, 0x0b, 0x03, 0x14, 0x06, 0x01, - 0x0c, 0x25, 0xec, 0x14, 0x0b, 0x01, 0x0c, 0x25, 0xec, 0x14, 0x18, 0x01, 0x0c, 0x25, 0xec, 0x78, - 0xfe, 0x89, 0x49, 0x01, 0x0c, 0x03, 0x14, 0x06, 0x01, 0x0c, 0x25, 0xbc, 0x14, 0x18, 0x01, 0x0c, - 0x25, 0xbc, 0x14, 0x06, 0x01, 0x0c, 0x25, 0xbc, 0xfe, 0x89, 0x49, 0x01, 0x0c, 0x25, 0xbc, 0x78, - 0xfe, 0x89, 0x4a, 0x01, 0x0c, 0x03, 0x51, 0x03, 0x29, 0xe8, 0x05, 0x06, 0x3b, 0xb6, 0x16, 0xe8, - 0xfe, 0x49, 0xf4, 0x00, 0x4f, 0x78, 0xce, 0x63, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf9, 0x01, - 0x0c, 0x40, 0x05, 0xfe, 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0xb6, 0x15, 0x2b, 0x16, 0xfc, - 0x01, 0x55, 0x29, 0xfc, 0x05, 0x06, 0x50, 0x0a, 0x41, 0x06, 0x39, 0x03, 0x0d, 0x5d, 0x12, 0x91, - 0xfe, 0x43, 0x58, 0x01, 0x15, 0x05, 0x10, 0xfe, 0x1e, 0x12, 0x4a, 0xf3, 0x96, 0x01, 0x49, 0xfe, - 0x90, 0x4d, 0xe6, 0x10, 0xfe, 0xc5, 0x59, 0x01, 0x49, 0xfe, 0x8d, 0x56, 0xbf, 0x4a, 0x03, 0x4a, - 0x21, 0x91, 0x01, 0x15, 0x4a, 0x96, 0x01, 0x49, 0xeb, 0x10, 0xe6, 0x10, 0x21, 0x5d, 0x62, 0x1e, - 0x89, 0x0f, 0x5f, 0x01, 0xaa, 0x03, 0x0d, 0x5d, 0x12, 0x91, 0xfe, 0xc3, 0x58, 0x01, 0x15, 0x05, - 0x10, 0xfe, 0x1a, 0x12, 0x4a, 0xf3, 0x96, 0x01, 0x49, 0xeb, 0x10, 0xfe, 0x80, 0x4d, 0xfe, 0xc5, - 0x59, 0x01, 0x49, 0x4a, 0x03, 0x4a, 0x21, 0x5d, 0x01, 0x15, 0x4a, 0x96, 0x01, 0x49, 0xeb, 0x10, - 0xe6, 0x10, 0x21, 0x5d, 0x62, 0x1e, 0x89, 0x0f, 0x5f, 0x01, 0xaa, 0x03, 0x0d, 0x5d, 0x12, 0x91, - 0xfe, 0x43, 0x58, 0x01, 0x15, 0xfe, 0x42, 0x48, 0x96, 0x01, 0x49, 0xfe, 0xc0, 0x5a, 0xb7, 0xfe, - 0x00, 0xcd, 0xfe, 0x01, 0xcc, 0xfe, 0x4a, 0x46, 0xe4, 0x9c, 0x80, 0x05, 0x10, 0xfe, 0x2e, 0x13, - 0x5a, 0x5d, 0xfe, 0x4d, 0xf4, 0x1e, 0xfe, 0x1c, 0x13, 0x0f, 0x5f, 0x01, 0x8e, 0xb0, 0xfe, 0x40, - 0x4c, 0xfe, 0xc5, 0x58, 0x01, 0x49, 0xfe, 0x00, 0x07, 0x80, 0x05, 0x10, 0x89, 0x5a, 0x91, 0xfe, - 0x05, 0x57, 0xfe, 0x08, 0x10, 0xfe, 0x45, 0x58, 0x01, 0x49, 0xfe, 0x8d, 0x56, 0xbf, 0xfe, 0x80, - 0x4c, 0xfe, 0x05, 0x17, 0x03, 0x09, 0x10, 0x77, 0x6f, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, - 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xe3, 0x38, 0x9d, 0xfe, 0xfa, 0x16, 0x01, 0xfe, 0x08, 0x18, 0xd9, - 0x8d, 0x38, 0x6f, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xc0, 0x28, 0xfe, 0xea, 0x16, 0xfe, - 0xe2, 0x10, 0x09, 0x10, 0x77, 0x04, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x22, 0xfe, 0x18, 0x58, - 0x04, 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0x8d, 0x22, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06, - 0xfe, 0x3c, 0x50, 0x6f, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x22, 0x9d, 0xfe, - 0x44, 0x17, 0xfe, 0xbe, 0x14, 0x35, 0x03, 0xc0, 0x28, 0xfe, 0x1c, 0x17, 0xfe, 0xa4, 0x10, 0x09, - 0x10, 0x77, 0xbf, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xdf, 0xe3, 0x30, 0x9d, 0xfe, 0x66, 0x17, 0xfe, - 0x9c, 0x14, 0xfe, 0x18, 0x13, 0x8d, 0x30, 0x6f, 0x1d, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, - 0xa7, 0x07, 0xfe, 0x7f, 0x00, 0xfe, 0x05, 0x40, 0x03, 0xc0, 0x28, 0xfe, 0x5a, 0x17, 0xfe, 0x6c, - 0x10, 0x09, 0x10, 0x77, 0xfe, 0x30, 0xbc, 0xfe, 0xb2, 0xbc, 0x8d, 0xe1, 0x6f, 0x1d, 0xfe, 0x0f, - 0x79, 0xfe, 0x1c, 0xf7, 0xe1, 0x9d, 0xfe, 0xa6, 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x03, 0xc0, 0x28, - 0xfe, 0x92, 0x17, 0xfe, 0x42, 0x10, 0xfe, 0x02, 0xf6, 0x10, 0x77, 0xfe, 0x18, 0xfe, 0x66, 0xfe, - 0x19, 0xfe, 0x67, 0xd0, 0xe3, 0x46, 0x9d, 0xfe, 0xcc, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, - 0x8d, 0x46, 0x47, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, - 0x10, 0x11, 0xfe, 0xdd, 0x00, 0x6d, 0x31, 0x03, 0x6d, 0x31, 0xfe, 0x12, 0x45, 0x28, 0xfe, 0xbc, - 0x17, 0x17, 0x06, 0x4c, 0xfe, 0x9b, 0x00, 0xe5, 0x02, 0x27, 0xfe, 0x39, 0xf0, 0xfe, 0x10, 0x18, - 0x2b, 0x03, 0xfe, 0x7e, 0x18, 0x1a, 0x18, 0x87, 0x08, 0x0e, 0x03, 0x77, 0x04, 0xe7, 0x1a, 0x06, - 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x1c, 0x0f, 0x1e, 0x01, 0x15, 0x05, 0x10, 0x50, 0x4d, 0xfe, - 0x78, 0x14, 0xfe, 0x34, 0x12, 0x59, 0x8c, 0x37, 0x38, 0xc7, 0xfe, 0xe9, 0x13, 0x1c, 0x0f, 0x3f, - 0x01, 0x15, 0x05, 0x10, 0x50, 0x4d, 0xfe, 0x56, 0x14, 0xe9, 0x59, 0x8c, 0x37, 0x38, 0xc7, 0xfe, - 0xe9, 0x13, 0x09, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x13, 0xfe, 0x15, 0x00, 0x7a, 0xa5, 0x31, - 0x01, 0xea, 0x09, 0x06, 0x03, 0x0a, 0x41, 0x38, 0x39, 0x08, 0x3f, 0x09, 0xa2, 0x01, 0x45, 0x11, - 0x48, 0x08, 0x1e, 0x09, 0x52, 0x01, 0x7e, 0x09, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, - 0x36, 0xfe, 0xa8, 0x00, 0x21, 0x7b, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x03, 0x29, 0xc6, - 0x5b, 0x16, 0xc6, 0x03, 0x0f, 0xc8, 0x01, 0x15, 0xf2, 0x0f, 0x7d, 0x01, 0x15, 0xfe, 0x49, 0x44, - 0x28, 0xfe, 0x06, 0x19, 0x0f, 0x1e, 0x01, 0x15, 0x05, 0x10, 0x50, 0x0f, 0x5f, 0x01, 0xaa, 0x0f, - 0x7d, 0x01, 0x15, 0x5b, 0x80, 0x03, 0xfe, 0x40, 0x5e, 0xfe, 0xe2, 0x08, 0xfe, 0xc0, 0x4c, 0x29, - 0x3e, 0x05, 0x10, 0xfe, 0x52, 0x12, 0x4d, 0x05, 0x00, 0xfe, 0x18, 0x12, 0xfe, 0xe1, 0x18, 0xfe, - 0x19, 0xf4, 0xfe, 0x7f, 0x00, 0xaf, 0xfe, 0xe2, 0x08, 0x5b, 0x4d, 0x40, 0x05, 0x7b, 0xab, 0xfe, - 0x82, 0x48, 0xfe, 0x01, 0x80, 0xfe, 0xd7, 0x10, 0xfe, 0xc4, 0x48, 0x08, 0x2d, 0x09, 0x3e, 0xfe, - 0x40, 0x5f, 0x1c, 0x01, 0x45, 0x11, 0xfe, 0xdd, 0x00, 0xfe, 0x14, 0x46, 0x08, 0x2d, 0x09, 0x3e, - 0x01, 0x45, 0x11, 0xfe, 0xdd, 0x00, 0xfe, 0x40, 0x4a, 0x72, 0xfe, 0x06, 0x17, 0xfe, 0x01, 0x07, - 0xfe, 0x82, 0x48, 0xfe, 0x04, 0x17, 0x03, 0xf5, 0x18, 0x79, 0xfe, 0x8e, 0x19, 0x04, 0xfe, 0x90, - 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xf5, 0xd4, 0x79, 0xfe, 0xa0, 0x19, 0x04, 0xfe, 0x92, - 0x00, 0xcf, 0x1d, 0xe0, 0xf5, 0xfe, 0x0b, 0x00, 0x79, 0xfe, 0xb2, 0x19, 0x04, 0xfe, 0x94, 0x00, - 0xcf, 0x22, 0xfe, 0x08, 0x10, 0x04, 0xfe, 0x96, 0x00, 0xcf, 0x8b, 0xfe, 0x4e, 0x45, 0xd8, 0xfe, - 0x0a, 0x45, 0xff, 0x04, 0x68, 0x54, 0xfe, 0xf1, 0x10, 0x1a, 0x74, 0xfe, 0x08, 0x1c, 0xfe, 0x67, - 0x19, 0xfe, 0x0a, 0x1c, 0xfe, 0x1a, 0xf4, 0xfe, 0x00, 0x04, 0xd8, 0xfe, 0x48, 0xf4, 0x18, 0x99, - 0xfe, 0xe6, 0x19, 0x08, 0x18, 0x03, 0x05, 0x84, 0xfe, 0x5a, 0xf0, 0xfe, 0xf6, 0x19, 0x20, 0xfe, - 0x09, 0x00, 0xfe, 0x34, 0x10, 0x05, 0x1d, 0xfe, 0x5a, 0xf0, 0xfe, 0x04, 0x1a, 0x20, 0xd5, 0xfe, - 0x26, 0x10, 0x05, 0x18, 0x87, 0x20, 0x8b, 0xe0, 0x05, 0x0b, 0x87, 0x20, 0xb1, 0xfe, 0x0e, 0x10, - 0x05, 0x06, 0x87, 0x20, 0x5e, 0xce, 0xb6, 0x03, 0x17, 0xfe, 0x09, 0x00, 0x01, 0x3b, 0x2f, 0xfe, - 0x34, 0x1a, 0x04, 0x76, 0xb7, 0x03, 0x1b, 0xfe, 0x54, 0x1a, 0xfe, 0x14, 0xf0, 0x0c, 0x2f, 0xfe, - 0x48, 0x1a, 0x1b, 0xfe, 0x54, 0x1a, 0xfe, 0x82, 0xf0, 0xfe, 0x4c, 0x1a, 0x03, 0xff, 0x15, 0x00, - 0x00, + 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4, 0x01, 0x00, 0x48, 0xe4, + 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff, 0x1c, 0x0f, 0x00, 0xf6, + 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0, + 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0, 0x18, 0xf4, 0x08, 0x00, + 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6, 0x86, 0xf0, 0xb1, 0xf0, + 0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x3c, 0x00, 0xbb, 0x00, + 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13, 0xba, 0x13, 0x18, 0x40, + 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x74, 0x01, + 0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01, + 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12, 0x08, 0x12, 0x02, 0x4a, + 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x5d, 0xf0, 0x02, 0xfa, + 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, + 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d, 0x06, 0x13, 0x4c, 0x1c, + 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00, 0x0f, 0x00, 0x47, 0x00, + 0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, + 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa, 0x05, 0x00, 0x34, 0x00, + 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b, 0x42, 0x0c, 0x12, 0x0f, + 0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48, 0x00, 0x4e, 0x42, 0x54, + 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xb8, 0xf0, + 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, + 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xe2, 0x03, + 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13, 0x12, 0x13, 0x24, 0x14, + 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, + 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x3a, 0x55, 0x83, 0x55, + 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0, 0x0c, 0xf0, 0x04, 0xf8, + 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00, + 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01, 0xc4, 0x01, 0xc6, 0x01, + 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08, 0x68, 0x08, 0x69, 0x08, + 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10, 0xed, 0x10, 0xf1, 0x10, + 0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x46, 0x14, + 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18, 0xca, 0x18, 0xe6, 0x19, + 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c, 0xf0, 0x2b, 0x02, 0xfe, + 0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6, 0xfe, 0x84, 0x01, 0xff, + 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00, 0x00, 0xfe, 0x57, 0x24, + 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, + 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x11, + 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, 0xfe, 0x04, 0xf7, 0xd6, + 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99, 0x0a, 0x42, 0x2c, 0xfe, + 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, + 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d, 0x02, 0xfe, 0xc8, 0x0d, + 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6, + 0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48, 0xf0, 0xfe, 0x8a, 0x02, + 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02, 0xfe, 0x46, 0xf0, 0xfe, + 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x44, + 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a, 0xaa, 0x18, 0x06, 0x14, + 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9, + 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce, 0x09, 0x70, 0x01, 0xa8, + 0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xbd, + 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, 0x58, 0x1c, 0x18, 0x06, + 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23, 0xfe, 0x98, 0x02, 0xfe, + 0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, + 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe, 0x69, 0x10, 0x18, 0x06, + 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05, 0xf6, 0xce, 0x01, 0xfe, + 0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b, + 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x09, + 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b, + 0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, + 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x40, 0x1c, 0x1c, + 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48, 0x03, 0xfe, 0x11, 0xf0, + 0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10, 0xfe, 0x11, 0x00, 0x02, + 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13, 0x21, 0x22, 0xa3, 0xb7, + 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16, 0x12, 0xd1, 0x1c, 0xd9, + 0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12, 0xfe, 0xe4, 0x00, 0x27, + 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe, 0x06, 0xf0, 0xfe, 0xc8, + 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03, 0x70, 0x28, 0x17, 0xfe, + 0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8, 0xf9, 0x2c, 0x99, 0x19, + 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c, 0x74, 0x01, 0xaf, 0x8c, + 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e, 0x8d, 0x51, 0x64, 0x79, + 0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, + 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d, 0xfe, 0x3c, 0x04, 0x3b, + 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02, 0x00, 0x10, 0x01, 0x0b, + 0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde, 0xfe, 0x4c, 0x44, 0xfe, + 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b, 0xda, 0x4f, 0x79, 0x2a, + 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x2a, 0x13, 0x32, + 0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b, 0xda, 0xfe, + 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x08, 0x13, 0x32, 0x07, + 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, + 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x2d, 0x12, 0xfe, 0xe6, + 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36, 0x02, 0x2b, 0xfe, 0x42, + 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x87, 0x80, 0xfe, + 0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x19, 0xfe, 0x7c, + 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28, 0x17, 0xfe, 0x90, 0x05, + 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x28, 0xfe, + 0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c, 0x34, 0xfe, 0x89, 0x48, + 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0x12, 0xfe, 0xe3, 0x00, + 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0x70, 0x05, 0x88, 0x25, + 0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe, 0x09, 0x48, 0xff, 0x02, + 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2, 0x08, 0x53, 0x05, 0xcb, + 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08, 0x05, 0x1b, 0xfe, 0x22, + 0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, + 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb, 0x03, 0x5c, 0x28, 0xfe, + 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53, 0x05, 0x1f, 0xfe, 0x02, + 0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, + 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62, 0x12, 0x03, 0x45, 0x28, + 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe, 0x43, 0x48, 0xc4, 0xcc, + 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4, 0x6e, 0x41, 0x01, 0xb2, + 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01, 0xfe, 0xcc, 0x15, 0x1d, + 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03, 0x45, 0xc1, 0x0c, 0x45, + 0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe, 0xe2, 0x00, 0x27, 0xdb, + 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, + 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12, 0x16, 0x19, 0x01, 0x0b, + 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0xfe, 0x99, 0xa4, 0x01, + 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38, 0x12, 0x08, 0x05, 0x1a, + 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, + 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02, 0xe2, 0x6c, 0x58, 0xbe, + 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b, 0xfe, 0x09, 0x6f, 0xba, + 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27, 0xfe, 0x54, 0x07, 0x1c, + 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c, 0x07, 0x02, 0x24, 0x01, + 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe, 0x2c, 0x90, 0xfe, 0xae, + 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a, 0x37, 0x22, 0x20, 0x07, + 0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a, 0xfe, 0x06, 0x10, 0xfe, + 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b, 0x37, 0x01, 0xb3, 0xb8, + 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, + 0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x0c, + 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d, 0x14, 0x3e, 0xfe, 0x4a, + 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x60, 0x14, + 0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62, 0xfe, 0x44, 0x90, 0xfe, + 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e, 0x14, 0x5f, + 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e, 0x14, 0x3c, 0x21, 0x0c, + 0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27, 0xdd, 0xfe, 0x9e, + 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe, 0x9a, 0x08, 0xc6, 0xfe, + 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08, 0x95, 0x86, 0x02, 0x24, + 0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05, 0x06, 0xfe, 0x10, 0x12, + 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e, 0x1c, 0x02, 0xfe, 0x18, + 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, + 0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe, 0xde, 0x09, 0xfe, 0xb7, + 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18, 0xfe, 0xf1, 0x18, 0xfe, + 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, + 0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0, 0xfe, 0xf0, 0x08, 0xb5, + 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18, 0x0b, 0xb6, 0xfe, 0xbf, + 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xc2, 0xfe, 0xd2, + 0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e, 0x06, 0x17, 0x85, 0xc5, + 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15, 0x9d, 0x01, 0x36, 0x10, + 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe, 0x98, 0x80, 0xfe, 0x19, + 0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18, 0xfe, 0x44, 0x54, 0xbe, + 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0x08, 0x05, + 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x6c, + 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f, 0x3b, 0x40, 0x03, 0x49, + 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18, 0x8f, 0xfe, 0xe3, 0x54, + 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe, 0xda, 0x09, 0xfe, 0x8b, + 0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa, 0x0a, 0x3a, 0x49, 0x3b, + 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00, 0xad, 0xfe, 0x01, 0x59, + 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a, 0x49, 0x8f, 0xfe, 0xe3, + 0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02, 0x4a, 0x3a, 0x49, 0x3b, + 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63, 0x02, 0x4a, 0x08, 0x05, + 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62, 0xb7, 0xfe, 0x03, 0xa1, + 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x6a, + 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29, 0x61, 0x0c, 0x7f, 0x14, + 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62, 0x9b, 0x2e, 0x9c, 0x3c, + 0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0x01, 0xef, + 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40, 0xe4, 0x08, 0x05, 0x1f, + 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0x03, 0x5e, 0x29, 0x5f, + 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe, 0xf4, 0x09, 0x08, 0x05, + 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19, 0x81, 0x50, 0xfe, 0x10, + 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe, 0x08, 0x09, 0x12, 0xa6, + 0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe, 0x08, 0x09, 0xfe, 0x0c, + 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7, 0x08, 0x05, 0x0a, 0xfe, + 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1, 0xf0, 0xe2, 0x15, 0x7e, + 0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0x57, 0x3d, 0xfe, 0xed, + 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe, 0x00, 0xff, 0x35, 0xfe, + 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x8a, 0x03, + 0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65, 0xfe, 0xd1, 0xf0, 0xfe, + 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe, 0xce, 0xf0, + 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b, 0x10, 0xfe, 0x22, 0x00, + 0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00, 0x02, 0x65, 0xfe, 0xd0, + 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea, 0x0b, 0x10, 0x58, 0xfe, + 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe, 0x12, 0x00, 0x2c, 0x0f, + 0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14, 0x0c, 0xbc, 0x17, 0x34, + 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20, 0x0c, 0x1c, 0x34, 0x94, + 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xdb, 0x10, + 0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe, 0x89, 0xf0, 0x24, 0x33, + 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24, 0x33, 0x31, 0xdf, 0xbc, + 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49, 0x17, 0xfe, 0x2c, 0x0d, + 0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54, 0x12, 0x55, 0xfe, 0x28, + 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x44, 0xfe, 0x28, 0x00, + 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26, 0x0f, 0x64, 0x12, 0x2f, + 0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44, 0x0a, 0xfe, 0xb4, 0x10, + 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xac, + 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a, 0x37, 0x01, 0xf5, 0x01, + 0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02, 0xfe, 0x2e, 0x03, 0x08, + 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05, 0x1a, 0xfe, 0x58, 0x12, + 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x50, 0x0d, 0xfe, + 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37, 0xfe, 0xa9, 0x10, 0x10, + 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10, 0xfe, 0x13, 0x00, 0xfe, + 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe, 0x24, 0x00, 0x8c, 0xb5, + 0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a, 0xfe, 0x9d, 0x41, 0xfe, + 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0, 0xb4, 0x15, 0xfe, 0x31, + 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06, 0xec, 0xd0, 0xfc, 0x44, + 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47, 0x4b, 0x91, 0xfe, 0x75, + 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x44, 0x48, + 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41, 0xfe, 0x41, 0x58, 0x09, + 0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe, 0x2e, 0x03, 0x09, 0x5d, + 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0xce, 0x47, 0xfe, 0xad, + 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13, 0x59, 0x13, 0x9f, 0x13, + 0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe, 0xe0, 0x0e, 0x0f, 0x06, + 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe, 0x3a, 0x01, 0x56, 0xfe, + 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0xfe, 0x05, + 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, + 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13, 0x15, 0x1a, 0x39, 0xa0, + 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, + 0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25, 0x06, 0x13, 0x2f, 0x12, + 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12, 0x22, 0x9f, 0xb7, 0x13, + 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39, 0xa0, 0xb4, 0xfe, 0xd9, + 0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xc3, 0xfe, 0x03, 0xdc, + 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21, 0xfe, 0x00, 0xcc, 0x04, + 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, + 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae, 0xfe, 0x0c, 0x90, 0xfe, + 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x0a, 0xfe, 0x3c, 0x50, + 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4, 0x16, 0x08, 0x05, 0x1b, + 0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58, 0xfe, 0x2c, 0x13, 0x01, + 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, + 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03, 0x80, 0x8d, 0xfe, 0x01, + 0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64, 0x22, 0x20, 0xfb, 0x79, + 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, 0x03, 0xfe, 0xae, 0x00, + + 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00, 0xfe, 0x09, + 0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c, 0x45, 0x0f, 0x46, 0x52, + 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc, 0x0f, 0x44, 0x11, 0x0f, + 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4, 0x25, 0x11, 0x13, 0x20, + 0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, + 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x04, 0x42, + 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x04, 0x01, + 0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0x32, 0x07, 0x2f, + 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, + 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, + 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07, 0x82, 0x4e, 0xfe, 0x14, + 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d, 0xfe, 0x01, 0xec, 0xa2, + 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79, 0x2a, 0x01, 0xe3, 0xfe, + 0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a, 0xfe, 0x48, 0x12, 0x07, + 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17, 0xfe, 0x32, 0x12, 0x07, + 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07, 0x1f, 0xfe, 0x12, 0x12, + 0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b, 0x94, 0x4b, 0x04, 0x2d, + 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d, 0x32, 0x07, 0xa6, 0xfe, + 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05, 0x5a, 0xfe, 0x72, 0x12, + 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62, 0xfe, 0x26, 0x13, 0x03, + 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21, 0x0c, 0x7f, 0x0c, 0x80, + 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x04, 0x55, + 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe, 0x91, 0x10, 0x03, 0x3f, + 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40, 0x88, 0x9b, 0x2e, 0x9c, + 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x0c, 0x5e, 0x14, + 0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40, 0x03, 0x60, 0x29, 0x61, + 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44, 0x50, 0xfe, 0xc6, 0x50, + 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d, 0x29, 0x3e, 0xfe, 0x40, + 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1d, + 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23, 0x72, 0x01, 0xaf, 0x1e, + 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe, 0x0a, 0x55, 0x35, 0xfe, + 0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x72, 0xfe, 0x19, + 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0xe8, 0x33, 0x31, + 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01, 0x0b, 0x1c, 0x34, 0x1d, + 0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8, 0x33, 0x31, 0xfe, 0xe8, + 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53, 0x05, 0x1f, 0x35, 0xa9, + 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda, 0x14, 0x01, 0xaf, 0x8c, + 0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a, 0x03, 0x45, 0x28, 0x35, + 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17, 0x03, 0x5c, 0xc1, 0x0c, + 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02, 0x89, 0x01, 0x0b, 0x1c, + 0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1, 0xfe, 0x42, 0x58, 0xf1, + 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a, 0xf4, 0x06, 0xea, 0x32, + 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, + 0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13, 0x26, 0xfe, 0xd4, 0x13, + 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0, 0x13, 0x1c, 0xfe, 0xd0, + 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10, 0x0f, 0x71, 0xff, 0x02, + 0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x04, 0x0f, + 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x04, + 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, + 0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01, 0x87, 0x04, 0xfe, 0x03, + 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52, 0xfe, 0x00, 0x7d, 0xfe, + 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e, 0x14, 0x5f, 0x57, 0x3f, + 0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x8d, 0x04, 0x01, + 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, + 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, + 0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13, 0x21, 0x69, 0x1a, 0xee, + 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c, 0x30, 0xfe, 0x78, 0x10, + 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae, 0x98, 0xfe, 0x30, 0x00, + 0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed, 0x98, 0xfe, 0x64, 0x00, + 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28, 0x10, 0x69, 0x06, 0xfe, + 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00, 0x18, 0x59, 0x0f, 0x06, + 0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe, 0x43, 0xf4, 0x9f, 0xfe, + 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4, 0x9e, 0xfe, 0xf3, 0x10, + 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, + 0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, + 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d, 0xf4, 0x00, 0xe9, 0x91, + 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a, 0x04, 0x16, 0x06, 0x01, + 0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01, 0x0b, 0x26, 0xf3, 0x76, + 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0x16, 0x19, 0x01, 0x0b, + 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x26, 0xb1, 0x76, + 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06, 0xfe, 0x48, 0x13, 0xb8, + 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, + 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32, 0x07, 0xfe, 0xe3, 0x00, + 0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b, 0x22, 0xd4, 0x07, 0x06, + 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e, 0x07, 0x11, 0xae, 0x09, + 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0xfe, 0x80, + 0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04, 0x09, 0x48, 0x01, 0x0e, + 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80, 0x80, 0xfe, 0x80, 0x4c, + 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c, 0x09, 0x5d, 0x01, 0x87, + 0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, + 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4, 0x17, 0xad, 0x9a, 0x1b, + 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde, 0x16, 0xfe, 0xda, 0x10, + 0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe, 0x18, 0x58, 0x03, 0xfe, + 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, + 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f, 0x97, 0xfe, 0x38, 0x17, + 0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c, 0x10, 0x18, 0x11, 0x75, + 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x2e, 0x97, 0xfe, 0x5a, + 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, + 0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75, 0xfe, 0x30, 0xbc, 0xfe, + 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0xcb, 0x97, 0xfe, 0x92, + 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe, 0x42, 0x10, 0xfe, 0x02, + 0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe, 0x03, 0xa1, 0xfe, 0x1d, + 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x9a, 0x5b, 0x41, 0xfe, + 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7, 0x11, 0x12, 0xfe, 0xdd, + 0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8, 0x17, 0x15, 0x06, 0x39, + 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04, 0xfe, 0x7e, 0x18, 0x1e, + 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, + 0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42, 0x13, 0x42, 0x92, 0x09, + 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, + 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c, + 0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, 0xfe, 0x14, + 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c, 0xe7, 0x0a, 0x10, 0xfe, + 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92, 0x08, 0x54, 0x1b, 0x37, + 0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x3a, 0xce, 0x3b, + 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77, 0x13, 0xa3, 0x04, 0x09, + 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x17, 0xfe, 0xe8, + 0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09, 0x5d, 0x01, 0xa8, 0x09, + 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe, 0x1c, 0x19, 0x03, 0xfe, + 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9, 0x6b, 0xfe, 0x2e, 0x19, + 0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x6b, + 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe, 0x08, 0x10, 0x03, 0xfe, + 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff, 0x04, 0x68, 0x54, 0xe7, + 0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe, 0x1a, 0xf4, 0xfe, 0x00, + 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19, 0x04, 0x07, 0x7e, 0xfe, + 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10, 0x07, 0x1a, 0xfe, 0x5a, + 0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66, 0x25, 0x6d, 0xe5, 0x07, + 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59, 0xa9, 0xb8, 0x04, 0x15, + 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe, 0x40, 0x5c, 0x04, 0x1c, + 0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b, 0xf7, 0xfe, 0x82, 0xf0, + 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00, }; STATIC unsigned short _adv_asc38C0800_size = - sizeof(_adv_asc38C0800_buf); /* 0x14F1 */ + sizeof(_adv_asc38C0800_buf); /* 0x14E1 */ STATIC ADV_DCNT _adv_asc38C0800_chksum = - 0x053503A5; /* Expanded checksum. */ + 0x050D3FD8UL; /* Expanded little-endian checksum. */ + +/* Microcode buffer is kept after initialization for error recovery. */ +STATIC unsigned char _adv_asc38C1600_buf[] = { + 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0, 0x18, 0xe4, 0x01, 0x00, + 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00, 0x07, 0x17, 0xc0, 0x5f, + 0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7, 0x85, 0xf0, 0x86, 0xf0, + 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00, 0x98, 0x57, 0x01, 0xe6, + 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d, 0x38, 0x54, 0x32, 0xf0, + 0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4, 0x00, 0xe6, 0xb1, 0xf0, + 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01, 0x06, 0x13, 0x0c, 0x1c, + 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12, 0xb9, 0x54, 0x00, 0x80, + 0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56, 0x03, 0xe6, 0x01, 0xea, + 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x04, 0x13, 0xbb, 0x55, + 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00, 0xbb, 0x00, 0xc0, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12, 0x4c, 0x1c, 0x4e, 0x1c, + 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, + 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x7c, 0x01, + 0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c, 0x6e, 0x1e, 0x02, 0x48, + 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7, 0x03, 0xfc, 0x06, 0x00, + 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a, 0x30, 0x1c, 0x38, 0x1c, + 0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea, 0x5d, 0xf0, 0xa7, 0xf0, + 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, + 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x79, 0x01, 0x3c, 0x09, + 0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13, 0x40, 0x16, 0x50, 0x16, + 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, + 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0xa4, 0x00, + 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08, 0xe9, 0x09, 0x5c, 0x0c, + 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x42, 0x1d, 0x08, 0x44, + 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54, 0x83, 0x55, 0x83, 0x59, + 0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, + 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0xa8, 0x00, 0xaa, 0x00, + 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01, 0x7a, 0x01, 0x82, 0x01, + 0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07, 0x68, 0x08, 0x10, 0x0d, + 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10, 0xf3, 0x10, 0x06, 0x12, + 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c, 0xf0, 0x35, 0x05, 0xfe, + 0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8, 0xfe, 0x88, 0x01, 0xff, + 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00, 0x00, 0xfe, 0x57, 0x24, + 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, + 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x13, + 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, 0xfe, 0x04, 0xf7, 0xe8, + 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d, 0x0d, 0x51, 0x37, 0xfe, + 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, + 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d, 0x05, 0xfe, 0x08, 0x0f, + 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe, 0x28, 0x1c, 0x03, 0xfe, + 0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe, 0x48, 0xf0, 0xfe, 0x90, + 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8, 0x02, 0xfe, 0x46, 0xf0, + 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x4e, 0x02, 0xfe, + 0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c, 0x0d, 0xa2, 0x1c, 0x07, + 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02, 0x1c, 0xf5, 0xfe, 0x1e, + 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xde, 0x0a, 0x81, 0x01, + 0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a, 0x81, 0x01, 0x5c, 0xfe, + 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, 0x58, 0x1c, 0x1c, + 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0x2b, 0xfe, 0x9e, 0x02, + 0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30, 0x00, 0x47, 0xb8, 0x01, + 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09, 0x1a, 0x31, 0xfe, 0x69, + 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe, 0x1e, 0x1e, 0x20, 0x2c, + 0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a, 0x44, 0x15, 0x56, 0x51, + 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, + 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0xc8, 0x54, + 0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60, 0xfe, 0x02, 0xe8, 0x30, + 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0, 0xfe, 0xe4, 0x01, 0xfe, + 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe, 0x26, 0xf0, 0xfe, 0x66, + 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe, 0xef, 0x10, 0xfe, 0x9f, + 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05, 0x70, 0x37, 0xfe, 0x48, + 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26, 0x21, 0xb9, 0xc7, 0x20, + 0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15, 0xe1, 0x2a, 0xeb, 0xfe, + 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32, 0x15, 0xfe, 0xe4, 0x00, + 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41, 0xfe, 0x06, 0xf0, 0xfe, + 0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29, 0x03, 0x81, 0x1e, 0x1b, + 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05, 0xea, 0xfe, 0x46, 0x1c, + 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c, 0x75, + 0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a, 0xe1, 0x01, 0x18, 0x77, + 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, + 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04, 0x16, 0xfe, 0x4a, 0x04, + 0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff, 0x02, 0x00, 0x10, 0x01, + 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25, 0xee, 0xfe, 0x4c, 0x44, + 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x60, 0x8d, + 0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xfe, + 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10, 0x13, 0x34, 0xfe, 0x4c, + 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54, 0x13, 0x01, 0x0c, 0x06, + 0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xf9, 0x1f, 0x7f, + 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f, 0xfe, 0xa4, 0x0e, 0x05, + 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe, 0x9c, 0x93, 0x3a, 0x0b, + 0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b, 0x7d, 0x1d, 0xfe, 0x46, + 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04, 0xfe, 0x87, 0x83, 0xfe, + 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98, 0x13, 0x0f, 0xfe, 0x20, + 0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84, 0x12, 0x01, 0x38, 0x06, + 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda, 0x05, 0xd0, 0x54, 0x01, + 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe, 0x50, 0x12, 0x5e, 0xff, + 0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe, + 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01, 0x38, 0xfe, 0x4a, 0xf0, + 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe, 0x21, 0x00, 0xf1, 0x2e, + 0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe, 0xd0, + 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe, 0x1c, 0x00, 0x4d, 0x01, + 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x24, 0x12, + 0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, + 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13, 0x03, 0xb6, 0x1e, 0xfe, + 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17, 0xfe, 0x72, 0x06, 0x0a, + 0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56, 0x19, 0x16, 0xfe, 0x68, + 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x03, 0x9a, 0x1e, 0xfe, + 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12, 0x48, 0xfe, 0x92, 0x06, + 0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13, 0x58, 0xff, 0x02, 0x00, + 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17, 0xfe, 0xea, 0x06, 0x01, + 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16, 0xfe, 0xe0, 0x06, 0x15, + 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07, 0x01, 0x84, 0xfe, 0xae, + 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a, 0x1e, 0xfe, 0x1a, 0x12, + 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, + 0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24, 0x36, 0xfe, 0x02, 0xf6, + 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d, 0x17, 0xfe, + 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20, 0x9e, 0x15, 0x82, 0x01, + 0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58, 0x57, 0x10, 0xe6, 0x05, + 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84, 0xfe, 0x9c, 0x32, 0x5f, + 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe, + 0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08, 0xaf, 0xa0, 0x05, 0x29, + 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, + 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x14, 0x00, 0x05, 0xfe, + 0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x30, 0x13, + 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00, + 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a, 0x78, 0x4f, 0x0f, 0xfe, + 0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d, 0x28, 0x48, 0xfe, 0x6c, + 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x53, 0x63, 0x4e, + 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe, 0x6c, 0x08, 0xaf, 0xa0, + 0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24, 0x05, 0xed, 0xfe, 0x9c, + 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe, 0x1e, 0xfe, 0x99, 0x58, + 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a, 0x22, 0x6b, 0x01, 0x0c, + 0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e, 0x1e, 0x47, 0x2c, 0x7a, + 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40, 0x01, 0x0c, 0x61, 0x65, + 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xfe, 0x08, 0x50, + 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10, 0x01, 0xfe, 0xce, 0x1e, + 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e, 0x01, 0xfe, 0xfe, 0x1e, + 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a, 0x10, 0x01, 0x0c, 0x06, + 0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e, 0x10, 0x6a, 0x22, 0x6b, + 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04, 0xfe, 0x9f, 0x83, 0x33, + 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93, 0x3a, 0x0b, 0xfe, 0xc6, + 0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d, 0x01, 0xfe, 0xce, 0x1e, + 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90, 0x04, 0xfe, 0xc0, 0x93, + 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x4b, 0x22, 0x4c, + 0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe, + 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b, 0x3c, 0x37, 0x88, 0xf5, + 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a, 0xd3, 0xfe, 0x42, 0x0a, + 0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0, 0x05, 0x29, 0x01, 0x41, + 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07, 0xfe, 0x14, 0x12, 0x01, + 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe, 0x2e, 0x1c, 0x05, 0xfe, + 0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41, 0xfe, 0x2c, 0x1c, 0xfe, + 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe, 0x92, 0x10, 0xc4, 0xf6, + 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe, 0xe7, 0x10, 0xfe, 0x2b, + 0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xac, 0xfe, 0xd2, 0xf0, + 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07, 0x1b, 0xbf, 0xd4, 0x5b, + 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75, 0x5e, 0x32, 0x1f, 0x7f, + 0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98, 0x05, 0x70, 0xfe, 0x74, + 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78, 0x0f, 0x4d, 0x01, 0xfe, + 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x0d, 0x2b, 0xfe, 0xe2, + 0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24, 0xfe, 0x88, 0x13, 0x21, + 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe, 0x83, 0x83, 0xfe, 0xc9, + 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04, 0x91, 0x04, 0xfe, 0x84, + 0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93, 0xfe, 0xcb, 0x57, 0x0b, + 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03, 0x6a, 0x3b, 0x6b, 0x10, + 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30, 0x20, 0x6e, 0xdb, 0x64, + 0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xfe, 0x04, 0xfa, 0x64, + 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97, 0x10, 0x98, 0x91, 0x6c, + 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91, 0x4b, 0x7e, 0x4c, 0x01, + 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, + 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x01, 0x0c, + 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f, 0xfe, 0x10, 0x90, 0x04, + 0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93, 0x79, 0x0b, 0x0e, 0xfe, + 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb, 0x01, 0x0c, 0x06, 0x0d, + 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, + 0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99, 0x83, 0x33, 0x0b, 0x0e, + 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, + 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42, 0x19, 0xfe, 0x44, 0x00, + 0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda, 0x4c, 0xfe, 0x0c, 0x51, + 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe, 0x76, 0x10, 0xac, 0xfe, + 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03, 0xe3, 0x23, 0x07, 0xfe, + 0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe, 0xcc, 0x0c, 0x1f, 0x92, + 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2, 0x0c, 0xfe, 0x3e, 0x10, + 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70, 0xfe, 0xcb, 0xf0, 0xfe, + 0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe, 0xf4, 0x0c, 0x19, 0x94, + 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3, 0xfe, 0xcc, 0xf0, 0xef, + 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe, + 0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b, 0x3c, 0x37, 0x88, 0xf5, + 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32, 0x2f, 0xfe, 0x3e, 0x0d, + 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f, 0xd2, 0x9f, 0xd3, 0x9f, + 0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4, 0xc5, 0x75, 0xd7, 0x99, + 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8, 0x9c, 0x2f, 0xfe, 0x8c, + 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe, 0x42, 0x00, 0x05, 0x70, + 0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x44, 0x13, + 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b, 0xfe, 0xda, 0x0e, 0x0a, + 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa, 0x10, 0x01, 0xfe, 0xf4, + 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40, 0x15, 0x56, 0x01, 0x85, + 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe, 0xcc, 0x10, 0x01, 0xa7, + 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04, 0xfe, 0x99, 0x83, 0xfe, + 0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe, 0x43, 0x00, 0xfe, 0xa2, + 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x40, 0x15, + 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05, 0xfe, 0x3a, 0x03, 0x01, + 0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01, 0x76, 0x06, 0x12, 0xfe, + 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, + 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01, 0x0c, 0x61, 0x12, 0x44, + 0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f, 0xfe, 0x2e, 0x10, 0x19, + 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19, 0xfe, 0x41, 0x00, 0xa2, + 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b, 0xea, 0x4f, 0xfe, 0x04, + 0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05, 0x35, 0xfe, 0x12, 0x1c, + 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01, 0xfe, 0xd4, 0x11, 0x05, + 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, + 0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03, 0x67, 0xfe, 0x98, 0x56, + 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01, 0x0c, 0x06, 0x28, 0xfe, + 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0xfe, 0xfa, 0x14, 0xfe, + 0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67, 0xfe, 0xe0, 0x14, 0xfe, + 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47, 0xfe, 0xad, 0x13, 0x05, + 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20, 0xe7, 0xfe, 0x08, 0x1c, + 0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe, 0x48, 0x55, 0xa5, 0x3b, + 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe, 0xf0, 0x1a, 0x03, 0xfe, + 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02, 0xec, 0xe7, 0x53, 0x00, + 0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x62, 0x1b, + 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02, 0xea, 0xe7, 0x53, 0x92, + 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x23, + 0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62, 0x01, 0x01, 0xfe, 0x1e, + 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02, 0x26, 0x02, 0x21, 0x96, + 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5, 0xc3, 0xfe, 0xe1, 0x10, + 0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf, 0xfe, 0x03, 0xdc, 0xfe, + 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe, 0x00, 0xcc, 0x02, 0xfe, + 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x0f, 0xfe, 0x1c, 0x80, + 0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13, 0x0f, 0xfe, 0x1e, 0x80, + 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe, 0x1d, 0x80, 0x04, 0xfe, + 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee, 0x1e, 0xac, 0xfe, 0x14, + 0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4, + 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09, 0x56, 0xfb, 0x01, 0xfe, + 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x15, + 0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe, 0x22, 0x1b, 0xfe, 0x1e, + 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe, 0x96, 0x90, 0x04, 0xfe, + 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66, 0x01, 0x01, 0x0c, 0x06, + 0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x0e, 0x77, 0xfe, 0x01, + 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40, 0x21, 0x2c, 0xfe, 0x00, + 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, 0x03, 0xfe, + 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00, + 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10, 0x66, 0x10, 0x55, 0x10, + 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe, 0x88, + 0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe, + 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe, 0x00, 0x40, 0x8d, 0x2c, + 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe, 0x12, 0x1c, 0x75, 0xfe, + 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c, 0x14, 0xfe, 0x0e, 0x47, + 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01, 0xa7, 0x90, 0x34, 0x60, + 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x34, + 0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, + 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, + 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4, 0xfe, 0x14, 0x56, 0xfe, + 0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01, 0xec, 0xb8, 0xfe, 0x9e, + 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01, 0xf4, 0xfe, 0xdd, 0x10, + 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48, 0x12, 0x09, 0x0d, 0xfe, + 0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4, 0x13, 0x09, 0xfe, 0x23, + 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09, 0x24, 0xfe, 0x12, 0x12, + 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08, 0xae, 0x41, 0x02, 0x32, + 0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05, 0x35, 0x32, 0x01, 0x43, + 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80, 0x13, 0x01, 0x0c, 0x06, + 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xb0, 0xfe, + 0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e, 0xfe, 0xb6, 0x0e, 0x10, + 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49, 0x88, 0x20, 0x6e, 0x01, + 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, + 0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x40, 0x56, 0xfe, + 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe, 0xe5, + 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10, 0x68, 0x22, 0x69, 0x01, + 0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b, 0x6b, 0xfe, 0x2c, 0x50, + 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6, 0x50, 0x03, 0x68, 0x3b, + 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe, 0x40, 0x50, 0xfe, 0xc2, + 0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08, 0x16, 0x3d, 0x27, 0x25, + 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01, 0xa6, 0x23, 0x3f, 0x1b, + 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0xfe, 0x0a, 0x55, 0x31, + 0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x05, 0x72, 0x01, + 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, + 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b, 0xfe, 0x66, 0x15, 0x05, + 0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d, 0x2b, 0x3d, 0x01, 0x08, + 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03, 0xb6, 0x1e, 0x83, 0x01, + 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46, 0x07, 0x90, 0x3f, 0x01, + 0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13, 0x01, 0x43, 0x09, 0x82, + 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e, 0x05, 0x72, 0xfe, 0xc0, + 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e, 0x32, 0x01, 0x08, 0x17, + 0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d, 0x27, 0x25, 0xbd, + 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe, 0xe8, 0x14, 0x01, 0xa6, + 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, + 0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, + 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d, 0x27, 0x25, 0xbd, 0x09, + 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe, 0xb6, 0x14, 0x86, 0xa8, + 0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05, 0x72, + 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01, 0xfe, 0xc0, 0x19, 0x05, + 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f, 0xcc, 0x01, 0x08, 0x26, + 0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe, 0xcc, 0x15, 0x5e, 0x32, + 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0x23, 0xfe, 0xff, + 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, + 0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, + 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e, 0x02, 0x13, 0x58, 0xff, + 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01, 0x5c, 0x0a, 0x55, 0x01, + 0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a, 0xff, 0x03, 0x00, 0x54, + 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07, 0x7c, 0x3a, 0x0b, 0x0e, + 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19, 0xfe, 0x1a, 0xf7, 0x00, + 0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c, 0xda, 0x6d, 0x02, 0xfe, + 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77, 0x02, 0x01, 0xc6, 0xfe, + 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xbe, 0x01, 0x08, + 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0x9a, 0x1e, 0xfe, + 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12, 0x48, 0xfe, 0x08, 0x17, + 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26, 0x17, 0x4d, 0x13, 0x07, + 0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1, 0xff, 0x02, 0x83, 0x55, + 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x1c, 0x63, 0x13, + 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64, 0x00, 0xb0, 0xfe, 0x80, + 0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10, 0x53, 0x07, 0xfe, 0x60, + 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8, 0x00, 0x1c, 0x95, 0x13, + 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3, 0xfe, 0x43, 0xf4, 0x96, + 0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43, 0xf4, 0x94, 0xf6, 0x8b, + 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x49, + 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80, 0x71, 0x50, 0x26, 0xfe, + 0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x02, 0x50, 0x13, + 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xbe, 0xfe, 0x03, + 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0x01, 0x08, 0x16, + 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01, 0x01, 0x08, 0x16, 0xa9, + 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, + 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24, + 0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1, 0x78, 0x03, 0x9a, 0x1e, + 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10, 0xfe, 0x40, 0x5a, 0x23, + 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c, 0x80, 0x48, 0xfe, 0xaa, + 0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe, + 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe, 0x43, 0x48, 0x2d, 0x93, + 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4, 0x36, 0xfe, 0x34, 0xf4, + 0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe, 0x28, 0x10, 0xfe, 0xc0, + 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa, 0x18, 0x45, 0xfe, 0x1c, + 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c, 0x19, 0xfe, 0x04, 0xf4, + 0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d, 0x21, 0xfe, 0x7f, 0x01, + 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe, 0x7e, 0x01, 0xfe, 0xc8, + 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa, 0x21, 0xfe, 0x81, 0x01, + 0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50, 0x13, 0x0d, 0x02, 0x14, + 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, + 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x02, 0x14, 0x07, + 0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1, + 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01, 0x08, 0x02, 0x50, 0x02, + 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74, 0x14, 0x12, 0x01, 0x08, + 0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01, 0x08, 0x17, 0x74, 0xfe, + 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17, 0x74, 0x5f, 0xcc, 0x01, + 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4, 0xfe, 0x49, 0xf4, 0x00, + 0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f, + 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13, 0x16, 0xfe, 0x64, 0x1a, + 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c, 0x61, 0x07, 0x44, 0x02, + 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, + 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa, 0xfe, 0x80, 0xe7, 0x1a, + 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02, 0x0a, 0x5a, 0x01, 0x18, + 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe, 0x7e, 0x1e, 0xfe, 0x80, + 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x4c, 0x0a, + 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, + 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe, 0x2a, 0x1c, 0xfa, 0xb3, + 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe, 0xf4, 0x1a, 0xfe, 0xfa, + 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24, 0xfe, 0x18, 0x58, 0x03, + 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4, 0x07, + 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x24, 0xb1, 0xfe, + 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b, 0xfe, 0xba, 0x10, 0x1c, + 0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x54, 0xb1, + 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe, 0xaf, 0x19, 0xfe, 0x98, + 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c, 0x1a, 0x87, 0x8b, 0x0f, + 0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58, 0xfe, 0x32, 0x90, 0x04, + 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a, 0x7c, 0x12, 0xfe, 0x0f, + 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14, 0x31, 0x02, 0xc9, 0x2b, + 0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe, 0x6a, 0xfe, 0x19, 0xfe, + 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee, 0x1b, 0xfe, 0x36, 0x14, + 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x1a, + 0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a, 0x30, 0xfe, 0x12, 0x45, + 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe, 0x39, 0xf0, 0x75, 0x26, + 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03, 0xe3, 0x23, 0x07, 0xfe, + 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x3c, 0x13, + 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, + 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, + 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x4c, 0x01, + 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, 0xfe, 0x14, 0x56, + 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7, 0x0d, 0x19, 0xfe, 0x15, + 0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06, 0x83, 0xfe, 0x18, 0x80, + 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, + 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02, 0x21, 0xb9, 0x88, 0x20, + 0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01, 0x18, 0xfe, 0x49, 0x44, + 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09, 0x1a, 0xa4, 0x0a, 0x67, + 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4, 0x1d, 0x7b, 0xfe, 0x52, + 0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xdd, 0x7b, + 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10, 0xfe, 0x4e, 0xe4, 0xfe, + 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24, 0xfe, 0x08, 0x10, 0x03, + 0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04, 0x68, 0x54, 0xfe, 0xf1, + 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe, 0x1a, 0xf4, 0xfe, + 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02, 0x09, 0x92, 0xfe, 0x5a, + 0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe, 0x5a, 0xf0, 0xfe, 0xc8, + 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe, 0x1a, 0x10, 0x09, 0x0d, + 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02, 0x1f, 0x93, 0x01, 0x42, + 0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e, 0xfe, 0x14, 0xf0, 0x08, + 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e, 0xfe, 0x82, 0xf0, 0xfe, + 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x18, + 0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02, 0x80, 0x04, 0xfe, 0x82, + 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86, 0x83, 0x33, 0x0b, 0x0e, + 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x04, + 0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80, 0x80, 0x04, 0xfe, 0x80, + 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04, 0xfe, 0x99, 0x83, 0xfe, + 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86, 0x83, 0xfe, 0xce, 0x47, + 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, + 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x08, 0x90, 0x04, + 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04, 0xfe, 0x8a, 0x93, 0x79, + 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, + 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x3c, 0x90, 0x04, + 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, + 0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00, +}; + +STATIC unsigned short _adv_asc38C1600_size = + sizeof(_adv_asc38C1600_buf); /* 0x1673 */ +STATIC ADV_DCNT _adv_asc38C1600_chksum = + 0x0604EF77UL; /* Expanded little-endian checksum. */ /* a_init.c */ /* @@ -15455,6 +14570,14 @@ * configuration. The BIOS now uses this structure when it is built. * Additional structure information can be found in a_condor.h where * the structure is defined. + * + * The *_Field_IsChar structs are needed to correct for endianness. + * These values are read from the board 16 bits at a time directly + * into the structs. Because some fields are char, the values will be + * in the wrong order. The *_Field_IsChar tells when to flip the + * bytes. Data read and written to PCI memory is automatically swapped + * on big-endian platforms so char fields read as words are actually being + * unswapped on big-endian platforms. */ STATIC ADVEEP_3550_CONFIG Default_3550_EEPROM_Config ASC_INITDATA = { @@ -15494,6 +14617,44 @@ 0 /* num_of_err */ }; +STATIC ADVEEP_3550_CONFIG +ADVEEP_3550_Config_Field_IsChar ASC_INITDATA = { + 0, /* cfg_lsw */ + 0, /* cfg_msw */ + 0, /* -disc_enable */ + 0, /* wdtr_able */ + 0, /* sdtr_able */ + 0, /* start_motor */ + 0, /* tagqng_able */ + 0, /* bios_scan */ + 0, /* scam_tolerant */ + 1, /* adapter_scsi_id */ + 1, /* bios_boot_delay */ + 1, /* scsi_reset_delay */ + 1, /* bios_id_lun */ + 1, /* termination */ + 1, /* reserved1 */ + 0, /* bios_ctrl */ + 0, /* ultra_able */ + 0, /* reserved2 */ + 1, /* max_host_qng */ + 1, /* max_dvc_qng */ + 0, /* dvc_cntl */ + 0, /* bug_fix */ + 0, /* serial_number_word1 */ + 0, /* serial_number_word2 */ + 0, /* serial_number_word3 */ + 0, /* check_sum */ + { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, /* oem_name[16] */ + 0, /* dvc_err_code */ + 0, /* adv_err_code */ + 0, /* adv_err_addr */ + 0, /* saved_dvc_err_code */ + 0, /* saved_adv_err_code */ + 0, /* saved_adv_err_addr */ + 0 /* num_of_err */ +}; + STATIC ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config ASC_INITDATA = { ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */ @@ -15559,6 +14720,201 @@ 0 /* 63 reserved */ }; +STATIC ADVEEP_38C0800_CONFIG +ADVEEP_38C0800_Config_Field_IsChar ASC_INITDATA = { + 0, /* 00 cfg_lsw */ + 0, /* 01 cfg_msw */ + 0, /* 02 disc_enable */ + 0, /* 03 wdtr_able */ + 0, /* 04 sdtr_speed1 */ + 0, /* 05 start_motor */ + 0, /* 06 tagqng_able */ + 0, /* 07 bios_scan */ + 0, /* 08 scam_tolerant */ + 1, /* 09 adapter_scsi_id */ + 1, /* bios_boot_delay */ + 1, /* 10 scsi_reset_delay */ + 1, /* bios_id_lun */ + 1, /* 11 termination_se */ + 1, /* termination_lvd */ + 0, /* 12 bios_ctrl */ + 0, /* 13 sdtr_speed2 */ + 0, /* 14 sdtr_speed3 */ + 1, /* 15 max_host_qng */ + 1, /* max_dvc_qng */ + 0, /* 16 dvc_cntl */ + 0, /* 17 sdtr_speed4 */ + 0, /* 18 serial_number_word1 */ + 0, /* 19 serial_number_word2 */ + 0, /* 20 serial_number_word3 */ + 0, /* 21 check_sum */ + { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, /* 22-29 oem_name[16] */ + 0, /* 30 dvc_err_code */ + 0, /* 31 adv_err_code */ + 0, /* 32 adv_err_addr */ + 0, /* 33 saved_dvc_err_code */ + 0, /* 34 saved_adv_err_code */ + 0, /* 35 saved_adv_err_addr */ + 0, /* 36 reserved */ + 0, /* 37 reserved */ + 0, /* 38 reserved */ + 0, /* 39 reserved */ + 0, /* 40 reserved */ + 0, /* 41 reserved */ + 0, /* 42 reserved */ + 0, /* 43 reserved */ + 0, /* 44 reserved */ + 0, /* 45 reserved */ + 0, /* 46 reserved */ + 0, /* 47 reserved */ + 0, /* 48 reserved */ + 0, /* 49 reserved */ + 0, /* 50 reserved */ + 0, /* 51 reserved */ + 0, /* 52 reserved */ + 0, /* 53 reserved */ + 0, /* 54 reserved */ + 0, /* 55 reserved */ + 0, /* 56 cisptr_lsw */ + 0, /* 57 cisprt_msw */ + 0, /* 58 subsysvid */ + 0, /* 59 subsysid */ + 0, /* 60 reserved */ + 0, /* 61 reserved */ + 0, /* 62 reserved */ + 0 /* 63 reserved */ +}; + +STATIC ADVEEP_38C1600_CONFIG +Default_38C1600_EEPROM_Config ASC_INITDATA = { + ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */ + 0x0000, /* 01 cfg_msw */ + 0xFFFF, /* 02 disc_enable */ + 0xFFFF, /* 03 wdtr_able */ + 0x5555, /* 04 sdtr_speed1 */ + 0xFFFF, /* 05 start_motor */ + 0xFFFF, /* 06 tagqng_able */ + 0xFFFF, /* 07 bios_scan */ + 0, /* 08 scam_tolerant */ + 7, /* 09 adapter_scsi_id */ + 0, /* bios_boot_delay */ + 3, /* 10 scsi_reset_delay */ + 0, /* bios_id_lun */ + 0, /* 11 termination_se */ + 0, /* termination_lvd */ + 0xFFE7, /* 12 bios_ctrl */ + 0x5555, /* 13 sdtr_speed2 */ + 0x5555, /* 14 sdtr_speed3 */ + ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */ + ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */ + 0, /* 16 dvc_cntl */ + 0x5555, /* 17 sdtr_speed4 */ + 0, /* 18 serial_number_word1 */ + 0, /* 19 serial_number_word2 */ + 0, /* 20 serial_number_word3 */ + 0, /* 21 check_sum */ + { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* 22-29 oem_name[16] */ + 0, /* 30 dvc_err_code */ + 0, /* 31 adv_err_code */ + 0, /* 32 adv_err_addr */ + 0, /* 33 saved_dvc_err_code */ + 0, /* 34 saved_adv_err_code */ + 0, /* 35 saved_adv_err_addr */ + 0, /* 36 reserved */ + 0, /* 37 reserved */ + 0, /* 38 reserved */ + 0, /* 39 reserved */ + 0, /* 40 reserved */ + 0, /* 41 reserved */ + 0, /* 42 reserved */ + 0, /* 43 reserved */ + 0, /* 44 reserved */ + 0, /* 45 reserved */ + 0, /* 46 reserved */ + 0, /* 47 reserved */ + 0, /* 48 reserved */ + 0, /* 49 reserved */ + 0, /* 50 reserved */ + 0, /* 51 reserved */ + 0, /* 52 reserved */ + 0, /* 53 reserved */ + 0, /* 54 reserved */ + 0, /* 55 reserved */ + 0, /* 56 cisptr_lsw */ + 0, /* 57 cisprt_msw */ + ADV_PCI_VENDOR_ID, /* 58 subsysvid */ + ADV_PCI_DEVID_38C1600_REV1, /* 59 subsysid */ + 0, /* 60 reserved */ + 0, /* 61 reserved */ + 0, /* 62 reserved */ + 0 /* 63 reserved */ +}; + +STATIC ADVEEP_38C1600_CONFIG +ADVEEP_38C1600_Config_Field_IsChar ASC_INITDATA = { + 0, /* 00 cfg_lsw */ + 0, /* 01 cfg_msw */ + 0, /* 02 disc_enable */ + 0, /* 03 wdtr_able */ + 0, /* 04 sdtr_speed1 */ + 0, /* 05 start_motor */ + 0, /* 06 tagqng_able */ + 0, /* 07 bios_scan */ + 0, /* 08 scam_tolerant */ + 1, /* 09 adapter_scsi_id */ + 1, /* bios_boot_delay */ + 1, /* 10 scsi_reset_delay */ + 1, /* bios_id_lun */ + 1, /* 11 termination_se */ + 1, /* termination_lvd */ + 0, /* 12 bios_ctrl */ + 0, /* 13 sdtr_speed2 */ + 0, /* 14 sdtr_speed3 */ + 1, /* 15 max_host_qng */ + 1, /* max_dvc_qng */ + 0, /* 16 dvc_cntl */ + 0, /* 17 sdtr_speed4 */ + 0, /* 18 serial_number_word1 */ + 0, /* 19 serial_number_word2 */ + 0, /* 20 serial_number_word3 */ + 0, /* 21 check_sum */ + { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, /* 22-29 oem_name[16] */ + 0, /* 30 dvc_err_code */ + 0, /* 31 adv_err_code */ + 0, /* 32 adv_err_addr */ + 0, /* 33 saved_dvc_err_code */ + 0, /* 34 saved_adv_err_code */ + 0, /* 35 saved_adv_err_addr */ + 0, /* 36 reserved */ + 0, /* 37 reserved */ + 0, /* 38 reserved */ + 0, /* 39 reserved */ + 0, /* 40 reserved */ + 0, /* 41 reserved */ + 0, /* 42 reserved */ + 0, /* 43 reserved */ + 0, /* 44 reserved */ + 0, /* 45 reserved */ + 0, /* 46 reserved */ + 0, /* 47 reserved */ + 0, /* 48 reserved */ + 0, /* 49 reserved */ + 0, /* 50 reserved */ + 0, /* 51 reserved */ + 0, /* 52 reserved */ + 0, /* 53 reserved */ + 0, /* 54 reserved */ + 0, /* 55 reserved */ + 0, /* 56 cisptr_lsw */ + 0, /* 57 cisprt_msw */ + 0, /* 58 subsysvid */ + 0, /* 59 subsysid */ + 0, /* 60 reserved */ + 0, /* 61 reserved */ + 0, /* 62 reserved */ + 0 /* 63 reserved */ +}; + /* * Initialize the ADV_DVC_VAR structure. * @@ -15639,11 +14995,11 @@ asc_dvc->cfg->chip_version = AdvGetChipVersion(iop_base, asc_dvc->bus_type); - ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: %x %x\n", + ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n", (ushort) AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1), (ushort) ADV_CHIP_ID_BYTE); - ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: %x %x\n", + ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n", (ushort) AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0), (ushort) ADV_CHIP_ID_WORD); @@ -15676,7 +15032,13 @@ AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_WR_IO_REG); - if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) + if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) + { + if ((status = AdvInitFrom38C1600EEP(asc_dvc)) == ADV_ERROR) + { + return ADV_ERROR; + } + } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { if ((status = AdvInitFrom38C0800EEP(asc_dvc)) == ADV_ERROR) { @@ -15702,6 +15064,8 @@ * * For a non-fatal error return a warning code. If there are no warnings * then 0 is returned. + * + * Needed after initialization for error recovery. */ STATIC int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc) @@ -15814,22 +15178,662 @@ { AdvWriteWordAutoIncLram(iop_base, (((ushort) _adv_asc3550_buf[i + 3] << 8) | - _adv_asc3550_buf[i + 2])); + _adv_asc3550_buf[i + 2])); word++; } i += 3; } else if (_adv_asc3550_buf[i] == 0xfe) { AdvWriteWordAutoIncLram(iop_base, (((ushort) - _adv_asc3550_buf[i + 2] << 8) | - _adv_asc3550_buf[i + 1])); + _adv_asc3550_buf[i + 2] << 8) | + _adv_asc3550_buf[i + 1])); + i += 2; + word++; + } else + { + AdvWriteWordAutoIncLram(iop_base, (((ushort) + _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | + _adv_asc3550_buf[_adv_asc3550_buf[i] * 2])); + word++; + } + } + + /* + * Set 'word' for later use to clear the rest of memory and save + * the expanded mcode size. + */ + word *= 2; + adv_asc3550_expanded_size = word; + + /* + * Clear the rest of ASC-3550 Internal RAM (8KB). + */ + for (; word < ADV_3550_MEMSIZE; word += 2) + { + AdvWriteWordAutoIncLram(iop_base, 0); + } + + /* + * Verify the microcode checksum. + */ + sum = 0; + AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); + + for (word = 0; word < adv_asc3550_expanded_size; word += 2) + { + sum += AdvReadWordAutoIncLram(iop_base); + } + + if (sum != _adv_asc3550_chksum) + { + asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; + return ADV_ERROR; + } + + /* + * Restore the RISC memory BIOS region. + */ + for (i = 0; i < ASC_MC_BIOSLEN/2; i++) + { + AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]); + } + + /* + * Calculate and write the microcode code checksum to the microcode + * code checksum location ASC_MC_CODE_CHK_SUM (0x2C). + */ + AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr); + AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr); + code_sum = 0; + AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr); + for (word = begin_addr; word < end_addr; word += 2) + { + code_sum += AdvReadWordAutoIncLram(iop_base); + } + AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum); + + /* + * Read and save microcode version and date. + */ + AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date); + AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version); + + /* + * Set the chip type to indicate the ASC3550. + */ + AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550); + + /* + * If the PCI Configuration Command Register "Parity Error Response + * Control" Bit was clear (0), then set the microcode variable + * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode + * to ignore DMA parity errors. + */ + if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) + { + AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); + word |= CONTROL_FLAG_IGNORE_PERR; + AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); + } + + /* + * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO + * threshold of 128 bytes. This register is only accessible to the host. + */ + AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0, + START_CTL_EMFU | READ_CMD_MRM); + + /* + * Microcode operating variables for WDTR, SDTR, and command tag + * queuing will be set in AdvInquiryHandling() based on what a + * device reports it is capable of in Inquiry byte 7. + * + * If SCSI Bus Resets have been disabled, then directly set + * SDTR and WDTR from the EEPROM configuration. This will allow + * the BIOS and warm boot to work without a SCSI bus hang on + * the Inquiry caused by host and target mismatched DTR values. + * Without the SCSI Bus Reset, before an Inquiry a device can't + * be assumed to be in Asynchronous, Narrow mode. + */ + if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) + { + AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, asc_dvc->wdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, asc_dvc->sdtr_able); + } + + /* + * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2, + * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID + * bitmask. These values determine the maximum SDTR speed negotiated + * with a device. + * + * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2, + * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them + * without determining here whether the device supports SDTR. + * + * 4-bit speed SDTR speed name + * =========== =============== + * 0000b (0x0) SDTR disabled + * 0001b (0x1) 5 Mhz + * 0010b (0x2) 10 Mhz + * 0011b (0x3) 20 Mhz (Ultra) + * 0100b (0x4) 40 Mhz (LVD/Ultra2) + * 0101b (0x5) 80 Mhz (LVD2/Ultra3) + * 0110b (0x6) Undefined + * . + * 1111b (0xF) Undefined + */ + word = 0; + for (tid = 0; tid <= ADV_MAX_TID; tid++) + { + if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) + { + /* Set Ultra speed for TID 'tid'. */ + word |= (0x3 << (4 * (tid % 4))); + } else + { + /* Set Fast speed for TID 'tid'. */ + word |= (0x2 << (4 * (tid % 4))); + } + if (tid == 3) /* Check if done with sdtr_speed1. */ + { + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word); + word = 0; + } else if (tid == 7) /* Check if done with sdtr_speed2. */ + { + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word); + word = 0; + } else if (tid == 11) /* Check if done with sdtr_speed3. */ + { + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word); + word = 0; + } else if (tid == 15) /* Check if done with sdtr_speed4. */ + { + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word); + /* End of loop. */ + } + } + + /* + * Set microcode operating variable for the disconnect per TID bitmask. + */ + AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable); + + /* + * Set SCSI_CFG0 Microcode Default Value. + * + * The microcode will set the SCSI_CFG0 register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0, + PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN | + asc_dvc->chip_scsi_id); + + /* + * Determine SCSI_CFG1 Microcode Default Value. + * + * The microcode will set the SCSI_CFG1 register using this value + * after it is started below. + */ + + /* Read current SCSI_CFG1 Register value. */ + scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); + + /* + * If all three connectors are in use, return an error. + */ + if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 || + (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) + { + asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION; + return ADV_ERROR; + } + + /* + * If the internal narrow cable is reversed all of the SCSI_CTRL + * register signals will be set. Check for and return an error if + * this condition is found. + */ + if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) + { + asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE; + return ADV_ERROR; + } + + /* + * If this is a differential board and a single-ended device + * is attached to one of the connectors, return an error. + */ + if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) + { + asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE; + return ADV_ERROR; + } + + /* + * If automatic termination control is enabled, then set the + * termination value based on a table listed in a_condor.h. + * + * If manual termination was specified with an EEPROM setting + * then 'termination' was set-up in AdvInitFrom3550EEPROM() and + * is ready to be 'ored' into SCSI_CFG1. + */ + if (asc_dvc->cfg->termination == 0) + { + /* + * The software always controls termination by setting TERM_CTL_SEL. + * If TERM_CTL_SEL were set to 0, the hardware would set termination. + */ + asc_dvc->cfg->termination |= TERM_CTL_SEL; + + switch(scsi_cfg1 & CABLE_DETECT) + { + /* TERM_CTL_H: on, TERM_CTL_L: on */ + case 0x3: case 0x7: case 0xB: case 0xD: case 0xE: case 0xF: + asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L); + break; + + /* TERM_CTL_H: on, TERM_CTL_L: off */ + case 0x1: case 0x5: case 0x9: case 0xA: case 0xC: + asc_dvc->cfg->termination |= TERM_CTL_H; + break; + + /* TERM_CTL_H: off, TERM_CTL_L: off */ + case 0x2: case 0x6: + break; + } + } + + /* + * Clear any set TERM_CTL_H and TERM_CTL_L bits. + */ + scsi_cfg1 &= ~TERM_CTL; + + /* + * Invert the TERM_CTL_H and TERM_CTL_L bits and then + * set 'scsi_cfg1'. The TERM_POL bit does not need to be + * referenced, because the hardware internally inverts + * the Termination High and Low bits if TERM_POL is set. + */ + scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL)); + + /* + * Set SCSI_CFG1 Microcode Default Value + * + * Set filter value and possibly modified termination control + * bits in the Microcode SCSI_CFG1 Register Value. + * + * The microcode will set the SCSI_CFG1 register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, + FLTR_DISABLE | scsi_cfg1); + + /* + * Set MEM_CFG Microcode Default Value + * + * The microcode will set the MEM_CFG register using this value + * after it is started below. + * + * MEM_CFG may be accessed as a word or byte, but only bits 0-7 + * are defined. + * + * ASC-3550 has 8KB internal memory. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, + BIOS_EN | RAM_SZ_8KB); + + /* + * Set SEL_MASK Microcode Default Value + * + * The microcode will set the SEL_MASK register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK, + ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id)); + + /* + * Build carrier freelist. + * + * Driver must have already allocated memory and set 'carrier_buf'. + */ + ASC_ASSERT(asc_dvc->carrier_buf != NULL); + + carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf); + asc_dvc->carr_freelist = NULL; + if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) + { + buf_size = ADV_CARRIER_BUFSIZE; + } else + { + buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T); + } + + do { + /* + * Get physical address of the carrier 'carrp'. + */ + contig_len = sizeof(ADV_CARR_T); + carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp, + (ADV_SDCNT *) &contig_len, ADV_IS_CARRIER_FLAG)); + + buf_size -= sizeof(ADV_CARR_T); + + /* + * If the current carrier is not physically contiguous, then + * maybe there was a page crossing. Try the next carrier aligned + * start address. + */ + if (contig_len < sizeof(ADV_CARR_T)) + { + carrp++; + continue; + } + + carrp->carr_pa = carr_paddr; + carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp)); + + /* + * Insert the carrier at the beginning of the freelist. + */ + carrp->next_vpa = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist)); + asc_dvc->carr_freelist = carrp; + + carrp++; + } + while (buf_size > 0); + + /* + * Set-up the Host->RISC Initiator Command Queue (ICQ). + */ + + if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) + { + asc_dvc->err_code |= ASC_IERR_NO_CARRIER; + return ADV_ERROR; + } + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa)); + + /* + * The first command issued will be placed in the stopper carrier. + */ + asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); + + /* + * Set RISC ICQ physical address start value. + */ + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa); + + /* + * Set-up the RISC->Host Initiator Response Queue (IRQ). + */ + if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) + { + asc_dvc->err_code |= ASC_IERR_NO_CARRIER; + return ADV_ERROR; + } + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa)); + + /* + * The first command completed by the RISC will be placed in + * the stopper. + * + * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is + * completed the RISC will set the ASC_RQ_STOPPER bit. + */ + asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); + + /* + * Set RISC IRQ physical address start value. + */ + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa); + asc_dvc->carr_pending_cnt = 0; + + AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES, + (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR)); + + AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word); + AdvWriteWordRegister(iop_base, IOPW_PC, word); + + /* finally, finally, gentlemen, start your engine */ + AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN); + + /* + * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus + * Resets should be performed. The RISC has to be running + * to issue a SCSI Bus Reset. + */ + if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) + { + /* + * If the BIOS Signature is present in memory, restore the + * BIOS Handshake Configuration Table and do not perform + * a SCSI Bus Reset. + */ + if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA) + { + /* + * Restore per TID negotiated values. + */ + AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); + for (tid = 0; tid <= ADV_MAX_TID; tid++) + { + AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, + max_cmd[tid]); + } + } else + { + if (AdvResetSB(asc_dvc) != ADV_TRUE) + { + warn_code = ASC_WARN_BUSRESET_ERROR; + } + } + } + + return warn_code; +} + +/* + * Initialize the ASC-38C0800. + * + * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. + * + * For a non-fatal error return a warning code. If there are no warnings + * then 0 is returned. + * + * Needed after initialization for error recovery. + */ +STATIC int +AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc) +{ + AdvPortAddr iop_base; + ushort warn_code; + ADV_DCNT sum; + int begin_addr; + int end_addr; + ushort code_sum; + int word; + int j; + int adv_asc38C0800_expanded_size; + ADV_CARR_T *carrp; + ADV_DCNT contig_len; + ADV_SDCNT buf_size; + ADV_PADDR carr_paddr; + int i; + ushort scsi_cfg1; + uchar byte; + uchar tid; + ushort bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */ + ushort wdtr_able, sdtr_able, tagqng_able; + uchar max_cmd[ADV_MAX_TID + 1]; + + /* If there is already an error, don't continue. */ + if (asc_dvc->err_code != 0) + { + return ADV_ERROR; + } + + /* + * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800. + */ + if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) + { + asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE; + return ADV_ERROR; + } + + warn_code = 0; + iop_base = asc_dvc->iop_base; + + /* + * Save the RISC memory BIOS region before writing the microcode. + * The BIOS may already be loaded and using its RISC LRAM region + * so its region must be saved and restored. + * + * Note: This code makes the assumption, which is currently true, + * that a chip reset does not clear RISC LRAM. + */ + for (i = 0; i < ASC_MC_BIOSLEN/2; i++) + { + AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]); + } + + /* + * Save current per TID negotiated values. + */ + AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); + AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); + for (tid = 0; tid <= ADV_MAX_TID; tid++) + { + AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, + max_cmd[tid]); + } + + /* + * RAM BIST (RAM Built-In Self Test) + * + * Address : I/O base + offset 0x38h register (byte). + * Function: Bit 7-6(RW) : RAM mode + * Normal Mode : 0x00 + * Pre-test Mode : 0x40 + * RAM Test Mode : 0x80 + * Bit 5 : unused + * Bit 4(RO) : Done bit + * Bit 3-0(RO) : Status + * Host Error : 0x08 + * Int_RAM Error : 0x04 + * RISC Error : 0x02 + * SCSI Error : 0x01 + * No Error : 0x00 + * + * Note: RAM BIST code should be put right here, before loading the + * microcode and after saving the RISC memory BIOS region. + */ + + /* + * LRAM Pre-test + * + * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds. + * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return + * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset + * to NORMAL_MODE, return an error too. + */ + for (i = 0; i < 2; i++) + { + AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE); + DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */ + byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); + if ((byte & RAM_TEST_DONE) == 0 || (byte & 0x0F) != PRE_TEST_VALUE) + { + asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST; + return ADV_ERROR; + } + + AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE); + DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */ + if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST) + != NORMAL_VALUE) + { + asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST; + return ADV_ERROR; + } + } + + /* + * LRAM Test - It takes about 1.5 ms to run through the test. + * + * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds. + * If Done bit not set or Status not 0, save register byte, set the + * err_code, and return an error. + */ + AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE); + DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */ + + byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); + if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) + { + /* Get here if Done bit not set or Status not 0. */ + asc_dvc->bist_err_code = byte; /* for BIOS display message */ + asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST; + return ADV_ERROR; + } + + /* We need to reset back to normal mode after LRAM test passes. */ + AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE); + + /* + * Load the Microcode + * + * Write the microcode image to RISC memory starting at address 0. + * + */ + AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); + + /* Assume the following compressed format of the microcode buffer: + * + * 254 word (508 byte) table indexed by byte code followed + * by the following byte codes: + * + * 1-Byte Code: + * 00: Emit word 0 in table. + * 01: Emit word 1 in table. + * . + * FD: Emit word 253 in table. + * + * Multi-Byte Code: + * FE WW WW: (3 byte code) Word to emit is the next word WW WW. + * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW. + */ + word = 0; + for (i = 253 * 2; i < _adv_asc38C0800_size; i++) + { + if (_adv_asc38C0800_buf[i] == 0xff) + { + for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) + { + AdvWriteWordAutoIncLram(iop_base, (((ushort) + _adv_asc38C0800_buf[i + 3] << 8) | + _adv_asc38C0800_buf[i + 2])); + word++; + } + i += 3; + } else if (_adv_asc38C0800_buf[i] == 0xfe) + { + AdvWriteWordAutoIncLram(iop_base, (((ushort) + _adv_asc38C0800_buf[i + 2] << 8) | + _adv_asc38C0800_buf[i + 1])); i += 2; word++; } else { AdvWriteWordAutoIncLram(iop_base, (((ushort) - _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | - _adv_asc3550_buf[_adv_asc3550_buf[i] * 2])); + _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | + _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2])); word++; } } @@ -15839,12 +15843,12 @@ * the expanded mcode size. */ word *= 2; - adv_asc3550_expanded_size = word; + adv_asc38C0800_expanded_size = word; /* - * Clear the rest of ASC-3550 Internal RAM (8KB). + * Clear the rest of ASC-38C0800 Internal RAM (16KB). */ - for (; word < ADV_3550_MEMSIZE; word += 2) + for (; word < ADV_38C0800_MEMSIZE; word += 2) { AdvWriteWordAutoIncLram(iop_base, 0); } @@ -15855,12 +15859,17 @@ sum = 0; AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); - for (word = 0; word < adv_asc3550_expanded_size; word += 2) + for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) { sum += AdvReadWordAutoIncLram(iop_base); } + ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i); - if (sum != _adv_asc3550_chksum) + ASC_DBG2(1, + "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n", + (ulong) sum, (ulong) _adv_asc38C0800_chksum); + + if (sum != _adv_asc38C0800_chksum) { asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; return ADV_ERROR; @@ -15871,7 +15880,7 @@ */ for (i = 0; i < ASC_MC_BIOSLEN/2; i++) { - AdvWriteByteLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]); + AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]); } /* @@ -15889,15 +15898,26 @@ AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum); /* - * Read and save microcode version and date. + * Read microcode version and date. */ AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date); AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version); /* - * Set the chip type to indicate the ASC3550. + * Set the chip type to indicate the ASC38C0800. */ - AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550); + AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800); + + /* + * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register. + * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current + * cable detection and then we are able to read C_DET[3:0]. + * + * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1 + * Microcode Default Value' section below. + */ + scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); + AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, scsi_cfg1 | DIS_TERM_DRV); /* * If the PCI Configuration Command Register "Parity Error Response @@ -15907,22 +15927,21 @@ */ if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) { - /* - * Note: Don't remove the use of a temporary variable in - * the following code, otherwise the Microsoft C compiler - * will turn the following lines into a no-op. - */ AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); word |= CONTROL_FLAG_IGNORE_PERR; AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); } /* - * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO - * threshold of 128 bytes. This register is only accessible to the host. + * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2] + * bits for the default FIFO threshold. + * + * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes. + * + * For DMA Errata #4 set the BC_THRESH_ENB bit. */ AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0, - START_CTL_EMFU | READ_CMD_MRM); + BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM); /* * Microcode operating variables for WDTR, SDTR, and command tag @@ -15943,63 +15962,19 @@ } /* - * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2, - * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID - * bitmask. These values determine the maximum SDTR speed negotiated - * with a device. + * Set microcode operating variables for DISC and SDTR_SPEED1, + * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM + * configuration values. * * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2, * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them * without determining here whether the device supports SDTR. - * - * 4-bit speed SDTR speed name - * =========== =============== - * 0000b (0x0) SDTR disabled - * 0001b (0x1) 5 Mhz - * 0010b (0x2) 10 Mhz - * 0011b (0x3) 20 Mhz (Ultra) - * 0100b (0x4) 40 Mhz (LVD/Ultra2) - * 0101b (0x5) 80 Mhz (LVD2/Ultra3) - * 0110b (0x6) Undefined - * . - * 1111b (0xF) Undefined - */ - word = 0; - for (tid = 0; tid <= ADV_MAX_TID; tid++) - { - if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) - { - /* Set Ultra speed for TID 'tid'. */ - word |= (0x3 << (4 * (tid % 4))); - } else - { - /* Set Fast speed for TID 'tid'. */ - word |= (0x2 << (4 * (tid % 4))); - } - if (tid == 3) /* Check if done with sdtr_speed1. */ - { - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word); - word = 0; - } else if (tid == 7) /* Check if done with sdtr_speed2. */ - { - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word); - word = 0; - } else if (tid == 11) /* Check if done with sdtr_speed3. */ - { - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word); - word = 0; - } else if (tid == 15) /* Check if done with sdtr_speed4. */ - { - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word); - /* End of loop. */ - } - } - - /* - * Set microcode operating variable for the disconnect per TID bitmask. */ AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable); - + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4); /* * Set SCSI_CFG0 Microcode Default Value. @@ -16008,7 +15983,8 @@ * after it is started below. */ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0, - PARITY_EN | SEL_TMO_LONG | OUR_ID_EN | asc_dvc->chip_scsi_id); + PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN | + asc_dvc->chip_scsi_id); /* * Determine SCSI_CFG1 Microcode Default Value. @@ -16021,16 +15997,6 @@ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); /* - * If all three connectors are in use, return an error. - */ - if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 || - (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) - { - asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION; - return ADV_ERROR; - } - - /* * If the internal narrow cable is reversed all of the SCSI_CTRL * register signals will be set. Check for and return an error if * this condition is found. @@ -16042,73 +16008,88 @@ } /* - * If this is a differential board and a single-ended device - * is attached to one of the connectors, return an error. + * All kind of combinations of devices attached to one of four connectors + * are acceptable except HVD device attached. For example, LVD device can + * be attached to SE connector while SE device attached to LVD connector. + * If LVD device attached to SE connector, it only runs up to Ultra speed. + * + * If an HVD device is attached to one of LVD connectors, return an error. + * However, there is no way to detect HVD device attached to SE connectors. */ - if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) + if (scsi_cfg1 & HVD) { - asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE; + asc_dvc->err_code |= ASC_IERR_HVD_DEVICE; return ADV_ERROR; } /* - * If automatic termination control is enabled, then set the - * termination value based on a table listed in a_condor.h. + * If either SE or LVD automatic termination control is enabled, then + * set the termination value based on a table listed in a_condor.h. * - * If manual termination was specified with an EEPROM setting - * then 'termination' was set-up in AdvInitFrom3550EEPROM() and - * is ready to be 'ored' into SCSI_CFG1. + * If manual termination was specified with an EEPROM setting then + * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to + * be 'ored' into SCSI_CFG1. */ - if (asc_dvc->cfg->termination == 0) + if ((asc_dvc->cfg->termination & TERM_SE) == 0) { - /* - * The software always controls termination by setting TERM_CTL_SEL. - * If TERM_CTL_SEL were set to 0, the hardware would set termination. - */ - asc_dvc->cfg->termination |= TERM_CTL_SEL; - - switch(scsi_cfg1 & CABLE_DETECT) + /* SE automatic termination control is enabled. */ + switch(scsi_cfg1 & C_DET_SE) { - /* TERM_CTL_H: on, TERM_CTL_L: on */ - case 0x3: case 0x7: case 0xB: case 0xD: case 0xE: case 0xF: - asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L); + /* TERM_SE_HI: on, TERM_SE_LO: on */ + case 0x1: case 0x2: case 0x3: + asc_dvc->cfg->termination |= TERM_SE; break; - /* TERM_CTL_H: on, TERM_CTL_L: off */ - case 0x1: case 0x5: case 0x9: case 0xA: case 0xC: - asc_dvc->cfg->termination |= TERM_CTL_H; + /* TERM_SE_HI: on, TERM_SE_LO: off */ + case 0x0: + asc_dvc->cfg->termination |= TERM_SE_HI; break; + } + } - /* TERM_CTL_H: off, TERM_CTL_L: off */ - case 0x2: case 0x6: + if ((asc_dvc->cfg->termination & TERM_LVD) == 0) + { + /* LVD automatic termination control is enabled. */ + switch(scsi_cfg1 & C_DET_LVD) + { + /* TERM_LVD_HI: on, TERM_LVD_LO: on */ + case 0x4: case 0x8: case 0xC: + asc_dvc->cfg->termination |= TERM_LVD; + break; + + /* TERM_LVD_HI: off, TERM_LVD_LO: off */ + case 0x0: break; } } /* - * Clear any set TERM_CTL_H and TERM_CTL_L bits. + * Clear any set TERM_SE and TERM_LVD bits. */ - scsi_cfg1 &= ~TERM_CTL; + scsi_cfg1 &= (~TERM_SE & ~TERM_LVD); /* - * Invert the TERM_CTL_H and TERM_CTL_L bits and then - * set 'scsi_cfg1'. The TERM_POL bit does not need to be - * referenced, because the hardware internally inverts - * the Termination High and Low bits if TERM_POL is set. + * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'. */ - scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL)); + scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0); + + /* + * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits + * and set possibly modified termination control bits in the Microcode + * SCSI_CFG1 Register Value. + */ + scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE); /* * Set SCSI_CFG1 Microcode Default Value * - * Set filter value and possibly modified termination control + * Set possibly modified termination control and reset DIS_TERM_DRV * bits in the Microcode SCSI_CFG1 Register Value. * * The microcode will set the SCSI_CFG1 register using this value * after it is started below. */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, - FLTR_DISABLE | scsi_cfg1); + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1); /* * Set MEM_CFG Microcode Default Value @@ -16119,10 +16100,10 @@ * MEM_CFG may be accessed as a word or byte, but only bits 0-7 * are defined. * - * ASC-3550 has 8KB internal memory. + * ASC-38C0800 has 16KB internal memory. */ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, - BIOS_EN | RAM_SZ_8KB); + BIOS_EN | RAM_SZ_16KB); /* * Set SEL_MASK Microcode Default Value @@ -16134,7 +16115,7 @@ ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id)); /* - * Build carrier freelist. + * Build the carrier freelist. * * Driver must have already allocated memory and set 'carrier_buf'. */ @@ -16152,7 +16133,7 @@ do { /* - * Get physical address of the carrier 'carrp'. + * Get physical address for the carrier 'carrp'. */ contig_len = sizeof(ADV_CARR_T); carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp, @@ -16172,12 +16153,12 @@ } carrp->carr_pa = carr_paddr; - carrp->carr_va = ADV_VADDR_TO_U32(carrp); + carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp)); /* * Insert the carrier at the beginning of the freelist. */ - carrp->next_vpa = ADV_VADDR_TO_U32(asc_dvc->carr_freelist); + carrp->next_vpa = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist)); asc_dvc->carr_freelist = carrp; carrp++; @@ -16193,19 +16174,19 @@ asc_dvc->err_code |= ASC_IERR_NO_CARRIER; return ADV_ERROR; } - asc_dvc->carr_freelist = - (ADV_CARR_T *) ADV_U32_TO_VADDR(asc_dvc->icq_sp->next_vpa); + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa)); /* * The first command issued will be placed in the stopper carrier. */ - asc_dvc->icq_sp->next_vpa = ASC_CQ_STOPPER; + asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); /* * Set RISC ICQ physical address start value. + * carr_pa is LE, must be native before write */ - AdvWriteDWordLram(iop_base, ASC_MC_ICQ, - cpu_to_le32(asc_dvc->icq_sp->carr_pa)); + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa); /* * Set-up the RISC->Host Initiator Response Queue (IRQ). @@ -16215,8 +16196,8 @@ asc_dvc->err_code |= ASC_IERR_NO_CARRIER; return ADV_ERROR; } - asc_dvc->carr_freelist = - (ADV_CARR_T *) ADV_U32_TO_VADDR(asc_dvc->irq_sp->next_vpa); + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa)); /* * The first command completed by the RISC will be placed in @@ -16225,23 +16206,19 @@ * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is * completed the RISC will set the ASC_RQ_STOPPER bit. */ - asc_dvc->irq_sp->next_vpa = ASC_CQ_STOPPER; + asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); /* * Set RISC IRQ physical address start value. + * + * carr_pa is LE, must be native before write * */ - AdvWriteDWordLram(iop_base, ASC_MC_IRQ, - cpu_to_le32(asc_dvc->irq_sp->carr_pa)); + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa); asc_dvc->carr_pending_cnt = 0; AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES, (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR)); - /* - * Note: Don't remove the use of a temporary variable in - * the following code, otherwise the Microsoft C compiler - * will turn the following lines into a no-op. - */ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word); AdvWriteWordRegister(iop_base, IOPW_PC, word); @@ -16286,15 +16263,17 @@ } /* - * Initialize the ASC-38C0800. + * Initialize the ASC-38C1600. * - * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. + * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR. * * For a non-fatal error return a warning code. If there are no warnings * then 0 is returned. + * + * Needed after initialization for error recovery. */ STATIC int -AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc) +AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc) { AdvPortAddr iop_base; ushort warn_code; @@ -16302,9 +16281,9 @@ int begin_addr; int end_addr; ushort code_sum; - int word; + long word; int j; - int adv_asc38C0800_expanded_size; + int adv_asc38C1600_expanded_size; ADV_CARR_T *carrp; ADV_DCNT contig_len; ADV_SDCNT buf_size; @@ -16314,8 +16293,8 @@ uchar byte; uchar tid; ushort bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */ - ushort wdtr_able, sdtr_able, tagqng_able; - uchar max_cmd[ADV_MAX_TID + 1]; + ushort wdtr_able, sdtr_able, ppr_able, tagqng_able; + uchar max_cmd[ASC_MAX_TID + 1]; /* If there is already an error, don't continue. */ if (asc_dvc->err_code != 0) @@ -16324,9 +16303,9 @@ } /* - * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800. + * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600. */ - if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) + if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) { asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE; return ADV_ERROR; @@ -16353,15 +16332,16 @@ */ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able); AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); - for (tid = 0; tid <= ADV_MAX_TID; tid++) + for (tid = 0; tid <= ASC_MAX_TID; tid++) { AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, max_cmd[tid]); } /* - * RAM BIST (RAM Built-In Self Test) + * RAM BIST (Built-In Self Test) * * Address : I/O base + offset 0x38h register (byte). * Function: Bit 7-6(RW) : RAM mode @@ -16440,7 +16420,8 @@ */ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); - /* Assume the following compressed format of the microcode buffer: + /* + * Assume the following compressed format of the microcode buffer: * * 254 word (508 byte) table indexed by byte code followed * by the following byte codes: @@ -16456,30 +16437,30 @@ * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW. */ word = 0; - for (i = 253 * 2; i < _adv_asc38C0800_size; i++) + for (i = 253 * 2; i < _adv_asc38C1600_size; i++) { - if (_adv_asc38C0800_buf[i] == 0xff) + if (_adv_asc38C1600_buf[i] == 0xff) { - for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) + for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++) { AdvWriteWordAutoIncLram(iop_base, (((ushort) - _adv_asc38C0800_buf[i + 3] << 8) | - _adv_asc38C0800_buf[i + 2])); + _adv_asc38C1600_buf[i + 3] << 8) | + _adv_asc38C1600_buf[i + 2])); word++; } - i += 3; - } else if (_adv_asc38C0800_buf[i] == 0xfe) + i += 3; + } else if (_adv_asc38C1600_buf[i] == 0xfe) { - AdvWriteWordAutoIncLram(iop_base, (((ushort) - _adv_asc38C0800_buf[i + 2] << 8) | - _adv_asc38C0800_buf[i + 1])); + AdvWriteWordAutoIncLram(iop_base, (((ushort) + _adv_asc38C1600_buf[i + 2] << 8) | + _adv_asc38C1600_buf[i + 1])); i += 2; word++; } else { AdvWriteWordAutoIncLram(iop_base, (((ushort) - _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | - _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2])); + _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) | + _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2])); word++; } } @@ -16489,12 +16470,12 @@ * the expanded mcode size. */ word *= 2; - adv_asc38C0800_expanded_size = word; + adv_asc38C1600_expanded_size = word; /* - * Clear the rest of ASC-38C0800 Internal RAM (16KB). + * Clear the rest of ASC-38C1600 Internal RAM (32KB). */ - for (; word < ADV_38C0800_MEMSIZE; word += 2) + for (; word < ADV_38C1600_MEMSIZE; word += 2) { AdvWriteWordAutoIncLram(iop_base, 0); } @@ -16505,17 +16486,12 @@ sum = 0; AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); - for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) + for (word = 0; word < adv_asc38C1600_expanded_size; word += 2) { sum += AdvReadWordAutoIncLram(iop_base); } - ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i); - - ASC_DBG2(1, - "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n", - (ulong) sum, (ulong) _adv_asc38C0800_chksum); - if (sum != _adv_asc38C0800_chksum) + if (sum != _adv_asc38C1600_chksum) { asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; return ADV_ERROR; @@ -16550,9 +16526,9 @@ AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version); /* - * Set the chip type to indicate the ASC38C0800. + * Set the chip type to indicate the ASC38C1600. */ - AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800); + AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600); /* * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register. @@ -16573,26 +16549,30 @@ */ if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) { - /* - * Note: Don't remove the use of a temporary variable in - * the following code, otherwise the Microsoft C compiler - * will turn the following lines into a no-op. - */ AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); word |= CONTROL_FLAG_IGNORE_PERR; AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); } /* - * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2] - * bits for the default FIFO threshold. - * - * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes. - * - * For DMA Errata #4 set the BC_THRESH_ENB bit. + * If the BIOS control flag AIPP (Asynchronous Information + * Phase Protection) disable bit is not set, then set the firmware + * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable + * AIPP checking and encoding. + */ + if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) + { + AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); + word |= CONTROL_FLAG_ENABLE_AIPP; + AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); + } + + /* + * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4], + * and START_CTL_TH [3:2]. */ AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0, - BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM); + FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM); /* * Microcode operating variables for WDTR, SDTR, and command tag @@ -16634,22 +16614,24 @@ * after it is started below. */ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0, - PARITY_EN | SEL_TMO_LONG | OUR_ID_EN | asc_dvc->chip_scsi_id); + PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN | + asc_dvc->chip_scsi_id); /* - * Determine SCSI_CFG1 Microcode Default Value. + * Calculate SCSI_CFG1 Microcode Default Value. * * The microcode will set the SCSI_CFG1 register using this value * after it is started below. + * + * Each ASC-38C1600 function has only two cable detect bits. + * The bus mode override bits are in IOPB_SOFT_OVER_WR. */ - - /* Read current SCSI_CFG1 Register value. */ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); /* - * If the internal narrow cable is reversed all of the SCSI_CTRL - * register signals will be set. Check for and return an error if - * this condition is found. + * If the cable is reversed all of the SCSI_CTRL register signals + * will be set. Check for and return an error if this condition is + * found. */ if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) { @@ -16658,13 +16640,12 @@ } /* - * All kind of combinations of devices attached to one of four connectors - * are acceptable except HVD device attached. For example, LVD device can - * be attached to SE connector while SE device attached to LVD connector. - * If LVD device attached to SE connector, it only runs up to Ultra speed. + * Each ASC-38C1600 function has two connectors. Only an HVD device + * can not be connected to either connector. An LVD device or SE device + * may be connected to either connecor. If an SE device is connected, + * then at most Ultra speed (20 Mhz) can be used on both connectors. * - * If an HVD device is attached to one of LVD connectors, return an error. - * However, there is no way to detect HVD device attached to SE connectors. + * If an HVD device is attached, return an error. */ if (scsi_cfg1 & HVD) { @@ -16673,12 +16654,17 @@ } /* - * If either SE or LVD automatic termination control is enabled, then - * set the termination value based on a table listed in a_condor.h. + * Each function in the ASC-38C1600 uses only the SE cable detect and + * termination because there are two connectors for each function. Each + * function may use either LVD or SE mode. Corresponding the SE automatic + * termination control EEPROM bits are used for each function. Each + * function has its own EEPROM. If SE automatic control is enabled for + * the function, then set the termination value based on a table listed + * in a_condor.h. * - * If manual termination was specified with an EEPROM setting then - * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to - * be 'ored' into SCSI_CFG1. + * If manual termination is specified in the EEPROM for the function, + * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is + * ready to be 'ored' into SCSI_CFG1. */ if ((asc_dvc->cfg->termination & TERM_SE) == 0) { @@ -16690,51 +16676,44 @@ asc_dvc->cfg->termination |= TERM_SE; break; - /* TERM_SE_HI: on, TERM_SE_LO: off */ - case 0x0: - asc_dvc->cfg->termination |= TERM_SE_HI; - break; - } - } - - if ((asc_dvc->cfg->termination & TERM_LVD) == 0) - { - /* LVD automatic termination control is enabled. */ - switch(scsi_cfg1 & C_DET_LVD) - { - /* TERM_LVD_HI: on, TERM_LVD_LO: on */ - case 0x4: case 0x8: case 0xC: - asc_dvc->cfg->termination |= TERM_LVD; - break; - - /* TERM_LVD_HI: off, TERM_LVD_LO: off */ case 0x0: + if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0) + { + /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */ + } + else + { + /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */ + asc_dvc->cfg->termination |= TERM_SE_HI; + } break; } } /* - * Clear any set TERM_SE and TERM_LVD bits. + * Clear any set TERM_SE bits. */ - scsi_cfg1 &= (~TERM_SE & ~TERM_LVD); + scsi_cfg1 &= ~TERM_SE; /* - * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'. + * Invert the TERM_SE bits and then set 'scsi_cfg1'. */ - scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0); + scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE); /* - * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits - * and set possibly modified termination control bits in the Microcode - * SCSI_CFG1 Register Value. + * Clear Big Endian and Terminator Polarity bits and set possibly + * modified termination control bits in the Microcode SCSI_CFG1 + * Register Value. + * + * Big Endian bit is not used even on big endian machines. */ - scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE); + scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL); /* * Set SCSI_CFG1 Microcode Default Value * - * Set possibly modified termination control and reset DIS_TERM_DRV - * bits in the Microcode SCSI_CFG1 Register Value. + * Set possibly modified termination control bits in the Microcode + * SCSI_CFG1 Register Value. * * The microcode will set the SCSI_CFG1 register using this value * after it is started below. @@ -16750,10 +16729,17 @@ * MEM_CFG may be accessed as a word or byte, but only bits 0-7 * are defined. * - * ASC-38C0800 has 16KB internal memory. + * ASC-38C1600 has 32KB internal memory. + * + * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come + * out a special 16K Adv Library and Microcode version. After the issue + * resolved, we should turn back to the 32K support. Both a_condor.h and + * mcode.sas files also need to be updated. + * + * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, + * BIOS_EN | RAM_SZ_32KB); */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, - BIOS_EN | RAM_SZ_16KB); + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, BIOS_EN | RAM_SZ_16KB); /* * Set SEL_MASK Microcode Default Value @@ -16769,6 +16755,7 @@ * * Driver must have already allocated memory and set 'carrier_buf'. */ + ASC_ASSERT(asc_dvc->carrier_buf != NULL); carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf); @@ -16803,12 +16790,12 @@ } carrp->carr_pa = carr_paddr; - carrp->carr_va = ADV_VADDR_TO_U32(carrp); + carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp)); /* * Insert the carrier at the beginning of the freelist. */ - carrp->next_vpa = ADV_VADDR_TO_U32(asc_dvc->carr_freelist); + carrp->next_vpa = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist)); asc_dvc->carr_freelist = carrp; carrp++; @@ -16818,25 +16805,27 @@ /* * Set-up the Host->RISC Initiator Command Queue (ICQ). */ - if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) { asc_dvc->err_code |= ASC_IERR_NO_CARRIER; return ADV_ERROR; } - asc_dvc->carr_freelist = - (ADV_CARR_T *) ADV_U32_TO_VADDR(asc_dvc->icq_sp->next_vpa); + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa)); /* * The first command issued will be placed in the stopper carrier. */ - asc_dvc->icq_sp->next_vpa = ASC_CQ_STOPPER; + asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); /* - * Set RISC ICQ physical address start value. + * Set RISC ICQ physical address start value. Initialize the + * COMMA register to the same value otherwise the RISC will + * prematurely detect a command is available. */ - AdvWriteDWordLram(iop_base, ASC_MC_ICQ, - cpu_to_le32(asc_dvc->icq_sp->carr_pa)); + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa); + AdvWriteDWordRegister(iop_base, IOPDW_COMMA, + le32_to_cpu(asc_dvc->icq_sp->carr_pa)); /* * Set-up the RISC->Host Initiator Response Queue (IRQ). @@ -16846,8 +16835,8 @@ asc_dvc->err_code |= ASC_IERR_NO_CARRIER; return ADV_ERROR; } - asc_dvc->carr_freelist = - (ADV_CARR_T *) ADV_U32_TO_VADDR(asc_dvc->irq_sp->next_vpa); + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa)); /* * The first command completed by the RISC will be placed in @@ -16856,22 +16845,16 @@ * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is * completed the RISC will set the ASC_RQ_STOPPER bit. */ - asc_dvc->irq_sp->next_vpa = ASC_CQ_STOPPER; + asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); /* * Set RISC IRQ physical address start value. */ - AdvWriteDWordLram(iop_base, ASC_MC_IRQ, - cpu_to_le32(asc_dvc->irq_sp->carr_pa)); + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa); asc_dvc->carr_pending_cnt = 0; AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES, (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR)); - /* - * Note: Don't remove the use of a temporary variable in - * the following code, otherwise the Microsoft C compiler - * will turn the following lines into a no-op. - */ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word); AdvWriteWordRegister(iop_base, IOPW_PC, word); @@ -16887,8 +16870,7 @@ { /* * If the BIOS Signature is present in memory, restore the - * BIOS Handshake Configuration Table and do not perform - * a SCSI Bus Reset. + * per TID microcode operating variables. */ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA) { @@ -16897,8 +16879,9 @@ */ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able); AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); - for (tid = 0; tid <= ADV_MAX_TID; tid++) + for (tid = 0; tid <= ASC_MAX_TID; tid++) { AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, max_cmd[tid]); @@ -16945,8 +16928,6 @@ * Read the board's EEPROM configuration. * * Set default values if a bad checksum is found. - * - * XXX - Don't handle big-endian access to EEPROM yet. */ if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) { @@ -16967,13 +16948,13 @@ * failed. */ eep_config.serial_number_word3 = - AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 1); + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1); eep_config.serial_number_word2 = - AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 2); + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2); eep_config.serial_number_word1 = - AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 3); + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3); AdvSet3550EEPConfig(iop_base, &eep_config); } @@ -17049,7 +17030,211 @@ asc_dvc->max_host_qng = eep_config.max_host_qng; asc_dvc->max_dvc_qng = eep_config.max_dvc_qng; - + + /* + * If the EEPROM 'termination' field is set to automatic (0), then set + * the ADV_DVC_CFG 'termination' field to automatic also. + * + * If the termination is specified with a non-zero 'termination' + * value check that a legal value is set and set the ADV_DVC_CFG + * 'termination' field appropriately. + */ + if (eep_config.termination == 0) + { + asc_dvc->cfg->termination = 0; /* auto termination */ + } else + { + /* Enable manual control with low off / high off. */ + if (eep_config.termination == 1) + { + asc_dvc->cfg->termination = TERM_CTL_SEL; + + /* Enable manual control with low off / high on. */ + } else if (eep_config.termination == 2) + { + asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H; + + /* Enable manual control with low on / high on. */ + } else if (eep_config.termination == 3) + { + asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L; + } else + { + /* + * The EEPROM 'termination' field contains a bad value. Use + * automatic termination instead. + */ + asc_dvc->cfg->termination = 0; + warn_code |= ASC_WARN_EEPROM_TERMINATION; + } + } + + return warn_code; +} + +/* + * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and + * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while + * all of this is done. + * + * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. + * + * For a non-fatal error return a warning code. If there are no warnings + * then 0 is returned. + * + * Note: Chip is stopped on entry. + */ +ASC_INITFUNC( +STATIC int, +AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc) +) +{ + AdvPortAddr iop_base; + ushort warn_code; + ADVEEP_38C0800_CONFIG eep_config; + int i; + uchar tid, termination; + ushort sdtr_speed = 0; + + iop_base = asc_dvc->iop_base; + + warn_code = 0; + + /* + * Read the board's EEPROM configuration. + * + * Set default values if a bad checksum is found. + */ + if (AdvGet38C0800EEPConfig(iop_base, &eep_config) != eep_config.check_sum) + { + warn_code |= ASC_WARN_EEPROM_CHKSUM; + + /* + * Set EEPROM default values. + */ + for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) + { + *((uchar *) &eep_config + i) = + *((uchar *) &Default_38C0800_EEPROM_Config + i); + } + + /* + * Assume the 6 byte board serial number that was read + * from EEPROM is correct even if the EEPROM checksum + * failed. + */ + eep_config.serial_number_word3 = + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1); + + eep_config.serial_number_word2 = + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2); + + eep_config.serial_number_word1 = + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3); + + AdvSet38C0800EEPConfig(iop_base, &eep_config); + } + /* + * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the + * EEPROM configuration that was read. + * + * This is the mapping of EEPROM fields to Adv Library fields. + */ + asc_dvc->wdtr_able = eep_config.wdtr_able; + asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1; + asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2; + asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3; + asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4; + asc_dvc->tagqng_able = eep_config.tagqng_able; + asc_dvc->cfg->disc_enable = eep_config.disc_enable; + asc_dvc->max_host_qng = eep_config.max_host_qng; + asc_dvc->max_dvc_qng = eep_config.max_dvc_qng; + asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID); + asc_dvc->start_motor = eep_config.start_motor; + asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay; + asc_dvc->bios_ctrl = eep_config.bios_ctrl; + asc_dvc->no_scam = eep_config.scam_tolerant; + asc_dvc->cfg->serial1 = eep_config.serial_number_word1; + asc_dvc->cfg->serial2 = eep_config.serial_number_word2; + asc_dvc->cfg->serial3 = eep_config.serial_number_word3; + + /* + * For every Target ID if any of its 'sdtr_speed[1234]' bits + * are set, then set an 'sdtr_able' bit for it. + */ + asc_dvc->sdtr_able = 0; + for (tid = 0; tid <= ADV_MAX_TID; tid++) + { + if (tid == 0) + { + sdtr_speed = asc_dvc->sdtr_speed1; + } else if (tid == 4) + { + sdtr_speed = asc_dvc->sdtr_speed2; + } else if (tid == 8) + { + sdtr_speed = asc_dvc->sdtr_speed3; + } else if (tid == 12) + { + sdtr_speed = asc_dvc->sdtr_speed4; + } + if (sdtr_speed & ADV_MAX_TID) + { + asc_dvc->sdtr_able |= (1 << tid); + } + sdtr_speed >>= 4; + } + + /* + * Set the host maximum queuing (max. 253, min. 16) and the per device + * maximum queuing (max. 63, min. 4). + */ + if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) + { + eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG; + } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) + { + /* If the value is zero, assume it is uninitialized. */ + if (eep_config.max_host_qng == 0) + { + eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG; + } else + { + eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG; + } + } + + if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) + { + eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG; + } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) + { + /* If the value is zero, assume it is uninitialized. */ + if (eep_config.max_dvc_qng == 0) + { + eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG; + } else + { + eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG; + } + } + + /* + * If 'max_dvc_qng' is greater than 'max_host_qng', then + * set 'max_dvc_qng' to 'max_host_qng'. + */ + if (eep_config.max_dvc_qng > eep_config.max_host_qng) + { + eep_config.max_dvc_qng = eep_config.max_host_qng; + } + + /* + * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng' + * values based on possibly adjusted EEPROM values. + */ + asc_dvc->max_host_qng = eep_config.max_host_qng; + asc_dvc->max_dvc_qng = eep_config.max_dvc_qng; + /* * If the EEPROM 'termination' field is set to automatic (0), then set * the ADV_DVC_CFG 'termination' field to automatic also. @@ -17058,32 +17243,63 @@ * value check that a legal value is set and set the ADV_DVC_CFG * 'termination' field appropriately. */ - if (eep_config.termination == 0) + if (eep_config.termination_se == 0) { - asc_dvc->cfg->termination = 0; /* auto termination */ + termination = 0; /* auto termination for SE */ } else { /* Enable manual control with low off / high off. */ - if (eep_config.termination == 1) + if (eep_config.termination_se == 1) { - asc_dvc->cfg->termination = TERM_CTL_SEL; + termination = 0; /* Enable manual control with low off / high on. */ - } else if (eep_config.termination == 2) + } else if (eep_config.termination_se == 2) { - asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H; + termination = TERM_SE_HI; /* Enable manual control with low on / high on. */ - } else if (eep_config.termination == 3) + } else if (eep_config.termination_se == 3) { - asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L; + termination = TERM_SE; } else { /* - * The EEPROM 'termination' field contains a bad value. Use - * automatic termination instead. + * The EEPROM 'termination_se' field contains a bad value. + * Use automatic termination instead. */ - asc_dvc->cfg->termination = 0; + termination = 0; + warn_code |= ASC_WARN_EEPROM_TERMINATION; + } + } + + if (eep_config.termination_lvd == 0) + { + asc_dvc->cfg->termination = termination; /* auto termination for LVD */ + } else + { + /* Enable manual control with low off / high off. */ + if (eep_config.termination_lvd == 1) + { + asc_dvc->cfg->termination = termination; + + /* Enable manual control with low off / high on. */ + } else if (eep_config.termination_lvd == 2) + { + asc_dvc->cfg->termination = termination | TERM_LVD_HI; + + /* Enable manual control with low on / high on. */ + } else if (eep_config.termination_lvd == 3) + { + asc_dvc->cfg->termination = + termination | TERM_LVD; + } else + { + /* + * The EEPROM 'termination_lvd' field contains a bad value. + * Use automatic termination instead. + */ + asc_dvc->cfg->termination = termination; warn_code |= ASC_WARN_EEPROM_TERMINATION; } } @@ -17092,11 +17308,11 @@ } /* - * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and - * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while + * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and + * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while * all of this is done. * - * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. + * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR. * * For a non-fatal error return a warning code. If there are no warnings * then 0 is returned. @@ -17105,12 +17321,12 @@ */ ASC_INITFUNC( STATIC int, -AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc) +AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc) ) { AdvPortAddr iop_base; ushort warn_code; - ADVEEP_38C0800_CONFIG eep_config; + ADVEEP_38C1600_CONFIG eep_config; int i; uchar tid, termination; ushort sdtr_speed = 0; @@ -17123,20 +17339,59 @@ * Read the board's EEPROM configuration. * * Set default values if a bad checksum is found. - * - * XXX - Don't handle big-endian access to EEPROM yet. */ - if (AdvGet38C0800EEPConfig(iop_base, &eep_config) != eep_config.check_sum) + if (AdvGet38C1600EEPConfig(iop_base, &eep_config) != eep_config.check_sum) { warn_code |= ASC_WARN_EEPROM_CHKSUM; /* * Set EEPROM default values. */ - for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) + for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++) { - *((uchar *) &eep_config + i) = - *((uchar *) &Default_38C0800_EEPROM_Config + i); + if (i == 1 && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) != 0) + { + /* + * Set Function 1 EEPROM Word 0 MSB + * + * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11) + * EEPROM bits. + * + * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and + * old Mac system booting problem. The Expansion ROM must + * be disabled in Function 1 for these systems. + * + */ + *((uchar *) &eep_config + i) = + ((*((uchar *) &Default_38C1600_EEPROM_Config + i)) & + (~(((ADV_EEPROM_BIOS_ENABLE | ADV_EEPROM_INTAB) >> 8) & + 0xFF))); + + /* + * Set the INTAB (bit 11) if the GPIO 0 input indicates + * the Function 1 interrupt line is wired to INTA. + * + * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input: + * 1 - Function 1 interrupt line wired to INT A. + * 0 - Function 1 interrupt line wired to INT B. + * + * Note: Adapter boards always have Function 0 wired to INTA. + * Put all 5 GPIO bits in input mode and then read + * their input values. + */ + AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL, 0); + if (AdvReadByteRegister(iop_base, IOPB_GPIO_DATA) & 0x01) + { + /* Function 1 interrupt wired to INTA; Set EEPROM bit. */ + *((uchar *) &eep_config + i) |= + ((ADV_EEPROM_INTAB >> 8) & 0xFF); + } + } + else + { + *((uchar *) &eep_config + i) = + *((uchar *) &Default_38C1600_EEPROM_Config + i); + } } /* @@ -17145,18 +17400,19 @@ * failed. */ eep_config.serial_number_word3 = - AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 1); + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1); eep_config.serial_number_word2 = - AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 2); + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2); eep_config.serial_number_word1 = - AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 3); + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3); - AdvSet38C0800EEPConfig(iop_base, &eep_config); + AdvSet38C1600EEPConfig(iop_base, &eep_config); } + /* - * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the + * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the * EEPROM configuration that was read. * * This is the mapping of EEPROM fields to Adv Library fields. @@ -17166,25 +17422,23 @@ asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2; asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3; asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4; + asc_dvc->ppr_able = 0; asc_dvc->tagqng_able = eep_config.tagqng_able; asc_dvc->cfg->disc_enable = eep_config.disc_enable; asc_dvc->max_host_qng = eep_config.max_host_qng; asc_dvc->max_dvc_qng = eep_config.max_dvc_qng; - asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID); + asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID); asc_dvc->start_motor = eep_config.start_motor; asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay; asc_dvc->bios_ctrl = eep_config.bios_ctrl; asc_dvc->no_scam = eep_config.scam_tolerant; - asc_dvc->cfg->serial1 = eep_config.serial_number_word1; - asc_dvc->cfg->serial2 = eep_config.serial_number_word2; - asc_dvc->cfg->serial3 = eep_config.serial_number_word3; /* * For every Target ID if any of its 'sdtr_speed[1234]' bits * are set, then set an 'sdtr_able' bit for it. */ asc_dvc->sdtr_able = 0; - for (tid = 0; tid <= ADV_MAX_TID; tid++) + for (tid = 0; tid <= ASC_MAX_TID; tid++) { if (tid == 0) { @@ -17199,7 +17453,7 @@ { sdtr_speed = asc_dvc->sdtr_speed4; } - if (sdtr_speed & ADV_MAX_TID) + if (sdtr_speed & ASC_MAX_TID) { asc_dvc->sdtr_able |= (1 << tid); } @@ -17250,7 +17504,7 @@ } /* - * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng' + * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng' * values based on possibly adjusted EEPROM values. */ asc_dvc->max_host_qng = eep_config.max_host_qng; @@ -17258,10 +17512,10 @@ /* * If the EEPROM 'termination' field is set to automatic (0), then set - * the ADV_DVC_CFG 'termination' field to automatic also. + * the ASC_DVC_CFG 'termination' field to automatic also. * * If the termination is specified with a non-zero 'termination' - * value check that a legal value is set and set the ADV_DVC_CFG + * value check that a legal value is set and set the ASC_DVC_CFG * 'termination' field appropriately. */ if (eep_config.termination_se == 0) @@ -17341,25 +17595,37 @@ ushort wval, chksum; ushort *wbuf; int eep_addr; + ushort *charfields; + charfields = (ushort *) &ADVEEP_3550_Config_Field_IsChar; wbuf = (ushort *) cfg_buf; chksum = 0; - for (eep_addr = ASC_EEP_DVC_CFG_BEGIN; - eep_addr < ASC_EEP_DVC_CFG_END; + for (eep_addr = ADV_EEP_DVC_CFG_BEGIN; + eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) { wval = AdvReadEEPWord(iop_base, eep_addr); - chksum += wval; - *wbuf = wval; + chksum += wval; /* Checksum is calculated from word values. */ + if (*charfields++) { + *wbuf = le16_to_cpu(wval); + } else { + *wbuf = wval; + } } + /* Read checksum word. */ *wbuf = AdvReadEEPWord(iop_base, eep_addr); - wbuf++; - for (eep_addr = ASC_EEP_DVC_CTL_BEGIN; - eep_addr < ASC_EEP_MAX_WORD_ADDR; + wbuf++; charfields++; + + /* Read rest of EEPROM not covered by the checksum. */ + for (eep_addr = ADV_EEP_DVC_CTL_BEGIN; + eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) { *wbuf = AdvReadEEPWord(iop_base, eep_addr); + if (*charfields++) { + *wbuf = le16_to_cpu(*wbuf); + } } return chksum; } @@ -17378,29 +17644,89 @@ ushort wval, chksum; ushort *wbuf; int eep_addr; + ushort *charfields; + charfields = (ushort *) &ADVEEP_38C0800_Config_Field_IsChar; wbuf = (ushort *) cfg_buf; chksum = 0; - for (eep_addr = ASC_EEP_DVC_CFG_BEGIN; - eep_addr < ASC_EEP_DVC_CFG_END; + for (eep_addr = ADV_EEP_DVC_CFG_BEGIN; + eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) { wval = AdvReadEEPWord(iop_base, eep_addr); - chksum += wval; - *wbuf = wval; + chksum += wval; /* Checksum is calculated from word values. */ + if (*charfields++) { + *wbuf = le16_to_cpu(wval); + } else { + *wbuf = wval; + } } + /* Read checksum word. */ *wbuf = AdvReadEEPWord(iop_base, eep_addr); - wbuf++; - for (eep_addr = ASC_EEP_DVC_CTL_BEGIN; - eep_addr < ASC_EEP_MAX_WORD_ADDR; + wbuf++; charfields++; + + /* Read rest of EEPROM not covered by the checksum. */ + for (eep_addr = ADV_EEP_DVC_CTL_BEGIN; + eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) { *wbuf = AdvReadEEPWord(iop_base, eep_addr); + if (*charfields++) { + *wbuf = le16_to_cpu(*wbuf); + } } return chksum; } +/* + * Read EEPROM configuration into the specified buffer. + * + * Return a checksum based on the EEPROM configuration read. + */ +ASC_INITFUNC( +STATIC ushort, +AdvGet38C1600EEPConfig(AdvPortAddr iop_base, + ADVEEP_38C1600_CONFIG *cfg_buf) +) +{ + ushort wval, chksum; + ushort *wbuf; + int eep_addr; + ushort *charfields; + + charfields = (ushort*) &ADVEEP_38C1600_Config_Field_IsChar; + wbuf = (ushort *) cfg_buf; + chksum = 0; + + for (eep_addr = ADV_EEP_DVC_CFG_BEGIN; + eep_addr < ADV_EEP_DVC_CFG_END; + eep_addr++, wbuf++) + { + wval = AdvReadEEPWord(iop_base, eep_addr); + chksum += wval; /* Checksum is calculated from word values. */ + if (*charfields++) { + *wbuf = le16_to_cpu(wval); + } else { + *wbuf = wval; + } + } + /* Read checksum word. */ + *wbuf = AdvReadEEPWord(iop_base, eep_addr); + wbuf++; charfields++; + + /* Read rest of EEPROM not covered by the checksum. */ + for (eep_addr = ADV_EEP_DVC_CTL_BEGIN; + eep_addr < ADV_EEP_MAX_WORD_ADDR; + eep_addr++, wbuf++) + { + *wbuf = AdvReadEEPWord(iop_base, eep_addr); + if (*charfields++) { + *wbuf = le16_to_cpu(*wbuf); + } + } + return chksum; +} /* * Read the EEPROM from specified location @@ -17426,7 +17752,7 @@ { int eep_delay_ms; - for (eep_delay_ms = 0; eep_delay_ms < ASC_EEP_DELAY_MS; eep_delay_ms++) + for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) { if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) { @@ -17449,41 +17775,57 @@ { ushort *wbuf; ushort addr, chksum; + ushort *charfields; wbuf = (ushort *) cfg_buf; + charfields = (ushort *) &ADVEEP_3550_Config_Field_IsChar; chksum = 0; AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE); AdvWaitEEPCmd(iop_base); /* - * Write EEPROM from word 0 to word 20 + * Write EEPROM from word 0 to word 20. */ - for (addr = ASC_EEP_DVC_CFG_BEGIN; - addr < ASC_EEP_DVC_CFG_END; addr++, wbuf++) + for (addr = ADV_EEP_DVC_CFG_BEGIN; + addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) { - chksum += *wbuf; - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf); + ushort word; + + if (*charfields++) { + word = cpu_to_le16(*wbuf); + } else { + word = *wbuf; + } + chksum += *wbuf; /* Checksum is calculated from word values. */ + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); AdvWaitEEPCmd(iop_base); - DvcSleepMilliSecond(ASC_EEP_DELAY_MS); + DvcSleepMilliSecond(ADV_EEP_DELAY_MS); } /* - * Write EEPROM checksum at word 21 + * Write EEPROM checksum at word 21. */ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum); AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); AdvWaitEEPCmd(iop_base); - wbuf++; /* skip over check_sum */ + wbuf++; charfields++; /* - * Write EEPROM OEM name at words 22 to 29 + * Write EEPROM OEM name at words 22 to 29. */ - for (addr = ASC_EEP_DVC_CTL_BEGIN; - addr < ASC_EEP_MAX_WORD_ADDR; addr++, wbuf++) + for (addr = ADV_EEP_DVC_CTL_BEGIN; + addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) { - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf); + ushort word; + + if (*charfields++) { + word = cpu_to_le16(*wbuf); + } else { + word = *wbuf; + } + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); AdvWaitEEPCmd(iop_base); } @@ -17500,42 +17842,126 @@ ADVEEP_38C0800_CONFIG *cfg_buf) { ushort *wbuf; + ushort *charfields; ushort addr, chksum; wbuf = (ushort *) cfg_buf; + charfields = (ushort *) &ADVEEP_38C0800_Config_Field_IsChar; + chksum = 0; + + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE); + AdvWaitEEPCmd(iop_base); + + /* + * Write EEPROM from word 0 to word 20. + */ + for (addr = ADV_EEP_DVC_CFG_BEGIN; + addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) + { + ushort word; + + if (*charfields++) { + word = cpu_to_le16(*wbuf); + } else { + word = *wbuf; + } + chksum += *wbuf; /* Checksum is calculated from word values. */ + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + DvcSleepMilliSecond(ADV_EEP_DELAY_MS); + } + + /* + * Write EEPROM checksum at word 21. + */ + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + wbuf++; charfields++; + + /* + * Write EEPROM OEM name at words 22 to 29. + */ + for (addr = ADV_EEP_DVC_CTL_BEGIN; + addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) + { + ushort word; + + if (*charfields++) { + word = cpu_to_le16(*wbuf); + } else { + word = *wbuf; + } + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + } + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE); + AdvWaitEEPCmd(iop_base); + return; +} + +/* + * Write the EEPROM from 'cfg_buf'. + */ +void +AdvSet38C1600EEPConfig(AdvPortAddr iop_base, + ADVEEP_38C1600_CONFIG *cfg_buf) +{ + ushort *wbuf; + ushort *charfields; + ushort addr, chksum; + + wbuf = (ushort *) cfg_buf; + charfields = (ushort *) &ADVEEP_38C1600_Config_Field_IsChar; chksum = 0; AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE); AdvWaitEEPCmd(iop_base); /* - * Write EEPROM from word 0 to word 20 + * Write EEPROM from word 0 to word 20. */ - for (addr = ASC_EEP_DVC_CFG_BEGIN; - addr < ASC_EEP_DVC_CFG_END; addr++, wbuf++) + for (addr = ADV_EEP_DVC_CFG_BEGIN; + addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) { - chksum += *wbuf; - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf); + ushort word; + + if (*charfields++) { + word = cpu_to_le16(*wbuf); + } else { + word = *wbuf; + } + chksum += *wbuf; /* Checksum is calculated from word values. */ + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); AdvWaitEEPCmd(iop_base); - DvcSleepMilliSecond(ASC_EEP_DELAY_MS); + DvcSleepMilliSecond(ADV_EEP_DELAY_MS); } /* - * Write EEPROM checksum at word 21 + * Write EEPROM checksum at word 21. */ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum); AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); AdvWaitEEPCmd(iop_base); - wbuf++; /* skip over check_sum */ + wbuf++; charfields++; /* - * Write EEPROM OEM name at words 22 to 29 + * Write EEPROM OEM name at words 22 to 29. */ - for (addr = ASC_EEP_DVC_CTL_BEGIN; - addr < ASC_EEP_MAX_WORD_ADDR; addr++, wbuf++) + for (addr = ADV_EEP_DVC_CTL_BEGIN; + addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) { - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf); + ushort word; + + if (*charfields++) { + word = cpu_to_le16(*wbuf); + } else { + word = *wbuf; + } + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); AdvWaitEEPCmd(iop_base); } @@ -17570,7 +17996,7 @@ AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq) { - int last_int_level; + ulong last_int_level; AdvPortAddr iop_base; ADV_DCNT req_size; ADV_PADDR req_paddr; @@ -17598,10 +18024,11 @@ */ if ((new_carrp = asc_dvc->carr_freelist) == NULL) { + DvcLeaveCritical(last_int_level); return ADV_BUSY; } - asc_dvc->carr_freelist = - (ADV_CARR_T *) ADV_U32_TO_VADDR(new_carrp->next_vpa); + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa)); asc_dvc->carr_pending_cnt++; /* @@ -17609,7 +18036,7 @@ * to the stopper value. The current stopper will be changed * below to point to the new stopper. */ - new_carrp->next_vpa = ASC_CQ_STOPPER; + new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); /* * Clear the ADV_SCSI_REQ_Q done flag. @@ -17617,17 +18044,20 @@ scsiq->a_flag &= ~ADV_SCSIQ_DONE; req_size = sizeof(ADV_SCSI_REQ_Q); - req_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, scsiq, (uchar *) scsiq, - (ADV_SDCNT *) &req_size, ADV_IS_SCSIQ_FLAG)); + req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *) scsiq, + (ADV_SDCNT *) &req_size, ADV_IS_SCSIQ_FLAG); - ASC_ASSERT(ADV_DWALIGN(req_paddr) == req_paddr); + ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr); ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q)); + /* Wait for assertion before making little-endian */ + req_paddr = cpu_to_le32(req_paddr); + /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */ - scsiq->scsiq_ptr = ADV_VADDR_TO_U32(scsiq); + scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq)); scsiq->scsiq_rptr = req_paddr; - scsiq->carr_va = ADV_VADDR_TO_U32(asc_dvc->icq_sp); + scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp)); /* * Every ADV_CARR_T.carr_pa is byte swapped to little-endian * order during initialization. @@ -17653,18 +18083,30 @@ */ asc_dvc->icq_sp = new_carrp; - /* - * Tickle the RISC to tell it to read its Command Queue Head pointer. - */ - AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A); - if (asc_dvc->chip_type == ADV_CHIP_ASC3550) + if (asc_dvc->chip_type == ADV_CHIP_ASC3550 || + asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { /* - * Clear the tickle value. In the ASC-3550 the RISC flag - * command 'clr_tickle_a' does not work unless the host - * value is cleared. + * Tickle the RISC to tell it to read its Command Queue Head pointer. */ - AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP); + AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A); + if (asc_dvc->chip_type == ADV_CHIP_ASC3550) + { + /* + * Clear the tickle value. In the ASC-3550 the RISC flag + * command 'clr_tickle_a' does not work unless the host + * value is cleared. + */ + AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP); + } + } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) + { + /* + * Notify the RISC a carrier is ready by writing the physical + * address of the new carrier stopper to the COMMA register. + */ + AdvWriteDWordRegister(iop_base, IOPDW_COMMA, + le32_to_cpu(new_carrp->carr_pa)); } DvcLeaveCritical(last_int_level); @@ -17731,6 +18173,7 @@ { int status; ushort wdtr_able, sdtr_able, tagqng_able; + ushort ppr_able = 0; uchar tid, max_cmd[ADV_MAX_TID + 1]; AdvPortAddr iop_base; ushort bios_sig; @@ -17742,6 +18185,10 @@ */ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) + { + AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able); + } AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); for (tid = 0; tid <= ADV_MAX_TID; tid++) { @@ -17771,7 +18218,11 @@ * re-initializing the chip. */ asc_dvc->err_code = 0; - if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) + if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) + { + status = AdvInitAsc38C1600Driver(asc_dvc); + } + else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { status = AdvInitAsc38C0800Driver(asc_dvc); } else @@ -17798,6 +18249,10 @@ */ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) + { + AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able); + } AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); for (tid = 0; tid <= ADV_MAX_TID; tid++) { @@ -17848,6 +18303,7 @@ if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB | ADV_INTR_STATUS_INTRC)) == 0) { + DvcLeaveCritical(flags); return ADV_FALSE; } @@ -17861,13 +18317,18 @@ uchar intrb_code; AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code); - if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE && - asc_dvc->carr_pending_cnt != 0) + + if (asc_dvc->chip_type == ADV_CHIP_ASC3550 || + asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { - AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A); - if (asc_dvc->chip_type == ADV_CHIP_ASC3550) + if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE && + asc_dvc->carr_pending_cnt != 0) { - AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP); + AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A); + if (asc_dvc->chip_type == ADV_CHIP_ASC3550) + { + AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP); + } } } @@ -17880,7 +18341,8 @@ /* * Check if the IRQ stopper carrier contains a completed request. */ - while (((irq_next_vpa = asc_dvc->irq_sp->next_vpa) & ASC_RQ_DONE) != 0) + while (((irq_next_vpa = + le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) { /* * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure. @@ -17891,7 +18353,20 @@ * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr' * in AdvExeScsiQueue(). */ - scsiq = (ADV_SCSI_REQ_Q *) ADV_U32_TO_VADDR(asc_dvc->irq_sp->areq_vpa); + scsiq = (ADV_SCSI_REQ_Q *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa)); + + /* + * Request finished with good status and the queue was not + * DMAed to host memory by the firmware. Set all status fields + * to indicate good status. + */ + if ((irq_next_vpa & ASC_RQ_GOOD) != 0) + { + scsiq->done_status = QD_NO_ERROR; + scsiq->host_status = scsiq->scsi_status = 0; + scsiq->data_cnt = 0L; + } /* * Advance the stopper pointer to the next carrier @@ -17902,7 +18377,8 @@ asc_dvc->irq_sp = (ADV_CARR_T *) ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa)); - free_carrp->next_vpa = ADV_VADDR_TO_U32(asc_dvc->carr_freelist); + free_carrp->next_vpa = + cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist)); asc_dvc->carr_freelist = free_carrp; asc_dvc->carr_pending_cnt--; @@ -17914,23 +18390,20 @@ */ scsiq->cntl = 0; -#if __BIG_ENDIAN - /* - * After the request completes the only field in the ASC_SCSI_REQ_Q - * structure needs to be byte swapped from little endian order to - * big endian order is the residual data count. - */ - scsiqp->data_cnt = le32_to_cpu(scsiqp->data_cnt); -#endif /* __BIG_ENDIAN */ - /* * If the command that completed was a SCSI INQUIRY and * LUN 0 was sent the command, then process the INQUIRY * command information for the device. + * + * Note: If data returned were either VPD or CmdDt data, + * don't process the INQUIRY command information for + * the device, otherwise may erroneously set *_able bits. */ if (scsiq->done_status == QD_NO_ERROR && scsiq->cdb[0] == SCSICMD_Inquiry && - scsiq->target_lun == 0) + scsiq->target_lun == 0 && + (scsiq->cdb[1] & ADV_INQ_RTN_VPD_AND_CMDDT) + == ADV_INQ_RTN_STD_INQUIRY_DATA) { AdvInquiryHandling(asc_dvc, scsiq); } @@ -17982,7 +18455,7 @@ ushort idle_cmd, ADV_DCNT idle_cmd_parameter) { - int last_int_level; + ulong last_int_level; int result; ADV_DCNT i, j; AdvPortAddr iop_base; @@ -18005,8 +18478,8 @@ * followed, the microcode may process the idle command before the * parameters have been written to LRAM. */ - AdvWriteDWordLram(iop_base, ASC_MC_IDLE_CMD_PARAMETER, - idle_cmd_parameter); + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER, + cpu_to_le32(idle_cmd_parameter)); AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd); /* @@ -18072,7 +18545,8 @@ * microcode to the transfer residual count. */ - if (scsiq->cdb[4] < 8 || (scsiq->cdb[4] - scsiq->data_cnt) < 8) + if (scsiq->cdb[4] < 8 || + (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) < 8) { return; } @@ -18085,7 +18559,7 @@ /* * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices. */ - if (inq->rsp_data_fmt < 2 && inq->ansi_apr_ver < 2) + if (ADV_INQ_RESPONSE_FMT(inq) < 2 && ADV_INQ_ANSI_VER(inq) < 2) { return; } else @@ -18109,7 +18583,7 @@ * device's 'wdtr_able' bit and write the new value to the * microcode. */ - if ((asc_dvc->wdtr_able & tidmask) && inq->WBus16) + if ((asc_dvc->wdtr_able & tidmask) && ADV_INQ_WIDE16(inq)) { AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word); if ((cfg_word & tidmask) == 0) @@ -18140,7 +18614,7 @@ * supports synchronous transfers, then turn on the device's * 'sdtr_able' bit. Write the new value to the microcode. */ - if ((asc_dvc->sdtr_able & tidmask) && inq->Sync) + if ((asc_dvc->sdtr_able & tidmask) && ADV_INQ_SYNC(inq)) { AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word); if ((cfg_word & tidmask) == 0) @@ -18158,6 +18632,29 @@ AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word); } } + /* + * If the Inquiry data included enough space for the SPI-3 + * Clocking field, then check if DT mode is supported. + */ + if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600 && + (scsiq->cdb[4] >= 57 || + (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) >= 57)) + { + /* + * PPR (Parallel Protocol Request) Capable + * + * If the device supports DT mode, then it must be PPR capable. + * The PPR message will be used in place of the SDTR and WDTR + * messages to negotiate synchronous speed and offset, transfer + * width, and protocol options. + */ + if (ADV_INQ_CLOCKING(inq) & ADV_INQ_CLOCKING_DT_ONLY) + { + AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, asc_dvc->ppr_able); + asc_dvc->ppr_able |= tidmask; + AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, asc_dvc->ppr_able); + } + } /* * If the EEPROM enabled Tag Queuing for the device and the @@ -18171,7 +18668,7 @@ * disabling Tag Queuing in the BIOS devices with Tag Queuing * bugs will at least work with the BIOS. */ - if ((asc_dvc->tagqng_able & tidmask) && inq->CmdQue) + if ((asc_dvc->tagqng_able & tidmask) && ADV_INQ_CMD_QUEUE(inq)) { AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word); cfg_word |= tidmask; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/advansys.h linux.ac/drivers/scsi/advansys.h --- linux.vanilla/drivers/scsi/advansys.h Mon Dec 11 21:18:51 2000 +++ linux.ac/drivers/scsi/advansys.h Sat Apr 14 15:48:39 2001 @@ -1,9 +1,8 @@ -/* $Id: advansys.h,v 1.18 1999/11/29 21:47:16 bobf Exp bobf $ */ - /* * advansys.h - Linux Host Driver for AdvanSys SCSI Adapters * - * Copyright (c) 1995-1998 Advanced System Products, Inc. + * Copyright (c) 1995-2000 Advanced System Products, Inc. + * Copyright (c) 2000-2001 ConnectCom Solutions, Inc. * All Rights Reserved. * * Redistribution and use in source and binary forms, with or without @@ -11,49 +10,57 @@ * code retain the above copyright notice and this comment without * modification. * + * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys) + * changed its name to ConnectCom Solutions, Inc. + * * There is an AdvanSys Linux WWW page at: + * http://www.connectcom.net/downloads/software/os/linux.html * http://www.advansys.com/linux.html * - * The latest version of the AdvanSys driver is available at: - * ftp://ftp.advansys.com/pub/linux + * The latest released version of the AdvanSys driver is available at: + * ftp://ftp.advansys.com/pub/linux/linux.tgz + * ftp://ftp.connectcom.net/pub/linux/linux.tgz * * Please send questions, comments, bug reports to: - * bobf@advansys.com (Bob Frey) + * linux@connectcom.net or bfrey@turbolinux.com.cn */ #ifndef _ADVANSYS_H #define _ADVANSYS_H -/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */ -#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) - +#include <linux/config.h> #ifndef LINUX_VERSION_CODE #include <linux/version.h> #endif /* LINUX_VERSION_CODE */ +/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */ +#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) +/* Driver supported only in version 2.2 and version >= 2.4. */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,2,0) || \ + (LINUX_VERSION_CODE > ASC_LINUX_VERSION(2,3,0) && \ + LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,4,0)) +#error "AdvanSys driver supported only in 2.2 and 2.4 or greater kernels." +#endif +#define ASC_LINUX_KERNEL22 (LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,4,0)) +#define ASC_LINUX_KERNEL24 (LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,4,0)) + /* * Scsi_Host_Template function prototypes. */ int advansys_detect(Scsi_Host_Template *); int advansys_release(struct Scsi_Host *); const char *advansys_info(struct Scsi_Host *); -int advansys_command(Scsi_Cmnd *); int advansys_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); -int advansys_abort(Scsi_Cmnd *); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) int advansys_reset(Scsi_Cmnd *); -#else /* version >= v1.3.89 */ -int advansys_reset(Scsi_Cmnd *, unsigned int); -#endif /* version >= v1.3.89 */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) -int advansys_biosparam(Disk *, int, int[]); -#else /* version >= v1.3.0 */ int advansys_biosparam(Disk *, kdev_t, int[]); +#ifdef CONFIG_PROC_FS #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28) extern struct proc_dir_entry proc_scsi_advansys; #endif /* version < v2.3.28 */ int advansys_proc_info(char *, char **, off_t, int, int, int); -#endif /* version >= v1.3.0 */ +#else /* !defined(CONFIG_PROC_FS) */ +#define advansys_proc_info NULL +#endif /* !defined(CONFIG_PROC_FS) */ /* init/main.c setup function */ void advansys_setup(char *, int *); @@ -61,108 +68,24 @@ /* * AdvanSys Host Driver Scsi_Host_Template (struct SHT) from hosts.h. */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) -#define ADVANSYS { \ - NULL, /* struct SHT *next */ \ - NULL, /* int *usage_count */ \ - "advansys", /* char *name */ \ - advansys_detect, /* int (*detect)(struct SHT *) */ \ - advansys_release, /* int (*release)(struct Scsi_Host *) */ \ - advansys_info, /* const char *(*info)(struct Scsi_Host *) */ \ - advansys_command, /* int (*command)(Scsi_Cmnd *) */ \ - advansys_queuecommand, \ - /* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \ - advansys_abort, /* int (*abort)(Scsi_Cmnd *) */ \ - advansys_reset, /* int (*reset)(Scsi_Cmnd *) */ \ - NULL, /* int (*slave_attach)(int, int) */ \ - advansys_biosparam, /* int (* bios_param)(Disk *, int, int []) */ \ - /* \ - * The following fields are set per adapter in advansys_detect(). \ - */ \ - 0, /* int can_queue */ \ - 0, /* int this_id */ \ - 0, /* short unsigned int sg_tablesize */ \ - 0, /* short cmd_per_lun */ \ - 0, /* unsigned char present */ \ - /* \ - * Because the driver may control an ISA adapter 'unchecked_isa_dma' \ - * must be set. The flag will be cleared in advansys_detect for non-ISA \ - * adapters. Refer to the comment in scsi_module.c for more information. \ - */ \ - 1, /* unsigned unchecked_isa_dma:1 */ \ - /* \ - * All adapters controlled by this driver are capable of large \ - * scatter-gather lists. According to the mid-level SCSI documentation \ - * this obviates any performance gain provided by setting \ - * 'use_clustering'. But empirically while CPU utilization is increased \ - * by enabling clustering, I/O throughput increases as well. \ - */ \ - ENABLE_CLUSTERING, /* unsigned use_clustering:1 */ \ -} -#elif LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,75) -#define ADVANSYS { \ - NULL, /* struct SHT *next */ \ - NULL, \ - /* version < v2.1.23 long *usage_count */ \ - /* version >= v2.1.23 struct module * */ \ - &proc_scsi_advansys, /* struct proc_dir_entry *proc_dir */ \ - advansys_proc_info, \ - /* int (*proc_info)(char *, char **, off_t, int, int, int) */ \ - "advansys", /* const char *name */ \ - advansys_detect, /* int (*detect)(struct SHT *) */ \ - advansys_release, /* int (*release)(struct Scsi_Host *) */ \ - advansys_info, /* const char *(*info)(struct Scsi_Host *) */ \ - advansys_command, /* int (*command)(Scsi_Cmnd *) */ \ - advansys_queuecommand, \ - /* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \ - advansys_abort, /* int (*abort)(Scsi_Cmnd *) */ \ - advansys_reset, \ - /* version < v1.3.89 int (*reset)(Scsi_Cmnd *) */ \ - /* version >= v1.3.89 int (*reset)(Scsi_Cmnd *, unsigned int) */ \ - NULL, /* int (*slave_attach)(int, int) */ \ - advansys_biosparam, /* int (* bios_param)(Disk *, kdev_t, int []) */ \ - /* \ - * The following fields are set per adapter in advansys_detect(). \ - */ \ - 0, /* int can_queue */ \ - 0, /* int this_id */ \ - 0, /* short unsigned int sg_tablesize */ \ - 0, /* short cmd_per_lun */ \ - 0, /* unsigned char present */ \ - /* \ - * Because the driver may control an ISA adapter 'unchecked_isa_dma' \ - * must be set. The flag will be cleared in advansys_detect for non-ISA \ - * adapters. Refer to the comment in scsi_module.c for more information. \ - */ \ - 1, /* unsigned unchecked_isa_dma:1 */ \ - /* \ - * All adapters controlled by this driver are capable of large \ - * scatter-gather lists. According to the mid-level SCSI documentation \ - * this obviates any performance gain provided by setting \ - * 'use_clustering'. But empirically while CPU utilization is increased \ - * by enabling clustering, I/O throughput increases as well. \ - */ \ - ENABLE_CLUSTERING, /* unsigned use_clustering:1 */ \ -} -#elif LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28) +#if ASC_LINUX_KERNEL24 #define ADVANSYS { \ - proc_dir: &proc_scsi_advansys, \ - proc_info: advansys_proc_info, \ - name: "advansys", \ - detect: advansys_detect, \ - release: advansys_release, \ - info: advansys_info, \ - command: advansys_command, \ - queuecommand: advansys_queuecommand, \ - abort: advansys_abort, \ - reset: advansys_reset, \ - bios_param: advansys_biosparam, \ + proc_name: "advansys", \ + proc_info: advansys_proc_info, \ + name: "advansys", \ + detect: advansys_detect, \ + release: advansys_release, \ + info: advansys_info, \ + queuecommand: advansys_queuecommand, \ + use_new_eh_code: 1, \ + eh_bus_reset_handler: advansys_reset, \ + bios_param: advansys_biosparam, \ /* \ * Because the driver may control an ISA adapter 'unchecked_isa_dma' \ * must be set. The flag will be cleared in advansys_detect for non-ISA \ * adapters. Refer to the comment in scsi_module.c for more information. \ */ \ - unchecked_isa_dma: 1, \ + unchecked_isa_dma: 1, \ /* \ * All adapters controlled by this driver are capable of large \ * scatter-gather lists. According to the mid-level SCSI documentation \ @@ -170,27 +93,25 @@ * 'use_clustering'. But empirically while CPU utilization is increased \ * by enabling clustering, I/O throughput increases as well. \ */ \ - use_clustering: ENABLE_CLUSTERING, \ + use_clustering: ENABLE_CLUSTERING, \ } -#else /* version >= v2.3.28 */ +#elif ASC_LINUX_KERNEL22 #define ADVANSYS { \ - proc_name: "advansys", \ - proc_info: advansys_proc_info, \ - name: "advansys", \ - detect: advansys_detect, \ - release: advansys_release, \ - info: advansys_info, \ - command: advansys_command, \ - queuecommand: advansys_queuecommand, \ - abort: advansys_abort, \ - reset: advansys_reset, \ - bios_param: advansys_biosparam, \ + proc_info: advansys_proc_info, \ + name: "advansys", \ + detect: advansys_detect, \ + release: advansys_release, \ + info: advansys_info, \ + queuecommand: advansys_queuecommand, \ + use_new_eh_code: 1, \ + eh_bus_reset_handler: advansys_reset, \ + bios_param: advansys_biosparam, \ /* \ * Because the driver may control an ISA adapter 'unchecked_isa_dma' \ * must be set. The flag will be cleared in advansys_detect for non-ISA \ * adapters. Refer to the comment in scsi_module.c for more information. \ */ \ - unchecked_isa_dma: 1, \ + unchecked_isa_dma: 1, \ /* \ * All adapters controlled by this driver are capable of large \ * scatter-gather lists. According to the mid-level SCSI documentation \ @@ -198,7 +119,7 @@ * 'use_clustering'. But empirically while CPU utilization is increased \ * by enabling clustering, I/O throughput increases as well. \ */ \ - use_clustering: ENABLE_CLUSTERING, \ + use_clustering: ENABLE_CLUSTERING, \ } -#endif /* version >= v2.3.28 */ +#endif #endif /* _ADVANSYS_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aha1542.c linux.ac/drivers/scsi/aha1542.c --- linux.vanilla/drivers/scsi/aha1542.c Tue Apr 3 17:32:18 2001 +++ linux.ac/drivers/scsi/aha1542.c Sun Apr 15 23:15:33 2001 @@ -254,7 +254,7 @@ /* Only used at boot time, so we do not need to worry about latency as much here */ -static int aha1542_in(unsigned int base, unchar * cmdp, int len) +static int __init aha1542_in(unsigned int base, unchar * cmdp, int len) { unsigned long flags; @@ -276,7 +276,7 @@ /* Similar to aha1542_in, except that we wait a very short period of time. We use this if we know the board is alive and awake, but we are not sure if the board will respond to the command we are about to send or not */ -static int aha1542_in1(unsigned int base, unchar * cmdp, int len) +static int __init aha1542_in1(unsigned int base, unchar * cmdp, int len) { unsigned long flags; @@ -886,7 +886,7 @@ /* This function should only be called for 1542C boards - we can detect the special firmware settings and unlock the board */ -static int aha1542_mbenable(int base) +static int __init aha1542_mbenable(int base) { static unchar mbenable_cmd[3]; static unchar mbenable_result[2]; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/Config.in linux.ac/drivers/scsi/aic7xxx/Config.in --- linux.vanilla/drivers/scsi/aic7xxx/Config.in Tue Apr 3 17:32:18 2001 +++ linux.ac/drivers/scsi/aic7xxx/Config.in Thu Apr 12 17:50:05 2001 @@ -2,6 +2,7 @@ dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then int ' Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 253 - int ' Initial bus reset delay in milli-seconds' CONFIG_AIC7XXX_RESET_DELAY 5000 + int ' Initial bus reset delay in milli-seconds' CONFIG_AIC7XXX_RESET_DELAY_MS 15000 + bool ' Build Adapter Firmware with Kernel Build' CONFIG_AIC7XXX_BUILD_FIRMWARE fi fi diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/Makefile linux.ac/drivers/scsi/aic7xxx/Makefile --- linux.vanilla/drivers/scsi/aic7xxx/Makefile Tue Apr 3 17:32:18 2001 +++ linux.ac/drivers/scsi/aic7xxx/Makefile Thu Apr 12 17:50:05 2001 @@ -4,7 +4,7 @@ # Makefile for the Linux aic7xxx SCSI driver. # -O_TARGET = aic7xxx_drv.o +O_TARGET := aic7xxx_drv.o list-multi := aic7xxx_mod.o @@ -25,8 +25,13 @@ aic7xxx_mod.o: aic7xxx_seq.h aic7xxx_reg.h $(AIC7XXX_OBJS) $(LD) $(LD_RFLAG) -r -o $@ $(AIC7XXX_OBJS) +ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y) aic7xxx_seq.h aic7xxx_reg.h: aic7xxx.seq aic7xxx.reg aicasm/aicasm aicasm/aicasm -I. -r aic7xxx_reg.h -o aic7xxx_seq.h aic7xxx.seq +else +aic7xxx_seq.h aic7xxx_reg.h: aic7xxx.seq aic7xxx.reg + echo "Warning, generated aic7xxx firmware files may be out of date!\n" +endif aicasm/aicasm: aicasm/*.[chyl] $(MAKE) -C aicasm diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7770.c linux.ac/drivers/scsi/aic7xxx/aic7770.c --- linux.vanilla/drivers/scsi/aic7xxx/aic7770.c Tue Apr 3 17:32:18 2001 +++ linux.ac/drivers/scsi/aic7xxx/aic7770.c Thu Apr 12 17:50:05 2001 @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7770.c#6 $ + * $Id: //depot/src/aic7xxx/aic7770.c#11 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7770.c,v 1.1 2000/09/16 20:02:27 gibbs Exp $ */ @@ -95,8 +95,6 @@ u_int hostconf; u_int irq; u_int intdef; - u_int hcntrl; - int shared; ahc_init_probe_config(&probe_config); error = entry->setup(ahc->dev_softc, &probe_config); @@ -107,15 +105,15 @@ if (error != 0) return (error); - /* Pause the card preseving the IRQ type */ - hcntrl = ahc_inb(ahc, HCNTRL) & IRQMS; - ahc_outb(ahc, HCNTRL, hcntrl | PAUSE); - while ((ahc_inb(ahc, HCNTRL) & PAUSE) == 0) - ; + probe_config.description = entry->name; + error = ahc_softc_init(ahc, &probe_config); + + error = ahc_reset(ahc); + if (error != 0) + return (error); /* Make sure we have a valid interrupt vector */ intdef = ahc_inb(ahc, INTDEF); - shared = (intdef & EDGE_TRIG) ? 0 : 1; irq = intdef & VECTOR; switch (irq) { case 9: @@ -130,16 +128,8 @@ return (ENXIO); } - probe_config.description = entry->name; - error = ahc_softc_init(ahc, &probe_config); - - error = aic7770_map_int(ahc, irq, shared); - if (error != 0) - return (error); - - error = ahc_reset(ahc); - if (error != 0) - return (error); + if ((intdef & EDGE_TRIG) != 0) + ahc->flags |= AHC_EDGE_INTERRUPT; switch (probe_config.chip & (AHC_EISA|AHC_VL)) { case AHC_EISA: @@ -154,7 +144,7 @@ /* Get the primary channel information */ if ((biosctrl & CHANNEL_B_PRIMARY) != 0) - ahc->flags |= AHC_CHANNEL_B_PRIMARY; + ahc->flags |= 1; if ((biosctrl & BIOSMODE) == BIOSDISABLED) { ahc->flags |= AHC_USEDEFAULTS; @@ -210,10 +200,19 @@ */ ahc_softc_insert(ahc); + error = aic7770_map_int(ahc, irq); + if (error != 0) + return (error); + /* * Enable the board's BUS drivers */ ahc_outb(ahc, BCTL, ENABLE); + + /* + * Allow interrupts. + */ + ahc_intr_enable(ahc, TRUE); return (0); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7770_linux.c linux.ac/drivers/scsi/aic7xxx/aic7770_linux.c --- linux.vanilla/drivers/scsi/aic7xxx/aic7770_linux.c Tue Apr 3 17:32:18 2001 +++ linux.ac/drivers/scsi/aic7xxx/aic7770_linux.c Thu Apr 12 17:50:46 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7770_linux.c#5 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7770_linux.c#7 $ */ #include "aic7xxx_osm.h" @@ -128,19 +128,18 @@ } int -aic7770_map_int(struct ahc_softc *ahc, u_int irq, int shared) +aic7770_map_int(struct ahc_softc *ahc, u_int irq) { int error; + int shared; - if (shared) + shared = 0; + if ((ahc->flags & AHC_EDGE_INTERRUPT) == 0) shared = SA_SHIRQ; ahc->platform_data->irq = irq; - error = request_irq(ahc->platform_data->irq, aic7xxx_isr, - SA_INTERRUPT|shared, "aic7xxx", ahc); - if (error < 0) - error = request_irq(ahc->platform_data->irq, aic7xxx_isr, - shared, "aic7xxx", ahc); + error = request_irq(ahc->platform_data->irq, ahc_linux_isr, + shared, "aic7xxx", ahc); return (-error); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx.c linux.ac/drivers/scsi/aic7xxx/aic7xxx.c --- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx.c Tue Apr 3 17:32:18 2001 +++ linux.ac/drivers/scsi/aic7xxx/aic7xxx.c Thu Apr 12 17:50:46 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx.c#32 $ + * $Id: //depot/src/aic7xxx/aic7xxx.c#38 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.c,v 1.61 2000/11/13 03:35:43 gibbs Exp $ */ @@ -58,9 +58,17 @@ "aic7892", "aic7899" }; -const u_int num_chip_names = NUM_ELEMENTS(ahc_chip_names); +static const u_int num_chip_names = NUM_ELEMENTS(ahc_chip_names); -struct hard_error_entry hard_error[] = { +/* + * Hardware error codes. + */ +struct ahc_hard_error_entry { + uint8_t errno; + char *errmesg; +}; + +static struct ahc_hard_error_entry ahc_hard_errors[] = { { ILLHADDR, "Illegal Host Access" }, { ILLSADDR, "Illegal Sequencer Address referrenced" }, { ILLOPCODE, "Illegal Opcode in sequencer program" }, @@ -70,9 +78,9 @@ { PCIERRSTAT, "PCI Error detected" }, { CIOPARERR, "CIOBUS Parity Error" }, }; -const u_int num_errors = NUM_ELEMENTS(hard_error); +static const u_int num_errors = NUM_ELEMENTS(ahc_hard_errors); -struct phase_table_entry phase_table[] = +static struct ahc_phase_table_entry ahc_phase_table[] = { { P_DATAOUT, MSG_NOOP, "in Data-out phase" }, { P_DATAIN, MSG_INITIATOR_DET_ERR, "in Data-in phase" }, @@ -90,14 +98,14 @@ * In most cases we only wish to itterate over real phases, so * exclude the last element from the count. */ -const u_int num_phases = NUM_ELEMENTS(phase_table) - 1; +static const u_int num_phases = NUM_ELEMENTS(ahc_phase_table) - 1; /* * Valid SCSIRATE values. (p. 3-17) * Provides a mapping of tranfer periods in ns to the proper value to * stick in the scsixfer reg. */ -struct ahc_syncrate ahc_syncrates[] = +static struct ahc_syncrate ahc_syncrates[] = { /* ultra2 fast/ultra period rate */ { 0x42, 0x000, 9, "80.0" }, @@ -121,7 +129,7 @@ #include "aic7xxx_seq.h" /**************************** Function Declarations ***************************/ -static struct tmode_tstate* +static struct ahc_tmode_tstate* ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel); #ifdef AHC_TARGET_MODE @@ -134,7 +142,7 @@ u_int *period, u_int *ppr_options, role_t role); -static void ahc_update_pending_syncrates(struct ahc_softc *ahc); +static void ahc_update_pending_scbs(struct ahc_softc *ahc); static void ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo); static void ahc_scb_devinfo(struct ahc_softc *ahc, @@ -174,6 +182,11 @@ struct ahc_devinfo *devinfo, cam_status status, char *message, int verbose_level); +#if AHC_TARGET_MODE +static void ahc_setup_target_msgin(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + struct scb *scb); +#endif static bus_dmamap_callback_t ahc_dmamap_cb; static void ahc_build_free_scb_list(struct ahc_softc *ahc); @@ -204,7 +217,7 @@ u_int instrptr, uint8_t *dconsts); #ifdef AHC_TARGET_MODE static void ahc_queue_lstate_event(struct ahc_softc *ahc, - struct tmode_lstate *lstate, + struct ahc_tmode_lstate *lstate, u_int initiator_id, u_int event_type, u_int event_arg); @@ -218,10 +231,10 @@ * Restart the sequencer program from address zero */ void -restart_sequencer(struct ahc_softc *ahc) +ahc_restart(struct ahc_softc *ahc) { - pause_sequencer(ahc); + ahc_pause(ahc); ahc_outb(ahc, SCSISIGO, 0); /* De-assert BSY */ ahc_outb(ahc, MSG_OUT, MSG_NOOP); /* No message to send */ @@ -259,7 +272,7 @@ ahc_outb(ahc, SEQCTL, FASTMODE); ahc_outb(ahc, SEQADDR0, 0); ahc_outb(ahc, SEQADDR1, 0); - unpause_sequencer(ahc); + ahc_unpause(ahc); } /************************* Input/Output Queues ********************************/ @@ -277,7 +290,7 @@ /* * Clear 32bits of QOUTFIFO at a time - * so that we don't clobber an incomming + * so that we don't clobber an incoming * byte DMA to the array on architectures * that only support 32bit load and store * operations. @@ -340,14 +353,14 @@ * We upset the sequencer :-( * Lookup the error message */ - int i, error, num_errors; + int i; + int error; error = ahc_inb(ahc, ERROR); - num_errors = sizeof(hard_error)/sizeof(hard_error[0]); for (i = 0; error != 1 && i < num_errors; i++) error >>= 1; printf("%s: brkadrint, %s at seqaddr = 0x%x\n", - ahc_name(ahc), hard_error[i].errmesg, + ahc_name(ahc), ahc_hard_errors[i].errmesg, ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); @@ -436,6 +449,12 @@ break; case SCSI_STATUS_CMD_TERMINATED: case SCSI_STATUS_CHECK_COND: + { + struct ahc_dma_seg *sg; + struct scsi_sense *sc; + struct ahc_initiator_tinfo *targ_info; + struct ahc_tmode_tstate *tstate; + struct ahc_transinfo *tinfo; #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOWSENSE) { ahc_print_path(ahc, scb); @@ -444,99 +463,97 @@ } #endif - if (ahc_perform_autosense(scb)) { - struct ahc_dma_seg *sg; - struct scsi_sense *sc; - struct ahc_initiator_tinfo *targ_info; - struct tmode_tstate *tstate; - struct ahc_transinfo *tinfo; + if (ahc_perform_autosense(scb) == 0) + break; - targ_info = - ahc_fetch_transinfo(ahc, + targ_info = ahc_fetch_transinfo(ahc, devinfo.channel, devinfo.our_scsiid, devinfo.target, &tstate); - tinfo = &targ_info->current; - sg = scb->sg_list; - sc = (struct scsi_sense *) - (&hscb->shared_data.cdb); - /* - * Save off the residual if there is one. - */ - if (ahc_check_residual(scb)) - ahc_calc_residual(scb); - else - ahc_set_residual(scb, 0); + tinfo = &targ_info->current; + sg = scb->sg_list; + sc = (struct scsi_sense *)(&hscb->shared_data.cdb); + /* + * Save off the residual if there is one. + */ + if (ahc_check_residual(scb)) + ahc_calc_residual(scb); + else + ahc_set_residual(scb, 0); #ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOWSENSE) { - ahc_print_path(ahc, scb); - printf("Sending Sense\n"); - } + if (ahc_debug & AHC_SHOWSENSE) { + ahc_print_path(ahc, scb); + printf("Sending Sense\n"); + } #endif - sg->addr = ahc_get_sense_bufaddr(ahc, scb); - sg->len = ahc_get_sense_bufsize(ahc, scb); - sg->len |= AHC_DMA_LAST_SEG; - - /* Fixup byte order */ - sg->addr = ahc_htole32(sg->addr); - sg->len = ahc_htole32(sg->len); - - sc->opcode = REQUEST_SENSE; - sc->byte2 = 0; - if (tinfo->protocol_version <= SCSI_REV_2 - && SCB_GET_LUN(scb) < 8) - sc->byte2 = SCB_GET_LUN(scb) << 5; - sc->unused[0] = 0; - sc->unused[1] = 0; - sc->length = sg->len; - sc->control = 0; + sg->addr = ahc_get_sense_bufaddr(ahc, scb); + sg->len = ahc_get_sense_bufsize(ahc, scb); + sg->len |= AHC_DMA_LAST_SEG; + + /* Fixup byte order */ + sg->addr = ahc_htole32(sg->addr); + sg->len = ahc_htole32(sg->len); + + sc->opcode = REQUEST_SENSE; + sc->byte2 = 0; + if (tinfo->protocol_version <= SCSI_REV_2 + && SCB_GET_LUN(scb) < 8) + sc->byte2 = SCB_GET_LUN(scb) << 5; + sc->unused[0] = 0; + sc->unused[1] = 0; + sc->length = sg->len; + sc->control = 0; - /* - * XXX Still true??? - * Would be nice to preserve DISCENB here, - * but due to the way we manage busy targets, - * we can't. - */ - hscb->control = 0; + /* + * We can't allow the target to disconnect. + * This will be an untagged transaction and + * having the target disconnect will make this + * transaction indestinguishable from outstanding + * tagged transactions. + */ + hscb->control = 0; - /* - * This request sense could be because the - * the device lost power or in some other - * way has lost our transfer negotiations. - * Renegotiate if appropriate. Unit attention - * errors will be reported before any data - * phases occur. - */ - if (ahc_get_residual(scb) - == ahc_get_transfer_length(scb)) { - ahc_update_target_msg_request(ahc, - &devinfo, - targ_info, - /*force*/TRUE, - /*paused*/TRUE); - } - hscb->cdb_len = sizeof(*sc); - hscb->dataptr = sg->addr; - hscb->datacnt = sg->len; - hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID; - hscb->sgptr = ahc_htole32(hscb->sgptr); - scb->sg_count = 1; - scb->flags |= SCB_SENSE; - ahc_qinfifo_requeue_tail(ahc, scb); - ahc_outb(ahc, RETURN_1, SEND_SENSE); + /* + * This request sense could be because the + * the device lost power or in some other + * way has lost our transfer negotiations. + * Renegotiate if appropriate. Unit attention + * errors will be reported before any data + * phases occur. + */ + if (ahc_get_residual(scb) + == ahc_get_transfer_length(scb)) { + ahc_update_neg_request(ahc, &devinfo, + tstate, targ_info, + /*force*/TRUE); + } + if (tstate->auto_negotiate & devinfo.target_mask) { + hscb->control |= MK_MESSAGE; + scb->flags &= ~SCB_NEGOTIATE; + scb->flags |= SCB_AUTO_NEGOTIATE; + } + hscb->cdb_len = sizeof(*sc); + hscb->dataptr = sg->addr; + hscb->datacnt = sg->len; + hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID; + hscb->sgptr = ahc_htole32(hscb->sgptr); + scb->sg_count = 1; + scb->flags |= SCB_SENSE; + ahc_qinfifo_requeue_tail(ahc, scb); + ahc_outb(ahc, RETURN_1, SEND_SENSE); #ifdef __FreeBSD__ - /* - * Ensure we have enough time to actually - * retrieve the sense. - */ - untimeout(ahc_timeout, (caddr_t)scb, - scb->io_ctx->ccb_h.timeout_ch); - scb->io_ctx->ccb_h.timeout_ch = - timeout(ahc_timeout, (caddr_t)scb, 5 * hz); + /* + * Ensure we have enough time to actually + * retrieve the sense. + */ + untimeout(ahc_timeout, (caddr_t)scb, + scb->io_ctx->ccb_h.timeout_ch); + scb->io_ctx->ccb_h.timeout_ch = + timeout(ahc_timeout, (caddr_t)scb, 5 * hz); #endif - } break; + } default: break; } @@ -633,7 +650,7 @@ "Lastphase = 0x%x, Curphase = 0x%x\n", ahc_name(ahc), devinfo.channel, devinfo.target, lastphase, ahc_inb(ahc, SCSISIGI)); - restart_sequencer(ahc); + ahc_restart(ahc); return; } case HOST_MSG_LOOP: @@ -650,6 +667,8 @@ * loop. */ if (ahc->msg_type == MSG_TYPE_NONE) { + struct scb *scb; + u_int scb_index; u_int bus_phase; bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; @@ -663,17 +682,13 @@ * we got here. Just punt the message. */ ahc_clear_intstat(ahc); - restart_sequencer(ahc); + ahc_restart(ahc); return; } + scb_index = ahc_inb(ahc, SCB_TAG); + scb = ahc_lookup_scb(ahc, scb_index); if (devinfo.role == ROLE_INITIATOR) { - struct scb *scb; - u_int scb_index; - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc_lookup_scb(ahc, scb_index); - if (scb == NULL) panic("HOST_MSG_LOOP with " "invalid SCB %x\n", scb_index); @@ -695,7 +710,9 @@ } #if AHC_TARGET_MODE else - ahc_setup_target_msgin(ahc, &devinfo); + ahc_setup_target_msgin(ahc, + &devinfo, + scb); #endif } } @@ -749,13 +766,13 @@ scb = ahc_lookup_scb(ahc, scbindex); for (i = 0; i < num_phases; i++) { - if (lastphase == phase_table[i].phase) + if (lastphase == ahc_phase_table[i].phase) break; } ahc_print_path(ahc, scb); printf("data overrun detected %s." " Tag == 0x%x.\n", - phase_table[i].phasemsg, + ahc_phase_table[i].phasemsg, scb->hscb->tag); ahc_print_path(ahc, scb); printf("%s seen Data Phase. Length = %ld. NumSGs = %d.\n", @@ -858,7 +875,7 @@ * a SEQINT, so we should restart it when * we're done. */ - unpause_sequencer(ahc); + ahc_unpause(ahc); } void @@ -897,7 +914,7 @@ if (status == 0) { printf("%s: Spurious SCSI interrupt\n", ahc_name(ahc)); ahc_outb(ahc, CLRINT, CLRSCSIINT); - unpause_sequencer(ahc); + ahc_unpause(ahc); return; } } @@ -975,10 +992,10 @@ errorphase = lastphase; for (i = 0; i < num_phases; i++) { - if (errorphase == phase_table[i].phase) + if (errorphase == ahc_phase_table[i].phase) break; } - mesg_out = phase_table[i].mesg_out; + mesg_out = ahc_phase_table[i].mesg_out; if (scb != NULL) ahc_print_path(ahc, scb); else @@ -987,7 +1004,7 @@ scsirate = ahc_inb(ahc, SCSIRATE); printf("parity error detected %s. " "SEQADDR(0x%x) SCSIRATE(0x%x)\n", - phase_table[i].phasemsg, + ahc_phase_table[i].phasemsg, ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8), scsirate); @@ -1018,7 +1035,7 @@ ahc_outb(ahc, MSG_OUT, mesg_out); } ahc_outb(ahc, CLRINT, CLRSCSIINT); - unpause_sequencer(ahc); + ahc_unpause(ahc); } else if ((status & BUSFREE) != 0 && (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) { u_int lastphase; @@ -1113,7 +1130,7 @@ } else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_PPR, FALSE)) { struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; /* * PPR Rejected. Try non-ppr negotiation @@ -1174,17 +1191,18 @@ printf("%s: ", ahc_name(ahc)); } for (i = 0; i < num_phases; i++) { - if (lastphase == phase_table[i].phase) + if (lastphase == ahc_phase_table[i].phase) break; } printf("Unexpected busfree %s\n" "SEQADDR == 0x%x\n", - phase_table[i].phasemsg, ahc_inb(ahc, SEQADDR0) + ahc_phase_table[i].phasemsg, + ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); } ahc_clear_msg_state(ahc); ahc_outb(ahc, CLRINT, CLRSCSIINT); - restart_sequencer(ahc); + ahc_restart(ahc); } else if ((status & SELTO) != 0) { u_int scbptr; @@ -1200,7 +1218,7 @@ /* * Although the driver does not care about the * 'Selection in Progress' status bit, the busy - * LED does. SELINGO is only cleared by a sucessful + * LED does. SELINGO is only cleared by a successful * selection, so we must manually clear it to insure * the LED turns off just incase no future successful * selections occur (e.g. no devices on the bus). @@ -1221,7 +1239,7 @@ ahc_freeze_devq(ahc, scb); } ahc_outb(ahc, CLRINT, CLRSCSIINT); - restart_sequencer(ahc); + ahc_restart(ahc); } else { printf("%s: Missing case in ahc_handle_scsiint. status = %x\n", ahc_name(ahc), status); @@ -1290,7 +1308,7 @@ ahc_outb(ahc, HCNTRL, ahc->unpause); do { ahc_delay(200); - } while (!sequencer_paused(ahc)); + } while (!ahc_is_paused(ahc)); } if (stepping) { ahc_outb(ahc, SIMODE0, simode0); @@ -1363,11 +1381,11 @@ * Allocate per target mode instance (ID we respond to as a target) * transfer negotiation data structures. */ -static struct tmode_tstate * +static struct ahc_tmode_tstate * ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel) { - struct tmode_tstate *master_tstate; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *master_tstate; + struct ahc_tmode_tstate *tstate; int i; master_tstate = ahc->enabled_targets[ahc->our_id]; @@ -1413,11 +1431,13 @@ static void ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force) { - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; - /* Don't clean up the entry for our initiator role */ - if ((ahc->flags & AHC_INITIATORROLE) != 0 - && ((channel == 'B' && scsi_id == ahc->our_id_b) + /* + * Don't clean up our "master" tstate. + * It has our default user settings. + */ + if (((channel == 'B' && scsi_id == ahc->our_id_b) || (channel == 'A' && scsi_id == ahc->our_id)) && force == FALSE) return; @@ -1647,15 +1667,14 @@ * means the next time we send the initial identify messages for * a new transaction. */ -void -ahc_update_target_msg_request(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - struct ahc_initiator_tinfo *tinfo, - int force, int paused) +int +ahc_update_neg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + struct ahc_tmode_tstate *tstate, + struct ahc_initiator_tinfo *tinfo, int force) { - u_int targ_msg_req_orig; + u_int auto_negotiate_orig; - targ_msg_req_orig = ahc->targ_msg_req; + auto_negotiate_orig = tstate->auto_negotiate; if (tinfo->current.period != tinfo->goal.period || tinfo->current.width != tinfo->goal.width || tinfo->current.offset != tinfo->goal.offset @@ -1664,23 +1683,11 @@ && (tinfo->goal.period != 0 || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT || tinfo->goal.ppr_options != 0))) - ahc->targ_msg_req |= devinfo->target_mask; + tstate->auto_negotiate |= devinfo->target_mask; else - ahc->targ_msg_req &= ~devinfo->target_mask; - - if (ahc->targ_msg_req != targ_msg_req_orig) { - /* Update the message request bit for this target */ - if (!paused) - pause_sequencer(ahc); - - ahc_outb(ahc, TARGET_MSG_REQUEST, - ahc->targ_msg_req & 0xFF); - ahc_outb(ahc, TARGET_MSG_REQUEST + 1, - (ahc->targ_msg_req >> 8) & 0xFF); + tstate->auto_negotiate &= ~devinfo->target_mask; - if (!paused) - unpause_sequencer(ahc); - } + return (auto_negotiate_orig != tstate->auto_negotiate); } /* @@ -1697,11 +1704,15 @@ u_int offset, u_int ppr_options, u_int type, int paused) { struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; u_int old_period; u_int old_offset; u_int old_ppr; - int active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; + int active; + int update_needed; + + active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; + update_needed = 0; if (syncrate == NULL) { period = 0; @@ -1733,6 +1744,7 @@ || old_ppr != ppr_options)) { u_int scsirate; + update_needed++; scsirate = tinfo->scsirate; if ((ahc->features & AHC_ULTRA2) != 0) { @@ -1781,11 +1793,8 @@ tinfo->current.offset = offset; tinfo->current.ppr_options = ppr_options; - /* Update the syncrates in any pending scbs */ - ahc_update_pending_syncrates(ahc); - ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG); + CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); if (bootverbose) { if (offset != 0) { printf("%s: target %d synchronous at %sMHz%s, " @@ -1801,9 +1810,11 @@ } } - ahc_update_target_msg_request(ahc, devinfo, tinfo, - /*force*/FALSE, - paused); + update_needed += ahc_update_neg_request(ahc, devinfo, tstate, + tinfo, /*force*/FALSE); + + if (update_needed) + ahc_update_pending_scbs(ahc); } /* @@ -1818,11 +1829,14 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, u_int width, u_int type, int paused) { - struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; - u_int oldwidth; - int active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; + struct ahc_initiator_tinfo *tinfo; + struct ahc_tmode_tstate *tstate; + u_int oldwidth; + int active; + int update_needed; + active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; + update_needed = 0; tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, devinfo->target, &tstate); @@ -1836,6 +1850,7 @@ if ((type & AHC_TRANS_CUR) != 0 && oldwidth != width) { u_int scsirate; + update_needed++; scsirate = tinfo->scsirate; scsirate &= ~WIDEXFER; if (width == MSG_EXT_WDTR_BUS_16_BIT) @@ -1849,7 +1864,7 @@ tinfo->current.width = width; ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG); + CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); if (bootverbose) { printf("%s: target %d using %dbit transfers\n", ahc_name(ahc), devinfo->target, @@ -1857,35 +1872,22 @@ } } - ahc_update_target_msg_request(ahc, devinfo, tinfo, - /*force*/FALSE, paused); + update_needed += ahc_update_neg_request(ahc, devinfo, tstate, + tinfo, /*force*/FALSE); + if (update_needed) + ahc_update_pending_scbs(ahc); } /* * Update the current state of tagged queuing for a given target. */ void -ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, int enable) +ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + ahc_queue_alg alg) { - struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; - uint16_t orig_tagenable; - - tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, - devinfo->target, &tstate); - - orig_tagenable = tstate->tagenable; - if (enable) - tstate->tagenable |= devinfo->target_mask; - else - tstate->tagenable &= ~devinfo->target_mask; - - if (orig_tagenable != tstate->tagenable) { - ahc_platform_set_tags(ahc, devinfo, enable); - ahc_send_async(ahc, devinfo->channel, devinfo->target, - devinfo->lun, AC_TRANSFER_NEG); - } - + ahc_platform_set_tags(ahc, devinfo, alg); + ahc_send_async(ahc, devinfo->channel, devinfo->target, + devinfo->lun, AC_TRANSFER_NEG, &alg); } /* @@ -1894,11 +1896,12 @@ * be set correctly during future (re)selections. */ static void -ahc_update_pending_syncrates(struct ahc_softc *ahc) +ahc_update_pending_scbs(struct ahc_softc *ahc) { struct scb *pending_scb; int pending_scb_count; int i; + int paused; u_int saved_scbptr; /* @@ -1910,7 +1913,7 @@ struct ahc_devinfo devinfo; struct hardware_scb *pending_hscb; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; ahc_scb_devinfo(ahc, &devinfo, pending_scb); tinfo = ahc_fetch_transinfo(ahc, devinfo.channel, @@ -1922,12 +1925,24 @@ pending_hscb->control |= ULTRAENB; pending_hscb->scsirate = tinfo->scsirate; pending_hscb->scsioffset = tinfo->current.offset; + if ((tstate->auto_negotiate & devinfo.target_mask) == 0 + && (pending_scb->flags & SCB_AUTO_NEGOTIATE) != 0) { + pending_scb->flags &= ~SCB_AUTO_NEGOTIATE; + pending_hscb->control &= ~MK_MESSAGE; + } pending_scb_count++; } if (pending_scb_count == 0) return; + if (ahc_is_paused(ahc)) { + paused = 1; + } else { + paused = 0; + ahc_pause(ahc); + } + saved_scbptr = ahc_inb(ahc, SCBPTR); /* Ensure that the hscbs down on the card match the new information */ for (i = 0; i < ahc->scb_data->maxhscbs; i++) { @@ -1943,14 +1958,16 @@ pending_hscb = pending_scb->hscb; control = ahc_inb(ahc, SCB_CONTROL); - control &= ~ULTRAENB; - if ((pending_hscb->control & ULTRAENB) != 0) - control |= ULTRAENB; + control &= ~(ULTRAENB|MK_MESSAGE); + control |= pending_hscb->control & (ULTRAENB|MK_MESSAGE); ahc_outb(ahc, SCB_CONTROL, control); ahc_outb(ahc, SCB_SCSIRATE, pending_hscb->scsirate); ahc_outb(ahc, SCB_SCSIOFFSET, pending_hscb->scsioffset); } ahc_outb(ahc, SCBPTR, saved_scbptr); + + if (paused == 0) + ahc_unpause(ahc); } /**************************** Pathing Information *****************************/ @@ -1985,6 +2002,24 @@ role); } +struct ahc_phase_table_entry* +ahc_lookup_phase_entry(int phase) +{ + struct ahc_phase_table_entry *entry; + struct ahc_phase_table_entry *last_entry; + + /* + * num_phases doesn't include the default entry which + * will be returned if the phase doesn't match. + */ + last_entry = &ahc_phase_table[num_phases]; + for (entry = ahc_phase_table; entry < last_entry; entry++) { + if (phase == entry->phase) + break; + } + return (entry); +} + void ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target, u_int lun, char channel, role_t role) @@ -2083,8 +2118,7 @@ * away. */ ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO)); - } else if ((ahc->targ_msg_req & devinfo->target_mask) != 0 - || (scb->flags & SCB_NEGOTIATE) != 0) { + } else if ((scb->flags & (SCB_AUTO_NEGOTIATE|SCB_NEGOTIATE)) != 0) { ahc_build_transfer_msg(ahc, devinfo); } else { printf("ahc_intr: AWAITING_MSG for an SCB that " @@ -2101,6 +2135,7 @@ * asked to send this message again. */ ahc_outb(ahc, SCB_CONTROL, ahc_inb(ahc, SCB_CONTROL) & ~MK_MESSAGE); + scb->hscb->control &= ~MK_MESSAGE; ahc->msgout_index = 0; ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; } @@ -2118,7 +2153,7 @@ * we want to renegotiate due to a check condition. */ struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; struct ahc_syncrate *rate; int dowide; int dosync; @@ -2130,9 +2165,19 @@ tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, devinfo->target, &tstate); + /* + * Filter our period based on the current connection. + * If we can't perform DT transfers on this segment (not in LVD + * mode for instance), then our decision to issue a PPR message + * may change. + */ + period = tinfo->goal.period; + ppr_options = tinfo->goal.ppr_options; + rate = ahc_devlimited_syncrate(ahc, tinfo, &period, + &ppr_options, devinfo->role); dowide = tinfo->current.width != tinfo->goal.width; - dosync = tinfo->current.period != tinfo->goal.period; - doppr = tinfo->current.ppr_options != tinfo->goal.ppr_options; + dosync = tinfo->current.period != period; + doppr = tinfo->current.ppr_options != ppr_options; if (!dowide && !dosync && !doppr) { dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT; @@ -2160,12 +2205,6 @@ */ if (use_ppr || (dosync && !dowide)) { - period = tinfo->goal.period; - ppr_options = tinfo->goal.ppr_options; - if (use_ppr == 0) - ppr_options = 0; - rate = ahc_devlimited_syncrate(ahc, tinfo, &period, - &ppr_options, devinfo->role); offset = tinfo->goal.offset; ahc_validate_offset(ahc, tinfo, rate, &offset, use_ppr ? tinfo->goal.width @@ -2258,7 +2297,7 @@ ahc->msgout_len = 0; ahc->msgin_index = 0; ahc->msg_type = MSG_TYPE_NONE; - if ((ahc_inb(ahc, SCSISIGI) & ATNI) == 0) { + if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0) { /* * The target didn't care to respond to our * message request, so clear ATN. @@ -2548,7 +2587,7 @@ found = TRUE; } index = end_index; - } else if (ahc->msgout_buf[index] >= MSG_SIMPLE_Q_TAG + } else if (ahc->msgout_buf[index] >= MSG_SIMPLE_TASK && ahc->msgout_buf[index] <= MSG_IGN_WIDE_RESIDUE) { /* Skip tag type and tag id or residue param*/ @@ -2569,13 +2608,13 @@ } /* - * Wait for a complete incomming message, parse it, and respond accordingly. + * Wait for a complete incoming message, parse it, and respond accordingly. */ static int ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) { struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; int reject; int done; int response; @@ -2674,7 +2713,8 @@ /* * Send our own SDTR in reply */ - if (bootverbose) { + if (bootverbose + && devinfo->role == ROLE_INITIATOR) { printf("(%s:%c:%d:%d): Target " "Initiated SDTR\n", ahc_name(ahc), devinfo->channel, @@ -2744,7 +2784,8 @@ /* * Send our own WDTR in reply */ - if (bootverbose) { + if (bootverbose + && devinfo->role == ROLE_INITIATOR) { printf("(%s:%c:%d:%d): Target " "Initiated WDTR\n", ahc_name(ahc), devinfo->channel, @@ -2879,7 +2920,7 @@ "offset %x, options %x\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun, - ahc->msgin_buf[3], saved_width, + saved_width, ahc->msgin_buf[3], saved_offset, saved_ppr_options, bus_width, period, offset, ppr_options); } @@ -2906,7 +2947,7 @@ CAM_BDR_SENT, "Bus Device Reset Received", /*verbose_level*/0); - restart_sequencer(ahc); + ahc_restart(ahc); done = MSGLOOP_TERMINATED; break; case MSG_ABORT_TAG: @@ -2927,7 +2968,7 @@ tstate = ahc->enabled_targets[devinfo->our_scsiid]; if (tstate != NULL) { - struct tmode_lstate* lstate; + struct ahc_tmode_lstate* lstate; lstate = tstate->enabled_luns[devinfo->lun]; if (lstate != NULL) { @@ -2979,7 +3020,7 @@ */ struct scb *scb; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; u_int scb_index; u_int last_msg; int response = 0; @@ -3046,22 +3087,37 @@ "Using asynchronous transfers\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun); - } else if ((scb->hscb->control & MSG_SIMPLE_Q_TAG) != 0) { - - printf("(%s:%c:%d:%d): refuses tagged commands. Performing " - "non-tagged I/O\n", ahc_name(ahc), - devinfo->channel, devinfo->target, devinfo->lun); - ahc_set_tags(ahc, devinfo, FALSE); + } else if ((scb->hscb->control & MSG_SIMPLE_TASK) != 0) { + int tag_type; + int mask; + + tag_type = (scb->hscb->control & MSG_SIMPLE_TASK); + + if (tag_type == MSG_SIMPLE_TASK) { + printf("(%s:%c:%d:%d): refuses tagged commands. " + "Performing non-tagged I/O\n", ahc_name(ahc), + devinfo->channel, devinfo->target, devinfo->lun); + ahc_set_tags(ahc, devinfo, AHC_QUEUE_NONE); + mask = ~0x23; + } else { + printf("(%s:%c:%d:%d): refuses %s tagged commands. " + "Performing simple queue tagged I/O only\n", + ahc_name(ahc), devinfo->channel, devinfo->target, + devinfo->lun, tag_type == MSG_ORDERED_TASK + ? "ordered" : "head of queue"); + ahc_set_tags(ahc, devinfo, AHC_QUEUE_BASIC); + mask = ~0x03; + } /* * Resend the identify for this CCB as the target * may believe that the selection is invalid otherwise. */ ahc_outb(ahc, SCB_CONTROL, - ahc_inb(ahc, SCB_CONTROL) & ~MSG_SIMPLE_Q_TAG); - scb->hscb->control &= ~MSG_SIMPLE_Q_TAG; + ahc_inb(ahc, SCB_CONTROL) & mask); + scb->hscb->control &= mask; ahc_set_transaction_tag(scb, /*enabled*/FALSE, - /*type*/MSG_SIMPLE_Q_TAG); + /*type*/MSG_SIMPLE_TASK); ahc_outb(ahc, MSG_OUT, MSG_IDENTIFYFLAG); ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO); @@ -3225,7 +3281,7 @@ cam_status status, char *message, int verbose_level) { #ifdef AHC_TARGET_MODE - struct tmode_tstate* tstate; + struct ahc_tmode_tstate* tstate; u_int lun; #endif int found; @@ -3242,7 +3298,7 @@ tstate = ahc->enabled_targets[devinfo->our_scsiid]; if (tstate != NULL) { for (lun = 0; lun < AHC_NUM_LUNS; lun++) { - struct tmode_lstate* lstate; + struct ahc_tmode_lstate* lstate; lstate = tstate->enabled_luns[lun]; if (lstate == NULL) @@ -3265,7 +3321,7 @@ AHC_TRANS_CUR, /*paused*/TRUE); ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_SENT_BDR); + CAM_LUN_WILDCARD, AC_SENT_BDR, NULL); if (message != NULL && (verbose_level <= bootverbose)) @@ -3274,9 +3330,11 @@ } #ifdef AHC_TARGET_MODE -void -ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) +static void +ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + struct scb *scb) { + /* * To facilitate adding multiple messages together, * each routine should increment the index and len @@ -3285,7 +3343,7 @@ ahc->msgout_index = 0; ahc->msgout_len = 0; - if ((ahc->targ_msg_req & devinfo->target_mask) != 0) + if (scb != NULL && (scb->flags & SCB_AUTO_NEGOTIATE) != 0) ahc_build_transfer_msg(ahc, devinfo); else panic("ahc_intr: AWAITING target message with no message"); @@ -3319,6 +3377,7 @@ LIST_INIT(&ahc->pending_scbs); /* We don't know our unit number until the OSM sets it */ ahc->name = name; + ahc->unit = -1; for (i = 0; i < 16; i++) TAILQ_INIT(&ahc->untagged_queues[i]); if (ahc_platform_alloc(ahc, platform_arg) != 0) { @@ -3337,7 +3396,7 @@ ahc->bugs = config->bugs; ahc->flags = config->flags; ahc->channel = config->channel; - ahc->unpause = (ahc_inb(ahc, HCNTRL) & IRQMS) | INTEN; + ahc->unpause = (ahc_inb(ahc, HCNTRL) & IRQMS); ahc->description = config->description; /* The IRQMS bit is only valid on VL and EISA chips */ if ((ahc->chip & AHC_PCI) != 0) @@ -3360,29 +3419,37 @@ { struct ahc_softc *list_ahc; -#ifdef AHC_SUPPORT_PCI +#if AHC_PCI_CONFIG > 0 /* * Second Function PCI devices need to inherit some - * settings from function 0. We assume that function 0 - * will always be found prior to function 1. + * settings from function 0. */ if ((ahc->chip & AHC_BUS_MASK) == AHC_PCI - && ahc_get_pci_function(ahc->dev_softc) == 1) { + && (ahc->features & AHC_MULTI_FUNC) != 0) { TAILQ_FOREACH(list_ahc, &ahc_tailq, links) { ahc_dev_softc_t list_pci; ahc_dev_softc_t pci; list_pci = list_ahc->dev_softc; pci = ahc->dev_softc; - if (ahc_get_pci_bus(list_pci) == ahc_get_pci_bus(pci) - && ahc_get_pci_slot(list_pci) == ahc_get_pci_slot(pci) - && ahc_get_pci_function(list_pci) == 0) { - ahc->flags &= ~AHC_BIOS_ENABLED; - ahc->flags |= - list_ahc->flags & AHC_BIOS_ENABLED; - ahc->flags &= ~AHC_CHANNEL_B_PRIMARY; - ahc->flags |= - list_ahc->flags & AHC_CHANNEL_B_PRIMARY; + if (ahc_get_pci_slot(list_pci) == ahc_get_pci_slot(pci) + && ahc_get_pci_bus(list_pci) == ahc_get_pci_bus(pci)) { + struct ahc_softc *master; + struct ahc_softc *slave; + + if (ahc_get_pci_function(list_pci) == 0) { + master = list_ahc; + slave = ahc; + } else { + master = ahc; + slave = list_ahc; + } + slave->flags &= ~AHC_BIOS_ENABLED; + slave->flags |= + master->flags & AHC_BIOS_ENABLED; + slave->flags &= ~AHC_PRIMARY_CHANNEL; + slave->flags |= + master->flags & AHC_PRIMARY_CHANNEL; break; } } @@ -3455,7 +3522,7 @@ #endif ahc_platform_free(ahc); for (i = 0; i < AHC_NUM_TARGETS; i++) { - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; tstate = ahc->enabled_targets[i]; if (tstate != NULL) { @@ -3463,7 +3530,7 @@ int j; for (j = 0; j < AHC_NUM_LUNS; j++) { - struct tmode_lstate *lstate; + struct ahc_tmode_lstate *lstate; lstate = tstate->enabled_luns[j]; if (lstate != NULL) { @@ -3523,7 +3590,7 @@ * It contains settings that affect termination and we don't want * to disturb the integrity of the bus. */ - pause_sequencer(ahc); + ahc_pause(ahc); sxfrctl1_b = 0; if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7770) { u_int sblkctl; @@ -3811,7 +3878,7 @@ ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag); /* - * Note that we were successfull + * Note that we were successful */ return (0); @@ -3961,7 +4028,7 @@ len = sprintf(buf, "Twin Channel, A SCSI Id=%d, " "B SCSI Id=%d, primary %c, ", ahc->our_id, ahc->our_id_b, - ahc->flags & AHC_CHANNEL_B_PRIMARY ? 'B': 'A'); + (ahc->flags & AHC_PRIMARY_CHANNEL) + 'A'); else { const char *type; @@ -4124,16 +4191,16 @@ * data for any target mode initiator. */ if (ahc_alloc_tstate(ahc, ahc->our_id, 'A') == NULL) { - printf("%s: unable to allocate tmode_tstate. " + printf("%s: unable to allocate ahc_tmode_tstate. " "Failing attach\n", ahc_name(ahc)); - return (-1); + return (ENOMEM); } if ((ahc->features & AHC_TWIN) != 0) { if (ahc_alloc_tstate(ahc, ahc->our_id_b, 'B') == NULL) { - printf("%s: unable to allocate tmode_tstate. " + printf("%s: unable to allocate ahc_tmode_tstate. " "Failing attach\n", ahc_name(ahc)); - return (-1); + return (ENOMEM); } } @@ -4231,7 +4298,7 @@ for (i = 0; i <= max_targ; i++) { struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; u_int our_id; u_int target_id; char channel; @@ -4328,8 +4395,6 @@ tinfo->current.transport_version = 2; } tstate->ultraenb = ultraenb; - tstate->discenable = discenable; - tstate->tagenable = 0; /* Wait until the XPT says its okay */ } ahc->user_discenable = discenable; ahc->user_tagenable = tagenable; @@ -4395,10 +4460,6 @@ ahc_outb(ahc, QINPOS, 0); ahc_outb(ahc, QOUTPOS, 0); - /* Don't have any special messages to send to targets */ - ahc_outb(ahc, TARGET_MSG_REQUEST, 0); - ahc_outb(ahc, TARGET_MSG_REQUEST + 1, 0); - /* * Use the built in queue management registers * if they are available. @@ -4450,16 +4511,33 @@ * never settle, so don't complain if we * fail here. */ - pause_sequencer(ahc); + ahc_pause(ahc); for (wait = 5000; (ahc_inb(ahc, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait; wait--) ahc_delay(100); - unpause_sequencer(ahc); + ahc_unpause(ahc); } return (0); } +void +ahc_intr_enable(struct ahc_softc *ahc, int enable) +{ + u_int hcntrl; + + hcntrl = ahc_inb(ahc, HCNTRL); + hcntrl &= ~INTEN; + ahc->pause &= ~INTEN; + ahc->unpause &= ~INTEN; + if (enable) { + hcntrl |= INTEN; + ahc->pause |= INTEN; + ahc->unpause |= INTEN; + } + ahc_outb(ahc, HCNTRL, hcntrl); +} + /* * Ensure that the card is paused in a location * outside of all critical sections and that all @@ -4478,7 +4556,7 @@ intstat = 0; do { ahc_intr(ahc); - pause_sequencer(ahc); + ahc_pause(ahc); ahc_clear_critical_section(ahc); if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) break; @@ -5348,7 +5426,7 @@ * Go through the pending CCB list and look for * commands for this target that are still active. * These are other tagged commands that were - * disconnected when the reset occured. + * disconnected when the reset occurred. */ scbp_next = LIST_FIRST(&ahc->pending_scbs); while (scbp_next != NULL) { @@ -5409,7 +5487,7 @@ CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD, channel, ROLE_UNKNOWN); - pause_sequencer(ahc); + ahc_pause(ahc); /* Make sure the sequencer is in a safe location. */ ahc_clear_critical_section(ahc); @@ -5478,14 +5556,14 @@ * drivers affected by this action. */ for (target = 0; target <= max_scsiid; target++) { - struct tmode_tstate* tstate; + struct ahc_tmode_tstate* tstate; u_int lun; tstate = ahc->enabled_targets[target]; if (tstate == NULL) continue; for (lun = 0; lun < AHC_NUM_LUNS; lun++) { - struct tmode_lstate* lstate; + struct ahc_tmode_lstate* lstate; lstate = tstate->enabled_luns[lun]; if (lstate == NULL) @@ -5499,7 +5577,7 @@ #endif /* Notify the XPT that a bus reset occurred */ ahc_send_async(ahc, devinfo.channel, CAM_TARGET_WILDCARD, - CAM_LUN_WILDCARD, AC_BUS_RESET); + CAM_LUN_WILDCARD, AC_BUS_RESET, NULL); /* * Revert to async/narrow transfers until we renegotiate. @@ -5524,9 +5602,9 @@ } if (restart_needed) - restart_sequencer(ahc); + ahc_restart(ahc); else - unpause_sequencer(ahc); + ahc_unpause(ahc); return found; } @@ -5623,7 +5701,7 @@ * Add a target mode event to this lun's queue */ static void -ahc_queue_lstate_event(struct ahc_softc *ahc, struct tmode_lstate *lstate, +ahc_queue_lstate_event(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate, u_int initiator_id, u_int event_type, u_int event_arg) { struct ahc_tmode_event *event; @@ -5674,7 +5752,7 @@ * for immediate notify resources. */ void -ahc_send_lstate_events(struct ahc_softc *ahc, struct tmode_lstate *lstate) +ahc_send_lstate_events(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate) { struct ccb_hdr *ccbh; struct ccb_immed_notify *inot; @@ -5825,7 +5903,7 @@ memcpy(ahc->critical_sections, cs_table, cs_count); } ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE); - restart_sequencer(ahc); + ahc_restart(ahc); if (bootverbose) printf(" %d instructions downloaded\n", downloaded); @@ -6000,6 +6078,7 @@ int target; int maxtarget; int i; + uint8_t last_phase; uint8_t qinpos; uint8_t qintail; uint8_t qoutpos; @@ -6008,13 +6087,25 @@ saved_scbptr = ahc_inb(ahc, SCBPTR); - printf("%s: Dumping Card State at SEQADDR 0x%x\n", - ahc_name(ahc), + last_phase = ahc_inb(ahc, LASTPHASE); + printf("%s: Dumping Card State %s, at SEQADDR 0x%x\n", + ahc_name(ahc), ahc_lookup_phase_entry(last_phase)->phasemsg, ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); - - printf("SCSISEQ = 0x%x, SBLKCTL = 0x%x, SSTAT0 0x%x\n", - ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SBLKCTL), - ahc_inb(ahc, SSTAT0)); + printf("SCSISEQ = 0x%x, SBLKCTL = 0x%x\n", + ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SBLKCTL)); + printf(" DFCNTRL = 0x%x, DFSTATUS = 0x%x\n", + ahc_inb(ahc, DFCNTRL), ahc_inb(ahc, DFSTATUS)); + printf("LASTPHASE = 0x%x, SCSISIGI = 0x%x, SXFRCTL0 = 0x%x\n", + last_phase, ahc_inb(ahc, SCSISIGI), ahc_inb(ahc, SXFRCTL0)); + printf("SSTAT0 = 0x%x, SSTAT1 = 0x%x\n", + ahc_inb(ahc, SSTAT0), ahc_inb(ahc, SSTAT1)); + if ((ahc->features & AHC_DT) != 0) + printf("SCSIPHASE = 0x%x\n", ahc_inb(ahc, SCSIPHASE)); + printf("STACK == 0x%x, 0x%x, 0x%x, 0x%x\n", + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8)); printf("SCB count = %d\n", ahc->scb_data->numscbs); printf("Kernel NEXTQSCB = %d\n", ahc->next_queued_scb->hscb->tag); printf("Card NEXTQSCB = %d\n", ahc_inb(ahc, NEXT_QUEUED_SCB)); @@ -6112,7 +6203,8 @@ #ifdef AHC_TARGET_MODE cam_status ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, - struct tmode_tstate **tstate, struct tmode_lstate **lstate, + struct ahc_tmode_tstate **tstate, + struct ahc_tmode_lstate **lstate, int notfound_failure) { @@ -6153,8 +6245,8 @@ void ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) { - struct tmode_tstate *tstate; - struct tmode_lstate *lstate; + struct ahc_tmode_tstate *tstate; + struct ahc_tmode_lstate *lstate; struct ccb_en_lun *cel; cam_status status; u_int target; @@ -6227,7 +6319,7 @@ ahc->flags |= AHC_TARGETROLE; if ((ahc->features & AHC_MULTIROLE) == 0) ahc->flags &= ~AHC_INITIATORROLE; - pause_sequencer(ahc); + ahc_pause(ahc); ahc_loadseq(ahc); ahc_unlock(ahc, &s); } @@ -6296,7 +6388,7 @@ SLIST_INIT(&lstate->accept_tios); SLIST_INIT(&lstate->immed_notifies); ahc_lock(ahc, &s); - pause_sequencer(ahc); + ahc_pause(ahc); if (target != CAM_TARGET_WILDCARD) { tstate->enabled_luns[lun] = lstate; ahc->enabled_luns++; @@ -6360,7 +6452,7 @@ scsiseq |= ENSELI; ahc_outb(ahc, SCSISEQ, scsiseq); } - unpause_sequencer(ahc); + ahc_unpause(ahc); ahc_unlock(ahc, &s); ccb->ccb_h.status = CAM_REQ_CMP; xpt_print_path(ccb->ccb_h.path); @@ -6410,7 +6502,7 @@ xpt_free_path(lstate->path); free(lstate, M_DEVBUF); - pause_sequencer(ahc); + ahc_pause(ahc); /* Can we clean up the target too? */ if (target != CAM_TARGET_WILDCARD) { tstate->enabled_luns[lun] = NULL; @@ -6463,11 +6555,11 @@ printf("Configuring Initiator Mode\n"); ahc->flags &= ~AHC_TARGETROLE; ahc->flags |= AHC_INITIATORROLE; - pause_sequencer(ahc); + ahc_pause(ahc); ahc_loadseq(ahc); } } - unpause_sequencer(ahc); + ahc_unpause(ahc); ahc_unlock(ahc, &s); } } @@ -6536,7 +6628,7 @@ cmd->cmd_valid = 0; /* - * Lazily update our position in the target mode incomming + * Lazily update our position in the target mode incoming * command queue as seen by the sequencer. */ if ((ahc->tqinfifonext & (HOST_TQINPOS - 1)) == 1) { @@ -6549,11 +6641,11 @@ ahc_outb(ahc, HS_MAILBOX, hs_mailbox); } else { if (!paused) - pause_sequencer(ahc); + ahc_pause(ahc); ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext & HOST_TQINPOS); if (!paused) - unpause_sequencer(ahc); + ahc_unpause(ahc); } } } @@ -6562,8 +6654,8 @@ static int ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) { - struct tmode_tstate *tstate; - struct tmode_lstate *lstate; + struct ahc_tmode_tstate *tstate; + struct ahc_tmode_lstate *lstate; struct ccb_accept_tio *atio; uint8_t *byte; int initiator; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx.h linux.ac/drivers/scsi/aic7xxx/aic7xxx.h --- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx.h Tue Apr 3 17:32:18 2001 +++ linux.ac/drivers/scsi/aic7xxx/aic7xxx.h Thu Apr 12 17:50:46 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx.h#19 $ + * $Id: //depot/src/aic7xxx/aic7xxx.h#26 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.h,v 1.30 2000/11/10 20:13:40 gibbs Exp $ */ @@ -286,56 +286,56 @@ * chip/controller's configuration. */ typedef enum { - AHC_FNONE = 0x000, - AHC_PAGESCBS = 0x001,/* Enable SCB paging */ - AHC_CHANNEL_B_PRIMARY = 0x002,/* - * On twin channel adapters, probe - * channel B first since it is the - * primary bus. + AHC_FNONE = 0x000, + AHC_PRIMARY_CHANNEL = 0x003,/* + * The channel that should + * be probed first. */ - AHC_USEDEFAULTS = 0x004,/* + AHC_USEDEFAULTS = 0x004,/* * For cards without an seeprom * or a BIOS to initialize the chip's * SRAM, we use the default target * settings. */ - AHC_SEQUENCER_DEBUG = 0x008, - AHC_SHARED_SRAM = 0x010, - AHC_LARGE_SEEPROM = 0x020,/* Uses C56_66 not C46 */ - AHC_RESET_BUS_A = 0x040, - AHC_RESET_BUS_B = 0x080, - AHC_EXTENDED_TRANS_A = 0x100, - AHC_EXTENDED_TRANS_B = 0x200, - AHC_TERM_ENB_A = 0x400, - AHC_TERM_ENB_B = 0x800, - AHC_INITIATORROLE = 0x1000,/* + AHC_SEQUENCER_DEBUG = 0x008, + AHC_SHARED_SRAM = 0x010, + AHC_LARGE_SEEPROM = 0x020,/* Uses C56_66 not C46 */ + AHC_RESET_BUS_A = 0x040, + AHC_RESET_BUS_B = 0x080, + AHC_EXTENDED_TRANS_A = 0x100, + AHC_EXTENDED_TRANS_B = 0x200, + AHC_TERM_ENB_A = 0x400, + AHC_TERM_ENB_B = 0x800, + AHC_INITIATORROLE = 0x1000,/* * Allow initiator operations on * this controller. */ - AHC_TARGETROLE = 0x2000,/* + AHC_TARGETROLE = 0x2000,/* * Allow target operations on this * controller. */ - AHC_NEWEEPROM_FMT = 0x4000, - AHC_RESOURCE_SHORTAGE = 0x8000, - AHC_TQINFIFO_BLOCKED = 0x10000,/* Blocked waiting for ATIOs */ - AHC_INT50_SPEEDFLEX = 0x20000,/* + AHC_NEWEEPROM_FMT = 0x4000, + AHC_RESOURCE_SHORTAGE = 0x8000, + AHC_TQINFIFO_BLOCKED = 0x10000,/* Blocked waiting for ATIOs */ + AHC_INT50_SPEEDFLEX = 0x20000,/* * Internal 50pin connector * sits behind an aic3860 */ - AHC_SCB_BTT = 0x40000,/* + AHC_SCB_BTT = 0x40000,/* * The busy targets table is * stored in SCB space rather * than SRAM. */ - AHC_BIOS_ENABLED = 0x80000, - AHC_ALL_INTERRUPTS = 0x100000, - AHC_ULTRA_DISABLED = 0x200000/* + AHC_BIOS_ENABLED = 0x80000, + AHC_ALL_INTERRUPTS = 0x100000, + AHC_ULTRA_DISABLED = 0x200000, /* * The precision resistor for * ultra transmission speeds is * missing, so we must limit * ourselves to fast SCSI. */ + AHC_PAGESCBS = 0x400000, /* Enable SCB paging */ + AHC_EDGE_INTERRUPT = 0x800000 /* Device uses edge triggered ints */ } ahc_flag; /* @@ -515,8 +515,9 @@ SCB_DEVICE_RESET = 0x0004, SCB_SENSE = 0x0008, SCB_CDB32_PTR = 0x0010, - SCB_RECOVERY_SCB = 0x0040, - SCB_NEGOTIATE = 0x0080, + SCB_RECOVERY_SCB = 0x0020, + SCB_AUTO_NEGOTIATE = 0x0040,/* Negotiate to achieve goal. */ + SCB_NEGOTIATE = 0x0080,/* Negotiation forced for command. */ SCB_ABORT = 0x1000, SCB_UNTAGGEDQ = 0x2000, SCB_ACTIVE = 0x4000, @@ -625,7 +626,7 @@ * data structures. */ #ifdef AHC_TARGET_MODE -struct tmode_lstate { +struct ahc_tmode_lstate { struct cam_path *path; struct ccb_hdr_slist accept_tios; struct ccb_hdr_slist immed_notifies; @@ -634,7 +635,7 @@ uint8_t event_w_idx; }; #else -struct tmode_lstate; +struct ahc_tmode_lstate; #endif /******************** Transfer Negotiation Datastructures *********************/ @@ -671,16 +672,17 @@ * that we are the target and the targets are the initiators since the * negotiation is the same regardless of role. */ -struct tmode_tstate { - struct tmode_lstate* enabled_luns[AHC_NUM_LUNS]; +struct ahc_tmode_tstate { + struct ahc_tmode_lstate* enabled_luns[AHC_NUM_LUNS]; struct ahc_initiator_tinfo transinfo[AHC_NUM_TARGETS]; /* * Per initiator state bitmasks. */ - uint16_t ultraenb; /* Using ultra sync rate */ - uint16_t discenable; /* Disconnection allowed */ - uint16_t tagenable; /* Tagged Queuing allowed */ + uint16_t auto_negotiate;/* Auto Negotiation Required */ + uint16_t ultraenb; /* Using ultra sync rate */ + uint16_t discenable; /* Disconnection allowed */ + uint16_t tagenable; /* Tagged Queuing allowed */ }; /* @@ -711,32 +713,14 @@ /***************************** Lookup Tables **********************************/ /* - * Textual descriptions of the different chips indexed by chip type. - */ -extern char *ahc_chip_names[]; -extern const u_int num_chip_names; - -/* - * Hardware error codes. - */ -struct hard_error_entry { - uint8_t errno; - char *errmesg; -}; -extern struct hard_error_entry hard_error[]; -extern const u_int num_errors; - -/* * Phase -> name and message out response * to parity errors in each phase table. */ -struct phase_table_entry { +struct ahc_phase_table_entry { uint8_t phase; uint8_t mesg_out; /* Message response to parity errors */ char *phasemsg; }; -extern struct phase_table_entry phase_table[]; -extern const u_int num_phases; /************************** Serial EEPROM Format ******************************/ @@ -765,12 +749,19 @@ #define CFSUPREM 0x0001 /* support all removeable drives */ #define CFSUPREMB 0x0002 /* support removeable boot drives */ #define CFBIOSEN 0x0004 /* BIOS enabled */ -/* UNUSED 0x0008 */ +#define CFBIOS_BUSSCAN 0x0008 /* Have the BIOS Scan the Bus */ #define CFSM2DRV 0x0010 /* support more than two drives */ -#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */ #define CFSTPWLEVEL 0x0010 /* Termination level control */ +#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */ +#define CFCTRL_A 0x0020 /* BIOS displays Ctrl-A message */ +#define CFTERM_MENU 0x0040 /* BIOS displays termination menu */ #define CFEXTEND 0x0080 /* extended translation enabled */ #define CFSCAMEN 0x0100 /* SCAM enable */ +#define CFMSG_LEVEL 0x0600 /* BIOS Message Level */ +#define CFMSG_VERBOSE 0x0000 +#define CFMSG_SILENT 0x0200 +#define CFMSG_DIAG 0x0400 +#define CFBOOTCD 0x0800 /* Support Bootable CD-ROM */ /* UNUSED 0xff00 */ /* @@ -785,10 +776,11 @@ #define CFWSTERM 0x0008 /* SCSI high byte termination */ #define CFSPARITY 0x0010 /* SCSI parity */ #define CF284XSTERM 0x0020 /* SCSI low byte term (284x cards) */ -#define CFMULTILUN 0x0020 /* SCSI low byte term (284x cards) */ +#define CFMULTILUN 0x0020 #define CFRESETB 0x0040 /* reset SCSI bus at boot */ #define CFCLUSTERENB 0x0080 /* Cluster Enable */ -#define CFCHNLBPRIMARY 0x0100 /* aic7895 probe B channel first */ +#define CFBOOTCHAN 0x0300 /* probe this channel first */ +#define CFBOOTCHANSHIFT 8 #define CFSEAUTOTERM 0x0400 /* Ultra2 Perform secondary Auto Term*/ #define CFSELOWTERM 0x0800 /* Ultra2 secondary low term */ #define CFSEHIGHTERM 0x1000 /* Ultra2 secondary high term */ @@ -812,6 +804,7 @@ uint16_t res_1[10]; /* words 20-29 */ uint16_t signature; /* Signature == 0x250 */ #define CFSIGNATURE 0x250 +#define CFSIGNATURE2 0x300 uint16_t checksum; /* word 31 */ }; @@ -857,6 +850,8 @@ uint8_t *btt; }; +typedef void (*ahc_bus_intr_t)(struct ahc_softc *); + struct ahc_softc { bus_space_tag_t tag; bus_space_handle_t bsh; @@ -900,24 +895,29 @@ ahc_dev_softc_t dev_softc; /* + * Bus specific device information. + */ + ahc_bus_intr_t bus_intr; + + /* * Target mode related state kept on a per enabled lun basis. * Targets that are not enabled will have null entries. * As an initiator, we keep one target entry for our initiator * ID to store our sync/wide transfer settings. */ - struct tmode_tstate* enabled_targets[AHC_NUM_TARGETS]; + struct ahc_tmode_tstate *enabled_targets[AHC_NUM_TARGETS]; /* * The black hole device responsible for handling requests for * disabled luns on enabled targets. */ - struct tmode_lstate* black_hole; + struct ahc_tmode_lstate *black_hole; /* * Device instance currently on the bus awaiting a continue TIO * for a command that was not given the disconnect priveledge. */ - struct tmode_lstate* pending_device; + struct ahc_tmode_lstate *pending_device; /* * Card characteristics @@ -952,9 +952,6 @@ uint8_t our_id; uint8_t our_id_b; - /* Targets that need negotiation messages */ - uint16_t targ_msg_req; - /* * PCI error detection. */ @@ -1102,6 +1099,7 @@ struct ahc_probe_config*); void ahc_controller_info(struct ahc_softc *ahc, char *buf); int ahc_init(struct ahc_softc *ahc); +void ahc_intr_enable(struct ahc_softc *ahc, int enable); void ahc_pause_and_flushwork(struct ahc_softc *ahc); int ahc_suspend(struct ahc_softc *ahc); int ahc_resume(struct ahc_softc *ahc); @@ -1143,8 +1141,10 @@ void ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb); int ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset); -void restart_sequencer(struct ahc_softc *ahc); +void ahc_restart(struct ahc_softc *ahc); /*************************** Utility Functions ********************************/ +struct ahc_phase_table_entry* + ahc_lookup_phase_entry(int phase); void ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target, u_int lun, char channel, @@ -1163,10 +1163,11 @@ struct ahc_initiator_tinfo *tinfo, u_int *bus_width, role_t role); -void ahc_update_target_msg_request(struct ahc_softc *ahc, - struct ahc_devinfo *dinfo, - struct ahc_initiator_tinfo *tinfo, - int force, int paused); +int ahc_update_neg_request(struct ahc_softc*, + struct ahc_devinfo*, + struct ahc_tmode_tstate*, + struct ahc_initiator_tinfo*, + int /*force*/); void ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, u_int width, u_int type, int paused); @@ -1176,22 +1177,27 @@ u_int period, u_int offset, u_int ppr_options, u_int type, int paused); +typedef enum { + AHC_QUEUE_NONE, + AHC_QUEUE_BASIC, + AHC_QUEUE_TAGGED +} ahc_queue_alg; + void ahc_set_tags(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, int enable); + struct ahc_devinfo *devinfo, + ahc_queue_alg alg); /**************************** Target Mode *************************************/ #ifdef AHC_TARGET_MODE void ahc_send_lstate_events(struct ahc_softc *, - struct tmode_lstate *); + struct ahc_tmode_lstate *); void ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb); cam_status ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, - struct tmode_tstate **tstate, - struct tmode_lstate **lstate, + struct ahc_tmode_tstate **tstate, + struct ahc_tmode_lstate **lstate, int notfound_failure); -void ahc_setup_target_msgin(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo); #ifndef AHC_TMODE_ENABLE #define AHC_TMODE_ENABLE 0 #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx.reg linux.ac/drivers/scsi/aic7xxx/aic7xxx.reg --- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx.reg Tue Apr 3 17:32:18 2001 +++ linux.ac/drivers/scsi/aic7xxx/aic7xxx.reg Thu Apr 12 17:50:46 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx.reg#13 $ + * $Id: //depot/src/aic7xxx/aic7xxx.reg#16 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.reg,v 1.31 2000/11/10 20:13:40 gibbs Exp $ */ @@ -877,7 +877,8 @@ address 0x094 access_mode RO bit PRELOAD_AVAIL 0x80 - bit DWORDEMP 0x20 + bit DFCACHETH 0x40 + bit FIFOQWDEMP 0x20 bit MREQPEND 0x10 bit HDONE 0x08 bit DFTHRESH 0x04 @@ -1415,15 +1416,6 @@ */ LAST_MSG { size 1 - } - - /* - * Interrupt kernel for a message to this target on - * the next transaction. This is usually used for - * negotiation requests. - */ - TARGET_MSG_REQUEST { - size 2 } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx.seq linux.ac/drivers/scsi/aic7xxx/aic7xxx.seq --- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx.seq Tue Apr 3 17:32:19 2001 +++ linux.ac/drivers/scsi/aic7xxx/aic7xxx.seq Thu Apr 12 17:50:46 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx.seq#22 $ + * $Id: //depot/src/aic7xxx/aic7xxx.seq#25 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.seq,v 1.106 2000/11/12 05:19:46 gibbs Exp $ */ @@ -479,6 +479,9 @@ */ mov SEQ_FLAGS, SCB_TARGET_INFO[SCB_TARGET_PHASES]; + test SCB_CONTROL, MK_MESSAGE jz target_ITloop; + mvi P_MESGIN|BSYO call change_phase; + jmp host_target_message_loop; target_ITloop: /* * Start honoring ATN signals now that @@ -494,12 +497,12 @@ * on the state of NO_DISCONNECT. */ test SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; - if ((ahc->flags & AHC_PAGESCBS) != 0) { - mov ALLZEROS call get_free_or_disc_scb; - } mov RETURN_1, ALLZEROS; call complete_target_cmd; cmp RETURN_1, CONT_MSG_LOOP jne .; + if ((ahc->flags & AHC_PAGESCBS) != 0) { + mov ALLZEROS call get_free_or_disc_scb; + } mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; mov SCB_TAG call dma_scb; jmp target_synccmd; @@ -758,8 +761,8 @@ test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; or SINDEX, LAST_SEG; mov SG_CACHE_PRE, SINDEX; - /* Load the segment by writing DFCNTRL again */ - mov DFCNTRL, DMAPARAMS; + /* Load the segment */ + or DFCNTRL, PRELOADEN; } ret; } @@ -948,7 +951,7 @@ test DFSTATUS, MREQPEND jnz ultra2_dmafifoempty; ultra2_dmahalt: and DFCNTRL, ~(SCSIEN|HDMAEN); - test DFCNTRL, HDMAEN jnz .; + test DFCNTRL, SCSIEN|HDMAEN jnz .; /* * If, by chance, we stopped before being able @@ -1260,7 +1263,7 @@ jmp p_command_loop; p_command_embedded: /* - * The data fifo seems to require 4 byte alligned + * The data fifo seems to require 4 byte aligned * transfers from the sequencer. Force this to * be the case by clearing HADDR[0] even though * we aren't going to touch host memeory. @@ -1351,18 +1354,6 @@ mov SINDEX, MSG_OUT; cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; test SCB_CONTROL,MK_MESSAGE jnz host_message_loop; - mov FUNCTION1, SCB_SCSIID; - mov A, FUNCTION1; - mov SINDEX, TARGET_MSG_REQUEST[0]; - if ((ahc->features & AHC_TWIN) != 0) { - /* Second Channel uses high byte bits */ - test SCB_SCSIID, TWIN_CHNLB jz . + 2; - mov SINDEX, TARGET_MSG_REQUEST[1]; - } else if ((ahc->features & AHC_WIDE) != 0) { - test SCB_SCSIID, 0x80 jz . + 2; /* target > 7 */ - mov SINDEX, TARGET_MSG_REQUEST[1]; - } - test SINDEX, A jnz host_message_loop; p_mesgout_identify: or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN; test SCB_CONTROL, DISCENB jnz . + 2; @@ -2068,9 +2059,9 @@ * latch is full. */ clr A; - /* Wait for some data to arrive. */ + /* Wait for at least 8 bytes of data to arrive. */ dma_scb_hang_fifo: - test DFSTATUS, FIFOEMP jnz dma_scb_hang_fifo; + test DFSTATUS, FIFOQWDEMP jnz dma_scb_hang_fifo; dma_scb_hang_wait: test DFSTATUS, MREQPEND jnz dma_scb_hang_wait; test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; @@ -2078,8 +2069,7 @@ test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; /* * The PCI module no longer intends to perform - * a PCI transaction and HDONE has not come true. - * We are hung. Drain the fifo. + * a PCI transaction. Drain the fifo. */ dma_scb_hang_empty_fifo: /* @@ -2101,6 +2091,7 @@ */ not SINDEX; add A, 5, SINDEX; + cmp A, 4 je dma_finish_nowait; jmp dma_scb_hang_fifo; dma_scb_hang_dma_done: and DFCNTRL, ~HDMAEN; @@ -2146,6 +2137,7 @@ */ dma_finish: test DFSTATUS,HDONE jz dma_finish; +dma_finish_nowait: /* Turn off DMA */ and DFCNTRL, ~HDMAEN; test DFCNTRL, HDMAEN jnz .; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_inline.h linux.ac/drivers/scsi/aic7xxx/aic7xxx_inline.h --- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_inline.h Tue Apr 3 17:32:19 2001 +++ linux.ac/drivers/scsi/aic7xxx/aic7xxx_inline.h Thu Apr 12 17:50:46 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx_inline.h#15 $ + * $Id: //depot/src/aic7xxx/aic7xxx_inline.h#20 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_inline.h,v 1.8 2000/11/12 05:19:46 gibbs Exp $ */ @@ -37,10 +37,10 @@ #define _AIC7XXX_INLINE_H_ /************************* Sequencer Execution Control ************************/ -static __inline int sequencer_paused(struct ahc_softc *ahc); +static __inline int ahc_is_paused(struct ahc_softc *ahc); static __inline void ahc_pause_bug_fix(struct ahc_softc *ahc); -static __inline void pause_sequencer(struct ahc_softc *ahc); -static __inline void unpause_sequencer(struct ahc_softc *ahc); +static __inline void ahc_pause(struct ahc_softc *ahc); +static __inline void ahc_unpause(struct ahc_softc *ahc); /* * Work around any chip bugs related to halting sequencer execution. @@ -62,7 +62,7 @@ * Returns non-zero status if the sequencer is stopped. */ static __inline int -sequencer_paused(struct ahc_softc *ahc) +ahc_is_paused(struct ahc_softc *ahc) { return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0); } @@ -75,7 +75,7 @@ * for critical sections. */ static __inline void -pause_sequencer(struct ahc_softc *ahc) +ahc_pause(struct ahc_softc *ahc) { ahc_outb(ahc, HCNTRL, ahc->pause); @@ -83,7 +83,7 @@ * Since the sequencer can disable pausing in a critical section, we * must loop until it actually stops. */ - while (sequencer_paused(ahc) == 0) + while (ahc_is_paused(ahc) == 0) ; ahc_pause_bug_fix(ahc); @@ -100,7 +100,7 @@ * condition. */ static __inline void -unpause_sequencer(struct ahc_softc *ahc) +ahc_unpause(struct ahc_softc *ahc) { if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0) ahc_outb(ahc, HCNTRL, ahc->unpause); @@ -193,7 +193,7 @@ ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id, u_int remote_id, - struct tmode_tstate **tstate); + struct ahc_tmode_tstate **tstate); static __inline struct scb* ahc_get_scb(struct ahc_softc *ahc); static __inline void ahc_free_scb(struct ahc_softc *ahc, struct scb *scb); @@ -228,7 +228,7 @@ */ static __inline struct ahc_initiator_tinfo * ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id, - u_int remote_id, struct tmode_tstate **tstate) + u_int remote_id, struct ahc_tmode_tstate **tstate) { /* * Transfer data structures are stored from the perspective @@ -345,10 +345,10 @@ ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); } else { if ((ahc->features & AHC_AUTOPAUSE) == 0) - pause_sequencer(ahc); + ahc_pause(ahc); ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); if ((ahc->features & AHC_AUTOPAUSE) == 0) - unpause_sequencer(ahc); + ahc_unpause(ahc); } } @@ -412,19 +412,28 @@ * completion queues. This avoids a costly PCI bus read in * most cases. */ - intstat = 0; - if ((queuestat = ahc_check_cmdcmpltqueues(ahc)) != 0) + if ((ahc->flags & (AHC_ALL_INTERRUPTS|AHC_EDGE_INTERRUPT)) == 0 + && (queuestat = ahc_check_cmdcmpltqueues(ahc)) != 0) intstat = CMDCMPLT; - - if ((intstat & INT_PEND) == 0 - || (ahc->flags & AHC_ALL_INTERRUPTS) != 0) { - + else { intstat = ahc_inb(ahc, INTSTAT); + /* + * We can't generate queuestat once above + * or we are exposed to a race when our + * interrupt is shared with another device. + * if instat showed a command complete interrupt, + * but our first generation of queue stat + * "just missed" the delivery of this transaction, + * we would clear the command complete interrupt + * below without ever servicing the completed + * command. + */ + queuestat = ahc_check_cmdcmpltqueues(ahc); #if AHC_PCI_CONFIG > 0 if (ahc->unsolicited_ints > 500 && (ahc->chip & AHC_PCI) != 0 && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0) - ahc_pci_intr(ahc); + ahc->bus_intr(ahc); #endif } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_linux.c linux.ac/drivers/scsi/aic7xxx/aic7xxx_linux.c --- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_linux.c Tue Apr 3 17:32:19 2001 +++ linux.ac/drivers/scsi/aic7xxx/aic7xxx_linux.c Sat Apr 14 01:29:21 2001 @@ -1,7 +1,7 @@ /* * Adaptec AIC7xxx device driver for Linux. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c#54 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c#63 $ * * Copyright (c) 1994 John Aycock * The University of Calgary Department of Computer Science. @@ -112,6 +112,9 @@ * 8: SMP friendliness has been improved * */ +#include <linux/config.h> + +#include <linux/config.h> /* * The next three defines are user configurable. These should be the only @@ -157,8 +160,8 @@ * The scsi error recovery code performs its own bus settle * delay handling for error recovery actions. */ -#ifdef CONFIG_AIC7XXX_RESET_DELAY -#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY +#ifdef CONFIG_AIC7XXX_RESET_DELAY_MS +#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY_MS #else #define AIC7XXX_RESET_DELAY 5000 #endif @@ -478,45 +481,47 @@ #endif -static void ahc_handle_scsi_status(struct ahc_softc *, - struct ahc_linux_device *, struct scb *); -static void ahc_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd); -static void ahc_sem_timeout(u_long arg); -static void ahc_release_sim_queue(u_long arg); -static int aic7xxx_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag); -static void aic7xxx_initialize_scsi_bus(struct ahc_softc *ahc); -static void aic7xxx_select_queue_depth(struct Scsi_Host *host, - Scsi_Device *scsi_devs); -static void aic7xxx_device_queue_depth(struct ahc_softc *ahc, - Scsi_Device *device); -static struct ahc_linux_target* ahc_alloc_target(struct ahc_softc *, - u_int, u_int); -static void ahc_free_target(struct ahc_softc *ahc, - struct ahc_linux_target *targ); -static struct ahc_linux_device* ahc_alloc_device(struct ahc_softc *, - struct ahc_linux_target *, - u_int); -static void ahc_free_device(struct ahc_softc *ahc, - struct ahc_linux_device *dev); -static void ahc_run_device_queue(struct ahc_softc *ahc, - struct ahc_linux_device *dev); -static void ahc_setup_tag_info(char *p, char *end); -static int ahc_next_unit(void); +static void ahc_linux_handle_scsi_status(struct ahc_softc *, + struct ahc_linux_device *, + struct scb *); +static void ahc_linux_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd); +static void ahc_linux_sem_timeout(u_long arg); +static void ahc_linux_release_sim_queue(u_long arg); +static int ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag); +static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc); +static void ahc_linux_select_queue_depth(struct Scsi_Host *host, + Scsi_Device *scsi_devs); +static void ahc_linux_device_queue_depth(struct ahc_softc *ahc, + Scsi_Device *device); +static struct ahc_linux_target* ahc_linux_alloc_target(struct ahc_softc*, + u_int, u_int); +static void ahc_linux_free_target(struct ahc_softc*, + struct ahc_linux_target*); +static struct ahc_linux_device* ahc_linux_alloc_device(struct ahc_softc*, + struct ahc_linux_target*, + u_int); +static void ahc_linux_free_device(struct ahc_softc*, + struct ahc_linux_device*); +static void ahc_linux_run_device_queue(struct ahc_softc*, + struct ahc_linux_device*); +static void ahc_linux_setup_tag_info(char *p, char *end); +static int ahc_linux_next_unit(void); +static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf); static __inline struct ahc_linux_device* - ahc_get_device(struct ahc_softc *ahc, u_int channel, - u_int target, u_int lun, int /*alloc*/); -static __inline void ahc_queue_cmd_complete(struct ahc_softc *ahc, - Scsi_Cmnd *cmd); -static __inline void ahc_run_complete_queue(struct ahc_softc *ahc, - struct ahc_cmd *acmd); -static __inline void ahc_check_device_queue(struct ahc_softc *ahc, - struct ahc_linux_device *dev); -static __inline void ahc_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd); -static __inline void ahc_unmap_scb(struct ahc_softc *ahc, struct scb *scb); + ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, + u_int target, u_int lun, int alloc); +static __inline void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, + Scsi_Cmnd *cmd); +static __inline void ahc_linux_run_complete_queue(struct ahc_softc *ahc, + struct ahc_cmd *acmd); +static __inline void ahc_linux_check_device_queue(struct ahc_softc *ahc, + struct ahc_linux_device *dev); +static __inline void ahc_linux_sniff_command(struct ahc_softc*, Scsi_Cmnd*); +static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*); static __inline struct ahc_linux_device* -ahc_get_device(struct ahc_softc *ahc, u_int channel, u_int target, +ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target, u_int lun, int alloc) { struct ahc_linux_target *targ; @@ -529,7 +534,7 @@ targ = ahc->platform_data->targets[target_offset]; if (targ == NULL) { if (alloc != 0) { - targ = ahc_alloc_target(ahc, channel, target); + targ = ahc_linux_alloc_target(ahc, channel, target); if (targ == NULL) return (NULL); } else @@ -537,17 +542,17 @@ } dev = targ->devices[lun]; if (dev == NULL && alloc != 0) - dev = ahc_alloc_device(ahc, targ, lun); + dev = ahc_linux_alloc_device(ahc, targ, lun); return (dev); } static __inline void -ahc_queue_cmd_complete(struct ahc_softc *ahc, Scsi_Cmnd *cmd) +ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, Scsi_Cmnd *cmd) { /* * Typically, the complete queue has very few entries * queued to it before the queue is emptied by - * ahc_run_complete_queue, so sorting the entries + * ahc_linux_run_complete_queue, so sorting the entries * by generation number should be inexpensive. * We perform the sort so that commands that complete * with an error are retuned in the order origionally @@ -583,7 +588,7 @@ } static __inline void -ahc_run_complete_queue(struct ahc_softc *ahc, struct ahc_cmd *acmd) +ahc_linux_run_complete_queue(struct ahc_softc *ahc, struct ahc_cmd *acmd) { u_long done_flags; @@ -600,7 +605,8 @@ } static __inline void -ahc_check_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev) +ahc_linux_check_device_queue(struct ahc_softc *ahc, + struct ahc_linux_device *dev) { if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) != 0 && dev->active == 0) { @@ -612,11 +618,11 @@ || dev->openings == 0 || dev->qfrozen != 0) return; - ahc_run_device_queue(ahc, dev); + ahc_linux_run_device_queue(ahc, dev); } static __inline void -ahc_run_device_queues(struct ahc_softc *ahc) +ahc_linux_run_device_queues(struct ahc_softc *ahc) { struct ahc_linux_device *dev; @@ -625,25 +631,25 @@ && (dev = LIST_FIRST(&ahc->platform_data->device_runq)) != NULL) { LIST_REMOVE(dev, links); dev->flags &= ~AHC_DEV_ON_RUN_LIST; - ahc_check_device_queue(ahc, dev); + ahc_linux_check_device_queue(ahc, dev); } } static __inline void -ahc_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd) +ahc_linux_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd) { /* * Determine whether we care to filter * information out of this command. If so, - * pass it on to ahc_filter_command() for more + * pass it on to ahc_linux_filter_command() for more * heavy weight processing. */ if (cmd->cmnd[0] == INQUIRY) - ahc_filter_command(ahc, cmd); + ahc_linux_filter_command(ahc, cmd); } static __inline void -ahc_unmap_scb(struct ahc_softc *ahc, struct scb *scb) +ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb) { Scsi_Cmnd *cmd; @@ -661,6 +667,25 @@ scsi_to_pci_dma_dir(cmd->sc_data_direction)); } +/************************ Shutdown/halt/reboot hook ***************************/ +#include <linux/notifier.h> +#include <linux/reboot.h> + +static struct notifier_block ahc_linux_notifier = { + ahc_linux_halt, NULL, 0 +}; + +static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf) +{ + struct ahc_softc *ahc; + + TAILQ_FOREACH(ahc, &ahc_tailq, links) { + ahc_shutdown(ahc); + } + unregister_reboot_notifier(&ahc_linux_notifier); + return (NOTIFY_OK); +} + /******************************** Macros **************************************/ #define BUILD_SCSIID(ahc, cmd) \ ((((cmd)->target << TID_SHIFT) & TID) \ @@ -819,6 +844,9 @@ /* Still equal. Sort by BIOS address, ioport, or bus/slot/func. */ switch (rvalue) { case AHC_PCI: + { + char primary_channel; + value = ahc_get_pci_bus(lahc->dev_softc) - ahc_get_pci_bus(rahc->dev_softc); if (value != 0) @@ -827,19 +855,18 @@ - ahc_get_pci_slot(rahc->dev_softc); if (value != 0) break; - value = ahc_get_pci_function(lahc->dev_softc) - - ahc_get_pci_function(rahc->dev_softc); /* * On multi-function devices, the user can choose * to have function 1 probed before function 0. - * Function 0 is the only one that will have - * CHANNEL_B_PRIMARY set. + * Give whichever channel is the primary channel + * the lowest priority. */ - if (value < 0 - && (lahc->flags & AHC_CHANNEL_B_PRIMARY) != 0) - /* Swap the two */ - value = -value; + primary_channel = (lahc->flags & AHC_PRIMARY_CHANNEL) + 'A'; + value = 1; + if (lahc->channel == primary_channel) + value = -1; break; + } case AHC_EISA: if ((rahc->flags & AHC_BIOS_ENABLED) != 0) { value = lahc->platform_data->bios_address @@ -856,7 +883,7 @@ } static void -ahc_setup_tag_info(char *p, char *end) +ahc_linux_setup_tag_info(char *p, char *end) { char *base; char *tok; @@ -864,7 +891,7 @@ char *tok_end2; int i; int instance; - int device; + int targ; int done; char tok_list[] = {'.', ',', '{', '}', '\0'}; @@ -872,7 +899,7 @@ return; instance = -1; - device = -1; + targ = -1; done = FALSE; base = p; /* Forward us just past the ':' */ @@ -885,13 +912,13 @@ case '{': if (instance == -1) instance = 0; - else if (device == -1) - device = 0; + else if (targ == -1) + targ = 0; tok++; break; case '}': - if (device != -1) - device = -1; + if (targ != -1) + targ = -1; else if (instance != -1) instance = -1; tok++; @@ -900,11 +927,11 @@ case '.': if (instance == -1) done = TRUE; - else if (device >= 0) - device++; + else if (targ >= 0) + targ++; else if (instance >= 0) instance++; - if ((device >= AHC_NUM_TARGETS) || + if ((targ >= AHC_NUM_TARGETS) || (instance >= NUM_ELEMENTS(aic7xxx_tag_info))) done = TRUE; tok++; @@ -925,11 +952,12 @@ done = FALSE; } } - if ((instance >= 0) && (device >= 0) && - (instance < NUM_ELEMENTS(aic7xxx_tag_info)) && - (device < AHC_NUM_TARGETS)) - aic7xxx_tag_info[instance].tag_commands[device] = + if ((instance >= 0) && (targ >= 0) + && (instance < NUM_ELEMENTS(aic7xxx_tag_info)) + && (targ < AHC_NUM_TARGETS)) { + aic7xxx_tag_info[instance].tag_commands[targ] = simple_strtoul(tok, NULL, 0) & 0xff; + } tok = tok_end; break; } @@ -979,7 +1007,7 @@ continue; if (strncmp(p, "tag_info", n) == 0) { - ahc_setup_tag_info(p + n, end); + ahc_linux_setup_tag_info(p + n, end); } else if (p[n] == ':') { *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); @@ -988,8 +1016,10 @@ } else { *(options[i].flag) = ~(*(options[i].flag)); } + break; } } + register_reboot_notifier(&ahc_linux_notifier); return 1; } @@ -1003,7 +1033,7 @@ * Try to detect an Adaptec 7XXX controller. */ int -aic7xxx_detect(Scsi_Host_Template *template) +ahc_linux_detect(Scsi_Host_Template *template) { struct ahc_softc *ahc; int found; @@ -1015,8 +1045,8 @@ */ if (offsetof(struct ahc_cmd_internal, end) > offsetof(struct scsi_cmnd, host_scribble)) { - printf("aic7xxx_detect: SCSI data structures changed.\n"); - printf("aic7xxx_detect: Unable to attach\n"); + printf("ahc_linux_detect: SCSI data structures changed.\n"); + printf("ahc_linux_detect: Unable to attach\n"); return (0); } #ifdef MODULE @@ -1053,7 +1083,7 @@ found = 0; TAILQ_FOREACH(ahc, &ahc_tailq, links) { - if (aic7xxx_register_host(ahc, template) == 0) + if (ahc_linux_register_host(ahc, template) == 0) found++; } aic7xxx_detect_complete++; @@ -1061,7 +1091,7 @@ } int -aic7xxx_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) +ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) { char buf[80]; struct Scsi_Host *host; @@ -1080,12 +1110,13 @@ host->can_queue = AHC_MAX_QUEUE; host->cmd_per_lun = 2; host->sg_tablesize = AHC_NSEG; - host->select_queue_depths = aic7xxx_select_queue_depth; + host->select_queue_depths = ahc_linux_select_queue_depth; + /* XXX No way to communicate the ID for multiple channels */ host->this_id = ahc->our_id; host->irq = ahc->platform_data->irq; host->max_id = (ahc->features & AHC_WIDE) ? 16 : 8; host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0; - ahc_set_unit(ahc, ahc_next_unit()); + ahc_set_unit(ahc, ahc_linux_next_unit()); sprintf(buf, "scsi%d", host->host_no); new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); if (new_name != NULL) { @@ -1093,7 +1124,7 @@ ahc_set_name(ahc, new_name); } host->unique_id = ahc->unit; - aic7xxx_initialize_scsi_bus(ahc); + ahc_linux_initialize_scsi_bus(ahc); ahc_unlock(ahc, &s); return (0); } @@ -1105,7 +1136,7 @@ * scenario. */ static int -ahc_next_unit() +ahc_linux_next_unit() { struct ahc_softc *ahc; int unit; @@ -1127,7 +1158,7 @@ * target. */ void -aic7xxx_initialize_scsi_bus(struct ahc_softc *ahc) +ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc) { int i; int numtarg; @@ -1157,7 +1188,7 @@ for (; i < numtarg; i++) { struct ahc_devinfo devinfo; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; u_int our_id; u_int target_id; char channel; @@ -1173,20 +1204,28 @@ tinfo = ahc_fetch_transinfo(ahc, channel, our_id, target_id, &tstate); tinfo->goal = tinfo->user; + /* + * Don't try negotiations that require PPR messages + * until we successfully retrieve Inquiry data. + */ + tinfo->goal.ppr_options = 0; + if (tinfo->goal.transport_version > SCSI_REV_2) + tinfo->goal.transport_version = SCSI_REV_2; ahc_compile_devinfo(&devinfo, our_id, target_id, CAM_LUN_WILDCARD, channel, ROLE_INITIATOR); - ahc_update_target_msg_request(ahc, &devinfo, tinfo, - /*force*/FALSE, /*paused*/FALSE); + ahc_update_neg_request(ahc, &devinfo, tstate, + tinfo, /*force*/FALSE); } /* Give the bus some time to recover */ if ((ahc->flags & (AHC_RESET_BUS_A|AHC_RESET_BUS_B)) != 0) { + scsi_block_requests(ahc->platform_data->host); ahc->platform_data->qfrozen++; init_timer(&ahc->platform_data->reset_timer); ahc->platform_data->reset_timer.data = (u_long)ahc; ahc->platform_data->reset_timer.expires = jiffies + (AIC7XXX_RESET_DELAY * HZ)/1000; ahc->platform_data->reset_timer.function = - ahc_release_sim_queue; + ahc_linux_release_sim_queue; add_timer(&ahc->platform_data->reset_timer); } } @@ -1236,6 +1275,11 @@ 0x1000); #endif } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + /* XXX Need an instance detach in the PCI code */ + if (ahc->dev_softc != NULL) + ahc->dev_softc->driver = NULL; +#endif free(ahc->platform_data, M_DEVBUF); } } @@ -1250,28 +1294,41 @@ } void -ahc_platform_set_tags(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, int enable) +ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + ahc_queue_alg alg) { struct ahc_linux_device *dev; + int was_queuing; + int now_queuing; - dev = ahc_get_device(ahc, devinfo->channel - 'A', - devinfo->target, - devinfo->lun, /*alloc*/FALSE); + dev = ahc_linux_get_device(ahc, devinfo->channel - 'A', + devinfo->target, + devinfo->lun, /*alloc*/FALSE); + was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED); + now_queuing = alg != AHC_QUEUE_NONE; if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) == 0 + && (was_queuing != now_queuing) && (dev->active != 0)) { dev->flags |= AHC_DEV_FREEZE_TIL_EMPTY; dev->qfrozen++; } - if (enable) { - /* - * Start out agressively and allow our - * dynamic queue depth algorithm take - * care of the rest. - */ - dev->maxtags = AHC_MAX_QUEUE; - dev->openings = dev->maxtags - dev->active; + dev->flags &= ~(AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED); + if (now_queuing) { + + if (!was_queuing) { + /* + * Start out agressively and allow our + * dynamic queue depth algorithm to take + * care of the rest. + */ + dev->maxtags = AHC_MAX_QUEUE; + dev->openings = dev->maxtags - dev->active; + } + if (alg == AHC_QUEUE_TAGGED) + dev->flags |= AHC_DEV_Q_TAGGED; + else + dev->flags |= AHC_DEV_Q_BASIC; } else { /* We can only have one opening */ dev->maxtags = 0; @@ -1324,9 +1381,9 @@ struct ahc_busyq *busyq; struct ahc_cmd *acmd; - dev = ahc_get_device(ahc, chan, targ, - clun, /*alloc*/FALSE); - + dev = ahc_linux_get_device(ahc, chan, + targ, clun, + /*alloc*/FALSE); if (dev == NULL) continue; @@ -1339,7 +1396,7 @@ acmd_links.tqe); count++; cmd->result = status << 16; - ahc_queue_cmd_complete(ahc, cmd); + ahc_linux_queue_cmd_complete(ahc, cmd); } } } @@ -1353,8 +1410,8 @@ * off the input host adapter. */ static void -aic7xxx_select_queue_depth(struct Scsi_Host * host, - Scsi_Device * scsi_devs) +ahc_linux_select_queue_depth(struct Scsi_Host * host, + Scsi_Device * scsi_devs) { Scsi_Device *device; struct ahc_softc *ahc; @@ -1366,7 +1423,7 @@ scbnum = 0; for (device = scsi_devs; device != NULL; device = device->next) { if (device->host == host) { - aic7xxx_device_queue_depth(ahc, device); + ahc_linux_device_queue_depth(ahc, device); scbnum += device->queue_depth; } } @@ -1377,11 +1434,11 @@ * Determines the queue depth for a given device. */ static void -aic7xxx_device_queue_depth(struct ahc_softc *ahc, Scsi_Device * device) +ahc_linux_device_queue_depth(struct ahc_softc *ahc, Scsi_Device * device) { struct ahc_devinfo devinfo; struct ahc_initiator_tinfo *targ_info; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; uint8_t tags; ahc_compile_devinfo(&devinfo, @@ -1395,7 +1452,7 @@ tags = 0; if (device->tagged_supported != 0 - && (tstate->discenable & devinfo.target_mask) != 0) { + && (ahc->user_discenable & devinfo.target_mask) != 0) { if (ahc->unit >= NUM_ELEMENTS(aic7xxx_tag_info)) { printf("aic7xxx: WARNING, insufficient " @@ -1416,7 +1473,7 @@ } if (tags != 0) { device->queue_depth = tags; - ahc_set_tags(ahc, &devinfo, TRUE); + ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED); printf("scsi%d:%d:%d:%d: Tagged Queuing enabled. Depth %d\n", ahc->platform_data->host->host_no, device->channel, device->id, device->lun, tags); @@ -1435,7 +1492,7 @@ * Queue an SCB to the controller. */ int -aic7xxx_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) +ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) { struct ahc_softc *ahc; struct ahc_linux_device *dev; @@ -1449,29 +1506,29 @@ cmd->scsi_done = scsi_done; ahc_lock(ahc, &flags); - dev = ahc_get_device(ahc, cmd->channel, cmd->target, - cmd->lun, /*alloc*/TRUE); + dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target, + cmd->lun, /*alloc*/TRUE); if (dev == NULL) { ahc_unlock(ahc, &flags); - printf("aic7xxx_queue: Unable to allocate device!\n"); + printf("aic7xxx_linux_queue: Unable to allocate device!\n"); return (-ENOMEM); } cmd->result = CAM_REQ_INPROG << 16; TAILQ_INSERT_TAIL(&dev->busyq, (struct ahc_cmd *)cmd, acmd_links.tqe); - ahc_run_device_queue(ahc, dev); + ahc_linux_run_device_queue(ahc, dev); ahc_unlock(ahc, &flags); return (0); } static void -ahc_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev) +ahc_linux_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev) { struct ahc_cmd *acmd; struct scsi_cmnd *cmd; struct scb *scb; struct hardware_scb *hscb; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; uint16_t mask; while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL @@ -1526,15 +1583,22 @@ if ((tstate->ultraenb & mask) != 0) hscb->control |= ULTRAENB; - if ((tstate->discenable & mask) != 0) + if ((ahc->user_discenable & mask) != 0) hscb->control |= DISCENB; - if ((tstate->tagenable & mask) != 0) { - /* XXX What about devices that dislike ordered tags? */ - if ((dev->num_commands % 256) == 0) - hscb->control |= MSG_ORDERED_Q_TAG; - else - hscb->control |= MSG_SIMPLE_Q_TAG; + if ((tstate->auto_negotiate & mask) != 0) { + scb->flags |= SCB_AUTO_NEGOTIATE; + scb->hscb->control |= MK_MESSAGE; + } + + if ((dev->flags & (AHC_DEV_Q_TAGGED|AHC_DEV_Q_BASIC)) != 0) { + if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH + && (dev->flags & AHC_DEV_Q_TAGGED) != 0) { + hscb->control |= MSG_ORDERED_TASK; + dev->commands_since_idle_or_otag = 0; + } else { + hscb->control |= MSG_SIMPLE_TASK; + } } hscb->cdb_len = cmd->cmd_len; @@ -1630,7 +1694,8 @@ LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links); dev->openings--; dev->active++; - dev->num_commands++; + dev->commands_issued++; + dev->commands_since_idle_or_otag++; /* * We only allow one untagged transaction @@ -1659,7 +1724,7 @@ * SCSI controller interrupt handler. */ void -aic7xxx_isr(int irq, void *dev_id, struct pt_regs * regs) +ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs) { struct ahc_softc *ahc; struct ahc_cmd *acmd; @@ -1674,12 +1739,12 @@ * dynamically register one, we'll have to postpone * that until we get integrated into the kernel. */ - ahc_run_device_queues(ahc); + ahc_linux_run_device_queues(ahc); acmd = TAILQ_FIRST(&ahc->platform_data->completeq); TAILQ_INIT(&ahc->platform_data->completeq); ahc_unlock(ahc, &flags); if (acmd != NULL) - ahc_run_complete_queue(ahc, acmd); + ahc_linux_run_complete_queue(ahc, acmd); } void @@ -1690,11 +1755,11 @@ acmd = TAILQ_FIRST(&ahc->platform_data->completeq); TAILQ_INIT(&ahc->platform_data->completeq); if (acmd != NULL) - ahc_run_complete_queue(ahc, acmd); + ahc_linux_run_complete_queue(ahc, acmd); } static struct ahc_linux_target* -ahc_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target) +ahc_linux_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target) { struct ahc_linux_target *targ; u_int target_offset; @@ -1713,7 +1778,7 @@ } static void -ahc_free_target(struct ahc_softc *ahc, struct ahc_linux_target *targ) +ahc_linux_free_target(struct ahc_softc *ahc, struct ahc_linux_target *targ) { u_int target_offset; @@ -1725,7 +1790,7 @@ } static struct ahc_linux_device* -ahc_alloc_device(struct ahc_softc *ahc, +ahc_linux_alloc_device(struct ahc_softc *ahc, struct ahc_linux_target *targ, u_int lun) { struct ahc_linux_device *dev; @@ -1758,7 +1823,7 @@ } static void -ahc_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) +ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) { struct ahc_linux_target *targ; @@ -1767,14 +1832,14 @@ free(dev, M_DEVBUF); targ->refcount--; if (targ->refcount == 0) - ahc_free_target(ahc, targ); + ahc_linux_free_target(ahc, targ); } /* * Return a string describing the driver. */ const char * -aic7xxx_info(struct Scsi_Host *host) +ahc_linux_info(struct Scsi_Host *host) { static char buffer[512]; char ahc_info[256]; @@ -1800,7 +1865,7 @@ void ahc_send_async(struct ahc_softc *ahc, char channel, - u_int target, u_int lun, ac_code code) + u_int target, u_int lun, ac_code code, void *arg) { switch (code) { case AC_TRANSFER_NEG: @@ -1809,7 +1874,7 @@ struct ahc_linux_target *targ; struct info_str info; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; int target_offset; info.buffer = buf; @@ -1907,7 +1972,7 @@ dev = scb->platform_data->dev; dev->active--; dev->openings++; - ahc_unmap_scb(ahc, scb); + ahc_linux_unmap_scb(ahc, scb); if (scb->flags & SCB_SENSE) { memcpy(cmd->sense_buffer, ahc_get_sense_buf(ahc, scb), MIN(sizeof(struct scsi_sense_data), @@ -1926,10 +1991,19 @@ ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR); } else { ahc_set_transaction_status(scb, CAM_REQ_CMP); - ahc_sniff_command(ahc, cmd); + ahc_linux_sniff_command(ahc, cmd); } } else if (ahc_get_transaction_status(scb) == DID_OK) { - ahc_handle_scsi_status(ahc, dev, scb); + ahc_linux_handle_scsi_status(ahc, dev, scb); + } else if (ahc_get_transaction_status(scb) == DID_NO_CONNECT) { + /* + * Should a selection timeout kill the device? + * That depends on whether the selection timeout + * is persistent. Since we have no guarantee that + * the mid-layer will issue an inquiry for this device + * again, we can't just kill it off. + dev->flags |= AHC_DEV_UNCONFIGURED; + */ } if (dev->openings == 1 @@ -1948,10 +2022,14 @@ dev->openings++; } - if (dev->active == 0 - && (dev->flags & AHC_DEV_UNCONFIGURED) != 0) - ahc_free_device(ahc, dev); - else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { + if (dev->active == 0) + dev->commands_since_idle_or_otag = 0; + + if (TAILQ_EMPTY(&dev->busyq)) { + if ((dev->flags & AHC_DEV_UNCONFIGURED) != 0 + && dev->active == 0) + ahc_linux_free_device(ahc, dev); + } else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { LIST_INSERT_HEAD(&ahc->platform_data->device_runq, dev, links); dev->flags |= AHC_DEV_ON_RUN_LIST; } @@ -1962,12 +2040,12 @@ } ahc_free_scb(ahc, scb); - ahc_queue_cmd_complete(ahc, cmd); + ahc_linux_queue_cmd_complete(ahc, cmd); } static void -ahc_handle_scsi_status(struct ahc_softc *ahc, - struct ahc_linux_device *dev, struct scb *scb) +ahc_linux_handle_scsi_status(struct ahc_softc *ahc, + struct ahc_linux_device *dev, struct scb *scb) { /* * We don't currently trust the mid-layer to @@ -2048,7 +2126,7 @@ } static void -ahc_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd) +ahc_linux_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd) { switch (cmd->cmnd[0]) { case INQUIRY: @@ -2056,8 +2134,9 @@ struct ahc_devinfo devinfo; struct scsi_inquiry_data *sid; struct ahc_initiator_tinfo *targ_info; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; struct ahc_syncrate *syncrate; + struct ahc_linux_device *dev; u_int scsiid; u_int maxsync; int minlen; @@ -2076,15 +2155,20 @@ /* * Determine if this lun actually exists. If so, * hold on to its corresponding device structure. - */ + * If not, make sure we release the device and + * don't bother processing the rest of this inquiry + * command. + */ + dev = ahc_linux_get_device(ahc, cmd->channel, + cmd->target, cmd->lun, + /*alloc*/FALSE); if (cmd->request_bufflen >= 1 && SID_QUAL(sid) == SID_QUAL_LU_CONNECTED) { - struct ahc_linux_device *dev; - dev = ahc_get_device(ahc, cmd->channel, - cmd->target, cmd->lun, - /*alloc*/FALSE); dev->flags &= ~AHC_DEV_UNCONFIGURED; + } else { + dev->flags |= AHC_DEV_UNCONFIGURED; + break; } /* @@ -2160,6 +2244,11 @@ &ppr_options, maxsync); ahc_validate_offset(ahc, /*tinfo limit*/NULL, syncrate, &offset, width, ROLE_UNKNOWN); + if (offset == 0 || period == 0) { + period = 0; + offset = 0; + ppr_options = 0; + } /* Apply our filtered user settings. */ ahc_set_width(ahc, &devinfo, width, AHC_TRANS_GOAL, /*paused*/FALSE); @@ -2169,14 +2258,14 @@ break; } default: - panic("ahc_filter_command: Unexpected Command type %x\n", + panic("ahc_linux_filter_command: Unexpected Command type %x\n", cmd->cmnd[0]); break; } } static void -ahc_sem_timeout(u_long arg) +ahc_linux_sem_timeout(u_long arg) { struct semaphore *sem; @@ -2185,7 +2274,7 @@ } static void -ahc_release_sim_queue(u_long arg) +ahc_linux_release_sim_queue(u_long arg) { struct ahc_softc *ahc; u_long s; @@ -2195,12 +2284,13 @@ if (ahc->platform_data->qfrozen > 0) ahc->platform_data->qfrozen--; if (ahc->platform_data->qfrozen == 0) - ahc_run_device_queues(ahc); + ahc_linux_run_device_queues(ahc); ahc_unlock(ahc, &s); + scsi_unblock_requests(ahc->platform_data->host); } static int -aic7xxx_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) +ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) { struct ahc_softc *ahc; struct ahc_cmd *acmd; @@ -2240,8 +2330,8 @@ * at all, and the system wanted us to just abort the * command return success. */ - dev = ahc_get_device(ahc, cmd->channel, cmd->target, - cmd->lun, /*alloc*/FALSE); + dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target, + cmd->lun, /*alloc*/FALSE); if (dev == NULL) { /* @@ -2265,7 +2355,7 @@ if (flag == SCB_ABORT) { TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe); cmd->result = DID_ABORT << 16; - ahc_queue_cmd_complete(ahc, cmd); + ahc_linux_queue_cmd_complete(ahc, cmd); retval = SUCCESS; goto done; } @@ -2313,7 +2403,7 @@ ahc->flags |= AHC_ALL_INTERRUPTS; do { ahc_intr(ahc); - pause_sequencer(ahc); + ahc_pause(ahc); ahc_clear_critical_section(ahc); } while (ahc_inb(ahc, INTSTAT) & INT_PEND); ahc->flags &= ~AHC_ALL_INTERRUPTS; @@ -2453,7 +2543,7 @@ retval = SUCCESS; done: if (paused) - unpause_sequencer(ahc); + ahc_unpause(ahc); if (wait) { struct timer_list timer; int ret; @@ -2462,7 +2552,7 @@ init_timer(&timer); timer.data = (u_long)&ahc->platform_data->eh_sem; timer.expires = jiffies + (5 * HZ); - timer.function = ahc_sem_timeout; + timer.function = ahc_linux_sem_timeout; add_timer(&timer); printf("Recovery code sleeping\n"); down(&ahc->platform_data->eh_sem); @@ -2474,12 +2564,12 @@ } ahc_lock(ahc, &s); } - ahc_run_device_queues(ahc); + ahc_linux_run_device_queues(ahc); acmd = TAILQ_FIRST(&ahc->platform_data->completeq); TAILQ_INIT(&ahc->platform_data->completeq); ahc_unlock(ahc, &s); if (acmd != NULL) - ahc_run_complete_queue(ahc, acmd); + ahc_linux_run_complete_queue(ahc, acmd); spin_lock_irq(&io_request_lock); return (retval); } @@ -2488,11 +2578,11 @@ * Abort the current SCSI command(s). */ int -aic7xxx_abort(Scsi_Cmnd *cmd) +ahc_linux_abort(Scsi_Cmnd *cmd) { int error; - error = aic7xxx_queue_recovery_cmd(cmd, SCB_ABORT); + error = ahc_linux_queue_recovery_cmd(cmd, SCB_ABORT); if (error != 0) printf("aic7xxx_abort returns %d\n", error); return (error); @@ -2502,11 +2592,11 @@ * Attempt to send a target reset message to the device that timed out. */ int -aic7xxx_dev_reset(Scsi_Cmnd *cmd) +ahc_linux_dev_reset(Scsi_Cmnd *cmd) { int error; - error = aic7xxx_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); + error = ahc_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); if (error != 0) printf("aic7xxx_dev_reset returns %d\n", error); return (error); @@ -2516,7 +2606,7 @@ * Reset the SCSI bus. */ int -aic7xxx_bus_reset(Scsi_Cmnd *cmd) +ahc_linux_bus_reset(Scsi_Cmnd *cmd) { struct ahc_softc *ahc; struct ahc_cmd *acmd; @@ -2541,7 +2631,7 @@ "%d SCBs aborted.\n", ahc_name(ahc), found); if (acmd != NULL) - ahc_run_complete_queue(ahc, acmd); + ahc_linux_run_complete_queue(ahc, acmd); spin_lock_irq(&io_request_lock); return SUCCESS; @@ -2551,7 +2641,7 @@ * Return the disk geometry for the given SCSI device. */ int -aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[]) +ahc_linux_biosparam(Disk *disk, kdev_t dev, int geom[]) { int heads; int sectors; @@ -2595,14 +2685,23 @@ * module. */ int -aic7xxx_release(struct Scsi_Host * host) +ahc_linux_release(struct Scsi_Host * host) { struct ahc_softc *ahc; if (host != NULL) { + ahc = *(struct ahc_softc **)host->hostdata; ahc_free(ahc); } + if (TAILQ_EMPTY(&ahc_tailq)) { + unregister_reboot_notifier(&ahc_linux_notifier); +#ifdef CONFIG_PCI +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pci_unregister_driver(&aic7xxx_pci_driver); +#endif +#endif + } return (0); } @@ -2624,8 +2723,8 @@ for (lun = 0; lun < AHC_NUM_LUNS; lun++) { struct ahc_cmd *acmd; - dev = ahc_get_device(ahc, channel, target, - lun, /*alloc*/FALSE); + dev = ahc_linux_get_device(ahc, channel, target, + lun, /*alloc*/FALSE); if (dev == NULL) continue; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_linux_host.h linux.ac/drivers/scsi/aic7xxx/aic7xxx_linux_host.h --- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_linux_host.h Tue Apr 3 17:32:19 2001 +++ linux.ac/drivers/scsi/aic7xxx/aic7xxx_linux_host.h Thu Apr 12 17:50:46 2001 @@ -28,24 +28,24 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h#2 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h#3 $ */ #ifndef _AIC7XXX_LINUX_HOST_H_ #define _AIC7XXX_LINUX_HOST_H_ -int aic7xxx_proc_info(char *, char **, off_t, int, int, int); -int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); -int aic7xxx_detect(Scsi_Host_Template *); -int aic7xxx_release(struct Scsi_Host *); -const char *aic7xxx_info(struct Scsi_Host *); -int aic7xxx_biosparam(Disk *, kdev_t, int[]); -int aic7xxx_bus_reset(Scsi_Cmnd *); -int aic7xxx_dev_reset(Scsi_Cmnd *); -int aic7xxx_abort(Scsi_Cmnd *); +int ahc_linux_proc_info(char *, char **, off_t, int, int, int); +int ahc_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); +int ahc_linux_detect(Scsi_Host_Template *); +int ahc_linux_release(struct Scsi_Host *); +const char *ahc_linux_info(struct Scsi_Host *); +int ahc_linux_biosparam(Disk *, kdev_t, int[]); +int ahc_linux_bus_reset(Scsi_Cmnd *); +int ahc_linux_dev_reset(Scsi_Cmnd *); +int ahc_linux_abort(Scsi_Cmnd *); #if defined(__i386__) -# define AIC7XXX_BIOSPARAM aic7xxx_biosparam +# define AIC7XXX_BIOSPARAM ahc_linux_biosparam #else # define AIC7XXX_BIOSPARAM NULL #endif @@ -58,23 +58,23 @@ next: NULL, \ module: NULL, \ proc_dir: NULL, \ - proc_info: aic7xxx_proc_info, \ + proc_info: ahc_linux_proc_info, \ name: NULL, \ - detect: aic7xxx_detect, \ - release: aic7xxx_release, \ - info: aic7xxx_info, \ + detect: ahc_linux_detect, \ + release: ahc_linux_release, \ + info: ahc_linux_info, \ command: NULL, \ - queuecommand: aic7xxx_queue, \ + queuecommand: ahc_linux_queue, \ eh_strategy_handler: NULL, \ - eh_abort_handler: aic7xxx_abort, \ - eh_device_reset_handler: aic7xxx_dev_reset, \ - eh_bus_reset_handler: aic7xxx_bus_reset, \ + eh_abort_handler: ahc_linux_abort, \ + eh_device_reset_handler: ahc_linux_dev_reset, \ + eh_bus_reset_handler: ahc_linux_bus_reset, \ eh_host_reset_handler: NULL, \ abort: NULL, \ reset: NULL, \ slave_attach: NULL, \ bios_param: AIC7XXX_BIOSPARAM, \ - can_queue: 254, /* max simultaneous cmds */\ + can_queue: 253, /* max simultaneous cmds */\ this_id: -1, /* scsi id of host adapter */\ sg_tablesize: 0, /* max scatter-gather cmds */\ cmd_per_lun: 2, /* cmds per lun */\ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c linux.ac/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c --- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c Tue Apr 3 17:32:19 2001 +++ linux.ac/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c Thu Apr 12 17:50:46 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c#15 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c#17 $ */ #include "aic7xxx_osm.h" @@ -57,7 +57,7 @@ { 0 } }; -static struct pci_driver aic7xxx_pci_driver = { +struct pci_driver aic7xxx_pci_driver = { name: "aic7xxx", probe: ahc_linux_pci_dev_probe, remove: ahc_linux_pci_dev_remove, @@ -133,7 +133,7 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pdev->driver_data = ahc; if (aic7xxx_detect_complete) - aic7xxx_register_host(ahc, aic7xxx_driver_template); + ahc_linux_register_host(ahc, aic7xxx_driver_template); #endif return (0); } @@ -191,11 +191,9 @@ { uint32_t command; u_long base; -#ifdef MMAPIO u_long start; u_long base_page; u_long base_offset; -#endif uint8_t *maddr; command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 4); @@ -306,11 +304,47 @@ int error; ahc->platform_data->irq = ahc->dev_softc->irq; - error = request_irq(ahc->platform_data->irq, aic7xxx_isr, - SA_INTERRUPT|SA_SHIRQ, "aic7xxx", ahc); - if (error < 0) - error = request_irq(ahc->platform_data->irq, aic7xxx_isr, - SA_SHIRQ, "aic7xxx", ahc); + error = request_irq(ahc->platform_data->irq, ahc_linux_isr, + SA_SHIRQ, "aic7xxx", ahc); return (-error); +} + +void +ahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pci_set_power_state(ahc->dev_softc, new_state); +#else + uint32_t cap; + u_int cap_offset; + + /* + * Traverse the capability list looking for + * the power management capability. + */ + cap = 0; + cap_offset = ahc_pci_read_config(ahc->dev_softc, + PCIR_CAP_PTR, /*bytes*/1); + while (cap_offset != 0) { + + cap = ahc_pci_read_config(ahc->dev_softc, + cap_offset, /*bytes*/4); + if ((cap & 0xFF) == 1 + && ((cap >> 16) & 0x3) > 0) { + uint32_t pm_control; + + pm_control = ahc_pci_read_config(ahc->dev_softc, + cap_offset + 4, + /*bytes*/4); + pm_control &= ~0x3; + pm_control |= new_state; + ahc_pci_write_config(ahc->dev_softc, + cap_offset + 4, + pm_control, /*bytes*/2); + break; + } + cap_offset = (cap >> 8) & 0xFF; + } +#endif } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_osm.h linux.ac/drivers/scsi/aic7xxx/aic7xxx_osm.h --- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_osm.h Tue Apr 3 17:32:19 2001 +++ linux.ac/drivers/scsi/aic7xxx/aic7xxx_osm.h Thu Apr 12 17:50:47 2001 @@ -18,7 +18,7 @@ * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#45 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#55 $ * * Copyright (c) 2000, 2001 Adaptec Inc. * All rights reserved. @@ -47,7 +47,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#45 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#55 $ * */ #ifndef _AIC7XXX_LINUX_H_ @@ -353,11 +353,7 @@ #include <linux/smp.h> #endif -#define AIC7XXX_DRIVER_VERSION "6.1.5" - -#ifndef LINUX_VERSION_CODE -#include <linux/version.h> -#endif +#define AIC7XXX_DRIVER_VERSION "6.1.11" #ifndef KERNEL_VERSION #define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) @@ -405,7 +401,9 @@ AHC_DEV_UNCONFIGURED = 0x01, AHC_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ AHC_DEV_TIMER_ACTIVE = 0x04, /* Our timer is active */ - AHC_DEV_ON_RUN_LIST = 0x08 /* Queued to be run later */ + AHC_DEV_ON_RUN_LIST = 0x08, /* Queued to be run later */ + AHC_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */ + AHC_DEV_Q_TAGGED = 0x20 /* Allow full SCSI2 command queueing */ } ahc_dev_flags; struct ahc_linux_target; @@ -438,7 +436,7 @@ /* * Cumulative command counter. */ - u_int num_commands; + u_long commands_issued; /* * The number of tagged transactions when @@ -469,8 +467,16 @@ * on devices with a fixed number of tags. */ u_int last_queuefull_same_count; - #define AHC_LOCK_TAGS_COUNT 50 + + /* + * How many transactions have been queued + * without the device going idle. We use + * this statistic to + */ + u_int commands_since_idle_or_otag; +#define AHC_OTAG_THRESH 250 + int lun; struct ahc_linux_target *target; }; @@ -574,9 +580,6 @@ #endif #define mb() \ __asm__ __volatile__("mb": : :"memory") -#elif defined(__sparc__) -#define MMAPIO -/* The default mb() define does what this driver wants. -DaveM */ #endif static __inline uint8_t ahc_inb(struct ahc_softc * ahc, long port); @@ -648,8 +651,8 @@ } /**************************** Initialization **********************************/ -int aic7xxx_register_host(struct ahc_softc *ahc, - Scsi_Host_Template *template); +int ahc_linux_register_host(struct ahc_softc *, + Scsi_Host_Template *); /*************************** Pretty Printing **********************************/ struct info_str { @@ -788,11 +791,24 @@ #define PCIR_SUBVEND_0 0x2c #define PCIR_SUBDEV_0 0x2e +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +extern struct pci_driver aic7xxx_pci_driver; +#endif + +typedef enum +{ + AHC_POWER_STATE_D0, + AHC_POWER_STATE_D1, + AHC_POWER_STATE_D2, + AHC_POWER_STATE_D3 +} ahc_power_state; + +void ahc_power_state_change(struct ahc_softc *ahc, + ahc_power_state new_state); /**************************** VL/EISA Routines ********************************/ int aic7770_linux_probe(Scsi_Host_Template *); int aic7770_map_registers(struct ahc_softc *ahc); -int aic7770_map_int(struct ahc_softc *ahc, - u_int irq, int shared); +int aic7770_map_int(struct ahc_softc *ahc, u_int irq); /******************************* PCI Routines *********************************/ /* @@ -1051,16 +1067,16 @@ } void ahc_platform_set_tags(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, int enable); + struct ahc_devinfo *devinfo, ahc_queue_alg); int ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, char channel, int lun, u_int tag, role_t role, uint32_t status); -void aic7xxx_isr(int irq, void *dev_id, struct pt_regs * regs); +void ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs); void ahc_platform_flushwork(struct ahc_softc *ahc); int ahc_softc_comp(struct ahc_softc *, struct ahc_softc *); void ahc_done(struct ahc_softc*, struct scb*); void ahc_send_async(struct ahc_softc *, char channel, - u_int target, u_int lun, ac_code); + u_int target, u_int lun, ac_code, void *); void ahc_print_path(struct ahc_softc *, struct scb *); void ahc_platform_dump_card_state(struct ahc_softc *ahc); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_pci.c linux.ac/drivers/scsi/aic7xxx/aic7xxx_pci.c --- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_pci.c Tue Apr 3 17:32:19 2001 +++ linux.ac/drivers/scsi/aic7xxx/aic7xxx_pci.c Thu Apr 12 17:50:47 2001 @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx_pci.c#17 $ + * $Id: //depot/src/aic7xxx/aic7xxx_pci.c#23 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_pci.c,v 1.6 2000/11/10 20:13:41 gibbs Exp $ */ @@ -644,16 +644,6 @@ #define CACHESIZE 0x0000003ful /* only 5 bits */ #define LATTIME 0x0000ff00ul -typedef enum -{ - AHC_POWER_STATE_D0, - AHC_POWER_STATE_D1, - AHC_POWER_STATE_D2, - AHC_POWER_STATE_D3 -} ahc_power_state; - -static void ahc_power_state_change(struct ahc_softc *ahc, - ahc_power_state new_state); static int ahc_ext_scbram_present(struct ahc_softc *ahc); static void ahc_scbram_config(struct ahc_softc *ahc, int enable, int pcheck, int fast, int large); @@ -761,9 +751,11 @@ if (error != 0) return (error); + ahc->bus_intr = ahc_pci_intr; + /* Remeber how the card was setup in case there is no SEEPROM */ if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) { - pause_sequencer(ahc); + ahc_pause(ahc); if ((ahc->features & AHC_ULTRA2) != 0) our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID; else @@ -794,9 +786,6 @@ |TARGCRCENDEN); } - error = ahc_pci_map_int(ahc); - if (error != 0) - return (error); dscommand0 = ahc_inb(ahc, DSCOMMAND0); dscommand0 |= MPARCKEN|CACHETHEN; if ((ahc->features & AHC_ULTRA2) != 0) { @@ -903,42 +892,16 @@ */ ahc_softc_insert(ahc); - return (0); -} - -static void -ahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state) -{ - uint32_t cap; - u_int cap_offset; - /* - * Traverse the capability list looking for - * the power management capability. + * Allow interrupts now that we are completely setup. */ - cap = 0; - cap_offset = ahc_pci_read_config(ahc->dev_softc, - PCIR_CAP_PTR, /*bytes*/1); - while (cap_offset != 0) { - - cap = ahc_pci_read_config(ahc->dev_softc, - cap_offset, /*bytes*/4); - if ((cap & 0xFF) == 1 - && ((cap >> 16) & 0x3) > 0) { - uint32_t pm_control; - - pm_control = ahc_pci_read_config(ahc->dev_softc, - cap_offset + 4, - /*bytes*/4); - pm_control &= ~0x3; - pm_control |= new_state; - ahc_pci_write_config(ahc->dev_softc, - cap_offset + 4, - pm_control, /*bytes*/2); - break; - } - cap_offset = (cap >> 8) & 0xFF; - } + error = ahc_pci_map_int(ahc); + if (error != 0) + return (error); + + ahc_intr_enable(ahc, TRUE); + + return (0); } /* @@ -1190,32 +1153,37 @@ } sd.sd_chip = C56_66; } + release_seeprom(&sd); } -#if 0 if (!have_seeprom) { /* * Pull scratch ram settings and treat them as * if they are the contents of an seeprom if * the 'ADPT' signature is found in SCB2. + * We manually compose the data as 16bit values + * to avoid endian issues. */ ahc_outb(ahc, SCBPTR, 2); if (ahc_inb(ahc, SCB_BASE) == 'A' && ahc_inb(ahc, SCB_BASE + 1) == 'D' && ahc_inb(ahc, SCB_BASE + 2) == 'P' && ahc_inb(ahc, SCB_BASE + 3) == 'T') { - uint8_t *sc_bytes; + uint16_t *sc_data; int i; - sc_bytes = (uint8_t *)≻ - for (i = 0; i < 64; i++) - sc_bytes[i] = ahc_inb(ahc, TARG_SCSIRATE + i); - /* Byte 0x1c is stored in byte 4 of SCB2 */ - sc_bytes[0x1c] = ahc_inb(ahc, SCB_BASE + 4); + sc_data = (uint16_t *)≻ + for (i = 0; i < 32; i++) { + uint16_t val; + int j; + + j = i * 2; + val = ahc_inb(ahc, SRAM_BASE + j) + | ahc_inb(ahc, SRAM_BASE + j + 1) << 8; + } have_seeprom = verify_cksum(&sc); } } -#endif if (!have_seeprom) { if (bootverbose) @@ -1301,9 +1269,8 @@ if (sc.adapter_control & CFRESETB) scsi_conf |= RESET_SCSI; - if ((sc.adapter_control & CFCHNLBPRIMARY) != 0 - && (ahc->features & AHC_MULTI_FUNC) != 0) - ahc->flags |= AHC_CHANNEL_B_PRIMARY; + ahc->flags |= + (sc.adapter_control & CFBOOTCHAN) >> CFBOOTCHANSHIFT; if (sc.bios_control & CFEXTEND) ahc->flags |= AHC_EXTENDED_TRANS_A; @@ -1318,7 +1285,8 @@ ultraenb = 0; } - if (sc.signature == CFSIGNATURE) { + if (sc.signature == CFSIGNATURE + || sc.signature == CFSIGNATURE2) { uint32_t devconfig; /* Honor the STPWLEVEL settings */ @@ -1362,10 +1330,11 @@ have_autoterm = FALSE; } - if (have_autoterm) + if (have_autoterm) { + acquire_seeprom(ahc, &sd); configure_termination(ahc, &sd, adapter_control, sxfrctl1); - - release_seeprom(&sd); + release_seeprom(&sd); + } } static void @@ -1806,7 +1775,7 @@ ahc_outb(ahc, CLRINT, CLRPARERR); } - unpause_sequencer(ahc); + ahc_unpause(ahc); } static int diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_proc.c linux.ac/drivers/scsi/aic7xxx/aic7xxx_proc.c --- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_proc.c Tue Apr 3 17:32:19 2001 +++ linux.ac/drivers/scsi/aic7xxx/aic7xxx_proc.c Thu Apr 12 17:50:47 2001 @@ -29,7 +29,7 @@ * String handling code courtesy of Gerard Roudier's <groudier@club-internet.fr> * sym driver. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#7 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#10 $ */ #include "aic7xxx_osm.h" #include "aic7xxx_inline.h" @@ -174,7 +174,7 @@ { struct ahc_linux_target *targ; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; int lun; tinfo = ahc_fetch_transinfo(ahc, channel, our_id, @@ -210,7 +210,7 @@ copy_info(info, "\tChannel %c Target %d Lun %d Settings\n", dev->target->channel + 'A', dev->target->target, dev->lun); - copy_info(info, "\t\tCommands Queued %d\n", dev->num_commands); + copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued); copy_info(info, "\t\tCommands Active %d\n", dev->active); copy_info(info, "\t\tCommand Openings %d\n", dev->openings); copy_info(info, "\t\tMax Tagged Openings %d\n", dev->maxtags); @@ -221,7 +221,7 @@ * Return information to handle /proc support for the driver. */ int -aic7xxx_proc_info(char *buffer, char **start, off_t offset, +ahc_linux_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) { struct ahc_softc *ahc; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_reg.h linux.ac/drivers/scsi/aic7xxx/aic7xxx_reg.h --- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_reg.h Tue Apr 3 17:32:19 2001 +++ linux.ac/drivers/scsi/aic7xxx/aic7xxx_reg.h Thu Apr 12 17:50:47 2001 @@ -86,8 +86,8 @@ #define SELDO 0x40 #define SELDI 0x20 #define SELINGO 0x10 -#define IOERR 0x08 #define SWRAP 0x08 +#define IOERR 0x08 #define SDONE 0x04 #define SPIORDY 0x02 #define DMADONE 0x01 @@ -191,8 +191,8 @@ #define BRDDAT5 0x20 #define BRDDAT4 0x10 #define BRDSTB 0x10 -#define BRDCS 0x08 #define BRDDAT3 0x08 +#define BRDCS 0x08 #define BRDDAT2 0x04 #define BRDRW 0x04 #define BRDRW_ULTRA2 0x02 @@ -242,8 +242,8 @@ #define PRELOADEN 0x80 #define WIDEODD 0x40 #define SCSIEN 0x20 -#define SDMAENACK 0x10 #define SDMAEN 0x10 +#define SDMAENACK 0x10 #define HDMAEN 0x08 #define HDMAENACK 0x08 #define DIRECTION 0x04 @@ -271,8 +271,8 @@ #define P_MESGOUT 0xa0 #define P_COMMAND 0x80 #define CDI 0x80 -#define IOI 0x40 #define P_DATAIN 0x40 +#define IOI 0x40 #define MSGI 0x20 #define P_BUSFREE 0x01 #define P_DATAOUT 0x00 @@ -314,9 +314,7 @@ #define LAST_MSG 0x53 -#define TARGET_MSG_REQUEST 0x54 - -#define SCSISEQ_TEMPLATE 0x56 +#define SCSISEQ_TEMPLATE 0x54 #define ENSELO 0x40 #define ENSELI 0x20 #define ENRSELI 0x10 @@ -324,11 +322,11 @@ #define ENAUTOATNI 0x04 #define ENAUTOATNP 0x02 -#define DATA_COUNT_ODD 0x57 +#define DATA_COUNT_ODD 0x55 -#define INITIATOR_TAG 0x58 +#define INITIATOR_TAG 0x56 -#define SEQ_FLAGS2 0x59 +#define SEQ_FLAGS2 0x57 #define SCB_DMA 0x01 #define SCSICONF 0x5a @@ -345,8 +343,8 @@ #define HOSTCONF 0x5d #define HA_274_BIOSCTRL 0x5f -#define BIOSMODE 0x30 #define BIOSDISABLED 0x30 +#define BIOSMODE 0x30 #define CHANNEL_B_PRIMARY 0x08 #define SEQCTL 0x60 @@ -483,7 +481,8 @@ #define DFSTATUS 0x94 #define PRELOAD_AVAIL 0x80 -#define DWORDEMP 0x20 +#define DFCACHETH 0x40 +#define FIFOQWDEMP 0x20 #define MREQPEND 0x10 #define HDONE 0x08 #define DFTHRESH 0x04 @@ -527,12 +526,12 @@ #define SFUNCT 0x9f #define ALT_MODE 0x80 +#define SCB_BASE 0xa0 + #define SCB_CDB_PTR 0xa0 +#define SCB_RESIDUAL_DATACNT 0xa0 #define SCB_CDB_STORE 0xa0 #define SCB_TARGET_INFO 0xa0 -#define SCB_RESIDUAL_DATACNT 0xa0 - -#define SCB_BASE 0xa0 #define SCB_RESIDUAL_SGPTR 0xa4 @@ -579,13 +578,13 @@ #define SCB_NEXT 0xbf +#define SCB_64_SPARE 0xc0 + #define SEECTL_2840 0xc0 #define CS_2840 0x04 #define CK_2840 0x02 #define DO_2840 0x01 -#define SCB_64_SPARE 0xc0 - #define STATUS_2840 0xc1 #define EEPROM_TF 0x80 #define BIOS_SEL 0x60 @@ -648,8 +647,8 @@ #define WR_DFTHRSH_63 0x30 #define WR_DFTHRSH_50 0x20 #define WR_DFTHRSH_25 0x10 -#define RD_DFTHRSH_MAX 0x07 #define RD_DFTHRSH 0x07 +#define RD_DFTHRSH_MAX 0x07 #define RD_DFTHRSH_90 0x06 #define RD_DFTHRSH_85 0x05 #define RD_DFTHRSH_75 0x04 @@ -668,39 +667,39 @@ #define SG_CACHE_PRE 0xfc -#define CMD_GROUP_CODE_SHIFT 0x05 +#define SCB_INITIATOR_TAG 0x03 +#define SCB_TARGET_DATA_DIR 0x01 +#define SCB_TARGET_PHASES 0x00 +#define MAX_OFFSET_ULTRA2 0x7f +#define MAX_OFFSET_16BIT 0x08 #define BUS_8_BIT 0x00 -#define CCSGRAM_MAXSEGS 0x10 -#define TARGET_DATA_IN 0x01 +#define TARGET_CMD_CMPLT 0xfe #define STATUS_QUEUE_FULL 0x28 #define STATUS_BUSY 0x08 #define MAX_OFFSET_8BIT 0x0f -#define BUS_16_BIT 0x01 +#define BUS_32_BIT 0x02 +#define CCSGADDR_MAX 0x80 #define TID_SHIFT 0x04 #define SCB_DOWNLOAD_SIZE_64 0x30 -#define SCB_UPLOAD_SIZE 0x20 #define HOST_MAILBOX_SHIFT 0x04 -#define SCB_INITIATOR_TAG 0x03 #define SCB_TARGET_STATUS 0x02 -#define SCB_TARGET_DATA_DIR 0x01 -#define SCB_TARGET_PHASES 0x00 -#define MAX_OFFSET_ULTRA2 0x7f -#define MAX_OFFSET_16BIT 0x08 -#define TARGET_CMD_CMPLT 0xfe +#define CMD_GROUP_CODE_SHIFT 0x05 +#define CCSGRAM_MAXSEGS 0x10 #define SCB_LIST_NULL 0xff #define SG_SIZEOF 0x08 #define SCB_DOWNLOAD_SIZE 0x20 #define SEQ_MAILBOX_SHIFT 0x00 +#define TARGET_DATA_IN 0x01 #define HOST_MSG 0xff -#define BUS_32_BIT 0x02 -#define CCSGADDR_MAX 0x80 +#define BUS_16_BIT 0x01 +#define SCB_UPLOAD_SIZE 0x20 /* Downloaded Constant Definitions */ +#define INVERTED_CACHESIZE_MASK 0x03 #define SG_PREFETCH_ADDR_MASK 0x06 #define SG_PREFETCH_ALIGN_MASK 0x05 #define QOUTFIFO_OFFSET 0x00 #define SG_PREFETCH_CNT 0x04 -#define INVERTED_CACHESIZE_MASK 0x03 #define CACHESIZE_MASK 0x02 #define QINFIFO_OFFSET 0x01 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_seq.h linux.ac/drivers/scsi/aic7xxx/aic7xxx_seq.h --- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_seq.h Tue Apr 3 17:32:19 2001 +++ linux.ac/drivers/scsi/aic7xxx/aic7xxx_seq.h Thu Apr 12 17:50:47 2001 @@ -4,7 +4,7 @@ static uint8_t seqprog[] = { 0xb2, 0x00, 0x00, 0x08, 0xf7, 0x11, 0x22, 0x08, - 0x00, 0x65, 0xde, 0x59, + 0x00, 0x65, 0xe4, 0x59, 0xf7, 0x01, 0x02, 0x08, 0xff, 0x6a, 0x24, 0x08, 0x40, 0x00, 0x40, 0x68, @@ -17,21 +17,21 @@ 0x01, 0x4d, 0xc8, 0x30, 0x00, 0x4c, 0x12, 0x70, 0x01, 0x39, 0xa2, 0x30, - 0x00, 0x6a, 0x7e, 0x5e, + 0x00, 0x6a, 0x76, 0x5e, 0x01, 0x51, 0x20, 0x31, - 0x01, 0x59, 0xb2, 0x00, + 0x01, 0x57, 0xae, 0x00, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x51, 0xda, 0x5d, + 0x00, 0x51, 0xd0, 0x5d, 0x01, 0x51, 0xc8, 0x30, 0x00, 0x39, 0xde, 0x60, 0x00, 0xbb, 0x30, 0x70, - 0xc1, 0x6a, 0x96, 0x5e, + 0xc1, 0x6a, 0x8e, 0x5e, 0x01, 0xbf, 0x72, 0x30, 0x01, 0x40, 0x7e, 0x31, 0x01, 0x90, 0x80, 0x30, 0x01, 0xf6, 0xd4, 0x30, 0x01, 0x4d, 0x9a, 0x18, - 0xfe, 0x59, 0xb2, 0x08, + 0xfe, 0x57, 0xae, 0x08, 0x01, 0x40, 0x20, 0x31, 0x00, 0x65, 0xe2, 0x58, 0x60, 0x0b, 0x40, 0x78, @@ -48,10 +48,10 @@ 0x08, 0x3c, 0x78, 0x00, 0x01, 0x50, 0xc8, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xc4, 0x5d, + 0x48, 0x6a, 0xba, 0x5d, 0x01, 0x6a, 0xdc, 0x01, 0x88, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xc4, 0x5d, + 0x48, 0x6a, 0xba, 0x5d, 0x01, 0x6a, 0x26, 0x01, 0xf0, 0x19, 0x7a, 0x08, 0x0f, 0x18, 0xc8, 0x08, @@ -62,7 +62,7 @@ 0x80, 0x3d, 0x7a, 0x00, 0x01, 0x3d, 0xd8, 0x31, 0x01, 0x3d, 0x32, 0x31, - 0x10, 0x03, 0x56, 0x79, + 0x10, 0x03, 0x5c, 0x79, 0x00, 0x65, 0x0a, 0x59, 0x80, 0x66, 0xa8, 0x78, 0x01, 0x66, 0xd8, 0x31, @@ -77,33 +77,33 @@ 0x00, 0x65, 0xb0, 0x48, 0x01, 0x66, 0xd8, 0x31, 0x01, 0x66, 0x32, 0x31, - 0x10, 0x03, 0x56, 0x79, + 0x10, 0x03, 0x5c, 0x79, 0x00, 0x65, 0x0a, 0x59, 0x01, 0x66, 0xd8, 0x31, 0x01, 0x66, 0x32, 0x31, - 0x01, 0x66, 0xb0, 0x30, + 0x01, 0x66, 0xac, 0x30, 0x40, 0x3c, 0x78, 0x00, 0x10, 0x03, 0xa6, 0x78, 0x00, 0x65, 0x0a, 0x59, 0x00, 0x65, 0xb0, 0x40, - 0x61, 0x6a, 0x96, 0x5e, - 0x08, 0x51, 0x2e, 0x71, + 0x61, 0x6a, 0x8e, 0x5e, + 0x08, 0x51, 0x34, 0x71, 0x02, 0x0b, 0xac, 0x78, 0x00, 0x65, 0xa8, 0x40, 0x80, 0x86, 0xc8, 0x08, 0x01, 0x4f, 0xc8, 0x30, 0x00, 0x50, 0xc2, 0x60, - 0xc4, 0x6a, 0x32, 0x5d, + 0xc4, 0x6a, 0x28, 0x5d, 0x40, 0x3c, 0xbe, 0x78, - 0x28, 0x6a, 0x48, 0x5d, - 0x00, 0x65, 0x54, 0x41, - 0x08, 0x6a, 0x48, 0x5d, - 0x00, 0x65, 0x54, 0x41, + 0x28, 0x6a, 0x3e, 0x5d, + 0x00, 0x65, 0x5a, 0x41, + 0x08, 0x6a, 0x3e, 0x5d, + 0x00, 0x65, 0x5a, 0x41, 0xff, 0x6a, 0xd8, 0x01, 0xff, 0x6a, 0x32, 0x01, 0x90, 0x3c, 0x78, 0x00, - 0x10, 0x03, 0x4a, 0x69, - 0x00, 0x65, 0x2e, 0x41, + 0x10, 0x03, 0x50, 0x69, + 0x00, 0x65, 0x34, 0x41, 0x1a, 0x01, 0x02, 0x00, 0xf0, 0x19, 0x7a, 0x08, 0x0f, 0x0f, 0xc8, 0x08, @@ -112,8 +112,8 @@ 0x08, 0x1f, 0xda, 0x78, 0x80, 0x3d, 0x7a, 0x00, 0x20, 0x6a, 0x16, 0x00, - 0x00, 0x65, 0xbe, 0x41, - 0x00, 0x65, 0x76, 0x5e, + 0x00, 0x65, 0xc4, 0x41, + 0x00, 0x65, 0x6e, 0x5e, 0x00, 0x65, 0x12, 0x40, 0x20, 0x11, 0xe8, 0x68, 0x20, 0x6a, 0x18, 0x00, @@ -125,11 +125,11 @@ 0x01, 0xb9, 0x1e, 0x30, 0x7f, 0xb9, 0x0a, 0x08, 0x01, 0xb9, 0x0a, 0x30, - 0x01, 0x56, 0xca, 0x30, + 0x01, 0x54, 0xca, 0x30, 0x80, 0xb8, 0xfc, 0x78, 0x80, 0x65, 0xca, 0x00, 0x01, 0x65, 0x00, 0x34, - 0x01, 0x56, 0x00, 0x34, + 0x01, 0x54, 0x00, 0x34, 0x1a, 0x01, 0x02, 0x00, 0x08, 0xb8, 0x06, 0x79, 0x20, 0x01, 0x02, 0x00, @@ -146,40 +146,43 @@ 0x01, 0xb9, 0x7a, 0x30, 0x01, 0xba, 0x7c, 0x30, 0x00, 0x65, 0x00, 0x59, - 0x80, 0x0b, 0xba, 0x79, - 0xe4, 0x6a, 0x32, 0x5d, - 0x80, 0xba, 0x48, 0x5d, + 0x80, 0x0b, 0xc0, 0x79, + 0xe4, 0x6a, 0x28, 0x5d, + 0x80, 0xba, 0x3e, 0x5d, 0x20, 0xb8, 0x2c, 0x79, - 0x20, 0x6a, 0x48, 0x5d, - 0x00, 0xa3, 0x48, 0x5d, + 0x20, 0x6a, 0x3e, 0x5d, + 0x00, 0xa3, 0x3e, 0x5d, 0x01, 0xa0, 0x78, 0x30, - 0x10, 0x03, 0x46, 0x69, - 0x08, 0x3c, 0x62, 0x69, - 0x04, 0x3c, 0x88, 0x69, - 0x02, 0x3c, 0x8e, 0x69, - 0x01, 0x3c, 0x4c, 0x79, - 0x00, 0x6a, 0x7e, 0x5e, + 0x10, 0xb8, 0x34, 0x79, + 0xe4, 0x6a, 0x28, 0x5d, + 0x00, 0x65, 0xa8, 0x40, + 0x10, 0x03, 0x4c, 0x69, + 0x08, 0x3c, 0x68, 0x69, + 0x04, 0x3c, 0x8e, 0x69, + 0x02, 0x3c, 0x94, 0x69, + 0x01, 0x3c, 0x52, 0x79, 0x01, 0x6a, 0xa2, 0x30, - 0x00, 0x65, 0x9a, 0x59, - 0x04, 0x51, 0x3e, 0x61, + 0x00, 0x65, 0xa0, 0x59, + 0x04, 0x51, 0x42, 0x61, + 0x00, 0x6a, 0x76, 0x5e, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0xda, 0x5d, + 0x00, 0xbb, 0xd0, 0x5d, 0x00, 0x65, 0x2c, 0x41, 0xa4, 0x6a, 0x06, 0x00, 0x00, 0x65, 0x0a, 0x59, 0x00, 0x65, 0xa8, 0x40, - 0xe4, 0x6a, 0x32, 0x5d, - 0x20, 0x3c, 0x52, 0x79, - 0x02, 0x6a, 0x48, 0x5d, - 0x04, 0x6a, 0x48, 0x5d, - 0x01, 0x03, 0x54, 0x69, + 0xe4, 0x6a, 0x28, 0x5d, + 0x20, 0x3c, 0x58, 0x79, + 0x02, 0x6a, 0x3e, 0x5d, + 0x04, 0x6a, 0x3e, 0x5d, + 0x01, 0x03, 0x5a, 0x69, 0xf7, 0x11, 0x22, 0x08, 0xff, 0x6a, 0x24, 0x08, 0xff, 0x6a, 0x06, 0x08, 0x01, 0x6a, 0x7e, 0x00, - 0x00, 0x65, 0x9a, 0x59, + 0x00, 0x65, 0xa0, 0x59, 0x00, 0x65, 0x04, 0x40, - 0x84, 0x6a, 0x32, 0x5d, + 0x84, 0x6a, 0x28, 0x5d, 0x00, 0x65, 0x0a, 0x59, 0x01, 0x66, 0xc8, 0x30, 0x01, 0x64, 0xd8, 0x31, @@ -187,60 +190,60 @@ 0x5b, 0x64, 0xc8, 0x28, 0x30, 0x64, 0xca, 0x18, 0x01, 0x6c, 0xc8, 0x30, - 0xff, 0x64, 0x84, 0x79, + 0xff, 0x64, 0x8a, 0x79, 0x08, 0x01, 0x02, 0x00, - 0x02, 0x0b, 0x76, 0x79, - 0x01, 0x64, 0x7c, 0x61, + 0x02, 0x0b, 0x7c, 0x79, + 0x01, 0x64, 0x82, 0x61, 0xf7, 0x01, 0x02, 0x08, 0x01, 0x06, 0xd8, 0x31, 0x01, 0x06, 0x32, 0x31, 0xff, 0x64, 0xc8, 0x18, - 0xff, 0x64, 0x76, 0x69, + 0xff, 0x64, 0x7c, 0x69, 0xf7, 0x3c, 0x78, 0x08, - 0x00, 0x65, 0x2e, 0x41, + 0x00, 0x65, 0x34, 0x41, 0x40, 0xa1, 0x7e, 0x10, - 0x04, 0xa1, 0x32, 0x5d, - 0x00, 0x65, 0x62, 0x42, - 0xc4, 0x6a, 0x32, 0x5d, + 0x04, 0xa1, 0x28, 0x5d, + 0x00, 0x65, 0x68, 0x42, + 0xc4, 0x6a, 0x28, 0x5d, 0xc0, 0x6a, 0x7e, 0x00, - 0x00, 0xa2, 0x48, 0x5d, + 0x00, 0xa2, 0x3e, 0x5d, 0xe4, 0x6a, 0x06, 0x00, - 0x00, 0x6a, 0x48, 0x5d, - 0x00, 0x65, 0x54, 0x41, - 0x10, 0x3c, 0x9e, 0x69, - 0x00, 0xbb, 0x64, 0x44, + 0x00, 0x6a, 0x3e, 0x5d, + 0x00, 0x65, 0x5a, 0x41, + 0x10, 0x3c, 0xa4, 0x69, + 0x00, 0xbb, 0x5a, 0x44, 0x18, 0x6a, 0xda, 0x01, 0x01, 0x69, 0xd8, 0x31, 0x1c, 0x6a, 0xd0, 0x01, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xa6, 0x79, + 0x80, 0xee, 0xac, 0x79, 0xff, 0x6a, 0xdc, 0x09, 0x01, 0x93, 0x26, 0x01, 0x03, 0x6a, 0x2a, 0x01, 0x01, 0x69, 0x32, 0x31, - 0x1c, 0x6a, 0xa8, 0x5d, + 0x1c, 0x6a, 0x9e, 0x5d, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x6c, 0x5e, + 0x00, 0x65, 0x64, 0x5e, 0x01, 0x50, 0xa0, 0x18, 0x02, 0x6a, 0x22, 0x05, 0x80, 0x6a, 0x74, 0x00, 0x80, 0x3c, 0x78, 0x00, - 0x00, 0x65, 0xa0, 0x5d, + 0x00, 0x65, 0x96, 0x5d, 0x01, 0x3f, 0xc8, 0x30, - 0xbf, 0x64, 0x62, 0x7a, - 0x80, 0x64, 0x82, 0x73, - 0xa0, 0x64, 0xd8, 0x73, - 0xc0, 0x64, 0xd0, 0x73, - 0xe0, 0x64, 0x18, 0x74, - 0x01, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0xbe, 0x41, + 0xbf, 0x64, 0x68, 0x7a, + 0x80, 0x64, 0x88, 0x73, + 0xa0, 0x64, 0xde, 0x73, + 0xc0, 0x64, 0xd6, 0x73, + 0xe0, 0x64, 0x0e, 0x74, + 0x01, 0x6a, 0x8e, 0x5e, + 0x00, 0x65, 0xc4, 0x41, 0xf7, 0x11, 0x22, 0x08, 0x01, 0x06, 0xd4, 0x30, 0xff, 0x6a, 0x24, 0x08, 0xf7, 0x01, 0x02, 0x08, - 0x09, 0x0c, 0xd8, 0x79, + 0x09, 0x0c, 0xde, 0x79, 0x08, 0x0c, 0x04, 0x68, - 0xb1, 0x6a, 0x96, 0x5e, + 0xb1, 0x6a, 0x8e, 0x5e, 0xff, 0x6a, 0x26, 0x09, 0x12, 0x01, 0x02, 0x00, 0x02, 0x6a, 0x08, 0x30, @@ -253,47 +256,47 @@ 0x00, 0xa5, 0x4a, 0x21, 0x00, 0xa6, 0x4c, 0x21, 0x00, 0xa7, 0x4e, 0x25, - 0x08, 0xeb, 0x9a, 0x7e, - 0x80, 0xeb, 0xf8, 0x79, + 0x08, 0xeb, 0x92, 0x7e, + 0x80, 0xeb, 0xfe, 0x79, 0xff, 0x6a, 0xd6, 0x09, - 0x08, 0xeb, 0xfc, 0x69, + 0x08, 0xeb, 0x02, 0x6a, 0xff, 0x6a, 0xd4, 0x0c, - 0x88, 0xeb, 0x12, 0x72, - 0x08, 0xeb, 0x9a, 0x6e, - 0x80, 0xa3, 0x9a, 0x6e, - 0x04, 0xea, 0x16, 0xe2, - 0x08, 0xee, 0x9a, 0x6e, + 0x88, 0xeb, 0x18, 0x72, + 0x08, 0xeb, 0x92, 0x6e, + 0x80, 0xa3, 0x92, 0x6e, + 0x04, 0xea, 0x1c, 0xe2, + 0x08, 0xee, 0x92, 0x6e, 0x04, 0x6a, 0xd0, 0x81, 0x05, 0xa4, 0xc0, 0x89, 0x03, 0xa5, 0xc2, 0x31, 0x09, 0x6a, 0xd6, 0x05, - 0x00, 0x65, 0xfa, 0x59, + 0x00, 0x65, 0x00, 0x5a, 0x06, 0xa4, 0xd4, 0x89, - 0x80, 0x94, 0x9a, 0x7e, + 0x80, 0x94, 0x92, 0x7e, 0x04, 0xe9, 0x10, 0x31, 0x01, 0xe9, 0xca, 0x30, - 0x01, 0x65, 0x20, 0x7a, - 0x01, 0x57, 0xae, 0x10, + 0x01, 0x65, 0x26, 0x7a, + 0x01, 0x55, 0xaa, 0x10, 0x01, 0x65, 0x18, 0x31, 0x02, 0xe9, 0x1a, 0x31, 0x01, 0xe9, 0x46, 0x31, - 0x00, 0x65, 0xec, 0x59, + 0x00, 0x65, 0xf2, 0x59, 0x01, 0xa4, 0xca, 0x30, - 0x01, 0x57, 0x2e, 0x7a, + 0x01, 0x55, 0x34, 0x7a, 0x04, 0x65, 0xca, 0x00, - 0x80, 0xa3, 0x32, 0x7a, + 0x80, 0xa3, 0x38, 0x7a, 0x02, 0x65, 0xca, 0x00, 0x01, 0x65, 0xf8, 0x31, - 0x01, 0x3b, 0x26, 0x31, + 0x80, 0x93, 0x26, 0x01, 0xff, 0x6a, 0xd4, 0x0c, 0x01, 0x8c, 0xc8, 0x30, 0x00, 0x88, 0xc8, 0x18, 0x02, 0x64, 0xc8, 0x88, - 0xff, 0x64, 0x9a, 0x7e, - 0xff, 0x8d, 0x48, 0x6a, - 0xff, 0x8e, 0x48, 0x6a, + 0xff, 0x64, 0x92, 0x7e, + 0xff, 0x8d, 0x4e, 0x6a, + 0xff, 0x8e, 0x4e, 0x6a, 0x03, 0x8c, 0xd4, 0x98, - 0x00, 0x65, 0x9a, 0x56, + 0x00, 0x65, 0x92, 0x56, 0x01, 0x64, 0x70, 0x30, 0xff, 0x64, 0xc8, 0x10, 0x01, 0x64, 0xc8, 0x18, @@ -304,139 +307,139 @@ 0x03, 0xa0, 0x18, 0x31, 0x03, 0xa0, 0x10, 0x30, 0x08, 0x6a, 0xcc, 0x00, - 0xa0, 0x6a, 0xbe, 0x5d, - 0x01, 0xa0, 0xae, 0x08, - 0x00, 0x65, 0x88, 0x42, + 0xa0, 0x6a, 0xb4, 0x5d, + 0x01, 0xa0, 0xaa, 0x08, + 0x00, 0x65, 0x8e, 0x42, 0xa8, 0x6a, 0x76, 0x00, 0x79, 0x6a, 0x76, 0x00, - 0x40, 0x3f, 0x6a, 0x6a, + 0x40, 0x3f, 0x70, 0x6a, 0x04, 0x3b, 0x76, 0x00, - 0x00, 0x65, 0x52, 0x5d, + 0x00, 0x65, 0x48, 0x5d, 0x04, 0x6a, 0xd4, 0x81, - 0x20, 0x3c, 0x54, 0x6a, + 0x20, 0x3c, 0x5a, 0x6a, 0x20, 0x3c, 0x78, 0x00, 0x07, 0xac, 0x10, 0x31, 0x05, 0xb3, 0x46, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0xac, 0x6a, 0xb6, 0x5d, + 0xac, 0x6a, 0xac, 0x5d, 0xa3, 0x6a, 0xcc, 0x00, - 0xb3, 0x6a, 0xba, 0x5d, - 0x00, 0x65, 0x38, 0x5a, + 0xb3, 0x6a, 0xb0, 0x5d, + 0x00, 0x65, 0x3e, 0x5a, 0xfd, 0xa4, 0x48, 0x09, - 0x01, 0x8c, 0xae, 0x08, + 0x01, 0x8c, 0xaa, 0x08, 0x03, 0x8c, 0x10, 0x30, - 0x00, 0x65, 0xae, 0x5d, - 0x01, 0xa4, 0x98, 0x7a, + 0x00, 0x65, 0xa4, 0x5d, + 0x01, 0xa4, 0x9e, 0x7a, 0x04, 0x3b, 0x76, 0x08, 0x01, 0x3b, 0x26, 0x31, 0x80, 0x02, 0x04, 0x00, - 0x10, 0x0c, 0x90, 0x7a, + 0x10, 0x0c, 0x96, 0x7a, 0x7f, 0x02, 0x04, 0x08, - 0x91, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0xbe, 0x41, + 0x91, 0x6a, 0x8e, 0x5e, + 0x00, 0x65, 0xc4, 0x41, 0x01, 0xa4, 0xca, 0x30, - 0x80, 0xa3, 0x9e, 0x7a, + 0x80, 0xa3, 0xa4, 0x7a, 0x02, 0x65, 0xca, 0x00, - 0x01, 0x57, 0xa2, 0x7a, + 0x01, 0x55, 0xa8, 0x7a, 0x04, 0x65, 0xca, 0x00, 0x01, 0x65, 0xf8, 0x31, 0x01, 0x3b, 0x26, 0x31, - 0x00, 0x65, 0x00, 0x5a, - 0x01, 0xfc, 0xae, 0x6a, - 0x80, 0x0b, 0xa6, 0x6a, - 0x10, 0x0c, 0xa6, 0x7a, - 0x04, 0x93, 0xc0, 0x6a, + 0x00, 0x65, 0x06, 0x5a, + 0x01, 0xfc, 0xb4, 0x6a, + 0x80, 0x0b, 0xac, 0x6a, + 0x10, 0x0c, 0xac, 0x7a, + 0x04, 0x93, 0xc6, 0x6a, 0xdf, 0x93, 0x26, 0x09, - 0x20, 0x93, 0xb2, 0x6a, + 0x20, 0x93, 0xb8, 0x6a, 0x02, 0x93, 0x26, 0x01, - 0x01, 0x94, 0xb4, 0x7a, - 0x01, 0x94, 0xb4, 0x7a, - 0x01, 0x94, 0xb4, 0x7a, - 0x01, 0x94, 0xb4, 0x7a, - 0x01, 0x94, 0xb4, 0x7a, - 0x10, 0x94, 0xc0, 0x6a, + 0x01, 0x94, 0xba, 0x7a, + 0x01, 0x94, 0xba, 0x7a, + 0x01, 0x94, 0xba, 0x7a, + 0x01, 0x94, 0xba, 0x7a, + 0x01, 0x94, 0xba, 0x7a, + 0x10, 0x94, 0xc6, 0x6a, 0xd7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0xc4, 0x6a, - 0x02, 0xfc, 0xce, 0x7a, - 0x01, 0xfc, 0x4e, 0x7b, + 0x28, 0x93, 0xca, 0x6a, + 0x02, 0xfc, 0xd4, 0x7a, + 0x01, 0xfc, 0x54, 0x7b, 0x01, 0xa4, 0x48, 0x01, - 0x00, 0x65, 0x4e, 0x43, - 0x40, 0x0d, 0xd4, 0x6a, - 0x00, 0x65, 0x00, 0x5a, - 0x00, 0x65, 0xc6, 0x42, - 0x80, 0xfc, 0xde, 0x7a, - 0x80, 0xa4, 0xde, 0x6a, + 0x00, 0x65, 0x54, 0x43, + 0x40, 0x0d, 0xda, 0x6a, + 0x00, 0x65, 0x06, 0x5a, + 0x00, 0x65, 0xcc, 0x42, + 0x80, 0xfc, 0xe4, 0x7a, + 0x80, 0xa4, 0xe4, 0x6a, 0xff, 0xa5, 0x4a, 0x19, 0xff, 0xa6, 0x4c, 0x21, 0xff, 0xa7, 0x4e, 0x21, 0xf8, 0xfc, 0x48, 0x09, - 0xff, 0x6a, 0xae, 0x08, - 0x04, 0xfc, 0xe6, 0x7a, - 0x01, 0x57, 0xae, 0x00, + 0xff, 0x6a, 0xaa, 0x08, + 0x04, 0xfc, 0xec, 0x7a, + 0x01, 0x55, 0xaa, 0x00, 0xff, 0x6a, 0x46, 0x09, - 0xff, 0x38, 0xf2, 0x6a, - 0x80, 0xa3, 0xf2, 0x7a, - 0x80, 0x0b, 0xf0, 0x7a, - 0x04, 0x3b, 0xf2, 0x7a, + 0xff, 0x38, 0xf8, 0x6a, + 0x80, 0xa3, 0xf8, 0x7a, + 0x80, 0x0b, 0xf6, 0x7a, + 0x04, 0x3b, 0xf8, 0x7a, 0xbf, 0x3b, 0x76, 0x08, 0x01, 0x3b, 0x26, 0x31, - 0x00, 0x65, 0x00, 0x5a, - 0x01, 0x0b, 0x00, 0x6b, - 0x10, 0x0c, 0xf4, 0x7a, - 0x04, 0x93, 0xfe, 0x6a, - 0x01, 0x94, 0xfc, 0x7a, - 0x10, 0x94, 0xfe, 0x6a, + 0x00, 0x65, 0x06, 0x5a, + 0x01, 0x0b, 0x06, 0x6b, + 0x10, 0x0c, 0xfa, 0x7a, + 0x04, 0x93, 0x04, 0x6b, + 0x01, 0x94, 0x02, 0x7b, + 0x10, 0x94, 0x04, 0x6b, 0xc7, 0x93, 0x26, 0x09, 0x01, 0x99, 0xd4, 0x30, - 0x38, 0x93, 0x02, 0x6b, - 0xff, 0x08, 0x4e, 0x6b, - 0xff, 0x09, 0x4e, 0x6b, - 0xff, 0x0a, 0x4e, 0x6b, - 0xff, 0x38, 0x1e, 0x7b, + 0x38, 0x93, 0x08, 0x6b, + 0xff, 0x08, 0x54, 0x6b, + 0xff, 0x09, 0x54, 0x6b, + 0xff, 0x0a, 0x54, 0x6b, + 0xff, 0x38, 0x24, 0x7b, 0x04, 0x14, 0x10, 0x31, 0x01, 0x38, 0x18, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xbc, 0x5d, - 0x00, 0x38, 0xa8, 0x5d, + 0x14, 0x6a, 0xb2, 0x5d, + 0x00, 0x38, 0x9e, 0x5d, 0xff, 0x6a, 0x70, 0x08, - 0x00, 0x65, 0x44, 0x43, - 0x80, 0xa3, 0x24, 0x7b, + 0x00, 0x65, 0x4a, 0x43, + 0x80, 0xa3, 0x2a, 0x7b, 0x01, 0xa4, 0x48, 0x01, - 0x00, 0x65, 0x4e, 0x43, - 0x08, 0xeb, 0x2a, 0x7b, - 0x00, 0x65, 0x00, 0x5a, - 0x08, 0xeb, 0x26, 0x6b, + 0x00, 0x65, 0x54, 0x43, + 0x08, 0xeb, 0x30, 0x7b, + 0x00, 0x65, 0x06, 0x5a, + 0x08, 0xeb, 0x2c, 0x6b, 0x07, 0xe9, 0x10, 0x31, - 0x80, 0xe9, 0x30, 0x7b, + 0x80, 0xe9, 0x36, 0x7b, 0x80, 0xa3, 0x46, 0x01, 0x88, 0x6a, 0xcc, 0x00, - 0xa4, 0x6a, 0xbc, 0x5d, - 0x08, 0x6a, 0xa8, 0x5d, + 0xa4, 0x6a, 0xb2, 0x5d, + 0x08, 0x6a, 0x9e, 0x5d, 0x0d, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x6c, 0x5e, + 0x00, 0x65, 0x64, 0x5e, 0x88, 0x6a, 0xcc, 0x00, - 0x00, 0x65, 0x4e, 0x5e, + 0x00, 0x65, 0x46, 0x5e, 0x01, 0x99, 0x46, 0x31, - 0x00, 0x65, 0x38, 0x5a, - 0x00, 0x65, 0xec, 0x59, + 0x00, 0x65, 0x3e, 0x5a, + 0x00, 0x65, 0xf2, 0x59, 0x03, 0x8c, 0x10, 0x30, - 0x00, 0x65, 0xae, 0x5d, - 0x01, 0x8c, 0x4c, 0x7b, - 0x01, 0x57, 0xae, 0x10, - 0x80, 0x0b, 0x88, 0x6a, - 0x80, 0x0b, 0x54, 0x6b, - 0x01, 0x0c, 0x50, 0x7b, - 0x10, 0x0c, 0x88, 0x7a, - 0x00, 0x65, 0xf6, 0x59, - 0xff, 0x38, 0x66, 0x7b, + 0x00, 0x65, 0xa4, 0x5d, + 0x01, 0x8c, 0x52, 0x7b, + 0x01, 0x55, 0xaa, 0x10, + 0x80, 0x0b, 0x8e, 0x6a, + 0x80, 0x0b, 0x5a, 0x6b, + 0x01, 0x0c, 0x56, 0x7b, + 0x10, 0x0c, 0x8e, 0x7a, + 0x00, 0x65, 0xfc, 0x59, + 0xff, 0x38, 0x6c, 0x7b, 0x01, 0x38, 0xc8, 0x30, 0x00, 0x08, 0x40, 0x19, 0xff, 0x6a, 0xc8, 0x08, 0x00, 0x09, 0x42, 0x21, 0x00, 0x0a, 0x44, 0x21, 0xff, 0x6a, 0x70, 0x08, - 0x00, 0x65, 0x68, 0x43, + 0x00, 0x65, 0x6e, 0x43, 0x03, 0x08, 0x40, 0x31, 0x03, 0x08, 0x40, 0x31, 0x01, 0x08, 0x40, 0x31, @@ -445,13 +448,13 @@ 0xfd, 0xb4, 0x68, 0x09, 0x12, 0x01, 0x02, 0x00, 0x12, 0x01, 0x02, 0x00, - 0x04, 0x3c, 0xbe, 0x79, + 0x04, 0x3c, 0xc4, 0x79, 0xfb, 0x3c, 0x78, 0x08, - 0x04, 0x93, 0x2e, 0x79, - 0x01, 0x0c, 0x7c, 0x6b, - 0x00, 0x65, 0x2e, 0x41, - 0x00, 0x65, 0xbe, 0x41, - 0x00, 0x65, 0x52, 0x5d, + 0x04, 0x93, 0x34, 0x79, + 0x01, 0x0c, 0x82, 0x6b, + 0x00, 0x65, 0x34, 0x41, + 0x00, 0x65, 0xc4, 0x41, + 0x00, 0x65, 0x48, 0x5d, 0x01, 0xbc, 0x18, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x02, 0x6a, 0xf8, 0x01, @@ -461,16 +464,16 @@ 0xff, 0x6a, 0x12, 0x08, 0xff, 0x6a, 0x14, 0x08, 0xf3, 0xbc, 0xd4, 0x18, - 0xa0, 0x6a, 0xaa, 0x53, + 0xa0, 0x6a, 0xb0, 0x53, 0x04, 0xa0, 0x10, 0x31, 0xac, 0x6a, 0x26, 0x01, 0x04, 0xa0, 0x10, 0x31, 0x03, 0x08, 0x18, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0xa0, 0x6a, 0xbc, 0x5d, - 0x00, 0xbc, 0xa8, 0x5d, + 0xa0, 0x6a, 0xb2, 0x5d, + 0x00, 0xbc, 0x9e, 0x5d, 0x3d, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0xc2, 0x43, + 0x00, 0x65, 0xc8, 0x43, 0xff, 0x6a, 0x10, 0x09, 0xa4, 0x6a, 0x26, 0x01, 0x0c, 0xa0, 0x32, 0x31, @@ -480,114 +483,106 @@ 0x36, 0x6a, 0x26, 0x01, 0x02, 0x93, 0x26, 0x01, 0x35, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0x60, 0x5e, - 0x00, 0x65, 0x60, 0x5e, + 0x00, 0x65, 0x58, 0x5e, + 0x00, 0x65, 0x58, 0x5e, 0x02, 0x93, 0x26, 0x01, - 0x04, 0x0b, 0xc6, 0x6b, - 0x10, 0x0c, 0xc2, 0x7b, - 0x01, 0x03, 0xc6, 0x6b, + 0x04, 0x0b, 0xcc, 0x6b, + 0x10, 0x0c, 0xc8, 0x7b, + 0x01, 0x03, 0xcc, 0x6b, 0xc7, 0x93, 0x26, 0x09, - 0x38, 0x93, 0xca, 0x6b, + 0x38, 0x93, 0xd0, 0x6b, 0x10, 0x01, 0x02, 0x00, - 0x00, 0x65, 0xbe, 0x41, - 0x00, 0x65, 0x52, 0x5d, + 0x00, 0x65, 0xc4, 0x41, + 0x00, 0x65, 0x48, 0x5d, 0x01, 0x06, 0x50, 0x31, - 0x00, 0x65, 0xbe, 0x41, + 0x00, 0x65, 0xc4, 0x41, 0x10, 0x3f, 0x06, 0x00, 0x01, 0x3a, 0xca, 0x30, - 0x80, 0x65, 0x04, 0x64, - 0x10, 0xb8, 0x28, 0x6c, - 0x01, 0xb9, 0xdc, 0x30, - 0x01, 0x6e, 0xc8, 0x30, - 0x01, 0x54, 0xca, 0x30, - 0x80, 0xb9, 0xe8, 0x7b, - 0x01, 0x55, 0xca, 0x30, - 0x80, 0xb9, 0xec, 0x7b, - 0x01, 0x55, 0xca, 0x30, - 0x00, 0x65, 0x28, 0x6c, + 0x80, 0x65, 0xfa, 0x63, + 0x10, 0xb8, 0x1e, 0x6c, 0xc0, 0xba, 0xca, 0x00, - 0x40, 0xb8, 0xf4, 0x6b, + 0x40, 0xb8, 0xea, 0x6b, 0xbf, 0x65, 0xca, 0x08, - 0x20, 0xb8, 0x08, 0x7c, + 0x20, 0xb8, 0xfe, 0x7b, 0x01, 0x65, 0x0c, 0x30, - 0x00, 0x65, 0xa0, 0x5d, - 0xa0, 0x3f, 0x10, 0x64, + 0x00, 0x65, 0x96, 0x5d, + 0xa0, 0x3f, 0x06, 0x64, 0x23, 0xb8, 0x0c, 0x08, - 0x00, 0x65, 0xa0, 0x5d, - 0xa0, 0x3f, 0x10, 0x64, - 0x00, 0xbb, 0x08, 0x44, - 0xff, 0x65, 0x08, 0x64, - 0x00, 0x65, 0x28, 0x44, + 0x00, 0x65, 0x96, 0x5d, + 0xa0, 0x3f, 0x06, 0x64, + 0x00, 0xbb, 0xfe, 0x43, + 0xff, 0x65, 0xfe, 0x63, + 0x00, 0x65, 0x1e, 0x44, 0x40, 0x6a, 0x18, 0x00, 0x01, 0x65, 0x0c, 0x30, - 0x00, 0x65, 0xa0, 0x5d, - 0xa0, 0x3f, 0xd6, 0x73, + 0x00, 0x65, 0x96, 0x5d, + 0xa0, 0x3f, 0xdc, 0x73, 0x40, 0x6a, 0x18, 0x00, 0x01, 0x3a, 0xa6, 0x30, 0x08, 0x6a, 0x74, 0x00, - 0x00, 0x65, 0xbe, 0x41, - 0x64, 0x6a, 0x2c, 0x5d, - 0x80, 0x64, 0x9e, 0x6c, - 0x04, 0x64, 0x74, 0x74, - 0x02, 0x64, 0x82, 0x74, - 0x00, 0x6a, 0x44, 0x74, - 0x03, 0x64, 0x90, 0x74, - 0x23, 0x64, 0x30, 0x74, - 0x08, 0x64, 0x40, 0x74, - 0x61, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0xa0, 0x5d, - 0x08, 0x51, 0xc0, 0x71, - 0x00, 0x65, 0x28, 0x44, - 0x80, 0x04, 0x3e, 0x7c, - 0x51, 0x6a, 0x22, 0x5d, - 0x01, 0x51, 0x3e, 0x64, - 0x01, 0xa4, 0x3a, 0x7c, - 0x01, 0x57, 0x40, 0x7c, - 0x41, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0x40, 0x44, - 0x07, 0x6a, 0x1a, 0x5d, + 0x00, 0x65, 0xc4, 0x41, + 0x64, 0x6a, 0x22, 0x5d, + 0x80, 0x64, 0x94, 0x6c, + 0x04, 0x64, 0x6a, 0x74, + 0x02, 0x64, 0x78, 0x74, + 0x00, 0x6a, 0x3a, 0x74, + 0x03, 0x64, 0x86, 0x74, + 0x23, 0x64, 0x26, 0x74, + 0x08, 0x64, 0x36, 0x74, + 0x61, 0x6a, 0x8e, 0x5e, + 0x00, 0x65, 0x96, 0x5d, + 0x08, 0x51, 0xc6, 0x71, + 0x00, 0x65, 0x1e, 0x44, + 0x80, 0x04, 0x34, 0x7c, + 0x51, 0x6a, 0x18, 0x5d, + 0x01, 0x51, 0x34, 0x64, + 0x01, 0xa4, 0x30, 0x7c, + 0x01, 0x55, 0x36, 0x7c, + 0x41, 0x6a, 0x8e, 0x5e, + 0x00, 0x65, 0x36, 0x44, + 0x07, 0x6a, 0x10, 0x5d, 0x01, 0x06, 0xd4, 0x30, - 0x00, 0x65, 0xbe, 0x41, - 0x10, 0xb8, 0x48, 0x7c, - 0xa1, 0x6a, 0x96, 0x5e, - 0x01, 0xb4, 0x4e, 0x6c, - 0x02, 0xb4, 0x50, 0x6c, - 0x01, 0xa4, 0x50, 0x7c, - 0xff, 0xa8, 0x60, 0x7c, + 0x00, 0x65, 0xc4, 0x41, + 0x10, 0xb8, 0x3e, 0x7c, + 0xa1, 0x6a, 0x8e, 0x5e, + 0x01, 0xb4, 0x44, 0x6c, + 0x02, 0xb4, 0x46, 0x6c, + 0x01, 0xa4, 0x46, 0x7c, + 0xff, 0xa8, 0x56, 0x7c, 0x04, 0xb4, 0x68, 0x01, 0x01, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0xda, 0x5d, - 0xff, 0xa8, 0x60, 0x7c, - 0x71, 0x6a, 0x96, 0x5e, - 0x40, 0x51, 0x60, 0x64, - 0x00, 0x65, 0x76, 0x5e, - 0x00, 0x65, 0xd0, 0x41, - 0x00, 0xbb, 0x64, 0x5c, - 0x00, 0x65, 0xd0, 0x41, - 0x00, 0x65, 0x76, 0x5e, + 0x00, 0xbb, 0xd0, 0x5d, + 0xff, 0xa8, 0x56, 0x7c, + 0x71, 0x6a, 0x8e, 0x5e, + 0x40, 0x51, 0x56, 0x64, + 0x00, 0x65, 0x6e, 0x5e, + 0x00, 0x65, 0xd6, 0x41, + 0x00, 0xbb, 0x5a, 0x5c, + 0x00, 0x65, 0xd6, 0x41, + 0x00, 0x65, 0x6e, 0x5e, 0x01, 0x65, 0xa2, 0x30, 0x01, 0xf8, 0xc8, 0x30, 0x01, 0x4e, 0xc8, 0x30, - 0x00, 0x6a, 0x7e, 0xdd, - 0x00, 0x51, 0x90, 0x5d, + 0x00, 0x6a, 0x74, 0xdd, + 0x00, 0x51, 0x86, 0x5d, 0x01, 0x4e, 0x9c, 0x18, 0x02, 0x6a, 0x22, 0x05, 0x04, 0xb8, 0x70, 0x01, - 0x00, 0x65, 0x92, 0x5e, - 0x20, 0xb8, 0xd0, 0x69, + 0x00, 0x65, 0x8a, 0x5e, + 0x20, 0xb8, 0xd6, 0x69, 0x01, 0xbb, 0xa2, 0x30, 0x01, 0xba, 0x7c, 0x30, - 0x00, 0xb9, 0x94, 0x5c, - 0x00, 0x65, 0xd0, 0x41, - 0x20, 0x3c, 0x40, 0x7c, + 0x00, 0xb9, 0x8a, 0x5c, + 0x00, 0x65, 0xd6, 0x41, + 0x20, 0x3c, 0x36, 0x7c, 0x04, 0x14, 0x58, 0x31, 0x08, 0xa0, 0x60, 0x31, 0xac, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xbc, 0x5d, - 0xa0, 0x6a, 0xb4, 0x5d, - 0x00, 0x65, 0x40, 0x44, + 0x14, 0x6a, 0xb2, 0x5d, + 0xa0, 0x6a, 0xaa, 0x5d, + 0x00, 0x65, 0x36, 0x44, 0xdf, 0x3c, 0x78, 0x08, - 0x00, 0x65, 0x40, 0x44, + 0x00, 0x65, 0x36, 0x44, 0x4c, 0x65, 0xcc, 0x28, 0x01, 0x3e, 0x20, 0x31, 0xd0, 0x66, 0xcc, 0x18, @@ -598,103 +593,103 @@ 0xd0, 0x65, 0xca, 0x18, 0x01, 0x3e, 0x20, 0x31, 0x30, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xac, 0x4c, + 0x00, 0x65, 0xa2, 0x4c, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x20, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xb4, 0x54, + 0x00, 0x65, 0xaa, 0x54, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x20, 0x65, 0xca, 0x18, 0xe0, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xbe, 0x4c, + 0x00, 0x65, 0xb4, 0x4c, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0xd0, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xc6, 0x54, + 0x00, 0x65, 0xbc, 0x54, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x01, 0x6c, 0xa2, 0x30, - 0xff, 0x51, 0xd8, 0x74, - 0x00, 0x51, 0x56, 0x5d, + 0xff, 0x51, 0xce, 0x74, + 0x00, 0x51, 0x4c, 0x5d, 0x01, 0x51, 0x20, 0x31, - 0x00, 0x65, 0xfa, 0x44, + 0x00, 0x65, 0xf0, 0x44, 0x01, 0xba, 0xc8, 0x30, - 0x00, 0x3e, 0xfa, 0x74, - 0x00, 0x65, 0x74, 0x5e, + 0x00, 0x3e, 0xf0, 0x74, + 0x00, 0x65, 0x6c, 0x5e, 0x80, 0x3c, 0x78, 0x00, 0x01, 0x06, 0xd4, 0x30, - 0x00, 0x65, 0xa0, 0x5d, + 0x00, 0x65, 0x96, 0x5d, 0x01, 0x3c, 0x78, 0x00, - 0xe0, 0x3f, 0x16, 0x65, + 0xe0, 0x3f, 0x0c, 0x65, 0x02, 0x3c, 0x78, 0x00, - 0x20, 0x12, 0x16, 0x65, - 0x51, 0x6a, 0x22, 0x5d, - 0x00, 0x51, 0x56, 0x5d, - 0x51, 0x6a, 0x22, 0x5d, + 0x20, 0x12, 0x0c, 0x65, + 0x51, 0x6a, 0x18, 0x5d, + 0x00, 0x51, 0x4c, 0x5d, + 0x51, 0x6a, 0x18, 0x5d, 0x01, 0x51, 0x20, 0x31, 0x04, 0x3c, 0x78, 0x00, 0x01, 0xb9, 0xc8, 0x30, - 0x00, 0x3d, 0x14, 0x65, + 0x00, 0x3d, 0x0a, 0x65, 0x08, 0x3c, 0x78, 0x00, 0x01, 0xba, 0xc8, 0x30, - 0x00, 0x3e, 0x14, 0x65, + 0x00, 0x3e, 0x0a, 0x65, 0x10, 0x3c, 0x78, 0x00, - 0x04, 0xb8, 0x14, 0x7d, + 0x04, 0xb8, 0x0a, 0x7d, 0xfb, 0xb8, 0x70, 0x09, - 0x20, 0xb8, 0x0a, 0x6d, + 0x20, 0xb8, 0x00, 0x6d, 0x01, 0x90, 0xc8, 0x30, 0xff, 0x6a, 0xa2, 0x00, - 0x00, 0x3d, 0x94, 0x5c, + 0x00, 0x3d, 0x8a, 0x5c, 0x01, 0x64, 0x20, 0x31, 0x80, 0x6a, 0x78, 0x00, 0x00, 0x65, 0x02, 0x59, - 0x10, 0xb8, 0x40, 0x7c, - 0xff, 0x6a, 0x1a, 0x5d, - 0x00, 0x65, 0x40, 0x44, - 0x00, 0x65, 0x74, 0x5e, - 0x31, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0x40, 0x44, + 0x10, 0xb8, 0x36, 0x7c, + 0xff, 0x6a, 0x10, 0x5d, + 0x00, 0x65, 0x36, 0x44, + 0x00, 0x65, 0x6c, 0x5e, + 0x31, 0x6a, 0x8e, 0x5e, + 0x00, 0x65, 0x36, 0x44, 0x10, 0x3f, 0x06, 0x00, 0x01, 0x65, 0x74, 0x34, - 0x81, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0x24, 0x45, + 0x81, 0x6a, 0x8e, 0x5e, + 0x00, 0x65, 0x1a, 0x45, 0x01, 0x06, 0xd4, 0x30, - 0x01, 0x0c, 0x24, 0x7d, - 0x04, 0x0c, 0x1e, 0x6d, + 0x01, 0x0c, 0x1a, 0x7d, + 0x04, 0x0c, 0x14, 0x6d, 0xe0, 0x03, 0x7e, 0x08, - 0xe0, 0x3f, 0xbe, 0x61, + 0xe0, 0x3f, 0xc4, 0x61, 0x01, 0x65, 0xcc, 0x30, 0x01, 0x12, 0xda, 0x34, 0x01, 0x06, 0xd4, 0x34, - 0x01, 0x03, 0x32, 0x6d, + 0x01, 0x03, 0x28, 0x6d, 0x40, 0x03, 0xcc, 0x08, 0x01, 0x65, 0x06, 0x30, 0x40, 0x65, 0xc8, 0x08, - 0x00, 0x66, 0x40, 0x75, - 0x40, 0x65, 0x40, 0x7d, - 0x00, 0x65, 0x40, 0x5d, + 0x00, 0x66, 0x36, 0x75, + 0x40, 0x65, 0x36, 0x7d, + 0x00, 0x65, 0x36, 0x5d, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x0c, 0x08, 0x01, 0x02, 0x00, - 0x02, 0x0b, 0x4a, 0x7d, + 0x02, 0x0b, 0x40, 0x7d, 0x01, 0x65, 0x0c, 0x30, - 0x02, 0x0b, 0x4e, 0x7d, + 0x02, 0x0b, 0x44, 0x7d, 0xf7, 0x01, 0x02, 0x0c, - 0x80, 0x3c, 0x9a, 0x6e, - 0x21, 0x6a, 0x96, 0x46, + 0x80, 0x3c, 0x92, 0x6e, + 0x21, 0x6a, 0x8e, 0x46, 0x01, 0x65, 0xc8, 0x30, - 0xff, 0x41, 0x76, 0x75, + 0xff, 0x41, 0x6c, 0x75, 0x01, 0x41, 0x20, 0x31, 0xff, 0x6a, 0xa4, 0x00, - 0x00, 0x65, 0x66, 0x45, - 0xff, 0xbf, 0x76, 0x75, + 0x00, 0x65, 0x5c, 0x45, + 0xff, 0xbf, 0x6c, 0x75, 0x01, 0x90, 0xa4, 0x30, 0x01, 0xbf, 0x20, 0x31, - 0x00, 0xbb, 0x60, 0x65, - 0xff, 0x52, 0x74, 0x75, + 0x00, 0xbb, 0x56, 0x65, + 0xff, 0x52, 0x6a, 0x75, 0x01, 0xbf, 0xcc, 0x30, 0x01, 0x90, 0xca, 0x30, 0x01, 0x52, 0x20, 0x31, @@ -702,28 +697,28 @@ 0x01, 0x65, 0x20, 0x35, 0x01, 0xbf, 0x82, 0x34, 0x01, 0x64, 0xa2, 0x30, - 0x00, 0x6a, 0x7e, 0x5e, + 0x00, 0x6a, 0x76, 0x5e, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x51, 0xda, 0x45, + 0x00, 0x51, 0xd0, 0x45, 0x01, 0x65, 0xa4, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xce, 0x5d, + 0x48, 0x6a, 0xc4, 0x5d, 0x01, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x05, 0x88, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xce, 0x5d, - 0x01, 0x6a, 0xa8, 0x5d, + 0x48, 0x6a, 0xc4, 0x5d, + 0x01, 0x6a, 0x9e, 0x5d, 0x01, 0x6a, 0x26, 0x05, 0x01, 0x65, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0x94, 0x7d, + 0x80, 0xee, 0x8a, 0x7d, 0xff, 0x6a, 0xdc, 0x0d, 0x01, 0x65, 0x32, 0x31, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x6c, 0x46, - 0x81, 0x6a, 0x96, 0x5e, - 0x01, 0x0c, 0xa0, 0x7d, - 0x04, 0x0c, 0x9e, 0x6d, + 0x00, 0x65, 0x64, 0x46, + 0x81, 0x6a, 0x8e, 0x5e, + 0x01, 0x0c, 0x96, 0x7d, + 0x04, 0x0c, 0x94, 0x6d, 0xe0, 0x03, 0x06, 0x08, 0xe0, 0x03, 0x7e, 0x0c, 0x01, 0x65, 0x18, 0x31, @@ -742,7 +737,7 @@ 0x01, 0x6c, 0xda, 0x34, 0x3d, 0x64, 0xa4, 0x28, 0x55, 0x64, 0xc8, 0x28, - 0x00, 0x65, 0xce, 0x45, + 0x00, 0x65, 0xc4, 0x45, 0x2e, 0x64, 0xa4, 0x28, 0x66, 0x64, 0xc8, 0x28, 0x00, 0x6c, 0xda, 0x18, @@ -753,61 +748,62 @@ 0x00, 0x6c, 0xda, 0x24, 0x01, 0x65, 0xc8, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x44, 0x6a, 0xca, 0x5d, + 0x44, 0x6a, 0xc0, 0x5d, 0x01, 0x90, 0xe2, 0x31, - 0x04, 0x3b, 0xee, 0x7d, + 0x04, 0x3b, 0xe4, 0x7d, 0x30, 0x6a, 0xd0, 0x01, 0x20, 0x6a, 0xd0, 0x01, 0x1d, 0x6a, 0xdc, 0x01, - 0xdc, 0xee, 0xea, 0x65, - 0x00, 0x65, 0x06, 0x46, + 0xdc, 0xee, 0xe0, 0x65, + 0x00, 0x65, 0xfc, 0x45, 0x20, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x01, 0x20, 0xa0, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xf6, 0x7d, + 0x80, 0xee, 0xec, 0x7d, 0x11, 0x6a, 0xdc, 0x01, - 0x50, 0xee, 0xfa, 0x65, + 0x50, 0xee, 0xf0, 0x65, 0x20, 0x6a, 0xd0, 0x01, 0x09, 0x6a, 0xdc, 0x01, - 0x88, 0xee, 0x00, 0x66, + 0x88, 0xee, 0xf6, 0x65, 0x19, 0x6a, 0xdc, 0x01, - 0xd8, 0xee, 0x04, 0x66, + 0xd8, 0xee, 0xfa, 0x65, 0xff, 0x6a, 0xdc, 0x09, - 0x18, 0xee, 0x08, 0x6e, + 0x18, 0xee, 0xfe, 0x6d, 0xff, 0x6a, 0xd4, 0x0c, 0x88, 0x6a, 0xcc, 0x00, - 0x44, 0x6a, 0xca, 0x5d, - 0x20, 0x6a, 0xa8, 0x5d, + 0x44, 0x6a, 0xc0, 0x5d, + 0x20, 0x6a, 0x9e, 0x5d, 0x01, 0x3b, 0x26, 0x31, - 0x04, 0x3b, 0x22, 0x6e, + 0x04, 0x3b, 0x18, 0x6e, 0xa0, 0x6a, 0xca, 0x00, 0x20, 0x65, 0xc8, 0x18, - 0x00, 0x65, 0x5c, 0x5e, - 0x00, 0x65, 0x1a, 0x66, + 0x00, 0x65, 0x54, 0x5e, + 0x00, 0x65, 0x10, 0x66, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x6c, 0x46, + 0x00, 0x65, 0x64, 0x46, 0xa0, 0x6a, 0xcc, 0x00, 0xff, 0x6a, 0xc8, 0x08, - 0x01, 0x94, 0x26, 0x6e, - 0x10, 0x94, 0x28, 0x6e, - 0x08, 0x94, 0x3e, 0x6e, - 0x08, 0x94, 0x3e, 0x6e, - 0x08, 0x94, 0x3e, 0x6e, + 0x20, 0x94, 0x1c, 0x6e, + 0x10, 0x94, 0x1e, 0x6e, + 0x08, 0x94, 0x36, 0x6e, + 0x08, 0x94, 0x36, 0x6e, + 0x08, 0x94, 0x36, 0x6e, 0x07, 0x8c, 0xca, 0x18, 0x3d, 0x65, 0xca, 0x28, 0x00, 0x65, 0xc8, 0x18, - 0x00, 0x65, 0x42, 0x5e, + 0x00, 0x65, 0x3a, 0x5e, 0xff, 0x65, 0xca, 0x10, 0x05, 0x65, 0xc8, 0x18, - 0x00, 0x65, 0x26, 0x46, + 0x04, 0x64, 0x66, 0x76, + 0x00, 0x65, 0x1c, 0x46, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x40, 0x6e, + 0x08, 0x93, 0x38, 0x6e, 0x00, 0x62, 0xc4, 0x18, - 0x00, 0x65, 0x6c, 0x5e, - 0x00, 0x65, 0x4c, 0x5e, - 0x00, 0x65, 0x4c, 0x5e, - 0x00, 0x65, 0x4c, 0x5e, + 0x00, 0x65, 0x64, 0x5e, + 0x00, 0x65, 0x44, 0x5e, + 0x00, 0x65, 0x44, 0x5e, + 0x00, 0x65, 0x44, 0x5e, 0x01, 0x99, 0xda, 0x30, 0x01, 0x99, 0xda, 0x30, 0x01, 0x99, 0xda, 0x30, @@ -824,23 +820,23 @@ 0x01, 0x6c, 0x32, 0x31, 0x01, 0x6c, 0x32, 0x31, 0x01, 0x6c, 0x32, 0x35, - 0x08, 0x94, 0x6c, 0x7e, + 0x08, 0x94, 0x64, 0x7e, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x70, 0x6e, + 0x08, 0x93, 0x68, 0x6e, 0xff, 0x6a, 0xd4, 0x0c, - 0x04, 0xb8, 0x92, 0x6e, + 0x04, 0xb8, 0x8a, 0x6e, 0x01, 0x42, 0x7e, 0x31, 0xff, 0x6a, 0x76, 0x01, 0x01, 0x90, 0x84, 0x34, 0xff, 0x6a, 0x76, 0x05, - 0xff, 0x42, 0x8e, 0x66, - 0xff, 0x41, 0x86, 0x66, - 0xd1, 0x6a, 0x96, 0x5e, + 0xff, 0x42, 0x86, 0x66, + 0xff, 0x41, 0x7e, 0x66, + 0xd1, 0x6a, 0x8e, 0x5e, 0xff, 0x6a, 0xca, 0x04, 0x01, 0x41, 0x20, 0x31, 0x01, 0xbf, 0x82, 0x30, 0x01, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0xda, 0x45, + 0x00, 0xbb, 0xd0, 0x45, 0x01, 0x42, 0x20, 0x31, 0x01, 0xbf, 0x84, 0x34, 0x01, 0x41, 0x7e, 0x31, @@ -1087,141 +1083,138 @@ { ahc_patch1_func, 131, 1, 2 }, { ahc_patch0_func, 132, 1, 1 }, { ahc_patch6_func, 133, 4, 1 }, - { ahc_patch6_func, 144, 77, 9 }, - { ahc_patch4_func, 156, 1, 1 }, - { ahc_patch1_func, 172, 1, 1 }, - { ahc_patch8_func, 180, 1, 2 }, - { ahc_patch0_func, 181, 1, 1 }, - { ahc_patch8_func, 190, 1, 2 }, - { ahc_patch0_func, 191, 1, 1 }, - { ahc_patch8_func, 207, 6, 2 }, - { ahc_patch0_func, 213, 6, 1 }, - { ahc_patch7_func, 221, 18, 2 }, - { ahc_patch1_func, 234, 1, 1 }, - { ahc_patch1_func, 241, 1, 2 }, - { ahc_patch0_func, 242, 2, 2 }, - { ahc_patch11_func, 243, 1, 1 }, - { ahc_patch8_func, 251, 33, 2 }, - { ahc_patch1_func, 267, 16, 1 }, - { ahc_patch12_func, 284, 14, 1 }, - { ahc_patch1_func, 298, 2, 2 }, - { ahc_patch0_func, 300, 3, 3 }, - { ahc_patch8_func, 300, 1, 2 }, - { ahc_patch0_func, 301, 2, 1 }, - { ahc_patch1_func, 305, 1, 2 }, - { ahc_patch0_func, 306, 1, 1 }, - { ahc_patch8_func, 310, 1, 1 }, - { ahc_patch8_func, 313, 2, 2 }, - { ahc_patch0_func, 315, 4, 1 }, - { ahc_patch12_func, 319, 1, 1 }, - { ahc_patch13_func, 322, 2, 3 }, - { ahc_patch8_func, 322, 1, 2 }, - { ahc_patch0_func, 323, 1, 1 }, - { ahc_patch1_func, 332, 40, 6 }, - { ahc_patch6_func, 341, 1, 1 }, - { ahc_patch7_func, 342, 1, 1 }, - { ahc_patch14_func, 344, 2, 1 }, - { ahc_patch15_func, 346, 5, 1 }, - { ahc_patch0_func, 372, 51, 15 }, - { ahc_patch12_func, 372, 1, 1 }, - { ahc_patch6_func, 374, 2, 2 }, - { ahc_patch16_func, 375, 1, 1 }, - { ahc_patch8_func, 378, 1, 1 }, - { ahc_patch17_func, 385, 1, 1 }, - { ahc_patch12_func, 390, 9, 3 }, - { ahc_patch8_func, 391, 3, 2 }, - { ahc_patch0_func, 394, 3, 1 }, - { ahc_patch8_func, 402, 6, 2 }, - { ahc_patch0_func, 408, 8, 1 }, - { ahc_patch12_func, 416, 1, 1 }, - { ahc_patch8_func, 418, 1, 2 }, - { ahc_patch0_func, 419, 1, 1 }, - { ahc_patch6_func, 422, 1, 1 }, - { ahc_patch6_func, 423, 1, 1 }, - { ahc_patch7_func, 424, 2, 1 }, - { ahc_patch8_func, 426, 1, 1 }, - { ahc_patch12_func, 427, 9, 4 }, - { ahc_patch8_func, 427, 1, 1 }, - { ahc_patch8_func, 434, 2, 1 }, - { ahc_patch0_func, 436, 4, 3 }, - { ahc_patch8_func, 436, 1, 2 }, - { ahc_patch0_func, 437, 3, 1 }, - { ahc_patch1_func, 441, 2, 1 }, - { ahc_patch6_func, 443, 5, 2 }, - { ahc_patch0_func, 448, 1, 1 }, - { ahc_patch7_func, 449, 113, 22 }, - { ahc_patch1_func, 450, 3, 2 }, - { ahc_patch0_func, 453, 5, 3 }, - { ahc_patch8_func, 453, 2, 2 }, - { ahc_patch0_func, 455, 3, 1 }, - { ahc_patch1_func, 460, 2, 2 }, - { ahc_patch0_func, 462, 6, 3 }, - { ahc_patch8_func, 462, 2, 2 }, - { ahc_patch0_func, 464, 3, 1 }, - { ahc_patch1_func, 470, 2, 2 }, - { ahc_patch0_func, 472, 9, 7 }, - { ahc_patch8_func, 472, 5, 6 }, - { ahc_patch18_func, 472, 1, 2 }, - { ahc_patch0_func, 473, 1, 1 }, + { ahc_patch6_func, 144, 80, 9 }, + { ahc_patch4_func, 162, 1, 1 }, + { ahc_patch1_func, 175, 1, 1 }, + { ahc_patch8_func, 183, 1, 2 }, + { ahc_patch0_func, 184, 1, 1 }, + { ahc_patch8_func, 193, 1, 2 }, + { ahc_patch0_func, 194, 1, 1 }, + { ahc_patch8_func, 210, 6, 2 }, + { ahc_patch0_func, 216, 6, 1 }, + { ahc_patch7_func, 224, 18, 2 }, + { ahc_patch1_func, 237, 1, 1 }, + { ahc_patch1_func, 244, 1, 2 }, + { ahc_patch0_func, 245, 2, 2 }, + { ahc_patch11_func, 246, 1, 1 }, + { ahc_patch8_func, 254, 33, 2 }, + { ahc_patch1_func, 270, 16, 1 }, + { ahc_patch12_func, 287, 14, 1 }, + { ahc_patch1_func, 301, 2, 2 }, + { ahc_patch0_func, 303, 3, 3 }, + { ahc_patch8_func, 303, 1, 2 }, + { ahc_patch0_func, 304, 2, 1 }, + { ahc_patch1_func, 308, 1, 2 }, + { ahc_patch0_func, 309, 1, 1 }, + { ahc_patch8_func, 313, 1, 1 }, + { ahc_patch8_func, 316, 2, 2 }, + { ahc_patch0_func, 318, 4, 1 }, + { ahc_patch12_func, 322, 1, 1 }, + { ahc_patch13_func, 325, 2, 3 }, + { ahc_patch8_func, 325, 1, 2 }, + { ahc_patch0_func, 326, 1, 1 }, + { ahc_patch1_func, 335, 40, 6 }, + { ahc_patch6_func, 344, 1, 1 }, + { ahc_patch7_func, 345, 1, 1 }, + { ahc_patch14_func, 347, 2, 1 }, + { ahc_patch15_func, 349, 5, 1 }, + { ahc_patch0_func, 375, 51, 15 }, + { ahc_patch12_func, 375, 1, 1 }, + { ahc_patch6_func, 377, 2, 2 }, + { ahc_patch16_func, 378, 1, 1 }, + { ahc_patch8_func, 381, 1, 1 }, + { ahc_patch17_func, 388, 1, 1 }, + { ahc_patch12_func, 393, 9, 3 }, + { ahc_patch8_func, 394, 3, 2 }, + { ahc_patch0_func, 397, 3, 1 }, + { ahc_patch8_func, 405, 6, 2 }, + { ahc_patch0_func, 411, 8, 1 }, + { ahc_patch12_func, 419, 1, 1 }, + { ahc_patch8_func, 421, 1, 2 }, + { ahc_patch0_func, 422, 1, 1 }, + { ahc_patch6_func, 425, 1, 1 }, + { ahc_patch6_func, 426, 1, 1 }, + { ahc_patch7_func, 427, 2, 1 }, + { ahc_patch8_func, 429, 1, 1 }, + { ahc_patch12_func, 430, 9, 4 }, + { ahc_patch8_func, 430, 1, 1 }, + { ahc_patch8_func, 437, 2, 1 }, + { ahc_patch0_func, 439, 4, 3 }, + { ahc_patch8_func, 439, 1, 2 }, + { ahc_patch0_func, 440, 3, 1 }, + { ahc_patch1_func, 444, 2, 1 }, + { ahc_patch6_func, 446, 5, 2 }, + { ahc_patch0_func, 451, 1, 1 }, + { ahc_patch7_func, 452, 105, 19 }, + { ahc_patch1_func, 453, 3, 2 }, + { ahc_patch0_func, 456, 5, 3 }, + { ahc_patch8_func, 456, 2, 2 }, + { ahc_patch0_func, 458, 3, 1 }, + { ahc_patch1_func, 463, 2, 2 }, + { ahc_patch0_func, 465, 6, 3 }, + { ahc_patch8_func, 465, 2, 2 }, + { ahc_patch0_func, 467, 3, 1 }, + { ahc_patch1_func, 473, 2, 2 }, + { ahc_patch0_func, 475, 9, 7 }, + { ahc_patch8_func, 475, 5, 6 }, { ahc_patch18_func, 475, 1, 2 }, { ahc_patch0_func, 476, 1, 1 }, - { ahc_patch0_func, 477, 4, 1 }, - { ahc_patch1_func, 486, 1, 1 }, - { ahc_patch2_func, 498, 2, 2 }, - { ahc_patch0_func, 500, 2, 2 }, - { ahc_patch19_func, 500, 2, 1 }, - { ahc_patch19_func, 536, 7, 1 }, - { ahc_patch3_func, 564, 1, 2 }, - { ahc_patch0_func, 565, 1, 1 }, - { ahc_patch20_func, 568, 1, 1 }, - { ahc_patch7_func, 570, 95, 26 }, - { ahc_patch4_func, 571, 1, 1 }, - { ahc_patch8_func, 578, 2, 2 }, - { ahc_patch0_func, 580, 3, 1 }, - { ahc_patch18_func, 587, 2, 2 }, - { ahc_patch0_func, 589, 1, 1 }, - { ahc_patch18_func, 593, 10, 3 }, - { ahc_patch5_func, 595, 8, 1 }, - { ahc_patch0_func, 603, 9, 2 }, - { ahc_patch5_func, 604, 8, 1 }, - { ahc_patch4_func, 614, 1, 2 }, - { ahc_patch0_func, 615, 1, 1 }, - { ahc_patch18_func, 616, 1, 2 }, - { ahc_patch0_func, 617, 3, 2 }, - { ahc_patch4_func, 619, 1, 1 }, + { ahc_patch18_func, 478, 1, 2 }, + { ahc_patch0_func, 479, 1, 1 }, + { ahc_patch0_func, 480, 4, 1 }, + { ahc_patch1_func, 489, 1, 1 }, + { ahc_patch19_func, 531, 7, 1 }, + { ahc_patch3_func, 559, 1, 2 }, + { ahc_patch0_func, 560, 1, 1 }, + { ahc_patch20_func, 563, 1, 1 }, + { ahc_patch7_func, 565, 95, 26 }, + { ahc_patch4_func, 566, 1, 1 }, + { ahc_patch8_func, 573, 2, 2 }, + { ahc_patch0_func, 575, 3, 1 }, + { ahc_patch18_func, 582, 2, 2 }, + { ahc_patch0_func, 584, 1, 1 }, + { ahc_patch18_func, 588, 10, 3 }, + { ahc_patch5_func, 590, 8, 1 }, + { ahc_patch0_func, 598, 9, 2 }, + { ahc_patch5_func, 599, 8, 1 }, + { ahc_patch4_func, 609, 1, 2 }, + { ahc_patch0_func, 610, 1, 1 }, + { ahc_patch18_func, 611, 1, 2 }, + { ahc_patch0_func, 612, 3, 2 }, + { ahc_patch4_func, 614, 1, 1 }, + { ahc_patch5_func, 615, 1, 1 }, + { ahc_patch5_func, 618, 1, 1 }, { ahc_patch5_func, 620, 1, 1 }, - { ahc_patch5_func, 623, 1, 1 }, - { ahc_patch5_func, 625, 1, 1 }, - { ahc_patch4_func, 627, 2, 2 }, - { ahc_patch0_func, 629, 2, 1 }, - { ahc_patch5_func, 631, 1, 1 }, - { ahc_patch5_func, 634, 1, 1 }, - { ahc_patch5_func, 637, 1, 1 }, - { ahc_patch18_func, 641, 1, 1 }, - { ahc_patch18_func, 644, 1, 1 }, - { ahc_patch4_func, 650, 1, 1 }, - { ahc_patch6_func, 665, 16, 1 }, - { ahc_patch4_func, 683, 20, 1 }, - { ahc_patch8_func, 704, 4, 2 }, - { ahc_patch0_func, 708, 4, 1 }, - { ahc_patch8_func, 712, 4, 2 }, - { ahc_patch0_func, 716, 3, 1 }, - { ahc_patch21_func, 724, 14, 1 }, - { ahc_patch6_func, 738, 3, 1 }, - { ahc_patch8_func, 750, 24, 8 }, - { ahc_patch18_func, 754, 1, 2 }, - { ahc_patch0_func, 755, 1, 1 }, - { ahc_patch13_func, 760, 4, 2 }, - { ahc_patch0_func, 764, 7, 3 }, - { ahc_patch22_func, 764, 5, 2 }, - { ahc_patch0_func, 769, 2, 1 }, - { ahc_patch0_func, 774, 40, 3 }, - { ahc_patch17_func, 786, 16, 2 }, - { ahc_patch0_func, 802, 1, 1 }, - { ahc_patch4_func, 826, 1, 1 }, - { ahc_patch4_func, 827, 3, 2 }, - { ahc_patch0_func, 830, 1, 1 }, - { ahc_patch4_func, 831, 12, 1 } + { ahc_patch4_func, 622, 2, 2 }, + { ahc_patch0_func, 624, 2, 1 }, + { ahc_patch5_func, 626, 1, 1 }, + { ahc_patch5_func, 629, 1, 1 }, + { ahc_patch5_func, 632, 1, 1 }, + { ahc_patch18_func, 636, 1, 1 }, + { ahc_patch18_func, 639, 1, 1 }, + { ahc_patch4_func, 645, 1, 1 }, + { ahc_patch6_func, 660, 16, 1 }, + { ahc_patch4_func, 678, 20, 1 }, + { ahc_patch8_func, 699, 4, 2 }, + { ahc_patch0_func, 703, 4, 1 }, + { ahc_patch8_func, 707, 4, 2 }, + { ahc_patch0_func, 711, 3, 1 }, + { ahc_patch21_func, 719, 14, 1 }, + { ahc_patch6_func, 733, 3, 1 }, + { ahc_patch8_func, 745, 24, 8 }, + { ahc_patch18_func, 749, 1, 2 }, + { ahc_patch0_func, 750, 1, 1 }, + { ahc_patch13_func, 755, 4, 2 }, + { ahc_patch0_func, 759, 7, 3 }, + { ahc_patch22_func, 759, 5, 2 }, + { ahc_patch0_func, 764, 2, 1 }, + { ahc_patch0_func, 769, 41, 3 }, + { ahc_patch17_func, 781, 17, 2 }, + { ahc_patch0_func, 798, 1, 1 }, + { ahc_patch4_func, 822, 1, 1 }, + { ahc_patch4_func, 823, 3, 2 }, + { ahc_patch0_func, 826, 1, 1 }, + { ahc_patch4_func, 827, 12, 1 } }; struct cs { u_int16_t begin; @@ -1229,11 +1222,11 @@ } critical_sections[] = { { 11, 18 }, { 21, 30 }, - { 683, 699 }, - { 827, 830 }, - { 831, 837 }, - { 839, 841 }, - { 841, 843 } + { 678, 694 }, + { 823, 826 }, + { 827, 833 }, + { 835, 837 }, + { 837, 839 } }; const int num_critical_sections = sizeof(critical_sections) / sizeof(*critical_sections); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aicasm/Makefile linux.ac/drivers/scsi/aic7xxx/aicasm/Makefile --- linux.vanilla/drivers/scsi/aic7xxx/aicasm/Makefile Tue Apr 3 17:32:19 2001 +++ linux.ac/drivers/scsi/aic7xxx/aicasm/Makefile Thu Apr 12 17:53:47 2001 @@ -2,17 +2,23 @@ CSRCS= aicasm.c aicasm_symbol.c GENSRCS= aicasm_gram.c aicasm_scan.c - -GENHDRS= y.tab.h +DEPHDRS= aicdb.h +GENHDRS= y.tab.h aicdb.h SRCS= ${GENSRCS} ${CSRCS} CLEANFILES= ${GENSRCS} ${GENHDRS} y.output # Override default kernel CFLAGS. This is a userland app. -AICASM_CFLAGS:= -I/usr/include -ldb1 +AICASM_CFLAGS:= -I/usr/include -I. -ldb YFLAGS= -d NOMAN= noman +ifneq ($(HOSTCC),) +AICASM_CC= $(HOSTCC) +else +AICASM_CC= $(CC) +endif + ifdef DEBUG CFLAGS+= -DDEBUG -g YFLAGS+= -t -v @@ -21,8 +27,24 @@ .SUFFIXES= .l .y .c -$(PROG): $(SRCS) - $(HOSTCC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG) + +$(PROG): $(SRCS) $(DEPHDRS) + $(AICASM_CC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG) + +aicdb.h: + @if [ -e "/usr/include/db3/db_185.h" ]; then \ + echo "#include <db3/db_185.h>" > aicdb.h; \ + elif [ -e "/usr/include/db_185.h" ]; then \ + echo "#include <db_185.h>" > aicdb.h; \ + elif [ -e "/usr/include/db/db_185.h" ]; then \ + echo "#include <db/db_185.h>" > aicdb.h; \ + elif [ -e "/usr/include/db2/db_185.h" ]; then \ + echo "#include <db2/db_185.h>" > aicdb.h; \ + elif [ -e "/usr/include/db1/db_185.h" ]; then \ + echo "#include <db1/db_185.h>" > aicdb.h; \ + else \ + echo "*** Install db development libraries"; \ + fi clean: - rm -f $(CLEANFILES) $(PROG) + rm -f $(CLEANFILES) $(PROG) aicdb.h diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c linux.ac/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c --- linux.vanilla/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c Tue Apr 3 17:32:19 2001 +++ linux.ac/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c Thu Apr 12 17:51:15 2001 @@ -28,18 +28,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aicasm/aicasm_symbol.c#4 $ + * $Id: //depot/src/aic7xxx/aicasm/aicasm_symbol.c#5 $ * * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.c,v 1.11 2000/09/22 22:19:54 gibbs Exp $ */ #include <sys/types.h> - -#ifdef __linux__ -#include <db1/db.h> -#else -#include <db.h> -#endif +#include "aicdb.h" #include <fcntl.h> #include <stdio.h> #include <stdlib.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx_old/README.aic7xxx linux.ac/drivers/scsi/aic7xxx_old/README.aic7xxx --- linux.vanilla/drivers/scsi/aic7xxx_old/README.aic7xxx Tue Apr 3 17:32:19 2001 +++ linux.ac/drivers/scsi/aic7xxx_old/README.aic7xxx Tue Apr 3 17:55:02 2001 @@ -478,10 +478,10 @@ information in the process. Second, if you specify the option "aic7xxx=verbose:0x1ffff", the system will print out *SOOOO* much information as it runs that you won't be able to see anything. - However, this can actually be very usefull if your machine simply + However, this can actually be very useful if your machine simply locks up when trying to boot, since it will pin-point what was last happening (in regards to the aic7xxx driver) immediately prior to - the lockup. This is really only usefull if your machine simply can + the lockup. This is really only useful if your machine simply can not boot up successfully. If you can get your machine to run, then this will produce far too much information. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx_old/aic7xxx.reg linux.ac/drivers/scsi/aic7xxx_old/aic7xxx.reg --- linux.vanilla/drivers/scsi/aic7xxx_old/aic7xxx.reg Tue Apr 3 17:32:19 2001 +++ linux.ac/drivers/scsi/aic7xxx_old/aic7xxx.reg Tue Apr 10 18:16:57 2001 @@ -14,7 +14,7 @@ * derived from this software without specific prior written permission. * * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the + * the GNU General Public License ("GPL") and the terms of the GPL would require the * combined work to also be released under the terms of the GPL, the terms * and conditions of this License will apply in addition to those of the * GPL with the exception of any terms or conditions of this License that @@ -703,7 +703,12 @@ * it that it can fill the * message buffer. */ - mask TRACEPOINT 0xb0|SEQINT + mask SEQ_SG_FIXUP 0xb0|SEQINT /* need help with fixing up + * the sg array pointer after + * a phasemis with no valid + * sg elements in the shadow + * pipeline. + */ mask TRACEPOINT2 0xc0|SEQINT mask MSGIN_PHASEMIS 0xd0|SEQINT /* * Target changed phase on us diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx_old/aic7xxx.seq linux.ac/drivers/scsi/aic7xxx_old/aic7xxx.seq --- linux.vanilla/drivers/scsi/aic7xxx_old/aic7xxx.seq Tue Apr 3 17:32:19 2001 +++ linux.ac/drivers/scsi/aic7xxx_old/aic7xxx.seq Tue Apr 10 18:16:57 2001 @@ -14,7 +14,7 @@ * derived from this software without specific prior written permission. * * Where this Software is combined with software released under the terms of - * the GNU Public License (GPL) and the terms of the GPL would require the + * the GNU General Public License (GPL) and the terms of the GPL would require the * combined work to also be released under the terms of the GPL, the terms * and conditions of this License will apply in addition to those of the * GPL with the exception of any terms or conditions of this License that @@ -332,12 +332,15 @@ /* clear target specific flags */ clr SEQ_FLAGS ret; + +data_phase_reinit: /* * If we re-enter the data phase after going through another phase, the * STCNT may have been cleared, so restore it from the residual field. + * On Ultra2, we have to put it into the HCNT field because we have to + * drop the data down into the shadow layer via the preload ability. */ -data_phase_reinit: - if ((p->features & AHC_ULTRA2) != 0) { + if ((p->features & AHC_ULTRA2) != 0) { bmov HADDR, SHADDR, 4; bmov HCNT, SCB_RESID_DCNT, 3; } @@ -349,27 +352,24 @@ mvi SCB_RESID_DCNT call bcopy_3; } jmp data_phase_loop; - p_data: - if ((p->features & AHC_ULTRA2) != 0) { + if ((p->features & AHC_ULTRA2) != 0) { mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN; } else { mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; } test LASTPHASE, IOI jnz . + 2; or DMAPARAMS, DIRECTION; - call assert; /* - * Ensure entering a data - * phase is okay - seen identify, etc. - */ + call assert; /* + * Ensure entering a data + * phase is okay - seen identify, etc. + */ if ((p->features & AHC_CMD_CHAN) != 0) { mvi CCSGADDR, CCSGADDR_MAX; } - test SEQ_FLAGS, DPHASE jnz data_phase_reinit; - - /* We have seen a data phase */ - or SEQ_FLAGS, DPHASE; + test SEQ_FLAGS, DPHASE jnz data_phase_reinit; + or SEQ_FLAGS, DPHASE; /* we've seen a data phase */ /* * Initialize the DMA address and counter from the SCB. * Also set SG_COUNT and SG_NEXT in memory since we cannot @@ -378,8 +378,10 @@ */ if ((p->features & AHC_CMD_CHAN) != 0) { bmov HADDR, SCB_DATAPTR, 7; - bmov STCNT, HCNT, 3; bmov SG_COUNT, SCB_SGCOUNT, 5; + if ((p->features & AHC_ULTRA2) == 0) { + bmov STCNT, HCNT, 3; + } } else { mvi DINDEX, HADDR; mvi SCB_DATAPTR call bcopy_7; @@ -387,9 +389,8 @@ mvi DINDEX, SG_COUNT; mvi SCB_SGCOUNT call bcopy_5; } - data_phase_loop: -/* Guard against overruns */ + /* Guard against overruns */ test SG_COUNT, 0xff jnz data_phase_inbounds; /* * Turn on 'Bit Bucket' mode, set the transfer count to @@ -399,66 +400,62 @@ */ or SXFRCTL1,BITBUCKET; and DMAPARAMS, ~(HDMAEN|SDMAEN); - if ((p->features & AHC_CMD_CHAN) != 0) { - if ((p->features & AHC_ULTRA2) != 0) { - bmov HCNT, ALLONES, 3; - } + if ((p->features & AHC_ULTRA2) != 0) { + bmov HCNT, ALLONES, 3; + } + if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { bmov STCNT, ALLONES, 3; - } else { + } + if ((p->features & AHC_CMD_CHAN) == 0) { mvi STCNT[0], 0xFF; mvi STCNT[1], 0xFF; mvi STCNT[2], 0xFF; } + data_phase_inbounds: /* If we are the last SG block, tell the hardware. */ - cmp SG_COUNT,0x01 jne data_phase_wideodd; - if ((p->features & AHC_ULTRA2) == 0) { - and DMAPARAMS, ~WIDEODD; + if ((p->features & AHC_ULTRA2) != 0) { + shl A, 2, SG_COUNT; + cmp SG_COUNT,0x01 jne data_phase_wideodd; + or A, LAST_SEG; } else { - mvi SG_CACHEPTR, LAST_SEG; + cmp SG_COUNT,0x01 jne data_phase_wideodd; + and DMAPARAMS, ~WIDEODD; } data_phase_wideodd: - if ((p->features & AHC_ULTRA2) != 0) { - mov SINDEX, ALLONES; - mov DFCNTRL, DMAPARAMS; - test SSTAT0, SDONE jnz .; -data_phase_dma_loop: - test SSTAT0, SDONE jnz data_phase_dma_done; - test SSTAT1,PHASEMIS jz data_phase_dma_loop; /* ie. underrun */ -data_phase_dma_phasemis: - test SSTAT0,SDONE jnz data_phase_dma_done; - clr SINDEX; /* Remember the phasemiss */ + if ((p->features & AHC_ULTRA2) != 0) { + mov SG_CACHEPTR, A; + mov DFCNTRL, DMAPARAMS; /* start the operation */ + test SXFRCTL1, BITBUCKET jnz data_phase_overrun; +u2_preload_wait: + test SSTAT1, PHASEMIS jnz u2_phasemis; + test DFSTATUS, PRELOAD_AVAIL jz u2_preload_wait; } else { mov DMAPARAMS call dma; - } - data_phase_dma_done: /* Go tell the host about any overruns */ - test SXFRCTL1,BITBUCKET jnz data_phase_overrun; + test SXFRCTL1,BITBUCKET jnz data_phase_overrun; /* Exit if we had an underrun. dma clears SINDEX in this case. */ - test SINDEX,0xff jz data_phase_finish; - + test SINDEX,0xff jz data_phase_finish; + } /* - * Advance the scatter-gather pointers if needed + * Advance the scatter-gather pointers */ sg_advance: - dec SG_COUNT; /* one less segment to go */ + if ((p->features & AHC_ULTRA2) != 0) { + cmp SG_COUNT, 0x01 je u2_data_phase_finish; + } else { + dec SG_COUNT; + test SG_COUNT, 0xff jz data_phase_finish; + } - test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */ -/* - * Load a struct scatter and set up the data address and length. - * If the working value of the SG count is nonzero, then - * we need to load a new set of values. - * - * This, like all DMA's, assumes little-endian host data storage. - */ -sg_load: if ((p->features & AHC_CMD_CHAN) != 0) { + /* * Do we have any prefetch left??? */ - cmp CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail; + cmp CCSGADDR, CCSGADDR_MAX jne prefetch_avail; /* * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes. @@ -474,10 +471,12 @@ and CCSGCTL, ~CCSGEN; test CCSGCTL, CCSGEN jnz .; mvi CCSGCTL, CCSGRESET; -prefetched_segs_avail: +prefetch_avail: bmov HADDR, CCSGRAM, 8; if ((p->features & AHC_ULTRA2) == 0) { bmov STCNT, HCNT, 3; + } else { + dec SG_COUNT; } } else { mvi DINDEX, HADDR; @@ -491,30 +490,63 @@ call dma_finish; - /* - * Copy data from FIFO into SCB data pointer and data count. - * This assumes that the SG segments are of the form: - * struct ahc_dma_seg { - * u_int32_t addr; four bytes, little-endian order - * u_int32_t len; four bytes, little endian order - * }; - */ - mvi HADDR call dfdat_in_7; +/* + * Copy data from FIFO into SCB data pointer and data count. + * This assumes that the SG segments are of the form: + * struct ahc_dma_seg { + * u_int32_t addr; four bytes, little-endian order + * u_int32_t len; four bytes, little endian order + * }; + */ + mvi DINDEX, HADDR; + call dfdat_in_7; call set_stcnt_from_hcnt; } - /* Advance the SG pointer */ - clr A; /* add sizeof(struct scatter) */ + clr A; /* add sizeof(struct scatter) */ add SG_NEXT[0],SG_SIZEOF; adc SG_NEXT[1],A; - test SSTAT1, REQINIT jz .; - test SSTAT1,PHASEMIS jz data_phase_loop; + if ((p->features & AHC_ULTRA2) != 0) { + jmp data_phase_loop; + } else { + test SSTAT1, REQINIT jz .; + test SSTAT1,PHASEMIS jz data_phase_loop; + } + -/* This drops the last SG segment down to the shadow layer for us */ +/* + * We've loaded all of our segments into the preload layer. Now, we simply + * have to wait for it to finish or for us to get a phasemis. And, since + * we'll get a phasemis if we do finish, all we really need to do is wait + * for a phasemis then check if we did actually complete all the segments. + */ if ((p->features & AHC_ULTRA2) != 0) { - mov DFCNTRL, DMAPARAMS; - test SSTAT0, SDONE jnz .; +u2_data_phase_finish: + test SSTAT1, PHASEMIS jnz u2_phasemis; + test SG_CACHEPTR, LAST_SEG_DONE jz u2_data_phase_finish; + clr SG_COUNT; + test SSTAT1, REQINIT jz .; + test SSTAT1, PHASEMIS jz data_phase_loop; +u2_phasemis: + call ultra2_dmafinish; + test SG_CACHEPTR, LAST_SEG_DONE jnz data_phase_finish; + test SSTAT2, SHVALID jnz u2_fixup_residual; + mvi INTSTAT, SEQ_SG_FIXUP; + jmp data_phase_finish; +u2_fixup_residual: + shr ARG_1, 2, SG_CACHEPTR; +u2_phasemis_loop: + and A, 0x3f, SG_COUNT; + cmp ARG_1, A je data_phase_finish; +/* + * Subtract SG_SIZEOF from the SG_NEXT pointer and add 1 to the SG_COUNT + */ + clr A; + add SG_NEXT[0], -SG_SIZEOF; + adc SG_NEXT[1], 0xff; + inc SG_COUNT; + jmp u2_phasemis_loop; } data_phase_finish: @@ -523,64 +555,83 @@ * We use STCNT instead of HCNT, since it's a reflection of how many bytes * were transferred on the SCSI (as opposed to the host) bus. */ - if ((p->features & AHC_ULTRA2) != 0) { - call ultra2_dmafinish; - } - if ((p->features & AHC_ULTRA2) == 0) { - if ((p->features & AHC_CMD_CHAN) != 0) { - bmov SCB_RESID_DCNT, STCNT, 3; - mov SCB_RESID_SGCNT, SG_COUNT; - } else { - mov SCB_RESID_DCNT[0],STCNT[0]; - mov SCB_RESID_DCNT[1],STCNT[1]; - mov SCB_RESID_DCNT[2],STCNT[2]; - mov SCB_RESID_SGCNT, SG_COUNT; + if ((p->features & AHC_CMD_CHAN) != 0) { + bmov SCB_RESID_DCNT, STCNT, 3; + mov SCB_RESID_SGCNT, SG_COUNT; + if ((p->features & AHC_ULTRA2) != 0) { + or SXFRCTL0, CLRSTCNT|CLRCHN; } + } else { + mov SCB_RESID_DCNT[0],STCNT[0]; + mov SCB_RESID_DCNT[1],STCNT[1]; + mov SCB_RESID_DCNT[2],STCNT[2]; + mov SCB_RESID_SGCNT, SG_COUNT; } jmp ITloop; data_phase_overrun: - if ((p->features & AHC_ULTRA2) != 0) { - call ultra2_dmafinish; - } /* * Turn off BITBUCKET mode and notify the host */ + if ((p->features & AHC_ULTRA2) != 0) { +/* + * Wait for the target to quit transferring data on the SCSI bus + */ + test SSTAT1, PHASEMIS jz .; + call ultra2_dmafinish; + } and SXFRCTL1, ~BITBUCKET; mvi INTSTAT,DATA_OVERRUN; jmp ITloop; -ultra2_dmafinish: + + + +/* + * Actually turn off the DMA hardware, save our current position into the + * proper residual variables, wait for the next REQ signal, then jump to + * the ITloop. Jumping to the ITloop ensures that if we happen to get + * brought into the data phase again (or are still in it after our last + * segment) that we will properly signal an overrun to the kernel. + */ if ((p->features & AHC_ULTRA2) != 0) { +ultra2_dmafinish: test DFCNTRL, DIRECTION jnz ultra2_dmahalt; and DFCNTRL, ~SCSIEN; test DFCNTRL, SCSIEN jnz .; + if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) { + or DFCNTRL, FIFOFLUSH; + } ultra2_dmafifoflush: - or DFCNTRL, FIFOFLUSH; - test DFSTATUS, FIFOEMP jz . - 1; - /* - * hardware bug alert! This needless set of jumps is to - * protect against a FIFOEMP status bit glitch in the - * silicon. - */ - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) { + /* + * hardware bug alert! This needless set of jumps + * works around a glitch in the silicon. When the + * PCI DMA fifo goes empty, but there is still SCSI + * data to be flushed into the PCI DMA fifo (and from + * there on into main memory), the FIFOEMP bit will + * come on between the time when the PCI DMA buffer + * went empty and the next bit of data is copied from + * the SCSI fifo into the PCI fifo. It should only + * come on when both FIFOs (meaning the entire FIFO + * chain) are emtpy. Since it can take up to 4 cycles + * for new data to be copied from the SCSI fifo into + * the PCI fifo, testing for FIFOEMP status for 4 + * extra times gives the needed time for any + * remaining SCSI fifo data to be put in the PCI fifo + * before we declare it *truly* empty. + */ + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + } test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; test DFSTATUS, MREQPEND jnz .; ultra2_dmahalt: - test SCSIOFFSET, 0x7f jnz ultra2_shutdown; -ultra2_await_nreq: - test SCSISIGI, REQI jz ultra2_shutdown; - test SSTAT1, (PHASEMIS|REQINIT) jz ultra2_await_nreq; -ultra2_shutdown: and DFCNTRL, ~(HDMAEN|SCSIEN); test DFCNTRL, (HDMAEN|SCSIEN) jnz .; - bmov SCB_RESID_DCNT, STCNT, 3; - mov SCB_RESID_SGCNT, SG_COUNT; - or SXFRCTL0, CLRSTCNT|CLRCHN; ret; } @@ -1021,6 +1072,7 @@ inb_last: mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ + mesgin_phasemis: /* * We expected to receive another byte, but the target changed phase @@ -1080,7 +1132,9 @@ * to drain the data fifo until there is space for the input * latch to drain and HDMAEN de-asserts. */ - mov NONE, DFDAT; + if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) { + mov NONE, DFDAT; + } test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; } return: @@ -1306,20 +1360,30 @@ cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; jmp dma_scb_finish; dma_scb_tohost: - if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { + if ((p->features & AHC_ULTRA2) == 0) { mvi CCSCBCTL, CCSCBRESET; bmov CCSCBRAM, SCB_CONTROL, 32; or CCSCBCTL, CCSCBEN|CCSCBRESET; test CCSCBCTL, CCSCBDONE jz .; - } else { - mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; - cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; + } + if ((p->features & AHC_ULTRA2) != 0) { + if ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0) { + mvi CCSCBCTL, CCARREN|CCSCBRESET; + cmp CCSCBCTL, ARRDONE|CCARREN jne .; + mvi CCHCNT, 32; + mvi CCSCBCTL, CCSCBEN|CCSCBRESET; + cmp CCSCBCTL, CCSCBDONE|CCSCBEN jne .; + } else { + mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; + cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; + } } dma_scb_finish: clr CCSCBCTL; test CCSCBCTL, CCARREN|CCSCBEN jnz .; ret; - } else { + } + if ((p->features & AHC_CMD_CHAN) == 0) { mvi DINDEX, HADDR; mvi HSCB_ADDR call set_32byte_addr; mvi HCNT[0], 32; @@ -1342,17 +1406,81 @@ mov DFDAT,SINDIR; cmp SINDEX, A jne copy_scb_tofifo_loop; or DFCNTRL, HDMAEN|FIFOFLUSH; + jmp dma_finish; dma_scb_fromhost: - call dma_finish; - /* If we were putting the SCB, we are done */ - test DMAPARAMS, DIRECTION jz return; - mvi SCB_CONTROL call dfdat_in_7; - call dfdat_in_7_continued; - call dfdat_in_7_continued; - jmp dfdat_in_7_continued; + mvi DINDEX, SCB_CONTROL; + if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) { + /* + * Set the A to -24. It it hits 0, then we let + * our code fall through to dfdat_in_8 to complete + * the last of the copy. + * + * Also, things happen 8 bytes at a time in this + * case, so we may need to drain the fifo at most + * 3 times to keep things flowing + */ + mvi A, -24; +dma_scb_hang_fifo: + /* Wait for the first bit of data to hit the fifo */ + test DFSTATUS, FIFOEMP jnz .; +dma_scb_hang_wait: + /* OK, now they've started to transfer into the fifo, + * so wait for them to stop trying to transfer any + * more data. + */ + test DFSTATUS, MREQPEND jnz .; + /* + * OK, they started, then they stopped, now see if they + * managed to complete the job before stopping. Try + * it multiple times to give the chip a few cycles to + * set the flag if it did complete. + */ + test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; + test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; + test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; + /* + * Too bad, the chip didn't complete the DMA, but there + * aren't any more memory requests pending, so that + * means it stopped part way through and hung. That's + * our bug, so now we drain what data there is in the + * fifo in order to get things going again. + */ +dma_scb_hang_empty_fifo: + call dfdat_in_8; + add A, 8; + add SINDEX, A, HCNT; + /* + * If there are another 8 bytes of data waiting in the + * fifo, then the carry bit will be set as a result + * of the above add command (unless A is non-negative, + * in which case the carry bit won't be set). + */ + jc dma_scb_hang_empty_fifo; + /* + * We've emptied the fifo now, but we wouldn't have got + * here if the memory transfer hadn't stopped part way + * through, so go back up to the beginning of the + * loop and start over. When it succeeds in getting + * all the data down, HDONE will be set and we'll + * jump to the code just below here. + */ + jmp dma_scb_hang_fifo; +dma_scb_hang_dma_done: + and DFCNTRL, ~HDMAEN; + test DFCNTRL, HDMAEN jnz .; + call dfdat_in_8; + add A, 8; + cmp A, 8 jne . - 2; + ret; + } else { + call dma_finish; + call dfdat_in_8; + call dfdat_in_8; + call dfdat_in_8; + } +dfdat_in_8: + mov DINDIR,DFDAT; dfdat_in_7: - mov DINDEX,SINDEX; -dfdat_in_7_continued: mov DINDIR,DFDAT; mov DINDIR,DFDAT; mov DINDIR,DFDAT; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx_old/aic7xxx_proc.c linux.ac/drivers/scsi/aic7xxx_old/aic7xxx_proc.c --- linux.vanilla/drivers/scsi/aic7xxx_old/aic7xxx_proc.c Tue Apr 3 17:32:19 2001 +++ linux.ac/drivers/scsi/aic7xxx_old/aic7xxx_proc.c Tue Apr 3 17:55:02 2001 @@ -162,7 +162,7 @@ size += sprintf(BLS, "%s", AIC7XXX_H_VERSION); size += sprintf(BLS, "\n"); size += sprintf(BLS, "Compile Options:\n"); -#ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT +#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT size += sprintf(BLS, " TCQ Enabled By Default : Enabled\n"); #else size += sprintf(BLS, " TCQ Enabled By Default : Disabled\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx_old/aic7xxx_reg.h linux.ac/drivers/scsi/aic7xxx_old/aic7xxx_reg.h --- linux.vanilla/drivers/scsi/aic7xxx_old/aic7xxx_reg.h Tue Apr 3 17:32:19 2001 +++ linux.ac/drivers/scsi/aic7xxx_old/aic7xxx_reg.h Tue Apr 3 17:55:02 2001 @@ -188,8 +188,8 @@ #define BRDRW 0x04 #define BRDRW_ULTRA2 0x02 #define BRDCTL1 0x02 -#define BRDCTL0 0x01 #define BRDSTB_ULTRA2 0x01 +#define BRDCTL0 0x01 #define SEECTL 0x1e #define EXTARBACK 0x80 @@ -397,7 +397,7 @@ #define DATA_OVERRUN 0xe1 #define MSGIN_PHASEMIS 0xd1 #define TRACEPOINT2 0xc1 -#define TRACEPOINT 0xb1 +#define SEQ_SG_FIXUP 0xb1 #define AWAITING_MSG 0xa1 #define RESIDUAL 0x81 #define BAD_STATUS 0x71 @@ -465,8 +465,6 @@ #define TARGCRCENDEN 0x08 #define TARGCRCCNTEN 0x04 -#define QOUTCNT 0x9e - #define SCSIPHASE 0x9e #define SP_STATUS 0x20 #define SP_COMMAND 0x10 @@ -475,6 +473,8 @@ #define SP_DATA_IN 0x02 #define SP_DATA_OUT 0x01 +#define QOUTCNT 0x9e + #define SFUNCT 0x9f #define ALT_MODE 0x80 @@ -595,8 +595,8 @@ #define RD_DFTHRSH_63 0x03 #define RD_DFTHRSH_50 0x02 #define RD_DFTHRSH_25 0x01 -#define RD_DFTHRSH_MIN 0x00 #define WR_DFTHRSH_MIN 0x00 +#define RD_DFTHRSH_MIN 0x00 #define SG_CACHEPTR 0xfc #define SG_USER_DATA 0xfc @@ -604,18 +604,18 @@ #define LAST_SEG_DONE 0x01 -#define CMD_GROUP_CODE_SHIFT 0x05 -#define BUS_8_BIT 0x00 -#define QOUTFIFO_OFFSET 0x01 -#define CCSGRAM_MAXSEGS 0x10 #define CMD_GROUP2_BYTE_DELTA 0xfa #define MAX_OFFSET_8BIT 0x0f #define BUS_16_BIT 0x01 #define QINFIFO_OFFSET 0x02 #define CMD_GROUP5_BYTE_DELTA 0x0b +#define CMD_GROUP_CODE_SHIFT 0x05 #define MAX_OFFSET_ULTRA2 0x7f #define MAX_OFFSET_16BIT 0x08 +#define BUS_8_BIT 0x00 +#define QOUTFIFO_OFFSET 0x01 #define UNTAGGEDSCB_OFFSET 0x00 +#define CCSGRAM_MAXSEGS 0x10 #define SCB_LIST_NULL 0xff #define SG_SIZEOF 0x08 #define CMD_GROUP4_BYTE_DELTA 0x04 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx_old/aic7xxx_seq.c linux.ac/drivers/scsi/aic7xxx_old/aic7xxx_seq.c --- linux.vanilla/drivers/scsi/aic7xxx_old/aic7xxx_seq.c Tue Apr 3 17:32:19 2001 +++ linux.ac/drivers/scsi/aic7xxx_old/aic7xxx_seq.c Tue Apr 3 17:55:02 2001 @@ -25,12 +25,12 @@ 0x00, 0x4d, 0x10, 0x70, 0x01, 0x4e, 0x9c, 0x18, 0xbf, 0x60, 0xc0, 0x08, - 0x00, 0x6a, 0x3e, 0x5c, + 0x00, 0x6a, 0x86, 0x5c, 0xff, 0x4e, 0xc8, 0x18, - 0x02, 0x6a, 0x54, 0x5b, + 0x02, 0x6a, 0x70, 0x5b, 0xff, 0x52, 0x20, 0x09, 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0x52, 0xca, 0x5b, + 0x00, 0x52, 0xe6, 0x5b, 0x03, 0xb0, 0x52, 0x31, 0xff, 0xb0, 0x52, 0x09, 0xff, 0xb1, 0x54, 0x09, @@ -87,13 +87,13 @@ 0x08, 0x6a, 0x66, 0x58, 0x80, 0x6a, 0x68, 0x00, 0x80, 0x36, 0x6c, 0x00, - 0x00, 0x65, 0x9e, 0x5b, + 0x00, 0x65, 0xba, 0x5b, 0xff, 0x3d, 0xc8, 0x08, 0xbf, 0x64, 0xe2, 0x78, - 0x80, 0x64, 0xac, 0x71, - 0xa0, 0x64, 0xdc, 0x71, - 0xc0, 0x64, 0xd4, 0x71, - 0xe0, 0x64, 0x1c, 0x72, + 0x80, 0x64, 0xc8, 0x71, + 0xa0, 0x64, 0xf8, 0x71, + 0xc0, 0x64, 0xf0, 0x71, + 0xe0, 0x64, 0x38, 0x72, 0x01, 0x6a, 0x22, 0x01, 0x00, 0x65, 0xaa, 0x40, 0xf7, 0x11, 0x22, 0x08, @@ -113,24 +113,24 @@ 0x03, 0xa9, 0x18, 0x31, 0x03, 0xa9, 0x10, 0x30, 0x08, 0x6a, 0xcc, 0x00, - 0xa9, 0x6a, 0xb4, 0x5b, + 0xa9, 0x6a, 0xd0, 0x5b, 0x00, 0x65, 0x02, 0x41, 0xa8, 0x6a, 0x6a, 0x00, 0x79, 0x6a, 0x6a, 0x00, 0x40, 0x3d, 0xea, 0x68, 0x04, 0x35, 0x6a, 0x00, - 0x00, 0x65, 0x0e, 0x5b, + 0x00, 0x65, 0x2a, 0x5b, 0x80, 0x6a, 0xd4, 0x01, 0x10, 0x36, 0xd6, 0x68, 0x10, 0x36, 0x6c, 0x00, 0x07, 0xac, 0x10, 0x31, - 0x03, 0x8c, 0x10, 0x30, 0x05, 0xa3, 0x70, 0x30, + 0x03, 0x8c, 0x10, 0x30, 0x88, 0x6a, 0xcc, 0x00, - 0xac, 0x6a, 0xac, 0x5b, - 0x00, 0x65, 0xa6, 0x5b, + 0xac, 0x6a, 0xc8, 0x5b, + 0x00, 0x65, 0xc2, 0x5b, 0x38, 0x6a, 0xcc, 0x00, - 0xa3, 0x6a, 0xb0, 0x5b, + 0xa3, 0x6a, 0xcc, 0x5b, 0xff, 0x38, 0x12, 0x69, 0x80, 0x02, 0x04, 0x00, 0xe7, 0x35, 0x6a, 0x08, @@ -139,334 +139,348 @@ 0xff, 0x6a, 0x10, 0x00, 0xff, 0x6a, 0x12, 0x00, 0xff, 0x6a, 0x14, 0x00, - 0x01, 0x38, 0x18, 0x61, + 0x22, 0x38, 0xc8, 0x28, + 0x01, 0x38, 0x1c, 0x61, + 0x02, 0x64, 0xc8, 0x00, + 0x01, 0x38, 0x1c, 0x61, 0xbf, 0x35, 0x6a, 0x08, - 0x02, 0x6a, 0xf8, 0x01, - 0xff, 0x69, 0xca, 0x08, + 0xff, 0x64, 0xf8, 0x09, 0xff, 0x35, 0x26, 0x09, - 0x04, 0x0b, 0x1c, 0x69, - 0x04, 0x0b, 0x28, 0x69, - 0x10, 0x0c, 0x1e, 0x79, - 0x04, 0x0b, 0x28, 0x69, - 0xff, 0x6a, 0xca, 0x08, - 0x00, 0x35, 0xee, 0x5a, - 0x80, 0x02, 0x7c, 0x69, - 0xff, 0x65, 0x6c, 0x79, + 0x80, 0x02, 0xa4, 0x69, + 0x10, 0x0c, 0x7a, 0x69, + 0x80, 0x94, 0x22, 0x79, + 0x00, 0x35, 0x0a, 0x5b, + 0x80, 0x02, 0xa4, 0x69, + 0xff, 0x65, 0x94, 0x79, + 0x01, 0x38, 0x70, 0x71, 0xff, 0x38, 0x70, 0x18, - 0xff, 0x38, 0x6c, 0x79, - 0x80, 0xea, 0x48, 0x61, + 0xff, 0x38, 0x94, 0x79, + 0x80, 0xea, 0x4a, 0x61, 0xef, 0x38, 0xc8, 0x18, 0x80, 0x6a, 0xc8, 0x00, - 0x00, 0x65, 0x3a, 0x49, + 0x00, 0x65, 0x3c, 0x49, 0x33, 0x38, 0xc8, 0x28, 0xff, 0x64, 0xd0, 0x09, 0x04, 0x39, 0xc0, 0x31, 0x09, 0x6a, 0xd6, 0x01, - 0x80, 0xeb, 0x40, 0x79, + 0x80, 0xeb, 0x42, 0x79, 0xf7, 0xeb, 0xd6, 0x09, - 0x08, 0xeb, 0x44, 0x69, + 0x08, 0xeb, 0x46, 0x69, 0x01, 0x6a, 0xd6, 0x01, 0x08, 0xe9, 0x10, 0x31, 0x03, 0x8c, 0x10, 0x30, + 0xff, 0x38, 0x70, 0x18, 0x88, 0x6a, 0xcc, 0x00, - 0x39, 0x6a, 0xb2, 0x5b, + 0x39, 0x6a, 0xce, 0x5b, 0x08, 0x6a, 0x18, 0x01, 0xff, 0x6a, 0x1a, 0x09, 0xff, 0x6a, 0x1c, 0x09, 0x0d, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x30, 0x5c, - 0x88, 0x6a, 0x20, 0x5c, - 0x00, 0x65, 0xa6, 0x5b, + 0x00, 0x65, 0x78, 0x5c, + 0x88, 0x6a, 0xcc, 0x00, + 0x00, 0x65, 0x6a, 0x5c, + 0x00, 0x65, 0xc2, 0x5b, 0xff, 0x6a, 0xc8, 0x08, 0x08, 0x39, 0x72, 0x18, 0x00, 0x3a, 0x74, 0x20, - 0x01, 0x0c, 0x64, 0x79, + 0x00, 0x65, 0x02, 0x41, + 0x01, 0x0c, 0x6c, 0x79, 0x10, 0x0c, 0x02, 0x79, - 0xff, 0x35, 0x26, 0x09, - 0x04, 0x0b, 0x6a, 0x69, - 0x00, 0x65, 0x84, 0x59, + 0x10, 0x0c, 0x7a, 0x69, + 0x01, 0xfc, 0x70, 0x79, + 0xff, 0x6a, 0x70, 0x08, + 0x01, 0x0c, 0x76, 0x79, + 0x10, 0x0c, 0x02, 0x79, + 0x00, 0x65, 0xae, 0x59, + 0x01, 0xfc, 0x94, 0x69, + 0x40, 0x0d, 0x84, 0x69, + 0xb1, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0x94, 0x41, + 0x2e, 0xfc, 0xa2, 0x28, + 0x3f, 0x38, 0xc8, 0x08, + 0x00, 0x51, 0x94, 0x71, + 0xff, 0x6a, 0xc8, 0x08, + 0xf8, 0x39, 0x72, 0x18, + 0xff, 0x3a, 0x74, 0x20, + 0x01, 0x38, 0x70, 0x18, + 0x00, 0x65, 0x86, 0x41, 0x03, 0x08, 0x52, 0x31, 0xff, 0x38, 0x50, 0x09, + 0x12, 0x01, 0x02, 0x00, 0xff, 0x08, 0x52, 0x09, 0xff, 0x09, 0x54, 0x09, 0xff, 0x0a, 0x56, 0x09, 0xff, 0x38, 0x50, 0x09, 0x00, 0x65, 0xaa, 0x40, - 0x00, 0x65, 0x84, 0x59, + 0x10, 0x0c, 0xa4, 0x79, + 0x00, 0x65, 0xae, 0x59, 0x7f, 0x02, 0x04, 0x08, 0xe1, 0x6a, 0x22, 0x01, 0x00, 0x65, 0xaa, 0x40, - 0x04, 0x93, 0x9a, 0x69, + 0x04, 0x93, 0xc2, 0x69, 0xdf, 0x93, 0x26, 0x09, - 0x20, 0x93, 0x88, 0x69, + 0x20, 0x93, 0xb2, 0x69, 0x02, 0x93, 0x26, 0x01, - 0x01, 0x94, 0x8a, 0x79, - 0x01, 0x94, 0x8a, 0x79, - 0x01, 0x94, 0x8a, 0x79, - 0x01, 0x94, 0x8a, 0x79, - 0x01, 0x94, 0x8a, 0x79, - 0x01, 0x94, 0x8a, 0x79, - 0x10, 0x94, 0x98, 0x69, - 0x7f, 0x05, 0xa0, 0x69, - 0x02, 0x03, 0xa0, 0x79, - 0x11, 0x0c, 0x9c, 0x79, + 0x01, 0x94, 0xb6, 0x79, + 0x01, 0x94, 0xb6, 0x79, + 0x01, 0x94, 0xb6, 0x79, + 0x01, 0x94, 0xb6, 0x79, + 0x01, 0x94, 0xb6, 0x79, + 0x10, 0x94, 0xc0, 0x69, 0xd7, 0x93, 0x26, 0x09, - 0x28, 0x93, 0xa2, 0x69, - 0x03, 0x08, 0x52, 0x31, - 0xff, 0x38, 0x50, 0x09, - 0x12, 0x01, 0x02, 0x00, + 0x28, 0x93, 0xc4, 0x69, 0xff, 0x6a, 0xd4, 0x0c, - 0x00, 0x65, 0x0e, 0x5b, + 0x00, 0x65, 0x2a, 0x5b, 0x05, 0xb4, 0x10, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x03, 0x8c, 0x10, 0x30, 0x88, 0x6a, 0xcc, 0x00, - 0xb4, 0x6a, 0xb0, 0x5b, + 0xb4, 0x6a, 0xcc, 0x5b, 0xff, 0x6a, 0x1a, 0x09, 0xff, 0x6a, 0x1c, 0x09, - 0x00, 0x65, 0xa6, 0x5b, - 0x3d, 0x6a, 0xee, 0x5a, + 0x00, 0x65, 0xc2, 0x5b, + 0x3d, 0x6a, 0x0a, 0x5b, 0xac, 0x6a, 0x26, 0x01, - 0x04, 0x0b, 0xc2, 0x69, - 0x04, 0x0b, 0xc8, 0x69, - 0x10, 0x0c, 0xc4, 0x79, - 0x02, 0x03, 0xcc, 0x79, - 0x11, 0x0c, 0xc8, 0x79, + 0x04, 0x0b, 0xde, 0x69, + 0x04, 0x0b, 0xe4, 0x69, + 0x10, 0x0c, 0xe0, 0x79, + 0x02, 0x03, 0xe8, 0x79, + 0x11, 0x0c, 0xe4, 0x79, 0xd7, 0x93, 0x26, 0x09, - 0x28, 0x93, 0xce, 0x69, + 0x28, 0x93, 0xea, 0x69, 0x12, 0x01, 0x02, 0x00, 0x00, 0x65, 0xaa, 0x40, - 0x00, 0x65, 0x0e, 0x5b, + 0x00, 0x65, 0x2a, 0x5b, 0xff, 0x06, 0x44, 0x09, 0x00, 0x65, 0xaa, 0x40, 0x10, 0x3d, 0x06, 0x00, 0xff, 0x34, 0xca, 0x08, - 0x80, 0x65, 0x00, 0x62, + 0x80, 0x65, 0x1c, 0x62, 0x0f, 0xa1, 0xca, 0x08, 0x07, 0xa1, 0xca, 0x08, 0x40, 0xa0, 0xc8, 0x08, 0x00, 0x65, 0xca, 0x00, 0x80, 0x65, 0xca, 0x00, - 0x80, 0xa0, 0xf0, 0x79, + 0x80, 0xa0, 0x0c, 0x7a, 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0x02, 0x42, - 0x20, 0xa0, 0x08, 0x7a, + 0x00, 0x65, 0x1e, 0x42, + 0x20, 0xa0, 0x24, 0x7a, 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0x9e, 0x5b, - 0xa0, 0x3d, 0x10, 0x62, + 0x00, 0x65, 0xba, 0x5b, + 0xa0, 0x3d, 0x2c, 0x62, 0x23, 0xa0, 0x0c, 0x08, - 0x00, 0x65, 0x9e, 0x5b, - 0xa0, 0x3d, 0x10, 0x62, - 0x00, 0xb9, 0x08, 0x42, - 0xff, 0x65, 0x08, 0x62, + 0x00, 0x65, 0xba, 0x5b, + 0xa0, 0x3d, 0x2c, 0x62, + 0x00, 0xb9, 0x24, 0x42, + 0xff, 0x65, 0x24, 0x62, 0xa1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, - 0x10, 0x51, 0x10, 0x72, + 0x10, 0x51, 0x2c, 0x72, 0x40, 0x6a, 0x18, 0x00, 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0x9e, 0x5b, - 0xa0, 0x3d, 0xda, 0x71, + 0x00, 0x65, 0xba, 0x5b, + 0xa0, 0x3d, 0xf6, 0x71, 0x40, 0x6a, 0x18, 0x00, 0xff, 0x34, 0xa6, 0x08, - 0x80, 0x34, 0x18, 0x62, + 0x80, 0x34, 0x34, 0x62, 0x7f, 0xa0, 0x40, 0x09, 0x08, 0x6a, 0x68, 0x00, 0x00, 0x65, 0xaa, 0x40, - 0x64, 0x6a, 0xe4, 0x5a, - 0x80, 0x64, 0x8e, 0x6a, - 0x04, 0x64, 0x70, 0x72, - 0x02, 0x64, 0x76, 0x72, - 0x00, 0x6a, 0x38, 0x72, - 0x03, 0x64, 0x8a, 0x72, - 0x01, 0x64, 0x6c, 0x72, - 0x07, 0x64, 0xcc, 0x72, - 0x08, 0x64, 0x34, 0x72, - 0x23, 0x64, 0xd0, 0x72, + 0x64, 0x6a, 0x00, 0x5b, + 0x80, 0x64, 0xaa, 0x6a, + 0x04, 0x64, 0x8c, 0x72, + 0x02, 0x64, 0x92, 0x72, + 0x00, 0x6a, 0x54, 0x72, + 0x03, 0x64, 0xa6, 0x72, + 0x01, 0x64, 0x88, 0x72, + 0x07, 0x64, 0xe8, 0x72, + 0x08, 0x64, 0x50, 0x72, + 0x23, 0x64, 0xec, 0x72, 0x11, 0x6a, 0x22, 0x01, - 0x07, 0x6a, 0xd6, 0x5a, + 0x07, 0x6a, 0xf2, 0x5a, 0xff, 0x06, 0xd4, 0x08, 0x00, 0x65, 0xaa, 0x40, - 0xff, 0xa8, 0x3c, 0x6a, - 0xff, 0xa2, 0x54, 0x7a, + 0xff, 0xa8, 0x58, 0x6a, + 0xff, 0xa2, 0x70, 0x7a, 0x01, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0xca, 0x5b, - 0xff, 0xa2, 0x54, 0x7a, + 0x00, 0xb9, 0xe6, 0x5b, + 0xff, 0xa2, 0x70, 0x7a, 0x71, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, - 0x40, 0x51, 0x54, 0x62, + 0x40, 0x51, 0x70, 0x62, 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0xca, 0x5b, + 0x00, 0xb9, 0xe6, 0x5b, 0xff, 0x3e, 0x74, 0x09, 0xff, 0x90, 0x7c, 0x08, 0x00, 0x65, 0x4e, 0x58, 0x00, 0x65, 0xbc, 0x40, - 0x20, 0xa0, 0x5c, 0x6a, + 0x20, 0xa0, 0x78, 0x6a, 0xff, 0x37, 0xc8, 0x08, - 0x00, 0x6a, 0x74, 0x5b, - 0xff, 0x6a, 0x8a, 0x5b, + 0x00, 0x6a, 0x90, 0x5b, + 0xff, 0x6a, 0xa6, 0x5b, 0xff, 0xf8, 0xc8, 0x08, 0xff, 0x4f, 0xc8, 0x08, - 0x01, 0x6a, 0x74, 0x5b, - 0x00, 0xb9, 0x8a, 0x5b, + 0x01, 0x6a, 0x90, 0x5b, + 0x00, 0xb9, 0xa6, 0x5b, 0x01, 0x4f, 0x9e, 0x18, 0x02, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x38, 0x5c, + 0x00, 0x65, 0x80, 0x5c, 0x00, 0x65, 0xbc, 0x40, 0x41, 0x6a, 0x22, 0x01, 0x00, 0x65, 0xaa, 0x40, 0x04, 0xa0, 0x40, 0x01, - 0x00, 0x65, 0x50, 0x5c, + 0x00, 0x65, 0x98, 0x5c, 0x00, 0x65, 0xbc, 0x40, - 0x10, 0x36, 0x34, 0x7a, + 0x10, 0x36, 0x50, 0x7a, 0x05, 0x38, 0x46, 0x31, 0x04, 0x14, 0x58, 0x31, 0x03, 0xa9, 0x60, 0x31, 0xa3, 0x6a, 0xcc, 0x00, - 0x38, 0x6a, 0xb0, 0x5b, + 0x38, 0x6a, 0xcc, 0x5b, 0xac, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xb2, 0x5b, - 0xa9, 0x6a, 0xb4, 0x5b, - 0x00, 0x65, 0x34, 0x42, + 0x14, 0x6a, 0xce, 0x5b, + 0xa9, 0x6a, 0xd0, 0x5b, + 0x00, 0x65, 0x50, 0x42, 0xef, 0x36, 0x6c, 0x08, - 0x00, 0x65, 0x34, 0x42, + 0x00, 0x65, 0x50, 0x42, 0x0f, 0x64, 0xc8, 0x08, 0x07, 0x64, 0xc8, 0x08, 0x00, 0x37, 0x6e, 0x00, 0xff, 0x6a, 0xa4, 0x00, - 0x00, 0x65, 0x44, 0x5b, - 0xff, 0x51, 0xa0, 0x72, - 0x20, 0x36, 0xaa, 0x7a, - 0x00, 0x90, 0x32, 0x5b, - 0x00, 0x65, 0xac, 0x42, + 0x00, 0x65, 0x60, 0x5b, + 0xff, 0x51, 0xbc, 0x72, + 0x20, 0x36, 0xc6, 0x7a, + 0x00, 0x90, 0x4e, 0x5b, + 0x00, 0x65, 0xc8, 0x42, 0xff, 0x06, 0xd4, 0x08, - 0x00, 0x65, 0x9e, 0x5b, - 0xe0, 0x3d, 0xc6, 0x62, - 0x20, 0x12, 0xc6, 0x62, - 0x51, 0x6a, 0xda, 0x5a, - 0x00, 0x65, 0x2c, 0x5b, + 0x00, 0x65, 0xba, 0x5b, + 0xe0, 0x3d, 0xe2, 0x62, + 0x20, 0x12, 0xe2, 0x62, + 0x51, 0x6a, 0xf6, 0x5a, + 0x00, 0x65, 0x48, 0x5b, 0xff, 0x37, 0xc8, 0x08, - 0x00, 0xa1, 0xbe, 0x62, - 0x04, 0xa0, 0xbe, 0x7a, + 0x00, 0xa1, 0xda, 0x62, + 0x04, 0xa0, 0xda, 0x7a, 0xfb, 0xa0, 0x40, 0x09, 0x80, 0x36, 0x6c, 0x00, - 0x80, 0xa0, 0x34, 0x7a, + 0x80, 0xa0, 0x50, 0x7a, 0x7f, 0xa0, 0x40, 0x09, - 0xff, 0x6a, 0xd6, 0x5a, - 0x00, 0x65, 0x34, 0x42, - 0x04, 0xa0, 0xc4, 0x7a, - 0x00, 0x65, 0x50, 0x5c, - 0x00, 0x65, 0xc6, 0x42, - 0x00, 0x65, 0x38, 0x5c, + 0xff, 0x6a, 0xf2, 0x5a, + 0x00, 0x65, 0x50, 0x42, + 0x04, 0xa0, 0xe0, 0x7a, + 0x00, 0x65, 0x98, 0x5c, + 0x00, 0x65, 0xe2, 0x42, + 0x00, 0x65, 0x80, 0x5c, 0x31, 0x6a, 0x22, 0x01, - 0x0c, 0x6a, 0xd6, 0x5a, - 0x00, 0x65, 0x34, 0x42, + 0x0c, 0x6a, 0xf2, 0x5a, + 0x00, 0x65, 0x50, 0x42, 0x61, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x34, 0x42, - 0x51, 0x6a, 0xda, 0x5a, + 0x00, 0x65, 0x50, 0x42, + 0x51, 0x6a, 0xf6, 0x5a, 0x51, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x34, 0x42, + 0x00, 0x65, 0x50, 0x42, 0x10, 0x3d, 0x06, 0x00, 0xff, 0x65, 0x68, 0x0c, 0xff, 0x06, 0xd4, 0x08, - 0x01, 0x0c, 0xdc, 0x7a, - 0x04, 0x0c, 0xde, 0x6a, + 0x01, 0x0c, 0xf8, 0x7a, + 0x04, 0x0c, 0xfa, 0x6a, 0xe0, 0x03, 0x7a, 0x08, - 0xe0, 0x3d, 0xea, 0x62, + 0xe0, 0x3d, 0x06, 0x63, 0xff, 0x65, 0xcc, 0x08, 0xff, 0x12, 0xda, 0x0c, 0xff, 0x06, 0xd4, 0x0c, 0xd1, 0x6a, 0x22, 0x01, 0x00, 0x65, 0xaa, 0x40, 0xff, 0x65, 0x26, 0x09, - 0x01, 0x0b, 0xfe, 0x6a, - 0x10, 0x0c, 0xf0, 0x7a, - 0x04, 0x0b, 0xf8, 0x6a, + 0x01, 0x0b, 0x1a, 0x6b, + 0x10, 0x0c, 0x0c, 0x7b, + 0x04, 0x0b, 0x14, 0x6b, 0xff, 0x6a, 0xca, 0x08, - 0x04, 0x93, 0xfc, 0x6a, - 0x01, 0x94, 0xfa, 0x7a, - 0x10, 0x94, 0xfc, 0x6a, - 0x80, 0x3d, 0x02, 0x73, - 0x0f, 0x04, 0x06, 0x6b, - 0x02, 0x03, 0x06, 0x7b, - 0x11, 0x0c, 0x02, 0x7b, + 0x04, 0x93, 0x18, 0x6b, + 0x01, 0x94, 0x16, 0x7b, + 0x10, 0x94, 0x18, 0x6b, + 0x80, 0x3d, 0x1e, 0x73, + 0x0f, 0x04, 0x22, 0x6b, + 0x02, 0x03, 0x22, 0x7b, + 0x11, 0x0c, 0x1e, 0x7b, 0xc7, 0x93, 0x26, 0x09, 0xff, 0x99, 0xd4, 0x08, - 0x38, 0x93, 0x08, 0x6b, + 0x38, 0x93, 0x24, 0x6b, 0xff, 0x6a, 0xd4, 0x0c, - 0x80, 0x36, 0x0c, 0x6b, + 0x80, 0x36, 0x28, 0x6b, 0x21, 0x6a, 0x22, 0x05, 0xff, 0x65, 0x20, 0x09, - 0xff, 0x51, 0x1a, 0x63, + 0xff, 0x51, 0x36, 0x63, 0xff, 0x37, 0xc8, 0x08, - 0xa1, 0x6a, 0x26, 0x43, + 0xa1, 0x6a, 0x42, 0x43, 0xff, 0x51, 0xc8, 0x08, - 0xb9, 0x6a, 0x26, 0x43, + 0xb9, 0x6a, 0x42, 0x43, 0xff, 0x90, 0xa4, 0x08, - 0xff, 0xba, 0x2a, 0x73, + 0xff, 0xba, 0x46, 0x73, 0xff, 0xba, 0x20, 0x09, 0xff, 0x65, 0xca, 0x18, - 0x00, 0x6c, 0x1e, 0x63, + 0x00, 0x6c, 0x3a, 0x63, 0xff, 0x90, 0xca, 0x0c, 0xff, 0x6a, 0xca, 0x04, - 0x20, 0x36, 0x3e, 0x7b, - 0x00, 0x90, 0x12, 0x5b, - 0xff, 0x65, 0x3e, 0x73, - 0xff, 0x52, 0x3c, 0x73, + 0x20, 0x36, 0x5a, 0x7b, + 0x00, 0x90, 0x2e, 0x5b, + 0xff, 0x65, 0x5a, 0x73, + 0xff, 0x52, 0x58, 0x73, 0xff, 0xba, 0xcc, 0x08, 0xff, 0x52, 0x20, 0x09, 0xff, 0x66, 0x74, 0x09, 0xff, 0x65, 0x20, 0x0d, 0xff, 0xba, 0x7e, 0x0c, - 0x00, 0x6a, 0x3e, 0x5c, + 0x00, 0x6a, 0x86, 0x5c, 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0x51, 0xca, 0x43, - 0xff, 0x3f, 0x98, 0x73, + 0x00, 0x51, 0xe6, 0x43, + 0xff, 0x3f, 0xb4, 0x73, 0xff, 0x6a, 0xa2, 0x00, - 0x00, 0x3f, 0x12, 0x5b, - 0xff, 0x65, 0x98, 0x73, + 0x00, 0x3f, 0x2e, 0x5b, + 0xff, 0x65, 0xb4, 0x73, 0x20, 0x36, 0x6c, 0x00, - 0x20, 0xa0, 0x52, 0x6b, + 0x20, 0xa0, 0x6e, 0x6b, 0xff, 0xb9, 0xa2, 0x0c, 0xff, 0x6a, 0xa2, 0x04, 0xff, 0x65, 0xa4, 0x08, 0xe0, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xbe, 0x5b, + 0x45, 0x6a, 0xda, 0x5b, 0x01, 0x6a, 0xd0, 0x01, 0x09, 0x6a, 0xd6, 0x01, - 0x80, 0xeb, 0x5e, 0x7b, + 0x80, 0xeb, 0x7a, 0x7b, 0x01, 0x6a, 0xd6, 0x01, 0x01, 0xe9, 0xa4, 0x34, 0x88, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xbe, 0x5b, + 0x45, 0x6a, 0xda, 0x5b, 0x01, 0x6a, 0x18, 0x01, 0xff, 0x6a, 0x1a, 0x09, 0xff, 0x6a, 0x1c, 0x09, 0x0d, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0x30, 0x5c, + 0x00, 0x65, 0x78, 0x5c, 0xff, 0x99, 0xa4, 0x0c, 0xff, 0x65, 0xa4, 0x08, 0xe0, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xbe, 0x5b, + 0x45, 0x6a, 0xda, 0x5b, 0x01, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x05, 0x88, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xbe, 0x5b, + 0x45, 0x6a, 0xda, 0x5b, 0x01, 0x6a, 0x18, 0x01, 0xff, 0x6a, 0x1a, 0x09, 0xff, 0x6a, 0x1c, 0x09, 0x01, 0x6a, 0x26, 0x05, 0x01, 0x65, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0x8e, 0x7b, + 0x80, 0xee, 0xaa, 0x7b, 0xff, 0x6a, 0xdc, 0x0d, 0xff, 0x65, 0x32, 0x09, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x30, 0x44, + 0x00, 0x65, 0x78, 0x44, 0xff, 0x37, 0xc8, 0x08, - 0x00, 0x6a, 0x54, 0x5b, + 0x00, 0x6a, 0x70, 0x5b, 0xff, 0x52, 0xa2, 0x0c, - 0x01, 0x0c, 0x9e, 0x7b, - 0x04, 0x0c, 0x9e, 0x6b, + 0x01, 0x0c, 0xba, 0x7b, + 0x04, 0x0c, 0xba, 0x6b, 0xe0, 0x03, 0x06, 0x08, 0xe0, 0x03, 0x7a, 0x0c, 0xff, 0x8c, 0x10, 0x08, @@ -489,29 +503,34 @@ 0x00, 0x6c, 0xda, 0x24, 0xff, 0x65, 0xc8, 0x08, 0xe0, 0x6a, 0xcc, 0x00, - 0x41, 0x6a, 0xba, 0x5b, + 0x41, 0x6a, 0xd6, 0x5b, 0xff, 0x90, 0xe2, 0x09, 0x20, 0x6a, 0xd0, 0x01, - 0x04, 0x35, 0xdc, 0x7b, + 0x04, 0x35, 0xf8, 0x7b, 0x1d, 0x6a, 0xdc, 0x01, - 0xdc, 0xee, 0xd8, 0x63, - 0x00, 0x65, 0xe8, 0x43, + 0xdc, 0xee, 0xf4, 0x63, + 0x00, 0x65, 0x0e, 0x44, 0x01, 0x6a, 0xdc, 0x01, 0x20, 0xa0, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xe2, 0x7b, + 0x80, 0xee, 0xfe, 0x7b, + 0x11, 0x6a, 0xdc, 0x01, + 0x50, 0xee, 0x02, 0x64, + 0x20, 0x6a, 0xd0, 0x01, + 0x09, 0x6a, 0xdc, 0x01, + 0x88, 0xee, 0x08, 0x64, 0x19, 0x6a, 0xdc, 0x01, - 0xd8, 0xee, 0xe6, 0x63, + 0xd8, 0xee, 0x0c, 0x64, 0xff, 0x6a, 0xdc, 0x09, - 0x18, 0xee, 0xea, 0x6b, + 0x18, 0xee, 0x10, 0x6c, 0xff, 0x6a, 0xd4, 0x0c, 0x88, 0x6a, 0xcc, 0x00, - 0x41, 0x6a, 0xba, 0x5b, + 0x41, 0x6a, 0xd6, 0x5b, 0x20, 0x6a, 0x18, 0x01, 0xff, 0x6a, 0x1a, 0x09, 0xff, 0x6a, 0x1c, 0x09, 0xff, 0x35, 0x26, 0x09, - 0x04, 0x35, 0x14, 0x6c, + 0x04, 0x35, 0x3c, 0x6c, 0xa0, 0x6a, 0xca, 0x00, 0x20, 0x65, 0xc8, 0x18, 0xff, 0x6c, 0x32, 0x09, @@ -522,15 +541,32 @@ 0xff, 0x6c, 0x32, 0x09, 0xff, 0x6c, 0x32, 0x09, 0xff, 0x6c, 0x32, 0x09, - 0x00, 0x65, 0x00, 0x64, + 0x00, 0x65, 0x26, 0x64, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x30, 0x5c, - 0x04, 0x35, 0x0c, 0x7b, - 0xa0, 0x6a, 0x20, 0x5c, - 0x00, 0x65, 0x22, 0x5c, - 0x00, 0x65, 0x22, 0x5c, - 0x00, 0x65, 0x22, 0x44, - 0xff, 0x65, 0xcc, 0x08, + 0x00, 0x65, 0x78, 0x44, + 0xa0, 0x6a, 0xcc, 0x00, + 0xe8, 0x6a, 0xc8, 0x00, + 0x01, 0x94, 0x40, 0x6c, + 0x10, 0x94, 0x42, 0x6c, + 0x08, 0x94, 0x54, 0x6c, + 0x08, 0x94, 0x54, 0x6c, + 0x08, 0x94, 0x54, 0x6c, + 0x00, 0x65, 0x68, 0x5c, + 0x08, 0x64, 0xc8, 0x18, + 0x00, 0x8c, 0xca, 0x18, + 0x00, 0x65, 0x4a, 0x4c, + 0x00, 0x65, 0x40, 0x44, + 0xf7, 0x93, 0x26, 0x09, + 0x08, 0x93, 0x56, 0x6c, + 0x00, 0x65, 0x68, 0x5c, + 0x08, 0x64, 0xc8, 0x18, + 0x08, 0x64, 0x58, 0x64, + 0xff, 0x6a, 0xd4, 0x0c, + 0x00, 0x65, 0x78, 0x5c, + 0x00, 0x65, 0x68, 0x5c, + 0x00, 0x65, 0x68, 0x5c, + 0x00, 0x65, 0x68, 0x5c, + 0xff, 0x99, 0xda, 0x08, 0xff, 0x99, 0xda, 0x08, 0xff, 0x99, 0xda, 0x08, 0xff, 0x99, 0xda, 0x08, @@ -538,19 +574,19 @@ 0xff, 0x99, 0xda, 0x08, 0xff, 0x99, 0xda, 0x08, 0xff, 0x99, 0xda, 0x0c, - 0x08, 0x94, 0x30, 0x7c, + 0x08, 0x94, 0x78, 0x7c, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x34, 0x6c, + 0x08, 0x93, 0x7c, 0x6c, 0xff, 0x6a, 0xd4, 0x0c, 0xff, 0x40, 0x74, 0x09, 0xff, 0x90, 0x80, 0x08, 0xff, 0x6a, 0x72, 0x05, - 0xff, 0x40, 0x4c, 0x64, - 0xff, 0x3f, 0x44, 0x64, + 0xff, 0x40, 0x94, 0x64, + 0xff, 0x3f, 0x8c, 0x64, 0xff, 0x6a, 0xca, 0x04, 0xff, 0x3f, 0x20, 0x09, 0x01, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0xca, 0x5b, + 0x00, 0xb9, 0xe6, 0x5b, 0xff, 0xba, 0x7e, 0x0c, 0xff, 0x40, 0x20, 0x09, 0xff, 0xba, 0x80, 0x0c, @@ -558,12 +594,36 @@ 0xff, 0x90, 0x7e, 0x0c, }; +static int aic7xxx_patch15_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch15_func(struct aic7xxx_host *p) +{ + return ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0); +} + +static int aic7xxx_patch14_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch14_func(struct aic7xxx_host *p) +{ + return ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0); +} + +static int aic7xxx_patch13_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch13_func(struct aic7xxx_host *p) +{ + return ((p->features & AHC_WIDE) != 0); +} + static int aic7xxx_patch12_func(struct aic7xxx_host *p); static int aic7xxx_patch12_func(struct aic7xxx_host *p) { - return ((p->features & AHC_WIDE) != 0); + return ((p->bugs & AHC_BUG_AUTOFLUSH) != 0); } static int aic7xxx_patch11_func(struct aic7xxx_host *p); @@ -692,54 +752,66 @@ { aic7xxx_patch7_func, 113, 1, 2 }, { aic7xxx_patch0_func, 114, 1, 1 }, { aic7xxx_patch1_func, 118, 1, 1 }, - { aic7xxx_patch1_func, 121, 3, 2 }, + { aic7xxx_patch1_func, 121, 3, 3 }, + { aic7xxx_patch11_func, 123, 1, 1 }, { aic7xxx_patch0_func, 124, 5, 1 }, - { aic7xxx_patch1_func, 132, 2, 3 }, { aic7xxx_patch7_func, 132, 1, 1 }, - { aic7xxx_patch0_func, 134, 3, 1 }, - { aic7xxx_patch11_func, 138, 1, 2 }, - { aic7xxx_patch0_func, 139, 1, 1 }, - { aic7xxx_patch7_func, 140, 7, 2 }, - { aic7xxx_patch0_func, 147, 1, 1 }, - { aic7xxx_patch1_func, 152, 14, 3 }, - { aic7xxx_patch11_func, 165, 1, 1 }, - { aic7xxx_patch0_func, 166, 9, 1 }, - { aic7xxx_patch7_func, 180, 2, 1 }, - { aic7xxx_patch7_func, 182, 1, 1 }, - { aic7xxx_patch11_func, 183, 6, 3 }, - { aic7xxx_patch1_func, 183, 2, 2 }, - { aic7xxx_patch0_func, 185, 4, 1 }, - { aic7xxx_patch7_func, 190, 1, 1 }, - { aic7xxx_patch7_func, 194, 20, 1 }, - { aic7xxx_patch1_func, 215, 3, 3 }, - { aic7xxx_patch11_func, 217, 1, 1 }, - { aic7xxx_patch0_func, 218, 5, 1 }, - { aic7xxx_patch11_func, 223, 1, 2 }, - { aic7xxx_patch0_func, 224, 9, 1 }, - { aic7xxx_patch12_func, 240, 1, 2 }, - { aic7xxx_patch0_func, 241, 1, 1 }, - { aic7xxx_patch4_func, 302, 1, 2 }, - { aic7xxx_patch0_func, 303, 1, 1 }, - { aic7xxx_patch2_func, 306, 1, 1 }, - { aic7xxx_patch1_func, 316, 3, 2 }, - { aic7xxx_patch0_func, 319, 5, 1 }, - { aic7xxx_patch12_func, 327, 1, 2 }, - { aic7xxx_patch0_func, 328, 1, 1 }, - { aic7xxx_patch5_func, 333, 1, 1 }, - { aic7xxx_patch11_func, 375, 15, 1 }, - { aic7xxx_patch1_func, 427, 7, 2 }, - { aic7xxx_patch0_func, 434, 8, 1 }, - { aic7xxx_patch1_func, 443, 4, 2 }, - { aic7xxx_patch0_func, 447, 6, 1 }, - { aic7xxx_patch1_func, 453, 4, 2 }, - { aic7xxx_patch0_func, 457, 3, 1 }, - { aic7xxx_patch10_func, 467, 10, 1 }, - { aic7xxx_patch1_func, 486, 17, 4 }, - { aic7xxx_patch9_func, 494, 4, 2 }, - { aic7xxx_patch0_func, 498, 2, 1 }, - { aic7xxx_patch0_func, 503, 33, 1 }, - { aic7xxx_patch10_func, 536, 4, 1 }, - { aic7xxx_patch5_func, 540, 2, 1 }, - { aic7xxx_patch5_func, 543, 9, 1 }, + { aic7xxx_patch9_func, 133, 1, 1 }, + { aic7xxx_patch10_func, 134, 3, 1 }, + { aic7xxx_patch7_func, 137, 3, 2 }, + { aic7xxx_patch0_func, 140, 2, 1 }, + { aic7xxx_patch7_func, 142, 5, 2 }, + { aic7xxx_patch0_func, 147, 3, 1 }, + { aic7xxx_patch7_func, 150, 1, 2 }, + { aic7xxx_patch0_func, 151, 2, 1 }, + { aic7xxx_patch1_func, 153, 15, 4 }, + { aic7xxx_patch11_func, 166, 1, 2 }, + { aic7xxx_patch0_func, 167, 1, 1 }, + { aic7xxx_patch0_func, 168, 10, 1 }, + { aic7xxx_patch7_func, 181, 1, 2 }, + { aic7xxx_patch0_func, 182, 2, 1 }, + { aic7xxx_patch7_func, 184, 18, 1 }, + { aic7xxx_patch1_func, 202, 3, 3 }, + { aic7xxx_patch7_func, 204, 1, 1 }, + { aic7xxx_patch0_func, 205, 4, 1 }, + { aic7xxx_patch7_func, 210, 2, 1 }, + { aic7xxx_patch7_func, 215, 13, 3 }, + { aic7xxx_patch12_func, 218, 1, 1 }, + { aic7xxx_patch12_func, 219, 4, 1 }, + { aic7xxx_patch1_func, 229, 3, 3 }, + { aic7xxx_patch11_func, 231, 1, 1 }, + { aic7xxx_patch0_func, 232, 5, 1 }, + { aic7xxx_patch11_func, 237, 1, 2 }, + { aic7xxx_patch0_func, 238, 9, 1 }, + { aic7xxx_patch13_func, 254, 1, 2 }, + { aic7xxx_patch0_func, 255, 1, 1 }, + { aic7xxx_patch4_func, 316, 1, 2 }, + { aic7xxx_patch0_func, 317, 1, 1 }, + { aic7xxx_patch2_func, 320, 1, 1 }, + { aic7xxx_patch1_func, 330, 3, 2 }, + { aic7xxx_patch0_func, 333, 5, 1 }, + { aic7xxx_patch13_func, 341, 1, 2 }, + { aic7xxx_patch0_func, 342, 1, 1 }, + { aic7xxx_patch5_func, 347, 1, 1 }, + { aic7xxx_patch11_func, 389, 15, 2 }, + { aic7xxx_patch14_func, 402, 1, 1 }, + { aic7xxx_patch1_func, 441, 7, 2 }, + { aic7xxx_patch0_func, 448, 8, 1 }, + { aic7xxx_patch1_func, 457, 4, 2 }, + { aic7xxx_patch0_func, 461, 6, 1 }, + { aic7xxx_patch1_func, 467, 4, 2 }, + { aic7xxx_patch0_func, 471, 3, 1 }, + { aic7xxx_patch10_func, 481, 10, 1 }, + { aic7xxx_patch1_func, 500, 22, 5 }, + { aic7xxx_patch11_func, 508, 4, 1 }, + { aic7xxx_patch7_func, 512, 7, 3 }, + { aic7xxx_patch15_func, 512, 5, 2 }, + { aic7xxx_patch0_func, 517, 2, 1 }, + { aic7xxx_patch10_func, 522, 50, 3 }, + { aic7xxx_patch14_func, 543, 17, 2 }, + { aic7xxx_patch0_func, 560, 4, 1 }, + { aic7xxx_patch10_func, 572, 4, 1 }, + { aic7xxx_patch5_func, 576, 2, 1 }, + { aic7xxx_patch5_func, 579, 9, 1 }, }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx_old/sequencer.h linux.ac/drivers/scsi/aic7xxx_old/sequencer.h --- linux.vanilla/drivers/scsi/aic7xxx_old/sequencer.h Tue Apr 3 17:32:19 2001 +++ linux.ac/drivers/scsi/aic7xxx_old/sequencer.h Tue Apr 10 18:16:57 2001 @@ -15,7 +15,7 @@ * derived from this software without specific prior written permission. * * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the + * the GNU General Public License ("GPL") and the terms of the GPL would require the * combined work to also be released under the terms of the GPL, the terms * and conditions of this License will apply in addition to those of the * GPL with the exception of any terms or conditions of this License that diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx_old.c linux.ac/drivers/scsi/aic7xxx_old.c --- linux.vanilla/drivers/scsi/aic7xxx_old.c Tue Apr 3 17:32:19 2001 +++ linux.ac/drivers/scsi/aic7xxx_old.c Tue Apr 10 18:16:57 2001 @@ -55,7 +55,7 @@ * derived from this software without specific prior written permission. * * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the + * the GNU General Public License ("GPL") and the terms of the GPL would require the * combined work to also be released under the terms of the GPL, the terms * and conditions of this License will apply in addition to those of the * GPL with the exception of any terms or conditions of this License that @@ -256,7 +256,7 @@ #include <scsi/scsicam.h> #include <linux/stat.h> -#include <linux/malloc.h> /* for kmalloc() */ +#include <linux/slab.h> /* for kmalloc() */ #include <linux/config.h> /* for CONFIG_PCI */ @@ -266,7 +266,7 @@ */ #define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a)) -#define AIC7XXX_C_VERSION "5.2.1" +#define AIC7XXX_C_VERSION "5.2.4" #define NUMBER(arr) (sizeof(arr) / sizeof(arr[0])) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) @@ -311,8 +311,8 @@ * You can try raising me if tagged queueing is enabled, or lowering * me if you only have 4 SCBs. */ -#ifdef CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE -#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE +#ifdef CONFIG_AIC7XXX_CMDS_PER_DEVICE +#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_CMDS_PER_DEVICE #else #define AIC7XXX_CMDS_PER_DEVICE 8 #endif @@ -323,7 +323,7 @@ * NOTE: Do NOT enable this when running on kernels version 1.2.x and below. * NOTE: This does affect performance since it has to maintain statistics. */ -#ifdef CONFIG_AIC7XXX_OLD_PROC_STATS +#ifdef CONFIG_AIC7XXX_PROC_STATS #define AIC7XXX_PROC_STATS #endif @@ -347,7 +347,7 @@ * Make a define that will tell the driver not to use tagged queueing * by default. */ -#ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT +#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT #define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\ 0, 0, 0, 0, 0, 0, 0, 0} #else @@ -706,13 +706,14 @@ /*28*/ unsigned int pad; /* * Unused by the kernel, but we require * the padding so that the array of - * hardware SCBs is alligned on 32 byte + * hardware SCBs is aligned on 32 byte * boundaries so the sequencer can index */ }; typedef enum { SCB_FREE = 0x0000, + SCB_DTR_SCB = 0x0001, SCB_WAITINGQ = 0x0002, SCB_ACTIVE = 0x0004, SCB_SENSE = 0x0008, @@ -830,6 +831,17 @@ unsigned int dma_len; /* DMA length */ }; +typedef enum { + AHC_BUG_NONE = 0x0000, + AHC_BUG_TMODE_WIDEODD = 0x0001, + AHC_BUG_AUTOFLUSH = 0x0002, + AHC_BUG_CACHETHEN = 0x0004, + AHC_BUG_CACHETHEN_DIS = 0x0008, + AHC_BUG_PCI_2_1_RETRY = 0x0010, + AHC_BUG_PCI_MWI = 0x0020, + AHC_BUG_SCBCHAN_UPLOAD = 0x0040, +} ahc_bugs; + struct aic7xxx_scb { struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */ Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */ @@ -942,7 +954,6 @@ unsigned long isr_count; /* Interrupt count */ unsigned long spurious_int; scb_data_type *scb_data; - volatile unsigned short needdv; volatile unsigned short needppr; volatile unsigned short needsdtr; volatile unsigned short needwdtr; @@ -973,10 +984,9 @@ #define BUS_DEVICE_RESET_PENDING 0x02 #define DEVICE_RESET_DELAY 0x04 #define DEVICE_PRINT_DTR 0x08 -#define DEVICE_PARITY_ERROR 0x10 -#define DEVICE_WAS_BUSY 0x20 -#define DEVICE_SCSI_3 0x40 -#define DEVICE_SCANNED 0x80 +#define DEVICE_WAS_BUSY 0x10 +#define DEVICE_SCSI_3 0x20 +#define DEVICE_DTR_SCANNED 0x40 volatile unsigned char dev_flags[MAX_TARGETS]; volatile unsigned char dev_active_cmds[MAX_TARGETS]; volatile unsigned char dev_temp_queue_depth[MAX_TARGETS]; @@ -989,10 +999,6 @@ spinlock_t spin_lock; volatile unsigned char cpu_lock_count[NR_CPUS]; - Scsi_Cmnd *dev_dtr_cmnd[MAX_TARGETS]; - - unsigned int dev_checksum[MAX_TARGETS]; - unsigned char dev_last_queue_full[MAX_TARGETS]; unsigned char dev_last_queue_full_count[MAX_TARGETS]; unsigned char dev_max_queue_depth[MAX_TARGETS]; @@ -1040,6 +1046,7 @@ int host_no; /* SCSI host number */ unsigned long mbase; /* I/O memory address */ ahc_chip chip; /* chip type */ + ahc_bugs bugs; dma_addr_t fifo_dma; /* DMA handle for fifo arrays */ /* @@ -2821,138 +2828,98 @@ { p->flags &= ~AHC_ABORT_PENDING; } - if (scb->flags & SCB_RESET) + if (scb->flags & (SCB_RESET|SCB_ABORT)) { - cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff); + cmd->result |= (DID_RESET << 16); } - else if (scb->flags & SCB_ABORT) - { - cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff); - } - else if (!(p->dev_flags[tindex] & DEVICE_SCANNED)) + + if (!(p->dev_flags[tindex] & DEVICE_PRESENT)) { if ( (cmd->cmnd[0] == INQUIRY) && (cmd->result == DID_OK) ) { - char *buffer; - + p->dev_flags[tindex] |= DEVICE_PRESENT; - if(cmd->use_sg) - { - struct scatterlist *sg; - - sg = (struct scatterlist *)cmd->request_buffer; - buffer = (char *)sg[0].address; - } - else - { - buffer = (char *)cmd->request_buffer; - } #define WIDE_INQUIRY_BITS 0x60 #define SYNC_INQUIRY_BITS 0x10 #define SCSI_VERSION_BITS 0x07 #define SCSI_DT_BIT 0x04 - if ( (buffer[7] & WIDE_INQUIRY_BITS) && - (p->features & AHC_WIDE) ) - { - p->needwdtr |= (1<<tindex); - p->needwdtr_copy |= (1<<tindex); - p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width; - } - else - { - p->needwdtr &= ~(1<<tindex); - p->needwdtr_copy &= ~(1<<tindex); - pause_sequencer(p); - aic7xxx_set_width(p, cmd->target, cmd->channel, cmd->lun, - MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE | - AHC_TRANS_GOAL | - AHC_TRANS_CUR) ); - unpause_sequencer(p, FALSE); - } - if ( (buffer[7] & SYNC_INQUIRY_BITS) && - p->transinfo[tindex].user_offset ) - { - p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period; - p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options; - if (p->features & AHC_ULTRA2) - p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; - else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT) - p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; + if(!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED)) { + char *buffer; + + if(cmd->use_sg) + { + struct scatterlist *sg; + + sg = (struct scatterlist *)cmd->request_buffer; + buffer = (char *)sg[0].address; + } + else + { + buffer = (char *)cmd->request_buffer; + } + + + if ( (buffer[7] & WIDE_INQUIRY_BITS) && + (p->features & AHC_WIDE) ) + { + p->needwdtr |= (1<<tindex); + p->needwdtr_copy |= (1<<tindex); + p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width; + } else - p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; - if ( (((buffer[2] & SCSI_VERSION_BITS) == 3) || - (buffer[56] & SCSI_DT_BIT) || - (p->dev_flags[tindex] & DEVICE_SCSI_3) ) && - (p->transinfo[tindex].user_period <= 9) && - (p->transinfo[tindex].user_options) ) { - p->needppr |= (1<<tindex); - p->needppr_copy |= (1<<tindex); - p->needsdtr &= ~(1<<tindex); - p->needsdtr_copy &= ~(1<<tindex); p->needwdtr &= ~(1<<tindex); p->needwdtr_copy &= ~(1<<tindex); - p->dev_flags[tindex] |= DEVICE_SCSI_3; + pause_sequencer(p); + aic7xxx_set_width(p, cmd->target, cmd->channel, cmd->lun, + MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE | + AHC_TRANS_GOAL | + AHC_TRANS_CUR) ); + unpause_sequencer(p, FALSE); } - else + if ( (buffer[7] & SYNC_INQUIRY_BITS) && + p->transinfo[tindex].user_offset ) { - p->needsdtr |= (1<<tindex); - p->needsdtr_copy |= (1<<tindex); - p->transinfo[tindex].goal_period = - MAX(10, p->transinfo[tindex].goal_period); - p->transinfo[tindex].goal_options = 0; + p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period; + p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options; + if (p->features & AHC_ULTRA2) + p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; + else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT) + p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; + else + p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; + if ( (((buffer[2] & SCSI_VERSION_BITS) >= 3) || + (buffer[56] & SCSI_DT_BIT) || + (p->dev_flags[tindex] & DEVICE_SCSI_3) ) && + (p->transinfo[tindex].user_period <= 9) && + (p->transinfo[tindex].user_options) ) + { + p->needppr |= (1<<tindex); + p->needppr_copy |= (1<<tindex); + p->needsdtr &= ~(1<<tindex); + p->needsdtr_copy &= ~(1<<tindex); + p->needwdtr &= ~(1<<tindex); + p->needwdtr_copy &= ~(1<<tindex); + p->dev_flags[tindex] |= DEVICE_SCSI_3; + } + else + { + p->needsdtr |= (1<<tindex); + p->needsdtr_copy |= (1<<tindex); + p->transinfo[tindex].goal_period = + MAX(10, p->transinfo[tindex].goal_period); + p->transinfo[tindex].goal_options = 0; + } } - } - else - { - p->needsdtr &= ~(1<<tindex); - p->needsdtr_copy &= ~(1<<tindex); - p->transinfo[tindex].goal_period = 255; - p->transinfo[tindex].goal_offset = 0; - p->transinfo[tindex].goal_options = 0; - } - /* - * This is needed to work around a sequencer bug for now. Regardless - * of the controller in use, if we have a Quantum drive, we need to - * limit the speed to 80MByte/sec. As soon as I get a fixed version - * of the sequencer, this code will get yanked. - */ - if(!strncmp(buffer + 8, "QUANTUM", 7) && - p->transinfo[tindex].goal_options ) - { - p->transinfo[tindex].goal_period = - MAX(p->transinfo[tindex].goal_period, 10); - p->transinfo[tindex].goal_options = 0; - p->needppr &= ~(1<<tindex); - p->needppr_copy &= ~(1<<tindex); - p->needsdtr |= (1<<tindex); - p->needsdtr_copy |= (1<<tindex); - p->needwdtr |= (1<<tindex); - p->needwdtr_copy |= (1<<tindex); - } - /* - * Get the INQUIRY checksum. We use this on Ultra 160/m - * and older devices both. It allows us to drop speed on any bus type - * while at the same time giving us the needed domain validation for - * Ultra 160/m - * - * Note: We only get the checksum and set the SCANNED bit if this is - * one of our dtr commands. If we don't do this, then we end up - * getting bad checksum results on the mid-level SCSI code's INQUIRY - * commands. - */ - if(p->dev_dtr_cmnd[tindex] == cmd) { - unsigned int checksum = 0; - int *ibuffer; - int i=0; - - ibuffer = (int *)buffer; - for( i = 0; i < (cmd->request_bufflen >> 2); i++) + else { - checksum += ibuffer[i]; + p->needsdtr &= ~(1<<tindex); + p->needsdtr_copy &= ~(1<<tindex); + p->transinfo[tindex].goal_period = 255; + p->transinfo[tindex].goal_offset = 0; + p->transinfo[tindex].goal_options = 0; } - p->dev_checksum[tindex] = checksum; - p->dev_flags[tindex] |= DEVICE_SCANNED; + p->dev_flags[tindex] |= DEVICE_DTR_SCANNED; p->dev_flags[tindex] |= DEVICE_PRINT_DTR; } #undef WIDE_INQUIRY_BITS @@ -2961,7 +2928,8 @@ #undef SCSI_DT_BIT } } - else if ((scb->flags & SCB_MSGOUT_BITS) != 0) + + if ((scb->flags & SCB_MSGOUT_BITS) != 0) { unsigned short mask; int message_error = FALSE; @@ -2981,7 +2949,6 @@ if (scb->flags & SCB_MSGOUT_WDTR) { - p->dtr_pending &= ~mask; if (message_error) { if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && @@ -3000,7 +2967,6 @@ } if (scb->flags & SCB_MSGOUT_SDTR) { - p->dtr_pending &= ~mask; if (message_error) { if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && @@ -3020,7 +2986,6 @@ } if (scb->flags & SCB_MSGOUT_PPR) { - p->dtr_pending &= ~mask; if(message_error) { if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && @@ -3045,6 +3010,7 @@ } } } + queue_depth = p->dev_temp_queue_depth[tindex]; if (queue_depth >= p->dev_active_cmds[tindex]) { @@ -3078,9 +3044,18 @@ } } } - if ( !(scb->tag_action) && (p->tagenable & (1<<tindex)) ) + if (!(scb->tag_action)) + { + aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, + /* unbusy */ TRUE); + if (p->tagenable & (1<<tindex)) + { + p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex]; + } + } + if(scb->flags & SCB_DTR_SCB) { - p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex]; + p->dtr_pending &= ~(1 << tindex); } p->dev_active_cmds[tindex]--; p->activescbs--; @@ -3189,6 +3164,14 @@ printk(INFO_LEAD "Aborting scb %d\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag); found++; + /* + * Clear any residual information since the normal aic7xxx_done() path + * doesn't touch the residuals. + */ + scb->hscb->residual_SG_segment_count = 0; + scb->hscb->residual_data_count[0] = 0; + scb->hscb->residual_data_count[1] = 0; + scb->hscb->residual_data_count[2] = 0; aic7xxx_done(p, scb); } } @@ -3401,8 +3384,22 @@ active_scb = aic_inb(p, SCBPTR); if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS)) + { printk(INFO_LEAD "Reset device, active_scb %d\n", p->host_no, channel, target, lun, active_scb); + printk(INFO_LEAD "Current scb_tag %d, SEQADDR 0x%x, LASTPHASE " + "0x%x\n", + p->host_no, channel, target, lun, aic_inb(p, SCB_TAG), + aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), + aic_inb(p, LASTPHASE)); + printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n", + p->host_no, channel, target, lun, + (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0, + aic_inb(p, SG_COUNT), aic_inb(p, SCSISIGI)); + printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n", + p->host_no, channel, target, lun, aic_inb(p, SSTAT0), + aic_inb(p, SSTAT1), aic_inb(p, SSTAT2)); + } /* * Deal with the busy target and linked next issues. */ @@ -3446,11 +3443,11 @@ if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) printk(INFO_LEAD "Cleaning up status information " "and delayed_scbs.\n", p->host_no, channel, i, lun); - p->dev_flags[i] &= ~(BUS_DEVICE_RESET_PENDING | DEVICE_PARITY_ERROR); + p->dev_flags[i] &= ~BUS_DEVICE_RESET_PENDING; if ( tag == SCB_LIST_NULL ) { p->dev_flags[i] |= DEVICE_PRINT_DTR | DEVICE_RESET_DELAY; - p->dev_expires[i] = jiffies + (4 * HZ); + p->dev_expires[i] = jiffies + (1 * HZ); p->dev_timer_active |= (0x01 << i); p->dev_last_queue_full_count[i] = 0; p->dev_last_queue_full[i] = 0; @@ -3495,7 +3492,7 @@ prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; } } - if ( j > (p->scb_data->maxscbs + 1) ) + if ( j > (p->scb_data->numscbs + 1) ) { if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET)) printk(WARN_LEAD "Yikes!! There's a loop in the " @@ -3554,7 +3551,7 @@ prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; } } - if ( j > (p->scb_data->maxscbs + 1) ) + if ( j > (p->scb_data->numscbs + 1) ) { if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET)) printk(WARN_LEAD "Yikes!! There's a loop in the " @@ -4300,11 +4297,25 @@ if (actual < cmd->underflow) { if (aic7xxx_verbose & VERBOSE_MINOR_ERROR) + { printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG " "count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow, (cmd->request.cmd == WRITE) ? "wrote" : "read", actual, hscb->residual_SG_segment_count); + printk(INFO_LEAD "status 0x%x.\n", p->host_no, CTL_OF_SCB(scb), + hscb->target_status); + } + /* + * In 2.4, only send back the residual information, don't flag this + * as an error. Before 2.4 we had to flag this as an error because + * the mid layer didn't check residual data counts to see if the + * command needs retried. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + cmd->resid = scb->sg_length - actual; +#else aic7xxx_error(cmd) = DID_RETRY_COMMAND; +#endif aic7xxx_status(cmd) = hscb->target_status; } } @@ -4623,7 +4634,6 @@ */ p->needwdtr &= ~target_mask; p->needwdtr_copy &= ~target_mask; - p->dtr_pending &= ~target_mask; scb->flags &= ~SCB_MSGOUT_BITS; aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR)); @@ -4643,8 +4653,7 @@ */ p->needsdtr &= ~target_mask; p->needsdtr_copy &= ~target_mask; - p->dtr_pending &= ~target_mask; - scb->flags &= ~SCB_MSGOUT_SDTR; + scb->flags &= ~SCB_MSGOUT_BITS; aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0, (AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL)); if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) @@ -4778,6 +4787,8 @@ aic7xxx_error(cmd) = DID_OK; break; } /* first time sense, no errors */ + printk(INFO_LEAD "CHECK_CONDITION on REQUEST_SENSE, returning " + "an error.\n", p->host_no, CTL_OF_SCB(scb)); aic7xxx_error(cmd) = DID_ERROR; scb->flags &= ~SCB_SENSE; break; @@ -5136,12 +5147,21 @@ printk(KERN_WARNING " %s seen Data Phase. Length=%d, NumSGs=%d.\n", (aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't", scb->sg_length, scb->sg_count); - for (i = 0; i < scb->sg_count; i++) + printk(KERN_WARNING " Raw SCSI Command: 0x"); + for (i = 0; i < scb->hscb->SCSI_cmd_length; i++) + { + printk("%02x ", scb->cmd->cmnd[i]); + } + printk("\n"); + if(aic7xxx_verbose > 0xffff) { - printk(KERN_WARNING " sg[%d] - Addr 0x%x : Length %d\n", + for (i = 0; i < scb->sg_count; i++) + { + printk(KERN_WARNING " sg[%d] - Addr 0x%x : Length %d\n", i, le32_to_cpu(scb->sg_list[i].address), le32_to_cpu(scb->sg_list[i].length) ); + } } aic7xxx_error(scb->cmd) = DID_ERROR; } @@ -5156,7 +5176,7 @@ unsigned char resid_sgcnt, index; unsigned char scb_index = aic_inb(p, SCB_TAG); unsigned int cur_addr, resid_dcnt; - unsigned int native_addr, native_length; + unsigned int native_addr, native_length, sg_addr; int i; if(scb_index > p->scb_data->numscbs) @@ -5176,6 +5196,9 @@ scb->flags, (unsigned long)scb->cmd); break; } + if(aic7xxx_verbose & VERBOSE_MINOR_ERROR) + printk(INFO_LEAD "Got WIDE_RESIDUE message, patching up data " + "pointer.\n", p->host_no, CTL_OF_SCB(scb)); /* * We have a valid scb to use on this WIDE_RESIDUE message, so @@ -5188,132 +5211,87 @@ */ cur_addr = aic_inb(p, SHADDR) | (aic_inb(p, SHADDR + 1) << 8) | (aic_inb(p, SHADDR + 2) << 16) | (aic_inb(p, SHADDR + 3) << 24); + sg_addr = aic_inb(p, SG_COUNT + 1) | (aic_inb(p, SG_COUNT + 2) << 8) | + (aic_inb(p, SG_COUNT + 3) << 16) | (aic_inb(p, SG_COUNT + 4) << 24); resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT); resid_dcnt = aic_inb(p, SCB_RESID_DCNT) | (aic_inb(p, SCB_RESID_DCNT + 1) << 8) | (aic_inb(p, SCB_RESID_DCNT + 2) << 16); - index = scb->sg_count - (resid_sgcnt + 1); + index = scb->sg_count - ((resid_sgcnt) ? resid_sgcnt : 1); native_addr = le32_to_cpu(scb->sg_list[index].address); native_length = le32_to_cpu(scb->sg_list[index].length); /* - * Make sure this is a valid sg_seg for the given pointer + * If resid_dcnt == native_length, then we just loaded this SG + * segment and we need to back it up one... */ - if(cur_addr < native_addr || - cur_addr > (native_addr + native_length + 1)) - { - printk(WARN_LEAD "invalid cur_addr:0x%x during WIDE_RESIDUE\n", - p->host_no, CTL_OF_SCB(scb), cur_addr); - if(index > 0) - printk(WARN_LEAD " sg_address[-1]:0x%x sg_length[-1]:%d\n", - p->host_no, CTL_OF_SCB(scb), - le32_to_cpu(scb->sg_list[index - 1].address), - le32_to_cpu(scb->sg_list[index - 1].length)); - printk(WARN_LEAD " sg_address:0x%x sg_length:%d\n", - p->host_no, CTL_OF_SCB(scb), - native_addr, native_length); - if(resid_sgcnt > 1) - printk(WARN_LEAD " sg_address[1]:0x%x sg_length[1]:%d\n", - p->host_no, CTL_OF_SCB(scb), - le32_to_cpu(scb->sg_list[index + 1].address), - le32_to_cpu(scb->sg_list[index + 1].length)); - printk(WARN_LEAD " cur_address:0x%x resid_dcnt:0x%06x\n", - p->host_no, CTL_OF_SCB(scb), - cur_addr, resid_dcnt); - break; - } - - if( (resid_sgcnt == 0) && - ((resid_dcnt == 0) || (resid_dcnt == 0xffffff))) - { - /* - * We are at the end of the transfer and this is about a byte - * we ignored already (because the sequencer knew this was - * the last segment and set the adapter to ignore any wide - * residue bytes that might come through, which is only done - * on the last scatter gather segment of transfers). - */ - break; - } - else if(cur_addr == native_addr) + if(resid_dcnt == native_length) { - /* - * If our current address matches the sg_seg->address then we - * have to back up the sg array to the previous segment and set - * it up to have only one byte of transfer left to go. - */ if(index == 0) { - printk(WARN_LEAD "bogus WIDE_RESIDUE message, no data has been " - "transferred.\n", p->host_no, CTL_OF_SCB(scb)); + /* + * Oops, this isn't right, we can't back up to before the + * beginning. This must be a bogus message, ignore it. + */ break; } - resid_sgcnt++; - index--; - cur_addr = le32_to_cpu(scb->sg_list[index].address) + - le32_to_cpu(scb->sg_list[index].length) - 1; - native_addr = aic_inb(p, SG_NEXT) | (aic_inb(p, SG_NEXT + 1) << 8) - | (aic_inb(p, SG_NEXT + 2) << 16) | (aic_inb(p, SG_NEXT + 3) << 24); - native_addr -= SG_SIZEOF; - aic_outb(p, resid_sgcnt, SG_COUNT); - aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT); - aic_outb(p, native_addr & 0xff, SG_NEXT); - aic_outb(p, (native_addr >> 8) & 0xff, SG_NEXT + 1); - aic_outb(p, (native_addr >> 16) & 0xff, SG_NEXT + 2); - aic_outb(p, (native_addr >> 24) & 0xff, SG_NEXT + 3); - aic_outb(p, 1, SCB_RESID_DCNT); - aic_outb(p, 0, SCB_RESID_DCNT + 1); - aic_outb(p, 0, SCB_RESID_DCNT + 2); - aic_outb(p, 1, HCNT); - aic_outb(p, 0, HCNT + 1); - aic_outb(p, 0, HCNT + 2); - aic_outb(p, cur_addr & 0xff, HADDR); - aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1); - aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2); - aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3); + resid_dcnt = 1; + resid_sgcnt += 1; + native_addr = le32_to_cpu(scb->sg_list[index - 1].address); + native_length = le32_to_cpu(scb->sg_list[index - 1].length); + cur_addr = native_addr + (native_length - 1); + sg_addr -= sizeof(struct hw_scatterlist); } else { /* - * Back the data pointer up by one and add one to the remaining - * byte count. Then store that in the HCNT and HADDR registers. + * resid_dcnt != native_length, so we are in the middle of a SG + * element. Back it up one byte and leave the rest alone. */ - cur_addr--; - resid_dcnt++; - aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT); - aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1); - aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2); - aic_outb(p, resid_dcnt & 0xff, HCNT); - aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1); - aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2); - aic_outb(p, cur_addr & 0xff, HADDR); - aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1); - aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2); - aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3); + resid_dcnt += 1; + cur_addr -= 1; } + + /* + * Output the new addresses and counts to the right places on the + * card. + */ + aic_outb(p, resid_sgcnt, SG_COUNT); + aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT); + aic_outb(p, sg_addr & 0xff, SG_COUNT + 1); + aic_outb(p, (sg_addr >> 8) & 0xff, SG_COUNT + 2); + aic_outb(p, (sg_addr >> 16) & 0xff, SG_COUNT + 3); + aic_outb(p, (sg_addr >> 24) & 0xff, SG_COUNT + 4); + aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT); + aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1); + aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2); + /* - * The sequencer actually wants to find the new address and byte - * count in the SHCNT and SHADDR register sets. These registers - * are a shadow of the regular HCNT and HADDR registers. On the - * Ultra2 controllers, these registers are read only and the way - * we have to set their values is to put the values we want into - * the HCNT and HADDR registers and then output PRELOADEN into - * the DFCNTRL register which causes the card to latch the current - * values in the HADDR and HCNT registers and drop it through to - * the shadow registers. On older cards we copy them directly - * across by hand. + * The sequencer actually wants to find the new address + * in the SHADDR register set. On the Ultra2 and later controllers + * this register set is readonly. In order to get the right number + * into the register, you actually have to enter it in HADDR and then + * use the PRELOADEN bit of DFCNTRL to drop it through from the + * HADDR register to the SHADDR register. On non-Ultra2 controllers, + * we simply write it direct. */ if(p->features & AHC_ULTRA2) { - aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL); - i=0; + /* + * We might as well be accurate and drop both the resid_dcnt and + * cur_addr into HCNT and HADDR and have both of them drop + * through to the shadow layer together. + */ + aic_outb(p, resid_dcnt & 0xff, HCNT); + aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1); + aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2); + aic_outb(p, cur_addr & 0xff, HADDR); + aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1); + aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2); + aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3); + aic_outb(p, aic_inb(p, DMAPARAMS) | PRELOADEN, DFCNTRL); udelay(1); - while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000)) - { - udelay(1); - } aic_outb(p, aic_inb(p, DMAPARAMS) & ~(SCSIEN|HDMAEN), DFCNTRL); i=0; - udelay(1); while(((aic_inb(p, DFCNTRL) & (SCSIEN|HDMAEN)) != 0) && (i++ < 1000)) { udelay(1); @@ -5321,9 +5299,6 @@ } else { - aic_outb(p, resid_dcnt & 0xff, STCNT); - aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1); - aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2); aic_outb(p, cur_addr & 0xff, SHADDR); aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1); aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2); @@ -5332,15 +5307,82 @@ } break; - -#if AIC7XXX_NOT_YET - case TRACEPOINT: + case SEQ_SG_FIXUP: + { + unsigned char scb_index, tmp; + int sg_addr, sg_length; + + scb_index = aic_inb(p, SCB_TAG); + + if(scb_index > p->scb_data->numscbs) { - printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no, - channel, target, lun); + printk(WARN_LEAD "invalid scb_index during SEQ_SG_FIXUP.\n", + p->host_no, -1, -1, -1); + printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 " + "0x%x\n", p->host_no, -1, -1, -1, + aic_inb(p, SCSISIGI), + aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), + aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); + printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", + p->host_no, -1, -1, -1, aic_inb(p, SG_CACHEPTR), + aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 | + aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT)); + /* + * XXX: Add error handling here + */ + break; } - break; + scb = p->scb_data->scb_array[scb_index]; + if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL)) + { + printk(WARN_LEAD "invalid scb during SEQ_SG_FIXUP flags:0x%x " + "scb->cmd:0x%x\n", p->host_no, CTL_OF_SCB(scb), + scb->flags, (unsigned int)scb->cmd); + printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 " + "0x%x\n", p->host_no, CTL_OF_SCB(scb), + aic_inb(p, SCSISIGI), + aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), + aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); + printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", + p->host_no, CTL_OF_SCB(scb), aic_inb(p, SG_CACHEPTR), + aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 | + aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT)); + break; + } + if(aic7xxx_verbose & VERBOSE_MINOR_ERROR) + printk(INFO_LEAD "Fixing up SG address for sequencer.\n", p->host_no, + CTL_OF_SCB(scb)); + /* + * Advance the SG pointer to the next element in the list + */ + tmp = aic_inb(p, SG_NEXT); + tmp += SG_SIZEOF; + aic_outb(p, tmp, SG_NEXT); + if( tmp < SG_SIZEOF ) + aic_outb(p, aic_inb(p, SG_NEXT + 1) + 1, SG_NEXT + 1); + tmp = aic_inb(p, SG_COUNT) - 1; + aic_outb(p, tmp, SG_COUNT); + sg_addr = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].address); + sg_length = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].length); + /* + * Now stuff the element we just advanced past down onto the + * card so it can be stored in the residual area. + */ + aic_outb(p, sg_addr & 0xff, HADDR); + aic_outb(p, (sg_addr >> 8) & 0xff, HADDR + 1); + aic_outb(p, (sg_addr >> 16) & 0xff, HADDR + 2); + aic_outb(p, (sg_addr >> 24) & 0xff, HADDR + 3); + aic_outb(p, sg_length & 0xff, HCNT); + aic_outb(p, (sg_length >> 8) & 0xff, HCNT + 1); + aic_outb(p, (sg_length >> 16) & 0xff, HCNT + 2); + aic_outb(p, (tmp << 2) | ((tmp == 1) ? LAST_SEG : 0), SG_CACHEPTR); + aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL); + while(aic_inb(p, SSTAT0) & SDONE) udelay(1); + while(aic_inb(p, DFCNTRL) & (HDMAEN|SCSIEN)) aic_outb(p, 0, DFCNTRL); + } + break; +#if AIC7XXX_NOT_YET case TRACEPOINT2: { printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no, @@ -5385,6 +5427,10 @@ unsigned char target_scsirate, tindex; unsigned short target_mask; unsigned char target, channel, lun; + unsigned char bus_width, new_bus_width; + unsigned char trans_options, new_trans_options; + unsigned int period, new_period, offset, new_offset, maxsync; + struct aic7xxx_syncrate *syncrate; target = scb->cmd->target; channel = scb->cmd->channel; @@ -5408,6 +5454,35 @@ } /* + * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when + * using the SDTR messages. We need the PPR messages to enable the + * higher speeds that include things like Dual Edge clocking. + */ + if (p->features & AHC_ULTRA2) + { + if ( (aic_inb(p, SBLKCTL) & ENAB40) && + !(aic_inb(p, SSTAT2) & EXP_ACTIVE) ) + { + if (p->features & AHC_ULTRA3) + maxsync = AHC_SYNCRATE_ULTRA3; + else + maxsync = AHC_SYNCRATE_ULTRA2; + } + else + { + maxsync = AHC_SYNCRATE_ULTRA; + } + } + else if (p->features & AHC_ULTRA) + { + maxsync = AHC_SYNCRATE_ULTRA; + } + else + { + maxsync = AHC_SYNCRATE_FAST; + } + + /* * Just accept the length byte outright and perform * more checking once we know the message type. */ @@ -5418,9 +5493,6 @@ { case MSG_EXT_SDTR: { - unsigned int period, offset; - unsigned char maxsync, saved_offset, options; - struct aic7xxx_syncrate *syncrate; if (p->msg_buf[1] != MSG_EXT_SDTR_LEN) { @@ -5433,35 +5505,18 @@ break; } - period = p->msg_buf[3]; - saved_offset = offset = p->msg_buf[4]; - options = 0; + period = new_period = p->msg_buf[3]; + offset = new_offset = p->msg_buf[4]; + trans_options = new_trans_options = 0; + bus_width = new_bus_width = target_scsirate & WIDEXFER; /* - * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when - * using the SDTR messages. We need the PPR messages to enable the - * higher speeds that include things like Dual Edge clocking. + * If our current max syncrate is in the Ultra3 range, bump it back + * down to Ultra2 since we can't negotiate DT transfers using SDTR */ - if (p->features & AHC_ULTRA2) - { - if ( (aic_inb(p, SBLKCTL) & ENAB40) && - !(aic_inb(p, SSTAT2) & EXP_ACTIVE) ) - { - maxsync = AHC_SYNCRATE_ULTRA2; - } - else - { - maxsync = AHC_SYNCRATE_ULTRA; - } - } - else if (p->features & AHC_ULTRA) - { - maxsync = AHC_SYNCRATE_ULTRA; - } - else - { - maxsync = AHC_SYNCRATE_FAST; - } + if(maxsync == AHC_SYNCRATE_ULTRA3) + maxsync = AHC_SYNCRATE_ULTRA2; + /* * We might have a device that is starting negotiation with us * before we can start up negotiation with it....be prepared to @@ -5471,88 +5526,116 @@ if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) != (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) { - if (!(p->dev_flags[tindex] & DEVICE_SCANNED) && - !(p->needsdtr_copy & target_mask) && - (p->transinfo[tindex].user_offset) ) + if (!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED)) { /* - * Not only is the device starting this up, but it also hasn't - * been scanned yet, so this would likely be our TUR or our - * INQUIRY command at scan time, so we need to use the - * settings from the SEEPROM if they existed. Of course, even - * if we didn't find a SEEPROM, we stuffed default values into - * the user settings anyway, so use those in all cases. + * We shouldn't get here unless this is a narrow drive, wide + * devices should trigger this same section of code in the WDTR + * handler first instead. */ - p->transinfo[tindex].goal_period = - p->transinfo[tindex].user_period; - if(p->features & AHC_ULTRA2) - { - p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; - } - else if (p->transinfo[tindex].cur_width) + p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT; + p->transinfo[tindex].goal_options = 0; + if(p->transinfo[tindex].user_offset) { - p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; + p->needsdtr_copy |= target_mask; + p->transinfo[tindex].goal_period = + MAX(10,p->transinfo[tindex].user_period); + if(p->features & AHC_ULTRA2) + { + p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; + } + else + { + p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; + } } else { - p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; + p->needsdtr_copy &= ~target_mask; + p->transinfo[tindex].goal_period = 255; + p->transinfo[tindex].goal_offset = 0; } - p->needsdtr_copy |= target_mask; + p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR; + } + else if ((p->needsdtr_copy & target_mask) == 0) + { + /* + * This is a preemptive message from the target, we've already + * scanned this target and set our options for it, and we + * don't need a WDTR with this target (for whatever reason), + * so reject this incoming WDTR + */ + reject = TRUE; + break; } + + /* The device is sending this message first and we have to reply */ + reply = TRUE; + if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) { printk(INFO_LEAD "Received pre-emptive SDTR message from " "target.\n", p->host_no, CTL_OF_SCB(scb)); } - if ( !p->transinfo[tindex].goal_offset ) - period = 255; - if ( p->transinfo[tindex].goal_period > period ) - period = p->transinfo[tindex].goal_period; + /* + * Validate the values the device passed to us against our SEEPROM + * settings. We don't have to do this if we aren't replying since + * the device isn't allowed to send values greater than the ones + * we first sent to it. + */ + new_period = MAX(period, p->transinfo[tindex].goal_period); + new_offset = MIN(offset, p->transinfo[tindex].goal_offset); } - - syncrate = aic7xxx_find_syncrate(p, &period, maxsync, &options); - aic7xxx_validate_offset(p, syncrate, &offset, - target_scsirate & WIDEXFER); - aic7xxx_set_syncrate(p, syncrate, target, channel, period, - offset, options, AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + + /* + * Use our new_period, new_offset, bus_width, and card options + * to determine the actual syncrate settings + */ + syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync, + &trans_options); + aic7xxx_validate_offset(p, syncrate, &new_offset, bus_width); /* - * Did we drop to async? Or are we sending a reply? If we are, - * then we have to make sure that the reply value reflects the proper - * settings so we need to set the goal values according to what - * we need to send. + * Did we drop to async? If so, send a reply regardless of whether + * or not we initiated this negotiation. */ - if ( (offset != saved_offset) || - ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) != - (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) ) + if ((new_offset == 0) && (new_offset != offset)) { - aic7xxx_set_syncrate(p, syncrate, target, channel, period, offset, - options, AHC_TRANS_GOAL|AHC_TRANS_QUITE); + p->needsdtr_copy &= ~target_mask; + reply = TRUE; } /* - * Did we start this, if not, or if we went to low and had to + * Did we start this, if not, or if we went too low and had to * go async, then send an SDTR back to the target */ - p->needsdtr &= ~target_mask; - p->dtr_pending &= ~target_mask; - if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) != - (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) || - (offset != saved_offset) ) + if(reply) { - reply = TRUE; - p->dtr_pending |= target_mask; + /* when sending a reply, make sure that the goal settings are + * updated along with current and active since the code that + * will actually build the message for the sequencer uses the + * goal settings as its guidelines. + */ + aic7xxx_set_syncrate(p, syncrate, target, channel, new_period, + new_offset, trans_options, + AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR); scb->flags &= ~SCB_MSGOUT_BITS; scb->flags |= SCB_MSGOUT_SDTR; aic_outb(p, HOST_MSG, MSG_OUT); aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); } + else + { + aic7xxx_set_syncrate(p, syncrate, target, channel, new_period, + new_offset, trans_options, + AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + p->needsdtr &= ~target_mask; + } done = TRUE; break; } case MSG_EXT_WDTR: { - unsigned char bus_width; if (p->msg_buf[1] != MSG_EXT_WDTR_LEN) { @@ -5565,7 +5648,8 @@ break; } - bus_width = p->msg_buf[3]; + bus_width = new_bus_width = p->msg_buf[3]; + if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR)) == (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR) ) { @@ -5584,7 +5668,7 @@ } /* We fall through on purpose */ case MSG_EXT_WDTR_BUS_8_BIT: { - bus_width = MSG_EXT_WDTR_BUS_8_BIT; + p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT; p->needwdtr_copy &= ~target_mask; break; } @@ -5593,29 +5677,40 @@ break; } } - p->dtr_pending &= ~target_mask; p->needwdtr &= ~target_mask; + aic7xxx_set_width(p, target, channel, lun, new_bus_width, + AHC_TRANS_ACTIVE|AHC_TRANS_CUR); } else { - if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) ) + if ( !(p->dev_flags[tindex] & DEVICE_DTR_SCANNED) ) { /* * Well, we now know the WDTR and SYNC caps of this device since * it contacted us first, mark it as such and copy the user stuff * over to the goal stuff. */ - p->transinfo[tindex].goal_period = - p->transinfo[tindex].user_period; + if( (p->features & AHC_WIDE) && p->transinfo[tindex].user_width ) + { + p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_16_BIT; + p->needwdtr_copy |= target_mask; + } + + /* + * Devices that support DT transfers don't start WDTR requests + */ + p->transinfo[tindex].goal_options = 0; + if(p->transinfo[tindex].user_offset) { + p->needsdtr_copy |= target_mask; + p->transinfo[tindex].goal_period = + MAX(10,p->transinfo[tindex].user_period); if(p->features & AHC_ULTRA2) { p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; } - else if( p->transinfo[tindex].user_width && - (bus_width == MSG_EXT_WDTR_BUS_16_BIT) && - p->features & AHC_WIDE ) + else if( p->transinfo[tindex].goal_width ) { p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; } @@ -5623,48 +5718,76 @@ { p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; } + } else { + p->needsdtr_copy &= ~target_mask; + p->transinfo[tindex].goal_period = 255; + p->transinfo[tindex].goal_offset = 0; } - p->transinfo[tindex].goal_width = - p->transinfo[tindex].user_width; - p->needwdtr_copy |= target_mask; - p->needsdtr_copy |= target_mask; + + p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR; } - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) + else if ((p->needwdtr_copy & target_mask) == 0) { - printk(INFO_LEAD "Received pre-emptive WDTR message from " - "target.\n", p->host_no, CTL_OF_SCB(scb)); - } - switch(bus_width) + /* + * This is a preemptive message from the target, we've already + * scanned this target and set our options for it, and we + * don't need a WDTR with this target (for whatever reason), + * so reject this incoming WDTR + */ + reject = TRUE; + break; + } + + /* The device is sending this message first and we have to reply */ + reply = TRUE; + + if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) { - default: + printk(INFO_LEAD "Received pre-emptive WDTR message from " + "target.\n", p->host_no, CTL_OF_SCB(scb)); + } + switch(bus_width) + { + case MSG_EXT_WDTR_BUS_16_BIT: { if ( (p->features & AHC_WIDE) && (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT) ) { - bus_width = MSG_EXT_WDTR_BUS_16_BIT; + new_bus_width = MSG_EXT_WDTR_BUS_16_BIT; break; } } /* Fall through if we aren't a wide card */ + default: case MSG_EXT_WDTR_BUS_8_BIT: { p->needwdtr_copy &= ~target_mask; - bus_width = MSG_EXT_WDTR_BUS_8_BIT; - aic7xxx_set_width(p, target, channel, lun, bus_width, - AHC_TRANS_GOAL|AHC_TRANS_QUITE); + new_bus_width = MSG_EXT_WDTR_BUS_8_BIT; break; } } - reply = TRUE; scb->flags &= ~SCB_MSGOUT_BITS; scb->flags |= SCB_MSGOUT_WDTR; p->needwdtr &= ~target_mask; - p->dtr_pending |= target_mask; + if((p->dtr_pending & target_mask) == 0) + { + /* there is no other command with SCB_DTR_SCB already set that will + * trigger the release of the dtr_pending bit. Both set the bit + * and set scb->flags |= SCB_DTR_SCB + */ + p->dtr_pending |= target_mask; + scb->flags |= SCB_DTR_SCB; + } aic_outb(p, HOST_MSG, MSG_OUT); aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); + /* when sending a reply, make sure that the goal settings are + * updated along with current and active since the code that + * will actually build the message for the sequencer uses the + * goal settings as its guidelines. + */ + aic7xxx_set_width(p, target, channel, lun, new_bus_width, + AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR); } - aic7xxx_set_width(p, target, channel, lun, bus_width, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR); /* * By virtue of the SCSI spec, a WDTR message negates any existing @@ -5681,10 +5804,6 @@ } case MSG_EXT_PPR: { - unsigned char bus_width, trans_options, new_trans_options; - unsigned int period, offset; - unsigned char maxsync, saved_offset; - struct aic7xxx_syncrate *syncrate; if (p->msg_buf[1] != MSG_EXT_PPR_LEN) { @@ -5697,9 +5816,9 @@ break; } - period = p->msg_buf[3]; - offset = saved_offset = p->msg_buf[5]; - bus_width = p->msg_buf[6]; + period = new_period = p->msg_buf[3]; + offset = new_offset = p->msg_buf[5]; + bus_width = new_bus_width = p->msg_buf[6]; trans_options = new_trans_options = p->msg_buf[7] & 0xf; if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) @@ -5709,22 +5828,6 @@ trans_options); } - if ( (aic_inb(p, SBLKCTL) & ENAB40) && - !(aic_inb(p, SSTAT2) & EXP_ACTIVE) ) - { - if(p->features & AHC_ULTRA3) - { - maxsync = AHC_SYNCRATE_ULTRA3; - } - else - { - maxsync = AHC_SYNCRATE_ULTRA2; - } - } - else - { - maxsync = AHC_SYNCRATE_ULTRA; - } /* * We might have a device that is starting negotiation with us * before we can start up negotiation with it....be prepared to @@ -5733,13 +5836,22 @@ */ if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) != (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR) ) - { - reply = TRUE; - scb->flags &= ~SCB_MSGOUT_BITS; - scb->flags |= SCB_MSGOUT_PPR; - p->dev_flags[tindex] |= DEVICE_SCSI_3; - if (!(p->dev_flags[tindex] & DEVICE_SCANNED)) - { + { + /* Have we scanned the device yet? */ + if (!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED)) + { + /* The device is electing to use PPR messages, so we will too until + * we know better */ + p->needppr |= target_mask; + p->needppr_copy |= target_mask; + p->needsdtr &= ~target_mask; + p->needsdtr_copy &= ~target_mask; + p->needwdtr &= ~target_mask; + p->needwdtr_copy &= ~target_mask; + + /* We know the device is SCSI-3 compliant due to PPR */ + p->dev_flags[tindex] |= DEVICE_SCSI_3; + /* * Not only is the device starting this up, but it also hasn't * been scanned yet, so this would likely be our TUR or our @@ -5748,15 +5860,19 @@ * if we didn't find a SEEPROM, we stuffed default values into * the user settings anyway, so use those in all cases. */ - p->transinfo[tindex].goal_period = - p->transinfo[tindex].user_period; + p->transinfo[tindex].goal_width = + p->transinfo[tindex].user_width; if(p->transinfo[tindex].user_offset) { + p->transinfo[tindex].goal_period = + p->transinfo[tindex].user_period; + p->transinfo[tindex].goal_options = + p->transinfo[tindex].user_options; if(p->features & AHC_ULTRA2) { p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; } - else if( p->transinfo[tindex].user_width && + else if( p->transinfo[tindex].goal_width && (bus_width == MSG_EXT_WDTR_BUS_16_BIT) && p->features & AHC_WIDE ) { @@ -5767,117 +5883,142 @@ p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; } } - p->transinfo[tindex].goal_width = - p->transinfo[tindex].user_width; - p->transinfo[tindex].goal_options = - p->transinfo[tindex].user_options; + else + { + p->transinfo[tindex].goal_period = 255; + p->transinfo[tindex].goal_offset = 0; + p->transinfo[tindex].goal_options = 0; + } + p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR; } + else if ((p->needppr_copy & target_mask) == 0) + { + /* + * This is a preemptive message from the target, we've already + * scanned this target and set our options for it, and we + * don't need a PPR with this target (for whatever reason), + * so reject this incoming PPR + */ + reject = TRUE; + break; + } + + /* The device is sending this message first and we have to reply */ + reply = TRUE; + if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) { printk(INFO_LEAD "Received pre-emptive PPR message from " "target.\n", p->host_no, CTL_OF_SCB(scb)); } - if ( !p->transinfo[tindex].goal_offset ) - period = 255; - if ( p->transinfo[tindex].goal_period > period ) - period = p->transinfo[tindex].goal_period; - if ( p->transinfo[tindex].goal_options == 0 ) - new_trans_options = 0; - switch(bus_width) + + } + + switch(bus_width) + { + case MSG_EXT_WDTR_BUS_16_BIT: { - default: + if ( (p->transinfo[tindex].goal_width == + MSG_EXT_WDTR_BUS_16_BIT) && p->features & AHC_WIDE) { - if ( (p->features & AHC_WIDE) && - (p->transinfo[tindex].goal_width == - MSG_EXT_WDTR_BUS_16_BIT) ) - { - bus_width = MSG_EXT_WDTR_BUS_16_BIT; - break; - } - } /* Fall through if we aren't a wide card */ - case MSG_EXT_WDTR_BUS_8_BIT: - { - p->needwdtr_copy &= ~target_mask; - bus_width = MSG_EXT_WDTR_BUS_8_BIT; - aic7xxx_set_width(p, target, channel, lun, bus_width, - AHC_TRANS_GOAL|AHC_TRANS_QUITE); break; } } - if ( (p->transinfo[tindex].goal_period > 9) || - (p->transinfo[tindex].goal_options == 0) ) + default: { - scb->flags &= ~SCB_MSGOUT_BITS; - reject = TRUE; - reply = FALSE; - p->needppr &= ~(1 << tindex); - p->needppr_copy &= ~(1 << tindex); - if ( p->transinfo[tindex].goal_offset ) + if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && + ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) || + (aic7xxx_verbose > 0xffff)) ) { - p->needsdtr |= (1 << tindex); - p->needsdtr_copy |= (1 << tindex); - } - if ( p->transinfo[tindex].goal_width ) - { - p->needwdtr |= (1 << tindex); - p->needwdtr_copy |= (1 << tindex); + reply = TRUE; + printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n", + p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width)); } + } /* We fall through on purpose */ + case MSG_EXT_WDTR_BUS_8_BIT: + { + /* + * According to the spec, if we aren't wide, we also can't be + * Dual Edge so clear the options byte + */ + new_trans_options = 0; + new_bus_width = MSG_EXT_WDTR_BUS_8_BIT; + break; } } + + if(reply) + { + /* when sending a reply, make sure that the goal settings are + * updated along with current and active since the code that + * will actually build the message for the sequencer uses the + * goal settings as its guidelines. + */ + aic7xxx_set_width(p, target, channel, lun, new_bus_width, + AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync, + &new_trans_options); + aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width); + aic7xxx_set_syncrate(p, syncrate, target, channel, new_period, + new_offset, new_trans_options, + AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + } else { - switch(bus_width) + aic7xxx_set_width(p, target, channel, lun, new_bus_width, + AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync, + &new_trans_options); + aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width); + aic7xxx_set_syncrate(p, syncrate, target, channel, new_period, + new_offset, new_trans_options, + AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + } + + /* + * As it turns out, if we don't *have* to have PPR messages, then + * configure ourselves not to use them since that makes some + * external drive chassis work (those chassis can't parse PPR + * messages and they mangle the SCSI bus until you send a WDTR + * and SDTR that they can understand). + */ + if(new_trans_options == 0) + { + p->needppr &= ~target_mask; + p->needppr_copy &= ~target_mask; + if(new_offset) { - default: - { - reject = TRUE; - if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) || - (aic7xxx_verbose > 0xffff)) ) - { - printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n", - p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width)); - } - } /* We fall through on purpose */ - case MSG_EXT_WDTR_BUS_8_BIT: - { - /* - * According to the spec, if we aren't wide, we also can't be - * Dual Edge so clear the options byte - */ - new_trans_options = 0; - bus_width = MSG_EXT_WDTR_BUS_8_BIT; - break; - } - case MSG_EXT_WDTR_BUS_16_BIT: - { - break; - } + p->needsdtr |= target_mask; + p->needsdtr_copy |= target_mask; + } + if (new_bus_width) + { + p->needwdtr |= target_mask; + p->needwdtr_copy |= target_mask; } } - if ( !reject ) + if((new_offset == 0) && (offset != 0)) { - aic7xxx_set_width(p, target, channel, lun, bus_width, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR); - syncrate = aic7xxx_find_syncrate(p, &period, maxsync, - &new_trans_options); - aic7xxx_validate_offset(p, syncrate, &offset, bus_width); - aic7xxx_set_syncrate(p, syncrate, target, channel, period, - offset, new_trans_options, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + /* + * Oops, the syncrate went to low for this card and we fell off + * to async (should never happen with a device that uses PPR + * messages, but have to be complete) + */ + reply = TRUE; } - p->dtr_pending &= ~target_mask; - p->needppr &= ~target_mask; if(reply) { - p->dtr_pending |= target_mask; scb->flags &= ~SCB_MSGOUT_BITS; scb->flags |= SCB_MSGOUT_PPR; aic_outb(p, HOST_MSG, MSG_OUT); aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); } + else + { + p->needppr &= ~target_mask; + } done = TRUE; break; } @@ -6115,16 +6256,14 @@ printerror = 0; } } - if ( (scb != NULL) && - (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) ) + if ( (scb != NULL) && (scb->flags & SCB_DTR_SCB) ) { /* - * This might be a SCSI-3 device that is dropping the bus due to - * errors and signalling that we should reduce the transfer speed. - * All we have to do is complete this command (since it's a negotiation - * command already) and the checksum routine should flag an error and - * reduce the speed setting and renegotiate. We call the reset routing - * just to clean out the hardware from this scb. + * Hmmm...error during a negotiation command. Either we have a + * borken bus, or the device doesn't like our negotiation message. + * Since we check the INQUIRY data of a device before sending it + * negotiation messages, assume the bus is borken for whatever + * reason. Complete the command. */ printerror = 0; aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag); @@ -6256,19 +6395,6 @@ cmd->result = 0; scb = NULL; } - else if (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) - { - /* - * Turn off the needsdtr, needwdtr, and needppr bits since this device - * doesn't seem to exist. - */ - p->needppr &= ~(0x01 << TARGET_INDEX(scb->cmd)); - p->needppr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd)); - p->needsdtr &= ~(0x01 << TARGET_INDEX(scb->cmd)); - p->needsdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd)); - p->needwdtr &= ~(0x01 << TARGET_INDEX(scb->cmd)); - p->needwdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd)); - } } /* * Keep the sequencer from trying to restart any selections @@ -6391,7 +6517,6 @@ } } else if( (lastphase == P_MESGOUT) && - (cmd == p->dev_dtr_cmnd[tindex]) && (scb->flags & SCB_MSGOUT_PPR) ) { /* @@ -6410,7 +6535,6 @@ aic7xxx_set_syncrate(p, NULL, scb->cmd->target, scb->cmd->channel, 0, 0, 0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE); p->transinfo[tindex].goal_options = 0; - p->dtr_pending &= ~(1 << tindex); scb->flags &= ~SCB_MSGOUT_BITS; if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) { @@ -6433,87 +6557,6 @@ } scb = NULL; } - else if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR) - { - struct aic7xxx_syncrate *syncrate; - unsigned int period = p->transinfo[tindex].cur_period; - unsigned char options = p->transinfo[tindex].cur_options; - /* - * oops, we had a failure, lower the transfer rate and try again. It's - * worth noting here that it might be wise to also check for typical - * wide setting on narrow cable type problems and try disabling wide - * instead of slowing down if those exist. That's hard to do with simple - * checksums though. - */ - printk(WARN_LEAD "Parity error during %s phase.\n", - p->host_no, CTL_OF_SCB(scb), phase); - if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL) - { - syncrate++; - if( (syncrate->rate[0] != NULL) && - (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) ) - { - p->transinfo[tindex].goal_period = syncrate->period; - if( p->transinfo[tindex].goal_period > 9 ) - { - p->transinfo[tindex].goal_options = 0; - p->needppr &= ~(1<<tindex); - p->needsdtr |= (1<<tindex); - p->needppr_copy &= ~(1<<tindex); - p->needsdtr_copy |= (1<<tindex); - if (p->transinfo[tindex].goal_width) - { - p->needwdtr |= (1<<tindex); - p->needwdtr_copy |= (1<<tindex); - } - } - } - else if (p->transinfo[tindex].goal_width) - { - p->transinfo[tindex].goal_width = 0; - p->needwdtr &= ~(1<<tindex); - p->needwdtr_copy &= ~(1<<tindex); - p->transinfo[tindex].goal_offset = - p->transinfo[tindex].user_offset; - p->transinfo[tindex].goal_period = - p->transinfo[tindex].user_period; - p->transinfo[tindex].goal_options = - p->transinfo[tindex].user_options; - if( p->transinfo[tindex].goal_period <= 9 ) - { - p->needppr |= (1<<tindex); - p->needsdtr &= ~(1<<tindex); - p->needppr_copy |= (1<<tindex); - p->needsdtr_copy &= ~(1<<tindex); - } - else - { - p->needppr &= ~(1<<tindex); - p->needsdtr |= (1<<tindex); - p->needppr_copy &= ~(1<<tindex); - p->needsdtr_copy |= (1<<tindex); - } - } - else - { - p->transinfo[tindex].goal_offset = 0; - p->transinfo[tindex].goal_period = 255; - p->transinfo[tindex].goal_options = 0; - p->transinfo[tindex].goal_width = 0; - p->needppr &= ~(1<<tindex); - p->needsdtr &= ~(1<<tindex); - p->needwdtr &= ~(1<<tindex); - p->needppr_copy &= ~(1<<tindex); - p->needsdtr_copy &= ~(1<<tindex); - p->needwdtr_copy &= ~(1<<tindex); - } - } - p->dev_flags[tindex] &= ~DEVICE_PARITY_ERROR; - } - else - { - p->dev_flags[tindex] |= DEVICE_PARITY_ERROR; - } /* * We've set the hardware to assert ATN if we get a parity @@ -6782,34 +6825,11 @@ else if (scb->flags & SCB_SENSE) { char *buffer = &scb->cmd->sense_buffer[0]; - if (scb->cmd == p->dev_dtr_cmnd[tindex]) - { - struct aic7xxx_scb *old_scb; - /* - * We have valid sense data, send it back immediately. - */ - old_scb = p->scb_data->scb_array[scb->cmd->next->tag]; - *old_scb->cmd->sense_buffer = *scb->cmd->sense_buffer; - old_scb->hscb->target_status = scb->hscb->target_status; - old_scb->cmd->result = scb->hscb->target_status; - old_scb->cmd->result |= (DID_ERROR << 16); - aic7xxx_status(old_scb->cmd) = scb->hscb->target_status; - scbq_remove(&p->waiting_scbs, old_scb); - scbq_remove(&p->delayed_scbs[tindex], old_scb); - scb->cmd->next = NULL; - aic7xxx_done(p, scb); - aic7xxx_done(p, old_scb); - continue; - } - else if (buffer[12] == 0x47 || buffer[12] == 0x54) + + if (buffer[12] == 0x47 || buffer[12] == 0x54) { /* - * SCSI errors, run domain validation and re-run negotiation - */ - p->needdv |= (1<<tindex); - /* - * Signal that we need to re-negotiate things, this also gets us our - * INQUIRY command to re-checksum off of. + * Signal that we need to re-negotiate things. */ p->needppr |= (p->needppr_copy & (1<<tindex)); p->needsdtr |= (p->needsdtr_copy & (1<<tindex)); @@ -6822,7 +6842,18 @@ case BUSY: scb->hscb->target_status = 0; scb->cmd->result = 0; + scb->hscb->residual_SG_segment_count = 0; + scb->hscb->residual_data_count[0] = 0; + scb->hscb->residual_data_count[1] = 0; + scb->hscb->residual_data_count[2] = 0; aic7xxx_error(scb->cmd) = DID_OK; + aic7xxx_status(scb->cmd) = 0; + /* + * The QUEUE_FULL/BUSY handler in aic7xxx_seqint takes care of putting + * this command on a timer and allowing us to retry it. Here, we + * just 0 out a few values so that they don't carry through to when + * the command finally does complete. + */ break; default: cmd = scb->cmd; @@ -6987,18 +7018,14 @@ if(!p) return; spin_lock_irqsave(&io_request_lock, cpu_flags); - if(test_and_set_bit(AHC_IN_ISR_BIT, (void *)&p->flags)) - { - spin_unlock_irqrestore(&io_request_lock, cpu_flags); - return; - } + p->flags |= AHC_IN_ISR; do { aic7xxx_isr(irq, dev_id, regs); } while ( (aic_inb(p, INTSTAT) & INT_PEND) ); aic7xxx_done_cmds_complete(p); aic7xxx_run_waiting_queues(p); - clear_bit(AHC_IN_ISR_BIT, (void *)&p->flags); + p->flags &= ~AHC_IN_ISR; spin_unlock_irqrestore(&io_request_lock, cpu_flags); } @@ -8779,7 +8806,7 @@ /* * In the future, we may call this function as a last resort for - * error handling. Let's be nice and not do any unecessary delays. + * error handling. Let's be nice and not do any unnecessary delays. */ wait = 1000; /* 1 msec (1000 * 1 msec) */ while (--wait && !(aic_inb(p, HCNTRL) & CHIPRSTACK)) @@ -8922,22 +8949,6 @@ kfree(p->scb_data); } - /* - * Free any alloced Scsi_Cmnd structures that might be around for - * negotiation purposes.... - */ - for (i = 0; i < MAX_TARGETS; i++) - { - if(p->dev_dtr_cmnd[i]) - { - if(p->dev_dtr_cmnd[i]->request_buffer) - { - kfree(p->dev_dtr_cmnd[i]->request_buffer); - } - kfree(p->dev_dtr_cmnd[i]); - } - } - pci_free_consistent(p->pdev, 3*256, (void *)p->untagged_scbs, p->fifo_dma); } @@ -9324,7 +9335,7 @@ } aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB); aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1); - p->needppr = p->needppr_copy = p->needdv = 0; + p->needppr = p->needppr_copy = 0; p->needwdtr = p->needwdtr_copy; p->needsdtr = p->needsdtr_copy; p->dtr_pending = 0; @@ -9382,6 +9393,81 @@ /*+F************************************************************************* * Function: + * aic7xxx_configure_bugs + * + * Description: + * Take the card passed in and set the appropriate bug flags based upon + * the card model. Also make any changes needed to device registers or + * PCI registers while we are here. + *-F*************************************************************************/ +static void +aic7xxx_configure_bugs(struct aic7xxx_host *p) +{ + unsigned short tmp_word; + + switch(p->chip & AHC_CHIPID_MASK) + { + case AHC_AIC7860: + p->bugs |= AHC_BUG_PCI_2_1_RETRY; + /* fall through */ + case AHC_AIC7850: + case AHC_AIC7870: + p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI; + break; + case AHC_AIC7880: + p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY | + AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI; + break; + case AHC_AIC7890: + p->bugs |= AHC_BUG_AUTOFLUSH | AHC_BUG_CACHETHEN; + break; + case AHC_AIC7892: + p->bugs |= AHC_BUG_SCBCHAN_UPLOAD; + break; + case AHC_AIC7895: + p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY | + AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI; + break; + case AHC_AIC7896: + p->bugs |= AHC_BUG_CACHETHEN_DIS; + break; + case AHC_AIC7899: + p->bugs |= AHC_BUG_SCBCHAN_UPLOAD; + break; + default: + /* Nothing to do */ + break; + } + + /* + * Now handle the bugs that require PCI register or card register tweaks + */ + pci_read_config_word(p->pdev, PCI_COMMAND, &tmp_word); + if(p->bugs & AHC_BUG_PCI_MWI) + { + tmp_word &= ~PCI_COMMAND_INVALIDATE; + } + else + { + tmp_word |= PCI_COMMAND_INVALIDATE; + } + pci_write_config_word(p->pdev, PCI_COMMAND, tmp_word); + + if(p->bugs & AHC_BUG_CACHETHEN) + { + aic_outb(p, aic_inb(p, DSCOMMAND0) & ~CACHETHEN, DSCOMMAND0); + } + else if (p->bugs & AHC_BUG_CACHETHEN_DIS) + { + aic_outb(p, aic_inb(p, DSCOMMAND0) | CACHETHEN, DSCOMMAND0); + } + + return; +} + + +/*+F************************************************************************* + * Function: * aic7xxx_detect * * Description: @@ -10075,6 +10161,14 @@ aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS); } + /* + * Call our function to fixup any bugs that exist on this chipset. + * This may muck with PCI settings and other device settings, so + * make sure it's after all the other PCI and device register + * tweaks so it can back out bad settings on specific broken cards. + */ + aic7xxx_configure_bugs(temp_p); + if ( list_p == NULL ) { list_p = current_p = temp_p; @@ -10318,6 +10412,11 @@ } /* + * All the 7770 based chipsets have this bug + */ + temp_p->bugs |= AHC_BUG_TMODE_WIDEODD; + + /* * Set the FIFO threshold and the bus off time. */ hostconf = aic_inb(temp_p, HOSTCONF); @@ -10536,308 +10635,16 @@ return (found); } -static void aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, - Scsi_Cmnd *old_cmd, int tindex); - +#ifdef AIC7XXX_VERBOSE_DEBUGGING /*+F************************************************************************* * Function: - * aic7xxx_allocate_negotiation_command + * aic7xxx_print_scb * * Description: - * allocate the actual command struct and fill in the gaps... + * Dump the byte codes for an about to be sent SCB. *-F*************************************************************************/ -static Scsi_Cmnd * -aic7xxx_allocate_negotiation_command(struct aic7xxx_host *p, - Scsi_Cmnd *old_cmd, int tindex) -{ - Scsi_Cmnd *cmd; - char *buffer; - - if (!(p->dev_dtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) ) - { - return(NULL); - } - if (!(buffer = kmalloc(256, GFP_ATOMIC))) - { - kfree(p->dev_dtr_cmnd[tindex]); - p->dev_dtr_cmnd[tindex] = NULL; - return(NULL); - } - cmd = p->dev_dtr_cmnd[tindex]; - memset(cmd, 0, sizeof(Scsi_Cmnd)); - memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd)); - memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd)); - memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd)); - cmd->lun = 0; - cmd->request_bufflen = 255; - cmd->request_buffer = buffer; - cmd->sc_data_direction = SCSI_DATA_READ; - cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0; - cmd->bufflen = 0; - cmd->buffer = NULL; - cmd->underflow = 0; - cmd->cmd_len = 6; - cmd->cmnd[0] = cmd->data_cmnd[0] = INQUIRY; - cmd->cmnd[1] = cmd->data_cmnd[1] = 0; - cmd->cmnd[2] = cmd->data_cmnd[2] = 0; - cmd->cmnd[3] = cmd->data_cmnd[3] = 0; - cmd->cmnd[4] = cmd->data_cmnd[4] = 255; /* match what scsi.c does here */ - cmd->cmnd[5] = cmd->data_cmnd[5] = 0; - return(cmd); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_negotiation_complete - * - * Description: - * Handle completion events for our Negotiation commands. Clear out the - * struct and get it ready for its next use. - *-F*************************************************************************/ -static void -aic7xxx_negotiation_complete(Scsi_Cmnd *cmd) -{ - unsigned int checksum; - int i; - int *ibuffer; - struct aic7xxx_host *p = (struct aic7xxx_host *)cmd->host->hostdata; - int tindex = TARGET_INDEX(cmd); - struct aic7xxx_syncrate *syncrate; - - /* - * perform our minimalistic domain validation - */ - if(p->dev_flags[tindex] & DEVICE_SCANNED) - { - ibuffer = (int *)cmd->request_buffer; - checksum = 0; - for(i = 0; i < (cmd->request_bufflen >> 2); i++) - { - checksum += ibuffer[i]; - } - if( (checksum != p->dev_checksum[tindex]) && - (p->transinfo[tindex].cur_offset != 0) ) - { - unsigned int period = p->transinfo[tindex].cur_period; - unsigned char options = p->transinfo[tindex].cur_options; - - if (p->needdv & (1<<tindex)) - { - /* - * oops, we had a failure, lower the transfer rate and try again. It's - * worth noting here that it might be wise to also check for typical - * wide setting on narrow cable type problems and try disabling wide - * instead of slowing down if those exist. That's hard to do with simple - * checksums though. - */ - if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "reducing SCSI transfer speed due to Domain " - "validation failure.\n", p->host_no, CTL_OF_CMD(cmd)); - } - if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL) - { - syncrate++; - if( (syncrate->rate[0] != NULL) && - (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) ) - { - p->transinfo[tindex].goal_period = syncrate->period; - if( p->transinfo[tindex].goal_period > 9 ) - { - p->transinfo[tindex].goal_options = 0; - p->needppr &= ~(1<<tindex); - p->needsdtr |= (1<<tindex); - p->needppr_copy &= ~(1<<tindex); - p->needsdtr_copy |= (1<<tindex); - if (p->transinfo[tindex].goal_width) - { - p->needwdtr |= (1<<tindex); - p->needwdtr_copy |= (1<<tindex); - } - } - } - else if (p->transinfo[tindex].goal_width) - { - p->transinfo[tindex].goal_width = 0; - p->needwdtr &= ~(1<<tindex); - p->needwdtr_copy &= ~(1<<tindex); - p->transinfo[tindex].goal_offset = - p->transinfo[tindex].user_offset; - p->transinfo[tindex].goal_period = - p->transinfo[tindex].user_period; - p->transinfo[tindex].goal_options = - p->transinfo[tindex].user_options; - if( p->transinfo[tindex].goal_period <= 9 ) - { - p->needppr |= (1<<tindex); - p->needsdtr &= ~(1<<tindex); - p->needppr_copy |= (1<<tindex); - p->needsdtr_copy &= ~(1<<tindex); - } - else - { - p->needppr &= ~(1<<tindex); - p->needsdtr |= (1<<tindex); - p->needppr_copy &= ~(1<<tindex); - p->needsdtr_copy |= (1<<tindex); - } - } - else - { - p->transinfo[tindex].goal_offset = 0; - p->transinfo[tindex].goal_period = 255; - p->transinfo[tindex].goal_options = 0; - p->transinfo[tindex].goal_width = 0; - p->needppr &= ~(1<<tindex); - p->needsdtr &= ~(1<<tindex); - p->needwdtr &= ~(1<<tindex); - p->needppr_copy &= ~(1<<tindex); - p->needsdtr_copy &= ~(1<<tindex); - p->needwdtr_copy &= ~(1<<tindex); - } - } - p->needdv &= ~(1<<tindex); - } - else - { - if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Performing Domain validation.\n", - p->host_no, CTL_OF_CMD(cmd)); - } - /* - * Update the checksum in case the INQUIRY data has changed, maybe - * in relation to a change in the mode pages, or whatever. - */ - p->dev_checksum[tindex] = checksum; - /* - * Signal that we are trying out the domain validation - */ - p->needdv |= (1<<tindex); - /* - * Signal that we need to re-negotiate things, this also gets us our - * INQUIRY command to re-checksum off of. - */ - p->needppr |= (p->needppr_copy & (1<<tindex)); - p->needsdtr |= (p->needsdtr_copy & (1<<tindex)); - p->needwdtr |= (p->needwdtr_copy & (1<<tindex)); - } - } - else - { - if( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - (p->needdv & (1<<tindex)) ) - { - printk(INFO_LEAD "Successfully completed Domain validation.\n", - p->host_no, CTL_OF_CMD(cmd)); - } - /* - * We successfully did our checksum, so don't leave the needdv flag set - * in case we might have set it last time through. - */ - p->needdv &= ~(1<<tindex); - } - } - - p->dtr_pending &= ~(0x01 << tindex); - /* - * This looks recursive in the extreme, but if this was a WDTR negotiation - * and we didn't follow up with SDTR yet, then this will get it started. - * For all other cases, this should work out to be a no-op, unless we are - * doing domain validation and happen to need a new negotiation command. - * - * In case we don't want this to go any further, the cmdcmplt interrupt - * handler will NULL out the cmd->next entry so that the real SCSI command - * can be sent back to the mid layer code with SENSE data intact. We'll - * finish things up when the cmd gets sent back down to us, so no worries. - */ - if(cmd->next) - { - aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex); - } - return; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_build_negotiation_command - * - * Description: - * Build a Scsi_Cmnd structure to perform negotiation with or else send - * a pre-built command specifically for this purpose. - *-F*************************************************************************/ -static void -aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, Scsi_Cmnd *old_cmd, - int tindex) -{ - - if ( !(p->dtr_pending & (1<<tindex)) && - ( (p->needppr & (1<<tindex)) || - (p->needwdtr & (1<<tindex)) || - (p->needsdtr & (1<<tindex)) ) ) - { - if ( (p->dev_dtr_cmnd[tindex] == NULL) && - (aic7xxx_allocate_negotiation_command(p, old_cmd, tindex) == NULL) ) - { - return; - } - /* - * Before sending this thing out, we also make the cmd->next pointer - * point to the real command so we can stuff any possible SENSE data - * into the real command instead of this fake command. This has to be - * done each time the command is built, not just the first time, hence - * it's outside of the above if()... - */ - p->dev_dtr_cmnd[tindex]->next = old_cmd; - /* - * Clear the buffer so checksums come out right.... - */ - memset(p->dev_dtr_cmnd[tindex]->request_buffer, 0, - p->dev_dtr_cmnd[tindex]->request_bufflen); - /* - * Remove any commands for this particular device that might be on the - * waiting_scbs queue or qinfifo so that this command goes out first. - * This is vital for our implementation of domain validation. - */ - pause_sequencer(p); - aic7xxx_search_qinfifo(p, old_cmd->target, old_cmd->channel, ALL_LUNS, - SCB_LIST_NULL, 0, TRUE, &p->delayed_scbs[tindex]); - unpause_sequencer(p, FALSE); - { - struct aic7xxx_scb *scb, *next; - - scb = p->waiting_scbs.head; - while(scb != NULL) - { - if( aic7xxx_match_scb(p, scb, old_cmd->target, old_cmd->channel, - ALL_LUNS, SCB_LIST_NULL) ) - { - next = scb->q_next; - scbq_remove(&p->waiting_scbs, scb); - scbq_insert_tail(&p->delayed_scbs[tindex], scb); - scb = next; - } - else - { - scb = scb->q_next; - } - } - } - aic7xxx_queue(p->dev_dtr_cmnd[tindex], - aic7xxx_negotiation_complete); - } -} - -#ifdef AIC7XXX_VERBOSE_DEBUGGING -/*+F************************************************************************* - * Function: - * aic7xxx_print_scb - * - * Description: - * Dump the byte codes for an about to be sent SCB. - *-F*************************************************************************/ -static void -aic7xxx_print_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb) +static void +aic7xxx_print_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb) { int i; unsigned char *x; @@ -10876,7 +10683,7 @@ */ hscb->control = 0; scb->tag_action = 0; - cmd->tag = hscb->tag; + if (p->discenable & mask) { hscb->control |= DISCENB; @@ -10905,34 +10712,29 @@ } } } - if ( cmd == p->dev_dtr_cmnd[tindex] ) + if ( !(p->dtr_pending & mask) && + ( (p->needppr & mask) || + (p->needwdtr & mask) || + (p->needsdtr & mask) ) && + (p->dev_flags[tindex] & DEVICE_DTR_SCANNED) ) { p->dtr_pending |= mask; scb->tag_action = 0; - if (p->dev_flags[tindex] & DEVICE_SCANNED) + hscb->control &= DISCENB; + hscb->control |= MK_MESSAGE; + if(p->needppr & mask) { - hscb->control &= DISCENB; - hscb->control |= MK_MESSAGE; - if(p->needppr & mask) - { - scb->flags |= SCB_MSGOUT_PPR; - } - else if(p->needwdtr & mask) - { - scb->flags |= SCB_MSGOUT_WDTR; - } - else if(p->needsdtr & mask) - { - scb->flags |= SCB_MSGOUT_SDTR; - } + scb->flags |= SCB_MSGOUT_PPR; } - } - if ( !(p->dtr_pending & mask) && - ( (p->needppr & mask) || - (p->needwdtr & mask) || - (p->needsdtr & mask) ) ) - { - aic7xxx_build_negotiation_cmnd(p, cmd, tindex); + else if(p->needwdtr & mask) + { + scb->flags |= SCB_MSGOUT_WDTR; + } + else if(p->needsdtr & mask) + { + scb->flags |= SCB_MSGOUT_SDTR; + } + scb->flags |= SCB_DTR_SCB; } hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) | ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07); @@ -11078,50 +10880,58 @@ aic7xxx_allocate_scb(p); DRIVER_UNLOCK scb = scbq_remove_head(&p->scb_data->free_scbs); - } - if (scb == NULL) - { - printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no, - CTL_OF_CMD(cmd)); - cmd->result = (DID_BUS_BUSY << 16); + if(scb == NULL) + printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no, + CTL_OF_CMD(cmd)); + } + while (scb == NULL) + { + /* + * Well, all SCBs are currently active on the bus. So, we spin here + * running the interrupt handler until one completes and becomes free. + * We can do this safely because we either A) hold the driver lock (in + * 2.0 kernels) or we have the io_request_lock held (in 2.2 and later + * kernels) and so either way, we won't take any other interrupts and + * the queue path will block until we release it. Also, we would worry + * about running the completion queues, but obviously there are plenty + * of commands outstanding to trigger a later interrupt that will do + * that for us, so skip it here. + */ DRIVER_LOCK - aic7xxx_queue_cmd_complete(p, cmd); + aic7xxx_isr(p->irq, p, NULL); DRIVER_UNLOCK - return 0; + scb = scbq_remove_head(&p->scb_data->free_scbs); } - else - { - scb->cmd = cmd; - aic7xxx_position(cmd) = scb->hscb->tag; + scb->cmd = cmd; + aic7xxx_position(cmd) = scb->hscb->tag; - /* - * Construct the SCB beforehand, so the sequencer is - * paused a minimal amount of time. - */ - aic7xxx_buildscb(p, cmd, scb); + /* + * Make sure the Scsi_Cmnd pointer is saved, the struct it points to + * is set up properly, and the parity error flag is reset, then send + * the SCB to the sequencer and watch the fun begin. + */ + cmd->scsi_done = fn; + cmd->result = DID_OK; + memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); + aic7xxx_error(cmd) = DID_OK; + aic7xxx_status(cmd) = 0; + cmd->host_scribble = NULL; - /* - * Make sure the Scsi_Cmnd pointer is saved, the struct it points to - * is set up properly, and the parity error flag is reset, then send - * the SCB to the sequencer and watch the fun begin. - */ - cmd->scsi_done = fn; - cmd->result = DID_OK; - memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); - aic7xxx_error(cmd) = DID_OK; - aic7xxx_status(cmd) = 0; - cmd->host_scribble = NULL; + /* + * Construct the SCB beforehand, so the sequencer is + * paused a minimal amount of time. + */ + aic7xxx_buildscb(p, cmd, scb); - scb->flags |= SCB_ACTIVE | SCB_WAITINGQ; + scb->flags |= SCB_ACTIVE | SCB_WAITINGQ; - DRIVER_LOCK - scbq_insert_tail(&p->waiting_scbs, scb); - if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0) - { - aic7xxx_run_waiting_queues(p); - } - DRIVER_UNLOCK + DRIVER_LOCK + scbq_insert_tail(&p->waiting_scbs, scb); + if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0) + { + aic7xxx_run_waiting_queues(p); } + DRIVER_UNLOCK return (0); } @@ -11187,6 +10997,12 @@ aic_inb(p, SCSISIGI), aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); + printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", p->host_no, + CTL_OF_SCB(scb), + (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0, + aic_inb(p, SSTAT2), + aic_inb(p, STCNT + 2) << 16 | aic_inb(p, STCNT + 1) << 8 | + aic_inb(p, STCNT)); } channel = cmd->channel; @@ -11357,7 +11173,6 @@ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) unsigned long cpu_flags = 0; #endif - Scsi_Cmnd *cmd_next, *cmd_prev; p = (struct aic7xxx_host *) cmd->host->hostdata; scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]); @@ -11366,7 +11181,7 @@ * I added a new config option to the driver: "panic_on_abort" that will * cause the driver to panic and the machine to stop on the first abort * or reset call into the driver. At that point, it prints out a lot of - * usefull information for me which I can then use to try and debug the + * useful information for me which I can then use to try and debug the * problem. Simply enable the boot time prompt in order to activate this * code. */ @@ -11387,13 +11202,11 @@ { aic7xxx_isr(p->irq, p, (void *)NULL); pause_sequencer(p); - aic7xxx_done_cmds_complete(p); } + aic7xxx_done_cmds_complete(p); - if ((scb == NULL) || (cmd->serial_number != cmd->serial_number_at_timeout)) - /* Totally bogus cmd since it points beyond our */ - { /* valid SCB range or doesn't even match it's own*/ - /* timeout serial number. */ + if (scb == NULL) + { if (aic7xxx_verbose & VERBOSE_ABORT_MID) printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd " "pointer.\n", p->host_no, CTL_OF_CMD(cmd)); @@ -11412,28 +11225,6 @@ /* finish successfully, or to indicate that we */ /* don't have this cmd any more and the mid level */ /* code needs to find it. */ - cmd_next = p->completeq.head; - cmd_prev = NULL; - while (cmd_next != NULL) - { - if (cmd_next == cmd) - { - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "Abort called for command " - "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd)); - if ( cmd_prev == NULL ) - p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble; - else - cmd_prev->host_scribble = cmd_next->host_scribble; - cmd_next->scsi_done(cmd_next); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_ABORT_NOT_RUNNING); /* It's already back as a successful - * completion */ - } - cmd_prev = cmd_next; - cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble; - } if (aic7xxx_verbose & VERBOSE_ABORT_MID) printk(INFO_LEAD "Abort called for already completed" " command.\n", p->host_no, CTL_OF_CMD(cmd)); @@ -11491,8 +11282,20 @@ found = 0; p->flags |= AHC_IN_ABORT; if (aic7xxx_verbose & VERBOSE_ABORT) - printk(INFO_LEAD "Aborting scb %d, flags 0x%x\n", - p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags); + { + printk(INFO_LEAD "Aborting scb %d, flags 0x%x, SEQADDR 0x%x, LASTPHASE " + "0x%x\n", + p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags, + aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), + aic_inb(p, LASTPHASE)); + printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n", + p->host_no, CTL_OF_SCB(scb), (p->features & AHC_ULTRA2) ? + aic_inb(p, SG_CACHEPTR) : 0, aic_inb(p, SG_COUNT), + aic_inb(p, SCSISIGI)); + printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n", + p->host_no, CTL_OF_SCB(scb), aic_inb(p, SSTAT0), + aic_inb(p, SSTAT1), aic_inb(p, SSTAT2)); + } /* * First, let's check to see if the currently running command is our target @@ -11520,6 +11323,16 @@ if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) printk(INFO_LEAD "SCB is currently active. " "Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb)); + printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 " + "0x%x\n", p->host_no, CTL_OF_SCB(scb), + aic_inb(p, SCSISIGI), + aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), + aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); + printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", + p->host_no, CTL_OF_SCB(scb), + (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0, + aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 | + aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT)); unpause_sequencer(p, FALSE); p->flags &= ~AHC_IN_ABORT; scb->flags |= SCB_RECOVERY_SCB; /* Note the fact that we've been */ @@ -11535,35 +11348,7 @@ if ((found == 0) && (scb->flags & SCB_WAITINGQ)) { int tindex = TARGET_INDEX(cmd); - unsigned short mask; - - mask = (1 << tindex); - if (p->dtr_pending & mask) - { - if (p->dev_dtr_cmnd[tindex]->next != cmd) - found = 1; - else - found = 0; - } - else - { - found = 1; - } - if (found == 0) - { - /* - * OK..this means the command we are currently getting an abort - * for has an outstanding negotiation command in front of it. - * We don't really have a way to tie back into the negotiation - * commands, so we just send this back as pending, then it - * will get reset in 2 seconds. - */ - unpause_sequencer(p, TRUE); - scb->flags |= SCB_ABORT; - DRIVER_UNLOCK - return(SCSI_ABORT_PENDING); - } if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) printk(INFO_LEAD "SCB found on waiting list and " "aborted.\n", p->host_no, CTL_OF_SCB(scb)); @@ -11720,10 +11505,8 @@ #define DEVICE_RESET 0x01 #define BUS_RESET 0x02 #define HOST_RESET 0x04 -#define FAIL 0x08 -#define RESET_DELAY 0x10 +#define RESET_DELAY 0x08 int action; - Scsi_Cmnd *cmd_prev, *cmd_next; if ( cmd == NULL ) @@ -11741,7 +11524,7 @@ * I added a new config option to the driver: "panic_on_abort" that will * cause the driver to panic and the machine to stop on the first abort * or reset call into the driver. At that point, it prints out a lot of - * usefull information for me which I can then use to try and debug the + * useful information for me which I can then use to try and debug the * problem. Simply enable the boot time prompt in order to activate this * code. */ @@ -11751,86 +11534,32 @@ DRIVER_LOCK pause_sequencer(p); - while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR)) - { - aic7xxx_isr(p->irq, p, (void *)NULL ); - pause_sequencer(p); - aic7xxx_done_cmds_complete(p); - } - if (scb == NULL) + if(flags & SCSI_RESET_SYNCHRONOUS) { if (aic7xxx_verbose & VERBOSE_RESET_MID) - printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd" - "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd)); - if ( flags & SCSI_RESET_SUGGEST_HOST_RESET ) - { - action = HOST_RESET; - } - else - { - action = BUS_RESET; - } + printk(INFO_LEAD "Reset called for a SYNCHRONOUS reset, flags 0x%x, " + "cmd->result 0x%x.\n", p->host_no, CTL_OF_CMD(cmd), flags, + cmd->result); + scb = NULL; + action = HOST_RESET; } - else if (scb->cmd != cmd) + else if ((scb == NULL) || (scb->cmd != cmd)) { if (aic7xxx_verbose & VERBOSE_RESET_MID) - printk(INFO_LEAD "Reset called with recycled SCB " - "for cmd.\n", p->host_no, CTL_OF_CMD(cmd)); - cmd_prev = NULL; - cmd_next = p->completeq.head; - while ( cmd_next != NULL ) - { - if (cmd_next == cmd) - { - if (aic7xxx_verbose & VERBOSE_RESET_RETURN) - printk(INFO_LEAD "Reset, found cmd on completeq" - ", completing.\n", p->host_no, CTL_OF_CMD(cmd)); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_RESET_NOT_RUNNING); - } - cmd_prev = cmd_next; - cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble; - } - if ( !(flags & SCSI_RESET_SYNCHRONOUS) ) - { - if (aic7xxx_verbose & VERBOSE_RESET_RETURN) - printk(INFO_LEAD "Reset, cmd not found," - " failing.\n", p->host_no, CTL_OF_CMD(cmd)); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_RESET_NOT_RUNNING); - } - else - { - if (aic7xxx_verbose & VERBOSE_RESET_MID) - printk(INFO_LEAD "Reset called, no scb, " - "flags 0x%x\n", p->host_no, CTL_OF_CMD(cmd), flags); - scb = NULL; - action = HOST_RESET; - } + printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd" + "->SCB mapping, failing.\n", p->host_no, CTL_OF_CMD(cmd)); + aic7xxx_done_cmds_complete(p); + aic7xxx_run_waiting_queues(p); + unpause_sequencer(p, FALSE); + DRIVER_UNLOCK + return(SCSI_RESET_NOT_RUNNING); } else { if (aic7xxx_verbose & VERBOSE_RESET_MID) printk(INFO_LEAD "Reset called, scb %d, flags " "0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags); - if ( aic7xxx_scb_on_qoutfifo(p, scb) ) - { - if(aic7xxx_verbose & VERBOSE_RESET_RETURN) - printk(INFO_LEAD "SCB on qoutfifo, completing.\n", p->host_no, - CTL_OF_SCB(scb)); - if ((aic_inb(p,INTSTAT) & CMDCMPLT) == 0) - printk(INFO_LEAD "missed CMDCMPLT interrupt!\n", p->host_no, - CTL_OF_SCB(scb)); - aic7xxx_handle_command_completion_intr(p); - aic7xxx_done_cmds_complete(p); - aic7xxx_run_waiting_queues(p); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_RESET_SUCCESS); - } if ( flags & SCSI_RESET_SUGGEST_HOST_RESET ) { action = HOST_RESET; @@ -11844,6 +11573,26 @@ action = DEVICE_RESET; } } + + while((aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR)) + { + aic7xxx_isr(p->irq, p, (void *)NULL ); + pause_sequencer(p); + } + aic7xxx_done_cmds_complete(p); + + if(scb && (scb->cmd == NULL)) + { + /* + * We just completed the command when we ran the isr stuff, so we no + * longer have it. + */ + aic7xxx_run_waiting_queues(p); + unpause_sequencer(p, FALSE); + DRIVER_UNLOCK + return(SCSI_RESET_SUCCESS); + } + if ( (action & DEVICE_RESET) && (p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) ) { @@ -11903,14 +11652,13 @@ switch (action) { case RESET_DELAY: + aic7xxx_run_waiting_queues(p); unpause_sequencer(p, FALSE); DRIVER_UNLOCK - return(SCSI_RESET_PENDING); - break; - case FAIL: - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_RESET_ERROR); + if(scb == NULL) + return(SCSI_RESET_PUNT); + else + return(SCSI_RESET_PENDING); break; case DEVICE_RESET: p->flags |= AHC_IN_RESET; @@ -11928,7 +11676,7 @@ case HOST_RESET: default: p->flags |= AHC_IN_RESET | AHC_RESET_DELAY; - p->dev_expires[p->scsi_id] = jiffies + (3 * HZ); + p->dev_expires[p->scsi_id] = jiffies + (1 * HZ); p->dev_timer_active |= (0x01 << p->scsi_id); if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) || time_after_eq(p->dev_timer.expires, p->dev_expires[p->scsi_id]) ) @@ -11955,21 +11703,14 @@ p->msg_index = 0; p->msg_len = 0; } - aic7xxx_run_done_queue(p, TRUE); - /* - * If this a SCSI_RESET_SYNCHRONOUS then the command we were given is - * in need of being re-started, so send it on through to aic7xxx_queue - * and let it set until the delay is over. This keeps it from dying - * entirely and avoids getting a bogus dead command back through the - * mid-level code due to too many retries. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132) - if ( flags & SCSI_RESET_SYNCHRONOUS ) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + if(flags & SCSI_RESET_SYNCHRONOUS) { - cmd->result = DID_BUS_BUSY << 16; + cmd->result = DID_RESET << 16; cmd->done(cmd); } #endif + aic7xxx_run_done_queue(p, TRUE); p->flags &= ~AHC_IN_RESET; /* * We can't rely on run_waiting_queues to unpause the sequencer for @@ -11980,7 +11721,10 @@ aic7xxx_run_waiting_queues(p); unpause_sequencer(p, FALSE); DRIVER_UNLOCK - return(result); + if(scb == NULL) + return(SCSI_RESET_SUCCESS|SCSI_RESET_HOST_RESET); + else + return(result); break; } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/dec_esp.c linux.ac/drivers/scsi/dec_esp.c --- linux.vanilla/drivers/scsi/dec_esp.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/scsi/dec_esp.c Tue Apr 3 17:55:03 2001 @@ -87,7 +87,7 @@ unsigned char scsi_pmaz_dma_buff_used[ESP_NCMD]; unsigned char scsi_cur_buff = 1; /* Leave space for command buffer */ __u32 esp_virt_buffer; -int scsi_current_length = 0; +int scsi_current_length; volatile unsigned char cmd_buffer[16]; volatile unsigned char pmaz_cmd_buffer[16]; @@ -181,10 +181,13 @@ esp->esp_command_dvma = (__u32) KSEG1ADDR((volatile unsigned char *) cmd_buffer); esp->irq = SCSI_INT; - request_irq(esp->irq, esp_intr, SA_INTERRUPT, "NCR 53C94 SCSI", - NULL); - request_irq(SCSI_DMA_INT, scsi_dma_int, SA_INTERRUPT, "JUNKIO SCSI DMA", - NULL); + if (request_irq(esp->irq, esp_intr, SA_INTERRUPT, + "NCR 53C94 SCSI", NULL)) + goto err_dealloc; + if (request_irq(SCSI_DMA_INT, scsi_dma_int, SA_INTERRUPT, + "JUNKIO SCSI DMA", NULL)) + goto err_free_irq; + esp->scsi_id = 7; @@ -257,7 +260,12 @@ esp->dma_mmu_release_scsi_sgl = 0; esp->dma_advance_sg = 0; - request_irq(esp->irq, esp_intr, SA_INTERRUPT, "PMAZ_AA", NULL); + if (request_irq(esp->irq, esp_intr, SA_INTERRUPT, + "PMAZ_AA", NULL)) { + esp_deallocate(esp); + release_tc_card(slot); + continue; + } esp->scsi_id = 7; esp->diff = 0; esp_initialize(esp); @@ -267,10 +275,16 @@ if(nesps) { printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); - esps_running = esps_in_use; - return esps_in_use; - } else - return 0; + esps_running = esps_in_use; + return esps_in_use; + } + return 0; + + err_free_irq: + free_irq(esp->irq, esp_intr); + err_dealloc: + esp_deallocate(esp); + return 0; } /************************************************************* DMA Functions */ @@ -524,4 +538,4 @@ (char *) KSEG0ADDR((sp->request_buffer)); } -#endif \ No newline at end of file +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/eata_dma.c linux.ac/drivers/scsi/eata_dma.c --- linux.vanilla/drivers/scsi/eata_dma.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/scsi/eata_dma.c Tue Apr 3 17:55:03 2001 @@ -1066,7 +1066,7 @@ char *buff = 0; unchar bugs = 0; struct Scsi_Host *sh; - hostdata *hd; + hostdata *hd=NULL; int x; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/fastlane.c linux.ac/drivers/scsi/fastlane.c --- linux.vanilla/drivers/scsi/fastlane.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/scsi/fastlane.c Thu Apr 12 12:04:02 2001 @@ -76,7 +76,7 @@ volatile unsigned char cmd_buffer[16]; /* This is where all commands are put - * before they are transfered to the ESP chip + * before they are transferred to the ESP chip * via PIO. */ @@ -96,9 +96,7 @@ * this ID value. Fortunately only Fastlane maps in Z3 space */ if (board < 0x1000000) { - release_mem_region(board+FASTLANE_ESP_ADDR, - sizeof(struct ESP_regs)); - return 0; + goto err_release; } esp = esp_allocate(tpnt, (void *)board+FASTLANE_ESP_ADDR); @@ -146,10 +144,7 @@ if(!address){ printk("Could not remap Fastlane controller memory!"); - scsi_unregister (esp->ehost); - release_mem_region(board+FASTLANE_ESP_ADDR, - sizeof(struct ESP_regs)); - return 0; + goto err_unregister; } @@ -171,8 +166,11 @@ esp->irq = IRQ_AMIGA_PORTS; esp->slot = board+FASTLANE_ESP_ADDR; - request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ, - "Fastlane SCSI", esp_intr); + if (request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ, + "Fastlane SCSI", esp_intr)) { + printk(KERN_WARNING "Fastlane: Could not get IRQ%d, aborting.\n", IRQ_AMIGA_PORTS); + goto err_unmap; + } /* Controller ID */ esp->scsi_id = 7; @@ -188,6 +186,15 @@ return esps_in_use; } } + return 0; + + err_unmap: + iounmap((void *)address); + err_unregister: + scsi_unregister (esp->ehost); + err_release: + release_mem_region(z->resource.start+FASTLANE_ESP_ADDR, + sizeof(struct ESP_regs)); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/hosts.c linux.ac/drivers/scsi/hosts.c --- linux.vanilla/drivers/scsi/hosts.c Mon Oct 30 22:44:29 2000 +++ linux.ac/drivers/scsi/hosts.c Tue Apr 3 17:55:03 2001 @@ -232,6 +232,7 @@ retval->use_clustering = tpnt->use_clustering; retval->select_queue_depths = tpnt->select_queue_depths; + retval->max_sectors = tpnt->max_sectors; if(!scsi_hostlist) scsi_hostlist = retval; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/hosts.h linux.ac/drivers/scsi/hosts.h --- linux.vanilla/drivers/scsi/hosts.h Thu Feb 22 00:10:51 2001 +++ linux.ac/drivers/scsi/hosts.h Tue Apr 17 17:49:03 2001 @@ -242,6 +242,11 @@ short unsigned int sg_tablesize; /* + * if the host adapter has limitations beside segment count + */ + short unsigned int max_sectors; + + /* * True if this host adapter can make good use of linked commands. * This will allow more than one command to be queued to a given * unit on a given host. Set this to the maximum number of command @@ -379,6 +384,7 @@ int can_queue; short cmd_per_lun; short unsigned int sg_tablesize; + short unsigned int max_sectors; unsigned in_recovery:1; unsigned unchecked_isa_dma:1; @@ -509,7 +515,7 @@ /* These are used by loadable modules */ extern int scsi_register_module(int, void *); -extern void scsi_unregister_module(int, void *); +extern int scsi_unregister_module(int, void *); /* The different types of modules that we can load and unload */ #define MODULE_SCSI_HA 1 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/i91uscsi.c linux.ac/drivers/scsi/i91uscsi.c --- linux.vanilla/drivers/scsi/i91uscsi.c Tue Apr 3 17:32:20 2001 +++ linux.ac/drivers/scsi/i91uscsi.c Tue Apr 3 17:55:03 2001 @@ -590,7 +590,7 @@ int init_tulip(HCS * pCurHcb, SCB * scbp, int tul_num_scb, BYTE * pbBiosAdr, int seconds) { int i; - WORD *pwFlags; + BYTE *pwFlags; BYTE *pbHeads; SCB *pTmpScb, *pPrevScb = NULL; @@ -674,7 +674,7 @@ ((pCurHcb->HCS_Config & HCC_AUTO_TERM) >> 4) | (TUL_RD(pCurHcb->HCS_Base, TUL_GCTRL1) & 0xFE)); for (i = 0, - pwFlags = (WORD *) & (i91unvramp->NVM_SCSIInfo[0].NVM_Targ0Config), + pwFlags = & (i91unvramp->NVM_SCSIInfo[0].NVM_Targ0Config), pbHeads = pbBiosAdr + 0x180; i < pCurHcb->HCS_MaxTar; i++, pwFlags++) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/ips.c linux.ac/drivers/scsi/ips.c --- linux.vanilla/drivers/scsi/ips.c Tue Apr 3 17:32:20 2001 +++ linux.ac/drivers/scsi/ips.c Tue Apr 3 17:55:03 2001 @@ -4902,7 +4902,7 @@ /****************************************************************************/ static int ips_init_copperhead_memio(ips_ha_t *ha) { - u8 Isr; + u8 Isr=0; u8 Cbsp; u8 PostByte[IPS_MAX_POST_BYTES]; u8 ConfigByte[IPS_MAX_CONFIG_BYTES]; @@ -5708,7 +5708,7 @@ spin_unlock(&io_request_lock); } - UDELAY(1000); /* 1 milisecond */ + UDELAY(1000); /* 1 millisecond */ time--; } @@ -6153,7 +6153,7 @@ static int ips_erase_bios(ips_ha_t *ha) { int timeout; - u8 status; + u8 status=0; METHOD_TRACE("ips_erase_bios", 1); @@ -6372,7 +6372,7 @@ ips_program_bios(ips_ha_t *ha, char *buffer, int buffersize) { int i; int timeout; - u8 status; + u8 status=0; METHOD_TRACE("ips_program_bios", 1); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/megaraid.c linux.ac/drivers/scsi/megaraid.c --- linux.vanilla/drivers/scsi/megaraid.c Tue Apr 3 17:32:20 2001 +++ linux.ac/drivers/scsi/megaraid.c Tue Apr 3 17:55:03 2001 @@ -75,7 +75,7 @@ * Changed megaraid_command to use wait_queue. * * Version 1.00: - * Checks to see if an irq ocurred while in isr, and runs through + * Checks to see if an irq occurred while in isr, and runs through * routine again. * Copies mailbox to temp area before processing in isr * Added barrier() in busy wait to fix volatility bug @@ -293,6 +293,9 @@ * Left 2.0 support but removed 2.1.x support. * Collected much of the compat glue into one spot * + * Version 1.14g-ac2 - 22/03/01 + * Fixed a non obvious dereference after free in the driver unload path + * * BUGS: * Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that * fails to detect the controller as a pci device on the system. @@ -391,6 +394,11 @@ writel (value, megaCfg->base + 0x2C); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) /* 0x020200 */ +#include <linux/smp.h> +#define cpuid smp_processor_id() +#endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020100 */ /* @@ -401,9 +409,6 @@ * queue task is a simple api without irq forms */ -#include <linux/smp.h> -#define cpuid smp_processor_id() - MODULE_AUTHOR ("American Megatrends Inc."); MODULE_DESCRIPTION ("AMI MegaRAID driver"); @@ -428,10 +433,8 @@ * No pci region api * queue_task is now a single simple API */ - -#include <linux/smp.h> -#define cpuid smp_processor_id() +static char kernel_version[] = UTS_RELEASE; MODULE_AUTHOR ("American Megatrends Inc."); MODULE_DESCRIPTION ("AMI MegaRAID driver"); @@ -2764,7 +2767,6 @@ sizeof (mega_mailbox64), (void *) megaCfg->mailbox64ptr, megaCfg->dma_handle64); - scsi_unregister (pSHost); #ifdef CONFIG_PROC_FS if (megaCfg->controller_proc_dir_entry) { @@ -2785,12 +2787,21 @@ #endif /* + * Release the controller memory. A word of warning this frees + * hostdata and that includes megaCfg-> so be careful what you + * dereference beyond this point + */ + + scsi_unregister (pSHost); + + /* * Unregister the character device interface to the driver. Ideally this * should have been done in cleanup_module routine. Since this is hidden * in file "scsi_module.c", we do it here. * major is the major number of the character device returned by call to * register_chrdev() routine. */ + unregister_chrdev (major, "megadev"); unregister_reboot_notifier (&mega_notifier); @@ -4299,12 +4310,10 @@ } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) -static Scsi_Host_Template driver_template = MEGARAID; -#include "scsi_module.c" -#else -#ifdef MODULE +static +#endif /* LINUX VERSION 2.4.XX */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) || defined(MODULE) Scsi_Host_Template driver_template = MEGARAID; #include "scsi_module.c" -#endif /* MODULE */ -#endif /* LINUX VERSION 2.4.XX test */ +#endif /* LINUX VERSION 2.4.XX || MODULE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/megaraid.h linux.ac/drivers/scsi/megaraid.h --- linux.vanilla/drivers/scsi/megaraid.h Tue Apr 3 17:32:21 2001 +++ linux.ac/drivers/scsi/megaraid.h Sat Apr 14 15:50:52 2001 @@ -27,7 +27,7 @@ #define M_RD_IOCTL_CMD_NEW 0x81 #define M_RD_DRIVER_IOCTL_INTERFACE 0x82 -#define MEGARAID_VERSION "v1.14g (Release Date: Feb 5, 2001; 11:42)" +#define MEGARAID_VERSION "v1.14g-ac2 (Release Date: Mar 22, 2001; 19:34:02)" #define MEGARAID_IOCTL_VERSION 114 /* Methods */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/ncr53c8xx.c linux.ac/drivers/scsi/ncr53c8xx.c --- linux.vanilla/drivers/scsi/ncr53c8xx.c Tue Apr 3 17:32:21 2001 +++ linux.ac/drivers/scsi/ncr53c8xx.c Tue Apr 3 17:55:03 2001 @@ -3082,7 +3082,7 @@ }; /* -** Print something which allows to retrieve the controler type, unit, +** Print something which allows to retrieve the controller type, unit, ** target, lun concerned by a kernel message. */ @@ -4301,7 +4301,7 @@ ** **---------------------------------------------------- */ -#if 0 /* This stuff was only usefull for linux-1.2.13 */ +#if 0 /* This stuff was only useful for linux-1.2.13 */ if (lp && !lp->numtags && cmd->device && cmd->device->tagged_queue) { lp->numtags = tp->usrtags; ncr_setup_tags (np, cmd->target, cmd->lun); @@ -5700,7 +5700,7 @@ */ fak = (kpc - 1) / div_10M[div] + 1; -#if 0 /* This optimization does not seem very usefull */ +#if 0 /* This optimization does not seem very useful */ per = (fak * div_10M[div]) / clk; @@ -6646,7 +6646,7 @@ delta=(INB (nc_dfifo) - rest) & 0x7f; /* - ** The data in the dma fifo has not been transfered to + ** The data in the dma fifo has not been transferred to ** the target -> add the amount to the rest ** and clear the data. ** Check the sstat2 register in case of wide transfer. @@ -7152,7 +7152,7 @@ ** Was Sie schon immer ueber transfermode negotiation wissen wollten ... ** ** We try to negotiate sync and wide transfer only after -** a successfull inquire command. We look at byte 7 of the +** a successful inquire command. We look at byte 7 of the ** inquire data to determine the capabilities of the target. ** ** When we try to negotiate, we append the negotiation message @@ -7549,7 +7549,7 @@ /*========================================================== ** ** -** Aquire a control block +** Acquire a control block ** ** **========================================================== @@ -9271,9 +9271,9 @@ */ #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) -static Scsi_Host_Template driver_template = NCR53C8XX; -#include "scsi_module.c" -#elif defined(MODULE) +static +#endif +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) || defined(MODULE) Scsi_Host_Template driver_template = NCR53C8XX; #include "scsi_module.c" #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/osst.c linux.ac/drivers/scsi/osst.c --- linux.vanilla/drivers/scsi/osst.c Thu Jan 4 21:00:55 2001 +++ linux.ac/drivers/scsi/osst.c Tue Apr 3 17:55:03 2001 @@ -318,7 +318,8 @@ } } - cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0; + if (SRpnt->sr_device->scsi_level <= SCSI_2) + cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0; init_MUTEX_LOCKED(&STp->sem); SRpnt->sr_use_sg = (bytes > (STp->buffer)->sg[0].length) ? (STp->buffer)->use_sg : 0; @@ -679,7 +680,7 @@ result = osst_get_frame_position (STp, aSRpnt); if (result == -EIO) if ((result = osst_write_error_recovery(STp, aSRpnt, 0)) == 0) - return 0; /* successfull recovery leaves drive ready for frame */ + return 0; /* successful recovery leaves drive ready for frame */ if (result < 0) break; if (STp->first_frame_position == curr && ((minlast < 0 && diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/osst.h linux.ac/drivers/scsi/osst.h --- linux.vanilla/drivers/scsi/osst.h Sat Dec 30 19:23:14 2000 +++ linux.ac/drivers/scsi/osst.h Mon Apr 16 00:00:49 2001 @@ -591,7 +591,7 @@ unsigned char logical_blk_in_buffer; /* flag that the block as per logical_blk_num * has been read into STp->buffer and is valid */ int logical_blk_num; /* logical block number */ - unsigned first_frame_position; /* physical frame to be transfered to/from host */ + unsigned first_frame_position; /* physical frame to be transferred to/from host */ unsigned last_frame_position; /* physical frame to be transferd to/from tape */ int cur_frames; /* current number of frames in internal buffer */ int max_frames; /* max number of frames in internal buffer */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/pci2220i.c linux.ac/drivers/scsi/pci2220i.c --- linux.vanilla/drivers/scsi/pci2220i.c Tue Apr 3 17:32:21 2001 +++ linux.ac/drivers/scsi/pci2220i.c Tue Apr 3 17:55:04 2001 @@ -2393,7 +2393,7 @@ padapter->regRemap = zr + RTR_LOCAL_REMAP; // 32 bit local space remap padapter->regDesc = zr + RTR_REGIONS; // 32 bit local region descriptor padapter->regRange = zr + RTR_LOCAL_RANGE; // 32 bit local range - padapter->regIrqControl = zr + RTR_INT_CONTROL_STATUS; // 16 bit interupt control and status + padapter->regIrqControl = zr + RTR_INT_CONTROL_STATUS; // 16 bit interrupt control and status padapter->regScratchPad = zr + RTR_MAILBOX; // 16 byte scratchpad I/O base address padapter->regBase = zl; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/pcmcia/Config.in linux.ac/drivers/scsi/pcmcia/Config.in --- linux.vanilla/drivers/scsi/pcmcia/Config.in Tue Apr 3 17:32:21 2001 +++ linux.ac/drivers/scsi/pcmcia/Config.in Tue Apr 3 17:55:04 2001 @@ -8,12 +8,17 @@ bool 'PCMCIA SCSI adapter support' CONFIG_SCSI_PCMCIA if [ "$CONFIG_SCSI_PCMCIA" = "y" ]; then dep_tristate ' Adaptec AHA152X PCMCIA support' CONFIG_PCMCIA_AHA152X m - dep_tristate ' Qlogic PCMCIA support' CONFIG_PCMCIA_QLOGIC m + if [ "$CONFIG_CARDBUS" = "y" -a "$CONFIG_SCSI_AIC7XXX" = "n" ]; then + dep_tristate ' Adaptec APA1480 CardBus support' CONFIG_PCMCIA_APA1480 m + fi dep_tristate ' Future Domain PCMCIA support' CONFIG_PCMCIA_FDOMAIN m + dep_tristate ' NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support' CONFIG_PCMCIA_NINJA_SCSI m + dep_tristate ' Qlogic PCMCIA support' CONFIG_PCMCIA_QLOGIC m fi if [ "$CONFIG_PCMCIA_QLOGIC" = "y" -o "$CONFIG_PCMCIA_AHA152X" = "y" -o \ - "$CONFIG_PCMCIA_FDOMAIN" = "y" ]; then + "$CONFIG_PCMCIA_FDOMAIN" = "y" -o "$CONFIG_PCMCIA_APA1480" = "y" -o \ + "$CONFIG_PCMCIA_NINJA_SCSI" ]; then define_bool CONFIG_PCMCIA_SCSICARD y fi diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/pcmcia/Makefile linux.ac/drivers/scsi/pcmcia/Makefile --- linux.vanilla/drivers/scsi/pcmcia/Makefile Tue Apr 3 17:32:21 2001 +++ linux.ac/drivers/scsi/pcmcia/Makefile Tue Apr 3 18:05:13 2001 @@ -12,6 +12,7 @@ vpath %c .. CFLAGS_aha152x.o = -DPCMCIA -D__NO_VERSION__ -DAHA152X_STAT +CFLAGS_aic7xxx_old.o = -DPCMCIA -D__NO_VERSION__ CFLAGS_fdomain.o = -DPCMCIA -D__NO_VERSION__ CFLAGS_qlogicfas.o = -DPCMCIA -D__NO_VERSION__ @@ -19,9 +20,14 @@ obj-$(CONFIG_PCMCIA_QLOGIC) += qlogic_cs.o obj-$(CONFIG_PCMCIA_FDOMAIN) += fdomain_cs.o obj-$(CONFIG_PCMCIA_AHA152X) += aha152x_cs.o +obj-$(CONFIG_PCMCIA_NINJA_SCSI) += nsp_cs.o -list-multi := qlogic_cs.o fdomain_cs.o aha152x_cs.o +# Cardbus client drivers +obj-$(CONFIG_PCMCIA_APA1480) += apa1480_cb.o + +list-multi := qlogic_cs.o fdomain_cs.o aha152x_cs.o apa1480_cb.o aha152x_cs-objs := aha152x_stub.o aha152x.o +apa1480_cb-objs := apa1480_stub.o aic7xxx_old.o fdomain_cs-objs := fdomain_stub.o fdomain.o qlogic_cs-objs := qlogic_stub.o qlogicfas.o @@ -29,6 +35,9 @@ aha152x_cs.o: $(aha152x_cs-objs) $(LD) -r -o $@ $(aha152x_cs-objs) + +apa1480_cb.o: $(apa1480_cb-objs) + $(LD) -r -o $@ $(apa1480_cb-objs) fdomain_cs.o: $(fdomain_cs-objs) $(LD) -r -o $@ $(fdomain_cs-objs) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/pcmcia/apa1480_stub.c linux.ac/drivers/scsi/pcmcia/apa1480_stub.c --- linux.vanilla/drivers/scsi/pcmcia/apa1480_stub.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/scsi/pcmcia/apa1480_stub.c Tue Apr 3 17:55:04 2001 @@ -0,0 +1,176 @@ +/*====================================================================== + + A driver for the Adaptec APA1480 CardBus SCSI Host Adapter + + apa1480_cb.c 1.22 2000/06/12 21:27:25 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + <dahinds@users.sourceforge.net>. Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU General Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/ioport.h> +#include <scsi/scsi.h> +#include <linux/major.h> +#include <linux/blk.h> + +#include <../drivers/scsi/scsi.h> +#include <../drivers/scsi/hosts.h> +#include <scsi/scsi_ioctl.h> +#include <../drivers/scsi/aic7xxx_old/aic7xxx.h> + +#include <pcmcia/driver_ops.h> + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"apa1480_cb.c 1.22 2000/06/12 21:27:25 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +static int reset = 1; +static int ultra = 0; + +MODULE_PARM(reset, "i"); +MODULE_PARM(ultra, "i"); + +/*====================================================================*/ + +static Scsi_Host_Template driver_template = AIC7XXX; + +extern void aic7xxx_setup(char *, int *); + +static dev_node_t *apa1480_attach(dev_locator_t *loc); +static void apa1480_detach(dev_node_t *node); + +struct driver_operations apa1480_ops = { + "apa1480_cb", apa1480_attach, NULL, NULL, apa1480_detach +}; + +/*====================================================================*/ + +static dev_node_t *apa1480_attach(dev_locator_t *loc) +{ + u_char bus, devfn; + Scsi_Device *dev; + dev_node_t *node; + char s[60]; + int n = 0; + struct Scsi_Host *host; + + if (loc->bus != LOC_PCI) return NULL; + bus = loc->b.pci.bus; devfn = loc->b.pci.devfn; + printk(KERN_INFO "apa1480_attach(bus %d, function %d)\n", + bus, devfn); + + driver_template.module = &__this_module; + + sprintf(s, "no_probe:1,no_reset:%d,ultra:%d", + (reset==0), (ultra!=0)); + aic7xxx_setup(s, NULL); + scsi_register_module(MODULE_SCSI_HA, &driver_template); + + node = kmalloc(7 * sizeof(dev_node_t), GFP_KERNEL); + if (!node) + return NULL; + for (host = scsi_hostlist; host; host = host->next) + if (host->hostt == &driver_template) + for (dev = host->host_queue; dev; dev = dev->next) { + u_long arg[2], id; + kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg); + id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) + + ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000); + node[n].minor = 0; + switch (dev->type) { + case TYPE_TAPE: + node[n].major = SCSI_TAPE_MAJOR; + sprintf(node[n].dev_name, "st#%04lx", id); + break; + case TYPE_DISK: + case TYPE_MOD: + node[n].major = SCSI_DISK0_MAJOR; + sprintf(node[n].dev_name, "sd#%04lx", id); + break; + case TYPE_ROM: + case TYPE_WORM: + node[n].major = SCSI_CDROM_MAJOR; + sprintf(node[n].dev_name, "sr#%04lx", id); + break; + default: + node[n].major = SCSI_GENERIC_MAJOR; + sprintf(node[n].dev_name, "sg#%04lx", id); + break; + } + if (n) node[n-1].next = &node[n]; + n++; + } + if (n == 0) { + printk(KERN_INFO "apa1480_cs: no SCSI devices found\n"); + scsi_unregister_module(MODULE_SCSI_HA, &driver_template); + kfree(node); + return NULL; + } else + node[n-1].next = NULL; + + MOD_INC_USE_COUNT; + return node; +} + +static void apa1480_detach(dev_node_t *node) +{ + MOD_DEC_USE_COUNT; + scsi_unregister_module(MODULE_SCSI_HA, &driver_template); + kfree(node); +} + +/*====================================================================*/ + +static int __init init_apa1480_cb(void) { + DEBUG(0, "%s\n", version); + register_driver(&apa1480_ops); + return 0; +} + +static void __exit exit_apa1480_cb(void) { + DEBUG(0, "apa1480_cs: unloading\n"); + unregister_driver(&apa1480_ops); +} + +module_init(init_apa1480_cb); +module_exit(exit_apa1480_cb); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/pcmcia/nsp_cs.c linux.ac/drivers/scsi/pcmcia/nsp_cs.c --- linux.vanilla/drivers/scsi/pcmcia/nsp_cs.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/scsi/pcmcia/nsp_cs.c Tue Apr 3 17:55:04 2001 @@ -0,0 +1,1714 @@ +/*====================================================================== + + NinjaSCSI-3 / NinjaSCSI-32Bi PCMCIA SCSI hostadapter card driver + By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp> + + Ver.2.0 Support 32bit PIO mode + Ver.1.1.2 Fix for scatter list buffer exceeds + Ver.1.1 Support scatter list + Ver.0.1 Initial version + + This software may be used and distributed according to the terms of + the GNU General Public License. + +======================================================================*/ + +/*********************************************************************** + This driver is for these PCcards. + + I-O DATA PCSC-F (Workbit NinjaSCSI-3) + "WBT", "NinjaSCSI-3", "R1.0" + I-O DATA CBSC-II (Workbit NinjaSCSI-32Bi in 16bit mode) + "IO DATA", "CBSC16 ", "1" + +***********************************************************************/ + +/* $Id: nsp_cs.c,v 1.28 2001/02/15 02:56:32 elca Exp $ */ + +#ifdef NSP_KERNEL_2_2 +#include <pcmcia/config.h> +#include <pcmcia/k_compat.h> +#endif + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/tqueue.h> +#include <linux/interrupt.h> +#include <linux/major.h> +#include <linux/blk.h> +#include <linux/stat.h> + +#include <asm/io.h> +#include <asm/irq.h> + +#include <../drivers/scsi/scsi.h> +#include <../drivers/scsi/hosts.h> +#include <../drivers/scsi/sd.h> + +#include <scsi/scsi.h> +#include <scsi/scsi_ioctl.h> + +#include <pcmcia/version.h> +#include <pcmcia/cs_types.h> +#include <pcmcia/cs.h> +#include <pcmcia/cistpl.h> +#include <pcmcia/ds.h> + +#include "nsp_cs.h" + +MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>"); +MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module"); +MODULE_SUPPORTED_DEVICE("sd,sr,sg,st"); + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +MODULE_PARM_DESC(pc_debug, "set debug level"); +static char *version = "$Id: nsp_cs.c,v 1.28 2001/02/15 02:56:32 elca Exp $"; +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +#else +#define DEBUG(n, args...) /* */ +#endif + +#include "nsp_io.h" + +/*====================================================================*/ + +typedef struct scsi_info_t { + dev_link_t link; + struct Scsi_Host *host; + int ndev; + dev_node_t node[8]; + int stop; + struct bus_operations *bus; +} scsi_info_t; + +static void nsp_release(u_long arg); +static int nsp_event(event_t event, int priority, + event_callback_args_t *args); +static dev_link_t *nsp_attach(void); +static void nsp_detach(dev_link_t *); +static int nsp_detect(Scsi_Host_Template * ); +static const char * nsp_info(struct Scsi_Host *); +static int nsp_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); +static int nsp_abort(Scsi_Cmnd *); +static int nsp_reset(Scsi_Cmnd *, unsigned int); + + +/*----------------------------------------------------------------*/ + +#if (KERNEL_VERSION(2,4,0) > LINUX_VERSION_CODE) +#define PROC_SCSI_NSP PROC_SCSI_IBMMCA /* bad hack... */ +static struct proc_dir_entry proc_scsi_nsp = { + PROC_SCSI_NSP, 6, "nsp_cs", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; +#endif + +/*====================================================================*/ +/* Parameters that can be set with 'insmod' */ + +static unsigned int irq_mask = 0xffff; +MODULE_PARM(irq_mask, "i"); +MODULE_PARM_DESC(irq_mask, "IRQ mask bits"); + +static int irq_list[4] = { -1 }; +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM_DESC(irq_list, "IRQ number list"); + +/*----------------------------------------------------------------*/ +/* driver state info, local to driver */ +static char nspinfo[100]; /* description */ + +/* /usr/src/linux/drivers/scsi/hosts.h */ +static Scsi_Host_Template driver_template = { +/* next: NULL,*/ +/* proc_dir: NULL,*/ +/* proc_info: NULL,*/ + name: "WorkBit NinjaSCSI-3/32Bi", + detect: nsp_detect, +/* release: NULL,*/ + info: nsp_info, +/* command: NULL,*/ + queuecommand: nsp_queuecommand, +/* eh_strategy_handler: nsp_eh_strategy,*/ +/* eh_abort_handler: nsp_eh_abort,*/ +/* eh_device_reset_handler: nsp_eh_device_reset,*/ + eh_bus_reset_handler: nsp_eh_bus_reset, +/* eh_host_reset_handler: nsp_eh_host_reset,*/ + abort: nsp_abort, + reset: nsp_reset, +/* slave_attach: NULL,*/ +/* bios_param: nsp_biosparam,*/ + can_queue: 1, + this_id: -1, + sg_tablesize: SG_ALL, + cmd_per_lun: 1, +/* present: 0,*/ +/* unchecked_isa_dma: 0,*/ + use_clustering: DISABLE_CLUSTERING, + use_new_eh_code: 0, +/* emulated: 0,*/ +}; + +static dev_link_t *dev_list = NULL; +static dev_info_t dev_info = {"nsp_cs"}; + +static nsp_hw_data nsp_data; + +/***********************************************************/ + +static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +{ +#ifdef PCMCIA_DEBUG + //unsigned int host_id = SCpnt->host->this_id; + //unsigned int base = SCpnt->host->io_port; + unsigned char target = SCpnt->target; +#endif + + DEBUG(0, __FUNCTION__ "() SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d\n", + SCpnt, target, SCpnt->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg); + //DEBUG(0, " before CurrentSC=0x%p\n", nsp_data.CurrentSC); + + if(nsp_data.CurrentSC != NULL) { + printk(KERN_DEBUG " " __FUNCTION__ "() CurrentSC!=NULL this can't be happen\n"); + nsp_data.CurrentSC = NULL; + SCpnt->result = DID_BAD_TARGET << 16; + done(SCpnt); + return FAILED; + } + +#ifdef PCMCIA_DEBUG + show_command(SCpnt); +#endif + + SCpnt->scsi_done = done; + nsp_data.CurrentSC = SCpnt; + RESID = SCpnt->request_bufflen; + + SCpnt->SCp.Status = -1; + SCpnt->SCp.Message = -1; + SCpnt->SCp.have_data_in = IO_UNKNOWN; + SCpnt->SCp.sent_command = 0; + SCpnt->SCp.phase = PH_UNDETERMINED; + + /* setup scratch area + SCp.ptr : buffer pointer + SCp.this_residual : buffer length + SCp.buffer : next buffer + SCp.buffers_residual : left buffers in list + SCp.phase : current state of the command */ + if (SCpnt->use_sg) { + SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; + SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; + } else { + SCpnt->SCp.ptr = (char *) SCpnt->request_buffer; + SCpnt->SCp.this_residual = SCpnt->request_bufflen; + SCpnt->SCp.buffer = NULL; + SCpnt->SCp.buffers_residual = 0; + } + + if(nsphw_start_selection(SCpnt) == FALSE) { + DEBUG(0, " selection fail\n"); + nsp_data.CurrentSC = NULL; + SCpnt->result = DID_NO_CONNECT << 16; + done(SCpnt); + return FAILED; + } + + + //DEBUG(0, __FUNCTION__ "() out\n"); + return SUCCESS; +} + +/* + * setup PIO FIFO transfer mode and enable/disable to data out + */ +static void nsp_setup_fifo(unsigned int base, int enabled) +{ + unsigned char transfer_mode; + + //DEBUG(0, __FUNCTION__ "() enabled=%d\n", enabled); + + if (enabled != FALSE) { + transfer_mode = TRANSFER_GO | BRAIND; + } else { + transfer_mode = 0; + } + + transfer_mode |= nsp_data.TransferMode; + + nsp_index_write(base, TRANSFERMODE, transfer_mode); +} + +/* + * Initialize Ninja hardware + */ +static int nsphw_init(void) +{ + unsigned int base = nsp_data.BaseAddress; + int i, j; + sync_data tmp_sync = { SyncNegotiation: SYNC_NOT_YET, + SyncPeriod: 0, + SyncOffset: 0 + }; + + //DEBUG(0, __FUNCTION__ "() in\n"); + + nsp_data.ScsiClockDiv = CLOCK_40M; + nsp_data.CurrentSC = NULL; + nsp_data.FifoCount = 0; + nsp_data.TransferMode = MODE_IO8; + + /* setup sync data */ + for ( i = 0; i < N_TARGET; i++ ) { + for ( j = 0; j < N_LUN; j++ ) { + nsp_data.Sync[i][j] = tmp_sync; + } + } + + /* block all interrupts */ + nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK); + + /* setup SCSI interface */ + nsp_write(base, IFSELECT, IF_IFSEL); + + nsp_index_write(base, SCSIIRQMODE, 0); + + nsp_index_write(base, TRANSFERMODE, MODE_IO8); + nsp_index_write(base, CLOCKDIV, nsp_data.ScsiClockDiv); + + nsp_index_write(base, PARITYCTRL, 0); + nsp_index_write(base, POINTERCLR, POINTER_CLEAR | + ACK_COUNTER_CLEAR | + REQ_COUNTER_CLEAR | + HOST_COUNTER_CLEAR); + + /* setup fifo asic */ + nsp_write(base, IFSELECT, IF_REGSEL); + nsp_index_write(base, TERMPWRCTRL, 0); + if ((nsp_index_read(base, OTHERCONTROL) & TPWR_SENSE) == 0) { + printk(KERN_INFO "nsp_cs: terminator power on\n"); + nsp_index_write(base, TERMPWRCTRL, POWER_ON); + } + + nsp_index_write(base, TIMERCOUNT, 0); + nsp_index_write(base, TIMERCOUNT, 0); /* requires 2 times!! */ + + nsp_index_write(base, SYNCREG, 0); + nsp_index_write(base, ACKWIDTH, 0); + + /* enable interrupts and ack them */ + nsp_index_write(base, SCSIIRQMODE, SCSI_PHASE_CHANGE_EI | + RESELECT_EI | + SCSI_RESET_IRQ_EI ); + nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR); + + nsp_setup_fifo(base, FALSE); + + return TRUE; +} + +/* + * Start selection phase + */ +static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt) +{ + unsigned int host_id = SCpnt->host->this_id; + unsigned int base = SCpnt->host->io_port; + unsigned char target = SCpnt->target; + int wait_count; + unsigned char phase, arbit; + + //DEBUG(0, __FUNCTION__ "()in\n"); + + + phase = nsp_index_read(base, SCSIBUSMON); + if(phase != BUSMON_BUS_FREE) { + //DEBUG(0, " bus busy\n"); + return FALSE; + } + + /* start arbitration */ + //DEBUG(0, " start arbit\n"); + SCpnt->SCp.phase = PH_ARBSTART; + nsp_index_write(base, SETARBIT, ARBIT_GO); + + wait_count = jiffies + 10 * HZ; + do { + /* XXX: what a stupid chip! */ + arbit = nsp_index_read(base, ARBITSTATUS); + //DEBUG(0, " arbit=%d, wait_count=%d\n", arbit, wait_count); + udelay(1); /* hold 1.2us */ + } while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 && + time_before(jiffies, wait_count)); + + if((arbit & ARBIT_WIN) == 0) { + //DEBUG(0, " arbit fail\n"); + nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR); + return FALSE; + } + + /* assert select line */ + //DEBUG(0, " assert SEL line\n"); + SCpnt->SCp.phase = PH_SELSTART; + udelay(3); + nsp_index_write(base, SCSIDATALATCH, (1 << host_id) | (1 << target)); + nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_ATN); + udelay(3); + nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN); + nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR); + udelay(3); + nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN); + + /* check selection timeout */ + nsp_start_timer(SCpnt, 1000/51); + nsp_data.SelectionTimeOut = 1; + + return TRUE; +} + +struct nsp_sync_table { + unsigned int min_period; + unsigned int max_period; + unsigned int chip_period; + unsigned int ack_width; +}; + +static struct nsp_sync_table nsp_sync_table_40M[] = { + {0x0c,0x0c,0x1,0}, /* 20MB 50ns*/ + {0x19,0x19,0x3,1}, /* 10MB 100ns*/ + {0x1a,0x25,0x5,2}, /* 7.5MB 150ns*/ + {0x26,0x32,0x7,3}, /* 5MB 200ns*/ + {0x0, 0, 0, 0} +}; + +static struct nsp_sync_table nsp_sync_table_20M[] = { + {0x19,0x19,0x1,0}, /* 10MB 100ns*/ + {0x1a,0x25,0x2,0}, /* 7.5MB 150ns*/ + {0x26,0x32,0x3,1}, /* 5MB 200ns*/ + {0x0, 0, 0, 0} +}; + +/* + * setup synchronous data transfer mode + */ +static int nsp_msg(Scsi_Cmnd *SCpnt) +{ + unsigned char target = SCpnt->target; + unsigned char lun = SCpnt->lun; + sync_data *sync = &(nsp_data.Sync[target][lun]); + struct nsp_sync_table *sync_table; + unsigned int period, offset; + int i; + + + DEBUG(0, __FUNCTION__ "()\n"); + +/**!**/ + + period = sync->SyncPeriod; + offset = sync->SyncOffset; + + DEBUG(0, " period=0x%x, offset=0x%x\n", period, offset); + + if (nsp_data.ScsiClockDiv == CLOCK_20M) { + sync_table = &nsp_sync_table_20M[0]; + } else { + sync_table = &nsp_sync_table_40M[0]; + } + + for ( i = 0; sync_table->max_period != 0; i++, sync_table++) { + if ( period >= sync_table->min_period && + period <= sync_table->max_period ) { + break; + } + } + + if (period != 0 && sync_table->max_period == 0) { + /* + * No proper period/offset found + */ + DEBUG(0, " no proper period/offset\n"); + + sync->SyncPeriod = 0; + sync->SyncOffset = 0; + sync->SyncRegister = 0; + sync->AckWidth = 0; + + return FALSE; + } + + sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) | + (offset & SYNCREG_OFFSET_MASK); + sync->AckWidth = sync_table->ack_width; + + DEBUG(0, " sync_reg=0x%x, ack_width=0x%x\n", sync->SyncRegister, sync->AckWidth); + + return TRUE; +} + + +/* + * start ninja hardware timer + */ +static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time) +{ + unsigned int base = SCpnt->host->io_port; + + //DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p, time=%d\n", SCpnt, time); + nsp_data.TimerCount = time; + nsp_index_write(base, TIMERCOUNT, time); +} + +/* + * wait for bus phase change + */ +static int nsp_negate_signal(Scsi_Cmnd *SCpnt, unsigned char mask, char *str) +{ + unsigned int base = SCpnt->host->io_port; + unsigned char reg; + int count, i = TRUE; + + //DEBUG(0, __FUNCTION__ "()\n"); + + count = jiffies + HZ; + + do { + reg = nsp_index_read(base, SCSIBUSMON); + if (reg == 0xff) { + break; + } + } while ((i = time_before(jiffies, count)) && (reg & mask) != 0); + + if (!i) { + printk(KERN_DEBUG __FUNCTION__ " %s signal off timeut\n", str); + } + + return 0; +} + +/* + * expect Ninja Irq + */ +static int nsp_expect_signal(Scsi_Cmnd *SCpnt, + unsigned char current_phase, + unsigned char mask) +{ + unsigned int base = SCpnt->host->io_port; + int wait_count; + unsigned char phase, i_src; + + //DEBUG(0, __FUNCTION__ "() current_phase=0x%x, mask=0x%x\n", current_phase, mask); + + wait_count = jiffies + HZ; + do { + phase = nsp_index_read(base, SCSIBUSMON); + if (phase == 0xff) { + //DEBUG(0, " ret -1\n"); + return -1; + } + i_src = nsp_read(base, IRQSTATUS); + if (i_src & IRQSTATUS_SCSI) { + //DEBUG(0, " ret 0 found scsi signal\n"); + return 0; + } + if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) { + //DEBUG(0, " ret 1 phase=0x%x\n", phase); + return 1; + } + } while(time_before(jiffies, wait_count)); + + //DEBUG(0, __FUNCTION__ " : " __FUNCTION__ " timeout\n"); + return -1; +} + +/* + * transfer SCSI message + */ +static int nsp_xfer(Scsi_Cmnd *SCpnt, int phase) +{ + unsigned int base = SCpnt->host->io_port; + char *buf = nsp_data.MsgBuffer; + int len = MIN(MSGBUF_SIZE, nsp_data.MsgLen); + int ptr; + int ret; + + //DEBUG(0, __FUNCTION__ "()\n"); +/**!**/ + for (ptr = 0; len > 0; len --, ptr ++) { + + ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ); + if (ret <= 0) { + DEBUG(0, " xfer quit\n"); + return 0; + } + + /* if last byte, negate ATN */ + if (len == 1) { + nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB); + } + + /* read & write message */ + if (phase & BUSMON_IO) { + //DEBUG(0, " read msg\n"); + buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK); + } else { + //DEBUG(0, " write msg\n"); + nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]); + } + nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>"); + + } + return len; +} + +/* + * get extra SCSI data from fifo + */ +static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt) +{ + unsigned int base = SCpnt->host->io_port; + unsigned int count; + + //DEBUG(0, __FUNCTION__ "()\n"); + + if (SCpnt->SCp.have_data_in != IO_IN) { + return 0; + } + + count = nsp_fifo_count(SCpnt); + if (nsp_data.FifoCount == count) { + //DEBUG(0, " not use bypass quirk\n"); + return 0; + } + + /* + * XXX: NSP_QUIRK + * data phase skip only occures in case of SCSI_LOW_READ + */ + SCpnt->SCp.phase = PH_DATA; + nsp_pio_read(SCpnt); + nsp_setup_fifo(base, FALSE); + + DEBUG(0, " use bypass quirk\n"); + return 0; +} + +/* + * accept reselection + */ +static int nsp_reselected(Scsi_Cmnd *SCpnt) +{ + unsigned int base = SCpnt->host->io_port; + unsigned char reg; + + //DEBUG(0, __FUNCTION__ "()\n"); + + nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>"); + + nsp_nexus(SCpnt); + reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN); + nsp_index_write(base, SCSIBUSCTRL, reg); + nsp_index_write(base, SCSIBUSCTRL, reg | AUTODIRECTION | ACKENB); + + return TRUE; +} + +/* + * count how many data transferd + */ +static int nsp_fifo_count(Scsi_Cmnd *SCpnt) +{ + unsigned int base = SCpnt->host->io_port; + unsigned int count; + unsigned int l, m, h; + + nsp_index_write(base, POINTERCLR, POINTER_CLEAR); + + l = (unsigned int)nsp_read(base, DATAREG); + m = (unsigned int)nsp_read(base, DATAREG); + h = (unsigned int)nsp_read(base, DATAREG); + + count = (h << 16) | (m << 8) | (l << 0); + + //DEBUG(0, __FUNCTION__ "() =0x%x\n", count); + + return count; +} + +/* fifo size */ +#define RFIFO_CRIT 64 +#define WFIFO_CRIT 64 + +/* + * read data in DATA IN phase + */ +static void nsp_pio_read(Scsi_Cmnd *SCpnt) +{ + unsigned int base = SCpnt->host->io_port; + int time_out, i; + int ocount, res; + unsigned char stat, fifo_stat; + + ocount = nsp_data.FifoCount; + + DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d\n", SCpnt, RESID, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual); + + time_out = jiffies + 10 * HZ; + + while ((i = time_before(jiffies,time_out)) && + (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0 ) ) { + + stat = nsp_index_read(base, SCSIBUSMON); + stat &= BUSMON_PHASE_MASK; + + res = nsp_fifo_count(SCpnt) - ocount; + + //DEBUG(0, " ptr=0x%p this=0x%x ocount=0x%x res=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount, res); + if (res == 0) { /* if some data avilable ? */ + if (stat == BUSPHASE_DATA_IN) { /* phase changed? */ + //DEBUG(0, " wait for data this=%d\n", SCpnt->SCp.this_residual); + continue; + } else { + DEBUG(0, " phase changed stat=0x%x\n", stat); + break; + } + } + + fifo_stat = nsp_read(base, FIFOSTATUS); + if ((fifo_stat & FIFOSTATUS_FULL_EMPTY) == 0 && + stat == BUSPHASE_DATA_IN) { + continue; + } + + res = MIN(res, SCpnt->SCp.this_residual); + + switch (nsp_data.TransferMode) { + case MODE_IO32: + res &= ~(BIT(1)|BIT(0)); /* align 4 */ + nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2); + break; + case MODE_IO8: + nsp_fifo8_read (base, SCpnt->SCp.ptr, res ); + break; + default: + DEBUG(0, "unknown read mode\n"); + break; + } + + RESID -= res; + SCpnt->SCp.ptr += res; + SCpnt->SCp.this_residual -= res; + ocount += res; + //DEBUG(0, " ptr=0x%p this_residual=0x%x ocount=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount); + + /* go to next scatter list if availavle */ + if (SCpnt->SCp.this_residual == 0 && + SCpnt->SCp.buffers_residual != 0 ) { + //DEBUG(0, " scatterlist next timeout=%d\n", time_out); + SCpnt->SCp.buffers_residual--; + SCpnt->SCp.buffer++; + SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + } + + time_out = jiffies + 10 * HZ; + } + + nsp_data.FifoCount = ocount; + + if (!i) { + printk(KERN_DEBUG __FUNCTION__ "() pio read timeout resid=%d this_residual=%d buffers_residual=%d\n", RESID, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual); + } + DEBUG(0, " read ocount=0x%x\n", ocount); +} + +/* + * write data in DATA OUT phase + */ +static void nsp_pio_write(Scsi_Cmnd *SCpnt) +{ + unsigned int base = SCpnt->host->io_port; + int time_out, i; + unsigned int ocount, res; + unsigned char stat; + + ocount = nsp_data.FifoCount; + + DEBUG(0, __FUNCTION__ "() in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x\n", nsp_data.FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, SCpnt->resid); + + time_out = jiffies + 10 * HZ; + + while ((i = time_before(jiffies, time_out)) && + (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0)) { + stat = nsp_index_read(base, SCSIBUSMON); + stat &= BUSMON_PHASE_MASK; + if (stat != BUSPHASE_DATA_OUT) { + DEBUG(0, " phase changed stat=0x%x\n", stat); + break; + } + + res = ocount - nsp_fifo_count(SCpnt); + if (res > 0) { /* write all data? */ + DEBUG(0, " wait for all data out. ocount=0x%x res=%d\n", ocount, res); + continue; + } + + res = MIN(SCpnt->SCp.this_residual, WFIFO_CRIT); + + //DEBUG(0, " ptr=0x%p this=0x%x res=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res); + switch (nsp_data.TransferMode) { + case MODE_IO32: + res &= ~(BIT(1)|BIT(0)); /* align 4 */ + nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2); + break; + case MODE_IO8: + nsp_fifo8_write (base, SCpnt->SCp.ptr, res ); + break; + default: + DEBUG(0, "unknown write mode\n"); + break; + } + + RESID -= res; + SCpnt->SCp.ptr += res; + SCpnt->SCp.this_residual -= res; + ocount += res; + + /* go to next scatter list if availavle */ + if (SCpnt->SCp.this_residual == 0 && + SCpnt->SCp.buffers_residual != 0 ) { + //DEBUG(0, " scatterlist next\n"); + SCpnt->SCp.buffers_residual--; + SCpnt->SCp.buffer++; + SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + } + + time_out = jiffies + 10 * HZ; + } + + nsp_data.FifoCount = ocount; + + if (!i) { + printk(KERN_DEBUG __FUNCTION__ "() pio write timeout resid=%d\n", RESID); + } + //DEBUG(0, " write ocount=%d\n", ocount); +} + +#undef RFIFO_CRIT +#undef WFIFO_CRIT + +/* + * setup synchronous/asynchronous data transfer mode + */ +static int nsp_nexus(Scsi_Cmnd *SCpnt) +{ + unsigned int base = SCpnt->host->io_port; + unsigned char target = SCpnt->target; + unsigned char lun = SCpnt->lun; + sync_data *sync = &(nsp_data.Sync[target][lun]); + + //DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p\n", SCpnt); + + /* setup synch transfer registers */ + nsp_index_write(base, SYNCREG, sync->SyncRegister); + nsp_index_write(base, ACKWIDTH, sync->AckWidth); + + if (RESID % 4 != 0 || + RESID <= 256 ) { + nsp_data.TransferMode = MODE_IO8; + } else { + nsp_data.TransferMode = MODE_IO32; + } + + /* setup pdma fifo */ + nsp_setup_fifo(base, TRUE); + + /* clear ack counter */ + nsp_data.FifoCount = 0; + nsp_index_write(base, POINTERCLR, POINTER_CLEAR | + ACK_COUNTER_CLEAR | + REQ_COUNTER_CLEAR | + HOST_COUNTER_CLEAR); + + return 0; +} + +/* + * interrupt handler + */ +static void nspintr(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int base; + unsigned char i_src, irq_phase, phase; + Scsi_Cmnd *tmpSC; + int ret, len; + unsigned char data_reg, control_reg; + + + //DEBUG(0, __FUNCTION__ "(%d) CurrentSC=0x%p\n", irq, nsp_data.CurrentSC); + + base = nsp_data.BaseAddress; + //DEBUG(0, " base=0x%x\n", base); + + /* + * interrupt check + */ + nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE); + i_src = nsp_read(base, IRQSTATUS); + if (i_src == 0xff || (i_src & IRQSTATUS_MASK) == 0) { + nsp_write(base, IRQCONTROL, 0); + //DEBUG(0, " no irq\n"); + return; + } + + //DEBUG(0, " i_src=0x%x\n", i_src); + + /* XXX: IMPORTANT + * Do not read an irq_phase register if no scsi phase interrupt. + * Unless, you should lose a scsi phase interrupt. + */ + phase = nsp_index_read(base, SCSIBUSMON); + if((i_src & IRQSTATUS_SCSI) != 0) { + irq_phase = nsp_index_read(base, IRQPHASESENCE); + } else { + irq_phase = 0; + } + + //DEBUG(0, " irq_phase=0x%x\n", irq_phase); + + /* + * timer interrupt handler (scsi vs timer interrupts) + */ + //DEBUG(0, " timercount=%d\n", nsp_data.TimerCount); + if (nsp_data.TimerCount != 0) { + //DEBUG(0, " stop timer\n"); + nsp_index_write(base, TIMERCOUNT, 0); + nsp_index_write(base, TIMERCOUNT, 0); + nsp_data.TimerCount = 0; + } + + if ((i_src & IRQSTATUS_MASK) == IRQSTATUS_TIMER && + nsp_data.SelectionTimeOut == 0) { + //DEBUG(0, " timer start\n"); + nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR); + return; + } + + nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR); + + if (nsp_data.CurrentSC == NULL) { + printk(KERN_DEBUG __FUNCTION__ " CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x this can't be happen\n", i_src, phase, irq_phase); + return; + } else { + tmpSC = nsp_data.CurrentSC; + } + + /* + * parse hardware SCSI irq reasons register + */ + if ((i_src & IRQSTATUS_SCSI) != 0) { + if ((irq_phase & SCSI_RESET_IRQ) != 0) { + printk(KERN_DEBUG " " __FUNCTION__ "() bus reset (power off?)\n"); + + nsp_data.CurrentSC = NULL; + tmpSC->result = DID_RESET << 16; + tmpSC->scsi_done(tmpSC); + return; + } + + if ((irq_phase & RESELECT_IRQ) != 0) { + DEBUG(0, " reselect\n"); + nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR); + if (nsp_reselected(tmpSC) != FALSE) { + return; + } + } + + if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) { + return; + } + } + + //show_phase(tmpSC); + + switch(tmpSC->SCp.phase) { + case PH_SELSTART: + if ((phase & BUSMON_BSY) == 0) { + //DEBUG(0, " selection count=%d\n", nsp_data.SelectionTimeOut); + if (nsp_data.SelectionTimeOut >= NSP_SELTIMEOUT) { + DEBUG(0, " selection time out\n"); + nsp_data.SelectionTimeOut = 0; + nsp_index_write(base, SCSIBUSCTRL, 0); + + nsp_data.CurrentSC = NULL; + tmpSC->result = DID_NO_CONNECT << 16; + tmpSC->scsi_done(tmpSC); + + return; + } + nsp_data.SelectionTimeOut += 1; + nsp_start_timer(tmpSC, 1000/51); + return; + } + + /* attention assert */ + //DEBUG(0, " attention assert\n"); + nsp_data.SelectionTimeOut = 0; + tmpSC->SCp.phase = PH_SELECTED; + nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN); + udelay(1); + nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB); + return; + + break; + + case PH_RESELECT: + //DEBUG(0, " phase reselect\n"); + if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) { + + nsp_data.CurrentSC = NULL; + tmpSC->result = DID_ABORT << 16; + tmpSC->scsi_done(tmpSC); + return; + } + /* fall thru */ + default: + if (( i_src & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) { + return; + } + break; + } + + /* + * SCSI sequencer + */ + //DEBUG(0, " start scsi seq\n"); + + /* normal disconnect */ + if ((irq_phase & LATCHED_BUS_FREE) != 0) { + //DEBUG(0, " normal disconnect i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", i_src, phase, irq_phase); + if ((tmpSC->SCp.Message == 0)) { /* all command complete and return status */ + nsp_data.CurrentSC = NULL; + tmpSC->result = (DID_OK << 16) | + (tmpSC->SCp.Message << 8) | + (tmpSC->SCp.Status << 0); + DEBUG(0, " command complete result=0x%x\n", tmpSC->result); + tmpSC->scsi_done(tmpSC); + return; + } + + return; + } + + + /* check unexpected bus free state */ + if (phase == 0) { + printk(KERN_DEBUG " " __FUNCTION__ " unexpected bus free. i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", i_src, phase, irq_phase); + + nsp_data.CurrentSC = NULL; + tmpSC->result = DID_ERROR << 16; + tmpSC->scsi_done(tmpSC); + return; + } + + switch (phase & BUSMON_PHASE_MASK) { + case BUSPHASE_COMMAND: + DEBUG(0, " BUSPHASE_COMMAND\n"); + if ((phase & BUSMON_REQ) == 0) { + DEBUG(0, " REQ == 0\n"); + return; + } + + tmpSC->SCp.phase = PH_COMMAND; + + nsp_nexus(tmpSC); + + /* write scsi command */ + nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER); + for (len = 0; len < COMMAND_SIZE(tmpSC->cmnd[0]); len++) { + nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[len]); + } + nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO); + break; + + case BUSPHASE_DATA_OUT: + DEBUG(0, " BUSPHASE_DATA_OUT\n"); + + tmpSC->SCp.phase = PH_DATA; + tmpSC->SCp.have_data_in = IO_OUT; + + nsp_pio_write(tmpSC); + + break; + + case BUSPHASE_DATA_IN: + DEBUG(0, " BUSPHASE_DATA_IN\n"); + + tmpSC->SCp.phase = PH_DATA; + tmpSC->SCp.have_data_in = IO_IN; + + nsp_pio_read(tmpSC); + + break; + + case BUSPHASE_STATUS: + nsp_dataphase_bypass(tmpSC); + DEBUG(0, " BUSPHASE_STATUS\n"); + + tmpSC->SCp.phase = PH_STATUS; + + tmpSC->SCp.Status = nsp_index_read(base, SCSIDATAWITHACK); + //DEBUG(0, " message=0x%x status=0x%x\n", tmpSC->SCp.Message, tmpSC->SCp.Status); + + break; + + case BUSPHASE_MESSAGE_OUT: + DEBUG(0, " BUSPHASE_MESSAGE_OUT\n"); + if ((phase & BUSMON_REQ) == 0) { + goto timer_out; + } + + tmpSC->SCp.phase = PH_MSG_OUT; + + /* + * XXX: NSP QUIRK + * NSP invoke interrupts only in the case of scsi phase changes, + * therefore we should poll the scsi phase here to catch + * the next "msg out" if exists (no scsi phase changes). + */ + ret = 16; + len = 0; + + nsp_msg(tmpSC); + + nsp_data.MsgBuffer[len] = IDENTIFY(TRUE, tmpSC->lun); len++; + nsp_data.MsgLen = len; + + do { + DEBUG(0, " msgout loop\n"); + + if (nsp_xfer(tmpSC, BUSPHASE_MESSAGE_OUT)) { + printk(KERN_DEBUG " " __FUNCTION__ " msgout: xfer short\n"); + } + + /* catch a next signal */ + ret = nsp_expect_signal(tmpSC, BUSPHASE_MESSAGE_OUT, BUSMON_REQ); + } while (ret > 0 && len-- > 0); + + break; + + case BUSPHASE_MESSAGE_IN: + nsp_dataphase_bypass(tmpSC); + DEBUG(0, " BUSPHASE_MESSAGE_IN\n"); + if ((phase & BUSMON_REQ) == 0) { + goto timer_out; + } + + tmpSC->SCp.phase = PH_MSG_IN; + + /* + * XXX: NSP QUIRK + * NSP invoke interrupts only in the case of scsi phase changes, + * therefore we should poll the scsi phase here to catch + * the next "msg in" if exists (no scsi phase changes). + */ + ret = 16; + len = 0; + + do { + //DEBUG(0, " msgin loop\n"); + /* read data */ + data_reg = nsp_index_read(base, SCSIDATAIN); + + /* assert ACK */ + control_reg = nsp_index_read(base, SCSIBUSCTRL); + control_reg |= SCSI_ACK; + nsp_index_write(base, SCSIBUSCTRL, control_reg); + nsp_negate_signal(tmpSC, BUSMON_REQ, "msgin<REQ>"); + + nsp_data.MsgBuffer[len] = data_reg; len++; + DEBUG(0, " msg=0x%x\n", data_reg); + + /* deassert ACK */ + control_reg = nsp_index_read(base, SCSIBUSCTRL); + control_reg &= ~SCSI_ACK; + nsp_index_write(base, SCSIBUSCTRL, control_reg); + + /* catch a next signal */ + ret = nsp_expect_signal(tmpSC, BUSPHASE_MESSAGE_IN, BUSMON_REQ); + } while (ret > 0 && MSGBUF_SIZE > len); + + nsp_data.MsgLen = len; + tmpSC->SCp.Message = nsp_data.MsgBuffer[len-1]; + + //DEBUG(0, " message=0x%x len=%d\n", tmpSC->SCp.Message, nsp_data.MsgLen); + break; + + case BUSPHASE_SELECT: + default: + DEBUG(0, " BUSPHASE other\n"); + + break; + } + + //DEBUG(0, __FUNCTION__ "() out\n"); + return; + +timer_out: + nsp_start_timer(tmpSC, 1000/102); + return; +} + +#ifdef DBG_SHOWCOMMAND +#include "nsp_debug.c" +#endif /* DBG_SHOWCOMMAND */ + +/*====================================================================*/ +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================== + nsp_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + + The dev_link structure is initialized, but we don't actually + configure the card at this point -- we wait until we receive a + card insertion event. +======================================================================*/ +static dev_link_t *nsp_attach(void) +{ + scsi_info_t *info; + client_reg_t client_reg; + dev_link_t *link; + int ret, i; + + DEBUG(0, __FUNCTION__ "()\n"); + + /* Create new SCSI device */ + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) return NULL; + memset(info, 0, sizeof(*info)); + link = &info->link; + link->priv = info; + + /* Initialize the dev_link_t structure */ + link->release.function = &nsp_release; + link->release.data = (u_long)link; + + /* The io structure describes IO port mapping */ + link->io.NumPorts1 = 0x10; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.IOAddrLines = 10; /* not used */ + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if (irq_list[0] == -1) { + link->irq.IRQInfo2 = irq_mask; + } else { + for (i = 0; i < 4; i++) { + link->irq.IRQInfo2 |= 1 << irq_list[i]; + } + } + link->irq.Handler = &nspintr; + + /* General socket configuration */ + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.Present = PRESENT_OPTION; + + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME ; + client_reg.event_handler = &nsp_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + nsp_detach(link); + return NULL; + } + + return link; +} /* nsp_attach */ + + +/*====================================================================== + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. +======================================================================*/ +static void nsp_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + DEBUG(0, __FUNCTION__ "(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) { + if (*linkp == link) { + break; + } + } + if (*linkp == NULL) { + return; + } + + del_timer(&link->release); + if (link->state & DEV_CONFIG) { + nsp_release((u_long)link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } + } + + /* Break the link with Card Services */ + if (link->handle) { + CardServices(DeregisterClient, link->handle); + } + + /* Unlink device structure, free bits */ + *linkp = link->next; + kfree(link->priv); + +} /* nsp_detach */ + + +/*====================================================================== + nsp_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + ethernet device available to the system. +======================================================================*/ +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry +/*====================================================================*/ + +static void nsp_config(dev_link_t *link) +{ + client_handle_t handle = link->handle; + scsi_info_t *info = link->priv; + tuple_t tuple; + cisparse_t parse; + int i, last_ret, last_fn; + u_char tuple_data[64]; + config_info_t conf; + Scsi_Device *dev; + dev_node_t **tail, *node; + struct Scsi_Host *host; + + DEBUG(0, __FUNCTION__ "() in\n"); + + tuple.DesiredTuple = CISTPL_CONFIG; + tuple.Attributes = 0; + tuple.TupleData = tuple_data; + tuple.TupleDataMax = sizeof(tuple_data); + tuple.TupleOffset = 0; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + driver_template.module = &__this_module; + link->state |= DEV_CONFIG; + + /* Look up the current Vcc */ + CS_CHECK(GetConfigurationInfo, handle, &conf); + link->conf.Vcc = conf.Vcc; + + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigIndex = parse.cftable_entry.index; + link->io.BasePort1 = parse.cftable_entry.io.win[0].base; + i = CardServices(RequestIO, handle, &link->io); + if (i == CS_SUCCESS) { + break; + } + next_entry: + DEBUG(0, __FUNCTION__ " next\n"); + CS_CHECK(GetNextTuple, handle, &tuple); + } + + CS_CHECK(RequestIRQ, handle, &link->irq); + CS_CHECK(RequestConfiguration, handle, &link->conf); + + /* A bad hack... */ + release_region(link->io.BasePort1, link->io.NumPorts1); + + /* Set port and IRQ */ + nsp_data.BaseAddress = link->io.BasePort1; + nsp_data.NumAddress = link->io.NumPorts1; + nsp_data.IrqNumber = link->irq.AssignedIRQ; + + DEBUG(0, __FUNCTION__ " I/O[0x%x+0x%x] IRQ %d\n", + nsp_data.BaseAddress, nsp_data.NumAddress, nsp_data.IrqNumber); + + if(nsphw_init() == FALSE) { + goto cs_failed; + } + + scsi_register_module(MODULE_SCSI_HA, &driver_template); + + DEBUG(0, "GET_SCSI_INFO\n"); + tail = &link->dev; + info->ndev = 0; + for (host = scsi_hostlist; host != NULL; host = host->next) { + if (host->hostt == &driver_template) { + for (dev = host->host_queue; dev != NULL; dev = dev->next) { + u_long arg[2], id; + kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg); + id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) + + ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000); + node = &info->node[info->ndev]; + node->minor = 0; + switch (dev->type) { + case TYPE_TAPE: + node->major = SCSI_TAPE_MAJOR; + sprintf(node->dev_name, "st#%04lx", id); + break; + case TYPE_DISK: + case TYPE_MOD: + node->major = SCSI_DISK0_MAJOR; + sprintf(node->dev_name, "sd#%04lx", id); + break; + case TYPE_ROM: + case TYPE_WORM: + node->major = SCSI_CDROM_MAJOR; + sprintf(node->dev_name, "sr#%04lx", id); + break; + default: + node->major = SCSI_GENERIC_MAJOR; + sprintf(node->dev_name, "sg#%04lx", id); + break; + } + *tail = node; tail = &node->next; + info->ndev++; + info->host = dev->host; + } + } + } + *tail = NULL; + if (info->ndev == 0) { + printk(KERN_INFO "nsp_cs: no SCSI devices found\n"); + } + + /* Finally, report what we've done */ + printk(KERN_INFO "nsp_cs: index 0x%02x: Vcc %d.%d", + link->conf.ConfigIndex, + link->conf.Vcc/10, link->conf.Vcc%10); + if (link->conf.Vpp1) { + printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); + } + if (link->conf.Attributes & CONF_ENABLE_IRQ) { + printk(", irq %d", link->irq.AssignedIRQ); + } + if (link->io.NumPorts1) { + printk(", io 0x%04x-0x%04x", link->io.BasePort1, + link->io.BasePort1+link->io.NumPorts1-1); + } + printk("\n"); + + link->state &= ~DEV_CONFIG_PENDING; + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); + nsp_release((u_long)link); + return; + +} /* nsp_config */ +#undef CS_CHECK +#undef CFG_CHECK + +/*====================================================================== + After a card is removed, nsp_release() will unregister the net + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. +======================================================================*/ +static void nsp_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + + DEBUG(0, __FUNCTION__ "(0x%p)\n", link); + + /* + * If the device is currently in use, we won't release until it + * is actually closed. + */ + if (link->open) { + DEBUG(1, "nsp_cs: release postponed, '%s' still open\n", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + /* Unlink the device chain */ + scsi_unregister_module(MODULE_SCSI_HA, &driver_template); + link->dev = NULL; + + if (link->win) { + CardServices(ReleaseWindow, link->win); + } + CardServices(ReleaseConfiguration, link->handle); + if (link->io.NumPorts1) { + CardServices(ReleaseIO, link->handle, &link->io); + } + if (link->irq.AssignedIRQ) { + CardServices(ReleaseIRQ, link->handle, &link->irq); + } + link->state &= ~DEV_CONFIG; + + if (link->state & DEV_STALE_LINK) { + nsp_detach(link); + } +} /* nsp_release */ + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the net drivers from trying + to talk to the card any more. + + When a CARD_REMOVAL event is received, we immediately set a flag + to block future accesses to this device. All the functions that + actually access the device should check this flag to make sure + the card is still present. + +======================================================================*/ +static int nsp_event(event_t event, + int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + scsi_info_t *info = link->priv; + + DEBUG(1, __FUNCTION__ "(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + DEBUG(0, " event: remove\n"); + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + ((scsi_info_t *)link->priv)->stop = 1; + mod_timer(&link->release, jiffies + HZ/20); + } + break; + + case CS_EVENT_CARD_INSERTION: + DEBUG(0, " event: insert\n"); + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + info->bus = args->bus; + nsp_config(link); + break; + + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + /* Mark the device as stopped, to block IO until later */ + info->stop = 1; + if (link->state & DEV_CONFIG) { + CardServices(ReleaseConfiguration, link->handle); + } + break; + + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + DEBUG(0, " event: reset\n"); + if (link->state & DEV_CONFIG) { + Scsi_Cmnd tmp; + + CardServices(RequestConfiguration, link->handle, &link->conf); + tmp.host = info->host; + nsp_reset(&tmp, 0); + } + info->stop = 0; + /* restart IO */ + nsphw_init(); + break; + + default: + DEBUG(0, " event: unknown\n"); + break; + } + DEBUG(0, __FUNCTION__ " end\n"); + return 0; +} /* nsp_event */ + +/*----------------------------------------------------------------*/ +/* look for ninja3 card and init if found */ +/*----------------------------------------------------------------*/ +static int nsp_detect(Scsi_Host_Template *sht) +{ + struct Scsi_Host *host; /* registered host structure */ + + DEBUG(0, __FUNCTION__ " this_id=%d\n", sht->this_id); + +#if (KERNEL_VERSION(2,3,99) > LINUX_VERSION_CODE) + sht->proc_dir = &proc_scsi_nsp; /* kernel 2.2 */ +#else + sht->proc_name = "nsp_cs"; /* kernel 2.4 */ +#endif + + sht->this_id = SCSI_INITIATOR_ID; + + request_region(nsp_data.BaseAddress, nsp_data.NumAddress,"nsp_cs"); + host = scsi_register(sht, 0); + host->io_port = nsp_data.BaseAddress; + host->unique_id = nsp_data.BaseAddress; + host->n_io_port = nsp_data.NumAddress; + host->irq = nsp_data.IrqNumber; + host->dma_channel = -1; + + sprintf(nspinfo, +/* Buffer size is 100 bytes */ +/* 0 1 2 3 4 5 6 7 8 9 0*/ +/* 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890*/ + "NinjaSCSI-3/32Bi Driver version 2.0, I/O 0x%04lx-0x%04lx IRQ %2d", + host->io_port, host->io_port + host->n_io_port, + host->irq); + sht->name = nspinfo; + + DEBUG(0, __FUNCTION__ " end\n"); + + return 1; /* detect done. */ +} + + +/*----------------------------------------------------------------*/ +/* return info string */ +/*----------------------------------------------------------------*/ +static const char *nsp_info(struct Scsi_Host *host) +{ + return nspinfo; +} + +static int nsp_reset(Scsi_Cmnd *SCpnt, unsigned int why) +{ + DEBUG(0, __FUNCTION__ "() SCpnt=0x%p why=%d\n", SCpnt, why); + + return nsp_eh_bus_reset(SCpnt); +} + +static int nsp_abort(Scsi_Cmnd *SCpnt) +{ + DEBUG(0, __FUNCTION__ "() SCpnt=0x%p\n", SCpnt); + return FAILED; +} + +/*static int nsp_eh_strategy(struct Scsi_Host *Shost) +{ +} +static int nsp_eh_abort(Scsi_Cmnd * cmd) +{ + DEBUG(0, __FUNCTION__"() SCpnt\n"); +} + +static nsp_eh_device_reset(Scsi_Cmnd *) +{ +} +*/ +static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt) +{ + unsigned int base = SCpnt->host->io_port; + int i; + + DEBUG(0, __FUNCTION__ "() SCpnt=0x%p\n", SCpnt); + + nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK); + + nsp_index_write(base, SCSIBUSCTRL, SCSI_RST); + mdelay(100); /* 100ms */ + nsp_index_write(base, SCSIBUSCTRL, 0); + for(i = 0; i < 5; i++) { + (void) nsp_index_read(base, IRQPHASESENCE); /* dummy read */ + } + + nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR); + + return 0; +} +/* +static nsp_eh_host_reset(Scsi_Cmnd *) +{ +}*/ + +/*======================================================================* + * module entry point + *====================================================================*/ +static int __init nsp_init(void) +{ + servinfo_t serv; + + DEBUG(0, __FUNCTION__ "() in\n"); + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_DEBUG "nsp_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pcmcia_driver(&dev_info, &nsp_attach, &nsp_detach); + + DEBUG(0, __FUNCTION__ "() out\n"); + return 0; +} + + +static void __exit nsp_cleanup(void) +{ + DEBUG(0, "nsp_cs: unloading\n"); + unregister_pcmcia_driver(&dev_info); + while (dev_list != NULL) { + if (dev_list->state & DEV_CONFIG) { + nsp_release((u_long)dev_list); + } + nsp_detach(dev_list); + } +} + +module_init(nsp_init); +module_exit(nsp_cleanup); + +/* + * + * + */ + +/* end */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/pcmcia/nsp_cs.h linux.ac/drivers/scsi/pcmcia/nsp_cs.h --- linux.vanilla/drivers/scsi/pcmcia/nsp_cs.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/scsi/pcmcia/nsp_cs.h Tue Apr 3 17:55:04 2001 @@ -0,0 +1,302 @@ +/*=======================================================/ + Header file for nsp_cs.c + By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp> + + Ver.1.0 : Cut unused lines. + Ver 0.1 : Initial version. + + This software may be used and distributed according to the terms of + the GNU General Public License. + +=========================================================*/ + +/* $Id: nsp_cs.h,v 1.18 2001/02/09 04:42:19 elca Exp $ */ + +#ifndef __nsp_cs__ +#define __nsp_cs__ + +/* for debugging */ +/* +#define DBG +#define DBG_PRINT +#define DBG_SHOWCOMMAND +#define PCMCIA_DEBUG 9 +*/ + +/* +#define static +#define inline +*/ + +/************************************ + * Some useful macros... + */ +#define Number(arr) ((int) (sizeof(arr) / sizeof(arr[0]))) +#define BIT(x) (1<<(x)) +#define MIN(a,b) ((a) > (b) ? (b) : (a)) + +/* SCSI initiator must be 7 */ +#define SCSI_INITIATOR_ID 7 + +/* base register */ +#define IRQCONTROL 0x00 +# define IRQCONTROL_RESELECT_CLEAR BIT(0) +# define IRQCONTROL_PHASE_CHANGE_CLEAR BIT(1) +# define IRQCONTROL_TIMER_CLEAR BIT(2) +# define IRQCONTROL_FIFO_CLEAR BIT(3) +# define IRQCONTROL_ALLMASK 0xff +# define IRQCONTROL_ALLCLEAR 0x0f +# define IRQCONTROL_IRQDISABLE 0xf0 + +#define IRQSTATUS 0x00 +# define IRQSTATUS_SCSI BIT(0) +# define IRQSTATUS_TIMER BIT(2) +# define IRQSTATUS_FIFO BIT(3) +# define IRQSTATUS_MASK 0x0f + +#define IFSELECT 0x01 +# define IF_IFSEL BIT(0) +# define IF_REGSEL BIT(2) + +#define FIFOSTATUS 0x01 +# define FIFOSTATUS_CHIP_REVISION 0x0f +# define FIFOSTATUS_CHIP_ID 0x70 +# define FIFOSTATUS_FULL_EMPTY 0x80 + +#define INDEXREG 0x02 +#define DATAREG 0x03 +#define FIFODATA 0x04 +#define FIFODATA1 0x05 +#define FIFODATA2 0x06 +#define FIFODATA3 0x07 + +/* indexed register */ +#define EXTBUSCTRL 0x10 + +#define CLOCKDIV 0x11 +# define CLOCK_40M 0x02 +# define CLOCK_20M 0x01 + +#define TERMPWRCTRL 0x13 +# define POWER_ON BIT(0) + +#define SCSIIRQMODE 0x15 +# define SCSI_PHASE_CHANGE_EI BIT(0) +# define RESELECT_EI BIT(4) +# define FIFO_IRQ_EI BIT(5) +# define SCSI_RESET_IRQ_EI BIT(6) + +#define IRQPHASESENCE 0x16 +# define LATCHED_MSG BIT(0) +# define LATCHED_IO BIT(1) +# define LATCHED_CD BIT(2) +# define LATCHED_BUS_FREE BIT(3) +# define PHASE_CHANGE_IRQ BIT(4) +# define RESELECT_IRQ BIT(5) +# define FIFO_IRQ BIT(6) +# define SCSI_RESET_IRQ BIT(7) + +#define TIMERCOUNT 0x17 + +#define SCSIBUSCTRL 0x18 +# define SCSI_SEL BIT(0) +# define SCSI_RST BIT(1) +# define SCSI_DATAOUT_ENB BIT(2) +# define SCSI_ATN BIT(3) +# define SCSI_ACK BIT(4) +# define SCSI_BSY BIT(5) +# define AUTODIRECTION BIT(6) +# define ACKENB BIT(7) + +#define SCSIBUSMON 0x19 + +#define SETARBIT 0x1A +# define ARBIT_GO BIT(0) +# define ARBIT_FLAG_CLEAR BIT(1) + +#define ARBITSTATUS 0x1A +/*# define ARBIT_GO BIT(0)*/ +# define ARBIT_WIN BIT(1) +# define ARBIT_FAIL BIT(2) +# define RESELECT_FLAG BIT(3) + +#define PARITYCTRL 0x1B /* W */ +#define PARITYSTATUS 0x1B /* R */ + +#define COMMANDCTRL 0x1C /* W */ +# define CLEAR_COMMAND_POINTER BIT(0) +# define AUTO_COMMAND_GO BIT(1) + +#define RESELECTID 0x1C /* R */ +#define COMMANDDATA 0x1D + +#define POINTERCLR 0x1E /* W */ +# define POINTER_CLEAR BIT(0) +# define ACK_COUNTER_CLEAR BIT(1) +# define REQ_COUNTER_CLEAR BIT(2) +# define HOST_COUNTER_CLEAR BIT(3) +# define READ_SOURCE 0x30 + +#define TRANSFERCOUNT 0x1E /* R */ + +#define TRANSFERMODE 0x20 +# define MODE_MEM8 BIT(0) +# define MODE_MEM32 BIT(1) +# define MODE_ADR24 BIT(2) +# define MODE_ADR32 BIT(3) +# define MODE_IO8 BIT(4) +# define MODE_IO32 BIT(5) +# define TRANSFER_GO BIT(6) +# define BRAIND BIT(7) + +#define SYNCREG 0x21 +# define SYNCREG_OFFSET_MASK 0x0f +# define SYNCREG_PERIOD_MASK 0xf0 +# define SYNCREG_PERIOD_SHIFT 4 + +#define SCSIDATALATCH 0x22 +#define SCSIDATAIN 0x22 +#define SCSIDATAWITHACK 0x23 +#define SCAMCONTROL 0x24 +#define SCAMSTATUS 0x24 +#define SCAMDATA 0x25 + +#define OTHERCONTROL 0x26 +# define TPL_ROM_WRITE_EN BIT(0) +# define TPWR_OUT BIT(1) +# define TPWR_SENSE BIT(2) +# define RA8_CONTROL BIT(3) + +#define ACKWIDTH 0x27 +#define CLRTESTPNT 0x28 +#define ACKCNTLD 0x29 +#define REQCNTLD 0x2A +#define HSTCNTLD 0x2B +#define CHECKSUM 0x2C + +/* + * Input status bit definitions. + */ +#define S_ATN 0x80 /**/ +#define S_SELECT 0x40 /**/ +#define S_REQUEST 0x20 /* Request line from SCSI bus*/ +#define S_ACK 0x10 /* Acknowlege line from SCSI bus*/ +#define S_BUSY 0x08 /* Busy line from SCSI bus*/ +#define S_CD 0x04 /* Command/Data line from SCSI bus*/ +#define S_IO 0x02 /* Input/Output line from SCSI bus*/ +#define S_MESSAGE 0x01 /* Message line from SCSI bus*/ + +/* + * Useful Bus Monitor status combinations. + */ +#define BUSMON_SEL S_SELECT +#define BUSMON_BSY S_BUSY +#define BUSMON_REQ S_REQUEST +#define BUSMON_IO S_IO +#define BUSMON_ACK S_ACK +#define BUSMON_BUS_FREE 0 +#define BUSMON_COMMAND ( S_BUSY | S_CD | S_REQUEST ) +#define BUSMON_MESSAGE_IN ( S_BUSY | S_MESSAGE | S_IO | S_CD | S_REQUEST ) +#define BUSMON_MESSAGE_OUT ( S_BUSY | S_MESSAGE | S_CD | S_REQUEST ) +#define BUSMON_DATA_IN ( S_BUSY | S_IO | S_REQUEST ) +#define BUSMON_DATA_OUT ( S_BUSY | S_REQUEST ) +#define BUSMON_STATUS ( S_BUSY | S_IO | S_CD | S_REQUEST ) +#define BUSMON_RESELECT ( S_SELECT | S_IO ) +#define BUSMON_PHASE_MASK ( S_SELECT | S_CD | S_MESSAGE | S_IO ) + +#define BUSPHASE_COMMAND ( BUSMON_COMMAND & BUSMON_PHASE_MASK ) +#define BUSPHASE_MESSAGE_IN ( BUSMON_MESSAGE_IN & BUSMON_PHASE_MASK ) +#define BUSPHASE_MESSAGE_OUT ( BUSMON_MESSAGE_OUT & BUSMON_PHASE_MASK ) +#define BUSPHASE_DATA_IN ( BUSMON_DATA_IN & BUSMON_PHASE_MASK ) +#define BUSPHASE_DATA_OUT ( BUSMON_DATA_OUT & BUSMON_PHASE_MASK ) +#define BUSPHASE_STATUS ( BUSMON_STATUS & BUSMON_PHASE_MASK ) +#define BUSPHASE_SELECT ( S_SELECT | S_IO ) + +/* synchronous transfer negotiation data */ +typedef struct _sync_data { + unsigned int SyncNegotiation; +#define SYNC_NOT_YET 0 +#define SYNC_OK 1 +#define SYNC_NG 2 + + unsigned int SyncPeriod; + unsigned int SyncOffset; + unsigned char SyncRegister; + unsigned char AckWidth; +} sync_data; + +typedef struct _nsp_data { + unsigned int BaseAddress; + unsigned int NumAddress; + unsigned int IrqNumber; + + unsigned char ScsiClockDiv; + + unsigned char TransferMode; + + int TimerCount; + int SelectionTimeOut; + Scsi_Cmnd *CurrentSC; + + int FifoCount; +#if (KERNEL_VERSION(2,4,0) > LINUX_VERSION_CODE) + int Residual; +#define RESID nsp_data.Residual +#else +#define RESID SCpnt->resid +#endif + +#define MSGBUF_SIZE 20 + unsigned char MsgBuffer[MSGBUF_SIZE]; + int MsgLen; + +#define N_TARGET 8 +#define N_LUN 8 + sync_data Sync[N_TARGET][N_LUN]; +} nsp_hw_data; + + +static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt); +static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time); + +static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt); + +static int nsp_fifo_count(Scsi_Cmnd *SCpnt); +static void nsp_pio_read(Scsi_Cmnd *SCpnt); +static int nsp_nexus(Scsi_Cmnd *SCpnt); + +#ifdef PCMCIA_DEBUG +# ifdef DBG_SHOWCOMMAND +static void show_command(Scsi_Cmnd *ptr); +static void show_phase(Scsi_Cmnd *SCpnt); +static void show_busphase(unsigned char stat); +# endif /* DBG_SHOWCOMMAND */ +#endif + +/* + * SCSI phase + */ +enum _scsi_phase { + PH_UNDETERMINED, + PH_ARBSTART, + PH_SELSTART, + PH_SELECTED, + PH_COMMAND, + PH_DATA, + PH_STATUS, + PH_MSG_IN, + PH_MSG_OUT, + PH_DISCONNECT, + PH_RESELECT +}; + +enum _data_in_out { + IO_UNKNOWN, + IO_IN, + IO_OUT +}; + + +#define NSP_SELTIMEOUT 200 + +#endif /*__nsp_cs__*/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/pcmcia/nsp_debug.c linux.ac/drivers/scsi/pcmcia/nsp_debug.c --- linux.vanilla/drivers/scsi/pcmcia/nsp_debug.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/scsi/pcmcia/nsp_debug.c Tue Apr 3 17:55:04 2001 @@ -0,0 +1,195 @@ +/*======================================================================== + Debug routines for nsp_cs + By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp> + + This software may be used and distributed according to the terms of + the GNU General Public License. +=========================================================================*/ + +/* $Id: nsp_debug.c,v 1.5 2001/02/08 08:08:58 elca Exp $ */ + +/* + * Show the command data of a command + */ +static const char unknown[] = "UNKNOWN"; + +static const char * group_0_commands[] = { +/* 00-03 */ "Test Unit Ready", "Rezero Unit", unknown, "Request Sense", +/* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reasssign Blocks", +/* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown, +/* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry", +/* 13-16 */ unknown, "Recover Buffered Data", "Mode Select", "Reserve", +/* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit", +/* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", +/* 1e-1f */ "Prevent/Allow Medium Removal", unknown, +}; + + +static const char *group_1_commands[] = { +/* 20-22 */ unknown, unknown, unknown, +/* 23-28 */ unknown, unknown, "Read Capacity", unknown, unknown, "Read (10)", +/* 29-2d */ unknown, "Write (10)", "Seek (10)", unknown, unknown, +/* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal", +/* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", +/* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data", +/* 38-3c */ "Medium Scan", "Compare","Copy Verify", "Write Buffer", "Read Buffer", +/* 3d-3f */ "Update Block", "Read Long", "Write Long", +}; + + +static const char *group_2_commands[] = { +/* 40-41 */ "Change Definition", "Write Same", +/* 42-48 */ "Read Sub-Ch(cd)", "Read TOC", "Read Header(cd)", "Play Audio(cd)", unknown, "Play Audio MSF(cd)", "Play Audio Track/Index(cd)", +/* 49-4f */ "Play Track Relative(10)(cd)", unknown, "Pause/Resume(cd)", "Log Select", "Log Sense", unknown, unknown, +/* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)", +/* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown, +/* 5c-5f */ unknown, unknown, unknown, +}; + +#define group(opcode) (((opcode) >> 5) & 7) + +#define RESERVED_GROUP 0 +#define VENDOR_GROUP 1 +#define NOTEXT_GROUP 2 + +static const char **commands[] = { + group_0_commands, group_1_commands, group_2_commands, + (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, + (const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP, + (const char **) VENDOR_GROUP +}; + +static const char reserved[] = "RESERVED"; +static const char vendor[] = "VENDOR SPECIFIC"; + +static void print_opcodek(unsigned char opcode) +{ + const char **table = commands[ group(opcode) ]; + + switch ((unsigned long) table) { + case RESERVED_GROUP: + printk("%s[%02x] ", reserved, opcode); + break; + case NOTEXT_GROUP: + printk("%s(notext)[%02x] ", unknown, opcode); + break; + case VENDOR_GROUP: + printk("%s[%02x] ", vendor, opcode); + break; + default: + if (table[opcode & 0x1f] != unknown) + printk("%s[%02x] ", table[opcode & 0x1f], opcode); + else + printk("%s[%02x] ", unknown, opcode); + break; + } +} + +void print_commandk (unsigned char *command) +{ + int i,s; + printk(KERN_DEBUG); + print_opcodek(command[0]); + /*printk(KERN_DEBUG __FUNCTION__ " ");*/ + for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) { + printk("%02x ", command[i]); + } + switch (COMMAND_SIZE(command[0])) { + case 6: + printk("LBA=%d len=%d", + (((unsigned int)command[1] & 0x0f) << 16) | + ( (unsigned int)command[2] << 8) | + ( (unsigned int)command[3] ), + (unsigned int)command[4] + ); + break; + case 10: + printk("LBA=%d len=%d", + ((unsigned int)command[2] << 24) | + ((unsigned int)command[3] << 16) | + ((unsigned int)command[4] << 8) | + ((unsigned int)command[5] ), + ((unsigned int)command[7] << 8) | + ((unsigned int)command[8] ) + ); + break; + case 12: + printk("LBA=%d len=%d", + ((unsigned int)command[2] << 24) | + ((unsigned int)command[3] << 16) | + ((unsigned int)command[4] << 8) | + ((unsigned int)command[5] ), + ((unsigned int)command[6] << 24) | + ((unsigned int)command[7] << 16) | + ((unsigned int)command[8] << 8) | + ((unsigned int)command[9] ) + ); + break; + default: + break; + } + printk("\n"); +} + +static void show_command(Scsi_Cmnd *ptr) +{ + print_commandk(ptr->cmnd); +} + +static void show_phase(Scsi_Cmnd *SCpnt) +{ + int i = SCpnt->SCp.phase; + + char *ph[] = { + "PH_UNDETERMINED", + "PH_ARBSTART", + "PH_SELSTART", + "PH_SELECTED", + "PH_COMMAND", + "PH_DATA", + "PH_STATUS", + "PH_MSG_IN", + "PH_MSG_OUT", + "PH_DISCONNECT", + "PH_RESELECT" + }; + + if ( i < PH_UNDETERMINED || i > PH_RESELECT ) { + printk(KERN_DEBUG "scsi phase: unknown(%d)\n", i); + return; + } + + printk(KERN_DEBUG "scsi phase: %s\n", ph[i]); + + return; +} + +static void show_busphase(unsigned char stat) +{ + switch(stat) { + case BUSPHASE_COMMAND: + printk(KERN_DEBUG "BUSPHASE_COMMAND\n"); + break; + case BUSPHASE_MESSAGE_IN: + printk(KERN_DEBUG "BUSPHASE_MESSAGE_IN\n"); + break; + case BUSPHASE_MESSAGE_OUT: + printk(KERN_DEBUG "BUSPHASE_MESSAGE_OUT\n"); + break; + case BUSPHASE_DATA_IN: + printk(KERN_DEBUG "BUSPHASE_DATA_IN\n"); + break; + case BUSPHASE_DATA_OUT: + printk(KERN_DEBUG "BUSPHASE_DATA_OUT\n"); + break; + case BUSPHASE_STATUS: + printk(KERN_DEBUG "BUSPHASE_STATUS\n"); + break; + case BUSPHASE_SELECT: + printk(KERN_DEBUG "BUSPHASE_SELECT\n"); + break; + default: + printk(KERN_DEBUG "BUSPHASE_other\n"); + break; + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/pcmcia/nsp_io.h linux.ac/drivers/scsi/pcmcia/nsp_io.h --- linux.vanilla/drivers/scsi/pcmcia/nsp_io.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/scsi/pcmcia/nsp_io.h Tue Apr 3 17:55:04 2001 @@ -0,0 +1,176 @@ +/* + NinjaSCSI I/O funtions + By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp> + + This software may be used and distributed according to the terms of + the GNU General Public License. + + */ + +/* $Id: nsp_io.h,v 1.8 2001/01/30 05:16:02 elca Exp $ */ + +#ifndef __NSP_IO_H__ +#define __NSP_IO_H__ + +static inline void nsp_write(unsigned int base, + unsigned int index, + unsigned char val); +static inline unsigned char nsp_read(unsigned int base, + unsigned int index); +static inline void nsp_index_write(unsigned int BaseAddr, + unsigned int Register, + unsigned char Value); +static inline unsigned char nsp_index_read(unsigned int BaseAddr, + unsigned int Register); + +/******************************************************************* + * Basic IO + */ + +static inline void nsp_write(unsigned int base, + unsigned int index, + unsigned char val) +{ + outb(val, (base + index)); +} + +static inline unsigned char nsp_read(unsigned int base, + unsigned int index) +{ + return inb(base + index); +} + + +/********************************************************************** + * Indexed IO + */ +static inline unsigned char nsp_index_read(unsigned int BaseAddr, + unsigned int Register) +{ + outb(Register, BaseAddr + INDEXREG); + return inb(BaseAddr + DATAREG); +} + +static inline void nsp_index_write(unsigned int BaseAddr, + unsigned int Register, + unsigned char Value) +{ + outb(Register, BaseAddr + INDEXREG); + outb(Value, BaseAddr + DATAREG); +} + +/********************************************************************* + * fifo func + */ + +/* read 8 bit FIFO */ +static inline void nsp_multi_read_1(unsigned int BaseAddr, + unsigned int Register, + void *buf, + unsigned long count) +{ + insb(BaseAddr + Register, buf, count); +} + +static inline void nsp_fifo8_read(unsigned int base, + void *buf, + unsigned long count) +{ + //DEBUG(0, __FUNCTION__ "() buf=0x%p, count=0x%lx\n", buf, count); + nsp_multi_read_1(base, FIFODATA, buf, count); +} + +/*--------------------------------------------------------------*/ + +/* read 16 bit FIFO */ +static inline void nsp_multi_read_2(unsigned int BaseAddr, + unsigned int Register, + void *buf, + unsigned long count) +{ + insw(BaseAddr + Register, buf, count); +} + +static inline void nsp_fifo16_read(unsigned int base, + void *buf, + unsigned long count) +{ + //DEBUG(0, __FUNCTION__ "() buf=0x%p, count=0x%lx*2\n", buf, count); + nsp_multi_read_2(base, FIFODATA, buf, count); +} + +/*--------------------------------------------------------------*/ + +/* read 32bit FIFO */ +static inline void nsp_multi_read_4(unsigned int BaseAddr, + unsigned int Register, + void *buf, + unsigned long count) +{ + insl(BaseAddr + Register, buf, count); +} + +static inline void nsp_fifo32_read(unsigned int base, + void *buf, + unsigned long count) +{ + //DEBUG(0, __FUNCTION__ "() buf=0x%p, count=0x%lx*4\n", buf, count); + nsp_multi_read_4(base, FIFODATA, buf, count); +} + +/*----------------------------------------------------------*/ + +/* write 8bit FIFO */ +static inline void nsp_multi_write_1(unsigned int BaseAddr, + unsigned int Register, + void *buf, + unsigned long count) +{ + outsb(BaseAddr + Register, buf, count); +} + +static inline void nsp_fifo8_write(unsigned int base, + void *buf, + unsigned long count) +{ + nsp_multi_write_1(base, FIFODATA, buf, count); +} + +/*---------------------------------------------------------*/ + +/* write 16bit FIFO */ +static inline void nsp_multi_write_2(unsigned int BaseAddr, + unsigned int Register, + void *buf, + unsigned long count) +{ + outsw(BaseAddr + Register, buf, count); +} + +static inline void nsp_fifo16_write(unsigned int base, + void *buf, + unsigned long count) +{ + nsp_multi_write_2(base, FIFODATA, buf, count); +} + +/*---------------------------------------------------------*/ + +/* write 32bit FIFO */ +static inline void nsp_multi_write_4(unsigned int BaseAddr, + unsigned int Register, + void *buf, + unsigned long count) +{ + outsl(BaseAddr + Register, buf, count); +} + +static inline void nsp_fifo32_write(unsigned int base, + void *buf, + unsigned long count) +{ + nsp_multi_write_4(base, FIFODATA, buf, count); +} + +#endif +/* end */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/qlogicfas.c linux.ac/drivers/scsi/qlogicfas.c --- linux.vanilla/drivers/scsi/qlogicfas.c Mon Sep 18 21:36:25 2000 +++ linux.ac/drivers/scsi/qlogicfas.c Thu Apr 12 12:04:02 2001 @@ -23,7 +23,7 @@ Functions as standalone, loadable, and PCMCIA driver, the latter from Dave Hinds' PCMCIA package. - Redistributable under terms of the GNU Public License + Redistributable under terms of the GNU General Public License */ /*----------------------------------------------------------------*/ @@ -118,6 +118,7 @@ #include <linux/blk.h> /* to get disk capacity */ #include <linux/kernel.h> #include <linux/string.h> +#include <linux/init.h> #include <linux/ioport.h> #include <linux/sched.h> #include <linux/proc_fs.h> @@ -128,11 +129,11 @@ #include "sd.h" #include "hosts.h" #include "qlogicfas.h" -#include<linux/stat.h> +#include <linux/stat.h> /*----------------------------------------------------------------*/ /* driver state info, local to driver */ -static int qbase = 0; /* Port */ +static int qbase; /* Port */ static int qinitid; /* initiator ID */ static int qabort; /* Flag to cause an abort */ static int qlirq = -1; /* IRQ being used */ @@ -537,7 +538,7 @@ /*----------------------------------------------------------------*/ /* look for qlogic card and init if found */ -int qlogicfas_detect(Scsi_Host_Template * host) +int __QLINIT qlogicfas_detect(Scsi_Host_Template * host) { int i, j; /* these are only used by IRQ detect */ int qltyp; /* type of chip */ @@ -556,7 +557,7 @@ if( !qbase ) { for (qbase = 0x230; qbase < 0x430; qbase += 0x100) { - if( check_region( qbase , 0x10 ) ) + if( !request_region( qbase , 0x10, "qlogicfas" ) ) continue; REG1; if ( ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) @@ -616,8 +617,9 @@ if (qlirq >= 0 && !request_irq(qlirq, do_ql_ihandl, 0, "qlogicfas", NULL)) host->can_queue = 1; #endif - request_region( qbase , 0x10 ,"qlogicfas"); hreg = scsi_register( host , 0 ); /* no host data */ + if (!hreg) + goto err_release_mem; hreg->io_port = qbase; hreg->n_io_port = 16; hreg->dma_channel = -1; @@ -629,6 +631,13 @@ host->name = qinfo; return 1; + + err_release_mem: + release_region(qbase, 0x10); + if (host->can_queue) + free_irq(qlirq, do_ql_ihandl); + return 0; + } /*----------------------------------------------------------------*/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/qlogicfas.h linux.ac/drivers/scsi/qlogicfas.h --- linux.vanilla/drivers/scsi/qlogicfas.h Mon Dec 22 01:04:49 1997 +++ linux.ac/drivers/scsi/qlogicfas.h Thu Apr 12 12:04:02 2001 @@ -13,6 +13,12 @@ #define NULL (0) #endif +#ifdef PCMCIA +#define __QLINIT __devinit +#else +#define __QLINIT __init +#endif + #define QLOGICFAS { \ detect: qlogicfas_detect, \ info: qlogicfas_info, \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/qlogicfc.c linux.ac/drivers/scsi/qlogicfc.c --- linux.vanilla/drivers/scsi/qlogicfc.c Tue Apr 3 17:32:21 2001 +++ linux.ac/drivers/scsi/qlogicfc.c Tue Apr 17 15:31:48 2001 @@ -195,8 +195,8 @@ #define FLASH_BIOS_ADDR 0x00 #define FLASH_BIOS_DATA 0x02 #define ISP_CTRL_STATUS 0x06 /* configuration register #1 */ -#define PCI_INTER_CTL 0x08 /* pci interupt control */ -#define PCI_INTER_STS 0x0a /* pci interupt status */ +#define PCI_INTER_CTL 0x08 /* pci interrupt control */ +#define PCI_INTER_STS 0x0a /* pci interrupt status */ #define PCI_SEMAPHORE 0x0c /* pci semaphore */ #define PCI_NVRAM 0x0e /* pci nvram interface */ @@ -227,7 +227,7 @@ #define REQUEST_TRANSFER_ERROR 0x8003 #define RESPONSE_TRANSFER_ERROR 0x8004 #define REQUEST_QUEUE_WAKEUP 0x8005 -#define LIP_OCCURED 0x8010 +#define LIP_OCCURRED 0x8010 #define LOOP_UP 0x8011 #define LOOP_DOWN 0x8012 #define LIP_RECEIVED 0x8013 @@ -369,7 +369,7 @@ #define STF_ABORTED 0x0020 #define STF_TIMEOUT 0x0040 -/* interupt control commands */ +/* interrupt control commands */ #define ISP_EN_INT 0x8000 #define ISP_EN_RISC 0x0008 @@ -757,6 +757,10 @@ continue; host = scsi_register(tmpt, sizeof(struct isp2x00_hostdata)); + if (!host) { + printk("qlogicfc%d : could not register host.\n", hostdata->host_id); + continue; + } host->max_id = QLOGICFC_MAX_ID + 1; host->max_lun = QLOGICFC_MAX_LUN; host->hostt->use_new_eh_code = 1; @@ -768,6 +772,7 @@ if (!hostdata->res){ printk("qlogicfc%d : could not allocate memory for request and response queue.\n", hostdata->host_id); + pci64_free_consistent(pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); scsi_unregister(host); continue; } @@ -813,7 +818,7 @@ scsi_unregister(host); continue; } - if (check_region(host->io_port, 0xff)) { + if (!request_region(host->io_port, 0xff, "qlogicfc")) { printk("qlogicfc%d : i/o region 0x%lx-0x%lx already " "in use\n", hostdata->host_id, host->io_port, host->io_port + 0xff); @@ -822,7 +827,6 @@ scsi_unregister(host); continue; } - request_region(host->io_port, 0xff, "qlogicfc"); outw(0x0, host->io_port + PCI_SEMAPHORE); outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); @@ -1520,7 +1524,7 @@ if (hostdata->adapter_state == AS_LOOP_GOOD) hostdata->adapter_state = AS_REDO_FABRIC_PORTDB; break; - case LIP_OCCURED: + case LIP_OCCURRED: case LIP_RECEIVED: printk("qlogicfc%d : Loop Reinitialized\n", hostdata->host_id); if (hostdata->adapter_state == AS_LOOP_GOOD) @@ -1865,8 +1869,15 @@ hostdata = (struct isp2x00_hostdata *) host->hostdata; + /* + * This cannot be right - PCI writes are posted + * (apparently this is hardware design flaw not software ?) + */ + outw(0x01, host->io_port + ISP_CTRL_STATUS); + udelay(100); outw(HCCR_RESET, host->io_port + HOST_HCCR); + udelay(100); outw(HCCR_RELEASE, host->io_port + HOST_HCCR); outw(HCCR_BIOS_DISABLE, host->io_port + HOST_HCCR); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/qlogicisp.c linux.ac/drivers/scsi/qlogicisp.c --- linux.vanilla/drivers/scsi/qlogicisp.c Tue Apr 3 17:32:21 2001 +++ linux.ac/drivers/scsi/qlogicisp.c Tue Apr 3 17:55:04 2001 @@ -705,6 +705,7 @@ } host->this_id = hostdata->host_param.initiator_scsi_id; + host->max_sectors = 64; if (request_irq(host->irq, do_isp1020_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicisp", host)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/qlogicpti.c linux.ac/drivers/scsi/qlogicpti.c --- linux.vanilla/drivers/scsi/qlogicpti.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/scsi/qlogicpti.c Tue Apr 3 17:55:04 2001 @@ -737,6 +737,7 @@ prom_getintdefault(qpti->sdev->bus->prom_node, "scsi-initiator-id", 7); qpti->qhost->this_id = qpti->scsi_id; + qpti->qhost->max_sectors = 64; printk("SCSI ID %d ", qpti->scsi_id); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/scsi.c linux.ac/drivers/scsi/scsi.c --- linux.vanilla/drivers/scsi/scsi.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/scsi/scsi.c Tue Apr 3 17:55:04 2001 @@ -53,6 +53,7 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/smp_lock.h> #define __KERNEL_SYSCALLS__ @@ -1101,7 +1102,7 @@ * the response. We treat it as if the command never finished. * * Since serial_number is now 0, the error handler cound detect this - * situation and avoid to call the the low level driver abort routine. + * situation and avoid to call the low level driver abort routine. * (DB) * * FIXME(eric) - I believe that this test is now redundant, due to @@ -1376,7 +1377,7 @@ } static int scsi_register_host(Scsi_Host_Template *); -static void scsi_unregister_host(Scsi_Host_Template *); +static int scsi_unregister_host(Scsi_Host_Template *); /* * Function: scsi_release_commandblocks() @@ -1819,6 +1820,11 @@ return 1; /* Must be already loaded, or * no detect routine available */ + + /* If max_sectors isn't set, default to max */ + if (!tpnt->max_sectors) + tpnt->max_sectors = MAX_SECTORS; + pcount = next_scsi_host; /* The detect routine must carefully spinunlock/spinlock if @@ -1963,14 +1969,8 @@ /* * Similarly, this entry point should be called by a loadable module if it * is trying to remove a low level scsi driver from the system. - * - * Note - there is a fatal flaw in the deregister module function. - * There is no way to return a code that says 'I cannot be unloaded now'. - * The system relies entirely upon usage counts that are maintained, - * and the assumption is that if the usage count is 0, then the module - * can be unloaded. */ -static void scsi_unregister_host(Scsi_Host_Template * tpnt) +static int scsi_unregister_host(Scsi_Host_Template * tpnt) { int online_status; int pcount0, pcount; @@ -1982,6 +1982,9 @@ struct Scsi_Host *shpnt; char name[10]; /* host_no>=10^9? I don't think so. */ + /* get the big kernel lock, so we don't race with open() */ + lock_kernel(); + /* * First verify that this host adapter is completely free with no pending * commands @@ -1992,7 +1995,7 @@ if (SDpnt->host->hostt == tpnt && SDpnt->host->hostt->module && GET_USE_COUNT(SDpnt->host->hostt->module)) - return; + goto err_out; /* * FIXME(eric) - We need to find a way to notify the * low level driver that we are shutting down - via the @@ -2044,7 +2047,7 @@ } SDpnt->online = online_status; printk(KERN_ERR "Device busy???\n"); - return; + goto err_out; } /* * No, this device is really free. Mark it as such, and @@ -2070,7 +2073,7 @@ /* If something still attached, punt */ if (SDpnt->attached) { printk(KERN_ERR "Attached usage count = %d\n", SDpnt->attached); - return; + goto err_out; } devfs_unregister (SDpnt->de); } @@ -2178,6 +2181,13 @@ } } MOD_DEC_USE_COUNT; + + unlock_kernel(); + return 0; + +err_out: + unlock_kernel(); + return -1; } static int scsi_unregister_device(struct Scsi_Device_Template *tpnt); @@ -2259,12 +2269,13 @@ struct Scsi_Host *shpnt; struct Scsi_Device_Template *spnt; struct Scsi_Device_Template *prev_spnt; - + + lock_kernel(); /* * If we are busy, this is not going to fly. */ if (GET_USE_COUNT(tpnt->module) != 0) - return 0; + goto error_out; /* * Next, detach the devices from the driver. @@ -2301,11 +2312,15 @@ prev_spnt->next = spnt->next; MOD_DEC_USE_COUNT; + unlock_kernel(); /* * Final cleanup for the driver is done in the driver sources in the * cleanup function. */ return 0; +error_out: + unlock_kernel(); + return -1; } @@ -2342,22 +2357,24 @@ /* Reverse the actions taken above */ -void scsi_unregister_module(int module_type, void *ptr) +int scsi_unregister_module(int module_type, void *ptr) { + int retval = 0; + switch (module_type) { case MODULE_SCSI_HA: - scsi_unregister_host((Scsi_Host_Template *) ptr); + retval = scsi_unregister_host((Scsi_Host_Template *) ptr); break; case MODULE_SCSI_DEV: - scsi_unregister_device((struct Scsi_Device_Template *) ptr); - break; + retval = scsi_unregister_device((struct Scsi_Device_Template *)ptr); + break; /* The rest of these are not yet implemented. */ case MODULE_SCSI_CONST: case MODULE_SCSI_IOCTL: break; - default: + default:; } - return; + return retval; } #ifdef CONFIG_PROC_FS diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/scsi.h linux.ac/drivers/scsi/scsi.h --- linux.vanilla/drivers/scsi/scsi.h Thu Feb 22 00:10:50 2001 +++ linux.ac/drivers/scsi/scsi.h Tue Apr 17 17:49:03 2001 @@ -617,6 +617,9 @@ unsigned remap:1; /* support remapping */ unsigned starved:1; /* unable to process commands because host busy */ + + // Flag to allow revalidate to succeed in sd_open + int allow_revalidate; }; @@ -668,7 +671,7 @@ unsigned short sr_use_sg; /* Number of pieces of scatter-gather */ unsigned short sr_sglist_len; /* size of malloc'd scatter-gather list */ unsigned sr_underflow; /* Return error if less than - this amount is transfered */ + this amount is transferred */ }; /* @@ -756,7 +759,7 @@ void *buffer; /* Data buffer */ unsigned underflow; /* Return error if less than - this amount is transfered */ + this amount is transferred */ unsigned old_underflow; /* save underflow here when reusing the * command for error handling */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/scsi_error.c linux.ac/drivers/scsi/scsi_error.c --- linux.vanilla/drivers/scsi/scsi_error.c Tue Apr 3 17:32:21 2001 +++ linux.ac/drivers/scsi/scsi_error.c Tue Apr 3 17:55:04 2001 @@ -427,7 +427,8 @@ memcpy((void *) SCpnt->cmnd, (void *) generic_sense, sizeof(generic_sense)); - SCpnt->cmnd[1] = SCpnt->lun << 5; + if (SCpnt->device->scsi_level <= SCSI_2) + SCpnt->cmnd[1] = SCpnt->lun << 5; scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma) ? &scsi_result0[0] : kmalloc(512, GFP_ATOMIC | GFP_DMA); @@ -496,7 +497,8 @@ memcpy((void *) SCpnt->cmnd, (void *) tur_command, sizeof(tur_command)); - SCpnt->cmnd[1] = SCpnt->lun << 5; + if (SCpnt->device->scsi_level <= SCSI_2) + SCpnt->cmnd[1] = SCpnt->lun << 5; /* * Zero the sense buffer. The SCSI spec mandates that any diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/scsi_ioctl.c linux.ac/drivers/scsi/scsi_ioctl.c --- linux.vanilla/drivers/scsi/scsi_ioctl.c Sun Feb 4 18:05:30 2001 +++ linux.ac/drivers/scsi/scsi_ioctl.c Tue Apr 3 17:55:04 2001 @@ -79,7 +79,7 @@ * * *(char *) ((int *) arg)[2] the actual command byte. * - * Note that if more than MAX_BUF bytes are requested to be transfered, + * Note that if more than MAX_BUF bytes are requested to be transferred, * the ioctl will fail with error EINVAL. MAX_BUF can be increased in * the future by increasing the size that scsi_malloc will accept. * @@ -268,7 +268,8 @@ /* * Set the lun field to the correct value. */ - cmd[1] = (cmd[1] & 0x1f) | (dev->lun << 5); + if (dev->scsi_level <= SCSI_2) + cmd[1] = (cmd[1] & 0x1f) | (dev->lun << 5); switch (opcode) { case FORMAT_UNIT: @@ -359,6 +360,7 @@ int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg) { char scsi_cmd[MAX_COMMAND_SIZE]; + char cmd_byte1; /* No idea how this happens.... */ if (!dev) @@ -373,14 +375,16 @@ if (!scsi_block_when_processing_errors(dev)) { return -ENODEV; } + cmd_byte1 = (dev->scsi_level <= SCSI_2) ? (dev->lun << 5) : 0; + switch (cmd) { case SCSI_IOCTL_GET_IDLUN: if (verify_area(VERIFY_WRITE, arg, sizeof(Scsi_Idlun))) return -EFAULT; - __put_user(dev->id - + (dev->lun << 8) - + (dev->channel << 16) + __put_user((dev->id & 0xff) + + ((dev->lun & 0xff) << 8) + + ((dev->channel & 0xff) << 16) + ((dev->host->host_no & 0xff) << 24), &((Scsi_Idlun *) arg)->dev_id); __put_user(dev->host->unique_id, &((Scsi_Idlun *) arg)->host_unique_id); @@ -414,7 +418,7 @@ if (!dev->removable || !dev->lockable) return 0; scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; - scsi_cmd[1] = dev->lun << 5; + scsi_cmd[1] = cmd_byte1; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; scsi_cmd[4] = SCSI_REMOVAL_PREVENT; return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, @@ -424,14 +428,14 @@ if (!dev->removable || !dev->lockable) return 0; scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; - scsi_cmd[1] = dev->lun << 5; + scsi_cmd[1] = cmd_byte1; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; scsi_cmd[4] = SCSI_REMOVAL_ALLOW; return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES); case SCSI_IOCTL_TEST_UNIT_READY: scsi_cmd[0] = TEST_UNIT_READY; - scsi_cmd[1] = dev->lun << 5; + scsi_cmd[1] = cmd_byte1; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; scsi_cmd[4] = 0; return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, @@ -439,7 +443,7 @@ break; case SCSI_IOCTL_START_UNIT: scsi_cmd[0] = START_STOP; - scsi_cmd[1] = dev->lun << 5; + scsi_cmd[1] = cmd_byte1; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; scsi_cmd[4] = 1; return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, @@ -447,7 +451,7 @@ break; case SCSI_IOCTL_STOP_UNIT: scsi_cmd[0] = START_STOP; - scsi_cmd[1] = dev->lun << 5; + scsi_cmd[1] = cmd_byte1; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; scsi_cmd[4] = 0; return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/scsi_lib.c linux.ac/drivers/scsi/scsi_lib.c --- linux.vanilla/drivers/scsi/scsi_lib.c Tue Apr 3 17:32:21 2001 +++ linux.ac/drivers/scsi/scsi_lib.c Thu Apr 12 17:51:15 2001 @@ -377,12 +377,15 @@ nsect = bh->b_size >> 9; blk_finished_io(nsect); req->bh = bh->b_reqnext; - req->nr_sectors -= nsect; - req->sector += nsect; bh->b_reqnext = NULL; sectors -= nsect; bh->b_end_io(bh, uptodate); if ((bh = req->bh) != NULL) { + req->hard_sector += nsect; + req->hard_nr_sectors -= nsect; + req->sector += nsect; + req->nr_sectors -= nsect; + req->current_nr_sectors = bh->b_size >> 9; if (req->nr_sectors < req->current_nr_sectors) { req->nr_sectors = req->current_nr_sectors; @@ -1108,9 +1111,13 @@ */ void scsi_unblock_requests(struct Scsi_Host * SHpnt) { + Scsi_Device *SDloop; + SHpnt->host_self_blocked = FALSE; + /* Now that we are unblocked, try to start the queues. */ + for (SDloop = SHpnt->host_queue; SDloop; SDloop = SDloop->next) + scsi_queue_next_request(&SDloop->request_queue, NULL); } - /* * Function: scsi_report_bus_reset() diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/scsi_merge.c linux.ac/drivers/scsi/scsi_merge.c --- linux.vanilla/drivers/scsi/scsi_merge.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/scsi/scsi_merge.c Tue Apr 3 23:30:07 2001 @@ -417,6 +417,9 @@ max_segments = 64; #endif + if ((req->nr_sectors + (bh->b_size >> 9)) > SHpnt->max_sectors) + return 0; + if (use_clustering) { /* * See if we can do this without creating another @@ -473,6 +476,9 @@ max_segments = 64; #endif + if ((req->nr_sectors + (bh->b_size >> 9)) > SHpnt->max_sectors) + return 0; + if (use_clustering) { /* * See if we can do this without creating another @@ -597,6 +603,13 @@ Scsi_Device *SDpnt; struct Scsi_Host *SHpnt; + /* + * First check if the either of the requests are re-queued + * requests. Can't merge them if they are. + */ + if (req->special || next->special) + return 0; + SDpnt = (Scsi_Device *) q->queuedata; SHpnt = SDpnt->host; @@ -624,6 +637,10 @@ return 0; } #endif + + if ((req->nr_sectors + next->nr_sectors) > SHpnt->max_sectors) + return 0; + /* * The main question is whether the two segments at the boundaries * would be considered one or two. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/scsi_obsolete.c linux.ac/drivers/scsi/scsi_obsolete.c --- linux.vanilla/drivers/scsi/scsi_obsolete.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/scsi/scsi_obsolete.c Tue Apr 3 17:55:04 2001 @@ -223,7 +223,8 @@ memset((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); - SCpnt->cmnd[1] = SCpnt->lun << 5; + if (SCpnt->device->scsi_level <= SCSI_2) + SCpnt->cmnd[1] = SCpnt->lun << 5; SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer); SCpnt->request_buffer = &SCpnt->sense_buffer; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/scsi_scan.c linux.ac/drivers/scsi/scsi_scan.c --- linux.vanilla/drivers/scsi/scsi_scan.c Sun Feb 4 18:05:30 2001 +++ linux.ac/drivers/scsi/scsi_scan.c Thu Apr 12 12:04:14 2001 @@ -40,9 +40,13 @@ #define BLIST_ISROM 0x200 static void print_inquiry(unsigned char *data); -static int scan_scsis_single(int channel, int dev, int lun, int *max_scsi_dev, - int *sparse_lun, Scsi_Device ** SDpnt, - struct Scsi_Host *shpnt, char *scsi_result); +static int scan_scsis_single(unsigned int channel, unsigned int dev, + unsigned int lun, int lun0_scsi_level, + unsigned int *max_scsi_dev, unsigned int *sparse_lun, + Scsi_Device ** SDpnt, struct Scsi_Host *shpnt, + char *scsi_result); +static int find_lun0_scsi_level(unsigned int channel, unsigned int dev, + struct Scsi_Host *shpnt); struct dev_info { const char *vendor; @@ -135,10 +139,12 @@ {"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN}, {"DEC","HSG80","*", BLIST_FORCELUN}, {"COMPAQ","LOGICAL VOLUME","*", BLIST_FORCELUN}, + {"COMPAQ","CR3500","*", BLIST_FORCELUN}, {"NEC", "PD-1 ODX654P", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"MATSHITA", "PD-1", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN}, {"TOSHIBA","CDROM","*", BLIST_ISROM}, + {"TOSHIBA","CD-ROM","*", BLIST_ISROM}, {"MegaRAID", "LD", "*", BLIST_FORCELUN}, {"DGC", "RAID", "*", BLIST_SPARSELUN}, // Dell PV 650F (tgt @ LUN 0) {"DGC", "DISK", "*", BLIST_SPARSELUN}, // Dell PV 650F (no tgt @ LUN 0) @@ -153,29 +159,31 @@ {NULL, NULL, NULL} }; +#define MAX_SCSI_LUNS 0xFFFFFFFF + #ifdef CONFIG_SCSI_MULTI_LUN -static int max_scsi_luns = 8; +static unsigned int max_scsi_luns = MAX_SCSI_LUNS; #else -static int max_scsi_luns = 1; +static unsigned int max_scsi_luns = 1; #endif #ifdef MODULE MODULE_PARM(max_scsi_luns, "i"); -MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 8)"); +MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 2^32-1)"); #else static int __init scsi_luns_setup(char *str) { - int tmp; + unsigned int tmp; if (get_option(&str, &tmp) == 1) { max_scsi_luns = tmp; return 1; } else { printk("scsi_luns_setup : usage max_scsi_luns=n " - "(n should be between 1 and 8)\n"); + "(n should be between 1 and 2^32-1)\n"); return 0; } } @@ -263,14 +271,15 @@ uint hlun) { uint channel; - int dev; - int lun; - int max_dev_lun; + unsigned int dev; + unsigned int lun; + unsigned int max_dev_lun; unsigned char *scsi_result; unsigned char scsi_result0[256]; Scsi_Device *SDpnt; Scsi_Device *SDtail; - int sparse_lun; + unsigned int sparse_lun; + int lun0_sl; scsi_result = NULL; @@ -342,8 +351,12 @@ lun = hlun; if (lun >= shpnt->max_lun) goto leave; - scan_scsis_single(channel, dev, lun, &max_dev_lun, &sparse_lun, - &SDpnt, shpnt, scsi_result); + if ((0 == lun) || (lun > 7)) + lun0_sl = SCSI_3; /* actually don't care for 0 == lun */ + else + lun0_sl = find_lun0_scsi_level(channel, dev, shpnt); + scan_scsis_single(channel, dev, lun, lun0_sl, &max_dev_lun, + &sparse_lun, &SDpnt, shpnt, scsi_result); if (SDpnt != oldSDpnt) { /* it could happen the blockdevice hasn't yet been inited */ @@ -399,12 +412,14 @@ max_dev_lun = (max_scsi_luns < shpnt->max_lun ? max_scsi_luns : shpnt->max_lun); sparse_lun = 0; - for (lun = 0; lun < max_dev_lun; ++lun) { - if (!scan_scsis_single(channel, order_dev, lun, &max_dev_lun, - &sparse_lun, &SDpnt, shpnt, - scsi_result) + for (lun = 0, lun0_sl = SCSI_2; lun < max_dev_lun; ++lun) { + if (!scan_scsis_single(channel, order_dev, lun, lun0_sl, + &max_dev_lun, &sparse_lun, &SDpnt, shpnt, + scsi_result) && !sparse_lun) break; /* break means don't probe further for luns!=0 */ + if (SDpnt && (0 == lun)) + lun0_sl = SDpnt->scsi_level; } /* for lun ends */ } /* if this_id != id ends */ } /* for dev ends */ @@ -460,9 +475,11 @@ * Returning 0 means Please don't ask further for lun!=0, 1 means OK go on. * Global variables used : scsi_devices(linked list) */ -static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun, - int *sparse_lun, Scsi_Device ** SDpnt2, - struct Scsi_Host *shpnt, char *scsi_result) +static int scan_scsis_single(unsigned int channel, unsigned int dev, + unsigned int lun, int lun0_scsi_level, + unsigned int *max_dev_lun, unsigned int *sparse_lun, + Scsi_Device ** SDpnt2, struct Scsi_Host *shpnt, + char *scsi_result) { char devname[64]; unsigned char scsi_cmd[MAX_COMMAND_SIZE]; @@ -508,7 +525,10 @@ * Build an INQUIRY command block. */ scsi_cmd[0] = INQUIRY; - scsi_cmd[1] = (lun << 5) & 0xe0; + if ((lun > 0) && (lun0_scsi_level <= SCSI_2)) + scsi_cmd[1] = (lun << 5) & 0xe0; + else + scsi_cmd[1] = 0; /* SCSI_3 and higher, don't touch */ scsi_cmd[2] = 0; scsi_cmd[3] = 0; scsi_cmd[4] = 255; @@ -664,7 +684,9 @@ printk("Unlocked floptical drive.\n"); SDpnt->lockable = 0; scsi_cmd[0] = MODE_SENSE; - scsi_cmd[1] = (lun << 5) & 0xe0; + if (shpnt->max_lun <= 8) + scsi_cmd[1] = (lun << 5) & 0xe0; + else scsi_cmd[1] = 0; /* any other idea? */ scsi_cmd[2] = 0x2e; scsi_cmd[3] = 0; scsi_cmd[4] = 0x2a; @@ -747,7 +769,19 @@ * other settings, and scan all of them. */ if (bflags & BLIST_SPARSELUN) { - *max_dev_lun = 8; + /* + * Scanning MAX_SCSI_LUNS units would be a bad idea. + * Any better idea? + * I think we need REPORT LUNS in future to avoid scanning + * of unused LUNs. But, that is another item. + * + * FIXME(eric) - perhaps this should be a kernel configurable? + */ + if (*max_dev_lun < shpnt->max_lun) + *max_dev_lun = shpnt->max_lun; + else if ((max_scsi_luns >> 1) >= *max_dev_lun) + *max_dev_lun += shpnt->max_lun; + else *max_dev_lun = max_scsi_luns; *sparse_lun = 1; return 1; } @@ -756,7 +790,17 @@ * settings, and scan all of them. */ if (bflags & BLIST_FORCELUN) { - *max_dev_lun = 8; + /* + * Scanning MAX_SCSI_LUNS units would be a bad idea. + * Any better idea? + * I think we need REPORT LUNS in future to avoid scanning + * of unused LUNs. But, that is another item. + */ + if (*max_dev_lun < shpnt->max_lun) + *max_dev_lun = shpnt->max_lun; + else if ((max_scsi_luns >> 1) >= *max_dev_lun) + *max_dev_lun += shpnt->max_lun; + else *max_dev_lun = max_scsi_luns; return 1; } /* @@ -780,3 +824,23 @@ return 1; } +/* + * The worker for scan_scsis. + * Returns the scsi_level of lun0 on this host, channel and dev (if already + * known), otherwise returns SCSI_2. + */ +static int find_lun0_scsi_level(unsigned int channel, unsigned int dev, + struct Scsi_Host *shpnt) +{ + int res = SCSI_2; + Scsi_Device *SDpnt; + + for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) + { + if ((0 == SDpnt->lun) && (dev == SDpnt->id) && + (channel == SDpnt->channel)) + return (int)SDpnt->scsi_level; + } + /* haven't found lun0, should send INQUIRY but take easy route */ + return res; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/sd.c linux.ac/drivers/scsi/sd.c --- linux.vanilla/drivers/scsi/sd.c Sat Feb 3 19:45:55 2001 +++ linux.ac/drivers/scsi/sd.c Tue Apr 3 17:55:04 2001 @@ -22,6 +22,12 @@ * * Modified by Torben Mathiasen tmm@image.dk * Resource allocation fixes in sd_init and cleanups. + * + * Modified by Alex Davis <letmein@erols.com> + * Fix problem where partition info not being read in sd_open. + * + * Modified by Alex Davis <letmein@erols.com> + * Fix problem where removable media could be ejected after sd_open. */ #include <linux/config.h> @@ -372,7 +378,8 @@ (SCpnt->request.cmd == WRITE) ? "writing" : "reading", this_count, SCpnt->request.nr_sectors)); - SCpnt->cmnd[1] = (SCpnt->lun << 5) & 0xe0; + SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ? + ((SCpnt->lun << 5) & 0xe0) : 0; if (((this_count > 0xff) || (block > 0x1fffff)) || SCpnt->device->ten) { if (this_count > 0xffff) @@ -424,7 +431,7 @@ static int sd_open(struct inode *inode, struct file *filp) { - int target; + int target, retval = -ENXIO; Scsi_Device * SDev; target = DEVICE_NR(inode->i_rdev); @@ -448,24 +455,40 @@ while (rscsi_disks[target].device->busy) barrier(); + /* + * The following code can sleep. + * Module unloading must be prevented + */ + SDev = rscsi_disks[target].device; + if (SDev->host->hostt->module) + __MOD_INC_USE_COUNT(SDev->host->hostt->module); + if (sd_template.module) + __MOD_INC_USE_COUNT(sd_template.module); + SDev->access_count++; + if (rscsi_disks[target].device->removable) { + SDev->allow_revalidate = 1; check_disk_change(inode->i_rdev); + SDev->allow_revalidate = 0; /* * If the drive is empty, just let the open fail. */ - if (!rscsi_disks[target].ready) - return -ENXIO; + if ((!rscsi_disks[target].ready) && !(filp->f_flags & O_NDELAY)) { + retval = -ENOMEDIUM; + goto error_out; + } /* * Similarly, if the device has the write protect tab set, * have the open fail if the user expects to be able to write * to the thing. */ - if ((rscsi_disks[target].write_prot) && (filp->f_mode & 2)) - return -EROFS; + if ((rscsi_disks[target].write_prot) && (filp->f_mode & 2)) { + retval = -EROFS; + goto error_out; + } } - SDev = rscsi_disks[target].device; /* * It is possible that the disk changing stuff resulted in the device * being taken offline. If this is the case, report this to the user, @@ -473,26 +496,31 @@ * the open actually succeeded. */ if (!SDev->online) { - return -ENXIO; + goto error_out; } /* * See if we are requesting a non-existent partition. Do this * after checking for disk change. */ - if (sd_sizes[SD_PARTITION(inode->i_rdev)] == 0) - return -ENXIO; + if (sd_sizes[SD_PARTITION(inode->i_rdev)] == 0) { + goto error_out; + } if (SDev->removable) - if (!SDev->access_count) + if (SDev->access_count==1) if (scsi_block_when_processing_errors(SDev)) scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, NULL); - SDev->access_count++; + + return 0; + +error_out: + SDev->access_count--; if (SDev->host->hostt->module) - __MOD_INC_USE_COUNT(SDev->host->hostt->module); + __MOD_DEC_USE_COUNT(SDev->host->hostt->module); if (sd_template.module) - __MOD_INC_USE_COUNT(sd_template.module); - return 0; + __MOD_DEC_USE_COUNT(sd_template.module); + return retval; } static int sd_release(struct inode *inode, struct file *file) @@ -746,7 +774,8 @@ while (retries < 3) { cmd[0] = TEST_UNIT_READY; - cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; + cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ? + ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0; memset((void *) &cmd[2], 0, 8); SRpnt->sr_cmd_len = 0; SRpnt->sr_sense_buffer[0] = 0; @@ -787,7 +816,8 @@ if (!spintime) { printk("%s: Spinning up disk...", nbuff); cmd[0] = START_STOP; - cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; + cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ? + ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0; cmd[1] |= 1; /* Return immediately */ memset((void *) &cmd[2], 0, 8); cmd[4] = 1; /* Start spin cycle */ @@ -820,7 +850,8 @@ retries = 3; do { cmd[0] = READ_CAPACITY; - cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; + cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ? + ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0; memset((void *) &cmd[2], 0, 8); memset((void *) buffer, 0, 8); SRpnt->sr_cmd_len = 0; @@ -978,7 +1009,8 @@ memset((void *) &cmd[0], 0, 8); cmd[0] = MODE_SENSE; - cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; + cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ? + ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0; cmd[2] = 0x3f; /* Get all pages */ cmd[4] = 8; /* But we only want the 8 byte header */ SRpnt->sr_cmd_len = 0; @@ -1185,16 +1217,9 @@ static int sd_detect(Scsi_Device * SDp) { - char nbuff[6]; if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0; - - sd_devname(sd_template.dev_noticed++, nbuff); - printk("Detected scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n", - SDp->removable ? "removable " : "", - nbuff, - SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); - + sd_template.dev_noticed++; return 1; } @@ -1203,6 +1228,7 @@ unsigned int devnum; Scsi_Disk *dpnt; int i; + char nbuff[6]; if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0; @@ -1226,10 +1252,15 @@ SD_GENDISK(i).de_arr[devnum] = SDp->de; if (SDp->removable) SD_GENDISK(i).flags[devnum] |= GENHD_FL_REMOVABLE; + sd_devname(i, nbuff); + printk("Attached scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n", + SDp->removable ? "removable " : "", + nbuff, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); return 0; } #define DEVICE_BUSY rscsi_disks[target].device->busy +#define ALLOW_REVALIDATE rscsi_disks[target].device->allow_revalidate #define USAGE rscsi_disks[target].device->access_count #define CAPACITY rscsi_disks[target].capacity #define MAYBE_REINIT sd_init_onedisk(target) @@ -1250,7 +1281,7 @@ target = DEVICE_NR(dev); - if (DEVICE_BUSY || USAGE > maxusage) { + if (DEVICE_BUSY || (ALLOW_REVALIDATE == 0 && USAGE > maxusage)) { printk("Device busy for revalidation (usage=%d)\n", USAGE); return -EBUSY; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/sg.c linux.ac/drivers/scsi/sg.c --- linux.vanilla/drivers/scsi/sg.c Mon Jan 15 21:08:15 2001 +++ linux.ac/drivers/scsi/sg.c Tue Apr 3 17:55:04 2001 @@ -19,7 +19,7 @@ */ #include <linux/config.h> #ifdef CONFIG_PROC_FS - static char * sg_version_str = "Version: 3.1.17 (20001002)"; + static char * sg_version_str = "Version: 3.1.17 (20010116)"; #endif static int sg_version_num = 30117; /* 2 digits for each component */ /* @@ -663,8 +663,10 @@ SRpnt->sr_sense_buffer[0] = 0; SRpnt->sr_cmd_len = hp->cmd_len; /* Set the LUN field in the command structure, overriding user input */ - if (! (hp->flags & SG_FLAG_LUN_INHIBIT)) - cmnd[1] = (cmnd[1] & 0x1f) | (sdp->device->lun << 5); + if (! (hp->flags & SG_FLAG_LUN_INHIBIT)) { + if (sdp->device->scsi_level <= SCSI_2) + cmnd[1] = (cmnd[1] & 0x1f) | (sdp->device->lun << 5); + } /* SCSI_LOG_TIMEOUT(7, printk("sg_write: do cmd\n")); */ SRpnt->sr_use_sg = srp->data.k_use_sg; @@ -1110,19 +1112,6 @@ static int sg_detect(Scsi_Device * scsidp) { - switch (scsidp->type) { - case TYPE_DISK: - case TYPE_MOD: - case TYPE_ROM: - case TYPE_WORM: - case TYPE_TAPE: break; - default: - printk("Detected scsi generic sg%d at scsi%d," - " channel %d, id %d, lun %d, type %d\n", - sg_template.dev_noticed, - scsidp->host->host_no, scsidp->channel, - scsidp->id, scsidp->lun, scsidp->type); - } sg_template.dev_noticed++; return 1; } @@ -1241,6 +1230,18 @@ sg_template.nr_dev++; sg_dev_arr[k] = sdp; write_unlock_irqrestore(&sg_dev_arr_lock, iflags); + switch (scsidp->type) { + case TYPE_DISK: + case TYPE_MOD: + case TYPE_ROM: + case TYPE_WORM: + case TYPE_TAPE: break; + default: + printk("Attached scsi generic sg%d at scsi%d," + " channel %d, id %d, lun %d, type %d\n", + k, scsidp->host->host_no, scsidp->channel, + scsidp->id, scsidp->lun, scsidp->type); + } return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/sr.c linux.ac/drivers/scsi/sr.c --- linux.vanilla/drivers/scsi/sr.c Mon Feb 19 18:25:17 2001 +++ linux.ac/drivers/scsi/sr.c Tue Apr 3 17:55:04 2001 @@ -88,6 +88,7 @@ static int *sr_sizes; static int *sr_blocksizes; +static int *sr_hardsizes; static int sr_open(struct cdrom_device_info *, int); void get_sectorsize(int); @@ -343,12 +344,12 @@ static int sr_init_command(Scsi_Cmnd * SCpnt) { - int dev, devm, block, this_count, s_size; + int dev, devm, block=0, this_count, s_size; devm = MINOR(SCpnt->request.rq_dev); dev = DEVICE_NR(SCpnt->request.rq_dev); - SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %d\n", devm)); + SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %d, block = %d\n", devm, block)); if (dev >= sr_template.nr_dev || !scsi_CDs[dev].device || @@ -415,7 +416,8 @@ (SCpnt->request.cmd == WRITE) ? "writing" : "reading", this_count, SCpnt->request.nr_sectors)); - SCpnt->cmnd[1] = (SCpnt->lun << 5) & 0xe0; + SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ? + ((SCpnt->lun << 5) & 0xe0) : 0; if (this_count > 0xffff) this_count = 0xffff; @@ -508,11 +510,7 @@ if (SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 0; - - printk("Detected scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n", - sr_template.dev_noticed++, - SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); - + sr_template.dev_noticed++; return 1; } @@ -541,6 +539,9 @@ sr_template.nr_dev++; if (sr_template.nr_dev > sr_template.dev_max) panic("scsi_devices corrupt (sr)"); + + printk("Attached scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n", + i, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); return 0; } @@ -571,7 +572,8 @@ retries = 3; do { cmd[0] = READ_CAPACITY; - cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0; + cmd[1] = (scsi_CDs[i].device->scsi_level <= SCSI_2) ? + ((scsi_CDs[i].device->lun << 5) & 0xe0) : 0; memset((void *) &cmd[2], 0, 8); SRpnt->sr_request.rq_status = RQ_SCSI_BUSY; /* Mark as really busy */ SRpnt->sr_cmd_len = 0; @@ -600,7 +602,7 @@ } else { #if 0 if (cdrom_get_last_written(MKDEV(MAJOR_NR, i), - (long *) &scsi_CDs[i].capacity)) + &scsi_CDs[i].capacity)) #endif scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) | (buffer[1] << 16) | @@ -664,7 +666,8 @@ buffer = (unsigned char *) scsi_malloc(512); cmd[0] = MODE_SENSE; - cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0; + cmd[1] = (scsi_CDs[i].device->scsi_level <= SCSI_2) ? + ((scsi_CDs[i].device->lun << 5) & 0xe0) : 0; cmd[2] = 0x2a; cmd[4] = 128; cmd[3] = cmd[5] = 0; @@ -741,7 +744,8 @@ Scsi_Device *device = scsi_CDs[MINOR(cdi->dev)].device; /* set the LUN */ - cgc->cmd[1] |= device->lun << 5; + if (device->scsi_level <= SCSI_2) + cgc->cmd[1] |= device->lun << 5; cgc->stat = sr_do_ioctl(MINOR(cdi->dev), cgc->cmd, cgc->buffer, cgc->buflen, cgc->quiet, cgc->data_direction, cgc->sense); @@ -782,16 +786,21 @@ if (!sr_blocksizes) goto cleanup_sizes; + sr_hardsizes = kmalloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC); + if (!sr_hardsizes) + goto cleanup_blocksizes; /* * These are good guesses for the time being. - * Don't set sr_hardsizes here! That will prevent reading anything smaller. */ for (i = 0; i < sr_template.dev_max; i++) { sr_blocksizes[i] = 2048; + sr_hardsizes[i] = 2048; } blksize_size[MAJOR_NR] = sr_blocksizes; + hardsect_size[MAJOR_NR] = sr_hardsizes; return 0; - +cleanup_blocksizes: + kfree(sr_blocksizes); cleanup_sizes: kfree(sr_sizes); cleanup_cds: @@ -915,8 +924,11 @@ kfree(sr_blocksizes); sr_blocksizes = NULL; + kfree(sr_hardsizes); + sr_hardsizes = NULL; } blksize_size[MAJOR_NR] = NULL; + hardsect_size[MAJOR_NR] = NULL; blk_size[MAJOR_NR] = NULL; read_ahead[MAJOR_NR] = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/sr_ioctl.c linux.ac/drivers/scsi/sr_ioctl.c --- linux.vanilla/drivers/scsi/sr_ioctl.c Fri Dec 29 22:07:22 2000 +++ linux.ac/drivers/scsi/sr_ioctl.c Tue Apr 3 17:55:04 2001 @@ -191,7 +191,8 @@ u_char sr_cmd[10]; sr_cmd[0] = GPCMD_TEST_UNIT_READY; - sr_cmd[1] = ((scsi_CDs[minor].device->lun) << 5); + sr_cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ? + ((scsi_CDs[minor].device->lun) << 5) : 0; sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; return sr_do_ioctl(minor, sr_cmd, NULL, 0, 1, SCSI_DATA_NONE, NULL); } @@ -201,7 +202,8 @@ u_char sr_cmd[10]; sr_cmd[0] = GPCMD_START_STOP_UNIT; - sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5); + sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ? + ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0; sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ; @@ -273,7 +275,8 @@ int result; sr_cmd[0] = GPCMD_READ_SUBCHANNEL; - sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5); + sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ? + ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0; sr_cmd[2] = 0x40; /* I do want the subchannel info */ sr_cmd[3] = 0x02; /* Give me medium catalog number info */ sr_cmd[4] = sr_cmd[5] = 0; @@ -307,7 +310,8 @@ memset(sr_cmd, 0, MAX_COMMAND_SIZE); sr_cmd[0] = GPCMD_SET_SPEED; /* SET CD SPEED */ - sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->lun) << 5; + sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ? + ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0; sr_cmd[2] = (speed >> 8) & 0xff; /* MSB for speed (in kbytes/sec) */ sr_cmd[3] = speed & 0xff; /* LSB */ @@ -336,7 +340,8 @@ struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg; sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP; - sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5); + sr_cmd[1] = (scsi_CDs[target].device->scsi_level <= SCSI_2) ? + ((scsi_CDs[target].device->lun) << 5) : 0; sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; sr_cmd[8] = 12; /* LSB of length */ @@ -353,8 +358,9 @@ struct cdrom_tocentry *tocentry = (struct cdrom_tocentry *) arg; sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP; - sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | - (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0); + sr_cmd[1] = (scsi_CDs[target].device->scsi_level <= SCSI_2) ? + ((scsi_CDs[target].device->lun) << 5) : 0; + sr_cmd[1] |= (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0; sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; sr_cmd[6] = tocentry->cdte_track; sr_cmd[8] = 12; /* LSB of length */ @@ -379,7 +385,8 @@ struct cdrom_ti* ti = (struct cdrom_ti*)arg; sr_cmd[0] = GPCMD_PLAYAUDIO_TI; - sr_cmd[1] = scsi_CDs[target].device->lun << 5; + sr_cmd[1] = (scsi_CDs[target].device->scsi_level <= SCSI_2) ? + (scsi_CDs[target].device->lun << 5) : 0; sr_cmd[4] = ti->cdti_trk0; sr_cmd[5] = ti->cdti_ind0; sr_cmd[7] = ti->cdti_trk1; @@ -429,7 +436,9 @@ memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = GPCMD_READ_CD; /* READ_CD */ - cmd[1] = (scsi_CDs[minor].device->lun << 5) | ((format & 7) << 2); + cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ? + (scsi_CDs[minor].device->lun << 5) : 0; + cmd[1] |= ((format & 7) << 2); cmd[2] = (unsigned char) (lba >> 24) & 0xff; cmd[3] = (unsigned char) (lba >> 16) & 0xff; cmd[4] = (unsigned char) (lba >> 8) & 0xff; @@ -481,7 +490,8 @@ memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = GPCMD_READ_10; - cmd[1] = (scsi_CDs[minor].device->lun << 5); + cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ? + (scsi_CDs[minor].device->lun << 5) : 0; cmd[2] = (unsigned char) (lba >> 24) & 0xff; cmd[3] = (unsigned char) (lba >> 16) & 0xff; cmd[4] = (unsigned char) (lba >> 8) & 0xff; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/sr_vendor.c linux.ac/drivers/scsi/sr_vendor.c --- linux.vanilla/drivers/scsi/sr_vendor.c Fri Dec 29 22:07:22 2000 +++ linux.ac/drivers/scsi/sr_vendor.c Tue Apr 3 17:55:04 2001 @@ -124,7 +124,9 @@ #endif memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = MODE_SELECT; - cmd[1] = (scsi_CDs[minor].device->lun << 5) | (1 << 4); + cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ? + (scsi_CDs[minor].device->lun << 5) : 0; + cmd[1] |= (1 << 4); cmd[4] = 12; modesel = (struct ccs_modesel_head *) buffer; memset(modesel, 0, sizeof(*modesel)); @@ -173,7 +175,8 @@ case VENDOR_SCSI3: memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = READ_TOC; - cmd[1] = (scsi_CDs[minor].device->lun << 5); + cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ? + (scsi_CDs[minor].device->lun << 5) : 0; cmd[8] = 12; cmd[9] = 0x40; rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL); @@ -198,7 +201,9 @@ unsigned long min, sec, frame; memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = 0xde; - cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03; + cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ? + (scsi_CDs[minor].device->lun << 5) : 0; + cmd[1] |= 0x03; cmd[2] = 0xb0; rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1, SCSI_DATA_READ, NULL); if (rc != 0) @@ -223,7 +228,9 @@ * where starts the last session ?) */ memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = 0xc7; - cmd[1] = (scsi_CDs[minor].device->lun << 5) | 3; + cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ? + (scsi_CDs[minor].device->lun << 5) : 0; + cmd[1] |= 0x03; rc = sr_do_ioctl(minor, cmd, buffer, 4, 1, SCSI_DATA_READ, NULL); if (rc == -EINVAL) { printk(KERN_INFO "sr%d: Hmm, seems the drive " @@ -246,7 +253,8 @@ case VENDOR_WRITER: memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = READ_TOC; - cmd[1] = (scsi_CDs[minor].device->lun << 5); + cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ? + (scsi_CDs[minor].device->lun << 5) : 0; cmd[8] = 0x04; cmd[9] = 0x40; rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1, SCSI_DATA_READ, NULL); @@ -259,7 +267,8 @@ break; } cmd[0] = READ_TOC; /* Read TOC */ - cmd[1] = (scsi_CDs[minor].device->lun << 5); + cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ? + (scsi_CDs[minor].device->lun << 5) : 0; cmd[6] = rc & 0x7f; /* number of last session */ cmd[8] = 0x0c; cmd[9] = 0x40; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/st.c linux.ac/drivers/scsi/st.c --- linux.vanilla/drivers/scsi/st.c Sat Dec 30 19:23:14 2000 +++ linux.ac/drivers/scsi/st.c Tue Apr 3 17:55:04 2001 @@ -359,7 +359,8 @@ } } - cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0; + if (SRpnt->sr_device->scsi_level <= SCSI_2) + cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0; init_MUTEX_LOCKED(&STp->sem); SRpnt->sr_use_sg = (bytes > (STp->buffer)->sg[0].length) ? (STp->buffer)->use_sg : 0; @@ -3495,7 +3496,7 @@ Scsi_Tape *tpnt; ST_mode *STm; ST_partstat *STps; - int i, mode, target_nbr; + int i, mode, target_nbr, dev_num; unsigned long flags = 0; char *stp; @@ -3573,6 +3574,7 @@ } memset(tpnt, 0, sizeof(Scsi_Tape)); scsi_tapes[i] = tpnt; + dev_num = i; for (mode = 0; mode < ST_NBR_MODES; ++mode) { char name[8]; @@ -3653,6 +3655,9 @@ st_template.nr_dev++; write_unlock_irqrestore(&st_dev_arr_lock, flags); + printk(KERN_WARNING + "Attached scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n", + dev_num, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); /* See if we need to allocate more static buffers */ target_nbr = st_template.nr_dev; @@ -3673,12 +3678,7 @@ { if (SDp->type != TYPE_TAPE || st_incompatible(SDp)) return 0; - - printk(KERN_WARNING - "Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n", - st_template.dev_noticed++, - SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); - + st_template.dev_noticed++; return 1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/sym53c8xx.c linux.ac/drivers/scsi/sym53c8xx.c --- linux.vanilla/drivers/scsi/sym53c8xx.c Tue Apr 3 17:32:21 2001 +++ linux.ac/drivers/scsi/sym53c8xx.c Mon Apr 9 23:31:27 2001 @@ -85,7 +85,7 @@ /* ** Name and version of the driver */ -#define SCSI_NCR_DRIVER_NAME "sym53c8xx-1.7.3a-20010304" +#define SCSI_NCR_DRIVER_NAME "sym53c8xx-1.7.3b-20010407" #define SCSI_NCR_DEBUG_FLAGS (0) @@ -3781,7 +3781,7 @@ SIR_MSG_RECEIVED, }/*-------------------------< MSG_WEIRD_SEEN >------------------*/,{ - SCR_LOAD_REL (scratcha1, 4), /* DUMMY READ */ + SCR_LOAD_REL (scratcha, 4), /* DUMMY READ */ 0, SCR_INT, SIR_MSG_WEIRD, @@ -4729,7 +4729,7 @@ }; /* -** Print something which allows to retrieve the controler type, unit, +** Print something which allows to retrieve the controller type, unit, ** target, lun concerned by a kernel message. */ @@ -6590,7 +6590,7 @@ ** **---------------------------------------------------- */ -#if 0 /* This stuff was only usefull for linux-1.2.13 */ +#if 0 /* This stuff was only useful for linux-1.2.13 */ if (lp && !lp->numtags && cmd->device && cmd->device->tagged_queue) { lp->numtags = tp->usrtags; ncr_setup_tags (np, cp->target, cp->lun); @@ -6990,22 +6990,27 @@ u_char istat; int i; + if (!(np->features & FE_ISTAT1) || !(INB (nc_istat1) & SRUN)) + goto do_chip_reset; + OUTB (nc_istat, CABRT); - for (i = 1000000 ; i ; --i) { + for (i = 100000 ; i ; --i) { istat = INB (nc_istat); if (istat & SIP) { INW (nc_sist); continue; } if (istat & DIP) { - OUTB (nc_istat, 0); - INB (nc_dstat); - break; + if (INB (nc_dstat) & ABRT); + break; } + UDELAY(5); } + OUTB (nc_istat, 0); if (!i) - printk("%s: unable to abort current chip operation.\n", - ncr_name(np)); + printk("%s: unable to abort current chip operation, " + "ISTAT=0x%02x.\n", ncr_name(np), istat); +do_chip_reset: ncr_chip_reset(np); } @@ -7958,7 +7963,7 @@ */ fak = (kpc - 1) / div_10M[div] + 1; -#if 0 /* This optimization does not seem very usefull */ +#if 0 /* This optimization does not seem very useful */ per = (fak * div_10M[div]) / clk; @@ -8684,7 +8689,7 @@ ** scntl3: (see the manual) ** ** current script command: -** dsp: script adress (relative to start of script). +** dsp: script address (relative to start of script). ** dbc: first word of script command. ** ** First 24 register of the chip: @@ -10166,14 +10171,16 @@ if (i >= MAX_START*2) i = 0; } - assert(k != -1); - if (k != 1) { + /* + ** If job removed, repair the start queue. + */ + if (k != -1) { np->squeue[k] = np->squeue[i]; /* Idle task */ np->squeueput = k; /* Start queue pointer */ - cp->host_status = HS_ABORTED; - cp->scsi_status = S_ILLEGAL; - ncr_complete(np, cp); } + cp->host_status = HS_ABORTED; + cp->scsi_status = S_ILLEGAL; + ncr_complete(np, cp); } break; /* @@ -10729,7 +10736,7 @@ ** Was Sie schon immer ueber transfermode negotiation wissen wollten ... ** ** We try to negotiate sync and wide transfer only after -** a successfull inquire command. We look at byte 7 of the +** a successful inquire command. We look at byte 7 of the ** inquire data to determine the capabilities of the target. ** ** When we try to negotiate, we append the negotiation message @@ -11569,7 +11576,7 @@ /*========================================================== ** ** -** Aquire a control block +** Acquire a control block ** ** **========================================================== @@ -14672,9 +14679,9 @@ */ #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) -static Scsi_Host_Template driver_template = SYM53C8XX; -#include "scsi_module.c" -#elif defined(MODULE) +static +#endif +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) || defined(MODULE) Scsi_Host_Template driver_template = SYM53C8XX; #include "scsi_module.c" #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/sym53c8xx_defs.h linux.ac/drivers/scsi/sym53c8xx_defs.h --- linux.vanilla/drivers/scsi/sym53c8xx_defs.h Tue Apr 3 17:32:22 2001 +++ linux.ac/drivers/scsi/sym53c8xx_defs.h Sat Apr 14 15:50:10 2001 @@ -734,7 +734,7 @@ #define FE_PFEN (1<<12) /* Prefetch enable */ #define FE_LDSTR (1<<13) /* Load/Store supported */ #define FE_RAM (1<<14) /* On chip RAM present */ -#define FE_VARCLK (1<<15) /* SCSI lock may vary */ +#define FE_VARCLK (1<<15) /* SCSI clock may vary */ #define FE_RAM8K (1<<16) /* On chip RAM sized 8Kb */ #define FE_64BIT (1<<17) /* Have a 64-bit PCI interface */ #define FE_IO256 (1<<18) /* Requires full 256 bytes in PCI space */ @@ -744,6 +744,7 @@ #define FE_ULTRA3 (1<<22) /* Ultra-3 80Mtrans/sec */ #define FE_66MHZ (1<<23) /* 66MHz PCI Support */ #define FE_DAC (1<<24) /* Support DAC cycles (64 bit addressing) */ +#define FE_ISTAT1 (1<<25) /* Have ISTAT1, MBOX0, MBOX1 registers */ #define FE_CACHE_SET (FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP) #define FE_SCSI_SET (FE_WIDE|FE_ULTRA|FE_ULTRA2|FE_DBLR|FE_QUAD|F_CLK80) @@ -808,7 +809,7 @@ , \ {PCI_DEVICE_ID_NCR_53C896, 0xff, "896", 6, 31, 7, \ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ - FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC} \ + FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_ISTAT1} \ , \ {PCI_DEVICE_ID_NCR_53C895A, 0xff, "895a", 6, 31, 7, \ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ @@ -823,11 +824,11 @@ FE_RAM|FE_IO256} \ , \ {PCI_DEVICE_ID_LSI_53C1010, 0xff, "1010-33", 6, 62, 7, \ - FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ + FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_ISTAT1| \ FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_ULTRA3} \ , \ {PCI_DEVICE_ID_LSI_53C1010_66, 0xff, "1010-66", 6, 62, 7, \ - FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ + FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_ISTAT1| \ FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_ULTRA3| \ FE_66MHZ} \ } @@ -1179,9 +1180,13 @@ #define SIP 0x02 /* sta: scsi-interrupt */ #define DIP 0x01 /* sta: host/script interrupt */ -/*15*/ u_char nc_istat1; /* 896 only */ -/*16*/ u_char nc_mbox0; /* 896 only */ -/*17*/ u_char nc_mbox1; /* 896 only */ +/*15*/ u_char nc_istat1; /* 896 and later cores only */ + #define FLSH 0x04 /* sta: chip is flushing */ + #define SRUN 0x02 /* sta: scripts are running */ + #define SIRQD 0x01 /* r/w: disable INT pin */ + +/*16*/ u_char nc_mbox0; /* 896 and later cores only */ +/*17*/ u_char nc_mbox1; /* 896 and later cores only */ /*18*/ u_char nc_ctest0; /*19*/ u_char nc_ctest1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/tmscsim.c linux.ac/drivers/scsi/tmscsim.c --- linux.vanilla/drivers/scsi/tmscsim.c Sat Feb 17 00:06:17 2001 +++ linux.ac/drivers/scsi/tmscsim.c Thu Apr 12 12:04:14 2001 @@ -206,10 +206,7 @@ #define DCBDEBUG1(x) /* Includes */ -#ifdef MODULE -# include <linux/module.h> -#endif - +#include <linux/module.h> #include <asm/dma.h> #include <asm/io.h> #include <asm/system.h> @@ -663,16 +660,30 @@ * tmscsim: AdaptID, MaxSpeed (Index), DevMode (Bitmapped), AdaptMode (Bitmapped) */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13) -void __init dc390_setup (char *str) +int __init dc390_setup (char *str) { int ints[8]; int i, im; (void)get_options (str, ARRAY_SIZE(ints), ints); + im = ints[0]; + if (im > 6) + { + printk (KERN_NOTICE "DC390: ignore extra params!\n"); + im = 6; + }; + for (i = 0; i < im; i++) + tmscsim[i] = ints[i+1]; + /* dc390_checkparams (); */ + return 1; +}; +#ifndef MODULE +__setup("tmscsim=", dc390_setup); +#endif + #else void __init dc390_setup (char *str, int *ints) { int i, im; -#endif im = ints[0]; if (im > 6) { @@ -683,14 +694,10 @@ tmscsim[i] = ints[i+1]; /* dc390_checkparams (); */ }; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13) -#ifndef MODULE -__setup("tmscsim=", dc390_setup); -#endif #endif + static void __init dc390_EEpromOutDI( PDEVDECL, PUCHAR regval, UCHAR Carry ) { UCHAR bval; @@ -828,7 +835,7 @@ /* Queueing philosphy: * There are a couple of lists: * - Query: Contains the Scsi Commands not yet turned into SRBs (per ACB) - * (Note: For new EH, it is unecessary!) + * (Note: For new EH, it is unnecessary!) * - Waiting: Contains a list of SRBs not yet sent (per DCB) * - Free: List of free SRB slots * @@ -2852,7 +2859,7 @@ { int dev, spd, spd1; char *pos = buffer; - PSH shpnt; + PSH shpnt = 0; PACB pACB; PDCB pDCB; PSCSICMD pcmd; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/tmscsim.h linux.ac/drivers/scsi/tmscsim.h --- linux.vanilla/drivers/scsi/tmscsim.h Sun Dec 31 19:06:00 2000 +++ linux.ac/drivers/scsi/tmscsim.h Thu Apr 12 12:04:14 2001 @@ -10,15 +10,6 @@ #include <linux/types.h> #include <linux/config.h> -/* 2.0 compat */ -#if defined(__SMP__) && !defined(CONFIG_SMP) -# if LINUX_VERSION_CODE < KERNEL_VERSION (2,2,0) -# define CONFIG_SMP -# else -# error __SMP__ defined but not CONFIG_SMP -# endif -#endif - #define IRQ_NONE 255 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/wd7000.c linux.ac/drivers/scsi/wd7000.c --- linux.vanilla/drivers/scsi/wd7000.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/scsi/wd7000.c Thu Apr 12 12:04:14 2001 @@ -863,7 +863,7 @@ */ if (freescbs < needed) { busy = 0; - panic ("wd7000: can't get enough free SCBs.\n"); + printk (KERN_ERR "wd7000: can't get enough free SCBs.\n"); restore_flags (flags); return (NULL); } @@ -1593,7 +1593,7 @@ printk ("wd7000_detect: check IO 0x%x region...\n", iobase); #endif - if (!check_region (iobase, 4)) { + if (request_region (iobase, 4, "wd7000")) { #ifdef WD7000_DEBUG printk ("wd7000_detect: ASC reset (IO 0x%x) ...", iobase); @@ -1609,12 +1609,12 @@ #ifdef WD7000_DEBUG { printk ("failed!\n"); - continue; + goto err_release; } - else + else printk ("ok!\n"); #else - continue; + goto err_release; #endif if (inb (iobase + ASC_INTR_STAT) == 1) { @@ -1627,7 +1627,8 @@ */ sh = scsi_register (tpnt, sizeof (Adapter)); if(sh==NULL) - continue; + goto err_release; + host = (Adapter *) sh->hostdata; #ifdef WD7000_DEBUG @@ -1650,11 +1651,8 @@ host->iobase, host->irq, host->dma); #endif - if (!wd7000_init (host)) { /* Initialization failed */ - scsi_unregister (sh); - - continue; - } + if (!wd7000_init (host)) /* Initialization failed */ + goto err_unregister; /* * OK from here - we'll use this adapter/configuration. @@ -1662,11 +1660,6 @@ wd7000_revision (host); /* important for scatter/gather */ /* - * Register our ports. - */ - request_region (host->iobase, 4, "wd7000"); - - /* * For boards before rev 6.0, scatter/gather isn't supported. */ if (host->rev1 < 6) @@ -1690,6 +1683,13 @@ else printk ("wd7000_detect: IO 0x%x region already allocated!\n", iobase); #endif + + continue; + + err_unregister: + scsi_unregister (sh); + err_release: + release_region(iobase, 4); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sgi/Makefile linux.ac/drivers/sgi/Makefile --- linux.vanilla/drivers/sgi/Makefile Sun Aug 6 19:23:40 2000 +++ linux.ac/drivers/sgi/Makefile Tue Apr 3 17:55:04 2001 @@ -7,17 +7,13 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -SUB_DIRS := -MOD_SUB_DIRS := $(SUB_DIRS) char -ALL_SUB_DIRS := $(SUB_DIRS) char - - -L_OBJS := L_TARGET := sgi.a +# # Character and Audio devices for SGI machines. # -SUB_DIRS += char -L_OBJS += char/sgichar.o +subdir-y += char +subdir-m += char +obj-y += char/sgichar.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sgi/char/Makefile linux.ac/drivers/sgi/char/Makefile --- linux.vanilla/drivers/sgi/char/Makefile Sat Jun 26 01:39:34 1999 +++ linux.ac/drivers/sgi/char/Makefile Tue Apr 3 17:55:04 2001 @@ -8,25 +8,12 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := sgichar.o -OX_OBJS := newport.o -O_OBJS := sgicons.o \ - usema.o shmiq.o streamable.o -ifeq ($(CONFIG_SGI_SERIAL),y) - O_OBJS += sgiserial.o -endif +export-objs := newport.o shmiq.o sgicons.o usema.o +obj-y := newport.o shmiq.o sgicons.o usema.o streamable.o -ifeq ($(CONFIG_SGI_DS1286),y) - O_OBJS += ds1286.o -endif - -ifeq ($(CONFIG_SGI_NEWPORT_GFX),y) - O_OBJS += graphics.o rrm.o -else -ifeq ($(CONFIG_SGI_NEWPORT_GFX),m) - OX_OBJS += graphics_syms.o - MX_OBJS += graphics.o rrm.o -endif -endif +obj-$(CONFIG_SGI_SERIAL) += sgiserial.o +obj-$(CONFIG_SGI_DS1286) += ds1286.o +obj-$(CONFIG_SGI_NEWPORT_GFX) += graphics.o rrm.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/724hwmcode.h linux.ac/drivers/sound/724hwmcode.h --- linux.vanilla/drivers/sound/724hwmcode.h Sun Nov 12 02:33:13 2000 +++ linux.ac/drivers/sound/724hwmcode.h Tue Apr 3 17:55:04 2001 @@ -9,7 +9,7 @@ #ifndef _HWMCODE_ #define _HWMCODE_ -static unsigned long int DspInst[] __initdata = { +static unsigned long int DspInst[] = { 0x00000081, 0x000001a4, 0x0000000a, 0x0000002f, 0x00080253, 0x01800317, 0x0000407b, 0x0000843f, 0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c, @@ -20,7 +20,7 @@ 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; -static unsigned long int CntrlInst[] __initdata = { +static unsigned long int CntrlInst[] = { 0x000007, 0x240007, 0x0C0007, 0x1C0007, 0x060007, 0x700002, 0x000020, 0x030040, 0x007104, 0x004286, 0x030040, 0x000F0D, @@ -799,7 +799,7 @@ // 04/09?@creat // 04/12 stop nise fix // 06/21?@WorkingOff timming -static unsigned long int CntrlInst1E[] __initdata = { +static unsigned long int CntrlInst1E[] = { 0x000007, 0x240007, 0x0C0007, 0x1C0007, 0x060007, 0x700002, 0x000020, 0x030040, 0x007104, 0x004286, 0x030040, 0x000F0D, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/Config.in linux.ac/drivers/sound/Config.in --- linux.vanilla/drivers/sound/Config.in Tue Apr 3 17:32:22 2001 +++ linux.ac/drivers/sound/Config.in Sun Apr 15 23:10:22 2001 @@ -14,11 +14,11 @@ bool ' Separate rear out jack' CONFIG_SOUND_CMPCI_REAR fi fi -dep_tristate ' Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND +dep_tristate ' Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND $CONFIG_PCI dep_tristate ' Crystal SoundFusion (CS4280/461x)' CONFIG_SOUND_FUSION $CONFIG_SOUND dep_tristate ' Crystal Sound CS4281' CONFIG_SOUND_CS4281 $CONFIG_SOUND -dep_tristate ' Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND -dep_tristate ' Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND +dep_tristate ' Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND $CONFIG_PCI +dep_tristate ' Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND $CONFIG_PCI dep_tristate ' ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND dep_tristate ' ESS Maestro, Maestro2, Maestro2E driver' CONFIG_SOUND_MAESTRO $CONFIG_SOUND dep_tristate ' ESS Maestro3/Allegro driver (EXPERIMENTAL)' CONFIG_SOUND_MAESTRO3 $CONFIG_SOUND $CONFIG_PCI $CONFIG_EXPERIMENTAL @@ -93,7 +93,7 @@ fi dep_tristate ' Aztech Sound Galaxy (non-PnP) cards' CONFIG_SOUND_SGALAXY $CONFIG_SOUND_OSS dep_tristate ' Adlib Cards' CONFIG_SOUND_ADLIB $CONFIG_SOUND_OSS - dep_tristate ' ACI mixer (miroPCM12)' CONFIG_SOUND_ACI_MIXER $CONFIG_SOUND_OSS + dep_tristate ' ACI mixer (miroSOUND PCM1-pro/PCM12/PCM20)' CONFIG_SOUND_ACI_MIXER $CONFIG_SOUND_OSS dep_tristate ' Crystal CS4232 based (PnP) cards' CONFIG_SOUND_CS4232 $CONFIG_SOUND_OSS dep_tristate ' Ensoniq SoundScape support' CONFIG_SOUND_SSCAPE $CONFIG_SOUND_OSS dep_tristate ' Gravis Ultrasound support' CONFIG_SOUND_GUS $CONFIG_SOUND_OSS @@ -171,8 +171,10 @@ fi if [ "$CONFIG_ARM" = "y" ]; then - dep_tristate ' VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS - dep_tristate ' Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS + if [ "$CONFIG_ARCH_ACORN" = "y" -o "$CONFIG_ARCH_CLPS7500" = "y" ]; then + dep_tristate ' VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS + fi + dep_tristate ' Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS $CONFIG_ARCH_NETWINDER fi fi diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/Makefile linux.ac/drivers/sound/Makefile --- linux.vanilla/drivers/sound/Makefile Sun Feb 4 18:05:29 2001 +++ linux.ac/drivers/sound/Makefile Tue Apr 3 17:55:04 2001 @@ -10,7 +10,7 @@ export-objs := ad1848.o audio_syms.o midi_syms.o mpu401.o \ msnd.o opl3.o sb_common.o sequencer_syms.o \ sound_core.o sound_syms.o uart401.o \ - nm256_audio.o ac97.o ac97_codec.o + nm256_audio.o ac97.o ac97_codec.o aci.o # Each configuration option enables a list of files. @@ -29,7 +29,7 @@ obj-$(CONFIG_SOUND_CS4232) += cs4232.o uart401.o obj-$(CONFIG_SOUND_OPL3SA2) += opl3sa2.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_MSS) += ad1848.o -obj-$(CONFIG_SOUND_PAS) += pas2.o sb_lib.o uart401.o +obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o sb_lib.o uart401.o obj-$(CONFIG_SOUND_SB) += sb.o sb_lib.o uart401.o obj-$(CONFIG_SOUND_WAVEFRONT) += wavefront.o obj-$(CONFIG_SOUND_MAUI) += maui.o mpu401.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/ac97.c linux.ac/drivers/sound/ac97.c --- linux.vanilla/drivers/sound/ac97.c Thu Jan 6 23:01:56 2000 +++ linux.ac/drivers/sound/ac97.c Tue Apr 3 17:55:04 2001 @@ -407,19 +407,19 @@ /* Read or write request. */ ret = -EINVAL; if (_IOC_TYPE (cmd) == 'M') { - int dir = _IOC_DIR (cmd); + int dir = _SIOC_DIR (cmd); int channel = _IOC_NR (cmd); if (channel >= 0 && channel < SOUND_MIXER_NRDEVICES) { ret = 0; - if (dir & _IOC_WRITE) { + if (dir & _SIOC_WRITE) { int val; if (get_user (val, (int *) arg) == 0) ret = ac97_set_mixer (dev, channel, val); else ret = -EFAULT; } - if (ret >= 0 && (dir & _IOC_READ)) { + if (ret >= 0 && (dir & _SIOC_READ)) { if (dev->last_written_OSS_values[channel] == AC97_REGVAL_UNKNOWN) dev->last_written_OSS_values[channel] diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/ac97_codec.c linux.ac/drivers/sound/ac97_codec.c --- linux.vanilla/drivers/sound/ac97_codec.c Thu Dec 7 08:21:37 2000 +++ linux.ac/drivers/sound/ac97_codec.c Tue Apr 10 18:17:07 2001 @@ -20,6 +20,16 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ************************************************************************** + * + * The Intel Audio Codec '97 specification is available at the Intel + * audio homepage: http://developer.intel.com/ial/scalableplatforms/audio/ + * + * The specification itself is currently available at: + * ftp://download.intel.com/ial/scalableplatforms/ac97r22.pdf + * + ************************************************************************** + * * History * v0.4 Mar 15 2000 Ollie Lho * dual codecs support verified with 4 channels output @@ -49,41 +59,61 @@ static int ac97_init_mixer(struct ac97_codec *codec); -static int sigmatel_init(struct ac97_codec *codec); +static int wolfson_init(struct ac97_codec * codec); +static int tritech_init(struct ac97_codec * codec); +static int tritech_maestro_init(struct ac97_codec * codec); +static int sigmatel_9708_init(struct ac97_codec *codec); +static int sigmatel_9721_init(struct ac97_codec *codec); +static int sigmatel_9744_init(struct ac97_codec *codec); static int enable_eapd(struct ac97_codec *codec); -#define arraysize(x) (sizeof(x)/sizeof((x)[0])) - -static struct { - unsigned int id; +/* sorted by vendor/device id */ +static const struct { + u32 id; char *name; int (*init) (struct ac97_codec *codec); } ac97_codec_ids[] = { - {0x414B4D00, "Asahi Kasei AK4540 rev 0", NULL}, - {0x414B4D01, "Asahi Kasei AK4540 rev 1", NULL}, - {0x41445340, "Analog Devices AD1881" , NULL}, - {0x41445360, "Analog Devices AD1885" , enable_eapd}, - {0x43525900, "Cirrus Logic CS4297" , NULL}, - {0x43525903, "Cirrus Logic CS4297" , NULL}, - {0x43525913, "Cirrus Logic CS4297A" , NULL}, - {0x43525923, "Cirrus Logic CS4298" , NULL}, - {0x4352592B, "Cirrus Logic CS4294" , NULL}, - {0x43525931, "Cirrus Logic CS4299" , NULL}, - {0x43525934, "Cirrus Logic CS4299" , NULL}, - {0x4e534331, "National Semiconductor LM4549" , NULL}, - {0x53494c22, "Silicon Laboratory Si3036" , NULL}, - {0x53494c23, "Silicon Laboratory Si3038" , NULL}, - {0x83847600, "SigmaTel STAC????" , NULL}, + {0x41445303, "Analog Devices AD1819", NULL}, + {0x41445340, "Analog Devices AD1881", NULL}, + {0x41445348, "Analog Devices AD1881A", NULL}, + {0x41445460, "Analog Devices AD1885", enable_eapd}, + {0x414B4D00, "Asahi Kasei AK4540", NULL}, + {0x414B4D01, "Asahi Kasei AK4542", NULL}, + {0x414B4D02, "Asahi Kasei AK4543", NULL}, + {0x414C4710, "ALC200/200P", NULL}, + {0x43525900, "Cirrus Logic CS4297", enable_eapd}, + {0x43525903, "Cirrus Logic CS4297", enable_eapd}, + {0x43525913, "Cirrus Logic CS4297A rev A", enable_eapd}, + {0x43525914, "Cirrus Logic CS4297A rev B", NULL}, + {0x43525923, "Cirrus Logic CS4298", NULL}, + {0x4352592B, "Cirrus Logic CS4294", NULL}, + {0x4352592D, "Cirrus Logic CS4294", NULL}, + {0x43525931, "Cirrus Logic CS4299 rev A", NULL}, + {0x43525933, "Cirrus Logic CS4299 rev C", NULL}, + {0x43525934, "Cirrus Logic CS4299 rev D", NULL}, + {0x45838308, "ESS Allegro ES1988", NULL}, + {0x49434511, "ICE1232", NULL}, /* I hope --jk */ + {0x4e534331, "National Semiconductor LM4549", NULL}, + {0x53494c22, "Silicon Laboratory Si3036", NULL}, + {0x53494c23, "Silicon Laboratory Si3038", NULL}, + {0x545200FF, "TriTech TR?????", tritech_maestro_init}, + {0x54524102, "TriTech TR28022", NULL}, + {0x54524103, "TriTech TR28023", NULL}, + {0x54524106, "TriTech TR28026", NULL}, + {0x54524108, "TriTech TR28028", tritech_init}, + {0x54524123, "TriTech TR?????", NULL}, + {0x574D4C00, "Wolfson WM9704", wolfson_init}, + {0x574D4C03, "Wolfson WM9703/9704", wolfson_init}, + {0x574D4C04, "Wolfson WM9704 (quad)", wolfson_init}, + {0x83847600, "SigmaTel STAC????", NULL}, {0x83847604, "SigmaTel STAC9701/3/4/5", NULL}, - {0x83847605, "SigmaTel STAC9704" , NULL}, - {0x83847608, "SigmaTel STAC9708" , NULL}, - {0x83847609, "SigmaTel STAC9721/23" , sigmatel_init}, - {0x54524103, "TriTech TR?????" , NULL}, - {0x54524106, "TriTech TR28026" , NULL}, - {0x54524108, "TriTech TR28028" , NULL}, - {0x54524123, "TriTech TR?????" , NULL}, - {0x574D4C00, "Wolfson WM9704" , NULL}, - {0x00000000, NULL, NULL} + {0x83847605, "SigmaTel STAC9704", NULL}, + {0x83847608, "SigmaTel STAC9708", sigmatel_9708_init}, + {0x83847609, "SigmaTel STAC9721/23", sigmatel_9721_init}, + {0x83847644, "SigmaTel STAC9744/45", sigmatel_9744_init}, + {0x83847656, "SigmaTel STAC9756/57", sigmatel_9744_init}, + {0x83847684, "SigmaTel STAC9783/84?", NULL}, + {0,} }; static const char *ac97_stereo_enhancements[] = @@ -175,10 +205,10 @@ AC97_REC_LINE, AC97_REC_STEREO, /* combination of all enabled outputs.. */ AC97_REC_MONO, /*.. or the mono equivalent */ - AC97_REC_PHONE + AC97_REC_PHONE }; -static unsigned int ac97_rm2oss[] = { +static const unsigned int ac97_rm2oss[] = { [AC97_REC_MIC] = SOUND_MIXER_MIC, [AC97_REC_CD] = SOUND_MIXER_CD, [AC97_REC_VIDEO] = SOUND_MIXER_VIDEO, @@ -189,7 +219,7 @@ }; /* indexed by bit position */ -static unsigned int ac97_oss_rm[] = { +static const unsigned int ac97_oss_rm[] = { [SOUND_MIXER_MIC] = AC97_REC_MIC, [SOUND_MIXER_CD] = AC97_REC_CD, [SOUND_MIXER_VIDEO] = AC97_REC_VIDEO, @@ -431,13 +461,13 @@ return 0; } - if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int)) + if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int)) return -EINVAL; if (cmd == OSS_GETVERSION) return put_user(SOUND_VERSION, (int *)arg); - if (_IOC_DIR(cmd) == _IOC_READ) { + if (_SIOC_DIR(cmd) == _SIOC_READ) { switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: /* give them the current record source */ if (!codec->recmask_io) { @@ -477,7 +507,7 @@ return put_user(val, (int *)arg); } - if (_IOC_DIR(cmd) == (_IOC_WRITE|_IOC_READ)) { + if (_SIOC_DIR(cmd) == (_SIOC_WRITE|_SIOC_READ)) { codec->modcnt++; if (get_user(val, (int *)arg)) return -EFAULT; @@ -640,7 +670,7 @@ id1 = codec->codec_read(codec, AC97_VENDOR_ID1); id2 = codec->codec_read(codec, AC97_VENDOR_ID2); - for (i = 0; i < arraysize(ac97_codec_ids); i++) { + for (i = 0; i < ARRAY_SIZE(ac97_codec_ids); i++) { if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) { codec->type = ac97_codec_ids[i].id; codec->name = ac97_codec_ids[i].name; @@ -691,7 +721,7 @@ codec->codec_init(codec); } - /* initilize mixer channel volumes */ + /* initialize mixer channel volumes */ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { struct mixer_defaults *md = &mixer_defaults[i]; if (md->mixer == -1) @@ -704,40 +734,151 @@ return 1; } -static int sigmatel_init(struct ac97_codec * codec) +#define AC97_SIGMATEL_ANALOG 0x6c /* Analog Special */ +#define AC97_SIGMATEL_DAC2INVERT 0x6e +#define AC97_SIGMATEL_BIAS1 0x70 +#define AC97_SIGMATEL_BIAS2 0x72 +#define AC97_SIGMATEL_MULTICHN 0x74 /* Multi-Channel programming */ +#define AC97_SIGMATEL_CIC1 0x76 +#define AC97_SIGMATEL_CIC2 0x78 + + +static int sigmatel_9708_init(struct ac97_codec * codec) +{ + u16 codec72, codec6c; + + codec72 = codec->codec_read(codec, AC97_SIGMATEL_BIAS2) & 0x8000; + codec6c = codec->codec_read(codec, AC97_SIGMATEL_ANALOG); + + if ((codec72==0) && (codec6c==0)) { + codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); + codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1000); + codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba); + codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0007); + } else if ((codec72==0x8000) && (codec6c==0)) { + codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); + codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1001); + codec->codec_write(codec, AC97_SIGMATEL_DAC2INVERT, 0x0008); + } else if ((codec72==0x8000) && (codec6c==0x0080)) { + /* nothing */ + } + codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000); + return 0; +} + + +static int sigmatel_9721_init(struct ac97_codec * codec) { /* Only set up secondary codec */ if (codec->id == 0) - return 1; + return 0; codec->codec_write(codec, AC97_SURROUND_MASTER, 0L); /* initialize SigmaTel STAC9721/23 as secondary codec, decoding AC link sloc 3,4 = 0x01, slot 7,8 = 0x00, */ - codec->codec_write(codec, 0x74, 0x00); + codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x00); /* we don't have the crystal when we are on an AMR card, so use BIT_CLK as our clock source. Write the magic word ABBA and read back to enable register 0x78 */ - codec->codec_write(codec, 0x76, 0xabba); - codec->codec_read(codec, 0x76); + codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); + codec->codec_read(codec, AC97_SIGMATEL_CIC1); /* sync all the clocks*/ - codec->codec_write(codec, 0x78, 0x3802); + codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x3802); - return 1; + return 0; +} + + +static int sigmatel_9744_init(struct ac97_codec * codec) +{ + // patch for SigmaTel + codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); + codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x0000); // is this correct? --jk + codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba); + codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0002); + codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000); + return 0; +} + + +static int wolfson_init(struct ac97_codec * codec) +{ + codec->codec_write(codec, 0x72, 0x0808); + codec->codec_write(codec, 0x74, 0x0808); + + // patch for DVD noise + codec->codec_write(codec, 0x5a, 0x0200); + + // init vol as PCM vol + codec->codec_write(codec, 0x70, + codec->codec_read(codec, AC97_PCMOUT_VOL)); + + codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000); + return 0; +} + + +static int tritech_init(struct ac97_codec * codec) +{ + codec->codec_write(codec, 0x26, 0x0300); + codec->codec_write(codec, 0x26, 0x0000); + codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000); + codec->codec_write(codec, AC97_RESERVED_3A, 0x0000); + return 0; +} + + +/* copied from drivers/sound/maestro.c */ +static int tritech_maestro_init(struct ac97_codec * codec) +{ + /* no idea what this does */ + codec->codec_write(codec, 0x2A, 0x0001); + codec->codec_write(codec, 0x2C, 0x0000); + codec->codec_write(codec, 0x2C, 0XFFFF); + return 0; } + /* - * Bring up an AD1885 + * External AMP management for EAPD using codecs + * (CS4279A, AD1885, ...) */ - + static int enable_eapd(struct ac97_codec * codec) { codec->codec_write(codec, AC97_POWER_CONTROL, codec->codec_read(codec, AC97_POWER_CONTROL)|0x8000); return 0; } + + +/* copied from drivers/sound/maestro.c */ +#if 0 /* there has been 1 person on the planet with a pt101 that we + know of. If they care, they can put this back in :) */ +static int pt101_init(struct ac97_codec * codec) +{ + printk(KERN_INFO "ac97_codec: PT101 Codec detected, initializing but _not_ installing mixer device.\n"); + /* who knows.. */ + codec->codec_write(codec, 0x2A, 0x0001); + codec->codec_write(codec, 0x2C, 0x0000); + codec->codec_write(codec, 0x2C, 0xFFFF); + codec->codec_write(codec, 0x10, 0x9F1F); + codec->codec_write(codec, 0x12, 0x0808); + codec->codec_write(codec, 0x14, 0x9F1F); + codec->codec_write(codec, 0x16, 0x9F1F); + codec->codec_write(codec, 0x18, 0x0404); + codec->codec_write(codec, 0x1A, 0x0000); + codec->codec_write(codec, 0x1C, 0x0000); + codec->codec_write(codec, 0x02, 0x0404); + codec->codec_write(codec, 0x04, 0x0808); + codec->codec_write(codec, 0x0C, 0x801F); + codec->codec_write(codec, 0x0E, 0x801F); + return 0; +} +#endif EXPORT_SYMBOL(ac97_read_proc); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/aci.c linux.ac/drivers/sound/aci.c --- linux.vanilla/drivers/sound/aci.c Sat Feb 17 00:02:36 2001 +++ linux.ac/drivers/sound/aci.c Tue Apr 3 17:55:04 2001 @@ -10,15 +10,17 @@ * The main function of the ACI is to control the mixer and to get a * product identification. On the PCM20, ACI also controls the radio * tuner on this card, this is supported in the Video for Linux - * radio-miropcm20 driver. - * - * This Voxware ACI driver currently only supports the ACI functions - * on the miroSOUND PCM12 and PCM20 card. Support for miro sound cards - * with additional ACI functions can easily be added later. - * - * / NOTE / When compiling as a module, make sure to load the module - * after loading the mad16 module. The initialisation code expects the - * MAD16 default mixer to be already available. + * miropcm20 driver. + * - + * This is a fullfeatured implementation. Unsupported features + * are bugs... (: + * + * It is not longer necessary to load the mad16 module first. The + * user is currently responsible to set the mad16 mixer correctly. + * + * To toggle the solo mode for full duplex operation just use the OSS + * record switch for the pcm ('wave') controller. Robert + * - * * Revision history: * @@ -34,72 +36,78 @@ * 1998-08-18 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl> * Small modification to export ACI functions and * complete modularisation. + * 2000-06-20 Robert Siemer <Robert.Siemer@gmx.de> + * Don't initialize the CS4231A mixer anymore, so the code is + * working again, and other small changes to fit in todays + * kernels. + * 2000-08-26 Robert Siemer + * Clean up and rewrite for 2.4.x. Maybe it's SMP safe now... (: + * ioctl bugfix, and integration of solo-mode into OSS-API, + * added (OSS-limited) equalizer support, return value bugfix, + * changed param aci_reset to reset, new params: ide, wss. */ -/* - * Some driver specific information and features: - * - * This mixer driver identifies itself to applications as "ACI" in - * mixer_info.id as retrieved by ioctl(fd, SOUND_MIXER_INFO, &mixer_info). - * - * Proprietary mixer features that go beyond the standard OSS mixer - * interface are: - * - * Full duplex solo configuration: - * - * int solo_mode; - * ioctl(fd, SOUND_MIXER_PRIVATE1, &solo_mode); - * - * solo_mode = 0: deactivate solo mode (default) - * solo_mode > 0: activate solo mode - * With activated solo mode, the PCM input can not any - * longer hear the signals produced by the PCM output. - * Activating solo mode is important in duplex mode in order - * to avoid feedback distortions. - * solo_mode < 0: do not change solo mode (just retrieve the status) - * - * When the ioctl() returns 0, solo_mode contains the previous - * status (0 = deactivated, 1 = activated). If solo mode is not - * implemented on this card, ioctl() returns -1 and sets errno to - * EINVAL. - * - */ - +#include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> - +#include <linux/proc_fs.h> +#include <linux/slab.h> +#include <asm/semaphore.h> +#include <asm/io.h> +#include <asm/uaccess.h> #include "sound_config.h" -#undef DEBUG /* if defined, produce a verbose report via syslog */ +int aci_port; /* as determined by bit 4 in the OPTi 929 MC4 register */ +int aci_idcode[2]; /* manufacturer and product ID */ +int aci_version; /* ACI firmware version */ + +EXPORT_SYMBOL(aci_port); +EXPORT_SYMBOL(aci_idcode); +EXPORT_SYMBOL(aci_version); -int aci_port = 0x354; /* as determined by bit 4 in the OPTi 929 MC4 register */ -unsigned char aci_idcode[2] = {0, 0}; /* manufacturer and product ID */ -unsigned char aci_version = 0; /* ACI firmware version */ -int aci_solo; /* status bit of the card that can't be * +#include "aci.h" + + +static int aci_solo=0; /* status bit of the card that can't be * + * checked with ACI versions prior to 0xb0 */ +static int aci_amp=0; /* status bit for power-amp/line-out level + but I have no docs about what is what... */ +static int aci_micpreamp=3; /* microphone preamp-level that can't be * * checked with ACI versions prior to 0xb0 */ -static int aci_present = 0; +static int mixer_device; +static struct semaphore aci_sem; -#ifdef MODULE /* Whether the aci mixer is to be reset. */ -int aci_reset = 0; /* Default: don't reset if the driver is a */ -MODULE_PARM(aci_reset,"i"); -#else /* module; use "insmod aci.o aci_reset=1" */ -int aci_reset = 1; /* to override. */ +#ifdef MODULE +static int reset = 0; +MODULE_PARM(reset,"i"); +MODULE_PARM_DESC(reset,"When set to 1, reset aci mixer."); +#else +static int reset = 1; #endif +static int ide=-1; +MODULE_PARM(ide,"i"); +MODULE_PARM_DESC(ide,"1 enable, 0 disable ide-port - untested" + " default: do nothing"); +static int wss=-1; +MODULE_PARM(wss,"i"); +MODULE_PARM_DESC(wss,"change between ACI/WSS-mixer; use 0 and 1 - untested" + " default: do nothing; for PCM1-pro only"); + +static void print_bits(unsigned char c) +{ + int j; + printk(KERN_DEBUG "aci: "); + + for (j=7; j>=0; j--) { + printk(KERN_DEBUG "%d", (c >> j) & 0x1); + } -#define COMMAND_REGISTER (aci_port) -#define STATUS_REGISTER (aci_port + 1) -#define BUSY_REGISTER (aci_port + 2) + printk(KERN_DEBUG "\n"); +} /* - * Wait until the ACI microcontroller has set the READYFLAG in the - * Busy/IRQ Source Register to 0. This is required to avoid - * overrunning the sound card microcontroller. We do a busy wait here, - * because the microcontroller is not supposed to signal a busy - * condition for more than a few clock cycles. In case of a time-out, - * this function returns -1. - * * This busy wait code normally requires less than 15 loops and * practically always less than 100 loops on my i486/DX2 66 MHz. * @@ -107,459 +115,476 @@ * function can take a VERY long time, because the PCM12 does some kind * of fade-in effect. For this reason, access to the MUTE function has * not been implemented at all. + * + * - The OSS interface has no mute option. It takes about 3 seconds to + * fade-in on my PCM20. busy_wait() handles it great now... Robert */ static int busy_wait(void) { + #define MINTIME 500 long timeout; + unsigned char byte; - for (timeout = 0; timeout < 10000000L; timeout++) - if ((inb_p(BUSY_REGISTER) & 1) == 0) - return 0; - -#ifdef DEBUG - printk("ACI: READYFLAG timed out.\n"); -#endif - - return -1; -} - - -/* - * Read the GENERAL STATUS register. - */ - -static int read_general_status(void) -{ - unsigned long flags; - int status; - - save_flags(flags); - cli(); - - if (busy_wait()) { - restore_flags(flags); - return -1; + for (timeout = 1; timeout <= MINTIME+30; timeout++) { + if (((byte=inb(BUSY_REGISTER)) & 1) == 0) { + if (timeout >= MINTIME) + printk(KERN_DEBUG "aci: Got READYFLAG in round %ld.\n", timeout-MINTIME); + return byte; + } + if (timeout >= MINTIME) { + long out=10*HZ; + switch (timeout-MINTIME) { + case 0 ... 9: + out /= 10; + case 10 ... 19: + out /= 10; + case 20 ... 30: + out /= 10; + default: + current->state=TASK_UNINTERRUPTIBLE; + schedule_timeout(out); + break; + } + } } - - status = (unsigned) inb_p(STATUS_REGISTER); - restore_flags(flags); - return status; + printk(KERN_WARNING "aci: busy_wait() time out.\n"); + return -EBUSY; } +/* The four ACI command types are fucked up. [-: + * implied is: 1w - special case for INIT + * write is: 2w1r + * read is: x(1w1r) where x is 1 or 2 (1 CHECK_SIG, 1 CHECK_STER, + * 1 VERSION, 2 IDCODE) + * the command is only in the first write, rest is protocol overhead + * + * indexed is technically a write and used for STATUS + * and the special case for TUNE is: 3w1r + * + * Here the new general sheme: TUNE --> aci_rw_cmd(x, y, z) + * indexed and write --> aci_rw_cmd(x, y, -1) + * implied and read (x=1) --> aci_rw_cmd(x, -1, -1) + * + * Read (x>=2) is not implemented (only used during initialization). + * Use aci_idcode[2] and aci_version... Robert + */ -/* - * The four ACI command types (implied, write, read and indexed) can - * be sent to the microcontroller using the following four functions. - * If a problem occurred, they return -1. +/* Some notes for error detection: theoretically it is possible. + * But it doubles the I/O-traffic from ww(r) to wwwrw(r) in the normal + * case and doesn't seem to be designed for that... Robert */ -int aci_implied_cmd(unsigned char opcode) +static inline int aci_rawwrite(unsigned char byte) { - unsigned long flags; - -#ifdef DEBUG - printk("ACI: aci_implied_cmd(0x%02x)\n", opcode); + if (busy_wait() >= 0) { +#if DEBUG + printk(KERN_DEBUG "aci_rawwrite(%d)\n", byte); #endif - - save_flags(flags); - cli(); - - if (read_general_status() < 0 || busy_wait()) { - restore_flags(flags); - return -1; - } - - outb_p(opcode, COMMAND_REGISTER); - - restore_flags(flags); - return 0; + outb(byte, COMMAND_REGISTER); + return 0; + } else + return -EBUSY; } - -int aci_write_cmd(unsigned char opcode, unsigned char parameter) +static inline int aci_rawread(void) { - unsigned long flags; - int status; + unsigned char byte; -#ifdef DEBUG - printk("ACI: aci_write_cmd(0x%02x, 0x%02x)\n", opcode, parameter); + if (busy_wait() >= 0) { + byte=inb(STATUS_REGISTER); +#if DEBUG + printk(KERN_DEBUG "%d = aci_rawread()\n", byte); #endif + return byte; + } else + return -EBUSY; +} - save_flags(flags); - cli(); - - if (read_general_status() < 0 || busy_wait()) { - restore_flags(flags); - return -1; - } - outb_p(opcode, COMMAND_REGISTER); - if (busy_wait()) { - restore_flags(flags); - return -1; - } +int aci_rw_cmd(int write1, int write2, int write3) +{ + int write[] = {write1, write2, write3}; + int read, i; - outb_p(parameter, COMMAND_REGISTER); + if (down_interruptible(&aci_sem)) + return -EINTR; - if ((status = read_general_status()) < 0) { - restore_flags(flags); - return -1; + for (i=0; i<3; i++) { + if (write[i]< 0 || write[i] > 255) + break; + else + if (aci_rawwrite(write[i])<0) { + up(&aci_sem); + return -EBUSY; + } } - - /* polarity of the INVALID flag depends on ACI version */ - if ((aci_version < 0xb0 && (status & 0x40) != 0) || - (aci_version >= 0xb0 && (status & 0x40) == 0)) { - restore_flags(flags); - printk("ACI: invalid write command 0x%02x, 0x%02x.\n", - opcode, parameter); - return -1; + + if ((read=aci_rawread())<0) { + up(&aci_sem); + return -EBUSY; } - restore_flags(flags); - return 0; + up(&aci_sem); + return read; } -/* - * This write command send 2 parameters instead of one. - * Only used in PCM20 radio frequency tuning control - */ +EXPORT_SYMBOL(aci_rw_cmd); -int aci_write_cmd_d(unsigned char opcode, unsigned char parameter, unsigned char parameter2) +static int setvolume(caddr_t arg, + unsigned char left_index, unsigned char right_index) { - unsigned long flags; - int status; + int vol, ret, uservol, buf; -#ifdef DEBUG - printk("ACI: aci_write_cmd_d(0x%02x, 0x%02x)\n", opcode, parameter, parameter2); -#endif - - save_flags(flags); - cli(); - - if (read_general_status() < 0 || busy_wait()) { - restore_flags(flags); - return -1; - } + __get_user(uservol, (int *)arg); - outb_p(opcode, COMMAND_REGISTER); - if (busy_wait()) { - restore_flags(flags); - return -1; - } + /* left channel */ + vol = uservol & 0xff; + if (vol > 100) + vol = 100; + vol = SCALE(100, 0x20, vol); + if ((buf=aci_write_cmd(left_index, 0x20 - vol))<0) + return buf; + ret = SCALE(0x20, 100, vol); - outb_p(parameter, COMMAND_REGISTER); - if (busy_wait()) { - restore_flags(flags); - return -1; - } - - outb_p(parameter2, COMMAND_REGISTER); - - if ((status = read_general_status()) < 0) { - restore_flags(flags); - return -1; - } - - /* polarity of the INVALID flag depends on ACI version */ - if ((aci_version < 0xb0 && (status & 0x40) != 0) || - (aci_version >= 0xb0 && (status & 0x40) == 0)) { - restore_flags(flags); -#if 0 /* Frequency tuning works, but the INVALID flag is set ??? */ - printk("ACI: invalid write (double) command 0x%02x, 0x%02x, 0x%02x.\n", - opcode, parameter, parameter2); -#endif - return -1; - } - - restore_flags(flags); - return 0; -} -int aci_read_cmd(unsigned char opcode, int length, unsigned char *parameter) -{ - unsigned long flags; - int i = 0; - - save_flags(flags); - cli(); + /* right channel */ + vol = (uservol >> 8) & 0xff; + if (vol > 100) + vol = 100; + vol = SCALE(100, 0x20, vol); + if ((buf=aci_write_cmd(right_index, 0x20 - vol))<0) + return buf; + ret |= SCALE(0x20, 100, vol) << 8; - if (read_general_status() < 0) { - restore_flags(flags); - return -1; - } - while (i < length) { - if (busy_wait()) { - restore_flags(flags); - return -1; - } - - outb_p(opcode, COMMAND_REGISTER); - if (busy_wait()) { - restore_flags(flags); - return -1; - } - - parameter[i++] = inb_p(STATUS_REGISTER); -#ifdef DEBUG - if (i == 1) - printk("ACI: aci_read_cmd(0x%02x, %d) = 0x%02x\n", - opcode, length, parameter[i-1]); - else - printk("ACI: aci_read_cmd cont.: 0x%02x\n", parameter[i-1]); -#endif - } + __put_user(ret, (int *)arg); - restore_flags(flags); return 0; } - -int aci_indexed_cmd(unsigned char opcode, unsigned char index, - unsigned char *parameter) +static int getvolume(caddr_t arg, + unsigned char left_index, unsigned char right_index) { - unsigned long flags; + int vol; + int buf; - save_flags(flags); - cli(); - - if (read_general_status() < 0 || busy_wait()) { - restore_flags(flags); - return -1; - } - - outb_p(opcode, COMMAND_REGISTER); - if (busy_wait()) { - restore_flags(flags); - return -1; - } - - outb_p(index, COMMAND_REGISTER); - if (busy_wait()) { - restore_flags(flags); - return -1; - } + /* left channel */ + if ((buf=aci_indexed_cmd(0xf0, left_index))<0) + return buf; + vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0); - *parameter = inb_p(STATUS_REGISTER); -#ifdef DEBUG - printk("ACI: aci_indexed_cmd(0x%02x, 0x%02x) = 0x%02x\n", opcode, index, - *parameter); -#endif + /* right channel */ + if ((buf=aci_indexed_cmd(0xf0, right_index))<0) + return buf; + vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8; + + __put_user(vol, (int *)arg); - restore_flags(flags); return 0; } -/* - * The following macro SCALE can be used to scale one integer volume - * value into another one using only integer arithmetic. If the input - * value x is in the range 0 <= x <= xmax, then the result will be in - * the range 0 <= SCALE(xmax,ymax,x) <= ymax. - * - * This macro has for all xmax, ymax > 0 and all 0 <= x <= xmax the - * following nice properties: - * - * - SCALE(xmax,ymax,xmax) = ymax - * - SCALE(xmax,ymax,0) = 0 - * - SCALE(xmax,ymax,SCALE(ymax,xmax,SCALE(xmax,ymax,x))) = SCALE(xmax,ymax,x) - * - * In addition, the rounding error is minimal and nicely distributed. - * The proofs are left as an exercise to the reader. +/* The equalizer is somewhat strange on the ACI. From -12dB to +12dB + * write: 0xff..down.to..0x80==0x00..up.to..0x7f */ -#define SCALE(xmax,ymax,x) (((x)*(ymax)+(xmax)/2)/(xmax)) +static inline unsigned int eq_oss2aci(unsigned int vol) +{ + int boost=0; + unsigned int ret; + + if (vol > 100) + vol = 100; + if (vol > 50) { + vol -= 51; + boost=1; + } + if (boost) + ret=SCALE(49, 0x7e, vol)+1; + else + ret=0xff - SCALE(50, 0x7f, vol); + return ret; +} + +static inline unsigned int eq_aci2oss(unsigned int vol) +{ + if (vol < 0x80) + return SCALE(0x7f, 50, vol) + 50; + else + return SCALE(0x7f, 50, 0xff-vol); +} -static int getvolume(caddr_t arg, - unsigned char left_index, unsigned char right_index) +static int setequalizer(caddr_t arg, + unsigned char left_index, unsigned char right_index) { - int vol; - unsigned char buf; + int buf; + unsigned int vol; + + __get_user(vol, (int *)arg); /* left channel */ - if (aci_indexed_cmd(0xf0, left_index, &buf)) - return -EIO; - vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0); - + if ((buf=aci_write_cmd(left_index, eq_oss2aci(vol & 0xff)))<0) + return buf; + /* right channel */ - if (aci_indexed_cmd(0xf0, right_index, &buf)) - return -EIO; - vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8; + if ((buf=aci_write_cmd(right_index, eq_oss2aci((vol>>8) & 0xff)))<0) + return buf; - return (*(int *) arg = vol); + /* the ACI equalizer is more precise */ + return 0; } - -static int setvolume(caddr_t arg, - unsigned char left_index, unsigned char right_index) +static int getequalizer(caddr_t arg, + unsigned char left_index, unsigned char right_index) { - int vol, ret; + int buf; + unsigned int vol; /* left channel */ - vol = *(int *)arg & 0xff; - if (vol > 100) - vol = 100; - vol = SCALE(100, 0x20, vol); - if (aci_write_cmd(left_index, 0x20 - vol)) - return -EIO; - ret = SCALE(0x20, 100, vol); + if ((buf=aci_indexed_cmd(0xf0, left_index))<0) + return buf; + vol = eq_aci2oss(buf); + + /* right channel */ + if ((buf=aci_indexed_cmd(0xf0, right_index))<0) + return buf; + vol |= eq_aci2oss(buf) << 8; + __put_user(vol, (int *)arg); - /* right channel */ - vol = (*(int *)arg >> 8) & 0xff; - if (vol > 100) - vol = 100; - vol = SCALE(100, 0x20, vol); - if (aci_write_cmd(right_index, 0x20 - vol)) - return -EIO; - ret |= SCALE(0x20, 100, vol) << 8; - - return (*(int *) arg = ret); + return 0; } - -static int -aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) +static int aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) { - int status, vol; - unsigned char buf; + int vol, buf; - /* handle solo mode control */ - if (cmd == SOUND_MIXER_PRIVATE1) { - if (*(int *) arg >= 0) { - aci_solo = !!*(int *) arg; - if (aci_write_cmd(0xd2, aci_solo)) - return -EIO; - } else if (aci_version >= 0xb0) { - if ((status = read_general_status()) < 0) - return -EIO; - return (*(int *) arg = (status & 0x20) == 0); + switch (cmd) { + case SOUND_MIXER_WRITE_VOLUME: + return setvolume(arg, 0x01, 0x00); + case SOUND_MIXER_WRITE_CD: + return setvolume(arg, 0x3c, 0x34); + case SOUND_MIXER_WRITE_MIC: + return setvolume(arg, 0x38, 0x30); + case SOUND_MIXER_WRITE_LINE: + return setvolume(arg, 0x39, 0x31); + case SOUND_MIXER_WRITE_SYNTH: + return setvolume(arg, 0x3b, 0x33); + case SOUND_MIXER_WRITE_PCM: + return setvolume(arg, 0x3a, 0x32); + case MIXER_WRITE(SOUND_MIXER_RADIO): /* fall through */ + case SOUND_MIXER_WRITE_LINE1: /* AUX1 or radio */ + return setvolume(arg, 0x3d, 0x35); + case SOUND_MIXER_WRITE_LINE2: /* AUX2 */ + return setvolume(arg, 0x3e, 0x36); + case SOUND_MIXER_WRITE_BASS: /* set band one and two */ + if (aci_idcode[1]=='C') { + if ((buf=setequalizer(arg, 0x48, 0x40)) || + (buf=setequalizer(arg, 0x49, 0x41))); + return buf; } - - return (*(int *) arg = aci_solo); - } - - if (((cmd >> 8) & 0xff) == 'M') { - if (cmd & SIOC_IN) - /* read and write */ - switch (cmd & 0xff) { - case SOUND_MIXER_VOLUME: - return setvolume(arg, 0x01, 0x00); - case SOUND_MIXER_CD: - return setvolume(arg, 0x3c, 0x34); - case SOUND_MIXER_MIC: - return setvolume(arg, 0x38, 0x30); - case SOUND_MIXER_LINE: - return setvolume(arg, 0x39, 0x31); - case SOUND_MIXER_SYNTH: - return setvolume(arg, 0x3b, 0x33); - case SOUND_MIXER_PCM: - return setvolume(arg, 0x3a, 0x32); - case SOUND_MIXER_LINE1: /* AUX1 */ - return setvolume(arg, 0x3d, 0x35); - case SOUND_MIXER_LINE2: /* AUX2 */ - return setvolume(arg, 0x3e, 0x36); - case SOUND_MIXER_IGAIN: /* MIC pre-amp */ - vol = *(int *) arg & 0xff; - if (vol > 100) - vol = 100; - vol = SCALE(100, 3, vol); - if (aci_write_cmd(0x03, vol)) - return -EIO; - vol = SCALE(3, 100, vol); - return (*(int *) arg = vol | (vol << 8)); - case SOUND_MIXER_RECSRC: - return (*(int *) arg = 0); - break; - default: - return -EINVAL; + break; + case SOUND_MIXER_WRITE_TREBLE: /* set band six and seven */ + if (aci_idcode[1]=='C') { + if ((buf=setequalizer(arg, 0x4d, 0x45)) || + (buf=setequalizer(arg, 0x4e, 0x46))); + return buf; + } + break; + case SOUND_MIXER_WRITE_IGAIN: /* MIC pre-amp */ + if (aci_idcode[1]=='B' || aci_idcode[1]=='C') { + __get_user(vol, (int *)arg); + vol = vol & 0xff; + if (vol > 100) + vol = 100; + vol = SCALE(100, 3, vol); + if ((buf=aci_write_cmd(0x03, vol))<0) + return buf; + aci_micpreamp = vol; + vol = SCALE(3, 100, vol); + vol |= (vol << 8); + __put_user(vol, (int *)arg); + return 0; + } + break; + case SOUND_MIXER_WRITE_OGAIN: /* Power-amp/line-out level */ + if (aci_idcode[1]=='A' || aci_idcode[1]=='B') { + __get_user(buf, (int *)arg); + buf = buf & 0xff; + if (buf > 50) + vol = 1; + else + vol = 0; + if ((buf=aci_write_cmd(0x0f, vol))<0) + return buf; + aci_amp = vol; + if (aci_amp) + buf = (100 || 100<<8); + else + buf = 0; + __put_user(buf, (int *)arg); + return 0; + } + break; + case SOUND_MIXER_WRITE_RECSRC: + /* handle solo mode control */ + __get_user(buf, (int *)arg); + /* unset solo when RECSRC for PCM is requested */ + if (aci_idcode[1]=='B' || aci_idcode[1]=='C') { + vol = !(buf & SOUND_MASK_PCM); + if ((buf=aci_write_cmd(0xd2, vol))<0) + return buf; + aci_solo = vol; + } + buf = (SOUND_MASK_CD| SOUND_MASK_MIC| SOUND_MASK_LINE| + SOUND_MASK_SYNTH| SOUND_MASK_LINE2); + if (aci_idcode[1] == 'C') /* PCM20 radio */ + buf |= SOUND_MASK_RADIO; + else + buf |= SOUND_MASK_LINE1; + if (!aci_solo) + buf |= SOUND_MASK_PCM; + __put_user(buf, (int *)arg); + return 0; + case SOUND_MIXER_READ_DEVMASK: + buf = (SOUND_MASK_VOLUME | SOUND_MASK_CD | + SOUND_MASK_MIC | SOUND_MASK_LINE | + SOUND_MASK_SYNTH | SOUND_MASK_PCM | + SOUND_MASK_LINE2); + switch (aci_idcode[1]) { + case 'C': /* PCM20 radio */ + buf |= (SOUND_MASK_RADIO | SOUND_MASK_IGAIN | + SOUND_MASK_BASS | SOUND_MASK_TREBLE); + break; + case 'B': /* PCM12 */ + buf |= (SOUND_MASK_LINE1 | SOUND_MASK_IGAIN | + SOUND_MASK_OGAIN); + break; + case 'A': /* PCM1-pro */ + buf |= (SOUND_MASK_LINE1 | SOUND_MASK_OGAIN); + break; + default: + buf |= SOUND_MASK_LINE1; + } + __put_user(buf, (int *)arg); + return 0; + case SOUND_MIXER_READ_STEREODEVS: + buf = (SOUND_MASK_VOLUME | SOUND_MASK_CD | + SOUND_MASK_MIC | SOUND_MASK_LINE | + SOUND_MASK_SYNTH | SOUND_MASK_PCM | + SOUND_MASK_LINE2); + switch (aci_idcode[1]) { + case 'C': /* PCM20 radio */ + buf |= (SOUND_MASK_RADIO | + SOUND_MASK_BASS | SOUND_MASK_TREBLE); + break; + default: + buf |= SOUND_MASK_LINE1; + } + __put_user(buf, (int *)arg); + return 0; + case SOUND_MIXER_READ_RECMASK: + buf = (SOUND_MASK_CD| SOUND_MASK_MIC| SOUND_MASK_LINE| + SOUND_MASK_SYNTH| SOUND_MASK_LINE2| SOUND_MASK_PCM); + if (aci_idcode[1] == 'C') /* PCM20 radio */ + buf |= SOUND_MASK_RADIO; + else + buf |= SOUND_MASK_LINE1; + + __put_user(buf, (int *)arg); + return 0; + case SOUND_MIXER_READ_RECSRC: + buf = (SOUND_MASK_CD | SOUND_MASK_MIC | SOUND_MASK_LINE | + SOUND_MASK_SYNTH | SOUND_MASK_LINE2); + /* do we need aci_solo or can I get it from the ACI? */ + switch (aci_idcode[1]) { + case 'B': /* PCM12 */ + case 'C': /* PCM20 radio */ + if (aci_version >= 0xb0) { + if ((vol=aci_rw_cmd(0xf0, 0x00, -1))<0) + return vol; + if (vol & 0x20) + buf |= SOUND_MASK_PCM; } + else + if (!aci_solo) + buf |= SOUND_MASK_PCM; + break; + default: + buf |= SOUND_MASK_PCM; + } + if (aci_idcode[1] == 'C') /* PCM20 radio */ + buf |= SOUND_MASK_RADIO; else - /* only read */ - switch (cmd & 0xff) { - case SOUND_MIXER_DEVMASK: - return (*(int *) arg = - SOUND_MASK_VOLUME | SOUND_MASK_CD | - SOUND_MASK_MIC | SOUND_MASK_LINE | - SOUND_MASK_SYNTH | SOUND_MASK_PCM | -#if 0 - SOUND_MASK_IGAIN | -#endif - SOUND_MASK_LINE1 | SOUND_MASK_LINE2); - break; - case SOUND_MIXER_STEREODEVS: - return (*(int *) arg = - SOUND_MASK_VOLUME | SOUND_MASK_CD | - SOUND_MASK_MIC | SOUND_MASK_LINE | - SOUND_MASK_SYNTH | SOUND_MASK_PCM | - SOUND_MASK_LINE1 | SOUND_MASK_LINE2); - break; - case SOUND_MIXER_RECMASK: - return (*(int *) arg = 0); - break; - case SOUND_MIXER_RECSRC: - return (*(int *) arg = 0); - break; - case SOUND_MIXER_CAPS: - return (*(int *) arg = 0); - break; - case SOUND_MIXER_VOLUME: - return getvolume(arg, 0x04, 0x03); - case SOUND_MIXER_CD: - return getvolume(arg, 0x0a, 0x09); - case SOUND_MIXER_MIC: - return getvolume(arg, 0x06, 0x05); - case SOUND_MIXER_LINE: - return getvolume(arg, 0x08, 0x07); - case SOUND_MIXER_SYNTH: - return getvolume(arg, 0x0c, 0x0b); - case SOUND_MIXER_PCM: - return getvolume(arg, 0x0e, 0x0d); - case SOUND_MIXER_LINE1: /* AUX1 */ - return getvolume(arg, 0x11, 0x10); - case SOUND_MIXER_LINE2: /* AUX2 */ - return getvolume(arg, 0x13, 0x12); - case SOUND_MIXER_IGAIN: /* MIC pre-amp */ - if (aci_indexed_cmd(0xf0, 0x21, &buf)) - return -EIO; - vol = SCALE(3, 100, buf <= 3 ? buf : 3); - vol |= vol << 8; - return (*(int *) arg = vol); - default: - return -EINVAL; + buf |= SOUND_MASK_LINE1; + + __put_user(buf, (int *)arg); + return 0; + case SOUND_MIXER_READ_CAPS: + __put_user(0, (int *)arg); + return 0; + case SOUND_MIXER_READ_VOLUME: + return getvolume(arg, 0x04, 0x03); + case SOUND_MIXER_READ_CD: + return getvolume(arg, 0x0a, 0x09); + case SOUND_MIXER_READ_MIC: + return getvolume(arg, 0x06, 0x05); + case SOUND_MIXER_READ_LINE: + return getvolume(arg, 0x08, 0x07); + case SOUND_MIXER_READ_SYNTH: + return getvolume(arg, 0x0c, 0x0b); + case SOUND_MIXER_READ_PCM: + return getvolume(arg, 0x0e, 0x0d); + case MIXER_READ(SOUND_MIXER_RADIO): /* fall through */ + case SOUND_MIXER_READ_LINE1: /* AUX1 */ + return getvolume(arg, 0x11, 0x10); + case SOUND_MIXER_READ_LINE2: /* AUX2 */ + return getvolume(arg, 0x13, 0x12); + case SOUND_MIXER_READ_BASS: /* get band one */ + if (aci_idcode[1]=='C') { + return getequalizer(arg, 0x23, 0x22); + } + break; + case SOUND_MIXER_READ_TREBLE: /* get band seven */ + if (aci_idcode[1]=='C') { + return getequalizer(arg, 0x2f, 0x2e); + } + break; + case SOUND_MIXER_READ_IGAIN: /* MIC pre-amp */ + if (aci_idcode[1]=='B' || aci_idcode[1]=='C') { + /* aci_micpreamp or ACI? */ + if (aci_version >= 0xb0) { + if ((buf=aci_indexed_cmd(0xf0, 0x21))<0) + return buf; } + else + buf=aci_micpreamp; + vol = SCALE(3, 100, buf <= 3 ? buf : 3); + vol |= vol << 8; + __put_user(vol, (int *)arg); + return 0; + } + break; + case SOUND_MIXER_READ_OGAIN: + if (aci_amp) + buf = (100 || 100<<8); + else + buf = 0; + __put_user(buf, (int *)arg); + return 0; } - return -EINVAL; } - static struct mixer_operations aci_mixer_operations = { - owner: THIS_MODULE, - id: "ACI", - name: "ACI mixer", - ioctl: aci_mixer_ioctl + owner: THIS_MODULE, + id: "ACI", + ioctl: aci_mixer_ioctl }; -static unsigned char -mad_read (int port) -{ - outb (0xE3, 0xf8f); /* Write MAD16 password */ - return inb (port); /* Read from port */ -} - - /* - * Check, whether there actually is any ACI port operational and if - * one was found, then initialize the ACI interface, reserve the I/O - * addresses and attach the new mixer to the relevant VoxWare data - * structures. - * - * Returns: 1 ACI mixer detected - * 0 nothing there - * * There is also an internal mixer in the codec (CS4231A or AD1845), * that deserves no purpose in an ACI based system which uses an * external ACI controlled stereo mixer. Make sure that this codec @@ -570,153 +595,108 @@ static int __init attach_aci(void) { - char *boardname = "unknown"; - int volume; + char *boardname; + int i; -#define MC4_PORT 0xf90 + init_MUTEX(&aci_sem); - aci_port = - (mad_read(MC4_PORT) & 0x10) ? 0x344 : 0x354; + outb(0xE3, 0xf8f); /* Write MAD16 password */ + aci_port = (inb(0xf90) & 0x10) ? + 0x344: 0x354; /* Get aci_port from MC4_PORT */ if (check_region(aci_port, 3)) { -#ifdef DEBUG - printk("ACI: I/O area 0x%03x-0x%03x already used.\n", - aci_port, aci_port+2); -#endif - return 0; + printk(KERN_NOTICE "aci: I/O area 0x%03x-0x%03x already used.\n", + aci_port, aci_port+2); + return -EBUSY; } - - if (aci_read_cmd(0xf2, 2, aci_idcode)) { -#ifdef DEBUG - printk("ACI: Failed to read idcode.\n"); -#endif - return 0; + + /* force ACI into a known state */ + for (i=0; i<3; i++) + if (aci_rw_cmd(0xdf, -1, -1)<0) + return -EFAULT; + + /* official this is one aci read call: */ + if ((aci_idcode[0]=aci_rw_cmd(0xf2, -1, -1))<0 || + (aci_idcode[1]=aci_rw_cmd(0xf2, -1, -1))<0) { + printk(KERN_ERR "aci: Failed to read idcode on 0x%03x.\n", aci_port); + return -EFAULT; } - - if (aci_read_cmd(0xf1, 1, &aci_version)) { -#ifdef DEBUG - printk("ACI: Failed to read version.\n"); -#endif - return 0; + + if ((aci_version=aci_rw_cmd(0xf1, -1, -1))<0) { + printk(KERN_ERR "aci: Failed to read version on 0x%03x.\n", aci_port); + return -EFAULT; } - if (aci_idcode[0] == 0x6d) { + if (aci_idcode[0] == 'm') { /* It looks like a miro sound card. */ switch (aci_idcode[1]) { - case 0x41: - boardname = "PCM1 pro / early PCM12"; - break; - case 0x42: - boardname = "PCM12"; - break; - case 0x43: - boardname = "PCM20"; - break; - default: - boardname = "unknown miro"; + case 'A': + boardname = "PCM1 pro / early PCM12"; + break; + case 'B': + boardname = "PCM12"; + break; + case 'C': + boardname = "PCM20 radio"; + break; + default: + boardname = "unknown miro"; } - } else -#ifndef DEBUG - return 0; -#endif - - printk("<ACI %02x, id %02x %02x (%s)> at 0x%03x\n", - aci_version, aci_idcode[0], aci_idcode[1], boardname, aci_port); - - if (aci_reset) { - /* initialize ACI mixer */ - aci_implied_cmd(0xff); - aci_solo = 0; - } - - /* attach the mixer */ - request_region(aci_port, 3, "sound mixer (ACI)"); - if (num_mixers < MAX_MIXER_DEV) { - if (num_mixers > 0 && - !strncmp("MAD16 WSS", mixer_devs[num_mixers-1]->name, 9)) { - /* - * The previously registered mixer device is the CS4231A which - * has no function on an ACI card. Make the ACI mixer the first - * of the two mixer devices. - */ - mixer_devs[num_mixers] = mixer_devs[num_mixers-1]; - mixer_devs[num_mixers-1] = &aci_mixer_operations; - /* - * Initialize the CS4231A mixer with reasonable values. It is - * unlikely that the user ever will want to change these as all - * channels can be mixed via ACI. - */ - volume = 0x6464; - mixer_devs[num_mixers]->ioctl(num_mixers, - SOUND_MIXER_WRITE_PCM, (caddr_t) &volume); - volume = 0x6464; - mixer_devs[num_mixers]->ioctl(num_mixers, - SOUND_MIXER_WRITE_IGAIN, (caddr_t) &volume); - volume = 0; - mixer_devs[num_mixers]->ioctl(num_mixers, - SOUND_MIXER_WRITE_SPEAKER, (caddr_t) &volume); - volume = 0; - mixer_devs[num_mixers]->ioctl(num_mixers, - SOUND_MIXER_WRITE_MIC, (caddr_t) &volume); - volume = 0; - mixer_devs[num_mixers]->ioctl(num_mixers, - SOUND_MIXER_WRITE_IMIX, (caddr_t) &volume); - volume = 0; - mixer_devs[num_mixers]->ioctl(num_mixers, - SOUND_MIXER_WRITE_LINE1, (caddr_t) &volume); - volume = 0; - mixer_devs[num_mixers]->ioctl(num_mixers, - SOUND_MIXER_WRITE_LINE2, (caddr_t) &volume); - volume = 0; - mixer_devs[num_mixers]->ioctl(num_mixers, - SOUND_MIXER_WRITE_LINE3, (caddr_t) &volume); - volume = SOUND_MASK_LINE1; - mixer_devs[num_mixers]->ioctl(num_mixers, - SOUND_MIXER_WRITE_RECSRC, (caddr_t) &volume); - num_mixers++; - } else - mixer_devs[num_mixers++] = &aci_mixer_operations; - } - - /* Just do something; otherwise the first write command fails, at - * least with my PCM20. - */ - aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_READ_VOLUME, (caddr_t) &volume); - - if (aci_reset) { - /* Initialize ACI mixer with reasonable power-up values */ - volume = 0x3232; - aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_VOLUME, (caddr_t) &volume); - volume = 0x3232; - aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_SYNTH, (caddr_t) &volume); - volume = 0x3232; - aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_PCM, (caddr_t) &volume); - volume = 0x3232; - aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE, (caddr_t) &volume); - volume = 0x3232; - aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_MIC, (caddr_t) &volume); - volume = 0x3232; - aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_CD, (caddr_t) &volume); - volume = 0x3232; - aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE1, (caddr_t) &volume); - volume = 0x3232; - aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE2, (caddr_t) &volume); + } else { + printk(KERN_WARNING "aci: Warning: unsupported card! - " + "no hardware, no specs...\n"); + boardname = "unknown Cardinal Technologies"; + } + + printk(KERN_INFO "<ACI 0x%02x, id %02x/%02x \"%c/%c\", (%s)> at 0x%03x\n", + aci_version, + aci_idcode[0], aci_idcode[1], + aci_idcode[0], aci_idcode[1], + boardname, aci_port); + + if (reset) { + /* first write()s after reset fail with my PCM20 */ + if (aci_rw_cmd(0xff, -1, -1)<0 || + aci_rw_cmd(0xdf, 0xdf, 0xdf)<0 || + aci_rw_cmd(0xdf, 0xdf, 0xdf)<0) + return -EBUSY; + } + + /* the PCM20 is muted after reset (and reboot) */ + if (aci_rw_cmd(0x0d, 0x00, -1)<0) + return -EBUSY; + + if (ide>=0) + if (aci_rw_cmd(0xd0, !ide, -1)<0) + return -EBUSY; + + if (wss>=0 && aci_idcode[1]=='A') + if (aci_rw_cmd(0xd1, !!wss, -1)<0) + return -EBUSY; + + if (!request_region(aci_port, 3, "sound mixer (ACI)")) + return -ENOMEM; + + if ((mixer_device = sound_install_mixer(MIXER_DRIVER_VERSION, + boardname, + &aci_mixer_operations, + sizeof(aci_mixer_operations), + NULL)) >= 0) { + /* Maybe initialize the CS4231A mixer here... */ + } else { + printk(KERN_ERR "aci: Failed to install mixer.\n"); + release_region(aci_port, 3); + return mixer_device; } - aci_present = 1; - - return 1; + return 0; } static void __exit unload_aci(void) { - if (aci_present) - release_region(aci_port, 3); + sound_unload_mixerdev(mixer_device); + release_region(aci_port, 3); } - -EXPORT_SYMBOL(aci_write_cmd); -EXPORT_SYMBOL(aci_indexed_cmd); -EXPORT_SYMBOL(aci_write_cmd_d); module_init(attach_aci); module_exit(unload_aci); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/aci.h linux.ac/drivers/sound/aci.h --- linux.vanilla/drivers/sound/aci.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/aci.h Tue Apr 3 17:55:04 2001 @@ -0,0 +1,55 @@ +#ifndef _ACI_H_ +#define _ACI_H_ + +extern int aci_port; +extern int aci_idcode[2]; /* manufacturer and product ID */ +extern int aci_version; /* ACI firmware version */ +extern int aci_rw_cmd(int write1, int write2, int write3); + +extern char * aci_radio_name; +extern int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize); + +#define aci_indexed_cmd(a, b) aci_rw_cmd(a, b, -1) +#define aci_write_cmd(a, b) aci_rw_cmd(a, b, -1) +#define aci_read_cmd(a) aci_rw_cmd(a,-1, -1) + +#define COMMAND_REGISTER (aci_port) /* write register */ +#define STATUS_REGISTER (aci_port + 1) /* read register */ +#define BUSY_REGISTER (aci_port + 2) /* also used for rds */ + +#define RDS_REGISTER BUSY_REGISTER + +#define RDS_STATUS 0x01 +#define RDS_STATIONNAME 0x02 +#define RDS_TEXT 0x03 +#define RDS_ALTFREQ 0x04 +#define RDS_TIMEDATE 0x05 +#define RDS_PI_CODE 0x06 +#define RDS_PTYTATP 0x07 +#define RDS_RESET 0x08 +#define RDS_RXVALUE 0x09 + +/* + * The following macro SCALE can be used to scale one integer volume + * value into another one using only integer arithmetic. If the input + * value x is in the range 0 <= x <= xmax, then the result will be in + * the range 0 <= SCALE(xmax,ymax,x) <= ymax. + * + * This macro has for all xmax, ymax > 0 and all 0 <= x <= xmax the + * following nice properties: + * + * - SCALE(xmax,ymax,xmax) = ymax + * - SCALE(xmax,ymax,0) = 0 + * - SCALE(xmax,ymax,SCALE(ymax,xmax,SCALE(xmax,ymax,x))) = SCALE(xmax,ymax,x) + * + * In addition, the rounding error is minimal and nicely distributed. + * The proofs are left as an exercise to the reader. + */ + +#define SCALE(xmax,ymax,x) (((x)*(ymax)+(xmax)/2)/(xmax)) + +extern void __exit unload_aci_rds(void); +extern int __init attach_aci_rds(void); + + +#endif /* _ACI_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/aedsp16.c linux.ac/drivers/sound/aedsp16.c --- linux.vanilla/drivers/sound/aedsp16.c Wed Sep 27 21:53:57 2000 +++ linux.ac/drivers/sound/aedsp16.c Fri Apr 13 23:21:23 2001 @@ -257,9 +257,9 @@ #define VERSION "1.3" /* Version of Audio Excel DSP 16 driver */ -#undef AEDSP16_DEBUG 1 /* Define this to enable debug code */ -#undef AEDSP16_DEBUG_MORE 1 /* Define this to enable more debug */ -#undef AEDSP16_INFO 1 /* Define this to enable info code */ +#undef AEDSP16_DEBUG /* Define this to 1 to enable debug code */ +#undef AEDSP16_DEBUG_MORE /* Define this to 1 to enable more debug */ +#undef AEDSP16_INFO /* Define this to 1 to enable info code */ #if defined(AEDSP16_DEBUG) # define DBG(x) printk x diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/cs4232.c linux.ac/drivers/sound/cs4232.c --- linux.vanilla/drivers/sound/cs4232.c Sun Nov 12 02:33:13 2000 +++ linux.ac/drivers/sound/cs4232.c Tue Apr 3 17:55:05 2001 @@ -338,7 +338,7 @@ { #ifdef CONFIG_SOUND_WAVEFRONT_MODULE if(synthio == -1) - printk(KERN_WARNING "cs4232: set synthio and synthirq to use the wavefront facilities.\n"); + printk(KERN_INFO "cs4232: set synthio and synthirq to use the wavefront facilities.\n"); else { synth_base = synthio; synth_irq = synthirq; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/cs4281/cs4281_wrapper-24.c linux.ac/drivers/sound/cs4281/cs4281_wrapper-24.c --- linux.vanilla/drivers/sound/cs4281/cs4281_wrapper-24.c Sun Feb 4 18:05:29 2001 +++ linux.ac/drivers/sound/cs4281/cs4281_wrapper-24.c Sun Apr 15 23:06:39 2001 @@ -40,12 +40,3 @@ (state)->tmpbuff, (state)->dmaaddr_tmpbuff); #define cs4x_pgoff(vma) ((vma)->vm_pgoff) -#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \ - ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) -#define RSRCISMEMORYREGION(dev,num) ((dev)->resource[(num)].start != 0 && \ - ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) -#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) -#define PCI_GET_DRIVER_DATA pci_get_drvdata -#define PCI_SET_DRIVER_DATA pci_set_drvdata -#define PCI_SET_DMA_MASK(pcidev,mask) pcidev->dma_mask = mask - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/cs4281/cs4281m.c linux.ac/drivers/sound/cs4281/cs4281m.c --- linux.vanilla/drivers/sound/cs4281/cs4281m.c Sun Feb 4 18:05:29 2001 +++ linux.ac/drivers/sound/cs4281/cs4281m.c Sun Apr 15 23:06:39 2001 @@ -4289,23 +4289,29 @@ CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO "cs4281: probe()+\n")); - if (!RSRCISMEMORYREGION(pcidev, 0) || - !RSRCISMEMORYREGION(pcidev, 1)) { + if (pci_enable_device(pcidev)) { + CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR + "cs4281: pci_enable_device() failed\n")); + return -1; + } + if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_MEM) || + !(pci_resource_flags(pcidev, 1) & IORESOURCE_MEM)) { CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR "cs4281: probe()- Memory region not assigned\n")); - return -1; + return -ENODEV; } if (pcidev->irq == 0) { CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR "cs4281: probe() IRQ not assigned\n")); - return -1; + return -ENODEV; } - if (!pci_dma_supported(pcidev, 0xffffffff)) { + dma_mask = 0xffffffff; /* this enables playback and recording */ + i = pci_set_dma_mask(pcidev, dma_mask); + if (i) { CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR "cs4281: probe() architecture does not support 32bit PCI busmaster DMA\n")); - return -1; + return i; } - dma_mask = 0xffffffff; /* this enables playback and recording */ if (!(s = kmalloc(sizeof(struct cs4281_state), GFP_KERNEL))) { CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR "cs4281: probe() no memory for state struct.\n")); @@ -4323,8 +4329,8 @@ init_MUTEX(&s->open_sem_adc); init_MUTEX(&s->open_sem_dac); spin_lock_init(&s->lock); - s->pBA0phys = RSRCADDRESS(pcidev, 0); - s->pBA1phys = RSRCADDRESS(pcidev, 1); + s->pBA0phys = pci_resource_start(pcidev, 0); + s->pBA1phys = pci_resource_start(pcidev, 1); /* Convert phys to linear. */ s->pBA0 = ioremap_nocache(s->pBA0phys, 4096); @@ -4366,11 +4372,6 @@ s->magic = CS4281_MAGIC; s->pcidev = pcidev; s->irq = pcidev->irq; - if (pci_enable_device(pcidev)) { - CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR - "cs4281: pci_enable_device() failed\n")); - goto err_irq; - } if (request_irq (s->irq, cs4281_interrupt, SA_SHIRQ, "Crystal CS4281", s)) { CS_DBGOUT(CS_INIT | CS_ERROR, 1, @@ -4427,8 +4428,7 @@ mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long) &val); set_fs(fs); - PCI_SET_DRIVER_DATA(pcidev, s); - PCI_SET_DMA_MASK(pcidev, dma_mask); + pci_set_drvdata(pcidev, s); list_add(&s->list, &cs4281_devs); CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO "cs4281: probe()- device allocated successfully\n")); @@ -4457,7 +4457,7 @@ static void __devinit cs4281_remove(struct pci_dev *pci_dev) { - struct cs4281_state *s = PCI_GET_DRIVER_DATA(pci_dev); + struct cs4281_state *s = pci_get_drvdata(pci_dev); // stop DMA controller synchronize_irq(); free_irq(s->irq, s); @@ -4467,7 +4467,7 @@ iounmap(s->pBA1); iounmap(s->pBA0); kfree(s); - PCI_SET_DRIVER_DATA(pci_dev,NULL); + pci_set_drvdata(pci_dev,NULL); list_del(&s->list); CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO "cs4281: cs4281_remove()-: remove successful\n")); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/cs461x.h linux.ac/drivers/sound/cs461x.h --- linux.vanilla/drivers/sound/cs461x.h Tue Aug 22 19:31:05 2000 +++ linux.ac/drivers/sound/cs461x.h Thu Apr 12 12:04:32 2001 @@ -2,6 +2,7 @@ #define __CS461X_H /* + * Copyright (c) by Cirrus Logic Corporation <pcaudio@crystal.cirrus.com> * Copyright (c) by Jaroslav Kysela <perex@suse.cz> * Definitions for Cirrus Logic CS461x chips * @@ -1614,4 +1615,77 @@ #define CS461X_MODE_OUTPUT (1<<0) /* MIDI UART - output */ #define CS461X_MODE_INPUT (1<<1) /* MIDI UART - input */ +//**************************************************************************** +// +// The following define the offsets of the AC97 shadow registers, which appear +// as a virtual extension to the base address register zero memory range. +// +//**************************************************************************** +#define AC97_REG_OFFSET_MASK 0x0000007EL +#define AC97_CODEC_NUMBER_MASK 0x00003000L + +#define BA0_AC97_RESET 0x00001000L +#define BA0_AC97_MASTER_VOLUME 0x00001002L +#define BA0_AC97_HEADPHONE_VOLUME 0x00001004L +#define BA0_AC97_MASTER_VOLUME_MONO 0x00001006L +#define BA0_AC97_MASTER_TONE 0x00001008L +#define BA0_AC97_PC_BEEP_VOLUME 0x0000100AL +#define BA0_AC97_PHONE_VOLUME 0x0000100CL +#define BA0_AC97_MIC_VOLUME 0x0000100EL +#define BA0_AC97_LINE_IN_VOLUME 0x00001010L +#define BA0_AC97_CD_VOLUME 0x00001012L +#define BA0_AC97_VIDEO_VOLUME 0x00001014L +#define BA0_AC97_AUX_VOLUME 0x00001016L +#define BA0_AC97_PCM_OUT_VOLUME 0x00001018L +#define BA0_AC97_RECORD_SELECT 0x0000101AL +#define BA0_AC97_RECORD_GAIN 0x0000101CL +#define BA0_AC97_RECORD_GAIN_MIC 0x0000101EL +#define BA0_AC97_GENERAL_PURPOSE 0x00001020L +#define BA0_AC97_3D_CONTROL 0x00001022L +#define BA0_AC97_MODEM_RATE 0x00001024L +#define BA0_AC97_POWERDOWN 0x00001026L +#define BA0_AC97_EXT_AUDIO_ID 0x00001028L +#define BA0_AC97_EXT_AUDIO_POWER 0x0000102AL +#define BA0_AC97_PCM_FRONT_DAC_RATE 0x0000102CL +#define BA0_AC97_PCM_SURR_DAC_RATE 0x0000102EL +#define BA0_AC97_PCM_LFE_DAC_RATE 0x00001030L +#define BA0_AC97_PCM_LR_ADC_RATE 0x00001032L +#define BA0_AC97_MIC_ADC_RATE 0x00001034L +#define BA0_AC97_6CH_VOL_C_LFE 0x00001036L +#define BA0_AC97_6CH_VOL_SURROUND 0x00001038L +#define BA0_AC97_RESERVED_3A 0x0000103AL +#define BA0_AC97_EXT_MODEM_ID 0x0000103CL +#define BA0_AC97_EXT_MODEM_POWER 0x0000103EL +#define BA0_AC97_LINE1_CODEC_RATE 0x00001040L +#define BA0_AC97_LINE2_CODEC_RATE 0x00001042L +#define BA0_AC97_HANDSET_CODEC_RATE 0x00001044L +#define BA0_AC97_LINE1_CODEC_LEVEL 0x00001046L +#define BA0_AC97_LINE2_CODEC_LEVEL 0x00001048L +#define BA0_AC97_HANDSET_CODEC_LEVEL 0x0000104AL +#define BA0_AC97_GPIO_PIN_CONFIG 0x0000104CL +#define BA0_AC97_GPIO_PIN_TYPE 0x0000104EL +#define BA0_AC97_GPIO_PIN_STICKY 0x00001050L +#define BA0_AC97_GPIO_PIN_WAKEUP 0x00001052L +#define BA0_AC97_GPIO_PIN_STATUS 0x00001054L +#define BA0_AC97_MISC_MODEM_AFE_STAT 0x00001056L +#define BA0_AC97_RESERVED_58 0x00001058L +#define BA0_AC97_CRYSTAL_REV_N_FAB_ID 0x0000105AL +#define BA0_AC97_TEST_AND_MISC_CTRL 0x0000105CL +#define BA0_AC97_AC_MODE 0x0000105EL +#define BA0_AC97_MISC_CRYSTAL_CONTROL 0x00001060L +#define BA0_AC97_LINE1_HYPRID_CTRL 0x00001062L +#define BA0_AC97_VENDOR_RESERVED_64 0x00001064L +#define BA0_AC97_VENDOR_RESERVED_66 0x00001066L +#define BA0_AC97_SPDIF_CONTROL 0x00001068L +#define BA0_AC97_VENDOR_RESERVED_6A 0x0000106AL +#define BA0_AC97_VENDOR_RESERVED_6C 0x0000106CL +#define BA0_AC97_VENDOR_RESERVED_6E 0x0000106EL +#define BA0_AC97_VENDOR_RESERVED_70 0x00001070L +#define BA0_AC97_VENDOR_RESERVED_72 0x00001072L +#define BA0_AC97_VENDOR_RESERVED_74 0x00001074L +#define BA0_AC97_CAL_ADDRESS 0x00001076L +#define BA0_AC97_CAL_DATA 0x00001078L +#define BA0_AC97_VENDOR_RESERVED_7A 0x0000107AL +#define BA0_AC97_VENDOR_ID1 0x0000107CL +#define BA0_AC97_VENDOR_ID2 0x0000107EL #endif /* __CS461X_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/cs461x_image.h linux.ac/drivers/sound/cs461x_image.h --- linux.vanilla/drivers/sound/cs461x_image.h Thu Dec 7 00:13:33 2000 +++ linux.ac/drivers/sound/cs461x_image.h Thu Apr 12 12:04:32 2001 @@ -1,9 +1,12 @@ /**************************************************************************** * "CWCIMAGE.H"-- For CS46XX. Ver 1.04 - * Copyright 1998-2000 (c) Cirrus Logic Corp. + * Copyright 1998-2001 (c) Cirrus Logic Corp. * Version 1.04 **************************************************************************** */ +#ifndef __CS_IMAGE_H +#define __CS_IMAGE_H + #define CLEAR__COUNT 3 #define FILL__COUNT 4 #define BA1__DWORD_SIZE 13*1024+512 @@ -314,3 +317,6 @@ {0x000137f0, sizeof(FillArray3), FillArray3}, {0x00020000, sizeof(FillArray4), FillArray4} }; + + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/cs46xx.c linux.ac/drivers/sound/cs46xx.c --- linux.vanilla/drivers/sound/cs46xx.c Tue Apr 3 17:32:22 2001 +++ linux.ac/drivers/sound/cs46xx.c Sat Apr 14 01:35:55 2001 @@ -1,7 +1,8 @@ /* * Crystal SoundFusion CS46xx driver * - * Copyright 1998-2000 Cirrus Logic Corporation <audio@crystal.cirrus.com> + * Copyright 1998-2001 Cirrus Logic Corporation <pcaudio@crystal.cirrus.com> + * <twoller@crystal.cirrus.com> * Copyright 1999-2000 Jaroslav Kysela <perex@suse.cz> * Copyright 2000 Alan Cox <alan@redhat.com> * @@ -22,7 +23,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. - * * Current maintainers: * Cirrus Logic Corporation, Thomas Woller (tw) * <twoller@crystal.cirrus.com> @@ -43,17 +43,33 @@ * underruns. * 20001201-tw add resyncing of swptr on underruns. * 20001205-tw-nf fixed GETOSPACE ioctl() after open() - * + * 20010113-tw patch from Hans Grobler general cleanup. + * 20010117-tw 2.4.0 pci cleanup, wrapper code for 2.2.16-2.4.0 + * 20010118-tw basic PM support for 2.2.16+ and 2.4.0/2.4.2. + * 20010228-dh patch from David Huggins - cs_update_ptr recursion. * * Status: * Playback/Capture supported from 8k-48k. * 16Bit Signed LE & 8Bit Unsigned, with Mono or Stereo supported. + * + * APM/PM - 2.2.x APM is enabled and functioning fine. APM can also + * be enabled for 2.4.x by modifying the CS46XX_ACPI_SUPPORT macro + * definition. + * + * Hercules Game Pro XP - the EGPIO2 pin controls the external Amp, + * but the static image can not modify the EGPIO pins, so we can not + * turn on the external amp. + * + * VTB Santa Cruz - the GPIO7/GPIO8 on the Secondary Codec control + * the external amplifier for the "back" speakers, since we do not + * support the secondary codec then this external amp is also not + * turned on. */ -#include <linux/module.h> +#include <linux/list.h> #include <linux/version.h> +#include <linux/module.h> #include <linux/string.h> -#include <linux/ctype.h> #include <linux/ioport.h> #include <linux/sched.h> #include <linux/delay.h> @@ -61,22 +77,21 @@ #include <linux/slab.h> #include <linux/soundcard.h> #include <linux/pci.h> -#ifdef CS46XX_PM -#include <linux/pm.h> -#endif +#include <linux/bitops.h> #include <asm/io.h> #include <asm/dma.h> #include <linux/init.h> #include <linux/poll.h> -#include <linux/spinlock.h> -#include <linux/ac97_codec.h> +#include <linux/smp_lock.h> #include <linux/wrapper.h> #include <asm/uaccess.h> #include <asm/hardirq.h> +#include <linux/ac97_codec.h> +#include "cs46xxpm-24.h" +#include "cs46xx_wrapper-24.h" #include "cs461x.h" - /* MIDI buffer sizes */ #define CS_MIDIINBUF 500 #define CS_MIDIOUTBUF 500 @@ -90,6 +105,11 @@ #define CS_TYPE_ADC 1 #define CS_TYPE_DAC 2 + +#define CS_TRUE 1 +#define CS_FALSE 0 + +#define CS_DBGBREAKPOINT {__asm__("INT $3");} /* * CS461x definitions */ @@ -135,14 +155,22 @@ #define CS_RELEASE 0x00000800 /* all release functions in the driver */ #define CS_PARMS 0x00001000 /* functional and operational parameters */ #define CS_IOCTL 0x00002000 /* ioctl (non-mixer) */ +#define CS_PM 0x00004000 /* PM */ #define CS_TMP 0x10000000 /* tmp debug mask bit */ +#define CS_IOCTL_CMD_SUSPEND 0x1 // suspend +#define CS_IOCTL_CMD_RESUME 0x2 // resume + #if CSDEBUG static unsigned long cs_debuglevel=1; /* levels range from 1-9 */ MODULE_PARM(cs_debuglevel, "i"); static unsigned long cs_debugmask=CS_INIT | CS_ERROR; /* use CS_DBGOUT with various mask values */ MODULE_PARM(cs_debugmask, "i"); #endif +static unsigned long initdelay=700; /* PM delay in millisecs */ +MODULE_PARM(initdelay, "i"); +static unsigned long powerdown=1; /* turn on/off powerdown processing in driver */ +MODULE_PARM(powerdown, "i"); #define DMABUF_DEFAULTORDER 3 static unsigned long defaultorder=DMABUF_DEFAULTORDER; MODULE_PARM(defaultorder, "i"); @@ -153,7 +181,6 @@ MODULE_PARM(thinkpad, "i"); /* An instance of the 4610 channel */ - struct cs_channel { int used; @@ -161,7 +188,16 @@ void *state; }; -#define DRIVER_VERSION "1.10" +#define CS46XX_MAJOR_VERSION "1" +#define CS46XX_MINOR_VERSION "22" + +#ifdef __ia64__ +#define CS46XX_ARCH "64" //architecture key +#else +#define CS46XX_ARCH "32" //architecture key +#endif + +struct list_head cs46xx_devs = { &cs46xx_devs, &cs46xx_devs }; /* magic numbers to protect our data structures */ #define CS_CARD_MAGIC 0x43525553 /* "CRUS" */ @@ -208,7 +244,8 @@ unsigned divisor; unsigned type; void *tmpbuff; /* tmp buffer for sample conversions */ - dma_addr_t dma_handle_tmpbuff; + dma_addr_t dmaaddr; + dma_addr_t dmaaddr_tmpbuff; unsigned buforder_tmpbuff; /* Log base 2 of size in bytes.. */ /* our buffer acts like a circular ring */ @@ -239,7 +276,6 @@ } dmabuf; }; - struct cs_card { struct cs_channel channel[2]; unsigned int magic; @@ -253,6 +289,7 @@ /* PCI device stuff */ struct pci_dev * pci_dev; + struct list_head list; unsigned int pctl, cctl; /* Hardware DMA flag sets */ @@ -268,6 +305,7 @@ int amplifier; /* Amplifier control */ void (*amplifier_ctrl)(struct cs_card *, int); + void (*amp_init)(struct cs_card *); int active; /* Active clocking */ void (*active_ctrl)(struct cs_card *, int); @@ -309,15 +347,17 @@ mode_t open_mode; struct semaphore open_sem; } midi; + struct cs46xx_pm pm; }; -static struct cs_card *devs; - static int cs_open_mixdev(struct inode *inode, struct file *file); static int cs_release_mixdev(struct inode *inode, struct file *file); static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); static loff_t cs_llseek(struct file *file, loff_t offset, int origin); +static int cs_hardware_init(struct cs_card *card); +static int cs46xx_powerup(struct cs_card *card, unsigned int type); +static int cs461x_powerdown(struct cs_card *card, unsigned int type); static inline unsigned ld2(unsigned int x) { @@ -352,13 +392,9 @@ #define SOUND_MIXER_CS_SETDBGLEVEL _SIOWR('M',121, int) #define SOUND_MIXER_CS_GETDBGMASK _SIOWR('M',122, int) #define SOUND_MIXER_CS_SETDBGMASK _SIOWR('M',123, int) +#define SOUND_MIXER_CS_APM _SIOWR('M',124, int) -#define SNDCTL_DSP_CS_GETDBGLEVEL _SIOWR('P', 50, int) -#define SNDCTL_DSP_CS_SETDBGLEVEL _SIOWR('P', 51, int) -#define SNDCTL_DSP_CS_GETDBGMASK _SIOWR('P', 52, int) -#define SNDCTL_DSP_CS_SETDBGMASK _SIOWR('P', 53, int) - -static void printioctl(unsigned int x) +void printioctl(unsigned int x) { unsigned int i; unsigned char vidx; @@ -477,18 +513,6 @@ case SOUND_PCM_READ_FILTER: CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER: ") ); break; - case SNDCTL_DSP_CS_GETDBGMASK: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CS_GETDBGMASK: ") ); - break; - case SNDCTL_DSP_CS_GETDBGLEVEL: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CS_GETDBGLEVEL: ") ); - break; - case SNDCTL_DSP_CS_SETDBGMASK: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CS_SETDBGMASK: ") ); - break; - case SNDCTL_DSP_CS_SETDBGLEVEL: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CS_SETDBGLEVEL: ") ); - break; case SOUND_MIXER_PRIVATE1: CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1: ") ); @@ -650,6 +674,8 @@ unsigned int tmp1, tmp2; unsigned int phiIncr; unsigned int correctionPerGOF, correctionPerSec; + unsigned long flags; + CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_dac_rate()+ %d\n",rate) ); /* @@ -685,11 +711,11 @@ * Fill in the SampleRateConverter control block. */ - spin_lock_irq(&state->card->lock); + spin_lock_irqsave(&state->card->lock, flags); cs461x_poke(state->card, BA1_PSRC, ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF)); cs461x_poke(state->card, BA1_PPI, phiIncr); - spin_unlock_irq(&state->card->lock); + spin_unlock_irqrestore(&state->card->lock, flags); dmabuf->rate = rate; CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_dac_rate()- %d\n",rate) ); @@ -704,6 +730,7 @@ unsigned int phiIncr, coeffIncr, tmp1, tmp2; unsigned int correctionPerGOF, correctionPerSec, initialDelay; unsigned int frameGroupLength, cnt; + unsigned long flags; CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_adc_rate()+ %d\n",rate) ); /* @@ -766,14 +793,14 @@ /* * Fill in the VariDecimate control block. */ - spin_lock_irq(&card->lock); + spin_lock_irqsave(&card->lock, flags); cs461x_poke(card, BA1_CSRC, ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF)); cs461x_poke(card, BA1_CCI, coeffIncr); cs461x_poke(card, BA1_CD, (((BA1_VARIDEC_BUF_1 + (initialDelay << 2)) << 16) & 0xFFFF0000) | 0x80); cs461x_poke(card, BA1_CPI, phiIncr); - spin_unlock_irq(&card->lock); + spin_unlock_irqrestore(&card->lock, flags); /* * Figure out the frame group length for the write back task. Basically, @@ -796,13 +823,13 @@ /* * Fill in the WriteBack control block. */ - spin_lock_irq(&card->lock); + spin_lock_irqsave(&card->lock, flags); cs461x_poke(card, BA1_CFG1, frameGroupLength); cs461x_poke(card, BA1_CFG2, (0x00800000 | frameGroupLength)); cs461x_poke(card, BA1_CCST, 0x0000FFFF); cs461x_poke(card, BA1_CSPB, ((65536 * rate) / 24000)); cs461x_poke(card, (BA1_CSPB + 4), 0x0000FFFF); - spin_unlock_irq(&card->lock); + spin_unlock_irqrestore(&card->lock, flags); dmabuf->rate = rate; CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_adc_rate()- %d\n",rate) ); return rate; @@ -904,7 +931,7 @@ /* get current playback/recording dma buffer pointer (byte offset from LBA), called with spinlock held! */ -static inline unsigned cs_get_dma_addr(struct cs_state *state) +extern __inline__ unsigned cs_get_dma_addr(struct cs_state *state) { struct dmabuf *dmabuf = &state->dmabuf; u32 offset; @@ -938,18 +965,20 @@ static void resync_dma_ptrs(struct cs_state *state) { - struct dmabuf *dmabuf = &state->dmabuf; - int offset; + struct dmabuf *dmabuf; CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: resync_dma_ptrs()+ \n") ); - offset = 0; - dmabuf->hwptr=dmabuf->swptr = 0; - dmabuf->pringbuf = 0; + if(state) + { + dmabuf = &state->dmabuf; + dmabuf->hwptr=dmabuf->swptr = 0; + dmabuf->pringbuf = 0; + } CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: resync_dma_ptrs()- \n") ); } /* Stop recording (lock held) */ -static inline void __stop_adc(struct cs_state *state) +extern __inline__ void __stop_adc(struct cs_state *state) { struct dmabuf *dmabuf = &state->dmabuf; struct cs_card *card = state->card; @@ -983,7 +1012,9 @@ spin_lock_irqsave(&card->lock, flags); if (!(dmabuf->enable & ADC_RUNNING) && ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize) - && dmabuf->ready)) + && dmabuf->ready) && + ((card->pm.flags & CS46XX_PM_IDLE) || + (card->pm.flags & CS46XX_PM_RESUMED)) ) { dmabuf->enable |= ADC_RUNNING; cs_set_divisor(dmabuf); @@ -1032,7 +1063,10 @@ CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: start_dac()+ \n") ); spin_lock_irqsave(&card->lock, flags); if (!(dmabuf->enable & DAC_RUNNING) && - ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready)) { + ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) && + ((card->pm.flags & CS46XX_PM_IDLE) || + (card->pm.flags & CS46XX_PM_RESUMED)) ) + { dmabuf->enable |= DAC_RUNNING; tmp = cs461x_peek(card, BA1_PCTL); tmp &= 0xFFFF; @@ -1054,54 +1088,82 @@ */ static int alloc_dmabuf(struct cs_state *state) { + + struct cs_card *card=state->card; struct dmabuf *dmabuf = &state->dmabuf; void *rawbuf = NULL; void *tmpbuff = NULL; int order; - struct page *page, *pend; - - /* alloc as big a chunk as we can */ - for (order = defaultorder; order >= DMABUF_MINORDER; order--) - if((rawbuf = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, order))) - break; + struct page *map, *mapend; + unsigned long df; + + dmabuf->ready = dmabuf->mapped = 0; + dmabuf->SGok = 0; +/* +* check for order within limits, but do not overwrite value. +*/ + if((defaultorder > 1) && (defaultorder < 12)) + df = defaultorder; + else + df = 2; - if (!rawbuf) + for (order = df; order >= DMABUF_MINORDER; order--) + if ( (rawbuf = (void *) pci_alloc_consistent( + card->pci_dev, PAGE_SIZE << order, &dmabuf->dmaaddr))) + break; + if (!rawbuf) { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR + "cs46xx: alloc_dmabuf(): unable to allocate rawbuf\n")); return -ENOMEM; - + } dmabuf->buforder = order; dmabuf->rawbuf = rawbuf; + // Now mark the pages as reserved; otherwise the + // remap_page_range() in cs46xx_mmap doesn't work. + // 1. get index to last page in mem_map array for rawbuf. + mapend = virt_to_page(dmabuf->rawbuf + + (PAGE_SIZE << dmabuf->buforder) - 1); + + // 2. mark each physical page in range as 'reserved'. + for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++) + cs4x_mem_map_reserve(map); - /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */ - pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1); - for (page = virt_to_page(rawbuf); page <= pend; page++) - mem_map_reserve(page); - - CS_DBGOUT(CS_PARMS, 9, printk("cs461x: allocated %ld (order = %d) bytes at %p\n", + CS_DBGOUT(CS_PARMS, 9, printk("cs46xx: alloc_dmabuf(): allocated %ld (order = %d) bytes at %p\n", PAGE_SIZE << order, order, rawbuf) ); + +/* +* only allocate the conversion buffer for the ADC +*/ + if(dmabuf->type == CS_TYPE_DAC) + { + dmabuf->tmpbuff = NULL; + dmabuf->buforder_tmpbuff = 0; + return 0; + } /* * now the temp buffer for 16/8 conversions */ - for (order = defaultorder; order >= DMABUF_MINORDER; order--) - if((tmpbuff = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, order))) - break; + + tmpbuff = (void *) pci_alloc_consistent( + card->pci_dev, PAGE_SIZE << order, &dmabuf->dmaaddr_tmpbuff); + if (!tmpbuff) return -ENOMEM; - CS_DBGOUT(CS_PARMS, 9, printk("cs461x: allocated %ld (order = %d) bytes at %p\n", + CS_DBGOUT(CS_PARMS, 9, printk("cs46xx: allocated %ld (order = %d) bytes at %p\n", PAGE_SIZE << order, order, tmpbuff) ); dmabuf->tmpbuff = tmpbuff; dmabuf->buforder_tmpbuff = order; - /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */ - pend = virt_to_page(tmpbuff + (PAGE_SIZE << order) - 1); - for (page = virt_to_page(tmpbuff); page <= pend; page++) - mem_map_reserve(page); - - CS_DBGOUT(CS_PARMS, 9, printk("cs461x: allocated %ld (order = %d) bytes at %p\n", - PAGE_SIZE << order, order, tmpbuff) ); - - dmabuf->ready = dmabuf->mapped = 0; - dmabuf->SGok = 0; + // Now mark the pages as reserved; otherwise the + // remap_page_range() in cs46xx_mmap doesn't work. + // 1. get index to last page in mem_map array for rawbuf. + mapend = virt_to_page(dmabuf->tmpbuff + + (PAGE_SIZE << dmabuf->buforder_tmpbuff) - 1); + + // 2. mark each physical page in range as 'reserved'. + for (map = virt_to_page(dmabuf->tmpbuff); map <= mapend; map++) + cs4x_mem_map_reserve(map); return 0; } @@ -1109,24 +1171,24 @@ static void dealloc_dmabuf(struct cs_state *state) { struct dmabuf *dmabuf = &state->dmabuf; - struct page *page, *pend; + struct page *map, *mapend; if (dmabuf->rawbuf) { - pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1); - for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++) - mem_map_unreserve(page); - pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder, - dmabuf->rawbuf, dmabuf->dma_handle); + // Undo prog_dmabuf()'s marking the pages as reserved + mapend = virt_to_page(dmabuf->rawbuf + + (PAGE_SIZE << dmabuf->buforder) - 1); + for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++) + cs4x_mem_map_unreserve(map); + free_dmabuf(state->card, dmabuf); } - dmabuf->rawbuf = NULL; if (dmabuf->tmpbuff) { - /* undo marking the pages as reserved */ - pend = virt_to_page(dmabuf->tmpbuff + (PAGE_SIZE << dmabuf->buforder_tmpbuff) - 1); - for (page = virt_to_page(dmabuf->tmpbuff); page <= pend; page++) - mem_map_unreserve(page); - pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder_tmpbuff, - dmabuf->tmpbuff, dmabuf->dma_handle_tmpbuff); + // Undo prog_dmabuf()'s marking the pages as reserved + mapend = virt_to_page(dmabuf->tmpbuff + + (PAGE_SIZE << dmabuf->buforder_tmpbuff) - 1); + for (map = virt_to_page(dmabuf->tmpbuff); map <= mapend; map++) + cs4x_mem_map_unreserve(map); + free_dmabuf2(state->card, dmabuf); } dmabuf->rawbuf = NULL; @@ -1197,7 +1259,7 @@ dmabuf->ready = 1; CS_DBGOUT(CS_PARMS, 4, printk( - "cs461x: prog_dmabuf(): CAPTURE rate=%d fmt=0x%x numfrag=%d " + "cs46xx: prog_dmabuf(): CAPTURE rate=%d fmt=0x%x numfrag=%d " "fragsize=%d dmasize=%d\n", dmabuf->rate, dmabuf->fmt, dmabuf->numfrag, dmabuf->fragsize, dmabuf->dmasize) ); @@ -1300,7 +1362,7 @@ dmabuf->ready = 1; CS_DBGOUT(CS_PARMS, 4, printk( - "cs461x: prog_dmabuf(): PLAYBACK rate=%d fmt=0x%x numfrag=%d " + "cs46xx: prog_dmabuf(): PLAYBACK rate=%d fmt=0x%x numfrag=%d " "fragsize=%d dmasize=%d\n", dmabuf->rate, dmabuf->fmt, dmabuf->numfrag, dmabuf->fragsize, dmabuf->dmasize) ); @@ -1358,7 +1420,7 @@ tmo += (2048*HZ)/dmabuf->rate; if (!schedule_timeout(tmo ? tmo : 1) && tmo){ - printk(KERN_ERR "cs461x: drain_dac, dma timeout? %d\n", count); + printk(KERN_ERR "cs46xx: drain_dac, dma timeout? %d\n", count); break; } } @@ -1372,9 +1434,8 @@ /* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */ -static void cs_update_ptr(void) +static void cs_update_ptr(struct cs_card *card, int wake) { - struct cs_card *card=devs; struct cs_state *state; struct dmabuf *dmabuf; unsigned hwptr; @@ -1401,11 +1462,11 @@ if(dmabuf->mapped) { - if (dmabuf->count >= (signed)dmabuf->fragsize) + if (wake && dmabuf->count >= (signed)dmabuf->fragsize) wake_up(&dmabuf->wait); } else { - if (dmabuf->count > 0) + if (wake && dmabuf->count > 0) wake_up(&dmabuf->wait); } } @@ -1431,7 +1492,7 @@ dmabuf->total_bytes += diff; if (dmabuf->mapped) { dmabuf->count += diff; - if (dmabuf->count >= (signed)dmabuf->fragsize) + if (wake && dmabuf->count >= (signed)dmabuf->fragsize) wake_up(&dmabuf->wait); /* * other drivers use fragsize, but don't see any sense @@ -1475,7 +1536,7 @@ dmabuf->count = 0; dmabuf->error++; } - if (dmabuf->count < (signed)dmabuf->dmasize/2) + if (wake && dmabuf->count < (signed)dmabuf->dmasize/2) wake_up(&dmabuf->wait); } } @@ -1544,7 +1605,7 @@ { CS_DBGOUT(CS_INTERRUPT, 8, printk( "cs46xx: cs_interrupt() interrupt bit(s) set (0x%x)\n",status)); - cs_update_ptr(); + cs_update_ptr(card, CS_TRUE); } if( status & HISR_MIDI ) @@ -1681,12 +1742,26 @@ static int cs_midi_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); - struct cs_card *card = devs; + struct cs_card *card=NULL; unsigned long flags; - while (card && card->dev_midi != minor) - card = card->next; - if (!card) - return -ENODEV; + struct list_head *entry; + + list_for_each(entry, &cs46xx_devs) + { + card = list_entry(entry, struct cs_card, list); + if (card->dev_midi == minor) + break; + } + + if (entry == &cs46xx_devs) + return -ENODEV; + if (!card) + { + CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO + "cs46xx: cs46xx_midi_open(): Error - unable to find card struct\n")); + return -ENODEV; + } + file->private_data = card; /* wait for device to become free */ down(&card->midi.open_sem); @@ -1765,13 +1840,13 @@ * Midi file operations struct. */ static /*const*/ struct file_operations cs_midi_fops = { - owner: THIS_MODULE, - llseek: cs_llseek, - read: cs_midi_read, - write: cs_midi_write, - poll: cs_midi_poll, - open: cs_midi_open, - release: cs_midi_release, + CS_OWNER CS_THIS_MODULE + llseek: cs_llseek, + read: cs_midi_read, + write: cs_midi_write, + poll: cs_midi_poll, + open: cs_midi_open, + release: cs_midi_release, }; static loff_t cs_llseek(struct file *file, loff_t offset, int origin) @@ -1806,7 +1881,7 @@ s16 *psDst=(s16 *)dst; u8 *pucDst=(u8 *)dst; - CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: CopySamples()+ ") ); + CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: CopySamples()+ ") ); CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO " dst=0x%x src=0x%x count=%d fmt=0x%x\n", (unsigned)dst,(unsigned)src,(unsigned)count,(unsigned)fmt) ); @@ -1912,14 +1987,14 @@ if (copy_to_user(dest, src, cnt)) { CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR - "cs4281: cs_copy_to_user()- fault dest=0x%x src=0x%x cnt=%d\n", + "cs46xx: cs_copy_to_user()- fault dest=0x%x src=0x%x cnt=%d\n", (unsigned)dest,(unsigned)src,cnt) ); *copied = 0; return -EFAULT; } *copied = cnt; CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO - "cs4281: cs_copy_to_user()- copied bytes is %d \n",cnt) ); + "cs46xx: cs_copy_to_user()- copied bytes is %d \n",cnt) ); return 0; } @@ -1927,7 +2002,7 @@ the user's buffer. it is filled by the dma machine and drained by this loop. */ static ssize_t cs_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { - struct cs_card *card=devs; + struct cs_card *card = (struct cs_card *) file->private_data; struct cs_state *state; DECLARE_WAITQUEUE(wait, current); struct dmabuf *dmabuf; @@ -1937,7 +2012,8 @@ int cnt; unsigned copied=0; - CS_DBGOUT(CS_WAVE_READ, 4, printk("cs461x: cs_read()+ %d\n",count) ); + CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4, + printk("cs46xx: cs_read()+ %d\n",count) ); state = (struct cs_state *)card->states[0]; if(!state) return -ENODEV; @@ -1951,9 +2027,18 @@ return ret; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; + ret = 0; add_wait_queue(&state->dmabuf.wait, &wait); while (count > 0) { + while(!(card->pm.flags & CS46XX_PM_IDLE)) + { + schedule(); + if (signal_pending(current)) { + ret = ret ? ret : -ERESTARTSYS; + break; + } + } spin_lock_irqsave(&state->card->lock, flags); swptr = dmabuf->swptr; cnt = dmabuf->dmasize - swptr; @@ -1978,7 +2063,7 @@ ret = ret ? ret : -ERESTARTSYS; break; } - continue; + continue; } CS_DBGOUT(CS_WAVE_READ, 2, printk(KERN_INFO @@ -2005,7 +2090,8 @@ } remove_wait_queue(&state->dmabuf.wait, &wait); set_current_state(TASK_RUNNING); - CS_DBGOUT(CS_WAVE_READ, 4, printk("cs461x: cs_read()- %d\n",ret) ); + CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4, + printk("cs46xx: cs_read()- %d\n",ret) ); return ret; } @@ -2013,17 +2099,17 @@ the soundcard. it is drained by the dma machine and filled by this loop. */ static ssize_t cs_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { - struct cs_card *card=devs; + struct cs_card *card = (struct cs_card *) file->private_data; struct cs_state *state; DECLARE_WAITQUEUE(wait, current); struct dmabuf *dmabuf; - ssize_t ret = 0; + ssize_t ret; unsigned long flags; unsigned swptr; int cnt; CS_DBGOUT(CS_WAVE_WRITE | CS_FUNCTION, 4, - printk("cs461x: cs_write called, count = %d\n", count) ); + printk("cs46xx: cs_write called, count = %d\n", count) ); state = (struct cs_state *)card->states[1]; if(!state) return -ENODEV; @@ -2038,7 +2124,20 @@ if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; add_wait_queue(&state->dmabuf.wait, &wait); + ret = 0; +/* +* Start the loop to read from the user's buffer and write to the dma buffer. +* check for PM events and underrun/overrun in the loop. +*/ while (count > 0) { + while(!(card->pm.flags & CS46XX_PM_IDLE)) + { + schedule(); + if (signal_pending(current)) { + ret = ret ? ret : -ERESTARTSYS; + break; + } + } spin_lock_irqsave(&state->card->lock, flags); if (dmabuf->count < 0) { /* buffer underrun, we are recovering from sleep_on_timeout, @@ -2052,6 +2151,7 @@ dmabuf->hwptr = cs_get_dma_addr(state); dmabuf->swptr = dmabuf->hwptr; } + swptr = dmabuf->swptr; cnt = dmabuf->dmasize - swptr; if (dmabuf->count + cnt > dmabuf->dmasize) @@ -2081,10 +2181,8 @@ if (!ret) ret = -EFAULT; return ret; } - - swptr = (swptr + cnt) % dmabuf->dmasize; - spin_lock_irqsave(&state->card->lock, flags); + swptr = (swptr + cnt) % dmabuf->dmasize; dmabuf->swptr = swptr; dmabuf->count += cnt; if(dmabuf->count > dmabuf->dmasize) @@ -2143,7 +2241,7 @@ } spin_lock_irqsave(&card->lock, flags); - cs_update_ptr(); + cs_update_ptr(card, CS_FALSE); if (file->f_mode & FMODE_READ) { state = card->states[0]; if(state) @@ -2170,7 +2268,8 @@ } spin_unlock_irqrestore(&card->lock, flags); - CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_poll()- \n")); + CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_poll()- (0x%x) \n", + mask)); return mask; } @@ -2184,7 +2283,7 @@ static int cs_mmap(struct file *file, struct vm_area_struct *vma) { - struct cs_card *card=devs; + struct cs_card *card = (struct cs_card *)file->private_data; struct cs_state *state; struct dmabuf *dmabuf; int ret; @@ -2199,7 +2298,7 @@ if(state) { CS_DBGOUT(CS_OPEN, 2, printk( - "cs46xx: cs_mmap() VM_WRITE - state TRUE prog_dmabuf DAC\n") ); + "cs46xx: cs_mmap() VM_WRITE - state CS_TRUE prog_dmabuf DAC\n") ); if ((ret = prog_dmabuf(state)) != 0) return ret; } @@ -2208,7 +2307,7 @@ if(state) { CS_DBGOUT(CS_OPEN, 2, printk( - "cs46xx: cs_mmap() VM_READ - state TRUE prog_dmabuf ADC\n") ); + "cs46xx: cs_mmap() VM_READ - state CS_TRUE prog_dmabuf ADC\n") ); if ((ret = prog_dmabuf(state)) != 0) return ret; } @@ -2231,7 +2330,7 @@ return -EINVAL; dmabuf = &state->dmabuf; - if (vma->vm_pgoff != 0) + if (cs4x_pgoff(vma) != 0) return -EINVAL; size = vma->vm_end - vma->vm_start; @@ -2617,7 +2716,7 @@ { dmabuf = &state->dmabuf; spin_lock_irqsave(&state->card->lock, flags); - cs_update_ptr(); + cs_update_ptr(card, CS_TRUE); abinfo.fragsize = dmabuf->fragsize; abinfo.fragstotal = dmabuf->numfrag; /* @@ -2640,7 +2739,7 @@ { dmabuf = &state->dmabuf; spin_lock_irqsave(&state->card->lock, flags); - cs_update_ptr(); + cs_update_ptr(card, CS_TRUE); abinfo.fragsize = dmabuf->fragsize/dmabuf->divisor; abinfo.bytes = dmabuf->count/dmabuf->divisor; abinfo.fragstotal = dmabuf->numfrag; @@ -2721,7 +2820,7 @@ { dmabuf = &state->dmabuf; spin_lock_irqsave(&state->card->lock, flags); - cs_update_ptr(); + cs_update_ptr(card, CS_TRUE); cinfo.bytes = dmabuf->total_bytes/dmabuf->divisor; cinfo.blocks = dmabuf->count/dmabuf->divisor >> dmabuf->fragshift; cinfo.ptr = dmabuf->hwptr/dmabuf->divisor; @@ -2736,7 +2835,7 @@ { dmabuf = &state->dmabuf; spin_lock_irqsave(&state->card->lock, flags); - cs_update_ptr(); + cs_update_ptr(card, CS_TRUE); cinfo.bytes = dmabuf->total_bytes; if (dmabuf->mapped) { @@ -2772,7 +2871,7 @@ { dmabuf = &state->dmabuf; spin_lock_irqsave(&state->card->lock, flags); - cs_update_ptr(); + cs_update_ptr(card, CS_TRUE); val = dmabuf->count; spin_unlock_irqrestore(&state->card->lock, flags); } @@ -2856,10 +2955,12 @@ } } - - /* - * Untested + * For the VTB Santa Cruz card, the Secondary Codec must have the + * GPIO pins 7 and 8 manipulated, not the Primary codec. + * Currently, only the primary codec is supported, so the following + * code will not function. Additionally, slot 12 must be setup + * to allow proper output for 7 and 8 to occur (trw). */ static void amp_voyetra_4294(struct cs_card *card, int change) @@ -2897,9 +2998,9 @@ u16 control; u8 pp; unsigned long port; - int old=card->amplifier; + int old=card->active; - card->amplifier+=change; + card->active+=change; acpi_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL); if(acpi_dev == NULL) @@ -2913,24 +3014,55 @@ control=inw(port+0x10); /* Flip CLKRUN off while running */ - if(!card->amplifier && old) + if(!card->active && old) + { + CS_DBGOUT(CS_PARMS , 9, printk( + "cs46xx: clkrun() enable clkrun - change=%d active=%d\n", + change,card->active)); outw(control|0x2000, port+0x10); - else if(card->amplifier && !old) + } + else + { + /* + * sometimes on a resume the bit is set, so always reset the bit. + */ + CS_DBGOUT(CS_PARMS , 9, printk( + "cs46xx: clkrun() disable clkrun - change=%d active=%d\n", + change,card->active)); outw(control&~0x2000, port+0x10); + } } static int cs_open(struct inode *inode, struct file *file) { - struct cs_card *card = devs; + struct cs_card *card = (struct cs_card *)file->private_data; struct cs_state *state = NULL; struct dmabuf *dmabuf = NULL; + struct list_head *entry; + int minor = MINOR(inode->i_rdev); int ret=0; + unsigned int tmp; CS_DBGOUT(CS_OPEN | CS_FUNCTION, 2, printk("cs46xx: cs_open()+ file=0x%x %s %s\n", (unsigned)file, file->f_mode & FMODE_WRITE ? "FMODE_WRITE" : "", file->f_mode & FMODE_READ ? "FMODE_READ" : "") ); + list_for_each(entry, &cs46xx_devs) + { + card = list_entry(entry, struct cs_card, list); + + if (!((card->dev_audio ^ minor) & ~0xf)) + break; + } + if (entry == &cs46xx_devs) + return -ENODEV; + if (!card) { + CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO + "cs46xx: cs_open(): Error - unable to find audio card struct\n")); + return -ENODEV; + } + /* * hardcode state[0] for capture, [1] for playback */ @@ -2971,6 +3103,13 @@ state->card->active_ctrl(state->card,1); state->card->amplifier_ctrl(state->card,1); + if( (tmp = cs46xx_powerup(card, CS_POWER_ADC)) ) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "cs46xx: cs46xx_powerup of ADC failed (0x%x)\n",tmp) ); + return -EIO; + } + dmabuf->channel->state = state; /* initialize the virtual channel */ state->virt = 0; @@ -3034,6 +3173,13 @@ state->card = card; state->card->active_ctrl(state->card,1); state->card->amplifier_ctrl(state->card,1); + + if( (tmp = cs46xx_powerup(card, CS_POWER_DAC)) ) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "cs46xx: cs46xx_powerup of DAC failed (0x%x)\n",tmp) ); + return -EIO; + } dmabuf->channel->state = state; /* initialize the virtual channel */ @@ -3074,6 +3220,7 @@ struct cs_card *card = (struct cs_card *)file->private_data; struct dmabuf *dmabuf; struct cs_state *state; + unsigned int tmp; CS_DBGOUT(CS_RELEASE | CS_FUNCTION, 2, printk("cs46xx: cs_release()+ file=0x%x %s %s\n", (unsigned)file, file->f_mode & FMODE_WRITE ? "FMODE_WRITE" : "", file->f_mode & FMODE_READ ? "FMODE_READ" : "") ); @@ -3103,6 +3250,13 @@ state->card->states[state->virt] = NULL; state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); + if( (tmp = cs461x_powerdown(card, CS_POWER_DAC )) ) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO + "cs46xx: cs_release_mixdev() powerdown DAC failure (0x%x)\n",tmp) ); + return -EIO; + } + /* Now turn off external AMP if needed */ state->card->amplifier_ctrl(state->card, -1); state->card->active_ctrl(state->card, -1); @@ -3130,6 +3284,13 @@ state->card->states[state->virt] = NULL; state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); + if( (tmp = cs461x_powerdown(card, CS_POWER_ADC )) ) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO + "cs46xx: cs_release_mixdev() powerdown ADC failure (0x%x)\n",tmp) ); + return -EIO; + } + /* Now turn off external AMP if needed */ state->card->amplifier_ctrl(state->card, -1); state->card->active_ctrl(state->card, -1); @@ -3143,127 +3304,494 @@ return 0; } -static /*const*/ struct file_operations cs461x_fops = { - owner: THIS_MODULE, - llseek: cs_llseek, - read: cs_read, - write: cs_write, - poll: cs_poll, - ioctl: cs_ioctl, - mmap: cs_mmap, - open: cs_open, - release: cs_release, -}; - -/* Write AC97 codec registers */ +void printpm(struct cs_card *s) +{ + CS_DBGOUT(CS_PM, 9, printk("pm struct:\n")); + CS_DBGOUT(CS_PM, 9, printk("flags:0x%x u32CLKCR1_SAVE: 0%x u32SSPMValue: 0x%x\n", + (unsigned)s->pm.flags,s->pm.u32CLKCR1_SAVE,s->pm.u32SSPMValue)); + CS_DBGOUT(CS_PM, 9, printk("u32PPLVCvalue: 0x%x u32PPRVCvalue: 0x%x\n", + s->pm.u32PPLVCvalue,s->pm.u32PPRVCvalue)); + CS_DBGOUT(CS_PM, 9, printk("u32FMLVCvalue: 0x%x u32FMRVCvalue: 0x%x\n", + s->pm.u32FMLVCvalue,s->pm.u32FMRVCvalue)); + CS_DBGOUT(CS_PM, 9, printk("u32GPIORvalue: 0x%x u32JSCTLvalue: 0x%x\n", + s->pm.u32GPIORvalue,s->pm.u32JSCTLvalue)); + CS_DBGOUT(CS_PM, 9, printk("u32SSCR: 0x%x u32SRCSA: 0x%x\n", + s->pm.u32SSCR,s->pm.u32SRCSA)); + CS_DBGOUT(CS_PM, 9, printk("u32DacASR: 0x%x u32AdcASR: 0x%x\n", + s->pm.u32DacASR,s->pm.u32AdcASR)); + CS_DBGOUT(CS_PM, 9, printk("u32DacSR: 0x%x u32AdcSR: 0x%x\n", + s->pm.u32DacSR,s->pm.u32AdcSR)); + CS_DBGOUT(CS_PM, 9, printk("u32MIDCR_Save: 0x%x\n", + s->pm.u32MIDCR_Save)); + CS_DBGOUT(CS_PM, 9, printk("u32AC97_powerdown: 0x%x _general_purpose 0x%x\n", + s->pm.u32AC97_powerdown,s->pm.u32AC97_general_purpose)); + CS_DBGOUT(CS_PM, 9, printk("u32AC97_master_volume: 0x%x\n", + s->pm.u32AC97_master_volume)); + CS_DBGOUT(CS_PM, 9, printk("u32AC97_headphone_volume: 0x%x\n", + s->pm.u32AC97_headphone_volume)); + CS_DBGOUT(CS_PM, 9, printk("u32AC97_master_volume_mono: 0x%x\n", + s->pm.u32AC97_master_volume_mono)); + CS_DBGOUT(CS_PM, 9, printk("u32AC97_pcm_out_volume: 0x%x\n", + s->pm.u32AC97_pcm_out_volume)); + CS_DBGOUT(CS_PM, 9, printk("dmabuf_swptr_play: 0x%x dmabuf_count_play: %d\n", + s->pm.dmabuf_swptr_play,s->pm.dmabuf_count_play)); + CS_DBGOUT(CS_PM, 9, printk("dmabuf_swptr_capture: 0x%x dmabuf_count_capture: %d\n", + s->pm.dmabuf_swptr_capture,s->pm.dmabuf_count_capture)); +} -static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg) +/**************************************************************************** +* +* Suspend - save the ac97 regs, mute the outputs and power down the part. +* +****************************************************************************/ +void cs46xx_ac97_suspend(struct cs_card *card) { - struct cs_card *card = dev->private_data; - int count; - - /* - * 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address - * 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 - * 3. Write ACCTL = Control Register = 460h for initiating the write - * 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h - * 5. if DCV not cleared, break and return error - * 6. Read ACSTS = Status Register = 464h, check VSTS bit - */ - + int Count,i; + unsigned int tmp; + struct ac97_codec *dev=card->ac97_codec[0]; - cs461x_peekBA0(card, BA0_ACSDA); + CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_suspend()+\n")); - /* - * Setup the AC97 control registers on the CS461x to send the - * appropriate command to the AC97 to perform the read. - * ACCAD = Command Address Register = 46Ch - * ACCDA = Command Data Register = 470h - * ACCTL = Control Register = 460h - * set DCV - will clear when process completed - * set CRW - Read command - * set VFRM - valid frame enabled - * set ESYN - ASYNC generation enabled - * set RSTN - ARST# inactive, AC97 codec not reset - */ + if(card->states[1]) + { + stop_dac(card->states[1]); + resync_dma_ptrs(card->states[1]); + } + if(card->states[0]) + { + stop_adc(card->states[0]); + resync_dma_ptrs(card->states[0]); + } - cs461x_pokeBA0(card, BA0_ACCAD, reg); - cs461x_pokeBA0(card, BA0_ACCDA, 0); - cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_CRW | - ACCTL_VFRM | ACCTL_ESYN | - ACCTL_RSTN); + for(Count = 0x2, i=0; (Count <= CS46XX_AC97_HIGHESTREGTORESTORE) + && (i < CS46XX_AC97_NUMBER_RESTORE_REGS); + Count += 2, i++) + { + card->pm.ac97[i] = cs_ac97_get(dev, BA0_AC97_RESET + Count); + } +/* +* Save the ac97 volume registers as well as the current powerdown state. +* Now, mute the all the outputs (master, headphone, and mono), as well +* as the PCM volume, in preparation for powering down the entire part. +*/ + card->pm.u32AC97_master_volume = (u32)cs_ac97_get( dev, + (u8)BA0_AC97_MASTER_VOLUME); + card->pm.u32AC97_headphone_volume = (u32)cs_ac97_get(dev, + (u8)BA0_AC97_HEADPHONE_VOLUME); + card->pm.u32AC97_master_volume_mono = (u32)cs_ac97_get(dev, + (u8)BA0_AC97_MASTER_VOLUME_MONO); + card->pm.u32AC97_pcm_out_volume = (u32)cs_ac97_get(dev, + (u8)BA0_AC97_PCM_OUT_VOLUME); + + cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, 0x8000); + cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, 0x8000); + cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, 0x8000); + cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, 0x8000); + card->pm.u32AC97_powerdown = (u32)cs_ac97_get(dev, (u8)AC97_POWER_CONTROL); + card->pm.u32AC97_general_purpose = (u32)cs_ac97_get(dev, (u8)BA0_AC97_GENERAL_PURPOSE); - /* - * Wait for the read to occur. - */ - for (count = 0; count < 500; count++) { - /* - * First, we want to wait for a short time. - */ - udelay(10); - /* - * Now, check to see if the read has completed. - * ACCTL = 460h, DCV should be reset by now and 460h = 17h - */ - if (!(cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV)) - break; +/* +* And power down everything on the AC97 codec. +* well, for now, only power down the DAC/ADC and MIXER VREFON components. +* trouble with removing VREF. +*/ + if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC | + CS_POWER_MIXVON )) ) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "cs46xx: cs46xx_ac97_suspend() failure (0x%x)\n",tmp) ); } - /* - * Make sure the read completed. - */ - if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) { - printk(KERN_WARNING "cs461x: AC'97 read problem (ACCTL_DCV), reg = 0x%x\n", reg); - return 0xffff; - } + CS_DBGOUT(CS_PM, 9, printk("cs4281: cs46xx_ac97_suspend()-\n")); +} - /* - * Wait for the valid status bit to go active. - */ - for (count = 0; count < 100; count++) { - /* - * Read the AC97 status register. - * ACSTS = Status Register = 464h - * VSTS - Valid Status - */ - if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_VSTS) - break; - udelay(10); - } - - /* - * Make sure we got valid status. - */ - if (!(cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_VSTS)) { - printk(KERN_WARNING "cs461x: AC'97 read problem (ACSTS_VSTS), reg = 0x%x\n", reg); - return 0xffff; +/**************************************************************************** +* +* Resume - power up the part and restore its registers.. +* +****************************************************************************/ +void cs46xx_ac97_resume(struct cs_card *card) +{ + int Count,i; + struct ac97_codec *dev=card->ac97_codec[0]; + + CS_DBGOUT(CS_PM, 9, printk("cs4281: cs46xx_ac97_resume()+\n")); + +/* +* First, we restore the state of the general purpose register. This +* contains the mic select (mic1 or mic2) and if we restore this after +* we restore the mic volume/boost state and mic2 was selected at +* suspend time, we will end up with a brief period of time where mic1 +* is selected with the volume/boost settings for mic2, causing +* acoustic feedback. So we restore the general purpose register +* first, thereby getting the correct mic selected before we restore +* the mic volume/boost. +*/ + cs_ac97_set(dev, (u8)BA0_AC97_GENERAL_PURPOSE, + (u16)card->pm.u32AC97_general_purpose); + + cs_ac97_set(dev, (u8)AC97_POWER_CONTROL, + (u16)card->pm.u32AC97_powerdown); + mdelay(10); + +/* +* Now, while the outputs are still muted, restore the state of power +* on the AC97 part. +*/ + cs_ac97_set(dev, (u8)BA0_AC97_POWERDOWN, (u16)card->pm.u32AC97_powerdown); + mdelay(5); +/* +* Restore just the first set of registers, from register number +* 0x02 to the register number that ulHighestRegToRestore specifies. +*/ + for( Count = 0x2, i=0; + (Count <= CS46XX_AC97_HIGHESTREGTORESTORE) + && (i < CS46XX_AC97_NUMBER_RESTORE_REGS); + Count += 2, i++) + { + cs_ac97_set(dev, (u8)(BA0_AC97_RESET + Count), (u16)card->pm.ac97[i]); } - /* - * Read the data returned from the AC97 register. - * ACSDA = Status Data Register = 474h - */ -#if 0 - printk("e) reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n", reg, - cs461x_peekBA0(card, BA0_ACSDA), - cs461x_peekBA0(card, BA0_ACCAD)); -#endif - return cs461x_peekBA0(card, BA0_ACSDA); + /* Check if we have to init the amplifier */ + if(card->amp_init) + card->amp_init(card); + + CS_DBGOUT(CS_PM, 9, printk("cs4281: cs46xx_ac97_resume()-\n")); } -static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val) + +static int cs46xx_restart_part(struct cs_card *card) { - struct cs_card *card = dev->private_data; - int count; - int val2 = 0; - - if(reg == AC97_CD_VOL) - { - val2 = cs_ac97_get(dev, AC97_CD_VOL); - } - + struct dmabuf *dmabuf; + CS_DBGOUT(CS_PM | CS_FUNCTION, 4, + printk( "cs46xx: cs46xx_restart_part()+\n")); + if(card->states[1]) + { + dmabuf = &card->states[1]->dmabuf; + dmabuf->ready = 0; + resync_dma_ptrs(card->states[1]); + cs_set_divisor(dmabuf); + if(prog_dmabuf(card->states[1])) + { + CS_DBGOUT(CS_PM | CS_ERROR, 1, + printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() dac error\n")); + return -1; + } + cs_set_dac_rate(card->states[1], dmabuf->rate); + } + if(card->states[0]) + { + dmabuf = &card->states[0]->dmabuf; + dmabuf->ready = 0; + resync_dma_ptrs(card->states[0]); + cs_set_divisor(dmabuf); + if(prog_dmabuf(card->states[0])) + { + CS_DBGOUT(CS_PM | CS_ERROR, 1, + printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() adc error\n")); + return -1; + } + cs_set_adc_rate(card->states[0], dmabuf->rate); + } + card->pm.flags |= CS46XX_PM_RESUMED; + if(card->states[0]) + start_adc(card->states[0]); + if(card->states[1]) + start_dac(card->states[1]); + + card->pm.flags |= CS46XX_PM_IDLE; + card->pm.flags &= ~(CS46XX_PM_SUSPENDING | CS46XX_PM_SUSPENDED + | CS46XX_PM_RESUMING | CS46XX_PM_RESUMED); + if(card->states[0]) + wake_up(&card->states[0]->dmabuf.wait); + if(card->states[1]) + wake_up(&card->states[1]->dmabuf.wait); + + CS_DBGOUT(CS_PM | CS_FUNCTION, 4, + printk( "cs46xx: cs46xx_restart_part()-\n")); + return 0; +} + + +static void cs461x_reset(struct cs_card *card); +static void cs461x_proc_stop(struct cs_card *card); +int cs46xx_suspend(struct cs_card *card) +{ + unsigned int tmp; + CS_DBGOUT(CS_PM | CS_FUNCTION, 4, + printk("cs46xx: cs46xx_suspend()+ flags=%d s=0x%x\n", + (unsigned)card->pm.flags,(unsigned)card)); +/* +* check the current state, only suspend if IDLE +*/ + if(!(card->pm.flags & CS46XX_PM_IDLE)) + { + CS_DBGOUT(CS_PM | CS_ERROR, 2, + printk("cs46xx: cs46xx_suspend() unable to suspend, not IDLE\n")); + return 1; + } + card->pm.flags &= ~CS46XX_PM_IDLE; + card->pm.flags |= CS46XX_PM_SUSPENDING; + + card->active_ctrl(card,1); + + tmp = cs461x_peek(card, BA1_PFIE); + tmp &= ~0x0000f03f; + tmp |= 0x00000010; + cs461x_poke(card, BA1_PFIE, tmp); /* playback interrupt disable */ + + tmp = cs461x_peek(card, BA1_CIE); + tmp &= ~0x0000003f; + tmp |= 0x00000011; + cs461x_poke(card, BA1_CIE, tmp); /* capture interrupt disable */ + + /* + * Stop playback DMA. + */ + tmp = cs461x_peek(card, BA1_PCTL); + cs461x_poke(card, BA1_PCTL, tmp & 0x0000ffff); + + /* + * Stop capture DMA. + */ + tmp = cs461x_peek(card, BA1_CCTL); + cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000); + + if(card->states[1]) + { + card->pm.dmabuf_swptr_play = card->states[1]->dmabuf.swptr; + card->pm.dmabuf_count_play = card->states[1]->dmabuf.count; + } + if(card->states[0]) + { + card->pm.dmabuf_swptr_capture = card->states[0]->dmabuf.swptr; + card->pm.dmabuf_count_capture = card->states[0]->dmabuf.count; + } + + cs46xx_ac97_suspend(card); + + /* + * Reset the processor. + */ + cs461x_reset(card); + + cs461x_proc_stop(card); + + /* + * Power down the DAC and ADC. For now leave the other areas on. + */ + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, 0x0300); + + /* + * Power down the PLL. + */ + cs461x_pokeBA0(card, BA0_CLKCR1, 0); + + /* + * Turn off the Processor by turning off the software clock enable flag in + * the clock control register. + */ + tmp = cs461x_peekBA0(card, BA0_CLKCR1) & ~CLKCR1_SWCE; + cs461x_pokeBA0(card, BA0_CLKCR1, tmp); + + card->active_ctrl(card,-1); + + card->pm.flags &= ~CS46XX_PM_SUSPENDING; + card->pm.flags |= CS46XX_PM_SUSPENDED; + + printpm(card); + + CS_DBGOUT(CS_PM | CS_FUNCTION, 4, + printk("cs46xx: cs46xx_suspend()- flags=%d\n", + (unsigned)card->pm.flags)); + return 0; +} + +int cs46xx_resume(struct cs_card *card) +{ + int i; + + CS_DBGOUT(CS_PM | CS_FUNCTION, 4, + printk( "cs46xx: cs46xx_resume()+ flags=%d\n", + (unsigned)card->pm.flags)); + if(!(card->pm.flags & CS46XX_PM_SUSPENDED)) + { + CS_DBGOUT(CS_PM | CS_ERROR, 2, + printk("cs46xx: cs46xx_resume() unable to resume, not SUSPENDED\n")); + return 1; + } + card->pm.flags |= CS46XX_PM_RESUMING; + card->pm.flags &= ~CS46XX_PM_SUSPENDED; + printpm(card); + card->active_ctrl(card, 1); + + for(i=0;i<5;i++) + { + if (cs_hardware_init(card) != 0) + { + CS_DBGOUT(CS_PM | CS_ERROR, 4, printk( + "cs46xx: cs46xx_resume()- ERROR in cs_hardware_init()\n")); + mdelay(10); + cs461x_reset(card); + continue; + } + break; + } + if(i>=4) + { + CS_DBGOUT(CS_PM | CS_ERROR, 1, printk( + "cs46xx: cs46xx_resume()- cs_hardware_init() failed, retried %d times.\n",i)); + return 0; + } + + if(cs46xx_restart_part(card)) + { + CS_DBGOUT(CS_PM | CS_ERROR, 4, printk( + "cs46xx: cs46xx_resume(): cs46xx_restart_part() returned error\n")); + } + + card->active_ctrl(card, -1); + + CS_DBGOUT(CS_PM | CS_FUNCTION, 4, printk("cs46xx: cs46xx_resume()- flags=%d\n", + (unsigned)card->pm.flags)); + return 0; +} + +static /*const*/ struct file_operations cs461x_fops = { + CS_OWNER CS_THIS_MODULE + llseek: cs_llseek, + read: cs_read, + write: cs_write, + poll: cs_poll, + ioctl: cs_ioctl, + mmap: cs_mmap, + open: cs_open, + release: cs_release, +}; + +/* Write AC97 codec registers */ + + +static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg) +{ + struct cs_card *card = dev->private_data; + int count,loopcnt; + unsigned int tmp; + + /* + * 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address + * 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 + * 3. Write ACCTL = Control Register = 460h for initiating the write + * 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h + * 5. if DCV not cleared, break and return error + * 6. Read ACSTS = Status Register = 464h, check VSTS bit + */ + + + cs461x_peekBA0(card, BA0_ACSDA); + + /* + * Setup the AC97 control registers on the CS461x to send the + * appropriate command to the AC97 to perform the read. + * ACCAD = Command Address Register = 46Ch + * ACCDA = Command Data Register = 470h + * ACCTL = Control Register = 460h + * set DCV - will clear when process completed + * set CRW - Read command + * set VFRM - valid frame enabled + * set ESYN - ASYNC generation enabled + * set RSTN - ARST# inactive, AC97 codec not reset + */ + + cs461x_pokeBA0(card, BA0_ACCAD, reg); + cs461x_pokeBA0(card, BA0_ACCDA, 0); + cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_CRW | + ACCTL_VFRM | ACCTL_ESYN | + ACCTL_RSTN); + + + /* + * Wait for the read to occur. + */ + if(!(card->pm.flags & CS46XX_PM_IDLE)) + loopcnt = 2000; + else + loopcnt = 500; + for (count = 0; count < loopcnt; count++) { + /* + * First, we want to wait for a short time. + */ + udelay(10); + /* + * Now, check to see if the read has completed. + * ACCTL = 460h, DCV should be reset by now and 460h = 17h + */ + if (!(cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV)) + break; + } + + /* + * Make sure the read completed. + */ + if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: AC'97 read problem (ACCTL_DCV), reg = 0x%x returning 0xffff\n", reg)); + return 0xffff; + } + + /* + * Wait for the valid status bit to go active. + */ + + if(!(card->pm.flags & CS46XX_PM_IDLE)) + loopcnt = 2000; + else + loopcnt = 100; + for (count = 0; count < loopcnt; count++) { + /* + * Read the AC97 status register. + * ACSTS = Status Register = 464h + * VSTS - Valid Status + */ + if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_VSTS) + break; + udelay(10); + } + + /* + * Make sure we got valid status. + */ + if (!( (tmp=cs461x_peekBA0(card, BA0_ACSTS)) & ACSTS_VSTS)) { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: AC'97 read problem (ACSTS_VSTS), reg = 0x%x val=0x%x \n", reg, tmp)); + CS_DBGOUT(CS_ERROR, 9, printk(KERN_WARNING "returning 0xffff\n")); + return 0xffff; + } + + /* + * Read the data returned from the AC97 register. + * ACSDA = Status Data Register = 474h + */ + CS_DBGOUT(CS_FUNCTION, 9, printk(KERN_INFO + "cs46xx: cs_ac97_get() reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n", + reg, cs461x_peekBA0(card, BA0_ACSDA), + cs461x_peekBA0(card, BA0_ACCAD))); + return (cs461x_peekBA0(card, BA0_ACSDA)); +} + +static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val) +{ + struct cs_card *card = dev->private_data; + int count; + int val2 = 0; + + if(reg == AC97_CD_VOL) + { + val2 = cs_ac97_get(dev, AC97_CD_VOL); + } + /* * 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address * 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 @@ -3286,6 +3814,8 @@ */ cs461x_pokeBA0(card, BA0_ACCAD, reg); cs461x_pokeBA0(card, BA0_ACCDA, val); + cs461x_peekBA0(card, BA0_ACCTL); + cs461x_pokeBA0(card, BA0_ACCTL, 0 | ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN); cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN); for (count = 0; count < 1000; count++) { @@ -3304,7 +3834,10 @@ * Make sure the write completed. */ if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) - printk(KERN_WARNING "cs461x: AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val); + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val)); + } /* * Adjust power if the mixer is selected/deselected according @@ -3343,7 +3876,11 @@ if(val&0x8000 || val == 0x1f1f) card->amplifier_ctrl(card, -1); else /* Mute off power on */ + { + if(card->amp_init) + card->amp_init(card); card->amplifier_ctrl(card, 1); + } } } } @@ -3355,49 +3892,87 @@ { int i=0; int minor = MINOR(inode->i_rdev); - struct cs_card *card = devs; + struct cs_card *card=NULL; + struct list_head *entry; + unsigned int tmp; + + CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, + printk(KERN_INFO "cs46xx: cs_open_mixdev()+\n")); - for (card = devs; card != NULL; card = card->next) + list_for_each(entry, &cs46xx_devs) + { + card = list_entry(entry, struct cs_card, list); for (i = 0; i < NR_AC97; i++) if (card->ac97_codec[i] != NULL && card->ac97_codec[i]->dev_mixer == minor) goto match; - + } if (!card) + { + CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, + printk(KERN_INFO "cs46xx: cs46xx_open_mixdev()- -ENODEV\n")); return -ENODEV; - + } match: + if(!card->ac97_codec[i]) + return -ENODEV; file->private_data = card->ac97_codec[i]; card->active_ctrl(card,1); + if( (tmp = cs46xx_powerup(card, CS_POWER_MIXVON )) ) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "cs46xx: cs_open_mixdev() powerup failure (0x%x)\n",tmp) ); + return -EIO; + } MOD_INC_USE_COUNT; + CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, + printk(KERN_INFO "cs46xx: cs_open_mixdev()- 0\n")); return 0; } static int cs_release_mixdev(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); - struct cs_card *card = devs; + struct cs_card *card=NULL; + struct list_head *entry; int i; + unsigned int tmp; + - for (card = devs; card != NULL; card = card->next) + list_for_each(entry, &cs46xx_devs) + { + card = list_entry(entry, struct cs_card, list); for (i = 0; i < NR_AC97; i++) if (card->ac97_codec[i] != NULL && card->ac97_codec[i]->dev_mixer == minor) goto match; - + } if (!card) + { + CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, + printk(KERN_INFO "cs46xx: cs46xx_open_mixdev()- -ENODEV\n")); return -ENODEV; + } match: + if( (tmp = cs461x_powerdown(card, CS_POWER_MIXVON )) ) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "cs46xx: cs_release_mixdev() powerdown MIXVON failure (0x%x)\n",tmp) ); + return -EIO; + } card->active_ctrl(card, -1); MOD_DEC_USE_COUNT; return 0; } +void __exit cs46xx_cleanup_module(void); static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct ac97_codec *codec = (struct ac97_codec *)file->private_data; + struct cs_card *card=NULL; + struct list_head *entry; #if CSDEBUG_INTERFACE int val; @@ -3405,7 +3980,8 @@ if( (cmd == SOUND_MIXER_CS_GETDBGMASK) || (cmd == SOUND_MIXER_CS_SETDBGMASK) || (cmd == SOUND_MIXER_CS_GETDBGLEVEL) || - (cmd == SOUND_MIXER_CS_SETDBGLEVEL) ) + (cmd == SOUND_MIXER_CS_SETDBGLEVEL) || + (cmd == SOUND_MIXER_CS_APM)) { switch(cmd) { @@ -3427,9 +4003,38 @@ return -EFAULT; cs_debuglevel = val; return 0; + + case SOUND_MIXER_CS_APM: + if (get_user(val, (unsigned long *) arg)) + return -EFAULT; + if(val == CS_IOCTL_CMD_SUSPEND) + { + list_for_each(entry, &cs46xx_devs) + { + card = list_entry(entry, struct cs_card, list); + cs46xx_suspend(card); + } + + } + else if(val == CS_IOCTL_CMD_RESUME) + { + list_for_each(entry, &cs46xx_devs) + { + card = list_entry(entry, struct cs_card, list); + cs46xx_resume(card); + } + } + else + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO + "cs4281: mixer_ioctl(): invalid APM cmd (%d)\n", + val)); + } + return 0; + default: CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO - "cs4281: mixer_ioctl(): ERROR unknown debug cmd\n") ); + "cs46xx: mixer_ioctl(): ERROR unknown debug cmd\n") ); return 0; } } @@ -3438,7 +4043,7 @@ } static /*const*/ struct file_operations cs_mixer_fops = { - owner: THIS_MODULE, + CS_OWNER CS_THIS_MODULE llseek: cs_llseek, ioctl: cs_ioctl_mixdev, open: cs_open_mixdev, @@ -3453,6 +4058,9 @@ struct ac97_codec *codec; u16 eid; + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO + "cs46xx: cs_ac97_init()+\n") ); + for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL) return -ENOMEM; @@ -3467,13 +4075,21 @@ codec->codec_write = cs_ac97_set; if (ac97_probe_codec(codec) == 0) + { + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO + "cs46xx: cs_ac97_init()- codec number %d not found\n", + num_ac97) ); + card->ac97_codec[num_ac97] = 0; break; + } + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO + "cs46xx: cs_ac97_init() found codec %d\n",num_ac97) ); eid = cs_ac97_get(codec, AC97_EXTENDED_ID); if(eid==0xFFFFFF) { - printk(KERN_WARNING "cs461x: no codec attached ?\n"); + printk(KERN_WARNING "cs46xx: codec %d not present\n",num_ac97); kfree(codec); break; } @@ -3481,17 +4097,25 @@ card->ac97_features = eid; if ((codec->dev_mixer = register_sound_mixer(&cs_mixer_fops, -1)) < 0) { - printk(KERN_ERR "cs461x: couldn't register mixer!\n"); + printk(KERN_ERR "cs46xx: couldn't register mixer!\n"); kfree(codec); break; } - card->ac97_codec[num_ac97] = codec; + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO + "cs46xx: cs_ac97_init() ac97_codec[%d] set to 0x%x\n", + (unsigned int)num_ac97, + (unsigned int)codec)); /* if there is no secondary codec at all, don't probe any more */ if (!ready_2nd) - return num_ac97+1; + { + num_ac97 += 1; + break; + } } + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO + "cs46xx: cs_ac97_init()- %d\n", (unsigned int)num_ac97)); return num_ac97; } @@ -3599,96 +4223,426 @@ */ cs461x_pokeBA0(card, BA0_SERBAD, idx); /* - * Tell the serial port to load the new value into the FIFO location. + * Tell the serial port to load the new value into the FIFO location. + */ + cs461x_pokeBA0(card, BA0_SERBCM, SERBCM_WRC); + } + /* + * Now, if we powered up the devices, then power them back down again. + * This is kinda ugly, but should never happen. + */ + if (powerdown) + cs461x_pokeBA0(card, BA0_CLKCR1, tmp); +} + + +static int cs461x_powerdown(struct cs_card *card, unsigned int type) +{ + int count; + unsigned int tmp=0; + + CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO + "cs46xx: cs461x_powerdown()+ type=0x%x\n",type)); + if(!powerdown) + { + CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO + "cs46xx: cs461x_powerdown() DISABLED exiting\n")); + return 0; + } + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO + "cs46xx: cs461x_powerdown() powerdown reg=0x%x\n",tmp)); +/* +* if powering down only the VREF, and not powering down the DAC/ADC, +* then do not power down the VREF, UNLESS both the DAC and ADC are not +* currently powered down. If powering down DAC and ADC, then +* it is possible to power down the VREF (ON). +*/ + if ( ((type & CS_POWER_MIXVON) && + (!(type & CS_POWER_ADC) || (!(type & CS_POWER_DAC))) ) + && + ((tmp & CS_AC97_POWER_CONTROL_ADC_ON) || + (tmp & CS_AC97_POWER_CONTROL_DAC_ON) ) ) + { + CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO + "cs46xx: cs461x_powerdown()- 0 unable to powerdown. tmp=0x%x\n",tmp)); + return 0; + } + /* + * Power down indicated areas. + */ + if(type & CS_POWER_MIXVOFF) + { + + CS_DBGOUT(CS_FUNCTION, 4, + printk(KERN_INFO "cs46xx: cs461x_powerdown()+ MIXVOFF\n")); + /* + * Power down the MIXER (VREF ON) on the AC97 card. + */ + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + if (tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON) + { + tmp |= CS_AC97_POWER_CONTROL_MIXVOFF; + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp ); + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); + + /* + * Read the current state of the power control register. + */ + if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_MIXVOFF_ON)) + break; + } + + /* + * Check the status.. + */ + if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_MIXVOFF_ON) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: powerdown MIXVOFF failed\n")); + return 1; + } + } + } + if(type & CS_POWER_MIXVON) + { + + CS_DBGOUT(CS_FUNCTION, 4, + printk(KERN_INFO "cs46xx: cs461x_powerdown()+ MIXVON\n")); + /* + * Power down the MIXER (VREF ON) on the AC97 card. + */ + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + if (tmp & CS_AC97_POWER_CONTROL_MIXVON_ON) + { + tmp |= CS_AC97_POWER_CONTROL_MIXVON; + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp ); + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); + + /* + * Read the current state of the power control register. + */ + if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_MIXVON_ON)) + break; + } + + /* + * Check the status.. + */ + if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_MIXVON_ON) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: powerdown MIXVON failed\n")); + return 1; + } + } + } + if(type & CS_POWER_ADC) + { + /* + * Power down the ADC on the AC97 card. + */ + CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO "cs46xx: cs461x_powerdown()+ ADC\n")); + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + if (tmp & CS_AC97_POWER_CONTROL_ADC_ON) + { + tmp |= CS_AC97_POWER_CONTROL_ADC; + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp ); + + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); + + /* + * Read the current state of the power control register. + */ + if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_ADC_ON)) + break; + } + + /* + * Check the status.. + */ + if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_ADC_ON) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: powerdown ADC failed\n")); + return 1; + } + } + } + if(type & CS_POWER_DAC) + { + /* + * Power down the DAC on the AC97 card. */ - cs461x_pokeBA0(card, BA0_SERBCM, SERBCM_WRC); + + CS_DBGOUT(CS_FUNCTION, 4, + printk(KERN_INFO "cs46xx: cs461x_powerdown()+ DAC\n")); + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + if (tmp & CS_AC97_POWER_CONTROL_DAC_ON) + { + tmp |= CS_AC97_POWER_CONTROL_DAC; + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp ); + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); + + /* + * Read the current state of the power control register. + */ + if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_DAC_ON)) + break; + } + + /* + * Check the status.. + */ + if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_DAC_ON) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: powerdown DAC failed\n")); + return 1; + } + } } - /* - * Now, if we powered up the devices, then power them back down again. - * This is kinda ugly, but should never happen. - */ - if (powerdown) - cs461x_pokeBA0(card, BA0_CLKCR1, tmp); + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO + "cs46xx: cs461x_powerdown()- 0 tmp=0x%x\n",tmp)); + return 0; } -static void cs461x_powerup_dac(struct cs_card *card) +static int cs46xx_powerup(struct cs_card *card, unsigned int type) { int count; - unsigned int tmp; + unsigned int tmp=0; + CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO + "cs46xx: cs46xx_powerup()+ type=0x%x\n",type)); /* - * Power on the DACs on the AC97 card. We turn off the DAC - * powerdown bit and write the new value of the power control - * register. - */ - tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); - if (tmp & 2) /* already */ - return; - cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp & 0xfdff); - + * check for VREF and powerup if need to. + */ + if(type & CS_POWER_MIXVON) + type |= CS_POWER_MIXVOFF; + if(type & (CS_POWER_DAC | CS_POWER_ADC)) + type |= CS_POWER_MIXVON | CS_POWER_MIXVOFF; /* - * Now, we wait until we sample a DAC ready state. + * Power up indicated areas. */ - for (count = 0; count < 32; count++) { + if(type & CS_POWER_MIXVOFF) + { + + CS_DBGOUT(CS_FUNCTION, 4, + printk(KERN_INFO "cs46xx: cs46xx_powerup()+ MIXVOFF\n")); /* - * First, lets wait a short while to let things settle out a - * bit, and to prevent retrying the read too quickly. + * Power up the MIXER (VREF ON) on the AC97 card. */ - udelay(50); + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + if (!(tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON)) + { + tmp &= ~CS_AC97_POWER_CONTROL_MIXVOFF; + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp ); + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); + + /* + * Read the current state of the power control register. + */ + if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_MIXVOFF_ON) + break; + } + + /* + * Check the status.. + */ + if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_MIXVOFF_ON)) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: powerup MIXVOFF failed\n")); + return 1; + } + } + } + if(type & CS_POWER_MIXVON) + { + CS_DBGOUT(CS_FUNCTION, 4, + printk(KERN_INFO "cs46xx: cs46xx_powerup()+ MIXVON\n")); /* - * Read the current state of the power control register. + * Power up the MIXER (VREF ON) on the AC97 card. */ - if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 2) - break; + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + if (!(tmp & CS_AC97_POWER_CONTROL_MIXVON_ON)) + { + tmp &= ~CS_AC97_POWER_CONTROL_MIXVON; + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp ); + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); + + /* + * Read the current state of the power control register. + */ + if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_MIXVON_ON) + break; + } + + /* + * Check the status.. + */ + if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_MIXVON_ON)) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: powerup MIXVON failed\n")); + return 1; + } + } } - - /* - * Check the status.. - */ - if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 2)) - printk(KERN_WARNING "cs461x: powerup DAC failed\n"); -} + if(type & CS_POWER_ADC) + { + /* + * Power up the ADC on the AC97 card. + */ + CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO "cs46xx: cs46xx_powerup()+ ADC\n")); + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + if (!(tmp & CS_AC97_POWER_CONTROL_ADC_ON)) + { + tmp &= ~CS_AC97_POWER_CONTROL_ADC; + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp ); -static void cs461x_powerup_adc(struct cs_card *card) -{ - int count; - unsigned int tmp; + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); - /* - * Power on the ADCs on the AC97 card. We turn off the DAC - * powerdown bit and write the new value of the power control - * register. - */ - tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); - if (tmp & 1) /* already */ - return; - cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp & 0xfeff); + /* + * Read the current state of the power control register. + */ + if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_ADC_ON) + break; + } - /* - * Now, we wait until we sample a ADC ready state. - */ - for (count = 0; count < 32; count++) { + /* + * Check the status.. + */ + if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_ADC_ON)) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: powerup ADC failed\n")); + return 1; + } + } + } + if(type & CS_POWER_DAC) + { /* - * First, lets wait a short while to let things settle out a - * bit, and to prevent retrying the read too quickly. + * Power up the DAC on the AC97 card. */ - udelay(50); - /* - * Read the current state of the power control register. - */ - if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 1) - break; - } + CS_DBGOUT(CS_FUNCTION, 4, + printk(KERN_INFO "cs46xx: cs46xx_powerup()+ DAC\n")); + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + if (!(tmp & CS_AC97_POWER_CONTROL_DAC_ON)) + { + tmp &= ~CS_AC97_POWER_CONTROL_DAC; + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp ); + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); - /* - * Check the status.. - */ - if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 1)) - printk(KERN_WARNING "cs461x: powerup ADC failed\n"); + /* + * Read the current state of the power control register. + */ + if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_DAC_ON) + break; + } + + /* + * Check the status.. + */ + if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_DAC_ON)) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: powerup DAC failed\n")); + return 1; + } + } + } + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO + "cs46xx: cs46xx_powerup()- 0 tmp=0x%x\n",tmp)); + return 0; } + static void cs461x_proc_start(struct cs_card *card) { int cnt; @@ -3713,7 +4667,7 @@ } if (cs461x_peek(card, BA1_SPCR) & SPCR_RUNFR) - printk(KERN_WARNING "cs461x: SPCR_RUNFR never reset\n"); + printk(KERN_WARNING "cs46xx: SPCR_RUNFR never reset\n"); } static void cs461x_proc_stop(struct cs_card *card) @@ -3725,13 +4679,13 @@ cs461x_poke(card, BA1_SPCR, 0); } - - static int cs_hardware_init(struct cs_card *card) { unsigned long end_time; - unsigned int tmp; + unsigned int tmp,count; + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO + "cs46xx: cs_hardware_init()+\n") ); /* * First, blast the clock control register to zero so that the PLL starts * out in a known state, and blast the master serial port control register @@ -3753,6 +4707,8 @@ * there might be logic external to the CS461x that uses the ARST# line * for a reset. */ + cs461x_pokeBA0(card, BA0_ACCTL, 1); + udelay(50); cs461x_pokeBA0(card, BA0_ACCTL, 0); udelay(50); cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_RSTN); @@ -3778,6 +4734,15 @@ cs461x_pokeBA0(card, BA0_SERMC1, SERMC1_PTC_AC97); /* + * The part seems to not be ready for a while after a resume. + * so, if we are resuming, then wait for 700 mils. Note that 600 mils + * is not enough for some platforms! tested on an IBM Thinkpads and + * reference cards. + */ + if(!(card->pm.flags & CS46XX_PM_IDLE)) + mdelay(initdelay); + + /* * Write the selected clock control setup to the hardware. Do not turn on * SWCE yet (if requested), so that the devices clocked by the output of * PLL are not clocked until the PLL is stable. @@ -3823,27 +4788,48 @@ mdelay(5); /* Shouldnt be needed ?? */ +/* +* If we are resuming under 2.2.x then we can not schedule a timeout. +* so, just spin the CPU. +*/ + if(card->pm.flags & CS46XX_PM_IDLE) + { /* * Wait for the card ready signal from the AC97 card. */ - end_time = jiffies + 3 * (HZ >> 2); - do { + end_time = jiffies + 3 * (HZ >> 2); + do { /* * Read the AC97 status register to see if we've seen a CODEC READY * signal from the AC97 card. */ - if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY) - break; - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(1); - } while (time_before(jiffies, end_time)); + if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY) + break; + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1); + } while (time_before(jiffies, end_time)); + } + else + { + for (count = 0; count < 100; count++) { + // First, we want to wait for a short time. + udelay(25); + + if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY) + break; + } + } /* * Make sure CODEC is READY. */ if (!(cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)) { - printk(KERN_WARNING "cs461x: create - never read card ready from AC'97\n"); - printk(KERN_WARNING "cs461x: it is probably not a bug, try using the CS4232 driver\n"); + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING + "cs46xx: create - never read card ready from AC'97\n")); + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING + "cs46xx: probably not a bug, try using the CS4232 driver,\n")); + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING + "cs46xx: or turn off any automatic Power Management support in the BIOS.\n")); return -EIO; } @@ -3853,28 +4839,40 @@ */ cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN); + if(card->pm.flags & CS46XX_PM_IDLE) + { /* * Wait until we've sampled input slots 3 and 4 as valid, meaning that * the card is pumping ADC data across the AC-link. */ - end_time = jiffies + 3 * (HZ >> 2); - do { - /* - * Read the input slot valid register and see if input slots 3 and - * 4 are valid yet. - */ - if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4)) - break; - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(1); - } while (time_before(jiffies, end_time)); + end_time = jiffies + 3 * (HZ >> 2); + do { + /* + * Read the input slot valid register and see if input slots 3 and + * 4 are valid yet. + */ + if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4)) + break; + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1); + } while (time_before(jiffies, end_time)); + } + else + { + for (count = 0; count < 100; count++) { + // First, we want to wait for a short time. + udelay(25); + if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4)) + break; + } + } /* * Make sure input slots 3 and 4 are valid. If not, then return * an error. */ if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) != (ACISV_ISV3 | ACISV_ISV4)) { - printk(KERN_WARNING "cs461x: create - never read ISV3 & ISV4 from AC'97\n"); + printk(KERN_WARNING "cs46xx: create - never read ISV3 & ISV4 from AC'97\n"); return -EIO; } @@ -3885,12 +4883,6 @@ cs461x_pokeBA0(card, BA0_ACOSV, ACOSV_SLV3 | ACOSV_SLV4); /* - * Power down the DAC and ADC. We will power them up (if) when we need - * them. - */ - /* cs461x_pokeBA0(card, BA0_AC97_POWERDOWN, 0x300); */ - - /* * Turn off the Processor by turning off the software clock enable flag in * the clock control register. */ @@ -3923,14 +4915,20 @@ cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000); /* initialize AC97 codec and register /dev/mixer */ - if (cs_ac97_init(card) <= 0) - return -EIO; - - mdelay(5); /* Do we need this ?? */ + if(card->pm.flags & CS46XX_PM_IDLE) + { + if (cs_ac97_init(card) <= 0) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "cs46xx: cs_ac97_init() failure\n") ); + return -EIO; + } + } + else + { + cs46xx_ac97_resume(card); + } - cs461x_powerup_adc(card); - cs461x_powerup_dac(card); - cs461x_proc_start(card); /* @@ -3946,11 +4944,29 @@ tmp &= ~0x0000003f; tmp |= 0x00000001; cs461x_poke(card, BA1_CIE, tmp); /* capture interrupt enable */ + + /* + * If IDLE then Power down the part. We will power components up + * when we need them. + */ + if(card->pm.flags & CS46XX_PM_IDLE) + { + if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC | + CS_POWER_MIXVON )) ) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) ); + return -EIO; + } + } + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO + "cs46xx: cs_hardware_init()- 0\n")); return 0; } + /* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered - untill "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */ + until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */ /* @@ -3963,65 +4979,77 @@ u16 id; char *name; void (*amp)(struct cs_card *, int); + void (*amp_init)(struct cs_card *); void (*active)(struct cs_card *, int); }; -static struct cs_card_type __initdata cards[]={ - {0x1489, 0x7001, "Genius Soundmaker 128 value", amp_none, NULL}, - {0x5053, 0x3357, "Voyetra", amp_voyetra, NULL}, - {0x1071, 0x6003, "Mitac MI6020/21", amp_voyetra, NULL}, +static struct cs_card_type cards[]={ + {0x1489, 0x7001, "Genius Soundmaker 128 value", amp_none, NULL, NULL}, + {0x5053, 0x3357, "Voyetra", amp_voyetra, NULL, NULL}, + {0x1071, 0x6003, "Mitac MI6020/21", amp_voyetra, NULL, NULL}, + {0x14AF, 0x0050, "Hercules Game Theatre XP", NULL, NULL, NULL}, + {0x1681, 0x0050, "Hercules Game Theatre XP", NULL, NULL, NULL}, /* Not sure if the 570 needs the clkrun hack */ - {PCI_VENDOR_ID_IBM, 0x0132, "Thinkpad 570", amp_none, clkrun_hack}, - {PCI_VENDOR_ID_IBM, 0x0153, "Thinkpad 600X/A20/T20", amp_none, clkrun_hack}, - {PCI_VENDOR_ID_IBM, 0x1010, "Thinkpad 600E (unsupported)", NULL, NULL}, - {0, 0, "Card without SSID set", NULL, NULL }, + {PCI_VENDOR_ID_IBM, 0x0132, "Thinkpad 570", amp_none, NULL, clkrun_hack}, + {PCI_VENDOR_ID_IBM, 0x0153, "Thinkpad 600X/A20/T20", amp_none, NULL, clkrun_hack}, + {PCI_VENDOR_ID_IBM, 0x1010, "Thinkpad 600E (unsupported)", NULL, NULL, NULL}, + {0, 0, "Card without SSID set", NULL, NULL, NULL }, {0, 0, NULL, NULL, NULL} }; -#ifdef CS46XX_PM -static int cs46xx_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) -{ -struct cs_state *state = (struct cs_state *) dev->data; - - if (state) { - switch(rqst) { - case PM_RESUME: - printk( KERN_DEBUG "cs46xx: PM resume request\n"); - cs_hardware_init(state->card); - break; - case PM_SUSPEND: - printk( KERN_DEBUG "cs46xx: PM suspend request\n"); - stop_dac(state); - resync_dma_ptrs(state); - break; - } - } +MODULE_AUTHOR("Alan Cox <alan@redhat.com>, Jaroslav Kysela, <pcaudio@crystal.cirrus.com>"); +MODULE_DESCRIPTION("Crystal SoundFusion Audio Support"); -return 0; -} -#endif +static const char cs46xx_banner[] = KERN_INFO "Crystal 4280/46xx + AC97 Audio, version " CS46XX_MAJOR_VERSION "." CS46XX_MINOR_VERSION "." CS46XX_ARCH ", " __TIME__ " " __DATE__ "\n"; +static const char fndmsg[] = KERN_INFO "cs46xx: Found %d audio device(s).\n"; -static int __init cs_install(struct pci_dev *pci_dev) +static int __devinit cs46xx_probe(struct pci_dev *pci_dev, + const struct pci_device_id *pciid) { - struct cs_card *card; - struct cs_card_type *cp = &cards[0]; -#ifdef CS46XX_PM struct pm_dev *pmdev; -#endif + int i,j; u16 ss_card, ss_vendor; - - + struct cs_card *card; + dma_addr_t dma_mask; + struct cs_card_type *cp = &cards[0]; + + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, + printk(KERN_INFO "cs46xx: probe()+\n")); + + if (!RSRCISMEMORYREGION(pci_dev, 0) || + !RSRCISMEMORYREGION(pci_dev, 1)) { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR + "cs46xx: probe()- Memory region not assigned\n")); + return -1; + } + if (pci_dev->irq == 0) { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR + "cs46xx: probe() IRQ not assigned\n")); + return -1; + } + if (!pci_dma_supported(pci_dev, 0xffffffff)) { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR + "cs46xx: probe() architecture does not support 32bit PCI busmaster DMA\n")); + return -1; + } + dma_mask = 0xffffffff; /* this enables playback and recording */ + pci_read_config_word(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor); pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &ss_card); if ((card = kmalloc(sizeof(struct cs_card), GFP_KERNEL)) == NULL) { - printk(KERN_ERR "cs461x: out of memory\n"); + printk(KERN_ERR "cs46xx: out of memory\n"); return -ENOMEM; } memset(card, 0, sizeof(*card)); - card->ba0_addr = pci_resource_start(pci_dev, 0); - card->ba1_addr = pci_resource_start(pci_dev, 1); + if (pci_enable_device(pci_dev)) { + CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR + "cs46xx: pci_enable_device() failed\n")); + goto fail2; + } + card->ba0_addr = RSRCADDRESS(pci_dev, 0); + card->ba1_addr = RSRCADDRESS(pci_dev, 1); card->pci_dev = pci_dev; card->irq = pci_dev->irq; card->magic = CS_CARD_MAGIC; @@ -4029,7 +5057,8 @@ pci_set_master(pci_dev); - printk(KERN_INFO "cs461x: Card found at 0x%08lx and 0x%08lx, IRQ %d\n", + printk(cs46xx_banner); + printk(KERN_INFO "cs46xx: Card found at 0x%08lx and 0x%08lx, IRQ %d\n", card->ba0_addr, card->ba1_addr, card->irq); card->alloc_pcm_channel = cs_alloc_pcm_channel; @@ -4037,7 +5066,7 @@ card->free_pcm_channel = cs_free_pcm_channel; card->amplifier_ctrl = amp_none; card->active_ctrl = amp_none; - + while (cp->name) { if(cp->vendor == ss_vendor && cp->id == ss_card) @@ -4045,19 +5074,21 @@ card->amplifier_ctrl = cp->amp; if(cp->active) card->active_ctrl = cp->active; + if(cp->amp_init) + card->amp_init = cp->amp_init; break; } cp++; } if (cp->name==NULL) { - printk(KERN_INFO "cs461x: Unknown card (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n", + printk(KERN_INFO "cs46xx: Unknown card (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n", ss_vendor, ss_card, card->ba0_addr, card->ba1_addr, card->irq); } else { - printk(KERN_INFO "cs461x: %s at 0x%08lx/0x%08lx, IRQ %d\n", - cp->name, card->ba0_addr, card->ba1_addr, card->irq); + printk(KERN_INFO "cs46xx: %s (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n", + cp->name, ss_vendor, ss_card, card->ba0_addr, card->ba1_addr, card->irq); } if (card->amplifier_ctrl==NULL) @@ -4068,74 +5099,121 @@ if (external_amp == 1) { - printk(KERN_INFO "cs461x: Crystal EAPD support forced on.\n"); + printk(KERN_INFO "cs46xx: Crystal EAPD support forced on.\n"); card->amplifier_ctrl = amp_voyetra; } if (thinkpad == 1) { + printk(KERN_INFO "cs46xx: Activating CLKRUN hack for Thinkpad.\n"); card->active_ctrl = clkrun_hack; - printk(KERN_INFO "cs461x: Activating CLKRUN hack for Thinkpad.\n"); } card->active_ctrl(card, 1); - + /* claim our iospace and irq */ - card->ba0 = ioremap(card->ba0_addr, CS461X_BA0_SIZE); - card->ba1.name.data0 = ioremap(card->ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE); - card->ba1.name.data1 = ioremap(card->ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE); - card->ba1.name.pmem = ioremap(card->ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE); - card->ba1.name.reg = ioremap(card->ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE); - - CS_DBGOUT(CS_INIT, 4, printk("card->ba0=0x%.08x\n",(unsigned)card->ba0) ); - CS_DBGOUT(CS_INIT, 4, printk("card->ba1=0x%.08x 0x%.08x 0x%.08x 0x%.08x\n", - (unsigned)card->ba1.name.data0, - (unsigned)card->ba1.name.data1, - (unsigned)card->ba1.name.pmem, - (unsigned)card->ba1.name.reg) ); + card->ba0 = ioremap_nocache(card->ba0_addr, CS461X_BA0_SIZE); + card->ba1.name.data0 = ioremap_nocache(card->ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE); + card->ba1.name.data1 = ioremap_nocache(card->ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE); + card->ba1.name.pmem = ioremap_nocache(card->ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE); + card->ba1.name.reg = ioremap_nocache(card->ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE); + + CS_DBGOUT(CS_INIT, 4, printk(KERN_INFO + "cs46xx: card->ba0=0x%.08x\n",(unsigned)card->ba0) ); + CS_DBGOUT(CS_INIT, 4, printk(KERN_INFO + "cs46xx: card->ba1=0x%.08x 0x%.08x 0x%.08x 0x%.08x\n", + (unsigned)card->ba1.name.data0, + (unsigned)card->ba1.name.data1, + (unsigned)card->ba1.name.pmem, + (unsigned)card->ba1.name.reg) ); if(card->ba0 == 0 || card->ba1.name.data0 == 0 || card->ba1.name.data1 == 0 || card->ba1.name.pmem == 0 || card->ba1.name.reg == 0) goto fail2; - if (request_irq(card->irq, &cs_interrupt, SA_SHIRQ, "cs461x", card)) { - printk(KERN_ERR "cs461x: unable to allocate irq %d\n", card->irq); + if (request_irq(card->irq, &cs_interrupt, SA_SHIRQ, "cs46xx", card)) { + printk(KERN_ERR "cs46xx: unable to allocate irq %d\n", card->irq); goto fail2; } /* register /dev/dsp */ if ((card->dev_audio = register_sound_dsp(&cs461x_fops, -1)) < 0) { - printk(KERN_ERR "cs461x: unable to register dsp\n"); + printk(KERN_ERR "cs46xx: unable to register dsp\n"); goto fail; } /* register /dev/midi */ if((card->dev_midi = register_sound_midi(&cs_midi_fops, -1)) < 0) - printk(KERN_ERR "cs461x: unable to register midi\n"); + printk(KERN_ERR "cs46xx: unable to register midi\n"); - if (cs_hardware_init(card)<0) - { + card->pm.flags |= CS46XX_PM_IDLE; + for(i=0;i<5;i++) + { + if (cs_hardware_init(card) != 0) + { + CS_DBGOUT(CS_ERROR, 4, printk( + "cs46xx: ERROR in cs_hardware_init()... retrying\n")); + for (j = 0; j < NR_AC97; j++) + if (card->ac97_codec[j] != NULL) { + unregister_sound_mixer(card->ac97_codec[j]->dev_mixer); + kfree (card->ac97_codec[j]); + } + mdelay(10); + continue; + } + break; + } + if(i>=4) + { + CS_DBGOUT(CS_PM | CS_ERROR, 1, printk( + "cs46xx: cs46xx_probe()- cs_hardware_init() failed, retried %d times.\n",i)); unregister_sound_dsp(card->dev_audio); if(card->dev_midi) unregister_sound_midi(card->dev_midi); goto fail; - } + } + init_waitqueue_head(&card->midi.open_wait); init_MUTEX(&card->midi.open_sem); init_waitqueue_head(&card->midi.iwait); init_waitqueue_head(&card->midi.owait); - card->next = devs; - devs = card; cs461x_pokeBA0(card, BA0_MIDCR, MIDCR_MRST); cs461x_pokeBA0(card, BA0_MIDCR, 0); - + + /* + * Check if we have to init the amplifier, but probably already done + * since the CD logic in the ac97 init code will turn on the ext amp. + */ + if(cp->amp_init) + cp->amp_init(card); card->active_ctrl(card, -1); -#ifdef CS46XX_PM - pmdev = pm_register(PM_PCI_DEV, PM_PCI_ID(pci_dev), cs46xx_pm_callback); - if (pmdev) - pmdev->data = card; -#endif + + PCI_SET_DRIVER_DATA(pci_dev, card); + PCI_SET_DMA_MASK(pci_dev, dma_mask); + list_add(&card->list, &cs46xx_devs); + + pmdev = cs_pm_register(PM_PCI_DEV, PM_PCI_ID(pci_dev), cs46xx_pm_callback); + if (pmdev) + { + CS_DBGOUT(CS_INIT | CS_PM, 4, printk(KERN_INFO + "cs46xx: probe() pm_register() succeeded (0x%x).\n", + (unsigned)pmdev)); + pmdev->data = card; + } + else + { + CS_DBGOUT(CS_INIT | CS_PM | CS_ERROR, 2, printk(KERN_INFO + "cs46xx: probe() pm_register() failed (0x%x).\n", + (unsigned)pmdev)); + card->pm.flags |= CS46XX_PM_NOT_REGISTERED; + } + + CS_DBGOUT(CS_PM, 9, printk(KERN_INFO "cs46xx: pm.flags=0x%x card=0x%x\n", + (unsigned)card->pm.flags,(unsigned)card)); + + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO + "cs46xx: probe()- device allocated successfully\n")); return 0; fail: @@ -4152,15 +5230,22 @@ if(card->ba1.name.reg) iounmap(card->ba1.name.reg); kfree(card); + CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO + "cs46xx: probe()- no device allocated\n")); return -ENODEV; +} // probe_cs46xx -} +// --------------------------------------------------------------------- -static void cs_remove(struct cs_card *card) +static void __devinit cs46xx_remove(struct pci_dev *pci_dev) { + struct cs_card *card = PCI_GET_DRIVER_DATA(pci_dev); int i; unsigned int tmp; + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO + "cs46xx: cs46xx_remove()+\n")); + card->active_ctrl(card,1); tmp = cs461x_peek(card, BA1_PFIE); @@ -4196,7 +5281,12 @@ * Power down the DAC and ADC. We will power them up (if) when we need * them. */ - cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, 0x300); + if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC | + CS_POWER_MIXVON )) ) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) ); + } /* * Power down the PLL. @@ -4230,54 +5320,123 @@ if(card->dev_midi) unregister_sound_midi(card->dev_midi); kfree(card); -} + PCI_SET_DRIVER_DATA(pci_dev,NULL); + list_del(&card->list); -MODULE_AUTHOR("Alan Cox <alan@redhat.com>, Jaroslav Kysela, <audio@crystal.cirrus.com>"); -MODULE_DESCRIPTION("Crystal SoundFusion Audio Support"); + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO + "cs46xx: cs46xx_remove()-: remove successful\n")); +} -static char banner[] __initdata = KERN_INFO "Crystal 4280/461x + AC97 Audio, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"; -static char fndmsg[] __initdata = KERN_INFO "cs461x: Found %d audio device(s).\n"; +enum { + CS46XX_4610 = 0, + CS46XX_4612, /* same as 4624 */ + CS46XX_4615, /* same as 4630 */ +}; -static int __init cs_init_driver(void) -{ - struct pci_dev *pcidev = NULL; - int foundone=0; +static struct pci_device_id cs46xx_pci_tbl[] __devinitdata = { + + {PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_4610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CS46XX_4610}, + {PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_4612, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CS46XX_4612}, + {PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_4615, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CS46XX_4615}, + {0,} +}; - if (!pci_present()) /* No PCI bus in this machine! */ - return -ENODEV; +MODULE_DEVICE_TABLE(pci, cs46xx_pci_tbl); - printk(banner); +struct pci_driver cs46xx_pci_driver = { + name:"cs46xx", + id_table:cs46xx_pci_tbl, + probe:cs46xx_probe, + remove:cs46xx_remove, + suspend:CS46XX_SUSPEND_TBL, + resume:CS46XX_RESUME_TBL, +}; - while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6001 , pcidev))!=NULL ) { - if (cs_install(pcidev)==0) - foundone++; - } - while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6003 , pcidev))!=NULL ) { - if (cs_install(pcidev)==0) - foundone++; +int __init cs46xx_init_module(void) +{ + int rtn = 0; + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO + "cs46xx: cs46xx_init_module()+ \n")); + if (!pci_present()) { /* No PCI bus in this machine! */ + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO + "cs46xx: cs46xx_init_module()- no pci bus found\n")); + return -ENODEV; } - while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6004 , pcidev))!=NULL ) { - if (cs_install(pcidev)==0) - foundone++; + rtn = pci_module_init(&cs46xx_pci_driver); + + if(rtn == -ENODEV) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk( + "cs46xx: Unable to detect valid cs46xx device\n")); } - printk(fndmsg, foundone); - return foundone ? 0 : -ENODEV; + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, + printk(KERN_INFO "cs46xx: cs46xx_init_module()- (%d)\n",rtn)); + return rtn; } -static void __exit cs_exit_driver(void) +void __exit cs46xx_cleanup_module(void) { - struct cs_card *next; -#ifdef CS46XX_PM - pm_unregister_all(cs46xx_pm_callback); -#endif - while(devs) - { - next=devs->next; - cs_remove(devs); - devs=next; + pci_unregister_driver(&cs46xx_pci_driver); + cs_pm_unregister_all(cs46xx_pm_callback); + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, + printk(KERN_INFO "cs46xx: cleanup_cs46xx() finished\n")); +} + +module_init(cs46xx_init_module); +module_exit(cs46xx_cleanup_module); + +int cs46xx_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + struct cs_card *card; + + CS_DBGOUT(CS_PM, 2, printk(KERN_INFO + "cs46xx: cs46xx_pm_callback dev=0x%x rqst=0x%x card=%d\n", + (unsigned)dev,(unsigned)rqst,(unsigned)data)); + card = (struct cs_card *) dev->data; + if (card) { + switch(rqst) { + case PM_SUSPEND: + CS_DBGOUT(CS_PM, 2, printk(KERN_INFO + "cs46xx: PM suspend request\n")); + if(cs46xx_suspend(card)) + { + CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO + "cs46xx: PM suspend request refused\n")); + return 1; + } + break; + case PM_RESUME: + CS_DBGOUT(CS_PM, 2, printk(KERN_INFO + "cs46xx: PM resume request\n")); + if(cs46xx_resume(card)) + { + CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO + "cs46xx: PM resume request refused\n")); + return 1; + } + break; + } } + + return 0; +} + +static void cs46xx_suspend_tbl(struct pci_dev *pcidev) +{ + struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev); + CS_DBGOUT(CS_PM | CS_FUNCTION, 2, + printk(KERN_INFO "cs46xx: cs46xx_suspend_tbl request\n")); + cs46xx_suspend(s); + return; +} + +static void cs46xx_resume_tbl(struct pci_dev *pcidev) +{ + struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev); + CS_DBGOUT(CS_PM | CS_FUNCTION, 2, + printk(KERN_INFO "cs46xx: cs46xx_resume_tbl request\n")); + cs46xx_resume(s); + return; } -module_init(cs_init_driver); -module_exit(cs_exit_driver); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/cs46xx_wrapper-24.h linux.ac/drivers/sound/cs46xx_wrapper-24.h --- linux.vanilla/drivers/sound/cs46xx_wrapper-24.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/cs46xx_wrapper-24.h Sat Apr 14 15:54:08 2001 @@ -0,0 +1,56 @@ +/******************************************************************************* +* +* "cs46xx_wrapper.c" -- Cirrus Logic-Crystal CS46XX linux audio driver. +* +* Copyright (C) 2000,2001 Cirrus Logic Corp. +* -- tom woller (twoller@crystal.cirrus.com) or +* (pcaudio@crystal.cirrus.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. +* +* 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. +* +* 01/11/2001 trw - new file from cs4281 wrapper code. +* +*******************************************************************************/ +#ifndef __CS46XX_WRAPPER24_H +#define __CS46XX_WRAPPER24_H + +#include <linux/spinlock.h> + +#define CS_OWNER owner: +#define CS_THIS_MODULE THIS_MODULE, +void cs46xx_null(struct pci_dev *pcidev) { return; } +#define cs4x_mem_map_reserve(page) mem_map_reserve(page) +#define cs4x_mem_map_unreserve(page) mem_map_unreserve(page) + +#define free_dmabuf(card, dmabuf) \ + pci_free_consistent((card)->pci_dev, \ + PAGE_SIZE << (dmabuf)->buforder, \ + (dmabuf)->rawbuf, (dmabuf)->dmaaddr); +#define free_dmabuf2(card, dmabuf) \ + pci_free_consistent((card)->pci_dev, \ + PAGE_SIZE << (dmabuf)->buforder_tmpbuff, \ + (dmabuf)->tmpbuff, (dmabuf)->dmaaddr_tmpbuff); +#define cs4x_pgoff(vma) ((vma)->vm_pgoff) + +#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \ + ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) +#define RSRCISMEMORYREGION(dev,num) ((dev)->resource[(num)].start != 0 && \ + ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) +#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) +#define PCI_GET_DRIVER_DATA pci_get_drvdata +#define PCI_SET_DRIVER_DATA pci_set_drvdata +#define PCI_SET_DMA_MASK(pcidev,mask) pcidev->dma_mask = mask + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/cs46xxpm-24.h linux.ac/drivers/sound/cs46xxpm-24.h --- linux.vanilla/drivers/sound/cs46xxpm-24.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/cs46xxpm-24.h Thu Apr 12 12:04:32 2001 @@ -0,0 +1,53 @@ +/******************************************************************************* +* +* "cs46xxpm-24.h" -- Cirrus Logic-Crystal CS46XX linux audio driver. +* +* Copyright (C) 2000,2001 Cirrus Logic Corp. +* -- tom woller (twoller@crystal.cirrus.com) or +* (pcaudio@crystal.cirrus.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. +* +* 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. +* +* 12/22/00 trw - new file. +* +*******************************************************************************/ +#ifndef __CS46XXPM24_H +#define __CS46XXPM24_H + +#include <linux/pm.h> +#include "cs46xxpm.h" + + +#define CS46XX_ACPI_SUPPORT 1 +#ifdef CS46XX_ACPI_SUPPORT +/* +* for now (12/22/00) only enable the pm_register PM support. +* allow these table entries to be null. +*/ +static void cs46xx_suspend_tbl(struct pci_dev *pcidev); +static void cs46xx_resume_tbl(struct pci_dev *pcidev); +#define cs_pm_register(a, b, c) 0 +#define cs_pm_unregister_all(a) +#define CS46XX_SUSPEND_TBL cs46xx_suspend_tbl +#define CS46XX_RESUME_TBL cs46xx_resume_tbl +#else +#define cs_pm_register(a, b, c) pm_register((a), (b), (c)); +#define cs_pm_unregister_all(a) pm_unregister_all((a)); +#define CS46XX_SUSPEND_TBL cs46xx_null +#define CS46XX_RESUME_TBL cs46xx_null +#endif +int cs46xx_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data); + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/cs46xxpm.h linux.ac/drivers/sound/cs46xxpm.h --- linux.vanilla/drivers/sound/cs46xxpm.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/cs46xxpm.h Thu Apr 12 12:04:32 2001 @@ -0,0 +1,70 @@ +/******************************************************************************* +* +* "cs46xxpm.h" -- Cirrus Logic-Crystal CS46XX linux audio driver. +* +* Copyright (C) 2000,2001 Cirrus Logic Corp. +* -- tom woller (twoller@crystal.cirrus.com) or +* (pcaudio@crystal.cirrus.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. +* +* 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. +* +* 12/22/00 trw - new file. +* +*******************************************************************************/ +#ifndef __CS46XXPM_H +#define __CS46XXPM_H + +#define CS46XX_AC97_HIGHESTREGTORESTORE 0x26 +#define CS46XX_AC97_NUMBER_RESTORE_REGS (CS46XX_AC97_HIGHESTREGTORESTORE/2-1) + +/* PM state defintions */ +#define CS46XX_PM_NOT_REGISTERED 0x1000 +#define CS46XX_PM_IDLE 0x0001 +#define CS46XX_PM_SUSPENDING 0x0002 +#define CS46XX_PM_SUSPENDED 0x0004 +#define CS46XX_PM_RESUMING 0x0008 +#define CS46XX_PM_RESUMED 0x0010 + +#define CS_POWER_DAC 0x0001 +#define CS_POWER_ADC 0x0002 +#define CS_POWER_MIXVON 0x0004 +#define CS_POWER_MIXVOFF 0x0008 +#define CS_AC97_POWER_CONTROL_ON 0xf000 /* always on bits (inverted) */ +#define CS_AC97_POWER_CONTROL_ADC 0x0100 +#define CS_AC97_POWER_CONTROL_DAC 0x0200 +#define CS_AC97_POWER_CONTROL_MIXVON 0x0400 +#define CS_AC97_POWER_CONTROL_MIXVOFF 0x0800 +#define CS_AC97_POWER_CONTROL_ADC_ON 0x0001 +#define CS_AC97_POWER_CONTROL_DAC_ON 0x0002 +#define CS_AC97_POWER_CONTROL_MIXVON_ON 0x0004 +#define CS_AC97_POWER_CONTROL_MIXVOFF_ON 0x0008 + +struct cs46xx_pm { + unsigned long flags; + u32 u32CLKCR1_SAVE,u32SSPMValue,u32PPLVCvalue,u32PPRVCvalue; + u32 u32FMLVCvalue,u32FMRVCvalue,u32GPIORvalue,u32JSCTLvalue,u32SSCR; + u32 u32SRCSA,u32DacASR,u32AdcASR,u32DacSR,u32AdcSR,u32MIDCR_Save; + u32 u32SSPM_BITS; + u32 ac97[CS46XX_AC97_NUMBER_RESTORE_REGS]; + u32 u32AC97_master_volume, u32AC97_headphone_volume, u32AC97_master_volume_mono; + u32 u32AC97_pcm_out_volume, u32AC97_powerdown, u32AC97_general_purpose; + u32 u32hwptr_playback,u32hwptr_capture; + unsigned dmabuf_swptr_play; + int dmabuf_count_play; + unsigned dmabuf_swptr_capture; + int dmabuf_count_capture; +}; + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/audio.c linux.ac/drivers/sound/emu10k1/audio.c --- linux.vanilla/drivers/sound/emu10k1/audio.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/sound/emu10k1/audio.c Tue Apr 17 15:35:21 2001 @@ -272,7 +272,7 @@ /* Undo marking the pages as reserved */ for (i = 0; i < woinst->buffer.pages; i++) - mem_map_reserve(virt_to_page(woinst->buffer.addr[i])); + mem_map_unreserve(virt_to_page(woinst->buffer.addr[i])); } emu10k1_waveout_close(wave_dev); @@ -322,7 +322,7 @@ /* Undo marking the pages as reserved */ for (i = 0; i < woinst->buffer.pages; i++) - mem_map_reserve(virt_to_page(woinst->buffer.addr[i])); + mem_map_unreserve(virt_to_page(woinst->buffer.addr[i])); } emu10k1_waveout_close(wave_dev); @@ -1011,7 +1011,7 @@ static int emu10k1_audio_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); - struct emu10k1_card *card; + struct emu10k1_card *card=NULL; struct list_head *entry; struct emu10k1_wavedevice *wave_dev; @@ -1204,7 +1204,7 @@ /* Undo marking the pages as reserved */ for (i = 0; i < woinst->buffer.pages; i++) - mem_map_reserve(virt_to_page(woinst->buffer.addr[i])); + mem_map_unreserve(virt_to_page(woinst->buffer.addr[i])); } emu10k1_waveout_close(wave_dev); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/cardmi.h linux.ac/drivers/sound/emu10k1/cardmi.h --- linux.vanilla/drivers/sound/emu10k1/cardmi.h Mon Dec 11 21:02:20 2000 +++ linux.ac/drivers/sound/emu10k1/cardmi.h Mon Apr 16 00:04:23 2001 @@ -34,6 +34,7 @@ #define _CARDMI_H #include "icardmid.h" +#include <linux/sched.h> #include <linux/interrupt.h> typedef enum diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/mixer.c linux.ac/drivers/sound/emu10k1/mixer.c --- linux.vanilla/drivers/sound/emu10k1/mixer.c Thu Sep 21 21:25:09 2000 +++ linux.ac/drivers/sound/emu10k1/mixer.c Tue Apr 3 17:55:05 2001 @@ -1082,7 +1082,7 @@ static int emu10k1_mixer_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); - struct emu10k1_card *card; + struct emu10k1_card *card=NULL; struct list_head *entry; DPF(4, "emu10k1_mixer_open()\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/timer.h linux.ac/drivers/sound/emu10k1/timer.h --- linux.vanilla/drivers/sound/emu10k1/timer.h Mon Dec 11 21:02:19 2000 +++ linux.ac/drivers/sound/emu10k1/timer.h Tue Apr 17 18:41:22 2001 @@ -27,6 +27,7 @@ #ifndef _TIMER_H #define _TIMER_H +#include <linux/sched.h> #include <linux/interrupt.h> #include "hwaccess.h" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/es1370.c linux.ac/drivers/sound/es1370.c --- linux.vanilla/drivers/sound/es1370.c Tue Apr 3 17:32:22 2001 +++ linux.ac/drivers/sound/es1370.c Thu Apr 12 12:04:32 2001 @@ -3,7 +3,7 @@ /* * es1370.c -- Ensoniq ES1370/Asahi Kasei AK4531 audio driver. * - * Copyright (C) 1998-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) + * Copyright (C) 1998-2001 Thomas Sailer (t.sailer@alumni.ethz.ch) * * 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 @@ -117,6 +117,11 @@ * Tim Janik's BSE (Bedevilled Sound Engine) found this * 07.02.2000 0.33 Use pci_alloc_consistent and pci_register_driver * 21.11.2000 0.34 Initialize dma buffers in poll, otherwise poll may return a bogus mask + * 12.12.2000 0.35 More dma buffer initializations, patch from + * Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com> + * 07.01.2001 0.36 Timeout change in wrcodec as requested by Frank Klemm <pfk@fuchs.offl.uni-jena.de> + * 31.01.2001 0.37 Register/Unregister gameport + * Fix SETTRIGGER non OSS API conformity * * some important things missing in Ensoniq documentation: * @@ -159,6 +164,23 @@ #include <asm/uaccess.h> #include <asm/hardirq.h> +#if defined(CONFIG_INPUT_ANALOG) || defined(CONFIG_INPUT_ANALOG_MODULE) +#include <linux/gameport.h> +#else +struct gameport { + int io; + int size; +}; + +extern inline void gameport_register_port(struct gameport *gameport) +{ +} + +extern inline void gameport_unregister_port(struct gameport *gameport) +{ +} +#endif + /* --------------------------------------------------------------------- */ #undef OSS_DOCUMENTED_MIXER_SEMANTICS @@ -170,6 +192,7 @@ #ifndef PCI_VENDOR_ID_ENSONIQ #define PCI_VENDOR_ID_ENSONIQ 0x1274 #endif + #ifndef PCI_DEVICE_ID_ENSONIQ_ES1370 #define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000 #endif @@ -361,6 +384,7 @@ unsigned mapped:1; unsigned ready:1; unsigned endcleared:1; + unsigned enabled:1; unsigned ossfragshift; int ossmaxfrags; unsigned subdivision; @@ -375,6 +399,8 @@ unsigned char ibuf[MIDIINBUF]; unsigned char obuf[MIDIOUTBUF]; } midi; + + struct gameport gameport; }; /* --------------------------------------------------------------------- */ @@ -419,15 +445,16 @@ static void wrcodec(struct es1370_state *s, unsigned char idx, unsigned char data) { - unsigned long tmo = jiffies + HZ/10; + unsigned long tmo = jiffies + HZ/10, j; do { + j = jiffies; if (!(inl(s->io+ES1370_REG_STATUS) & STAT_CSTAT)) { outw((((unsigned short)idx)<<8)|data, s->io+ES1370_REG_CODEC); return; } schedule(); - } while ((signed)(tmo-jiffies) > 0); + } while ((signed)(tmo-j) > 0); printk(KERN_ERR "es1370: write to codec register timeout\n"); } @@ -600,6 +627,7 @@ outl((reg >> 8) & 15, s->io+ES1370_REG_MEMPAGE); outl(db->dmaaddr, s->io+(reg & 0xff)); outl((db->dmasize >> 2)-1, s->io+((reg + 4) & 0xff)); + db->enabled = 1; db->ready = 1; return 0; } @@ -1168,7 +1196,8 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - start_adc(s); + if (s->dma_adc.enabled) + start_adc(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; @@ -1195,7 +1224,8 @@ count -= cnt; buffer += cnt; ret += cnt; - start_adc(s); + if (s->dma_adc.enabled) + start_adc(s); } remove_wait_queue(&s->dma_adc.wait, &wait); set_current_state(TASK_RUNNING); @@ -1238,7 +1268,8 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - start_dac2(s); + if (s->dma_dac2.enabled) + start_dac2(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; @@ -1266,7 +1297,8 @@ count -= cnt; buffer += cnt; ret += cnt; - start_dac2(s); + if (s->dma_dac2.enabled) + start_dac2(s); } remove_wait_queue(&s->dma_dac2.wait, &wait); set_current_state(TASK_RUNNING); @@ -1520,25 +1552,31 @@ if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) return ret; + s->dma_adc.enabled = 1; start_adc(s); - } else + } else { + s->dma_adc.enabled = 0; stop_adc(s); + } } if (file->f_mode & FMODE_WRITE) { if (val & PCM_ENABLE_OUTPUT) { if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) return ret; + s->dma_dac2.enabled = 1; start_dac2(s); - } else + } else { + s->dma_dac2.enabled = 0; stop_dac2(s); + } } return 0; case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) - return ret; + if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); abinfo.fragsize = s->dma_dac2.fragsize; @@ -1554,8 +1592,8 @@ case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; + if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); abinfo.fragsize = s->dma_adc.fragsize; @@ -1575,8 +1613,8 @@ case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) - return ret; + if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); count = s->dma_dac2.count; @@ -1588,8 +1626,8 @@ case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; + if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; @@ -1606,8 +1644,8 @@ case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) - return ret; + if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_dac2.total_bytes; @@ -1729,6 +1767,7 @@ s->ctrl = (s->ctrl & ~CTRL_PCLKDIV) | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV); if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; + s->dma_adc.enabled = 1; s->sctrl &= ~SCTRL_R1FMT; if ((minor & 0xf) == SND_DEV_DSP16) s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_R1FMT; @@ -1737,6 +1776,7 @@ } if (file->f_mode & FMODE_WRITE) { s->dma_dac2.ossfragshift = s->dma_dac2.ossmaxfrags = s->dma_dac2.subdivision = 0; + s->dma_dac2.enabled = 1; s->sctrl &= ~SCTRL_P2FMT; if ((minor & 0xf) == SND_DEV_DSP16) s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_P2FMT; @@ -1772,8 +1812,8 @@ s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); wake_up(&s->open_wait); up(&s->open_sem); - return 0; unlock_kernel(); + return 0; } static /*const*/ struct file_operations es1370_audio_fops = { @@ -1825,7 +1865,8 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - start_dac1(s); + if (s->dma_dac1.enabled) + start_dac1(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; @@ -1853,7 +1894,8 @@ count -= cnt; buffer += cnt; ret += cnt; - start_dac1(s); + if (s->dma_dac1.enabled) + start_dac1(s); } remove_wait_queue(&s->dma_dac1.wait, &wait); set_current_state(TASK_RUNNING); @@ -2021,13 +2063,16 @@ if (val & PCM_ENABLE_OUTPUT) { if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s))) return ret; + s->dma_dac1.enabled = 1; start_dac1(s); - } else + } else { + s->dma_dac1.enabled = 0; stop_dac1(s); + } return 0; case SNDCTL_DSP_GETOSPACE: - if (!(s->ctrl & CTRL_DAC1_EN) && (val = prog_dmabuf_dac1(s)) != 0) + if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); @@ -2046,6 +2091,8 @@ return 0; case SNDCTL_DSP_GETODELAY: + if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); count = s->dma_dac1.count; @@ -2055,8 +2102,8 @@ return put_user(count, (int *)arg); case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; + if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_dac1.total_bytes; @@ -2158,6 +2205,7 @@ down(&s->open_sem); } s->dma_dac1.ossfragshift = s->dma_dac1.ossmaxfrags = s->dma_dac1.subdivision = 0; + s->dma_dac1.enabled = 1; spin_lock_irqsave(&s->lock, flags); s->ctrl = (s->ctrl & ~CTRL_WTSRSEL) | (1 << CTRL_SH_WTSRSEL); s->sctrl &= ~SCTRL_P1FMT; @@ -2439,6 +2487,7 @@ if (file->f_flags & O_NONBLOCK) { remove_wait_queue(&s->midi.owait, &wait); set_current_state(TASK_RUNNING); + unlock_kernel(); return -EBUSY; } tmo = (count * HZ) / 3100; @@ -2560,11 +2609,16 @@ /* note: setting CTRL_SERR_DIS is reported to break * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */ s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL); + s->gameport.io = 0; + s->gameport.size = 0; if (joystick[devindex]) { - if (check_region(0x200, JOY_EXTENT)) - printk(KERN_ERR "es1370: io port 0x200 in use\n"); - else + if (!request_region(0x200, JOY_EXTENT, "es1370")) + printk(KERN_ERR "es1370: joystick io port 0x200 in use\n"); + else { s->ctrl |= CTRL_JYSTK_EN; + s->gameport.io = 0x200; + s->gameport.size = JOY_EXTENT; + } } if (lineout[devindex]) s->ctrl |= CTRL_XCTL0; @@ -2607,6 +2661,9 @@ mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val); } set_fs(fs); + /* register gameport */ + gameport_register_port(&s->gameport); + /* store it in the driver field */ pci_set_drvdata(pcidev, s); /* put it into driver list */ @@ -2625,6 +2682,8 @@ err_dev1: printk(KERN_ERR "es1370: cannot register misc device\n"); free_irq(s->irq, s); + if (s->gameport.io) + release_region(s->gameport.io, s->gameport.size); err_irq: release_region(s->io, ES1370_EXTENT); err_region: @@ -2634,22 +2693,26 @@ static void __devinit es1370_remove(struct pci_dev *dev) { - struct es1370_state *s = pci_get_drvdata(dev); + struct es1370_state *s = pci_get_drvdata(dev); - if (!s) - return; - list_del(&s->devs); - outl(CTRL_SERR_DIS | (1 << CTRL_SH_WTSRSEL), s->io+ES1370_REG_CONTROL); /* switch everything off */ - outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */ - synchronize_irq(); - free_irq(s->irq, s); - release_region(s->io, ES1370_EXTENT); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->dev_mixer); - unregister_sound_dsp(s->dev_dac); - unregister_sound_midi(s->dev_midi); - kfree(s); - pci_set_drvdata(dev, NULL); + if (!s) + return; + list_del(&s->devs); + outl(CTRL_SERR_DIS | (1 << CTRL_SH_WTSRSEL), s->io+ES1370_REG_CONTROL); /* switch everything off */ + outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */ + synchronize_irq(); + free_irq(s->irq, s); + if (s->gameport.io) { + gameport_unregister_port(&s->gameport); + release_region(s->gameport.io, s->gameport.size); + } + release_region(s->io, ES1370_EXTENT); + unregister_sound_dsp(s->dev_audio); + unregister_sound_mixer(s->dev_mixer); + unregister_sound_dsp(s->dev_dac); + unregister_sound_midi(s->dev_midi); + kfree(s); + pci_set_drvdata(dev, NULL); } static struct pci_device_id id_table[] __devinitdata = { @@ -2670,7 +2733,7 @@ { if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1370: version v0.34 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1370: version v0.37 time " __TIME__ " " __DATE__ "\n"); return pci_module_init(&es1370_driver); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/es1371.c linux.ac/drivers/sound/es1371.c --- linux.vanilla/drivers/sound/es1371.c Tue Apr 3 17:32:22 2001 +++ linux.ac/drivers/sound/es1371.c Thu Apr 12 12:04:32 2001 @@ -3,7 +3,7 @@ /* * es1371.c -- Creative Ensoniq ES1371. * - * Copyright (C) 1998-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) + * Copyright (C) 1998-2001 Thomas Sailer (t.sailer@alumni.ethz.ch) * * 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 @@ -102,6 +102,13 @@ * 01.03.2000 0.26 SPDIF patch by Mikael Bouillot <mikael.bouillot@bigfoot.com> * Use pci_module_init * 21.11.2000 0.27 Initialize dma buffers in poll, otherwise poll may return a bogus mask + * 12.12.2000 0.28 More dma buffer initializations, patch from + * Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com> + * 05.01.2001 0.29 Hopefully updates will not be required anymore when Creative bumps + * the CT5880 revision. + * suggested by Stephan Müller <smueller@chronox.de> + * 31.01.2001 0.30 Register/Unregister gameport + * Fix SETTRIGGER non OSS API conformity */ /*****************************************************************************/ @@ -129,6 +136,23 @@ #include <asm/uaccess.h> #include <asm/hardirq.h> +#if defined(CONFIG_INPUT_ANALOG) || defined(CONFIG_INPUT_ANALOG_MODULE) +#include <linux/gameport.h> +#else +struct gameport { + int io; + int size; +}; + +extern inline void gameport_register_port(struct gameport *gameport) +{ +} + +extern inline void gameport_unregister_port(struct gameport *gameport) +{ +} +#endif + /* --------------------------------------------------------------------- */ #undef OSS_DOCUMENTED_MIXER_SEMANTICS @@ -168,6 +192,7 @@ #define ES1371REV_ES1373_B 0x06 #define ES1371REV_CT5880_A 0x07 #define CT5880REV_CT5880_C 0x02 +#define CT5880REV_CT5880_D 0x03 #define ES1371REV_ES1371_B 0x09 #define EV1938REV_EV1938_A 0x00 #define ES1371REV_ES1373_8 0x08 @@ -432,6 +457,7 @@ unsigned mapped:1; unsigned ready:1; unsigned endcleared:1; + unsigned enabled:1; unsigned ossfragshift; int ossmaxfrags; unsigned subdivision; @@ -446,6 +472,8 @@ unsigned char ibuf[MIDIINBUF]; unsigned char obuf[MIDIOUTBUF]; } midi; + + struct gameport gameport; }; /* --------------------------------------------------------------------- */ @@ -932,6 +960,7 @@ outl((reg >> 8) & 15, s->io+ES1371_REG_MEMPAGE); outl(db->dmaaddr, s->io+(reg & 0xff)); outl((db->dmasize >> 2)-1, s->io+((reg + 4) & 0xff)); + db->enabled = 1; db->ready = 1; return 0; } @@ -1351,7 +1380,8 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - start_adc(s); + if (s->dma_adc.enabled) + start_adc(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; @@ -1378,7 +1408,8 @@ count -= cnt; buffer += cnt; ret += cnt; - start_adc(s); + if (s->dma_adc.enabled) + start_adc(s); } remove_wait_queue(&s->dma_adc.wait, &wait); set_current_state(TASK_RUNNING); @@ -1421,7 +1452,8 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - start_dac2(s); + if (s->dma_dac2.enabled) + start_dac2(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; @@ -1449,7 +1481,8 @@ count -= cnt; buffer += cnt; ret += cnt; - start_dac2(s); + if (s->dma_dac2.enabled) + start_dac2(s); } remove_wait_queue(&s->dma_dac2.wait, &wait); set_current_state(TASK_RUNNING); @@ -1700,25 +1733,31 @@ if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) return ret; + s->dma_adc.enabled = 1; start_adc(s); - } else + } else { + s->dma_adc.enabled = 0; stop_adc(s); + } } if (file->f_mode & FMODE_WRITE) { if (val & PCM_ENABLE_OUTPUT) { if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) return ret; + s->dma_dac2.enabled = 1; start_dac2(s); - } else + } else { + s->dma_dac2.enabled = 0; stop_dac2(s); + } } return 0; case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) - return ret; + if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); abinfo.fragsize = s->dma_dac2.fragsize; @@ -1734,8 +1773,8 @@ case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; + if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); abinfo.fragsize = s->dma_adc.fragsize; @@ -1755,8 +1794,8 @@ case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) - return ret; + if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); count = s->dma_dac2.count; @@ -1768,8 +1807,8 @@ case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; + if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; @@ -1786,8 +1825,8 @@ case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) - return ret; + if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_dac2.total_bytes; @@ -1904,10 +1943,12 @@ } if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; + s->dma_adc.enabled = 1; set_adc_rate(s, 8000); } if (file->f_mode & FMODE_WRITE) { s->dma_dac2.ossfragshift = s->dma_dac2.ossmaxfrags = s->dma_dac2.subdivision = 0; + s->dma_dac2.enabled = 1; set_dac2_rate(s, 8000); } spin_lock_irqsave(&s->lock, flags); @@ -2005,7 +2046,8 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - start_dac1(s); + if (s->dma_dac1.enabled) + start_dac1(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; @@ -2033,7 +2075,8 @@ count -= cnt; buffer += cnt; ret += cnt; - start_dac1(s); + if (s->dma_dac1.enabled) + start_dac1(s); } remove_wait_queue(&s->dma_dac1.wait, &wait); set_current_state(TASK_RUNNING); @@ -2192,13 +2235,16 @@ if (val & PCM_ENABLE_OUTPUT) { if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s))) return ret; + s->dma_dac1.enabled = 1; start_dac1(s); - } else + } else { + s->dma_dac1.enabled = 0; stop_dac1(s); + } return 0; case SNDCTL_DSP_GETOSPACE: - if (!(s->ctrl & CTRL_DAC1_EN) && (val = prog_dmabuf_dac1(s)) != 0) + if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); @@ -2217,6 +2263,8 @@ return 0; case SNDCTL_DSP_GETODELAY: + if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); count = s->dma_dac1.count; @@ -2226,8 +2274,8 @@ return put_user(count, (int *)arg); case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; + if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_dac1.total_bytes; @@ -2329,6 +2377,7 @@ down(&s->open_sem); } s->dma_dac1.ossfragshift = s->dma_dac1.ossmaxfrags = s->dma_dac1.subdivision = 0; + s->dma_dac1.enabled = 1; set_dac1_rate(s, 8000); spin_lock_irqsave(&s->lock, flags); s->sctrl &= ~SCTRL_P1FMT; @@ -2608,6 +2657,7 @@ if (file->f_flags & O_NONBLOCK) { remove_wait_queue(&s->midi.owait, &wait); set_current_state(TASK_RUNNING); + unlock_kernel(); return -EBUSY; } tmo = (count * HZ) / 3100; @@ -2800,12 +2850,26 @@ s->ctrl |= CTRL_GPIO_OUT0; printk(KERN_INFO PFX "Running On Gateway 2000 Solo 2510 - Amp On \n"); } + s->gameport.io = s->gameport.size = 0; if ((joystick[devindex] & ~0x18) == 0x200) { - if (check_region(joystick[devindex], JOY_EXTENT)) + if (!request_region(joystick[devindex], JOY_EXTENT, "es1371")) printk(KERN_ERR PFX "joystick address 0x%x already in use\n", joystick[devindex]); else { s->ctrl |= CTRL_JYSTK_EN | (((joystick[devindex] >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT); + s->gameport.io = joystick[devindex]; + s->gameport.size = JOY_EXTENT; } + } else if (joystick[devindex] == 1) { + for (i = 0x218; i >= 0x200; i -= 0x08) { + if (request_region(i, JOY_EXTENT, "es1371")) { + s->ctrl |= CTRL_JYSTK_EN | (((i >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT); + s->gameport.io = i; + s->gameport.size = JOY_EXTENT; + break; + } + } + if (!s->gameport.io) + printk(KERN_ERR PFX "no free joystick address found\n"); } s->sctrl = 0; cssr = 0; @@ -2830,7 +2894,7 @@ pci_set_master(pcidev); /* enable bus mastering */ /* if we are a 5880 turn on the AC97 */ if (s->vendor == PCI_VENDOR_ID_ENSONIQ && - ((s->device == PCI_DEVICE_ID_ENSONIQ_CT5880 && s->rev == CT5880REV_CT5880_C) || + ((s->device == PCI_DEVICE_ID_ENSONIQ_CT5880 && s->rev >= CT5880REV_CT5880_C) || (s->device == PCI_DEVICE_ID_ENSONIQ_ES1371 && s->rev == ES1371REV_CT5880_A) || (s->device == PCI_DEVICE_ID_ENSONIQ_ES1371 && s->rev == ES1371REV_ES1373_8))) { cssr |= CSTAT_5880_AC97_RST; @@ -2853,7 +2917,7 @@ src_init(s); /* codec init */ if (!ac97_probe_codec(&s->codec)) - goto err_dev4; + goto err_gp; /* set default values */ fs = get_fs(); @@ -2873,6 +2937,8 @@ set_fs(fs); /* turn on S/PDIF output driver if requested */ outl(cssr, s->io+ES1371_REG_STATUS); + /* register gameport */ + gameport_register_port(&s->gameport); /* store it in the driver field */ pci_set_drvdata(pcidev, s); /* put it into driver list */ @@ -2882,6 +2948,9 @@ devindex++; return 0; + err_gp: + if (s->gameport.io) + release_region(s->gameport.io, s->gameport.size); err_dev4: unregister_sound_dsp(s->dev_dac); err_dev3: @@ -2913,6 +2982,10 @@ outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */ synchronize_irq(); free_irq(s->irq, s); + if (s->gameport.io) { + gameport_unregister_port(&s->gameport); + release_region(s->gameport.io, s->gameport.size); + } release_region(s->io, ES1371_EXTENT); unregister_sound_dsp(s->dev_audio); unregister_sound_mixer(s->codec.dev_mixer); @@ -2942,7 +3015,7 @@ { if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO PFX "version v0.27 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO PFX "version v0.30 time " __TIME__ " " __DATE__ "\n"); return pci_module_init(&es1371_driver); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/esssolo1.c linux.ac/drivers/sound/esssolo1.c --- linux.vanilla/drivers/sound/esssolo1.c Tue Apr 3 17:32:22 2001 +++ linux.ac/drivers/sound/esssolo1.c Thu Apr 12 12:04:32 2001 @@ -3,7 +3,7 @@ /* * esssolo1.c -- ESS Technology Solo1 (ES1946) audio driver. * - * Copyright (C) 1998-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) + * Copyright (C) 1998-2001 Thomas Sailer (t.sailer@alumni.ethz.ch) * * 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 @@ -70,6 +70,13 @@ * 19.02.2000 0.14 Use pci_dma_supported to determine if recording should be disabled * 13.03.2000 0.15 Reintroduce initialization of a couple of PCI config space registers * 21.11.2000 0.16 Initialize dma buffers in poll, otherwise poll may return a bogus mask + * 12.12.2000 0.17 More dma buffer initializations, patch from + * Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com> + * 31.01.2001 0.18 Register/Unregister gameport, original patch from + * Nathaniel Daw <daw@cs.cmu.edu> + * Fix SETTRIGGER non OSS API conformity + * 10.03.2001 provide abs function, prevent picking up a bogus kernel macro + * for abs. Bug report by Andrew Morton <andrewm@uow.edu.au> */ /*****************************************************************************/ @@ -98,12 +105,40 @@ #include "dm.h" +#if defined(CONFIG_INPUT_ANALOG) || defined(CONFIG_INPUT_ANALOG_MODULE) +#include <linux/gameport.h> +#else +struct gameport { + int io; + int size; +}; + +extern inline void gameport_register_port(struct gameport *gameport) +{ +} + +extern inline void gameport_unregister_port(struct gameport *gameport) +{ +} +#endif + /* --------------------------------------------------------------------- */ #undef OSS_DOCUMENTED_MIXER_SEMANTICS /* --------------------------------------------------------------------- */ +/* prevent picking up a bogus abs macro */ +#undef abs +extern inline int abs(int x) +{ + if (x < 0) + return -x; + return x; +} + +/* --------------------------------------------------------------------- */ + #ifndef PCI_VENDOR_ID_ESS #define PCI_VENDOR_ID_ESS 0x125d #endif @@ -154,7 +189,7 @@ int dev_dmfm; /* hardware resources */ - unsigned long iobase, sbbase, vcbase, ddmabase, mpubase, gpbase; /* long for SPARC */ + unsigned long iobase, sbbase, vcbase, ddmabase, mpubase; /* long for SPARC */ unsigned int irq; /* mixer registers */ @@ -196,6 +231,7 @@ unsigned mapped:1; unsigned ready:1; unsigned endcleared:1; + unsigned enabled:1; unsigned ossfragshift; int ossmaxfrags; unsigned subdivision; @@ -211,6 +247,8 @@ unsigned char ibuf[MIDIINBUF]; unsigned char obuf[MIDIOUTBUF]; } midi; + + struct gameport gameport; }; /* --------------------------------------------------------------------- */ @@ -465,6 +503,7 @@ db->numfrag = db->ossmaxfrags; db->fragsamples = db->fragsize >> sample_shift; db->dmasize = db->numfrag << db->fragshift; + db->enabled = 1; return 0; } @@ -1024,7 +1063,8 @@ read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc), cnt); #endif if (cnt <= 0) { - start_adc(s); + if (s->dma_adc.enabled) + start_adc(s); #ifdef DEBUGREC printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n" KERN_DEBUG "solo1_read: regs: B1: 0x%02x B2: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n" @@ -1071,7 +1111,8 @@ count -= cnt; buffer += cnt; ret += cnt; - start_adc(s); + if (s->dma_adc.enabled) + start_adc(s); #ifdef DEBUGREC printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x DMAstat: 0x%02x DMAcnt: 0x%04x SBstat: 0x%02x\n", read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc)); @@ -1126,7 +1167,8 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - start_dac(s); + if (s->dma_dac.enabled) + start_dac(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; @@ -1154,7 +1196,8 @@ count -= cnt; buffer += cnt; ret += cnt; - start_dac(s); + if (s->dma_dac.enabled) + start_dac(s); } remove_wait_queue(&s->dma_dac.wait, &wait); set_current_state(TASK_RUNNING); @@ -1370,27 +1413,33 @@ if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) return ret; + s->dma_dac.enabled = 1; start_adc(s); if (inb(s->ddmabase+15) & 1) printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n"); - } else + } else { + s->dma_dac.enabled = 0; stop_adc(s); + } } if (file->f_mode & FMODE_WRITE) { if (val & PCM_ENABLE_OUTPUT) { if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) return ret; + s->dma_dac.enabled = 1; start_dac(s); - } else + } else { + s->dma_dac.enabled = 0; stop_dac(s); + } } return 0; case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) - return ret; + if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); solo1_update_ptr(s); abinfo.fragsize = s->dma_dac.fragsize; @@ -1406,8 +1455,8 @@ case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; + if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); solo1_update_ptr(s); abinfo.fragsize = s->dma_adc.fragsize; @@ -1424,8 +1473,8 @@ case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) - return ret; + if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); solo1_update_ptr(s); count = s->dma_dac.count; @@ -1437,8 +1486,8 @@ case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; + if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); solo1_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; @@ -1452,8 +1501,8 @@ case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) - return ret; + if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); solo1_update_ptr(s); cinfo.bytes = s->dma_dac.total_bytes; @@ -1606,7 +1655,9 @@ s->clkdiv = 96 | 0x80; s->ena = 0; s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; + s->dma_adc.enabled = 1; s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0; + s->dma_dac.enabled = 1; s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); up(&s->open_sem); prog_codec(s); @@ -1933,6 +1984,7 @@ if (file->f_flags & O_NONBLOCK) { remove_wait_queue(&s->midi.owait, &wait); set_current_state(TASK_RUNNING); + unlock_kernel(); return -EBUSY; } tmo = (count * HZ) / 3100; @@ -2281,7 +2333,8 @@ s->vcbase = pci_resource_start(pcidev, 2); s->ddmabase = s->vcbase + DDMABASE_OFFSET; s->mpubase = pci_resource_start(pcidev, 3); - s->gpbase = pci_resource_start(pcidev, 4); + s->gameport.io = pci_resource_start(pcidev, 4); + s->gameport.size = pci_resource_len(pcidev,4); s->irq = pcidev->irq; if (!request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1")) { printk(KERN_ERR "solo1: io ports in use\n"); @@ -2299,13 +2352,19 @@ printk(KERN_ERR "solo1: io ports in use\n"); goto err_region4; } + if (!s->gameport.size) + s->gameport.io = 0; + if (s->gameport.io && !request_region(s->gameport.io, s->gameport.size, "ESS Solo1")) { + printk(KERN_ERR "solo1: gameport io ports in use\n"); + s->gameport.io = s->gameport.size = 0; + } if (request_irq(s->irq, solo1_interrupt, SA_SHIRQ, "ESS Solo1", s)) { printk(KERN_ERR "solo1: irq %u in use\n", s->irq); goto err_irq; } if (pci_enable_device(pcidev)) goto err_irq; - printk(KERN_INFO "solo1: joystick port at %#lx\n", s->gpbase+1); + printk(KERN_INFO "solo1: joystick port at %#x\n", s->gameport.io+1); /* register devices */ if ((s->dev_audio = register_sound_dsp(&solo1_audio_fops, -1)) < 0) goto err_dev1; @@ -2317,6 +2376,8 @@ goto err_dev4; if (setup_solo1(s)) goto err; + /* register gameport */ + gameport_register_port(&s->gameport); /* store it in the driver field */ pci_set_drvdata(pcidev, s); /* put it into driver list */ @@ -2340,6 +2401,8 @@ printk(KERN_ERR "solo1: initialisation error\n"); free_irq(s->irq, s); err_irq: + if (s->gameport.io) + release_region(s->gameport.io, s->gameport.size); release_region(s->iobase, IOBASE_EXTENT); err_region4: release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT); @@ -2366,6 +2429,10 @@ synchronize_irq(); pci_write_config_word(s->dev, 0x60, 0); /* turn off DDMA controller address space */ free_irq(s->irq, s); + if (s->gameport.io) { + gameport_unregister_port(&s->gameport); + release_region(s->gameport.io, s->gameport.size); + } release_region(s->iobase, IOBASE_EXTENT); release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT); release_region(s->ddmabase, DDMABASE_EXTENT); @@ -2397,7 +2464,7 @@ { if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "solo1: version v0.16 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "solo1: version v0.18 time " __TIME__ " " __DATE__ "\n"); if (!pci_register_driver(&solo1_driver)) { pci_unregister_driver(&solo1_driver); return -ENODEV; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/i810_audio.c linux.ac/drivers/sound/i810_audio.c --- linux.vanilla/drivers/sound/i810_audio.c Tue Apr 3 17:32:22 2001 +++ linux.ac/drivers/sound/i810_audio.c Tue Apr 17 15:35:58 2001 @@ -101,8 +101,11 @@ #endif static int ftsodell=0; +static int strict_clocking=0; static unsigned int clocking=48000; +//#define DEBUG +//#define DEBUG2 #define ADC_RUNNING 1 #define DAC_RUNNING 2 @@ -169,6 +172,7 @@ #define DMA_INT_COMPLETE (1<<3) /* buffer read/write complete and ioc set */ #define DMA_INT_LVI (1<<2) /* last valid done */ #define DMA_INT_CELV (1<<1) /* last valid is current */ +#define DMA_INT_DCH (1) /* DMA Controller Halted (happens on LVI interrupts) */ #define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI) /* interrupts for the whole chip */ @@ -183,7 +187,7 @@ #define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI) -#define DRIVER_VERSION "0.01" +#define DRIVER_VERSION "0.02" /* magic numbers to protect our data structures */ #define I810_CARD_MAGIC 0x5072696E /* "Prin" */ @@ -247,7 +251,7 @@ struct dmabuf { /* wave sample stuff */ unsigned int rate; - unsigned char fmt, enable; + unsigned char fmt, enable, trigger; /* hardware channel */ struct i810_channel *read_channel; @@ -277,10 +281,9 @@ /* OSS stuff */ unsigned mapped:1; unsigned ready:1; - unsigned endcleared:1; unsigned update_flag; - unsigned ossfragshift; - int ossmaxfrags; + unsigned ossfragsize; + unsigned ossmaxfrags; unsigned subdivision; } dmabuf; }; @@ -408,8 +411,11 @@ /* * Adjust for misclocked crap */ - rate = ( rate * clocking)/48000; + if(strict_clocking && rate < 8000) { + rate = 8000; + dmabuf->rate = (rate * 48000)/clocking; + } if(rate != i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE)) { @@ -456,6 +462,10 @@ */ rate = ( rate * clocking)/48000; + if(strict_clocking && rate < 8000) { + rate = 8000; + dmabuf->rate = (rate * 48000)/clocking; + } if(rate != i810_ac97_get(codec, AC97_PCM_LR_DAC_RATE)) { @@ -478,34 +488,10 @@ return dmabuf->rate; } -/* prepare channel attributes for playback */ -static void i810_play_setup(struct i810_state *state) -{ -// struct dmabuf *dmabuf = &state->dmabuf; -// struct i810_channel *channel = dmabuf->channel; - /* Fixed format. .. */ - //if (dmabuf->fmt & I810_FMT_16BIT) - //if (dmabuf->fmt & I810_FMT_STEREO) -} - -/* prepare channel attributes for recording */ -static void i810_rec_setup(struct i810_state *state) -{ -// u16 w; -// struct i810_card *card = state->card; -// struct dmabuf *dmabuf = &state->dmabuf; -// struct i810_channel *channel = dmabuf->channel; - - /* Enable AC-97 ADC (capture) */ -// if (dmabuf->fmt & I810_FMT_16BIT) { -// if (dmabuf->fmt & I810_FMT_STEREO) -} - - /* get current playback/recording dma buffer pointer (byte offset from LBA), called with spinlock held! */ -extern __inline__ unsigned i810_get_dma_addr(struct i810_state *state) +extern __inline__ unsigned i810_get_dma_addr(struct i810_state *state, int rec) { struct dmabuf *dmabuf = &state->dmabuf; unsigned int civ, offset; @@ -513,17 +499,13 @@ if (!dmabuf->enable) return 0; - if (dmabuf->enable & DAC_RUNNING) - c = dmabuf->write_channel; - else if (dmabuf->enable & ADC_RUNNING) + if (rec) c = dmabuf->read_channel; - else { - printk("i810_audio: invalid dmabuf->enable state in get_dma_addr\n"); - return 0; - } + else + c = dmabuf->write_channel; do { civ = inb(state->card->iobase+c->port+OFF_CIV); - offset = (civ + 1) * (dmabuf->dmasize/SG_LEN) - + offset = (civ + 1) * dmabuf->fragsize - 2 * inw(state->card->iobase+c->port+OFF_PICB); /* CIV changed before we read PICB (very seldom) ? * then PICB was rubbish, so try again */ @@ -532,22 +514,26 @@ return offset; } -static void resync_dma_ptrs(struct i810_state *state, int rec) -{ - struct dmabuf *dmabuf = &state->dmabuf; - struct i810_channel *c; - int offset; - - if(rec) { - c = dmabuf->read_channel; - } else { - c = dmabuf->write_channel; - } - offset = inb(state->card->iobase+c->port+OFF_CIV); - offset *= (dmabuf->dmasize/SG_LEN); - - dmabuf->hwptr=dmabuf->swptr = offset; -} +//static void resync_dma_ptrs(struct i810_state *state, int rec) +//{ +// struct dmabuf *dmabuf = &state->dmabuf; +// struct i810_channel *c; +// int offset; +// +// if(rec) { +// c = dmabuf->read_channel; +// } else { +// c = dmabuf->write_channel; +// } +// if(c==NULL) +// return; +// offset = inb(state->card->iobase+c->port+OFF_CIV); +// if(offset == inb(state->card->iobase+c->port+OFF_LVI)) +// offset++; +// offset *= dmabuf->fragsize; +// +// dmabuf->hwptr=dmabuf->swptr = offset; +//} /* Stop recording (lock held) */ extern __inline__ void __stop_adc(struct i810_state *state) @@ -575,12 +561,13 @@ struct i810_card *card = state->card; unsigned long flags; - spin_lock_irqsave(&card->lock, flags); - if ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize) && dmabuf->ready) { + if (dmabuf->count < dmabuf->dmasize && dmabuf->ready && !dmabuf->enable && + (dmabuf->trigger & PCM_ENABLE_INPUT)) { + spin_lock_irqsave(&card->lock, flags); dmabuf->enable |= ADC_RUNNING; - outb((1<<4) | 1<<2 | 1, card->iobase + PI_CR); + outb((1<<4) | (1<<2) | 1, card->iobase + PI_CR); + spin_unlock_irqrestore(&card->lock, flags); } - spin_unlock_irqrestore(&card->lock, flags); } /* stop playback (lock held) */ @@ -609,12 +596,13 @@ struct i810_card *card = state->card; unsigned long flags; - spin_lock_irqsave(&card->lock, flags); - if ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) { + if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable && + (dmabuf->trigger & PCM_ENABLE_OUTPUT)) { + spin_lock_irqsave(&card->lock, flags); dmabuf->enable |= DAC_RUNNING; - outb((1<<4) | 1<<2 | 1, card->iobase + PO_CR); + outb((1<<4) | (1<<2) | 1, card->iobase + PO_CR); + spin_unlock_irqrestore(&card->lock, flags); } - spin_unlock_irqrestore(&card->lock, flags); } #define DMABUF_DEFAULTORDER (16-PAGE_SHIFT) @@ -625,18 +613,29 @@ { struct dmabuf *dmabuf = &state->dmabuf; void *rawbuf= NULL; - int order; + int order, size; struct page *page, *pend; - /* alloc as big a chunk as we can, FIXME: is this necessary ?? */ - for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) + /* If we don't have any oss frag params, then use our default ones */ + if(dmabuf->ossmaxfrags == 0) + dmabuf->ossmaxfrags = 4; + if(dmabuf->ossfragsize == 0) + dmabuf->ossfragsize = (PAGE_SIZE<<DMABUF_DEFAULTORDER)/dmabuf->ossmaxfrags; + size = dmabuf->ossfragsize * dmabuf->ossmaxfrags; + + /* alloc enough to satisfy the oss params */ + for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) { + if ( (PAGE_SIZE<<order) > size ) + continue; if ((rawbuf = pci_alloc_consistent(state->card->pci_dev, PAGE_SIZE << order, &dmabuf->dma_handle))) break; + } if (!rawbuf) return -ENOMEM; + #ifdef DEBUG printk("i810_audio: allocated %ld (order = %d) bytes at %p\n", PAGE_SIZE << order, order, rawbuf); @@ -677,52 +676,53 @@ struct dmabuf *dmabuf = &state->dmabuf; struct i810_channel *c; struct sg_item *sg; - unsigned bytepersec; - unsigned bufsize; unsigned long flags; int ret; - unsigned fragsize; + unsigned fragint; int i; spin_lock_irqsave(&state->card->lock, flags); - resync_dma_ptrs(state, rec); + if(dmabuf->enable & DAC_RUNNING) + __stop_dac(state); + if(dmabuf->enable & ADC_RUNNING) + __stop_adc(state); dmabuf->total_bytes = 0; dmabuf->count = dmabuf->error = 0; + dmabuf->swptr = dmabuf->hwptr = 0; spin_unlock_irqrestore(&state->card->lock, flags); /* allocate DMA buffer if not allocated yet */ - if (!dmabuf->rawbuf) - if ((ret = alloc_dmabuf(state))) - return ret; + if (dmabuf->rawbuf) + dealloc_dmabuf(state); + if ((ret = alloc_dmabuf(state))) + return ret; /* FIXME: figure out all this OSS fragment stuff */ - /* sample_shift is for 16 byte samples, add an extra shift for bytes */ - bytepersec = dmabuf->rate << (sample_shift[dmabuf->fmt] + 1); - bufsize = PAGE_SIZE << dmabuf->buforder; - if (dmabuf->ossfragshift) { - if ((1000 << dmabuf->ossfragshift) < bytepersec) - dmabuf->fragshift = ld2(bytepersec/1000); - else - dmabuf->fragshift = dmabuf->ossfragshift; + /* I did, it now does what it should according to the OSS API. DL */ + dmabuf->dmasize = PAGE_SIZE << dmabuf->buforder; + dmabuf->numfrag = SG_LEN; + dmabuf->fragsize = dmabuf->dmasize/dmabuf->numfrag; + dmabuf->fragsamples = dmabuf->fragsize >> 1; + + memset(dmabuf->rawbuf, 0, dmabuf->dmasize); + + if(dmabuf->ossmaxfrags == 4) { + fragint = 8; + dmabuf->ossfragsize = dmabuf->dmasize>>2; + dmabuf->fragshift = 2; + } else if (dmabuf->ossmaxfrags == 8) { + fragint = 4; + dmabuf->ossfragsize = dmabuf->dmasize>>3; + dmabuf->fragshift = 3; + } else if (dmabuf->ossmaxfrags == 16) { + fragint = 2; + dmabuf->ossfragsize = dmabuf->dmasize>>4; + dmabuf->fragshift = 4; } else { - /* lets hand out reasonable big ass buffers by default */ - dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2); + fragint = 1; + dmabuf->ossfragsize = dmabuf->dmasize>>5; + dmabuf->fragshift = 5; } - dmabuf->numfrag = bufsize >> dmabuf->fragshift; - while (dmabuf->numfrag < 4 && dmabuf->fragshift > 3) { - dmabuf->fragshift--; - dmabuf->numfrag = bufsize >> dmabuf->fragshift; - } - dmabuf->fragsize = 1 << dmabuf->fragshift; - if (dmabuf->ossmaxfrags >= 4 && dmabuf->ossmaxfrags < dmabuf->numfrag) - dmabuf->numfrag = dmabuf->ossmaxfrags; - dmabuf->fragsamples = dmabuf->fragsize >> sample_shift[dmabuf->fmt]; - dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift; - - memset(dmabuf->rawbuf, (dmabuf->fmt & I810_FMT_16BIT) ? 0 : 0x80, - dmabuf->dmasize); - - fragsize = bufsize / SG_LEN; /* * Now set up the ring */ @@ -737,24 +737,26 @@ * way (we might want more interrupts later..) */ - for(i=0;i<32;i++) + for(i=0;i<dmabuf->numfrag;i++) { - sg->busaddr=virt_to_bus(dmabuf->rawbuf+fragsize*i); - sg->control=(fragsize>>sample_shift[dmabuf->fmt]); - sg->control|=CON_IOC; + sg->busaddr=virt_to_bus(dmabuf->rawbuf+dmabuf->fragsize*i); + // the card will always be doing 16bit stereo + sg->control=dmabuf->fragsamples; + sg->control|=CON_BUFPAD; + // set us up to get IOC interrupts as often as needed to + // satisfy numfrag requirements, no more + if( ((i+1) % fragint) == 0) { + sg->control|=CON_IOC; + } sg++; } spin_lock_irqsave(&state->card->lock, flags); outb(2, state->card->iobase+c->port+OFF_CR); /* reset DMA machine */ outl(virt_to_bus(&c->sg[0]), state->card->iobase+c->port+OFF_BDBAR); - outb(31, state->card->iobase+c->port+OFF_LVI); outb(0, state->card->iobase+c->port+OFF_CIV); + outb(0, state->card->iobase+c->port+OFF_LVI); + dmabuf->count = 0; - if (c == dmabuf->read_channel) { - i810_rec_setup(state); - } else { - i810_play_setup(state); - } spin_unlock_irqrestore(&state->card->lock, flags); if(c != dmabuf->write_channel) @@ -775,36 +777,115 @@ return 0; } -/* - * Clear the rest of the last i810 dma buffer, normally there is no rest - * because the OSS fragment size is the same as the size of this buffer. - */ -static void i810_clear_tail(struct i810_state *state) + +static void __i810_update_lvi(struct i810_state *state, int rec) { struct dmabuf *dmabuf = &state->dmabuf; - unsigned swptr; - unsigned char silence = (dmabuf->fmt & I810_FMT_16BIT) ? 0 : 0x80; - unsigned int len; - unsigned long flags; + int x, port; + + port = state->card->iobase; + if(rec) + port += dmabuf->read_channel->port; + else + port += dmabuf->write_channel->port; - spin_lock_irqsave(&state->card->lock, flags); - swptr = dmabuf->swptr; - spin_unlock_irqrestore(&state->card->lock, flags); + if(dmabuf->mapped) { + if(rec) + dmabuf->swptr = (dmabuf->hwptr + dmabuf->dmasize + - dmabuf->count) % dmabuf->dmasize; + else + dmabuf->swptr = (dmabuf->hwptr + dmabuf->count) + % dmabuf->dmasize; + } + /* + * two special cases, count == 0 on write + * means no data, and count == dmasize + * means no data on read, handle appropriately + */ + if(!rec && dmabuf->count == 0) { + outb(inb(port+OFF_CIV),port+OFF_LVI); + return; + } + if(rec && dmabuf->count == dmabuf->dmasize) { + outb(inb(port+OFF_CIV),port+OFF_LVI); + return; + } + /* swptr - 1 is the tail of our transfer */ + x = (dmabuf->dmasize + dmabuf->swptr - 1) % dmabuf->dmasize; + x /= dmabuf->fragsize; + outb(x&31, port+OFF_LVI); +} - if(dmabuf->dmasize) - len = swptr % (dmabuf->dmasize/SG_LEN); - else - len = 0; - - memset(dmabuf->rawbuf + swptr, silence, len); +static void i810_update_lvi(struct i810_state *state, int rec) +{ + struct dmabuf *dmabuf = &state->dmabuf; + unsigned long flags; + if(!dmabuf->ready) + return; spin_lock_irqsave(&state->card->lock, flags); - dmabuf->swptr += len; - dmabuf->count += len; + __i810_update_lvi(state, rec); spin_unlock_irqrestore(&state->card->lock, flags); +} - /* restart the dma machine in case it is halted */ - start_dac(state); +/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */ +static void i810_update_ptr(struct i810_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + unsigned hwptr; + int diff; + + /* error handling and process wake up for DAC */ + if (dmabuf->enable == ADC_RUNNING) { + /* update hardware pointer */ + hwptr = i810_get_dma_addr(state, 1); + diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; +// printk("HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff); + dmabuf->hwptr = hwptr; + dmabuf->total_bytes += diff; + dmabuf->count += diff; + if (dmabuf->count > dmabuf->dmasize) { + /* buffer underrun or buffer overrun */ + /* this is normal for the end of a read */ + /* only give an error if we went past the */ + /* last valid sg entry */ + if(inb(state->card->iobase + PI_CIV) != + inb(state->card->iobase + PI_LVI)) { + printk(KERN_WARNING "i810_audio: DMA overrun on read\n"); + dmabuf->error++; + } + } + if (dmabuf->count > dmabuf->ossfragsize) + wake_up(&dmabuf->wait); + } + /* error handling and process wake up for DAC */ + if (dmabuf->enable == DAC_RUNNING) { + /* update hardware pointer */ + hwptr = i810_get_dma_addr(state, 0); + diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; +// printk("HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff); + dmabuf->hwptr = hwptr; + dmabuf->total_bytes += diff; + dmabuf->count -= diff; + if (dmabuf->count < 0) { + /* buffer underrun or buffer overrun */ + /* this is normal for the end of a write */ + /* only give an error if we went past the */ + /* last valid sg entry */ + if(inb(state->card->iobase + PO_CIV) != + inb(state->card->iobase + PO_LVI)) { + printk(KERN_WARNING "i810_audio: DMA overrun on write\n"); + printk("i810_audio: CIV %d, LVI %d, hwptr %x, " + "count %d\n", + inb(state->card->iobase + PO_CIV), + inb(state->card->iobase + PO_LVI), + dmabuf->hwptr, dmabuf->count); + dmabuf->error++; + } + } + if (dmabuf->count < (dmabuf->dmasize-dmabuf->ossfragsize)) + wake_up(&dmabuf->wait); + } } static int drain_dac(struct i810_state *state, int nonblock) @@ -815,7 +896,7 @@ unsigned long tmo; int count; - if (dmabuf->mapped || !dmabuf->ready) + if (!dmabuf->ready) return 0; add_wait_queue(&dmabuf->wait, &wait); @@ -825,6 +906,7 @@ current->state = TASK_INTERRUPTIBLE; spin_lock_irqsave(&state->card->lock, flags); + i810_update_ptr(state); count = dmabuf->count; spin_unlock_irqrestore(&state->card->lock, flags); @@ -834,6 +916,10 @@ if (signal_pending(current)) break; + i810_update_lvi(state,0); + if (dmabuf->enable != DAC_RUNNING) + start_dac(state); + if (nonblock) { remove_wait_queue(&dmabuf->wait, &wait); current->state = TASK_RUNNING; @@ -841,7 +927,7 @@ } tmo = (dmabuf->dmasize * HZ) / dmabuf->rate; - tmo >>= sample_shift[dmabuf->fmt]; + tmo >>= 1; if (!schedule_timeout(tmo ? tmo : 1) && tmo){ printk(KERN_ERR "i810_audio: drain_dac, dma timeout?\n"); break; @@ -855,88 +941,18 @@ return 0; } -/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */ -static void i810_update_ptr(struct i810_state *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - unsigned hwptr, swptr; - int clear_cnt = 0; - int diff; - unsigned char silence; -// unsigned half_dmasize; - - /* update hardware pointer */ - hwptr = i810_get_dma_addr(state); - diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; -// printk("HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff); - dmabuf->hwptr = hwptr; - dmabuf->total_bytes += diff; - - /* error handling and process wake up for DAC */ - if (dmabuf->enable == ADC_RUNNING) { - if (dmabuf->mapped) { - dmabuf->count -= diff; - if (dmabuf->count >= (signed)dmabuf->fragsize) - wake_up(&dmabuf->wait); - } else { - dmabuf->count += diff; - - if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) { - /* buffer underrun or buffer overrun, we have no way to recover - it here, just stop the machine and let the process force hwptr - and swptr to sync */ - __stop_adc(state); - dmabuf->error++; - } - else if (!dmabuf->endcleared) { - swptr = dmabuf->swptr; - silence = (dmabuf->fmt & I810_FMT_16BIT ? 0 : 0x80); - if (dmabuf->count < (signed) dmabuf->fragsize) - { - clear_cnt = dmabuf->fragsize; - if ((swptr + clear_cnt) > dmabuf->dmasize) - clear_cnt = dmabuf->dmasize - swptr; - memset (dmabuf->rawbuf + swptr, silence, clear_cnt); - dmabuf->endcleared = 1; - } - } - if (dmabuf->count < (signed)dmabuf->dmasize/2) { - wake_up(&dmabuf->wait); - } - } - } - /* error handling and process wake up for DAC */ - if (dmabuf->enable == DAC_RUNNING) { - if (dmabuf->mapped) { - dmabuf->count += diff; - if (dmabuf->count >= (signed)dmabuf->fragsize) - wake_up(&dmabuf->wait); - } else { - dmabuf->count -= diff; - - if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) { - /* buffer underrun or buffer overrun, we have no way to recover - it here, just stop the machine and let the process force hwptr - and swptr to sync */ - __stop_dac(state); - printk(KERN_WARNING "i810_audio: DMA overrun on send\n"); - dmabuf->error++; - } - if (dmabuf->count < (signed)dmabuf->dmasize/2) { - wake_up(&dmabuf->wait); - } - } - } -} - static void i810_channel_interrupt(struct i810_card *card) { - int i; - + int i, count; + +#ifdef DEBUG_INTERRUPTS + printk("CHANNEL "); +#endif for(i=0;i<NR_HW_CH;i++) { struct i810_state *state = card->states[i]; struct i810_channel *c; + struct dmabuf *dmabuf; unsigned long port = card->iobase; u16 status; @@ -944,35 +960,56 @@ continue; if(!state->dmabuf.ready) continue; - if(state->dmabuf.enable & DAC_RUNNING) - c=state->dmabuf.write_channel; + dmabuf = &state->dmabuf; + if(dmabuf->enable & DAC_RUNNING) + c=dmabuf->write_channel; else - c=state->dmabuf.read_channel; + c=dmabuf->read_channel; port+=c->port; status = inw(port + OFF_SR); - +#ifdef DEBUG_INTERRUPTS + printk("NUM %d PORT %lX IRQ ( ST%d ", c->num, c->port, status); +#endif if(status & DMA_INT_COMPLETE) { - int x; - /* Keep the card chasing its tail */ - outb(x=((inb(port+OFF_CIV)-1)&31), port+OFF_LVI); i810_update_ptr(state); +#ifdef DEBUG_INTERRUPTS + printk("COMP%d ",x); +#endif } if(status & DMA_INT_LVI) { - /* Back to the start */ i810_update_ptr(state); - outb(0, port + OFF_CR); + wake_up(&dmabuf->wait); +#ifdef DEBUG_INTERRUPTS + printk("LVI "); +#endif + } + if(status & DMA_INT_DCH) + { + i810_update_ptr(state); + if(dmabuf->enable & DAC_RUNNING) + count = dmabuf->count; + else + count = dmabuf->dmasize - dmabuf->count; + if(count > 0) { + outb(inb(port+OFF_CR) | 1, port+OFF_CR); + } else { + wake_up(&dmabuf->wait); +#ifdef DEBUG_INTERRUPTS + printk("DCH - STOP "); +#endif + } } outw(status & DMA_INT_MASK, port + OFF_SR); } +#ifdef DEBUG_INTERRUPTS + printk(")\n"); +#endif } -static u32 jiff = 0; -static u32 jiff_count = 0; - static void i810_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct i810_card *card = (struct i810_card *)dev_id; @@ -1009,10 +1046,10 @@ struct dmabuf *dmabuf = &state->dmabuf; ssize_t ret; unsigned long flags; - unsigned swptr; + unsigned int swptr; int cnt; -#ifdef DEBUG +#ifdef DEBUG2 printk("i810_audio: i810_read called, count = %d\n", count); #endif @@ -1026,43 +1063,45 @@ dmabuf->ready = 0; dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card); if (!dmabuf->read_channel) { - return -ENODEV; + return -EBUSY; } } if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) return ret; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; + dmabuf->trigger &= ~PCM_ENABLE_OUTPUT; ret = 0; while (count > 0) { spin_lock_irqsave(&state->card->lock, flags); - if (dmabuf->count > (signed) dmabuf->dmasize) { - /* buffer overrun, we are recovering from sleep_on_timeout, - resync hwptr and swptr, make process flush the buffer */ - dmabuf->count = dmabuf->dmasize; - dmabuf->swptr = dmabuf->hwptr; - } swptr = dmabuf->swptr; - cnt = dmabuf->dmasize - swptr; - if (dmabuf->count < cnt) - cnt = dmabuf->count; + if (dmabuf->count > dmabuf->dmasize) { + dmabuf->count = 0; + } + cnt = dmabuf->count; + if(cnt > (dmabuf->dmasize - swptr)) + cnt = dmabuf->dmasize - swptr; spin_unlock_irqrestore(&state->card->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { unsigned long tmo; - /* buffer is empty, start the dma machine and wait for data to be - recorded */ - start_adc(state); + // are we already running? only start us if we aren't running + // currently + i810_update_lvi(state,1); + if(!dmabuf->enable) { + dmabuf->trigger |= PCM_ENABLE_INPUT; + start_adc(state); + } if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; return ret; } /* This isnt strictly right for the 810 but it'll do */ tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); - tmo >>= sample_shift[dmabuf->fmt]; + tmo >>= 1; /* There are two situations when sleep_on_timeout returns, one is when the interrupt is serviced correctly and the process is waked up by ISR ON TIME. Another is when timeout is expired, which means that @@ -1102,8 +1141,9 @@ count -= cnt; buffer += cnt; ret += cnt; - start_adc(state); } + i810_update_lvi(state,1); + start_adc(state); return ret; } @@ -1115,10 +1155,10 @@ struct dmabuf *dmabuf = &state->dmabuf; ssize_t ret; unsigned long flags; - unsigned swptr; - int cnt; + unsigned int swptr = 0; + int cnt, x; -#ifdef DEBUG +#ifdef DEBUG2 printk("i810_audio: i810_write called, count = %d\n", count); #endif @@ -1132,25 +1172,23 @@ dmabuf->ready = 0; dmabuf->write_channel = state->card->alloc_pcm_channel(state->card); if(!dmabuf->write_channel) - return -ENODEV; + return -EBUSY; } if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) return ret; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; + dmabuf->trigger &= ~PCM_ENABLE_INPUT; ret = 0; while (count > 0) { spin_lock_irqsave(&state->card->lock, flags); + swptr = dmabuf->swptr; if (dmabuf->count < 0) { - /* buffer underrun, we are recovering from sleep_on_timeout, - resync hwptr and swptr */ dmabuf->count = 0; - dmabuf->swptr = dmabuf->hwptr; } - swptr = dmabuf->swptr; cnt = dmabuf->dmasize - swptr; - if (dmabuf->count + cnt > dmabuf->dmasize) + if(cnt > (dmabuf->dmasize - dmabuf->count)) cnt = dmabuf->dmasize - dmabuf->count; spin_unlock_irqrestore(&state->card->lock, flags); @@ -1158,16 +1196,20 @@ cnt = count; if (cnt <= 0) { unsigned long tmo; - /* buffer is full, start the dma machine and wait for data to be - played */ - start_dac(state); + // There is data waiting to be played + i810_update_lvi(state,0); + if(!dmabuf->enable && dmabuf->count) { + /* force the starting incase SETTRIGGER has been used */ + /* to stop it, otherwise this is a deadlock situation */ + dmabuf->trigger |= PCM_ENABLE_OUTPUT; + start_dac(state); + } if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; return ret; } /* Not strictly correct but works */ - tmo = dmabuf->rate << (sample_shift[dmabuf->fmt] + 1); - tmo = dmabuf->dmasize * HZ / tmo; + tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 4); /* There are two situations when sleep_on_timeout returns, one is when the interrupt is serviced correctly and the process is waked up by ISR ON TIME. Another is when timeout is expired, which means that @@ -1184,6 +1226,7 @@ #endif /* a buffer underrun, we delay the recovery until next time the while loop begin and we REALLY have data to play */ + //return ret; } if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; @@ -1191,7 +1234,7 @@ } continue; } - if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) { + if (copy_from_user(dmabuf->rawbuf+swptr,buffer,cnt)) { if (!ret) ret = -EFAULT; return ret; } @@ -1201,14 +1244,21 @@ spin_lock_irqsave(&state->card->lock, flags); dmabuf->swptr = swptr; dmabuf->count += cnt; - dmabuf->endcleared = 0; spin_unlock_irqrestore(&state->card->lock, flags); count -= cnt; buffer += cnt; ret += cnt; - start_dac(state); } + if (swptr % dmabuf->fragsize) { + x = dmabuf->fragsize - (swptr % dmabuf->fragsize); + if((x + dmabuf->count) < dmabuf->dmasize) + memset(dmabuf->rawbuf + swptr, '\0', x); + } + i810_update_lvi(state,0); + if (!dmabuf->enable && dmabuf->count >= dmabuf->ossfragsize) + start_dac(state); + return ret; } @@ -1220,21 +1270,9 @@ unsigned long flags; unsigned int mask = 0; - if (file->f_mode & FMODE_WRITE) { - if (!dmabuf->write_channel) - return 0; - if (!dmabuf->ready && prog_dmabuf(state, 0)) - return 0; - poll_wait(file, &dmabuf->wait, wait); - } else { - // don't do both read and write paths or we won't get woke up properly - // when we have a file with both permissions - if (!dmabuf->read_channel) - return 0; - if (!dmabuf->ready && prog_dmabuf(state, 1)) - return 0; - poll_wait(file, &dmabuf->wait, wait); - } + if(!dmabuf->ready) + return 0; + poll_wait(file, &dmabuf->wait, wait); spin_lock_irqsave(&state->card->lock, flags); i810_update_ptr(state); if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING) { @@ -1262,22 +1300,24 @@ int ret = -EINVAL; unsigned long size; - /* - * Until we figure out a few problems - */ - lock_kernel(); if (vma->vm_flags & VM_WRITE) { - if (!dmabuf->write_channel && (dmabuf->write_channel = state->card->alloc_pcm_channel(state->card)) == NULL) - goto out; - if ((ret = prog_dmabuf(state, 0)) != 0) + if (!dmabuf->write_channel && + (dmabuf->write_channel = + state->card->alloc_pcm_channel(state->card)) == NULL) { + ret = -EBUSY; goto out; - } else if (vma->vm_flags & VM_READ) { - if (!dmabuf->read_channel && (dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card)) == NULL) - goto out; - if ((ret = prog_dmabuf(state, 1)) != 0) + } + } + if (vma->vm_flags & VM_READ) { + if (!dmabuf->read_channel && + (dmabuf->read_channel = + state->card->alloc_rec_pcm_channel(state->card)) == NULL) { + ret = -EBUSY; goto out; - } else + } + } + if ((ret = prog_dmabuf(state, 0)) != 0) goto out; ret = -EINVAL; @@ -1291,9 +1331,13 @@ size, vma->vm_page_prot)) goto out; dmabuf->mapped = 1; + if(vma->vm_flags & VM_WRITE) + dmabuf->count = dmabuf->dmasize; + else + dmabuf->count = 0; ret = 0; #ifdef DEBUG - printk("i810_audio: mmap'ed %d bytes of data space\n", size); + printk("i810_audio: mmap'ed %ld bytes of data space\n", size); #endif out: unlock_kernel(); @@ -1312,41 +1356,52 @@ mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) || ((file->f_mode & FMODE_READ) && dmabuf->mapped); #ifdef DEBUG - printk("i810_audio: i810_ioctl, command = %2d, arg = 0x%08x\n", - _IOC_NR(cmd), arg ? *(int *)arg : 0); + printk("i810_audio: i810_ioctl, arg=0x%x, cmd=", arg ? *(int *)arg : 0); #endif switch (cmd) { case OSS_GETVERSION: +#ifdef DEBUG + printk("OSS_GETVERSION\n"); +#endif return put_user(SOUND_VERSION, (int *)arg); case SNDCTL_DSP_RESET: +#ifdef DEBUG + printk("SNDCTL_DSP_RESET\n"); +#endif /* FIXME: spin_lock ? */ - if (file->f_mode & FMODE_WRITE) { + if (dmabuf->enable == DAC_RUNNING) { stop_dac(state); - synchronize_irq(); - dmabuf->ready = 0; - resync_dma_ptrs(state, 0); - dmabuf->swptr = dmabuf->hwptr = 0; - dmabuf->count = dmabuf->total_bytes = 0; } - if (file->f_mode & FMODE_READ) { + if (dmabuf->enable == ADC_RUNNING) { stop_adc(state); - synchronize_irq(); - resync_dma_ptrs(state, 1); - dmabuf->ready = 0; - dmabuf->swptr = dmabuf->hwptr = 0; - dmabuf->count = dmabuf->total_bytes = 0; } + synchronize_irq(); + dmabuf->ready = 0; + dmabuf->swptr = dmabuf->hwptr = 0; + dmabuf->count = dmabuf->total_bytes = 0; return 0; case SNDCTL_DSP_SYNC: - if (file->f_mode & FMODE_WRITE) - return drain_dac(state, file->f_flags & O_NONBLOCK); +#ifdef DEBUG + printk("SNDCTL_DSP_SYNC\n"); +#endif + if (dmabuf->enable != DAC_RUNNING || file->f_flags & O_NONBLOCK) + return 0; + drain_dac(state, 0); + stop_dac(state); + synchronize_irq(); + dmabuf->ready = 0; + dmabuf->swptr = dmabuf->hwptr = 0; + dmabuf->count = dmabuf->total_bytes = 0; return 0; case SNDCTL_DSP_SPEED: /* set smaple rate */ +#ifdef DEBUG + printk("SNDCTL_DSP_SPEED\n"); +#endif if (get_user(val, (int *)arg)) return -EFAULT; if (val >= 0) { @@ -1368,71 +1423,68 @@ return put_user(dmabuf->rate, (int *)arg); case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ +#ifdef DEBUG + printk("SNDCTL_DSP_STEREO\n"); +#endif if (get_user(val, (int *)arg)) return -EFAULT; - if(val==0) - return -EINVAL; - if (file->f_mode & FMODE_WRITE) { + if(val==0) { + ret = -EINVAL; + } else { + ret = 1; + } + if (dmabuf->enable & DAC_RUNNING) { stop_dac(state); - dmabuf->ready = 0; - dmabuf->fmt |= I810_FMT_STEREO; } - if (file->f_mode & FMODE_READ) { + if (dmabuf->enable & ADC_RUNNING) { stop_adc(state); - dmabuf->ready = 0; - dmabuf->fmt |= I810_FMT_STEREO; } - return 0; + return ret; case SNDCTL_DSP_GETBLKSIZE: if (file->f_mode & FMODE_WRITE) { if (!dmabuf->ready && (val = prog_dmabuf(state, 0))) return val; - return put_user(dmabuf->fragsize, (int *)arg); } if (file->f_mode & FMODE_READ) { if (!dmabuf->ready && (val = prog_dmabuf(state, 1))) return val; - return put_user(dmabuf->fragsize, (int *)arg); } +#ifdef DEBUG + printk("SNDCTL_DSP_GETBLKSIZE %d\n", dmabuf->ossfragsize); +#endif + return put_user(dmabuf->ossfragsize, (int *)arg); case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/ +#ifdef DEBUG + printk("SNDCTL_DSP_GETFMTS\n"); +#endif return put_user(AFMT_S16_LE, (int *)arg); case SNDCTL_DSP_SETFMT: /* Select sample format */ - if (get_user(val, (int *)arg)) - return -EFAULT; - if (val != AFMT_QUERY) { - if (file->f_mode & FMODE_WRITE) { - stop_dac(state); - dmabuf->ready = 0; - dmabuf->fmt |= I810_FMT_16BIT; - } - if (file->f_mode & FMODE_READ) { - stop_adc(state); - dmabuf->ready = 0; - dmabuf->fmt |= I810_FMT_16BIT; - } - } +#ifdef DEBUG + printk("SNDCTL_DSP_SETFMT\n"); +#endif return put_user(AFMT_S16_LE, (int *)arg); case SNDCTL_DSP_CHANNELS: - if (get_user(val, (int *)arg)) - return -EFAULT; - if (val != 0) { - if (file->f_mode & FMODE_WRITE) { - stop_dac(state); - dmabuf->ready = 0; - } - if (file->f_mode & FMODE_READ) { - stop_adc(state); - dmabuf->ready = 0; - } - } +#ifdef DEBUG + printk("SNDCTL_DSP_CHANNELS\n"); +#endif return put_user(2, (int *)arg); - case SNDCTL_DSP_POST: - /* FIXME: the same as RESET ?? */ + case SNDCTL_DSP_POST: /* the user has sent all data and is notifying us */ + /* we update the swptr to the end of the last sg segment then return */ +#ifdef DEBUG + printk("SNDCTL_DSP_POST\n"); +#endif + if(!dmabuf->ready || (dmabuf->enable != DAC_RUNNING)) + return 0; + if((dmabuf->swptr % dmabuf->fragsize) != 0) { + val = dmabuf->fragsize - (dmabuf->swptr % dmabuf->fragsize); + dmabuf->swptr += val; + dmabuf->count += val; + } return 0; case SNDCTL_DSP_SUBDIVIDE: @@ -1442,6 +1494,9 @@ return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; +#ifdef DEBUG + printk("SNDCTL_DSP_SUBDIVIDE %d\n", val); +#endif dmabuf->subdivision = val; dmabuf->ready = 0; return 0; @@ -1450,15 +1505,27 @@ if (get_user(val, (int *)arg)) return -EFAULT; - dmabuf->ossfragshift = val & 0xffff; + dmabuf->ossfragsize = 1<<(val & 0xffff); dmabuf->ossmaxfrags = (val >> 16) & 0xffff; - if (dmabuf->ossfragshift < 4) - dmabuf->ossfragshift = 4; - if (dmabuf->ossfragshift > 15) - dmabuf->ossfragshift = 15; - if (dmabuf->ossmaxfrags < 4) + if (dmabuf->ossmaxfrags <= 4) dmabuf->ossmaxfrags = 4; + else if (dmabuf->ossmaxfrags <= 8) + dmabuf->ossmaxfrags = 8; + else if (dmabuf->ossmaxfrags <= 16) + dmabuf->ossmaxfrags = 16; + else + dmabuf->ossmaxfrags = 32; + val = dmabuf->ossfragsize * dmabuf->ossmaxfrags; + if (val < 16384) + val = 16384; + if (val > 65536) + val = 65536; + dmabuf->ossfragsize = val/dmabuf->ossmaxfrags; dmabuf->ready = 0; +#ifdef DEBUG + printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val, + dmabuf->ossfragsize, dmabuf->ossmaxfrags); +#endif return 0; @@ -1469,13 +1536,42 @@ return val; spin_lock_irqsave(&state->card->lock, flags); i810_update_ptr(state); - abinfo.fragsize = dmabuf->fragsize; - abinfo.bytes = dmabuf->dmasize - dmabuf->count; - abinfo.fragstotal = dmabuf->numfrag; - abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; + abinfo.fragsize = dmabuf->ossfragsize; + abinfo.fragstotal = dmabuf->ossmaxfrags; + if(dmabuf->mapped) + abinfo.bytes = dmabuf->count; + else + abinfo.bytes = dmabuf->dmasize - dmabuf->count; + abinfo.fragments = abinfo.bytes / dmabuf->ossfragsize; spin_unlock_irqrestore(&state->card->lock, flags); +#ifdef DEBUG + printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n", abinfo.bytes, + abinfo.fragsize, abinfo.fragments, abinfo.fragstotal); +#endif return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + case SNDCTL_DSP_GETOPTR: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) + return val; + spin_lock_irqsave(&state->card->lock, flags); + i810_update_ptr(state); + cinfo.bytes = dmabuf->total_bytes; + cinfo.ptr = dmabuf->hwptr; + cinfo.blocks = (dmabuf->dmasize - dmabuf->count)/dmabuf->ossfragsize; + if (dmabuf->mapped) { + dmabuf->count = (dmabuf->dmasize - + (dmabuf->count & (dmabuf->ossfragsize-1))); + __i810_update_lvi(state, 0); + } + spin_unlock_irqrestore(&state->card->lock, flags); +#ifdef DEBUG + printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes, + cinfo.blocks, cinfo.ptr, dmabuf->count); +#endif + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; @@ -1483,87 +1579,111 @@ return val; spin_lock_irqsave(&state->card->lock, flags); i810_update_ptr(state); - abinfo.fragsize = dmabuf->fragsize; - abinfo.bytes = dmabuf->count; - abinfo.fragstotal = dmabuf->numfrag; - abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; + abinfo.fragsize = dmabuf->ossfragsize; + abinfo.fragstotal = dmabuf->ossmaxfrags; + abinfo.bytes = dmabuf->dmasize - dmabuf->count; + abinfo.fragments = abinfo.bytes / dmabuf->ossfragsize; spin_unlock_irqrestore(&state->card->lock, flags); +#ifdef DEBUG + printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n", abinfo.bytes, + abinfo.fragsize, abinfo.fragments, abinfo.fragstotal); +#endif return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + case SNDCTL_DSP_GETIPTR: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) + return val; + spin_lock_irqsave(&state->card->lock, flags); + i810_update_ptr(state); + cinfo.bytes = dmabuf->total_bytes; + cinfo.blocks = dmabuf->count/dmabuf->ossfragsize; + cinfo.ptr = dmabuf->hwptr; + if (dmabuf->mapped) { + dmabuf->count &= dmabuf->ossfragsize-1; + __i810_update_lvi(state, 1); + } + spin_unlock_irqrestore(&state->card->lock, flags); +#ifdef DEBUG + printk("SNDCTL_DSP_GETIPTR %d, %d, %d, %d\n", cinfo.bytes, + cinfo.blocks, cinfo.ptr, dmabuf->count); +#endif + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + case SNDCTL_DSP_NONBLOCK: +#ifdef DEBUG + printk("SNDCTL_DSP_NONBLOCK\n"); +#endif file->f_flags |= O_NONBLOCK; return 0; case SNDCTL_DSP_GETCAPS: +#ifdef DEBUG + printk("SNDCTL_DSP_GETCAPS\n"); +#endif return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP|DSP_CAP_BIND, (int *)arg); case SNDCTL_DSP_GETTRIGGER: val = 0; - if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING) - val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && dmabuf->enable & DAC_RUNNING) - val |= PCM_ENABLE_OUTPUT; - return put_user(val, (int *)arg); +#ifdef DEBUG + printk("SNDCTL_DSP_GETTRIGGER 0x%x\n", dmabuf->trigger); +#endif + return put_user(dmabuf->trigger, (int *)arg); case SNDCTL_DSP_SETTRIGGER: if (get_user(val, (int *)arg)) return -EFAULT; - if (file->f_mode & FMODE_READ && val & PCM_ENABLE_INPUT) { - if (dmabuf->enable & DAC_RUNNING) - return -ENODEV; - if (!dmabuf->read_channel) { - dmabuf->ready = 0; - dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card); - if (!dmabuf->read_channel) - return -ENODEV; - } - if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) - return ret; - start_adc(state); +#ifdef DEBUG + printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val); +#endif + if( !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) { + stop_adc(state); } - if (file->f_mode & FMODE_WRITE && val & PCM_ENABLE_OUTPUT) { - if (dmabuf->enable & ADC_RUNNING) - return -ENODEV; + if( !(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) { + stop_dac(state); + } + dmabuf->trigger = val; + if(val & PCM_ENABLE_OUTPUT) { if (!dmabuf->write_channel) { dmabuf->ready = 0; dmabuf->write_channel = state->card->alloc_pcm_channel(state->card); if (!dmabuf->write_channel) - return -ENODEV; + return -EBUSY; } if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) return ret; - start_dac(state); + if (dmabuf->mapped) { + dmabuf->count = dmabuf->dmasize; + i810_update_lvi(state,0); + } + if (!dmabuf->enable && dmabuf->count > dmabuf->fragsize) + start_dac(state); + } + if(val & PCM_ENABLE_INPUT) { + if (!dmabuf->read_channel) { + dmabuf->ready = 0; + dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card); + if (!dmabuf->read_channel) + return -EBUSY; + } + if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) + return ret; + if (dmabuf->mapped) { + dmabuf->count = 0; + i810_update_lvi(state,1); + } + if (!dmabuf->enable && dmabuf->count < + (dmabuf->dmasize - dmabuf->fragsize)) + start_adc(state); } return 0; - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - spin_lock_irqsave(&state->card->lock, flags); - i810_update_ptr(state); - cinfo.bytes = dmabuf->total_bytes; - cinfo.blocks = dmabuf->count >> dmabuf->fragshift; - cinfo.ptr = dmabuf->hwptr; - if (dmabuf->mapped) - dmabuf->count &= dmabuf->fragsize-1; - spin_unlock_irqrestore(&state->card->lock, flags); - return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - spin_lock_irqsave(&state->card->lock, flags); - i810_update_ptr(state); - cinfo.bytes = dmabuf->total_bytes; - cinfo.blocks = dmabuf->count >> dmabuf->fragshift; - cinfo.ptr = dmabuf->hwptr; - if (dmabuf->mapped) - dmabuf->count &= dmabuf->fragsize-1; - spin_unlock_irqrestore(&state->card->lock, flags); - return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); - case SNDCTL_DSP_SETDUPLEX: +#ifdef DEBUG + printk("SNDCTL_DSP_SETDUPLEX\n"); +#endif return -EINVAL; case SNDCTL_DSP_GETODELAY: @@ -1573,16 +1693,27 @@ i810_update_ptr(state); val = dmabuf->count; spin_unlock_irqrestore(&state->card->lock, flags); +#ifdef DEBUG + printk("SNDCTL_DSP_GETODELAY %d\n", dmabuf->count); +#endif return put_user(val, (int *)arg); case SOUND_PCM_READ_RATE: +#ifdef DEBUG + printk("SOUND_PCM_READ_RATE %d\n", dmabuf->rate); +#endif return put_user(dmabuf->rate, (int *)arg); case SOUND_PCM_READ_CHANNELS: - return put_user((dmabuf->fmt & I810_FMT_STEREO) ? 2 : 1, - (int *)arg); +#ifdef DEBUG + printk("SOUND_PCM_READ_CHANNELS\n"); +#endif + return put_user(2, (int *)arg); case SOUND_PCM_READ_BITS: +#ifdef DEBUG + printk("SOUND_PCM_READ_BITS\n"); +#endif return put_user(AFMT_S16_LE, (int *)arg); case SNDCTL_DSP_MAPINBUF: @@ -1590,6 +1721,9 @@ case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_WRITE_FILTER: case SOUND_PCM_READ_FILTER: +#ifdef DEBUG + printk("SNDCTL_* -EINVAL\n"); +#endif return -EINVAL; } return -EINVAL; @@ -1621,7 +1755,7 @@ if (!state) return -ENODEV; - found_virt: +found_virt: /* initialize the virtual channel */ state->virt = i; state->card = card; @@ -1629,33 +1763,36 @@ init_waitqueue_head(&dmabuf->wait); init_MUTEX(&state->open_sem); file->private_data = state; + dmabuf->trigger = 0; /* allocate hardware channels */ if(file->f_mode & FMODE_READ) { if((dmabuf->read_channel = card->alloc_rec_pcm_channel(card)) == NULL) { kfree (card->states[i]); card->states[i] = NULL;; - return -ENODEV; + return -EBUSY; } - i810_set_adc_rate(state, 48000); + i810_set_adc_rate(state, 8000); + dmabuf->trigger |= PCM_ENABLE_INPUT; } if(file->f_mode & FMODE_WRITE) { if((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) { kfree (card->states[i]); card->states[i] = NULL;; - return -ENODEV; + return -EBUSY; } - i810_set_dac_rate(state, 48000); + i810_set_dac_rate(state, 8000); + dmabuf->trigger |= PCM_ENABLE_OUTPUT; } down(&state->open_sem); /* set default sample format. According to OSS Programmer's Guide /dev/dsp should be default to unsigned 8-bits, mono, with sample rate 8kHz and - /dev/dspW will accept 16-bits sample */ - dmabuf->fmt &= ~I810_FMT_MASK; - dmabuf->fmt |= I810_FMT_16BIT; - dmabuf->ossfragshift = 0; + /dev/dspW will accept 16-bits sample, but we don't support those so we + set it immediately to stereo and 16bit, which is all we do support */ + dmabuf->fmt |= I810_FMT_16BIT | I810_FMT_STEREO; + dmabuf->ossfragsize = 0; dmabuf->ossmaxfrags = 0; dmabuf->subdivision = 0; @@ -1671,22 +1808,19 @@ struct dmabuf *dmabuf = &state->dmabuf; lock_kernel(); - if (file->f_mode & FMODE_WRITE) { - } - /* stop DMA state machine and free DMA buffers/channels */ down(&state->open_sem); - if (dmabuf->enable & DAC_RUNNING) { - i810_clear_tail(state); - drain_dac(state, file->f_flags & O_NONBLOCK); + /* stop DMA state machine and free DMA buffers/channels */ + if(dmabuf->enable == DAC_RUNNING || + (dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT))) { + drain_dac(state,0); stop_dac(state); - dealloc_dmabuf(state); } if(dmabuf->enable & ADC_RUNNING) { stop_adc(state); - dealloc_dmabuf(state); } + dealloc_dmabuf(state); if (file->f_mode & FMODE_WRITE) { state->card->free_pcm_channel(state->card, dmabuf->write_channel->num); } @@ -1827,6 +1961,19 @@ if (ac97_probe_codec(codec) == 0) break; + /* power up everything, modify this when implementing power saving */ + i810_ac97_set(codec, AC97_POWER_CONTROL, + i810_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00); + /* wait for analog ready */ + for (i=10; + i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); + i--) + { + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/20); + } + + /* Don't attempt to get eid until powerup is complete */ eid = i810_ac97_get(codec, AC97_EXTENDED_ID); if(eid==0xFFFFFF) @@ -1845,18 +1992,6 @@ printk(KERN_WARNING "i810_audio: only 48Khz playback available.\n"); else { - /* power up everything, modify this when implementing power saving */ - i810_ac97_set(codec, AC97_POWER_CONTROL, - i810_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00); - /* wait for analog ready */ - for (i=10; - i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); - i--) - { - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ/20); - } - /* Enable variable rate mode */ i810_ac97_set(codec, AC97_EXTENDED_STATUS, 9); i810_ac97_set(codec,AC97_EXTENDED_STATUS, @@ -1996,6 +2131,7 @@ MODULE_DESCRIPTION("Intel 810 audio support"); MODULE_PARM(ftsodell, "i"); MODULE_PARM(clocking, "i"); +MODULE_PARM(strict_clocking, "i"); #define I810_MODULE_NAME "intel810_audio" @@ -2036,6 +2172,7 @@ init_waitqueue_head(&dmabuf->wait); init_MUTEX(&state->open_sem); dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT; + dmabuf->trigger = PCM_ENABLE_OUTPUT; i810_set_dac_rate(state, 48000); if(prog_dmabuf(state, 0) != 0) { goto config_out_nodmabuf; @@ -2044,25 +2181,30 @@ goto config_out; } dmabuf->count = dmabuf->dmasize; + outb(31,card->iobase+dmabuf->write_channel->port+OFF_LVI); save_flags(flags); cli(); start_dac(state); - offset = i810_get_dma_addr(state); + offset = i810_get_dma_addr(state, 0); mdelay(50); - new_offset = i810_get_dma_addr(state); + new_offset = i810_get_dma_addr(state, 0); stop_dac(state); outb(2,card->iobase+dmabuf->write_channel->port+OFF_CR); restore_flags(flags); i = new_offset - offset; +#ifdef DEBUG printk("i810_audio: %d bytes in 50 milliseconds\n", i); +#endif + if(i == 0) + goto config_out; i = i / 4 * 20; if (i > 48500 || i < 47500) { clocking = clocking * clocking / i; - printk("i810_audio: setting clocking to %d to compensate\n", clocking); + printk("i810_audio: setting clocking to %d\n", clocking); } -config_out_nodmabuf: - dealloc_dmabuf(state); config_out: + dealloc_dmabuf(state); +config_out_nodmabuf: state->card->free_pcm_channel(state->card,state->dmabuf.write_channel->num); kfree(state); card->states[0] = NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/mad16.c linux.ac/drivers/sound/mad16.c --- linux.vanilla/drivers/sound/mad16.c Sat Dec 30 19:23:14 2000 +++ linux.ac/drivers/sound/mad16.c Tue Apr 10 18:17:36 2001 @@ -423,72 +423,80 @@ DDB(printk("Detect using password = 0xE5\n")); - if (!detect_mad16()) /* No luck. Try different model */ - { - board_type = C928; + if (detect_mad16()) { + return 1; + } + + board_type = C928; - DDB(printk("Detect using password = 0xE2\n")); + DDB(printk("Detect using password = 0xE2\n")); - if (!detect_mad16()) - { - board_type = C929; - - DDB(printk("Detect using password = 0xE3\n")); - - if (!detect_mad16()) - { - if (inb(PASSWD_REG) != 0xff) - return 0; - - /* - * First relocate MC# registers to 0xe0e/0xe0f, disable password - */ - - outb((0xE4), PASSWD_REG); - outb((0x80), PASSWD_REG); - - board_type = C930; - - DDB(printk("Detect using password = 0xE4\n")); - - for (i = 0xf8d; i <= 0xf93; i++) - DDB(printk("port %03x = %02x\n", i, mad_read(i))); - if(!detect_mad16()) { - - /* The C931 has the password reg at F8D */ - outb((0xE4), 0xF8D); - outb((0x80), 0xF8D); - DDB(printk("Detect using password = 0xE4 for C931\n")); - - if (!detect_mad16()) { - board_type = C924; - c924pnp++; - DDB(printk("Detect using password = 0xE5 (again), port offset -0x80\n")); - if (!detect_mad16()) { - c924pnp=0; - return 0; - } - - DDB(printk("mad16.c: 82C924 PnP detected\n")); - } - } - else - DDB(printk("mad16.c: 82C930 detected\n")); - } else - DDB(printk("mad16.c: 82C929 detected\n")); - } else { - unsigned char model; + if (detect_mad16()) + { + unsigned char model; - if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03) { - DDB(printk("mad16.c: Mozart detected\n")); - board_type = MOZART; - } else { - DDB(printk("mad16.c: 82C928 detected???\n")); - board_type = C928; - } + if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03) { + DDB(printk("mad16.c: Mozart detected\n")); + board_type = MOZART; + } else { + DDB(printk("mad16.c: 82C928 detected???\n")); + board_type = C928; } + return 1; + } + + board_type = C929; + + DDB(printk("Detect using password = 0xE3\n")); + + if (detect_mad16()) + { + DDB(printk("mad16.c: 82C929 detected\n")); + return 1; + } + + if (inb(PASSWD_REG) != 0xff) + return 0; + + /* + * First relocate MC# registers to 0xe0e/0xe0f, disable password + */ + + outb((0xE4), PASSWD_REG); + outb((0x80), PASSWD_REG); + + board_type = C930; + + DDB(printk("Detect using password = 0xE4\n")); + + for (i = 0xf8d; i <= 0xf93; i++) + DDB(printk("port %03x = %02x\n", i, mad_read(i))); + + if(detect_mad16()) { + DDB(printk("mad16.c: 82C930 detected\n")); + return 1; } - return 1; + + /* The C931 has the password reg at F8D */ + outb((0xE4), 0xF8D); + outb((0x80), 0xF8D); + DDB(printk("Detect using password = 0xE4 for C931\n")); + + if (detect_mad16()) { + return 1; + } + + board_type = C924; + c924pnp++; + DDB(printk("Detect using password = 0xE5 (again), port offset -0x80\n")); + if (detect_mad16()) { + DDB(printk("mad16.c: 82C924 PnP detected\n")); + return 1; + } + + c924pnp=0; + + return 0; } static int __init probe_mad16(struct address_info *hw_config) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/maestro3.c linux.ac/drivers/sound/maestro3.c --- linux.vanilla/drivers/sound/maestro3.c Tue Apr 3 17:32:22 2001 +++ linux.ac/drivers/sound/maestro3.c Sun Apr 15 23:07:14 2001 @@ -81,7 +81,7 @@ * do the real work. The kernel presumably jumps into each of them in turn. * These code images tend to have their own data area, and one can have * multiple data areas representing different states for each of the 'client - * instance' code portions. There is generaly a list in the kernel data + * instance' code portions. There is generally a list in the kernel data * that points to the data instances for a given piece of code. * * We've only been given the binary image for the 'minisrc', mini sample @@ -2595,17 +2595,15 @@ DPRINTK(DPMOD, "in maestro_install\n"); - if (!pci_dma_supported(pci_dev, M3_PCI_DMA_MASK)) { + if (pci_enable_device(pci_dev)) + return -EIO; + + if (pci_set_dma_mask(pci_dev, M3_PCI_DMA_MASK)) { printk(KERN_ERR PFX "architecture does not support limiting to 28bit PCI bus addresses\n"); return -ENODEV; } - if (pci_enable_device(pci_dev)) - return -EIO; - pci_set_master(pci_dev); - - pci_dev->dma_mask = M3_PCI_DMA_MASK; if( (card = kmalloc(sizeof(struct m3_card), GFP_KERNEL)) == NULL) { printk(KERN_WARNING PFX "out of memory\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/miroaci.h linux.ac/drivers/sound/miroaci.h --- linux.vanilla/drivers/sound/miroaci.h Mon Mar 13 03:13:06 2000 +++ linux.ac/drivers/sound/miroaci.h Thu Jan 1 01:00:00 1970 @@ -1,5 +0,0 @@ -extern int aci_implied_cmd(unsigned char opcode); -extern int aci_write_cmd(unsigned char opcode, unsigned char parameter); -extern int aci_write_cmd_d(unsigned char opcode, unsigned char parameter, unsigned char parameter2); -extern int aci_read_cmd(unsigned char opcode, int length, unsigned char *parameter); -extern int aci_indexed_cmd(unsigned char opcode, unsigned char index, unsigned char *parameter); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/sb_common.c linux.ac/drivers/sound/sb_common.c --- linux.vanilla/drivers/sound/sb_common.c Sat Feb 17 00:02:37 2001 +++ linux.ac/drivers/sound/sb_common.c Sun Apr 15 23:09:54 2001 @@ -1227,7 +1227,7 @@ if (!ess_midi_init(devc, hw_config)) return 0; hw_config->name = "ESS1xxx MPU"; - devc->midi_irq_cookie = -1; + devc->midi_irq_cookie = NULL; if (!probe_mpu401(hw_config)) return 0; attach_mpu401(hw_config, owner); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/sonicvibes.c linux.ac/drivers/sound/sonicvibes.c --- linux.vanilla/drivers/sound/sonicvibes.c Tue Apr 3 17:32:22 2001 +++ linux.ac/drivers/sound/sonicvibes.c Thu Apr 12 12:04:32 2001 @@ -3,7 +3,7 @@ /* * sonicvibes.c -- S3 Sonic Vibes audio driver. * - * Copyright (C) 1998-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) + * Copyright (C) 1998-2001 Thomas Sailer (t.sailer@alumni.ethz.ch) * * 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 @@ -88,6 +88,10 @@ * use Martin Mares' pci_assign_resource * 07.02.2000 0.26 Use pci_alloc_consistent and pci_register_driver * 21.11.2000 0.27 Initialize dma buffers in poll, otherwise poll may return a bogus mask + * 12.12.2000 0.28 More dma buffer initializations, patch from + * Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com> + * 31.01.2001 0.29 Register/Unregister gameport + * Fix SETTRIGGER non OSS API conformity * */ @@ -115,6 +119,23 @@ #include "dm.h" +#if defined(CONFIG_INPUT_ANALOG) || defined(CONFIG_INPUT_ANALOG_MODULE) +#include <linux/gameport.h> +#else +struct gameport { + int io; + int size; +}; + +extern inline void gameport_register_port(struct gameport *gameport) +{ +} + +extern inline void gameport_unregister_port(struct gameport *gameport) +{ +} +#endif + /* --------------------------------------------------------------------- */ #undef OSS_DOCUMENTED_MIXER_SEMANTICS @@ -301,7 +322,7 @@ int dev_dmfm; /* hardware resources */ - unsigned long iosb, ioenh, iosynth, iomidi, iogame; /* long for SPARC */ + unsigned long iosb, ioenh, iosynth, iomidi; /* long for SPARC */ unsigned int iodmaa, iodmac, irq; /* mixer stuff */ @@ -340,6 +361,7 @@ unsigned mapped:1; unsigned ready:1; unsigned endcleared:1; + unsigned enabled:1; unsigned ossfragshift; int ossmaxfrags; unsigned subdivision; @@ -355,6 +377,8 @@ unsigned char ibuf[MIDIINBUF]; unsigned char obuf[MIDIOUTBUF]; } midi; + + struct gameport gameport; }; /* --------------------------------------------------------------------- */ @@ -786,6 +810,7 @@ wrindir(s, SV_CIDMAABASECOUNT0, db->fragsamples-1); } spin_unlock_irqrestore(&s->lock, flags); + db->enabled = 1; db->ready = 1; return 0; } @@ -1343,7 +1368,8 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - start_adc(s); + if (s->dma_adc.enabled) + start_adc(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; @@ -1382,7 +1408,8 @@ count -= cnt; buffer += cnt; ret += cnt; - start_adc(s); + if (s->dma_adc.enabled) + start_adc(s); } remove_wait_queue(&s->dma_adc.wait, &wait); set_current_state(TASK_RUNNING); @@ -1430,7 +1457,8 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - start_dac(s); + if (s->dma_dac.enabled) + start_dac(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; @@ -1470,7 +1498,8 @@ count -= cnt; buffer += cnt; ret += cnt; - start_dac(s); + if (s->dma_dac.enabled) + start_dac(s); } remove_wait_queue(&s->dma_dac.wait, &wait); set_current_state(TASK_RUNNING); @@ -1706,25 +1735,31 @@ if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) return ret; + s->dma_adc.enabled = 1; start_adc(s); - } else + } else { + s->dma_adc.enabled = 0; stop_adc(s); + } } if (file->f_mode & FMODE_WRITE) { if (val & PCM_ENABLE_OUTPUT) { if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) return ret; + s->dma_dac.enabled = 1; start_dac(s); - } else + } else { + s->dma_dac.enabled = 0; stop_dac(s); + } } return 0; case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; + if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); abinfo.fragsize = s->dma_dac.fragsize; @@ -1740,8 +1775,8 @@ case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) - return ret; + if (!s->dma_adc.ready && (val = prog_dmabuf(s, 1)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); abinfo.fragsize = s->dma_adc.fragsize; @@ -1761,8 +1796,8 @@ case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; + if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); count = s->dma_dac.count; @@ -1774,8 +1809,8 @@ case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) - return ret; + if (!s->dma_adc.ready && (val = prog_dmabuf(s, 1)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; @@ -1792,8 +1827,8 @@ case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; + if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); cinfo.bytes = s->dma_dac.total_bytes; @@ -1915,6 +1950,7 @@ if ((minor & 0xf) == SND_DEV_DSP16) fmts |= SV_CFMT_16BIT << SV_CFMT_CSHIFT; s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; + s->dma_adc.enabled = 1; set_adc_rate(s, 8000); } if (file->f_mode & FMODE_WRITE) { @@ -1922,6 +1958,7 @@ if ((minor & 0xf) == SND_DEV_DSP16) fmts |= SV_CFMT_16BIT << SV_CFMT_ASHIFT; s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0; + s->dma_dac.enabled = 1; set_dac_rate(s, 8000); } set_fmt(s, fmtm, fmts); @@ -2212,6 +2249,7 @@ if (file->f_flags & O_NONBLOCK) { remove_wait_queue(&s->midi.owait, &wait); set_current_state(TASK_RUNNING); + unlock_kernel(); return -EBUSY; } tmo = (count * HZ) / 3100; @@ -2517,13 +2555,14 @@ s->ioenh = pci_resource_start(pcidev, RESOURCE_ENH); s->iosynth = pci_resource_start(pcidev, RESOURCE_SYNTH); s->iomidi = pci_resource_start(pcidev, RESOURCE_MIDI); - s->iogame = pci_resource_start(pcidev, RESOURCE_GAME); s->iodmaa = pci_resource_start(pcidev, RESOURCE_DDMA); s->iodmac = pci_resource_start(pcidev, RESOURCE_DDMA) + SV_EXTENT_DMA; + s->gameport.io = pci_resource_start(pcidev, RESOURCE_GAME); + s->gameport.size = pci_resource_len(pcidev,RESOURCE_GAME); pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9); /* enable and use extended mode */ pci_write_config_dword(pcidev, 0x48, s->iodmac | 9); /* enable */ - printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#lx %#x %#x\n", - s->iosb, s->ioenh, s->iosynth, s->iomidi, s->iogame, s->iodmaa, s->iodmac); + printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#x %#x %#x\n", + s->iosb, s->ioenh, s->iosynth, s->iomidi, s->gameport.io, s->iodmaa, s->iodmac); s->irq = pcidev->irq; /* hack */ @@ -2549,6 +2588,12 @@ printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1); goto err_region1; } + if (!s->gameport.size) + s->gameport.io = 0; + if (s->gameport.io && !request_region(s->gameport.io, s->gameport.size, "ESS Solo1")) { + printk(KERN_ERR "sv: gameport io ports in use\n"); + s->gameport.io = s->gameport.size = 0; + } if (pci_enable_device(pcidev)) goto err_irq; /* initialize codec registers */ @@ -2600,7 +2645,9 @@ mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val); } set_fs(fs); - /* store it in the driver field */ + /* register gameport */ + gameport_register_port(&s->gameport); + /* store it in the driver field */ pci_set_drvdata(pcidev, s); /* put it into driver list */ list_add_tail(&s->devs, &devs); @@ -2619,6 +2666,8 @@ printk(KERN_ERR "sv: cannot register misc device\n"); free_irq(s->irq, s); err_irq: + if (s->gameport.io) + release_region(s->gameport.io, s->gameport.size); release_region(s->iosynth, SV_EXTENT_SYNTH); err_region1: release_region(s->iomidi, SV_EXTENT_MIDI); @@ -2635,29 +2684,33 @@ static void __devinit sv_remove(struct pci_dev *dev) { - struct sv_state *s = pci_get_drvdata(dev); + struct sv_state *s = pci_get_drvdata(dev); - if (!s) - return; - list_del(&s->devs); - outb(~0, s->ioenh + SV_CODEC_INTMASK); /* disable ints */ - synchronize_irq(); - inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */ - wrindir(s, SV_CIENABLE, 0); /* disable DMAA and DMAC */ - /*outb(0, s->iodmaa + SV_DMA_RESET);*/ - /*outb(0, s->iodmac + SV_DMA_RESET);*/ - free_irq(s->irq, s); - release_region(s->iodmac, SV_EXTENT_DMA); - release_region(s->iodmaa, SV_EXTENT_DMA); - release_region(s->ioenh, SV_EXTENT_ENH); - release_region(s->iomidi, SV_EXTENT_MIDI); - release_region(s->iosynth, SV_EXTENT_SYNTH); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->dev_mixer); - unregister_sound_midi(s->dev_midi); - unregister_sound_special(s->dev_dmfm); - kfree(s); - pci_set_drvdata(dev, NULL); + if (!s) + return; + list_del(&s->devs); + outb(~0, s->ioenh + SV_CODEC_INTMASK); /* disable ints */ + synchronize_irq(); + inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */ + wrindir(s, SV_CIENABLE, 0); /* disable DMAA and DMAC */ + /*outb(0, s->iodmaa + SV_DMA_RESET);*/ + /*outb(0, s->iodmac + SV_DMA_RESET);*/ + free_irq(s->irq, s); + if (s->gameport.io) { + gameport_unregister_port(&s->gameport); + release_region(s->gameport.io, s->gameport.size); + } + release_region(s->iodmac, SV_EXTENT_DMA); + release_region(s->iodmaa, SV_EXTENT_DMA); + release_region(s->ioenh, SV_EXTENT_ENH); + release_region(s->iomidi, SV_EXTENT_MIDI); + release_region(s->iosynth, SV_EXTENT_SYNTH); + unregister_sound_dsp(s->dev_audio); + unregister_sound_mixer(s->dev_mixer); + unregister_sound_midi(s->dev_midi); + unregister_sound_special(s->dev_dmfm); + kfree(s); + pci_set_drvdata(dev, NULL); } static struct pci_device_id id_table[] __devinitdata = { @@ -2678,7 +2731,7 @@ { if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "sv: version v0.27 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "sv: version v0.29 time " __TIME__ " " __DATE__ "\n"); #if 0 if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT))) printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/sound_core.c linux.ac/drivers/sound/sound_core.c --- linux.vanilla/drivers/sound/sound_core.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/sound/sound_core.c Tue Apr 10 18:17:36 2001 @@ -168,7 +168,11 @@ spin_unlock(&sound_loader_lock); if(r<0) + { kfree(s); + return r; + } + if (r == low) sprintf (name_buf, "%s", name); else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/trident.c linux.ac/drivers/sound/trident.c --- linux.vanilla/drivers/sound/trident.c Tue Apr 3 17:32:23 2001 +++ linux.ac/drivers/sound/trident.c Tue Apr 10 18:17:44 2001 @@ -2890,7 +2890,7 @@ { if ((i*4 == T4D_MISCINT) || (i*4 == T4D_STOP_A) || (i*4 == T4D_START_A)) continue; - ali_registers.global_regs[i] = inl(TRID_REG(card, i*4)); + outl(ali_registers.global_regs[i], TRID_REG(card, i*4)); } //start HW channel diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/vidc.c linux.ac/drivers/sound/vidc.c --- linux.vanilla/drivers/sound/vidc.c Wed Sep 27 21:39:23 2000 +++ linux.ac/drivers/sound/vidc.c Tue Apr 10 00:07:04 2001 @@ -17,6 +17,7 @@ * We currently support a mixer device, but it is currently non-functional. */ +#include <linux/config.h> #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> @@ -82,6 +83,7 @@ static void (*old_mksound)(unsigned int hz, unsigned int ticks); extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); extern void vidc_update_filler(int bits, int channels); +extern int softoss_dev; static void vidc_mksound(unsigned int hz, unsigned int ticks) @@ -214,8 +216,8 @@ rate = VIDC_SOUND_CLOCK / hwrate; } - outl(0xb0000000 | (hwrate - 2), IO_VIDC_BASE); - outl(0xb1000000 | hwctrl, IO_VIDC_BASE); + vidc_writel(0xb0000000 | (hwrate - 2)); + vidc_writel(0xb1000000 | hwctrl); newsize = (10000 / hwrate) & ~3; if (newsize < 208) @@ -354,7 +356,7 @@ dma_interrupt = vidc_audio_dma_interrupt; vidc_sound_dma_irq(0, NULL, NULL); - outb(DMA_CR_E | 0x10, IOMD_SD0CR); + iomd_writeb(DMA_CR_E | 0x10, IOMD_SD0CR); local_irq_restore(flags); } @@ -473,6 +475,9 @@ vidc_adev = adev; vidc_mixer_set(SOUND_MIXER_VOLUME, (85 | 85 << 8)); +#if defined(CONFIG_SOUND_SOFTOSS) || defined(CONFIG_SOUND_SOFTOSS_MODULE) + softoss_dev = adev; +#endif return; irq_failed: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/waveartist.c linux.ac/drivers/sound/waveartist.c --- linux.vanilla/drivers/sound/waveartist.c Sun Nov 12 02:33:14 2000 +++ linux.ac/drivers/sound/waveartist.c Tue Apr 10 00:07:04 2001 @@ -1824,7 +1824,7 @@ io = ints[1]; irq = ints[2]; dma = ints[3]; - dma16 = ints[4]; + dma2 = ints[4]; return 1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/ymfpci.c linux.ac/drivers/sound/ymfpci.c --- linux.vanilla/drivers/sound/ymfpci.c Tue Apr 3 17:32:23 2001 +++ linux.ac/drivers/sound/ymfpci.c Tue Apr 10 18:17:44 2001 @@ -1853,6 +1853,7 @@ return -ENXIO; } + unit = NULL; /* gcc warns */ for (list = ymf_devs.next; list != &ymf_devs; list = list->next) { unit = list_entry(list, ymfpci_t, ymf_devs); if (((unit->dev_audio ^ minor) & ~0x0F) == 0) @@ -2147,8 +2148,8 @@ ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007); /* setup DSP instruction code */ - for (i = 0; i < YDSXG_DSPLENGTH; i++) - ymfpci_writel(codec, YDSXGR_DSPINSTRAM + i, DspInst[i >> 2]); + for (i = 0; i < YDSXG_DSPLENGTH / 4; i++) + ymfpci_writel(codec, YDSXGR_DSPINSTRAM + (i << 2), DspInst[i]); switch (codec->pci->device) { case PCI_DEVICE_ID_YAMAHA_724F: @@ -2163,11 +2164,11 @@ if (ver_1e) { /* setup control instruction code */ - for (i = 0; i < YDSXG_CTRLLENGTH; i++) - ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + i, CntrlInst1E[i >> 2]); + for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++) + ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + (i << 2), CntrlInst1E[i]); } else { - for (i = 0; i < YDSXG_CTRLLENGTH; i++) - ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + i, CntrlInst[i >> 2]); + for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++) + ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + (i << 2), CntrlInst[i]); } ymfpci_enable_dsp(codec); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/ymfpci_image.h linux.ac/drivers/sound/ymfpci_image.h --- linux.vanilla/drivers/sound/ymfpci_image.h Mon Dec 4 07:58:10 2000 +++ linux.ac/drivers/sound/ymfpci_image.h Tue Apr 10 18:17:53 2001 @@ -1,7 +1,7 @@ #ifndef _HWMCODE_ #define _HWMCODE_ -static unsigned long int DspInst[] = { +static u32 DspInst[YDSXG_DSPLENGTH / 4] = { 0x00000081, 0x000001a4, 0x0000000a, 0x0000002f, 0x00080253, 0x01800317, 0x0000407b, 0x0000843f, 0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c, @@ -12,7 +12,7 @@ 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; -static unsigned long int CntrlInst[] = { +static u32 CntrlInst[YDSXG_CTRLLENGTH / 4] = { 0x000007, 0x240007, 0x0C0007, 0x1C0007, 0x060007, 0x700002, 0x000020, 0x030040, 0x007104, 0x004286, 0x030040, 0x000F0D, @@ -791,7 +791,7 @@ // 04/09 creat // 04/12 stop nise fix // 06/21 WorkingOff timming -static unsigned long int CntrlInst1E[] = { +static u32 CntrlInst1E[YDSXG_CTRLLENGTH / 4] = { 0x000007, 0x240007, 0x0C0007, 0x1C0007, 0x060007, 0x700002, 0x000020, 0x030040, 0x007104, 0x004286, 0x030040, 0x000F0D, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/tc/Makefile linux.ac/drivers/tc/Makefile --- linux.vanilla/drivers/tc/Makefile Sat Jun 26 01:38:40 1999 +++ linux.ac/drivers/tc/Makefile Tue Apr 3 17:55:06 2001 @@ -7,27 +7,36 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -SUB_DIRS := -MOD_SUB_DIRS := -ALL_SUB_DIRS := - -L_TARGET := tc.a -L_OBJS := tc.o - -# Nasty trick as nobody references tcsyms.o, but we still want it linked. -# Stolen from pci Makefile -ifeq ($(CONFIG_MODULES),y) -O_TARGET = tc_syms.o -OX_OBJS = tcsyms.o -O_OBJS = tc.o -L_OBJS := tc_syms.o -else -L_OBJS := tc.o -endif - -ifdef CONFIG_ZS -L_OBJS += zs.o -endif +# All of the (potential) objects that export symbols. +# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. + +export-objs := tc.o + +# Object file lists. + +obj-y := +obj-m := +obj-n := +obj- := + +obj-$(CONFIG_TC) += tc.o +obj-$(CONFIG_ZS) += zs.o +obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o + +# Files that are both resident and modular: remove from modular. + +obj-m := $(filter-out $(obj-y), $(obj-m)) + +# Translate to Rules.make lists. + +L_TARGET := tc.a + +L_OBJS := $(sort $(filter-out $(export-objs), $(obj-y))) +LX_OBJS := $(sort $(filter $(export-objs), $(obj-y))) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) include $(TOPDIR)/Rules.make +lk201-map.c: lk201-map.map + loadkeys --mktable lk201-map.map > lk201-map.c diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/CDCEther.c linux.ac/drivers/usb/CDCEther.c --- linux.vanilla/drivers/usb/CDCEther.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/usb/CDCEther.c Tue Apr 3 23:15:34 2001 @@ -0,0 +1,1269 @@ +// Portions of this file taken from +// Petko Manolov - Petkan (petkan@dce.bg) +// from his driver pegasus.c + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include <linux/sched.h> +#include <linux/malloc.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/usb.h> +#include <linux/module.h> +#include "CDCEther.h" + +static const char *version = __FILE__ ": v0.98.2 28 March 2001 Brad Hards and another"; + +// We will attempt to probe anything that is in the +// communication device class... +// We will sort through them later. +static struct usb_device_id CDCEther_ids[] = { + { USB_DEVICE_INFO(2, 0, 0) }, + { } +}; + +////////////////////////////////////////////////////////////////////////////// +// Callback routines from USB device ///////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +static void read_bulk_callback( struct urb *urb ) +{ + ether_dev_t *ether_dev = urb->context; + struct net_device *net; + int count = urb->actual_length, res; + struct sk_buff *skb; + + // Sanity check + if ( !ether_dev || !(ether_dev->flags & CDC_ETHER_RUNNING) ) { + dbg("BULK IN callback but driver is not active!"); + return; + } + + net = ether_dev->net; + if ( !netif_device_present(net) ) { + // Somebody killed our network interface... + return; + } + + if ( ether_dev->flags & CDC_ETHER_RX_BUSY ) { + // Are we already trying to receive a frame??? + ether_dev->stats.rx_errors++; + dbg("ether_dev Rx busy"); + return; + } + + // We are busy, leave us alone! + ether_dev->flags |= CDC_ETHER_RX_BUSY; + + switch ( urb->status ) { + case USB_ST_NOERROR: + break; + case USB_ST_NORESPONSE: + dbg( "no repsonse in BULK IN" ); + ether_dev->flags &= ~CDC_ETHER_RX_BUSY; + break; + default: + dbg( "%s: RX status %d", net->name, urb->status ); + goto goon; + } + + // Check to make sure we got some data... + if ( !count ) { + // We got no data!!! + goto goon; + } + + // Tell the kernel we want some memory + if ( !(skb = dev_alloc_skb(count)) ) { + // We got no receive buffer. + goto goon; + } + + // Here's where it came from + skb->dev = net; + + // Now we copy it over + eth_copy_and_sum(skb, ether_dev->rx_buff, count, 0); + + // Not sure + skb_put(skb, count); + // Not sure here either + skb->protocol = eth_type_trans(skb, net); + + // Ship it off to the kernel + netif_rx(skb); + + // update out statistics + ether_dev->stats.rx_packets++; + ether_dev->stats.rx_bytes += count; + +goon: + // Prep the USB to wait for another frame + FILL_BULK_URB( ðer_dev->rx_urb, ether_dev->usb, + usb_rcvbulkpipe(ether_dev->usb, ether_dev->data_ep_in), + ether_dev->rx_buff, ether_dev->wMaxSegmentSize, + read_bulk_callback, ether_dev ); + + // Give this to the USB subsystem so it can tell us + // when more data arrives. + if ( (res = usb_submit_urb(ðer_dev->rx_urb)) ) { + warn( __FUNCTION__ " failed submint rx_urb %d", res); + } + + // We are no longer busy, show us the frames!!! + ether_dev->flags &= ~CDC_ETHER_RX_BUSY; +} + +static void write_bulk_callback( struct urb *urb ) +{ + ether_dev_t *ether_dev = urb->context; + + // Sanity check + if ( !ether_dev || !(ether_dev->flags & CDC_ETHER_RUNNING) ) { + // We are insane!!! + err( "write_bulk_callback: device not running" ); + return; + } + + // Do we still have a valid kernel network device? + if ( !netif_device_present(ether_dev->net) ) { + // Someone killed our network interface. + err( "write_bulk_callback: net device not present" ); + return; + } + + // Hmm... What on Earth could have happened??? + if ( urb->status ) { + info("%s: TX status %d", ether_dev->net->name, urb->status); + } + + // Update the network interface and tell it we are + // ready for another frame + ether_dev->net->trans_start = jiffies; + netif_wake_queue( ether_dev->net ); +} + +//static void intr_callback( struct urb *urb ) +//{ +// ether_dev_t *ether_dev = urb->context; +// struct net_device *net; +// __u8 *d; +// +// if ( !ether_dev ) +// return; +// +// switch ( urb->status ) { +// case USB_ST_NOERROR: +// break; +// case USB_ST_URB_KILLED: +// return; +// default: +// info("intr status %d", urb->status); +// } +// +// d = urb->transfer_buffer; +// net = ether_dev->net; +// if ( d[0] & 0xfc ) { +// ether_dev->stats.tx_errors++; +// if ( d[0] & TX_UNDERRUN ) +// ether_dev->stats.tx_fifo_errors++; +// if ( d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT) ) +// ether_dev->stats.tx_aborted_errors++; +// if ( d[0] & LATE_COL ) +// ether_dev->stats.tx_window_errors++; +// if ( d[0] & (NO_CARRIER | LOSS_CARRIER) ) +// ether_dev->stats.tx_carrier_errors++; +// } +//} + +////////////////////////////////////////////////////////////////////////////// +// Routines for turning net traffic on and off on the USB side /////////////// +////////////////////////////////////////////////////////////////////////////// + +static inline int enable_net_traffic( ether_dev_t *ether_dev ) +{ + struct usb_device *usb = ether_dev->usb; + + // Here would be the time to set the data interface to the configuration where + // it has two endpoints that use a protocol we can understand. + + if (usb_set_interface( usb, + ether_dev->data_bInterfaceNumber, + ether_dev->data_bAlternateSetting_with_traffic ) ) { + err("usb_set_interface() failed" ); + err("Attempted to set interface %d", ether_dev->data_bInterfaceNumber); + err("To alternate setting %d", ether_dev->data_bAlternateSetting_with_traffic); + return -1; + } + return 0; +} + +static inline void disable_net_traffic( ether_dev_t *ether_dev ) +{ + // The thing to do is to set the data interface to the alternate setting that has + // no endpoints. This is what the spec suggests. + + if (ether_dev->data_interface_altset_num_without_traffic >= 0 ) { + if (usb_set_interface( ether_dev->usb, + ether_dev->data_bInterfaceNumber, + ether_dev->data_bAlternateSetting_without_traffic ) ) { + err("usb_set_interface() failed"); + } + } else { + // Some devices just may not support this... + warn("No way to disable net traffic"); + } +} + +////////////////////////////////////////////////////////////////////////////// +// Callback routines for kernel Ethernet Device ////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +static void CDCEther_tx_timeout( struct net_device *net ) +{ + ether_dev_t *ether_dev = net->priv; + + // Sanity check + if ( !ether_dev ) { + // Seems to be a case of insanity here + return; + } + + // Tell syslog we are hosed. + warn("%s: Tx timed out.", net->name); + + // Tear the waiting frame off the list + ether_dev->tx_urb.transfer_flags |= USB_ASYNC_UNLINK; + usb_unlink_urb( ðer_dev->tx_urb ); + + // Update statistics + ether_dev->stats.tx_errors++; +} + +static int CDCEther_start_xmit( struct sk_buff *skb, struct net_device *net ) +{ + ether_dev_t *ether_dev = net->priv; + int count; + int res; + + // If we are told to transmit an ethernet frame that fits EXACTLY + // into an integer number of USB packets, we force it to send one + // more byte so the device will get a runt USB packet signalling the + // end of the ethernet frame + if ( (skb->len) ^ (ether_dev->data_ep_out_size) ) { + // It was not an exact multiple + // no need to add anything extra + count = skb->len; + } else { + // Add one to make it NOT an exact multiple + count = skb->len + 1; + } + + // Tell the kernel, "No more frames 'til we are done + // with this one.' + netif_stop_queue( net ); + + // Copy it from kernel memory to OUR memory + memcpy(ether_dev->tx_buff, skb->data, skb->len); + + // Fill in the URB for shipping it out. + FILL_BULK_URB( ðer_dev->tx_urb, ether_dev->usb, + usb_sndbulkpipe(ether_dev->usb, ether_dev->data_ep_out), + ether_dev->tx_buff, ether_dev->wMaxSegmentSize, + write_bulk_callback, ether_dev ); + + // Tell the URB how much it will be transporting today + ether_dev->tx_urb.transfer_buffer_length = count; + + // Send the URB on its merry way. + if ((res = usb_submit_urb(ðer_dev->tx_urb))) { + // Hmm... It didn't go. Tell someone... + warn("failed tx_urb %d", res); + // update some stats... + ether_dev->stats.tx_errors++; + // and tell the kernel to give us another. + // Maybe we'll get it right next time. + netif_start_queue( net ); + } else { + // Okay, it went out. + // Update statistics + ether_dev->stats.tx_packets++; + ether_dev->stats.tx_bytes += skb->len; + // And tell the kernel when the last transmit occurred. + net->trans_start = jiffies; + } + + // We are done with the kernel's memory + dev_kfree_skb(skb); + + // We are done here. + return 0; +} + +static struct net_device_stats *CDCEther_netdev_stats( struct net_device *net ) +{ + // Easy enough! + return &((ether_dev_t *)net->priv)->stats; +} + +static int CDCEther_open(struct net_device *net) +{ + ether_dev_t *ether_dev = (ether_dev_t *)net->priv; + int res; + + // We are finally getting used! + MOD_INC_USE_COUNT; + + // Turn on the USB and let the packets flow!!! + if ( (res = enable_net_traffic( ether_dev )) ) { + err( __FUNCTION__ "can't enable_net_traffic() - %d", res ); + MOD_DEC_USE_COUNT; + return -EIO; + } + + // Prep a receive URB + FILL_BULK_URB( ðer_dev->rx_urb, ether_dev->usb, + usb_rcvbulkpipe(ether_dev->usb, ether_dev->data_ep_in), + ether_dev->rx_buff, ether_dev->wMaxSegmentSize, + read_bulk_callback, ether_dev ); + + // Put it out there so the device can send us stuff + if ( (res = usb_submit_urb(ðer_dev->rx_urb)) ) + { + // Hmm... Okay... + warn( __FUNCTION__ " failed rx_urb %d", res ); + } + + // Tell the kernel we are ready to start receiving from it + netif_start_queue( net ); + + // We are up and running. + ether_dev->flags |= CDC_ETHER_RUNNING; + + // Let's get ready to move frames!!! + return 0; +} + +static int CDCEther_close( struct net_device *net ) +{ + ether_dev_t *ether_dev = net->priv; + + // We are no longer running. + ether_dev->flags &= ~CDC_ETHER_RUNNING; + + // Tell the kernel to stop sending us stuff + netif_stop_queue( net ); + + // If we are not already unplugged, turn off USB + // traffic + if ( !(ether_dev->flags & CDC_ETHER_UNPLUG) ) { + disable_net_traffic( ether_dev ); + } + + // We don't need the URBs anymore. + usb_unlink_urb( ðer_dev->rx_urb ); + usb_unlink_urb( ðer_dev->tx_urb ); + usb_unlink_urb( ðer_dev->intr_urb ); + + // We are not being used now. + MOD_DEC_USE_COUNT; + + // That's it. I'm done. + return 0; +} + +static int CDCEther_ioctl( struct net_device *net, struct ifreq *rq, int cmd ) +{ + //__u16 *data = (__u16 *)&rq->ifr_data; + //ether_dev_t *ether_dev = net->priv; + + // No support here yet. + // Do we need support??? + switch(cmd) { + case SIOCDEVPRIVATE: + return -EOPNOTSUPP; + case SIOCDEVPRIVATE+1: + return -EOPNOTSUPP; + case SIOCDEVPRIVATE+2: + //return 0; + return -EOPNOTSUPP; + default: + return -EOPNOTSUPP; + } +} + +static void CDCEther_set_multicast( struct net_device *net ) +{ + ether_dev_t *ether_dev = net->priv; + + // Tell the kernel to stop sending us frames while we get this + // all set up. + netif_stop_queue(net); + + // Do what we are told. + if (net->flags & IFF_PROMISC) { + // TODO - Turn on promiscuous mode + info( "%s: Promiscuous mode enabled", net->name); + } else if (net->flags & IFF_ALLMULTI){ + // TODO - Here we need to tell the device to block ALL multicast traffic. + info("%s: set allmulti", net->name); + } else if (net->mc_count > ether_dev->wNumberMCFilters) { + // TODO - Here we need to set multicast filters, but + // There are more than our limit... Hmm... + info("%s: set too many MC filters", net->name); + } else { + // TODO - Here we are supposed to set SOME of the multicast filters. + // I must learn how to do this... + //info("%s: set Rx mode", net->name); + } + + // Tell the kernel to start giving frames to us again. + netif_wake_queue(net); +} + +////////////////////////////////////////////////////////////////////////////// +// Routines used to parse out the Functional Descriptors ///////////////////// +////////////////////////////////////////////////////////////////////////////// + +static int parse_header_functional_descriptor( int *bFunctionLength, + int bDescriptorType, + int bDescriptorSubtype, + unsigned char *data, + ether_dev_t *ether_dev, + int *requirements ) +{ + // Check to make sure we haven't seen one of these already. + if ( (~*requirements) & REQ_HDR_FUNC_DESCR ) { + err( "Multiple Header Functional Descriptors found." ); + return -1; + } + + // Is it the right size??? + if (*bFunctionLength != 5) { + info( "Invalid length in Header Functional Descriptor" ); + // This is a hack to get around a particular device (NO NAMES) + // It has this function length set to the length of the + // whole class-specific descriptor + *bFunctionLength = 5; + } + + // Nothing extremely useful here. + // We'll keep it for posterity + ether_dev->bcdCDC = data[0] + (data[1] << 8); + + // We've seen one of these + *requirements &= ~REQ_HDR_FUNC_DESCR; + + // It's all good. + return 0; +} + +static int parse_union_functional_descriptor( int *bFunctionLength, + int bDescriptorType, + int bDescriptorSubtype, + unsigned char *data, + ether_dev_t *ether_dev, + int *requirements ) +{ + // Check to make sure we haven't seen one of these already. + if ( (~*requirements) & REQ_UNION_FUNC_DESCR ) { + err( "Multiple Union Functional Descriptors found." ); + return -1; + } + + // Is it the right size? + if (*bFunctionLength != 5) { + // It is NOT the size we expected. + err( "Unsupported length in Union Functional Descriptor" ); + return -1; + } + + // Sanity check of sorts + if (ether_dev->comm_interface != data[0]) { + // This tells us that we are chasing the wrong comm + // interface or we are crazy or something else wierd. + err( "Union Functional Descriptor tells us to use a different Communication Interface" ); + return -1; + } + + // We'll need this in a few microseconds! + ether_dev->data_interface = data[1]; + + // We've seen one of these now. + *requirements &= ~REQ_UNION_FUNC_DESCR; + + // Done + return 0; +} + +static int parse_ethernet_functional_descriptor( int *bFunctionLength, + int bDescriptorType, + int bDescriptorSubtype, + unsigned char *data, + ether_dev_t *ether_dev, + int *requirements ) +{ + // Check to make sure we haven't seen one of these already. + if ( (~*requirements) & REQ_ETH_FUNC_DESCR ) { + err( "Multiple Ethernet Functional Descriptors found." ); + return -1; + } + + // Is it the right size? + if (*bFunctionLength != 13) { + err( "Invalid length in Ethernet Networking Functional Descriptor" ); + return -1; + } + + // Lots of goodies from this one. They are all important. + ether_dev->iMACAddress = data[0]; + ether_dev->bmEthernetStatistics = data[1] + (data[2] << 8) + (data[3] << 16) + (data[4] << 24); + ether_dev->wMaxSegmentSize = data[5] + (data[6] << 8); + ether_dev->wNumberMCFilters = (data[7] + (data[8] << 8)) & 0x00007FFF; + ether_dev->bNumberPowerFilters = data[9]; + + // We've seen one of these now. + *requirements &= ~REQ_ETH_FUNC_DESCR; + + // That's all she wrote. + return 0; +} + +static int parse_protocol_unit_functional_descriptor( int *bFunctionLength, + int bDescriptorType, + int bDescriptorSubtype, + unsigned char *data, + ether_dev_t *ether_dev, + int *requirements ) +{ + // There should only be one type if we are sane + if (bDescriptorType != CS_INTERFACE) { + info( "Invalid bDescriptorType found." ); + return -1; + } + + // The Subtype tells the tale. + switch (bDescriptorSubtype){ + case 0x00: // Header Functional Descriptor + return parse_header_functional_descriptor( bFunctionLength, + bDescriptorType, + bDescriptorSubtype, + data, + ether_dev, + requirements ); + break; + case 0x06: // Union Functional Descriptor + return parse_union_functional_descriptor( bFunctionLength, + bDescriptorType, + bDescriptorSubtype, + data, + ether_dev, + requirements ); + break; + case 0x0F: // Ethernet Networking Functional Descriptor + return parse_ethernet_functional_descriptor( bFunctionLength, + bDescriptorType, + bDescriptorSubtype, + data, + ether_dev, + requirements ); + break; + default: // We don't support this at this time... + // However that doesn't necessarily indicate an error. + return 0; + } + // How did we get here??? + return -1; +} + +static int parse_ethernet_class_information( unsigned char *data, int length, ether_dev_t *ether_dev ) +{ + int loc = 0; + int rc; + int bFunctionLength; + int bDescriptorType; + int bDescriptorSubtype; + int requirements = REQUIREMENTS_TOTAL; + + // As long as there is something here, we will try to parse it + while (loc < length) { + // Length + bFunctionLength = data[loc]; + loc++; + + // Type + bDescriptorType = data[loc]; + loc++; + + // Subtype + bDescriptorSubtype = data[loc]; + loc++; + + // ship this off to be processed elsewhere. + rc = parse_protocol_unit_functional_descriptor( &bFunctionLength, + bDescriptorType, + bDescriptorSubtype, + &data[loc], + ether_dev, + &requirements ); + // Did it process okay? + if (rc) { + // Something was hosed somewhere. + // No need to continue; + return -1; + } + // We have already taken three bytes. + loc += (bFunctionLength - 3); + } + // Check to see if we got everything we need. + if (requirements) { + // We missed some of the requirements... + err( "Not all required functional descriptors present 0x%08X", requirements ); + return -1; + } + // We got everything. + return 0; +} + +////////////////////////////////////////////////////////////////////////////// +// Routine to check for the existence of the Functional Descriptors ////////// +////////////////////////////////////////////////////////////////////////////// + +static int find_and_parse_ethernet_class_information( struct usb_device *device, ether_dev_t *ether_dev ) +{ + struct usb_config_descriptor *conf = NULL; + struct usb_interface *comm_intf_group = NULL; + struct usb_interface_descriptor *comm_intf = NULL; + int rc = -1; + // The assumption here is that find_ethernet_comm_interface + // and find_valid_configuration + // have already filled in the information about where to find + // the a valid commication interface. + + conf = &( device->config[ether_dev->configuration_num] ); + comm_intf_group = &( conf->interface[ether_dev->comm_interface] ); + comm_intf = &( comm_intf_group->altsetting[ether_dev->comm_interface_altset_num] ); + // Let's check and see if it has the extra information we need... + + if (comm_intf->extralen > 0) { + // This is where the information is SUPPOSED to be. + rc = parse_ethernet_class_information( comm_intf->extra, comm_intf->extralen, ether_dev ); + } else if (conf->extralen > 0) { + // This is a hack. The spec says it should be at the interface + // location checked above. However I have seen it here also. + // This is the same device that requires the functional descriptor hack above + warn( "Ethernet information found at device configuration. This is broken." ); + rc = parse_ethernet_class_information( comm_intf->extra, comm_intf->extralen, ether_dev ); + } else { + // I don't know where else to look. + warn( "No ethernet information found." ); + rc = -1; + } + return rc; +} + +////////////////////////////////////////////////////////////////////////////// +// Routines to verify the data interface ///////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +static int get_data_interface_endpoints( struct usb_device *device, ether_dev_t *ether_dev ) +{ + struct usb_config_descriptor *conf = NULL; + struct usb_interface *data_intf_group = NULL; + struct usb_interface_descriptor *data_intf = NULL; + + // Walk through and get to the data interface we are checking. + conf = &( device->config[ether_dev->configuration_num] ); + data_intf_group = &( conf->interface[ether_dev->data_interface] ); + data_intf = &( data_intf_group->altsetting[ether_dev->data_interface_altset_num_with_traffic] ); + + // Start out assuming we won't find anything we can use + ether_dev->data_ep_in = 0; + ether_dev->data_ep_out = 0; + + // If these are not BULK endpoints, we don't want them + if ( data_intf->endpoint[0].bmAttributes != 0x02 ) { + return -1; + } if ( data_intf->endpoint[1].bmAttributes != 0x02 ) { + return -1; + } + + // Check the first endpoint to see if it is IN or OUT + if ( data_intf->endpoint[0].bEndpointAddress & 0x80 ) { + // This endpoint is IN + ether_dev->data_ep_in = data_intf->endpoint[0].bEndpointAddress & 0x7F; + } else { + // This endpoint is OUT + ether_dev->data_ep_out = data_intf->endpoint[0].bEndpointAddress & 0x7F; + ether_dev->data_ep_out_size = data_intf->endpoint[0].wMaxPacketSize; + } + + // Check the second endpoint to see if it is IN or OUT + if ( data_intf->endpoint[1].bEndpointAddress & 0x80 ) { + // This endpoint is IN + ether_dev->data_ep_in = data_intf->endpoint[1].bEndpointAddress & 0x7F; + } else { + // This endpoint is OUT + ether_dev->data_ep_out = data_intf->endpoint[1].bEndpointAddress & 0x7F; + ether_dev->data_ep_out_size = data_intf->endpoint[1].wMaxPacketSize; + } + + // Now make sure we got both an IN and an OUT + if (ether_dev->data_ep_in && ether_dev->data_ep_out) { + // We did get both, we are in good shape... + info( "detected BULK OUT packets of size %d", ether_dev->data_ep_out_size ); + return 0; + } + return -1; +} + +static int verify_ethernet_data_interface( struct usb_device *device, ether_dev_t *ether_dev ) +{ + struct usb_config_descriptor *conf = NULL; + struct usb_interface *data_intf_group = NULL; + struct usb_interface_descriptor *data_intf = NULL; + int rc = -1; + int status; + int altset_num; + + // The assumption here is that parse_ethernet_class_information() + // and find_valid_configuration() + // have already filled in the information about where to find + // a data interface + conf = &( device->config[ether_dev->configuration_num] ); + data_intf_group = &( conf->interface[ether_dev->data_interface] ); + + // start out assuming we won't find what we are looking for. + ether_dev->data_interface_altset_num_with_traffic = -1; + ether_dev->data_bAlternateSetting_with_traffic = -1; + ether_dev->data_interface_altset_num_without_traffic = -1; + ether_dev->data_bAlternateSetting_without_traffic = -1; + + // Walk through every possible setting for this interface until + // we find what makes us happy. + for ( altset_num = 0; altset_num < data_intf_group->num_altsetting; altset_num++ ) { + data_intf = &( data_intf_group->altsetting[altset_num] ); + + // Is this a data interface we like? + if ( ( data_intf->bInterfaceClass == 0x0A ) + && ( data_intf->bInterfaceSubClass == 0x00 ) + && ( data_intf->bInterfaceProtocol == 0x00 ) ) { + if ( data_intf->bNumEndpoints == 2 ) { + // We are required to have one of these. + // An interface with 2 endpoints to send Ethernet traffic back and forth + // It actually may be possible that the device might only + // communicate in a vendor specific manner. + // That would not be very nice. + // We can add that one later. + ether_dev->data_bInterfaceNumber = data_intf->bInterfaceNumber; + ether_dev->data_interface_altset_num_with_traffic = altset_num; + ether_dev->data_bAlternateSetting_with_traffic = data_intf->bAlternateSetting; + status = get_data_interface_endpoints( device, ether_dev ); + if (!status) { + rc = 0; + } + } + if ( data_intf->bNumEndpoints == 0 ) { + // According to the spec we are SUPPOSED to have one of these + // In fact the device is supposed to come up in this state. + // However, I have seen a device that did not have such an interface. + // So it must be just optional for our driver... + ether_dev->data_bInterfaceNumber = data_intf->bInterfaceNumber; + ether_dev->data_interface_altset_num_without_traffic = altset_num; + ether_dev->data_bAlternateSetting_without_traffic = data_intf->bAlternateSetting; + } + } + } + return rc; +} + +////////////////////////////////////////////////////////////////////////////// +// Routine to find a communication interface ///////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +static int find_ethernet_comm_interface( struct usb_device *device, ether_dev_t *ether_dev ) +{ + struct usb_config_descriptor *conf = NULL; + struct usb_interface *comm_intf_group = NULL; + struct usb_interface_descriptor *comm_intf = NULL; + int intf_num; + int altset_num; + int rc; + + conf = &( device->config[ether_dev->configuration_num] ); + + // We need to check and see if any of these interfaces are something we want. + // Walk through each interface one at a time + for ( intf_num = 0; intf_num < conf->bNumInterfaces; intf_num++ ) { + comm_intf_group = &( conf->interface[intf_num] ); + // Now for each of those interfaces, check every possible + // alternate setting. + for ( altset_num = 0; altset_num < comm_intf_group->num_altsetting; altset_num++ ) { + comm_intf = &( comm_intf_group->altsetting[altset_num] ); + + // Is this a communication class of interface of the + // ethernet subclass variety. + if ( ( comm_intf->bInterfaceClass == 0x02 ) + && ( comm_intf->bInterfaceSubClass == 0x06 ) + && ( comm_intf->bInterfaceProtocol == 0x00 ) ) { + if ( comm_intf->bNumEndpoints == 1 ) { + // Good, we found one, we will try this one + // Fill in the structure... + ether_dev->comm_interface = intf_num; + ether_dev->comm_bInterfaceNumber = comm_intf->bInterfaceNumber; + ether_dev->comm_interface_altset_num = altset_num; + ether_dev->comm_bAlternateSetting = comm_intf->bAlternateSetting; + + // Look for the Ethernet Functional Descriptors + rc = find_and_parse_ethernet_class_information( device, ether_dev ); + if (rc) { + // Nope this was no good after all. + continue; + } + + // Check that we really can talk to the data + // interface + // This includes # of endpoints, protocols, + // etc. + rc = verify_ethernet_data_interface( device, ether_dev ); + if (rc) { + // We got something we didn't like + continue; + } + // This communication interface seems to give us everything + // we require. We have all the ethernet info we need. + // Let's get out of here and go home right now. + return 0; + } else { + // bNumEndPoints != 1 + // We found an interface that had the wrong number of + // endpoints but would have otherwise been okay + } // end bNumEndpoints check. + } // end interface specifics check. + } // end for altset_num + } // end for intf_num + return -1; +} + +////////////////////////////////////////////////////////////////////////////// +// Routine to go through all configurations and find one that //////////////// +// is an Ethernet Networking Device ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +static int find_valid_configuration( struct usb_device *device, ether_dev_t *ether_dev ) +{ + struct usb_config_descriptor *conf = NULL; + int conf_num; + int rc; + + // We will try each and every possible configuration + for ( conf_num = 0; conf_num < device->descriptor.bNumConfigurations; conf_num++ ) { + conf = &( device->config[conf_num] ); + + // Our first requirement : 2 interfaces + if ( conf->bNumInterfaces != 2 ) { + // I currently don't know how to handle devices with any number of interfaces + // other than 2. + continue; + } + + // This one passed our first check, fill in some + // useful data + ether_dev->configuration_num = conf_num; + ether_dev->bConfigurationValue = conf->bConfigurationValue; + + // Now run it through the ringers and see what comes + // out the other side. + rc = find_ethernet_comm_interface( device, ether_dev ); + + // Check if we found an ethernet Communcation Device + if ( !rc ) { + // We found one. + return 0; + } + } + // None of the configurations suited us. + return -1; +} + +////////////////////////////////////////////////////////////////////////////// +// Routine that checks a given configuration to see if any driver //////////// +// has claimed any of the devices interfaces ///////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +static int check_for_claimed_interfaces( struct usb_config_descriptor *config ) +{ + struct usb_interface *comm_intf_group; + int intf_num; + + // Go through all the interfaces and make sure none are + // claimed by anybody else. + for ( intf_num = 0; intf_num < config->bNumInterfaces; intf_num++ ) { + comm_intf_group = &( config->interface[intf_num] ); + if ( usb_interface_claimed( comm_intf_group ) ) { + // Somebody has beat us to this guy. + // We can't change the configuration out from underneath of whoever + // is using this device, so we will go ahead and give up. + return -1; + } + } + // We made it all the way through. + // I guess no one has claimed any of these interfaces. + return 0; +} + +////////////////////////////////////////////////////////////////////////////// +// Routines to ask for and set the kernel network interface's MAC address //// +// Used by driver's probe routine //////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +static inline unsigned char hex2dec( unsigned char digit ) +{ + // Is there a standard way to do this??? + // I have written this code TOO MANY times. + if ( (digit >= '0') && (digit <= '9') ) { + return (digit - '0'); + } + if ( (digit >= 'a') && (digit <= 'f') ) { + return (digit - 'a' + 10); + } + if ( (digit >= 'A') && (digit <= 'F') ) { + return (digit - 'A' + 10); + } + return 0; +} + +static void set_ethernet_addr( ether_dev_t *ether_dev ) +{ + unsigned char mac_addr[6]; + int i; + int len; + unsigned char buffer[13]; + + // Let's assume we don't get anything... + mac_addr[0] = 0x00; + mac_addr[1] = 0x00; + mac_addr[2] = 0x00; + mac_addr[3] = 0x00; + mac_addr[4] = 0x00; + mac_addr[5] = 0x00; + + // Let's ask the device... + len = usb_string(ether_dev->usb, ether_dev->iMACAddress, buffer, 13); + + // Sanity check! + if (len != 12) { + // You gotta love failing sanity checks + err("Attempting to get MAC address returned %d bytes", len); + return; + } + + // Fill in the mac_addr + for (i = 0; i < 6; i++) { + mac_addr[i] = ( hex2dec( buffer[2 * i] ) << 4 ) + hex2dec( buffer[2 * i + 1] ); + } + + // Now copy it over to the kernel's network driver. + memcpy( ether_dev->net->dev_addr, mac_addr, sizeof(mac_addr) ); +} + +////////////////////////////////////////////////////////////////////////////// +// Routine to print to syslog information about the driver /////////////////// +// Used by driver's probe routine //////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +void log_device_info(ether_dev_t *ether_dev) +{ + int len; + int string_num; + unsigned char manu[256]; + unsigned char prod[256]; + unsigned char sern[256]; + unsigned char *mac_addr; + + // Default empty strings in case we don't find a real one + manu[0] = 0x00; + prod[0] = 0x00; + sern[0] = 0x00; + + // Try to get the device Manufacturer + string_num = ether_dev->usb->descriptor.iManufacturer; + if (string_num) { + // Put it into its buffer + len = usb_string(ether_dev->usb, string_num, manu, 255); + // Just to be safe + manu[len] = 0x00; + } + + // Try to get the device Product Name + string_num = ether_dev->usb->descriptor.iProduct; + if (string_num) { + // Put it into its buffer + len = usb_string(ether_dev->usb, string_num, prod, 255); + // Just to be safe + prod[len] = 0x00; + } + + // Try to get the device Serial Number + string_num = ether_dev->usb->descriptor.iSerialNumber; + if (string_num) { + // Put it into its buffer + len = usb_string(ether_dev->usb, string_num, sern, 255); + // Just to be safe + sern[len] = 0x00; + } + + // This makes it easier for us to print + mac_addr = ether_dev->net->dev_addr; + + // Now send everything we found to the syslog + info( "%s: %s %s %s %02X:%02X:%02X:%02X:%02X:%02X", + ether_dev->net->name, manu, prod, sern, mac_addr[0], + mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], + mac_addr[5] ); +} + +/* Forward declaration */ +static struct usb_driver CDCEther_driver ; + +////////////////////////////////////////////////////////////////////////////// +// Module's probe routine //////////////////////////////////////////////////// +// claims interfaces if they are for an Ethernet CDC ///////////////////////// +////////////////////////////////////////////////////////////////////////////// + +static void * CDCEther_probe( struct usb_device *usb, unsigned int ifnum, + const struct usb_device_id *id) +{ + struct net_device *net; + ether_dev_t *ether_dev; + int rc; + + // First we should check the active configuration to see if + // any other driver has claimed any of the interfaces. + if ( check_for_claimed_interfaces( usb->actconfig ) ) { + // Someone has already put there grubby paws on this device. + // We don't want it now... + return NULL; + } + + // We might be finding a device we can use. + // We all go ahead and allocate our storage space. + // We need to because we have to start filling in the data that + // we are going to need later. + if(!(ether_dev = kmalloc(sizeof(ether_dev_t), GFP_KERNEL))) { + err("out of memory allocating device structure"); + return NULL; + } + + // Zero everything out. + memset(ether_dev, 0, sizeof(ether_dev_t)); + + // Let's see if we can find a configuration we can use. + rc = find_valid_configuration( usb, ether_dev ); + if (rc) { + // Nope we couldn't find one we liked. + // This device was not meant for us to control. + kfree( ether_dev ); + return NULL; + } + + // Now that we FOUND a configuration. let's try to make the + // device go into it. + if ( usb_set_configuration( usb, ether_dev->bConfigurationValue ) ) { + err("usb_set_configuration() failed"); + kfree( ether_dev ); + return NULL; + } + + // Now set the communication interface up as required. + if (usb_set_interface(usb, ether_dev->comm_bInterfaceNumber, ether_dev->comm_bAlternateSetting)) { + err("usb_set_interface() failed"); + kfree( ether_dev ); + return NULL; + } + + // Only turn traffic on right now if we must... + if (ether_dev->data_interface_altset_num_without_traffic >= 0) { + // We found an alternate setting for the data + // interface that allows us to turn off traffic. + // We should use it. + if (usb_set_interface( usb, + ether_dev->data_bInterfaceNumber, + ether_dev->data_bAlternateSetting_without_traffic)) { + err("usb_set_interface() failed"); + kfree( ether_dev ); + return NULL; + } + } else { + // We didn't find an alternate setting for the data + // interface that would let us turn off traffic. + // Oh well, let's go ahead and do what we must... + if (usb_set_interface( usb, + ether_dev->data_bInterfaceNumber, + ether_dev->data_bAlternateSetting_with_traffic)) { + err("usb_set_interface() failed"); + kfree( ether_dev ); + return NULL; + } + } + + // Now we need to get a kernel Ethernet interface. + net = init_etherdev( NULL, 0 ); + if ( !net ) { + // Hmm... The kernel is not sharing today... + // Fine, we didn't want it anyway... + err( "Unable to initialize ethernet device" ); + kfree( ether_dev ); + return NULL; + } + + // Now that we have an ethernet device, let's set it up + // (And I don't mean "set [it] up the bomb".) + net->priv = ether_dev; + net->open = CDCEther_open; + net->stop = CDCEther_close; + net->watchdog_timeo = CDC_ETHER_TX_TIMEOUT; + net->tx_timeout = CDCEther_tx_timeout; // TX timeout function + net->do_ioctl = CDCEther_ioctl; + net->hard_start_xmit = CDCEther_start_xmit; + net->set_multicast_list = CDCEther_set_multicast; + net->get_stats = CDCEther_netdev_stats; + net->mtu = ether_dev->wMaxSegmentSize - 14; + + // We'll keep track of this information for later... + ether_dev->usb = usb; + ether_dev->net = net; + + // and don't forget the MAC address. + set_ethernet_addr( ether_dev ); + + // Send a message to syslog about what we are handling + log_device_info( ether_dev ); + + // I claim this interface to be a CDC Ethernet Networking device + usb_driver_claim_interface( &CDCEther_driver, + &(usb->config[ether_dev->configuration_num].interface[ether_dev->comm_interface]), + ether_dev ); + // I claim this interface to be a CDC Ethernet Networking device + usb_driver_claim_interface( &CDCEther_driver, + &(usb->config[ether_dev->configuration_num].interface[ether_dev->data_interface]), + ether_dev ); + + // Does this REALLY do anything??? + usb_inc_dev_use( usb ); + + // TODO - last minute HACK + ether_dev->comm_ep_in = 5; + + // Okay, we are finally done... + return NULL; +} + + +////////////////////////////////////////////////////////////////////////////// +// Module's disconnect routine /////////////////////////////////////////////// +// Called when the driver is unloaded or the device is unplugged ///////////// +// (Whichever happens first assuming the driver suceeded at its probe) /////// +////////////////////////////////////////////////////////////////////////////// + +static void CDCEther_disconnect( struct usb_device *usb, void *ptr ) +{ + ether_dev_t *ether_dev = ptr; + + // Sanity check!!! + if ( !ether_dev || !ether_dev->usb ) { + // We failed. We are insane!!! + warn("unregistering non-existant device"); + return; + } + + // Make sure we fail the sanity check if we try this again. + ether_dev->usb = NULL; + + // It is possible that this function is called before + // the "close" function. + // This tells the close function we are already disconnected + ether_dev->flags |= CDC_ETHER_UNPLUG; + + // We don't need the network device any more + unregister_netdev( ether_dev->net ); + + // For sanity checks + ether_dev->net = NULL; + + // I ask again, does this do anything??? + usb_dec_dev_use( usb ); + + // We are done with this interface + usb_driver_release_interface( &CDCEther_driver, + &(usb->config[ether_dev->configuration_num].interface[ether_dev->comm_interface]) ); + + // We are done with this interface too + usb_driver_release_interface( &CDCEther_driver, + &(usb->config[ether_dev->configuration_num].interface[ether_dev->data_interface]) ); + + // No more tied up kernel memory + kfree( ether_dev ); + + // This does no good, but it looks nice! + ether_dev = NULL; +} + +////////////////////////////////////////////////////////////////////////////// +// Driver info /////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +static struct usb_driver CDCEther_driver = { + name: "CDCEther", + probe: CDCEther_probe, + disconnect: CDCEther_disconnect, + id_table: CDCEther_ids, +}; + +////////////////////////////////////////////////////////////////////////////// +// init and exit routines called when driver is installed and uninstalled //// +////////////////////////////////////////////////////////////////////////////// + +int __init CDCEther_init(void) +{ + info( "%s", version ); + return usb_register( &CDCEther_driver ); +} + +void __exit CDCEther_exit(void) +{ + usb_deregister( &CDCEther_driver ); +} + +////////////////////////////////////////////////////////////////////////////// +// Module info /////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +module_init( CDCEther_init ); +module_exit( CDCEther_exit ); + +MODULE_AUTHOR("Brad Hards and another"); +MODULE_DESCRIPTION("USB CDC Ethernet driver"); + +MODULE_DEVICE_TABLE (usb, CDCEther_ids); + +////////////////////////////////////////////////////////////////////////////// +// End of file /////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/CDCEther.h linux.ac/drivers/usb/CDCEther.h --- linux.vanilla/drivers/usb/CDCEther.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/usb/CDCEther.h Tue Apr 3 23:15:34 2001 @@ -0,0 +1,88 @@ +// Portions of this file taken from +// Petko Manolov - Petkan (petkan@dce.bg) +// from his driver pegasus.h + +/* + * 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 + */ + + +#define CS_INTERFACE 0x24 + +#define CDC_ETHER_MAX_MTU 1536 + +#define CDC_ETHER_PRESENT 0x00000001 +#define CDC_ETHER_RUNNING 0x00000002 +#define CDC_ETHER_TX_BUSY 0x00000004 +#define CDC_ETHER_RX_BUSY 0x00000008 +#define CDC_ETHER_UNPLUG 0x00000040 + +#define CDC_ETHER_TX_TIMEOUT (HZ*10) + +#define TX_UNDERRUN 0x80 +#define EXCESSIVE_COL 0x40 +#define LATE_COL 0x20 +#define NO_CARRIER 0x10 +#define LOSS_CARRIER 0x08 +#define JABBER_TIMEOUT 0x04 + +#define CDC_ETHER_REQT_READ 0xc0 +#define CDC_ETHER_REQT_WRITE 0x40 +#define CDC_ETHER_REQ_GET_REGS 0xf0 +#define CDC_ETHER_REQ_SET_REGS 0xf1 +#define CDC_ETHER_REQ_SET_REG PIPERIDER_REQ_SET_REGS +#define ALIGN(x) x __attribute__((aligned(L1_CACHE_BYTES))) + +typedef struct _ether_dev_t { + struct usb_device *usb; + struct net_device *net; + struct net_device_stats stats; + unsigned flags; + int configuration_num; + int bConfigurationValue; + int comm_interface; + int comm_bInterfaceNumber; + int comm_interface_altset_num; + int comm_bAlternateSetting; + int comm_ep_in; + int data_interface; + int data_bInterfaceNumber; + int data_interface_altset_num_with_traffic; + int data_bAlternateSetting_with_traffic; + int data_interface_altset_num_without_traffic; + int data_bAlternateSetting_without_traffic; + int data_ep_in; + int data_ep_out; + int data_ep_out_size; + __u16 bcdCDC; + __u8 iMACAddress; + __u32 bmEthernetStatistics; + __u16 wMaxSegmentSize; + __u16 wNumberMCFilters; + __u8 bNumberPowerFilters; + int intr_interval; + struct urb rx_urb, tx_urb, intr_urb; + unsigned char ALIGN(rx_buff[CDC_ETHER_MAX_MTU]); + unsigned char ALIGN(tx_buff[CDC_ETHER_MAX_MTU]); + unsigned char ALIGN(intr_buff[8]); +} ether_dev_t; + +#define REQ_HDR_FUNC_DESCR 0x0001 +#define REQ_UNION_FUNC_DESCR 0x0002 +#define REQ_ETH_FUNC_DESCR 0x0004 +#define REQUIREMENTS_TOTAL 0x0007 + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/Config.in linux.ac/drivers/usb/Config.in --- linux.vanilla/drivers/usb/Config.in Tue Nov 28 02:10:35 2000 +++ linux.ac/drivers/usb/Config.in Tue Apr 3 23:15:34 2001 @@ -53,6 +53,7 @@ dep_tristate ' USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB $CONFIG_EXPERIMENTAL dep_tristate ' USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB dep_tristate ' Microtek X6USB scanner support (EXPERIMENTAL)' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI $CONFIG_EXPERIMENTAL + dep_tristate ' HP 5300 C scanner support (EXPERIMENTAL)' CONFIG_USB_HP5300 $CONFIG_USB $CONFIG_SCSI $CONFIG_EXPERIMENTAL comment 'USB Multimedia devices' dep_tristate ' USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV @@ -63,7 +64,9 @@ comment 'USB Network adaptors' dep_tristate ' PLUSB Prolific USB-Network driver (EXPERIMENTAL)' CONFIG_USB_PLUSB $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL dep_tristate ' USB ADMtek Pegasus-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL - dep_tristate ' NetChip 1080-based USB Host-to-Host Link (EXPERIMENTAL)' CONFIG_USB_NET1080 $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL + dep_tristate ' USB KLSI KL5USB101-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_KAWETH $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL + dep_tristate ' USB Communication Class Ethernet driver (EXPERIMENTAL)' CONFIG_USB_CDCETHER $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL + dep_tristate ' USB-to-USB Networking (NetChip, Prolific, ...) (EXPERIMENTAL)' CONFIG_USB_USBNET $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL comment 'USB port drivers' dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/Makefile linux.ac/drivers/usb/Makefile --- linux.vanilla/drivers/usb/Makefile Fri Dec 29 22:07:23 2000 +++ linux.ac/drivers/usb/Makefile Tue Apr 3 23:15:34 2001 @@ -46,19 +46,25 @@ obj-$(CONFIG_USB_ACM) += acm.o obj-$(CONFIG_USB_PRINTER) += printer.o obj-$(CONFIG_USB_AUDIO) += audio.o -obj-$(CONFIG_USB_IBMCAM) += ibmcam.o +obj-$(CONFIG_USB_IBMCAM) += ibmcam.o usbvideo.o ultracam.o obj-$(CONFIG_USB_DC2XX) += dc2xx.o obj-$(CONFIG_USB_MDC800) += mdc800.o obj-$(CONFIG_USB_USS720) += uss720.o obj-$(CONFIG_USB_DABUSB) += dabusb.o -obj-$(CONFIG_USB_PLUSB) += plusb.o obj-$(CONFIG_USB_OV511) += ov511.o -obj-$(CONFIG_USB_PEGASUS) += pegasus.o obj-$(CONFIG_USB_RIO500) += rio500.o obj-$(CONFIG_USB_DSBR) += dsbr100.o obj-$(CONFIG_USB_MICROTEK) += microtek.o +obj-$(CONFIG_USB_HP5300) += hp5300.o obj-$(CONFIG_USB_BLUETOOTH) += bluetooth.o -obj-$(CONFIG_USB_NET1080) += net1080.o + +# network drivers + +obj-$(CONFIG_USB_CDCETHER) += CDCEther.o +obj-$(CONFIG_USB_KAWETH) += kaweth.o +obj-$(CONFIG_USB_PEGASUS) += pegasus.o +obj-$(CONFIG_USB_PLUSB) += plusb.o +obj-$(CONFIG_USB_USBNET) += usbnet.o # Object files in subdirectories @@ -79,4 +85,3 @@ usbcore.o: $(usbcore-objs) $(LD) -r -o $@ $(usbcore-objs) - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/acm.c linux.ac/drivers/usb/acm.c --- linux.vanilla/drivers/usb/acm.c Sat Feb 17 00:06:17 2001 +++ linux.ac/drivers/usb/acm.c Tue Apr 3 23:27:23 2001 @@ -1,5 +1,5 @@ /* - * acm.c Version 0.18 + * acm.c Version 0.19 * * Copyright (c) 1999 Armin Fuerst <fuerst@in.tum.de> * Copyright (c) 1999 Pavel Machek <pavel@suse.cz> @@ -21,6 +21,7 @@ * v0.16 - added code for modems with swapped data and control interfaces * v0.17 - added new style probing * v0.18 - fixed new style probing for devices with more configurations + * v0.19 - fixed CLOCAL handling (thanks to Richard Shih-Ping Chan) */ /* @@ -195,13 +196,10 @@ newctrl = le16_to_cpup((__u16 *) data); -#if 0 - /* Please someone tell me how to do this properly to kill pppd and not kill minicom */ if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { dbg("calling hangup"); tty_hangup(acm->tty); } -#endif acm->ctrlin = newctrl; @@ -458,7 +456,7 @@ (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0; newline.databits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4]; - acm->clocal = termios->c_cflag & CLOCAL; + acm->clocal = ((termios->c_cflag & CLOCAL) != 0); if (!newline.speed) { newline.speed = acm->line.speed; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/audio.c linux.ac/drivers/usb/audio.c --- linux.vanilla/drivers/usb/audio.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/usb/audio.c Tue Apr 3 17:55:06 2001 @@ -3,7 +3,7 @@ /* * audio.c -- USB Audio Class driver * - * Copyright (C) 1999, 2000 + * Copyright (C) 1999, 2000, 2001 * Alan Cox (alan@lxorguk.ukuu.org.uk) * Thomas Sailer (sailer@ife.ee.ethz.ch) * @@ -92,7 +92,9 @@ * 2000-11-26: Thomas Sailer * Workaround for Dallas DS4201. The DS4201 uses PCM8 as format tag for * its 8 bit modes, but expects signed data (and should therefore have used PCM). - * + * 2001-03-10: Thomas Sailer + * provide abs function, prevent picking up a bogus kernel macro + * for abs. Bug report by Andrew Morton <andrewm@uow.edu.au> */ /* @@ -381,6 +383,17 @@ /* --------------------------------------------------------------------- */ +/* prevent picking up a bogus abs macro */ +#undef abs +extern inline int abs(int x) +{ + if (x < 0) + return -x; + return x; +} + +/* --------------------------------------------------------------------- */ + extern inline unsigned ld2(unsigned int x) { unsigned r = 0; @@ -3679,8 +3692,8 @@ return NULL; } ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buf, 8); - if (ret<0) { - printk(KERN_ERR "usbaudio: cannot get first 8 bytes of config descriptor %d of device %d\n", i, dev->devnum); + if (ret < 0) { + printk(KERN_ERR "usbaudio: cannot get first 8 bytes of config descriptor %d of device %d (error %d)\n", i, dev->devnum, ret); return NULL; } if (buf[1] != USB_DT_CONFIG || buf[0] < 9) { @@ -3693,7 +3706,7 @@ ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buffer, buflen); if (ret < 0) { kfree(buffer); - printk(KERN_ERR "usbaudio: cannot get config descriptor %d of device %d\n", i, dev->devnum); + printk(KERN_ERR "usbaudio: cannot get config descriptor %d of device %d (error %d)\n", i, dev->devnum, ret); return NULL; } return usb_audio_parsecontrol(dev, buffer, buflen, ifnum); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/dc2xx.c linux.ac/drivers/usb/dc2xx.c --- linux.vanilla/drivers/usb/dc2xx.c Tue Apr 3 17:32:23 2001 +++ linux.ac/drivers/usb/dc2xx.c Tue Apr 3 17:55:06 2001 @@ -48,7 +48,7 @@ * 01 Nov, 2000 .. usb_device_id support added by Adam J. Richter * * Thanks to: the folk who've provided USB product IDs, sent in - * patches, and shared their sucesses! + * patches, and shared their successes! */ #include <linux/config.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/devices.c linux.ac/drivers/usb/devices.c --- linux.vanilla/drivers/usb/devices.c Mon Sep 25 23:25:29 2000 +++ linux.ac/drivers/usb/devices.c Tue Apr 3 17:55:07 2001 @@ -384,7 +384,7 @@ int chix; int ret, cnt = 0; int parent_devnum = 0; - char *pages_start, *data_end; + char *pages_start, *data_end, *speed; unsigned int length; ssize_t total_written = 0; @@ -404,8 +404,21 @@ * So the root hub's parent is 0 and any device that is * plugged into the root hub has a parent of 0. */ - data_end = pages_start + sprintf(pages_start, format_topo, bus->busnum, level, parent_devnum, index, count, - usbdev->devnum, usbdev->slow ? "1.5" : "12 ", usbdev->maxchild); + switch (usbdev->speed) { + case USB_SPEED_LOW: + speed = "1.5"; break; + case USB_SPEED_UNKNOWN: /* usb 1.1 root hub code */ + case USB_SPEED_FULL: + speed = "12 "; break; + case USB_SPEED_HIGH: + speed = "480"; break; + default: + speed = "?? "; + } + data_end = pages_start + sprintf(pages_start, format_topo, + bus->busnum, level, parent_devnum, + index, count, usbdev->devnum, + speed, usbdev->maxchild); /* * level = topology-tier level; * parent_devnum = parent device number; @@ -475,6 +488,7 @@ return -EFAULT; /* enumerate busses */ + read_lock_irq (&usb_bus_list_lock); for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) { /* print devices for this bus */ bus = list_entry(buslist, struct usb_bus, bus_list); @@ -484,6 +498,7 @@ return ret; total_written += ret; } + read_unlock_irq (&usb_bus_list_lock); return total_written; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/devio.c linux.ac/drivers/usb/devio.c --- linux.vanilla/drivers/usb/devio.c Tue Apr 3 17:32:23 2001 +++ linux.ac/drivers/usb/devio.c Tue Apr 10 18:17:53 2001 @@ -175,6 +175,7 @@ return NULL; memset(as, 0, assize); as->urb.number_of_packets = numisoframes; + spin_lock_init(&as->urb.lock); return as; } @@ -250,10 +251,6 @@ struct dev_state *ps = as->ps; struct siginfo sinfo; -#if 1 - printk(KERN_DEBUG "usbdevfs: async_completed: status %d errcount %d actlen %d pipe 0x%x\n", - urb->status, urb->error_count, urb->actual_length, urb->pipe); -#endif spin_lock(&ps->lock); list_del(&as->asynclist); list_add_tail(&as->asynclist, &ps->async_completed); @@ -684,7 +681,7 @@ struct usbdevfs_connectinfo ci; ci.devnum = ps->dev->devnum; - ci.slow = ps->dev->slow; + ci.slow = ps->dev->speed == USB_SPEED_LOW; if (copy_to_user(arg, &ci, sizeof(ci))) return -EFAULT; return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/hid.c linux.ac/drivers/usb/hid.c --- linux.vanilla/drivers/usb/hid.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/usb/hid.c Tue Apr 3 17:55:07 2001 @@ -698,7 +698,7 @@ static __inline__ __u32 s32ton(__s32 value, unsigned n) { __s32 a = value >> (n - 1); - if (a && a != -1) return value > 0 ? 1 << (n - 1) : (1 << n) - 1; + if (a && a != -1) return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; return value & ((1 << n) - 1); } @@ -1016,9 +1016,15 @@ __s32 max = field->logical_maximum; __s32 value[count]; /* WARNING: gcc specific */ - for (n = 0; n < count; n++) + for (n = 0; n < count; n++) { value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) : extract(data, offset + n * size, size); + /* Handle the ErrorRollOver code (1) by simply ignoring this report */ + if (!(field->flags & HID_MAIN_ITEM_VARIABLE) + && value[n] >= min && value[n] <= max + && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) + return; + } for (n = 0; n < count; n++) { @@ -1181,7 +1187,7 @@ /* * Set a field value. The report this field belongs to has to be - * created and transfered to the device, to set this value in the + * created and transferred to the device, to set this value in the * device. */ @@ -1231,7 +1237,7 @@ static int hid_submit_out(struct hid_device *hid) { - hid->urbout.transfer_buffer_length = hid->out[hid->outtail].dr.length; + hid->urbout.transfer_buffer_length = le16_to_cpup(&hid->out[hid->outtail].dr.length); hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer; hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr); hid->urbout.dev = hid->dev; @@ -1271,8 +1277,8 @@ hid_set_field(field, offset, value); hid_output_report(field->report, hid->out[hid->outhead].buffer); - hid->out[hid->outhead].dr.value = 0x200 | field->report->id; - hid->out[hid->outhead].dr.length = ((field->report->size - 1) >> 3) + 1; + hid->out[hid->outhead].dr.value = cpu_to_le16(0x200 | field->report->id); + hid->out[hid->outhead].dr.length = cpu_to_le16((field->report->size + 7) >> 3); hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1); @@ -1445,7 +1451,7 @@ for (n = 0; n < HID_CONTROL_FIFO_SIZE; n++) { hid->out[n].dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE; hid->out[n].dr.request = USB_REQ_SET_REPORT; - hid->out[n].dr.index = hid->ifnum; + hid->out[n].dr.index = cpu_to_le16(hid->ifnum); } hid->input.name = hid->name; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/hid.h linux.ac/drivers/usb/hid.h --- linux.vanilla/drivers/usb/hid.h Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/usb/hid.h Tue Apr 17 18:42:29 2001 @@ -205,7 +205,7 @@ }; /* - * This is the local enviroment. It is resistent up the the next main-item. + * This is the local enviroment. It is resistent up the next main-item. */ #define HID_MAX_DESCRIPTOR_SIZE 4096 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/hp5300.c linux.ac/drivers/usb/hp5300.c --- linux.vanilla/drivers/usb/hp5300.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/usb/hp5300.c Tue Apr 3 17:55:07 2001 @@ -0,0 +1,1088 @@ +/* a driver to encapsulate SCSI in USB +* + * (C) Copyright 2000 John Fremlin <vii@penguinpowered.com> + * (C) Copyright 2000 Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de> + * (C) Copyright 2000 Jeremy Hall <JHall@UU.NET> + * + * Parts shamelessly stolen from usb-storage and microtek and copyright by their + * authors. Thanks to Matt Dharm for giving us permission! + * + * This driver implements a SCSI host controller driver and a USB + * device driver. To avoid confusion, all the USB related stuff is + * prefixed by usc_usb_ and all the SCSI stuff by usc_scsi_. + * + * Guessed protocol: + * + * Send raw SCSI command to EP 0x1 + * + * If there is data to receive: + * If the command was READ datatype=image: + * Read a lot of data from EP 0x83 + * Else: + * Read data from EP 0x82 + * Else: + * If there is data to transmit: + * Write it to EP 0x1 + * + * Read status byte from EP 0x82 + * + * References: + * + * The SCSI command set for the scanner is available from + * ftp://ftp.microtek.com/microtek/devpack/ + * + * We'll fix the comments later + * 20001006 16:53 EDT work begins + * 20001007 00:58:35 first test run + * 20001008 02:24:40 FIRST IMAGE SCANNED! + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/errno.h> +#include <linux/random.h> +#include <linux/poll.h> +#include <linux/init.h> +#include <linux/malloc.h> +#include <linux/spinlock.h> +#include <linux/smp_lock.h> +#include <linux/usb.h> +#include <linux/proc_fs.h> + +#include <asm/atomic.h> +#include <linux/blk.h> +#include "../scsi/scsi.h" +#include "../scsi/hosts.h" +#include "../scsi/sd.h" + +#include "hp5300.h" + +/* Constants */ + +#define USC_ABORT_TIMEOUT HZ /*jiffies*/ + + +/* Should we do debugging? */ + +#define USC_DO_DEBUG + + +static struct usb_device_id hp5300_usb_id [] = +{ + { USB_DEVICE(0x3f0, 0x0701) }, + { } +}; + + +/* USB layer driver interface */ + +static void *usc_usb_probe(struct usb_device *dev, unsigned int interface, const struct usb_device_id *id); +static void usc_usb_disconnect(struct usb_device *dev, void *ptr); + +static struct usb_driver usc_usb_driver = { + name: "hp5300", + probe: usc_usb_probe, + disconnect: usc_usb_disconnect, + id_table: hp5300_usb_id, +}; + + +/* Internal driver stuff */ + +#define USC_VERSION "0.0.1" +#define USC_NAME "USB-SCSI: " + +#define USC_WARNING(x...) \ + printk( KERN_WARNING USC_NAME x ) +#define USC_ERROR(x...) \ + printk( KERN_ERR USC_NAME x ) +#define USC_INT_ERROR(x...) \ + USC_ERROR(x) +#define USC_MESSAGE(x...) \ + printk( KERN_INFO USC_NAME x ) + +#if defined USC_DO_DEBUG + +#define USC_DEBUG(x...) \ + printk( KERN_DEBUG USC_NAME x ) + +#define USC_DEBUG_GOT_HERE() \ + USC_DEBUG("got to %s:%d (%s)\n", __FILE__, (int)__LINE__, __PRETTY_FUNCTION__ ) +#define USC_DEBUG_INT() \ + do { USC_DEBUG_GOT_HERE(); \ + USC_DEBUG("transfer = %x context = %x\n",(int)transfer,(int)context ); \ + USC_DEBUG("transfer->status = %x data-length = %x sent = %x\n",(int)transfer->status,(int)context->data_length, (int)transfer->actual_length ); \ + usc_debug_dump(context->instance);\ + } while(0) +#else + +#define USC_NUL_STATEMENT do { } while(0) + +#define USC_DEBUG(x...) USC_NUL_STATEMENT +#define USC_DEBUG_GOT_HERE() USC_NUL_STATEMENT +#define USC_DEBUG_INT() USC_NUL_STATEMENT +#define USC_DEBUG_HERE USC_NUL_STATEMENT + +#endif + + +static void usc_transfer_cleanup( struct urb *transfer ); + +#define USC_INT_INIT()\ + do {\ + context = (struct usc_transfer_context*)transfer->context; \ + if (atomic_read(&context->do_abort)) {\ + usc_transfer_cleanup(transfer);\ + return;\ + }\ + USC_DEBUG_INT();\ + } while (0) + +static inline void usc_debug_dump(struct usc_desc* desc) { + USC_DEBUG("desc at 0x%x: halted = %x%x, toggle = %x%x\n", + (int)desc,(int)desc->usb_dev->halted[1],(int)desc->usb_dev->halted[0], + (int)desc->usb_dev->toggle[1],(int)desc->usb_dev->toggle[0] + ); + USC_DEBUG("ep_out=%x ep_response=%x ep_image=%x\n", + desc->out_pipe, + desc->status_pipe, + desc->image_pipe + ); +} + + +static inline void usc_show_command(Scsi_Cmnd *srb) +{ + char *what = NULL; + + switch (srb->cmnd[0]) { + case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break; + case REZERO_UNIT: what = "REZERO_UNIT"; break; + case REQUEST_SENSE: what = "REQUEST_SENSE"; break; + case FORMAT_UNIT: what = "FORMAT_UNIT"; break; + case READ_BLOCK_LIMITS: what = "READ_BLOCK_LIMITS"; break; + case REASSIGN_BLOCKS: what = "REASSIGN_BLOCKS"; break; + case READ_6: what = "READ_6"; break; + case WRITE_6: what = "WRITE_6"; break; + case SEEK_6: what = "SEEK_6"; break; + case READ_REVERSE: what = "READ_REVERSE"; break; + case WRITE_FILEMARKS: what = "WRITE_FILEMARKS"; break; + case SPACE: what = "SPACE"; break; + case INQUIRY: what = "INQUIRY"; break; + case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break; + case MODE_SELECT: what = "MODE_SELECT"; break; + case RESERVE: what = "RESERVE"; break; + case RELEASE: what = "RELEASE"; break; + case COPY: what = "COPY"; break; + case ERASE: what = "ERASE"; break; + case MODE_SENSE: what = "MODE_SENSE"; break; + case START_STOP: what = "START_STOP"; break; + case RECEIVE_DIAGNOSTIC: what = "RECEIVE_DIAGNOSTIC"; break; + case SEND_DIAGNOSTIC: what = "SEND_DIAGNOSTIC"; break; + case ALLOW_MEDIUM_REMOVAL: what = "ALLOW_MEDIUM_REMOVAL"; break; + case SET_WINDOW: what = "SET_WINDOW"; break; + case READ_CAPACITY: what = "READ_CAPACITY"; break; + case READ_10: what = "READ_10"; break; + case WRITE_10: what = "WRITE_10"; break; + case SEEK_10: what = "SEEK_10"; break; + case WRITE_VERIFY: what = "WRITE_VERIFY"; break; + case VERIFY: what = "VERIFY"; break; + case SEARCH_HIGH: what = "SEARCH_HIGH"; break; + case SEARCH_EQUAL: what = "SEARCH_EQUAL"; break; + case SEARCH_LOW: what = "SEARCH_LOW"; break; + case SET_LIMITS: what = "SET_LIMITS"; break; + case READ_POSITION: what = "READ_POSITION"; break; + case SYNCHRONIZE_CACHE: what = "SYNCHRONIZE_CACHE"; break; + case LOCK_UNLOCK_CACHE: what = "LOCK_UNLOCK_CACHE"; break; + case READ_DEFECT_DATA: what = "READ_DEFECT_DATA"; break; + case MEDIUM_SCAN: what = "MEDIUM_SCAN"; break; + case COMPARE: what = "COMPARE"; break; + case COPY_VERIFY: what = "COPY_VERIFY"; break; + case WRITE_BUFFER: what = "WRITE_BUFFER"; break; + case READ_BUFFER: what = "READ_BUFFER"; break; + case UPDATE_BLOCK: what = "UPDATE_BLOCK"; break; + case READ_LONG: what = "READ_LONG"; break; + case WRITE_LONG: what = "WRITE_LONG"; break; + case CHANGE_DEFINITION: what = "CHANGE_DEFINITION"; break; + case WRITE_SAME: what = "WRITE_SAME"; break; + case READ_TOC: what = "READ_TOC"; break; + case LOG_SELECT: what = "LOG_SELECT"; break; + case LOG_SENSE: what = "LOG_SENSE"; break; + case MODE_SELECT_10: what = "MODE_SELECT_10"; break; + case MODE_SENSE_10: what = "MODE_SENSE_10"; break; + case MOVE_MEDIUM: what = "MOVE_MEDIUM"; break; + case READ_12: what = "READ_12"; break; + case WRITE_12: what = "WRITE_12"; break; + case WRITE_VERIFY_12: what = "WRITE_VERIFY_12"; break; + case SEARCH_HIGH_12: what = "SEARCH_HIGH_12"; break; + case SEARCH_EQUAL_12: what = "SEARCH_EQUAL_12"; break; + case SEARCH_LOW_12: what = "SEARCH_LOW_12"; break; + case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break; + case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break; + case WRITE_LONG_2: what = "WRITE_LONG_2"; break; + default: + USC_DEBUG("can't decode command\n"); + goto out; + break; + } + USC_DEBUG( "Command %s (%d bytes)\n", what, srb->cmd_len); + + out: + USC_DEBUG( " %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5], + srb->cmnd[6], srb->cmnd[7], srb->cmnd[8], srb->cmnd[9]); +} + +static inline int usc_is_aborting(struct usc_desc* desc) { + return (atomic_read(&desc->context.do_abort)); +} + +static inline void usc_request_abort(struct usc_desc* desc, struct urb *urb) { + USC_DEBUG_GOT_HERE(); + usc_debug_dump(desc); + atomic_set(&desc->context.do_abort,1); +} + +static inline void usc_urb_abort(struct usc_desc* desc, struct urb* urb) { + USC_DEBUG_GOT_HERE(); + usc_debug_dump(desc); + if ( urb->status == USB_ST_URB_PENDING ) { + usb_unlink_urb( urb ); + } +} + +static inline void usc_wait_abort(struct usc_desc* desc, struct urb *urb, int which_urb) +{ + usc_request_abort(desc, urb); + + if (which_urb) { + while( !atomic_read(&desc->status_lock.count) ) { +/* Is there a function to check if the semaphore is locked? */ + schedule_timeout( USC_ABORT_TIMEOUT ); + USC_DEBUG_GOT_HERE(); + usc_urb_abort(desc, urb); + } + } else { + while( !atomic_read(&desc->cmd_lock.count) ) { +/* Is there a function to check if the semaphore is locked? */ + schedule_timeout( USC_ABORT_TIMEOUT ); + USC_DEBUG_GOT_HERE(); + usc_urb_abort(desc, urb); + } + } + +} + + +static struct usc_desc * usc_list; /* list of active scanners */ +struct semaphore usc_list_semaphore; + +/* Internal list operations */ + +static +void usc_remove_nolock( struct usc_desc* to_remove ) +{ + USC_DEBUG( "removing 0x%x from list\n", + (int)to_remove ); + + USC_DEBUG("line %d: locking kernel!\n",__LINE__); + lock_kernel(); + USC_DEBUG("line %d: trying to abort cmd_urb.\n",__LINE__); + usc_wait_abort(to_remove, &to_remove->cmd_urb, 0); + USC_DEBUG("line %d: Trying to abort status urb.\n",__LINE__); +up(&to_remove->status_lock); +// usc_wait_abort(to_remove, &to_remove->status_urb, 1); +USC_DEBUG("line %d: unlinking status_urb which currently has status 0x%x\n",__LINE__,to_remove->status_urb.status); + usb_unlink_urb(&to_remove->status_urb); + USC_DEBUG("Finished aborting my urbs!\n"); + + USC_DEBUG_GOT_HERE(); + + if ( to_remove != usc_list ) { + USC_DEBUG_GOT_HERE(); + if (to_remove->prev && to_remove->next) + to_remove->prev->next = to_remove->next; + } else { + USC_DEBUG_GOT_HERE(); + usc_list = to_remove->next; + if (usc_list) { + USC_DEBUG_GOT_HERE(); + usc_list->prev = 0; + } + } + + if ( to_remove->next ) { + USC_DEBUG_GOT_HERE(); + to_remove->next->prev = to_remove->prev; + } + + USC_DEBUG_GOT_HERE(); + scsi_unregister_module(MODULE_SCSI_HA, &(to_remove->ctempl)); + USC_DEBUG_GOT_HERE(); + unlock_kernel(); + USC_DEBUG_GOT_HERE(); + + kfree( to_remove ); + USC_DEBUG_GOT_HERE(); +} + +static +void usc_add_nolock( struct usc_desc* to_add ) +{ + USC_DEBUG( "adding 0x%x to list\n", (int)to_add ); + + to_add->prev = 0; + to_add->next = usc_list; + if ( usc_list ) { + usc_list->prev = to_add; + } + + usc_list = to_add; +} + + +static void usc_get_status( struct usc_desc *desc, struct urb *status_transfer, int pipe, void *status, int want_init ); + + +/* SCSI driver interface */ + +/* scsi related functions - dummies for now mostly */ + +static int usc_scsi_release(struct Scsi_Host *psh) +{ + USC_DEBUG_GOT_HERE(); + + return 0; +} + +static int usc_scsi_abort (Scsi_Cmnd *srb) +/* interrupt context (!) */ /* FIXME this is about to become task context */ +{ + struct usc_desc* desc = (struct usc_desc*)(srb->host->hostdata[0]); + + USC_DEBUG_GOT_HERE(); + + usc_request_abort(desc, &desc->cmd_urb); + usc_urb_abort(desc, &desc->cmd_urb); + + return SCSI_ABORT_PENDING; +} + +static int usc_scsi_host_reset (Scsi_Cmnd *srb) +{ + struct usc_desc* desc = (struct usc_desc*)(srb->host->hostdata[0]); + + USC_DEBUG_GOT_HERE(); + usc_debug_dump(desc); + + usb_reset_device(desc->usb_dev); /*FIXME: untested on new reset code */ + return 0; /* RANT why here 0 and not SUCCESS */ +} + +/* the core of the scsi part */ + +/* faking a detection - which can't fail :-) */ + +static int usc_scsi_detect (struct SHT * sht) +{ + /* Whole function stolen from usb-storage */ + + struct usc_desc * desc = (struct usc_desc *)sht->proc_dir; + /* What a hideous hack! */ + + char local_name[48]; + + USC_DEBUG_GOT_HERE(); + + /* set up the name of our subdirectory under /proc/scsi/ */ + sprintf(local_name, "usb-scsi-%d", desc->host_number); + sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_KERNEL); + /* FIXME: where is this freed ? */ + + if (!sht->proc_name) { + USC_ERROR( "unable to allocate memory for proc interface!!\n" ); + return 0; + } + + strcpy(sht->proc_name, local_name); + + sht->proc_dir = NULL; + + /* In host->hostdata we store a pointer to desc */ + desc->host = scsi_register(sht, sizeof(desc)); + desc->host->hostdata[0] = (unsigned long)desc; +/* FIXME: what if sizeof(void*) != sizeof(unsigned long)? */ + + return 1; +} + + + +/* Main entrypoint: SCSI commands are dispatched to here */ + + + +static +int usc_scsi_queuecommand (Scsi_Cmnd *srb, usc_scsi_cmnd_callback callback ); + + + +inline static +void usc_int_submit_urb (struct urb* transfer, + int pipe, + void* data, + unsigned length, + usc_usb_urb_callback callback ) +/* Interrupt context! */ + +/* Holding transfer->context->lock! */ +{ + int res; + struct usc_transfer_context* context; + + USC_INT_INIT(); + + USC_DEBUG("Line %d: filling the bulk urb.\n",__LINE__); + FILL_BULK_URB(transfer, + context->instance->usb_dev, + pipe, + data, + length, + callback, + context + ); + +/* transfer->transfer_flags = USB_DISABLE_SPD;*/ + transfer->transfer_flags = USB_ASYNC_UNLINK; + transfer->status = 0; + transfer->timeout = 100; + + USC_DEBUG("about to submit the bulk urb.\n"); + res = usb_submit_urb( transfer ); + USC_DEBUG("submitted! res is %d\n",res); + if ( res ) { + USC_INT_ERROR( "could not submit URB! Error was %d\n",(int)res ); + context->srb->result = DID_ERROR << 16; + usc_transfer_cleanup(transfer); + } + return; +} + + +static void usc_transfer_cleanup( struct urb *transfer ) +/* Interrupt context! */ +{ + usc_scsi_cmnd_callback callback; + struct usc_transfer_context* context = (struct usc_transfer_context*)transfer->context; + + USC_DEBUG_GOT_HERE(); + if ( context->lock) + return; + context->lock = 1; + USC_DEBUG("not locked.\n"); + if ( context->final_callback ) { + callback = context->final_callback; + USC_DEBUG("running srb->callback.\n"); + context->final_callback = 0; + wmb(); + callback(context->srb); + } + USC_DEBUG("releasing lock.\n"); + up( &context->instance->cmd_lock ); + +} + +static void usc_status_done( struct urb *transfer ) +/* interrupt context */ +{ +// struct usc_transfer_context* context; + +// USC_INT_INIT(); + struct usc_transfer_context* context = (struct usc_transfer_context*)transfer->context; + +USC_DEBUG_GOT_HERE(); + if (context->status) { +USC_DEBUG_GOT_HERE(); +USC_DEBUG ("context->status is 0x%x\n",context->status); + context->srb->result = DID_ERROR << 16; + context->srb->result &= USC_SCSI_ERR_MASK; + context->srb->result |= (unsigned)context->status<<1; + usc_request_abort(context->instance, &context->instance->cmd_urb); + usc_urb_abort(context->instance, &context->instance->cmd_urb); +USC_DEBUG_GOT_HERE(); + usc_transfer_cleanup(&context->instance->cmd_urb); +// usc_get_status( context->instance, &context->instance->status_urb, context->instance->status_pipe, &context->status, 0); +return; + } else { +USC_DEBUG_GOT_HERE(); + USC_DEBUG("status == 0\n"); + context->srb->result &= USC_SCSI_ERR_MASK; + context->srb->result |= (unsigned)context->status<<1; +USC_DEBUG_GOT_HERE(); +USC_DEBUG("context->srb->result = 0x%x\n",context->srb->result); + usc_transfer_cleanup(&context->instance->cmd_urb); + +// usc_get_status( context->instance, &context->instance->status_urb, context->instance->status_pipe, &context->status, 0); +return; + } + +} + +static void usc_transfer_done( struct urb *transfer ) +{ + struct usc_transfer_context* context; + + USC_INT_INIT(); + + context->srb->result &= USC_SCSI_ERR_MASK; + context->srb->result |= (unsigned)context->status<<1; + + usc_transfer_cleanup(transfer); + + return; +} + + +static void usc_get_status( struct usc_desc *desc, struct urb *status_transfer, int pipe, void *status, int want_init ) +/* Interrupt context! */ +{ +// struct usc_transfer_context* context; + +// USC_INT_INIT(); +int res; + + + if (want_init) { +USC_DEBUG("line %d: filling the status urb.\n",__LINE__); + FILL_INT_URB(status_transfer, + desc->usb_dev, + pipe, + status, + 1, + usc_status_done, + &desc->context, + desc->interrupt_interval + ); + status_transfer->transfer_flags = USB_ASYNC_UNLINK; + } + USC_DEBUG("line %d: sending the status urb.\n",__LINE__); + res = usb_submit_urb(status_transfer); + if (res) + USC_ERROR ("ERROR! unable to transmit status urb. res == %d status_transfer->status == 0x%x\n",res, status_transfer->status); + + + return; +} + +static void usc_data_done( struct urb* transfer ) +/* Interrupt context! */ +{ + struct usc_transfer_context* context; + + USC_INT_INIT(); + +USC_DEBUG_GOT_HERE(); +if ( transfer->status ) { + context->srb->result = DID_ERROR<<16; +USC_DEBUG ("JHALL: line %d: status %d error %x hope status_done takes this.\n",__LINE__, (int)transfer->status, context->srb->result); + usc_transfer_cleanup(transfer); + } else if ( context->data_length != transfer->actual_length ) { + context->srb->resid = context->data_length - transfer->actual_length; +USC_DEBUG_GOT_HERE(); + usc_transfer_cleanup(transfer); + } +//usc_transfer_done(transfer); + + return; +} + + +static void usc_command_done( struct urb *transfer ) +/* Interrupt context! */ +{ + struct usc_transfer_context* context; + + USC_INT_INIT(); + + USC_DEBUG_GOT_HERE(); + if ( transfer->status ) { + USC_DEBUG_GOT_HERE(); + context->srb->result = DID_ERROR<<16; + usc_transfer_cleanup(transfer); + + return; + } + + USC_DEBUG_GOT_HERE(); + if ( context->data ) { + USC_DEBUG_GOT_HERE(); + usc_int_submit_urb(transfer, + context->data_pipe, + context->data, + context->data_length, + usc_data_done); +// } else usc_transfer_done(transfer); +} + + return; +} + + + + static const unsigned char usc_direction[256/8] = { + 0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, + 0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + +#define USC_DIRECTION_IS_IN(x) ((usc_direction[x>>3] >> (x & 7)) & 1) + +static void +usc_build_transfer_context( Scsi_Cmnd *srb, struct usc_desc* desc ) +{ + + int pipe; + + + USC_DEBUG_GOT_HERE(); + + desc->context.instance = desc; + desc->context.srb = srb; + atomic_set(&desc->context.do_abort,0); + + if ( !srb->bufflen ){ + desc->context.data = 0; + desc->context.data_length = 0; + return; + } else { + desc->context.data = srb->buffer; + desc->context.data_length = srb->bufflen; + } + + /* can't rely on srb->sc_data_direction */ + + /* Brutally ripped from usb-storage */ + + if ( USC_DIRECTION_IS_IN(srb->cmnd[0]) ) { + pipe = desc->image_pipe; + USC_DEBUG( "transfering from desc->ep_image == %d\n", + (int)desc->ep_image ); + } else { + USC_DEBUG("transfering to desc->ep_out == %d\n", + (int)desc->ep_out); + pipe = desc->out_pipe; + } + desc->context.data_pipe = pipe; +} + + +static +int usc_scsi_queuecommand( Scsi_Cmnd *srb, usc_scsi_cmnd_callback callback ) +{ + struct usc_desc* desc = (struct usc_desc*)(srb->host->hostdata[0]); + int err = 0; + int res; + + USC_DEBUG_GOT_HERE(); + usc_show_command(srb); + usc_debug_dump(desc); + + if ( srb->device->lun || srb->device->id || srb->device->channel ) { + + USC_DEBUG("Command to LUN=%d ID=%d CHANNEL=%d from SCSI layer\n",(int)srb->device->lun,(int)srb->device->id, (int)srb->device->channel ); + + USC_DEBUG("this device doesn't exist\n"); + + srb->result = DID_BAD_TARGET << 16; + + if(callback) + callback(srb); + + goto out; + } + +USC_DEBUG("Line %d: trying to engage the cmd_lock.\n",__LINE__); + down(&desc->cmd_lock); + desc->context.lock = 0; + + USC_DEBUG_GOT_HERE(); + usc_show_command(srb); + + + FILL_BULK_URB(&desc->cmd_urb, + desc->usb_dev, + desc->out_pipe, + srb->cmnd, + srb->cmd_len, + usc_command_done, + &desc->context + ); + + + usc_build_transfer_context( srb, desc ); + desc->context.final_callback = callback; + desc->cmd_urb.timeout = 100; + desc->cmd_urb.transfer_flags = USB_ASYNC_UNLINK; + +/* desc->cmd_urb.transfer_flags = USB_DISABLE_SPD;*/ + + res=usb_submit_urb(&desc->cmd_urb); + + if(res){ + USC_ERROR("error %d submitting URB\n",(int)res); + srb->result = DID_ERROR << 16; + USC_DEBUG_GOT_HERE(); +desc->context.lock = 1; + + if(callback) + callback(srb); + up(&desc->cmd_lock); /* no further cleanup is done */ + + goto out; + } + + USC_DEBUG_GOT_HERE(); + + out: + return err; +} +/* + * this defines our 'host' + */ + +/* NOTE: This is taken from usb-storage, should be right. */ + + +static Scsi_Host_Template usc_scsi_host_template = { + name: "hp5300", + detect: usc_scsi_detect, + release: usc_scsi_release, + command: 0, + queuecommand: usc_scsi_queuecommand, + + eh_abort_handler: usc_scsi_abort, + eh_device_reset_handler:0, + eh_bus_reset_handler: 0, + eh_host_reset_handler: usc_scsi_host_reset, + + can_queue: 1, + this_id: -1, + cmd_per_lun: 1, + present: 0, + unchecked_isa_dma: FALSE, + use_clustering: FALSE, + use_new_eh_code: TRUE, + emulated: TRUE +}; + + +/* USB layer driver interface implementation */ + +static void usc_usb_disconnect (struct usb_device *dev, void *ptr) +{ + struct usc_desc* to_remove = (struct usc_desc*)ptr; + + USC_DEBUG_GOT_HERE(); + + /* leave the list - lock it */ + down(&usc_list_semaphore); + + usc_remove_nolock(to_remove); + + up(&usc_list_semaphore); +} + +struct vendor_product +{ + u16 idVendor; + u16 idProduct; + char* name; + enum + { + usc_sup_unknown=0, + usc_sup_alpha, + usc_sup_full + } + support_status; +} ; + + +/* These are taken from the msmUSB.inf file on the Windows driver CD */ +const static struct vendor_product usc_supported_products[] = +{ + { + 0x3f0, 0x701,"HP 5300C",usc_sup_unknown + } +} +; + + +MODULE_DEVICE_TABLE (usb, hp5300_usb_id); + +const static struct vendor_product* usc_last_product = &usc_supported_products[ sizeof(usc_supported_products) / sizeof(struct vendor_product) ]; + /* Must never be derefed, points to one after last entry */ + + +static void * usc_usb_probe (struct usb_device *dev, unsigned int interface, const struct usb_device_id *id) +{ + int i; + int result; + int ep_out = -1; + int interrupt_interval = 0; + int ep_in_set[3]; /* this will break if we have more than three endpoints + which is why we check */ + int *ep_in_current = ep_in_set; + + struct usc_desc * new_desc; + struct vendor_product const* p; + + /* the altsettting 0 on the interface we're probing */ + struct usb_interface_descriptor *altsetting; + + USC_DEBUG_GOT_HERE(); + USC_DEBUG( "usb-device descriptor at %x\n", (int)dev ); + + USC_DEBUG( "product id = 0x%x, vendor id = 0x%x\n", + (int)dev->descriptor.idProduct, + (int)dev->descriptor.idVendor ); + + USC_DEBUG_GOT_HERE(); + + /* checking IDs */ + for( p = usc_supported_products; p != usc_last_product; p++ ) + if ( dev->descriptor.idVendor == p->idVendor && + dev->descriptor.idProduct == p->idProduct ) + goto is_supported; + else + USC_DEBUG( "doesn't appear to be model %s\n", p->name ); + + USC_DEBUG( "returning NULL: unsupported\n" ); + + return NULL; + + is_supported: + + USC_DEBUG_GOT_HERE(); + + USC_DEBUG( "found model %s\n", p->name ); + if ( p->support_status != usc_sup_full ) + USC_MESSAGE( "model %s is not known to be fully supported, reports welcome!\n", + p->name ); + + /* the altsettting 0 on the interface we're probing */ + altsetting = + &(dev->actconfig->interface[interface].altsetting[0]); + + + /* Check if the config is sane */ + + if ( altsetting->bNumEndpoints != USC_EP_TOTAL ) { + USC_WARNING( "expecting %d got %d endpoints! Bailing out.\n", + (int)USC_EP_TOTAL, (int)altsetting->bNumEndpoints ); + return NULL; + } + + for( i = 0; i < altsetting->bNumEndpoints; i++ ) { + if ((altsetting->endpoint[i].bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) + interrupt_interval = altsetting->endpoint[i].bInterval; + if (((altsetting->endpoint[i].bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) && + ((altsetting->endpoint[i].bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)) { + + USC_WARNING( "can only deal with 2 bulk and 1 interrupt endpoints; endpoint %d is not either.\n", + (int)altsetting->endpoint[i].bEndpointAddress ); + } else { + if (altsetting->endpoint[i].bEndpointAddress & + USB_DIR_IN) + *ep_in_current++ + = altsetting->endpoint[i].bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; + else { + if ( ep_out != -1 ) { + USC_WARNING( "can only deal with one output endpoints. Bailing out." ); + return NULL; + } + + ep_out = altsetting->endpoint[i].bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; + } + } + + } + + + if ( ep_out == -1 ) { + USC_WARNING( "couldn't find an output bulk endpoint. Bailing out.\n" ); + return NULL; + } + + +USC_DEBUG_GOT_HERE(); + /* I don't understand the following fully (it's from usb-storage) -- John */ + + /* set the interface -- STALL is an acceptable response here */ + result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0); + + USC_DEBUG("usb_set_interface returned %d.\n",result); + switch( result ) + { + case 0: /* no error */ + break; + + case -EPIPE: + usb_clear_halt(dev, usb_sndctrlpipe(dev, 0)); + USC_DEBUG( "clearing clearing stall on control interface\n" ); + break; + + default: + USC_DEBUG( "unknown error %d from usb_set_interface\n", + (int)result ); + return NULL; + } + + + /* allocating a new descriptor */ + new_desc = (struct usc_desc *)kmalloc(sizeof(struct usc_desc), GFP_KERNEL); + if (new_desc == NULL) + { + USC_ERROR("couldn't allocate scanner desc, bailing out!\n"); + return NULL; + } + + /* As done by usb_alloc_urb */ + memset( new_desc, 0, sizeof(*new_desc) ); + spin_lock_init(&new_desc->cmd_urb.lock); + spin_lock_init(&new_desc->status_urb.lock); + + + /* initialising that descriptor */ + new_desc->usb_dev = dev; + new_desc->interface = interface; + + init_MUTEX(&new_desc->cmd_lock); + init_MUTEX(&new_desc->status_lock); + + if(usc_list){ + new_desc->host_number = usc_list->host_number+1; + } else { + new_desc->host_number = 0; + } + + /* endpoints */ + + new_desc->ep_out = ep_out; + new_desc->out_pipe = usb_sndbulkpipe(dev, ep_out); + new_desc->ep_response = ep_in_set[0]; + new_desc->status_pipe = usb_rcvintpipe(dev, ep_in_set[0]); + new_desc->ep_image = ep_in_set[1]; + new_desc->image_pipe = usb_rcvbulkpipe(dev, ep_in_set[1]); + new_desc->interrupt_interval = interrupt_interval; + + + if ( new_desc->ep_out != USC_EP_OUT ) + USC_WARNING( "will this work? Command EP is not usually %d\n", + (int)new_desc->ep_out ); + + if ( new_desc->ep_response != USC_EP_RESPONSE ) + USC_WARNING( "will this work? Response EP is not usually %d\n", + (int)new_desc->ep_response ); + + if ( new_desc->ep_image != USC_EP_IMAGE ) + USC_WARNING( "will this work? Image data EP is not usually %d\n", + (int)new_desc->ep_image ); + +/* start the status handler */ +down(&new_desc->status_lock); +usc_get_status(new_desc, &new_desc->status_urb, new_desc->status_pipe, &new_desc->context.status, 1); + + /* Initialize the host template based on the default one */ + memcpy(&(new_desc->ctempl), &usc_scsi_host_template, sizeof(usc_scsi_host_template)); + /* HACK from usb-storage - this is needed for scsi detection */ + (struct usc_desc *)new_desc->ctempl.proc_dir = new_desc; /* FIXME */ + + USC_DEBUG("registering SCSI module\n"); + + new_desc->ctempl.module = THIS_MODULE; + result = scsi_register_module(MODULE_SCSI_HA, &(new_desc->ctempl)); + /* Will get hit back in microtek_detect by this func */ + if ( result ) + { + USC_ERROR( "error %d from scsi_register_module! Help!\n", + (int)result ); + usb_unlink_urb(&new_desc->status_urb); + + /* FIXME: need more cleanup? */ + kfree( new_desc ); + return NULL; + } + USC_DEBUG_GOT_HERE(); + + /* FIXME: the bomb is armed, must the host be registered under lock ? */ + /* join the list - lock it */ + down(&usc_list_semaphore); + + usc_add_nolock( new_desc ); + + up(&usc_list_semaphore); + + + USC_DEBUG("completed probe and exiting happily\n"); + + return (void *)new_desc; +} + + + +/* get us noticed by the rest of the kernel */ + +int __init usbscsibulkint_drv_init(void) +{ + int result; + + USC_DEBUG_GOT_HERE(); + init_MUTEX(&usc_list_semaphore); + + if ((result = usb_register(&usc_usb_driver)) < 0) { + USC_DEBUG("usb_register returned %d\n", result ); + return -1; + } else { + USC_DEBUG("driver registered.\n"); + } + + return 0; +} + +void __exit usbscsibulkint_drv_exit(void) +{ + struct usc_desc* next; + + USC_DEBUG_GOT_HERE(); + + usb_deregister(&usc_usb_driver); + + down(&usc_list_semaphore); + + while (usc_list) { + /* keep track of where the next one is */ + next = usc_list->next; + + usc_remove_nolock( usc_list ); + + /* advance the list pointer */ + usc_list = next; + } + + up(&usc_list_semaphore); +} + +module_init(usbscsibulkint_drv_init); +module_exit(usbscsibulkint_drv_exit); + +MODULE_AUTHOR("Jeremy Hall, <JHall@UU.NET>"); +MODULE_DESCRIPTION("SCSI over USB driver for scanners"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/hp5300.h linux.ac/drivers/usb/hp5300.h --- linux.vanilla/drivers/usb/hp5300.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/usb/hp5300.h Tue Apr 3 17:55:07 2001 @@ -0,0 +1,69 @@ + /* + * Driver for Microtek Scanmaker X6 USB scanner and possibly others. + * + * (C) Copyright 2000 John Fremlin <vii@penguinpowered.com> + * (C) Copyright 2000 Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de> + * + * See microtek.c for history + * + */ + +typedef void (*usc_scsi_cmnd_callback)(Scsi_Cmnd *); +typedef void (*usc_usb_urb_callback) (struct urb *); + + +struct usc_transfer_context +{ + struct usc_desc* instance; + usc_scsi_cmnd_callback final_callback; + Scsi_Cmnd *srb; + + void* data; + unsigned data_length; + int data_pipe; + + int lock; + + atomic_t do_abort; /* when != 0 URB completion routines will + return straightaway */ + + u8 status; /* status returned from ep_response after command completion */ +}; + + +struct usc_desc { + struct usc_desc *next; + struct usc_desc *prev; + + struct usb_device *usb_dev; + + int interface; + + /* Endpoint addresses */ + u8 ep_out; + u8 ep_response; + u8 ep_image; + u8 interrupt_interval; + int image_pipe; + int status_pipe; + int out_pipe; + + struct Scsi_Host * host; + Scsi_Host_Template ctempl; + int host_number; + + struct semaphore cmd_lock; + struct semaphore status_lock; + + struct urb cmd_urb; + struct urb status_urb; + struct usc_transfer_context context; +}; + + +#define USC_EP_OUT 0x1 +#define USC_EP_RESPONSE 0x2 +#define USC_EP_IMAGE 0x3 +#define USC_EP_TOTAL 0x3 + +#define USC_SCSI_ERR_MASK ~0x3fu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/hub.c linux.ac/drivers/usb/hub.c --- linux.vanilla/drivers/usb/hub.c Tue Apr 3 17:32:23 2001 +++ linux.ac/drivers/usb/hub.c Mon Apr 16 00:05:53 2001 @@ -4,6 +4,8 @@ * (C) Copyright 1999 Linus Torvalds * (C) Copyright 1999 Johannes Erdfelt * (C) Copyright 1999 Gregory P. Smith + * (C) Copyright 2001 Brad Hards (bhards@bigpond.net.au + * */ #include <linux/config.h> @@ -38,6 +40,19 @@ static int khubd_pid = 0; /* PID of khubd */ static DECLARE_MUTEX_LOCKED(khubd_exited); +#ifdef DEBUG +static inline char *portspeed (int portstatus) +{ + if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED)) + return "480 Mb/s"; + else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED)) + return "1.5 Mb/s"; + else + return "12 Mb/s"; +} +#endif + +/* USB 2.0 spec Section 11.24.4.5 */ static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size) { return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), @@ -45,24 +60,38 @@ USB_DT_HUB << 8, 0, data, size, HZ); } +/* + * USB 2.0 spec Section 11.24.2.1 + */ static int usb_clear_hub_feature(struct usb_device *dev, int feature) { return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, HZ); } +/* + * USB 2.0 spec Section 11.24.2.2 + * BUG: doesn't handle port indicator selector in high byte of wIndex + */ static int usb_clear_port_feature(struct usb_device *dev, int port, int feature) { return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ); } +/* + * USB 2.0 spec Section 11.24.2.13 + * BUG: doesn't handle port indicator selector in high byte of wIndex + */ static int usb_set_port_feature(struct usb_device *dev, int port, int feature) { return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ); } +/* + * USB 2.0 spec Section 11.24.2.6 + */ static int usb_get_hub_status(struct usb_device *dev, void *data) { return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), @@ -70,6 +99,9 @@ data, sizeof(struct usb_hub_status), HZ); } +/* + * USB 2.0 spec Section 11.24.2.7 + */ static int usb_get_port_status(struct usb_device *dev, int port, void *data) { return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), @@ -115,7 +147,7 @@ /* Enable power to the ports */ dbg("enabling power on all ports"); - for (i = 0; i < hub->nports; i++) + for (i = 0; i < hub->descriptor->bNbrPorts; i++) usb_set_port_feature(hub->dev, i + 1, USB_PORT_FEAT_POWER); /* Wait for power to be enabled */ @@ -130,14 +162,14 @@ unsigned int pipe; int i, maxp, ret; - hub->descriptor = kmalloc(HUB_DESCRIPTOR_MAX_SIZE, GFP_KERNEL); + hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL); if (!hub->descriptor) { - err("Unable to kmalloc %d bytes for hub descriptor", HUB_DESCRIPTOR_MAX_SIZE); + err("Unable to kmalloc %d bytes for hub descriptor", sizeof(*hub->descriptor)); return -1; } /* Request the entire hub descriptor. */ - ret = usb_get_hub_descriptor(dev, hub->descriptor, HUB_DESCRIPTOR_MAX_SIZE); + ret = usb_get_hub_descriptor(dev, hub->descriptor, sizeof(*hub->descriptor)); /* <hub->descriptor> is large enough for a hub with 127 ports; * the hub can/will return fewer bytes here. */ if (ret < 0) { @@ -146,10 +178,10 @@ return -1; } - le16_to_cpus(&hub->descriptor->wHubCharacteristics); + dev->maxchild = hub->descriptor->bNbrPorts; + info("%d port%s detected", hub->descriptor->bNbrPorts, (hub->descriptor->bNbrPorts == 1) ? "" : "s"); - hub->nports = dev->maxchild = hub->descriptor->bNbrPorts; - info("%d port%s detected", hub->nports, (hub->nports == 1) ? "" : "s"); + le16_to_cpus(&hub->descriptor->wHubCharacteristics); if (hub->descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND) dbg("part of a compound device"); @@ -182,11 +214,45 @@ break; } + switch (dev->descriptor.bDeviceProtocol) { + case 0: + break; + case 1: + dbg("Single TT"); + break; + case 2: + dbg("Multiple TT"); + break; + default: + dbg("Unrecognized hub protocol %d", + dev->descriptor.bDeviceProtocol); + break; + } + + switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_TTTT) { + case 0x00: + if (dev->descriptor.bDeviceProtocol != 0) + dbg("TT requires at most 8 FS bit times"); + break; + case 0x20: + dbg("TT requires at most 16 FS bit times"); + break; + case 0x40: + dbg("TT requires at most 24 FS bit times"); + break; + case 0x60: + dbg("TT requires at most 32 FS bit times"); + break; + } + + dbg("Port indicators are %s supported", + (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND) ? "" : "not"); + dbg("power on to power good time: %dms", hub->descriptor->bPwrOn2PwrGood * 2); dbg("hub controller current requirement: %dmA", hub->descriptor->bHubContrCurrent); for (i = 0; i < dev->maxchild; i++) - portstr[i] = hub->descriptor->bitmap[((i + 1) / 8)] & (1 << ((i + 1) % 8)) ? 'F' : 'R'; + portstr[i] = hub->descriptor->DeviceRemovable[((i + 1) / 8)] & (1 << ((i + 1) % 8)) ? 'F' : 'R'; portstr[dev->maxchild] = 0; dbg("port removable status: %s", portstr); @@ -337,6 +403,9 @@ spin_unlock_irqrestore(&hub_event_lock, flags); + down(&hub->khubd_sem); /* Wait for khubd to leave this hub alone. */ + up(&hub->khubd_sem); + down(&hub->khubd_sem); /* Wait for khubd to leave this hub alone. */ up(&hub->khubd_sem); @@ -392,7 +461,7 @@ int i; /* Disconnect any attached devices */ - for (i = 0; i < hub->nports; i++) { + for (i = 0; i < hub->descriptor->bNbrPorts; i++) { if (dev->children[i]) usb_disconnect(&dev->children[i]); } @@ -459,8 +528,7 @@ portstatus = le16_to_cpu(portsts.wPortStatus); portchange = le16_to_cpu(portsts.wPortChange); dbg("port %d, portstatus %x, change %x, %s", port + 1, - portstatus, portchange, - portstatus & (1 << USB_PORT_FEAT_LOWSPEED) ? "1.5 Mb/s" : "12 Mb/s"); + portstatus, portchange, portspeed (portstatus)); /* bomb out completely if something weird happened */ if ((portchange & USB_PORT_STAT_C_CONNECTION) || @@ -470,7 +538,12 @@ /* if we`ve finished resetting, then break out of the loop */ if (!(portstatus & USB_PORT_STAT_RESET) && (portstatus & USB_PORT_STAT_ENABLE)) { - dev->slow = (portstatus & USB_PORT_STAT_LOW_SPEED) ? 1 : 0; + if (portstatus & USB_PORT_STAT_HIGH_SPEED) + dev->speed = USB_SPEED_HIGH; + else if (portstatus & USB_PORT_STAT_LOW_SPEED) + dev->speed = USB_SPEED_LOW; + else + dev->speed = USB_SPEED_FULL; return 0; } @@ -533,8 +606,8 @@ portstatus = le16_to_cpu(portsts->wPortStatus); portchange = le16_to_cpu(portsts->wPortChange); - dbg("port %d, portstatus %x, change %x, %s", port + 1, portstatus, - portchange, portstatus & (1 << USB_PORT_FEAT_LOWSPEED) ? "1.5 Mb/s" : "12 Mb/s"); + dbg("port %d, portstatus %x, change %x, %s", + port + 1, portstatus, portchange, portspeed (portstatus)); /* Clear the connection change status */ usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION); @@ -551,8 +624,7 @@ return; } - /* Some low speed devices have problems with the quick delay, so */ - /* be a bit pessimistic with those devices. RHbug #23670 */ + /* zaitcev RHbug #23670 - 1.5Mb/s mice die when switching VCs */ if (portstatus & USB_PORT_STAT_LOW_SPEED) { wait_ms(400); delay = HUB_LONG_RESET_TIME; @@ -663,7 +735,7 @@ list_del(tmp); INIT_LIST_HEAD(tmp); - down(&hub->khubd_sem); /* never blocks, we were on list */ + down(&hub->khubd_sem); /* never blocks, we were on list */ spin_unlock_irqrestore(&hub_event_lock, flags); if (hub->error) { @@ -680,13 +752,14 @@ hub->error = 0; } - for (i = 0; i < hub->nports; i++) { + for (i = 0; i < hub->descriptor->bNbrPorts; i++) { struct usb_port_status portsts; unsigned short portstatus, portchange; ret = usb_get_port_status(dev, i + 1, &portsts); if (ret < 0) { err("get_port_status failed (err = %d)", ret); + up(&hub->khubd_sem); continue; } @@ -776,6 +849,7 @@ dbg("usb_hub_thread exiting"); + unlock_kernel(); up_and_exit(&khubd_exited, 0); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/hub.h linux.ac/drivers/usb/hub.h --- linux.vanilla/drivers/usb/hub.h Tue Apr 3 17:32:23 2001 +++ linux.ac/drivers/usb/hub.h Mon Apr 16 00:14:56 2001 @@ -12,12 +12,14 @@ /* * Hub Class feature numbers + * See USB 2.0 spec Table 11-17 */ #define C_HUB_LOCAL_POWER 0 #define C_HUB_OVER_CURRENT 1 /* * Port feature numbers + * See USB 2.0 spec Table 11-17 */ #define USB_PORT_FEAT_CONNECTION 0 #define USB_PORT_FEAT_ENABLE 1 @@ -26,37 +28,61 @@ #define USB_PORT_FEAT_RESET 4 #define USB_PORT_FEAT_POWER 8 #define USB_PORT_FEAT_LOWSPEED 9 +#define USB_PORT_FEAT_HIGHSPEED 10 #define USB_PORT_FEAT_C_CONNECTION 16 #define USB_PORT_FEAT_C_ENABLE 17 #define USB_PORT_FEAT_C_SUSPEND 18 #define USB_PORT_FEAT_C_OVER_CURRENT 19 #define USB_PORT_FEAT_C_RESET 20 +#define USB_PORT_FEAT_TEST 21 +#define USB_PORT_FEAT_INDICATOR 22 +/* + * Hub Status and Hub Change results + * See USB 2.0 spec Table 11-19 and Table 11-20 + */ struct usb_port_status { __u16 wPortStatus; __u16 wPortChange; } __attribute__ ((packed)); -/* wPortStatus bits */ +/* + * wPortStatus bit field + * See USB 2.0 spec Table 11-21 + */ #define USB_PORT_STAT_CONNECTION 0x0001 #define USB_PORT_STAT_ENABLE 0x0002 #define USB_PORT_STAT_SUSPEND 0x0004 #define USB_PORT_STAT_OVERCURRENT 0x0008 #define USB_PORT_STAT_RESET 0x0010 +/* bits 5 for 7 are reserved */ #define USB_PORT_STAT_POWER 0x0100 #define USB_PORT_STAT_LOW_SPEED 0x0200 - -/* wPortChange bits */ +#define USB_PORT_STAT_HIGH_SPEED 0x0400 +#define USB_PORT_STAT_TEST 0x0800 +#define USB_PORT_STAT_INDICATOR 0x1000 +/* bits 13 to 15 are reserved */ + +/* + * wPortChange bit field + * See USB 2.0 spec Table 11-22 + * Bits 0 to 4 shown, bits 5 to 15 are reserved + */ #define USB_PORT_STAT_C_CONNECTION 0x0001 #define USB_PORT_STAT_C_ENABLE 0x0002 #define USB_PORT_STAT_C_SUSPEND 0x0004 #define USB_PORT_STAT_C_OVERCURRENT 0x0008 #define USB_PORT_STAT_C_RESET 0x0010 -/* wHubCharacteristics (masks) */ -#define HUB_CHAR_LPSM 0x0003 -#define HUB_CHAR_COMPOUND 0x0004 -#define HUB_CHAR_OCPM 0x0018 +/* + * wHubCharacteristics (masks) + * See USB 2.0 spec Table 11-13, offset 3 + */ +#define HUB_CHAR_LPSM 0x0003 /* D1 .. D0 */ +#define HUB_CHAR_COMPOUND 0x0004 /* D2 */ +#define HUB_CHAR_OCPM 0x0018 /* D4 .. D3 */ +#define HUB_CHAR_TTTT 0x0060 /* D6 .. D5 */ +#define HUB_CHAR_PORTIND 0x0080 /* D7 */ struct usb_hub_status { __u16 wHubStatus; @@ -64,28 +90,31 @@ } __attribute__ ((packed)); /* - *Hub Status & Hub Change bit masks + * Hub Status & Hub Change bit masks + * See USB 2.0 spec Table 11-19 and Table 11-20 + * Bits 0 and 1 for wHubStatus and wHubChange + * Bits 2 to 15 are reserved for both */ #define HUB_STATUS_LOCAL_POWER 0x0001 #define HUB_STATUS_OVERCURRENT 0x0002 - #define HUB_CHANGE_LOCAL_POWER 0x0001 #define HUB_CHANGE_OVERCURRENT 0x0002 -#define HUB_DESCRIPTOR_MAX_SIZE 39 /* enough for 127 ports on a hub */ -/* Hub descriptor */ +/* + * Hub descriptor + * See USB 2.0 spec Table 11-13 + */ struct usb_hub_descriptor { - __u8 bLength; + __u8 bDescLength; __u8 bDescriptorType; __u8 bNbrPorts; __u16 wHubCharacteristics; __u8 bPwrOn2PwrGood; __u8 bHubContrCurrent; - - /* DeviceRemovable and PortPwrCtrlMask want to be variable-length - bitmaps that hold max 256 entries, but for now they're ignored */ - __u8 bitmap[0]; + /* add 1 bit for hub status change; round to bytes */ + __u8 DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8]; + __u8 PortPwrCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8]; } __attribute__ ((packed)); struct usb_device; @@ -104,12 +133,9 @@ struct list_head event_list; - /* Number of ports on the hub */ - int nports; - struct usb_hub_descriptor *descriptor; struct semaphore khubd_sem; }; -#endif +#endif /* __LINUX_HUB_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/ibmcam.c linux.ac/drivers/usb/ibmcam.c --- linux.vanilla/drivers/usb/ibmcam.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/usb/ibmcam.c Tue Apr 3 17:55:07 2001 @@ -27,49 +27,71 @@ #include <linux/kernel.h> #include <linux/sched.h> -#include <linux/list.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/smp_lock.h> -#include <linux/videodev.h> -#include <linux/vmalloc.h> #include <linux/wrapper.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/usb.h> -#include <asm/io.h> +#include "usbvideo.h" -#include "ibmcam.h" +#define IBMCAM_VENDOR_ID 0x0545 +#define IBMCAM_PRODUCT_ID 0x8080 +#define NETCAM_PRODUCT_ID 0x8002 /* IBM NetCamera, close to model 2 */ + +#define MAX_IBMCAM 4 /* How many devices we allow to connect */ +#define USES_IBMCAM_PUTPIXEL 0 /* 0=Fast/oops 1=Slow/secure */ + +/* Header signatures */ + +/* Model 1 header: 00 FF 00 xx */ +#define HDRSIG_MODEL1_128x96 0x06 /* U Y V Y ... */ +#define HDRSIG_MODEL1_176x144 0x0e /* U Y V Y ... */ +#define HDRSIG_MODEL1_352x288 0x00 /* V Y U Y ... */ + +#define IBMCAM_MODEL_1 1 /* XVP-501, 3 interfaces, rev. 0.02 */ +#define IBMCAM_MODEL_2 2 /* KSX-X9903, 2 interfaces, rev. 3.0a */ +#define IBMCAM_MODEL_3 3 /* KSX-X9902, 2 interfaces, rev. 3.01 */ +#define IBMCAM_MODEL_4 4 /* IBM NetCamera, 0545/8002/3.0a */ + +/* Video sizes supported */ +#define VIDEOSIZE_128x96 VIDEOSIZE(128, 96) +#define VIDEOSIZE_176x144 VIDEOSIZE(176,144) +#define VIDEOSIZE_352x288 VIDEOSIZE(352,288) +#define VIDEOSIZE_320x240 VIDEOSIZE(320,240) +#define VIDEOSIZE_352x240 VIDEOSIZE(352,240) +#define VIDEOSIZE_640x480 VIDEOSIZE(640,480) +#define VIDEOSIZE_160x120 VIDEOSIZE(160,120) -#define ENABLE_HEXDUMP 0 /* Enable if you need it */ -static int debug = 0; +/* Video sizes supported */ +enum { + SIZE_128x96 = 0, + SIZE_160x120, + SIZE_176x144, + SIZE_320x240, + SIZE_352x240, + SIZE_352x288, + SIZE_640x480, + /* Add/remove/rearrange items before this line */ + SIZE_LastItem +}; + +/* + * This structure lives in uvd_t->user field. + */ +typedef struct { + int initialized; /* Had we already sent init sequence? */ + int camera_model; /* What type of IBM camera we got? */ + int has_hdr; +} ibmcam_t; +#define IBMCAM_T(uvd) ((ibmcam_t *)((uvd)->user_data)) -/* Completion states of the data parser */ -typedef enum { - scan_Continue, /* Just parse next item */ - scan_NextFrame, /* Frame done, send it to V4L */ - scan_Out, /* Not enough data for frame */ - scan_EndParse /* End parsing */ -} scan_state_t; - -/* Bit flags (options) */ -#define FLAGS_RETRY_VIDIOCSYNC (1 << 0) -#define FLAGS_MONOCHROME (1 << 1) -#define FLAGS_DISPLAY_HINTS (1 << 2) -#define FLAGS_OVERLAY_STATS (1 << 3) -#define FLAGS_FORCE_TESTPATTERN (1 << 4) -#define FLAGS_SEPARATE_FRAMES (1 << 5) -#define FLAGS_CLEAN_FRAMES (1 << 6) +usbvideo_t *cams = NULL; + +static int debug = 0; static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */ -/* This is the size of V4L frame that we provide */ -static const int imgwidth = V4L_FRAME_WIDTH_USED; -static const int imgheight = V4L_FRAME_HEIGHT; -static const int min_imgwidth = 8; -static const int min_imgheight = 4; +static const int min_canvasWidth = 8; +static const int min_canvasHeight = 4; static int lighting = 1; /* Medium */ @@ -79,27 +101,9 @@ #define FRAMERATE_MIN 0 #define FRAMERATE_MAX 6 -static int framerate = 2; /* Lower, reliable frame rate (8-12 fps) */ +static int framerate = -1; -enum { - VIDEOSIZE_128x96 = 0, - VIDEOSIZE_176x144, - VIDEOSIZE_352x288, - VIDEOSIZE_320x240, - VIDEOSIZE_352x240, -}; - -static int videosize = VIDEOSIZE_352x288; - -/* - * The value of 'scratchbufsize' affects quality of the picture - * in many ways. Shorter buffers may cause loss of data when client - * is too slow. Larger buffers are memory-consuming and take longer - * to work with. This setting can be adjusted, but the default value - * should be OK for most desktop users. - */ -#define DEFAULT_SCRATCH_BUF_SIZE (0x10000) /* 64 KB */ -static const int scratchbufsize = DEFAULT_SCRATCH_BUF_SIZE; +static int size = SIZE_352x288; /* * Here we define several initialization variables. They may @@ -122,36 +126,37 @@ static int hue_correction = 128; /* Settings for camera model 2 */ -static int init_model2_rg = -1; static int init_model2_rg2 = -1; static int init_model2_sat = -1; static int init_model2_yb = -1; +/* 01.01.08 - Added for RCA video in support -LO */ +/* Settings for camera model 3 */ +static int init_model3_input = 0; + MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); MODULE_PARM(flags, "i"); -MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, 1=B/W, 2=show hints, 3=show stats, 4=test pattern, 5=seperate frames, 6=clean frames"); +MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, 1=B/W, 2=show hints, 3=show stats, 4=test pattern, 5=separate frames, 6=clean frames"); MODULE_PARM(framerate, "i"); MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)"); MODULE_PARM(lighting, "i"); MODULE_PARM_DESC(lighting, "Photosensitivity: 0=bright, 1=medium (default), 2=low light"); MODULE_PARM(sharpness, "i"); MODULE_PARM_DESC(sharpness, "Model1 noise reduction: 0=smooth, 6=sharp (default=4)"); -MODULE_PARM(videosize, "i"); -MODULE_PARM_DESC(videosize, "Image size: 0=128x96, 1=176x144, 2=352x288, 3=320x240, 4=352x240 (default=1)"); +MODULE_PARM(size, "i"); +MODULE_PARM_DESC(size, "Image size: 0=128x96 1=160x120 2=176x144 3=320x240 4=352x240 5=352x288 6=640x480 (default=5)"); MODULE_PARM(init_brightness, "i"); MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)"); MODULE_PARM(init_contrast, "i"); MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)"); MODULE_PARM(init_color, "i"); -MODULE_PARM_DESC(init_color, "Dolor preconfiguration: 0-255 (default=128)"); +MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)"); MODULE_PARM(init_hue, "i"); MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)"); MODULE_PARM(hue_correction, "i"); MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)"); -MODULE_PARM(init_model2_rg, "i"); -MODULE_PARM_DESC(init_model2_rg, "Model2 preconfiguration: 0-255 (default=112)"); MODULE_PARM(init_model2_rg2, "i"); MODULE_PARM_DESC(init_model2_rg2, "Model2 preconfiguration: 0-255 (default=47)"); MODULE_PARM(init_model2_sat, "i"); @@ -159,7 +164,11 @@ MODULE_PARM(init_model2_yb, "i"); MODULE_PARM_DESC(init_model2_yb, "Model2 preconfiguration: 0-255 (default=160)"); -MODULE_AUTHOR ("module author"); +/* 01.01.08 - Added for RCA video in support -LO */ +MODULE_PARM(init_model3_input, "i"); +MODULE_PARM_DESC(init_model3_input, "Model3 input: 0=CCD 1=RCA"); + +MODULE_AUTHOR ("Dmitri"); MODULE_DESCRIPTION ("IBM/Xirlink C-it USB Camera Driver for Linux (c) 2000"); /* Still mysterious i2c commands */ @@ -176,594 +185,326 @@ static const unsigned short mod2_color_balance_rg2 = 0x001e; /* 0 (red) .. $7F (green) */ static const unsigned short mod2_saturation = 0x0020; /* 0 (b/w) - $7F (full color) */ static const unsigned short mod2_color_balance_yb = 0x0022; /* 0..$7F, $50 is about right */ -static const unsigned short mod2_color_balance_rg = 0x0024; /* 0..$7F, $70 is about right */ +static const unsigned short mod2_hue = 0x0024; /* 0..$7F, $70 is about right */ static const unsigned short mod2_sensitivity = 0x0028; /* 0 (min) .. $1F (max) */ -#define MAX_IBMCAM 4 - -struct usb_ibmcam cams[MAX_IBMCAM]; - -/*******************************/ -/* Memory management functions */ -/*******************************/ - -#define MDEBUG(x) do { } while(0) /* Debug memory management */ - -static struct usb_driver ibmcam_driver; -static void usb_ibmcam_release(struct usb_ibmcam *ibmcam); - -/* 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 = (unsigned long) page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE - 1)); - } - } - } - MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); - return ret; -} - -static inline unsigned long uvirt_to_bus(unsigned long adr) -{ - unsigned long kva, ret; - - kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); - ret = virt_to_bus((void *)kva); - MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); - return ret; -} - -static inline unsigned long kvirt_to_bus(unsigned long adr) -{ - unsigned long va, kva, ret; - - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); - ret = virt_to_bus((void *)kva); - MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); - 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); - MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); - return ret; -} - -static void *rvmalloc(unsigned long size) -{ - void *mem; - unsigned long adr, page; - - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - - mem = vmalloc_32(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); - mem_map_reserve(virt_to_page(__va(page))); - adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - - return mem; -} - -static void rvfree(void *mem, unsigned long size) -{ - unsigned long adr, page; - - if (!mem) - return; - - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - - adr=(unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); - adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - vfree(mem); -} - -#if ENABLE_HEXDUMP -static void ibmcam_hexdump(const unsigned char *data, int len) -{ - char tmp[80]; - int i, k; - - for (i=k=0; len > 0; i++, len--) { - if (i > 0 && (i%16 == 0)) { - printk("%s\n", tmp); - k=0; - } - k += sprintf(&tmp[k], "%02x ", data[i]); - } - if (k > 0) - printk("%s\n", tmp); -} -#endif - -/* - * usb_ibmcam_overlaychar() - * - * History: - * 1/2/00 Created. - */ -void usb_ibmcam_overlaychar( - struct usb_ibmcam *ibmcam, - struct ibmcam_frame *frame, - int x, int y, int ch) -{ - static const unsigned short digits[16] = { - 0xF6DE, /* 0 */ - 0x2492, /* 1 */ - 0xE7CE, /* 2 */ - 0xE79E, /* 3 */ - 0xB792, /* 4 */ - 0xF39E, /* 5 */ - 0xF3DE, /* 6 */ - 0xF492, /* 7 */ - 0xF7DE, /* 8 */ - 0xF79E, /* 9 */ - 0x77DA, /* a */ - 0xD75C, /* b */ - 0xF24E, /* c */ - 0xD6DC, /* d */ - 0xF34E, /* e */ - 0xF348 /* f */ - }; - unsigned short digit; - int ix, iy; - - if ((ibmcam == NULL) || (frame == NULL)) - return; - - if (ch >= '0' && ch <= '9') - ch -= '0'; - else if (ch >= 'A' && ch <= 'F') - ch = 10 + (ch - 'A'); - else if (ch >= 'a' && ch <= 'f') - ch = 10 + (ch - 'a'); - else - return; - digit = digits[ch]; - - for (iy=0; iy < 5; iy++) { - for (ix=0; ix < 3; ix++) { - if (digit & 0x8000) { - IBMCAM_PUTPIXEL(frame, x+ix, y+iy, 0xFF, 0xFF, 0xFF); - } - digit = digit << 1; - } - } -} +struct struct_initData { + unsigned char req; + unsigned short value; + unsigned short index; +}; /* - * usb_ibmcam_overlaystring() + * ibmcam_size_to_videosize() * - * History: - * 1/2/00 Created. + * This procedure converts module option 'size' into the actual + * videosize_t that defines the image size in pixels. We need + * simplified 'size' because user wants a simple enumerated list + * of choices, not an infinite set of possibilities. */ -void usb_ibmcam_overlaystring( - struct usb_ibmcam *ibmcam, - struct ibmcam_frame *frame, - int x, int y, const char *str) +static videosize_t ibmcam_size_to_videosize(int size) { - while (*str) { - usb_ibmcam_overlaychar(ibmcam, frame, x, y, *str); - str++; - x += 4; /* 3 pixels character + 1 space */ + videosize_t vs = VIDEOSIZE_352x288; + RESTRICT_TO_RANGE(size, 0, (SIZE_LastItem-1)); + switch (size) { + case SIZE_128x96: + vs = VIDEOSIZE_128x96; + break; + case SIZE_160x120: + vs = VIDEOSIZE_160x120; + break; + case SIZE_176x144: + vs = VIDEOSIZE_176x144; + break; + case SIZE_320x240: + vs = VIDEOSIZE_320x240; + break; + case SIZE_352x240: + vs = VIDEOSIZE_352x240; + break; + case SIZE_352x288: + vs = VIDEOSIZE_352x288; + break; + case SIZE_640x480: + vs = VIDEOSIZE_640x480; + break; + default: + err("size=%d. is not valid", size); + break; } + return vs; } /* - * usb_ibmcam_overlaystats() + * ibmcam_find_header() * - * Overlays important debugging information. - * - * History: - * 1/2/00 Created. - */ -void usb_ibmcam_overlaystats(struct usb_ibmcam *ibmcam, struct ibmcam_frame *frame) -{ - const int y_diff = 8; - char tmp[16]; - int x = 10; - int y = 10; - - sprintf(tmp, "%8x", ibmcam->frame_num); - usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", ibmcam->urb_count); - usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", ibmcam->urb_length); - usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", ibmcam->data_count); - usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", ibmcam->header_count); - usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", ibmcam->scratch_ovf_count); - usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", ibmcam->iso_skip_count); - usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", ibmcam->iso_err_count); - usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8x", ibmcam->vpic.colour); - usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8x", ibmcam->vpic.hue); - usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8x", ibmcam->vpic.brightness >> 8); - usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8x", ibmcam->vpic.contrast >> 12); - usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8d", ibmcam->vpic.whiteness >> 8); - usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp); - y += y_diff; -} - -/* - * usb_ibmcam_testpattern() - * - * Procedure forms a test pattern (yellow grid on blue background). - * - * Parameters: - * fullframe: if TRUE then entire frame is filled, otherwise the procedure - * continues from the current scanline. - * pmode 0: fill the frame with solid blue color (like on VCR or TV) - * 1: Draw a colored grid + * Locate one of supported header markers in the queue. + * Once found, remove all preceding bytes AND the marker (4 bytes) + * from the data pump queue. Whatever follows must be video lines. * * History: - * 1/2/00 Created. + * 1/21/00 Created. */ -void usb_ibmcam_testpattern(struct usb_ibmcam *ibmcam, int fullframe, int pmode) +static ParseState_t ibmcam_find_header(uvd_t *uvd) /* FIXME: Add frame here */ { - static const char proc[] = "usb_ibmcam_testpattern"; - struct ibmcam_frame *frame; - unsigned char *f; - int num_cell = 0; - int scan_length = 0; - static int num_pass = 0; - - if (ibmcam == NULL) { - printk(KERN_ERR "%s: ibmcam == NULL\n", proc); - return; - } - if ((ibmcam->curframe < 0) || (ibmcam->curframe >= IBMCAM_NUMFRAMES)) { - printk(KERN_ERR "%s: ibmcam->curframe=%d.\n", proc, ibmcam->curframe); - return; - } + usbvideo_frame_t *frame; + ibmcam_t *icam; - /* Grab the current frame */ - frame = &ibmcam->frame[ibmcam->curframe]; - - /* Optionally start at the beginning */ - if (fullframe) { - frame->curline = 0; - frame->scanlength = 0; + if ((uvd->curframe) < 0 || (uvd->curframe >= USBVIDEO_NUMFRAMES)) { + err("ibmcam_find_header: Illegal frame %d.", uvd->curframe); + return scan_EndParse; } - - /* Form every scan line */ - for (; frame->curline < imgheight; frame->curline++) { - int i; - - f = frame->data + (imgwidth * 3 * frame->curline); - for (i=0; i < imgwidth; i++) { - unsigned char cb=0x80; - unsigned char cg = 0; - unsigned char cr = 0; - - if (pmode == 1) { - if (frame->curline % 32 == 0) - cb = 0, cg = cr = 0xFF; - else if (i % 32 == 0) { - if (frame->curline % 32 == 1) - num_cell++; - cb = 0, cg = cr = 0xFF; - } else { - cb = ((num_cell*7) + num_pass) & 0xFF; - cg = ((num_cell*5) + num_pass*2) & 0xFF; - cr = ((num_cell*3) + num_pass*3) & 0xFF; + icam = IBMCAM_T(uvd); + assert(icam != NULL); + frame = &uvd->frame[uvd->curframe]; + icam->has_hdr = 0; + switch (icam->camera_model) { + case IBMCAM_MODEL_1: + { + const int marker_len = 4; + while (RingQueue_GetLength(&uvd->dp) >= marker_len) { + if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && + (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) && + (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00)) + { +#if 0 /* This code helps to detect new frame markers */ + info("Header sig: 00 FF 00 %02X", RING_QUEUE_PEEK(&uvd->dp, 3)); +#endif + frame->header = RING_QUEUE_PEEK(&uvd->dp, 3); + if ((frame->header == HDRSIG_MODEL1_128x96) || + (frame->header == HDRSIG_MODEL1_176x144) || + (frame->header == HDRSIG_MODEL1_352x288)) + { +#if 0 + info("Header found."); +#endif + RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len); + icam->has_hdr = 1; + break; } - } else { - /* Just the blue screen */ } - - *f++ = cb; - *f++ = cg; - *f++ = cr; - scan_length += 3; + /* If we are still here then this doesn't look like a header */ + RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); } + break; } - - frame->grabstate = FRAME_DONE; - frame->scanlength += scan_length; - ++num_pass; - - /* We do this unconditionally, regardless of FLAGS_OVERLAY_STATS */ - usb_ibmcam_overlaystats(ibmcam, frame); -} - -static unsigned char *ibmcam_model1_find_header(unsigned char hdr_sig, unsigned char *data, int len) -{ - while (len >= 4) + case IBMCAM_MODEL_2: +case IBMCAM_MODEL_4: { - if ((data[0] == 0x00) && (data[1] == 0xFF) && (data[2] == 0x00)) - { + int marker_len = 0; + switch (uvd->videosize) { + case VIDEOSIZE_176x144: + marker_len = 10; + break; + default: + marker_len = 2; + break; + } + while (RingQueue_GetLength(&uvd->dp) >= marker_len) { + if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && + (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF)) + { #if 0 - /* This code helps to detect new frame markers */ - printk(KERN_DEBUG "Header sig: 00 FF 00 %02X\n", data[3]); + info("Header found."); #endif - if (data[3] == hdr_sig) { - if (debug > 2) - printk(KERN_DEBUG "Header found.\n"); - return data+4; + RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len); + icam->has_hdr = 1; + frame->header = HDRSIG_MODEL1_176x144; + break; } + /* If we are still here then this doesn't look like a header */ + RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); } - ++data; - --len; - } - return NULL; -} - -static unsigned char *ibmcam_model2_find_header(unsigned char hdr_sig, unsigned char *data, int len) -{ - int marker_len = 0; - - switch (videosize) { - case VIDEOSIZE_176x144: - marker_len = 10; - break; - default: - marker_len = 2; break; } - while (len >= marker_len) - { - if ((data[0] == 0x00) && (data[1] == 0xFF)) - { + case IBMCAM_MODEL_3: + { /* + * Headers: (one precedes every frame). nc=no compression, + * bq=best quality bf=best frame rate. + * + * 176x144: 00 FF 02 { 0A=nc CA=bq EA=bf } + * 320x240: 00 FF 02 { 08=nc 28=bq 68=bf } + * 640x480: 00 FF 03 { 08=nc 28=bq 68=bf } + * + * Bytes '00 FF' seem to indicate header. Other two bytes + * encode the frame type. This is a set of bit fields that + * encode image size, compression type etc. These fields + * do NOT contain frame number because all frames carry + * the same header. + */ + const int marker_len = 4; + while (RingQueue_GetLength(&uvd->dp) >= marker_len) { + if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && + (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) && + (RING_QUEUE_PEEK(&uvd->dp, 2) != 0xFF)) + { + /* + * Combine 2 bytes of frame type into one + * easy to use value + */ + unsigned long byte3, byte4; + + byte3 = RING_QUEUE_PEEK(&uvd->dp, 2); + byte4 = RING_QUEUE_PEEK(&uvd->dp, 3); + frame->header = (byte3 << 8) | byte4; #if 0 - /* This code helps to detect new frame markers */ - static int pass = 0; - if (pass++ == 0) - ibmcam_hexdump(data, (len > 16) ? 16 : len); + info("Header found."); #endif - if (debug > 2) - printk(KERN_DEBUG "Header found.\n"); - return data+marker_len; + RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len); + icam->has_hdr = 1; + break; + } + /* If we are still here then this doesn't look like a header */ + RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); } - ++data; - --len; + break; } - return NULL; -} - -/* How much data is left in the scratch buf? */ -#define scratch_left(x) (ibmcam->scratchlen - (int)((char *)x - (char *)ibmcam->scratch)) - -/* Grab the remaining */ -static void usb_ibmcam_align_scratch(struct usb_ibmcam *ibmcam, unsigned char *data) -{ - unsigned long left; - - left = scratch_left(data); - memmove(ibmcam->scratch, data, left); - ibmcam->scratchlen = left; -} - -/* - * usb_ibmcam_find_header() - * - * Locate one of supported header markers in the scratch buffer. - * Once found, remove all preceding bytes AND the marker (4 bytes) - * from the scratch buffer. Whatever follows must be video lines. - * - * History: - * 1/21/00 Created. - */ -static scan_state_t usb_ibmcam_find_header(struct usb_ibmcam *ibmcam) -{ - struct ibmcam_frame *frame; - unsigned char *data, *tmp; - - data = ibmcam->scratch; - frame = &ibmcam->frame[ibmcam->curframe]; - - if (ibmcam->camera_model == IBMCAM_MODEL_1) - tmp = ibmcam_model1_find_header(frame->hdr_sig, data, scratch_left(data)); - else if (ibmcam->camera_model == IBMCAM_MODEL_2) - tmp = ibmcam_model2_find_header(frame->hdr_sig, data, scratch_left(data)); - else - tmp = NULL; - - if (tmp == NULL) { - /* No header - entire scratch buffer is useless! */ - if (debug > 2) - printk(KERN_DEBUG "Skipping frame, no header\n"); - ibmcam->scratchlen = 0; + default: + break; + } + if (!icam->has_hdr) { + if (uvd->debug > 2) + info("Skipping frame, no header"); return scan_EndParse; } - /* Header found */ - data = tmp; - ibmcam->has_hdr = 1; - ibmcam->header_count++; - frame->scanstate = STATE_LINES; + /* Header found */ + icam->has_hdr = 1; + uvd->stats.header_count++; + frame->scanstate = ScanState_Lines; frame->curline = 0; if (flags & FLAGS_FORCE_TESTPATTERN) { - usb_ibmcam_testpattern(ibmcam, 1, 1); + usbvideo_TestPattern(uvd, 1, 1); return scan_NextFrame; } - usb_ibmcam_align_scratch(ibmcam, data); return scan_Continue; } /* - * usb_ibmcam_parse_lines() + * ibmcam_parse_lines() * - * Parse one line (TODO: more than one!) from the scratch buffer, put - * decoded RGB value into the current frame buffer and add the written - * number of bytes (RGB) to the *pcopylen. + * Parse one line (interlaced) from the buffer, put + * decoded RGB value into the current frame buffer + * and add the written number of bytes (RGB) to + * the *pcopylen. * * History: - * 1/21/00 Created. + * 21-Jan-2000 Created. + * 12-Oct-2000 Reworked to reflect interlaced nature of the data. */ -static scan_state_t usb_ibmcam_parse_lines(struct usb_ibmcam *ibmcam, long *pcopylen) +static ParseState_t ibmcam_parse_lines( + uvd_t *uvd, + usbvideo_frame_t *frame, + long *pcopylen) { - struct ibmcam_frame *frame; - unsigned char *data, *f, *chromaLine; - unsigned int len; - const int v4l_linesize = imgwidth * V4L_BYTES_PER_PIXEL; /* V4L line offset */ - const int hue_corr = (ibmcam->vpic.hue - 0x8000) >> 10; /* -32..+31 */ + unsigned char *f; + ibmcam_t *icam; + unsigned int len, scanLength, scanHeight, order_uv, order_yc; + int v4l_linesize; /* V4L line offset */ + const int hue_corr = (uvd->vpic.hue - 0x8000) >> 10; /* -32..+31 */ const int hue2_corr = (hue_correction - 128) / 4; /* -32..+31 */ const int ccm = 128; /* Color correction median - see below */ - int y, u, v, i, frame_done=0, mono_plane, color_corr; - - color_corr = (ibmcam->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/ + int y, u, v, i, frame_done=0, color_corr; + static unsigned char lineBuffer[640*3]; + unsigned const char *chromaLine, *lumaLine; + + assert(uvd != NULL); + assert(frame != NULL); + icam = IBMCAM_T(uvd); + assert(icam != NULL); + color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/ RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1); - data = ibmcam->scratch; - frame = &ibmcam->frame[ibmcam->curframe]; - len = frame->frmwidth * 3; /* 1 line of mono + 1 line of color */ - /*printk(KERN_DEBUG "len=%d. left=%d.\n",len,scratch_left(data));*/ + v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; + + if (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_4) { + /* Model 4 frame markers do not carry image size identification */ + switch (uvd->videosize) { + case VIDEOSIZE_128x96: + case VIDEOSIZE_160x120: + case VIDEOSIZE_176x144: + scanLength = VIDEOSIZE_X(uvd->videosize); + scanHeight = VIDEOSIZE_Y(uvd->videosize); + break; + default: + err("ibmcam_parse_lines: Wrong mode."); + return scan_Out; + } + order_yc = 1; /* order_yc: true=Yc false=cY ('c'=either U or V) */ + order_uv = 1; /* Always true in this algorithm */ + } else { + switch (frame->header) { + case HDRSIG_MODEL1_128x96: + scanLength = 128; + scanHeight = 96; + order_uv = 1; /* U Y V Y ... */ + break; + case HDRSIG_MODEL1_176x144: + scanLength = 176; + scanHeight = 144; + order_uv = 1; /* U Y V Y ... */ + break; + case HDRSIG_MODEL1_352x288: + scanLength = 352; + scanHeight = 288; + order_uv = 0; /* Y V Y V ... */ + break; + default: + err("Unknown header signature 00 FF 00 %02lX", frame->header); + return scan_NextFrame; + } + /* order_yc: true=Yc false=cY ('c'=either U or V) */ + order_yc = (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_2); + } - mono_plane = ((frame->curline & 1) == 0); + len = scanLength * 3; + assert(len <= sizeof(lineBuffer)); /* - * Lines are organized this way (or are they?) + * Lines are organized this way: * * I420: * ~~~~ + * <scanLength-> * ___________________________________ * |-----Y-----|---UVUVUV...UVUV-----| \ * |-----------+---------------------| \ - * |<-- 176 -->|<------ 176*2 ------>| Total 72. pairs of lines - * |... ... ...| / - * |___________|_____________________| / - * - odd line- ------- even line --- - * - * another format: - * ~~~~~~~~~~~~~~ - * ___________________________________ - * |-----Y-----|---UVUVUV...UVUV-----| \ - * |-----------+---------------------| \ - * |<-- 352 -->|<------ 352*2 ------>| Total 144. pairs of lines - * |... ... ...| / + * |<-- 176 -->|<------ 176*2 ------>| Total 72. lines (interlaced) + * |... ... | ... | / + * |<-- 352 -->|<------ 352*2 ------>| Total 144. lines (interlaced) * |___________|_____________________| / - * - odd line- ------- even line --- + * \ \ + * lumaLine chromaLine */ /* Make sure there's enough data for the entire line */ - if (scratch_left(data) < (len+1024)) { - /*printk(KERN_DEBUG "out of data, need %u.\n", len);*/ + if (RingQueue_GetLength(&uvd->dp) < len) return scan_Out; - } -#if 0 - { /* This code prints beginning of the source frame */ - static int pass = 0; - if ((pass++ % 3000) == 0) - ibmcam_hexdump(data, 16); - } -#endif + /* Suck one line out of the ring queue */ + RingQueue_Dequeue(&uvd->dp, lineBuffer, len); -#if 0 - if (frame->curline == 10 || frame->curline == 11) { - /* This code prints beginning of 10th (mono), 11th (chroma) line */ - static int pass = 0; - if ((pass % 100) == 0) - ibmcam_hexdump(data, 16); - if (frame->curline == 11) - pass++; - } -#endif /* * Make sure that our writing into output buffer * will not exceed the buffer. Mind that we may write * not into current output scanline but in several after * it as well (if we enlarge image vertically.) */ - if ((frame->curline + 1) >= V4L_FRAME_HEIGHT) + if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request)) return scan_NextFrame; /* - * Now we are sure that entire line (representing all 'frame->frmwidth' - * pixels from the camera) is available in the scratch buffer. We - * start copying the line left-aligned to the V4L buffer (which - * might be larger - not smaller, hopefully). If the camera - * line is shorter then we should pad the V4L buffer with something - * (black in this case) to complete the line. + * Now we are sure that entire line (representing all 'scanLength' + * pixels from the camera) is available in the buffer. We + * start copying the line left-aligned to the V4L buffer. + * If the camera line is shorter then we should pad the V4L + * buffer with something (black) to complete the line. */ + assert(frame->data != NULL); f = frame->data + (v4l_linesize * frame->curline); /* - * chromaLine points to 1st pixel of the line with chrominance. - * If current line is monochrome then chromaLine points to next - * line after monochrome one. If current line has chrominance - * then chromaLine points to this very line. Such method allows - * to access chrominance data uniformly. - * * To obtain chrominance data from the 'chromaLine' use this: * v = chromaLine[0]; // 0-1:[0], 2-3:[4], 4-5:[8]... * u = chromaLine[2]; // 0-1:[2], 2-3:[6], 4-5:[10]... @@ -772,40 +513,16 @@ * v_index = (i >> 1) << 2; * u_index = (i >> 1) << 2 + 2; * - * where 'i' is the column number [0..frame->frmwidth-1] + * where 'i' is the column number [0..VIDEOSIZE_X(frame->request)-1] */ - chromaLine = data; - if (mono_plane) - chromaLine += frame->frmwidth; - - for (i = 0; i < frame->frmwidth; i++, data += (mono_plane ? 1 : 2)) + lumaLine = lineBuffer; + chromaLine = lineBuffer + scanLength; + for (i = 0; i < VIDEOSIZE_X(frame->request); i++) { unsigned char rv, gv, bv; /* RGB components */ - /* - * Search for potential Start-Of-Frame marker. It should - * not be here, of course, but if your formats don't match - * you might exceed the frame. We must match the marker to - * each byte of multi-byte data element if it is multi-byte. - */ -#if 1 - if ((ibmcam->camera_model == IBMCAM_MODEL_1) && (scratch_left(data) >= (4+2))) { - unsigned char *dp; - int j; - - for (j=0, dp=data; j < 2; j++, dp++) { - if ((dp[0] == 0x00) && (dp[1] == 0xFF) && - (dp[2] == 0x00) && (dp[3] == frame->hdr_sig)) { - ibmcam->has_hdr = 2; - frame_done++; - break; - } - } - } -#endif - /* Check for various visual debugging hints (colorized pixels) */ - if ((flags & FLAGS_DISPLAY_HINTS) && (ibmcam->has_hdr)) { + if ((flags & FLAGS_DISPLAY_HINTS) && (icam->has_hdr)) { /* * This is bad and should not happen. This means that * we somehow overshoot the line and encountered new @@ -813,7 +530,7 @@ * of whack. This cyan dot will help you to figure * out where exactly the new frame arrived. */ - if (ibmcam->has_hdr == 1) { + if (icam->has_hdr == 1) { bv = 0; /* Yellow marker */ gv = 0xFF; rv = 0xFF; @@ -822,15 +539,27 @@ gv = 0xFF; rv = 0; } - ibmcam->has_hdr = 0; + icam->has_hdr = 0; goto make_pixel; } - if (mono_plane || frame->order_yc) - y = data[0]; - else - y = data[1]; + /* + * Check if we are still in range. We may be out of range if our + * V4L canvas is wider or taller than the camera "native" image. + * Then we quickly fill the remainder of the line with zeros to + * make black color and quit the horizontal scanning loop. + */ + if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) { + const int j = i * V4L_BYTES_PER_PIXEL; +#if USES_IBMCAM_PUTPIXEL + /* Refresh 'f' because we don't use it much with PUTPIXEL */ + f = frame->data + (v4l_linesize * frame->curline) + j; +#endif + memset(f, 0, v4l_linesize - j); + break; + } + y = lumaLine[i]; if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */ rv = gv = bv = y; else { @@ -839,11 +568,11 @@ off_0 = (i >> 1) << 2; off_2 = off_0 + 2; - if (frame->order_yc) { + if (order_yc) { off_0++; off_2++; } - if (!frame->order_uv) { + if (!order_uv) { off_0 += 2; off_2 -= 2; } @@ -871,7 +600,7 @@ * (in this order). */ #if USES_IBMCAM_PUTPIXEL - IBMCAM_PUTPIXEL(frame, i, frame->curline, rv, gv, bv); + RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv); #else *f++ = bv; *f++ = gv; @@ -893,18 +622,19 @@ * may fill more than one output scanline if we do vertical * enlargement. */ - frame->curline++; - *pcopylen += v4l_linesize; - usb_ibmcam_align_scratch(ibmcam, data); + frame->curline += 2; + if (pcopylen != NULL) + *pcopylen += 2 * v4l_linesize; + frame->deinterlace = Deinterlace_FillOddLines; - if (frame_done || (frame->curline >= frame->frmheight)) + if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request))) return scan_NextFrame; else return scan_Continue; } /* - * usb_ibmcam_model2_parse_lines() + * ibmcam_model2_320x240_parse_lines() * * This procedure deals with a weird RGB format that is produced by IBM * camera model 2 in modes 320x240 and above; 'x' below is 159 or 175, @@ -912,15 +642,15 @@ * * <--- 160 or 176 pairs of RA,RB bytes -----> * *-----------------------------------------* \ - * | RA0 | RB0 | RA1 | RB1 | ... | RAx | RBx | \ - * |-----+-----+-----+-----+ ... +-----+-----| *- This is pair of horizontal lines, - * | B0 | G0 | B1 | G1 | ... | Bx | Gx | / total 240 or 288 lines (120 or 144 - * |=====+=====+=====+=====+ ... +=====+=====| / such pairs). + * | RA0 | RB0 | RA1 | RB1 | ... | RAx | RBx | \ This is pair of horizontal lines, + * |-----+-----+-----+-----+ ... +-----+-----| *- or one interlaced line, total + * | B0 | G0 | B1 | G1 | ... | Bx | Gx | / 120 or 144 such pairs which yield + * |=====+=====+=====+=====+ ... +=====+=====| / 240 or 288 lines after deinterlacing. * * Each group of FOUR bytes (RAi, RBi, Bi, Gi) where i=0..frame_width/2-1 * defines ONE pixel. Therefore this format yields 176x144 "decoded" * resolution at best. I do not know why camera sends such format - the - * previous model just used I420 and everyone was happy. + * previous model (1) just used interlaced I420 and everyone was happy. * * I do not know what is the difference between RAi and RBi bytes. Both * seemingly represent R component, but slightly vary in value (so that @@ -928,49 +658,58 @@ * them both as R component in attempt to at least partially recover the * lost resolution. */ -static scan_state_t usb_ibmcam_model2_parse_lines(struct usb_ibmcam *ibmcam, long *pcopylen) +static ParseState_t ibmcam_model2_320x240_parse_lines( + uvd_t *uvd, + usbvideo_frame_t *frame, + long *pcopylen) { - struct ibmcam_frame *frame; - unsigned char *data, *f, *la, *lb; + unsigned char *f, *la, *lb; unsigned int len; - const int v4l_linesize = imgwidth * V4L_BYTES_PER_PIXEL; /* V4L line offset */ + int v4l_linesize; /* V4L line offset */ int i, j, frame_done=0, color_corr; + int scanLength, scanHeight; + static unsigned char lineBuffer[352*2]; - color_corr = (ibmcam->vpic.colour) >> 8; /* 0..+255 */ - - data = ibmcam->scratch; - frame = &ibmcam->frame[ibmcam->curframe]; - - /* Here we deal with pairs of horizontal lines */ - - len = frame->frmwidth * 2; /* 2 lines */ - /*printk(KERN_DEBUG "len=%d. left=%d.\n",len,scratch_left(data));*/ - - /* Make sure there's enough data for the entire line */ - if (scratch_left(data) < (len+32)) { - /*printk(KERN_DEBUG "out of data, need %u.\n", len);*/ + switch (uvd->videosize) { + case VIDEOSIZE_320x240: + case VIDEOSIZE_352x240: + case VIDEOSIZE_352x288: + scanLength = VIDEOSIZE_X(uvd->videosize); + scanHeight = VIDEOSIZE_Y(uvd->videosize); + break; + default: + err("ibmcam_model2_320x240_parse_lines: Wrong mode."); return scan_Out; } + color_corr = (uvd->vpic.colour) >> 8; /* 0..+255 */ + v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; + + len = scanLength * 2; /* See explanation above */ + assert(len <= sizeof(lineBuffer)); + + /* Make sure there's enough data for the entire line */ + if (RingQueue_GetLength(&uvd->dp) < len) + return scan_Out; + + /* Suck one line out of the ring queue */ + RingQueue_Dequeue(&uvd->dp, lineBuffer, len); + /* * Make sure that our writing into output buffer * will not exceed the buffer. Mind that we may write * not into current output scanline but in several after * it as well (if we enlarge image vertically.) */ - if ((frame->curline + 1) >= V4L_FRAME_HEIGHT) + if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request)) return scan_NextFrame; - if ((frame->curline & 1) == 0) { - la = data; - lb = data + frame->frmwidth; - } else { - la = data + frame->frmwidth; - lb = data; - } + la = lineBuffer; + lb = lineBuffer + scanLength; /* - * Now we are sure that entire line (representing all 'frame->frmwidth' + * Now we are sure that entire line (representing all + * VIDEOSIZE_X(frame->request) * pixels from the camera) is available in the scratch buffer. We * start copying the line left-aligned to the V4L buffer (which * might be larger - not smaller, hopefully). If the camera @@ -980,14 +719,14 @@ f = frame->data + (v4l_linesize * frame->curline); /* Fill the 2-line strip */ - for (i = 0; i < frame->frmwidth; i++) { + for (i = 0; i < VIDEOSIZE_X(frame->request); i++) { int y, rv, gv, bv; /* RGB components */ j = i & (~1); /* Check for various visual debugging hints (colorized pixels) */ - if ((flags & FLAGS_DISPLAY_HINTS) && (ibmcam->has_hdr)) { - if (ibmcam->has_hdr == 1) { + if ((flags & FLAGS_DISPLAY_HINTS) && (IBMCAM_T(uvd)->has_hdr)) { + if (IBMCAM_T(uvd)->has_hdr == 1) { bv = 0; /* Yellow marker */ gv = 0xFF; rv = 0xFF; @@ -996,11 +735,27 @@ gv = 0xFF; rv = 0; } - ibmcam->has_hdr = 0; + IBMCAM_T(uvd)->has_hdr = 0; goto make_pixel; } /* + * Check if we are still in range. We may be out of range if our + * V4L canvas is wider or taller than the camera "native" image. + * Then we quickly fill the remainder of the line with zeros to + * make black color and quit the horizontal scanning loop. + */ + if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) { + const int j = i * V4L_BYTES_PER_PIXEL; +#if USES_IBMCAM_PUTPIXEL + /* Refresh 'f' because we don't use it much with PUTPIXEL */ + f = frame->data + (v4l_linesize * frame->curline) + j; +#endif + memset(f, 0, v4l_linesize - j); + break; + } + + /* * Here I use RA and RB components, one per physical pixel. * This causes fine vertical grid on the picture but may improve * horizontal resolution. If you prefer replicating, use this: @@ -1039,8 +794,7 @@ } make_pixel: - IBMCAM_PUTPIXEL(frame, i, frame->curline, rv, gv, bv); - IBMCAM_PUTPIXEL(frame, i, frame->curline+1, rv, gv, bv); + RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv); } /* * Account for number of bytes that we wrote into output V4L frame. @@ -1050,257 +804,342 @@ */ frame->curline += 2; *pcopylen += v4l_linesize * 2; - data += frame->frmwidth * 2; - usb_ibmcam_align_scratch(ibmcam, data); + frame->deinterlace = Deinterlace_FillOddLines; - if (frame_done || (frame->curline >= frame->frmheight)) + if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request))) return scan_NextFrame; else return scan_Continue; } -/* - * ibmcam_parse_data() - * - * Generic routine to parse the scratch buffer. It employs either - * usb_ibmcam_find_header() or usb_ibmcam_parse_lines() to do most - * of work. - * - * History: - * 1/21/00 Created. - */ -static void ibmcam_parse_data(struct usb_ibmcam *ibmcam) +static ParseState_t ibmcam_model3_parse_lines( + uvd_t *uvd, + usbvideo_frame_t *frame, + long *pcopylen) { - struct ibmcam_frame *frame; - unsigned char *data = ibmcam->scratch; - scan_state_t newstate; - long copylen = 0; - - /* Grab the current frame and the previous frame */ - frame = &ibmcam->frame[ibmcam->curframe]; + unsigned char *data; + const unsigned char *color; + unsigned int len; + int v4l_linesize; /* V4L line offset */ + const int hue_corr = (uvd->vpic.hue - 0x8000) >> 10; /* -32..+31 */ + const int hue2_corr = (hue_correction - 128) / 4; /* -32..+31 */ + const int ccm = 128; /* Color correction median - see below */ + int i, u, v, rw, data_w=0, data_h=0, color_corr; + static unsigned char lineBuffer[640*3]; - /* printk(KERN_DEBUG "parsing %u.\n", ibmcam->scratchlen); */ + color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/ + RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1); - while (1) { + v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; - newstate = scan_Out; - if (scratch_left(data)) { - if (frame->scanstate == STATE_SCANNING) - newstate = usb_ibmcam_find_header(ibmcam); - else if (frame->scanstate == STATE_LINES) { - if ((ibmcam->camera_model == IBMCAM_MODEL_2) && - (videosize >= VIDEOSIZE_352x288)) { - newstate = usb_ibmcam_model2_parse_lines(ibmcam, ©len); - } - else { - newstate = usb_ibmcam_parse_lines(ibmcam, ©len); - } - } - } - if (newstate == scan_Continue) - continue; - else if ((newstate == scan_NextFrame) || (newstate == scan_Out)) - break; - else - return; /* scan_EndParse */ + /* The header tells us what sort of data is in this frame */ + switch (frame->header) { + /* + * Uncompressed modes (that are easy to decode). + */ + case 0x0308: + data_w = 640; + data_h = 480; + break; + case 0x0208: + data_w = 320; + data_h = 240; + break; + case 0x020A: + data_w = 160; + data_h = 120; + break; + /* + * Compressed modes (ViCE - that I don't know how to decode). + */ + case 0x0328: /* 640x480, best quality compression */ + case 0x0368: /* 640x480, best frame rate compression */ + case 0x0228: /* 320x240, best quality compression */ + case 0x0268: /* 320x240, best frame rate compression */ + case 0x02CA: /* 160x120, best quality compression */ + case 0x02EA: /* 160x120, best frame rate compression */ + /* Do nothing with this - not supported */ + err("Unsupported mode $%04lx", frame->header); + return scan_NextFrame; + default: + /* Catch unknown headers, may help in learning new headers */ + err("Strange frame->header=$%08lx", frame->header); + return scan_NextFrame; } - if (newstate == scan_NextFrame) { - frame->grabstate = FRAME_DONE; - ibmcam->curframe = -1; - ibmcam->frame_num++; - - /* Optionally display statistics on the screen */ - if (flags & FLAGS_OVERLAY_STATS) - usb_ibmcam_overlaystats(ibmcam, frame); - - /* This will cause the process to request another frame. */ - if (waitqueue_active(&frame->wq)) - wake_up_interruptible(&frame->wq); + /* + * Make sure that our writing into output buffer + * will not exceed the buffer. Note that we may write + * not into current output scanline but in several after + * it as well (if we enlarge image vertically.) + */ + if ((frame->curline + 1) >= data_h) { + if (uvd->debug >= 3) + info("Reached line %d. (frame is done)", frame->curline); + return scan_NextFrame; } - /* Update the frame's uncompressed length. */ - frame->scanlength += copylen; -} + /* Make sure there's enough data for the entire line */ + len = 3 * data_w; /* <y-data> <uv-data> */ + assert(len <= sizeof(lineBuffer)); -/* - * Make all of the blocks of data contiguous - */ -static int ibmcam_compress_isochronous(struct usb_ibmcam *ibmcam, urb_t *urb) -{ - unsigned char *cdata, *data, *data0; - int i, totlen = 0; + /* Make sure there's enough data for the entire line */ + if (RingQueue_GetLength(&uvd->dp) < len) + return scan_Out; - data = data0 = ibmcam->scratch + ibmcam->scratchlen; - 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; + /* Suck one line out of the ring queue */ + RingQueue_Dequeue(&uvd->dp, lineBuffer, len); - /* Detect and ignore errored packets */ - if (st < 0) { - if (debug >= 1) { - printk(KERN_ERR "ibmcam data error: [%d] len=%d, status=%X\n", - i, n, st); - } - ibmcam->iso_err_count++; - continue; - } + data = lineBuffer; + color = data + data_w; /* Point to where color planes begin */ - /* Detect and ignore empty packets */ - if (n <= 0) { - ibmcam->iso_skip_count++; - continue; - } + /* Bottom-to-top scanning */ + rw = (int)VIDEOSIZE_Y(frame->request) - (int)(frame->curline) - 1; + RESTRICT_TO_RANGE(rw, 0, VIDEOSIZE_Y(frame->request)-1); - /* - * If camera continues to feed us with data but there is no - * consumption (if, for example, V4L client fell asleep) we - * may overflow the buffer. We have to move old data over to - * free room for new data. This is bad for old data. If we - * just drop new data then it's bad for new data... choose - * your favorite evil here. - */ - if ((ibmcam->scratchlen + n) > scratchbufsize) { -#if 0 - ibmcam->scratch_ovf_count++; - if (debug >= 3) - printk(KERN_ERR "ibmcam: scratch buf overflow! " - "scr_len: %d, n: %d\n", ibmcam->scratchlen, n ); - return totlen; -#else - int mv; + for (i = 0; i < VIDEOSIZE_X(frame->request); i++) { + int y, rv, gv, bv; /* RGB components */ - ibmcam->scratch_ovf_count++; - if (debug >= 3) { - printk(KERN_ERR "ibmcam: scratch buf overflow! " - "scr_len: %d, n: %d\n", ibmcam->scratchlen, n ); - } - mv = (ibmcam->scratchlen + n) - scratchbufsize; - if (ibmcam->scratchlen >= mv) { - int newslen = ibmcam->scratchlen - mv; - memmove(ibmcam->scratch, ibmcam->scratch + mv, newslen); - ibmcam->scratchlen = newslen; - data = data0 = ibmcam->scratch + ibmcam->scratchlen; - } else { - printk(KERN_ERR "ibmcam: scratch buf too small\n"); - return totlen; + if (i < data_w) { + y = data[i]; /* Luminosity is the first line */ + + /* Apply static color correction */ + u = color[i*2] + hue_corr; + v = color[i*2 + 1] + hue2_corr; + + /* Apply color correction */ + if (color_corr != 0) { + /* Magnify up to 2 times, reduce down to zero saturation */ + u = 128 + ((ccm + color_corr) * (u - 128)) / ccm; + v = 128 + ((ccm + color_corr) * (v - 128)) / ccm; } -#endif - } + } else + y = 0, u = v = 128; - /* Now we know that there is enough room in scratch buffer */ - memmove(data, cdata, n); - data += n; - totlen += n; - ibmcam->scratchlen += n; + YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv); + RGB24_PUTPIXEL(frame, i, rw, rv, gv, bv); /* Done by deinterlacing now */ } -#if 0 - if (totlen > 0) { - static int foo=0; - if (foo < 1) { - printk(KERN_DEBUG "+%d.\n", totlen); - ibmcam_hexdump(data0, (totlen > 64) ? 64:totlen); - ++foo; + frame->deinterlace = Deinterlace_FillEvenLines; + + /* + * Account for number of bytes that we wrote into output V4L frame. + * We do it here, after we are done with the scanline, because we + * may fill more than one output scanline if we do vertical + * enlargement. + */ + frame->curline += 2; + *pcopylen += 2 * v4l_linesize; + + if (frame->curline >= VIDEOSIZE_Y(frame->request)) { + if (uvd->debug >= 3) { + info("All requested lines (%ld.) done.", + VIDEOSIZE_Y(frame->request)); } - } -#endif - return totlen; + return scan_NextFrame; + } else + return scan_Continue; } -static void ibmcam_isoc_irq(struct urb *urb) +/* + * ibmcam_model4_128x96_parse_lines() + * + * This decoder is for one strange data format that is produced by Model 4 + * camera only in 128x96 mode. This is RGB format and here is its description. + * First of all, this is non-interlaced stream, meaning that all scan lines + * are present in the datastream. There are 96 consecutive blocks of data + * that describe all 96 lines of the image. Each block is 5*128 bytes long + * and carries R, G, B components. The format of the block is shown in the + * code below. First 128*2 bytes are interleaved R and G components. Then + * we have a gap (junk data) 64 bytes long. Then follow B and something + * else, also interleaved (this makes another 128*2 bytes). After that + * probably another 64 bytes of junk follow. + * + * History: + * 10-Feb-2001 Created. + */ +static ParseState_t ibmcam_model4_128x96_parse_lines( + uvd_t *uvd, + usbvideo_frame_t *frame, + long *pcopylen) { - int len; - struct usb_ibmcam *ibmcam = urb->context; - struct ibmcam_sbuf *sbuf; - int i; + const unsigned char *data_rv, *data_gv, *data_bv; + unsigned int len; + int i, v4l_linesize; /* V4L line offset */ + const int data_w=128, data_h=96; + static unsigned char lineBuffer[128*5]; - /* We don't want to do anything if we are about to be removed! */ - if (!IBMCAM_IS_OPERATIONAL(ibmcam)) - return; + v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; -#if 0 - if (urb->actual_length > 0) { - printk(KERN_DEBUG "ibmcam_isoc_irq: %p status %d, " - " errcount = %d, length = %d\n", urb, urb->status, - urb->error_count, urb->actual_length); - } else { - static int c = 0; - if (c++ % 100 == 0) - printk(KERN_DEBUG "ibmcam_isoc_irq: no data\n"); + /* + * Make sure that our writing into output buffer + * will not exceed the buffer. Note that we may write + * not into current output scanline but in several after + * it as well (if we enlarge image vertically.) + */ + if ((frame->curline + 1) >= data_h) { + if (uvd->debug >= 3) + info("Reached line %d. (frame is done)", frame->curline); + return scan_NextFrame; } -#endif - if (!ibmcam->streaming) { - if (debug >= 1) - printk(KERN_DEBUG "ibmcam: oops, not streaming, but interrupt\n"); - return; - } - - sbuf = &ibmcam->sbuf[ibmcam->cursbuf]; + /* + * RGRGRG .... RGRG_____________B?B?B? ... B?B?____________ + * <---- 128*2 ---><---- 64 ---><--- 128*2 ---><--- 64 ---> + */ + + /* Make sure there's enough data for the entire line */ + len = 5 * data_w; + assert(len <= sizeof(lineBuffer)); - /* Copy the data received into our scratch buffer */ - len = ibmcam_compress_isochronous(ibmcam, urb); + /* Make sure there's enough data for the entire line */ + if (RingQueue_GetLength(&uvd->dp) < len) + return scan_Out; - ibmcam->urb_count++; - ibmcam->urb_length = len; - ibmcam->data_count += len; - -#if 0 /* This code prints few initial bytes of ISO data: used to decode markers */ - if (ibmcam->urb_count % 64 == 1) { - if (ibmcam->urb_count == 1) { - ibmcam_hexdump(ibmcam->scratch, - (ibmcam->scratchlen > 32) ? 32 : ibmcam->scratchlen); + /* Suck one line out of the ring queue */ + RingQueue_Dequeue(&uvd->dp, lineBuffer, len); + + data_rv = lineBuffer; + data_gv = lineBuffer + 1; + data_bv = lineBuffer + data_w*2 + data_w/2; + for (i = 0; i < VIDEOSIZE_X(frame->request); i++) { + int rv, gv, bv; /* RGB components */ + if (i < data_w) { + const int j = i * 2; + gv = data_rv[j]; + rv = data_gv[j]; + bv = data_bv[j]; + if (flags & FLAGS_MONOCHROME) { + unsigned long y; + y = rv + gv + bv; + y /= 3; + if (y > 0xFF) + y = 0xFF; + rv = gv = bv = (unsigned char) y; + } + } else { + rv = gv = bv = 0; } + RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv); } -#endif + frame->deinterlace = Deinterlace_None; + frame->curline++; + *pcopylen += v4l_linesize; - /* If we collected enough data let's parse! */ - if (ibmcam->scratchlen) { - /* If we don't have a frame we're current working on, complain */ - if (ibmcam->curframe >= 0) - ibmcam_parse_data(ibmcam); - else { - if (debug >= 1) - printk(KERN_DEBUG "ibmcam: received data, but no frame available\n"); + if (frame->curline >= VIDEOSIZE_Y(frame->request)) { + if (uvd->debug >= 3) { + info("All requested lines (%ld.) done.", + VIDEOSIZE_Y(frame->request)); + } + return scan_NextFrame; + } else + return scan_Continue; +} + +/* + * ibmcam_ProcessIsocData() + * + * Generic routine to parse the ring queue data. It employs either + * ibmcam_find_header() or ibmcam_parse_lines() to do most + * of work. + * + * History: + * 1/21/00 Created. + */ +void ibmcam_ProcessIsocData(uvd_t *uvd, usbvideo_frame_t *frame) +{ + ParseState_t newstate; + long copylen = 0; + int mod = IBMCAM_T(uvd)->camera_model; + + while (1) { + newstate = scan_Out; + if (RingQueue_GetLength(&uvd->dp) > 0) { + if (frame->scanstate == ScanState_Scanning) { + newstate = ibmcam_find_header(uvd); + } else if (frame->scanstate == ScanState_Lines) { + if ((mod == IBMCAM_MODEL_2) && + ((uvd->videosize == VIDEOSIZE_352x288) || + (uvd->videosize == VIDEOSIZE_320x240) || + (uvd->videosize == VIDEOSIZE_352x240))) + { + newstate = ibmcam_model2_320x240_parse_lines( + uvd, frame, ©len); + } else if (mod == IBMCAM_MODEL_4) { + /* + * Model 4 cameras (IBM NetCamera) use Model 2 decoder (RGB) + * for 320x240 and above; 160x120 and 176x144 uses Model 1 + * decoder (YUV), and 128x96 mode uses ??? + */ + if ((uvd->videosize == VIDEOSIZE_352x288) || + (uvd->videosize == VIDEOSIZE_320x240) || + (uvd->videosize == VIDEOSIZE_352x240)) + { + newstate = ibmcam_model2_320x240_parse_lines(uvd, frame, ©len); + } else if (uvd->videosize == VIDEOSIZE_128x96) { + newstate = ibmcam_model4_128x96_parse_lines(uvd, frame, ©len); + } else { + newstate = ibmcam_parse_lines(uvd, frame, ©len); + } + } else if (mod == IBMCAM_MODEL_3) { + newstate = ibmcam_model3_parse_lines(uvd, frame, ©len); + } else { + newstate = ibmcam_parse_lines(uvd, frame, ©len); + } + } } + if (newstate == scan_Continue) + continue; + else if ((newstate == scan_NextFrame) || (newstate == scan_Out)) + break; + else + return; /* scan_EndParse */ } - for (i = 0; i < FRAMES_PER_DESC; i++) { - sbuf->urb->iso_frame_desc[i].status = 0; - sbuf->urb->iso_frame_desc[i].actual_length = 0; + if (newstate == scan_NextFrame) { + frame->frameState = FrameState_Done; + uvd->curframe = -1; + uvd->stats.frame_num++; + if ((mod == IBMCAM_MODEL_2) || (mod == IBMCAM_MODEL_4)) { + /* Need software contrast adjustment for those cameras */ + frame->flags |= USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST; + } } - /* Move to the next sbuf */ - ibmcam->cursbuf = (ibmcam->cursbuf + 1) % IBMCAM_NUMSBUF; + /* Update the frame's uncompressed length. */ + frame->seqRead_Length += copylen; - return; +#if 0 + { + static unsigned char j=0; + memset(frame->data, j++, uvd->max_frame_size); + frame->frameState = FrameState_Ready; + } +#endif } /* - * usb_ibmcam_veio() + * ibmcam_veio() * * History: * 1/27/00 Added check for dev == NULL; this happens if camera is unplugged. */ -static int usb_ibmcam_veio( - struct usb_ibmcam *ibmcam, +static int ibmcam_veio( + uvd_t *uvd, unsigned char req, unsigned short value, unsigned short index) { - static const char proc[] = "usb_ibmcam_veio"; + static const char proc[] = "ibmcam_veio"; unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */; int i; - if (!IBMCAM_IS_OPERATIONAL(ibmcam)) + if (!CAMERA_IS_OPERATIONAL(uvd)) return 0; if (req == 1) { i = usb_control_msg( - ibmcam->dev, - usb_rcvctrlpipe(ibmcam->dev, 0), + uvd->dev, + usb_rcvctrlpipe(uvd->dev, 0), req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, value, @@ -1309,15 +1148,15 @@ sizeof(cp), HZ); #if 0 - printk(KERN_DEBUG "USB => %02x%02x%02x%02x%02x%02x%02x%02x " - "(req=$%02x val=$%04x ind=$%04x)\n", + info("USB => %02x%02x%02x%02x%02x%02x%02x%02x " + "(req=$%02x val=$%04x ind=$%04x)", cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7], req, value, index); #endif } else { i = usb_control_msg( - ibmcam->dev, - usb_sndctrlpipe(ibmcam->dev, 0), + uvd->dev, + usb_sndctrlpipe(uvd->dev, 0), req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, value, @@ -1327,15 +1166,15 @@ HZ); } if (i < 0) { - printk(KERN_ERR "%s: ERROR=%d. Camera stopped - " - "reconnect or reload driver.\n", proc, i); - ibmcam->last_error = i; + err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.", + proc, i); + uvd->last_error = i; } return i; } /* - * usb_ibmcam_calculate_fps() + * ibmcam_calculate_fps() * * This procedure roughly calculates the real frame rate based * on FPS code (framerate=NNN option). Actual FPS differs @@ -1352,13 +1191,13 @@ * History: * 1/18/00 Created. */ -static int usb_ibmcam_calculate_fps(void) +static int ibmcam_calculate_fps(uvd_t *uvd) { return 3 + framerate*4 + framerate/2; } /* - * usb_ibmcam_send_FF_04_02() + * ibmcam_send_FF_04_02() * * This procedure sends magic 3-command prefix to the camera. * The purpose of this prefix is not known. @@ -1366,108 +1205,140 @@ * History: * 1/2/00 Created. */ -static void usb_ibmcam_send_FF_04_02(struct usb_ibmcam *ibmcam) +static void ibmcam_send_FF_04_02(uvd_t *uvd) { - usb_ibmcam_veio(ibmcam, 0, 0x00FF, 0x0127); - usb_ibmcam_veio(ibmcam, 0, 0x0004, 0x0124); - usb_ibmcam_veio(ibmcam, 0, 0x0002, 0x0124); + ibmcam_veio(uvd, 0, 0x00FF, 0x0127); + ibmcam_veio(uvd, 0, 0x0004, 0x0124); + ibmcam_veio(uvd, 0, 0x0002, 0x0124); } -static void usb_ibmcam_send_00_04_06(struct usb_ibmcam *ibmcam) +static void ibmcam_send_00_04_06(uvd_t *uvd) { - usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0127); - usb_ibmcam_veio(ibmcam, 0, 0x0004, 0x0124); - usb_ibmcam_veio(ibmcam, 0, 0x0006, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0x0004, 0x0124); + ibmcam_veio(uvd, 0, 0x0006, 0x0124); } -static void usb_ibmcam_send_x_00(struct usb_ibmcam *ibmcam, unsigned short x) +static void ibmcam_send_x_00(uvd_t *uvd, unsigned short x) { - usb_ibmcam_veio(ibmcam, 0, x, 0x0127); - usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0124); + ibmcam_veio(uvd, 0, x, 0x0127); + ibmcam_veio(uvd, 0, 0x0000, 0x0124); } -static void usb_ibmcam_send_x_00_05(struct usb_ibmcam *ibmcam, unsigned short x) +static void ibmcam_send_x_00_05(uvd_t *uvd, unsigned short x) { - usb_ibmcam_send_x_00(ibmcam, x); - usb_ibmcam_veio(ibmcam, 0, 0x0005, 0x0124); + ibmcam_send_x_00(uvd, x); + ibmcam_veio(uvd, 0, 0x0005, 0x0124); } -static void usb_ibmcam_send_x_00_05_02(struct usb_ibmcam *ibmcam, unsigned short x) +static void ibmcam_send_x_00_05_02(uvd_t *uvd, unsigned short x) { - usb_ibmcam_veio(ibmcam, 0, x, 0x0127); - usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0124); - usb_ibmcam_veio(ibmcam, 0, 0x0005, 0x0124); - usb_ibmcam_veio(ibmcam, 0, 0x0002, 0x0124); + ibmcam_veio(uvd, 0, x, 0x0127); + ibmcam_veio(uvd, 0, 0x0000, 0x0124); + ibmcam_veio(uvd, 0, 0x0005, 0x0124); + ibmcam_veio(uvd, 0, 0x0002, 0x0124); } -static void usb_ibmcam_send_x_01_00_05(struct usb_ibmcam *ibmcam, unsigned short x) +static void ibmcam_send_x_01_00_05(uvd_t *uvd, unsigned short x) { - usb_ibmcam_veio(ibmcam, 0, x, 0x0127); - usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0124); - usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0124); - usb_ibmcam_veio(ibmcam, 0, 0x0005, 0x0124); + ibmcam_veio(uvd, 0, x, 0x0127); + ibmcam_veio(uvd, 0, 0x0001, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0124); + ibmcam_veio(uvd, 0, 0x0005, 0x0124); } -static void usb_ibmcam_send_x_00_05_02_01(struct usb_ibmcam *ibmcam, unsigned short x) +static void ibmcam_send_x_00_05_02_01(uvd_t *uvd, unsigned short x) { - usb_ibmcam_veio(ibmcam, 0, x, 0x0127); - usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0124); - usb_ibmcam_veio(ibmcam, 0, 0x0005, 0x0124); - usb_ibmcam_veio(ibmcam, 0, 0x0002, 0x0124); - usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0124); + ibmcam_veio(uvd, 0, x, 0x0127); + ibmcam_veio(uvd, 0, 0x0000, 0x0124); + ibmcam_veio(uvd, 0, 0x0005, 0x0124); + ibmcam_veio(uvd, 0, 0x0002, 0x0124); + ibmcam_veio(uvd, 0, 0x0001, 0x0124); } -static void usb_ibmcam_send_x_00_05_02_08_01(struct usb_ibmcam *ibmcam, unsigned short x) +static void ibmcam_send_x_00_05_02_08_01(uvd_t *uvd, unsigned short x) { - usb_ibmcam_veio(ibmcam, 0, x, 0x0127); - usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0124); - usb_ibmcam_veio(ibmcam, 0, 0x0005, 0x0124); - usb_ibmcam_veio(ibmcam, 0, 0x0002, 0x0124); - usb_ibmcam_veio(ibmcam, 0, 0x0008, 0x0124); - usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0124); + ibmcam_veio(uvd, 0, x, 0x0127); + ibmcam_veio(uvd, 0, 0x0000, 0x0124); + ibmcam_veio(uvd, 0, 0x0005, 0x0124); + ibmcam_veio(uvd, 0, 0x0002, 0x0124); + ibmcam_veio(uvd, 0, 0x0008, 0x0124); + ibmcam_veio(uvd, 0, 0x0001, 0x0124); } -static void usb_ibmcam_Packet_Format1(struct usb_ibmcam *ibmcam, unsigned char fkey, unsigned char val) +static void ibmcam_Packet_Format1(uvd_t *uvd, unsigned char fkey, unsigned char val) { - usb_ibmcam_send_x_01_00_05 (ibmcam, unknown_88); - usb_ibmcam_send_x_00_05 (ibmcam, fkey); - usb_ibmcam_send_x_00_05_02_08_01(ibmcam, val); - usb_ibmcam_send_x_00_05 (ibmcam, unknown_88); - usb_ibmcam_send_x_00_05_02_01 (ibmcam, fkey); - usb_ibmcam_send_x_00_05 (ibmcam, unknown_89); - usb_ibmcam_send_x_00 (ibmcam, fkey); - usb_ibmcam_send_00_04_06 (ibmcam); - usb_ibmcam_veio (ibmcam, 1, 0x0000, 0x0126); - usb_ibmcam_send_FF_04_02 (ibmcam); + ibmcam_send_x_01_00_05(uvd, unknown_88); + ibmcam_send_x_00_05(uvd, fkey); + ibmcam_send_x_00_05_02_08_01(uvd, val); + ibmcam_send_x_00_05(uvd, unknown_88); + ibmcam_send_x_00_05_02_01(uvd, fkey); + ibmcam_send_x_00_05(uvd, unknown_89); + ibmcam_send_x_00(uvd, fkey); + ibmcam_send_00_04_06(uvd); + ibmcam_veio(uvd, 1, 0x0000, 0x0126); + ibmcam_send_FF_04_02(uvd); } -static void usb_ibmcam_PacketFormat2(struct usb_ibmcam *ibmcam, unsigned char fkey, unsigned char val) +static void ibmcam_PacketFormat2(uvd_t *uvd, unsigned char fkey, unsigned char val) { - usb_ibmcam_send_x_01_00_05 (ibmcam, unknown_88); - usb_ibmcam_send_x_00_05 (ibmcam, fkey); - usb_ibmcam_send_x_00_05_02 (ibmcam, val); + ibmcam_send_x_01_00_05 (uvd, unknown_88); + ibmcam_send_x_00_05 (uvd, fkey); + ibmcam_send_x_00_05_02 (uvd, val); } -static void usb_ibmcam_model2_Packet2(struct usb_ibmcam *ibmcam) +static void ibmcam_model2_Packet2(uvd_t *uvd) { - usb_ibmcam_veio(ibmcam, 0, 0x00ff, 0x012d); - usb_ibmcam_veio(ibmcam, 0, 0xfea3, 0x0124); + ibmcam_veio(uvd, 0, 0x00ff, 0x012d); + ibmcam_veio(uvd, 0, 0xfea3, 0x0124); } -static void usb_ibmcam_model2_Packet1(struct usb_ibmcam *ibmcam, unsigned short v1, unsigned short v2) +static void ibmcam_model2_Packet1(uvd_t *uvd, unsigned short v1, unsigned short v2) { - usb_ibmcam_veio(ibmcam, 0, 0x00aa, 0x012d); - usb_ibmcam_veio(ibmcam, 0, 0x00ff, 0x012e); - usb_ibmcam_veio(ibmcam, 0, v1, 0x012f); - usb_ibmcam_veio(ibmcam, 0, 0x00ff, 0x0130); - usb_ibmcam_veio(ibmcam, 0, 0xc719, 0x0124); - usb_ibmcam_veio(ibmcam, 0, v2, 0x0127); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x00ff, 0x012e); + ibmcam_veio(uvd, 0, v1, 0x012f); + ibmcam_veio(uvd, 0, 0x00ff, 0x0130); + ibmcam_veio(uvd, 0, 0xc719, 0x0124); + ibmcam_veio(uvd, 0, v2, 0x0127); - usb_ibmcam_model2_Packet2(ibmcam); + ibmcam_model2_Packet2(uvd); +} + +/* + * ibmcam_model3_Packet1() + * + * 00_0078_012d + * 00_0097_012f + * 00_d141_0124 + * 00_0096_0127 + * 00_fea8_0124 +*/ +static void ibmcam_model3_Packet1(uvd_t *uvd, unsigned short v1, unsigned short v2) +{ + ibmcam_veio(uvd, 0, 0x0078, 0x012d); + ibmcam_veio(uvd, 0, v1, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, v2, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); +} + +static void ibmcam_model4_BrightnessPacket(uvd_t *uvd, int i) +{ + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0026, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, i, 0x0127); + ibmcam_veio(uvd, 0, 0x00aa, 0x0130); + ibmcam_veio(uvd, 0, 0x82a8, 0x0124); + ibmcam_veio(uvd, 0, 0x0038, 0x012d); + ibmcam_veio(uvd, 0, 0x0004, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0xfffa, 0x0124); } /* - * usb_ibmcam_adjust_contrast() + * ibmcam_adjust_contrast() * * The contrast value changes from 0 (high contrast) to 15 (low contrast). * This is in reverse to usual order of things (such as TV controls), so @@ -1478,30 +1349,65 @@ * History: * 1/2/00 Created. */ -static void usb_ibmcam_adjust_contrast(struct usb_ibmcam *ibmcam) +static void ibmcam_adjust_contrast(uvd_t *uvd) { - unsigned char new_contrast = ibmcam->vpic.contrast >> 12; - const int ntries = 5; + unsigned char a_contrast = uvd->vpic.contrast >> 12; + unsigned char new_contrast; - if (new_contrast >= 16) - new_contrast = 15; - new_contrast = 15 - new_contrast; - if (new_contrast != ibmcam->vpic_old.contrast) { - ibmcam->vpic_old.contrast = new_contrast; - if (ibmcam->camera_model == IBMCAM_MODEL_1) { - int i; - for (i=0; i < ntries; i++) { - usb_ibmcam_Packet_Format1(ibmcam, contrast_14, new_contrast); - usb_ibmcam_send_FF_04_02(ibmcam); - } - } else { - /* Camera model 2 does not have this control; implemented in software. */ + if (a_contrast >= 16) + a_contrast = 15; + new_contrast = 15 - a_contrast; + if (new_contrast == uvd->vpic_old.contrast) + return; + uvd->vpic_old.contrast = new_contrast; + switch (IBMCAM_T(uvd)->camera_model) { + case IBMCAM_MODEL_1: + { + const int ntries = 5; + int i; + for (i=0; i < ntries; i++) { + ibmcam_Packet_Format1(uvd, contrast_14, new_contrast); + ibmcam_send_FF_04_02(uvd); } + break; + } + case IBMCAM_MODEL_2: + case IBMCAM_MODEL_4: + /* Models 2, 4 do not have this control; implemented in software. */ + break; + case IBMCAM_MODEL_3: + { /* Preset hardware values */ + static const struct { + unsigned short cv1; + unsigned short cv2; + unsigned short cv3; + } cv[7] = { + { 0x05, 0x05, 0x0f }, /* Minimum */ + { 0x04, 0x04, 0x16 }, + { 0x02, 0x03, 0x16 }, + { 0x02, 0x08, 0x16 }, + { 0x01, 0x0c, 0x16 }, + { 0x01, 0x0e, 0x16 }, + { 0x01, 0x10, 0x16 } /* Maximum */ + }; + int i = a_contrast / 2; + RESTRICT_TO_RANGE(i, 0, 6); + ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */ + ibmcam_model3_Packet1(uvd, 0x0067, cv[i].cv1); + ibmcam_model3_Packet1(uvd, 0x005b, cv[i].cv2); + ibmcam_model3_Packet1(uvd, 0x005c, cv[i].cv3); + ibmcam_veio(uvd, 0, 0x0001, 0x0114); + ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */ + usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); + break; + } + default: + break; } } /* - * usb_ibmcam_change_lighting_conditions() + * ibmcam_change_lighting_conditions() * * Camera model 1: * We have 3 levels of lighting conditions: 0=Bright, 1=Medium, 2=Low. @@ -1518,19 +1424,24 @@ * 1/5/00 Created. * 2/20/00 Added support for Model 2 cameras. */ -static void usb_ibmcam_change_lighting_conditions(struct usb_ibmcam *ibmcam) +static void ibmcam_change_lighting_conditions(uvd_t *uvd) { - static const char proc[] = "usb_ibmcam_change_lighting_conditions"; + static const char proc[] = "ibmcam_change_lighting_conditions"; if (debug > 0) - printk(KERN_INFO "%s: Set lighting to %hu.\n", proc, lighting); + info("%s: Set lighting to %hu.", proc, lighting); - if (ibmcam->camera_model == IBMCAM_MODEL_1) { + switch (IBMCAM_T(uvd)->camera_model) { + case IBMCAM_MODEL_1: + { const int ntries = 5; int i; for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(ibmcam, light_27, (unsigned short) lighting); - } else { + ibmcam_Packet_Format1(uvd, light_27, (unsigned short) lighting); + break; + } + case IBMCAM_MODEL_2: +#if 0 /* * This command apparently requires camera to be stopped. My * experiments showed that it -is- possible to alter the lighting @@ -1540,385 +1451,549 @@ * is commented out because it does not work at -any- moment, so its * presence makes no sense. You may use it for experiments. */ -#if 0 - usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x010c); /* Stop camera */ - usb_ibmcam_model2_Packet1(ibmcam, mod2_sensitivity, lighting); - usb_ibmcam_veio(ibmcam, 0, 0x00c0, 0x010c); /* Start camera */ + ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop camera */ + ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting); + ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Start camera */ #endif + break; + case IBMCAM_MODEL_3: + case IBMCAM_MODEL_4: + default: + break; } } /* - * usb_ibmcam_set_sharpness() + * ibmcam_set_sharpness() * * Cameras model 1 have internal smoothing feature. It is controlled by value in * range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess). * Recommended value is 4. Cameras model 2 do not have this feature at all. */ -static void usb_ibmcam_set_sharpness(struct usb_ibmcam *ibmcam) +static void ibmcam_set_sharpness(uvd_t *uvd) { - static const char proc[] = "usb_ibmcam_set_sharpness"; + static const char proc[] = "ibmcam_set_sharpness"; - if (ibmcam->camera_model == IBMCAM_MODEL_1) { + switch (IBMCAM_T(uvd)->camera_model) { + case IBMCAM_MODEL_1: + { static const unsigned short sa[] = { 0x11, 0x13, 0x16, 0x18, 0x1a, 0x8, 0x0a }; unsigned short i, sv; RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX); if (debug > 0) - printk(KERN_INFO "%s: Set sharpness to %hu.\n", proc, sharpness); + info("%s: Set sharpness to %hu.", proc, sharpness); sv = sa[sharpness - SHARPNESS_MIN]; for (i=0; i < 2; i++) { - usb_ibmcam_send_x_01_00_05 (ibmcam, unknown_88); - usb_ibmcam_send_x_00_05 (ibmcam, sharp_13); - usb_ibmcam_send_x_00_05_02 (ibmcam, sv); + ibmcam_send_x_01_00_05 (uvd, unknown_88); + ibmcam_send_x_00_05 (uvd, sharp_13); + ibmcam_send_x_00_05_02 (uvd, sv); } - } else { - /* Camera model 2 does not have this control */ + break; + } + case IBMCAM_MODEL_2: + case IBMCAM_MODEL_4: + /* Models 2, 4 do not have this control */ + break; + case IBMCAM_MODEL_3: + { /* + * "Use a table of magic numbers. + * This setting doesn't really change much. + * But that's how Windows does it." + */ + static const struct { + unsigned short sv1; + unsigned short sv2; + unsigned short sv3; + unsigned short sv4; + } sv[7] = { + { 0x00, 0x00, 0x05, 0x14 }, /* Smoothest */ + { 0x01, 0x04, 0x05, 0x14 }, + { 0x02, 0x04, 0x05, 0x14 }, + { 0x03, 0x04, 0x05, 0x14 }, + { 0x03, 0x05, 0x05, 0x14 }, + { 0x03, 0x06, 0x05, 0x14 }, + { 0x03, 0x07, 0x05, 0x14 } /* Sharpest */ + }; + RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX); + RESTRICT_TO_RANGE(sharpness, 0, 6); + ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */ + ibmcam_model3_Packet1(uvd, 0x0060, sv[sharpness].sv1); + ibmcam_model3_Packet1(uvd, 0x0061, sv[sharpness].sv2); + ibmcam_model3_Packet1(uvd, 0x0062, sv[sharpness].sv3); + ibmcam_model3_Packet1(uvd, 0x0063, sv[sharpness].sv4); + ibmcam_veio(uvd, 0, 0x0001, 0x0114); + ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */ + usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); + ibmcam_veio(uvd, 0, 0x0001, 0x0113); + break; + } + default: + break; } } /* - * usb_ibmcam_set_brightness() + * ibmcam_set_brightness() * * This procedure changes brightness of the picture. */ -static void usb_ibmcam_set_brightness(struct usb_ibmcam *ibmcam) +static void ibmcam_set_brightness(uvd_t *uvd) { - static const char proc[] = "usb_ibmcam_set_brightness"; + static const char proc[] = "ibmcam_set_brightness"; static const unsigned short n = 1; - unsigned short i, j, bv[3]; - - bv[0] = bv[1] = bv[2] = ibmcam->vpic.brightness >> 10; - if (bv[0] == (ibmcam->vpic_old.brightness >> 10)) - return; - ibmcam->vpic_old.brightness = ibmcam->vpic.brightness; if (debug > 0) - printk(KERN_INFO "%s: Set brightness to (%hu,%hu,%hu)\n", - proc, bv[0], bv[1], bv[2]); + info("%s: Set brightness to %hu.", proc, uvd->vpic.brightness); - if (ibmcam->camera_model == IBMCAM_MODEL_1) { + switch (IBMCAM_T(uvd)->camera_model) { + case IBMCAM_MODEL_1: + { + unsigned short i, j, bv[3]; + bv[0] = bv[1] = bv[2] = uvd->vpic.brightness >> 10; + if (bv[0] == (uvd->vpic_old.brightness >> 10)) + return; + uvd->vpic_old.brightness = bv[0]; for (j=0; j < 3; j++) for (i=0; i < n; i++) - usb_ibmcam_Packet_Format1(ibmcam, bright_3x[j], bv[j]); - } else { - i = ibmcam->vpic.brightness >> 12; /* 0 .. 15 */ + ibmcam_Packet_Format1(uvd, bright_3x[j], bv[j]); + break; + } + case IBMCAM_MODEL_2: + { + unsigned short i, j; + i = uvd->vpic.brightness >> 12; /* 0 .. 15 */ j = 0x60 + i * ((0xee - 0x60) / 16); /* 0x60 .. 0xee or so */ - usb_ibmcam_model2_Packet1(ibmcam, mod2_brightness, j); + if (uvd->vpic_old.brightness == j) + break; + uvd->vpic_old.brightness = j; + ibmcam_model2_Packet1(uvd, mod2_brightness, j); + break; + } + case IBMCAM_MODEL_3: + { + /* Model 3: Brightness range 'i' in [0x0C..0x3F] */ + unsigned short i = + 0x0C + (uvd->vpic.brightness / (0xFFFF / (0x3F - 0x0C + 1))); + RESTRICT_TO_RANGE(i, 0x0C, 0x3F); + if (uvd->vpic_old.brightness == i) + break; + uvd->vpic_old.brightness = i; + ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */ + ibmcam_model3_Packet1(uvd, 0x0036, i); + ibmcam_veio(uvd, 0, 0x0001, 0x0114); + ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */ + usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); + ibmcam_veio(uvd, 0, 0x0001, 0x0113); + break; + } + case IBMCAM_MODEL_4: + { + /* Model 4: Brightness range 'i' in [0x04..0xb4] */ + unsigned short i = 0x04 + (uvd->vpic.brightness / (0xFFFF / (0xb4 - 0x04 + 1))); + RESTRICT_TO_RANGE(i, 0x04, 0xb4); + if (uvd->vpic_old.brightness == i) + break; + uvd->vpic_old.brightness = i; + ibmcam_model4_BrightnessPacket(uvd, i); + break; + } + default: + break; } } -static void usb_ibmcam_model2_set_hue(struct usb_ibmcam *ibmcam) +static void ibmcam_set_hue(uvd_t *uvd) { - unsigned short hue = ibmcam->vpic.hue >> 9; /* 0 .. 7F */ + switch (IBMCAM_T(uvd)->camera_model) { + case IBMCAM_MODEL_2: + { + unsigned short hue = uvd->vpic.hue >> 9; /* 0 .. 7F */ + if (uvd->vpic_old.hue == hue) + return; + uvd->vpic_old.hue = hue; + ibmcam_model2_Packet1(uvd, mod2_hue, hue); + /* ibmcam_model2_Packet1(uvd, mod2_saturation, sat); */ + break; + } + case IBMCAM_MODEL_3: + { +#if 0 /* This seems not to work. No problem, will fix programmatically */ + unsigned short hue = 0x05 + (uvd->vpic.hue / (0xFFFF / (0x37 - 0x05 + 1))); + RESTRICT_TO_RANGE(hue, 0x05, 0x37); + if (uvd->vpic_old.hue == hue) + return; + uvd->vpic_old.hue = hue; + ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */ + ibmcam_model3_Packet1(uvd, 0x007e, hue); + ibmcam_veio(uvd, 0, 0x0001, 0x0114); + ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */ + usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); + ibmcam_veio(uvd, 0, 0x0001, 0x0113); +#endif + break; + } + case IBMCAM_MODEL_4: + { + unsigned short r_gain, g_gain, b_gain, hue; + + /* + * I am not sure r/g/b_gain variables exactly control gain + * of those channels. Most likely they subtly change some + * very internal image processing settings in the camera. + * In any case, here is what they do, and feel free to tweak: + * + * r_gain: seriously affects red gain + * g_gain: seriously affects green gain + * b_gain: seriously affects blue gain + * hue: changes average color from violet (0) to red (0xFF) + * + * These settings are preset for a decent white balance in + * 320x240, 352x288 modes. Low-res modes exhibit higher contrast + * and therefore may need different values here. + */ + hue = 20 + (uvd->vpic.hue >> 9); + switch (uvd->videosize) { + case VIDEOSIZE_128x96: + r_gain = 90; + g_gain = 166; + b_gain = 175; + break; + case VIDEOSIZE_160x120: + r_gain = 70; + g_gain = 166; + b_gain = 185; + break; + case VIDEOSIZE_176x144: + r_gain = 160; + g_gain = 175; + b_gain = 185; + break; + default: + r_gain = 120; + g_gain = 166; + b_gain = 175; + break; + } + RESTRICT_TO_RANGE(hue, 1, 0x7f); - usb_ibmcam_model2_Packet1(ibmcam, mod2_color_balance_rg, hue); - /* usb_ibmcam_model2_Packet1(ibmcam, mod2_saturation, sat); */ + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x001e, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, g_gain, 0x0127); /* Green gain */ + ibmcam_veio(uvd, 0, r_gain, 0x012e); /* Red gain */ + ibmcam_veio(uvd, 0, b_gain, 0x0130); /* Blue gain */ + ibmcam_veio(uvd, 0, 0x8a28, 0x0124); + ibmcam_veio(uvd, 0, hue, 0x012d); /* Hue */ + ibmcam_veio(uvd, 0, 0xf545, 0x0124); + break; + } + default: + break; + } } /* - * usb_ibmcam_adjust_picture() + * ibmcam_adjust_picture() * * This procedure gets called from V4L interface to update picture settings. * Here we change brightness and contrast. */ -static void usb_ibmcam_adjust_picture(struct usb_ibmcam *ibmcam) +static void ibmcam_adjust_picture(uvd_t *uvd) { - usb_ibmcam_adjust_contrast(ibmcam); - usb_ibmcam_set_brightness(ibmcam); - if (ibmcam->camera_model == IBMCAM_MODEL_2) { - usb_ibmcam_model2_set_hue(ibmcam); - } + ibmcam_adjust_contrast(uvd); + ibmcam_set_brightness(uvd); + ibmcam_set_hue(uvd); } -static int usb_ibmcam_model1_setup(struct usb_ibmcam *ibmcam) +static int ibmcam_model1_setup(uvd_t *uvd) { const int ntries = 5; int i; - usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0128); - usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0100); - usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0100); /* LED On */ - usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0100); - usb_ibmcam_veio(ibmcam, 0, 0x81, 0x0100); /* LED Off */ - usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0100); - usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0100); /* LED On */ - usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0108); - - usb_ibmcam_veio(ibmcam, 0, 0x03, 0x0112); - usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0115); - usb_ibmcam_veio(ibmcam, 0, 0x06, 0x0115); - usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0116); - usb_ibmcam_veio(ibmcam, 0, 0x44, 0x0116); - usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0116); - usb_ibmcam_veio(ibmcam, 0, 0x40, 0x0116); - usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0115); - usb_ibmcam_veio(ibmcam, 0, 0x0e, 0x0115); - usb_ibmcam_veio(ibmcam, 0, 0x19, 0x012c); - - usb_ibmcam_Packet_Format1(ibmcam, 0x00, 0x1e); - usb_ibmcam_Packet_Format1(ibmcam, 0x39, 0x0d); - usb_ibmcam_Packet_Format1(ibmcam, 0x39, 0x09); - usb_ibmcam_Packet_Format1(ibmcam, 0x3b, 0x00); - usb_ibmcam_Packet_Format1(ibmcam, 0x28, 0x22); - usb_ibmcam_Packet_Format1(ibmcam, light_27, 0); - usb_ibmcam_Packet_Format1(ibmcam, 0x2b, 0x1f); - usb_ibmcam_Packet_Format1(ibmcam, 0x39, 0x08); + ibmcam_veio(uvd, 1, 0x00, 0x0128); + ibmcam_veio(uvd, 1, 0x00, 0x0100); + ibmcam_veio(uvd, 0, 0x01, 0x0100); /* LED On */ + ibmcam_veio(uvd, 1, 0x00, 0x0100); + ibmcam_veio(uvd, 0, 0x81, 0x0100); /* LED Off */ + ibmcam_veio(uvd, 1, 0x00, 0x0100); + ibmcam_veio(uvd, 0, 0x01, 0x0100); /* LED On */ + ibmcam_veio(uvd, 0, 0x01, 0x0108); + + ibmcam_veio(uvd, 0, 0x03, 0x0112); + ibmcam_veio(uvd, 1, 0x00, 0x0115); + ibmcam_veio(uvd, 0, 0x06, 0x0115); + ibmcam_veio(uvd, 1, 0x00, 0x0116); + ibmcam_veio(uvd, 0, 0x44, 0x0116); + ibmcam_veio(uvd, 1, 0x00, 0x0116); + ibmcam_veio(uvd, 0, 0x40, 0x0116); + ibmcam_veio(uvd, 1, 0x00, 0x0115); + ibmcam_veio(uvd, 0, 0x0e, 0x0115); + ibmcam_veio(uvd, 0, 0x19, 0x012c); + + ibmcam_Packet_Format1(uvd, 0x00, 0x1e); + ibmcam_Packet_Format1(uvd, 0x39, 0x0d); + ibmcam_Packet_Format1(uvd, 0x39, 0x09); + ibmcam_Packet_Format1(uvd, 0x3b, 0x00); + ibmcam_Packet_Format1(uvd, 0x28, 0x22); + ibmcam_Packet_Format1(uvd, light_27, 0); + ibmcam_Packet_Format1(uvd, 0x2b, 0x1f); + ibmcam_Packet_Format1(uvd, 0x39, 0x08); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(ibmcam, 0x2c, 0x00); + ibmcam_Packet_Format1(uvd, 0x2c, 0x00); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(ibmcam, 0x30, 0x14); + ibmcam_Packet_Format1(uvd, 0x30, 0x14); - usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x02); - usb_ibmcam_PacketFormat2(ibmcam, 0x01, 0xe1); - usb_ibmcam_PacketFormat2(ibmcam, 0x02, 0xcd); - usb_ibmcam_PacketFormat2(ibmcam, 0x03, 0xcd); - usb_ibmcam_PacketFormat2(ibmcam, 0x04, 0xfa); - usb_ibmcam_PacketFormat2(ibmcam, 0x3f, 0xff); - usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x00); - - usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x02); - usb_ibmcam_PacketFormat2(ibmcam, 0x0a, 0x37); - usb_ibmcam_PacketFormat2(ibmcam, 0x0b, 0xb8); - usb_ibmcam_PacketFormat2(ibmcam, 0x0c, 0xf3); - usb_ibmcam_PacketFormat2(ibmcam, 0x0d, 0xe3); - usb_ibmcam_PacketFormat2(ibmcam, 0x0e, 0x0d); - usb_ibmcam_PacketFormat2(ibmcam, 0x0f, 0xf2); - usb_ibmcam_PacketFormat2(ibmcam, 0x10, 0xd5); - usb_ibmcam_PacketFormat2(ibmcam, 0x11, 0xba); - usb_ibmcam_PacketFormat2(ibmcam, 0x12, 0x53); - usb_ibmcam_PacketFormat2(ibmcam, 0x3f, 0xff); - usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x00); - - usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x02); - usb_ibmcam_PacketFormat2(ibmcam, 0x16, 0x00); - usb_ibmcam_PacketFormat2(ibmcam, 0x17, 0x28); - usb_ibmcam_PacketFormat2(ibmcam, 0x18, 0x7d); - usb_ibmcam_PacketFormat2(ibmcam, 0x19, 0xbe); - usb_ibmcam_PacketFormat2(ibmcam, 0x3f, 0xff); - usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x00); + ibmcam_PacketFormat2(uvd, 0x39, 0x02); + ibmcam_PacketFormat2(uvd, 0x01, 0xe1); + ibmcam_PacketFormat2(uvd, 0x02, 0xcd); + ibmcam_PacketFormat2(uvd, 0x03, 0xcd); + ibmcam_PacketFormat2(uvd, 0x04, 0xfa); + ibmcam_PacketFormat2(uvd, 0x3f, 0xff); + ibmcam_PacketFormat2(uvd, 0x39, 0x00); + + ibmcam_PacketFormat2(uvd, 0x39, 0x02); + ibmcam_PacketFormat2(uvd, 0x0a, 0x37); + ibmcam_PacketFormat2(uvd, 0x0b, 0xb8); + ibmcam_PacketFormat2(uvd, 0x0c, 0xf3); + ibmcam_PacketFormat2(uvd, 0x0d, 0xe3); + ibmcam_PacketFormat2(uvd, 0x0e, 0x0d); + ibmcam_PacketFormat2(uvd, 0x0f, 0xf2); + ibmcam_PacketFormat2(uvd, 0x10, 0xd5); + ibmcam_PacketFormat2(uvd, 0x11, 0xba); + ibmcam_PacketFormat2(uvd, 0x12, 0x53); + ibmcam_PacketFormat2(uvd, 0x3f, 0xff); + ibmcam_PacketFormat2(uvd, 0x39, 0x00); + + ibmcam_PacketFormat2(uvd, 0x39, 0x02); + ibmcam_PacketFormat2(uvd, 0x16, 0x00); + ibmcam_PacketFormat2(uvd, 0x17, 0x28); + ibmcam_PacketFormat2(uvd, 0x18, 0x7d); + ibmcam_PacketFormat2(uvd, 0x19, 0xbe); + ibmcam_PacketFormat2(uvd, 0x3f, 0xff); + ibmcam_PacketFormat2(uvd, 0x39, 0x00); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(ibmcam, 0x00, 0x18); + ibmcam_Packet_Format1(uvd, 0x00, 0x18); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(ibmcam, 0x13, 0x18); + ibmcam_Packet_Format1(uvd, 0x13, 0x18); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(ibmcam, 0x14, 0x06); + ibmcam_Packet_Format1(uvd, 0x14, 0x06); /* This is default brightness */ for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(ibmcam, 0x31, 0x37); + ibmcam_Packet_Format1(uvd, 0x31, 0x37); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(ibmcam, 0x32, 0x46); + ibmcam_Packet_Format1(uvd, 0x32, 0x46); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(ibmcam, 0x33, 0x55); + ibmcam_Packet_Format1(uvd, 0x33, 0x55); - usb_ibmcam_Packet_Format1(ibmcam, 0x2e, 0x04); + ibmcam_Packet_Format1(uvd, 0x2e, 0x04); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(ibmcam, 0x2d, 0x04); + ibmcam_Packet_Format1(uvd, 0x2d, 0x04); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(ibmcam, 0x29, 0x80); - usb_ibmcam_Packet_Format1(ibmcam, 0x2c, 0x01); - usb_ibmcam_Packet_Format1(ibmcam, 0x30, 0x17); - usb_ibmcam_Packet_Format1(ibmcam, 0x39, 0x08); + ibmcam_Packet_Format1(uvd, 0x29, 0x80); + ibmcam_Packet_Format1(uvd, 0x2c, 0x01); + ibmcam_Packet_Format1(uvd, 0x30, 0x17); + ibmcam_Packet_Format1(uvd, 0x39, 0x08); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(ibmcam, 0x34, 0x00); + ibmcam_Packet_Format1(uvd, 0x34, 0x00); - usb_ibmcam_veio(ibmcam, 0, 0x00, 0x0101); - usb_ibmcam_veio(ibmcam, 0, 0x00, 0x010a); + ibmcam_veio(uvd, 0, 0x00, 0x0101); + ibmcam_veio(uvd, 0, 0x00, 0x010a); - switch (videosize) { + switch (uvd->videosize) { case VIDEOSIZE_128x96: - usb_ibmcam_veio(ibmcam, 0, 0x80, 0x0103); - usb_ibmcam_veio(ibmcam, 0, 0x60, 0x0105); - usb_ibmcam_veio(ibmcam, 0, 0x0c, 0x010b); - usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011b); /* Same everywhere */ - usb_ibmcam_veio(ibmcam, 0, 0x0b, 0x011d); - usb_ibmcam_veio(ibmcam, 0, 0x00, 0x011e); /* Same everywhere */ - usb_ibmcam_veio(ibmcam, 0, 0x00, 0x0129); + ibmcam_veio(uvd, 0, 0x80, 0x0103); + ibmcam_veio(uvd, 0, 0x60, 0x0105); + ibmcam_veio(uvd, 0, 0x0c, 0x010b); + ibmcam_veio(uvd, 0, 0x04, 0x011b); /* Same everywhere */ + ibmcam_veio(uvd, 0, 0x0b, 0x011d); + ibmcam_veio(uvd, 0, 0x00, 0x011e); /* Same everywhere */ + ibmcam_veio(uvd, 0, 0x00, 0x0129); break; case VIDEOSIZE_176x144: - usb_ibmcam_veio(ibmcam, 0, 0xb0, 0x0103); - usb_ibmcam_veio(ibmcam, 0, 0x8f, 0x0105); - usb_ibmcam_veio(ibmcam, 0, 0x06, 0x010b); - usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011b); /* Same everywhere */ - usb_ibmcam_veio(ibmcam, 0, 0x0d, 0x011d); - usb_ibmcam_veio(ibmcam, 0, 0x00, 0x011e); /* Same everywhere */ - usb_ibmcam_veio(ibmcam, 0, 0x03, 0x0129); + ibmcam_veio(uvd, 0, 0xb0, 0x0103); + ibmcam_veio(uvd, 0, 0x8f, 0x0105); + ibmcam_veio(uvd, 0, 0x06, 0x010b); + ibmcam_veio(uvd, 0, 0x04, 0x011b); /* Same everywhere */ + ibmcam_veio(uvd, 0, 0x0d, 0x011d); + ibmcam_veio(uvd, 0, 0x00, 0x011e); /* Same everywhere */ + ibmcam_veio(uvd, 0, 0x03, 0x0129); break; case VIDEOSIZE_352x288: - usb_ibmcam_veio(ibmcam, 0, 0xb0, 0x0103); - usb_ibmcam_veio(ibmcam, 0, 0x90, 0x0105); - usb_ibmcam_veio(ibmcam, 0, 0x02, 0x010b); - usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011b); /* Same everywhere */ - usb_ibmcam_veio(ibmcam, 0, 0x05, 0x011d); - usb_ibmcam_veio(ibmcam, 0, 0x00, 0x011e); /* Same everywhere */ - usb_ibmcam_veio(ibmcam, 0, 0x00, 0x0129); + ibmcam_veio(uvd, 0, 0xb0, 0x0103); + ibmcam_veio(uvd, 0, 0x90, 0x0105); + ibmcam_veio(uvd, 0, 0x02, 0x010b); + ibmcam_veio(uvd, 0, 0x04, 0x011b); /* Same everywhere */ + ibmcam_veio(uvd, 0, 0x05, 0x011d); + ibmcam_veio(uvd, 0, 0x00, 0x011e); /* Same everywhere */ + ibmcam_veio(uvd, 0, 0x00, 0x0129); break; } - usb_ibmcam_veio(ibmcam, 0, 0xff, 0x012b); + ibmcam_veio(uvd, 0, 0xff, 0x012b); /* This is another brightness - don't know why */ for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(ibmcam, 0x31, 0xc3); + ibmcam_Packet_Format1(uvd, 0x31, 0xc3); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(ibmcam, 0x32, 0xd2); + ibmcam_Packet_Format1(uvd, 0x32, 0xd2); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(ibmcam, 0x33, 0xe1); + ibmcam_Packet_Format1(uvd, 0x33, 0xe1); /* Default contrast */ for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(ibmcam, contrast_14, 0x0a); + ibmcam_Packet_Format1(uvd, contrast_14, 0x0a); /* Default sharpness */ for (i=0; i < 2; i++) - usb_ibmcam_PacketFormat2(ibmcam, sharp_13, 0x1a); /* Level 4 FIXME */ + ibmcam_PacketFormat2(uvd, sharp_13, 0x1a); /* Level 4 FIXME */ /* Default lighting conditions */ - usb_ibmcam_Packet_Format1(ibmcam, light_27, lighting); /* 0=Bright 2=Low */ + ibmcam_Packet_Format1(uvd, light_27, lighting); /* 0=Bright 2=Low */ /* Assorted init */ - switch (videosize) { + switch (uvd->videosize) { case VIDEOSIZE_128x96: - usb_ibmcam_Packet_Format1(ibmcam, 0x2b, 0x1e); - usb_ibmcam_veio(ibmcam, 0, 0xc9, 0x0119); /* Same everywhere */ - usb_ibmcam_veio(ibmcam, 0, 0x80, 0x0109); /* Same everywhere */ - usb_ibmcam_veio(ibmcam, 0, 0x36, 0x0102); - usb_ibmcam_veio(ibmcam, 0, 0x1a, 0x0104); - usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011a); /* Same everywhere */ - usb_ibmcam_veio(ibmcam, 0, 0x2b, 0x011c); - usb_ibmcam_veio(ibmcam, 0, 0x23, 0x012a); /* Same everywhere */ + ibmcam_Packet_Format1(uvd, 0x2b, 0x1e); + ibmcam_veio(uvd, 0, 0xc9, 0x0119); /* Same everywhere */ + ibmcam_veio(uvd, 0, 0x80, 0x0109); /* Same everywhere */ + ibmcam_veio(uvd, 0, 0x36, 0x0102); + ibmcam_veio(uvd, 0, 0x1a, 0x0104); + ibmcam_veio(uvd, 0, 0x04, 0x011a); /* Same everywhere */ + ibmcam_veio(uvd, 0, 0x2b, 0x011c); + ibmcam_veio(uvd, 0, 0x23, 0x012a); /* Same everywhere */ #if 0 - usb_ibmcam_veio(ibmcam, 0, 0x00, 0x0106); - usb_ibmcam_veio(ibmcam, 0, 0x38, 0x0107); + ibmcam_veio(uvd, 0, 0x00, 0x0106); + ibmcam_veio(uvd, 0, 0x38, 0x0107); #else - usb_ibmcam_veio(ibmcam, 0, 0x02, 0x0106); - usb_ibmcam_veio(ibmcam, 0, 0x2a, 0x0107); + ibmcam_veio(uvd, 0, 0x02, 0x0106); + ibmcam_veio(uvd, 0, 0x2a, 0x0107); #endif break; case VIDEOSIZE_176x144: - usb_ibmcam_Packet_Format1(ibmcam, 0x2b, 0x1e); - usb_ibmcam_veio(ibmcam, 0, 0xc9, 0x0119); /* Same everywhere */ - usb_ibmcam_veio(ibmcam, 0, 0x80, 0x0109); /* Same everywhere */ - usb_ibmcam_veio(ibmcam, 0, 0x04, 0x0102); - usb_ibmcam_veio(ibmcam, 0, 0x02, 0x0104); - usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011a); /* Same everywhere */ - usb_ibmcam_veio(ibmcam, 0, 0x2b, 0x011c); - usb_ibmcam_veio(ibmcam, 0, 0x23, 0x012a); /* Same everywhere */ - usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0106); - usb_ibmcam_veio(ibmcam, 0, 0xca, 0x0107); + ibmcam_Packet_Format1(uvd, 0x2b, 0x1e); + ibmcam_veio(uvd, 0, 0xc9, 0x0119); /* Same everywhere */ + ibmcam_veio(uvd, 0, 0x80, 0x0109); /* Same everywhere */ + ibmcam_veio(uvd, 0, 0x04, 0x0102); + ibmcam_veio(uvd, 0, 0x02, 0x0104); + ibmcam_veio(uvd, 0, 0x04, 0x011a); /* Same everywhere */ + ibmcam_veio(uvd, 0, 0x2b, 0x011c); + ibmcam_veio(uvd, 0, 0x23, 0x012a); /* Same everywhere */ + ibmcam_veio(uvd, 0, 0x01, 0x0106); + ibmcam_veio(uvd, 0, 0xca, 0x0107); break; case VIDEOSIZE_352x288: - usb_ibmcam_Packet_Format1(ibmcam, 0x2b, 0x1f); - usb_ibmcam_veio(ibmcam, 0, 0xc9, 0x0119); /* Same everywhere */ - usb_ibmcam_veio(ibmcam, 0, 0x80, 0x0109); /* Same everywhere */ - usb_ibmcam_veio(ibmcam, 0, 0x08, 0x0102); - usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0104); - usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011a); /* Same everywhere */ - usb_ibmcam_veio(ibmcam, 0, 0x2f, 0x011c); - usb_ibmcam_veio(ibmcam, 0, 0x23, 0x012a); /* Same everywhere */ - usb_ibmcam_veio(ibmcam, 0, 0x03, 0x0106); - usb_ibmcam_veio(ibmcam, 0, 0xf6, 0x0107); - break; - } - return IBMCAM_IS_OPERATIONAL(ibmcam); -} - -static int usb_ibmcam_model2_setup(struct usb_ibmcam *ibmcam) -{ - usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0100); /* LED on */ - usb_ibmcam_veio(ibmcam, 1, 0x0000, 0x0116); - usb_ibmcam_veio(ibmcam, 0, 0x0060, 0x0116); - usb_ibmcam_veio(ibmcam, 0, 0x0002, 0x0112); - usb_ibmcam_veio(ibmcam, 0, 0x00bc, 0x012c); - usb_ibmcam_veio(ibmcam, 0, 0x0008, 0x012b); - usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0108); - usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0133); - usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0102); - switch (videosize) { + ibmcam_Packet_Format1(uvd, 0x2b, 0x1f); + ibmcam_veio(uvd, 0, 0xc9, 0x0119); /* Same everywhere */ + ibmcam_veio(uvd, 0, 0x80, 0x0109); /* Same everywhere */ + ibmcam_veio(uvd, 0, 0x08, 0x0102); + ibmcam_veio(uvd, 0, 0x01, 0x0104); + ibmcam_veio(uvd, 0, 0x04, 0x011a); /* Same everywhere */ + ibmcam_veio(uvd, 0, 0x2f, 0x011c); + ibmcam_veio(uvd, 0, 0x23, 0x012a); /* Same everywhere */ + ibmcam_veio(uvd, 0, 0x03, 0x0106); + ibmcam_veio(uvd, 0, 0xf6, 0x0107); + break; + } + return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT); +} + +static int ibmcam_model2_setup(uvd_t *uvd) +{ + ibmcam_veio(uvd, 0, 0x0000, 0x0100); /* LED on */ + ibmcam_veio(uvd, 1, 0x0000, 0x0116); + ibmcam_veio(uvd, 0, 0x0060, 0x0116); + ibmcam_veio(uvd, 0, 0x0002, 0x0112); + ibmcam_veio(uvd, 0, 0x00bc, 0x012c); + ibmcam_veio(uvd, 0, 0x0008, 0x012b); + ibmcam_veio(uvd, 0, 0x0000, 0x0108); + ibmcam_veio(uvd, 0, 0x0001, 0x0133); + ibmcam_veio(uvd, 0, 0x0001, 0x0102); + switch (uvd->videosize) { case VIDEOSIZE_176x144: - usb_ibmcam_veio(ibmcam, 0, 0x002c, 0x0103); /* All except 320x240 */ - usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0104); /* Same */ - usb_ibmcam_veio(ibmcam, 0, 0x0024, 0x0105); /* 176x144, 352x288 */ - usb_ibmcam_veio(ibmcam, 0, 0x00b9, 0x010a); /* Unique to this mode */ - usb_ibmcam_veio(ibmcam, 0, 0x0038, 0x0119); /* Unique to this mode */ - usb_ibmcam_veio(ibmcam, 0, 0x0003, 0x0106); /* Same */ - usb_ibmcam_veio(ibmcam, 0, 0x0090, 0x0107); /* Unique to every mode*/ + ibmcam_veio(uvd, 0, 0x002c, 0x0103); /* All except 320x240 */ + ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */ + ibmcam_veio(uvd, 0, 0x0024, 0x0105); /* 176x144, 352x288 */ + ibmcam_veio(uvd, 0, 0x00b9, 0x010a); /* Unique to this mode */ + ibmcam_veio(uvd, 0, 0x0038, 0x0119); /* Unique to this mode */ + ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */ + ibmcam_veio(uvd, 0, 0x0090, 0x0107); /* Unique to every mode*/ break; case VIDEOSIZE_320x240: - usb_ibmcam_veio(ibmcam, 0, 0x0028, 0x0103); /* Unique to this mode */ - usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0104); /* Same */ - usb_ibmcam_veio(ibmcam, 0, 0x001e, 0x0105); /* 320x240, 352x240 */ - usb_ibmcam_veio(ibmcam, 0, 0x0039, 0x010a); /* All except 176x144 */ - usb_ibmcam_veio(ibmcam, 0, 0x0070, 0x0119); /* All except 176x144 */ - usb_ibmcam_veio(ibmcam, 0, 0x0003, 0x0106); /* Same */ - usb_ibmcam_veio(ibmcam, 0, 0x0098, 0x0107); /* Unique to every mode*/ + ibmcam_veio(uvd, 0, 0x0028, 0x0103); /* Unique to this mode */ + ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */ + ibmcam_veio(uvd, 0, 0x001e, 0x0105); /* 320x240, 352x240 */ + ibmcam_veio(uvd, 0, 0x0039, 0x010a); /* All except 176x144 */ + ibmcam_veio(uvd, 0, 0x0070, 0x0119); /* All except 176x144 */ + ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */ + ibmcam_veio(uvd, 0, 0x0098, 0x0107); /* Unique to every mode*/ break; case VIDEOSIZE_352x240: - usb_ibmcam_veio(ibmcam, 0, 0x002c, 0x0103); /* All except 320x240 */ - usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0104); /* Same */ - usb_ibmcam_veio(ibmcam, 0, 0x001e, 0x0105); /* 320x240, 352x240 */ - usb_ibmcam_veio(ibmcam, 0, 0x0039, 0x010a); /* All except 176x144 */ - usb_ibmcam_veio(ibmcam, 0, 0x0070, 0x0119); /* All except 176x144 */ - usb_ibmcam_veio(ibmcam, 0, 0x0003, 0x0106); /* Same */ - usb_ibmcam_veio(ibmcam, 0, 0x00da, 0x0107); /* Unique to every mode*/ + ibmcam_veio(uvd, 0, 0x002c, 0x0103); /* All except 320x240 */ + ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */ + ibmcam_veio(uvd, 0, 0x001e, 0x0105); /* 320x240, 352x240 */ + ibmcam_veio(uvd, 0, 0x0039, 0x010a); /* All except 176x144 */ + ibmcam_veio(uvd, 0, 0x0070, 0x0119); /* All except 176x144 */ + ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */ + ibmcam_veio(uvd, 0, 0x00da, 0x0107); /* Unique to every mode*/ break; case VIDEOSIZE_352x288: - usb_ibmcam_veio(ibmcam, 0, 0x002c, 0x0103); /* All except 320x240 */ - usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0104); /* Same */ - usb_ibmcam_veio(ibmcam, 0, 0x0024, 0x0105); /* 176x144, 352x288 */ - usb_ibmcam_veio(ibmcam, 0, 0x0039, 0x010a); /* All except 176x144 */ - usb_ibmcam_veio(ibmcam, 0, 0x0070, 0x0119); /* All except 176x144 */ - usb_ibmcam_veio(ibmcam, 0, 0x0003, 0x0106); /* Same */ - usb_ibmcam_veio(ibmcam, 0, 0x00fe, 0x0107); /* Unique to every mode*/ + ibmcam_veio(uvd, 0, 0x002c, 0x0103); /* All except 320x240 */ + ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */ + ibmcam_veio(uvd, 0, 0x0024, 0x0105); /* 176x144, 352x288 */ + ibmcam_veio(uvd, 0, 0x0039, 0x010a); /* All except 176x144 */ + ibmcam_veio(uvd, 0, 0x0070, 0x0119); /* All except 176x144 */ + ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */ + ibmcam_veio(uvd, 0, 0x00fe, 0x0107); /* Unique to every mode*/ break; } - return IBMCAM_IS_OPERATIONAL(ibmcam); + return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT); } /* - * usb_ibmcam_model1_setup_after_video_if() + * ibmcam_model1_setup_after_video_if() * * This code adds finishing touches to the video data interface. * Here we configure the frame rate and turn on the LED. */ -static void usb_ibmcam_model1_setup_after_video_if(struct usb_ibmcam *ibmcam) +static void ibmcam_model1_setup_after_video_if(uvd_t *uvd) { unsigned short internal_frame_rate; RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX); internal_frame_rate = FRAMERATE_MAX - framerate; /* 0=Fast 6=Slow */ - usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0100); /* LED On */ - usb_ibmcam_veio(ibmcam, 0, internal_frame_rate, 0x0111); - usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0114); - usb_ibmcam_veio(ibmcam, 0, 0xc0, 0x010c); + ibmcam_veio(uvd, 0, 0x01, 0x0100); /* LED On */ + ibmcam_veio(uvd, 0, internal_frame_rate, 0x0111); + ibmcam_veio(uvd, 0, 0x01, 0x0114); + ibmcam_veio(uvd, 0, 0xc0, 0x010c); } -static void usb_ibmcam_model2_setup_after_video_if(struct usb_ibmcam *ibmcam) +static void ibmcam_model2_setup_after_video_if(uvd_t *uvd) { - unsigned short setup_model2_rg, setup_model2_rg2, setup_model2_sat, setup_model2_yb; + unsigned short setup_model2_rg2, setup_model2_sat, setup_model2_yb; - usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0100); /* LED on */ + ibmcam_veio(uvd, 0, 0x0000, 0x0100); /* LED on */ - switch (videosize) { + switch (uvd->videosize) { case VIDEOSIZE_176x144: - usb_ibmcam_veio(ibmcam, 0, 0x0050, 0x0111); - usb_ibmcam_veio(ibmcam, 0, 0x00d0, 0x0111); + ibmcam_veio(uvd, 0, 0x0050, 0x0111); + ibmcam_veio(uvd, 0, 0x00d0, 0x0111); break; case VIDEOSIZE_320x240: case VIDEOSIZE_352x240: case VIDEOSIZE_352x288: - usb_ibmcam_veio(ibmcam, 0, 0x0040, 0x0111); - usb_ibmcam_veio(ibmcam, 0, 0x00c0, 0x0111); + ibmcam_veio(uvd, 0, 0x0040, 0x0111); + ibmcam_veio(uvd, 0, 0x00c0, 0x0111); break; } - usb_ibmcam_veio(ibmcam, 0, 0x009b, 0x010f); - usb_ibmcam_veio(ibmcam, 0, 0x00bb, 0x010f); + ibmcam_veio(uvd, 0, 0x009b, 0x010f); + ibmcam_veio(uvd, 0, 0x00bb, 0x010f); /* * Hardware settings, may affect CMOS sensor; not user controls! @@ -1933,52 +2008,52 @@ * 0x002c: hardware setting (related to scan lines) * 0x002e: stops video stream, probably important h/w setting */ - usb_ibmcam_model2_Packet1(ibmcam, 0x000a, 0x005c); - usb_ibmcam_model2_Packet1(ibmcam, 0x0004, 0x0000); - usb_ibmcam_model2_Packet1(ibmcam, 0x0006, 0x00fb); - usb_ibmcam_model2_Packet1(ibmcam, 0x0008, 0x0000); - usb_ibmcam_model2_Packet1(ibmcam, 0x000c, 0x0009); - usb_ibmcam_model2_Packet1(ibmcam, 0x0012, 0x000a); - usb_ibmcam_model2_Packet1(ibmcam, 0x002a, 0x0000); - usb_ibmcam_model2_Packet1(ibmcam, 0x002c, 0x0000); - usb_ibmcam_model2_Packet1(ibmcam, 0x002e, 0x0008); + ibmcam_model2_Packet1(uvd, 0x000a, 0x005c); + ibmcam_model2_Packet1(uvd, 0x0004, 0x0000); + ibmcam_model2_Packet1(uvd, 0x0006, 0x00fb); + ibmcam_model2_Packet1(uvd, 0x0008, 0x0000); + ibmcam_model2_Packet1(uvd, 0x000c, 0x0009); + ibmcam_model2_Packet1(uvd, 0x0012, 0x000a); + ibmcam_model2_Packet1(uvd, 0x002a, 0x0000); + ibmcam_model2_Packet1(uvd, 0x002c, 0x0000); + ibmcam_model2_Packet1(uvd, 0x002e, 0x0008); /* * Function 0x0030 pops up all over the place. Apparently * it is a hardware control register, with every bit assigned to * do something. */ - usb_ibmcam_model2_Packet1(ibmcam, 0x0030, 0x0000); + ibmcam_model2_Packet1(uvd, 0x0030, 0x0000); /* * Magic control of CMOS sensor. Only lower values like * 0-3 work, and picture shifts left or right. Don't change. */ - switch (videosize) { + switch (uvd->videosize) { case VIDEOSIZE_176x144: - usb_ibmcam_model2_Packet1(ibmcam, 0x0014, 0x0002); - usb_ibmcam_model2_Packet1(ibmcam, 0x0016, 0x0002); /* Horizontal shift */ - usb_ibmcam_model2_Packet1(ibmcam, 0x0018, 0x004a); /* Another hardware setting */ + ibmcam_model2_Packet1(uvd, 0x0014, 0x0002); + ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */ + ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */ break; case VIDEOSIZE_320x240: - usb_ibmcam_model2_Packet1(ibmcam, 0x0014, 0x0009); - usb_ibmcam_model2_Packet1(ibmcam, 0x0016, 0x0005); /* Horizontal shift */ - usb_ibmcam_model2_Packet1(ibmcam, 0x0018, 0x0044); /* Another hardware setting */ + ibmcam_model2_Packet1(uvd, 0x0014, 0x0009); + ibmcam_model2_Packet1(uvd, 0x0016, 0x0005); /* Horizontal shift */ + ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Another hardware setting */ break; case VIDEOSIZE_352x240: /* This mode doesn't work as Windows programs it; changed to work */ - usb_ibmcam_model2_Packet1(ibmcam, 0x0014, 0x0009); /* Windows sets this to 8 */ - usb_ibmcam_model2_Packet1(ibmcam, 0x0016, 0x0003); /* Horizontal shift */ - usb_ibmcam_model2_Packet1(ibmcam, 0x0018, 0x0044); /* Windows sets this to 0x0045 */ + ibmcam_model2_Packet1(uvd, 0x0014, 0x0009); /* Windows sets this to 8 */ + ibmcam_model2_Packet1(uvd, 0x0016, 0x0003); /* Horizontal shift */ + ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Windows sets this to 0x0045 */ break; case VIDEOSIZE_352x288: - usb_ibmcam_model2_Packet1(ibmcam, 0x0014, 0x0003); - usb_ibmcam_model2_Packet1(ibmcam, 0x0016, 0x0002); /* Horizontal shift */ - usb_ibmcam_model2_Packet1(ibmcam, 0x0018, 0x004a); /* Another hardware setting */ + ibmcam_model2_Packet1(uvd, 0x0014, 0x0003); + ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */ + ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */ break; } - usb_ibmcam_model2_Packet1(ibmcam, mod2_brightness, 0x005a); + ibmcam_model2_Packet1(uvd, mod2_brightness, 0x005a); /* * We have our own frame rate setting varying from 0 (slowest) to 6 (fastest). @@ -2002,7 +2077,7 @@ RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX); i_framerate = FRAMERATE_MAX - framerate + FRAMERATE_MIN; - switch (videosize) { + switch (uvd->videosize) { case VIDEOSIZE_176x144: hw_fps = 6 + i_framerate*4; break; @@ -2016,10 +2091,10 @@ hw_fps = 28 + i_framerate/2; break; } - if (debug > 0) - printk(KERN_DEBUG "Framerate (hardware): %hd.\n", hw_fps); + if (uvd->debug > 0) + info("Framerate (hardware): %hd.", hw_fps); RESTRICT_TO_RANGE(hw_fps, 0, 31); - usb_ibmcam_model2_Packet1(ibmcam, mod2_set_framerate, hw_fps); + ibmcam_model2_Packet1(uvd, mod2_set_framerate, hw_fps); } /* @@ -2028,28 +2103,22 @@ * does not allow arbitrary values and apparently is a bit mask, to * be activated only at appropriate time. Don't change it randomly! */ - switch (videosize) { + switch (uvd->videosize) { case VIDEOSIZE_176x144: - usb_ibmcam_model2_Packet1(ibmcam, 0x0026, 0x00c2); + ibmcam_model2_Packet1(uvd, 0x0026, 0x00c2); break; case VIDEOSIZE_320x240: - usb_ibmcam_model2_Packet1(ibmcam, 0x0026, 0x0044); + ibmcam_model2_Packet1(uvd, 0x0026, 0x0044); break; case VIDEOSIZE_352x240: - usb_ibmcam_model2_Packet1(ibmcam, 0x0026, 0x0046); + ibmcam_model2_Packet1(uvd, 0x0026, 0x0046); break; case VIDEOSIZE_352x288: - usb_ibmcam_model2_Packet1(ibmcam, 0x0026, 0x0048); + ibmcam_model2_Packet1(uvd, 0x0026, 0x0048); break; } - usb_ibmcam_model2_Packet1(ibmcam, mod2_sensitivity, lighting); - - if (init_model2_rg >= 0) { - RESTRICT_TO_RANGE(init_model2_rg, 0, 255); - setup_model2_rg = init_model2_rg; - } else - setup_model2_rg = 0x0070; + ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting); if (init_model2_rg2 >= 0) { RESTRICT_TO_RANGE(init_model2_rg2, 0, 255); @@ -2069,801 +2138,1469 @@ } else setup_model2_yb = 0x00a0; - usb_ibmcam_model2_Packet1(ibmcam, mod2_color_balance_rg2, setup_model2_rg2); - usb_ibmcam_model2_Packet1(ibmcam, mod2_saturation, setup_model2_sat); - usb_ibmcam_model2_Packet1(ibmcam, mod2_color_balance_yb, setup_model2_yb); - usb_ibmcam_model2_Packet1(ibmcam, mod2_color_balance_rg, setup_model2_rg); + ibmcam_model2_Packet1(uvd, mod2_color_balance_rg2, setup_model2_rg2); + ibmcam_model2_Packet1(uvd, mod2_saturation, setup_model2_sat); + ibmcam_model2_Packet1(uvd, mod2_color_balance_yb, setup_model2_yb); + ibmcam_model2_Packet1(uvd, mod2_hue, uvd->vpic.hue >> 9); /* 0 .. 7F */; /* Hardware control command */ - usb_ibmcam_model2_Packet1(ibmcam, 0x0030, 0x0004); + ibmcam_model2_Packet1(uvd, 0x0030, 0x0004); - usb_ibmcam_veio(ibmcam, 0, 0x00c0, 0x010c); /* Go camera, go! */ - usb_clear_halt(ibmcam->dev, ibmcam->video_endp); + ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go camera, go! */ + usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); } -/* - * usb_ibmcam_setup_video_stop() - * - * This code tells camera to stop streaming. The interface remains - * configured and bandwidth - claimed. - */ -static void usb_ibmcam_setup_video_stop(struct usb_ibmcam *ibmcam) +static void ibmcam_model4_setup_after_video_if(uvd_t *uvd) { - if (ibmcam->camera_model == IBMCAM_MODEL_1) { - usb_ibmcam_veio(ibmcam, 0, 0x00, 0x010c); - usb_ibmcam_veio(ibmcam, 0, 0x00, 0x010c); - usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0114); - usb_ibmcam_veio(ibmcam, 0, 0xc0, 0x010c); - usb_ibmcam_veio(ibmcam, 0, 0x00, 0x010c); - usb_ibmcam_send_FF_04_02(ibmcam); - usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0100); - usb_ibmcam_veio(ibmcam, 0, 0x81, 0x0100); /* LED Off */ - } else if (ibmcam->camera_model == IBMCAM_MODEL_2) { - usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x010c); /* Stop the camera */ - - usb_ibmcam_model2_Packet1(ibmcam, 0x0030, 0x0004); - - usb_ibmcam_veio(ibmcam, 0, 0x0080, 0x0100); /* LED Off */ - usb_ibmcam_veio(ibmcam, 0, 0x0020, 0x0111); - usb_ibmcam_veio(ibmcam, 0, 0x00a0, 0x0111); - - usb_ibmcam_model2_Packet1(ibmcam, 0x0030, 0x0002); - - usb_ibmcam_veio(ibmcam, 0, 0x0020, 0x0111); - usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0112); - } -} - -/* - * usb_ibmcam_reinit_iso() - * - * This procedure sends couple of commands to the camera and then - * resets the video pipe. This sequence was observed to reinit the - * camera or, at least, to initiate ISO data stream. - * - * History: - * 1/2/00 Created. - */ -static void usb_ibmcam_reinit_iso(struct usb_ibmcam *ibmcam, int do_stop) -{ - if (ibmcam->camera_model == IBMCAM_MODEL_1) { - if (do_stop) - usb_ibmcam_setup_video_stop(ibmcam); - usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0114); - usb_ibmcam_veio(ibmcam, 0, 0x00c0, 0x010c); - usb_clear_halt(ibmcam->dev, ibmcam->video_endp); - usb_ibmcam_model1_setup_after_video_if(ibmcam); - } else if (ibmcam->camera_model == IBMCAM_MODEL_2) { - usb_ibmcam_model2_setup_after_video_if(ibmcam); + switch (uvd->videosize) { + case VIDEOSIZE_128x96: + ibmcam_veio(uvd, 0, 0x0000, 0x0100); + ibmcam_veio(uvd, 0, 0x00c0, 0x0111); + ibmcam_veio(uvd, 0, 0x00bc, 0x012c); + ibmcam_veio(uvd, 0, 0x0080, 0x012b); + ibmcam_veio(uvd, 0, 0x0000, 0x0108); + ibmcam_veio(uvd, 0, 0x0001, 0x0133); + ibmcam_veio(uvd, 0, 0x009b, 0x010f); + ibmcam_veio(uvd, 0, 0x00bb, 0x010f); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0038, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x000a, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x005c, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0004, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0x00fb, 0x012e); + ibmcam_veio(uvd, 0, 0x0000, 0x0130); + ibmcam_veio(uvd, 0, 0x8a28, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012f); + ibmcam_veio(uvd, 0, 0xd055, 0x0124); + ibmcam_veio(uvd, 0, 0x000c, 0x0127); + ibmcam_veio(uvd, 0, 0x0009, 0x012e); + ibmcam_veio(uvd, 0, 0xaa28, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0012, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0008, 0x0127); + ibmcam_veio(uvd, 0, 0x00aa, 0x0130); + ibmcam_veio(uvd, 0, 0x82a8, 0x0124); + ibmcam_veio(uvd, 0, 0x002a, 0x012d); + ibmcam_veio(uvd, 0, 0x0000, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0xfffa, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0034, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x0070, 0x0119); + ibmcam_veio(uvd, 0, 0x00d2, 0x0107); + ibmcam_veio(uvd, 0, 0x0003, 0x0106); + ibmcam_veio(uvd, 0, 0x005e, 0x0107); + ibmcam_veio(uvd, 0, 0x0003, 0x0106); + ibmcam_veio(uvd, 0, 0x00d0, 0x0111); + ibmcam_veio(uvd, 0, 0x0039, 0x010a); + ibmcam_veio(uvd, 0, 0x0001, 0x0102); + ibmcam_veio(uvd, 0, 0x0028, 0x0103); + ibmcam_veio(uvd, 0, 0x0000, 0x0104); + ibmcam_veio(uvd, 0, 0x001e, 0x0105); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0016, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x000a, 0x0127); + ibmcam_veio(uvd, 0, 0x00aa, 0x0130); + ibmcam_veio(uvd, 0, 0x82a8, 0x0124); + ibmcam_veio(uvd, 0, 0x0014, 0x012d); + ibmcam_veio(uvd, 0, 0x0008, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012e); + ibmcam_veio(uvd, 0, 0x001a, 0x0130); + ibmcam_veio(uvd, 0, 0x8a0a, 0x0124); + ibmcam_veio(uvd, 0, 0x005a, 0x012d); + ibmcam_veio(uvd, 0, 0x9545, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x0127); + ibmcam_veio(uvd, 0, 0x0018, 0x012e); + ibmcam_veio(uvd, 0, 0x0043, 0x0130); + ibmcam_veio(uvd, 0, 0x8a28, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012f); + ibmcam_veio(uvd, 0, 0xd055, 0x0124); + ibmcam_veio(uvd, 0, 0x001c, 0x0127); + ibmcam_veio(uvd, 0, 0x00eb, 0x012e); + ibmcam_veio(uvd, 0, 0xaa28, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0032, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0x00aa, 0x0130); + ibmcam_veio(uvd, 0, 0x82a8, 0x0124); + ibmcam_veio(uvd, 0, 0x0036, 0x012d); + ibmcam_veio(uvd, 0, 0x0008, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0xfffa, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x001e, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0017, 0x0127); + ibmcam_veio(uvd, 0, 0x0013, 0x012e); + ibmcam_veio(uvd, 0, 0x0031, 0x0130); + ibmcam_veio(uvd, 0, 0x8a28, 0x0124); + ibmcam_veio(uvd, 0, 0x0017, 0x012d); + ibmcam_veio(uvd, 0, 0x0078, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0038, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0004, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x00c0, 0x010c); + break; + case VIDEOSIZE_160x120: + ibmcam_veio(uvd, 0, 0x0000, 0x0100); + ibmcam_veio(uvd, 0, 0x00c0, 0x0111); + ibmcam_veio(uvd, 0, 0x00bc, 0x012c); + ibmcam_veio(uvd, 0, 0x0080, 0x012b); + ibmcam_veio(uvd, 0, 0x0000, 0x0108); + ibmcam_veio(uvd, 0, 0x0001, 0x0133); + ibmcam_veio(uvd, 0, 0x009b, 0x010f); + ibmcam_veio(uvd, 0, 0x00bb, 0x010f); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0038, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x000a, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x005c, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0004, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0x00fb, 0x012e); + ibmcam_veio(uvd, 0, 0x0000, 0x0130); + ibmcam_veio(uvd, 0, 0x8a28, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012f); + ibmcam_veio(uvd, 0, 0xd055, 0x0124); + ibmcam_veio(uvd, 0, 0x000c, 0x0127); + ibmcam_veio(uvd, 0, 0x0009, 0x012e); + ibmcam_veio(uvd, 0, 0xaa28, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0012, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0008, 0x0127); + ibmcam_veio(uvd, 0, 0x00aa, 0x0130); + ibmcam_veio(uvd, 0, 0x82a8, 0x0124); + ibmcam_veio(uvd, 0, 0x002a, 0x012d); + ibmcam_veio(uvd, 0, 0x0000, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0xfffa, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0034, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x0038, 0x0119); + ibmcam_veio(uvd, 0, 0x00d8, 0x0107); + ibmcam_veio(uvd, 0, 0x0002, 0x0106); + ibmcam_veio(uvd, 0, 0x00d0, 0x0111); + ibmcam_veio(uvd, 0, 0x00b9, 0x010a); + ibmcam_veio(uvd, 0, 0x0001, 0x0102); + ibmcam_veio(uvd, 0, 0x0028, 0x0103); + ibmcam_veio(uvd, 0, 0x0000, 0x0104); + ibmcam_veio(uvd, 0, 0x001e, 0x0105); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0016, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x000b, 0x0127); + ibmcam_veio(uvd, 0, 0x00aa, 0x0130); + ibmcam_veio(uvd, 0, 0x82a8, 0x0124); + ibmcam_veio(uvd, 0, 0x0014, 0x012d); + ibmcam_veio(uvd, 0, 0x0008, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012e); + ibmcam_veio(uvd, 0, 0x001a, 0x0130); + ibmcam_veio(uvd, 0, 0x8a0a, 0x0124); + ibmcam_veio(uvd, 0, 0x005a, 0x012d); + ibmcam_veio(uvd, 0, 0x9545, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x0127); + ibmcam_veio(uvd, 0, 0x0018, 0x012e); + ibmcam_veio(uvd, 0, 0x0043, 0x0130); + ibmcam_veio(uvd, 0, 0x8a28, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012f); + ibmcam_veio(uvd, 0, 0xd055, 0x0124); + ibmcam_veio(uvd, 0, 0x001c, 0x0127); + ibmcam_veio(uvd, 0, 0x00c7, 0x012e); + ibmcam_veio(uvd, 0, 0xaa28, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0032, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0025, 0x0127); + ibmcam_veio(uvd, 0, 0x00aa, 0x0130); + ibmcam_veio(uvd, 0, 0x82a8, 0x0124); + ibmcam_veio(uvd, 0, 0x0036, 0x012d); + ibmcam_veio(uvd, 0, 0x0008, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0xfffa, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x001e, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0048, 0x0127); + ibmcam_veio(uvd, 0, 0x0035, 0x012e); + ibmcam_veio(uvd, 0, 0x00d0, 0x0130); + ibmcam_veio(uvd, 0, 0x8a28, 0x0124); + ibmcam_veio(uvd, 0, 0x0048, 0x012d); + ibmcam_veio(uvd, 0, 0x0090, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0x0001, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0038, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0004, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x00c0, 0x010c); + break; + case VIDEOSIZE_176x144: + ibmcam_veio(uvd, 0, 0x0000, 0x0100); + ibmcam_veio(uvd, 0, 0x00c0, 0x0111); + ibmcam_veio(uvd, 0, 0x00bc, 0x012c); + ibmcam_veio(uvd, 0, 0x0080, 0x012b); + ibmcam_veio(uvd, 0, 0x0000, 0x0108); + ibmcam_veio(uvd, 0, 0x0001, 0x0133); + ibmcam_veio(uvd, 0, 0x009b, 0x010f); + ibmcam_veio(uvd, 0, 0x00bb, 0x010f); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0038, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x000a, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x005c, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0004, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0x00fb, 0x012e); + ibmcam_veio(uvd, 0, 0x0000, 0x0130); + ibmcam_veio(uvd, 0, 0x8a28, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012f); + ibmcam_veio(uvd, 0, 0xd055, 0x0124); + ibmcam_veio(uvd, 0, 0x000c, 0x0127); + ibmcam_veio(uvd, 0, 0x0009, 0x012e); + ibmcam_veio(uvd, 0, 0xaa28, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0012, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0008, 0x0127); + ibmcam_veio(uvd, 0, 0x00aa, 0x0130); + ibmcam_veio(uvd, 0, 0x82a8, 0x0124); + ibmcam_veio(uvd, 0, 0x002a, 0x012d); + ibmcam_veio(uvd, 0, 0x0000, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0xfffa, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0034, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x0038, 0x0119); + ibmcam_veio(uvd, 0, 0x00d6, 0x0107); + ibmcam_veio(uvd, 0, 0x0003, 0x0106); + ibmcam_veio(uvd, 0, 0x0018, 0x0107); + ibmcam_veio(uvd, 0, 0x0003, 0x0106); + ibmcam_veio(uvd, 0, 0x00d0, 0x0111); + ibmcam_veio(uvd, 0, 0x00b9, 0x010a); + ibmcam_veio(uvd, 0, 0x0001, 0x0102); + ibmcam_veio(uvd, 0, 0x002c, 0x0103); + ibmcam_veio(uvd, 0, 0x0000, 0x0104); + ibmcam_veio(uvd, 0, 0x0024, 0x0105); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0016, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0007, 0x0127); + ibmcam_veio(uvd, 0, 0x00aa, 0x0130); + ibmcam_veio(uvd, 0, 0x82a8, 0x0124); + ibmcam_veio(uvd, 0, 0x0014, 0x012d); + ibmcam_veio(uvd, 0, 0x0001, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012e); + ibmcam_veio(uvd, 0, 0x001a, 0x0130); + ibmcam_veio(uvd, 0, 0x8a0a, 0x0124); + ibmcam_veio(uvd, 0, 0x005e, 0x012d); + ibmcam_veio(uvd, 0, 0x9545, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x0127); + ibmcam_veio(uvd, 0, 0x0018, 0x012e); + ibmcam_veio(uvd, 0, 0x0049, 0x0130); + ibmcam_veio(uvd, 0, 0x8a28, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012f); + ibmcam_veio(uvd, 0, 0xd055, 0x0124); + ibmcam_veio(uvd, 0, 0x001c, 0x0127); + ibmcam_veio(uvd, 0, 0x00c7, 0x012e); + ibmcam_veio(uvd, 0, 0xaa28, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0032, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0028, 0x0127); + ibmcam_veio(uvd, 0, 0x00aa, 0x0130); + ibmcam_veio(uvd, 0, 0x82a8, 0x0124); + ibmcam_veio(uvd, 0, 0x0036, 0x012d); + ibmcam_veio(uvd, 0, 0x0008, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0xfffa, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x001e, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0010, 0x0127); + ibmcam_veio(uvd, 0, 0x0013, 0x012e); + ibmcam_veio(uvd, 0, 0x002a, 0x0130); + ibmcam_veio(uvd, 0, 0x8a28, 0x0124); + ibmcam_veio(uvd, 0, 0x0010, 0x012d); + ibmcam_veio(uvd, 0, 0x006d, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0x0001, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0038, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0004, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x00c0, 0x010c); + break; + case VIDEOSIZE_320x240: + ibmcam_veio(uvd, 0, 0x0000, 0x0100); + ibmcam_veio(uvd, 0, 0x00c0, 0x0111); + ibmcam_veio(uvd, 0, 0x00bc, 0x012c); + ibmcam_veio(uvd, 0, 0x0080, 0x012b); + ibmcam_veio(uvd, 0, 0x0000, 0x0108); + ibmcam_veio(uvd, 0, 0x0001, 0x0133); + ibmcam_veio(uvd, 0, 0x009b, 0x010f); + ibmcam_veio(uvd, 0, 0x00bb, 0x010f); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0038, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x000a, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x005c, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0004, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0x00fb, 0x012e); + ibmcam_veio(uvd, 0, 0x0000, 0x0130); + ibmcam_veio(uvd, 0, 0x8a28, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012f); + ibmcam_veio(uvd, 0, 0xd055, 0x0124); + ibmcam_veio(uvd, 0, 0x000c, 0x0127); + ibmcam_veio(uvd, 0, 0x0009, 0x012e); + ibmcam_veio(uvd, 0, 0xaa28, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0012, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0008, 0x0127); + ibmcam_veio(uvd, 0, 0x00aa, 0x0130); + ibmcam_veio(uvd, 0, 0x82a8, 0x0124); + ibmcam_veio(uvd, 0, 0x002a, 0x012d); + ibmcam_veio(uvd, 0, 0x0000, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0xfffa, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0034, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x0070, 0x0119); + ibmcam_veio(uvd, 0, 0x00d2, 0x0107); + ibmcam_veio(uvd, 0, 0x0003, 0x0106); + ibmcam_veio(uvd, 0, 0x005e, 0x0107); + ibmcam_veio(uvd, 0, 0x0003, 0x0106); + ibmcam_veio(uvd, 0, 0x00d0, 0x0111); + ibmcam_veio(uvd, 0, 0x0039, 0x010a); + ibmcam_veio(uvd, 0, 0x0001, 0x0102); + ibmcam_veio(uvd, 0, 0x0028, 0x0103); + ibmcam_veio(uvd, 0, 0x0000, 0x0104); + ibmcam_veio(uvd, 0, 0x001e, 0x0105); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0016, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x000a, 0x0127); + ibmcam_veio(uvd, 0, 0x00aa, 0x0130); + ibmcam_veio(uvd, 0, 0x82a8, 0x0124); + ibmcam_veio(uvd, 0, 0x0014, 0x012d); + ibmcam_veio(uvd, 0, 0x0008, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012e); + ibmcam_veio(uvd, 0, 0x001a, 0x0130); + ibmcam_veio(uvd, 0, 0x8a0a, 0x0124); + ibmcam_veio(uvd, 0, 0x005a, 0x012d); + ibmcam_veio(uvd, 0, 0x9545, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x0127); + ibmcam_veio(uvd, 0, 0x0018, 0x012e); + ibmcam_veio(uvd, 0, 0x0043, 0x0130); + ibmcam_veio(uvd, 0, 0x8a28, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012f); + ibmcam_veio(uvd, 0, 0xd055, 0x0124); + ibmcam_veio(uvd, 0, 0x001c, 0x0127); + ibmcam_veio(uvd, 0, 0x00eb, 0x012e); + ibmcam_veio(uvd, 0, 0xaa28, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0032, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0x00aa, 0x0130); + ibmcam_veio(uvd, 0, 0x82a8, 0x0124); + ibmcam_veio(uvd, 0, 0x0036, 0x012d); + ibmcam_veio(uvd, 0, 0x0008, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0xfffa, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x001e, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0017, 0x0127); + ibmcam_veio(uvd, 0, 0x0013, 0x012e); + ibmcam_veio(uvd, 0, 0x0031, 0x0130); + ibmcam_veio(uvd, 0, 0x8a28, 0x0124); + ibmcam_veio(uvd, 0, 0x0017, 0x012d); + ibmcam_veio(uvd, 0, 0x0078, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0038, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0004, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x00c0, 0x010c); + break; + case VIDEOSIZE_352x288: + ibmcam_veio(uvd, 0, 0x0000, 0x0100); + ibmcam_veio(uvd, 0, 0x00c0, 0x0111); + ibmcam_veio(uvd, 0, 0x00bc, 0x012c); + ibmcam_veio(uvd, 0, 0x0080, 0x012b); + ibmcam_veio(uvd, 0, 0x0000, 0x0108); + ibmcam_veio(uvd, 0, 0x0001, 0x0133); + ibmcam_veio(uvd, 0, 0x009b, 0x010f); + ibmcam_veio(uvd, 0, 0x00bb, 0x010f); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0038, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x000a, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x005c, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0004, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0x00fb, 0x012e); + ibmcam_veio(uvd, 0, 0x0000, 0x0130); + ibmcam_veio(uvd, 0, 0x8a28, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012f); + ibmcam_veio(uvd, 0, 0xd055, 0x0124); + ibmcam_veio(uvd, 0, 0x000c, 0x0127); + ibmcam_veio(uvd, 0, 0x0009, 0x012e); + ibmcam_veio(uvd, 0, 0xaa28, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0012, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0008, 0x0127); + ibmcam_veio(uvd, 0, 0x00aa, 0x0130); + ibmcam_veio(uvd, 0, 0x82a8, 0x0124); + ibmcam_veio(uvd, 0, 0x002a, 0x012d); + ibmcam_veio(uvd, 0, 0x0000, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0xfffa, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0034, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x0070, 0x0119); + ibmcam_veio(uvd, 0, 0x00f2, 0x0107); + ibmcam_veio(uvd, 0, 0x0003, 0x0106); + ibmcam_veio(uvd, 0, 0x008c, 0x0107); + ibmcam_veio(uvd, 0, 0x0003, 0x0106); + ibmcam_veio(uvd, 0, 0x00c0, 0x0111); + ibmcam_veio(uvd, 0, 0x0039, 0x010a); + ibmcam_veio(uvd, 0, 0x0001, 0x0102); + ibmcam_veio(uvd, 0, 0x002c, 0x0103); + ibmcam_veio(uvd, 0, 0x0000, 0x0104); + ibmcam_veio(uvd, 0, 0x0024, 0x0105); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0016, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0006, 0x0127); + ibmcam_veio(uvd, 0, 0x00aa, 0x0130); + ibmcam_veio(uvd, 0, 0x82a8, 0x0124); + ibmcam_veio(uvd, 0, 0x0014, 0x012d); + ibmcam_veio(uvd, 0, 0x0002, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012e); + ibmcam_veio(uvd, 0, 0x001a, 0x0130); + ibmcam_veio(uvd, 0, 0x8a0a, 0x0124); + ibmcam_veio(uvd, 0, 0x005e, 0x012d); + ibmcam_veio(uvd, 0, 0x9545, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x0127); + ibmcam_veio(uvd, 0, 0x0018, 0x012e); + ibmcam_veio(uvd, 0, 0x0049, 0x0130); + ibmcam_veio(uvd, 0, 0x8a28, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012f); + ibmcam_veio(uvd, 0, 0xd055, 0x0124); + ibmcam_veio(uvd, 0, 0x001c, 0x0127); + ibmcam_veio(uvd, 0, 0x00cf, 0x012e); + ibmcam_veio(uvd, 0, 0xaa28, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0032, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0x00aa, 0x0130); + ibmcam_veio(uvd, 0, 0x82a8, 0x0124); + ibmcam_veio(uvd, 0, 0x0036, 0x012d); + ibmcam_veio(uvd, 0, 0x0008, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0xfffa, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x001e, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0010, 0x0127); + ibmcam_veio(uvd, 0, 0x0013, 0x012e); + ibmcam_veio(uvd, 0, 0x0025, 0x0130); + ibmcam_veio(uvd, 0, 0x8a28, 0x0124); + ibmcam_veio(uvd, 0, 0x0010, 0x012d); + ibmcam_veio(uvd, 0, 0x0048, 0x012f); + ibmcam_veio(uvd, 0, 0xd145, 0x0124); + ibmcam_veio(uvd, 0, 0x0000, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x00aa, 0x012d); + ibmcam_veio(uvd, 0, 0x0038, 0x012f); + ibmcam_veio(uvd, 0, 0xd141, 0x0124); + ibmcam_veio(uvd, 0, 0x0004, 0x0127); + ibmcam_veio(uvd, 0, 0xfea8, 0x0124); + ibmcam_veio(uvd, 0, 0x00c0, 0x010c); + break; } + usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); } -/* - * ibmcam_init_isoc() - * - * History: - * 1/27/00 Used ibmcam->iface, ibmcam->ifaceAltActive instead of hardcoded values. - * Simplified by using for loop, allowed any number of URBs. - */ -static int ibmcam_init_isoc(struct usb_ibmcam *ibmcam) +static void ibmcam_model3_setup_after_video_if(uvd_t *uvd) { - struct usb_device *dev = ibmcam->dev; - int i, err; - - if (!IBMCAM_IS_OPERATIONAL(ibmcam)) - return -EFAULT; - - ibmcam->compress = 0; - ibmcam->curframe = -1; - ibmcam->cursbuf = 0; - ibmcam->scratchlen = 0; - - /* Alternate interface 1 is is the biggest frame size */ - i = usb_set_interface(dev, ibmcam->iface, ibmcam->ifaceAltActive); - if (i < 0) { - printk(KERN_ERR "usb_set_interface error\n"); - ibmcam->last_error = i; - return -EBUSY; - } - usb_ibmcam_change_lighting_conditions(ibmcam); - usb_ibmcam_set_sharpness(ibmcam); - usb_ibmcam_reinit_iso(ibmcam, 0); - - /* We double buffer the Iso lists */ - - for (i=0; i < IBMCAM_NUMSBUF; i++) { - int j, k; - urb_t *urb; - - urb = usb_alloc_urb(FRAMES_PER_DESC); - if (urb == NULL) { - printk(KERN_ERR "ibmcam_init_isoc: usb_init_isoc() failed.\n"); - return -ENOMEM; - } - ibmcam->sbuf[i].urb = urb; - urb->dev = dev; - urb->context = ibmcam; - urb->pipe = usb_rcvisocpipe(dev, ibmcam->video_endp); - urb->transfer_flags = USB_ISO_ASAP; - urb->transfer_buffer = ibmcam->sbuf[i].data; - urb->complete = ibmcam_isoc_irq; - urb->number_of_packets = FRAMES_PER_DESC; - urb->transfer_buffer_length = ibmcam->iso_packet_len * FRAMES_PER_DESC; - for (j=k=0; j < FRAMES_PER_DESC; j++, k += ibmcam->iso_packet_len) { - urb->iso_frame_desc[j].offset = k; - urb->iso_frame_desc[j].length = ibmcam->iso_packet_len; - } - } - - /* Link URBs into a ring so that they invoke each other infinitely */ - for (i=0; i < IBMCAM_NUMSBUF; i++) { - if ((i+1) < IBMCAM_NUMSBUF) - ibmcam->sbuf[i].urb->next = ibmcam->sbuf[i+1].urb; - else - ibmcam->sbuf[i].urb->next = ibmcam->sbuf[0].urb; - } - - /* Submit all URBs */ - for (i=0; i < IBMCAM_NUMSBUF; i++) { - err = usb_submit_urb(ibmcam->sbuf[i].urb); - if (err) - printk(KERN_ERR "ibmcam_init_isoc: usb_run_isoc(%d) ret %d\n", - i, err); - } + int i; + /* + * 01.01.08 - Added for RCA video in support -LO + * This struct is used to init the Model3 cam to use the RCA video in port + * instead of the CCD sensor. + */ + static const struct struct_initData initData[] = { + {0, 0x0000, 0x010c}, + {0, 0x0006, 0x012c}, + {0, 0x0078, 0x012d}, + {0, 0x0046, 0x012f}, + {0, 0xd141, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfea8, 0x0124}, + {1, 0x0000, 0x0116}, + {0, 0x0064, 0x0116}, + {1, 0x0000, 0x0115}, + {0, 0x0003, 0x0115}, + {0, 0x0008, 0x0123}, + {0, 0x0000, 0x0117}, + {0, 0x0000, 0x0112}, + {0, 0x0080, 0x0100}, + {0, 0x0000, 0x0100}, + {1, 0x0000, 0x0116}, + {0, 0x0060, 0x0116}, + {0, 0x0002, 0x0112}, + {0, 0x0000, 0x0123}, + {0, 0x0001, 0x0117}, + {0, 0x0040, 0x0108}, + {0, 0x0019, 0x012c}, + {0, 0x0040, 0x0116}, + {0, 0x000a, 0x0115}, + {0, 0x000b, 0x0115}, + {0, 0x0078, 0x012d}, + {0, 0x0046, 0x012f}, + {0, 0xd141, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfea8, 0x0124}, + {0, 0x0064, 0x0116}, + {0, 0x0000, 0x0115}, + {0, 0x0001, 0x0115}, + {0, 0xffff, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x00aa, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xffff, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x00f2, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x000f, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xffff, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x00f8, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x00fc, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xffff, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x00f9, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x003c, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xffff, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0027, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0019, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0021, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0006, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0045, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x002a, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x000e, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x002b, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x00f4, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x002c, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0004, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x002d, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0014, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x002e, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0003, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x002f, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0003, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0014, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0040, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0040, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0053, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0x0000, 0x0101}, + {0, 0x00a0, 0x0103}, + {0, 0x0078, 0x0105}, + {0, 0x0000, 0x010a}, + {0, 0x0024, 0x010b}, + {0, 0x0028, 0x0119}, + {0, 0x0088, 0x011b}, + {0, 0x0002, 0x011d}, + {0, 0x0003, 0x011e}, + {0, 0x0000, 0x0129}, + {0, 0x00fc, 0x012b}, + {0, 0x0008, 0x0102}, + {0, 0x0000, 0x0104}, + {0, 0x0008, 0x011a}, + {0, 0x0028, 0x011c}, + {0, 0x0021, 0x012a}, + {0, 0x0000, 0x0118}, + {0, 0x0000, 0x0132}, + {0, 0x0000, 0x0109}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0031, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0040, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0040, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x00dc, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0032, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0020, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0040, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0040, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0030, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0008, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0x0003, 0x0106}, + {0, 0x0062, 0x0107}, + {0, 0x0003, 0x0111}, + }; +#define NUM_INIT_DATA - ibmcam->streaming = 1; - /* printk(KERN_DEBUG "streaming=1 ibmcam->video_endp=$%02x\n", ibmcam->video_endp); */ - return 0; -} + unsigned short compression = 0; /* 0=none, 7=best frame rate */ + int f_rate; /* 0=Fastest 7=slowest */ -/* - * ibmcam_stop_isoc() - * - * This procedure stops streaming and deallocates URBs. Then it - * activates zero-bandwidth alt. setting of the video interface. - * - * History: - * 1/22/00 Corrected order of actions to work after surprise removal. - * 1/27/00 Used ibmcam->iface, ibmcam->ifaceAltInactive instead of hardcoded values. - */ -static void ibmcam_stop_isoc(struct usb_ibmcam *ibmcam) -{ - static const char proc[] = "ibmcam_stop_isoc"; - int i, j; - - if (!ibmcam->streaming || (ibmcam->dev == NULL)) + if (IBMCAM_T(uvd)->initialized) return; - /* Unschedule all of the iso td's */ - for (i=0; i < IBMCAM_NUMSBUF; i++) { - j = usb_unlink_urb(ibmcam->sbuf[i].urb); - if (j < 0) - printk(KERN_ERR "%s: usb_unlink_urb() error %d.\n", proc, j); - } - /* printk(KERN_DEBUG "streaming=0\n"); */ - ibmcam->streaming = 0; - - /* Delete them all */ - for (i=0; i < IBMCAM_NUMSBUF; i++) - usb_free_urb(ibmcam->sbuf[i].urb); - - if (!ibmcam->remove_pending) { - usb_ibmcam_setup_video_stop(ibmcam); - - /* Set packet size to 0 */ - j = usb_set_interface(ibmcam->dev, ibmcam->iface, ibmcam->ifaceAltInactive); - if (j < 0) { - printk(KERN_ERR "%s: usb_set_interface() error %d.\n", proc, j); - ibmcam->last_error = j; - } - } -} - -/* - * ibmcam_new_frame() - * - * History: - * 29-Mar-00 Added copying of previous frame into the current one. - */ -static int ibmcam_new_frame(struct usb_ibmcam *ibmcam, int framenum) -{ - struct ibmcam_frame *frame; - int n, width, height; - - /* If we're not grabbing a frame right now and the other frame is */ - /* ready to be grabbed into, then use it instead */ - if (ibmcam->curframe != -1) - return 0; - - n = (framenum - 1 + IBMCAM_NUMFRAMES) % IBMCAM_NUMFRAMES; - if (ibmcam->frame[n].grabstate == FRAME_READY) - framenum = n; - - frame = &ibmcam->frame[framenum]; - - frame->grabstate = FRAME_GRABBING; - frame->scanstate = STATE_SCANNING; - frame->scanlength = 0; /* Accumulated in ibmcam_parse_data() */ - ibmcam->curframe = framenum; - - /* - * Normally we would want to copy previous frame into the current one - * before we even start filling it with data; this allows us to stop - * filling at any moment; top portion of the frame will be new and - * bottom portion will stay as it was in previous frame. If we don't - * do that then missing chunks of video stream will result in flickering - * portions of old data whatever it was before. - * - * If we choose not to copy previous frame (to, for example, save few - * bus cycles - the frame can be pretty large!) then we have an option - * to clear the frame before using. If we experience losses in this - * mode then missing picture will be black (no flickering). - * - * Finally, if user chooses not to clean the current frame before - * filling it with data then the old data will be visible if we fail - * to refill entire frame with new data. - */ - if (!(flags & FLAGS_SEPARATE_FRAMES)) { - /* This copies previous frame into this one to mask losses */ - memmove(frame->data, ibmcam->frame[1-framenum].data, MAX_FRAME_SIZE); - } else { - if (flags & FLAGS_CLEAN_FRAMES) { - /* This provides a "clean" frame but slows things down */ - memset(frame->data, 0, MAX_FRAME_SIZE); - } - } - switch (videosize) { - case VIDEOSIZE_128x96: - frame->frmwidth = 128; - frame->frmheight = 96; - frame->order_uv = 1; /* U Y V Y ... */ - frame->hdr_sig = 0x06; /* 00 FF 00 06 */ + /* Internal frame rate is controlled by f_rate value */ + f_rate = 7 - framerate; + RESTRICT_TO_RANGE(f_rate, 0, 7); + + ibmcam_veio(uvd, 0, 0x0000, 0x0100); + ibmcam_veio(uvd, 1, 0x0000, 0x0116); + ibmcam_veio(uvd, 0, 0x0060, 0x0116); + ibmcam_veio(uvd, 0, 0x0002, 0x0112); + ibmcam_veio(uvd, 0, 0x0000, 0x0123); + ibmcam_veio(uvd, 0, 0x0001, 0x0117); + ibmcam_veio(uvd, 0, 0x0040, 0x0108); + ibmcam_veio(uvd, 0, 0x0019, 0x012c); + ibmcam_veio(uvd, 0, 0x0060, 0x0116); + ibmcam_veio(uvd, 0, 0x0002, 0x0115); + ibmcam_veio(uvd, 0, 0x0003, 0x0115); + ibmcam_veio(uvd, 1, 0x0000, 0x0115); + ibmcam_veio(uvd, 0, 0x000b, 0x0115); + ibmcam_model3_Packet1(uvd, 0x000a, 0x0040); + ibmcam_model3_Packet1(uvd, 0x000b, 0x00f6); + ibmcam_model3_Packet1(uvd, 0x000c, 0x0002); + ibmcam_model3_Packet1(uvd, 0x000d, 0x0020); + ibmcam_model3_Packet1(uvd, 0x000e, 0x0033); + ibmcam_model3_Packet1(uvd, 0x000f, 0x0007); + ibmcam_model3_Packet1(uvd, 0x0010, 0x0000); + ibmcam_model3_Packet1(uvd, 0x0011, 0x0070); + ibmcam_model3_Packet1(uvd, 0x0012, 0x0030); + ibmcam_model3_Packet1(uvd, 0x0013, 0x0000); + ibmcam_model3_Packet1(uvd, 0x0014, 0x0001); + ibmcam_model3_Packet1(uvd, 0x0015, 0x0001); + ibmcam_model3_Packet1(uvd, 0x0016, 0x0001); + ibmcam_model3_Packet1(uvd, 0x0017, 0x0001); + ibmcam_model3_Packet1(uvd, 0x0018, 0x0000); + ibmcam_model3_Packet1(uvd, 0x001e, 0x00c3); + ibmcam_model3_Packet1(uvd, 0x0020, 0x0000); + ibmcam_model3_Packet1(uvd, 0x0028, 0x0010); + ibmcam_model3_Packet1(uvd, 0x0029, 0x0054); + ibmcam_model3_Packet1(uvd, 0x002a, 0x0013); + ibmcam_model3_Packet1(uvd, 0x002b, 0x0007); + ibmcam_model3_Packet1(uvd, 0x002d, 0x0028); + ibmcam_model3_Packet1(uvd, 0x002e, 0x0000); + ibmcam_model3_Packet1(uvd, 0x0031, 0x0000); + ibmcam_model3_Packet1(uvd, 0x0032, 0x0000); + ibmcam_model3_Packet1(uvd, 0x0033, 0x0000); + ibmcam_model3_Packet1(uvd, 0x0034, 0x0000); + ibmcam_model3_Packet1(uvd, 0x0035, 0x0038); + ibmcam_model3_Packet1(uvd, 0x003a, 0x0001); + ibmcam_model3_Packet1(uvd, 0x003c, 0x001e); + ibmcam_model3_Packet1(uvd, 0x003f, 0x000a); + ibmcam_model3_Packet1(uvd, 0x0041, 0x0000); + ibmcam_model3_Packet1(uvd, 0x0046, 0x003f); + ibmcam_model3_Packet1(uvd, 0x0047, 0x0000); + ibmcam_model3_Packet1(uvd, 0x0050, 0x0005); + ibmcam_model3_Packet1(uvd, 0x0052, 0x001a); + ibmcam_model3_Packet1(uvd, 0x0053, 0x0003); + ibmcam_model3_Packet1(uvd, 0x005a, 0x006b); + ibmcam_model3_Packet1(uvd, 0x005d, 0x001e); + ibmcam_model3_Packet1(uvd, 0x005e, 0x0030); + ibmcam_model3_Packet1(uvd, 0x005f, 0x0041); + ibmcam_model3_Packet1(uvd, 0x0064, 0x0008); + ibmcam_model3_Packet1(uvd, 0x0065, 0x0015); + ibmcam_model3_Packet1(uvd, 0x0068, 0x000f); + ibmcam_model3_Packet1(uvd, 0x0079, 0x0000); + ibmcam_model3_Packet1(uvd, 0x007a, 0x0000); + ibmcam_model3_Packet1(uvd, 0x007c, 0x003f); + ibmcam_model3_Packet1(uvd, 0x0082, 0x000f); + ibmcam_model3_Packet1(uvd, 0x0085, 0x0000); + ibmcam_model3_Packet1(uvd, 0x0099, 0x0000); + ibmcam_model3_Packet1(uvd, 0x009b, 0x0023); + ibmcam_model3_Packet1(uvd, 0x009c, 0x0022); + ibmcam_model3_Packet1(uvd, 0x009d, 0x0096); + ibmcam_model3_Packet1(uvd, 0x009e, 0x0096); + ibmcam_model3_Packet1(uvd, 0x009f, 0x000a); + + switch (uvd->videosize) { + case VIDEOSIZE_160x120: + ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */ + ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */ + ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */ + ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */ + ibmcam_veio(uvd, 0, 0x0024, 0x010b); /* Differs everywhere */ + ibmcam_veio(uvd, 0, 0x00a9, 0x0119); + ibmcam_veio(uvd, 0, 0x0016, 0x011b); + ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same on 176x144, 320x240 */ + ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */ + ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */ + ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */ + ibmcam_veio(uvd, 0, 0x0018, 0x0102); + ibmcam_veio(uvd, 0, 0x0004, 0x0104); + ibmcam_veio(uvd, 0, 0x0004, 0x011a); + ibmcam_veio(uvd, 0, 0x0028, 0x011c); + ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */ + ibmcam_veio(uvd, 0, 0x0000, 0x0118); + ibmcam_veio(uvd, 0, 0x0000, 0x0132); + ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */ + ibmcam_veio(uvd, 0, compression, 0x0109); break; - case VIDEOSIZE_176x144: - frame->frmwidth = 176; - frame->frmheight = 144; - frame->order_uv = 1; /* U Y V Y ... */ - frame->hdr_sig = 0x0E; /* 00 FF 00 0E */ - break; - case VIDEOSIZE_320x240: /* For model 2 only */ - frame->frmwidth = 320; - frame->frmheight = 240; - break; - case VIDEOSIZE_352x240: /* For model 2 only */ - frame->frmwidth = 352; - frame->frmheight = 240; + case VIDEOSIZE_320x240: + ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */ + ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */ + ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */ + ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */ + ibmcam_veio(uvd, 0, 0x0028, 0x010b); /* Differs everywhere */ + ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same */ + ibmcam_veio(uvd, 0, 0x0000, 0x011e); + ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */ + ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */ + /* 4 commands from 160x120 skipped */ + ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */ + ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */ + ibmcam_veio(uvd, 0, compression, 0x0109); + ibmcam_veio(uvd, 0, 0x00d9, 0x0119); + ibmcam_veio(uvd, 0, 0x0006, 0x011b); + ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */ + ibmcam_veio(uvd, 0, 0x0010, 0x0104); + ibmcam_veio(uvd, 0, 0x0004, 0x011a); + ibmcam_veio(uvd, 0, 0x003f, 0x011c); + ibmcam_veio(uvd, 0, 0x001c, 0x0118); + ibmcam_veio(uvd, 0, 0x0000, 0x0132); + break; + case VIDEOSIZE_640x480: + ibmcam_veio(uvd, 0, 0x00f0, 0x0105); + ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */ + ibmcam_veio(uvd, 0, 0x0038, 0x010b); /* Differs everywhere */ + ibmcam_veio(uvd, 0, 0x00d9, 0x0119); /* Same on 320x240, 640x480 */ + ibmcam_veio(uvd, 0, 0x0006, 0x011b); /* Same on 320x240, 640x480 */ + ibmcam_veio(uvd, 0, 0x0004, 0x011d); /* NC */ + ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */ + ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */ + ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */ + ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */ + ibmcam_veio(uvd, 0, 0x0016, 0x0104); /* NC */ + ibmcam_veio(uvd, 0, 0x0004, 0x011a); /* Same on 320x240, 640x480 */ + ibmcam_veio(uvd, 0, 0x003f, 0x011c); /* Same on 320x240, 640x480 */ + ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */ + ibmcam_veio(uvd, 0, 0x001c, 0x0118); /* Same on 320x240, 640x480 */ + ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */ + ibmcam_veio(uvd, 0, compression, 0x0109); + ibmcam_veio(uvd, 0, 0x0040, 0x0101); + ibmcam_veio(uvd, 0, 0x0040, 0x0103); + ibmcam_veio(uvd, 0, 0x0000, 0x0132); /* Same on 320x240, 640x480 */ + break; + } + ibmcam_model3_Packet1(uvd, 0x007e, 0x000e); /* Hue */ + ibmcam_model3_Packet1(uvd, 0x0036, 0x0011); /* Brightness */ + ibmcam_model3_Packet1(uvd, 0x0060, 0x0002); /* Sharpness */ + ibmcam_model3_Packet1(uvd, 0x0061, 0x0004); /* Sharpness */ + ibmcam_model3_Packet1(uvd, 0x0062, 0x0005); /* Sharpness */ + ibmcam_model3_Packet1(uvd, 0x0063, 0x0014); /* Sharpness */ + ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0); /* Red gain */ + ibmcam_model3_Packet1(uvd, 0x0097, 0x0096); /* Blue gain */ + ibmcam_model3_Packet1(uvd, 0x0067, 0x0001); /* Contrast */ + ibmcam_model3_Packet1(uvd, 0x005b, 0x000c); /* Contrast */ + ibmcam_model3_Packet1(uvd, 0x005c, 0x0016); /* Contrast */ + ibmcam_model3_Packet1(uvd, 0x0098, 0x000b); + ibmcam_model3_Packet1(uvd, 0x002c, 0x0003); /* Was 1, broke 640x480 */ + ibmcam_model3_Packet1(uvd, 0x002f, 0x002a); + ibmcam_model3_Packet1(uvd, 0x0030, 0x0029); + ibmcam_model3_Packet1(uvd, 0x0037, 0x0002); + ibmcam_model3_Packet1(uvd, 0x0038, 0x0059); + ibmcam_model3_Packet1(uvd, 0x003d, 0x002e); + ibmcam_model3_Packet1(uvd, 0x003e, 0x0028); + ibmcam_model3_Packet1(uvd, 0x0078, 0x0005); + ibmcam_model3_Packet1(uvd, 0x007b, 0x0011); + ibmcam_model3_Packet1(uvd, 0x007d, 0x004b); + ibmcam_model3_Packet1(uvd, 0x007f, 0x0022); + ibmcam_model3_Packet1(uvd, 0x0080, 0x000c); + ibmcam_model3_Packet1(uvd, 0x0081, 0x000b); + ibmcam_model3_Packet1(uvd, 0x0083, 0x00fd); + ibmcam_model3_Packet1(uvd, 0x0086, 0x000b); + ibmcam_model3_Packet1(uvd, 0x0087, 0x000b); + ibmcam_model3_Packet1(uvd, 0x007e, 0x000e); + ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0); /* Red gain */ + ibmcam_model3_Packet1(uvd, 0x0097, 0x0096); /* Blue gain */ + ibmcam_model3_Packet1(uvd, 0x0098, 0x000b); + + switch (uvd->videosize) { + case VIDEOSIZE_160x120: + ibmcam_veio(uvd, 0, 0x0002, 0x0106); + ibmcam_veio(uvd, 0, 0x0008, 0x0107); + ibmcam_veio(uvd, 0, f_rate, 0x0111); /* Frame rate */ + ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */ + ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */ + ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */ + ibmcam_model3_Packet1(uvd, 0x0040, 0x000a); + ibmcam_model3_Packet1(uvd, 0x0051, 0x000a); break; - case VIDEOSIZE_352x288: - frame->frmwidth = 352; - frame->frmheight = 288; - frame->order_uv = 0; /* V Y U Y ... */ - frame->hdr_sig = 0x00; /* 00 FF 00 00 */ + case VIDEOSIZE_320x240: + ibmcam_veio(uvd, 0, 0x0003, 0x0106); + ibmcam_veio(uvd, 0, 0x0062, 0x0107); + ibmcam_veio(uvd, 0, f_rate, 0x0111); /* Frame rate */ + ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */ + ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */ + ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */ + ibmcam_model3_Packet1(uvd, 0x0040, 0x0008); + ibmcam_model3_Packet1(uvd, 0x0051, 0x000b); + break; + case VIDEOSIZE_640x480: + ibmcam_veio(uvd, 0, 0x0002, 0x0106); /* Adjustments */ + ibmcam_veio(uvd, 0, 0x00b4, 0x0107); /* Adjustments */ + ibmcam_veio(uvd, 0, f_rate, 0x0111); /* Frame rate */ + ibmcam_model3_Packet1(uvd, 0x001f, 0x0002); /* !Same */ + ibmcam_model3_Packet1(uvd, 0x0039, 0x003e); /* !Same */ + ibmcam_model3_Packet1(uvd, 0x0040, 0x0008); + ibmcam_model3_Packet1(uvd, 0x0051, 0x000a); break; } - frame->order_yc = (ibmcam->camera_model == IBMCAM_MODEL_2); - - width = frame->width; - RESTRICT_TO_RANGE(width, min_imgwidth, imgwidth); - width &= ~7; /* Multiple of 8 */ - height = frame->height; - RESTRICT_TO_RANGE(height, min_imgheight, imgheight); - height &= ~3; /* Multiple of 4 */ - - return 0; -} - -/* - * ibmcam_open() - * - * This is part of Video 4 Linux API. The driver can be opened by one - * client only (checks internal counter 'ibmcam->user'). The procedure - * then allocates buffers needed for video processing. - * - * History: - * 1/22/00 Rewrote, moved scratch buffer allocation here. Now the - * camera is also initialized here (once per connect), at - * expense of V4L client (it waits on open() call). - * 1/27/00 Used IBMCAM_NUMSBUF as number of URB buffers. - * 5/24/00 Corrected to prevent race condition (MOD_xxx_USE_COUNT). - */ -static int ibmcam_open(struct video_device *dev, int flags) -{ - struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev; - const int sb_size = FRAMES_PER_DESC * ibmcam->iso_packet_len; - int i, err = 0; - - MOD_INC_USE_COUNT; - down(&ibmcam->lock); - - if (ibmcam->user) - err = -EBUSY; - else { - /* Clean pointers so we know if we allocated something */ - for (i=0; i < IBMCAM_NUMSBUF; i++) - ibmcam->sbuf[i].data = NULL; - - /* Allocate memory for the frame buffers */ - ibmcam->fbuf_size = IBMCAM_NUMFRAMES * MAX_FRAME_SIZE; - ibmcam->fbuf = rvmalloc(ibmcam->fbuf_size); - ibmcam->scratch = kmalloc(scratchbufsize, GFP_KERNEL); - ibmcam->scratchlen = 0; - if ((ibmcam->fbuf == NULL) || (ibmcam->scratch == NULL)) - err = -ENOMEM; - else { - /* Allocate all buffers */ - for (i=0; i < IBMCAM_NUMFRAMES; i++) { - ibmcam->frame[i].grabstate = FRAME_UNUSED; - ibmcam->frame[i].data = ibmcam->fbuf + i*MAX_FRAME_SIZE; - /* - * Set default sizes in case IOCTL (VIDIOCMCAPTURE) - * is not used (using read() instead). - */ - ibmcam->frame[i].width = imgwidth; - ibmcam->frame[i].height = imgheight; - ibmcam->frame[i].bytes_read = 0; - } - for (i=0; i < IBMCAM_NUMSBUF; i++) { - ibmcam->sbuf[i].data = kmalloc(sb_size, GFP_KERNEL); - if (ibmcam->sbuf[i].data == NULL) { - err = -ENOMEM; - break; - } - } - } - if (err) { - /* Have to free all that memory */ - if (ibmcam->fbuf != NULL) { - rvfree(ibmcam->fbuf, ibmcam->fbuf_size); - ibmcam->fbuf = NULL; - } - if (ibmcam->scratch != NULL) { - kfree(ibmcam->scratch); - ibmcam->scratch = NULL; - } - for (i=0; i < IBMCAM_NUMSBUF; i++) { - if (ibmcam->sbuf[i].data != NULL) { - kfree (ibmcam->sbuf[i].data); - ibmcam->sbuf[i].data = NULL; - } - } + /* 01.01.08 - Added for RCA video in support -LO */ + if(init_model3_input) { + if (debug > 0) + info("Setting input to RCA."); + for (i=0; i < (sizeof(initData)/sizeof(initData[0])); i++) { + ibmcam_veio(uvd, initData[i].req, initData[i].value, initData[i].index); } } - /* If so far no errors then we shall start the camera */ - if (!err) { - err = ibmcam_init_isoc(ibmcam); - if (!err) { - /* Send init sequence only once, it's large! */ - if (!ibmcam->initialized) { - int setup_ok = 0; - if (ibmcam->camera_model == IBMCAM_MODEL_1) - setup_ok = usb_ibmcam_model1_setup(ibmcam); - else if (ibmcam->camera_model == IBMCAM_MODEL_2) - setup_ok = usb_ibmcam_model2_setup(ibmcam); - if (setup_ok) - ibmcam->initialized = 1; - else - err = -EBUSY; - } - if (!err) - ibmcam->user++; - } - } - up(&ibmcam->lock); - if (err) - MOD_DEC_USE_COUNT; - return err; + ibmcam_veio(uvd, 0, 0x0001, 0x0114); + ibmcam_veio(uvd, 0, 0x00c0, 0x010c); + usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); } /* - * ibmcam_close() - * - * This is part of Video 4 Linux API. The procedure - * stops streaming and deallocates all buffers that were earlier - * allocated in ibmcam_open(). + * ibmcam_video_stop() * - * History: - * 1/22/00 Moved scratch buffer deallocation here. - * 1/27/00 Used IBMCAM_NUMSBUF as number of URB buffers. - * 5/24/00 Moved MOD_DEC_USE_COUNT outside of code that can sleep. + * This code tells camera to stop streaming. The interface remains + * configured and bandwidth - claimed. */ -static void ibmcam_close(struct video_device *dev) +static void ibmcam_video_stop(uvd_t *uvd) { - struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev; - int i; - - down(&ibmcam->lock); + switch (IBMCAM_T(uvd)->camera_model) { + case IBMCAM_MODEL_1: + ibmcam_veio(uvd, 0, 0x00, 0x010c); + ibmcam_veio(uvd, 0, 0x00, 0x010c); + ibmcam_veio(uvd, 0, 0x01, 0x0114); + ibmcam_veio(uvd, 0, 0xc0, 0x010c); + ibmcam_veio(uvd, 0, 0x00, 0x010c); + ibmcam_send_FF_04_02(uvd); + ibmcam_veio(uvd, 1, 0x00, 0x0100); + ibmcam_veio(uvd, 0, 0x81, 0x0100); /* LED Off */ + break; + case IBMCAM_MODEL_2: +case IBMCAM_MODEL_4: + ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop the camera */ + + ibmcam_model2_Packet1(uvd, 0x0030, 0x0004); + + ibmcam_veio(uvd, 0, 0x0080, 0x0100); /* LED Off */ + ibmcam_veio(uvd, 0, 0x0020, 0x0111); + ibmcam_veio(uvd, 0, 0x00a0, 0x0111); - ibmcam_stop_isoc(ibmcam); + ibmcam_model2_Packet1(uvd, 0x0030, 0x0002); - rvfree(ibmcam->fbuf, ibmcam->fbuf_size); - kfree(ibmcam->scratch); - for (i=0; i < IBMCAM_NUMSBUF; i++) - kfree(ibmcam->sbuf[i].data); + ibmcam_veio(uvd, 0, 0x0020, 0x0111); + ibmcam_veio(uvd, 0, 0x0000, 0x0112); + break; + case IBMCAM_MODEL_3: +#if 1 + ibmcam_veio(uvd, 0, 0x0000, 0x010c); - ibmcam->user--; + /* Here we are supposed to select video interface alt. setting 0 */ + ibmcam_veio(uvd, 0, 0x0006, 0x012c); - if (ibmcam->remove_pending) { - printk(KERN_INFO "ibmcam_close: Final disconnect.\n"); - usb_ibmcam_release(ibmcam); - } - up(&ibmcam->lock); - MOD_DEC_USE_COUNT; -} + ibmcam_model3_Packet1(uvd, 0x0046, 0x0000); -static long ibmcam_write(struct video_device *dev, const char *buf, unsigned long count, int noblock) -{ - return -EINVAL; + ibmcam_veio(uvd, 1, 0x0000, 0x0116); + ibmcam_veio(uvd, 0, 0x0064, 0x0116); + ibmcam_veio(uvd, 1, 0x0000, 0x0115); + ibmcam_veio(uvd, 0, 0x0003, 0x0115); + ibmcam_veio(uvd, 0, 0x0008, 0x0123); + ibmcam_veio(uvd, 0, 0x0000, 0x0117); + ibmcam_veio(uvd, 0, 0x0000, 0x0112); + ibmcam_veio(uvd, 0, 0x0080, 0x0100); + IBMCAM_T(uvd)->initialized = 0; +#endif + break; + } /* switch */ } /* - * ibmcam_ioctl() + * ibmcam_reinit_iso() * - * This is part of Video 4 Linux API. The procedure handles ioctl() calls. + * This procedure sends couple of commands to the camera and then + * resets the video pipe. This sequence was observed to reinit the + * camera or, at least, to initiate ISO data stream. * * History: - * 1/22/00 Corrected VIDIOCSPICT to reject unsupported settings. + * 1/2/00 Created. */ -static int ibmcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +static void ibmcam_reinit_iso(uvd_t *uvd, int do_stop) { - struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev; - - if (!IBMCAM_IS_OPERATIONAL(ibmcam)) - return -EFAULT; - - switch (cmd) { - case VIDIOCGCAP: - { - if (copy_to_user(arg, &ibmcam->vcap, sizeof(ibmcam->vcap))) - return -EFAULT; - return 0; - } - case VIDIOCGCHAN: - { - if (copy_to_user(arg, &ibmcam->vchan, sizeof(ibmcam->vchan))) - return -EFAULT; - return 0; - } - case VIDIOCSCHAN: - { - int v; - - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if ((v < 0) || (v >= 3)) /* 3 grades of lighting conditions */ - return -EINVAL; - if (v != ibmcam->vchan.channel) { - ibmcam->vchan.channel = v; - usb_ibmcam_change_lighting_conditions(ibmcam); - } - return 0; - } - case VIDIOCGPICT: - { - if (copy_to_user(arg, &ibmcam->vpic, sizeof(ibmcam->vpic))) - return -EFAULT; - return 0; - } - case VIDIOCSPICT: - { - struct video_picture tmp; - /* - * Use temporary 'video_picture' structure to preserve our - * own settings (such as color depth, palette) that we - * aren't allowing everyone (V4L client) to change. - */ - if (copy_from_user(&tmp, arg, sizeof(tmp))) - return -EFAULT; - ibmcam->vpic.brightness = tmp.brightness; - ibmcam->vpic.hue = tmp.hue; - ibmcam->vpic.colour = tmp.colour; - ibmcam->vpic.contrast = tmp.contrast; - usb_ibmcam_adjust_picture(ibmcam); - return 0; - } - case VIDIOCSWIN: - { - struct video_window vw; - - if (copy_from_user(&vw, arg, sizeof(vw))) - return -EFAULT; - if (vw.flags) - return -EINVAL; - if (vw.clipcount) - return -EINVAL; - if (vw.height != imgheight) - return -EINVAL; - if (vw.width != imgwidth) - return -EINVAL; - - ibmcam->compress = 0; - - return 0; - } - case VIDIOCGWIN: - { - struct video_window vw; - - vw.x = 0; - vw.y = 0; - vw.width = imgwidth; - vw.height = imgheight; - vw.chromakey = 0; - vw.flags = usb_ibmcam_calculate_fps(); - - if (copy_to_user(arg, &vw, sizeof(vw))) - return -EFAULT; - - return 0; - } - case VIDIOCGMBUF: - { - struct video_mbuf vm; - - memset(&vm, 0, sizeof(vm)); - vm.size = MAX_FRAME_SIZE * 2; - vm.frames = 2; - vm.offsets[0] = 0; - vm.offsets[1] = MAX_FRAME_SIZE; - - if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) - return -EFAULT; - - return 0; - } - case VIDIOCMCAPTURE: - { - struct video_mmap vm; - - if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) - return -EFAULT; - - if (debug >= 1) - printk(KERN_DEBUG "frame: %d, size: %dx%d, format: %d\n", - vm.frame, vm.width, vm.height, vm.format); - - if (vm.format != VIDEO_PALETTE_RGB24) - return -EINVAL; - - if ((vm.frame != 0) && (vm.frame != 1)) - return -EINVAL; - - if (ibmcam->frame[vm.frame].grabstate == FRAME_GRABBING) - return -EBUSY; - - /* Don't compress if the size changed */ - if ((ibmcam->frame[vm.frame].width != vm.width) || - (ibmcam->frame[vm.frame].height != vm.height)) - ibmcam->compress = 0; - - ibmcam->frame[vm.frame].width = vm.width; - ibmcam->frame[vm.frame].height = vm.height; - - /* Mark it as ready */ - ibmcam->frame[vm.frame].grabstate = FRAME_READY; - - return ibmcam_new_frame(ibmcam, vm.frame); - } - case VIDIOCSYNC: - { - int frame; - - if (copy_from_user((void *)&frame, arg, sizeof(int))) - return -EFAULT; - - if (debug >= 1) - printk(KERN_DEBUG "ibmcam: syncing to frame %d\n", frame); - - switch (ibmcam->frame[frame].grabstate) { - case FRAME_UNUSED: - return -EINVAL; - case FRAME_READY: - case FRAME_GRABBING: - case FRAME_ERROR: - { - int ntries; - redo: - if (!IBMCAM_IS_OPERATIONAL(ibmcam)) - return -EIO; - ntries = 0; - do { - interruptible_sleep_on(&ibmcam->frame[frame].wq); - if (signal_pending(current)) { - if (flags & FLAGS_RETRY_VIDIOCSYNC) { - /* Polling apps will destroy frames with that! */ - ibmcam_new_frame(ibmcam, frame); - usb_ibmcam_testpattern(ibmcam, 1, 0); - ibmcam->curframe = -1; - ibmcam->frame_num++; - - /* This will request another frame. */ - if (waitqueue_active(&ibmcam->frame[frame].wq)) - wake_up_interruptible(&ibmcam->frame[frame].wq); - return 0; - } else { - /* Standard answer: not ready yet! */ - return -EINTR; - } - } - } while (ibmcam->frame[frame].grabstate == FRAME_GRABBING); - - if (ibmcam->frame[frame].grabstate == FRAME_ERROR) { - int ret = ibmcam_new_frame(ibmcam, frame); - if (ret < 0) - return ret; - goto redo; - } - } - case FRAME_DONE: - ibmcam->frame[frame].grabstate = FRAME_UNUSED; - break; - } - - ibmcam->frame[frame].grabstate = FRAME_UNUSED; - - return 0; - } - case VIDIOCGFBUF: - { - struct video_buffer vb; - - memset(&vb, 0, sizeof(vb)); - vb.base = NULL; /* frame buffer not supported, not used */ - - if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb))) - return -EFAULT; - - return 0; - } - case VIDIOCKEY: - return 0; - - case VIDIOCCAPTURE: - return -EINVAL; - - case VIDIOCSFBUF: - - case VIDIOCGTUNER: - case VIDIOCSTUNER: - - case VIDIOCGFREQ: - case VIDIOCSFREQ: - - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - return -EINVAL; - - default: - return -ENOIOCTLCMD; + switch (IBMCAM_T(uvd)->camera_model) { + case IBMCAM_MODEL_1: + if (do_stop) + ibmcam_video_stop(uvd); + ibmcam_veio(uvd, 0, 0x0001, 0x0114); + ibmcam_veio(uvd, 0, 0x00c0, 0x010c); + usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); + ibmcam_model1_setup_after_video_if(uvd); + break; + case IBMCAM_MODEL_2: + ibmcam_model2_setup_after_video_if(uvd); + break; + case IBMCAM_MODEL_3: + ibmcam_video_stop(uvd); + ibmcam_model3_setup_after_video_if(uvd); + break; + case IBMCAM_MODEL_4: + ibmcam_model4_setup_after_video_if(uvd); + break; } - return 0; } -static long ibmcam_read(struct video_device *dev, char *buf, unsigned long count, int noblock) +static void ibmcam_video_start(uvd_t *uvd) { - struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev; - int frmx = -1; - volatile struct ibmcam_frame *frame; - - if (debug >= 1) - printk(KERN_DEBUG "ibmcam_read: %ld bytes, noblock=%d\n", count, noblock); - - if (!IBMCAM_IS_OPERATIONAL(ibmcam) || (buf == NULL)) - return -EFAULT; - - /* See if a frame is completed, then use it. */ - if (ibmcam->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */ - frmx = 0; - else if (ibmcam->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */ - frmx = 1; - - if (noblock && (frmx == -1)) - return -EAGAIN; - - /* If no FRAME_DONE, look for a FRAME_GRABBING state. */ - /* See if a frame is in process (grabbing), then use it. */ - if (frmx == -1) { - if (ibmcam->frame[0].grabstate == FRAME_GRABBING) - frmx = 0; - else if (ibmcam->frame[1].grabstate == FRAME_GRABBING) - frmx = 1; - } - - /* If no frame is active, start one. */ - if (frmx == -1) - ibmcam_new_frame(ibmcam, frmx = 0); - - frame = &ibmcam->frame[frmx]; - -restart: - if (!IBMCAM_IS_OPERATIONAL(ibmcam)) - return -EIO; - while (frame->grabstate == FRAME_GRABBING) { - interruptible_sleep_on((void *)&frame->wq); - if (signal_pending(current)) - return -EINTR; - } - - if (frame->grabstate == FRAME_ERROR) { - frame->bytes_read = 0; - if (ibmcam_new_frame(ibmcam, frmx)) - printk(KERN_ERR "ibmcam_read: ibmcam_new_frame error\n"); - goto restart; - } - - if (debug >= 1) - printk(KERN_DEBUG "ibmcam_read: frmx=%d, bytes_read=%ld, scanlength=%ld\n", - frmx, frame->bytes_read, frame->scanlength); - - /* copy bytes to user space; we allow for partials reads */ - if ((count + frame->bytes_read) > frame->scanlength) - count = frame->scanlength - frame->bytes_read; - - if (copy_to_user(buf, frame->data + frame->bytes_read, count)) - return -EFAULT; - - frame->bytes_read += count; - if (debug >= 1) - printk(KERN_DEBUG "ibmcam_read: {copy} count used=%ld, new bytes_read=%ld\n", - count, frame->bytes_read); - - if (frame->bytes_read >= frame->scanlength) { /* All data has been read */ - frame->bytes_read = 0; - - /* Mark it as available to be used again. */ - ibmcam->frame[frmx].grabstate = FRAME_UNUSED; - if (ibmcam_new_frame(ibmcam, frmx ? 0 : 1)) - printk(KERN_ERR "ibmcam_read: ibmcam_new_frame returned error\n"); - } - - return count; + ibmcam_change_lighting_conditions(uvd); + ibmcam_set_sharpness(uvd); + ibmcam_reinit_iso(uvd, 0); } -static int ibmcam_mmap(struct video_device *dev, const char *adr, unsigned long size) +/* + * Return negative code on failure, 0 on success. + */ +static int ibmcam_setup_on_open(uvd_t *uvd) { - struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev; - unsigned long start = (unsigned long)adr; - unsigned long page, pos; - - if (!IBMCAM_IS_OPERATIONAL(ibmcam)) - return -EFAULT; - - if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) - return -EINVAL; - - pos = (unsigned long)ibmcam->fbuf; - while (size > 0) { - page = kvirt_to_pa(pos); - if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + int setup_ok = 0; /* Success by default */ + /* Send init sequence only once, it's large! */ + if (!IBMCAM_T(uvd)->initialized) { /* FIXME rename */ + switch (IBMCAM_T(uvd)->camera_model) { + case IBMCAM_MODEL_1: + setup_ok = ibmcam_model1_setup(uvd); + break; + case IBMCAM_MODEL_2: + setup_ok = ibmcam_model2_setup(uvd); + break; + case IBMCAM_MODEL_3: + case IBMCAM_MODEL_4: + /* We do all setup when Isoc stream is requested */ + break; + } + IBMCAM_T(uvd)->initialized = (setup_ok != 0); } - - return 0; + return setup_ok; } -static struct video_device ibmcam_template = { - name: "CPiA USB Camera", - type: VID_TYPE_CAPTURE, - hardware: VID_HARDWARE_CPIA, - open: ibmcam_open, - close: ibmcam_close, - read: ibmcam_read, - write: ibmcam_write, - ioctl: ibmcam_ioctl, - mmap: ibmcam_mmap, -}; - -static void usb_ibmcam_configure_video(struct usb_ibmcam *ibmcam) +static void ibmcam_configure_video(uvd_t *uvd) { - if (ibmcam == NULL) + if (uvd == NULL) return; RESTRICT_TO_RANGE(init_brightness, 0, 255); @@ -2872,284 +3609,320 @@ RESTRICT_TO_RANGE(init_hue, 0, 255); RESTRICT_TO_RANGE(hue_correction, 0, 255); - memset(&ibmcam->vpic, 0, sizeof(ibmcam->vpic)); - memset(&ibmcam->vpic_old, 0x55, sizeof(ibmcam->vpic_old)); + memset(&uvd->vpic, 0, sizeof(uvd->vpic)); + memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old)); - ibmcam->vpic.colour = init_color << 8; - ibmcam->vpic.hue = init_hue << 8; - ibmcam->vpic.brightness = init_brightness << 8; - ibmcam->vpic.contrast = init_contrast << 8; - ibmcam->vpic.whiteness = 105 << 8; /* This one isn't used */ - ibmcam->vpic.depth = 24; - ibmcam->vpic.palette = VIDEO_PALETTE_RGB24; - - memset(&ibmcam->vcap, 0, sizeof(ibmcam->vcap)); - strcpy(ibmcam->vcap.name, "IBM USB Camera"); - ibmcam->vcap.type = VID_TYPE_CAPTURE; - ibmcam->vcap.channels = 1; - ibmcam->vcap.audios = 0; - ibmcam->vcap.maxwidth = imgwidth; - ibmcam->vcap.maxheight = imgheight; - ibmcam->vcap.minwidth = min_imgwidth; - ibmcam->vcap.minheight = min_imgheight; - - memset(&ibmcam->vchan, 0, sizeof(ibmcam->vchan)); - ibmcam->vchan.flags = 0; - ibmcam->vchan.tuners = 0; - ibmcam->vchan.channel = 0; - ibmcam->vchan.type = VIDEO_TYPE_CAMERA; - strcpy(ibmcam->vchan.name, "Camera"); + uvd->vpic.colour = init_color << 8; + uvd->vpic.hue = init_hue << 8; + uvd->vpic.brightness = init_brightness << 8; + uvd->vpic.contrast = init_contrast << 8; + uvd->vpic.whiteness = 105 << 8; /* This one isn't used */ + uvd->vpic.depth = 24; + uvd->vpic.palette = VIDEO_PALETTE_RGB24; + + memset(&uvd->vcap, 0, sizeof(uvd->vcap)); + strcpy(uvd->vcap.name, "IBM USB Camera"); + uvd->vcap.type = VID_TYPE_CAPTURE; + uvd->vcap.channels = 1; + uvd->vcap.audios = 0; + uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas); + uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas); + uvd->vcap.minwidth = min_canvasWidth; + uvd->vcap.minheight = min_canvasHeight; + + memset(&uvd->vchan, 0, sizeof(uvd->vchan)); + uvd->vchan.flags = 0; + uvd->vchan.tuners = 0; + uvd->vchan.channel = 0; + uvd->vchan.type = VIDEO_TYPE_CAMERA; + strcpy(uvd->vchan.name, "Camera"); } /* - * ibmcam_find_struct() - * - * This code searches the array of preallocated (static) structures - * and returns index of the first one that isn't in use. Returns -1 - * if there are no free structures. - * - * History: - * 1/27/00 Created. - */ -static int ibmcam_find_struct(void) -{ - int i, u; - - for (u = 0; u < MAX_IBMCAM; u++) { - struct usb_ibmcam *ibmcam = &cams[u]; - if (!ibmcam->ibmcam_used) /* This one is free */ - { - ibmcam->ibmcam_used = 1; /* In use now */ - for (i=0; i < IBMCAM_NUMFRAMES; i++) - init_waitqueue_head(&ibmcam->frame[i].wq); - init_MUTEX(&ibmcam->lock); /* to 1 == available */ - ibmcam->dev = NULL; - memcpy(&ibmcam->vdev, &ibmcam_template, sizeof(ibmcam_template)); - return u; - } - } - return -1; -} - -/* - * usb_ibmcam_probe() + * ibmcam_probe() * * This procedure queries device descriptor and accepts the interface * if it looks like IBM C-it camera. * * History: - * 1/22/00 Moved camera init code to ibmcam_open() - * 1/27/00 Changed to use static structures, added locking. - * 5/24/00 Corrected to prevent race condition (MOD_xxx_USE_COUNT). - * 7/3/00 Fixed endianness bug. - */ -static void *usb_ibmcam_probe(struct usb_device *dev, unsigned int ifnum, - const struct usb_device_id *id) -{ - struct usb_ibmcam *ibmcam = NULL; - const struct usb_interface_descriptor *interface; - const struct usb_endpoint_descriptor *endpoint; - int devnum, model=0; + * 22-Jan-2000 Moved camera init code to ibmcam_open() + * 27=Jan-2000 Changed to use static structures, added locking. + * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT). + * 03-Jul-2000 Fixed endianness bug. + * 12-Nov-2000 Reworked to comply with new probe() signature. + * 23-Jan-2001 Added compatibility with 2.2.x kernels. + */ +static void *ibmcam_probe(struct usb_device *dev, unsigned int ifnum +#if defined(usb_device_id_ver) + ,const struct usb_device_id *devid +#endif + ) +{ + uvd_t *uvd = NULL; + int i, nas, model=0, canvasX=0, canvasY=0; + int actInterface=-1, inactInterface=-1, maxPS=0; + unsigned char video_ep = 0; if (debug >= 1) - printk(KERN_DEBUG "ibmcam_probe(%p,%u.)\n", dev, ifnum); + info("ibmcam_probe(%p,%u.)", dev, ifnum); /* We don't handle multi-config cameras */ if (dev->descriptor.bNumConfigurations != 1) return NULL; + /* Is it an IBM camera? */ + if (dev->descriptor.idVendor != IBMCAM_VENDOR_ID) + return NULL; + if ((dev->descriptor.idProduct != IBMCAM_PRODUCT_ID) && + (dev->descriptor.idProduct != NETCAM_PRODUCT_ID)) + return NULL; + /* Check the version/revision */ switch (dev->descriptor.bcdDevice) { case 0x0002: if (ifnum != 2) return NULL; - printk(KERN_INFO "IBM USB camera found (model 1, rev. 0x%04x).\n", - dev->descriptor.bcdDevice); model = IBMCAM_MODEL_1; break; case 0x030A: if (ifnum != 0) return NULL; - printk(KERN_INFO "IBM USB camera found (model 2, rev. 0x%04x).\n", - dev->descriptor.bcdDevice); - model = IBMCAM_MODEL_2; + if (dev->descriptor.idProduct == NETCAM_PRODUCT_ID) + model = IBMCAM_MODEL_4; + else + model = IBMCAM_MODEL_2; break; - - /* ibmcam_table contents prevents any other values from ever - being passed to us, so no need for "default" case. */ + case 0x0301: + if (ifnum != 0) + return NULL; + model = IBMCAM_MODEL_3; + break; + default: + err("IBM camera with revision 0x%04x is not supported.", + dev->descriptor.bcdDevice); + return NULL; } + info("IBM USB camera found (model %d, rev. 0x%04x)", + model, dev->descriptor.bcdDevice); /* Validate found interface: must have one ISO endpoint */ - interface = &dev->actconfig->interface[ifnum].altsetting[0]; - if (interface->bNumEndpoints != 1) { - printk(KERN_ERR "IBM camera: interface %d. has %u. endpoints!\n", - ifnum, (unsigned)(interface->bNumEndpoints)); + nas = dev->actconfig->interface[ifnum].num_altsetting; + if (debug > 0) + info("Number of alternate settings=%d.", nas); + if (nas < 2) { + err("Too few alternate settings for this camera!"); return NULL; } - endpoint = &interface->endpoint[0]; - if ((endpoint->bmAttributes & 0x03) != 0x01) { - printk(KERN_ERR "IBM camera: interface %d. has non-ISO endpoint!\n", ifnum); - return NULL; + /* Validate all alternate settings */ + for (i=0; i < nas; i++) { + const struct usb_interface_descriptor *interface; + const struct usb_endpoint_descriptor *endpoint; + + interface = &dev->actconfig->interface[ifnum].altsetting[i]; + if (interface->bNumEndpoints != 1) { + err("Interface %d. has %u. endpoints!", + ifnum, (unsigned)(interface->bNumEndpoints)); + return NULL; + } + endpoint = &interface->endpoint[0]; + if (video_ep == 0) + video_ep = endpoint->bEndpointAddress; + else if (video_ep != endpoint->bEndpointAddress) { + err("Alternate settings have different endpoint addresses!"); + return NULL; + } + if ((endpoint->bmAttributes & 0x03) != 0x01) { + err("Interface %d. has non-ISO endpoint!", ifnum); + return NULL; + } + if ((endpoint->bEndpointAddress & 0x80) == 0) { + err("Interface %d. has ISO OUT endpoint!", ifnum); + return NULL; + } + if (endpoint->wMaxPacketSize == 0) { + if (inactInterface < 0) + inactInterface = i; + else { + err("More than one inactive alt. setting!"); + return NULL; + } + } else { + if (actInterface < 0) { + actInterface = i; + maxPS = endpoint->wMaxPacketSize; + if (debug > 0) + info("Active setting=%d. maxPS=%d.", i, maxPS); + } else + err("More than one active alt. setting! Ignoring #%d.", i); + } } - if ((endpoint->bEndpointAddress & 0x80) == 0) { - printk(KERN_ERR "IBM camera: interface %d. has ISO OUT endpoint!\n", ifnum); + if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) { + err("Failed to recognize the camera!"); return NULL; } /* Validate options */ - if (model == IBMCAM_MODEL_1) { + switch (model) { + case IBMCAM_MODEL_1: RESTRICT_TO_RANGE(lighting, 0, 2); - RESTRICT_TO_RANGE(videosize, VIDEOSIZE_128x96, VIDEOSIZE_352x288); - } else { + RESTRICT_TO_RANGE(size, SIZE_128x96, SIZE_352x288); + if (framerate < 0) + framerate = 2; + canvasX = 352; + canvasY = 288; + break; + case IBMCAM_MODEL_2: RESTRICT_TO_RANGE(lighting, 0, 15); - RESTRICT_TO_RANGE(videosize, VIDEOSIZE_176x144, VIDEOSIZE_352x240); + RESTRICT_TO_RANGE(size, SIZE_176x144, SIZE_352x240); + if (framerate < 0) + framerate = 2; + canvasX = 352; + canvasY = 240; + break; + case IBMCAM_MODEL_3: + RESTRICT_TO_RANGE(lighting, 0, 15); /* FIXME */ + switch (size) { + case SIZE_160x120: + canvasX = 160; + canvasY = 120; + if (framerate < 0) + framerate = 2; + RESTRICT_TO_RANGE(framerate, 0, 5); + break; + default: + info("IBM camera: using 320x240"); + size = SIZE_320x240; + /* No break here */ + case SIZE_320x240: + canvasX = 320; + canvasY = 240; + if (framerate < 0) + framerate = 3; + RESTRICT_TO_RANGE(framerate, 0, 5); + break; + case SIZE_640x480: + canvasX = 640; + canvasY = 480; + framerate = 0; /* Slowest, and maybe even that is too fast */ + break; + } + break; + case IBMCAM_MODEL_4: + RESTRICT_TO_RANGE(lighting, 0, 2); + switch (size) { + case SIZE_128x96: + canvasX = 128; + canvasY = 96; + break; + case SIZE_160x120: + canvasX = 160; + canvasY = 120; + break; + default: + info("IBM NetCamera: using 176x144"); + size = SIZE_176x144; + /* No break here */ + case SIZE_176x144: + canvasX = 176; + canvasY = 144; + break; + case SIZE_320x240: + canvasX = 320; + canvasY = 240; + break; + case SIZE_352x288: + canvasX = 352; + canvasY = 288; + break; + } + break; + default: + err("IBM camera: Model %d. not supported!", model); + return NULL; } /* Code below may sleep, need to lock module while we are here */ MOD_INC_USE_COUNT; - - devnum = ibmcam_find_struct(); - if (devnum == -1) { - printk(KERN_INFO "IBM USB camera driver: Too many devices!\n"); - ibmcam = NULL; /* Do not free, it's preallocated */ - goto probe_done; - } - ibmcam = &cams[devnum]; - - down(&ibmcam->lock); - ibmcam->camera_model = model; - ibmcam->remove_pending = 0; - ibmcam->last_error = 0; - ibmcam->dev = dev; - ibmcam->iface = ifnum; - ibmcam->ifaceAltInactive = 0; - ibmcam->ifaceAltActive = 1; - ibmcam->video_endp = endpoint->bEndpointAddress; - ibmcam->iso_packet_len = 1014; - ibmcam->compress = 0; - ibmcam->user=0; - - usb_ibmcam_configure_video(ibmcam); - up (&ibmcam->lock); - - if (video_register_device(&ibmcam->vdev, VFL_TYPE_GRABBER) == -1) { - printk(KERN_ERR "video_register_device failed\n"); - ibmcam = NULL; /* Do not free, it's preallocated */ - } - if (debug > 1) - printk(KERN_DEBUG "video_register_device() successful\n"); -probe_done: - MOD_DEC_USE_COUNT; - return ibmcam; -} - -/* - * usb_ibmcam_release() - * - * This code does final release of struct usb_ibmcam. This happens - * after the device is disconnected -and- all clients closed their files. - * - * History: - * 1/27/00 Created. - */ -static void usb_ibmcam_release(struct usb_ibmcam *ibmcam) -{ - video_unregister_device(&ibmcam->vdev); - if (debug > 0) - printk(KERN_DEBUG "usb_ibmcam_release: Video unregistered.\n"); - ibmcam->ibmcam_used = 0; - ibmcam->initialized = 0; -} - -/* - * usb_ibmcam_disconnect() - * - * This procedure stops all driver activity, deallocates interface-private - * structure (pointed by 'ptr') and after that driver should be removable - * with no ill consequences. - * - * This code handles surprise removal. The ibmcam->user is a counter which - * increments on open() and decrements on close(). If we see here that - * this counter is not 0 then we have a client who still has us opened. - * We set ibmcam->remove_pending flag as early as possible, and after that - * all access to the camera will gracefully fail. These failures should - * prompt client to (eventually) close the video device, and then - in - * ibmcam_close() - we decrement ibmcam->ibmcam_used and usage counter. - * - * History: - * 1/22/00 Added polling of MOD_IN_USE to delay removal until all users gone. - * 1/27/00 Reworked to allow pending disconnects; see ibmcam_close() - * 5/24/00 Corrected to prevent race condition (MOD_xxx_USE_COUNT). - */ -static void usb_ibmcam_disconnect(struct usb_device *dev, void *ptr) -{ - static const char proc[] = "usb_ibmcam_disconnect"; - struct usb_ibmcam *ibmcam = (struct usb_ibmcam *) ptr; - - MOD_INC_USE_COUNT; - - if (debug > 0) - printk(KERN_DEBUG "%s(%p,%p.)\n", proc, dev, ptr); - - down(&ibmcam->lock); - ibmcam->remove_pending = 1; /* Now all ISO data will be ignored */ - - /* At this time we ask to cancel outstanding URBs */ - ibmcam_stop_isoc(ibmcam); - - ibmcam->dev = NULL; /* USB device is no more */ - - if (ibmcam->user) - printk(KERN_INFO "%s: In use, disconnect pending.\n", proc); - else - usb_ibmcam_release(ibmcam); - up(&ibmcam->lock); - printk(KERN_INFO "IBM USB camera disconnected.\n"); - + uvd = usbvideo_AllocateDevice(cams); + if (uvd != NULL) { + /* Here uvd is a fully allocated uvd_t object */ + uvd->flags = flags; + uvd->debug = debug; + uvd->dev = dev; + uvd->iface = ifnum; + uvd->ifaceAltInactive = inactInterface; + uvd->ifaceAltActive = actInterface; + uvd->video_endp = video_ep; + uvd->iso_packet_len = maxPS; + uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24; + uvd->defaultPalette = VIDEO_PALETTE_RGB24; + uvd->canvas = VIDEOSIZE(canvasX, canvasY); + uvd->videosize = ibmcam_size_to_videosize(size); + + /* Initialize ibmcam-specific data */ + assert(IBMCAM_T(uvd) != NULL); + IBMCAM_T(uvd)->camera_model = model; + IBMCAM_T(uvd)->initialized = 0; + + ibmcam_configure_video(uvd); + + i = usbvideo_RegisterVideoDevice(uvd); + if (i != 0) { + err("usbvideo_RegisterVideoDevice() failed."); + uvd = NULL; + } + } MOD_DEC_USE_COUNT; + return uvd; } -static struct usb_device_id ibmcam_table [] = { - { USB_DEVICE_VER(0x0545, 0x8080, 0x0002, 0x0002) }, - { USB_DEVICE_VER(0x0545, 0x8080, 0x030a, 0x030a) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, ibmcam_table); - -static struct usb_driver ibmcam_driver = { - name: "ibmcam", - probe: usb_ibmcam_probe, - disconnect: usb_ibmcam_disconnect, - id_table: ibmcam_table, -}; - /* - * usb_ibmcam_init() + * ibmcam_init() * * This code is run to initialize the driver. * * History: - * 1/27/00 Reworked to use statically allocated usb_ibmcam structures. + * 1/27/00 Reworked to use statically allocated ibmcam structures. + * 21/10/00 Completely redesigned to use usbvideo services. */ -static int __init usb_ibmcam_init(void) +static int __init ibmcam_init(void) { - unsigned u; - - /* Initialize struct */ - for (u = 0; u < MAX_IBMCAM; u++) { - struct usb_ibmcam *ibmcam = &cams[u]; - memset (ibmcam, 0, sizeof(struct usb_ibmcam)); - } - return usb_register(&ibmcam_driver); -} - -static void __exit usb_ibmcam_cleanup(void) -{ - usb_deregister(&ibmcam_driver); -} - -module_init(usb_ibmcam_init); -module_exit(usb_ibmcam_cleanup); + usbvideo_cb_t cbTbl; + memset(&cbTbl, 0, sizeof(cbTbl)); + cbTbl.probe = ibmcam_probe; + cbTbl.setupOnOpen = ibmcam_setup_on_open; + cbTbl.videoStart = ibmcam_video_start; + cbTbl.videoStop = ibmcam_video_stop; + cbTbl.processData = ibmcam_ProcessIsocData; + cbTbl.postProcess = usbvideo_DeinterlaceFrame; + cbTbl.adjustPicture = ibmcam_adjust_picture; + cbTbl.getFPS = ibmcam_calculate_fps; + return usbvideo_register( + &cams, + MAX_IBMCAM, + sizeof(ibmcam_t), + "ibmcam", + &cbTbl, + THIS_MODULE); +} + +static void __exit ibmcam_cleanup(void) +{ + usbvideo_Deregister(&cams); +} + +#if defined(usb_device_id_ver) + +static __devinitdata struct usb_device_id id_table[] = { + { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x00, 0x02) }, /* Model 1 */ + { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x03, 0x0a) }, /* Model 2 */ + { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x03, 0x01) }, /* Model 3 */ + { USB_DEVICE_VER(IBMCAM_VENDOR_ID, NETCAM_PRODUCT_ID, 0x03, 0x0a) }, /* Model 4 */ + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, id_table); +#endif /* defined(usb_device_id_ver) */ +module_init(ibmcam_init); +module_exit(ibmcam_cleanup); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/inode.c linux.ac/drivers/usb/inode.c --- linux.vanilla/drivers/usb/inode.c Tue Apr 3 17:32:23 2001 +++ linux.ac/drivers/usb/inode.c Tue Apr 3 17:55:07 2001 @@ -164,11 +164,15 @@ struct list_head *list; struct usb_bus *bus; + read_lock_irq (&usb_bus_list_lock); for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) { bus = list_entry(list, struct usb_bus, bus_list); - if (bus->busnum == busnr) + if (bus->busnum == busnr) { + read_unlock_irq (&usb_bus_list_lock); return bus; + } } + read_unlock_irq (&usb_bus_list_lock); return NULL; } @@ -316,7 +320,7 @@ if (i < 2+NRSPECIAL) return 0; i -= 2+NRSPECIAL; - lock_kernel(); + read_lock_irq (&usb_bus_list_lock); for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) { if (i > 0) { i--; @@ -328,7 +332,7 @@ break; filp->f_pos++; } - unlock_kernel(); + read_unlock_irq (&usb_bus_list_lock); return 0; } } @@ -577,13 +581,13 @@ list_add_tail(&inode->u.usbdev_i.slist, &s->u.usbdevfs_sb.ilist); list_add_tail(&inode->u.usbdev_i.dlist, &special[i].inodes); } - lock_kernel(); + read_lock_irq (&usb_bus_list_lock); for (blist = usb_bus_list.next; blist != &usb_bus_list; blist = blist->next) { bus = list_entry(blist, struct usb_bus, bus_list); new_bus_inode(bus, s); recurse_new_dev_inode(bus->root_hub, s); } - unlock_kernel(); + read_unlock_irq (&usb_bus_list_lock); return s; out_no_root: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/kaweth.c linux.ac/drivers/usb/kaweth.c --- linux.vanilla/drivers/usb/kaweth.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/usb/kaweth.c Tue Apr 3 17:55:07 2001 @@ -0,0 +1,1053 @@ +/**************************************************************** + * + * kaweth.c - driver for KL5KUSB101 based USB->Ethernet + * + * (c) 2000 Interlan Communications + * (c) 2000 Stephane Alnet + * (C) 2001 Brad Hards + * + * Original author: The Zapman <zapman@interlan.net> + * Inspired by, and much credit goes to Michael Rothwell + * <rothwell@interlan.net> for the test equipment, help, and patience + * Based off of (and with thanks to) Petko Manolov's pegaus.c driver. + * Also many thanks to Joel Silverman and Ed Surprenant at Kawasaki + * for providing the firmware and driver resources. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + ****************************************************************/ + +/* TODO: + * Fix in_interrupt() problem + * Develop test procedures for USB net interfaces + * Run test procedures + * Fix bugs from previous two steps + * Snoop other OSs for any tricks we're not doing + * SMP locking + * Reduce arbitrary timeouts + * Smart multicast support + * Temporary MAC change support + * Tunable SOFs parameter - ioctl()? + * Ethernet stats collection + * Code formatting improvements + */ + +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/malloc.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/usb.h> +#include <linux/types.h> +#include <asm/semaphore.h> + +#define DEBUG + +#ifdef DEBUG +#define kaweth_dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" ,##arg) +#else +#define kaweth_dbg(format, arg...) do {} while (0) +#endif +#define kaweth_err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" ,##arg) +#define kaweth_info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ##arg) +#define kaweth_warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ##arg) + + +#include "kawethfw.h" + +#define KAWETH_MTU 1514 +#define KAWETH_BUF_SIZE 1664 +#define KAWETH_TX_TIMEOUT (5 * HZ) +#define KAWETH_FIRMWARE_BUF_SIZE 4096 +#define KAWETH_CONTROL_TIMEOUT (30 * HZ) + +#define KAWETH_STATUS_BROKEN 0x0000001 +#define KAWETH_STATUS_CLOSING 0x0000002 + +#define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01 +#define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02 +#define KAWETH_PACKET_FILTER_DIRECTED 0x04 +#define KAWETH_PACKET_FILTER_BROADCAST 0x08 +#define KAWETH_PACKET_FILTER_MULTICAST 0x10 + +/* Table 7 */ +#define KAWETH_COMMAND_GET_ETHERNET_DESC 0x00 +#define KAWETH_COMMAND_MULTICAST_FILTERS 0x01 +#define KAWETH_COMMAND_SET_PACKET_FILTER 0x02 +#define KAWETH_COMMAND_STATISTICS 0x03 +#define KAWETH_COMMAND_SET_TEMP_MAC 0x06 +#define KAWETH_COMMAND_GET_TEMP_MAC 0x07 +#define KAWETH_COMMAND_SET_URB_SIZE 0x08 +#define KAWETH_COMMAND_SET_SOFS_WAIT 0x09 +#define KAWETH_COMMAND_SCAN 0xFF + +#define KAWETH_SOFS_TO_WAIT 0x05 + + +MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-picardie.fr> and Brad Hards <bhards@bigpond.net.au>"); +MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver"); + +static void *kaweth_probe( + struct usb_device *dev, /* the device */ + unsigned ifnum, /* what interface */ + const struct usb_device_id *id /* from id_table */ + ); +static void kaweth_disconnect(struct usb_device *dev, void *ptr); +int kaweth_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, + devrequest *cmd, void *data, int len, + int timeout); + +/**************************************************************** + * usb_device_id + ****************************************************************/ +static struct usb_device_id usb_klsi_table[] = { + { USB_DEVICE(0x03e8, 0x0008) }, /* AOX Endpoints USB Ethernet */ + { USB_DEVICE(0x0506, 0x03e8) }, /* 3Com 3C19250 */ + { USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */ + { USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */ + { USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */ + { USB_DEVICE(0x0565, 0x0005) }, /* Peracom Enet2 */ + { USB_DEVICE(0x05e9, 0x0008) }, /* KLSI KL5KUSB101B */ + { USB_DEVICE(0x05e9, 0x0009) }, /* KLSI KL5KUSB101B (Board change) */ + { USB_DEVICE(0x066b, 0x2202) }, /* Linksys USB10T */ + { USB_DEVICE(0x06e1, 0x0008) }, /* ADS USB-10BT */ + { USB_DEVICE(0x06e1, 0x0009) }, /* ADS USB-10BT */ + { USB_DEVICE(0x0707, 0x0100) }, /* SMC 2202USB */ + { USB_DEVICE(0x07aa, 0x0001) }, /* Correga K.K. */ + { USB_DEVICE(0x07b8, 0x4000) }, /* D-Link DU-E10 */ + { USB_DEVICE(0x0846, 0x1001) }, /* NetGear EA-101 */ + { USB_DEVICE(0x0846, 0x1002) }, /* NetGear EA-101 */ + { USB_DEVICE(0x085a, 0x0008) }, /* PortGear Ethernet Adapter */ + { USB_DEVICE(0x085a, 0x0009) }, /* PortGear Ethernet Adapter */ + { USB_DEVICE(0x087d, 0x5704) }, /* Jaton USB Ethernet Device Adapter */ + { USB_DEVICE(0x0951, 0x0008) }, /* Kingston Technology USB Ethernet Adapter */ + { USB_DEVICE(0x095a, 0x3003) }, /* Portsmith Express Ethernet Adapter */ + { USB_DEVICE(0x10bd, 0x1427) }, /* ASANTE USB To Ethernet Adapter */ + { USB_DEVICE(0x1342, 0x0204) }, /* Mobility USB-Ethernet Adapter */ + { USB_DEVICE(0x13d2, 0x0400) }, /* Shark Pocket Adapter */ + { USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */ + { USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */ + { USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */ + { USB_DEVICE(0x2001, 0x4000) }, /* D-link DSB-650C */ + {} /* Null terminator */ +}; + +MODULE_DEVICE_TABLE (usb, usb_klsi_table); + +/**************************************************************** + * kaweth_driver + ****************************************************************/ +static struct usb_driver kaweth_driver = { + name: "kaweth", + probe: kaweth_probe, + disconnect: kaweth_disconnect, + id_table: usb_klsi_table, +}; + +typedef __u8 eth_addr_t[6]; + +/**************************************************************** + * usb_eth_dev + ****************************************************************/ +struct usb_eth_dev { + char *name; + __u16 vendor; + __u16 device; + void *pdata; +}; + +/**************************************************************** + * kaweth_ethernet_configuration + * Refer Table 8 + ****************************************************************/ +struct kaweth_ethernet_configuration +{ + __u8 size; + __u8 reserved1; + __u8 reserved2; + eth_addr_t hw_addr; + __u32 statistics_mask; + __u16 segment_size; + __u16 max_multicast_filters; + __u8 reserved3; +} __attribute__ ((packed)); + +/**************************************************************** + * kaweth_device + ****************************************************************/ +struct kaweth_device +{ + spinlock_t device_lock; + + __u32 status; + + struct usb_device *dev; + struct net_device *net; + wait_queue_head_t control_wait; + + struct urb *rx_urb; + struct urb *tx_urb; + + __u8 firmware_buf[KAWETH_FIRMWARE_BUF_SIZE]; + __u8 tx_buf[KAWETH_BUF_SIZE]; + __u8 rx_buf[KAWETH_BUF_SIZE]; + __u16 packet_filter_bitmap; + + struct kaweth_ethernet_configuration configuration; + + struct net_device_stats stats; +} __attribute__ ((packed)); + + +/**************************************************************** + * kaweth_control + ****************************************************************/ +static int kaweth_control(struct kaweth_device *kaweth, + unsigned int pipe, + __u8 request, + __u8 requesttype, + __u16 value, + __u16 index, + void *data, + __u16 size, + int timeout) +{ + devrequest *dr; + + kaweth_dbg("kaweth_control()"); + + if(in_interrupt()) { + kaweth_dbg("in_interrupt()"); + return -EBUSY; + } + + dr = kmalloc(sizeof(devrequest), + in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); + + if(!dr) + { + kaweth_dbg("kmalloc() failed"); + return -ENOMEM; + } + + dr->requesttype = requesttype; + dr->request = request; + dr->value = value; + dr->index = index; + dr->length = size; + + return kaweth_internal_control_msg(kaweth->dev, + pipe, + dr, + data, + size, + timeout); +} + +/**************************************************************** + * kaweth_read_configuration + ****************************************************************/ +static int kaweth_read_configuration(struct kaweth_device *kaweth) +{ + int retval; + + kaweth_dbg("Reading kaweth configuration"); + + retval = kaweth_control(kaweth, + usb_rcvctrlpipe(kaweth->dev, 0), + KAWETH_COMMAND_GET_ETHERNET_DESC, + USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, + 0, + 0, + (void *)&kaweth->configuration, + sizeof(kaweth->configuration), + KAWETH_CONTROL_TIMEOUT); + + return retval; +} + +/**************************************************************** + * kaweth_set_urb_size + ****************************************************************/ +static int kaweth_set_urb_size(struct kaweth_device *kaweth, __u16 urb_size) +{ + int retval; + + kaweth_dbg("Setting URB size to %d", (unsigned)urb_size); + + retval = kaweth_control(kaweth, + usb_sndctrlpipe(kaweth->dev, 0), + KAWETH_COMMAND_SET_URB_SIZE, + USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, + urb_size, + 0, + (void *)&kaweth->firmware_buf, + 0, + KAWETH_CONTROL_TIMEOUT); + + return retval; +} + +/**************************************************************** + * kaweth_set_sofs_wait + ****************************************************************/ +static int kaweth_set_sofs_wait(struct kaweth_device *kaweth, __u16 sofs_wait) +{ + int retval; + + kaweth_dbg("Set SOFS wait to %d", (unsigned)sofs_wait); + + retval = kaweth_control(kaweth, + usb_sndctrlpipe(kaweth->dev, 0), + KAWETH_COMMAND_SET_SOFS_WAIT, + USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, + sofs_wait, + 0, + (void *)&kaweth->firmware_buf, + 0, + KAWETH_CONTROL_TIMEOUT); + + return retval; +} + +/**************************************************************** + * kaweth_set_receive_filter + ****************************************************************/ +static int kaweth_set_receive_filter(struct kaweth_device *kaweth, + __u16 receive_filter) +{ + int retval; + + kaweth_dbg("Set receive filter to %d", (unsigned)receive_filter); + + retval = kaweth_control(kaweth, + usb_sndctrlpipe(kaweth->dev, 0), + KAWETH_COMMAND_SET_PACKET_FILTER, + USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, + receive_filter, + 0, + (void *)&kaweth->firmware_buf, + 0, + KAWETH_CONTROL_TIMEOUT); + + return retval; +} + +/**************************************************************** + * kaweth_download_firmware + ****************************************************************/ +static int kaweth_download_firmware(struct kaweth_device *kaweth, + __u8 *data, + __u16 data_len, + __u8 interrupt, + __u8 type) +{ + if(data_len > KAWETH_FIRMWARE_BUF_SIZE) { + kaweth_err("Firmware too big: %d", data_len); + return -ENOSPC; + } + + memcpy(kaweth->firmware_buf, data, data_len); + + kaweth->firmware_buf[2] = (data_len & 0xFF) - 7; + kaweth->firmware_buf[3] = data_len >> 8; + kaweth->firmware_buf[4] = type; + kaweth->firmware_buf[5] = interrupt; + + kaweth_dbg("Downloading firmware at %x to kaweth device at %x", + (int)data, + (int)kaweth); + kaweth_dbg("Firmware length: %d", data_len); + + return kaweth_control(kaweth, + usb_sndctrlpipe(kaweth->dev, 0), + KAWETH_COMMAND_SCAN, + USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, + 0, + 0, + (void *)&kaweth->firmware_buf, + data_len, + KAWETH_CONTROL_TIMEOUT); +} + +/**************************************************************** + * kaweth_trigger_firmware + ****************************************************************/ +static int kaweth_trigger_firmware(struct kaweth_device *kaweth, + __u8 interrupt) +{ + kaweth->firmware_buf[0] = 0xB6; + kaweth->firmware_buf[1] = 0xC3; + kaweth->firmware_buf[2] = 0x01; + kaweth->firmware_buf[3] = 0x00; + kaweth->firmware_buf[4] = 0x06; + kaweth->firmware_buf[5] = interrupt; + kaweth->firmware_buf[6] = 0x00; + kaweth->firmware_buf[7] = 0x00; + + kaweth_dbg("Triggering firmware"); + + return kaweth_control(kaweth, + usb_sndctrlpipe(kaweth->dev, 0), + KAWETH_COMMAND_SCAN, + USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, + 0, + 0, + (void *)&kaweth->firmware_buf, + 8, + KAWETH_CONTROL_TIMEOUT); +} + +/**************************************************************** + * kaweth_reset + ****************************************************************/ +static int kaweth_reset(struct kaweth_device *kaweth) +{ + int result; + + kaweth_dbg("kaweth_reset(%p)", kaweth); + result = kaweth_control(kaweth, + usb_sndctrlpipe(kaweth->dev, 0), + USB_REQ_SET_CONFIGURATION, + 0, + kaweth->dev->config[0].bConfigurationValue, + 0, + NULL, + 0, + KAWETH_CONTROL_TIMEOUT); + + udelay(10000); + + kaweth_dbg("kaweth_reset() returns %d.",result); + + return result; +} + +static void kaweth_usb_receive(struct urb *); + +/**************************************************************** + * kaweth_resubmit_rx_urb + ****************************************************************/ +static inline void kaweth_resubmit_rx_urb(struct kaweth_device *kaweth) +{ + int result; + + memset(kaweth->rx_urb, 0, sizeof(*kaweth->rx_urb)); + + FILL_BULK_URB(kaweth->rx_urb, + kaweth->dev, + usb_rcvbulkpipe(kaweth->dev, 1), + kaweth->rx_buf, + KAWETH_BUF_SIZE, + kaweth_usb_receive, + kaweth); + + if((result = usb_submit_urb(kaweth->rx_urb))) { + kaweth_err("resubmitting rx_urb %d failed", result); + } +} + +static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth); + +/**************************************************************** + * kaweth_usb_receive + ****************************************************************/ +static void kaweth_usb_receive(struct urb *urb) +{ + struct kaweth_device *kaweth = urb->context; + struct net_device *net = kaweth->net; + + int count = urb->actual_length; + int count2 = urb->transfer_buffer_length; + + __u16 pkt_len = *(__u16 *)kaweth->rx_buf; + + struct sk_buff *skb; + + if(kaweth->status & KAWETH_STATUS_CLOSING) { + return; + } + + if(urb->status && urb->status != -EREMOTEIO && count != 1) { + kaweth_err("%s RX status: %d count: %d packet_len: %d", + net->name, + urb->status, + count, + (int)pkt_len); + kaweth_resubmit_rx_urb(kaweth); + return; + } + + if(kaweth->net && (count > 2)) { + if(pkt_len > (count - 2)) { + kaweth_err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count); + kaweth_err("Packet len & 2047: %x", pkt_len & 2047); + kaweth_err("Count 2: %x", count2); + kaweth_resubmit_rx_urb(kaweth); + return; + } + + if(!(skb = dev_alloc_skb(pkt_len+2))) { + kaweth_resubmit_rx_urb(kaweth); + return; + } + + skb->dev = net; + + eth_copy_and_sum(skb, kaweth->rx_buf + 2, pkt_len, 0); + + skb_put(skb, pkt_len); + + skb->protocol = eth_type_trans(skb, net); + + netif_rx(skb); + + kaweth->stats.rx_packets++; + kaweth->stats.rx_bytes += pkt_len; + } + + kaweth_resubmit_rx_urb(kaweth); +} + +/**************************************************************** + * kaweth_open + ****************************************************************/ +static int kaweth_open(struct net_device *net) +{ + struct kaweth_device *kaweth = (struct kaweth_device *)net->priv; + + kaweth_dbg("Dev usage: %d", kaweth->dev->refcnt.counter); + + kaweth_dbg("Opening network device."); + + kaweth_resubmit_rx_urb(kaweth); + + netif_start_queue(net); + + MOD_INC_USE_COUNT; + + kaweth_async_set_rx_mode(kaweth); + return 0; +} + +/**************************************************************** + * kaweth_close + ****************************************************************/ +static int kaweth_close(struct net_device *net) +{ + struct kaweth_device *kaweth = net->priv; + + netif_stop_queue(net); + + kaweth->status |= KAWETH_STATUS_CLOSING; + + usb_unlink_urb(kaweth->rx_urb); + + kaweth->status &= ~KAWETH_STATUS_CLOSING; + + MOD_DEC_USE_COUNT; + + printk("Dev usage: %d", kaweth->dev->refcnt.counter); + + return 0; +} + +/**************************************************************** + * kaweth_ioctl + ****************************************************************/ +static int kaweth_ioctl(struct net_device *net, struct ifreq *rq, int cmd) +{ + return -EOPNOTSUPP; +} + +/**************************************************************** + * kaweth_usb_transmit_complete + ****************************************************************/ +static void kaweth_usb_transmit_complete(struct urb *urb) +{ + struct kaweth_device *kaweth = urb->context; + + spin_lock(&kaweth->device_lock); + + if (urb->status) + kaweth_dbg("%s: TX status %d.", kaweth->net->name, urb->status); + + netif_wake_queue(kaweth->net); + + spin_unlock(&kaweth->device_lock); +} + +/**************************************************************** + * kaweth_start_xmit + ****************************************************************/ +static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) +{ + struct kaweth_device *kaweth = net->priv; + int count = skb->len; + + int res; + + spin_lock(&kaweth->device_lock); + + kaweth_async_set_rx_mode(kaweth); + netif_stop_queue(net); + + *((__u16 *)kaweth->tx_buf) = skb->len; + + memcpy(kaweth->tx_buf + 2, skb->data, skb->len); + + memset(kaweth->tx_urb, 0, sizeof(*kaweth->tx_urb)); + + FILL_BULK_URB(kaweth->tx_urb, + kaweth->dev, + usb_sndbulkpipe(kaweth->dev, 2), + kaweth->tx_buf, + count + 2, + kaweth_usb_transmit_complete, + kaweth); + + if((res = usb_submit_urb(kaweth->tx_urb))) + { + kaweth_warn("kaweth failed tx_urb %d", res); + kaweth->stats.tx_errors++; + + netif_start_queue(net); + } + else + { + kaweth->stats.tx_packets++; + kaweth->stats.tx_bytes += skb->len; + net->trans_start = jiffies; + } + + dev_kfree_skb(skb); + + spin_unlock(&kaweth->device_lock); + + return 0; +} + +/**************************************************************** + * kaweth_set_rx_mode + ****************************************************************/ +static void kaweth_set_rx_mode(struct net_device *net) +{ + struct kaweth_device *kaweth = net->priv; + + __u16 packet_filter_bitmap = KAWETH_PACKET_FILTER_DIRECTED | + KAWETH_PACKET_FILTER_BROADCAST | + KAWETH_PACKET_FILTER_MULTICAST; + + kaweth_dbg("Setting Rx mode to %d", packet_filter_bitmap); + + netif_stop_queue(net); + + if (net->flags & IFF_PROMISC) { + packet_filter_bitmap |= KAWETH_PACKET_FILTER_PROMISCUOUS; + } + else if ((net->mc_count) || (net->flags & IFF_ALLMULTI)) { + packet_filter_bitmap |= KAWETH_PACKET_FILTER_ALL_MULTICAST; + } + + kaweth->packet_filter_bitmap = packet_filter_bitmap; + netif_wake_queue(net); +} + +/**************************************************************** + * kaweth_async_set_rx_mode + ****************************************************************/ +static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth) +{ + __u16 packet_filter_bitmap = kaweth->packet_filter_bitmap; + kaweth->packet_filter_bitmap = 0; + if(packet_filter_bitmap == 0) return; + + { + int result; + result = kaweth_control(kaweth, + usb_sndctrlpipe(kaweth->dev, 0), + KAWETH_COMMAND_SET_PACKET_FILTER, + USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, + packet_filter_bitmap, + 0, + (void *)&kaweth->firmware_buf, + 0, + KAWETH_CONTROL_TIMEOUT); + + if(result < 0) { + kaweth_err("Failed to set Rx mode: %d", result); + } + else { + kaweth_dbg("Set Rx mode to %d", packet_filter_bitmap); + } + } +} + +/**************************************************************** + * kaweth_netdev_stats + ****************************************************************/ +static struct net_device_stats *kaweth_netdev_stats(struct net_device *dev) +{ + return &((struct kaweth_device *)dev->priv)->stats; +} + +/**************************************************************** + * kaweth_tx_timeout + ****************************************************************/ +static void kaweth_tx_timeout(struct net_device *net) +{ + struct kaweth_device *kaweth = net->priv; + + kaweth_warn("%s: Tx timed out. Resetting.", net->name); + kaweth->stats.tx_errors++; + net->trans_start = jiffies; + + usb_unlink_urb(kaweth->tx_urb); + + netif_wake_queue(net); +} + +/**************************************************************** + * kaweth_probe + ****************************************************************/ +static void *kaweth_probe( + struct usb_device *dev, /* the device */ + unsigned ifnum, /* what interface */ + const struct usb_device_id *id /* from id_table */ + ) +{ + struct kaweth_device *kaweth; + const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + int result = 0; + + kaweth_dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x", + dev->devnum, + (int)dev->descriptor.idVendor, + (int)dev->descriptor.idProduct, + (int)dev->descriptor.bcdDevice); + + kaweth_dbg("Device at %p", dev); + + kaweth_dbg("Descriptor length: %x type: %x", + (int)dev->descriptor.bLength, + (int)dev->descriptor.bDescriptorType); + + if(!(kaweth = kmalloc(sizeof(struct kaweth_device), GFP_KERNEL))) { + kaweth_dbg("out of memory allocating device structure\n"); + return NULL; + } + + memset(kaweth, 0, sizeof(struct kaweth_device)); + + kaweth->dev = dev; + kaweth->status = 0; + kaweth->net = NULL; + kaweth->device_lock = SPIN_LOCK_UNLOCKED; + + kaweth_dbg("Resetting."); + + kaweth_reset(kaweth); + + /* + * If high byte of bcdDevice is nonzero, firmware is already + * downloaded. Don't try to do it again, or we'll hang the device. + */ + + if (dev->descriptor.bcdDevice >> 8) { + kaweth_info("Firmware present in device."); + } else { + /* Download the firmware */ + kaweth_info("Downloading firmware..."); + if ((result = kaweth_download_firmware(kaweth, + kaweth_new_code, + len_kaweth_new_code, + 100, + 2)) < 0) { + kaweth_err("Error downloading firmware (%d)", result); + kfree(kaweth); + return NULL; + } + + if ((result = kaweth_download_firmware(kaweth, + kaweth_new_code_fix, + len_kaweth_new_code_fix, + 100, + 3)) < 0) { + kaweth_err("Error downloading firmware fix (%d)", result); + kfree(kaweth); + return NULL; + } + + if ((result = kaweth_download_firmware(kaweth, + kaweth_trigger_code, + len_kaweth_trigger_code, + 126, + 2)) < 0) { + kaweth_err("Error downloading trigger code (%d)", result); + kfree(kaweth); + return NULL; + } + + if ((result = kaweth_download_firmware(kaweth, + kaweth_trigger_code_fix, + len_kaweth_trigger_code_fix, + 126, + 3)) < 0) { + kaweth_err("Error downloading trigger code fix (%d)", result); + kfree(kaweth); + return NULL; + } + + + if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) { + kaweth_err("Error triggering firmware (%d)", result); + kfree(kaweth); + return NULL; + } + + /* Device will now disappear for a moment... */ + kaweth_info("Firmware loaded. I'll be back..."); + return NULL; + } + + result = kaweth_read_configuration(kaweth); + + if(result < 0) { + kaweth_err("Error reading configuration (%d), no net device created", result); + kfree(kaweth); + return NULL; + } + + kaweth_info("Statistics collection: %x", kaweth->configuration.statistics_mask); + kaweth_info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1)); + kaweth_info("MTU: %d", kaweth->configuration.segment_size); + kaweth_info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", + (int)kaweth->configuration.hw_addr[0], + (int)kaweth->configuration.hw_addr[1], + (int)kaweth->configuration.hw_addr[2], + (int)kaweth->configuration.hw_addr[3], + (int)kaweth->configuration.hw_addr[4], + (int)kaweth->configuration.hw_addr[5]); + + if(!memcmp(&kaweth->configuration.hw_addr, + &bcast_addr, + sizeof(bcast_addr))) { + kaweth_err("Firmware not functioning properly, no net device created"); + kfree(kaweth); + return NULL; + } + + if(kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE) < 0) { + kaweth_dbg("Error setting URB size"); + return kaweth; + } + + if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) { + kaweth_err("Error setting SOFS wait"); + return kaweth; + } + + result = kaweth_set_receive_filter(kaweth, + KAWETH_PACKET_FILTER_DIRECTED | + KAWETH_PACKET_FILTER_BROADCAST | + KAWETH_PACKET_FILTER_MULTICAST); + + if(result < 0) { + kaweth_err("Error setting receive filter"); + return kaweth; + } + + kaweth_dbg("Initializing net device."); + + kaweth->tx_urb = usb_alloc_urb(0); + kaweth->rx_urb = usb_alloc_urb(0); + + kaweth->net = init_etherdev(0, 0); + + memcpy(kaweth->net->broadcast, &bcast_addr, sizeof(bcast_addr)); + memcpy(kaweth->net->dev_addr, + &kaweth->configuration.hw_addr, + sizeof(kaweth->configuration.hw_addr)); + + kaweth->net->priv = kaweth; + kaweth->net->open = kaweth_open; + kaweth->net->stop = kaweth_close; + + kaweth->net->watchdog_timeo = KAWETH_TX_TIMEOUT; + kaweth->net->tx_timeout = kaweth_tx_timeout; + + kaweth->net->do_ioctl = kaweth_ioctl; + kaweth->net->hard_start_xmit = kaweth_start_xmit; + kaweth->net->set_multicast_list = kaweth_set_rx_mode; + kaweth->net->get_stats = kaweth_netdev_stats; + kaweth->net->mtu = kaweth->configuration.segment_size; + + memset(&kaweth->stats, 0, sizeof(kaweth->stats)); + + kaweth_info("kaweth interface created at %s", kaweth->net->name); + + kaweth_dbg("Kaweth probe returning."); + + return kaweth; +} + +/**************************************************************** + * kaweth_disconnect + ****************************************************************/ +static void kaweth_disconnect(struct usb_device *dev, void *ptr) +{ + struct kaweth_device *kaweth = ptr; + + kaweth_info("Unregistering"); + + if (!kaweth) { + kaweth_warn("unregistering non-existant device"); + return; + } + + if(kaweth->net) { + if(kaweth->net->flags & IFF_UP) { + kaweth_dbg("Closing net device"); + dev_close(kaweth->net); + } + + kaweth_dbg("Unregistering net device"); + unregister_netdev(kaweth->net); + } + + usb_free_urb(kaweth->rx_urb); + usb_free_urb(kaweth->tx_urb); + + kfree(kaweth); +} + + +/*-------------------------------------------------------------------* + * completion handler for compatibility wrappers (sync control/bulk) * + *-------------------------------------------------------------------*/ +static void usb_api_blocking_completion(urb_t *urb) +{ + api_wrapper_data *awd = (api_wrapper_data *)urb->context; + + if (waitqueue_active(awd->wakeup)) { + wake_up(awd->wakeup); + } + +} + +/*-------------------------------------------------------------------* + * COMPATIBILITY STUFF * + *-------------------------------------------------------------------*/ + +// Starts urb and waits for completion or timeout +static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length) +{ + DECLARE_WAITQUEUE(wait, current); + DECLARE_WAIT_QUEUE_HEAD(wqh); + api_wrapper_data awd; + int status; + + awd.wakeup = &wqh; + init_waitqueue_head(&wqh); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&wqh, &wait); + urb->context = &awd; + status = usb_submit_urb(urb); + if (status) { + // something went wrong + usb_free_urb(urb); + current->state = TASK_RUNNING; + remove_wait_queue(&wqh, &wait); + return status; + } + + if (urb->status == -EINPROGRESS) { + while (timeout && urb->status == -EINPROGRESS) + status = timeout = schedule_timeout(timeout); + } + else { + status = 1; + } + + current->state = TASK_RUNNING; + remove_wait_queue(&wqh, &wait); + + if (!status) { + // timeout + kaweth_warn("usb_control/bulk_msg: timeout"); + usb_unlink_urb(urb); // remove urb safely + status = -ETIMEDOUT; + } + else { + status = urb->status; + } + + if (actual_length) { + *actual_length = urb->actual_length; + } + + usb_free_urb(urb); + return status; +} + +/*-------------------------------------------------------------------*/ +// returns status (negative) or length (positive) +int kaweth_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, + devrequest *cmd, void *data, int len, int timeout) +{ + urb_t *urb; + int retv; + int length; + + urb = usb_alloc_urb(0); + if (!urb) + return -ENOMEM; + + FILL_CONTROL_URB(urb, usb_dev, pipe, (unsigned char*)cmd, data, + len, (usb_complete_t)usb_api_blocking_completion,0); + + retv = usb_start_wait_urb(urb, timeout, &length); + if (retv < 0) { + return retv; + } + else { + return length; + } +} + + +/**************************************************************** + * kaweth_init + ****************************************************************/ +int __init kaweth_init(void) +{ + kaweth_dbg("Driver loading"); + return usb_register(&kaweth_driver); +} + +/**************************************************************** + * kaweth_exit + ****************************************************************/ +void __exit kaweth_exit(void) +{ + usb_deregister(&kaweth_driver); +} + +module_init(kaweth_init); +module_exit(kaweth_exit); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/kawethfw.h linux.ac/drivers/usb/kawethfw.h --- linux.vanilla/drivers/usb/kawethfw.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/usb/kawethfw.h Tue Apr 3 17:55:07 2001 @@ -0,0 +1,557 @@ +/******************************************/ +/* NOTE: B6/C3 is data header signature */ +/* 0xAA/0xBB is data length = total */ +/* bytes - 7, 0xCC is type, 0xDD is */ +/* interrupt to use. */ +/******************************************/ + +/**************************************************************** + * kaweth_trigger_code + ****************************************************************/ +static __u8 kaweth_trigger_code[] = +{ + 0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD, + 0xc8, 0x07, 0xa0, 0x00, 0xf0, 0x07, 0x5e, 0x00, + 0x06, 0x00, 0xf0, 0x07, 0x0a, 0x00, 0x08, 0x00, + 0xf0, 0x09, 0x00, 0x00, 0x02, 0x00, 0xe7, 0x07, + 0x36, 0x00, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, + 0x04, 0x00, 0xe7, 0x07, 0x50, 0xc3, 0x10, 0xc0, + 0xf0, 0x09, 0x0e, 0xc0, 0x00, 0x00, 0xe7, 0x87, + 0x01, 0x00, 0x0e, 0xc0, 0x97, 0xcf, 0xd7, 0x09, + 0x00, 0xc0, 0x17, 0x02, 0xc8, 0x07, 0xa0, 0x00, + 0xe7, 0x17, 0x50, 0xc3, 0x10, 0xc0, 0x30, 0xd8, + 0x04, 0x00, 0x30, 0x5c, 0x08, 0x00, 0x04, 0x00, + 0xb0, 0xc0, 0x06, 0x00, 0xc8, 0x05, 0xe7, 0x05, + 0x00, 0xc0, 0xc0, 0xdf, 0x97, 0xcf, 0x49, 0xaf, + 0xc0, 0x07, 0x00, 0x00, 0x60, 0xaf, 0x4a, 0xaf, + 0x00, 0x0c, 0x0c, 0x00, 0x40, 0xd2, 0x00, 0x1c, + 0x0c, 0x00, 0x40, 0xd2, 0x30, 0x00, 0x08, 0x00, + 0xf0, 0x07, 0x00, 0x00, 0x04, 0x00, 0xf0, 0x07, + 0x86, 0x00, 0x06, 0x00, 0x67, 0xcf, 0x27, 0x0c, + 0x02, 0x00, 0x00, 0x00, 0x27, 0x0c, 0x00, 0x00, + 0x0e, 0xc0, 0x49, 0xaf, 0x64, 0xaf, 0xc0, 0x07, + 0x00, 0x00, 0x4b, 0xaf, 0x4a, 0xaf, 0x5a, 0xcf, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x94, 0x00, 0x05, 0x00, + 0x00, 0x00 +}; +/**************************************************************** + * kaweth_trigger_code_fix + ****************************************************************/ +static __u8 kaweth_trigger_code_fix[] = +{ + 0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD, + 0x02, 0x00, 0x06, 0x00, 0x18, 0x00, 0x3e, 0x00, + 0x80, 0x00, 0x98, 0x00, 0xaa, 0x00, + 0x00, 0x00 +}; + +/**************************************************************** + * kaweth_new_code + ****************************************************************/ +static __u8 kaweth_new_code[] = +{ + 0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD, + 0x9f, 0xcf, 0xde, 0x06, 0xe7, 0x57, 0x00, 0x00, + 0xc4, 0x06, 0x97, 0xc1, 0xe7, 0x67, 0xff, 0x1f, + 0x28, 0xc0, 0xe7, 0x87, 0x00, 0x04, 0x24, 0xc0, + 0xe7, 0x67, 0xff, 0xf9, 0x22, 0xc0, 0x97, 0xcf, + 0xd7, 0x09, 0x00, 0xc0, 0xe7, 0x09, 0xa2, 0xc0, + 0xbe, 0x06, 0x9f, 0xaf, 0x36, 0x00, 0xe7, 0x05, + 0x00, 0xc0, 0xa7, 0xcf, 0xbc, 0x06, 0x97, 0xcf, + 0xe7, 0x57, 0x00, 0x00, 0xb8, 0x06, 0xa7, 0xa1, + 0xb8, 0x06, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00, + 0x14, 0x08, 0x0a, 0xc0, 0xe7, 0x57, 0x00, 0x00, + 0xa4, 0xc0, 0xa7, 0xc0, 0x7a, 0x06, 0x9f, 0xaf, + 0x92, 0x07, 0xe7, 0x07, 0x00, 0x00, 0x14, 0x08, + 0xe7, 0x57, 0xff, 0xff, 0xba, 0x06, 0x9f, 0xa0, + 0x38, 0x00, 0xe7, 0x59, 0xba, 0x06, 0xbe, 0x06, + 0x9f, 0xa0, 0x38, 0x00, 0xc8, 0x09, 0xca, 0x06, + 0x08, 0x62, 0x9f, 0xa1, 0x36, 0x08, 0xc0, 0x09, + 0x76, 0x06, 0x00, 0x60, 0xa7, 0xc0, 0x7a, 0x06, + 0x9f, 0xaf, 0xcc, 0x02, 0xe7, 0x57, 0x00, 0x00, + 0xb8, 0x06, 0xa7, 0xc1, 0x7a, 0x06, 0x9f, 0xaf, + 0x04, 0x00, 0xe7, 0x57, 0x00, 0x00, 0x8e, 0x06, + 0x0a, 0xc1, 0xe7, 0x09, 0x20, 0xc0, 0x10, 0x08, + 0xe7, 0xd0, 0x10, 0x08, 0xe7, 0x67, 0x40, 0x00, + 0x10, 0x08, 0x9f, 0xaf, 0x92, 0x0c, 0xc0, 0x09, + 0xd0, 0x06, 0x00, 0x60, 0x05, 0xc4, 0xc0, 0x59, + 0xbe, 0x06, 0x02, 0xc0, 0x9f, 0xaf, 0xec, 0x00, + 0x9f, 0xaf, 0x34, 0x02, 0xe7, 0x57, 0x00, 0x00, + 0xa6, 0x06, 0x9f, 0xa0, 0x7a, 0x02, 0xa7, 0xcf, + 0x7a, 0x06, 0x48, 0x02, 0xe7, 0x09, 0xbe, 0x06, + 0xd0, 0x06, 0xc8, 0x37, 0x04, 0x00, 0x9f, 0xaf, + 0x08, 0x03, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00, + 0xce, 0x06, 0x97, 0xc0, 0xd7, 0x09, 0x00, 0xc0, + 0xc1, 0xdf, 0xc8, 0x09, 0xc6, 0x06, 0x08, 0x62, + 0x14, 0xc0, 0x27, 0x04, 0xc6, 0x06, 0x10, 0x94, + 0xf0, 0x07, 0x10, 0x08, 0x02, 0x00, 0xc1, 0x07, + 0x01, 0x00, 0x70, 0x00, 0x04, 0x00, 0xf0, 0x07, + 0x30, 0x01, 0x06, 0x00, 0x50, 0xaf, 0xe7, 0x07, + 0xff, 0xff, 0xd0, 0x06, 0xe7, 0x07, 0x00, 0x00, + 0xce, 0x06, 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf, + 0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x48, 0x02, + 0xd0, 0x09, 0xc6, 0x06, 0x27, 0x02, 0xc6, 0x06, + 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf, 0x48, 0x02, + 0xc8, 0x37, 0x04, 0x00, 0x00, 0x0c, 0x0c, 0x00, + 0x00, 0x60, 0x21, 0xc0, 0xc0, 0x37, 0x3e, 0x00, + 0x23, 0xc9, 0xc0, 0x57, 0xb4, 0x05, 0x1b, 0xc8, + 0xc0, 0x17, 0x3f, 0x00, 0xc0, 0x67, 0xc0, 0xff, + 0x30, 0x00, 0x08, 0x00, 0xf0, 0x07, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x02, 0xc0, 0x17, 0x4c, 0x00, + 0x30, 0x00, 0x06, 0x00, 0xf0, 0x07, 0xa0, 0x01, + 0x0a, 0x00, 0x48, 0x02, 0xc1, 0x07, 0x02, 0x00, + 0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x51, 0xaf, + 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf, 0x9f, 0xaf, + 0x08, 0x03, 0x9f, 0xaf, 0x7a, 0x02, 0x97, 0xcf, + 0x9f, 0xaf, 0x7a, 0x02, 0xc9, 0x37, 0x04, 0x00, + 0xc1, 0xdf, 0xc8, 0x09, 0xa2, 0x06, 0x50, 0x02, + 0x67, 0x02, 0xa2, 0x06, 0xd1, 0x07, 0x00, 0x00, + 0x27, 0xd8, 0xaa, 0x06, 0xc0, 0xdf, 0x9f, 0xaf, + 0xc4, 0x01, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00, + 0xd2, 0x06, 0x97, 0xc1, 0xe7, 0x57, 0x01, 0x00, + 0xa8, 0x06, 0x97, 0xc0, 0xc8, 0x09, 0xa0, 0x06, + 0x08, 0x62, 0x97, 0xc0, 0x00, 0x02, 0xc0, 0x17, + 0x0e, 0x00, 0x27, 0x00, 0x34, 0x01, 0x27, 0x0c, + 0x0c, 0x00, 0x36, 0x01, 0xe7, 0x07, 0x50, 0xc3, + 0x12, 0xc0, 0xe7, 0x07, 0xcc, 0x0b, 0x02, 0x00, + 0xe7, 0x07, 0x01, 0x00, 0xa8, 0x06, 0xe7, 0x07, + 0x05, 0x00, 0x90, 0xc0, 0x97, 0xcf, 0xc8, 0x09, + 0xa4, 0x06, 0x08, 0x62, 0x02, 0xc0, 0x10, 0x64, + 0x07, 0xc1, 0xe7, 0x07, 0x00, 0x00, 0x9e, 0x06, + 0xe7, 0x07, 0x72, 0x04, 0x24, 0x00, 0x97, 0xcf, + 0x27, 0x04, 0xa4, 0x06, 0xc8, 0x17, 0x0e, 0x00, + 0x27, 0x02, 0x9e, 0x06, 0xe7, 0x07, 0x80, 0x04, + 0x24, 0x00, 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0, + 0xc1, 0xdf, 0xe7, 0x57, 0x00, 0x00, 0x90, 0x06, + 0x13, 0xc1, 0x9f, 0xaf, 0x06, 0x02, 0xe7, 0x57, + 0x00, 0x00, 0x9e, 0x06, 0x13, 0xc0, 0xe7, 0x09, + 0x9e, 0x06, 0x30, 0x01, 0xe7, 0x07, 0xf2, 0x05, + 0x32, 0x01, 0xe7, 0x07, 0x10, 0x00, 0x96, 0xc0, + 0xe7, 0x09, 0x9e, 0x06, 0x90, 0x06, 0x04, 0xcf, + 0xe7, 0x57, 0x00, 0x00, 0x9e, 0x06, 0x02, 0xc1, + 0x9f, 0xaf, 0x06, 0x02, 0xe7, 0x05, 0x00, 0xc0, + 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, + 0x08, 0x92, 0xe7, 0x57, 0x02, 0x00, 0xaa, 0x06, + 0x02, 0xc3, 0xc8, 0x09, 0xa4, 0x06, 0x27, 0x02, + 0xa6, 0x06, 0x08, 0x62, 0x03, 0xc1, 0xe7, 0x05, + 0x00, 0xc0, 0x97, 0xcf, 0x27, 0x04, 0xa4, 0x06, + 0xe7, 0x05, 0x00, 0xc0, 0xf0, 0x07, 0x40, 0x00, + 0x08, 0x00, 0xf0, 0x07, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x02, 0xc0, 0x17, 0x0c, 0x00, 0x30, 0x00, + 0x06, 0x00, 0xf0, 0x07, 0x46, 0x01, 0x0a, 0x00, + 0xc8, 0x17, 0x04, 0x00, 0xc1, 0x07, 0x02, 0x00, + 0x51, 0xaf, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00, + 0x96, 0x06, 0x97, 0xc0, 0xc1, 0xdf, 0xc8, 0x09, + 0x96, 0x06, 0x27, 0x04, 0x96, 0x06, 0x27, 0x52, + 0x98, 0x06, 0x03, 0xc1, 0xe7, 0x07, 0x96, 0x06, + 0x98, 0x06, 0xc0, 0xdf, 0x17, 0x02, 0xc8, 0x17, + 0x0e, 0x00, 0x9f, 0xaf, 0xba, 0x03, 0xc8, 0x05, + 0x00, 0x60, 0x03, 0xc0, 0x9f, 0xaf, 0x24, 0x03, + 0x97, 0xcf, 0x9f, 0xaf, 0x08, 0x03, 0x97, 0xcf, + 0x57, 0x02, 0xc9, 0x07, 0xa4, 0x06, 0xd7, 0x09, + 0x00, 0xc0, 0xc1, 0xdf, 0x08, 0x62, 0x1b, 0xc0, + 0x50, 0x04, 0x11, 0x02, 0xe7, 0x05, 0x00, 0xc0, + 0xc9, 0x05, 0x97, 0xcf, 0x97, 0x02, 0xca, 0x09, + 0xd6, 0x06, 0xf2, 0x17, 0x01, 0x00, 0x04, 0x00, + 0xf2, 0x27, 0x00, 0x00, 0x06, 0x00, 0xca, 0x17, + 0x2c, 0x00, 0xf8, 0x77, 0x01, 0x00, 0x0e, 0x00, + 0x06, 0xc0, 0xca, 0xd9, 0xf8, 0x57, 0xff, 0x00, + 0x0e, 0x00, 0x01, 0xc1, 0xca, 0xd9, 0x22, 0x1c, + 0x0c, 0x00, 0xe2, 0x27, 0x00, 0x00, 0xe2, 0x17, + 0x01, 0x00, 0xe2, 0x27, 0x00, 0x00, 0xca, 0x05, + 0x00, 0x0c, 0x0c, 0x00, 0xc0, 0x17, 0x41, 0x00, + 0xc0, 0x67, 0xc0, 0xff, 0x30, 0x00, 0x08, 0x00, + 0x00, 0x02, 0xc0, 0x17, 0x0c, 0x00, 0x30, 0x00, + 0x06, 0x00, 0xf0, 0x07, 0xda, 0x00, 0x0a, 0x00, + 0xf0, 0x07, 0x00, 0x00, 0x04, 0x00, 0x00, 0x0c, + 0x08, 0x00, 0x40, 0xd1, 0x01, 0x00, 0xc0, 0x19, + 0xce, 0x06, 0xc0, 0x59, 0xc2, 0x06, 0x04, 0xc9, + 0x49, 0xaf, 0x9f, 0xaf, 0xec, 0x00, 0x4a, 0xaf, + 0x67, 0x10, 0xce, 0x06, 0xc8, 0x17, 0x04, 0x00, + 0xc1, 0x07, 0x01, 0x00, 0xd7, 0x09, 0x00, 0xc0, + 0xc1, 0xdf, 0x50, 0xaf, 0xe7, 0x05, 0x00, 0xc0, + 0x97, 0xcf, 0xc0, 0x07, 0x01, 0x00, 0xc1, 0x09, + 0xac, 0x06, 0xc1, 0x77, 0x01, 0x00, 0x97, 0xc1, + 0xd8, 0x77, 0x01, 0x00, 0x12, 0xc0, 0xc9, 0x07, + 0x6a, 0x06, 0x9f, 0xaf, 0x08, 0x04, 0x04, 0xc1, + 0xc1, 0x77, 0x08, 0x00, 0x13, 0xc0, 0x97, 0xcf, + 0xc1, 0x77, 0x02, 0x00, 0x97, 0xc1, 0xc1, 0x77, + 0x10, 0x00, 0x0c, 0xc0, 0x9f, 0xaf, 0x2c, 0x04, + 0x97, 0xcf, 0xc1, 0x77, 0x04, 0x00, 0x06, 0xc0, + 0xc9, 0x07, 0x70, 0x06, 0x9f, 0xaf, 0x08, 0x04, + 0x97, 0xc0, 0x00, 0xcf, 0x00, 0x90, 0x97, 0xcf, + 0x50, 0x54, 0x97, 0xc1, 0x70, 0x5c, 0x02, 0x00, + 0x02, 0x00, 0x97, 0xc1, 0x70, 0x5c, 0x04, 0x00, + 0x04, 0x00, 0x97, 0xcf, 0x80, 0x01, 0xc0, 0x00, + 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, 0x0c, 0x00, + 0x06, 0x00, 0x00, 0x00, 0xcb, 0x09, 0xb2, 0x06, + 0xcc, 0x09, 0xb4, 0x06, 0x0b, 0x53, 0x11, 0xc0, + 0xc9, 0x02, 0xca, 0x07, 0x1c, 0x04, 0x9f, 0xaf, + 0x08, 0x04, 0x97, 0xc0, 0x0a, 0xc8, 0x82, 0x08, + 0x0a, 0xcf, 0x82, 0x08, 0x9f, 0xaf, 0x08, 0x04, + 0x97, 0xc0, 0x05, 0xc2, 0x89, 0x30, 0x82, 0x60, + 0x78, 0xc1, 0x00, 0x90, 0x97, 0xcf, 0x89, 0x10, + 0x09, 0x53, 0x79, 0xc2, 0x89, 0x30, 0x82, 0x08, + 0x7a, 0xcf, 0xc0, 0xdf, 0x97, 0xcf, 0xc0, 0xdf, + 0x97, 0xcf, 0xe7, 0x09, 0x96, 0xc0, 0x92, 0x06, + 0xe7, 0x09, 0x98, 0xc0, 0x94, 0x06, 0x0f, 0xcf, + 0xe7, 0x09, 0x96, 0xc0, 0x92, 0x06, 0xe7, 0x09, + 0x98, 0xc0, 0x94, 0x06, 0xe7, 0x09, 0x9e, 0x06, + 0x30, 0x01, 0xe7, 0x07, 0xf2, 0x05, 0x32, 0x01, + 0xe7, 0x07, 0x10, 0x00, 0x96, 0xc0, 0xd7, 0x09, + 0x00, 0xc0, 0x17, 0x02, 0xc8, 0x09, 0x90, 0x06, + 0xc8, 0x37, 0x0e, 0x00, 0xe7, 0x77, 0x2a, 0x00, + 0x92, 0x06, 0x30, 0xc0, 0x97, 0x02, 0xca, 0x09, + 0xd6, 0x06, 0xe7, 0x77, 0x20, 0x00, 0x92, 0x06, + 0x0e, 0xc0, 0xf2, 0x17, 0x01, 0x00, 0x10, 0x00, + 0xf2, 0x27, 0x00, 0x00, 0x12, 0x00, 0xe7, 0x77, + 0x0a, 0x00, 0x92, 0x06, 0xca, 0x05, 0x1e, 0xc0, + 0x97, 0x02, 0xca, 0x09, 0xd6, 0x06, 0xf2, 0x17, + 0x01, 0x00, 0x0c, 0x00, 0xf2, 0x27, 0x00, 0x00, + 0x0e, 0x00, 0xe7, 0x77, 0x02, 0x00, 0x92, 0x06, + 0x07, 0xc0, 0xf2, 0x17, 0x01, 0x00, 0x44, 0x00, + 0xf2, 0x27, 0x00, 0x00, 0x46, 0x00, 0x06, 0xcf, + 0xf2, 0x17, 0x01, 0x00, 0x60, 0x00, 0xf2, 0x27, + 0x00, 0x00, 0x62, 0x00, 0xca, 0x05, 0x9f, 0xaf, + 0x08, 0x03, 0x0f, 0xcf, 0x57, 0x02, 0x09, 0x02, + 0xf1, 0x09, 0x94, 0x06, 0x0c, 0x00, 0xf1, 0xda, + 0x0c, 0x00, 0xc8, 0x09, 0x98, 0x06, 0x50, 0x02, + 0x67, 0x02, 0x98, 0x06, 0xd1, 0x07, 0x00, 0x00, + 0xc9, 0x05, 0xe7, 0x09, 0x9e, 0x06, 0x90, 0x06, + 0xe7, 0x57, 0x00, 0x00, 0x90, 0x06, 0x02, 0xc0, + 0x9f, 0xaf, 0x06, 0x02, 0xc8, 0x05, 0xe7, 0x05, + 0x00, 0xc0, 0xc0, 0xdf, 0x97, 0xcf, 0xd7, 0x09, + 0x00, 0xc0, 0x17, 0x00, 0x17, 0x02, 0x97, 0x02, + 0xc0, 0x09, 0x92, 0xc0, 0xe7, 0x07, 0x04, 0x00, + 0x90, 0xc0, 0xca, 0x09, 0xd6, 0x06, 0xe7, 0x07, + 0x00, 0x00, 0xa8, 0x06, 0xe7, 0x07, 0x6a, 0x04, + 0x02, 0x00, 0xc0, 0x77, 0x02, 0x00, 0x08, 0xc0, + 0xf2, 0x17, 0x01, 0x00, 0x50, 0x00, 0xf2, 0x27, + 0x00, 0x00, 0x52, 0x00, 0x9f, 0xcf, 0x24, 0x06, + 0xc0, 0x77, 0x10, 0x00, 0x06, 0xc0, 0xf2, 0x17, + 0x01, 0x00, 0x58, 0x00, 0xf2, 0x27, 0x00, 0x00, + 0x5a, 0x00, 0xc0, 0x77, 0x80, 0x00, 0x06, 0xc0, + 0xf2, 0x17, 0x01, 0x00, 0x70, 0x00, 0xf2, 0x27, + 0x00, 0x00, 0x72, 0x00, 0xc0, 0x77, 0x08, 0x00, + 0x1d, 0xc1, 0xf2, 0x17, 0x01, 0x00, 0x08, 0x00, + 0xf2, 0x27, 0x00, 0x00, 0x0a, 0x00, 0xc0, 0x77, + 0x00, 0x02, 0x06, 0xc0, 0xf2, 0x17, 0x01, 0x00, + 0x64, 0x00, 0xf2, 0x27, 0x00, 0x00, 0x66, 0x00, + 0xc0, 0x77, 0x40, 0x00, 0x06, 0xc0, 0xf2, 0x17, + 0x01, 0x00, 0x5c, 0x00, 0xf2, 0x27, 0x00, 0x00, + 0x5e, 0x00, 0xc0, 0x77, 0x01, 0x00, 0x01, 0xc0, + 0x1b, 0xcf, 0x1a, 0xcf, 0xf2, 0x17, 0x01, 0x00, + 0x00, 0x00, 0xf2, 0x27, 0x00, 0x00, 0x02, 0x00, + 0xc8, 0x09, 0x34, 0x01, 0xca, 0x17, 0x14, 0x00, + 0xd8, 0x77, 0x01, 0x00, 0x05, 0xc0, 0xca, 0xd9, + 0xd8, 0x57, 0xff, 0x00, 0x01, 0xc0, 0xca, 0xd9, + 0xe2, 0x19, 0x94, 0xc0, 0xe2, 0x27, 0x00, 0x00, + 0xe2, 0x17, 0x01, 0x00, 0xe2, 0x27, 0x00, 0x00, + 0x9f, 0xaf, 0x40, 0x06, 0x9f, 0xaf, 0xc4, 0x01, + 0xe7, 0x57, 0x00, 0x00, 0xd2, 0x06, 0x9f, 0xa1, + 0x0e, 0x0a, 0xca, 0x05, 0xc8, 0x05, 0xc0, 0x05, + 0xe7, 0x05, 0x00, 0xc0, 0xc0, 0xdf, 0x97, 0xcf, + 0xc8, 0x09, 0xa0, 0x06, 0x08, 0x62, 0x97, 0xc0, + 0x27, 0x04, 0xa0, 0x06, 0x27, 0x52, 0xa2, 0x06, + 0x03, 0xc1, 0xe7, 0x07, 0xa0, 0x06, 0xa2, 0x06, + 0x9f, 0xaf, 0x08, 0x03, 0xe7, 0x57, 0x00, 0x00, + 0xaa, 0x06, 0x02, 0xc0, 0x27, 0xda, 0xaa, 0x06, + 0x97, 0xcf, 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, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xfb, 0x13, 0xe7, 0x57, + 0x00, 0x80, 0xb2, 0x00, 0x06, 0xc2, 0xe7, 0x07, + 0xee, 0x0b, 0x12, 0x00, 0xe7, 0x07, 0x34, 0x0c, + 0xb2, 0x00, 0xe7, 0x07, 0xc6, 0x07, 0xf2, 0x02, + 0xc8, 0x09, 0xb4, 0x00, 0xf8, 0x07, 0x02, 0x00, + 0x0d, 0x00, 0xd7, 0x09, 0x0e, 0xc0, 0xe7, 0x07, + 0x00, 0x00, 0x0e, 0xc0, 0xc8, 0x09, 0xde, 0x00, + 0xc8, 0x17, 0x09, 0x00, 0xc9, 0x07, 0xda, 0x06, + 0xc0, 0x07, 0x04, 0x00, 0x68, 0x0a, 0x00, 0xda, + 0x7d, 0xc1, 0xe7, 0x09, 0xc0, 0x00, 0x7c, 0x06, + 0xe7, 0x09, 0xbe, 0x00, 0x78, 0x06, 0xe7, 0x09, + 0x10, 0x00, 0xbc, 0x06, 0xc8, 0x07, 0xd6, 0x07, + 0x9f, 0xaf, 0xae, 0x07, 0x9f, 0xaf, 0x00, 0x0a, + 0xc8, 0x09, 0xde, 0x00, 0x00, 0x0e, 0x0f, 0x00, + 0x41, 0x90, 0x9f, 0xde, 0x06, 0x00, 0x44, 0xaf, + 0x27, 0x00, 0xb2, 0x06, 0x27, 0x00, 0xb4, 0x06, + 0x27, 0x00, 0xb6, 0x06, 0xc0, 0x07, 0x74, 0x00, + 0x44, 0xaf, 0x27, 0x00, 0xd6, 0x06, 0x08, 0x00, + 0x00, 0x90, 0xc1, 0x07, 0x3a, 0x00, 0x20, 0x00, + 0x01, 0xda, 0x7d, 0xc1, 0x9f, 0xaf, 0xba, 0x09, + 0xc0, 0x07, 0x44, 0x00, 0x48, 0xaf, 0x27, 0x00, + 0x7a, 0x06, 0x9f, 0xaf, 0x96, 0x0a, 0xe7, 0x07, + 0x01, 0x00, 0xc0, 0x06, 0xe7, 0x05, 0x0e, 0xc0, + 0x97, 0xcf, 0x49, 0xaf, 0xe7, 0x87, 0x43, 0x00, + 0x0e, 0xc0, 0xe7, 0x07, 0xff, 0xff, 0xbe, 0x06, + 0x9f, 0xaf, 0xae, 0x0a, 0xc0, 0x07, 0x01, 0x00, + 0x60, 0xaf, 0x4a, 0xaf, 0x97, 0xcf, 0x00, 0x08, + 0x09, 0x08, 0x11, 0x08, 0x00, 0xda, 0x7c, 0xc1, + 0x97, 0xcf, 0x67, 0x04, 0xcc, 0x02, 0xc0, 0xdf, + 0x51, 0x94, 0xb1, 0xaf, 0x06, 0x00, 0xc1, 0xdf, + 0xc9, 0x09, 0xcc, 0x02, 0x49, 0x62, 0x75, 0xc1, + 0xc0, 0xdf, 0xa7, 0xcf, 0xd6, 0x02, 0x0e, 0x00, + 0x24, 0x00, 0x80, 0x04, 0x22, 0x00, 0x4e, 0x05, + 0xd0, 0x00, 0x0e, 0x0a, 0xaa, 0x00, 0x30, 0x08, + 0xbe, 0x00, 0x4a, 0x0a, 0x10, 0x00, 0x20, 0x00, + 0x04, 0x00, 0x6e, 0x04, 0x02, 0x00, 0x6a, 0x04, + 0x06, 0x00, 0x00, 0x00, 0x24, 0xc0, 0x04, 0x04, + 0x28, 0xc0, 0xfe, 0xfb, 0x1e, 0xc0, 0x00, 0x04, + 0x22, 0xc0, 0xff, 0xf4, 0xc0, 0x00, 0x90, 0x09, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x56, 0x08, + 0x60, 0x08, 0xd0, 0x08, 0xda, 0x08, 0x00, 0x09, + 0x04, 0x09, 0x08, 0x09, 0x32, 0x09, 0x42, 0x09, + 0x50, 0x09, 0x52, 0x09, 0x5a, 0x09, 0x5a, 0x09, + 0x27, 0x02, 0xca, 0x06, 0x97, 0xcf, 0xe7, 0x07, + 0x00, 0x00, 0xca, 0x06, 0x0a, 0x0e, 0x01, 0x00, + 0xca, 0x57, 0x0e, 0x00, 0x9f, 0xc3, 0x5a, 0x09, + 0xca, 0x37, 0x00, 0x00, 0x9f, 0xc2, 0x5a, 0x09, + 0x0a, 0xd2, 0xb2, 0xcf, 0x16, 0x08, 0xc8, 0x09, + 0xde, 0x00, 0x07, 0x06, 0x9f, 0xcf, 0x6c, 0x09, + 0x17, 0x02, 0xc8, 0x09, 0xde, 0x00, 0x00, 0x0e, + 0x0f, 0x00, 0x41, 0x90, 0x9f, 0xde, 0x06, 0x00, + 0xc8, 0x05, 0x30, 0x50, 0x06, 0x00, 0x9f, 0xc8, + 0x5a, 0x09, 0x27, 0x0c, 0x02, 0x00, 0xb0, 0x06, + 0xc0, 0x09, 0xb2, 0x06, 0x27, 0x00, 0xb4, 0x06, + 0xe7, 0x07, 0x00, 0x00, 0xae, 0x06, 0x27, 0x00, + 0x80, 0x06, 0x00, 0x1c, 0x06, 0x00, 0x27, 0x00, + 0xb6, 0x06, 0x41, 0x90, 0x67, 0x50, 0xb0, 0x06, + 0x0d, 0xc0, 0x67, 0x00, 0x7e, 0x06, 0x27, 0x0c, + 0x06, 0x00, 0x82, 0x06, 0xe7, 0x07, 0xbc, 0x08, + 0x84, 0x06, 0xc8, 0x07, 0x7e, 0x06, 0x41, 0x90, + 0x51, 0xaf, 0x97, 0xcf, 0x9f, 0xaf, 0x48, 0x0c, + 0xe7, 0x09, 0xb6, 0x06, 0xb4, 0x06, 0xe7, 0x09, + 0xb0, 0x06, 0xae, 0x06, 0x59, 0xaf, 0x97, 0xcf, + 0x27, 0x0c, 0x02, 0x00, 0xac, 0x06, 0x59, 0xaf, + 0x97, 0xcf, 0x09, 0x0c, 0x02, 0x00, 0x09, 0xda, + 0x49, 0xd2, 0xc9, 0x19, 0xd6, 0x06, 0xc8, 0x07, + 0x7e, 0x06, 0xe0, 0x07, 0x00, 0x00, 0x60, 0x02, + 0xe0, 0x07, 0x04, 0x00, 0xd0, 0x07, 0xcc, 0x08, + 0x48, 0xdb, 0x41, 0x90, 0x50, 0xaf, 0x97, 0xcf, + 0x59, 0xaf, 0x97, 0xcf, 0x59, 0xaf, 0x97, 0xcf, + 0xf0, 0x57, 0x06, 0x00, 0x06, 0x00, 0x25, 0xc1, + 0xe7, 0x07, 0x70, 0x06, 0x80, 0x06, 0x41, 0x90, + 0x67, 0x00, 0x7e, 0x06, 0x27, 0x0c, 0x06, 0x00, + 0x82, 0x06, 0xe7, 0x07, 0x8c, 0x09, 0x84, 0x06, + 0xc8, 0x07, 0x7e, 0x06, 0x41, 0x90, 0x51, 0xaf, + 0x97, 0xcf, 0x07, 0x0c, 0x06, 0x00, 0xc7, 0x57, + 0x06, 0x00, 0x0f, 0xc1, 0xc8, 0x07, 0x70, 0x06, + 0x15, 0xcf, 0x00, 0x0c, 0x02, 0x00, 0x00, 0xda, + 0x40, 0xd1, 0x27, 0x00, 0xc2, 0x06, 0x1e, 0xcf, + 0x1d, 0xcf, 0x27, 0x0c, 0x02, 0x00, 0xcc, 0x06, + 0x19, 0xcf, 0x27, 0x02, 0x20, 0x01, 0xe7, 0x07, + 0x08, 0x00, 0x22, 0x01, 0xe7, 0x07, 0x13, 0x00, + 0xb0, 0xc0, 0x97, 0xcf, 0x41, 0x90, 0x67, 0x00, + 0x7e, 0x06, 0xe7, 0x01, 0x82, 0x06, 0x27, 0x02, + 0x80, 0x06, 0xe7, 0x07, 0x8c, 0x09, 0x84, 0x06, + 0xc8, 0x07, 0x7e, 0x06, 0xc1, 0x07, 0x00, 0x80, + 0x50, 0xaf, 0x97, 0xcf, 0x59, 0xaf, 0x97, 0xcf, + 0x00, 0x60, 0x05, 0xc0, 0xe7, 0x07, 0x00, 0x00, + 0xc4, 0x06, 0xa7, 0xcf, 0x7c, 0x06, 0x9f, 0xaf, + 0x00, 0x0a, 0xe7, 0x07, 0x01, 0x00, 0xc4, 0x06, + 0x49, 0xaf, 0xd7, 0x09, 0x00, 0xc0, 0x07, 0xaf, + 0xe7, 0x05, 0x00, 0xc0, 0x4a, 0xaf, 0xa7, 0xcf, + 0x7c, 0x06, 0xc0, 0x07, 0xfe, 0x7f, 0x44, 0xaf, + 0x40, 0x00, 0xc0, 0x37, 0x00, 0x01, 0x41, 0x90, + 0xc0, 0x37, 0x08, 0x00, 0xdf, 0xde, 0x50, 0x06, + 0xc0, 0x57, 0x10, 0x00, 0x02, 0xc2, 0xc0, 0x07, + 0x10, 0x00, 0x27, 0x00, 0x9a, 0x06, 0x41, 0x90, + 0x9f, 0xde, 0x40, 0x06, 0x44, 0xaf, 0x27, 0x00, + 0x9c, 0x06, 0xc0, 0x09, 0x9a, 0x06, 0x41, 0x90, + 0x00, 0xd2, 0x00, 0xd8, 0x9f, 0xde, 0x08, 0x00, + 0x44, 0xaf, 0x27, 0x00, 0xc8, 0x06, 0x97, 0xcf, + 0xe7, 0x87, 0x00, 0x84, 0x28, 0xc0, 0xe7, 0x67, + 0xff, 0xfb, 0x24, 0xc0, 0x97, 0xcf, 0xe7, 0x87, + 0x01, 0x00, 0xd2, 0x06, 0xe7, 0x57, 0x00, 0x00, + 0xa8, 0x06, 0x97, 0xc1, 0x9f, 0xaf, 0x00, 0x0a, + 0xe7, 0x87, 0x00, 0x06, 0x22, 0xc0, 0xe7, 0x07, + 0x00, 0x00, 0x90, 0xc0, 0xe7, 0x67, 0xfe, 0xff, + 0x3e, 0xc0, 0xe7, 0x07, 0x26, 0x00, 0x0a, 0xc0, + 0xe7, 0x87, 0x01, 0x00, 0x3e, 0xc0, 0xe7, 0x07, + 0xff, 0xff, 0xbe, 0x06, 0x9f, 0xaf, 0x10, 0x0b, + 0x97, 0xcf, 0x17, 0x00, 0xa7, 0xaf, 0x78, 0x06, + 0xc0, 0x05, 0x27, 0x00, 0x76, 0x06, 0xe7, 0x87, + 0x01, 0x00, 0xd2, 0x06, 0x9f, 0xaf, 0x00, 0x0a, + 0xe7, 0x07, 0x0c, 0x00, 0x40, 0xc0, 0x9f, 0xaf, + 0x10, 0x0b, 0x00, 0x90, 0x27, 0x00, 0xa6, 0x06, + 0x27, 0x00, 0xaa, 0x06, 0xe7, 0x09, 0xb2, 0x06, + 0xb4, 0x06, 0x27, 0x00, 0xae, 0x06, 0x27, 0x00, + 0xac, 0x06, 0x9f, 0xaf, 0xae, 0x0a, 0xc0, 0x07, + 0x00, 0x00, 0x27, 0x00, 0xb2, 0x02, 0x27, 0x00, + 0xb4, 0x02, 0x27, 0x00, 0x8e, 0x06, 0xc0, 0x07, + 0x06, 0x00, 0xc8, 0x09, 0xde, 0x00, 0xc8, 0x17, + 0x03, 0x00, 0xc9, 0x07, 0x70, 0x06, 0x29, 0x0a, + 0x00, 0xda, 0x7d, 0xc1, 0x97, 0xcf, 0xd7, 0x09, + 0x00, 0xc0, 0xc1, 0xdf, 0x00, 0x90, 0x27, 0x00, + 0x96, 0x06, 0xe7, 0x07, 0x96, 0x06, 0x98, 0x06, + 0x27, 0x00, 0xa0, 0x06, 0xe7, 0x07, 0xa0, 0x06, + 0xa2, 0x06, 0x27, 0x00, 0xa6, 0x06, 0x27, 0x00, + 0x90, 0x06, 0x27, 0x00, 0x9e, 0x06, 0xc8, 0x09, + 0x9c, 0x06, 0xc1, 0x09, 0x9a, 0x06, 0xc9, 0x07, + 0xa4, 0x06, 0x11, 0x02, 0x09, 0x02, 0xc8, 0x17, + 0x40, 0x06, 0x01, 0xda, 0x7a, 0xc1, 0x51, 0x94, + 0xc8, 0x09, 0xc8, 0x06, 0xc9, 0x07, 0xc6, 0x06, + 0xc1, 0x09, 0x9a, 0x06, 0x11, 0x02, 0x09, 0x02, + 0xc8, 0x17, 0x08, 0x00, 0x01, 0xda, 0x7a, 0xc1, + 0x51, 0x94, 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf, + 0xe7, 0x57, 0x00, 0x00, 0x76, 0x06, 0x97, 0xc0, + 0x9f, 0xaf, 0x04, 0x00, 0xe7, 0x09, 0xbe, 0x06, + 0xba, 0x06, 0xe7, 0x57, 0xff, 0xff, 0xba, 0x06, + 0x04, 0xc1, 0xe7, 0x07, 0x10, 0x0b, 0xb8, 0x06, + 0x97, 0xcf, 0xe7, 0x17, 0x32, 0x00, 0xba, 0x06, + 0xe7, 0x67, 0xff, 0x07, 0xba, 0x06, 0xe7, 0x07, + 0x46, 0x0b, 0xb8, 0x06, 0x97, 0xcf, 0xe7, 0x57, + 0x00, 0x00, 0xc0, 0x06, 0x23, 0xc0, 0xe7, 0x07, + 0x04, 0x00, 0x90, 0xc0, 0xe7, 0x07, 0x00, 0x80, + 0x80, 0xc0, 0xe7, 0x07, 0x00, 0x00, 0x80, 0xc0, + 0xe7, 0x07, 0x00, 0x80, 0x80, 0xc0, 0xc0, 0x07, + 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xc0, 0x07, + 0x00, 0x00, 0xe7, 0x07, 0x00, 0x00, 0x80, 0xc0, + 0xe7, 0x07, 0x00, 0x80, 0x80, 0xc0, 0xe7, 0x07, + 0x00, 0x80, 0x40, 0xc0, 0xc0, 0x07, 0x00, 0x00, + 0xe7, 0x07, 0x00, 0x00, 0x40, 0xc0, 0xe7, 0x07, + 0x00, 0x00, 0x80, 0xc0, 0xe7, 0x07, 0x04, 0x00, + 0x90, 0xc0, 0xe7, 0x07, 0x00, 0x02, 0x40, 0xc0, + 0xe7, 0x07, 0x0c, 0x02, 0x40, 0xc0, 0xe7, 0x07, + 0x00, 0x00, 0xc0, 0x06, 0xe7, 0x07, 0x00, 0x00, + 0xb8, 0x06, 0xe7, 0x07, 0x00, 0x00, 0xd2, 0x06, + 0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x9f, 0xaf, + 0x34, 0x02, 0xe7, 0x05, 0x00, 0xc0, 0x9f, 0xaf, + 0xc4, 0x01, 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0, + 0x17, 0x00, 0x17, 0x02, 0x97, 0x02, 0xe7, 0x57, + 0x00, 0x00, 0xa8, 0x06, 0x06, 0xc0, 0xc0, 0x09, + 0x92, 0xc0, 0xc0, 0x77, 0x09, 0x02, 0x9f, 0xc1, + 0x5c, 0x05, 0x9f, 0xcf, 0x32, 0x06, 0xd7, 0x09, + 0x0e, 0xc0, 0xe7, 0x07, 0x00, 0x00, 0x0e, 0xc0, + 0x9f, 0xaf, 0x02, 0x0c, 0xe7, 0x05, 0x0e, 0xc0, + 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0, 0x17, 0x02, + 0xc8, 0x09, 0xb0, 0xc0, 0xe7, 0x67, 0xfe, 0x7f, + 0xb0, 0xc0, 0xc8, 0x77, 0x00, 0x20, 0x9f, 0xc1, + 0x64, 0xeb, 0xe7, 0x57, 0x00, 0x00, 0xc8, 0x02, + 0x9f, 0xc1, 0x80, 0xeb, 0xc8, 0x99, 0xca, 0x02, + 0xc8, 0x67, 0x04, 0x00, 0x9f, 0xc1, 0x96, 0xeb, + 0x9f, 0xcf, 0x4c, 0xeb, 0xe7, 0x07, 0x00, 0x00, + 0xa6, 0xc0, 0xe7, 0x09, 0xb0, 0xc0, 0xc8, 0x02, + 0xe7, 0x07, 0x03, 0x00, 0xb0, 0xc0, 0x97, 0xcf, + 0xc0, 0x09, 0xb0, 0x06, 0xc0, 0x37, 0x01, 0x00, + 0x97, 0xc9, 0xc9, 0x09, 0xb2, 0x06, 0x02, 0x00, + 0x41, 0x90, 0x48, 0x02, 0xc9, 0x17, 0x06, 0x00, + 0x9f, 0xaf, 0x08, 0x04, 0x9f, 0xa2, 0x72, 0x0c, + 0x02, 0xda, 0x77, 0xc1, 0x41, 0x60, 0x71, 0xc1, + 0x97, 0xcf, 0x17, 0x02, 0x57, 0x02, 0x43, 0x04, + 0x21, 0x04, 0xe0, 0x00, 0x43, 0x04, 0x21, 0x04, + 0xe0, 0x00, 0x43, 0x04, 0x21, 0x04, 0xe0, 0x00, + 0xc1, 0x07, 0x01, 0x00, 0xc9, 0x05, 0xc8, 0x05, + 0x97, 0xcf, 0xe7, 0x07, 0x01, 0x00, 0x8e, 0x06, + 0xc8, 0x07, 0x86, 0x06, 0xe7, 0x07, 0x00, 0x00, + 0x86, 0x06, 0xe7, 0x07, 0x10, 0x08, 0x88, 0x06, + 0xe7, 0x07, 0x04, 0x00, 0x8a, 0x06, 0xe7, 0x07, + 0xbc, 0x0c, 0x8c, 0x06, 0xc1, 0x07, 0x03, 0x80, + 0x50, 0xaf, 0x97, 0xcf, 0xe7, 0x07, 0x00, 0x00, + 0x8e, 0x06, 0x97, 0xcf, + 0x00, 0x00 +}; + +/**************************************************************** + * kaweth_new_code_fix + ****************************************************************/ +static __u8 kaweth_new_code_fix[] = +{ + 0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD, + 0x02, 0x00, 0x08, 0x00, 0x28, 0x00, 0x2c, 0x00, + 0x34, 0x00, 0x3c, 0x00, 0x40, 0x00, 0x48, 0x00, + 0x54, 0x00, 0x58, 0x00, 0x5e, 0x00, 0x64, 0x00, + 0x68, 0x00, 0x6e, 0x00, 0x6c, 0x00, 0x72, 0x00, + 0x76, 0x00, 0x7c, 0x00, 0x80, 0x00, 0x86, 0x00, + 0x8a, 0x00, 0x90, 0x00, 0x94, 0x00, 0x98, 0x00, + 0x9e, 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xb0, 0x00, + 0xb4, 0x00, 0xb8, 0x00, 0xc0, 0x00, 0xc6, 0x00, + 0xca, 0x00, 0xd0, 0x00, 0xd4, 0x00, 0xd8, 0x00, + 0xe0, 0x00, 0xde, 0x00, 0xe8, 0x00, 0xf0, 0x00, + 0xfc, 0x00, 0x04, 0x01, 0x0a, 0x01, 0x18, 0x01, + 0x22, 0x01, 0x28, 0x01, 0x3a, 0x01, 0x3e, 0x01, + 0x7e, 0x01, 0x98, 0x01, 0x9c, 0x01, 0xa2, 0x01, + 0xac, 0x01, 0xb2, 0x01, 0xba, 0x01, 0xc0, 0x01, + 0xc8, 0x01, 0xd0, 0x01, 0xd6, 0x01, 0xf4, 0x01, + 0xfc, 0x01, 0x08, 0x02, 0x16, 0x02, 0x1a, 0x02, + 0x22, 0x02, 0x2a, 0x02, 0x2e, 0x02, 0x3e, 0x02, + 0x44, 0x02, 0x4a, 0x02, 0x50, 0x02, 0x64, 0x02, + 0x62, 0x02, 0x6c, 0x02, 0x72, 0x02, 0x86, 0x02, + 0x8c, 0x02, 0x90, 0x02, 0x9e, 0x02, 0xbc, 0x02, + 0xd0, 0x02, 0xd8, 0x02, 0xdc, 0x02, 0xe0, 0x02, + 0xe8, 0x02, 0xe6, 0x02, 0xf4, 0x02, 0xfe, 0x02, + 0x04, 0x03, 0x0c, 0x03, 0x28, 0x03, 0x7c, 0x03, + 0x90, 0x03, 0x94, 0x03, 0x9c, 0x03, 0xa2, 0x03, + 0xc0, 0x03, 0xd0, 0x03, 0xd4, 0x03, 0xee, 0x03, + 0xfa, 0x03, 0xfe, 0x03, 0x2e, 0x04, 0x32, 0x04, + 0x3c, 0x04, 0x40, 0x04, 0x4e, 0x04, 0x76, 0x04, + 0x7c, 0x04, 0x84, 0x04, 0x8a, 0x04, 0x8e, 0x04, + 0xa6, 0x04, 0xb0, 0x04, 0xb8, 0x04, 0xbe, 0x04, + 0xd2, 0x04, 0xdc, 0x04, 0xee, 0x04, 0x10, 0x05, + 0x1a, 0x05, 0x24, 0x05, 0x2a, 0x05, 0x36, 0x05, + 0x34, 0x05, 0x3c, 0x05, 0x42, 0x05, 0x64, 0x05, + 0x6a, 0x05, 0x6e, 0x05, 0x86, 0x05, 0x22, 0x06, + 0x26, 0x06, 0x2c, 0x06, 0x30, 0x06, 0x42, 0x06, + 0x4a, 0x06, 0x4e, 0x06, 0x56, 0x06, 0x54, 0x06, + 0x5a, 0x06, 0x60, 0x06, 0x66, 0x06, 0xe8, 0x06, + 0xee, 0x06, 0xf4, 0x06, 0x16, 0x07, 0x26, 0x07, + 0x2c, 0x07, 0x32, 0x07, 0x36, 0x07, 0x3a, 0x07, + 0x3e, 0x07, 0x52, 0x07, 0x56, 0x07, 0x5a, 0x07, + 0x64, 0x07, 0x76, 0x07, 0x7a, 0x07, 0x80, 0x07, + 0x84, 0x07, 0x8a, 0x07, 0x9e, 0x07, 0xa2, 0x07, + 0xda, 0x07, 0xde, 0x07, 0xe2, 0x07, 0xe6, 0x07, + 0xea, 0x07, 0xee, 0x07, 0xf2, 0x07, 0xf6, 0x07, + 0x0e, 0x08, 0x16, 0x08, 0x18, 0x08, 0x1a, 0x08, + 0x1c, 0x08, 0x1e, 0x08, 0x20, 0x08, 0x22, 0x08, + 0x24, 0x08, 0x26, 0x08, 0x28, 0x08, 0x2a, 0x08, + 0x2c, 0x08, 0x2e, 0x08, 0x32, 0x08, 0x3a, 0x08, + 0x46, 0x08, 0x4e, 0x08, 0x54, 0x08, 0x5e, 0x08, + 0x78, 0x08, 0x7e, 0x08, 0x82, 0x08, 0x86, 0x08, + 0x8c, 0x08, 0x90, 0x08, 0x98, 0x08, 0x9e, 0x08, + 0xa4, 0x08, 0xaa, 0x08, 0xb0, 0x08, 0xae, 0x08, + 0xb4, 0x08, 0xbe, 0x08, 0xc4, 0x08, 0xc2, 0x08, + 0xca, 0x08, 0xc8, 0x08, 0xd4, 0x08, 0xe4, 0x08, + 0xe8, 0x08, 0xf6, 0x08, 0x14, 0x09, 0x12, 0x09, + 0x1a, 0x09, 0x20, 0x09, 0x26, 0x09, 0x24, 0x09, + 0x2a, 0x09, 0x3e, 0x09, 0x4c, 0x09, 0x56, 0x09, + 0x70, 0x09, 0x74, 0x09, 0x78, 0x09, 0x7e, 0x09, + 0x7c, 0x09, 0x82, 0x09, 0x98, 0x09, 0x9c, 0x09, + 0xa0, 0x09, 0xa6, 0x09, 0xb8, 0x09, 0xdc, 0x09, + 0xe8, 0x09, 0xec, 0x09, 0xfc, 0x09, 0x12, 0x0a, + 0x18, 0x0a, 0x1e, 0x0a, 0x42, 0x0a, 0x46, 0x0a, + 0x4e, 0x0a, 0x54, 0x0a, 0x5a, 0x0a, 0x5e, 0x0a, + 0x68, 0x0a, 0x6e, 0x0a, 0x72, 0x0a, 0x78, 0x0a, + 0x76, 0x0a, 0x7c, 0x0a, 0x80, 0x0a, 0x84, 0x0a, + 0x94, 0x0a, 0xa4, 0x0a, 0xb8, 0x0a, 0xbe, 0x0a, + 0xbc, 0x0a, 0xc2, 0x0a, 0xc8, 0x0a, 0xc6, 0x0a, + 0xcc, 0x0a, 0xd0, 0x0a, 0xd4, 0x0a, 0xd8, 0x0a, + 0xdc, 0x0a, 0xe0, 0x0a, 0xf2, 0x0a, 0xf6, 0x0a, + 0xfa, 0x0a, 0x14, 0x0b, 0x1a, 0x0b, 0x20, 0x0b, + 0x1e, 0x0b, 0x26, 0x0b, 0x2e, 0x0b, 0x2c, 0x0b, + 0x36, 0x0b, 0x3c, 0x0b, 0x42, 0x0b, 0x40, 0x0b, + 0x4a, 0x0b, 0xaa, 0x0b, 0xb0, 0x0b, 0xb6, 0x0b, + 0xc0, 0x0b, 0xc8, 0x0b, 0xda, 0x0b, 0xe8, 0x0b, + 0xec, 0x0b, 0xfa, 0x0b, 0x4a, 0x0c, 0x54, 0x0c, + 0x62, 0x0c, 0x66, 0x0c, 0x96, 0x0c, 0x9a, 0x0c, + 0xa0, 0x0c, 0xa6, 0x0c, 0xa4, 0x0c, 0xac, 0x0c, + 0xb2, 0x0c, 0xb0, 0x0c, 0xc0, 0x0c, + 0x00, 0x00 +}; + + +const int len_kaweth_trigger_code = sizeof(kaweth_trigger_code); +const int len_kaweth_trigger_code_fix = sizeof(kaweth_trigger_code_fix); +const int len_kaweth_new_code = sizeof(kaweth_new_code); +const int len_kaweth_new_code_fix = sizeof(kaweth_new_code_fix); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/net1080.c linux.ac/drivers/usb/net1080.c --- linux.vanilla/drivers/usb/net1080.c Thu Jan 4 21:15:32 2001 +++ linux.ac/drivers/usb/net1080.c Thu Jan 1 01:00:00 1970 @@ -1,1115 +0,0 @@ -/* - * NetChip 1080 Driver (USB Host-to-Host Link) - * Copyright (C) 2000 by David Brownell <dbrownell@users.sourceforge.net> - */ - -/* - * This talks to the NetChip 1080, which can appear in "network cables" - * and other designs. This driver interoperates with the Win32 network - * drivers from NetChip, using the NetChip reference design. - * - * The IP-over-USB protocol here may be of interest. Embedded devices - * could implement it at the cost of two bulk endpoints, and whatever - * other system resources the desired IP-based applications need. - * Some Linux palmtops could support that today. (Devices that don't - * support the TTL-driven data mangling of the net1080 chip won't need - * the header/trailer support though.) - * - * STATUS: - * - * 13-sept-2000 experimental, new - * - * This doesn't yet do any network hotplugging, and there's no matching - * ifup policy script ... it should arrange bridging with "brctl", and - * should handle static and dynamic ("pump") setups. - * - * RX/TX queue sizes currently fixed at one due to URB unlink problems. - * - * 10-oct-2000 - * usb_device_id table created. - * - * 28-oct-2000 - * misc fixes; mostly, discard more TTL-mangled rx packets. - * - * 01-nov-2000 - * usb_device_id table support added by Adam J. Richter <adam@yggdrasil.com>. - * - *-------------------------------------------------------------------------*/ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kmod.h> -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/random.h> -#include <asm/unaligned.h> - -#define DEBUG // error path messages -// #define VERBOSE // more; success messages -#define USE_TTL // timeout our reads - -#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG) -# define DEBUG -#endif -#include <linux/usb.h> - - -static const struct usb_device_id products [] = { - // reference design - { USB_DEVICE(0x1080, 0x525), - driver_info: (unsigned long) "NetChip TurboCONNECT" }, - // Belkin, ... - { }, // END -}; - -MODULE_DEVICE_TABLE (usb, products); - -static u8 node_id [ETH_ALEN]; - - -/*------------------------------------------------------------------------- - * - * NetChip protocol: ethernet framing, and only use bulk endpoints (01/81; - * not mailboxes 02/82 or status interrupt 83). Expects Ethernet bridging. - * Odd USB length == always short read. - * - nc_header - * - payload, in Ethernet framing (14 byte header etc) - * - (optional padding byte, if needed so length is odd) - * - nc_trailer - */ - -struct nc_header { - u16 hdr_len; // sizeof nc_header (LE, all) - u16 packet_len; // packet size - u16 packet_id; // detects dropped packets -#define NC_MIN_HEADER 6 - - // all else is optional, and must start with: - // u16 vendorId; // from usb-if - // u16 productId; -}; - -#define NC_PAD_BYTE ((unsigned char)0xAC) - -struct nc_trailer { - u16 packet_id; -}; - -// packetsize == f(mtu setting), with upper limit -#define NC_MAX_PACKET(mtu) (sizeof (struct nc_header) \ - + (mtu) \ - + 1 \ - + sizeof (struct nc_trailer)) -#define MAX_PACKET 8191 - -// zero means no timeout; else, how long a 64 byte bulk -// read may be queued before HW flushes it. -#define NC_READ_TTL ((u8)255) // ms - - -/*-------------------------------------------------------------------------*/ - -// list of all devices we manage -static DECLARE_MUTEX (net1080_mutex); -static LIST_HEAD (net1080_list); - - -// Nineteen USB 1.1 max size bulk transactions per frame, max. -#if 0 -#define RX_QLEN 4 -#define TX_QLEN 4 - -#else -// unlink_urbs() has probs on OHCI without test8-pre patches. -#define RX_QLEN 1 -#define TX_QLEN 1 -#endif - -enum skb_state { - illegal = 0, - tx_start, tx_done, - rx_start, rx_done, rx_cleanup -}; - -struct skb_data { // skb->cb is one of these - struct urb *urb; - struct net1080 *dev; - enum skb_state state; - size_t length; -}; - - -struct net1080 { - // housekeeping - struct usb_device *udev; - const struct usb_device_id *prod_info; - struct semaphore mutex; - struct list_head dev_list; - wait_queue_head_t *wait; - - // protocol/interface state - struct net_device net; - struct net_device_stats stats; - u16 packet_id; - - // various kinds of pending driver work - struct sk_buff_head rxq; - struct sk_buff_head txq; - struct sk_buff_head done; - struct tasklet_struct bh; -}; - -#define mutex_lock(x) down(x) -#define mutex_unlock(x) up(x) - -static void defer_bh (struct net1080 *dev, struct sk_buff *skb) -{ - unsigned long flags; - - skb_unlink (skb); - spin_lock_irqsave (&dev->done.lock, flags); - __skb_queue_tail (&dev->done, skb); - if (dev->done.qlen == 1) - tasklet_schedule (&dev->bh); - spin_unlock_irqrestore (&dev->done.lock, flags); -} - -/*------------------------------------------------------------------------- - * - * We ignore most registers and EEPROM contents. - */ - -#define REG_USBCTL ((u8)0x04) -#define REG_TTL ((u8)0x10) -#define REG_STATUS ((u8)0x11) - -/* - * Vendor specific requests to read/write data - */ - -#define REQUEST_REGISTER ((u8)0x10) -#define REQUEST_EEPROM ((u8)0x11) - -#define CONTROL_TIMEOUT (500) /* msec */ - -static int -vendor_read (struct net1080 *dev, u8 req, u8 regnum, u16 *retval_ptr) -{ - int status = usb_control_msg (dev->udev, - usb_rcvctrlpipe (dev->udev, 0), - req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, regnum, - retval_ptr, sizeof *retval_ptr, - CONTROL_TIMEOUT); - if (status > 0) - status = 0; - if (!status) - le16_to_cpus (retval_ptr); - return status; -} - -static inline int -register_read (struct net1080 *dev, u8 regnum, u16 *retval_ptr) -{ - return vendor_read (dev, REQUEST_REGISTER, regnum, retval_ptr); -} - -// without retval, this can become fully async (usable in_interrupt) -static void -vendor_write (struct net1080 *dev, u8 req, u8 regnum, u16 value) -{ - usb_control_msg (dev->udev, - usb_sndctrlpipe (dev->udev, 0), - req, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, regnum, - 0, 0, // data is in setup packet - CONTROL_TIMEOUT); -} - -static inline void -register_write (struct net1080 *dev, u8 regnum, u16 value) -{ - vendor_write (dev, REQUEST_REGISTER, regnum, value); -} - - -#if 0 -static void dump_registers (struct net1080 *dev) -{ - u8 reg; - u16 value; - - dbg ("%s registers:", dev->net.name); - for (reg = 0; reg < 0x20; reg++) { - int retval; - - // reading some registers is trouble - if (reg >= 0x08 && reg <= 0xf) - continue; - if (reg >= 0x12 && reg <= 0x1e) - continue; - - retval = register_read (dev, reg, &value); - if (retval < 0) - dbg ("%s reg [0x%x] ==> error %d", - dev->net.name, reg, retval); - else - dbg ("%s reg [0x%x] = 0x%x", - dev->net.name, reg, value); - } -} -#endif - - -/*------------------------------------------------------------------------- - * - * Control register - */ - -#define USBCTL_WRITABLE_MASK 0x1f0f -// bits 15-13 reserved, r/o -#define USBCTL_ENABLE_LANG (1 << 12) -#define USBCTL_ENABLE_MFGR (1 << 11) -#define USBCTL_ENABLE_PROD (1 << 10) -#define USBCTL_ENABLE_SERIAL (1 << 9) -#define USBCTL_ENABLE_DEFAULTS (1 << 8) -// bits 7-4 reserved, r/o -#define USBCTL_FLUSH_OTHER (1 << 3) -#define USBCTL_FLUSH_THIS (1 << 2) -#define USBCTL_DISCONN_OTHER (1 << 1) -#define USBCTL_DISCONN_THIS (1 << 0) - -#ifdef DEBUG -static void dump_usbctl (struct net1080 *dev, u16 usbctl) -{ - dbg ("%s: USB %d dev %d usbctl 0x%x:%s%s%s%s%s;" - " this%s%s;" - " other%s%s; r/o 0x%x", - dev->net.name, - dev->udev->bus->busnum, dev->udev->devnum, - usbctl, - (usbctl & USBCTL_ENABLE_LANG) ? " lang" : "", - (usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "", - (usbctl & USBCTL_ENABLE_PROD) ? " prod" : "", - (usbctl & USBCTL_ENABLE_SERIAL) ? " serial" : "", - (usbctl & USBCTL_ENABLE_DEFAULTS) ? " defaults" : "", - - (usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "", - (usbctl & USBCTL_DISCONN_OTHER) ? " DIS" : "", - (usbctl & USBCTL_FLUSH_THIS) ? " FLUSH" : "", - (usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "", - usbctl & ~USBCTL_WRITABLE_MASK - ); -} -#else -static inline void dump_usbctl (struct net1080 *dev, u16 usbctl) {} -#endif - -/*------------------------------------------------------------------------- - * - * Status register - */ - -#define STATUS_PORT_A (1 << 15) - -#define STATUS_CONN_OTHER (1 << 14) -#define STATUS_SUSPEND_OTHER (1 << 13) -#define STATUS_MAILBOX_OTHER (1 << 12) -#define STATUS_PACKETS_OTHER(n) (((n) >> 8) && 0x03) - -#define STATUS_CONN_THIS (1 << 6) -#define STATUS_SUSPEND_THIS (1 << 5) -#define STATUS_MAILBOX_THIS (1 << 4) -#define STATUS_PACKETS_THIS(n) (((n) >> 0) && 0x03) - -#define STATUS_UNSPEC_MASK 0x0c8c -#define STATUS_NOISE_MASK ((u16)~(0x0303|STATUS_UNSPEC_MASK)) - - -#ifdef DEBUG -static void dump_status (struct net1080 *dev, u16 status) -{ - dbg ("%s: USB %d dev %d status 0x%x:" - " this (%c) PKT=%d%s%s%s;" - " other PKT=%d%s%s%s; unspec 0x%x", - dev->net.name, - dev->udev->bus->busnum, dev->udev->devnum, - status, - - // XXX the packet counts don't seem right - // (1 at reset, not 0); maybe UNSPEC too - - (status & STATUS_PORT_A) ? 'A' : 'B', - STATUS_PACKETS_THIS (status), - (status & STATUS_CONN_THIS) ? " CON" : "", - (status & STATUS_SUSPEND_THIS) ? " SUS" : "", - (status & STATUS_MAILBOX_THIS) ? " MBOX" : "", - - STATUS_PACKETS_OTHER (status), - (status & STATUS_CONN_OTHER) ? " CON" : "", - (status & STATUS_SUSPEND_OTHER) ? " SUS" : "", - (status & STATUS_MAILBOX_OTHER) ? " MBOX" : "", - - status & STATUS_UNSPEC_MASK - ); -} -#else -static inline void dump_status (struct net1080 *dev, u16 status) {} -#endif - -/*------------------------------------------------------------------------- - * - * TTL register - */ - -#define TTL_THIS(ttl) (0x00ff & ttl) -#define TTL_OTHER(ttl) (0x00ff & (ttl >> 8)) -#define MK_TTL(this,other) ((u16)(((other)<<8)|(0x00ff&(this)))) - -#ifdef DEBUG -static void dump_ttl (struct net1080 *dev, u16 ttl) -{ - dbg ("%s: USB %d dev %d ttl 0x%x this = %d, other = %d", - dev->net.name, - dev->udev->bus->busnum, dev->udev->devnum, - ttl, - - TTL_THIS (ttl), - TTL_OTHER (ttl) - ); -} -#else -static inline void dump_ttl (struct net1080 *dev, u16 ttl) {} -#endif - -#define RUN_CONTEXT (in_irq () ? "in_irq" \ - : (in_interrupt () ? "in_interrupt" : "can sleep")) - -/*-------------------------------------------------------------------------*/ - -// ensure that the device is in a known state before using it. - -// preconditions: -// caller owns the device mutex -// caller has a process context - -static int net1080_reset (struct net1080 *dev) -{ - u16 usbctl, status, ttl; - int retval; - - if ((retval = register_read (dev, REG_STATUS, &status)) < 0) { - dbg ("can't read dev %d status: %d", dev->udev->devnum, retval); - goto done; - } - dump_status (dev, status); - - if ((retval = register_read (dev, REG_USBCTL, &usbctl)) < 0) { - dbg ("can't read USBCTL, %d", retval); - goto done; - } - dump_usbctl (dev, usbctl); - - register_write (dev, REG_USBCTL, - USBCTL_FLUSH_THIS | USBCTL_FLUSH_OTHER); - - if ((retval = register_read (dev, REG_TTL, &ttl)) < 0) { - dbg ("can't read TTL, %d", retval); - goto done; - } - dump_ttl (dev, ttl); - -#ifdef USE_TTL - // Have the chip flush reads that seem to be starving for read - // bandwidth ... or we're otherwise reading. Note, Win32 drivers - // may change our read TTL for us. - - register_write (dev, REG_TTL, - MK_TTL (NC_READ_TTL, TTL_OTHER (ttl)) ); - dbg ("%s: assigned TTL, %d ms", dev->net.name, NC_READ_TTL); -#endif - - info ("%s: %s, port %c on USB %d dev %d, peer %sconnected", - dev->net.name, (char *) dev->prod_info->driver_info, - (status & STATUS_PORT_A) ? 'A' : 'B', - dev->udev->bus->busnum, - dev->udev->devnum, - (status & STATUS_CONN_OTHER) ? "" : "dis" - ); - retval = 0; - -done: - return retval; -} - - -/*------------------------------------------------------------------------- - * - * Network Device Driver support (peer link to USB Host) - * - --------------------------------------------------------------------------*/ - -static int net1080_change_mtu (struct net_device *net, int new_mtu) -{ - if ((new_mtu < 0) || NC_MAX_PACKET (new_mtu) > MAX_PACKET) - return -EINVAL; - net->mtu = new_mtu; - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static struct net_device_stats *net1080_get_stats (struct net_device *net) -{ - return &((struct net1080 *) net->priv)->stats; -} - -/*-------------------------------------------------------------------------*/ - -static void rx_complete (struct urb *urb); - -static void rx_submit (struct net1080 *dev, struct urb *urb, int flags) -{ - struct sk_buff *skb; - struct skb_data *entry; - int retval = 0; - unsigned long lockflags; - - if ((skb = alloc_skb (NC_MAX_PACKET (dev->net.mtu), flags)) == 0) { - err ("no rx skb"); - tasklet_schedule (&dev->bh); - usb_free_urb (urb); - return; - } - - entry = (struct skb_data *) skb->cb; - entry->urb = urb; - entry->dev = dev; - entry->state = rx_start; - entry->length = 0; - - FILL_BULK_URB (urb, dev->udev, usb_rcvbulkpipe (dev->udev, 1), - skb->data, skb->truesize, rx_complete, skb); - urb->transfer_flags |= USB_QUEUE_BULK; - - spin_lock_irqsave (&dev->rxq.lock, lockflags); - if (!netif_queue_stopped (&dev->net)) { - if ((retval = usb_submit_urb (urb)) != 0) { - err ("%s rx submit, %d", dev->net.name, retval); - tasklet_schedule (&dev->bh); - } else { - __skb_queue_tail (&dev->rxq, skb); - } - } else { - dbg ("rx: stopped"); - retval = -ENOLINK; - } - spin_unlock_irqrestore (&dev->rxq.lock, lockflags); - if (retval) { - dev_kfree_skb_any (skb); - usb_free_urb (urb); - } -} - - -/*-------------------------------------------------------------------------*/ - -static void rx_complete (struct urb *urb) -{ - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct skb_data *entry = (struct skb_data *) skb->cb; - struct net1080 *dev = entry->dev; - int urb_status = urb->status; - - urb->dev = 0; - skb->len = urb->actual_length; - entry->state = rx_done; - entry->urb = 0; - - if ((urb->transfer_flags & USB_ASYNC_UNLINK) != 0) { - dbg ("rx ... shutting down"); - usb_free_urb (urb); - urb = 0; - } - - switch (urb_status) { - // success - case 0: - if (!(skb->len & 0x01)) { - entry->state = rx_cleanup; - dev->stats.rx_errors++; - dev->stats.rx_length_errors++; - dbg ("even rx len %d", skb->len); - } else if (skb->len > MAX_PACKET) { - entry->state = rx_cleanup; - dev->stats.rx_errors++; - dev->stats.rx_frame_errors++; - dbg ("rx too big, %d", skb->len); - } - break; - - // hardware-reported interface shutdown ... which we - // typically see before khubd calls disconnect() - case -ETIMEDOUT: // usb-ohci - case -EILSEQ: // *uhci ... "crc"/timeout error - // netif_device_detach (&dev->net); - // FALLTHROUGH - - // software-driven interface shutdown - case -ECONNRESET: - entry->state = rx_cleanup; - usb_free_urb (urb); - urb = 0; - dbg ("%s ... shutdown rx (%d)", dev->net.name, urb_status); - break; - - // data overrun ... flush fifo? - case -EOVERFLOW: - dev->stats.rx_over_errors++; - // FALLTHROUGH - - default: - entry->state = rx_cleanup; - dev->stats.rx_errors++; - err ("%s rx: status %d", dev->net.name, urb_status); - break; - } - defer_bh (dev, skb); - - if (urb) { - if (!netif_queue_stopped (&dev->net)) { - rx_submit (dev, urb, GFP_ATOMIC); - return; - } else - usb_free_urb (urb); - } -#ifdef VERBOSE - dbg ("no read resubmitted"); -#endif VERBOSE -} - -/*-------------------------------------------------------------------------*/ - -// unlink pending rx/tx; completion handlers do all other cleanup - -static int unlink_urbs (struct sk_buff_head *q) -{ - unsigned long flags; - struct sk_buff *skb; - struct skb_data *entry; - int retval; - int count = 0; - - spin_lock_irqsave (&q->lock, flags); - for (skb = q->next; skb != (struct sk_buff *) q; skb = skb->next) { - entry = (struct skb_data *) skb->cb; - entry->urb->transfer_flags |= USB_ASYNC_UNLINK; - retval = usb_unlink_urb (entry->urb); - if (retval < 0) - dbg ("unlink urb err, %d", retval); - else - count++; - } - spin_unlock_irqrestore (&q->lock, flags); - return count; -} - - -/*-------------------------------------------------------------------------*/ - -// precondition: never called in_interrupt - -static int net1080_stop (struct net_device *net) -{ - struct net1080 *dev = (struct net1080 *) net->priv; - int temp; - DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); - DECLARE_WAITQUEUE (wait, current); - - mutex_lock (&dev->mutex); - - dbg ("%s stop stats: rx/tx %ld/%ld, errs %ld/%ld", net->name, - dev->stats.rx_packets, dev->stats.tx_packets, - dev->stats.rx_errors, dev->stats.tx_errors - ); - - netif_stop_queue(net); - - // ensure there are no more active urbs - add_wait_queue (&unlink_wakeup, &wait); - dev->wait = &unlink_wakeup; - temp = unlink_urbs (&dev->txq) + unlink_urbs (&dev->rxq); - - // maybe wait for deletions to finish. - if (temp) { - current->state = TASK_UNINTERRUPTIBLE; - schedule (); - dbg ("waited for %d urb completions", temp); - } - dev->wait = 0; - current->state = TASK_RUNNING; - remove_wait_queue (&unlink_wakeup, &wait); - - mutex_unlock (&dev->mutex); - MOD_DEC_USE_COUNT; - return 0; -} - -/*-------------------------------------------------------------------------*/ - -// posts a read, and enables write queing - -// precondition: never called in_interrupt - -static int net1080_open (struct net_device *net) -{ - struct net1080 *dev = (struct net1080 *) net->priv; - int retval; - u16 status; - int i; - - MOD_INC_USE_COUNT; - mutex_lock (&dev->mutex); - - // insist peer be connected -- is this the best place? - if ((retval = register_read (dev, REG_STATUS, &status)) != 0) { - dbg ("%s open: status read failed - %d", net->name, retval); - goto done; - } - if ((status & STATUS_CONN_OTHER) != STATUS_CONN_OTHER) { - retval = -ENOLINK; - dbg ("%s open: peer not connected", net->name); - goto done; - } - - MOD_INC_USE_COUNT; - netif_start_queue (net); - for (i = 0; i < RX_QLEN; i++) - rx_submit (dev, usb_alloc_urb (0), GFP_KERNEL); - - dbg ("%s open: started queueing (rx %d, tx %d)", - net->name, RX_QLEN, TX_QLEN); -done: - mutex_unlock (&dev->mutex); - MOD_DEC_USE_COUNT; - return retval; -} - -/*-------------------------------------------------------------------------*/ - -static void tx_complete (struct urb *urb) -{ - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct skb_data *entry = (struct skb_data *) skb->cb; - struct net1080 *dev = entry->dev; - - urb->dev = 0; - entry->state = tx_done; - defer_bh (dev, skb); - netif_wake_queue (&dev->net); -} - -/*-------------------------------------------------------------------------*/ - -static struct sk_buff *fixup_skb (struct sk_buff *skb) -{ - int padlen; - struct sk_buff *skb2; - - padlen = ((skb->len + sizeof (struct nc_header) - + sizeof (struct nc_trailer)) & 0x01) ? 0 : 1; - if (!skb_cloned (skb)) { - int headroom = skb_headroom (skb); - int tailroom = skb_tailroom (skb); - - if ((padlen + sizeof (struct nc_trailer)) <= tailroom - && sizeof (struct nc_header) <= headroom) - return skb; - - if ((sizeof (struct nc_header) + padlen - + sizeof (struct nc_trailer)) < - (headroom + tailroom)) { - skb->data = memmove (skb->head - + sizeof (struct nc_header), - skb->data, skb->len); - skb->tail = skb->data + skb->len; - return skb; - } - } - skb2 = skb_copy_expand (skb, - sizeof (struct nc_header), - sizeof (struct nc_trailer) + padlen, - in_interrupt () ? GFP_ATOMIC : GFP_KERNEL); - dev_kfree_skb_any (skb); - return skb2; -} - -/*-------------------------------------------------------------------------*/ - -static int net1080_start_xmit (struct sk_buff *skb, struct net_device *net) -{ - struct net1080 *dev = (struct net1080 *) net->priv; - int length = skb->len; - int retval = 0; - struct urb *urb = 0; - struct skb_data *entry; - struct nc_header *header; - struct nc_trailer *trailer; - unsigned long flags; - - if ((skb = fixup_skb (skb)) == 0) { - dbg ("can't fixup skb"); - goto drop; - } - if ((urb = usb_alloc_urb (0)) == 0) { - dbg ("no urb"); - goto drop; - } - - entry = (struct skb_data *) skb->cb; - entry->urb = urb; - entry->dev = dev; - entry->state = tx_start; - entry->length = length; - - header = (struct nc_header *) skb_push (skb, sizeof *header); - header->hdr_len = cpu_to_le16 (sizeof (*header)); - header->packet_len = cpu_to_le16 (length); - if (!((skb->len + sizeof *trailer) & 0x01)) - *skb_put (skb, 1) = NC_PAD_BYTE; - trailer = (struct nc_trailer *) skb_put (skb, sizeof *trailer); - - FILL_BULK_URB (urb, dev->udev, - usb_sndbulkpipe (dev->udev, 1), - skb->data, skb->len, tx_complete, skb); - urb->transfer_flags |= USB_QUEUE_BULK; - // FIXME urb->timeout = ...; - - spin_lock_irqsave (&dev->txq.lock, flags); - if (!netif_queue_stopped (&dev->net)) { - header->packet_id = cpu_to_le16 (dev->packet_id++); - put_unaligned (header->packet_id, &trailer->packet_id); - - netif_stop_queue (net); - if ((retval = usb_submit_urb (urb)) != 0) { - netif_start_queue (net); - dbg ("%s tx: submit urb err %d", net->name, retval); - } else { - net->trans_start = jiffies; - __skb_queue_tail (&dev->txq, skb); - if (dev->txq.qlen < TX_QLEN) - netif_start_queue (net); - } - } else - retval = -ENOLINK; - spin_unlock_irqrestore (&dev->txq.lock, flags); - - if (retval) { - dbg ("drop"); -drop: - dev->stats.tx_dropped++; - dev_kfree_skb_any (skb); - usb_free_urb (urb); -#ifdef VERBOSE - } else { - dbg ("%s: tx %p len %d", net->name, skb, length); -#endif - } - return retval; -} - - -/*-------------------------------------------------------------------------*/ - -static void rx_process (struct net1080 *dev, struct sk_buff *skb) -{ - struct nc_header *header; - struct nc_trailer *trailer; - - header = (struct nc_header *) skb->data; - le16_to_cpus (&header->hdr_len); - le16_to_cpus (&header->packet_len); - if (header->packet_len > MAX_PACKET) { - dev->stats.rx_frame_errors++; - dbg ("packet too big, %d", header->packet_len); - goto error; - } else if (header->hdr_len < NC_MIN_HEADER) { - dev->stats.rx_frame_errors++; - dbg ("header too short, %d", header->hdr_len); - goto error; - } else if (header->hdr_len > header->packet_len) { - dev->stats.rx_frame_errors++; - dbg ("header too big, %d packet %d", header->hdr_len, header->packet_len); - goto error; - } else if (header->hdr_len != sizeof *header) { - // out of band data for us? - dbg ("header OOB, %d bytes", header->hdr_len - NC_MIN_HEADER); - // switch (vendor/product ids) { ... } - } - skb_pull (skb, header->hdr_len); - - trailer = (struct nc_trailer *) - (skb->data + skb->len - sizeof *trailer); - skb_trim (skb, skb->len - sizeof *trailer); - - if ((header->packet_len & 0x01) == 0) { - if (skb->data [header->packet_len] != NC_PAD_BYTE) { - dev->stats.rx_frame_errors++; - dbg ("bad pad"); - goto error; - } - skb_trim (skb, skb->len - 1); - } - if (skb->len != header->packet_len) { - dev->stats.rx_length_errors++; - dbg ("bad packet len %d (expected %d)", - skb->len, header->packet_len); - goto error; - } - if (header->packet_id != get_unaligned (&trailer->packet_id)) { - dev->stats.rx_fifo_errors++; - dbg ("(2+ dropped) rx packet_id mismatch 0x%x 0x%x", - header->packet_id, trailer->packet_id); - goto error; - } - - if (skb->len) { - skb->dev = &dev->net; - skb->protocol = eth_type_trans (skb, &dev->net); - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - -#ifdef VERBOSE - dbg ("%s: rx %p len %d, type 0x%x, id 0x%x", - dev->net.name, skb, skb->len, skb->protocol, - le16_to_cpu (header->packet_id)); -#endif - netif_rx (skb); - } else { - dbg ("drop"); -error: - dev->stats.rx_errors++; - dev_kfree_skb (skb); - } -} - -/*-------------------------------------------------------------------------*/ - -// tasklet - -// We can have a state machine in this tasklet monitor the link state, -// using async control messaging and calling attach/detach routines. - -// But then some listener ought to respond to the changes; do those -// network attach/detach notifications get to userland somehow, such -// as by calling "ifup usb0" and "ifdown usb0"? - -static void net1080_bh (unsigned long param) -{ - struct net1080 *dev = (struct net1080 *) param; - struct sk_buff *skb; - struct skb_data *entry; - - while ((skb = skb_dequeue (&dev->done))) { - entry = (struct skb_data *) skb->cb; - switch (entry->state) { - case rx_done: - rx_process (dev, skb); - continue; - case tx_done: - if (entry->urb->status) { - // can this statistic become more specific? - dev->stats.tx_errors++; - dbg ("%s tx: err %d", dev->net.name, - entry->urb->status); - } else { - dev->stats.tx_packets++; - dev->stats.tx_bytes += entry->length; - } - // FALLTHROUGH: - case rx_cleanup: - usb_free_urb (entry->urb); - dev_kfree_skb (skb); - continue; - default: - dbg ("%s: bogus skb state %d", - dev->net.name, entry->state); - } - } - - // waiting for all pending urbs to complete? - if (dev->wait) { - if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) { - wake_up (dev->wait); - } - - // or are we maybe short a few urbs? - } else if (!netif_queue_stopped (&dev->net)) { - if (dev->rxq.qlen < TX_QLEN) { - struct urb *urb; - int i; - for (i = 0; i < 3 && dev->rxq.qlen < TX_QLEN; i++) { - if ((urb = usb_alloc_urb (0)) != 0) - rx_submit (dev, urb, GFP_ATOMIC); - } - dbg ("%s: rxqlen now %d", - dev->net.name, dev->rxq.qlen); - } - } -} - -/*------------------------------------------------------------------------- - * - * USB Device Driver support - * - --------------------------------------------------------------------------*/ - -// precondition: never called in_interrupt - -static void net1080_disconnect (struct usb_device *udev, void *ptr) -{ - struct net1080 *dev = (struct net1080 *) ptr; - - info ("%s: USB %d dev %d, %s, disconnected", - dev->net.name, - udev->bus->busnum, udev->devnum, - (char *) dev->prod_info->driver_info); - - unregister_netdev (&dev->net); - - mutex_lock (&net1080_mutex); - mutex_lock (&dev->mutex); - list_del (&dev->dev_list); - mutex_unlock (&net1080_mutex); - -#ifdef DEBUG - memset (dev, 0x55, sizeof *dev); -#endif - kfree (dev); - usb_dec_dev_use (udev); -} - - -/*-------------------------------------------------------------------------*/ - -// precondition: never called in_interrupt - -static void * -net1080_probe (struct usb_device *udev, unsigned ifnum, const struct usb_device_id *prod) -{ - struct net1080 *dev; - struct net_device *net; - struct usb_interface_descriptor *interface; - int retval; - - // sanity check; expect dedicated interface/devices for now. - interface = &udev->actconfig->interface [ifnum].altsetting[0]; - if (udev->descriptor.bNumConfigurations != 1 - || udev->config[0].bNumInterfaces != 1 - || udev->config[0].bNumInterfaces != 1 - || interface->bInterfaceClass != USB_CLASS_VENDOR_SPEC - || interface->bNumEndpoints != 5 - ) { - dbg ("Bogus config info"); - return 0; - } - - // set up our own records - if (!(dev = kmalloc (sizeof *dev, GFP_KERNEL))) { - dbg ("can't kmalloc dev"); - return 0; - } - memset (dev, 0, sizeof *dev); - - init_MUTEX_LOCKED (&dev->mutex); - usb_inc_dev_use (udev); - dev->udev = udev; - dev->prod_info = prod; - INIT_LIST_HEAD (&dev->dev_list); - skb_queue_head_init (&dev->rxq); - skb_queue_head_init (&dev->txq); - skb_queue_head_init (&dev->done); - dev->bh.func = net1080_bh; - dev->bh.data = (unsigned long) dev; - - // set up network interface records - net = &dev->net; - net->priv = dev; - strcpy (net->name, "usb%d"); - memcpy (net->dev_addr, node_id, sizeof node_id); - - ether_setup (net); - // net->flags |= IFF_POINTOPOINT; - - net->change_mtu = net1080_change_mtu; - net->get_stats = net1080_get_stats; - net->hard_start_xmit = net1080_start_xmit; - net->open = net1080_open; - net->stop = net1080_stop; - - register_netdev (&dev->net); - - // ... talk to the device - // dump_registers (dev); - - if ((retval = net1080_reset (dev)) < 0) { - err ("%s: init reset fail on USB %d dev %d - %d", - dev->net.name, udev->bus->busnum, udev->devnum, retval); - mutex_unlock (&dev->mutex); - net1080_disconnect (udev, dev); - return 0; - } - - // ok, it's ready to go. - mutex_lock (&net1080_mutex); - list_add (&dev->dev_list, &net1080_list); - mutex_unlock (&dev->mutex); - - // start as if the link is up - netif_device_attach (&dev->net); - - mutex_unlock (&net1080_mutex); - - return dev; -} - - -/*-------------------------------------------------------------------------*/ - -static struct usb_driver net1080_driver = { - name: "net1080", - id_table: products, - probe: net1080_probe, - disconnect: net1080_disconnect, -}; - -/*-------------------------------------------------------------------------*/ - -static int __init net1080_init (void) -{ - // compiler should optimize this out - if (sizeof (((struct sk_buff *)0)->cb) < sizeof (struct skb_data)) - BUG (); - - if (usb_register (&net1080_driver) < 0) - return -1; - - get_random_bytes (node_id, sizeof node_id); - node_id [0] &= 0x7f; - - return 0; -} -module_init (net1080_init); - -static void __exit net1080_exit (void) -{ - usb_deregister (&net1080_driver); -} -module_exit (net1080_exit); - -MODULE_AUTHOR ("David Brownell <dbrownell@users.sourceforge.net>"); -MODULE_DESCRIPTION ("NetChip 1080 Driver (USB Host-to-Host Link)"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/ov511.c linux.ac/drivers/usb/ov511.c --- linux.vanilla/drivers/usb/ov511.c Tue Apr 3 17:32:23 2001 +++ linux.ac/drivers/usb/ov511.c Tue Apr 3 17:55:07 2001 @@ -3139,11 +3139,6 @@ init_waitqueue_head(&ov511->wq); - if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER) < 0) { - err("video_register_device failed"); - return -EBUSY; - } - if (ov511_write_regvals(dev, aRegvalsInit)) goto error; if (ov511_write_regvals(dev, aRegvalsNorm511)) goto error; @@ -3212,7 +3207,6 @@ return 0; error: - video_unregister_device(&ov511->vdev); usb_driver_release_interface(&ov511_driver, &dev->actconfig->interface[ov511->iface]); @@ -3321,6 +3315,11 @@ ov511->buf_state = BUF_NOT_ALLOCATED; } else { err("Failed to configure camera"); + goto error; + } + + if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER) < 0) { + err("video_register_device failed"); goto error; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/plusb.c linux.ac/drivers/usb/plusb.c --- linux.vanilla/drivers/usb/plusb.c Tue Apr 3 17:32:23 2001 +++ linux.ac/drivers/usb/plusb.c Tue Apr 3 17:55:07 2001 @@ -255,7 +255,7 @@ /* * dequeue_next_skb - submit the first thing on the tx_skb_list to the * USB stack. This function should be called each time we get a new - * message to send to the other host, or each time a message is sucessfully + * message to send to the other host, or each time a message is successfully * sent. */ static void dequeue_next_skb(char * func, plusb_t * s) @@ -393,7 +393,7 @@ /* * plusb_write_bulk_complete () - callback after the data has been - * sent to the USB device, or a timeout occured. + * sent to the USB device, or a timeout occurred. */ static void plusb_write_bulk_complete(urb_t *purb) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/printer.c linux.ac/drivers/usb/printer.c --- linux.vanilla/drivers/usb/printer.c Tue Apr 3 17:32:23 2001 +++ linux.ac/drivers/usb/printer.c Tue Apr 3 17:55:07 2001 @@ -634,6 +634,9 @@ } static struct usb_device_id usblp_ids [] = { + { USB_DEVICE_INFO(7, 1, 1) }, + { USB_DEVICE_INFO(7, 1, 2) }, + { USB_DEVICE_INFO(7, 1, 3) }, { USB_INTERFACE_INFO(7, 1, 1) }, { USB_INTERFACE_INFO(7, 1, 2) }, { USB_INTERFACE_INFO(7, 1, 3) }, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/scanner.c linux.ac/drivers/usb/scanner.c --- linux.vanilla/drivers/usb/scanner.c Tue Apr 3 17:32:23 2001 +++ linux.ac/drivers/usb/scanner.c Tue Apr 3 17:55:07 2001 @@ -174,7 +174,7 @@ * <flynn@isr.uni-stuttgart.de>. * - Added iVina 1200U ID. Thanks to Dyson Lin <dyson@avision.com.tw>. * - Added access time update for the device file courtesy of Paul - * Mackerras <paulus@linuxcare.com>. This allows a user space daemon + * Mackerras <paulus@samba.org>. This allows a user space daemon * to turn the lamp off for a Umax 1220U scanner after a prescribed * time. * - Fixed HP S20 ID's. Thanks to Ruud Linders <rlinders@xs4all.nl>. @@ -420,7 +420,7 @@ dbg("write stats(%d): result:%d this_write:%d partial:%d", scn_minor, result, this_write, partial); if (result == -ETIMEDOUT) { /* NAK -- shouldn't happen */ - warn("write_scanner: NAK recieved."); + warn("write_scanner: NAK received."); ret = result; break; } else if (result < 0) { /* We should not get any I/O errors */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/scanner.h linux.ac/drivers/usb/scanner.h --- linux.vanilla/drivers/usb/scanner.h Tue Apr 3 17:32:23 2001 +++ linux.ac/drivers/usb/scanner.h Tue Apr 17 18:42:35 2001 @@ -120,8 +120,9 @@ { USB_DEVICE(0x04b8, 0x0104) }, /* Perfection 1200U and 1200Photo*/ { USB_DEVICE(0x04b8, 0x0106) }, /* Stylus Scan 2500 */ { USB_DEVICE(0x04b8, 0x0107) }, /* Expression 1600 */ - { USB_DEVICE(0x04b8, 0x010b) }, /* Perfection 1240U */ { USB_DEVICE(0x04b8, 0x010a) }, /* Perfection 1640SU and 1640SU Photo */ + { USB_DEVICE(0x04b8, 0x010b) }, /* Perfection 1240U */ + { USB_DEVICE(0x04b8, 0x010c) }, /* Perfection 640U */ /* Umax */ { USB_DEVICE(0x1606, 0x0010) }, /* Astra 1220U */ { USB_DEVICE(0x1606, 0x0030) }, /* Astra 2000U */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/Config.in linux.ac/drivers/usb/serial/Config.in --- linux.vanilla/drivers/usb/serial/Config.in Tue Apr 3 17:32:23 2001 +++ linux.ac/drivers/usb/serial/Config.in Tue Apr 10 18:18:11 2001 @@ -4,9 +4,11 @@ mainmenu_option next_comment comment 'USB Serial Converter support' -tristate 'USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB +dep_tristate 'USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB if [ "$CONFIG_USB_SERIAL" != "n" ]; then - bool ' USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG + if [ "$CONFIG_USB_SERIAL" = "y" ]; then + bool ' USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG + fi bool ' USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC dep_tristate ' USB Belkin and Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/belkin_sa.c linux.ac/drivers/usb/serial/belkin_sa.c --- linux.vanilla/drivers/usb/serial/belkin_sa.c Tue Apr 3 17:32:23 2001 +++ linux.ac/drivers/usb/serial/belkin_sa.c Tue Apr 10 18:18:30 2001 @@ -68,13 +68,13 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/usb.h> #ifdef CONFIG_USB_SERIAL_DEBUG - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> #include "usb-serial.h" #include "belkin_sa.h" @@ -607,3 +607,7 @@ module_exit (belkin_sa_exit); MODULE_DESCRIPTION("USB Belkin Serial converter driver"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/belkin_sa.h linux.ac/drivers/usb/serial/belkin_sa.h --- linux.vanilla/drivers/usb/serial/belkin_sa.h Tue Apr 3 17:32:23 2001 +++ linux.ac/drivers/usb/serial/belkin_sa.h Tue Apr 10 18:18:36 2001 @@ -43,7 +43,7 @@ #define PERACOM_PID 0x0001 /* Peracom's single port serial converter's id */ #define GOHUBS_VID 0x0921 /* GoHubs vendor id */ -#define GOHUBS_PID 0x0100 /* GoHubs single port serial converter's id (identical to the Peracom device) */ +#define GOHUBS_PID 0x1000 /* GoHubs single port serial converter's id (identical to the Peracom device) */ /* Vendor Request Interface */ #define BELKIN_SA_SET_BAUDRATE_REQUEST 0 /* Set baud rate */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/digi_acceleport.c linux.ac/drivers/usb/serial/digi_acceleport.c --- linux.vanilla/drivers/usb/serial/digi_acceleport.c Tue Apr 3 17:32:23 2001 +++ linux.ac/drivers/usb/serial/digi_acceleport.c Tue Apr 10 18:18:36 2001 @@ -241,14 +241,14 @@ #include <linux/module.h> #include <linux/spinlock.h> #include <linux/tqueue.h> +#include <linux/usb.h> #ifdef CONFIG_USB_SERIAL_DEBUG - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> #include "usb-serial.h" @@ -2085,4 +2085,7 @@ MODULE_AUTHOR("Peter Berger <pberger@brimson.com>, Al Borchers <borchers@steinerpoint.com>"); MODULE_DESCRIPTION("Digi AccelePort USB-2/USB-4 Serial Converter driver"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/empeg.c linux.ac/drivers/usb/serial/empeg.c --- linux.vanilla/drivers/usb/serial/empeg.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/usb/serial/empeg.c Tue Apr 10 18:18:41 2001 @@ -55,12 +55,13 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/usb.h> + #ifdef CONFIG_USB_SERIAL_DEBUG - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> #include "usb-serial.h" @@ -705,3 +706,7 @@ MODULE_AUTHOR("Gary Brubaker <xavyer@ix.netcom.com>"); MODULE_DESCRIPTION("USB Empeg Mark I/II Driver"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/ftdi_sio.c linux.ac/drivers/usb/serial/ftdi_sio.c --- linux.vanilla/drivers/usb/serial/ftdi_sio.c Tue Apr 3 17:32:23 2001 +++ linux.ac/drivers/usb/serial/ftdi_sio.c Tue Apr 10 18:18:41 2001 @@ -78,16 +78,15 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/usb.h> #ifdef CONFIG_USB_SERIAL_DEBUG - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> #include "usb-serial.h" - #include "ftdi_sio.h" @@ -423,7 +422,7 @@ unsigned char *first_byte = port->write_urb->transfer_buffer; /* Was seeing a race here, got a read callback, then write callback before - hitting interuptible_sleep_on - so wrapping in a wait_queue */ + hitting interruptible_sleep_on - so wrapping in a wait_queue */ add_wait_queue(&port->write_wait, &wait); set_current_state (TASK_INTERRUPTIBLE); @@ -881,3 +880,7 @@ MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>"); MODULE_DESCRIPTION("USB FTDI RS232 converters driver"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/io_edgeport.c linux.ac/drivers/usb/serial/io_edgeport.c --- linux.vanilla/drivers/usb/serial/io_edgeport.c Tue Apr 3 17:32:24 2001 +++ linux.ac/drivers/usb/serial/io_edgeport.c Tue Apr 10 18:18:46 2001 @@ -223,6 +223,7 @@ * */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/signal.h> @@ -239,15 +240,14 @@ #include <linux/serial.h> #include <linux/ioctl.h> #include <linux/proc_fs.h> +#include <linux/usb.h> #ifdef CONFIG_USB_SERIAL_DEBUG - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> - #include "usb-serial.h" #include "io_edgeport.h" @@ -279,6 +279,9 @@ MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli"); MODULE_DESCRIPTION("Edgeport USB Serial Driver"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + #define MAX_NAME_LEN 64 @@ -474,47 +477,6 @@ - -#ifdef DEBUG - -/* Dump a buffer in HEX and Ascii */ -void DbgDisplayBuffer( void *pBuffer, __u32 Len ) -{ - char DisplayBuf[80]; - char * pStr = DisplayBuf; - __u8 *pBuf = pBuffer; - __u32 i; - __u8 d; - - while (Len) { - // Init for new line - memset( DisplayBuf, ' ', sizeof( DisplayBuf )); - DisplayBuf[79]=0; - pStr = DisplayBuf; - pStr[54] = '['; - pStr[71] = ']'; - - for ( i = 0; i < MIN(16, Len) ; i++ ) { - d = (__u8)(*pBuf >> 4); - pStr[(i*3)+0] = (char)((d < 10) ? d+'0' : d -10 + 'A'); - d = (__u8)(*pBuf & 0xf); - pStr[(i*3)+1] = (char)((d < 10) ? d+'0' : d -10 + 'A'); - - if (*pBuf > 31 && *pBuf < 127) - pStr[i+55]=*pBuf; - else - pStr[i+55]='.'; - - pBuf++; - } - Len -= i; - dbg("%s", DisplayBuf ); - } -} -#endif - - - // ************************************************************************ // ************************************************************************ // ************************************************************************ @@ -745,7 +707,6 @@ break; } -#ifdef DEBUG // Dump Product Info structure dbg("**Product Information:"); dbg(" ProductId %x", product_info->ProductId ); @@ -770,7 +731,6 @@ product_info->ManufactureDescDate[2]+1900); dbg(" iDownloadFile 0x%x", product_info->iDownloadFile); -#endif } @@ -812,14 +772,7 @@ // process this interrupt-read even if there are no ports open if (length) { -#ifdef DEBUG - int i; - printk (KERN_DEBUG __FILE__ ": "__FUNCTION__" - length = %d, data = ", length); - for (i = 0; i < length; ++i) { - printk ("%.2x ", data[i]); - } - printk ("\n"); -#endif + usb_serial_debug_data (__FILE__, __FUNCTION__, length, data); if (length > 1) { bytes_avail = data[0] | (data[1] << 8); @@ -894,13 +847,7 @@ if (urb->actual_length) { raw_data_length = urb->actual_length; -#ifdef DEBUG - { -// int i; - dbg (__FUNCTION__" - length = %d, data = ", raw_data_length); -// DbgDisplayBuffer((void *)data, raw_data_length); - } -#endif + usb_serial_debug_data (__FILE__, __FUNCTION__, raw_data_length, data); /* decrement our rxBytes available by the number that we just got */ edge_serial->rxBytesAvail -= raw_data_length; @@ -976,10 +923,8 @@ dbg(__FUNCTION__); -#ifdef DEBUG CmdUrbs--; dbg(__FUNCTION__" - FREE URB %p (outstanding %d)", urb, CmdUrbs); -#endif /* if this urb had a transfer buffer already (old transfer) free it */ @@ -1412,12 +1357,9 @@ // No need to check for wrap since we can not get to end of fifo in this part } -#ifdef DEBUG if (copySize) { - dbg (__FUNCTION__" - length = %d, data = ", copySize); - DbgDisplayBuffer((void *)data, copySize); + usb_serial_debug_data (__FILE__, __FUNCTION__, copySize, data); } -#endif send_more_port_data((struct edgeport_serial *)port->serial->private, edge_port); @@ -1519,12 +1461,9 @@ fifo->count -= secondhalf; } -#ifdef DEBUG if (count) { - dbg (__FUNCTION__" - length = %d, data = ", count); - DbgDisplayBuffer((void *)&buffer[2], count); + usb_serial_debug_data (__FILE__, __FUNCTION__, count, &buffer[2]); } -#endif /* fill up the urb with all of our data and submit it */ FILL_BULK_URB (urb, edge_serial->serial->dev, @@ -2498,16 +2437,7 @@ urb_t *urb; int timeout; -#ifdef DEBUG - if (length) { - int i; - printk (KERN_DEBUG __FILE__ ": "__FUNCTION__" - length = %d, buffer = ", length); - for (i = 0; i < length; ++i) { - printk ("%.2x ", buffer[i]); - } - printk ("\n"); - } -#endif + usb_serial_debug_data (__FILE__, __FUNCTION__, length, buffer); /* Allocate our next urb */ urb = usb_alloc_urb (0); @@ -2857,7 +2787,6 @@ if (response < 1) { err("error in getting manufacturer descriptor"); } else { -#ifdef DEBUG char string[30]; dbg("**Manufacturer Descriptor"); dbg(" RomSize: %dK", edge_serial->manuf_descriptor.RomSize); @@ -2875,7 +2804,6 @@ dbg(" UartType: %d", edge_serial->manuf_descriptor.UartType); dbg(" IonPid: %d", edge_serial->manuf_descriptor.IonPid); dbg(" IonConfig: %d", edge_serial->manuf_descriptor.IonConfig); -#endif } } @@ -3138,6 +3066,4 @@ module_init(edgeport_init); module_exit(edgeport_exit); - - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/keyspan.c linux.ac/drivers/usb/serial/keyspan.c --- linux.vanilla/drivers/usb/serial/keyspan.c Tue Apr 3 17:32:24 2001 +++ linux.ac/drivers/usb/serial/keyspan.c Sat Apr 14 01:36:05 2001 @@ -49,6 +49,7 @@ */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/signal.h> @@ -62,13 +63,14 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> - -#define DEBUG -/* #ifdef CONFIG_USB_SERIAL_DEBUG */ - #define DEBUG -/* #endif */ #include <linux/usb.h> +#ifdef CONFIG_USB_SERIAL_DEBUG + static int debug = 1; +#else + static int debug; +#endif + #include "usb-serial.h" #include "keyspan.h" @@ -1671,3 +1673,7 @@ kfree(port->private); } } + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/keyspan_pda.c linux.ac/drivers/usb/serial/keyspan_pda.c --- linux.vanilla/drivers/usb/serial/keyspan_pda.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/usb/serial/keyspan_pda.c Tue Apr 10 18:18:53 2001 @@ -67,13 +67,14 @@ #include <linux/module.h> #include <linux/spinlock.h> #include <linux/tqueue.h> +#include <linux/usb.h> #ifdef CONFIG_USB_SERIAL_DEBUG - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> + struct ezusb_hex_record { __u16 address; @@ -82,7 +83,6 @@ }; #include "keyspan_pda_fw.h" - #include "usb-serial.h" struct keyspan_pda_private { @@ -823,3 +823,7 @@ MODULE_AUTHOR("Brian Warner <warner@lothar.com>"); MODULE_DESCRIPTION("USB Keyspan PDA Converter driver"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/mct_u232.c linux.ac/drivers/usb/serial/mct_u232.c --- linux.vanilla/drivers/usb/serial/mct_u232.c Tue Apr 3 17:32:24 2001 +++ linux.ac/drivers/usb/serial/mct_u232.c Tue Apr 10 18:18:53 2001 @@ -53,13 +53,13 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/usb.h> #ifdef CONFIG_USB_SERIAL_DEBUG - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> #include "usb-serial.h" #include "mct_u232.h" @@ -848,3 +848,7 @@ MODULE_PARM_DESC(write_blocking, "The write function will block to write out all data"); #endif + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/omninet.c linux.ac/drivers/usb/serial/omninet.c --- linux.vanilla/drivers/usb/serial/omninet.c Tue Apr 3 17:32:24 2001 +++ linux.ac/drivers/usb/serial/omninet.c Tue Apr 10 18:18:53 2001 @@ -43,17 +43,14 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> - +#include <linux/usb.h> #ifdef CONFIG_USB_SERIAL_DEBUG - #define isalpha(x) ( ( x > 96 && x < 123) || ( x > 64 && x < 91) || (x > 47 && x < 58) ) - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> - #include "usb-serial.h" @@ -252,8 +249,7 @@ return; } -#ifdef DEBUG - if(header->oh_xxx != 0x30) { + if ((debug) && (header->oh_xxx != 0x30)) { if (urb->actual_length) { printk (KERN_DEBUG __FILE__ ": omninet_read %d: ", header->oh_len); for (i = 0; i < (header->oh_len + OMNINET_HEADERLEN); i++) { @@ -262,7 +258,6 @@ printk ("\n"); } } -#endif if (urb->actual_length && header->oh_len) { for (i = 0; i < header->oh_len; i++) { @@ -413,4 +408,7 @@ module_init(omninet_init); module_exit(omninet_exit); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/usb-serial.h linux.ac/drivers/usb/serial/usb-serial.h --- linux.vanilla/drivers/usb/serial/usb-serial.h Mon Dec 11 21:17:29 2000 +++ linux.ac/drivers/usb/serial/usb-serial.h Tue Apr 10 18:18:53 2001 @@ -219,15 +219,24 @@ static inline void usb_serial_debug_data (const char *file, const char *function, int size, const unsigned char *data) { -#ifdef CONFIG_USB_SERIAL_DEBUG int i; + + if (!debug) + return; + printk (KERN_DEBUG "%s: %s - length = %d, data = ", file, function, size); for (i = 0; i < size; ++i) { printk ("%.2x ", data[i]); } printk ("\n"); -#endif } + + +/* Use our own dbg macro */ +#undef dbg +#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0) + + #endif /* ifdef __LINUX_USB_SERIAL_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/usbserial.c linux.ac/drivers/usb/serial/usbserial.c --- linux.vanilla/drivers/usb/serial/usbserial.c Tue Apr 3 17:32:24 2001 +++ linux.ac/drivers/usb/serial/usbserial.c Tue Apr 10 18:18:53 2001 @@ -272,19 +272,24 @@ #include <linux/spinlock.h> #include <linux/list.h> #include <linux/smp_lock.h> +#include <linux/usb.h> #ifdef CONFIG_USB_SERIAL_DEBUG - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> + +#include "usb-serial.h" + /* Module information */ MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/"); MODULE_DESCRIPTION("USB Serial Driver"); -#include "usb-serial.h" +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + #define MAX(a,b) (((a)>(b))?(a):(b)) @@ -298,10 +303,10 @@ static int generic_chars_in_buffer (struct usb_serial_port *port); static void generic_read_bulk_callback (struct urb *urb); static void generic_write_bulk_callback (struct urb *urb); -static void generic_shutdown (struct usb_serial *serial); #ifdef CONFIG_USB_SERIAL_GENERIC +static void generic_shutdown (struct usb_serial *serial); static __u16 vendor = 0x05f9; static __u16 product = 0xffff; MODULE_PARM(vendor, "i"); @@ -365,6 +370,7 @@ static struct termios * serial_termios_locked[SERIAL_TTY_MINORS]; static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ + LIST_HEAD(usb_serial_driver_list); @@ -968,6 +974,7 @@ } +#ifdef CONFIG_USB_SERIAL_GENERIC static void generic_shutdown (struct usb_serial *serial) { int i; @@ -981,6 +988,7 @@ } } } +#endif static void port_softint(void *private) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/visor.c linux.ac/drivers/usb/serial/visor.c --- linux.vanilla/drivers/usb/serial/visor.c Tue Apr 3 17:32:24 2001 +++ linux.ac/drivers/usb/serial/visor.c Tue Apr 10 18:19:00 2001 @@ -92,16 +92,15 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/usb.h> #ifdef CONFIG_USB_SERIAL_DEBUG - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> #include "usb-serial.h" - #include "visor.h" #define MIN(a,b) (((a)<(b))?(a):(b)) @@ -689,3 +688,7 @@ MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>"); MODULE_DESCRIPTION("USB HandSpring Visor driver"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/visor.h linux.ac/drivers/usb/serial/visor.h --- linux.vanilla/drivers/usb/serial/visor.h Fri May 5 21:41:30 2000 +++ linux.ac/drivers/usb/serial/visor.h Tue Apr 3 17:55:08 2001 @@ -29,7 +29,7 @@ /**************************************************************************** * VISOR_REQUEST_BYTES_AVAILABLE asks the visor for the number of bytes that - * are available to be transfered to the host for the specified endpoint. + * are available to be transferred to the host for the specified endpoint. * Currently this is not used, and always returns 0x0001 ****************************************************************************/ #define VISOR_REQUEST_BYTES_AVAILABLE 0x01 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/whiteheat.c linux.ac/drivers/usb/serial/whiteheat.c --- linux.vanilla/drivers/usb/serial/whiteheat.c Tue Apr 3 17:32:24 2001 +++ linux.ac/drivers/usb/serial/whiteheat.c Tue Apr 10 18:19:00 2001 @@ -67,18 +67,16 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/usb.h> #ifdef CONFIG_USB_SERIAL_DEBUG - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> #include "usb-serial.h" - #include "whiteheat_fw.h" /* firmware for the ConnectTech WhiteHEAT device */ - #include "whiteheat.h" /* WhiteHEAT specific commands */ #define CONNECT_TECH_VENDOR_ID 0x0710 @@ -634,3 +632,7 @@ MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>"); MODULE_DESCRIPTION("USB ConnectTech WhiteHEAT driver"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/storage/freecom.c linux.ac/drivers/usb/storage/freecom.c --- linux.vanilla/drivers/usb/storage/freecom.c Wed Nov 29 05:50:07 2000 +++ linux.ac/drivers/usb/storage/freecom.c Tue Apr 3 17:55:08 2001 @@ -96,7 +96,7 @@ #define FCM_PACKET_OUTPUT 0x01 /* Write a value to an ide register. Or the ide register to write after - * munging the addres a bit. */ + * munging the address a bit. */ #define FCM_PACKET_IDE_WRITE 0x40 #define FCM_PACKET_IDE_READ 0xC0 @@ -412,7 +412,7 @@ US_DEBUG(pdump ((void *) fst, partial)); - /* while we haven't recieved the IRQ */ + /* while we haven't received the IRQ */ while (!(fst->Status & 0x2)) { /* send a command to re-fetch the status */ US_DEBUGP("Re-attempting to get status...\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/storage/scsiglue.c linux.ac/drivers/usb/storage/scsiglue.c --- linux.vanilla/drivers/usb/storage/scsiglue.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/usb/storage/scsiglue.c Tue Apr 3 17:55:08 2001 @@ -122,7 +122,8 @@ */ US_DEBUGP("-- sending US_ACT_EXIT command to thread\n"); us->action = US_ACT_EXIT; - wake_up(&(us->wqh)); + + up(&(us->sema)); down(&(us->notify)); /* remove the pointer to the data structure we were using */ @@ -160,7 +161,7 @@ up(&(us->queue_exclusion)); /* wake up the process task */ - wake_up(&(us->wqh)); + up(&(us->sema)); return 0; } @@ -331,7 +332,7 @@ return -ESRCH; } - /* print the controler name */ + /* print the controller name */ SPRINTF(" Host scsi%d: usb-storage\n", hostno); /* print product, vendor, and serial number strings */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/storage/sddr09.c linux.ac/drivers/usb/storage/sddr09.c --- linux.vanilla/drivers/usb/storage/sddr09.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/usb/storage/sddr09.c Tue Apr 3 17:55:08 2001 @@ -182,7 +182,7 @@ return US_BULK_TRANSFER_SHORT; } - US_DEBUGP("Transfered %d of %d bytes\n", act_len, len); + US_DEBUGP("Transferred %d of %d bytes\n", act_len, len); return US_BULK_TRANSFER_GOOD; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/storage/transport.c linux.ac/drivers/usb/storage/transport.c --- linux.vanilla/drivers/usb/storage/transport.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/usb/storage/transport.c Tue Apr 3 17:55:08 2001 @@ -635,7 +635,7 @@ /* Invoke the transport and basic error-handling/recovery methods * * This is used by the protocol layers to actually send the message to - * the device and recieve the response. + * the device and receive the response. */ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) { @@ -821,7 +821,7 @@ { struct us_data *us = (struct us_data *)urb->context; - US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no); + US_DEBUGP("USB IRQ received for device on host %d\n", us->host_no); US_DEBUGP("-- IRQ data length is %d\n", urb->actual_length); US_DEBUGP("-- IRQ state is %d\n", urb->status); US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n", @@ -1117,7 +1117,7 @@ return USB_STOR_TRANSPORT_ERROR; } - /* if the command transfered well, then we go to the data stage */ + /* if the command transferred well, then we go to the data stage */ if (result == 0) { /* send/receive data payload, if there is any */ if (bcb.DataTransferLength) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/storage/transport.h linux.ac/drivers/usb/storage/transport.h --- linux.vanilla/drivers/usb/storage/transport.h Thu Feb 22 00:11:24 2001 +++ linux.ac/drivers/usb/storage/transport.h Tue Apr 17 18:44:10 2001 @@ -107,7 +107,7 @@ * us_bulk_transfer() return codes */ #define US_BULK_TRANSFER_GOOD 0 /* good transfer */ -#define US_BULK_TRANSFER_SHORT 1 /* transfered less than expected */ +#define US_BULK_TRANSFER_SHORT 1 /* transferred less than expected */ #define US_BULK_TRANSFER_FAILED 2 /* transfer died in the middle */ #define US_BULK_TRANSFER_ABORTED 3 /* transfer canceled */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/storage/unusual_devs.h linux.ac/drivers/usb/storage/unusual_devs.h --- linux.vanilla/drivers/usb/storage/unusual_devs.h Thu Feb 22 00:11:24 2001 +++ linux.ac/drivers/usb/storage/unusual_devs.h Tue Apr 3 19:11:04 2001 @@ -54,6 +54,11 @@ US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0), #endif +UNUSUAL_DEV( 0x04cb, 0x0100, 0x0000, 0x2210, + "Fujifilm", + "FinePix 1400Zoom", + US_SC_8070, US_PR_CBI, NULL, US_FL_FIX_INQUIRY), + UNUSUAL_DEV( 0x04e6, 0x0001, 0x0200, 0x0200, "Matshita", "LS-120", @@ -132,6 +137,12 @@ US_SC_UFI, US_PR_CB, NULL, US_FL_SINGLE_LUN | US_FL_START_STOP ), +UNUSUAL_DEV( 0x054c, 0x0032, 0x0000, 0x9999, + "Sony", + "Memorystick MSC-U01N", + US_SC_UFI, US_PR_CB, NULL, + US_FL_SINGLE_LUN | US_FL_START_STOP ), + UNUSUAL_DEV( 0x057b, 0x0000, 0x0000, 0x0299, "Y-E Data", "Flashbuster-U", @@ -229,4 +240,10 @@ US_SC_SCSI, US_PR_DPCM_USB, NULL, US_FL_START_STOP ), #endif + +UNUSUAL_DEV( 0x07cf, 0x1001, 0x9009, 0x9009, + "Casio", + "QV DigitalCamera", + US_SC_8070, US_PR_CB, NULL, + US_FL_FIX_INQUIRY ), diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/storage/usb.c linux.ac/drivers/usb/storage/usb.c --- linux.vanilla/drivers/usb/storage/usb.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/usb/storage/usb.c Tue Apr 3 17:55:08 2001 @@ -281,7 +281,6 @@ static int usb_stor_control_thread(void * __us) { - wait_queue_t wait; struct us_data *us = (struct us_data *)__us; int action; @@ -302,9 +301,7 @@ unlock_kernel(); /* set up for wakeups by new commands */ - init_waitqueue_entry(&wait, current); - init_waitqueue_head(&(us->wqh)); - add_wait_queue(&(us->wqh), &wait); + init_MUTEX_LOCKED(&us->sema); /* signal that we've started the thread */ up(&(us->notify)); @@ -312,7 +309,9 @@ for(;;) { US_DEBUGP("*** thread sleeping.\n"); - schedule(); + if(down_interruptible(&us->sema)) + break; + US_DEBUGP("*** thread awakened.\n"); /* lock access to the queue element */ @@ -378,6 +377,22 @@ break; } + if ((us->srb->cmnd[0] == INQUIRY) && + (us->flags & US_FL_FIX_INQUIRY)) { + unsigned char data_ptr[36] = { + 0x00, 0x80, 0x02, 0x02, 0x1F, 0x00, 0x00, 0x00}; + + US_DEBUGP("Faking INQUIRY command\n"); + fill_inquiry_response(us, data_ptr, 36); + us->srb->result = GOOD << 1; + + set_current_state(TASK_INTERRUPTIBLE); + us->srb->scsi_done(us->srb); + us->srb = NULL; + break; + } + + /* lock the device pointers */ down(&(us->dev_semaphore)); @@ -435,14 +450,13 @@ /* exit if we get a signal to exit */ if (action == US_ACT_EXIT) { - US_DEBUGP("-- US_ACT_EXIT command recieved\n"); + US_DEBUGP("-- US_ACT_EXIT command received\n"); break; } } /* for (;;) */ /* clean up after ourselves */ set_current_state(TASK_INTERRUPTIBLE); - remove_wait_queue(&(us->wqh), &wait); /* notify the exit routine that we're actually exiting now */ up(&(us->notify)); @@ -907,7 +921,7 @@ ss->host_number = my_host_number++; /* We abuse this pointer so we can pass the ss pointer to - * the host controler thread in us_detect. But how else are + * the host controller thread in us_detect. But how else are * we to do it? */ (struct us_data *)ss->htmplt.proc_dir = ss; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/storage/usb.h linux.ac/drivers/usb/storage/usb.h --- linux.vanilla/drivers/usb/storage/usb.h Tue Apr 3 17:32:24 2001 +++ linux.ac/drivers/usb/storage/usb.h Tue Apr 17 18:44:10 2001 @@ -94,11 +94,12 @@ /* Flag definitions */ #define US_FL_SINGLE_LUN 0x00000001 /* allow access to only LUN 0 */ -#define US_FL_MODE_XLATE 0x00000002 /* translate _6 to _10 comands for +#define US_FL_MODE_XLATE 0x00000002 /* translate _6 to _10 commands for Win/MacOS compatibility */ #define US_FL_START_STOP 0x00000004 /* ignore START_STOP commands */ #define US_FL_IGNORE_SER 0x00000010 /* Ignore the serial number given */ #define US_FL_SCM_MULT_TARG 0x00000020 /* supports multiple targets */ +#define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs fixing */ #define USB_STOR_STRING_LEN 32 @@ -165,8 +166,8 @@ struct semaphore current_urb_sem; /* to protect irq_urb */ struct urb *current_urb; /* non-int USB requests */ - /* the waitqueue for sleeping the control thread */ - wait_queue_head_t wqh; /* to sleep thread on */ + /* the semaphore for sleeping the control thread */ + struct semaphore sema; /* to sleep thread on */ /* mutual exclusion structures */ struct semaphore notify; /* thread begin/end */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/uhci-debug.h linux.ac/drivers/usb/uhci-debug.h --- linux.vanilla/drivers/usb/uhci-debug.h Thu Feb 22 00:11:50 2001 +++ linux.ac/drivers/usb/uhci-debug.h Tue Apr 17 18:42:20 2001 @@ -6,20 +6,23 @@ * visible pointers are surrounded in ()'s * * (C) Copyright 1999 Linus Torvalds - * (C) Copyright 1999 Johannes Erdfelt + * (C) Copyright 1999-2001 Johannes Erdfelt */ +#include <linux/config.h> #include <linux/kernel.h> +#include <linux/proc_fs.h> #include <asm/io.h> #include "uhci.h" -void uhci_show_td(struct uhci_td *td) +static int uhci_show_td(struct uhci_td *td, char *buf, int len) { + char *out = buf; char *spid; - printk("%08x ", td->link); - printk("e%d %s%s%s%s%s%s%s%s%s%sLength=%x ", + out += sprintf(out, "[%p] link (%08x) ", td, td->link); + out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ", ((td->status >> 27) & 3), (td->status & TD_CTRL_SPD) ? "SPD " : "", (td->status & TD_CTRL_LS) ? "LS " : "", @@ -48,19 +51,23 @@ break; } - printk("MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ", + out += sprintf(out, "MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ", td->info >> 21, ((td->info >> 19) & 1), (td->info >> 15) & 15, (td->info >> 8) & 127, (td->info & 0xff), spid); - printk("(buf=%08x)\n", td->buffer); + out += sprintf(out, "(buf=%08x)\n", td->buffer); + + return out - buf; } -static void uhci_show_sc(int port, unsigned short status) +static int uhci_show_sc(int port, unsigned short status, char *buf, int len) { - printk(" stat%d = %04x %s%s%s%s%s%s%s%s\n", + char *out = buf; + + out += sprintf(out, " stat%d = %04x %s%s%s%s%s%s%s%s\n", port, status, (status & USBPORTSC_SUSP) ? "PortSuspend " : "", @@ -71,10 +78,13 @@ (status & USBPORTSC_PE) ? "PortEnabled " : "", (status & USBPORTSC_CSC) ? "ConnectChange " : "", (status & USBPORTSC_CCS) ? "PortConnected " : ""); + + return out - buf; } -void uhci_show_status(struct uhci *uhci) +static int uhci_show_status(struct uhci *uhci, char *buf, int len) { + char *out = buf; unsigned int io_addr = uhci->io_addr; unsigned short usbcmd, usbstat, usbint, usbfrnum; unsigned int flbaseadd; @@ -90,7 +100,7 @@ portsc1 = inw(io_addr + 16); portsc2 = inw(io_addr + 18); - printk(" usbcmd = %04x %s%s%s%s%s%s%s%s\n", + out += sprintf(out, " usbcmd = %04x %s%s%s%s%s%s%s%s\n", usbcmd, (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ", (usbcmd & USBCMD_CF) ? "CF " : "", @@ -101,7 +111,7 @@ (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "", (usbcmd & USBCMD_RS) ? "RS " : ""); - printk(" usbstat = %04x %s%s%s%s%s%s\n", + out += sprintf(out, " usbstat = %04x %s%s%s%s%s%s\n", usbstat, (usbstat & USBSTS_HCH) ? "HCHalted " : "", (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "", @@ -110,53 +120,66 @@ (usbstat & USBSTS_ERROR) ? "USBError " : "", (usbstat & USBSTS_USBINT) ? "USBINT " : ""); - printk(" usbint = %04x\n", usbint); - printk(" usbfrnum = (%d)%03x\n", (usbfrnum >> 10) & 1, + out += sprintf(out, " usbint = %04x\n", usbint); + out += sprintf(out, " usbfrnum = (%d)%03x\n", (usbfrnum >> 10) & 1, 0xfff & (4*(unsigned int)usbfrnum)); - printk(" flbaseadd = %08x\n", flbaseadd); - printk(" sof = %02x\n", sof); - uhci_show_sc(1, portsc1); - uhci_show_sc(2, portsc2); -} - -#define uhci_link_to_qh(x) ((struct uhci_qh *) uhci_link_to_td(x)) - -struct uhci_td *uhci_link_to_td(unsigned int link) -{ - if (link & UHCI_PTR_TERM) - return NULL; + out += sprintf(out, " flbaseadd = %08x\n", flbaseadd); + out += sprintf(out, " sof = %02x\n", sof); + out += uhci_show_sc(1, portsc1, out, len - (out - buf)); + out += uhci_show_sc(2, portsc2, out, len - (out - buf)); - return bus_to_virt(link & ~UHCI_PTR_BITS); + return out - buf; } -void uhci_show_urb_queue(struct urb *urb) +static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len) { - struct urb_priv *urbp = urb->hcpriv; + char *out = buf; + struct urb_priv *urbp; struct list_head *head, *tmp; - int i, checked = 0, prevactive = 0; + struct uhci_td *td; + int i = 0, checked = 0, prevactive = 0; + + out += sprintf(out, "[%p] link (%08x) element (%08x)\n", + qh, qh->link, qh->element); + if (qh->element & UHCI_PTR_QH) + out += sprintf(out, " Element points to QH (bug?)\n"); + + if (qh->element & UHCI_PTR_DEPTH) + out += sprintf(out, " Depth traverse\n"); - printk(" URB [%p] urbp [%p]\n", urb, urbp); + if (qh->element & UHCI_PTR_TERM) + out += sprintf(out, " Terminate\n"); - if (urbp->qh) - printk(" QH [%p]\n", urbp->qh); - else - printk(" QH [%p] element (%08x) link (%08x)\n", urbp->qh, - urbp->qh->element, urbp->qh->link); + if (!(qh->element & ~UHCI_PTR_BITS)) { + out += sprintf(out, " td 0: [NULL]\n"); + goto out; + } - i = 0; + if (!qh->urbp) { + out += sprintf(out, " urbp == NULL\n"); + goto out; + } - head = &urbp->list; + urbp = qh->urbp; + + head = &urbp->td_list; tmp = head->next; + + td = list_entry(tmp, struct uhci_td, list); + + if (td->dma_handle != (qh->element & ~3)) + out += sprintf(out, " Element != First TD\n"); + while (tmp != head) { struct uhci_td *td = list_entry(tmp, struct uhci_td, list); tmp = tmp->next; - printk(" td %d: [%p]\n", i++, td); - printk(" "); - uhci_show_td(td); + out += sprintf(out, " td %d: ", i++); + out += uhci_show_td(td, out, len - (out - buf)); - if (i > 10 && !checked && prevactive && tmp != head) { + if (i > 10 && !checked && prevactive && tmp != head && + debug <= 2) { struct list_head *ntmp = tmp; struct uhci_td *ntd = td; int active = 1, ni = i; @@ -174,7 +197,7 @@ } if (active && ni > i) { - printk(" [skipped %d active TD's]\n", ni - i); + out += sprintf(out, " [skipped %d active TD's]\n", ni - i); tmp = ntmp; td = ntd; i = ni; @@ -183,60 +206,30 @@ prevactive = td->status & TD_CTRL_ACTIVE; } -} - -void uhci_show_queue(struct uhci_qh *qh) -{ - struct uhci_td *td, *first; - int i = 0, count = 1000; - if (qh->element & UHCI_PTR_QH) - printk(" Element points to QH (bug?)\n"); + /* FIXME: Show queued URB's as well */ - if (qh->element & UHCI_PTR_DEPTH) - printk(" Depth traverse\n"); - - if (qh->element & UHCI_PTR_TERM) - printk(" Terminate\n"); - - if (!(qh->element & ~UHCI_PTR_BITS)) { - printk(" td 0: [NULL]\n"); - return; - } - - first = uhci_link_to_td(qh->element); - - /* Make sure it doesn't runaway */ - for (td = first; td && count > 0; - td = uhci_link_to_td(td->link), --count) { - printk(" td %d: [%p]\n", i++, td); - printk(" "); - uhci_show_td(td); - - if (td == uhci_link_to_td(td->link)) { - printk(KERN_ERR "td links to itself!\n"); - break; - } - } +out: + return out - buf; } -static int uhci_is_skeleton_td(struct uhci *uhci, struct uhci_td *td) +static inline int uhci_is_skeleton_td(struct uhci *uhci, struct uhci_td *td) { - int j; + int i; - for (j = 0; j < UHCI_NUM_SKELTD; j++) - if (td == uhci->skeltd + j) + for (i = 0; i < UHCI_NUM_SKELTD; i++) + if (td == uhci->skeltd[i]) return 1; return 0; } -static int uhci_is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh) +static inline int uhci_is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh) { - int j; + int i; - for (j = 0; j < UHCI_NUM_SKELQH; j++) - if (qh == uhci->skelqh + j) + for (i = 0; i < UHCI_NUM_SKELQH; i++) + if (qh == uhci->skelqh[i]) return 1; return 0; @@ -244,73 +237,262 @@ static const char *td_names[] = {"interrupt1", "interrupt2", "interrupt4", "interrupt8", "interrupt16", "interrupt32", - "interrupt64", "interrupt128", "interrupt256" }; -static const char *qh_names[] = { "control", "bulk" }; + "interrupt64", "interrupt128", "interrupt256", + "term" }; +static const char *qh_names[] = { "low speed control", "high speed control", + "bulk", "term" }; + +#define show_frame_num() \ + if (!shown) { \ + shown = 1; \ + out += sprintf(out, " Frame %d\n", i); \ + } -void uhci_show_queues(struct uhci *uhci) +#define show_td_name() \ + if (!shown) { \ + shown = 1; \ + out += sprintf(out, " %s: [%p] (%08x) link (%08x)\n", td_names[i], \ + td, td->dma_handle, td->link); \ + } + +#define show_qh_name() \ + if (!shown) { \ + shown = 1; \ + out += sprintf(out, " %s: [%p] (%08x) link (%08x) element (%08x)\n", \ + qh_names[i], qh, qh->dma_handle, qh->link, \ + qh->element); \ + } + +static int uhci_sprint_schedule(struct uhci *uhci, char *buf, int len) { - int i, isqh = 0; + char *out = buf; + int i; struct uhci_qh *qh; struct uhci_td *td; + struct list_head *tmp, *head; + out += sprintf(out, "HC status\n"); + out += uhci_show_status(uhci, out, len - (out - buf)); + + out += sprintf(out, "Frame List\n"); for (i = 0; i < UHCI_NUMFRAMES; ++i) { int shown = 0; - td = uhci_link_to_td(uhci->fl->frame[i]); - if (td) - isqh = uhci->fl->frame[i] & UHCI_PTR_QH; - while (td && !isqh) { - if (uhci_is_skeleton_td(uhci, td)) - break; - - if (!shown) { - printk(" Frame %d\n", i); - shown = 1; + td = uhci->fl->frame_cpu[i]; + if (!td) { + show_frame_num(); + out += sprintf(out, "Frame %d empty?\n", i); + continue; + } + + if (td->dma_handle != (dma_addr_t)uhci->fl->frame[i]) { + show_frame_num(); + out += sprintf(out, "frame_cpu does not match frame\n"); + } + + if (uhci_is_skeleton_td(uhci, td)) + continue; + + show_frame_num(); + + head = &td->fl_list; + tmp = head; + + do { + td = list_entry(tmp, struct uhci_td, fl_list); + + tmp = tmp->next; + + out += sprintf(out, " "); + out += uhci_show_td(td, out, len - (out - buf)); + } while (tmp != head); + } + + out += sprintf(out, "Skeleton TD's\n"); + for (i = UHCI_NUM_SKELTD - 1; i >= 0; i--) { + int shown = 0; + + td = uhci->skeltd[i]; + + if (debug > 2) + show_td_name(); + + if (list_empty(&td->fl_list)) { + if (i < 8 && i > 0) { + if (td->link != uhci->skeltd[i - 1]->dma_handle) { + show_td_name(); + out += sprintf(out, " Skeleton TD not linked to next skeleton TD!\n"); + } + } else if (!i) { + if (td->link != + (uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH)) { + show_td_name(); + out += sprintf(out, " Skeleton TD not linked to ls_control QH!\n"); + } } - printk("[%p] ", td); + continue; + } + + show_td_name(); + + head = &td->fl_list; + tmp = head->next; - uhci_show_td(td); - td = uhci_link_to_td(td->link); - if (td) - isqh = td->link & UHCI_PTR_QH; + while (tmp != head) { + td = list_entry(tmp, struct uhci_td, fl_list); + + tmp = tmp->next; + + out += sprintf(out, " "); + out += uhci_show_td(td, out, len - (out - buf)); } - } - for (i = 0; i < UHCI_NUM_SKELTD; ++i) { - printk(" %s: [%p] (%08x)\n", td_names[i], - &uhci->skeltd[i], - uhci->skeltd[i].link); - - td = uhci_link_to_td(uhci->skeltd[i].link); - if (td) - isqh = uhci->skeltd[i].link & UHCI_PTR_QH; - while (td && !isqh) { - if (uhci_is_skeleton_td(uhci, td)) - break; - - printk("[%p] ", td); - - uhci_show_td(td); - td = uhci_link_to_td(td->link); - if (td) - isqh = td->link & UHCI_PTR_QH; + + if (i < 8 && i > 0) { + if (td->link != uhci->skeltd[i - 1]->dma_handle) + out += sprintf(out, " Last TD not linked to next skeleton!\n"); + } else if (!i) { + if (td->link != + (uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH)) + out += sprintf(out, " Last TD not linked to ls_control QH!\n"); } } + + out += sprintf(out, "Skeleton QH's\n"); for (i = 0; i < UHCI_NUM_SKELQH; ++i) { - printk(" %s: [%p] (%08x) (%08x)\n", qh_names[i], - &uhci->skelqh[i], - uhci->skelqh[i].link, uhci->skelqh[i].element); - - qh = uhci_link_to_qh(uhci->skelqh[i].link); - for (; qh; qh = uhci_link_to_qh(qh->link)) { - if (uhci_is_skeleton_qh(uhci, qh)) - break; + int shown = 0; - printk(" [%p] (%08x) (%08x)\n", - qh, qh->link, qh->element); + qh = uhci->skelqh[i]; + + if (debug > 2) + show_qh_name(); + + if (list_empty(&qh->list)) + continue; + + show_qh_name(); - uhci_show_queue(qh); + head = &qh->list; + tmp = head->next; + + while (tmp != head) { + qh = list_entry(tmp, struct uhci_qh, list); + + tmp = tmp->next; + + out += sprintf(out, " "); + out += uhci_show_qh(qh, out, len - (out - buf)); } } + + return out - buf; } + +#ifdef CONFIG_PROC_FS +#define MAX_OUTPUT (PAGE_SIZE * 2) + +static struct proc_dir_entry *uhci_proc_root = NULL; + +struct uhci_proc { + int size; + char *data; + struct uhci *uhci; +}; + +static int uhci_proc_open(struct inode *inode, struct file *file) +{ + const struct proc_dir_entry *dp = inode->u.generic_ip; + struct uhci *uhci = dp->data; + struct uhci_proc *up; + unsigned long flags; + int ret = -ENOMEM; + + lock_kernel(); + up = kmalloc(sizeof(*up), GFP_KERNEL); + if (!up) + goto out; + + up->data = kmalloc(MAX_OUTPUT, GFP_KERNEL); + if (!up->data) { + kfree(up); + goto out; + } + + spin_lock_irqsave(&uhci->frame_list_lock, flags); + up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT); + spin_unlock_irqrestore(&uhci->frame_list_lock, flags); + + file->private_data = up; + + ret = 0; +out: + unlock_kernel(); + return ret; +} + +static loff_t uhci_proc_lseek(struct file *file, loff_t off, int whence) +{ + struct uhci_proc *up = file->private_data; + loff_t new; + + switch (whence) { + case 0: + new = off; + break; + case 1: + new = file->f_pos + off; + break; + case 2: + default: + return -EINVAL; + } + if (new < 0 || new > up->size) + return -EINVAL; + return (file->f_pos = new); +} + +static ssize_t uhci_proc_read(struct file *file, char *buf, size_t nbytes, + loff_t *ppos) +{ + struct uhci_proc *up = file->private_data; + unsigned int pos; + unsigned int size; + + pos = *ppos; + size = up->size; + if (pos >= size) + return 0; + if (nbytes >= size) + nbytes = size; + if (pos + nbytes > size) + nbytes = size - pos; + + if (!access_ok(VERIFY_WRITE, buf, nbytes)) + return -EINVAL; + + copy_to_user(buf, up->data + pos, nbytes); + + *ppos += nbytes; + + return nbytes; +} + +static int uhci_proc_release(struct inode *inode, struct file *file) +{ + struct uhci_proc *up = file->private_data; + + kfree(up->data); + kfree(up); + + return 0; +} + +static struct file_operations uhci_proc_operations = { + open: uhci_proc_open, + llseek: uhci_proc_lseek, + read: uhci_proc_read, +// write: uhci_proc_write, + release: uhci_proc_release, +}; +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/uhci.c linux.ac/drivers/usb/uhci.c --- linux.vanilla/drivers/usb/uhci.c Tue Apr 3 17:32:24 2001 +++ linux.ac/drivers/usb/uhci.c Tue Apr 3 17:55:08 2001 @@ -1,8 +1,10 @@ /* * Universal Host Controller Interface driver for USB. * + * Maintainer: Johannes Erdfelt <johannes@erdfelt.com> + * * (C) Copyright 1999 Linus Torvalds - * (C) Copyright 1999-2000 Johannes Erdfelt, johannes@erdfelt.com + * (C) Copyright 1999-2001 Johannes Erdfelt, johannes@erdfelt.com * (C) Copyright 1999 Randy Dunlap * (C) Copyright 1999 Georg Acher, acher@in.tum.de * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de @@ -12,7 +14,6 @@ * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) * - * * Intel documents this fairly well, and as far as I know there * are no royalties or anything like that, but even so there are * people who decided that they want to do the same thing in a @@ -39,7 +40,12 @@ #include <linux/unistd.h> #include <linux/interrupt.h> #include <linux/spinlock.h> +#include <linux/proc_fs.h> +#ifdef CONFIG_USB_DEBUG #define DEBUG +#else +#undef DEBUG +#endif #include <linux/usb.h> #include <asm/uaccess.h> @@ -48,23 +54,33 @@ #include <asm/system.h> #include "uhci.h" -#include "uhci-debug.h" #include <linux/pm.h> +/* + * debug = 0, no debugging messages + * debug = 1, dump failed URB's except for stalls + * debug = 2, dump all failed URB's (including stalls) + * show all queues in /proc/uhci/hc* + */ +#ifdef DEBUG static int debug = 1; +#else +static int debug = 0; +#endif MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debug level"); -static kmem_cache_t *uhci_td_cachep; -static kmem_cache_t *uhci_qh_cachep; +#include "uhci-debug.h" + static kmem_cache_t *uhci_up_cachep; /* urb_priv */ static int rh_submit_urb(struct urb *urb); static int rh_unlink_urb(struct urb *urb); static int uhci_get_current_frame_number(struct usb_device *dev); -static int uhci_unlink_generic(struct urb *urb); static int uhci_unlink_urb(struct urb *urb); +static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb); +static void uhci_call_completion(struct urb *urb); static int ports_active(struct uhci *uhci); static void suspend_hc(struct uhci *uhci); @@ -75,6 +91,8 @@ /* If a transfer is still active after this much time, turn off FSBR */ #define IDLE_TIMEOUT (HZ / 20) /* 50 ms */ +#define MAX_URB_LOOP 2048 /* Maximum number of linked URB's */ + /* * Only the USB core should call uhci_alloc_dev and uhci_free_dev */ @@ -86,87 +104,104 @@ static int uhci_free_dev(struct usb_device *dev) { struct uhci *uhci = (struct uhci *)dev->bus->hcpriv; - struct list_head *tmp, *head = &uhci->urb_list; + struct list_head list, *tmp, *head; unsigned long flags; /* Walk through the entire URB list and forcefully remove any */ /* URBs that are still active for that device */ - nested_lock(&uhci->urblist_lock, flags); + + /* Two stage unlink so we don't deadlock on urb_list_lock */ + INIT_LIST_HEAD(&list); + + spin_lock_irqsave(&uhci->urb_list_lock, flags); + head = &uhci->urb_list; tmp = head->next; while (tmp != head) { - struct urb *u = list_entry(tmp, struct urb, urb_list); + struct urb *urb = list_entry(tmp, struct urb, urb_list); tmp = tmp->next; - if (u->dev == dev) - uhci_unlink_urb(u); + if (urb->dev == dev) { + list_del(&urb->urb_list); + list_add(&urb->urb_list, &list); + } } - nested_unlock(&uhci->urblist_lock, flags); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); - return 0; -} + head = &list; + tmp = head->next; + while (tmp != head) { + struct urb *urb = list_entry(tmp, struct urb, urb_list); + + tmp = tmp->next; + + /* Make sure we block waiting on these to die */ + urb->transfer_flags &= ~USB_ASYNC_UNLINK; + + /* uhci_unlink_urb will unlink from the temp list */ + uhci_unlink_urb(urb); + } -static void uhci_add_urb_list(struct uhci *uhci, struct urb *urb) -{ - unsigned long flags; - nested_lock(&uhci->urblist_lock, flags); - list_add(&urb->urb_list, &uhci->urb_list); - nested_unlock(&uhci->urblist_lock, flags); + return 0; } -static void uhci_remove_urb_list(struct uhci *uhci, struct urb *urb) +static inline void uhci_set_next_interrupt(struct uhci *uhci) { unsigned long flags; - nested_lock(&uhci->urblist_lock, flags); - if (!list_empty(&urb->urb_list)) { - list_del(&urb->urb_list); - INIT_LIST_HEAD(&urb->urb_list); - } - nested_unlock(&uhci->urblist_lock, flags); + spin_lock_irqsave(&uhci->frame_list_lock, flags); + uhci->skel_term_td->status |= TD_CTRL_IOC; + spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } -void uhci_set_next_interrupt(struct uhci *uhci) +static inline void uhci_clear_next_interrupt(struct uhci *uhci) { unsigned long flags; - spin_lock_irqsave(&uhci->framelist_lock, flags); - uhci->skel_term_td.status |= TD_CTRL_IOC; - spin_unlock_irqrestore(&uhci->framelist_lock, flags); + spin_lock_irqsave(&uhci->frame_list_lock, flags); + uhci->skel_term_td->status &= ~TD_CTRL_IOC; + spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } -void uhci_clear_next_interrupt(struct uhci *uhci) +static inline void uhci_add_complete(struct urb *urb) { + struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; unsigned long flags; - spin_lock_irqsave(&uhci->framelist_lock, flags); - uhci->skel_term_td.status &= ~TD_CTRL_IOC; - spin_unlock_irqrestore(&uhci->framelist_lock, flags); + spin_lock_irqsave(&uhci->complete_list_lock, flags); + list_add(&urbp->complete_list, &uhci->complete_list); + spin_unlock_irqrestore(&uhci->complete_list_lock, flags); } -static struct uhci_td *uhci_alloc_td(struct usb_device *dev) +/* FIXME: We should do our own cache since pci_alloc_consistent is */ +/* inefficient under i386 and ia64 atleast. One page per TD, ick */ +static struct uhci_td *uhci_alloc_td(struct uhci *uhci, struct usb_device *dev) { + dma_addr_t dma_handle; struct uhci_td *td; - td = kmem_cache_alloc(uhci_td_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL); + td = pci_alloc_consistent(uhci->dev, sizeof(*td), &dma_handle); if (!td) return NULL; td->link = UHCI_PTR_TERM; td->buffer = 0; - td->frameptr = NULL; - td->nexttd = td->prevtd = NULL; + td->dma_handle = dma_handle; + td->frame = -1; td->dev = dev; + INIT_LIST_HEAD(&td->list); + INIT_LIST_HEAD(&td->fl_list); usb_inc_dev_use(dev); return td; } -static void inline uhci_fill_td(struct uhci_td *td, __u32 status, +static inline void uhci_fill_td(struct uhci_td *td, __u32 status, __u32 info, __u32 buffer) { td->status = status; @@ -177,20 +212,19 @@ static void uhci_insert_td(struct uhci *uhci, struct uhci_td *skeltd, struct uhci_td *td) { unsigned long flags; + struct uhci_td *ltd; - spin_lock_irqsave(&uhci->framelist_lock, flags); + spin_lock_irqsave(&uhci->frame_list_lock, flags); - /* Fix the linked list pointers */ - td->nexttd = skeltd->nexttd; - td->prevtd = skeltd; - if (skeltd->nexttd) - skeltd->nexttd->prevtd = td; - skeltd->nexttd = td; + ltd = list_entry(skeltd->fl_list.prev, struct uhci_td, fl_list); - td->link = skeltd->link; - skeltd->link = virt_to_bus(td); + td->link = ltd->link; + mb(); + ltd->link = td->dma_handle; - spin_unlock_irqrestore(&uhci->framelist_lock, flags); + list_add_tail(&td->fl_list, &skeltd->fl_list); + + spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } /* @@ -200,27 +234,36 @@ * frame list pointer -> iso td's (if any) -> * periodic interrupt td (if frame 0) -> irq td's -> control qh -> bulk qh */ - static void uhci_insert_td_frame_list(struct uhci *uhci, struct uhci_td *td, unsigned framenum) { unsigned long flags; - struct uhci_td *nexttd; framenum %= UHCI_NUMFRAMES; - spin_lock_irqsave(&uhci->framelist_lock, flags); + spin_lock_irqsave(&uhci->frame_list_lock, flags); + + td->frame = framenum; + + /* Is there a TD already mapped there? */ + if (uhci->fl->frame_cpu[framenum]) { + struct uhci_td *ftd, *ltd; + + ftd = uhci->fl->frame_cpu[framenum]; + ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list); - td->frameptr = &uhci->fl->frame[framenum]; - td->link = uhci->fl->frame[framenum]; - if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) { - nexttd = (struct uhci_td *)uhci_ptr_to_virt(td->link); - td->nexttd = nexttd; - nexttd->prevtd = td; - nexttd->frameptr = NULL; + list_add_tail(&td->fl_list, &ftd->fl_list); + + td->link = ltd->link; + mb(); + ltd->link = td->dma_handle; + } else { + td->link = uhci->fl->frame[framenum]; + mb(); + uhci->fl->frame[framenum] = td->dma_handle; + uhci->fl->frame_cpu[framenum] = td; } - uhci->fl->frame[framenum] = virt_to_bus(td); - spin_unlock_irqrestore(&uhci->framelist_lock, flags); + spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } static void uhci_remove_td(struct uhci *uhci, struct uhci_td *td) @@ -228,29 +271,36 @@ unsigned long flags; /* If it's not inserted, don't remove it */ - if (!td->frameptr && !td->prevtd && !td->nexttd) + if (td->frame == -1 && list_empty(&td->fl_list)) return; - spin_lock_irqsave(&uhci->framelist_lock, flags); - if (td->frameptr) { - *(td->frameptr) = td->link; - if (td->nexttd) { - td->nexttd->frameptr = td->frameptr; - td->nexttd->prevtd = NULL; - td->nexttd = NULL; + spin_lock_irqsave(&uhci->frame_list_lock, flags); + if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) { + if (list_empty(&td->fl_list)) { + uhci->fl->frame[td->frame] = td->link; + uhci->fl->frame_cpu[td->frame] = NULL; + } else { + struct uhci_td *ntd; + + ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list); + uhci->fl->frame[td->frame] = ntd->dma_handle; + uhci->fl->frame_cpu[td->frame] = ntd; } - td->frameptr = NULL; } else { - if (td->prevtd) { - td->prevtd->nexttd = td->nexttd; - td->prevtd->link = td->link; - } - if (td->nexttd) - td->nexttd->prevtd = td->prevtd; - td->prevtd = td->nexttd = NULL; + struct uhci_td *ptd; + + ptd = list_entry(td->fl_list.prev, struct uhci_td, fl_list); + ptd->link = td->link; } + + mb(); td->link = UHCI_PTR_TERM; - spin_unlock_irqrestore(&uhci->framelist_lock, flags); + + list_del(&td->fl_list); + INIT_LIST_HEAD(&td->fl_list); + td->frame = -1; + + spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } /* @@ -260,22 +310,21 @@ { struct list_head *tmp, *head; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct uhci_td *td, *prevtd; + struct uhci_td *td, *ptd; - if (!urbp) - return; - - head = &urbp->list; + head = &urbp->td_list; tmp = head->next; if (head == tmp) return; + /* Ordering isn't important here yet since the QH hasn't been */ + /* inserted into the schedule yet */ td = list_entry(tmp, struct uhci_td, list); /* Add the first TD to the QH element pointer */ - qh->element = virt_to_bus(td) | (breadth ? 0 : UHCI_PTR_DEPTH); + qh->element = td->dma_handle | (breadth ? 0 : UHCI_PTR_DEPTH); - prevtd = td; + ptd = td; /* Then link the rest of the TD's */ tmp = tmp->next; @@ -284,39 +333,43 @@ tmp = tmp->next; - prevtd->link = virt_to_bus(td) | (breadth ? 0 : UHCI_PTR_DEPTH); + ptd->link = td->dma_handle | (breadth ? 0 : UHCI_PTR_DEPTH); - prevtd = td; + ptd = td; } - prevtd->link = UHCI_PTR_TERM; + ptd->link = UHCI_PTR_TERM; } -static void uhci_free_td(struct uhci_td *td) +static void uhci_free_td(struct uhci *uhci, struct uhci_td *td) { - if (!list_empty(&td->list)) +#ifdef DEBUG + if (!list_empty(&td->list) || !list_empty(&td->fl_list)) dbg("td is still in URB list!"); +#endif if (td->dev) usb_dec_dev_use(td->dev); - kmem_cache_free(uhci_td_cachep, td); + pci_free_consistent(uhci->dev, sizeof(*td), td, td->dma_handle); } -static struct uhci_qh *uhci_alloc_qh(struct usb_device *dev) +static struct uhci_qh *uhci_alloc_qh(struct uhci *uhci, struct usb_device *dev) { + dma_addr_t dma_handle; struct uhci_qh *qh; - qh = kmem_cache_alloc(uhci_qh_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL); + qh = pci_alloc_consistent(uhci->dev, sizeof(*qh), &dma_handle); if (!qh) return NULL; qh->element = UHCI_PTR_TERM; qh->link = UHCI_PTR_TERM; + qh->dma_handle = dma_handle; qh->dev = dev; - qh->prevqh = qh->nextqh = NULL; + INIT_LIST_HEAD(&qh->list); INIT_LIST_HEAD(&qh->remove_list); usb_inc_dev_use(dev); @@ -324,181 +377,277 @@ return qh; } -static void uhci_free_qh(struct uhci_qh *qh) +static void uhci_free_qh(struct uhci *uhci, struct uhci_qh *qh) { +#ifdef DEBUG + if (!list_empty(&qh->list)) + dbg("qh list not empty!"); + if (!list_empty(&qh->remove_list)) + dbg("qh still in remove_list!\n"); +#endif + if (qh->dev) usb_dec_dev_use(qh->dev); - kmem_cache_free(uhci_qh_cachep, qh); + pci_free_consistent(uhci->dev, sizeof(*qh), qh, qh->dma_handle); } -static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct uhci_qh *qh) +static void _uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct uhci_qh *qh) { - unsigned long flags; + struct uhci_qh *lqh; - spin_lock_irqsave(&uhci->framelist_lock, flags); + /* Grab the last QH */ + lqh = list_entry(skelqh->list.prev, struct uhci_qh, list); - /* Fix the linked list pointers */ - qh->nextqh = skelqh->nextqh; - qh->prevqh = skelqh; - if (skelqh->nextqh) - skelqh->nextqh->prevqh = qh; - skelqh->nextqh = qh; + qh->link = lqh->link; /* Does this really matter? */ + mb(); /* Ordering is important */ + lqh->link = qh->dma_handle | UHCI_PTR_QH; - qh->link = skelqh->link; - skelqh->link = virt_to_bus(qh) | UHCI_PTR_QH; + list_add_tail(&qh->list, &skelqh->list); +} + +static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct uhci_qh *qh) +{ + unsigned long flags; - spin_unlock_irqrestore(&uhci->framelist_lock, flags); + spin_lock_irqsave(&uhci->frame_list_lock, flags); + _uhci_insert_qh(uhci, skelqh, qh); + spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh) { unsigned long flags; - int delayed; + struct uhci_qh *prevqh; + + /* Only go through the hoops if it's actually linked in */ + if (list_empty(&qh->list)) { + uhci_free_qh(uhci, qh); + return; + } - /* If the QH isn't queued, then we don't need to delay unlink it */ - delayed = (qh->prevqh || qh->nextqh); + qh->urbp = NULL; - spin_lock_irqsave(&uhci->framelist_lock, flags); - if (qh->prevqh) { - qh->prevqh->nextqh = qh->nextqh; - qh->prevqh->link = qh->link; - } - if (qh->nextqh) - qh->nextqh->prevqh = qh->prevqh; - qh->prevqh = qh->nextqh = NULL; + spin_lock_irqsave(&uhci->frame_list_lock, flags); + + prevqh = list_entry(qh->list.prev, struct uhci_qh, list); + + prevqh->link = qh->link; + mb(); qh->element = qh->link = UHCI_PTR_TERM; - spin_unlock_irqrestore(&uhci->framelist_lock, flags); - if (delayed) { - spin_lock_irqsave(&uhci->qh_remove_lock, flags); + list_del(&qh->list); + INIT_LIST_HEAD(&qh->list); - /* Check to see if the remove list is empty */ - /* Set the IOC bit to force an interrupt so we can remove the QH */ - if (list_empty(&uhci->qh_remove_list)) - uhci_set_next_interrupt(uhci); + spin_unlock_irqrestore(&uhci->frame_list_lock, flags); - /* Add it */ - list_add(&qh->remove_list, &uhci->qh_remove_list); + spin_lock_irqsave(&uhci->qh_remove_list_lock, flags); - spin_unlock_irqrestore(&uhci->qh_remove_lock, flags); - } else - uhci_free_qh(qh); + /* Check to see if the remove list is empty. Set the IOC bit */ + /* to force an interrupt so we can remove the QH */ + if (list_empty(&uhci->qh_remove_list)) + uhci_set_next_interrupt(uhci); + + list_add(&qh->remove_list, &uhci->qh_remove_list); + + spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags); } -static spinlock_t uhci_append_urb_lock = SPIN_LOCK_UNLOCKED; +static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle) +{ + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + struct list_head *head, *tmp; + + head = &urbp->td_list; + tmp = head->next; + while (head != tmp) { + struct uhci_td *td = list_entry(tmp, struct uhci_td, list); + + tmp = tmp->next; + + td->info &= ~(1 << TD_TOKEN_TOGGLE); + if (toggle) + td->info |= (1 << TD_TOKEN_TOGGLE); + + toggle ^= 1; + } + + return toggle; +} /* This function will append one URB's QH to another URB's QH. This is for */ -/* USB_QUEUE_BULK support */ +/* USB_QUEUE_BULK support for bulk transfers and implicitily for control */ +/* transfers */ static void uhci_append_queued_urb(struct uhci *uhci, struct urb *eurb, struct urb *urb) { + /* eurb = existing, urb = new, furb = first, lurb = last */ struct urb_priv *eurbp, *urbp, *furbp, *lurbp; struct list_head *tmp; - struct uhci_td *td, *ltd; + struct uhci_td *ftd, *lltd; unsigned long flags; eurbp = eurb->hcpriv; urbp = urb->hcpriv; - spin_lock_irqsave(&uhci_append_urb_lock, flags); + spin_lock_irqsave(&uhci->frame_list_lock, flags); - /* Find the beginning URB in the queue */ + /* Find the first URB in the queue */ if (eurbp->queued) { - struct list_head *head = &eurbp->urb_queue_list; + struct list_head *head = &eurbp->queue_list; tmp = head->next; while (tmp != head) { struct urb_priv *turbp = - list_entry(tmp, struct urb_priv, urb_queue_list); - - tmp = tmp->next; + list_entry(tmp, struct urb_priv, queue_list); if (!turbp->queued) break; + + tmp = tmp->next; } } else - tmp = &eurbp->urb_queue_list; + tmp = &eurbp->queue_list; - furbp = list_entry(tmp, struct urb_priv, urb_queue_list); + furbp = list_entry(tmp, struct urb_priv, queue_list); + lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list); - tmp = furbp->urb_queue_list.prev; - lurbp = list_entry(tmp, struct urb_priv, urb_queue_list); + lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list); + ftd = list_entry(urbp->td_list.next, struct uhci_td, list); - /* Add this one to the end */ - list_add_tail(&urbp->urb_queue_list, &furbp->urb_queue_list); + uhci_fixup_toggle(urb, uhci_toggle(lltd->info) ^ 1); - /* Grab the last TD from the last URB */ - ltd = list_entry(lurbp->list.prev, struct uhci_td, list); + /* No breadth since this will only be called for bulk transfers */ + lltd->link = ftd->dma_handle; - /* Grab the first TD from the first URB */ - td = list_entry(urbp->list.next, struct uhci_td, list); + list_add_tail(&urbp->queue_list, &furbp->queue_list); - /* No breadth since this will only be called for bulk transfers */ - ltd->link = virt_to_bus(td); + urbp->queued = 1; - spin_unlock_irqrestore(&uhci_append_urb_lock, flags); + spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } static void uhci_delete_queued_urb(struct uhci *uhci, struct urb *urb) { struct urb_priv *urbp, *nurbp; + struct list_head *head, *tmp; + struct urb_priv *purbp; + struct uhci_td *pltd; + unsigned int toggle; unsigned long flags; urbp = urb->hcpriv; - spin_lock_irqsave(&uhci_append_urb_lock, flags); + spin_lock_irqsave(&uhci->frame_list_lock, flags); + + if (list_empty(&urbp->queue_list)) + goto out; + + nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list); + + /* Fix up the toggle for the next URB's */ + if (!urbp->queued) + toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); + else { + purbp = list_entry(urbp->queue_list.prev, struct urb_priv, + queue_list); + + pltd = list_entry(purbp->td_list.prev, struct uhci_td, list); + + toggle = uhci_toggle(pltd->info) ^ 1; + } + + head = &urbp->queue_list; + tmp = head->next; + while (head != tmp) { + struct urb_priv *turbp; + + turbp = list_entry(tmp, struct urb_priv, queue_list); + + tmp = tmp->next; + + if (!turbp->queued) + break; + + toggle = uhci_fixup_toggle(turbp->urb, toggle); + } - nurbp = list_entry(urbp->urb_queue_list.next, struct urb_priv, - urb_queue_list); + usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe), toggle); if (!urbp->queued) { /* We're the head, so just insert the QH for the next URB */ - uhci_insert_qh(uhci, &uhci->skel_bulk_qh, nurbp->qh); + _uhci_insert_qh(uhci, uhci->skel_bulk_qh, nurbp->qh); nurbp->queued = 0; } else { - struct urb_priv *purbp; - struct uhci_td *ptd; - /* We're somewhere in the middle (or end). A bit trickier */ /* than the head scenario */ - purbp = list_entry(urbp->urb_queue_list.prev, struct urb_priv, - urb_queue_list); + purbp = list_entry(urbp->queue_list.prev, struct urb_priv, + queue_list); + + pltd = list_entry(purbp->td_list.prev, struct uhci_td, list); + if (nurbp->queued) { + struct uhci_td *nftd; - ptd = list_entry(purbp->list.prev, struct uhci_td, list); - if (nurbp->queued) /* Close the gap between the two */ - ptd->link = virt_to_bus(list_entry(nurbp->list.next, - struct uhci_td, list)); - else + nftd = list_entry(nurbp->td_list.next, struct uhci_td, + list); + pltd->link = nftd->dma_handle; + } else /* The next URB happens to be the beggining, so */ /* we're the last, end the chain */ - ptd->link = UHCI_PTR_TERM; - + pltd->link = UHCI_PTR_TERM; } - list_del(&urbp->urb_queue_list); + list_del(&urbp->queue_list); + INIT_LIST_HEAD(&urbp->queue_list); - spin_unlock_irqrestore(&uhci_append_urb_lock, flags); +out: + spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } -struct urb_priv *uhci_alloc_urb_priv(struct urb *urb) +struct urb_priv *uhci_alloc_urb_priv(struct urb *urb, struct uhci *uhci) { struct urb_priv *urbp; urbp = kmem_cache_alloc(uhci_up_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL); - if (!urbp) + if (!urbp) { + err("uhci_alloc_urb_priv: couldn't allocate memory for urb_priv\n"); return NULL; + } memset((void *)urbp, 0, sizeof(*urbp)); urbp->inserttime = jiffies; urbp->urb = urb; + urbp->dev = urb->dev; - INIT_LIST_HEAD(&urbp->list); - INIT_LIST_HEAD(&urbp->urb_queue_list); + INIT_LIST_HEAD(&urbp->td_list); + INIT_LIST_HEAD(&urbp->queue_list); + INIT_LIST_HEAD(&urbp->complete_list); urb->hcpriv = urbp; + if (urb->transfer_buffer_length) { + urbp->transfer_buffer = pci_alloc_consistent(uhci->dev, + urb->transfer_buffer_length, &urbp->transfer_buffer_dma_handle); + if (!urbp->transfer_buffer) + return NULL; + + if (usb_pipeout(urb->pipe)) + memcpy(urbp->transfer_buffer, urb->transfer_buffer, + urb->transfer_buffer_length); + } + + if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet) { + urbp->setup_buffer = pci_alloc_consistent(uhci->dev, + sizeof(devrequest), &urbp->setup_buffer_dma_handle); + if (!urbp->setup_buffer) + return NULL; + + memcpy(urbp->setup_buffer, urb->setup_packet, + sizeof(devrequest)); + } + return urbp; } @@ -508,13 +657,11 @@ td->urb = urb; - list_add_tail(&td->list, &urbp->list); + list_add_tail(&td->list, &urbp->td_list); } -static void uhci_remove_td_from_urb(struct urb *urb, struct uhci_td *td) +static void uhci_remove_td_from_urb(struct uhci_td *td) { - urb = NULL; /* No warnings */ - if (list_empty(&td->list)) return; @@ -526,41 +673,54 @@ static void uhci_destroy_urb_priv(struct urb *urb) { - struct list_head *tmp, *head; + struct list_head *head, *tmp; struct urb_priv *urbp; struct uhci *uhci; - struct uhci_td *td; unsigned long flags; spin_lock_irqsave(&urb->lock, flags); urbp = (struct urb_priv *)urb->hcpriv; if (!urbp) - goto unlock; + goto out; - if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) - goto unlock; + if (!urbp->dev || !urbp->dev->bus || !urbp->dev->bus->hcpriv) { + warn("uhci_destroy_urb_priv: urb %p belongs to disconnected device or bus?", urb); + goto out; + } + + if (!list_empty(&urb->urb_list)) + warn("uhci_destroy_urb_priv: urb %p still on uhci->urb_list or uhci->remove_list", urb); + + if (!list_empty(&urbp->complete_list)) + warn("uhci_destroy_urb_priv: urb %p still on uhci->complete_list", urb); - uhci = urb->dev->bus->hcpriv; + uhci = urbp->dev->bus->hcpriv; - head = &urbp->list; + head = &urbp->td_list; tmp = head->next; while (tmp != head) { - td = list_entry(tmp, struct uhci_td, list); + struct uhci_td *td = list_entry(tmp, struct uhci_td, list); tmp = tmp->next; - uhci_remove_td_from_urb(urb, td); - + uhci_remove_td_from_urb(td); uhci_remove_td(uhci, td); - - uhci_free_td(td); + uhci_free_td(uhci, td); } + if (urbp->setup_buffer) + pci_free_consistent(uhci->dev, sizeof(devrequest), + urbp->setup_buffer, urbp->setup_buffer_dma_handle); + + if (urbp->transfer_buffer) + pci_free_consistent(uhci->dev, urb->transfer_buffer_length, + urbp->transfer_buffer, urbp->transfer_buffer_dma_handle); + urb->hcpriv = NULL; kmem_cache_free(uhci_up_cachep, urbp); -unlock: +out: spin_unlock_irqrestore(&urb->lock, flags); } @@ -569,18 +729,15 @@ unsigned long flags; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - if (!urbp) - return; - - spin_lock_irqsave(&uhci->framelist_lock, flags); + spin_lock_irqsave(&uhci->frame_list_lock, flags); if ((!(urb->transfer_flags & USB_NO_FSBR)) && (!urbp->fsbr)) { urbp->fsbr = 1; if (!uhci->fsbr++) - uhci->skel_term_qh.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH; + uhci->skel_term_qh->link = uhci->skel_hs_control_qh->dma_handle | UHCI_PTR_QH; } - spin_unlock_irqrestore(&uhci->framelist_lock, flags); + spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } static void uhci_dec_fsbr(struct uhci *uhci, struct urb *urb) @@ -588,18 +745,15 @@ unsigned long flags; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - if (!urbp) - return; - - spin_lock_irqsave(&uhci->framelist_lock, flags); + spin_lock_irqsave(&uhci->frame_list_lock, flags); if ((!(urb->transfer_flags & USB_NO_FSBR)) && urbp->fsbr) { urbp->fsbr = 0; if (!--uhci->fsbr) - uhci->skel_term_qh.link = UHCI_PTR_TERM; + uhci->skel_term_qh->link = UHCI_PTR_TERM; } - spin_unlock_irqrestore(&uhci->framelist_lock, flags); + spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } /* @@ -637,7 +791,7 @@ /* * Control transfers */ -static int uhci_submit_control(struct urb *urb) +static int uhci_submit_control(struct urb *urb, struct urb *eurb) { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; @@ -646,7 +800,7 @@ unsigned long destination, status; int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); int len = urb->transfer_buffer_length; - unsigned char *data = urb->transfer_buffer; + dma_addr_t data = urbp->transfer_buffer_dma_handle; /* The "pipe" thing contains the destination in bits 8--18 */ destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; @@ -657,13 +811,13 @@ /* * Build the TD for the control request */ - td = uhci_alloc_td(urb->dev); + td = uhci_alloc_td(uhci, urb->dev); if (!td) return -ENOMEM; uhci_add_td_to_urb(urb, td); uhci_fill_td(td, status, destination | (7 << 21), - virt_to_bus(urb->setup_packet)); + urbp->setup_buffer_dma_handle); /* * If direction is "send", change the frame from SETUP (0x2D) @@ -683,7 +837,7 @@ if (pktsze > maxsze) pktsze = maxsze; - td = uhci_alloc_td(urb->dev); + td = uhci_alloc_td(uhci, urb->dev); if (!td) return -ENOMEM; @@ -692,7 +846,7 @@ uhci_add_td_to_urb(urb, td); uhci_fill_td(td, status, destination | ((pktsze - 1) << 21), - virt_to_bus(data)); + data); data += pktsze; len -= pktsze; @@ -701,7 +855,7 @@ /* * Build the final TD for control status */ - td = uhci_alloc_td(urb->dev); + td = uhci_alloc_td(uhci, urb->dev); if (!td) return -ENOMEM; @@ -723,23 +877,22 @@ uhci_fill_td(td, status | TD_CTRL_IOC, destination | (UHCI_NULL_DATA_SIZE << 21), 0); - qh = uhci_alloc_qh(urb->dev); + qh = uhci_alloc_qh(uhci, urb->dev); if (!qh) return -ENOMEM; /* Low speed or small transfers gets a different queue and treatment */ if (urb->pipe & TD_CTRL_LS) { uhci_insert_tds_in_qh(qh, urb, 0); - uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, qh); + uhci_insert_qh(uhci, uhci->skel_ls_control_qh, qh); } else { uhci_insert_tds_in_qh(qh, urb, 1); - uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, qh); + uhci_insert_qh(uhci, uhci->skel_hs_control_qh, qh); uhci_inc_fsbr(uhci, urb); } urbp->qh = qh; - - uhci_add_urb_list(uhci, urb); + qh->urbp = urbp; return -EINPROGRESS; } @@ -754,12 +907,10 @@ unsigned int status; int ret = 0; - if (!urbp) + if (list_empty(&urbp->td_list)) return -EINVAL; - head = &urbp->list; - if (head->next == head) - return -EINVAL; + head = &urbp->td_list; if (urbp->short_control_packet) { tmp = head->prev; @@ -849,12 +1000,16 @@ uhci_packetout(td->info)); err: - if (debug && ret != -EPIPE) { + if ((debug == 1 && ret != -EPIPE) || debug > 1) { + char buf[1024]; + /* Some debugging code */ dbg("uhci_result_control() failed with status %x", status); /* Print the chain for debugging purposes */ - uhci_show_urb_queue(urb); + uhci_show_qh(urbp->qh, buf, sizeof(buf)); + + printk("%s", buf); } return ret; @@ -872,34 +1027,34 @@ uhci_remove_qh(uhci, urbp->qh); /* Delete all of the TD's except for the status TD at the end */ - head = &urbp->list; + head = &urbp->td_list; tmp = head->next; while (tmp != head && tmp->next != head) { struct uhci_td *td = list_entry(tmp, struct uhci_td, list); tmp = tmp->next; - uhci_remove_td_from_urb(urb, td); - + uhci_remove_td_from_urb(td); uhci_remove_td(uhci, td); - - uhci_free_td(td); + uhci_free_td(uhci, td); } - urbp->qh = uhci_alloc_qh(urb->dev); + urbp->qh = uhci_alloc_qh(uhci, urb->dev); if (!urbp->qh) { err("unable to allocate new QH for control retrigger"); return -ENOMEM; } + urbp->qh->urbp = urbp; + /* One TD, who cares about Breadth first? */ uhci_insert_tds_in_qh(urbp->qh, urb, 0); /* Low speed or small transfers gets a different queue and treatment */ if (urb->pipe & TD_CTRL_LS) - uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, urbp->qh); + uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urbp->qh); else - uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, urbp->qh); + uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urbp->qh); return -EINPROGRESS; } @@ -912,6 +1067,7 @@ struct uhci_td *td; unsigned long destination, status; struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; if (urb->transfer_buffer_length > usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) return -EINVAL; @@ -921,7 +1077,7 @@ status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC; - td = uhci_alloc_td(urb->dev); + td = uhci_alloc_td(uhci, urb->dev); if (!td) return -ENOMEM; @@ -931,12 +1087,9 @@ usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); uhci_add_td_to_urb(urb, td); - uhci_fill_td(td, status, destination, - virt_to_bus(urb->transfer_buffer)); + uhci_fill_td(td, status, destination, urbp->transfer_buffer_dma_handle); - uhci_insert_td(uhci, &uhci->skeltd[__interval_to_skel(urb->interval)], td); - - uhci_add_urb_list(uhci, urb); + uhci_insert_td(uhci, uhci->skeltd[__interval_to_skel(urb->interval)], td); return -EINPROGRESS; } @@ -949,12 +1102,9 @@ unsigned int status; int ret = 0; - if (!urbp) - return -EINVAL; - urb->actual_length = 0; - head = &urbp->list; + head = &urbp->td_list; tmp = head->next; while (tmp != head) { td = list_entry(tmp, struct uhci_td, list); @@ -1000,16 +1150,20 @@ uhci_packetout(td->info)); err: - if (debug && ret != -EPIPE) { + if ((debug == 1 && ret != -EPIPE) || debug > 1) { + char buf[1024]; + /* Some debugging code */ dbg("uhci_result_interrupt/bulk() failed with status %x", status); /* Print the chain for debugging purposes */ if (urbp->qh) - uhci_show_urb_queue(urb); + uhci_show_qh(urbp->qh, buf, sizeof(buf)); else - uhci_show_td(td); + uhci_show_td(td, buf, sizeof(buf)); + + printk(buf); } return ret; @@ -1017,24 +1171,28 @@ static void uhci_reset_interrupt(struct urb *urb) { - struct list_head *tmp; + struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; struct uhci_td *td; + unsigned long flags; - if (!urbp) - return; + spin_lock_irqsave(&urb->lock, flags); - tmp = urbp->list.next; - td = list_entry(tmp, struct uhci_td, list); - if (!td) - return; + /* Root hub is special */ + if (urb->dev == uhci->rh.dev) + goto out; + + td = list_entry(urbp->td_list.next, struct uhci_td, list); td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC; td->info &= ~(1 << TD_TOKEN_TOGGLE); td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE); usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); +out: urb->status = -EINPROGRESS; + + spin_unlock_irqrestore(&urb->lock, flags); } /* @@ -1048,8 +1206,8 @@ struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); int len = urb->transfer_buffer_length; - unsigned char *data = urb->transfer_buffer; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + dma_addr_t data = urbp->transfer_buffer_dma_handle; if (len < 0) return -EINVAL; @@ -1076,7 +1234,7 @@ if (pktsze > maxsze) pktsze = maxsze; - td = uhci_alloc_td(urb->dev); + td = uhci_alloc_td(uhci, urb->dev); if (!td) return -ENOMEM; @@ -1084,7 +1242,7 @@ uhci_fill_td(td, status, destination | ((pktsze - 1) << 21) | (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE), - virt_to_bus(data)); + data); data += pktsze; len -= maxsze; @@ -1096,22 +1254,20 @@ usb_pipeout(urb->pipe)); } while (len > 0); - qh = uhci_alloc_qh(urb->dev); + qh = uhci_alloc_qh(uhci, urb->dev); if (!qh) return -ENOMEM; urbp->qh = qh; + qh->urbp = urbp; /* Always assume depth first */ uhci_insert_tds_in_qh(qh, urb, 1); - if (urb->transfer_flags & USB_QUEUE_BULK && eurb) { - urbp->queued = 1; + if (urb->transfer_flags & USB_QUEUE_BULK && eurb) uhci_append_queued_urb(uhci, eurb, urb); - } else - uhci_insert_qh(uhci, &uhci->skel_bulk_qh, qh); - - uhci_add_urb_list(uhci, urb); + else + uhci_insert_qh(uhci, uhci->skel_bulk_qh, qh); uhci_inc_fsbr(uhci, urb); @@ -1128,11 +1284,12 @@ { struct urb *last_urb = NULL; struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; - struct list_head *tmp, *head = &uhci->urb_list; + struct list_head *tmp, *head; int ret = 0; unsigned long flags; - nested_lock(&uhci->urblist_lock, flags); + spin_lock_irqsave(&uhci->urb_list_lock, flags); + head = &uhci->urb_list; tmp = head->next; while (tmp != head) { struct urb *u = list_entry(tmp, struct urb, urb_list); @@ -1154,7 +1311,7 @@ } else ret = -1; /* no previous urb found */ - nested_unlock(&uhci->urblist_lock, flags); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); return ret; } @@ -1185,12 +1342,16 @@ return 0; } +/* + * Isochronous transfers + */ static int uhci_submit_isochronous(struct urb *urb) { struct uhci_td *td; struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; int i, ret, framenum; int status, destination; + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; status = TD_CTRL_ACTIVE | TD_CTRL_IOS; destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); @@ -1204,13 +1365,13 @@ if (!urb->iso_frame_desc[i].length) continue; - td = uhci_alloc_td(urb->dev); + td = uhci_alloc_td(uhci, urb->dev); if (!td) return -ENOMEM; uhci_add_td_to_urb(urb, td); uhci_fill_td(td, status, destination | ((urb->iso_frame_desc[i].length - 1) << 21), - virt_to_bus(urb->transfer_buffer + urb->iso_frame_desc[i].offset)); + urbp->transfer_buffer_dma_handle + urb->iso_frame_desc[i].offset); if (i + 1 >= urb->number_of_packets) td->status |= TD_CTRL_IOC; @@ -1218,8 +1379,6 @@ uhci_insert_td_frame_list(uhci, td, framenum); } - uhci_add_urb_list(uhci, urb); - return -EINPROGRESS; } @@ -1230,13 +1389,10 @@ int status; int i, ret = 0; - if (!urbp) - return -EINVAL; - urb->actual_length = 0; i = 0; - head = &urbp->list; + head = &urbp->td_list; tmp = head->next; while (tmp != head) { struct uhci_td *td = list_entry(tmp, struct uhci_td, list); @@ -1253,7 +1409,7 @@ status = uhci_map_status(uhci_status_bits(td->status), usb_pipeout(urb->pipe)); urb->iso_frame_desc[i].status = status; - if (status != 0) { + if (status) { urb->error_count++; ret = status; } @@ -1266,28 +1422,30 @@ static struct urb *uhci_find_urb_ep(struct uhci *uhci, struct urb *urb) { - struct list_head *tmp, *head = &uhci->urb_list; + struct list_head *tmp, *head; unsigned long flags; struct urb *u = NULL; + /* We don't match Isoc transfers since they are special */ if (usb_pipeisoc(urb->pipe)) return NULL; - nested_lock(&uhci->urblist_lock, flags); + spin_lock_irqsave(&uhci->urb_list_lock, flags); + head = &uhci->urb_list; tmp = head->next; while (tmp != head) { u = list_entry(tmp, struct urb, urb_list); tmp = tmp->next; - if (u->dev == urb->dev && - u->pipe == urb->pipe) - goto found; + if (u->dev == urb->dev && u->pipe == urb->pipe && + u->status == -EINPROGRESS) + goto out; } u = NULL; -found: - nested_unlock(&uhci->urblist_lock, flags); +out: + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); return u; } @@ -1297,38 +1455,62 @@ int ret = -EINVAL; struct uhci *uhci; unsigned long flags; - struct urb *u; + struct urb *eurb; int bustime; if (!urb) return -EINVAL; - if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) + if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) { + warn("uhci_submit_urb: urb %p belongs to disconnected device or bus?", urb); return -ENODEV; + } uhci = (struct uhci *)urb->dev->bus->hcpriv; - /* Short circuit the virtual root hub */ - if (usb_pipedevice(urb->pipe) == uhci->rh.devnum) - return rh_submit_urb(urb); - - u = uhci_find_urb_ep(uhci, urb); - if (u && !(urb->transfer_flags & USB_QUEUE_BULK)) - return -ENXIO; + /* Grab the urb_list lock first to avoid deadlocks */ + spin_lock_irqsave(&uhci->urb_list_lock, flags); + /* We use tail to make find_urb_ep more efficient */ + list_add_tail(&urb->urb_list, &uhci->urb_list); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); usb_inc_dev_use(urb->dev); + spin_lock_irqsave(&urb->lock, flags); - if (!uhci_alloc_urb_priv(urb)) { + if (urb->status == -EINPROGRESS || urb->status == -ECONNRESET || + urb->status == -ECONNABORTED) { + dbg("uhci_submit_urb: urb not available to submit (status = %d)", urb->status); + /* Since we can have problems on the out path */ spin_unlock_irqrestore(&urb->lock, flags); usb_dec_dev_use(urb->dev); - return -ENOMEM; + return ret; + } + + if (!uhci_alloc_urb_priv(urb, uhci)) { + ret = -ENOMEM; + + goto out; + } + + eurb = uhci_find_urb_ep(uhci, urb); + if (eurb && !(urb->transfer_flags & USB_QUEUE_BULK)) { + ret = -ENXIO; + + goto out; + } + + /* Short circuit the virtual root hub */ + if (urb->dev == uhci->rh.dev) { + ret = rh_submit_urb(urb); + + goto out; } switch (usb_pipetype(urb->pipe)) { case PIPE_CONTROL: - ret = uhci_submit_control(urb); + ret = uhci_submit_control(urb, eurb); break; case PIPE_INTERRUPT: if (urb->bandwidth == 0) { /* not yet checked/allocated */ @@ -1344,7 +1526,7 @@ ret = uhci_submit_interrupt(urb); break; case PIPE_BULK: - ret = uhci_submit_bulk(urb, u); + ret = uhci_submit_bulk(urb, eurb); break; case PIPE_ISOCHRONOUS: if (urb->bandwidth == 0) { /* not yet checked/allocated */ @@ -1366,16 +1548,24 @@ break; } +out: urb->status = ret; spin_unlock_irqrestore(&urb->lock, flags); if (ret == -EINPROGRESS) - ret = 0; - else { - uhci_unlink_generic(urb); - usb_dec_dev_use(urb->dev); - } + return 0; + + /* If we got here, then we're done with this URB */ + spin_lock_irqsave(&uhci->urb_list_lock, flags); + list_del(&urb->urb_list); + INIT_LIST_HEAD(&urb->urb_list); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + + uhci_unlink_generic(uhci, urb); + uhci_destroy_urb_priv(urb); + + usb_dec_dev_use(urb->dev); return ret; } @@ -1383,18 +1573,28 @@ /* * Return the result of a transfer * - * Must be called with urblist_lock acquired + * Must be called with urb_list_lock acquired */ -static void uhci_transfer_result(struct urb *urb) +static void uhci_transfer_result(struct uhci *uhci, struct urb *urb) { - struct usb_device *dev = urb->dev; - struct urb *turb; - int proceed = 0, is_ring = 0; int ret = -EINVAL; unsigned long flags; + struct urb_priv *urbp; + + /* The root hub is special */ + if (urb->dev == uhci->rh.dev) + return; spin_lock_irqsave(&urb->lock, flags); + urbp = (struct urb_priv *)urb->hcpriv; + + if (urb->status != -EINPROGRESS) { + info("uhci_transfer_result: called for URB %p not in flight?", urb); + spin_unlock_irqrestore(&urb->lock, flags); + return; + } + switch (usb_pipetype(urb->pipe)) { case PIPE_CONTROL: ret = uhci_result_control(urb); @@ -1410,7 +1610,7 @@ break; } - urb->status = ret; + urbp->status = ret; spin_unlock_irqrestore(&urb->lock, flags); @@ -1425,106 +1625,65 @@ /* Spinlock needed ? */ if (urb->bandwidth) usb_release_bandwidth(urb->dev, urb, 1); - uhci_unlink_generic(urb); + uhci_unlink_generic(uhci, urb); break; case PIPE_INTERRUPT: /* Interrupts are an exception */ if (urb->interval) { - urb->complete(urb); - uhci_reset_interrupt(urb); - return; + uhci_add_complete(urb); + return; /* <-- note return */ } /* Release bandwidth for Interrupt or Isoc. transfers */ /* Spinlock needed ? */ if (urb->bandwidth) usb_release_bandwidth(urb->dev, urb, 0); - uhci_unlink_generic(urb); + uhci_unlink_generic(uhci, urb); break; + default: + info("uhci_transfer_result: unknown pipe type %d for urb %p\n", + usb_pipetype(urb->pipe), urb); } - if (urb->next) { - turb = urb->next; - do { - if (turb->status != -EINPROGRESS) { - proceed = 1; - break; - } - - turb = turb->next; - } while (turb && turb != urb && turb != urb->next); - - if (turb == urb || turb == urb->next) - is_ring = 1; - } - - if (urb->complete && !proceed) { - urb->complete(urb); - if (!proceed && is_ring) - uhci_submit_urb(urb); - } - - if (proceed && urb->next) { - turb = urb->next; - do { - if (turb->status != -EINPROGRESS && - uhci_submit_urb(turb) != 0) - - turb = turb->next; - } while (turb && turb != urb->next); - - if (urb->complete) - urb->complete(urb); - } + list_del(&urb->urb_list); + INIT_LIST_HEAD(&urb->urb_list); - /* We decrement the usage count after we're done with everything */ - usb_dec_dev_use(dev); + uhci_add_complete(urb); } -static int uhci_unlink_generic(struct urb *urb) +static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb) { struct urb_priv *urbp = urb->hcpriv; - struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; + /* We can get called when urbp allocation fails, so check */ if (!urbp) - return -EINVAL; + return; uhci_dec_fsbr(uhci, urb); /* Safe since it checks */ - uhci_remove_urb_list(uhci, urb); - if (urbp->qh) /* The interrupt loop will reclaim the QH's */ uhci_remove_qh(uhci, urbp->qh); - if (!list_empty(&urbp->urb_queue_list)) - uhci_delete_queued_urb(uhci, urb); - - uhci_destroy_urb_priv(urb); - - urb->dev = NULL; - - return 0; + uhci_delete_queued_urb(uhci, urb); /* It checks */ } +/* FIXME: If we forcefully unlink an urb, we should reset the toggle for */ +/* that pipe to match what actually completed */ static int uhci_unlink_urb(struct urb *urb) { struct uhci *uhci; - int ret = 0; unsigned long flags; + struct urb_priv *urbp = urb->hcpriv; if (!urb) return -EINVAL; - if (!urb->dev || !urb->dev->bus) + if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) return -ENODEV; uhci = (struct uhci *)urb->dev->bus->hcpriv; - /* Short circuit the virtual root hub */ - if (usb_pipedevice(urb->pipe) == uhci->rh.devnum) - return rh_unlink_urb(urb); - /* Release bandwidth for Interrupt or Isoc. transfers */ /* Spinlock needed ? */ if (urb->bandwidth) { @@ -1540,13 +1699,28 @@ } } - if (urb->status == -EINPROGRESS) { - uhci_unlink_generic(urb); + if (urb->status != -EINPROGRESS) + return -1; + + spin_lock_irqsave(&uhci->urb_list_lock, flags); + list_del(&urb->urb_list); + INIT_LIST_HEAD(&urb->urb_list); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + uhci_unlink_generic(uhci, urb); + + /* Short circuit the virtual root hub */ + if (urb->dev == uhci->rh.dev) { + rh_unlink_urb(urb); + uhci_call_completion(urb); + } else { if (urb->transfer_flags & USB_ASYNC_UNLINK) { - urb->status = -ECONNABORTED; + /* urb_list is available now since we called */ + /* uhci_unlink_generic already */ - spin_lock_irqsave(&uhci->urb_remove_lock, flags); + urbp->status = urb->status = -ECONNABORTED; + + spin_lock_irqsave(&uhci->urb_remove_list_lock, flags); /* Check to see if the remove list is empty */ if (list_empty(&uhci->urb_remove_list)) @@ -1554,7 +1728,7 @@ list_add(&urb->urb_list, &uhci->urb_remove_list); - spin_unlock_irqrestore(&uhci->urb_remove_lock, flags); + spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags); } else { urb->status = -ENOENT; @@ -1567,12 +1741,11 @@ } else schedule_timeout(1+1*HZ/1000); - if (urb->complete) - urb->complete(urb); + uhci_call_completion(urb); } } - return ret; + return 0; } static int uhci_fsbr_timeout(struct uhci *uhci, struct urb *urb) @@ -1588,7 +1761,7 @@ /* and we'd be turning on FSBR next frame anyway, so it's a wash */ urbp->fsbr_timeout = 1; - head = &urbp->list; + head = &urbp->td_list; tmp = head->next; while (tmp != head) { struct uhci_td *td = list_entry(tmp, struct uhci_td, list); @@ -1624,9 +1797,7 @@ uhci_unlink_urb }; -/* ------------------------------------------------------------------- - Virtual Root Hub - ------------------------------------------------------------------- */ +/* Virtual Root Hub */ static __u8 root_hub_dev_des[] = { @@ -1700,7 +1871,6 @@ 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */ }; -/*-------------------------------------------------------------------------*/ /* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */ static int rh_send_irq(struct urb *urb) { @@ -1708,6 +1878,7 @@ struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; unsigned int io_addr = uhci->io_addr; __u16 data = 0; + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; for (i = 0; i < uhci->rh.numports; i++) { data |= ((inw(io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0); @@ -1715,19 +1886,20 @@ } *(__u16 *) urb->transfer_buffer = cpu_to_le16(data); - urb->actual_length = len; - urb->status = USB_ST_NOERROR; if ((data > 0) && (uhci->rh.send != 0)) { dbg("root-hub INT complete: port1: %x port2: %x data: %x", inw(io_addr + USBPORTSC1), inw(io_addr + USBPORTSC2), data); - urb->complete(urb); + urb->actual_length = len; + urbp->status = 0; + + uhci_add_complete(urb); + uhci_set_next_interrupt(uhci); } - return USB_ST_NOERROR; + return 0; } -/*-------------------------------------------------------------------------*/ /* Virtual Root Hub INTs are polled by this timer every "interval" ms */ static int rh_init_int_timer(struct urb *urb); @@ -1735,41 +1907,45 @@ { struct urb *urb = (struct urb *)ptr; struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; - struct list_head *tmp, *head = &uhci->urb_list; - struct urb_priv *urbp; - int len; + struct list_head list, *tmp, *head; unsigned long flags; - if (uhci->rh.send) { - len = rh_send_irq(urb); - if (len > 0) { - urb->actual_length = len; - if (urb->complete) - urb->complete(urb); + if (uhci->rh.send) + rh_send_irq(urb); + + INIT_LIST_HEAD(&list); + + spin_lock_irqsave(&uhci->urb_list_lock, flags); + head = &uhci->urb_list; + tmp = head->next; + while (tmp != head) { + struct urb *u = list_entry(tmp, struct urb, urb_list); + struct urb_priv *urbp = (struct urb_priv *)u->hcpriv; + + tmp = tmp->next; + + /* Check if the FSBR timed out */ + if (urbp->fsbr && time_after_eq(jiffies, urbp->inserttime + IDLE_TIMEOUT)) + uhci_fsbr_timeout(uhci, u); + + /* Check if the URB timed out */ + if (u->timeout && time_after_eq(jiffies, u->timeout)) { + list_del(&u->urb_list); + list_add_tail(&u->urb_list, &list); } } + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); - nested_lock(&uhci->urblist_lock, flags); + head = &list; tmp = head->next; while (tmp != head) { - struct urb *u = list_entry(tmp, urb_t, urb_list); + struct urb *u = list_entry(tmp, struct urb, urb_list); tmp = tmp->next; - urbp = (struct urb_priv *)u->hcpriv; - if (urbp) { - /* Check if the FSBR timed out */ - if (urbp->fsbr && time_after_eq(jiffies, urbp->inserttime + IDLE_TIMEOUT)) - uhci_fsbr_timeout(uhci, u); - - /* Check if the URB timed out */ - if (u->timeout && time_after_eq(jiffies, u->timeout)) { - u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED; - uhci_unlink_urb(u); - } - } + u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED; + uhci_unlink_urb(u); } - nested_unlock(&uhci->urblist_lock, flags); /* enter global suspend if nothing connected */ if (!uhci->is_suspended && !ports_active(uhci)) @@ -1778,7 +1954,6 @@ rh_init_int_timer(urb); } -/*-------------------------------------------------------------------------*/ /* Root Hub INTs are polled by this timer */ static int rh_init_int_timer(struct urb *urb) { @@ -1794,7 +1969,6 @@ return 0; } -/*-------------------------------------------------------------------------*/ #define OK(x) len = (x); break #define CLR_RH_PORTSTAT(x) \ @@ -1808,10 +1982,7 @@ outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1)) -/*-------------------------------------------------------------------------*/ -/************************* - ** Root Hub Control Pipe - *************************/ +/* Root Hub Control Pipe */ static int rh_submit_urb(struct urb *urb) { @@ -1822,7 +1993,7 @@ int leni = urb->transfer_buffer_length; int len = 0; int status = 0; - int stat = USB_ST_NOERROR; + int stat = 0; int i; unsigned int io_addr = uhci->io_addr; __u16 cstatus; @@ -1837,7 +2008,7 @@ uhci->rh.interval = urb->interval; rh_init_int_timer(urb); - return USB_ST_NOERROR; + return -EINPROGRESS; } bmRType_bReq = cmd->requesttype | cmd->request << 8; @@ -1945,7 +2116,6 @@ } break; case RH_SET_ADDRESS: - uhci->rh.devnum = wValue; OK(0); case RH_GET_DESCRIPTOR: switch ((wValue & 0xff00) >> 8) { @@ -1955,14 +2125,14 @@ OK(len); case 0x02: /* configuration descriptor */ len = min(leni, min(sizeof(root_hub_config_des), wLength)); - memcpy (data, root_hub_config_des, len); + memcpy(data, root_hub_config_des, len); OK(len); case 0x03: /* string descriptors */ - len = usb_root_hub_string (wValue & 0xff, + len = usb_root_hub_string(wValue & 0xff, uhci->io_addr, "UHCI-alt", data, wLength); if (len > 0) { - OK (min (leni, len)); + OK(min (leni, len)); } else stat = -EPIPE; } @@ -1987,33 +2157,29 @@ } urb->actual_length = len; - urb->status = stat; - if (urb->complete) - urb->complete(urb); - return USB_ST_NOERROR; + return stat; } -/*-------------------------------------------------------------------------*/ static int rh_unlink_urb(struct urb *urb) { struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; if (uhci->rh.urb == urb) { + urb->status = -ENOENT; uhci->rh.send = 0; + uhci->rh.urb = NULL; del_timer(&uhci->rh.rh_int_timer); } return 0; } -/*-------------------------------------------------------------------*/ -void uhci_free_pending_qhs(struct uhci *uhci) +static void uhci_free_pending_qhs(struct uhci *uhci) { struct list_head *tmp, *head; unsigned long flags; - /* Free any pending QH's */ - spin_lock_irqsave(&uhci->qh_remove_lock, flags); + spin_lock_irqsave(&uhci->qh_remove_list_lock, flags); head = &uhci->qh_remove_list; tmp = head->next; while (tmp != head) { @@ -2022,10 +2188,147 @@ tmp = tmp->next; list_del(&qh->remove_list); + INIT_LIST_HEAD(&qh->remove_list); + + uhci_free_qh(uhci, qh); + } + spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags); +} + +static void uhci_call_completion(struct urb *urb) +{ + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + struct usb_device *dev = urb->dev; + int is_ring = 0, killed, resubmit_interrupt, status; + struct urb *nurb; + + killed = (urb->status == -ENOENT || urb->status == -ECONNABORTED || + urb->status == -ECONNRESET); + resubmit_interrupt = (usb_pipetype(urb->pipe) == PIPE_INTERRUPT && + urb->interval && !killed); + + nurb = urb->next; + if (nurb && !killed) { + /* First loop to check for any other URB's that are killed */ + int count = 0; + + while (nurb && nurb != urb && count < MAX_URB_LOOP) { + if (nurb->status == -ENOENT || + nurb->status == -ECONNABORTED || + nurb->status == -ECONNRESET) { + killed = 1; + break; + } + + nurb = nurb->next; + count++; + } + + if (count == MAX_URB_LOOP) + err("uhci_call_completion: too many linked URB's, loop? (first loop)"); + + /* Check to see if chain is a ring */ + is_ring = (nurb == urb); + } + + if (usb_pipein(urb->pipe) && urb->transfer_buffer_length) + memcpy(urb->transfer_buffer, urbp->transfer_buffer, + urb->transfer_buffer_length); + + status = urbp->status; + if (!resubmit_interrupt) + /* We don't need urb_priv anymore */ + uhci_destroy_urb_priv(urb); + +#if 0 + nurb = urb->next; + if (nurb && !killed) { + /* Second loop to submit any other URB's */ + int count = 0; + + while (nurb && nurb != urb && count < MAX_URB_LOOP) { + if (nurb->status != -EINPROGRESS) { + /* usb_submit_urb since there's no reason */ + /* that this URB doesn't belong to another */ + /* HCD (ohci, ehci, etc) */ + if (usb_submit_urb(nurb)) + break; + } + + nurb = nurb->next; + count++; + } + + if (count == MAX_URB_LOOP) + err("uhci_call_completion: too many linked URB's, loop? (second loop)"); + } +#endif + + if (!killed) + urb->status = status; + + urb->dev = NULL; + if (urb->complete) + urb->complete(urb); + + if (resubmit_interrupt) { + urb->dev = dev; + uhci_reset_interrupt(urb); + } else { + if (is_ring && !killed) { + urb->dev = dev; + uhci_submit_urb(urb); + } else { + /* We decrement the usage count after we're done */ + /* with everything */ + usb_dec_dev_use(dev); + } + } +} + +static void uhci_finish_completion(struct uhci *uhci) +{ + struct list_head *tmp, *head; + unsigned long flags; + + spin_lock_irqsave(&uhci->complete_list_lock, flags); + head = &uhci->complete_list; + tmp = head->next; + while (tmp != head) { + struct urb_priv *urbp = list_entry(tmp, struct urb_priv, complete_list); + struct urb *urb = urbp->urb; + + tmp = tmp->next; + + list_del(&urbp->complete_list); + INIT_LIST_HEAD(&urbp->complete_list); + + uhci_call_completion(urb); + } + spin_unlock_irqrestore(&uhci->complete_list_lock, flags); +} + +static void uhci_remove_pending_qhs(struct uhci *uhci) +{ + struct list_head *tmp, *head; + unsigned long flags; + + spin_lock_irqsave(&uhci->urb_remove_list_lock, flags); + head = &uhci->urb_remove_list; + tmp = head->next; + while (tmp != head) { + struct urb *urb = list_entry(tmp, struct urb, urb_list); + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + + tmp = tmp->next; + + list_del(&urb->urb_list); + INIT_LIST_HEAD(&urb->urb_list); - uhci_free_qh(qh); + urbp->status = urb->status = -ECONNRESET; + uhci_call_completion(urb); } - spin_unlock_irqrestore(&uhci->qh_remove_lock, flags); + spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags); } static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs) @@ -2033,7 +2336,6 @@ struct uhci *uhci = __uhci; unsigned int io_addr = uhci->io_addr; unsigned short status; - unsigned long flags; struct list_head *tmp, *head; /* @@ -2043,7 +2345,7 @@ status = inw(io_addr + USBSTS); if (!status) /* shared interrupt, not mine */ return; - outw(status, io_addr + USBSTS); + outw(status, io_addr + USBSTS); /* Clear it */ if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) { if (status & USBSTS_HSE) @@ -2062,25 +2364,12 @@ uhci_free_pending_qhs(uhci); - spin_lock(&uhci->urb_remove_lock); - head = &uhci->urb_remove_list; - tmp = head->next; - while (tmp != head) { - struct urb *urb = list_entry(tmp, struct urb, urb_list); - - tmp = tmp->next; - - list_del(&urb->urb_list); - - if (urb->complete) - urb->complete(urb); - } - spin_unlock(&uhci->urb_remove_lock); + uhci_remove_pending_qhs(uhci); uhci_clear_next_interrupt(uhci); - /* Walk the list of pending TD's to see which ones completed */ - nested_lock(&uhci->urblist_lock, flags); + /* Walk the list of pending URB's to see which ones completed */ + spin_lock(&uhci->urb_list_lock); head = &uhci->urb_list; tmp = head->next; while (tmp != head) { @@ -2089,12 +2378,14 @@ tmp = tmp->next; /* Checks the status and does all of the magic necessary */ - uhci_transfer_result(urb); + uhci_transfer_result(uhci, urb); } - nested_unlock(&uhci->urblist_lock, flags); + spin_unlock(&uhci->urb_list_lock); + + uhci_finish_completion(uhci); } -static void reset_hc(struct uhci *uhci) +static void uhci_reset(struct uhci *uhci) { unsigned int io_addr = uhci->io_addr; @@ -2148,7 +2439,7 @@ return connection; } -static void start_hc(struct uhci *uhci) +static void uhci_start(struct uhci *uhci) { unsigned int io_addr = uhci->io_addr; int timeout = 1000; @@ -2173,12 +2464,43 @@ /* Start at frame 0 */ outw(0, io_addr + USBFRNUM); - outl(virt_to_bus(uhci->fl), io_addr + USBFLBASEADD); + outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD); /* Run and mark it configured with a 64-byte max packet */ outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD); } +static int uhci_alloc_root_hub(struct uhci *uhci) +{ + struct usb_device *dev; + + dev = usb_alloc_dev(NULL, uhci->bus); + if (!dev) + return -1; + + uhci->bus->root_hub = dev; + uhci->rh.dev = dev; + + return 0; +} + +static int uhci_start_root_hub(struct uhci *uhci) +{ + usb_connect(uhci->rh.dev); + + if (usb_new_device(uhci->rh.dev) != 0) { + usb_free_dev(uhci->rh.dev); + + return -1; + } + + return 0; +} + +#ifdef CONFIG_PROC_FS +static int uhci_num = 0; +#endif + /* * Allocate a frame list, and then setup the skeleton * @@ -2193,8 +2515,9 @@ * - The second queue is the "control queue", split into low and high speed * - The third queue is "bulk data". */ -static struct uhci *alloc_uhci(unsigned int io_addr, unsigned int io_size) +static struct uhci *uhci_alloc(unsigned int io_addr, unsigned int io_size) { + dma_addr_t dma_handle; int i, port; struct uhci *uhci; struct usb_bus *bus; @@ -2209,32 +2532,39 @@ uhci->io_addr = io_addr; uhci->io_size = io_size; - spin_lock_init(&uhci->qh_remove_lock); + /* Initialize some lists/spinlocks */ + spin_lock_init(&uhci->qh_remove_list_lock); INIT_LIST_HEAD(&uhci->qh_remove_list); - spin_lock_init(&uhci->urb_remove_lock); + spin_lock_init(&uhci->urb_remove_list_lock); INIT_LIST_HEAD(&uhci->urb_remove_list); - nested_init(&uhci->urblist_lock); + spin_lock_init(&uhci->urb_list_lock); INIT_LIST_HEAD(&uhci->urb_list); - spin_lock_init(&uhci->framelist_lock); + spin_lock_init(&uhci->complete_list_lock); + INIT_LIST_HEAD(&uhci->complete_list); + + spin_lock_init(&uhci->frame_list_lock); /* We need exactly one page (per UHCI specs), how convenient */ /* We assume that one page is atleast 4k (1024 frames * 4 bytes) */ - uhci->fl = (void *)__get_free_page(GFP_KERNEL); + uhci->fl = pci_alloc_consistent(uhci->dev, sizeof(*uhci->fl), &dma_handle); if (!uhci->fl) - goto au_free_uhci; + goto free_uhci; + + memset((void *)uhci->fl, 0, sizeof(*uhci->fl)); + + uhci->fl->dma_handle = dma_handle; bus = usb_alloc_bus(&uhci_device_operations); if (!bus) - goto au_free_fl; + goto free_fl; uhci->bus = bus; bus->hcpriv = uhci; /* Initialize the root hub */ - /* UHCI specs says devices must have 2 ports, but goes on to say */ /* they may have more but give no way to determine how many they */ /* have. However, according to the UHCI spec, Bit 7 is always set */ @@ -2258,36 +2588,66 @@ uhci->rh.numports = port; + if (uhci_alloc_root_hub(uhci)) { + err("unable to allocate root hub"); + goto free_fl; + } + + uhci->skeltd[0] = uhci_alloc_td(uhci, uhci->rh.dev); + if (!uhci->skeltd[0]) { + err("unable to allocate TD 0"); + goto free_fl; + } + /* * 9 Interrupt queues; link int2 to int1, int4 to int2, etc * then link int1 to control and control to bulk */ for (i = 1; i < 9; i++) { - struct uhci_td *td = &uhci->skeltd[i]; + struct uhci_td *td; + + td = uhci->skeltd[i] = uhci_alloc_td(uhci, uhci->rh.dev); + if (!td) { + err("unable to allocate TD %d", i); + goto free_tds; + } uhci_fill_td(td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0); - td->link = virt_to_bus(&uhci->skeltd[i - 1]); + td->link = uhci->skeltd[i - 1]->dma_handle; } + uhci->skel_term_td = uhci_alloc_td(uhci, uhci->rh.dev); + if (!uhci->skel_term_td) { + err("unable to allocate TD 0"); + goto free_fl; + } + + for (i = 0; i < UHCI_NUM_SKELQH; i++) { + uhci->skelqh[i] = uhci_alloc_qh(uhci, uhci->rh.dev); + if (!uhci->skelqh[i]) { + err("unable to allocate QH %d", i); + goto free_qhs; + } + } - uhci_fill_td(&uhci->skel_int1_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0); - uhci->skel_int1_td.link = virt_to_bus(&uhci->skel_ls_control_qh) | UHCI_PTR_QH; + uhci_fill_td(uhci->skel_int1_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0); + uhci->skel_int1_td->link = uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH; - uhci->skel_ls_control_qh.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH; - uhci->skel_ls_control_qh.element = UHCI_PTR_TERM; + uhci->skel_ls_control_qh->link = uhci->skel_hs_control_qh->dma_handle | UHCI_PTR_QH; + uhci->skel_ls_control_qh->element = UHCI_PTR_TERM; - uhci->skel_hs_control_qh.link = virt_to_bus(&uhci->skel_bulk_qh) | UHCI_PTR_QH; - uhci->skel_hs_control_qh.element = UHCI_PTR_TERM; + uhci->skel_hs_control_qh->link = uhci->skel_bulk_qh->dma_handle | UHCI_PTR_QH; + uhci->skel_hs_control_qh->element = UHCI_PTR_TERM; - uhci->skel_bulk_qh.link = virt_to_bus(&uhci->skel_term_qh) | UHCI_PTR_QH; - uhci->skel_bulk_qh.element = UHCI_PTR_TERM; + uhci->skel_bulk_qh->link = uhci->skel_term_qh->dma_handle | UHCI_PTR_QH; + uhci->skel_bulk_qh->element = UHCI_PTR_TERM; /* This dummy TD is to work around a bug in Intel PIIX controllers */ - uhci_fill_td(&uhci->skel_term_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0); - uhci->skel_term_td.link = UHCI_PTR_TERM; + uhci_fill_td(uhci->skel_term_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0); + uhci->skel_term_td->link = UHCI_PTR_TERM; - uhci->skel_term_qh.link = UHCI_PTR_TERM; - uhci->skel_term_qh.element = virt_to_bus(&uhci->skel_term_td); + uhci->skel_term_qh->link = UHCI_PTR_TERM; + uhci->skel_term_qh->element = uhci->skel_term_td->dma_handle; /* * Fill the frame list: make all entries point to @@ -2297,8 +2657,8 @@ * scatter the interrupt queues in a way that gives * us a reasonable dynamic range for irq latencies. */ - for (i = 0; i < 1024; i++) { - struct uhci_td *irq = &uhci->skel_int1_td; + for (i = 0; i < UHCI_NUMFRAMES; i++) { + int irq = 0; if (i & 1) { irq++; @@ -2322,7 +2682,7 @@ } /* Only place we don't use the frame list routines */ - uhci->fl->frame[i] = virt_to_bus(irq); + uhci->fl->frame[i] = uhci->skeltd[irq]->dma_handle; } return uhci; @@ -2330,9 +2690,23 @@ /* * error exits: */ -au_free_fl: - free_page((unsigned long)uhci->fl); -au_free_uhci: +free_qhs: + for (i = 0; i < UHCI_NUM_SKELQH; i++) + if (uhci->skelqh[i]) { + uhci_free_qh(uhci, uhci->skelqh[i]); + uhci->skelqh[i] = NULL; + } +free_tds: + for (i = 0; i < UHCI_NUM_SKELTD; i++) + if (uhci->skeltd[i]) { + uhci_free_td(uhci, uhci->skeltd[i]); + uhci->skeltd[i] = NULL; + } + +free_fl: + pci_free_consistent(uhci->dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle); + +free_uhci: kfree(uhci); return NULL; @@ -2341,51 +2715,70 @@ /* * De-allocate all resources.. */ -static void release_uhci(struct uhci *uhci) +static void uhci_release(struct uhci *uhci) { + unsigned long flags; + int i; +#ifdef CONFIG_PROC_FS + char buf[8]; +#endif + + spin_lock_irqsave(&uhci->frame_list_lock, flags); + for (i = 0; i < UHCI_NUMFRAMES; i++) { + uhci->fl->frame[i] = UHCI_PTR_TERM; + uhci->fl->frame_cpu[i] = NULL; + } + spin_unlock_irqrestore(&uhci->frame_list_lock, flags); + + for (i = 0; i < UHCI_NUM_SKELQH; i++) + if (uhci->skelqh[i]) { + uhci_free_qh(uhci, uhci->skelqh[i]); + uhci->skelqh[i] = NULL; + } + + for (i = 0; i < UHCI_NUM_SKELTD; i++) + if (uhci->skeltd[i]) { + uhci_free_td(uhci, uhci->skeltd[i]); + uhci->skeltd[i] = NULL; + } + + release_region(uhci->io_addr, uhci->io_size); + if (uhci->irq >= 0) { free_irq(uhci->irq, uhci); uhci->irq = -1; } - if (uhci->fl) { - free_page((unsigned long)uhci->fl); - uhci->fl = NULL; - } +#ifdef CONFIG_PROC_FS + sprintf(buf, "hc%d", uhci->num); - usb_free_bus(uhci->bus); - kfree(uhci); + remove_proc_entry(buf, uhci_proc_root); + uhci->proc_entry = NULL; +#endif } -int uhci_start_root_hub(struct uhci *uhci) +static void uhci_free(struct uhci *uhci) { - struct usb_device *dev; - - dev = usb_alloc_dev(NULL, uhci->bus); - if (!dev) - return -1; - - uhci->bus->root_hub = dev; - usb_connect(dev); - - if (usb_new_device(dev) != 0) { - usb_free_dev(dev); - - return -1; + if (uhci->fl) { + pci_free_consistent(uhci->dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle); + uhci->fl = NULL; } - return 0; + usb_free_bus(uhci->bus); + kfree(uhci); } /* - * If we've successfully found a UHCI, now is the time to increment the - * module usage count, and return success.. + * If we've successfully found a UHCI, now is the time to return success.. */ -static int setup_uhci(struct pci_dev *dev, int irq, unsigned int io_addr, unsigned int io_size) +static int uhci_found(struct pci_dev *dev, int irq, unsigned int io_addr, unsigned int io_size) { int retval; struct uhci *uhci; char buf[8], *bufp = buf; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *ent; +#endif #ifndef __sparc__ sprintf(buf, "%d", irq); @@ -2395,17 +2788,35 @@ printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n", io_addr, bufp); - uhci = alloc_uhci(io_addr, io_size); + uhci = uhci_alloc(io_addr, io_size); if (!uhci) return -ENOMEM; + + uhci->dev = dev; dev->driver_data = uhci; +#ifdef CONFIG_PROC_FS + uhci->num = uhci_num++; + + sprintf(buf, "hc%d", uhci->num); + + ent = create_proc_entry(buf, S_IFREG|S_IRUGO|S_IWUSR, uhci_proc_root); + if (!ent) + return -ENOMEM; + + ent->data = uhci; + ent->proc_fops = &uhci_proc_operations; + ent->size = 0; + uhci->proc_entry = ent; +#endif + request_region(uhci->io_addr, io_size, "usb-uhci"); - reset_hc(uhci); + uhci_reset(uhci); usb_register_bus(uhci->bus); - start_hc(uhci); + + uhci_start(uhci); retval = -EBUSY; if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "usb-uhci", uhci) == 0) { @@ -2418,10 +2829,12 @@ } /* Couldn't allocate IRQ if we got here */ + uhci_reset(uhci); + uhci_release(uhci); - reset_hc(uhci); - release_region(uhci->io_addr, uhci->io_size); - release_uhci(uhci); + usb_deregister_bus(uhci->bus); + + uhci_free(uhci); return retval; } @@ -2455,7 +2868,8 @@ break; pci_set_master(dev); - return setup_uhci(dev, dev->irq, io_addr, io_size); + + return uhci_found(dev, dev->irq, io_addr, io_size); } return -ENODEV; @@ -2468,31 +2882,33 @@ if (uhci->bus->root_hub) usb_disconnect(&uhci->bus->root_hub); - usb_deregister_bus(uhci->bus); + /* At this point, we're pretty much guaranteed that no new */ + /* connects can be made to this bus since there are no more */ + /* parents */ + uhci_free_pending_qhs(uhci); + uhci_remove_pending_qhs(uhci); + uhci_finish_completion(uhci); - reset_hc(uhci); - release_region(uhci->io_addr, uhci->io_size); + uhci_reset(uhci); + uhci_release(uhci); - uhci_free_pending_qhs(uhci); + usb_deregister_bus(uhci->bus); - release_uhci(uhci); + uhci_free(uhci); } static void uhci_pci_suspend(struct pci_dev *dev) { - reset_hc((struct uhci *) dev->driver_data); + uhci_reset((struct uhci *)dev->driver_data); } static void uhci_pci_resume(struct pci_dev *dev) { - reset_hc((struct uhci *) dev->driver_data); - start_hc((struct uhci *) dev->driver_data); + uhci_reset((struct uhci *)dev->driver_data); + uhci_start((struct uhci *)dev->driver_data); } -/*-------------------------------------------------------------------------*/ - -static const struct pci_device_id __devinitdata uhci_pci_ids [] = { { - +static const struct pci_device_id __devinitdata uhci_pci_ids[] = { { /* handle any USB UHCI controller */ class: ((PCI_CLASS_SERIAL_USB << 8) | 0x00), class_mask: ~0, @@ -2520,38 +2936,23 @@ resume: uhci_pci_resume, #endif /* PM */ }; - static int __init uhci_hcd_init(void) { - int retval; - - retval = -ENOMEM; - - /* We throw all of the TD's and QH's into a kmem cache */ - /* TD's and QH's need to be 16 byte aligned and SLAB_HWCACHE_ALIGN */ - /* does this for us */ - uhci_td_cachep = kmem_cache_create("uhci_td", - sizeof(struct uhci_td), 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); - - if (!uhci_td_cachep) - goto td_failed; - - uhci_qh_cachep = kmem_cache_create("uhci_qh", - sizeof(struct uhci_qh), 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); + int retval = -ENOMEM; - if (!uhci_qh_cachep) - goto qh_failed; +#ifdef CONFIG_PROC_FS + uhci_proc_root = create_proc_entry("uhci", S_IFDIR, 0); + if (!uhci_proc_root) + goto proc_failed; +#endif uhci_up_cachep = kmem_cache_create("uhci_urb_priv", sizeof(struct urb_priv), 0, 0, NULL, NULL); - if (!uhci_up_cachep) goto up_failed; - retval = pci_module_init (&uhci_pci_driver); + retval = pci_module_init(&uhci_pci_driver); if (retval) goto init_failed; @@ -2562,29 +2963,24 @@ printk(KERN_INFO "uhci: not all urb_priv's were freed\n"); up_failed: - if (kmem_cache_destroy(uhci_qh_cachep)) - printk(KERN_INFO "uhci: not all QH's were freed\n"); - -qh_failed: - if (kmem_cache_destroy(uhci_td_cachep)) - printk(KERN_INFO "uhci: not all TD's were freed\n"); +#ifdef CONFIG_PROC_FS + remove_proc_entry("uhci", 0); -td_failed: +proc_failed: +#endif return retval; } static void __exit uhci_hcd_cleanup (void) { - pci_unregister_driver (&uhci_pci_driver); + pci_unregister_driver(&uhci_pci_driver); if (kmem_cache_destroy(uhci_up_cachep)) printk(KERN_INFO "uhci: not all urb_priv's were freed\n"); - if (kmem_cache_destroy(uhci_qh_cachep)) - printk(KERN_INFO "uhci: not all QH's were freed\n"); - - if (kmem_cache_destroy(uhci_td_cachep)) - printk(KERN_INFO "uhci: not all TD's were freed\n"); +#ifdef CONFIG_PROC_FS + remove_proc_entry("uhci", 0); +#endif } module_init(uhci_hcd_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/uhci.h linux.ac/drivers/usb/uhci.h --- linux.vanilla/drivers/usb/uhci.h Tue Apr 3 17:32:24 2001 +++ linux.ac/drivers/usb/uhci.h Mon Apr 16 00:15:40 2001 @@ -5,36 +5,6 @@ #include <linux/usb.h> /* - * This nested spinlock code is courtesy of Davide Libenzi <dlibenzi@maticad.it> - */ -struct s_nested_lock { - spinlock_t lock; - void *uniq; - short int count; -}; - -#define nested_init(snl) \ - spin_lock_init(&(snl)->lock); \ - (snl)->uniq = NULL; \ - (snl)->count = 0; - -#define nested_lock(snl, flags) \ - if ((snl)->uniq == current) { \ - (snl)->count++; \ - flags = 0; /* No warnings */ \ - } else { \ - spin_lock_irqsave(&(snl)->lock, flags); \ - (snl)->count++; \ - (snl)->uniq = current; \ - } - -#define nested_unlock(snl, flags) \ - if (!--(snl)->count) { \ - (snl)->uniq = NULL; \ - spin_unlock_irqrestore(&(snl)->lock, flags); \ - } - -/* * Universal Host Controller Interface data structures and defines */ @@ -97,11 +67,15 @@ #define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */ #define CAN_SCHEDULE_FRAMES 1000 /* how far future frames can be scheduled */ -struct uhci_framelist { +struct uhci_frame_list { __u32 frame[UHCI_NUMFRAMES]; -} __attribute__((aligned(4096))); -struct uhci_td; + dma_addr_t dma_handle; + + void *frame_cpu[UHCI_NUMFRAMES]; +}; + +struct urb_priv; struct uhci_qh { /* Hardware fields */ @@ -109,12 +83,13 @@ __u32 element; /* Queue element pointer */ /* Software fields */ - /* Can't use list_head since we want a specific order */ + dma_addr_t dma_handle; struct usb_device *dev; /* The owning device */ - struct uhci_qh *prevqh, *nextqh; + struct urb_priv *urbp; - struct list_head remove_list; + struct list_head list; /* P: uhci->frame_list_lock */ + struct list_head remove_list; /* P: uhci->remove_list_lock */ } __attribute__((aligned(16))); /* @@ -141,8 +116,6 @@ #define uhci_status_bits(ctrl_sts) (ctrl_sts & 0xFE0000) #define uhci_actual_length(ctrl_sts) ((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */ -#define uhci_ptr_to_virt(x) bus_to_virt(x & ~UHCI_PTR_BITS) - /* * for TD <info>: (a.k.a. Token) */ @@ -170,7 +143,8 @@ * On 64-bit machines we probably want to take advantage of the fact that * hw doesn't really care about the size of the sw-only area. * - * Alas, not anymore, we have more than 4 words for software, woops + * Alas, not anymore, we have more than 4 words for software, woops. + * Everything still works tho, surprise! -jerdfelt */ struct uhci_td { /* Hardware fields */ @@ -180,13 +154,14 @@ __u32 buffer; /* Software fields */ - unsigned int *frameptr; /* Frame list pointer */ - struct uhci_td *prevtd, *nexttd; /* Previous and next TD in queue */ + dma_addr_t dma_handle; + int frame; struct usb_device *dev; struct urb *urb; /* URB this TD belongs to */ - struct list_head list; + struct list_head list; /* P: urb->lock */ + struct list_head fl_list; /* P: frame_list_lock */ } __attribute__((aligned(16))); /* @@ -289,8 +264,8 @@ } struct virt_root_hub { - int devnum; /* Address of Root Hub endpoint */ - void *urb; + struct usb_device *dev; + struct urb *urb; void *int_addr; int send; int interval; @@ -306,6 +281,12 @@ * a subset of what the full implementation needs. */ struct uhci { + struct pci_dev *dev; + + /* procfs */ + int num; + struct proc_dir_entry *proc_entry; + /* Grabbed from PCI */ int irq; unsigned int io_addr; @@ -315,30 +296,41 @@ struct usb_bus *bus; - struct uhci_td skeltd[UHCI_NUM_SKELTD]; /* Skeleton TD's */ - struct uhci_qh skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */ + struct uhci_td *skeltd[UHCI_NUM_SKELTD]; /* Skeleton TD's */ + struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */ - spinlock_t framelist_lock; - struct uhci_framelist *fl; /* Frame list */ - int fsbr; /* Full speed bandwidth reclamation */ + spinlock_t frame_list_lock; + struct uhci_frame_list *fl; /* Frame list */ + int fsbr; /* Full speed bandwidth reclamation */ int is_suspended; - spinlock_t qh_remove_lock; + spinlock_t qh_remove_list_lock; struct list_head qh_remove_list; - spinlock_t urb_remove_lock; + spinlock_t urb_remove_list_lock; struct list_head urb_remove_list; - struct s_nested_lock urblist_lock; + spinlock_t urb_list_lock; struct list_head urb_list; + spinlock_t complete_list_lock; + struct list_head complete_list; + struct virt_root_hub rh; /* private data of the virtual root hub */ }; struct urb_priv { struct urb *urb; + struct usb_device *dev; + + void *setup_buffer; /* CPU handle */ + dma_addr_t setup_buffer_dma_handle; /* DMA address */ + + void *transfer_buffer; /* CPU handle */ + dma_addr_t transfer_buffer_dma_handle; /* DMA address */ struct uhci_qh *qh; /* QH for this URB */ + struct list_head td_list; /* List of TD's (if !qh) */ int fsbr : 1; /* URB turned on FSBR */ int fsbr_timeout : 1; /* URB timed out on FSBR */ @@ -347,11 +339,13 @@ /* a control transfer, retrigger */ /* the status phase */ - unsigned long inserttime; /* In jiffies */ + int status; /* Final status */ - struct list_head list; + unsigned long inserttime; /* In jiffies */ - struct list_head urb_queue_list; /* URB's linked together */ + /* P: urb->lock */ + struct list_head queue_list; /* URB's linked together */ + struct list_head complete_list; /* URB's to be completed */ }; /* ------------------------------------------------------------------------- @@ -409,6 +403,7 @@ #define RH_REQ_ERR -1 #define RH_NACK 0x00 +#if 0 /* needed for the debugging code */ struct uhci_td *uhci_link_to_td(unsigned int element); @@ -418,6 +413,7 @@ void uhci_show_urb_queue(struct urb *urb); void uhci_show_queue(struct uhci_qh *qh); void uhci_show_queues(struct uhci *uhci); +#endif #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/ultracam.c linux.ac/drivers/usb/ultracam.c --- linux.vanilla/drivers/usb/ultracam.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/usb/ultracam.c Tue Apr 3 17:55:08 2001 @@ -0,0 +1,708 @@ +/* + * USB NB Camera driver + */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/wrapper.h> +#include <linux/module.h> +#include <linux/init.h> + +#include "usbvideo.h" + +#define ULTRACAM_VENDOR_ID 0x0461 +#define ULTRACAM_PRODUCT_ID 0x0813 + +#define MAX_CAMERAS 4 /* How many devices we allow to connect */ + +/* + * This structure lives in uvd_t->user field. + */ +typedef struct { + int initialized; /* Had we already sent init sequence? */ + int camera_model; /* What type of IBM camera we got? */ + int has_hdr; +} ultracam_t; +#define ULTRACAM_T(uvd) ((ultracam_t *)((uvd)->user_data)) + +usbvideo_t *cams = NULL; + +static int debug = 0; + +static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */ + +static const int min_canvasWidth = 8; +static const int min_canvasHeight = 4; + +//static int lighting = 1; /* Medium */ + +#define SHARPNESS_MIN 0 +#define SHARPNESS_MAX 6 +//static int sharpness = 4; /* Low noise, good details */ + +#define FRAMERATE_MIN 0 +#define FRAMERATE_MAX 6 +static int framerate = -1; + +/* + * Here we define several initialization variables. They may + * be used to automatically set color, hue, brightness and + * contrast to desired values. This is particularly useful in + * case of webcams (which have no controls and no on-screen + * output) and also when a client V4L software is used that + * does not have some of those controls. In any case it's + * good to have startup values as options. + * + * These values are all in [0..255] range. This simplifies + * operation. Note that actual values of V4L variables may + * be scaled up (as much as << 8). User can see that only + * on overlay output, however, or through a V4L client. + */ +static int init_brightness = 128; +static int init_contrast = 192; +static int init_color = 128; +static int init_hue = 128; +static int hue_correction = 128; + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); +MODULE_PARM(flags, "i"); +MODULE_PARM_DESC(flags, + "Bitfield: 0=VIDIOCSYNC, " + "1=B/W, " + "2=show hints, " + "3=show stats, " + "4=test pattern, " + "5=separate frames, " + "6=clean frames"); +MODULE_PARM(framerate, "i"); +MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)"); +MODULE_PARM(lighting, "i"); +MODULE_PARM_DESC(lighting, "Photosensitivity: 0=bright, 1=medium (default), 2=low light"); +MODULE_PARM(sharpness, "i"); +MODULE_PARM_DESC(sharpness, "Model1 noise reduction: 0=smooth, 6=sharp (default=4)"); + +MODULE_PARM(init_brightness, "i"); +MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)"); +MODULE_PARM(init_contrast, "i"); +MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)"); +MODULE_PARM(init_color, "i"); +MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)"); +MODULE_PARM(init_hue, "i"); +MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)"); +MODULE_PARM(hue_correction, "i"); +MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)"); + +/* + * ultracam_ProcessIsocData() + * + * Generic routine to parse the ring queue data. It employs either + * ultracam_find_header() or ultracam_parse_lines() to do most + * of work. + * + * 02-Nov-2000 First (mostly dummy) version. + * 06-Nov-2000 Rewrote to dump all data into frame. + */ +void ultracam_ProcessIsocData(uvd_t *uvd, usbvideo_frame_t *frame) +{ + int n; + + assert(uvd != NULL); + assert(frame != NULL); + + /* Try to move data from queue into frame buffer */ + n = RingQueue_GetLength(&uvd->dp); + if (n > 0) { + int m; + /* See how much spare we have left */ + m = uvd->max_frame_size - frame->seqRead_Length; + if (n > m) + n = m; + /* Now move that much data into frame buffer */ + RingQueue_Dequeue( + &uvd->dp, + frame->data + frame->seqRead_Length, + m); + frame->seqRead_Length += m; + } + /* See if we filled the frame */ + if (frame->seqRead_Length >= uvd->max_frame_size) { + frame->frameState = FrameState_Done; + uvd->curframe = -1; + uvd->stats.frame_num++; + } +} + +/* + * ultracam_veio() + * + * History: + * 1/27/00 Added check for dev == NULL; this happens if camera is unplugged. + */ +static int ultracam_veio( + uvd_t *uvd, + unsigned char req, + unsigned short value, + unsigned short index, + int is_out) +{ + static const char proc[] = "ultracam_veio"; + unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */; + int i; + + if (!CAMERA_IS_OPERATIONAL(uvd)) + return 0; + + if (!is_out) { + i = usb_control_msg( + uvd->dev, + usb_rcvctrlpipe(uvd->dev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, + index, + cp, + sizeof(cp), + HZ); +#if 1 + info("USB => %02x%02x%02x%02x%02x%02x%02x%02x " + "(req=$%02x val=$%04x ind=$%04x)", + cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7], + req, value, index); +#endif + } else { + i = usb_control_msg( + uvd->dev, + usb_sndctrlpipe(uvd->dev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, + index, + NULL, + 0, + HZ); + } + if (i < 0) { + err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.", + proc, i); + uvd->last_error = i; + } + return i; +} + +/* + * ultracam_calculate_fps() + */ +static int ultracam_calculate_fps(uvd_t *uvd) +{ + return 3 + framerate*4 + framerate/2; +} + +/* + * ultracam_adjust_contrast() + */ +static void ultracam_adjust_contrast(uvd_t *uvd) +{ +} + +/* + * ultracam_change_lighting_conditions() + */ +static void ultracam_change_lighting_conditions(uvd_t *uvd) +{ +} + +/* + * ultracam_set_sharpness() + * + * Cameras model 1 have internal smoothing feature. It is controlled by value in + * range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess). + * Recommended value is 4. Cameras model 2 do not have this feature at all. + */ +static void ultracam_set_sharpness(uvd_t *uvd) +{ +} + +/* + * ultracam_set_brightness() + * + * This procedure changes brightness of the picture. + */ +static void ultracam_set_brightness(uvd_t *uvd) +{ +} + +static void ultracam_set_hue(uvd_t *uvd) +{ +} + +/* + * ultracam_adjust_picture() + * + * This procedure gets called from V4L interface to update picture settings. + * Here we change brightness and contrast. + */ +static void ultracam_adjust_picture(uvd_t *uvd) +{ + ultracam_adjust_contrast(uvd); + ultracam_set_brightness(uvd); + ultracam_set_hue(uvd); +} + +/* + * ultracam_video_stop() + * + * This code tells camera to stop streaming. The interface remains + * configured and bandwidth - claimed. + */ +static void ultracam_video_stop(uvd_t *uvd) +{ +} + +/* + * ultracam_reinit_iso() + * + * This procedure sends couple of commands to the camera and then + * resets the video pipe. This sequence was observed to reinit the + * camera or, at least, to initiate ISO data stream. + */ +static void ultracam_reinit_iso(uvd_t *uvd, int do_stop) +{ +} + +static void ultracam_video_start(uvd_t *uvd) +{ + ultracam_change_lighting_conditions(uvd); + ultracam_set_sharpness(uvd); + ultracam_reinit_iso(uvd, 0); +} + +static int ultracam_resetPipe(uvd_t *uvd) +{ + usb_clear_halt(uvd->dev, uvd->video_endp); + return 0; +} + +static int ultracam_alternateSetting(uvd_t *uvd, int setting) +{ + static const char proc[] = "ultracam_alternateSetting"; + int i; + i = usb_set_interface(uvd->dev, uvd->iface, setting); + if (i < 0) { + err("%s: usb_set_interface error", proc); + uvd->last_error = i; + return -EBUSY; + } + return 0; +} + +/* + * Return negative code on failure, 0 on success. + */ +static int ultracam_setup_on_open(uvd_t *uvd) +{ + int setup_ok = 0; /* Success by default */ + /* Send init sequence only once, it's large! */ + if (!ULTRACAM_T(uvd)->initialized) { + ultracam_alternateSetting(uvd, 0x04); + ultracam_alternateSetting(uvd, 0x00); + ultracam_veio(uvd, 0x02, 0x0004, 0x000b, 1); + ultracam_veio(uvd, 0x02, 0x0001, 0x0005, 1); + ultracam_veio(uvd, 0x02, 0x8000, 0x0000, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1); + ultracam_veio(uvd, 0x00, 0x00b0, 0x0001, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x0002, 1); + ultracam_veio(uvd, 0x00, 0x000c, 0x0003, 1); + ultracam_veio(uvd, 0x00, 0x000b, 0x0004, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x0005, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x0006, 1); + ultracam_veio(uvd, 0x00, 0x0079, 0x0007, 1); + ultracam_veio(uvd, 0x00, 0x003b, 0x0008, 1); + ultracam_veio(uvd, 0x00, 0x0002, 0x000f, 1); + ultracam_veio(uvd, 0x00, 0x0001, 0x0010, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x0011, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00bf, 1); + ultracam_veio(uvd, 0x00, 0x0001, 0x00c0, 1); + ultracam_veio(uvd, 0x00, 0x0010, 0x00cb, 1); + ultracam_veio(uvd, 0x01, 0x00a4, 0x0001, 1); + ultracam_veio(uvd, 0x01, 0x0010, 0x0002, 1); + ultracam_veio(uvd, 0x01, 0x0066, 0x0007, 1); + ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1); + ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1); + ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1); + ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1); + ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1); + ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1); + ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1); + ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1); + ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1); + ultracam_veio(uvd, 0x01, 0x000b, 0x0011, 1); + ultracam_veio(uvd, 0x01, 0x0001, 0x0012, 1); + ultracam_veio(uvd, 0x01, 0x0000, 0x0013, 1); + ultracam_veio(uvd, 0x01, 0x0000, 0x0014, 1); + ultracam_veio(uvd, 0x01, 0x0087, 0x0051, 1); + ultracam_veio(uvd, 0x01, 0x0040, 0x0052, 1); + ultracam_veio(uvd, 0x01, 0x0058, 0x0053, 1); + ultracam_veio(uvd, 0x01, 0x0040, 0x0054, 1); + ultracam_veio(uvd, 0x01, 0x0000, 0x0040, 1); + ultracam_veio(uvd, 0x01, 0x0010, 0x0041, 1); + ultracam_veio(uvd, 0x01, 0x0020, 0x0042, 1); + ultracam_veio(uvd, 0x01, 0x0030, 0x0043, 1); + ultracam_veio(uvd, 0x01, 0x0040, 0x0044, 1); + ultracam_veio(uvd, 0x01, 0x0050, 0x0045, 1); + ultracam_veio(uvd, 0x01, 0x0060, 0x0046, 1); + ultracam_veio(uvd, 0x01, 0x0070, 0x0047, 1); + ultracam_veio(uvd, 0x01, 0x0080, 0x0048, 1); + ultracam_veio(uvd, 0x01, 0x0090, 0x0049, 1); + ultracam_veio(uvd, 0x01, 0x00a0, 0x004a, 1); + ultracam_veio(uvd, 0x01, 0x00b0, 0x004b, 1); + ultracam_veio(uvd, 0x01, 0x00c0, 0x004c, 1); + ultracam_veio(uvd, 0x01, 0x00d0, 0x004d, 1); + ultracam_veio(uvd, 0x01, 0x00e0, 0x004e, 1); + ultracam_veio(uvd, 0x01, 0x00f0, 0x004f, 1); + ultracam_veio(uvd, 0x01, 0x00ff, 0x0050, 1); + ultracam_veio(uvd, 0x01, 0x0000, 0x0056, 1); + ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1); + ultracam_veio(uvd, 0x00, 0x0004, 0x00c2, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0002, 0x00c1, 1); + ultracam_veio(uvd, 0x00, 0x0020, 0x00c2, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0040, 0x00c1, 1); + ultracam_veio(uvd, 0x00, 0x0017, 0x00c2, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); + ultracam_veio(uvd, 0x00, 0x00c0, 0x00c1, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); + ultracam_veio(uvd, 0x02, 0xc040, 0x0001, 1); + ultracam_veio(uvd, 0x01, 0x0000, 0x0008, 0); + ultracam_veio(uvd, 0x01, 0x0000, 0x0009, 0); + ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 0); + ultracam_veio(uvd, 0x01, 0x0000, 0x000b, 0); + ultracam_veio(uvd, 0x01, 0x0000, 0x000c, 0); + ultracam_veio(uvd, 0x01, 0x0000, 0x000d, 0); + ultracam_veio(uvd, 0x01, 0x0000, 0x000e, 0); + ultracam_veio(uvd, 0x01, 0x0000, 0x000f, 0); + ultracam_veio(uvd, 0x01, 0x0000, 0x0010, 0); + ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1); + ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1); + ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1); + ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1); + ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1); + ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1); + ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1); + ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1); + ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1); + ultracam_veio(uvd, 0x01, 0x0000, 0x0001, 0); + ultracam_veio(uvd, 0x01, 0x0064, 0x0001, 1); + ultracam_veio(uvd, 0x01, 0x0059, 0x0051, 1); + ultracam_veio(uvd, 0x01, 0x003f, 0x0052, 1); + ultracam_veio(uvd, 0x01, 0x0094, 0x0053, 1); + ultracam_veio(uvd, 0x01, 0x00ff, 0x0011, 1); + ultracam_veio(uvd, 0x01, 0x0003, 0x0012, 1); + ultracam_veio(uvd, 0x01, 0x00f7, 0x0013, 1); + ultracam_veio(uvd, 0x00, 0x0009, 0x0011, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x0001, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1); + ultracam_veio(uvd, 0x00, 0x0020, 0x00c1, 1); + ultracam_veio(uvd, 0x00, 0x0010, 0x00c2, 1); + ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); + ultracam_alternateSetting(uvd, 0x04); + ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1); + ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1); + ultracam_veio(uvd, 0x02, 0x0000, 0x0006, 1); + ultracam_veio(uvd, 0x02, 0x9000, 0x0007, 1); + ultracam_veio(uvd, 0x02, 0x0042, 0x0001, 1); + ultracam_veio(uvd, 0x02, 0x0000, 0x000b, 0); + ultracam_resetPipe(uvd); + ULTRACAM_T(uvd)->initialized = (setup_ok != 0); + } + return setup_ok; +} + +static void ultracam_configure_video(uvd_t *uvd) +{ + if (uvd == NULL) + return; + + RESTRICT_TO_RANGE(init_brightness, 0, 255); + RESTRICT_TO_RANGE(init_contrast, 0, 255); + RESTRICT_TO_RANGE(init_color, 0, 255); + RESTRICT_TO_RANGE(init_hue, 0, 255); + RESTRICT_TO_RANGE(hue_correction, 0, 255); + + memset(&uvd->vpic, 0, sizeof(uvd->vpic)); + memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old)); + + uvd->vpic.colour = init_color << 8; + uvd->vpic.hue = init_hue << 8; + uvd->vpic.brightness = init_brightness << 8; + uvd->vpic.contrast = init_contrast << 8; + uvd->vpic.whiteness = 105 << 8; /* This one isn't used */ + uvd->vpic.depth = 24; + uvd->vpic.palette = VIDEO_PALETTE_RGB24; + + memset(&uvd->vcap, 0, sizeof(uvd->vcap)); + strcpy(uvd->vcap.name, "IBM Ultra Camera"); + uvd->vcap.type = VID_TYPE_CAPTURE; + uvd->vcap.channels = 1; + uvd->vcap.audios = 0; + uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas); + uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas); + uvd->vcap.minwidth = min_canvasWidth; + uvd->vcap.minheight = min_canvasHeight; + + memset(&uvd->vchan, 0, sizeof(uvd->vchan)); + uvd->vchan.flags = 0; + uvd->vchan.tuners = 0; + uvd->vchan.channel = 0; + uvd->vchan.type = VIDEO_TYPE_CAMERA; + strcpy(uvd->vchan.name, "Camera"); +} + +/* + * ultracam_probe() + * + * This procedure queries device descriptor and accepts the interface + * if it looks like our camera. + * + * History: + * 12-Nov-2000 Reworked to comply with new probe() signature. + * 23-Jan-2001 Added compatibility with 2.2.x kernels. + */ +static void *ultracam_probe(struct usb_device *dev, unsigned int ifnum +#if defined(usb_device_id_ver) + ,const struct usb_device_id *devid +#endif + ) +{ + uvd_t *uvd = NULL; + int i, nas; + int actInterface=-1, inactInterface=-1, maxPS=0; + unsigned char video_ep = 0; + + if (debug >= 1) + info("ultracam_probe(%p,%u.)", dev, ifnum); + + /* We don't handle multi-config cameras */ + if (dev->descriptor.bNumConfigurations != 1) + return NULL; + + /* Is it an IBM camera? */ + if ((dev->descriptor.idVendor != ULTRACAM_VENDOR_ID) || + (dev->descriptor.idProduct != ULTRACAM_PRODUCT_ID)) + return NULL; + + info("IBM Ultra camera found (rev. 0x%04x)", dev->descriptor.bcdDevice); + + /* Validate found interface: must have one ISO endpoint */ + nas = dev->actconfig->interface[ifnum].num_altsetting; + if (debug > 0) + info("Number of alternate settings=%d.", nas); + if (nas < 8) { + err("Too few alternate settings for this camera!"); + return NULL; + } + /* Validate all alternate settings */ + for (i=0; i < nas; i++) { + const struct usb_interface_descriptor *interface; + const struct usb_endpoint_descriptor *endpoint; + + interface = &dev->actconfig->interface[ifnum].altsetting[i]; + if (interface->bNumEndpoints != 1) { + err("Interface %d. has %u. endpoints!", + ifnum, (unsigned)(interface->bNumEndpoints)); + return NULL; + } + endpoint = &interface->endpoint[0]; + if (video_ep == 0) + video_ep = endpoint->bEndpointAddress; + else if (video_ep != endpoint->bEndpointAddress) { + err("Alternate settings have different endpoint addresses!"); + return NULL; + } + if ((endpoint->bmAttributes & 0x03) != 0x01) { + err("Interface %d. has non-ISO endpoint!", ifnum); + return NULL; + } + if ((endpoint->bEndpointAddress & 0x80) == 0) { + err("Interface %d. has ISO OUT endpoint!", ifnum); + return NULL; + } + if (endpoint->wMaxPacketSize == 0) { + if (inactInterface < 0) + inactInterface = i; + else { + err("More than one inactive alt. setting!"); + return NULL; + } + } else { + if (actInterface < 0) { + actInterface = i; + maxPS = endpoint->wMaxPacketSize; + if (debug > 0) + info("Active setting=%d. maxPS=%d.", i, maxPS); + } else { + /* Got another active alt. setting */ + if (maxPS < endpoint->wMaxPacketSize) { + /* This one is better! */ + actInterface = i; + maxPS = endpoint->wMaxPacketSize; + if (debug > 0) { + info("Even better ctive setting=%d. maxPS=%d.", + i, maxPS); + } + } + } + } + } + if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) { + err("Failed to recognize the camera!"); + return NULL; + } + + /* Code below may sleep, need to lock module while we are here */ + MOD_INC_USE_COUNT; + uvd = usbvideo_AllocateDevice(cams); + if (uvd != NULL) { + /* Here uvd is a fully allocated uvd_t object */ + uvd->flags = flags; + uvd->debug = debug; + uvd->dev = dev; + uvd->iface = ifnum; + uvd->ifaceAltInactive = inactInterface; + uvd->ifaceAltActive = actInterface; + uvd->video_endp = video_ep; + uvd->iso_packet_len = maxPS; + uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24; + uvd->defaultPalette = VIDEO_PALETTE_RGB24; + uvd->canvas = VIDEOSIZE(640, 480); /* FIXME */ + uvd->videosize = uvd->canvas; /* ultracam_size_to_videosize(size);*/ + + /* Initialize ibmcam-specific data */ + assert(ULTRACAM_T(uvd) != NULL); + ULTRACAM_T(uvd)->camera_model = 0; /* Not used yet */ + ULTRACAM_T(uvd)->initialized = 0; + + ultracam_configure_video(uvd); + + i = usbvideo_RegisterVideoDevice(uvd); + if (i != 0) { + err("usbvideo_RegisterVideoDevice() failed."); + uvd = NULL; + } + } + MOD_DEC_USE_COUNT; + return uvd; +} + +/* + * ultracam_init() + * + * This code is run to initialize the driver. + */ +static int __init ultracam_init(void) +{ + usbvideo_cb_t cbTbl; + memset(&cbTbl, 0, sizeof(cbTbl)); + cbTbl.probe = ultracam_probe; + cbTbl.setupOnOpen = ultracam_setup_on_open; + cbTbl.videoStart = ultracam_video_start; + cbTbl.videoStop = ultracam_video_stop; + cbTbl.processData = ultracam_ProcessIsocData; + cbTbl.postProcess = usbvideo_DeinterlaceFrame; + cbTbl.adjustPicture = ultracam_adjust_picture; + cbTbl.getFPS = ultracam_calculate_fps; + return usbvideo_register( + &cams, + MAX_CAMERAS, + sizeof(ultracam_t), + "ultracam", + &cbTbl, + THIS_MODULE); +} + +static void __exit ultracam_cleanup(void) +{ + usbvideo_Deregister(&cams); +} + +#if defined(usb_device_id_ver) + +static __devinitdata struct usb_device_id id_table[] = { + { USB_DEVICE(ULTRACAM_VENDOR_ID, ULTRACAM_PRODUCT_ID) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, id_table); + +#endif /* defined(usb_device_id_ver) */ + +module_init(ultracam_init); +module_exit(ultracam_cleanup); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usb-ohci.c linux.ac/drivers/usb/usb-ohci.c --- linux.vanilla/drivers/usb/usb-ohci.c Tue Apr 3 17:32:24 2001 +++ linux.ac/drivers/usb/usb-ohci.c Wed Apr 4 18:25:48 2001 @@ -2098,6 +2098,7 @@ // Count and limit the retries though; either hardware or // software errors can go forever... #endif + hc_reset (ohci); } if (ints & OHCI_INTR_WDH) { @@ -2340,6 +2341,11 @@ if (pci_enable_device(dev) < 0) return -ENODEV; + + if (!dev->irq) { + err("found OHCI device with no IRQ assigned. check BIOS settings!"); + return -ENODEV; + } /* we read its hardware registers as memory */ mem_resource = pci_resource_start(dev, 0); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usb-uhci.c linux.ac/drivers/usb/usb-uhci.c --- linux.vanilla/drivers/usb/usb-uhci.c Tue Apr 3 17:32:24 2001 +++ linux.ac/drivers/usb/usb-uhci.c Tue Apr 3 17:55:08 2001 @@ -1411,7 +1411,7 @@ /*-------------------------------------------------------------------*/ // submits USB interrupt (ie. polling ;-) // ASAP-flag set implicitely -// if period==0, the the transfer is only done once +// if period==0, the transfer is only done once _static int uhci_submit_int_urb (urb_t *urb) { @@ -2390,7 +2390,7 @@ usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)); } - // if any error occured: ignore this td, and continue + // if any error occurred: ignore this td, and continue if (status != 0) { //uhci_show_td (desc); urb->error_count++; @@ -2625,19 +2625,22 @@ // Completion if (urb->complete) { + int was_unlinked = (urb->status == -ENOENT); urb->dev = NULL; spin_unlock(&s->urb_list_lock); urb->complete ((struct urb *) urb); // Re-submit the URB if ring-linked - if (is_ring && (urb->status != -ENOENT) && !contains_killed) { + if (is_ring && !was_unlinked && !contains_killed) { urb->dev=usb_dev; uhci_submit_urb (urb); - } + } else + urb = 0; spin_lock(&s->urb_list_lock); } usb_dec_dev_use (usb_dev); - spin_unlock(&urb->lock); + if (urb) + spin_unlock(&urb->lock); } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usb.c linux.ac/drivers/usb/usb.c --- linux.vanilla/drivers/usb/usb.c Tue Apr 3 17:32:24 2001 +++ linux.ac/drivers/usb/usb.c Tue Apr 3 17:55:08 2001 @@ -31,6 +31,7 @@ #include <linux/kmod.h> #include <linux/init.h> #include <linux/devfs_fs_kernel.h> +#include <linux/spinlock.h> #ifdef CONFIG_USB_DEBUG #define DEBUG @@ -61,6 +62,7 @@ */ LIST_HEAD(usb_driver_list); LIST_HEAD(usb_bus_list); +rwlock_t usb_bus_list_lock = RW_LOCK_UNLOCKED; devfs_handle_t usb_devfs_handle; /* /dev/usb dir. */ @@ -112,6 +114,7 @@ { struct list_head *tmp; + read_lock_irq (&usb_bus_list_lock); tmp = usb_bus_list.next; while (tmp != &usb_bus_list) { struct usb_bus *bus = list_entry(tmp,struct usb_bus, bus_list); @@ -119,6 +122,7 @@ tmp = tmp->next; usb_check_support(bus->root_hub); } + read_unlock_irq (&usb_bus_list_lock); } /* @@ -180,6 +184,7 @@ */ list_del(&driver->driver_list); + read_lock_irq (&usb_bus_list_lock); tmp = usb_bus_list.next; while (tmp != &usb_bus_list) { struct usb_bus *bus = list_entry(tmp,struct usb_bus,bus_list); @@ -187,6 +192,7 @@ tmp = tmp->next; usb_drivers_purge(driver, bus->root_hub); } + read_unlock_irq (&usb_bus_list_lock); } struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum) @@ -404,6 +410,7 @@ { int busnum; + write_lock_irq (&usb_bus_list_lock); busnum = find_next_zero_bit(busmap.busmap, USB_MAXBUS, 1); if (busnum < USB_MAXBUS) { set_bit(busnum, busmap.busmap); @@ -413,6 +420,7 @@ /* Add it to the list of buses */ list_add(&bus->bus_list, &usb_bus_list); + write_unlock_irq (&usb_bus_list_lock); usbdevfs_add_bus(bus); @@ -434,7 +442,9 @@ * controller code, as well as having it call this when cleaning * itself up */ + write_lock_irq (&usb_bus_list_lock); list_del(&bus->bus_list); + write_unlock_irq (&usb_bus_list_lock); usbdevfs_remove_bus(bus); @@ -685,6 +695,10 @@ tmp = tmp->next; down(&driver->serialize); + if (usb_interface_claimed(interface)) { + up(&driver->serialize); + return -1; + } id = driver->id_table; /* new style driver? */ if (id) { @@ -704,11 +718,13 @@ else /* "old style" driver */ private = driver->probe(dev, ifnum, NULL); - up(&driver->serialize); - if (private) { - usb_driver_claim_interface(driver, interface, private); - return 0; + if (!private) { + up(&driver->serialize); + continue; } + usb_driver_claim_interface(driver, interface, private); + up(&driver->serialize); + return 0; } return -1; @@ -1137,7 +1153,7 @@ * @pipe: endpoint "pipe" to send the message to * @data: pointer to the data to send * @len: length in bytes of the data to send - * @actual_length: pointer to a location to put the actual length transfered in bytes + * @actual_length: pointer to a location to put the actual length transferred in bytes * @timeout: time to wait for the message to complete before timing out (if 0 the wait is forever) * * This function sends a simple bulk message to a specified endpoint diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usbnet.c linux.ac/drivers/usb/usbnet.c --- linux.vanilla/drivers/usb/usbnet.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/usb/usbnet.c Tue Apr 3 17:55:08 2001 @@ -0,0 +1,1527 @@ +/* + * USB Host-to-Host Links + * Copyright (C) 2000-2001 by David Brownell <dbrownell@users.sourceforge.net> + */ + +/* + * This is used for "USB networking", connecting USB hosts as peers. + * + * It can be used with USB "network cables", for IP-over-USB communications; + * Ethernet speeds without the Ethernet. USB devices (including some PDAs) + * can support such links directly, replacing device-specific protocols + * with Internet standard ones. + * + * The links can be bridged using the Ethernet bridging (net/bridge) + * support as appropriate. Devices currently supported include: + * + * - AnchorChip 2720 + * - "Linux Devices" (like iPaq and similar SA-1100 based PDAs) + * - NetChip 1080 (interoperates with NetChip Win32 drivers) + * - Prolific PL-2301/2302 (replaces "plusb" driver) + * + * USB devices can implement their side of this protocol at the cost + * of two bulk endpoints; it's not restricted to "cable" applications. + * See the LINUXDEV support. + * + * + * TODO: + * + * This needs to be retested for bulk queuing problems ... earlier versions + * seemed to find different types of problems in each HCD. Once they're fixed, + * re-enable queues to get higher bandwidth utilization (without needing + * to tweak MTU for larger packets). + * + * Add support for more "network cable" chips; interop with their Win32 + * drivers may be a good thing. Test the AnchorChip 2720 support.. + * Figure out the initialization protocol used by the Prolific chips, + * for better robustness. + * + * Use interrupt on PL230x to detect peer connect/disconnect, and call + * netif_carrier_{on,off} (?) appropriately. For Net1080, detect peer + * connect/disconnect with async control messages. + * + * Find some way to report "peer connected" network hotplug events; it'll + * likely mean updating the networking layer. + * + * Craft smarter hotplug policy scripts ... ones that know how to arrange + * bridging with "brctl", and can handle static and dynamic ("pump") setups. + * Use those "peer connected" events. + * + * + * CHANGELOG: + * + * 13-sep-2000 experimental, new + * 10-oct-2000 usb_device_id table created. + * 28-oct-2000 misc fixes; mostly, discard more TTL-mangled rx packets. + * 01-nov-2000 usb_device_id table and probing api update by + * Adam J. Richter <adam@yggdrasil.com>. + * 18-dec-2000 (db) tx watchdog, "net1080" renaming to "usbnet", device_info + * and prolific support, isolate net1080-specific bits, cleanup. + * fix unlink_urbs oops in D3 PM resume code path. + * 02-feb-2001 (db) fix tx skb sharing, packet length, match_flags, ... + * 08-feb-2001 stubbed in "linuxdev", maybe the SA-1100 folk can use it; + * AnchorChips 2720 support (from spec) for testing; + * fix bit-ordering problem with ethernet multicast addr + * 19-feb-2001 Support for clearing halt conditions. SA1100 UDC support + * updates. Oleg Drokin (green@iXcelerator.com) + * 25-mar-2001 More SA-110 updates, including workaround for ip problem + * expecting cleared skb->cb and framing change to match latest + * handhelds.org version (Oleg). Enable device IDs from the + * Win32 Belkin driver; other cleanups (db). + * + *-------------------------------------------------------------------------*/ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kmod.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/random.h> +#include <asm/unaligned.h> + +#define DEBUG // error path messages, extra info +// #define VERBOSE // more; success messages +// #define REALLY_QUEUE + +#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG) +# define DEBUG +#endif +#include <linux/usb.h> + + +#define CONFIG_USB_AN2720 +#define CONFIG_USB_LINUXDEV +#define CONFIG_USB_NET1080 +#define CONFIG_USB_PL2301 + + +/*-------------------------------------------------------------------------*/ + +/* + * Nineteen USB 1.1 max size bulk transactions per frame (ms), max. + * Several dozen bytes of IPv4 data can fit in two such transactions. + * One maximum size Ethernet packet takes twenty four of them. + */ +#ifdef REALLY_QUEUE +#define RX_QLEN 4 +#define TX_QLEN 4 +#else +#define RX_QLEN 1 +#define TX_QLEN 1 +#endif + +// packets are always ethernet inside +// ... except they can be bigger (up to 64K with this framing) +#define MIN_PACKET sizeof(struct ethhdr) +#define MAX_PACKET 32768 + +// reawaken network queue this soon after stopping; else watchdog barks +#define TX_TIMEOUT_JIFFIES (5*HZ) + +// for vendor-specific control operations +#define CONTROL_TIMEOUT_MS (500) /* msec */ +#define CONTROL_TIMEOUT_JIFFIES ((CONTROL_TIMEOUT_MS * HZ)/1000) + +// between wakeups +#define UNLINK_TIMEOUT_JIFFIES ((3 /*ms*/ * HZ)/1000) + +/*-------------------------------------------------------------------------*/ + +// list of all devices we manage +static DECLARE_MUTEX (usbnet_mutex); +static LIST_HEAD (usbnet_list); + +// randomly generated ethernet address +static u8 node_id [ETH_ALEN]; + +// state we keep for each device we handle +struct usbnet { + // housekeeping + struct usb_device *udev; + struct driver_info *driver_info; + struct semaphore mutex; + struct list_head dev_list; + wait_queue_head_t *wait; + + // protocol/interface state + struct net_device net; + struct net_device_stats stats; + u16 packet_id; + + // various kinds of pending driver work + struct sk_buff_head rxq; + struct sk_buff_head txq; + struct sk_buff_head done; + struct tasklet_struct bh; + struct tq_struct ctrl_task; +}; + +// device-specific info used by the driver +struct driver_info { + char *description; + + int flags; +#define FLAG_FRAMING 0x0001 /* guard against device dropouts */ + + /* reset device ... can sleep */ + int (*reset)(struct usbnet *); + + /* see if peer is connected ... can sleep */ + int (*check_connect)(struct usbnet *); + + // FIXME -- also an interrupt mechanism + + /* framework currently "knows" bulk EPs talk packets */ + int in; /* rx endpoint */ + int out; /* tx endpoint */ + int epsize; +}; + +#define EP_SIZE(usbnet) ((usbnet)->driver_info->epsize) + +// we record the state for each of our queued skbs +enum skb_state { + illegal = 0, + tx_start, tx_done, + rx_start, rx_done, rx_cleanup +}; + +struct skb_data { // skb->cb is one of these + struct urb *urb; + struct usbnet *dev; + enum skb_state state; + size_t length; +}; + + +#define mutex_lock(x) down(x) +#define mutex_unlock(x) up(x) + +#define RUN_CONTEXT (in_irq () ? "in_irq" \ + : (in_interrupt () ? "in_interrupt" : "can sleep")) + +/*-------------------------------------------------------------------------*/ + +#ifdef DEBUG +#define devdbg(usbnet, fmt, arg...) \ + printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net.name, ## arg) +#else +#define devdbg(usbnet, fmt, arg...) do {} while(0) +#endif + +#define devinfo(usbnet, fmt, arg...) \ + printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net.name, ## arg) + +/*------------------------------------------------------------------------- + * + * NetChip framing of ethernet packets, supporting additional error + * checks for links that may drop bulk packets from inside messages. + * Odd USB length == always short read for last usb packet. + * - nc_header + * - Ethernet header (14 bytes) + * - payload + * - (optional padding byte, if needed so length becomes odd) + * - nc_trailer + * + * This framing is to be avoided for non-NetChip devices. + */ + +struct nc_header { // packed: + u16 hdr_len; // sizeof nc_header (LE, all) + u16 packet_len; // payload size (including ethhdr) + u16 packet_id; // detects dropped packets +#define MIN_HEADER 6 + + // all else is optional, and must start with: + // u16 vendorId; // from usb-if + // u16 productId; +} __attribute__((__packed__)); + +#define PAD_BYTE ((unsigned char)0xAC) + +struct nc_trailer { + u16 packet_id; +} __attribute__((__packed__)); + +// packets may use FLAG_FRAMING and optional pad +#define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \ + + sizeof (struct ethhdr) \ + + (mtu) \ + + 1 \ + + sizeof (struct nc_trailer)) + +#define MIN_FRAMED FRAMED_SIZE(0) + + + +#ifdef CONFIG_USB_AN2720 + +/*------------------------------------------------------------------------- + * + * AnchorChips 2720 driver ... http://www.cypress.com + * + * This doesn't seem to have a way to detect whether the peer is + * connected, or need any reset handshaking. It's got pretty big + * internal buffers (handles most of a frame's worth of data). + * Chip data sheets don't describe any vendor control messages. + * + *-------------------------------------------------------------------------*/ + +static const struct driver_info an2720_info = { + description: "AnchorChips/Cypress 2720", + // no reset available! + // no check_connect available! + + in: 2, out: 2, // direction distinguishes these + epsize: 64, +}; + +#endif /* CONFIG_USB_AN2720 */ + + + +#ifdef CONFIG_USB_LINUXDEV + +/*------------------------------------------------------------------------- + * + * This could talk to a device that uses Linux, such as a PDA or + * an embedded system, or in fact to any "smart" device using this + * particular mapping of USB and Ethernet. + * + * Such a Linux host would need a "USB Device Controller" hardware + * (not "USB Host Controller"), and a network driver talking to that + * hardware. + * + * One example is Intel's SA-1100 chip, which integrates basic USB + * support (arch/arm/sa1100/usb-eth.c). + * + *-------------------------------------------------------------------------*/ + + +static const struct driver_info linuxdev_info = { + description: "Linux Device", + // no reset defined (yet?) + // no check_connect needed! + in: 2, out: 1, + epsize: 64, +}; + +#endif /* CONFIG_USB_LINUXDEV */ + + + +#ifdef CONFIG_USB_NET1080 + +/*------------------------------------------------------------------------- + * + * Netchip 1080 driver ... http://www.netchip.com + * + *-------------------------------------------------------------------------*/ + +/* + * Zero means no timeout; else, how long a 64 byte bulk packet may be queued + * before the hardware drops it. If that's done, the driver will need to + * frame network packets to guard against the dropped USB packets. The win32 + * driver sets this for both sides of the link. + */ +#define NC_READ_TTL_MS ((u8)255) // ms + +/* + * We ignore most registers and EEPROM contents. + */ +#define REG_USBCTL ((u8)0x04) +#define REG_TTL ((u8)0x10) +#define REG_STATUS ((u8)0x11) + +/* + * Vendor specific requests to read/write data + */ +#define REQUEST_REGISTER ((u8)0x10) +#define REQUEST_EEPROM ((u8)0x11) + +static int +nc_vendor_read (struct usbnet *dev, u8 req, u8 regnum, u16 *retval_ptr) +{ + int status = usb_control_msg (dev->udev, + usb_rcvctrlpipe (dev->udev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, regnum, + retval_ptr, sizeof *retval_ptr, + CONTROL_TIMEOUT_JIFFIES); + if (status > 0) + status = 0; + if (!status) + le16_to_cpus (retval_ptr); + return status; +} + +static inline int +nc_register_read (struct usbnet *dev, u8 regnum, u16 *retval_ptr) +{ + return nc_vendor_read (dev, REQUEST_REGISTER, regnum, retval_ptr); +} + +// no retval ... can become async, usable in_interrupt() +static void +nc_vendor_write (struct usbnet *dev, u8 req, u8 regnum, u16 value) +{ + usb_control_msg (dev->udev, + usb_sndctrlpipe (dev->udev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, regnum, + 0, 0, // data is in setup packet + CONTROL_TIMEOUT_JIFFIES); +} + +static inline void +nc_register_write (struct usbnet *dev, u8 regnum, u16 value) +{ + nc_vendor_write (dev, REQUEST_REGISTER, regnum, value); +} + + +#if 0 +static void nc_dump_registers (struct usbnet *dev) +{ + u8 reg; + u16 value; + + dbg ("%s registers:", dev->net.name); + for (reg = 0; reg < 0x20; reg++) { + int retval; + + // reading some registers is trouble + if (reg >= 0x08 && reg <= 0xf) + continue; + if (reg >= 0x12 && reg <= 0x1e) + continue; + + retval = nc_register_read (dev, reg, &value); + if (retval < 0) + dbg ("%s reg [0x%x] ==> error %d", + dev->net.name, reg, retval); + else + dbg ("%s reg [0x%x] = 0x%x", + dev->net.name, reg, value); + } +} +#endif + + +/*-------------------------------------------------------------------------*/ + +/* + * Control register + */ + +#define USBCTL_WRITABLE_MASK 0x1f0f +// bits 15-13 reserved, r/o +#define USBCTL_ENABLE_LANG (1 << 12) +#define USBCTL_ENABLE_MFGR (1 << 11) +#define USBCTL_ENABLE_PROD (1 << 10) +#define USBCTL_ENABLE_SERIAL (1 << 9) +#define USBCTL_ENABLE_DEFAULTS (1 << 8) +// bits 7-4 reserved, r/o +#define USBCTL_FLUSH_OTHER (1 << 3) +#define USBCTL_FLUSH_THIS (1 << 2) +#define USBCTL_DISCONN_OTHER (1 << 1) +#define USBCTL_DISCONN_THIS (1 << 0) + +static inline void nc_dump_usbctl (struct usbnet *dev, u16 usbctl) +{ +#ifdef DEBUG + devdbg (dev, "net1080 %03d/%03d usbctl 0x%x:%s%s%s%s%s;" + " this%s%s;" + " other%s%s; r/o 0x%x", + dev->udev->bus->busnum, dev->udev->devnum, + usbctl, + (usbctl & USBCTL_ENABLE_LANG) ? " lang" : "", + (usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "", + (usbctl & USBCTL_ENABLE_PROD) ? " prod" : "", + (usbctl & USBCTL_ENABLE_SERIAL) ? " serial" : "", + (usbctl & USBCTL_ENABLE_DEFAULTS) ? " defaults" : "", + + (usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "", + (usbctl & USBCTL_DISCONN_OTHER) ? " DIS" : "", + (usbctl & USBCTL_FLUSH_THIS) ? " FLUSH" : "", + (usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "", + usbctl & ~USBCTL_WRITABLE_MASK + ); +#endif +} + +/*-------------------------------------------------------------------------*/ + +/* + * Status register + */ + +#define STATUS_PORT_A (1 << 15) + +#define STATUS_CONN_OTHER (1 << 14) +#define STATUS_SUSPEND_OTHER (1 << 13) +#define STATUS_MAILBOX_OTHER (1 << 12) +#define STATUS_PACKETS_OTHER(n) (((n) >> 8) && 0x03) + +#define STATUS_CONN_THIS (1 << 6) +#define STATUS_SUSPEND_THIS (1 << 5) +#define STATUS_MAILBOX_THIS (1 << 4) +#define STATUS_PACKETS_THIS(n) (((n) >> 0) && 0x03) + +#define STATUS_UNSPEC_MASK 0x0c8c +#define STATUS_NOISE_MASK ((u16)~(0x0303|STATUS_UNSPEC_MASK)) + + +static inline void nc_dump_status (struct usbnet *dev, u16 status) +{ +#ifdef DEBUG + devdbg (dev, "net1080 %03d/%03d status 0x%x:" + " this (%c) PKT=%d%s%s%s;" + " other PKT=%d%s%s%s; unspec 0x%x", + dev->udev->bus->busnum, dev->udev->devnum, + status, + + // XXX the packet counts don't seem right + // (1 at reset, not 0); maybe UNSPEC too + + (status & STATUS_PORT_A) ? 'A' : 'B', + STATUS_PACKETS_THIS (status), + (status & STATUS_CONN_THIS) ? " CON" : "", + (status & STATUS_SUSPEND_THIS) ? " SUS" : "", + (status & STATUS_MAILBOX_THIS) ? " MBOX" : "", + + STATUS_PACKETS_OTHER (status), + (status & STATUS_CONN_OTHER) ? " CON" : "", + (status & STATUS_SUSPEND_OTHER) ? " SUS" : "", + (status & STATUS_MAILBOX_OTHER) ? " MBOX" : "", + + status & STATUS_UNSPEC_MASK + ); +#endif +} + +/*-------------------------------------------------------------------------*/ + +/* + * TTL register + */ + +#define TTL_THIS(ttl) (0x00ff & ttl) +#define TTL_OTHER(ttl) (0x00ff & (ttl >> 8)) +#define MK_TTL(this,other) ((u16)(((other)<<8)|(0x00ff&(this)))) + +static inline void nc_dump_ttl (struct usbnet *dev, u16 ttl) +{ +#ifdef DEBUG + devdbg (dev, "net1080 %03d/%03d ttl 0x%x this = %d, other = %d", + dev->udev->bus->busnum, dev->udev->devnum, + ttl, + + TTL_THIS (ttl), + TTL_OTHER (ttl) + ); +#endif +} + +/*-------------------------------------------------------------------------*/ + +static int net1080_reset (struct usbnet *dev) +{ + u16 usbctl, status, ttl; + int retval; + + // nc_dump_registers (dev); + + if ((retval = nc_register_read (dev, REG_STATUS, &status)) < 0) { + dbg ("can't read dev %d status: %d", dev->udev->devnum, retval); + goto done; + } + // nc_dump_status (dev, status); + + if ((retval = nc_register_read (dev, REG_USBCTL, &usbctl)) < 0) { + dbg ("can't read USBCTL, %d", retval); + goto done; + } + // nc_dump_usbctl (dev, usbctl); + + nc_register_write (dev, REG_USBCTL, + USBCTL_FLUSH_THIS | USBCTL_FLUSH_OTHER); + + if ((retval = nc_register_read (dev, REG_TTL, &ttl)) < 0) { + dbg ("can't read TTL, %d", retval); + goto done; + } + // nc_dump_ttl (dev, ttl); + + nc_register_write (dev, REG_TTL, + MK_TTL (NC_READ_TTL_MS, TTL_OTHER (ttl)) ); + dbg ("%s: assigned TTL, %d ms", dev->net.name, NC_READ_TTL_MS); + + devdbg (dev, "port %c, peer %sconnected", + (status & STATUS_PORT_A) ? 'A' : 'B', + (status & STATUS_CONN_OTHER) ? "" : "dis" + ); + retval = 0; + +done: + return retval; +} + +static int net1080_check_connect (struct usbnet *dev) +{ + int retval; + u16 status; + + if ((retval = nc_register_read (dev, REG_STATUS, &status)) != 0) { + dbg ("%s net1080_check_conn read - %d", dev->net.name, retval); + return retval; + } + if ((status & STATUS_CONN_OTHER) != STATUS_CONN_OTHER) + return -ENOLINK; + return 0; +} + +static const struct driver_info net1080_info = { + description: "NetChip TurboCONNECT", + flags: FLAG_FRAMING, + reset: net1080_reset, + check_connect: net1080_check_connect, + + in: 1, out: 1, // direction distinguishes these + epsize: 64, +}; + +#endif /* CONFIG_USB_NET1080 */ + + + +#ifdef CONFIG_USB_PL2301 + +/*------------------------------------------------------------------------- + * + * Prolific PL-2301/PL-2302 driver ... http://www.prolifictech.com + * + *-------------------------------------------------------------------------*/ + +/* + * Bits 0-4 can be used for software handshaking; they're set from + * one end, cleared from the other, "read" with the interrupt byte. + */ +#define PL_S_EN (1<<7) /* (feature only) suspend enable */ +/* reserved bit -- rx ready (6) ? */ +#define PL_TX_READY (1<<5) /* (interrupt only) transmit ready */ +#define PL_RESET_OUT (1<<4) /* reset output pipe */ +#define PL_RESET_IN (1<<3) /* reset input pipe */ +#define PL_TX_C (1<<2) /* transmission complete */ +#define PL_TX_REQ (1<<1) /* transmission received */ +#define PL_PEER_E (1<<0) /* peer exists */ + +static inline int +pl_vendor_req (struct usbnet *dev, u8 req, u8 val, u8 index) +{ + return usb_control_msg (dev->udev, + usb_rcvctrlpipe (dev->udev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + val, index, + 0, 0, + CONTROL_TIMEOUT_JIFFIES); +} + +static inline int +pl_clear_QuickLink_features (struct usbnet *dev, int val) +{ + return pl_vendor_req (dev, 1, (u8) val, 0); +} + +static inline int +pl_set_QuickLink_features (struct usbnet *dev, int val) +{ + return pl_vendor_req (dev, 3, (u8) val, 0); +} + +/*-------------------------------------------------------------------------*/ + +static int pl_reset (struct usbnet *dev) +{ + return pl_set_QuickLink_features (dev, + PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E); +} + +static int pl_check_connect (struct usbnet *dev) +{ + // FIXME test interrupt data PL_PEER_E bit + // plus, there's some handshake done by + // the prolific win32 driver... + dbg ("%s: assuming peer is connected", dev->net.name); + return 0; +} + +static const struct driver_info prolific_info = { + description: "Prolific PL-2301/PL-2302", + reset: pl_reset, + check_connect: pl_check_connect, + + in: 3, out: 2, + epsize: 64, +}; + +#endif /* CONFIG_USB_PL2301 */ + + + +/*------------------------------------------------------------------------- + * + * Network Device Driver (peer link to "Host Device", from USB host) + * + *-------------------------------------------------------------------------*/ + +static int usbnet_change_mtu (struct net_device *net, int new_mtu) +{ + struct usbnet *dev = (struct usbnet *) net->priv; + + if (new_mtu <= sizeof (struct ethhdr) || new_mtu > MAX_PACKET) + return -EINVAL; + if (((dev->driver_info->flags) & FLAG_FRAMING)) { + if (FRAMED_SIZE (new_mtu) > MAX_PACKET) + return -EINVAL; + // no second zero-length packet read wanted after mtu-sized packets + } else if (((new_mtu + sizeof (struct ethhdr)) % EP_SIZE (dev)) == 0) + return -EDOM; + net->mtu = new_mtu; + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static struct net_device_stats *usbnet_get_stats (struct net_device *net) +{ + return &((struct usbnet *) net->priv)->stats; +} + +/*-------------------------------------------------------------------------*/ + +/* urb completions are currently in_irq; avoid doing real work then. */ + +static void defer_bh (struct usbnet *dev, struct sk_buff *skb) +{ + struct sk_buff_head *list = skb->list; + + spin_lock (&list->lock); + __skb_unlink (skb, list); + spin_unlock (&list->lock); + spin_lock (&dev->done.lock); + __skb_queue_tail (&dev->done, skb); + if (dev->done.qlen == 1) + tasklet_schedule (&dev->bh); + spin_unlock (&dev->done.lock); +} + +/*-------------------------------------------------------------------------*/ + +static void rx_complete (struct urb *urb); + +static void rx_submit (struct usbnet *dev, struct urb *urb, int flags) +{ + struct sk_buff *skb; + struct skb_data *entry; + int retval = 0; + unsigned long lockflags; + size_t size; + + /* make the IP layer happier with 16-byte alignment. + * Ethernet header uses 14 bytes; pad 2 normally. + * NetChip framing adds another 6, so pad total of 12. + */ + size = (dev->driver_info->flags & FLAG_FRAMING) + ? (12 + FRAMED_SIZE (dev->net.mtu)) + : (2 + sizeof (struct ethhdr) + dev->net.mtu); + if ((skb = alloc_skb (size, flags)) == 0) { + dbg ("no rx skb"); + tasklet_schedule (&dev->bh); + usb_free_urb (urb); + return; + } + skb_reserve (skb, (dev->driver_info->flags & FLAG_FRAMING) ? 12 : 2); + + entry = (struct skb_data *) skb->cb; + entry->urb = urb; + entry->dev = dev; + entry->state = rx_start; + entry->length = 0; + + FILL_BULK_URB (urb, dev->udev, + usb_rcvbulkpipe (dev->udev, dev->driver_info->in), + skb->data, size, rx_complete, skb); +#ifdef REALLY_QUEUE + urb->transfer_flags |= USB_QUEUE_BULK; +#endif + + spin_lock_irqsave (&dev->rxq.lock, lockflags); + + if (netif_running (&dev->net)) { + if ((retval = usb_submit_urb (urb)) != 0) { + dbg ("%s rx submit, %d", dev->net.name, retval); + tasklet_schedule (&dev->bh); + } else { + __skb_queue_tail (&dev->rxq, skb); + } + } else { + dbg ("rx: stopped"); + retval = -ENOLINK; + } + spin_unlock_irqrestore (&dev->rxq.lock, lockflags); + if (retval) { + dev_kfree_skb_any (skb); + usb_free_urb (urb); + } +} + + +/*-------------------------------------------------------------------------*/ + +static inline void rx_process (struct usbnet *dev, struct sk_buff *skb) +{ + if (dev->driver_info->flags & FLAG_FRAMING) { + struct nc_header *header; + struct nc_trailer *trailer; + + if (!(skb->len & 0x01) + || MIN_FRAMED > skb->len + || skb->len > FRAMED_SIZE (dev->net.mtu)) { + dev->stats.rx_frame_errors++; + dbg ("rx framesize %d range %d..%d mtu %d", skb->len, + MIN_FRAMED, FRAMED_SIZE (dev->net.mtu), + dev->net.mtu + ); + goto error; + } + + header = (struct nc_header *) skb->data; + le16_to_cpus (&header->hdr_len); + le16_to_cpus (&header->packet_len); + if (FRAMED_SIZE (header->packet_len) > MAX_PACKET) { + dev->stats.rx_frame_errors++; + dbg ("packet too big, %d", header->packet_len); + goto error; + } else if (header->hdr_len < MIN_HEADER) { + dev->stats.rx_frame_errors++; + dbg ("header too short, %d", header->hdr_len); + goto error; + } else if (header->hdr_len > MIN_HEADER) { + // out of band data for us? + dbg ("header OOB, %d bytes", + header->hdr_len - MIN_HEADER); + // switch (vendor/product ids) { ... } + } + skb_pull (skb, header->hdr_len); + + trailer = (struct nc_trailer *) + (skb->data + skb->len - sizeof *trailer); + skb_trim (skb, skb->len - sizeof *trailer); + + if ((header->packet_len & 0x01) == 0) { + if (skb->data [header->packet_len] != PAD_BYTE) { + dev->stats.rx_frame_errors++; + dbg ("bad pad"); + goto error; + } + skb_trim (skb, skb->len - 1); + } + if (skb->len != header->packet_len) { + dev->stats.rx_frame_errors++; + dbg ("bad packet len %d (expected %d)", + skb->len, header->packet_len); + goto error; + } + if (header->packet_id != get_unaligned (&trailer->packet_id)) { + dev->stats.rx_fifo_errors++; + dbg ("(2+ dropped) rx packet_id mismatch 0x%x 0x%x", + header->packet_id, trailer->packet_id); + goto error; + } +#if 0 + devdbg (dev, "frame <rx h %d p %d id %d", header->hdr_len, + header->packet_len, header->packet_id); +#endif + } else { + // we trust the network stack to remove + // the extra byte we may have appended + } + + if (skb->len) { + int status; + +// FIXME: eth_copy_and_csum "small" packets to new SKB (small < ~200 bytes) ? + + skb->dev = &dev->net; + skb->protocol = eth_type_trans (skb, &dev->net); + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + +#ifdef VERBOSE + devdbg (dev, "< rx, len %d, type 0x%x", + skb->len + sizeof (struct ethhdr), skb->protocol); +#endif + memset (skb->cb,0,sizeof(struct skb_data)); + status = netif_rx (skb); + if (status != NET_RX_SUCCESS) + devdbg (dev, "netif_rx status %d", status); + } else { + dbg ("drop"); +error: + dev->stats.rx_errors++; + skb_queue_tail (&dev->done, skb); + } +} + +/*-------------------------------------------------------------------------*/ + +static void rx_complete (struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct skb_data *entry = (struct skb_data *) skb->cb; + struct usbnet *dev = entry->dev; + int urb_status = urb->status; + + skb_put (skb, urb->actual_length); + entry->state = rx_done; + entry->urb = 0; + + if ((urb->transfer_flags & USB_ASYNC_UNLINK) != 0) { + dbg ("rx ... shutting down"); + usb_free_urb (urb); + urb = 0; + } + + switch (urb_status) { + // success + case 0: + if (MIN_PACKET > skb->len || skb->len > MAX_PACKET) { + entry->state = rx_cleanup; + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; + dbg ("rx length %d", skb->len); + } + break; + + // software-driven interface shutdown + case -ECONNRESET: // usb-ohci, usb-uhci + case -ECONNABORTED: // uhci ... for usb-uhci, INTR + dbg ("%s shutdown, code %d", dev->net.name, urb_status); + entry->state = rx_cleanup; + usb_free_urb (urb); + urb = 0; + break; + + // data overrun ... flush fifo? + case -EOVERFLOW: + dev->stats.rx_over_errors++; + // FALLTHROUGH + + default: + // on unplug we'll get a burst of ETIMEDOUT/EILSEQ + // till the khubd gets and handles its interrupt. + entry->state = rx_cleanup; + dev->stats.rx_errors++; + dbg ("%s rx: status %d", dev->net.name, urb_status); + break; + } + + defer_bh (dev, skb); + + if (urb) { + if (netif_running (&dev->net)) { + rx_submit (dev, urb, GFP_ATOMIC); + return; + } else + usb_free_urb (urb); + } +#ifdef VERBOSE + dbg ("no read resubmitted"); +#endif /* VERBOSE */ +} + +/*-------------------------------------------------------------------------*/ + +// unlink pending rx/tx; completion handlers do all other cleanup + +static int unlink_urbs (struct sk_buff_head *q) +{ + unsigned long flags; + struct sk_buff *skb, *skbnext; + int count = 0; + + spin_lock_irqsave (&q->lock, flags); + for (skb = q->next; skb != (struct sk_buff *) q; skb = skbnext) { + struct skb_data *entry; + struct urb *urb; + int retval; + + entry = (struct skb_data *) skb->cb; + urb = entry->urb; + skbnext = skb->next; + + // during some PM-driven resume scenarios, + // these unlinks complete immediately + urb->transfer_flags |= USB_ASYNC_UNLINK; + retval = usb_unlink_urb (urb); + if (retval < 0) + dbg ("unlink urb err, %d", retval); + else + count++; + } + spin_unlock_irqrestore (&q->lock, flags); + return count; +} + + +/*-------------------------------------------------------------------------*/ + +// precondition: never called in_interrupt + +static int usbnet_stop (struct net_device *net) +{ + struct usbnet *dev = (struct usbnet *) net->priv; + int temp; + DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); + DECLARE_WAITQUEUE (wait, current); + + mutex_lock (&dev->mutex); + netif_stop_queue(net); + + devdbg (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld", + dev->stats.rx_packets, dev->stats.tx_packets, + dev->stats.rx_errors, dev->stats.tx_errors + ); + + // ensure there are no more active urbs + add_wait_queue (&unlink_wakeup, &wait); + dev->wait = &unlink_wakeup; + temp = unlink_urbs (&dev->txq) + unlink_urbs (&dev->rxq); + + // maybe wait for deletions to finish. + while (skb_queue_len (&dev->rxq) + && skb_queue_len (&dev->done) + && skb_queue_len (&dev->txq)) { + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout (UNLINK_TIMEOUT_JIFFIES); + dbg ("waited for %d urb completions", temp); + } + dev->wait = 0; + remove_wait_queue (&unlink_wakeup, &wait); + + mutex_unlock (&dev->mutex); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +// posts reads, and enables write queing + +// precondition: never called in_interrupt + +static int usbnet_open (struct net_device *net) +{ + struct usbnet *dev = (struct usbnet *) net->priv; + int retval = 0; + struct driver_info *info = dev->driver_info; + + mutex_lock (&dev->mutex); + + // put into "known safe" state + if (info->reset && (retval = info->reset (dev)) < 0) { + devinfo (dev, "open reset fail (%d) usbnet %03d/%03d, %s", + retval, + dev->udev->bus->busnum, dev->udev->devnum, + info->description); + goto done; + } + + // insist peer be connected + if (info->check_connect && (retval = info->check_connect (dev)) < 0) { + devdbg (dev, "can't open; %d", retval); + goto done; + } + + netif_start_queue (net); + devdbg (dev, "open: enable queueing (rx %d, tx %d) mtu %d %sframed", + RX_QLEN, TX_QLEN, dev->net.mtu, + (info->flags & FLAG_FRAMING) ? "" : "un" + ); + + // delay posting reads until we're fully open + tasklet_schedule (&dev->bh); +done: + mutex_unlock (&dev->mutex); + return retval; +} + +/*-------------------------------------------------------------------------*/ + +/* usb_clear_halt cannot be called in interrupt context */ + +static void +tx_clear_halt(void *data) +{ + struct usbnet *dev = data; + + usb_clear_halt (dev->udev, + usb_sndbulkpipe (dev->udev, dev->driver_info->out)); + netif_wake_queue (&dev->net); +} + +/*-------------------------------------------------------------------------*/ + +static void tx_complete (struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct skb_data *entry = (struct skb_data *) skb->cb; + struct usbnet *dev = entry->dev; + + if (urb->status == USB_ST_STALL) { + if (dev->ctrl_task.sync == 0) { + dev->ctrl_task.routine = tx_clear_halt; + dev->ctrl_task.data = dev; + schedule_task(&dev->ctrl_task); + } else { + dbg ("Cannot clear TX stall"); + } + } + urb->dev = 0; + entry->state = tx_done; + defer_bh (dev, skb); +} + +/*-------------------------------------------------------------------------*/ + +static void usbnet_tx_timeout (struct net_device *net) +{ + struct usbnet *dev = (struct usbnet *) net->priv; + + unlink_urbs (&dev->txq); + tasklet_schedule (&dev->bh); + + // FIXME: device recovery -- reset? +} + +/*-------------------------------------------------------------------------*/ + +static inline struct sk_buff *fixup_skb (struct sk_buff *skb, int flags) +{ + int padlen; + struct sk_buff *skb2; + + padlen = ((skb->len + sizeof (struct nc_header) + + sizeof (struct nc_trailer)) & 0x01) ? 0 : 1; + if (!skb_cloned (skb)) { + int headroom = skb_headroom (skb); + int tailroom = skb_tailroom (skb); + + if ((padlen + sizeof (struct nc_trailer)) <= tailroom + && sizeof (struct nc_header) <= headroom) + return skb; + + if ((sizeof (struct nc_header) + padlen + + sizeof (struct nc_trailer)) < + (headroom + tailroom)) { + skb->data = memmove (skb->head + + sizeof (struct nc_header), + skb->data, skb->len); + skb->tail = skb->data + skb->len; + return skb; + } + } + skb2 = skb_copy_expand (skb, + sizeof (struct nc_header), + sizeof (struct nc_trailer) + padlen, + flags); + dev_kfree_skb_any (skb); + return skb2; +} + +/*-------------------------------------------------------------------------*/ + +static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) +{ + struct usbnet *dev = (struct usbnet *) net->priv; + int length = skb->len; + int retval = NET_XMIT_SUCCESS; + struct urb *urb = 0; + struct skb_data *entry; + struct nc_header *header = 0; + struct nc_trailer *trailer = 0; + struct driver_info *info = dev->driver_info; + int flags; + + flags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL; + + if (info->flags & FLAG_FRAMING) { + struct sk_buff *skb2; + skb2 = fixup_skb (skb, flags); + if (!skb2) { + dbg ("can't fixup skb"); + goto drop; + } + skb = skb2; + } + + if (!(urb = usb_alloc_urb (0))) { + dbg ("no urb"); + goto drop; + } + + entry = (struct skb_data *) skb->cb; + entry->urb = urb; + entry->dev = dev; + entry->state = tx_start; + entry->length = length; + + if (info->flags & FLAG_FRAMING) { + header = (struct nc_header *) skb_push (skb, sizeof *header); + header->hdr_len = cpu_to_le16 (sizeof (*header)); + header->packet_len = cpu_to_le16 (length); + if (!((skb->len + sizeof *trailer) & 0x01)) + *skb_put (skb, 1) = PAD_BYTE; + trailer = (struct nc_trailer *) skb_put (skb, sizeof *trailer); + } else if ((length % EP_SIZE (dev)) == 0) { + if (skb_shared (skb)) { + struct sk_buff *skb2; + skb2 = skb_unshare (skb, flags); + if (!skb2) { + usb_free_urb (urb); + dbg ("can't unshare skb"); + goto drop; + } + skb = skb2; + } + skb->len++; + } + + FILL_BULK_URB (urb, dev->udev, + usb_sndbulkpipe (dev->udev, info->out), + skb->data, skb->len, tx_complete, skb); +#ifdef REALLY_QUEUE + urb->transfer_flags |= USB_QUEUE_BULK; +#endif + // FIXME urb->timeout = ... jiffies ... ; + + spin_lock_irqsave (&dev->txq.lock, flags); + if (info->flags & FLAG_FRAMING) { + header->packet_id = cpu_to_le16 (dev->packet_id++); + put_unaligned (header->packet_id, &trailer->packet_id); +#if 0 + devdbg (dev, "frame >tx h %d p %d id %d", + header->hdr_len, header->packet_len, + header->packet_id); +#endif + } + + netif_stop_queue (net); + if ((retval = usb_submit_urb (urb)) != 0) { + netif_start_queue (net); + dbg ("%s tx: submit urb err %d", net->name, retval); + } else { + net->trans_start = jiffies; + __skb_queue_tail (&dev->txq, skb); + if (dev->txq.qlen < TX_QLEN) + netif_start_queue (net); + } + spin_unlock_irqrestore (&dev->txq.lock, flags); + + if (retval) { + devdbg (dev, "drop, code %d", retval); +drop: + retval = NET_XMIT_DROP; + dev->stats.tx_dropped++; + dev_kfree_skb_any (skb); + usb_free_urb (urb); +#ifdef VERBOSE + } else { + devdbg (dev, "> tx, len %d, type 0x%x", + length, skb->protocol); +#endif + } + return retval; +} + + +/*-------------------------------------------------------------------------*/ + +// tasklet ... work that avoided running in_irq() + +static void usbnet_bh (unsigned long param) +{ + struct usbnet *dev = (struct usbnet *) param; + struct sk_buff *skb; + struct skb_data *entry; + + while ((skb = skb_dequeue (&dev->done))) { + entry = (struct skb_data *) skb->cb; + switch (entry->state) { + case rx_done: + entry->state = rx_cleanup; + rx_process (dev, skb); + continue; + case tx_done: + if (entry->urb->status) { + // can this statistic become more specific? + dev->stats.tx_errors++; + dbg ("%s tx: err %d", dev->net.name, + entry->urb->status); + } else { + dev->stats.tx_packets++; + dev->stats.tx_bytes += entry->length; + } + // FALLTHROUGH: + case rx_cleanup: + usb_free_urb (entry->urb); + dev_kfree_skb (skb); + continue; + default: + dbg ("%s: bogus skb state %d", + dev->net.name, entry->state); + } + } + + // waiting for all pending urbs to complete? + if (dev->wait) { + if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) { + wake_up (dev->wait); + } + + // or are we maybe short a few urbs? + } else if (netif_running (&dev->net)) { + int temp = dev->rxq.qlen; + + if (temp < RX_QLEN) { + struct urb *urb; + int i; + for (i = 0; i < 3 && dev->rxq.qlen < RX_QLEN; i++) { + if ((urb = usb_alloc_urb (0)) != 0) + rx_submit (dev, urb, GFP_ATOMIC); + } + if (temp != dev->rxq.qlen) + devdbg (dev, "rxqlen %d --> %d", + temp, dev->rxq.qlen); + if (dev->rxq.qlen < RX_QLEN) + tasklet_schedule (&dev->bh); + } + if (dev->txq.qlen < TX_QLEN) + netif_wake_queue (&dev->net); + } +} + + + +/*------------------------------------------------------------------------- + * + * USB Device Driver support + * + *-------------------------------------------------------------------------*/ + +// precondition: never called in_interrupt + +static void usbnet_disconnect (struct usb_device *udev, void *ptr) +{ + struct usbnet *dev = (struct usbnet *) ptr; + + devinfo (dev, "unregister usbnet %03d/%03d, %s", + udev->bus->busnum, udev->devnum, + dev->driver_info->description); + + unregister_netdev (&dev->net); + + mutex_lock (&usbnet_mutex); + mutex_lock (&dev->mutex); + list_del (&dev->dev_list); + mutex_unlock (&usbnet_mutex); + + kfree (dev); + usb_dec_dev_use (udev); +} + + +/*-------------------------------------------------------------------------*/ + +// precondition: never called in_interrupt + +static void * +usbnet_probe (struct usb_device *udev, unsigned ifnum, + const struct usb_device_id *prod) +{ + struct usbnet *dev; + struct net_device *net; + struct usb_interface_descriptor *interface; + struct driver_info *info; + int altnum = 0; + + info = (struct driver_info *) prod->driver_info; + + // sanity check; expect dedicated interface/devices for now. + interface = &udev->actconfig->interface [ifnum].altsetting [altnum]; + if (udev->descriptor.bNumConfigurations != 1 + || udev->config[0].bNumInterfaces != 1 + || interface->bInterfaceClass != USB_CLASS_VENDOR_SPEC + ) { + dbg ("Bogus config info"); + return 0; + } + + if (usb_set_interface (udev, ifnum, altnum) < 0) { + err ("set_interface failed"); + return 0; + } + + // set up our own records + if (!(dev = kmalloc (sizeof *dev, GFP_KERNEL))) { + dbg ("can't kmalloc dev"); + return 0; + } + memset (dev, 0, sizeof *dev); + + init_MUTEX_LOCKED (&dev->mutex); + usb_inc_dev_use (udev); + dev->udev = udev; + dev->driver_info = info; + INIT_LIST_HEAD (&dev->dev_list); + skb_queue_head_init (&dev->rxq); + skb_queue_head_init (&dev->txq); + skb_queue_head_init (&dev->done); + dev->bh.func = usbnet_bh; + dev->bh.data = (unsigned long) dev; + + // set up network interface records + net = &dev->net; + SET_MODULE_OWNER (net); + net->priv = dev; + strcpy (net->name, "usb%d"); + memcpy (net->dev_addr, node_id, sizeof node_id); + + // point-to-point link ... we always use Ethernet headers + // supports win32 interop and the bridge driver. + ether_setup (net); + + net->change_mtu = usbnet_change_mtu; + net->get_stats = usbnet_get_stats; + net->hard_start_xmit = usbnet_start_xmit; + net->open = usbnet_open; + net->stop = usbnet_stop; + net->watchdog_timeo = TX_TIMEOUT_JIFFIES; + net->tx_timeout = usbnet_tx_timeout; + + register_netdev (&dev->net); + devinfo (dev, "register usbnet %03d/%03d, %s", + udev->bus->busnum, udev->devnum, + dev->driver_info->description); + + // ok, it's ready to go. + mutex_lock (&usbnet_mutex); + list_add (&dev->dev_list, &usbnet_list); + mutex_unlock (&dev->mutex); + + // start as if the link is up + netif_device_attach (&dev->net); + + mutex_unlock (&usbnet_mutex); + return dev; +} + + +/*-------------------------------------------------------------------------*/ + +/* + * chip vendor names won't normally be on the cables, and + * may not be on the device. + */ + +static const struct usb_device_id products [] = { + +#ifdef CONFIG_USB_AN2720 +{ + USB_DEVICE (0x0547, 0x2720), // AnchorChips defaults + driver_info: (unsigned long) &an2720_info, +}, +#endif + + +// GeneSys GL620USB (www.genesyslogic.com.tw) +// (patch exists against an older driver version) + + +#ifdef CONFIG_USB_LINUXDEV +/* + * for example, this can be a host side talk-to-PDA driver. + * this driver is NOT what runs _inside_ a Linux device !! + */ +{ + // 1183 = 0x049F, both used as hex values? + USB_DEVICE (0x049F, 0x505A), // Compaq "Itsy" + driver_info: (unsigned long) &linuxdev_info, +}, +#endif + +#ifdef CONFIG_USB_NET1080 +{ + USB_DEVICE (0x0525, 0x1080), // NetChip ref design + driver_info: (unsigned long) &net1080_info, +}, { + USB_DEVICE (0x050d, 0x0004), // Belkin + driver_info: (unsigned long) &net1080_info, +}, { + USB_DEVICE (0x056c, 0x8100), // eTEK + driver_info: (unsigned long) &net1080_info, +}, +#endif + +#ifdef CONFIG_USB_PL2301 +{ + USB_DEVICE (0x067b, 0x0000), // PL-2301 + driver_info: (unsigned long) &prolific_info, +}, { + USB_DEVICE (0x067b, 0x0001), // PL-2302 + driver_info: (unsigned long) &prolific_info, +}, +#endif + + { }, // END +}; +MODULE_DEVICE_TABLE (usb, products); + +static struct usb_driver usbnet_driver = { + name: "usbnet", + id_table: products, + probe: usbnet_probe, + disconnect: usbnet_disconnect, +}; + +/*-------------------------------------------------------------------------*/ + +static int __init usbnet_init (void) +{ + // compiler should optimize this out + if (sizeof (((struct sk_buff *)0)->cb) < sizeof (struct skb_data)) + BUG (); + + get_random_bytes (node_id, sizeof node_id); + node_id [0] &= 0xfe; // clear multicast bit + + if (usb_register (&usbnet_driver) < 0) + return -1; + + return 0; +} +module_init (usbnet_init); + +static void __exit usbnet_exit (void) +{ + usb_deregister (&usbnet_driver); +} +module_exit (usbnet_exit); + +MODULE_AUTHOR ("David Brownell <dbrownell@users.sourceforge.net>"); +MODULE_DESCRIPTION ("USB Host-to-Host Link Drivers (Linux, NetChip, Prolific, ...)"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usbvideo.c linux.ac/drivers/usb/usbvideo.c --- linux.vanilla/drivers/usb/usbvideo.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/usb/usbvideo.c Tue Apr 3 17:55:08 2001 @@ -0,0 +1,2468 @@ +/* + * 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. + */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/list.h> +#include <linux/malloc.h> +#define __NO_VERSION__ /* Temporary: usbvideo is not a module yet */ +#include <linux/module.h> +#include <linux/mm.h> +#include <linux/smp_lock.h> +#include <linux/vmalloc.h> +#include <linux/wrapper.h> +#include <linux/init.h> +#include <linux/spinlock.h> + +#include <asm/io.h> + +#include "usbvideo.h" + +#if defined(MAP_NR) +#define virt_to_page(v) MAP_NR(v) /* Kernels 2.2.x */ +#endif + +/* + * Local prototypes. + */ +#if USES_PROC_FS +static void usbvideo_procfs_level1_create(usbvideo_t *ut); +static void usbvideo_procfs_level1_destroy(usbvideo_t *ut); +static void usbvideo_procfs_level2_create(uvd_t *uvd); +static void usbvideo_procfs_level2_destroy(uvd_t *uvd); +static int usbvideo_default_procfs_read_proc( + char *page, char **start, off_t off, int count, + int *eof, void *data); +static int usbvideo_default_procfs_write_proc( + struct file *file, const char *buffer, + unsigned long count, void *data); +#endif + +/*******************************/ +/* Memory management functions */ +/*******************************/ + +#define MDEBUG(x) do { } while(0) /* Debug memory management */ + +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. + */ +unsigned long usbvideo_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 = (unsigned long) page_address(pte_page(pte)); + ret |= (adr & (PAGE_SIZE-1)); + } + } + } + MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); + return ret; +} + +unsigned long usbvideo_uvirt_to_bus(unsigned long adr) +{ + unsigned long kva, ret; + + kva = usbvideo_uvirt_to_kva(pgd_offset(current->mm, adr), adr); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); + return ret; +} + +unsigned long usbvideo_kvirt_to_bus(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = usbvideo_uvirt_to_kva(pgd_offset_k(va), va); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); + 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. + */ +unsigned long usbvideo_kvirt_to_pa(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = usbvideo_uvirt_to_kva(pgd_offset_k(va), va); + ret = __pa(kva); + MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); + return ret; +} + +void *usbvideo_rvmalloc(unsigned long size) +{ + void *mem; + unsigned long adr, page; + + /* Round it off to PAGE_SIZE */ + size += (PAGE_SIZE - 1); + size &= ~(PAGE_SIZE - 1); + + mem = vmalloc_32(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 = usbvideo_kvirt_to_pa(adr); + mem_map_reserve(virt_to_page(__va(page))); + adr += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + return mem; +} + +void usbvideo_rvfree(void *mem, unsigned long size) +{ + unsigned long adr, page; + + if (!mem) + return; + + size += (PAGE_SIZE - 1); + size &= ~(PAGE_SIZE - 1); + + adr=(unsigned long) mem; + while (size > 0) { + page = usbvideo_kvirt_to_pa(adr); + mem_map_unreserve(virt_to_page(__va(page))); + adr += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + vfree(mem); +} + +void RingQueue_Initialize(RingQueue_t *rq) +{ + assert(rq != NULL); + init_waitqueue_head(&rq->wqh); +} + +void RingQueue_Allocate(RingQueue_t *rq, int rqLen) +{ + assert(rq != NULL); + assert(rqLen > 0); + rq->length = rqLen; + rq->queue = usbvideo_rvmalloc(rq->length); + assert(rq->queue != NULL); +} + +int RingQueue_IsAllocated(const RingQueue_t *rq) +{ + if (rq == NULL) + return 0; + return (rq->queue != NULL) && (rq->length > 0); +} + +void RingQueue_Free(RingQueue_t *rq) +{ + assert(rq != NULL); + if (RingQueue_IsAllocated(rq)) { + usbvideo_rvfree(rq->queue, rq->length); + rq->queue = NULL; + rq->length = 0; + } +} + +int RingQueue_Dequeue(RingQueue_t *rq, unsigned char *dst, int len) +{ + int i; + assert(rq != NULL); + assert(dst != NULL); + for (i=0; i < len; i++) { + dst[i] = rq->queue[rq->ri]; + RING_QUEUE_DEQUEUE_BYTES(rq,1); + } + return len; +} + +int RingQueue_Enqueue(RingQueue_t *rq, const unsigned char *cdata, int n) +{ + int enqueued = 0; + + assert(rq != NULL); + assert(cdata != NULL); + assert(rq->length > 0); + while (n > 0) { + int m, q_avail; + + /* Calculate the largest chunk that fits the tail of the ring */ + q_avail = rq->length - rq->wi; + if (q_avail <= 0) { + rq->wi = 0; + q_avail = rq->length; + } + m = n; + assert(q_avail > 0); + if (m > q_avail) + m = q_avail; + + memmove(rq->queue + rq->wi, cdata, m); + RING_QUEUE_ADVANCE_INDEX(rq, wi, m); + cdata += m; + enqueued += m; + n -= m; + } + return enqueued; +} + +int RingQueue_GetLength(const RingQueue_t *rq) +{ + int ri, wi; + + assert(rq != NULL); + + ri = rq->ri; + wi = rq->wi; + if (ri == wi) + return 0; + else if (ri < wi) + return wi - ri; + else + return wi + (rq->length - ri); +} + +void RingQueue_InterruptibleSleepOn(RingQueue_t *rq) +{ + assert(rq != NULL); + interruptible_sleep_on(&rq->wqh); +} + +void RingQueue_WakeUpInterruptible(RingQueue_t *rq) +{ + assert(rq != NULL); + if (waitqueue_active(&rq->wqh)) + wake_up_interruptible(&rq->wqh); +} + +/* + * usbvideo_VideosizeToString() + * + * This procedure converts given videosize value to readable string. + * + * History: + * 07-Aug-2000 Created. + * 19-Oct-2000 Reworked for usbvideo module. + */ +void usbvideo_VideosizeToString(char *buf, int bufLen, videosize_t vs) +{ + char tmp[40]; + int n; + + n = 1 + sprintf(tmp, "%ldx%ld", VIDEOSIZE_X(vs), VIDEOSIZE_Y(vs)); + assert(n < sizeof(tmp)); + if ((buf == NULL) || (bufLen < n)) + err("usbvideo_VideosizeToString: buffer is too small."); + else + memmove(buf, tmp, n); +} + +/* + * usbvideo_OverlayChar() + * + * History: + * 01-Feb-2000 Created. + */ +void usbvideo_OverlayChar(uvd_t *uvd, usbvideo_frame_t *frame, + int x, int y, int ch) +{ + static const unsigned short digits[16] = { + 0xF6DE, /* 0 */ + 0x2492, /* 1 */ + 0xE7CE, /* 2 */ + 0xE79E, /* 3 */ + 0xB792, /* 4 */ + 0xF39E, /* 5 */ + 0xF3DE, /* 6 */ + 0xF492, /* 7 */ + 0xF7DE, /* 8 */ + 0xF79E, /* 9 */ + 0x77DA, /* a */ + 0xD75C, /* b */ + 0xF24E, /* c */ + 0xD6DC, /* d */ + 0xF34E, /* e */ + 0xF348 /* f */ + }; + unsigned short digit; + int ix, iy; + + if ((uvd == NULL) || (frame == NULL)) + return; + + if (ch >= '0' && ch <= '9') + ch -= '0'; + else if (ch >= 'A' && ch <= 'F') + ch = 10 + (ch - 'A'); + else if (ch >= 'a' && ch <= 'f') + ch = 10 + (ch - 'a'); + else + return; + digit = digits[ch]; + + for (iy=0; iy < 5; iy++) { + for (ix=0; ix < 3; ix++) { + if (digit & 0x8000) { + if (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24)) { +/* TODO */ RGB24_PUTPIXEL(frame, x+ix, y+iy, 0xFF, 0xFF, 0xFF); + } + } + digit = digit << 1; + } + } +} + +/* + * usbvideo_OverlayString() + * + * History: + * 01-Feb-2000 Created. + */ +void usbvideo_OverlayString(uvd_t *uvd, usbvideo_frame_t *frame, + int x, int y, const char *str) +{ + while (*str) { + usbvideo_OverlayChar(uvd, frame, x, y, *str); + str++; + x += 4; /* 3 pixels character + 1 space */ + } +} + +/* + * usbvideo_OverlayStats() + * + * Overlays important debugging information. + * + * History: + * 01-Feb-2000 Created. + */ +void usbvideo_OverlayStats(uvd_t *uvd, usbvideo_frame_t *frame) +{ + const int y_diff = 8; + char tmp[16]; + int x = 10, y=10; + long i, j, barLength; + const int qi_x1 = 60, qi_y1 = 10; + const int qi_x2 = VIDEOSIZE_X(frame->request) - 10, qi_h = 10; + + /* Call the user callback, see if we may proceed after that */ + if (VALID_CALLBACK(uvd, overlayHook)) { + if (GET_CALLBACK(uvd, overlayHook)(uvd, frame) < 0) + return; + } + + /* + * We draw a (mostly) hollow rectangle with qi_xxx coordinates. + * Left edge symbolizes the queue index 0; right edge symbolizes + * the full capacity of the queue. + */ + barLength = qi_x2 - qi_x1 - 2; + if ((barLength > 10) && (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24))) { +/* TODO */ long u_lo, u_hi, q_used; + long m_ri, m_wi, m_lo, m_hi; + + /* + * Determine fill zones (used areas of the queue): + * 0 xxxxxxx u_lo ...... uvd->dp.ri xxxxxxxx u_hi ..... uvd->dp.length + * + * if u_lo < 0 then there is no first filler. + */ + + q_used = RingQueue_GetLength(&uvd->dp); + if ((uvd->dp.ri + q_used) >= uvd->dp.length) { + u_hi = uvd->dp.length; + u_lo = (q_used + uvd->dp.ri) % uvd->dp.length; + } else { + u_hi = (q_used + uvd->dp.ri); + u_lo = -1; + } + + /* Convert byte indices into screen units */ + m_ri = qi_x1 + ((barLength * uvd->dp.ri) / uvd->dp.length); + m_wi = qi_x1 + ((barLength * uvd->dp.wi) / uvd->dp.length); + m_lo = (u_lo > 0) ? (qi_x1 + ((barLength * u_lo) / uvd->dp.length)) : -1; + m_hi = qi_x1 + ((barLength * u_hi) / uvd->dp.length); + + for (j=qi_y1; j < (qi_y1 + qi_h); j++) { + for (i=qi_x1; i < qi_x2; i++) { + /* Draw border lines */ + if ((j == qi_y1) || (j == (qi_y1 + qi_h - 1)) || + (i == qi_x1) || (i == (qi_x2 - 1))) { + RGB24_PUTPIXEL(frame, i, j, 0xFF, 0xFF, 0xFF); + continue; + } + /* For all other points the Y coordinate does not matter */ + if ((i >= m_ri) && (i <= (m_ri + 3))) { + RGB24_PUTPIXEL(frame, i, j, 0x00, 0xFF, 0x00); + } else if ((i >= m_wi) && (i <= (m_wi + 3))) { + RGB24_PUTPIXEL(frame, i, j, 0xFF, 0x00, 0x00); + } else if ((i < m_lo) || ((i > m_ri) && (i < m_hi))) + RGB24_PUTPIXEL(frame, i, j, 0x00, 0x00, 0xFF); + } + } + } + + sprintf(tmp, "%8lx", uvd->stats.frame_num); + usbvideo_OverlayString(uvd, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8lx", uvd->stats.urb_count); + usbvideo_OverlayString(uvd, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8lx", uvd->stats.urb_length); + usbvideo_OverlayString(uvd, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8lx", uvd->stats.data_count); + usbvideo_OverlayString(uvd, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8lx", uvd->stats.header_count); + usbvideo_OverlayString(uvd, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8lx", uvd->stats.iso_skip_count); + usbvideo_OverlayString(uvd, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8lx", uvd->stats.iso_err_count); + usbvideo_OverlayString(uvd, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8x", uvd->vpic.colour); + usbvideo_OverlayString(uvd, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8x", uvd->vpic.hue); + usbvideo_OverlayString(uvd, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8x", uvd->vpic.brightness >> 8); + usbvideo_OverlayString(uvd, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8x", uvd->vpic.contrast >> 12); + usbvideo_OverlayString(uvd, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8d", uvd->vpic.whiteness >> 8); + usbvideo_OverlayString(uvd, frame, x, y, tmp); + y += y_diff; +} + +/* + * usbvideo_ReportStatistics() + * + * This procedure prints packet and transfer statistics. + * + * History: + * 14-Jan-2000 Corrected default multiplier. + */ +void usbvideo_ReportStatistics(const uvd_t *uvd) +{ + if ((uvd != NULL) && (uvd->stats.urb_count > 0)) { + unsigned long allPackets, badPackets, goodPackets, percent; + allPackets = uvd->stats.urb_count * CAMERA_URB_FRAMES; + badPackets = uvd->stats.iso_skip_count + uvd->stats.iso_err_count; + goodPackets = allPackets - badPackets; + /* Calculate percentage wisely, remember integer limits */ + assert(allPackets != 0); + if (goodPackets < (((unsigned long)-1)/100)) + percent = (100 * goodPackets) / allPackets; + else + percent = goodPackets / (allPackets / 100); + info("Packet Statistics: Total=%lu. Empty=%lu. Usage=%lu%%", + allPackets, badPackets, percent); + if (uvd->iso_packet_len > 0) { + unsigned long allBytes, xferBytes; + char multiplier = ' '; + allBytes = allPackets * uvd->iso_packet_len; + xferBytes = uvd->stats.data_count; + assert(allBytes != 0); + if (xferBytes < (((unsigned long)-1)/100)) + percent = (100 * xferBytes) / allBytes; + else + percent = xferBytes / (allBytes / 100); + /* Scale xferBytes for easy reading */ + if (xferBytes > 10*1024) { + xferBytes /= 1024; + multiplier = 'K'; + if (xferBytes > 10*1024) { + xferBytes /= 1024; + multiplier = 'M'; + if (xferBytes > 10*1024) { + xferBytes /= 1024; + multiplier = 'G'; + if (xferBytes > 10*1024) { + xferBytes /= 1024; + multiplier = 'T'; + } + } + } + } + info("Transfer Statistics: Transferred=%lu%cB Usage=%lu%%", + xferBytes, multiplier, percent); + } + } +} + +/* + * usbvideo_DrawLine() + * + * A standard implementation of Bresenham's line drawing algorithm. + * This procedure is provided primarily for debugging or demo + * purposes. + */ +void usbvideo_DrawLine( + usbvideo_frame_t *frame, + int x1, int y1, + int x2, int y2, + unsigned char cr, unsigned char cg, unsigned char cb) +{ + int i, dx, dy, np, d; + int dinc1, dinc2, x, xinc1, xinc2, y, yinc1, yinc2; + + if ((dx = x2 - x1) < 0) + dx = -dx; + if ((dy = y2 - y1) < 0) + dy = -dy; + if (dx >= dy) { + np = dx + 1; + d = (2 * dy) - dx; + dinc1 = dy << 1; + dinc2 = (dy - dx) << 1; + xinc1 = 1; + xinc2 = 1; + yinc1 = 0; + yinc2 = 1; + } else { + np = dy + 1; + d = (2 * dx) - dy; + dinc1 = dx << 1; + dinc2 = (dx - dy) << 1; + xinc1 = 0; + xinc2 = 1; + yinc1 = 1; + yinc2 = 1; + } + /* Make sure x and y move in the right directions */ + if (x1 > x2) { + xinc1 = -xinc1; + xinc2 = -xinc2; + } + if (y1 > y2) { + yinc1 = -yinc1; + yinc2 = -yinc2; + } + for (i=0, x=x1, y=y1; i < np; i++) { + if (frame->palette == VIDEO_PALETTE_RGB24) { +/* TODO */ RGB24_PUTPIXEL(frame, x, y, cr, cg, cb); + } + if (d < 0) { + d += dinc1; + x += xinc1; + y += yinc1; + } else { + d += dinc2; + x += xinc2; + y += yinc2; + } + } +} + +/* + * usbvideo_TestPattern() + * + * Procedure forms a test pattern (yellow grid on blue background). + * + * Parameters: + * fullframe: if TRUE then entire frame is filled, otherwise the procedure + * continues from the current scanline. + * pmode 0: fill the frame with solid blue color (like on VCR or TV) + * 1: Draw a colored grid + * + * History: + * 01-Feb-2000 Created. + */ +void usbvideo_TestPattern(uvd_t *uvd, int fullframe, int pmode) +{ + static const char proc[] = "usbvideo_TestPattern"; + usbvideo_frame_t *frame; + int num_cell = 0; + int scan_length = 0; + static int num_pass = 0; + + if (uvd == NULL) { + err("%s: uvd == NULL", proc); + return; + } + if ((uvd->curframe < 0) || (uvd->curframe >= USBVIDEO_NUMFRAMES)) { + err("%s: uvd->curframe=%d.", proc, uvd->curframe); + return; + } + + /* Grab the current frame */ + frame = &uvd->frame[uvd->curframe]; + + /* Optionally start at the beginning */ + if (fullframe) { + frame->curline = 0; + frame->seqRead_Length = 0; + } +#if 0 + { /* For debugging purposes only */ + char tmp[20]; + usbvideo_VideosizeToString(tmp, sizeof(tmp), frame->request); + info("testpattern: frame=%s", tmp); + } +#endif + /* Form every scan line */ + for (; frame->curline < VIDEOSIZE_Y(frame->request); frame->curline++) { + int i; + unsigned char *f = frame->data + + (VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL * frame->curline); + for (i=0; i < VIDEOSIZE_X(frame->request); i++) { + unsigned char cb=0x80; + unsigned char cg = 0; + unsigned char cr = 0; + + if (pmode == 1) { + if (frame->curline % 32 == 0) + cb = 0, cg = cr = 0xFF; + else if (i % 32 == 0) { + if (frame->curline % 32 == 1) + num_cell++; + cb = 0, cg = cr = 0xFF; + } else { + cb = ((num_cell*7) + num_pass) & 0xFF; + cg = ((num_cell*5) + num_pass*2) & 0xFF; + cr = ((num_cell*3) + num_pass*3) & 0xFF; + } + } else { + /* Just the blue screen */ + } + + *f++ = cb; + *f++ = cg; + *f++ = cr; + scan_length += 3; + } + } + + frame->frameState = FrameState_Done; + frame->seqRead_Length += scan_length; + ++num_pass; + + /* We do this unconditionally, regardless of FLAGS_OVERLAY_STATS */ + usbvideo_OverlayStats(uvd, frame); +} + +/* + * usbvideo_HexDump() + * + * A debugging tool. Prints hex dumps. + * + * History: + * 29-Jul-2000 Added printing of offsets. + */ +void usbvideo_HexDump(const unsigned char *data, int len) +{ + const int bytes_per_line = 32; + char tmp[128]; /* 32*3 + 5 */ + int i, k; + + for (i=k=0; len > 0; i++, len--) { + if (i > 0 && ((i % bytes_per_line) == 0)) { + printk("%s\n", tmp); + k=0; + } + if ((i % bytes_per_line) == 0) + k += sprintf(&tmp[k], "%04x: ", i); + k += sprintf(&tmp[k], "%02x ", data[i]); + } + if (k > 0) + printk("%s\n", tmp); +} + +/* Debugging aid */ +void usbvideo_SayAndWait(const char *what) +{ + wait_queue_head_t wq; + init_waitqueue_head(&wq); + info("Say: %s", what); + interruptible_sleep_on_timeout (&wq, HZ*3); /* Timeout */ +} + +/* ******************************************************************** */ + +static void usbvideo_ClientIncModCount(uvd_t *uvd) +{ + static const char proc[] = "usbvideo_ClientIncModCount"; + if (uvd == NULL) { + err("%s: uvd == NULL", proc); + return; + } + if (uvd->handle == NULL) { + err("%s: uvd->handle == NULL", proc); + return; + } + if (uvd->handle->md_module == NULL) { + err("%s: uvd->handle->md_module == NULL", proc); + return; + } + __MOD_INC_USE_COUNT(uvd->handle->md_module); +} + +static void usbvideo_ClientDecModCount(uvd_t *uvd) +{ + static const char proc[] = "usbvideo_ClientDecModCount"; + if (uvd == NULL) { + err("%s: uvd == NULL", proc); + return; + } + if (uvd->handle == NULL) { + err("%s: uvd->handle == NULL", proc); + return; + } + if (uvd->handle->md_module == NULL) { + err("%s: uvd->handle->md_module == NULL", proc); + return; + } + __MOD_DEC_USE_COUNT(uvd->handle->md_module); +} + +int usbvideo_register( + usbvideo_t **pCams, + const int num_cams, + const int num_extra, + const char *driverName, + const usbvideo_cb_t *cbTbl, + struct module *md ) +{ + static const char proc[] = "usbvideo_register"; + usbvideo_t *cams; + int i, base_size; + + /* Check parameters for sanity */ + if ((num_cams <= 0) || (pCams == NULL) || (cbTbl == NULL)) { + err("%s: Illegal call", proc); + return -EINVAL; + } + + /* Check registration callback - must be set! */ + if (cbTbl->probe == NULL) { + err("%s: probe() is required!", proc); + return -EINVAL; + } + + base_size = num_cams * sizeof(uvd_t) + sizeof(usbvideo_t); + cams = (usbvideo_t *) kmalloc(base_size, GFP_KERNEL); + if (cams == NULL) { + err("Failed to allocate %d. bytes for usbvideo_t", base_size); + return -ENOMEM; + } + dbg("%s: Allocated $%p (%d. bytes) for %d. cameras", + proc, cams, base_size, num_cams); + memset(cams, 0, base_size); + + /* Copy callbacks, apply defaults for those that are not set */ + memmove(&cams->cb, cbTbl, sizeof(cams->cb)); + if (cams->cb.getFrame == NULL) + cams->cb.getFrame = usbvideo_GetFrame; + if (cams->cb.disconnect == NULL) + cams->cb.disconnect = usbvideo_Disconnect; +#if USES_PROC_FS + /* + * If both /proc fs callbacks are NULL then we assume that the driver + * does not need procfs services at all. Leave them NULL. + */ + cams->uses_procfs = (cams->cb.procfs_read != NULL) || (cams->cb.procfs_write == NULL); + if (cams->uses_procfs) { + if (cams->cb.procfs_read == NULL) + cams->cb.procfs_read = usbvideo_default_procfs_read_proc; + if (cams->cb.procfs_write == NULL) + cams->cb.procfs_write = usbvideo_default_procfs_write_proc; + } +#else /* !USES_PROC_FS */ + /* Report a warning so that user knows why there is no /proc entries */ + if ((cams->cb.procfs_read != NULL) || (cams->cb.procfs_write == NULL)) { + dbg("%s: /proc fs support requested but not configured!", proc); + } +#endif + cams->num_cameras = num_cams; + cams->cam = (uvd_t *) &cams[1]; + cams->md_module = md; + if (cams->md_module == NULL) + warn("%s: module == NULL!", proc); + init_MUTEX(&cams->lock); /* to 1 == available */ + + for (i = 0; i < num_cams; i++) { + uvd_t *up = &cams->cam[i]; + + up->handle = cams; + + /* Allocate user_data separately because of kmalloc's limits */ + if (num_extra > 0) { + up->user_size = num_cams * num_extra; + up->user_data = (char *) kmalloc(up->user_size, GFP_KERNEL); + if (up->user_data == NULL) { + up->user_size = 0; + err("%s: Failed to allocate user_data (%d. bytes)", + proc, up->user_size); + return -ENOMEM; + } + dbg("%s: Allocated cams[%d].user_data=$%p (%d. bytes)", + proc, i, up->user_data, up->user_size); + } + } + + /* + * Register ourselves with USB stack. + */ + strcpy(cams->drvName, (driverName != NULL) ? driverName : "Unknown"); + cams->usbdrv.name = cams->drvName; + cams->usbdrv.probe = cams->cb.probe; + cams->usbdrv.disconnect = cams->cb.disconnect; + +#if USES_PROC_FS + if (cams->uses_procfs) { + dbg("%s: Creating /proc filesystem entries.", proc); + usbvideo_procfs_level1_create(cams); + } +#endif + + /* + * Update global handle to usbvideo. This is very important + * because probe() can be called before usb_register() returns. + * If the handle is not yet updated then the probe() will fail. + */ + *pCams = cams; + usb_register(&cams->usbdrv); + + return 0; +} + +/* + * usbvideo_Deregister() + * + * Procedure frees all usbvideo and user data structures. Be warned that + * if you had some dynamically allocated components in ->user field then + * you should free them before calling here. + */ +void usbvideo_Deregister(usbvideo_t **pCams) +{ + static const char proc[] = "usbvideo_deregister"; + usbvideo_t *cams; + int i; + + if (pCams == NULL) { + err("%s: pCams == NULL", proc); + return; + } + cams = *pCams; + if (cams == NULL) { + err("%s: cams == NULL", proc); + return; + } + +#if USES_PROC_FS + if (cams->uses_procfs) { + dbg("%s: Deregistering filesystem entries.", proc); + usbvideo_procfs_level1_destroy(cams); + } +#endif + + dbg("%s: Deregistering %s driver.", proc, cams->drvName); + usb_deregister(&cams->usbdrv); + + dbg("%s: Deallocating cams=$%p (%d. cameras)", proc, cams, cams->num_cameras); + for (i=0; i < cams->num_cameras; i++) { + uvd_t *up = &cams->cam[i]; + int warning = 0; + + if (up->user_data != NULL) { + if (up->user_size <= 0) + ++warning; + } else { + if (up->user_size > 0) + ++warning; + } + if (warning) { + err("%s: Warning: user_data=$%p user_size=%d.", + proc, up->user_data, up->user_size); + } else { + dbg("%s: Freeing %d. $%p->user_data=$%p", + proc, i, up, up->user_data); + kfree(up->user_data); + } + } + /* Whole array was allocated in one chunk */ + dbg("%s: Freed %d uvd_t structures", + proc, cams->num_cameras); + kfree(cams); + *pCams = NULL; +} + +/* + * usbvideo_Disconnect() + * + * This procedure stops all driver activity. Deallocation of + * the interface-private structure (pointed by 'ptr') is done now + * (if we don't have any open files) or later, when those files + * are closed. After that driver should be removable. + * + * This code handles surprise removal. The uvd->user is a counter which + * increments on open() and decrements on close(). If we see here that + * this counter is not 0 then we have a client who still has us opened. + * We set uvd->remove_pending flag as early as possible, and after that + * all access to the camera will gracefully fail. These failures should + * prompt client to (eventually) close the video device, and then - in + * usbvideo_v4l_close() - we decrement uvd->uvd_used and usage counter. + * + * History: + * 22-Jan-2000 Added polling of MOD_IN_USE to delay removal until all users gone. + * 27-Jan-2000 Reworked to allow pending disconnects; see xxx_close() + * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT). + * 19-Oct-2000 Moved to usbvideo module. + */ +void usbvideo_Disconnect(struct usb_device *dev, void *ptr) +{ + static const char proc[] = "usbvideo_Disconnect"; + uvd_t *uvd = (uvd_t *) ptr; + int i; + + if ((dev == NULL) || (uvd == NULL)) { + err("%s($%p,$%p): Illegal call.", proc, dev, ptr); + return; + } + usbvideo_ClientIncModCount(uvd); + if (uvd->debug > 0) + info("%s(%p,%p.)", proc, dev, ptr); + + down(&uvd->lock); + uvd->remove_pending = 1; /* Now all ISO data will be ignored */ + + /* At this time we ask to cancel outstanding URBs */ + usbvideo_StopDataPump(uvd); + + for (i=0; i < USBVIDEO_NUMSBUF; i++) + usb_free_urb(uvd->sbuf[i].urb); + + usb_dec_dev_use(uvd->dev); + uvd->dev = NULL; /* USB device is no more */ + + if (uvd->user) + info("%s: In use, disconnect pending.", proc); + else + usbvideo_CameraRelease(uvd); + up(&uvd->lock); + info("USB camera disconnected."); + + usbvideo_ClientDecModCount(uvd); +} + +/* + * usbvideo_CameraRelease() + * + * This code does final release of uvd_t. This happens + * after the device is disconnected -and- all clients + * closed their files. + * + * History: + * 27-Jan-2000 Created. + */ +void usbvideo_CameraRelease(uvd_t *uvd) +{ + static const char proc[] = "usbvideo_CameraRelease"; + if (uvd == NULL) { + err("%s: Illegal call", proc); + return; + } + video_unregister_device(&uvd->vdev); + if (uvd->debug > 0) + info("%s: Video unregistered.", proc); + +#if USES_PROC_FS + assert(uvd->handle != NULL); + if (uvd->handle->uses_procfs) { + dbg("%s: Removing /proc/%s/ filesystem entries.", proc, uvd->handle->drvName); + usbvideo_procfs_level2_destroy(uvd); + } +#endif + + RingQueue_Free(&uvd->dp); + if (VALID_CALLBACK(uvd, userFree)) + GET_CALLBACK(uvd, userFree)(uvd); + uvd->uvd_used = 0; /* This is atomic, no need to take mutex */ +} + +/* + * usbvideo_find_struct() + * + * This code searches the array of preallocated (static) structures + * and returns index of the first one that isn't in use. Returns -1 + * if there are no free structures. + * + * History: + * 27-Jan-2000 Created. + */ +static int usbvideo_find_struct(usbvideo_t *cams) +{ + int u, rv = -1; + + if (cams == NULL) { + err("No usbvideo_t handle?"); + return -1; + } + down(&cams->lock); + for (u = 0; u < cams->num_cameras; u++) { + uvd_t *uvd = &cams->cam[u]; + if (!uvd->uvd_used) /* This one is free */ + { + uvd->uvd_used = 1; /* In use now */ + init_MUTEX(&uvd->lock); /* to 1 == available */ + uvd->dev = NULL; + rv = u; + break; + } + } + up(&cams->lock); + return rv; +} + +uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams) +{ + int i, devnum; + uvd_t *uvd = NULL; + + if (cams == NULL) { + err("No usbvideo_t handle?"); + return NULL; + } + + devnum = usbvideo_find_struct(cams); + if (devnum == -1) { + err("IBM USB camera driver: Too many devices!"); + return NULL; + } + uvd = &cams->cam[devnum]; + dbg("Device entry #%d. at $%p", devnum, uvd); + + /* Not relying upon caller we increase module counter ourselves */ + usbvideo_ClientIncModCount(uvd); + + down(&uvd->lock); + for (i=0; i < USBVIDEO_NUMSBUF; i++) { + uvd->sbuf[i].urb = usb_alloc_urb(FRAMES_PER_DESC); + if (uvd->sbuf[i].urb == NULL) { + err("usb_alloc_urb(%d.) failed.", FRAMES_PER_DESC); + uvd->uvd_used = 0; + uvd = NULL; + goto allocate_done; + } + } + uvd->user=0; + uvd->remove_pending = 0; + uvd->last_error = 0; + RingQueue_Initialize(&uvd->dp); + + /* Initialize video device structure */ + memset(&uvd->vdev, 0, sizeof(uvd->vdev)); + i = sprintf(uvd->vdev.name, "%s USB Camera", cams->drvName); + if (i >= sizeof(uvd->vdev.name)) { + err("Wrote too much into uvd->vdev.name, expect trouble!"); + } + uvd->vdev.type = VID_TYPE_CAPTURE; + uvd->vdev.hardware = VID_HARDWARE_CPIA; + uvd->vdev.open = usbvideo_v4l_open; + uvd->vdev.close = usbvideo_v4l_close; + uvd->vdev.read = usbvideo_v4l_read; + uvd->vdev.write = usbvideo_v4l_write; + uvd->vdev.ioctl = usbvideo_v4l_ioctl; + uvd->vdev.mmap = usbvideo_v4l_mmap; + uvd->vdev.initialize = usbvideo_v4l_initialize; + /* + * The client is free to overwrite those because we + * return control to the client's probe function right now. + */ +allocate_done: + up (&uvd->lock); + usbvideo_ClientDecModCount(uvd); + return uvd; +} + +int usbvideo_RegisterVideoDevice(uvd_t *uvd) +{ + static const char proc[] = "usbvideo_RegisterVideoDevice"; + char tmp1[20], tmp2[20]; /* Buffers for printing */ + + if (uvd == NULL) { + err("%s: Illegal call.", proc); + return -EINVAL; + } + if (uvd->video_endp == 0) { + info("%s: No video endpoint specified; data pump disabled.", proc); + } + if (uvd->paletteBits == 0) { + err("%s: No palettes specified!", proc); + return -EINVAL; + } + if (uvd->defaultPalette == 0) { + info("%s: No default palette!", proc); + } + + uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) * + VIDEOSIZE_Y(uvd->canvas) * V4L_BYTES_PER_PIXEL; + usbvideo_VideosizeToString(tmp1, sizeof(tmp1), uvd->videosize); + usbvideo_VideosizeToString(tmp2, sizeof(tmp2), uvd->canvas); + + if (uvd->debug > 0) { + info("%s: iface=%d. endpoint=$%02x paletteBits=$%08lx", + proc, uvd->iface, uvd->video_endp, uvd->paletteBits); + } + if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER) == -1) { + err("%s: video_register_device failed", proc); + return -EPIPE; + } + if (uvd->debug > 1) { + info("%s: video_register_device() successful", proc); + } + if (uvd->dev == NULL) { + err("%s: uvd->dev == NULL", proc); + return -EINVAL; + } + + info("%s on /dev/video%d: canvas=%s videosize=%s", + (uvd->handle != NULL) ? uvd->handle->drvName : "???", + uvd->vdev.minor, tmp2, tmp1); + +#if USES_PROC_FS + assert(uvd->handle != NULL); + if (uvd->handle->uses_procfs) { + if (uvd->debug > 0) { + info("%s: Creating /proc/%s/ filesystem entries.", + proc, uvd->handle->drvName); + } + usbvideo_procfs_level2_create(uvd); + } +#endif + + usb_inc_dev_use(uvd->dev); + return 0; +} + +/* ******************************************************************** */ + +int usbvideo_v4l_initialize(struct video_device *dev) +{ + return 0; +} + +long usbvideo_v4l_write(struct video_device *dev, const char *buf, + unsigned long count, int noblock) +{ + return -EINVAL; +} + +int usbvideo_v4l_mmap(struct video_device *dev, const char *adr, unsigned long size) +{ + uvd_t *uvd = (uvd_t *) dev; + unsigned long start = (unsigned long) adr; + unsigned long page, pos; + + if (!CAMERA_IS_OPERATIONAL(uvd)) + return -EFAULT; + + if (size > (((2 * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) + return -EINVAL; + + pos = (unsigned long) uvd->fbuf; + while (size > 0) { + page = usbvideo_kvirt_to_pa(pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + return 0; +} + +/* + * usbvideo_v4l_open() + * + * This is part of Video 4 Linux API. The driver can be opened by one + * client only (checks internal counter 'uvdser'). The procedure + * then allocates buffers needed for video processing. + * + * History: + * 22-Jan-2000 Rewrote, moved scratch buffer allocation here. Now the + * camera is also initialized here (once per connect), at + * expense of V4L client (it waits on open() call). + * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers. + * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT). + */ +int usbvideo_v4l_open(struct video_device *dev, int flags) +{ + static const char proc[] = "usbvideo_v4l_open"; + uvd_t *uvd = (uvd_t *) dev; + const int sb_size = FRAMES_PER_DESC * uvd->iso_packet_len; + int i, errCode = 0; + + if (uvd->debug > 1) + info("%s($%p,$%08x", proc, dev, flags); + + usbvideo_ClientIncModCount(uvd); + down(&uvd->lock); + + if (uvd->user) { + err("%s: Someone tried to open an already opened device!", proc); + errCode = -EBUSY; + } else { + /* Clear statistics */ + memset(&uvd->stats, 0, sizeof(uvd->stats)); + + /* Clean pointers so we know if we allocated something */ + for (i=0; i < USBVIDEO_NUMSBUF; i++) + uvd->sbuf[i].data = NULL; + + /* Allocate memory for the frame buffers */ + uvd->fbuf_size = USBVIDEO_NUMFRAMES * uvd->max_frame_size; + uvd->fbuf = usbvideo_rvmalloc(uvd->fbuf_size); + RingQueue_Allocate(&uvd->dp, 128*1024); /* FIXME #define */ + if ((uvd->fbuf == NULL) || + (!RingQueue_IsAllocated(&uvd->dp))) { + err("%s: Failed to allocate fbuf or dp", proc); + errCode = -ENOMEM; + } else { + /* Allocate all buffers */ + for (i=0; i < USBVIDEO_NUMFRAMES; i++) { + uvd->frame[i].frameState = FrameState_Unused; + uvd->frame[i].data = uvd->fbuf + i*(uvd->max_frame_size); + /* + * Set default sizes in case IOCTL (VIDIOCMCAPTURE) + * is not used (using read() instead). + */ + uvd->frame[i].canvas = uvd->canvas; + uvd->frame[i].seqRead_Index = 0; + } + for (i=0; i < USBVIDEO_NUMSBUF; i++) { + uvd->sbuf[i].data = kmalloc(sb_size, GFP_KERNEL); + if (uvd->sbuf[i].data == NULL) { + errCode = -ENOMEM; + break; + } + } + } + if (errCode != 0) { + /* Have to free all that memory */ + if (uvd->fbuf != NULL) { + usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size); + uvd->fbuf = NULL; + } + RingQueue_Free(&uvd->dp); + for (i=0; i < USBVIDEO_NUMSBUF; i++) { + if (uvd->sbuf[i].data != NULL) { + kfree (uvd->sbuf[i].data); + uvd->sbuf[i].data = NULL; + } + } + } + } + + /* If so far no errors then we shall start the camera */ + if (errCode == 0) { + /* Start data pump if we have valid endpoint */ + if (uvd->video_endp != 0) + errCode = usbvideo_StartDataPump(uvd); + if (errCode == 0) { + if (VALID_CALLBACK(uvd, setupOnOpen)) { + if (uvd->debug > 1) + info("%s: setupOnOpen callback", proc); + errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd); + if (errCode < 0) { + err("%s: setupOnOpen callback failed (%d.).", + proc, errCode); + } else if (uvd->debug > 1) { + info("%s: setupOnOpen callback successful", proc); + } + } + if (errCode == 0) { + uvd->settingsAdjusted = 0; + if (uvd->debug > 1) + info("%s: Open succeeded.", proc); + uvd->user++; + } + } + } + up(&uvd->lock); + if (errCode != 0) + usbvideo_ClientDecModCount(uvd); + if (uvd->debug > 0) + info("%s: Returning %d.", proc, errCode); + return errCode; +} + +/* + * usbvideo_v4l_close() + * + * This is part of Video 4 Linux API. The procedure + * stops streaming and deallocates all buffers that were earlier + * allocated in usbvideo_v4l_open(). + * + * History: + * 22-Jan-2000 Moved scratch buffer deallocation here. + * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers. + * 24-May-2000 Moved MOD_DEC_USE_COUNT outside of code that can sleep. + */ +void usbvideo_v4l_close(struct video_device *dev) +{ + static const char proc[] = "usbvideo_v4l_close"; + uvd_t *uvd = (uvd_t *)dev; + int i; + + if (uvd->debug > 1) + info("%s($%p)", proc, dev); + + down(&uvd->lock); + usbvideo_StopDataPump(uvd); + usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size); + uvd->fbuf = NULL; + RingQueue_Free(&uvd->dp); + + for (i=0; i < USBVIDEO_NUMSBUF; i++) { + kfree(uvd->sbuf[i].data); + uvd->sbuf[i].data = NULL; + } + +#if USBVIDEO_REPORT_STATS + usbvideo_ReportStatistics(uvd); +#endif + + uvd->user--; + if (uvd->remove_pending) { + if (uvd->debug > 0) + info("usbvideo_v4l_close: Final disconnect."); + usbvideo_CameraRelease(uvd); + } + up(&uvd->lock); + usbvideo_ClientDecModCount(uvd); + + if (uvd->debug > 1) + info("%s: Completed.", proc); +} + +/* + * usbvideo_v4l_ioctl() + * + * This is part of Video 4 Linux API. The procedure handles ioctl() calls. + * + * History: + * 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings. + */ +int usbvideo_v4l_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + uvd_t *uvd = (uvd_t *)dev; + + if (!CAMERA_IS_OPERATIONAL(uvd)) + return -EFAULT; + + switch (cmd) { + case VIDIOCGCAP: + { + if (copy_to_user(arg, &uvd->vcap, sizeof(uvd->vcap))) + return -EFAULT; + return 0; + } + case VIDIOCGCHAN: + { + if (copy_to_user(arg, &uvd->vchan, sizeof(uvd->vchan))) + return -EFAULT; + return 0; + } + case VIDIOCSCHAN: + { /* Not used but we return success */ + int v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCGPICT: + { + if (copy_to_user(arg, &uvd->vpic, sizeof(uvd->vpic))) + return -EFAULT; + return 0; + } + case VIDIOCSPICT: + { + struct video_picture tmp; + /* + * Use temporary 'video_picture' structure to preserve our + * own settings (such as color depth, palette) that we + * aren't allowing everyone (V4L client) to change. + */ + if (copy_from_user(&tmp, arg, sizeof(tmp))) + return -EFAULT; + uvd->vpic.brightness = tmp.brightness; + uvd->vpic.hue = tmp.hue; + uvd->vpic.colour = tmp.colour; + uvd->vpic.contrast = tmp.contrast; + uvd->settingsAdjusted = 0; /* Will force new settings */ + return 0; + } + case VIDIOCSWIN: + { + struct video_window vw; + + if (copy_from_user(&vw, arg, sizeof(vw))) + return -EFAULT; + if (vw.flags) + return -EINVAL; + if (vw.clipcount) + return -EINVAL; + if (vw.width != VIDEOSIZE_X(uvd->canvas)) + return -EINVAL; + if (vw.height != VIDEOSIZE_Y(uvd->canvas)) + return -EINVAL; + + return 0; + } + case VIDIOCGWIN: + { + struct video_window vw; + + vw.x = 0; + vw.y = 0; + vw.width = VIDEOSIZE_X(uvd->canvas); + vw.height = VIDEOSIZE_Y(uvd->canvas); + vw.chromakey = 0; + if (VALID_CALLBACK(uvd, getFPS)) + vw.flags = GET_CALLBACK(uvd, getFPS)(uvd); + else + vw.flags = 10; /* FIXME: do better! */ + + if (copy_to_user(arg, &vw, sizeof(vw))) + return -EFAULT; + + return 0; + } + case VIDIOCGMBUF: + { + struct video_mbuf vm; + + memset(&vm, 0, sizeof(vm)); + vm.size = uvd->max_frame_size * 2; + vm.frames = 2; + vm.offsets[0] = 0; + vm.offsets[1] = uvd->max_frame_size; + + if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) + return -EFAULT; + + return 0; + } + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + + if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) { + err("VIDIOCMCAPTURE: copy_from_user() failed."); + return -EFAULT; + } + if (uvd->debug >= 1) { + info("VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.", + vm.frame, vm.width, vm.height, vm.format); + } + /* + * Check if the requested size is supported. If the requestor + * requests too big a frame then we may be tricked into accessing + * outside of own preallocated frame buffer (in uvd->frame). + * This will cause oops or a security hole. Theoretically, we + * could only clamp the size down to acceptable bounds, but then + * we'd need to figure out how to insert our smaller buffer into + * larger caller's buffer... this is not an easy question. So we + * here just flatly reject too large requests, assuming that the + * caller will resubmit with smaller size. Callers should know + * what size we support (returned by VIDIOCGCAP). However vidcat, + * for one, does not care and allows to ask for any size. + */ + if ((vm.width > VIDEOSIZE_X(uvd->canvas)) || + (vm.height > VIDEOSIZE_Y(uvd->canvas))) { + if (uvd->debug > 0) { + info("VIDIOCMCAPTURE: Size=%dx%d too large; " + "allowed only up to %ldx%ld", vm.width, vm.height, + VIDEOSIZE_X(uvd->canvas), VIDEOSIZE_Y(uvd->canvas)); + } + return -EINVAL; + } + /* Check if the palette is supported */ + if (((1L << vm.format) & uvd->paletteBits) == 0) { + if (uvd->debug > 0) { + info("VIDIOCMCAPTURE: format=%d. not supported" + " (paletteBits=$%08lx)", + vm.format, uvd->paletteBits); + } + return -EINVAL; + } + if ((vm.frame != 0) && (vm.frame != 1)) { + err("VIDIOCMCAPTURE: vm.frame=%d. !E [0,1]", vm.frame); + return -EINVAL; + } + if (uvd->frame[vm.frame].frameState == FrameState_Grabbing) { + /* Not an error - can happen */ + } + uvd->frame[vm.frame].request = VIDEOSIZE(vm.width, vm.height); + uvd->frame[vm.frame].palette = vm.format; + + /* Mark it as ready */ + uvd->frame[vm.frame].frameState = FrameState_Ready; + + return usbvideo_NewFrame(uvd, vm.frame); + } + case VIDIOCSYNC: + { + int frameNum, ret; + + if (copy_from_user((void *)&frameNum, arg, sizeof(frameNum))) { + err("VIDIOCSYNC: copy_from_user() failed."); + return -EFAULT; + } + if (uvd->debug >= 1) + info("VIDIOCSYNC: syncing to frame %d.", frameNum); + if (uvd->flags & FLAGS_NO_DECODING) + ret = usbvideo_GetFrame(uvd, frameNum); + else if (VALID_CALLBACK(uvd, getFrame)) { + ret = GET_CALLBACK(uvd, getFrame)(uvd, frameNum); + if ((ret < 0) && (uvd->debug >= 1)) { + err("VIDIOCSYNC: getFrame() returned %d.", ret); + } + } else { + err("VIDIOCSYNC: getFrame is not set"); + ret = -EFAULT; + } + + /* + * The frame is in FrameState_Done_Hold state. Release it + * right now because its data is already mapped into + * the user space and it's up to the application to + * make use of it until it asks for another frame. + */ + uvd->frame[frameNum].frameState = FrameState_Unused; + return ret; + } + case VIDIOCGFBUF: + { + struct video_buffer vb; + + memset(&vb, 0, sizeof(vb)); + vb.base = NULL; /* frame buffer not supported, not used */ + + if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb))) + return -EFAULT; + + return 0; + } + case VIDIOCKEY: + return 0; + + case VIDIOCCAPTURE: + return -EINVAL; + + case VIDIOCSFBUF: + + case VIDIOCGTUNER: + case VIDIOCSTUNER: + + case VIDIOCGFREQ: + case VIDIOCSFREQ: + + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + return -EINVAL; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +/* + * usbvideo_v4l_read() + * + * This is mostly boring stuff. We simply ask for a frame and when it + * arrives copy all the video data from it into user space. There is + * no obvious need to override this method. + * + * History: + * 20-Oct-2000 Created. + * 01-Nov-2000 Added mutex (uvd->lock). + */ +long usbvideo_v4l_read(struct video_device *dev, char *buf, unsigned long count, int noblock) +{ + static const char proc[] = "usbvideo_v4l_read"; + uvd_t *uvd = (uvd_t *) dev; + int frmx = -1; + usbvideo_frame_t *frame; + + if (!CAMERA_IS_OPERATIONAL(uvd) || (buf == NULL)) + return -EFAULT; + + if (uvd->debug >= 1) + info("%s: %ld. bytes, noblock=%d.", proc, count, noblock); + + down(&uvd->lock); + + /* See if a frame is completed, then use it. */ + if ((uvd->frame[0].frameState == FrameState_Done) || + (uvd->frame[0].frameState == FrameState_Done_Hold) || + (uvd->frame[0].frameState == FrameState_Error)) { + frmx = 0; + } else if ((uvd->frame[1].frameState >= FrameState_Done) || + (uvd->frame[1].frameState == FrameState_Done_Hold) || + (uvd->frame[1].frameState >= FrameState_Done)) { + frmx = 1; + } + + /* FIXME: If we don't start a frame here then who ever does? */ + if (noblock && (frmx == -1)) { + count = -EAGAIN; + goto read_done; + } + + /* + * If no FrameState_Done, look for a FrameState_Grabbing state. + * See if a frame is in process (grabbing), then use it. + * We will need to wait until it becomes cooked, of course. + */ + if (frmx == -1) { + if (uvd->frame[0].frameState == FrameState_Grabbing) + frmx = 0; + else if (uvd->frame[1].frameState == FrameState_Grabbing) + frmx = 1; + } + + /* + * If no frame is active, start one. We don't care which one + * it will be, so #0 is as good as any. + * In read access mode we don't have convenience of VIDIOCMCAPTURE + * to specify the requested palette (video format) on per-frame + * basis. This means that we have to return data in -some- format + * and just hope that the client knows what to do with it. + * The default format is configured in uvd->defaultPalette field + * as one of VIDEO_PALETTE_xxx values. We stuff it into the new + * frame and initiate the frame filling process. + */ + if (frmx == -1) { + if (uvd->defaultPalette == 0) { + err("%s: No default palette; don't know what to do!", proc); + count = -EFAULT; + goto read_done; + } + frmx = 0; + /* + * We have no per-frame control over video size. + * Therefore we only can use whatever size was + * specified as default. + */ + uvd->frame[frmx].request = uvd->videosize; + uvd->frame[frmx].palette = uvd->defaultPalette; + uvd->frame[frmx].frameState = FrameState_Ready; + usbvideo_NewFrame(uvd, frmx); + /* Now frame 0 is supposed to start filling... */ + } + + /* + * Get a pointer to the active frame. It is either previously + * completed frame or frame in progress but not completed yet. + */ + frame = &uvd->frame[frmx]; + + /* + * Sit back & wait until the frame gets filled and postprocessed. + * If we fail to get the picture [in time] then return the error. + * In this call we specify that we want the frame to be waited for, + * postprocessed and switched into FrameState_Done_Hold state. This + * state is used to hold the frame as "fully completed" between + * subsequent partial reads of the same frame. + */ + if (frame->frameState != FrameState_Done_Hold) { + long rv = -EFAULT; + if (uvd->flags & FLAGS_NO_DECODING) + rv = usbvideo_GetFrame(uvd, frmx); + else if (VALID_CALLBACK(uvd, getFrame)) + rv = GET_CALLBACK(uvd, getFrame)(uvd, frmx); + else + err("getFrame is not set"); + if ((rv != 0) || (frame->frameState != FrameState_Done_Hold)) { + count = rv; + goto read_done; + } + } + + /* + * Copy bytes to user space. We allow for partial reads, which + * means that the user application can request read less than + * the full frame size. It is up to the application to issue + * subsequent calls until entire frame is read. + * + * First things first, make sure we don't copy more than we + * have - even if the application wants more. That would be + * a big security embarassment! + */ + if ((count + frame->seqRead_Index) > frame->seqRead_Length) + count = frame->seqRead_Length - frame->seqRead_Index; + + /* + * Copy requested amount of data to user space. We start + * copying from the position where we last left it, which + * will be zero for a new frame (not read before). + */ + if (copy_to_user(buf, frame->data + frame->seqRead_Index, count)) { + count = -EFAULT; + goto read_done; + } + + /* Update last read position */ + frame->seqRead_Index += count; + if (uvd->debug >= 1) { + err("%s: {copy} count used=%ld, new seqRead_Index=%ld", + proc, count, frame->seqRead_Index); + } + + /* Finally check if the frame is done with and "release" it */ + if (frame->seqRead_Index >= frame->seqRead_Length) { + /* All data has been read */ + frame->seqRead_Index = 0; + + /* Mark it as available to be used again. */ + uvd->frame[frmx].frameState = FrameState_Unused; + if (usbvideo_NewFrame(uvd, frmx ? 0 : 1)) { + err("%s: usbvideo_NewFrame failed.", proc); + } + } +read_done: + up(&uvd->lock); + return count; +} + +/* + * Make all of the blocks of data contiguous + */ +static int usbvideo_CompressIsochronous(uvd_t *uvd, urb_t *urb) +{ + char *cdata; + int i, totlen = 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; + + /* Detect and ignore errored packets */ + if (st < 0) { + if (uvd->debug >= 1) + err("Data error: packet=%d. len=%d. status=%d.", i, n, st); + uvd->stats.iso_err_count++; + continue; + } + + /* Detect and ignore empty packets */ + if (n <= 0) { + uvd->stats.iso_skip_count++; + continue; + } + totlen += n; /* Little local accounting */ + RingQueue_Enqueue(&uvd->dp, cdata, n); + } + return totlen; +} + +static void usbvideo_IsocIrq(struct urb *urb) +{ + int i, len; + uvd_t *uvd = urb->context; + + /* We don't want to do anything if we are about to be removed! */ + if (!CAMERA_IS_OPERATIONAL(uvd)) + return; +#if 0 + if (urb->actual_length > 0) { + info("urb=$%p status=%d. errcount=%d. length=%d.", + urb, urb->status, urb->error_count, urb->actual_length); + } else { + static int c = 0; + if (c++ % 100 == 0) + info("No Isoc data"); + } +#endif + + if (!uvd->streaming) { + if (uvd->debug >= 1) + info("Not streaming, but interrupt!"); + return; + } + + uvd->stats.urb_count++; + if (urb->actual_length <= 0) + goto urb_done_with; + + /* Copy the data received into ring queue */ + len = usbvideo_CompressIsochronous(uvd, urb); + uvd->stats.urb_length = len; + if (len <= 0) + goto urb_done_with; + + /* Here we got some data */ + uvd->stats.data_count += len; + RingQueue_WakeUpInterruptible(&uvd->dp); + +urb_done_with: + for (i = 0; i < FRAMES_PER_DESC; i++) { + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + return; +} + +/* + * usbvideo_StartDataPump() + * + * History: + * 27-Jan-2000 Used ibmcam->iface, ibmcam->ifaceAltActive instead + * of hardcoded values. Simplified by using for loop, + * allowed any number of URBs. + */ +int usbvideo_StartDataPump(uvd_t *uvd) +{ + static const char proc[] = "usbvideo_StartDataPump"; + struct usb_device *dev = uvd->dev; + int i, errFlag; + + if (uvd->debug > 1) + info("%s($%p)", proc, uvd); + + if (!CAMERA_IS_OPERATIONAL(uvd)) { + err("%s: Camera is not operational",proc); + return -EFAULT; + } + uvd->curframe = -1; + + /* Alternate interface 1 is is the biggest frame size */ + i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive); + if (i < 0) { + err("%s: usb_set_interface error", proc); + uvd->last_error = i; + return -EBUSY; + } + if (VALID_CALLBACK(uvd, videoStart)) + GET_CALLBACK(uvd, videoStart)(uvd); + else + err("%s: videoStart not set", proc); + + /* We double buffer the Iso lists */ + for (i=0; i < USBVIDEO_NUMSBUF; i++) { + int j, k; + urb_t *urb = uvd->sbuf[i].urb; + urb->dev = dev; + urb->context = uvd; + urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp); + urb->transfer_flags = USB_ISO_ASAP; + urb->transfer_buffer = uvd->sbuf[i].data; + urb->complete = usbvideo_IsocIrq; + urb->number_of_packets = FRAMES_PER_DESC; + urb->transfer_buffer_length = uvd->iso_packet_len * FRAMES_PER_DESC; + for (j=k=0; j < FRAMES_PER_DESC; j++, k += uvd->iso_packet_len) { + urb->iso_frame_desc[j].offset = k; + urb->iso_frame_desc[j].length = uvd->iso_packet_len; + } + } + + /* Link URBs into a ring so that they invoke each other infinitely */ + for (i=0; i < USBVIDEO_NUMSBUF; i++) { + if ((i+1) < USBVIDEO_NUMSBUF) + uvd->sbuf[i].urb->next = uvd->sbuf[i+1].urb; + else + uvd->sbuf[i].urb->next = uvd->sbuf[0].urb; + } + + /* Submit all URBs */ + for (i=0; i < USBVIDEO_NUMSBUF; i++) { + errFlag = usb_submit_urb(uvd->sbuf[i].urb); + if (errFlag) + err("%s: usb_submit_isoc(%d) ret %d", proc, i, errFlag); + } + + uvd->streaming = 1; + if (uvd->debug > 1) + info("%s: streaming=1 video_endp=$%02x", proc, uvd->video_endp); + return 0; +} + +/* + * usbvideo_StopDataPump() + * + * This procedure stops streaming and deallocates URBs. Then it + * activates zero-bandwidth alt. setting of the video interface. + * + * History: + * 22-Jan-2000 Corrected order of actions to work after surprise removal. + * 27-Jan-2000 Used uvd->iface, uvd->ifaceAltInactive instead of hardcoded values. + */ +void usbvideo_StopDataPump(uvd_t *uvd) +{ + static const char proc[] = "usbvideo_StopDataPump"; + int i, j; + + if (uvd->debug > 1) + info("%s($%p)", proc, uvd); + + if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL)) + return; + + /* Unschedule all of the iso td's */ + for (i=0; i < USBVIDEO_NUMSBUF; i++) { + j = usb_unlink_urb(uvd->sbuf[i].urb); + if (j < 0) + err("%s: usb_unlink_urb() error %d.", proc, j); + } + if (uvd->debug > 1) + info("%s: streaming=0", proc); + uvd->streaming = 0; + + if (!uvd->remove_pending) { + /* Invoke minidriver's magic to stop the camera */ + if (VALID_CALLBACK(uvd, videoStop)) + GET_CALLBACK(uvd, videoStop)(uvd); + else + err("%s: videoStop not set" ,proc); + + /* Set packet size to 0 */ + j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive); + if (j < 0) { + err("%s: usb_set_interface() error %d.", proc, j); + uvd->last_error = j; + } + } +} + +/* + * usbvideo_NewFrame() + * + * History: + * 29-Mar-00 Added copying of previous frame into the current one. + * 6-Aug-00 Added model 3 video sizes, removed redundant width, height. + */ +int usbvideo_NewFrame(uvd_t *uvd, int framenum) +{ + usbvideo_frame_t *frame; + int n; + + if (uvd->debug > 1) + info("usbvideo_NewFrame($%p,%d.)", uvd, framenum); + + /* If we're not grabbing a frame right now and the other frame is */ + /* ready to be grabbed into, then use it instead */ + if (uvd->curframe != -1) + return 0; + + /* If necessary we adjust picture settings between frames */ + if (!uvd->settingsAdjusted) { + if (VALID_CALLBACK(uvd, adjustPicture)) + GET_CALLBACK(uvd, adjustPicture)(uvd); + uvd->settingsAdjusted = 1; + } + + n = (framenum - 1 + USBVIDEO_NUMFRAMES) % USBVIDEO_NUMFRAMES; + if (uvd->frame[n].frameState == FrameState_Ready) + framenum = n; + + frame = &uvd->frame[framenum]; + + frame->frameState = FrameState_Grabbing; + frame->scanstate = ScanState_Scanning; + frame->seqRead_Length = 0; /* Accumulated in xxx_parse_data() */ + frame->deinterlace = Deinterlace_None; + frame->flags = 0; /* No flags yet, up to minidriver (or us) to set them */ + uvd->curframe = framenum; + + /* + * Normally we would want to copy previous frame into the current one + * before we even start filling it with data; this allows us to stop + * filling at any moment; top portion of the frame will be new and + * bottom portion will stay as it was in previous frame. If we don't + * do that then missing chunks of video stream will result in flickering + * portions of old data whatever it was before. + * + * If we choose not to copy previous frame (to, for example, save few + * bus cycles - the frame can be pretty large!) then we have an option + * to clear the frame before using. If we experience losses in this + * mode then missing picture will be black (no flickering). + * + * Finally, if user chooses not to clean the current frame before + * filling it with data then the old data will be visible if we fail + * to refill entire frame with new data. + */ + if (!(uvd->flags & FLAGS_SEPARATE_FRAMES)) { + /* This copies previous frame into this one to mask losses */ + memmove(frame->data, uvd->frame[1-framenum].data, uvd->max_frame_size); + } else { + if (uvd->flags & FLAGS_CLEAN_FRAMES) { + /* This provides a "clean" frame but slows things down */ + memset(frame->data, 0, uvd->max_frame_size); + } + } + return 0; +} + +/* + * usbvideo_CollectRawData() + * + * This procedure can be used instead of 'processData' callback if you + * only want to dump the raw data from the camera into the output + * device (frame buffer). You can look at it with V4L client, but the + * image will be unwatchable. The main purpose of this code and of the + * mode FLAGS_NO_DECODING is debugging and capturing of datastreams from + * new, unknown cameras. This procedure will be automatically invoked + * instead of the specified callback handler when uvd->flags has bit + * FLAGS_NO_DECODING set. Therefore, any regular build of any driver + * based on usbvideo can use this feature at any time. + */ +void usbvideo_CollectRawData(uvd_t *uvd, usbvideo_frame_t *frame) +{ + int n; + + assert(uvd != NULL); + assert(frame != NULL); + + /* Try to move data from queue into frame buffer */ + n = RingQueue_GetLength(&uvd->dp); + if (n > 0) { + int m; + /* See how much space we have left */ + m = uvd->max_frame_size - frame->seqRead_Length; + if (n > m) + n = m; + /* Now move that much data into frame buffer */ + RingQueue_Dequeue( + &uvd->dp, + frame->data + frame->seqRead_Length, + m); + frame->seqRead_Length += m; + } + /* See if we filled the frame */ + if (frame->seqRead_Length >= uvd->max_frame_size) { + frame->frameState = FrameState_Done; + uvd->curframe = -1; + uvd->stats.frame_num++; + } +} + +int usbvideo_GetFrame(uvd_t *uvd, int frameNum) +{ + static const char proc[] = "usbvideo_GetFrame"; + usbvideo_frame_t *frame = &uvd->frame[frameNum]; + + if (uvd->debug >= 2) + info("%s($%p,%d.)", proc, uvd, frameNum); + + switch (frame->frameState) { + case FrameState_Unused: + if (uvd->debug >= 2) + info("%s: FrameState_Unused", proc); + return -EINVAL; + case FrameState_Ready: + case FrameState_Grabbing: + case FrameState_Error: + { + int ntries, signalPending; + redo: + if (!CAMERA_IS_OPERATIONAL(uvd)) { + if (uvd->debug >= 2) + info("%s: Camera is not operational (1)", proc); + return -EIO; + } + ntries = 0; + do { + RingQueue_InterruptibleSleepOn(&uvd->dp); + signalPending = signal_pending(current); + if (!CAMERA_IS_OPERATIONAL(uvd)) { + if (uvd->debug >= 2) + info("%s: Camera is not operational (2)", proc); + return -EIO; + } + assert(uvd->fbuf != NULL); + if (signalPending) { + if (uvd->debug >= 2) + info("%s: Signal=$%08x", proc, signalPending); + if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) { + usbvideo_TestPattern(uvd, 1, 0); + uvd->curframe = -1; + uvd->stats.frame_num++; + if (uvd->debug >= 2) + info("%s: Forced test pattern screen", proc); + return 0; + } else { + /* Standard answer: Interrupted! */ + if (uvd->debug >= 2) + info("%s: Interrupted!", proc); + return -EINTR; + } + } else { + /* No signals - we just got new data in dp queue */ + if (uvd->flags & FLAGS_NO_DECODING) + usbvideo_CollectRawData(uvd, frame); + else if (VALID_CALLBACK(uvd, processData)) + GET_CALLBACK(uvd, processData)(uvd, frame); + else + err("%s: processData not set", proc); + } + } while (frame->frameState == FrameState_Grabbing); + if (uvd->debug >= 2) { + info("%s: Grabbing done; state=%d. (%lu. bytes)", + proc, frame->frameState, frame->seqRead_Length); + } + if (frame->frameState == FrameState_Error) { + int ret = usbvideo_NewFrame(uvd, frameNum); + if (ret < 0) { + err("%s: usbvideo_NewFrame() failed (%d.)", proc, ret); + return ret; + } + goto redo; + } + /* Note that we fall through to meet our destiny below */ + } + case FrameState_Done: + /* + * Do all necessary postprocessing of data prepared in + * "interrupt" code and the collecting code above. The + * frame gets marked as FrameState_Done by queue parsing code. + * This status means that we collected enough data and + * most likely processed it as we went through. However + * the data may need postprocessing, such as deinterlacing + * or picture adjustments implemented in software (horror!) + * + * As soon as the frame becomes "final" it gets promoted to + * FrameState_Done_Hold status where it will remain until the + * caller consumed all the video data from the frame. Then + * the empty shell of ex-frame is thrown out for dogs to eat. + * But we, worried about pets, will recycle the frame! + */ + uvd->stats.frame_num++; + if ((uvd->flags & FLAGS_NO_DECODING) == 0) { + if (VALID_CALLBACK(uvd, postProcess)) + GET_CALLBACK(uvd, postProcess)(uvd, frame); + if (frame->flags & USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST) + usbvideo_SoftwareContrastAdjustment(uvd, frame); + } + frame->frameState = FrameState_Done_Hold; + if (uvd->debug >= 2) + info("%s: Entered FrameState_Done_Hold state.", proc); + return 0; + + case FrameState_Done_Hold: + /* + * We stay in this state indefinitely until someone external, + * like ioctl() or read() call finishes digesting the frame + * data. Then it will mark the frame as FrameState_Unused and + * it will be released back into the wild to roam freely. + */ + if (uvd->debug >= 2) + info("%s: FrameState_Done_Hold state.", proc); + return 0; + } + + /* Catch-all for other cases. We shall not be here. */ + err("%s: Invalid state %d.", proc, frame->frameState); + frame->frameState = FrameState_Unused; + return 0; +} + +/* + * usbvideo_DeinterlaceFrame() + * + * This procedure deinterlaces the given frame. Some cameras produce + * only half of scanlines - sometimes only even lines, sometimes only + * odd lines. The deinterlacing method is stored in frame->deinterlace + * variable. + * + * Here we scan the frame vertically and replace missing scanlines with + * average between surrounding ones - before and after. If we have no + * line above then we just copy next line. Similarly, if we need to + * create a last line then preceding line is used. + */ +void usbvideo_DeinterlaceFrame(uvd_t *uvd, usbvideo_frame_t *frame) +{ + if ((uvd == NULL) || (frame == NULL)) + return; + + if ((frame->deinterlace == Deinterlace_FillEvenLines) || + (frame->deinterlace == Deinterlace_FillOddLines)) + { + const int v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; + int i = (frame->deinterlace == Deinterlace_FillEvenLines) ? 0 : 1; + + for (; i < VIDEOSIZE_Y(frame->request); i += 2) { + const unsigned char *fs1, *fs2; + unsigned char *fd; + int ip, in, j; /* Previous and next lines */ + + /* + * Need to average lines before and after 'i'. + * If we go out of bounds seeking those lines then + * we point back to existing line. + */ + ip = i - 1; /* First, get rough numbers */ + in = i + 1; + + /* Now validate */ + if (ip < 0) + ip = in; + if (in >= VIDEOSIZE_Y(frame->request)) + in = ip; + + /* Sanity check */ + if ((ip < 0) || (in < 0) || + (ip >= VIDEOSIZE_Y(frame->request)) || + (in >= VIDEOSIZE_Y(frame->request))) + { + err("Error: ip=%d. in=%d. req.height=%ld.", + ip, in, VIDEOSIZE_Y(frame->request)); + break; + } + + /* Now we need to average lines 'ip' and 'in' to produce line 'i' */ + fs1 = frame->data + (v4l_linesize * ip); + fs2 = frame->data + (v4l_linesize * in); + fd = frame->data + (v4l_linesize * i); + + /* Average lines around destination */ + for (j=0; j < v4l_linesize; j++) { + fd[j] = (unsigned char)((((unsigned) fs1[j]) + + ((unsigned)fs2[j])) >> 1); + } + } + } + + /* Optionally display statistics on the screen */ + if (uvd->flags & FLAGS_OVERLAY_STATS) + usbvideo_OverlayStats(uvd, frame); +} + +/* + * usbvideo_SoftwareContrastAdjustment() + * + * This code adjusts the contrast of the frame, assuming RGB24 format. + * As most software image processing, this job is CPU-intensive. + * Get a camera that supports hardware adjustment! + * + * History: + * 09-Feb-2001 Created. + */ +void usbvideo_SoftwareContrastAdjustment(uvd_t *uvd, usbvideo_frame_t *frame) +{ + static const char proc[] = "usbvideo_SoftwareContrastAdjustment"; + int i, j, v4l_linesize; + signed long adj; + const int ccm = 128; /* Color correction median - see below */ + + if ((uvd == NULL) || (frame == NULL)) { + err("%s: Illegal call.", proc); + return; + } + adj = (uvd->vpic.contrast - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/ + RESTRICT_TO_RANGE(adj, -ccm, ccm+1); + if (adj == 0) { + /* In rare case of no adjustment */ + return; + } + v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; + for (i=0; i < VIDEOSIZE_Y(frame->request); i++) { + unsigned char *fd = frame->data + (v4l_linesize * i); + for (j=0; j < v4l_linesize; j++) { + signed long v = (signed long) fd[j]; + /* Magnify up to 2 times, reduce down to zero */ + v = 128 + ((ccm + adj) * (v - 128)) / ccm; + RESTRICT_TO_RANGE(v, 0, 0xFF); /* Must flatten tails */ + fd[j] = (unsigned char) v; + } + } +} + +/* + * /proc interface + * + * We will be creating directories and entries under /proc/video using + * external 'video_proc_entry' directory which is exported by videodev.o + * module. Within that directory we will create $driver/ directory to + * uniquely and uniformly refer to our specific $driver. Within that + * directory we will finally create an entry that is named after the + * video device node - video3, for example. The format of that file + * is determined by callbacks that the minidriver may provide. If no + * callbacks are provided (neither read nor write) then we don't create + * the entry. + * + * Here is a sample directory entry: /proc/video/ibmcam/video3 + * + * The "file" video3 (in example above) is readable and writeable, in + * theory. If the minidriver provides callbacks to do reading and + * writing then both those procedures are supported. However if the + * driver leaves callbacks in default (NULL) state the default + * read and write handlers are used. The default read handler reports + * that the driver does not support /proc fs. The default write handler + * returns error code on any write attempt. + */ + +#if USES_PROC_FS + +extern struct proc_dir_entry *video_proc_entry; + +static void usbvideo_procfs_level1_create(usbvideo_t *ut) +{ + static const char proc[] = "usbvideo_procfs_level1_create"; + + if (ut == NULL) { + err("%s: ut == NULL", proc); + return; + } + if (video_proc_entry == NULL) { + err("%s: /proc/video/ doesn't exist.", proc); + return; + } + ut->procfs_dEntry = create_proc_entry(ut->drvName, S_IFDIR, video_proc_entry); + if (ut->procfs_dEntry != NULL) { + if (ut->md_module != NULL) + ut->procfs_dEntry->owner = ut->md_module; + } else { + err("%s: Unable to initialize /proc/video/%s", proc, ut->drvName); + } +} + +static void usbvideo_procfs_level1_destroy(usbvideo_t *ut) +{ + static const char proc[] = "usbvideo_procfs_level1_destroy"; + + if (ut == NULL) { + err("%s: ut == NULL", proc); + return; + } + if (ut->procfs_dEntry != NULL) { + remove_proc_entry(ut->drvName, video_proc_entry); + ut->procfs_dEntry = NULL; + } +} + +static void usbvideo_procfs_level2_create(uvd_t *uvd) +{ + static const char proc[] = "usbvideo_procfs_level2_create"; + + if (uvd == NULL) { + err("%s: uvd == NULL", proc); + return; + } + assert(uvd->handle != NULL); + if (uvd->handle->procfs_dEntry == NULL) { + err("%s: uvd->handle->procfs_dEntry == NULL", proc); + return; + } + + sprintf(uvd->videoName, "video%d", uvd->vdev.minor); + uvd->procfs_vEntry = create_proc_entry( + uvd->videoName, + S_IFREG | S_IRUGO | S_IWUSR, + uvd->handle->procfs_dEntry); + if (uvd->procfs_vEntry != NULL) { + uvd->procfs_vEntry->data = uvd; + uvd->procfs_vEntry->read_proc = uvd->handle->cb.procfs_read; + uvd->procfs_vEntry->write_proc = uvd->handle->cb.procfs_write; + } else { + err("%s: Failed to create entry \"%s\"", proc, uvd->videoName); + } +} + +static void usbvideo_procfs_level2_destroy(uvd_t *uvd) +{ + static const char proc[] = "usbvideo_procfs_level2_destroy"; + + if (uvd == NULL) { + err("%s: uvd == NULL", proc); + return; + } + if (uvd->procfs_vEntry != NULL) { + remove_proc_entry(uvd->videoName, uvd->procfs_vEntry); + uvd->procfs_vEntry = NULL; + } +} + +static int usbvideo_default_procfs_read_proc( + char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + char *out = page; + int len; + + /* Stay under PAGE_SIZE or else */ + out += sprintf(out, "This driver does not support /proc services.\n"); + len = out - page; + len -= off; + if (len < count) { + *eof = 1; + if (len <= 0) + return 0; + } else + len = count; + *start = page + off; + return len; +} + +static int usbvideo_default_procfs_write_proc( + struct file *file, const char *buffer, + unsigned long count, void *data) +{ + return -EINVAL; +} + +#endif /* USES_PROC_FS */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usbvideo.h linux.ac/drivers/usb/usbvideo.h --- linux.vanilla/drivers/usb/usbvideo.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/usb/usbvideo.h Tue Apr 17 18:42:47 2001 @@ -0,0 +1,423 @@ +/* + * 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 usbvideo_h +#define usbvideo_h + +#include <linux/proc_fs.h> +#include <linux/videodev.h> +#include <linux/usb.h> + +/* Most helpful debugging aid */ +#define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__)))) + +#define USES_PROC_FS (defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)) +#define USBVIDEO_REPORT_STATS 1 /* Set to 0 to block statistics on close */ + +/* Bit flags (options) */ +#define FLAGS_RETRY_VIDIOCSYNC (1 << 0) +#define FLAGS_MONOCHROME (1 << 1) +#define FLAGS_DISPLAY_HINTS (1 << 2) +#define FLAGS_OVERLAY_STATS (1 << 3) +#define FLAGS_FORCE_TESTPATTERN (1 << 4) +#define FLAGS_SEPARATE_FRAMES (1 << 5) +#define FLAGS_CLEAN_FRAMES (1 << 6) +#define FLAGS_NO_DECODING (1 << 7) + +/* Bit flags for frames (apply to the frame where they are specified) */ +#define USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST (1 << 0) + +/* Camera capabilities (maximum) */ +#define CAMERA_URB_FRAMES 32 +#define CAMERA_MAX_ISO_PACKET 1023 /* 1022 actually sent by camera */ +#define FRAMES_PER_DESC (CAMERA_URB_FRAMES) +#define FRAME_SIZE_PER_DESC (CAMERA_MAX_ISO_PACKET) + +/* This macro restricts an int variable to an inclusive range */ +#define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); } + +#define V4L_BYTES_PER_PIXEL 3 /* Because we produce RGB24 */ + +/* + * Use this macro to construct constants for different video sizes. + * We have to deal with different video sizes that have to be + * configured in the device or compared against when we receive + * a data. Normally one would define a bunch of VIDEOSIZE_x_by_y + * #defines and that's the end of story. However this solution + * does not allow to convert between real pixel sizes and the + * constant (integer) value that may be used to tag a frame or + * whatever. The set of macros below constructs videosize constants + * from the pixel size and allows to reconstruct the pixel size + * from the combined value later. + */ +#define VIDEOSIZE(x,y) (((x) & 0xFFFFL) | (((y) & 0xFFFFL) << 16)) +#define VIDEOSIZE_X(vs) ((vs) & 0xFFFFL) +#define VIDEOSIZE_Y(vs) (((vs) >> 16) & 0xFFFFL) +typedef unsigned long videosize_t; + +/* + * This macro checks if the camera is still operational. The 'uvd' + * pointer must be valid, uvd->dev must be valid, we are not + * removing the device and the device has not erred on us. + */ +#define CAMERA_IS_OPERATIONAL(uvd) (\ + (uvd != NULL) && \ + ((uvd)->dev != NULL) && \ + ((uvd)->last_error == 0) && \ + (!(uvd)->remove_pending)) + +/* + * We use macros to do YUV -> RGB conversion because this is + * very important for speed and totally unimportant for size. + * + * YUV -> RGB Conversion + * --------------------- + * + * B = 1.164*(Y-16) + 2.018*(V-128) + * G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128) + * R = 1.164*(Y-16) + 1.596*(U-128) + * + * If you fancy integer arithmetics (as you should), hear this: + * + * 65536*B = 76284*(Y-16) + 132252*(V-128) + * 65536*G = 76284*(Y-16) - 53281*(U-128) - 25625*(V-128) + * 65536*R = 76284*(Y-16) + 104595*(U-128) + * + * Make sure the output values are within [0..255] range. + */ +#define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x))) +#define YUV_TO_RGB_BY_THE_BOOK(my,mu,mv,mr,mg,mb) { \ + int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \ + mm_y = (my) - 16; \ + mm_u = (mu) - 128; \ + mm_v = (mv) - 128; \ + mm_yc= mm_y * 76284; \ + mm_b = (mm_yc + 132252*mm_v ) >> 16; \ + mm_g = (mm_yc - 53281*mm_u - 25625*mm_v ) >> 16; \ + mm_r = (mm_yc + 104595*mm_u ) >> 16; \ + mb = LIMIT_RGB(mm_b); \ + mg = LIMIT_RGB(mm_g); \ + mr = LIMIT_RGB(mm_r); \ +} + +#define RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) % (rq)->length +#define RING_QUEUE_DEQUEUE_BYTES(rq,n) RING_QUEUE_ADVANCE_INDEX(rq,ri,n) +#define RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) % (rq)->length]) + +typedef struct { + unsigned char *queue; /* Data from the Isoc data pump */ + int length; /* How many bytes allocated for the queue */ + int wi; /* That's where we write */ + int ri; /* Read from here until you hit write index */ + wait_queue_head_t wqh; /* Processes waiting */ +} RingQueue_t; + +typedef enum { + ScanState_Scanning, /* Scanning for header */ + ScanState_Lines /* Parsing lines */ +} ScanState_t; + +/* Completion states of the data parser */ +typedef enum { + scan_Continue, /* Just parse next item */ + scan_NextFrame, /* Frame done, send it to V4L */ + scan_Out, /* Not enough data for frame */ + scan_EndParse /* End parsing */ +} ParseState_t; + +typedef enum { + FrameState_Unused, /* Unused (no MCAPTURE) */ + FrameState_Ready, /* Ready to start grabbing */ + FrameState_Grabbing, /* In the process of being grabbed into */ + FrameState_Done, /* Finished grabbing, but not been synced yet */ + FrameState_Done_Hold, /* Are syncing or reading */ + FrameState_Error, /* Something bad happened while processing */ +} FrameState_t; + +/* + * Some frames may contain only even or odd lines. This type + * specifies what type of deinterlacing is required. + */ +typedef enum { + Deinterlace_None=0, + Deinterlace_FillOddLines, + Deinterlace_FillEvenLines +} Deinterlace_t; + +struct usb_device; + +#define USBVIDEO_NUMFRAMES 2 /* How many frames we work with */ +#define USBVIDEO_NUMSBUF 2 /* How many URBs linked in a ring */ + +/* This structure represents one Isoc request - URB and buffer */ +typedef struct { + char *data; + urb_t *urb; +} usbvideo_sbuf_t; + +typedef struct { + char *data; /* Frame buffer */ + unsigned long header; /* Significant bits from the header */ + + videosize_t canvas; /* The canvas (max. image) allocated */ + videosize_t request; /* That's what the application asked for */ + unsigned short palette; /* The desired format */ + + FrameState_t frameState;/* State of grabbing */ + ScanState_t scanstate; /* State of scanning */ + Deinterlace_t deinterlace; + int flags; /* USBVIDEO_FRAME_FLAG_xxx bit flags */ + + int curline; /* Line of frame we're working on */ + + long seqRead_Length; /* Raw data length of frame */ + long seqRead_Index; /* Amount of data that has been already read */ + + void *user; /* Additional data that user may need */ +} usbvideo_frame_t; + +/* Statistics that can be overlaid on screen */ +typedef struct { + unsigned long frame_num; /* Sequential number of the frame */ + unsigned long urb_count; /* How many URBs we received so far */ + unsigned long urb_length; /* Length of last URB */ + unsigned long data_count; /* How many bytes we received */ + unsigned long header_count; /* How many frame headers we found */ + unsigned long iso_skip_count; /* How many empty ISO packets received */ + unsigned long iso_err_count; /* How many bad ISO packets received */ +} usbvideo_statistics_t; + +struct s_usbvideo_t; + +typedef struct { + struct video_device vdev; /* Must be the first field! */ + struct usb_device *dev; + struct s_usbvideo_t *handle; /* Points back to the usbvideo_t */ + void *user_data; /* Camera-dependent data */ + int user_size; /* Size of that camera-dependent data */ + int debug; /* Debug level for usbvideo */ + unsigned char iface; /* Video interface number */ + unsigned char video_endp; + unsigned char ifaceAltActive; + unsigned char ifaceAltInactive; /* Alt settings */ + unsigned long flags; /* FLAGS_USBVIDEO_xxx */ + unsigned long paletteBits; /* Which palettes we accept? */ + unsigned short defaultPalette; /* What palette to use for read() */ + struct semaphore lock; + int user; /* user count for exclusive use */ + + videosize_t videosize; /* Current setting */ + videosize_t canvas; /* This is the width,height of the V4L canvas */ + int max_frame_size; /* Bytes in one video frame */ + + int uvd_used; /* Is this structure in use? */ + int streaming; /* Are we streaming Isochronous? */ + int grabbing; /* Are we grabbing? */ + int settingsAdjusted; /* Have we adjusted contrast etc.? */ + int last_error; /* What calamity struck us? */ + + char *fbuf; /* Videodev buffer area */ + int fbuf_size; /* Videodev buffer size */ + + int curframe; + int iso_packet_len; /* Videomode-dependent, saves bus bandwidth */ + + RingQueue_t dp; /* Isoc data pump */ + usbvideo_frame_t frame[USBVIDEO_NUMFRAMES]; + usbvideo_sbuf_t sbuf[USBVIDEO_NUMSBUF]; + + volatile int remove_pending; /* If set then about to exit */ + + struct video_picture vpic, vpic_old; /* Picture settings */ + struct video_capability vcap; /* Video capabilities */ + struct video_channel vchan; /* May be used for tuner support */ + usbvideo_statistics_t stats; + struct proc_dir_entry *procfs_vEntry; /* /proc/video/MYDRIVER/video2 */ + char videoName[32]; /* Holds name like "video7" */ +} uvd_t; + +/* + * usbvideo callbacks (virtual methods). They are set when usbvideo + * services are registered. All of these default to NULL, except those + * that default to usbvideo-provided methods. + */ +typedef struct { +#if defined(usb_device_id_ver) + /* New style probe (for 2.4.x kernels with hotplugging) */ + void *(*probe)(struct usb_device *, unsigned int,const struct usb_device_id *); +#else + /* Old style probe (for 2.2.x kernels) */ + void *(*probe)(struct usb_device *, unsigned int); +#endif + void (*userFree)(uvd_t *); + void (*disconnect)(struct usb_device *, void *); + int (*setupOnOpen)(uvd_t *); + void (*videoStart)(uvd_t *); + void (*videoStop)(uvd_t *); + void (*processData)(uvd_t *, usbvideo_frame_t *); + void (*postProcess)(uvd_t *, usbvideo_frame_t *); + void (*adjustPicture)(uvd_t *); + int (*getFPS)(uvd_t *); + int (*overlayHook)(uvd_t *, usbvideo_frame_t *); + int (*getFrame)(uvd_t *, int); + int (*procfs_read)(char *page,char **start,off_t off,int count,int *eof,void *data); + int (*procfs_write)(struct file *file,const char *buffer,unsigned long count,void *data); +} usbvideo_cb_t; + +struct s_usbvideo_t { + int num_cameras; /* As allocated */ + struct usb_driver usbdrv; /* Interface to the USB stack */ + char drvName[80]; /* Driver name */ + struct semaphore lock; /* Mutex protecting camera structures */ + usbvideo_cb_t cb; /* Table of callbacks (virtual methods) */ + struct video_device vdt; /* Video device template */ + uvd_t *cam; /* Array of camera structures */ + int uses_procfs; /* Non-zero if we create /proc entries */ + struct proc_dir_entry *procfs_dEntry; /* /proc/video/MYDRIVER */ + struct module *md_module; /* Minidriver module */ +}; +typedef struct s_usbvideo_t usbvideo_t; + +/* + * This macro retrieves callback address from the uvd_t object. + * No validity checks are done here, so be sure to check the + * callback beforehand with VALID_CALLBACK. + */ +#define GET_CALLBACK(uvd,cbName) ((uvd)->handle->cb.cbName) + +/* + * This macro returns either callback pointer or NULL. This is safe + * macro, meaning that most of components of data structures involved + * may be NULL - this only results in NULL being returned. You may + * wish to use this macro to make sure that the callback is callable. + * However keep in mind that those checks take time. + */ +#define VALID_CALLBACK(uvd,cbName) ((((uvd) != NULL) && \ + ((uvd)->handle != NULL)) ? GET_CALLBACK(uvd,cbName) : NULL) + +void RingQueue_Initialize(RingQueue_t *rq); +void RingQueue_Allocate(RingQueue_t *rq, int rqLen); +int RingQueue_IsAllocated(const RingQueue_t *rq); +void RingQueue_Free(RingQueue_t *rq); +int RingQueue_Dequeue(RingQueue_t *rq, unsigned char *dst, int len); +int RingQueue_Enqueue(RingQueue_t *rq, const unsigned char *cdata, int n); +int RingQueue_GetLength(const RingQueue_t *rq); +void RingQueue_InterruptibleSleepOn(RingQueue_t *rq); +void RingQueue_WakeUpInterruptible(RingQueue_t *rq); + +void usbvideo_CollectRawData(uvd_t *uvd, usbvideo_frame_t *frame); +void usbvideo_DrawLine( + usbvideo_frame_t *frame, + int x1, int y1, + int x2, int y2, + unsigned char cr, unsigned char cg, unsigned char cb); +void usbvideo_HexDump(const unsigned char *data, int len); +void usbvideo_OverlayChar(uvd_t *uvd, usbvideo_frame_t *frame, int x, int y, int ch); +void usbvideo_OverlayString(uvd_t *uvd, usbvideo_frame_t *frame, int x, int y, const char *str); +void usbvideo_OverlayStats(uvd_t *uvd, usbvideo_frame_t *frame); +void usbvideo_ReportStatistics(const uvd_t *uvd); +void usbvideo_SayAndWait(const char *what); +void usbvideo_TestPattern(uvd_t *uvd, int fullframe, int pmode); +void usbvideo_VideosizeToString(char *buf, int bufLen, videosize_t vs); + +/* Memory allocation routines */ +unsigned long usbvideo_uvirt_to_kva(pgd_t *pgd, unsigned long adr); +unsigned long usbvideo_uvirt_to_bus(unsigned long adr); +unsigned long usbvideo_kvirt_to_bus(unsigned long adr); +unsigned long usbvideo_kvirt_to_pa(unsigned long adr); +void *usbvideo_rvmalloc(unsigned long size); +void usbvideo_rvfree(void *mem, unsigned long size); + +int usbvideo_register( + usbvideo_t **pCams, + const int num_cams, + const int num_extra, + const char *driverName, + const usbvideo_cb_t *cbTable, + struct module *md); +uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams); +int usbvideo_RegisterVideoDevice(uvd_t *uvd); +void usbvideo_Deregister(usbvideo_t **uvt); +void usbvideo_Disconnect(struct usb_device *dev, void *ptr); +void usbvideo_CameraRelease(uvd_t *uvd); + +void usbvideo_v4l_close(struct video_device *dev); +int usbvideo_v4l_initialize(struct video_device *dev); +int usbvideo_v4l_ioctl(struct video_device *dev, unsigned int cmd, void *arg); +int usbvideo_v4l_mmap(struct video_device *dev, const char *adr, unsigned long size); +int usbvideo_v4l_open(struct video_device *dev, int flags); +long usbvideo_v4l_read(struct video_device *dev, char *buf, + unsigned long count, int noblock); +long usbvideo_v4l_write(struct video_device *dev, const char *buf, + unsigned long count, int noblock); + +int usbvideo_GetFrame(uvd_t *uvd, int frameNum); +int usbvideo_NewFrame(uvd_t *uvd, int framenum); +int usbvideo_StartDataPump(uvd_t *uvd); +void usbvideo_StopDataPump(uvd_t *uvd); +void usbvideo_DeinterlaceFrame(uvd_t *uvd, usbvideo_frame_t *frame); +void usbvideo_SoftwareContrastAdjustment(uvd_t *uvd, usbvideo_frame_t *frame); + +/* + * This code performs bounds checking - use it when working with + * new formats, or else you may get oopses all over the place. + * If pixel falls out of bounds then it gets shoved back (as close + * to place of offence as possible) and is painted bright red. + * + * There are two important concepts: frame width, height and + * V4L canvas width, height. The former is the area requested by + * the application -for this very frame-. The latter is the largest + * possible frame that we can serve (we advertise that via V4L ioctl). + * The frame data is expected to be formatted as lines of length + * VIDEOSIZE_X(fr->request), total VIDEOSIZE_Y(frame->request) lines. + */ +static inline void RGB24_PUTPIXEL( + usbvideo_frame_t *fr, + int ix, int iy, + unsigned char vr, + unsigned char vg, + unsigned char vb) +{ + register unsigned char *pf; + int limiter = 0, mx, my; + mx = ix; + my = iy; + if (mx < 0) { + mx=0; + limiter++; + } else if (mx >= VIDEOSIZE_X((fr)->request)) { + mx= VIDEOSIZE_X((fr)->request) - 1; + limiter++; + } + if (my < 0) { + my = 0; + limiter++; + } else if (my >= VIDEOSIZE_Y((fr)->request)) { + my = VIDEOSIZE_Y((fr)->request) - 1; + limiter++; + } + pf = (fr)->data + V4L_BYTES_PER_PIXEL*((iy)*VIDEOSIZE_X((fr)->request) + (ix)); + if (limiter) { + *pf++ = 0; + *pf++ = 0; + *pf++ = 0xFF; + } else { + *pf++ = (vb); + *pf++ = (vg); + *pf++ = (vr); + } +} + +#endif /* usbvideo_h */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/Config.in linux.ac/drivers/video/Config.in --- linux.vanilla/drivers/video/Config.in Thu Jan 4 21:00:55 2001 +++ linux.ac/drivers/video/Config.in Tue Apr 3 17:55:08 2001 @@ -59,6 +59,9 @@ if [ "$CONFIG_ATARI" = "y" ]; then bool ' Atari native chipset support' CONFIG_FB_ATARI tristate ' ATI Mach64 display support' CONFIG_FB_ATY + if [ "$CONFIG_FB_ATY" != "n" ]; then + define_bool CONFIG_FB_ATY_GX y + fi fi if [ "$CONFIG_PPC" = "y" ]; then bool ' Open Firmware frame buffer device support' CONFIG_FB_OF @@ -70,6 +73,9 @@ bool ' S3 Trio display support' CONFIG_FB_S3TRIO tristate ' VGA 16-color graphics console' CONFIG_FB_VGA16 fi + if [ "$CONFIG_PARISC" = "y" ]; then + bool ' Generic STI frame buffer device support' CONFIG_FB_STI + fi if [ "$CONFIG_MAC" = "y" ]; then define_bool CONFIG_FB_MAC y bool ' Apple "valkyrie" display support' CONFIG_FB_VALKYRIE @@ -115,9 +121,18 @@ bool ' Multihead support' CONFIG_FB_MATROX_MULTIHEAD fi tristate ' ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY - tristate ' ATI Rage 128 display support (EXPERIMENTAL)' CONFIG_FB_ATY128 + if [ "$CONFIG_FB_ATY" != "n" ]; then + bool ' Mach64 GX support (EXPERIMENTAL)' CONFIG_FB_ATY_GX + bool ' Mach64 CT/VT/GT/LT (incl. 3D RAGE) support' CONFIG_FB_ATY_CT + fi + tristate ' ATI Radeon display support (EXPERIMENTAL)' CONFIG_FB_RADEON + tristate ' ATI Rage128 display support (EXPERIMENTAL)' CONFIG_FB_ATY128 + tristate ' SIS acceleration (EXPERIMENTAL)' CONFIG_FB_SIS + if [ "$CONFIG_FB_SIS" != "n" ]; then + bool ' SIS 630/540/730 support' CONFIG_FB_SIS_300 + bool ' SIS 315H/315 support' CONFIG_FB_SIS_315 + fi tristate ' 3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX - tristate ' SIS 630/540 display support (EXPERIMENTAL)' CONFIG_FB_SIS fi fi if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then @@ -150,12 +165,22 @@ bool ' PCI framebuffers' CONFIG_FB_PCI if [ "$CONFIG_FB_PCI" != "n" ]; then tristate ' ATI Mach64 display support' CONFIG_FB_ATY + if [ "$CONFIG_FB_ATY" != "n" ]; then + define_bool CONFIG_FB_ATY_CT y + fi fi fi fi if [ "$CONFIG_HD64461" = "y" ]; then tristate ' HD64461 Frame Buffer support' CONFIG_FB_HIT fi + if [ "$CONFIG_DECSTATION" = "y" ]; then + if [ "$CONFIG_TC" = "y" ]; then + bool ' PMAG-BA TURBOchannel framebuffer support' CONFIG_FB_PMAG_BA + bool ' PMAGB-B TURBOchannel framebuffer spport' CONFIG_FB_PMAGB_B + bool ' Maxine (Personal DECstation) onboard framebuffer spport' CONFIG_FB_MAXINE + fi + fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL fi @@ -219,9 +244,11 @@ "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \ "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ "$CONFIG_FB_P9100" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ - "$CONFIG_FB_RIVA" = "y" -o \ + "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \ "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \ "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \ + "$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \ + "$CONFIG_FB_MAXINE" = "y" -o \ "$CONFIG_FB_SIS" = "y" ]; then define_tristate CONFIG_FBCON_CFB8 y else @@ -239,6 +266,8 @@ "$CONFIG_FB_P9100" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_3DFX" = "m" -o \ "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \ + "$CONFIG_FB_PMAG_BA" = "m" -o "CONFIG_FB_PMAGB_B" = "m" -o \ + "$CONFIG_FB_MAXINE" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \ "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" ]; then define_tristate CONFIG_FBCON_CFB8 m fi @@ -246,7 +275,7 @@ if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \ "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \ - "$CONFIG_FB_Q40" = "y" -o \ + "$CONFIG_FB_Q40" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \ "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ @@ -268,21 +297,21 @@ "$CONFIG_FB_PM2" = "m" -o "$CONFIG_FB_SGIVW" = "m" -o \ "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \ - "$CONFIG_FB_SA1100" = "m" ]; then + "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" ]; then define_tristate CONFIG_FBCON_CFB16 m fi fi if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" -o \ "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ - "$CONFIG_FB_ATY128" = "y" -o \ + "$CONFIG_FB_ATY128" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \ "$CONFIG_FB_CYBER2000" = "y" ]; then define_tristate CONFIG_FBCON_CFB24 y else if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" -o \ "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ - "$CONFIG_FB_ATY128" = "m" -o \ + "$CONFIG_FB_ATY128" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \ "$CONFIG_FB_CYBER2000" = "m" ]; then define_tristate CONFIG_FBCON_CFB24 m fi @@ -294,6 +323,7 @@ "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ + "$CONFIG_FB_RADEON" = "y" -o \ "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_SIS" = "y" ]; then define_tristate CONFIG_FBCON_CFB32 y else @@ -303,7 +333,7 @@ "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ - "$CONFIG_FB_3DFX" = "m" -o \ + "$CONFIG_FB_3DFX" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \ "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" ]; then define_tristate CONFIG_FBCON_CFB32 m fi @@ -350,6 +380,9 @@ if [ "$CONFIG_FB_HGA" = "m" ]; then define_tristate CONFIG_FBCON_HGA m fi + fi + if [ "$CONFIG_FB_STI" = "y" ]; then + define_tristate CONFIG_FBCON_STI y fi fi bool ' Support only 8 pixels wide fonts' CONFIG_FBCON_FONTWIDTH8_ONLY diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/Makefile linux.ac/drivers/video/Makefile --- linux.vanilla/drivers/video/Makefile Fri Dec 29 22:07:23 2000 +++ linux.ac/drivers/video/Makefile Tue Apr 3 17:55:08 2001 @@ -22,6 +22,7 @@ obj-$(CONFIG_DUMMY_CONSOLE) += dummycon.o obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o obj-$(CONFIG_PROM_CONSOLE) += promcon.o promcon_tbl.o +obj-$(CONFIG_STI_CONSOLE) += sticon.o sticon-bmode.o sticore.o obj-$(CONFIG_VGA_CONSOLE) += vgacon.o obj-$(CONFIG_MDA_CONSOLE) += mdacon.o @@ -46,8 +47,8 @@ obj-$(CONFIG_FB_APOLLO) += dnfb.o obj-$(CONFIG_FB_Q40) += q40fb.o obj-$(CONFIG_FB_ATARI) += atafb.o -obj-$(CONFIG_FB_ATY) += atyfb.o obj-$(CONFIG_FB_ATY128) += aty128fb.o +obj-$(CONFIG_FB_RADEON) += radeonfb.o obj-$(CONFIG_FB_IGA) += igafb.o obj-$(CONFIG_FB_CONTROL) += controlfb.o obj-$(CONFIG_FB_PLATINUM) += platinumfb.o @@ -78,6 +79,10 @@ obj-$(CONFIG_FB_CGFOURTEEN) += cgfourteenfb.o sbusfb.o obj-$(CONFIG_FB_P9100) += p9100fb.o sbusfb.o obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o +obj-$(CONFIG_FB_STI) += stifb.o sticore.o fbgen.o +obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o +obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o +obj-$(CONFIG_FB_MAXINE) += maxinefb.o subdir-$(CONFIG_FB_MATROX) += matrox ifeq ($(CONFIG_FB_MATROX),y) @@ -94,6 +99,11 @@ obj-y += sis/sisfb.o endif +subdir-$(CONFIG_FB_ATY) += aty +ifeq ($(CONFIG_FB_ATY),y) +obj-y += aty/atyfb.o +endif + obj-$(CONFIG_FB_SUN3) += sun3fb.o obj-$(CONFIG_FB_BWTWO) += bwtwofb.o obj-$(CONFIG_FB_HGA) += hgafb.o @@ -119,6 +129,7 @@ obj-$(CONFIG_FBCON_MFB) += fbcon-mfb.o obj-$(CONFIG_FBCON_VGA) += fbcon-vga.o obj-$(CONFIG_FBCON_HGA) += fbcon-hga.o +obj-$(CONFIG_FBCON_STI) += fbcon-sti.o include $(TOPDIR)/Rules.make @@ -134,3 +145,4 @@ -e 's/dfont\(_uni.*\]\)/promfont\1 __initdata/' > promcon_tbl.c promcon_tbl.o: promcon_tbl.c $(TOPDIR)/include/linux/types.h + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/acornfb.c linux.ac/drivers/video/acornfb.c --- linux.vanilla/drivers/video/acornfb.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/acornfb.c Mon Apr 9 23:32:17 2001 @@ -263,28 +263,28 @@ vidc.v_border_end = vidc.v_display_end; #ifdef CONFIG_ARCH_A5K - outb(vid_ctl, IOEB_VID_CTL); + __raw_writeb(vid_ctl, IOEB_VID_CTL); #endif if (memcmp(¤t_vidc, &vidc, sizeof(vidc))) { current_vidc = vidc; - outl(0xe0000000 | vidc_ctl, IO_VIDC_BASE); - outl(0x80000000 | (vidc.h_cycle << 14), IO_VIDC_BASE); - outl(0x84000000 | (vidc.h_sync_width << 14), IO_VIDC_BASE); - outl(0x88000000 | (vidc.h_border_start << 14), IO_VIDC_BASE); - outl(0x8c000000 | (vidc.h_display_start << 14), IO_VIDC_BASE); - outl(0x90000000 | (vidc.h_display_end << 14), IO_VIDC_BASE); - outl(0x94000000 | (vidc.h_border_end << 14), IO_VIDC_BASE); - outl(0x98000000, IO_VIDC_BASE); - outl(0x9c000000 | (vidc.h_interlace << 14), IO_VIDC_BASE); - outl(0xa0000000 | (vidc.v_cycle << 14), IO_VIDC_BASE); - outl(0xa4000000 | (vidc.v_sync_width << 14), IO_VIDC_BASE); - outl(0xa8000000 | (vidc.v_border_start << 14), IO_VIDC_BASE); - outl(0xac000000 | (vidc.v_display_start << 14), IO_VIDC_BASE); - outl(0xb0000000 | (vidc.v_display_end << 14), IO_VIDC_BASE); - outl(0xb4000000 | (vidc.v_border_end << 14), IO_VIDC_BASE); - outl(0xb8000000, IO_VIDC_BASE); - outl(0xbc000000, IO_VIDC_BASE); + vidc_writel(0xe0000000 | vidc_ctl); + vidc_writel(0x80000000 | (vidc.h_cycle << 14)); + vidc_writel(0x84000000 | (vidc.h_sync_width << 14)); + vidc_writel(0x88000000 | (vidc.h_border_start << 14)); + vidc_writel(0x8c000000 | (vidc.h_display_start << 14)); + vidc_writel(0x90000000 | (vidc.h_display_end << 14)); + vidc_writel(0x94000000 | (vidc.h_border_end << 14)); + vidc_writel(0x98000000); + vidc_writel(0x9c000000 | (vidc.h_interlace << 14)); + vidc_writel(0xa0000000 | (vidc.v_cycle << 14)); + vidc_writel(0xa4000000 | (vidc.v_sync_width << 14)); + vidc_writel(0xa8000000 | (vidc.v_border_start << 14)); + vidc_writel(0xac000000 | (vidc.v_display_start << 14)); + vidc_writel(0xb0000000 | (vidc.v_display_end << 14)); + vidc_writel(0xb4000000 | (vidc.v_border_end << 14)); + vidc_writel(0xb8000000); + vidc_writel(0xbc000000); } #ifdef DEBUG_MODE_SELECTION printk(KERN_DEBUG "VIDC registers for %dx%dx%d:\n", var->xres, @@ -310,7 +310,7 @@ static inline void acornfb_palette_write(u_int regno, union palette pal) { - outl(pal.p, IO_VIDC_BASE); + vidc_writel(pal.p); } static inline union palette @@ -402,27 +402,27 @@ if (memcmp(¤t_vidc, &vidc, sizeof(vidc))) { current_vidc = vidc; - outl(VIDC20_CTRL| vidc.control, IO_VIDC_BASE); - outl(0xd0000000 | vidc.pll_ctl, IO_VIDC_BASE); - outl(0x80000000 | vidc.h_cycle, IO_VIDC_BASE); - outl(0x81000000 | vidc.h_sync_width, IO_VIDC_BASE); - outl(0x82000000 | vidc.h_border_start, IO_VIDC_BASE); - outl(0x83000000 | vidc.h_display_start, IO_VIDC_BASE); - outl(0x84000000 | vidc.h_display_end, IO_VIDC_BASE); - outl(0x85000000 | vidc.h_border_end, IO_VIDC_BASE); - outl(0x86000000, IO_VIDC_BASE); - outl(0x87000000 | vidc.h_interlace, IO_VIDC_BASE); - outl(0x90000000 | vidc.v_cycle, IO_VIDC_BASE); - outl(0x91000000 | vidc.v_sync_width, IO_VIDC_BASE); - outl(0x92000000 | vidc.v_border_start, IO_VIDC_BASE); - outl(0x93000000 | vidc.v_display_start, IO_VIDC_BASE); - outl(0x94000000 | vidc.v_display_end, IO_VIDC_BASE); - outl(0x95000000 | vidc.v_border_end, IO_VIDC_BASE); - outl(0x96000000, IO_VIDC_BASE); - outl(0x97000000, IO_VIDC_BASE); + vidc_writel(VIDC20_CTRL| vidc.control); + vidc_writel(0xd0000000 | vidc.pll_ctl); + vidc_writel(0x80000000 | vidc.h_cycle); + vidc_writel(0x81000000 | vidc.h_sync_width); + vidc_writel(0x82000000 | vidc.h_border_start); + vidc_writel(0x83000000 | vidc.h_display_start); + vidc_writel(0x84000000 | vidc.h_display_end); + vidc_writel(0x85000000 | vidc.h_border_end); + vidc_writel(0x86000000); + vidc_writel(0x87000000 | vidc.h_interlace); + vidc_writel(0x90000000 | vidc.v_cycle); + vidc_writel(0x91000000 | vidc.v_sync_width); + vidc_writel(0x92000000 | vidc.v_border_start); + vidc_writel(0x93000000 | vidc.v_display_start); + vidc_writel(0x94000000 | vidc.v_display_end); + vidc_writel(0x95000000 | vidc.v_border_end); + vidc_writel(0x96000000); + vidc_writel(0x97000000); } - outl(fsize, IOMD_FSIZE); + iomd_writel(fsize, IOMD_FSIZE); ext_ctl = acornfb_default_econtrol(); @@ -440,7 +440,7 @@ ext_ctl |= VIDC20_ECTL_VS_NVSYNC; } - outl(VIDC20_ECTL | ext_ctl, IO_VIDC_BASE); + vidc_writel(VIDC20_ECTL | ext_ctl); words_per_line = var->xres * var->bits_per_pixel / 32; @@ -461,7 +461,7 @@ } else dat_ctl |= VIDC20_DCTL_BUS_D31_0; - outl(VIDC20_DCTL | dat_ctl, IO_VIDC_BASE); + vidc_writel(VIDC20_DCTL | dat_ctl); #ifdef DEBUG_MODE_SELECTION printk(KERN_DEBUG "VIDC registers for %dx%dx%d:\n", var->xres, @@ -490,8 +490,8 @@ static inline void acornfb_palette_write(u_int regno, union palette pal) { - outl(0x10000000 | regno, IO_VIDC_BASE); - outl(pal.p, IO_VIDC_BASE); + vidc_writel(0x10000000 | regno); + vidc_writel(pal.p); } static inline union palette @@ -672,7 +672,7 @@ #if defined(HAS_MEMC) memc_write(VDMA_INIT, off >> 2); #elif defined(HAS_IOMD) - outl(current_par.screen_base_p + off, IOMD_VIDINIT); + iomd_writel(current_par.screen_base_p + off, IOMD_VIDINIT); #endif } @@ -744,12 +744,12 @@ int i; pal.p = 0; - outl(0x10000000, IO_VIDC_BASE); + vidc_writel(0x10000000); for (i = 0; i < 256; i += 1) { pal.vidc20.red = current_par.palette[ i & 31].vidc20.red; pal.vidc20.green = current_par.palette[(i >> 1) & 31].vidc20.green; pal.vidc20.blue = current_par.palette[(i >> 2) & 31].vidc20.blue; - outl(pal.p, IO_VIDC_BASE); + vidc_writel(pal.p); /* Palette register pointer auto-increments */ } } else @@ -1074,9 +1074,9 @@ control = DMA_CR_E | DMA_CR_D | 16; } - outl(start, IOMD_VIDSTART); - outl(size, IOMD_VIDEND); - outl(control, IOMD_VIDCR); + iomd_writel(start, IOMD_VIDSTART); + iomd_writel(size, IOMD_VIDEND); + iomd_writel(control, IOMD_VIDCR); #endif acornfb_update_dma(var); acornfb_set_timing(var); @@ -1119,6 +1119,45 @@ return 0; } +/* + * Note that we are entered with the kernel locked. + */ +static int +acornfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma) +{ + unsigned long off, start; + u32 len; + + off = vma->vm_pgoff << PAGE_SHIFT; + + start = current_par.screen_base_p; + len = PAGE_ALIGN(start & ~PAGE_MASK) + current_par.screen_size; + start &= PAGE_MASK; + if ((vma->vm_end - vma->vm_start + off) > len) + return -EINVAL; + off += start; + vma->vm_pgoff = off >> PAGE_SHIFT; + + /* This is an IO map - tell maydump to skip this VMA */ + vma->vm_flags |= VM_IO; + +#ifdef CONFIG_CPU_32 + pgprot_val(vma->vm_page_prot) &= ~L_PTE_CACHEABLE; +#endif + + /* + * Don't alter the page protection flags; we want to keep the area + * cached for better performance. This does mean that we may miss + * some updates to the screen occasionally, but process switches + * should cause the caches and buffers to be flushed often enough. + */ + if (io_remap_page_range(vma->vm_start, off, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + return 0; +} + static struct fb_ops acornfb_ops = { owner: THIS_MODULE, fb_get_fix: acornfb_get_fix, @@ -1127,6 +1166,7 @@ fb_get_cmap: acornfb_get_cmap, fb_set_cmap: acornfb_set_cmap, fb_pan_display: acornfb_pan_display, + fb_mmap: acornfb_mmap, }; static int diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/amifb.c linux.ac/drivers/video/amifb.c --- linux.vanilla/drivers/video/amifb.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/amifb.c Tue Apr 3 17:55:08 2001 @@ -256,7 +256,7 @@ - for horizontal panning decrease diwstrt_h - the length of a fetchline must be aligned to fetchsize (table 3) - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit - moved to optimize use of dma (usefull for OCS/ECS overscan displays) + moved to optimize use of dma (useful for OCS/ECS overscan displays) - ddfstop is ddfstrt+ddfsize-fetchsize - If C= didn't change anything for AGA, then at following positions the dma bus is allready used: @@ -2106,7 +2106,7 @@ return -EINVAL; } if (par->diwstop_v > par->vtotal) { - DPRINTK("invaild diwstop_v\n"); + DPRINTK("invalid diwstop_v\n"); return -EINVAL; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/atafb.c linux.ac/drivers/video/atafb.c --- linux.vanilla/drivers/video/atafb.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/atafb.c Tue Apr 3 17:55:08 2001 @@ -208,7 +208,7 @@ /* The MV300 mixes the color registers. So we need an array of munged -indices in order to acces the correct reg. +indices in order to access the correct reg. */ static int MV300_reg_1bit[2]={0,1}; static int MV300_reg_4bit[16]={ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/aty/Makefile linux.ac/drivers/video/aty/Makefile --- linux.vanilla/drivers/video/aty/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/aty/Makefile Tue Apr 3 17:55:08 2001 @@ -0,0 +1,12 @@ + +O_TARGET := atyfb.o + +export-objs := atyfb_base.o mach64_accel.o + +obj-y := atyfb_base.o mach64_accel.o +obj-$(CONFIG_FB_ATY_GX) += mach64_gx.o +obj-$(CONFIG_FB_ATY_CT) += mach64_ct.o mach64_cursor.o +obj-m := $(O_TARGET) + +include $(TOPDIR)/Rules.make + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/aty/aty.h linux.ac/drivers/video/aty/aty.h --- linux.vanilla/drivers/video/aty/aty.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/aty/aty.h Tue Apr 3 17:55:08 2001 @@ -0,0 +1,1011 @@ +/* + * Exported procedures for the ATI/mach64 display driver on PowerMacs. + * + * Copyright (C) 1997 Michael AK Tesch + * written with much help from Jon Howell + * + * Updated for 3D RAGE PRO by Geert Uytterhoeven + * + * 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. + */ + +/* + * most of the rest of this file comes from ATI sample code + */ +#ifndef REGMACH64_H +#define REGMACH64_H + +/* NON-GUI MEMORY MAPPED Registers - expressed in BYTE offsets */ + +#define CRTC_H_TOTAL_DISP 0x0000 /* Dword offset 0_00 */ +#define CRTC_H_SYNC_STRT_WID 0x0004 /* Dword offset 0_01 */ +#define CRTC_H_SYNC_STRT 0x0004 +#define CRTC_H_SYNC_DLY 0x0005 +#define CRTC_H_SYNC_WID 0x0006 + +#define CRTC_V_TOTAL_DISP 0x0008 /* Dword offset 0_02 */ +#define CRTC_V_TOTAL 0x0008 +#define CRTC_V_DISP 0x000A +#define CRTC_V_SYNC_STRT_WID 0x000C /* Dword offset 0_03 */ +#define CRTC_V_SYNC_STRT 0x000C +#define CRTC_V_SYNC_WID 0x000E + +#define CRTC_VLINE_CRNT_VLINE 0x0010 /* Dword offset 0_04 */ +#define CRTC_OFF_PITCH 0x0014 /* Dword offset 0_05 */ +#define CRTC_OFFSET 0x0014 +#define CRTC_PITCH 0x0016 + +#define CRTC_INT_CNTL 0x0018 /* Dword offset 0_06 */ +#define CRTC_GEN_CNTL 0x001C /* Dword offset 0_07 */ +#define CRTC_PIX_WIDTH 0x001D +#define CRTC_FIFO 0x001E +#define CRTC_EXT_DISP 0x001F + +#define DSP_CONFIG 0x0020 /* Dword offset 0_08 */ +#define DSP_ON_OFF 0x0024 /* Dword offset 0_09 */ +#define TIMER_CONFIG 0x0028 /* Dword offset 0_0A */ +#define MEM_BUF_CNTL 0x002C /* Dword offset 0_0B */ +#define MEM_ADDR_CONFIG 0x0034 /* Dword offset 0_0D */ + +#define CRT_TRAP 0x0038 /* Dword offset 0_0E */ + +#define I2C_CNTL_0 0x003C /* Dword offset 0_0F */ + +#define OVR_CLR 0x0040 /* Dword offset 0_10 */ +#define OVR_WID_LEFT_RIGHT 0x0044 /* Dword offset 0_11 */ +#define OVR_WID_TOP_BOTTOM 0x0048 /* Dword offset 0_12 */ + +#define VGA_DSP_CONFIG 0x004C /* Dword offset 0_13 */ +#define VGA_DSP_ON_OFF 0x0050 /* Dword offset 0_14 */ + +#define CUR_CLR0 0x0060 /* Dword offset 0_18 */ +#define CUR_CLR1 0x0064 /* Dword offset 0_19 */ +#define CUR_OFFSET 0x0068 /* Dword offset 0_1A */ +#define CUR_HORZ_VERT_POSN 0x006C /* Dword offset 0_1B */ +#define CUR_HORZ_VERT_OFF 0x0070 /* Dword offset 0_1C */ + +#define CONFIG_PANEL_LG 0x0074 /* Dword offset 0_1D */ + +#define GP_IO 0x0078 /* Dword offset 0_1E */ + +#define HW_DEBUG 0x007C /* Dword offset 0_1F */ + +#define SCRATCH_REG0 0x0080 /* Dword offset 0_20 */ +#define SCRATCH_REG1 0x0084 /* Dword offset 0_21 */ + +#define CLOCK_CNTL 0x0090 /* Dword offset 0_24 */ +#define CLOCK_SEL_CNTL 0x0090 /* Dword offset 0_24 */ + +#define CONFIG_STAT1 0x0094 /* Dword offset 0_25 */ +#define CONFIG_STAT2 0x0098 /* Dword offset 0_26 */ + +#define BUS_CNTL 0x00A0 /* Dword offset 0_28 */ + +#define LCD_INDEX 0x00A4 /* Dword offset 0_29 */ +#define LCD_DATA 0x00A8 /* Dword offset 0_2A */ + +#define EXT_MEM_CNTL 0x00AC /* Dword offset 0_2B */ +#define MEM_CNTL 0x00B0 /* Dword offset 0_2C */ + +#define MEM_VGA_WP_SEL 0x00B4 /* Dword offset 0_2D */ +#define MEM_VGA_RP_SEL 0x00B8 /* Dword offset 0_2E */ + +#define I2C_CNTL_1 0x00BC /* Dword offset 0_2F */ + +#define DAC_REGS 0x00C0 /* Dword offset 0_30 */ +#define DAC_W_INDEX 0x00C0 /* Dword offset 0_30 */ +#define DAC_DATA 0x00C1 /* Dword offset 0_30 */ +#define DAC_MASK 0x00C2 /* Dword offset 0_30 */ +#define DAC_R_INDEX 0x00C3 /* Dword offset 0_30 */ +#define DAC_CNTL 0x00C4 /* Dword offset 0_31 */ + +#define EXT_DAC_REGS 0x00C8 /* Dword offset 0_32 */ + +#define GEN_TEST_CNTL 0x00D0 /* Dword offset 0_34 */ + +#define CUSTOM_MACRO_CNTL 0x00D4 /* Dword offset 0_35 */ +#define LCD_GEN_CNTL_LG 0x00D4 /* Dword offset 0_35 */ + +#define POWER_MANAGEMENT_LG 0x00D8 /* Dword offset 0_36 (LG) */ + +#define CONFIG_CNTL 0x00DC /* Dword offset 0_37 (CT, ET, VT) */ +#define CONFIG_CHIP_ID 0x00E0 /* Dword offset 0_38 */ +#define CONFIG_STAT0 0x00E4 /* Dword offset 0_39 */ +#define CRC_SIG 0x00E8 /* Dword offset 0_3A */ + + +/* GUI MEMORY MAPPED Registers */ + +#define DST_OFF_PITCH 0x0100 /* Dword offset 0_40 */ +#define DST_X 0x0104 /* Dword offset 0_41 */ +#define DST_Y 0x0108 /* Dword offset 0_42 */ +#define DST_Y_X 0x010C /* Dword offset 0_43 */ +#define DST_WIDTH 0x0110 /* Dword offset 0_44 */ +#define DST_HEIGHT 0x0114 /* Dword offset 0_45 */ +#define DST_HEIGHT_WIDTH 0x0118 /* Dword offset 0_46 */ +#define DST_X_WIDTH 0x011C /* Dword offset 0_47 */ +#define DST_BRES_LNTH 0x0120 /* Dword offset 0_48 */ +#define DST_BRES_ERR 0x0124 /* Dword offset 0_49 */ +#define DST_BRES_INC 0x0128 /* Dword offset 0_4A */ +#define DST_BRES_DEC 0x012C /* Dword offset 0_4B */ +#define DST_CNTL 0x0130 /* Dword offset 0_4C */ +#define DST_Y_X__ALIAS__ 0x0134 /* Dword offset 0_4D */ +#define TRAIL_BRES_ERR 0x0138 /* Dword offset 0_4E */ +#define TRAIL_BRES_INC 0x013C /* Dword offset 0_4F */ +#define TRAIL_BRES_DEC 0x0140 /* Dword offset 0_50 */ +#define LEAD_BRES_LNTH 0x0144 /* Dword offset 0_51 */ +#define Z_OFF_PITCH 0x0148 /* Dword offset 0_52 */ +#define Z_CNTL 0x014C /* Dword offset 0_53 */ +#define ALPHA_TST_CNTL 0x0150 /* Dword offset 0_54 */ +#define SECONDARY_STW_EXP 0x0158 /* Dword offset 0_56 */ +#define SECONDARY_S_X_INC 0x015C /* Dword offset 0_57 */ +#define SECONDARY_S_Y_INC 0x0160 /* Dword offset 0_58 */ +#define SECONDARY_S_START 0x0164 /* Dword offset 0_59 */ +#define SECONDARY_W_X_INC 0x0168 /* Dword offset 0_5A */ +#define SECONDARY_W_Y_INC 0x016C /* Dword offset 0_5B */ +#define SECONDARY_W_START 0x0170 /* Dword offset 0_5C */ +#define SECONDARY_T_X_INC 0x0174 /* Dword offset 0_5D */ +#define SECONDARY_T_Y_INC 0x0178 /* Dword offset 0_5E */ +#define SECONDARY_T_START 0x017C /* Dword offset 0_5F */ + +#define SRC_OFF_PITCH 0x0180 /* Dword offset 0_60 */ +#define SRC_X 0x0184 /* Dword offset 0_61 */ +#define SRC_Y 0x0188 /* Dword offset 0_62 */ +#define SRC_Y_X 0x018C /* Dword offset 0_63 */ +#define SRC_WIDTH1 0x0190 /* Dword offset 0_64 */ +#define SRC_HEIGHT1 0x0194 /* Dword offset 0_65 */ +#define SRC_HEIGHT1_WIDTH1 0x0198 /* Dword offset 0_66 */ +#define SRC_X_START 0x019C /* Dword offset 0_67 */ +#define SRC_Y_START 0x01A0 /* Dword offset 0_68 */ +#define SRC_Y_X_START 0x01A4 /* Dword offset 0_69 */ +#define SRC_WIDTH2 0x01A8 /* Dword offset 0_6A */ +#define SRC_HEIGHT2 0x01AC /* Dword offset 0_6B */ +#define SRC_HEIGHT2_WIDTH2 0x01B0 /* Dword offset 0_6C */ +#define SRC_CNTL 0x01B4 /* Dword offset 0_6D */ + +#define SCALE_OFF 0x01C0 /* Dword offset 0_70 */ +#define SECONDARY_SCALE_OFF 0x01C4 /* Dword offset 0_71 */ + +#define TEX_0_OFF 0x01C0 /* Dword offset 0_70 */ +#define TEX_1_OFF 0x01C4 /* Dword offset 0_71 */ +#define TEX_2_OFF 0x01C8 /* Dword offset 0_72 */ +#define TEX_3_OFF 0x01CC /* Dword offset 0_73 */ +#define TEX_4_OFF 0x01D0 /* Dword offset 0_74 */ +#define TEX_5_OFF 0x01D4 /* Dword offset 0_75 */ +#define TEX_6_OFF 0x01D8 /* Dword offset 0_76 */ +#define TEX_7_OFF 0x01DC /* Dword offset 0_77 */ + +#define SCALE_WIDTH 0x01DC /* Dword offset 0_77 */ +#define SCALE_HEIGHT 0x01E0 /* Dword offset 0_78 */ + +#define TEX_8_OFF 0x01E0 /* Dword offset 0_78 */ +#define TEX_9_OFF 0x01E4 /* Dword offset 0_79 */ +#define TEX_10_OFF 0x01E8 /* Dword offset 0_7A */ +#define S_Y_INC 0x01EC /* Dword offset 0_7B */ + +#define SCALE_PITCH 0x01EC /* Dword offset 0_7B */ +#define SCALE_X_INC 0x01F0 /* Dword offset 0_7C */ + +#define RED_X_INC 0x01F0 /* Dword offset 0_7C */ +#define GREEN_X_INC 0x01F4 /* Dword offset 0_7D */ + +#define SCALE_Y_INC 0x01F4 /* Dword offset 0_7D */ +#define SCALE_VACC 0x01F8 /* Dword offset 0_7E */ +#define SCALE_3D_CNTL 0x01FC /* Dword offset 0_7F */ + +#define HOST_DATA0 0x0200 /* Dword offset 0_80 */ +#define HOST_DATA1 0x0204 /* Dword offset 0_81 */ +#define HOST_DATA2 0x0208 /* Dword offset 0_82 */ +#define HOST_DATA3 0x020C /* Dword offset 0_83 */ +#define HOST_DATA4 0x0210 /* Dword offset 0_84 */ +#define HOST_DATA5 0x0214 /* Dword offset 0_85 */ +#define HOST_DATA6 0x0218 /* Dword offset 0_86 */ +#define HOST_DATA7 0x021C /* Dword offset 0_87 */ +#define HOST_DATA8 0x0220 /* Dword offset 0_88 */ +#define HOST_DATA9 0x0224 /* Dword offset 0_89 */ +#define HOST_DATAA 0x0228 /* Dword offset 0_8A */ +#define HOST_DATAB 0x022C /* Dword offset 0_8B */ +#define HOST_DATAC 0x0230 /* Dword offset 0_8C */ +#define HOST_DATAD 0x0234 /* Dword offset 0_8D */ +#define HOST_DATAE 0x0238 /* Dword offset 0_8E */ +#define HOST_DATAF 0x023C /* Dword offset 0_8F */ +#define HOST_CNTL 0x0240 /* Dword offset 0_90 */ + +#define BM_HOSTDATA 0x0244 /* Dword offset 0_91 */ +#define BM_ADDR 0x0248 /* Dword offset 0_92 */ +#define BM_DATA 0x0248 /* Dword offset 0_92 */ +#define BM_GUI_TABLE_CMD 0x024C /* Dword offset 0_93 */ + +#define PAT_REG0 0x0280 /* Dword offset 0_A0 */ +#define PAT_REG1 0x0284 /* Dword offset 0_A1 */ +#define PAT_CNTL 0x0288 /* Dword offset 0_A2 */ + +#define SC_LEFT 0x02A0 /* Dword offset 0_A8 */ +#define SC_RIGHT 0x02A4 /* Dword offset 0_A9 */ +#define SC_LEFT_RIGHT 0x02A8 /* Dword offset 0_AA */ +#define SC_TOP 0x02AC /* Dword offset 0_AB */ +#define SC_BOTTOM 0x02B0 /* Dword offset 0_AC */ +#define SC_TOP_BOTTOM 0x02B4 /* Dword offset 0_AD */ + +#define DP_BKGD_CLR 0x02C0 /* Dword offset 0_B0 */ +#define DP_FOG_CLR 0x02C4 /* Dword offset 0_B1 */ +#define DP_FRGD_CLR 0x02C4 /* Dword offset 0_B1 */ +#define DP_WRITE_MASK 0x02C8 /* Dword offset 0_B2 */ +#define DP_CHAIN_MASK 0x02CC /* Dword offset 0_B3 */ +#define DP_PIX_WIDTH 0x02D0 /* Dword offset 0_B4 */ +#define DP_MIX 0x02D4 /* Dword offset 0_B5 */ +#define DP_SRC 0x02D8 /* Dword offset 0_B6 */ +#define DP_FRGD_CLR_MIX 0x02DC /* Dword offset 0_B7 */ +#define DP_FRGD_BLGD_CLR 0x02E0 /* Dword offset 0_B8 */ + +#define DST_X_Y 0x02E8 /* Dword offset 0_BA */ +#define DST_WIDTH_HEIGHT 0x02EC /* Dword offset 0_BB */ +#define USR_DST_PICTH 0x02F0 /* Dword offset 0_BC */ +#define DP_SET_GUI_ENGINE2 0x02F8 /* Dword offset 0_BE */ +#define DP_SET_GUI_ENGINE 0x02FC /* Dword offset 0_BF */ + +#define CLR_CMP_CLR 0x0300 /* Dword offset 0_C0 */ +#define CLR_CMP_MASK 0x0304 /* Dword offset 0_C1 */ +#define CLR_CMP_CNTL 0x0308 /* Dword offset 0_C2 */ + +#define FIFO_STAT 0x0310 /* Dword offset 0_C4 */ + +#define CONTEXT_MASK 0x0320 /* Dword offset 0_C8 */ +#define CONTEXT_LOAD_CNTL 0x032C /* Dword offset 0_CB */ + +#define GUI_TRAJ_CNTL 0x0330 /* Dword offset 0_CC */ +#define GUI_STAT 0x0338 /* Dword offset 0_CE */ + +#define TEX_PALETTE_INDEX 0x0340 /* Dword offset 0_D0 */ +#define STW_EXP 0x0344 /* Dword offset 0_D1 */ +#define LOG_MAX_INC 0x0348 /* Dword offset 0_D2 */ +#define S_X_INC 0x034C /* Dword offset 0_D3 */ +#define S_Y_INC__ALIAS__ 0x0350 /* Dword offset 0_D4 */ + +#define SCALE_PITCH__ALIAS__ 0x0350 /* Dword offset 0_D4 */ + +#define S_START 0x0354 /* Dword offset 0_D5 */ +#define W_X_INC 0x0358 /* Dword offset 0_D6 */ +#define W_Y_INC 0x035C /* Dword offset 0_D7 */ +#define W_START 0x0360 /* Dword offset 0_D8 */ +#define T_X_INC 0x0364 /* Dword offset 0_D9 */ +#define T_Y_INC 0x0368 /* Dword offset 0_DA */ + +#define SECONDARY_SCALE_PITCH 0x0368 /* Dword offset 0_DA */ + +#define T_START 0x036C /* Dword offset 0_DB */ +#define TEX_SIZE_PITCH 0x0370 /* Dword offset 0_DC */ +#define TEX_CNTL 0x0374 /* Dword offset 0_DD */ +#define SECONDARY_TEX_OFFSET 0x0378 /* Dword offset 0_DE */ +#define TEX_PALETTE 0x037C /* Dword offset 0_DF */ + +#define SCALE_PITCH_BOTH 0x0380 /* Dword offset 0_E0 */ +#define SECONDARY_SCALE_OFF_ACC 0x0384 /* Dword offset 0_E1 */ +#define SCALE_OFF_ACC 0x0388 /* Dword offset 0_E2 */ +#define SCALE_DST_Y_X 0x038C /* Dword offset 0_E3 */ + +#define COMPOSITE_SHADOW_ID 0x0398 /* Dword offset 0_E6 */ + +#define SECONDARY_SCALE_X_INC 0x039C /* Dword offset 0_E7 */ + +#define SPECULAR_RED_X_INC 0x039C /* Dword offset 0_E7 */ +#define SPECULAR_RED_Y_INC 0x03A0 /* Dword offset 0_E8 */ +#define SPECULAR_RED_START 0x03A4 /* Dword offset 0_E9 */ + +#define SECONDARY_SCALE_HACC 0x03A4 /* Dword offset 0_E9 */ + +#define SPECULAR_GREEN_X_INC 0x03A8 /* Dword offset 0_EA */ +#define SPECULAR_GREEN_Y_INC 0x03AC /* Dword offset 0_EB */ +#define SPECULAR_GREEN_START 0x03B0 /* Dword offset 0_EC */ +#define SPECULAR_BLUE_X_INC 0x03B4 /* Dword offset 0_ED */ +#define SPECULAR_BLUE_Y_INC 0x03B8 /* Dword offset 0_EE */ +#define SPECULAR_BLUE_START 0x03BC /* Dword offset 0_EF */ + +#define SCALE_X_INC__ALIAS__ 0x03C0 /* Dword offset 0_F0 */ + +#define RED_X_INC__ALIAS__ 0x03C0 /* Dword offset 0_F0 */ +#define RED_Y_INC 0x03C4 /* Dword offset 0_F1 */ +#define RED_START 0x03C8 /* Dword offset 0_F2 */ + +#define SCALE_HACC 0x03C8 /* Dword offset 0_F2 */ +#define SCALE_Y_INC__ALIAS__ 0x03CC /* Dword offset 0_F3 */ + +#define GREEN_X_INC__ALIAS__ 0x03CC /* Dword offset 0_F3 */ +#define GREEN_Y_INC 0x03D0 /* Dword offset 0_F4 */ + +#define SECONDARY_SCALE_Y_INC 0x03D0 /* Dword offset 0_F4 */ +#define SECONDARY_SCALE_VACC 0x03D4 /* Dword offset 0_F5 */ + +#define GREEN_START 0x03D4 /* Dword offset 0_F5 */ +#define BLUE_X_INC 0x03D8 /* Dword offset 0_F6 */ +#define BLUE_Y_INC 0x03DC /* Dword offset 0_F7 */ +#define BLUE_START 0x03E0 /* Dword offset 0_F8 */ +#define Z_X_INC 0x03E4 /* Dword offset 0_F9 */ +#define Z_Y_INC 0x03E8 /* Dword offset 0_FA */ +#define Z_START 0x03EC /* Dword offset 0_FB */ +#define ALPHA_X_INC 0x03F0 /* Dword offset 0_FC */ +#define FOG_X_INC 0x03F0 /* Dword offset 0_FC */ +#define ALPHA_Y_INC 0x03F4 /* Dword offset 0_FD */ +#define FOG_Y_INC 0x03F4 /* Dword offset 0_FD */ +#define ALPHA_START 0x03F8 /* Dword offset 0_FE */ +#define FOG_START 0x03F8 /* Dword offset 0_FE */ + +#define OVERLAY_Y_X_START 0x0400 /* Dword offset 1_00 */ +#define OVERLAY_Y_X_END 0x0404 /* Dword offset 1_01 */ +#define OVERLAY_VIDEO_KEY_CLR 0x0408 /* Dword offset 1_02 */ +#define OVERLAY_VIDEO_KEY_MSK 0x040C /* Dword offset 1_03 */ +#define OVERLAY_GRAPHICS_KEY_CLR 0x0410 /* Dword offset 1_04 */ +#define OVERLAY_GRAPHICS_KEY_MSK 0x0414 /* Dword offset 1_05 */ +#define OVERLAY_KEY_CNTL 0x0418 /* Dword offset 1_06 */ + +#define OVERLAY_SCALE_INC 0x0420 /* Dword offset 1_08 */ +#define OVERLAY_SCALE_CNTL 0x0424 /* Dword offset 1_09 */ +#define SCALER_HEIGHT_WIDTH 0x0428 /* Dword offset 1_0A */ +#define SCALER_TEST 0x042C /* Dword offset 1_0B */ +#define SCALER_BUF0_OFFSET 0x0434 /* Dword offset 1_0D */ +#define SCALER_BUF1_OFFSET 0x0438 /* Dword offset 1_0E */ +#define SCALE_BUF_PITCH 0x043C /* Dword offset 1_0F */ + +#define CAPTURE_START_END 0x0440 /* Dword offset 1_10 */ +#define CAPTURE_X_WIDTH 0x0444 /* Dword offset 1_11 */ +#define VIDEO_FORMAT 0x0448 /* Dword offset 1_12 */ +#define VBI_START_END 0x044C /* Dword offset 1_13 */ +#define CAPTURE_CONFIG 0x0450 /* Dword offset 1_14 */ +#define TRIG_CNTL 0x0454 /* Dword offset 1_15 */ + +#define OVERLAY_EXCLUSIVE_HORZ 0x0458 /* Dword offset 1_16 */ +#define OVERLAY_EXCLUSIVE_VERT 0x045C /* Dword offset 1_17 */ + +#define VAL_WIDTH 0x0460 /* Dword offset 1_18 */ +#define CAPTURE_DEBUG 0x0464 /* Dword offset 1_19 */ +#define VIDEO_SYNC_TEST 0x0468 /* Dword offset 1_1A */ + +#define SNAPSHOT_VH_COUNTS 0x0470 /* Dword offset 1_1C */ +#define SNAPSHOT_F_COUNT 0x0474 /* Dword offset 1_1D */ +#define N_VIF_COUNT 0x0478 /* Dword offset 1_1E */ +#define SNAPSHOT_VIF_COUNT 0x047C /* Dword offset 1_1F */ + +#define CAPTURE_BUF0_OFFSET 0x0480 /* Dword offset 1_20 */ +#define CAPTURE_BUF1_OFFSET 0x0484 /* Dword offset 1_21 */ +#define CAPTURE_BUF_PITCH 0x0488 /* Dword offset 1_22 */ + +#define MPP_CONFIG 0x04C0 /* Dword offset 1_30 */ +#define MPP_STROBE_SEQ 0x04C4 /* Dword offset 1_31 */ +#define MPP_ADDR 0x04C8 /* Dword offset 1_32 */ +#define MPP_DATA 0x04CC /* Dword offset 1_33 */ +#define TVO_CNTL 0x0500 /* Dword offset 1_40 */ + +#define CRT_HORZ_VERT_LOAD 0x0544 /* Dword offset 1_51 */ + +#define AGP_BASE 0x0548 /* Dword offset 1_52 */ +#define AGP_CNTL 0x054C /* Dword offset 1_53 */ + +#define SCALER_COLOUR_CNTL 0x0550 /* Dword offset 1_54 */ +#define SCALER_H_COEFF0 0x0554 /* Dword offset 1_55 */ +#define SCALER_H_COEFF1 0x0558 /* Dword offset 1_56 */ +#define SCALER_H_COEFF2 0x055C /* Dword offset 1_57 */ +#define SCALER_H_COEFF3 0x0560 /* Dword offset 1_58 */ +#define SCALER_H_COEFF4 0x0564 /* Dword offset 1_59 */ + +#define GUI_CNTL 0x0578 /* Dword offset 1_5E */ + +#define BM_FRAME_BUF_OFFSET 0x0580 /* Dword offset 1_60 */ +#define BM_SYSTEM_MEM_ADDR 0x0584 /* Dword offset 1_61 */ +#define BM_COMMAND 0x0588 /* Dword offset 1_62 */ +#define BM_STATUS 0x058C /* Dword offset 1_63 */ +#define BM_GUI_TABLE 0x05B8 /* Dword offset 1_6E */ +#define BM_SYSTEM_TABLE 0x05BC /* Dword offset 1_6F */ + +#define SCALER_BUF0_OFFSET_U 0x05D4 /* Dword offset 1_75 */ +#define SCALER_BUF0_OFFSET_V 0x05D8 /* Dword offset 1_76 */ +#define SCALER_BUF1_OFFSET_U 0x05DC /* Dword offset 1_77 */ +#define SCALER_BUF1_OFFSET_V 0x05E0 /* Dword offset 1_78 */ + +#define VERTEX_1_S 0x0640 /* Dword offset 1_90 */ +#define VERTEX_1_T 0x0644 /* Dword offset 1_91 */ +#define VERTEX_1_W 0x0648 /* Dword offset 1_92 */ +#define VERTEX_1_SPEC_ARGB 0x064C /* Dword offset 1_93 */ +#define VERTEX_1_Z 0x0650 /* Dword offset 1_94 */ +#define VERTEX_1_ARGB 0x0654 /* Dword offset 1_95 */ +#define VERTEX_1_X_Y 0x0658 /* Dword offset 1_96 */ +#define ONE_OVER_AREA 0x065C /* Dword offset 1_97 */ +#define VERTEX_2_S 0x0660 /* Dword offset 1_98 */ +#define VERTEX_2_T 0x0664 /* Dword offset 1_99 */ +#define VERTEX_2_W 0x0668 /* Dword offset 1_9A */ +#define VERTEX_2_SPEC_ARGB 0x066C /* Dword offset 1_9B */ +#define VERTEX_2_Z 0x0670 /* Dword offset 1_9C */ +#define VERTEX_2_ARGB 0x0674 /* Dword offset 1_9D */ +#define VERTEX_2_X_Y 0x0678 /* Dword offset 1_9E */ +#define ONE_OVER_AREA 0x065C /* Dword offset 1_9F */ +#define VERTEX_3_S 0x0680 /* Dword offset 1_A0 */ +#define VERTEX_3_T 0x0684 /* Dword offset 1_A1 */ +#define VERTEX_3_W 0x0688 /* Dword offset 1_A2 */ +#define VERTEX_3_SPEC_ARGB 0x068C /* Dword offset 1_A3 */ +#define VERTEX_3_Z 0x0690 /* Dword offset 1_A4 */ +#define VERTEX_3_ARGB 0x0694 /* Dword offset 1_A5 */ +#define VERTEX_3_X_Y 0x0698 /* Dword offset 1_A6 */ +#define ONE_OVER_AREA 0x065C /* Dword offset 1_A7 */ +#define VERTEX_1_S 0x0640 /* Dword offset 1_AB */ +#define VERTEX_1_T 0x0644 /* Dword offset 1_AC */ +#define VERTEX_1_W 0x0648 /* Dword offset 1_AD */ +#define VERTEX_2_S 0x0660 /* Dword offset 1_AE */ +#define VERTEX_2_T 0x0664 /* Dword offset 1_AF */ +#define VERTEX_2_W 0x0668 /* Dword offset 1_B0 */ +#define VERTEX_3_SECONDARY_S 0x06C0 /* Dword offset 1_B0 */ +#define VERTEX_3_S 0x0680 /* Dword offset 1_B1 */ +#define VERTEX_3_SECONDARY_T 0x06C4 /* Dword offset 1_B1 */ +#define VERTEX_3_T 0x0684 /* Dword offset 1_B2 */ +#define VERTEX_3_SECONDARY_W 0x06C8 /* Dword offset 1_B2 */ +#define VERTEX_3_W 0x0688 /* Dword offset 1_B3 */ +#define VERTEX_1_SPEC_ARGB 0x064C /* Dword offset 1_B4 */ +#define VERTEX_2_SPEC_ARGB 0x066C /* Dword offset 1_B5 */ +#define VERTEX_3_SPEC_ARGB 0x068C /* Dword offset 1_B6 */ +#define VERTEX_1_Z 0x0650 /* Dword offset 1_B7 */ +#define VERTEX_2_Z 0x0670 /* Dword offset 1_B8 */ +#define VERTEX_3_Z 0x0690 /* Dword offset 1_B9 */ +#define VERTEX_1_ARGB 0x0654 /* Dword offset 1_BA */ +#define VERTEX_2_ARGB 0x0674 /* Dword offset 1_BB */ +#define VERTEX_3_ARGB 0x0694 /* Dword offset 1_BC */ +#define VERTEX_1_X_Y 0x0658 /* Dword offset 1_BD */ +#define VERTEX_2_X_Y 0x0678 /* Dword offset 1_BE */ +#define VERTEX_3_X_Y 0x0698 /* Dword offset 1_BF */ +#define ONE_OVER_AREA_UC 0x0700 /* Dword offset 1_C0 */ +#define SETUP_CNTL 0x0704 /* Dword offset 1_C1 */ +#define VERTEX_1_SECONDARY_S 0x0728 /* Dword offset 1_CA */ +#define VERTEX_1_SECONDARY_T 0x072C /* Dword offset 1_CB */ +#define VERTEX_1_SECONDARY_W 0x0730 /* Dword offset 1_CC */ +#define VERTEX_2_SECONDARY_S 0x0734 /* Dword offset 1_CD */ +#define VERTEX_2_SECONDARY_T 0x0738 /* Dword offset 1_CE */ +#define VERTEX_2_SECONDARY_W 0x073C /* Dword offset 1_CF */ + +#define GTC_3D_RESET_DELAY 3 /* 3D engine reset delay in ms */ + +/* CRTC control values (mostly CRTC_GEN_CNTL) */ + +#define CRTC_H_SYNC_NEG 0x00200000 +#define CRTC_V_SYNC_NEG 0x00200000 + +#define CRTC_DBL_SCAN_EN 0x00000001 +#define CRTC_INTERLACE_EN 0x00000002 +#define CRTC_HSYNC_DIS 0x00000004 +#define CRTC_VSYNC_DIS 0x00000008 +#define CRTC_CSYNC_EN 0x00000010 +#define CRTC_PIX_BY_2_EN 0x00000020 /* unused on RAGE */ +#define CRTC_DISPLAY_DIS 0x00000040 +#define CRTC_VGA_XOVERSCAN 0x00000040 + +#define CRTC_PIX_WIDTH_MASK 0x00000700 +#define CRTC_PIX_WIDTH_4BPP 0x00000100 +#define CRTC_PIX_WIDTH_8BPP 0x00000200 +#define CRTC_PIX_WIDTH_15BPP 0x00000300 +#define CRTC_PIX_WIDTH_16BPP 0x00000400 +#define CRTC_PIX_WIDTH_24BPP 0x00000500 +#define CRTC_PIX_WIDTH_32BPP 0x00000600 + +#define CRTC_BYTE_PIX_ORDER 0x00000800 +#define CRTC_PIX_ORDER_MSN_LSN 0x00000000 +#define CRTC_PIX_ORDER_LSN_MSN 0x00000800 + +#define CRTC_FIFO_LWM 0x000f0000 + +#define VGA_128KAP_PAGING 0x00100000 +#define VFC_SYNC_TRISTATE 0x00200000 +#define CRTC_LOCK_REGS 0x00400000 +#define CRTC_SYNC_TRISTATE 0x00800000 + +#define CRTC_EXT_DISP_EN 0x01000000 +#define CRTC_ENABLE 0x02000000 +#define CRTC_DISP_REQ_ENB 0x04000000 +#define VGA_ATI_LINEAR 0x08000000 +#define CRTC_VSYNC_FALL_EDGE 0x10000000 +#define VGA_TEXT_132 0x20000000 +#define VGA_XCRT_CNT_EN 0x40000000 +#define VGA_CUR_B_TEST 0x80000000 + +#define CRTC_CRNT_VLINE 0x07f00000 +#define CRTC_VBLANK 0x00000001 + + +/* DAC control values */ + +#define DAC_EXT_SEL_RS2 0x01 +#define DAC_EXT_SEL_RS3 0x02 +#define DAC_8BIT_EN 0x00000100 +#define DAC_PIX_DLY_MASK 0x00000600 +#define DAC_PIX_DLY_0NS 0x00000000 +#define DAC_PIX_DLY_2NS 0x00000200 +#define DAC_PIX_DLY_4NS 0x00000400 +#define DAC_BLANK_ADJ_MASK 0x00001800 +#define DAC_BLANK_ADJ_0 0x00000000 +#define DAC_BLANK_ADJ_1 0x00000800 +#define DAC_BLANK_ADJ_2 0x00001000 + + +/* Mix control values */ + +#define MIX_NOT_DST 0x0000 +#define MIX_0 0x0001 +#define MIX_1 0x0002 +#define MIX_DST 0x0003 +#define MIX_NOT_SRC 0x0004 +#define MIX_XOR 0x0005 +#define MIX_XNOR 0x0006 +#define MIX_SRC 0x0007 +#define MIX_NAND 0x0008 +#define MIX_NOT_SRC_OR_DST 0x0009 +#define MIX_SRC_OR_NOT_DST 0x000a +#define MIX_OR 0x000b +#define MIX_AND 0x000c +#define MIX_SRC_AND_NOT_DST 0x000d +#define MIX_NOT_SRC_AND_DST 0x000e +#define MIX_NOR 0x000f + +/* Maximum engine dimensions */ +#define ENGINE_MIN_X 0 +#define ENGINE_MIN_Y 0 +#define ENGINE_MAX_X 4095 +#define ENGINE_MAX_Y 16383 + +/* Mach64 engine bit constants - these are typically ORed together */ + +/* BUS_CNTL register constants */ +#define BUS_FIFO_ERR_ACK 0x00200000 +#define BUS_HOST_ERR_ACK 0x00800000 + +/* GEN_TEST_CNTL register constants */ +#define GEN_OVR_OUTPUT_EN 0x20 +#define HWCURSOR_ENABLE 0x80 +#define GUI_ENGINE_ENABLE 0x100 +#define BLOCK_WRITE_ENABLE 0x200 + +/* DSP_CONFIG register constants */ +#define DSP_XCLKS_PER_QW 0x00003fff +#define DSP_LOOP_LATENCY 0x000f0000 +#define DSP_PRECISION 0x00700000 + +/* DSP_ON_OFF register constants */ +#define DSP_OFF 0x000007ff +#define DSP_ON 0x07ff0000 + +/* CLOCK_CNTL register constants */ +#define CLOCK_SEL 0x0f +#define CLOCK_DIV 0x30 +#define CLOCK_DIV1 0x00 +#define CLOCK_DIV2 0x10 +#define CLOCK_DIV4 0x20 +#define CLOCK_STROBE 0x40 +#define PLL_WR_EN 0x02 + +/* PLL registers */ +#define MPLL_CNTL 0x00 +#define VPLL_CNTL 0x01 +#define PLL_REF_DIV 0x02 +#define PLL_GEN_CNTL 0x03 +#define MCLK_FB_DIV 0x04 +#define PLL_VCLK_CNTL 0x05 +#define VCLK_POST_DIV 0x06 +#define VCLK0_FB_DIV 0x07 +#define VCLK1_FB_DIV 0x08 +#define VCLK2_FB_DIV 0x09 +#define VCLK3_FB_DIV 0x0A +#define PLL_EXT_CNTL 0x0B +#define DLL_CNTL 0x0C +#define VFC_CNTL 0x0D +#define PLL_TEST_CTRL 0x0E +#define PLL_TEST_COUNT 0x0F + +/* Fields in PLL registers */ +#define PLL_PC_GAIN 0x07 +#define PLL_VC_GAIN 0x18 +#define PLL_DUTY_CYC 0xE0 +#define PLL_OVERRIDE 0x01 +#define PLL_MCLK_RST 0x02 +#define OSC_EN 0x04 +#define EXT_CLK_EN 0x08 +#define MCLK_SRC_SEL 0x70 +#define EXT_CLK_CNTL 0x80 +#define VCLK_SRC_SEL 0x03 +#define PLL_VCLK_RST 0x04 +#define VCLK_INVERT 0x08 +#define VCLK0_POST 0x03 +#define VCLK1_POST 0x0C +#define VCLK2_POST 0x30 +#define VCLK3_POST 0xC0 + +/* CONFIG_CNTL register constants */ +#define APERTURE_4M_ENABLE 1 +#define APERTURE_8M_ENABLE 2 +#define VGA_APERTURE_ENABLE 4 + +/* CONFIG_STAT0 register constants (GX, CX) */ +#define CFG_BUS_TYPE 0x00000007 +#define CFG_MEM_TYPE 0x00000038 +#define CFG_INIT_DAC_TYPE 0x00000e00 + +/* CONFIG_STAT0 register constants (CT, ET, VT) */ +#define CFG_MEM_TYPE_xT 0x00000007 + +#define ISA 0 +#define EISA 1 +#define LOCAL_BUS 6 +#define PCI 7 + +/* Memory types for GX, CX */ +#define DRAMx4 0 +#define VRAMx16 1 +#define VRAMx16ssr 2 +#define DRAMx16 3 +#define GraphicsDRAMx16 4 +#define EnhancedVRAMx16 5 +#define EnhancedVRAMx16ssr 6 + +/* Memory types for CT, ET, VT, GT */ +#define DRAM 1 +#define EDO 2 +#define PSEUDO_EDO 3 +#define SDRAM 4 +#define SGRAM 5 +#define WRAM 6 + +#define DAC_INTERNAL 0x00 +#define DAC_IBMRGB514 0x01 +#define DAC_ATI68875 0x02 +#define DAC_TVP3026_A 0x72 +#define DAC_BT476 0x03 +#define DAC_BT481 0x04 +#define DAC_ATT20C491 0x14 +#define DAC_SC15026 0x24 +#define DAC_MU9C1880 0x34 +#define DAC_IMSG174 0x44 +#define DAC_ATI68860_B 0x05 +#define DAC_ATI68860_C 0x15 +#define DAC_TVP3026_B 0x75 +#define DAC_STG1700 0x06 +#define DAC_ATT498 0x16 +#define DAC_STG1702 0x07 +#define DAC_SC15021 0x17 +#define DAC_ATT21C498 0x27 +#define DAC_STG1703 0x37 +#define DAC_CH8398 0x47 +#define DAC_ATT20C408 0x57 + +#define CLK_ATI18818_0 0 +#define CLK_ATI18818_1 1 +#define CLK_STG1703 2 +#define CLK_CH8398 3 +#define CLK_INTERNAL 4 +#define CLK_ATT20C408 5 +#define CLK_IBMRGB514 6 + +/* MEM_CNTL register constants */ +#define MEM_SIZE_ALIAS 0x00000007 +#define MEM_SIZE_512K 0x00000000 +#define MEM_SIZE_1M 0x00000001 +#define MEM_SIZE_2M 0x00000002 +#define MEM_SIZE_4M 0x00000003 +#define MEM_SIZE_6M 0x00000004 +#define MEM_SIZE_8M 0x00000005 +#define MEM_SIZE_ALIAS_GTB 0x0000000F +#define MEM_SIZE_2M_GTB 0x00000003 +#define MEM_SIZE_4M_GTB 0x00000007 +#define MEM_SIZE_6M_GTB 0x00000009 +#define MEM_SIZE_8M_GTB 0x0000000B +#define MEM_BNDRY 0x00030000 +#define MEM_BNDRY_0K 0x00000000 +#define MEM_BNDRY_256K 0x00010000 +#define MEM_BNDRY_512K 0x00020000 +#define MEM_BNDRY_1M 0x00030000 +#define MEM_BNDRY_EN 0x00040000 + +/* ATI PCI constants */ +#define PCI_ATI_VENDOR_ID 0x1002 + + +/* CONFIG_CHIP_ID register constants */ +#define CFG_CHIP_TYPE 0x0000FFFF +#define CFG_CHIP_CLASS 0x00FF0000 +#define CFG_CHIP_REV 0xFF000000 +#define CFG_CHIP_MAJOR 0x07000000 +#define CFG_CHIP_FND_ID 0x38000000 +#define CFG_CHIP_MINOR 0xC0000000 + + +/* Chip IDs read from CONFIG_CHIP_ID */ + +/* mach64GX family */ +#define GX_CHIP_ID 0xD7 /* mach64GX (ATI888GX00) */ +#define CX_CHIP_ID 0x57 /* mach64CX (ATI888CX00) */ + +#define GX_PCI_ID 0x4758 /* mach64GX (ATI888GX00) */ +#define CX_PCI_ID 0x4358 /* mach64CX (ATI888CX00) */ + +/* mach64CT family */ +#define CT_CHIP_ID 0x4354 /* mach64CT (ATI264CT) */ +#define ET_CHIP_ID 0x4554 /* mach64ET (ATI264ET) */ + +/* mach64CT family / mach64VT class */ +#define VT_CHIP_ID 0x5654 /* mach64VT (ATI264VT) */ +#define VU_CHIP_ID 0x5655 /* mach64VTB (ATI264VTB) */ +#define VV_CHIP_ID 0x5656 /* mach64VT4 (ATI264VT4) */ + +/* mach64CT family / mach64GT (3D RAGE) class */ +#define LB_CHIP_ID 0x4c42 /* RAGE LT PRO, AGP */ +#define LD_CHIP_ID 0x4c44 /* RAGE LT PRO */ +#define LG_CHIP_ID 0x4c47 /* RAGE LT */ +#define LI_CHIP_ID 0x4c49 /* RAGE LT PRO */ +#define LP_CHIP_ID 0x4c50 /* RAGE LT PRO */ +#define LT_CHIP_ID 0x4c54 /* RAGE LT */ +#define GT_CHIP_ID 0x4754 /* RAGE (GT) */ +#define GU_CHIP_ID 0x4755 /* RAGE II/II+ (GTB) */ +#define GV_CHIP_ID 0x4756 /* RAGE IIC, PCI */ +#define GW_CHIP_ID 0x4757 /* RAGE IIC, AGP */ +#define GZ_CHIP_ID 0x475a /* RAGE IIC, AGP */ +#define GB_CHIP_ID 0x4742 /* RAGE PRO, BGA, AGP 1x and 2x */ +#define GD_CHIP_ID 0x4744 /* RAGE PRO, BGA, AGP 1x only */ +#define GI_CHIP_ID 0x4749 /* RAGE PRO, BGA, PCI33 only */ +#define GP_CHIP_ID 0x4750 /* RAGE PRO, PQFP, PCI33, full 3D */ +#define GQ_CHIP_ID 0x4751 /* RAGE PRO, PQFP, PCI33, limited 3D */ +#define LM_CHIP_ID 0x4c4d /* RAGE Mobility PCI */ +#define LN_CHIP_ID 0x4c4e /* RAGE Mobility AGP */ + + +/* Mach64 major ASIC revisions */ +#define MACH64_ASIC_NEC_VT_A3 0x08 +#define MACH64_ASIC_NEC_VT_A4 0x48 +#define MACH64_ASIC_SGS_VT_A4 0x40 +#define MACH64_ASIC_SGS_VT_B1S1 0x01 +#define MACH64_ASIC_SGS_GT_B1S1 0x01 +#define MACH64_ASIC_SGS_GT_B1S2 0x41 +#define MACH64_ASIC_UMC_GT_B2U1 0x1a +#define MACH64_ASIC_UMC_GT_B2U2 0x5a +#define MACH64_ASIC_UMC_VT_B2U3 0x9a +#define MACH64_ASIC_UMC_GT_B2U3 0x9a +#define MACH64_ASIC_UMC_R3B_D_P_A1 0x1b +#define MACH64_ASIC_UMC_R3B_D_P_A2 0x5b +#define MACH64_ASIC_UMC_R3B_D_P_A3 0x1c +#define MACH64_ASIC_UMC_R3B_D_P_A4 0x5c + +/* Mach64 foundries */ +#define MACH64_FND_SGS 0 +#define MACH64_FND_NEC 1 +#define MACH64_FND_UMC 3 + +/* Mach64 chip types */ +#define MACH64_UNKNOWN 0 +#define MACH64_GX 1 +#define MACH64_CX 2 +#define MACH64_CT 3 +#define MACH64_ET 4 +#define MACH64_VT 5 +#define MACH64_GT 6 + +/* DST_CNTL register constants */ +#define DST_X_RIGHT_TO_LEFT 0 +#define DST_X_LEFT_TO_RIGHT 1 +#define DST_Y_BOTTOM_TO_TOP 0 +#define DST_Y_TOP_TO_BOTTOM 2 +#define DST_X_MAJOR 0 +#define DST_Y_MAJOR 4 +#define DST_X_TILE 8 +#define DST_Y_TILE 0x10 +#define DST_LAST_PEL 0x20 +#define DST_POLYGON_ENABLE 0x40 +#define DST_24_ROTATION_ENABLE 0x80 + +/* SRC_CNTL register constants */ +#define SRC_PATTERN_ENABLE 1 +#define SRC_ROTATION_ENABLE 2 +#define SRC_LINEAR_ENABLE 4 +#define SRC_BYTE_ALIGN 8 +#define SRC_LINE_X_RIGHT_TO_LEFT 0 +#define SRC_LINE_X_LEFT_TO_RIGHT 0x10 + +/* HOST_CNTL register constants */ +#define HOST_BYTE_ALIGN 1 + +/* GUI_TRAJ_CNTL register constants */ +#define PAT_MONO_8x8_ENABLE 0x01000000 +#define PAT_CLR_4x2_ENABLE 0x02000000 +#define PAT_CLR_8x1_ENABLE 0x04000000 + +/* DP_CHAIN_MASK register constants */ +#define DP_CHAIN_4BPP 0x8888 +#define DP_CHAIN_7BPP 0xD2D2 +#define DP_CHAIN_8BPP 0x8080 +#define DP_CHAIN_8BPP_RGB 0x9292 +#define DP_CHAIN_15BPP 0x4210 +#define DP_CHAIN_16BPP 0x8410 +#define DP_CHAIN_24BPP 0x8080 +#define DP_CHAIN_32BPP 0x8080 + +/* DP_PIX_WIDTH register constants */ +#define DST_1BPP 0 +#define DST_4BPP 1 +#define DST_8BPP 2 +#define DST_15BPP 3 +#define DST_16BPP 4 +#define DST_32BPP 6 +#define SRC_1BPP 0 +#define SRC_4BPP 0x100 +#define SRC_8BPP 0x200 +#define SRC_15BPP 0x300 +#define SRC_16BPP 0x400 +#define SRC_32BPP 0x600 +#define HOST_1BPP 0 +#define HOST_4BPP 0x10000 +#define HOST_8BPP 0x20000 +#define HOST_15BPP 0x30000 +#define HOST_16BPP 0x40000 +#define HOST_32BPP 0x60000 +#define BYTE_ORDER_MSB_TO_LSB 0 +#define BYTE_ORDER_LSB_TO_MSB 0x1000000 + +/* DP_MIX register constants */ +#define BKGD_MIX_NOT_D 0 +#define BKGD_MIX_ZERO 1 +#define BKGD_MIX_ONE 2 +#define BKGD_MIX_D 3 +#define BKGD_MIX_NOT_S 4 +#define BKGD_MIX_D_XOR_S 5 +#define BKGD_MIX_NOT_D_XOR_S 6 +#define BKGD_MIX_S 7 +#define BKGD_MIX_NOT_D_OR_NOT_S 8 +#define BKGD_MIX_D_OR_NOT_S 9 +#define BKGD_MIX_NOT_D_OR_S 10 +#define BKGD_MIX_D_OR_S 11 +#define BKGD_MIX_D_AND_S 12 +#define BKGD_MIX_NOT_D_AND_S 13 +#define BKGD_MIX_D_AND_NOT_S 14 +#define BKGD_MIX_NOT_D_AND_NOT_S 15 +#define BKGD_MIX_D_PLUS_S_DIV2 0x17 +#define FRGD_MIX_NOT_D 0 +#define FRGD_MIX_ZERO 0x10000 +#define FRGD_MIX_ONE 0x20000 +#define FRGD_MIX_D 0x30000 +#define FRGD_MIX_NOT_S 0x40000 +#define FRGD_MIX_D_XOR_S 0x50000 +#define FRGD_MIX_NOT_D_XOR_S 0x60000 +#define FRGD_MIX_S 0x70000 +#define FRGD_MIX_NOT_D_OR_NOT_S 0x80000 +#define FRGD_MIX_D_OR_NOT_S 0x90000 +#define FRGD_MIX_NOT_D_OR_S 0xa0000 +#define FRGD_MIX_D_OR_S 0xb0000 +#define FRGD_MIX_D_AND_S 0xc0000 +#define FRGD_MIX_NOT_D_AND_S 0xd0000 +#define FRGD_MIX_D_AND_NOT_S 0xe0000 +#define FRGD_MIX_NOT_D_AND_NOT_S 0xf0000 +#define FRGD_MIX_D_PLUS_S_DIV2 0x170000 + +/* DP_SRC register constants */ +#define BKGD_SRC_BKGD_CLR 0 +#define BKGD_SRC_FRGD_CLR 1 +#define BKGD_SRC_HOST 2 +#define BKGD_SRC_BLIT 3 +#define BKGD_SRC_PATTERN 4 +#define FRGD_SRC_BKGD_CLR 0 +#define FRGD_SRC_FRGD_CLR 0x100 +#define FRGD_SRC_HOST 0x200 +#define FRGD_SRC_BLIT 0x300 +#define FRGD_SRC_PATTERN 0x400 +#define MONO_SRC_ONE 0 +#define MONO_SRC_PATTERN 0x10000 +#define MONO_SRC_HOST 0x20000 +#define MONO_SRC_BLIT 0x30000 + +/* CLR_CMP_CNTL register constants */ +#define COMPARE_FALSE 0 +#define COMPARE_TRUE 1 +#define COMPARE_NOT_EQUAL 4 +#define COMPARE_EQUAL 5 +#define COMPARE_DESTINATION 0 +#define COMPARE_SOURCE 0x1000000 + +/* FIFO_STAT register constants */ +#define FIFO_ERR 0x80000000 + +/* CONTEXT_LOAD_CNTL constants */ +#define CONTEXT_NO_LOAD 0 +#define CONTEXT_LOAD 0x10000 +#define CONTEXT_LOAD_AND_DO_FILL 0x20000 +#define CONTEXT_LOAD_AND_DO_LINE 0x30000 +#define CONTEXT_EXECUTE 0 +#define CONTEXT_CMD_DISABLE 0x80000000 + +/* GUI_STAT register constants */ +#define ENGINE_IDLE 0 +#define ENGINE_BUSY 1 +#define SCISSOR_LEFT_FLAG 0x10 +#define SCISSOR_RIGHT_FLAG 0x20 +#define SCISSOR_TOP_FLAG 0x40 +#define SCISSOR_BOTTOM_FLAG 0x80 + +/* ATI VGA Extended Regsiters */ +#define sioATIEXT 0x1ce +#define bioATIEXT 0x3ce + +#define ATI2E 0xae +#define ATI32 0xb2 +#define ATI36 0xb6 + +/* VGA Graphics Controller Registers */ +#define VGAGRA 0x3ce +#define GRA06 0x06 + +/* VGA Seququencer Registers */ +#define VGASEQ 0x3c4 +#define SEQ02 0x02 +#define SEQ04 0x04 + +#define MACH64_MAX_X ENGINE_MAX_X +#define MACH64_MAX_Y ENGINE_MAX_Y + +#define INC_X 0x0020 +#define INC_Y 0x0080 + +#define RGB16_555 0x0000 +#define RGB16_565 0x0040 +#define RGB16_655 0x0080 +#define RGB16_664 0x00c0 + +#define POLY_TEXT_TYPE 0x0001 +#define IMAGE_TEXT_TYPE 0x0002 +#define TEXT_TYPE_8_BIT 0x0004 +#define TEXT_TYPE_16_BIT 0x0008 +#define POLY_TEXT_TYPE_8 (POLY_TEXT_TYPE | TEXT_TYPE_8_BIT) +#define IMAGE_TEXT_TYPE_8 (IMAGE_TEXT_TYPE | TEXT_TYPE_8_BIT) +#define POLY_TEXT_TYPE_16 (POLY_TEXT_TYPE | TEXT_TYPE_16_BIT) +#define IMAGE_TEXT_TYPE_16 (IMAGE_TEXT_TYPE | TEXT_TYPE_16_BIT) + +#define MACH64_NUM_CLOCKS 16 +#define MACH64_NUM_FREQS 50 + +/* Power Management register constants (LT & LT Pro) */ +#define PWR_MGT_ON 0x00000001 +#define PWR_MGT_MODE_MASK 0x00000006 +#define AUTO_PWR_UP 0x00000008 +#define USE_F32KHZ 0x00000400 +#define TRISTATE_MEM_EN 0x00000800 +#define SELF_REFRESH 0x00000080 +#define PWR_BLON 0x02000000 +#define STANDBY_NOW 0x10000000 +#define SUSPEND_NOW 0x20000000 +#define PWR_MGT_STATUS_MASK 0xC0000000 +#define PWR_MGT_STATUS_SUSPEND 0x80000000 + +/* PM Mode constants */ +#define PWR_MGT_MODE_PIN 0x00000000 +#define PWR_MGT_MODE_REG 0x00000002 +#define PWR_MGT_MODE_TIMER 0x00000004 +#define PWR_MGT_MODE_PCI 0x00000006 + +/* LCD registers (LT Pro) */ + +/* LCD Index register */ +#define LCD_INDEX_MASK 0x0000003F +#define LCD_DISPLAY_DIS 0x00000100 +#define LCD_SRC_SEL 0x00000200 +#define CRTC2_DISPLAY_DIS 0x00000400 + +/* LCD register indices */ +#define LCD_CONFIG_PANEL 0x00 +#define LCD_GEN_CTRL 0x01 +#define LCD_DSTN_CONTROL 0x02 +#define LCD_HFB_PITCH_ADDR 0x03 +#define LCD_HORZ_STRETCHING 0x04 +#define LCD_VERT_STRETCHING 0x05 +#define LCD_EXT_VERT_STRETCH 0x06 +#define LCD_LT_GIO 0x07 +#define LCD_POWER_MANAGEMENT 0x08 +#define LCD_ZVGPIO 0x09 +#define LCD_MISC_CNTL 0x14 + +/* Values in LCD_MISC_CNTL */ +#define BIAS_MOD_LEVEL_MASK 0x0000ff00 +#define BIAS_MOD_LEVEL_SHIFT 8 +#define BLMOD_EN 0x00010000 +#define BIASMOD_EN 0x00020000 + +#endif /* REGMACH64_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/aty/atyfb.h linux.ac/drivers/video/aty/atyfb.h --- linux.vanilla/drivers/video/aty/atyfb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/aty/atyfb.h Tue Apr 3 17:55:08 2001 @@ -0,0 +1,316 @@ + +/* + * ATI Frame Buffer Device Driver Core Definitions + */ + +#include <linux/config.h> + + + /* + * Elements of the Hardware specific atyfb_par structure + */ + +struct crtc { + u32 vxres; + u32 vyres; + u32 xoffset; + u32 yoffset; + u32 bpp; + u32 h_tot_disp; + u32 h_sync_strt_wid; + u32 v_tot_disp; + u32 v_sync_strt_wid; + u32 off_pitch; + u32 gen_cntl; + u32 dp_pix_width; /* acceleration */ + u32 dp_chain_mask; /* acceleration */ +}; + +struct pll_514 { + u8 m; + u8 n; +}; + +struct pll_18818 +{ + u32 program_bits; + u32 locationAddr; + u32 period_in_ps; + u32 post_divider; +}; + +struct pll_ct { + u8 pll_ref_div; + u8 pll_gen_cntl; + u8 mclk_fb_div; + u8 pll_vclk_cntl; + u8 vclk_post_div; + u8 vclk_fb_div; + u8 pll_ext_cntl; + u32 dsp_config; /* Mach64 GTB DSP */ + u32 dsp_on_off; /* Mach64 GTB DSP */ + u8 mclk_post_div_real; + u8 vclk_post_div_real; +}; + +union aty_pll { + struct pll_ct ct; + struct pll_514 ibm514; + struct pll_18818 ics2595; +}; + + + /* + * The Hardware parameters for each card + */ + +struct atyfb_par { + struct crtc crtc; + union aty_pll pll; + u32 accel_flags; +}; + +struct aty_cursor { + int enable; + int on; + int vbl_cnt; + int blink_rate; + u32 offset; + struct { + u16 x, y; + } pos, hot, size; + u32 color[2]; + u8 bits[8][64]; + u8 mask[8][64]; + u8 *ram; + struct timer_list *timer; +}; + +struct fb_info_aty { + struct fb_info fb_info; + struct fb_info_aty *next; + unsigned long ati_regbase_phys; + unsigned long ati_regbase; + unsigned long frame_buffer_phys; + unsigned long frame_buffer; + unsigned long clk_wr_offset; + struct pci_mmap_map *mmap_map; + struct aty_cursor *cursor; + struct aty_cmap_regs *aty_cmap_regs; + struct { u8 red, green, blue, pad; } palette[256]; + struct atyfb_par default_par; + struct atyfb_par current_par; + u32 features; + u32 total_vram; + u32 ref_clk_per; + u32 pll_per; + u32 mclk_per; + u8 bus_type; + u8 ram_type; + u8 mem_refresh_rate; + const struct aty_dac_ops *dac_ops; + const struct aty_pll_ops *pll_ops; + struct display disp; + struct display_switch dispsw; + union { +#ifdef FBCON_HAS_CFB16 + u16 cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB24 + u32 cfb24[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u32 cfb32[16]; +#endif + } fbcon_cmap; + u8 blitter_may_be_busy; +#ifdef __sparc__ + u8 mmaped; + int open; + int vtconsole; + int consolecnt; +#endif +#ifdef CONFIG_PMAC_PBOOK + unsigned char *save_framebuffer; + unsigned long save_pll[64]; +#endif +}; + + + /* + * Mach64 features + */ + +#define M64_HAS(feature) ((info)->features & (M64F_##feature)) + +#define M64F_RESET_3D 0x00000001 +#define M64F_MAGIC_FIFO 0x00000002 +#define M64F_GTB_DSP 0x00000004 +#define M64F_FIFO_24 0x00000008 +#define M64F_SDRAM_MAGIC_PLL 0x00000010 +#define M64F_MAGIC_POSTDIV 0x00000020 +#define M64F_INTEGRATED 0x00000040 +#define M64F_CT_BUS 0x00000080 +#define M64F_VT_BUS 0x00000100 +#define M64F_MOBIL_BUS 0x00000200 +#define M64F_GX 0x00000400 +#define M64F_CT 0x00000800 +#define M64F_VT 0x00001000 +#define M64F_GT 0x00002000 +#define M64F_MAGIC_VRAM_SIZE 0x00004000 +#define M64F_G3_PB_1_1 0x00008000 +#define M64F_G3_PB_1024x768 0x00010000 +#define M64F_EXTRA_BRIGHT 0x00020000 +#define M64F_LT_SLEEP 0x00040000 + + + /* + * Register access + */ + +static inline u32 aty_ld_le32(int regindex, + const struct fb_info_aty *info) +{ + /* Hack for bloc 1, should be cleanly optimized by compiler */ + if (regindex >= 0x400) + regindex -= 0x800; + +#if defined(__mc68000__) + return le32_to_cpu(*((volatile u32 *)(info->ati_regbase+regindex))); +#else + return readl (info->ati_regbase + regindex); +#endif +} + +static inline void aty_st_le32(int regindex, u32 val, + const struct fb_info_aty *info) +{ + /* Hack for bloc 1, should be cleanly optimized by compiler */ + if (regindex >= 0x400) + regindex -= 0x800; + +#if defined(__mc68000__) + *((volatile u32 *)(info->ati_regbase+regindex)) = cpu_to_le32(val); +#else + writel (val, info->ati_regbase + regindex); +#endif +} + +static inline u8 aty_ld_8(int regindex, + const struct fb_info_aty *info) +{ + /* Hack for bloc 1, should be cleanly optimized by compiler */ + if (regindex >= 0x400) + regindex -= 0x800; + + return readb (info->ati_regbase + regindex); +} + +static inline void aty_st_8(int regindex, u8 val, + const struct fb_info_aty *info) +{ + /* Hack for bloc 1, should be cleanly optimized by compiler */ + if (regindex >= 0x400) + regindex -= 0x800; + + writeb (val, info->ati_regbase + regindex); +} + +static inline u8 aty_ld_pll(int offset, const struct fb_info_aty *info) +{ + u8 res; + + /* write addr byte */ + aty_st_8(CLOCK_CNTL + 1, (offset << 2), info); + /* read the register value */ + res = aty_ld_8(CLOCK_CNTL + 2, info); + return res; +} + + + /* + * DAC operations + */ + +struct aty_dac_ops { + int (*set_dac)(const struct fb_info_aty *info, const union aty_pll *pll, + u32 bpp, u32 accel); +}; + +extern const struct aty_dac_ops aty_dac_ibm514; /* IBM RGB514 */ +extern const struct aty_dac_ops aty_dac_ati68860b; /* ATI 68860-B */ +extern const struct aty_dac_ops aty_dac_att21c498; /* AT&T 21C498 */ +extern const struct aty_dac_ops aty_dac_unsupported; /* unsupported */ +extern const struct aty_dac_ops aty_dac_ct; /* Integrated */ + + + /* + * Clock operations + */ + +struct aty_pll_ops { + int (*var_to_pll)(const struct fb_info_aty *info, u32 vclk_per, u8 bpp, + union aty_pll *pll); + u32 (*pll_to_var)(const struct fb_info_aty *info, + const union aty_pll *pll); + void (*set_pll)(const struct fb_info_aty *info, const union aty_pll *pll); +}; + +extern const struct aty_pll_ops aty_pll_ati18818_1; /* ATI 18818 */ +extern const struct aty_pll_ops aty_pll_stg1703; /* STG 1703 */ +extern const struct aty_pll_ops aty_pll_ch8398; /* Chrontel 8398 */ +extern const struct aty_pll_ops aty_pll_att20c408; /* AT&T 20C408 */ +extern const struct aty_pll_ops aty_pll_ibm514; /* IBM RGB514 */ +extern const struct aty_pll_ops aty_pll_unsupported; /* unsupported */ +extern const struct aty_pll_ops aty_pll_ct; /* Integrated */ + + +extern void aty_set_pll_ct(const struct fb_info_aty *info, + const union aty_pll *pll); +extern void aty_calc_pll_ct(const struct fb_info_aty *info, + struct pll_ct *pll); + + + /* + * Hardware cursor support + */ + +extern struct aty_cursor *aty_init_cursor(struct fb_info_aty *fb); +extern void atyfb_cursor(struct display *p, int mode, int x, int y); +extern void aty_set_cursor_color(struct fb_info_aty *fb); +extern void aty_set_cursor_shape(struct fb_info_aty *fb); +extern int atyfb_set_font(struct display *d, int width, int height); + + + /* + * Hardware acceleration + */ + +static inline void wait_for_fifo(u16 entries, const struct fb_info_aty *info) +{ + while ((aty_ld_le32(FIFO_STAT, info) & 0xffff) > + ((u32)(0x8000 >> entries))); +} + +static inline void wait_for_idle(struct fb_info_aty *info) +{ + wait_for_fifo(16, info); + while ((aty_ld_le32(GUI_STAT, info) & 1)!= 0); + info->blitter_may_be_busy = 0; +} + +extern void aty_reset_engine(const struct fb_info_aty *info); +extern void aty_init_engine(const struct atyfb_par *par, + struct fb_info_aty *info); +extern void aty_rectfill(int dstx, int dsty, u_int width, u_int height, + u_int color, struct fb_info_aty *info); + + + /* + * Text console acceleration + */ + +extern const struct display_switch fbcon_aty8; +extern const struct display_switch fbcon_aty16; +extern const struct display_switch fbcon_aty24; +extern const struct display_switch fbcon_aty32; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/aty/atyfb_base.c linux.ac/drivers/video/aty/atyfb_base.c --- linux.vanilla/drivers/video/aty/atyfb_base.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/aty/atyfb_base.c Sat Apr 14 01:36:46 2001 @@ -0,0 +1,2886 @@ + +/* + * ATI Frame Buffer Device Driver Core + * + * Copyright (C) 1997-2001 Geert Uytterhoeven + * Copyright (C) 1998 Bernd Harries + * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) + * + * This driver supports the following ATI graphics chips: + * - ATI Mach64 + * + * To do: add support for + * - ATI Rage128 (from aty128fb.c) + * - ATI Radeon (from radeonfb.c) + * + * This driver is partly based on the PowerMac console driver: + * + * Copyright (C) 1996 Paul Mackerras + * + * and on the PowerMac ATI/mach64 display driver: + * + * Copyright (C) 1997 Michael AK Tesch + * + * with work by Jon Howell + * Harry AC Eaton + * Anthony Tong <atong@uiuc.edu> + * + * 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. + * + * Many thanks to Nitya from ATI devrel for support and patience ! + */ + +/****************************************************************************** + + TODO: + + - cursor support on all cards and all ramdacs. + - cursor parameters controlable via ioctl()s. + - guess PLL and MCLK based on the original PLL register values initialized + by the BIOS or Open Firmware (if they are initialized). + + (Anyone to help with this?) + +******************************************************************************/ + + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/malloc.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> +#include <linux/selection.h> +#include <linux/console.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/vt_kern.h> + +#include <asm/io.h> +#include <asm/uaccess.h> + +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb24.h> +#include <video/fbcon-cfb32.h> + +#include "mach64.h" +#include "atyfb.h" + +#ifdef __powerpc__ +#include <asm/prom.h> +#include <video/macmodes.h> +#endif +#ifdef __sparc__ +#include <asm/pbm.h> +#include <asm/fbio.h> +#endif + +#ifdef CONFIG_ADB_PMU +#include <linux/adb.h> +#include <linux/pmu.h> +#endif +#ifdef CONFIG_NVRAM +#include <linux/nvram.h> +#endif +#ifdef CONFIG_FB_COMPAT_XPMAC +#include <asm/vc_ioctl.h> +#endif +#ifdef CONFIG_PMAC_BACKLIGHT +#include <asm/backlight.h> +#endif + + +/* + * Debug flags. + */ +#undef DEBUG + +/* Make sure n * PAGE_SIZE is protected at end of Aperture for GUI-regs */ +/* - must be large enough to catch all GUI-Regs */ +/* - must be aligned to a PAGE boundary */ +#define GUI_RESERVE (1 * PAGE_SIZE) + + +/* FIXME: remove the FAIL definition */ +#define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0) + + + /* + * The Hardware parameters for each card + */ + +struct aty_cmap_regs { + u8 windex; + u8 lut; + u8 mask; + u8 rindex; + u8 cntl; +}; + +struct pci_mmap_map { + unsigned long voff; + unsigned long poff; + unsigned long size; + unsigned long prot_flag; + unsigned long prot_mask; +}; + + + /* + * Frame buffer device API + */ + +static int atyfb_open(struct fb_info *info, int user); +static int atyfb_release(struct fb_info *info, int user); +static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *fb); +static int atyfb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *fb); +static int atyfb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *fb); +static int atyfb_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info *fb); +static int atyfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con, struct fb_info *info); +#ifdef __sparc__ +static int atyfb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma); +#endif +static int atyfb_rasterimg(struct fb_info *info, int start); + + + /* + * Interface to the low level console driver + */ + +static int atyfbcon_switch(int con, struct fb_info *fb); +static int atyfbcon_updatevar(int con, struct fb_info *fb); +static void atyfbcon_blank(int blank, struct fb_info *fb); + + + /* + * Internal routines + */ + +static int aty_init(struct fb_info_aty *info, const char *name); +#ifdef CONFIG_ATARI +static int store_video_par(char *videopar, unsigned char m64_num); +static char *strtoke(char *s, const char *ct); +#endif + +static void aty_set_crtc(const struct fb_info_aty *info, + const struct crtc *crtc); +static int aty_var_to_crtc(const struct fb_info_aty *info, + const struct fb_var_screeninfo *var, + struct crtc *crtc); +static int aty_crtc_to_var(const struct crtc *crtc, + struct fb_var_screeninfo *var); + +static void atyfb_set_par(const struct atyfb_par *par, + struct fb_info_aty *info); +static int atyfb_decode_var(const struct fb_var_screeninfo *var, + struct atyfb_par *par, + const struct fb_info_aty *info); +static int atyfb_encode_var(struct fb_var_screeninfo *var, + const struct atyfb_par *par, + const struct fb_info_aty *info); +static void set_off_pitch(struct atyfb_par *par, + const struct fb_info_aty *info); +static int encode_fix(struct fb_fix_screeninfo *fix, + const struct atyfb_par *par, + const struct fb_info_aty *info); +static void atyfb_set_dispsw(struct display *disp, struct fb_info_aty *info, + int bpp, int accel); +static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp, struct fb_info *fb); +static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *fb); +static void do_install_cmap(int con, struct fb_info *info); +#ifdef CONFIG_PPC +static int read_aty_sense(const struct fb_info_aty *info); +#endif + + + /* + * Interface used by the world + */ + +int atyfb_init(void); +#ifndef MODULE +int atyfb_setup(char*); +#endif + +static int currcon = 0; + +static struct fb_ops atyfb_ops = { + owner: THIS_MODULE, + fb_open: atyfb_open, + fb_release: atyfb_release, + fb_get_fix: atyfb_get_fix, + fb_get_var: atyfb_get_var, + fb_set_var: atyfb_set_var, + fb_get_cmap: atyfb_get_cmap, + fb_set_cmap: atyfb_set_cmap, + fb_pan_display: atyfb_pan_display, + fb_ioctl: atyfb_ioctl, +#ifdef __sparc__ + fb_mmap: atyfb_mmap, +#endif + fb_rasterimg: atyfb_rasterimg, +}; + +static char atyfb_name[16] = "ATY Mach64"; +static char fontname[40] __initdata = { 0 }; +static char curblink __initdata = 1; +static char noaccel __initdata = 0; +static u32 default_vram __initdata = 0; +static int default_pll __initdata = 0; +static int default_mclk __initdata = 0; + +#ifndef MODULE +static const char *mode_option __initdata = NULL; +#endif + +#ifdef CONFIG_PPC +#ifdef CONFIG_NVRAM_NOT_DEFINED +static int default_vmode __initdata = VMODE_NVRAM; +static int default_cmode __initdata = CMODE_NVRAM; +#else +static int default_vmode __initdata = VMODE_CHOOSE; +static int default_cmode __initdata = CMODE_CHOOSE; +#endif +#endif + +#ifdef CONFIG_ATARI +static unsigned int mach64_count __initdata = 0; +static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, }; +static unsigned long phys_size[FB_MAX] __initdata = { 0, }; +static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, }; +#endif + +static const char m64n_gx[] __initdata = "mach64GX (ATI888GX00)"; +static const char m64n_cx[] __initdata = "mach64CX (ATI888CX00)"; +static const char m64n_ct[] __initdata = "mach64CT (ATI264CT)"; +static const char m64n_et[] __initdata = "mach64ET (ATI264ET)"; +static const char m64n_vta3[] __initdata = "mach64VTA3 (ATI264VT)"; +static const char m64n_vta4[] __initdata = "mach64VTA4 (ATI264VT)"; +static const char m64n_vtb[] __initdata = "mach64VTB (ATI264VTB)"; +static const char m64n_vt4[] __initdata = "mach64VT4 (ATI264VT4)"; +static const char m64n_gt[] __initdata = "3D RAGE (GT)"; +static const char m64n_gtb[] __initdata = "3D RAGE II+ (GTB)"; +static const char m64n_iic_p[] __initdata = "3D RAGE IIC (PCI)"; +static const char m64n_iic_a[] __initdata = "3D RAGE IIC (AGP)"; +static const char m64n_lt[] __initdata = "3D RAGE LT"; +static const char m64n_ltg[] __initdata = "3D RAGE LT-G"; +static const char m64n_gtc_ba[] __initdata = "3D RAGE PRO (BGA, AGP)"; +static const char m64n_gtc_ba1[] __initdata = "3D RAGE PRO (BGA, AGP, 1x only)"; +static const char m64n_gtc_bp[] __initdata = "3D RAGE PRO (BGA, PCI)"; +static const char m64n_gtc_pp[] __initdata = "3D RAGE PRO (PQFP, PCI)"; +static const char m64n_gtc_ppl[] __initdata = "3D RAGE PRO (PQFP, PCI, limited 3D)"; +static const char m64n_ltp_a[] __initdata = "3D RAGE LT PRO (AGP)"; +static const char m64n_ltp_p[] __initdata = "3D RAGE LT PRO (PCI)"; +static const char m64n_mob_p[] __initdata = "3D RAGE Mobility (PCI)"; +static const char m64n_mob_a[] __initdata = "3D RAGE Mobility (AGP)"; + + +static const struct { + u16 pci_id, chip_type; + u8 rev_mask, rev_val; + const char *name; + int pll, mclk; + u32 features; +} aty_chips[] __initdata = { +#ifdef CONFIG_FB_ATY_GX + /* Mach64 GX */ + { 0x4758, 0x00d7, 0x00, 0x00, m64n_gx, 135, 50, M64F_GX }, + { 0x4358, 0x0057, 0x00, 0x00, m64n_cx, 135, 50, M64F_GX }, +#endif /* CONFIG_FB_ATY_GX */ + +#ifdef CONFIG_FB_ATY_CT + /* Mach64 CT */ + { 0x4354, 0x4354, 0x00, 0x00, m64n_ct, 135, 60, M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO }, + { 0x4554, 0x4554, 0x00, 0x00, m64n_et, 135, 60, M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO }, + + /* Mach64 VT */ + { 0x5654, 0x5654, 0xc7, 0x00, m64n_vta3, 170, 67, M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_MAGIC_FIFO | M64F_FIFO_24 }, + { 0x5654, 0x5654, 0xc7, 0x40, m64n_vta4, 200, 67, M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_MAGIC_FIFO | M64F_FIFO_24 | M64F_MAGIC_POSTDIV }, + { 0x5654, 0x5654, 0x00, 0x00, m64n_vtb, 200, 67, M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP | M64F_FIFO_24 }, + { 0x5655, 0x5655, 0x00, 0x00, m64n_vtb, 200, 67, M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL }, + { 0x5656, 0x5656, 0x00, 0x00, m64n_vt4, 230, 83, M64F_VT | M64F_INTEGRATED | M64F_GTB_DSP }, + + /* Mach64 GT (3D RAGE) */ + { 0x4754, 0x4754, 0x07, 0x00, m64n_gt, 135, 63, M64F_GT | M64F_INTEGRATED | M64F_MAGIC_FIFO | M64F_FIFO_24 | M64F_EXTRA_BRIGHT }, + { 0x4754, 0x4754, 0x07, 0x01, m64n_gt, 170, 67, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, + { 0x4754, 0x4754, 0x07, 0x02, m64n_gt, 200, 67, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, + { 0x4755, 0x4755, 0x00, 0x00, m64n_gtb, 200, 67, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, + { 0x4756, 0x4756, 0x00, 0x00, m64n_iic_p, 230, 83, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, + { 0x4757, 0x4757, 0x00, 0x00, m64n_iic_a, 230, 83, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, + { 0x475a, 0x475a, 0x00, 0x00, m64n_iic_a, 230, 83, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, + + /* Mach64 LT */ + { 0x4c54, 0x4c54, 0x00, 0x00, m64n_lt, 135, 63, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP }, + { 0x4c47, 0x4c47, 0x00, 0x00, m64n_ltg, 230, 63, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | M64F_LT_SLEEP | M64F_G3_PB_1024x768 }, + + /* Mach64 GTC (3D RAGE PRO) */ + { 0x4742, 0x4742, 0x00, 0x00, m64n_gtc_ba, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, + { 0x4744, 0x4744, 0x00, 0x00, m64n_gtc_ba1, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, + { 0x4749, 0x4749, 0x00, 0x00, m64n_gtc_bp, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | M64F_MAGIC_VRAM_SIZE }, + { 0x4750, 0x4750, 0x00, 0x00, m64n_gtc_pp, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, + { 0x4751, 0x4751, 0x00, 0x00, m64n_gtc_ppl, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, + + /* Mach64 LT PRO */ + { 0x4c42, 0x4c42, 0x00, 0x00, m64n_ltp_a, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP }, + { 0x4c44, 0x4c44, 0x00, 0x00, m64n_ltp_p, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP }, + { 0x4c49, 0x4c49, 0x00, 0x00, m64n_ltp_p, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_EXTRA_BRIGHT | M64F_G3_PB_1_1 | M64F_G3_PB_1024x768 }, + { 0x4c50, 0x4c50, 0x00, 0x00, m64n_ltp_p, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP }, + + /* 3D RAGE Mobility */ + { 0x4c4d, 0x4c4d, 0x00, 0x00, m64n_mob_p, 230, 50, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_MOBIL_BUS }, + { 0x4c4e, 0x4c4e, 0x00, 0x00, m64n_mob_a, 230, 50, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_MOBIL_BUS }, +#endif /* CONFIG_FB_ATY_CT */ +}; + +static const char ram_dram[] __initdata = "DRAM"; +static const char ram_vram[] __initdata = "VRAM"; +static const char ram_edo[] __initdata = "EDO"; +static const char ram_sdram[] __initdata = "SDRAM"; +static const char ram_sgram[] __initdata = "SGRAM"; +static const char ram_wram[] __initdata = "WRAM"; +static const char ram_off[] __initdata = "OFF"; +static const char ram_resv[] __initdata = "RESV"; + +#ifdef CONFIG_FB_ATY_GX +static const char *aty_gx_ram[8] __initdata = { + ram_dram, ram_vram, ram_vram, ram_dram, + ram_dram, ram_vram, ram_vram, ram_resv +}; +#endif /* CONFIG_FB_ATY_GX */ + +#ifdef CONFIG_FB_ATY_CT +static const char *aty_ct_ram[8] __initdata = { + ram_off, ram_dram, ram_edo, ram_edo, + ram_sdram, ram_sgram, ram_wram, ram_resv +}; +#endif /* CONFIG_FB_ATY_CT */ + + +#if defined(CONFIG_PPC) + + /* + * Apple monitor sense + */ + +static int __init read_aty_sense(const struct fb_info_aty *info) +{ + int sense, i; + + aty_st_le32(GP_IO, 0x31003100, info); /* drive outputs high */ + __delay(200); + aty_st_le32(GP_IO, 0, info); /* turn off outputs */ + __delay(2000); + i = aty_ld_le32(GP_IO, info); /* get primary sense value */ + sense = ((i & 0x3000) >> 3) | (i & 0x100); + + /* drive each sense line low in turn and collect the other 2 */ + aty_st_le32(GP_IO, 0x20000000, info); /* drive A low */ + __delay(2000); + i = aty_ld_le32(GP_IO, info); + sense |= ((i & 0x1000) >> 7) | ((i & 0x100) >> 4); + aty_st_le32(GP_IO, 0x20002000, info); /* drive A high again */ + __delay(200); + + aty_st_le32(GP_IO, 0x10000000, info); /* drive B low */ + __delay(2000); + i = aty_ld_le32(GP_IO, info); + sense |= ((i & 0x2000) >> 10) | ((i & 0x100) >> 6); + aty_st_le32(GP_IO, 0x10001000, info); /* drive B high again */ + __delay(200); + + aty_st_le32(GP_IO, 0x01000000, info); /* drive C low */ + __delay(2000); + sense |= (aty_ld_le32(GP_IO, info) & 0x3000) >> 12; + aty_st_le32(GP_IO, 0, info); /* turn off outputs */ + + return sense; +} + +#endif /* defined(CONFIG_PPC) */ + +#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_PMAC_BACKLIGHT) +static void aty_st_lcd(int index, u32 val, const struct fb_info_aty *info) +{ + unsigned long temp; + + /* write addr byte */ + temp = aty_ld_le32(LCD_INDEX, info); + aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, info); + /* write the register value */ + aty_st_le32(LCD_DATA, val, info); +} + +static u32 aty_ld_lcd(int index, const struct fb_info_aty *info) +{ + unsigned long temp; + + /* write addr byte */ + temp = aty_ld_le32(LCD_INDEX, info); + aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, info); + /* read the register value */ + return aty_ld_le32(LCD_DATA, info); +} +#endif /* CONFIG_PMAC_PBOOK || CONFIG_PMAC_BACKLIGHT */ + +/* ------------------------------------------------------------------------- */ + + /* + * CRTC programming + */ + +static void aty_set_crtc(const struct fb_info_aty *info, + const struct crtc *crtc) +{ + aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, info); + aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, info); + aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_tot_disp, info); + aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid, info); + aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0, info); + aty_st_le32(CRTC_OFF_PITCH, crtc->off_pitch, info); + aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, info); +} + +static int aty_var_to_crtc(const struct fb_info_aty *info, + const struct fb_var_screeninfo *var, + struct crtc *crtc) +{ + u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp; + u32 left, right, upper, lower, hslen, vslen, sync, vmode; + u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; + u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; + u32 pix_width, dp_pix_width, dp_chain_mask; + + /* input */ + xres = var->xres; + yres = var->yres; + vxres = var->xres_virtual; + vyres = var->yres_virtual; + xoffset = var->xoffset; + yoffset = var->yoffset; + bpp = var->bits_per_pixel; + left = var->left_margin; + right = var->right_margin; + upper = var->upper_margin; + lower = var->lower_margin; + hslen = var->hsync_len; + vslen = var->vsync_len; + sync = var->sync; + vmode = var->vmode; + + /* convert (and round up) and validate */ + xres = (xres+7) & ~7; + xoffset = (xoffset+7) & ~7; + vxres = (vxres+7) & ~7; + if (vxres < xres+xoffset) + vxres = xres+xoffset; + h_disp = xres/8-1; + if (h_disp > 0xff) + FAIL("h_disp too large"); + h_sync_strt = h_disp+(right/8); + if (h_sync_strt > 0x1ff) + FAIL("h_sync_start too large"); + h_sync_dly = right & 7; + h_sync_wid = (hslen+7)/8; + if (h_sync_wid > 0x1f) + FAIL("h_sync_wid too large"); + h_total = h_sync_strt+h_sync_wid+(h_sync_dly+left+7)/8; + if (h_total > 0x1ff) + FAIL("h_total too large"); + h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; + + if (vyres < yres+yoffset) + vyres = yres+yoffset; + v_disp = yres-1; + if (v_disp > 0x7ff) + FAIL("v_disp too large"); + v_sync_strt = v_disp+lower; + if (v_sync_strt > 0x7ff) + FAIL("v_sync_strt too large"); + v_sync_wid = vslen; + if (v_sync_wid > 0x1f) + FAIL("v_sync_wid too large"); + v_total = v_sync_strt+v_sync_wid+upper; + if (v_total > 0x7ff) + FAIL("v_total too large"); + v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; + + c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? CRTC_CSYNC_EN : 0; + + if (bpp <= 8) { + bpp = 8; + pix_width = CRTC_PIX_WIDTH_8BPP; + dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB; + dp_chain_mask = 0x8080; + } else if (bpp <= 16) { + bpp = 16; + pix_width = CRTC_PIX_WIDTH_15BPP; + dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP | + BYTE_ORDER_LSB_TO_MSB; + dp_chain_mask = 0x4210; + } else if (bpp <= 24 && M64_HAS(INTEGRATED)) { + bpp = 24; + pix_width = CRTC_PIX_WIDTH_24BPP; + dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB; + dp_chain_mask = 0x8080; + } else if (bpp <= 32) { + bpp = 32; + pix_width = CRTC_PIX_WIDTH_32BPP; + dp_pix_width = HOST_32BPP | SRC_32BPP | DST_32BPP | + BYTE_ORDER_LSB_TO_MSB; + dp_chain_mask = 0x8080; + } else + FAIL("invalid bpp"); + + if (vxres*vyres*bpp/8 > info->total_vram) + FAIL("not enough video RAM"); + + if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) + FAIL("invalid vmode"); + + /* output */ + crtc->vxres = vxres; + crtc->vyres = vyres; + crtc->xoffset = xoffset; + crtc->yoffset = yoffset; + crtc->bpp = bpp; + crtc->h_tot_disp = h_total | (h_disp<<16); + crtc->h_sync_strt_wid = (h_sync_strt & 0xff) | (h_sync_dly<<8) | + ((h_sync_strt & 0x100)<<4) | (h_sync_wid<<16) | + (h_sync_pol<<21); + crtc->v_tot_disp = v_total | (v_disp<<16); + crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid<<16) | (v_sync_pol<<21); + crtc->off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19); + crtc->gen_cntl = pix_width | c_sync | CRTC_EXT_DISP_EN | CRTC_ENABLE; + if (M64_HAS(MAGIC_FIFO)) { + /* Not VTB/GTB */ + /* FIXME: magic FIFO values */ + crtc->gen_cntl |= aty_ld_le32(CRTC_GEN_CNTL, info) & 0x000e0000; + } + crtc->dp_pix_width = dp_pix_width; + crtc->dp_chain_mask = dp_chain_mask; + + return 0; +} + + +static int aty_crtc_to_var(const struct crtc *crtc, + struct fb_var_screeninfo *var) +{ + u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync; + u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; + u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; + u32 pix_width; + + /* input */ + h_total = crtc->h_tot_disp & 0x1ff; + h_disp = (crtc->h_tot_disp>>16) & 0xff; + h_sync_strt = (crtc->h_sync_strt_wid & 0xff) | + ((crtc->h_sync_strt_wid>>4) & 0x100); + h_sync_dly = (crtc->h_sync_strt_wid>>8) & 0x7; + h_sync_wid = (crtc->h_sync_strt_wid>>16) & 0x1f; + h_sync_pol = (crtc->h_sync_strt_wid>>21) & 0x1; + v_total = crtc->v_tot_disp & 0x7ff; + v_disp = (crtc->v_tot_disp>>16) & 0x7ff; + v_sync_strt = crtc->v_sync_strt_wid & 0x7ff; + v_sync_wid = (crtc->v_sync_strt_wid>>16) & 0x1f; + v_sync_pol = (crtc->v_sync_strt_wid>>21) & 0x1; + c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0; + pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK; + + /* convert */ + xres = (h_disp+1)*8; + yres = v_disp+1; + left = (h_total-h_sync_strt-h_sync_wid)*8-h_sync_dly; + right = (h_sync_strt-h_disp)*8+h_sync_dly; + hslen = h_sync_wid*8; + upper = v_total-v_sync_strt-v_sync_wid; + lower = v_sync_strt-v_disp; + vslen = v_sync_wid; + sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) | + (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) | + (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0); + + switch (pix_width) { +#if 0 + case CRTC_PIX_WIDTH_4BPP: + bpp = 4; + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; +#endif + case CRTC_PIX_WIDTH_8BPP: + bpp = 8; + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case CRTC_PIX_WIDTH_15BPP: /* RGB 555 */ + bpp = 16; + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; +#if 0 + case CRTC_PIX_WIDTH_16BPP: /* RGB 565 */ + bpp = 16; + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; +#endif + case CRTC_PIX_WIDTH_24BPP: /* RGB 888 */ + bpp = 24; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case CRTC_PIX_WIDTH_32BPP: /* ARGB 8888 */ + bpp = 32; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + break; + default: + FAIL("Invalid pixel width"); + } + + /* output */ + var->xres = xres; + var->yres = yres; + var->xres_virtual = crtc->vxres; + var->yres_virtual = crtc->vyres; + var->bits_per_pixel = bpp; + var->xoffset = crtc->xoffset; + var->yoffset = crtc->yoffset; + var->left_margin = left; + var->right_margin = right; + var->upper_margin = upper; + var->lower_margin = lower; + var->hsync_len = hslen; + var->vsync_len = vslen; + var->sync = sync; + var->vmode = FB_VMODE_NONINTERLACED; + + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static void atyfb_set_par(const struct atyfb_par *par, + struct fb_info_aty *info) +{ + u32 i; + int accelmode; + u8 tmp; + + accelmode = par->accel_flags; /* hack */ + + info->current_par = *par; + + if (info->blitter_may_be_busy) + wait_for_idle(info); + tmp = aty_ld_8(CRTC_GEN_CNTL + 3, info); + aty_set_crtc(info, &par->crtc); + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info); + /* better call aty_StrobeClock ?? */ + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, CLOCK_STROBE, info); + + info->dac_ops->set_dac(info, &par->pll, par->crtc.bpp, accelmode); + info->pll_ops->set_pll(info, &par->pll); + + if (!M64_HAS(INTEGRATED)) { + /* Don't forget MEM_CNTL */ + i = aty_ld_le32(MEM_CNTL, info) & 0xf0ffffff; + switch (par->crtc.bpp) { + case 8: + i |= 0x02000000; + break; + case 16: + i |= 0x03000000; + break; + case 32: + i |= 0x06000000; + break; + } + aty_st_le32(MEM_CNTL, i, info); + } else { + i = aty_ld_le32(MEM_CNTL, info) & 0xf00fffff; + if (!M64_HAS(MAGIC_POSTDIV)) + i |= info->mem_refresh_rate << 20; + switch (par->crtc.bpp) { + case 8: + case 24: + i |= 0x00000000; + break; + case 16: + i |= 0x04000000; + break; + case 32: + i |= 0x08000000; + break; + } + if (M64_HAS(CT_BUS)) { + aty_st_le32(DAC_CNTL, 0x87010184, info); + aty_st_le32(BUS_CNTL, 0x680000f9, info); + } else if (M64_HAS(VT_BUS)) { + aty_st_le32(DAC_CNTL, 0x87010184, info); + aty_st_le32(BUS_CNTL, 0x680000f9, info); + } else if (M64_HAS(MOBIL_BUS)) { + aty_st_le32(DAC_CNTL, 0x80010102, info); + aty_st_le32(BUS_CNTL, 0x7b33a040, info); + } else { + /* GT */ + aty_st_le32(DAC_CNTL, 0x86010102, info); + aty_st_le32(BUS_CNTL, 0x7b23a040, info); + aty_st_le32(EXT_MEM_CNTL, + aty_ld_le32(EXT_MEM_CNTL, info) | 0x5000001, info); + } + aty_st_le32(MEM_CNTL, i, info); + } + aty_st_8(DAC_MASK, 0xff, info); + + /* Initialize the graphics engine */ + if (par->accel_flags & FB_ACCELF_TEXT) + aty_init_engine(par, info); + +#ifdef CONFIG_FB_COMPAT_XPMAC + if (!console_fb_info || console_fb_info == &info->fb_info) { + struct fb_var_screeninfo var; + int vmode, cmode; + display_info.height = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1; + display_info.width = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8; + display_info.depth = par->crtc.bpp; + display_info.pitch = par->crtc.vxres*par->crtc.bpp/8; + atyfb_encode_var(&var, par, info); + if (mac_var_to_vmode(&var, &vmode, &cmode)) + display_info.mode = 0; + else + display_info.mode = vmode; + strcpy(display_info.name, atyfb_name); + display_info.fb_address = info->frame_buffer_phys; + display_info.cmap_adr_address = info->ati_regbase_phys+0xc0; + display_info.cmap_data_address = info->ati_regbase_phys+0xc1; + display_info.disp_reg_address = info->ati_regbase_phys; + } +#endif /* CONFIG_FB_COMPAT_XPMAC */ +} + +static int atyfb_decode_var(const struct fb_var_screeninfo *var, + struct atyfb_par *par, + const struct fb_info_aty *info) +{ + int err; + + if ((err = aty_var_to_crtc(info, var, &par->crtc)) || + (err = info->pll_ops->var_to_pll(info, var->pixclock, par->crtc.bpp, + &par->pll))) + return err; + + if (var->accel_flags & FB_ACCELF_TEXT) + par->accel_flags = FB_ACCELF_TEXT; + else + par->accel_flags = 0; + +#if 0 /* fbmon is not done. uncomment for 2.5.x -brad */ + if (!fbmon_valid_timings(var->pixclock, htotal, vtotal, info)) + return -EINVAL; +#endif + + return 0; +} + +static int atyfb_encode_var(struct fb_var_screeninfo *var, + const struct atyfb_par *par, + const struct fb_info_aty *info) +{ + int err; + + memset(var, 0, sizeof(struct fb_var_screeninfo)); + + if ((err = aty_crtc_to_var(&par->crtc, var))) + return err; + var->pixclock = info->pll_ops->pll_to_var(info, &par->pll); + + var->height = -1; + var->width = -1; + var->accel_flags = par->accel_flags; + + return 0; +} + + + +static void set_off_pitch(struct atyfb_par *par, + const struct fb_info_aty *info) +{ + u32 xoffset = par->crtc.xoffset; + u32 yoffset = par->crtc.yoffset; + u32 vxres = par->crtc.vxres; + u32 bpp = par->crtc.bpp; + + par->crtc.off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19); + aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, info); +} + + + /* + * Open/Release the frame buffer device + */ + +static int atyfb_open(struct fb_info *info, int user) + +{ +#ifdef __sparc__ + struct fb_info_aty *fb = (struct fb_info_aty *)info; + + if (user) { + fb->open++; + fb->mmaped = 0; + fb->vtconsole = -1; + } else { + fb->consolecnt++; + } +#endif + return(0); +} + +struct fb_var_screeninfo default_var = { + /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ + 640, 480, 640, 480, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2, + 0, FB_VMODE_NONINTERLACED +}; + +static int atyfb_release(struct fb_info *info, int user) +{ +#ifdef __sparc__ + struct fb_info_aty *fb = (struct fb_info_aty *)info; + + if (user) { + fb->open--; + mdelay(1); + wait_for_idle(fb); + if (!fb->open) { + int was_mmaped = fb->mmaped; + + fb->mmaped = 0; + if (fb->vtconsole != -1) + vt_cons[fb->vtconsole]->vc_mode = KD_TEXT; + fb->vtconsole = -1; + + if (was_mmaped) { + struct fb_var_screeninfo var; + + /* Now reset the default display config, we have no + * idea what the program(s) which mmap'd the chip did + * to the configuration, nor whether it restored it + * correctly. + */ + var = default_var; + if (noaccel) + var.accel_flags &= ~FB_ACCELF_TEXT; + else + var.accel_flags |= FB_ACCELF_TEXT; + if (var.yres == var.yres_virtual) { + u32 vram = (fb->total_vram - (PAGE_SIZE << 2)); + var.yres_virtual = ((vram * 8) / var.bits_per_pixel) / + var.xres_virtual; + if (var.yres_virtual < var.yres) + var.yres_virtual = var.yres; + } + atyfb_set_var(&var, -1, &fb->fb_info); + } + } + } else { + fb->consolecnt--; + } +#endif + return(0); +} + + +static int encode_fix(struct fb_fix_screeninfo *fix, + const struct atyfb_par *par, + const struct fb_info_aty *info) +{ + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + + strcpy(fix->id, atyfb_name); + fix->smem_start = info->frame_buffer_phys; + fix->smem_len = (u32)info->total_vram; + + /* + * Reg Block 0 (CT-compatible block) is at ati_regbase_phys + * Reg Block 1 (multimedia extensions) is at ati_regbase_phys-0x400 + */ + if (M64_HAS(GX)) { + fix->mmio_start = info->ati_regbase_phys; + fix->mmio_len = 0x400; + fix->accel = FB_ACCEL_ATI_MACH64GX; + } else if (M64_HAS(CT)) { + fix->mmio_start = info->ati_regbase_phys; + fix->mmio_len = 0x400; + fix->accel = FB_ACCEL_ATI_MACH64CT; + } else if (M64_HAS(VT)) { + fix->mmio_start = info->ati_regbase_phys-0x400; + fix->mmio_len = 0x800; + fix->accel = FB_ACCEL_ATI_MACH64VT; + } else /* if (M64_HAS(GT)) */ { + fix->mmio_start = info->ati_regbase_phys-0x400; + fix->mmio_len = 0x800; + fix->accel = FB_ACCEL_ATI_MACH64GT; + } + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + fix->line_length = par->crtc.vxres*par->crtc.bpp/8; + fix->visual = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR + : FB_VISUAL_DIRECTCOLOR; + fix->ywrapstep = 0; + fix->xpanstep = 8; + fix->ypanstep = 1; + + return 0; +} + + + /* + * Get the Fixed Part of the Display + */ + +static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *fb) +{ + const struct fb_info_aty *info = (struct fb_info_aty *)fb; + struct atyfb_par par; + + if (con == -1) + par = info->default_par; + else + atyfb_decode_var(&fb_display[con].var, &par, info); + encode_fix(fix, &par, info); + return 0; +} + + + /* + * Get the User Defined Part of the Display + */ + +static int atyfb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *fb) +{ + const struct fb_info_aty *info = (struct fb_info_aty *)fb; + + if (con == -1) + atyfb_encode_var(var, &info->default_par, info); + else + *var = fb_display[con].var; + return 0; +} + + +static void atyfb_set_dispsw(struct display *disp, struct fb_info_aty *info, + int bpp, int accel) +{ + switch (bpp) { +#ifdef FBCON_HAS_CFB8 + case 8: + info->dispsw = accel ? fbcon_aty8 : fbcon_cfb8; + disp->dispsw = &info->dispsw; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + info->dispsw = accel ? fbcon_aty16 : fbcon_cfb16; + disp->dispsw = &info->dispsw; + disp->dispsw_data = info->fbcon_cmap.cfb16; + break; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: + info->dispsw = accel ? fbcon_aty24 : fbcon_cfb24; + disp->dispsw = &info->dispsw; + disp->dispsw_data = info->fbcon_cmap.cfb24; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + info->dispsw = accel ? fbcon_aty32 : fbcon_cfb32; + disp->dispsw = &info->dispsw; + disp->dispsw_data = info->fbcon_cmap.cfb32; + break; +#endif + default: + disp->dispsw = &fbcon_dummy; + } +#ifdef CONFIG_FB_ATY_CT + if (info->cursor) { + info->dispsw.cursor = atyfb_cursor; + info->dispsw.set_font = atyfb_set_font; + } +#endif /* CONFIG_FB_ATY_CT */ +} + + + /* + * Set the User Defined Part of the Display + */ + +static int atyfb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *fb) +{ + struct fb_info_aty *info = (struct fb_info_aty *)fb; + struct atyfb_par par; + struct display *display; + int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err; + int activate = var->activate; + + if (con >= 0) + display = &fb_display[con]; + else + display = fb->disp; /* used during initialization */ + + if ((err = atyfb_decode_var(var, &par, info))) + return err; + + atyfb_encode_var(var, &par, (struct fb_info_aty *)info); + + if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + oldxres = display->var.xres; + oldyres = display->var.yres; + oldvxres = display->var.xres_virtual; + oldvyres = display->var.yres_virtual; + oldbpp = display->var.bits_per_pixel; + oldaccel = display->var.accel_flags; + display->var = *var; + accel = var->accel_flags & FB_ACCELF_TEXT; + if (oldxres != var->xres || oldyres != var->yres || + oldvxres != var->xres_virtual || oldvyres != var->yres_virtual || + oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) { + struct fb_fix_screeninfo fix; + + encode_fix(&fix, &par, info); + display->screen_base = (char *)info->frame_buffer; + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->line_length = fix.line_length; + display->can_soft_blank = 1; + display->inverse = 0; + if (accel) + display->scrollmode = (info->bus_type == PCI) ? SCROLL_YNOMOVE : 0; + else + display->scrollmode = SCROLL_YREDRAW; + if (info->fb_info.changevar) + (*info->fb_info.changevar)(con); + } + if (!info->fb_info.display_fg || + info->fb_info.display_fg->vc_num == con) { + atyfb_set_par(&par, info); + atyfb_set_dispsw(display, info, par.crtc.bpp, accel); + } + if (oldbpp != var->bits_per_pixel) { + if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) + return err; + do_install_cmap(con, &info->fb_info); + } + } + + return 0; +} + + + /* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + */ + +static int atyfb_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info *fb) +{ + struct fb_info_aty *info = (struct fb_info_aty *)fb; + u32 xres, yres, xoffset, yoffset; + struct atyfb_par *par = &info->current_par; + + xres = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8; + yres = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1; + xoffset = (var->xoffset+7) & ~7; + yoffset = var->yoffset; + if (xoffset+xres > par->crtc.vxres || yoffset+yres > par->crtc.vyres) + return -EINVAL; + par->crtc.xoffset = xoffset; + par->crtc.yoffset = yoffset; + set_off_pitch(par, info); + return 0; +} + + /* + * Get the Colormap + */ + +static int atyfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + if (!info->display_fg || con == info->display_fg->vc_num) /* current console? */ + return fb_get_cmap(cmap, kspc, atyfb_getcolreg, info); + else if (fb_display[con].cmap.len) /* non default colormap? */ + fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); + else { + int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; + fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2); + } + return 0; +} + + /* + * Set the Colormap + */ + +static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + int err; + struct display *disp; + + if (con >= 0) + disp = &fb_display[con]; + else + disp = info->disp; + if (!disp->cmap.len) { /* no colormap allocated? */ + int size = disp->var.bits_per_pixel == 16 ? 32 : 256; + if ((err = fb_alloc_cmap(&disp->cmap, size, 0))) + return err; + } + if (!info->display_fg || con == info->display_fg->vc_num) /* current console? */ + return fb_set_cmap(cmap, kspc, atyfb_setcolreg, info); + else + fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1); + return 0; +} + + +#ifdef DEBUG +#define ATYIO_CLKR 0x41545900 /* ATY\00 */ +#define ATYIO_CLKW 0x41545901 /* ATY\01 */ + +struct atyclk { + u32 ref_clk_per; + u8 pll_ref_div; + u8 mclk_fb_div; + u8 mclk_post_div; /* 1,2,3,4,8 */ + u8 vclk_fb_div; + u8 vclk_post_div; /* 1,2,3,4,6,8,12 */ + u32 dsp_xclks_per_row; /* 0-16383 */ + u32 dsp_loop_latency; /* 0-15 */ + u32 dsp_precision; /* 0-7 */ + u32 dsp_on; /* 0-2047 */ + u32 dsp_off; /* 0-2047 */ +}; + +#define ATYIO_FEATR 0x41545902 /* ATY\02 */ +#define ATYIO_FEATW 0x41545903 /* ATY\03 */ +#endif + +static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con, struct fb_info *info2) +{ +#if defined(__sparc__) || (defined(DEBUG) && defined(CONFIG_FB_ATY_CT)) + struct fb_info_aty *info = (struct fb_info_aty *)info2; +#endif /* __sparc__ || DEBUG */ +#ifdef __sparc__ + struct fbtype fbtyp; + struct display *disp; + + if (con >= 0) + disp = &fb_display[con]; + else + disp = info2->disp; +#endif + + switch (cmd) { +#ifdef __sparc__ + case FBIOGTYPE: + fbtyp.fb_type = FBTYPE_PCI_GENERIC; + fbtyp.fb_width = info->current_par.crtc.vxres; + fbtyp.fb_height = info->current_par.crtc.vyres; + fbtyp.fb_depth = info->current_par.crtc.bpp; + fbtyp.fb_cmsize = disp->cmap.len; + fbtyp.fb_size = info->total_vram; + if (copy_to_user((struct fbtype *)arg, &fbtyp, sizeof(fbtyp))) + return -EFAULT; + break; +#endif /* __sparc__ */ +#if defined(DEBUG) && defined(CONFIG_FB_ATY_CT) + case ATYIO_CLKR: + if (M64_HAS(INTEGRATED)) { + struct atyclk clk; + union aty_pll *pll = &info->current_par.pll; + u32 dsp_config = pll->ct.dsp_config; + u32 dsp_on_off = pll->ct.dsp_on_off; + clk.ref_clk_per = info->ref_clk_per; + clk.pll_ref_div = pll->ct.pll_ref_div; + clk.mclk_fb_div = pll->ct.mclk_fb_div; + clk.mclk_post_div = pll->ct.mclk_post_div_real; + clk.vclk_fb_div = pll->ct.vclk_fb_div; + clk.vclk_post_div = pll->ct.vclk_post_div_real; + clk.dsp_xclks_per_row = dsp_config & 0x3fff; + clk.dsp_loop_latency = (dsp_config>>16) & 0xf; + clk.dsp_precision = (dsp_config>>20) & 7; + clk.dsp_on = dsp_on_off & 0x7ff; + clk.dsp_off = (dsp_on_off>>16) & 0x7ff; + if (copy_to_user((struct atyclk *)arg, &clk, sizeof(clk))) + return -EFAULT; + } else + return -EINVAL; + break; + case ATYIO_CLKW: + if (M64_HAS(INTEGRATED)) { + struct atyclk clk; + union aty_pll *pll = &info->current_par.pll; + if (copy_from_user(&clk, (struct atyclk *)arg, sizeof(clk))) + return -EFAULT; + info->ref_clk_per = clk.ref_clk_per; + pll->ct.pll_ref_div = clk.pll_ref_div; + pll->ct.mclk_fb_div = clk.mclk_fb_div; + pll->ct.mclk_post_div_real = clk.mclk_post_div; + pll->ct.vclk_fb_div = clk.vclk_fb_div; + pll->ct.vclk_post_div_real = clk.vclk_post_div; + pll->ct.dsp_config = (clk.dsp_xclks_per_row & 0x3fff) | + ((clk.dsp_loop_latency & 0xf)<<16) | + ((clk.dsp_precision & 7)<<20); + pll->ct.dsp_on_off = (clk.dsp_on & 0x7ff) | + ((clk.dsp_off & 0x7ff)<<16); + aty_calc_pll_ct(info, &pll->ct); + aty_set_pll_ct(info, pll); + } else + return -EINVAL; + break; + case ATYIO_FEATR: + if (get_user(info->features, (u32 *)arg)) + return -EFAULT; + break; + case ATYIO_FEATW: + if (put_user(info->features, (u32 *)arg)) + return -EFAULT; + break; +#endif /* DEBUG && CONFIG_FB_ATY_CT */ + default: + return -EINVAL; + } + return 0; +} + +static int atyfb_rasterimg(struct fb_info *info, int start) +{ + struct fb_info_aty *fb = (struct fb_info_aty *)info; + + if (fb->blitter_may_be_busy) + wait_for_idle(fb); + return 0; +} + +#ifdef __sparc__ +static int atyfb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma) +{ + struct fb_info_aty *fb = (struct fb_info_aty *)info; + unsigned int size, page, map_size = 0; + unsigned long map_offset = 0; + unsigned long off; + int i; + + if (!fb->mmap_map) + return -ENXIO; + + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) + return -EINVAL; + + off = vma->vm_pgoff << PAGE_SHIFT; + size = vma->vm_end - vma->vm_start; + + /* To stop the swapper from even considering these pages. */ + vma->vm_flags |= (VM_SHM | VM_LOCKED); + + if (((vma->vm_pgoff == 0) && (size == fb->total_vram)) || + ((off == fb->total_vram) && (size == PAGE_SIZE))) + off += 0x8000000000000000UL; + + vma->vm_pgoff = off >> PAGE_SHIFT; /* propagate off changes */ + + /* Each page, see which map applies */ + for (page = 0; page < size; ) { + map_size = 0; + for (i = 0; fb->mmap_map[i].size; i++) { + unsigned long start = fb->mmap_map[i].voff; + unsigned long end = start + fb->mmap_map[i].size; + unsigned long offset = off + page; + + if (start > offset) + continue; + if (offset >= end) + continue; + + map_size = fb->mmap_map[i].size - (offset - start); + map_offset = fb->mmap_map[i].poff + (offset - start); + break; + } + if (!map_size) { + page += PAGE_SIZE; + continue; + } + if (page + map_size > size) + map_size = size - page; + + pgprot_val(vma->vm_page_prot) &= ~(fb->mmap_map[i].prot_mask); + pgprot_val(vma->vm_page_prot) |= fb->mmap_map[i].prot_flag; + + if (remap_page_range(vma->vm_start + page, map_offset, + map_size, vma->vm_page_prot)) + return -EAGAIN; + + page += map_size; + } + + if (!map_size) + return -EINVAL; + + vma->vm_flags |= VM_IO; + + if (!fb->mmaped) { + int lastconsole = 0; + + if (info->display_fg) + lastconsole = info->display_fg->vc_num; + fb->mmaped = 1; + if (fb->consolecnt && fb_display[lastconsole].fb_info == info) { + fb->vtconsole = lastconsole; + vt_cons[lastconsole]->vc_mode = KD_GRAPHICS; + } + } + return 0; +} + +static struct { + u32 yoffset; + u8 r[2][256]; + u8 g[2][256]; + u8 b[2][256]; +} atyfb_save; + +static void atyfb_save_palette(struct fb_info *fb, int enter) +{ + struct fb_info_aty *info = (struct fb_info_aty *)fb; + int i, tmp, scale; + + for (i = 0; i < 256; i++) { + tmp = aty_ld_8(DAC_CNTL, info) & 0xfc; + if (M64_HAS(EXTRA_BRIGHT)) + tmp |= 0x2; + aty_st_8(DAC_CNTL, tmp, info); + aty_st_8(DAC_MASK, 0xff, info); + + scale = (M64_HAS(INTEGRATED) && + info->current_par.crtc.bpp == 16) ? 3 : 0; + writeb(i << scale, &info->aty_cmap_regs->rindex); + + atyfb_save.r[enter][i] = readb(&info->aty_cmap_regs->lut); + atyfb_save.g[enter][i] = readb(&info->aty_cmap_regs->lut); + atyfb_save.b[enter][i] = readb(&info->aty_cmap_regs->lut); + writeb(i << scale, &info->aty_cmap_regs->windex); + writeb(atyfb_save.r[1-enter][i], &info->aty_cmap_regs->lut); + writeb(atyfb_save.g[1-enter][i], &info->aty_cmap_regs->lut); + writeb(atyfb_save.b[1-enter][i], &info->aty_cmap_regs->lut); + } +} + +static void atyfb_palette(int enter) +{ + struct fb_info_aty *info; + struct atyfb_par *par; + struct display *d; + int i; + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + d = &fb_display[i]; + if (d->fb_info && + d->fb_info->fbops == &atyfb_ops && + d->fb_info->display_fg && + d->fb_info->display_fg->vc_num == i) { + atyfb_save_palette(d->fb_info, enter); + info = (struct fb_info_aty *)d->fb_info; + par = &info->current_par; + if (enter) { + atyfb_save.yoffset = par->crtc.yoffset; + par->crtc.yoffset = 0; + set_off_pitch(par, info); + } else { + par->crtc.yoffset = atyfb_save.yoffset; + set_off_pitch(par, info); + } + break; + } + } +} +#endif /* __sparc__ */ + + + +#ifdef CONFIG_PMAC_PBOOK + +static struct fb_info_aty* first_display = NULL; + +/* Power management routines. Those are used for PowerBook sleep. + * + * It appears that Rage LT and Rage LT Pro have different power + * management registers. There's is some confusion about which + * chipID is a Rage LT or LT pro :( + */ +static int aty_power_mgmt_LT(int sleep, struct fb_info_aty *info) +{ + unsigned int pm; + int timeout; + + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + + timeout = 200000; + if (sleep) { + /* Sleep */ + pm &= ~PWR_MGT_ON; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + udelay(10); + pm &= ~(PWR_BLON | AUTO_PWR_UP); + pm |= SUSPEND_NOW; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + udelay(10); + pm |= PWR_MGT_ON; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + do { + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + udelay(10); + if ((--timeout) == 0) + break; + } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND); + } else { + /* Wakeup */ + pm &= ~PWR_MGT_ON; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + udelay(10); + pm |= (PWR_BLON | AUTO_PWR_UP); + pm &= ~SUSPEND_NOW; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + udelay(10); + pm |= PWR_MGT_ON; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + do { + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + udelay(10); + if ((--timeout) == 0) + break; + } while ((pm & PWR_MGT_STATUS_MASK) != 0); + } + mdelay(500); + + return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE; +} + +static int aty_power_mgmt_LTPro(int sleep, struct fb_info_aty *info) +{ + unsigned int pm; + int timeout; + + pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); + pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG; + aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); + pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); + + timeout = 200; + if (sleep) { + /* Sleep */ + pm &= ~PWR_MGT_ON; + aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); + pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); + udelay(10); + pm &= ~(PWR_BLON | AUTO_PWR_UP); + pm |= SUSPEND_NOW; + aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); + pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); + udelay(10); + pm |= PWR_MGT_ON; + aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); + do { + pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); + mdelay(1); + if ((--timeout) == 0) + break; + } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND); + } else { + /* Wakeup */ + pm &= ~PWR_MGT_ON; + aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); + pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); + udelay(10); + pm &= ~SUSPEND_NOW; + pm |= (PWR_BLON | AUTO_PWR_UP); + aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); + pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); + udelay(10); + pm |= PWR_MGT_ON; + aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); + do { + pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); + mdelay(1); + if ((--timeout) == 0) + break; + } while ((pm & PWR_MGT_STATUS_MASK) != 0); + } + + return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE; +} + +static int aty_power_mgmt(int sleep, struct fb_info_aty *info) +{ + return M64_HAS(LT_SLEEP) ? aty_power_mgmt_LT(sleep, info) + : aty_power_mgmt_LTPro(sleep, info); +} + +/* + * Save the contents of the frame buffer when we go to sleep, + * and restore it when we wake up again. + */ +static int aty_sleep_notify(struct pmu_sleep_notifier *self, int when) +{ + struct fb_info_aty *info; + int result; + + result = PBOOK_SLEEP_OK; + + for (info = first_display; info != NULL; info = info->next) { + struct fb_fix_screeninfo fix; + int nb; + + atyfb_get_fix(&fix, fg_console, (struct fb_info *)info); + nb = fb_display[fg_console].var.yres * fix.line_length; + + switch (when) { + case PBOOK_SLEEP_REQUEST: + info->save_framebuffer = vmalloc(nb); + if (info->save_framebuffer == NULL) + return PBOOK_SLEEP_REFUSE; + break; + case PBOOK_SLEEP_REJECT: + if (info->save_framebuffer) { + vfree(info->save_framebuffer); + info->save_framebuffer = 0; + } + break; + case PBOOK_SLEEP_NOW: + if (info->blitter_may_be_busy) + wait_for_idle(info); + /* Stop accel engine (stop bus mastering) */ + if (info->current_par.accel_flags & FB_ACCELF_TEXT) + aty_reset_engine(info); + + /* Backup fb content */ + if (info->save_framebuffer) + memcpy_fromio(info->save_framebuffer, + (void *)info->frame_buffer, nb); + + /* Blank display and LCD */ + atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info); + + /* Set chip to "suspend" mode */ + result = aty_power_mgmt(1, info); + break; + case PBOOK_WAKE: + /* Wakeup chip */ + result = aty_power_mgmt(0, info); + + /* Restore fb content */ + if (info->save_framebuffer) { + memcpy_toio((void *)info->frame_buffer, + info->save_framebuffer, nb); + vfree(info->save_framebuffer); + info->save_framebuffer = 0; + } + /* Restore display */ + atyfb_set_par(&info->current_par, info); + atyfbcon_blank(0, (struct fb_info *)info); + break; + } + } + return result; +} + +static struct pmu_sleep_notifier aty_sleep_notifier = { + aty_sleep_notify, SLEEP_LEVEL_VIDEO, +}; +#endif /* CONFIG_PMAC_PBOOK */ + +#ifdef CONFIG_PMAC_BACKLIGHT + + /* + * LCD backlight control + */ + +static int backlight_conv[] = { + 0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d, + 0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff +}; + +static int +aty_set_backlight_enable(int on, int level, void* data) +{ + struct fb_info_aty *info = (struct fb_info_aty *)data; + unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, info); + + reg |= (BLMOD_EN | BIASMOD_EN); + if (on && level > BACKLIGHT_OFF) { + reg &= ~BIAS_MOD_LEVEL_MASK; + reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT); + } else { + reg &= ~BIAS_MOD_LEVEL_MASK; + reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT); + } + aty_st_lcd(LCD_MISC_CNTL, reg, info); + + return 0; +} + +static int +aty_set_backlight_level(int level, void* data) +{ + return aty_set_backlight_enable(1, level, data); +} + +static struct backlight_controller aty_backlight_controller = { + aty_set_backlight_enable, + aty_set_backlight_level +}; +#endif /* CONFIG_PMAC_BACKLIGHT */ + + + + /* + * Initialisation + */ + +static struct fb_info_aty *fb_list = NULL; + +static int __init aty_init(struct fb_info_aty *info, const char *name) +{ + u32 chip_id; + u32 i; + int j, k; + struct fb_var_screeninfo var; + struct display *disp; + u16 type; + u8 rev; + const char *chipname = NULL, *ramname = NULL, *xtal; + int pll, mclk, gtb_memsize; +#if defined(CONFIG_PPC) + int sense; +#endif + u8 pll_ref_div; + + info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0); + chip_id = aty_ld_le32(CONFIG_CHIP_ID, info); + type = chip_id & CFG_CHIP_TYPE; + rev = (chip_id & CFG_CHIP_REV)>>24; + for (j = 0; j < (sizeof(aty_chips)/sizeof(*aty_chips)); j++) + if (type == aty_chips[j].chip_type && + (rev & aty_chips[j].rev_mask) == aty_chips[j].rev_val) { + chipname = aty_chips[j].name; + pll = aty_chips[j].pll; + mclk = aty_chips[j].mclk; + info->features = aty_chips[j].features; + goto found; + } + printk("atyfb: Unknown mach64 0x%04x rev 0x%04x\n", type, rev); + return 0; + +found: + printk("*NEW* atyfb: %s [0x%04x rev 0x%02x] ", chipname, type, rev); +#ifdef CONFIG_FB_ATY_GX + if (!M64_HAS(INTEGRATED)) { + u32 stat0; + u8 dac_type, dac_subtype, clk_type; + stat0 = aty_ld_le32(CONFIG_STAT0, info); + info->bus_type = (stat0 >> 0) & 0x07; + info->ram_type = (stat0 >> 3) & 0x07; + ramname = aty_gx_ram[info->ram_type]; + /* FIXME: clockchip/RAMDAC probing? */ + dac_type = (aty_ld_le32(DAC_CNTL, info) >> 16) & 0x07; +#ifdef CONFIG_ATARI + clk_type = CLK_ATI18818_1; + dac_type = (stat0 >> 9) & 0x07; + if (dac_type == 0x07) + dac_subtype = DAC_ATT20C408; + else + dac_subtype = (aty_ld_8(SCRATCH_REG1 + 1, info) & 0xF0) | dac_type; +#else + dac_type = DAC_IBMRGB514; + dac_subtype = DAC_IBMRGB514; + clk_type = CLK_IBMRGB514; +#endif + switch (dac_subtype) { + case DAC_IBMRGB514: + info->dac_ops = &aty_dac_ibm514; + break; + case DAC_ATI68860_B: + case DAC_ATI68860_C: + info->dac_ops = &aty_dac_ati68860b; + break; + case DAC_ATT20C408: + case DAC_ATT21C498: + info->dac_ops = &aty_dac_att21c498; + break; + default: + printk(" atyfb_set_par: DAC type not implemented yet!\n"); + info->dac_ops = &aty_dac_unsupported; + break; + } + switch (clk_type) { + case CLK_ATI18818_1: + info->pll_ops = &aty_pll_ati18818_1; + break; + case CLK_STG1703: + info->pll_ops = &aty_pll_stg1703; + break; + case CLK_CH8398: + info->pll_ops = &aty_pll_ch8398; + break; + case CLK_ATT20C408: + info->pll_ops = &aty_pll_att20c408; + break; + case CLK_IBMRGB514: + info->pll_ops = &aty_pll_ibm514; + break; + default: + printk(" atyfb_set_par: CLK type not implemented yet!"); + info->pll_ops = &aty_pll_unsupported; + break; + } + } +#endif /* CONFIG_FB_ATY_GX */ +#ifdef CONFIG_FB_ATY_CT + if (M64_HAS(INTEGRATED)) { + info->bus_type = PCI; + info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) & 0x07); + ramname = aty_ct_ram[info->ram_type]; + info->dac_ops = &aty_dac_ct; + info->pll_ops = &aty_pll_ct; + /* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */ + if (mclk == 67 && info->ram_type < SDRAM) + mclk = 63; + } +#endif /* CONFIG_FB_ATY_CT */ + + info->ref_clk_per = 1000000000000ULL/14318180; + xtal = "14.31818"; + if (M64_HAS(GTB_DSP) && (pll_ref_div = aty_ld_pll(PLL_REF_DIV, info))) { + int diff1, diff2; + diff1 = 510*14/pll_ref_div-pll; + diff2 = 510*29/pll_ref_div-pll; + if (diff1 < 0) + diff1 = -diff1; + if (diff2 < 0) + diff2 = -diff2; + if (diff2 < diff1) { + info->ref_clk_per = 1000000000000ULL/29498928; + xtal = "29.498928"; + } + } + + i = aty_ld_le32(MEM_CNTL, info); + gtb_memsize = M64_HAS(GTB_DSP); + if (gtb_memsize) + switch (i & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */ + case MEM_SIZE_512K: + info->total_vram = 0x80000; + break; + case MEM_SIZE_1M: + info->total_vram = 0x100000; + break; + case MEM_SIZE_2M_GTB: + info->total_vram = 0x200000; + break; + case MEM_SIZE_4M_GTB: + info->total_vram = 0x400000; + break; + case MEM_SIZE_6M_GTB: + info->total_vram = 0x600000; + break; + case MEM_SIZE_8M_GTB: + info->total_vram = 0x800000; + break; + default: + info->total_vram = 0x80000; + } + else + switch (i & MEM_SIZE_ALIAS) { + case MEM_SIZE_512K: + info->total_vram = 0x80000; + break; + case MEM_SIZE_1M: + info->total_vram = 0x100000; + break; + case MEM_SIZE_2M: + info->total_vram = 0x200000; + break; + case MEM_SIZE_4M: + info->total_vram = 0x400000; + break; + case MEM_SIZE_6M: + info->total_vram = 0x600000; + break; + case MEM_SIZE_8M: + info->total_vram = 0x800000; + break; + default: + info->total_vram = 0x80000; + } + + if (M64_HAS(MAGIC_VRAM_SIZE)) { + if (aty_ld_le32(CONFIG_STAT1, info) & 0x40000000) + info->total_vram += 0x400000; + } + + if (default_vram) { + info->total_vram = default_vram*1024; + i = i & ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS); + if (info->total_vram <= 0x80000) + i |= MEM_SIZE_512K; + else if (info->total_vram <= 0x100000) + i |= MEM_SIZE_1M; + else if (info->total_vram <= 0x200000) + i |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M; + else if (info->total_vram <= 0x400000) + i |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M; + else if (info->total_vram <= 0x600000) + i |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M; + else + i |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M; + aty_st_le32(MEM_CNTL, i, info); + } + if (default_pll) + pll = default_pll; + if (default_mclk) + mclk = default_mclk; + + printk("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK\n", + info->total_vram == 0x80000 ? 512 : (info->total_vram >> 20), + info->total_vram == 0x80000 ? 'K' : 'M', ramname, xtal, pll, mclk); + + if (mclk < 44) + info->mem_refresh_rate = 0; /* 000 = 10 Mhz - 43 Mhz */ + else if (mclk < 50) + info->mem_refresh_rate = 1; /* 001 = 44 Mhz - 49 Mhz */ + else if (mclk < 55) + info->mem_refresh_rate = 2; /* 010 = 50 Mhz - 54 Mhz */ + else if (mclk < 66) + info->mem_refresh_rate = 3; /* 011 = 55 Mhz - 65 Mhz */ + else if (mclk < 75) + info->mem_refresh_rate = 4; /* 100 = 66 Mhz - 74 Mhz */ + else if (mclk < 80) + info->mem_refresh_rate = 5; /* 101 = 75 Mhz - 79 Mhz */ + else if (mclk < 100) + info->mem_refresh_rate = 6; /* 110 = 80 Mhz - 100 Mhz */ + else + info->mem_refresh_rate = 7; /* 111 = 100 Mhz and above */ + info->pll_per = 1000000/pll; + info->mclk_per = 1000000/mclk; + +#ifdef DEBUG + if (M64_HAS(INTEGRATED)) { + int i; + printk("BUS_CNTL DAC_CNTL MEM_CNTL EXT_MEM_CNTL CRTC_GEN_CNTL " + "DSP_CONFIG DSP_ON_OFF\n" + "%08x %08x %08x %08x %08x %08x %08x\n" + "PLL", + aty_ld_le32(BUS_CNTL, info), aty_ld_le32(DAC_CNTL, info), + aty_ld_le32(MEM_CNTL, info), aty_ld_le32(EXT_MEM_CNTL, info), + aty_ld_le32(CRTC_GEN_CNTL, info), aty_ld_le32(DSP_CONFIG, info), + aty_ld_le32(DSP_ON_OFF, info)); + for (i = 0; i < 16; i++) + printk(" %02x", aty_ld_pll(i, info)); + printk("\n"); + } +#endif + + /* + * Last page of 8 MB (4 MB on ISA) aperture is MMIO + * FIXME: we should use the auxiliary aperture instead so we can acces the + * full 8 MB of video RAM on 8 MB boards + */ + if (info->total_vram == 0x800000 || + (info->bus_type == ISA && info->total_vram == 0x400000)) + info->total_vram -= GUI_RESERVE; + + /* Clear the video memory */ + fb_memset((void *)info->frame_buffer, 0, info->total_vram); + + disp = &info->disp; + + strcpy(info->fb_info.modename, atyfb_name); + info->fb_info.node = -1; + info->fb_info.fbops = &atyfb_ops; + info->fb_info.disp = disp; + strcpy(info->fb_info.fontname, fontname); + info->fb_info.changevar = NULL; + info->fb_info.switch_con = &atyfbcon_switch; + info->fb_info.updatevar = &atyfbcon_updatevar; + info->fb_info.blank = &atyfbcon_blank; + info->fb_info.flags = FBINFO_FLAG_DEFAULT; + +#ifdef CONFIG_PMAC_BACKLIGHT + if (M64_HAS(G3_PB_1_1) && machine_is_compatible("PowerBook1,1")) { + /* these bits let the 101 powerbook wake up from sleep -- paulus */ + aty_st_lcd(LCD_POWER_MANAGEMENT, aty_ld_lcd(LCD_POWER_MANAGEMENT, info) + | (USE_F32KHZ | TRISTATE_MEM_EN), info); + } + if (M64_HAS(MOBIL_BUS)) + register_backlight_controller(&aty_backlight_controller, info, "ati"); +#endif /* CONFIG_PMAC_BACKLIGHT */ + +#ifdef MODULE + var = default_var; +#else /* !MODULE */ + memset(&var, 0, sizeof(var)); +#ifdef CONFIG_PPC + if (_machine == _MACH_Pmac) { + /* + * FIXME: The NVRAM stuff should be put in a Mac-specific file, as it + * applies to all Mac video cards + */ + if (mode_option) { + if (!mac_find_mode(&var, &info->fb_info, mode_option, 8)) + var = default_var; + } else { +#ifdef CONFIG_NVRAM + if (default_vmode == VMODE_NVRAM) { + default_vmode = nvram_read_byte(NV_VMODE); + if (default_vmode <= 0 || default_vmode > VMODE_MAX) + default_vmode = VMODE_CHOOSE; + } +#endif + if (default_vmode == VMODE_CHOOSE) { + if (M64_HAS(G3_PB_1024x768)) + /* G3 PowerBook with 1024x768 LCD */ + default_vmode = VMODE_1024_768_60; + else if (machine_is_compatible("iMac")) + default_vmode = VMODE_1024_768_75; + else if (machine_is_compatible("PowerBook2,1")) + /* iBook with 800x600 LCD */ + default_vmode = VMODE_800_600_60; + else + default_vmode = VMODE_640_480_67; + sense = read_aty_sense(info); + printk(KERN_INFO "atyfb: monitor sense=%x, mode %d\n", + sense, mac_map_monitor_sense(sense)); + } + if (default_vmode <= 0 || default_vmode > VMODE_MAX) + default_vmode = VMODE_640_480_60; +#ifdef CONFIG_NVRAM + if (default_cmode == CMODE_NVRAM) + default_cmode = nvram_read_byte(NV_CMODE); +#endif + if (default_cmode < CMODE_8 || default_cmode > CMODE_32) + default_cmode = CMODE_8; + if (mac_vmode_to_var(default_vmode, default_cmode, &var)) + var = default_var; + } + } + else if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, NULL, 8)) + var = default_var; +#else /* !CONFIG_PPC */ +#ifdef __sparc__ + if (mode_option) { + if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, NULL, 8)) + var = default_var; + } else + var = default_var; +#else + if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, NULL, 8)) + var = default_var; +#endif /* !__sparc__ */ +#endif /* !CONFIG_PPC */ +#endif /* !MODULE */ + if (noaccel) + var.accel_flags &= ~FB_ACCELF_TEXT; + else + var.accel_flags |= FB_ACCELF_TEXT; + + if (var.yres == var.yres_virtual) { + u32 vram = (info->total_vram - (PAGE_SIZE << 2)); + var.yres_virtual = ((vram * 8) / var.bits_per_pixel) / var.xres_virtual; + if (var.yres_virtual < var.yres) + var.yres_virtual = var.yres; + } + + if (atyfb_decode_var(&var, &info->default_par, info)) { + printk("atyfb: can't set default video mode\n"); + return 0; + } + +#ifdef __sparc__ + atyfb_save_palette(&info->fb_info, 0); +#endif + for (j = 0; j < 16; j++) { + k = color_table[j]; + info->palette[j].red = default_red[k]; + info->palette[j].green = default_grn[k]; + info->palette[j].blue = default_blu[k]; + } + +#ifdef CONFIG_FB_ATY_CT + if (curblink && M64_HAS(INTEGRATED)) { + info->cursor = aty_init_cursor(info); + if (info->cursor) { + info->dispsw.cursor = atyfb_cursor; + info->dispsw.set_font = atyfb_set_font; + } + } +#endif /* CONFIG_FB_ATY_CT */ + + atyfb_set_var(&var, -1, &info->fb_info); + + if (register_framebuffer(&info->fb_info) < 0) + return 0; + + info->next = fb_list; + fb_list = info; + + printk("fb%d: %s frame buffer device on %s\n", + GET_FB_IDX(info->fb_info.node), atyfb_name, name); + return 1; +} + +int __init atyfb_init(void) +{ +#if defined(CONFIG_PCI) + struct pci_dev *pdev = NULL; + struct fb_info_aty *info; + unsigned long addr, res_start, res_size; + int i; +#ifdef __sparc__ + extern void (*prom_palette) (int); + extern int con_is_present(void); + struct pcidev_cookie *pcp; + char prop[128]; + int node, len, j; + u32 mem, chip_id; + + /* Do not attach when we have a serial console. */ + if (!con_is_present()) + return -ENXIO; +#else + u16 tmp; +#endif + + while ((pdev = pci_find_device(PCI_VENDOR_ID_ATI, PCI_ANY_ID, pdev))) { + if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { + struct resource *rp; + + for (i = sizeof(aty_chips)/sizeof(*aty_chips)-1; i >= 0; i--) + if (pdev->device == aty_chips[i].pci_id) + break; + if (i < 0) + continue; + + info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC); + if (!info) { + printk("atyfb_init: can't alloc fb_info_aty\n"); + return -ENXIO; + } + memset(info, 0, sizeof(struct fb_info_aty)); + + rp = &pdev->resource[0]; + if (rp->flags & IORESOURCE_IO) + rp = &pdev->resource[1]; + addr = rp->start; + if (!addr) + continue; + + res_start = rp->start; + res_size = rp->end-rp->start+1; + if (!request_mem_region(res_start, res_size, "atyfb")) + continue; + +#ifdef __sparc__ + /* + * Map memory-mapped registers. + */ + info->ati_regbase = addr + 0x7ffc00UL; + info->ati_regbase_phys = addr + 0x7ffc00UL; + + /* + * Map in big-endian aperture. + */ + info->frame_buffer = (unsigned long) addr + 0x800000UL; + info->frame_buffer_phys = addr + 0x800000UL; + + /* + * Figure mmap addresses from PCI config space. + * Split Framebuffer in big- and little-endian halfs. + */ + for (i = 0; i < 6 && pdev->resource[i].start; i++) + /* nothing */; + j = i + 4; + + info->mmap_map = kmalloc(j * sizeof(*info->mmap_map), GFP_ATOMIC); + if (!info->mmap_map) { + printk("atyfb_init: can't alloc mmap_map\n"); + kfree(info); + release_mem_region(res_start, res_size); + return -ENXIO; + } + memset(info->mmap_map, 0, j * sizeof(*info->mmap_map)); + + for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) { + struct resource *rp = &pdev->resource[i]; + int io, breg = PCI_BASE_ADDRESS_0 + (i << 2); + unsigned long base; + u32 size, pbase; + + base = rp->start; + + io = (rp->flags & IORESOURCE_IO); + + size = rp->end - base + 1; + + pci_read_config_dword(pdev, breg, &pbase); + + if (io) + size &= ~1; + + /* + * Map the framebuffer a second time, this time without + * the braindead _PAGE_IE setting. This is used by the + * fixed Xserver, but we need to maintain the old mapping + * to stay compatible with older ones... + */ + if (base == addr) { + info->mmap_map[j].voff = (pbase + 0x10000000) & PAGE_MASK; + info->mmap_map[j].poff = base & PAGE_MASK; + info->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK; + info->mmap_map[j].prot_mask = _PAGE_CACHE; + info->mmap_map[j].prot_flag = _PAGE_E; + j++; + } + + /* + * Here comes the old framebuffer mapping with _PAGE_IE + * set for the big endian half of the framebuffer... + */ + if (base == addr) { + info->mmap_map[j].voff = (pbase + 0x800000) & PAGE_MASK; + info->mmap_map[j].poff = (base+0x800000) & PAGE_MASK; + info->mmap_map[j].size = 0x800000; + info->mmap_map[j].prot_mask = _PAGE_CACHE; + info->mmap_map[j].prot_flag = _PAGE_E|_PAGE_IE; + size -= 0x800000; + j++; + } + + info->mmap_map[j].voff = pbase & PAGE_MASK; + info->mmap_map[j].poff = base & PAGE_MASK; + info->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK; + info->mmap_map[j].prot_mask = _PAGE_CACHE; + info->mmap_map[j].prot_flag = _PAGE_E; + j++; + } + + /* + * Fix PROMs idea of MEM_CNTL settings... + */ + mem = aty_ld_le32(MEM_CNTL, info); + chip_id = aty_ld_le32(CONFIG_CHIP_ID, info); + if (((chip_id & CFG_CHIP_TYPE) == VT_CHIP_ID) && + !((chip_id >> 24) & 1)) { + switch (mem & 0x0f) { + case 3: + mem = (mem & ~(0x0f)) | 2; + break; + case 7: + mem = (mem & ~(0x0f)) | 3; + break; + case 9: + mem = (mem & ~(0x0f)) | 4; + break; + case 11: + mem = (mem & ~(0x0f)) | 5; + break; + default: + break; + } + if ((aty_ld_le32(CONFIG_STAT0, info) & 7) >= SDRAM) + mem &= ~(0x00700000); + } + mem &= ~(0xcf80e000); /* Turn off all undocumented bits. */ + aty_st_le32(MEM_CNTL, mem, info); + + /* + * If this is the console device, we will set default video + * settings to what the PROM left us with. + */ + node = prom_getchild(prom_root_node); + node = prom_searchsiblings(node, "aliases"); + if (node) { + len = prom_getproperty(node, "screen", prop, sizeof(prop)); + if (len > 0) { + prop[len] = '\0'; + node = prom_finddevice(prop); + } else { + node = 0; + } + } + + pcp = pdev->sysdata; + if (node == pcp->prom_node) { + + struct fb_var_screeninfo *var = &default_var; + unsigned int N, P, Q, M, T; + u32 v_total, h_total; + struct crtc crtc; + u8 pll_regs[16]; + u8 clock_cntl; + + crtc.vxres = prom_getintdefault(node, "width", 1024); + crtc.vyres = prom_getintdefault(node, "height", 768); + crtc.bpp = prom_getintdefault(node, "depth", 8); + crtc.xoffset = crtc.yoffset = 0; + crtc.h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, info); + crtc.h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, info); + crtc.v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, info); + crtc.v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, info); + crtc.gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, info); + aty_crtc_to_var(&crtc, var); + + h_total = var->xres + var->right_margin + + var->hsync_len + var->left_margin; + v_total = var->yres + var->lower_margin + + var->vsync_len + var->upper_margin; + + /* + * Read the PLL to figure actual Refresh Rate. + */ + clock_cntl = aty_ld_8(CLOCK_CNTL, info); + /* printk("atyfb: CLOCK_CNTL: %02x\n", clock_cntl); */ + for (i = 0; i < 16; i++) + pll_regs[i] = aty_ld_pll(i, info); + + /* + * PLL Reference Devider M: + */ + M = pll_regs[2]; + + /* + * PLL Feedback Devider N (Dependant on CLOCK_CNTL): + */ + N = pll_regs[7 + (clock_cntl & 3)]; + + /* + * PLL Post Devider P (Dependant on CLOCK_CNTL): + */ + P = 1 << (pll_regs[6] >> ((clock_cntl & 3) << 1)); + + /* + * PLL Devider Q: + */ + Q = N / P; + + /* + * Target Frequency: + * + * T * M + * Q = ------- + * 2 * R + * + * where R is XTALIN (= 14318 kHz). + */ + T = 2 * Q * 14318 / M; + + default_var.pixclock = 1000000000 / T; + } + +#else /* __sparc__ */ + + info->ati_regbase_phys = 0x7ff000 + addr; + info->ati_regbase = (unsigned long) + ioremap(info->ati_regbase_phys, 0x1000); + + if(!info->ati_regbase) { + kfree(info); + release_mem_region(res_start, res_size); + return -ENOMEM; + } + + info->ati_regbase_phys += 0xc00; + info->ati_regbase += 0xc00; + + /* + * Enable memory-space accesses using config-space + * command register. + */ + pci_read_config_word(pdev, PCI_COMMAND, &tmp); + if (!(tmp & PCI_COMMAND_MEMORY)) { + tmp |= PCI_COMMAND_MEMORY; + pci_write_config_word(pdev, PCI_COMMAND, tmp); + } + +#ifdef __BIG_ENDIAN + /* Use the big-endian aperture */ + addr += 0x800000; +#endif + + /* Map in frame buffer */ + info->frame_buffer_phys = addr; + info->frame_buffer = (unsigned long)ioremap(addr, 0x800000); + + if(!info->frame_buffer) { + kfree(info); + release_mem_region(res_start, res_size); + return -ENXIO; + } + +#endif /* __sparc__ */ + + if (!aty_init(info, "PCI")) { + if (info->mmap_map) + kfree(info->mmap_map); + kfree(info); + release_mem_region(res_start, res_size); + return -ENXIO; + } + +#ifdef __sparc__ + if (!prom_palette) + prom_palette = atyfb_palette; + + /* + * Add /dev/fb mmap values. + */ + info->mmap_map[0].voff = 0x8000000000000000UL; + info->mmap_map[0].poff = info->frame_buffer & PAGE_MASK; + info->mmap_map[0].size = info->total_vram; + info->mmap_map[0].prot_mask = _PAGE_CACHE; + info->mmap_map[0].prot_flag = _PAGE_E; + info->mmap_map[1].voff = info->mmap_map[0].voff + info->total_vram; + info->mmap_map[1].poff = info->ati_regbase & PAGE_MASK; + info->mmap_map[1].size = PAGE_SIZE; + info->mmap_map[1].prot_mask = _PAGE_CACHE; + info->mmap_map[1].prot_flag = _PAGE_E; +#endif /* __sparc__ */ + +#ifdef CONFIG_PMAC_PBOOK + if (first_display == NULL) + pmu_register_sleep_notifier(&aty_sleep_notifier); + info->next = first_display; + first_display = info; +#endif + +#ifdef CONFIG_FB_COMPAT_XPMAC + if (!console_fb_info) + console_fb_info = &info->fb_info; +#endif /* CONFIG_FB_COMPAT_XPMAC */ + } + } + +#elif defined(CONFIG_ATARI) + u32 clock_r; + int m64_num; + struct fb_info_aty *info; + + for (m64_num = 0; m64_num < mach64_count; m64_num++) { + if (!phys_vmembase[m64_num] || !phys_size[m64_num] || + !phys_guiregbase[m64_num]) { + printk(" phys_*[%d] parameters not set => returning early. \n", + m64_num); + continue; + } + + info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC); + if (!info) { + printk("atyfb_init: can't alloc fb_info_aty\n"); + return -ENOMEM; + } + memset(info, 0, sizeof(struct fb_info_aty)); + + /* + * Map the video memory (physical address given) to somewhere in the + * kernel address space. + */ + info->frame_buffer = ioremap(phys_vmembase[m64_num], phys_size[m64_num]); + info->frame_buffer_phys = info->frame_buffer; /* Fake! */ + info->ati_regbase = ioremap(phys_guiregbase[m64_num], 0x10000)+0xFC00ul; + info->ati_regbase_phys = info->ati_regbase; /* Fake! */ + + aty_st_le32(CLOCK_CNTL, 0x12345678, info); + clock_r = aty_ld_le32(CLOCK_CNTL, info); + + switch (clock_r & 0x003F) { + case 0x12: + info->clk_wr_offset = 3; /* */ + break; + case 0x34: + info->clk_wr_offset = 2; /* Medusa ST-IO ISA Adapter etc. */ + break; + case 0x16: + info->clk_wr_offset = 1; /* */ + break; + case 0x38: + info->clk_wr_offset = 0; /* Panther 1 ISA Adapter (Gerald) */ + break; + } + + if (!aty_init(info, "ISA bus")) { + kfree(info); + /* This is insufficient! kernel_map has added two large chunks!! */ + return -ENXIO; + } + } +#endif /* CONFIG_ATARI */ + return 0; +} + +#ifndef MODULE +int __init atyfb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + for (this_opt = strtok(options, ","); this_opt; + this_opt = strtok(NULL, ",")) { + if (!strncmp(this_opt, "font:", 5)) { + char *p; + int i; + + p = this_opt + 5; + for (i = 0; i < sizeof(fontname) - 1; i++) + if (!*p || *p == ' ' || *p == ',') + break; + memcpy(fontname, this_opt + 5, i); + fontname[i] = 0; + } else if (!strncmp(this_opt, "noblink", 7)) { + curblink = 0; + } else if (!strncmp(this_opt, "noaccel", 7)) { + noaccel = 1; + } else if (!strncmp(this_opt, "vram:", 5)) + default_vram = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "pll:", 4)) + default_pll = simple_strtoul(this_opt+4, NULL, 0); + else if (!strncmp(this_opt, "mclk:", 5)) + default_mclk = simple_strtoul(this_opt+5, NULL, 0); +#ifdef CONFIG_PPC + else if (!strncmp(this_opt, "vmode:", 6)) { + unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0); + if (vmode > 0 && vmode <= VMODE_MAX) + default_vmode = vmode; + } else if (!strncmp(this_opt, "cmode:", 6)) { + unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0); + switch (cmode) { + case 0: + case 8: + default_cmode = CMODE_8; + break; + case 15: + case 16: + default_cmode = CMODE_16; + break; + case 24: + case 32: + default_cmode = CMODE_32; + break; + } + } +#endif +#ifdef CONFIG_ATARI + /* + * Why do we need this silly Mach64 argument? + * We are already here because of mach64= so its redundant. + */ + else if (MACH_IS_ATARI && (!strncmp(this_opt, "Mach64:", 7))) { + static unsigned char m64_num; + static char mach64_str[80]; + strncpy(mach64_str, this_opt+7, 80); + if (!store_video_par(mach64_str, m64_num)) { + m64_num++; + mach64_count = m64_num; + } + } +#endif + else + mode_option = this_opt; + } + return 0; +} +#endif /* !MODULE */ + +#ifdef CONFIG_ATARI +static int __init store_video_par(char *video_str, unsigned char m64_num) +{ + char *p; + unsigned long vmembase, size, guiregbase; + + printk("store_video_par() '%s' \n", video_str); + + if (!(p = strtoke(video_str, ";")) || !*p) + goto mach64_invalid; + vmembase = simple_strtoul(p, NULL, 0); + if (!(p = strtoke(NULL, ";")) || !*p) + goto mach64_invalid; + size = simple_strtoul(p, NULL, 0); + if (!(p = strtoke(NULL, ";")) || !*p) + goto mach64_invalid; + guiregbase = simple_strtoul(p, NULL, 0); + + phys_vmembase[m64_num] = vmembase; + phys_size[m64_num] = size; + phys_guiregbase[m64_num] = guiregbase; + printk(" stored them all: $%08lX $%08lX $%08lX \n", vmembase, size, + guiregbase); + return 0; + +mach64_invalid: + phys_vmembase[m64_num] = 0; + return -1; +} + +static char __init *strtoke(char *s, const char *ct) +{ + static char *ssave = NULL; + char *sbegin, *send; + + sbegin = s ? s : ssave; + if (!sbegin) + return NULL; + if (*sbegin == '\0') { + ssave = NULL; + return NULL; + } + send = strpbrk(sbegin, ct); + if (send && *send != '\0') + *send++ = '\0'; + ssave = send; + return sbegin; +} +#endif /* CONFIG_ATARI */ + +static int atyfbcon_switch(int con, struct fb_info *fb) +{ + struct fb_info_aty *info = (struct fb_info_aty *)fb; + struct atyfb_par par; + + /* Do we have to save the colormap? */ + if (fb_display[currcon].cmap.len) + fb_get_cmap(&fb_display[currcon].cmap, 1, atyfb_getcolreg, fb); + +#ifdef CONFIG_FB_ATY_CT + /* Erase HW Cursor */ + if (info->cursor) + atyfb_cursor(&fb_display[currcon], CM_ERASE, + info->cursor->pos.x, info->cursor->pos.y); +#endif /* CONFIG_FB_ATY_CT */ + + currcon = con; + + atyfb_decode_var(&fb_display[con].var, &par, info); + atyfb_set_par(&par, info); + atyfb_set_dispsw(&fb_display[con], info, par.crtc.bpp, + par.accel_flags & FB_ACCELF_TEXT); + + /* Install new colormap */ + do_install_cmap(con, fb); + +#ifdef CONFIG_FB_ATY_CT + /* Install hw cursor */ + if (info->cursor) { + aty_set_cursor_color(info); + aty_set_cursor_shape(info); + } +#endif /* CONFIG_FB_ATY_CT */ + return 1; +} + + /* + * Blank the display. + */ + +static void atyfbcon_blank(int blank, struct fb_info *fb) +{ + struct fb_info_aty *info = (struct fb_info_aty *)fb; + u8 gen_cntl; + +#ifdef CONFIG_PMAC_BACKLIGHT + if ((_machine == _MACH_Pmac) && blank) + set_backlight_enable(0); +#endif /* CONFIG_PMAC_BACKLIGHT */ + + gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info); + if (blank > 0) + switch (blank-1) { + case VESA_NO_BLANKING: + gen_cntl |= 0x40; + break; + case VESA_VSYNC_SUSPEND: + gen_cntl |= 0x8; + break; + case VESA_HSYNC_SUSPEND: + gen_cntl |= 0x4; + break; + case VESA_POWERDOWN: + gen_cntl |= 0x4c; + break; + } + else + gen_cntl &= ~(0x4c); + aty_st_8(CRTC_GEN_CNTL, gen_cntl, info); + +#ifdef CONFIG_PMAC_BACKLIGHT + if ((_machine == _MACH_Pmac) && !blank) + set_backlight_enable(1); +#endif /* CONFIG_PMAC_BACKLIGHT */ +} + + + /* + * Read a single color register and split it into + * colors/transparent. Return != 0 for invalid regno. + */ + +static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp, struct fb_info *fb) +{ + struct fb_info_aty *info = (struct fb_info_aty *)fb; + + if (regno > 255) + return 1; + *red = (info->palette[regno].red<<8) | info->palette[regno].red; + *green = (info->palette[regno].green<<8) | info->palette[regno].green; + *blue = (info->palette[regno].blue<<8) | info->palette[regno].blue; + *transp = 0; + return 0; +} + + + /* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *fb) +{ + struct fb_info_aty *info = (struct fb_info_aty *)fb; + int i, scale; + + if (regno > 255) + return 1; + red >>= 8; + green >>= 8; + blue >>= 8; + info->palette[regno].red = red; + info->palette[regno].green = green; + info->palette[regno].blue = blue; + i = aty_ld_8(DAC_CNTL, info) & 0xfc; + if (M64_HAS(EXTRA_BRIGHT)) + i |= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt*/ + aty_st_8(DAC_CNTL, i, info); + aty_st_8(DAC_MASK, 0xff, info); + scale = (M64_HAS(INTEGRATED) && info->current_par.crtc.bpp == 16) ? 3 : 0; + writeb(regno << scale, &info->aty_cmap_regs->windex); + writeb(red, &info->aty_cmap_regs->lut); + writeb(green, &info->aty_cmap_regs->lut); + writeb(blue, &info->aty_cmap_regs->lut); + if (regno < 16) + switch (info->current_par.crtc.bpp) { +#ifdef FBCON_HAS_CFB16 + case 16: + info->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | + regno; + break; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: + info->fbcon_cmap.cfb24[regno] = (regno << 16) | (regno << 8) | + regno; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + i = (regno << 8) | regno; + info->fbcon_cmap.cfb32[regno] = (i << 16) | i; + break; +#endif + } + return 0; +} + + +static void do_install_cmap(int con, struct fb_info *info) +{ + if (con != currcon) + return; + if (fb_display[con].cmap.len) + fb_set_cmap(&fb_display[con].cmap, 1, atyfb_setcolreg, info); + else { + int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; + fb_set_cmap(fb_default_cmap(size), 1, atyfb_setcolreg, info); + } +} + + + /* + * Update the `var' structure (called by fbcon.c) + */ + +static int atyfbcon_updatevar(int con, struct fb_info *fb) +{ + struct fb_info_aty *info = (struct fb_info_aty *)fb; + struct atyfb_par *par = &info->current_par; + struct display *p = &fb_display[con]; + struct vc_data *conp = p->conp; + u32 yres, yoffset, sy, height; + + yres = ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1; + yoffset = fb_display[con].var.yoffset; + + sy = (conp->vc_rows + p->yscroll) * fontheight(p); + height = yres - conp->vc_rows * fontheight(p); + + if (height && (yoffset + yres > sy)) { + u32 xres, xoffset; + u32 bgx; + + xres = (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8; + xoffset = fb_display[con].var.xoffset; + + + bgx = attr_bgcol_ec(p, conp); + bgx |= (bgx << 8); + bgx |= (bgx << 16); + + if (sy + height > par->crtc.vyres) { + wait_for_fifo(1, info); + aty_st_le32(SC_BOTTOM, sy + height - 1, info); + } + aty_rectfill(xoffset, sy, xres, height, bgx, info); + } + +#ifdef CONFIG_FB_ATY_CT + if (info->cursor && (yoffset + yres <= sy)) + atyfb_cursor(p, CM_ERASE, info->cursor->pos.x, info->cursor->pos.y); +#endif /* CONFIG_FB_ATY_CT */ + + info->current_par.crtc.yoffset = yoffset; + set_off_pitch(&info->current_par, info); + return 0; +} + + + +#ifdef MODULE +int __init init_module(void) +{ + atyfb_init(); + return fb_list ? 0 : -ENXIO; +} + +void cleanup_module(void) +{ + while (fb_list) { + struct fb_info_aty *info = fb_list; + fb_list = info->next; + + unregister_framebuffer(&info->fb_info); + +#ifndef __sparc__ + if (info->ati_regbase) + iounmap((void *)info->ati_regbase); + if (info->frame_buffer) + iounmap((void *)info->frame_buffer); +#ifdef __BIG_ENDIAN + if (info->cursor && info->cursor->ram) + iounmap(info->cursor->ram); +#endif +#endif + + if (info->cursor) { + if (info->cursor->timer) + kfree(info->cursor->timer); + kfree(info->cursor); + } +#ifdef __sparc__ + if (info->mmap_map) + kfree(info->mmap_map); +#endif + kfree(info); + } +} + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/aty/mach64.h linux.ac/drivers/video/aty/mach64.h --- linux.vanilla/drivers/video/aty/mach64.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/aty/mach64.h Tue Apr 3 17:55:08 2001 @@ -0,0 +1,1011 @@ +/* + * ATI Mach64 Register Definitions + * + * Copyright (C) 1997 Michael AK Tesch + * written with much help from Jon Howell + * + * Updated for 3D RAGE PRO by Geert Uytterhoeven + * + * 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. + */ + +/* + * most of the rest of this file comes from ATI sample code + */ +#ifndef REGMACH64_H +#define REGMACH64_H + +/* NON-GUI MEMORY MAPPED Registers - expressed in BYTE offsets */ + +#define CRTC_H_TOTAL_DISP 0x0000 /* Dword offset 0_00 */ +#define CRTC_H_SYNC_STRT_WID 0x0004 /* Dword offset 0_01 */ +#define CRTC_H_SYNC_STRT 0x0004 +#define CRTC_H_SYNC_DLY 0x0005 +#define CRTC_H_SYNC_WID 0x0006 + +#define CRTC_V_TOTAL_DISP 0x0008 /* Dword offset 0_02 */ +#define CRTC_V_TOTAL 0x0008 +#define CRTC_V_DISP 0x000A +#define CRTC_V_SYNC_STRT_WID 0x000C /* Dword offset 0_03 */ +#define CRTC_V_SYNC_STRT 0x000C +#define CRTC_V_SYNC_WID 0x000E + +#define CRTC_VLINE_CRNT_VLINE 0x0010 /* Dword offset 0_04 */ +#define CRTC_OFF_PITCH 0x0014 /* Dword offset 0_05 */ +#define CRTC_OFFSET 0x0014 +#define CRTC_PITCH 0x0016 + +#define CRTC_INT_CNTL 0x0018 /* Dword offset 0_06 */ +#define CRTC_GEN_CNTL 0x001C /* Dword offset 0_07 */ +#define CRTC_PIX_WIDTH 0x001D +#define CRTC_FIFO 0x001E +#define CRTC_EXT_DISP 0x001F + +#define DSP_CONFIG 0x0020 /* Dword offset 0_08 */ +#define DSP_ON_OFF 0x0024 /* Dword offset 0_09 */ +#define TIMER_CONFIG 0x0028 /* Dword offset 0_0A */ +#define MEM_BUF_CNTL 0x002C /* Dword offset 0_0B */ +#define MEM_ADDR_CONFIG 0x0034 /* Dword offset 0_0D */ + +#define CRT_TRAP 0x0038 /* Dword offset 0_0E */ + +#define I2C_CNTL_0 0x003C /* Dword offset 0_0F */ + +#define OVR_CLR 0x0040 /* Dword offset 0_10 */ +#define OVR_WID_LEFT_RIGHT 0x0044 /* Dword offset 0_11 */ +#define OVR_WID_TOP_BOTTOM 0x0048 /* Dword offset 0_12 */ + +#define VGA_DSP_CONFIG 0x004C /* Dword offset 0_13 */ +#define VGA_DSP_ON_OFF 0x0050 /* Dword offset 0_14 */ + +#define CUR_CLR0 0x0060 /* Dword offset 0_18 */ +#define CUR_CLR1 0x0064 /* Dword offset 0_19 */ +#define CUR_OFFSET 0x0068 /* Dword offset 0_1A */ +#define CUR_HORZ_VERT_POSN 0x006C /* Dword offset 0_1B */ +#define CUR_HORZ_VERT_OFF 0x0070 /* Dword offset 0_1C */ + +#define CONFIG_PANEL_LG 0x0074 /* Dword offset 0_1D */ + +#define GP_IO 0x0078 /* Dword offset 0_1E */ + +#define HW_DEBUG 0x007C /* Dword offset 0_1F */ + +#define SCRATCH_REG0 0x0080 /* Dword offset 0_20 */ +#define SCRATCH_REG1 0x0084 /* Dword offset 0_21 */ + +#define CLOCK_CNTL 0x0090 /* Dword offset 0_24 */ +#define CLOCK_SEL_CNTL 0x0090 /* Dword offset 0_24 */ + +#define CONFIG_STAT1 0x0094 /* Dword offset 0_25 */ +#define CONFIG_STAT2 0x0098 /* Dword offset 0_26 */ + +#define BUS_CNTL 0x00A0 /* Dword offset 0_28 */ + +#define LCD_INDEX 0x00A4 /* Dword offset 0_29 */ +#define LCD_DATA 0x00A8 /* Dword offset 0_2A */ + +#define EXT_MEM_CNTL 0x00AC /* Dword offset 0_2B */ +#define MEM_CNTL 0x00B0 /* Dword offset 0_2C */ + +#define MEM_VGA_WP_SEL 0x00B4 /* Dword offset 0_2D */ +#define MEM_VGA_RP_SEL 0x00B8 /* Dword offset 0_2E */ + +#define I2C_CNTL_1 0x00BC /* Dword offset 0_2F */ + +#define DAC_REGS 0x00C0 /* Dword offset 0_30 */ +#define DAC_W_INDEX 0x00C0 /* Dword offset 0_30 */ +#define DAC_DATA 0x00C1 /* Dword offset 0_30 */ +#define DAC_MASK 0x00C2 /* Dword offset 0_30 */ +#define DAC_R_INDEX 0x00C3 /* Dword offset 0_30 */ +#define DAC_CNTL 0x00C4 /* Dword offset 0_31 */ + +#define EXT_DAC_REGS 0x00C8 /* Dword offset 0_32 */ + +#define GEN_TEST_CNTL 0x00D0 /* Dword offset 0_34 */ + +#define CUSTOM_MACRO_CNTL 0x00D4 /* Dword offset 0_35 */ +#define LCD_GEN_CNTL_LG 0x00D4 /* Dword offset 0_35 */ + +#define POWER_MANAGEMENT_LG 0x00D8 /* Dword offset 0_36 (LG) */ + +#define CONFIG_CNTL 0x00DC /* Dword offset 0_37 (CT, ET, VT) */ +#define CONFIG_CHIP_ID 0x00E0 /* Dword offset 0_38 */ +#define CONFIG_STAT0 0x00E4 /* Dword offset 0_39 */ +#define CRC_SIG 0x00E8 /* Dword offset 0_3A */ + + +/* GUI MEMORY MAPPED Registers */ + +#define DST_OFF_PITCH 0x0100 /* Dword offset 0_40 */ +#define DST_X 0x0104 /* Dword offset 0_41 */ +#define DST_Y 0x0108 /* Dword offset 0_42 */ +#define DST_Y_X 0x010C /* Dword offset 0_43 */ +#define DST_WIDTH 0x0110 /* Dword offset 0_44 */ +#define DST_HEIGHT 0x0114 /* Dword offset 0_45 */ +#define DST_HEIGHT_WIDTH 0x0118 /* Dword offset 0_46 */ +#define DST_X_WIDTH 0x011C /* Dword offset 0_47 */ +#define DST_BRES_LNTH 0x0120 /* Dword offset 0_48 */ +#define DST_BRES_ERR 0x0124 /* Dword offset 0_49 */ +#define DST_BRES_INC 0x0128 /* Dword offset 0_4A */ +#define DST_BRES_DEC 0x012C /* Dword offset 0_4B */ +#define DST_CNTL 0x0130 /* Dword offset 0_4C */ +#define DST_Y_X__ALIAS__ 0x0134 /* Dword offset 0_4D */ +#define TRAIL_BRES_ERR 0x0138 /* Dword offset 0_4E */ +#define TRAIL_BRES_INC 0x013C /* Dword offset 0_4F */ +#define TRAIL_BRES_DEC 0x0140 /* Dword offset 0_50 */ +#define LEAD_BRES_LNTH 0x0144 /* Dword offset 0_51 */ +#define Z_OFF_PITCH 0x0148 /* Dword offset 0_52 */ +#define Z_CNTL 0x014C /* Dword offset 0_53 */ +#define ALPHA_TST_CNTL 0x0150 /* Dword offset 0_54 */ +#define SECONDARY_STW_EXP 0x0158 /* Dword offset 0_56 */ +#define SECONDARY_S_X_INC 0x015C /* Dword offset 0_57 */ +#define SECONDARY_S_Y_INC 0x0160 /* Dword offset 0_58 */ +#define SECONDARY_S_START 0x0164 /* Dword offset 0_59 */ +#define SECONDARY_W_X_INC 0x0168 /* Dword offset 0_5A */ +#define SECONDARY_W_Y_INC 0x016C /* Dword offset 0_5B */ +#define SECONDARY_W_START 0x0170 /* Dword offset 0_5C */ +#define SECONDARY_T_X_INC 0x0174 /* Dword offset 0_5D */ +#define SECONDARY_T_Y_INC 0x0178 /* Dword offset 0_5E */ +#define SECONDARY_T_START 0x017C /* Dword offset 0_5F */ + +#define SRC_OFF_PITCH 0x0180 /* Dword offset 0_60 */ +#define SRC_X 0x0184 /* Dword offset 0_61 */ +#define SRC_Y 0x0188 /* Dword offset 0_62 */ +#define SRC_Y_X 0x018C /* Dword offset 0_63 */ +#define SRC_WIDTH1 0x0190 /* Dword offset 0_64 */ +#define SRC_HEIGHT1 0x0194 /* Dword offset 0_65 */ +#define SRC_HEIGHT1_WIDTH1 0x0198 /* Dword offset 0_66 */ +#define SRC_X_START 0x019C /* Dword offset 0_67 */ +#define SRC_Y_START 0x01A0 /* Dword offset 0_68 */ +#define SRC_Y_X_START 0x01A4 /* Dword offset 0_69 */ +#define SRC_WIDTH2 0x01A8 /* Dword offset 0_6A */ +#define SRC_HEIGHT2 0x01AC /* Dword offset 0_6B */ +#define SRC_HEIGHT2_WIDTH2 0x01B0 /* Dword offset 0_6C */ +#define SRC_CNTL 0x01B4 /* Dword offset 0_6D */ + +#define SCALE_OFF 0x01C0 /* Dword offset 0_70 */ +#define SECONDARY_SCALE_OFF 0x01C4 /* Dword offset 0_71 */ + +#define TEX_0_OFF 0x01C0 /* Dword offset 0_70 */ +#define TEX_1_OFF 0x01C4 /* Dword offset 0_71 */ +#define TEX_2_OFF 0x01C8 /* Dword offset 0_72 */ +#define TEX_3_OFF 0x01CC /* Dword offset 0_73 */ +#define TEX_4_OFF 0x01D0 /* Dword offset 0_74 */ +#define TEX_5_OFF 0x01D4 /* Dword offset 0_75 */ +#define TEX_6_OFF 0x01D8 /* Dword offset 0_76 */ +#define TEX_7_OFF 0x01DC /* Dword offset 0_77 */ + +#define SCALE_WIDTH 0x01DC /* Dword offset 0_77 */ +#define SCALE_HEIGHT 0x01E0 /* Dword offset 0_78 */ + +#define TEX_8_OFF 0x01E0 /* Dword offset 0_78 */ +#define TEX_9_OFF 0x01E4 /* Dword offset 0_79 */ +#define TEX_10_OFF 0x01E8 /* Dword offset 0_7A */ +#define S_Y_INC 0x01EC /* Dword offset 0_7B */ + +#define SCALE_PITCH 0x01EC /* Dword offset 0_7B */ +#define SCALE_X_INC 0x01F0 /* Dword offset 0_7C */ + +#define RED_X_INC 0x01F0 /* Dword offset 0_7C */ +#define GREEN_X_INC 0x01F4 /* Dword offset 0_7D */ + +#define SCALE_Y_INC 0x01F4 /* Dword offset 0_7D */ +#define SCALE_VACC 0x01F8 /* Dword offset 0_7E */ +#define SCALE_3D_CNTL 0x01FC /* Dword offset 0_7F */ + +#define HOST_DATA0 0x0200 /* Dword offset 0_80 */ +#define HOST_DATA1 0x0204 /* Dword offset 0_81 */ +#define HOST_DATA2 0x0208 /* Dword offset 0_82 */ +#define HOST_DATA3 0x020C /* Dword offset 0_83 */ +#define HOST_DATA4 0x0210 /* Dword offset 0_84 */ +#define HOST_DATA5 0x0214 /* Dword offset 0_85 */ +#define HOST_DATA6 0x0218 /* Dword offset 0_86 */ +#define HOST_DATA7 0x021C /* Dword offset 0_87 */ +#define HOST_DATA8 0x0220 /* Dword offset 0_88 */ +#define HOST_DATA9 0x0224 /* Dword offset 0_89 */ +#define HOST_DATAA 0x0228 /* Dword offset 0_8A */ +#define HOST_DATAB 0x022C /* Dword offset 0_8B */ +#define HOST_DATAC 0x0230 /* Dword offset 0_8C */ +#define HOST_DATAD 0x0234 /* Dword offset 0_8D */ +#define HOST_DATAE 0x0238 /* Dword offset 0_8E */ +#define HOST_DATAF 0x023C /* Dword offset 0_8F */ +#define HOST_CNTL 0x0240 /* Dword offset 0_90 */ + +#define BM_HOSTDATA 0x0244 /* Dword offset 0_91 */ +#define BM_ADDR 0x0248 /* Dword offset 0_92 */ +#define BM_DATA 0x0248 /* Dword offset 0_92 */ +#define BM_GUI_TABLE_CMD 0x024C /* Dword offset 0_93 */ + +#define PAT_REG0 0x0280 /* Dword offset 0_A0 */ +#define PAT_REG1 0x0284 /* Dword offset 0_A1 */ +#define PAT_CNTL 0x0288 /* Dword offset 0_A2 */ + +#define SC_LEFT 0x02A0 /* Dword offset 0_A8 */ +#define SC_RIGHT 0x02A4 /* Dword offset 0_A9 */ +#define SC_LEFT_RIGHT 0x02A8 /* Dword offset 0_AA */ +#define SC_TOP 0x02AC /* Dword offset 0_AB */ +#define SC_BOTTOM 0x02B0 /* Dword offset 0_AC */ +#define SC_TOP_BOTTOM 0x02B4 /* Dword offset 0_AD */ + +#define DP_BKGD_CLR 0x02C0 /* Dword offset 0_B0 */ +#define DP_FOG_CLR 0x02C4 /* Dword offset 0_B1 */ +#define DP_FRGD_CLR 0x02C4 /* Dword offset 0_B1 */ +#define DP_WRITE_MASK 0x02C8 /* Dword offset 0_B2 */ +#define DP_CHAIN_MASK 0x02CC /* Dword offset 0_B3 */ +#define DP_PIX_WIDTH 0x02D0 /* Dword offset 0_B4 */ +#define DP_MIX 0x02D4 /* Dword offset 0_B5 */ +#define DP_SRC 0x02D8 /* Dword offset 0_B6 */ +#define DP_FRGD_CLR_MIX 0x02DC /* Dword offset 0_B7 */ +#define DP_FRGD_BLGD_CLR 0x02E0 /* Dword offset 0_B8 */ + +#define DST_X_Y 0x02E8 /* Dword offset 0_BA */ +#define DST_WIDTH_HEIGHT 0x02EC /* Dword offset 0_BB */ +#define USR_DST_PICTH 0x02F0 /* Dword offset 0_BC */ +#define DP_SET_GUI_ENGINE2 0x02F8 /* Dword offset 0_BE */ +#define DP_SET_GUI_ENGINE 0x02FC /* Dword offset 0_BF */ + +#define CLR_CMP_CLR 0x0300 /* Dword offset 0_C0 */ +#define CLR_CMP_MASK 0x0304 /* Dword offset 0_C1 */ +#define CLR_CMP_CNTL 0x0308 /* Dword offset 0_C2 */ + +#define FIFO_STAT 0x0310 /* Dword offset 0_C4 */ + +#define CONTEXT_MASK 0x0320 /* Dword offset 0_C8 */ +#define CONTEXT_LOAD_CNTL 0x032C /* Dword offset 0_CB */ + +#define GUI_TRAJ_CNTL 0x0330 /* Dword offset 0_CC */ +#define GUI_STAT 0x0338 /* Dword offset 0_CE */ + +#define TEX_PALETTE_INDEX 0x0340 /* Dword offset 0_D0 */ +#define STW_EXP 0x0344 /* Dword offset 0_D1 */ +#define LOG_MAX_INC 0x0348 /* Dword offset 0_D2 */ +#define S_X_INC 0x034C /* Dword offset 0_D3 */ +#define S_Y_INC__ALIAS__ 0x0350 /* Dword offset 0_D4 */ + +#define SCALE_PITCH__ALIAS__ 0x0350 /* Dword offset 0_D4 */ + +#define S_START 0x0354 /* Dword offset 0_D5 */ +#define W_X_INC 0x0358 /* Dword offset 0_D6 */ +#define W_Y_INC 0x035C /* Dword offset 0_D7 */ +#define W_START 0x0360 /* Dword offset 0_D8 */ +#define T_X_INC 0x0364 /* Dword offset 0_D9 */ +#define T_Y_INC 0x0368 /* Dword offset 0_DA */ + +#define SECONDARY_SCALE_PITCH 0x0368 /* Dword offset 0_DA */ + +#define T_START 0x036C /* Dword offset 0_DB */ +#define TEX_SIZE_PITCH 0x0370 /* Dword offset 0_DC */ +#define TEX_CNTL 0x0374 /* Dword offset 0_DD */ +#define SECONDARY_TEX_OFFSET 0x0378 /* Dword offset 0_DE */ +#define TEX_PALETTE 0x037C /* Dword offset 0_DF */ + +#define SCALE_PITCH_BOTH 0x0380 /* Dword offset 0_E0 */ +#define SECONDARY_SCALE_OFF_ACC 0x0384 /* Dword offset 0_E1 */ +#define SCALE_OFF_ACC 0x0388 /* Dword offset 0_E2 */ +#define SCALE_DST_Y_X 0x038C /* Dword offset 0_E3 */ + +#define COMPOSITE_SHADOW_ID 0x0398 /* Dword offset 0_E6 */ + +#define SECONDARY_SCALE_X_INC 0x039C /* Dword offset 0_E7 */ + +#define SPECULAR_RED_X_INC 0x039C /* Dword offset 0_E7 */ +#define SPECULAR_RED_Y_INC 0x03A0 /* Dword offset 0_E8 */ +#define SPECULAR_RED_START 0x03A4 /* Dword offset 0_E9 */ + +#define SECONDARY_SCALE_HACC 0x03A4 /* Dword offset 0_E9 */ + +#define SPECULAR_GREEN_X_INC 0x03A8 /* Dword offset 0_EA */ +#define SPECULAR_GREEN_Y_INC 0x03AC /* Dword offset 0_EB */ +#define SPECULAR_GREEN_START 0x03B0 /* Dword offset 0_EC */ +#define SPECULAR_BLUE_X_INC 0x03B4 /* Dword offset 0_ED */ +#define SPECULAR_BLUE_Y_INC 0x03B8 /* Dword offset 0_EE */ +#define SPECULAR_BLUE_START 0x03BC /* Dword offset 0_EF */ + +#define SCALE_X_INC__ALIAS__ 0x03C0 /* Dword offset 0_F0 */ + +#define RED_X_INC__ALIAS__ 0x03C0 /* Dword offset 0_F0 */ +#define RED_Y_INC 0x03C4 /* Dword offset 0_F1 */ +#define RED_START 0x03C8 /* Dword offset 0_F2 */ + +#define SCALE_HACC 0x03C8 /* Dword offset 0_F2 */ +#define SCALE_Y_INC__ALIAS__ 0x03CC /* Dword offset 0_F3 */ + +#define GREEN_X_INC__ALIAS__ 0x03CC /* Dword offset 0_F3 */ +#define GREEN_Y_INC 0x03D0 /* Dword offset 0_F4 */ + +#define SECONDARY_SCALE_Y_INC 0x03D0 /* Dword offset 0_F4 */ +#define SECONDARY_SCALE_VACC 0x03D4 /* Dword offset 0_F5 */ + +#define GREEN_START 0x03D4 /* Dword offset 0_F5 */ +#define BLUE_X_INC 0x03D8 /* Dword offset 0_F6 */ +#define BLUE_Y_INC 0x03DC /* Dword offset 0_F7 */ +#define BLUE_START 0x03E0 /* Dword offset 0_F8 */ +#define Z_X_INC 0x03E4 /* Dword offset 0_F9 */ +#define Z_Y_INC 0x03E8 /* Dword offset 0_FA */ +#define Z_START 0x03EC /* Dword offset 0_FB */ +#define ALPHA_X_INC 0x03F0 /* Dword offset 0_FC */ +#define FOG_X_INC 0x03F0 /* Dword offset 0_FC */ +#define ALPHA_Y_INC 0x03F4 /* Dword offset 0_FD */ +#define FOG_Y_INC 0x03F4 /* Dword offset 0_FD */ +#define ALPHA_START 0x03F8 /* Dword offset 0_FE */ +#define FOG_START 0x03F8 /* Dword offset 0_FE */ + +#define OVERLAY_Y_X_START 0x0400 /* Dword offset 1_00 */ +#define OVERLAY_Y_X_END 0x0404 /* Dword offset 1_01 */ +#define OVERLAY_VIDEO_KEY_CLR 0x0408 /* Dword offset 1_02 */ +#define OVERLAY_VIDEO_KEY_MSK 0x040C /* Dword offset 1_03 */ +#define OVERLAY_GRAPHICS_KEY_CLR 0x0410 /* Dword offset 1_04 */ +#define OVERLAY_GRAPHICS_KEY_MSK 0x0414 /* Dword offset 1_05 */ +#define OVERLAY_KEY_CNTL 0x0418 /* Dword offset 1_06 */ + +#define OVERLAY_SCALE_INC 0x0420 /* Dword offset 1_08 */ +#define OVERLAY_SCALE_CNTL 0x0424 /* Dword offset 1_09 */ +#define SCALER_HEIGHT_WIDTH 0x0428 /* Dword offset 1_0A */ +#define SCALER_TEST 0x042C /* Dword offset 1_0B */ +#define SCALER_BUF0_OFFSET 0x0434 /* Dword offset 1_0D */ +#define SCALER_BUF1_OFFSET 0x0438 /* Dword offset 1_0E */ +#define SCALE_BUF_PITCH 0x043C /* Dword offset 1_0F */ + +#define CAPTURE_START_END 0x0440 /* Dword offset 1_10 */ +#define CAPTURE_X_WIDTH 0x0444 /* Dword offset 1_11 */ +#define VIDEO_FORMAT 0x0448 /* Dword offset 1_12 */ +#define VBI_START_END 0x044C /* Dword offset 1_13 */ +#define CAPTURE_CONFIG 0x0450 /* Dword offset 1_14 */ +#define TRIG_CNTL 0x0454 /* Dword offset 1_15 */ + +#define OVERLAY_EXCLUSIVE_HORZ 0x0458 /* Dword offset 1_16 */ +#define OVERLAY_EXCLUSIVE_VERT 0x045C /* Dword offset 1_17 */ + +#define VAL_WIDTH 0x0460 /* Dword offset 1_18 */ +#define CAPTURE_DEBUG 0x0464 /* Dword offset 1_19 */ +#define VIDEO_SYNC_TEST 0x0468 /* Dword offset 1_1A */ + +#define SNAPSHOT_VH_COUNTS 0x0470 /* Dword offset 1_1C */ +#define SNAPSHOT_F_COUNT 0x0474 /* Dword offset 1_1D */ +#define N_VIF_COUNT 0x0478 /* Dword offset 1_1E */ +#define SNAPSHOT_VIF_COUNT 0x047C /* Dword offset 1_1F */ + +#define CAPTURE_BUF0_OFFSET 0x0480 /* Dword offset 1_20 */ +#define CAPTURE_BUF1_OFFSET 0x0484 /* Dword offset 1_21 */ +#define CAPTURE_BUF_PITCH 0x0488 /* Dword offset 1_22 */ + +#define MPP_CONFIG 0x04C0 /* Dword offset 1_30 */ +#define MPP_STROBE_SEQ 0x04C4 /* Dword offset 1_31 */ +#define MPP_ADDR 0x04C8 /* Dword offset 1_32 */ +#define MPP_DATA 0x04CC /* Dword offset 1_33 */ +#define TVO_CNTL 0x0500 /* Dword offset 1_40 */ + +#define CRT_HORZ_VERT_LOAD 0x0544 /* Dword offset 1_51 */ + +#define AGP_BASE 0x0548 /* Dword offset 1_52 */ +#define AGP_CNTL 0x054C /* Dword offset 1_53 */ + +#define SCALER_COLOUR_CNTL 0x0550 /* Dword offset 1_54 */ +#define SCALER_H_COEFF0 0x0554 /* Dword offset 1_55 */ +#define SCALER_H_COEFF1 0x0558 /* Dword offset 1_56 */ +#define SCALER_H_COEFF2 0x055C /* Dword offset 1_57 */ +#define SCALER_H_COEFF3 0x0560 /* Dword offset 1_58 */ +#define SCALER_H_COEFF4 0x0564 /* Dword offset 1_59 */ + +#define GUI_CNTL 0x0578 /* Dword offset 1_5E */ + +#define BM_FRAME_BUF_OFFSET 0x0580 /* Dword offset 1_60 */ +#define BM_SYSTEM_MEM_ADDR 0x0584 /* Dword offset 1_61 */ +#define BM_COMMAND 0x0588 /* Dword offset 1_62 */ +#define BM_STATUS 0x058C /* Dword offset 1_63 */ +#define BM_GUI_TABLE 0x05B8 /* Dword offset 1_6E */ +#define BM_SYSTEM_TABLE 0x05BC /* Dword offset 1_6F */ + +#define SCALER_BUF0_OFFSET_U 0x05D4 /* Dword offset 1_75 */ +#define SCALER_BUF0_OFFSET_V 0x05D8 /* Dword offset 1_76 */ +#define SCALER_BUF1_OFFSET_U 0x05DC /* Dword offset 1_77 */ +#define SCALER_BUF1_OFFSET_V 0x05E0 /* Dword offset 1_78 */ + +#define VERTEX_1_S 0x0640 /* Dword offset 1_90 */ +#define VERTEX_1_T 0x0644 /* Dword offset 1_91 */ +#define VERTEX_1_W 0x0648 /* Dword offset 1_92 */ +#define VERTEX_1_SPEC_ARGB 0x064C /* Dword offset 1_93 */ +#define VERTEX_1_Z 0x0650 /* Dword offset 1_94 */ +#define VERTEX_1_ARGB 0x0654 /* Dword offset 1_95 */ +#define VERTEX_1_X_Y 0x0658 /* Dword offset 1_96 */ +#define ONE_OVER_AREA 0x065C /* Dword offset 1_97 */ +#define VERTEX_2_S 0x0660 /* Dword offset 1_98 */ +#define VERTEX_2_T 0x0664 /* Dword offset 1_99 */ +#define VERTEX_2_W 0x0668 /* Dword offset 1_9A */ +#define VERTEX_2_SPEC_ARGB 0x066C /* Dword offset 1_9B */ +#define VERTEX_2_Z 0x0670 /* Dword offset 1_9C */ +#define VERTEX_2_ARGB 0x0674 /* Dword offset 1_9D */ +#define VERTEX_2_X_Y 0x0678 /* Dword offset 1_9E */ +#define ONE_OVER_AREA 0x065C /* Dword offset 1_9F */ +#define VERTEX_3_S 0x0680 /* Dword offset 1_A0 */ +#define VERTEX_3_T 0x0684 /* Dword offset 1_A1 */ +#define VERTEX_3_W 0x0688 /* Dword offset 1_A2 */ +#define VERTEX_3_SPEC_ARGB 0x068C /* Dword offset 1_A3 */ +#define VERTEX_3_Z 0x0690 /* Dword offset 1_A4 */ +#define VERTEX_3_ARGB 0x0694 /* Dword offset 1_A5 */ +#define VERTEX_3_X_Y 0x0698 /* Dword offset 1_A6 */ +#define ONE_OVER_AREA 0x065C /* Dword offset 1_A7 */ +#define VERTEX_1_S 0x0640 /* Dword offset 1_AB */ +#define VERTEX_1_T 0x0644 /* Dword offset 1_AC */ +#define VERTEX_1_W 0x0648 /* Dword offset 1_AD */ +#define VERTEX_2_S 0x0660 /* Dword offset 1_AE */ +#define VERTEX_2_T 0x0664 /* Dword offset 1_AF */ +#define VERTEX_2_W 0x0668 /* Dword offset 1_B0 */ +#define VERTEX_3_SECONDARY_S 0x06C0 /* Dword offset 1_B0 */ +#define VERTEX_3_S 0x0680 /* Dword offset 1_B1 */ +#define VERTEX_3_SECONDARY_T 0x06C4 /* Dword offset 1_B1 */ +#define VERTEX_3_T 0x0684 /* Dword offset 1_B2 */ +#define VERTEX_3_SECONDARY_W 0x06C8 /* Dword offset 1_B2 */ +#define VERTEX_3_W 0x0688 /* Dword offset 1_B3 */ +#define VERTEX_1_SPEC_ARGB 0x064C /* Dword offset 1_B4 */ +#define VERTEX_2_SPEC_ARGB 0x066C /* Dword offset 1_B5 */ +#define VERTEX_3_SPEC_ARGB 0x068C /* Dword offset 1_B6 */ +#define VERTEX_1_Z 0x0650 /* Dword offset 1_B7 */ +#define VERTEX_2_Z 0x0670 /* Dword offset 1_B8 */ +#define VERTEX_3_Z 0x0690 /* Dword offset 1_B9 */ +#define VERTEX_1_ARGB 0x0654 /* Dword offset 1_BA */ +#define VERTEX_2_ARGB 0x0674 /* Dword offset 1_BB */ +#define VERTEX_3_ARGB 0x0694 /* Dword offset 1_BC */ +#define VERTEX_1_X_Y 0x0658 /* Dword offset 1_BD */ +#define VERTEX_2_X_Y 0x0678 /* Dword offset 1_BE */ +#define VERTEX_3_X_Y 0x0698 /* Dword offset 1_BF */ +#define ONE_OVER_AREA_UC 0x0700 /* Dword offset 1_C0 */ +#define SETUP_CNTL 0x0704 /* Dword offset 1_C1 */ +#define VERTEX_1_SECONDARY_S 0x0728 /* Dword offset 1_CA */ +#define VERTEX_1_SECONDARY_T 0x072C /* Dword offset 1_CB */ +#define VERTEX_1_SECONDARY_W 0x0730 /* Dword offset 1_CC */ +#define VERTEX_2_SECONDARY_S 0x0734 /* Dword offset 1_CD */ +#define VERTEX_2_SECONDARY_T 0x0738 /* Dword offset 1_CE */ +#define VERTEX_2_SECONDARY_W 0x073C /* Dword offset 1_CF */ + +#define GTC_3D_RESET_DELAY 3 /* 3D engine reset delay in ms */ + +/* CRTC control values (mostly CRTC_GEN_CNTL) */ + +#define CRTC_H_SYNC_NEG 0x00200000 +#define CRTC_V_SYNC_NEG 0x00200000 + +#define CRTC_DBL_SCAN_EN 0x00000001 +#define CRTC_INTERLACE_EN 0x00000002 +#define CRTC_HSYNC_DIS 0x00000004 +#define CRTC_VSYNC_DIS 0x00000008 +#define CRTC_CSYNC_EN 0x00000010 +#define CRTC_PIX_BY_2_EN 0x00000020 /* unused on RAGE */ +#define CRTC_DISPLAY_DIS 0x00000040 +#define CRTC_VGA_XOVERSCAN 0x00000040 + +#define CRTC_PIX_WIDTH_MASK 0x00000700 +#define CRTC_PIX_WIDTH_4BPP 0x00000100 +#define CRTC_PIX_WIDTH_8BPP 0x00000200 +#define CRTC_PIX_WIDTH_15BPP 0x00000300 +#define CRTC_PIX_WIDTH_16BPP 0x00000400 +#define CRTC_PIX_WIDTH_24BPP 0x00000500 +#define CRTC_PIX_WIDTH_32BPP 0x00000600 + +#define CRTC_BYTE_PIX_ORDER 0x00000800 +#define CRTC_PIX_ORDER_MSN_LSN 0x00000000 +#define CRTC_PIX_ORDER_LSN_MSN 0x00000800 + +#define CRTC_FIFO_LWM 0x000f0000 + +#define VGA_128KAP_PAGING 0x00100000 +#define VFC_SYNC_TRISTATE 0x00200000 +#define CRTC_LOCK_REGS 0x00400000 +#define CRTC_SYNC_TRISTATE 0x00800000 + +#define CRTC_EXT_DISP_EN 0x01000000 +#define CRTC_ENABLE 0x02000000 +#define CRTC_DISP_REQ_ENB 0x04000000 +#define VGA_ATI_LINEAR 0x08000000 +#define CRTC_VSYNC_FALL_EDGE 0x10000000 +#define VGA_TEXT_132 0x20000000 +#define VGA_XCRT_CNT_EN 0x40000000 +#define VGA_CUR_B_TEST 0x80000000 + +#define CRTC_CRNT_VLINE 0x07f00000 +#define CRTC_VBLANK 0x00000001 + + +/* DAC control values */ + +#define DAC_EXT_SEL_RS2 0x01 +#define DAC_EXT_SEL_RS3 0x02 +#define DAC_8BIT_EN 0x00000100 +#define DAC_PIX_DLY_MASK 0x00000600 +#define DAC_PIX_DLY_0NS 0x00000000 +#define DAC_PIX_DLY_2NS 0x00000200 +#define DAC_PIX_DLY_4NS 0x00000400 +#define DAC_BLANK_ADJ_MASK 0x00001800 +#define DAC_BLANK_ADJ_0 0x00000000 +#define DAC_BLANK_ADJ_1 0x00000800 +#define DAC_BLANK_ADJ_2 0x00001000 + + +/* Mix control values */ + +#define MIX_NOT_DST 0x0000 +#define MIX_0 0x0001 +#define MIX_1 0x0002 +#define MIX_DST 0x0003 +#define MIX_NOT_SRC 0x0004 +#define MIX_XOR 0x0005 +#define MIX_XNOR 0x0006 +#define MIX_SRC 0x0007 +#define MIX_NAND 0x0008 +#define MIX_NOT_SRC_OR_DST 0x0009 +#define MIX_SRC_OR_NOT_DST 0x000a +#define MIX_OR 0x000b +#define MIX_AND 0x000c +#define MIX_SRC_AND_NOT_DST 0x000d +#define MIX_NOT_SRC_AND_DST 0x000e +#define MIX_NOR 0x000f + +/* Maximum engine dimensions */ +#define ENGINE_MIN_X 0 +#define ENGINE_MIN_Y 0 +#define ENGINE_MAX_X 4095 +#define ENGINE_MAX_Y 16383 + +/* Mach64 engine bit constants - these are typically ORed together */ + +/* BUS_CNTL register constants */ +#define BUS_FIFO_ERR_ACK 0x00200000 +#define BUS_HOST_ERR_ACK 0x00800000 + +/* GEN_TEST_CNTL register constants */ +#define GEN_OVR_OUTPUT_EN 0x20 +#define HWCURSOR_ENABLE 0x80 +#define GUI_ENGINE_ENABLE 0x100 +#define BLOCK_WRITE_ENABLE 0x200 + +/* DSP_CONFIG register constants */ +#define DSP_XCLKS_PER_QW 0x00003fff +#define DSP_LOOP_LATENCY 0x000f0000 +#define DSP_PRECISION 0x00700000 + +/* DSP_ON_OFF register constants */ +#define DSP_OFF 0x000007ff +#define DSP_ON 0x07ff0000 + +/* CLOCK_CNTL register constants */ +#define CLOCK_SEL 0x0f +#define CLOCK_DIV 0x30 +#define CLOCK_DIV1 0x00 +#define CLOCK_DIV2 0x10 +#define CLOCK_DIV4 0x20 +#define CLOCK_STROBE 0x40 +#define PLL_WR_EN 0x02 + +/* PLL registers */ +#define MPLL_CNTL 0x00 +#define VPLL_CNTL 0x01 +#define PLL_REF_DIV 0x02 +#define PLL_GEN_CNTL 0x03 +#define MCLK_FB_DIV 0x04 +#define PLL_VCLK_CNTL 0x05 +#define VCLK_POST_DIV 0x06 +#define VCLK0_FB_DIV 0x07 +#define VCLK1_FB_DIV 0x08 +#define VCLK2_FB_DIV 0x09 +#define VCLK3_FB_DIV 0x0A +#define PLL_EXT_CNTL 0x0B +#define DLL_CNTL 0x0C +#define VFC_CNTL 0x0D +#define PLL_TEST_CTRL 0x0E +#define PLL_TEST_COUNT 0x0F + +/* Fields in PLL registers */ +#define PLL_PC_GAIN 0x07 +#define PLL_VC_GAIN 0x18 +#define PLL_DUTY_CYC 0xE0 +#define PLL_OVERRIDE 0x01 +#define PLL_MCLK_RST 0x02 +#define OSC_EN 0x04 +#define EXT_CLK_EN 0x08 +#define MCLK_SRC_SEL 0x70 +#define EXT_CLK_CNTL 0x80 +#define VCLK_SRC_SEL 0x03 +#define PLL_VCLK_RST 0x04 +#define VCLK_INVERT 0x08 +#define VCLK0_POST 0x03 +#define VCLK1_POST 0x0C +#define VCLK2_POST 0x30 +#define VCLK3_POST 0xC0 + +/* CONFIG_CNTL register constants */ +#define APERTURE_4M_ENABLE 1 +#define APERTURE_8M_ENABLE 2 +#define VGA_APERTURE_ENABLE 4 + +/* CONFIG_STAT0 register constants (GX, CX) */ +#define CFG_BUS_TYPE 0x00000007 +#define CFG_MEM_TYPE 0x00000038 +#define CFG_INIT_DAC_TYPE 0x00000e00 + +/* CONFIG_STAT0 register constants (CT, ET, VT) */ +#define CFG_MEM_TYPE_xT 0x00000007 + +#define ISA 0 +#define EISA 1 +#define LOCAL_BUS 6 +#define PCI 7 + +/* Memory types for GX, CX */ +#define DRAMx4 0 +#define VRAMx16 1 +#define VRAMx16ssr 2 +#define DRAMx16 3 +#define GraphicsDRAMx16 4 +#define EnhancedVRAMx16 5 +#define EnhancedVRAMx16ssr 6 + +/* Memory types for CT, ET, VT, GT */ +#define DRAM 1 +#define EDO 2 +#define PSEUDO_EDO 3 +#define SDRAM 4 +#define SGRAM 5 +#define WRAM 6 + +#define DAC_INTERNAL 0x00 +#define DAC_IBMRGB514 0x01 +#define DAC_ATI68875 0x02 +#define DAC_TVP3026_A 0x72 +#define DAC_BT476 0x03 +#define DAC_BT481 0x04 +#define DAC_ATT20C491 0x14 +#define DAC_SC15026 0x24 +#define DAC_MU9C1880 0x34 +#define DAC_IMSG174 0x44 +#define DAC_ATI68860_B 0x05 +#define DAC_ATI68860_C 0x15 +#define DAC_TVP3026_B 0x75 +#define DAC_STG1700 0x06 +#define DAC_ATT498 0x16 +#define DAC_STG1702 0x07 +#define DAC_SC15021 0x17 +#define DAC_ATT21C498 0x27 +#define DAC_STG1703 0x37 +#define DAC_CH8398 0x47 +#define DAC_ATT20C408 0x57 + +#define CLK_ATI18818_0 0 +#define CLK_ATI18818_1 1 +#define CLK_STG1703 2 +#define CLK_CH8398 3 +#define CLK_INTERNAL 4 +#define CLK_ATT20C408 5 +#define CLK_IBMRGB514 6 + +/* MEM_CNTL register constants */ +#define MEM_SIZE_ALIAS 0x00000007 +#define MEM_SIZE_512K 0x00000000 +#define MEM_SIZE_1M 0x00000001 +#define MEM_SIZE_2M 0x00000002 +#define MEM_SIZE_4M 0x00000003 +#define MEM_SIZE_6M 0x00000004 +#define MEM_SIZE_8M 0x00000005 +#define MEM_SIZE_ALIAS_GTB 0x0000000F +#define MEM_SIZE_2M_GTB 0x00000003 +#define MEM_SIZE_4M_GTB 0x00000007 +#define MEM_SIZE_6M_GTB 0x00000009 +#define MEM_SIZE_8M_GTB 0x0000000B +#define MEM_BNDRY 0x00030000 +#define MEM_BNDRY_0K 0x00000000 +#define MEM_BNDRY_256K 0x00010000 +#define MEM_BNDRY_512K 0x00020000 +#define MEM_BNDRY_1M 0x00030000 +#define MEM_BNDRY_EN 0x00040000 + +/* ATI PCI constants */ +#define PCI_ATI_VENDOR_ID 0x1002 + + +/* CONFIG_CHIP_ID register constants */ +#define CFG_CHIP_TYPE 0x0000FFFF +#define CFG_CHIP_CLASS 0x00FF0000 +#define CFG_CHIP_REV 0xFF000000 +#define CFG_CHIP_MAJOR 0x07000000 +#define CFG_CHIP_FND_ID 0x38000000 +#define CFG_CHIP_MINOR 0xC0000000 + + +/* Chip IDs read from CONFIG_CHIP_ID */ + +/* mach64GX family */ +#define GX_CHIP_ID 0xD7 /* mach64GX (ATI888GX00) */ +#define CX_CHIP_ID 0x57 /* mach64CX (ATI888CX00) */ + +#define GX_PCI_ID 0x4758 /* mach64GX (ATI888GX00) */ +#define CX_PCI_ID 0x4358 /* mach64CX (ATI888CX00) */ + +/* mach64CT family */ +#define CT_CHIP_ID 0x4354 /* mach64CT (ATI264CT) */ +#define ET_CHIP_ID 0x4554 /* mach64ET (ATI264ET) */ + +/* mach64CT family / mach64VT class */ +#define VT_CHIP_ID 0x5654 /* mach64VT (ATI264VT) */ +#define VU_CHIP_ID 0x5655 /* mach64VTB (ATI264VTB) */ +#define VV_CHIP_ID 0x5656 /* mach64VT4 (ATI264VT4) */ + +/* mach64CT family / mach64GT (3D RAGE) class */ +#define LB_CHIP_ID 0x4c42 /* RAGE LT PRO, AGP */ +#define LD_CHIP_ID 0x4c44 /* RAGE LT PRO */ +#define LG_CHIP_ID 0x4c47 /* RAGE LT */ +#define LI_CHIP_ID 0x4c49 /* RAGE LT PRO */ +#define LP_CHIP_ID 0x4c50 /* RAGE LT PRO */ +#define LT_CHIP_ID 0x4c54 /* RAGE LT */ +#define GT_CHIP_ID 0x4754 /* RAGE (GT) */ +#define GU_CHIP_ID 0x4755 /* RAGE II/II+ (GTB) */ +#define GV_CHIP_ID 0x4756 /* RAGE IIC, PCI */ +#define GW_CHIP_ID 0x4757 /* RAGE IIC, AGP */ +#define GZ_CHIP_ID 0x475a /* RAGE IIC, AGP */ +#define GB_CHIP_ID 0x4742 /* RAGE PRO, BGA, AGP 1x and 2x */ +#define GD_CHIP_ID 0x4744 /* RAGE PRO, BGA, AGP 1x only */ +#define GI_CHIP_ID 0x4749 /* RAGE PRO, BGA, PCI33 only */ +#define GP_CHIP_ID 0x4750 /* RAGE PRO, PQFP, PCI33, full 3D */ +#define GQ_CHIP_ID 0x4751 /* RAGE PRO, PQFP, PCI33, limited 3D */ +#define LM_CHIP_ID 0x4c4d /* RAGE Mobility PCI */ +#define LN_CHIP_ID 0x4c4e /* RAGE Mobility AGP */ + + +/* Mach64 major ASIC revisions */ +#define MACH64_ASIC_NEC_VT_A3 0x08 +#define MACH64_ASIC_NEC_VT_A4 0x48 +#define MACH64_ASIC_SGS_VT_A4 0x40 +#define MACH64_ASIC_SGS_VT_B1S1 0x01 +#define MACH64_ASIC_SGS_GT_B1S1 0x01 +#define MACH64_ASIC_SGS_GT_B1S2 0x41 +#define MACH64_ASIC_UMC_GT_B2U1 0x1a +#define MACH64_ASIC_UMC_GT_B2U2 0x5a +#define MACH64_ASIC_UMC_VT_B2U3 0x9a +#define MACH64_ASIC_UMC_GT_B2U3 0x9a +#define MACH64_ASIC_UMC_R3B_D_P_A1 0x1b +#define MACH64_ASIC_UMC_R3B_D_P_A2 0x5b +#define MACH64_ASIC_UMC_R3B_D_P_A3 0x1c +#define MACH64_ASIC_UMC_R3B_D_P_A4 0x5c + +/* Mach64 foundries */ +#define MACH64_FND_SGS 0 +#define MACH64_FND_NEC 1 +#define MACH64_FND_UMC 3 + +/* Mach64 chip types */ +#define MACH64_UNKNOWN 0 +#define MACH64_GX 1 +#define MACH64_CX 2 +#define MACH64_CT 3 +#define MACH64_ET 4 +#define MACH64_VT 5 +#define MACH64_GT 6 + +/* DST_CNTL register constants */ +#define DST_X_RIGHT_TO_LEFT 0 +#define DST_X_LEFT_TO_RIGHT 1 +#define DST_Y_BOTTOM_TO_TOP 0 +#define DST_Y_TOP_TO_BOTTOM 2 +#define DST_X_MAJOR 0 +#define DST_Y_MAJOR 4 +#define DST_X_TILE 8 +#define DST_Y_TILE 0x10 +#define DST_LAST_PEL 0x20 +#define DST_POLYGON_ENABLE 0x40 +#define DST_24_ROTATION_ENABLE 0x80 + +/* SRC_CNTL register constants */ +#define SRC_PATTERN_ENABLE 1 +#define SRC_ROTATION_ENABLE 2 +#define SRC_LINEAR_ENABLE 4 +#define SRC_BYTE_ALIGN 8 +#define SRC_LINE_X_RIGHT_TO_LEFT 0 +#define SRC_LINE_X_LEFT_TO_RIGHT 0x10 + +/* HOST_CNTL register constants */ +#define HOST_BYTE_ALIGN 1 + +/* GUI_TRAJ_CNTL register constants */ +#define PAT_MONO_8x8_ENABLE 0x01000000 +#define PAT_CLR_4x2_ENABLE 0x02000000 +#define PAT_CLR_8x1_ENABLE 0x04000000 + +/* DP_CHAIN_MASK register constants */ +#define DP_CHAIN_4BPP 0x8888 +#define DP_CHAIN_7BPP 0xD2D2 +#define DP_CHAIN_8BPP 0x8080 +#define DP_CHAIN_8BPP_RGB 0x9292 +#define DP_CHAIN_15BPP 0x4210 +#define DP_CHAIN_16BPP 0x8410 +#define DP_CHAIN_24BPP 0x8080 +#define DP_CHAIN_32BPP 0x8080 + +/* DP_PIX_WIDTH register constants */ +#define DST_1BPP 0 +#define DST_4BPP 1 +#define DST_8BPP 2 +#define DST_15BPP 3 +#define DST_16BPP 4 +#define DST_32BPP 6 +#define SRC_1BPP 0 +#define SRC_4BPP 0x100 +#define SRC_8BPP 0x200 +#define SRC_15BPP 0x300 +#define SRC_16BPP 0x400 +#define SRC_32BPP 0x600 +#define HOST_1BPP 0 +#define HOST_4BPP 0x10000 +#define HOST_8BPP 0x20000 +#define HOST_15BPP 0x30000 +#define HOST_16BPP 0x40000 +#define HOST_32BPP 0x60000 +#define BYTE_ORDER_MSB_TO_LSB 0 +#define BYTE_ORDER_LSB_TO_MSB 0x1000000 + +/* DP_MIX register constants */ +#define BKGD_MIX_NOT_D 0 +#define BKGD_MIX_ZERO 1 +#define BKGD_MIX_ONE 2 +#define BKGD_MIX_D 3 +#define BKGD_MIX_NOT_S 4 +#define BKGD_MIX_D_XOR_S 5 +#define BKGD_MIX_NOT_D_XOR_S 6 +#define BKGD_MIX_S 7 +#define BKGD_MIX_NOT_D_OR_NOT_S 8 +#define BKGD_MIX_D_OR_NOT_S 9 +#define BKGD_MIX_NOT_D_OR_S 10 +#define BKGD_MIX_D_OR_S 11 +#define BKGD_MIX_D_AND_S 12 +#define BKGD_MIX_NOT_D_AND_S 13 +#define BKGD_MIX_D_AND_NOT_S 14 +#define BKGD_MIX_NOT_D_AND_NOT_S 15 +#define BKGD_MIX_D_PLUS_S_DIV2 0x17 +#define FRGD_MIX_NOT_D 0 +#define FRGD_MIX_ZERO 0x10000 +#define FRGD_MIX_ONE 0x20000 +#define FRGD_MIX_D 0x30000 +#define FRGD_MIX_NOT_S 0x40000 +#define FRGD_MIX_D_XOR_S 0x50000 +#define FRGD_MIX_NOT_D_XOR_S 0x60000 +#define FRGD_MIX_S 0x70000 +#define FRGD_MIX_NOT_D_OR_NOT_S 0x80000 +#define FRGD_MIX_D_OR_NOT_S 0x90000 +#define FRGD_MIX_NOT_D_OR_S 0xa0000 +#define FRGD_MIX_D_OR_S 0xb0000 +#define FRGD_MIX_D_AND_S 0xc0000 +#define FRGD_MIX_NOT_D_AND_S 0xd0000 +#define FRGD_MIX_D_AND_NOT_S 0xe0000 +#define FRGD_MIX_NOT_D_AND_NOT_S 0xf0000 +#define FRGD_MIX_D_PLUS_S_DIV2 0x170000 + +/* DP_SRC register constants */ +#define BKGD_SRC_BKGD_CLR 0 +#define BKGD_SRC_FRGD_CLR 1 +#define BKGD_SRC_HOST 2 +#define BKGD_SRC_BLIT 3 +#define BKGD_SRC_PATTERN 4 +#define FRGD_SRC_BKGD_CLR 0 +#define FRGD_SRC_FRGD_CLR 0x100 +#define FRGD_SRC_HOST 0x200 +#define FRGD_SRC_BLIT 0x300 +#define FRGD_SRC_PATTERN 0x400 +#define MONO_SRC_ONE 0 +#define MONO_SRC_PATTERN 0x10000 +#define MONO_SRC_HOST 0x20000 +#define MONO_SRC_BLIT 0x30000 + +/* CLR_CMP_CNTL register constants */ +#define COMPARE_FALSE 0 +#define COMPARE_TRUE 1 +#define COMPARE_NOT_EQUAL 4 +#define COMPARE_EQUAL 5 +#define COMPARE_DESTINATION 0 +#define COMPARE_SOURCE 0x1000000 + +/* FIFO_STAT register constants */ +#define FIFO_ERR 0x80000000 + +/* CONTEXT_LOAD_CNTL constants */ +#define CONTEXT_NO_LOAD 0 +#define CONTEXT_LOAD 0x10000 +#define CONTEXT_LOAD_AND_DO_FILL 0x20000 +#define CONTEXT_LOAD_AND_DO_LINE 0x30000 +#define CONTEXT_EXECUTE 0 +#define CONTEXT_CMD_DISABLE 0x80000000 + +/* GUI_STAT register constants */ +#define ENGINE_IDLE 0 +#define ENGINE_BUSY 1 +#define SCISSOR_LEFT_FLAG 0x10 +#define SCISSOR_RIGHT_FLAG 0x20 +#define SCISSOR_TOP_FLAG 0x40 +#define SCISSOR_BOTTOM_FLAG 0x80 + +/* ATI VGA Extended Regsiters */ +#define sioATIEXT 0x1ce +#define bioATIEXT 0x3ce + +#define ATI2E 0xae +#define ATI32 0xb2 +#define ATI36 0xb6 + +/* VGA Graphics Controller Registers */ +#define VGAGRA 0x3ce +#define GRA06 0x06 + +/* VGA Seququencer Registers */ +#define VGASEQ 0x3c4 +#define SEQ02 0x02 +#define SEQ04 0x04 + +#define MACH64_MAX_X ENGINE_MAX_X +#define MACH64_MAX_Y ENGINE_MAX_Y + +#define INC_X 0x0020 +#define INC_Y 0x0080 + +#define RGB16_555 0x0000 +#define RGB16_565 0x0040 +#define RGB16_655 0x0080 +#define RGB16_664 0x00c0 + +#define POLY_TEXT_TYPE 0x0001 +#define IMAGE_TEXT_TYPE 0x0002 +#define TEXT_TYPE_8_BIT 0x0004 +#define TEXT_TYPE_16_BIT 0x0008 +#define POLY_TEXT_TYPE_8 (POLY_TEXT_TYPE | TEXT_TYPE_8_BIT) +#define IMAGE_TEXT_TYPE_8 (IMAGE_TEXT_TYPE | TEXT_TYPE_8_BIT) +#define POLY_TEXT_TYPE_16 (POLY_TEXT_TYPE | TEXT_TYPE_16_BIT) +#define IMAGE_TEXT_TYPE_16 (IMAGE_TEXT_TYPE | TEXT_TYPE_16_BIT) + +#define MACH64_NUM_CLOCKS 16 +#define MACH64_NUM_FREQS 50 + +/* Power Management register constants (LT & LT Pro) */ +#define PWR_MGT_ON 0x00000001 +#define PWR_MGT_MODE_MASK 0x00000006 +#define AUTO_PWR_UP 0x00000008 +#define USE_F32KHZ 0x00000400 +#define TRISTATE_MEM_EN 0x00000800 +#define SELF_REFRESH 0x00000080 +#define PWR_BLON 0x02000000 +#define STANDBY_NOW 0x10000000 +#define SUSPEND_NOW 0x20000000 +#define PWR_MGT_STATUS_MASK 0xC0000000 +#define PWR_MGT_STATUS_SUSPEND 0x80000000 + +/* PM Mode constants */ +#define PWR_MGT_MODE_PIN 0x00000000 +#define PWR_MGT_MODE_REG 0x00000002 +#define PWR_MGT_MODE_TIMER 0x00000004 +#define PWR_MGT_MODE_PCI 0x00000006 + +/* LCD registers (LT Pro) */ + +/* LCD Index register */ +#define LCD_INDEX_MASK 0x0000003F +#define LCD_DISPLAY_DIS 0x00000100 +#define LCD_SRC_SEL 0x00000200 +#define CRTC2_DISPLAY_DIS 0x00000400 + +/* LCD register indices */ +#define LCD_CONFIG_PANEL 0x00 +#define LCD_GEN_CTRL 0x01 +#define LCD_DSTN_CONTROL 0x02 +#define LCD_HFB_PITCH_ADDR 0x03 +#define LCD_HORZ_STRETCHING 0x04 +#define LCD_VERT_STRETCHING 0x05 +#define LCD_EXT_VERT_STRETCH 0x06 +#define LCD_LT_GIO 0x07 +#define LCD_POWER_MANAGEMENT 0x08 +#define LCD_ZVGPIO 0x09 +#define LCD_MISC_CNTL 0x14 + +/* Values in LCD_MISC_CNTL */ +#define BIAS_MOD_LEVEL_MASK 0x0000ff00 +#define BIAS_MOD_LEVEL_SHIFT 8 +#define BLMOD_EN 0x00010000 +#define BIASMOD_EN 0x00020000 + +#endif /* REGMACH64_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/aty/mach64_accel.c linux.ac/drivers/video/aty/mach64_accel.c --- linux.vanilla/drivers/video/aty/mach64_accel.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/aty/mach64_accel.c Tue Apr 3 17:55:08 2001 @@ -0,0 +1,352 @@ + +/* + * ATI Mach64 Hardware Acceleration + */ + +#include <linux/delay.h> +#include <linux/fb.h> + +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb24.h> +#include <video/fbcon-cfb32.h> + +#include "mach64.h" +#include "atyfb.h" + + /* + * Text console acceleration + */ + +static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void fbcon_aty_clear(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width); + + + /* + * Generic Mach64 routines + */ + +void aty_reset_engine(const struct fb_info_aty *info) +{ + /* reset engine */ + aty_st_le32(GEN_TEST_CNTL, + aty_ld_le32(GEN_TEST_CNTL, info) & ~GUI_ENGINE_ENABLE, info); + /* enable engine */ + aty_st_le32(GEN_TEST_CNTL, + aty_ld_le32(GEN_TEST_CNTL, info) | GUI_ENGINE_ENABLE, info); + /* ensure engine is not locked up by clearing any FIFO or */ + /* HOST errors */ + aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, info) | BUS_HOST_ERR_ACK | + BUS_FIFO_ERR_ACK, info); +} + +static void reset_GTC_3D_engine(const struct fb_info_aty *info) +{ + aty_st_le32(SCALE_3D_CNTL, 0xc0, info); + mdelay(GTC_3D_RESET_DELAY); + aty_st_le32(SETUP_CNTL, 0x00, info); + mdelay(GTC_3D_RESET_DELAY); + aty_st_le32(SCALE_3D_CNTL, 0x00, info); + mdelay(GTC_3D_RESET_DELAY); +} + +void aty_init_engine(const struct atyfb_par *par, struct fb_info_aty *info) +{ + u32 pitch_value; + + /* determine modal information from global mode structure */ + pitch_value = par->crtc.vxres; + + if (par->crtc.bpp == 24) { + /* In 24 bpp, the engine is in 8 bpp - this requires that all */ + /* horizontal coordinates and widths must be adjusted */ + pitch_value = pitch_value * 3; + } + + /* On GTC (RagePro), we need to reset the 3D engine before */ + if (M64_HAS(RESET_3D)) + reset_GTC_3D_engine(info); + + /* Reset engine, enable, and clear any engine errors */ + aty_reset_engine(info); + /* Ensure that vga page pointers are set to zero - the upper */ + /* page pointers are set to 1 to handle overflows in the */ + /* lower page */ + aty_st_le32(MEM_VGA_WP_SEL, 0x00010000, info); + aty_st_le32(MEM_VGA_RP_SEL, 0x00010000, info); + + /* ---- Setup standard engine context ---- */ + + /* All GUI registers here are FIFOed - therefore, wait for */ + /* the appropriate number of empty FIFO entries */ + wait_for_fifo(14, info); + + /* enable all registers to be loaded for context loads */ + aty_st_le32(CONTEXT_MASK, 0xFFFFFFFF, info); + + /* set destination pitch to modal pitch, set offset to zero */ + aty_st_le32(DST_OFF_PITCH, (pitch_value / 8) << 22, info); + + /* zero these registers (set them to a known state) */ + aty_st_le32(DST_Y_X, 0, info); + aty_st_le32(DST_HEIGHT, 0, info); + aty_st_le32(DST_BRES_ERR, 0, info); + aty_st_le32(DST_BRES_INC, 0, info); + aty_st_le32(DST_BRES_DEC, 0, info); + + /* set destination drawing attributes */ + aty_st_le32(DST_CNTL, DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM | + DST_X_LEFT_TO_RIGHT, info); + + /* set source pitch to modal pitch, set offset to zero */ + aty_st_le32(SRC_OFF_PITCH, (pitch_value / 8) << 22, info); + + /* set these registers to a known state */ + aty_st_le32(SRC_Y_X, 0, info); + aty_st_le32(SRC_HEIGHT1_WIDTH1, 1, info); + aty_st_le32(SRC_Y_X_START, 0, info); + aty_st_le32(SRC_HEIGHT2_WIDTH2, 1, info); + + /* set source pixel retrieving attributes */ + aty_st_le32(SRC_CNTL, SRC_LINE_X_LEFT_TO_RIGHT, info); + + /* set host attributes */ + wait_for_fifo(13, info); + aty_st_le32(HOST_CNTL, 0, info); + + /* set pattern attributes */ + aty_st_le32(PAT_REG0, 0, info); + aty_st_le32(PAT_REG1, 0, info); + aty_st_le32(PAT_CNTL, 0, info); + + /* set scissors to modal size */ + aty_st_le32(SC_LEFT, 0, info); + aty_st_le32(SC_TOP, 0, info); + aty_st_le32(SC_BOTTOM, par->crtc.vyres-1, info); + aty_st_le32(SC_RIGHT, pitch_value-1, info); + + /* set background color to minimum value (usually BLACK) */ + aty_st_le32(DP_BKGD_CLR, 0, info); + + /* set foreground color to maximum value (usually WHITE) */ + aty_st_le32(DP_FRGD_CLR, 0xFFFFFFFF, info); + + /* set write mask to effect all pixel bits */ + aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, info); + + /* set foreground mix to overpaint and background mix to */ + /* no-effect */ + aty_st_le32(DP_MIX, FRGD_MIX_S | BKGD_MIX_D, info); + + /* set primary source pixel channel to foreground color */ + /* register */ + aty_st_le32(DP_SRC, FRGD_SRC_FRGD_CLR, info); + + /* set compare functionality to false (no-effect on */ + /* destination) */ + wait_for_fifo(3, info); + aty_st_le32(CLR_CMP_CLR, 0, info); + aty_st_le32(CLR_CMP_MASK, 0xFFFFFFFF, info); + aty_st_le32(CLR_CMP_CNTL, 0, info); + + /* set pixel depth */ + wait_for_fifo(2, info); + aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, info); + aty_st_le32(DP_CHAIN_MASK, par->crtc.dp_chain_mask, info); + + wait_for_fifo(5, info); + aty_st_le32(SCALE_3D_CNTL, 0, info); + aty_st_le32(Z_CNTL, 0, info); + aty_st_le32(CRTC_INT_CNTL, aty_ld_le32(CRTC_INT_CNTL, info) & ~0x20, info); + aty_st_le32(GUI_TRAJ_CNTL, 0x100023, info); + + /* insure engine is idle before leaving */ + wait_for_idle(info); +} + + + /* + * Accelerated functions + */ + +static inline void draw_rect(s16 x, s16 y, u16 width, u16 height, + struct fb_info_aty *info) +{ + /* perform rectangle fill */ + wait_for_fifo(2, info); + aty_st_le32(DST_Y_X, (x << 16) | y, info); + aty_st_le32(DST_HEIGHT_WIDTH, (width << 16) | height, info); + info->blitter_may_be_busy = 1; +} + +static inline void aty_rectcopy(int srcx, int srcy, int dstx, int dsty, + u_int width, u_int height, + struct fb_info_aty *info) +{ + u32 direction = DST_LAST_PEL; + u32 pitch_value; + + if (!width || !height) + return; + + pitch_value = info->current_par.crtc.vxres; + if (info->current_par.crtc.bpp == 24) { + /* In 24 bpp, the engine is in 8 bpp - this requires that all */ + /* horizontal coordinates and widths must be adjusted */ + pitch_value *= 3; + srcx *= 3; + dstx *= 3; + width *= 3; + } + + if (srcy < dsty) { + dsty += height - 1; + srcy += height - 1; + } else + direction |= DST_Y_TOP_TO_BOTTOM; + + if (srcx < dstx) { + dstx += width - 1; + srcx += width - 1; + } else + direction |= DST_X_LEFT_TO_RIGHT; + + wait_for_fifo(4, info); + aty_st_le32(DP_SRC, FRGD_SRC_BLIT, info); + aty_st_le32(SRC_Y_X, (srcx << 16) | srcy, info); + aty_st_le32(SRC_HEIGHT1_WIDTH1, (width << 16) | height, info); + aty_st_le32(DST_CNTL, direction, info); + draw_rect(dstx, dsty, width, height, info); +} + +void aty_rectfill(int dstx, int dsty, u_int width, u_int height, u_int color, + struct fb_info_aty *info) +{ + if (!width || !height) + return; + + if (info->current_par.crtc.bpp == 24) { + /* In 24 bpp, the engine is in 8 bpp - this requires that all */ + /* horizontal coordinates and widths must be adjusted */ + dstx *= 3; + width *= 3; + } + + wait_for_fifo(3, info); + aty_st_le32(DP_FRGD_CLR, color, info); + aty_st_le32(DP_SRC, BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE, + info); + aty_st_le32(DST_CNTL, DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM | + DST_X_LEFT_TO_RIGHT, info); + draw_rect(dstx, dsty, width, height, info); +} + + + /* + * Text console acceleration + */ + +static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ +#ifdef __sparc__ + struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); + + if (fb->mmaped && (!fb->fb_info.display_fg + || fb->fb_info.display_fg->vc_num == fb->vtconsole)) + return; +#endif + + sx *= fontwidth(p); + sy *= fontheight(p); + dx *= fontwidth(p); + dy *= fontheight(p); + width *= fontwidth(p); + height *= fontheight(p); + + aty_rectcopy(sx, sy, dx, dy, width, height, + (struct fb_info_aty *)p->fb_info); +} + +static void fbcon_aty_clear(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width) +{ + u32 bgx; +#ifdef __sparc__ + struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); + + if (fb->mmaped && (!fb->fb_info.display_fg + || fb->fb_info.display_fg->vc_num == fb->vtconsole)) + return; +#endif + + bgx = attr_bgcol_ec(p, conp); + bgx |= (bgx << 8); + bgx |= (bgx << 16); + + sx *= fontwidth(p); + sy *= fontheight(p); + width *= fontwidth(p); + height *= fontheight(p); + + aty_rectfill(sx, sy, width, height, bgx, + (struct fb_info_aty *)p->fb_info); +} + +#ifdef __sparc__ +#define check_access \ + if (fb->mmaped && (!fb->fb_info.display_fg \ + || fb->fb_info.display_fg->vc_num == fb->vtconsole)) \ + return; +#else +#define check_access do { } while (0) +#endif + +#define DEF_FBCON_ATY_OP(name, call, args...) \ +static void name(struct vc_data *conp, struct display *p, args) \ +{ \ + struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); \ + check_access; \ + if (fb->blitter_may_be_busy) \ + wait_for_idle((struct fb_info_aty *)p->fb_info); \ + call; \ +} + +#define DEF_FBCON_ATY(width) \ + DEF_FBCON_ATY_OP(fbcon_aty##width##_putc, \ + fbcon_cfb##width##_putc(conp, p, c, yy, xx), \ + int c, int yy, int xx) \ + DEF_FBCON_ATY_OP(fbcon_aty##width##_putcs, \ + fbcon_cfb##width##_putcs(conp, p, s, count, yy, xx), \ + const unsigned short *s, int count, int yy, int xx) \ + DEF_FBCON_ATY_OP(fbcon_aty##width##_clear_margins, \ + fbcon_cfb##width##_clear_margins(conp, p, bottom_only), \ + int bottom_only) \ + \ +const struct display_switch fbcon_aty##width## = { \ + setup: fbcon_cfb##width##_setup, \ + bmove: fbcon_aty_bmove, \ + clear: fbcon_aty_clear, \ + putc: fbcon_aty##width##_putc, \ + putcs: fbcon_aty##width##_putcs, \ + revc: fbcon_cfb##width##_revc, \ + clear_margins: fbcon_aty##width##_clear_margins, \ + fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) \ +}; + +#ifdef FBCON_HAS_CFB8 +DEF_FBCON_ATY(8) +#endif +#ifdef FBCON_HAS_CFB16 +DEF_FBCON_ATY(16) +#endif +#ifdef FBCON_HAS_CFB24 +DEF_FBCON_ATY(24) +#endif +#ifdef FBCON_HAS_CFB32 +DEF_FBCON_ATY(32) +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/aty/mach64_ct.c linux.ac/drivers/video/aty/mach64_ct.c --- linux.vanilla/drivers/video/aty/mach64_ct.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/aty/mach64_ct.c Tue Apr 3 17:55:08 2001 @@ -0,0 +1,270 @@ + +/* + * ATI Mach64 CT/VT/GT/LT Support + */ + +#include <linux/fb.h> + +#include <asm/io.h> + +#include <video/fbcon.h> + +#include "mach64.h" +#include "atyfb.h" + + +/* FIXME: remove the FAIL definition */ +#define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0) + +static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info); + +static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per, + struct pll_ct *pll); +static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp, + struct pll_ct *pll); +static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per, + u8 bpp, union aty_pll *pll); +static u32 aty_pll_ct_to_var(const struct fb_info_aty *info, + const union aty_pll *pll); + + + +static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info) +{ + /* write addr byte */ + aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN, info); + /* write the register value */ + aty_st_8(CLOCK_CNTL + 2, val, info); + aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN, info); +} + + +/* ------------------------------------------------------------------------- */ + + /* + * PLL programming (Mach64 CT family) + */ + +static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp, + struct pll_ct *pll) +{ + u32 dsp_xclks_per_row, dsp_loop_latency, dsp_precision, dsp_off, dsp_on; + u32 xclks_per_row, fifo_off, fifo_on, y, fifo_size, page_size; + + /* xclocks_per_row<<11 */ + xclks_per_row = (pll->mclk_fb_div*pll->vclk_post_div_real*64<<11)/ + (pll->vclk_fb_div*pll->mclk_post_div_real*bpp); + if (xclks_per_row < (1<<11)) + FAIL("Dotclock to high"); + if (M64_HAS(FIFO_24)) { + fifo_size = 24; + dsp_loop_latency = 0; + } else { + fifo_size = 32; + dsp_loop_latency = 2; + } + dsp_precision = 0; + y = (xclks_per_row*fifo_size)>>11; + while (y) { + y >>= 1; + dsp_precision++; + } + dsp_precision -= 5; + /* fifo_off<<6 */ + fifo_off = ((xclks_per_row*(fifo_size-1))>>5)+(3<<6); + + if (info->total_vram > 1*1024*1024) { + if (info->ram_type >= SDRAM) { + /* >1 MB SDRAM */ + dsp_loop_latency += 8; + page_size = 8; + } else { + /* >1 MB DRAM */ + dsp_loop_latency += 6; + page_size = 9; + } + } else { + if (info->ram_type >= SDRAM) { + /* <2 MB SDRAM */ + dsp_loop_latency += 9; + page_size = 10; + } else { + /* <2 MB DRAM */ + dsp_loop_latency += 8; + page_size = 10; + } + } + /* fifo_on<<6 */ + if (xclks_per_row >= (page_size<<11)) + fifo_on = ((2*page_size+1)<<6)+(xclks_per_row>>5); + else + fifo_on = (3*page_size+2)<<6; + + dsp_xclks_per_row = xclks_per_row>>dsp_precision; + dsp_on = fifo_on>>dsp_precision; + dsp_off = fifo_off>>dsp_precision; + + pll->dsp_config = (dsp_xclks_per_row & 0x3fff) | + ((dsp_loop_latency & 0xf)<<16) | + ((dsp_precision & 7)<<20); + pll->dsp_on_off = (dsp_on & 0x7ff) | ((dsp_off & 0x7ff)<<16); + return 0; +} + +static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per, + struct pll_ct *pll) +{ + u32 q, x; /* x is a workaround for sparc64-linux-gcc */ + x = x; /* x is a workaround for sparc64-linux-gcc */ + + pll->pll_ref_div = info->pll_per*2*255/info->ref_clk_per; + + /* FIXME: use the VTB/GTB /3 post divider if it's better suited */ + q = info->ref_clk_per*pll->pll_ref_div*4/info->mclk_per; /* actually 8*q */ + if (q < 16*8 || q > 255*8) + FAIL("mclk out of range"); + else if (q < 32*8) + pll->mclk_post_div_real = 8; + else if (q < 64*8) + pll->mclk_post_div_real = 4; + else if (q < 128*8) + pll->mclk_post_div_real = 2; + else + pll->mclk_post_div_real = 1; + pll->mclk_fb_div = q*pll->mclk_post_div_real/8; + + /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */ + q = info->ref_clk_per*pll->pll_ref_div*4/vclk_per; /* actually 8*q */ + if (q < 16*8 || q > 255*8) + FAIL("vclk out of range"); + else if (q < 32*8) + pll->vclk_post_div_real = 8; + else if (q < 64*8) + pll->vclk_post_div_real = 4; + else if (q < 128*8) + pll->vclk_post_div_real = 2; + else + pll->vclk_post_div_real = 1; + pll->vclk_fb_div = q*pll->vclk_post_div_real/8; + return 0; +} + +void aty_calc_pll_ct(const struct fb_info_aty *info, struct pll_ct *pll) +{ + u8 mpostdiv = 0; + u8 vpostdiv = 0; + + if (M64_HAS(SDRAM_MAGIC_PLL) && (info->ram_type >= SDRAM)) + pll->pll_gen_cntl = 0x04; + else + pll->pll_gen_cntl = 0x84; + + switch (pll->mclk_post_div_real) { + case 1: + mpostdiv = 0; + break; + case 2: + mpostdiv = 1; + break; + case 3: + mpostdiv = 4; + break; + case 4: + mpostdiv = 2; + break; + case 8: + mpostdiv = 3; + break; + } + pll->pll_gen_cntl |= mpostdiv<<4; /* mclk */ + + if (M64_HAS(MAGIC_POSTDIV)) + pll->pll_ext_cntl = 0; + else + pll->pll_ext_cntl = mpostdiv; /* xclk == mclk */ + + switch (pll->vclk_post_div_real) { + case 2: + vpostdiv = 1; + break; + case 3: + pll->pll_ext_cntl |= 0x10; + case 1: + vpostdiv = 0; + break; + case 6: + pll->pll_ext_cntl |= 0x10; + case 4: + vpostdiv = 2; + break; + case 12: + pll->pll_ext_cntl |= 0x10; + case 8: + vpostdiv = 3; + break; + } + + pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */ + pll->vclk_post_div = vpostdiv; +} + +static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per, + u8 bpp, union aty_pll *pll) +{ + int err; + + if ((err = aty_valid_pll_ct(info, vclk_per, &pll->ct))) + return err; + if (M64_HAS(GTB_DSP) && (err = aty_dsp_gt(info, bpp, &pll->ct))) + return err; + aty_calc_pll_ct(info, &pll->ct); + return 0; +} + +static u32 aty_pll_ct_to_var(const struct fb_info_aty *info, + const union aty_pll *pll) +{ + u32 ref_clk_per = info->ref_clk_per; + u8 pll_ref_div = pll->ct.pll_ref_div; + u8 vclk_fb_div = pll->ct.vclk_fb_div; + u8 vclk_post_div = pll->ct.vclk_post_div_real; + + return ref_clk_per*pll_ref_div*vclk_post_div/vclk_fb_div/2; +} + +void aty_set_pll_ct(const struct fb_info_aty *info, const union aty_pll *pll) +{ + aty_st_pll(PLL_REF_DIV, pll->ct.pll_ref_div, info); + aty_st_pll(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, info); + aty_st_pll(MCLK_FB_DIV, pll->ct.mclk_fb_div, info); + aty_st_pll(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, info); + aty_st_pll(VCLK_POST_DIV, pll->ct.vclk_post_div, info); + aty_st_pll(VCLK0_FB_DIV, pll->ct.vclk_fb_div, info); + aty_st_pll(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, info); + + if (M64_HAS(GTB_DSP)) { + if (info->ram_type >= SDRAM) + aty_st_pll(DLL_CNTL, 0xa6, info); + else + aty_st_pll(DLL_CNTL, 0xa0, info); + aty_st_pll(VFC_CNTL, 0x1b, info); + aty_st_le32(DSP_CONFIG, pll->ct.dsp_config, info); + aty_st_le32(DSP_ON_OFF, pll->ct.dsp_on_off, info); + } +} + +static int dummy(void) +{ + return 0; +} + +const struct aty_dac_ops aty_dac_ct = { + set_dac: (void *)dummy, +}; + +const struct aty_pll_ops aty_pll_ct = { + var_to_pll: aty_var_to_pll_ct, + pll_to_var: aty_pll_ct_to_var, + set_pll: aty_set_pll_ct, +}; + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/aty/mach64_cursor.c linux.ac/drivers/video/aty/mach64_cursor.c --- linux.vanilla/drivers/video/aty/mach64_cursor.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/aty/mach64_cursor.c Tue Apr 3 17:55:08 2001 @@ -0,0 +1,305 @@ + +/* + * ATI Mach64 CT/VT/GT/LT Cursor Support + */ + +#include <linux/malloc.h> +#include <linux/console.h> +#include <linux/fb.h> +#include <linux/init.h> + +#include <asm/io.h> +#include <asm/uaccess.h> + +#include <video/fbcon.h> + +#ifdef __sparc__ +#include <asm/pbm.h> +#include <asm/fbio.h> +#endif + +#include "mach64.h" +#include "atyfb.h" + + +#define DEFAULT_CURSOR_BLINK_RATE (20) +#define CURSOR_DRAW_DELAY (2) + + + /* + * Hardware Cursor support. + */ + +static const u8 cursor_pixel_map[2] = { 0, 15 }; +static const u8 cursor_color_map[2] = { 0, 0xff }; + +static const u8 cursor_bits_lookup[16] = +{ + 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, + 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55 +}; + +static const u8 cursor_mask_lookup[16] = +{ + 0xaa, 0x2a, 0x8a, 0x0a, 0xa2, 0x22, 0x82, 0x02, + 0xa8, 0x28, 0x88, 0x08, 0xa0, 0x20, 0x80, 0x00 +}; + +void aty_set_cursor_color(struct fb_info_aty *fb) +{ + struct aty_cursor *c = fb->cursor; + const u8 *pixel = cursor_pixel_map; /* ++Geert: Why?? */ + const u8 *red = cursor_color_map; + const u8 *green = cursor_color_map; + const u8 *blue = cursor_color_map; + int i; + + if (!c) + return; + +#ifdef __sparc__ + if (fb->mmaped && (!fb->fb_info.display_fg + || fb->fb_info.display_fg->vc_num == fb->vtconsole)) + return; +#endif + + for (i = 0; i < 2; i++) { + c->color[i] = (u32)red[i] << 24; + c->color[i] |= (u32)green[i] << 16; + c->color[i] |= (u32)blue[i] << 8; + c->color[i] |= (u32)pixel[i]; + } + + wait_for_fifo(2, fb); + aty_st_le32(CUR_CLR0, c->color[0], fb); + aty_st_le32(CUR_CLR1, c->color[1], fb); +} + +void aty_set_cursor_shape(struct fb_info_aty *fb) +{ + struct aty_cursor *c = fb->cursor; + u8 *ram, m, b; + int x, y; + + if (!c) + return; + +#ifdef __sparc__ + if (fb->mmaped && (!fb->fb_info.display_fg + || fb->fb_info.display_fg->vc_num == fb->vtconsole)) + return; +#endif + + ram = c->ram; + for (y = 0; y < c->size.y; y++) { + for (x = 0; x < c->size.x >> 2; x++) { + m = c->mask[x][y]; + b = c->bits[x][y]; + fb_writeb (cursor_mask_lookup[m >> 4] | + cursor_bits_lookup[(b & m) >> 4], + ram++); + fb_writeb (cursor_mask_lookup[m & 0x0f] | + cursor_bits_lookup[(b & m) & 0x0f], + ram++); + } + for ( ; x < 8; x++) { + fb_writeb (0xaa, ram++); + fb_writeb (0xaa, ram++); + } + } + fb_memset (ram, 0xaa, (64 - c->size.y) * 16); +} + +static void +aty_set_cursor(struct fb_info_aty *fb, int on) +{ + struct atyfb_par *par = &fb->current_par; + struct aty_cursor *c = fb->cursor; + u16 xoff, yoff; + int x, y; + + if (!c) + return; + +#ifdef __sparc__ + if (fb->mmaped && (!fb->fb_info.display_fg + || fb->fb_info.display_fg->vc_num == fb->vtconsole)) + return; +#endif + + if (on) { + x = c->pos.x - c->hot.x - par->crtc.xoffset; + if (x < 0) { + xoff = -x; + x = 0; + } else { + xoff = 0; + } + + y = c->pos.y - c->hot.y - par->crtc.yoffset; + if (y < 0) { + yoff = -y; + y = 0; + } else { + yoff = 0; + } + + wait_for_fifo(4, fb); + aty_st_le32(CUR_OFFSET, (c->offset >> 3) + (yoff << 1), fb); + aty_st_le32(CUR_HORZ_VERT_OFF, + ((u32)(64 - c->size.y + yoff) << 16) | xoff, fb); + aty_st_le32(CUR_HORZ_VERT_POSN, ((u32)y << 16) | x, fb); + aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, fb) + | HWCURSOR_ENABLE, fb); + } else { + wait_for_fifo(1, fb); + aty_st_le32(GEN_TEST_CNTL, + aty_ld_le32(GEN_TEST_CNTL, fb) & ~HWCURSOR_ENABLE, + fb); + } + if (fb->blitter_may_be_busy) + wait_for_idle(fb); +} + +static void +aty_cursor_timer_handler(unsigned long dev_addr) +{ + struct fb_info_aty *fb = (struct fb_info_aty *)dev_addr; + + if (!fb->cursor) + return; + + if (!fb->cursor->enable) + goto out; + + if (fb->cursor->vbl_cnt && --fb->cursor->vbl_cnt == 0) { + fb->cursor->on ^= 1; + aty_set_cursor(fb, fb->cursor->on); + fb->cursor->vbl_cnt = fb->cursor->blink_rate; + } + +out: + fb->cursor->timer->expires = jiffies + (HZ / 50); + add_timer(fb->cursor->timer); +} + +void atyfb_cursor(struct display *p, int mode, int x, int y) +{ + struct fb_info_aty *fb = (struct fb_info_aty *)p->fb_info; + struct aty_cursor *c = fb->cursor; + + if (!c) + return; + +#ifdef __sparc__ + if (fb->mmaped && (!fb->fb_info.display_fg + || fb->fb_info.display_fg->vc_num == fb->vtconsole)) + return; +#endif + + x *= fontwidth(p); + y *= fontheight(p); + if (c->pos.x == x && c->pos.y == y && (mode == CM_ERASE) == !c->enable) + return; + + c->enable = 0; + if (c->on) + aty_set_cursor(fb, 0); + c->pos.x = x; + c->pos.y = y; + + switch (mode) { + case CM_ERASE: + c->on = 0; + break; + + case CM_DRAW: + case CM_MOVE: + if (c->on) + aty_set_cursor(fb, 1); + else + c->vbl_cnt = CURSOR_DRAW_DELAY; + c->enable = 1; + break; + } +} + +struct aty_cursor * __init aty_init_cursor(struct fb_info_aty *fb) +{ + struct aty_cursor *cursor; + unsigned long addr; + + cursor = kmalloc(sizeof(struct aty_cursor), GFP_ATOMIC); + if (!cursor) + return 0; + memset(cursor, 0, sizeof(*cursor)); + + cursor->timer = kmalloc(sizeof(*cursor->timer), GFP_KERNEL); + if (!cursor->timer) { + kfree(cursor); + return 0; + } + memset(cursor->timer, 0, sizeof(*cursor->timer)); + + cursor->blink_rate = DEFAULT_CURSOR_BLINK_RATE; + fb->total_vram -= PAGE_SIZE; + cursor->offset = fb->total_vram; + +#ifdef __sparc__ + addr = fb->frame_buffer - 0x800000 + cursor->offset; + cursor->ram = (u8 *)addr; +#else +#ifdef __BIG_ENDIAN + addr = fb->frame_buffer_phys - 0x800000 + cursor->offset; + cursor->ram = (u8 *)ioremap(addr, 1024); +#else + addr = fb->frame_buffer + cursor->offset; + cursor->ram = (u8 *)addr; +#endif +#endif + + if (!cursor->ram) { + kfree(cursor); + return NULL; + } + + init_timer(cursor->timer); + cursor->timer->expires = jiffies + (HZ / 50); + cursor->timer->data = (unsigned long)fb; + cursor->timer->function = aty_cursor_timer_handler; + add_timer(cursor->timer); + + return cursor; +} + +int atyfb_set_font(struct display *d, int width, int height) +{ + struct fb_info_aty *fb = (struct fb_info_aty *)d->fb_info; + struct aty_cursor *c = fb->cursor; + int i, j; + + if (c) { + if (!width || !height) { + width = 8; + height = 16; + } + + c->hot.x = 0; + c->hot.y = 0; + c->size.x = width; + c->size.y = height; + + memset(c->bits, 0xff, sizeof(c->bits)); + memset(c->mask, 0, sizeof(c->mask)); + + for (i = 0, j = width; j >= 0; j -= 8, i++) { + c->mask[i][height-2] = (j >= 8) ? 0xff : (0xff << (8 - j)); + c->mask[i][height-1] = (j >= 8) ? 0xff : (0xff << (8 - j)); + } + + aty_set_cursor_color(fb); + aty_set_cursor_shape(fb); + } + return 1; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/aty/mach64_gx.c linux.ac/drivers/video/aty/mach64_gx.c --- linux.vanilla/drivers/video/aty/mach64_gx.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/aty/mach64_gx.c Tue Apr 3 17:55:08 2001 @@ -0,0 +1,886 @@ + +/* + * ATI Mach64 GX Support + */ + +#include <linux/delay.h> +#include <linux/fb.h> + +#include <asm/io.h> + +#include <video/fbcon.h> + +#include "mach64.h" +#include "atyfb.h" + +/* Definitions for the ICS 2595 == ATI 18818_1 Clockchip */ + +#define REF_FREQ_2595 1432 /* 14.33 MHz (exact 14.31818) */ +#define REF_DIV_2595 46 /* really 43 on ICS 2595 !!! */ + /* ohne Prescaler */ +#define MAX_FREQ_2595 15938 /* 159.38 MHz (really 170.486) */ +#define MIN_FREQ_2595 8000 /* 80.00 MHz ( 85.565) */ + /* mit Prescaler 2, 4, 8 */ +#define ABS_MIN_FREQ_2595 1000 /* 10.00 MHz (really 10.697) */ +#define N_ADJ_2595 257 + +#define STOP_BITS_2595 0x1800 + + +#define MIN_N_408 2 + +#define MIN_N_1703 6 + +#define MIN_M 2 +#define MAX_M 30 +#define MIN_N 35 +#define MAX_N 255-8 + + + /* + * Support Functions + */ + +static void aty_dac_waste4(const struct fb_info_aty *info) +{ + (void)aty_ld_8(DAC_REGS, info); + + (void)aty_ld_8(DAC_REGS + 2, info); + (void)aty_ld_8(DAC_REGS + 2, info); + (void)aty_ld_8(DAC_REGS + 2, info); + (void)aty_ld_8(DAC_REGS + 2, info); +} + +static void aty_StrobeClock(const struct fb_info_aty *info) +{ + u8 tmp; + + udelay(26); + + tmp = aty_ld_8(CLOCK_CNTL, info); + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, tmp | CLOCK_STROBE, info); + + return; +} + + + /* + * IBM RGB514 DAC and Clock Chip + */ + +static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info) +{ + aty_st_8(DAC_CNTL, 1, info); + /* right addr byte */ + aty_st_8(DAC_W_INDEX, offset & 0xff, info); + /* left addr byte */ + aty_st_8(DAC_DATA, (offset >> 8) & 0xff, info); + aty_st_8(DAC_MASK, val, info); + aty_st_8(DAC_CNTL, 0, info); +} + +static int aty_set_dac_514(const struct fb_info_aty *info, + const union aty_pll *pll, u32 bpp, u32 accel) +{ + static struct { + u8 pixel_dly; + u8 misc2_cntl; + u8 pixel_rep; + u8 pixel_cntl_index; + u8 pixel_cntl_v1; + } tab[3] = { + { 0, 0x41, 0x03, 0x71, 0x45 }, /* 8 bpp */ + { 0, 0x45, 0x04, 0x0c, 0x01 }, /* 555 */ + { 0, 0x45, 0x06, 0x0e, 0x00 }, /* XRGB */ + }; + int i; + + switch (bpp) { + case 8: + default: + i = 0; + break; + case 16: + i = 1; + break; + case 32: + i = 2; + break; + } + aty_st_514(0x90, 0x00, info); /* VRAM Mask Low */ + aty_st_514(0x04, tab[i].pixel_dly, info); /* Horizontal Sync Control */ + aty_st_514(0x05, 0x00, info); /* Power Management */ + aty_st_514(0x02, 0x01, info); /* Misc Clock Control */ + aty_st_514(0x71, tab[i].misc2_cntl, info); /* Misc Control 2 */ + aty_st_514(0x0a, tab[i].pixel_rep, info); /* Pixel Format */ + aty_st_514(tab[i].pixel_cntl_index, tab[i].pixel_cntl_v1, info); + /* Misc Control 2 / 16 BPP Control / 32 BPP Control */ + return 0; +} + +static int aty_var_to_pll_514(const struct fb_info_aty *info, u32 vclk_per, + u8 bpp, union aty_pll *pll) +{ + /* + * FIXME: use real calculations instead of using fixed values from the old + * driver + */ + static struct { + u32 limit; /* pixlock rounding limit (arbitrary) */ + u8 m; /* (df<<6) | vco_div_count */ + u8 n; /* ref_div_count */ + } RGB514_clocks[7] = { + { 8000, (3<<6) | 20, 9 }, /* 7395 ps / 135.2273 MHz */ + { 10000, (1<<6) | 19, 3 }, /* 9977 ps / 100.2273 MHz */ + { 13000, (1<<6) | 2, 3 }, /* 12509 ps / 79.9432 MHz */ + { 14000, (2<<6) | 8, 7 }, /* 13394 ps / 74.6591 MHz */ + { 16000, (1<<6) | 44, 6 }, /* 15378 ps / 65.0284 MHz */ + { 25000, (1<<6) | 15, 5 }, /* 17460 ps / 57.2727 MHz */ + { 50000, (0<<6) | 53, 7 }, /* 33145 ps / 30.1705 MHz */ + }; + int i; + + for (i = 0; i < sizeof(RGB514_clocks)/sizeof(*RGB514_clocks); i++) + if (vclk_per <= RGB514_clocks[i].limit) { + pll->ibm514.m = RGB514_clocks[i].m; + pll->ibm514.n = RGB514_clocks[i].n; + return 0; + } + return -EINVAL; +} + +static u32 aty_pll_514_to_var(const struct fb_info_aty *info, + const union aty_pll *pll) +{ + u8 df, vco_div_count, ref_div_count; + + df = pll->ibm514.m >> 6; + vco_div_count = pll->ibm514.m & 0x3f; + ref_div_count = pll->ibm514.n; + + return ((info->ref_clk_per*ref_div_count)<<(3-df))/(vco_div_count+65); +} + +static void aty_set_pll_514(const struct fb_info_aty *info, + const union aty_pll *pll) +{ + aty_st_514(0x06, 0x02, info); /* DAC Operation */ + aty_st_514(0x10, 0x01, info); /* PLL Control 1 */ + aty_st_514(0x70, 0x01, info); /* Misc Control 1 */ + aty_st_514(0x8f, 0x1f, info); /* PLL Ref. Divider Input */ + aty_st_514(0x03, 0x00, info); /* Sync Control */ + aty_st_514(0x05, 0x00, info); /* Power Management */ + aty_st_514(0x20, pll->ibm514.m, info); /* F0 / M0 */ + aty_st_514(0x21, pll->ibm514.n, info); /* F1 / N0 */ +} + +const struct aty_dac_ops aty_dac_ibm514 = { + set_dac: aty_set_dac_514, +}; + +const struct aty_pll_ops aty_pll_ibm514 = { + var_to_pll: aty_var_to_pll_514, + pll_to_var: aty_pll_514_to_var, + set_pll: aty_set_pll_514, +}; + + + /* + * ATI 68860-B DAC + */ + +static int aty_set_dac_ATI68860_B(const struct fb_info_aty *info, + const union aty_pll *pll, u32 bpp, u32 accel) +{ + u32 gModeReg, devSetupRegA, temp, mask; + + gModeReg = 0; + devSetupRegA = 0; + + switch (bpp) { + case 8: + gModeReg = 0x83; + devSetupRegA = 0x60 | 0x00 /*(info->mach64DAC8Bit ? 0x00 : 0x01) */; + break; + case 15: + gModeReg = 0xA0; + devSetupRegA = 0x60; + break; + case 16: + gModeReg = 0xA1; + devSetupRegA = 0x60; + break; + case 24: + gModeReg = 0xC0; + devSetupRegA = 0x60; + break; + case 32: + gModeReg = 0xE3; + devSetupRegA = 0x60; + break; + } + + if (!accel) { + gModeReg = 0x80; + devSetupRegA = 0x61; + } + + temp = aty_ld_8(DAC_CNTL, info); + aty_st_8(DAC_CNTL, (temp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3, info); + + aty_st_8(DAC_REGS + 2, 0x1D, info); + aty_st_8(DAC_REGS + 3, gModeReg, info); + aty_st_8(DAC_REGS, 0x02, info); + + temp = aty_ld_8(DAC_CNTL, info); + aty_st_8(DAC_CNTL, temp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, info); + + if (info->total_vram < MEM_SIZE_1M) + mask = 0x04; + else if (info->total_vram == MEM_SIZE_1M) + mask = 0x08; + else + mask = 0x0C; + + /* The following assumes that the BIOS has correctly set R7 of the + * Device Setup Register A at boot time. + */ +#define A860_DELAY_L 0x80 + + temp = aty_ld_8(DAC_REGS, info); + aty_st_8(DAC_REGS, (devSetupRegA | mask) | (temp & A860_DELAY_L), info); + temp = aty_ld_8(DAC_CNTL, info); + aty_st_8(DAC_CNTL, (temp & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3)), info); + + aty_st_le32(BUS_CNTL, 0x890e20f1, info); + aty_st_le32(DAC_CNTL, 0x47052100, info); + + return 0; +} + +const struct aty_dac_ops aty_dac_ati68860b = { + set_dac: aty_set_dac_ATI68860_B, +}; + + + /* + * AT&T 21C498 DAC + */ + +static int aty_set_dac_ATT21C498(const struct fb_info_aty *info, + const union aty_pll *pll, u32 bpp, u32 accel) +{ + u32 dotClock; + int muxmode = 0; + int DACMask = 0; + + dotClock = 100000000 / pll->ics2595.period_in_ps; + + switch (bpp) { + case 8: + if (dotClock > 8000) { + DACMask = 0x24; + muxmode = 1; + } else + DACMask = 0x04; + break; + case 15: + DACMask = 0x16; + break; + case 16: + DACMask = 0x36; + break; + case 24: + DACMask = 0xE6; + break; + case 32: + DACMask = 0xE6; + break; + } + + if (1 /* info->mach64DAC8Bit */) + DACMask |= 0x02; + + aty_dac_waste4(info); + aty_st_8(DAC_REGS + 2, DACMask, info); + + aty_st_le32(BUS_CNTL, 0x890e20f1, info); + aty_st_le32(DAC_CNTL, 0x00072000, info); + return muxmode; +} + +const struct aty_dac_ops aty_dac_att21c498 = { + set_dac: aty_set_dac_ATT21C498, +}; + + + /* + * ATI 18818 / ICS 2595 Clock Chip + */ + +static int aty_var_to_pll_18818(const struct fb_info_aty *info, u32 vclk_per, + u8 bpp, union aty_pll *pll) +{ + u32 MHz100; /* in 0.01 MHz */ + u32 program_bits; + u32 post_divider; + + /* Calculate the programming word */ + MHz100 = 100000000 / vclk_per; + + program_bits = -1; + post_divider = 1; + + if (MHz100 > MAX_FREQ_2595) { + MHz100 = MAX_FREQ_2595; + return -EINVAL; + } else if (MHz100 < ABS_MIN_FREQ_2595) { + program_bits = 0; /* MHz100 = 257 */ + return -EINVAL; + } else { + while (MHz100 < MIN_FREQ_2595) { + MHz100 *= 2; + post_divider *= 2; + } + } + MHz100 *= 1000; + MHz100 = (REF_DIV_2595 * MHz100) / REF_FREQ_2595; + + MHz100 += 500; /* + 0.5 round */ + MHz100 /= 1000; + + if (program_bits == -1) { + program_bits = MHz100 - N_ADJ_2595; + switch (post_divider) { + case 1: + program_bits |= 0x0600; + break; + case 2: + program_bits |= 0x0400; + break; + case 4: + program_bits |= 0x0200; + break; + case 8: + default: + break; + } + } + + program_bits |= STOP_BITS_2595; + + pll->ics2595.program_bits = program_bits; + pll->ics2595.locationAddr = 0; + pll->ics2595.post_divider = post_divider; + pll->ics2595.period_in_ps = vclk_per; + + return 0; +} + +static u32 aty_pll_18818_to_var(const struct fb_info_aty *info, + const union aty_pll *pll) +{ + return(pll->ics2595.period_in_ps); /* default for now */ +} + +static void aty_ICS2595_put1bit(u8 data, const struct fb_info_aty *info) +{ + u8 tmp; + + data &= 0x01; + tmp = aty_ld_8(CLOCK_CNTL, info); + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x04) | (data << 2), + info); + + tmp = aty_ld_8(CLOCK_CNTL, info); + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x08) | (0 << 3), info); + + aty_StrobeClock(info); + + tmp = aty_ld_8(CLOCK_CNTL, info); + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x08) | (1 << 3), info); + + aty_StrobeClock(info); + + return; +} + +static void aty_set_pll18818(const struct fb_info_aty *info, + const union aty_pll *pll) +{ + u32 program_bits; + u32 locationAddr; + + u32 i; + + u8 old_clock_cntl; + u8 old_crtc_ext_disp; + + old_clock_cntl = aty_ld_8(CLOCK_CNTL, info); + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info); + + old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info); + aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), + info); + + mdelay(15); /* delay for 50 (15) ms */ + + program_bits = pll->ics2595.program_bits; + locationAddr = pll->ics2595.locationAddr; + + /* Program the clock chip */ + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info); /* Strobe = 0 */ + aty_StrobeClock(info); + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 1, info); /* Strobe = 0 */ + aty_StrobeClock(info); + + aty_ICS2595_put1bit(1, info); /* Send start bits */ + aty_ICS2595_put1bit(0, info); /* Start bit */ + aty_ICS2595_put1bit(0, info); /* Read / ~Write */ + + for (i = 0; i < 5; i++) { /* Location 0..4 */ + aty_ICS2595_put1bit(locationAddr & 1, info); + locationAddr >>= 1; + } + + for (i = 0; i < 8 + 1 + 2 + 2; i++) { + aty_ICS2595_put1bit(program_bits & 1, info); + program_bits >>= 1; + } + + mdelay(1); /* delay for 1 ms */ + + (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */ + aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info); + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, old_clock_cntl | CLOCK_STROBE, + info); + + mdelay(50); /* delay for 50 (15) ms */ + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, + ((pll->ics2595.locationAddr & 0x0F) | CLOCK_STROBE), info); + + return; +} + +const struct aty_pll_ops aty_pll_ati18818_1 = { + var_to_pll: aty_var_to_pll_18818, + pll_to_var: aty_pll_18818_to_var, + set_pll: aty_set_pll18818, +}; + + + /* + * STG 1703 Clock Chip + */ + +static int aty_var_to_pll_1703(const struct fb_info_aty *info, u32 vclk_per, + u8 bpp, union aty_pll *pll) +{ + u32 mhz100; /* in 0.01 MHz */ + u32 program_bits; + /* u32 post_divider; */ + u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq; + u32 temp, tempB; + u16 remainder, preRemainder; + short divider = 0, tempA; + + /* Calculate the programming word */ + mhz100 = 100000000 / vclk_per; + mach64MinFreq = MIN_FREQ_2595; + mach64MaxFreq = MAX_FREQ_2595; + mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */ + + /* Calculate program word */ + if (mhz100 == 0) + program_bits = 0xE0; + else { + if (mhz100 < mach64MinFreq) + mhz100 = mach64MinFreq; + if (mhz100 > mach64MaxFreq) + mhz100 = mach64MaxFreq; + + divider = 0; + while (mhz100 < (mach64MinFreq << 3)) { + mhz100 <<= 1; + divider += 0x20; + } + + temp = (unsigned int)(mhz100); + temp = (unsigned int)(temp * (MIN_N_1703 + 2)); + temp -= (short)(mach64RefFreq << 1); + + tempA = MIN_N_1703; + preRemainder = 0xffff; + + do { + tempB = temp; + remainder = tempB % mach64RefFreq; + tempB = tempB / mach64RefFreq; + + if ((tempB & 0xffff) <= 127 && (remainder <= preRemainder)) { + preRemainder = remainder; + divider &= ~0x1f; + divider |= tempA; + divider = (divider & 0x00ff) + ((tempB & 0xff) << 8); + } + + temp += mhz100; + tempA++; + } while (tempA <= (MIN_N_1703 << 1)); + + program_bits = divider; + } + + pll->ics2595.program_bits = program_bits; + pll->ics2595.locationAddr = 0; + pll->ics2595.post_divider = divider; /* fuer nix */ + pll->ics2595.period_in_ps = vclk_per; + + return 0; +} + +static u32 aty_pll_1703_to_var(const struct fb_info_aty *info, + const union aty_pll *pll) +{ + return(pll->ics2595.period_in_ps); /* default for now */ +} + +static void aty_set_pll_1703(const struct fb_info_aty *info, + const union aty_pll *pll) +{ + u32 program_bits; + u32 locationAddr; + + char old_crtc_ext_disp; + + old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info); + aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), + info); + + program_bits = pll->ics2595.program_bits; + locationAddr = pll->ics2595.locationAddr; + + /* Program clock */ + aty_dac_waste4(info); + + (void)aty_ld_8(DAC_REGS + 2, info); + aty_st_8(DAC_REGS+2, (locationAddr << 1) + 0x20, info); + aty_st_8(DAC_REGS+2, 0, info); + aty_st_8(DAC_REGS+2, (program_bits & 0xFF00) >> 8, info); + aty_st_8(DAC_REGS+2, (program_bits & 0xFF), info); + + (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */ + aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info); + + return; +} + +const struct aty_pll_ops aty_pll_stg1703 = { + var_to_pll: aty_var_to_pll_1703, + pll_to_var: aty_pll_1703_to_var, + set_pll: aty_set_pll_1703, +}; + + + /* + * Chrontel 8398 Clock Chip + */ + +static int aty_var_to_pll_8398(const struct fb_info_aty *info, u32 vclk_per, + u8 bpp, union aty_pll *pll) +{ + u32 tempA, tempB, fOut, longMHz100, diff, preDiff; + + u32 mhz100; /* in 0.01 MHz */ + u32 program_bits; + /* u32 post_divider; */ + u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq; + u16 m, n, k=0, save_m, save_n, twoToKth; + + /* Calculate the programming word */ + mhz100 = 100000000 / vclk_per; + mach64MinFreq = MIN_FREQ_2595; + mach64MaxFreq = MAX_FREQ_2595; + mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */ + + save_m = 0; + save_n = 0; + + /* Calculate program word */ + if (mhz100 == 0) + program_bits = 0xE0; + else + { + if (mhz100 < mach64MinFreq) + mhz100 = mach64MinFreq; + if (mhz100 > mach64MaxFreq) + mhz100 = mach64MaxFreq; + + longMHz100 = mhz100 * 256 / 100; /* 8 bit scale this */ + + while (mhz100 < (mach64MinFreq << 3)) + { + mhz100 <<= 1; + k++; + } + + twoToKth = 1 << k; + diff = 0; + preDiff = 0xFFFFFFFF; + + for (m = MIN_M; m <= MAX_M; m++) + { + for (n = MIN_N; n <= MAX_N; n++) + { + tempA = (14.31818 * 65536); + tempA *= (n + 8); /* 43..256 */ + tempB = twoToKth * 256; + tempB *= (m + 2); /* 4..32 */ + fOut = tempA / tempB; /* 8 bit scale */ + + if (longMHz100 > fOut) + diff = longMHz100 - fOut; + else + diff = fOut - longMHz100; + + if (diff < preDiff) + { + save_m = m; + save_n = n; + preDiff = diff; + } + } + } + + program_bits = (k << 6) + (save_m) + (save_n << 8); + } + + pll->ics2595.program_bits = program_bits; + pll->ics2595.locationAddr = 0; + pll->ics2595.post_divider = 0; + pll->ics2595.period_in_ps = vclk_per; + + return 0; +} + +static u32 aty_pll_8398_to_var(const struct fb_info_aty *info, + const union aty_pll *pll) +{ + return(pll->ics2595.period_in_ps); /* default for now */ +} + +static void aty_set_pll_8398(const struct fb_info_aty *info, + const union aty_pll *pll) +{ + u32 program_bits; + u32 locationAddr; + + char old_crtc_ext_disp; + char tmp; + + old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info); + aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), + info); + + program_bits = pll->ics2595.program_bits; + locationAddr = pll->ics2595.locationAddr; + + /* Program clock */ + tmp = aty_ld_8(DAC_CNTL, info); + aty_st_8(DAC_CNTL, tmp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, info); + + aty_st_8(DAC_REGS, locationAddr, info); + aty_st_8(DAC_REGS+1, (program_bits & 0xff00) >> 8, info); + aty_st_8(DAC_REGS+1, (program_bits & 0xff), info); + + tmp = aty_ld_8(DAC_CNTL, info); + aty_st_8(DAC_CNTL, (tmp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3, info); + + (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */ + aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info); + + return; +} + +const struct aty_pll_ops aty_pll_ch8398 = { + var_to_pll: aty_var_to_pll_8398, + pll_to_var: aty_pll_8398_to_var, + set_pll: aty_set_pll_8398, +}; + + + /* + * AT&T 20C408 Clock Chip + */ + +static int aty_var_to_pll_408(const struct fb_info_aty *info, u32 vclk_per, + u8 bpp, union aty_pll *pll) +{ + u32 mhz100; /* in 0.01 MHz */ + u32 program_bits; + /* u32 post_divider; */ + u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq; + u32 temp, tempB; + u16 remainder, preRemainder; + short divider = 0, tempA; + + /* Calculate the programming word */ + mhz100 = 100000000 / vclk_per; + mach64MinFreq = MIN_FREQ_2595; + mach64MaxFreq = MAX_FREQ_2595; + mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */ + + /* Calculate program word */ + if (mhz100 == 0) + program_bits = 0xFF; + else { + if (mhz100 < mach64MinFreq) + mhz100 = mach64MinFreq; + if (mhz100 > mach64MaxFreq) + mhz100 = mach64MaxFreq; + + while (mhz100 < (mach64MinFreq << 3)) { + mhz100 <<= 1; + divider += 0x40; + } + + temp = (unsigned int)mhz100; + temp = (unsigned int)(temp * (MIN_N_408 + 2)); + temp -= ((short)(mach64RefFreq << 1)); + + tempA = MIN_N_408; + preRemainder = 0xFFFF; + + do { + tempB = temp; + remainder = tempB % mach64RefFreq; + tempB = tempB / mach64RefFreq; + if (((tempB & 0xFFFF) <= 255) && (remainder <= preRemainder)) { + preRemainder = remainder; + divider &= ~0x3f; + divider |= tempA; + divider = (divider & 0x00FF) + ((tempB & 0xFF) << 8); + } + temp += mhz100; + tempA++; + } while(tempA <= 32); + + program_bits = divider; + } + + pll->ics2595.program_bits = program_bits; + pll->ics2595.locationAddr = 0; + pll->ics2595.post_divider = divider; /* fuer nix */ + pll->ics2595.period_in_ps = vclk_per; + + return 0; +} + +static u32 aty_pll_408_to_var(const struct fb_info_aty *info, + const union aty_pll *pll) +{ + return(pll->ics2595.period_in_ps); /* default for now */ +} + +static void aty_set_pll_408(const struct fb_info_aty *info, + const union aty_pll *pll) +{ + u32 program_bits; + u32 locationAddr; + + u8 tmpA, tmpB, tmpC; + char old_crtc_ext_disp; + + old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info); + aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), + info); + + program_bits = pll->ics2595.program_bits; + locationAddr = pll->ics2595.locationAddr; + + /* Program clock */ + aty_dac_waste4(info); + tmpB = aty_ld_8(DAC_REGS + 2, info) | 1; + aty_dac_waste4(info); + aty_st_8(DAC_REGS + 2, tmpB, info); + + tmpA = tmpB; + tmpC = tmpA; + tmpA |= 8; + tmpB = 1; + + aty_st_8(DAC_REGS, tmpB, info); + aty_st_8(DAC_REGS + 2, tmpA, info); + + udelay(400); /* delay for 400 us */ + + locationAddr = (locationAddr << 2) + 0x40; + tmpB = locationAddr; + tmpA = program_bits >> 8; + + aty_st_8(DAC_REGS, tmpB, info); + aty_st_8(DAC_REGS + 2, tmpA, info); + + tmpB = locationAddr + 1; + tmpA = (u8)program_bits; + + aty_st_8(DAC_REGS, tmpB, info); + aty_st_8(DAC_REGS + 2, tmpA, info); + + tmpB = locationAddr + 2; + tmpA = 0x77; + + aty_st_8(DAC_REGS, tmpB, info); + aty_st_8(DAC_REGS + 2, tmpA, info); + + udelay(400); /* delay for 400 us */ + tmpA = tmpC & (~(1 | 8)); + tmpB = 1; + + aty_st_8(DAC_REGS, tmpB, info); + aty_st_8(DAC_REGS + 2, tmpA, info); + + (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */ + aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info); + + return; +} + +const struct aty_pll_ops aty_pll_att20c408 = { + var_to_pll: aty_var_to_pll_408, + pll_to_var: aty_pll_408_to_var, + set_pll: aty_set_pll_408, +}; + + + /* + * Unsupported DAC and Clock Chip + */ + +static int aty_set_dac_unsupported(const struct fb_info_aty *info, + const union aty_pll *pll, u32 bpp, + u32 accel) +{ + aty_st_le32(BUS_CNTL, 0x890e20f1, info); + aty_st_le32(DAC_CNTL, 0x47052100, info); + /* new in 2.2.3p1 from Geert. ???????? */ + aty_st_le32(BUS_CNTL, 0x590e10ff, info); + aty_st_le32(DAC_CNTL, 0x47012100, info); + return 0; +} + +static int dummy(void) +{ + return 0; +} + +const struct aty_dac_ops aty_dac_unsupported = { + set_dac: aty_set_dac_unsupported, +}; + +const struct aty_pll_ops aty_pll_unsupported = { + var_to_pll: (void *)dummy, + pll_to_var: (void *)dummy, + set_pll: (void *)dummy, +}; + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/aty.h linux.ac/drivers/video/aty.h --- linux.vanilla/drivers/video/aty.h Sun Sep 17 17:48:04 2000 +++ linux.ac/drivers/video/aty.h Thu Jan 1 01:00:00 1970 @@ -1,1011 +0,0 @@ -/* - * Exported procedures for the ATI/mach64 display driver on PowerMacs. - * - * Copyright (C) 1997 Michael AK Tesch - * written with much help from Jon Howell - * - * Updated for 3D RAGE PRO by Geert Uytterhoeven - * - * 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. - */ - -/* - * most of the rest of this file comes from ATI sample code - */ -#ifndef REGMACH64_H -#define REGMACH64_H - -/* NON-GUI MEMORY MAPPED Registers - expressed in BYTE offsets */ - -#define CRTC_H_TOTAL_DISP 0x0000 /* Dword offset 0_00 */ -#define CRTC_H_SYNC_STRT_WID 0x0004 /* Dword offset 0_01 */ -#define CRTC_H_SYNC_STRT 0x0004 -#define CRTC_H_SYNC_DLY 0x0005 -#define CRTC_H_SYNC_WID 0x0006 - -#define CRTC_V_TOTAL_DISP 0x0008 /* Dword offset 0_02 */ -#define CRTC_V_TOTAL 0x0008 -#define CRTC_V_DISP 0x000A -#define CRTC_V_SYNC_STRT_WID 0x000C /* Dword offset 0_03 */ -#define CRTC_V_SYNC_STRT 0x000C -#define CRTC_V_SYNC_WID 0x000E - -#define CRTC_VLINE_CRNT_VLINE 0x0010 /* Dword offset 0_04 */ -#define CRTC_OFF_PITCH 0x0014 /* Dword offset 0_05 */ -#define CRTC_OFFSET 0x0014 -#define CRTC_PITCH 0x0016 - -#define CRTC_INT_CNTL 0x0018 /* Dword offset 0_06 */ -#define CRTC_GEN_CNTL 0x001C /* Dword offset 0_07 */ -#define CRTC_PIX_WIDTH 0x001D -#define CRTC_FIFO 0x001E -#define CRTC_EXT_DISP 0x001F - -#define DSP_CONFIG 0x0020 /* Dword offset 0_08 */ -#define DSP_ON_OFF 0x0024 /* Dword offset 0_09 */ -#define TIMER_CONFIG 0x0028 /* Dword offset 0_0A */ -#define MEM_BUF_CNTL 0x002C /* Dword offset 0_0B */ -#define MEM_ADDR_CONFIG 0x0034 /* Dword offset 0_0D */ - -#define CRT_TRAP 0x0038 /* Dword offset 0_0E */ - -#define I2C_CNTL_0 0x003C /* Dword offset 0_0F */ - -#define OVR_CLR 0x0040 /* Dword offset 0_10 */ -#define OVR_WID_LEFT_RIGHT 0x0044 /* Dword offset 0_11 */ -#define OVR_WID_TOP_BOTTOM 0x0048 /* Dword offset 0_12 */ - -#define VGA_DSP_CONFIG 0x004C /* Dword offset 0_13 */ -#define VGA_DSP_ON_OFF 0x0050 /* Dword offset 0_14 */ - -#define CUR_CLR0 0x0060 /* Dword offset 0_18 */ -#define CUR_CLR1 0x0064 /* Dword offset 0_19 */ -#define CUR_OFFSET 0x0068 /* Dword offset 0_1A */ -#define CUR_HORZ_VERT_POSN 0x006C /* Dword offset 0_1B */ -#define CUR_HORZ_VERT_OFF 0x0070 /* Dword offset 0_1C */ - -#define CONFIG_PANEL_LG 0x0074 /* Dword offset 0_1D */ - -#define GP_IO 0x0078 /* Dword offset 0_1E */ - -#define HW_DEBUG 0x007C /* Dword offset 0_1F */ - -#define SCRATCH_REG0 0x0080 /* Dword offset 0_20 */ -#define SCRATCH_REG1 0x0084 /* Dword offset 0_21 */ - -#define CLOCK_CNTL 0x0090 /* Dword offset 0_24 */ -#define CLOCK_SEL_CNTL 0x0090 /* Dword offset 0_24 */ - -#define CONFIG_STAT1 0x0094 /* Dword offset 0_25 */ -#define CONFIG_STAT2 0x0098 /* Dword offset 0_26 */ - -#define BUS_CNTL 0x00A0 /* Dword offset 0_28 */ - -#define LCD_INDEX 0x00A4 /* Dword offset 0_29 */ -#define LCD_DATA 0x00A8 /* Dword offset 0_2A */ - -#define EXT_MEM_CNTL 0x00AC /* Dword offset 0_2B */ -#define MEM_CNTL 0x00B0 /* Dword offset 0_2C */ - -#define MEM_VGA_WP_SEL 0x00B4 /* Dword offset 0_2D */ -#define MEM_VGA_RP_SEL 0x00B8 /* Dword offset 0_2E */ - -#define I2C_CNTL_1 0x00BC /* Dword offset 0_2F */ - -#define DAC_REGS 0x00C0 /* Dword offset 0_30 */ -#define DAC_W_INDEX 0x00C0 /* Dword offset 0_30 */ -#define DAC_DATA 0x00C1 /* Dword offset 0_30 */ -#define DAC_MASK 0x00C2 /* Dword offset 0_30 */ -#define DAC_R_INDEX 0x00C3 /* Dword offset 0_30 */ -#define DAC_CNTL 0x00C4 /* Dword offset 0_31 */ - -#define EXT_DAC_REGS 0x00C8 /* Dword offset 0_32 */ - -#define GEN_TEST_CNTL 0x00D0 /* Dword offset 0_34 */ - -#define CUSTOM_MACRO_CNTL 0x00D4 /* Dword offset 0_35 */ -#define LCD_GEN_CNTL_LG 0x00D4 /* Dword offset 0_35 */ - -#define POWER_MANAGEMENT_LG 0x00D8 /* Dword offset 0_36 (LG) */ - -#define CONFIG_CNTL 0x00DC /* Dword offset 0_37 (CT, ET, VT) */ -#define CONFIG_CHIP_ID 0x00E0 /* Dword offset 0_38 */ -#define CONFIG_STAT0 0x00E4 /* Dword offset 0_39 */ -#define CRC_SIG 0x00E8 /* Dword offset 0_3A */ - - -/* GUI MEMORY MAPPED Registers */ - -#define DST_OFF_PITCH 0x0100 /* Dword offset 0_40 */ -#define DST_X 0x0104 /* Dword offset 0_41 */ -#define DST_Y 0x0108 /* Dword offset 0_42 */ -#define DST_Y_X 0x010C /* Dword offset 0_43 */ -#define DST_WIDTH 0x0110 /* Dword offset 0_44 */ -#define DST_HEIGHT 0x0114 /* Dword offset 0_45 */ -#define DST_HEIGHT_WIDTH 0x0118 /* Dword offset 0_46 */ -#define DST_X_WIDTH 0x011C /* Dword offset 0_47 */ -#define DST_BRES_LNTH 0x0120 /* Dword offset 0_48 */ -#define DST_BRES_ERR 0x0124 /* Dword offset 0_49 */ -#define DST_BRES_INC 0x0128 /* Dword offset 0_4A */ -#define DST_BRES_DEC 0x012C /* Dword offset 0_4B */ -#define DST_CNTL 0x0130 /* Dword offset 0_4C */ -#define DST_Y_X__ALIAS__ 0x0134 /* Dword offset 0_4D */ -#define TRAIL_BRES_ERR 0x0138 /* Dword offset 0_4E */ -#define TRAIL_BRES_INC 0x013C /* Dword offset 0_4F */ -#define TRAIL_BRES_DEC 0x0140 /* Dword offset 0_50 */ -#define LEAD_BRES_LNTH 0x0144 /* Dword offset 0_51 */ -#define Z_OFF_PITCH 0x0148 /* Dword offset 0_52 */ -#define Z_CNTL 0x014C /* Dword offset 0_53 */ -#define ALPHA_TST_CNTL 0x0150 /* Dword offset 0_54 */ -#define SECONDARY_STW_EXP 0x0158 /* Dword offset 0_56 */ -#define SECONDARY_S_X_INC 0x015C /* Dword offset 0_57 */ -#define SECONDARY_S_Y_INC 0x0160 /* Dword offset 0_58 */ -#define SECONDARY_S_START 0x0164 /* Dword offset 0_59 */ -#define SECONDARY_W_X_INC 0x0168 /* Dword offset 0_5A */ -#define SECONDARY_W_Y_INC 0x016C /* Dword offset 0_5B */ -#define SECONDARY_W_START 0x0170 /* Dword offset 0_5C */ -#define SECONDARY_T_X_INC 0x0174 /* Dword offset 0_5D */ -#define SECONDARY_T_Y_INC 0x0178 /* Dword offset 0_5E */ -#define SECONDARY_T_START 0x017C /* Dword offset 0_5F */ - -#define SRC_OFF_PITCH 0x0180 /* Dword offset 0_60 */ -#define SRC_X 0x0184 /* Dword offset 0_61 */ -#define SRC_Y 0x0188 /* Dword offset 0_62 */ -#define SRC_Y_X 0x018C /* Dword offset 0_63 */ -#define SRC_WIDTH1 0x0190 /* Dword offset 0_64 */ -#define SRC_HEIGHT1 0x0194 /* Dword offset 0_65 */ -#define SRC_HEIGHT1_WIDTH1 0x0198 /* Dword offset 0_66 */ -#define SRC_X_START 0x019C /* Dword offset 0_67 */ -#define SRC_Y_START 0x01A0 /* Dword offset 0_68 */ -#define SRC_Y_X_START 0x01A4 /* Dword offset 0_69 */ -#define SRC_WIDTH2 0x01A8 /* Dword offset 0_6A */ -#define SRC_HEIGHT2 0x01AC /* Dword offset 0_6B */ -#define SRC_HEIGHT2_WIDTH2 0x01B0 /* Dword offset 0_6C */ -#define SRC_CNTL 0x01B4 /* Dword offset 0_6D */ - -#define SCALE_OFF 0x01C0 /* Dword offset 0_70 */ -#define SECONDARY_SCALE_OFF 0x01C4 /* Dword offset 0_71 */ - -#define TEX_0_OFF 0x01C0 /* Dword offset 0_70 */ -#define TEX_1_OFF 0x01C4 /* Dword offset 0_71 */ -#define TEX_2_OFF 0x01C8 /* Dword offset 0_72 */ -#define TEX_3_OFF 0x01CC /* Dword offset 0_73 */ -#define TEX_4_OFF 0x01D0 /* Dword offset 0_74 */ -#define TEX_5_OFF 0x01D4 /* Dword offset 0_75 */ -#define TEX_6_OFF 0x01D8 /* Dword offset 0_76 */ -#define TEX_7_OFF 0x01DC /* Dword offset 0_77 */ - -#define SCALE_WIDTH 0x01DC /* Dword offset 0_77 */ -#define SCALE_HEIGHT 0x01E0 /* Dword offset 0_78 */ - -#define TEX_8_OFF 0x01E0 /* Dword offset 0_78 */ -#define TEX_9_OFF 0x01E4 /* Dword offset 0_79 */ -#define TEX_10_OFF 0x01E8 /* Dword offset 0_7A */ -#define S_Y_INC 0x01EC /* Dword offset 0_7B */ - -#define SCALE_PITCH 0x01EC /* Dword offset 0_7B */ -#define SCALE_X_INC 0x01F0 /* Dword offset 0_7C */ - -#define RED_X_INC 0x01F0 /* Dword offset 0_7C */ -#define GREEN_X_INC 0x01F4 /* Dword offset 0_7D */ - -#define SCALE_Y_INC 0x01F4 /* Dword offset 0_7D */ -#define SCALE_VACC 0x01F8 /* Dword offset 0_7E */ -#define SCALE_3D_CNTL 0x01FC /* Dword offset 0_7F */ - -#define HOST_DATA0 0x0200 /* Dword offset 0_80 */ -#define HOST_DATA1 0x0204 /* Dword offset 0_81 */ -#define HOST_DATA2 0x0208 /* Dword offset 0_82 */ -#define HOST_DATA3 0x020C /* Dword offset 0_83 */ -#define HOST_DATA4 0x0210 /* Dword offset 0_84 */ -#define HOST_DATA5 0x0214 /* Dword offset 0_85 */ -#define HOST_DATA6 0x0218 /* Dword offset 0_86 */ -#define HOST_DATA7 0x021C /* Dword offset 0_87 */ -#define HOST_DATA8 0x0220 /* Dword offset 0_88 */ -#define HOST_DATA9 0x0224 /* Dword offset 0_89 */ -#define HOST_DATAA 0x0228 /* Dword offset 0_8A */ -#define HOST_DATAB 0x022C /* Dword offset 0_8B */ -#define HOST_DATAC 0x0230 /* Dword offset 0_8C */ -#define HOST_DATAD 0x0234 /* Dword offset 0_8D */ -#define HOST_DATAE 0x0238 /* Dword offset 0_8E */ -#define HOST_DATAF 0x023C /* Dword offset 0_8F */ -#define HOST_CNTL 0x0240 /* Dword offset 0_90 */ - -#define BM_HOSTDATA 0x0244 /* Dword offset 0_91 */ -#define BM_ADDR 0x0248 /* Dword offset 0_92 */ -#define BM_DATA 0x0248 /* Dword offset 0_92 */ -#define BM_GUI_TABLE_CMD 0x024C /* Dword offset 0_93 */ - -#define PAT_REG0 0x0280 /* Dword offset 0_A0 */ -#define PAT_REG1 0x0284 /* Dword offset 0_A1 */ -#define PAT_CNTL 0x0288 /* Dword offset 0_A2 */ - -#define SC_LEFT 0x02A0 /* Dword offset 0_A8 */ -#define SC_RIGHT 0x02A4 /* Dword offset 0_A9 */ -#define SC_LEFT_RIGHT 0x02A8 /* Dword offset 0_AA */ -#define SC_TOP 0x02AC /* Dword offset 0_AB */ -#define SC_BOTTOM 0x02B0 /* Dword offset 0_AC */ -#define SC_TOP_BOTTOM 0x02B4 /* Dword offset 0_AD */ - -#define DP_BKGD_CLR 0x02C0 /* Dword offset 0_B0 */ -#define DP_FOG_CLR 0x02C4 /* Dword offset 0_B1 */ -#define DP_FRGD_CLR 0x02C4 /* Dword offset 0_B1 */ -#define DP_WRITE_MASK 0x02C8 /* Dword offset 0_B2 */ -#define DP_CHAIN_MASK 0x02CC /* Dword offset 0_B3 */ -#define DP_PIX_WIDTH 0x02D0 /* Dword offset 0_B4 */ -#define DP_MIX 0x02D4 /* Dword offset 0_B5 */ -#define DP_SRC 0x02D8 /* Dword offset 0_B6 */ -#define DP_FRGD_CLR_MIX 0x02DC /* Dword offset 0_B7 */ -#define DP_FRGD_BLGD_CLR 0x02E0 /* Dword offset 0_B8 */ - -#define DST_X_Y 0x02E8 /* Dword offset 0_BA */ -#define DST_WIDTH_HEIGHT 0x02EC /* Dword offset 0_BB */ -#define USR_DST_PICTH 0x02F0 /* Dword offset 0_BC */ -#define DP_SET_GUI_ENGINE2 0x02F8 /* Dword offset 0_BE */ -#define DP_SET_GUI_ENGINE 0x02FC /* Dword offset 0_BF */ - -#define CLR_CMP_CLR 0x0300 /* Dword offset 0_C0 */ -#define CLR_CMP_MASK 0x0304 /* Dword offset 0_C1 */ -#define CLR_CMP_CNTL 0x0308 /* Dword offset 0_C2 */ - -#define FIFO_STAT 0x0310 /* Dword offset 0_C4 */ - -#define CONTEXT_MASK 0x0320 /* Dword offset 0_C8 */ -#define CONTEXT_LOAD_CNTL 0x032C /* Dword offset 0_CB */ - -#define GUI_TRAJ_CNTL 0x0330 /* Dword offset 0_CC */ -#define GUI_STAT 0x0338 /* Dword offset 0_CE */ - -#define TEX_PALETTE_INDEX 0x0340 /* Dword offset 0_D0 */ -#define STW_EXP 0x0344 /* Dword offset 0_D1 */ -#define LOG_MAX_INC 0x0348 /* Dword offset 0_D2 */ -#define S_X_INC 0x034C /* Dword offset 0_D3 */ -#define S_Y_INC__ALIAS__ 0x0350 /* Dword offset 0_D4 */ - -#define SCALE_PITCH__ALIAS__ 0x0350 /* Dword offset 0_D4 */ - -#define S_START 0x0354 /* Dword offset 0_D5 */ -#define W_X_INC 0x0358 /* Dword offset 0_D6 */ -#define W_Y_INC 0x035C /* Dword offset 0_D7 */ -#define W_START 0x0360 /* Dword offset 0_D8 */ -#define T_X_INC 0x0364 /* Dword offset 0_D9 */ -#define T_Y_INC 0x0368 /* Dword offset 0_DA */ - -#define SECONDARY_SCALE_PITCH 0x0368 /* Dword offset 0_DA */ - -#define T_START 0x036C /* Dword offset 0_DB */ -#define TEX_SIZE_PITCH 0x0370 /* Dword offset 0_DC */ -#define TEX_CNTL 0x0374 /* Dword offset 0_DD */ -#define SECONDARY_TEX_OFFSET 0x0378 /* Dword offset 0_DE */ -#define TEX_PALETTE 0x037C /* Dword offset 0_DF */ - -#define SCALE_PITCH_BOTH 0x0380 /* Dword offset 0_E0 */ -#define SECONDARY_SCALE_OFF_ACC 0x0384 /* Dword offset 0_E1 */ -#define SCALE_OFF_ACC 0x0388 /* Dword offset 0_E2 */ -#define SCALE_DST_Y_X 0x038C /* Dword offset 0_E3 */ - -#define COMPOSITE_SHADOW_ID 0x0398 /* Dword offset 0_E6 */ - -#define SECONDARY_SCALE_X_INC 0x039C /* Dword offset 0_E7 */ - -#define SPECULAR_RED_X_INC 0x039C /* Dword offset 0_E7 */ -#define SPECULAR_RED_Y_INC 0x03A0 /* Dword offset 0_E8 */ -#define SPECULAR_RED_START 0x03A4 /* Dword offset 0_E9 */ - -#define SECONDARY_SCALE_HACC 0x03A4 /* Dword offset 0_E9 */ - -#define SPECULAR_GREEN_X_INC 0x03A8 /* Dword offset 0_EA */ -#define SPECULAR_GREEN_Y_INC 0x03AC /* Dword offset 0_EB */ -#define SPECULAR_GREEN_START 0x03B0 /* Dword offset 0_EC */ -#define SPECULAR_BLUE_X_INC 0x03B4 /* Dword offset 0_ED */ -#define SPECULAR_BLUE_Y_INC 0x03B8 /* Dword offset 0_EE */ -#define SPECULAR_BLUE_START 0x03BC /* Dword offset 0_EF */ - -#define SCALE_X_INC__ALIAS__ 0x03C0 /* Dword offset 0_F0 */ - -#define RED_X_INC__ALIAS__ 0x03C0 /* Dword offset 0_F0 */ -#define RED_Y_INC 0x03C4 /* Dword offset 0_F1 */ -#define RED_START 0x03C8 /* Dword offset 0_F2 */ - -#define SCALE_HACC 0x03C8 /* Dword offset 0_F2 */ -#define SCALE_Y_INC__ALIAS__ 0x03CC /* Dword offset 0_F3 */ - -#define GREEN_X_INC__ALIAS__ 0x03CC /* Dword offset 0_F3 */ -#define GREEN_Y_INC 0x03D0 /* Dword offset 0_F4 */ - -#define SECONDARY_SCALE_Y_INC 0x03D0 /* Dword offset 0_F4 */ -#define SECONDARY_SCALE_VACC 0x03D4 /* Dword offset 0_F5 */ - -#define GREEN_START 0x03D4 /* Dword offset 0_F5 */ -#define BLUE_X_INC 0x03D8 /* Dword offset 0_F6 */ -#define BLUE_Y_INC 0x03DC /* Dword offset 0_F7 */ -#define BLUE_START 0x03E0 /* Dword offset 0_F8 */ -#define Z_X_INC 0x03E4 /* Dword offset 0_F9 */ -#define Z_Y_INC 0x03E8 /* Dword offset 0_FA */ -#define Z_START 0x03EC /* Dword offset 0_FB */ -#define ALPHA_X_INC 0x03F0 /* Dword offset 0_FC */ -#define FOG_X_INC 0x03F0 /* Dword offset 0_FC */ -#define ALPHA_Y_INC 0x03F4 /* Dword offset 0_FD */ -#define FOG_Y_INC 0x03F4 /* Dword offset 0_FD */ -#define ALPHA_START 0x03F8 /* Dword offset 0_FE */ -#define FOG_START 0x03F8 /* Dword offset 0_FE */ - -#define OVERLAY_Y_X_START 0x0400 /* Dword offset 1_00 */ -#define OVERLAY_Y_X_END 0x0404 /* Dword offset 1_01 */ -#define OVERLAY_VIDEO_KEY_CLR 0x0408 /* Dword offset 1_02 */ -#define OVERLAY_VIDEO_KEY_MSK 0x040C /* Dword offset 1_03 */ -#define OVERLAY_GRAPHICS_KEY_CLR 0x0410 /* Dword offset 1_04 */ -#define OVERLAY_GRAPHICS_KEY_MSK 0x0414 /* Dword offset 1_05 */ -#define OVERLAY_KEY_CNTL 0x0418 /* Dword offset 1_06 */ - -#define OVERLAY_SCALE_INC 0x0420 /* Dword offset 1_08 */ -#define OVERLAY_SCALE_CNTL 0x0424 /* Dword offset 1_09 */ -#define SCALER_HEIGHT_WIDTH 0x0428 /* Dword offset 1_0A */ -#define SCALER_TEST 0x042C /* Dword offset 1_0B */ -#define SCALER_BUF0_OFFSET 0x0434 /* Dword offset 1_0D */ -#define SCALER_BUF1_OFFSET 0x0438 /* Dword offset 1_0E */ -#define SCALE_BUF_PITCH 0x043C /* Dword offset 1_0F */ - -#define CAPTURE_START_END 0x0440 /* Dword offset 1_10 */ -#define CAPTURE_X_WIDTH 0x0444 /* Dword offset 1_11 */ -#define VIDEO_FORMAT 0x0448 /* Dword offset 1_12 */ -#define VBI_START_END 0x044C /* Dword offset 1_13 */ -#define CAPTURE_CONFIG 0x0450 /* Dword offset 1_14 */ -#define TRIG_CNTL 0x0454 /* Dword offset 1_15 */ - -#define OVERLAY_EXCLUSIVE_HORZ 0x0458 /* Dword offset 1_16 */ -#define OVERLAY_EXCLUSIVE_VERT 0x045C /* Dword offset 1_17 */ - -#define VAL_WIDTH 0x0460 /* Dword offset 1_18 */ -#define CAPTURE_DEBUG 0x0464 /* Dword offset 1_19 */ -#define VIDEO_SYNC_TEST 0x0468 /* Dword offset 1_1A */ - -#define SNAPSHOT_VH_COUNTS 0x0470 /* Dword offset 1_1C */ -#define SNAPSHOT_F_COUNT 0x0474 /* Dword offset 1_1D */ -#define N_VIF_COUNT 0x0478 /* Dword offset 1_1E */ -#define SNAPSHOT_VIF_COUNT 0x047C /* Dword offset 1_1F */ - -#define CAPTURE_BUF0_OFFSET 0x0480 /* Dword offset 1_20 */ -#define CAPTURE_BUF1_OFFSET 0x0484 /* Dword offset 1_21 */ -#define CAPTURE_BUF_PITCH 0x0488 /* Dword offset 1_22 */ - -#define MPP_CONFIG 0x04C0 /* Dword offset 1_30 */ -#define MPP_STROBE_SEQ 0x04C4 /* Dword offset 1_31 */ -#define MPP_ADDR 0x04C8 /* Dword offset 1_32 */ -#define MPP_DATA 0x04CC /* Dword offset 1_33 */ -#define TVO_CNTL 0x0500 /* Dword offset 1_40 */ - -#define CRT_HORZ_VERT_LOAD 0x0544 /* Dword offset 1_51 */ - -#define AGP_BASE 0x0548 /* Dword offset 1_52 */ -#define AGP_CNTL 0x054C /* Dword offset 1_53 */ - -#define SCALER_COLOUR_CNTL 0x0550 /* Dword offset 1_54 */ -#define SCALER_H_COEFF0 0x0554 /* Dword offset 1_55 */ -#define SCALER_H_COEFF1 0x0558 /* Dword offset 1_56 */ -#define SCALER_H_COEFF2 0x055C /* Dword offset 1_57 */ -#define SCALER_H_COEFF3 0x0560 /* Dword offset 1_58 */ -#define SCALER_H_COEFF4 0x0564 /* Dword offset 1_59 */ - -#define GUI_CNTL 0x0578 /* Dword offset 1_5E */ - -#define BM_FRAME_BUF_OFFSET 0x0580 /* Dword offset 1_60 */ -#define BM_SYSTEM_MEM_ADDR 0x0584 /* Dword offset 1_61 */ -#define BM_COMMAND 0x0588 /* Dword offset 1_62 */ -#define BM_STATUS 0x058C /* Dword offset 1_63 */ -#define BM_GUI_TABLE 0x05B8 /* Dword offset 1_6E */ -#define BM_SYSTEM_TABLE 0x05BC /* Dword offset 1_6F */ - -#define SCALER_BUF0_OFFSET_U 0x05D4 /* Dword offset 1_75 */ -#define SCALER_BUF0_OFFSET_V 0x05D8 /* Dword offset 1_76 */ -#define SCALER_BUF1_OFFSET_U 0x05DC /* Dword offset 1_77 */ -#define SCALER_BUF1_OFFSET_V 0x05E0 /* Dword offset 1_78 */ - -#define VERTEX_1_S 0x0640 /* Dword offset 1_90 */ -#define VERTEX_1_T 0x0644 /* Dword offset 1_91 */ -#define VERTEX_1_W 0x0648 /* Dword offset 1_92 */ -#define VERTEX_1_SPEC_ARGB 0x064C /* Dword offset 1_93 */ -#define VERTEX_1_Z 0x0650 /* Dword offset 1_94 */ -#define VERTEX_1_ARGB 0x0654 /* Dword offset 1_95 */ -#define VERTEX_1_X_Y 0x0658 /* Dword offset 1_96 */ -#define ONE_OVER_AREA 0x065C /* Dword offset 1_97 */ -#define VERTEX_2_S 0x0660 /* Dword offset 1_98 */ -#define VERTEX_2_T 0x0664 /* Dword offset 1_99 */ -#define VERTEX_2_W 0x0668 /* Dword offset 1_9A */ -#define VERTEX_2_SPEC_ARGB 0x066C /* Dword offset 1_9B */ -#define VERTEX_2_Z 0x0670 /* Dword offset 1_9C */ -#define VERTEX_2_ARGB 0x0674 /* Dword offset 1_9D */ -#define VERTEX_2_X_Y 0x0678 /* Dword offset 1_9E */ -#define ONE_OVER_AREA 0x065C /* Dword offset 1_9F */ -#define VERTEX_3_S 0x0680 /* Dword offset 1_A0 */ -#define VERTEX_3_T 0x0684 /* Dword offset 1_A1 */ -#define VERTEX_3_W 0x0688 /* Dword offset 1_A2 */ -#define VERTEX_3_SPEC_ARGB 0x068C /* Dword offset 1_A3 */ -#define VERTEX_3_Z 0x0690 /* Dword offset 1_A4 */ -#define VERTEX_3_ARGB 0x0694 /* Dword offset 1_A5 */ -#define VERTEX_3_X_Y 0x0698 /* Dword offset 1_A6 */ -#define ONE_OVER_AREA 0x065C /* Dword offset 1_A7 */ -#define VERTEX_1_S 0x0640 /* Dword offset 1_AB */ -#define VERTEX_1_T 0x0644 /* Dword offset 1_AC */ -#define VERTEX_1_W 0x0648 /* Dword offset 1_AD */ -#define VERTEX_2_S 0x0660 /* Dword offset 1_AE */ -#define VERTEX_2_T 0x0664 /* Dword offset 1_AF */ -#define VERTEX_2_W 0x0668 /* Dword offset 1_B0 */ -#define VERTEX_3_SECONDARY_S 0x06C0 /* Dword offset 1_B0 */ -#define VERTEX_3_S 0x0680 /* Dword offset 1_B1 */ -#define VERTEX_3_SECONDARY_T 0x06C4 /* Dword offset 1_B1 */ -#define VERTEX_3_T 0x0684 /* Dword offset 1_B2 */ -#define VERTEX_3_SECONDARY_W 0x06C8 /* Dword offset 1_B2 */ -#define VERTEX_3_W 0x0688 /* Dword offset 1_B3 */ -#define VERTEX_1_SPEC_ARGB 0x064C /* Dword offset 1_B4 */ -#define VERTEX_2_SPEC_ARGB 0x066C /* Dword offset 1_B5 */ -#define VERTEX_3_SPEC_ARGB 0x068C /* Dword offset 1_B6 */ -#define VERTEX_1_Z 0x0650 /* Dword offset 1_B7 */ -#define VERTEX_2_Z 0x0670 /* Dword offset 1_B8 */ -#define VERTEX_3_Z 0x0690 /* Dword offset 1_B9 */ -#define VERTEX_1_ARGB 0x0654 /* Dword offset 1_BA */ -#define VERTEX_2_ARGB 0x0674 /* Dword offset 1_BB */ -#define VERTEX_3_ARGB 0x0694 /* Dword offset 1_BC */ -#define VERTEX_1_X_Y 0x0658 /* Dword offset 1_BD */ -#define VERTEX_2_X_Y 0x0678 /* Dword offset 1_BE */ -#define VERTEX_3_X_Y 0x0698 /* Dword offset 1_BF */ -#define ONE_OVER_AREA_UC 0x0700 /* Dword offset 1_C0 */ -#define SETUP_CNTL 0x0704 /* Dword offset 1_C1 */ -#define VERTEX_1_SECONDARY_S 0x0728 /* Dword offset 1_CA */ -#define VERTEX_1_SECONDARY_T 0x072C /* Dword offset 1_CB */ -#define VERTEX_1_SECONDARY_W 0x0730 /* Dword offset 1_CC */ -#define VERTEX_2_SECONDARY_S 0x0734 /* Dword offset 1_CD */ -#define VERTEX_2_SECONDARY_T 0x0738 /* Dword offset 1_CE */ -#define VERTEX_2_SECONDARY_W 0x073C /* Dword offset 1_CF */ - -#define GTC_3D_RESET_DELAY 3 /* 3D engine reset delay in ms */ - -/* CRTC control values (mostly CRTC_GEN_CNTL) */ - -#define CRTC_H_SYNC_NEG 0x00200000 -#define CRTC_V_SYNC_NEG 0x00200000 - -#define CRTC_DBL_SCAN_EN 0x00000001 -#define CRTC_INTERLACE_EN 0x00000002 -#define CRTC_HSYNC_DIS 0x00000004 -#define CRTC_VSYNC_DIS 0x00000008 -#define CRTC_CSYNC_EN 0x00000010 -#define CRTC_PIX_BY_2_EN 0x00000020 /* unused on RAGE */ -#define CRTC_DISPLAY_DIS 0x00000040 -#define CRTC_VGA_XOVERSCAN 0x00000040 - -#define CRTC_PIX_WIDTH_MASK 0x00000700 -#define CRTC_PIX_WIDTH_4BPP 0x00000100 -#define CRTC_PIX_WIDTH_8BPP 0x00000200 -#define CRTC_PIX_WIDTH_15BPP 0x00000300 -#define CRTC_PIX_WIDTH_16BPP 0x00000400 -#define CRTC_PIX_WIDTH_24BPP 0x00000500 -#define CRTC_PIX_WIDTH_32BPP 0x00000600 - -#define CRTC_BYTE_PIX_ORDER 0x00000800 -#define CRTC_PIX_ORDER_MSN_LSN 0x00000000 -#define CRTC_PIX_ORDER_LSN_MSN 0x00000800 - -#define CRTC_FIFO_LWM 0x000f0000 - -#define VGA_128KAP_PAGING 0x00100000 -#define VFC_SYNC_TRISTATE 0x00200000 -#define CRTC_LOCK_REGS 0x00400000 -#define CRTC_SYNC_TRISTATE 0x00800000 - -#define CRTC_EXT_DISP_EN 0x01000000 -#define CRTC_ENABLE 0x02000000 -#define CRTC_DISP_REQ_ENB 0x04000000 -#define VGA_ATI_LINEAR 0x08000000 -#define CRTC_VSYNC_FALL_EDGE 0x10000000 -#define VGA_TEXT_132 0x20000000 -#define VGA_XCRT_CNT_EN 0x40000000 -#define VGA_CUR_B_TEST 0x80000000 - -#define CRTC_CRNT_VLINE 0x07f00000 -#define CRTC_VBLANK 0x00000001 - - -/* DAC control values */ - -#define DAC_EXT_SEL_RS2 0x01 -#define DAC_EXT_SEL_RS3 0x02 -#define DAC_8BIT_EN 0x00000100 -#define DAC_PIX_DLY_MASK 0x00000600 -#define DAC_PIX_DLY_0NS 0x00000000 -#define DAC_PIX_DLY_2NS 0x00000200 -#define DAC_PIX_DLY_4NS 0x00000400 -#define DAC_BLANK_ADJ_MASK 0x00001800 -#define DAC_BLANK_ADJ_0 0x00000000 -#define DAC_BLANK_ADJ_1 0x00000800 -#define DAC_BLANK_ADJ_2 0x00001000 - - -/* Mix control values */ - -#define MIX_NOT_DST 0x0000 -#define MIX_0 0x0001 -#define MIX_1 0x0002 -#define MIX_DST 0x0003 -#define MIX_NOT_SRC 0x0004 -#define MIX_XOR 0x0005 -#define MIX_XNOR 0x0006 -#define MIX_SRC 0x0007 -#define MIX_NAND 0x0008 -#define MIX_NOT_SRC_OR_DST 0x0009 -#define MIX_SRC_OR_NOT_DST 0x000a -#define MIX_OR 0x000b -#define MIX_AND 0x000c -#define MIX_SRC_AND_NOT_DST 0x000d -#define MIX_NOT_SRC_AND_DST 0x000e -#define MIX_NOR 0x000f - -/* Maximum engine dimensions */ -#define ENGINE_MIN_X 0 -#define ENGINE_MIN_Y 0 -#define ENGINE_MAX_X 4095 -#define ENGINE_MAX_Y 16383 - -/* Mach64 engine bit constants - these are typically ORed together */ - -/* BUS_CNTL register constants */ -#define BUS_FIFO_ERR_ACK 0x00200000 -#define BUS_HOST_ERR_ACK 0x00800000 - -/* GEN_TEST_CNTL register constants */ -#define GEN_OVR_OUTPUT_EN 0x20 -#define HWCURSOR_ENABLE 0x80 -#define GUI_ENGINE_ENABLE 0x100 -#define BLOCK_WRITE_ENABLE 0x200 - -/* DSP_CONFIG register constants */ -#define DSP_XCLKS_PER_QW 0x00003fff -#define DSP_LOOP_LATENCY 0x000f0000 -#define DSP_PRECISION 0x00700000 - -/* DSP_ON_OFF register constants */ -#define DSP_OFF 0x000007ff -#define DSP_ON 0x07ff0000 - -/* CLOCK_CNTL register constants */ -#define CLOCK_SEL 0x0f -#define CLOCK_DIV 0x30 -#define CLOCK_DIV1 0x00 -#define CLOCK_DIV2 0x10 -#define CLOCK_DIV4 0x20 -#define CLOCK_STROBE 0x40 -#define PLL_WR_EN 0x02 - -/* PLL registers */ -#define MPLL_CNTL 0x00 -#define VPLL_CNTL 0x01 -#define PLL_REF_DIV 0x02 -#define PLL_GEN_CNTL 0x03 -#define MCLK_FB_DIV 0x04 -#define PLL_VCLK_CNTL 0x05 -#define VCLK_POST_DIV 0x06 -#define VCLK0_FB_DIV 0x07 -#define VCLK1_FB_DIV 0x08 -#define VCLK2_FB_DIV 0x09 -#define VCLK3_FB_DIV 0x0A -#define PLL_EXT_CNTL 0x0B -#define DLL_CNTL 0x0C -#define VFC_CNTL 0x0D -#define PLL_TEST_CTRL 0x0E -#define PLL_TEST_COUNT 0x0F - -/* Fields in PLL registers */ -#define PLL_PC_GAIN 0x07 -#define PLL_VC_GAIN 0x18 -#define PLL_DUTY_CYC 0xE0 -#define PLL_OVERRIDE 0x01 -#define PLL_MCLK_RST 0x02 -#define OSC_EN 0x04 -#define EXT_CLK_EN 0x08 -#define MCLK_SRC_SEL 0x70 -#define EXT_CLK_CNTL 0x80 -#define VCLK_SRC_SEL 0x03 -#define PLL_VCLK_RST 0x04 -#define VCLK_INVERT 0x08 -#define VCLK0_POST 0x03 -#define VCLK1_POST 0x0C -#define VCLK2_POST 0x30 -#define VCLK3_POST 0xC0 - -/* CONFIG_CNTL register constants */ -#define APERTURE_4M_ENABLE 1 -#define APERTURE_8M_ENABLE 2 -#define VGA_APERTURE_ENABLE 4 - -/* CONFIG_STAT0 register constants (GX, CX) */ -#define CFG_BUS_TYPE 0x00000007 -#define CFG_MEM_TYPE 0x00000038 -#define CFG_INIT_DAC_TYPE 0x00000e00 - -/* CONFIG_STAT0 register constants (CT, ET, VT) */ -#define CFG_MEM_TYPE_xT 0x00000007 - -#define ISA 0 -#define EISA 1 -#define LOCAL_BUS 6 -#define PCI 7 - -/* Memory types for GX, CX */ -#define DRAMx4 0 -#define VRAMx16 1 -#define VRAMx16ssr 2 -#define DRAMx16 3 -#define GraphicsDRAMx16 4 -#define EnhancedVRAMx16 5 -#define EnhancedVRAMx16ssr 6 - -/* Memory types for CT, ET, VT, GT */ -#define DRAM 1 -#define EDO 2 -#define PSEUDO_EDO 3 -#define SDRAM 4 -#define SGRAM 5 -#define WRAM 6 - -#define DAC_INTERNAL 0x00 -#define DAC_IBMRGB514 0x01 -#define DAC_ATI68875 0x02 -#define DAC_TVP3026_A 0x72 -#define DAC_BT476 0x03 -#define DAC_BT481 0x04 -#define DAC_ATT20C491 0x14 -#define DAC_SC15026 0x24 -#define DAC_MU9C1880 0x34 -#define DAC_IMSG174 0x44 -#define DAC_ATI68860_B 0x05 -#define DAC_ATI68860_C 0x15 -#define DAC_TVP3026_B 0x75 -#define DAC_STG1700 0x06 -#define DAC_ATT498 0x16 -#define DAC_STG1702 0x07 -#define DAC_SC15021 0x17 -#define DAC_ATT21C498 0x27 -#define DAC_STG1703 0x37 -#define DAC_CH8398 0x47 -#define DAC_ATT20C408 0x57 - -#define CLK_ATI18818_0 0 -#define CLK_ATI18818_1 1 -#define CLK_STG1703 2 -#define CLK_CH8398 3 -#define CLK_INTERNAL 4 -#define CLK_ATT20C408 5 -#define CLK_IBMRGB514 6 - -/* MEM_CNTL register constants */ -#define MEM_SIZE_ALIAS 0x00000007 -#define MEM_SIZE_512K 0x00000000 -#define MEM_SIZE_1M 0x00000001 -#define MEM_SIZE_2M 0x00000002 -#define MEM_SIZE_4M 0x00000003 -#define MEM_SIZE_6M 0x00000004 -#define MEM_SIZE_8M 0x00000005 -#define MEM_SIZE_ALIAS_GTB 0x0000000F -#define MEM_SIZE_2M_GTB 0x00000003 -#define MEM_SIZE_4M_GTB 0x00000007 -#define MEM_SIZE_6M_GTB 0x00000009 -#define MEM_SIZE_8M_GTB 0x0000000B -#define MEM_BNDRY 0x00030000 -#define MEM_BNDRY_0K 0x00000000 -#define MEM_BNDRY_256K 0x00010000 -#define MEM_BNDRY_512K 0x00020000 -#define MEM_BNDRY_1M 0x00030000 -#define MEM_BNDRY_EN 0x00040000 - -/* ATI PCI constants */ -#define PCI_ATI_VENDOR_ID 0x1002 - - -/* CONFIG_CHIP_ID register constants */ -#define CFG_CHIP_TYPE 0x0000FFFF -#define CFG_CHIP_CLASS 0x00FF0000 -#define CFG_CHIP_REV 0xFF000000 -#define CFG_CHIP_MAJOR 0x07000000 -#define CFG_CHIP_FND_ID 0x38000000 -#define CFG_CHIP_MINOR 0xC0000000 - - -/* Chip IDs read from CONFIG_CHIP_ID */ - -/* mach64GX family */ -#define GX_CHIP_ID 0xD7 /* mach64GX (ATI888GX00) */ -#define CX_CHIP_ID 0x57 /* mach64CX (ATI888CX00) */ - -#define GX_PCI_ID 0x4758 /* mach64GX (ATI888GX00) */ -#define CX_PCI_ID 0x4358 /* mach64CX (ATI888CX00) */ - -/* mach64CT family */ -#define CT_CHIP_ID 0x4354 /* mach64CT (ATI264CT) */ -#define ET_CHIP_ID 0x4554 /* mach64ET (ATI264ET) */ - -/* mach64CT family / mach64VT class */ -#define VT_CHIP_ID 0x5654 /* mach64VT (ATI264VT) */ -#define VU_CHIP_ID 0x5655 /* mach64VTB (ATI264VTB) */ -#define VV_CHIP_ID 0x5656 /* mach64VT4 (ATI264VT4) */ - -/* mach64CT family / mach64GT (3D RAGE) class */ -#define LB_CHIP_ID 0x4c42 /* RAGE LT PRO, AGP */ -#define LD_CHIP_ID 0x4c44 /* RAGE LT PRO */ -#define LG_CHIP_ID 0x4c47 /* RAGE LT */ -#define LI_CHIP_ID 0x4c49 /* RAGE LT PRO */ -#define LP_CHIP_ID 0x4c50 /* RAGE LT PRO */ -#define LT_CHIP_ID 0x4c54 /* RAGE LT */ -#define GT_CHIP_ID 0x4754 /* RAGE (GT) */ -#define GU_CHIP_ID 0x4755 /* RAGE II/II+ (GTB) */ -#define GV_CHIP_ID 0x4756 /* RAGE IIC, PCI */ -#define GW_CHIP_ID 0x4757 /* RAGE IIC, AGP */ -#define GZ_CHIP_ID 0x475a /* RAGE IIC, AGP */ -#define GB_CHIP_ID 0x4742 /* RAGE PRO, BGA, AGP 1x and 2x */ -#define GD_CHIP_ID 0x4744 /* RAGE PRO, BGA, AGP 1x only */ -#define GI_CHIP_ID 0x4749 /* RAGE PRO, BGA, PCI33 only */ -#define GP_CHIP_ID 0x4750 /* RAGE PRO, PQFP, PCI33, full 3D */ -#define GQ_CHIP_ID 0x4751 /* RAGE PRO, PQFP, PCI33, limited 3D */ -#define LM_CHIP_ID 0x4c4d /* RAGE Mobility PCI */ -#define LN_CHIP_ID 0x4c4e /* RAGE Mobility AGP */ - - -/* Mach64 major ASIC revisions */ -#define MACH64_ASIC_NEC_VT_A3 0x08 -#define MACH64_ASIC_NEC_VT_A4 0x48 -#define MACH64_ASIC_SGS_VT_A4 0x40 -#define MACH64_ASIC_SGS_VT_B1S1 0x01 -#define MACH64_ASIC_SGS_GT_B1S1 0x01 -#define MACH64_ASIC_SGS_GT_B1S2 0x41 -#define MACH64_ASIC_UMC_GT_B2U1 0x1a -#define MACH64_ASIC_UMC_GT_B2U2 0x5a -#define MACH64_ASIC_UMC_VT_B2U3 0x9a -#define MACH64_ASIC_UMC_GT_B2U3 0x9a -#define MACH64_ASIC_UMC_R3B_D_P_A1 0x1b -#define MACH64_ASIC_UMC_R3B_D_P_A2 0x5b -#define MACH64_ASIC_UMC_R3B_D_P_A3 0x1c -#define MACH64_ASIC_UMC_R3B_D_P_A4 0x5c - -/* Mach64 foundries */ -#define MACH64_FND_SGS 0 -#define MACH64_FND_NEC 1 -#define MACH64_FND_UMC 3 - -/* Mach64 chip types */ -#define MACH64_UNKNOWN 0 -#define MACH64_GX 1 -#define MACH64_CX 2 -#define MACH64_CT 3 -#define MACH64_ET 4 -#define MACH64_VT 5 -#define MACH64_GT 6 - -/* DST_CNTL register constants */ -#define DST_X_RIGHT_TO_LEFT 0 -#define DST_X_LEFT_TO_RIGHT 1 -#define DST_Y_BOTTOM_TO_TOP 0 -#define DST_Y_TOP_TO_BOTTOM 2 -#define DST_X_MAJOR 0 -#define DST_Y_MAJOR 4 -#define DST_X_TILE 8 -#define DST_Y_TILE 0x10 -#define DST_LAST_PEL 0x20 -#define DST_POLYGON_ENABLE 0x40 -#define DST_24_ROTATION_ENABLE 0x80 - -/* SRC_CNTL register constants */ -#define SRC_PATTERN_ENABLE 1 -#define SRC_ROTATION_ENABLE 2 -#define SRC_LINEAR_ENABLE 4 -#define SRC_BYTE_ALIGN 8 -#define SRC_LINE_X_RIGHT_TO_LEFT 0 -#define SRC_LINE_X_LEFT_TO_RIGHT 0x10 - -/* HOST_CNTL register constants */ -#define HOST_BYTE_ALIGN 1 - -/* GUI_TRAJ_CNTL register constants */ -#define PAT_MONO_8x8_ENABLE 0x01000000 -#define PAT_CLR_4x2_ENABLE 0x02000000 -#define PAT_CLR_8x1_ENABLE 0x04000000 - -/* DP_CHAIN_MASK register constants */ -#define DP_CHAIN_4BPP 0x8888 -#define DP_CHAIN_7BPP 0xD2D2 -#define DP_CHAIN_8BPP 0x8080 -#define DP_CHAIN_8BPP_RGB 0x9292 -#define DP_CHAIN_15BPP 0x4210 -#define DP_CHAIN_16BPP 0x8410 -#define DP_CHAIN_24BPP 0x8080 -#define DP_CHAIN_32BPP 0x8080 - -/* DP_PIX_WIDTH register constants */ -#define DST_1BPP 0 -#define DST_4BPP 1 -#define DST_8BPP 2 -#define DST_15BPP 3 -#define DST_16BPP 4 -#define DST_32BPP 6 -#define SRC_1BPP 0 -#define SRC_4BPP 0x100 -#define SRC_8BPP 0x200 -#define SRC_15BPP 0x300 -#define SRC_16BPP 0x400 -#define SRC_32BPP 0x600 -#define HOST_1BPP 0 -#define HOST_4BPP 0x10000 -#define HOST_8BPP 0x20000 -#define HOST_15BPP 0x30000 -#define HOST_16BPP 0x40000 -#define HOST_32BPP 0x60000 -#define BYTE_ORDER_MSB_TO_LSB 0 -#define BYTE_ORDER_LSB_TO_MSB 0x1000000 - -/* DP_MIX register constants */ -#define BKGD_MIX_NOT_D 0 -#define BKGD_MIX_ZERO 1 -#define BKGD_MIX_ONE 2 -#define BKGD_MIX_D 3 -#define BKGD_MIX_NOT_S 4 -#define BKGD_MIX_D_XOR_S 5 -#define BKGD_MIX_NOT_D_XOR_S 6 -#define BKGD_MIX_S 7 -#define BKGD_MIX_NOT_D_OR_NOT_S 8 -#define BKGD_MIX_D_OR_NOT_S 9 -#define BKGD_MIX_NOT_D_OR_S 10 -#define BKGD_MIX_D_OR_S 11 -#define BKGD_MIX_D_AND_S 12 -#define BKGD_MIX_NOT_D_AND_S 13 -#define BKGD_MIX_D_AND_NOT_S 14 -#define BKGD_MIX_NOT_D_AND_NOT_S 15 -#define BKGD_MIX_D_PLUS_S_DIV2 0x17 -#define FRGD_MIX_NOT_D 0 -#define FRGD_MIX_ZERO 0x10000 -#define FRGD_MIX_ONE 0x20000 -#define FRGD_MIX_D 0x30000 -#define FRGD_MIX_NOT_S 0x40000 -#define FRGD_MIX_D_XOR_S 0x50000 -#define FRGD_MIX_NOT_D_XOR_S 0x60000 -#define FRGD_MIX_S 0x70000 -#define FRGD_MIX_NOT_D_OR_NOT_S 0x80000 -#define FRGD_MIX_D_OR_NOT_S 0x90000 -#define FRGD_MIX_NOT_D_OR_S 0xa0000 -#define FRGD_MIX_D_OR_S 0xb0000 -#define FRGD_MIX_D_AND_S 0xc0000 -#define FRGD_MIX_NOT_D_AND_S 0xd0000 -#define FRGD_MIX_D_AND_NOT_S 0xe0000 -#define FRGD_MIX_NOT_D_AND_NOT_S 0xf0000 -#define FRGD_MIX_D_PLUS_S_DIV2 0x170000 - -/* DP_SRC register constants */ -#define BKGD_SRC_BKGD_CLR 0 -#define BKGD_SRC_FRGD_CLR 1 -#define BKGD_SRC_HOST 2 -#define BKGD_SRC_BLIT 3 -#define BKGD_SRC_PATTERN 4 -#define FRGD_SRC_BKGD_CLR 0 -#define FRGD_SRC_FRGD_CLR 0x100 -#define FRGD_SRC_HOST 0x200 -#define FRGD_SRC_BLIT 0x300 -#define FRGD_SRC_PATTERN 0x400 -#define MONO_SRC_ONE 0 -#define MONO_SRC_PATTERN 0x10000 -#define MONO_SRC_HOST 0x20000 -#define MONO_SRC_BLIT 0x30000 - -/* CLR_CMP_CNTL register constants */ -#define COMPARE_FALSE 0 -#define COMPARE_TRUE 1 -#define COMPARE_NOT_EQUAL 4 -#define COMPARE_EQUAL 5 -#define COMPARE_DESTINATION 0 -#define COMPARE_SOURCE 0x1000000 - -/* FIFO_STAT register constants */ -#define FIFO_ERR 0x80000000 - -/* CONTEXT_LOAD_CNTL constants */ -#define CONTEXT_NO_LOAD 0 -#define CONTEXT_LOAD 0x10000 -#define CONTEXT_LOAD_AND_DO_FILL 0x20000 -#define CONTEXT_LOAD_AND_DO_LINE 0x30000 -#define CONTEXT_EXECUTE 0 -#define CONTEXT_CMD_DISABLE 0x80000000 - -/* GUI_STAT register constants */ -#define ENGINE_IDLE 0 -#define ENGINE_BUSY 1 -#define SCISSOR_LEFT_FLAG 0x10 -#define SCISSOR_RIGHT_FLAG 0x20 -#define SCISSOR_TOP_FLAG 0x40 -#define SCISSOR_BOTTOM_FLAG 0x80 - -/* ATI VGA Extended Regsiters */ -#define sioATIEXT 0x1ce -#define bioATIEXT 0x3ce - -#define ATI2E 0xae -#define ATI32 0xb2 -#define ATI36 0xb6 - -/* VGA Graphics Controller Registers */ -#define VGAGRA 0x3ce -#define GRA06 0x06 - -/* VGA Seququencer Registers */ -#define VGASEQ 0x3c4 -#define SEQ02 0x02 -#define SEQ04 0x04 - -#define MACH64_MAX_X ENGINE_MAX_X -#define MACH64_MAX_Y ENGINE_MAX_Y - -#define INC_X 0x0020 -#define INC_Y 0x0080 - -#define RGB16_555 0x0000 -#define RGB16_565 0x0040 -#define RGB16_655 0x0080 -#define RGB16_664 0x00c0 - -#define POLY_TEXT_TYPE 0x0001 -#define IMAGE_TEXT_TYPE 0x0002 -#define TEXT_TYPE_8_BIT 0x0004 -#define TEXT_TYPE_16_BIT 0x0008 -#define POLY_TEXT_TYPE_8 (POLY_TEXT_TYPE | TEXT_TYPE_8_BIT) -#define IMAGE_TEXT_TYPE_8 (IMAGE_TEXT_TYPE | TEXT_TYPE_8_BIT) -#define POLY_TEXT_TYPE_16 (POLY_TEXT_TYPE | TEXT_TYPE_16_BIT) -#define IMAGE_TEXT_TYPE_16 (IMAGE_TEXT_TYPE | TEXT_TYPE_16_BIT) - -#define MACH64_NUM_CLOCKS 16 -#define MACH64_NUM_FREQS 50 - -/* Power Management register constants (LT & LT Pro) */ -#define PWR_MGT_ON 0x00000001 -#define PWR_MGT_MODE_MASK 0x00000006 -#define AUTO_PWR_UP 0x00000008 -#define USE_F32KHZ 0x00000400 -#define TRISTATE_MEM_EN 0x00000800 -#define SELF_REFRESH 0x00000080 -#define PWR_BLON 0x02000000 -#define STANDBY_NOW 0x10000000 -#define SUSPEND_NOW 0x20000000 -#define PWR_MGT_STATUS_MASK 0xC0000000 -#define PWR_MGT_STATUS_SUSPEND 0x80000000 - -/* PM Mode constants */ -#define PWR_MGT_MODE_PIN 0x00000000 -#define PWR_MGT_MODE_REG 0x00000002 -#define PWR_MGT_MODE_TIMER 0x00000004 -#define PWR_MGT_MODE_PCI 0x00000006 - -/* LCD registers (LT Pro) */ - -/* LCD Index register */ -#define LCD_INDEX_MASK 0x0000003F -#define LCD_DISPLAY_DIS 0x00000100 -#define LCD_SRC_SEL 0x00000200 -#define CRTC2_DISPLAY_DIS 0x00000400 - -/* LCD register indices */ -#define LCD_CONFIG_PANEL 0x00 -#define LCD_GEN_CTRL 0x01 -#define LCD_DSTN_CONTROL 0x02 -#define LCD_HFB_PITCH_ADDR 0x03 -#define LCD_HORZ_STRETCHING 0x04 -#define LCD_VERT_STRETCHING 0x05 -#define LCD_EXT_VERT_STRETCH 0x06 -#define LCD_LT_GIO 0x07 -#define LCD_POWER_MANAGEMENT 0x08 -#define LCD_ZVGPIO 0x09 -#define LCD_MISC_CNTL 0x14 - -/* Values in LCD_MISC_CNTL */ -#define BIAS_MOD_LEVEL_MASK 0x0000ff00 -#define BIAS_MOD_LEVEL_SHIFT 8 -#define BLMOD_EN 0x00010000 -#define BIASMOD_EN 0x00020000 - -#endif /* REGMACH64_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/aty128.h linux.ac/drivers/video/aty128.h --- linux.vanilla/drivers/video/aty128.h Sun Sep 17 17:48:04 2000 +++ linux.ac/drivers/video/aty128.h Tue Apr 3 17:55:08 2001 @@ -267,7 +267,6 @@ #define DAC_MASK 0xFF000000 #define DAC_BLANKING 0x00000004 #define DAC_RANGE_CNTL 0x00000003 -#define DAC_RANGE_CNTL 0x00000003 #define DAC_PALETTE_ACCESS_CNTL 0x00000020 #define DAC_PDWN 0x00008000 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/aty128fb.c linux.ac/drivers/video/aty128fb.c --- linux.vanilla/drivers/video/aty128fb.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/aty128fb.c Tue Apr 3 17:55:08 2001 @@ -7,15 +7,21 @@ * Ani Joshi / Jeff Garzik * - Code cleanup * + * PPC Backlight support by Benjamin Herrenschmidt + * <bh40@calva.net> + * 16bit depth fix by Michel Danzer + * <daenzerm@student.ethz.ch> + * + * Other fixes: + * Andreas Hundt <andi@convergence.de> + * * Based off of Geert's atyfb.c and vfb.c. * * TODO: - * - panning * - monitor sensing (DDC) * - virtual display * - other platform support (only ppc/x86 supported) * - hardware cursor support - * - ioctl()'s * * Please cc: your patches to brad@neruo.com. */ @@ -27,16 +33,10 @@ #include <linux/config.h> +#include <linux/slab.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/tty.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> -#include <linux/delay.h> -#include <linux/interrupt.h> #include <asm/uaccess.h> #include <linux/fb.h> #include <linux/init.h> @@ -67,6 +67,9 @@ #ifdef CONFIG_FB_COMPAT_XPMAC #include <asm/vc_ioctl.h> #endif +#ifdef CONFIG_BOOTX_TEXT +#include <asm/bootx.h> +#endif /* CONFIG_BOOTX_TEXT */ #include <video/fbcon.h> #include <video/fbcon-cfb8.h> @@ -89,9 +92,30 @@ #define DBG(fmt, args...) #endif +#define FIFO_WIDTH 128 +#define FIFO_DEPTH 32 + +#define R128_TIMEOUT 2000000 + +static const char *aty128fb_name = "ATY Rage128"; +static int noaccel __initdata = 0; +static char fontname[40] __initdata = { 0 }; + +#ifdef CONFIG_MTRR +static int mtrr = 1; +#endif + +static char *mode_option __initdata = NULL; + +#ifdef CONFIG_PPC +static int default_vmode __initdata = VMODE_1024_768_60; +static int default_cmode __initdata = CMODE_8; +#endif + + #ifndef CONFIG_PPC /* default mode */ -static struct fb_var_screeninfo default_var __initdata = { +static const struct fb_var_screeninfo default_var __initdata = { /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ 640, 480, 640, 480, 0, 0, 8, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, @@ -102,7 +126,7 @@ #else /* CONFIG_PPC */ /* default to 1024x768 at 75Hz on PPC - this will work * on the iMac, the usual 640x480 @ 60Hz doesn't. */ -static struct fb_var_screeninfo default_var = { +static const struct fb_var_screeninfo default_var __initdata = { /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */ 1024, 768, 1024, 768, 0, 0, 8, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, @@ -111,10 +135,9 @@ }; #endif /* CONFIG_PPC */ -#ifndef MODULE /* default modedb mode */ /* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */ -static struct fb_videomode defaultmode __initdata = { +static const struct fb_videomode defaultmode __initdata = { refresh: 60, xres: 640, yres: 480, @@ -128,13 +151,13 @@ sync: 0, vmode: FB_VMODE_NONINTERLACED }; -#endif /* MODULE */ /* struct to hold chip description information */ struct aty128_chip_info { const char *name; - unsigned short device; - int chip_gen; + const unsigned short device; + const short chip_gen; + const char *bus_type; }; /* Chip generations */ @@ -147,57 +170,31 @@ /* supported Rage128 chipsets */ static const struct aty128_chip_info aty128_pci_probe_list[] __initdata = { - {"Rage128 RE (PCI)", PCI_DEVICE_ID_ATI_RAGE128_RE, rage_128}, - {"Rage128 RF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_RF, rage_128}, - {"Rage128 RK (PCI)", PCI_DEVICE_ID_ATI_RAGE128_RK, rage_128}, - {"Rage128 RL (AGP)", PCI_DEVICE_ID_ATI_RAGE128_RL, rage_128}, - {"Rage128 Pro PF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_PF, rage_128_pro}, - {"Rage128 Pro PR (PCI)", PCI_DEVICE_ID_ATI_RAGE128_PR, rage_128_pro}, - {"Rage Mobility M3 (PCI)", PCI_DEVICE_ID_ATI_RAGE128_LE, rage_M3}, - {"Rage Mobility M3 (AGP)", PCI_DEVICE_ID_ATI_RAGE128_LF, rage_M3}, - {NULL, 0, rage_128} + {"Rage128 RE", PCI_DEVICE_ID_ATI_RAGE128_RE, rage_128, "PCI" }, + {"Rage128 RF", PCI_DEVICE_ID_ATI_RAGE128_RF, rage_128, "AGP" }, + {"Rage128 RK", PCI_DEVICE_ID_ATI_RAGE128_RK, rage_128, "PCI" }, + {"Rage128 RL", PCI_DEVICE_ID_ATI_RAGE128_RL, rage_128, "AGP" }, + {"Rage128 Pro PF", PCI_DEVICE_ID_ATI_RAGE128_PF, rage_128_pro, "AGP" }, + {"Rage128 Pro PR", PCI_DEVICE_ID_ATI_RAGE128_PR, rage_128_pro, "PCI" }, + {"Rage128 Pro TR", PCI_DEVICE_ID_ATI_RAGE128_TR, rage_128_pro, "AGP" }, + {"Rage Mobility M3", PCI_DEVICE_ID_ATI_RAGE128_LE, rage_M3, "PCI" }, + {"Rage Mobility M3", PCI_DEVICE_ID_ATI_RAGE128_LF, rage_M3, "AGP" }, + {NULL, 0, rage_128, NULL } }; -/* packed BIOS settings */ -#ifndef CONFIG_PPC -typedef struct { - u8 clock_chip_type; - u8 struct_size; - u8 accelerator_entry; - u8 VGA_entry; - u16 VGA_table_offset; - u16 POST_table_offset; - u16 XCLK; - u16 MCLK; - u8 num_PLL_blocks; - u8 size_PLL_blocks; - u16 PCLK_ref_freq; - u16 PCLK_ref_divider; - u32 PCLK_min_freq; - u32 PCLK_max_freq; - u16 MCLK_ref_freq; - u16 MCLK_ref_divider; - u32 MCLK_min_freq; - u32 MCLK_max_freq; - u16 XCLK_ref_freq; - u16 XCLK_ref_divider; - u32 XCLK_min_freq; - u32 XCLK_max_freq; -} __attribute__ ((packed)) PLL_BLOCK; -#endif /* !CONFIG_PPC */ /* onboard memory information */ struct aty128_meminfo { - u8 ML; - u8 MB; - u8 Trcd; - u8 Trp; - u8 Twr; - u8 CL; - u8 Tr2w; - u8 LoopLatency; - u8 DspOn; - u8 Rloop; + const u8 ML; + const u8 MB; + const u8 Trcd; + const u8 Trp; + const u8 Twr; + const u8 CL; + const u8 Tr2w; + const u8 LoopLatency; + const u8 DspOn; + const u8 Rloop; const char *name; }; @@ -211,22 +208,6 @@ static const struct aty128_meminfo ddr_sgram = { 4, 4, 3, 3, 2, 3, 1, 16, 31, 16, "64-bit DDR SGRAM" }; -static const char *aty128fb_name = "ATY Rage128"; -static char fontname[40] __initdata = { 0 }; -static int noaccel __initdata = 0; - -#ifndef MODULE -static const char *mode_option __initdata = NULL; -#endif - -#ifdef CONFIG_PPC -static int default_vmode __initdata = VMODE_1024_768_60; -static int default_cmode __initdata = CMODE_8; -#endif - -#ifdef CONFIG_MTRR -static int mtrr = 1; -#endif /* PLL constants */ struct aty128_constants { @@ -235,20 +216,17 @@ u32 ppll_max; u32 ref_divider; u32 xclk; - u32 fifo_width; - u32 fifo_depth; }; struct aty128_crtc { u32 gen_cntl; - u32 ext_cntl; u32 h_total, h_sync_strt_wid; u32 v_total, v_sync_strt_wid; u32 pitch; u32 offset, offset_cntl; u32 xoffset, yoffset; u32 vxres, vyres; - u32 bpp; + u32 depth, bpp; }; struct aty128_pll { @@ -274,10 +252,10 @@ struct fb_info fb_info; struct fb_info_aty128 *next; struct aty128_constants constants; /* PLL and others */ - u32 regbase_phys; /* physical mmio */ + unsigned long regbase_phys; /* physical mmio */ void *regbase; /* remapped mmio */ - u32 frame_buffer_phys; /* physical fb memory */ - u32 frame_buffer; /* remaped framebuffer */ + unsigned long frame_buffer_phys; /* physical fb memory */ + void *frame_buffer; /* remapped fb memory */ u32 vram_size; /* onboard video ram */ int chip_gen; const struct aty128_meminfo *mem; /* onboard mem info */ @@ -306,7 +284,7 @@ int fifo_slots; /* free slots in FIFO (64 max) */ }; -static struct fb_info_aty128 *board_list = NULL; +static struct fb_info_aty128 *board_list; #define round_div(n, d) ((n+(d/2))/d) @@ -364,11 +342,9 @@ static struct fb_info_aty128 *aty128_board_list_add(struct fb_info_aty128 *board_list, struct fb_info_aty128 *new_node); #if !defined(CONFIG_PPC) && !defined(__sparc__) -static void __init aty128_get_pllinfo(struct fb_info_aty128 *info, - char *bios_seg); -static char __init *aty128find_ROM(struct fb_info_aty128 *info); +static int __init aty128_get_pllinfo(struct fb_info_aty128 *info); #endif -static void aty128_timings(struct fb_info_aty128 *info); +static int __init aty128_timings(struct fb_info_aty128 *info); static void aty128_init_engine(const struct aty128fb_par *par, struct fb_info_aty128 *info); static void aty128_reset_engine(const struct fb_info_aty128 *info); @@ -376,7 +352,7 @@ static void do_wait_for_fifo(u16 entries, struct fb_info_aty128 *info); static void wait_for_fifo(u16 entries, struct fb_info_aty128 *info); static void wait_for_idle(struct fb_info_aty128 *info); -static u32 bpp_to_depth(u32 bpp); +static u32 depth_to_dst(u32 depth); #ifdef FBCON_HAS_CFB8 static struct display_switch fbcon_aty128_8; @@ -419,7 +395,7 @@ fb_get_cmap: aty128fb_get_cmap, fb_set_cmap: aty128fb_set_cmap, fb_pan_display: aty128fb_pan_display, - fb_rasterimg: aty128fb_rasterimg, + fb_rasterimg: aty128fb_rasterimg }; #ifdef CONFIG_PMAC_BACKLIGHT @@ -427,8 +403,8 @@ static int aty128_set_backlight_level(int level, void* data); static struct backlight_controller aty128_backlight_controller = { - aty128_set_backlight_enable, - aty128_set_backlight_level + set_enable: aty128_set_backlight_enable, + set_level: aty128_set_backlight_level }; #endif /* CONFIG_PMAC_BACKLIGHT */ @@ -485,10 +461,6 @@ * Functions to read from/write to the pll registers */ -#define aty_ld_pll(pll_index) _aty_ld_pll(pll_index, info) -#define aty_st_pll(pll_index, val) _aty_st_pll(pll_index, val, info) - - static u32 _aty_ld_pll(unsigned int pll_index, const struct fb_info_aty128 *info) @@ -506,6 +478,9 @@ aty_st_le32(CLOCK_CNTL_DATA, val); } +#define aty_ld_pll(pll_index) _aty_ld_pll(pll_index, info) +#define aty_st_pll(pll_index, val) _aty_st_pll(pll_index, val, info) + /* return true when the PLL has completed an atomic update */ static int @@ -574,7 +549,7 @@ int i; for (;;) { - for (i = 0; i < 2000000; i++) { + for (i = 0; i < R128_TIMEOUT; i++) { info->fifo_slots = aty_ld_le32(GUI_STAT) & 0x0fff; if (info->fifo_slots >= entries) return; @@ -592,7 +567,7 @@ do_wait_for_fifo(64, info); for (;;) { - for (i = 0; i < 2000000; i++) { + for (i = 0; i < R128_TIMEOUT; i++) { if (!(aty_ld_le32(GUI_STAT) & (1 << 31))) { aty128_flush_pixel_cache(info); info->blitter_may_be_busy = 0; @@ -624,7 +599,7 @@ tmp |= 0x00ff; aty_st_le32(PC_NGUI_CTLSTAT, tmp); - for (i = 0; i < 2000000; i++) + for (i = 0; i < R128_TIMEOUT; i++) if (!(aty_ld_le32(PC_NGUI_CTLSTAT) & PC_BUSY)) break; } @@ -655,7 +630,7 @@ /* use old pio mode */ aty_st_le32(PM4_BUFFER_CNTL, PM4_BUFFER_CNTL_NONPM4); - DBG("engine reset"); + DBG("engine reset %s", ""); } @@ -674,9 +649,8 @@ aty128_reset_engine(info); pitch_value = par->crtc.pitch; - if (par->crtc.bpp == 24) { - pitch_value = pitch_value * 3; - } + if (par->crtc.bpp == 24) + pitch_value *= 3; wait_for_fifo(4, info); /* setup engine offset registers */ @@ -695,7 +669,7 @@ GMC_SRC_CLIP_DEFAULT | GMC_DST_CLIP_DEFAULT | GMC_BRUSH_SOLIDCOLOR | - (bpp_to_depth(par->crtc.bpp) << 8) | + (depth_to_dst(par->crtc.depth) << 8) | GMC_SRC_DSTCOLOR | GMC_BYTE_ORDER_MSB_TO_LSB | GMC_DP_CONVERSION_TEMP_6500 | @@ -728,17 +702,19 @@ } -/* convert bpp values to their register representation */ +/* convert depth values to their register representation */ static u32 -bpp_to_depth(u32 bpp) +depth_to_dst(u32 depth) { - if (bpp <= 8) + if (depth <= 8) return DST_8BPP; - else if (bpp <= 16) + else if (depth <= 15) return DST_15BPP; - else if (bpp <= 24) + else if (depth == 16) + return DST_16BPP; + else if (depth <= 24) return DST_24BPP; - else if (bpp <= 32) + else if (depth <= 32) return DST_32BPP; return -EINVAL; @@ -762,12 +738,6 @@ aty_st_le32(CRTC_PITCH, crtc->pitch); aty_st_le32(CRTC_OFFSET, crtc->offset); aty_st_le32(CRTC_OFFSET_CNTL, crtc->offset_cntl); - /* Disable ATOMIC updating. Is this the right place? - * -- BenH: Breaks on my G4 - */ -#if 0 - aty_st_le32(PPLL_CNTL, aty_ld_le32(PPLL_CNTL) & ~(0x00030000)); -#endif } @@ -776,13 +746,13 @@ struct aty128_crtc *crtc, const struct fb_info_aty128 *info) { - u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp; + u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp, dst; u32 left, right, upper, lower, hslen, vslen, sync, vmode; u32 h_total, h_disp, h_sync_strt, h_sync_wid, h_sync_pol; u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; u32 depth, bytpp; - u8 hsync_strt_pix[5] = { 0, 0x12, 9, 6, 5 }; - u8 mode_bytpp[7] = { 0, 0, 1, 2, 2, 3, 4 }; + const u8 hsync_strt_pix[5] = { 0, 0x12, 9, 6, 5 }; + const u8 mode_bytpp[7] = { 0, 0, 1, 2, 2, 3, 4 }; /* input */ xres = var->xres; @@ -801,6 +771,11 @@ sync = var->sync; vmode = var->vmode; + if (bpp != 16) + depth = bpp; + else + depth = (var->green.length == 6) ? 16 : 15; + /* check for mode eligibility * accept only non interlaced modes */ if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) @@ -816,17 +791,17 @@ if (vyres < yres + yoffset) vyres = yres + yoffset; - /* convert bpp into ATI register depth */ - depth = bpp_to_depth(bpp); + /* convert depth into ATI register depth */ + dst = depth_to_dst(depth); /* make sure we didn't get an invalid depth */ if (depth == -EINVAL) { - printk(KERN_ERR "aty128fb: Invalid depth\n"); + printk(KERN_ERR "aty128fb: Invalid depth or RGBa\n"); return -EINVAL; } - /* convert depth to bpp */ - bytpp = mode_bytpp[depth]; + /* convert register depth to bytes per pixel */ + bytpp = mode_bytpp[dst]; /* make sure there is enough video ram for the mode */ if ((u32)(vxres * vyres * bytpp) > info->vram_size) { @@ -834,25 +809,25 @@ return -EINVAL; } - h_disp = (xres >> 3) - 1; - h_total = (((xres + right + hslen + left) >> 3) - 1) & 0xFFFFL; + h_disp = (xres / 8) - 1; + h_total = (((xres + right + hslen + left) / 8) - 1) & 0xFFFFL; v_disp = yres - 1; v_total = (yres + upper + vslen + lower - 1) & 0xFFFFL; /* check to make sure h_total and v_total are in range */ - if (((h_total >> 3) - 1) > 0x1ff || (v_total - 1) > 0x7FF) { + if (((h_total / 8) - 1) > 0x1ff || (v_total - 1) > 0x7FF) { printk(KERN_ERR "aty128fb: invalid width ranges\n"); return -EINVAL; } - h_sync_wid = (hslen + 7) >> 3; + h_sync_wid = (hslen + 7) / 8; if (h_sync_wid == 0) h_sync_wid = 1; else if (h_sync_wid > 0x3f) /* 0x3f = max hwidth */ h_sync_wid = 0x3f; - h_sync_strt = h_disp + (right >> 3); + h_sync_strt = h_disp + (right / 8); v_sync_wid = vslen; if (v_sync_wid == 0) @@ -867,7 +842,7 @@ c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0; - crtc->gen_cntl = 0x3000000L | c_sync | (depth << 8); + crtc->gen_cntl = 0x3000000L | c_sync | (dst << 8); crtc->h_total = h_total | (h_disp << 16); crtc->v_total = v_total | (v_disp << 16); @@ -877,7 +852,7 @@ crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid << 16) | (v_sync_pol << 23); - crtc->pitch = vxres >> 3; + crtc->pitch = vxres / 8; crtc->offset = 0; crtc->offset_cntl = 0; @@ -886,6 +861,7 @@ crtc->vyres = vyres; crtc->xoffset = xoffset; crtc->yoffset = yoffset; + crtc->depth = depth; crtc->bpp = bpp; return 0; @@ -893,8 +869,41 @@ static int -aty128_bpp_to_var(int pix_width, struct fb_var_screeninfo *var) +aty128_crtc_to_var(const struct aty128_crtc *crtc, + struct fb_var_screeninfo *var) { + u32 xres, yres, left, right, upper, lower, hslen, vslen, sync; + u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; + u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; + u32 pix_width; + + /* fun with masking */ + h_total = crtc->h_total & 0x1ff; + h_disp = (crtc->h_total >> 16) & 0xff; + h_sync_strt = (crtc->h_sync_strt_wid >> 3) & 0x1ff; + h_sync_dly = crtc->h_sync_strt_wid & 0x7; + h_sync_wid = (crtc->h_sync_strt_wid >> 16) & 0x3f; + h_sync_pol = (crtc->h_sync_strt_wid >> 23) & 0x1; + v_total = crtc->v_total & 0x7ff; + v_disp = (crtc->v_total >> 16) & 0x7ff; + v_sync_strt = crtc->v_sync_strt_wid & 0x7ff; + v_sync_wid = (crtc->v_sync_strt_wid >> 16) & 0x1f; + v_sync_pol = (crtc->v_sync_strt_wid >> 23) & 0x1; + c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0; + pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK; + + /* do conversions */ + xres = (h_disp + 1) * 8; + yres = v_disp + 1; + left = ((h_total - h_sync_strt - h_sync_wid) * 8) - h_sync_dly; + right = ((h_sync_strt - h_disp) * 8) + h_sync_dly; + hslen = h_sync_wid * 8; + upper = v_total - v_sync_strt - v_sync_wid; + lower = v_sync_strt - v_disp; + vslen = v_sync_wid; + sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) | + (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) | + (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0); /* fill in pixel info */ switch (pix_width) { @@ -910,7 +919,6 @@ var->transp.length = 0; break; case CRTC_PIX_WIDTH_15BPP: - case CRTC_PIX_WIDTH_16BPP: var->bits_per_pixel = 16; var->red.offset = 10; var->red.length = 5; @@ -921,6 +929,17 @@ var->transp.offset = 0; var->transp.length = 0; break; + case CRTC_PIX_WIDTH_16BPP: + var->bits_per_pixel = 16; + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; case CRTC_PIX_WIDTH_24BPP: var->bits_per_pixel = 24; var->red.offset = 16; @@ -948,49 +967,6 @@ return -EINVAL; } - return 0; -} - - -static int -aty128_crtc_to_var(const struct aty128_crtc *crtc, - struct fb_var_screeninfo *var) -{ - u32 xres, yres, left, right, upper, lower, hslen, vslen, sync; - u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; - u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; - u32 pix_width; - - /* fun with masking */ - h_total = crtc->h_total & 0x1ff; - h_disp = (crtc->h_total >> 16) & 0xff; - h_sync_strt = (crtc->h_sync_strt_wid >> 3) & 0x1ff; - h_sync_dly = crtc->h_sync_strt_wid & 0x7; - h_sync_wid = (crtc->h_sync_strt_wid >> 16) & 0x3f; - h_sync_pol = (crtc->h_sync_strt_wid >> 23) & 0x1; - v_total = crtc->v_total & 0x7ff; - v_disp = (crtc->v_total >> 16) & 0x7ff; - v_sync_strt = crtc->v_sync_strt_wid & 0x7ff; - v_sync_wid = (crtc->v_sync_strt_wid >> 16) & 0x1f; - v_sync_pol = (crtc->v_sync_strt_wid >> 23) & 0x1; - c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0; - pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK; - - /* do conversions */ - xres = (h_disp + 1) << 3; - yres = v_disp + 1; - left = ((h_total - h_sync_strt - h_sync_wid) << 3) - h_sync_dly; - right = ((h_sync_strt - h_disp) << 3) + h_sync_dly; - hslen = h_sync_wid << 3; - upper = v_total - v_sync_strt - v_sync_wid; - lower = v_sync_strt - v_disp; - vslen = v_sync_wid; - sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) | - (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) | - (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0); - - aty128_bpp_to_var(pix_width, var); - var->xres = xres; var->yres = yres; var->xres_virtual = crtc->vxres; @@ -1014,7 +990,7 @@ { u32 div3; - unsigned char post_conv[] = /* register values for post dividers */ + const unsigned char post_conv[] = /* register values for post dividers */ { 2, 0, 1, 4, 2, 2, 6, 2, 3, 2, 2, 2, 7 }; /* select PPLL_DIV_3 */ @@ -1054,7 +1030,7 @@ const struct fb_info_aty128 *info) { const struct aty128_constants c = info->constants; - unsigned char post_dividers[] = {1,2,4,8,3,6,12}; + const unsigned char post_dividers[] = { 1, 2, 4, 8, 3, 6, 12 }; u32 output_freq; u32 vclk; /* in .01 MHz */ int i; @@ -1092,16 +1068,6 @@ } -static int -aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var, - const struct fb_info_aty128 *info) -{ - var->pixclock = 100000000 / pll->vclk; - - return 0; -} - - static void aty128_set_fifo(const struct aty128_ddafifo *dsp, const struct fb_info_aty128 *info) @@ -1114,21 +1080,18 @@ static int aty128_ddafifo(struct aty128_ddafifo *dsp, const struct aty128_pll *pll, - u32 bpp, + u32 depth, const struct fb_info_aty128 *info) { const struct aty128_meminfo *m = info->mem; u32 xclk = info->constants.xclk; - u32 fifo_width = info->constants.fifo_width; - u32 fifo_depth = info->constants.fifo_depth; s32 x, b, p, ron, roff; - u32 n, d; + u32 n, d, bpp; - /* 15bpp is really 16bpp */ - if (bpp == 15) - bpp = 16; + /* round to a multiple of 8 */ + bpp = (depth + 7) & ~7; - n = xclk * fifo_width; + n = xclk * FIFO_WIDTH; d = pll->vclk * bpp; x = round_div(n, d); @@ -1140,7 +1103,7 @@ m->Tr2w + x; - DBG("x %x\n", x); + DBG("n: %x d: %x x: %x\n", n, d, x); b = 0; while (x) { @@ -1153,7 +1116,7 @@ n <<= (11 - p); x = round_div(n, d); - roff = x * (fifo_depth - 4); + roff = x * (FIFO_DEPTH - 4); if ((ron + m->Rloop) >= roff) { printk(KERN_ERR "aty128fb: Mode out of range!\n"); @@ -1207,9 +1170,9 @@ config = aty_ld_le32(CONFIG_CNTL) & ~3; #if defined(__BIG_ENDIAN) - if (par->crtc.bpp >= 24) + if (par->crtc.bpp == 32) config |= 2; /* make aperture do 32 byte swapping */ - else if (par->crtc.bpp > 8) + else if (par->crtc.bpp == 16) config |= 1; /* make aperture do 16 byte swapping */ #endif @@ -1225,9 +1188,9 @@ int cmode, vmode; display_info.height = ((par->crtc.v_total >> 16) & 0x7ff) + 1; - display_info.width = (((par->crtc.h_total >> 16) & 0xff) + 1) << 3; - display_info.depth = par->crtc.bpp; - display_info.pitch = (par->crtc.vxres * par->crtc.bpp) >> 3; + display_info.width = (((par->crtc.h_total >> 16) & 0xff) + 1) * 8; + display_info.depth = par->crtc.depth; + display_info.pitch = (par->crtc.vxres * par->crtc.depth) / 8; aty128_encode_var(&var, par, info); if (mac_var_to_vmode(&var, &vmode, &cmode)) display_info.mode = 0; @@ -1240,6 +1203,13 @@ display_info.disp_reg_address = info->regbase_phys; } #endif /* CONFIG_FB_COMPAT_XPMAC */ +#ifdef CONFIG_BOOTX_TEXT + bootx_update_display(info->frame_buffer_phys, + (((par->crtc.h_total>>16) & 0xff)+1)*8, + ((par->crtc.v_total>>16) & 0x7ff)+1, + par->crtc.bpp, + par->crtc.vxres*par->crtc.bpp/8); +#endif /* CONFIG_BOOTX_TEXT */ } /* @@ -1258,13 +1228,12 @@ if ((err = aty128_var_to_pll(var->pixclock, &par->pll, info))) return err; - if ((err = aty128_ddafifo(&par->fifo_reg, &par->pll, par->crtc.bpp, info))) + if ((err = aty128_ddafifo(&par->fifo_reg, &par->pll, + par->crtc.depth, info))) return err; - if (var->accel_flags & FB_ACCELF_TEXT) - par->accel_flags = FB_ACCELF_TEXT; - else - par->accel_flags = 0; + par->accel_flags = (var->accel_flags & FB_ACCELF_TEXT) + ? FB_ACCELF_TEXT : 0; return 0; } @@ -1280,8 +1249,7 @@ if ((err = aty128_crtc_to_var(&par->crtc, var))) return err; - if ((err = aty128_pll_to_var(&par->pll, var, info))) - return err; + var->pixclock = 100000000 / par->pll.vclk; var->red.msb_right = 0; var->green.msb_right = 0; @@ -1326,7 +1294,7 @@ struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb; struct aty128fb_par par; struct display *display; - int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel; + int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldgreen, oldaccel; int accel, err; display = (con >= 0) ? &fb_display[con] : fb->disp; @@ -1343,17 +1311,13 @@ switch (var->bits_per_pixel) { case 0 ... 8: - var->bits_per_pixel = 8; - break; + var->bits_per_pixel = 8; break; case 9 ... 16: - var->bits_per_pixel = 16; - break; + var->bits_per_pixel = 16; break; case 17 ... 24: - var->bits_per_pixel = 24; - break; + var->bits_per_pixel = 24; break; case 25 ... 32: - var->bits_per_pixel = 32; - break; + var->bits_per_pixel = 32; break; default: return -EINVAL; } @@ -1363,7 +1327,7 @@ aty128_encode_var(var, &par, info); - if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST) return 0; oldxres = display->var.xres; @@ -1371,11 +1335,16 @@ oldvxres = display->var.xres_virtual; oldvyres = display->var.yres_virtual; oldbpp = display->var.bits_per_pixel; + oldgreen = display->var.green.length; oldaccel = display->var.accel_flags; display->var = *var; + if (oldxres != var->xres || oldyres != var->yres || - oldvxres != var->xres_virtual || oldvyres != var->yres_virtual || - oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) { + oldvxres != var->xres_virtual || + oldvyres != var->yres_virtual || + oldgreen != var->green.length || + oldbpp != var->bits_per_pixel || + oldaccel != var->accel_flags) { struct fb_fix_screeninfo fix; @@ -1393,10 +1362,7 @@ accel = var->accel_flags & FB_ACCELF_TEXT; aty128_set_dispsw(display, info, par.crtc.bpp, accel); - if (accel) - display->scrollmode = SCROLL_YNOMOVE; - else - display->scrollmode = SCROLL_YREDRAW; + display->scrollmode = accel ? SCROLL_YNOMOVE : SCROLL_YREDRAW; if (info->fb_info.changevar) (*info->fb_info.changevar)(con); @@ -1405,9 +1371,10 @@ if (!info->fb_info.display_fg || info->fb_info.display_fg->vc_num == con) aty128_set_par(&par, info); - if (oldbpp != var->bits_per_pixel) { + if (oldbpp != var->bits_per_pixel || oldgreen != var->green.length) { if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) return err; + do_install_cmap(con, &info->fb_info); } @@ -1423,10 +1390,10 @@ #ifdef FBCON_HAS_CFB8 case 8: disp->dispsw = accel ? &fbcon_aty128_8 : &fbcon_cfb8; + disp->dispsw_data = NULL; break; #endif #ifdef FBCON_HAS_CFB16 - case 15: case 16: disp->dispsw = accel ? &fbcon_aty128_16 : &fbcon_cfb16; disp->dispsw_data = info->fbcon_cmap.cfb16; @@ -1459,24 +1426,22 @@ strcpy(fix->id, aty128fb_name); - fix->smem_start = (unsigned long)info->frame_buffer_phys; - fix->mmio_start = (unsigned long)info->regbase_phys; + fix->smem_start = info->frame_buffer_phys; + fix->mmio_start = info->regbase_phys; fix->smem_len = info->vram_size; fix->mmio_len = 0x1fff; fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; - fix->line_length = (par->crtc.vxres * par->crtc.bpp) >> 3; - fix->visual = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR + fix->line_length = (par->crtc.vxres * par->crtc.bpp) / 8; + fix->visual = par->crtc.bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; fix->ywrapstep = 0; fix->xpanstep = 8; fix->ypanstep = 1; fix->accel = FB_ACCEL_ATI_RAGE128; - - return; } @@ -1502,8 +1467,6 @@ /* * Pan or Wrap the Display - * - * Not supported (yet!) */ static int aty128fb_pan_display(struct fb_var_screeninfo *var, int con, @@ -1511,11 +1474,10 @@ { struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb; struct aty128fb_par *par = &info->current_par; - u32 xoffset, yoffset; - u32 offset; + u32 xoffset, yoffset, offset; u32 xres, yres; - xres = (((par->crtc.h_total >> 16) & 0xff) + 1) << 3; + xres = (((par->crtc.h_total >> 16) & 0xff) + 1) * 8; yres = ((par->crtc.v_total >> 16) & 0x7ff) + 1; xoffset = (var->xoffset +7) & ~7; @@ -1527,7 +1489,19 @@ par->crtc.xoffset = xoffset; par->crtc.yoffset = yoffset; - offset = ((yoffset * par->crtc.vxres + xoffset) * par->crtc.bpp) >> 6; + offset = yoffset * par->crtc.vxres + xoffset; + + switch (par->crtc.bpp) { + case 16: offset *= 2; break; + case 24: offset *= 3; break; + case 32: offset *= 4; break; + default: break; + } + + offset &= ~7; /* 3 lower bits are always 0 */ + + if (par->crtc.bpp == 24) + offset += 8 * (offset % 3); /* Must be a multiple of 8 and 3 */ aty_st_le32(CRTC_OFFSET, offset); @@ -1543,20 +1517,26 @@ aty128fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { -#if 1 - fb_copy_cmap(&info->cmap, cmap, kspc ? 0 : 2); -#else - struct fb_info_aty128 fb = (struct fb_info_aty128 *)info; + struct fb_info_aty128 *fb = (struct fb_info_aty128 *)info; if (con == fb->currcon) /* current console? */ return fb_get_cmap(cmap, kspc, aty128_getcolreg, info); else if (fb_display[con].cmap.len) /* non default colormap? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else { - int size = (fb_display[con].var.bits_per_pixel <= 8) ? 256 : 32; + int size; + + switch (fb->current_par.crtc.depth) { + case 8: + size = 256; break; + case 16: + size = 64; break; + default: + size = 32; break; + } + fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2); } -#endif return 0; } @@ -1569,17 +1549,24 @@ aty128fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { - int err; struct fb_info_aty128 *fb = (struct fb_info_aty128 *)info; struct display *disp; + int err; - if (con >= 0) - disp = &fb_display[con]; - else - disp = info->disp; + disp = (con >= 0) ? &fb_display[con] : info->disp; if (!disp->cmap.len) { /* no colormap allocated? */ - int size = (disp->var.bits_per_pixel <= 8) ? 256 : 32; + int size; + + switch (fb->current_par.crtc.depth) { + case 8: + size = 256; break; + case 16: + size = 64; break; + default: + size = 32; break; + } + if ((err = fb_alloc_cmap(&disp->cmap, size, 0))) return err; } @@ -1671,14 +1658,13 @@ */ static int __init -aty128_init(struct fb_info_aty128 *info, const char *name) +aty128_init(struct fb_info_aty128 *info) { + const struct aty128_chip_info *aci = &aty128_pci_probe_list[0]; struct fb_var_screeninfo var; u32 dac; int j, k; u8 chip_rev; - const struct aty128_chip_info *aci = &aty128_pci_probe_list[0]; - char *video_card = "Rage128"; if (!info->vram_size) /* may have already been probed */ info->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF; @@ -1688,32 +1674,26 @@ /* put a name with the face */ while (aci->name && info->pdev->device != aci->device) { aci++; } - video_card = (char *)aci->name; info->chip_gen = aci->chip_gen; - printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev); - - if (info->vram_size % (1024 * 1024) == 0) - printk("%dM %s\n", info->vram_size / (1024*1024), info->mem->name); - else - printk("%dk %s\n", info->vram_size / 1024, info->mem->name); + printk(KERN_INFO "aty128fb: %s (%s) [chip rev 0x%x] %dM %s\n", + aci->name, aci->bus_type, chip_rev, + info->vram_size / (1024 * 1024), + info->mem->name); /* fill in info */ strcpy(info->fb_info.modename, aty128fb_name); + strcpy(info->fb_info.fontname, fontname); info->fb_info.node = -1; info->fb_info.fbops = &aty128fb_ops; info->fb_info.disp = &info->disp; - strcpy(info->fb_info.fontname, fontname); info->fb_info.changevar = NULL; info->fb_info.switch_con = &aty128fbcon_switch; info->fb_info.updatevar = NULL; info->fb_info.blank = &aty128fbcon_blank; info->fb_info.flags = FBINFO_FLAG_DEFAULT; -#ifdef MODULE - var = default_var; -#else - memset(&var, 0, sizeof(var)); + memset(&var, 0, sizeof(struct fb_var_screeninfo)); #ifdef CONFIG_PPC if (_machine == _MACH_Pmac) { if (mode_option) { @@ -1723,6 +1703,28 @@ if (default_vmode <= 0 || default_vmode > VMODE_MAX) default_vmode = VMODE_1024_768_60; + /* iMacs need that resolution + * PowerMac2,1 first r128 iMacs + * PowerMac2,2 summer 2000 iMacs + * PowerMac4,1 januar 2001 iMacs "flower power" + */ + if (machine_is_compatible("PowerMac2,1") || + machine_is_compatible("PowerMac2,2") || + machine_is_compatible("PowerMac4,1")) + default_vmode = VMODE_1024_768_75; + + /* PowerBook Firewire (Pismo) */ + if (machine_is_compatible("PowerBook3,1")) + default_vmode = VMODE_1024_768_60; + + /* PowerBook Titanium */ + if (machine_is_compatible("PowerBook3,2")) + default_vmode = VMODE_1152_768_60; + + /* iBook Firewire */ + if (machine_is_compatible("PowerBook2,2")) + default_vmode = VMODE_800_600_60; + if (default_cmode < CMODE_8 || default_cmode > CMODE_32) default_cmode = CMODE_8; @@ -1732,11 +1734,15 @@ } else #endif /* CONFIG_PPC */ { - if (fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, - &defaultmode, 8) == 0) + int retval; + + retval = fb_find_mode(&var, &info->fb_info, mode_option, + NULL, 0, &defaultmode, 8); + + if (!retval || (retval == 4)) + /* Should not get here */ var = default_var; } -#endif /* MODULE */ if (noaccel) var.accel_flags &= ~FB_ACCELF_TEXT; @@ -1776,11 +1782,13 @@ #ifdef CONFIG_PMAC_BACKLIGHT /* Could be extended to Rage128Pro LVDS output too */ if (info->chip_gen == rage_M3) - register_backlight_controller(&aty128_backlight_controller, info, "ati"); -#endif /* CONFIG_PMAC_BACKLIGHT */ + register_backlight_controller(&aty128_backlight_controller, + info, "ati"); +#endif printk(KERN_INFO "fb%d: %s frame buffer device on %s\n", - GET_FB_IDX(info->fb_info.node), aty128fb_name, name); + GET_FB_IDX(info->fb_info.node), aty128fb_name, + aci->bus_type); return 1; /* success! */ } @@ -1835,9 +1843,6 @@ struct fb_info_aty128 *info = NULL; u32 fb_addr, reg_addr; int err; -#if !defined(CONFIG_PPC) && !defined(__sparc__) - char *bios_seg = NULL; -#endif /* Enable device in PCI config */ if ((err = pci_enable_device(pdev))) { @@ -1885,12 +1890,10 @@ /* Virtualize the framebuffer */ info->frame_buffer_phys = fb_addr; - info->frame_buffer = (u32)ioremap(fb_addr, info->vram_size); + info->frame_buffer = ioremap(fb_addr, info->vram_size); - if (!info->frame_buffer) { - iounmap((void *)info->regbase); - goto err_free_info; - } + if (!info->frame_buffer) + goto err_free_base; /* If we can't test scratch registers, something is seriously wrong */ if (!register_test(info)) { @@ -1899,18 +1902,13 @@ } #if !defined(CONFIG_PPC) && !defined(__sparc__) - if (!(bios_seg = aty128find_ROM(info))) + if (!aty128_get_pllinfo(info)) printk(KERN_INFO "aty128fb: Rage128 BIOS not located. " "Guessing...\n"); - else { - printk(KERN_INFO "aty128fb: Rage128 BIOS located at " - "segment %4.4X\n", (unsigned int)bios_seg); - aty128_get_pllinfo(info, bios_seg); - } #endif - aty128_timings(info); - - if (!aty128_init(info, "PCI")) + if (!aty128_timings(info)) + goto err_out; + if (!aty128_init(info)) goto err_out; #ifdef CONFIG_MTRR @@ -1932,6 +1930,7 @@ err_out: iounmap((void *)info->frame_buffer); +err_free_base: iounmap((void *)info->regbase); err_free_info: kfree(info); @@ -1951,102 +1950,54 @@ /* PPC and Sparc cannot read video ROM */ #if !defined(CONFIG_PPC) && !defined(__sparc__) -static char __init -*aty128find_ROM(struct fb_info_aty128 *info) +static int __init +aty128_get_pllinfo(struct fb_info_aty128 *info) { u32 segstart; char *rom_base; - char *rom; - int stage; - int i; - char aty_rom_sig[] = "761295520"; /* ATI ROM Signature */ - char R128_sig[] = "R128"; /* Rage128 ROM identifier */ + /* Search for video BIOS segment */ for (segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) { - stage = 1; rom_base = (char *)ioremap(segstart, 0x1000); - if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa)) - stage = 2; + if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa)) { + /* Video BIOS segment found */ + void *bios_header; + void *header_ptr; + + bios_header = rom_base + readw(rom_base + 0x48L); + bios_header += 0x30; + + header_ptr = rom_base + readw(bios_header); + + info->constants.ppll_max = readl(header_ptr + 0x16); + info->constants.ppll_min = readl(header_ptr + 0x12); + info->constants.xclk = readw(header_ptr + 0x08); + info->constants.ref_divider = readw(header_ptr + 0x10); + info->constants.dotclock = readw(header_ptr + 0x0e); - if (stage != 2) { iounmap(rom_base); - continue; - } - rom = rom_base; - for (i = 0; (i < 128 - strlen(aty_rom_sig)) && (stage != 3); i++) { - if (aty_rom_sig[0] == *rom) - if (strncmp(aty_rom_sig, rom, - strlen(aty_rom_sig)) == 0) - stage = 3; - rom++; - } - if (stage != 3) { - iounmap(rom_base); - continue; - } - rom = rom_base; + DBG("ppll_max %d ppll_min %d xclk %d " + "ref_divider %d dotclock %d\n", + info->constants.ppll_max, + info->constants.ppll_min, + info->constants.xclk, + info->constants.ref_divider, + info->constants.dotclock); - /* ATI signature found. Let's see if it's a Rage128 */ - for (i = 0; (i < 512) && (stage != 4); i++) { - if (R128_sig[0] == *rom) - if (strncmp(R128_sig, rom, - strlen(R128_sig)) == 0) - stage = 4; - rom++; + return 1; } - if (stage != 4) { - iounmap(rom_base); - continue; - } - - return rom_base; + iounmap(rom_base); } - - return NULL; -} - - -static void __init -aty128_get_pllinfo(struct fb_info_aty128 *info, char *bios_seg) -{ - void *bios_header; - void *header_ptr; - u16 bios_header_offset, pll_info_offset; - PLL_BLOCK pll; - - bios_header = bios_seg + 0x48L; - header_ptr = bios_header; - - bios_header_offset = readw(header_ptr); - bios_header = bios_seg + bios_header_offset; - bios_header += 0x30; - - header_ptr = bios_header; - pll_info_offset = readw(header_ptr); - header_ptr = bios_seg + pll_info_offset; - - memcpy_fromio(&pll, header_ptr, 50); - - info->constants.ppll_max = pll.PCLK_max_freq; - info->constants.ppll_min = pll.PCLK_min_freq; - info->constants.xclk = (u32)pll.XCLK; - info->constants.ref_divider = (u32)pll.PCLK_ref_divider; - info->constants.dotclock = (u32)pll.PCLK_ref_freq; - - DBG("ppll_max %d ppll_min %d xclk %d ref_divider %d dotclock %d\n", - info->constants.ppll_max, info->constants.ppll_min, - info->constants.xclk, info->constants.ref_divider, - info->constants.dotclock); - + return 0; } #endif /* !CONFIG_PPC */ -/* fill in known card constants if pll_block is not available */ -static void __init +/* fill in known card constants if BIOS pll_block is not available */ +static int __init aty128_timings(struct fb_info_aty128 *info) { #ifdef CONFIG_PPC @@ -2057,9 +2008,10 @@ u32 x_mpll_ref_fb_div; u32 xclk_cntl; u32 Nx, M; - unsigned PostDivSet[] = + const unsigned PostDivSet[] = { 0, 1, 2, 4, 8, 3, 6, 12 }; #endif + int mem_cntl; if (!info->constants.dotclock) info->constants.dotclock = 2950; @@ -2094,10 +2046,8 @@ if (!info->constants.xclk) info->constants.xclk = 0x1d4d; /* same as mclk */ - info->constants.fifo_width = 128; - info->constants.fifo_depth = 32; - - switch (aty_ld_le32(MEM_CNTL) & 0x3) { + mem_cntl = aty_ld_le32(MEM_CNTL) & 0x3; + switch (mem_cntl) { case 0: info->mem = &sdr_128; break; @@ -2108,8 +2058,12 @@ info->mem = &ddr_sgram; break; default: - info->mem = &sdr_sgram; + printk(KERN_ERR "aty128fb: unknown memory config: %d." + " Aborting...\n", mem_cntl); + return -EINVAL; } + + return 1; } @@ -2124,6 +2078,16 @@ fb_get_cmap(&fb_display[info->currcon].cmap, 1, aty128_getcolreg, fb); + /* Return if the mode is the same to switching avoid flicker */ + if (!memcmp(&fb_display[con].var, &fb_display[info->currcon].var, + sizeof(struct fb_var_screeninfo))) { + + /* set the current console */ + info->currcon = con; + + return 1; + } + /* set the current console */ info->currcon = con; @@ -2201,6 +2165,7 @@ { struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb; u32 col; + u_int palreg; if (regno > 255) return 1; @@ -2221,18 +2186,20 @@ int i; if (info->chip_gen == rage_M3) - aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL); + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & + ~DAC_PALETTE_ACCESS_CNTL); - for (i=16; i<256; i++) { + for (i = 0; i < 256; i++) { aty_st_8(PALETTE_INDEX, i); col = (i << 16) | (i << 8) | i; aty_st_le32(PALETTE_DATA, col); } if (info->chip_gen == rage_M3) { - aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL); + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | + DAC_PALETTE_ACCESS_CNTL); - for (i=16; i<256; i++) { + for (i = 0; i < 256; i++) { aty_st_8(PALETTE_INDEX, i); col = (i << 16) | (i << 8) | i; aty_st_le32(PALETTE_DATA, col); @@ -2241,37 +2208,51 @@ } /* initialize palette */ - if (info->chip_gen == rage_M3) - aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL); + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & + ~DAC_PALETTE_ACCESS_CNTL); - if (info->current_par.crtc.bpp == 16) - aty_st_8(PALETTE_INDEX, (regno << 3)); - else - aty_st_8(PALETTE_INDEX, regno); + if (info->current_par.crtc.bpp == 16) { + palreg = regno << 3; + + if (info->current_par.crtc.depth == 16 && regno >= 32) { + palreg -= 252; + col = (info->palette[regno >> 1].red << 16) | + (green << 8) | + info->palette[regno >> 1].blue; + } else col = (red << 16) | (green << 8) | blue; + } else { + palreg = regno; + col = (red << 16) | (green << 8) | blue; + } + + aty_st_8(PALETTE_INDEX, palreg); aty_st_le32(PALETTE_DATA, col); + if (info->chip_gen == rage_M3) { - aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL); - if (info->current_par.crtc.bpp == 16) - aty_st_8(PALETTE_INDEX, (regno << 3)); - else - aty_st_8(PALETTE_INDEX, regno); + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | + DAC_PALETTE_ACCESS_CNTL); + aty_st_8(PALETTE_INDEX, palreg); aty_st_le32(PALETTE_DATA, col); } - if (regno < 16) - switch (info->current_par.crtc.bpp) { + if (regno < 32) + switch (info->current_par.crtc.depth) { #ifdef FBCON_HAS_CFB16 - case 9 ... 16: - info->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | - regno; + case 9 ... 15: + info->fbcon_cmap.cfb16[regno] = (regno << 10) | + (regno << 5) | regno; + break; + case 16: + info->fbcon_cmap.cfb16[regno] = (regno << 11) | + (regno << 6) | regno; break; #endif #ifdef FBCON_HAS_CFB24 case 17 ... 24: - info->fbcon_cmap.cfb24[regno] = (regno << 16) | (regno << 8) | - regno; + info->fbcon_cmap.cfb24[regno] = (regno << 16) | + (regno << 8) | regno; break; #endif #ifdef FBCON_HAS_CFB32 @@ -2299,14 +2280,14 @@ if (fb_display[con].cmap.len) fb_set_cmap(&fb_display[con].cmap, 1, aty128_setcolreg, info); else { - int size = (fb_display[con].var.bits_per_pixel <= 8) ? 256 : 16; + int size = (fb_display[con].var.bits_per_pixel <= 8) ? 256 : 32; fb_set_cmap(fb_default_cmap(size), 1, aty128_setcolreg, info); } } #ifdef CONFIG_PMAC_BACKLIGHT -static int backlight_conv[] = { +static const int backlight_conv[] = { 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e, 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24 }; @@ -2346,18 +2327,18 @@ u_int width, u_int height, struct fb_info_aty128 *info) { - u32 save_dp_datatype, save_dp_cntl, bppval; + u32 save_dp_datatype, save_dp_cntl, dstval; if (!width || !height) return; - bppval = bpp_to_depth(info->current_par.crtc.bpp); - if (bppval == DST_24BPP) { + dstval = depth_to_dst(info->current_par.crtc.depth); + if (dstval == DST_24BPP) { srcx *= 3; dstx *= 3; width *= 3; - } else if (bppval == -EINVAL) { - printk("aty128fb: invalid depth\n"); + } else if (dstval == -EINVAL) { + printk("aty128fb: invalid depth or RGBa\n"); return; } @@ -2369,7 +2350,7 @@ aty_st_le32(SRC_Y_X, (srcy << 16) | srcx); aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT); aty_st_le32(DP_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM); - aty_st_le32(DP_DATATYPE, save_dp_datatype | bppval | SRC_DSTCOLOR); + aty_st_le32(DP_DATATYPE, save_dp_datatype | dstval | SRC_DSTCOLOR); aty_st_le32(DST_Y_X, (dsty << 16) | dstx); aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width); @@ -2596,7 +2577,7 @@ #endif #ifdef MODULE -MODULE_AUTHOR("(c)1999-2000 Brad Douglas <brad@neruo.com>"); +MODULE_AUTHOR("(c)1999-2001 Brad Douglas <brad@neruo.com>"); MODULE_DESCRIPTION("FBDev driver for ATI Rage128 / Pro cards"); int __init diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/atyfb.c linux.ac/drivers/video/atyfb.c --- linux.vanilla/drivers/video/atyfb.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/atyfb.c Thu Jan 1 01:00:00 1970 @@ -1,5081 +0,0 @@ -/* $Id: atyfb.c,v 1.147 2000/08/29 07:01:56 davem Exp $ - * linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64 - * - * Copyright (C) 1997-1998 Geert Uytterhoeven - * Copyright (C) 1998 Bernd Harries - * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) - * - * This driver is partly based on the PowerMac console driver: - * - * Copyright (C) 1996 Paul Mackerras - * - * and on the PowerMac ATI/mach64 display driver: - * - * Copyright (C) 1997 Michael AK Tesch - * - * with work by Jon Howell - * Harry AC Eaton - * Anthony Tong <atong@uiuc.edu> - * - * 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. - * - * Many thanks to Nitya from ATI devrel for support and patience ! - */ - -/****************************************************************************** - - TODO: - - - cursor support on all cards and all ramdacs. - - cursor parameters controlable via ioctl()s. - - guess PLL and MCLK based on the original PLL register values initialized - by the BIOS or Open Firmware (if they are initialized). - - (Anyone to help with this?) - -******************************************************************************/ - - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/tty.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/fb.h> -#include <linux/selection.h> -#include <linux/console.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/kd.h> -#include <linux/vt_kern.h> - -#ifdef CONFIG_FB_COMPAT_XPMAC -#include <asm/vc_ioctl.h> -#endif - -#include <asm/io.h> - -#ifdef __powerpc__ -#include <linux/adb.h> -#include <asm/prom.h> -#include <asm/pci-bridge.h> -#include <video/macmodes.h> -#endif -#ifdef CONFIG_ADB_PMU -#include <linux/pmu.h> -#endif -#ifdef CONFIG_NVRAM -#include <linux/nvram.h> -#endif -#ifdef CONFIG_PMAC_BACKLIGHT -#include <asm/backlight.h> -#endif - -#ifdef __sparc__ -#include <asm/pbm.h> -#include <asm/fbio.h> -#endif -#include <asm/uaccess.h> - -#include <video/fbcon.h> -#include <video/fbcon-cfb8.h> -#include <video/fbcon-cfb16.h> -#include <video/fbcon-cfb24.h> -#include <video/fbcon-cfb32.h> - -#include "aty.h" - - -/* - * Debug flags. - */ -#undef DEBUG - -/* Definitions for the ICS 2595 == ATI 18818_1 Clockchip */ - -#define REF_FREQ_2595 1432 /* 14.33 MHz (exact 14.31818) */ -#define REF_DIV_2595 46 /* really 43 on ICS 2595 !!! */ - /* ohne Prescaler */ -#define MAX_FREQ_2595 15938 /* 159.38 MHz (really 170.486) */ -#define MIN_FREQ_2595 8000 /* 80.00 MHz ( 85.565) */ - /* mit Prescaler 2, 4, 8 */ -#define ABS_MIN_FREQ_2595 1000 /* 10.00 MHz (really 10.697) */ -#define N_ADJ_2595 257 - -#define STOP_BITS_2595 0x1800 - - -#define MIN_N_408 2 - -#define MIN_N_1703 6 - -#define MIN_M 2 -#define MAX_M 30 -#define MIN_N 35 -#define MAX_N 255-8 - - -/* Make sure n * PAGE_SIZE is protected at end of Aperture for GUI-regs */ -/* - must be large enough to catch all GUI-Regs */ -/* - must be aligned to a PAGE boundary */ -#define GUI_RESERVE (1 * PAGE_SIZE) - - -/* FIXME: remove the FAIL definition */ -#define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0) - - - /* - * Elements of the Hardware specific atyfb_par structure - */ - -struct crtc { - u32 vxres; - u32 vyres; - u32 xoffset; - u32 yoffset; - u32 bpp; - u32 h_tot_disp; - u32 h_sync_strt_wid; - u32 v_tot_disp; - u32 v_sync_strt_wid; - u32 off_pitch; - u32 gen_cntl; - u32 dp_pix_width; /* acceleration */ - u32 dp_chain_mask; /* acceleration */ -}; - -struct pll_gx { - u8 m; - u8 n; -}; - -struct pll_18818 -{ - u32 program_bits; - u32 locationAddr; - u32 period_in_ps; - u32 post_divider; -}; - -struct pll_ct { - u8 pll_ref_div; - u8 pll_gen_cntl; - u8 mclk_fb_div; - u8 pll_vclk_cntl; - u8 vclk_post_div; - u8 vclk_fb_div; - u8 pll_ext_cntl; - u32 dsp_config; /* Mach64 GTB DSP */ - u32 dsp_on_off; /* Mach64 GTB DSP */ - u8 mclk_post_div_real; - u8 vclk_post_div_real; -}; - - - /* - * The Hardware parameters for each card - */ - -struct atyfb_par { - struct crtc crtc; - union { - struct pll_gx gx; - struct pll_ct ct; - struct pll_18818 ics2595; - } pll; - u32 accel_flags; -}; - -struct aty_cmap_regs { - u8 windex; - u8 lut; - u8 mask; - u8 rindex; - u8 cntl; -}; - -struct pci_mmap_map { - unsigned long voff; - unsigned long poff; - unsigned long size; - unsigned long prot_flag; - unsigned long prot_mask; -}; - -#define DEFAULT_CURSOR_BLINK_RATE (20) -#define CURSOR_DRAW_DELAY (2) - -struct aty_cursor { - int enable; - int on; - int vbl_cnt; - int blink_rate; - u32 offset; - struct { - u16 x, y; - } pos, hot, size; - u32 color[2]; - u8 bits[8][64]; - u8 mask[8][64]; - u8 *ram; - struct timer_list *timer; -}; - -struct fb_info_aty { - struct fb_info fb_info; - struct fb_info_aty *next; - unsigned long ati_regbase_phys; - unsigned long ati_regbase; - unsigned long frame_buffer_phys; - unsigned long frame_buffer; - unsigned long clk_wr_offset; - struct pci_mmap_map *mmap_map; - struct aty_cursor *cursor; - struct aty_cmap_regs *aty_cmap_regs; - struct { u8 red, green, blue, pad; } palette[256]; - struct atyfb_par default_par; - struct atyfb_par current_par; - u32 total_vram; - u32 ref_clk_per; - u32 pll_per; - u32 mclk_per; - u16 chip_type; -#define Gx info->chip_type - u8 chip_rev; -#define Rev info->chip_rev - u8 bus_type; - u8 ram_type; - u8 dac_type; - u8 dac_subtype; - u8 clk_type; - u8 mem_refresh_rate; - struct display disp; - struct display_switch dispsw; - union { -#ifdef FBCON_HAS_CFB16 - u16 cfb16[16]; -#endif -#ifdef FBCON_HAS_CFB24 - u32 cfb24[16]; -#endif -#ifdef FBCON_HAS_CFB32 - u32 cfb32[16]; -#endif - } fbcon_cmap; - u8 blitter_may_be_busy; -#ifdef __sparc__ - u8 mmaped; - int open; - int vtconsole; - int consolecnt; -#endif -#ifdef CONFIG_PMAC_PBOOK - unsigned char *save_framebuffer; - unsigned long save_pll[64]; -#endif -}; - -#ifdef CONFIG_PMAC_PBOOK - int aty_sleep_notify(struct pmu_sleep_notifier *self, int when); - static struct pmu_sleep_notifier aty_sleep_notifier = { - aty_sleep_notify, SLEEP_LEVEL_VIDEO, - }; - static struct fb_info_aty* first_display = NULL; -#endif - -#ifdef CONFIG_PMAC_BACKLIGHT -static int aty_set_backlight_enable(int on, int level, void* data); -static int aty_set_backlight_level(int level, void* data); - -static struct backlight_controller aty_backlight_controller = { - aty_set_backlight_enable, - aty_set_backlight_level -}; -#endif /* CONFIG_PMAC_BACKLIGHT */ - - /* - * Frame buffer device API - */ - -static int atyfb_open(struct fb_info *info, int user); -static int atyfb_release(struct fb_info *info, int user); -static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *fb); -static int atyfb_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *fb); -static int atyfb_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *fb); -static int atyfb_pan_display(struct fb_var_screeninfo *var, int con, - struct fb_info *fb); -static int atyfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); -static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); -static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg, int con, struct fb_info *info); -#ifdef __sparc__ -static int atyfb_mmap(struct fb_info *info, struct file *file, - struct vm_area_struct *vma); -#endif -static int atyfb_rasterimg(struct fb_info *info, int start); - - - /* - * Interface to the low level console driver - */ - -static int atyfbcon_switch(int con, struct fb_info *fb); -static int atyfbcon_updatevar(int con, struct fb_info *fb); -static void atyfbcon_blank(int blank, struct fb_info *fb); - - - /* - * Text console acceleration - */ - -static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy, int dx, - int height, int width); -static void fbcon_aty_clear(struct vc_data *conp, struct display *p, int sy, - int sx, int height, int width); -#ifdef FBCON_HAS_CFB8 -static struct display_switch fbcon_aty8; -static void fbcon_aty8_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx); -static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, - int xx); -#endif -#ifdef FBCON_HAS_CFB16 -static struct display_switch fbcon_aty16; -static void fbcon_aty16_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx); -static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, - int xx); -#endif -#ifdef FBCON_HAS_CFB24 -static struct display_switch fbcon_aty24; -static void fbcon_aty24_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx); -static void fbcon_aty24_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, - int xx); -#endif -#ifdef FBCON_HAS_CFB32 -static struct display_switch fbcon_aty32; -static void fbcon_aty32_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx); -static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, - int xx); -#endif - - - /* - * Internal routines - */ - -static int aty_init(struct fb_info_aty *info, const char *name); -static struct aty_cursor *aty_init_cursor(struct fb_info_aty *fb); -#ifdef CONFIG_ATARI -static int store_video_par(char *videopar, unsigned char m64_num); -static char *strtoke(char *s, const char *ct); -#endif - -static void reset_engine(const struct fb_info_aty *info); -static void init_engine(const struct atyfb_par *par, struct fb_info_aty *info); - -static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info); -static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info); -static u8 aty_ld_pll(int offset, const struct fb_info_aty *info); -static void aty_set_crtc(const struct fb_info_aty *info, - const struct crtc *crtc); -static int aty_var_to_crtc(const struct fb_info_aty *info, - const struct fb_var_screeninfo *var, - struct crtc *crtc); -static void aty_set_dac_514(const struct fb_info_aty *info, u32 bpp); -static int aty_crtc_to_var(const struct crtc *crtc, - struct fb_var_screeninfo *var); -static void aty_set_pll_gx(const struct fb_info_aty *info, - const struct pll_gx *pll); - -static int aty_set_dac_ATI68860_B(const struct fb_info_aty *info, u32 bpp, - u32 AccelMode); -static int aty_set_dac_ATT21C498(const struct fb_info_aty *info, - const struct pll_18818 *pll, u32 bpp); -void aty_dac_waste4(const struct fb_info_aty *info); - -static int aty_var_to_pll_18818(u32 period_in_ps, struct pll_18818 *pll); -static u32 aty_pll_18818_to_var(const struct pll_18818 *pll); -static void aty_set_pll18818(const struct fb_info_aty *info, - const struct pll_18818 *pll); - -static void aty_StrobeClock(const struct fb_info_aty *info); - -static void aty_ICS2595_put1bit(u8 data, const struct fb_info_aty *info); - -static int aty_var_to_pll_408(u32 period_in_ps, struct pll_18818 *pll); -static u32 aty_pll_408_to_var(const struct pll_18818 *pll); -static void aty_set_pll_408(const struct fb_info_aty *info, - const struct pll_18818 *pll); - -static int aty_var_to_pll_1703(u32 period_in_ps, struct pll_18818 *pll); -static u32 aty_pll_1703_to_var(const struct pll_18818 *pll); -static void aty_set_pll_1703(const struct fb_info_aty *info, - const struct pll_18818 *pll); - -static int aty_var_to_pll_8398(u32 period_in_ps, struct pll_18818 *pll); -static u32 aty_pll_8398_to_var(const struct pll_18818 *pll); -static void aty_set_pll_8398(const struct fb_info_aty *info, - const struct pll_18818 *pll); - -static int aty_var_to_pll_514(u32 vclk_per, struct pll_gx *pll); -static u32 aty_pll_gx_to_var(const struct pll_gx *pll, - const struct fb_info_aty *info); -static void aty_set_pll_ct(const struct fb_info_aty *info, - const struct pll_ct *pll); -static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per, - struct pll_ct *pll); -static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp, - struct pll_ct *pll); -static void aty_calc_pll_ct(const struct fb_info_aty *info, - struct pll_ct *pll); -static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per, - u8 bpp, struct pll_ct *pll); -static u32 aty_pll_ct_to_var(const struct pll_ct *pll, - const struct fb_info_aty *info); -static void atyfb_set_par(const struct atyfb_par *par, - struct fb_info_aty *info); -static int atyfb_decode_var(const struct fb_var_screeninfo *var, - struct atyfb_par *par, - const struct fb_info_aty *info); -static int atyfb_encode_var(struct fb_var_screeninfo *var, - const struct atyfb_par *par, - const struct fb_info_aty *info); -static void set_off_pitch(struct atyfb_par *par, - const struct fb_info_aty *info); -static int encode_fix(struct fb_fix_screeninfo *fix, - const struct atyfb_par *par, - const struct fb_info_aty *info); -static void atyfb_set_dispsw(struct display *disp, struct fb_info_aty *info, - int bpp, int accel); -static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, - u_int *transp, struct fb_info *fb); -static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *fb); -static void do_install_cmap(int con, struct fb_info *info); -#ifdef CONFIG_PPC -static int read_aty_sense(const struct fb_info_aty *info); -#endif - - - /* - * Interface used by the world - */ - -int atyfb_init(void); -#ifndef MODULE -int atyfb_setup(char*); -#endif - -static int currcon = 0; - -static struct fb_ops atyfb_ops = { - owner: THIS_MODULE, - fb_open: atyfb_open, - fb_release: atyfb_release, - fb_get_fix: atyfb_get_fix, - fb_get_var: atyfb_get_var, - fb_set_var: atyfb_set_var, - fb_get_cmap: atyfb_get_cmap, - fb_set_cmap: atyfb_set_cmap, - fb_pan_display: atyfb_pan_display, - fb_ioctl: atyfb_ioctl, -#ifdef __sparc__ - fb_mmap: atyfb_mmap, -#endif - fb_rasterimg: atyfb_rasterimg, -}; - -static char atyfb_name[16] = "ATY Mach64"; -static char fontname[40] __initdata = { 0 }; -static char curblink __initdata = 1; -static char noaccel __initdata = 0; -static u32 default_vram __initdata = 0; -static int default_pll __initdata = 0; -static int default_mclk __initdata = 0; - -#ifndef MODULE -static const char *mode_option __initdata = NULL; -#endif - -#ifdef CONFIG_PPC -#ifdef CONFIG_NVRAM_NOT_DEFINED -static int default_vmode __initdata = VMODE_NVRAM; -static int default_cmode __initdata = CMODE_NVRAM; -#else -static int default_vmode __initdata = VMODE_CHOOSE; -static int default_cmode __initdata = CMODE_CHOOSE; -#endif -#endif - -#ifdef CONFIG_ATARI -static unsigned int mach64_count __initdata = 0; -static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, }; -static unsigned long phys_size[FB_MAX] __initdata = { 0, }; -static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, }; -#endif - - -static struct aty_features { - u16 pci_id; - u16 chip_type; - const char *name; -} aty_features[] __initdata = { - /* mach64GX family */ - { 0x4758, 0x00d7, "mach64GX (ATI888GX00)" }, - { 0x4358, 0x0057, "mach64CX (ATI888CX00)" }, - - /* mach64CT family */ - { 0x4354, 0x4354, "mach64CT (ATI264CT)" }, - { 0x4554, 0x4554, "mach64ET (ATI264ET)" }, - - /* mach64CT family / mach64VT class */ - { 0x5654, 0x5654, "mach64VT (ATI264VT)" }, - { 0x5655, 0x5655, "mach64VTB (ATI264VTB)" }, - { 0x5656, 0x5656, "mach64VT4 (ATI264VT4)" }, - - /* mach64CT family / mach64GT (3D RAGE) class */ - { 0x4c42, 0x4c42, "3D RAGE LT PRO (AGP)" }, - { 0x4c44, 0x4c44, "3D RAGE LT PRO" }, - { 0x4c47, 0x4c47, "3D RAGE LT-G" }, - { 0x4c49, 0x4c49, "3D RAGE LT PRO" }, - { 0x4c50, 0x4c50, "3D RAGE LT PRO" }, - { 0x4c54, 0x4c54, "3D RAGE LT" }, - { 0x4754, 0x4754, "3D RAGE (GT)" }, - { 0x4755, 0x4755, "3D RAGE II+ (GTB)" }, - { 0x4756, 0x4756, "3D RAGE IIC (PCI)" }, - { 0x4757, 0x4757, "3D RAGE IIC (AGP)" }, - { 0x475a, 0x475a, "3D RAGE IIC (AGP)" }, - { 0x4742, 0x4742, "3D RAGE PRO (BGA, AGP)" }, - { 0x4744, 0x4744, "3D RAGE PRO (BGA, AGP, 1x only)" }, - { 0x4749, 0x4749, "3D RAGE PRO (BGA, PCI)" }, - { 0x4750, 0x4750, "3D RAGE PRO (PQFP, PCI)" }, - { 0x4751, 0x4751, "3D RAGE PRO (PQFP, PCI, limited 3D)" }, - { 0x4c4d, 0x4c4d, "3D RAGE Mobility (PCI)" }, - { 0x4c4e, 0x4c4e, "3D RAGE Mobility (AGP)" }, -}; - -static const char *aty_gx_ram[8] __initdata = { - "DRAM", "VRAM", "VRAM", "DRAM", "DRAM", "VRAM", "VRAM", "RESV" -}; - -static const char *aty_ct_ram[8] __initdata = { - "OFF", "DRAM", "EDO", "EDO", "SDRAM", "SGRAM", "WRAM", "RESV" -}; - - -static inline u32 aty_ld_le32(int regindex, - const struct fb_info_aty *info) -{ - /* Hack for bloc 1, should be cleanly optimized by compiler */ - if (regindex >= 0x400) - regindex -= 0x800; - -#if defined(__mc68000__) - return le32_to_cpu(*((volatile u32 *)(info->ati_regbase+regindex))); -#else - return readl (info->ati_regbase + regindex); -#endif -} - -static inline void aty_st_le32(int regindex, u32 val, - const struct fb_info_aty *info) -{ - /* Hack for bloc 1, should be cleanly optimized by compiler */ - if (regindex >= 0x400) - regindex -= 0x800; - -#if defined(__mc68000__) - *((volatile u32 *)(info->ati_regbase+regindex)) = cpu_to_le32(val); -#else - writel (val, info->ati_regbase + regindex); -#endif -} - -static inline u8 aty_ld_8(int regindex, - const struct fb_info_aty *info) -{ - /* Hack for bloc 1, should be cleanly optimized by compiler */ - if (regindex >= 0x400) - regindex -= 0x800; - - return readb (info->ati_regbase + regindex); -} - -static inline void aty_st_8(int regindex, u8 val, - const struct fb_info_aty *info) -{ - /* Hack for bloc 1, should be cleanly optimized by compiler */ - if (regindex >= 0x400) - regindex -= 0x800; - - writeb (val, info->ati_regbase + regindex); -} - -#if defined(CONFIG_PPC) || defined(CONFIG_PMAC_PBOOK) -static void aty_st_lcd(int index, u32 val, const struct fb_info_aty *info) -{ - unsigned long temp; - - /* write addr byte */ - temp = aty_ld_le32(LCD_INDEX, info); - aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, info); - /* write the register value */ - aty_st_le32(LCD_DATA, val, info); -} - -static u32 aty_ld_lcd(int index, const struct fb_info_aty *info) -{ - unsigned long temp; - - /* write addr byte */ - temp = aty_ld_le32(LCD_INDEX, info); - aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, info); - /* read the register value */ - return aty_ld_le32(LCD_DATA, info); -} -#endif - - /* - * Generic Mach64 routines - */ - - /* - * All writes to draw engine registers are automatically routed through a - * 32-bit-wide, 16-entry-deep command FIFO ... - * Register writes to registers with DWORD offsets less than 40h are not - * FIFOed. - * (from Chapter 5 of the Mach64 Programmer's Guide) - */ - -static inline void wait_for_fifo(u16 entries, const struct fb_info_aty *info) -{ - while ((aty_ld_le32(FIFO_STAT, info) & 0xffff) > - ((u32)(0x8000 >> entries))); -} - -static inline void wait_for_idle(struct fb_info_aty *info) -{ - wait_for_fifo(16, info); - while ((aty_ld_le32(GUI_STAT, info) & 1)!= 0); - info->blitter_may_be_busy = 0; -} - -static void reset_engine(const struct fb_info_aty *info) -{ - /* reset engine */ - aty_st_le32(GEN_TEST_CNTL, - aty_ld_le32(GEN_TEST_CNTL, info) & ~GUI_ENGINE_ENABLE, info); - /* enable engine */ - aty_st_le32(GEN_TEST_CNTL, - aty_ld_le32(GEN_TEST_CNTL, info) | GUI_ENGINE_ENABLE, info); - /* ensure engine is not locked up by clearing any FIFO or */ - /* HOST errors */ - aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, info) | BUS_HOST_ERR_ACK | - BUS_FIFO_ERR_ACK, info); -} - -static void reset_GTC_3D_engine(const struct fb_info_aty *info) -{ - aty_st_le32(SCALE_3D_CNTL, 0xc0, info); - mdelay(GTC_3D_RESET_DELAY); - aty_st_le32(SETUP_CNTL, 0x00, info); - mdelay(GTC_3D_RESET_DELAY); - aty_st_le32(SCALE_3D_CNTL, 0x00, info); - mdelay(GTC_3D_RESET_DELAY); -} - -static void init_engine(const struct atyfb_par *par, struct fb_info_aty *info) -{ - u32 pitch_value; - - /* determine modal information from global mode structure */ - pitch_value = par->crtc.vxres; - - if (par->crtc.bpp == 24) { - /* In 24 bpp, the engine is in 8 bpp - this requires that all */ - /* horizontal coordinates and widths must be adjusted */ - pitch_value = pitch_value * 3; - } - - /* On GTC (RagePro), we need to reset the 3D engine before */ - if (Gx == LB_CHIP_ID || Gx == LD_CHIP_ID || Gx == LI_CHIP_ID || - Gx == LP_CHIP_ID || Gx == GB_CHIP_ID || Gx == GD_CHIP_ID || - Gx == GI_CHIP_ID || Gx == GP_CHIP_ID || Gx == GQ_CHIP_ID || - Gx == LM_CHIP_ID || Gx == LN_CHIP_ID) - reset_GTC_3D_engine(info); - - /* Reset engine, enable, and clear any engine errors */ - reset_engine(info); - /* Ensure that vga page pointers are set to zero - the upper */ - /* page pointers are set to 1 to handle overflows in the */ - /* lower page */ - aty_st_le32(MEM_VGA_WP_SEL, 0x00010000, info); - aty_st_le32(MEM_VGA_RP_SEL, 0x00010000, info); - - /* ---- Setup standard engine context ---- */ - - /* All GUI registers here are FIFOed - therefore, wait for */ - /* the appropriate number of empty FIFO entries */ - wait_for_fifo(14, info); - - /* enable all registers to be loaded for context loads */ - aty_st_le32(CONTEXT_MASK, 0xFFFFFFFF, info); - - /* set destination pitch to modal pitch, set offset to zero */ - aty_st_le32(DST_OFF_PITCH, (pitch_value / 8) << 22, info); - - /* zero these registers (set them to a known state) */ - aty_st_le32(DST_Y_X, 0, info); - aty_st_le32(DST_HEIGHT, 0, info); - aty_st_le32(DST_BRES_ERR, 0, info); - aty_st_le32(DST_BRES_INC, 0, info); - aty_st_le32(DST_BRES_DEC, 0, info); - - /* set destination drawing attributes */ - aty_st_le32(DST_CNTL, DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM | - DST_X_LEFT_TO_RIGHT, info); - - /* set source pitch to modal pitch, set offset to zero */ - aty_st_le32(SRC_OFF_PITCH, (pitch_value / 8) << 22, info); - - /* set these registers to a known state */ - aty_st_le32(SRC_Y_X, 0, info); - aty_st_le32(SRC_HEIGHT1_WIDTH1, 1, info); - aty_st_le32(SRC_Y_X_START, 0, info); - aty_st_le32(SRC_HEIGHT2_WIDTH2, 1, info); - - /* set source pixel retrieving attributes */ - aty_st_le32(SRC_CNTL, SRC_LINE_X_LEFT_TO_RIGHT, info); - - /* set host attributes */ - wait_for_fifo(13, info); - aty_st_le32(HOST_CNTL, 0, info); - - /* set pattern attributes */ - aty_st_le32(PAT_REG0, 0, info); - aty_st_le32(PAT_REG1, 0, info); - aty_st_le32(PAT_CNTL, 0, info); - - /* set scissors to modal size */ - aty_st_le32(SC_LEFT, 0, info); - aty_st_le32(SC_TOP, 0, info); - aty_st_le32(SC_BOTTOM, par->crtc.vyres-1, info); - aty_st_le32(SC_RIGHT, pitch_value-1, info); - - /* set background color to minimum value (usually BLACK) */ - aty_st_le32(DP_BKGD_CLR, 0, info); - - /* set foreground color to maximum value (usually WHITE) */ - aty_st_le32(DP_FRGD_CLR, 0xFFFFFFFF, info); - - /* set write mask to effect all pixel bits */ - aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, info); - - /* set foreground mix to overpaint and background mix to */ - /* no-effect */ - aty_st_le32(DP_MIX, FRGD_MIX_S | BKGD_MIX_D, info); - - /* set primary source pixel channel to foreground color */ - /* register */ - aty_st_le32(DP_SRC, FRGD_SRC_FRGD_CLR, info); - - /* set compare functionality to false (no-effect on */ - /* destination) */ - wait_for_fifo(3, info); - aty_st_le32(CLR_CMP_CLR, 0, info); - aty_st_le32(CLR_CMP_MASK, 0xFFFFFFFF, info); - aty_st_le32(CLR_CMP_CNTL, 0, info); - - /* set pixel depth */ - wait_for_fifo(2, info); - aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, info); - aty_st_le32(DP_CHAIN_MASK, par->crtc.dp_chain_mask, info); - - wait_for_fifo(5, info); - aty_st_le32(SCALE_3D_CNTL, 0, info); - aty_st_le32(Z_CNTL, 0, info); - aty_st_le32(CRTC_INT_CNTL, aty_ld_le32(CRTC_INT_CNTL, info) & ~0x20, info); - aty_st_le32(GUI_TRAJ_CNTL, 0x100023, info); - - /* insure engine is idle before leaving */ - wait_for_idle(info); -} - -static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info) -{ - aty_st_8(DAC_CNTL, 1, info); - /* right addr byte */ - aty_st_8(DAC_W_INDEX, offset & 0xff, info); - /* left addr byte */ - aty_st_8(DAC_DATA, (offset >> 8) & 0xff, info); - aty_st_8(DAC_MASK, val, info); - aty_st_8(DAC_CNTL, 0, info); -} - -static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info) -{ - /* write addr byte */ - aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN, info); - /* write the register value */ - aty_st_8(CLOCK_CNTL + 2, val, info); - aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN, info); -} - -static u8 aty_ld_pll(int offset, const struct fb_info_aty *info) -{ - u8 res; - - /* write addr byte */ - aty_st_8(CLOCK_CNTL + 1, (offset << 2), info); - /* read the register value */ - res = aty_ld_8(CLOCK_CNTL + 2, info); - return res; -} - -#if defined(CONFIG_PPC) - - /* - * Apple monitor sense - */ - -static int read_aty_sense(const struct fb_info_aty *info) -{ - int sense, i; - - aty_st_le32(GP_IO, 0x31003100, info); /* drive outputs high */ - __delay(200); - aty_st_le32(GP_IO, 0, info); /* turn off outputs */ - __delay(2000); - i = aty_ld_le32(GP_IO, info); /* get primary sense value */ - sense = ((i & 0x3000) >> 3) | (i & 0x100); - - /* drive each sense line low in turn and collect the other 2 */ - aty_st_le32(GP_IO, 0x20000000, info); /* drive A low */ - __delay(2000); - i = aty_ld_le32(GP_IO, info); - sense |= ((i & 0x1000) >> 7) | ((i & 0x100) >> 4); - aty_st_le32(GP_IO, 0x20002000, info); /* drive A high again */ - __delay(200); - - aty_st_le32(GP_IO, 0x10000000, info); /* drive B low */ - __delay(2000); - i = aty_ld_le32(GP_IO, info); - sense |= ((i & 0x2000) >> 10) | ((i & 0x100) >> 6); - aty_st_le32(GP_IO, 0x10001000, info); /* drive B high again */ - __delay(200); - - aty_st_le32(GP_IO, 0x01000000, info); /* drive C low */ - __delay(2000); - sense |= (aty_ld_le32(GP_IO, info) & 0x3000) >> 12; - aty_st_le32(GP_IO, 0, info); /* turn off outputs */ - - return sense; -} - -#endif /* defined(CONFIG_PPC) */ - -/* ------------------------------------------------------------------------- */ - - /* - * Hardware Cursor support. - */ - -static u8 cursor_pixel_map[2] = { 0, 15 }; -static u8 cursor_color_map[2] = { 0, 0xff }; - -static u8 cursor_bits_lookup[16] = -{ - 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, - 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55 -}; - -static u8 cursor_mask_lookup[16] = -{ - 0xaa, 0x2a, 0x8a, 0x0a, 0xa2, 0x22, 0x82, 0x02, - 0xa8, 0x28, 0x88, 0x08, 0xa0, 0x20, 0x80, 0x00 -}; - -static void -aty_set_cursor_color(struct fb_info_aty *fb, u8 *pixel, - u8 *red, u8 *green, u8 *blue) -{ - struct aty_cursor *c = fb->cursor; - int i; - - if (!c) - return; - -#ifdef __sparc__ - if (fb->mmaped && (!fb->fb_info.display_fg - || fb->fb_info.display_fg->vc_num == fb->vtconsole)) - return; -#endif - - for (i = 0; i < 2; i++) { - c->color[i] = (u32)red[i] << 24; - c->color[i] |= (u32)green[i] << 16; - c->color[i] |= (u32)blue[i] << 8; - c->color[i] |= (u32)pixel[i]; - } - - wait_for_fifo(2, fb); - aty_st_le32(CUR_CLR0, c->color[0], fb); - aty_st_le32(CUR_CLR1, c->color[1], fb); -} - -static void -aty_set_cursor_shape(struct fb_info_aty *fb) -{ - struct aty_cursor *c = fb->cursor; - u8 *ram, m, b; - int x, y; - - if (!c) - return; - -#ifdef __sparc__ - if (fb->mmaped && (!fb->fb_info.display_fg - || fb->fb_info.display_fg->vc_num == fb->vtconsole)) - return; -#endif - - ram = c->ram; - for (y = 0; y < c->size.y; y++) { - for (x = 0; x < c->size.x >> 2; x++) { - m = c->mask[x][y]; - b = c->bits[x][y]; - fb_writeb (cursor_mask_lookup[m >> 4] | - cursor_bits_lookup[(b & m) >> 4], - ram++); - fb_writeb (cursor_mask_lookup[m & 0x0f] | - cursor_bits_lookup[(b & m) & 0x0f], - ram++); - } - for ( ; x < 8; x++) { - fb_writeb (0xaa, ram++); - fb_writeb (0xaa, ram++); - } - } - fb_memset (ram, 0xaa, (64 - c->size.y) * 16); -} - -static void -aty_set_cursor(struct fb_info_aty *fb, int on) -{ - struct atyfb_par *par = &fb->current_par; - struct aty_cursor *c = fb->cursor; - u16 xoff, yoff; - int x, y; - - if (!c) - return; - -#ifdef __sparc__ - if (fb->mmaped && (!fb->fb_info.display_fg - || fb->fb_info.display_fg->vc_num == fb->vtconsole)) - return; -#endif - - if (on) { - x = c->pos.x - c->hot.x - par->crtc.xoffset; - if (x < 0) { - xoff = -x; - x = 0; - } else { - xoff = 0; - } - - y = c->pos.y - c->hot.y - par->crtc.yoffset; - if (y < 0) { - yoff = -y; - y = 0; - } else { - yoff = 0; - } - - wait_for_fifo(4, fb); - aty_st_le32(CUR_OFFSET, (c->offset >> 3) + (yoff << 1), fb); - aty_st_le32(CUR_HORZ_VERT_OFF, - ((u32)(64 - c->size.y + yoff) << 16) | xoff, fb); - aty_st_le32(CUR_HORZ_VERT_POSN, ((u32)y << 16) | x, fb); - aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, fb) - | HWCURSOR_ENABLE, fb); - } else { - wait_for_fifo(1, fb); - aty_st_le32(GEN_TEST_CNTL, - aty_ld_le32(GEN_TEST_CNTL, fb) & ~HWCURSOR_ENABLE, - fb); - } - if (fb->blitter_may_be_busy) - wait_for_idle(fb); -} - -static void -aty_cursor_timer_handler(unsigned long dev_addr) -{ - struct fb_info_aty *fb = (struct fb_info_aty *)dev_addr; - - if (!fb->cursor) - return; - - if (!fb->cursor->enable) - goto out; - - if (fb->cursor->vbl_cnt && --fb->cursor->vbl_cnt == 0) { - fb->cursor->on ^= 1; - aty_set_cursor(fb, fb->cursor->on); - fb->cursor->vbl_cnt = fb->cursor->blink_rate; - } - -out: - fb->cursor->timer->expires = jiffies + (HZ / 50); - add_timer(fb->cursor->timer); -} - -static void -atyfb_cursor(struct display *p, int mode, int x, int y) -{ - struct fb_info_aty *fb = (struct fb_info_aty *)p->fb_info; - struct aty_cursor *c = fb->cursor; - - if (!c) - return; - -#ifdef __sparc__ - if (fb->mmaped && (!fb->fb_info.display_fg - || fb->fb_info.display_fg->vc_num == fb->vtconsole)) - return; -#endif - - x *= fontwidth(p); - y *= fontheight(p); - if (c->pos.x == x && c->pos.y == y && (mode == CM_ERASE) == !c->enable) - return; - - c->enable = 0; - if (c->on) - aty_set_cursor(fb, 0); - c->pos.x = x; - c->pos.y = y; - - switch (mode) { - case CM_ERASE: - c->on = 0; - break; - - case CM_DRAW: - case CM_MOVE: - if (c->on) - aty_set_cursor(fb, 1); - else - c->vbl_cnt = CURSOR_DRAW_DELAY; - c->enable = 1; - break; - } -} - -static struct fb_info_aty *fb_list = NULL; - -static struct aty_cursor * __init -aty_init_cursor(struct fb_info_aty *fb) -{ - struct aty_cursor *cursor; - unsigned long addr; - - cursor = kmalloc(sizeof(struct aty_cursor), GFP_ATOMIC); - if (!cursor) - return 0; - memset(cursor, 0, sizeof(*cursor)); - - cursor->timer = kmalloc(sizeof(*cursor->timer), GFP_KERNEL); - if (!cursor->timer) { - kfree(cursor); - return 0; - } - memset(cursor->timer, 0, sizeof(*cursor->timer)); - - cursor->blink_rate = DEFAULT_CURSOR_BLINK_RATE; - fb->total_vram -= PAGE_SIZE; - cursor->offset = fb->total_vram; - -#ifdef __sparc__ - addr = fb->frame_buffer - 0x800000 + cursor->offset; - cursor->ram = (u8 *)addr; -#else -#ifdef __BIG_ENDIAN - addr = fb->frame_buffer_phys - 0x800000 + cursor->offset; - cursor->ram = (u8 *)ioremap(addr, 1024); -#else - addr = fb->frame_buffer + cursor->offset; - cursor->ram = (u8 *)addr; -#endif -#endif - - if (! cursor->ram) { - kfree(cursor); - return NULL; - } - - if (curblink) { - init_timer(cursor->timer); - cursor->timer->expires = jiffies + (HZ / 50); - cursor->timer->data = (unsigned long)fb; - cursor->timer->function = aty_cursor_timer_handler; - add_timer(cursor->timer); - } - - return cursor; -} - -static int -atyfb_set_font(struct display *d, int width, int height) -{ - struct fb_info_aty *fb = (struct fb_info_aty *)d->fb_info; - struct aty_cursor *c = fb->cursor; - int i, j; - - if (c) { - if (!width || !height) { - width = 8; - height = 16; - } - - c->hot.x = 0; - c->hot.y = 0; - c->size.x = width; - c->size.y = height; - - memset(c->bits, 0xff, sizeof(c->bits)); - memset(c->mask, 0, sizeof(c->mask)); - - for (i = 0, j = width; j >= 0; j -= 8, i++) { - c->mask[i][height-2] = (j >= 8) ? 0xff : (0xff << (8 - j)); - c->mask[i][height-1] = (j >= 8) ? 0xff : (0xff << (8 - j)); - } - - aty_set_cursor_color(fb, cursor_pixel_map, cursor_color_map, - cursor_color_map, cursor_color_map); - aty_set_cursor_shape(fb); - } - return 1; -} - - - - -/* ------------------------------------------------------------------------- */ - - /* - * CRTC programming - */ - -static void aty_set_crtc(const struct fb_info_aty *info, - const struct crtc *crtc) -{ - aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, info); - aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, info); - aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_tot_disp, info); - aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid, info); - aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0, info); - aty_st_le32(CRTC_OFF_PITCH, crtc->off_pitch, info); - aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, info); -} - -static int aty_var_to_crtc(const struct fb_info_aty *info, - const struct fb_var_screeninfo *var, - struct crtc *crtc) -{ - u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp; - u32 left, right, upper, lower, hslen, vslen, sync, vmode; - u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; - u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; - u32 pix_width, dp_pix_width, dp_chain_mask; - - /* input */ - xres = var->xres; - yres = var->yres; - vxres = var->xres_virtual; - vyres = var->yres_virtual; - xoffset = var->xoffset; - yoffset = var->yoffset; - bpp = var->bits_per_pixel; - left = var->left_margin; - right = var->right_margin; - upper = var->upper_margin; - lower = var->lower_margin; - hslen = var->hsync_len; - vslen = var->vsync_len; - sync = var->sync; - vmode = var->vmode; - - /* convert (and round up) and validate */ - xres = (xres+7) & ~7; - xoffset = (xoffset+7) & ~7; - vxres = (vxres+7) & ~7; - if (vxres < xres+xoffset) - vxres = xres+xoffset; - h_disp = xres/8-1; - if (h_disp > 0xff) - FAIL("h_disp too large"); - h_sync_strt = h_disp+(right/8); - if (h_sync_strt > 0x1ff) - FAIL("h_sync_start too large"); - h_sync_dly = right & 7; - h_sync_wid = (hslen+7)/8; - if (h_sync_wid > 0x1f) - FAIL("h_sync_wid too large"); - h_total = h_sync_strt+h_sync_wid+(h_sync_dly+left+7)/8; - if (h_total > 0x1ff) - FAIL("h_total too large"); - h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; - - if (vyres < yres+yoffset) - vyres = yres+yoffset; - v_disp = yres-1; - if (v_disp > 0x7ff) - FAIL("v_disp too large"); - v_sync_strt = v_disp+lower; - if (v_sync_strt > 0x7ff) - FAIL("v_sync_strt too large"); - v_sync_wid = vslen; - if (v_sync_wid > 0x1f) - FAIL("v_sync_wid too large"); - v_total = v_sync_strt+v_sync_wid+upper; - if (v_total > 0x7ff) - FAIL("v_total too large"); - v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; - - c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? CRTC_CSYNC_EN : 0; - - if (bpp <= 8) { - bpp = 8; - pix_width = CRTC_PIX_WIDTH_8BPP; - dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB; - dp_chain_mask = 0x8080; - } else if (bpp <= 16) { - bpp = 16; - pix_width = CRTC_PIX_WIDTH_15BPP; - dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP | - BYTE_ORDER_LSB_TO_MSB; - dp_chain_mask = 0x4210; - } else if ((bpp <= 24) && (Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) { - bpp = 24; - pix_width = CRTC_PIX_WIDTH_24BPP; - dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB; - dp_chain_mask = 0x8080; - } else if (bpp <= 32) { - bpp = 32; - pix_width = CRTC_PIX_WIDTH_32BPP; - dp_pix_width = HOST_32BPP | SRC_32BPP | DST_32BPP | - BYTE_ORDER_LSB_TO_MSB; - dp_chain_mask = 0x8080; - } else - FAIL("invalid bpp"); - - if (vxres*vyres*bpp/8 > info->total_vram) - FAIL("not enough video RAM"); - - if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) - FAIL("invalid vmode"); - - /* output */ - crtc->vxres = vxres; - crtc->vyres = vyres; - crtc->xoffset = xoffset; - crtc->yoffset = yoffset; - crtc->bpp = bpp; - crtc->h_tot_disp = h_total | (h_disp<<16); - crtc->h_sync_strt_wid = (h_sync_strt & 0xff) | (h_sync_dly<<8) | - ((h_sync_strt & 0x100)<<4) | (h_sync_wid<<16) | - (h_sync_pol<<21); - crtc->v_tot_disp = v_total | (v_disp<<16); - crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid<<16) | (v_sync_pol<<21); - crtc->off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19); - crtc->gen_cntl = pix_width | c_sync | CRTC_EXT_DISP_EN | CRTC_ENABLE; - if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID) || - ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07))) { - /* Not VTB/GTB */ - /* FIXME: magic FIFO values */ - crtc->gen_cntl |= aty_ld_le32(CRTC_GEN_CNTL, info) & 0x000e0000; - } - crtc->dp_pix_width = dp_pix_width; - crtc->dp_chain_mask = dp_chain_mask; - - return 0; -} - - -static int aty_set_dac_ATI68860_B(const struct fb_info_aty *info, u32 bpp, - u32 AccelMode) -{ - u32 gModeReg, devSetupRegA, temp, mask; - - gModeReg = 0; - devSetupRegA = 0; - - switch (bpp) { - case 8: - gModeReg = 0x83; - devSetupRegA = 0x60 | 0x00 /*(info->mach64DAC8Bit ? 0x00 : 0x01) */; - break; - case 15: - gModeReg = 0xA0; - devSetupRegA = 0x60; - break; - case 16: - gModeReg = 0xA1; - devSetupRegA = 0x60; - break; - case 24: - gModeReg = 0xC0; - devSetupRegA = 0x60; - break; - case 32: - gModeReg = 0xE3; - devSetupRegA = 0x60; - break; - } - - if (!AccelMode) { - gModeReg = 0x80; - devSetupRegA = 0x61; - } - - temp = aty_ld_8(DAC_CNTL, info); - aty_st_8(DAC_CNTL, (temp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3, info); - - aty_st_8(DAC_REGS + 2, 0x1D, info); - aty_st_8(DAC_REGS + 3, gModeReg, info); - aty_st_8(DAC_REGS, 0x02, info); - - temp = aty_ld_8(DAC_CNTL, info); - aty_st_8(DAC_CNTL, temp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, info); - - if (info->total_vram < MEM_SIZE_1M) - mask = 0x04; - else if (info->total_vram == MEM_SIZE_1M) - mask = 0x08; - else - mask = 0x0C; - - /* The following assumes that the BIOS has correctly set R7 of the - * Device Setup Register A at boot time. - */ -#define A860_DELAY_L 0x80 - - temp = aty_ld_8(DAC_REGS, info); - aty_st_8(DAC_REGS, (devSetupRegA | mask) | (temp & A860_DELAY_L), info); - temp = aty_ld_8(DAC_CNTL, info); - aty_st_8(DAC_CNTL, (temp & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3)), info); - - return 0; -} - -static int aty_set_dac_ATT21C498(const struct fb_info_aty *info, - const struct pll_18818 *pll, u32 bpp) -{ - u32 dotClock; - int muxmode = 0; - int DACMask = 0; - - dotClock = 100000000 / pll->period_in_ps; - - switch (bpp) { - case 8: - if (dotClock > 8000) { - DACMask = 0x24; - muxmode = 1; - } else - DACMask = 0x04; - break; - case 15: - DACMask = 0x16; - break; - case 16: - DACMask = 0x36; - break; - case 24: - DACMask = 0xE6; - break; - case 32: - DACMask = 0xE6; - break; - } - - if (1 /* info->mach64DAC8Bit */) - DACMask |= 0x02; - - aty_dac_waste4(info); - aty_st_8(DAC_REGS + 2, DACMask, info); - - return muxmode; -} - -void aty_dac_waste4(const struct fb_info_aty *info) -{ - (void)aty_ld_8(DAC_REGS, info); - - (void)aty_ld_8(DAC_REGS + 2, info); - (void)aty_ld_8(DAC_REGS + 2, info); - (void)aty_ld_8(DAC_REGS + 2, info); - (void)aty_ld_8(DAC_REGS + 2, info); -} - - -static void aty_set_dac_514(const struct fb_info_aty *info, u32 bpp) -{ - static struct { - u8 pixel_dly; - u8 misc2_cntl; - u8 pixel_rep; - u8 pixel_cntl_index; - u8 pixel_cntl_v1; - } tab[3] = { - { 0, 0x41, 0x03, 0x71, 0x45 }, /* 8 bpp */ - { 0, 0x45, 0x04, 0x0c, 0x01 }, /* 555 */ - { 0, 0x45, 0x06, 0x0e, 0x00 }, /* XRGB */ - }; - int i; - - switch (bpp) { - case 8: - default: - i = 0; - break; - case 16: - i = 1; - break; - case 32: - i = 2; - break; - } - aty_st_514(0x90, 0x00, info); /* VRAM Mask Low */ - aty_st_514(0x04, tab[i].pixel_dly, info); /* Horizontal Sync Control */ - aty_st_514(0x05, 0x00, info); /* Power Management */ - aty_st_514(0x02, 0x01, info); /* Misc Clock Control */ - aty_st_514(0x71, tab[i].misc2_cntl, info); /* Misc Control 2 */ - aty_st_514(0x0a, tab[i].pixel_rep, info); /* Pixel Format */ - aty_st_514(tab[i].pixel_cntl_index, tab[i].pixel_cntl_v1, info); - /* Misc Control 2 / 16 BPP Control / 32 BPP Control */ -} - -static int aty_crtc_to_var(const struct crtc *crtc, - struct fb_var_screeninfo *var) -{ - u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync; - u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; - u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; - u32 pix_width; - - /* input */ - h_total = crtc->h_tot_disp & 0x1ff; - h_disp = (crtc->h_tot_disp>>16) & 0xff; - h_sync_strt = (crtc->h_sync_strt_wid & 0xff) | - ((crtc->h_sync_strt_wid>>4) & 0x100); - h_sync_dly = (crtc->h_sync_strt_wid>>8) & 0x7; - h_sync_wid = (crtc->h_sync_strt_wid>>16) & 0x1f; - h_sync_pol = (crtc->h_sync_strt_wid>>21) & 0x1; - v_total = crtc->v_tot_disp & 0x7ff; - v_disp = (crtc->v_tot_disp>>16) & 0x7ff; - v_sync_strt = crtc->v_sync_strt_wid & 0x7ff; - v_sync_wid = (crtc->v_sync_strt_wid>>16) & 0x1f; - v_sync_pol = (crtc->v_sync_strt_wid>>21) & 0x1; - c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0; - pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK; - - /* convert */ - xres = (h_disp+1)*8; - yres = v_disp+1; - left = (h_total-h_sync_strt-h_sync_wid)*8-h_sync_dly; - right = (h_sync_strt-h_disp)*8+h_sync_dly; - hslen = h_sync_wid*8; - upper = v_total-v_sync_strt-v_sync_wid; - lower = v_sync_strt-v_disp; - vslen = v_sync_wid; - sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) | - (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) | - (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0); - - switch (pix_width) { -#if 0 - case CRTC_PIX_WIDTH_4BPP: - bpp = 4; - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 0; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - break; -#endif - case CRTC_PIX_WIDTH_8BPP: - bpp = 8; - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 0; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - break; - case CRTC_PIX_WIDTH_15BPP: /* RGB 555 */ - bpp = 16; - var->red.offset = 10; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 5; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - break; -#if 0 - case CRTC_PIX_WIDTH_16BPP: /* RGB 565 */ - bpp = 16; - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - break; -#endif - case CRTC_PIX_WIDTH_24BPP: /* RGB 888 */ - bpp = 24; - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - break; - case CRTC_PIX_WIDTH_32BPP: /* ARGB 8888 */ - bpp = 32; - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 24; - var->transp.length = 8; - break; - default: - FAIL("Invalid pixel width"); - } - - /* output */ - var->xres = xres; - var->yres = yres; - var->xres_virtual = crtc->vxres; - var->yres_virtual = crtc->vyres; - var->bits_per_pixel = bpp; - var->xoffset = crtc->xoffset; - var->yoffset = crtc->yoffset; - var->left_margin = left; - var->right_margin = right; - var->upper_margin = upper; - var->lower_margin = lower; - var->hsync_len = hslen; - var->vsync_len = vslen; - var->sync = sync; - var->vmode = FB_VMODE_NONINTERLACED; - - return 0; -} - -/* ------------------------------------------------------------------------- */ - - /* - * PLL programming (Mach64 GX family) - * - * FIXME: use function pointer tables instead of switch statements - */ - -static void aty_set_pll_gx(const struct fb_info_aty *info, - const struct pll_gx *pll) -{ - switch (info->clk_type) { - case CLK_ATI18818_1: - aty_st_8(CLOCK_CNTL, pll->m, info); - break; - case CLK_IBMRGB514: - aty_st_514(0x06, 0x02, info); /* DAC Operation */ - aty_st_514(0x10, 0x01, info); /* PLL Control 1 */ - aty_st_514(0x70, 0x01, info); /* Misc Control 1 */ - aty_st_514(0x8f, 0x1f, info); /* PLL Ref. Divider Input */ - aty_st_514(0x03, 0x00, info); /* Sync Control */ - aty_st_514(0x05, 0x00, info); /* Power Management */ - aty_st_514(0x20, pll->m, info); /* F0 / M0 */ - aty_st_514(0x21, pll->n, info); /* F1 / N0 */ - break; - } -} - - -static int aty_var_to_pll_18818(u32 period_in_ps, struct pll_18818 *pll) -{ - u32 MHz100; /* in 0.01 MHz */ - u32 program_bits; - u32 post_divider; - - /* Calculate the programming word */ - MHz100 = 100000000 / period_in_ps; - - program_bits = -1; - post_divider = 1; - - if (MHz100 > MAX_FREQ_2595) { - MHz100 = MAX_FREQ_2595; - return -EINVAL; - } else if (MHz100 < ABS_MIN_FREQ_2595) { - program_bits = 0; /* MHz100 = 257 */ - return -EINVAL; - } else { - while (MHz100 < MIN_FREQ_2595) { - MHz100 *= 2; - post_divider *= 2; - } - } - MHz100 *= 1000; - MHz100 = (REF_DIV_2595 * MHz100) / REF_FREQ_2595; - - MHz100 += 500; /* + 0.5 round */ - MHz100 /= 1000; - - if (program_bits == -1) { - program_bits = MHz100 - N_ADJ_2595; - switch (post_divider) { - case 1: - program_bits |= 0x0600; - break; - case 2: - program_bits |= 0x0400; - break; - case 4: - program_bits |= 0x0200; - break; - case 8: - default: - break; - } - } - - program_bits |= STOP_BITS_2595; - - pll->program_bits = program_bits; - pll->locationAddr = 0; - pll->post_divider = post_divider; - pll->period_in_ps = period_in_ps; - - return 0; -} - -static u32 aty_pll_18818_to_var(const struct pll_18818 *pll) -{ - return(pll->period_in_ps); /* default for now */ -} - -static void aty_set_pll18818(const struct fb_info_aty *info, - const struct pll_18818 *pll) -{ - u32 program_bits; - u32 locationAddr; - - u32 i; - - u8 old_clock_cntl; - u8 old_crtc_ext_disp; - - old_clock_cntl = aty_ld_8(CLOCK_CNTL, info); - aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info); - - old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info); - aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), - info); - - mdelay(15); /* delay for 50 (15) ms */ - - program_bits = pll->program_bits; - locationAddr = pll->locationAddr; - - /* Program the clock chip */ - aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info); /* Strobe = 0 */ - aty_StrobeClock(info); - aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 1, info); /* Strobe = 0 */ - aty_StrobeClock(info); - - aty_ICS2595_put1bit(1, info); /* Send start bits */ - aty_ICS2595_put1bit(0, info); /* Start bit */ - aty_ICS2595_put1bit(0, info); /* Read / ~Write */ - - for (i = 0; i < 5; i++) { /* Location 0..4 */ - aty_ICS2595_put1bit(locationAddr & 1, info); - locationAddr >>= 1; - } - - for (i = 0; i < 8 + 1 + 2 + 2; i++) { - aty_ICS2595_put1bit(program_bits & 1, info); - program_bits >>= 1; - } - - udelay(1000); /* delay for 1 ms */ - - (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */ - aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info); - aty_st_8(CLOCK_CNTL + info->clk_wr_offset, old_clock_cntl | CLOCK_STROBE, - info); - - mdelay(50); /* delay for 50 (15) ms */ - aty_st_8(CLOCK_CNTL + info->clk_wr_offset, - ((pll->locationAddr & 0x0F) | CLOCK_STROBE), info); - - return; -} - - -static int aty_var_to_pll_408(u32 period_in_ps, struct pll_18818 *pll) -{ - u32 mhz100; /* in 0.01 MHz */ - u32 program_bits; - /* u32 post_divider; */ - u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq; - u32 temp, tempB; - u16 remainder, preRemainder; - short divider = 0, tempA; - - /* Calculate the programming word */ - mhz100 = 100000000 / period_in_ps; - mach64MinFreq = MIN_FREQ_2595; - mach64MaxFreq = MAX_FREQ_2595; - mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */ - - /* Calculate program word */ - if (mhz100 == 0) - program_bits = 0xFF; - else { - if (mhz100 < mach64MinFreq) - mhz100 = mach64MinFreq; - if (mhz100 > mach64MaxFreq) - mhz100 = mach64MaxFreq; - - while (mhz100 < (mach64MinFreq << 3)) { - mhz100 <<= 1; - divider += 0x40; - } - - temp = (unsigned int)mhz100; - temp = (unsigned int)(temp * (MIN_N_408 + 2)); - temp -= ((short)(mach64RefFreq << 1)); - - tempA = MIN_N_408; - preRemainder = 0xFFFF; - - do { - tempB = temp; - remainder = tempB % mach64RefFreq; - tempB = tempB / mach64RefFreq; - if (((tempB & 0xFFFF) <= 255) && (remainder <= preRemainder)) { - preRemainder = remainder; - divider &= ~0x3f; - divider |= tempA; - divider = (divider & 0x00FF) + ((tempB & 0xFF) << 8); - } - temp += mhz100; - tempA++; - } while(tempA <= 32); - - program_bits = divider; - } - - pll->program_bits = program_bits; - pll->locationAddr = 0; - pll->post_divider = divider; /* fuer nix */ - pll->period_in_ps = period_in_ps; - - return 0; -} - -static u32 aty_pll_408_to_var(const struct pll_18818 *pll) -{ - return(pll->period_in_ps); /* default for now */ -} - -static void aty_set_pll_408(const struct fb_info_aty *info, - const struct pll_18818 *pll) -{ - u32 program_bits; - u32 locationAddr; - - u8 tmpA, tmpB, tmpC; - char old_crtc_ext_disp; - - old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info); - aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), - info); - - program_bits = pll->program_bits; - locationAddr = pll->locationAddr; - - /* Program clock */ - aty_dac_waste4(info); - tmpB = aty_ld_8(DAC_REGS + 2, info) | 1; - aty_dac_waste4(info); - aty_st_8(DAC_REGS + 2, tmpB, info); - - tmpA = tmpB; - tmpC = tmpA; - tmpA |= 8; - tmpB = 1; - - aty_st_8(DAC_REGS, tmpB, info); - aty_st_8(DAC_REGS + 2, tmpA, info); - - udelay(400); /* delay for 400 us */ - - locationAddr = (locationAddr << 2) + 0x40; - tmpB = locationAddr; - tmpA = program_bits >> 8; - - aty_st_8(DAC_REGS, tmpB, info); - aty_st_8(DAC_REGS + 2, tmpA, info); - - tmpB = locationAddr + 1; - tmpA = (u8)program_bits; - - aty_st_8(DAC_REGS, tmpB, info); - aty_st_8(DAC_REGS + 2, tmpA, info); - - tmpB = locationAddr + 2; - tmpA = 0x77; - - aty_st_8(DAC_REGS, tmpB, info); - aty_st_8(DAC_REGS + 2, tmpA, info); - - udelay(400); /* delay for 400 us */ - tmpA = tmpC & (~(1 | 8)); - tmpB = 1; - - aty_st_8(DAC_REGS, tmpB, info); - aty_st_8(DAC_REGS + 2, tmpA, info); - - (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */ - aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info); - - return; -} - - -static int aty_var_to_pll_1703(u32 period_in_ps, struct pll_18818 *pll) -{ - u32 mhz100; /* in 0.01 MHz */ - u32 program_bits; - /* u32 post_divider; */ - u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq; - u32 temp, tempB; - u16 remainder, preRemainder; - short divider = 0, tempA; - - /* Calculate the programming word */ - mhz100 = 100000000 / period_in_ps; - mach64MinFreq = MIN_FREQ_2595; - mach64MaxFreq = MAX_FREQ_2595; - mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */ - - /* Calculate program word */ - if (mhz100 == 0) - program_bits = 0xE0; - else { - if (mhz100 < mach64MinFreq) - mhz100 = mach64MinFreq; - if (mhz100 > mach64MaxFreq) - mhz100 = mach64MaxFreq; - - divider = 0; - while (mhz100 < (mach64MinFreq << 3)) { - mhz100 <<= 1; - divider += 0x20; - } - - temp = (unsigned int)(mhz100); - temp = (unsigned int)(temp * (MIN_N_1703 + 2)); - temp -= (short)(mach64RefFreq << 1); - - tempA = MIN_N_1703; - preRemainder = 0xffff; - - do { - tempB = temp; - remainder = tempB % mach64RefFreq; - tempB = tempB / mach64RefFreq; - - if ((tempB & 0xffff) <= 127 && (remainder <= preRemainder)) { - preRemainder = remainder; - divider &= ~0x1f; - divider |= tempA; - divider = (divider & 0x00ff) + ((tempB & 0xff) << 8); - } - - temp += mhz100; - tempA++; - } while (tempA <= (MIN_N_1703 << 1)); - - program_bits = divider; - } - - pll->program_bits = program_bits; - pll->locationAddr = 0; - pll->post_divider = divider; /* fuer nix */ - pll->period_in_ps = period_in_ps; - - return 0; -} - -static u32 aty_pll_1703_to_var(const struct pll_18818 *pll) -{ - return(pll->period_in_ps); /* default for now */ -} - -static void aty_set_pll_1703(const struct fb_info_aty *info, - const struct pll_18818 *pll) -{ - u32 program_bits; - u32 locationAddr; - - char old_crtc_ext_disp; - - old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info); - aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), - info); - - program_bits = pll->program_bits; - locationAddr = pll->locationAddr; - - /* Program clock */ - aty_dac_waste4(info); - - (void)aty_ld_8(DAC_REGS + 2, info); - aty_st_8(DAC_REGS+2, (locationAddr << 1) + 0x20, info); - aty_st_8(DAC_REGS+2, 0, info); - aty_st_8(DAC_REGS+2, (program_bits & 0xFF00) >> 8, info); - aty_st_8(DAC_REGS+2, (program_bits & 0xFF), info); - - (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */ - aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info); - - return; -} - - -static int aty_var_to_pll_8398(u32 period_in_ps, struct pll_18818 *pll) -{ - - u32 tempA, tempB, fOut, longMHz100, diff, preDiff; - - u32 mhz100; /* in 0.01 MHz */ - u32 program_bits; - /* u32 post_divider; */ - u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq; - u16 m, n, k=0, save_m, save_n, twoToKth; - - /* Calculate the programming word */ - mhz100 = 100000000 / period_in_ps; - mach64MinFreq = MIN_FREQ_2595; - mach64MaxFreq = MAX_FREQ_2595; - mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */ - - save_m = 0; - save_n = 0; - - /* Calculate program word */ - if (mhz100 == 0) - program_bits = 0xE0; - else - { - if (mhz100 < mach64MinFreq) - mhz100 = mach64MinFreq; - if (mhz100 > mach64MaxFreq) - mhz100 = mach64MaxFreq; - - longMHz100 = mhz100 * 256 / 100; /* 8 bit scale this */ - - while (mhz100 < (mach64MinFreq << 3)) - { - mhz100 <<= 1; - k++; - } - - twoToKth = 1 << k; - diff = 0; - preDiff = 0xFFFFFFFF; - - for (m = MIN_M; m <= MAX_M; m++) - { - for (n = MIN_N; n <= MAX_N; n++) - { - tempA = (14.31818 * 65536); - tempA *= (n + 8); /* 43..256 */ - tempB = twoToKth * 256; - tempB *= (m + 2); /* 4..32 */ - fOut = tempA / tempB; /* 8 bit scale */ - - if (longMHz100 > fOut) - diff = longMHz100 - fOut; - else - diff = fOut - longMHz100; - - if (diff < preDiff) - { - save_m = m; - save_n = n; - preDiff = diff; - } - } - } - - program_bits = (k << 6) + (save_m) + (save_n << 8); - } - - pll->program_bits = program_bits; - pll->locationAddr = 0; - pll->post_divider = 0; - pll->period_in_ps = period_in_ps; - - return 0; -} - -static u32 aty_pll_8398_to_var(const struct pll_18818 *pll) -{ - return(pll->period_in_ps); /* default for now */ -} - -static void aty_set_pll_8398(const struct fb_info_aty *info, - const struct pll_18818 *pll) -{ - u32 program_bits; - u32 locationAddr; - - char old_crtc_ext_disp; - char tmp; - - old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info); - aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), - info); - - program_bits = pll->program_bits; - locationAddr = pll->locationAddr; - - /* Program clock */ - tmp = aty_ld_8(DAC_CNTL, info); - aty_st_8(DAC_CNTL, tmp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, info); - - aty_st_8(DAC_REGS, locationAddr, info); - aty_st_8(DAC_REGS+1, (program_bits & 0xff00) >> 8, info); - aty_st_8(DAC_REGS+1, (program_bits & 0xff), info); - - tmp = aty_ld_8(DAC_CNTL, info); - aty_st_8(DAC_CNTL, (tmp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3, info); - - (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */ - aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info); - - return; -} - - -static int aty_var_to_pll_514(u32 vclk_per, struct pll_gx *pll) -{ - /* - * FIXME: use real calculations instead of using fixed values from the old - * driver - */ - static struct { - u32 limit; /* pixlock rounding limit (arbitrary) */ - u8 m; /* (df<<6) | vco_div_count */ - u8 n; /* ref_div_count */ - } RGB514_clocks[7] = { - { 8000, (3<<6) | 20, 9 }, /* 7395 ps / 135.2273 MHz */ - { 10000, (1<<6) | 19, 3 }, /* 9977 ps / 100.2273 MHz */ - { 13000, (1<<6) | 2, 3 }, /* 12509 ps / 79.9432 MHz */ - { 14000, (2<<6) | 8, 7 }, /* 13394 ps / 74.6591 MHz */ - { 16000, (1<<6) | 44, 6 }, /* 15378 ps / 65.0284 MHz */ - { 25000, (1<<6) | 15, 5 }, /* 17460 ps / 57.2727 MHz */ - { 50000, (0<<6) | 53, 7 }, /* 33145 ps / 30.1705 MHz */ - }; - int i; - - for (i = 0; i < sizeof(RGB514_clocks)/sizeof(*RGB514_clocks); i++) - if (vclk_per <= RGB514_clocks[i].limit) { - pll->m = RGB514_clocks[i].m; - pll->n = RGB514_clocks[i].n; - return 0; - } - return -EINVAL; -} - - -static void aty_StrobeClock(const struct fb_info_aty *info) -{ - u8 tmp; - - udelay(26); - - tmp = aty_ld_8(CLOCK_CNTL, info); - aty_st_8(CLOCK_CNTL + info->clk_wr_offset, tmp | CLOCK_STROBE, info); - - return; -} - - -static void aty_ICS2595_put1bit(u8 data, const struct fb_info_aty *info) -{ - u8 tmp; - - data &= 0x01; - tmp = aty_ld_8(CLOCK_CNTL, info); - aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x04) | (data << 2), - info); - - tmp = aty_ld_8(CLOCK_CNTL, info); - aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x08) | (0 << 3), info); - - aty_StrobeClock(info); - - tmp = aty_ld_8(CLOCK_CNTL, info); - aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x08) | (1 << 3), info); - - aty_StrobeClock(info); - - return; -} - - -static u32 aty_pll_gx_to_var(const struct pll_gx *pll, - const struct fb_info_aty *info) -{ - u8 df, vco_div_count, ref_div_count; - - df = pll->m >> 6; - vco_div_count = pll->m & 0x3f; - ref_div_count = pll->n; - - return ((info->ref_clk_per*ref_div_count)<<(3-df))/(vco_div_count+65); -} - - - /* - * PLL programming (Mach64 CT family) - */ - -static void aty_set_pll_ct(const struct fb_info_aty *info, - const struct pll_ct *pll) -{ - aty_st_pll(PLL_REF_DIV, pll->pll_ref_div, info); - aty_st_pll(PLL_GEN_CNTL, pll->pll_gen_cntl, info); - aty_st_pll(MCLK_FB_DIV, pll->mclk_fb_div, info); - aty_st_pll(PLL_VCLK_CNTL, pll->pll_vclk_cntl, info); - aty_st_pll(VCLK_POST_DIV, pll->vclk_post_div, info); - aty_st_pll(VCLK0_FB_DIV, pll->vclk_fb_div, info); - aty_st_pll(PLL_EXT_CNTL, pll->pll_ext_cntl, info); - - if (!(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID || - Gx == ET_CHIP_ID || - ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07)))) { - if (info->ram_type >= SDRAM) - aty_st_pll(DLL_CNTL, 0xa6, info); - else - aty_st_pll(DLL_CNTL, 0xa0, info); - aty_st_pll(VFC_CNTL, 0x1b, info); - aty_st_le32(DSP_CONFIG, pll->dsp_config, info); - aty_st_le32(DSP_ON_OFF, pll->dsp_on_off, info); - } -} - -static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp, - struct pll_ct *pll) -{ - u32 dsp_xclks_per_row, dsp_loop_latency, dsp_precision, dsp_off, dsp_on; - u32 xclks_per_row, fifo_off, fifo_on, y, fifo_size, page_size; - - /* xclocks_per_row<<11 */ - xclks_per_row = (pll->mclk_fb_div*pll->vclk_post_div_real*64<<11)/ - (pll->vclk_fb_div*pll->mclk_post_div_real*bpp); - if (xclks_per_row < (1<<11)) - FAIL("Dotclock to high"); - if (Gx == GT_CHIP_ID || Gx == GU_CHIP_ID || Gx == VT_CHIP_ID || - Gx == VU_CHIP_ID || Gx == GV_CHIP_ID || Gx == GW_CHIP_ID || - Gx == GZ_CHIP_ID) { - fifo_size = 24; - dsp_loop_latency = 0; - } else { - fifo_size = 32; - dsp_loop_latency = 2; - } - dsp_precision = 0; - y = (xclks_per_row*fifo_size)>>11; - while (y) { - y >>= 1; - dsp_precision++; - } - dsp_precision -= 5; - /* fifo_off<<6 */ - fifo_off = ((xclks_per_row*(fifo_size-1))>>5)+(3<<6); - - if (info->total_vram > 1*1024*1024) { - if (info->ram_type >= SDRAM) { - /* >1 MB SDRAM */ - dsp_loop_latency += 8; - page_size = 8; - } else { - /* >1 MB DRAM */ - dsp_loop_latency += 6; - page_size = 9; - } - } else { - if (info->ram_type >= SDRAM) { - /* <2 MB SDRAM */ - dsp_loop_latency += 9; - page_size = 10; - } else { - /* <2 MB DRAM */ - dsp_loop_latency += 8; - page_size = 10; - } - } - /* fifo_on<<6 */ - if (xclks_per_row >= (page_size<<11)) - fifo_on = ((2*page_size+1)<<6)+(xclks_per_row>>5); - else - fifo_on = (3*page_size+2)<<6; - - dsp_xclks_per_row = xclks_per_row>>dsp_precision; - dsp_on = fifo_on>>dsp_precision; - dsp_off = fifo_off>>dsp_precision; - - pll->dsp_config = (dsp_xclks_per_row & 0x3fff) | - ((dsp_loop_latency & 0xf)<<16) | - ((dsp_precision & 7)<<20); - pll->dsp_on_off = (dsp_on & 0x7ff) | ((dsp_off & 0x7ff)<<16); - return 0; -} - -static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per, - struct pll_ct *pll) -{ - u32 q, x; /* x is a workaround for sparc64-linux-gcc */ - x = x; /* x is a workaround for sparc64-linux-gcc */ - - pll->pll_ref_div = info->pll_per*2*255/info->ref_clk_per; - - /* FIXME: use the VTB/GTB /3 post divider if it's better suited */ - q = info->ref_clk_per*pll->pll_ref_div*4/info->mclk_per; /* actually 8*q */ - if (q < 16*8 || q > 255*8) - FAIL("mclk out of range"); - else if (q < 32*8) - pll->mclk_post_div_real = 8; - else if (q < 64*8) - pll->mclk_post_div_real = 4; - else if (q < 128*8) - pll->mclk_post_div_real = 2; - else - pll->mclk_post_div_real = 1; - pll->mclk_fb_div = q*pll->mclk_post_div_real/8; - - /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */ - q = info->ref_clk_per*pll->pll_ref_div*4/vclk_per; /* actually 8*q */ - if (q < 16*8 || q > 255*8) - FAIL("vclk out of range"); - else if (q < 32*8) - pll->vclk_post_div_real = 8; - else if (q < 64*8) - pll->vclk_post_div_real = 4; - else if (q < 128*8) - pll->vclk_post_div_real = 2; - else - pll->vclk_post_div_real = 1; - pll->vclk_fb_div = q*pll->vclk_post_div_real/8; - return 0; -} - -static void aty_calc_pll_ct(const struct fb_info_aty *info, struct pll_ct *pll) -{ - u8 mpostdiv = 0; - u8 vpostdiv = 0; - - if ((((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID) || - (Gx == GV_CHIP_ID) || (Gx == GW_CHIP_ID) || (Gx == GZ_CHIP_ID) || - (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) || - (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID) || - (Gx == VU_CHIP_ID)) && (info->ram_type >= SDRAM)) - pll->pll_gen_cntl = 0x04; - else - pll->pll_gen_cntl = 0x84; - - switch (pll->mclk_post_div_real) { - case 1: - mpostdiv = 0; - break; - case 2: - mpostdiv = 1; - break; - case 3: - mpostdiv = 4; - break; - case 4: - mpostdiv = 2; - break; - case 8: - mpostdiv = 3; - break; - } - pll->pll_gen_cntl |= mpostdiv<<4; /* mclk */ - - if (Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48)) - pll->pll_ext_cntl = 0; - else - pll->pll_ext_cntl = mpostdiv; /* xclk == mclk */ - - switch (pll->vclk_post_div_real) { - case 2: - vpostdiv = 1; - break; - case 3: - pll->pll_ext_cntl |= 0x10; - case 1: - vpostdiv = 0; - break; - case 6: - pll->pll_ext_cntl |= 0x10; - case 4: - vpostdiv = 2; - break; - case 12: - pll->pll_ext_cntl |= 0x10; - case 8: - vpostdiv = 3; - break; - } - - pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */ - pll->vclk_post_div = vpostdiv; -} - -static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per, - u8 bpp, struct pll_ct *pll) -{ - int err; - - if ((err = aty_valid_pll_ct(info, vclk_per, pll))) - return err; - if (!(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID || - Gx == ET_CHIP_ID || - ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07)))) { - if ((err = aty_dsp_gt(info, bpp, pll))) - return err; - } - aty_calc_pll_ct(info, pll); - return 0; -} - -static u32 aty_pll_ct_to_var(const struct pll_ct *pll, - const struct fb_info_aty *info) -{ - u32 ref_clk_per = info->ref_clk_per; - u8 pll_ref_div = pll->pll_ref_div; - u8 vclk_fb_div = pll->vclk_fb_div; - u8 vclk_post_div = pll->vclk_post_div_real; - - return ref_clk_per*pll_ref_div*vclk_post_div/vclk_fb_div/2; -} - -/* ------------------------------------------------------------------------- */ - -static void atyfb_set_par(const struct atyfb_par *par, - struct fb_info_aty *info) -{ - u32 i; - int accelmode; - int muxmode; - u8 tmp; - - accelmode = par->accel_flags; /* hack */ - - info->current_par = *par; - - if (info->blitter_may_be_busy) - wait_for_idle(info); - tmp = aty_ld_8(CRTC_GEN_CNTL + 3, info); - aty_set_crtc(info, &par->crtc); - aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info); - /* better call aty_StrobeClock ?? */ - aty_st_8(CLOCK_CNTL + info->clk_wr_offset, CLOCK_STROBE, info); - - if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) { - switch (info->dac_subtype) { - case DAC_IBMRGB514: - aty_set_dac_514(info, par->crtc.bpp); - break; - case DAC_ATI68860_B: - case DAC_ATI68860_C: - muxmode = aty_set_dac_ATI68860_B(info, par->crtc.bpp, - accelmode); - aty_st_le32(BUS_CNTL, 0x890e20f1, info); - aty_st_le32(DAC_CNTL, 0x47052100, info); - break; - case DAC_ATT20C408: - muxmode = aty_set_dac_ATT21C498(info, &par->pll.ics2595, - par->crtc.bpp); - aty_st_le32(BUS_CNTL, 0x890e20f1, info); - aty_st_le32(DAC_CNTL, 0x00072000, info); - break; - case DAC_ATT21C498: - muxmode = aty_set_dac_ATT21C498(info, &par->pll.ics2595, - par->crtc.bpp); - aty_st_le32(BUS_CNTL, 0x890e20f1, info); - aty_st_le32(DAC_CNTL, 0x00072000, info); - break; - default: - printk(" atyfb_set_par: DAC type not implemented yet!\n"); - aty_st_le32(BUS_CNTL, 0x890e20f1, info); - aty_st_le32(DAC_CNTL, 0x47052100, info); - /* new in 2.2.3p1 from Geert. ???????? */ - aty_st_le32(BUS_CNTL, 0x590e10ff, info); - aty_st_le32(DAC_CNTL, 0x47012100, info); - break; - } - - switch (info->clk_type) { - case CLK_ATI18818_1: - aty_set_pll18818(info, &par->pll.ics2595); - break; - case CLK_STG1703: - aty_set_pll_1703(info, &par->pll.ics2595); - break; - case CLK_CH8398: - aty_set_pll_8398(info, &par->pll.ics2595); - break; - case CLK_ATT20C408: - aty_set_pll_408(info, &par->pll.ics2595); - break; - case CLK_IBMRGB514: - aty_set_pll_gx(info, &par->pll.gx); - break; - default: - printk(" atyfb_set_par: CLK type not implemented yet!"); - break; - } - - /* Don't forget MEM_CNTL */ - i = aty_ld_le32(MEM_CNTL, info) & 0xf0ffffff; - switch (par->crtc.bpp) { - case 8: - i |= 0x02000000; - break; - case 16: - i |= 0x03000000; - break; - case 32: - i |= 0x06000000; - break; - } - aty_st_le32(MEM_CNTL, i, info); - - } else { - aty_set_pll_ct(info, &par->pll.ct); - i = aty_ld_le32(MEM_CNTL, info) & 0xf00fffff; - if (!(Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48))) - i |= info->mem_refresh_rate << 20; - switch (par->crtc.bpp) { - case 8: - case 24: - i |= 0x00000000; - break; - case 16: - i |= 0x04000000; - break; - case 32: - i |= 0x08000000; - break; - } - if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) { - aty_st_le32(DAC_CNTL, 0x87010184, info); - aty_st_le32(BUS_CNTL, 0x680000f9, info); - } else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID)) { - aty_st_le32(DAC_CNTL, 0x87010184, info); - aty_st_le32(BUS_CNTL, 0x680000f9, info); - } else if ((Gx == LN_CHIP_ID) || (Gx == LM_CHIP_ID)) { - aty_st_le32(DAC_CNTL, 0x80010102, info); - aty_st_le32(BUS_CNTL, 0x7b33a040, info); - } else { - /* GT */ - aty_st_le32(DAC_CNTL, 0x86010102, info); - aty_st_le32(BUS_CNTL, 0x7b23a040, info); - aty_st_le32(EXT_MEM_CNTL, - aty_ld_le32(EXT_MEM_CNTL, info) | 0x5000001, info); - } - aty_st_le32(MEM_CNTL, i, info); - } - aty_st_8(DAC_MASK, 0xff, info); - - /* Initialize the graphics engine */ - if (par->accel_flags & FB_ACCELF_TEXT) - init_engine(par, info); - -#ifdef CONFIG_FB_COMPAT_XPMAC - if (!console_fb_info || console_fb_info == &info->fb_info) { - struct fb_var_screeninfo var; - int vmode, cmode; - display_info.height = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1; - display_info.width = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8; - display_info.depth = par->crtc.bpp; - display_info.pitch = par->crtc.vxres*par->crtc.bpp/8; - atyfb_encode_var(&var, par, info); - if (mac_var_to_vmode(&var, &vmode, &cmode)) - display_info.mode = 0; - else - display_info.mode = vmode; - strcpy(display_info.name, atyfb_name); - display_info.fb_address = info->frame_buffer_phys; - display_info.cmap_adr_address = info->ati_regbase_phys+0xc0; - display_info.cmap_data_address = info->ati_regbase_phys+0xc1; - display_info.disp_reg_address = info->ati_regbase_phys; - } -#endif /* CONFIG_FB_COMPAT_XPMAC */ -} - -static int atyfb_decode_var(const struct fb_var_screeninfo *var, - struct atyfb_par *par, - const struct fb_info_aty *info) -{ - int err; - - if ((err = aty_var_to_crtc(info, var, &par->crtc))) - return err; - if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) - switch (info->clk_type) { - case CLK_ATI18818_1: - err = aty_var_to_pll_18818(var->pixclock, &par->pll.ics2595); - break; - case CLK_STG1703: - err = aty_var_to_pll_1703(var->pixclock, &par->pll.ics2595); - break; - case CLK_CH8398: - err = aty_var_to_pll_8398(var->pixclock, &par->pll.ics2595); - break; - case CLK_ATT20C408: - err = aty_var_to_pll_408(var->pixclock, &par->pll.ics2595); - break; - case CLK_IBMRGB514: - err = aty_var_to_pll_514(var->pixclock, &par->pll.gx); - break; - } - else - err = aty_var_to_pll_ct(info, var->pixclock, par->crtc.bpp, - &par->pll.ct); - if (err) - return err; - - if (var->accel_flags & FB_ACCELF_TEXT) - par->accel_flags = FB_ACCELF_TEXT; - else - par->accel_flags = 0; - -#if 0 /* fbmon is not done. uncomment for 2.5.x -brad */ - if (!fbmon_valid_timings(var->pixclock, htotal, vtotal, info)) - return -EINVAL; -#endif - - return 0; -} - -static int atyfb_encode_var(struct fb_var_screeninfo *var, - const struct atyfb_par *par, - const struct fb_info_aty *info) -{ - int err; - - memset(var, 0, sizeof(struct fb_var_screeninfo)); - - if ((err = aty_crtc_to_var(&par->crtc, var))) - return err; - if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) - switch (info->clk_type) { - case CLK_ATI18818_1: - var->pixclock = aty_pll_18818_to_var(&par->pll.ics2595); - break; - case CLK_STG1703: - var->pixclock = aty_pll_1703_to_var(&par->pll.ics2595); - break; - case CLK_CH8398: - var->pixclock = aty_pll_8398_to_var(&par->pll.ics2595); - break; - case CLK_ATT20C408: - var->pixclock = aty_pll_408_to_var(&par->pll.ics2595); - break; - case CLK_IBMRGB514: - var->pixclock = aty_pll_gx_to_var(&par->pll.gx, info); - break; - } - else - var->pixclock = aty_pll_ct_to_var(&par->pll.ct, info); - - var->height = -1; - var->width = -1; - var->accel_flags = par->accel_flags; - - return 0; -} - - - -static void set_off_pitch(struct atyfb_par *par, - const struct fb_info_aty *info) -{ - u32 xoffset = par->crtc.xoffset; - u32 yoffset = par->crtc.yoffset; - u32 vxres = par->crtc.vxres; - u32 bpp = par->crtc.bpp; - - par->crtc.off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19); - aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, info); -} - - - /* - * Open/Release the frame buffer device - */ - -static int atyfb_open(struct fb_info *info, int user) - -{ -#ifdef __sparc__ - struct fb_info_aty *fb = (struct fb_info_aty *)info; - - if (user) { - fb->open++; - fb->mmaped = 0; - fb->vtconsole = -1; - } else { - fb->consolecnt++; - } -#endif - return(0); -} - -struct fb_var_screeninfo default_var = { - /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ - 640, 480, 640, 480, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2, - 0, FB_VMODE_NONINTERLACED -}; - -static int atyfb_release(struct fb_info *info, int user) -{ -#ifdef __sparc__ - struct fb_info_aty *fb = (struct fb_info_aty *)info; - - if (user) { - fb->open--; - udelay(1000); - wait_for_idle(fb); - if (!fb->open) { - int was_mmaped = fb->mmaped; - - fb->mmaped = 0; - if (fb->vtconsole != -1) - vt_cons[fb->vtconsole]->vc_mode = KD_TEXT; - fb->vtconsole = -1; - - if (was_mmaped) { - struct fb_var_screeninfo var; - - /* Now reset the default display config, we have no - * idea what the program(s) which mmap'd the chip did - * to the configuration, nor whether it restored it - * correctly. - */ - var = default_var; - if (noaccel) - var.accel_flags &= ~FB_ACCELF_TEXT; - else - var.accel_flags |= FB_ACCELF_TEXT; - if (var.yres == var.yres_virtual) { - u32 vram = (fb->total_vram - (PAGE_SIZE << 2)); - var.yres_virtual = ((vram * 8) / var.bits_per_pixel) / - var.xres_virtual; - if (var.yres_virtual < var.yres) - var.yres_virtual = var.yres; - } - atyfb_set_var(&var, -1, &fb->fb_info); - } - } - } else { - fb->consolecnt--; - } -#endif - return(0); -} - - -static int encode_fix(struct fb_fix_screeninfo *fix, - const struct atyfb_par *par, - const struct fb_info_aty *info) -{ - memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - - strcpy(fix->id, atyfb_name); - fix->smem_start = info->frame_buffer_phys; - fix->smem_len = (u32)info->total_vram; - - /* - * Reg Block 0 (CT-compatible block) is at ati_regbase_phys - * Reg Block 1 (multimedia extensions) is at ati_regbase_phys-0x400 - */ - if (Gx == GX_CHIP_ID || Gx == CX_CHIP_ID) { - fix->mmio_start = info->ati_regbase_phys; - fix->mmio_len = 0x400; - fix->accel = FB_ACCEL_ATI_MACH64GX; - } else if (Gx == CT_CHIP_ID || Gx == ET_CHIP_ID) { - fix->mmio_start = info->ati_regbase_phys; - fix->mmio_len = 0x400; - fix->accel = FB_ACCEL_ATI_MACH64CT; - } else if (Gx == VT_CHIP_ID || Gx == VU_CHIP_ID || Gx == VV_CHIP_ID) { - fix->mmio_start = info->ati_regbase_phys-0x400; - fix->mmio_len = 0x800; - fix->accel = FB_ACCEL_ATI_MACH64VT; - } else { - fix->mmio_start = info->ati_regbase_phys-0x400; - fix->mmio_len = 0x800; - fix->accel = FB_ACCEL_ATI_MACH64GT; - } - fix->type = FB_TYPE_PACKED_PIXELS; - fix->type_aux = 0; - fix->line_length = par->crtc.vxres*par->crtc.bpp/8; - fix->visual = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR - : FB_VISUAL_DIRECTCOLOR; - fix->ywrapstep = 0; - fix->xpanstep = 8; - fix->ypanstep = 1; - - return 0; -} - - - /* - * Get the Fixed Part of the Display - */ - -static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *fb) -{ - const struct fb_info_aty *info = (struct fb_info_aty *)fb; - struct atyfb_par par; - - if (con == -1) - par = info->default_par; - else - atyfb_decode_var(&fb_display[con].var, &par, info); - encode_fix(fix, &par, info); - return 0; -} - - - /* - * Get the User Defined Part of the Display - */ - -static int atyfb_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *fb) -{ - const struct fb_info_aty *info = (struct fb_info_aty *)fb; - - if (con == -1) - atyfb_encode_var(var, &info->default_par, info); - else - *var = fb_display[con].var; - return 0; -} - - -static void atyfb_set_dispsw(struct display *disp, struct fb_info_aty *info, - int bpp, int accel) -{ - switch (bpp) { -#ifdef FBCON_HAS_CFB8 - case 8: - info->dispsw = accel ? fbcon_aty8 : fbcon_cfb8; - disp->dispsw = &info->dispsw; - break; -#endif -#ifdef FBCON_HAS_CFB16 - case 16: - info->dispsw = accel ? fbcon_aty16 : fbcon_cfb16; - disp->dispsw = &info->dispsw; - disp->dispsw_data = info->fbcon_cmap.cfb16; - break; -#endif -#ifdef FBCON_HAS_CFB24 - case 24: - info->dispsw = accel ? fbcon_aty24 : fbcon_cfb24; - disp->dispsw = &info->dispsw; - disp->dispsw_data = info->fbcon_cmap.cfb24; - break; -#endif -#ifdef FBCON_HAS_CFB32 - case 32: - info->dispsw = accel ? fbcon_aty32 : fbcon_cfb32; - disp->dispsw = &info->dispsw; - disp->dispsw_data = info->fbcon_cmap.cfb32; - break; -#endif - default: - disp->dispsw = &fbcon_dummy; - } - if (info->cursor) { - info->dispsw.cursor = atyfb_cursor; - info->dispsw.set_font = atyfb_set_font; - } -} - - - /* - * Set the User Defined Part of the Display - */ - -static int atyfb_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *fb) -{ - struct fb_info_aty *info = (struct fb_info_aty *)fb; - struct atyfb_par par; - struct display *display; - int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err; - int activate = var->activate; - - if (con >= 0) - display = &fb_display[con]; - else - display = fb->disp; /* used during initialization */ - - if ((err = atyfb_decode_var(var, &par, info))) - return err; - - atyfb_encode_var(var, &par, (struct fb_info_aty *)info); - - if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { - oldxres = display->var.xres; - oldyres = display->var.yres; - oldvxres = display->var.xres_virtual; - oldvyres = display->var.yres_virtual; - oldbpp = display->var.bits_per_pixel; - oldaccel = display->var.accel_flags; - display->var = *var; - accel = var->accel_flags & FB_ACCELF_TEXT; - if (oldxres != var->xres || oldyres != var->yres || - oldvxres != var->xres_virtual || oldvyres != var->yres_virtual || - oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) { - struct fb_fix_screeninfo fix; - - encode_fix(&fix, &par, info); - display->screen_base = (char *)info->frame_buffer; - display->visual = fix.visual; - display->type = fix.type; - display->type_aux = fix.type_aux; - display->ypanstep = fix.ypanstep; - display->ywrapstep = fix.ywrapstep; - display->line_length = fix.line_length; - display->can_soft_blank = 1; - display->inverse = 0; - if (accel) - display->scrollmode = (info->bus_type == PCI) ? SCROLL_YNOMOVE : 0; - else - display->scrollmode = SCROLL_YREDRAW; - if (info->fb_info.changevar) - (*info->fb_info.changevar)(con); - } - if (!info->fb_info.display_fg || - info->fb_info.display_fg->vc_num == con) { - atyfb_set_par(&par, info); - atyfb_set_dispsw(display, info, par.crtc.bpp, accel); - } - if (oldbpp != var->bits_per_pixel) { - if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) - return err; - do_install_cmap(con, &info->fb_info); - } - } - - return 0; -} - - - /* - * Pan or Wrap the Display - * - * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag - */ - -static int atyfb_pan_display(struct fb_var_screeninfo *var, int con, - struct fb_info *fb) -{ - struct fb_info_aty *info = (struct fb_info_aty *)fb; - u32 xres, yres, xoffset, yoffset; - struct atyfb_par *par = &info->current_par; - - xres = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8; - yres = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1; - xoffset = (var->xoffset+7) & ~7; - yoffset = var->yoffset; - if (xoffset+xres > par->crtc.vxres || yoffset+yres > par->crtc.vyres) - return -EINVAL; - par->crtc.xoffset = xoffset; - par->crtc.yoffset = yoffset; - set_off_pitch(par, info); - return 0; -} - - /* - * Get the Colormap - */ - -static int atyfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) -{ - if (!info->display_fg || con == info->display_fg->vc_num) /* current console? */ - return fb_get_cmap(cmap, kspc, atyfb_getcolreg, info); - else if (fb_display[con].cmap.len) /* non default colormap? */ - fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); - else { - int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; - fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2); - } - return 0; -} - - /* - * Set the Colormap - */ - -static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) -{ - int err; - struct display *disp; - - if (con >= 0) - disp = &fb_display[con]; - else - disp = info->disp; - if (!disp->cmap.len) { /* no colormap allocated? */ - int size = disp->var.bits_per_pixel == 16 ? 32 : 256; - if ((err = fb_alloc_cmap(&disp->cmap, size, 0))) - return err; - } - if (!info->display_fg || con == info->display_fg->vc_num) /* current console? */ - return fb_set_cmap(cmap, kspc, atyfb_setcolreg, info); - else - fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1); - return 0; -} - - -#ifdef DEBUG -#define ATYIO_CLKR 0x41545900 /* ATY\00 */ -#define ATYIO_CLKW 0x41545901 /* ATY\01 */ - -struct atyclk { - u32 ref_clk_per; - u8 pll_ref_div; - u8 mclk_fb_div; - u8 mclk_post_div; /* 1,2,3,4,8 */ - u8 vclk_fb_div; - u8 vclk_post_div; /* 1,2,3,4,6,8,12 */ - u32 dsp_xclks_per_row; /* 0-16383 */ - u32 dsp_loop_latency; /* 0-15 */ - u32 dsp_precision; /* 0-7 */ - u32 dsp_on; /* 0-2047 */ - u32 dsp_off; /* 0-2047 */ -}; -#endif - -static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg, int con, struct fb_info *info2) -{ -#if defined(__sparc__) || defined(DEBUG) - struct fb_info_aty *info = (struct fb_info_aty *)info2; -#endif /* __sparc__ || DEBUG */ -#ifdef __sparc__ - struct fbtype fbtyp; - struct display *disp; - - if (con >= 0) - disp = &fb_display[con]; - else - disp = info2->disp; -#endif - - switch (cmd) { -#ifdef __sparc__ - case FBIOGTYPE: - fbtyp.fb_type = FBTYPE_PCI_GENERIC; - fbtyp.fb_width = info->current_par.crtc.vxres; - fbtyp.fb_height = info->current_par.crtc.vyres; - fbtyp.fb_depth = info->current_par.crtc.bpp; - fbtyp.fb_cmsize = disp->cmap.len; - fbtyp.fb_size = info->total_vram; - if (copy_to_user((struct fbtype *)arg, &fbtyp, sizeof(fbtyp))) - return -EFAULT; - break; -#endif /* __sparc__ */ -#ifdef DEBUG - case ATYIO_CLKR: - if ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) { - struct atyclk clk; - struct pll_ct *pll = &info->current_par.pll.ct; - u32 dsp_config = pll->dsp_config; - u32 dsp_on_off = pll->dsp_on_off; - clk.ref_clk_per = info->ref_clk_per; - clk.pll_ref_div = pll->pll_ref_div; - clk.mclk_fb_div = pll->mclk_fb_div; - clk.mclk_post_div = pll->mclk_post_div_real; - clk.vclk_fb_div = pll->vclk_fb_div; - clk.vclk_post_div = pll->vclk_post_div_real; - clk.dsp_xclks_per_row = dsp_config & 0x3fff; - clk.dsp_loop_latency = (dsp_config>>16) & 0xf; - clk.dsp_precision = (dsp_config>>20) & 7; - clk.dsp_on = dsp_on_off & 0x7ff; - clk.dsp_off = (dsp_on_off>>16) & 0x7ff; - if (copy_to_user((struct atyclk *)arg, &clk, sizeof(clk))) - return -EFAULT; - } else - return -EINVAL; - break; - case ATYIO_CLKW: - if ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) { - struct atyclk clk; - struct pll_ct *pll = &info->current_par.pll.ct; - if (copy_from_user(&clk, (struct atyclk *)arg, sizeof(clk))) - return -EFAULT; - info->ref_clk_per = clk.ref_clk_per; - pll->pll_ref_div = clk.pll_ref_div; - pll->mclk_fb_div = clk.mclk_fb_div; - pll->mclk_post_div_real = clk.mclk_post_div; - pll->vclk_fb_div = clk.vclk_fb_div; - pll->vclk_post_div_real = clk.vclk_post_div; - pll->dsp_config = (clk.dsp_xclks_per_row & 0x3fff) | - ((clk.dsp_loop_latency & 0xf)<<16) | - ((clk.dsp_precision & 7)<<20); - pll->dsp_on_off = (clk.dsp_on & 0x7ff) | - ((clk.dsp_off & 0x7ff)<<16); - aty_calc_pll_ct(info, pll); - aty_set_pll_ct(info, pll); - } else - return -EINVAL; - break; -#endif /* DEBUG */ - default: - return -EINVAL; - } - return 0; -} - -static int atyfb_rasterimg(struct fb_info *info, int start) -{ - struct fb_info_aty *fb = (struct fb_info_aty *)info; - - if (fb->blitter_may_be_busy) - wait_for_idle(fb); - return 0; -} - -#ifdef __sparc__ -static int atyfb_mmap(struct fb_info *info, struct file *file, - struct vm_area_struct *vma) -{ - struct fb_info_aty *fb = (struct fb_info_aty *)info; - unsigned int size, page, map_size = 0; - unsigned long map_offset = 0; - unsigned long off; - int i; - - if (!fb->mmap_map) - return -ENXIO; - - if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) - return -EINVAL; - - off = vma->vm_pgoff << PAGE_SHIFT; - size = vma->vm_end - vma->vm_start; - - /* To stop the swapper from even considering these pages. */ - vma->vm_flags |= (VM_SHM | VM_LOCKED); - - if (((vma->vm_pgoff == 0) && (size == fb->total_vram)) || - ((off == fb->total_vram) && (size == PAGE_SIZE))) - off += 0x8000000000000000UL; - - vma->vm_pgoff = off >> PAGE_SHIFT; /* propagate off changes */ - -#ifdef __sparc_v9__ - /* Align it as much as desirable */ - { - unsigned long j, align; - int max = -1; - - map_offset = off + size; - for (i = 0; fb->mmap_map[i].size; i++) { - if (fb->mmap_map[i].voff < off) - continue; - if (fb->mmap_map[i].voff >= map_offset) - break; - if (max < 0 || - fb->mmap_map[i].size > fb->mmap_map[max].size) - max = i; - } - if (max >= 0) { - j = fb->mmap_map[max].size; - if (fb->mmap_map[max].voff + j > map_offset) - j = map_offset - fb->mmap_map[max].voff; - for (align = 0x400000; align > PAGE_SIZE; align >>= 3) - if (j >= align && - !(fb->mmap_map[max].poff & (align - 1))) - break; - if (align > PAGE_SIZE) { - j = align; - align = j - ((vma->vm_start - + fb->mmap_map[max].voff - - off) & (j - 1)); - if (align != j) { - struct vm_area_struct *vmm; - - vmm = find_vma(current->mm, - vma->vm_start); - if (!vmm || vmm->vm_start - >= vma->vm_end + align) { - vma->vm_start += align; - vma->vm_end += align; - } - } - } - } - } -#endif - - /* Each page, see which map applies */ - for (page = 0; page < size; ) { - map_size = 0; - for (i = 0; fb->mmap_map[i].size; i++) { - unsigned long start = fb->mmap_map[i].voff; - unsigned long end = start + fb->mmap_map[i].size; - unsigned long offset = off + page; - - if (start > offset) - continue; - if (offset >= end) - continue; - - map_size = fb->mmap_map[i].size - (offset - start); - map_offset = fb->mmap_map[i].poff + (offset - start); - break; - } - if (!map_size) { - page += PAGE_SIZE; - continue; - } - if (page + map_size > size) - map_size = size - page; - - pgprot_val(vma->vm_page_prot) &= ~(fb->mmap_map[i].prot_mask); - pgprot_val(vma->vm_page_prot) |= fb->mmap_map[i].prot_flag; - - if (remap_page_range(vma->vm_start + page, map_offset, - map_size, vma->vm_page_prot)) - return -EAGAIN; - - page += map_size; - } - - if (!map_size) - return -EINVAL; - - vma->vm_flags |= VM_IO; - - if (!fb->mmaped) { - int lastconsole = 0; - - if (info->display_fg) - lastconsole = info->display_fg->vc_num; - fb->mmaped = 1; - if (fb->consolecnt && fb_display[lastconsole].fb_info == info) { - fb->vtconsole = lastconsole; - vt_cons[lastconsole]->vc_mode = KD_GRAPHICS; - } - } - return 0; -} - -static struct { - u32 yoffset; - u8 r[2][256]; - u8 g[2][256]; - u8 b[2][256]; -} atyfb_save; - -static void atyfb_save_palette(struct fb_info *fb, int enter) -{ - struct fb_info_aty *info = (struct fb_info_aty *)fb; - int i, tmp, scale; - - for (i = 0; i < 256; i++) { - tmp = aty_ld_8(DAC_CNTL, info) & 0xfc; - if (Gx == GT_CHIP_ID || Gx == GU_CHIP_ID || Gx == GV_CHIP_ID || - Gx == GW_CHIP_ID || Gx == GZ_CHIP_ID || Gx == LG_CHIP_ID || - Gx == GB_CHIP_ID || Gx == GD_CHIP_ID || Gx == GI_CHIP_ID || - Gx == GP_CHIP_ID || Gx == GQ_CHIP_ID) - tmp |= 0x2; - aty_st_8(DAC_CNTL, tmp, info); - aty_st_8(DAC_MASK, 0xff, info); - - scale = ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID) && - (info->current_par.crtc.bpp == 16)) ? 3 : 0; - writeb(i << scale, &info->aty_cmap_regs->rindex); - - atyfb_save.r[enter][i] = readb(&info->aty_cmap_regs->lut); - atyfb_save.g[enter][i] = readb(&info->aty_cmap_regs->lut); - atyfb_save.b[enter][i] = readb(&info->aty_cmap_regs->lut); - writeb(i << scale, &info->aty_cmap_regs->windex); - writeb(atyfb_save.r[1-enter][i], &info->aty_cmap_regs->lut); - writeb(atyfb_save.g[1-enter][i], &info->aty_cmap_regs->lut); - writeb(atyfb_save.b[1-enter][i], &info->aty_cmap_regs->lut); - } -} - -static void atyfb_palette(int enter) -{ - struct fb_info_aty *info; - struct atyfb_par *par; - struct display *d; - int i; - - for (i = 0; i < MAX_NR_CONSOLES; i++) { - d = &fb_display[i]; - if (d->fb_info && - d->fb_info->fbops == &atyfb_ops && - d->fb_info->display_fg && - d->fb_info->display_fg->vc_num == i) { - atyfb_save_palette(d->fb_info, enter); - info = (struct fb_info_aty *)d->fb_info; - par = &info->current_par; - if (enter) { - atyfb_save.yoffset = par->crtc.yoffset; - par->crtc.yoffset = 0; - set_off_pitch(par, info); - } else { - par->crtc.yoffset = atyfb_save.yoffset; - set_off_pitch(par, info); - } - break; - } - } -} -#endif /* __sparc__ */ - - /* - * Initialisation - */ - -static int __init aty_init(struct fb_info_aty *info, const char *name) -{ - u32 chip_id; - u32 i; - int j, k; - struct fb_var_screeninfo var; - struct display *disp; - const char *chipname = NULL, *ramname = NULL, *xtal; - int pll, mclk, gtb_memsize; -#if defined(CONFIG_PPC) - int sense; -#endif - u8 pll_ref_div; - - info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0); - chip_id = aty_ld_le32(CONFIG_CHIP_ID, info); - Gx = chip_id & CFG_CHIP_TYPE; - Rev = (chip_id & CFG_CHIP_REV)>>24; - for (j = 0; j < (sizeof(aty_features)/sizeof(*aty_features)); j++) - if (aty_features[j].chip_type == Gx) { - chipname = aty_features[j].name; - info->dac_type = (aty_ld_le32(DAC_CNTL, info) >> 16) & 0x07; - break; - } - if (!chipname) { - printk("atyfb: Unknown mach64 0x%04x\n", Gx); - return 0; - } else - printk("atyfb: %s [0x%04x rev 0x%02x] ", chipname, Gx, Rev); - if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) { - info->bus_type = (aty_ld_le32(CONFIG_STAT0, info) >> 0) & 0x07; - info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) >> 3) & 0x07; - ramname = aty_gx_ram[info->ram_type]; - /* FIXME: clockchip/RAMDAC probing? */ -#ifdef CONFIG_ATARI - info->clk_type = CLK_ATI18818_1; - info->dac_type = (aty_ld_le32(CONFIG_STAT0, info) >> 9) & 0x07; - if (info->dac_type == 0x07) - info->dac_subtype = DAC_ATT20C408; - else - info->dac_subtype = (aty_ld_8(SCRATCH_REG1 + 1, info) & 0xF0) | - info->dac_type; -#else - info->dac_type = DAC_IBMRGB514; - info->dac_subtype = DAC_IBMRGB514; - info->clk_type = CLK_IBMRGB514; -#endif - /* FIXME */ - pll = 135; - mclk = 50; - } else { - info->bus_type = PCI; - info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) & 0x07); - ramname = aty_ct_ram[info->ram_type]; - info->dac_type = DAC_INTERNAL; - info->dac_subtype = DAC_INTERNAL; - info->clk_type = CLK_INTERNAL; - if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) { - pll = 135; - mclk = 60; - } else { - mclk = info->ram_type >= SDRAM ? 67 : 63; - if ((Gx == VT_CHIP_ID) && (Rev == 0x08)) { - /* VTA3 */ - pll = 170; - } else if (((Gx == VT_CHIP_ID) && ((Rev == 0x40) || - (Rev == 0x48))) || - ((Gx == VT_CHIP_ID) && ((Rev == 0x01) || - (Rev == 0x9a))) || - Gx == VU_CHIP_ID) { - /* VTA4 or VTB */ - pll = 200; - } else if (Gx == VV_CHIP_ID) { - /* VT4 */ - pll = 230; - mclk = 83; - } else if (Gx == VT_CHIP_ID) { - /* other VT */ - pll = 135; - mclk = 63; - } else if ((Gx == GT_CHIP_ID) && (Rev & 0x01)) { - /* RAGE II */ - pll = 170; - } else if (((Gx == GT_CHIP_ID) && (Rev & 0x02)) || - (Gx == GU_CHIP_ID)) { - /* RAGE II+ */ - pll = 200; - } else if (Gx == GV_CHIP_ID || Gx == GW_CHIP_ID || - Gx == GZ_CHIP_ID) { - /* RAGE IIC */ - pll = 230; - mclk = 83; - } else if (Gx == GB_CHIP_ID || Gx == GD_CHIP_ID || - Gx == GI_CHIP_ID || Gx == GP_CHIP_ID || - Gx == GQ_CHIP_ID || Gx == LB_CHIP_ID || - Gx == LD_CHIP_ID || - Gx == LI_CHIP_ID || Gx == LP_CHIP_ID) { - /* RAGE PRO or LT PRO */ - pll = 230; - mclk = 100; - } else if (Gx == LG_CHIP_ID) { - /* Rage LT */ - pll = 230; - mclk = 63; - } else if ((Gx == LN_CHIP_ID) || (Gx == LM_CHIP_ID)) { - /* Rage mobility M1 */ - pll = 230; - mclk = 50; - } else { - /* other RAGE */ - pll = 135; - mclk = 63; - } - } - } - - info->ref_clk_per = 1000000000000ULL/14318180; - xtal = "14.31818"; - if (!(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID || - Gx == ET_CHIP_ID || - ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07))) && - (pll_ref_div = aty_ld_pll(PLL_REF_DIV, info))) { - int diff1, diff2; - diff1 = 510*14/pll_ref_div-pll; - diff2 = 510*29/pll_ref_div-pll; - if (diff1 < 0) - diff1 = -diff1; - if (diff2 < 0) - diff2 = -diff2; - if (diff2 < diff1) { - info->ref_clk_per = 1000000000000ULL/29498928; - xtal = "29.498928"; - } - } - - i = aty_ld_le32(MEM_CNTL, info); - gtb_memsize = !(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID || - Gx == ET_CHIP_ID || - ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07))); - if (gtb_memsize) - switch (i & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */ - case MEM_SIZE_512K: - info->total_vram = 0x80000; - break; - case MEM_SIZE_1M: - info->total_vram = 0x100000; - break; - case MEM_SIZE_2M_GTB: - info->total_vram = 0x200000; - break; - case MEM_SIZE_4M_GTB: - info->total_vram = 0x400000; - break; - case MEM_SIZE_6M_GTB: - info->total_vram = 0x600000; - break; - case MEM_SIZE_8M_GTB: - info->total_vram = 0x800000; - break; - default: - info->total_vram = 0x80000; - } - else - switch (i & MEM_SIZE_ALIAS) { - case MEM_SIZE_512K: - info->total_vram = 0x80000; - break; - case MEM_SIZE_1M: - info->total_vram = 0x100000; - break; - case MEM_SIZE_2M: - info->total_vram = 0x200000; - break; - case MEM_SIZE_4M: - info->total_vram = 0x400000; - break; - case MEM_SIZE_6M: - info->total_vram = 0x600000; - break; - case MEM_SIZE_8M: - info->total_vram = 0x800000; - break; - default: - info->total_vram = 0x80000; - } - - if (Gx == GI_CHIP_ID) { - if (aty_ld_le32(CONFIG_STAT1, info) & 0x40000000) - info->total_vram += 0x400000; - } - - if (default_vram) { - info->total_vram = default_vram*1024; - i = i & ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS); - if (info->total_vram <= 0x80000) - i |= MEM_SIZE_512K; - else if (info->total_vram <= 0x100000) - i |= MEM_SIZE_1M; - else if (info->total_vram <= 0x200000) - i |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M; - else if (info->total_vram <= 0x400000) - i |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M; - else if (info->total_vram <= 0x600000) - i |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M; - else - i |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M; - aty_st_le32(MEM_CNTL, i, info); - } - if (default_pll) - pll = default_pll; - if (default_mclk) - mclk = default_mclk; - - printk("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK\n", - info->total_vram == 0x80000 ? 512 : (info->total_vram >> 20), - info->total_vram == 0x80000 ? 'K' : 'M', ramname, xtal, pll, mclk); - - if (mclk < 44) - info->mem_refresh_rate = 0; /* 000 = 10 Mhz - 43 Mhz */ - else if (mclk < 50) - info->mem_refresh_rate = 1; /* 001 = 44 Mhz - 49 Mhz */ - else if (mclk < 55) - info->mem_refresh_rate = 2; /* 010 = 50 Mhz - 54 Mhz */ - else if (mclk < 66) - info->mem_refresh_rate = 3; /* 011 = 55 Mhz - 65 Mhz */ - else if (mclk < 75) - info->mem_refresh_rate = 4; /* 100 = 66 Mhz - 74 Mhz */ - else if (mclk < 80) - info->mem_refresh_rate = 5; /* 101 = 75 Mhz - 79 Mhz */ - else if (mclk < 100) - info->mem_refresh_rate = 6; /* 110 = 80 Mhz - 100 Mhz */ - else - info->mem_refresh_rate = 7; /* 111 = 100 Mhz and above */ - info->pll_per = 1000000/pll; - info->mclk_per = 1000000/mclk; - -#ifdef DEBUG - if ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) { - int i; - printk("BUS_CNTL DAC_CNTL MEM_CNTL EXT_MEM_CNTL CRTC_GEN_CNTL " - "DSP_CONFIG DSP_ON_OFF\n" - "%08x %08x %08x %08x %08x %08x %08x\n" - "PLL", - aty_ld_le32(BUS_CNTL, info), aty_ld_le32(DAC_CNTL, info), - aty_ld_le32(MEM_CNTL, info), aty_ld_le32(EXT_MEM_CNTL, info), - aty_ld_le32(CRTC_GEN_CNTL, info), aty_ld_le32(DSP_CONFIG, info), - aty_ld_le32(DSP_ON_OFF, info)); - for (i = 0; i < 16; i++) - printk(" %02x", aty_ld_pll(i, info)); - printk("\n"); - } -#endif - - /* - * Last page of 8 MB (4 MB on ISA) aperture is MMIO - * FIXME: we should use the auxiliary aperture instead so we can acces the - * full 8 MB of video RAM on 8 MB boards - */ - if (info->total_vram == 0x800000 || - (info->bus_type == ISA && info->total_vram == 0x400000)) - info->total_vram -= GUI_RESERVE; - - /* Clear the video memory */ - fb_memset((void *)info->frame_buffer, 0, info->total_vram); - - disp = &info->disp; - - strcpy(info->fb_info.modename, atyfb_name); - info->fb_info.node = -1; - info->fb_info.fbops = &atyfb_ops; - info->fb_info.disp = disp; - strcpy(info->fb_info.fontname, fontname); - info->fb_info.changevar = NULL; - info->fb_info.switch_con = &atyfbcon_switch; - info->fb_info.updatevar = &atyfbcon_updatevar; - info->fb_info.blank = &atyfbcon_blank; - info->fb_info.flags = FBINFO_FLAG_DEFAULT; - -#ifdef CONFIG_PMAC_BACKLIGHT - if (Gx == LI_CHIP_ID && machine_is_compatible("PowerBook1,1")) { - /* these bits let the 101 powerbook wake up from sleep -- paulus */ - aty_st_lcd(LCD_POWER_MANAGEMENT, aty_ld_lcd(LCD_POWER_MANAGEMENT, info) - | (USE_F32KHZ | TRISTATE_MEM_EN), info); - } - if ((Gx == LN_CHIP_ID) || (Gx == LM_CHIP_ID)) - register_backlight_controller(&aty_backlight_controller, info, "ati"); -#endif /* CONFIG_PMAC_BACKLIGHT */ - -#ifdef MODULE - var = default_var; -#else /* !MODULE */ - memset(&var, 0, sizeof(var)); -#ifdef CONFIG_PPC - if (_machine == _MACH_Pmac) { - /* - * FIXME: The NVRAM stuff should be put in a Mac-specific file, as it - * applies to all Mac video cards - */ - if (mode_option) { - if (!mac_find_mode(&var, &info->fb_info, mode_option, 8)) - var = default_var; - } else { -#ifdef CONFIG_NVRAM - if (default_vmode == VMODE_NVRAM) { - default_vmode = nvram_read_byte(NV_VMODE); - if (default_vmode <= 0 || default_vmode > VMODE_MAX) - default_vmode = VMODE_CHOOSE; - } -#endif - if (default_vmode == VMODE_CHOOSE) { - if (Gx == LG_CHIP_ID || Gx == LI_CHIP_ID) - /* G3 PowerBook with 1024x768 LCD */ - default_vmode = VMODE_1024_768_60; - else if (machine_is_compatible("iMac")) - default_vmode = VMODE_1024_768_75; - else if (machine_is_compatible("PowerBook2,1")) - /* iBook with 800x600 LCD */ - default_vmode = VMODE_800_600_60; - else - default_vmode = VMODE_640_480_67; - sense = read_aty_sense(info); - printk(KERN_INFO "atyfb: monitor sense=%x, mode %d\n", - sense, mac_map_monitor_sense(sense)); - } - if (default_vmode <= 0 || default_vmode > VMODE_MAX) - default_vmode = VMODE_640_480_60; -#ifdef CONFIG_NVRAM - if (default_cmode == CMODE_NVRAM) - default_cmode = nvram_read_byte(NV_CMODE); -#endif - if (default_cmode < CMODE_8 || default_cmode > CMODE_32) - default_cmode = CMODE_8; - if (mac_vmode_to_var(default_vmode, default_cmode, &var)) - var = default_var; - } - } - else if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, NULL, 8)) - var = default_var; -#else /* !CONFIG_PPC */ -#ifdef __sparc__ - if (mode_option) { - if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, NULL, 8)) - var = default_var; - } else - var = default_var; -#else - if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, NULL, 8)) - var = default_var; -#endif /* !__sparc__ */ -#endif /* !CONFIG_PPC */ -#endif /* !MODULE */ - if (noaccel) - var.accel_flags &= ~FB_ACCELF_TEXT; - else - var.accel_flags |= FB_ACCELF_TEXT; - - if (var.yres == var.yres_virtual) { - u32 vram = (info->total_vram - (PAGE_SIZE << 2)); - var.yres_virtual = ((vram * 8) / var.bits_per_pixel) / var.xres_virtual; - if (var.yres_virtual < var.yres) - var.yres_virtual = var.yres; - } - - if (atyfb_decode_var(&var, &info->default_par, info)) { - printk("atyfb: can't set default video mode\n"); - return 0; - } - -#ifdef __sparc__ - atyfb_save_palette(&info->fb_info, 0); -#endif - for (j = 0; j < 16; j++) { - k = color_table[j]; - info->palette[j].red = default_red[k]; - info->palette[j].green = default_grn[k]; - info->palette[j].blue = default_blu[k]; - } - - if (Gx != GX_CHIP_ID && Gx != CX_CHIP_ID) { - info->cursor = aty_init_cursor(info); - if (info->cursor) { - info->dispsw.cursor = atyfb_cursor; - info->dispsw.set_font = atyfb_set_font; - } - } - - atyfb_set_var(&var, -1, &info->fb_info); - - if (register_framebuffer(&info->fb_info) < 0) - return 0; - - info->next = fb_list; - fb_list = info; - - printk("fb%d: %s frame buffer device on %s\n", - GET_FB_IDX(info->fb_info.node), atyfb_name, name); - return 1; -} - -int __init atyfb_init(void) -{ -#if defined(CONFIG_PCI) - struct pci_dev *pdev = NULL; - struct fb_info_aty *info; - unsigned long addr, res_start, res_size; - int i; -#ifdef __sparc__ - extern void (*prom_palette) (int); - extern int con_is_present(void); - struct pcidev_cookie *pcp; - char prop[128]; - int node, len, j; - u32 mem, chip_id; - - /* Do not attach when we have a serial console. */ - if (!con_is_present()) - return -ENXIO; -#else - u16 tmp; -#endif - - while ((pdev = pci_find_device(PCI_VENDOR_ID_ATI, PCI_ANY_ID, pdev))) { - if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { - struct resource *rp; - - for (i = sizeof(aty_features)/sizeof(*aty_features)-1; i >= 0; i--) - if (pdev->device == aty_features[i].pci_id) - break; - if (i < 0) - continue; - - info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC); - if (!info) { - printk("atyfb_init: can't alloc fb_info_aty\n"); - return -ENXIO; - } - memset(info, 0, sizeof(struct fb_info_aty)); - - rp = &pdev->resource[0]; - if (rp->flags & IORESOURCE_IO) - rp = &pdev->resource[1]; - addr = rp->start; - if (!addr) - continue; - - res_start = rp->start; - res_size = rp->end-rp->start+1; - if (!request_mem_region(res_start, res_size, "atyfb")) - continue; - -#ifdef __sparc__ - /* - * Map memory-mapped registers. - */ - info->ati_regbase = addr + 0x7ffc00UL; - info->ati_regbase_phys = addr + 0x7ffc00UL; - - /* - * Map in big-endian aperture. - */ - info->frame_buffer = (unsigned long) addr + 0x800000UL; - info->frame_buffer_phys = addr + 0x800000UL; - - /* - * Figure mmap addresses from PCI config space. - * Split Framebuffer in big- and little-endian halfs. - */ - for (i = 0; i < 6 && pdev->resource[i].start; i++) - /* nothing */; - j = i + 4; - - info->mmap_map = kmalloc(j * sizeof(*info->mmap_map), GFP_ATOMIC); - if (!info->mmap_map) { - printk("atyfb_init: can't alloc mmap_map\n"); - kfree(info); - release_mem_region(res_start, res_size); - return -ENXIO; - } - memset(info->mmap_map, 0, j * sizeof(*info->mmap_map)); - - for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) { - struct resource *rp = &pdev->resource[i]; - int io, breg = PCI_BASE_ADDRESS_0 + (i << 2); - unsigned long base; - u32 size, pbase; - - base = rp->start; - - io = (rp->flags & IORESOURCE_IO); - - size = rp->end - base + 1; - - pci_read_config_dword(pdev, breg, &pbase); - - if (io) - size &= ~1; - - /* - * Map the framebuffer a second time, this time without - * the braindead _PAGE_IE setting. This is used by the - * fixed Xserver, but we need to maintain the old mapping - * to stay compatible with older ones... - */ - if (base == addr) { - info->mmap_map[j].voff = (pbase + 0x10000000) & PAGE_MASK; - info->mmap_map[j].poff = base & PAGE_MASK; - info->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK; - info->mmap_map[j].prot_mask = _PAGE_CACHE; - info->mmap_map[j].prot_flag = _PAGE_E; - j++; - } - - /* - * Here comes the old framebuffer mapping with _PAGE_IE - * set for the big endian half of the framebuffer... - */ - if (base == addr) { - info->mmap_map[j].voff = (pbase + 0x800000) & PAGE_MASK; - info->mmap_map[j].poff = (base+0x800000) & PAGE_MASK; - info->mmap_map[j].size = 0x800000; - info->mmap_map[j].prot_mask = _PAGE_CACHE; - info->mmap_map[j].prot_flag = _PAGE_E|_PAGE_IE; - size -= 0x800000; - j++; - } - - info->mmap_map[j].voff = pbase & PAGE_MASK; - info->mmap_map[j].poff = base & PAGE_MASK; - info->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK; - info->mmap_map[j].prot_mask = _PAGE_CACHE; - info->mmap_map[j].prot_flag = _PAGE_E; - j++; - } - - /* - * Fix PROMs idea of MEM_CNTL settings... - */ - mem = aty_ld_le32(MEM_CNTL, info); - chip_id = aty_ld_le32(CONFIG_CHIP_ID, info); - if (((chip_id & CFG_CHIP_TYPE) == VT_CHIP_ID) && - !((chip_id >> 24) & 1)) { - switch (mem & 0x0f) { - case 3: - mem = (mem & ~(0x0f)) | 2; - break; - case 7: - mem = (mem & ~(0x0f)) | 3; - break; - case 9: - mem = (mem & ~(0x0f)) | 4; - break; - case 11: - mem = (mem & ~(0x0f)) | 5; - break; - default: - break; - } - if ((aty_ld_le32(CONFIG_STAT0, info) & 7) >= SDRAM) - mem &= ~(0x00700000); - } - mem &= ~(0xcf80e000); /* Turn off all undocumented bits. */ - aty_st_le32(MEM_CNTL, mem, info); - - /* - * If this is the console device, we will set default video - * settings to what the PROM left us with. - */ - node = prom_getchild(prom_root_node); - node = prom_searchsiblings(node, "aliases"); - if (node) { - len = prom_getproperty(node, "screen", prop, sizeof(prop)); - if (len > 0) { - prop[len] = '\0'; - node = prom_finddevice(prop); - } else { - node = 0; - } - } - - pcp = pdev->sysdata; - if (node == pcp->prom_node) { - - struct fb_var_screeninfo *var = &default_var; - unsigned int N, P, Q, M, T; - u32 v_total, h_total; - struct crtc crtc; - u8 pll_regs[16]; - u8 clock_cntl; - - crtc.vxres = prom_getintdefault(node, "width", 1024); - crtc.vyres = prom_getintdefault(node, "height", 768); - crtc.bpp = prom_getintdefault(node, "depth", 8); - crtc.xoffset = crtc.yoffset = 0; - crtc.h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, info); - crtc.h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, info); - crtc.v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, info); - crtc.v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, info); - crtc.gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, info); - aty_crtc_to_var(&crtc, var); - - h_total = var->xres + var->right_margin + - var->hsync_len + var->left_margin; - v_total = var->yres + var->lower_margin + - var->vsync_len + var->upper_margin; - - /* - * Read the PLL to figure actual Refresh Rate. - */ - clock_cntl = aty_ld_8(CLOCK_CNTL, info); - /* printk("atyfb: CLOCK_CNTL: %02x\n", clock_cntl); */ - for (i = 0; i < 16; i++) - pll_regs[i] = aty_ld_pll(i, info); - - /* - * PLL Reference Devider M: - */ - M = pll_regs[2]; - - /* - * PLL Feedback Devider N (Dependant on CLOCK_CNTL): - */ - N = pll_regs[7 + (clock_cntl & 3)]; - - /* - * PLL Post Devider P (Dependant on CLOCK_CNTL): - */ - P = 1 << (pll_regs[6] >> ((clock_cntl & 3) << 1)); - - /* - * PLL Devider Q: - */ - Q = N / P; - - /* - * Target Frequency: - * - * T * M - * Q = ------- - * 2 * R - * - * where R is XTALIN (= 14318 kHz). - */ - T = 2 * Q * 14318 / M; - - default_var.pixclock = 1000000000 / T; - } - -#else /* __sparc__ */ - - info->ati_regbase_phys = 0x7ff000 + addr; - info->ati_regbase = (unsigned long) - ioremap(info->ati_regbase_phys, 0x1000); - - if(!info->ati_regbase) { - kfree(info); - release_mem_region(res_start, res_size); - return -ENOMEM; - } - - info->ati_regbase_phys += 0xc00; - info->ati_regbase += 0xc00; - - /* - * Enable memory-space accesses using config-space - * command register. - */ - pci_read_config_word(pdev, PCI_COMMAND, &tmp); - if (!(tmp & PCI_COMMAND_MEMORY)) { - tmp |= PCI_COMMAND_MEMORY; - pci_write_config_word(pdev, PCI_COMMAND, tmp); - } - -#ifdef __BIG_ENDIAN - /* Use the big-endian aperture */ - addr += 0x800000; -#endif - - /* Map in frame buffer */ - info->frame_buffer_phys = addr; - info->frame_buffer = (unsigned long)ioremap(addr, 0x800000); - - if(!info->frame_buffer) { - kfree(info); - release_mem_region(res_start, res_size); - return -ENXIO; - } - -#endif /* __sparc__ */ - - if (!aty_init(info, "PCI")) { - if (info->mmap_map) - kfree(info->mmap_map); - kfree(info); - release_mem_region(res_start, res_size); - return -ENXIO; - } - -#ifdef __sparc__ - if (!prom_palette) - prom_palette = atyfb_palette; - - /* - * Add /dev/fb mmap values. - */ - info->mmap_map[0].voff = 0x8000000000000000UL; - info->mmap_map[0].poff = info->frame_buffer & PAGE_MASK; - info->mmap_map[0].size = info->total_vram; - info->mmap_map[0].prot_mask = _PAGE_CACHE; - info->mmap_map[0].prot_flag = _PAGE_E; - info->mmap_map[1].voff = info->mmap_map[0].voff + info->total_vram; - info->mmap_map[1].poff = info->ati_regbase & PAGE_MASK; - info->mmap_map[1].size = PAGE_SIZE; - info->mmap_map[1].prot_mask = _PAGE_CACHE; - info->mmap_map[1].prot_flag = _PAGE_E; -#endif /* __sparc__ */ - -#ifdef CONFIG_PMAC_PBOOK - if (first_display == NULL) - pmu_register_sleep_notifier(&aty_sleep_notifier); - info->next = first_display; - first_display = info; -#endif - -#ifdef CONFIG_FB_COMPAT_XPMAC - if (!console_fb_info) - console_fb_info = &info->fb_info; -#endif /* CONFIG_FB_COMPAT_XPMAC */ - } - } - -#elif defined(CONFIG_ATARI) - u32 clock_r; - int m64_num; - struct fb_info_aty *info; - - for (m64_num = 0; m64_num < mach64_count; m64_num++) { - if (!phys_vmembase[m64_num] || !phys_size[m64_num] || - !phys_guiregbase[m64_num]) { - printk(" phys_*[%d] parameters not set => returning early. \n", - m64_num); - continue; - } - - info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC); - if (!info) { - printk("atyfb_init: can't alloc fb_info_aty\n"); - return -ENOMEM; - } - memset(info, 0, sizeof(struct fb_info_aty)); - - /* - * Map the video memory (physical address given) to somewhere in the - * kernel address space. - */ - info->frame_buffer = ioremap(phys_vmembase[m64_num], phys_size[m64_num]); - info->frame_buffer_phys = info->frame_buffer; /* Fake! */ - info->ati_regbase = ioremap(phys_guiregbase[m64_num], 0x10000)+0xFC00ul; - info->ati_regbase_phys = info->ati_regbase; /* Fake! */ - - aty_st_le32(CLOCK_CNTL, 0x12345678, info); - clock_r = aty_ld_le32(CLOCK_CNTL, info); - - switch (clock_r & 0x003F) { - case 0x12: - info->clk_wr_offset = 3; /* */ - break; - case 0x34: - info->clk_wr_offset = 2; /* Medusa ST-IO ISA Adapter etc. */ - break; - case 0x16: - info->clk_wr_offset = 1; /* */ - break; - case 0x38: - info->clk_wr_offset = 0; /* Panther 1 ISA Adapter (Gerald) */ - break; - } - - if (!aty_init(info, "ISA bus")) { - kfree(info); - /* This is insufficient! kernel_map has added two large chunks!! */ - return -ENXIO; - } - } -#endif /* CONFIG_ATARI */ - return 0; -} - -#ifndef MODULE -int __init atyfb_setup(char *options) -{ - char *this_opt; - - if (!options || !*options) - return 0; - - for (this_opt = strtok(options, ","); this_opt; - this_opt = strtok(NULL, ",")) { - if (!strncmp(this_opt, "font:", 5)) { - char *p; - int i; - - p = this_opt + 5; - for (i = 0; i < sizeof(fontname) - 1; i++) - if (!*p || *p == ' ' || *p == ',') - break; - memcpy(fontname, this_opt + 5, i); - fontname[i] = 0; - } else if (!strncmp(this_opt, "noblink", 7)) { - curblink = 0; - } else if (!strncmp(this_opt, "noaccel", 7)) { - noaccel = 1; - } else if (!strncmp(this_opt, "vram:", 5)) - default_vram = simple_strtoul(this_opt+5, NULL, 0); - else if (!strncmp(this_opt, "pll:", 4)) - default_pll = simple_strtoul(this_opt+4, NULL, 0); - else if (!strncmp(this_opt, "mclk:", 5)) - default_mclk = simple_strtoul(this_opt+5, NULL, 0); -#ifdef CONFIG_PPC - else if (!strncmp(this_opt, "vmode:", 6)) { - unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0); - if (vmode > 0 && vmode <= VMODE_MAX) - default_vmode = vmode; - } else if (!strncmp(this_opt, "cmode:", 6)) { - unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0); - switch (cmode) { - case 0: - case 8: - default_cmode = CMODE_8; - break; - case 15: - case 16: - default_cmode = CMODE_16; - break; - case 24: - case 32: - default_cmode = CMODE_32; - break; - } - } -#endif -#ifdef CONFIG_ATARI - /* - * Why do we need this silly Mach64 argument? - * We are already here because of mach64= so its redundant. - */ - else if (MACH_IS_ATARI && (!strncmp(this_opt, "Mach64:", 7))) { - static unsigned char m64_num; - static char mach64_str[80]; - strncpy(mach64_str, this_opt+7, 80); - if (!store_video_par(mach64_str, m64_num)) { - m64_num++; - mach64_count = m64_num; - } - } -#endif - else - mode_option = this_opt; - } - return 0; -} -#endif /* !MODULE */ - -#ifdef CONFIG_ATARI -static int __init store_video_par(char *video_str, unsigned char m64_num) -{ - char *p; - unsigned long vmembase, size, guiregbase; - - printk("store_video_par() '%s' \n", video_str); - - if (!(p = strtoke(video_str, ";")) || !*p) - goto mach64_invalid; - vmembase = simple_strtoul(p, NULL, 0); - if (!(p = strtoke(NULL, ";")) || !*p) - goto mach64_invalid; - size = simple_strtoul(p, NULL, 0); - if (!(p = strtoke(NULL, ";")) || !*p) - goto mach64_invalid; - guiregbase = simple_strtoul(p, NULL, 0); - - phys_vmembase[m64_num] = vmembase; - phys_size[m64_num] = size; - phys_guiregbase[m64_num] = guiregbase; - printk(" stored them all: $%08lX $%08lX $%08lX \n", vmembase, size, - guiregbase); - return 0; - -mach64_invalid: - phys_vmembase[m64_num] = 0; - return -1; -} - -static char __init *strtoke(char *s, const char *ct) -{ - static char *ssave = NULL; - char *sbegin, *send; - - sbegin = s ? s : ssave; - if (!sbegin) - return NULL; - if (*sbegin == '\0') { - ssave = NULL; - return NULL; - } - send = strpbrk(sbegin, ct); - if (send && *send != '\0') - *send++ = '\0'; - ssave = send; - return sbegin; -} -#endif /* CONFIG_ATARI */ - -static int atyfbcon_switch(int con, struct fb_info *fb) -{ - struct fb_info_aty *info = (struct fb_info_aty *)fb; - struct atyfb_par par; - - /* Do we have to save the colormap? */ - if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, 1, atyfb_getcolreg, fb); - - /* Erase HW Cursor */ - if (info->cursor) - atyfb_cursor(&fb_display[currcon], CM_ERASE, - info->cursor->pos.x, info->cursor->pos.y); - - currcon = con; - - atyfb_decode_var(&fb_display[con].var, &par, info); - atyfb_set_par(&par, info); - atyfb_set_dispsw(&fb_display[con], info, par.crtc.bpp, - par.accel_flags & FB_ACCELF_TEXT); - - /* Install new colormap */ - do_install_cmap(con, fb); - - /* Install hw cursor */ - if (info->cursor) { - aty_set_cursor_color(info, cursor_pixel_map, cursor_color_map, - cursor_color_map, cursor_color_map); - aty_set_cursor_shape(info); - } - return 1; -} - - /* - * Blank the display. - */ - -static void atyfbcon_blank(int blank, struct fb_info *fb) -{ - struct fb_info_aty *info = (struct fb_info_aty *)fb; - u8 gen_cntl; - -#ifdef CONFIG_PMAC_BACKLIGHT - if ((_machine == _MACH_Pmac) && blank) - set_backlight_enable(0); -#endif /* CONFIG_PMAC_BACKLIGHT */ - - gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info); - if (blank > 0) - switch (blank-1) { - case VESA_NO_BLANKING: - gen_cntl |= 0x40; - break; - case VESA_VSYNC_SUSPEND: - gen_cntl |= 0x8; - break; - case VESA_HSYNC_SUSPEND: - gen_cntl |= 0x4; - break; - case VESA_POWERDOWN: - gen_cntl |= 0x4c; - break; - } - else - gen_cntl &= ~(0x4c); - aty_st_8(CRTC_GEN_CNTL, gen_cntl, info); - -#ifdef CONFIG_PMAC_BACKLIGHT - if ((_machine == _MACH_Pmac) && !blank) - set_backlight_enable(1); -#endif /* CONFIG_PMAC_BACKLIGHT */ -} - - - /* - * Read a single color register and split it into - * colors/transparent. Return != 0 for invalid regno. - */ - -static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, - u_int *transp, struct fb_info *fb) -{ - struct fb_info_aty *info = (struct fb_info_aty *)fb; - - if (regno > 255) - return 1; - *red = (info->palette[regno].red<<8) | info->palette[regno].red; - *green = (info->palette[regno].green<<8) | info->palette[regno].green; - *blue = (info->palette[regno].blue<<8) | info->palette[regno].blue; - *transp = 0; - return 0; -} - - - /* - * Set a single color register. The values supplied are already - * rounded down to the hardware's capabilities (according to the - * entries in the var structure). Return != 0 for invalid regno. - */ - -static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *fb) -{ - struct fb_info_aty *info = (struct fb_info_aty *)fb; - int i, scale; - - if (regno > 255) - return 1; - red >>= 8; - green >>= 8; - blue >>= 8; - info->palette[regno].red = red; - info->palette[regno].green = green; - info->palette[regno].blue = blue; - i = aty_ld_8(DAC_CNTL, info) & 0xfc; - if (Gx == GT_CHIP_ID || Gx == GU_CHIP_ID || Gx == GV_CHIP_ID || - Gx == GW_CHIP_ID || Gx == GZ_CHIP_ID || Gx == LG_CHIP_ID || - Gx == GB_CHIP_ID || Gx == GD_CHIP_ID || Gx == GI_CHIP_ID || - Gx == GP_CHIP_ID || Gx == GQ_CHIP_ID || Gx == LI_CHIP_ID) - i |= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt*/ - aty_st_8(DAC_CNTL, i, info); - aty_st_8(DAC_MASK, 0xff, info); - scale = ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID) && - (info->current_par.crtc.bpp == 16)) ? 3 : 0; - writeb(regno << scale, &info->aty_cmap_regs->windex); - writeb(red, &info->aty_cmap_regs->lut); - writeb(green, &info->aty_cmap_regs->lut); - writeb(blue, &info->aty_cmap_regs->lut); - if (regno < 16) - switch (info->current_par.crtc.bpp) { -#ifdef FBCON_HAS_CFB16 - case 16: - info->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | - regno; - break; -#endif -#ifdef FBCON_HAS_CFB24 - case 24: - info->fbcon_cmap.cfb24[regno] = (regno << 16) | (regno << 8) | - regno; - break; -#endif -#ifdef FBCON_HAS_CFB32 - case 32: - i = (regno << 8) | regno; - info->fbcon_cmap.cfb32[regno] = (i << 16) | i; - break; -#endif - } - return 0; -} - - -static void do_install_cmap(int con, struct fb_info *info) -{ - if (con != currcon) - return; - if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, atyfb_setcolreg, info); - else { - int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; - fb_set_cmap(fb_default_cmap(size), 1, atyfb_setcolreg, info); - } -} - - - /* - * Accelerated functions - */ - -static inline void draw_rect(s16 x, s16 y, u16 width, u16 height, - struct fb_info_aty *info) -{ - /* perform rectangle fill */ - wait_for_fifo(2, info); - aty_st_le32(DST_Y_X, (x << 16) | y, info); - aty_st_le32(DST_HEIGHT_WIDTH, (width << 16) | height, info); - info->blitter_may_be_busy = 1; -} - -static inline void aty_rectcopy(int srcx, int srcy, int dstx, int dsty, - u_int width, u_int height, - struct fb_info_aty *info) -{ - u32 direction = DST_LAST_PEL; - u32 pitch_value; - - if (!width || !height) - return; - - pitch_value = info->current_par.crtc.vxres; - if (info->current_par.crtc.bpp == 24) { - /* In 24 bpp, the engine is in 8 bpp - this requires that all */ - /* horizontal coordinates and widths must be adjusted */ - pitch_value *= 3; - srcx *= 3; - dstx *= 3; - width *= 3; - } - - if (srcy < dsty) { - dsty += height - 1; - srcy += height - 1; - } else - direction |= DST_Y_TOP_TO_BOTTOM; - - if (srcx < dstx) { - dstx += width - 1; - srcx += width - 1; - } else - direction |= DST_X_LEFT_TO_RIGHT; - - wait_for_fifo(4, info); - aty_st_le32(DP_SRC, FRGD_SRC_BLIT, info); - aty_st_le32(SRC_Y_X, (srcx << 16) | srcy, info); - aty_st_le32(SRC_HEIGHT1_WIDTH1, (width << 16) | height, info); - aty_st_le32(DST_CNTL, direction, info); - draw_rect(dstx, dsty, width, height, info); -} - -static inline void aty_rectfill(int dstx, int dsty, u_int width, u_int height, - u_int color, struct fb_info_aty *info) -{ - if (!width || !height) - return; - - if (info->current_par.crtc.bpp == 24) { - /* In 24 bpp, the engine is in 8 bpp - this requires that all */ - /* horizontal coordinates and widths must be adjusted */ - dstx *= 3; - width *= 3; - } - - wait_for_fifo(3, info); - aty_st_le32(DP_FRGD_CLR, color, info); - aty_st_le32(DP_SRC, BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE, - info); - aty_st_le32(DST_CNTL, DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM | - DST_X_LEFT_TO_RIGHT, info); - draw_rect(dstx, dsty, width, height, info); -} - - /* - * Update the `var' structure (called by fbcon.c) - */ - -static int atyfbcon_updatevar(int con, struct fb_info *fb) -{ - struct fb_info_aty *info = (struct fb_info_aty *)fb; - struct atyfb_par *par = &info->current_par; - struct display *p = &fb_display[con]; - struct vc_data *conp = p->conp; - u32 yres, yoffset, sy, height; - - yres = ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1; - yoffset = fb_display[con].var.yoffset; - - sy = (conp->vc_rows + p->yscroll) * fontheight(p); - height = yres - conp->vc_rows * fontheight(p); - - if (height && (yoffset + yres > sy)) { - u32 xres, xoffset; - u32 bgx; - - xres = (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8; - xoffset = fb_display[con].var.xoffset; - - - bgx = attr_bgcol_ec(p, conp); - bgx |= (bgx << 8); - bgx |= (bgx << 16); - - if (sy + height > par->crtc.vyres) { - wait_for_fifo(1, info); - aty_st_le32(SC_BOTTOM, sy + height - 1, info); - } - aty_rectfill(xoffset, sy, xres, height, bgx, info); - } - - if (info->cursor && (yoffset + yres <= sy)) - atyfb_cursor(p, CM_ERASE, info->cursor->pos.x, info->cursor->pos.y); - - info->current_par.crtc.yoffset = yoffset; - set_off_pitch(&info->current_par, info); - return 0; -} - - /* - * Text console acceleration - */ - -static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy, int dx, - int height, int width) -{ -#ifdef __sparc__ - struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); - - if (fb->mmaped && (!fb->fb_info.display_fg - || fb->fb_info.display_fg->vc_num == fb->vtconsole)) - return; -#endif - - sx *= fontwidth(p); - sy *= fontheight(p); - dx *= fontwidth(p); - dy *= fontheight(p); - width *= fontwidth(p); - height *= fontheight(p); - - aty_rectcopy(sx, sy, dx, dy, width, height, - (struct fb_info_aty *)p->fb_info); -} - -static void fbcon_aty_clear(struct vc_data *conp, struct display *p, int sy, - int sx, int height, int width) -{ - u32 bgx; -#ifdef __sparc__ - struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); - - if (fb->mmaped && (!fb->fb_info.display_fg - || fb->fb_info.display_fg->vc_num == fb->vtconsole)) - return; -#endif - - bgx = attr_bgcol_ec(p, conp); - bgx |= (bgx << 8); - bgx |= (bgx << 16); - - sx *= fontwidth(p); - sy *= fontheight(p); - width *= fontwidth(p); - height *= fontheight(p); - - aty_rectfill(sx, sy, width, height, bgx, - (struct fb_info_aty *)p->fb_info); -} - -#ifdef FBCON_HAS_CFB8 -static void fbcon_aty8_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx) -{ - struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); - -#ifdef __sparc__ - if (fb->mmaped && (!fb->fb_info.display_fg - || fb->fb_info.display_fg->vc_num == fb->vtconsole)) - return; -#endif - - if (fb->blitter_may_be_busy) - wait_for_idle((struct fb_info_aty *)p->fb_info); - fbcon_cfb8_putc(conp, p, c, yy, xx); -} - -static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, - int xx) -{ - struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); - -#ifdef __sparc__ - if (fb->mmaped && (!fb->fb_info.display_fg - || fb->fb_info.display_fg->vc_num == fb->vtconsole)) - return; -#endif - - if (fb->blitter_may_be_busy) - wait_for_idle((struct fb_info_aty *)p->fb_info); - fbcon_cfb8_putcs(conp, p, s, count, yy, xx); -} - -static void fbcon_aty8_clear_margins(struct vc_data *conp, struct display *p, - int bottom_only) -{ - struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); - -#ifdef __sparc__ - if (fb->mmaped && (!fb->fb_info.display_fg - || fb->fb_info.display_fg->vc_num == fb->vtconsole)) - return; -#endif - - if (fb->blitter_may_be_busy) - wait_for_idle((struct fb_info_aty *)p->fb_info); - fbcon_cfb8_clear_margins(conp, p, bottom_only); -} - -static struct display_switch fbcon_aty8 = { - setup: fbcon_cfb8_setup, - bmove: fbcon_aty_bmove, - clear: fbcon_aty_clear, - putc: fbcon_aty8_putc, - putcs: fbcon_aty8_putcs, - revc: fbcon_cfb8_revc, - clear_margins: fbcon_aty8_clear_margins, - fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) -}; -#endif - -#ifdef FBCON_HAS_CFB16 -static void fbcon_aty16_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx) -{ - struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); - -#ifdef __sparc__ - if (fb->mmaped && (!fb->fb_info.display_fg - || fb->fb_info.display_fg->vc_num == fb->vtconsole)) - return; -#endif - - if (fb->blitter_may_be_busy) - wait_for_idle((struct fb_info_aty *)p->fb_info); - fbcon_cfb16_putc(conp, p, c, yy, xx); -} - -static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, - int xx) -{ - struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); - -#ifdef __sparc__ - if (fb->mmaped && (!fb->fb_info.display_fg - || fb->fb_info.display_fg->vc_num == fb->vtconsole)) - return; -#endif - - if (fb->blitter_may_be_busy) - wait_for_idle((struct fb_info_aty *)p->fb_info); - fbcon_cfb16_putcs(conp, p, s, count, yy, xx); -} - -static void fbcon_aty16_clear_margins(struct vc_data *conp, struct display *p, - int bottom_only) -{ - struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); - -#ifdef __sparc__ - if (fb->mmaped && (!fb->fb_info.display_fg - || fb->fb_info.display_fg->vc_num == fb->vtconsole)) - return; -#endif - - if (fb->blitter_may_be_busy) - wait_for_idle((struct fb_info_aty *)p->fb_info); - fbcon_cfb16_clear_margins(conp, p, bottom_only); -} - -static struct display_switch fbcon_aty16 = { - setup: fbcon_cfb16_setup, - bmove: fbcon_aty_bmove, - clear: fbcon_aty_clear, - putc: fbcon_aty16_putc, - putcs: fbcon_aty16_putcs, - revc: fbcon_cfb16_revc, - clear_margins: fbcon_aty16_clear_margins, - fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) -}; -#endif - -#ifdef FBCON_HAS_CFB24 -static void fbcon_aty24_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx) -{ - struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); - -#ifdef __sparc__ - if (fb->mmaped && (!fb->fb_info.display_fg - || fb->fb_info.display_fg->vc_num == fb->vtconsole)) - return; -#endif - - if (fb->blitter_may_be_busy) - wait_for_idle((struct fb_info_aty *)p->fb_info); - fbcon_cfb24_putc(conp, p, c, yy, xx); -} - -static void fbcon_aty24_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, - int xx) -{ - struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); - -#ifdef __sparc__ - if (fb->mmaped && (!fb->fb_info.display_fg - || fb->fb_info.display_fg->vc_num == fb->vtconsole)) - return; -#endif - - if (fb->blitter_may_be_busy) - wait_for_idle((struct fb_info_aty *)p->fb_info); - fbcon_cfb24_putcs(conp, p, s, count, yy, xx); -} - -static void fbcon_aty24_clear_margins(struct vc_data *conp, struct display *p, - int bottom_only) -{ - struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); - -#ifdef __sparc__ - if (fb->mmaped && (!fb->fb_info.display_fg - || fb->fb_info.display_fg->vc_num == fb->vtconsole)) - return; -#endif - - if (fb->blitter_may_be_busy) - wait_for_idle((struct fb_info_aty *)p->fb_info); - fbcon_cfb24_clear_margins(conp, p, bottom_only); -} - -static struct display_switch fbcon_aty24 = { - setup: fbcon_cfb24_setup, - bmove: fbcon_aty_bmove, - clear: fbcon_aty_clear, - putc: fbcon_aty24_putc, - putcs: fbcon_aty24_putcs, - revc: fbcon_cfb24_revc, - clear_margins: fbcon_aty24_clear_margins, - fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) -}; -#endif - -#ifdef FBCON_HAS_CFB32 -static void fbcon_aty32_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx) -{ - struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); - -#ifdef __sparc__ - if (fb->mmaped && (!fb->fb_info.display_fg - || fb->fb_info.display_fg->vc_num == fb->vtconsole)) - return; -#endif - - if (fb->blitter_may_be_busy) - wait_for_idle((struct fb_info_aty *)p->fb_info); - fbcon_cfb32_putc(conp, p, c, yy, xx); -} - -static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, - int xx) -{ - struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); - -#ifdef __sparc__ - if (fb->mmaped && (!fb->fb_info.display_fg - || fb->fb_info.display_fg->vc_num == fb->vtconsole)) - return; -#endif - - if (fb->blitter_may_be_busy) - wait_for_idle((struct fb_info_aty *)p->fb_info); - fbcon_cfb32_putcs(conp, p, s, count, yy, xx); -} - -static void fbcon_aty32_clear_margins(struct vc_data *conp, struct display *p, - int bottom_only) -{ - struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); - -#ifdef __sparc__ - if (fb->mmaped && (!fb->fb_info.display_fg - || fb->fb_info.display_fg->vc_num == fb->vtconsole)) - return; -#endif - - if (fb->blitter_may_be_busy) - wait_for_idle((struct fb_info_aty *)p->fb_info); - fbcon_cfb32_clear_margins(conp, p, bottom_only); -} - -static struct display_switch fbcon_aty32 = { - setup: fbcon_cfb32_setup, - bmove: fbcon_aty_bmove, - clear: fbcon_aty_clear, - putc: fbcon_aty32_putc, - putcs: fbcon_aty32_putcs, - revc: fbcon_cfb32_revc, - clear_margins: fbcon_aty32_clear_margins, - fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) -}; -#endif - -#ifdef CONFIG_PMAC_PBOOK - -/* Power management routines. Those are used for PowerBook sleep. - * - * It appears that Rage LT and Rage LT Pro have different power - * management registers. There's is some confusion about which - * chipID is a Rage LT or LT pro :( - */ -static int -aty_power_mgmt_LT(int sleep, struct fb_info_aty *info) -{ - unsigned int pm; - int timeout; - - pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); - pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG; - aty_st_le32(POWER_MANAGEMENT_LG, pm, info); - pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); - - timeout = 200000; - if (sleep) { - /* Sleep */ - pm &= ~PWR_MGT_ON; - aty_st_le32(POWER_MANAGEMENT_LG, pm, info); - pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); - udelay(10); - pm &= ~(PWR_BLON | AUTO_PWR_UP); - pm |= SUSPEND_NOW; - aty_st_le32(POWER_MANAGEMENT_LG, pm, info); - pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); - udelay(10); - pm |= PWR_MGT_ON; - aty_st_le32(POWER_MANAGEMENT_LG, pm, info); - do { - pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); - udelay(10); - if ((--timeout) == 0) - break; - } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND); - } else { - /* Wakeup */ - pm &= ~PWR_MGT_ON; - aty_st_le32(POWER_MANAGEMENT_LG, pm, info); - pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); - udelay(10); - pm |= (PWR_BLON | AUTO_PWR_UP); - pm &= ~SUSPEND_NOW; - aty_st_le32(POWER_MANAGEMENT_LG, pm, info); - pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); - udelay(10); - pm |= PWR_MGT_ON; - aty_st_le32(POWER_MANAGEMENT_LG, pm, info); - do { - pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); - udelay(10); - if ((--timeout) == 0) - break; - } while ((pm & PWR_MGT_STATUS_MASK) != 0); - } - mdelay(500); - - return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE; -} - -static int -aty_power_mgmt_LTPro(int sleep, struct fb_info_aty *info) -{ - unsigned int pm; - int timeout; - - pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); - pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG; - aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); - pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); - - timeout = 200; - if (sleep) { - /* Sleep */ - pm &= ~PWR_MGT_ON; - aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); - pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); - udelay(10); - pm &= ~(PWR_BLON | AUTO_PWR_UP); - pm |= SUSPEND_NOW; - aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); - pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); - udelay(10); - pm |= PWR_MGT_ON; - aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); - do { - pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); - udelay(1000); - if ((--timeout) == 0) - break; - } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND); - } else { - /* Wakeup */ - pm &= ~PWR_MGT_ON; - aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); - pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); - udelay(10); - pm &= ~SUSPEND_NOW; - pm |= (PWR_BLON | AUTO_PWR_UP); - aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); - pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); - udelay(10); - pm |= PWR_MGT_ON; - aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); - do { - pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); - udelay(1000); - if ((--timeout) == 0) - break; - } while ((pm & PWR_MGT_STATUS_MASK) != 0); - } - - return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE; -} - -/* - * Save the contents of the frame buffer when we go to sleep, - * and restore it when we wake up again. - */ -int -aty_sleep_notify(struct pmu_sleep_notifier *self, int when) -{ - struct fb_info_aty *info; - int result; - - result = PBOOK_SLEEP_OK; - - for (info = first_display; info != NULL; info = info->next) { - struct fb_fix_screeninfo fix; - int nb; - - atyfb_get_fix(&fix, fg_console, (struct fb_info *)info); - nb = fb_display[fg_console].var.yres * fix.line_length; - - switch (when) { - case PBOOK_SLEEP_REQUEST: - info->save_framebuffer = vmalloc(nb); - if (info->save_framebuffer == NULL) - return PBOOK_SLEEP_REFUSE; - break; - case PBOOK_SLEEP_REJECT: - if (info->save_framebuffer) { - vfree(info->save_framebuffer); - info->save_framebuffer = 0; - } - break; - case PBOOK_SLEEP_NOW: - if (info->blitter_may_be_busy) - wait_for_idle(info); - /* Stop accel engine (stop bus mastering) */ - if (info->current_par.accel_flags & FB_ACCELF_TEXT) - reset_engine(info); - - /* Backup fb content */ - if (info->save_framebuffer) - memcpy_fromio(info->save_framebuffer, - (void *)info->frame_buffer, nb); - - /* Blank display and LCD */ - atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info); - - /* Set chip to "suspend" mode */ - if (Gx == LG_CHIP_ID) - result = aty_power_mgmt_LT(1, info); - else - result = aty_power_mgmt_LTPro(1, info); - break; - case PBOOK_WAKE: - /* Wakeup chip */ - if (Gx == LG_CHIP_ID) - result = aty_power_mgmt_LT(0, info); - else - result = aty_power_mgmt_LTPro(0, info); - - /* Restore fb content */ - if (info->save_framebuffer) { - memcpy_toio((void *)info->frame_buffer, - info->save_framebuffer, nb); - vfree(info->save_framebuffer); - info->save_framebuffer = 0; - } - /* Restore display */ - atyfb_set_par(&info->current_par, info); - atyfbcon_blank(0, (struct fb_info *)info); - break; - } - } - return result; -} -#endif /* CONFIG_PMAC_PBOOK */ - -#ifdef CONFIG_PMAC_BACKLIGHT -static int backlight_conv[] = { - 0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d, - 0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff -}; - -static int -aty_set_backlight_enable(int on, int level, void* data) -{ - struct fb_info_aty *info = (struct fb_info_aty *)data; - unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, info); - - reg |= (BLMOD_EN | BIASMOD_EN); - if (on && level > BACKLIGHT_OFF) { - reg &= ~BIAS_MOD_LEVEL_MASK; - reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT); - } else { - reg &= ~BIAS_MOD_LEVEL_MASK; - reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT); - } - aty_st_lcd(LCD_MISC_CNTL, reg, info); - - return 0; -} - -static int -aty_set_backlight_level(int level, void* data) -{ - return aty_set_backlight_enable(1, level, data); -} - -#endif /* CONFIG_PMAC_BACKLIGHT */ - - -#ifdef MODULE -int __init init_module(void) -{ - atyfb_init(); - return fb_list ? 0 : -ENXIO; -} - -void cleanup_module(void) -{ - while (fb_list) { - struct fb_info_aty *info = fb_list; - fb_list = info->next; - - unregister_framebuffer(&info->fb_info); - -#ifndef __sparc__ - if (info->ati_regbase) - iounmap((void *)info->ati_regbase); - if (info->frame_buffer) - iounmap((void *)info->frame_buffer); -#ifdef __BIG_ENDIAN - if (info->cursor && info->cursor->ram) - iounmap(info->cursor->ram); -#endif -#endif - - if (info->cursor) { - if (info->cursor->timer) - kfree(info->cursor->timer); - kfree(info->cursor); - } -#ifdef __sparc__ - if (info->mmap_map) - kfree(info->mmap_map); -#endif - kfree(info); - } -} - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/chipsfb.c linux.ac/drivers/video/chipsfb.c --- linux.vanilla/drivers/video/chipsfb.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/chipsfb.c Tue Apr 3 17:55:09 2001 @@ -29,17 +29,19 @@ #include <linux/selection.h> #include <linux/init.h> #include <linux/pci.h> +#include <asm/io.h> + #ifdef CONFIG_FB_COMPAT_XPMAC #include <asm/vc_ioctl.h> -#endif -#include <asm/io.h> -#include <asm/prom.h> #include <asm/pci-bridge.h> +#endif #ifdef CONFIG_PMAC_BACKLIGHT #include <asm/backlight.h> #endif +#ifdef CONFIG_PMAC_PBOOK #include <linux/adb.h> #include <linux/pmu.h> +#endif #include <video/fbcon.h> #include <video/fbcon-cfb8.h> @@ -56,14 +58,13 @@ struct { __u8 red, green, blue; } palette[256]; + struct pci_dev *pdev; unsigned long frame_buffer_phys; __u8 *frame_buffer; unsigned long blitter_regs_phys; __u32 *blitter_regs; unsigned long blitter_data_phys; __u8 *blitter_data; - unsigned long io_base_phys; - __u8 *io_base; struct fb_info_chips *next; #ifdef CONFIG_PMAC_PBOOK unsigned char *save_framebuffer; @@ -74,10 +75,10 @@ }; #define write_ind(num, val, ap, dp) do { \ - out_8(p->io_base + (ap), (num)); out_8(p->io_base + (dp), (val)); \ + outb((num), (ap)); outb((val), (dp)); \ } while (0) #define read_ind(num, var, ap, dp) do { \ - out_8(p->io_base + (ap), (num)); var = in_8(p->io_base + (dp)); \ + outb((num), (ap)); var = inb((dp)); \ } while (0); /* extension registers */ @@ -97,10 +98,10 @@ #define read_sr(num, var) read_ind(num, var, 0x3c4, 0x3c5) /* attribute registers - slightly strange */ #define write_ar(num, val) do { \ - in_8(p->io_base + 0x3da); write_ind(num, val, 0x3c0, 0x3c0); \ + inb(0x3da); write_ind(num, val, 0x3c0, 0x3c0); \ } while (0) #define read_ar(num, var) do { \ - in_8(p->io_base + 0x3da); read_ind(num, var, 0x3c0, 0x3c1); \ + inb(0x3da); read_ind(num, var, 0x3c0, 0x3c1); \ } while (0) static struct fb_info_chips *all_chips; @@ -117,7 +118,7 @@ */ int chips_init(void); -static void chips_of_init(struct device_node *dp); +static void chips_pci_init(struct pci_dev *dp); static int chips_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info); static int chips_get_var(struct fb_var_screeninfo *var, int con, @@ -253,29 +254,29 @@ #endif /* CONFIG_PMAC_BACKLIGHT */ /* get the palette from the chip */ for (i = 0; i < 256; ++i) { - out_8(p->io_base + 0x3c7, i); + outb(i, 0x3c7); udelay(1); - p->palette[i].red = in_8(p->io_base + 0x3c9); - p->palette[i].green = in_8(p->io_base + 0x3c9); - p->palette[i].blue = in_8(p->io_base + 0x3c9); + p->palette[i].red = inb(0x3c9); + p->palette[i].green = inb(0x3c9); + p->palette[i].blue = inb(0x3c9); } for (i = 0; i < 256; ++i) { - out_8(p->io_base + 0x3c8, i); + outb(i, 0x3c8); udelay(1); - out_8(p->io_base + 0x3c9, 0); - out_8(p->io_base + 0x3c9, 0); - out_8(p->io_base + 0x3c9, 0); + outb(0, 0x3c9); + outb(0, 0x3c9); + outb(0, 0x3c9); } } else { #ifdef CONFIG_PMAC_BACKLIGHT set_backlight_enable(1); #endif /* CONFIG_PMAC_BACKLIGHT */ for (i = 0; i < 256; ++i) { - out_8(p->io_base + 0x3c8, i); + outb(i, 0x3c8); udelay(1); - out_8(p->io_base + 0x3c9, p->palette[i].red); - out_8(p->io_base + 0x3c9, p->palette[i].green); - out_8(p->io_base + 0x3c9, p->palette[i].blue); + outb(p->palette[i].red, 0x3c9); + outb(p->palette[i].green, 0x3c9); + outb(p->palette[i].blue, 0x3c9); } } } @@ -307,11 +308,11 @@ p->palette[regno].red = red; p->palette[regno].green = green; p->palette[regno].blue = blue; - out_8(p->io_base + 0x3c8, regno); + outb(regno, 0x3c8); udelay(1); - out_8(p->io_base + 0x3c9, red); - out_8(p->io_base + 0x3c9, green); - out_8(p->io_base + 0x3c9, blue); + outb(red, 0x3c9); + outb(green, 0x3c9); + outb(blue, 0x3c9); #ifdef FBCON_HAS_CFB16 if (regno < 16) @@ -388,7 +389,7 @@ disp->visual = fix->visual; disp->var = *var; -#if (defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_FB_COMPAT_XPMAC)) +#ifdef CONFIG_FB_COMPAT_XPMAC display_info.depth = bpp; display_info.pitch = fix->line_length; #endif @@ -517,7 +518,7 @@ for (i = 0; i < N_ELTS(chips_init_xr); ++i) write_xr(chips_init_xr[i].addr, chips_init_xr[i].data); - out_8(p->io_base + 0x3c2, 0x29); /* set misc output reg */ + outb(0x29, 0x3c2); /* set misc output reg */ for (i = 0; i < N_ELTS(chips_init_sr); ++i) write_sr(chips_init_sr[i].addr, chips_init_sr[i].data); for (i = 0; i < N_ELTS(chips_init_gr); ++i) @@ -545,7 +546,6 @@ // * 3400 has 1MB (I think). Don't know if it's expandable. // -- Tim Seufert p->fix.smem_len = 0x100000; // 1MB - p->fix.mmio_start = p->io_base_phys; p->fix.type = FB_TYPE_PACKED_PIXELS; p->fix.visual = FB_VISUAL_PSEUDOCOLOR; p->fix.line_length = 800; @@ -607,6 +607,8 @@ #ifdef CONFIG_FB_COMPAT_XPMAC if (!console_fb_info) { + unsigned long iobase; + display_info.height = p->var.yres; display_info.width = p->var.xres; display_info.depth = 8; @@ -615,8 +617,9 @@ strncpy(display_info.name, "chips65550", sizeof(display_info.name)); display_info.fb_address = p->frame_buffer_phys; - display_info.cmap_adr_address = p->io_base_phys + 0x3c8; - display_info.cmap_data_address = p->io_base_phys + 0x3c9; + iobase = pci_bus_io_base_phys(p->pdev->bus->number); + display_info.cmap_adr_address = iobase + 0x3c8; + display_info.cmap_data_address = iobase + 0x3c9; display_info.disp_reg_address = p->blitter_regs_phys; console_fb_info = &p->info; } @@ -632,35 +635,39 @@ int __init chips_init(void) { - struct device_node *dp; + struct pci_dev *dp = NULL; - dp = find_devices("chips65550"); - if (dp != 0) - chips_of_init(dp); - return 0; + while ((dp = pci_find_device(PCI_VENDOR_ID_CT, + PCI_DEVICE_ID_CT_65550, dp)) != NULL) + if ((dp->class >> 16) == PCI_BASE_CLASS_DISPLAY) + chips_pci_init(dp); + return all_chips? 0: -ENODEV; } -static void __init chips_of_init(struct device_node *dp) +static void __init chips_pci_init(struct pci_dev *dp) { struct fb_info_chips *p; - unsigned long addr; - unsigned char bus, devfn; + unsigned long addr, size; unsigned short cmd; - if (dp->n_addrs == 0) + if ((dp->resource[0].flags & IORESOURCE_MEM) == 0) + return; + addr = dp->resource[0].start; + size = dp->resource[0].end + 1 - addr; + if (addr == 0) return; p = kmalloc(sizeof(*p), GFP_ATOMIC); if (p == 0) return; memset(p, 0, sizeof(*p)); - addr = dp->addrs[0].address; - if (!request_mem_region(addr, dp->addrs[0].size, "chipsfb")) { + if (!request_mem_region(addr, size, "chipsfb")) { kfree(p); return; } #ifdef __BIG_ENDIAN addr += 0x800000; // Use big-endian aperture #endif + p->pdev = dp; p->frame_buffer_phys = addr; p->frame_buffer = __ioremap(addr, 0x200000, _PAGE_NO_CACHE); p->blitter_regs_phys = addr + 0x400000; @@ -668,13 +675,13 @@ p->blitter_data_phys = addr + 0x410000; p->blitter_data = ioremap(addr + 0x410000, 0x10000); - if (pci_device_loc(dp, &bus, &devfn) == 0) { + if (pci_device_from_OF_node(dp, &bus, &devfn) == 0) { pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd); cmd |= 3; /* enable memory and IO space */ pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd); - p->io_base = (__u8 *) pci_io_base(bus); + p->io_base = (__u8 *) pci_bus_io_base(bus); /* XXX really want the physical address here */ - p->io_base_phys = (unsigned long) pci_io_base(bus); + p->io_base_phys = (unsigned long) pci_bus_io_base(bus); } /* Clear the entire framebuffer */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/clgenfb.c linux.ac/drivers/video/clgenfb.c --- linux.vanilla/drivers/video/clgenfb.c Tue Apr 3 17:32:24 2001 +++ linux.ac/drivers/video/clgenfb.c Tue Apr 3 17:55:09 2001 @@ -56,6 +56,12 @@ #ifdef CONFIG_AMIGA #include <asm/amigahw.h> #endif +#ifdef CONFIG_ALL_PPC +#include <asm/processor.h> +#define isPReP (_machine == _MACH_prep) +#else +#define isPReP 0 +#endif #include <video/fbcon.h> #include <video/fbcon-mfb.h> @@ -876,15 +882,15 @@ case 16: _par->line_length = _par->var.xres_virtual * 2; _par->visual = FB_VISUAL_DIRECTCOLOR; -#ifdef CONFIG_PREP - _par->var.red.offset = 2; - _par->var.green.offset = -3; - _par->var.blue.offset = 8; -#else - _par->var.red.offset = 10; - _par->var.green.offset = 5; - _par->var.blue.offset = 0; -#endif + if(isPReP) { + _par->var.red.offset = 2; + _par->var.green.offset = -3; + _par->var.blue.offset = 8; + } else { + _par->var.red.offset = 10; + _par->var.green.offset = 5; + _par->var.blue.offset = 0; + } _par->var.red.length = 5; _par->var.green.length = 5; _par->var.blue.length = 5; @@ -893,15 +899,15 @@ case 24: _par->line_length = _par->var.xres_virtual * 3; _par->visual = FB_VISUAL_DIRECTCOLOR; -#ifdef CONFIG_PREP - _par->var.red.offset = 8; - _par->var.green.offset = 16; - _par->var.blue.offset = 24; -#else - _par->var.red.offset = 16; - _par->var.green.offset = 8; - _par->var.blue.offset = 0; -#endif + if(isPReP) { + _par->var.red.offset = 8; + _par->var.green.offset = 16; + _par->var.blue.offset = 24; + } else { + _par->var.red.offset = 16; + _par->var.green.offset = 8; + _par->var.blue.offset = 0; + } _par->var.red.length = 8; _par->var.green.length = 8; _par->var.blue.length = 8; @@ -910,15 +916,15 @@ case 32: _par->line_length = _par->var.xres_virtual * 4; _par->visual = FB_VISUAL_DIRECTCOLOR; -#ifdef CONFIG_PREP - _par->var.red.offset = 8; - _par->var.green.offset = 16; - _par->var.blue.offset = 24; -#else - _par->var.red.offset = 16; - _par->var.green.offset = 8; - _par->var.blue.offset = 0; -#endif + if(isPReP) { + _par->var.red.offset = 8; + _par->var.green.offset = 16; + _par->var.blue.offset = 24; + } else { + _par->var.red.offset = 16; + _par->var.green.offset = 8; + _par->var.blue.offset = 0; + } _par->var.red.length = 8; _par->var.green.length = 8; _par->var.blue.length = 8; @@ -1680,18 +1686,18 @@ #ifdef FBCON_HAS_CFB16 case 16: assert (regno < 16); -#ifdef CONFIG_PREP - fb_info->fbcon_cmap.cfb16[regno] = - ((red & 0xf800) >> 9) | - ((green & 0xf800) >> 14) | - ((green & 0xf800) << 2) | - ((blue & 0xf800) >> 3); -#else - fb_info->fbcon_cmap.cfb16[regno] = - ((red & 0xf800) >> 1) | - ((green & 0xf800) >> 6) | - ((blue & 0xf800) >> 11); -#endif + if(isPReP) { + fb_info->fbcon_cmap.cfb16[regno] = + ((red & 0xf800) >> 9) | + ((green & 0xf800) >> 14) | + ((green & 0xf800) << 2) | + ((blue & 0xf800) >> 3); + } else { + fb_info->fbcon_cmap.cfb16[regno] = + ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + } #endif /* FBCON_HAS_CFB16 */ #ifdef FBCON_HAS_CFB24 @@ -1707,17 +1713,17 @@ #ifdef FBCON_HAS_CFB32 case 32: assert (regno < 16); -#ifdef CONFIG_PREP - fb_info->fbcon_cmap.cfb32[regno] = - ((red & 0xff00)) | - ((green & 0xff00) << 8) | - ((blue & 0xff00) << 16); -#else - fb_info->fbcon_cmap.cfb32[regno] = - ((red & 0xff00) << 8) | - ((green & 0xff00)) | - ((blue & 0xff00) >> 8); -#endif + if(isPReP) { + fb_info->fbcon_cmap.cfb32[regno] = + ((red & 0xff00)) | + ((green & 0xff00) << 8) | + ((blue & 0xff00) << 16); + } else { + fb_info->fbcon_cmap.cfb32[regno] = + ((red & 0xff00) << 8) | + ((green & 0xff00)) | + ((blue & 0xff00) >> 8); + } break; #endif /* FBCON_HAS_CFB32 */ default: @@ -2374,7 +2380,7 @@ -#ifdef CONFIG_PREP +#ifdef CONFIG_ALL_PPC #define PREP_VIDEO_BASE ((volatile unsigned long) 0xC0000000) #define PREP_IO_BASE ((volatile unsigned char *) 0x80000000) static void __init get_prep_addrs (unsigned long *display, unsigned long *registers) @@ -2387,7 +2393,7 @@ DPRINTK ("EXIT\n"); } -#endif /* CONFIG_PREP */ +#endif /* CONFIG_ALL_PPC */ @@ -2510,26 +2516,26 @@ info->pdev = pdev; -#ifdef CONFIG_PREP - /* Xbh does this, though 0 seems to be the init value */ - pcibios_write_config_dword (0, pdev->devfn, PCI_BASE_ADDRESS_0, 0x00000000); -#endif + if(isPReP) { + /* Xbh does this, though 0 seems to be the init value */ + pcibios_write_config_dword (0, pdev->devfn, PCI_BASE_ADDRESS_0, + 0x00000000); -#ifdef CONFIG_PREP - get_prep_addrs (&board_addr, &info->fbregs_phys); -#else /* CONFIG_PREP */ - DPRINTK ("Attempt to get PCI info for Cirrus Graphics Card\n"); - get_pci_addrs (pdev, &board_addr, &info->fbregs_phys); -#endif /* CONFIG_PREP */ +#ifdef CONFIG_ALL_PPC + get_prep_addrs (&board_addr, &info->fbregs_phys); +#endif + } else { + DPRINTK ("Attempt to get PCI info for Cirrus Graphics Card\n"); + get_pci_addrs (pdev, &board_addr, &info->fbregs_phys); + } DPRINTK ("Board address: 0x%lx, register address: 0x%lx\n", board_addr, info->fbregs_phys); -#ifdef CONFIG_PREP - /* PReP dies if we ioremap the IO registers, but it works w/out... */ - info->regs = (char *) info->fbregs_phys; -#else - info->regs = 0; /* FIXME: this forces VGA. alternatives? */ -#endif + if(isPReP) { + /* PReP dies if we ioremap the IO registers, but it works w/out... */ + info->regs = (char *) info->fbregs_phys; + } else + info->regs = 0; /* FIXME: this forces VGA. alternatives? */ if (*btype == BT_GD5480) { board_size = 32 * MB_; @@ -3222,7 +3228,9 @@ * bestclock() - determine closest possible clock lower(?) than the * desired pixel clock **************************************************************************/ +#ifndef abs #define abs(x) ((x)<0 ? -(x) : (x)) +#endif static void bestclock (long freq, long *best, long *nom, long *den, long *div, long maxfreq) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/controlfb.c linux.ac/drivers/video/controlfb.c --- linux.vanilla/drivers/video/controlfb.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/controlfb.c Tue Apr 3 17:55:09 2001 @@ -3,6 +3,9 @@ * * Created 12 July 1998 by Dan Jacobowitz <dan@debian.org> * Copyright (C) 1998 Dan Jacobowitz + * Copyright (C) 2001 Takashi Oe + * + * Mmap code by Michel Lanners <mlan@cpu.lu> * * Frame buffer structure from: * drivers/video/chipsfb.c -- frame buffer device for @@ -62,26 +65,40 @@ int xres, yres; int vxres, vyres; int xoffset, yoffset; + int pitch; + struct control_regvals regvals; + unsigned long sync; + unsigned char ctrl; }; #define DIRTY(z) ((x)->z != (y)->z) +#define DIRTY_CMAP(z) (memcmp(&((x)->z), &((y)->z), sizeof((y)->z))) static inline int PAR_EQUAL(struct fb_par_control *x, struct fb_par_control *y) { - return (!DIRTY(vmode) && !DIRTY(cmode) && !DIRTY(xres) - && !DIRTY(yres) && !DIRTY(vxres) && !DIRTY(vyres) - && !DIRTY(xoffset) && !DIRTY(yoffset)); + int i, results; + + results = 1; + for (i = 0; i < 3; i++) + results &= !DIRTY(regvals.clock_params[i]); + if (!results) + return 0; + for (i = 0; i < 16; i++) + results &= !DIRTY(regvals.regs[i]); + if (!results) + return 0; + return (!DIRTY(cmode) && !DIRTY(xres) && !DIRTY(yres) + && !DIRTY(vxres) && !DIRTY(vyres)); } static inline int VAR_MATCH(struct fb_var_screeninfo *x, struct fb_var_screeninfo *y) { return (!DIRTY(bits_per_pixel) && !DIRTY(xres) && !DIRTY(yres) && !DIRTY(xres_virtual) - && !DIRTY(yres_virtual)); + && !DIRTY(yres_virtual) + && !DIRTY_CMAP(red) && !DIRTY_CMAP(green) && !DIRTY_CMAP(blue)); } struct fb_info_control { struct fb_info info; -/* struct fb_fix_screeninfo fix; - struct fb_var_screeninfo var;*/ struct display display; struct fb_par_control par; struct { @@ -93,12 +110,16 @@ struct control_regs *control_regs; unsigned long control_regs_phys; + unsigned long control_regs_size; __u8 *frame_buffer; unsigned long frame_buffer_phys; - - int sense, control_use_bank2; + unsigned long fb_orig_base; + unsigned long fb_orig_size; + + int control_use_bank2; unsigned long total_vram; + unsigned char vram_attr; union { #ifdef FBCON_HAS_CFB16 u16 cfb16[16]; @@ -109,61 +130,96 @@ } fbcon_cmap; }; +/* control register access macro */ +#define CNTRL_REG(INFO,REG) (&(((INFO)->control_regs-> ## REG).r)) + + /******************** Prototypes for exported functions ********************/ +/* + * struct fb_ops + */ static int control_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *info); + struct fb_info *info); static int control_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info); + struct fb_info *info); static int control_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info); + struct fb_info *info); static int control_pan_display(struct fb_var_screeninfo *var, int con, - struct fb_info *info); + struct fb_info *info); static int control_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); + struct fb_info *info); static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); + struct fb_info *info); static int control_mmap(struct fb_info *info, struct file *file, - struct vm_area_struct *vma); + struct vm_area_struct *vma); +/* + * low level fbcon ops + */ +static int controlfb_switch(int con, struct fb_info *info); +static int controlfb_updatevar(int con, struct fb_info *info); +static void controlfb_blank(int blank_mode, struct fb_info *info); +/* + * low level cmap set/get ops + */ static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green, - u_int *blue, u_int *transp, struct fb_info *info); + u_int *blue, u_int *transp, struct fb_info *info); static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); - -/******************** Prototypes for internal functions ********************/ -static void control_par_to_fix(struct fb_par_control *par, struct fb_fix_screeninfo *fix, - struct fb_info_control *p); -static void do_install_cmap(int con, struct fb_info *info); -static void control_set_dispsw(struct display *disp, int cmode, struct fb_info_control *p); - -/************************* Internal variables *****************************/ -static int currcon = 0; -static int par_set = 0; -static char fontname[40] __initdata = { 0 }; -static int default_vmode = VMODE_NVRAM; -static int default_cmode = CMODE_NVRAM; + u_int transp, struct fb_info *info); /* - * Exported functions + * inititialization */ int control_init(void); void control_setup(char *); -static void control_of_init(struct device_node *dp); -static int read_control_sense(struct fb_info_control *p); -static inline int control_vram_reqd(int video_mode, int color_mode); +/* + * low level fbcon revc ops + */ +static void control_cfb16_revc(struct display *p, int xx, int yy); +static void control_cfb32_revc(struct display *p, int xx, int yy); + + +/******************** Prototypes for internal functions **********************/ + +static void do_install_cmap(struct display *disp, struct fb_info *info); static void set_control_clock(unsigned char *params); -static void control_set_hardware(struct fb_info_control *p, struct fb_par_control *par); -static inline void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var); +static int init_control(struct fb_info_control *p); +static void control_set_hardware(struct fb_info_control *p, + struct fb_par_control *par); +static int control_of_init(struct device_node *dp); +static void control_par_to_fix(struct fb_par_control *par, + struct fb_fix_screeninfo *fix, struct fb_info_control *p); +static void control_set_dispsw(struct display *disp, int cmode, + struct fb_info_control *p); +static void find_vram_size(struct fb_info_control *p); +static int read_control_sense(struct fb_info_control *p); +static int calc_clock_params(unsigned long clk, unsigned char *param); static int control_var_to_par(struct fb_var_screeninfo *var, struct fb_par_control *par, const struct fb_info *fb_info); - -static void control_init_info(struct fb_info *info, struct fb_info_control *p); +static inline void control_par_to_var(struct fb_par_control *par, + struct fb_var_screeninfo *var); +static void control_par_to_fix(struct fb_par_control *par, + struct fb_fix_screeninfo *fix, struct fb_info_control *p); static void control_par_to_display(struct fb_par_control *par, - struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_control *p); + struct display *disp, struct fb_fix_screeninfo *fix, + struct fb_info_control *p); +static void control_set_dispsw(struct display *disp, int cmode, + struct fb_info_control *p); +static void control_init_info(struct fb_info *info, struct fb_info_control *p); +static void control_cleanup(void); + + +/************************** Internal variables *******************************/ + +static int currcon; +static struct fb_info_control *control_fb; + +static char fontname[40] __initdata = { 0 }; +static int default_vmode __initdata = VMODE_NVRAM; +static int default_cmode __initdata = CMODE_NVRAM; -static int controlfb_updatevar(int con, struct fb_info *info); static struct fb_ops controlfb_ops = { owner: THIS_MODULE, @@ -177,7 +233,6 @@ }; - /******************** The functions for controlfb_ops ********************/ #ifdef MODULE @@ -185,18 +240,16 @@ { struct device_node *dp; - printk("Loading...\n"); dp = find_devices("control"); - if (dp != 0) - control_of_init(dp); - else - printk("Failed.\n"); - printk("Done.\n"); + if (dp != 0 && !control_of_init(dp)) + return 0; + + return -ENXIO; } void cleanup_module(void) { - /* FIXME: clean up and release regions */ + control_cleanup(); } #endif @@ -207,8 +260,6 @@ { struct fb_info_control *p = (struct fb_info_control *) info; - if(!par_set) - printk(KERN_ERR "control_get_fix called with unset par!\n"); if(con == -1) { control_par_to_fix(&p->par, fix, p); } else { @@ -225,8 +276,6 @@ { struct fb_info_control *p = (struct fb_info_control *) info; - if(!par_set) - printk(KERN_ERR "control_get_var called with unset par!\n"); if(con == -1) { control_par_to_var(&p->par, var); } else { @@ -235,8 +284,10 @@ return 0; } -/* Sets everything according to var */ -/* No longer safe for use in console switching */ + +/* + * Sets everything according to var + */ static int control_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { @@ -246,10 +297,10 @@ int depthchange, err; int activate = var->activate; - disp = (con >= 0) ? &fb_display[con] : info->disp; - if((err = control_var_to_par(var, &par, info))) { - printk (KERN_ERR "control_set_var: error calling control_var_to_par: %d.\n", err); + if (con < 0) + printk (KERN_ERR "control_set_var: error calling" + " control_var_to_par: %d.\n", err); return err; } @@ -258,8 +309,8 @@ if ((activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) return 0; -/* I know, we want to use fb_display[con], but grab certain info from p->var instead. */ -/* [above no longer true] */ + disp = (con >= 0) ? &fb_display[con] : info->disp; + depthchange = (disp->var.bits_per_pixel != var->bits_per_pixel); if(!VAR_MATCH(&disp->var, var)) { struct fb_fix_screeninfo fix; @@ -269,32 +320,54 @@ (*info->changevar)(con); } else disp->var = *var; - /*p->disp = *disp;*/ - - if(con == currcon || con == -1) { + if(con == currcon) { control_set_hardware(p, &par); + if(depthchange) { + if((err = fb_alloc_cmap(&disp->cmap, 0, 0))) + return err; + do_install_cmap(disp, info); + } } - if(depthchange) { - if((err = fb_alloc_cmap(&disp->cmap, 0, 0))) - return err; - do_install_cmap(con, info); - } + return 0; } + +/* + * Set screen start address according to var offset values + */ +static inline void set_screen_start(int xoffset, int yoffset, + struct fb_info_control *p) +{ + struct fb_par_control *par = &p->par; + + par->xoffset = xoffset; + par->yoffset = yoffset; + out_le32(CNTRL_REG(p,start_addr), + par->yoffset * par->pitch + (par->xoffset << par->cmode)); +} + + static int control_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info) { + unsigned int xoffset, hstep; struct fb_info_control *p = (struct fb_info_control *)info; struct fb_par_control *par = &p->par; - - if (var->xoffset != 0 || var->yoffset+var->yres > var->yres_virtual) + + /* + * make sure start addr will be 32-byte aligned + */ + hstep = 0x1f >> par->cmode; + xoffset = (var->xoffset + hstep) & ~hstep; + + if (xoffset+par->xres > par->vxres || + var->yoffset+par->yres > par->vyres) return -EINVAL; - fb_display[con].var.yoffset = par->yoffset = var->yoffset; - if(con == currcon) - out_le32(&p->control_regs->start_addr.r, - par->yoffset * (par->vxres << par->cmode)); + + set_screen_start(xoffset, var->yoffset, p); + return 0; } @@ -315,11 +388,10 @@ static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { - struct display *disp = &fb_display[con]; - int err; + struct display *disp = (con < 0)? info->disp: &fb_display[con]; + int err, size = disp->var.bits_per_pixel == 16 ? 32 : 256; - if (disp->cmap.len == 0) { - int size = disp->var.bits_per_pixel == 16 ? 32 : 256; + if (disp->cmap.len != size) { err = fb_alloc_cmap(&disp->cmap, size, 0); if (err) return err; @@ -330,7 +402,9 @@ return 0; } -/* Private mmap since we want to have a different caching on the framebuffer + +/* + * Private mmap since we want to have a different caching on the framebuffer * for controlfb. * Note there's no locking in here; it's done in fb_mmap() in fbmem.c. */ @@ -363,6 +437,9 @@ pgprot_val(vma->vm_page_prot) |= _PAGE_WRITETHRU; } start &= PAGE_MASK; + if ((vma->vm_end - vma->vm_start + off) > len) + return -EINVAL; + off += start; vma->vm_pgoff = off >> PAGE_SHIFT; if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot)) @@ -372,77 +449,80 @@ } -/******************** End of controlfb_ops implementation ********************/ -/* (new one that is) */ +/******************** End of controlfb_ops implementation ******************/ +/* + * low level fbcon ops + */ static int controlfb_switch(int con, struct fb_info *info) { struct fb_info_control *p = (struct fb_info_control *)info; struct fb_par_control par; - int oldcon = currcon; - if (fb_display[currcon].cmap.len) + if (currcon >= 0 && fb_display[currcon].cmap.len) fb_get_cmap(&fb_display[currcon].cmap, 1, controlfb_getcolreg, info); currcon = con; + fb_display[con].var.activate = FB_ACTIVATE_NOW; control_var_to_par(&fb_display[con].var, &par, info); control_set_hardware(p, &par); control_set_dispsw(&fb_display[con], par.cmode, p); + do_install_cmap(&fb_display[con], info); - if(fb_display[oldcon].var.yoffset != fb_display[con].var.yoffset) - controlfb_updatevar(con, info); - - do_install_cmap(con, info); return 1; } + static int controlfb_updatevar(int con, struct fb_info *info) { - struct fb_info_control *p = (struct fb_info_control *)info; + struct fb_var_screeninfo *var = &fb_display[con].var; + struct fb_info_control *p = (struct fb_info_control *) info; + + set_screen_start(var->xoffset, var->yoffset, p); - if(con != currcon) - return 0; - /* imsttfb blanks the unused bottom of the screen here...hmm. */ - out_le32(&p->control_regs->start_addr.r, - fb_display[con].var.yoffset * fb_display[con].line_length); - return 0; } + static void controlfb_blank(int blank_mode, struct fb_info *info) { -/* - * Blank the screen if blank_mode != 0, else unblank. If blank == NULL - * then the caller blanks by setting the CLUT (Color Look Up Table) to all - * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due - * to e.g. a video mode which doesn't support it. Implements VESA suspend - * and powerdown modes on hardware that supports disabling hsync/vsync: - * blank_mode == 2: suspend vsync - * blank_mode == 3: suspend hsync - * blank_mode == 4: powerdown - */ -/* A blank_mode of 1+VESA_NO_BLANKING or 1+VESA_POWERDOWN act alike... */ struct fb_info_control *p = (struct fb_info_control *) info; - int ctrl; - - if(blank_mode == 1+VESA_NO_BLANKING) - blank_mode = 1+VESA_POWERDOWN; - ctrl = ld_le32(&p->control_regs->ctrl.r) | 0x33; - if (blank_mode) - --blank_mode; - if (blank_mode & VESA_VSYNC_SUSPEND) - ctrl &= ~3; - if (blank_mode & VESA_HSYNC_SUSPEND) - ctrl &= ~0x30; - out_le32(&p->control_regs->ctrl.r, ctrl); + unsigned ctrl; -/* TODO: Figure out how the heck to powerdown this thing! */ + ctrl = ld_le32(CNTRL_REG(p,ctrl)); + if (blank_mode > 0) + switch (blank_mode - 1) { + case VESA_VSYNC_SUSPEND: + ctrl &= ~3; + break; + case VESA_HSYNC_SUSPEND: + ctrl &= ~0x30; + break; + case VESA_POWERDOWN: + ctrl &= ~0x33; + /* fall through */ + case VESA_NO_BLANKING: + ctrl |= 0x400; + break; + default: + break; + } + else { + ctrl &= ~0x400; + ctrl |= 0x33; + } + out_le32(CNTRL_REG(p,ctrl), ctrl); - return; + return; } + +/* + * low level cmap set/get ops + */ + static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info) { @@ -497,33 +577,25 @@ return 0; } -static void do_install_cmap(int con, struct fb_info *info) +static void do_install_cmap(struct display *disp, struct fb_info *info) { - if (con != currcon) - return; - if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, controlfb_setcolreg, + if (disp->cmap.len) + fb_set_cmap(&disp->cmap, 1, controlfb_setcolreg, info); else { - int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; + int size = disp->var.bits_per_pixel == 16 ? 32 : 256; fb_set_cmap(fb_default_cmap(size), 1, controlfb_setcolreg, info); } } -static inline int control_vram_reqd(int video_mode, int color_mode) -{ - return (control_reg_init[video_mode-1]->vres - * control_reg_init[video_mode-1]->hres << color_mode) - + control_reg_init[video_mode-1]->offset[color_mode]; -} static void set_control_clock(unsigned char *params) { +#ifdef CONFIG_ADB_CUDA struct adb_request req; int i; -#ifdef CONFIG_ADB_CUDA for (i = 0; i < 3; ++i) { cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x50, i + 1, params[i]); @@ -534,128 +606,137 @@ } -static void __init init_control(struct fb_info_control *p) +/* + * finish off the driver initialization and register + */ +static int __init init_control(struct fb_info_control *p) { - struct fb_par_control parstruct; - struct fb_par_control *par = &parstruct; + int full, sense, vmode, cmode, vyres; struct fb_var_screeninfo var; - p->sense = read_control_sense(p); - printk(KERN_INFO "Monitor sense value = 0x%x, ", p->sense); + printk(KERN_INFO "controlfb: "); + + full = p->total_vram == 0x400000; + /* Try to pick a video mode out of NVRAM if we have one. */ - if (default_vmode == VMODE_NVRAM) { - par->vmode = nvram_read_byte(NV_VMODE); - if(par->vmode <= 0 || par->vmode > VMODE_MAX || !control_reg_init[par->vmode - 1]) - par->vmode = VMODE_CHOOSE; - if(par->vmode == VMODE_CHOOSE) - par->vmode = mac_map_monitor_sense(p->sense); - if(!control_reg_init[par->vmode - 1]) - par->vmode = VMODE_640_480_60; + if (default_cmode == CMODE_NVRAM){ + cmode = nvram_read_byte(NV_CMODE); + if(cmode < CMODE_8 || cmode > CMODE_32) + cmode = CMODE_8; } else - par->vmode=default_vmode; + cmode=default_cmode; + + if (default_vmode == VMODE_NVRAM) { + vmode = nvram_read_byte(NV_VMODE); + if (vmode < 1 || vmode > VMODE_MAX || + control_mac_modes[vmode - 1].m[full] < cmode) { + sense = read_control_sense(p); + printk("Monitor sense value = 0x%x, ", sense); + vmode = mac_map_monitor_sense(sense); + if (control_mac_modes[vmode - 1].m[full] < cmode) + vmode = VMODE_640_480_60; + } + } else { + vmode=default_vmode; + if (control_mac_modes[vmode - 1].m[full] < cmode) { + if (cmode > CMODE_8) + cmode--; + else + vmode = VMODE_640_480_60; + } + } + + if (mac_vmode_to_var(vmode, cmode, &var) < 0) { + /* This shouldn't happen! */ + printk("mac_vmode_to_var(%d, %d,) failed\n", vmode, cmode); +try_again: + vmode = VMODE_640_480_60; + cmode = CMODE_8; + if (mac_vmode_to_var(vmode, cmode, &var) < 0) { + printk(KERN_ERR "controlfb: mac_vmode_to_var() failed\n"); + return -ENXIO; + } + printk(KERN_INFO "controlfb: "); + } + printk("using video mode %d and color mode %d.\n", vmode, cmode); + + vyres = (p->total_vram - CTRLFB_OFF) / (var.xres << cmode); + if (vyres > var.yres) + var.yres_virtual = vyres; - if (default_cmode == CMODE_NVRAM){ - par->cmode = nvram_read_byte(NV_CMODE); - if(par->cmode < CMODE_8 || par->cmode > CMODE_32) - par->cmode = CMODE_8;} - else - par->cmode=default_cmode; - /* - * Reduce the pixel size if we don't have enough VRAM. - */ - while(par->cmode > CMODE_8 && control_vram_reqd(par->vmode, par->cmode) > p->total_vram) - par->cmode--; - - printk("using video mode %d and color mode %d.\n", par->vmode, par->cmode); - - par->vxres = par->xres = control_reg_init[par->vmode - 1]->hres; - par->yres = control_reg_init[par->vmode - 1]->vres; - par->vyres = p->total_vram / (par->vxres << par->cmode); - par->xoffset = par->yoffset = 0; - control_init_info(&p->info, p); - - par_set = 1; /* Debug */ - - control_par_to_var(par, &var); + currcon = -1; var.activate = FB_ACTIVATE_NOW; - control_set_var(&var, -1, &p->info); - - p->info.flags = FBINFO_FLAG_DEFAULT; - if (register_framebuffer(&p->info) < 0) { - kfree(p); - return; + + if (control_set_var(&var, -1, &p->info) < 0) { + if (vmode != VMODE_640_480_60 || cmode != CMODE_8) + goto try_again; + printk(KERN_ERR "controlfb: initilization failed\n"); + return -ENXIO; } + + p->info.flags = FBINFO_FLAG_DEFAULT; + if (register_framebuffer(&p->info) < 0) + return -ENXIO; printk(KERN_INFO "fb%d: control display adapter\n", GET_FB_IDX(p->info.node)); + + return 0; } -#define STORE_D2(a,d) \ +#define RADACAL_WRITE(a,d) \ out_8(&p->cmap_regs->addr, (a)); \ - out_8(&p->cmap_regs->d2, (d)) + out_8(&p->cmap_regs->dat, (d)) /* Now how about actually saying, Make it so! */ /* Some things in here probably don't need to be done each time. */ static void control_set_hardware(struct fb_info_control *p, struct fb_par_control *par) { - struct control_regvals *init; + struct control_regvals *r; volatile struct preg *rp; - int flags, ctrl, i; - int vmode, cmode; - - if(PAR_EQUAL(&p->par, par)) + int i, cmode; + + if (PAR_EQUAL(&p->par, par)) { + /* + * check if only xoffset or yoffset differs. + * this prevents flickers in typical VT switch case. + */ + if (p->par.xoffset != par->xoffset || + p->par.yoffset != par->yoffset) + set_screen_start(par->xoffset, par->yoffset, p); + return; + } p->par = *par; - - vmode = p->par.vmode; cmode = p->par.cmode; + r = &par->regvals; - init = control_reg_init[vmode - 1]; + /* Turn off display */ + out_le32(CNTRL_REG(p,ctrl), 0x400 | par->ctrl); - if (control_vram_reqd(vmode, cmode) > 0x200000) - flags = 0x51; - else if (p->control_use_bank2) - flags = 0x39; - else - flags = 0x31; - if (vmode >= VMODE_1280_960_75 && cmode >= CMODE_16) - ctrl = 0x7f; - else - ctrl = 0x3b; - - /* Initialize display timing registers */ - out_le32(&p->control_regs->ctrl.r, 0x43b); - - set_control_clock(init->clock_params); + set_control_clock(r->clock_params); - STORE_D2(0x20, init->radacal_ctrl[cmode]); - STORE_D2(0x21, p->control_use_bank2 ? 0 : 1); - STORE_D2(0x10, 0); - STORE_D2(0x11, 0); + RADACAL_WRITE(0x20, r->radacal_ctrl); + RADACAL_WRITE(0x21, p->control_use_bank2 ? 0 : 1); + RADACAL_WRITE(0x10, 0); + RADACAL_WRITE(0x11, 0); rp = &p->control_regs->vswin; for (i = 0; i < 16; ++i, ++rp) - out_le32(&rp->r, init->regs[i]); + out_le32(&rp->r, r->regs[i]); - out_le32(&p->control_regs->pitch.r, par->vxres << cmode); - out_le32(&p->control_regs->mode.r, init->mode[cmode]); - out_le32(&p->control_regs->flags.r, flags); - out_le32(&p->control_regs->start_addr.r, - par->yoffset * (par->vxres << cmode)); - out_le32(&p->control_regs->reg18.r, 0x1e5); - out_le32(&p->control_regs->reg19.r, 0); - - for (i = 0; i < 16; ++i) { - controlfb_setcolreg(color_table[i], default_red[i]<<8, - default_grn[i]<<8, default_blu[i]<<8, - 0, (struct fb_info *)p); - } -/* Does the above need to be here each time? -- danj */ + out_le32(CNTRL_REG(p,pitch), par->pitch); + out_le32(CNTRL_REG(p,mode), r->mode); + out_le32(CNTRL_REG(p,vram_attr), p->vram_attr); + out_le32(CNTRL_REG(p,start_addr), par->yoffset * par->pitch + + (par->xoffset << cmode)); + out_le32(CNTRL_REG(p,rfrcnt), 0x1e5); + out_le32(CNTRL_REG(p,intr_ena), 0); /* Turn on display */ - out_le32(&p->control_regs->ctrl.r, ctrl); - + out_le32(CNTRL_REG(p,ctrl), par->ctrl); + #ifdef CONFIG_FB_COMPAT_XPMAC /* And let the world know the truth. */ if (!console_fb_info || console_fb_info == &p->info) { @@ -663,12 +744,11 @@ display_info.width = p->par.xres; display_info.depth = (cmode == CMODE_32) ? 32 : ((cmode == CMODE_16) ? 16 : 8); - display_info.pitch = p->par.vxres << p->par.cmode; - display_info.mode = vmode; + display_info.pitch = p->par.pitch; + display_info.mode = p->par.vmode; strncpy(display_info.name, "control", sizeof(display_info.name)); - display_info.fb_address = p->frame_buffer_phys - + control_reg_init[vmode-1]->offset[cmode]; + display_info.fb_address = p->frame_buffer_phys + CTRLFB_OFF; display_info.cmap_adr_address = p->cmap_regs_phys; display_info.cmap_data_address = p->cmap_regs_phys + 0x30; display_info.disp_reg_address = p->control_regs_phys; @@ -677,99 +757,173 @@ #endif /* CONFIG_FB_COMPAT_XPMAC */ } + +/* + * Called from fbmem.c for probing & intializing + */ int __init control_init(void) { struct device_node *dp; dp = find_devices("control"); - if (dp != 0) - control_of_init(dp); - return 0; + if (dp != 0 && !control_of_init(dp)) + return 0; + + return -ENXIO; +} + + +/* Work out which banks of VRAM we have installed. */ +/* danj: I guess the card just ignores writes to nonexistant VRAM... */ + +static void __init find_vram_size(struct fb_info_control *p) +{ + int bank1, bank2; + + /* + * Set VRAM in 2MB (bank 1) mode + * VRAM Bank 2 will be accessible through offset 0x600000 if present + * and VRAM Bank 1 will not respond at that offset even if present + */ + out_le32(CNTRL_REG(p,vram_attr), 0x31); + + out_8(&p->frame_buffer[0x600000], 0xb3); + out_8(&p->frame_buffer[0x600001], 0x71); + asm volatile("eieio; dcbf 0,%0" : : "r" (&p->frame_buffer[0x600000]) + : "memory" ); + mb(); + asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x600000]) + : "memory" ); + mb(); + + bank2 = (in_8(&p->frame_buffer[0x600000]) == 0xb3) + && (in_8(&p->frame_buffer[0x600001]) == 0x71); + + /* + * Set VRAM in 2MB (bank 2) mode + * VRAM Bank 1 will be accessible through offset 0x000000 if present + * and VRAM Bank 2 will not respond at that offset even if present + */ + out_le32(CNTRL_REG(p,vram_attr), 0x39); + + out_8(&p->frame_buffer[0], 0x5a); + out_8(&p->frame_buffer[1], 0xc7); + asm volatile("eieio; dcbf 0,%0" : : "r" (&p->frame_buffer[0]) + : "memory" ); + mb(); + asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0]) + : "memory" ); + mb(); + + bank1 = (in_8(&p->frame_buffer[0]) == 0x5a) + && (in_8(&p->frame_buffer[1]) == 0xc7); + + if (bank2) { + if (!bank1) { + /* + * vram bank 2 only + */ + p->control_use_bank2 = 1; + p->vram_attr = 0x39; + p->frame_buffer += 0x600000; + p->frame_buffer_phys += 0x600000; + } else { + /* + * 4 MB vram + */ + p->vram_attr = 0x51; + } + } else { + /* + * vram bank 1 only + */ + p->vram_attr = 0x31; + } + + p->total_vram = (bank1 + bank2) * 0x200000; + + printk(KERN_INFO "controlfb: VRAM Total = %dMB " + "(%dMB @ bank 1, %dMB @ bank 2)\n", + (bank1 + bank2) << 1, bank1 << 1, bank2 << 1); } -static void __init control_of_init(struct device_node *dp) + +/* + * find "control" and initialize + */ +static int __init control_of_init(struct device_node *dp) { struct fb_info_control *p; - unsigned long addr, size; - int i, bank1, bank2; + unsigned long addr; + int i; + if (control_fb) { + printk(KERN_ERR "controlfb: only one control is supported\n"); + return -ENXIO; + } if(dp->n_addrs != 2) { printk(KERN_ERR "expecting 2 address for control (got %d)", dp->n_addrs); - return; + return -ENXIO; } p = kmalloc(sizeof(*p), GFP_ATOMIC); if (p == 0) - return; + return -ENXIO; + control_fb = p; /* save it for cleanups */ memset(p, 0, sizeof(*p)); /* Map in frame buffer and registers */ for (i = 0; i < dp->n_addrs; ++i) { addr = dp->addrs[i].address; - size = dp->addrs[i].size; - /* Let's assume we can request either all or nothing */ - if (!request_mem_region(addr, size, "controlfb")) { - kfree(p); - return; - } - if (size >= 0x800000) { + if (dp->addrs[i].size >= 0x800000) { + p->fb_orig_base = addr; + p->fb_orig_size = dp->addrs[i].size; /* use the big-endian aperture (??) */ - addr += 0x800000; - /* map at most 8MB for the frame buffer */ - p->frame_buffer_phys = addr; - p->frame_buffer = __ioremap(addr, 0x800000, _PAGE_WRITETHRU); + p->frame_buffer_phys = addr + 0x800000; } else { p->control_regs_phys = addr; - p->control_regs = ioremap(addr, size); + p->control_regs_size = dp->addrs[i].size; } } + + if (!p->fb_orig_base || + !request_mem_region(p->fb_orig_base,p->fb_orig_size,"controlfb")) { + p->fb_orig_base = 0; + goto error_out; + } + /* map at most 8MB for the frame buffer */ + p->frame_buffer = __ioremap(p->frame_buffer_phys, 0x800000, + _PAGE_WRITETHRU); + + if (!p->control_regs_phys || + !request_mem_region(p->control_regs_phys, p->control_regs_size, + "controlfb regs")) { + p->control_regs_phys = 0; + goto error_out; + } + p->control_regs = ioremap(p->control_regs_phys, p->control_regs_size); + p->cmap_regs_phys = 0xf301b000; /* XXX not in prom? */ - request_mem_region(p->cmap_regs_phys, 0x1000, "controlfb cmap"); + if (!request_mem_region(p->cmap_regs_phys, 0x1000, "controlfb cmap")) { + p->cmap_regs_phys = 0; + goto error_out; + } p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000); - /* Work out which banks of VRAM we have installed. */ - /* According to Andrew Fyfe <bandr@best.com>, the VRAM behaves like so: */ - /* afyfe: observations from an 8500: - * - with 2M vram in bank 1, it appears at offsets 0, 2M and 4M - * - with 2M vram in bank 2, it appears only at offset 6M - * - with 4M vram, it appears only as a 4M block at offset 0. - */ + if (!p->cmap_regs || !p->control_regs || !p->frame_buffer) + goto error_out; - /* We know there is something at 2M if there is something at 0M. */ - out_8(&p->frame_buffer[0x200000], 0xa5); - out_8(&p->frame_buffer[0x200001], 0x38); - asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x200000]) : "memory" ); + find_vram_size(p); + if (!p->total_vram) + goto error_out; - out_8(&p->frame_buffer[0], 0x5a); - out_8(&p->frame_buffer[1], 0xc7); - asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0]) : "memory" ); + if (init_control(p) < 0) + goto error_out; - bank1 = (in_8(&p->frame_buffer[0x000000]) == 0x5a) - && (in_8(&p->frame_buffer[0x000001]) == 0xc7); - bank2 = (in_8(&p->frame_buffer[0x200000]) == 0xa5) - && (in_8(&p->frame_buffer[0x200001]) == 0x38); - - if(bank2 && !bank1) - printk(KERN_INFO "controlfb: Found memory at 2MB but not at 0! Please contact dan@debian.org\n"); - - if(!bank1) { - out_8(&p->frame_buffer[0x600000], 0xa5); - out_8(&p->frame_buffer[0x600001], 0x38); - asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x600000]) : "memory" ); - bank2 = (in_8(&p->frame_buffer[0x600000]) == 0xa5) - && (in_8(&p->frame_buffer[0x600001]) == 0x38); - /* If we don't have bank 1 installed, we hope we have bank 2 :-) */ - p->control_use_bank2 = 1; - p->frame_buffer += 0x600000; - p->frame_buffer_phys += 0x600000; - } - - p->total_vram = (bank1 + bank2) * 0x200000; - - printk(KERN_INFO "controlfb: Memory bank 1 %s, bank 2 %s, total VRAM %dMB\n", - bank1 ? "present" : "absent", bank2 ? "present" : "absent", - 2 * (bank1 + bank2)); + return 0; - init_control(p); +error_out: + control_cleanup(); + return -ENXIO; } /* @@ -781,181 +935,234 @@ { int sense; - out_le32(&p->control_regs->mon_sense.r, 7); /* drive all lines high */ + out_le32(CNTRL_REG(p,mon_sense), 7); /* drive all lines high */ __delay(200); - out_le32(&p->control_regs->mon_sense.r, 077); /* turn off drivers */ + out_le32(CNTRL_REG(p,mon_sense), 077); /* turn off drivers */ __delay(2000); - sense = (in_le32(&p->control_regs->mon_sense.r) & 0x1c0) << 2; + sense = (in_le32(CNTRL_REG(p,mon_sense)) & 0x1c0) << 2; /* drive each sense line low in turn and collect the other 2 */ - out_le32(&p->control_regs->mon_sense.r, 033); /* drive A low */ + out_le32(CNTRL_REG(p,mon_sense), 033); /* drive A low */ __delay(2000); - sense |= (in_le32(&p->control_regs->mon_sense.r) & 0xc0) >> 2; - out_le32(&p->control_regs->mon_sense.r, 055); /* drive B low */ + sense |= (in_le32(CNTRL_REG(p,mon_sense)) & 0xc0) >> 2; + out_le32(CNTRL_REG(p,mon_sense), 055); /* drive B low */ __delay(2000); - sense |= ((in_le32(&p->control_regs->mon_sense.r) & 0x100) >> 5) - | ((in_le32(&p->control_regs->mon_sense.r) & 0x40) >> 4); - out_le32(&p->control_regs->mon_sense.r, 066); /* drive C low */ + sense |= ((in_le32(CNTRL_REG(p,mon_sense)) & 0x100) >> 5) + | ((in_le32(CNTRL_REG(p,mon_sense)) & 0x40) >> 4); + out_le32(CNTRL_REG(p,mon_sense), 066); /* drive C low */ __delay(2000); - sense |= (in_le32(&p->control_regs->mon_sense.r) & 0x180) >> 7; + sense |= (in_le32(CNTRL_REG(p,mon_sense)) & 0x180) >> 7; - out_le32(&p->control_regs->mon_sense.r, 077); /* turn off drivers */ + out_le32(CNTRL_REG(p,mon_sense), 077); /* turn off drivers */ return sense; } -/*********************** Various translation functions ***********************/ -#if 1 -/* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */ -static int control_var_to_par(struct fb_var_screeninfo *var, - struct fb_par_control *par, const struct fb_info *fb_info) -{ - int xres = var->xres; - int yres = var->yres; - int bpp = var->bits_per_pixel; - struct fb_info_control *p = (struct fb_info_control *) fb_info; +/********************** Various translation functions **********************/ - /* - * Get the video params out of 'var'. If a value doesn't fit, round it up, - * if it's too big, return -EINVAL. - * - * Suggestion: Round up in the following order: bits_per_pixel, xres, - * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale, - * bitfields, horizontal timing, vertical timing. - */ - /* swiped by jonh from atyfb.c */ - if (xres <= 640 && yres <= 480) - par->vmode = VMODE_640_480_67; /* 640x480, 67Hz */ - else if (xres <= 640 && yres <= 870) - par->vmode = VMODE_640_870_75P; /* 640x870, 75Hz (portrait) */ - else if (xres <= 800 && yres <= 600) - par->vmode = VMODE_800_600_75; /* 800x600, 75Hz */ - else if (xres <= 832 && yres <= 624) - par->vmode = VMODE_832_624_75; /* 832x624, 75Hz */ - else if (xres <= 1024 && yres <= 768) - par->vmode = VMODE_1024_768_75; /* 1024x768, 75Hz */ - else if (xres <= 1152 && yres <= 870) - par->vmode = VMODE_1152_870_75; /* 1152x870, 75Hz */ - else if (xres <= 1280 && yres <= 960) - par->vmode = VMODE_1280_960_75; /* 1280x960, 75Hz */ - else if (xres <= 1280 && yres <= 1024) - par->vmode = VMODE_1280_1024_75; /* 1280x1024, 75Hz */ - else { - printk(KERN_ERR "Bad x/y res in var_to_par\n"); - return -EINVAL; - } +#define CONTROL_PIXCLOCK_BASE 256016 +#define CONTROL_PIXCLOCK_MIN 5000 /* ~ 200 MHz dot clock */ - xres = control_reg_init[par->vmode-1]->hres; - yres = control_reg_init[par->vmode-1]->vres; +/* + * calculate the clock paramaters to be sent to CUDA according to given + * pixclock in pico second. + */ +static int calc_clock_params(unsigned long clk, unsigned char *param) +{ + unsigned long p0, p1, p2, k, l, m, n, min; - par->xres = xres; - par->yres = yres; + if (clk > (CONTROL_PIXCLOCK_BASE << 3)) + return 1; - if (var->xres_virtual <= xres) - par->vxres = xres; - else if(var->xres_virtual > xres) { - par->vxres = xres; - } else /* NotReached at present */ - par->vxres = (var->xres_virtual+7) & ~7; + p2 = ((clk << 4) < CONTROL_PIXCLOCK_BASE)? 3: 2; + l = clk << p2; + p0 = 0; + p1 = 0; + for (k = 1, min = l; k < 32; k++) { + unsigned long rem; + + m = CONTROL_PIXCLOCK_BASE * k; + n = m / l; + rem = m % l; + if (n && (n < 128) && rem < min) { + p0 = k; + p1 = n; + min = rem; + } + } + if (!p0 || !p1) + return 1; - if (var->yres_virtual <= yres) - par->vyres = yres; - else - par->vyres = var->yres_virtual; + param[0] = p0; + param[1] = p1; + param[2] = p2; - if (var->xoffset > 0 || var->yoffset+yres > par->vyres) { - printk(KERN_ERR "Bad offsets in var_to_par\n"); - return -EINVAL; - } + return 0; +} - par->xoffset = (var->xoffset+7) & ~7; - par->yoffset = var->yoffset; +/* + * This routine takes a user-supplied var, and picks the best vmode/cmode + * from it. + */ - if (bpp <= 8) +static int control_var_to_par(struct fb_var_screeninfo *var, + struct fb_par_control *par, const struct fb_info *fb_info) +{ + int cmode, piped_diff, hstep; + unsigned hperiod, hssync, hsblank, hesync, heblank, piped, heq, hlfln, + hserr, vperiod, vssync, vesync, veblank, vsblank, vswin, vewin; + unsigned long pixclock; + struct fb_info_control *p = (struct fb_info_control *) fb_info; + struct control_regvals *r = &par->regvals; + + switch (var->bits_per_pixel) { + case 8: par->cmode = CMODE_8; - else if (bpp <= 16) + if (p->total_vram > 0x200000) { + r->mode = 3; + r->radacal_ctrl = 0x20; + piped_diff = 13; + } else { + r->mode = 2; + r->radacal_ctrl = 0x10; + piped_diff = 9; + } + break; + case 15: + case 16: par->cmode = CMODE_16; - else if (bpp <= 32) + if (p->total_vram > 0x200000) { + r->mode = 2; + r->radacal_ctrl = 0x24; + piped_diff = 5; + } else { + r->mode = 1; + r->radacal_ctrl = 0x14; + piped_diff = 3; + } + break; + case 32: par->cmode = CMODE_32; - else { - printk(KERN_ERR "Bad bpp in var_to_par\n"); + if (p->total_vram > 0x200000) { + r->mode = 1; + r->radacal_ctrl = 0x28; + } else { + r->mode = 0; + r->radacal_ctrl = 0x18; + } + piped_diff = 1; + break; + default: return -EINVAL; } - if (control_vram_reqd(par->vmode, par->cmode) > p->total_vram) { - printk(KERN_ERR "Too much VRAM required for vmode %d cmode %d.\n", par->vmode, par->cmode); - return -EINVAL; - } + /* + * adjust xres and vxres so that the corresponding memory widths are + * 32-byte aligned + */ + hstep = 31 >> par->cmode; + par->xres = (var->xres + hstep) & ~hstep; + par->vxres = (var->xres_virtual + hstep) & ~hstep; + par->xoffset = (var->xoffset + hstep) & ~hstep; + if (par->vxres < par->xres) + par->vxres = par->xres; + par->pitch = par->vxres << par->cmode; - /* Check if we know about the wanted video mode */ - if (control_reg_init[par->vmode - 1] == NULL) { - printk(KERN_ERR "init is null in control_var_to_par().\n"); - /* I'm not sure if control has any specific requirements -- */ - /* if we have a regvals struct, we're good to go? */ - return -EINVAL; - } + par->yres = var->yres; + par->vyres = var->yres_virtual; + par->yoffset = var->yoffset; + if (par->vyres < par->yres) + par->vyres = par->yres; - return 0; -} -#else -/* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */ -static int control_var_to_par(struct fb_var_screeninfo *var, - struct fb_par_control *par, const struct fb_info *fb_info) -{ - struct fb_info_control *p = (struct fb_info_control *) fb_info; - - if(mac_var_to_vmode(var, &par->vmode, &par->cmode) != 0) - return -EINVAL; - par->xres = par->vxres = vmode_attrs[par->vmode - 1].hres; - par->yres = par->vyres = vmode_attrs[par->vmode - 1].vres; - par->xoffset = par->yoffset = 0; - - if (control_vram_reqd(par->vmode, par->cmode) > p->total_vram) + par->sync = var->sync; + + if (par->pitch * par->vyres + CTRLFB_OFF > p->total_vram) return -EINVAL; - /* Check if we know about the wanted video mode */ - if(!control_reg_init[par->vmode-1]) { - /* I'm not sure if control has any specific requirements -- */ - /* if we have a regvals struct, we're good to go? */ + if (par->xoffset + par->xres > par->vxres) + par->xoffset = par->vxres - par->xres; + if (par->yoffset + par->yres > par->vyres) + par->yoffset = par->vyres - par->yres; + + pixclock = (var->pixclock < CONTROL_PIXCLOCK_MIN)? CONTROL_PIXCLOCK_MIN: + var->pixclock; + if (calc_clock_params(pixclock, r->clock_params)) return -EINVAL; - } + + hperiod = ((var->left_margin + par->xres + var->right_margin + + var->hsync_len) >> 1) - 2; + hssync = hperiod + 1; + hsblank = hssync - (var->right_margin >> 1); + hesync = (var->hsync_len >> 1) - 1; + heblank = (var->left_margin >> 1) + hesync; + piped = heblank - piped_diff; + heq = var->hsync_len >> 2; + hlfln = (hperiod+2) >> 1; + hserr = hssync-hesync; + vperiod = (var->vsync_len + var->lower_margin + par->yres + + var->upper_margin) << 1; + vssync = vperiod - 2; + vesync = (var->vsync_len << 1) - vperiod + vssync; + veblank = (var->upper_margin << 1) + vesync; + vsblank = vssync - (var->lower_margin << 1); + vswin = (vsblank+vssync) >> 1; + vewin = (vesync+veblank) >> 1; + + r->regs[0] = vswin; + r->regs[1] = vsblank; + r->regs[2] = veblank; + r->regs[3] = vewin; + r->regs[4] = vesync; + r->regs[5] = vssync; + r->regs[6] = vperiod; + r->regs[7] = piped; + r->regs[8] = hperiod; + r->regs[9] = hsblank; + r->regs[10] = heblank; + r->regs[11] = hesync; + r->regs[12] = hssync; + r->regs[13] = heq; + r->regs[14] = hlfln; + r->regs[15] = hserr; + + if (par->xres >= 1280 && par->cmode >= CMODE_16) + par->ctrl = 0x7f; + else + par->ctrl = 0x3b; + + if (mac_var_to_vmode(var, &par->vmode, &cmode)) + par->vmode = 0; + return 0; } -#endif -/*********** Convert hardware data in par to an fb_var_screeninfo ***********/ + +/* + * Convert hardware data in par to an fb_var_screeninfo + */ static void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var) { struct control_regints *rv; - rv = (struct control_regints *) control_reg_init[par->vmode - 1]->regs; + rv = (struct control_regints *) par->regvals.regs; memset(var, 0, sizeof(*var)); - var->xres = control_reg_init[par->vmode - 1]->hres; - var->yres = control_reg_init[par->vmode - 1]->vres; + var->xres = par->xres; + var->yres = par->yres; var->xres_virtual = par->vxres; var->yres_virtual = par->vyres; var->xoffset = par->xoffset; var->yoffset = par->yoffset; - var->grayscale = 0; - if(par->cmode != CMODE_8 && par->cmode != CMODE_16 && par->cmode != CMODE_32) { - printk(KERN_ERR "Bad color mode in control_par_to_var()!\n"); - par->cmode = CMODE_8; - } switch(par->cmode) { + default: case CMODE_8: var->bits_per_pixel = 8; - var->red.offset = 0; var->red.length = 8; - var->green.offset = 0; var->green.length = 8; - var->blue.offset = 0; var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; break; case CMODE_16: /* RGB 555 */ var->bits_per_pixel = 16; @@ -963,10 +1170,7 @@ var->red.length = 5; var->green.offset = 5; var->green.length = 5; - var->blue.offset = 0; var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; break; case CMODE_32: /* RGB 888 */ var->bits_per_pixel = 32; @@ -974,67 +1178,41 @@ var->red.length = 8; var->green.offset = 8; var->green.length = 8; - var->blue.offset = 0; var->blue.length = 8; var->transp.offset = 24; var->transp.length = 8; break; } - var->red.msb_right = 0; - var->green.msb_right = 0; - var->blue.msb_right = 0; - var->transp.msb_right = 0; - var->nonstd = 0; - var->activate = 0; var->height = -1; var->width = -1; var->vmode = FB_VMODE_NONINTERLACED; - var->left_margin = (rv->heblank - rv->hesync) - << ((par->vmode > 18) ? 2 : 1); - var->right_margin = (rv->hssync - rv->hsblank) - << ((par->vmode > 18) ? 2 : 1); - var->hsync_len = (rv->hperiod + 2 - rv->hssync + rv->hesync) - << ((par->vmode > 18) ? 2 : 1); + var->left_margin = (rv->heblank - rv->hesync) << 1; + var->right_margin = (rv->hssync - rv->hsblank) << 1; + var->hsync_len = (rv->hperiod + 2 - rv->hssync + rv->hesync) << 1; var->upper_margin = (rv->veblank - rv->vesync) >> 1; var->lower_margin = (rv->vssync - rv->vsblank) >> 1; var->vsync_len = (rv->vperiod - rv->vssync + rv->vesync) >> 1; - /* Acording to macmodes.c... */ - if((par->vmode >= 9 && par->vmode <= 12) || - (par->vmode >= 16 && par->vmode <= 18) || - (par->vmode == 20)) - { - var->sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT; - } else { - var->sync = 0; /* I suppose */ - } + var->sync = par->sync; - /* The reason these are both here: with my revised margin calculations, */ - /* these SHOULD both give the same answer for each mode. Some day I */ - /* will sit down and check the rest. Works perfectly for vmode 13. */ - -#if 0 -/* jonh's pixclocks...*/ - /* no long long support in the kernel :-( */ - /* this splittig trick will work if xres > 232 */ - var->pixclock = 1000000000/ - (var->left_margin+var->xres+var->right_margin+var->hsync_len); - var->pixclock *= 1000; - var->pixclock /= vmode_attrs[par->vmode-1].vfreq* - (var->upper_margin+var->yres+var->lower_margin+var->vsync_len); -#else -/* danj's */ - /* 10^12 * clock_params[0] / (3906400 * clock_params[1] * 2^clock_params[2]) */ - /* (10^12 * clock_params[0] / (3906400 * clock_params[1])) >> clock_params[2] */ + /* + * 10^12 * clock_params[0] / (3906400 * clock_params[1] + * * 2^clock_params[2]) + * (10^12 * clock_params[0] / (3906400 * clock_params[1])) + * >> clock_params[2] + */ /* (255990.17 * clock_params[0] / clock_params[1]) >> clock_params[2] */ - var->pixclock = 255990 * control_reg_init[par->vmode-1]->clock_params[0]; - var->pixclock /= control_reg_init[par->vmode-1]->clock_params[1]; - var->pixclock >>= control_reg_init[par->vmode-1]->clock_params[2]; -#endif + var->pixclock = CONTROL_PIXCLOCK_BASE * par->regvals.clock_params[0]; + var->pixclock /= par->regvals.clock_params[1]; + var->pixclock >>= par->regvals.clock_params[2]; } + +/* + * init fix according to given par + */ static void control_par_to_fix(struct fb_par_control *par, struct fb_fix_screeninfo *fix, struct fb_info_control *p) { @@ -1044,52 +1222,41 @@ fix->mmio_len = sizeof(struct control_regs); fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 32 >> par->cmode; fix->ypanstep = 1; - /* - fix->type_aux = 0; - fix->ywrapstep = 0; - fix->ypanstep = 0; - fix->xpanstep = 0; - */ - - fix->smem_start = (p->frame_buffer_phys - + control_reg_init[par->vmode-1]->offset[par->cmode]); - fix->smem_len = p->total_vram - control_reg_init[par->vmode-1]->offset[par->cmode]; + + fix->smem_start = p->frame_buffer_phys + CTRLFB_OFF; + fix->smem_len = p->total_vram - CTRLFB_OFF; fix->visual = (par->cmode == CMODE_8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; - fix->line_length = par->vxres << par->cmode; + fix->line_length = par->pitch; } -/* We never initialize any display except for p->disp. - And p->disp is already memset to 0. So no memset here. - [Found by Takashi Oe] -*/ +/* + * initialize a portion of struct display which low level driver is responsible + * for. + */ static void control_par_to_display(struct fb_par_control *par, struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_control *p) { - /* memset(disp, 0, sizeof(*disp)); */ disp->type = fix->type; disp->can_soft_blank = 1; disp->scrollmode = SCROLL_YNOMOVE | SCROLL_YNOPARTIAL; disp->ypanstep = fix->ypanstep; disp->ywrapstep = fix->ywrapstep; -#if 0 - disp->type_aux = fix->type_aux; - disp->cmap.red = NULL; /* ??? danj */ - disp->cmap.green = NULL; - disp->cmap.blue = NULL; - disp->cmap.transp = NULL; - /* Yeah, I realize I just set 0 = 0. */ -#endif control_par_to_var(par, &disp->var); - disp->screen_base = (char *) p->frame_buffer - + control_reg_init[par->vmode-1]->offset[par->cmode]; + disp->screen_base = (char *) p->frame_buffer + CTRLFB_OFF; disp->visual = fix->visual; disp->line_length = fix->line_length; control_set_dispsw(disp, par->cmode, p); } + +/* + * our own _revc() routines since generic routines don't work for DIRECT Color + * devices like control + */ static void control_cfb16_revc(struct display *p, int xx, int yy) { u8 *dest; @@ -1164,6 +1331,9 @@ }; +/* + * Set struct dispsw according to given cmode + */ static void control_set_dispsw(struct display *disp, int cmode, struct fb_info_control *p) { switch (cmode) { @@ -1190,6 +1360,10 @@ } } + +/* + * Set misc info vars for this driver + */ static void __init control_init_info(struct fb_info *info, struct fb_info_control *p) { strcpy(info->modename, "control"); @@ -1203,7 +1377,36 @@ info->blank = &controlfb_blank; } -/* Parse user speficied options (`video=controlfb:') */ + +static void control_cleanup(void) +{ + struct fb_info_control *p = control_fb; + + if (!p) + return; + + if (p->cmap_regs) + iounmap(p->cmap_regs); + if (p->control_regs) + iounmap(p->control_regs); + if (p->frame_buffer) { + if (p->control_use_bank2) + p->frame_buffer -= 0x600000; + iounmap(p->frame_buffer); + } + if (p->cmap_regs_phys) + release_mem_region(p->cmap_regs_phys, 0x1000); + if (p->control_regs_phys) + release_mem_region(p->control_regs_phys, p->control_regs_size); + if (p->fb_orig_base) + release_mem_region(p->fb_orig_base, p->fb_orig_size); + kfree(p); +} + + +/* + * Parse user speficied options (`video=controlfb:') + */ void __init control_setup(char *options) { char *this_opt; @@ -1223,11 +1426,11 @@ break; memcpy(fontname, this_opt + 5, i); fontname[i] = 0; - } - if (!strncmp(this_opt, "vmode:", 6)) { + } else if (!strncmp(this_opt, "vmode:", 6)) { int vmode = simple_strtoul(this_opt+6, NULL, 0); - if (vmode > 0 && vmode <= VMODE_MAX) - default_vmode = vmode; + if (vmode > 0 && vmode <= VMODE_MAX && + control_mac_modes[vmode - 1].m[1] >= 0) + default_vmode = vmode; } else if (!strncmp(this_opt, "cmode:", 6)) { int depth = simple_strtoul(this_opt+6, NULL, 0); switch (depth) { @@ -1252,20 +1455,3 @@ } } -#if 0 -static int controlfb_pan_display(struct fb_var_screeninfo *var, - struct controlfb_par *par, - const struct fb_info *fb_info) -{ - /* - * Pan (or wrap, depending on the `vmode' field) the display using the - * `xoffset' and `yoffset' fields of the `var' structure. - * If the values don't fit, return -EINVAL. - */ - - FUNCID; - - return 0; -} - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/controlfb.h linux.ac/drivers/video/controlfb.h --- linux.vanilla/drivers/video/controlfb.h Mon Dec 21 22:48:04 1998 +++ linux.ac/drivers/video/controlfb.h Tue Apr 3 17:55:09 2001 @@ -21,13 +21,13 @@ * Structure of the registers for the RADACAL colormap device. */ struct cmap_regs { - unsigned char addr; + unsigned char addr; /* index for both cmap and misc registers */ char pad1[15]; - unsigned char d1; + unsigned char crsr; /* cursor palette */ char pad2[15]; - unsigned char d2; + unsigned char dat; /* RADACAL misc register data */ char pad3[15]; - unsigned char lut; + unsigned char lut; /* cmap data */ char pad4[15]; }; @@ -51,26 +51,27 @@ struct preg vesync; /* vert end sync */ struct preg vssync; /* vert start sync */ struct preg vperiod; /* vert period */ - struct preg reg8; + struct preg piped; /* pipe delay hardware cursor */ /* Horizontal params are in units of 2 pixels */ struct preg hperiod; /* horiz period - 2 */ struct preg hsblank; /* horiz start blank */ struct preg heblank; /* horiz end blank */ struct preg hesync; /* horiz end sync */ struct preg hssync; /* horiz start sync */ - struct preg rege; - struct preg regf; - struct preg reg10; - struct preg reg11; + struct preg heq; /* half horiz sync len */ + struct preg hlfln; /* half horiz period */ + struct preg hserr; /* horiz period - horiz sync len */ + struct preg cnttst; struct preg ctrl; /* display control */ struct preg start_addr; /* start address: 5 lsbs zero */ struct preg pitch; /* addrs diff between scan lines */ struct preg mon_sense; /* monitor sense bits */ - struct preg flags; + struct preg vram_attr; /* enable vram banks */ struct preg mode; - struct preg reg18; - struct preg reg19; - struct preg res[6]; + struct preg rfrcnt; /* refresh count */ + struct preg intr_ena; /* interrupt enable */ + struct preg intr_stat; /* interrupt status */ + struct preg res[5]; }; struct control_regints { @@ -82,7 +83,7 @@ unsigned vesync; /* vert end sync */ unsigned vssync; /* vert start sync */ unsigned vperiod; /* vert period */ - unsigned reg8; + unsigned piped; /* pipe delay hardware cursor */ /* Horizontal params are in units of 2 pixels */ /* Except, apparently, for hres > 1024 (or == 1280?) */ unsigned hperiod; /* horiz period - 2 */ @@ -90,183 +91,55 @@ unsigned heblank; /* horiz end blank */ unsigned hesync; /* horiz end sync */ unsigned hssync; /* horiz start sync */ - unsigned rege; - unsigned regf; - unsigned reg10; + unsigned heq; /* half horiz sync len */ + unsigned hlfln; /* half horiz period */ + unsigned hserr; /* horiz period - horiz sync len */ }; /* - * Register initialization tables for the control display. - * * Dot clock rate is * 3.9064MHz * 2**clock_params[2] * clock_params[1] / clock_params[0]. - * - * The values for vertical frequency (V) in the comments below - * are the values measured using the modes under MacOS. - * - * Pitch is always the same as bytes per line (for these video modes at least). */ struct control_regvals { - int offset[3]; /* first pixel address */ - unsigned regs[16]; /* for vswin .. reg10 */ - unsigned char mode[3]; /* indexed by color_mode */ - unsigned char radacal_ctrl[3]; + unsigned regs[16]; /* for vswin .. hserr */ + unsigned char mode; + unsigned char radacal_ctrl; unsigned char clock_params[3]; - int hres; - int vres; }; -/* Register values for 1280x1024, 75Hz mode (20) */ -static struct control_regvals control_reg_init_20 = { - { 0x10, 0x20, 0 }, - { 2129, 2128, 80, 42, 4, 2130, 2132, 88, - 420, 411, 91, 35, 421, 18, 211, 386, }, - { 1, 1, 1}, - { 0x50, 0x64, 0x64 }, - { 13, 56, 3 }, /* pixel clock = 134.61MHz for V=74.81Hz */ - 1280, 1024 -}; - -/* Register values for 1280x960, 75Hz mode (19) */ -static struct control_regvals control_reg_init_19 = { - { 0x10, 0x20, 0 }, - { 1997, 1996, 76, 40, 4, 1998, 2000, 86, - 418, 409, 89, 35, 419, 18, 210, 384, }, - { 1, 1, 1 }, - { 0x50, 0x64, 0x64 }, - { 31, 125, 3 }, /* pixel clock = 126.01MHz for V=75.01 Hz */ - 1280, 960 -}; - -/* Register values for 1152x870, 75Hz mode (18) */ -static struct control_regvals control_reg_init_18 = { - { 0x10, 0x28, 0x50 }, - { 1825, 1822, 82, 43, 4, 1828, 1830, 120, - 726, 705, 129, 63, 727, 32, 364, 664 }, - { 2, 1, 1 }, - { 0x10, 0x14, 0x28 }, - { 19, 61, 3 }, /* pixel clock = 100.33MHz for V=75.31Hz */ - 1152, 870 -}; - -/* Register values for 1024x768, 75Hz mode (17) */ -static struct control_regvals control_reg_init_17 = { - { 0x10, 0x28, 0x50 }, - { 1603, 1600, 64, 34, 4, 1606, 1608, 120, - 662, 641, 129, 47, 663, 24, 332, 616 }, - { 2, 1, 1 }, - { 0x10, 0x14, 0x28 }, - { 11, 28, 3 }, /* pixel clock = 79.55MHz for V=74.50Hz */ - 1024, 768 -}; - -/* Register values for 1024x768, 72Hz mode 16 (15?) */ -static struct control_regvals control_reg_init_15 = { - { 0x10, 0x28, 0x50 }, - { 1607, 1604, 68, 39, 10, 1610, 1612, 132, - 670, 653, 141, 67, 671, 34, 336, 604, }, - { 2, 1, 1 }, - { 0x10, 0x14, 0x28 }, - { 12, 30, 3 }, /* pixel clock = 78.12MHz for V=72.12Hz */ - 1024, 768 -}; - -/* Register values for 1024x768, 60Hz mode (14) */ -static struct control_regvals control_reg_init_14 = { - { 0x10, 0x28, 0x50 }, - { 1607, 1604, 68, 39, 10, 1610, 1612, 132, - 670, 653, 141, 67, 671, 34, 336, 604, }, - { 2, 1, 1 }, - { 0x10, 0x14, 0x28 }, - { 15, 31, 3 }, /* pixel clock = 64.58MHz for V=59.62Hz */ - 1024, 768 -}; - -/* Register values for 832x624, 75Hz mode (13) */ -static struct control_regvals control_reg_init_13 = { - { 0x10, 0x28, 0x50 }, - { 1331, 1330, 82, 43, 4, 1332, 1334, 128, - 574, 553, 137, 31, 575, 16, 288, 544 }, - { 2, 1, 0 }, { 0x10, 0x14, 0x18 }, - { 23, 42, 3 }, /* pixel clock = 57.07MHz for V=74.27Hz */ - 832, 624 -}; - -/* Register values for 800x600, 75Hz mode (12) */ -static struct control_regvals control_reg_init_12 = { - { 0x10, 0x28, 0x50 }, - { 1247, 1246, 46, 25, 4, 1248, 1250, 104, - 526, 513, 113, 39, 527, 20, 264, 488, }, - { 2, 1, 0 }, { 0x10, 0x14, 0x18 }, - { 7, 11, 3 }, /* pixel clock = 49.11MHz for V=74.40Hz */ - 800, 600 -}; - -/* Register values for 800x600, 72Hz mode (11) */ -static struct control_regvals control_reg_init_11 = { - { 0x10, 0x28, 0x50 }, - { 1293, 1256, 56, 33, 10, 1330, 1332, 76, - 518, 485, 85, 59, 519, 30, 260, 460, }, - { 2, 1, 0 }, { 0x10, 0x14, 0x18 }, - { 17, 27, 3 }, /* pixel clock = 49.63MHz for V=71.66Hz */ - 800, 600 -}; - -/* Register values for 800x600, 60Hz mode (10) */ -static struct control_regvals control_reg_init_10 = { - { 0x10, 0x28, 0x50 }, - { 1293, 1256, 56, 33, 10, 1330, 1332, 76, - 518, 485, 85, 59, 519, 30, 260, 460, }, - { 2, 1, 0 }, { 0x10, 0x14, 0x18 }, - { 20, 53, 2 }, /* pixel clock = 41.41MHz for V=59.78Hz */ - 800, 600 -}; - -/* Register values for 640x870, 75Hz Full Page Display (7) */ -static struct control_regvals control_reg_init_7 = { - { 0x10, 0x30, 0x68 }, - { 0x727, 0x724, 0x58, 0x2e, 0x4, 0x72a, 0x72c, 0x40, - 0x19e, 0x18c, 0x4c, 0x27, 0x19f, 0x14, 0xd0, 0x178 }, - { 2, 1, 0 }, { 0x10, 0x14, 0x18 }, - { 9, 33, 2 }, /* pixel clock = 57.29MHz for V=75.01Hz */ - 640, 870 -}; - -/* Register values for 640x480, 67Hz mode (6) */ -static struct control_regvals control_reg_init_6 = { - { 0, 8, 0x10 }, - { 1045, 1042, 82, 43, 4, 1048, 1050, 72, - 430, 393, 73, 31, 431, 16, 216, 400 }, - { 2, 1, 0 }, { 0x10, 0x14, 0x18 }, - { 14, 27, 2 }, /* pixel clock = 30.13MHz for V=66.43Hz */ - 640, 480 -}; - -/* Register values for 640x480, 60Hz mode (5) */ -static struct control_regvals control_reg_init_5 = { - { 0x10, 0x28, 0x50 }, - { 1037, 1026, 66, 34, 2, 1048, 1050, 56, - 398, 385, 65, 47, 399, 24, 200, 352, }, - { 2, 1, 0 }, { 0x10, 0x14, 0x18 }, - { 23, 37, 2 }, /* pixel clock = 25.14MHz for V=59.85Hz */ - 640, 480 -}; - -static struct control_regvals *control_reg_init[VMODE_MAX] = { - NULL, NULL, NULL, NULL, - &control_reg_init_5, - &control_reg_init_6, - &control_reg_init_7, - NULL, NULL, - &control_reg_init_10, - &control_reg_init_11, - &control_reg_init_12, - &control_reg_init_13, - &control_reg_init_14, - &control_reg_init_15, - &control_reg_init_15, - &control_reg_init_17, - &control_reg_init_18, - &control_reg_init_19, - &control_reg_init_20 +#define CTRLFB_OFF 16 /* position of pixel 0 in frame buffer */ + + +/* + * Best cmode supported by control + */ +struct max_cmodes { + int m[2]; /* 0: 2MB vram, 1: 4MB vram */ }; + +/* + * Video modes supported by macmodes.c + */ +static struct max_cmodes control_mac_modes[] = { + {{-1,-1}}, /* 512x384, 60Hz interlaced (NTSC) */ + {{-1,-1}}, /* 512x384, 60Hz */ + {{-1,-1}}, /* 640x480, 50Hz interlaced (PAL) */ + {{-1,-1}}, /* 640x480, 60Hz interlaced (NTSC) */ + {{ 2, 2}}, /* 640x480, 60Hz (VGA) */ + {{ 2, 2}}, /* 640x480, 67Hz */ + {{-1,-1}}, /* 640x870, 75Hz (portrait) */ + {{-1,-1}}, /* 768x576, 50Hz (PAL full frame) */ + {{ 2, 2}}, /* 800x600, 56Hz */ + {{ 2, 2}}, /* 800x600, 60Hz */ + {{ 2, 2}}, /* 800x600, 72Hz */ + {{ 2, 2}}, /* 800x600, 75Hz */ + {{ 1, 2}}, /* 832x624, 75Hz */ + {{ 1, 2}}, /* 1024x768, 60Hz */ + {{ 1, 2}}, /* 1024x768, 70Hz (or 72Hz?) */ + {{ 1, 2}}, /* 1024x768, 75Hz (VESA) */ + {{ 1, 2}}, /* 1024x768, 75Hz */ + {{ 1, 2}}, /* 1152x870, 75Hz */ + {{ 0, 1}}, /* 1280x960, 75Hz */ + {{ 0, 1}}, /* 1280x1024, 75Hz */ +}; + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/cyber2000fb.c linux.ac/drivers/video/cyber2000fb.c --- linux.vanilla/drivers/video/cyber2000fb.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/cyber2000fb.c Mon Apr 9 23:32:17 2001 @@ -367,6 +367,7 @@ * Other */ u_char palette_ctrl; + u_int vmode; }; static const u_char crtc_idx[] = { @@ -427,6 +428,16 @@ cyber2000_attrw(0x13, 0x00); cyber2000_attrw(0x14, 0x00); + /* woody: set the interlaced bit... */ + /* FIXME: what about doublescan? */ + cyber2000_outb(0x11, 0x3ce); + i = cyber2000_inb(0x3cf); + if (hw->vmode == FB_VMODE_INTERLACED) + i |= 0x20; + else + i &= ~0x20; + cyber2000_outb(i, 0x3cf); + /* PLL registers */ cyber2000_grphw(DCLK_MULT, hw->clock_mult); cyber2000_grphw(DCLK_DIV, hw->clock_div); @@ -711,6 +722,7 @@ hw->width = var->xres_virtual; hw->palette_ctrl = 0x06; + hw->vmode = var->vmode; switch (var->bits_per_pixel) { #ifdef FBCON_HAS_CFB8 @@ -1570,7 +1582,7 @@ /* * Our driver data */ - dev->driver_data = cfb; + pci_set_drvdata(dev, cfb); if (int_cfb_info == NULL) int_cfb_info = cfb; @@ -1586,7 +1598,7 @@ static void __devexit cyberpro_remove(struct pci_dev *dev) { - struct cfb_info *cfb = (struct cfb_info *)dev->driver_data; + struct cfb_info *cfb = pci_get_drvdata(dev); if (cfb) { /* @@ -1606,7 +1618,7 @@ * Ensure that the driver data is no longer * valid. */ - dev->driver_data = NULL; + pci_set_drvdata(dev, NULL); if (cfb == int_cfb_info) int_cfb_info = NULL; } @@ -1621,7 +1633,7 @@ */ static void cyberpro_resume(struct pci_dev *dev) { - struct cfb_info *cfb = (struct cfb_info *)dev->driver_data; + struct cfb_info *cfb = pci_get_drvdata(dev); if (cfb) { cyberpro_init_hw(cfb, 0); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/fbcon-sti.c linux.ac/drivers/video/fbcon-sti.c --- linux.vanilla/drivers/video/fbcon-sti.c Tue Dec 5 20:29:39 2000 +++ linux.ac/drivers/video/fbcon-sti.c Tue Apr 3 17:55:09 2001 @@ -16,7 +16,7 @@ #include <linux/console.h> #include <linux/string.h> #include <linux/fb.h> -#include <asm/delay.h> +#include <linux/delay.h> #include <asm/types.h> #include <video/fbcon.h> @@ -323,8 +323,12 @@ */ struct display_switch fbcon_sti = { - fbcon_sti_setup, fbcon_sti_bmove, fbcon_sti_clear, - fbcon_sti_putc, fbcon_sti_putcs, fbcon_sti_revc, - NULL, NULL, fbcon_sti_clear_margins, - FONTWIDTH(8) + setup: fbcon_sti_setup, + bmove: fbcon_sti_bmove, + clear: fbcon_sti_clear, + putc: fbcon_sti_putc, + putcs: fbcon_sti_putcs, + revc: fbcon_sti_revc, + clear_margins: fbcon_sti_clear_margins, + fontwidthmask: FONTWIDTH(8) }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/fbcon.c linux.ac/drivers/video/fbcon.c --- linux.vanilla/drivers/video/fbcon.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/fbcon.c Tue Apr 3 17:55:09 2001 @@ -31,6 +31,8 @@ * * Random hacking by Martin Mares <mj@ucw.cz> * + * 2001 - Documented with DocBook + * - Brad Douglas <brad@neruo.com> * * The low level operations for the various display memory organizations are * now in separate source files. @@ -239,6 +241,20 @@ add_timer(&cursor_timer); } + +/** + * PROC_CONSOLE - find the attached tty or visible console + * @info: frame buffer info structure + * + * Finds the tty attached to the process or visible console if + * the process is not directly attached to a tty (e.g. remote + * user) for device @info. + * + * Returns -1 errno on error, or tty/visible console number + * on success. + * + */ + int PROC_CONSOLE(const struct fb_info *info) { int fgc; @@ -261,6 +277,21 @@ return MINOR(current->tty->device) - 1; } + +/** + * set_all_vcs - set all virtual consoles to match + * @fbidx: frame buffer index (e.g. fb0, fb1, ...) + * @fb: frame buffer ops structure + * @var: frame buffer screen structure to set + * @info: frame buffer info structure + * + * Set all virtual consoles to match screen info set in @var + * for device @info. + * + * Returns negative errno on error, or zero on success. + * + */ + int set_all_vcs(int fbidx, struct fb_ops *fb, struct fb_var_screeninfo *var, struct fb_info *info) { @@ -277,6 +308,17 @@ return 0; } + +/** + * set_con2fb_map - map console to frame buffer device + * @unit: virtual console number to map + * @newidx: frame buffer index to map virtual console to + * + * Maps a virtual console @unit to a frame buffer device + * @newidx. + * + */ + void set_con2fb_map(int unit, int newidx) { int oldidx = con2fb_map[unit]; @@ -1108,11 +1150,13 @@ } } scr_writew(c, d); + console_conditional_schedule(); s++; d++; } while (s < le); if (s > start) p->dispsw->putcs(conp, p, start, s - start, real_y(p, line), x); + console_conditional_schedule(); if (offset > 0) line++; else { @@ -1124,6 +1168,20 @@ } } +/** + * fbcon_redraw_clear - clear area of the screen + * @conp: stucture pointing to current active virtual console + * @p: display structure + * @sy: starting Y coordinate + * @sx: starting X coordinate + * @height: height of area to clear + * @width: width of area to clear + * + * Clears a specified area of the screen. All dimensions are in + * pixels. + * + */ + void fbcon_redraw_clear(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width) { @@ -1133,7 +1191,25 @@ fbcon_putc(conp, ' ', sy+y, sx+x); } -/* This cannot be used together with ypan or ywrap */ + +/** + * fbcon_redraw_bmove - copy area of screen to another area + * @p: display structure + * @sy: origin Y coordinate + * @sx: origin X coordinate + * @dy: destination Y coordinate + * @dx: destination X coordinate + * @h: height of area to copy + * @w: width of area to copy + * + * Copies an area of the screen to another area of the same screen. + * All dimensions are in pixels. + * + * Note that this function cannot be used together with ypan or + * ywrap. + * + */ + void fbcon_redraw_bmove(struct display *p, int sy, int sx, int dy, int dx, int h, int w) { if (sy != dy) @@ -2060,44 +2136,32 @@ if (!fb) return 0; - /* Set colors if visual is PSEUDOCOLOR and we have enough colors, or for - * DIRECTCOLOR */ - if ((p->visual == FB_VISUAL_PSEUDOCOLOR && depth >= 4) || - p->visual == FB_VISUAL_DIRECTCOLOR) { - int is_truecolor = (p->visual == FB_VISUAL_DIRECTCOLOR); - int use_256 = (!is_truecolor && depth >= 8) || - (is_truecolor && depth >= 24); - int first_col = use_256 ? 32 : depth > 4 ? 16 : 0; - int num_cols = use_256 ? LINUX_LOGO_COLORS : 16; - unsigned char *red, *green, *blue; - - if (use_256) { - red = linux_logo_red; - green = linux_logo_green; - blue = linux_logo_blue; - } - else { - red = linux_logo16_red; - green = linux_logo16_green; - blue = linux_logo16_blue; - } - - for( i = 0; i < num_cols; i += n ) { - n = num_cols - i; + /* + * Set colors if visual is PSEUDOCOLOR and we have enough colors, or for + * DIRECTCOLOR + * We don't have to set the colors for the 16-color logo, since that logo + * uses the standard VGA text console palette + */ + if ((p->visual == FB_VISUAL_PSEUDOCOLOR && depth >= 8) || + (p->visual == FB_VISUAL_DIRECTCOLOR && depth >= 24)) + for (i = 0; i < LINUX_LOGO_COLORS; i += n) { + n = LINUX_LOGO_COLORS - i; if (n > 16) /* palette_cmap provides space for only 16 colors at once */ n = 16; - palette_cmap.start = first_col + i; + palette_cmap.start = 32 + i; palette_cmap.len = n; for( j = 0; j < n; ++j ) { - palette_cmap.red[j] = (red[i+j] << 8) | red[i+j]; - palette_cmap.green[j] = (green[i+j] << 8) | green[i+j]; - palette_cmap.blue[j] = (blue[i+j] << 8) | blue[i+j]; + palette_cmap.red[j] = (linux_logo_red[i+j] << 8) | + linux_logo_red[i+j]; + palette_cmap.green[j] = (linux_logo_green[i+j] << 8) | + linux_logo_green[i+j]; + palette_cmap.blue[j] = (linux_logo_blue[i+j] << 8) | + linux_logo_blue[i+j]; } p->fb_info->fbops->fb_set_cmap(&palette_cmap, 1, fg_console, p->fb_info); } - } if (depth >= 8) { logo = linux_logo; @@ -2155,15 +2219,15 @@ } } } - else if (depth >= 15 && depth <= 23) { - /* have 5..7 bits per color, using 16 color image */ + else if (depth >= 12 && depth <= 23) { + /* have 4..7 bits per color, using 16 color image */ unsigned int pix; src = linux_logo16; bdepth = (depth+7)/8; for( y1 = 0; y1 < LOGO_H; y1++ ) { dst = fb + y1*line + x*bdepth; for( x1 = 0; x1 < LOGO_W/2; x1++, src++ ) { - pix = (*src >> 4) | 0x10; /* upper nibble */ + pix = *src >> 4; /* upper nibble */ val = (pix << redshift) | (pix << greenshift) | (pix << blueshift); @@ -2173,7 +2237,7 @@ for( i = bdepth-1; i >= 0; --i ) #endif fb_writeb (val >> (i*8), dst++); - pix = (*src & 0x0f) | 0x10; /* lower nibble */ + pix = *src & 0x0f; /* lower nibble */ val = (pix << redshift) | (pix << greenshift) | (pix << blueshift); @@ -2297,16 +2361,13 @@ } } - /* fill remaining planes - * special case for logo_depth == 4: we used color registers 16..31, - * so fill plane 4 with 1 bits instead of 0 */ + /* fill remaining planes */ if (depth > logo_depth) { for( y1 = 0; y1 < LOGO_H; y1++ ) { for( x1 = 0; x1 < LOGO_LINE; x1++ ) { dst = fb + y1*line + MAP_X(x/8+x1) + logo_depth*plane; for( i = logo_depth; i < depth; i++, dst += plane ) - *dst = (i == logo_depth && logo_depth == 4) - ? 0xff : 0x00; + *dst = 0x00; } } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/fbmem.c linux.ac/drivers/video/fbmem.c --- linux.vanilla/drivers/video/fbmem.c Tue Apr 3 17:32:24 2001 +++ linux.ac/drivers/video/fbmem.c Sat Apr 14 01:36:53 2001 @@ -120,6 +120,12 @@ extern int stifb_setup(char*); extern int radeonfb_init(void); extern int radeonfb_setup(char*); +extern int pmagbafb_init(void); +extern int pmagbafb_setup(char *); +extern int pmagbbfb_init(void); +extern int pmagbbfb_setup(char *options, int *ints); +extern void maxinefb_init(void); +extern void maxinefb_setup(char *options, int *ints); static struct { const char *name; @@ -172,9 +178,6 @@ #ifdef CONFIG_FB_RIVA { "riva", rivafb_init, rivafb_setup }, #endif -#ifdef CONFIG_FB_RADEON - { "radeon", radeonfb_init, radeonfb_setup }, -#endif #ifdef CONFIG_FB_CONTROL { "controlfb", control_init, control_setup }, #endif @@ -196,7 +199,7 @@ #ifdef CONFIG_FB_FM2 { "fm2fb", fm2fb_init, fm2fb_setup }, #endif -#ifdef CONFIG_FB_SIS +#if defined(CONFIG_FB_SIS) && (defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)) { "sisfb", sisfb_init, sisfb_setup }, #endif @@ -264,6 +267,18 @@ #ifdef CONFIG_FB_HIT { "hitfb", hitfb_init, NULL }, #endif +#ifdef CONFIG_FB_RADEON + { "radeon", radeonfb_init, radeonfb_setup }, +#endif +#ifdef CONFIG_FB_PMAG_BA + { "pmagbafb", pmagbafb_init, pmagbafb_setup }, +#endif +#ifdef CONFIG_FB_PMAGB_B + { "pmagbbfb", pmagbbfb_init, pmagbbfb_setup }, +#endif +#ifdef CONFIG_FB_MAXINE + { "maxinefb", maxinefb_init, maxinefb_setup }, +#endif /* * Generic drivers that don't use resource management (yet) @@ -281,6 +296,8 @@ { "resolver", NULL, resolver_video_setup }, #endif + + #ifdef CONFIG_FB_VIRTUAL /* * Vfb must be last to avoid that it becomes your primary display if @@ -550,7 +567,10 @@ off -= len; fb->fb_get_var(&var, PROC_CONSOLE(info), info); if (var.accel_flags) + { + unlock_kernel(); return -EINVAL; + } start = fix.mmio_start; len = PAGE_ALIGN((start & ~PAGE_MASK)+fix.mmio_len); } @@ -562,22 +582,6 @@ vma->vm_pgoff = off >> PAGE_SHIFT; #if defined(__sparc_v9__) vma->vm_flags |= (VM_SHM | VM_LOCKED); - { - unsigned long align, j; - for (align = 0x400000; align > PAGE_SIZE; align >>= 3) - if (len >= align && !((start & ~PAGE_MASK) & (align - 1))) - break; - if (align > PAGE_SIZE && vma->vm_start & (align - 1)) { - /* align as much as possible */ - struct vm_area_struct *vmm; - j = (-vma->vm_start) & (align - 1); - vmm = find_vma(current->mm, vma->vm_start); - if (!vmm || vmm->vm_start >= vma->vm_end + j) { - vma->vm_start += j; - vma->vm_end += j; - } - } - } if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot, 0)) return -EAGAIN; @@ -687,6 +691,9 @@ mmap: fb_mmap, open: fb_open, release: fb_release, +#ifdef HAVE_ARCH_FB_UNMAPPED_AREA + get_unmapped_area: get_fb_unmapped_area, +#endif }; static devfs_handle_t devfs_handle; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/hitfb.c linux.ac/drivers/video/hitfb.c --- linux.vanilla/drivers/video/hitfb.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/hitfb.c Sat Apr 14 01:36:59 2001 @@ -22,9 +22,11 @@ #include <linux/nubus.h> #include <linux/init.h> +#include <asm/machvec.h> #include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/io.h> +#include <asm/hd64461.h> #include <linux/fb.h> @@ -32,20 +34,6 @@ #include <video/fbcon-cfb8.h> #include <video/fbcon-cfb16.h> -#include <asm/hd64461.h> - -#define CONFIG_SH_LCD_VIDEOBASE CONFIG_HD64461_IOBASE+0x2000000 - -/* These are for HP Jornada 680/690. - It is desired that they are configurable... */ -#define CONFIG_SH_LCD_VIDEOSIZE 1024*1024 -#define CONFIG_SH_LCD_HORZ 640 -#define CONFIG_SH_LCD_VERT 240 -#define CONFIG_SH_LCD_DEFAULTBPP 16 - -struct hitfb_info { - struct fb_info_gen gen; -}; struct hitfb_par { @@ -53,55 +41,79 @@ int bpp; }; -static struct hitfb_info fb_info; -static struct hitfb_par current_par; -static int current_par_valid = 0; -static struct display disp; -static union { +struct hitfb_info { + struct fb_info_gen gen; + struct display disp; + struct hitfb_par current_par; + struct fb_var_screeninfo default_var; + int current_par_valid; + unsigned long hit_videobase, hit_videosize; + union { #ifdef FBCON_HAS_CFB16 - u16 cfb16[16]; + u16 cfb16[16]; #endif -} fbcon_cmap; - -unsigned long hit_videobase, hit_videosize; -static struct fb_var_screeninfo default_var; + } fbcon_cmap; +} fb_info = { + {}, + {}, + {}, + {}, + 0, 0, 0, + {}, +}; -int hitfb_init(void); -static void hitfb_set_par(struct hitfb_par *par, const struct fb_info *info); -static void hitfb_encode_var(struct fb_var_screeninfo *var, - struct hitfb_par *par, - const struct fb_info *info); +static void hitfb_set_par(const void *fb_par, struct fb_info_gen *info); +static int hitfb_encode_var(struct fb_var_screeninfo *var, const void *fb_par, + struct fb_info_gen *info); static void hitfb_detect(void) { struct hitfb_par par; + unsigned short lcdclor, ldr3, ldvntr; + + fb_info.hit_videobase = CONFIG_HD64461_IOBASE + 0x02000000; + fb_info.hit_videosize = (MACH_HP680 || MACH_HP690) ? 1024*1024 : 512*1024; - hit_videobase = CONFIG_SH_LCD_VIDEOBASE; - hit_videosize = CONFIG_SH_LCD_VIDEOSIZE; + lcdclor = inw(HD64461_LCDCLOR); + ldvntr = inw(HD64461_LDVNTR); + ldr3 = inw(HD64461_LDR3); + + switch(ldr3&15) { + default: + case 4: + par.bpp = 8; + par.x = lcdclor; + break; + case 8: + par.bpp = 16; + par.x = lcdclor/2; + break; + } - par.x = CONFIG_SH_LCD_HORZ; - par.y = CONFIG_SH_LCD_VERT; - par.bpp = CONFIG_SH_LCD_DEFAULTBPP; + par.y = ldvntr+1; hitfb_set_par(&par, NULL); - hitfb_encode_var(&default_var, &par, NULL); + hitfb_encode_var(&fb_info.default_var, &par, NULL); } -static int hitfb_encode_fix(struct fb_fix_screeninfo *fix, - struct hitfb_par *par, - const struct fb_info *info) + +static int hitfb_encode_fix(struct fb_fix_screeninfo *fix, const void *fb_par, + struct fb_info_gen *info) { + const struct hitfb_par *par = fb_par; + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, "Hitachi HD64461"); - fix->smem_start = hit_videobase; - fix->smem_len = hit_videosize; + fix->smem_start = fb_info.hit_videobase; + fix->smem_len = fb_info.hit_videosize; fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; - fix->visual = FB_VISUAL_TRUECOLOR; + fix->visual = (par->bpp == 8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; fix->xpanstep = 0; fix->ypanstep = 0; fix->ywrapstep = 0; @@ -120,10 +132,11 @@ } -static int hitfb_decode_var(struct fb_var_screeninfo *var, - struct hitfb_par *par, - const struct fb_info *info) +static int hitfb_decode_var(const struct fb_var_screeninfo *var, void *fb_par, + struct fb_info_gen *info) { + struct hitfb_par *par = fb_par; + par->x = var->xres; par->y = var->yres; par->bpp = var->bits_per_pixel; @@ -131,10 +144,11 @@ } -static void hitfb_encode_var(struct fb_var_screeninfo *var, - struct hitfb_par *par, - const struct fb_info *info) +static int hitfb_encode_var(struct fb_var_screeninfo *var, const void *fb_par, + struct fb_info_gen *info) { + const struct hitfb_par *par = fb_par; + memset(var, 0, sizeof(*var)); var->xres = par->x; @@ -191,25 +205,28 @@ var->green.msb_right = 0; var->blue.msb_right = 0; var->transp.msb_right = 0; + + return 0; } -static void hitfb_get_par(struct hitfb_par *par, const struct fb_info *info) +static void hitfb_get_par(void *par, struct fb_info_gen *info) { - *par = current_par; + *(struct hitfb_par *)par = fb_info.current_par; } -static void hitfb_set_par(struct hitfb_par *par, const struct fb_info *info) +static void hitfb_set_par(const void *fb_par, struct fb_info_gen *info) { - /* Set the hardware according to 'par'. */ - current_par = *par; - current_par_valid = 1; + const struct hitfb_par *par = fb_par; + fb_info.current_par = *par; + fb_info.current_par_valid = 1; } -static int hitfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, - u_int *transp, struct fb_info *info) +static int hitfb_getcolreg(unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, + struct fb_info *info) { if (regno > 255) return 1; @@ -224,8 +241,9 @@ } -static int hitfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) +static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) { if (regno > 255) return 1; @@ -236,10 +254,10 @@ outw(blue>>10, HD64461_CPTWDR); if(regno<16) { - switch(current_par.bpp) { + switch(fb_info.current_par.bpp) { #ifdef FBCON_HAS_CFB16 case 16: - fbcon_cmap.cfb16[regno] = + fb_info.fbcon_cmap.cfb16[regno] = ((red & 0xf800) ) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); @@ -251,16 +269,34 @@ return 0; } -static int hitfb_blank(int blank_mode, const struct fb_info *info) + +static int hitfb_pan_display(const struct fb_var_screeninfo *var, + struct fb_info_gen *info) { + if (!fb_info.current_par_valid) + return -EINVAL; + return 0; } -static void hitfb_set_disp(const void *par, struct display *disp, - struct fb_info_gen *info) +static int hitfb_blank(int blank_mode, struct fb_info_gen *info) { - disp->screen_base = (void *)hit_videobase; + if (!fb_info.current_par_valid) + return 1; + + return 0; +} + + +static void hitfb_set_disp(const void *fb_par, struct display *disp, + struct fb_info_gen *info) +{ + const struct hitfb_par *par = fb_par; + + disp->screen_base = (void *)fb_info.hit_videobase; + disp->scrollmode = SCROLL_YREDRAW; + switch(((struct hitfb_par *)par)->bpp) { #ifdef FBCON_HAS_CFB8 case 8: @@ -270,7 +306,7 @@ #ifdef FBCON_HAS_CFB16 case 16: disp->dispsw = &fbcon_cfb16; - disp->dispsw_data = fbcon_cmap.cfb16; + disp->dispsw_data = fb_info.fbcon_cmap.cfb16; break; #endif default: @@ -288,18 +324,20 @@ hitfb_set_par, hitfb_getcolreg, hitfb_setcolreg, - NULL, + hitfb_pan_display, hitfb_blank, hitfb_set_disp }; + static struct fb_ops hitfb_ops = { - owner: THIS_MODULE, - fb_get_fix: fbgen_get_fix, - fb_get_var: fbgen_get_var, - fb_set_var: fbgen_set_var, - fb_get_cmap: fbgen_get_cmap, - fb_set_cmap: fbgen_set_cmap, + owner: THIS_MODULE, + fb_get_fix: fbgen_get_fix, + fb_get_var: fbgen_get_var, + fb_set_var: fbgen_set_var, + fb_get_cmap: fbgen_get_cmap, + fb_set_cmap: fbgen_set_cmap, + fb_pan_display: fbgen_pan_display, }; @@ -309,7 +347,7 @@ fb_info.gen.info.node = -1; fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT; fb_info.gen.info.fbops = &hitfb_ops; - fb_info.gen.info.disp = &disp; + fb_info.gen.info.disp = &fb_info.disp; fb_info.gen.info.changevar = NULL; fb_info.gen.info.switch_con = &fbgen_switch; fb_info.gen.info.updatevar = &fbgen_update_var; @@ -318,9 +356,9 @@ fb_info.gen.fbhw = &hitfb_switch; fb_info.gen.fbhw->detect(); - fbgen_get_var(&disp.var, -1, &fb_info.gen.info); - disp.var.activate = FB_ACTIVATE_NOW; - fbgen_do_set_var(&disp.var, 1, &fb_info.gen); + fbgen_get_var(&fb_info.disp.var, -1, &fb_info.gen.info); + fb_info.disp.var.activate = FB_ACTIVATE_NOW; + fbgen_do_set_var(&fb_info.disp.var, 1, &fb_info.gen); fbgen_set_disp(-1, &fb_info.gen); fbgen_install_cmap(0, &fb_info.gen); @@ -347,6 +385,13 @@ void cleanup_module(void) { - hitfb_cleanup(void); + hitfb_cleanup(void); } #endif + + +/* + * Local variables: + * c-basic-offset: 4 + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/imsttfb.c linux.ac/drivers/video/imsttfb.c --- linux.vanilla/drivers/video/imsttfb.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/imsttfb.c Tue Apr 3 17:55:09 2001 @@ -178,10 +178,10 @@ /* TI TVP 3030 RAMDAC Direct Registers */ enum { - TVPADDRW = 0x00, /* 0 Palette/Cursor RAM Write Adress/Index */ + TVPADDRW = 0x00, /* 0 Palette/Cursor RAM Write Address/Index */ TVPPDATA = 0x04, /* 1 Palette Data RAM Data */ TVPPMASK = 0x08, /* 2 Pixel Read-Mask */ - TVPPADRR = 0x0c, /* 3 Palette/Cursor RAM Read Adress */ + TVPPADRR = 0x0c, /* 3 Palette/Cursor RAM Read Address */ TVPCADRW = 0x10, /* 4 Cursor/Overscan Color Write Address */ TVPCDATA = 0x14, /* 5 Cursor/Overscan Color Data */ /* 6 reserved */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/macmodes.c linux.ac/drivers/video/macmodes.c --- linux.vanilla/drivers/video/macmodes.c Tue Apr 3 17:32:24 2001 +++ linux.ac/drivers/video/macmodes.c Tue Apr 3 17:55:09 2001 @@ -94,7 +94,15 @@ /* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */ "mac20", 75, 1280, 1024, 7408, 232, 64, 38, 1, 112, 3, FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, + }, { + /* 1152x768, 60 Hz, Titanium PowerBook */ + "mac21", 60, 1152, 768, 15386, 158, 26, 29, 3, 136, 6, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1600x1024, 60 Hz, Non-Interlaced (112.27 MHz dotclock) */ + "mac22", 60, 1600, 1024, 8908, 88, 104, 1, 10, 16, 1, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + } #if 0 /* Anyone who has timings for these? */ @@ -154,12 +162,16 @@ { VMODE_1024_768_75V, &mac_modedb[9] }, { VMODE_1024_768_70, &mac_modedb[8] }, { VMODE_1024_768_60, &mac_modedb[7] }, + /* 1152x768 */ + { VMODE_1152_768_60, &mac_modedb[14] }, /* 1152x870 */ { VMODE_1152_870_75, &mac_modedb[11] }, /* 1280x960 */ { VMODE_1280_960_75, &mac_modedb[12] }, /* 1280x1024 */ { VMODE_1280_1024_75, &mac_modedb[13] }, + /* 1600x1024 */ + { VMODE_1600_1024_60, &mac_modedb[15] }, { -1, NULL } }; @@ -191,6 +203,7 @@ { 0x730, VMODE_768_576_50I }, /* PAL (Alternate) */ { 0x73a, VMODE_1152_870_75 }, /* 3rd party 19" */ { 0x73f, VMODE_640_480_67 }, /* no sense lines connected at all */ + { 0xBEEF, VMODE_1600_1024_60 }, /* 22" Apple Cinema Display */ { -1, VMODE_640_480_60 }, /* catch-all, must be last */ }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/matrox/matroxfb_DAC1064.c linux.ac/drivers/video/matrox/matroxfb_DAC1064.c --- linux.vanilla/drivers/video/matrox/matroxfb_DAC1064.c Sun Feb 4 18:05:30 2001 +++ linux.ac/drivers/video/matrox/matroxfb_DAC1064.c Thu Apr 12 12:04:37 2001 @@ -33,12 +33,14 @@ #define DAC1064_OPT_RESERVED 0x10 static void matroxfb_DAC1064_flashcursor(unsigned long ptr) { + unsigned long flags; + #define minfo ((struct matrox_fb_info*)ptr) - matroxfb_DAC_lock(); + matroxfb_DAC_lock_irqsave(flags); outDAC1064(PMINFO M1064_XCURCTRL, inDAC1064(PMINFO M1064_XCURCTRL) ^ M1064_XCURCTRL_DIS ^ M1064_XCURCTRL_XGA); ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2; add_timer(&ACCESS_FBINFO(cursor.timer)); - matroxfb_DAC_unlock(); + matroxfb_DAC_unlock_irqrestore(flags); #undef minfo } @@ -416,7 +418,12 @@ outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]); outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]); outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5]); - if (!oldhw || memcmp(hw->DACreg, oldhw->DACreg, sizeof(MGA1064_DAC_regs))) { + /* + * We must ALWAYS reprogram hardware due to broken XF4 matrox drivers... + * + * if (!oldhw || memcmp(hw->DACreg, oldhw->DACreg, sizeof(MGA1064_DAC_regs))) + */ + { unsigned int i; for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/matrox/matroxfb_Ti3026.c linux.ac/drivers/video/matrox/matroxfb_Ti3026.c --- linux.vanilla/drivers/video/matrox/matroxfb_Ti3026.c Thu Aug 10 20:34:31 2000 +++ linux.ac/drivers/video/matrox/matroxfb_Ti3026.c Tue Apr 3 17:55:09 2001 @@ -279,12 +279,14 @@ 0x00, 0x00, TVP3026_XCURCTRL_DIS }; static void matroxfb_ti3026_flashcursor(unsigned long ptr) { + unsigned long flags; + #define minfo ((struct matrox_fb_info*)ptr) - matroxfb_DAC_lock(); + matroxfb_DAC_lock_irqsave(flags); outTi3026(PMINFO TVP3026_XCURCTRL, inTi3026(PMINFO TVP3026_XCURCTRL) ^ TVP3026_XCURCTRL_DIS ^ TVP3026_XCURCTRL_XGA); ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2; add_timer(&ACCESS_FBINFO(cursor.timer)); - matroxfb_DAC_unlock(); + matroxfb_DAC_unlock_irqrestore(flags); #undef minfo } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/matrox/matroxfb_g450.c linux.ac/drivers/video/matrox/matroxfb_g450.c --- linux.vanilla/drivers/video/matrox/matroxfb_g450.c Fri Dec 29 22:07:23 2000 +++ linux.ac/drivers/video/matrox/matroxfb_g450.c Tue Apr 3 17:55:09 2001 @@ -6,17 +6,20 @@ static int matroxfb_g450_get_reg(WPMINFO int reg) { int val; + unsigned long flags; - matroxfb_DAC_lock(); + matroxfb_DAC_lock_irqsave(flags); val = matroxfb_DAC_in(PMINFO reg); - matroxfb_DAC_unlock(); + matroxfb_DAC_unlock_irqrestore(flags); return val; } static int matroxfb_g450_set_reg(WPMINFO int reg, int val) { - matroxfb_DAC_lock(); + unsigned long flags; + + matroxfb_DAC_lock_irqsave(flags); matroxfb_DAC_out(PMINFO reg, val); - matroxfb_DAC_unlock(); + matroxfb_DAC_unlock_irqrestore(flags); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/maxinefb.c linux.ac/drivers/video/maxinefb.c --- linux.vanilla/drivers/video/maxinefb.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/maxinefb.c Tue Apr 3 17:55:09 2001 @@ -0,0 +1,425 @@ +/* + * linux/drivers/video/maxinefb.c + * + * DECstation 5000/xx onboard framebuffer support ... derived from: + * "HP300 Topcat framebuffer support (derived from macfb of all things) + * Phil Blundell <philb@gnu.org> 1998", the original code can be + * found in the file hpfb.c in the same directory. + * + * DECstation related code Copyright (C) 1999,2000,2001 by + * Michael Engel <engel@unix-ag.org> and + * Karsten Merker <merker@linuxtag.org>. + * 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. + * + */ + +/* + * Changes: + * 2001/01/27 removed debugging and testing code, fixed fb_ops + * initialization which had caused a crash before, + * general cleanup, first official release (KM) + * + */ + + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/malloc.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/fb.h> +#include <video/fbcon.h> +#include "maxinefb.h" + +/* bootinfo.h defines the machine type values, needed when checking */ +/* whether are really running on a maxine, KM */ +#include <asm/bootinfo.h> + +#include <video/fbcon-mfb.h> +#include <video/fbcon-cfb2.h> +#include <video/fbcon-cfb4.h> +#include <video/fbcon-cfb8.h> + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +static struct display disp; +static struct fb_info fb_info; + +unsigned long fb_start, fb_size = 1024 * 768, fb_line_length = 1024; +unsigned long fb_regs; +unsigned char fb_bitmask; + +static struct fb_var_screeninfo maxinefb_defined = { + 0, 0, 0, 0, /* W,H, W, H (virtual) load xres,xres_virtual */ + 0, 0, /* virtual -> visible no offset */ + 0, /* depth -> load bits_per_pixel */ + 0, /* greyscale ? */ + {0, 0, 0}, /* R */ + {0, 0, 0}, /* G */ + {0, 0, 0}, /* B */ + {0, 0, 0}, /* transparency */ + 0, /* standard pixel format */ + FB_ACTIVATE_NOW, + 274, 195, /* 14" monitor */ + FB_ACCEL_NONE, + 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0, /* No sync info */ + FB_VMODE_NONINTERLACED, + {0, 0, 0, 0, 0, 0} +}; + +struct maxinefb_par { +}; + +static int currcon = 0; +struct maxinefb_par current_par; + +/* Reference to machine type set in arch/mips/dec/prom/identify.c, KM */ +extern unsigned long mips_machtype; + + +/* Handle the funny Inmos RamDAC/video controller ... */ + +void maxinefb_ims332_write_register(int regno, register unsigned int val) +{ + register unsigned char *regs = (char *) MAXINEFB_IMS332_ADDRESS; + unsigned char *wptr; + + wptr = regs + 0xa0000 + (regno << 4); + *((volatile unsigned int *) (regs)) = (val >> 8) & 0xff00; + *((volatile unsigned short *) (wptr)) = val; +} + +unsigned int maxinefb_ims332_read_register(int regno) +{ + register unsigned char *regs = (char *) MAXINEFB_IMS332_ADDRESS; + unsigned char *rptr; + register unsigned int j, k; + + rptr = regs + 0x80000 + (regno << 4); + j = *((volatile unsigned short *) rptr); + k = *((volatile unsigned short *) regs); + + return (j & 0xffff) | ((k & 0xff00) << 8); +} + + +static void maxinefb_encode_var(struct fb_var_screeninfo *var, + struct maxinefb_par *par) +{ + int i = 0; + var->xres = 1024; + var->yres = 768; + var->xres_virtual = 1024; + var->yres_virtual = 768; + var->xoffset = 0; + var->yoffset = 0; + var->bits_per_pixel = 8; + var->grayscale = 0; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + var->nonstd = 0; + var->activate = 1; + var->height = -1; + var->width = -1; + var->vmode = FB_VMODE_NONINTERLACED; + var->pixclock = 0; + var->sync = 0; + var->left_margin = 0; + var->right_margin = 0; + var->upper_margin = 0; + var->lower_margin = 0; + var->hsync_len = 0; + var->vsync_len = 0; + for (i = 0; i < arraysize(var->reserved); i++) + var->reserved[i] = 0; +} + +static void maxinefb_get_par(struct maxinefb_par *par) +{ + *par = current_par; +} + +static int maxinefb_fb_update_var(int con, struct fb_info *info) +{ + return 0; +} + +static int maxinefb_do_fb_set_var(struct fb_var_screeninfo *var, + int isactive) +{ + struct maxinefb_par par; + + maxinefb_get_par(&par); + maxinefb_encode_var(var, &par); + return 0; +} + + +/* Get the palette */ + +static int maxinefb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + unsigned int i; + unsigned long hw_colorvalue = 0; /* raw color value from the register */ + unsigned int length; + + if (((cmap->start) + (cmap->len)) >= 256) { + length = 256 - (cmap->start); + } else { + length = cmap->len; + } + for (i = 0; i < length; i++) { + hw_colorvalue = + maxinefb_ims332_read_register(IMS332_REG_COLOR_PALETTE + + cmap->start + i); + (cmap->red[i]) = ((hw_colorvalue & 0x0000ff)); + (cmap->green[i]) = ((hw_colorvalue & 0x00ff00) >> 8); + (cmap->blue[i]) = ((hw_colorvalue & 0xff0000) >> 16); + + } + return 0; +} + + +/* Set the palette */ + +static int maxinefb_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + unsigned int i; + unsigned long hw_colorvalue; /* value to be written into the palette reg. */ + unsigned short cmap_red; + unsigned short cmap_green; + unsigned short cmap_blue; + unsigned int length; + + hw_colorvalue = 0; + if (((cmap->start) + (cmap->len)) >= 256) { + length = 256 - (cmap->start); + } else { + length = cmap->len; + } + + for (i = 0; i < length; i++) { + cmap_red = ((cmap->red[i]) >> 8); /* The cmap fields are 16 bits */ + cmap_green = ((cmap->green[i]) >> 8); /* wide, but the harware colormap */ + cmap_blue = ((cmap->blue[i]) >> 8); /* registers are only 8 bits wide */ + + hw_colorvalue = + (cmap_blue << 16) + (cmap_green << 8) + (cmap_red); + maxinefb_ims332_write_register(IMS332_REG_COLOR_PALETTE + + cmap->start + i, + hw_colorvalue); + } + return 0; +} + +static int maxinefb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct maxinefb_par par; + if (con == -1) { + maxinefb_get_par(&par); + maxinefb_encode_var(var, &par); + } else + *var = fb_display[con].var; + return 0; +} + + +static int maxinefb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + int err; + + if ((err = maxinefb_do_fb_set_var(var, 1))) + return err; + return 0; +} +static void maxinefb_encode_fix(struct fb_fix_screeninfo *fix, + struct maxinefb_par *par) +{ + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, "maxinefb"); + /* fix->id is a char[16], so a maximum of 15 characters, KM */ + + fix->smem_start = (char *) fb_start; /* display memory base address, KM */ + fix->smem_len = fb_size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = FB_VISUAL_PSEUDOCOLOR; + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->ywrapstep = 0; + fix->line_length = fb_line_length; +} + +static int maxinefb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + struct maxinefb_par par; + maxinefb_get_par(&par); + maxinefb_encode_fix(fix, &par); + return 0; +} + + +static int maxinefb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con, + struct fb_info *info) +{ + return -EINVAL; +} + +static int maxinefb_switch(int con, struct fb_info *info) +{ + maxinefb_do_fb_set_var(&fb_display[con].var, 1); + currcon = con; + return 0; +} + +/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ + +static void maxinefb_blank(int blank, struct fb_info *info) +{ + /* Not supported */ +} + +static int maxinefb_open(struct fb_info *info, int user) +{ + /* + * Nothing, only a usage count for the moment + */ + MOD_INC_USE_COUNT; + return (0); +} + +static void maxinefb_set_disp(int con) +{ + struct fb_fix_screeninfo fix; + struct display *display; + + if (con >= 0) + display = &fb_display[con]; + else + display = &disp; /* used during initialization */ + + maxinefb_get_fix(&fix, con, 0); + + display->screen_base = fix.smem_start; + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->line_length = fix.line_length; + display->next_line = fix.line_length; + display->can_soft_blank = 0; + display->inverse = 0; + + display->dispsw = &fbcon_cfb8; +} + +static int maxinefb_release(struct fb_info *info, int user) +{ + MOD_DEC_USE_COUNT; + return (0); +} + +static struct fb_ops maxinefb_ops = { + owner:THIS_MODULE, + fb_open:maxinefb_open, + fb_release:maxinefb_release, + fb_get_fix:maxinefb_get_fix, + fb_get_var:maxinefb_get_var, + fb_set_var:maxinefb_set_var, + fb_get_cmap:maxinefb_get_cmap, + fb_set_cmap:maxinefb_set_cmap, + fb_ioctl:maxinefb_ioctl, + fb_mmap:0, + fb_rasterimg:0 +}; + +int __init maxinefb_init_one() +{ + volatile unsigned char *fboff; + int i; + + /* Framebuffer display memory base address */ + fb_start = DS5000_xx_ONBOARD_FBMEM_START; + + /* Clear screen */ + for (fboff = fb_start; fboff < fb_start + 0x1ffff; fboff++) + *fboff = 0x0; + + /* erase hardware cursor */ + for (i = 0; i < 512; i++) { + maxinefb_ims332_write_register(IMS332_REG_CURSOR_RAM + i, + 0); + /* + if (i&0x8 == 0) + maxinefb_ims332_write_register (IMS332_REG_CURSOR_RAM + i, 0x0f); + else + maxinefb_ims332_write_register (IMS332_REG_CURSOR_RAM + i, 0xf0); + */ + } + + /* Fill in the available video resolution */ + maxinefb_defined.xres = 1024; + maxinefb_defined.yres = 768; + maxinefb_defined.xres_virtual = 1024; + maxinefb_defined.yres_virtual = 768; + maxinefb_defined.bits_per_pixel = 8; + + /* Let there be consoles... */ + + strcpy(fb_info.modename, "Maxine onboard graphics 1024x768x8"); + /* fb_info.modename: maximum of 39 characters + trailing nullbyte, KM */ + fb_info.changevar = NULL; + fb_info.node = -1; + fb_info.fbops = &maxinefb_ops; + fb_info.disp = &disp; + fb_info.switch_con = &maxinefb_switch; + fb_info.updatevar = &maxinefb_fb_update_var; + fb_info.blank = &maxinefb_blank; + fb_info.flags = FBINFO_FLAG_DEFAULT; + maxinefb_do_fb_set_var(&maxinefb_defined, 1); + + maxinefb_get_var(&disp.var, -1, &fb_info); + maxinefb_set_disp(-1); + + if (register_framebuffer(&fb_info) < 0) + return 1; + + return 0; +} + + +/* Initialise the framebuffer */ + +void __init maxinefb_init() +{ + unsigned int sid; + + if (mips_machtype == MACH_DS5000_XX) { + printk("Maxinefb: Personal DECstation detected\n"); + printk("Maxinefb: initializing onboard framebuffer\n"); + + maxinefb_init_one(); + + } + +} + +void __init maxinefb_setup(char *options, int *ints) +{ +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/maxinefb.h linux.ac/drivers/video/maxinefb.h --- linux.vanilla/drivers/video/maxinefb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/maxinefb.h Tue Apr 3 17:55:09 2001 @@ -0,0 +1,37 @@ +/* + * linux/drivers/video/maxinefb.h + * + * DECstation 5000/xx onboard framebuffer support, Copyright (C) 1999 by + * Michael Engel <engel@unix-ag.org> and Karsten Merker <merker@guug.de> + * 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. + */ + + +/* + * IMS332 video controller register base address + */ +#define MAXINEFB_IMS332_ADDRESS 0xbc140000 + +/* + * Begin of DECstation 5000/xx onboard framebuffer memory, default resolution + * is 1024x768x8 + */ +#define DS5000_xx_ONBOARD_FBMEM_START 0xaa000000 + +/* + * The IMS 332 video controller used in the DECstation 5000/xx series + * uses 32 bits wide registers; the following defines declare the + * register numbers, to get the real offset, these have to be multiplied + * by four. + */ + +#define IMS332_REG_CURSOR_RAM 0x200 /* hardware cursor bitmap */ + +/* + * The color palette entries have the form 0x00BBGGRR + */ +#define IMS332_REG_COLOR_PALETTE 0x100 /* color palette, 256 entries */ +#define IMS332_REG_CURSOR_COLOR_PALETTE 0x0a1 /* cursor color palette, */ + /* 3 entries */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/mdacon.c linux.ac/drivers/video/mdacon.c --- linux.vanilla/drivers/video/mdacon.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/mdacon.c Tue Apr 3 17:55:09 2001 @@ -21,6 +21,9 @@ * 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. + * + * Changelog: + * Paul G. (03/2001) Fix mdacon= boot prompt to use __setup(). */ #include <linux/types.h> @@ -129,6 +132,7 @@ spin_unlock_irqrestore(&mda_lock, flags); } +#ifdef TEST_MDA_B static int test_mda_b(unsigned char val, unsigned char reg) { unsigned long flags; @@ -143,6 +147,7 @@ spin_unlock_irqrestore(&mda_lock, flags); return val; } +#endif static inline void mda_set_origin(unsigned int location) { @@ -182,20 +187,27 @@ #ifndef MODULE -void __init mdacon_setup(char *str, int *ints) +static int __init mdacon_setup(char *str) { /* command line format: mdacon=<first>,<last> */ + int ints[3]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + if (ints[0] < 2) - return; + return 0; if (ints[1] < 1 || ints[1] > MAX_NR_CONSOLES || ints[2] < 1 || ints[2] > MAX_NR_CONSOLES) - return; + return 0; - mda_first_vc = ints[1]-1; - mda_last_vc = ints[2]-1; + mda_first_vc = ints[1]; + mda_last_vc = ints[2]; + return 1; } + +__setup("mdacon=", mdacon_setup); #endif static int __init mda_detect(void) @@ -237,17 +249,19 @@ * memory location, so now we do an I/O port test. */ +#ifdef TEST_MDA_B /* Edward: These two mess `tests' mess up my cursor on bootup */ /* cursor low register */ - /* if (! test_mda_b(0x66, 0x0f)) { + if (! test_mda_b(0x66, 0x0f)) { return 0; - } */ + } /* cursor low register */ - /* if (! test_mda_b(0x99, 0x0f)) { + if (! test_mda_b(0x99, 0x0f)) { return 0; - } */ + } +#endif /* See if the card is a Hercules, by checking whether the vsync * bit of the status register is changing. This test lasts for diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/offb.c linux.ac/drivers/video/offb.c --- linux.vanilla/drivers/video/offb.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/offb.c Tue Apr 3 17:55:09 2001 @@ -49,7 +49,8 @@ cmap_m64, /* ATI Mach64 */ cmap_r128, /* ATI Rage128 */ cmap_M3A, /* ATI Rage Mobility M3 Head A */ - cmap_M3B /* ATI Rage Mobility M3 Head B */ + cmap_M3B, /* ATI Rage Mobility M3 Head B */ + cmap_radeon /* ATI Radeon */ }; struct fb_info_offb { @@ -433,6 +434,10 @@ unsigned long regbase = dp->parent->addrs[2].address; info->cmap_adr = ioremap(regbase, 0x1FFF); info->cmap_type = cmap_M3B; + } else if (dp && !strncmp(name, "ATY,Rage6", 9)) { + unsigned long regbase = dp->addrs[1].address; + info->cmap_adr = ioremap(regbase, 0x1FFF); + info->cmap_type = cmap_radeon; } else if (!strncmp(name, "ATY,", 4)) { unsigned long base = address & 0xff000000UL; info->cmap_adr = ioremap(base + 0x7ff000, 0x1000) + 0xcc0; @@ -669,6 +674,10 @@ out_8(info2->cmap_adr + 0xb0, i); out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0); break; + case cmap_radeon: + out_8(info2->cmap_adr + 0xb0, i); + out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0); + break; } } else @@ -748,6 +757,12 @@ out_le32((unsigned *)(info2->cmap_adr + 0xb4), (red << 16 | green << 8 | blue)); break; + case cmap_radeon: + /* Set palette index & data (could be smarter) */ + out_8(info2->cmap_adr + 0xb0, regno); + out_le32((unsigned *)(info2->cmap_adr + 0xb4), + (red << 16 | green << 8 | blue)); + break; } if (regno < 16) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/pmag-ba-fb.c linux.ac/drivers/video/pmag-ba-fb.c --- linux.vanilla/drivers/video/pmag-ba-fb.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/pmag-ba-fb.c Tue Apr 3 17:55:09 2001 @@ -0,0 +1,431 @@ +/* + * linux/drivers/video/pmag-ba-fb.c + * + * PMAG-BA TurboChannel framebuffer card support ... derived from: + * "HP300 Topcat framebuffer support (derived from macfb of all things) + * Phil Blundell <philb@gnu.org> 1998", the original code can be + * found in the file hpfb.c in the same directory. + * + * Based on digital document: + * "PMAG-BA TURBOchannel Color Frame Buffer + * Functional Specification", Revision 1.2, August 27, 1990 + * + * DECstation related code Copyright (C) 1999, 2000, 2001 by + * Michael Engel <engel@unix-ag.org>, + * Karsten Merker <merker@linuxtag.org> and + * Harald Koerfgen <harald@unix-ag.org>. + * 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 <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/malloc.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/fb.h> +#include <asm/bootinfo.h> +#include <asm/dec/machtype.h> +#include <asm/dec/tc.h> +#include "pmag-ba-fb.h" + +#include <video/fbcon.h> +#include <video/fbcon-mfb.h> +#include <video/fbcon-cfb2.h> +#include <video/fbcon-cfb4.h> +#include <video/fbcon-cfb8.h> + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +struct pmag_ba_ramdac_regs { + unsigned char addr_low; + unsigned char pad0[3]; + unsigned char addr_hi; + unsigned char pad1[3]; + unsigned char data; + unsigned char pad2[3]; + unsigned char cmap; +}; + +struct pmag_ba_my_fb_info { + struct fb_info info; + struct pmag_ba_ramdac_regs *bt459_regs; + unsigned long pmagba_fb_start; + unsigned long pmagba_fb_size; + unsigned long pmagba_fb_line_length; +}; + +static struct display disp; +/* + * Max 3 TURBOchannel slots -> max 3 PMAG-BA :) + */ +static struct pmag_ba_my_fb_info pmagba_fb_info[3]; + +static struct fb_var_screeninfo pmagbafb_defined = { + 0, 0, 0, 0, /* W,H, W, H (virtual) load xres,xres_virtual */ + 0, 0, /* virtual -> visible no offset */ + 0, /* depth -> load bits_per_pixel */ + 0, /* greyscale ? */ + {0, 0, 0}, /* R */ + {0, 0, 0}, /* G */ + {0, 0, 0}, /* B */ + {0, 0, 0}, /* transparency */ + 0, /* standard pixel format */ + FB_ACTIVATE_NOW, + 274, 195, /* 14" monitor */ + FB_ACCEL_NONE, + 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0, /* No sync info */ + FB_VMODE_NONINTERLACED, + {0, 0, 0, 0, 0, 0} +}; + +struct pmagbafb_par { +}; + +static int currcon = 0; +struct pmagbafb_par current_par; + +static void pmagbafb_encode_var(struct fb_var_screeninfo *var, + struct pmagbafb_par *par) +{ + int i = 0; + var->xres = 1024; + var->yres = 864; + var->xres_virtual = 1024; + var->yres_virtual = 864; + var->xoffset = 0; + var->yoffset = 0; + var->bits_per_pixel = 8; + var->grayscale = 0; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + var->nonstd = 0; + var->activate = 1; + var->height = -1; + var->width = -1; + var->vmode = FB_VMODE_NONINTERLACED; + var->pixclock = 0; + var->sync = 0; + var->left_margin = 0; + var->right_margin = 0; + var->upper_margin = 0; + var->lower_margin = 0; + var->hsync_len = 0; + var->vsync_len = 0; + for (i = 0; i < arraysize(var->reserved); i++) + var->reserved[i] = 0; +} + +static void pmagbafb_get_par(struct pmagbafb_par *par) +{ + *par = current_par; +} + +static int pmagba_fb_update_var(int con, struct fb_info *info) +{ + return 0; +} + +static int pmagba_do_fb_set_var(struct fb_var_screeninfo *var, + int isactive) +{ + struct pmagbafb_par par; + + pmagbafb_get_par(&par); + pmagbafb_encode_var(var, &par); + return 0; +} + +/* + * Turn hardware cursor off + */ +void pmagbafb_erase_cursor(struct pmag_ba_my_fb_info *info) +{ + info->bt459_regs->addr_low = 0; + info->bt459_regs->addr_hi = 3; + info->bt459_regs->data = 0; +} + +/* + * Write to a Bt459 color map register + */ +void pmag_ba_bt459_write_colormap(struct pmag_ba_my_fb_info *info, + int reg, __u8 red, __u8 green, __u8 blue) +{ + info->bt459_regs->addr_low = (__u8) reg; + info->bt459_regs->addr_hi = 0; + info->bt459_regs->cmap = red; + info->bt459_regs->cmap = green; + info->bt459_regs->cmap = blue; +} + +/* + * Get the palette + */ + +static int pmagbafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + unsigned int i; + unsigned int length; + + if (((cmap->start) + (cmap->len)) >= 256) { + length = 256 - (cmap->start); + } else { + length = cmap->len; + } + for (i = 0; i < length; i++) { + /* + * TODO + */ + } + return 0; +} + +/* + * Set the palette. + */ +static int pmagbafb_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + unsigned int i; + __u8 cmap_red, cmap_green, cmap_blue; + unsigned int length; + + if (((cmap->start) + (cmap->len)) >= 256) + length = 256 - (cmap->start); + else + length = cmap->len; + + for (i = 0; i < length; i++) { + cmap_red = ((cmap->red[i]) >> 8); /* The cmap fields are 16 bits */ + cmap_green = ((cmap->green[i]) >> 8); /* wide, but the harware colormap */ + cmap_blue = ((cmap->blue[i]) >> 8); /* registers are only 8 bits wide */ + + pmag_ba_bt459_write_colormap((struct pmag_ba_my_fb_info *) + info, cmap->start + i, + cmap_red, cmap_green, + cmap_blue); + } + return 0; +} + +static int pmagbafb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct pmagbafb_par par; + if (con == -1) { + pmagbafb_get_par(&par); + pmagbafb_encode_var(var, &par); + } else + *var = fb_display[con].var; + return 0; +} + + +static int pmagbafb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + int err; + + if ((err = pmagba_do_fb_set_var(var, 1))) + return err; + return 0; +} + +static void pmagbafb_encode_fix(struct fb_fix_screeninfo *fix, + struct pmagbafb_par *par, + struct pmag_ba_my_fb_info *info) +{ + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, "PMAG-BA"); + + fix->smem_start = info->pmagba_fb_start; + fix->smem_len = info->pmagba_fb_size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = FB_VISUAL_PSEUDOCOLOR; + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->ywrapstep = 0; + fix->line_length = info->pmagba_fb_line_length; +} + +static int pmagbafb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + struct pmagbafb_par par; + + pmagbafb_get_par(&par); + pmagbafb_encode_fix(fix, &par, (struct pmag_ba_my_fb_info *) info); + + return 0; +} + + +static int pmagbafb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con, + struct fb_info *info) +{ + return -EINVAL; +} + +static int pmagbafb_switch(int con, struct fb_info *info) +{ + pmagba_do_fb_set_var(&fb_display[con].var, 1); + currcon = con; + + return 0; +} + +/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ + +static void pmagbafb_blank(int blank, struct fb_info *info) +{ + /* Not supported */ +} + +static int pmagbafb_open(struct fb_info *info, int user) +{ + /* + * Nothing, only a usage count for the moment + */ + MOD_INC_USE_COUNT; + return (0); +} + +static void pmagbafb_set_disp(int con, struct pmag_ba_my_fb_info *info) +{ + struct fb_fix_screeninfo fix; + struct display *display; + + if (con >= 0) + display = &fb_display[con]; + else + display = &disp; /* used during initialization */ + + pmagbafb_get_fix(&fix, con, (struct fb_info *) info); + + display->screen_base = (char *) fix.smem_start; + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->line_length = fix.line_length; + display->next_line = fix.line_length; + display->can_soft_blank = 0; + display->inverse = 0; + + display->dispsw = &fbcon_cfb8; +} + +static int pmagbafb_release(struct fb_info *info, int user) +{ + MOD_DEC_USE_COUNT; + return (0); +} + +static struct fb_ops pmagbafb_ops = { + owner:THIS_MODULE, + fb_open:pmagbafb_open, + fb_release:pmagbafb_release, + fb_get_fix:pmagbafb_get_fix, + fb_get_var:pmagbafb_get_var, + fb_set_var:pmagbafb_set_var, + fb_get_cmap:pmagbafb_get_cmap, + fb_set_cmap:pmagbafb_set_cmap, + fb_ioctl:pmagbafb_ioctl, + fb_mmap:0, + fb_rasterimg:0 +}; + +int __init pmagbafb_init_one(int slot) +{ + unsigned long base_addr = get_tc_base_addr(slot); + struct pmag_ba_my_fb_info *ip = + (struct pmag_ba_my_fb_info *) &pmagba_fb_info[slot]; + + printk("PMAG-BA framebuffer in slot %d\n", slot); + + /* + * Framebuffer display memory base address and friends + */ + ip->bt459_regs = + (struct pmag_ba_ramdac_regs *) (base_addr + + PMAG_BA_BT459_OFFSET); + ip->pmagba_fb_start = base_addr + PMAG_BA_ONBOARD_FBMEM_OFFSET; + ip->pmagba_fb_size = 1024 * 864; + ip->pmagba_fb_line_length = 1024; + + /* + * Configure the Bt459 RAM DAC + */ + pmagbafb_erase_cursor(ip); + + /* + * Fill in the available video resolution + */ + + pmagbafb_defined.xres = 1024; + pmagbafb_defined.yres = 864; + pmagbafb_defined.xres_virtual = 1024; + pmagbafb_defined.yres_virtual = 864; + pmagbafb_defined.bits_per_pixel = 8; + + /* + * Let there be consoles.. + */ + strcpy(ip->info.modename, "PMAG-BA"); + ip->info.changevar = NULL; + ip->info.node = -1; + ip->info.fbops = &pmagbafb_ops; + ip->info.disp = &disp; + ip->info.switch_con = &pmagbafb_switch; + ip->info.updatevar = &pmagba_fb_update_var; + ip->info.blank = &pmagbafb_blank; + ip->info.flags = FBINFO_FLAG_DEFAULT; + + pmagba_do_fb_set_var(&pmagbafb_defined, 1); + pmagbafb_get_var(&disp.var, -1, (struct fb_info *) ip); + pmagbafb_set_disp(-1, ip); + + if (register_framebuffer((struct fb_info *) ip) < 0) + return 1; + + return 0; +} + +/* + * Initialise the framebuffer + */ + +int __init pmagbafb_init(void) +{ + int sid; + int found = 0; + + if (TURBOCHANNEL) { + while ((sid = search_tc_card("PMAG-BA")) >= 0) { + found = 1; + claim_tc_card(sid); + pmagbafb_init_one(sid); + } + return found ? 0 : -ENODEV; + } else { + return -ENODEV; + } +} + +int __init pmagbafb_setup(char *options) +{ + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/pmag-ba-fb.h linux.ac/drivers/video/pmag-ba-fb.h --- linux.vanilla/drivers/video/pmag-ba-fb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/pmag-ba-fb.h Tue Apr 3 17:55:09 2001 @@ -0,0 +1,24 @@ +/* + * linux/drivers/video/pmag-ba-fb.h + * + * TurboChannel PMAG-BA framebuffer card support, + * Copyright (C) 1999,2000,2001 by + * Michael Engel <engel@unix-ag.org>, + * Karsten Merker <merker@linuxtag.org> + * 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. + */ + +/* + * Bt459 RAM DAC register base offset (rel. to TC slot base address) + */ + +#define PMAG_BA_BT459_OFFSET 0x00200000 + +/* + * Begin of PMAG-BA framebuffer memory relative to TC slot address, + * resolution is 1024x864x8 + */ + +#define PMAG_BA_ONBOARD_FBMEM_OFFSET 0x00000000 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/pmagb-b-fb.c linux.ac/drivers/video/pmagb-b-fb.c --- linux.vanilla/drivers/video/pmagb-b-fb.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/pmagb-b-fb.c Tue Apr 3 17:55:09 2001 @@ -0,0 +1,434 @@ +/* + * linux/drivers/video/pmagb-b-fb.c + * + * PMAGB-B TurboChannel framebuffer card support ... derived from: + * "HP300 Topcat framebuffer support (derived from macfb of all things) + * Phil Blundell <philb@gnu.org> 1998", the original code can be + * found in the file hpfb.c in the same directory. + * + * DECstation related code Copyright (C) 1999, 2000, 2001 by + * Michael Engel <engel@unix-ag.org>, + * Karsten Merker <merker@linuxtag.org> and + * Harald Koerfgen <harald@unix-ag.org>. + * 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. + * + */ + +/* + * We currently only support the PMAGB-B in high resolution mode + * as I know of no way to detect low resolution mode set via jumper. + * KM, 2001/01/07 + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/malloc.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/fb.h> +#include <asm/bootinfo.h> +#include <asm/dec/machtype.h> +#include <asm/dec/tc.h> +#include "pmagb-b-fb.h" + +#include <video/fbcon.h> +#include <video/fbcon-mfb.h> +#include <video/fbcon-cfb2.h> +#include <video/fbcon-cfb4.h> +#include <video/fbcon-cfb8.h> + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +struct pmagb_b_ramdac_regs { + unsigned char addr_low; + unsigned char pad0[3]; + unsigned char addr_hi; + unsigned char pad1[3]; + unsigned char data; + unsigned char pad2[3]; + unsigned char cmap; +}; + +struct pmagb_b_my_fb_info { + struct fb_info info; + struct pmagb_b_ramdac_regs *bt459_regs; + unsigned long pmagbb_fb_start; + unsigned long pmagbb_fb_size; + unsigned long pmagbb_fb_line_length; +}; + +static struct display disp; +/* + * Max 3 TURBOchannel slots -> max 3 PMAGB-B :) + */ +static struct pmagb_b_my_fb_info pmagbb_fb_info[3]; + +static struct fb_var_screeninfo pmagbbfb_defined = { + 0, 0, 0, 0, /* W,H, W, H (virtual) load xres,xres_virtual */ + 0, 0, /* virtual -> visible no offset */ + 0, /* depth -> load bits_per_pixel */ + 0, /* greyscale ? */ + {0, 0, 0}, /* R */ + {0, 0, 0}, /* G */ + {0, 0, 0}, /* B */ + {0, 0, 0}, /* transparency */ + 0, /* standard pixel format */ + FB_ACTIVATE_NOW, + 274, 195, /* 14" monitor */ + FB_ACCEL_NONE, + 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0, /* No sync info */ + FB_VMODE_NONINTERLACED, + {0, 0, 0, 0, 0, 0} +}; + +struct pmagbbfb_par { +}; + +static int currcon = 0; +struct pmagbbfb_par current_par; + +static void pmagbbfb_encode_var(struct fb_var_screeninfo *var, + struct pmagbbfb_par *par) +{ + int i = 0; + var->xres = 1280; + var->yres = 1024; + var->xres_virtual = 1280; + var->yres_virtual = 1024; + var->xoffset = 0; + var->yoffset = 0; + var->bits_per_pixel = 8; + var->grayscale = 0; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + var->nonstd = 0; + var->activate = 1; + var->height = -1; + var->width = -1; + var->vmode = FB_VMODE_NONINTERLACED; + var->pixclock = 0; + var->sync = 0; + var->left_margin = 0; + var->right_margin = 0; + var->upper_margin = 0; + var->lower_margin = 0; + var->hsync_len = 0; + var->vsync_len = 0; + for (i = 0; i < arraysize(var->reserved); i++) + var->reserved[i] = 0; +} + +static void pmagbbfb_get_par(struct pmagbbfb_par *par) +{ + *par = current_par; +} + +static int pmagbb_fb_update_var(int con, struct fb_info *info) +{ + return 0; +} + +static int pmagbb_do_fb_set_var(struct fb_var_screeninfo *var, + int isactive) +{ + struct pmagbbfb_par par; + + pmagbbfb_get_par(&par); + pmagbbfb_encode_var(var, &par); + return 0; +} + +/* + * Turn hardware cursor off + */ +void pmagbbfb_erase_cursor(struct pmagb_b_my_fb_info *info) +{ + info->bt459_regs->addr_low = 0; + info->bt459_regs->addr_hi = 3; + info->bt459_regs->data = 0; +} + +/* + * Write to a Bt459 color map register + */ +void pmagb_b_bt459_write_colormap(struct pmagb_b_my_fb_info *info, + int reg, __u8 red, __u8 green, __u8 blue) +{ + info->bt459_regs->addr_low = (__u8) reg; + info->bt459_regs->addr_hi = 0; + info->bt459_regs->cmap = red; + info->bt459_regs->cmap = green; + info->bt459_regs->cmap = blue; +} + +/* + * Get the palette + */ + +static int pmagbbfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + unsigned int i; + unsigned int length; + + if (((cmap->start) + (cmap->len)) >= 256) { + length = 256 - (cmap->start); + } else { + length = cmap->len; + } + for (i = 0; i < length; i++) { + /* + * TODO + */ + } + return 0; +} + +/* + * Set the palette. + */ +static int pmagbbfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + unsigned int i; + __u8 cmap_red, cmap_green, cmap_blue; + unsigned int length; + + if (((cmap->start) + (cmap->len)) >= 256) + length = 256 - (cmap->start); + else + length = cmap->len; + + for (i = 0; i < length; i++) { + cmap_red = ((cmap->red[i]) >> 8); /* The cmap fields are 16 bits */ + cmap_green = ((cmap->green[i]) >> 8); /* wide, but the harware colormap */ + cmap_blue = ((cmap->blue[i]) >> 8); /* registers are only 8 bits wide */ + + pmagb_b_bt459_write_colormap((struct pmagb_b_my_fb_info *) + info, cmap->start + i, + cmap_red, cmap_green, + cmap_blue); + } + return 0; +} + +static int pmagbbfb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct pmagbbfb_par par; + if (con == -1) { + pmagbbfb_get_par(&par); + pmagbbfb_encode_var(var, &par); + } else + *var = fb_display[con].var; + return 0; +} + + +static int pmagbbfb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + int err; + + if ((err = pmagbb_do_fb_set_var(var, 1))) + return err; + return 0; +} + +static void pmagbbfb_encode_fix(struct fb_fix_screeninfo *fix, + struct pmagbbfb_par *par, + struct pmagb_b_my_fb_info *info) +{ + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, "PMAGB-BA"); + + fix->smem_start = info->pmagbb_fb_start; + fix->smem_len = info->pmagbb_fb_size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = FB_VISUAL_PSEUDOCOLOR; + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->ywrapstep = 0; + fix->line_length = info->pmagbb_fb_line_length; +} + +static int pmagbbfb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + struct pmagbbfb_par par; + + pmagbbfb_get_par(&par); + pmagbbfb_encode_fix(fix, &par, (struct pmagb_b_my_fb_info *) info); + + return 0; +} + + +static int pmagbbfb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con, + struct fb_info *info) +{ + return -EINVAL; +} + +static int pmagbbfb_switch(int con, struct fb_info *info) +{ + pmagbb_do_fb_set_var(&fb_display[con].var, 1); + currcon = con; + + return 0; +} + +/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ + +static void pmagbbfb_blank(int blank, struct fb_info *info) +{ + /* Not supported */ +} + +static int pmagbbfb_open(struct fb_info *info, int user) +{ + /* + * Nothing, only a usage count for the moment + */ + MOD_INC_USE_COUNT; + return (0); +} + +static void pmagbbfb_set_disp(int con, struct pmagb_b_my_fb_info *info) +{ + struct fb_fix_screeninfo fix; + struct display *display; + + if (con >= 0) + display = &fb_display[con]; + else + display = &disp; /* used during initialization */ + + pmagbbfb_get_fix(&fix, con, (struct fb_info *) info); + + display->screen_base = (char *) fix.smem_start; + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->line_length = fix.line_length; + display->next_line = fix.line_length; + display->can_soft_blank = 0; + display->inverse = 0; + + display->dispsw = &fbcon_cfb8; +} + +static int pmagbbfb_release(struct fb_info *info, int user) +{ + MOD_DEC_USE_COUNT; + return (0); +} + +static struct fb_ops pmagbbfb_ops = { + owner:THIS_MODULE, + fb_open:pmagbbfb_open, + fb_release:pmagbbfb_release, + fb_get_fix:pmagbbfb_get_fix, + fb_get_var:pmagbbfb_get_var, + fb_set_var:pmagbbfb_set_var, + fb_get_cmap:pmagbbfb_get_cmap, + fb_set_cmap:pmagbbfb_set_cmap, + fb_ioctl:pmagbbfb_ioctl, + fb_mmap:0, + fb_rasterimg:0 +}; + +int __init pmagbbfb_init_one(int slot) +{ + unsigned long base_addr = get_tc_base_addr(slot); + struct pmagb_b_my_fb_info *ip = + (struct pmagb_b_my_fb_info *) &pmagbb_fb_info[slot]; + + printk("PMAGB-BA framebuffer in slot %d\n", slot); + + /* + * Framebuffer display memory base address and friends + */ + ip->bt459_regs = + (struct pmagb_b_ramdac_regs *) (base_addr + + PMAGB_B_BT459_OFFSET); + ip->pmagbb_fb_start = base_addr + PMAGB_B_ONBOARD_FBMEM_OFFSET; + ip->pmagbb_fb_size = 1280 * 1024; + ip->pmagbb_fb_line_length = 1280; + + /* + * Configure the Bt459 RAM DAC + */ + pmagbbfb_erase_cursor(ip); + + /* + * Fill in the available video resolution + */ + + pmagbbfb_defined.xres = 1280; + pmagbbfb_defined.yres = 1024; + pmagbbfb_defined.xres_virtual = 1280; + pmagbbfb_defined.yres_virtual = 1024; + pmagbbfb_defined.bits_per_pixel = 8; + + /* + * Let there be consoles.. + */ + strcpy(ip->info.modename, "PMAGB-BA"); + ip->info.changevar = NULL; + ip->info.node = -1; + ip->info.fbops = &pmagbbfb_ops; + ip->info.disp = &disp; + ip->info.switch_con = &pmagbbfb_switch; + ip->info.updatevar = &pmagbb_fb_update_var; + ip->info.blank = &pmagbbfb_blank; + ip->info.flags = FBINFO_FLAG_DEFAULT; + + pmagbb_do_fb_set_var(&pmagbbfb_defined, 1); + pmagbbfb_get_var(&disp.var, -1, (struct fb_info *) ip); + pmagbbfb_set_disp(-1, ip); + + if (register_framebuffer((struct fb_info *) ip) < 0) + return 1; + + return 0; +} + +/* + * Initialise the framebuffer + */ + +int __init pmagbbfb_init(void) +{ + int sid; + int found = 0; + + if (TURBOCHANNEL) { + while ((sid = search_tc_card("PMAGB-BA")) >= 0) { + found = 1; + claim_tc_card(sid); + pmagbbfb_init_one(sid); + } + return found ? 0 : -ENODEV; + } else { + return -ENODEV; + } +} + +int __init pmagbbfb_setup(char *options) +{ + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/pmagb-b-fb.h linux.ac/drivers/video/pmagb-b-fb.h --- linux.vanilla/drivers/video/pmagb-b-fb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/pmagb-b-fb.h Tue Apr 3 17:55:09 2001 @@ -0,0 +1,32 @@ +/* + * linux/drivers/video/pmagb-b-fb.h + * + * TurboChannel PMAGB-B framebuffer card support, + * Copyright (C) 1999, 2000, 2001 by + * Michael Engel <engel@unix-ag.org> and + * Karsten Merker <merker@linxutag.org> + * 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. + */ + + +/* + * Bt459 RAM DAC register base offset (rel. to TC slot base address) + */ +#define PMAGB_B_BT459_OFFSET 0x001C0000 + +/* + * Begin of PMAGB-B framebuffer memory, resolution is configurable: + * 1024x864x8 or 1280x1024x8, settable by jumper on the card + */ +#define PMAGB_B_ONBOARD_FBMEM_OFFSET 0x00201000 + +/* + * Bt459 register offsets, byte-wide registers + */ + +#define BT459_ADR_LOW BT459_OFFSET + 0x00 /* addr. low */ +#define BT459_ADR_HIGH BT459_OFFSET + 0x04 /* addr. high */ +#define BT459_DATA BT459_OFFSET + 0x08 /* r/w data */ +#define BT459_CMAP BT459_OFFSET + 0x0C /* color map */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/radeon.h linux.ac/drivers/video/radeon.h --- linux.vanilla/drivers/video/radeon.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/radeon.h Tue Apr 3 17:55:09 2001 @@ -0,0 +1,611 @@ +#ifndef _RADEON_H +#define _RADEON_H + + +/* radeon PCI ids */ +#define PCI_DEVICE_ID_RADEON_QD 0x5144 +#define PCI_DEVICE_ID_RADEON_QE 0x5145 +#define PCI_DEVICE_ID_RADEON_QF 0x5146 +#define PCI_DEVICE_ID_RADEON_QG 0x5147 + +#define RADEON_REGSIZE 0x4000 + + +#define MM_INDEX 0x0000 +#define MM_DATA 0x0004 +#define BUS_CNTL 0x0030 +#define HI_STAT 0x004C +#define BUS_CNTL1 0x0034 +#define I2C_CNTL_1 0x0094 +#define CONFIG_CNTL 0x00E0 +#define CONFIG_MEMSIZE 0x00F8 +#define CONFIG_APER_0_BASE 0x0100 +#define CONFIG_APER_1_BASE 0x0104 +#define CONFIG_APER_SIZE 0x0108 +#define CONFIG_REG_1_BASE 0x010C +#define CONFIG_REG_APER_SIZE 0x0110 +#define PAD_AGPINPUT_DELAY 0x0164 +#define PAD_CTLR_STRENGTH 0x0168 +#define PAD_CTLR_UPDATE 0x016C +#define AGP_CNTL 0x0174 +#define BM_STATUS 0x0160 +#define CAP0_TRIG_CNTL 0x0950 +#define VIPH_CONTROL 0x0C40 +#define VENDOR_ID 0x0F00 +#define DEVICE_ID 0x0F02 +#define COMMAND 0x0F04 +#define STATUS 0x0F06 +#define REVISION_ID 0x0F08 +#define REGPROG_INF 0x0F09 +#define SUB_CLASS 0x0F0A +#define BASE_CODE 0x0F0B +#define CACHE_LINE 0x0F0C +#define LATENCY 0x0F0D +#define HEADER 0x0F0E +#define BIST 0x0F0F +#define REG_MEM_BASE 0x0F10 +#define REG_IO_BASE 0x0F14 +#define REG_REG_BASE 0x0F18 +#define ADAPTER_ID 0x0F2C +#define BIOS_ROM 0x0F30 +#define CAPABILITIES_PTR 0x0F34 +#define INTERRUPT_LINE 0x0F3C +#define INTERRUPT_PIN 0x0F3D +#define MIN_GRANT 0x0F3E +#define MAX_LATENCY 0x0F3F +#define ADAPTER_ID_W 0x0F4C +#define PMI_CAP_ID 0x0F50 +#define PMI_NXT_CAP_PTR 0x0F51 +#define PMI_PMC_REG 0x0F52 +#define PM_STATUS 0x0F54 +#define PMI_DATA 0x0F57 +#define AGP_CAP_ID 0x0F58 +#define AGP_STATUS 0x0F5C +#define AGP_COMMAND 0x0F60 +#define AIC_CTRL 0x01D0 +#define AIC_STAT 0x01D4 +#define AIC_PT_BASE 0x01D8 +#define AIC_LO_ADDR 0x01DC +#define AIC_HI_ADDR 0x01E0 +#define AIC_TLB_ADDR 0x01E4 +#define AIC_TLB_DATA 0x01E8 +#define DAC_CNTL 0x0058 +#define CRTC_GEN_CNTL 0x0050 +#define MEM_CNTL 0x0140 +#define EXT_MEM_CNTL 0x0144 +#define MC_AGP_LOCATION 0x014C +#define MEM_IO_CNTL_A0 0x0178 +#define MEM_INIT_LATENCY_TIMER 0x0154 +#define MEM_SDRAM_MODE_REG 0x0158 +#define AGP_BASE 0x0170 +#define MEM_IO_CNTL_A1 0x017C +#define MEM_IO_CNTL_B0 0x0180 +#define MEM_IO_CNTL_B1 0x0184 +#define MC_DEBUG 0x0188 +#define MC_STATUS 0x0150 +#define MEM_IO_OE_CNTL 0x018C +#define MC_FB_LOCATION 0x0148 +#define HOST_PATH_CNTL 0x0130 +#define MEM_VGA_WP_SEL 0x0038 +#define MEM_VGA_RP_SEL 0x003C +#define HDP_DEBUG 0x0138 +#define SW_SEMAPHORE 0x013C +#define SURFACE_CNTL 0x0B00 +#define SURFACE0_LOWER_BOUND 0x0B04 +#define SURFACE1_LOWER_BOUND 0x0B14 +#define SURFACE2_LOWER_BOUND 0x0B24 +#define SURFACE3_LOWER_BOUND 0x0B34 +#define SURFACE4_LOWER_BOUND 0x0B44 +#define SURFACE5_LOWER_BOUND 0x0B54 +#define SURFACE6_LOWER_BOUND 0x0B64 +#define SURFACE7_LOWER_BOUND 0x0B74 +#define SURFACE0_UPPER_BOUND 0x0B08 +#define SURFACE1_UPPER_BOUND 0x0B18 +#define SURFACE2_UPPER_BOUND 0x0B28 +#define SURFACE3_UPPER_BOUND 0x0B38 +#define SURFACE4_UPPER_BOUND 0x0B48 +#define SURFACE5_UPPER_BOUND 0x0B58 +#define SURFACE6_UPPER_BOUND 0x0B68 +#define SURFACE7_UPPER_BOUND 0x0B78 +#define SURFACE0_INFO 0x0B0C +#define SURFACE1_INFO 0x0B1C +#define SURFACE2_INFO 0x0B2C +#define SURFACE3_INFO 0x0B3C +#define SURFACE4_INFO 0x0B4C +#define SURFACE5_INFO 0x0B5C +#define SURFACE6_INFO 0x0B6C +#define SURFACE7_INFO 0x0B7C +#define SURFACE_ACCESS_FLAGS 0x0BF8 +#define SURFACE_ACCESS_CLR 0x0BFC +#define GEN_INT_CNTL 0x0040 +#define GEN_INT_STATUS 0x0044 +#define CRTC_EXT_CNTL 0x0054 +#define RB3D_CNTL 0x1C3C +#define WAIT_UNTIL 0x1720 +#define ISYNC_CNTL 0x1724 +#define RBBM_GUICNTL 0x172C +#define RBBM_STATUS 0x0E40 +#define RBBM_STATUS_alt_1 0x1740 +#define RBBM_CNTL 0x00EC +#define RBBM_CNTL_alt_1 0x0E44 +#define RBBM_SOFT_RESET 0x00F0 +#define RBBM_SOFT_RESET_alt_1 0x0E48 +#define NQWAIT_UNTIL 0x0E50 +#define RBBM_DEBUG 0x0E6C +#define RBBM_CMDFIFO_ADDR 0x0E70 +#define RBBM_CMDFIFO_DATAL 0x0E74 +#define RBBM_CMDFIFO_DATAH 0x0E78 +#define RBBM_CMDFIFO_STAT 0x0E7C +#define CRTC_STATUS 0x005C +#define GPIO_VGA_DDC 0x0060 +#define GPIO_DVI_DDC 0x0064 +#define GPIO_MONID 0x0068 +#define PALETTE_INDEX 0x00B0 +#define PALETTE_DATA 0x00B4 +#define PALETTE_30_DATA 0x00B8 +#define CRTC_H_TOTAL_DISP 0x0200 +#define CRTC_H_SYNC_STRT_WID 0x0204 +#define CRTC_V_TOTAL_DISP 0x0208 +#define CRTC_V_SYNC_STRT_WID 0x020C +#define CRTC_VLINE_CRNT_VLINE 0x0210 +#define CRTC_CRNT_FRAME 0x0214 +#define CRTC_GUI_TRIG_VLINE 0x0218 +#define CRTC_DEBUG 0x021C +#define CRTC_OFFSET_RIGHT 0x0220 +#define CRTC_OFFSET 0x0224 +#define CRTC_OFFSET_CNTL 0x0228 +#define CRTC_PITCH 0x022C +#define OVR_CLR 0x0230 +#define OVR_WID_LEFT_RIGHT 0x0234 +#define OVR_WID_TOP_BOTTOM 0x0238 +#define DISPLAY_BASE_ADDR 0x023C +#define SNAPSHOT_VH_COUNTS 0x0240 +#define SNAPSHOT_F_COUNT 0x0244 +#define N_VIF_COUNT 0x0248 +#define SNAPSHOT_VIF_COUNT 0x024C +#define FP_CRTC_H_TOTAL_DISP 0x0250 +#define FP_CRTC_V_TOTAL_DISP 0x0254 +#define CRT_CRTC_H_SYNC_STRT_WID 0x0258 +#define CRT_CRTC_V_SYNC_STRT_WID 0x025C +#define CUR_OFFSET 0x0260 +#define CUR_HORZ_VERT_POSN 0x0264 +#define CUR_HORZ_VERT_OFF 0x0268 +#define CUR_CLR0 0x026C +#define CUR_CLR1 0x0270 +#define FP_HORZ_VERT_ACTIVE 0x0278 +#define CRTC_MORE_CNTL 0x027C +#define DAC_EXT_CNTL 0x0280 +#define FP_GEN_CNTL 0x0284 +#define FP_HORZ_STRETCH 0x028C +#define FP_VERT_STRETCH 0x0290 +#define FP_H_SYNC_STRT_WID 0x02C4 +#define FP_V_SYNC_STRT_WID 0x02C8 +#define AUX_WINDOW_HORZ_CNTL 0x02D8 +#define AUX_WINDOW_VERT_CNTL 0x02DC +#define DDA_CONFIG 0x02e0 +#define DDA_ON_OFF 0x02e4 +#define GRPH_BUFFER_CNTL 0x02F0 +#define VGA_BUFFER_CNTL 0x02F4 +#define OV0_Y_X_START 0x0400 +#define OV0_Y_X_END 0x0404 +#define OV0_PIPELINE_CNTL 0x0408 +#define OV0_REG_LOAD_CNTL 0x0410 +#define OV0_SCALE_CNTL 0x0420 +#define OV0_V_INC 0x0424 +#define OV0_P1_V_ACCUM_INIT 0x0428 +#define OV0_P23_V_ACCUM_INIT 0x042C +#define OV0_P1_BLANK_LINES_AT_TOP 0x0430 +#define OV0_P23_BLANK_LINES_AT_TOP 0x0434 +#define OV0_BASE_ADDR 0x043C +#define OV0_VID_BUF0_BASE_ADRS 0x0440 +#define OV0_VID_BUF1_BASE_ADRS 0x0444 +#define OV0_VID_BUF2_BASE_ADRS 0x0448 +#define OV0_VID_BUF3_BASE_ADRS 0x044C +#define OV0_VID_BUF4_BASE_ADRS 0x0450 +#define OV0_VID_BUF5_BASE_ADRS 0x0454 +#define OV0_VID_BUF_PITCH0_VALUE 0x0460 +#define OV0_VID_BUF_PITCH1_VALUE 0x0464 +#define OV0_AUTO_FLIP_CNTRL 0x0470 +#define OV0_DEINTERLACE_PATTERN 0x0474 +#define OV0_SUBMIT_HISTORY 0x0478 +#define OV0_H_INC 0x0480 +#define OV0_STEP_BY 0x0484 +#define OV0_P1_H_ACCUM_INIT 0x0488 +#define OV0_P23_H_ACCUM_INIT 0x048C +#define OV0_P1_X_START_END 0x0494 +#define OV0_P2_X_START_END 0x0498 +#define OV0_P3_X_START_END 0x049C +#define OV0_FILTER_CNTL 0x04A0 +#define OV0_FOUR_TAP_COEF_0 0x04B0 +#define OV0_FOUR_TAP_COEF_1 0x04B4 +#define OV0_FOUR_TAP_COEF_2 0x04B8 +#define OV0_FOUR_TAP_COEF_3 0x04BC +#define OV0_FOUR_TAP_COEF_4 0x04C0 +#define OV0_FLAG_CNTRL 0x04DC +#define OV0_SLICE_CNTL 0x04E0 +#define OV0_VID_KEY_CLR_LOW 0x04E4 +#define OV0_VID_KEY_CLR_HIGH 0x04E8 +#define OV0_GRPH_KEY_CLR_LOW 0x04EC +#define OV0_GRPH_KEY_CLR_HIGH 0x04F0 +#define OV0_KEY_CNTL 0x04F4 +#define OV0_TEST 0x04F8 +#define SUBPIC_CNTL 0x0540 +#define SUBPIC_DEFCOLCON 0x0544 +#define SUBPIC_Y_X_START 0x054C +#define SUBPIC_Y_X_END 0x0550 +#define SUBPIC_V_INC 0x0554 +#define SUBPIC_H_INC 0x0558 +#define SUBPIC_BUF0_OFFSET 0x055C +#define SUBPIC_BUF1_OFFSET 0x0560 +#define SUBPIC_LC0_OFFSET 0x0564 +#define SUBPIC_LC1_OFFSET 0x0568 +#define SUBPIC_PITCH 0x056C +#define SUBPIC_BTN_HLI_COLCON 0x0570 +#define SUBPIC_BTN_HLI_Y_X_START 0x0574 +#define SUBPIC_BTN_HLI_Y_X_END 0x0578 +#define SUBPIC_PALETTE_INDEX 0x057C +#define SUBPIC_PALETTE_DATA 0x0580 +#define SUBPIC_H_ACCUM_INIT 0x0584 +#define SUBPIC_V_ACCUM_INIT 0x0588 +#define DISP_MISC_CNTL 0x0D00 +#define DAC_MACRO_CNTL 0x0D04 +#define DISP_PWR_MAN 0x0D08 +#define DISP_TEST_DEBUG_CNTL 0x0D10 +#define DISP_HW_DEBUG 0x0D14 +#define DAC_CRC_SIG1 0x0D18 +#define DAC_CRC_SIG2 0x0D1C +#define OV0_LIN_TRANS_A 0x0D20 +#define OV0_LIN_TRANS_B 0x0D24 +#define OV0_LIN_TRANS_C 0x0D28 +#define OV0_LIN_TRANS_D 0x0D2C +#define OV0_LIN_TRANS_E 0x0D30 +#define OV0_LIN_TRANS_F 0x0D34 +#define OV0_GAMMA_0_F 0x0D40 +#define OV0_GAMMA_10_1F 0x0D44 +#define OV0_GAMMA_20_3F 0x0D48 +#define OV0_GAMMA_40_7F 0x0D4C +#define OV0_GAMMA_380_3BF 0x0D50 +#define OV0_GAMMA_3C0_3FF 0x0D54 +#define DISP_MERGE_CNTL 0x0D60 +#define DISP_OUTPUT_CNTL 0x0D64 +#define DISP_LIN_TRANS_GRPH_A 0x0D80 +#define DISP_LIN_TRANS_GRPH_B 0x0D84 +#define DISP_LIN_TRANS_GRPH_C 0x0D88 +#define DISP_LIN_TRANS_GRPH_D 0x0D8C +#define DISP_LIN_TRANS_GRPH_E 0x0D90 +#define DISP_LIN_TRANS_GRPH_F 0x0D94 +#define DISP_LIN_TRANS_VID_A 0x0D98 +#define DISP_LIN_TRANS_VID_B 0x0D9C +#define DISP_LIN_TRANS_VID_C 0x0DA0 +#define DISP_LIN_TRANS_VID_D 0x0DA4 +#define DISP_LIN_TRANS_VID_E 0x0DA8 +#define DISP_LIN_TRANS_VID_F 0x0DAC +#define RMX_HORZ_FILTER_0TAP_COEF 0x0DB0 +#define RMX_HORZ_FILTER_1TAP_COEF 0x0DB4 +#define RMX_HORZ_FILTER_2TAP_COEF 0x0DB8 +#define RMX_HORZ_PHASE 0x0DBC +#define DAC_EMBEDDED_SYNC_CNTL 0x0DC0 +#define DAC_BROAD_PULSE 0x0DC4 +#define DAC_SKEW_CLKS 0x0DC8 +#define DAC_INCR 0x0DCC +#define DAC_NEG_SYNC_LEVEL 0x0DD0 +#define DAC_POS_SYNC_LEVEL 0x0DD4 +#define DAC_BLANK_LEVEL 0x0DD8 +#define CLOCK_CNTL_INDEX 0x0008 +#define CLOCK_CNTL_DATA 0x000C +#define CP_RB_CNTL 0x0704 +#define CP_RB_BASE 0x0700 +#define CP_RB_RPTR_ADDR 0x070C +#define CP_RB_RPTR 0x0710 +#define CP_RB_WPTR 0x0714 +#define CP_RB_WPTR_DELAY 0x0718 +#define CP_IB_BASE 0x0738 +#define CP_IB_BUFSZ 0x073C +#define SCRATCH_REG0 0x15E0 +#define GUI_SCRATCH_REG0 0x15E0 +#define SCRATCH_REG1 0x15E4 +#define GUI_SCRATCH_REG1 0x15E4 +#define SCRATCH_REG2 0x15E8 +#define GUI_SCRATCH_REG2 0x15E8 +#define SCRATCH_REG3 0x15EC +#define GUI_SCRATCH_REG3 0x15EC +#define SCRATCH_REG4 0x15F0 +#define GUI_SCRATCH_REG4 0x15F0 +#define SCRATCH_REG5 0x15F4 +#define GUI_SCRATCH_REG5 0x15F4 +#define SCRATCH_UMSK 0x0770 +#define SCRATCH_ADDR 0x0774 +#define DP_BRUSH_FRGD_CLR 0x147C +#define DP_BRUSH_BKGD_CLR 0x1478 +#define DST_LINE_START 0x1600 +#define DST_LINE_END 0x1604 +#define SRC_OFFSET 0x15AC +#define SRC_PITCH 0x15B0 +#define SRC_TILE 0x1704 +#define SRC_PITCH_OFFSET 0x1428 +#define SRC_X 0x1414 +#define SRC_Y 0x1418 +#define SRC_X_Y 0x1590 +#define SRC_Y_X 0x1434 +#define SRC_CLUT_ADDRESS 0x1780 +#define SRC_CLUT_DATA 0x1784 +#define SRC_CLUT_DATA_RD 0x1788 +#define HOST_DATA0 0x17C0 +#define HOST_DATA1 0x17C4 +#define HOST_DATA2 0x17C8 +#define HOST_DATA3 0x17CC +#define HOST_DATA4 0x17D0 +#define HOST_DATA5 0x17D4 +#define HOST_DATA6 0x17D8 +#define HOST_DATA7 0x17DC +#define HOST_DATA_LAST 0x17E0 +#define DP_SRC_ENDIAN 0x15D4 +#define DP_SRC_FRGD_CLR 0x15D8 +#define DP_SRC_BKGD_CLR 0x15DC +#define SC_LEFT 0x1640 +#define SC_RIGHT 0x1644 +#define SC_TOP 0x1648 +#define SC_BOTTOM 0x164C +#define SRC_SC_RIGHT 0x1654 +#define SRC_SC_BOTTOM 0x165C +#define DP_CNTL 0x16C0 +#define DP_CNTL_XDIR_YDIR_YMAJOR 0x16D0 +#define DP_DATATYPE 0x16C4 +#define DP_MIX 0x16C8 +#define DP_WRITE_MSK 0x16CC +#define DP_XOP 0x17F8 +#define CLR_CMP_CLR_SRC 0x15C4 +#define CLR_CMP_CLR_DST 0x15C8 +#define CLR_CMP_CNTL 0x15C0 +#define CLR_CMP_MSK 0x15CC +#define DSTCACHE_MODE 0x1710 +#define DSTCACHE_CTLSTAT 0x1714 +#define DEFAULT_PITCH_OFFSET 0x16E0 +#define DEFAULT_SC_BOTTOM_RIGHT 0x16E8 +#define DP_GUI_MASTER_CNTL 0x146C +#define SC_TOP_LEFT 0x16EC +#define SC_BOTTOM_RIGHT 0x16F0 +#define SRC_SC_BOTTOM_RIGHT 0x16F4 +#define RB2D_DSTCACHE_CTLSTAT 0x342C + + +#define CLK_PIN_CNTL 0x0001 +#define PPLL_CNTL 0x0002 +#define PPLL_REF_DIV 0x0003 +#define PPLL_DIV_0 0x0004 +#define PPLL_DIV_1 0x0005 +#define PPLL_DIV_2 0x0006 +#define PPLL_DIV_3 0x0007 +#define VCLK_ECP_CNTL 0x0008 +#define HTOTAL_CNTL 0x0009 +#define M_SPLL_REF_FB_DIV 0x000a +#define AGP_PLL_CNTL 0x000b +#define SPLL_CNTL 0x000c +#define SCLK_CNTL 0x000d +#define MPLL_CNTL 0x000e +#define MCLK_CNTL 0x0012 +#define AGP_PLL_CNTL 0x000b +#define PLL_TEST_CNTL 0x0013 + + +/* BUS_CNTL bit constants */ +#define BUS_DBL_RESYNC 0x00000001 +#define BUS_MSTR_RESET 0x00000002 +#define BUS_FLUSH_BUF 0x00000004 +#define BUS_STOP_REQ_DIS 0x00000008 +#define BUS_ROTATION_DIS 0x00000010 +#define BUS_MASTER_DIS 0x00000040 +#define BUS_ROM_WRT_EN 0x00000080 +#define BUS_DIS_ROM 0x00001000 +#define BUS_PCI_READ_RETRY_EN 0x00002000 +#define BUS_AGP_AD_STEPPING_EN 0x00004000 +#define BUS_PCI_WRT_RETRY_EN 0x00008000 +#define BUS_MSTR_RD_MULT 0x00100000 +#define BUS_MSTR_RD_LINE 0x00200000 +#define BUS_SUSPEND 0x00400000 +#define LAT_16X 0x00800000 +#define BUS_RD_DISCARD_EN 0x01000000 +#define BUS_RD_ABORT_EN 0x02000000 +#define BUS_MSTR_WS 0x04000000 +#define BUS_PARKING_DIS 0x08000000 +#define BUS_MSTR_DISCONNECT_EN 0x10000000 +#define BUS_WRT_BURST 0x20000000 +#define BUS_READ_BURST 0x40000000 +#define BUS_RDY_READ_DLY 0x80000000 + + +/* CLOCK_CNTL_INDEX bit constants */ +#define PLL_WR_EN 0x00000080 + +/* CONFIG_CNTL bit constants */ +#define CFG_VGA_RAM_EN 0x00000100 + +/* CRTC_EXT_CNTL bit constants */ +#define VGA_ATI_LINEAR 0x00000008 +#define VGA_128KAP_PAGING 0x00000010 + +/* CRTC_GEN_CNTL bit constants */ +#define CRTC_DBL_SCAN_EN 0x00000001 +#define CRTC_CUR_EN 0x00010000 + +/* CRTC_STATUS bit constants */ +#define CRTC_VBLANK 0x00000001 + +/* CUR_OFFSET, CUR_HORZ_VERT_POSN, CUR_HORZ_VERT_OFF bit constants */ +#define CUR_LOCK 0x80000000 + +/* DAC_CNTL bit constants */ +#define DAC_8BIT_EN 0x00000100 +#define DAC_4BPP_PIX_ORDER 0x00000200 +#define DAC_CRC_EN 0x00080000 + +/* GEN_RESET_CNTL bit constants */ +#define SOFT_RESET_GUI 0x00000001 +#define SOFT_RESET_VCLK 0x00000100 +#define SOFT_RESET_PCLK 0x00000200 +#define SOFT_RESET_ECP 0x00000400 +#define SOFT_RESET_DISPENG_XCLK 0x00000800 + +/* MEM_CNTL bit constants */ +#define MEM_CTLR_STATUS_IDLE 0x00000000 +#define MEM_CTLR_STATUS_BUSY 0x00100000 +#define MEM_SEQNCR_STATUS_IDLE 0x00000000 +#define MEM_SEQNCR_STATUS_BUSY 0x00200000 +#define MEM_ARBITER_STATUS_IDLE 0x00000000 +#define MEM_ARBITER_STATUS_BUSY 0x00400000 +#define MEM_REQ_UNLOCK 0x00000000 +#define MEM_REQ_LOCK 0x00800000 + +/* MM_INDEX bit constants */ +#define MM_APER 0x80000000 + +/* CLR_CMP_CNTL bit constants */ +#define COMPARE_SRC_FALSE 0x00000000 +#define COMPARE_SRC_TRUE 0x00000001 +#define COMPARE_SRC_NOT_EQUAL 0x00000004 +#define COMPARE_SRC_EQUAL 0x00000005 +#define COMPARE_SRC_EQUAL_FLIP 0x00000007 +#define COMPARE_DST_FALSE 0x00000000 +#define COMPARE_DST_TRUE 0x00000100 +#define COMPARE_DST_NOT_EQUAL 0x00000400 +#define COMPARE_DST_EQUAL 0x00000500 +#define COMPARE_DESTINATION 0x00000000 +#define COMPARE_SOURCE 0x01000000 +#define COMPARE_SRC_AND_DST 0x02000000 + + +/* DP_CNTL bit constants */ +#define DST_X_RIGHT_TO_LEFT 0x00000000 +#define DST_X_LEFT_TO_RIGHT 0x00000001 +#define DST_Y_BOTTOM_TO_TOP 0x00000000 +#define DST_Y_TOP_TO_BOTTOM 0x00000002 +#define DST_X_MAJOR 0x00000000 +#define DST_Y_MAJOR 0x00000004 +#define DST_X_TILE 0x00000008 +#define DST_Y_TILE 0x00000010 +#define DST_LAST_PEL 0x00000020 +#define DST_TRAIL_X_RIGHT_TO_LEFT 0x00000000 +#define DST_TRAIL_X_LEFT_TO_RIGHT 0x00000040 +#define DST_TRAP_FILL_RIGHT_TO_LEFT 0x00000000 +#define DST_TRAP_FILL_LEFT_TO_RIGHT 0x00000080 +#define DST_BRES_SIGN 0x00000100 +#define DST_HOST_BIG_ENDIAN_EN 0x00000200 +#define DST_POLYLINE_NONLAST 0x00008000 +#define DST_RASTER_STALL 0x00010000 +#define DST_POLY_EDGE 0x00040000 + + +/* DP_CNTL_YDIR_XDIR_YMAJOR bit constants (short version of DP_CNTL) */ +#define DST_X_MAJOR_S 0x00000000 +#define DST_Y_MAJOR_S 0x00000001 +#define DST_Y_BOTTOM_TO_TOP_S 0x00000000 +#define DST_Y_TOP_TO_BOTTOM_S 0x00008000 +#define DST_X_RIGHT_TO_LEFT_S 0x00000000 +#define DST_X_LEFT_TO_RIGHT_S 0x80000000 + + +/* DP_DATATYPE bit constants */ +#define DST_8BPP 0x00000002 +#define DST_15BPP 0x00000003 +#define DST_16BPP 0x00000004 +#define DST_24BPP 0x00000005 +#define DST_32BPP 0x00000006 +#define DST_8BPP_RGB332 0x00000007 +#define DST_8BPP_Y8 0x00000008 +#define DST_8BPP_RGB8 0x00000009 +#define DST_16BPP_VYUY422 0x0000000b +#define DST_16BPP_YVYU422 0x0000000c +#define DST_32BPP_AYUV444 0x0000000e +#define DST_16BPP_ARGB4444 0x0000000f +#define BRUSH_SOLIDCOLOR 0x00000d00 +#define SRC_MONO 0x00000000 +#define SRC_MONO_LBKGD 0x00010000 +#define SRC_DSTCOLOR 0x00030000 +#define BYTE_ORDER_MSB_TO_LSB 0x00000000 +#define BYTE_ORDER_LSB_TO_MSB 0x40000000 +#define DP_CONVERSION_TEMP 0x80000000 + + + +/* DP_GUI_MASTER_CNTL bit constants */ +#define GMC_SRC_PITCH_OFFSET_DEFAULT 0x00000000 +#define GMC_SRC_PITCH_OFFSET_LEAVE 0x00000001 +#define GMC_DST_PITCH_OFFSET_DEFAULT 0x00000000 +#define GMC_DST_PITCH_OFFSET_LEAVE 0x00000002 +#define GMC_SRC_CLIP_DEFAULT 0x00000000 +#define GMC_SRC_CLIP_LEAVE 0x00000004 +#define GMC_DST_CLIP_DEFAULT 0x00000000 +#define GMC_DST_CLIP_LEAVE 0x00000008 +#define GMC_BRUSH_8x8MONO 0x00000000 +#define GMC_BRUSH_8x8MONO_LBKGD 0x00000010 +#define GMC_BRUSH_8x1MONO 0x00000020 +#define GMC_BRUSH_8x1MONO_LBKGD 0x00000030 +#define GMC_BRUSH_1x8MONO 0x00000040 +#define GMC_BRUSH_1x8MONO_LBKGD 0x00000050 +#define GMC_BRUSH_32x1MONO 0x00000060 +#define GMC_BRUSH_32x1MONO_LBKGD 0x00000070 +#define GMC_BRUSH_32x32MONO 0x00000080 +#define GMC_BRUSH_32x32MONO_LBKGD 0x00000090 +#define GMC_BRUSH_8x8COLOR 0x000000a0 +#define GMC_BRUSH_8x1COLOR 0x000000b0 +#define GMC_BRUSH_1x8COLOR 0x000000c0 +#define GMC_BRUSH_SOLIDCOLOR 0x000000d0 +#define GMC_DST_8BPP 0x00000200 +#define GMC_DST_15BPP 0x00000300 +#define GMC_DST_16BPP 0x00000400 +#define GMC_DST_24BPP 0x00000500 +#define GMC_DST_32BPP 0x00000600 +#define GMC_DST_8BPP_RGB332 0x00000700 +#define GMC_DST_8BPP_Y8 0x00000800 +#define GMC_DST_8BPP_RGB8 0x00000900 +#define GMC_DST_16BPP_VYUY422 0x00000b00 +#define GMC_DST_16BPP_YVYU422 0x00000c00 +#define GMC_DST_32BPP_AYUV444 0x00000e00 +#define GMC_DST_16BPP_ARGB4444 0x00000f00 +#define GMC_SRC_MONO 0x00000000 +#define GMC_SRC_MONO_LBKGD 0x00001000 +#define GMC_SRC_DSTCOLOR 0x00003000 +#define GMC_BYTE_ORDER_MSB_TO_LSB 0x00000000 +#define GMC_BYTE_ORDER_LSB_TO_MSB 0x00004000 +#define GMC_DP_CONVERSION_TEMP_9300 0x00008000 +#define GMC_DP_CONVERSION_TEMP_6500 0x00000000 +#define GMC_DP_SRC_RECT 0x02000000 +#define GMC_DP_SRC_HOST 0x03000000 +#define GMC_DP_SRC_HOST_BYTEALIGN 0x04000000 +#define GMC_3D_FCN_EN_CLR 0x00000000 +#define GMC_3D_FCN_EN_SET 0x08000000 +#define GMC_DST_CLR_CMP_FCN_LEAVE 0x00000000 +#define GMC_DST_CLR_CMP_FCN_CLEAR 0x10000000 +#define GMC_AUX_CLIP_LEAVE 0x00000000 +#define GMC_AUX_CLIP_CLEAR 0x20000000 +#define GMC_WRITE_MASK_LEAVE 0x00000000 +#define GMC_WRITE_MASK_SET 0x40000000 + +/* DP_MIX bit constants */ +#define DP_SRC_RECT 0x00000200 +#define DP_SRC_HOST 0x00000300 +#define DP_SRC_HOST_BYTEALIGN 0x00000400 + +#define ROP3_PATCOPY 0x00f00000 + +/* masks */ + +#define CONFIG_MEMSIZE_MASK 0x1f000000 +#define MEM_CFG_TYPE 0x40000000 +#define DST_OFFSET_MASK 0x003fffff +#define DST_PITCH_MASK 0x3fc00000 +#define DEFAULT_TILE_MASK 0xc0000000 +#define PPLL_DIV_SEL_MASK 0x00000300 +#define PPLL_RESET 0x00000001 +#define PPLL_ATOMIC_UPDATE_EN 0x00010000 +#define PPLL_REF_DIV_MASK 0x000003ff +#define PPLL_FB3_DIV_MASK 0x000007ff +#define PPLL_POST3_DIV_MASK 0x00070000 +#define PPLL_ATOMIC_UPDATE_R 0x00008000 +#define PPLL_ATOMIC_UPDATE_W 0x00008000 +#define PPLL_VGA_ATOMIC_UPDATE_EN 0x00020000 + +#define GUI_ACTIVE 0x80000000 + +#endif /* _RADEON_H */ + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/radeonfb.c linux.ac/drivers/video/radeonfb.c --- linux.vanilla/drivers/video/radeonfb.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/radeonfb.c Tue Apr 3 17:55:09 2001 @@ -0,0 +1,1628 @@ +/* + * drivers/video/radeonfb.c + * framebuffer driver for ATI Radeon chipset video boards + * + * Copyright 2000 Ani Joshi <ajoshi@unixbox.com> + * + * + * ChangeLog: + * 2000-08-03 initial version 0.0.1 + * 2000-09-10 more bug fixes, public release 0.0.5 + * 2001-02-19 mode bug fixes, 0.0.7 + * + * + * Special thanks to ATI DevRel team for their hardware donations. + * + */ + + +#define RADEON_VERSION "0.0.8" + + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/malloc.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/console.h> +#include <linux/selection.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/pci.h> + +#include <asm/io.h> + +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb24.h> +#include <video/fbcon-cfb32.h> + +#include "radeon.h" + + +#define DEBUG 0 + +#if DEBUG +#define RTRACE printk +#else +#define RTRACE if(0) printk +#endif + + + +enum radeon_chips { + RADEON_QD, + RADEON_QE, + RADEON_QF, + RADEON_QG +}; + + +static struct pci_device_id radeonfb_pci_table[] __devinitdata = { + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_QD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QD}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_QE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QE}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_QF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QF}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_QG, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QG}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, radeonfb_pci_table); + + +typedef struct { + u16 reg; + u32 val; +} reg_val; + + +/* these common regs are cleared before mode setting so they do not + * interfere with anything + */ +reg_val common_regs[] = { + { OVR_CLR, 0 }, + { OVR_WID_LEFT_RIGHT, 0 }, + { OVR_WID_TOP_BOTTOM, 0 }, + { OV0_SCALE_CNTL, 0 }, + { SUBPIC_CNTL, 0 }, + { VIPH_CONTROL, 0 }, + { I2C_CNTL_1, 0 }, + { GEN_INT_CNTL, 0 }, + { CAP0_TRIG_CNTL, 0 }, +}; + +#define COMMON_REGS_SIZE = (sizeof(common_regs)/sizeof(common_regs[0])) + +struct radeon_regs { + u32 crtc_h_total_disp; + u32 crtc_h_sync_strt_wid; + u32 crtc_v_total_disp; + u32 crtc_v_sync_strt_wid; + u32 flags; + u32 pix_clock; + u32 pitch; + int xres, yres; + int bpp; + u32 crtc_gen_cntl; + u32 crtc_ext_cntl; + u32 dac_cntl; + u32 dda_config; + u32 dda_on_off; +}; + + +struct radeonfb_info { + struct fb_info info; + + struct radeon_regs state; + struct radeon_regs init_state; + + char name[9]; + char ram_type[12]; + + u32 mmio_base_phys; + u32 fb_base_phys; + + u32 mmio_base; + u32 fb_base; + + struct pci_dev *pdev; + + struct display disp; + int currcon; + struct display *currcon_display; + + struct { u8 red, green, blue, pad; } palette[256]; + + int chipset; + int video_ram; + u8 rev; + int pitch, depth; + int xres, yres, pixclock; + + u32 ppll_ref_div, ppll_div_3; + int pll_output_freq, post_div, fb_div; + + int ml, mb, trcd, trp, twr, cl, tr2w, loop_latency, rloop; + +#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32) + union { +#if defined(FBCON_HAS_CFB16) + u_int16_t cfb16[16]; +#endif +#if defined(FBCON_HAS_CFB32) + u_int32_t cfb32[16]; +#endif + } con_cmap; +#endif +}; + + +static struct fb_var_screeninfo radeonfb_default_var = { + 640, 480, 640, 480, 0, 0, 8, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 39721, 40, 24, 32, 11, 96, 2, + 0, FB_VMODE_NONINTERLACED +}; + + +/* + * IO macros + */ + +#define INREG8(addr) readb((rinfo->mmio_base)+addr) +#define OUTREG8(addr,val) writeb(val, (rinfo->mmio_base)+addr) +#define INREG(addr) readl((rinfo->mmio_base)+addr) +#define OUTREG(addr,val) writel(val, (rinfo->mmio_base)+addr) + +#define OUTPLL(addr,val) OUTREG8(CLOCK_CNTL_INDEX, (addr & 0x0000001f) | 0x00000080); \ + OUTREG(CLOCK_CNTL_DATA, val); + +static __inline__ u32 _INPLL(struct radeonfb_info *rinfo, u32 addr) +{ + OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000001f); + return (INREG(CLOCK_CNTL_DATA)); +} + +#define INPLL(addr) _INPLL(rinfo, addr) + + +/* + * 2D engine routines + */ + +static __inline__ void radeon_engine_flush (struct radeonfb_info *rinfo) +{ + u16 tmp; + + /* initiate flush */ + OUTREG(RB2D_DSTCACHE_CTLSTAT, INREG(RB2D_DSTCACHE_CTLSTAT) | 0xf); + + tmp = 0; + while (((INREG(RB2D_DSTCACHE_CTLSTAT) & 0x80000000) == 0x80000000) + && (tmp < 16384)) + tmp++; +} + + +static __inline__ void _radeon_fifo_wait (struct radeonfb_info *rinfo, int entries) +{ + int i; + + for (i=0; i<2000000; i++) + if ((INREG(RBBM_STATUS) & 0x7f) >= entries) + return; +} + + +static __inline__ void _radeon_engine_idle (struct radeonfb_info *rinfo) +{ + int i; + + /* ensure FIFO is empty before waiting for idle */ + _radeon_fifo_wait (rinfo, 64); + + for (i=0; i<2000000; i++) { + if (((INREG(RBBM_STATUS) & GUI_ACTIVE)) == 0) { + radeon_engine_flush (rinfo); + return; + } + } +} + + +#define radeon_engine_idle() _radeon_engine_idle(rinfo) +#define radeon_fifo_wait(entries) _radeon_fifo_wait(rinfo,entries) + + + +/* + * helper routines + */ + +static __inline__ u32 radeon_get_dstbpp(u16 bpp) +{ + switch (bpp) { + case 8: + return DST_8BPP; + case 15: + return DST_15BPP; + case 16: + return DST_16BPP; + case 32: + return DST_32BPP; + default: + return 0; + } +} + + +static void _radeon_engine_reset(struct radeonfb_info *rinfo) +{ + u32 save_genresetcntl, save_clockcntlindex, save_mclkcntl; + + radeon_engine_flush (rinfo); + + save_clockcntlindex = INREG(CLOCK_CNTL_INDEX); + save_mclkcntl = INPLL(MCLK_CNTL); + + OUTPLL(MCLK_CNTL, save_mclkcntl | 0x000f0000); + + save_genresetcntl = INREG(RBBM_SOFT_RESET); + + OUTREG(DISP_MISC_CNTL, save_genresetcntl | 0x00000001); + INREG(DISP_MISC_CNTL); + + OUTREG(DISP_MISC_CNTL, save_genresetcntl & ~(0x00000001)); + INREG(DISP_MISC_CNTL); + + OUTPLL(MCLK_CNTL, save_mclkcntl); + + OUTREG(CLOCK_CNTL_INDEX, save_clockcntlindex); + OUTREG(DISP_MISC_CNTL, save_genresetcntl); + + return; +} + +#define radeon_engine_reset() _radeon_engine_reset(rinfo) + + +static __inline__ int radeon_pll_read_update_complete(struct radeonfb_info *rinfo) +{ + u32 tmp; + + tmp = INPLL(PPLL_REF_DIV); + + if (PPLL_ATOMIC_UPDATE_R & tmp) + return 0; + else + return 1; +} + + +static __inline__ void radeon_pll_write_update(struct radeonfb_info *rinfo) +{ + u32 tmp; + + while (radeon_pll_read_update_complete(rinfo) == 0); + + tmp = INPLL(PPLL_REF_DIV); + tmp &= ~PPLL_ATOMIC_UPDATE_W; + tmp |= PPLL_ATOMIC_UPDATE_W; + + OUTPLL(PPLL_REF_DIV, tmp); +} + + +static __inline__ u8 radeon_get_post_div_bitval(int post_div) +{ + switch (post_div) { + case 1: + return 0x00; + case 2: + return 0x01; + case 3: + return 0x04; + case 4: + return 0x02; + case 6: + return 0x06; + case 8: + return 0x03; + case 12: + return 0x07; + default: + return 0x02; + } +} + + + +static __inline__ int round_div(int num, int den) +{ + return (num + (den / 2)) / den; +} + + + +static __inline__ int min_bits_req(int val) +{ + int bits_req = 0; + + if (val == 0) + bits_req = 1; + + while (val) { + val >>= 1; + bits_req++; + } + + return (bits_req); +} + + +static __inline__ int _max(int val1, int val2) +{ + if (val1 >= val2) + return val1; + else + return val2; +} + + + +/* + * globals + */ + +static char fontname[40] __initdata; +static char *mode_option __initdata; + + +/* + * prototypes + */ + +static int radeonfb_get_fix (struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); +static int radeonfb_get_var (struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int radeonfb_set_var (struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int radeonfb_get_cmap (struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int radeonfb_set_cmap (struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int radeonfb_pan_display (struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int radeonfb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, int con, struct fb_info *info); +static int radeonfb_switch (int con, struct fb_info *info); +static int radeonfb_updatevar (int con, struct fb_info *info); +static void radeonfb_blank (int blank, struct fb_info *info); +static int radeon_get_cmap_len (const struct fb_var_screeninfo *var); +static int radeon_getcolreg (unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, + struct fb_info *info); +static int radeon_setcolreg (unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info); +static void radeon_set_dispsw (struct radeonfb_info *rinfo); +static void radeon_save_state (struct radeonfb_info *rinfo, + struct radeon_regs *save); +static void radeon_engine_init (struct radeonfb_info *rinfo); +static void radeon_load_video_mode (struct radeonfb_info *rinfo, + struct fb_var_screeninfo *mode); +static void radeon_write_mode (struct radeonfb_info *rinfo, + struct radeon_regs *mode); +static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo); +static int __devinit radeon_init_disp (struct radeonfb_info *rinfo); +static int radeon_init_disp_var (struct radeonfb_info *rinfo); +static int radeonfb_pci_register (struct pci_dev *pdev, + const struct pci_device_id *ent); +static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev); + + +static struct fb_ops radeon_fb_ops = { + fb_get_fix: radeonfb_get_fix, + fb_get_var: radeonfb_get_var, + fb_set_var: radeonfb_set_var, + fb_get_cmap: radeonfb_get_cmap, + fb_set_cmap: radeonfb_set_cmap, + fb_pan_display: radeonfb_pan_display, + fb_ioctl: radeonfb_ioctl, +}; + + +static struct pci_driver radeonfb_driver = { + name: "radeonfb", + id_table: radeonfb_pci_table, + probe: radeonfb_pci_register, + remove: radeonfb_pci_unregister, +}; + + +int __init radeonfb_init (void) +{ + return pci_module_init (&radeonfb_driver); +} + + +void __exit radeonfb_exit (void) +{ + pci_unregister_driver (&radeonfb_driver); +} + + +int __init radeonfb_setup (char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + for (this_opt = strtok (options, ","); this_opt; + this_opt = strtok (NULL, ",")) { + if (!strncmp (this_opt, "font:", 5)) { + char *p; + int i; + + p = this_opt + 5; + for (i=0; i<sizeof (fontname) - 1; i++) + if (!*p || *p == ' ' || *p == ',') + break; + memcpy(fontname, this_opt + 5, i); + } + else mode_option = this_opt; + } + + return 0; +} + +#ifdef MODULE +module_init(radeonfb_init); +module_exit(radeonfb_exit); +#endif + + +MODULE_AUTHOR("Ani Joshi"); +MODULE_DESCRIPTION("framebuffer driver for ATI Radeon chipset"); + + + +static int radeonfb_pci_register (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct radeonfb_info *rinfo; + u32 tmp; + int i, j; + + rinfo = kmalloc (sizeof (struct radeonfb_info), GFP_KERNEL); + if (!rinfo) { + printk ("radeonfb: could not allocate memory\n"); + return -ENODEV; + } + + memset (rinfo, 0, sizeof (struct radeonfb_info)); + + /* set base addrs */ + rinfo->fb_base_phys = pci_resource_start (pdev, 0); + rinfo->mmio_base_phys = pci_resource_start (pdev, 2); + +#if 0 + /* request the mem regions */ + if (!request_mem_region (rinfo->fb_base_phys, + rinfo->video_ram, "radeonfb")) { + printk ("radeonfb: cannot reserve FB region\n"); + kfree (rinfo); + return -ENODEV; + } + + if (!request_mem_region (rinfo->mmio_base_phys, + RADEON_REGSIZE, "radeonfb")) { + printk ("radeonfb: cannot reserve MMIO region\n"); + release_mem_region (rinfo->fb_base_phys, rinfo->video_ram); + kfree (rinfo); + return -ENODEV; + } +#endif + + /* map the regions */ + rinfo->mmio_base = (unsigned long) ioremap (rinfo->mmio_base_phys, + RADEON_REGSIZE); + if (!rinfo->mmio_base) { + printk ("radeonfb: cannot map MMIO\n"); + release_mem_region (rinfo->mmio_base_phys, RADEON_REGSIZE); + release_mem_region (rinfo->fb_base_phys, rinfo->video_ram); + kfree (rinfo); + return -ENODEV; + } + + /* chipset */ + switch (pdev->device) { + case PCI_DEVICE_ID_RADEON_QD: + strcpy(rinfo->name, "Radeon QD "); + break; + case PCI_DEVICE_ID_RADEON_QE: + strcpy(rinfo->name, "Radeon QE "); + break; + case PCI_DEVICE_ID_RADEON_QF: + strcpy(rinfo->name, "Radeon QF "); + break; + case PCI_DEVICE_ID_RADEON_QG: + strcpy(rinfo->name, "Radeon QG "); + break; + default: + return -ENODEV; + } + + /* framebuffer size */ + tmp = INREG(CONFIG_MEMSIZE); + + /* mem size is bits [28:0], mask off the rest */ + rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK; + + /* ram type */ + tmp = INREG(MEM_SDRAM_MODE_REG); + switch ((MEM_CFG_TYPE & tmp) >> 30) { + case 0: + /* SDR SGRAM (2:1) */ + strcpy(rinfo->ram_type, "SDR SGRAM"); + rinfo->ml = 4; + rinfo->mb = 4; + rinfo->trcd = 1; + rinfo->trp = 2; + rinfo->twr = 1; + rinfo->cl = 2; + rinfo->loop_latency = 16; + rinfo->rloop = 16; + + break; + case 1: + /* DDR SGRAM */ + strcpy(rinfo->ram_type, "DDR SGRAM"); + rinfo->ml = 4; + rinfo->mb = 4; + rinfo->trcd = 3; + rinfo->trp = 3; + rinfo->twr = 2; + rinfo->cl = 3; + rinfo->tr2w = 1; + rinfo->loop_latency = 16; + rinfo->rloop = 16; + + break; + default: + /* 64-bit SDR SGRAM */ + strcpy(rinfo->ram_type, "SDR SGRAM 64"); + rinfo->ml = 4; + rinfo->mb = 8; + rinfo->trcd = 3; + rinfo->trp = 3; + rinfo->twr = 1; + rinfo->cl = 3; + rinfo->tr2w = 1; + rinfo->loop_latency = 17; + rinfo->rloop = 17; + + break; + } + + RTRACE("radeonfb: probed %s %dk videoram\n", (rinfo->ram_type), (rinfo->video_ram/1024)); + + + rinfo->fb_base = (unsigned long) ioremap (rinfo->fb_base_phys, + rinfo->video_ram); + if (!rinfo->fb_base) { + printk ("radeonfb: cannot map FB\n"); + iounmap ((void*)rinfo->mmio_base); + release_mem_region (rinfo->mmio_base_phys, RADEON_REGSIZE); + release_mem_region (rinfo->fb_base_phys, rinfo->video_ram); + kfree (rinfo); + return -ENODEV; + } + + + /* set all the vital stuff */ + radeon_set_fbinfo (rinfo); + + /* save current mode regs before we switch into the new one + * so we can restore this upon __exit + */ + radeon_save_state (rinfo, &rinfo->init_state); + + /* init palette */ + for (i=0; i<16; i++) { + j = color_table[i]; + rinfo->palette[i].red = default_red[j]; + rinfo->palette[i].green = default_grn[j]; + rinfo->palette[i].blue = default_blu[j]; + } + +#if 0 + /* initialize the engine */ + radeon_engine_init (rinfo); +#endif + + pdev->driver_data = rinfo; + + if (register_framebuffer ((struct fb_info *) rinfo) < 0) { + printk ("radeonfb: could not register framebuffer\n"); + iounmap ((void*)rinfo->fb_base); + iounmap ((void*)rinfo->mmio_base); + release_mem_region (rinfo->mmio_base_phys, RADEON_REGSIZE); + release_mem_region (rinfo->fb_base_phys, rinfo->video_ram); + kfree (rinfo); + return -ENODEV; + } + + printk ("radeonfb: ATI Radeon %s %d MB\n", rinfo->ram_type, + (rinfo->video_ram/(1024*1024))); + + return 0; +} + + + +static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev) +{ + struct radeonfb_info *rinfo = pdev->driver_data; + + if (!rinfo) + return; + + /* restore original state */ + radeon_write_mode (rinfo, &rinfo->init_state); + + unregister_framebuffer ((struct fb_info *) rinfo); + + iounmap ((void*)rinfo->mmio_base); + iounmap ((void*)rinfo->fb_base); + + release_mem_region (rinfo->mmio_base_phys, RADEON_REGSIZE); + release_mem_region (rinfo->fb_base_phys, rinfo->video_ram); + + kfree (rinfo); +} + + + +static void radeon_engine_init (struct radeonfb_info *rinfo) +{ + u32 tmp; + int bpp; + + /* disable 3D engine */ + OUTREG(RB3D_CNTL, 0); + + radeon_engine_reset (); + + radeon_fifo_wait (1); + + /* setup engine pitch regs */ + tmp = INREG(DEFAULT_PITCH_OFFSET); + OUTREG(DEFAULT_PITCH_OFFSET, (tmp & DEFAULT_TILE_MASK) | + (rinfo->state.pitch << 0x16)); + + bpp = rinfo->depth; + if (rinfo->depth == 15) + bpp = 16; + + tmp = INREG(CRTC_PITCH) & 0x800; + tmp = tmp | (((rinfo->state.xres * rinfo->state.bpp + 0x3f) & + ~(0x3f)) / bpp); + OUTREG(CRTC_PITCH, tmp); + + /* set scissors to max size */ + radeon_fifo_wait (1); + OUTREG(DEFAULT_SC_BOTTOM_RIGHT, (0x1fff << 0x10) | 0x1fff); + + /* set drawing control regs */ + radeon_fifo_wait (1); + tmp = radeon_get_dstbpp(rinfo->depth); + + OUTREG(DP_GUI_MASTER_CNTL, GMC_SRC_PITCH_OFFSET_DEFAULT | + GMC_DST_PITCH_OFFSET_DEFAULT | + GMC_SRC_CLIP_DEFAULT | + GMC_DST_CLIP_DEFAULT | + GMC_BRUSH_SOLIDCOLOR | + (tmp << 0x8) | + GMC_SRC_DSTCOLOR | + GMC_BYTE_ORDER_MSB_TO_LSB | + GMC_DP_CONVERSION_TEMP_6500 | + ROP3_PATCOPY | + GMC_DP_SRC_RECT | + GMC_DST_CLR_CMP_FCN_CLEAR | + GMC_WRITE_MASK_SET); + + radeon_fifo_wait (7); + + /* clear line drawing regs */ + OUTREG(DST_LINE_START, 0); + OUTREG(DST_LINE_END, 0); + + /* set brush color regs */ + OUTREG(DP_BRUSH_FRGD_CLR, 0xffffffff); + OUTREG(DP_BRUSH_BKGD_CLR, 0x00000000); + + /* set source color regs */ + OUTREG(DP_SRC_FRGD_CLR, 0xffffffff); + OUTREG(DP_SRC_BKGD_CLR, 0x00000000); + + /* default write mask */ + OUTREG(DP_WRITE_MSK, 0xffffffff); + +/* radeon_engine_idle (); */ +} + + + +static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo) +{ + struct fb_info *info; + + info = &rinfo->info; + + strcpy (info->modename, rinfo->name); + info->node = -1; + info->flags = FBINFO_FLAG_DEFAULT; + info->fbops = &radeon_fb_ops; + info->display_fg = NULL; + strncpy (info->fontname, fontname, sizeof (info->fontname)); + info->fontname[sizeof (info->fontname) - 1] = 0; + info->changevar = NULL; + info->switch_con = radeonfb_switch; + info->updatevar = radeonfb_updatevar; + info->blank = radeonfb_blank; + + if (radeon_init_disp (rinfo) < 0) + return -1; + + return 0; +} + + + +static int __devinit radeon_init_disp (struct radeonfb_info *rinfo) +{ + struct fb_info *info; + struct display *disp; + + info = &rinfo->info; + disp = &rinfo->disp; + + disp->var = radeonfb_default_var; + info->disp = disp; + + disp->screen_base = (char *)rinfo->fb_base; + disp->visual = FB_VISUAL_PSEUDOCOLOR; + disp->type = FB_TYPE_PACKED_PIXELS; + disp->type_aux = 0; + disp->ypanstep = 1; + disp->ywrapstep = 0; + disp->next_line = disp->line_length = + (disp->var.xres_virtual * disp->var.bits_per_pixel) >> 3; + disp->can_soft_blank = 1; + disp->inverse = 0; + + radeon_set_dispsw (rinfo); + + disp->scrollmode = 0; + + rinfo->currcon_display = disp; + + if ((radeon_init_disp_var (rinfo)) < 0) + return -1; + + return 0; +} + + + +static int radeon_init_disp_var (struct radeonfb_info *rinfo) +{ +#ifndef MODULE + if (mode_option) + fb_find_mode (&rinfo->disp.var, &rinfo->info, mode_option, + NULL, 0, NULL, 8); + else +#endif + fb_find_mode (&rinfo->disp.var, &rinfo->info, "640x480-8@60", + NULL, 0, NULL, 0); + + return 0; +} + + + +static void radeon_set_dispsw (struct radeonfb_info *rinfo) +{ + struct display *disp = &rinfo->disp; + + disp->dispsw_data = NULL; + + rinfo->depth = disp->var.bits_per_pixel; + switch (disp->var.bits_per_pixel) { +#ifdef FBCON_HAS_CFB8 + case 8: + disp->dispsw = &fbcon_cfb8; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + disp->dispsw = &fbcon_cfb16; + disp->dispsw_data = &rinfo->con_cmap.cfb16; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + disp->dispsw = &fbcon_cfb32; + disp->dispsw_data = &rinfo->con_cmap.cfb32; + break; +#endif + default: + printk ("radeonfb: setting fbcon_dummy renderer\n"); + disp->dispsw = &fbcon_dummy; + } + + return; +} + + + +/* + * fb ops + */ + +static int radeonfb_get_fix (struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + struct radeonfb_info *rinfo = (struct radeonfb_info *) info; + struct display *disp; + + disp = (con < 0) ? rinfo->info.disp : &fb_display[con]; + + memset (fix, 0, sizeof (struct fb_fix_screeninfo)); + strcpy (fix->id, rinfo->name); + + fix->smem_start = rinfo->fb_base_phys; + fix->smem_len = rinfo->video_ram; + + fix->type = disp->type; + fix->type_aux = disp->type_aux; + fix->visual = disp->visual; + + fix->xpanstep = 1; + fix->ypanstep = 1; + fix->ywrapstep = 0; + + fix->line_length = disp->line_length; + + fix->mmio_start = rinfo->mmio_base_phys; + fix->mmio_len = RADEON_REGSIZE; + fix->accel = FB_ACCEL_NONE; + + return 0; +} + + + +static int radeonfb_get_var (struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct radeonfb_info *rinfo = (struct radeonfb_info *) info; + + *var = (con < 0) ? rinfo->disp.var : fb_display[con].var; + + return 0; +} + + + +static int radeonfb_set_var (struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct radeonfb_info *rinfo = (struct radeonfb_info *) info; + struct display *disp; + struct fb_var_screeninfo v; + int nom, den, i; + unsigned chgvar = 0; + static struct { + int xres, yres; + } modes[] = { + { + 1600, 1280}, { + 1280, 1024}, { + 1024, 768}, { + 800, 600}, { + 640, 480}, { + -1, -1} + }; + + disp = (con < 0) ? rinfo->info.disp : &fb_display[con]; + + if (con >= 0) { + chgvar = ((disp->var.xres != var->xres) || + (disp->var.yres != var->yres) || + (disp->var.xres_virtual != var->xres_virtual) || + (disp->var.yres_virtual != var->yres_virtual) || + memcmp (&disp->var.red, &var->red, sizeof (var->red)) || + memcmp (&disp->var.green, &var->green, sizeof (var->green)) || + memcmp (&disp->var.blue, &var->blue, sizeof (var->blue))); + } + + memcpy (&v, var, sizeof (v)); + + switch (v.bits_per_pixel) { +#ifdef FBCON_HAS_CFB8 + case 2 ... 8: + v.bits_per_pixel = 8; + disp->dispsw = &fbcon_cfb8; + nom = den = 1; + disp->line_length = v.xres_virtual; + disp->visual = FB_VISUAL_PSEUDOCOLOR; + v.red.offset = v.green.offset = v.blue.offset = 0; + v.red.length = v.green.length = v.blue.length = 6; + break; +#endif + +#ifdef FBCON_HAS_CFB16 + case 9 ... 16: + v.bits_per_pixel = 16; + disp->dispsw = &fbcon_cfb16; + disp->dispsw_data = &rinfo->con_cmap.cfb16; + nom = 2; + den = 1; + disp->line_length = v.xres_virtual * 2; + disp->visual = FB_VISUAL_DIRECTCOLOR; + v.red.offset = 10; + v.green.offset = 5; + v.blue.offset = 0; + v.red.length = v.green.length = v.blue.length = 5; + break; +#endif + +#ifdef FBCON_HAS_CFB32 + case 17 ... 32: + v.bits_per_pixel = 32; + disp->dispsw = &fbcon_cfb32; + disp->dispsw_data = rinfo->con_cmap.cfb32; + nom = 4; + den = 1; + disp->line_length = v.xres_virtual * 4; + disp->visual = FB_VISUAL_DIRECTCOLOR; + v.red.offset = 16; + v.green.offset = 8; + v.blue.offset = 0; + v.red.length = v.blue.length = v.green.length = 8; + break; +#endif + default: + printk ("radeonfb: mode %dx%dx%d rejected, color depth invalid\n", + var->xres, var->yres, var->bits_per_pixel); + return -EINVAL; + } + + if (v.xres * nom / den * v.yres > (rinfo->video_ram)) { + printk ("radeonfb: mode %dx%dx%d rejected, not enough video ram\n", + var->xres, var->yres, var->bits_per_pixel); + return -EINVAL; + } + + if (v.xres_virtual == -1 && v.yres_virtual == -1) { + printk ("radeonfb: using maximum available virtual resolution\n"); + for (i = 0; modes[i].xres != -1; i++) { + if (modes[i].xres * nom / den * modes[i].yres < (rinfo->video_ram/2)) + break; + } + if (modes[i].xres == -1) { + printk ("radeonfb: could not find a virtual res\n"); + return -EINVAL; + } + v.xres_virtual = modes[i].xres; + v.yres_virtual = modes[i].yres; + + printk ("radeonfb: virtual resolution set to maximum of %dx%d\n", + v.xres_virtual, v.yres_virtual); + } + + if (v.xoffset < 0) + v.xoffset = 0; + if (v.yoffset < 0) + v.yoffset = 0; + + if (v.xoffset > v.xres_virtual - v.xres) + v.xoffset = v.xres_virtual - v.xres - 1; + + if (v.yoffset > v.yres_virtual - v.yres) + v.yoffset = v.yres_virtual - v.yres - 1; + + v.red.msb_right = v.green.msb_right = v.blue.msb_right = + v.transp.offset = v.transp.length = + v.transp.msb_right = 0; + + switch (v.activate & FB_ACTIVATE_MASK) { + case FB_ACTIVATE_TEST: + return 0; + case FB_ACTIVATE_NXTOPEN: + case FB_ACTIVATE_NOW: + break; + default: + return -EINVAL; + } + + disp->type = FB_TYPE_PACKED_PIXELS; + + memcpy (&disp->var, &v, sizeof (v)); + + radeon_load_video_mode (rinfo, &v); + + if (chgvar && info && info->changevar) + info->changevar (con); + + return 0; +} + + + +static int radeonfb_get_cmap (struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + struct radeonfb_info *rinfo = (struct radeonfb_info *) info; + struct display *disp; + + disp = (con < 0) ? rinfo->info.disp : &fb_display[con]; + + if (con == rinfo->currcon) { + int rc = fb_get_cmap (cmap, kspc, radeon_getcolreg, info); + return rc; + } else if (disp->cmap.len) + fb_copy_cmap (&disp->cmap, cmap, kspc ? 0 : 2); + else + fb_copy_cmap (fb_default_cmap (radeon_get_cmap_len (&disp->var)), + cmap, kspc ? 0 : 2); + + return 0; +} + + + +static int radeonfb_set_cmap (struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + struct radeonfb_info *rinfo = (struct radeonfb_info *) info; + struct display *disp; + unsigned int cmap_len; + + disp = (con < 0) ? rinfo->info.disp : &fb_display[con]; + + cmap_len = radeon_get_cmap_len (&disp->var); + if (disp->cmap.len != cmap_len) { + int err = fb_alloc_cmap (&disp->cmap, cmap_len, 0); + if (err) + return err; + } + + if (con == rinfo->currcon) { + int rc = fb_set_cmap (cmap, kspc, radeon_setcolreg, info); + return rc; + } else + fb_copy_cmap (cmap, &disp->cmap, kspc ? 0 : 1); + + return 0; +} + + + +static int radeonfb_pan_display (struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct radeonfb_info *rinfo = (struct radeonfb_info *) info; + struct display *disp; + unsigned int base; + + disp = (con < 0) ? rinfo->info.disp : &fb_display[con]; + + if (var->xoffset > (var->xres_virtual - var->xres)) + return -EINVAL; + if (var->yoffset > (var->yres_virtual - var->yres)) + return -EINVAL; + + if (var->vmode & FB_VMODE_YWRAP) { + if (var->yoffset < 0 || + var->yoffset >= disp->var.yres_virtual || + var->xoffset ) + return -EINVAL; + } else { + if (var->xoffset + disp->var.xres > disp->var.xres_virtual || + var->yoffset + disp->var.yres > disp->var.yres_virtual) + return -EINVAL; + } + + base = var->yoffset * disp->line_length + var->xoffset; + + disp->var.xoffset = var->xoffset; + disp->var.yoffset = var->yoffset; + + if (var->vmode & FB_VMODE_YWRAP) + disp->var.vmode |= FB_VMODE_YWRAP; + else + disp->var.vmode &= ~FB_VMODE_YWRAP; + + return 0; +} + + + +static int radeonfb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, int con, struct fb_info *info) +{ + return -EINVAL; +} + + + +static int radeonfb_switch (int con, struct fb_info *info) +{ + struct radeonfb_info *rinfo = (struct radeonfb_info *) info; + struct display *disp; + struct fb_cmap *cmap; + int switchcon = 0; + + disp = (con < 0) ? rinfo->info.disp : &fb_display[con]; + + if (rinfo->currcon >= 0) { + cmap = &(rinfo->currcon_display->cmap); + if (cmap->len) + fb_get_cmap (cmap, 1, radeon_getcolreg, info); + } + + if ((disp->var.xres != rinfo->xres) || + (disp->var.yres != rinfo->yres) || + (disp->var.pixclock != rinfo->pixclock) || + (disp->var.bits_per_pixel != rinfo->depth)) + switchcon = 1; + + if (switchcon) { + rinfo->currcon = con; + rinfo->currcon_display = disp; + disp->var.activate = FB_ACTIVATE_NOW; + + radeonfb_set_var (&disp->var, con, info); + radeon_set_dispsw (rinfo); + } + + return 0; +} + + + +static int radeonfb_updatevar (int con, struct fb_info *info) +{ + int rc; + + rc = (con < 0) ? -EINVAL : radeonfb_pan_display (&fb_display[con].var, + con, info); + + return rc; +} + +static void radeonfb_blank (int blank, struct fb_info *info) +{ + struct radeonfb_info *rinfo = (struct radeonfb_info *) info; + u8 mode = 0; + + switch (blank) { + case 0: + /* unblank */ + mode = 0; + break; + case 1: + /* blank */ + mode = ((INREG8(CRTC_EXT_CNTL + 1) & 3) | 4); + break; + case 2: + case 3: + case 4: + mode = blank | 4; + break; + } + + OUTREG8(CRTC_EXT_CNTL + 1, mode); +} + + + +static int radeon_get_cmap_len (const struct fb_var_screeninfo *var) +{ + int rc = 16; /* reasonable default */ + + switch (var->bits_per_pixel) { + case 8: + rc = 256; + break; + default: + /* should not occur */ + break; + } + + return rc; +} + + + +static int radeon_getcolreg (unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, + struct fb_info *info) +{ + struct radeonfb_info *rinfo = (struct radeonfb_info *) info; + + if (regno > 255) + return 1; + + *red = (rinfo->palette[regno].red<<8) | rinfo->palette[regno].red; + *green = (rinfo->palette[regno].green<<8) | rinfo->palette[regno].green; + *blue = (rinfo->palette[regno].blue<<8) | rinfo->palette[regno].blue; + *transp = 0; + + return 0; +} + + + +static int radeon_setcolreg (unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info) +{ + struct radeonfb_info *rinfo = (struct radeonfb_info *) info; + u32 tmp; + + if (regno > 255) + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + rinfo->palette[regno].red = red; + rinfo->palette[regno].green = green; + rinfo->palette[regno].blue = blue; + + /* init gamma for hicolor */ + if ((rinfo->depth > 8) && (regno == 0)) { + int i; + u32 tmp; + + for (i=16; i<255; i++) { + tmp = (i << 16) | (i << 8) | i; + OUTREG(PALETTE_INDEX, i); + OUTREG(PALETTE_DATA, tmp); + } + } + + if (rinfo->depth == 16) + OUTREG(PALETTE_INDEX, (regno << 3)); + else + OUTREG(PALETTE_INDEX, regno); + + tmp = (red << 16) | (green << 8) | blue; + OUTREG(PALETTE_DATA, tmp); + +#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32) + if (regno < 16) { + switch (rinfo->depth) { +#ifdef FBCON_HAS_CFB16 + case 16: + rinfo->con_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | + regno; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: { + u32 i; + + i = (regno << 8) | regno; + rinfo->con_cmap.cfb32[regno] = (i << 16) | i; + break; + } +#endif + } + } +#endif + return 0; +} + + + +static void radeon_save_state (struct radeonfb_info *rinfo, + struct radeon_regs *save) +{ + save->crtc_gen_cntl = INREG(CRTC_GEN_CNTL); + save->crtc_ext_cntl = INREG(CRTC_EXT_CNTL); + save->dac_cntl = INREG(DAC_CNTL); + save->crtc_h_total_disp = INREG(CRTC_H_TOTAL_DISP); + save->crtc_h_sync_strt_wid = INREG(CRTC_H_SYNC_STRT_WID); + save->crtc_v_total_disp = INREG(CRTC_V_TOTAL_DISP); + save->crtc_v_sync_strt_wid = INREG(CRTC_V_SYNC_STRT_WID); + save->pitch = INREG(CRTC_PITCH); +} + + + +static void radeon_load_video_mode (struct radeonfb_info *rinfo, + struct fb_var_screeninfo *mode) +{ + struct radeon_regs newmode; + int hTotal, vTotal, hSyncStart, hSyncEnd, + hSyncPol, vSyncStart, vSyncEnd, vSyncPol, cSync; + u8 hsync_adj_tab[] = {0, 0x12, 9, 9, 6, 5}; + u32 tmp, dotClock = 1000000000 / mode->pixclock, + sync, h_sync_pol, v_sync_pol; + int freq = dotClock / 10; /* x 100 */ + int xclk_freq, vclk_freq, xclk_per_trans, xclk_per_trans_precise; + int useable_precision, roff, ron; + int min_bits, format = 0; + int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid; + + rinfo->xres = mode->xres; + rinfo->yres = mode->yres; + rinfo->pixclock = mode->pixclock; + + hSyncStart = mode->xres + mode->right_margin; + hSyncEnd = hSyncStart + mode->hsync_len; + hTotal = hSyncEnd + mode->left_margin; + + vSyncStart = mode->yres + mode->lower_margin; + vSyncEnd = vSyncStart + mode->vsync_len; + vTotal = vSyncEnd + mode->upper_margin; + + sync = mode->sync; + h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; + v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; + + RTRACE("hStart = %d, hEnd = %d, hTotal = %d\n", + hSyncStart, hSyncEnd, hTotal); + RTRACE("vStart = %d, vEnd = %d, vTotal = %d\n", + vSyncStart, vSyncEnd, vTotal); + + hsync_wid = (hSyncEnd - hSyncStart) / 8; + vsync_wid = vSyncEnd - vSyncStart; + if (hsync_wid == 0) + hsync_wid = 1; + else if (hsync_wid > 0x3f) /* max */ + hsync_wid = 0x3f; + vsync_wid = mode->vsync_len; + if (vsync_wid == 0) + vsync_wid = 1; + else if (vsync_wid > 0x1f) /* max */ + vsync_wid = 0x1f; + + hSyncPol = mode->sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; + vSyncPol = mode->sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; + + cSync = mode->sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0; + + switch (mode->bits_per_pixel) { + case 8: + format = 2; + bytpp = 1; + break; + case 16: + format = 4; + bytpp = 2; + break; + case 24: + format = 5; + bytpp = 3; + break; + case 32: + format = 6; + bytpp = 4; + break; + } + + hsync_fudge = hsync_adj_tab[format-1]; + hsync_start = hSyncStart - 8 + hsync_fudge; + + tmp = 0x01000000 | 0x02000000 | + (format << 8); + newmode.crtc_gen_cntl = tmp; + + tmp = INREG(CRTC_EXT_CNTL); + tmp &= (0x100 | 0x200 | 0x400); + tmp |= (0x40 | 0x8); + newmode.crtc_ext_cntl = tmp; + + tmp = INREG(DAC_CNTL); + tmp &= (0x100 | 0x3 | 0x4); + if (mode->bits_per_pixel == 8) + tmp |= 0xff000000; + else + tmp |= (0xff000000 | 0x100); + tmp |= 0x2000; + newmode.dac_cntl = tmp; + + newmode.crtc_h_total_disp = ((((hTotal / 8) - 1) & 0xffff) | + (((mode->xres / 8) - 1) << 16)); + + newmode.crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) | + (hsync_wid << 16) | (h_sync_pol << 23)); + + newmode.crtc_v_total_disp = ((vTotal - 1) & 0xffff) | + ((mode->yres - 1) << 16); + + newmode.crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) | + (vsync_wid << 16) | (v_sync_pol << 23)); + + newmode.pitch = ((mode->xres * mode->bits_per_pixel) + + ((mode->bits_per_pixel * 8) - 1)) / + (mode->bits_per_pixel * 8); + newmode.pitch |= newmode.pitch << 16; + + RTRACE("h_total_disp = 0x%x\t hsync_strt_wid = 0x%x\n", + newmode.crtc_h_total_disp, newmode.crtc_h_sync_strt_wid); + RTRACE("v_total_disp = 0x%x\t vsync_strt_wid = 0x%x\n", + newmode.crtc_v_total_disp, newmode.crtc_v_sync_strt_wid); + + newmode.xres = mode->xres; + newmode.yres = mode->yres; + + newmode.bpp = mode->bits_per_pixel; + + /* PLL -- XXX these are defaults, use BIOS */ + if (freq > 35000) + freq = 35000; + if (freq*12 < 12000) + freq = 12000 / 12; + + { + struct { + int divider; + int bitvalue; + } *post_div, + post_divs[] = { + { 1, 0 }, + { 2, 1 }, + { 4, 2 }, + { 8, 3 }, + { 3, 4 }, + { 16, 5 }, + { 6, 6 }, + { 12, 7 }, + { 0, 0 }, + }; + + for (post_div = &post_divs[0]; post_div->divider; ++post_div) { + rinfo->pll_output_freq = post_div->divider * freq; + if (rinfo->pll_output_freq >= 12000 && + rinfo->pll_output_freq <= 35000) + break; + } + + rinfo->post_div = post_div->divider; + rinfo->fb_div = round_div(60*rinfo->pll_output_freq, + 2700); + rinfo->ppll_ref_div = 60; + rinfo->ppll_div_3 = rinfo->fb_div | (post_div->bitvalue << 16); + } + + RTRACE("post div = 0x%x\n", rinfo->post_div); + RTRACE("fb_div = 0x%x\n", rinfo->fb_div); + + /* DDA */ + vclk_freq = round_div(2700 * rinfo->fb_div, 60 * rinfo->post_div); + xclk_freq = 16600; + + xclk_per_trans = round_div(xclk_freq * 128, vclk_freq * mode->bits_per_pixel); + + min_bits = min_bits_req(xclk_per_trans); + useable_precision = min_bits + 1; + + xclk_per_trans_precise = round_div((xclk_freq * 128) << (11 - useable_precision), + vclk_freq * mode->bits_per_pixel); + + ron = 4 * rinfo->mb + 3 * _max(rinfo->trcd - 2, 0) + + 2 * rinfo->trp + rinfo->twr + rinfo->cl + rinfo->tr2w + + xclk_per_trans; + ron = ron << (11 - useable_precision); + roff = xclk_per_trans_precise * (32 - 4); + + if ((ron + rinfo->rloop) >= roff) { + printk("radeonfb: error ron out of range\n"); + return; + } + + newmode.dda_config = (xclk_per_trans_precise | + (useable_precision << 16) | + (rinfo->rloop << 20)); + newmode.dda_on_off = (ron << 16) | roff; + + /* do it! */ + radeon_write_mode (rinfo, &newmode); + + return; +} + + + +static void radeon_write_mode (struct radeonfb_info *rinfo, + struct radeon_regs *mode) +{ + int i; + u32 tmp, tmp2; + + for (i=0; i<9; i++) + OUTREG(common_regs[i].reg, common_regs[i].val); + + OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl); + OUTREG(CRTC_EXT_CNTL, mode->crtc_ext_cntl); + OUTREG(DAC_CNTL, mode->dac_cntl); + OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp); + OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid); + OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp); + OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid); + OUTREG(CRTC_OFFSET, 0); + OUTREG(CRTC_OFFSET_CNTL, 0); + OUTREG(CRTC_PITCH, mode->pitch); + + tmp = INREG(CLOCK_CNTL_INDEX); + tmp |= PPLL_DIV_SEL_MASK; + OUTREG(CLOCK_CNTL_INDEX, tmp); + + /* i suppose i could use nifty macros to save time here but + * i'm too lazy to do that... + */ + tmp = INPLL(PPLL_CNTL); + tmp &= ~(PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN); + tmp |= PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN; + OUTPLL(PPLL_CNTL, tmp); + + while (radeon_pll_read_update_complete(rinfo) == 0); + + tmp = INPLL(PPLL_REF_DIV); + tmp &= ~PPLL_REF_DIV_MASK; + tmp |= (u32)(rinfo->ppll_ref_div); + OUTPLL(PPLL_REF_DIV, tmp); + + radeon_pll_write_update(rinfo); + + tmp = 0; + tmp |= rinfo->fb_div; + OUTPLL(PPLL_DIV_3, tmp); + + RTRACE("PPLL_DIV_3 = 0x%x\n", tmp); + + radeon_pll_write_update(rinfo); + + tmp = INPLL(PPLL_DIV_3); + + RTRACE("PPLL_DIV_3 = 0x%x\n", tmp); + + tmp &= ~PPLL_POST3_DIV_MASK; + tmp2 = (u32)(radeon_get_post_div_bitval(rinfo->post_div)); + tmp2 = tmp2 << 0x10; + tmp |= tmp2; + + OUTPLL(PPLL_DIV_3, tmp); + + RTRACE("PPLL_DIV_3 = 0x%x\n", tmp); + + radeon_pll_write_update(rinfo); + + while (radeon_pll_read_update_complete(rinfo) == 0); + while (radeon_pll_read_update_complete(rinfo) == 0); + + OUTPLL(HTOTAL_CNTL, 0); + + radeon_pll_write_update(rinfo); + + tmp = INPLL(PPLL_CNTL); + tmp &= ~PPLL_RESET; + OUTPLL(PPLL_CNTL, tmp); + + OUTREG(DDA_CONFIG, mode->dda_config); + OUTREG(DDA_ON_OFF, mode->dda_on_off); + + return; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/riva/rivafb.h linux.ac/drivers/video/riva/rivafb.h --- linux.vanilla/drivers/video/riva/rivafb.h Sat Feb 3 20:48:00 2001 +++ linux.ac/drivers/video/riva/rivafb.h Mon Apr 16 00:18:31 2001 @@ -82,4 +82,4 @@ #endif }; -#endif /* __RIVAFB_H */ \ No newline at end of file +#endif /* __RIVAFB_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/sa1100fb.c linux.ac/drivers/video/sa1100fb.c --- linux.vanilla/drivers/video/sa1100fb.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/sa1100fb.c Mon Apr 9 23:32:17 2001 @@ -688,6 +688,16 @@ init_var.grayscale = 0; init_var.sync = 0; init_var.pixclock = 171521; + } else if (machine_is_pangolin()) { + current_par.max_xres = 1024; + current_par.max_yres = 768; + current_par.max_bpp = 16; + init_var.red.length = 5; + init_var.green.length = 6; + init_var.blue.length = 5; + init_var.grayscale = 0; + init_var.sync = 0; + init_var.pixclock = 15400; } else if (machine_is_bitsy()) { current_par.max_xres = 320; current_par.max_yres = 240; @@ -717,15 +727,7 @@ init_var.grayscale = 1; init_var.pixclock = 150000; init_var.sync = 0; - } else if (machine_is_penny()) { - current_par.max_xres = 640; - current_par.max_yres = 480; - current_par.max_bpp = 8; - init_var.red.length = 4; - init_var.green = init_var.red; - init_var.blue = init_var.red; - init_var.sync = 0; - } else if (machine_is_thinclient() || machine_is_graphicsclient()) { + } else if (machine_is_graphicsclient()) { current_par.max_xres = 640; current_par.max_yres = 480; current_par.max_bpp = 8; @@ -733,24 +735,6 @@ init_var.green = init_var.red; init_var.blue = init_var.red; init_var.sync = 0; - } else if (machine_is_tifon()) { - current_par.max_xres = 640; - current_par.max_yres = 200; - current_par.max_bpp = 4; - current_par.inv_4bpp = 1; - init_var.red.length = 4; - init_var.green = init_var.red; - init_var.blue = init_var.red; - init_var.grayscale = 1; - init_var.pixclock = 150000; - init_var.left_margin = 20; - init_var.right_margin = 255; - init_var.upper_margin = 20; - init_var.lower_margin = 0; - init_var.hsync_len = 2; - init_var.vsync_len = 1; - init_var.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT; - init_var.vmode = 0; } else if (machine_is_xp860()) { current_par.max_xres = 1024; current_par.max_yres = 768; @@ -870,14 +854,7 @@ { unsigned int pcd = 0; - if (machine_is_tifon()) { - pcd = frequency[PPCR &0xf] / 1000; - pcd *= pixclock/1000; - pcd = pcd / 10000000 * 12; - /* the last multiplication by 1.2 is to handle */ - /* sync problems */ - } - if (machine_is_assabet()) { + if (machine_is_assabet() | machine_is_pangolin()) { pcd = frequency[PPCR & 0xf] / 1000; pcd *= pixclock / 1000; pcd = pcd / 1000000; @@ -933,6 +910,26 @@ /* Set board control register to handle new color depth */ sa1100fb_assabet_set_truecolor(var->bits_per_pixel >= 16); + } else if (machine_is_pangolin()) { + DPRINTK("Configuring Pangolin LCD\n"); + lcd_shadow.lccr0 = + LCCR0_LEN + LCCR0_Color + LCCR0_LDM + + LCCR0_BAM + LCCR0_ERM + LCCR0_Act + + LCCR0_LtlEnd + LCCR0_DMADel(0); + lcd_shadow.lccr1 = + LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(63) + + LCCR1_BegLnDel(127) + LCCR1_EndLnDel(127); + lcd_shadow.lccr2 = + LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(2) + + LCCR2_BegFrmDel(18) + LCCR2_EndFrmDel(18); + lcd_shadow.lccr3 = + LCCR3_PixClkDiv(pcd) + LCCR3_HorSnchH + + LCCR3_VrtSnchH + LCCR3_OutEnH; + DPRINTK("pcd = %d\n", pcd); + DPRINTK("LCCR1_DisWdth(var->xres) = 0x%x\n", + LCCR1_DisWdth(var->xres)); + DPRINTK("LCCR2_DisHght(var->yres) = 0x%x\n", + LCCR2_DisHght(var->yres)); } else if (machine_is_bitsy()) { DPRINTK("Configuring Bitsy LCD\n"); lcd_shadow.lccr0 = LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act + @@ -998,24 +995,8 @@ lcd_shadow.lccr3 = LCCR3_PixClkDiv(34) + LCCR3_ACBsDiv(512) + LCCR3_ACBsCntOff + LCCR3_HorSnchH + LCCR3_VrtSnchH; - } else if (machine_is_penny()) { - DPRINTK("Configuring Penny LCD\n"); - lcd_shadow.lccr0 = - LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act + - LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + - LCCR0_DMADel(0); - lcd_shadow.lccr1 = - LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(65) + - LCCR1_EndLnDel(43) + LCCR1_BegLnDel(43); - lcd_shadow.lccr2 = - LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(35) + - LCCR2_EndFrmDel(0) + LCCR2_BegFrmDel(0); - lcd_shadow.lccr3 = - LCCR3_PixClkDiv(16) + LCCR3_ACBsDiv (2) + LCCR3_ACBsCntOff + - ((var->sync & FB_SYNC_HOR_HIGH_ACT) ? LCCR3_HorSnchH : LCCR3_HorSnchL) + - ((var->sync & FB_SYNC_VERT_HIGH_ACT) ? LCCR3_VrtSnchH : LCCR3_VrtSnchL); - } else if (machine_is_thinclient() || machine_is_graphicsclient()) { - DPRINTK("Configuring ThinClient LCD\n"); + } else if (machine_is_graphicsclient()) { + DPRINTK("Configuring GraphicsClient LCD\n"); lcd_shadow.lccr0 = LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act; lcd_shadow.lccr1 = @@ -1027,29 +1008,6 @@ lcd_shadow.lccr3 = LCCR3_PixClkDiv(6) + LCCR3_ACBsDiv(2) + LCCR3_ACBsCntOff + LCCR3_HorSnchL + LCCR3_VrtSnchL; - } else if (machine_is_tifon()) { - DPRINTK("Configuring TIFON LCD\n"); - lcd_shadow.lccr0 = - LCCR0_LEN + LCCR0_Mono + LCCR0_Sngl + LCCR0_Pas + - LCCR0_BigEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + - LCCR0_8PixMono + LCCR0_DMADel(0); - lcd_shadow.lccr1 = - LCCR1_DisWdth(var->xres) + - LCCR1_HorSnchWdth(var->hsync_len) + - LCCR1_BegLnDel(var->left_margin) + - LCCR1_EndLnDel(var->right_margin); - lcd_shadow.lccr2 = - LCCR2_DisHght(var->yres) + - LCCR2_VrtSnchWdth(var->vsync_len) + - LCCR2_BegFrmDel(var->upper_margin) + - LCCR2_EndFrmDel(var->lower_margin); - lcd_shadow.lccr3 = - LCCR3_PixClkDiv(pcd) + LCCR3_ACBsDiv(512) + - LCCR3_ACBsCnt(0) + LCCR3_HorSnchH + LCCR3_VrtSnchH; - /* - ((current_var.sync & FB_SYNC_HOR_HIGH_ACT) ? LCCR3_HorSnchH : LCCR3_HorSnchL) + - ((current_var.sync & FB_SYNC_VERT_HIGH_ACT) ? LCCR3_VrtSnchH : LCCR3_VrtSnchL); - */ } else if (machine_is_xp860()) { DPRINTK("Configuring XP860 LCD\n"); lcd_shadow.lccr0 = @@ -1116,13 +1074,6 @@ if (current_par.controller_state != LCD_MODE_DISABLE_BEFORE_ENABLE) clr_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON); #endif - } else if (machine_is_penny()) { -#ifdef CONFIG_SA1100_PENNY - FpgaLcdCS1 = 0x000; /* LCD Backlight to 0% */ - FpgaPortI &= ~LCD_ON; /* Turn off LCD Backlight */ -#endif - } else if (machine_is_tifon()) { - GPCR = GPIO_GPIO(24); /* turn off display */ } } } @@ -1174,7 +1125,7 @@ /* Make sure the mode bits are present in the first palette entry */ current_par.v_palette_base[0] &= 0x0FFF; - current_par.v_palette_base[0] |= SA1100_PALETTE_MODE_VAL(current_par.bits_per_pixel); + current_par.v_palette_base[0] |= SA1100_PALETTE_MODE_VAL(current_par.bits_per_pixel); /* Enable GPIO<9:2> for LCD usage if dual-scan */ if (lcd_shadow.lccr0 & LCCR0_SDS) { @@ -1204,15 +1155,6 @@ DPRINTK("LCCR2=%x\n", LCCR2); DPRINTK("LCCR3=%x\n", LCCR3); #endif - } else if (machine_is_penny()) { -#ifdef CONFIG_SA1100_PENNY - FpgaLcdCS1 = 0x0FF; /* LCD Backlight to 100% */ - FpgaPortI |= LCD_ON; /* Turn on LCD Backlight */ -#endif - } else if (machine_is_tifon()) { - GPCR = GPIO_GPIO(24); /* cycle on/off-switch */ - udelay(150); - GPSR = GPIO_GPIO(24); /* turn on display */ } current_par.controller_state = LCD_MODE_ENABLED; @@ -1307,19 +1249,15 @@ GAFR |= 0x3fc; sa1100fb_assabet_set_truecolor(current_par.visual == FB_VISUAL_TRUECOLOR); + } else if (machine_is_pangolin()) { + GPDR |= 0x3fc; + GAFR |= 0x3fc; } else if (machine_is_bitsy()) { GPDR = (GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 | GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8); GAFR |= (GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 | GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8); } else if (machine_is_cerf()) { GPDR |= 0x3fc; GAFR |= 0x3fc; - } else if (machine_is_penny()) { -#ifdef CONFIG_SA1100_PENNY - GPDR |= GPIO_GPDR_GFX; /* GPIO Data Direction register for LCD data bits 8-11 */ - GAFR |= GPIO_GAFR_GFX; /* GPIO Alternate Function register for LCD data bits 8-11 */ -#endif - } else if (machine_is_tifon()) { - GPDR |= GPIO_GPIO(24); /* set GPIO24 to output */ } else if (machine_is_xp860()) { GPDR |= 0x3fc; GAFR |= 0x3fc; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/sbusfb.c linux.ac/drivers/video/sbusfb.c --- linux.vanilla/drivers/video/sbusfb.c Tue Apr 3 17:32:24 2001 +++ linux.ac/drivers/video/sbusfb.c Sat Apr 14 01:37:04 2001 @@ -193,44 +193,6 @@ /* To stop the swapper from even considering these pages */ vma->vm_flags |= (VM_SHM| VM_LOCKED); -#ifdef __sparc_v9__ - /* Align it as much as desirable */ - { - unsigned long j, alignment, s = 0; - int max = -1; - - map_offset = (vma->vm_pgoff << PAGE_SHIFT) + size; - for (i = 0; fb->mmap_map[i].size; i++) { - if (fb->mmap_map[i].voff < off) - continue; - if (fb->mmap_map[i].voff >= map_offset) - break; - if (max < 0 || sbusfb_mmapsize(fb,fb->mmap_map[i].size) > s) { - max = i; - s = sbusfb_mmapsize(fb,fb->mmap_map[max].size); - } - } - if (max >= 0) { - j = s; - if (fb->mmap_map[max].voff + j > map_offset) - j = map_offset - fb->mmap_map[max].voff; - for (alignment = 0x400000; alignment > PAGE_SIZE; alignment >>= 3) - if (j >= alignment && !(fb->mmap_map[max].poff & (alignment - 1))) - break; - if (alignment > PAGE_SIZE) { - j = alignment; - alignment = j - ((vma->vm_start + fb->mmap_map[max].voff - off) & (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; - } - } - } - } - } -#endif /* Each page, see which map applies */ for (page = 0; page < size; ){ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/sis/Makefile linux.ac/drivers/video/sis/Makefile --- linux.vanilla/drivers/video/sis/Makefile Fri Dec 29 22:07:23 2000 +++ linux.ac/drivers/video/sis/Makefile Tue Apr 3 17:55:09 2001 @@ -1,12 +1,10 @@ # -# Makefile for the SiS framebuffer device driver -# O_TARGET := sisfb.o -obj-y := sis_main.o sis_300.o sis_301.o -obj-m := $(O_TARGET) - -include $(TOPDIR)/Rules.make +export-objs := sis_main.o +obj-$(CONFIG_FB_SIS_300) += sis_300.o sis_301.o +obj-$(CONFIG_FB_SIS_315) += init310.o init301.o +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/sis/init301.c linux.ac/drivers/video/sis/init301.c --- linux.vanilla/drivers/video/sis/init301.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/sis/init301.c Tue Apr 3 17:55:09 2001 @@ -0,0 +1,4092 @@ +#include <linux/config.h> +#include <linux/kernel.h> +#include "init301.h" + +extern UCHAR SiSGet310DRAMType(ULONG); +#ifdef CONFIG_FB_SIS_315 +VOID SiSAutoThreshold (USHORT BaseAddr); +#endif + +BOOLEAN SiSSetCRT2Group301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + USHORT temp; + + SiSSetFlag = SiSSetFlag | ProgrammingCRT2; + SiSSearchModeID(ROMAddr,ModeNo); + + temp=SiSGetRatePtrCRT2(ROMAddr,ModeNo); + if (((temp&0x02)==0) && ((SiSVBInfo&CRT2DisplayFlag)==0)) + return(FALSE); + SiSSaveCRT2Info(ModeNo); + SiSDisableBridge(HwDeviceExtension,BaseAddr); + SiSUnLockCRT2(HwDeviceExtension,BaseAddr); + SiSSetDefCRT2ExtRegs(BaseAddr); + SiSSetCRT2ModeRegs(BaseAddr,ModeNo); + if (SiSVBInfo&CRT2DisplayFlag) { + SiSLockCRT2(HwDeviceExtension,BaseAddr); + return 0; + } + SiSGetCRT2Data(ROMAddr,ModeNo); + if (SIS_IF_DEF_LVDS==1) { + SiSGetLVDSDesData(ROMAddr,ModeNo); + } + SiSSetGroup1(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension); + if (SIS_IF_DEF_LVDS==0) { + SiSSetGroup2(BaseAddr,ROMAddr); + SiSSetGroup3(BaseAddr); + SiSSetGroup4(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension); + SiSSetGroup5(BaseAddr,ROMAddr); + } else { + if (SIS_IF_DEF_TRUMPION==0) { + SiSModCRT1CRTC(ROMAddr,ModeNo); + } + SiSSetCRT2ECLK(ROMAddr,ModeNo,HwDeviceExtension); + } + +#ifdef CONFIG_FB_SIS_315 + SiSAutoThreshold(BaseAddr); +#endif + + SiSOEM310Setting(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo); + + SiSEnableCRT2(); + SiSEnableBridge(HwDeviceExtension,BaseAddr); + SiSSetLockRegs(); + SiSLockCRT2(HwDeviceExtension,BaseAddr); + + return 1; +} + +VOID SiSoverwriteregs(ULONG ROMAddr,USHORT BaseAddr) +{ + int i; + USHORT Part1Port; + int p1reg[0x29]={0x84,0x76,0x4B,0x21,0x00,0x00,0x00,0x00,0x1F,0x51,0x0C,0x10,0x44,0x90,0x1E,0xFF, + 0x00,0x34,0x13,0x10,0x00,0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x01,0x97,0x16,0xA3}; + Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; + for(i=0;i<29;i++) { + SiSSetReg1(Part1Port,(USHORT)i,(USHORT)p1reg[i]); + } +} + +VOID SiSSetDefCRT2ExtRegs(USHORT BaseAddr) +{ + USHORT Part1Port,Part2Port,Part4Port; + USHORT temp; + Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; + Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; + Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14; + SiSSetReg1(Part1Port,0x02,0x40); + SiSSetReg1(Part4Port,0x10,0x80); + temp=(UCHAR)SiSGetReg1(SiSP3c4,0x16); + temp=temp&0xC3; + SiSSetReg1(SiSP3d4,0x35,temp); + +} + +USHORT SiSGetRatePtrCRT2(ULONG ROMAddr, USHORT ModeNo) +{ + SHORT index; + USHORT temp; + USHORT ulRefIndexLength; + USHORT temp1; + SHORT LCDRefreshIndex[4]={0x0,0x0,0x03,0x01}; + + + if (ModeNo<0x14) return(0); + + index=SiSGetReg1(SiSP3d4,0x33); + index=index>>SelectCRT2Rate; + index=index&0x0F; + if (index!=0) index--; + + if (SIS_IF_DEF_TRUMPION==1) { + if (SiSVBInfo&SetSimuScanMode) { + index=0; + } + } + if (SiSSetFlag&ProgrammingCRT2) { + if (SiSVBInfo&SetCRT2ToLCD) { + if (SIS_IF_DEF_LVDS==0) { + temp=SiSLCDResInfo; + temp1=LCDRefreshIndex[temp]; + if (index>temp1) { + index=temp1; + } + } else { + index=0; + } + } + } + + SiSREFIndex=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x05)); + + ulRefIndexLength =Ext2StructSize; + do { + temp=*((USHORT *)(ROMAddr+SiSREFIndex)); + if (temp==0xFFFF) break; + temp=temp&ModeInfoFlag; + if (temp<SiSModeType) break; + + SiSREFIndex=SiSREFIndex+ulRefIndexLength; + index--; + if (index<0) { + if (!(SiSVBInfo&SetCRT2ToRAMDAC)) { + if (SiSVBInfo&SetInSlaveMode) { + temp1=*((USHORT *)(ROMAddr+SiSREFIndex+0-Ext2StructSize)); + if (temp1&InterlaceMode) { + index=0; + } + } + } + } + } while(index>=0); + + SiSREFIndex=SiSREFIndex-ulRefIndexLength; + + if ((SiSSetFlag&ProgrammingCRT2)) { + temp1=SiSAjustCRT2Rate(ROMAddr); + } else { + temp1=0; + } + + return(0x01|(temp1<<1)); +} + +BOOLEAN SiSAjustCRT2Rate(ULONG ROMAddr) +{ + USHORT tempax,temp,tempbx=0; + USHORT tempextinfoflag; + tempax=0; + + if (SIS_IF_DEF_LVDS==0) { + if (SiSVBInfo&SetCRT2ToRAMDAC) { + tempax=tempax|SupportRAMDAC2; + } + if (SiSVBInfo&SetCRT2ToLCD) { + tempax=tempax|SupportLCD; + if (SiSLCDResInfo!=Panel1280x1024) { + temp=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x0a)); + if (temp>=9) { + tempax=0; + } + } + } + if (SiSVBInfo&(SetCRT2ToAVIDEO|SetCRT2ToSVIDEO|SetCRT2ToSCART)) { + tempax=tempax|SupportTV; + if (!(SiSVBInfo&SetPALTV)) { + tempextinfoflag=*((USHORT *)(ROMAddr+SiSREFIndex+0x0)); + if (tempextinfoflag&NoSupportSimuTV) { + if (SiSVBInfo&SetInSlaveMode) { + if (!(SiSVBInfo&SetNotSimuTVMode)) { + return 0; + } + } + } + } + } + tempbx=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x05)); + } else { + if (SiSVBInfo&SetCRT2ToLCD) { + tempax=tempax|SupportLCD; + temp=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x0a)); + if (temp>0x08) { + return 0; + } + if (SiSLCDResInfo<Panel1024x768) { + if (temp>0x07) { + return 0; + } + if (temp==0x04) { + return 0; + } + } + } + } + + for(;SiSREFIndex>tempbx;SiSREFIndex-=Ext2StructSize) { + tempextinfoflag=*((USHORT *)(ROMAddr+SiSREFIndex+0x0)); + if (tempextinfoflag&tempax) { + return 1; + } + } + + for(SiSREFIndex=tempbx;;SiSREFIndex+=Ext2StructSize) { + tempextinfoflag=*((USHORT *)(ROMAddr+SiSREFIndex+0x0)); + if (tempextinfoflag==0x0FFFF) { + return 0; + } + if (tempextinfoflag&tempax) { + return 1; + } + } + return(FALSE); +} + +VOID SiSSaveCRT2Info(USHORT ModeNo) { + USHORT temp1,temp2,temp3; + + temp1=(SiSVBInfo&SetInSlaveMode)>>8; + temp2=~(SetInSlaveMode>>8); + temp3=(UCHAR)SiSGetReg1(SiSP3d4,0x31); + temp3=((temp3&temp2)|temp1); + SiSSetReg1(SiSP3d4,0x31,(USHORT)temp3); + temp3=(UCHAR)SiSGetReg1(SiSP3d4,0x35); + temp3=temp3&0xF3; + SiSSetReg1(SiSP3d4,0x35,(USHORT)temp3); +} + +VOID SiSDisableLockRegs() { + UCHAR temp3; + temp3=(UCHAR)SiSGetReg1(SiSP3c4,0x32); + temp3=temp3&0xDF; + SiSSetReg1(SiSP3c4,0x32,(USHORT)temp3); +} + +VOID SiSDisableCRT2() { + UCHAR temp3; + temp3=(UCHAR)SiSGetReg1(SiSP3c4,0x1E); + temp3=temp3&0xDF; + SiSSetReg1(SiSP3c4,0x1E,(USHORT)temp3); +} + + + +VOID SiSDisableBridge(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr) +{ + USHORT Part2Port,Part1Port; + Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; + Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; + + if (SIS_IF_DEF_LVDS==0) { + SiSSetRegANDOR(Part2Port,0x00,0xDF,0x00); + SiSSetRegOR(Part1Port,0x00,0x80); + SiSDisableLockRegs(); + SiSSetRegAND(Part1Port,0x2E,0x7F); + SiSDisableCRT2(); + } else { + SiSDisableLockRegs(); + SiSDisableCRT2(); + if (SIS_IF_DEF_TRUMPION==0) { + SiSUnLockCRT2(HwDeviceExtension,BaseAddr); + SiSSetRegANDOR(Part1Port,0x02,0xFF,0x40); + } + } +} + +VOID SiSGetCRT2Data(ULONG ROMAddr,USHORT ModeNo) +{ + if (SIS_IF_DEF_LVDS==0) { + SiSGetCRT2Data301(ROMAddr,ModeNo); + return; + } else { + SiSGetCRT2DataLVDS(ROMAddr,ModeNo); + return; + } +} + +VOID SiSGetCRT2DataLVDS(ULONG ROMAddr,USHORT ModeNo) +{ + USHORT tempax,tempbx,OldREFIndex; + + OldREFIndex=(USHORT)SiSREFIndex; + SiSGetResInfo(ROMAddr,ModeNo); + SiSGetCRT2Ptr(ROMAddr,ModeNo); + + tempax=*((USHORT *)(ROMAddr+SiSREFIndex)); + tempax=tempax&0x0FFF; + SiSVGAHT=tempax; + + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+1)); + tempax=tempax>>4; + tempax=tempax&0x07FF; + SiSVGAVT=tempax; + + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+3)); + tempax=tempax&0x0FFF; + tempbx=*((USHORT *)(ROMAddr+SiSREFIndex+4)); + tempbx=tempbx>>4; + tempbx=tempbx&0x07FF; + + SiSHT=tempax; + SiSVT=tempbx; + + if (SIS_IF_DEF_TRUMPION==0) { + if (SiSVBInfo&SetCRT2ToLCD) { + if (!(SiSLCDInfo&LCDNonExpanding)) { + if (SiSLCDResInfo==Panel800x600) { + tempax=800; + tempbx=600; + } else if (SiSLCDResInfo==Panel1024x768) { + tempax=1024; + tempbx=768; + } else { + tempax=1280; + tempbx=1024; + } + SiSHDE=tempax; + SiSVDE=tempbx; + } + } + } + SiSREFIndex=OldREFIndex; + return; +} + +VOID SiSGetCRT2Data301(ULONG ROMAddr,USHORT ModeNo) +{ + USHORT tempax,tempbx,modeflag1,OldREFIndex; + USHORT tempal,tempah,tempbl; + + OldREFIndex=(USHORT)SiSREFIndex; + SiSRVBHRS=50;SiSNewFlickerMode=0;SiSRY1COE=0; + SiSRY2COE=0;SiSRY3COE=0;SiSRY4COE=0; + + SiSGetResInfo(ROMAddr,ModeNo); + if (SiSVBInfo&SetCRT2ToRAMDAC) { + SiSGetRAMDAC2DATA(ROMAddr,ModeNo); + SiSREFIndex=OldREFIndex; + return; + } + SiSGetCRT2Ptr(ROMAddr,ModeNo); + + tempal=*((UCHAR *)(ROMAddr+SiSREFIndex)); + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex+4)); + tempax=tempal|(((tempah<<8)>>7)&0xFF00); + SiSRVBHCMAX=tempax; + + tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+1)); + SiSRVBHCFACT=tempal; + + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+2)); + SiSVGAHT=(tempax&0x0FFF); + + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+3)); + SiSVGAVT=((tempax>>4)&0x07FF); + + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+5)); + tempax=(tempax&0x0FFF); + tempbx=*((USHORT *)(ROMAddr+SiSREFIndex+6)); + tempbx=((tempbx>>4)&0x07FF); + tempbl=tempbx&0x00FF; + + if (SiSVBInfo&SetCRT2ToTV) { + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+5)); + tempax=(tempax&0x0FFF); + SiSHDE=tempax; + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+6)); + tempax=((tempax>>4)&0x07FF); + SiSVDE=tempax; + + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+8)); + tempbl=(tempax>>8); + tempax=tempax&0x0FFF; + modeflag1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + if (modeflag1&HalfDCLK) { + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+10)); + } + SiSRVBHRS=tempax; + SiSNewFlickerMode=(tempbl&0x080); + + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+12)); + SiSRY1COE=(tempax&0x00FF); + SiSRY2COE=((tempax&0xFF00)>>8); + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+14)); + SiSRY3COE=(tempax&0x00FF); + SiSRY4COE=((tempax&0xFF00)>>8); + if (!(SiSVBInfo&SetPALTV)) { + tempax=NTSCHT; + tempbx=NTSCVT; + } else { + tempax=PALHT; + tempbx=PALVT; + } + } + SiSHT=tempax; + SiSVT=tempbx; + if (!(SiSVBInfo&SetCRT2ToLCD)) { + SiSREFIndex=OldREFIndex; + return; + } + + tempax=1024; + if (SiSVGAVDE==350) { + tempbx=560; + } else if (SiSVGAVDE==400) { + tempbx=640; + } else { + tempbx=768; + } + + if (SiSLCDResInfo==Panel1280x1024) { + tempax=1280; + if (SiSVGAVDE==360) { + tempbx=768; + } else if (SiSVGAVDE==375) { + tempbx=800; + } else if (SiSVGAVDE==405) { + tempbx=864; + } else { + tempbx=1024; + } + } + + SiSHDE=tempax; + SiSVDE=tempbx; + SiSREFIndex=OldREFIndex; + return; +} + +VOID SiSGetResInfo(ULONG ROMAddr,USHORT ModeNo) +{ + USHORT temp,xres,yres,modeflag1; + if (ModeNo<=0x13) { + temp=(USHORT)*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x05)); + xres=SiSStResInfo[temp][0]; + yres=SiSStResInfo[temp][1]; + } else { + temp=(USHORT)*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x0a)); + xres=SiSModeResInfo[temp][0]; + yres=SiSModeResInfo[temp][1]; + modeflag1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + if (modeflag1&HalfDCLK) { xres=xres*2;} + if (modeflag1&DoubleScanMode) {yres=yres*2;} + } + if (!(SiSLCDResInfo==Panel1024x768)) { + if (yres==400) yres=405; + if (yres==350) yres=360; + if (SiSSetFlag&LCDVESATiming) { + if (yres==360) yres=375; + } + } + SiSVGAHDE=xres; + SiSHDE=xres; + SiSVGAVDE=yres; + SiSVDE=yres; +} + +VOID SiSGetLVDSDesData(ULONG ROMAddr,USHORT ModeNo) +{ + USHORT old_REFIndex,tempax; + + old_REFIndex=(USHORT)SiSREFIndex; + SiSREFIndex=SiSGetLVDSDesPtr(ROMAddr,ModeNo); + + tempax=*((USHORT *)(ROMAddr+SiSREFIndex)); + tempax=tempax&0x0FFF; + SiSLCDHDES=tempax; + + if (SiSLCDInfo&LCDNonExpanding) { + if (SiSLCDResInfo>=Panel1024x768) { + if (ModeNo<=0x13) { + SiSLCDHDES=320; + } + } + } + + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+1)); + tempax=tempax>>4; + tempax=tempax&0x07FF; + SiSLCDVDES=tempax; + + SiSREFIndex=old_REFIndex; + return; +} + + +VOID SiSGetRAMDAC2DATA(ULONG ROMAddr,USHORT ModeNo) +{ + USHORT tempax,tempbx,tempbh,modeflag1,t2, t1=0; + SiSRVBHCMAX=1;SiSRVBHCFACT=1; + if (ModeNo<=0x13) { + tempax=*((UCHAR *)(ROMAddr+SiSREFIndex+10)); + tempbx=*((USHORT *)(ROMAddr+SiSREFIndex+16)); + } else { + t1=*((UCHAR *)(ROMAddr+SiSREFIndex+0x2)); + t1=t1&0x03F; + t1=t1*CRT1Len; + SiSREFIndex=*((USHORT *)(ROMAddr+CRT1TablePtrOffset)); + SiSREFIndex=SiSREFIndex+t1; + t1=*((UCHAR *)(ROMAddr+SiSREFIndex+0)); + t2=*((UCHAR *)(ROMAddr+SiSREFIndex+14)); + tempax=(t1&0xFF)|((t2&0x03)<<8); + tempbx=*((USHORT *)(ROMAddr+SiSREFIndex+6)); + t1=*((UCHAR *)(ROMAddr+SiSREFIndex+13)); + t1=(t1&0x01)<<2; + } + + tempbh=tempbx>>8; + tempbh=((tempbh&0x20)>>4)|(tempbh&0x01); + tempbh=tempbh|t1; + tempbx=(tempbx&0xFF)|(tempbh<<8); + tempax=tempax+5; + modeflag1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + if (modeflag1&Charx8Dot) { + tempax=tempax*8; + } else { + tempax=tempax*9; + } + + SiSVGAHT=tempax; + SiSHT=tempax; + tempbx++; + SiSVGAVT=tempbx; + SiSVT=tempbx; +} + +VOID SiSGetCRT2Ptr(ULONG ROMAddr,USHORT ModeNo) +{ + USHORT tempcl,tempbx,tempal,tempax,CRT2PtrData; + + if (SIS_IF_DEF_LVDS==0) { + if (SiSVBInfo&SetCRT2ToLCD) { + tempbx=0; + tempcl=LCDDataLen; + if (SiSLCDResInfo==Panel1024x768) { + tempbx=0; + } else if (SiSLCDResInfo==Panel1280x1024) { + tempbx=1; + } + if (!(SiSSetFlag&LCDVESATiming)) tempbx+=5; + } else if (SiSVBInfo&SetPALTV) { + tempcl=TVDataLen; + tempbx=3; + } else { + tempbx=4; + tempcl=TVDataLen; + } + if (SiSSetFlag&TVSimuMode) { + tempbx=tempbx+4; + } + if (ModeNo<=0x13) { + tempal=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x04)); + } else { + tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+4)); + } + tempal=tempal&0x1F; + + tempax=tempal*tempcl; + SiSREFIndex=*((USHORT *)(ROMAddr+CRT2PtrDataPtrOffset)); + SiSREFIndex = *((USHORT *)(ROMAddr+SiSREFIndex+tempbx*2)); + SiSREFIndex+=tempax; + } else { + tempcl=LVDSDataLen; + tempbx=SiSLCDResInfo-Panel800x600; + if (SiSLCDInfo&LCDNonExpanding) { + tempbx=tempbx+3; + } + if (ModeNo<=0x13) { + tempal=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x04)); + } else { + tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+0x04)); + } + tempal=tempal&0x1F; + tempax=tempal*tempcl; + CRT2PtrData=*((USHORT *)(ROMAddr+ADR_CRT2PtrData)); + SiSREFIndex=*((USHORT *)(ROMAddr+CRT2PtrData+tempbx*2)); + SiSREFIndex+=tempax; + } +} + +VOID SiSUnLockCRT2(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr) +{ + UCHAR temp3; + USHORT Part1Port; + Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; + + if (HwDeviceExtension->jChipID == SIS_GlamourII) { + temp3=(UCHAR)SiSGetReg1(Part1Port,0x2f); + temp3=temp3|0x01; + SiSSetReg1(Part1Port,0x2f,(USHORT)temp3); + } + else if (HwDeviceExtension->jChipID == SIS_GlamourII) { + temp3=(UCHAR)SiSGetReg1(Part1Port,0x24); + temp3=temp3|0x01; + SiSSetReg1(Part1Port,0x24,(USHORT)temp3); + } + +} + +VOID SiSSetCRT2ModeRegs(USHORT BaseAddr,USHORT ModeNo) +{ + USHORT i,j; + USHORT tempah=0,temp3; + SHORT tempcl; + USHORT Part4Port; + USHORT Part1Port; + Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14; + Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; + for(i=0,j=4;i<3;i++,j++) { + SiSSetReg1(Part1Port,j,0); + } + + tempcl=(USHORT)SiSModeType; + if (ModeNo>0x13) { + tempcl=tempcl-ModeVGA; + if (tempcl>=0) { +#ifdef CONFIG_FB_SIS_315 + tempah=(0x008>>tempcl); + if (tempah==0) tempah=1; + tempah |= 0x040; +#else + tempah=((0x010>>tempcl)|0x080); +#endif + } + } else { +#ifdef CONFIG_FB_SIS_315 + tempah=0x040; +#else + tempah=0x080; +#endif + } + + if (SiSVBInfo&SetInSlaveMode) { +#ifdef CONFIG_FB_SIS_315 + tempah=(tempah^0x050); +#else + tempah=(tempah^0x0A0); +#endif + } + + if (SiSVBInfo&CRT2DisplayFlag) { + tempah=0; + } + SiSSetReg1(Part1Port,0,tempah); + + if (SIS_IF_DEF_LVDS==0) { + tempah=0x01; + if (!(SiSVBInfo&SetInSlaveMode)) { + tempah=(tempah|0x02); + } + if (!(SiSVBInfo&SetCRT2ToRAMDAC)) { + tempah=(tempah^0x05); + if (!(SiSVBInfo&SetCRT2ToLCD)) { + tempah=(tempah^0x01); + } + } +#ifdef CONFIG_FB_SIS_315 + if (SiSVBInfo&CRT2DisplayFlag) { + tempah=0; + } + temp3 = SiSGetReg1(Part1Port, 0x2E); + temp3 = (temp3&0xF8)|tempah; + SiSSetReg1(Part1Port,0x2E,temp3); +#else + tempah=(tempah<<5)&0xFF; + if (SiSVBInfo&CRT2DisplayFlag) { + tempah=0; + } + SiSSetReg1(Part1Port,0x01,tempah); + tempah=tempah>>5; +#endif + + if ((SiSModeType==ModeVGA)&&(!(SiSVBInfo&SetInSlaveMode))) { + tempah=tempah|0x010; + } + if (SiSLCDResInfo!=Panel1024x768) { + tempah=tempah|0x080; + } + if (SiSVBInfo&SetCRT2ToTV) { + if (SiSVBInfo&SetInSlaveMode) { + tempah=tempah|0x020; + } + } + + temp3=(UCHAR)SiSGetReg1(Part4Port,0x0D); + temp3=temp3&(~0x0BF); + temp3=temp3|tempah; + SiSSetReg1(Part4Port,0x0D,(USHORT)temp3); + } else { + tempah=0; + if (!(SiSVBInfo&SetInSlaveMode)) { + tempah=tempah|0x02; + } + tempah=(tempah<<5)&0x0FF; + if (SiSVBInfo&CRT2DisplayFlag) { + tempah=0; + } + SiSSetReg1(Part1Port,0x01,tempah); + } +} + +VOID SiSSetGroup1(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + if (SIS_IF_DEF_LVDS==0) { + SiSSetGroup1_301(BaseAddr,ROMAddr,ModeNo, HwDeviceExtension); + } else { + SiSSetGroup1_LVDS(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension); + } +} +VOID SiSSetGroup1_LVDS(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + USHORT temp1,temp2,tempcl,tempch,tempbh,tempal,tempah,tempax,tempbx; + USHORT tempcx,OldREFIndex,lcdhdee; + USHORT Part1Port; + USHORT temppush1,temppush2; + unsigned long int tempeax,tempebx,tempecx,templong; + + Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; + OldREFIndex=(USHORT)SiSREFIndex; + + SiSSetCRT2Offset(Part1Port,ROMAddr); + SiSSetCRT2FIFO(Part1Port,ROMAddr,ModeNo,HwDeviceExtension); + SiSSetCRT2Sync(BaseAddr,ROMAddr,ModeNo); + + temp1=(SiSVGAHT-1)&0x0FF; + SiSSetReg1(Part1Port,0x08,temp1); + temp1=(((SiSVGAHT-1)&0xFF00)>>8)<<4; + SiSSetRegANDOR(Part1Port,0x09,~0x0F0,temp1); + + temp1=(SiSVGAHDE+12)&0x0FF; + SiSSetReg1(Part1Port,0x0A,temp1); + + temp1=SiSVGAHDE+12; + temp2=(SiSVGAHT-SiSVGAHDE)>>2; + temp1=temp1+temp2; + temp2=(temp2<<1)+temp1; + tempcl=temp2&0x0FF; + + SiSSetReg1(Part1Port,0x0B,(USHORT)(temp1&0x0FF)); + tempah=(temp1&0xFF00)>>8; + tempbh=((((SiSVGAHDE+12)&0xFF00)>>8)<<4)&0x0FF; + tempah=tempah|tempbh; + SiSSetReg1(Part1Port,0x0C,tempah); + SiSSetReg1(Part1Port,0x0D,tempcl); + tempcx=(SiSVGAVT-1); + tempah=tempcx&0x0FF; + SiSSetReg1(Part1Port,0x0E,tempah); + tempbx=SiSVGAVDE-1; + tempah=tempbx&0x0FF; + SiSSetReg1(Part1Port,0x0F,tempah); + tempah=((tempbx&0xFF00)<<3)>>8; + tempah=tempah|((tempcx&0xFF00)>>8); + SiSSetReg1(Part1Port,0x12,tempah); + + tempbx=(SiSVGAVT+SiSVGAVDE)>>1; + tempcx=((SiSVGAVT-SiSVGAVDE)>>4)+tempbx+1; + + tempah=tempbx&0x0FF; + SiSSetReg1(Part1Port,0x10,tempah); + tempbh=(tempbx&0xFF00)>>8; + tempah=((tempbh<<4)&0x0FF)|(tempcx&0x0F); + SiSSetReg1(Part1Port,0x11,tempah); + + SiSSetRegANDOR(Part1Port,0x13,~0x03C,tempah); + + tempax=SiSLCDHDES; + tempbx=SiSHDE; + tempcx=SiSHT; + tempcx=tempcx-tempbx; + + tempax=tempax+tempbx; + tempbx=SiSHT; + if (tempax>=tempbx) { + tempax=tempax-tempbx; + } + + lcdhdee=tempax; + tempcx=tempcx>>2; + tempcx=tempcx+tempax; + if (tempcx>=tempbx) { + tempcx=tempcx-tempbx; + } + + tempax=tempcx; + tempax=tempax>>3; + tempah=tempax&0x0FF; + SiSSetReg1(Part1Port,0x14,tempah); + tempah=tempah+2; + tempah=tempah+0x01F; + tempcl=tempcx&0x0FF; + tempcl=tempcl&0x07; + tempcl=(tempcl<<5)&0xFF; + tempah=tempah|tempcl; + SiSSetReg1(Part1Port,0x15,tempah); + tempbx=lcdhdee; + tempcx=SiSLCDHDES; + tempah=(tempcx&0xFF); + tempah=tempah&0x07; + SiSSetReg1(Part1Port,0x1A,tempah); + tempcx=tempcx>>3; + tempah=(tempcx&0xFF); + SiSSetReg1(Part1Port,0x16,tempah); + tempbx=tempbx>>3; + tempah=tempbx&0xFF; + SiSSetReg1(Part1Port,0x17,tempah); + + tempcx=SiSVGAVT; + tempbx=SiSVGAVDE; + tempcx=tempcx-tempbx; + tempbx=SiSLCDVDES; + temppush1=tempbx; + if (SIS_IF_DEF_TRUMPION==0) { + if (SiSLCDResInfo==Panel800x600) { + tempax=600; + } else { + tempax=768; + } + } else { + tempax=SiSVGAVDE; + } + tempbx=tempbx+tempax; + tempax=SiSVT; + if (tempbx>=SiSVT) { + tempbx=tempbx-tempax; + } + temppush2=tempbx; + tempcx=tempcx>>1; + tempbx=tempbx+tempcx; + tempbx++; + if (tempbx>=tempax) { + tempbx=tempbx-tempax; + } + tempah=tempbx&0xFF; + SiSSetReg1(Part1Port,0x18,tempah); + tempcx=tempcx>>3; + tempcx=tempcx+tempbx; + tempcx++; + tempah=tempcx&0xFF; + tempah=tempah&0x0F; + tempah=tempah|0x030; + SiSSetRegANDOR(Part1Port,0x19,~0x03F,tempah); + tempbh=(tempbx&0xFF00)>>8; + tempbh=tempbh&0x07; + tempah=tempbh; + tempah=(tempah<<3)&0xFF; + + tempbx=SiSVGAVDE; + if (tempbx!=SiSVDE) { + tempah=tempah|0x40; + } + SiSSetRegANDOR(Part1Port,0x1A,0x07,tempah); + tempecx=SiSVGAVT; + tempebx=SiSVDE; + tempeax=SiSVGAVDE; + tempecx=tempecx-tempeax; + tempeax=tempeax*64; + templong=tempeax/tempebx; + if (templong*tempebx<tempeax) { + templong++; + } + tempebx=templong; + if (SiSSetFlag&EnableLVDSDDA) { + tempebx=tempebx&0x03F; + } + tempah=(USHORT)(tempebx&0x0FF); + SiSSetReg1(Part1Port,0x1E,tempah); + tempbx=temppush2; + tempcx=temppush1; + tempbh=(tempbx&0xFF00)>>8; + tempah=tempah&0x07; + tempah=tempbh; + tempah=tempah<<3; + tempch=(tempcx&0xFF00)>>8; + tempch=tempah&0x07; + tempah=tempah|tempch; + SiSSetReg1(Part1Port,0x1D,tempah); + tempah=tempbx&0xFF; + SiSSetReg1(Part1Port,0x1C,tempah); + tempah=tempcx&0xFF; + SiSSetReg1(Part1Port,0x1B,tempah); + + tempecx=SiSVGAHDE; + tempebx=SiSHDE; + tempeax=tempecx; + tempeax=tempeax<<6; + tempeax=tempeax<<10; + tempeax=tempeax/tempebx; + if (tempebx==tempecx) { + tempeax=65535; + } + tempecx=tempeax; + tempeax=SiSVGAHT; + tempeax=tempeax<<6; + tempeax=tempeax<<10; + tempeax=tempeax/tempecx; + tempecx=tempecx<<16; + tempeax=tempeax-1; + tempax=(USHORT)(tempeax&0x00FFFF); + tempcx=tempax; + tempah=tempcx&0x0FF; + SiSSetReg1(Part1Port,0x1F,tempah); + tempbx=SiSVDE; + tempbx--; + if (SiSSetFlag&EnableLVDSDDA) { + tempbx=1; + } + tempah=(tempbx&0xFF00)>>8; + tempah=(tempah<<3)&0xFF; + tempch=(tempcx&0xFF00)>>8; + tempch=tempch&0x07; + tempah=tempah|tempch; + SiSSetReg1(Part1Port,0x20,tempah); + tempah=tempbx&0xFF; + SiSSetReg1(Part1Port,0x21,tempah); + tempecx=tempecx>>16; + temp1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + if (temp1&HalfDCLK) { + tempecx=tempecx>>1; + } + tempcx=(USHORT)(tempecx&0x0FFFF); + tempah=(tempcx&0xFF00)>>8; + SiSSetReg1(Part1Port,0x22,tempah); + tempah=tempcx&0x0FF; + SiSSetReg1(Part1Port,0x23,tempah); + if (SIS_IF_DEF_TRUMPION==1) { + tempal=(USHORT)*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x05)); + if (ModeNo>0x13) { + SiSSetFlag=SiSSetFlag|ProgrammingCRT2; + SiSGetRatePtrCRT2(ROMAddr,ModeNo); + tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+0x04)); + tempal=tempal&0x1F; + } + tempah=0x80; + tempal=tempal*tempah; + SiSREFIndex= offset_Zurac; + SiSREFIndex=SiSREFIndex+tempal; + SiSSetTPData(); + SiSSetTPData(); + SiSSetTPData(); + SiSSetTPData(); + SiSSetTPData(); + SiSSetTPData(); + SiSSetTPData(); + SiSSetTPData(); + SiSSetTPData(); + } + + SiSREFIndex=OldREFIndex; + return; +} + +VOID SiSSetTPData() +{ + return; +} + +VOID SiSSetGroup1_301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + USHORT temp1,temp2,tempcl,tempch,tempbl,tempbh,tempal,tempah,tempax,tempbx; + USHORT tempcx,OldREFIndex; + USHORT Part1Port; + Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; + OldREFIndex=(USHORT)SiSREFIndex; + + SiSSetCRT2Offset(Part1Port,ROMAddr); + SiSSetCRT2FIFO(Part1Port,ROMAddr,ModeNo,HwDeviceExtension); + SiSSetCRT2Sync(BaseAddr,ROMAddr,ModeNo); + + SiSGetCRT1Ptr(ROMAddr); + +#ifdef CONFIG_FB_SIS_315 + temp1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + if (temp1&HalfDCLK) { + temp1=(SiSVGAHT/2-1)&0x0FF; + SiSSetReg1(Part1Port,0x08,temp1); + temp1=(((SiSVGAHT/2-1)&0xFF00)>>8)<<4; + SiSSetRegANDOR(Part1Port,0x09,~0x0F0,temp1); + } else { + temp1=(SiSVGAHT-1)&0x0FF; + SiSSetReg1(Part1Port,0x08,temp1); + temp1=(((SiSVGAHT-1)&0xFF00)>>8)<<4; + SiSSetRegANDOR(Part1Port,0x09,~0x0F0,temp1); + } +#else + temp1=(SiSVGAHT-1)&0x0FF; + SiSSetReg1(Part1Port,0x08,temp1); + temp1=(((SiSVGAHT-1)&0xFF00)>>8)<<4; + SiSSetRegANDOR(Part1Port,0x09,~0x0F0,temp1); +#endif + + +#ifdef CONFIG_FB_SIS_315 + temp1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + if (temp1&HalfDCLK) + temp1=(SiSVGAHDE/2+16)&0x0FF; + else + temp1=(SiSVGAHDE+16)&0x0FF; + SiSSetReg1(Part1Port,0x0A,temp1); +#else + temp1=(SiSVGAHDE+12)&0x0FF; + SiSSetReg1(Part1Port,0x0A,temp1); +#endif + +#ifdef CONFIG_FB_SIS_315 + temp1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + if (temp1&HalfDCLK) { + temp1=SiSVGAHDE/2+16; + temp2=((SiSVGAHT-SiSVGAHDE)/2)>>2; + } else { + temp1=SiSVGAHDE+16; + temp2=(SiSVGAHT-SiSVGAHDE)>>2; + } + temp1=temp1+temp2; + temp2=temp2+temp1; +#else + temp1=SiSVGAHDE+12; + temp2=(SiSVGAHT-SiSVGAHDE)>>2; + temp1=temp1+temp2; + temp2=(temp2<<1)+temp1; +#endif + tempcl=temp2&0x0FF; + if (SiSVBInfo&SetCRT2ToRAMDAC) { + tempbl=*((UCHAR *)(ROMAddr+SiSREFIndex+4)); + tempbh=*((UCHAR *)(ROMAddr+SiSREFIndex+14)); + temp1=((tempbh>>6)<<8)|tempbl; + temp1=(temp1-1)<<3; + tempcl=*((UCHAR *)(ROMAddr+SiSREFIndex+5)); + tempch=*((UCHAR *)(ROMAddr+SiSREFIndex+15)); + tempcl=tempcl&0x01F; + tempch=(tempch&0x04)<<(6-2); + tempcl=((tempcl|tempch)-1)<<3; +#ifdef CONFIG_FB_SIS_315 + temp1 += 16; + tempcl += 16; + + temp2=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + if (temp2&HalfDCLK) { + if (tempcl>(SiSVGAHT/2)) + tempcl = SiSVGAHT/2; + } else { + if (tempcl>SiSVGAHT) + tempcl = SiSVGAHT; + } +#endif + } + SiSSetReg1(Part1Port,0x0B,(USHORT)(temp1&0x0FF)); + tempah=(temp1&0xFF00)>>8; + tempbh=((((SiSVGAHDE+12)&0xFF00)>>8)<<4)&0x0FF; + tempah=tempah|tempbh; + SiSSetReg1(Part1Port,0x0C,tempah); + SiSSetReg1(Part1Port,0x0D,tempcl); + tempcx=(SiSVGAVT-1); + tempah=tempcx&0x0FF; + SiSSetReg1(Part1Port,0x0E,tempah); + tempbx=SiSVGAVDE-1; + tempah=tempbx&0x0FF; + SiSSetReg1(Part1Port,0x0F,tempah); + tempah=((tempbx&0xFF00)<<3)>>8; + tempah=tempah|((tempcx&0xFF00)>>8); + SiSSetReg1(Part1Port,0x12,tempah); + + tempbx=(SiSVGAVT+SiSVGAVDE)>>1; + tempcx=((SiSVGAVT-SiSVGAVDE)>>4)+tempbx+1; + if (SiSVBInfo&SetCRT2ToRAMDAC) { + tempbx=*((UCHAR *)(ROMAddr+SiSREFIndex+8)); + temp1=*((UCHAR *)(ROMAddr+SiSREFIndex+7)); + if (temp1&0x04) { + tempbx=tempbx|0x0100; + } + if (temp1&0x080) { + tempbx=tempbx|0x0200; + } + temp1=*((UCHAR *)(ROMAddr+SiSREFIndex+13)); + if (temp1&0x08) { + tempbx=tempbx|0x0400; + } + tempcl= *((UCHAR *)(ROMAddr+SiSREFIndex+9)); + tempcx=(tempcx&0xFF00)|(tempcl&0x00FF); + } + tempah=tempbx&0x0FF; + SiSSetReg1(Part1Port,0x10,tempah); + tempbh=(tempbx&0xFF00)>>8; + tempah=((tempbh<<4)&0x0FF)|(tempcx&0x0F); + SiSSetReg1(Part1Port,0x11,tempah); + + if (HwDeviceExtension->jChipID == SIS_Glamour) { + tempah=0x10; + if ((SiSLCDResInfo!=Panel1024x768)&&(SiSLCDResInfo==Panel1280x1024)) { + tempah=0x20; + } + } else { + if (HwDeviceExtension->jChipID == SIS_GlamourII) { + tempah=0x10; + if ((SiSLCDResInfo!=Panel1024x768)&&(SiSLCDResInfo==Panel1280x1024)) { + tempah=0x20; + } + } + } + if (SiSVBInfo&SetCRT2ToTV) { + tempah=0x08; + } +#ifdef CONFIG_FB_SIS_315 + tempah >>=2; + SiSSetRegANDOR(Part1Port,0x2D,~0x00F,tempah); +#else + SiSSetRegANDOR(Part1Port,0x13,~0x03C,tempah); +#endif + +#ifdef CONFIG_FB_SIS_315 + SiSSetRegAND(Part1Port,0x13,0xEF); + tempah=0; + temp1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + if (temp1&DoubleScanMode) + tempah |= 0x80; + if (temp1&HalfDCLK) + tempah |= 0x80; + SiSSetRegANDOR(Part1Port,0x2C,~0x0C0,tempah); +#endif + + if (!(SiSVBInfo&SetInSlaveMode)) { + SiSREFIndex=OldREFIndex; + return; + } + if (SiSVBInfo&SetCRT2ToTV) { + tempax=0xFFFF; + } else { + tempax=SiSGetVGAHT2(); + } + tempcl=0x08; + temp1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + if (!(temp1&Charx8Dot)) { + tempcl=0x09; + } + if (tempax>=SiSVGAHT) { + tempax=SiSVGAHT; + } + if (temp1&HalfDCLK) { + tempax=tempax>>1; + } + tempax=(tempax/tempcl)-5; + tempbl=tempax; + + tempah=0xFF; + SiSSetReg1(Part1Port,0x03,tempah); + + tempax=SiSVGAHDE; + if (temp1&HalfDCLK) { + tempax=tempax>>1; + } + tempax=(tempax/tempcl)-1; + tempbh=tempax; + SiSSetReg1(Part1Port,0x04,tempax); + + tempah=tempbh; + if (SiSVBInfo&SetCRT2ToTV) { + tempah=tempah+2; + } + SiSSetReg1(Part1Port,0x05,tempah); + SiSSetReg1(Part1Port,0x06,0x03); + + tempcx=(tempbl+tempbh)>>1; + tempah=(tempcx&0xFF)+2; + + if (SiSVBInfo&SetCRT2ToTV) { + tempah=tempah-1; + if (!(temp1&HalfDCLK)) { + if ((temp1&Charx8Dot)) { + tempah=tempah+4; + if (SiSVGAHDE>=800) { + tempah=tempah-6; + } + } + } + } else { + if (!(temp1&HalfDCLK)) { + tempah=tempah-4; + if (SiSVGAHDE>=800) { + tempah=tempah-7; + if (SiSModeType==ModeEGA) { + if (SiSVGAVDE==1024) { + tempah=tempah+15; + if (SiSLCDResInfo!=Panel1280x1024) { + tempah=tempah+7; + } + } + } + if (SiSVGAHDE>=1280) { + tempah=tempah+28; + } + } + } + } + + SiSSetReg1(Part1Port,0x07,tempah); + + SiSSetReg1(Part1Port,0x08,0); + SiSSetReg1(Part1Port,0x18,0x03); + SiSSetReg1(Part1Port,0x19,0); + SiSSetReg1(Part1Port,0x09,0xFF); + + tempcx=0x121; + tempcl=0x21; + tempch=0x01; + tempbx=SiSVGAVDE; + if (tempbx==360) tempbx=350; + if (tempbx==375) tempbx=350; + if (tempbx==405) tempbx=400; + tempbx--; + tempah=tempbx&0x0FF; + SiSSetReg1(Part1Port,0x0E,tempah); + SiSSetReg1(Part1Port,0x10,tempah); + tempbh=(tempbx&0xFF00)>>8; + if (tempbh&0x01) { + tempcl=tempcl|0x0A; + } + tempah=0;tempal=0x0B; + if (temp1&DoubleScanMode) { + tempah=tempah|0x080; + } + if (tempbh&0x02) { + tempcl=tempcl|0x040; + tempah=tempah|0x020; + } + SiSSetReg1(Part1Port,0x0B,tempah); + if (tempbh&0x04) { + tempch=tempch|0x06; + } + + SiSSetReg1(Part1Port,0x11,0); + + tempax=SiSVGAVT-tempbx; + tempax=tempax>>2; + temp2=tempax; + tempax=tempax<<1; + tempbx=tempax+tempbx; + if ((SiSSetFlag&TVSimuMode)&&(SiSVBInfo&SetPALTV)&&(SiSVGAHDE==800)) { + tempbx=tempbx+40; + } + tempah=(tempbx&0x0FF); + SiSSetReg1(Part1Port,0x0C,tempah); + tempbh=(tempbx&0xFF00)>>8; + if (tempbh&0x01) { + tempcl=tempcl|0x04; + } + if (tempbh&0x02) { + tempcl=tempcl|0x080; + } + if (tempbh&0x04) { + tempch=tempch|0x08; + } + + tempax=temp2; + tempax=(tempax>>2)+1; + tempbx=tempbx+tempax; + tempah=(tempbx&0x0FF)&0x0F; + SiSSetReg1(Part1Port,0x0D,tempah); + tempbl=tempbx&0x0FF; + if (tempbl&0x10) { + tempch=tempch|0x020; + } + + tempah=tempcl; + SiSSetReg1(Part1Port,0x0A,tempah); + tempah=tempch; + SiSSetReg1(Part1Port,0x17,tempah); + tempax=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + tempah=(tempax&0xFF00)>>8; + tempah=(tempah>>1)&0x09; + SiSSetReg1(Part1Port,0x16,tempah); + SiSSetReg1(Part1Port,0x0F,0); + SiSSetReg1(Part1Port,0x12,0); + SiSSetReg1(Part1Port,0x1A,0); + + SiSREFIndex=OldREFIndex; +} + +#ifdef CONFIG_FB_SIS_315 +VOID SiSAutoThreshold (USHORT BaseAddr) +{ + USHORT temp1; + USHORT Part1Port; + Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; + temp1=SiSGetReg1(Part1Port,0x1); + temp1 |= 0x40; + SiSSetReg1(Part1Port,0x1,temp1); +} +#endif + +VOID SiSSetCRT2Offset(USHORT Part1Port,ULONG ROMAddr) +{ + USHORT offset; + if (SiSVBInfo&SetInSlaveMode) { + return; + } + offset=SiSGetOffset(ROMAddr); + SiSSetReg1(Part1Port,0x07,(USHORT)(offset&0xFF)); + SiSSetReg1(Part1Port,0x09,(USHORT)((offset&0xFF00)>>8)); + SiSSetReg1(Part1Port,0x03,(USHORT)(((offset>>3)&0xFF)+1)); +} + +USHORT SiSGetOffset(ULONG ROMAddr) +{ + USHORT tempal,temp1,colordepth; + tempal=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x03)); + tempal=(tempal>>8)&0xFF; + SiSScreenOffset=*((USHORT *)(ROMAddr+ScreenOffsetPtrOffset)); + tempal=*((UCHAR *)(ROMAddr+SiSScreenOffset+tempal)); + tempal=tempal&0xFF; + temp1=*((UCHAR *)(ROMAddr+SiSREFIndex)); + if (temp1&InterlaceMode) { + tempal=tempal<<1; + } + colordepth=SiSGetColorDepth(ROMAddr); + return(tempal*colordepth); +} + +USHORT SiSGetColorDepth(ULONG ROMAddr) +{ + USHORT ColorDepth[6]={1,2,4,4,6,8}; + USHORT temp; + int temp1; + temp=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + temp1=(temp&ModeInfoFlag)-ModeEGA; + if (temp1<0) temp1=0; + return(ColorDepth[temp1]); +} + +VOID SiSSetCRT2FIFO(USHORT Part1Port,ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + +#ifdef CONFIG_FB_SIS_315 + UCHAR CombCode[]={1,1,1,4,3,1,3,4,4,1,4,4,5,1,5,4}; + UCHAR CRT2ThLow[]={39,63,55,79,78,102,90,114,55,87,84,116,103,135,119,151}; + + USHORT temp,temp1,temp2,temp3; + USHORT CRT1ModeNo,CRT2ModeNo; + + SiSSetReg1(Part1Port,0x1,0x2B); + + CRT1ModeNo =ModeNo; + SiSSearchModeID(ROMAddr,CRT1ModeNo); + SiSSetFlag=SiSSetFlag|ProgrammingCRT2; + + SiSGetRatePtrCRT2(ROMAddr,CRT1ModeNo); + temp1=SiSGetVCLK(ROMAddr,CRT1ModeNo,HwDeviceExtension); + temp2=SiSGetColorTh(ROMAddr); + temp3=SiSGetMCLK(ROMAddr); + + temp=SiSGetReg1(SiSP3c4,0x14); + if (temp&0x02) + temp=16; + else + temp=8; + + temp = temp - temp1*temp2/temp3; + + if ((52*16 % temp)==0) + temp = 52*16/temp +40; + else + temp = 52*16/temp +40 + 1; + + temp1=(SiSGetReg1(SiSP3c4,0x17)>>3)&0x7; + temp2=(SiSGetReg1(SiSP3c4,0x17)>>6)&0x3; + + if (SiSGet310DRAMType(ROMAddr)<2) { + for (temp3=0;temp3<16;temp3+=2) { + if ((CombCode[temp3]==temp1) && (CombCode[temp3+1]==temp2)) { + temp3 = CRT2ThLow[temp3>>1]; + } + } + } else { + for (temp3=0;temp3<16;temp3+=2) { + if ((CombCode[temp3]==temp1) && (CombCode[temp3+1]==temp2)) { + temp3 = CRT2ThLow[8+(temp3>>1)]; + } + } + } + + temp += temp3; + + CRT2ModeNo=(UCHAR)SiSGetReg1(SiSP3d4,0x34); + temp1=SiSGetVCLK(ROMAddr,CRT1ModeNo,HwDeviceExtension); + temp2=SiSGetColorTh(ROMAddr); + temp3=SiSGetMCLK(ROMAddr); + + if ((temp*temp1*temp2)%(16*temp3)==0) + temp = temp*temp1*temp2/(16*temp3); + else + temp = temp*temp1*temp2/(16*temp3)+1; + + if (temp>0x27) + temp = 0x27; + + SiSSetRegANDOR(Part1Port,0x02,~0x3F,temp); + +#else + USHORT temp,temp1,temp2,temp3,flag; + USHORT vclk2ptr,latencyindex; + USHORT oldREFIndex,CRT1ModeNo,oldModeIDOffset; + long int longtemp; + + USHORT LatencyFactor[48]={ 88, 80, 78, 72, 70, 00, + 00, 79, 77, 71, 69, 49, + 88, 80, 78, 72, 70, 00, + 00, 72, 70, 64, 62, 44, + 73, 65, 63, 57, 55, 00, + 00, 64, 62, 56, 54, 34, + 78, 70, 68, 62, 60, 00, + 00, 62, 60, 54, 52, 34}; + + oldREFIndex=(USHORT)SiSREFIndex; + oldModeIDOffset=(USHORT)SiSModeIDOffset; + + CRT1ModeNo=(UCHAR)SiSGetReg1(SiSP3d4,0x34); + SiSSearchModeID(ROMAddr,CRT1ModeNo); + + SiSGetRatePtrCRT2(ROMAddr,CRT1ModeNo); + temp1=SiSGetVCLK(ROMAddr,CRT1ModeNo,HwDeviceExtension); + temp2=SiSGetColorTh(ROMAddr); + temp3=SiSGetMCLK(ROMAddr); + + temp=((USHORT)(temp1*temp2)/temp3); + temp1=(UCHAR)SiSGetReg1(SiSP3c4,0x14); + temp1=temp1>>6; + temp1=temp1<<1; + if (temp1==0) temp1=1; + temp1=temp1<<2; + + longtemp=temp1-temp; + + temp2=(USHORT)((28*16)/(int)longtemp); + if (!((temp2*(int)longtemp)==(28*16))) temp2++; + + if ( HwDeviceExtension->jChipID == SIS_Glamour ) { + temp1=SiSCalcDelay(); + } else { + flag=(UCHAR)SiSGetReg1(SiSP3c4,0x14); + if (flag&0x80) { + latencyindex=12; + } else { + latencyindex=0; + } + flag=SiSGetQueueConfig(); + if (!(flag&0x01)) { + latencyindex+=24; + } + if (flag&0x10) { + latencyindex+=6; + } + latencyindex=latencyindex + (flag>>5); + temp1= LatencyFactor[latencyindex]; + temp1=temp1+15; + flag=(UCHAR)SiSGetReg1(SiSP3c4,0x14); + if (!(flag&0x80)) { + temp1=temp1+5; + } + } + + temp2=temp2+temp1; + SiSREFIndex=oldREFIndex; + SiSModeIDOffset=oldModeIDOffset; + + vclk2ptr=SiSGetVCLK2Ptr(ROMAddr,ModeNo,HwDeviceExtension); + + temp1=*((USHORT *)(ROMAddr+vclk2ptr+(SiSVCLKLen-2))); + + temp3=SiSGetColorTh(ROMAddr); + longtemp=temp1*temp2*temp3; + temp3=SiSGetMCLK(ROMAddr); + temp3=temp3<<4; + temp2=(int)(longtemp/temp3); + if ((long int)temp2*(long int)temp3<(long int)longtemp) temp2++; + + temp1=(UCHAR)SiSGetReg1(Part1Port,0x01); + temp1=(temp1&(~0x1F))|0x16; + + if (HwDeviceExtension->jChipID >=SIS_Trojan) { + if (HwDeviceExtension->jChipRevision >=0x30) { + temp1=(temp1&(~0x1F))|0x19; + } + } + SiSSetReg1(Part1Port,0x01,temp1); + + if (temp2<=6) temp2=6; + if (temp2>0x14) temp2=0x14; + temp1=(UCHAR)SiSGetReg1(Part1Port,0x02); + temp1=(temp1&(~0x1F))|temp2; + SiSSetReg1(Part1Port,0x02,temp1); +#endif +} + +USHORT SiSGetVCLK(ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + USHORT tempptr; + USHORT temp1; + tempptr=SiSGetVCLKPtr(ROMAddr,ModeNo,HwDeviceExtension); + + temp1=*((USHORT *)(ROMAddr+tempptr+(SiSVCLKLen-2))); + + return temp1; +} + +USHORT SiSGetQueueConfig() +{ + USHORT tempal,tempbl; + ULONG tempeax; + + SiSSetReg4(0xcf8,0x80000050); + tempeax=SiSGetReg3(0xcfc); + tempeax=(tempeax>>24)&0x0f; + tempbl=(USHORT)tempeax; + tempbl=tempbl<<4; + + SiSSetReg4(0xcf8,0x800000A0); + tempeax=SiSGetReg3(0xcfc); + tempeax=(tempeax>>24)&0x0f; + tempal=(USHORT)tempeax; + tempbl=tempbl|tempal; + + return(tempbl); +} + +USHORT SiSGetVCLKPtr(ULONG ROMAddr,USHORT ModeNo,PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + USHORT tempal; + tempal=(UCHAR)SiSGetReg2((USHORT)(SiSP3ca+0x02)); + tempal=((tempal>>2)&0x03); + if (ModeNo>0x13) { + tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+0x03)); + tempal=tempal&0x03F; + } + SiSVCLKLen=SiSGetVCLKLen(ROMAddr,HwDeviceExtension); + tempal=tempal*SiSVCLKLen; + if (HwDeviceExtension->jChipID==SIS_GlamourII) + tempal=tempal+(*((USHORT *)(ROMAddr+VCLKDataPtrOffset))); + else + tempal=tempal+(*((USHORT *)(ROMAddr+VCLKDataPtrOffset))); + return ((USHORT)tempal); +} + +USHORT SiSGetColorTh(ULONG ROMAddr) +{ + USHORT temp; + temp=SiSGetColorDepth(ROMAddr); + temp=temp>>1; + if (temp==0) temp++; + return temp; +} + +USHORT SiSGetMCLK(ULONG ROMAddr) +{ + USHORT tempmclkptr; + USHORT tempmclk; + tempmclkptr=SiSGetMCLKPtr(ROMAddr); + tempmclk=*((USHORT *)(ROMAddr+tempmclkptr+0x03)); + return tempmclk; +} + +USHORT SiSGetMCLKPtr(ULONG ROMAddr) +{ + USHORT tempdi; + USHORT tempdramtype,tempax; + + tempdi=*((USHORT *)(ROMAddr+MCLKDataPtrOffset)); + + tempdramtype=SiSGetDRAMType(ROMAddr); + tempax=5*tempdramtype; + tempdi=tempdi+tempax; + return (tempdi); +} + +USHORT SiSGetDRAMType(ULONG ROMAddr) +{ + USHORT tsoftsetting,temp3; + tsoftsetting=*((UCHAR *)(ROMAddr+0x52)); + if (!(tsoftsetting&SoftDramType)) { + temp3=(UCHAR)SiSGetReg1(SiSP3c4,0x3A); + tsoftsetting=temp3; + } + tsoftsetting=tsoftsetting&0x07; + return(tsoftsetting); +} + +#if 0 +static USHORT SiSCalcDelay() +{ + USHORT tempal,tempah,temp1,tempbx; + USHORT ThTiming[8]={1,2,2,3,0,1,1,2}; + USHORT ThLowB[24]={81,4,72,6,88,8,120,12, + 55,4,54,6,66,8,90,12, + 42,4,45,6,55,8,75,12}; + + tempah=(UCHAR)SiSGetReg1(SiSP3c4,0x18); + tempah=tempah&0x62; + tempah=tempah>>1; + tempal=tempah; + tempah=tempah>>3; + tempal=tempal|tempah; + tempal=tempal&0x07; + + temp1=ThTiming[tempal]; + + tempbx=(UCHAR)SiSGetReg1(SiSP3c4,0x16); + tempbx=tempbx>>6; + tempah=(UCHAR)SiSGetReg1(SiSP3c4,0x14); + tempah=((tempah>>4)&0x0C); + tempbx=((tempbx|tempah)<<1); + + tempal=ThLowB[tempbx+1]*temp1; + tempbx=ThLowB[tempbx]; + tempbx=tempal+tempbx; + + return(tempbx); +} +#endif + + +USHORT SiSGetVCLK2Ptr(ULONG ROMAddr,USHORT ModeNo,PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + USHORT tempal; + USHORT LCDXlat1VCLK[4]={VCLK65,VCLK65,VCLK65,VCLK65}; + USHORT LCDXlat2VCLK[4]={VCLK108_2,VCLK108_2,VCLK108_2,VCLK108_2}; + + if (ModeNo<=0x13) { + tempal=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x04)); + } else { + tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+0x04)); + } + tempal=tempal>>6; + if (SiSLCDResInfo!=Panel1024x768) { + tempal=LCDXlat2VCLK[tempal]; + } else { + tempal=LCDXlat1VCLK[tempal]; + } + + if (SiSVBInfo&SetCRT2ToLCD) { + tempal=tempal; + } else if (SiSVBInfo&SetCRT2ToTV) { + if (SiSSetFlag&RPLLDIV2XO) { + tempal=TVVCLKDIV2; + } else { + tempal=TVVCLK; + } + } else { + tempal=(UCHAR)SiSGetReg2((USHORT)(SiSP3ca+0x02)); + tempal=((tempal>>2)&0x03); + if (ModeNo>0x13) { + tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+0x03)); + tempal=tempal&0x03F; + } + } + SiSVCLKLen=SiSGetVCLKLen(ROMAddr,HwDeviceExtension); + tempal=tempal*SiSVCLKLen; + if (HwDeviceExtension->jChipID==SIS_GlamourII) + tempal=tempal+(*((USHORT *)(ROMAddr+VCLKDataPtrOffset))); + else + tempal=tempal+(*((USHORT *)(ROMAddr+VCLKDataPtrOffset))); + return ((USHORT)tempal); +} + +USHORT SiSGetVCLKLen(ULONG ROMAddr,PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + USHORT VCLKDataStart,vclklabel,temp; + + if (HwDeviceExtension->jChipID==SIS_GlamourII) + VCLKDataStart=*((USHORT *)(ROMAddr+VCLKDataPtrOffset)); + else + VCLKDataStart=*((USHORT *)(ROMAddr+VCLKDataPtrOffset)); + + for(temp=0;;temp++) { + vclklabel=*((USHORT *)(ROMAddr+VCLKDataStart+temp)); + if (vclklabel==VCLKStartFreq) { + temp=temp+2; + return(temp); + } + } + return(0); +} + + +VOID SiSSetCRT2Sync(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo) +{ + USHORT temp1,tempah=0; + USHORT temp; + USHORT Part1Port; + Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; + if (SIS_IF_DEF_LVDS==1) { + if (SiSVBInfo&SetCRT2ToLCD) { + tempah=SiSLCDInfo; + if (!(tempah&LCDSync)) { + temp=*((USHORT *)(ROMAddr+SiSREFIndex)); + tempah=(temp>>8)&0x0C0; + } else { + tempah=tempah&0x0C0; + } + } + } else { + temp=*((USHORT *)(ROMAddr+SiSREFIndex)); + tempah=(temp>>8)&0x0C0; + } + temp1=(UCHAR)SiSGetReg1(Part1Port,0x19); + temp1=(temp1&(~0x0C0))|tempah; + SiSSetReg1(Part1Port,0x19,temp1); +} + +VOID SiSGetCRT1Ptr(ULONG ROMAddr) +{ + USHORT temprefcrt1; + USHORT temp; + temp=*((UCHAR *)(ROMAddr+SiSREFIndex+0x02)); + + temp=temp&0x03F; + + temp=temp*CRT1Len; + temprefcrt1=*((USHORT *)(ROMAddr+CRT1TablePtrOffset)); + SiSREFIndex=temprefcrt1+temp; +} + +VOID SiSSetRegAND(USHORT Port,USHORT Index,USHORT DataAND) +{ + USHORT temp1; + temp1=SiSGetReg1(Port,Index); + temp1= temp1&DataAND; + SiSSetReg1(Port,Index,temp1); +} + +VOID SiSSetRegOR(USHORT Port,USHORT Index,USHORT DataOR) +{ + USHORT temp1; + temp1=SiSGetReg1(Port,Index); + temp1= temp1|DataOR; + SiSSetReg1(Port,Index,temp1); +} + +VOID SiSSetRegANDOR(USHORT Port,USHORT Index,USHORT DataAND,USHORT DataOR) +{ + USHORT temp1; + temp1=SiSGetReg1(Port,Index); + temp1=(temp1&(DataAND))|DataOR; + SiSSetReg1(Port,Index,temp1); +} + +USHORT SiSGetVGAHT2() +{ + long int temp1,temp2; + temp1=(SiSVGAVT-SiSVGAVDE)*SiSRVBHCMAX; + temp1=temp1&0x0FFFF; + + temp2=(SiSVT-SiSVDE)*SiSRVBHCFACT; + temp2=temp2&0x0FFFF; + temp2=temp2*SiSHT; + temp2=temp2/temp1; + return((USHORT)temp2); +} + +VOID SiSSetGroup2(USHORT BaseAddr,ULONG ROMAddr) +{ + USHORT tempah,tempbl,tempbh,tempcl,i,j,tempcx,pushcx,tempbx,tempax; + USHORT tempmodeflag,tempflowflag; + UCHAR *temp1; + USHORT *temp2; + USHORT pushbx; + USHORT Part2Port; + long int longtemp; + ULONG PALPhase=0x00D3052A; + ULONG NTSCPhase=0x088AED21; + + Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; + + tempcx=SiSVBInfo; + tempah=SiSVBInfo&0x0FF; + tempbl=SiSVBInfo&0x0FF; + tempbh=SiSVBInfo&0x0FF; + tempbx=(tempbl&0xFF)|(tempbh<<8); + tempbl=tempbl&0x10; + tempbh=(tempbh&0x04)<<1; + + tempah=(tempah&0x08)>>1; + + tempah=tempah|tempbh; + tempbl=tempbl>>3; + + tempah=tempah|tempbl; + tempah=tempah^0x0C; + + if (SiSVBInfo&SetPALTV) { + temp1 = (UCHAR *)&PALPhase; + temp2= SiSPALTiming; + } else { + tempah=tempah|0x10; + temp1 =(UCHAR *)&NTSCPhase; + temp2=SiSNTSCTiming; + } + + SiSSetReg1(Part2Port,0x0,tempah); + for(i=0x31;i<=0x34;i++,temp1++) { + SiSSetReg1(Part2Port,i,*(UCHAR *)temp1); + } + for(i=0x01,j=0;i<=0x2D;i++,j++) { + SiSSetReg1(Part2Port,i,temp2[j]); + } + for(i=0x39;i<=0x45;i++,j++) { + SiSSetReg1(Part2Port,i,temp2[j]); + } + + tempah=SiSGetReg1(Part2Port,0x0A); + tempah=tempah|SiSNewFlickerMode; + SiSSetReg1(Part2Port,0x0A,tempah); + + SiSSetReg1(Part2Port,0x35,SiSRY1COE); + SiSSetReg1(Part2Port,0x36,SiSRY2COE); + SiSSetReg1(Part2Port,0x37,SiSRY3COE); + SiSSetReg1(Part2Port,0x38,SiSRY4COE); + + tempcx=SiSHT-1; + tempah=tempcx&0xFF; + SiSSetReg1(Part2Port,0x1B,tempah); + tempah=(tempcx&0xFF00)>>8; + SiSSetRegANDOR(Part2Port,0x1D,~0x0F,(UCHAR)tempah); + + tempcx=SiSHT>>1; + pushcx=tempcx; + + tempcx=tempcx+7; + + tempah=(tempcx&0xFF); + tempah=(tempah<<4)&0xFF; + SiSSetRegANDOR(Part2Port,0x22,~0x0F0,tempah); + + tempbx=temp2[j]; + tempbx=tempbx+tempcx; + tempah=tempbx&0xFF; + SiSSetReg1(Part2Port,0x24,tempah); + tempah=(tempbx&0xFF00)>>8; + tempah=(tempah<<4)&0xFF; + SiSSetRegANDOR(Part2Port,0x25,~0x0F0,tempah); + + tempbx=tempbx+8; + + tempah=((tempbx&0xFF)<<4)&0xFF; + SiSSetRegANDOR(Part2Port,0x29,~0x0F0,tempah); + + tempcx=tempcx+temp2[++j]; + tempah=tempcx&0xFF; + SiSSetReg1(Part2Port,0x27,tempah); + tempah=(((tempcx&0xFF00)>>8)<<4)&0xFF; + SiSSetRegANDOR(Part2Port,0x28,~0x0F0,tempah); + + tempcx=tempcx+8; + + tempah=tempcx&0xFF; + tempah=(tempah<<4)&0xFF; + SiSSetRegANDOR(Part2Port,0x2A,~0x0F0,tempah); + + tempcx=pushcx; + tempcx=tempcx-temp2[++j]; + tempah=tempcx&0xFF; + tempah=(tempah<<4)&0xFF; + SiSSetRegANDOR(Part2Port,0x2D,~0x0F0,tempah); + + tempcx=tempcx-11; + if (!(SiSVBInfo&SetCRT2ToTV)) { + tempax=SiSGetVGAHT2(); + tempcx=tempax-1; + } + tempah=tempcx&0xFF; + SiSSetReg1(Part2Port,0x2E,tempah); + + tempbx=SiSVDE; + if (SiSVGAVDE==360) { + tempbx=746; + } + if (SiSVGAVDE==375) { + tempbx=746; + } + if (SiSVGAVDE==405) { + tempbx=853; + } + + if ((SiSVBInfo&SetCRT2ToTV)) { + tempbx=tempbx>>1; + } + + tempbx=tempbx-2; + tempah=tempbx&0xFF; + SiSSetReg1(Part2Port,0x2F,tempah); + + tempah=(tempcx&0xFF00)>>8; + tempbh=(tempbx&0xFF00)>>8; + tempbh=(tempbh<<6)&0xFF; + tempah=tempah|tempbh; + + tempah=tempah|0x10; + if (!(SiSVBInfo&SetCRT2ToSVIDEO)) { + tempah=tempah|0x20; + } + + SiSSetReg1(Part2Port,0x30,tempah); + + tempbh=0; + tempbx=tempbx&0xFF; + + tempmodeflag=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + tempflowflag=0; + if (!(tempmodeflag&HalfDCLK)) { + tempcx=SiSVGAHDE; + if (tempcx>=SiSHDE) { + tempbh=tempbh|0x20; + tempbx=(tempbh<<8)|(tempbx&0xFF); + tempah=0; + } + } + + tempcx=0x0101; + + if (!(tempbh&0x20)) { + if (tempmodeflag&HalfDCLK) { + tempcl=((tempcx&0xFF)<<1)&0xFF; + tempcx=(tempcx&0xFF00)|tempcl; + } + pushbx=tempbx; + tempax=SiSVGAHDE; + tempbx=(tempcx&0xFF00)>>8; + longtemp=tempax*tempbx; + tempcx=tempcx&0xFF; + longtemp=longtemp/tempcx; + longtemp=longtemp*8*1024; + tempax=(USHORT)((longtemp)/SiSHDE); + if (tempax*SiSHDE<longtemp) { + tempax=tempax+1; + } else { + tempax=tempax; + } + tempbx=pushbx; + tempah=((tempax&0xFF00)>>8)&0x01F; + tempbh=tempbh|tempah; + tempah=tempax&0xFF; + } + + SiSSetReg1(Part2Port,0x44,tempah); + tempah=tempbh; + SiSSetRegANDOR(Part2Port,0x45,~0x03F,tempah); + + if (SiSVBInfo&SetCRT2ToTV) { + return; + } + + tempah=0x01; + if (SiSLCDResInfo==Panel1280x1024) { + if (SiSModeType==ModeEGA) { + if (SiSVGAHDE>=1024) { + tempah=0x02; + } + } + } + SiSSetReg1(Part2Port,0x0B,tempah); + + tempbx=SiSHDE-1; + tempah=tempbx&0xFF; + SiSSetReg1(Part2Port,0x2C,tempah); + tempah=(tempbx&0xFF00)>>8; + tempah=(tempah<<4)&0xFF; + SiSSetRegANDOR(Part2Port,0x2B,~0x0F0,tempah); + + tempbx=SiSVDE-1; + tempah=tempbx&0xFF; + SiSSetReg1(Part2Port,0x03,tempah); + tempah=((tempbx&0xFF00)>>8)&0x07; + SiSSetRegANDOR(Part2Port,0x0C,~0x07,tempah); + + tempcx=SiSVT-1; + tempah=tempcx&0xFF; + SiSSetReg1(Part2Port,0x19,tempah); + tempah=(tempcx&0xFF00)>>8; + tempah=(tempah<<5)&0xFF; + if (SiSLCDInfo&LCDRGB18Bit) { + tempah=tempah|0x10; + } + SiSSetReg1(Part2Port,0x1A,tempah); + + tempcx++; + if (SiSLCDResInfo==Panel1024x768) { + tempbx=768; + } else { + tempbx=1024; + } + + if (tempbx==SiSVDE) { + tempax=1; + } else { + tempax=tempbx; + tempax=(tempax-SiSVDE)>>1; + } + tempcx=tempcx-tempax; + tempbx=tempbx-tempax; + + tempah=tempcx&0xFF; + SiSSetReg1(Part2Port,0x05,tempah); + tempah=tempbx&0xFF; + SiSSetReg1(Part2Port,0x06,tempah); + + tempah=(tempbx&0xFF00)>>8; + tempah=(tempah<<3)&0xFF; + tempah=tempah|((tempcx&0xFF00)>>8); + + SiSSetReg1(Part2Port,0x02,tempah); + + tempcx=(SiSVT-SiSVDE)>>4; + tempbx=(SiSVT+SiSVDE)>>1; + tempah=tempbx&0xFF; + SiSSetReg1(Part2Port,0x04,tempah); + + tempah=(tempbx&0xFF00)>>8; + tempah=(tempah<<4)&0xFF; + tempbx=tempbx+tempcx+1; + tempbl=(tempbx&0x0F); + tempah=tempah|tempbl; + SiSSetReg1(Part2Port,0x01,tempah); + + tempah=SiSGetReg1(Part2Port,0x09); + tempah=tempah&0xF0; + SiSSetReg1(Part2Port,0x09,tempah); + + tempah=SiSGetReg1(Part2Port,0x0A); + tempah=tempah&0xF0; + SiSSetReg1(Part2Port,0x0A,tempah); + + tempcx=(SiSHT-SiSHDE)>>2; + tempbx=(SiSHDE+7); + tempah=tempbx&0xFF; + SiSSetReg1(Part2Port,0x23,tempah); + tempah=(tempbx&0xFF00)>>8; + SiSSetRegANDOR(Part2Port,0x25,~0x0F,tempah); + + SiSSetReg1(Part2Port,0x1F,0x07); + tempah=SiSGetReg1(Part2Port,0x20); + tempah=tempah&0x0F; + SiSSetReg1(Part2Port,0x20,tempah); + + tempbx=tempbx+tempcx; + tempah=tempbx&0xFF; + SiSSetReg1(Part2Port,0x1C,tempah); + tempah=(tempbx&0xFF00)>>8; + tempah=(tempah<<4)&0xFF; + SiSSetRegANDOR(Part2Port,0x1D,~0x0F0,tempah); + + tempbx=tempbx+tempcx; + tempah=tempbx&0xFF; + SiSSetReg1(Part2Port,0x21,tempah); + + tempah=SiSGetReg1(Part2Port,0x17); + tempah=tempah&0xFB; + SiSSetReg1(Part2Port,0x17,tempah); + + tempah=SiSGetReg1(Part2Port,0x18); + tempah=tempah&0xDF; + SiSSetReg1(Part2Port,0x18,tempah); + return; +} + +VOID SiSSetGroup3(USHORT BaseAddr) +{ + USHORT i; + USHORT *tempdi; + USHORT Part3Port; + Part3Port=BaseAddr+IND_SIS_CRT2_PORT_12; + + if (SiSVBInfo&SetPALTV) { + tempdi=SiSPALGroup3Data; + } else { + tempdi=SiSNTSCGroup3Data; + } + + for(i=0;i<=0x3E;i++) { + SiSSetReg1(Part3Port,i,tempdi[i]); + } + return; +} + +VOID SiSSetGroup4(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + USHORT Part4Port; + USHORT tempax,tempah,tempcx,tempbx,tempbh,tempch,tempmodeflag; + long int tempebx,tempeax,templong; + Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14; + + tempax=0x0c; + if (SiSVBInfo&SetCRT2ToTV) { + if (SiSVBInfo&SetInSlaveMode) { + if (!(SiSSetFlag&TVSimuMode)) { + SiSSetFlag=SiSSetFlag|RPLLDIV2XO; + tempax=tempax|0x04000; + } + } else { + SiSSetFlag=SiSSetFlag|RPLLDIV2XO; + tempax=tempax|0x04000; + } + } + + if (SiSLCDResInfo!=Panel1024x768) { + tempax=tempax|0x08000; + } + tempah=(tempax&0xFF00)>>8; + SiSSetReg1(Part4Port,0x0C,tempah); + + tempah=SiSRVBHCFACT; + SiSSetReg1(Part4Port,0x13,tempah); + + tempbx=SiSRVBHCMAX; + tempah=tempbx&0xFF; + SiSSetReg1(Part4Port,0x14,tempah); + tempbh=(((tempbx&0xFF00)>>8)<<7)&0xFF; + + tempcx=SiSVGAHT-1; + tempah=tempcx&0xFF; + SiSSetReg1(Part4Port,0x16,tempah); + tempch=(((tempcx&0xFF00)>>8)<<3)&0xFF; + tempbh=tempbh|tempch; + + tempcx=SiSVGAVT-1; + if (!(SiSVBInfo&SetCRT2ToTV)) { + tempcx=tempcx-5; + } + tempah=tempcx&0xFF; + SiSSetReg1(Part4Port,0x17,tempah); + tempbh=tempbh|((tempcx&0xFF00)>>8); + tempah=tempbh; + SiSSetReg1(Part4Port,0x15,tempah); + + tempcx=SiSVBInfo; + tempbx=SiSVGAHDE; + tempmodeflag=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + if (tempmodeflag&HalfDCLK) { + tempbx=tempbx>>1; + } + + if (SiSVBInfo&SetCRT2ToLCD) { + tempah=0; + if (tempbx>800) { + tempah=0x60; + } + } else { + tempah=0x080; + } + if (SiSLCDResInfo!=Panel1280x1024) { + tempah=tempah|0x0A; + } + + SiSSetRegANDOR(Part4Port,0x0E,~0xEF,tempah); + + tempebx=SiSVDE; + + tempcx=SiSRVBHRS; + tempah=tempcx&0xFF; + SiSSetReg1(Part4Port,0x18,tempah); + + tempeax=SiSVGAVDE; + tempcx=tempcx|0x04000; + tempeax=tempeax-tempebx; + if (tempeax<0) { + tempcx=tempcx^(0x04000); + tempeax=SiSVGAVDE; + } + + templong=(tempeax*256*1024)/tempebx; + if (tempeax*256*1024-templong*tempebx>0) { + tempebx=templong+1; + } else { + tempebx=templong; + } + + tempah=(USHORT)(tempebx&0xFF); + SiSSetReg1(Part4Port,0x1B,tempah); + tempah=(USHORT)((tempebx&0xFF00)>>8); + SiSSetReg1(Part4Port,0x1A,tempah); + tempebx=tempebx>>16; + tempah=(USHORT)(tempebx&0xFF); + tempah=(tempah<<4)&0xFF; + tempah=tempah|((tempcx&0xFF00)>>8); + SiSSetReg1(Part4Port,0x19,tempah); + + SiSSetCRT2VCLK(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension); +} + +VOID SiSSetCRT2VCLK(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + USHORT vclk2ptr; + USHORT tempah,temp1; + USHORT Part4Port; + Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14; + + vclk2ptr=SiSGetVCLK2Ptr(ROMAddr,ModeNo,HwDeviceExtension); + SiSSetReg1(Part4Port,0x0A,0x01); + tempah=*((UCHAR *)(ROMAddr+vclk2ptr+0x01)); + SiSSetReg1(Part4Port,0x0B,tempah); + tempah=*((UCHAR *)(ROMAddr+vclk2ptr+0x00)); + SiSSetReg1(Part4Port,0x0A,tempah); + SiSSetReg1(Part4Port,0x12,0x00); + tempah=0x08; + if (SiSVBInfo&SetCRT2ToRAMDAC) { + tempah=tempah|0x020; + } + temp1=SiSGetReg1(Part4Port,0x12); + tempah=tempah|temp1; + SiSSetReg1(Part4Port,0x12,tempah); +} + +VOID SiSSetGroup5(USHORT BaseAddr,ULONG ROMAddr) +{ + USHORT Part5Port; + USHORT Pindex,Pdata; + Part5Port=BaseAddr+IND_SIS_CRT2_PORT_14+2; + + Pindex=Part5Port; + Pdata=Part5Port+1; + if (SiSModeType==ModeVGA) { + if (!(SiSVBInfo&(SetInSlaveMode|LoadDACFlag|CRT2DisplayFlag))) { + SiSEnableCRT2(); + SiSLoadDAC2(ROMAddr,Part5Port); + } + } + return; +} + +VOID SiSEnableCRT2() +{ + USHORT temp1; + temp1=SiSGetReg1(SiSP3c4,0x1E); + temp1=temp1|0x20; + SiSSetReg1(SiSP3c4,0x1E,temp1); +} + +VOID SiSLoadDAC2(ULONG ROMAddr,USHORT Part5Port) +{ + USHORT data,data2; + USHORT time,i,j,k; + USHORT m,n,o; + USHORT si,di,bx,dl; + USHORT al,ah,dh; + USHORT *table=SIS_VGA_DAC; + USHORT Pindex,Pdata; + Pindex=Part5Port; + Pdata=Part5Port+1; + data=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + data=data&DACInfoFlag; + time=64; + if (data==0x00) table=SIS_MDA_DAC; + if (data==0x08) table=SIS_CGA_DAC; + if (data==0x10) table=SIS_EGA_DAC; + if (data==0x18) { + time=256; + table=SIS_VGA_DAC; + } + if (time==256) j=16; + else j=time; + + SiSSetReg3(Pindex,0x00); + + for(i=0;i<j;i++) { + data=table[i]; + for(k=0;k<3;k++) { + data2=0; + if (data&0x01) data2=0x2A; + if (data&0x02) data2=data2+0x15; + SiSSetReg3(Pdata,(USHORT)(data2)); + + data=data>>2; + } + } + + if (time==256) { + for(i=16;i<32;i++) { + data=table[i]; + for(k=0;k<3;k++) SiSSetReg3(Pdata,(USHORT)(data)); + } + si=32; + for(m=0;m<9;m++) { + di=si; + bx=si+0x04; + dl=0; + for(n=0;n<3;n++) { + for(o=0;o<5;o++) { + dh=table[si]; + ah=table[di]; + al=table[bx]; + si++; + SiSWriteDAC2(Pdata,dl,ah,al,dh); + } + si=si-2; + for(o=0;o<3;o++) { + dh=table[bx]; + ah=table[di]; + al=table[si]; + si--; + SiSWriteDAC2(Pdata,dl,ah,al,dh); + } + dl++; + } + si=si+5; + } + } +} + +VOID SiSWriteDAC2(USHORT Pdata,USHORT dl, USHORT ah, USHORT al, USHORT dh) +{ + USHORT temp; + USHORT bh,bl; + + bh=ah; + bl=al; + if (dl!=0) { + temp=bh; + bh=dh; + dh=temp; + if (dl==1) { + temp=bl; + bl=dh; + dh=temp; + } else { + temp=bl; + bl=bh; + bh=temp; + } + } + SiSSetReg3(Pdata,(USHORT)(dh)); + SiSSetReg3(Pdata,(USHORT)(bh)); + SiSSetReg3(Pdata,(USHORT)(bl)); +} + +VOID SiSLockCRT2(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr) +{ + USHORT Part1Port; + USHORT Part4Port; + USHORT temp1; + Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; + Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14; + if (HwDeviceExtension->jChipID == SIS_GlamourII) { + temp1=SiSGetReg1(Part1Port,0x2F); + temp1=temp1&0xFE; + SiSSetReg1(Part1Port,0x2F,temp1); + } + else if (HwDeviceExtension->jChipID == SIS_Glamour) { + temp1=SiSGetReg1(Part1Port,0x24); + temp1=temp1&0xFE; + SiSSetReg1(Part1Port,0x24,temp1); + } +} + +VOID SiSSetLockRegs() +{ + USHORT temp1; + + if ((SiSVBInfo&SetInSlaveMode)&&(!(SiSVBInfo&SetCRT2ToRAMDAC))) { + SiSVBLongWait(); + temp1=SiSGetReg1(SiSP3c4,0x32); + temp1=temp1|0x20; + SiSSetReg1(SiSP3c4,0x32,temp1); + SiSVBLongWait(); + } +} + +VOID SiSEnableBridge(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr) +{ + USHORT part2_02,part2_05; + USHORT Part2Port,Part1Port; + Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; + Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; + + if (SIS_IF_DEF_LVDS==0) { + SiSSetRegOR(Part1Port,0x2E,0x80); + part2_02=(UCHAR)SiSGetReg1(Part2Port,0x02); + part2_05=(UCHAR)SiSGetReg1(Part2Port,0x05); + SiSSetReg1(Part2Port,0x02,0x38); + SiSSetReg1(Part2Port,0x05,0xFF); + SiSLongWait(); + SiSSetRegANDOR(Part2Port,0x00,~0x0E0,0x020); + SiSWaitVBRetrace(HwDeviceExtension,BaseAddr); + SiSSetReg1(Part2Port,0x02,part2_02); + SiSSetReg1(Part2Port,0x05,part2_05); + SiSSetRegAND(Part1Port,0x00,0x7F); + } else { + SiSEnableCRT2(); + SiSUnLockCRT2(HwDeviceExtension,BaseAddr); + SiSSetRegANDOR(Part1Port,0x02,~0x040,0x0); + } +} + +USHORT SiSGetLockInfo(USHORT pattern) +{ + USHORT temp1; + + temp1=SiSGetReg1(SiSP3d4,0x36); + return(temp1&pattern); +} + +BOOLEAN SiSBridgeIsOn(USHORT BaseAddr) +{ + USHORT Part4Port; + USHORT flag1; + + Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14; + flag1=SiSGetReg1(Part4Port,0); + if ((flag1!=1)&&(flag1!=2)&&(flag1!=3)) + return FALSE; + else + return (BOOLEAN)flag1; +} + +VOID SiSGetVBInfo301(USHORT BaseAddr,ULONG ROMAddr) +{ + USHORT flag1,tempbx,tempbl,tempbh,tempah; + + SiSSetFlag=0; + tempbx=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + tempbl=tempbx&ModeInfoFlag; + SiSModeType=tempbl; + tempbx=0; + + if (!SiSBridgeIsOn(BaseAddr)) { + SiSVBInfo=CRT2DisplayFlag; + return; + } + tempbl=SiSGetReg1(SiSP3d4,0x30); + tempbh=SiSGetReg1(SiSP3d4,0x31); + + if (!(tempbl&0x07C)) { + SiSVBInfo=CRT2DisplayFlag; + return; + } + if (SIS_IF_DEF_LVDS==1) { + if (!(tempbl&SetCRT2ToLCD)) { + SiSVBInfo=CRT2DisplayFlag; + return; + } + } + if (SIS_IF_DEF_LVDS==0) { + if (tempbl&SetCRT2ToRAMDAC) { + tempbl=tempbl&(SetCRT2ToRAMDAC|SwitchToCRT2|SetSimuScanMode); + } else if (tempbl&SetCRT2ToLCD) { + tempbl=tempbl&(SetCRT2ToLCD|SwitchToCRT2|SetSimuScanMode); + } else if (tempbl&SetCRT2ToSCART) { + tempbl=tempbl&(SetCRT2ToSCART|SwitchToCRT2|SetSimuScanMode); + } else if (tempbl&SetCRT2ToHiVisionTV) { + tempbl=tempbl&(SetCRT2ToHiVisionTV|SwitchToCRT2|SetSimuScanMode); + } + } else { + if (tempbl&SetCRT2ToLCD) { + tempbl=tempbl&(SetCRT2ToLCD|SwitchToCRT2|SetSimuScanMode); + } + } + tempah=SiSGetReg1(SiSP3d4,0x31); + if (tempah&(CRT2DisplayFlag>>8)) { + if (!(tempbl&(SwitchToCRT2|SetSimuScanMode))) { + tempbx=SetSimuScanMode|CRT2DisplayFlag; + tempbh=((tempbx&0xFF00)>>8); + tempbl=tempbx&0xFF; + } + } + if (!(tempbh&(DriverMode>>8))) { + tempbl=tempbl|SetSimuScanMode; + } + SiSVBInfo=tempbl|(tempbh<<8); + if (!(SiSVBInfo&SetSimuScanMode)) { + if (!(SiSVBInfo&SwitchToCRT2)) { + if (SiSBridgeIsEnable(BaseAddr)) { + if (SiSBridgeInSlave()) { + SiSVBInfo=SiSVBInfo|SetSimuScanMode; + } + } + } + } + if (!((SiSVBInfo&(SetSimuScanMode|SwitchToCRT2)))) { + return; + } + if (!(SiSVBInfo&DriverMode)) { + SiSVBInfo=SiSVBInfo|SetInSlaveMode; + if ((SiSVBInfo&SetCRT2ToTV)&&(!(SiSVBInfo&SetNotSimuTVMode))) { + SiSSetFlag=SiSSetFlag|TVSimuMode; + } + return; + } + flag1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + if (!(flag1&(CRT2Mode|CRT2DisplayFlag))) { + SiSVBInfo=SiSVBInfo|SetInSlaveMode; + if ((SiSVBInfo&SetCRT2ToTV)&&(!(SiSVBInfo&SetNotSimuTVMode))) { + SiSSetFlag=SiSSetFlag|TVSimuMode; + } + } +} + +BOOLEAN SiSBridgeIsEnable(USHORT BaseAddr) +{ + USHORT flag1; + USHORT Part1Port; + Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; + + if (SIS_IF_DEF_LVDS==1) { + return 1; + } + if (!SiSBridgeIsOn(BaseAddr)) + return 0; + + flag1=SiSGetReg1(Part1Port,0x0); + if (flag1&0x0a0) { + return 1; + } else { + return 0; + } +} + +BOOLEAN SiSBridgeInSlave() +{ + USHORT flag1; + flag1=SiSGetReg1(SiSP3d4,0x31); + if (flag1&(SetInSlaveMode>>8)) { + return 1; + } else { + return 0; + } +} + +BOOLEAN SiSGetLCDResInfo301(ULONG ROMAddr,USHORT SiSP3d4) +{ + USHORT tempah,tempbh,tempflag; + + tempah=(UCHAR)SiSGetReg1(SiSP3d4,0x36); + tempbh=tempah; + tempah=tempah&0x0F; + + if (tempah>Panel1280x1024) tempah=Panel1024x768; + SiSLCDResInfo=tempah; + tempbh=tempbh>>4; + SiSLCDTypeInfo=tempbh; + + tempah=(UCHAR)SiSGetReg1(SiSP3d4,0x37); + SiSLCDInfo=tempah; + if (SIS_IF_DEF_TRUMPION) { + SiSLCDInfo=SiSLCDInfo&(~LCDNonExpanding); + } + if (SIS_IF_DEF_LVDS==1) { + tempflag=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + if (tempflag&HalfDCLK) { + if (SIS_IF_DEF_TRUMPION==0) { + if (!(SiSLCDInfo&LCDNonExpanding)) { + if (SiSLCDResInfo==Panel1024x768) { + tempflag=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x0a)); + if (tempflag==4) { + SiSSetFlag=SiSSetFlag|EnableLVDSDDA; + } + } else { + if (SiSLCDResInfo==Panel800x600) { + tempflag=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x0a)); + if (tempflag==3) { + SiSSetFlag=SiSSetFlag|EnableLVDSDDA; + } + } + } + } else { + SiSSetFlag=SiSSetFlag|EnableLVDSDDA; + } + } else { + SiSSetFlag=SiSSetFlag|EnableLVDSDDA; + } + } + } + + if (!(SiSVBInfo&SetCRT2ToLCD)) { + return 1; + } + if (!(SiSVBInfo&(SetSimuScanMode|SwitchToCRT2))) { + return 1; + } + if (SiSVBInfo&SetInSlaveMode) { + if (SiSVBInfo&SetNotSimuTVMode) { + SiSSetFlag=SiSSetFlag|LCDVESATiming; + } + } else { + SiSSetFlag=SiSSetFlag|LCDVESATiming; + } + return 1; +} + +VOID SiSPresetScratchregister301(USHORT SiSP3d4,PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + SiSSetReg1(SiSP3d4,0x37,0x00); +} + +BOOLEAN SiSGetLCDDDCInfo301(PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + USHORT tempah=0; + + + tempah=(HwDeviceExtension->usLCDType); + if (tempah>0) tempah++; + + SiSSetReg1(SiSP3d4,0x36,tempah); + if (tempah>0) return 1; + else return 0; +} + +VOID SiSSetTVSystem301(PHW_DEVICE_EXTENSION HwDeviceExtension,ULONG ROMAddr) +{ + USHORT tempah,temp; + if (SIS_IF_DEF_LVDS==0) { + if (PRIMARY_VGA==1) { + if (HwDeviceExtension->jChipID >= SIS_Trojan) { + tempah=SiSGetReg1(SiSP3c4,0x17); + if (tempah&ModeSwitchStatus) { + tempah=SiSGetReg1(SiSP3c4,0x16); + tempah=tempah&ActivePAL; + tempah=tempah>>ActivePALShift; + } else { + temp=*((UCHAR *)(ROMAddr+SoftSettingAddr)); + if (temp&SoftTVType) { + tempah=*((UCHAR *)(ROMAddr+ModeSettingAddr)); + } else { + tempah=SiSGetReg1(SiSP3c4,0x38); + } + } + } else { + temp=*((UCHAR *)(ROMAddr+SoftSettingAddr)); + if (temp&SoftTVType) { + tempah=*((UCHAR *)(ROMAddr+ModeSettingAddr)); + } else { + tempah=SiSGetReg1(SiSP3c4,0x38); + } + } + tempah=tempah&0x01; + + SiSSetRegANDOR(SiSP3d4,0x31,~0x01,tempah); + } + else { + tempah=SiSGetReg1(SiSP3c4,0x38); + tempah=tempah&0x01; + + SiSSetRegANDOR(SiSP3d4,0x31,~0x01,tempah); + } + return; + } else { + tempah=SiSGetReg1(SiSP3c4,0x16); + tempah=tempah&ActiveNonExpanding; + tempah=tempah>>ActiveNonExpandingShift; + tempah=tempah&0x01; + tempah=tempah<<LCDNonExpandingShift; + SiSSetRegANDOR(SiSP3d4,0x37,~LCDNonExpanding,tempah); + return; + } +} +BOOLEAN SiSGetSenseStatus301(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr) +{ + USHORT flag1,tempbx,tempal,tempah,tempcx,i; + USHORT Part2Port,Part4Port; + USHORT RGBSenseData,YCSenseData,VideoSenseData; + USHORT P2reg0,SenseModeNo,OutputSelect; + Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; + Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14; + + RGBSenseData=*((USHORT *)(ROMAddr+RGBSenseDataOffset)); + YCSenseData=*((USHORT *)(ROMAddr+YCSenseDataOffset)); + VideoSenseData=*((USHORT *)(ROMAddr+VideoSenseDataOffset)); + + if (SIS_IF_DEF_LVDS==1) { + SiSGetPanelID(); + tempah=LCDSense; + SiSSetRegANDOR(SiSP3d4,0x32,~0x5F,tempah); + return 0; + } + + if (!SiSBridgeIsOn(BaseAddr)) + return 0; + + P2reg0=SiSGetReg1(Part2Port,0x00); + + if (!(SiSBridgeIsEnable(BaseAddr))) { + SenseModeNo=0x2E; + + SiSModeType=ModeVGA; + SiSVBInfo=SetCRT2ToRAMDAC; + SiSSetFlag=0; + SiSSetCRT2Group301(BaseAddr,ROMAddr,SenseModeNo,HwDeviceExtension); + + for(i=0;i<0x7FFF;i++) { + flag1=SiSGetReg1(SiSP3c4,0x05); + } + } + + SiSSetReg1(Part2Port,0x00,0x1C); + tempah=0; + + OutputSelect=*((UCHAR *)(ROMAddr+OutputSelectOffset)); + + if (OutputSelect&SetSCARTOutput) { + tempal=SCARTSense; + } else { + tempal=Monitor2Sense; + } + tempbx=RGBSenseData; + tempcx=0x0E08; + if (SiSSense(Part4Port,tempbx,tempcx)) { + if (SiSSense(Part4Port,tempbx,tempcx)) { + tempah=tempah|tempal; + } + } + tempbx=YCSenseData; + tempcx=0x0604; + if (SiSSense(Part4Port,tempbx,tempcx)) { + if (SiSSense(Part4Port,tempbx,tempcx)) { + tempah=tempah|SVIDEOSense; + } + } + + if (OutputSelect&BoardTVType) { + tempbx=VideoSenseData; + tempcx=0x0804; + if (SiSSense(Part4Port,tempbx,tempcx)) { + if (SiSSense(Part4Port,tempbx,tempcx)) { + tempah=tempah|AVIDEOSense; + } + } + } else { + if (!(tempah&SVIDEOSense)) { + tempbx=VideoSenseData; + tempcx=0x0804; + if (SiSSense(Part4Port,tempbx,tempcx)) { + if (SiSSense(Part4Port,tempbx,tempcx)) { + tempah=tempah|AVIDEOSense; + } + } + } + } + + if (SiSSenseLCD(HwDeviceExtension,Part4Port,ROMAddr)) { + if (SiSSenseLCD(HwDeviceExtension,Part4Port,ROMAddr)) { + tempah=tempah|LCDSense; + } + } + + tempbx=0; + tempcx=0; + SiSSense(Part4Port,tempbx,tempcx); + + SiSSetRegANDOR(SiSP3d4,0x32,~0x5F,tempah); + SiSSetReg1(Part2Port,0x00,P2reg0); + + return 0; +} + +BOOLEAN SiSSense(USHORT Part4Port,USHORT inputbx,USHORT inputcx) +{ + USHORT tempah,tempcl,tempch; + + tempah=inputbx&0xFF; + SiSSetReg1(Part4Port,0x11,tempah); + tempah=(inputbx&0xFF00)>>8; + tempcl=inputcx&0xFF; + tempah=tempah|tempcl; + SiSSetRegANDOR(Part4Port,0x10,~0x1F,tempah); + + tempch=(inputcx&0xFF00)>>8; + tempch=tempch&0x7F; + + tempah=SiSGetReg1(Part4Port,0x03); + tempah=tempah^(0x0E); + tempah=tempah&tempch; + if (tempah>0) return 1; + else return 0; +} + +BOOLEAN SiSSenseLCD(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT Part4Port,ULONG ROMAddr) +{ + USHORT SoftSetting; + USHORT tempah; + + SoftSetting=*((UCHAR *)(ROMAddr+SoftSetting_OFFSET)); + if (SiSGetLCDDDCInfo301(HwDeviceExtension)) { + return 1; + } + if (SoftSetting&HotPlugFunction) { + tempah=SiSGetReg1(Part4Port,0x0F); + tempah=tempah&0x3F; + SiSSetReg1(Part4Port,0x0F,tempah); + if (SiSSense(Part4Port,0x0,0x9010)) { + return 1; + } else { + return 0; + } + } else { + return 0; + } +} + +BOOLEAN SiSDetectMonitor301(PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + USHORT flag1; + USHORT DAC_TEST_PARMS[3]={0x0F,0x0F,0x0F}; + USHORT DAC_CLR_PARMS[3]={0x00,0x00,0x00}; + + if (SiSBridgeIsOn( (USHORT) HwDeviceExtension->IOAddress)) + SiSSetReg1(SiSP3d4,0x30,0x41); + + SiSSetMode310(HwDeviceExtension,0x2E); + + SiSClearDAC(SiSP3c8); + SiSClearALLBuffer(HwDeviceExtension); + + SiSLongWait(); + SiSLongWait(); + + flag1=SiSTestMonitorType(DAC_TEST_PARMS[0],DAC_TEST_PARMS[1], + DAC_TEST_PARMS[2]); + if (flag1==0) { + flag1=SiSTestMonitorType(DAC_TEST_PARMS[0],DAC_TEST_PARMS[1], + DAC_TEST_PARMS[2]); + } + if (flag1==1) { + SiSSetRegANDOR(SiSP3d4,0x32,~Monitor1Sense,Monitor1Sense); + } else { + SiSSetRegANDOR(SiSP3d4,0x32,~Monitor1Sense,0x0); + } + SiSTestMonitorType(DAC_CLR_PARMS[0],DAC_CLR_PARMS[1], DAC_CLR_PARMS[2]); + + SiSSetReg1(SiSP3d4,0x34,0x4A); + + return 1; +} + +#if 0 +VOID SiSClearALLBuffer(PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + PVOID VideoMemoryAddress = (PVOID)HwDeviceExtension->pjVideoMemoryAddress; + ULONG AdapterMemorySize; + + AdapterMemorySize=SiSGetReg1(SiSP3c4,0x14); + AdapterMemorySize=AdapterMemorySize&0x3F; + AdapterMemorySize++; + VideoPortZeroMemory(VideoMemoryAddress, AdapterMemorySize*1024*1024); +} +#endif + +BOOLEAN SiSTestMonitorType(USHORT d1,USHORT d2,USHORT d3) +{ + USHORT temp; + SiSSetReg3(SiSP3c6,0xFF); + SiSSetReg3(SiSP3c8,0x00); + SiSSetReg3(SiSP3c9,d1); + SiSSetReg3(SiSP3c9,d2); + SiSSetReg3(SiSP3c9,d3); + SiSWaitDisplay(); + temp=SiSGetReg2(SiSP3c2); + if (temp&0x10) return 1; + else return 0; +} + +VOID SiSWaitDisplay() +{ + USHORT temp; + + for(temp=0;temp==0;) { + temp=SiSGetReg2(SiSP3da); + temp=temp&0x01; + } + for(;temp==1;) { + temp=SiSGetReg2(SiSP3da); + temp=temp&0x01; + } +} + +VOID SiSLongWait() +{ + USHORT temp,temp1; + + for(temp=1;temp>0;) { + temp=SiSGetReg2(SiSP3da); + temp=temp&0x08; + } + for(temp1=0;temp1<0xffff;temp1++) { + temp=SiSGetReg2(SiSP3da); + temp=temp&0x08; + if (temp!=0) + break; + } +} + +VOID SiSVBLongWait() +{ + USHORT regsr1f,tempah,temp; + + regsr1f=SiSGetReg1(SiSP3c4,0x1F); + tempah=regsr1f&(~0xC0); + SiSSetReg1(SiSP3c4,0x1F,tempah); + + for(temp=1;temp>0;) { + temp=SiSGetReg2(SiSP3da); + temp=temp&0x08; + } + for(;temp==0;) { + temp=SiSGetReg2(SiSP3da); + temp=temp&0x08; + } + + SiSSetReg1(SiSP3c4,0x1F,regsr1f); + return; +} + +BOOLEAN SiSWaitVBRetrace(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr) +{ + USHORT temp; + USHORT Part1Port; + Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; + + switch (HwDeviceExtension->jChipID) { + case SIS_Glamour: + temp=SiSGetReg1(Part1Port,0x00); + if (!(temp&0x80)) { + return 0; + } + + for(temp=0;temp==0;) { + temp=SiSGetReg1(Part1Port,0x25); + temp=temp&0x01; + } + for(;temp>0;) { + temp=SiSGetReg1(Part1Port,0x25); + temp=temp&0x01; + } + break; + case SIS_GlamourII: + temp=SiSGetReg1(Part1Port,0x00); + if (!(temp&0x40)) { + return 0; + } + + for(temp=0;temp==0;) { + temp=SiSGetReg1(Part1Port,0x30); + temp=temp&0x01; + } + for(;temp>0;) { + temp=SiSGetReg1(Part1Port,0x30); + temp=temp&0x01; + } + break; + case SIS_Trojan: + case SIS_Spartan: + case SIS_730: + case SIS_315: + case SIS_UNKNOWN: + case SIS_550: + case MAX_SIS_CHIP: + break; + } + return 1; +} + +BOOLEAN SiSGetPanelID() +{ + USHORT PanelTypeTable[16]={ SyncPP|Panel800x600|PanelType00, + SyncPP|Panel1024x768|PanelType01, + SyncPP|Panel1024x768|PanelType02, + SyncPP|Panel1024x768|PanelType03, + SyncPP|Panel1024x768|PanelType04, + SyncPP|Panel1024x768|PanelType05, + SyncPP|Panel1024x768|PanelType06, + SyncPP|Panel1024x768|PanelType07, + SyncPP|Panel1024x768|PanelType08, + SyncPP|Panel1024x768|PanelType09, + SyncPP|Panel800x600|PanelType0A, + SyncPP|Panel1024x768|PanelType0B, + SyncPP|Panel1024x768|PanelType0C, + SyncPP|Panel1024x768|PanelType0D, + SyncPP|Panel1024x768|PanelType0E, + SyncPP|Panel1024x768|PanelType0F}; + + USHORT tempah,tempbx; + USHORT return_flag; + + tempah=SiSGetReg1(SiSP3c4,0x18); + tempbx=tempah&0x0F; + if (tempah&0x10) { + return_flag=1; + } else { + return_flag=0; + } + + if (return_flag==0) { + if (SIS_IF_DEF_LVDS==1) { + tempbx=0; + tempah=SiSGetReg1(SiSP3c4,0x38); + if (tempah&0x40) tempbx=tempbx|0x08; + if (tempah&0x20) tempbx=tempbx|0x02; + if (tempah&0x01) tempbx=tempbx|0x01; + tempah=SiSGetReg1(SiSP3c4,0x39); + if (tempah&0x80) tempbx=tempbx|0x04; + } else { + return 0; + } + } + + if (SIS_IF_DEF_TRUMPION==1) { + tempbx=1; + } + tempbx=PanelTypeTable[tempbx]; + tempbx=tempbx|(USHORT)(LCDSync<<8); + + tempah=tempbx&0x0FF; + SiSSetReg1(SiSP3d4,0x36,tempah); + tempah=(tempbx&0xFF00)>>8; + SiSSetRegANDOR(SiSP3d4,0x37,~LCDSyncBit,tempah); + return 1; +} + +VOID SiSModCRT1CRTC(ULONG ROMAddr,USHORT ModeNo) +{ + USHORT OldREFIndex,temp,tempah,i,modeflag1; + + OldREFIndex=(USHORT)SiSREFIndex; + temp=SiSGetLVDSCRT1Ptr(ROMAddr,ModeNo); + if (temp==0) { + SiSREFIndex=OldREFIndex; + return; + } + tempah=(UCHAR)SiSGetReg1(SiSP3d4,0x11); + tempah=tempah&0x7F; + SiSSetReg1(SiSP3d4,0x11,tempah); + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex)); + SiSSetReg1(SiSP3d4,0x0,tempah); + SiSREFIndex++; + for(i=0x02;i<=0x05;SiSREFIndex++) { + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex)); + SiSSetReg1(SiSP3d4,i,tempah); + } + for(i=0x06;i<=0x07;SiSREFIndex++) { + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex)); + SiSSetReg1(SiSP3d4,i,tempah); + } + for(i=0x10;i<=0x11;SiSREFIndex++) { + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex)); + SiSSetReg1(SiSP3d4,i,tempah); + } + for(i=0x15;i<=0x16;SiSREFIndex++) { + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex)); + SiSSetReg1(SiSP3d4,i,tempah); + } + + for(i=0x0A;i<=0x0C;SiSREFIndex++) { + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex)); + SiSSetReg1(SiSP3c4,i,tempah); + } + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex)); + tempah=tempah&0x0E0; + SiSSetReg1(SiSP3c4,0x0E,tempah); + + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex)); + tempah=tempah&0x01; + tempah=tempah<<5; + modeflag1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + if (modeflag1&DoubleScanMode) { + tempah=tempah|0x080; + } + SiSSetRegANDOR(SiSP3d4,0x09,~0x020,tempah); + SiSREFIndex=OldREFIndex; + return; +} + +VOID SiSSetCRT2ECLK(ULONG ROMAddr, USHORT ModeNo,PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + USHORT OldREFIndex,tempah,tempal; + USHORT P3cc=SiSP3c9+3; + OldREFIndex=(USHORT)SiSREFIndex; + if (SIS_IF_DEF_TRUMPION==0) { + tempal=SiSGetReg2(P3cc); + tempal=tempal&0x0C; + SiSSetReg3(SiSP3c2,tempal); + SiSREFIndex=SiSGetVCLKPtr(ROMAddr,ModeNo,HwDeviceExtension); + } else { + SiSSetFlag=SiSSetFlag&(~ProgrammingCRT2); + tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+0x03)); + + tempal=tempal&0x03F; + + if (tempal==0x02) { + SiSREFIndex=SiSREFIndex-Ext2StructSize; + } + SiSREFIndex=SiSGetVCLKPtr(ROMAddr,ModeNo,HwDeviceExtension); + SiSSetFlag=SiSSetFlag|ProgrammingCRT2; + } + tempal=0x02B; + if (!(SiSVBInfo&SetInSlaveMode)) { + tempal=tempal+3; + } + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex)); + SiSSetReg1(SiSP3c4,tempal,tempah); + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex+1)); + tempal++; + SiSSetReg1(SiSP3c4,tempal,tempah); + SiSREFIndex=OldREFIndex; + return; +} + +USHORT SiSGetLVDSDesPtr(ULONG ROMAddr,USHORT ModeNo) +{ + USHORT tempcl,tempbx,tempal,tempptr,LVDSDesPtrData; + tempcl=LVDSDesDataLen; + tempbx=SiSLCDTypeInfo; + if (SiSLCDInfo&LCDNonExpanding) { + tempbx=tempbx+16; + } + if (ModeNo<=0x13) { + tempal=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x04)); + } else { + tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+4)); + } + tempal=tempal&0x1F; + tempal=tempal*tempcl; + tempbx=tempbx<<1; + LVDSDesPtrData=*((USHORT *)(ROMAddr+ADR_LVDSDesPtrData)); + tempptr=*((USHORT *)(ROMAddr+LVDSDesPtrData+tempbx)); + tempptr=tempptr+tempal; + return(tempptr); +} + +BOOLEAN SiSGetLVDSCRT1Ptr(ULONG ROMAddr,USHORT ModeNo) +{ + USHORT tempal,tempbx,modeflag1; + USHORT LVDSCRT1DataPtr; + + if (!(SiSVBInfo&SetInSlaveMode)) { + return 0; + } + if (ModeNo<=0x13) { + tempal=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x04)); + } else { + tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+4)); + } + tempal=tempal&0x3F; + + tempbx=SiSLCDResInfo; + tempbx=tempbx-Panel800x600; + if (SiSLCDInfo&LCDNonExpanding) { + tempbx=tempbx+6; + } + modeflag1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + if (modeflag1&HalfDCLK) { + tempbx=tempbx+3; + } + tempbx=tempbx<<1; + LVDSCRT1DataPtr=*((USHORT *)(ROMAddr+ADR_LVDSCRT1DataPtr)); + SiSREFIndex=*((USHORT *)(ROMAddr+LVDSCRT1DataPtr+tempbx)); + tempal=tempal*LVDSCRT1Len; + SiSREFIndex=SiSREFIndex+tempal; + return 1; +} + +USHORT SiSGetLCDPtrIndex (VOID) +{ + USHORT index; + + index = (SiSLCDResInfo & 0x0F)-1; + index *= 3; + if (SiSLCDInfo&LCDNonExpanding) + index += 2; + else { + if (!(SiSLCDInfo&LCDVESATiming)) + index++; + } + + return index; +} + +USHORT SiSGetTVPtrIndex(VOID) +{ + USHORT index; + + index = 0; + if (SiSVBInfo&SetPALTV) + index++; + if (SiSVBInfo&SetCRT2ToHiVisionTV) + index++; + index *= 2; + + if ((SiSVBInfo&SetInSlaveMode)&&(SiSSetFlag&TVSimuMode)) + index++; + + return index; +} + + +VOID SiSSetDelayComp(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo) +{ + USHORT Part1Port; + USHORT delay,index; + + if (SiSVBInfo&SetCRT2ToRAMDAC) { + index =*((USHORT *)(ROMAddr+CRT2Delay1Offset)); + delay =*((USHORT *)(ROMAddr+index)); + } else { + if (SiSVBInfo&SetCRT2ToLCD) { + index = SiSGetLCDPtrIndex(); + delay =*((USHORT *)(ROMAddr+LCDDelayPtr1Offset)); + delay =*((USHORT *)(ROMAddr+delay+index)); + } else { + index = SiSGetTVPtrIndex(); + delay =*((USHORT *)(ROMAddr+TVDelayPtr1Offset)); + delay =*((USHORT *)(ROMAddr+delay+index)); + } + } + + Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; + SiSSetRegANDOR(Part1Port,0x2D,~0x0F,delay); +} + +VOID SiSSetAntiFlicker(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo) +{ + USHORT Part2Port; + USHORT index,temp; + + Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; + index = SiSGetTVPtrIndex(); + index = (index>>1)<<1; + if (ModeNo<=0x13) { + index = index + *((USHORT *)(ROMAddr+SiSModeIDOffset+0x06)); + } else { + index = index + *((USHORT *)(ROMAddr+SiSModeIDOffset+0x0B)); + } + temp =*((USHORT *)(ROMAddr+TVAntiFlickPtrOffset)); + temp =*((USHORT *)(ROMAddr+temp+index)); + temp <<= 4; + + SiSSetRegANDOR(Part2Port,0x0A,~0x70,temp); +} + + +VOID SiSSetEdgeEnhance (PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo) +{ + USHORT Part2Port; + USHORT index,temp; + + Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; + index = SiSGetTVPtrIndex(); + index = (index>>1)<<1; + if (ModeNo<=0x13) { + index = index + *((USHORT *)(ROMAddr+SiSModeIDOffset+0x07)); + } else { + index = index + *((USHORT *)(ROMAddr+SiSModeIDOffset+0x0C)); + } + temp =*((USHORT *)(ROMAddr+TVEdgePtr1Offset)); + temp =*((USHORT *)(ROMAddr+temp+index)); + temp <<= 5; + + SiSSetRegANDOR(Part2Port,0x3A,~0xE0,temp); + +} + +VOID SiSSetYFilter(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo) +{ + USHORT Part2Port; + USHORT index,temp,i; + + Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; + index = SiSGetTVPtrIndex(); + index >>= 1; + index <<= 5; + if (ModeNo<=0x13) { + temp = *((USHORT *)(ROMAddr+SiSModeIDOffset+0x08)); + } else { + temp = *((USHORT *)(ROMAddr+SiSModeIDOffset+0x0D)); + } + temp *= 4; + if (SiSVBInfo&SetCRT2ToHiVisionTV) + temp = 0; + index += temp; + + temp =*((USHORT *)(ROMAddr+TVYFilterPtr1Offset)); + + for(i=0x35;i<=0x38;i++,temp++) { + SiSSetReg1(Part2Port,i,*(UCHAR *)(ROMAddr+index+temp)); + } +} + +VOID SiSSetPhaseIncr(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo) +{ + USHORT Part2Port; + USHORT index,temp,i; + + Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; + index = SiSGetTVPtrIndex(); + index <<= 2; + + temp =*((USHORT *)(ROMAddr+TVPhaseIncrPtr1Offset)); + + for(i=0x31;i<=0x34;i++,temp++) { + SiSSetReg1(Part2Port,i,*(UCHAR *)(ROMAddr+index+temp)); + } + +} + +VOID SiSOEM310Setting(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo) +{ + SiSSetDelayComp(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo); + if (SiSVBInfo&SetCRT2ToTV) { + SiSSetAntiFlicker(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo); + SiSSetPhaseIncr(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo); + SiSSetYFilter(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo); + SiSSetEdgeEnhance(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo); + } +} + + +BOOLEAN SiSOEMSetting(USHORT BaseAddr,ULONG ROMAddr, + PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT ModeNo) + +{ + USHORT modeptr; + modeptr=SiSSearchVBModeID(ROMAddr,ModeNo); + if (modeptr!=0) { + SiSSetOEMData(BaseAddr,ROMAddr,HwDeviceExtension,modeptr); + return 1; + } else { + return 0; + } +} + +USHORT SiSSearchVBModeID(ULONG ROMAddr,USHORT ModeNo) +{ + USHORT index,modeptr,tablelength; + UCHAR tempid; + + index=ModeNo; + if (ModeNo<=0x13) { + return(0); + } + + modeptr=*((USHORT *)(ROMAddr+VBModeIDTableAddr)); + tablelength=VBModeStructSize; + for(;;modeptr+=tablelength) { + tempid=*((UCHAR *)(ROMAddr+modeptr+VB_ModeID)); + if (tempid==0xFF) { + return(0); + } + if (tempid==ModeNo) { + return(modeptr); + } + } + return(0); +} + +VOID SiSSetOEMData(USHORT BaseAddr,ULONG ROMAddr, + PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT modeptr) +{ + USHORT OEMUtiltemp; + + OEMUtiltemp=*((USHORT *)(ROMAddr+OEMUtilIDCodeAddr)); + if (OEMUtiltemp&OEMLCDEnable) { + if (SiSVBInfo&SetCRT2ToLCD) { + SiSSetOEMLCDData(BaseAddr,ROMAddr,HwDeviceExtension,modeptr); + } + } + if (SIS_IF_DEF_LVDS==0) { + if (OEMUtiltemp&OEMTVEnable) { + if (SiSVBInfo&SetCRT2ToTV) { + SiSSetOEMTVData(BaseAddr,ROMAddr,modeptr); + } + } + } + return; +} + +VOID SiSSetOEMLCDData(USHORT BaseAddr,ULONG ROMAddr, + PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT modeptr) +{ + USHORT oemlcdindex; + oemlcdindex=SiSGetOEMLCDPtr(ROMAddr,HwDeviceExtension); + SiSSetOEMLCDReg(BaseAddr,ROMAddr,oemlcdindex,modeptr); +} + +VOID SiSSetOEMTVData(USHORT BaseAddr,ULONG ROMAddr,USHORT modeptr) +{ + USHORT oemtvptr; + oemtvptr=SiSGetOEMTVPtr(ROMAddr,modeptr); + SiSSetOEMTVReg(BaseAddr,ROMAddr,oemtvptr); + return; +} + +USHORT SiSGetOEMTVPtr(ULONG ROMAddr,USHORT modeptr) +{ + USHORT index,length,pbase,tempptr,oemtvptr,tempoffset; + + oemtvptr=0; + index=*((UCHAR *)(ROMAddr+modeptr+VB_TVTableIndex)); + length=3; + if (SiSVBInfo&SetInSlaveMode) { + pbase=0; + } else { + pbase=4; + } + if (SiSVBInfo&SetCRT2ToSCART) { + length=2; + pbase=pbase+2; + } else if (SiSVBInfo&SetCRT2ToHiVisionTV) { + length=1; + pbase=pbase+3; + } else if (SiSVBInfo&SetPALTV) { + pbase=pbase+1; + } + + tempptr=*((USHORT *)(ROMAddr+OEMTVPtrAddr)); + pbase=pbase<<1; + oemtvptr=*((USHORT *)(ROMAddr+tempptr+pbase)); + tempoffset=index*length; + oemtvptr=oemtvptr+tempoffset; + return(oemtvptr); +} + +VOID SiSSetOEMTVReg(USHORT BaseAddr,ULONG ROMAddr,USHORT oemtvptr) +{ + USHORT OEMUtilID,Part1Port,Part2Port; + USHORT tempah,tempptr,i,temp; + + OEMUtilID=*((USHORT *)(ROMAddr+OEMUtilIDCodeAddr)); + + if (OEMUtilID&OEMTVDelayEnable) { + Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; + tempah=*((UCHAR *)(ROMAddr+oemtvptr)); + tempah=(tempah&0x0F)<<2; + SiSSetRegANDOR(Part1Port,0x13,~0x3C,tempah); + } + Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; + if (OEMUtilID&OEMTVFlickerEnable) { + tempah=*((UCHAR *)(ROMAddr+oemtvptr)); + tempah=tempah&0x70; + SiSSetRegANDOR(Part2Port,0x0A,~0x70,tempah); + } + if (!(SiSVBInfo&SetCRT2ToHiVisionTV)) { + if (OEMUtilID&OEMTVPhaseEnable) { + tempptr=*((USHORT *)(ROMAddr+PhaseTableAddr)); + tempah=*((UCHAR *)(ROMAddr+oemtvptr+1)); + tempah=tempah*PhaseTableSize; + tempptr=tempptr+tempah; + for(i=0x31;i<=0x34;i++,tempptr++) { + tempah=*((UCHAR *)(ROMAddr+tempptr)); + SiSSetReg1(Part2Port,i,tempah); + } + } + } + if (!(SiSVBInfo&(SetCRT2ToSCART|SetCRT2ToHiVisionTV))) { + if (OEMUtilID&OEMTVFilterEnable) { + tempah=*((UCHAR *)(ROMAddr+oemtvptr+2)); + temp=(tempah>>4)<<1; + if (SiSVBInfo&SetPALTV) { + tempptr=*((USHORT *)(ROMAddr+PALFilterTableAddr)); + tempptr=*((USHORT *)(ROMAddr+tempptr+temp)); + } else { + tempptr=*((USHORT *)(ROMAddr+NTSCFilterTableAddr)); + tempptr=*((USHORT *)(ROMAddr+tempptr+temp)); + } + tempah=(tempah&0x0F)*FilterTableSize; + tempptr=tempptr+tempah; + for(i=0x35;i<=0x38;i++,tempptr++) { + tempah=*((UCHAR *)(ROMAddr+tempptr)); + SiSSetReg1(Part2Port,i,tempah); + } + } + } + return; +} + +USHORT SiSGetOEMLCDPtr(ULONG ROMAddr,PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + USHORT index,BIOSIDCode,temp,OEMLCDPIDTable; + + if (SIS_IF_DEF_LVDS==0) { + index= SiSLCDResInfo - Panel1024x768; + if (!(SiSSetFlag&LCDVESATiming)) { + index=index+4; + if (HwDeviceExtension->jChipID == SIS_Spartan) { + if (HwDeviceExtension->uRevisionID == 0) { + index=index+4; + } + } else if (HwDeviceExtension->jChipID == SIS_Trojan) { + if (HwDeviceExtension->uRevisionID < 3) { + index=index+4; + } + } + } + if (SiSLCDResInfo==Panel1024x768) { + if (SiSLCDInfo&LCDNonExpanding) { + index=index+3; + } + } + BIOSIDCode=*((USHORT *)(ROMAddr+BIOSIDCodeAddr)); + if (BIOSIDCode&OEMLCDPanelIDSupport) { + temp=(USHORT)SiSLCDTypeInfo; + OEMLCDPIDTable=*((USHORT *)(ROMAddr+OEMLCDPIDTableAddr)); + index=*((UCHAR *)(ROMAddr+OEMLCDPIDTable+temp)); + if (!(SiSSetFlag&LCDVESATiming)) { + index++; + } + } + index=index<<1; + return(index); + } else { + temp=0; + index= SiSLCDResInfo - Panel800x600; + BIOSIDCode=*((USHORT *)(ROMAddr+BIOSIDCodeAddr)); + if (BIOSIDCode&OEMLCDPanelIDSupport) { + temp=(USHORT)SiSLCDTypeInfo; + OEMLCDPIDTable=*((USHORT *)(ROMAddr+OEMLCDPIDTableAddr)); + index=*((UCHAR *)(ROMAddr+OEMLCDPIDTable+temp)); + } + index=index*OEMLVDSPIDTableSize; + index=index+temp; + if (SiSVBInfo&SetInSlaveMode) { + index=index+2; + } + if (SiSLCDInfo&LCDNonExpanding) { + index=index+1; + } + index=index<<1; + return(index); + } +} + +VOID SiSSetOEMLCDReg(USHORT BaseAddr,ULONG ROMAddr,USHORT oemlcdindex,USHORT modeptr) +{ + USHORT OEMUtilID,BIOSIDCode; + USHORT oemlcdptr,tempptr=0,tempoffset=0,tempah; + USHORT Part1Port=0,Part2Port,i; + + if (SIS_IF_DEF_LVDS==0) { + OEMUtilID=*((USHORT *)(ROMAddr+OEMUtilIDCodeAddr)); + if (OEMUtilID&OEMLCDDelayEnable) { + BIOSIDCode=*((USHORT *)(ROMAddr+BIOSIDCodeAddr)); + if (BIOSIDCode&OEMLCDPanelIDSupport) { + tempptr=*((USHORT *)(ROMAddr+OEMLCDPtr_2Addr)); + oemlcdptr=*((USHORT *)(ROMAddr+tempptr+oemlcdindex)); + } else { + tempptr=*((USHORT *)(ROMAddr+OEMLCDPtr_1Addr)); + oemlcdptr=*((USHORT *)(ROMAddr+tempptr+oemlcdindex)); + } + tempoffset=*((UCHAR *)(ROMAddr+modeptr+VB_LCDTableIndex)); + oemlcdptr=oemlcdptr+tempoffset; + Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; + tempah=*((UCHAR *)(ROMAddr+oemlcdptr)); + tempah=(tempah<<2)&0x03C; + SiSSetRegANDOR(Part1Port,0x13,~0x3C,tempah); + } + + Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; + if (OEMUtilID&OEMLCDPOSEnable) { + BIOSIDCode=*((USHORT *)(ROMAddr+BIOSIDCodeAddr)); + if (BIOSIDCode&OEMLCDPanelIDSupport) { + tempptr=*((USHORT *)(ROMAddr+LCDHPosTable_2Addr)); + oemlcdptr=*((USHORT *)(ROMAddr+tempptr+oemlcdindex)); + } else { + tempptr=*((USHORT *)(ROMAddr+LCDHPosTable_1Addr)); + oemlcdptr=*((USHORT *)(ROMAddr+tempptr+oemlcdindex)); + } + tempoffset=*((UCHAR *)(ROMAddr+modeptr+VB_LCDHIndex)); + tempoffset=tempoffset*LCDHPosTableSize; + oemlcdptr=oemlcdptr+tempoffset; + tempah=*((UCHAR *)(ROMAddr+oemlcdptr)); + SiSSetReg1(Part2Port,0x1C,tempah); + tempah=*((UCHAR *)(ROMAddr+oemlcdptr+1)); + SiSSetRegANDOR(Part2Port,0x1D,~0x0F0,tempah); + tempah=*((UCHAR *)(ROMAddr+oemlcdptr+2)); + SiSSetReg1(Part2Port,0x1F,tempah); + tempah=*((UCHAR *)(ROMAddr+oemlcdptr+3)); + SiSSetRegANDOR(Part2Port,0x20,~0x0F0,tempah); + tempah=*((UCHAR *)(ROMAddr+oemlcdptr+4)); + SiSSetReg1(Part2Port,0x21,tempah); + tempah=*((UCHAR *)(ROMAddr+oemlcdptr+5)); + SiSSetReg1(Part2Port,0x23,tempah); + tempah=*((UCHAR *)(ROMAddr+oemlcdptr+6)); + SiSSetRegANDOR(Part2Port,0x25,~0x0F,tempah); + + BIOSIDCode=*((USHORT *)(ROMAddr+BIOSIDCodeAddr)); + if (BIOSIDCode&OEMLCDPanelIDSupport) { + tempptr=*((USHORT *)(ROMAddr+LCDVPosTable_2Addr)); + oemlcdptr=*((USHORT *)(ROMAddr+tempptr+oemlcdindex)); + } else { + tempptr=*((USHORT *)(ROMAddr+LCDVPosTable_1Addr)); + oemlcdptr=*((USHORT *)(ROMAddr+tempptr+oemlcdindex)); + } + tempoffset=*((UCHAR *)(ROMAddr+modeptr+VB_LCDVIndex)); + tempoffset=tempoffset*LCDVPosTableSize; + oemlcdptr=oemlcdptr+tempoffset; + for(i=1;i<=2;i++,oemlcdptr++) { + tempah=*((UCHAR *)(ROMAddr+oemlcdptr)); + SiSSetReg1(Part2Port,i,tempah); + } + for(i=4;i<=6;i++,oemlcdptr++) { + tempah=*((UCHAR *)(ROMAddr+oemlcdptr)); + SiSSetReg1(Part2Port,i,tempah); + } + } + return; + } else { + OEMUtilID=*((USHORT *)(ROMAddr+OEMUtilIDCodeAddr)); + if (OEMUtilID&OEMLCDDelayEnable) { + BIOSIDCode=*((USHORT *)(ROMAddr+BIOSIDCodeAddr)); + if (BIOSIDCode&OEMLCDPanelIDSupport) { + tempptr=*((USHORT *)(ROMAddr+OEMLCDPtr_2Addr)); + oemlcdptr=*((USHORT *)(ROMAddr+tempptr+oemlcdindex)); + } else { + tempptr=*((USHORT *)(ROMAddr+OEMLCDPtr_1Addr)); + oemlcdptr=*((USHORT *)(ROMAddr+tempptr+oemlcdindex)); + } + tempoffset=*((UCHAR *)(ROMAddr+modeptr+VB_LCDTableIndex)); + oemlcdptr=oemlcdptr+tempoffset; + Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; + tempah=*((UCHAR *)(ROMAddr+oemlcdptr)); + tempah=(tempah<<2)&0x03C; + SiSSetRegANDOR(Part1Port,0x13,~0x3C,tempah); + } + if (OEMUtilID&OEMLCDPOSEnable) { + BIOSIDCode=*((USHORT *)(ROMAddr+BIOSIDCodeAddr)); + if (BIOSIDCode&OEMLCDPanelIDSupport) { + tempptr=*((USHORT *)(ROMAddr+LCDHPosTable_2Addr)); + oemlcdptr=*((USHORT *)(ROMAddr+tempptr+oemlcdindex)); + } else { + tempptr=*((USHORT *)(ROMAddr+LCDHPosTable_1Addr)); + oemlcdptr=*((USHORT *)(ROMAddr+tempptr+oemlcdindex)); + } + tempoffset=*((UCHAR *)(ROMAddr+modeptr+VB_LCDHIndex)); + tempoffset=tempoffset*LVDSHPosTableSize; + oemlcdptr=oemlcdptr+tempoffset; + for(i=0x14;i<=0x17;i++,oemlcdptr++) { + tempah=*((UCHAR *)(ROMAddr+oemlcdptr)); + SiSSetReg1(Part1Port,i,tempah); + } + + BIOSIDCode=*((USHORT *)(ROMAddr+BIOSIDCodeAddr)); + if (BIOSIDCode&OEMLCDPanelIDSupport) { + tempptr=*((USHORT *)(ROMAddr+LCDVPosTable_2Addr)); + oemlcdptr=*((USHORT *)(ROMAddr+tempptr+oemlcdindex)); + } else { + tempptr=*((USHORT *)(ROMAddr+LCDVPosTable_1Addr)); + oemlcdptr=*((USHORT *)(ROMAddr+tempptr+oemlcdindex)); + } + tempoffset=*((UCHAR *)(ROMAddr+modeptr+VB_LCDVIndex)); + tempoffset=tempoffset*LVDSVPosTableSize; + oemlcdptr=oemlcdptr+tempoffset; + tempah=*((UCHAR *)(ROMAddr+oemlcdptr)); + SiSSetReg1(Part1Port,0x18,tempah); + tempah=*((UCHAR *)(ROMAddr+oemlcdptr+1)); + SiSSetRegANDOR(Part1Port,0x19,~0x0F,tempah); + tempah=*((UCHAR *)(ROMAddr+oemlcdptr+2)); + SiSSetRegANDOR(Part1Port,0x1A,~0x03F,tempah); + oemlcdptr=oemlcdptr+3; + for(i=0x1B;i<=0x1D;i++,oemlcdptr++) { + tempah=*((UCHAR *)(ROMAddr+oemlcdptr)); + SiSSetReg1(Part1Port,i,tempah); + } + } + return; + } +} + + +USHORT SiSSaveRegisters(PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + UCHAR *regptr; + USHORT length; + USHORT Part1Port,Part2Port,Part3Port,Part4Port,Part5Port; + USHORT BaseAddr = (USHORT)HwDeviceExtension->IOAddress; + + Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; + Part2Port=Part1Port+0x0C; + Part3Port=Part1Port+0x0E; + Part4Port=Part1Port+0x10; + Part5Port=Part1Port+0x12; + SiSP3c4=BaseAddr+0x14; + SiSP3d4=BaseAddr+0x24; + SiSP3c0=BaseAddr+0x10; + SiSP3ce=BaseAddr+0x1e; + SiSP3c2=BaseAddr+0x12; + SiSP3ca=BaseAddr+0x1a; + SiSP3c6=BaseAddr+0x16; + SiSP3c7=BaseAddr+0x17; + SiSP3c8=BaseAddr+0x18; + SiSP3c9=BaseAddr+0x19; + SiSP3da=BaseAddr+0x2A; + + regptr=(UCHAR *)(HwDeviceExtension->pSavedRegisters); + + length=SiSSaveSR(regptr); + regptr+=length; + + length=SiSSaveMISC(regptr); + regptr+=length; + length=SiSSaveAR(regptr); + regptr+=length; + length=SiSSaveGR(regptr); + regptr+=length; + + length=SiSSavePart1(regptr,Part1Port); + regptr+=length; + length=SiSSavePart2(regptr,Part2Port); + regptr+=length; + length=SiSSaveCR(regptr); + regptr+=length; + + return(length); + +} + +USHORT SiSSaveSR(UCHAR *regptr) +{ + USHORT i,length; + UCHAR *ptr; + + ptr=regptr; + SiSSetReg1(SiSP3c4,0x05,0x86); + length=0; + for(i=0;i<=4;i++,length++) { + *ptr=(UCHAR)SiSGetReg1(SiSP3c4,i); + ptr++; + } + for(i=6;i<=0x36;i++,length++) { + *ptr=(UCHAR)SiSGetReg1(SiSP3c4,i); + ptr++; + } + return(length); +} + +USHORT SiSSaveCR(UCHAR *regptr) +{ + USHORT i,length; + UCHAR *ptr; + ptr=regptr; + length=0; + for(i=0;i<=0x18;i++,length++) { + *ptr=(UCHAR)SiSGetReg1(SiSP3d4,i); + ptr++; + } + for(i=0x30;i<=0x37;i++,length++) { + *ptr=(UCHAR)SiSGetReg1(SiSP3d4,i); + ptr++; + } + return(length); +} + +USHORT SiSSaveMISC(UCHAR *regptr) +{ + USHORT length; + UCHAR *ptr; + ptr=regptr; + length=0; + + *ptr=(UCHAR)SiSGetReg2((USHORT)(SiSP3c4+0x08)); + ptr++;length++; + *ptr=(UCHAR)SiSGetReg2((USHORT)(SiSP3c4+0x06)); + ptr++;length++; + *ptr=(UCHAR)SiSGetReg2((USHORT)(SiSP3c4-0x01)); + ptr++;length++; + + return(length); +} + +USHORT SiSSaveAR(UCHAR *regptr) +{ + USHORT i,length; + UCHAR *ptr; + + ptr=regptr; + length=0; + for(i=0;i<=0x14;i++,length++) { + SiSGetReg2(SiSP3da); + SiSSetReg3(SiSP3c0,i); + *ptr=(UCHAR)SiSGetReg2((USHORT)(SiSP3c4-3)); + ptr++; + } + return(length); +} + +USHORT SiSSaveGR(UCHAR *regptr) +{ + USHORT i,length; + UCHAR *ptr; + ptr=regptr; + length=0; + for(i=0;i<=0x8;i++,length++) { + *ptr=(UCHAR)SiSGetReg1((USHORT)(SiSP3c4+10),i); + ptr++; + } + return(length); +} + +USHORT SiSRestoreRegisters(PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + UCHAR *regptr; + USHORT length; + USHORT Part1Port,Part2Port,Part3Port,Part4Port,Part5Port; + USHORT BaseAddr = (USHORT)HwDeviceExtension->IOAddress; + + Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; + Part2Port=Part1Port+0x0C; + Part3Port=Part1Port+0x0E; + Part4Port=Part1Port+0x10; + Part5Port=Part1Port+0x12; + SiSP3c4=BaseAddr+0x14; + SiSP3d4=BaseAddr+0x24; + SiSP3c0=BaseAddr+0x10; + SiSP3ce=BaseAddr+0x1e; + SiSP3c2=BaseAddr+0x12; + SiSP3ca=BaseAddr+0x1a; + SiSP3c6=BaseAddr+0x16; + SiSP3c7=BaseAddr+0x17; + SiSP3c8=BaseAddr+0x18; + SiSP3c9=BaseAddr+0x19; + SiSP3da=BaseAddr+0x2A; + + regptr=(UCHAR *)(HwDeviceExtension->pSavedRegisters); + + length=SiSRestoreSR(regptr); + regptr+=length; + + length=SiSRestoreMISC(regptr); + regptr+=length; + length=SiSRestoreAR(regptr); + regptr+=length; + length=SiSRestoreGR(regptr); + regptr+=length; + + length=SiSRestorePart1(regptr,Part1Port); + regptr+=length; + length=SiSRestorePart2(regptr,Part2Port); + regptr+=length; + length=SiSRestoreCR(regptr); + regptr+=length; + + return(length); +} + +USHORT SiSRestoreSR(UCHAR *regptr) +{ + USHORT i,length,temp; + UCHAR *ptr; + ptr=regptr; + SiSSetReg1(SiSP3c4,0x05,0x86); + length=0; + for(i=0;i<=4;i++,length++) { + temp=(USHORT)(*(UCHAR*)ptr); + SiSSetReg1(SiSP3c4,i,temp); + ptr++; + } + for(i=6;i<=0x36;i++,length++) { + temp=(USHORT)(*(UCHAR*)ptr); + SiSSetReg1(SiSP3c4,i,temp); + ptr++; + } + return(length); +} + +USHORT SiSRestoreCR(UCHAR *regptr) +{ + USHORT i,length,temp; + UCHAR *ptr; + ptr=regptr; + length=0; + for(i=0;i<=0x18;i++,length++) { + temp=(USHORT)(*(UCHAR*)ptr); + SiSSetReg1(SiSP3d4,i,temp); + ptr++; + } + for(i=0x30;i<=0x37;i++,length++) { + temp=(USHORT)(*(UCHAR*)ptr); + SiSSetReg1(SiSP3d4,i,temp); + ptr++; + } + + return(length); +} + +USHORT SiSRestoreMISC(UCHAR *regptr) +{ + USHORT length,temp; + UCHAR *ptr; + ptr=regptr; + length=0; + temp=(USHORT)(*(UCHAR*)ptr); + SiSSetReg3((USHORT)(SiSP3c4-2),temp); + ptr++;length++; + temp=(USHORT)(*(UCHAR*)ptr); + SiSSetReg3((USHORT)(SiSP3d4+0x06),temp); + ptr++;length++; + temp=(USHORT)(*(UCHAR*)ptr); + SiSSetReg3((USHORT)(SiSP3c4-0x01),temp); + ptr++;length++; + + return(length); +} + +USHORT SiSRestoreAR(UCHAR *regptr) +{ + USHORT i,length,temp; + UCHAR *ptr; + ptr=regptr; + length=0; + for(i=0;i<=0x14;i++,length++) { + temp=(USHORT)(*(UCHAR*)ptr); + SiSGetReg2(SiSP3da); + SiSSetReg3(SiSP3c0,i); + SiSSetReg3(SiSP3c0,temp); + ptr++; + } + return(length); +} + +USHORT SiSRestoreGR(UCHAR *regptr) +{ + USHORT i,length,temp; + UCHAR *ptr; + ptr=regptr; + length=0; + for(i=0;i<=0x8;i++,length++) { + temp=(USHORT)(*(UCHAR*)ptr); + SiSSetReg1((USHORT)(SiSP3c4+10),i,temp); + ptr++; + } + return(length); +} + +USHORT SiSSavePart1(UCHAR *regptr,USHORT Part1Port) +{ + USHORT i,length; + UCHAR *ptr; + ptr=regptr; + SiSSetReg1(Part1Port,0x24,0x01); + length=0; + for(i=0;i<=0x23;i++,length++) { + *ptr=(UCHAR)SiSGetReg1(Part1Port,i); + ptr++; + } + return(length); +} + +USHORT SiSSavePart2(UCHAR *regptr,USHORT Part2Port) +{ + USHORT i,length; + UCHAR *ptr; + ptr=regptr; + length=0; + for(i=0;i<=0x45;i++,length++) { + *ptr=(UCHAR)SiSGetReg1(Part2Port,i); + ptr++; + } + return(length); +} + +USHORT SiSSavePart3(UCHAR *regptr,USHORT Part3Port) +{ + USHORT i,length; + UCHAR *ptr; + ptr=regptr; + length=0; + for(i=0;i<=0x3E;i++,length++) { + *ptr=(UCHAR)SiSGetReg1(Part3Port,i); + ptr++; + } + return(length); +} + +USHORT SiSSavePart4(UCHAR *regptr,USHORT Part4Port) +{ + USHORT i,length; + UCHAR *ptr; + ptr=regptr; + length=0; + for(i=0x0A;i<=0x1B;i++,length++) { + *ptr=(UCHAR)SiSGetReg1(Part4Port,i); + ptr++; + } + return(length); +} + +USHORT SiSSavePart5(UCHAR *regptr,USHORT Part5Port) +{ + USHORT i,j,length; + UCHAR *ptr; + USHORT Pindex,Pdata; + ptr=regptr; + length=0; + Pindex=Part5Port; + Pdata=Part5Port+1; + SiSSetReg3(Pindex,0); + for(i=0x0;i<=0x255;i++) { + for(j=0;j<3;j++,length++) { + *ptr=(UCHAR)SiSGetReg2(Pdata); + ptr++; + } + } + return(length); +} + + +USHORT SiSRestorePart1(UCHAR *regptr,USHORT Part1Port) +{ + USHORT i,length,temp; + UCHAR *ptr; + ptr=regptr; + SiSSetReg1(Part1Port,0x24,0x01); + length=0; + for(i=0;i<=0x23;i++,length++) { + temp=(USHORT)(*(UCHAR*)ptr); + SiSSetReg1(Part1Port,i,temp); + ptr++; + } + return(length); +} + +USHORT SiSRestorePart2(UCHAR *regptr,USHORT Part2Port) +{ + USHORT i,length,temp; + UCHAR *ptr; + ptr=regptr; + length=0; + for(i=0;i<=0x45;i++,length++) { + temp=(USHORT)(*(UCHAR*)ptr); + SiSSetReg1(Part2Port,i,temp); + ptr++; + } + return(length); +} + +USHORT SiSRestorePart3(UCHAR *regptr,USHORT Part3Port) +{ + USHORT i,length,temp; + UCHAR *ptr; + ptr=regptr; + length=0; + for(i=0;i<=0x3E;i++,length++) { + temp=(USHORT)(*(UCHAR*)ptr); + SiSSetReg1(Part3Port,i,temp); + ptr++; + } + return(length); +} + +USHORT SiSRestorePart4(UCHAR *regptr,USHORT Part4Port) +{ + USHORT i,length,temp; + UCHAR *ptr; + ptr=regptr; + length=0; + for(i=0x0A;i<=0x1B;i++,length++) { + temp=(USHORT)(*(UCHAR*)ptr); + SiSSetReg1(Part4Port,i,temp); + ptr++; + } + return(length); +} + +USHORT SiSRestorePart5(UCHAR *regptr,USHORT Part5Port) +{ + USHORT i,j,length,temp; + UCHAR *ptr; + USHORT Pindex,Pdata; + + ptr=regptr; + length=0; + Pindex=Part5Port; + Pdata=Part5Port+1; + SiSSetReg3(Pindex,0); + for(i=0x0;i<=0x255;i++) { + for(j=0;j<3;j++,length++) { + temp=(USHORT)(*(UCHAR*)ptr); + SiSSetReg1(Part5Port,i,temp); + ptr++; + } + } + return(length); +} + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/sis/init301.h linux.ac/drivers/video/sis/init301.h --- linux.vanilla/drivers/video/sis/init301.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/sis/init301.h Tue Apr 3 17:55:09 2001 @@ -0,0 +1,261 @@ +#include "sis.h" + +USHORT SiSSetFlag,SiSRVBHCFACT,SiSRVBHCMAX,SiSVGAVT,SiSVGAHT,SiSVT,SiSHT,SiSVGAVDE,SiSVGAHDE; +USHORT SiSVDE,SiSHDE,SiSRVBHRS,SiSNewFlickerMode,SiSRY1COE,SiSRY2COE,SiSRY3COE,SiSRY4COE; +USHORT SiSVCLKLen; +USHORT SiSLCDHDES,SiSLCDVDES; + +USHORT SiSStResInfo[5][2]={{640,400},{640,350},{720,400},{720,350},{640,480}}; +USHORT SiSModeResInfo[20][4]={{320,200,8,8},{320,240,8,8},{320,400,8,8}, + {400,300,8,8},{512,384,8,8},{640,400,8,16}, + {640,480,8,16},{800,600,8,16},{1024,768,8,16}, + {1280,1024,8,16},{1600,1200,8,16},{1920,1440,8,16}, + {2048,1536,8,16},{720,480,8,16},{720,576,8,16},{1280,960,8,16}, + {800,480,8,16},{1024,576,8,16},{1280,720,8,16},{856,480,8,16} + + }; + +USHORT SiSNTSCTiming[61]={0x017,0x01D,0x003,0x009,0x005,0x006,0x00C,0x00C, + 0x094,0x049,0x001,0x00A,0x006,0x00D,0x004,0x00A, + 0x006,0x014,0x00D,0x004,0x00A,0x000,0x085,0x01B, + 0x00C,0x050,0x000,0x099,0x000,0x0EC,0x04A,0x017, + 0x088,0x000,0x04B,0x000,0x000,0x0E2,0x000,0x002, + 0x003,0x00A,0x065,0x09D,0x008, + 0x092,0x08F,0x040,0x060,0x080,0x014,0x090,0x08C, + 0x060,0x014,0x050,0x000,0x040, + 0x00044,0x002DB,0x0003B}; + +USHORT SiSPALTiming[61]={ 0x019,0x052,0x035,0x06E,0x004,0x038,0x03D,0x070, + 0x094,0x049,0x001,0x012,0x006,0x03E,0x035,0x06D, + 0x006,0x014,0x03E,0x035,0x06D,0x000,0x045,0x02B, + 0x070,0x050,0x000,0x097,0x000,0x0D7,0x05D,0x017, + 0x088,0x000,0x045,0x000,0x000,0x0E8,0x000,0x002, + 0x00D,0x000,0x068,0x0B0,0x00B, + 0x092,0x08F,0x040,0x060,0x080,0x014,0x090,0x08C, + 0x060,0x014,0x063,0x000,0x040, + 0x0003E,0x002E1,0x00028}; + +USHORT SiSHiTVTiming[61]={0x017,0x01D,0x003,0x009,0x005,0x006,0x00C,0x00C, + 0x094,0x049,0x001,0x00A,0x006,0x00D,0x004,0x00A, + 0x006,0x014,0x00D,0x004,0x00A,0x000,0x085,0x01B, + 0x00C,0x050,0x000,0x099,0x000,0x0EC,0x04A,0x017, + 0x088,0x000,0x04B,0x000,0x000,0x0E2,0x000,0x002, + 0x003,0x00A,0x065,0x09D,0x008, + 0x092,0x08F,0x040,0x060,0x080,0x014,0x090,0x08C, + 0x060,0x014,0x050,0x000,0x040, + 0x00027,0x0FFFC,0x0003B}; + +USHORT SiSHiTVTimingSimu[61]={0x020,0x054,0x02C,0x060,0x008,0x031,0x03A,0x061, + 0x028,0x002,0x001,0x03D,0x006,0x00D,0x004,0x00A, + 0x006,0x014,0x00D,0x004,0x00A,0x000,0x0C5,0x03F, + 0x064,0x090,0x000,0x0AA,0x000,0x006,0x060,0x003, + 0x011,0x005,0x011,0x00F,0x010,0x011,0x000,0x000, + 0x005,0x005,0x034,0x034,0x008, + 0x092,0x00F,0x040,0x060,0x080,0x014,0x090,0x08C, + 0x060,0x004,0x05F,0x000,0x060, + 0x0000E,0x0FFFC,0x00042}; + +USHORT SiSHiTVGroup3Data[63]={0x000,0x01A,0x022,0x063,0x062,0x022,0x008,0x05B, + 0x0FF,0x021,0x0AD,0x0AD,0x055,0x077,0x02A,0x0A6, + 0x025,0x02F,0x047,0x0FA,0x0C8,0x0FF,0x08E,0x020, + 0x08C,0x06E,0x060,0x02D,0x056,0x047,0x070,0x044, + 0x056,0x036,0x04F,0x06E,0x03F,0x080,0x000,0x080, + 0x045,0x07D,0x003,0x0A5,0x076,0x020,0x01A,0x0A4, + 0x014,0x005,0x003,0x07E,0x064,0x031,0x014,0x075, + 0x018,0x005,0x018,0x005,0x04C,0x0A8,0x001}; + +USHORT SiSHiTVGroup3Simu[63]={0x000,0x01A,0x022,0x063,0x062,0x022,0x008,0x094, + 0x0DA,0x020,0x0B7,0x0B7,0x055,0x047,0x02A,0x0A6, + 0x025,0x02F,0x047,0x0FA,0x0C8,0x0FF,0x08E,0x020, + 0x08C,0x06E,0x060,0x015,0x026,0x0D3,0x0E4,0x011, + 0x056,0x036,0x04F,0x06E,0x03F,0x080,0x000,0x080, + 0x066,0x035,0x001,0x047,0x00E,0x010,0x0BE,0x0B4, + 0x001,0x005,0x003,0x07E,0x065,0x031,0x014,0x075, + 0x018,0x005,0x018,0x005,0x04C,0x0A8,0x001}; + +USHORT SiSNTSCGroup3Data[63]= {0x000,0x014,0x015,0x025,0x055,0x015,0x00B,0x089, + 0x0D7,0x040,0x0B0,0x0B0,0x0FF,0x0C4,0x045,0x0A6, + 0x025,0x02F,0x067,0x0F6,0x0BF,0x0FF,0x08E,0x020, + 0x08C,0x0DA,0x060,0x092,0x0C8,0x055,0x08B,0x000, + 0x051,0x004,0x018,0x00A,0x0F8,0x087,0x000,0x080, + 0x03B,0x03B,0x000,0x0F0,0x0F0,0x000,0x0F0,0x0F0, + 0x000,0x051,0x00F,0x00F,0x008,0x00F,0x008,0x06F, + 0x018,0x005,0x005,0x005,0x04C,0x0AA,0x001}; + +USHORT SiSPALGroup3Data[63]={0x000,0x01A,0x022,0x063,0x062,0x022,0x008,0x085, + 0x0C3,0x020,0x0A4,0x0A4,0x055,0x047,0x02A,0x0A6, + 0x025,0x02F,0x047,0x0FA,0x0C8,0x0FF,0x08E,0x020, + 0x08C,0x0DC,0x060,0x092,0x0C8,0x04F,0x085,0x000, + 0x056,0x036,0x04F,0x06E,0x0FE,0x083,0x054,0x081, + 0x030,0x030,0x000,0x0F3,0x0F3,0x000,0x0A2,0x0A2, + 0x000,0x048,0x0FE,0x07E,0x008,0x040,0x008,0x091, + 0x018,0x005,0x018,0x005,0x04C,0x0A8,0x001}; + +VOID SiSoverwriteregs(ULONG ROMAddr, USHORT BaseAddr); +VOID SiSSetDefCRT2ExtRegs(USHORT BaseAddr); +BOOLEAN SiSSetCRT2Group301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension); +USHORT SiSGetRatePtrCRT2(ULONG ROMAddr, USHORT ModeNo); +BOOLEAN SiSAjustCRT2Rate(ULONG ROMAddr); +VOID SiSSaveCRT2Info(USHORT ModeNo); +VOID SiSDisableLockRegs(VOID); +VOID SiSDisableCRT2(VOID); +VOID SiSDisableBridge(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr); +VOID SiSGetCRT2Data(ULONG ROMAddr,USHORT ModeNo); +VOID SiSGetResInfo(ULONG ROMAddr,USHORT ModeNo); +VOID SiSGetRAMDAC2DATA(ULONG ROMAddr,USHORT ModeNo); +VOID SiSGetCRT2Ptr(ULONG ROMAddr,USHORT ModeNo); +VOID SiSUnLockCRT2(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr); +VOID SiSSetCRT2ModeRegs(USHORT BaseAddr,USHORT ModeNo); +VOID SiSSetGroup1(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension); +VOID SiSSetCRT2Offset(USHORT Part1Port,ULONG ROMAddr); +USHORT SiSGetOffset(ULONG ROMAddr); +USHORT SiSGetColorDepth(ULONG ROMAddr); +VOID SiSSetCRT2FIFO(USHORT Part1Port,ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension); +USHORT SiSGetVCLK(ULONG ROMAddr,USHORT ModeNo, PHW_DEVICE_EXTENSION HwDeviceExtension); +USHORT SiSGetVCLKPtr(ULONG ROMAddr,USHORT ModeNo,PHW_DEVICE_EXTENSION HwDeviceExtension); +USHORT SiSGetColorTh(ULONG ROMAddr); +USHORT SiSGetMCLK(ULONG ROMAddr); +USHORT SiSGetMCLKPtr(ULONG ROMAddr); +USHORT SiSGetDRAMType(ULONG ROMAddr); +USHORT SiSGetVCLK2Ptr(ULONG ROMAddr,USHORT ModeNo,PHW_DEVICE_EXTENSION HwDeviceExtension); +VOID SiSSetCRT2Sync(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo); +VOID SiSGetCRT1Ptr(ULONG ROMAddr); +VOID SiSSetRegAND(USHORT Port,USHORT Index,USHORT DataAND); +VOID SiSSetRegOR(USHORT Port,USHORT Index,USHORT DataOR); +VOID SiSSetRegANDOR(USHORT Port,USHORT Index,USHORT DataAND,USHORT DataOR); +USHORT SiSGetVGAHT2(VOID); +VOID SiSSetGroup2(USHORT BaseAddr,ULONG ROMAddr); +VOID SiSSetGroup3(USHORT BaseAddr); +VOID SiSSetGroup4(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension); +VOID SiSSetCRT2VCLK(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension); +VOID SiSSetGroup5(USHORT BaseAddr,ULONG ROMAddr); +VOID SiSEnableCRT2(VOID); +VOID SiSLoadDAC2(ULONG ROMAddr,USHORT Part5Port); +VOID SiSWriteDAC2(USHORT Pdata,USHORT dl, USHORT ah, USHORT al, USHORT dh); +VOID SiSLockCRT2(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr); +VOID SiSSetLockRegs(VOID); +VOID SiSEnableBridge(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr); +USHORT SiSGetLockInfo(USHORT pattern); +VOID SiSGetVBInfo301(USHORT BaseAddr,ULONG ROMAddr); +BOOLEAN SiSBridgeIsEnable(USHORT BaseAddr); +BOOLEAN SiSBridgeInSlave(VOID); +BOOLEAN SiSGetLCDResInfo301(ULONG ROMAddr,USHORT SiSP3d4); +VOID SiSPresetScratchregister301(USHORT SiSP3d4,PHW_DEVICE_EXTENSION HwDeviceExtension); +BOOLEAN SiSGetLCDDDCInfo301(PHW_DEVICE_EXTENSION HwDeviceExtension); +VOID SiSSetTVSystem301(PHW_DEVICE_EXTENSION HwDeviceExtension,ULONG ROMAddr); +BOOLEAN SiSGetSenseStatus301(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr); +BOOLEAN SiSSense(USHORT Part4Port,USHORT inputbx,USHORT inputcx); +BOOLEAN SiSSenseLCD(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT Part4Port,ULONG ROMAddr); +BOOLEAN SiSTestMonitorType(USHORT d1,USHORT d2,USHORT d3); +VOID SiSWaitDisplay(VOID); +BOOLEAN SiSDetectMonitor301(PHW_DEVICE_EXTENSION HwDeviceExtension); +VOID SiSLongWait(VOID); +VOID SiSClearALLBuffer(PHW_DEVICE_EXTENSION HwDeviceExtension); +USHORT SiSGetQueueConfig(VOID); +VOID SiSVBLongWait(VOID); +USHORT SiSGetVCLKLen(ULONG ROMAddr,PHW_DEVICE_EXTENSION HwDeviceExtension); +BOOLEAN SiSWaitVBRetrace(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr); +VOID SiSGetLVDSDesData(ULONG ROMAddr,USHORT ModeNo); +VOID SiSModCRT1CRTC(ULONG ROMAddr,USHORT ModeNo); +VOID SiSSetCRT2ECLK(ULONG ROMAddr, USHORT ModeNo,PHW_DEVICE_EXTENSION HwDeviceExtension); +VOID SiSGetCRT2Data301(ULONG ROMAddr,USHORT ModeNo); +VOID SiSGetCRT2DataLVDS(ULONG ROMAddr,USHORT ModeNo); +USHORT SiSGetLVDSDesPtr(ULONG ROMAddr,USHORT ModeNo); +VOID SiSSetGroup1_301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension); +VOID SiSSetGroup1_LVDS(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension); +VOID SiSSetTPData(VOID); +BOOLEAN SiSGetPanelID(VOID); +BOOLEAN SiSGetLVDSCRT1Ptr(ULONG ROMAddr,USHORT ModeNo); +VOID SiSOEM310Setting(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr, + ULONG ROMAddr,USHORT ModeNo); +BOOLEAN SiSOEMSetting(USHORT BaseAddr,ULONG ROMAddr, + PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT ModeNo); +USHORT SiSSearchVBModeID(ULONG ROMAddr,USHORT ModeNo); +VOID SiSSetOEMData(USHORT BaseAddr,ULONG ROMAddr, + PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT modeptr); +VOID SiSSetOEMLCDData(USHORT BaseAddr,ULONG ROMAddr, + PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT modeptr); +VOID SiSSetOEMTVData(USHORT BaseAddr,ULONG ROMAddr,USHORT modeptr); +USHORT SiSGetOEMTVPtr(ULONG ROMAddr,USHORT modeptr); +VOID SiSSetOEMTVReg(USHORT BaseAddr,ULONG ROMAddr,USHORT oemtvptr); +USHORT SiSGetOEMLCDPtr(ULONG ROMAddr,PHW_DEVICE_EXTENSION HwDeviceExtension); +VOID SiSSetOEMLCDReg(USHORT BaseAddr,ULONG ROMAddr,USHORT oemlcdindex,USHORT modeptr); +USHORT SiSSaveRegisters(PHW_DEVICE_EXTENSION HwDeviceExtension); +USHORT SiSSaveSR(UCHAR *regptr); +USHORT SiSSaveCR(UCHAR *regptr); +USHORT SiSSaveMISC(UCHAR *regptr); +USHORT SiSSaveAR(UCHAR *regptr); +USHORT SiSSaveGR(UCHAR *regptr); +USHORT SiSRestoreRegisters(PHW_DEVICE_EXTENSION HwDeviceExtension); +USHORT SiSRestoreSR(UCHAR *regptr); +USHORT SiSRestoreCR(UCHAR *regptr); +USHORT SiSRestoreMISC(UCHAR *regptr); +USHORT SiSRestoreAR(UCHAR *regptr); +USHORT SiSRestoreGR(UCHAR *regptr); +USHORT SiSSavePart1(UCHAR *regptr,USHORT Part1Port); +USHORT SiSSavePart2(UCHAR *regptr,USHORT Part2Port); +USHORT SiSSavePart3(UCHAR *regptr,USHORT Part3Port); +USHORT SiSSavePart4(UCHAR *regptr,USHORT Part4Port); +USHORT SiSSavePart5(UCHAR *regptr,USHORT Part5Port); +USHORT SiSRestorePart1(UCHAR *regptr,USHORT Part1Port); +USHORT SiSRestorePart2(UCHAR *regptr,USHORT Part2Port); +USHORT SiSRestorePart3(UCHAR *regptr,USHORT Part3Port); +USHORT SiSRestorePart4(UCHAR *regptr,USHORT Part4Port); +USHORT SiSRestorePart5(UCHAR *regptr,USHORT Part5Port); + +#ifdef SIS310 +void SiSAutoThreshold (USHORT BaseAddr); +#endif + +extern USHORT SiSDRAMType[17][5]; +extern USHORT SIS_MDA_DAC[]; +extern USHORT SIS_CGA_DAC[]; +extern USHORT SIS_EGA_DAC[]; +extern USHORT SIS_VGA_DAC[]; + +extern USHORT SiSP3c4,SiSP3d4,SiSP3c0,SiSP3ce,SiSP3c2,SiSP3ca,SiSP3c6,SiSP3c7,SiSP3c8,SiSP3c9,SiSP3da; +extern USHORT SiS_flag_clearbuffer; +extern int SiSRAMType; +extern int SiSModeIDOffset,SiSStandTable,SiSCRT1Table,SiSScreenOffset,SiSVCLKData,SiSMCLKData, SiSECLKData; +extern int SiSREFIndex,SiSModeType; +extern USHORT SiSVBInfo,SiSLCDResInfo,SiSLCDTypeInfo,SiSLCDInfo; +extern USHORT SIS_IF_DEF_LVDS,SIS_IF_DEF_TRUMPION; + +extern VOID sisfb_set_reg1(USHORT, USHORT, USHORT); +extern VOID sisfb_set_reg3(USHORT, USHORT); +extern USHORT sisfb_get_reg1(USHORT, USHORT); +extern USHORT sisfb_get_reg2(USHORT); +extern VOID SiSSetMemoryClock(ULONG); +extern VOID SiSSetDRAMSize(PHW_DEVICE_EXTENSION); +extern BOOLEAN SiSSearchModeID(ULONG, USHORT); +extern BOOLEAN SiSCheckMemorySize(ULONG); +extern VOID SiSGetModePtr(ULONG, USHORT); +extern BOOLEAN SiSGetRatePtr(ULONG, USHORT); +extern VOID SiSSetSeqRegs(ULONG); +extern VOID SiSSetMiscRegs(ULONG); +extern VOID SiSSetCRTCRegs(ULONG); +extern VOID SiSSetATTRegs(ULONG); +extern VOID SiSSetGRCRegs(ULONG); +extern VOID SiSClearExt1Regs(VOID); +extern VOID SiSSetSync(ULONG); +extern VOID SiSSetCRT1CRTC(ULONG); +extern VOID SiSSetCRT1Offset(ULONG); +extern VOID SiSSetCRT1FIFO(ULONG, PHW_DEVICE_EXTENSION); +extern VOID SiSSetCRT1VCLK(ULONG); +extern VOID SiSLoadDAC(ULONG); +extern VOID SiSDisplayOn(VOID); +extern VOID SiSSetCRT1ModeRegs(ULONG, USHORT); +extern VOID SiSSetVCLKState(ULONG, USHORT); +extern VOID SiSWriteDAC(USHORT, USHORT, USHORT, USHORT); +extern VOID sisfb_clear_buffer(PHW_DEVICE_EXTENSION); +extern VOID sisfb_clear_DAC(ULONG); +extern void sisfb_set_reg4(USHORT, ULONG); +extern ULONG sisfb_get_reg3(USHORT); +extern BOOLEAN SiSSetMode310(PHW_DEVICE_EXTENSION HwDeviceExtension, USHORT ModeNo); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/sis/init310.c linux.ac/drivers/video/sis/init310.c --- linux.vanilla/drivers/video/sis/init310.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/sis/init310.c Tue Apr 3 17:55:09 2001 @@ -0,0 +1,1562 @@ +#include <linux/sisfb.h> +#include <linux/kernel.h> +#include "init310.h" + +BOOLEAN SiSSetMode310(PHW_DEVICE_EXTENSION HwDeviceExtension, USHORT ModeNo); +BOOLEAN SiSInit310(PHW_DEVICE_EXTENSION HwDeviceExtension); + +#if defined(ALLOC_PRAGMA) +#pragma alloc_text(PAGE,SiSSetMode310) +#pragma alloc_text(PAGE,SiSInit310) +#endif + +BOOLEAN SiSInit310(PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + ULONG ROMAddr = (ULONG)HwDeviceExtension->VirtualRomBase; + ULONG FBAddr = (ULONG)HwDeviceExtension->VirtualVideoMemoryAddress; + USHORT BaseAddr = (USHORT)HwDeviceExtension->IOAddress; + UCHAR i,temp,AGP; + ULONG j,k,ulTemp; + UCHAR SR07,SR11,SR19,SR1A,SR1F,SR21,SR22,SR23,SR24,SR25,SR31,SR32,SR33; + UCHAR SR14; + USHORT Part1Port,Part2Port,Part4Port; + ULONG Temp; + + if (ROMAddr==0) return (FALSE); + if (FBAddr==0) return (FALSE); + if (BaseAddr==0) return (FALSE); + if (HwDeviceExtension->jChipID > SIS_GlamourII) + if (!HwDeviceExtension->bIntegratedMMEnabled) return (FALSE); + + SiSP3c4=BaseAddr+0x14; + SiSP3d4=BaseAddr+0x24; + SiSP3c0=BaseAddr+0x10; + SiSP3ce=BaseAddr+0x1e; + SiSP3c2=BaseAddr+0x12; + SiSP3ca=BaseAddr+0x1a; + SiSP3c6=BaseAddr+0x16; + SiSP3c7=BaseAddr+0x17; + SiSP3c8=BaseAddr+0x18; + SiSP3c9=BaseAddr+0x19; + SiSP3da=BaseAddr+0x2A; + SiSSet_LVDS_TRUMPION(); + + SiSSetReg1(SiSP3c4,0x05,0x86); + + SR14 = (UCHAR)SiSGetReg1(SiSP3c4,0x14); + SR19 = (UCHAR)SiSGetReg1(SiSP3c4,0x19); + SR1A = (UCHAR)SiSGetReg1(SiSP3c4,0x1A); + + for(i=0x06;i< 0x20;i++) SiSSetReg1(SiSP3c4,i,0); + for(i=0x21;i<=0x27;i++) SiSSetReg1(SiSP3c4,i,0); + for(i=0x31;i<=0x3D;i++) SiSSetReg1(SiSP3c4,i,0); + for(i=0x30;i<=0x37;i++) SiSSetReg1(SiSP3d4,i,0); + + if (HwDeviceExtension->jChipID > SIS_GlamourII) + temp=(UCHAR)SR1A; + else { + + temp=*((UCHAR *)(ROMAddr+SoftSettingAddr)); + if ((temp&SoftDRAMType)==0) { + temp=(UCHAR)SiSGetReg1(SiSP3c4,0x3A); + } + } + SiSRAMType=temp&0x03; + SiSSetMemoryClock(ROMAddr); + + for(k=0; k<5; k++) { + for(j=0; j<0xffff; j++) { + ulTemp = (ULONG)SiSGetReg1(SiSP3c4, 0x05); + } + } + Temp = (ULONG)SiSGetReg1(SiSP3c4, 0x3C); + Temp = Temp | 0x01; + SiSSetReg1(SiSP3c4, 0x3C, (USHORT)Temp); + for(k=0; k<5; k++) { + for(j=0; j<0x1000; j++) { + Temp = (ULONG)SiSGetReg1(SiSP3c4, 0x05); + } + } + Temp = (ULONG)SiSGetReg1(SiSP3c4, 0x3C); + Temp = Temp & 0xFE; + SiSSetReg1(SiSP3c4, 0x3C, (USHORT)Temp); + for(k=0; k<5; k++) { + for(j=0; j<0x1000; j++) { + Temp = (ULONG)SiSGetReg1(SiSP3c4, 0x05); + } + } + + SR07=*((UCHAR *)(ROMAddr+SR07_OFFSET)); + SiSSetReg1(SiSP3c4,0x07,SR07); + if (HwDeviceExtension->jChipID == SIS_GlamourII ) { + for(i=0x15;i<0x1C;i++) { + temp=*((UCHAR *)(ROMAddr+SR15_OFFSET+((i-0x15)*4)+SiSRAMType)); + SiSSetReg1(SiSP3c4,i,temp); + } + + for(i=0x40;i<=0x44;i++) { + temp=*((UCHAR *)(ROMAddr+CR40_OFFSET+(i-0x40)*4+SiSRAMType)); + SiSSetReg1(SiSP3d4,i,temp); + } + } + + SR1F=*((UCHAR *)(ROMAddr+SR1F_OFFSET)); + SiSSetReg1(SiSP3c4,0x1F,SR1F); + + AGP=1; + temp=(UCHAR)SiSGetReg1(SiSP3c4,0x3A); + temp=temp&0x30; + if (temp==0x30) AGP=0; + + SR21=*((UCHAR *)(ROMAddr+SR21_OFFSET)); + if (AGP==0) SR21=SR21&0xEF; + SiSSetReg1(SiSP3c4,0x21,SR21); + + SR22=*((UCHAR *)(ROMAddr+SR22_OFFSET)); + if (AGP==1) SR22=SR22&0x20; + SiSSetReg1(SiSP3c4,0x22,SR22); + + SR23=*((UCHAR *)(ROMAddr+SR23_OFFSET)); + SiSSetReg1(SiSP3c4,0x23,SR23); + + SR24=*((UCHAR *)(ROMAddr+SR24_OFFSET)); + SiSSetReg1(SiSP3c4,0x24,SR24); + + SR25=*((UCHAR *)(ROMAddr+SR25_OFFSET)); + SiSSetReg1(SiSP3c4,0x25,SR25); + + SiSSetReg1(SiSP3c4,0x27,0x1F); + + SR31=*((UCHAR *)(ROMAddr+SR31_OFFSET)); + SiSSetReg1(SiSP3c4,0x31,SR31); + + SR32=*((UCHAR *)(ROMAddr+SR32_OFFSET)); + SiSSetReg1(SiSP3c4,0x32,SR32); + + SR33=*((UCHAR *)(ROMAddr+SR33_OFFSET)); + SiSSetReg1(SiSP3c4,0x33,SR33); + + SR11=0x0F; + SiSSetReg1(SiSP3c4,0x11,SR11); + + if (SiSBridgeIsOn(BaseAddr)==1) { + SiSUnLockCRT2(HwDeviceExtension, BaseAddr); + Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; + Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; + Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14; + temp = *((UCHAR *)(ROMAddr+VB310Data_1_2_Offset)); + SiSSetReg1(Part1Port,0x02,temp); + SiSSetReg1(Part1Port,0x2E,0x08); + + SiSSetReg1(Part2Port,0x00,0x1C); + + temp = *((UCHAR *)(ROMAddr+VB310Data_4_D_Offset)); + SiSSetReg1(Part4Port,0x0D,temp); + temp = *((UCHAR *)(ROMAddr+VB310Data_4_E_Offset)); + SiSSetReg1(Part4Port,0x0E,temp); + temp = *((UCHAR *)(ROMAddr+VB310Data_4_10_Offset)); + SiSSetReg1(Part4Port,0x10,temp); + + SiSLockCRT2(HwDeviceExtension, BaseAddr); + } + + if (SIS_IF_DEF_LVDS==1) { + temp=ExtChipLVDS; + } else if (SIS_IF_DEF_TRUMPION==1) { + temp=ExtChipTrumpion; + } else { + temp=ExtChip301; + } + SiSSetReg1(SiSP3d4,0x37,temp); + + if ( HwDeviceExtension->jChipID == SIS_GlamourII ) { +/* + if (HwDeviceExtension->bSkipDramSizing == TRUE) { + SiSSetDRAMModeRegister(ROMAddr); + temp = HwDeviceExtension->ujSR13; + SiSSetReg1(SiSP3c4,0x13,temp); + temp = HwDeviceExtension->ujSR14; + SiSSetReg1(SiSP3c4,0x14,temp); + } else +*/ + SiSSetDRAMSize(HwDeviceExtension); + } else { + SiSSetReg1(SiSP3c4,0x14,SR14); + SiSSetReg1(SiSP3c4,0x19,SR19); + SiSSetReg1(SiSP3c4,0x1A,SR1A); + } + + SiSSetReg3(SiSP3c6,0xff); + SiSClearDAC(SiSP3c8); + + SiSDetectMonitor301(HwDeviceExtension); + SiSGetSenseStatus301(HwDeviceExtension,BaseAddr,ROMAddr); + + return(TRUE); +} + + +VOID SiSSet_LVDS_TRUMPION() +{ + SIS_IF_DEF_LVDS=0; + SIS_IF_DEF_TRUMPION=0; +} + +UCHAR SiSGet310DRAMType(ULONG ROMAddr) +{ + UCHAR data,SoftSetting; + + SoftSetting=*((UCHAR *)(ROMAddr+SoftSetting_OFFSET)); + + if (SoftSetting&SoftDRAMType) + data = SoftSetting & 0x03; + else + data=SiSGetReg1(SiSP3c4,0x3a) & 0x03; + + return data; +} + +VOID SiSDelay15us(ULONG ulMicrsoSec) +{ +} + +VOID SiSSDR_MRS(VOID) +{ + USHORT data; + + data=SiSGetReg1(SiSP3c4,0x16); + data=data & 0x3F; + SiSSetReg1(SiSP3c4,0x16,data); + SiSDelay15us(0x100); + data=data | 0x80; + SiSSetReg1(SiSP3c4,0x16,data); + SiSDelay15us(0x100); +} + +VOID SiSDDR_MRS(VOID) +{ + USHORT data; + + data=SiSGetReg1(SiSP3c4,0x16); + data &= 0x0F; + data |= 0x10; + SiSSetReg1(SiSP3c4,0x16,data); + + data |= 0xC0; + SiSSetReg1(SiSP3c4,0x16,data); + + data &= 0x0F; + data |= 0x20; + SiSSetReg1(SiSP3c4,0x16,data); + + data |= 0x80; + SiSSetReg1(SiSP3c4,0x16,data); +} + +VOID SiSSetDRAMModeRegister(ULONG ROMAddr) +{ + if (SiSGet310DRAMType(ROMAddr)<2) { + SiSSDR_MRS(); + } else { + SiSDDR_MRS(); + } +} + +VOID SiSDisableRefresh(VOID) +{ + USHORT data; + + data=SiSGetReg1(SiSP3c4,0x17); + data &= 0xF8; + SiSSetReg1(SiSP3c4,0x17,data); + + data=SiSGetReg1(SiSP3c4,0x19); + data |= 0x03; + SiSSetReg1(SiSP3c4,0x19,data); +} + +VOID SiSEnableRefresh(ULONG ROMAddr) +{ + USHORT data; + + data=SiSGetReg1(SiSP3c4,0x17); + data &= 0xF8; + data |= 0x01; + + data=*((UCHAR *)(ROMAddr+SR17_OFFSET+SiSRAMType)); + SiSSetReg1(SiSP3c4,0x17,data); + + data=SiSGetReg1(SiSP3c4,0x19); + data &= 0xFC; + data=*((UCHAR *)(ROMAddr+SR19_OFFSET+SiSRAMType)); + SiSSetReg1(SiSP3c4,0x19,data); +} + +VOID SiSDisableChannelInterleaving(int index,USHORT SIS_DDRDRAM_TYPE[][5]) +{ + USHORT data; + + data=SiSGetReg1(SiSP3c4,0x15); + data &= 0x1F; + switch (SIS_DDRDRAM_TYPE[index][3]) { + case 64: + data |= 0; break; + case 32: + data |= 0x20; break; + case 16: + data |= 0x40; break; + case 4: + data |= 0x60; break; + } + SiSSetReg1(SiSP3c4,0x15,data); +} + + +VOID SiSSetDRAMSizingType(int index,USHORT DRAMTYPE_TABLE[][5]) +{ + USHORT data; + + data = DRAMTYPE_TABLE[index][4]; + SiSSetReg1(SiSP3c4,0x13,data); +} + + +VOID SiSCheckBusWidth(ULONG ROMAddress,ULONG FBAddress) +{ + USHORT data; + PULONG pVideoMemory; + + pVideoMemory = (PULONG) FBAddress; + if (SiSGet310DRAMType(ROMAddress)<2) { + SiSSetReg1(SiSP3c4,0x13,0x00); + SiSSetReg1(SiSP3c4,0x14,0x12); + + SiSChannelAB = 0; + SiSDataBusWidth = 128; + pVideoMemory[0] = 0x01234567; + pVideoMemory[1] = 0x456789AB; + pVideoMemory[2] = 0x89ABCDEF; + pVideoMemory[3] = 0xCDEF0123; + pVideoMemory[4] = 0x55555555; + pVideoMemory[5] = 0x55555555; + pVideoMemory[6] = 0xFFFFFFFF; + pVideoMemory[7] = 0xFFFFFFFF; + if ((pVideoMemory[3]!=0xCDEF0123) || (pVideoMemory[2] != 0x89ABCDEF)) { + SiSDataBusWidth = 64; + SiSChannelAB = 0; + data=SiSGetReg1(SiSP3c4,0x14); + SiSSetReg1(SiSP3c4, 0x14, (USHORT) (data & 0xFD)); + } + + if ((pVideoMemory[1]!=0x456789AB) || (pVideoMemory[0] != 0x01234567)) { + SiSDataBusWidth = 64; + SiSChannelAB = 1; + data=SiSGetReg1(SiSP3c4,0x14); + SiSSetReg1(SiSP3c4,0x14,(USHORT)((data&0xFD)|0x01)); + } + return; + } else { + SiSSetReg1(SiSP3c4,0x13,0x00); + SiSSetReg1(SiSP3c4,0x14,0x02); + + SiSChannelAB = 0; + SiSDataBusWidth = 64; + pVideoMemory[0] = 0x01234567; + pVideoMemory[1] = 0x456789AB; + pVideoMemory[2] = 0x89ABCDEF; + pVideoMemory[3] = 0xCDEF0123; + pVideoMemory[4] = 0x55555555; + pVideoMemory[5] = 0x55555555; + pVideoMemory[6] = 0xAAAAAAAA; + pVideoMemory[7] = 0xAAAAAAAA; + + if (pVideoMemory[1] != 0x456789AB) { + if (pVideoMemory[0] == 0x01234567) { + SiSDataBusWidth = 32; + SiSSetReg1(SiSP3c4,0x14,0x00); + } else { + SiSSetReg1(SiSP3c4,0x14,0x03); + + SiSChannelAB = 1; + if (pVideoMemory[1] != 0x456789AB) { + SiSDataBusWidth = 32; + SiSSetReg1(SiSP3c4,0x14,0x01); + } else { + + } + } + } else { + if (pVideoMemory[0] == 0x01234567) { + + } else { + SiSSetReg1(SiSP3c4,0x14,0x03); + + SiSChannelAB = 1; + if (pVideoMemory[1] != 0x456789AB) { + SiSDataBusWidth = 32; + SiSSetReg1(SiSP3c4,0x14,0x01); + } else { + + } + } + } + } +} + +int SiSSetRank(int index,UCHAR RankNo,UCHAR SiSChannelAB,USHORT DRAMTYPE_TABLE[][5]) +{ + USHORT data; + int RankSize; + + if ((RankNo==2)&&(DRAMTYPE_TABLE[index][0]==2)) + return 0; + + RankSize = DRAMTYPE_TABLE[index][3] * SiSDataBusWidth/64; + + if (RankNo*RankSize<=128) { + data = 0; + while ((RankSize>>=1)>0) { + data+=0x10; + } + data |= (RankNo-1)<<2; + data |= (SiSDataBusWidth/64)&2; + data |= SiSChannelAB; + SiSSetReg1(SiSP3c4,0x14,data); + SiSSDR_MRS(); + + return 1; + } else + return 0; +} + +int SiSSetDDRChannel(int index,UCHAR ChannelNo,UCHAR SiSChannelAB,USHORT DRAMTYPE_TABLE[][5]) +{ + USHORT data; + int RankSize; + + RankSize = DRAMTYPE_TABLE[index][3]; + if (ChannelNo*RankSize<=128) { + data = 0; + while ((RankSize>>=1)>0) { + data+=0x10; + } + if (ChannelNo==2) + data |= 0x0C; + + data |= (SiSDataBusWidth/32)&2; + data |= SiSChannelAB; + SiSSetReg1(SiSP3c4,0x14,data); + + SiSDDR_MRS(); + + return 1; + } else + return 0; +} + + +int SiSCheckColumn(int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress) +{ + int i; + ULONG Increment,Position; + + + Increment = 1<<(10 + SiSDataBusWidth / 64); + + for (i=0,Position=0;i<2;i++) { + *((PULONG)(FBAddress+Position))=Position; + Position += Increment; + } + + for (i=0,Position=0;i<2;i++) { + if ( (*(PULONG) (FBAddress + Position)) !=Position) + return 0; + Position += Increment; + } + return 1; +} + +int SiSCheckBanks(int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress) +{ + int i; + ULONG Increment,Position; + Increment = 1<<(DRAMTYPE_TABLE[index][2] + SiSDataBusWidth / 64 + 2); + + for (i=0,Position=0;i<4;i++) { + *((PULONG)(FBAddress+Position))=Position; + Position += Increment; + } + + for (i=0,Position=0;i<4;i++) { + if ( (*(PULONG) (FBAddress + Position)) !=Position) + return 0; + Position += Increment; + } + return 1; +} + +int SiSCheckRank(int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress) +{ + int i; + ULONG Increment,Position; + Increment = 1<<(DRAMTYPE_TABLE[index][2] + DRAMTYPE_TABLE[index][1] + + DRAMTYPE_TABLE[index][0] + SiSDataBusWidth / 64 + RankNo); + + for (i=0,Position=0;i<2;i++) { + *((PULONG)(FBAddress+Position))=Position; + Position += Increment; + } + + for (i=0,Position=0;i<2;i++) { + if ( (*(PULONG) (FBAddress + Position)) != Position) + return 0; + Position += Increment; + } + return 1; + +} + +int SiSCheckRanks(int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress) +{ + int r; + + for (r=RankNo;r>=1;r--) { + if (!SiSCheckRank(r,index,DRAMTYPE_TABLE,FBAddress)) + return 0; + } + if (!SiSCheckBanks(index,DRAMTYPE_TABLE,FBAddress)) + return 0; + + if (!SiSCheckColumn(index,DRAMTYPE_TABLE,FBAddress)) + return 0; + + return 1; +} + + +int SiSSDRSizing(ULONG FBAddress) +{ + int i; + UCHAR j; + + for (i=0;i<11;i++) { + SiSSetDRAMSizingType(i, SIS_SDRDRAM_TYPE); + for (j=2;j>0;j--) { + if (!SiSSetRank(i,(UCHAR) j, SiSChannelAB,SIS_SDRDRAM_TYPE)) + continue; + else { + if (SiSCheckRanks(j,i,SIS_SDRDRAM_TYPE, FBAddress)) + return 1; + } + } + } + return 0; +} + +int SiSDDRSizing(ULONG FBAddress) +{ + + int i; + UCHAR j; + + for (i=0;i<4;i++) { + SiSSetDRAMSizingType(i,SIS_DDRDRAM_TYPE); + SiSDisableChannelInterleaving(i,SIS_DDRDRAM_TYPE); + for (j=2;j>0;j--) { + + SiSSetDDRChannel(i, j, SiSChannelAB, SIS_DDRDRAM_TYPE); + if (!SiSSetRank(i,(UCHAR) j, SiSChannelAB,SIS_SDRDRAM_TYPE)) + continue; + else { + if (SiSCheckRanks(j,i,SIS_SDRDRAM_TYPE, FBAddress)) + return 1; + } + } + } + return 0; +} + +VOID SiSVerifyMclk(ULONG FBAddr) +{ + PUCHAR pVideoMemory = (PUCHAR) FBAddr; + UCHAR i,j; + USHORT Temp,SR21; + + + pVideoMemory[0]=0xaa; + pVideoMemory[16]=0x55; + + if ((pVideoMemory[0]!=0xaa)||(pVideoMemory[16]!=0x55)) { + for (i=0,j=16;i<2;i++,j+=16) { + SR21 = SiSGetReg1(SiSP3c4, 0x21); + Temp = SR21 & 0xFB; + SiSSetReg1(SiSP3c4, 0x21, Temp); + + Temp = SiSGetReg1(SiSP3c4, 0x3C); + Temp = Temp | 0x01; + SiSSetReg1(SiSP3c4, 0x3C, Temp); + Temp = SiSGetReg1(SiSP3c4, 0x3C); + Temp = Temp & 0xFE; + SiSSetReg1(SiSP3c4, 0x3C, Temp); + SiSSetReg1(SiSP3c4, 0x21, SR21); + + pVideoMemory[16+j] = j; + if (pVideoMemory[16+j]==j) { + pVideoMemory[j] = j; + break; + } + } + } +} + +VOID SiSSetDRAMSize(PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + ULONG ROMAddr = (ULONG)HwDeviceExtension->VirtualRomBase; + ULONG FBAddr = (ULONG)HwDeviceExtension->VirtualVideoMemoryAddress; + USHORT data; + +#ifdef SIS301 + +#else +#ifdef SIS302 + SiSSetReg1(SiSP3d4,0x30,0x4D); + SiSSetReg1(SiSP3d4,0x31,0xc0); + SiSSetReg1(SiSP3d4,0x34,0x3F); +#endif +#endif + SiSSetMode310(HwDeviceExtension,0x2e); + + data=SiSGetReg1(SiSP3c4,0x21); + SiSSetReg1(SiSP3c4,0x21,(USHORT) (data&0xDF)); + + data=SiSGetReg1(SiSP3c4,0x1); + data=data|0x20; + SiSSetReg1(SiSP3c4,0x01,data); + + data=SiSGetReg1(SiSP3c4,0x16); + SiSSetReg1(SiSP3c4,0x16,(USHORT) (data|0x0F)); + + SiSSetDRAMModeRegister(ROMAddr); + SiSDisableRefresh(); + SiSCheckBusWidth(ROMAddr,FBAddr); + SiSVerifyMclk(FBAddr); + + if (SiSGet310DRAMType(ROMAddr)<2) { + SiSSDRSizing(FBAddr); + } else { + SiSDDRSizing(FBAddr); + } + + data=*((UCHAR *)(ROMAddr+SR16_OFFSET+SiSRAMType)); + SiSSetReg1(SiSP3c4,0x16,data); + + SiSEnableRefresh(ROMAddr); + data=SiSGetReg1(SiSP3c4,0x21); + SiSSetReg1(SiSP3c4,0x21,(USHORT) (data|0x20)); +} + +VOID SiSSetMemoryClock(ULONG ROMAddr) +{ + UCHAR data,i; + + SiSMCLKData=*((USHORT *)(ROMAddr+MCLKDataPtrOffset)); + SiSMCLKData=SiSMCLKData+SiSRAMType*5; + SiSECLKData=SiSMCLKData+ECLK_MCLK_DISTANCE; + + for(i=0x28;i<=0x2A;i++) { + data=*((UCHAR *)(ROMAddr+SiSMCLKData)); + SiSSetReg1(SiSP3c4,i,data); + SiSMCLKData++; + } + + for(i=0x2E;i<=0x30;i++) { + data=*((UCHAR *)(ROMAddr+SiSECLKData)); + SiSSetReg1(SiSP3c4,i,data); + SiSECLKData++; + } +} + +BOOLEAN SiSSetMode310(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT ModeNo) +{ + ULONG temp; + USHORT cr30flag,cr31flag; + ULONG ROMAddr = (ULONG)HwDeviceExtension->VirtualRomBase; + USHORT BaseAddr = (USHORT)HwDeviceExtension->IOAddress; + + SiSP3c4=BaseAddr+0x14; + SiSP3d4=BaseAddr+0x24; + SiSP3c0=BaseAddr+0x10; + SiSP3ce=BaseAddr+0x1e; + SiSP3c2=BaseAddr+0x12; + SiSP3ca=BaseAddr+0x1a; + SiSP3c6=BaseAddr+0x16; + SiSP3c7=BaseAddr+0x17; + SiSP3c8=BaseAddr+0x18; + SiSP3c9=BaseAddr+0x19; + SiSP3da=BaseAddr+0x2A; + if (ModeNo&0x80) { + ModeNo=ModeNo&0x7F; + SiS_flag_clearbuffer=0; + } else { + SiS_flag_clearbuffer=1; + } + + SiSPresetScratchregister301(SiSP3d4,HwDeviceExtension); + + SiSSetReg1(SiSP3c4,0x05,0x86); + temp=SiSSearchModeID(ROMAddr,ModeNo); + if (temp==0) return(0); + + SiSSetTVSystem301(HwDeviceExtension,ROMAddr); + SiSGetLCDDDCInfo301(HwDeviceExtension); + SiSGetVBInfo301(BaseAddr,ROMAddr); + SiSGetLCDResInfo301(ROMAddr,SiSP3d4); + + temp=SiSCheckMemorySize(ROMAddr); + if (temp==0) return(0); + cr30flag=(UCHAR)SiSGetReg1(SiSP3d4,0x30); + if (((cr30flag&0x01)==1)||((cr30flag&0x02)==0)) { + SiSSetReg1(SiSP3d4,0x34,ModeNo); + + SiSGetModePtr(ROMAddr,ModeNo); + SiSSetSeqRegs(ROMAddr); + SiSSetMiscRegs(ROMAddr); + SiSSetCRTCRegs(ROMAddr); + SiSSetATTRegs(ROMAddr); + SiSSetGRCRegs(ROMAddr); + SiSClearExt1Regs(); + temp=SiSGetRatePtr(ROMAddr,ModeNo); + if (temp) { + SiSSetSync(ROMAddr); + SiSSetCRT1CRTC(ROMAddr); + SiSSetCRT1Offset(ROMAddr); + SiSSetCRT1VCLK(HwDeviceExtension, ROMAddr); + SiSSetVCLKState(HwDeviceExtension, ROMAddr, ModeNo); + if (HwDeviceExtension->jChipID > SIS_GlamourII) + SiSSetCRT1FIFO2(ROMAddr,HwDeviceExtension); + else + SiSSetCRT1FIFO(ROMAddr,ModeNo,HwDeviceExtension); + } + SiSSetCRT1ModeRegs(ROMAddr, ModeNo); + if (HwDeviceExtension->jChipID > SIS_GlamourII) + SiSSetInterlace(ROMAddr,ModeNo); + SiSLoadDAC(ROMAddr); + if (SiS_flag_clearbuffer) SiSClearBuffer(HwDeviceExtension); + } + cr31flag=(UCHAR)SiSGetReg1(SiSP3d4,0x31); + if (((cr30flag&0x01)==1)||((cr30flag&0x03)==0x02) + ||(((cr30flag&0x03)==0x00)&&((cr31flag&0x20)==0x20))) { + switch (HwDeviceExtension->hasVB) { + case HASVB_301: + SiSSetCRT2Group301(BaseAddr,ROMAddr,ModeNo, HwDeviceExtension); + break; + case HASVB_302: + case HASVB_303: + break; + default: + break; + } + } + SiSDisplayOn(); + return(NO_ERROR); +} + + +BOOLEAN SiSSearchModeID(ULONG ROMAddr, USHORT ModeNo) +{ + UCHAR ModeID; + USHORT usIDLength; + + SiSModeIDOffset=*((USHORT *)(ROMAddr+EModeIDTablePtrOffset)); + ModeID=*((UCHAR *)(ROMAddr+SiSModeIDOffset)); + usIDLength = SiSGetModeIDLength(ROMAddr, ModeNo); + while(ModeID!=0xff && ModeID!=ModeNo) { + SiSModeIDOffset=SiSModeIDOffset+usIDLength; + ModeID=*((UCHAR *)(ROMAddr+SiSModeIDOffset)); + } + if (ModeID==0xff) return(FALSE); + else return(TRUE); +} + +BOOLEAN SiSCheckMemorySize(ULONG ROMAddr) +{ + USHORT memorysize; + USHORT modeflag; + USHORT temp; + + modeflag=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + SiSModeType=modeflag&ModeInfoFlag; + + memorysize=modeflag&MemoryInfoFlag; + memorysize=memorysize>MemorySizeShift; + memorysize++; + + temp=SiSGetReg1(SiSP3c4,0x14); + + if ((temp&0x0c)!=0) { + temp=1 << ((temp&0x0F0)>>4); + temp <<= 1; + } else { + temp=1 << ((temp&0x0F0)>>4); + } + + if (temp<memorysize) return(FALSE); + else return(TRUE); +} + +VOID SiSGetModePtr(ULONG ROMAddr, USHORT ModeNo) +{ + UCHAR index; + + SiSStandTable=*((USHORT *)(ROMAddr+StandTablePtrOffset)); + + if (ModeNo<=13) { + index=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x03)); + } else { + if (SiSModeType <= 0x02) index=0x1B; + else index=0x0F; + } + + SiSStandTable=SiSStandTable+64*index; +} + +VOID SiSSetSeqRegs(ULONG ROMAddr) +{ + UCHAR SRdata; + USHORT i; + + SiSSetReg1(SiSP3c4,0x00,0x03); + SiSStandTable=SiSStandTable+0x05; + SRdata=*((UCHAR *)(ROMAddr+SiSStandTable)); + if (SIS_IF_DEF_LVDS==1) { + if (SiSVBInfo&SetCRT2ToLCD) { + if (SiSVBInfo&SetInSlaveMode) { + if (SiSLCDInfo&LCDNonExpanding) { + SRdata=SRdata|0x01; + } + } + } + } + + SRdata=SRdata|0x20; + SiSSetReg1(SiSP3c4,0x01,SRdata); + for(i=02;i<=04;i++) { + SiSStandTable++; + SRdata=*((UCHAR *)(ROMAddr+SiSStandTable)); + SiSSetReg1(SiSP3c4,i,SRdata); + } +} + +VOID SiSSetMiscRegs(ULONG ROMAddr) +{ + UCHAR Miscdata; + + SiSStandTable++; + Miscdata=*((UCHAR *)(ROMAddr+SiSStandTable)); + SiSSetReg3(SiSP3c2,Miscdata); +} + +VOID SiSSetCRTCRegs(ULONG ROMAddr) +{ + UCHAR CRTCdata; + USHORT i; + + CRTCdata=(UCHAR)SiSGetReg1(SiSP3d4,0x11); + CRTCdata=CRTCdata&0x7f; + SiSSetReg1(SiSP3d4,0x11,CRTCdata); + + for(i=0;i<=0x18;i++) { + SiSStandTable++; + CRTCdata=*((UCHAR *)(ROMAddr+SiSStandTable)); + SiSSetReg1(SiSP3d4,i,CRTCdata); + } +} + +VOID SiSSetATTRegs(ULONG ROMAddr) +{ + UCHAR ARdata; + USHORT i; + + for(i=0;i<=0x13;i++) { + SiSStandTable++; + ARdata=*((UCHAR *)(ROMAddr+SiSStandTable)); + if (SIS_IF_DEF_LVDS==1) { + if (SiSVBInfo&SetCRT2ToLCD) { + if (SiSVBInfo&SetInSlaveMode) { + if (SiSLCDInfo&LCDNonExpanding) { + if (i==0x13) { + ARdata=0; + } + } + } + } + } + SiSGetReg2(SiSP3da); + SiSSetReg3(SiSP3c0,i); + SiSSetReg3(SiSP3c0,ARdata); + } + if (SIS_IF_DEF_LVDS==1) { + if (SiSVBInfo&SetCRT2ToLCD) { + if (SiSVBInfo&SetInSlaveMode) { + if (SiSLCDInfo&LCDNonExpanding) { + + } + } + } + } + SiSGetReg2(SiSP3da); + SiSSetReg3(SiSP3c0,0x14); + SiSSetReg3(SiSP3c0,0x00); + + SiSGetReg2(SiSP3da); + SiSSetReg3(SiSP3c0,0x20); +} + +VOID SiSSetGRCRegs(ULONG ROMAddr) +{ + UCHAR GRdata; + USHORT i; + + for(i=0;i<=0x08;i++) { + SiSStandTable++; + GRdata=*((UCHAR *)(ROMAddr+SiSStandTable)); + SiSSetReg1(SiSP3ce,i,GRdata); + } + if (SiSModeType>ModeVGA) { + GRdata=(UCHAR)SiSGetReg1(SiSP3ce,0x05); + GRdata=GRdata&0xBF; + SiSSetReg1(SiSP3ce,0x05,GRdata); + } +} + +VOID SiSClearExt1Regs() +{ + USHORT i; + + for(i=0x0A;i<=0x0E;i++) SiSSetReg1(SiSP3c4,i,0x00); +} + + +BOOLEAN SiSGetRatePtr(ULONG ROMAddr, USHORT ModeNo) +{ + SHORT index; + USHORT temp; + USHORT ulRefIndexLength; + + if (ModeNo<0x14) return(FALSE); + + index=SiSGetReg1(SiSP3d4,0x33); + index=index&0x0F; + if (index!=0) index--; + + SiSREFIndex=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x05)); + + ulRefIndexLength = SiSGetRefindexLength(ROMAddr, ModeNo); + do { + temp=*((USHORT *)(ROMAddr+SiSREFIndex)); + if (temp==0xFFFF) break; + temp=temp&ModeInfoFlag; + if (temp<SiSModeType) break; + + SiSREFIndex=SiSREFIndex+ulRefIndexLength; + index--; + } while(index>=0); + + SiSREFIndex=SiSREFIndex-ulRefIndexLength; + return(TRUE); +} + +VOID SiSSetSync(ULONG ROMAddr) +{ + USHORT sync; + USHORT temp; + + sync=*((USHORT *)(ROMAddr+SiSREFIndex)); + sync=sync&0xC0; + temp=0x2F; + temp=temp|sync; + SiSSetReg3(SiSP3c2,temp); +} + +VOID SiSSetCRT1CRTC(ULONG ROMAddr) +{ + UCHAR index; + UCHAR data; + USHORT i; + + index=*((UCHAR *)(ROMAddr+SiSREFIndex+0x02)); + SiSCRT1Table=*((USHORT *)(ROMAddr+CRT1TablePtrOffset)); + SiSCRT1Table=SiSCRT1Table+index*CRT1Len; + + data=(UCHAR)SiSGetReg1(SiSP3d4,0x11); + data=data&0x7F; + SiSSetReg1(SiSP3d4,0x11,data); + + SiSCRT1Table--; + for(i=0;i<=0x05;i++) { + SiSCRT1Table++; + data=*((UCHAR *)(ROMAddr+SiSCRT1Table)); + SiSSetReg1(SiSP3d4,i,data); + } + for(i=0x06;i<=0x07;i++) { + SiSCRT1Table++; + data=*((UCHAR *)(ROMAddr+SiSCRT1Table)); + SiSSetReg1(SiSP3d4,i,data); + } + for(i=0x10;i<=0x12;i++) { + SiSCRT1Table++; + data=*((UCHAR *)(ROMAddr+SiSCRT1Table)); + SiSSetReg1(SiSP3d4,i,data); + } + for(i=0x15;i<=0x16;i++) { + SiSCRT1Table++; + data=*((UCHAR *)(ROMAddr+SiSCRT1Table)); + SiSSetReg1(SiSP3d4,i,data); + } + for(i=0x0A;i<=0x0C;i++) { + SiSCRT1Table++; + data=*((UCHAR *)(ROMAddr+SiSCRT1Table)); + SiSSetReg1(SiSP3c4,i,data); + } + + SiSCRT1Table++; + data=*((UCHAR *)(ROMAddr+SiSCRT1Table)); + data=data&0xE0; + SiSSetReg1(SiSP3c4,0x0E,data); + + data=(UCHAR)SiSGetReg1(SiSP3d4,0x09); + data=data&0xDF; + i=*((UCHAR *)(ROMAddr+SiSCRT1Table)); + i=i&0x01; + i=i<<5; + data=data|i; + i=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + i=i&DoubleScanMode; + if (i) data=data|0x80; + SiSSetReg1(SiSP3d4,0x09,data); + + if (SiSModeType>0x03) SiSSetReg1(SiSP3d4,0x14,0x4F); +} + +VOID SiSSetCRT1Offset(ULONG ROMAddr) +{ + USHORT temp,ah,al; + USHORT temp2,i; + USHORT DisplayUnit; + + + temp=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x03)); + temp=temp>>8; + SiSScreenOffset=*((USHORT *)(ROMAddr+ScreenOffsetPtrOffset)); + temp=*((UCHAR *)(ROMAddr+SiSScreenOffset+temp)); + + temp2=*((USHORT *)(ROMAddr+SiSREFIndex+0x00)); + temp2=temp2&InterlaceMode; + if (temp2) temp=temp<<1; + temp2=SiSModeType-ModeEGA; + switch (temp2) { + case 0 : temp2=1; break; + case 1 : temp2=2; break; + case 2 : temp2=4; break; + case 3 : temp2=4; break; + case 4 : temp2=6; break; + case 5 : temp2=8; break; + } + temp=temp*temp2; + DisplayUnit=temp; + + temp2=temp; + temp=temp>>8; + temp=temp&0x0F; + i=SiSGetReg1(SiSP3c4,0x0E); + i=i&0xF0; + i=i|temp; + SiSSetReg1(SiSP3c4,0x0E,i); + + temp=(UCHAR)temp2; + temp=temp&0xFF; + SiSSetReg1(SiSP3d4,0x13,temp); + + temp2=*((USHORT *)(ROMAddr+SiSREFIndex+0x00)); + temp2=temp2&InterlaceMode; + if (temp2) DisplayUnit>>=1; + + DisplayUnit=DisplayUnit<<5; + ah=(DisplayUnit&0xff00)>>8; + al=DisplayUnit&0x00ff; + if (al==0) ah=ah+1; + else ah=ah+2; + SiSSetReg1(SiSP3c4,0x10,ah); +} + +VOID SiSSetCRT1VCLK(PHW_DEVICE_EXTENSION HwDeviceExtension, ULONG ROMAddr) +{ + USHORT i; + UCHAR index,data; + + index=*((UCHAR *)(ROMAddr+SiSREFIndex+0x03)); + SiSCRT1VCLKLen=SiSGetVCLKLen(ROMAddr,HwDeviceExtension); + data=index*SiSCRT1VCLKLen; + SiSVCLKData=*((USHORT *)(ROMAddr+VCLKDataPtrOffset)); + SiSVCLKData=SiSVCLKData+data; + + SiSSetReg1(SiSP3c4,0x31,0); + + + for(i=0x2B;i<=0x2C;i++) { + data=*((UCHAR *)(ROMAddr+SiSVCLKData)); + SiSSetReg1(SiSP3c4,i,data); + SiSVCLKData++; + } + SiSSetReg1(SiSP3c4,0x2D,0x80); +} + +VOID SiSIsLowResolution(ULONG ROMAddr,USHORT ModeNo) +{ + USHORT data; + USHORT ModeFlag; + + + data = SiSGetReg1(SiSP3c4,0x0F); + data = data&0x7F; + SiSSetReg1(SiSP3c4,0x0F,data); + + if (ModeNo>0x13) { + ModeFlag = *((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + if ((ModeFlag & HalfDCLK) && (ModeFlag & DoubleScanMode)) { + data = SiSGetReg1(SiSP3c4,0x0F); + data = data|0x80; + SiSSetReg1(SiSP3c4,0x0F,data); + data = SiSGetReg1(SiSP3c4,0x01); + data = data&0xF7; + SiSSetReg1(SiSP3c4,0x01,data); + } + } +} + +VOID SiSSetCRT1ModeRegs(ULONG ROMAddr, USHORT ModeNo) +{ + USHORT data,data2,data3; + + if (ModeNo>0x13) data=*((USHORT *)(ROMAddr+SiSREFIndex+0x00)); + else data=0; + + data2=0; + if (ModeNo>0x13) + if (SiSModeType>0x02) { + data2=data2|0x02; + data3=SiSModeType-ModeVGA; + data3=data3<<2; + data2=data2|data3; + } + + data=data&InterlaceMode; + if (data) data2=data2|0x20; + SiSSetReg1(SiSP3c4,0x06,data2); + + data=SiSGetReg1(SiSP3c4,0x01); + data=data&0xF7; + data2=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + data2=data2&HalfDCLK; + if (data2) data=data|0x08; + SiSSetReg1(SiSP3c4,0x01,data); + + data=SiSGetReg1(SiSP3c4,0x0F); + data=data&0xF7; + data2=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + data2=data2&LineCompareOff; + if (data2) data=data|0x08; + SiSSetReg1(SiSP3c4,0x0F,data); + + data=SiSGetReg1(SiSP3c4,0x21); + data=data&0x1F; + if (SiSModeType==0x00) data=data|0x60; + else if (SiSModeType<=0x02) data=data|0x00; + else data=data|0xA0; + SiSSetReg1(SiSP3c4,0x21,data); +} + +VOID SiSSetVCLKState(PHW_DEVICE_EXTENSION HwDeviceExtension, ULONG ROMAddr, USHORT ModeNo) +{ + USHORT data,data2; + USHORT VCLK; + UCHAR index; + + index=*((UCHAR *)(ROMAddr+SiSREFIndex+0x03)); + SiSCRT1VCLKLen=SiSGetVCLKLen(ROMAddr,HwDeviceExtension); + data=index*SiSCRT1VCLKLen; + SiSVCLKData=*((USHORT *)(ROMAddr+VCLKDataPtrOffset)); + + SiSVCLKData=SiSVCLKData+data+(SiSCRT1VCLKLen-2); + + VCLK=*((USHORT *)(ROMAddr+SiSVCLKData)); + if (ModeNo<=0x13) VCLK=0; + + data=SiSGetReg1(SiSP3c4,0x32); + data=data&0xf3; + if (VCLK>=200) data=data|0x0c; + SiSSetReg1(SiSP3c4,0x32,data); + + data2=0x03; + if (VCLK>135) data2=0x02; + if (VCLK>160) data2=0x01; + if (VCLK>260) data2=0x00; + data=SiSGetReg1(SiSP3c4,0x07); + + data &= 0xFB; + + data=data&0xFC; + data=data|data2; + SiSSetReg1(SiSP3c4,0x07,data); +} + +VOID SiSLoadDAC(ULONG ROMAddr) +{ + USHORT data,data2; + USHORT time,i,j,k; + USHORT m,n,o; + USHORT si,di,bx,dl; + USHORT al,ah,dh; + USHORT *table=SIS_VGA_DAC; + + data=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + data=data&DACInfoFlag; + time=64; + if (data==0x00) table=SIS_MDA_DAC; + if (data==0x08) table=SIS_CGA_DAC; + if (data==0x10) table=SIS_EGA_DAC; + if (data==0x18) { + time=256; + table=SIS_VGA_DAC; + } + if (time==256) j=16; + else j=time; + + SiSSetReg3(SiSP3c6,0xFF); + SiSSetReg3(SiSP3c8,0x00); + + for(i=0;i<j;i++) { + data=table[i]; + for(k=0;k<3;k++) { + data2=0; + if (data&0x01) data2=0x2A; + if (data&0x02) data2=data2+0x15; + SiSSetReg3(SiSP3c9,data2); + data=data>>2; + } + } + + if (time==256) { + for(i=16;i<32;i++) { + data=table[i]; + for(k=0;k<3;k++) SiSSetReg3(SiSP3c9,data); + } + si=32; + for(m=0;m<9;m++) { + di=si; + bx=si+0x04; + dl=0; + for(n=0;n<3;n++) { + for(o=0;o<5;o++) { + dh=table[si]; + ah=table[di]; + al=table[bx]; + si++; + SiSWriteDAC(dl,ah,al,dh); + } + si=si-2; + for(o=0;o<3;o++) { + dh=table[bx]; + ah=table[di]; + al=table[si]; + si--; + SiSWriteDAC(dl,ah,al,dh); + } + dl++; + } + si=si+5; + } + } +} + +VOID SiSWriteDAC(USHORT dl, USHORT ah, USHORT al, USHORT dh) +{ + USHORT temp; + USHORT bh,bl; + + bh=ah; + bl=al; + if (dl!=0) { + temp=bh; + bh=dh; + dh=temp; + if (dl==1) { + temp=bl; + bl=dh; + dh=temp; + } else { + temp=bl; + bl=bh; + bh=temp; + } + } + SiSSetReg3(SiSP3c9,(USHORT)dh); + SiSSetReg3(SiSP3c9,(USHORT)bh); + SiSSetReg3(SiSP3c9,(USHORT)bl); +} + +VOID SiSDisplayOn() +{ + USHORT data; + + data=SiSGetReg1(SiSP3c4,0x01); + data=data&0xDF; + SiSSetReg1(SiSP3c4,0x01,data); +} + +USHORT SiSGetModeIDLength(ULONG ROMAddr, USHORT ModeNo) +{ + UCHAR ModeID; + USHORT modeidlength; + USHORT usModeIDOffset; + + modeidlength=0; + usModeIDOffset=*((USHORT *)(ROMAddr+EModeIDTablePtrOffset)); + ModeID=*((UCHAR *)(ROMAddr+usModeIDOffset)); + while(ModeID!=0x2E) { + modeidlength++; + usModeIDOffset=usModeIDOffset+1; + ModeID=*((UCHAR *)(ROMAddr+usModeIDOffset)); + } + return(modeidlength); +} + +USHORT SiSGetRefindexLength(ULONG ROMAddr, USHORT ModeNo) +{ + UCHAR ModeID; + UCHAR temp; + USHORT refindexlength; + USHORT usModeIDOffset; + USHORT usREFIndex; + USHORT usIDLength; + + usModeIDOffset=*((USHORT *)(ROMAddr+EModeIDTablePtrOffset)); + ModeID=*((UCHAR *)(ROMAddr+usModeIDOffset)); + usIDLength = SiSGetModeIDLength(ROMAddr, ModeNo); + while(ModeID!=0x40) { + usModeIDOffset=usModeIDOffset+usIDLength; + ModeID=*((UCHAR *)(ROMAddr+usModeIDOffset)); + } + + refindexlength=1; + usREFIndex=*((USHORT *)(ROMAddr+usModeIDOffset+0x05)); + usREFIndex++; + temp=*((UCHAR *)(ROMAddr+usREFIndex)); + while(temp!=0xFF) { + refindexlength++; + usREFIndex++; + temp=*((UCHAR *)(ROMAddr+usREFIndex)); + } + return(refindexlength); +} + +VOID SiSSetInterlace(ULONG ROMAddr, USHORT ModeNo) +{ + ULONG Temp; + USHORT data,Temp2; + + Temp = (ULONG)SiSGetReg1(SiSP3d4, 0x01); + Temp++; + Temp=Temp*8; + + if (Temp==1024) data=0x0035; + else if (Temp==1280) data=0x0048; + else data=0x0000; + + Temp2=*((USHORT *)(ROMAddr+SiSREFIndex+0x00)); + Temp2 &= InterlaceMode; + if (Temp2 == 0) data=0x0000; + + SiSSetReg1(SiSP3d4,0x19,data); + + Temp = (ULONG)SiSGetReg1(SiSP3d4, 0x1A); + Temp2= (USHORT)(Temp & 0xFC); + SiSSetReg1(SiSP3d4,0x1A,(USHORT)Temp); + + Temp = (ULONG)SiSGetReg1(SiSP3c4, 0x0f); + Temp2= (USHORT)Temp & 0xBF; + if (ModeNo==0x37) Temp2=Temp2|0x40; + SiSSetReg1(SiSP3d4,0x1A,(USHORT)Temp2); +} + +VOID SiSSetCRT1FIFO(ULONG ROMAddr,USHORT ModeNo,PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + + USHORT data; + + data=SiSGetReg1(SiSP3c4,0x3D); + data &= 0xfe; + SiSSetReg1(SiSP3c4,0x3D,data); + if (ModeNo>0x13) + { + SiSSetReg1(SiSP3c4,0x08,0x14); + data=SiSGetReg1(SiSP3c4,0x09); + data &= 0xF0; + SiSSetReg1(SiSP3c4,0x09,data); + + data=SiSGetReg1(SiSP3c4,0x3D); + data |= 0x01; + SiSSetReg1(SiSP3c4,0x3D,data); + } else { + SiSSetReg1(SiSP3c4,0x08,0xAE); + data=SiSGetReg1(SiSP3c4,0x09); + data &= 0xF0; + SiSSetReg1(SiSP3c4,0x09,data); + } +} + +USHORT SiSCalcDelay(ULONG ROMAddr,USHORT key) +{ + USHORT data,data2,temp0,temp1; + UCHAR ThLowA[]= {61,3,52,5,68,7,100,11, + 43,3,42,5,54,7, 78,11, + 34,3,37,5,47,7, 67,11}; + UCHAR ThLowB[]= {81,4,72,6,88,8,120,12, + 55,4,54,6,66,8, 90,12, + 42,4,45,6,55,8, 75,12}; + UCHAR ThTiming[]= {1,2,2,3,0,1,1,2}; + + data=SiSGetReg1(SiSP3c4,0x16); + data=data>>6; + data2=SiSGetReg1(SiSP3c4,0x14); + data2=(data2>>4)&0x0C; + data=data|data2; + data=data<1; + if (key==0) { + temp0=(USHORT)ThLowA[data]; + temp1=(USHORT)ThLowA[data+1]; + } else { + temp0=(USHORT)ThLowB[data]; + temp1=(USHORT)ThLowB[data+1]; + } + + data2=0; + data=SiSGetReg1(SiSP3c4,0x18); + if (data&0x02) data2=data2|0x01; + if (data&0x20) data2=data2|0x02; + if (data&0x40) data2=data2|0x04; + + data=temp1*ThTiming[data2]+temp0; + return(data); +} + +VOID SiSSetCRT1FIFO2(ULONG ROMAddr,PHW_DEVICE_EXTENSION HwDeviceExtension) +{ + USHORT index,data,VCLK,data2,MCLKOffset,MCLK,colorth=0; + USHORT ah,bl,B; + ULONG eax; + + index=*((UCHAR *)(ROMAddr+SiSREFIndex+0x03)); + SiSCRT1VCLKLen=SiSGetVCLKLen(ROMAddr,HwDeviceExtension); + data=index*SiSCRT1VCLKLen; + SiSVCLKData=*((USHORT *)(ROMAddr+0x208)); + SiSVCLKData=SiSVCLKData+data+(SiSCRT1VCLKLen-2); + VCLK=*((USHORT *)(ROMAddr+SiSVCLKData)); + + MCLKOffset=*((USHORT *)(ROMAddr+0x20C)); + index=SiSGetReg1(SiSP3c4,0x1A); + index=index&07; + MCLKOffset=MCLKOffset+index*5; + MCLK=*((USHORT *)(ROMAddr+MCLKOffset+0x03)); + + data2=SiSModeType-0x02; + switch (data2) { + case 0 : colorth=1; break; + case 1 : colorth=1; break; + case 2 : colorth=2; break; + case 3 : colorth=2; break; + case 4 : colorth=3; break; + case 5 : colorth=4; break; + } + + do{ + B=(SiSCalcDelay2(ROMAddr,0)*VCLK*colorth); + if (B%(16*MCLK) == 0) { + B=B/(16*MCLK); + bl=B+1; + } else { + B=B/(16*MCLK); + bl=B+2; + } + + if (bl>0x13) { + data=SiSGetReg1(SiSP3c4,0x15); + data=data&0xf0; + if (data!=0xb0) { + data=data+0x20; + if (data==0xa0) data=0x30; + + data2=SiSGetReg1(SiSP3c4,0x15); + data2=(data2&0x0f)|data; + SiSSetReg1(SiSP3c4,0x15,data2); + } else + bl=0x13; + } + } while(bl>0x13); + + data2=SiSGetReg1(SiSP3c4,0x15); + data2=(data2&0xf0)>>4; + data2=data2<<24; + + SiSSetReg4(0xcf8,0x80000050); + eax=SiSGetReg3(0xcfc); + eax=eax&0x0f0ffffff; + eax=eax|data2; + SiSSetReg4(0xcfc,eax); + + ah=bl; + ah=ah<<4; + ah=ah|0x0f; + SiSSetReg1(SiSP3c4,0x08,ah); + + data=bl; + data=data&0x10; + data=data<<1; + data2=SiSGetReg1(SiSP3c4,0x0F); + data2=data2&0x9f; + data2=data2|data; + SiSSetReg1(SiSP3c4,0x0F,data2); + + data=bl+3; + if (data>0x0f) data=0x0f; + SiSSetReg1(SiSP3c4,0x3b,0x00); + data2=SiSGetReg1(SiSP3c4,0x09); + data2=data2&0xF0; + data2=data2|data; + SiSSetReg1(SiSP3c4,0x09,data2); +} + +USHORT SiSCalcDelay2(ULONG ROMAddr,USHORT key) +{ + USHORT data,index; + UCHAR LatencyFactor[]={88,80,78,72,70,00, + 00,79,77,71,69,49, + 88,80,78,72,70,00, + 00,72,70,64,62,44}; + + index=0; + data=SiSGetReg1(SiSP3c4,0x14); + if (data&0x80) index=index+12; + + data=SiSGetReg1(SiSP3c4,0x15); + data=(data&0xf0)>>4; + if (data&0x01) index=index+6; + + data=data>>1; + index=index+data; + data=LatencyFactor[index]; + + return(data); +} + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/sis/init310.h linux.ac/drivers/video/sis/init310.h --- linux.vanilla/drivers/video/sis/init310.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/sis/init310.h Tue Apr 3 17:55:09 2001 @@ -0,0 +1,136 @@ +#include "sis.h" + +USHORT SIS_SDRDRAM_TYPE[11][5]= { + { 2,12, 9,64,0x35}, + { 1,13, 9,64,0x44}, + { 2,12, 8,32,0x31}, + { 1,13, 8,32,0x40}, + { 2,11, 8,16,0x21}, + { 1,12, 8,16,0x30}, + { 1,11, 9,16,0x24}, + { 1,11, 8, 8,0x20}, + { 2, 9, 8, 4,0x01}, + { 1,10, 8, 4,0x10}, + { 1, 9, 8, 2,0x00} +}; + +USHORT SIS_DDRDRAM_TYPE[4][5]= { + { 2,12, 9,64,0x35}, + { 2,12, 8,32,0x31}, + { 2,11, 8,16,0x21}, + { 2, 9, 8, 4,0x01} +}; + +UCHAR SiSChannelAB,SiSDataBusWidth; + + +USHORT SIS_MDA_DAC[]={ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F }; + +USHORT SIS_CGA_DAC[]={ + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F}; + +USHORT SIS_EGA_DAC[]={ + 0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15, + 0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35, + 0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D, + 0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D, + 0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17, + 0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37, + 0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F}; + +USHORT SIS_VGA_DAC[]={ + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, + 0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18, + 0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F, + 0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F, + 0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00, + 0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18, + 0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04, + 0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10, + 0x0B,0x0C,0x0D,0x0F,0x10}; + +USHORT SiSP3c4,SiSP3d4,SiSP3c0,SiSP3ce,SiSP3c2,SiSP3ca,SiSP3c6,SiSP3c7,SiSP3c8,SiSP3c9,SiSP3da; +USHORT SiSCRT1VCLKLen; +USHORT SiS_flag_clearbuffer; +int SiSRAMType; +int SiSModeIDOffset,SiSStandTable,SiSCRT1Table,SiSScreenOffset,SiSVCLKData,SiSMCLKData, SiSECLKData; +int SiSREFIndex,SiSModeType; +USHORT SIS_IF_DEF_LVDS,SIS_IF_DEF_TRUMPION; +USHORT SiSVBInfo,SiSLCDResInfo,SiSLCDTypeInfo,SiSLCDInfo; + +VOID SiSSetMemoryClock(ULONG); +VOID SiSSetDRAMModeRegister(ULONG ROMAddr); +VOID SiSSetDRAMSize(PHW_DEVICE_EXTENSION); +UCHAR SiSGet310DRAMType(ULONG ROMAddr); + +VOID SiSDelay15us(ULONG); +BOOLEAN SiSSearchModeID(ULONG, USHORT); +BOOLEAN SiSCheckMemorySize(ULONG); +VOID SiSGetModePtr(ULONG, USHORT); +BOOLEAN SiSGetRatePtr(ULONG, USHORT); +VOID SiSSetSeqRegs(ULONG); +VOID SiSSetMiscRegs(ULONG); +VOID SiSSetCRTCRegs(ULONG); +VOID SiSSetATTRegs(ULONG); +VOID SiSSetGRCRegs(ULONG); +VOID SiSClearExt1Regs(VOID); +VOID SiSSetSync(ULONG); +VOID SiSSetCRT1CRTC(ULONG); +VOID SiSSetCRT1Offset(ULONG); +VOID SiSSetCRT1FIFO(ULONG,USHORT,PHW_DEVICE_EXTENSION); +VOID SiSSetCRT1FIFO2(ULONG,PHW_DEVICE_EXTENSION); +VOID SiSSetCRT1VCLK(PHW_DEVICE_EXTENSION, ULONG); +VOID SiSLoadDAC(ULONG); +VOID SiSDisplayOn(VOID); +VOID SiSSetCRT1ModeRegs(ULONG, USHORT); +VOID SiSSetVCLKState(PHW_DEVICE_EXTENSION, ULONG, USHORT); +VOID SiSWriteDAC(USHORT, USHORT, USHORT, USHORT); +VOID sisfb_clear_buffer(PHW_DEVICE_EXTENSION); +USHORT SiSChkBUSWidth(ULONG); +USHORT SiSGetModeIDLength(ULONG, USHORT); +USHORT SiSGetRefindexLength(ULONG, USHORT); +VOID SiSSetInterlace(ULONG, USHORT); +USHORT SiSCalcDelay2(ULONG ,USHORT); +VOID SiSSet_LVDS_TRUMPION(VOID); + +extern BOOLEAN SiSBridgeIsOn(USHORT BaseAddr); +extern VOID SiSUnLockCRT2(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr); +extern VOID SiSLockCRT2(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr); + +extern BOOLEAN SiSSetCRT2Group301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension); +extern BOOLEAN SiSSetCRT2Group302(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension); +extern VOID SiSGetVBInfo301(USHORT BaseAddr,ULONG ROMAddr); +extern VOID SiSPresetScratchregister301(USHORT SiSP3d4,PHW_DEVICE_EXTENSION HwDeviceExtension); +extern BOOLEAN SiSGetLCDResInfo301(ULONG ROMAddr,USHORT SiSP3d4); +extern VOID SiSSetTVSystem301(PHW_DEVICE_EXTENSION HwDeviceExtension,ULONG ROMAddr); +extern BOOLEAN SiSGetLCDDDCInfo301(PHW_DEVICE_EXTENSION HwDeviceExtension); +extern BOOLEAN SiSGetSenseStatus301(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr); +extern BOOLEAN SiSDetectMonitor301(PHW_DEVICE_EXTENSION HwDeviceExtension); +extern USHORT SiSGetVCLKLen(ULONG ROMAddr,PHW_DEVICE_EXTENSION HwDeviceExtension); + +extern VOID sisfb_set_reg1(u16 port, u16 index, u16 data); +extern VOID sisfb_set_reg3(u16 port, u16 data); +extern VOID sisfb_set_reg4(u16 port, ULONG data); +extern u8 sisfb_get_reg1(u16 port, u16 index); +extern u8 sisfb_get_reg2(u16 port); +extern u32 sisfb_get_reg3(u16 port); +extern VOID sisfb_clear_DAC(u16 port); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/sis/sis.h linux.ac/drivers/video/sis/sis.h --- linux.vanilla/drivers/video/sis/sis.h Thu Nov 9 01:15:04 2000 +++ linux.ac/drivers/video/sis/sis.h Tue Apr 3 17:55:09 2001 @@ -1,13 +1,10 @@ #ifndef _SISFB_LOCAL #define _SISFB_LOCAL +#include <linux/config.h> #include <linux/types.h> +#include <linux/sisfb.h> #undef NOBIOS -#undef CONFIG_FB_SIS_LINUXBIOS - -#ifdef NOBIOS -#undef CONFIG_FB_SIS_LINUXBIOS -#endif #define TRUE 1 #define FALSE 0 @@ -20,45 +17,300 @@ #define SHORT short #define BOOLEAN int #define VOID void +#define PULONG unsigned long * +#define PUCHAR unsigned char * #define IND_SIS_CRT2_PORT_04 0x04 - 0x30 #define IND_SIS_CRT2_PORT_10 0x10 - 0x30 #define IND_SIS_CRT2_PORT_12 0x12 - 0x30 #define IND_SIS_CRT2_PORT_14 0x14 - 0x30 -#define ClearALLBuffer(x) ClearBuffer(x) +#define PRIMARY_VGA 1 -/* Data struct for setmode codes */ -typedef enum _CHIP_TYPE { - SIS_GENERIC = 0, - SIS_Glamour, //300 - SIS_Trojan, //630 - SIS_Spartan, //540 - SIS_730, - MAX_SIS_CHIP -} CHIP_TYPE; +#define ModeInfoFlag 0x07 +#define MemoryInfoFlag 0x1E0 +#define MemorySizeShift 0x05 +#define ModeText 0x00 +#define ModeCGA 0x01 +#define ModeEGA 0x02 +#define ModeVGA 0x03 +#define Mode15Bpp 0x04 +#define Mode16Bpp 0x05 +#define Mode24Bpp 0x06 +#define Mode32Bpp 0x07 +#define CRT1Len 17 +#define DoubleScanMode 0x8000 +#define ADR_CRT2PtrData 0x20E +#define offset_Zurac 0x210 +#define ADR_LVDSDesPtrData 0x212 +#define ADR_LVDSCRT1DataPtr 0x214 + +#define SoftDRAMType 0x80 +#define SoftSettingAddr 0x52 +#define ModeSettingAddr 0x53 + +#define InterlaceMode 0x80 +#define HalfDCLK 0x1000 +#define DACInfoFlag 0x18 +#define LineCompareOff 0x400 +#define ActivePAL 0x20 +#define ActivePALShift 5 + + +#define SelectCRT2Rate 0x4 +#define ProgrammingCRT2 0x1 +#define CRT2DisplayFlag 0x2000 +#define SetCRT2ToRAMDAC 0x0040 +#define Charx8Dot 0x0200 +#define LCDDataLen 8 +#define SetCRT2ToLCD 0x0020 +#define SetCRT2ToHiVisionTV 0x0080 +#define HiTVDataLen 12 +#define TVDataLen 16 +#define SetPALTV 0x0100 +#define SetInSlaveMode 0x0200 +#define SetCRT2ToTV 0x009C +#define SetNotSimuTVMode 0x0400 +#define SetSimuScanMode 0x0001 +#define DriverMode 0x4000 +#define CRT2Mode 0x0800 +#define HalfDCLK 0x1000 +#define NTSCHT 1716 +#define NTSCVT 525 +#define PALHT 1728 +#define PALVT 625 + +#define VCLKStartFreq 25 + +#define SoftDramType 0x80 +#define VCLK65 0x09 +#define VCLK108_2 0x14 +#define TVSimuMode 0x02 +#define SetCRT2ToSVIDEO 0x08 +#define LCDRGB18Bit 0x01 +#define Panel1280x1024 0x03 +#define Panel1024x768 0x02 +#define Panel800x600 0x01 +#define RPLLDIV2XO 0x04 +#define LoadDACFlag 0x1000 +#define AfterLockCRT2 0x4000 +#define SupportRAMDAC2 0x0040 +#define SupportLCD 0x0020 +#define SetCRT2ToAVIDEO 0x0004 +#define SetCRT2ToSCART 0x0010 +#define NoSupportSimuTV 0x2000 +#define Ext2StructSize 5 +#define SupportTV 0x0008 +#define SwitchToCRT2 0x0002 +#define LCDVESATiming 0x08 +#define SetSCARTOutput 0x01 +#define SCARTSense 0x04 +#define Monitor1Sense 0x20 +#define Monitor2Sense 0x10 +#define SVIDEOSense 0x02 +#define AVIDEOSense 0x01 +#define LCDSense 0x08 +#define BoardTVType 0x02 +#define HotPlugFunction 0x08 +#define StStructSize 0x06 + +#define ExtChip301 0x02 +#define ExtChipLVDS 0x04 +#define ExtChipTrumpion 0x06 +#define LCDNonExpanding 0x10 +#define LCDNonExpandingShift 4 +#define LVDSDataLen 6 +#define EnableLVDSDDA 0x10 +#define LCDSync 0x20 +#define SyncPP 0x0000 +#define LCDSyncBit 0xE0 +#define LVDSDesDataLen 3 +#define LVDSCRT1Len 15 +#define ActiveNonExpanding 0x40 +#define ActiveNonExpandingShift 6 +#define ModeSwitchStatus 0x0F +#define SoftTVType 0x40 + +#define PanelType00 0x00 +#define PanelType01 0x08 +#define PanelType02 0x10 +#define PanelType03 0x18 +#define PanelType04 0x20 +#define PanelType05 0x28 +#define PanelType06 0x30 +#define PanelType07 0x38 +#define PanelType08 0x40 +#define PanelType09 0x48 +#define PanelType0A 0x50 +#define PanelType0B 0x58 +#define PanelType0C 0x60 +#define PanelType0D 0x68 +#define PanelType0E 0x70 +#define PanelType0F 0x78 + +#define BIOSIDCodeAddr 0x235 +#define OEMUtilIDCodeAddr 0x237 +#define VBModeIDTableAddr 0x239 +#define OEMTVPtrAddr 0x241 +#define PhaseTableAddr 0x243 +#define NTSCFilterTableAddr 0x245 +#define PALFilterTableAddr 0x247 +#define OEMLCDPtr_1Addr 0x249 +#define OEMLCDPtr_2Addr 0x24B +#define LCDHPosTable_1Addr 0x24D +#define LCDHPosTable_2Addr 0x24F +#define LCDVPosTable_1Addr 0x251 +#define LCDVPosTable_2Addr 0x253 +#define OEMLCDPIDTableAddr 0x255 + +#define VBModeStructSize 5 +#define PhaseTableSize 4 +#define FilterTableSize 4 +#define LCDHPosTableSize 7 +#define LCDVPosTableSize 5 +#define OEMLVDSPIDTableSize 4 +#define LVDSHPosTableSize 4 +#define LVDSVPosTableSize 6 + +#define VB_ModeID 0 +#define VB_TVTableIndex 1 +#define VB_LCDTableIndex 2 +#define VB_LCDHIndex 3 +#define VB_LCDVIndex 4 + +#define OEMLCDEnable 0x0001 +#define OEMLCDDelayEnable 0x0002 +#define OEMLCDPOSEnable 0x0004 +#define OEMTVEnable 0x0100 +#define OEMTVDelayEnable 0x0200 +#define OEMTVFlickerEnable 0x0400 +#define OEMTVPhaseEnable 0x0800 +#define OEMTVFilterEnable 0x1000 + +#define OEMLCDPanelIDSupport 0x0080 + + +/* for 315 */ +#define SoftDRAMType 0x80 +#define SoftSetting_OFFSET 0x52 +#define SR07_OFFSET 0x7C +#define SR15_OFFSET 0x7D +#define SR16_OFFSET 0x81 +#define SR17_OFFSET 0x85 +#define SR19_OFFSET 0x8D +#define SR1F_OFFSET 0x99 +#define SR21_OFFSET 0x9A +#define SR22_OFFSET 0x9B +#define SR23_OFFSET 0x9C +#define SR24_OFFSET 0x9D +#define SR25_OFFSET 0x9E +#define SR31_OFFSET 0x9F +#define SR32_OFFSET 0xA0 +#define SR33_OFFSET 0xA1 + +#define CR40_OFFSET 0xA2 + +#define VB310Data_1_2_Offset 0xB6 +#define VB310Data_4_D_Offset 0xB7 +#define VB310Data_4_E_Offset 0xB8 +#define VB310Data_4_10_Offset 0xBB + +#define RGBSenseDataOffset 0xBD +#define YCSenseDataOffset 0xBF +#define VideoSenseDataOffset 0xC1 +#define OutputSelectOffset 0xF3 + +#define ECLK_MCLK_DISTANCE 0x14 +#define VBIOSTablePointerStart 0x100 +#define StandTablePtrOffset VBIOSTablePointerStart+0x02 +#define EModeIDTablePtrOffset VBIOSTablePointerStart+0x04 +#define CRT1TablePtrOffset VBIOSTablePointerStart+0x06 +#define ScreenOffsetPtrOffset VBIOSTablePointerStart+0x08 +#define VCLKDataPtrOffset VBIOSTablePointerStart+0x0A +#define MCLKDataPtrOffset VBIOSTablePointerStart+0x0E +#define CRT2PtrDataPtrOffset VBIOSTablePointerStart+0x10 +#define TVAntiFlickPtrOffset VBIOSTablePointerStart+0x12 +#define TVDelayPtr1Offset VBIOSTablePointerStart+0x14 +#define TVPhaseIncrPtr1Offset VBIOSTablePointerStart+0x16 +#define TVYFilterPtr1Offset VBIOSTablePointerStart+0x18 +#define LCDDelayPtr1Offset VBIOSTablePointerStart+0x20 +#define TVEdgePtr1Offset VBIOSTablePointerStart+0x24 +#define CRT2Delay1Offset VBIOSTablePointerStart+0x28 + +#ifdef CONFIG_FB_SIS_300 +#define TVVCLKDIV2 0x021 +#define TVVCLK 0x022 +#else +#ifdef CONFIG_FB_SIS_315 +#define TVVCLKDIV2 0x02C +#define TVVCLK 0x02D +#endif +#endif + +/* for 300 */ +#ifdef CONFIG_FB_SIS_300 +#define StHiTVHT 892 +#define StHiTVVT 1126 +#define StHiTextTVHT 1000 +#define StHiTextTVVT 1126 +#define ExtHiTVHT 2100 +#define ExtHiTVVT 1125 + +#define SupportHiVisionTV 0x0010 +#define SetNotSimuMode 0x0400 +#define SupportCHTV 0x0800 + +#define SetCHTVOverScan 0x8000 +#define Panel1280x960 0x04 +#define VCLK40 0x04 +#define HiTVVCLKDIV2 0x023 +#define HiTVVCLK 0x024 +#define HiTVSimuVCLK 0x025 +#define HiTVTextVCLK 0x026 +#define ADR_CHTVVCLKPtr 0x216 +#define DisableCRT2Display 0x2000 +#define TVOverScan 0x10 +#define CHTVRegDataLen 5 +#define ADR_CHTVRegDataPtr 0x218 +#define DDC2DelayTime 10 +#endif + +#define SiSSetReg1(port, index, data) \ + (sisfb_set_reg1(port, index, data)) +#define SiSSetReg3(port, data) \ + (sisfb_set_reg3(port, data)) +#define SiSSetReg4(port, data) \ + (sisfb_set_reg4(port, data)) +#define SiSGetReg1(port, index) \ + (sisfb_get_reg1(port, index)) +#define SiSGetReg2(port) \ + (sisfb_get_reg2(port)) +#define SiSGetReg3(port) \ + (sisfb_get_reg3(port)) + +#define SiSClearDAC(port) sisfb_clear_DAC(port) +#define SiSClearBuffer(phw_ext) sisfb_clear_buffer(phw_ext) +#define SiSClearALLBuffer(x) sisfb_clear_buffer(x) typedef enum _LCD_TYPE { - LCD1024 = 1, - LCD1280, - LCD2048, - LCD1920, - LCD1600, - LCD800, - LCD640 + LCD1024 = 1, + LCD1280, + LCD2048, + LCD1920, + LCD1600, + LCD800, + LCD640 } LCD_TYPE; - -typedef struct _HW_DEVICE_EXTENSION -{ +typedef struct _HW_DEVICE_EXTENSION { unsigned long VirtualRomBase; char *VirtualVideoMemoryAddress; unsigned short IOAddress; CHIP_TYPE jChipID; int bIntegratedMMEnabled; LCD_TYPE usLCDType; - u8 revision_id; - u8 uVBChipID; + u8 uRevisionID; + unsigned int hasVB; + unsigned char *pSavedRegisters; } HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION; - #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/sis/sis_300.c linux.ac/drivers/video/sis/sis_300.c --- linux.vanilla/drivers/video/sis/sis_300.c Mon Nov 13 04:40:42 2000 +++ linux.ac/drivers/video/sis/sis_300.c Tue Apr 3 17:55:09 2001 @@ -1,14 +1,12 @@ /* Recently Update by v1.09.50 */ -#include <linux/config.h> +#include <linux/kernel.h> #include "sis_300.h" +#include <linux/sisfb.h> #if defined(ALLOC_PRAGMA) #pragma alloc_text(PAGE,SiSSetMode) #pragma alloc_text(PAGE,SiSInit300) #endif - - -#ifdef NOBIOS BOOLEAN SiSInit300(PHW_DEVICE_EXTENSION HwDeviceExtension) { ULONG ROMAddr = (ULONG)HwDeviceExtension->VirtualRomBase; @@ -20,588 +18,160 @@ UCHAR SR14; ULONG Temp; - if(ROMAddr==0) return (FALSE); - if(FBAddr==0) return (FALSE); - if(BaseAddr==0) return (FALSE); - if(HwDeviceExtension->jChipID >= SIS_Trojan) - if(!HwDeviceExtension->bIntegratedMMEnabled) return (FALSE); - - P3c4=BaseAddr+0x14; - P3d4=BaseAddr+0x24; - P3c0=BaseAddr+0x10; - P3ce=BaseAddr+0x1e; - P3c2=BaseAddr+0x12; - P3ca=BaseAddr+0x1a; - P3c6=BaseAddr+0x16; - P3c7=BaseAddr+0x17; - P3c8=BaseAddr+0x18; - P3c9=BaseAddr+0x19; - P3da=BaseAddr+0x2A; - Set_LVDS_TRUMPION(); - - SetReg1(P3c4,0x05,0x86); // 1.Openkey - SR14 = (UCHAR)GetReg1(P3c4,0x14); - SR19 = (UCHAR)GetReg1(P3c4,0x19); - SR1A = (UCHAR)GetReg1(P3c4,0x1A); - for(i=0x06;i< 0x20;i++) SetReg1(P3c4,i,0); // 2.Reset Extended register - for(i=0x21;i<=0x27;i++) SetReg1(P3c4,i,0); // Reset Extended register - for(i=0x31;i<=0x3D;i++) SetReg1(P3c4,i,0); - for(i=0x30;i<=0x37;i++) SetReg1(P3d4,i,0); - - if(HwDeviceExtension->jChipID >= SIS_Trojan) - temp=(UCHAR)SR1A; // 3.Set Define Extended register - else - { + if (ROMAddr==0) return (FALSE); + if (FBAddr==0) return (FALSE); + if (BaseAddr==0) return (FALSE); + if (HwDeviceExtension->jChipID >= SIS_Trojan) + if (!HwDeviceExtension->bIntegratedMMEnabled) return (FALSE); + + SiSP3c4=BaseAddr+0x14; + SiSP3d4=BaseAddr+0x24; + SiSP3c0=BaseAddr+0x10; + SiSP3ce=BaseAddr+0x1e; + SiSP3c2=BaseAddr+0x12; + SiSP3ca=BaseAddr+0x1a; + SiSP3c6=BaseAddr+0x16; + SiSP3c7=BaseAddr+0x17; + SiSP3c8=BaseAddr+0x18; + SiSP3c9=BaseAddr+0x19; + SiSP3da=BaseAddr+0x2A; + SiSSet_LVDS_TRUMPION(); + + SiSSetReg1(SiSP3c4,0x05,0x86); /* 1.Openkey */ + SR14 = (UCHAR)SiSGetReg1(SiSP3c4,0x14); + SR19 = (UCHAR)SiSGetReg1(SiSP3c4,0x19); + SR1A = (UCHAR)SiSGetReg1(SiSP3c4,0x1A); + for(i=0x06;i< 0x20;i++) SiSSetReg1(SiSP3c4,i,0); /* 2.Reset Extended register */ + for(i=0x21;i<=0x27;i++) SiSSetReg1(SiSP3c4,i,0); /* Reset Extended register */ + for(i=0x31;i<=0x3D;i++) SiSSetReg1(SiSP3c4,i,0); + for(i=0x30;i<=0x37;i++) SiSSetReg1(SiSP3d4,i,0); + + if (HwDeviceExtension->jChipID >= SIS_Trojan) + temp=(UCHAR)SR1A; /* 3.Set Define Extended register */ + else { temp=*((UCHAR *)(ROMAddr+SoftSettingAddr)); - if((temp&SoftDRAMType)==0){ - temp=(UCHAR)GetReg1(P3c4,0x3A); // 3.Set Define Extended register + if ((temp&SoftDRAMType)==0) { + temp=(UCHAR)SiSGetReg1(SiSP3c4,0x3A); /* 3.Set Define Extended register */ } } - RAMType=temp&0x07; - SetMemoryClock(ROMAddr); - for(k=0; k<5; k++) - { - for(j=0; j<0xffff; j++) - { - ulTemp = (ULONG)GetReg1(P3c4, 0x05); + SiSRAMType=temp&0x07; + SiSSetMemoryClock(ROMAddr); + for(k=0; k<5; k++) { + for(j=0; j<0xffff; j++) { + ulTemp = (ULONG)SiSGetReg1(SiSP3c4, 0x05); } } - Temp = (ULONG)GetReg1(P3c4, 0x3C); + Temp = (ULONG)SiSGetReg1(SiSP3c4, 0x3C); Temp = Temp | 0x01; - SetReg1(P3c4, 0x3C, (USHORT)Temp); - for(k=0; k<5; k++) - { - for(j=0; j<0xffff; j++) - { - Temp = (ULONG)GetReg1(P3c4, 0x05); + SiSSetReg1(SiSP3c4, 0x3C, (USHORT)Temp); + for(k=0; k<5; k++) { + for(j=0; j<0xffff; j++) { + Temp = (ULONG)SiSGetReg1(SiSP3c4, 0x05); } } - Temp = (ULONG)GetReg1(P3c4, 0x3C); + Temp = (ULONG)SiSGetReg1(SiSP3c4, 0x3C); Temp = Temp & 0xFE; - SetReg1(P3c4, 0x3C, (USHORT)Temp); - for(k=0; k<5; k++) - { - for(j=0; j<0xffff; j++) - { - Temp = (ULONG)GetReg1(P3c4, 0x05); + SiSSetReg1(SiSP3c4, 0x3C, (USHORT)Temp); + for(k=0; k<5; k++) { + for(j=0; j<0xffff; j++) { + Temp = (ULONG)SiSGetReg1(SiSP3c4, 0x05); } } SR07=*((UCHAR *)(ROMAddr+0xA4)); - SetReg1(P3c4,0x07,SR07); - if (HwDeviceExtension->jChipID == SIS_Glamour ) - { - for(i=0x15;i<=0x1C;i++) - { - temp=*((UCHAR *)(ROMAddr+0xA5+((i-0x15)*8)+RAMType)); - SetReg1(P3c4,i,temp); + SiSSetReg1(SiSP3c4,0x07,SR07); + if (HwDeviceExtension->jChipID == SIS_Glamour ) { + for(i=0x15;i<=0x1C;i++) { + temp=*((UCHAR *)(ROMAddr+0xA5+((i-0x15)*8)+SiSRAMType)); + SiSSetReg1(SiSP3c4,i,temp); } } SR1F=*((UCHAR *)(ROMAddr+0xE5)); - SetReg1(P3c4,0x1F,SR1F); + SiSSetReg1(SiSP3c4,0x1F,SR1F); - AGP=1; // Get AGP - temp=(UCHAR)GetReg1(P3c4,0x3A); + AGP=1; /* Get AGP */ + temp=(UCHAR)SiSGetReg1(SiSP3c4,0x3A); temp=temp&0x30; - if(temp==0x30) AGP=0; // PCI + if (temp==0x30) AGP=0; /* PCI */ SR21=*((UCHAR *)(ROMAddr+0xE6)); - if(AGP==0) SR21=SR21&0xEF; // PCI - SetReg1(P3c4,0x21,SR21); + if (AGP==0) SR21=SR21&0xEF; /* PCI */ + SiSSetReg1(SiSP3c4,0x21,SR21); SR22=*((UCHAR *)(ROMAddr+0xE7)); - if(AGP==1) SR22=SR22&0x20; // AGP - SetReg1(P3c4,0x22,SR22); + if (AGP==1) SR22=SR22&0x20; /* AGP */ + SiSSetReg1(SiSP3c4,0x22,SR22); SR23=*((UCHAR *)(ROMAddr+0xE8)); - SetReg1(P3c4,0x23,SR23); + SiSSetReg1(SiSP3c4,0x23,SR23); SR24=*((UCHAR *)(ROMAddr+0xE9)); - SetReg1(P3c4,0x24,SR24); + SiSSetReg1(SiSP3c4,0x24,SR24); SR25=*((UCHAR *)(ROMAddr+0xEA)); - SetReg1(P3c4,0x25,SR25); + SiSSetReg1(SiSP3c4,0x25,SR25); SR32=*((UCHAR *)(ROMAddr+0xEB)); - SetReg1(P3c4,0x32,SR32); + SiSSetReg1(SiSP3c4,0x32,SR32); SR11=0x0F; - SetReg1(P3c4,0x11,SR11); + SiSSetReg1(SiSP3c4,0x11,SR11); - if(IF_DEF_LVDS==1){ //LVDS + if (SIS_IF_DEF_LVDS==1) { /* LVDS */ temp=ExtChipLVDS; - }else if(IF_DEF_TRUMPION==1){ //Trumpion + } else if (SIS_IF_DEF_TRUMPION==1) { /* Trumpion */ temp=ExtChipTrumpion; - }else{ //301 + } else{ /* 301 */ temp=ExtChip301; } - SetReg1(P3d4,0x37,temp); + SiSSetReg1(SiSP3d4,0x37,temp); - //For SiS 630/540 Chip - //Restore SR14, SR19 and SR1A - SetReg1(P3c4,0x14,SR14); - SetReg1(P3c4,0x19,SR19); - SetReg1(P3c4,0x1A,SR1A); - - SetReg3(P3c6,0xff); // Reset register - ClearDAC(P3c8); // Reset register - DetectMonitor(HwDeviceExtension); //sense CRT1 - GetSenseStatus(HwDeviceExtension,BaseAddr,ROMAddr);//sense CRT2 + /* For SiS 630/540 Chip */ + /* Restore SR14, SR19 and SR1A */ + SiSSetReg1(SiSP3c4,0x14,SR14); + SiSSetReg1(SiSP3c4,0x19,SR19); + SiSSetReg1(SiSP3c4,0x1A,SR1A); + + SiSSetReg3(SiSP3c6,0xff); /* Reset register */ + SiSClearDAC(SiSP3c8); /* Reset register */ + SiSDetectMonitor(HwDeviceExtension); /* sense CRT1 */ + SiSGetSenseStatus(HwDeviceExtension,BaseAddr,ROMAddr); /* sense CRT2 */ return(TRUE); } -VOID Set_LVDS_TRUMPION(VOID) +VOID SiSSet_LVDS_TRUMPION(VOID) { - IF_DEF_LVDS=0; - IF_DEF_TRUMPION=0; + SIS_IF_DEF_LVDS=0; + SIS_IF_DEF_TRUMPION=0; } -VOID SetMemoryClock(ULONG ROMAddr) +VOID SiSSetMemoryClock(ULONG ROMAddr) { UCHAR data,i; - MCLKData=*((USHORT *)(ROMAddr+0x20C)); // MCLKData Table - MCLKData=MCLKData+RAMType*5; - ECLKData=MCLKData+0x28; - - for(i=0x28;i<=0x2A;i++) { // Set MCLK - data=*((UCHAR *)(ROMAddr+MCLKData)); - SetReg1(P3c4,i,data); - MCLKData++; - } - - for(i=0x2E;i<=0x30;i++) { // Set ECLK - data=*((UCHAR *)(ROMAddr+ECLKData)); - SetReg1(P3c4,i,data); - ECLKData++; - } -} -#endif /* NOBIOS */ - -#ifdef CONFIG_FB_SIS_LINUXBIOS -BOOLEAN SiSInit300(PHW_DEVICE_EXTENSION HwDeviceExtension) -{ - ULONG ROMAddr = 0; - USHORT BaseAddr = (USHORT)HwDeviceExtension->IOAddress; - UCHAR i,temp,AGP; - ULONG j,k,ulTemp; - UCHAR SR07,SR11,SR19,SR1A,SR1F,SR21,SR22,SR23,SR24,SR25,SR32; - UCHAR SR14; - ULONG Temp; - - if(BaseAddr==0) return (FALSE); - if(HwDeviceExtension->jChipID >= SIS_Trojan) - if(!HwDeviceExtension->bIntegratedMMEnabled) return (FALSE); - - P3c4=BaseAddr+0x14; - P3d4=BaseAddr+0x24; - P3c0=BaseAddr+0x10; - P3ce=BaseAddr+0x1e; - P3c2=BaseAddr+0x12; - P3ca=BaseAddr+0x1a; - P3c6=BaseAddr+0x16; - P3c7=BaseAddr+0x17; - P3c8=BaseAddr+0x18; - P3c9=BaseAddr+0x19; - P3da=BaseAddr+0x2A; - - SetReg1(P3c4,0x05,0x86); // 1.Openkey - - SR14 = (UCHAR)GetReg1(P3c4,0x14); - SR19 = (UCHAR)GetReg1(P3c4,0x19); - SR1A = (UCHAR)GetReg1(P3c4,0x1A); - - for(i=0x06;i< 0x20;i++) SetReg1(P3c4,i,0); // 2.Reset Extended register - for(i=0x21;i<=0x27;i++) SetReg1(P3c4,i,0); // Reset Extended register - for(i=0x31;i<=0x3D;i++) SetReg1(P3c4,i,0); - for(i=0x30;i<=0x37;i++) SetReg1(P3d4,i,0); - - temp=(UCHAR)SR1A; // 3.Set Define Extended register - - RAMType=temp&0x07; - SetMemoryClock(ROMAddr); - for(k=0; k<5; k++) - for(j=0; j<0xffff; j++) - ulTemp = (ULONG)GetReg1(P3c4, 0x05); - - Temp = (ULONG)GetReg1(P3c4, 0x3C); - Temp = Temp | 0x01; - SetReg1(P3c4, 0x3C, (USHORT)Temp); - - for(k=0; k<5; k++) - for(j=0; j<0xffff; j++) - Temp = (ULONG)GetReg1(P3c4, 0x05); - - Temp = (ULONG)GetReg1(P3c4, 0x3C); - Temp = Temp & 0xFE; - SetReg1(P3c4, 0x3C, (USHORT)Temp); - - for(k=0; k<5; k++) - for(j=0; j<0xffff; j++) - Temp = (ULONG)GetReg1(P3c4, 0x05); + SiSMCLKData=*((USHORT *)(ROMAddr+0x20C)); /* SiSMCLKData Table */ + SiSMCLKData=SiSMCLKData+SiSRAMType*5; + SiSECLKData=SiSMCLKData+0x28; - SR07=SRegsInit[0x07]; - SetReg1(P3c4,0x07,SR07); - - SR1F=SRegsInit[0x1F]; - SetReg1(P3c4,0x1F,SR1F); - - AGP=1; // Get AGP - temp=(UCHAR)GetReg1(P3c4,0x3A); - temp=temp&0x30; - if(temp==0x30) AGP=0; // PCI - - SR21=SRegsInit[0x21]; - if(AGP==0) SR21=SR21&0xEF; // PCI - SetReg1(P3c4,0x21,SR21); - - SR22=SRegsInit[0x22]; - if(AGP==1) SR22=SR22&0x20; // AGP - SetReg1(P3c4,0x22,SR22); - - SR23=SRegsInit[0x23]; - SetReg1(P3c4,0x23,SR23); - - SR24=SRegsInit[0x24]; - SetReg1(P3c4,0x24,SR24); - - SR25=SRegsInit[0x25]; - SetReg1(P3c4,0x25,SR25); - - SR32=SRegsInit[0x32]; - SetReg1(P3c4,0x32,SR32); - - SR11=0x0F; - SetReg1(P3c4,0x11,SR11); - - temp=ExtChip301; - SetReg1(P3d4,0x37,temp); - - SetReg1(P3c4,0x14,SR14); - SetReg1(P3c4,0x19,SR19); - SetReg1(P3c4,0x1A,SR1A); - - SetReg3(P3c6,0xff); // Reset register - ClearDAC(P3c8); // Reset register - DetectMonitor(HwDeviceExtension); //sense CRT1 - - return(TRUE); -} - -VOID SetMemoryClock(ULONG ROMAddr) -{ - UCHAR i; - USHORT idx; - - u8 MCLK[] = { - 0x5A, 0x64, 0x80, 0x66, 0x00, // SDRAM - 0xB3, 0x45, 0x80, 0x83, 0x00, // SGRAM - 0x37, 0x61, 0x80, 0x00, 0x01, // ESDRAM - 0x37, 0x22, 0x80, 0x33, 0x01, - 0x37, 0x61, 0x80, 0x00, 0x01, - 0x37, 0x61, 0x80, 0x00, 0x01, - 0x37, 0x61, 0x80, 0x00, 0x01, - 0x37, 0x61, 0x80, 0x00, 0x01 - }; - - u8 ECLK[] = { - 0x54, 0x43, 0x80, 0x00, 0x01, - 0x53, 0x43, 0x80, 0x00, 0x01, - 0x55, 0x43, 0x80, 0x00, 0x01, - 0x52, 0x43, 0x80, 0x00, 0x01, - 0x3f, 0x42, 0x80, 0x00, 0x01, - 0x54, 0x43, 0x80, 0x00, 0x01, - 0x54, 0x43, 0x80, 0x00, 0x01, - 0x54, 0x43, 0x80, 0x00, 0x01 - }; - - idx = RAMType * 5; - - for (i = 0x28; i <= 0x2A; i++) { // Set MCLK - SetReg1(P3c4, i, MCLK[idx]); - idx++; + for(i=0x28;i<=0x2A;i++) { /* Set MCLK */ + data=*((UCHAR *)(ROMAddr+SiSMCLKData)); + SiSSetReg1(SiSP3c4,i,data); + SiSMCLKData++; } - idx = RAMType * 5; - for (i = 0x2E; i <= 0x30; i++) { // Set ECLK - SetReg1(P3c4, i, ECLK[idx]); - idx++; + for(i=0x2E;i<=0x30;i++) { /* Set ECLK */ + data=*((UCHAR *)(ROMAddr+SiSECLKData)); + SiSSetReg1(SiSP3c4,i,data); + SiSECLKData++; } - } -#endif /* CONFIG_FB_SIS_LINUXBIOS */ +/* ========================================= */ +/* ======== SiS SetMode Function ========== */ +/* ========================================= */ -// ========================================= -// ======== SiS SetMode Function ========== -// ========================================= - -#ifdef CONFIG_FB_SIS_LINUXBIOS -BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension, - USHORT ModeNo) -{ - ULONG i; - USHORT cr30flag,cr31flag; - ULONG ROMAddr = (ULONG)HwDeviceExtension->VirtualRomBase; - USHORT BaseAddr = (USHORT)HwDeviceExtension->IOAddress; - - P3c4=BaseAddr+0x14; - P3d4=BaseAddr+0x24; - P3c0=BaseAddr+0x10; - P3ce=BaseAddr+0x1e; - P3c2=BaseAddr+0x12; - P3ca=BaseAddr+0x1a; - P3c6=BaseAddr+0x16; - P3c7=BaseAddr+0x17; - P3c8=BaseAddr+0x18; - P3c9=BaseAddr+0x19; - P3da=BaseAddr+0x2A; - - cr30flag=(UCHAR)GetReg1(P3d4,0x30); - - if(((cr30flag&0x01)==1)||((cr30flag&0x02)==0)){ - SetReg1(P3d4,0x34,ModeNo); - //SetSeqRegs(ROMAddr); - { - UCHAR SRdata; - SRdata = SRegs[0x01] | 0x20; - SetReg1(P3c4, 0x01, SRdata); - - for (i = 02; i <= 04; i++) - SetReg1(P3c4, i, SRegs[i]); - } - - //SetMiscRegs(ROMAddr); - { - SetReg3(P3c2, 0x23); - } - - //SetCRTCRegs(ROMAddr); - { - UCHAR CRTCdata; - - CRTCdata = (UCHAR) GetReg1(P3d4, 0x11); - SetReg1(P3d4, 0x11, CRTCdata); - - for (i = 0; i <= 0x18; i++) - SetReg1(P3d4, i, CRegs[i]); - } - - //SetATTRegs(ROMAddr); - { - for (i = 0; i <= 0x13; i++) { - GetReg2(P3da); - SetReg3(P3c0, i); - SetReg3(P3c0, ARegs[i]); - } - GetReg2(P3da); - SetReg3(P3c0, 0x14); - SetReg3(P3c0, 0x00); - GetReg2(P3da); - SetReg3(P3c0, 0x20); - } - - //SetGRCRegs(ROMAddr); - { - for (i = 0; i <= 0x08; i++) - SetReg1(P3ce, i, GRegs[i]); - } - - //ClearExt1Regs(); - { - for (i = 0x0A; i <= 0x0E; i++) - SetReg1(P3c4, i, 0x00); - } - - - //SetSync(ROMAddr); - { - SetReg3(P3c2, MReg); - } - - //SetCRT1CRTC(ROMAddr); - { - UCHAR data; - - data = (UCHAR) GetReg1(P3d4, 0x11); - data = data & 0x7F; - SetReg1(P3d4, 0x11, data); - - for (i = 0; i <= 0x07; i++) - SetReg1(P3d4, i, CRegs[i]); - for (i = 0x10; i <= 0x12; i++) - SetReg1(P3d4, i, CRegs[i]); - for (i = 0x15; i <= 0x16; i++) - SetReg1(P3d4, i, CRegs[i]); - for (i = 0x0A; i <= 0x0C; i++) - SetReg1(P3c4, i, SRegs[i]); - - data = SRegs[0x0E] & 0xE0; - SetReg1(P3c4, 0x0E, data); - - SetReg1(P3d4, 0x09, CRegs[0x09]); - } - - //SetCRT1Offset(ROMAddr); - { - SetReg1(P3c4, 0x0E, SRegs[0x0E]); - SetReg1(P3c4, 0x10, SRegs[0x10]); - } - - //SetCRT1VCLK(HwDeviceExtension, ROMAddr); - { - SetReg1(P3c4, 0x31, 0); - - for (i = 0x2B; i <= 0x2C; i++) - SetReg1(P3c4, i, SRegs[i]); - SetReg1(P3c4, 0x2D, 0x80); - } - - //SetVCLKState(HwDeviceExtension, ROMAddr, ModeNo); - { - SetReg1(P3c4, 0x32, SRegs[0x32]); - SetReg1(P3c4, 0x07, SRegs[0x07]); - } - - //SetCRT1FIFO2(ROMAddr); - { - SetReg1(P3c4, 0x15, SRegs[0x15]); - - SetReg4(0xcf8, 0x80000050); - SetReg4(0xcfc, 0xc5041e04); - - SetReg1(P3c4, 0x08, SRegs[0x08]); - SetReg1(P3c4, 0x0F, SRegs[0x0F]); - SetReg1(P3c4, 0x3b, 0x00); - SetReg1(P3c4, 0x09, SRegs[0x09]); - } - - //SetCRT1ModeRegs(ROMAddr, ModeNo); - { - SetReg1(P3c4, 0x06, SRegs[0x06]); - SetReg1(P3c4, 0x01, SRegs[0x01]); - SetReg1(P3c4, 0x0F, SRegs[0x0F]); - SetReg1(P3c4, 0x21, SRegs[0x21]); - } - - if(HwDeviceExtension->jChipID >= SIS_Trojan) - { - //SetInterlace(ROMAddr,ModeNo); - SetReg1(P3d4, 0x19, CRegs[0x19]); - SetReg1(P3d4, 0x1A, CRegs[0x1A]); - } - - LoadDAC(ROMAddr); - - ClearBuffer(HwDeviceExtension); - } - - cr31flag=(UCHAR)GetReg1(P3d4,0x31); - DisplayOn(); // 16.DisplayOn - return(NO_ERROR); -} - -VOID LoadDAC(ULONG ROMAddr) -{ - USHORT data,data2; - USHORT time,i,j,k; - USHORT m,n,o; - USHORT si,di,bx,dl; - USHORT al,ah,dh; - USHORT *table=VGA_DAC; - - time=256; - table=VGA_DAC; - j=16; - - SetReg3(P3c6,0xFF); - SetReg3(P3c8,0x00); - - for(i=0;i<j;i++) { - data=table[i]; - for(k=0;k<3;k++) { - data2=0; - if(data&0x01) data2=0x2A; - if(data&0x02) data2=data2+0x15; - SetReg3(P3c9,data2); - data=data>>2; - } - } - - if(time==256) { - for(i=16;i<32;i++) { - data=table[i]; - for(k=0;k<3;k++) SetReg3(P3c9,data); - } - si=32; - for(m=0;m<9;m++) { - di=si; - bx=si+0x04; - dl=0; - for(n=0;n<3;n++) { - for(o=0;o<5;o++) { - dh=table[si]; - ah=table[di]; - al=table[bx]; - si++; - WriteDAC(dl,ah,al,dh); - } - si=si-2; - for(o=0;o<3;o++) { - dh=table[bx]; - ah=table[di]; - al=table[si]; - si--; - WriteDAC(dl,ah,al,dh); - } - dl++; - } - si=si+5; - } - } -} - -VOID WriteDAC(USHORT dl, USHORT ah, USHORT al, USHORT dh) -{ - USHORT temp; - USHORT bh,bl; - - bh=ah; - bl=al; - if(dl!=0) { - temp=bh; - bh=dh; - dh=temp; - if(dl==1) { - temp=bl; - bl=dh; - dh=temp; - } - else { - temp=bl; - bl=bh; - bh=temp; - } - } - SetReg3(P3c9,(USHORT)dh); - SetReg3(P3c9,(USHORT)bh); - SetReg3(P3c9,(USHORT)bl); -} - - -VOID DisplayOn() -{ - USHORT data; - - data=GetReg1(P3c4,0x01); - data=data&0xDF; - SetReg1(P3c4,0x01,data); -} - - -#else BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension, USHORT ModeNo) { @@ -609,374 +179,402 @@ USHORT cr30flag,cr31flag; ULONG ROMAddr = (ULONG)HwDeviceExtension->VirtualRomBase; USHORT BaseAddr = (USHORT)HwDeviceExtension->IOAddress; + USHORT uCR32; - P3c4=BaseAddr+0x14; - P3d4=BaseAddr+0x24; - P3c0=BaseAddr+0x10; - P3ce=BaseAddr+0x1e; - P3c2=BaseAddr+0x12; - P3ca=BaseAddr+0x1a; - P3c6=BaseAddr+0x16; - P3c7=BaseAddr+0x17; - P3c8=BaseAddr+0x18; - P3c9=BaseAddr+0x19; - P3da=BaseAddr+0x2A; - if(ModeNo&0x80){ + SiSP3c4=BaseAddr+0x14; + SiSP3d4=BaseAddr+0x24; + SiSP3c0=BaseAddr+0x10; + SiSP3ce=BaseAddr+0x1e; + SiSP3c2=BaseAddr+0x12; + SiSP3ca=BaseAddr+0x1a; + SiSP3c6=BaseAddr+0x16; + SiSP3c7=BaseAddr+0x17; + SiSP3c8=BaseAddr+0x18; + SiSP3c9=BaseAddr+0x19; + SiSP3da=BaseAddr+0x2A; + if (ModeNo&0x80) { ModeNo=ModeNo&0x7F; - flag_clearbuffer=0; - }else{ - flag_clearbuffer=1; - } - - PresetScratchregister(P3d4,HwDeviceExtension); //add for CRT2 - - SetReg1(P3c4,0x05,0x86); // 1.Openkey - temp=SearchModeID(ROMAddr,ModeNo); // 2.Get ModeID Table - if(temp==0) return(0); + SiS_flag_clearbuffer=0; + } else { + SiS_flag_clearbuffer=1; + } + + SIS_IF_DEF_LVDS = SIS_IF_DEF_TRUMPION = SIS_IF_DEF_CH7005 = SIS_IF_DEF_HiVision = 0; + + switch (HwDeviceExtension->hasVB) { + case HASVB_LVDS: + SIS_IF_DEF_LVDS = 1; + break; + case HASVB_LVDS_CHRONTEL: + uCR32 = (UCHAR) SiSGetReg1(SiSP3d4, 0x32); + if (uCR32 & 0x7) { + SIS_IF_DEF_LVDS = 1; + SIS_IF_DEF_CH7005 = 1; + } else if (uCR32 & 0x80) { + SIS_IF_DEF_LVDS = 1; + } + break; + case HASVB_TRUMPION: + SIS_IF_DEF_TRUMPION = 1; + break; + } + + SiSPresetScratchregister(SiSP3d4,HwDeviceExtension); /* add for CRT2 */ + + SiSDisplayOff(); + SiSSetReg1(SiSP3c4,0x05,0x86); /* 1.Openkey */ + temp=SiSSearchModeID(ROMAddr,ModeNo); /* 2.Get ModeID Table */ + if (temp==0) return(0); - SetTVSystem(HwDeviceExtension,ROMAddr); //add for CRT2 - GetLCDDDCInfo(HwDeviceExtension); //add for CRT2 - GetVBInfo(BaseAddr,ROMAddr); //add for CRT2 - GetLCDResInfo(ROMAddr,P3d4); //add for CRT2 - - temp=CheckMemorySize(ROMAddr); // 3.Check memory size - if(temp==0) return(0); - cr30flag=(UCHAR)GetReg1(P3d4,0x30); - if(((cr30flag&0x01)==1)||((cr30flag&0x02)==0)){ - // if cr30 d[0]=1 or d[1]=0 set crt1 - SetReg1(P3d4,0x34,ModeNo); - // set CR34->CRT1 ModeNofor CRT2 FIFO - GetModePtr(ROMAddr,ModeNo); // 4.GetModePtr - SetSeqRegs(ROMAddr); // 5.SetSeqRegs - SetMiscRegs(ROMAddr); // 6.SetMiscRegs - SetCRTCRegs(ROMAddr); // 7.SetCRTCRegs - SetATTRegs(ROMAddr); // 8.SetATTRegs - SetGRCRegs(ROMAddr); // 9.SetGRCRegs - ClearExt1Regs(); // 10.Clear Ext1Regs - temp=GetRatePtr(ROMAddr,ModeNo); // 11.GetRatePtr - if(temp) { - SetSync(ROMAddr); // 12.SetSync - SetCRT1CRTC(ROMAddr); // 13.SetCRT1CRTC - SetCRT1Offset(ROMAddr); // 14.SetCRT1Offset - SetCRT1VCLK(HwDeviceExtension, ROMAddr); // 15.SetCRT1VCLK - SetVCLKState(HwDeviceExtension, ROMAddr, ModeNo); - if(HwDeviceExtension->jChipID >= SIS_Trojan) - SetCRT1FIFO2(ROMAddr); + SiSSetTVSystem(HwDeviceExtension,ROMAddr); /* add for CRT2 */ + SiSGetLCDDDCInfo(HwDeviceExtension); /* add for CRT2 */ + SiSGetVBInfo(BaseAddr,ROMAddr); /* add for CRT2 */ + SiSGetLCDResInfo(ROMAddr,SiSP3d4); /* add for CRT2 */ + + temp=SiSCheckMemorySize(ROMAddr); /* 3.Check memory size */ + if (temp==0) return(0); + cr30flag=(UCHAR)SiSGetReg1(SiSP3d4,0x30); + if (((cr30flag&0x01)==1)||((cr30flag&0x02)==0)) { + /* if cr30 d[0]=1 or d[1]=0 set crt1 */ + SiSSetReg1(SiSP3d4,0x34,ModeNo); + /* set CR34->CRT1 ModeNofor CRT2 FIFO */ + SiSGetModePtr(ROMAddr,ModeNo); /* 4.SiSGetModePtr */ + SiSSetSeqRegs(ROMAddr); /* 5.SiSSetSeqRegs */ + SiSSetMiscRegs(ROMAddr); /* 6.SiSSetMiscRegs */ + SiSSetCRTCRegs(ROMAddr); /* 7.SiSSetCRTCRegs */ + SiSSetATTRegs(ROMAddr); /* 8.SiSSetATTRegs */ + SiSSetGRCRegs(ROMAddr); /* 9.SiSSetGRCRegs */ + SiSClearExt1Regs(); /* 10.Clear Ext1Regs */ + temp=SiSGetRatePtr(ROMAddr,ModeNo); /* 11.SiSGetRatePtr */ + if (temp) { + SiSSetSync(ROMAddr); /* 12.SiSSetSync */ + SiSSetCRT1CRTC(ROMAddr); /* 13.SiSSetCRT1CRTC */ + SiSSetCRT1Offset(ROMAddr); /* 14.SiSSetCRT1Offset */ + SiSSetCRT1VCLK(HwDeviceExtension, ROMAddr); /* 15.SiSSetCRT1VCLK */ + SiSSetVCLKState(HwDeviceExtension, ROMAddr, ModeNo); + if (HwDeviceExtension->jChipID >= SIS_Trojan) + SiSSetCRT1FIFO2(ROMAddr); else - SetCRT1FIFO(ROMAddr); + SiSSetCRT1FIFO(ROMAddr); } - SetCRT1ModeRegs(ROMAddr, ModeNo); - if(HwDeviceExtension->jChipID >= SIS_Trojan) - SetInterlace(ROMAddr,ModeNo); - LoadDAC(ROMAddr); - if(flag_clearbuffer) ClearBuffer(HwDeviceExtension); - } - - cr31flag=(UCHAR)GetReg1(P3d4,0x31); - if(((cr30flag&0x01)==1)||((cr30flag&0x03)==0x02) - ||(((cr30flag&0x03)==0x00)&&((cr31flag&0x20)==0x20))){ - //if CR30 d[0]=1 or d[1:0]=10, set CRT2 or cr30 cr31== 0x00 0x20 - SetCRT2Group(BaseAddr,ROMAddr,ModeNo, HwDeviceExtension); //CRT2 + SiSSetCRT1ModeRegs(ROMAddr, ModeNo); + if (HwDeviceExtension->jChipID >= SIS_Trojan) + SiSSetInterlace(ROMAddr,ModeNo); + SiSLoadDAC(ROMAddr); + if (SiS_flag_clearbuffer) SiSClearBuffer(HwDeviceExtension); + } + + cr31flag=(UCHAR)SiSGetReg1(SiSP3d4,0x31); + if (((cr30flag&0x01)==1)||((cr30flag&0x03)==0x02) + ||(((cr30flag&0x03)==0x00)&&((cr31flag&0x20)==0x20))) { + /* if CR30 d[0]=1 or d[1:0]=10, set CRT2 or cr30 cr31== 0x00 0x20 */ + SiSSetCRT2Group(BaseAddr,ROMAddr,ModeNo, HwDeviceExtension); /* CRT2 */ } - DisplayOn(); // 16.DisplayOn + SiSDisplayOn(); /* 16.SiSDisplayOn */ return(NO_ERROR); } -BOOLEAN SearchModeID(ULONG ROMAddr, USHORT ModeNo) +BOOLEAN SiSSearchModeID(ULONG ROMAddr, USHORT ModeNo) { UCHAR ModeID; USHORT usIDLength; - ModeIDOffset=*((USHORT *)(ROMAddr+0x20A)); // Get EModeIDTable - ModeID=*((UCHAR *)(ROMAddr+ModeIDOffset)); // Offset 0x20A - usIDLength = GetModeIDLength(ROMAddr, ModeNo); + SiSModeIDOffset=*((USHORT *)(ROMAddr+0x20A)); /* Get EModeIDTable */ + ModeID=*((UCHAR *)(ROMAddr+SiSModeIDOffset)); /* Offset 0x20A */ + usIDLength = SiSGetModeIDLength(ROMAddr, ModeNo); while(ModeID!=0xff && ModeID!=ModeNo) { - ModeIDOffset=ModeIDOffset+usIDLength; - ModeID=*((UCHAR *)(ROMAddr+ModeIDOffset)); + SiSModeIDOffset=SiSModeIDOffset+usIDLength; + ModeID=*((UCHAR *)(ROMAddr+SiSModeIDOffset)); } - if(ModeID==0xff) return(FALSE); + if (ModeID==0xff) return(FALSE); else return(TRUE); } -BOOLEAN CheckMemorySize(ULONG ROMAddr) +BOOLEAN SiSCheckMemorySize(ULONG ROMAddr) { USHORT memorysize; USHORT modeflag; USHORT temp; - modeflag=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - ModeType=modeflag&ModeInfoFlag; // Get mode type + modeflag=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); /* si+St_ModeFlag */ + SiSModeType=modeflag&ModeInfoFlag; /* Get mode type */ memorysize=modeflag&MemoryInfoFlag; memorysize=memorysize>MemorySizeShift; - memorysize++; // Get memory size + memorysize++; /* Get memory size */ - temp=GetReg1(P3c4,0x14); // Get DRAM Size + temp=SiSGetReg1(SiSP3c4,0x14); /* Get DRAM Size */ temp=temp&0x3F; temp++; - if(temp<memorysize) return(FALSE); + if (temp<memorysize) return(FALSE); else return(TRUE); } -VOID GetModePtr(ULONG ROMAddr, USHORT ModeNo) +VOID SiSGetModePtr(ULONG ROMAddr, USHORT ModeNo) { UCHAR index; - StandTable=*((USHORT *)(ROMAddr+0x202)); // Get First 0x202 - // StandTable Offset - if(ModeNo<=13) { - index=*((UCHAR *)(ROMAddr+ModeIDOffset+0x03)); // si+St_ModeFlag + SiSStandTable=*((USHORT *)(ROMAddr+0x202)); /* Get First 0x202 */ + /* SiSStandTable Offset */ + if (ModeNo<=13) { + index=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x03)); /* si+St_ModeFlag */ } else { - if(ModeType <= 0x02) index=0x1B; // 02 -> ModeEGA + if (SiSModeType <= 0x02) index=0x1B; /* 02 -> ModeEGA */ else index=0x0F; } - StandTable=StandTable+64*index; // Get ModeNo StandTable + SiSStandTable=SiSStandTable+64*index; /* Get ModeNo SiSStandTable */ } -VOID SetSeqRegs(ULONG ROMAddr) +VOID SiSSetSeqRegs(ULONG ROMAddr) { UCHAR SRdata; USHORT i; - SetReg1(P3c4,0x00,0x03); // Set SR0 - StandTable=StandTable+0x05; - SRdata=*((UCHAR *)(ROMAddr+StandTable)); // Get SR01 from file - if(IF_DEF_LVDS==1){ - if(VBInfo&SetCRT2ToLCD){ - if(VBInfo&SetInSlaveMode){ - if(LCDInfo&LCDNonExpanding){ + SiSSetReg1(SiSP3c4,0x00,0x03); /* Set SR0 */ + SiSStandTable=SiSStandTable+0x05; + SRdata=*((UCHAR *)(ROMAddr+SiSStandTable)); /* Get SR01 from file */ + if (SIS_IF_DEF_LVDS==1) { + if (SIS_IF_DEF_CH7005==1) { + if (SiSVBInfo&SetCRT2ToTV) { + if (SiSVBInfo&SetInSlaveMode) { + SRdata=SRdata|0x01; + } + } + } + if (SiSVBInfo&SetCRT2ToLCD) { + if (SiSVBInfo&SetInSlaveMode) { + if (SiSLCDInfo&LCDNonExpanding) { SRdata=SRdata|0x01; } } } } - SRdata=SRdata|0x20; - SetReg1(P3c4,0x01,SRdata); // Set SR1 + SiSSetReg1(SiSP3c4,0x01,SRdata); /* Set SR1 */ for(i=02;i<=04;i++) { - StandTable++; - SRdata=*((UCHAR *)(ROMAddr+StandTable)); // Get SR2,3,4 from file - SetReg1(P3c4,i,SRdata); // Set SR2 3 4 + SiSStandTable++; + SRdata=*((UCHAR *)(ROMAddr+SiSStandTable)); /* Get SR2,3,4 from file */ + SiSSetReg1(SiSP3c4,i,SRdata); /* Set SR2 3 4 */ } } -VOID SetMiscRegs(ULONG ROMAddr) +VOID SiSSetMiscRegs(ULONG ROMAddr) { UCHAR Miscdata; - StandTable++; - Miscdata=*((UCHAR *)(ROMAddr+StandTable)); // Get Misc from file - SetReg3(P3c2,Miscdata); // Set Misc(3c2) + SiSStandTable++; + Miscdata=*((UCHAR *)(ROMAddr+SiSStandTable)); /* Get Misc from file */ + SiSSetReg3(SiSP3c2,Miscdata); /* Set Misc(3c2) */ } -VOID SetCRTCRegs(ULONG ROMAddr) +VOID SiSSetCRTCRegs(ULONG ROMAddr) { UCHAR CRTCdata; USHORT i; - CRTCdata=(UCHAR)GetReg1(P3d4,0x11); + CRTCdata=(UCHAR)SiSGetReg1(SiSP3d4,0x11); CRTCdata=CRTCdata&0x7f; - SetReg1(P3d4,0x11,CRTCdata); // Unlock CRTC + SiSSetReg1(SiSP3d4,0x11,CRTCdata); /* Unlock CRTC */ for(i=0;i<=0x18;i++) { - StandTable++; - CRTCdata=*((UCHAR *)(ROMAddr+StandTable)); // Get CRTC from file - SetReg1(P3d4,i,CRTCdata); // Set CRTC(3d4) + SiSStandTable++; + CRTCdata=*((UCHAR *)(ROMAddr+SiSStandTable)); /* Get CRTC from file */ + SiSSetReg1(SiSP3d4,i,CRTCdata); /* Set CRTC(3d4) */ } } -VOID SetATTRegs(ULONG ROMAddr) +VOID SiSSetATTRegs(ULONG ROMAddr) { UCHAR ARdata; USHORT i; for(i=0;i<=0x13;i++) { - StandTable++; - ARdata=*((UCHAR *)(ROMAddr+StandTable)); // Get AR for file - if(IF_DEF_LVDS==1){ //for LVDS - if(VBInfo&SetCRT2ToLCD){ - if(VBInfo&SetInSlaveMode){ - if(LCDInfo&LCDNonExpanding){ - if(i==0x13){ - ARdata=0; - } + SiSStandTable++; + ARdata=*((UCHAR *)(ROMAddr+SiSStandTable)); /* Get AR for file */ + if (SIS_IF_DEF_LVDS==1) { /* for LVDS */ + if (SIS_IF_DEF_CH7005==1) { + if (SiSVBInfo&SetCRT2ToTV) { + if (SiSVBInfo&SetInSlaveMode) { + if (i==0x13) ARdata=0; } } } - } - GetReg2(P3da); // reset 3da - SetReg3(P3c0,i); // set index - SetReg3(P3c0,ARdata); // set data - } - if(IF_DEF_LVDS==1){ //for LVDS - if(VBInfo&SetCRT2ToLCD){ - if(VBInfo&SetInSlaveMode){ - if(LCDInfo&LCDNonExpanding){ - + if (SiSVBInfo&SetCRT2ToLCD) { + if (SiSVBInfo&SetInSlaveMode) { + if (i==0x13) ARdata=0; } - } + } } + SiSGetReg2(SiSP3da); /* reset 3da */ + SiSSetReg3(SiSP3c0,i); /* set index */ + SiSSetReg3(SiSP3c0,ARdata); /* set data */ } - GetReg2(P3da); // reset 3da - SetReg3(P3c0,0x14); // set index - SetReg3(P3c0,0x00); // set data + SiSGetReg2(SiSP3da); /* reset 3da */ + SiSSetReg3(SiSP3c0,0x14); /* set index */ + SiSSetReg3(SiSP3c0,0x00); /* set data */ - GetReg2(P3da); // Enable Attribute - SetReg3(P3c0,0x20); + SiSGetReg2(SiSP3da); /* Enable Attribute */ + SiSSetReg3(SiSP3c0,0x20); } -VOID SetGRCRegs(ULONG ROMAddr) +VOID SiSSetGRCRegs(ULONG ROMAddr) { UCHAR GRdata; USHORT i; for(i=0;i<=0x08;i++) { - StandTable++; - GRdata=*((UCHAR *)(ROMAddr+StandTable)); // Get GR from file - SetReg1(P3ce,i,GRdata); // Set GR(3ce) + SiSStandTable++; + GRdata=*((UCHAR *)(ROMAddr+SiSStandTable)); /* Get GR from file */ + SiSSetReg1(SiSP3ce,i,GRdata); /* Set GR(3ce) */ } - if(ModeType>ModeVGA){ - GRdata=(UCHAR)GetReg1(P3ce,0x05); + if (SiSModeType>ModeVGA) { + GRdata=(UCHAR)SiSGetReg1(SiSP3ce,0x05); GRdata=GRdata&0xBF; - SetReg1(P3ce,0x05,GRdata); + SiSSetReg1(SiSP3ce,0x05,GRdata); } } -VOID ClearExt1Regs() +VOID SiSClearExt1Regs() { USHORT i; - for(i=0x0A;i<=0x0E;i++) SetReg1(P3c4,i,0x00); // Clear SR0A-SR0E + for(i=0x0A;i<=0x0E;i++) SiSSetReg1(SiSP3c4,i,0x00); /* Clear SR0A-SR0E */ } -BOOLEAN GetRatePtr(ULONG ROMAddr, USHORT ModeNo) +BOOLEAN SiSGetRatePtr(ULONG ROMAddr, USHORT ModeNo) { SHORT index; USHORT temp; USHORT ulRefIndexLength; - if(ModeNo<0x14) return(FALSE); // Mode No <= 13h then return + if (ModeNo<0x14) return(FALSE); /* Mode No <= 13h then return */ - index=GetReg1(P3d4,0x33); // Get 3d4 CRTC33 - index=index&0x0F; // Frame rate index - if(index!=0) index--; - REFIndex=*((USHORT *)(ROMAddr+ModeIDOffset+0x04)); // si+Ext_point + index=SiSGetReg1(SiSP3d4,0x33); /* Get 3d4 CRTC33 */ + index=index&0x0F; /* Frame rate index */ + if (index!=0) index--; + SiSREFIndex=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x04)); /* si+Ext_point */ - ulRefIndexLength = GetRefindexLength(ROMAddr, ModeNo); + ulRefIndexLength = SiSGetRefindexLength(ROMAddr, ModeNo); do { - temp=*((USHORT *)(ROMAddr+REFIndex)); // di => REFIndex - if(temp==0xFFFF) break; + temp=*((USHORT *)(ROMAddr+SiSREFIndex)); /* di => SiSREFIndex */ + if (temp==0xFFFF) break; temp=temp&ModeInfoFlag; - if(temp<ModeType) break; + if (temp<SiSModeType) break; - REFIndex=REFIndex+ulRefIndexLength; // rate size + SiSREFIndex=SiSREFIndex+ulRefIndexLength; /* rate size */ index--; } while(index>=0); - REFIndex=REFIndex-ulRefIndexLength; // rate size + SiSREFIndex=SiSREFIndex-ulRefIndexLength; /* rate size */ return(TRUE); } -VOID SetSync(ULONG ROMAddr) +VOID SiSSetSync(ULONG ROMAddr) { USHORT sync; USHORT temp; - sync=*((USHORT *)(ROMAddr+REFIndex)); // di+0x00 + sync=*((USHORT *)(ROMAddr+SiSREFIndex)); /* di+0x00 */ sync=sync&0xC0; temp=0x2F; temp=temp|sync; - SetReg3(P3c2,temp); // Set Misc(3c2) + SiSSetReg3(SiSP3c2,temp); /* Set Misc(3c2) */ } -VOID SetCRT1CRTC(ULONG ROMAddr) +VOID SiSSetCRT1CRTC(ULONG ROMAddr) { UCHAR index; UCHAR data; USHORT i; - index=*((UCHAR *)(ROMAddr+REFIndex+0x02)); // Get index + index=*((UCHAR *)(ROMAddr+SiSREFIndex+0x02)); /* Get index */ index=index&0x03F; - CRT1Table=*((USHORT *)(ROMAddr+0x204)); // Get CRT1Table - CRT1Table=CRT1Table+index*CRT1Len; + SiSCRT1Table=*((USHORT *)(ROMAddr+0x204)); /* Get SiSCRT1Table */ + SiSCRT1Table=SiSCRT1Table+index*CRT1Len; - data=(UCHAR)GetReg1(P3d4,0x11); + data=(UCHAR)SiSGetReg1(SiSP3d4,0x11); data=data&0x7F; - SetReg1(P3d4,0x11,data); // Unlock CRTC + SiSSetReg1(SiSP3d4,0x11,data); /* Unlock CRTC */ - CRT1Table--; + SiSCRT1Table--; for(i=0;i<=0x05;i++) { - CRT1Table++; - data=*((UCHAR *)(ROMAddr+CRT1Table)); - SetReg1(P3d4,i,data); + SiSCRT1Table++; + data=*((UCHAR *)(ROMAddr+SiSCRT1Table)); + SiSSetReg1(SiSP3d4,i,data); } for(i=0x06;i<=0x07;i++) { - CRT1Table++; - data=*((UCHAR *)(ROMAddr+CRT1Table)); - SetReg1(P3d4,i,data); + SiSCRT1Table++; + data=*((UCHAR *)(ROMAddr+SiSCRT1Table)); + SiSSetReg1(SiSP3d4,i,data); } for(i=0x10;i<=0x12;i++) { - CRT1Table++; - data=*((UCHAR *)(ROMAddr+CRT1Table)); - SetReg1(P3d4,i,data); + SiSCRT1Table++; + data=*((UCHAR *)(ROMAddr+SiSCRT1Table)); + SiSSetReg1(SiSP3d4,i,data); } for(i=0x15;i<=0x16;i++) { - CRT1Table++; - data=*((UCHAR *)(ROMAddr+CRT1Table)); - SetReg1(P3d4,i,data); + SiSCRT1Table++; + data=*((UCHAR *)(ROMAddr+SiSCRT1Table)); + SiSSetReg1(SiSP3d4,i,data); } for(i=0x0A;i<=0x0C;i++) { - CRT1Table++; - data=*((UCHAR *)(ROMAddr+CRT1Table)); - SetReg1(P3c4,i,data); + SiSCRT1Table++; + data=*((UCHAR *)(ROMAddr+SiSCRT1Table)); + SiSSetReg1(SiSP3c4,i,data); } - CRT1Table++; - data=*((UCHAR *)(ROMAddr+CRT1Table)); + SiSCRT1Table++; + data=*((UCHAR *)(ROMAddr+SiSCRT1Table)); data=data&0xE0; - SetReg1(P3c4,0x0E,data); + SiSSetReg1(SiSP3c4,0x0E,data); - data=(UCHAR)GetReg1(P3d4,0x09); + data=(UCHAR)SiSGetReg1(SiSP3d4,0x09); data=data&0xDF; - i=*((UCHAR *)(ROMAddr+CRT1Table)); + i=*((UCHAR *)(ROMAddr+SiSCRT1Table)); i=i&0x01; i=i<<5; data=data|i; - i=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); + i=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); i=i&DoubleScanMode; - if(i) data=data|0x80; - SetReg1(P3d4,0x09,data); + if (i) data=data|0x80; + SiSSetReg1(SiSP3d4,0x09,data); - if(ModeType>0x03) SetReg1(P3d4,0x14,0x4F); + if (SiSModeType>0x03) SiSSetReg1(SiSP3d4,0x14,0x4F); } -VOID SetCRT1Offset(ULONG ROMAddr) +VOID SiSSetCRT1Offset(ULONG ROMAddr) { USHORT temp,ah,al; USHORT temp2,i; USHORT DisplayUnit; - temp=*((UCHAR *)(ROMAddr+ModeIDOffset+0x03)); // si+Ext_ModeInfo - temp=temp>>4; // index - ScreenOffset=*((USHORT *)(ROMAddr+0x206)); // ScreenOffset - temp=*((UCHAR *)(ROMAddr+ScreenOffset+temp)); // data + temp=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x03)); /* si+Ext_ModeInfo */ + temp=temp>>4; /* index */ + SiSScreenOffset=*((USHORT *)(ROMAddr+0x206)); /* SiSScreenOffset */ + temp=*((UCHAR *)(ROMAddr+SiSScreenOffset+temp)); /* data */ - temp2=*((USHORT *)(ROMAddr+REFIndex+0x00)); + temp2=*((USHORT *)(ROMAddr+SiSREFIndex+0x00)); temp2=temp2&InterlaceMode; - if(temp2) temp=temp<<1; - temp2=ModeType-ModeEGA; + if (temp2) temp=temp<<1; + temp2=SiSModeType-ModeEGA; switch (temp2) { - case 0 : temp2=1; break; - case 1 : temp2=2; break; - case 2 : temp2=4; break; - case 3 : temp2=4; break; - case 4 : temp2=6; break; - case 5 : temp2=8; break; + case 0 : + temp2=1; break; + case 1 : + temp2=2; break; + case 2 : + temp2=4; break; + case 3 : + temp2=4; break; + case 4 : + temp2=6; break; + case 5 : + temp2=8; break; } temp=temp*temp2; DisplayUnit=temp; @@ -984,168 +582,168 @@ temp2=temp; temp=temp>>8; temp=temp&0x0F; - i=GetReg1(P3c4,0x0E); + i=SiSGetReg1(SiSP3c4,0x0E); i=i&0xF0; i=i|temp; - SetReg1(P3c4,0x0E,i); + SiSSetReg1(SiSP3c4,0x0E,i); temp=(UCHAR)temp2; temp=temp&0xFF; - SetReg1(P3d4,0x13,temp); + SiSSetReg1(SiSP3d4,0x13,temp); - temp2=*((USHORT *)(ROMAddr+REFIndex+0x00)); + temp2=*((USHORT *)(ROMAddr+SiSREFIndex+0x00)); temp2=temp2&InterlaceMode; - if(temp2) DisplayUnit>>=1; + if (temp2) DisplayUnit>>=1; DisplayUnit=DisplayUnit<<5; ah=(DisplayUnit&0xff00)>>8; al=DisplayUnit&0x00ff; - if(al==0) ah=ah+1; + if (al==0) ah=ah+1; else ah=ah+2; - SetReg1(P3c4,0x10,ah); + SiSSetReg1(SiSP3c4,0x10,ah); } -VOID SetCRT1VCLK(PHW_DEVICE_EXTENSION HwDeviceExtension, ULONG ROMAddr) +VOID SiSSetCRT1VCLK(PHW_DEVICE_EXTENSION HwDeviceExtension, ULONG ROMAddr) { USHORT i; UCHAR index,data; - index=*((UCHAR *)(ROMAddr+REFIndex+0x03)); + index=*((UCHAR *)(ROMAddr+SiSREFIndex+0x03)); index=index&0x03F; - CRT1VCLKLen=GetVCLKLen(ROMAddr); - data=index*CRT1VCLKLen; - VCLKData=*((USHORT *)(ROMAddr+0x208)); - VCLKData=VCLKData+data; + SiSCRT1VCLKLen=SiSGetVCLKLen(ROMAddr); + data=index*SiSCRT1VCLKLen; + SiSVCLKData=*((USHORT *)(ROMAddr+0x208)); + SiSVCLKData=SiSVCLKData+data; - SetReg1(P3c4,0x31,0); + SiSSetReg1(SiSP3c4,0x31,0); for(i=0x2B;i<=0x2C;i++) { - data=*((UCHAR *)(ROMAddr+VCLKData)); - SetReg1(P3c4,i,data); - VCLKData++; + data=*((UCHAR *)(ROMAddr+SiSVCLKData)); + SiSSetReg1(SiSP3c4,i,data); + SiSVCLKData++; } - SetReg1(P3c4,0x2D,0x80); + SiSSetReg1(SiSP3c4,0x2D,0x80); } -VOID SetCRT1ModeRegs(ULONG ROMAddr, USHORT ModeNo) +VOID SiSSetCRT1ModeRegs(ULONG ROMAddr, USHORT ModeNo) { USHORT data,data2,data3; - if(ModeNo>0x13) data=*((USHORT *)(ROMAddr+REFIndex+0x00)); + if (ModeNo>0x13) data=*((USHORT *)(ROMAddr+SiSREFIndex+0x00)); else data=0; data2=0; - if(ModeNo>0x13) - if(ModeType>0x02) { + if (ModeNo>0x13) + if (SiSModeType>0x02) { data2=data2|0x02; - data3=ModeType-ModeVGA; + data3=SiSModeType-ModeVGA; data3=data3<<2; data2=data2|data3; } data=data&InterlaceMode; - if(data) data2=data2|0x20; - SetReg1(P3c4,0x06,data2); + if (data) data2=data2|0x20; + SiSSetReg1(SiSP3c4,0x06,data2); - data=GetReg1(P3c4,0x01); + data=SiSGetReg1(SiSP3c4,0x01); data=data&0xF7; - data2=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); + data2=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); data2=data2&HalfDCLK; - if(data2) data=data|0x08; - SetReg1(P3c4,0x01,data); + if (data2) data=data|0x08; + SiSSetReg1(SiSP3c4,0x01,data); - data=GetReg1(P3c4,0x0F); + data=SiSGetReg1(SiSP3c4,0x0F); data=data&0xF7; - data2=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); + data2=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); data2=data2&LineCompareOff; - if(data2) data=data|0x08; - SetReg1(P3c4,0x0F,data); + if (data2) data=data|0x08; + SiSSetReg1(SiSP3c4,0x0F,data); - data=GetReg1(P3c4,0x21); + data=SiSGetReg1(SiSP3c4,0x21); data=data&0x1F; - if(ModeType==0x00) data=data|0x60; // Text Mode - else if(ModeType<=0x02) data=data|0x00; // EGA Mode - else data=data|0xA0; // VGA Mode - SetReg1(P3c4,0x21,data); + if (SiSModeType==0x00) data=data|0x60; /* Text Mode */ + else if (SiSModeType<=0x02) data=data|0x00; /* EGA Mode */ + else data=data|0xA0; /* VGA Mode */ + SiSSetReg1(SiSP3c4,0x21,data); } -VOID SetVCLKState(PHW_DEVICE_EXTENSION HwDeviceExtension, ULONG ROMAddr, USHORT ModeNo) +VOID SiSSetVCLKState(PHW_DEVICE_EXTENSION HwDeviceExtension, ULONG ROMAddr, USHORT ModeNo) { USHORT data,data2; USHORT VCLK; UCHAR index; - index=*((UCHAR *)(ROMAddr+REFIndex+0x03)); + index=*((UCHAR *)(ROMAddr+SiSREFIndex+0x03)); index=index&0x03F; - CRT1VCLKLen=GetVCLKLen(ROMAddr); - data=index*CRT1VCLKLen; - VCLKData=*((USHORT *)(ROMAddr+0x208)); - VCLKData=VCLKData+data+(CRT1VCLKLen-2); - VCLK=*((USHORT *)(ROMAddr+VCLKData)); - if(ModeNo<=0x13) VCLK=0; + SiSCRT1VCLKLen=SiSGetVCLKLen(ROMAddr); + data=index*SiSCRT1VCLKLen; + SiSVCLKData=*((USHORT *)(ROMAddr+0x208)); + SiSVCLKData=SiSVCLKData+data+(SiSCRT1VCLKLen-2); + VCLK=*((USHORT *)(ROMAddr+SiSVCLKData)); + if (ModeNo<=0x13) VCLK=0; - data=GetReg1(P3c4,0x07); + data=SiSGetReg1(SiSP3c4,0x07); data=data&0x7B; - if(VCLK>=150) data=data|0x80; // VCLK > 150 - SetReg1(P3c4,0x07,data); + if (VCLK>=150) data=data|0x80; /* VCLK > 150 */ + SiSSetReg1(SiSP3c4,0x07,data); - data=GetReg1(P3c4,0x32); + data=SiSGetReg1(SiSP3c4,0x32); data=data&0xD7; - if(VCLK>=150) data=data|0x08; // VCLK > 150 - SetReg1(P3c4,0x32,data); + if (VCLK>=150) data=data|0x08; /* VCLK > 150 */ + SiSSetReg1(SiSP3c4,0x32,data); data2=0x03; - if(VCLK>135) data2=0x02; - if(VCLK>160) data2=0x01; - if(VCLK>260) data2=0x00; - data=GetReg1(P3c4,0x07); + if (VCLK>135) data2=0x02; + if (VCLK>160) data2=0x01; + if (VCLK>260) data2=0x00; + data=SiSGetReg1(SiSP3c4,0x07); data=data&0xFC; data=data|data2; - SetReg1(P3c4,0x07,data); + SiSSetReg1(SiSP3c4,0x07,data); } -VOID LoadDAC(ULONG ROMAddr) +VOID SiSLoadDAC(ULONG ROMAddr) { USHORT data,data2; USHORT time,i,j,k; USHORT m,n,o; USHORT si,di,bx,dl; USHORT al,ah,dh; - USHORT *table=VGA_DAC; + USHORT *table=SIS_VGA_DAC; - data=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); + data=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); data=data&DACInfoFlag; time=64; - if(data==0x00) table=MDA_DAC; - if(data==0x08) table=CGA_DAC; - if(data==0x10) table=EGA_DAC; - if(data==0x18) { + if (data==0x00) table=SIS_MDA_DAC; + if (data==0x08) table=SIS_CGA_DAC; + if (data==0x10) table=SIS_EGA_DAC; + if (data==0x18) { time=256; - table=VGA_DAC; + table=SIS_VGA_DAC; } - if(time==256) j=16; + if (time==256) j=16; else j=time; - SetReg3(P3c6,0xFF); - SetReg3(P3c8,0x00); + SiSSetReg3(SiSP3c6,0xFF); + SiSSetReg3(SiSP3c8,0x00); for(i=0;i<j;i++) { data=table[i]; for(k=0;k<3;k++) { data2=0; - if(data&0x01) data2=0x2A; - if(data&0x02) data2=data2+0x15; - SetReg3(P3c9,data2); + if (data&0x01) data2=0x2A; + if (data&0x02) data2=data2+0x15; + SiSSetReg3(SiSP3c9,data2); data=data>>2; } } - if(time==256) { + if (time==256) { for(i=16;i<32;i++) { data=table[i]; - for(k=0;k<3;k++) SetReg3(P3c9,data); + for(k=0;k<3;k++) SiSSetReg3(SiSP3c9,data); } si=32; for(m=0;m<9;m++) { @@ -1158,7 +756,7 @@ ah=table[di]; al=table[bx]; si++; - WriteDAC(dl,ah,al,dh); + SiSWriteDAC(dl,ah,al,dh); } si=si-2; for(o=0;o<3;o++) { @@ -1166,7 +764,7 @@ ah=table[di]; al=table[si]; si--; - WriteDAC(dl,ah,al,dh); + SiSWriteDAC(dl,ah,al,dh); } dl++; } @@ -1175,18 +773,18 @@ } } -VOID WriteDAC(USHORT dl, USHORT ah, USHORT al, USHORT dh) +VOID SiSWriteDAC(USHORT dl, USHORT ah, USHORT al, USHORT dh) { USHORT temp; USHORT bh,bl; bh=ah; bl=al; - if(dl!=0) { + if (dl!=0) { temp=bh; bh=dh; dh=temp; - if(dl==1) { + if (dl==1) { temp=bl; bl=dh; dh=temp; @@ -1197,35 +795,35 @@ bh=temp; } } - SetReg3(P3c9,(USHORT)dh); - SetReg3(P3c9,(USHORT)bh); - SetReg3(P3c9,(USHORT)bl); + SiSSetReg3(SiSP3c9,(USHORT)dh); + SiSSetReg3(SiSP3c9,(USHORT)bh); + SiSSetReg3(SiSP3c9,(USHORT)bl); } -VOID DisplayOn() +VOID SiSDisplayOn() { USHORT data; - data=GetReg1(P3c4,0x01); + data=SiSGetReg1(SiSP3c4,0x01); data=data&0xDF; - SetReg1(P3c4,0x01,data); + SiSSetReg1(SiSP3c4,0x01,data); } -USHORT GetModeIDLength(ULONG ROMAddr, USHORT ModeNo) +USHORT SiSGetModeIDLength(ULONG ROMAddr, USHORT ModeNo) { USHORT modeidlength; USHORT usModeIDOffset; USHORT PreviousWord,CurrentWord; modeidlength=0; - usModeIDOffset=*((USHORT *)(ROMAddr+0x20A)); // Get EModeIDTable - // maybe = 2Exx or xx2E - CurrentWord=*((USHORT *)(ROMAddr+usModeIDOffset)); // Offset 0x20A - PreviousWord=*((USHORT *)(ROMAddr+usModeIDOffset-2)); // Offset 0x20A + usModeIDOffset=*((USHORT *)(ROMAddr+0x20A)); /* Get EModeIDTable */ + /* maybe = 2Exx or xx2E */ + CurrentWord=*((USHORT *)(ROMAddr+usModeIDOffset)); /* Offset 0x20A */ + PreviousWord=*((USHORT *)(ROMAddr+usModeIDOffset-2)); /* Offset 0x20A */ while((CurrentWord!=0x2E07)||(PreviousWord!=0x0801)) { modeidlength++; - usModeIDOffset=usModeIDOffset+1; // 10 <= ExtStructSize + usModeIDOffset=usModeIDOffset+1; /* 10 <= ExtStructSize */ CurrentWord=*((USHORT *)(ROMAddr+usModeIDOffset)); PreviousWord=*((USHORT *)(ROMAddr+usModeIDOffset-2)); } @@ -1233,7 +831,7 @@ return(modeidlength); } -USHORT GetRefindexLength(ULONG ROMAddr, USHORT ModeNo) +USHORT SiSGetRefindexLength(ULONG ROMAddr, USHORT ModeNo) { UCHAR ModeID; UCHAR temp; @@ -1242,109 +840,109 @@ USHORT usREFIndex; USHORT usIDLength; - usModeIDOffset=*((USHORT *)(ROMAddr+0x20A)); // Get EModeIDTable - ModeID=*((UCHAR *)(ROMAddr+usModeIDOffset)); // Offset 0x20A - usIDLength = GetModeIDLength(ROMAddr, ModeNo); + usModeIDOffset=*((USHORT *)(ROMAddr+0x20A)); /* Get EModeIDTable */ + ModeID=*((UCHAR *)(ROMAddr+usModeIDOffset)); /* Offset 0x20A */ + usIDLength = SiSGetModeIDLength(ROMAddr, ModeNo); while(ModeID!=0x40) { - usModeIDOffset=usModeIDOffset+usIDLength; // 10 <= ExtStructSize + usModeIDOffset=usModeIDOffset+usIDLength; /* 10 <= ExtStructSize */ ModeID=*((UCHAR *)(ROMAddr+usModeIDOffset)); } refindexlength=1; - usREFIndex=*((USHORT *)(ROMAddr+usModeIDOffset+0x04)); // si+Ext_point + usREFIndex=*((USHORT *)(ROMAddr+usModeIDOffset+0x04)); /* si+Ext_point */ usREFIndex++; - temp=*((UCHAR *)(ROMAddr+usREFIndex)); // di => REFIndex + temp=*((UCHAR *)(ROMAddr+usREFIndex)); /* di => SiSREFIndex */ while(temp!=0xFF) { refindexlength++; usREFIndex++; - temp=*((UCHAR *)(ROMAddr+usREFIndex)); // di => REFIndex + temp=*((UCHAR *)(ROMAddr+usREFIndex)); /* di => SiSREFIndex */ } return(refindexlength); } -VOID SetInterlace(ULONG ROMAddr, USHORT ModeNo) +VOID SiSSetInterlace(ULONG ROMAddr, USHORT ModeNo) { ULONG Temp; USHORT data,Temp2; - Temp = (ULONG)GetReg1(P3d4, 0x01); + Temp = (ULONG)SiSGetReg1(SiSP3d4, 0x01); Temp++; Temp=Temp*8; - if(Temp==1024) data=0x0035; - else if(Temp==1280) data=0x0048; + if (Temp==1024) data=0x0035; + else if (Temp==1280) data=0x0048; else data=0x0000; - Temp2=*((USHORT *)(ROMAddr+REFIndex+0x00)); + Temp2=*((USHORT *)(ROMAddr+SiSREFIndex+0x00)); Temp2 &= InterlaceMode; - if(Temp2 == 0) data=0x0000; + if (Temp2 == 0) data=0x0000; - SetReg1(P3d4,0x19,data); + SiSSetReg1(SiSP3d4,0x19,data); - Temp = (ULONG)GetReg1(P3d4, 0x1A); + Temp = (ULONG)SiSGetReg1(SiSP3d4, 0x1A); Temp2= (USHORT)(Temp & 0xFC); - SetReg1(P3d4,0x1A,(USHORT)Temp); + SiSSetReg1(SiSP3d4,0x1A,(USHORT)Temp); - Temp = (ULONG)GetReg1(P3c4, 0x0f); + Temp = (ULONG)SiSGetReg1(SiSP3c4, 0x0f); Temp2= (USHORT)Temp & 0xBF; - if(ModeNo==0x37) Temp2=Temp2|0x40; - SetReg1(P3d4,0x1A,(USHORT)Temp2); + if (ModeNo==0x37) Temp2=Temp2|0x40; + SiSSetReg1(SiSP3d4,0x1A,(USHORT)Temp2); } -VOID SetCRT1FIFO(ULONG ROMAddr) +VOID SiSSetCRT1FIFO(ULONG ROMAddr) { USHORT colorth=0,index,data,VCLK,data2,MCLKOffset,MCLK; USHORT ah,bl,A,B; - index=*((UCHAR *)(ROMAddr+REFIndex+0x03)); + index=*((UCHAR *)(ROMAddr+SiSREFIndex+0x03)); index=index&0x03F; - CRT1VCLKLen=GetVCLKLen(ROMAddr); - data=index*CRT1VCLKLen; - VCLKData=*((USHORT *)(ROMAddr+0x208)); - VCLKData=VCLKData+data+(CRT1VCLKLen-2); - VCLK=*((USHORT *)(ROMAddr+VCLKData)); // Get VCLK + SiSCRT1VCLKLen=SiSGetVCLKLen(ROMAddr); + data=index*SiSCRT1VCLKLen; + SiSVCLKData=*((USHORT *)(ROMAddr+0x208)); + SiSVCLKData=SiSVCLKData+data+(SiSCRT1VCLKLen-2); + VCLK=*((USHORT *)(ROMAddr+SiSVCLKData)); /* Get VCLK */ MCLKOffset=*((USHORT *)(ROMAddr+0x20C)); - index=GetReg1(P3c4,0x3A); + index=SiSGetReg1(SiSP3c4,0x3A); index=index&07; MCLKOffset=MCLKOffset+index*5; - MCLK=*((UCHAR *)(ROMAddr+MCLKOffset+0x03)); // Get MCLK + MCLK=*((UCHAR *)(ROMAddr+MCLKOffset+0x03)); /* Get MCLK */ - data2=ModeType-0x02; + data2=SiSModeType-0x02; switch (data2) { - case 0 : colorth=1; break; - case 1 : colorth=2; break; - case 2 : colorth=4; break; - case 3 : colorth=4; break; - case 4 : colorth=6; break; - case 5 : colorth=8; break; - } + case 0 : colorth=1; break; + case 1 : colorth=2; break; + case 2 : colorth=4; break; + case 3 : colorth=4; break; + case 4 : colorth=6; break; + case 5 : colorth=8; break; + } do{ - B=(CalcDelay(ROMAddr,0)*VCLK*colorth); + B=(SiSCalcDelay(ROMAddr,0)*VCLK*colorth); B=B/(16*MCLK); B++; - A=(CalcDelay(ROMAddr,1)*VCLK*colorth); + A=(SiSCalcDelay(ROMAddr,1)*VCLK*colorth); A=A/(16*MCLK); A++; - if(A<4) A=0; + if (A<4) A=0; else A=A-4; - if(A>B) bl=A; + if (A>B) bl=A; else bl=B; bl++; - if(bl>0x13) { - data=GetReg1(P3c4,0x16); + if (bl>0x13) { + data=SiSGetReg1(SiSP3c4,0x16); data=data>>6; - if(data!=0) { + if (data!=0) { data--; data=data<<6; - data2=GetReg1(P3c4,0x16); + data2=SiSGetReg1(SiSP3c4,0x16); data2=(data2&0x3f)|data; - SetReg1(P3c4,0x16,data2); + SiSSetReg1(SiSP3c4,0x16,data2); } else bl=0x13; } @@ -1353,166 +951,166 @@ ah=bl; ah=ah<<4; ah=ah|0x0f; - SetReg1(P3c4,0x08,ah); + SiSSetReg1(SiSP3c4,0x08,ah); data=bl; data=data&0x10; data=data<<1; - data2=GetReg1(P3c4,0x0F); + data2=SiSGetReg1(SiSP3c4,0x0F); data2=data2&0x9f; data2=data2|data; - SetReg1(P3c4,0x0F,data2); + SiSSetReg1(SiSP3c4,0x0F,data2); data=bl+3; - if(data>0x0f) data=0x0f; - SetReg1(P3c4,0x3b,0x00); - data2=GetReg1(P3c4,0x09); + if (data>0x0f) data=0x0f; + SiSSetReg1(SiSP3c4,0x3b,0x00); + data2=SiSGetReg1(SiSP3c4,0x09); data2=data2&0xF0; data2=data2|data; - SetReg1(P3c4,0x09,data2); + SiSSetReg1(SiSP3c4,0x09,data2); } -static USHORT CalcDelay(ULONG ROMAddr,USHORT key) +static USHORT SiSCalcDelay(ULONG ROMAddr,USHORT key) { USHORT data,data2,temp0,temp1; - UCHAR ThLowA[]={61,3,52,5,68,7,100,11, - 43,3,42,5,54,7, 78,11, - 34,3,37,5,47,7, 67,11}; - UCHAR ThLowB[]={81,4,72,6,88,8,120,12, - 55,4,54,6,66,8, 90,12, - 42,4,45,6,55,8, 75,12}; + UCHAR ThLowA[]={ + 61,3,52,5,68,7,100,11, + 43,3,42,5,54,7, 78,11, + 34,3,37,5,47,7, 67,11}; + UCHAR ThLowB[]={ + 81,4,72,6,88,8,120,12, + 55,4,54,6,66,8, 90,12, + 42,4,45,6,55,8, 75,12}; UCHAR ThTiming[]= {1,2,2,3,0,1,1,2}; - data=GetReg1(P3c4,0x16); + data=SiSGetReg1(SiSP3c4,0x16); data=data>>6; - data2=GetReg1(P3c4,0x14); + data2=SiSGetReg1(SiSP3c4,0x14); data2=(data2>>4)&0x0C; data=data|data2; data=data<1; - if(key==0) { + if (key==0) { temp0=(USHORT)ThLowA[data]; temp1=(USHORT)ThLowA[data+1]; - } - else { + } else { temp0=(USHORT)ThLowB[data]; temp1=(USHORT)ThLowB[data+1]; } data2=0; - data=GetReg1(P3c4,0x18); - if(data&0x02) data2=data2|0x01; - if(data&0x20) data2=data2|0x02; - if(data&0x40) data2=data2|0x04; + data=SiSGetReg1(SiSP3c4,0x18); + if (data&0x02) data2=data2|0x01; + if (data&0x20) data2=data2|0x02; + if (data&0x40) data2=data2|0x04; data=temp1*ThTiming[data2]+temp0; return(data); } -VOID SetCRT1FIFO2(ULONG ROMAddr) +VOID SiSSetCRT1FIFO2(ULONG ROMAddr) { USHORT colorth=0,index,data,VCLK,data2,MCLKOffset,MCLK; USHORT ah,bl,B; ULONG eax; - index=*((UCHAR *)(ROMAddr+REFIndex+0x03)); + index=*((UCHAR *)(ROMAddr+SiSREFIndex+0x03)); index=index&0x03F; - CRT1VCLKLen=GetVCLKLen(ROMAddr); - data=index*CRT1VCLKLen; - VCLKData=*((USHORT *)(ROMAddr+0x208)); - VCLKData=VCLKData+data+(CRT1VCLKLen-2); - VCLK=*((USHORT *)(ROMAddr+VCLKData)); // Get VCLK + SiSCRT1VCLKLen=SiSGetVCLKLen(ROMAddr); + data=index*SiSCRT1VCLKLen; + SiSVCLKData=*((USHORT *)(ROMAddr+0x208)); + SiSVCLKData=SiSVCLKData+data+(SiSCRT1VCLKLen-2); + VCLK=*((USHORT *)(ROMAddr+SiSVCLKData)); /* Get VCLK */ MCLKOffset=*((USHORT *)(ROMAddr+0x20C)); - index=GetReg1(P3c4,0x1A); + index=SiSGetReg1(SiSP3c4,0x1A); index=index&07; MCLKOffset=MCLKOffset+index*5; - MCLK=*((USHORT *)(ROMAddr+MCLKOffset+0x03)); // Get MCLK + MCLK=*((USHORT *)(ROMAddr+MCLKOffset+0x03)); /* Get MCLK */ - data2=ModeType-0x02; + data2=SiSModeType-0x02; switch (data2) { - case 0 : colorth=1; break; - case 1 : colorth=1; break; - case 2 : colorth=2; break; - case 3 : colorth=2; break; - case 4 : colorth=3; break; - case 5 : colorth=4; break; + case 0 : colorth=1; break; + case 1 : colorth=1; break; + case 2 : colorth=2; break; + case 3 : colorth=2; break; + case 4 : colorth=3; break; + case 5 : colorth=4; break; } - do{ - B=(CalcDelay2(ROMAddr,0)*VCLK*colorth); - if (B%(16*MCLK) == 0) - { + do { + B=(SiSCalcDelay2(ROMAddr,0)*VCLK*colorth); + if (B%(16*MCLK) == 0) { B=B/(16*MCLK); bl=B+1; - } - else - { + } else { B=B/(16*MCLK); bl=B+2; } - if(bl>0x13) { - data=GetReg1(P3c4,0x15); + if (bl>0x13) { + data=SiSGetReg1(SiSP3c4,0x15); data=data&0xf0; - if(data!=0xb0) { + if (data!=0xb0) { data=data+0x20; - if(data==0xa0) data=0x30; + if (data==0xa0) data=0x30; - data2=GetReg1(P3c4,0x15); + data2=SiSGetReg1(SiSP3c4,0x15); data2=(data2&0x0f)|data; - SetReg1(P3c4,0x15,data2); + SiSSetReg1(SiSP3c4,0x15,data2); } else bl=0x13; } } while(bl>0x13); - data2=GetReg1(P3c4,0x15); + data2=SiSGetReg1(SiSP3c4,0x15); data2=(data2&0xf0)>>4; data2=data2<<24; - SetReg4(0xcf8,0x80000050); - eax=GetReg3(0xcfc); + SiSSetReg4(0xcf8,0x80000050); + eax=SiSGetReg3(0xcfc); eax=eax&0x0f0ffffff; eax=eax|data2; - SetReg4(0xcfc,eax); + SiSSetReg4(0xcfc,eax); ah=bl; ah=ah<<4; ah=ah|0x0f; - SetReg1(P3c4,0x08,ah); + SiSSetReg1(SiSP3c4,0x08,ah); data=bl; data=data&0x10; data=data<<1; - data2=GetReg1(P3c4,0x0F); + data2=SiSGetReg1(SiSP3c4,0x0F); data2=data2&0x9f; data2=data2|data; - SetReg1(P3c4,0x0F,data2); + SiSSetReg1(SiSP3c4,0x0F,data2); data=bl+3; - if(data>0x0f) data=0x0f; - SetReg1(P3c4,0x3b,0x00); - data2=GetReg1(P3c4,0x09); + if (data>0x0f) data=0x0f; + SiSSetReg1(SiSP3c4,0x3b,0x00); + data2=SiSGetReg1(SiSP3c4,0x09); data2=data2&0xF0; data2=data2|data; - SetReg1(P3c4,0x09,data2); + SiSSetReg1(SiSP3c4,0x09,data2); } -USHORT CalcDelay2(ULONG ROMAddr,USHORT key) +USHORT SiSCalcDelay2(ULONG ROMAddr,USHORT key) { USHORT data,index; - UCHAR LatencyFactor[]={88,80,78,72,70,00, - 00,79,77,71,69,49, - 88,80,78,72,70,00, - 00,72,70,64,62,44}; + UCHAR LatencyFactor[]={ + 88,80,78,72,70,00, + 00,79,77,71,69,49, + 88,80,78,72,70,00, + 00,72,70,64,62,44 + }; index=0; - data=GetReg1(P3c4,0x14); - if(data&0x80) index=index+12; + data=SiSGetReg1(SiSP3c4,0x14); + if (data&0x80) index=index+12; - data=GetReg1(P3c4,0x15); + data=SiSGetReg1(SiSP3c4,0x15); data=(data&0xf0)>>4; - if(data&0x01) index=index+6; + if (data&0x01) index=index+6; data=data>>1; index=index+data; @@ -1521,4 +1119,12 @@ return(data); } -#endif /* CONFIG_FB_SIS_LINUXBIOS */ +VOID SiSDisplayOff(VOID) +{ + USHORT data; + + data=SiSGetReg1(SiSP3c4,0x01); + data=data|0x20; + SiSSetReg1(SiSP3c4,0x01,data); +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/sis/sis_300.h linux.ac/drivers/video/sis/sis_300.h --- linux.vanilla/drivers/video/sis/sis_300.h Mon Nov 13 04:40:42 2000 +++ linux.ac/drivers/video/sis/sis_300.h Tue Apr 3 17:55:09 2001 @@ -1,7 +1,6 @@ -#include <linux/config.h> -#include "initdef.h" +#include "sis.h" -USHORT DRAMType[17][5]={{0x0C,0x0A,0x02,0x40,0x39},{0x0D,0x0A,0x01,0x40,0x48}, +USHORT SiSDRAMType[17][5]={{0x0C,0x0A,0x02,0x40,0x39},{0x0D,0x0A,0x01,0x40,0x48}, {0x0C,0x09,0x02,0x20,0x35},{0x0D,0x09,0x01,0x20,0x44}, {0x0C,0x08,0x02,0x10,0x31},{0x0D,0x08,0x01,0x10,0x40}, {0x0C,0x0A,0x01,0x20,0x34},{0x0C,0x09,0x01,0x08,0x32}, @@ -11,7 +10,7 @@ {0x0B,0x08,0x01,0x04,0x20},{0x0A,0x08,0x01,0x02,0x10}, {0x09,0x08,0x01,0x01,0x00}}; -USHORT MDA_DAC[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +USHORT SIS_MDA_DAC[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, @@ -20,7 +19,7 @@ 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F}; -USHORT CGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, +USHORT SIS_CGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, @@ -29,7 +28,7 @@ 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F}; -USHORT EGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15, +USHORT SIS_EGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15, 0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35, 0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D, 0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D, @@ -38,7 +37,7 @@ 0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F, 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F}; -USHORT VGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, +USHORT SIS_VGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, 0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18, 0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F, @@ -50,114 +49,67 @@ 0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10, 0x0B,0x0C,0x0D,0x0F,0x10}; -#ifdef CONFIG_FB_SIS_LINUXBIOS -unsigned char SRegsInit[] = { - 0x03, 0x00, 0x03, 0x00, 0x02, 0xa1, 0x00, 0x13, - 0x2f, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0f, 0x00, 0x00, 0x4f, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xa1, 0x76, 0xb2, 0xf6, 0x0d, 0x00, 0x00, 0x00, - 0x37, 0x61, 0x80, 0x1b, 0xe1, 0x01, 0x55, 0x43, - 0x80, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, - 0x8e, 0x40, 0x00, 0x00, 0x08, 0x00, 0xff, 0xff -}; - -unsigned char SRegs[] = { - 0x03, 0x01, 0x0F, 0x00, 0x0E, 0xA1, 0x02, 0x13, - 0x3F, 0x86, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x0B, 0x0F, 0x00, 0x00, 0x4F, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x40, 0x00, - 0xA1, 0xB6, 0xB2, 0xF6, 0x0D, 0x00, 0xF8, 0xF0, - 0x37, 0x61, 0x80, 0x1B, 0xE1, 0x80, 0x55, 0x43, - 0x80, 0x00, 0x11, 0xFF, 0x00, 0x00, 0x00, 0xFF, - 0x8E, 0x40, 0x00, 0x00, 0x08, 0x00, 0xFF, 0xFF -}; - -unsigned char CRegs[] = { - 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, - 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xe9, 0x0b, 0xdf, 0x50, 0x40, 0xe7, 0x04, 0xa3, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff -}; // clear CR11[7] - -unsigned char GRegs[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff, 0x00 -}; - -unsigned char ARegs[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -unsigned char MReg = 0x6f; - -#endif - -USHORT P3c4,P3d4,P3c0,P3ce,P3c2,P3ca,P3c6,P3c7,P3c8,P3c9,P3da; -USHORT CRT1VCLKLen; //VCLKData table length of bytes of each entry -USHORT flag_clearbuffer; //0: no clear frame buffer 1:clear frame buffer -int RAMType; -int ModeIDOffset,StandTable,CRT1Table,ScreenOffset,VCLKData,MCLKData, ECLKData; -int REFIndex,ModeType; -USHORT IF_DEF_LVDS,IF_DEF_TRUMPION; -USHORT VBInfo,LCDResInfo,LCDTypeInfo,LCDInfo; - -//int init300(int,int,int); -VOID SetMemoryClock(ULONG); -VOID SetDRAMSize(PHW_DEVICE_EXTENSION); -//extern "C" int ChkBUSWidth(int); - -//int setmode(int,int,int,int); -BOOLEAN SearchModeID(ULONG, USHORT); -BOOLEAN CheckMemorySize(ULONG); -VOID GetModePtr(ULONG, USHORT); -BOOLEAN GetRatePtr(ULONG, USHORT); -VOID SetSeqRegs(ULONG); -VOID SetMiscRegs(ULONG); -VOID SetCRTCRegs(ULONG); -VOID SetATTRegs(ULONG); -VOID SetGRCRegs(ULONG); -VOID ClearExt1Regs(VOID); -VOID SetSync(ULONG); -VOID SetCRT1CRTC(ULONG); -VOID SetCRT1Offset(ULONG); -VOID SetCRT1FIFO(ULONG); -VOID SetCRT1FIFO2(ULONG); -VOID SetCRT1VCLK(PHW_DEVICE_EXTENSION, ULONG); -VOID LoadDAC(ULONG); -VOID DisplayOn(VOID); -VOID SetCRT1ModeRegs(ULONG, USHORT); -VOID SetVCLKState(PHW_DEVICE_EXTENSION, ULONG, USHORT); -VOID WriteDAC(USHORT, USHORT, USHORT, USHORT); -VOID ClearBuffer(PHW_DEVICE_EXTENSION); -USHORT ChkBUSWidth(ULONG); -USHORT GetModeIDLength(ULONG, USHORT); -USHORT GetRefindexLength(ULONG, USHORT); -VOID SetInterlace(ULONG, USHORT); -USHORT CalcDelay2(ULONG ,USHORT); -void Set_LVDS_TRUMPION(VOID); -BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension, +USHORT SiSP3c4,SiSP3d4,SiSP3c0,SiSP3ce,SiSP3c2,SiSP3ca,SiSP3c6,SiSP3c7,SiSP3c8,SiSP3c9,SiSP3da; +USHORT SiSCRT1VCLKLen; +USHORT SiS_flag_clearbuffer; +int SiSRAMType; +int SiSModeIDOffset,SiSStandTable,SiSCRT1Table,SiSScreenOffset,SiSVCLKData,SiSMCLKData, SiSECLKData; +int SiSREFIndex,SiSModeType; +USHORT SIS_IF_DEF_LVDS,SIS_IF_DEF_TRUMPION,SIS_IF_DEF_CH7005,SIS_IF_DEF_HiVision; +USHORT SiSVBInfo,SiSLCDResInfo,SiSLCDTypeInfo,SiSLCDInfo; + +VOID SiSSetMemoryClock(ULONG); +VOID SiSSetDRAMSize(PHW_DEVICE_EXTENSION); + +BOOLEAN SiSSearchModeID(ULONG, USHORT); +BOOLEAN SiSCheckMemorySize(ULONG); +VOID SiSGetModePtr(ULONG, USHORT); +BOOLEAN SiSGetRatePtr(ULONG, USHORT); +VOID SiSSetSeqRegs(ULONG); +VOID SiSSetMiscRegs(ULONG); +VOID SiSSetCRTCRegs(ULONG); +VOID SiSSetATTRegs(ULONG); +VOID SiSSetGRCRegs(ULONG); +VOID SiSClearExt1Regs(VOID); +VOID SiSSetSync(ULONG); +VOID SiSSetCRT1CRTC(ULONG); +VOID SiSSetCRT1Offset(ULONG); +VOID SiSSetCRT1FIFO(ULONG); +VOID SiSSetCRT1FIFO2(ULONG); +VOID SiSSetCRT1VCLK(PHW_DEVICE_EXTENSION, ULONG); +VOID SiSLoadDAC(ULONG); +VOID SiSDisplayOn(VOID); +VOID SiSDisplayOff(VOID); +VOID SiSSetCRT1ModeRegs(ULONG, USHORT); +VOID SiSSetVCLKState(PHW_DEVICE_EXTENSION, ULONG, USHORT); +VOID SiSWriteDAC(USHORT, USHORT, USHORT, USHORT); +VOID sisfb_clear_buffer(PHW_DEVICE_EXTENSION); +USHORT SiSChkBUSWidth(ULONG); +USHORT SiSGetModeIDLength(ULONG, USHORT); +USHORT SiSGetRefindexLength(ULONG, USHORT); +VOID SiSSetInterlace(ULONG, USHORT); +USHORT SiSCalcDelay2(ULONG ,USHORT); +VOID SiSSet_LVDS_TRUMPION(VOID); +BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension, USHORT ModeNo); -#ifndef CONFIG_FB_SIS_LINUXBIOS -static USHORT CalcDelay(ULONG ,USHORT); -#endif +static USHORT SiSCalcDelay(ULONG ,USHORT); -extern BOOLEAN SetCRT2Group(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, +extern BOOLEAN SiSSetCRT2Group(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, PHW_DEVICE_EXTENSION HwDeviceExtension); -extern VOID GetVBInfo(USHORT BaseAddr,ULONG ROMAddr); -extern VOID PresetScratchregister(USHORT P3d4,PHW_DEVICE_EXTENSION HwDeviceExtension); -extern BOOLEAN GetLCDResInfo(ULONG ROMAddr,USHORT P3d4); -extern VOID SetTVSystem(PHW_DEVICE_EXTENSION HwDeviceExtension,ULONG ROMAddr); -extern BOOLEAN GetLCDDDCInfo(PHW_DEVICE_EXTENSION HwDeviceExtension); -extern BOOLEAN GetSenseStatus(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr); -extern BOOLEAN DetectMonitor(PHW_DEVICE_EXTENSION HwDeviceExtension); -extern USHORT GetVCLKLen(ULONG ROMAddr); -extern void SetReg1(u16 port, u16 index, u16 data); -extern void SetReg3(u16 port, u16 data); -extern void SetReg4(u16 port, unsigned long data); -extern u8 GetReg1(u16 port, u16 index); -extern u8 GetReg2(u16 port); -extern u32 GetReg3(u16 port); -extern void ClearDAC(u16 port); +extern VOID SiSGetVBInfo(USHORT BaseAddr,ULONG ROMAddr); +extern VOID SiSPresetScratchregister(USHORT SiSP3d4,PHW_DEVICE_EXTENSION HwDeviceExtension); +extern BOOLEAN SiSGetLCDResInfo(ULONG ROMAddr,USHORT SiSP3d4); +extern VOID SiSSetTVSystem(PHW_DEVICE_EXTENSION HwDeviceExtension,ULONG ROMAddr); +extern BOOLEAN SiSGetLCDDDCInfo(PHW_DEVICE_EXTENSION HwDeviceExtension); +extern BOOLEAN SiSGetSenseStatus(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr); +extern BOOLEAN SiSDetectMonitor(PHW_DEVICE_EXTENSION HwDeviceExtension); +extern USHORT SiSGetVCLKLen(ULONG ROMAddr); + +extern VOID sisfb_set_reg1(u16 port, u16 index, u16 data); +extern VOID sisfb_set_reg3(u16 port, u16 data); +extern VOID sisfb_set_reg4(u16 port, ULONG data); +extern u8 sisfb_get_reg1(u16 port, u16 index); +extern u8 sisfb_get_reg2(u16 port); +extern u32 sisfb_get_reg3(u16 port); +extern VOID sisfb_clear_DAC(u16 port); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/sis/sis_301.c linux.ac/drivers/video/sis/sis_301.c --- linux.vanilla/drivers/video/sis/sis_301.c Mon Nov 13 04:40:42 2000 +++ linux.ac/drivers/video/sis/sis_301.c Tue Apr 3 17:55:09 2001 @@ -1,505 +1,555 @@ -/* Recently Update by v1.09.50 */ - -#include <linux/config.h> +#include <linux/kernel.h> #include "sis_301.h" -#ifndef CONFIG_FB_SIS_LINUXBIOS - -BOOLEAN SetCRT2Group(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, +BOOLEAN SiSSetCRT2Group(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, PHW_DEVICE_EXTENSION HwDeviceExtension) { USHORT temp; - - SetFlag=SetFlag|ProgrammingCRT2; - SearchModeID(ROMAddr,ModeNo); - temp=GetRatePtrCRT2(ROMAddr,ModeNo); - if(((temp&0x02)==0) && ((VBInfo&CRT2DisplayFlag)==0)) - return(FALSE); - SaveCRT2Info(ModeNo); - DisableBridge(BaseAddr); - UnLockCRT2(BaseAddr); - SetDefCRT2ExtRegs(BaseAddr); - SetCRT2ModeRegs(BaseAddr,ModeNo); - if(VBInfo&CRT2DisplayFlag){ - LockCRT2(BaseAddr); - return 0; - } - GetCRT2Data(ROMAddr,ModeNo); - if(IF_DEF_LVDS==1){ //LVDS - GetLVDSDesData(ROMAddr,ModeNo); - } - SetGroup1(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension); - if(IF_DEF_LVDS==0){ - SetGroup2(BaseAddr,ROMAddr); - SetGroup3(BaseAddr); - SetGroup4(BaseAddr,ROMAddr,ModeNo); - SetGroup5(BaseAddr,ROMAddr); - }else{ //LVDS - if(IF_DEF_TRUMPION==0){ - ModCRT1CRTC(ROMAddr,ModeNo); - } - SetCRT2ECLK(ROMAddr,ModeNo); - } - - EnableCRT2(); - EnableBridge(BaseAddr); - SetLockRegs(); - LockCRT2(BaseAddr); - - return 1; -} + SiSSetFlag=SiSSetFlag|ProgrammingCRT2; + SiSSearchModeID(ROMAddr,ModeNo); -VOID overwriteregs(ULONG ROMAddr,USHORT BaseAddr) -{ - int i; - USHORT Part1Port; //reg data is for 1024x768 16bit 85hz - int p1reg[0x29]={0x84,0x76,0x4B,0x21,0x00,0x00,0x00,0x00,0x1F,0x51, - 0x0C,0x10,0x44,0x90,0x1E,0xFF,0x00,0x34,0x13,0x10, - 0x00,0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x97,0x16, - 0xA3}; - Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - for(i=0;i<29;i++){ - SetReg1(Part1Port,(USHORT)i,(USHORT)p1reg[i]); + temp=SiSGetRatePtrCRT2(ROMAddr,ModeNo); + if (((temp&0x02)==0) && ((SiSVBInfo&CRT2DisplayFlag)==0)) + return(FALSE); + SiSSaveCRT2Info(ModeNo); + SiSDisableBridge(BaseAddr); + SiSUnLockCRT2(BaseAddr); + SiSSetDefCRT2ExtRegs(BaseAddr); + SiSSetCRT2ModeRegs(BaseAddr,ModeNo); + if (SIS_IF_DEF_LVDS==0) { + if (SiSVBInfo&CRT2DisplayFlag) { + SiSLockCRT2(BaseAddr); + return 0; + } + } + SiSGetCRT2Data(ROMAddr,ModeNo); + if (SIS_IF_DEF_LVDS==1) { + SiSGetLVDSDesData(ROMAddr,ModeNo); + } + SiSSetGroup1(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension); + if (SIS_IF_DEF_LVDS==0) { + SiSSetGroup2(BaseAddr,ROMAddr); + SiSSetGroup3(BaseAddr,ROMAddr); + SiSSetGroup4(BaseAddr,ROMAddr,ModeNo); + SiSSetGroup5(BaseAddr,ROMAddr); + } + else { + if (SIS_IF_DEF_CH7005==1) SiSSetCHTVReg(ROMAddr,ModeNo); + SiSModCRT1CRTC(ROMAddr,ModeNo); + SiSSetCRT2ECLK(ROMAddr,ModeNo); + } + SiSEnableCRT2(); + SiSEnableBridge(BaseAddr); + if (SIS_IF_DEF_LVDS==0) { + /* SiSSetLockRegs(); */ } + SiSLockCRT2(BaseAddr); + return 1; } -VOID SetDefCRT2ExtRegs(USHORT BaseAddr) +VOID SiSSetDefCRT2ExtRegs(USHORT BaseAddr) { - USHORT Part1Port,Part2Port,Part4Port; - USHORT temp; + USHORT Part1Port,Part2Port,Part4Port; + USHORT temp; Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14; - SetReg1(Part1Port,0x02,0x40); - SetReg1(Part4Port,0x10,0x80); - temp=(UCHAR)GetReg1(P3c4,0x16); - temp=temp&0xC3; - SetReg1(P3d4,0x35,temp); + if (SIS_IF_DEF_LVDS==0) { + SiSSetReg1(Part1Port,0x02,0x40); + SiSSetReg1(Part4Port,0x10,0x80); + temp=(UCHAR)SiSGetReg1(SiSP3c4,0x16); + temp=temp&0xC3; + SiSSetReg1(SiSP3d4,0x35,temp); + } + else { + SiSSetReg1(SiSP3d4,0x32,0x02); + SiSSetReg1(Part1Port,0x02,0x00); + } } - -USHORT GetRatePtrCRT2(ULONG ROMAddr, USHORT ModeNo) -{ //return bit0=>0:standard mode 1:extended mode - SHORT index; // bit1=>0:crt2 no support this mode - USHORT temp; // 1:crt2 support this mode - USHORT ulRefIndexLength; - USHORT temp1; - SHORT LCDRefreshIndex[4]={0x0,0x0,0x03,0x01}; - // LCDPanel:no lcd,800x600,1024x768,1280x1024 - if(ModeNo<0x14) return(0); // Mode No <= 13h then return - - index=GetReg1(P3d4,0x33); // Get 3d4 CRTC33 - index=index>>SelectCRT2Rate; //For CRT2,cl=SelectCRT2Rate=4, shr ah,cl - index=index&0x0F; // Frame rate index - if(index!=0) index--; - - if(IF_DEF_TRUMPION==1){ - if(VBInfo&SetSimuScanMode){ - index=0; - } - } - if(SetFlag&ProgrammingCRT2){ - if(VBInfo&SetCRT2ToLCD){ - if(IF_DEF_LVDS==0){ - temp=LCDResInfo; + +USHORT SiSGetRatePtrCRT2(ULONG ROMAddr, USHORT ModeNo) +{ /* return bit0=>0:standard mode 1:extended mode */ + SHORT index; /* bit1=>0:crt2 no support this mode */ + USHORT temp; /* 1:crt2 support this mode */ + USHORT ulRefIndexLength; + USHORT temp1,modeflag1,Flag; + SHORT LCDRefreshIndex[2]={0x03,0x01}; + + if (SIS_IF_DEF_CH7005==1) { + if (SiSVBInfo&SetCRT2ToTV) { + modeflag1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); /* si+St_ModeFlag */ + if (modeflag1&HalfDCLK) return(0); + } + } + if (ModeNo<0x14) return(0); /* Mode No <= 13h then return */ + + index=SiSGetReg1(SiSP3d4,0x33); /* Get 3d4 CRTC33 */ + index=index>>SelectCRT2Rate; /* For CRT2,cl=SelectCRT2Rate=4, shr ah,cl */ + index=index&0x0F; /* Frame rate index */ + if (index!=0) index--; + + if (SiSSetFlag&ProgrammingCRT2) { + Flag=1; + if (SIS_IF_DEF_CH7005==1) { + if (SiSVBInfo&SetCRT2ToTV) { + index=0; + Flag=0; + } + } + if ((Flag)&&(SiSVBInfo&SetCRT2ToLCD)) { + if (SIS_IF_DEF_LVDS==0) { + temp=SiSLCDResInfo; temp1=LCDRefreshIndex[temp]; - if(index>temp1){ - index=temp1; + if (index>temp1) { + index=temp1; } - }else{ + } + else { index=0; - } - } + } + } } - - REFIndex=*((USHORT *)(ROMAddr+ModeIDOffset+0x04)); // si+Ext_point + + SiSREFIndex=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x04)); /* si+Ext_point */ ulRefIndexLength =Ext2StructSize; do { - temp=*((USHORT *)(ROMAddr+REFIndex)); // di => REFIndex - if(temp==0xFFFF) break; + temp=*((USHORT *)(ROMAddr+SiSREFIndex)); /* di => SiSREFIndex */ + if (temp==0xFFFF) break; temp=temp&ModeInfoFlag; - if(temp<ModeType) break; + if (temp<SiSModeType) break; - REFIndex=REFIndex+ulRefIndexLength; // rate size + SiSREFIndex=SiSREFIndex+ulRefIndexLength; /* rate size */ index--; - if(index<0){ - if(!(VBInfo&SetCRT2ToRAMDAC)){ - if(VBInfo&SetInSlaveMode){ - temp1=*((USHORT *)(ROMAddr+REFIndex+0-Ext2StructSize)); - if(temp1&InterlaceMode){ - index=0; - } + if (index<0) { + if (!(SiSVBInfo&SetCRT2ToRAMDAC)) { + if (SiSVBInfo&SetInSlaveMode) { + temp1=*((USHORT *)(ROMAddr+SiSREFIndex+0-Ext2StructSize)); + if (temp1&InterlaceMode) { + index=0; + } } } - } + } } while(index>=0); + SiSREFIndex=SiSREFIndex-ulRefIndexLength; /* rate size */ - REFIndex=REFIndex-ulRefIndexLength; // rate size - - if((SetFlag&ProgrammingCRT2)){ - temp1=AjustCRT2Rate(ROMAddr); - }else{ + if ((SiSSetFlag&ProgrammingCRT2)) { + temp1=SiSAjustCRT2Rate(ROMAddr); + } else { temp1=0; } - + return(0x01|(temp1<<1)); } - -BOOLEAN AjustCRT2Rate(ULONG ROMAddr) + +BOOLEAN SiSAjustCRT2Rate(ULONG ROMAddr) { - USHORT tempbx=0,tempax,temp; - USHORT tempextinfoflag; + USHORT tempax,tempbx=0,temp,resinfo; + USHORT tempextinfoflag,Flag; tempax=0; - - if(IF_DEF_LVDS==0){ - if(VBInfo&SetCRT2ToRAMDAC){ + if (SIS_IF_DEF_LVDS==0) { + if (SiSVBInfo&SetCRT2ToRAMDAC) { tempax=tempax|SupportRAMDAC2; } - if(VBInfo&SetCRT2ToLCD){ + if (SiSVBInfo&SetCRT2ToLCD) { tempax=tempax|SupportLCD; - if(LCDResInfo!=Panel1280x1024){ - temp=*((UCHAR *)(ROMAddr+ModeIDOffset+0x09)); //si+Ext_ResInfo - if(temp>=9){ - tempax=0; + if (SiSLCDResInfo!=Panel1280x1024) { + temp=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x09)); /* si+Ext_ResInfo */ + if (temp>=9) tempax=0; + } + } + if (SIS_IF_DEF_HiVision==1) { + tempax=tempax|SupportHiVisionTV; + if (SiSVBInfo&SetInSlaveMode) { + resinfo=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x09)); /* si+Ext_ResInfo */ + if (resinfo==4) return(0); + if (resinfo==3) { + if (SiSSetFlag&TVSimuMode) return(0); } + if (resinfo>7) return(0); } } - if(VBInfo&(SetCRT2ToAVIDEO|SetCRT2ToSVIDEO|SetCRT2ToSCART)){ - tempax=tempax|SupportTV; - if(!(VBInfo&SetPALTV)){ - tempextinfoflag=*((USHORT *)(ROMAddr+REFIndex+0x0)); //di+Ext_InfoFlag - if(tempextinfoflag&NoSupportSimuTV){ - if(VBInfo&SetInSlaveMode){ - if(!(VBInfo&SetNotSimuTVMode)){ - return 0; + else { + if (SiSVBInfo&(SetCRT2ToAVIDEO|SetCRT2ToSVIDEO|SetCRT2ToSCART)) { + tempax=tempax|SupportTV; + if (!(SiSVBInfo&SetPALTV)) { + tempextinfoflag=*((USHORT *)(ROMAddr+SiSREFIndex+0x0)); /* di+Ext_InfoFlag */ + if (tempextinfoflag&NoSupportSimuTV) { + if (SiSVBInfo&SetInSlaveMode) { + if (!(SiSVBInfo&SetNotSimuMode)) { + return 0; + } } } } } } - tempbx=*((USHORT *)(ROMAddr+ModeIDOffset+0x04)); // si+Ext_point - }else{ //for LVDS - if(VBInfo&SetCRT2ToLCD){ + + tempbx=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x04)); /* si+Ext_point */ + } + else { /* for LVDS */ + Flag=1; + if (SIS_IF_DEF_CH7005==1) { + if (SiSVBInfo&SetCRT2ToTV) { + tempax=tempax|SupportCHTV; + Flag=0; + } + } + tempbx=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x04)); + if ((Flag)&&(SiSVBInfo&SetCRT2ToLCD)) { tempax=tempax|SupportLCD; - temp=*((UCHAR *)(ROMAddr+ModeIDOffset+0x09)); //si+Ext_ResInfo - if(temp>0x08){ //1024x768 - return 0; - } - if(LCDResInfo<Panel1024x768){ - if(temp>0x07){ //800x600 - return 0; - } - if(temp==0x04){ //512x384 - return 0; - } + temp=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x09)); /* si+Ext_ResInfo */ + if (temp>0x08) return(0); /* 1024x768 */ + if (SiSLCDResInfo<Panel1024x768) { + if (temp>0x07) return(0); /* 800x600 */ + if (temp==0x04) return(0); /* 512x384 */ } } } - - for(;REFIndex>tempbx;REFIndex-=Ext2StructSize){ - tempextinfoflag=*((USHORT *)(ROMAddr+REFIndex+0x0)); //di+Ext_InfoFlag - if(tempextinfoflag&tempax){ + for(;SiSREFIndex>tempbx;SiSREFIndex-=Ext2StructSize) { + tempextinfoflag=*((USHORT *)(ROMAddr+SiSREFIndex+0x0)); /* di+Ext_InfoFlag */ + if (tempextinfoflag&tempax) { return 1; } - } - for(REFIndex=tempbx;;REFIndex+=Ext2StructSize){ - tempextinfoflag=*((USHORT *)(ROMAddr+REFIndex+0x0)); //di+Ext_InfoFlag - if(tempextinfoflag==0x0FFFF){ + } + for(SiSREFIndex=tempbx;;SiSREFIndex+=Ext2StructSize) { + tempextinfoflag=*((USHORT *)(ROMAddr+SiSREFIndex+0x0)); /* di+Ext_InfoFlag */ + if (tempextinfoflag==0x0FFFF) { return 0; } - if(tempextinfoflag&tempax){ + if (tempextinfoflag&tempax) { return 1; } } return(FALSE); } -VOID SaveCRT2Info(USHORT ModeNo){ +VOID SiSSaveCRT2Info(USHORT ModeNo) +{ USHORT temp1,temp2,temp3; - temp1=(VBInfo&SetInSlaveMode)>>8; + temp1=(SiSVBInfo&SetInSlaveMode)>>8; temp2=~(SetInSlaveMode>>8); - temp3=(UCHAR)GetReg1(P3d4,0x31); + temp3=(UCHAR)SiSGetReg1(SiSP3d4,0x31); temp3=((temp3&temp2)|temp1); - SetReg1(P3d4,0x31,(USHORT)temp3); - temp3=(UCHAR)GetReg1(P3d4,0x35); + SiSSetReg1(SiSP3d4,0x31,(USHORT)temp3); + temp3=(UCHAR)SiSGetReg1(SiSP3d4,0x35); temp3=temp3&0xF3; - SetReg1(P3d4,0x35,(USHORT)temp3); + SiSSetReg1(SiSP3d4,0x35,(USHORT)temp3); } -VOID DisableLockRegs(){ +VOID SiSDisableLockRegs() { UCHAR temp3; - temp3=(UCHAR)GetReg1(P3c4,0x32); + temp3=(UCHAR)SiSGetReg1(SiSP3c4,0x32); temp3=temp3&0xDF; - SetReg1(P3c4,0x32,(USHORT)temp3); + SiSSetReg1(SiSP3c4,0x32,(USHORT)temp3); } -VOID DisableCRT2(){ +VOID SiSDisableCRT2() { UCHAR temp3; - temp3=(UCHAR)GetReg1(P3c4,0x1E); + temp3=(UCHAR)SiSGetReg1(SiSP3c4,0x1E); temp3=temp3&0xDF; - SetReg1(P3c4,0x1E,(USHORT)temp3); + SiSSetReg1(SiSP3c4,0x1E,(USHORT)temp3); } -void DisableBridge(USHORT BaseAddr) +VOID SiSDisableBridge(USHORT BaseAddr) { - USHORT Part2Port,Part1Port; + UCHAR temp3,part2_02,part2_05; + USHORT Part2Port,Part1Port=0; Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; - Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - if(IF_DEF_LVDS==0){ - SetRegANDOR(Part2Port,0x00,0xDF,0x00); //Set Part2 Index0 D[5]=0 - DisableLockRegs(); // SR 32 - DisableCRT2(); // SR 1E - }else{ - DisableLockRegs(); - DisableCRT2(); - if(IF_DEF_TRUMPION==0){ - UnLockCRT2(BaseAddr); - SetRegANDOR(Part1Port,0x02,0xFF,0x40); //set Part1Port ,index 2, D6=1, - } + if (SIS_IF_DEF_LVDS==0) { + part2_02=(UCHAR)SiSGetReg1(Part2Port,0x02); + part2_05=(UCHAR)SiSGetReg1(Part2Port,0x05); + /* if (!SiSWaitVBRetrace(BaseAddr)) */ /* return 0:no enable read dram */ + { + SiSLongWait(); + SiSDisableLockRegs(); + } + SiSSetReg1(Part2Port,0x02,0x38); + SiSSetReg1(Part2Port,0x05,0xFF); + temp3=(UCHAR)SiSGetReg1(Part2Port,0x00); + temp3=temp3&0xDF; + SiSSetReg1(Part2Port,0x00,(USHORT)temp3); + SiSSetReg1(Part2Port,0x02,part2_02); + SiSSetReg1(Part2Port,0x05,part2_05); + SiSDisableCRT2(); + } + else { + SiSDisableLockRegs(); + SiSDisableCRT2(); + SiSUnLockCRT2(BaseAddr); + SiSSetRegANDOR(Part1Port,0x02,0xFF,0x40); /* et Part1Port ,index 2, D6=1, */ } } -VOID GetCRT2Data(ULONG ROMAddr,USHORT ModeNo) +VOID SiSGetCRT2Data(ULONG ROMAddr,USHORT ModeNo) { - if(IF_DEF_LVDS==0){ //301 - GetCRT2Data301(ROMAddr,ModeNo); + if (SIS_IF_DEF_LVDS==0) { /* 301 */ + SiSGetCRT2Data301(ROMAddr,ModeNo); return; - }else{ //LVDS - GetCRT2DataLVDS(ROMAddr,ModeNo); + } else { /* LVDS */ + SiSGetCRT2DataLVDS(ROMAddr,ModeNo); return; } } -VOID GetCRT2DataLVDS(ULONG ROMAddr,USHORT ModeNo) +VOID SiSGetCRT2DataLVDS(ULONG ROMAddr,USHORT ModeNo) { - USHORT tempax,tempbx,OldREFIndex; + USHORT tempax,tempbx,OldREFIndex; - OldREFIndex=(USHORT)REFIndex; //push di - GetResInfo(ROMAddr,ModeNo); - GetCRT2Ptr(ROMAddr,ModeNo); + OldREFIndex=(USHORT)SiSREFIndex; /* push di */ + SiSGetResInfo(ROMAddr,ModeNo); + SiSGetCRT2Ptr(ROMAddr,ModeNo); - tempax=*((USHORT *)(ROMAddr+REFIndex)); + tempax=*((USHORT *)(ROMAddr+SiSREFIndex)); tempax=tempax&0x0FFF; - VGAHT=tempax; + SiSVGAHT=tempax; - tempax=*((USHORT *)(ROMAddr+REFIndex+1)); + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+1)); tempax=tempax>>4; tempax=tempax&0x07FF; - VGAVT=tempax; + SiSVGAVT=tempax; - tempax=*((USHORT *)(ROMAddr+REFIndex+3)); + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+3)); tempax=tempax&0x0FFF; - tempbx=*((USHORT *)(ROMAddr+REFIndex+4)); + tempbx=*((USHORT *)(ROMAddr+SiSREFIndex+4)); tempbx=tempbx>>4; tempbx=tempbx&0x07FF; - HT=tempax; - VT=tempbx; + SiSHT=tempax; + SiSVT=tempbx; - if(IF_DEF_TRUMPION==0){ - if(VBInfo&SetCRT2ToLCD){ - if(!(LCDInfo&LCDNonExpanding)){ - if(LCDResInfo==Panel800x600){ + if (SIS_IF_DEF_TRUMPION==0) { + if (SiSVBInfo&SetCRT2ToLCD) { + if (!(SiSLCDInfo&LCDNonExpanding)) { + if (SiSLCDResInfo==Panel800x600) { tempax=800; tempbx=600; - }else if(LCDResInfo==Panel1024x768){ + } else if (SiSLCDResInfo==Panel1024x768) { tempax=1024; tempbx=768; - }else{ + } else { tempax=1280; tempbx=1024; - } - HDE=tempax; - VDE=tempbx; + } + SiSHDE=tempax; + SiSVDE=tempbx; } } } - REFIndex=OldREFIndex; //pop di + SiSREFIndex=OldREFIndex; /* pop di */ return; } -VOID GetCRT2Data301(ULONG ROMAddr,USHORT ModeNo) +VOID SiSGetCRT2Data301(ULONG ROMAddr,USHORT ModeNo) { USHORT tempax,tempbx,modeflag1,OldREFIndex; - USHORT tempal,tempah,tempbl; - - OldREFIndex=(USHORT)REFIndex; //push di - RVBHRS=50;NewFlickerMode=0;RY1COE=0; - RY2COE=0;RY3COE=0;RY4COE=0; - - GetResInfo(ROMAddr,ModeNo); - if(VBInfo&SetCRT2ToRAMDAC){ - GetRAMDAC2DATA(ROMAddr,ModeNo); - REFIndex=OldREFIndex; //pop di + USHORT tempal,tempah,tempbl,resinfo; + + OldREFIndex=SiSREFIndex; /* push di */ + SiSRVBHRS=50;SiSNewFlickerMode=0;SiSRY1COE=0; + SiSRY2COE=0;SiSRY3COE=0;SiSRY4COE=0; + + SiSGetResInfo(ROMAddr,ModeNo); + if (SiSVBInfo&SetCRT2ToRAMDAC) { + SiSGetRAMDAC2DATA(ROMAddr,ModeNo); + SiSREFIndex=OldREFIndex; /* pop di */ return; } - GetCRT2Ptr(ROMAddr,ModeNo); + SiSGetCRT2Ptr(ROMAddr,ModeNo); - tempal=*((UCHAR *)(ROMAddr+REFIndex)); - tempah=*((UCHAR *)(ROMAddr+REFIndex+4)); + tempal=*((UCHAR *)(ROMAddr+SiSREFIndex)); + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex+4)); tempax=tempal|(((tempah<<8)>>7)&0xFF00); - RVBHCMAX=tempax; + SiSRVBHCMAX=tempax; - tempal=*((UCHAR *)(ROMAddr+REFIndex+1)); - RVBHCFACT=tempal; + tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+1)); + SiSRVBHCFACT=tempal; - tempax=*((USHORT *)(ROMAddr+REFIndex+2)); - VGAHT=(tempax&0x0FFF); + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+2)); + SiSVGAHT=(tempax&0x0FFF); - tempax=*((USHORT *)(ROMAddr+REFIndex+3)); - VGAVT=((tempax>>4)&0x07FF); + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+3)); + SiSVGAVT=((tempax>>4)&0x07FF); - tempax=*((USHORT *)(ROMAddr+REFIndex+5)); + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+5)); tempax=(tempax&0x0FFF); - tempbx=*((USHORT *)(ROMAddr+REFIndex+6)); + tempbx=*((USHORT *)(ROMAddr+SiSREFIndex+6)); tempbx=((tempbx>>4)&0x07FF); tempbl=tempbx&0x00FF; - if(VBInfo&SetCRT2ToTV){ - tempax=*((USHORT *)(ROMAddr+REFIndex+5)); + if (SiSVBInfo&SetCRT2ToTV) { + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+5)); tempax=(tempax&0x0FFF); - HDE=tempax; - tempax=*((USHORT *)(ROMAddr+REFIndex+6)); + SiSHDE=tempax; + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+6)); tempax=((tempax>>4)&0x07FF); - VDE=tempax; - //skipp something about hivisiontv - tempax=*((USHORT *)(ROMAddr+REFIndex+8)); + SiSVDE=tempax; + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+8)); tempbl=(tempax>>8); - tempax=tempax&0x0FFF; - modeflag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - if(modeflag1&HalfDCLK){ - tempax=*((USHORT *)(ROMAddr+REFIndex+10)); - } - RVBHRS=tempax; - NewFlickerMode=(tempbl&0x080); - - tempax=*((USHORT *)(ROMAddr+REFIndex+12)); - RY1COE=(tempax&0x00FF); - RY2COE=((tempax&0xFF00)>>8); - tempax=*((USHORT *)(ROMAddr+REFIndex+14)); - RY3COE=(tempax&0x00FF); - RY4COE=((tempax&0xFF00)>>8); - if(!(VBInfo&SetPALTV)){ - tempax=NTSCHT; - tempbx=NTSCVT; - }else{ - tempax=PALHT; - tempbx=PALVT; - } + tempax=tempax&0x0FFF; + modeflag1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); /* si+St_ModeFlag */ + if (modeflag1&HalfDCLK) { + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+10)); + } + SiSRVBHRS=tempax; + + tempbl=tempbl&0x80; + if (SIS_IF_DEF_HiVision==1) { + resinfo=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x09)); /* si+Ext_ResInfo */ + if (resinfo==8) tempbl=0x40; + else if (resinfo==9) tempbl=0x40; + else if (resinfo==10) tempbl=0x40; + } + + SiSNewFlickerMode=tempbl; + + if (SIS_IF_DEF_HiVision==1) { + if (SiSVGAVDE==350) SiSSetFlag=SiSSetFlag|TVSimuMode; + tempax=ExtHiTVHT; + tempbx=ExtHiTVVT; + if (SiSVBInfo&SetInSlaveMode) { + if (SiSSetFlag&TVSimuMode) { + tempax=StHiTVHT; + tempbx=StHiTVVT; + modeflag1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); /* si+St_ModeFlag */ + if (!(modeflag1&Charx8Dot)) { + tempax=StHiTextTVHT; + tempbx=StHiTextTVVT; + } + } + } + } + else { + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+12)); + SiSRY1COE=(tempax&0x00FF); + SiSRY2COE=((tempax&0xFF00)>>8); + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+14)); + SiSRY3COE=(tempax&0x00FF); + SiSRY4COE=((tempax&0xFF00)>>8); + if (!(SiSVBInfo&SetPALTV)) { + tempax=NTSCHT; + tempbx=NTSCVT; + } else { + tempax=PALHT; + tempbx=PALVT; + } + } } - HT=tempax; - VT=tempbx; - if(!(VBInfo&SetCRT2ToLCD)){ - REFIndex=OldREFIndex; //pop di + SiSHT=tempax; + SiSVT=tempbx; + if (!(SiSVBInfo&SetCRT2ToLCD)) { + SiSREFIndex=OldREFIndex; /* pop di */ return; } tempax=1024; - if(VGAVDE==350){ //cx->VGAVDE + if (SiSVGAVDE==350) { /* cx->SiSVGAVDE */ tempbx=560; - }else if(VGAVDE==400){ + } else if (SiSVGAVDE==400) { tempbx=640; - }else{ + } else { tempbx=768; } - if(LCDResInfo==Panel1280x1024){ - tempax=1280; - if(VGAVDE==360){ + if (SiSLCDResInfo==Panel1280x1024) { + tempax=1280; + if (SiSVGAVDE==360) { tempbx=768; - }else if(VGAVDE==375){ - tempbx=800; - }else if(VGAVDE==405){ - tempbx=864; - }else{ + } else if (SiSVGAVDE==375) { + tempbx=800; + } else if (SiSVGAVDE==405) { + tempbx=864; + } else { tempbx=1024; - } + } } - HDE=tempax; - VDE=tempbx; - REFIndex=OldREFIndex; //pop di - return; + SiSHDE=tempax; + SiSVDE=tempbx; + SiSREFIndex=OldREFIndex; /* pop di */ + return; } -VOID GetResInfo(ULONG ROMAddr,USHORT ModeNo) -{ +VOID SiSGetResInfo(ULONG ROMAddr,USHORT ModeNo) +{ USHORT temp,xres,yres,modeflag1; - if(ModeNo<=0x13){ - temp=(USHORT)*((UCHAR *)(ROMAddr+ModeIDOffset+0x05)); // si+St_ResInfo - xres=StResInfo[temp][0]; - yres=StResInfo[temp][1]; - }else{ - temp=(USHORT)*((UCHAR *)(ROMAddr+ModeIDOffset+0x09)); // si+Ext_ResInfo - xres=ModeResInfo[temp][0]; //xres->ax - yres=ModeResInfo[temp][1]; //yres->bx - modeflag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - if(modeflag1&HalfDCLK){ xres=xres*2;} - if(modeflag1&DoubleScanMode){yres=yres*2;} - } - if(!(LCDResInfo==Panel1024x768)){ - if(yres==400) yres=405; - if(yres==350) yres=360; - if(SetFlag&LCDVESATiming){ - if(yres==360) yres=375; - } - } - VGAHDE=xres; - HDE=xres; - VGAVDE=yres; - VDE=yres; + if (ModeNo<=0x13) { + temp=(USHORT)*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x05)); /* si+St_ResInfo */ + xres=SiSStResInfo[temp][0]; + yres=SiSStResInfo[temp][1]; + } else { + temp=(USHORT)*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x09)); /* si+Ext_ResInfo */ + xres=SiSModeResInfo[temp][0]; /* xres->ax */ + yres=SiSModeResInfo[temp][1]; /* yres->bx */ + modeflag1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); /* si+St_ModeFlag */ + if (modeflag1&HalfDCLK) { xres=xres*2;} + if (modeflag1&DoubleScanMode) {yres=yres*2;} + } + if (!(SiSLCDResInfo==Panel1024x768)) { + if (yres==400) yres=405; + if (yres==350) yres=360; + if (SiSSetFlag&LCDVESATiming) { + if (yres==360) yres=375; + } + } + if (SIS_IF_DEF_LVDS==1) { + if (xres==720) xres=640; + } + SiSVGAHDE=xres; + SiSHDE=xres; + SiSVGAVDE=yres; + SiSVDE=yres; } -VOID GetLVDSDesData(ULONG ROMAddr,USHORT ModeNo) +VOID SiSGetLVDSDesData(ULONG ROMAddr,USHORT ModeNo) { USHORT old_REFIndex,tempax; - old_REFIndex=(USHORT)REFIndex; //push di - REFIndex=GetLVDSDesPtr(ROMAddr,ModeNo); + old_REFIndex=(USHORT)SiSREFIndex; /* push di */ + SiSREFIndex=SiSGetLVDSDesPtr(ROMAddr,ModeNo); - tempax=*((USHORT *)(ROMAddr+REFIndex)); + tempax=*((USHORT *)(ROMAddr+SiSREFIndex)); tempax=tempax&0x0FFF; - LCDHDES=tempax; + SiSLCDHDES=tempax; - if(LCDInfo&LCDNonExpanding){ //hw walk-a-round - if(LCDResInfo>=Panel1024x768){ - if(ModeNo<=0x13){ - LCDHDES=320; + if (SiSLCDInfo&LCDNonExpanding) { /* hw walk-a-round */ + if (SiSLCDResInfo>=Panel1024x768) { + if (ModeNo<=0x13) { + SiSLCDHDES=320; } } } - tempax=*((USHORT *)(ROMAddr+REFIndex+1)); + tempax=*((USHORT *)(ROMAddr+SiSREFIndex+1)); tempax=tempax>>4; tempax=tempax&0x07FF; - LCDVDES=tempax; + SiSLCDVDES=tempax; - REFIndex=old_REFIndex; //pop di - return; + SiSREFIndex=old_REFIndex; /* pop di */ + return; } -VOID GetRAMDAC2DATA(ULONG ROMAddr,USHORT ModeNo) +VOID SiSGetRAMDAC2DATA(ULONG ROMAddr,USHORT ModeNo) { USHORT tempax,tempbx,tempbh,modeflag1,t1=0,t2; - RVBHCMAX=1;RVBHCFACT=1; - if(ModeNo<=0x13){ - tempax=*((UCHAR *)(ROMAddr+REFIndex+10)); - tempbx=*((USHORT *)(ROMAddr+REFIndex+16)); - }else{ - t1=*((UCHAR *)(ROMAddr+REFIndex+0x2)); //Ext_CRT1CRTC=2 - t1=t1&0x03F; //[06/29/2000] fix bug for vbios >=v1.07.00 + SiSRVBHCMAX=1;SiSRVBHCFACT=1; + if (ModeNo<=0x13) { + tempax=*((UCHAR *)(ROMAddr+SiSREFIndex+10)); + tempbx=*((USHORT *)(ROMAddr+SiSREFIndex+16)); + } else { + t1=*((UCHAR *)(ROMAddr+SiSREFIndex+0x2)); /* Ext_CRT1CRTC=2 */ t1=t1*CRT1Len; - REFIndex=*((USHORT *)(ROMAddr+0x204)); // Get CRT1Table - REFIndex=REFIndex+t1; - t1=*((UCHAR *)(ROMAddr+REFIndex+0)); - t2=*((UCHAR *)(ROMAddr+REFIndex+14)); + SiSREFIndex=*((USHORT *)(ROMAddr+0x204)); /* Get SiSCRT1Table */ + SiSREFIndex=SiSREFIndex+t1; + t1=*((UCHAR *)(ROMAddr+SiSREFIndex+0)); + t2=*((UCHAR *)(ROMAddr+SiSREFIndex+14)); tempax=(t1&0xFF)|((t2&0x03)<<8); - tempbx=*((USHORT *)(ROMAddr+REFIndex+6)); - t1=*((UCHAR *)(ROMAddr+REFIndex+13)); + tempbx=*((USHORT *)(ROMAddr+SiSREFIndex+6)); + t1=*((UCHAR *)(ROMAddr+SiSREFIndex+13)); t1=(t1&0x01)<<2; } @@ -508,355 +558,407 @@ tempbh=tempbh|t1; tempbx=(tempbx&0xFF)|(tempbh<<8); tempax=tempax+5; - modeflag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - if(modeflag1&Charx8Dot){ + modeflag1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); /* si+St_ModeFlag */ + if (modeflag1&Charx8Dot) { tempax=tempax*8; - }else{ + } else { tempax=tempax*9; } - VGAHT=tempax; - HT=tempax; + SiSVGAHT=tempax; + SiSHT=tempax; tempbx++; - VGAVT=tempbx; - VT=tempbx; - + SiSVGAVT=tempbx; + SiSVT=tempbx; } -VOID GetCRT2Ptr(ULONG ROMAddr,USHORT ModeNo) +VOID SiSGetCRT2Ptr(ULONG ROMAddr,USHORT ModeNo) { - USHORT tempcl,tempbx,tempal,tempax,CRT2PtrData; + USHORT tempcl,tempbx,tempal,tempax,CRT2PtrData=0; + USHORT Flag; - if(IF_DEF_LVDS==0){ - if(VBInfo&SetCRT2ToLCD){ //LCD - tempbx=0; //default tempbx=0 -> ExtLCD1Data + if (SIS_IF_DEF_LVDS==0) { + if (SiSVBInfo&SetCRT2ToLCD) { /* LCD */ + tempbx=SiSLCDResInfo; tempcl=LCDDataLen; - if(LCDResInfo==Panel1024x768){ - tempbx=0; - }else if(LCDResInfo==Panel1280x1024){ - tempbx=1; - } - if(!(SetFlag&LCDVESATiming)) tempbx+=5; - }else if(VBInfo&SetPALTV){ - tempcl=TVDataLen; - tempbx=3; - }else{ - tempbx=4; - tempcl=TVDataLen; - } - if(SetFlag&TVSimuMode){ + tempbx=tempbx-Panel1024x768; + if (!(SiSSetFlag&LCDVESATiming)) tempbx+=5; + } + else { + if (SIS_IF_DEF_HiVision==1) { + if (SiSVGAVDE>480) SiSSetFlag=SiSSetFlag&(!TVSimuMode); + tempcl=HiTVDataLen; + tempbx=2; + if (SiSVBInfo&SetInSlaveMode) { + if (!(SiSSetFlag&TVSimuMode)) tempbx=10; + } + } + else { + if (SiSVBInfo&SetPALTV) { + tempcl=TVDataLen; + tempbx=3; + } + else { + tempbx=4; + tempcl=TVDataLen; + } + } + } + if (SiSSetFlag&TVSimuMode) { tempbx=tempbx+4; } - if(ModeNo<=0x13){ - tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x04)); // si+St_CRT2CRTC - }else{ - tempal=*((UCHAR *)(ROMAddr+REFIndex+4)); //di+Ext_CRT2CRTC + if (ModeNo<=0x13) { + tempal=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x04)); /* si+St_CRT2CRTC */ + } else { + tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+4)); /* di+Ext_CRT2CRTC */ } tempal=tempal&0x1F; tempax=tempal*tempcl; - REFIndex=*((USHORT *)(ROMAddr+tempbx*2+0x20E)); - REFIndex+=tempax; - }else{ //for LVDS - - tempcl=LVDSDataLen; - tempbx=LCDResInfo-Panel800x600; - if(LCDInfo&LCDNonExpanding){ - tempbx=tempbx+3; - } - if(ModeNo<=0x13){ - tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x04)); // si+St_CRT2CRTC - }else{ - tempal=*((UCHAR *)(ROMAddr+REFIndex+0x04)); // di+Ext_CRT2CRTC + SiSREFIndex=*((USHORT *)(ROMAddr + 0x20E + tempbx*2)); + SiSREFIndex+=tempax; + } + else { /* LVDS */ + Flag=1; + tempbx=0; + if (SIS_IF_DEF_CH7005==1) { + if (!(SiSVBInfo&SetCRT2ToLCD)) { + Flag=0; + tempbx=7; + if (SiSVBInfo&SetPALTV) tempbx=tempbx+2; + if (SiSVBInfo&SetCHTVOverScan) tempbx=tempbx+1; + } } + tempcl=LVDSDataLen; + if (Flag==1) { + tempbx=SiSLCDResInfo-Panel800x600; + if (SiSLCDInfo&LCDNonExpanding) { + tempbx=tempbx+3; + } + } + if (ModeNo<=0x13) tempal=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x04)); /* si+St_CRT2CRTC */ + else tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+0x04)); /* di+Ext_CRT2CRTC */ tempal=tempal&0x1F; tempax=tempal*tempcl; - CRT2PtrData=*((USHORT *)(ROMAddr+ADR_CRT2PtrData)); //ADR_CRT2PtrData is defined in init.def - REFIndex=*((USHORT *)(ROMAddr+CRT2PtrData+tempbx*2)); - REFIndex+=tempax; + CRT2PtrData=*((USHORT *)(ROMAddr+ADR_CRT2PtrData)); /* ADR_CRT2PtrData is defined in init.def */ + SiSREFIndex=*((USHORT *)(ROMAddr+CRT2PtrData+tempbx*2)); + SiSREFIndex+=tempax; } } -VOID UnLockCRT2(USHORT BaseAddr) +VOID SiSUnLockCRT2(USHORT BaseAddr) { UCHAR temp3; - USHORT Part1Port; + USHORT Part1Port; Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - temp3=(UCHAR)GetReg1(Part1Port,0x24); + temp3=(UCHAR)SiSGetReg1(Part1Port,0x24); temp3=temp3|0x01; - SetReg1(Part1Port,0x24,(USHORT)temp3); + SiSSetReg1(Part1Port,0x24,(USHORT)temp3); } -VOID SetCRT2ModeRegs(USHORT BaseAddr,USHORT ModeNo) +VOID SiSSetCRT2ModeRegs(USHORT BaseAddr,USHORT ModeNo) { USHORT i,j; - USHORT tempah=0,temp3; - SHORT tempcl; - USHORT Part4Port; - USHORT Part1Port; + USHORT tempcl,tempah,temp3; + USHORT Part4Port; + USHORT Part1Port; Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14; Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - for(i=0,j=4;i<3;i++,j++){ - SetReg1(Part1Port,j,0); + for(i=0,j=4;i<3;i++,j++) { + SiSSetReg1(Part1Port,j,0); } - - tempcl=(USHORT)ModeType; - if(ModeNo>0x13){ - tempcl=tempcl-ModeVGA; - if(tempcl>=0){ + + tempcl=SiSModeType; + if (ModeNo>0x13) { + tempcl=tempcl-ModeVGA; + if ((tempcl>0)||(tempcl==0)) { tempah=((0x010>>tempcl)|0x080); } - }else{ + } else { tempah=0x080; } - if(VBInfo&SetInSlaveMode){ + if (SiSVBInfo&SetInSlaveMode) { tempah=(tempah^0x0A0); } - if(VBInfo&CRT2DisplayFlag){ + if (SiSVBInfo&CRT2DisplayFlag) { tempah=0; } - SetReg1(Part1Port,0,tempah); + SiSSetReg1(Part1Port,0,tempah); - if(IF_DEF_LVDS==0){ //301 + + if (SIS_IF_DEF_LVDS==0) { tempah=0x01; - if(!(VBInfo&SetInSlaveMode)){ + if (!(SiSVBInfo&SetInSlaveMode)) { tempah=(tempah|0x02); } - if(!(VBInfo&SetCRT2ToRAMDAC)){ + if (!(SiSVBInfo&SetCRT2ToRAMDAC)) { tempah=(tempah^0x05); - if(!(VBInfo&SetCRT2ToLCD)){ + if (!(SiSVBInfo&SetCRT2ToLCD)) { tempah=(tempah^0x01); } } tempah=(tempah<<5)&0xFF; - if(VBInfo&CRT2DisplayFlag){ + if (SiSVBInfo&CRT2DisplayFlag) { tempah=0; } - SetReg1(Part1Port,0x01,tempah); + SiSSetReg1(Part1Port,0x01,tempah); tempah=tempah>>5; - if((ModeType==ModeVGA)&&(!(VBInfo&SetInSlaveMode))){ + if ((SiSModeType==ModeVGA)&&(!(SiSVBInfo&SetInSlaveMode))) { tempah=tempah|0x010; } - if(LCDResInfo!=Panel1024x768){ + if (SiSLCDResInfo!=Panel1024x768) { tempah=tempah|0x080; } - if(VBInfo&SetCRT2ToTV){ - if(VBInfo&SetInSlaveMode){ + if (SiSVBInfo&SetCRT2ToTV) { + if (SiSVBInfo&SetInSlaveMode) { tempah=tempah|0x020; } } - - temp3=(UCHAR)GetReg1(Part4Port,0x0D); + + temp3=(UCHAR)SiSGetReg1(Part4Port,0x0D); temp3=temp3&(~0x0BF); temp3=temp3|tempah; - SetReg1(Part4Port,0x0D,(USHORT)temp3); - }else{ //LVDS + SiSSetReg1(Part4Port,0x0D,(USHORT)temp3); + tempah=0; - if(!(VBInfo&SetInSlaveMode)){ + if (SiSVBInfo&SetCRT2ToTV) { + if (SiSVBInfo&SetInSlaveMode) { + if (!(SiSSetFlag&TVSimuMode)) { + if (SIS_IF_DEF_HiVision==0) { + SiSSetFlag=SiSSetFlag|RPLLDIV2XO; + tempah=tempah|0x40; + } + } + } + else { + SiSSetFlag=SiSSetFlag|RPLLDIV2XO; + tempah=tempah|0x40; + } + } + if (SiSLCDResInfo==Panel1280x1024) tempah=tempah|0x80; + if (SiSLCDResInfo==Panel1280x960) tempah=tempah|0x80; + SiSSetReg1(Part4Port,0x0C,(USHORT)temp3); + } + else { + tempah=0; + if (!(SiSVBInfo&SetInSlaveMode)) { tempah=tempah|0x02; } tempah=(tempah<<5)&0x0FF; - if(VBInfo&CRT2DisplayFlag){ + if (SiSVBInfo&CRT2DisplayFlag) { tempah=0; } - SetReg1(Part1Port,0x01,tempah); + SiSSetReg1(Part1Port,0x01,tempah); } } -VOID SetGroup1(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, +VOID SiSSetGroup1(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, PHW_DEVICE_EXTENSION HwDeviceExtension) { - if(IF_DEF_LVDS==0){ //301 - SetGroup1_301(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension); - }else{ //LVDS - SetGroup1_LVDS(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension); + if (SIS_IF_DEF_LVDS==0) { /* 301 */ + SiSSetGroup1_301(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension); + } else { /* LVDS */ + SiSSetGroup1_LVDS(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension); } } -VOID SetGroup1_LVDS(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, + +VOID SiSSetGroup1_LVDS(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, PHW_DEVICE_EXTENSION HwDeviceExtension) { USHORT temp1,temp2,tempcl,tempch,tempbh,tempal,tempah,tempax,tempbx; USHORT tempcx,OldREFIndex,lcdhdee; - USHORT Part1Port; + USHORT Part1Port; USHORT temppush1,temppush2; unsigned long int tempeax,tempebx,tempecx,templong; Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - OldREFIndex=(USHORT)REFIndex; //push di + OldREFIndex=(USHORT)SiSREFIndex; /* push di */ - SetCRT2Offset(Part1Port,ROMAddr); - SetCRT2FIFO(Part1Port,ROMAddr,ModeNo,HwDeviceExtension); - SetCRT2Sync(BaseAddr,ROMAddr,ModeNo); - - temp1=(VGAHT-1)&0x0FF; //BTVGA2HT 0x08,0x09 - SetReg1(Part1Port,0x08,temp1); - temp1=(((VGAHT-1)&0xFF00)>>8)<<4; - SetRegANDOR(Part1Port,0x09,~0x0F0,temp1); - - - temp1=(VGAHDE+12)&0x0FF; //BTVGA2HDEE 0x0A,0x0C - SetReg1(Part1Port,0x0A,temp1); - - temp1=VGAHDE+12; //bx BTVGA@HRS 0x0B,0x0C - temp2=(VGAHT-VGAHDE)>>2; //cx + SiSSetCRT2Offset(Part1Port,ROMAddr); + SiSSetCRT2FIFO(Part1Port,ROMAddr,ModeNo,HwDeviceExtension); + SiSSetCRT2Sync(BaseAddr,ROMAddr,ModeNo); + + temp1=(SiSVGAHT-1)&0x0FF; /* BTVGA2HT 0x08,0x09 */ + SiSSetReg1(Part1Port,0x08,temp1); + temp1=(((SiSVGAHT-1)&0xFF00)>>8)<<4; + SiSSetRegANDOR(Part1Port,0x09,~0x0F0,temp1); + + temp1=(SiSVGAHDE+12)&0x0FF; /* BTVGA2HDEE 0x0A,0x0C */ + SiSSetReg1(Part1Port,0x0A,temp1); + /* temp1=((SiSVGAHDE+12)&0xFF00)>>8; Wrong */ + /* SiSSetReg1(Part1Port,0x0C,temp1); */ + + temp1=SiSVGAHDE+12; /* bx BTVGA@HRS 0x0B,0x0C */ + temp2=(SiSVGAHT-SiSVGAHDE)>>2; temp1=temp1+temp2; temp2=(temp2<<1)+temp1; tempcl=temp2&0x0FF; - // - SetReg1(Part1Port,0x0B,(USHORT)(temp1&0x0FF)); + + SiSSetReg1(Part1Port,0x0B,(USHORT)(temp1&0x0FF)); tempah=(temp1&0xFF00)>>8; - tempbh=((((VGAHDE+12)&0xFF00)>>8)<<4)&0x0FF; + tempbh=((((SiSVGAHDE+12)&0xFF00)>>8)<<4)&0x0FF; tempah=tempah|tempbh; - SetReg1(Part1Port,0x0C,tempah); - SetReg1(Part1Port,0x0D,tempcl); //BTVGA2HRE 0x0D - tempcx=(VGAVT-1); + SiSSetReg1(Part1Port,0x0C,tempah); + SiSSetReg1(Part1Port,0x0D,tempcl); /* BTVGA2HRE 0x0D */ + tempcx=(SiSVGAVT-1); tempah=tempcx&0x0FF; - SetReg1(Part1Port,0x0E,tempah); //BTVGA2TV 0x0E,0x12 - tempbx=VGAVDE-1; + if (SIS_IF_DEF_CH7005==1) { + if (SiSVBInfo&0x0C) + tempah=tempah-1; + } + SiSSetReg1(Part1Port,0x0E,tempah); /* BTVGA2TV 0x0E,0x12 */ + tempbx=SiSVGAVDE-1; tempah=tempbx&0x0FF; - SetReg1(Part1Port,0x0F,tempah); //BTVGA2VDEE 0x0F,0x12 + if (SIS_IF_DEF_CH7005==1) { + if (SiSVBInfo&0x0C) + tempah=tempah-1; + } + SiSSetReg1(Part1Port,0x0F,tempah); /* BTVGA2VDEE 0x0F,0x12 */ tempah=((tempbx&0xFF00)<<3)>>8; tempah=tempah|((tempcx&0xFF00)>>8); - SetReg1(Part1Port,0x12,tempah); - - tempbx=(VGAVT+VGAVDE)>>1; //BTVGA2VRS 0x10,0x11 - tempcx=((VGAVT-VGAVDE)>>4)+tempbx+1; //BTVGA2VRE 0x11 - // + SiSSetReg1(Part1Port,0x12,tempah); + + tempbx=(SiSVGAVT+SiSVGAVDE)>>1; /* BTVGA2VRS 0x10,0x11 */ + tempcx=((SiSVGAVT-SiSVGAVDE)>>4)+tempbx+1; /* BTVGA2VRE 0x11 */ + tempah=tempbx&0x0FF; - SetReg1(Part1Port,0x10,tempah); + SiSSetReg1(Part1Port,0x10,tempah); tempbh=(tempbx&0xFF00)>>8; tempah=((tempbh<<4)&0x0FF)|(tempcx&0x0F); - SetReg1(Part1Port,0x11,tempah); + SiSSetReg1(Part1Port,0x11,tempah); - SetRegANDOR(Part1Port,0x13,~0x03C,tempah); + SiSSetRegANDOR(Part1Port,0x13,~0x03C,tempah); - tempax=LCDHDES; - tempbx=HDE; - tempcx=HT; - tempcx=tempcx-tempbx; //HT-HDE - tempax=tempax+tempbx; //lcdhdee - tempbx=HT; - if(tempax>=tempbx){ + /* lines below are newly added for LVDS */ + tempax=SiSLCDHDES; + tempbx=SiSHDE; + tempcx=SiSHT; + tempcx=tempcx-tempbx; /* SiSHT-SiSHDE */ + /* push ax lcdhdes */ + tempax=tempax+tempbx; /* lcdhdee */ + tempbx=SiSHT; + if (tempax>=tempbx) { tempax=tempax-tempbx; } - + /* push ax lcdhdee */ lcdhdee=tempax; - tempcx=tempcx>>2; //temp - tempcx=tempcx+tempax; //lcdhrs - if(tempcx>=tempbx){ + tempcx=tempcx>>2; /* temp */ + tempcx=tempcx+tempax; /* lcdhrs */ + if (tempcx>=tempbx) { tempcx=tempcx-tempbx; } - + /* v ah,cl */ tempax=tempcx; - tempax=tempax>>3; //BPLHRS + tempax=tempax>>3; /* BPLHRS */ tempah=tempax&0x0FF; - SetReg1(Part1Port,0x14,tempah); //Part1_14h + SiSSetReg1(Part1Port,0x14,tempah); /* Part1_14h */ tempah=tempah+2; tempah=tempah+0x01F; tempcl=tempcx&0x0FF; tempcl=tempcl&0x07; - tempcl=(tempcl<<5)&0xFF; //BPHLHSKEW + tempcl=(tempcl<<5)&0xFF; /* PHLHSKEW */ tempah=tempah|tempcl; - SetReg1(Part1Port,0x15,tempah); //Part1_15h - tempbx=lcdhdee; //lcdhdee - tempcx=LCDHDES; //lcdhdes + SiSSetReg1(Part1Port,0x15,tempah); /* Part1_15h */ + tempbx=lcdhdee; /* lcdhdee */ + tempcx=SiSLCDHDES; /* lcdhdes */ tempah=(tempcx&0xFF); - tempah=tempah&0x07; //BPLHDESKEW - SetReg1(Part1Port,0x1A,tempah); //Part1_1Ah - tempcx=tempcx>>3; //BPLHDES + tempah=tempah&0x07; /* BPLHDESKEW */ + SiSSetReg1(Part1Port,0x1A,tempah); /* Part1_1Ah */ + tempcx=tempcx>>3; /* BPLHDES */ tempah=(tempcx&0xFF); - SetReg1(Part1Port,0x16,tempah); //Part1_16h - tempbx=tempbx>>3; //BPLHDEE + SiSSetReg1(Part1Port,0x16,tempah); /* Part1_16h */ + tempbx=tempbx>>3; /* BPLHDEE */ tempah=tempbx&0xFF; - SetReg1(Part1Port,0x17,tempah); //Part1_17h + SiSSetReg1(Part1Port,0x17,tempah); /* Part1_17h */ - tempcx=VGAVT; - tempbx=VGAVDE; - tempcx=tempcx-tempbx; //VGAVT-VGAVDE - tempbx=LCDVDES; //VGAVDES - temppush1=tempbx; //push bx temppush1 - if(IF_DEF_TRUMPION==0){ - if(LCDResInfo==Panel800x600){ - tempax=600; - }else{ - tempax=768; + tempcx=SiSVGAVT; + tempbx=SiSVGAVDE; + tempcx=tempcx-tempbx; /* GAVT-SiSVGAVDE */ + tempbx=SiSLCDVDES; /* VGAVDES */ + temppush1=tempbx; /* push bx temppush1 */ + if (SIS_IF_DEF_TRUMPION==0) { + if (SIS_IF_DEF_CH7005==1) tempax=SiSVGAVDE; + if (SiSVBInfo&SetCRT2ToLCD) { + if (SiSLCDResInfo==Panel800x600) tempax=600; + else tempax=768; } - }else{ - tempax=VGAVDE; } + else + tempax=SiSVGAVDE; tempbx=tempbx+tempax; - tempax=VT; //VT - if(tempbx>=VT){ + tempax=SiSVT; /* SiSVT */ + if (tempbx>=SiSVT) { tempbx=tempbx-tempax; } - temppush2=tempbx; //push bx temppush2 + temppush2=tempbx; /* push bx temppush2 */ tempcx=tempcx>>1; tempbx=tempbx+tempcx; - tempbx++; //BPLVRS - if(tempbx>=tempax){ + tempbx++; /* BPLVRS */ + if (tempbx>=tempax) { tempbx=tempbx-tempax; } tempah=tempbx&0xFF; - SetReg1(Part1Port,0x18,tempah); //Part1_18h + SiSSetReg1(Part1Port,0x18,tempah); /* Part1_18h */ tempcx=tempcx>>3; tempcx=tempcx+tempbx; - tempcx++; //BPLVRE + tempcx++; /* BPLVRE */ tempah=tempcx&0xFF; tempah=tempah&0x0F; tempah=tempah|0x030; - SetRegANDOR(Part1Port,0x19,~0x03F,tempah); //Part1_19h + SiSSetRegANDOR(Part1Port,0x19,~0x03F,tempah); /* Part1_19h */ tempbh=(tempbx&0xFF00)>>8; tempbh=tempbh&0x07; tempah=tempbh; - tempah=(tempah<<3)&0xFF; //BPLDESKEW =0 - tempbx=VGAVDE; - if(tempbx!=VDE){ + tempah=(tempah<<3)&0xFF; /* BPLDESKEW =0 */ + /* movzx */ + tempbx=SiSVGAVDE; + if (tempbx!=SiSVDE) { tempah=tempah|0x40; } - SetRegANDOR(Part1Port,0x1A,0x07,tempah); //Part1_1Ah - tempecx=VGAVT; - tempebx=VDE; - tempeax=VGAVDE; - tempecx=tempecx-tempeax; //VGAVT-VGAVDE + SiSSetRegANDOR(Part1Port,0x1A,0x07,tempah); /* Part1_1Ah */ + tempecx=SiSVGAVT; + tempebx=SiSVDE; + tempeax=SiSVGAVDE; + tempecx=tempecx-tempeax; /* SiSVGAVT-SiSVGAVDE */ tempeax=tempeax*64; templong=tempeax/tempebx; - if(templong*tempebx<tempeax){ + if (templong*tempebx<tempeax) { templong++; } - tempebx=templong; //BPLVCFACT - if(SetFlag&EnableLVDSDDA){ + tempebx=templong; /* BPLVCFACT */ + if (SiSSetFlag&EnableLVDSDDA) { tempebx=tempebx&0x03F; } tempah=(USHORT)(tempebx&0x0FF); - SetReg1(Part1Port,0x1E,tempah); //Part1_1Eh - tempbx=temppush2; //pop bx temppush2 BPLVDEE - tempcx=temppush1; //pop cx temppush1 NPLVDES + SiSSetReg1(Part1Port,0x1E,tempah); /* Part1_1Eh */ + tempbx=temppush2; /* p bx temppush2 BPLVDEE */ + tempcx=temppush1; /* pop cx temppush1 NPLVDES */ tempbh=(tempbx&0xFF00)>>8; tempah=tempah&0x07; tempah=tempbh; tempah=tempah<<3; tempch=(tempcx&0xFF00)>>8; - tempch=tempah&0x07; + tempch=tempch&0x07; tempah=tempah|tempch; - SetReg1(Part1Port,0x1D,tempah); //Part1_1Dh + SiSSetReg1(Part1Port,0x1D,tempah); /* Part1_1Dh */ tempah=tempbx&0xFF; - SetReg1(Part1Port,0x1C,tempah); //Part1_1Ch + SiSSetReg1(Part1Port,0x1C,tempah); /* Part1_1Ch */ tempah=tempcx&0xFF; - SetReg1(Part1Port,0x1B,tempah); //Part1_1Bh - - tempecx=VGAHDE; - tempebx=HDE; + SiSSetReg1(Part1Port,0x1B,tempah); /* Part1_1Bh */ + + tempecx=SiSVGAHDE; + tempebx=SiSHDE; tempeax=tempecx; tempeax=tempeax<<6; tempeax=tempeax<<10; tempeax=tempeax/tempebx; - if(tempebx==tempecx){ + if (tempebx==tempecx) { tempeax=65535; } tempecx=tempeax; - tempeax=VGAHT; + tempeax=SiSVGAHT; tempeax=tempeax<<6; tempeax=tempeax<<10; tempeax=tempeax/tempecx; @@ -865,10 +967,10 @@ tempax=(USHORT)(tempeax&0x00FFFF); tempcx=tempax; tempah=tempcx&0x0FF; - SetReg1(Part1Port,0x1F,tempah); //Part1_1Fh - tempbx=VDE; - tempbx--; //BENPLACCEND - if(SetFlag&EnableLVDSDDA){ + SiSSetReg1(Part1Port,0x1F,tempah); /* Part1_1Fh */ + tempbx=SiSVDE; + tempbx--; /* BENPLACCEND */ + if (SiSSetFlag&EnableLVDSDDA) { tempbx=1; } tempah=(tempbx&0xFF00)>>8; @@ -876,341 +978,357 @@ tempch=(tempcx&0xFF00)>>8; tempch=tempch&0x07; tempah=tempah|tempch; - SetReg1(Part1Port,0x20,tempah); //Part1_20h + SiSSetReg1(Part1Port,0x20,tempah); /* Part1_20h */ tempah=tempbx&0xFF; - SetReg1(Part1Port,0x21,tempah); //Part1_21h - tempecx=tempecx>>16; //BPLHCFACT - temp1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - if(temp1&HalfDCLK){ + SiSSetReg1(Part1Port,0x21,tempah); /* Part1_21h */ + tempecx=tempecx>>16; /* BPLHCFACT */ + temp1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); /* si+St_ModeFlag */ + if (temp1&HalfDCLK) { tempecx=tempecx>>1; } tempcx=(USHORT)(tempecx&0x0FFFF); tempah=(tempcx&0xFF00)>>8; - SetReg1(Part1Port,0x22,tempah); //Part1_22h + SiSSetReg1(Part1Port,0x22,tempah); /* Part1_22h */ tempah=tempcx&0x0FF; - SetReg1(Part1Port,0x23,tempah); //Part1_23h - if(IF_DEF_TRUMPION==1){ - tempal=(USHORT)*((UCHAR *)(ROMAddr+ModeIDOffset+0x05)); // si+St_ResInfo - if(ModeNo>0x13){ - SetFlag=SetFlag|ProgrammingCRT2; - GetRatePtrCRT2(ROMAddr,ModeNo); - tempal=*((UCHAR *)(ROMAddr+REFIndex+0x04)); // di+Ext_CRT2CRTC + SiSSetReg1(Part1Port,0x23,tempah); /* Part1_23h */ + if (SIS_IF_DEF_TRUMPION==1) { + tempal=(USHORT)*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x05)); /* si+St_ResInfo */ + if (ModeNo>0x13) { + SiSSetFlag=SiSSetFlag|ProgrammingCRT2; + SiSGetRatePtrCRT2(ROMAddr,ModeNo); + tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+0x04)); /* di+Ext_CRT2CRTC */ tempal=tempal&0x1F; - } + } tempah=0x80; tempal=tempal*tempah; - REFIndex= offset_Zurac; //offset Zurac need added in rompost.asm - REFIndex=REFIndex+tempal; - SetTPData(); //this function not implemented yet - SetTPData(); - SetTPData(); - SetTPData(); - SetTPData(); - SetTPData(); - SetTPData(); - SetTPData(); - SetTPData(); + SiSREFIndex= offset_Zurac; /* offset Zurac need added in rompost.asm */ + SiSREFIndex=SiSREFIndex+tempal; + SiSSetTPData(); /* this function not implemented yet */ + SiSSetTPData(); + SiSSetTPData(); + SiSSetTPData(); + SiSSetTPData(); + SiSSetTPData(); + SiSSetTPData(); + SiSSetTPData(); + SiSSetTPData(); } - REFIndex=OldREFIndex; //pop di + SiSREFIndex=OldREFIndex; /* pop di */ + return; } -VOID SetTPData(VOID) +VOID SiSSetTPData() { return; } -VOID SetGroup1_301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, + +VOID SiSSetGroup1_301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, PHW_DEVICE_EXTENSION HwDeviceExtension) { - USHORT temp1,temp2,tempcl,tempch,tempbl,tempbh,tempal,tempah,tempax,tempbx; - USHORT tempcx,OldREFIndex; - USHORT Part1Port; + USHORT temp1,temp2,tempcl,tempch,tempbl,tempbh,tempal,tempah,tempax,tempbx; + USHORT tempcx,OldREFIndex; + USHORT Part1Port,resinfo,modeflag; Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - OldREFIndex=(USHORT)REFIndex; //push di + OldREFIndex=SiSREFIndex; /* di */ - SetCRT2Offset(Part1Port,ROMAddr); - SetCRT2FIFO(Part1Port,ROMAddr,ModeNo,HwDeviceExtension); - SetCRT2Sync(BaseAddr,ROMAddr,ModeNo); - - GetCRT1Ptr(ROMAddr); - - temp1=(VGAHT-1)&0x0FF; //BTVGA2HT 0x08,0x09 - SetReg1(Part1Port,0x08,temp1); - temp1=(((VGAHT-1)&0xFF00)>>8)<<4; - SetRegANDOR(Part1Port,0x09,~0x0F0,temp1); - - temp1=(VGAHDE+12)&0x0FF; //BTVGA2HDEE 0x0A,0x0C - SetReg1(Part1Port,0x0A,temp1); - - temp1=VGAHDE+12; //bx BTVGA@HRS 0x0B,0x0C - temp2=(VGAHT-VGAHDE)>>2; //cx + SiSSetCRT2Offset(Part1Port,ROMAddr); + SiSSetCRT2FIFO(Part1Port,ROMAddr,ModeNo,HwDeviceExtension); + SiSSetCRT2Sync(BaseAddr,ROMAddr,ModeNo); + + SiSGetCRT1Ptr(ROMAddr); + + temp1=(SiSVGAHT-1)&0x0FF; /* BTVGA2HT 0x08,0x09 */ + SiSSetReg1(Part1Port,0x08,temp1); + temp1=(((SiSVGAHT-1)&0xFF00)>>8)<<4; + SiSSetRegANDOR(Part1Port,0x09,~0x0F0,temp1); + + temp1=(SiSVGAHDE+12)&0x0FF; /* BTVGA2HDEE 0x0A,0x0C */ + SiSSetReg1(Part1Port,0x0A,temp1); + + temp1=SiSVGAHDE+12; /* bx BTVGA@HRS 0x0B,0x0C */ + temp2=(SiSVGAHT-SiSVGAHDE)>>2; /* cx */ temp1=temp1+temp2; temp2=(temp2<<1)+temp1; tempcl=temp2&0x0FF; - if(VBInfo&SetCRT2ToRAMDAC){ - tempbl=*((UCHAR *)(ROMAddr+REFIndex+4)); //di+4 - tempbh=*((UCHAR *)(ROMAddr+REFIndex+14)); //di+14 - temp1=((tempbh>>6)<<8)|tempbl; //temp1->bx - temp1=(temp1-1)<<3; - tempcl=*((UCHAR *)(ROMAddr+REFIndex+5)); //di+5 - tempch=*((UCHAR *)(ROMAddr+REFIndex+15)); //di+15 + if (SiSVBInfo&SetCRT2ToRAMDAC) { + tempbl=*((UCHAR *)(ROMAddr+SiSREFIndex+4)); /* di+4 */ + tempbh=*((UCHAR *)(ROMAddr+SiSREFIndex+14)); /* di+14 */ + temp1=((tempbh>>6)<<8)|tempbl; /* temp1->bx */ + temp1=(temp1-1)<<3; + tempcl=*((UCHAR *)(ROMAddr+SiSREFIndex+5)); /* di+5 */ + tempch=*((UCHAR *)(ROMAddr+SiSREFIndex+15)); /* di+15 */ tempcl=tempcl&0x01F; tempch=(tempch&0x04)<<(6-2); - tempcl=((tempcl|tempch)-1)<<3; + tempcl=((tempcl|tempch)-1)<<3; } - SetReg1(Part1Port,0x0B,(USHORT)(temp1&0x0FF)); + SiSSetReg1(Part1Port,0x0B,(USHORT)(temp1&0x0FF)); tempah=(temp1&0xFF00)>>8; - tempbh=((((VGAHDE+12)&0xFF00)>>8)<<4)&0x0FF; + tempbh=((((SiSVGAHDE+12)&0xFF00)>>8)<<4)&0x0FF; tempah=tempah|tempbh; - SetReg1(Part1Port,0x0C,tempah); - SetReg1(Part1Port,0x0D,tempcl); //BTVGA2HRE 0x0D - tempcx=(VGAVT-1); + SiSSetReg1(Part1Port,0x0C,tempah); + SiSSetReg1(Part1Port,0x0D,tempcl); /* BTVGA2HRE 0x0D */ + tempcx=(SiSVGAVT-1); tempah=tempcx&0x0FF; - SetReg1(Part1Port,0x0E,tempah); //BTVGA2TV 0x0E,0x12 - tempbx=VGAVDE-1; + SiSSetReg1(Part1Port,0x0E,tempah); /* BTVGA2TV 0x0E,0x12 */ + tempbx=SiSVGAVDE-1; tempah=tempbx&0x0FF; - SetReg1(Part1Port,0x0F,tempah); //BTVGA2VDEE 0x0F,0x12 + SiSSetReg1(Part1Port,0x0F,tempah); /* BTVGA2VDEE 0x0F,0x12 */ tempah=((tempbx&0xFF00)<<3)>>8; tempah=tempah|((tempcx&0xFF00)>>8); - SetReg1(Part1Port,0x12,tempah); - - tempbx=(VGAVT+VGAVDE)>>1; //BTVGA2VRS 0x10,0x11 - tempcx=((VGAVT-VGAVDE)>>4)+tempbx+1; //BTVGA2VRE 0x11 - if(VBInfo&SetCRT2ToRAMDAC){ - tempbx=*((UCHAR *)(ROMAddr+REFIndex+8)); //di+8 - temp1=*((UCHAR *)(ROMAddr+REFIndex+7)); //di+7 - if(temp1&0x04){ + SiSSetReg1(Part1Port,0x12,tempah); + + tempbx=(SiSVGAVT+SiSVGAVDE)>>1; /* BTVGA2VRS 0x10,0x11 */ + tempcx=((SiSVGAVT-SiSVGAVDE)>>4)+tempbx+1; /* BTVGA2VRE 0x11 */ + if (SiSVBInfo&SetCRT2ToRAMDAC) { + tempbx=*((UCHAR *)(ROMAddr+SiSREFIndex+8)); /* di+8 */ + temp1=*((UCHAR *)(ROMAddr+SiSREFIndex+7)); /* di+7 */ + if (temp1&0x04) { tempbx=tempbx|0x0100; } - if(temp1&0x080){ + if (temp1&0x080) { tempbx=tempbx|0x0200; } - temp1=*((UCHAR *)(ROMAddr+REFIndex+13)); //di+13 - if(temp1&0x08){ + temp1=*((UCHAR *)(ROMAddr+SiSREFIndex+13)); /* di+13 */ + if (temp1&0x08) { tempbx=tempbx|0x0400; } - tempcl= *((UCHAR *)(ROMAddr+REFIndex+9)); //di+9 + tempcl= *((UCHAR *)(ROMAddr+SiSREFIndex+9)); /* di+9 */ tempcx=(tempcx&0xFF00)|(tempcl&0x00FF); } tempah=tempbx&0x0FF; - SetReg1(Part1Port,0x10,tempah); + SiSSetReg1(Part1Port,0x10,tempah); tempbh=(tempbx&0xFF00)>>8; tempah=((tempbh<<4)&0x0FF)|(tempcx&0x0F); - SetReg1(Part1Port,0x11,tempah); + SiSSetReg1(Part1Port,0x11,tempah); - if(HwDeviceExtension->jChipID == SIS_Glamour) - { + if (HwDeviceExtension->jChipID == SIS_Glamour) { tempah=0x10; - if((LCDResInfo!=Panel1024x768)&&(LCDResInfo==Panel1280x1024)){ - tempah=0x20; - } - }else{ - tempah=0x20; + if ((SiSLCDResInfo!=Panel1024x768)&&(SiSLCDResInfo==Panel1280x1024)) tempah=0x20; } - if(VBInfo&SetCRT2ToTV){ - tempah=0x08; + else + tempah=0x20; + if (SiSVBInfo&SetCRT2ToTV) tempah=0x08; + if (SIS_IF_DEF_HiVision==1) { + if (SiSVBInfo&SetInSlaveMode) tempah=0x2c; + else tempah=0x20; } - - SetRegANDOR(Part1Port,0x13,~0x03C,tempah); + SiSSetRegANDOR(Part1Port,0x13,~0x03C,tempah); - if(!(VBInfo&SetInSlaveMode)){ - REFIndex=OldREFIndex; + if (!(SiSVBInfo&SetInSlaveMode)) { + SiSREFIndex=OldREFIndex; return; } - if(VBInfo&SetCRT2ToTV){ - tempax=0xFFFF; - }else{ - tempax=GetVGAHT2(); - } - tempcl=0x08; //Reg 0x03 Horozontal Total - temp1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - if(!(temp1&Charx8Dot)){ //temp1->St_ModeFlag + if (SiSVBInfo&SetCRT2ToTV) { + tempax=0xFFFF; + } else { + tempax=SiSGetVGAHT2(); + } + tempcl=0x08; /* Reg 0x03 Horozontal Total */ + temp1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); /* si+St_ModeFlag */ + if (!(temp1&Charx8Dot)) { /* temp1->St_ModeFlag */ tempcl=0x09; } - if(tempax>=VGAHT){ - tempax=VGAHT; + if (tempax>=SiSVGAHT) { + tempax=SiSVGAHT; } - if(temp1&HalfDCLK){ + if (temp1&HalfDCLK) { tempax=tempax>>1; } tempax=(tempax/tempcl)-5; tempbl=tempax; - tempah=0xFF; //set MAX HT - SetReg1(Part1Port,0x03,tempah); + tempah=0xFF; /* set MAX SiSHT */ + SiSSetReg1(Part1Port,0x03,tempah); - tempax=VGAHDE; //0x04 Horizontal Display End - if(temp1&HalfDCLK){ + tempax=SiSVGAHDE; /* 0x04 Horizontal Display End */ + if (temp1&HalfDCLK) { tempax=tempax>>1; } tempax=(tempax/tempcl)-1; tempbh=tempax; - SetReg1(Part1Port,0x04,tempax); - + SiSSetReg1(Part1Port,0x04,tempax); + tempah=tempbh; - if(VBInfo&SetCRT2ToTV){ + if (SiSVBInfo&SetCRT2ToTV) { tempah=tempah+2; } - SetReg1(Part1Port,0x05,tempah); //0x05 Horizontal Display Start - SetReg1(Part1Port,0x06,0x03); //0x06 Horizontal Blank end - //0x07 horizontal Retrace Start - tempcx=(tempbl+tempbh)>>1; - tempah=(tempcx&0xFF)+2; - - if(VBInfo&SetCRT2ToTV){ - tempah=tempah-1; - if(!(temp1&HalfDCLK)){ - if((temp1&Charx8Dot)){ - tempah=tempah+4; - if(VGAHDE>=800){ - tempah=tempah-6; - } + if (SIS_IF_DEF_HiVision==1) { + resinfo=*(USHORT *)(ROMAddr+SiSModeIDOffset+0x09); /* si+Ext_ResInfo */ + if (resinfo==7) tempah=tempah-2; + } + SiSSetReg1(Part1Port,0x05,tempah); /* 0x05 Horizontal Display Start */ + SiSSetReg1(Part1Port,0x06,0x03); /* 0x06 Horizontal Blank end */ + /* 0x07 horizontal Retrace Start */ + if (SIS_IF_DEF_HiVision==1) { + tempah=tempbl-1; + modeflag=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); /* si+St_ModeFlag */ + if (!(modeflag&HalfDCLK)) { + tempah=tempah-6; + if (SiSSetFlag&TVSimuMode) { + tempah=tempah-4; + if (ModeNo>0x13) tempah=tempah-10; } } - }else{ - if(!(temp1&HalfDCLK)){ - tempah=tempah-4; - if(VGAHDE>=800){ - tempah=tempah-7; - if(ModeType==ModeEGA){ - if(VGAVDE==1024){ - tempah=tempah+15; - if(LCDResInfo!=Panel1280x1024){ - tempah=tempah+7; - } - } + } + else { + tempcx=(tempbl+tempbh)>>1; + tempah=(tempcx&0xFF)+2; + + if (SiSVBInfo&SetCRT2ToTV) { + tempah=tempah-1; + if (!(temp1&HalfDCLK)) { + if ((temp1&Charx8Dot)) { + tempah=tempah+4; + if (SiSVGAHDE>=800) { + tempah=tempah-6; + } } - if(VGAHDE>=1280){ - tempah=tempah+28; + } + } else { + if (!(temp1&HalfDCLK)) { + tempah=tempah-4; + if (SiSVGAHDE>=800) { + tempah=tempah-7; + if (SiSModeType==ModeEGA) { + if (SiSVGAVDE==1024) { + tempah=tempah+15; + if (SiSLCDResInfo!=Panel1280x1024) { + tempah=tempah+7; + } + } + } + if (SiSVGAHDE>=1280) { + tempah=tempah+28; + } } } } } - - SetReg1(Part1Port,0x07,tempah);//0x07 Horizontal Retrace Start - - SetReg1(Part1Port,0x08,0); //0x08 Horizontal Retrace End - SetReg1(Part1Port,0x18,0x03); //0x18 SR08 - SetReg1(Part1Port,0x19,0); //0x19 SR0C - SetReg1(Part1Port,0x09,0xFF); //0x09 Set Max VT - + SiSSetReg1(Part1Port,0x07,tempah); /* 0x07 Horizontal Retrace Start */ + + SiSSetReg1(Part1Port,0x08,0); /* 0x08 Horizontal Retrace End */ + SiSSetReg1(Part1Port,0x18,0x03); /* 0x18 SR08 */ + SiSSetReg1(Part1Port,0x19,0); /* 0x19 SR0C */ + SiSSetReg1(Part1Port,0x09,0xFF); /* 0x09 Set Max SiSVT */ + tempcx=0x121; tempcl=0x21; tempch=0x01; - tempbx=VGAVDE; //0x0E Virtical Display End - if(tempbx==360) tempbx=350; - if(tempbx==375) tempbx=350; - if(tempbx==405) tempbx=400; + tempbx=SiSVGAVDE; /* 0x0E Virtical Display End */ + if (tempbx==360) tempbx=350; + if (tempbx==375) tempbx=350; + if (tempbx==405) tempbx=400; tempbx--; tempah=tempbx&0x0FF; - SetReg1(Part1Port,0x0E,tempah); - SetReg1(Part1Port,0x10,tempah);//0x10 vertical Blank Start + SiSSetReg1(Part1Port,0x0E,tempah); + SiSSetReg1(Part1Port,0x10,tempah); /* 0x10 vertical Blank Start */ tempbh=(tempbx&0xFF00)>>8; - if(tempbh&0x01){ + if (tempbh&0x01) { tempcl=tempcl|0x0A; } tempah=0;tempal=0x0B; - if(temp1&DoubleScanMode){ + if (temp1&DoubleScanMode) { tempah=tempah|0x080; } - if(tempbh&0x02){ + if (tempbh&0x02) { tempcl=tempcl|0x040; tempah=tempah|0x020; } - SetReg1(Part1Port,0x0B,tempah); - if(tempbh&0x04){ - tempch=tempch|0x06; + SiSSetReg1(Part1Port,0x0B,tempah); + if (tempbh&0x04) { + tempch=tempch|0x06; } - SetReg1(Part1Port,0x11,0); //0x11 Vertival Blank End - - tempax=VGAVT-tempbx; //0x0C Vertical Retrace Start + SiSSetReg1(Part1Port,0x11,0); /* 0x11 Vertival Blank End */ + + tempax=SiSVGAVT-tempbx; /* 0x0C Vertical Retrace Start */ tempax=tempax>>2; - temp2=tempax; //push ax + temp2=tempax; /* push ax */ tempax=tempax<<1; tempbx=tempax+tempbx; - if((SetFlag&TVSimuMode)&&(VBInfo&SetPALTV)&&(VGAHDE==800)){ + if ((SiSSetFlag&TVSimuMode)&&(SiSVBInfo&SetPALTV)&&(SiSVGAHDE==800)) { tempbx=tempbx+40; } tempah=(tempbx&0x0FF); - SetReg1(Part1Port,0x0C,tempah); + SiSSetReg1(Part1Port,0x0C,tempah); tempbh=(tempbx&0xFF00)>>8; - if(tempbh&0x01){ + if (tempbh&0x01) { tempcl=tempcl|0x04; } - if(tempbh&0x02){ + if (tempbh&0x02) { tempcl=tempcl|0x080; } - if(tempbh&0x04){ + if (tempbh&0x04) { tempch=tempch|0x08; } - tempax=temp2; //pop ax + tempax=temp2; /* pop ax */ tempax=(tempax>>2)+1; tempbx=tempbx+tempax; tempah=(tempbx&0x0FF)&0x0F; - SetReg1(Part1Port,0x0D,tempah); //0x0D vertical Retrace End + SiSSetReg1(Part1Port,0x0D,tempah); /* 0x0D vertical Retrace End */ tempbl=tempbx&0x0FF; - if(tempbl&0x10){ + if (tempbl&0x10) { tempch=tempch|0x020; } - + tempah=tempcl; - SetReg1(Part1Port,0x0A,tempah); //0x0A CR07 + SiSSetReg1(Part1Port,0x0A,tempah); /* 0x0A CR07 */ tempah=tempch; - SetReg1(Part1Port,0x17,tempah); //0x17 SR0A - tempax=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag + SiSSetReg1(Part1Port,0x17,tempah); /* 0x17 SR0A */ + tempax=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); /* si+St_ModeFlag */ tempah=(tempax&0xFF00)>>8; tempah=(tempah>>1)&0x09; - SetReg1(Part1Port,0x16,tempah); //0x16 SR01 - SetReg1(Part1Port,0x0F,0); //0x0F CR14 - SetReg1(Part1Port,0x12,0); //0x12 CR17 - SetReg1(Part1Port,0x1A,0); //0x1A SR0E + SiSSetReg1(Part1Port,0x16,tempah); /* 0x16 SR01 */ + SiSSetReg1(Part1Port,0x0F,0); /* 0x0F CR14 */ + SiSSetReg1(Part1Port,0x12,0); /* 0x12 CR17 */ + SiSSetReg1(Part1Port,0x1A,0); /* 0x1A SR0E */ - REFIndex=OldREFIndex; //pop di + SiSREFIndex=OldREFIndex; /* pop di */ } -VOID SetCRT2Offset(USHORT Part1Port,ULONG ROMAddr) +VOID SiSSetCRT2Offset(USHORT Part1Port,ULONG ROMAddr) { USHORT offset; - if(VBInfo&SetInSlaveMode){ - return; + if (SiSVBInfo&SetInSlaveMode) { + return; } - offset=GetOffset(ROMAddr); - SetReg1(Part1Port,0x07,(USHORT)(offset&0xFF)); - SetReg1(Part1Port,0x09,(USHORT)((offset&0xFF00)>>8)); - SetReg1(Part1Port,0x03,(USHORT)(((offset>>3)&0xFF)+1)); + offset=SiSGetOffset(ROMAddr); + SiSSetReg1(Part1Port,0x07,(USHORT)(offset&0xFF)); + SiSSetReg1(Part1Port,0x09,(USHORT)((offset&0xFF00)>>8)); + SiSSetReg1(Part1Port,0x03,(USHORT)(((offset>>3)&0xFF)+1)); } -USHORT GetOffset(ULONG ROMAddr) +USHORT SiSGetOffset(ULONG ROMAddr) { USHORT tempal,temp1,colordepth; - tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x03)); // si+Ext_ModeInfo + tempal=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x03)); /* si+Ext_ModeInfo */ tempal=(tempal>>4)&0xFF; - ScreenOffset=*((USHORT *)(ROMAddr+0x206)); // Get ScreeOffset table - tempal=*((UCHAR *)(ROMAddr+ScreenOffset+tempal)); // get ScreenOffset + SiSScreenOffset=*((USHORT *)(ROMAddr+0x206)); /* Get ScreeOffset table */ + tempal=*((UCHAR *)(ROMAddr+SiSScreenOffset+tempal)); /* get SiSScreenOffset */ tempal=tempal&0xFF; - temp1=*((UCHAR *)(ROMAddr+REFIndex)); //di+Ext_InfoFlag - if(temp1&InterlaceMode){ + temp1=*((UCHAR *)(ROMAddr+SiSREFIndex)); /* di+Ext_InfoFlag */ + if (temp1&InterlaceMode) { tempal=tempal<<1; } - colordepth=GetColorDepth(ROMAddr); - return(tempal*colordepth); + colordepth=SiSGetColorDepth(ROMAddr); + return(tempal*colordepth); } -USHORT GetColorDepth(ULONG ROMAddr) +USHORT SiSGetColorDepth(ULONG ROMAddr) { USHORT ColorDepth[6]={1,2,4,4,6,8}; USHORT temp; int temp1; - temp=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag + temp=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); /* si+St_ModeFlag */ temp1=(temp&ModeInfoFlag)-ModeEGA; - if(temp1<0) temp1=0; + if (temp1<0) temp1=0; return(ColorDepth[temp1]); } -VOID SetCRT2FIFO(USHORT Part1Port,ULONG ROMAddr,USHORT ModeNo, +VOID SiSSetCRT2FIFO(USHORT Part1Port,ULONG ROMAddr,USHORT ModeNo, PHW_DEVICE_EXTENSION HwDeviceExtension) { USHORT temp,temp1,temp2,temp3,flag; @@ -1218,193 +1336,210 @@ USHORT oldREFIndex,CRT1ModeNo,oldModeIDOffset; long int longtemp; - USHORT LatencyFactor[48]={ 88, 80, 78, 72, 70, 00, // 64 bit BQ=2 - 00, 79, 77, 71, 69, 49, // 64 bit BQ=1 - 88, 80, 78, 72, 70, 00, // 128 bit BQ=2 - 00, 72, 70, 64, 62, 44, // 128 bit BQ=1 - 73, 65, 63, 57, 55, 00, // 64 bit BQ=2 - 00, 64, 62, 56, 54, 34, // 64 bit BQ=1 - 78, 70, 68, 62, 60, 00, // 128 bit BQ=2 - 00, 62, 60, 54, 52, 34}; // 128 bit BQ=1 - - oldREFIndex=(USHORT)REFIndex; //push REFIndex(CRT2 now) - oldModeIDOffset=(USHORT)ModeIDOffset; //push ModeIDOffset - - CRT1ModeNo=(UCHAR)GetReg1(P3d4,0x34); //get CRT1 ModeNo - SearchModeID(ROMAddr,CRT1ModeNo); //Get ModeID Table - - GetRatePtr(ROMAddr,CRT1ModeNo); //Set REFIndex-> for crt1 refreshrate - temp1=GetVCLK(ROMAddr,CRT1ModeNo,HwDeviceExtension); - temp2=GetColorTh(ROMAddr); - temp3=GetMCLK(ROMAddr); - temp=((USHORT)(temp1*temp2)/temp3); //temp->bx - temp1=(UCHAR)GetReg1(P3c4,0x14); //SR_14 + USHORT LatencyFactor[48]={ 97, 88, 86, 79, 77, 00, /* 64 bit BQ=2 */ + 00, 87, 85, 78, 76, 54, /* 64 bit BQ=1 */ + 97, 88, 86, 79, 77, 00, /* 128 bit BQ=2 */ + 00, 79, 77, 70, 68, 48, /* 128 bit BQ=1 */ + 80, 72, 69, 63, 61, 00, /* 64 bit BQ=2 */ + 00, 70, 68, 61, 59, 37, /* 64 bit BQ=1 */ + 86, 77, 75, 68, 66, 00, /* 128 bit BQ=2 */ + 00, 68, 66, 59, 57, 37}; /* 128 bit BQ=1 */ + + oldREFIndex=SiSREFIndex; /* push SiSREFIndex(CRT2 now) */ + oldModeIDOffset=SiSModeIDOffset; /* push SiSModeIDOffset */ + + CRT1ModeNo=(UCHAR)SiSGetReg1(SiSP3d4,0x34); /* get CRT1 ModeNo */ + SiSSearchModeID(ROMAddr,CRT1ModeNo); /* Get ModeID Table */ + + SiSGetRatePtr(ROMAddr,CRT1ModeNo); /* Set SiSREFIndex-> for crt1 refreshrate */ + temp1=SiSGetVCLK(ROMAddr,CRT1ModeNo,HwDeviceExtension); + temp2=SiSGetColorTh(ROMAddr); + temp3=SiSGetMCLK(ROMAddr); + temp=((USHORT)(temp1*temp2)/temp3); /* temp->bx */ + temp1=(UCHAR)SiSGetReg1(SiSP3c4,0x14); /* SR_14 */ temp1=temp1>>6; temp1=temp1<<1; - if(temp1==0) temp1=1; - temp1=temp1<<2; //temp1->ax + if (temp1==0) temp1=1; + temp1=temp1<<2; /* temp1->ax */ longtemp=temp1-temp; - - temp2=(USHORT)((28*16)/(int)longtemp); //temp2->cx - if(!((temp2*(int)longtemp)==(28*16))) temp2++; - if( HwDeviceExtension->jChipID == SIS_Glamour ){ - temp1=CalcDelay(); - }else{ //for Trojan and Spartan - flag=(UCHAR)GetReg1(P3c4,0x14); //SR_14 - if(flag&0x80){ - latencyindex=12; //128 bit - }else{ - latencyindex=0; //64 bit - } - flag=GetQueueConfig(); - if(!(flag&0x01)){ - latencyindex+=24; //GUI timing =0 + temp2=(USHORT)((28*16)/(int)longtemp); /* temp2->cx */ + if (!((temp2*(int)longtemp)==(28*16))) temp2++; + + if ( HwDeviceExtension->jChipID == SIS_Glamour ) { + temp1=SiSCalcDelayVB(); + } else { /* for Trojan and Spartan */ + flag=(UCHAR)SiSGetReg1(SiSP3c4,0x14); /* SR_14 */ + if (flag&0x80) { + latencyindex=12; /* 128 bit */ + } else { + latencyindex=0; /* 64 bit */ + } + flag=SiSGetQueueConfig(); + if (!(flag&0x01)) { + latencyindex+=24; /* GUI timing =0 */ } - if(flag&0x10){ - latencyindex+=6; //BQ =2 + if (flag&0x10) { + latencyindex+=6; /* BQ =2 */ } latencyindex=latencyindex + (flag>>5); temp1= LatencyFactor[latencyindex]; temp1=temp1+15; - flag=(UCHAR)GetReg1(P3c4,0x14); //SR_14 - if(!(flag&0x80)){ - temp1=temp1+5; //64 bit + flag=(UCHAR)SiSGetReg1(SiSP3c4,0x14); /* SR_14 */ + if (!(flag&0x80)) { + temp1=temp1+5; /* 64 bit */ } - } - + } + temp2=temp2+temp1; - REFIndex=oldREFIndex; //pop REFIndex(CRT2) - ModeIDOffset=oldModeIDOffset; //pop ModeIDOffset - - vclk2ptr=GetVCLK2Ptr(ROMAddr,ModeNo); - temp1=*((USHORT *)(ROMAddr+vclk2ptr+(VCLKLen-2))); - temp3=GetColorTh(ROMAddr); + SiSREFIndex=oldREFIndex; /* pop SiSREFIndex(CRT2) */ + SiSModeIDOffset=oldModeIDOffset; /* pop SiSModeIDOffset */ + + vclk2ptr=SiSGetVCLK2Ptr(ROMAddr,ModeNo); + temp1=*((USHORT *)(ROMAddr+vclk2ptr+(SiSVCLKLen-2))); + temp3=SiSGetColorTh(ROMAddr); longtemp=temp1*temp2*temp3; - temp3=GetMCLK(ROMAddr); + temp3=SiSGetMCLK(ROMAddr); temp3=temp3<<4; temp2=(int)(longtemp/temp3); - if((long int)temp2*(long int)temp3<(long int)longtemp) temp2++; //temp2->cx - - temp1=(UCHAR)GetReg1(Part1Port,0x01); //part1port index 01 + if ((long int)temp2*(long int)temp3<(long int)longtemp) + temp2++; /* temp2->cx */ + temp1=(UCHAR)SiSGetReg1(Part1Port,0x01); /* part1port index 01 */ - if( (HwDeviceExtension->jChipID == SIS_Trojan ) && - ((HwDeviceExtension->revision_id & 0xf0) == 0x30) ) /* 630s */ - { - temp1=(temp1&(~0x1F))|0x19; - }else - { + if ( HwDeviceExtension->uRevisionID >= 0x30 ) /* 630s */ + temp1=(temp1&(~0x1F))|0x1b; + else temp1=(temp1&(~0x1F))|0x16; + + SiSSetReg1(Part1Port,0x01,temp1); + + if (SIS_IF_DEF_HiVision==1) { + if (temp2<=10) temp2=10; } - SetReg1(Part1Port,0x01,temp1); + else { + if (temp2<=6) temp2=6; + } + + if ( HwDeviceExtension->uRevisionID >= 0x30 ) + temp2=0x13; + else + temp2=0x14; - if(temp2<=6) temp2=6; - if(temp2>0x14) temp2=0x14; - temp1=(UCHAR)GetReg1(Part1Port,0x02); //part1port index 02 + if (temp2>0x14) temp2=0x14; + temp1=(UCHAR)SiSGetReg1(Part1Port,0x02); /* part1port index 02 */ temp1=(temp1&(~0x1F))|temp2; - SetReg1(Part1Port,0x02,temp1); + SiSSetReg1(Part1Port,0x02,temp1); } -USHORT GetVCLK(ULONG ROMAddr,USHORT ModeNo, +USHORT SiSGetVCLK(ULONG ROMAddr,USHORT ModeNo, PHW_DEVICE_EXTENSION HwDeviceExtension) { USHORT tempptr; - USHORT temp1; - tempptr=GetVCLKPtr(ROMAddr,ModeNo); - temp1=*((USHORT *)(ROMAddr+tempptr+(VCLKLen-2))); - + USHORT temp1; + tempptr=SiSGetVCLKPtr(ROMAddr,ModeNo); + temp1=*((USHORT *)(ROMAddr+tempptr+(SiSVCLKLen-2))); return temp1; } -USHORT GetQueueConfig(void) +USHORT SiSGetQueueConfig() { USHORT tempal,tempbl; ULONG tempeax; - - SetReg4(0xcf8,0x80000050); - tempeax=GetReg3(0xcfc); + + SiSSetReg4(0xcf8,0x80000050); + tempeax=SiSGetReg3(0xcfc); tempeax=(tempeax>>24)&0x0f; tempbl=(USHORT)tempeax; tempbl=tempbl<<4; - - SetReg4(0xcf8,0x800000A0); - tempeax=GetReg3(0xcfc); + + SiSSetReg4(0xcf8,0x800000A0); + tempeax=SiSGetReg3(0xcfc); tempeax=(tempeax>>24)&0x0f; tempal=(USHORT)tempeax; tempbl=tempbl|tempal; - + return(tempbl); } -USHORT GetVCLKPtr(ULONG ROMAddr,USHORT ModeNo) +USHORT SiSGetVCLKPtr(ULONG ROMAddr,USHORT ModeNo) { - USHORT tempal; - tempal=(UCHAR)GetReg2((USHORT)(P3ca+0x02)); // Port 3cch - tempal=((tempal>>2)&0x03); - if(ModeNo>0x13){ - tempal=*((UCHAR *)(ROMAddr+REFIndex+0x03)); //di+Ext_CRTVCLK - tempal=tempal&0x03F; + USHORT tempal=0; + if (SIS_IF_DEF_LVDS==0) { + tempal=(UCHAR)SiSGetReg2((USHORT)(SiSP3ca+0x02)); /* Port 3cch */ + tempal=((tempal>>2)&0x03); + if (ModeNo>0x13) { + tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+0x03)); /* di+Ext_CRTVCLK */ + } + SiSVCLKLen=SiSGetVCLKLen(ROMAddr); + tempal=tempal*SiSVCLKLen; + tempal=tempal+(*((USHORT *)(ROMAddr+0x208))); /* SiSVCLKData */ + return ((USHORT)tempal); + } else { + if (SiSLCDResInfo==Panel800x600) { + tempal=VCLK40; + } else if (SiSLCDResInfo==Panel1024x768) { + tempal=VCLK65; + } + SiSVCLKLen=SiSGetVCLKLen(ROMAddr); + tempal=tempal*SiSVCLKLen; + tempal=tempal+(*((USHORT *)(ROMAddr+0x208))); + return((USHORT)tempal); } - VCLKLen=GetVCLKLen(ROMAddr); - tempal=tempal*VCLKLen; - tempal=tempal+(*((USHORT *)(ROMAddr+0x208))); // VCLKData - return ((USHORT)tempal); } -USHORT GetColorTh(ULONG ROMAddr) +USHORT SiSGetColorTh(ULONG ROMAddr) { USHORT temp; - temp=GetColorDepth(ROMAddr); + temp=SiSGetColorDepth(ROMAddr); temp=temp>>1; - if(temp==0) temp++; + if (temp==0) temp++; return temp; } -USHORT GetMCLK(ULONG ROMAddr) +USHORT SiSGetMCLK(ULONG ROMAddr) { USHORT tempmclkptr; USHORT tempmclk; - tempmclkptr=GetMCLKPtr(ROMAddr); - tempmclk=*((USHORT *)(ROMAddr+tempmclkptr+0x03)); //di+3 + tempmclkptr=SiSGetMCLKPtr(ROMAddr); + tempmclk=*((USHORT *)(ROMAddr+tempmclkptr+0x03)); /* di+3 */ return tempmclk; } -USHORT GetMCLKPtr(ULONG ROMAddr) +USHORT SiSGetMCLKPtr(ULONG ROMAddr) { USHORT tempdi; USHORT tempdramtype,tempax; - tempdi=*((USHORT *)(ROMAddr+0x20C)); // MCLKData - tempdramtype=GetDRAMType(ROMAddr); + tempdi=*((USHORT *)(ROMAddr+0x20C)); /* SiSMCLKData */ + tempdramtype=SiSGetDRAMType(ROMAddr); tempax=5*tempdramtype; tempdi=tempdi+tempax; - return (tempdi); + return (tempdi); } -USHORT GetDRAMType(ULONG ROMAddr) +USHORT SiSGetDRAMType(ULONG ROMAddr) { USHORT tsoftsetting,temp3; - tsoftsetting=*((UCHAR *)(ROMAddr+0x52)); - if(!(tsoftsetting&SoftDramType)){ - temp3=(UCHAR)GetReg1(P3c4,0x3A); - tsoftsetting=temp3; + if (!(tsoftsetting&SoftDramType)) { + temp3=(UCHAR)SiSGetReg1(SiSP3c4,0x3A); + tsoftsetting=temp3; } tsoftsetting=tsoftsetting&0x07; return(tsoftsetting); } -static USHORT CalcDelay() +USHORT SiSCalcDelayVB() { USHORT tempal,tempah,temp1,tempbx; USHORT ThTiming[8]={1,2,2,3,0,1,1,2}; USHORT ThLowB[24]={81,4,72,6,88,8,120,12, - 55,4,54,6,66,8,90,12, - 42,4,45,6,55,8,75,12}; + 55,4,54,6,66,8,90,12, + 42,4,45,6,55,8,75,12}; - tempah=(UCHAR)GetReg1(P3c4,0x18); //SR_18 + tempah=(UCHAR)SiSGetReg1(SiSP3c4,0x18); /* SR_18 */ tempah=tempah&0x62; tempah=tempah>>1; tempal=tempah; @@ -1412,141 +1547,173 @@ tempal=tempal|tempah; tempal=tempal&0x07; - temp1=ThTiming[tempal]; //temp1->cl + temp1=ThTiming[tempal]; /* temp1->cl */ - tempbx=(UCHAR)GetReg1(P3c4,0x16); //SR_16 + tempbx=(UCHAR)SiSGetReg1(SiSP3c4,0x16); /* SR_16 */ tempbx=tempbx>>6; - tempah=(UCHAR)GetReg1(P3c4,0x14); //SR_14 + tempah=(UCHAR)SiSGetReg1(SiSP3c4,0x14); /* SR_14 */ tempah=((tempah>>4)&0x0C); tempbx=((tempbx|tempah)<<1); - + tempal=ThLowB[tempbx+1]*temp1; tempbx=ThLowB[tempbx]; tempbx=tempal+tempbx; - return(tempbx); + return(tempbx); } -USHORT GetVCLK2Ptr(ULONG ROMAddr,USHORT ModeNo) +USHORT SiSGetVCLK2Ptr(ULONG ROMAddr,USHORT ModeNo) { - USHORT tempal; + USHORT tempal,tempbx,temp; USHORT LCDXlat1VCLK[4]={VCLK65,VCLK65,VCLK65,VCLK65}; USHORT LCDXlat2VCLK[4]={VCLK108_2,VCLK108_2,VCLK108_2,VCLK108_2}; - - if(ModeNo<=0x13){ - tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x04)); // si+St_CRT2CRTC - }else{ - tempal=*((UCHAR *)(ROMAddr+REFIndex+0x04)); // di+Ext_CRT2CRTC - } - tempal=tempal>>6; - if(LCDResInfo!=Panel1024x768){ - tempal=LCDXlat2VCLK[tempal]; - }else{ - tempal=LCDXlat1VCLK[tempal]; - } - - if(VBInfo&SetCRT2ToLCD){ - tempal=tempal; - }else if(VBInfo&SetCRT2ToTV){ - if(SetFlag&RPLLDIV2XO){ - tempal=TVVCLKDIV2; - }else{ - tempal=TVVCLK; + USHORT LVDSXlat1VCLK[4]={VCLK40,VCLK40,VCLK40,VCLK40}; + USHORT LVDSXlat2VCLK[4]={VCLK65,VCLK65,VCLK65,VCLK65}; + USHORT LVDSXlat3VCLK[4]={VCLK65,VCLK65,VCLK65,VCLK65}; + + if (SIS_IF_DEF_LVDS==0) { + if (ModeNo<=0x13) { + tempal=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x04)); /* si+St_CRT2CRTC */ + } else { + tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+0x04)); /* di+Ext_CRT2CRTC */ + } + tempal=tempal>>6; + if (SiSLCDResInfo!=Panel1024x768) { + tempal=LCDXlat2VCLK[tempal]; + } else { + tempal=LCDXlat1VCLK[tempal]; + } + + if (SiSVBInfo&SetCRT2ToLCD) { + tempal=tempal; + } else { /* for TV */ + if (SiSVBInfo&SetCRT2ToTV) { + if (SIS_IF_DEF_HiVision==1) { + if (SiSSetFlag&RPLLDIV2XO) tempal=HiTVVCLKDIV2; + else tempal=HiTVVCLK; + if (SiSSetFlag&TVSimuMode) { + temp=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); /* si+St_ModeFlag */ + if (temp&Charx8Dot) tempal=HiTVSimuVCLK; + else tempal=HiTVTextVCLK; + } + } else { + if (SiSVBInfo&SetCRT2ToTV) { + if (SiSSetFlag&RPLLDIV2XO) tempal=TVVCLKDIV2; + else tempal=TVVCLK; + } else { + tempal=(UCHAR)SiSGetReg2((USHORT)(SiSP3ca+0x02)); /* Port 3cch */ + tempal=((tempal>>2)&0x03); + if (ModeNo>0x13) tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+0x03)); /* di+Ext_CRTVCLK */ + } + } + } } - }else{ - tempal=(UCHAR)GetReg2((USHORT)(P3ca+0x02)); // Port 3cch - tempal=((tempal>>2)&0x03); - if(ModeNo>0x13){ - tempal=*((UCHAR *)(ROMAddr+REFIndex+0x03)); //di+Ext_CRTVCLK - tempal=tempal&0x03F; - } - } - VCLKLen=GetVCLKLen(ROMAddr); - tempal=tempal*VCLKLen; - tempal=tempal+(*((USHORT *)(ROMAddr+0x208))); // VCLKData + } else { /* LVDS */ + if (ModeNo<=0x13) tempal=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x04)); + else tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+0x04)); + if (SIS_IF_DEF_CH7005==1) { + if (!(SiSVBInfo&SetCRT2ToLCD)) { + tempal=tempal&0x1f; + tempbx=0; + if (SiSVBInfo&SetPALTV) tempbx=tempbx+2; + if (SiSVBInfo&SetCHTVOverScan) tempbx=tempbx+1; + tempbx=tempbx<<1; + temp=(*((USHORT *)(ROMAddr+ADR_CHTVVCLKPtr))); + tempbx=(*((USHORT *)(ROMAddr+temp+tempbx))); + tempal=(*((USHORT *)(ROMAddr+tempbx+tempal))); + tempal=tempal&0x00FF; + } + } else { + tempal=tempal>>6; + if (SiSLCDResInfo==Panel800x600) tempal=LVDSXlat1VCLK[tempal]; + else if (SiSLCDResInfo==Panel1024x768) tempal=LVDSXlat2VCLK[tempal]; + else tempal=LVDSXlat3VCLK[tempal]; + } + } + SiSVCLKLen=SiSGetVCLKLen(ROMAddr); + tempal=tempal*SiSVCLKLen; + tempal=tempal+(*((USHORT *)(ROMAddr+0x208))); /* SiSVCLKData */ return ((USHORT)tempal); } -USHORT GetVCLKLen(ULONG ROMAddr) +USHORT SiSGetVCLKLen(ULONG ROMAddr) { USHORT VCLKDataStart,vclklabel,temp; VCLKDataStart=*((USHORT *)(ROMAddr+0x208)); - for(temp=0;;temp++){ + for(temp=0;;temp++) { vclklabel=*((USHORT *)(ROMAddr+VCLKDataStart+temp)); - if(vclklabel==VCLKStartFreq){ + if (vclklabel==VCLKStartFreq) { temp=temp+2; - return(temp); + return(temp); } } return(0); } -VOID SetCRT2Sync(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo) +VOID SiSSetCRT2Sync(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo) { USHORT temp1,tempah=0; - USHORT temp; - USHORT Part1Port; + USHORT temp; + USHORT Part1Port; Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - if(IF_DEF_LVDS==1){ //LVDS - if(VBInfo&SetCRT2ToLCD){ - tempah=LCDInfo; - if(!(tempah&LCDSync)){ - temp=*((USHORT *)(ROMAddr+REFIndex)); //di+Ext_InfoFlag + if (SIS_IF_DEF_LVDS==1) { + if (SiSVBInfo&SetCRT2ToLCD) { + tempah=SiSLCDInfo; + if (!(tempah&LCDSync)) { + temp=*((USHORT *)(ROMAddr+SiSREFIndex)); /*di+Ext_InfoFlag */ tempah=(temp>>8)&0x0C0; - }else{ + } else { tempah=tempah&0x0C0; } } - }else{ - temp=*((USHORT *)(ROMAddr+REFIndex)); //di+Ext_InfoFlag + } else { + temp=*((USHORT *)(ROMAddr+SiSREFIndex)); /* di+Ext_InfoFlag */ tempah=(temp>>8)&0x0C0; } - temp1=(UCHAR)GetReg1(Part1Port,0x19); //part1port index 02 + temp1=(UCHAR)SiSGetReg1(Part1Port,0x19); /* part1port index 02 */ temp1=(temp1&(~0x0C0))|tempah; - SetReg1(Part1Port,0x19,temp1); + SiSSetReg1(Part1Port,0x19,temp1); } -VOID GetCRT1Ptr(ULONG ROMAddr) +VOID SiSGetCRT1Ptr(ULONG ROMAddr) { USHORT temprefcrt1; USHORT temp; - temp=*((UCHAR *)(ROMAddr+REFIndex+0x02)); //di+Ext_CRT1CRTC - temp=temp&0x03F; + temp=*((UCHAR *)(ROMAddr+SiSREFIndex+0x02)); /* di+Ext_CRT1CRTC */ temp=temp*CRT1Len; - temprefcrt1=*((USHORT *)(ROMAddr+0x204)); // Get CRT1Table - REFIndex=temprefcrt1+temp; // di->CRT1Table+Ext_CRT1CRTC*CRT1Len + temprefcrt1=*((USHORT *)(ROMAddr+0x204)); /* Get SiSCRT1Table */ + SiSREFIndex=temprefcrt1+temp; /* di->SiSCRT1Table+Ext_CRT1CRTC*CRT1Len */ } -USHORT GetVGAHT2() +USHORT SiSGetVGAHT2() { long int temp1,temp2; - - temp1=(VGAVT-VGAVDE)*RVBHCMAX; + temp1=(SiSVGAVT-SiSVGAVDE)*SiSRVBHCMAX; temp1=temp1&0x0FFFF; - temp2=(VT-VDE)*RVBHCFACT; + temp2=(SiSVT-SiSVDE)*SiSRVBHCFACT; temp2=temp2&0x0FFFF; - temp2=temp2*HT; + temp2=temp2*SiSHT; temp2=temp2/temp1; return((USHORT)temp2); } -VOID SetGroup2(USHORT BaseAddr,ULONG ROMAddr) +VOID SiSSetGroup2(USHORT BaseAddr,ULONG ROMAddr) { USHORT tempah,tempbl,tempbh,tempcl,i,j,tempcx,pushcx,tempbx,tempax; USHORT tempmodeflag,tempflowflag; UCHAR *temp1; USHORT *temp2; USHORT pushbx; - USHORT Part2Port; + USHORT Part2Port; + USHORT modeflag; long int longtemp; Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; - - tempcx=VBInfo; - tempah=VBInfo&0x0FF; - tempbl=VBInfo&0x0FF; - tempbh=VBInfo&0x0FF; + tempcx=SiSVBInfo; + tempah=SiSVBInfo&0x0FF; + tempbl=SiSVBInfo&0x0FF; + tempbh=SiSVBInfo&0x0FF; tempbx=(tempbl&0xFF)|(tempbh<<8); tempbl=tempbl&0x10; tempbh=(tempbh&0x04)<<1; @@ -1556,491 +1723,559 @@ tempah=tempah|tempbl; tempah=tempah^0x0C; - if(VBInfo&SetPALTV){ - temp1=(UCHAR *)(ROMAddr+0x0F1); //PALPhase - temp2=PALTiming; - }else{ - tempah=tempah|0x10; - temp1=(UCHAR *)(ROMAddr+0x0ED); //NTSCPhase - temp2=NTSCTiming; - } - - SetReg1(Part2Port,0x0,tempah); - for(i=0x31;i<=0x34;i++,temp1++){ - SetReg1(Part2Port,i,*(UCHAR *)temp1); - } - for(i=0x01,j=0;i<=0x2D;i++,j++){ - SetReg1(Part2Port,i,temp2[j]); + if (SIS_IF_DEF_HiVision==1) { + temp1=(UCHAR *)(ROMAddr+0x0F1); /* PALPhase */ + tempah=tempah^0x01; + if (SiSVBInfo&SetInSlaveMode) { + temp2=SiSHiTVSt2Timing; + if (SiSSetFlag&TVSimuMode) { + modeflag=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + if (modeflag&Charx8Dot) temp2=SiSHiTVSt1Timing; + else temp2=SiSHiTVTextTiming; + } + } + else temp2=SiSHiTVExtTiming; + } else { + if (SiSVBInfo&SetPALTV) { + temp1=(UCHAR *)(ROMAddr+0x0F1); /* PALPhase */ + temp2=SiSPALTiming; + } else { + tempah=tempah|0x10; + temp1=(UCHAR *)(ROMAddr+0x0ED); /* NTSCPhase */ + temp2=SiSNTSCTiming; + } + } + SiSSetReg1(Part2Port,0x0,tempah); + for(i=0x31;i<=0x34;i++,temp1++) { + SiSSetReg1(Part2Port,i,*(UCHAR *)temp1); + } + for(i=0x01,j=0;i<=0x2D;i++,j++) { + SiSSetReg1(Part2Port,i,temp2[j]); + } + for(i=0x39;i<=0x45;i++,j++) { + SiSSetReg1(Part2Port,i,temp2[j]); /* di->temp2[j] */ + } + + tempah=SiSGetReg1(Part2Port,0x0A); + tempah=tempah|SiSNewFlickerMode; + SiSSetReg1(Part2Port,0x0A,tempah); + + SiSSetReg1(Part2Port,0x35,SiSRY1COE); + SiSSetReg1(Part2Port,0x36,SiSRY2COE); + SiSSetReg1(Part2Port,0x37,SiSRY3COE); + SiSSetReg1(Part2Port,0x38,SiSRY4COE); + + if (SIS_IF_DEF_HiVision==1) tempax=950; + else { + if (SiSVBInfo&SetPALTV) tempax=520; + else tempax=440; + } + if (SiSVDE<=tempax) { + tempax=tempax-SiSVDE; + tempax=tempax>>2; + tempah=(tempax&0xFF00)>>8; + tempah=tempah+temp2[0]; + SiSSetReg1(Part2Port,0x01,tempah); + tempah=tempax&0x00FF; + tempah=tempah+temp2[1]; + SiSSetReg1(Part2Port,0x02,tempah); } - for(i=0x39;i<=0x45;i++,j++){ - SetReg1(Part2Port,i,temp2[j]); //di->temp2[j] - } - - tempah=GetReg1(Part2Port,0x0A); - tempah=tempah|NewFlickerMode; - SetReg1(Part2Port,0x0A,tempah); - - SetReg1(Part2Port,0x35,RY1COE); - SetReg1(Part2Port,0x36,RY2COE); - SetReg1(Part2Port,0x37,RY3COE); - SetReg1(Part2Port,0x38,RY4COE); - - tempcx=HT-1; + + tempcx=SiSHT-1; tempah=tempcx&0xFF; - SetReg1(Part2Port,0x1B,tempah); + SiSSetReg1(Part2Port,0x1B,tempah); tempah=(tempcx&0xFF00)>>8; - SetRegANDOR(Part2Port,0x1D,~0x0F,(UCHAR)tempah); - - tempcx=HT>>1; - pushcx=tempcx; - + SiSSetRegANDOR(Part2Port,0x1D,~0x0F,(UCHAR)tempah); + + tempcx=SiSHT>>1; + pushcx=tempcx; /* push cx */ + tempcx=tempcx+7; + if (SIS_IF_DEF_HiVision==1) tempcx=tempcx-4; tempah=(tempcx&0xFF); tempah=(tempah<<4)&0xFF; - SetRegANDOR(Part2Port,0x22,~0x0F0,tempah); - + SiSSetRegANDOR(Part2Port,0x22,~0x0F0,tempah); + tempbx=temp2[j]; tempbx=tempbx+tempcx; tempah=tempbx&0xFF; - SetReg1(Part2Port,0x24,tempah); + SiSSetReg1(Part2Port,0x24,tempah); tempah=(tempbx&0xFF00)>>8; tempah=(tempah<<4)&0xFF; - SetRegANDOR(Part2Port,0x25,~0x0F0,tempah); - + SiSSetRegANDOR(Part2Port,0x25,~0x0F0,tempah); + tempbx=tempbx+8; - + if (SIS_IF_DEF_HiVision==1) { + tempbx=tempbx-4; + tempcx=tempbx; + } tempah=((tempbx&0xFF)<<4)&0xFF; - SetRegANDOR(Part2Port,0x29,~0x0F0,tempah); - + SiSSetRegANDOR(Part2Port,0x29,~0x0F0,tempah); + tempcx=tempcx+temp2[++j]; tempah=tempcx&0xFF; - SetReg1(Part2Port,0x27,tempah); + SiSSetReg1(Part2Port,0x27,tempah); tempah=(((tempcx&0xFF00)>>8)<<4)&0xFF; - SetRegANDOR(Part2Port,0x28,~0x0F0,tempah); - + SiSSetRegANDOR(Part2Port,0x28,~0x0F0,tempah); + tempcx=tempcx+8; - + if (SIS_IF_DEF_HiVision==1) tempcx=tempcx-4; tempah=tempcx&0xFF; tempah=(tempah<<4)&0xFF; - SetRegANDOR(Part2Port,0x2A,~0x0F0,tempah); - - tempcx=pushcx; //pop cx + SiSSetRegANDOR(Part2Port,0x2A,~0x0F0,tempah); + + tempcx=pushcx; /* pop cx */ tempcx=tempcx-temp2[++j]; tempah=tempcx&0xFF; tempah=(tempah<<4)&0xFF; - SetRegANDOR(Part2Port,0x2D,~0x0F0,tempah); - + SiSSetRegANDOR(Part2Port,0x2D,~0x0F0,tempah); + tempcx=tempcx-11; - if(!(VBInfo&SetCRT2ToTV)){ - tempax=GetVGAHT2(); + if (!(SiSVBInfo&SetCRT2ToTV)) { + tempax=SiSGetVGAHT2(); tempcx=tempax-1; } tempah=tempcx&0xFF; - SetReg1(Part2Port,0x2E,tempah); - - tempbx=VDE; - if(VGAVDE==360){ + SiSSetReg1(Part2Port,0x2E,tempah); + + tempbx=SiSVDE; + if (SiSVGAVDE==360) { tempbx=746; - } - if(VGAVDE==375){ + } + if (SiSVGAVDE==375) { tempbx=746; } - if(VGAVDE==405){ + if (SiSVGAVDE==405) { tempbx=853; } - if((VBInfo&SetCRT2ToTV)){ - tempbx=tempbx>>1; + /* assuming <<ifndef>> HivisionTV */ + if ((SiSVBInfo&SetCRT2ToTV)) { + tempbx=tempbx>>1; } tempbx=tempbx-2; tempah=tempbx&0xFF; - SetReg1(Part2Port,0x2F,tempah); - + SiSSetReg1(Part2Port,0x2F,tempah); + tempah=(tempcx&0xFF00)>>8; tempbh=(tempbx&0xFF00)>>8; tempbh=(tempbh<<6)&0xFF; tempah=tempah|tempbh; - //assuming <<ifndef>> hivisiontv - tempah=tempah|0x10; - if(!(VBInfo&SetCRT2ToSVIDEO)){ - tempah=tempah|0x20; + if (SIS_IF_DEF_HiVision==0) { + tempah=tempah|0x10; + if (!(SiSVBInfo&SetCRT2ToSVIDEO)) { + tempah=tempah|0x20; + } } - - SetReg1(Part2Port,0x30,tempah); - + SiSSetReg1(Part2Port,0x30,tempah); + tempbh=0; tempbx=tempbx&0xFF; - tempmodeflag=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag + tempmodeflag=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); /* si+St_ModeFlag */ tempflowflag=0; - if(!(tempmodeflag&HalfDCLK)){ - tempcx=VGAHDE; - if(tempcx>=HDE){ + if (!(tempmodeflag&HalfDCLK)) { + tempcx=SiSVGAHDE; + if (tempcx>=SiSHDE) { tempbh=tempbh|0x20; tempbx=(tempbh<<8)|(tempbx&0xFF); tempah=0; } } tempcx=0x0101; - if(!(tempbh&0x20)){ - if(tempmodeflag&HalfDCLK){ + if (SIS_IF_DEF_HiVision==1) { + if (SiSVGAHDE>=1024) { + tempcx=0x1920; + if (SiSVGAHDE>=1280) tempcx=0x1420; + } + } + if (!(tempbh&0x20)) { + if (tempmodeflag&HalfDCLK) { tempcl=((tempcx&0xFF)<<1)&0xFF; - tempcx=(tempcx&0xFF00)|tempcl; - } + tempcx=(tempcx&0xFF00)|tempcl; + } pushbx=tempbx; - tempax=VGAHDE; + tempax=SiSVGAHDE; tempbx=(tempcx&0xFF00)>>8; longtemp=tempax*tempbx; tempcx=tempcx&0xFF; longtemp=longtemp/tempcx; longtemp=longtemp*8*1024; - tempax=(USHORT)((longtemp)/HDE); - if(tempax*HDE<longtemp){ + tempax=(longtemp)/SiSHDE; + if (tempax*SiSHDE<longtemp) { tempax=tempax+1; - }else{ + } else { tempax=tempax; - } - tempbx=pushbx; - tempah=((tempax&0xFF00)>>8)&0x01F; - tempbh=tempbh|tempah; - tempah=tempax&0xFF; + } + tempbx=pushbx; + tempah=((tempax&0xFF00)>>8)&0x01F; + tempbh=tempbh|tempah; + tempah=tempax&0xFF; } - - SetReg1(Part2Port,0x44,tempah); + + SiSSetReg1(Part2Port,0x44,tempah); tempah=tempbh; - SetRegANDOR(Part2Port,0x45,~0x03F,tempah); + SiSSetRegANDOR(Part2Port,0x45,~0x03F,tempah); - if(VBInfo&SetCRT2ToTV){ + if (SIS_IF_DEF_HiVision==1) { + if (!(SiSVBInfo&SetInSlaveMode)) { + SiSSetReg1(Part2Port,0x0B,0x00); + } + } + + if (SiSVBInfo&SetCRT2ToTV) { return; } - tempah=0x01; - if(LCDResInfo==Panel1280x1024){ - if(ModeType==ModeEGA){ - if(VGAHDE>=1024){ - tempah=0x02; + if (SiSLCDResInfo==Panel1280x1024) { + if (SiSModeType==ModeEGA) { + if (SiSVGAHDE>=1024) { + tempah=0x02; } - } - } - SetReg1(Part2Port,0x0B,tempah); + } + } + SiSSetReg1(Part2Port,0x0B,tempah); - tempbx=HDE-1; //RHACTE=HDE-1 + tempbx=SiSHDE-1; /* RHACTE=SiSHDE-1 */ tempah=tempbx&0xFF; - SetReg1(Part2Port,0x2C,tempah); + SiSSetReg1(Part2Port,0x2C,tempah); tempah=(tempbx&0xFF00)>>8; tempah=(tempah<<4)&0xFF; - SetRegANDOR(Part2Port,0x2B,~0x0F0,tempah); + SiSSetRegANDOR(Part2Port,0x2B,~0x0F0,tempah); - tempbx=VDE-1; //RTVACTEO=(VDE-1)&0xFF + tempbx=SiSVDE-1; /* RTVACTEO=(SiSVDE-1)&0xFF */ tempah=tempbx&0xFF; - SetReg1(Part2Port,0x03,tempah); + SiSSetReg1(Part2Port,0x03,tempah); tempah=((tempbx&0xFF00)>>8)&0x07; - SetRegANDOR(Part2Port,0x0C,~0x07,tempah); - - tempcx=VT-1; - tempah=tempcx&0xFF; //RVTVT=VT-1 - SetReg1(Part2Port,0x19,tempah); + SiSSetRegANDOR(Part2Port,0x0C,~0x07,tempah); + + tempcx=SiSVT-1; + tempah=tempcx&0xFF; /* RVTVT=SiSVT-1 */ + SiSSetReg1(Part2Port,0x19,tempah); tempah=(tempcx&0xFF00)>>8; tempah=(tempah<<5)&0xFF; - if(LCDInfo&LCDRGB18Bit){ + if (SiSLCDInfo&LCDRGB18Bit) { tempah=tempah|0x10; } - SetReg1(Part2Port,0x1A,tempah); + SiSSetReg1(Part2Port,0x1A,tempah); tempcx++; - if(LCDResInfo==Panel1024x768){ + if (SiSLCDResInfo==Panel1024x768) { tempbx=768; - }else{ + } else { tempbx=1024; } - if(tempbx==VDE){ + if (tempbx==SiSVDE) { tempax=1; - }else{ + } else { tempax=tempbx; - tempax=(tempax-VDE)>>1; + tempax=(tempax-SiSVDE)>>1; } - tempcx=tempcx-tempax; //lcdvdes - tempbx=tempbx-tempax; //lcdvdee - - tempah=tempcx&0xFF; //RVEQ1EQ=lcdvdes - SetReg1(Part2Port,0x05,tempah); - tempah=tempbx&0xFF; //RVEQ2EQ=lcdvdee - SetReg1(Part2Port,0x06,tempah); - + tempcx=tempcx-tempax; /* lcdvdes */ + tempbx=tempbx-tempax; /* lcdvdee */ + + tempah=tempcx&0xFF; /* RVEQ1EQ=lcdvdes */ + SiSSetReg1(Part2Port,0x05,tempah); + tempah=tempbx&0xFF; /* RVEQ2EQ=lcdvdee */ + SiSSetReg1(Part2Port,0x06,tempah); + tempah=(tempbx&0xFF00)>>8; tempah=(tempah<<3)&0xFF; - tempah=tempah|((tempcx&0xFF00)>>8); - //RTVACTSE=(lcdvdes&0x700>>8)+(lcdvdee&0x700>>5); - SetReg1(Part2Port,0x02,tempah); + tempah=tempah|((tempcx&0xFF00)>>8); + SiSSetReg1(Part2Port,0x02,tempah); + + tempcx=(SiSVT-SiSVDE)>>4; /* (SiSVT-SiSVDE)>>4 */ + tempbx=(SiSVT+SiSVDE)>>1; + tempah=tempbx&0xFF; /* RTVACTEE=lcdvrs */ + SiSSetReg1(Part2Port,0x04,tempah); - - tempcx=(VT-VDE)>>4; //(VT-VDE)>>4 - tempbx=(VT+VDE)>>1; - tempah=tempbx&0xFF; //RTVACTEE=lcdvrs - SetReg1(Part2Port,0x04,tempah); - tempah=(tempbx&0xFF00)>>8; tempah=(tempah<<4)&0xFF; tempbx=tempbx+tempcx+1; tempbl=(tempbx&0x0F); - tempah=tempah|tempbl; //RTVACTSO=lcdvrs&0x700>>4+lcdvre - SetReg1(Part2Port,0x01,tempah); - - tempah=GetReg1(Part2Port,0x09); + tempah=tempah|tempbl; /* RTVACTSO=lcdvrs&0x700>>4+lcdvre */ + SiSSetReg1(Part2Port,0x01,tempah); + + tempah=SiSGetReg1(Part2Port,0x09); tempah=tempah&0xF0; - SetReg1(Part2Port,0x09,tempah); - - tempah=GetReg1(Part2Port,0x0A); + SiSSetReg1(Part2Port,0x09,tempah); + + tempah=SiSGetReg1(Part2Port,0x0A); tempah=tempah&0xF0; - SetReg1(Part2Port,0x0A,tempah); - - tempcx=(HT-HDE)>>2; //(HT-HDE)>>2 - tempbx=(HDE+7); //lcdhdee - tempah=tempbx&0xFF; //RHEQPLE=lcdhdee - SetReg1(Part2Port,0x23,tempah); + SiSSetReg1(Part2Port,0x0A,tempah); + + tempcx=(SiSHT-SiSHDE)>>2; /* (SiSHT-SiSHDE)>>2 */ + tempbx=(SiSHDE+7); /* lcdhdee */ + tempah=tempbx&0xFF; /* RHEQPLE=lcdhdee */ + SiSSetReg1(Part2Port,0x23,tempah); tempah=(tempbx&0xFF00)>>8; - SetRegANDOR(Part2Port,0x25,~0x0F,tempah); - - SetReg1(Part2Port,0x1F,0x07); //RHBLKE=lcdhdes - tempah=GetReg1(Part2Port,0x20); + SiSSetRegANDOR(Part2Port,0x25,~0x0F,tempah); + + SiSSetReg1(Part2Port,0x1F,0x07); /* RHBLKE=lcdhdes */ + tempah=SiSGetReg1(Part2Port,0x20); tempah=tempah&0x0F; - SetReg1(Part2Port,0x20,tempah); - + SiSSetReg1(Part2Port,0x20,tempah); + tempbx=tempbx+tempcx; - tempah=tempbx&0xFF; //RHBURSTS=lcdhrs - SetReg1(Part2Port,0x1C,tempah); + tempah=tempbx&0xFF; /* RHBURSTS=lcdhrs */ + SiSSetReg1(Part2Port,0x1C,tempah); tempah=(tempbx&0xFF00)>>8; - tempah=(tempah<<4)&0xFF; - SetRegANDOR(Part2Port,0x1D,~0x0F0,tempah); - + tempah=(tempah<<4)&0xFF; + SiSSetRegANDOR(Part2Port,0x1D,~0x0F0,tempah); + tempbx=tempbx+tempcx; - tempah=tempbx&0xFF; //RHSYEXP2S=lcdhre - SetReg1(Part2Port,0x21,tempah); - - tempah=GetReg1(Part2Port,0x17); + tempah=tempbx&0xFF; /* RHSYEXP2S=lcdhre */ + SiSSetReg1(Part2Port,0x21,tempah); + + tempah=SiSGetReg1(Part2Port,0x17); tempah=tempah&0xFB; - SetReg1(Part2Port,0x17,tempah); - - tempah=GetReg1(Part2Port,0x18); + SiSSetReg1(Part2Port,0x17,tempah); + + tempah=SiSGetReg1(Part2Port,0x18); tempah=tempah&0xDF; - SetReg1(Part2Port,0x18,tempah); + SiSSetReg1(Part2Port,0x18,tempah); return; } -VOID SetGroup3(USHORT BaseAddr) +VOID SiSSetGroup3(USHORT BaseAddr,ULONG ROMAddr) { USHORT i; USHORT *tempdi; - USHORT Part3Port; + USHORT Part3Port; + USHORT modeflag; Part3Port=BaseAddr+IND_SIS_CRT2_PORT_12; - if(VBInfo&SetPALTV){ - tempdi=PALGroup3Data; - }else{ - tempdi=NTSCGroup3Data; - } - - for(i=0;i<=0x3E;i++){ - SetReg1(Part3Port,i,tempdi[i]); + SiSSetReg1(Part3Port,0x00,0x00); + if (SiSVBInfo&SetPALTV) { + SiSSetReg1(Part3Port,0x13,0xFA); + SiSSetReg1(Part3Port,0x14,0xC8); + } else { + SiSSetReg1(Part3Port,0x13,0xF6); + SiSSetReg1(Part3Port,0x14,0xBF); + } + if (SIS_IF_DEF_HiVision==1) { + tempdi=SiSHiTVGroup3Data; + if (SiSSetFlag&TVSimuMode) { + tempdi=SiSHiTVGroup3Simu; + modeflag=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); + if (!(modeflag&Charx8Dot)) { + tempdi=SiSHiTVGroup3Text; + } + } + for(i=0;i<=0x3E;i++) { + SiSSetReg1(Part3Port,i,tempdi[i]); + } } return; } -VOID SetGroup4(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo) +VOID SiSSetGroup4(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo) { - USHORT Part4Port; + USHORT Part4Port; USHORT tempax,tempah,tempcx,tempbx,tempbh,tempch,tempmodeflag; - long int tempebx,tempeax,templong; + long int tempebx,tempeax,templong; Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14; - + tempax=0x0c; - if(VBInfo&SetCRT2ToTV){ - if(VBInfo&SetInSlaveMode){ - if(!(SetFlag&TVSimuMode)){ - SetFlag=SetFlag|RPLLDIV2XO; - tempax=tempax|0x04000; + if (SiSVBInfo&SetCRT2ToTV) { + if (SiSVBInfo&SetInSlaveMode) { + if (!(SiSSetFlag&TVSimuMode)) { + SiSSetFlag=SiSSetFlag|RPLLDIV2XO; + tempax=tempax|0x04000; } - }else{ - SetFlag=SetFlag|RPLLDIV2XO; - tempax=tempax|0x04000; + } else { + SiSSetFlag=SiSSetFlag|RPLLDIV2XO; + tempax=tempax|0x04000; } } - - if(LCDResInfo!=Panel1024x768){ + + if (SiSLCDResInfo!=Panel1024x768) { tempax=tempax|0x08000; } tempah=(tempax&0xFF00)>>8; - SetReg1(Part4Port,0x0C,tempah); + SiSSetReg1(Part4Port,0x0C,tempah); - tempah=RVBHCFACT; - SetReg1(Part4Port,0x13,tempah); + tempah=SiSRVBHCFACT; + SiSSetReg1(Part4Port,0x13,tempah); - tempbx=RVBHCMAX; + tempbx=SiSRVBHCMAX; tempah=tempbx&0xFF; - SetReg1(Part4Port,0x14,tempah); + SiSSetReg1(Part4Port,0x14,tempah); tempbh=(((tempbx&0xFF00)>>8)<<7)&0xFF; - - tempcx=VGAHT-1; + + tempcx=SiSVGAHT-1; tempah=tempcx&0xFF; - SetReg1(Part4Port,0x16,tempah); + SiSSetReg1(Part4Port,0x16,tempah); tempch=(((tempcx&0xFF00)>>8)<<3)&0xFF; tempbh=tempbh|tempch; - tempcx=VGAVT-1; - if(!(VBInfo&SetCRT2ToTV)){ + tempcx=SiSVGAVT-1; + if (!(SiSVBInfo&SetCRT2ToTV)) { tempcx=tempcx-5; } tempah=tempcx&0xFF; - SetReg1(Part4Port,0x17,tempah); + SiSSetReg1(Part4Port,0x17,tempah); tempbh=tempbh|((tempcx&0xFF00)>>8); tempah=tempbh; - SetReg1(Part4Port,0x15,tempah); + SiSSetReg1(Part4Port,0x15,tempah); - tempcx=VBInfo; - tempbx=VGAHDE; - tempmodeflag=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - if(tempmodeflag&HalfDCLK){ - tempbx=tempbx>>1; - } - - if(VBInfo&SetCRT2ToLCD){ - tempah=0; - if(tempbx>800){ - tempah=0x60; + tempcx=SiSVBInfo; + tempbx=SiSVGAHDE; + tempmodeflag=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); /* si+St_ModeFlag */ + if (tempmodeflag&HalfDCLK) { + tempbx=tempbx>>1; + } + + if (SIS_IF_DEF_HiVision==1) { + tempah=0xA0; + if (tempbx!=1024) { + tempah=0xC0; + if (tempbx!=1280) tempah=0; + } + } else { + if (SiSVBInfo&SetCRT2ToLCD) { + tempah=0; + if (tempbx>800) { + tempah=0x60; + } + } else { + tempah=0x080; } - }else{ - tempah=0x080; } - if(LCDResInfo!=Panel1280x1024){ + if (SiSLCDResInfo!=Panel1280x1024) { tempah=tempah|0x0A; } - - SetRegANDOR(Part4Port,0x0E,~0xEF,tempah); - - tempebx=VDE; - tempcx=RVBHRS; + SiSSetRegANDOR(Part4Port,0x0E,~0xEF,tempah); + + tempebx=SiSVDE; + + if (SIS_IF_DEF_HiVision==1) { + if (!(tempah&0xE0)) tempbx=tempbx>>1; + } + + tempcx=SiSRVBHRS; tempah=tempcx&0xFF; - SetReg1(Part4Port,0x18,tempah); - - tempeax=VGAVDE; + SiSSetReg1(Part4Port,0x18,tempah); + + tempeax=SiSVGAVDE; tempcx=tempcx|0x04000; tempeax=tempeax-tempebx; - if(tempeax<0){ + if (tempeax<0) { tempcx=tempcx^(0x04000); - tempeax=VGAVDE; + tempeax=SiSVGAVDE; } - + templong=(tempeax*256*1024)/tempebx; - if(tempeax*256*1024-templong*tempebx>0){ + if (tempeax*256*1024-templong*tempebx>0) { tempebx=templong+1; - }else{ + } else { tempebx=templong; - } + } - - tempah=(USHORT)(tempebx&0xFF); - SetReg1(Part4Port,0x1B,tempah); - tempah=(USHORT)((tempebx&0xFF00)>>8); - SetReg1(Part4Port,0x1A,tempah); + + tempah=tempebx&0xFF; + SiSSetReg1(Part4Port,0x1B,tempah); + tempah=(tempebx&0xFF00)>>8; + SiSSetReg1(Part4Port,0x1A,tempah); tempebx=tempebx>>16; - tempah=(USHORT)(tempebx&0xFF); + tempah=tempebx&0xFF; tempah=(tempah<<4)&0xFF; tempah=tempah|((tempcx&0xFF00)>>8); - SetReg1(Part4Port,0x19,tempah); + SiSSetReg1(Part4Port,0x19,tempah); - SetCRT2VCLK(BaseAddr,ROMAddr,ModeNo); + SiSSetCRT2VCLK(BaseAddr,ROMAddr,ModeNo); } -VOID SetCRT2VCLK(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo) +VOID SiSSetCRT2VCLK(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo) { USHORT vclk2ptr; USHORT tempah,temp1; - USHORT Part4Port; + USHORT Part4Port; + Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14; - vclk2ptr=GetVCLK2Ptr(ROMAddr,ModeNo); - SetReg1(Part4Port,0x0A,0x01); - tempah=*((UCHAR *)(ROMAddr+vclk2ptr+0x01)); //di+1 - SetReg1(Part4Port,0x0B,tempah); - tempah=*((UCHAR *)(ROMAddr+vclk2ptr+0x00)); //di - SetReg1(Part4Port,0x0A,tempah); - SetReg1(Part4Port,0x12,0x00); + vclk2ptr=SiSGetVCLK2Ptr(ROMAddr,ModeNo); + SiSSetReg1(Part4Port,0x0A,0x01); + tempah=*((UCHAR *)(ROMAddr+vclk2ptr+0x01)); /* di+1 */ + SiSSetReg1(Part4Port,0x0B,tempah); + tempah=*((UCHAR *)(ROMAddr+vclk2ptr+0x00)); /* di */ + SiSSetReg1(Part4Port,0x0A,tempah); + SiSSetReg1(Part4Port,0x12,0x00); tempah=0x08; - if(VBInfo&SetCRT2ToRAMDAC){ + if (SiSVBInfo&SetCRT2ToRAMDAC) { tempah=tempah|0x020; } - temp1=GetReg1(Part4Port,0x12); + temp1=SiSGetReg1(Part4Port,0x12); tempah=tempah|temp1; - SetReg1(Part4Port,0x12,tempah); + SiSSetReg1(Part4Port,0x12,tempah); } -VOID SetGroup5(USHORT BaseAddr,ULONG ROMAddr) +VOID SiSSetGroup5(USHORT BaseAddr,ULONG ROMAddr) { - USHORT Part5Port; + USHORT Part5Port; USHORT Pindex,Pdata; Part5Port=BaseAddr+IND_SIS_CRT2_PORT_14+2; Pindex=Part5Port; Pdata=Part5Port+1; - if(ModeType==ModeVGA){ - if(!(VBInfo&(SetInSlaveMode|LoadDACFlag|CRT2DisplayFlag))){ - EnableCRT2(); - LoadDAC2(ROMAddr,Part5Port); + if (SiSModeType==ModeVGA) { + if (!(SiSVBInfo&(SetInSlaveMode|LoadDACFlag|CRT2DisplayFlag))) { + SiSEnableCRT2(); + SiSLoadDAC2(ROMAddr,Part5Port); } } return; } -VOID EnableCRT2() +VOID SiSEnableCRT2() { USHORT temp1; - temp1=GetReg1(P3c4,0x1E); + temp1=SiSGetReg1(SiSP3c4,0x1E); temp1=temp1|0x20; - SetReg1(P3c4,0x1E,temp1); //SR 1E + SiSSetReg1(SiSP3c4,0x1E,temp1); /* SR 1E */ } -VOID LoadDAC2(ULONG ROMAddr,USHORT Part5Port) +VOID SiSLoadDAC2(ULONG ROMAddr,USHORT Part5Port) { USHORT data,data2; USHORT time,i,j,k; USHORT m,n,o; USHORT si,di,bx,dl; USHORT al,ah,dh; - USHORT *table=VGA_DAC; + USHORT *table=0; USHORT Pindex,Pdata; Pindex=Part5Port; Pdata=Part5Port+1; - data=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); + data=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); data=data&DACInfoFlag; time=64; - if(data==0x00) table=MDA_DAC; - if(data==0x08) table=CGA_DAC; - if(data==0x10) table=EGA_DAC; - if(data==0x18) { + if (data==0x00) table=SIS_MDA_DAC; + if (data==0x08) table=SIS_CGA_DAC; + if (data==0x10) table=SIS_EGA_DAC; + if (data==0x18) { time=256; - table=VGA_DAC; + table=SIS_VGA_DAC; } - if(time==256) j=16; + if (time==256) j=16; else j=time; - //SetReg3(P3c6,0xFF); - SetReg3(Pindex,0x00); - + SiSSetReg3(Pindex,0x00); + for(i=0;i<j;i++) { data=table[i]; for(k=0;k<3;k++) { data2=0; - if(data&0x01) data2=0x2A; - if(data&0x02) data2=data2+0x15; - SetReg3(Pdata,data2); + if (data&0x01) data2=0x2A; + if (data&0x02) data2=data2+0x15; + SiSSetReg3(Pdata,data2); data=data>>2; } } - - if(time==256) { + + if (time==256) { for(i=16;i<32;i++) { data=table[i]; - for(k=0;k<3;k++) SetReg3(Pdata,data); + for(k=0;k<3;k++) SiSSetReg3(Pdata,data); } si=32; for(m=0;m<9;m++) { @@ -2053,345 +2288,365 @@ ah=table[di]; al=table[bx]; si++; - WriteDAC2(Pdata,dl,ah,al,dh); - } // for 5 + SiSWriteDAC2(Pdata,dl,ah,al,dh); + } /* for 5 */ si=si-2; for(o=0;o<3;o++) { dh=table[bx]; ah=table[di]; al=table[si]; si--; - WriteDAC2(Pdata,dl,ah,al,dh); - } // for 3 + SiSWriteDAC2(Pdata,dl,ah,al,dh); + } /* for 3 */ dl++; - } // for 3 + } /* for 3 */ si=si+5; - } // for 9 + } /* for 9 */ } } -VOID WriteDAC2(USHORT Pdata,USHORT dl, USHORT ah, USHORT al, USHORT dh) +VOID SiSWriteDAC2(USHORT Pdata,USHORT dl, USHORT ah, USHORT al, USHORT dh) { USHORT temp; USHORT bh,bl; bh=ah; bl=al; - if(dl!=0) { + if (dl!=0) { temp=bh; bh=dh; dh=temp; - if(dl==1) { + if (dl==1) { temp=bl; bl=dh; dh=temp; - } - else { + } else { temp=bl; bl=bh; bh=temp; } } - SetReg3(Pdata,(USHORT)dh); - SetReg3(Pdata,(USHORT)bh); - SetReg3(Pdata,(USHORT)bl); + SiSSetReg3(Pdata,(USHORT)dh); + SiSSetReg3(Pdata,(USHORT)bh); + SiSSetReg3(Pdata,(USHORT)bl); } -VOID LockCRT2(USHORT BaseAddr) +VOID SiSLockCRT2(USHORT BaseAddr) { - USHORT Part1Port; - USHORT Part4Port; + USHORT Part1Port; + USHORT Part4Port; USHORT temp1; Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14; - temp1=GetReg1(Part1Port,0x24); + temp1=SiSGetReg1(Part1Port,0x24); temp1=temp1&0xFE; - SetReg1(Part1Port,0x24,temp1); + SiSSetReg1(Part1Port,0x24,temp1); } -VOID SetLockRegs() +VOID SiSSetLockRegs() { USHORT temp1; - if((VBInfo&SetInSlaveMode)&&(!(VBInfo&SetCRT2ToRAMDAC))){ - VBLongWait(); - temp1=GetReg1(P3c4,0x32); + if ((SiSVBInfo&SetInSlaveMode)&&(!(SiSVBInfo&SetCRT2ToRAMDAC))) { + SiSVBLongWait(); + temp1=SiSGetReg1(SiSP3c4,0x32); temp1=temp1|0x20; - SetReg1(P3c4,0x32,temp1); - VBLongWait(); + SiSSetReg1(SiSP3c4,0x32,temp1); + SiSVBLongWait(); } } -VOID EnableBridge(USHORT BaseAddr) +VOID SiSEnableBridge(USHORT BaseAddr) { USHORT part2_02,part2_05; - USHORT Part2Port,Part1Port; + USHORT Part2Port; Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; - Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - if(IF_DEF_LVDS==0){ - part2_02=(UCHAR)GetReg1(Part2Port,0x02); - part2_05=(UCHAR)GetReg1(Part2Port,0x05); - SetReg1(Part2Port,0x02,0x38); - SetReg1(Part2Port,0x05,0xFF); - LongWait(); - SetRegANDOR(Part2Port,0x00,~0x0E0,0x020); - WaitVBRetrace(BaseAddr); - SetReg1(Part2Port,0x02,part2_02); - SetReg1(Part2Port,0x05,part2_05); - }else{ - EnableCRT2(); - UnLockCRT2(BaseAddr); - SetRegANDOR(Part1Port,0x02,~0x040,0x0); + if (SIS_IF_DEF_LVDS==0) { + part2_02=(UCHAR)SiSGetReg1(Part2Port,0x02); + part2_05=(UCHAR)SiSGetReg1(Part2Port,0x05); + SiSSetReg1(Part2Port,0x02,0x38); + SiSSetReg1(Part2Port,0x05,0xFF); + SiSLongWait(); + SiSSetRegANDOR(Part2Port,0x00,~0x0E0,0x020); + /* SiSWaitVBRetrace(BaseAddr); */ + SiSSetReg1(Part2Port,0x02,part2_02); + SiSSetReg1(Part2Port,0x05,part2_05); + } else { + SiSEnableCRT2(); + SiSUnLockCRT2(BaseAddr); + /* SiSSetRegANDOR(Part1Port,0x02,~0x040,0x0); */ } } -USHORT GetLockInfo(USHORT pattern) -{ - USHORT temp1; - temp1=GetReg1(P3d4,0x36); - return(temp1&pattern); -} - -VOID GetVBInfo(USHORT BaseAddr,ULONG ROMAddr) +VOID SiSGetVBInfo(USHORT BaseAddr,ULONG ROMAddr) { - USHORT flag1,tempbx,tempbl,tempbh,tempah; + USHORT flag1,tempbx,tempbl,tempbh,tempah,temp; - SetFlag=0; - tempbx=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag + SiSSetFlag=0; + tempbx=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); /* si+St_ModeFlag */ tempbl=tempbx&ModeInfoFlag; - ModeType=tempbl; + SiSModeType=tempbl; tempbx=0; - flag1=GetReg1(P3c4,0x38); //call BridgeisOn - if(!(flag1&0x20)){ - VBInfo=CRT2DisplayFlag; - return; - } - tempbl=GetReg1(P3d4,0x30); - tempbh=GetReg1(P3d4,0x31); - if(!(tempbl&0x07C)){ - VBInfo=CRT2DisplayFlag; - return; - } - if(IF_DEF_LVDS==1){ //for LVDS - if(!(tempbl&SetCRT2ToLCD)){ - VBInfo=CRT2DisplayFlag; + flag1=SiSGetReg1(SiSP3c4,0x38); /* call BridgeisOn */ + if (SIS_IF_DEF_LVDS==0) { /* for 301 */ + if (!(flag1&0x20)) { + SiSVBInfo=CRT2DisplayFlag; return; } } - if(IF_DEF_LVDS==0){ //for 301 - if(tempbl&SetCRT2ToRAMDAC){ + tempbl=SiSGetReg1(SiSP3d4,0x30); + tempbh=SiSGetReg1(SiSP3d4,0x31); + + tempah=((SetCHTVOverScan>>8)|(SetInSlaveMode>>8)|(DisableCRT2Display>>8)); + tempah=tempah^0xFF; + tempbh=tempbh&tempah; + if (SIS_IF_DEF_LVDS==1) { /* for LVDS */ + if (SIS_IF_DEF_CH7005==1) temp=SetCRT2ToLCD|SetCRT2ToTV; + else temp=SetCRT2ToLCD; + } else { + if (SIS_IF_DEF_HiVision==1) temp=0xFC; + else temp=0x7C; + } + if (!(tempbl&temp)) { + SiSVBInfo=DisableCRT2Display; + return; + } + if (SIS_IF_DEF_LVDS==0) { + if (tempbl&SetCRT2ToRAMDAC) { tempbl=tempbl&(SetCRT2ToRAMDAC|SwitchToCRT2|SetSimuScanMode); - }else if(tempbl&SetCRT2ToLCD){ + } else if (tempbl&SetCRT2ToLCD) { tempbl=tempbl&(SetCRT2ToLCD|SwitchToCRT2|SetSimuScanMode); - }else if(tempbl&SetCRT2ToSCART){ + } else if (tempbl&SetCRT2ToSCART) { tempbl=tempbl&(SetCRT2ToSCART|SwitchToCRT2|SetSimuScanMode); - }else if(tempbl&SetCRT2ToHiVisionTV){ + tempbh=tempbh|(SetPALTV>>8); + } else if (tempbl&SetCRT2ToHiVisionTV) { tempbl=tempbl&(SetCRT2ToHiVisionTV|SwitchToCRT2|SetSimuScanMode); + tempbh=tempbh|(SetPALTV>>8); } - }else{ //for LVDS - if(tempbl&SetCRT2ToLCD){ - tempbl=tempbl&(SetCRT2ToLCD|SwitchToCRT2|SetSimuScanMode); - } + } else { + if (SIS_IF_DEF_CH7005==1) { + if (tempbl&SetCRT2ToTV) + tempbl=tempbl&(SetCRT2ToTV|SwitchToCRT2|SetSimuScanMode); + } + if (tempbl&SetCRT2ToLCD) + tempbl=tempbl&(SetCRT2ToLCD|SwitchToCRT2|SetSimuScanMode); } - tempah=GetReg1(P3d4,0x31); - if(tempah&(CRT2DisplayFlag>>8)){ - if(!(tempbl&(SwitchToCRT2|SetSimuScanMode))){ + tempah=SiSGetReg1(SiSP3d4,0x31); + if (tempah&(CRT2DisplayFlag>>8)) { + if (!(tempbl&(SwitchToCRT2|SetSimuScanMode))) { tempbx=SetSimuScanMode|CRT2DisplayFlag; tempbh=((tempbx&0xFF00)>>8); tempbl=tempbx&0xFF; } } - if(!(tempbh&(DriverMode>>8))){ + if (!(tempbh&(DriverMode>>8))) { tempbl=tempbl|SetSimuScanMode; } - VBInfo=tempbl|(tempbh<<8); - if(!(VBInfo&SetSimuScanMode)){ - if(!(VBInfo&SwitchToCRT2)){ - if(BridgeIsEnable(BaseAddr)){ - if(BridgeInSlave()){ - VBInfo=VBInfo|SetSimuScanMode; - } + SiSVBInfo=tempbl|(tempbh<<8); + if (!(SiSVBInfo&SetSimuScanMode)) { + if (!(SiSVBInfo&SwitchToCRT2)) { + if (SiSBridgeIsEnable(BaseAddr)) { + if (SiSBridgeInSlave()) { + SiSVBInfo=SiSVBInfo|SetSimuScanMode; + } + } + } else { + flag1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); /* si+St_ModeFlag */ + if (!(flag1&CRT2Mode)) { + SiSVBInfo=SiSVBInfo|SetSimuScanMode; } } } - if(!((VBInfo&(SetSimuScanMode|SwitchToCRT2)))){ - return; - } - if(!(VBInfo&DriverMode)){ - VBInfo=VBInfo|SetInSlaveMode; - if((VBInfo&SetCRT2ToTV)&&(!(VBInfo&SetNotSimuTVMode))){ - SetFlag=SetFlag|TVSimuMode; - } - return; - } - flag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - if(!(flag1&(CRT2Mode|CRT2DisplayFlag))){ - VBInfo=VBInfo|SetInSlaveMode; - if((VBInfo&SetCRT2ToTV)&&(!(VBInfo&SetNotSimuTVMode))){ - SetFlag=SetFlag|TVSimuMode; + if (!(SiSVBInfo&DisableCRT2Display)) { + if (SiSVBInfo&DriverMode) { + if (SiSVBInfo&SetSimuScanMode) { + flag1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); /* si+St_ModeFlag */ + if (!(flag1&CRT2Mode)) { + SiSVBInfo=SiSVBInfo|SetInSlaveMode; + } + } + } else { + SiSVBInfo=SiSVBInfo|SetSimuScanMode; + if (SIS_IF_DEF_LVDS==0) { + if (SiSVBInfo&SetCRT2ToTV) { + if (!(SiSVBInfo&SetNotSimuMode)) SiSSetFlag=SiSSetFlag|TVSimuMode; + } + } } + } + if (SIS_IF_DEF_CH7005==1) { + tempah=SiSGetReg1(SiSP3d4,0x35); + if (tempah&TVOverScan) SiSVBInfo=SiSVBInfo|SetCHTVOverScan; } } -BOOLEAN BridgeIsEnable(USHORT BaseAddr) +BOOLEAN SiSBridgeIsEnable(USHORT BaseAddr) { USHORT flag1; - USHORT Part1Port; + USHORT Part1Port; Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - if(IF_DEF_LVDS==1){ + if (SIS_IF_DEF_LVDS==1) { return 1; } - flag1=GetReg1(P3c4,0x38); //call BridgeisOn - if(!(flag1&0x20)){ return 0;} - flag1=GetReg1(Part1Port,0x0); - if(flag1&0x0a0){ + flag1=SiSGetReg1(SiSP3c4,0x38); /* call BridgeisOn */ + if (!(flag1&0x20)) { return 0;} + flag1=SiSGetReg1(Part1Port,0x0); + if (flag1&0x0a0) { return 1; - }else{ + } else { return 0; } } -BOOLEAN BridgeInSlave() +BOOLEAN SiSBridgeInSlave() { USHORT flag1; - flag1=GetReg1(P3d4,0x31); - if(flag1&(SetInSlaveMode>>8)){ + flag1=SiSGetReg1(SiSP3d4,0x31); + if (flag1&(SetInSlaveMode>>8)) { return 1; - }else{ + } else { return 0; } } -BOOLEAN GetLCDResInfo(ULONG ROMAddr,USHORT P3d4) +BOOLEAN SiSGetLCDResInfo(ULONG ROMAddr,USHORT SiSP3d4) { - USHORT tempah,tempbh,tempflag; - - tempah=(UCHAR)GetReg1(P3d4,0x36); + USHORT tempah,tempbh,tempflag; + + tempah=(UCHAR)SiSGetReg1(SiSP3d4,0x36); tempbh=tempah; tempah=tempah&0x0F; - if(tempah>Panel1280x1024) tempah=Panel1024x768; - LCDResInfo=tempah; +/* if (tempah!=0) tempah--; */ + if (tempah>Panel1280x1024) tempah=0; + SiSLCDResInfo=tempah; tempbh=tempbh>>4; - LCDTypeInfo=tempbh; - - tempah=(UCHAR)GetReg1(P3d4,0x37); - LCDInfo=tempah; - if(IF_DEF_TRUMPION){ - LCDInfo=LCDInfo&(~LCDNonExpanding); - } - if(IF_DEF_LVDS==1){ - tempflag=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - if(tempflag&HalfDCLK){ - if(IF_DEF_TRUMPION==0){ - if(!(LCDInfo&LCDNonExpanding)){ - if(LCDResInfo==Panel1024x768){ - tempflag=*((UCHAR *)(ROMAddr+ModeIDOffset+0x09)); //si+Ext_ResInfo - if(tempflag==4){ //512x384 - SetFlag=SetFlag|EnableLVDSDDA; + SiSLCDTypeInfo=tempbh; + + tempah=(UCHAR)SiSGetReg1(SiSP3d4,0x37); + SiSLCDInfo=tempah; + + if (SIS_IF_DEF_LVDS==1) { + tempflag=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); /* si+St_ModeFlag */ + if (tempflag&HalfDCLK) { + if (SIS_IF_DEF_TRUMPION==0) { + if (!(SiSLCDInfo&LCDNonExpanding)) { + if (SiSLCDResInfo==Panel1024x768) { + tempflag=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x09));/* si+Ext_ResInfo*/ + if (tempflag==4) { /* 512x384 */ + SiSSetFlag=SiSSetFlag|EnableLVDSDDA; } - }else{ - if(LCDResInfo==Panel800x600){ - tempflag=*((UCHAR *)(ROMAddr+ModeIDOffset+0x09)); //si+Ext_ResInfo - if(tempflag==3){ //400x300 - SetFlag=SetFlag|EnableLVDSDDA; + } else { + if (SiSLCDResInfo==Panel800x600) { + tempflag=*((UCHAR*)(ROMAddr+SiSModeIDOffset+0x09));/* si+Ext_ResInfo*/ + if (tempflag==3) { /* 400x300 */ + SiSSetFlag=SiSSetFlag|EnableLVDSDDA; } } } - }else{ - SetFlag=SetFlag|EnableLVDSDDA; + } else { + SiSSetFlag=SiSSetFlag|EnableLVDSDDA; } - }else{ - SetFlag=SetFlag|EnableLVDSDDA; + } else { + SiSSetFlag=SiSSetFlag|EnableLVDSDDA; } } } - - if(!(VBInfo&SetCRT2ToLCD)){ - return 1; + + if (!(SiSVBInfo&SetCRT2ToLCD)) { + return 1; } - if(!(VBInfo&(SetSimuScanMode|SwitchToCRT2))){ - return 1; + if (!(SiSVBInfo&(SetSimuScanMode|SwitchToCRT2))) { + return 1; } - if(VBInfo&SetInSlaveMode){ - if(VBInfo&SetNotSimuTVMode){ - SetFlag=SetFlag|LCDVESATiming; - } - }else{ - SetFlag=SetFlag|LCDVESATiming; + if (SiSVBInfo&SetInSlaveMode) { + if (SiSVBInfo&SetNotSimuMode) { + SiSSetFlag=SiSSetFlag|LCDVESATiming; + } + } else { + SiSSetFlag=SiSSetFlag|LCDVESATiming; } - return 1; + return 1; } -VOID PresetScratchregister(USHORT P3d4,PHW_DEVICE_EXTENSION HwDeviceExtension) +VOID SiSPresetScratchregister(USHORT SiSP3d4,PHW_DEVICE_EXTENSION HwDeviceExtension) { - SetReg1(P3d4,0x37,0x00); + SiSSetReg1(SiSP3d4,0x37,0x00); } -BOOLEAN GetLCDDDCInfo(PHW_DEVICE_EXTENSION HwDeviceExtension) +BOOLEAN SiSGetLCDDDCInfo(PHW_DEVICE_EXTENSION HwDeviceExtension) { USHORT tempah; - tempah=(HwDeviceExtension->usLCDType);// set in sisv.c - //0:no lcd 1:1024x768 2:1280x1024 - if(tempah>0) tempah++; // usLCDType: - // 0:no lcd 1:800x600 2:1024x768 3:1280x1024 - SetReg1(P3d4,0x36,tempah);//cr 36 0:no LCD 1:800x600 2:1024x768 3:1280x1024 - if(tempah>0) return 1; - else return 0; + tempah=(HwDeviceExtension->usLCDType);/* set in sisv.c */ + + if (tempah>0) tempah++; /* usLCDType: */ + + SiSSetReg1(SiSP3d4,0x36,tempah); /* cr 36 0:no LCD 1:1024x768 2:1280x1024 */ + if (tempah>0) return 1; + else return 0; } -VOID SetTVSystem(PHW_DEVICE_EXTENSION HwDeviceExtension,ULONG ROMAddr) +VOID SiSSetTVSystem(PHW_DEVICE_EXTENSION HwDeviceExtension,ULONG ROMAddr) { +#if 0 + USHORT tempah; + tempah=SiSGetReg1(SiSP3c4,0x38); /* SR 38 */ + tempah=tempah&0x01; /* get SR 38 D0 TV Type Selection */ + /* 0:NTSC 1:PAL */ + SiSSetRegANDOR(SiSP3d4,0x31,~0x01,tempah); /* set CR 31 D0= SR 38 D0 */ + return; +#else USHORT tempah,temp; - if(IF_DEF_LVDS==0){ //301 - if(PRIMARY_VGA==1){ //primary vga - if(HwDeviceExtension->jChipID >= SIS_Trojan){ - tempah=GetReg1(P3c4,0x17); - if(tempah&ModeSwitchStatus){ - tempah=GetReg1(P3c4,0x16); + if (SIS_IF_DEF_LVDS==0) { /* 301 */ + if (PRIMARY_VGA==1) { /* primary vga */ + if (HwDeviceExtension->jChipID >= SIS_Trojan) { + tempah=SiSGetReg1(SiSP3c4,0x17); + if (tempah&ModeSwitchStatus) { + tempah=SiSGetReg1(SiSP3c4,0x16); tempah=tempah&ActivePAL; tempah=tempah>>ActivePALShift; - }else{ + } else { temp=*((UCHAR *)(ROMAddr+SoftSettingAddr)); - if(temp&SoftTVType){ + if (temp&SoftTVType) { tempah=*((UCHAR *)(ROMAddr+ModeSettingAddr)); - }else{ - tempah=GetReg1(P3c4,0x38); //SR 38 + } else { + tempah=SiSGetReg1(SiSP3c4,0x38); /* SR 38 */ } } - }else{ + } else { temp=*((UCHAR *)(ROMAddr+SoftSettingAddr)); - if(temp&SoftTVType){ + if (temp&SoftTVType) { tempah=*((UCHAR *)(ROMAddr+ModeSettingAddr)); - }else{ - tempah=GetReg1(P3c4,0x38); //SR 38 + } else { + tempah=SiSGetReg1(SiSP3c4,0x38); /* SR 38 */ } } - tempah=tempah&0x01; //get SR 38 D0 TV Type Selection - //0:NTSC 1:PAL - SetRegANDOR(P3d4,0x31,~0x01,tempah);//set CR 31 D0= SR 38 D0 - } - else{ //Secondary - tempah=GetReg1(P3c4,0x38); //SR 38 - tempah=tempah&0x01; //get SR 38 D0 TV Type Selection - //0:NTSC 1:PAL - SetRegANDOR(P3d4,0x31,~0x01,tempah);//set CR 31 D0= SR 38 D0 + tempah=tempah&0x01; /* get SR 38 D0 TV Type Selection */ + /* 0:NTSC 1:PAL */ + SiSSetRegANDOR(SiSP3d4,0x31,~0x01,tempah);/* set CR 31 D0= SR 38 D0 */ + } + else { /* Secondary */ + tempah=SiSGetReg1(SiSP3c4,0x38); /* SR 38 */ + tempah=tempah&0x01; /* get SR 38 D0 TV Type Selection */ + /* 0:NTSC 1:PAL */ + SiSSetRegANDOR(SiSP3d4,0x31,~0x01,tempah);/* set CR 31 D0= SR 38 D0 */ } return; - }else{ //LVDS - tempah=GetReg1(P3c4,0x16); //SR 16 + } else { /* LVDS */ + tempah=SiSGetReg1(SiSP3c4,0x16); /* SR 16 */ tempah=tempah&ActiveNonExpanding; tempah=tempah>>ActiveNonExpandingShift; tempah=tempah&0x01; tempah=tempah<<LCDNonExpandingShift; - SetRegANDOR(P3d4,0x37,~LCDNonExpanding,tempah); + SiSSetRegANDOR(SiSP3d4,0x37,~LCDNonExpanding,tempah); return; } +#endif } -BOOLEAN GetSenseStatus(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr) +BOOLEAN SiSGetSenseStatus(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr) { USHORT flag1,tempbx,tempal,tempah,tempcx,i; USHORT Part2Port,Part4Port; @@ -2399,430 +2654,451 @@ USHORT P2reg0,SenseModeNo,OutputSelect; Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14; - RGBSenseData=*((USHORT *)(ROMAddr+0xF8)); //0:F8 in rompost.asm - YCSenseData=*((USHORT *)(ROMAddr+0xFA)); //0:FA in rompost.asm - VideoSenseData=*((USHORT *)(ROMAddr+0xFC)); //0:FC in rompost.asm + RGBSenseData=*((USHORT *)(ROMAddr+0xF8)); /* 0:F8 in rompost.asm */ + YCSenseData=*((USHORT *)(ROMAddr+0xFA)); /* 0:FA in rompost.asm */ + VideoSenseData=*((USHORT *)(ROMAddr+0xFC)); /* 0:FC in rompost.asm */ - if(IF_DEF_LVDS==1){ - GetPanelID(); + if (SIS_IF_DEF_LVDS==1) { + SiSGetPanelID(); tempah=LCDSense; - SetRegANDOR(P3d4,0x32,~0x5F,tempah); //Set CR 32 + SiSSetRegANDOR(SiSP3d4,0x32,~0x5F,tempah); /* Set CR 32 */ return 0; } - flag1=GetReg1(P3c4,0x38); //call BridgeisOn - if(!(flag1&0x20)){ return 0;} - P2reg0=GetReg1(Part2Port,0x00); //save Part2 Reg index 0 + flag1=SiSGetReg1(SiSP3c4,0x38); /* call BridgeisOn */ + if (!(flag1&0x20)) { return 0;} + P2reg0=SiSGetReg1(Part2Port,0x00); /* save Part2 Reg index 0 */ - if(!(BridgeIsEnable(BaseAddr))){ + if (!(SiSBridgeIsEnable(BaseAddr))) { SenseModeNo=0x2E; - ModeType=ModeVGA; - VBInfo=SetCRT2ToRAMDAC; - SetFlag=0; - SetCRT2Group(BaseAddr,ROMAddr,SenseModeNo,HwDeviceExtension); - //here perform I/O delay ,read SR 05 - for(i=0;i<0x7FFF;i++){ - flag1=GetReg1(P3c4,0x05); + SiSModeType=ModeVGA; + SiSVBInfo=SetCRT2ToRAMDAC; + SiSSetFlag=0; + SiSSetCRT2Group(BaseAddr,ROMAddr,SenseModeNo,HwDeviceExtension); + /* here perform I/O delay ,read SR 05 */ + for(i=0;i<0x7FFF;i++) { + flag1=SiSGetReg1(SiSP3c4,0x05); } } - SetReg1(Part2Port,0x00,0x1C); //Set part2 index 0= 0x1C + SiSSetReg1(Part2Port,0x00,0x1C); /* Set part2 index 0= 0x1C */ tempah=0; - OutputSelect=*((UCHAR *)(ROMAddr+0xFE)); //OutputSelect 0:FE in Rompost.asm - if(OutputSelect&SetSCARTOutput){ + OutputSelect=*((UCHAR *)(ROMAddr+0xFE)); /* OutputSelect 0:FE in Rompost.asm */ + if (OutputSelect&SetSCARTOutput) { tempal=SCARTSense; - }else{ + } else { tempal=Monitor2Sense; } tempbx=RGBSenseData; tempcx=0x0E08; - if(Sense(Part4Port,tempbx,tempcx)){ - if(Sense(Part4Port,tempbx,tempcx)){ + if (SiSSense(Part4Port,tempbx,tempcx)) { + if (SiSSense(Part4Port,tempbx,tempcx)) { tempah=tempah|tempal; } } tempbx=YCSenseData; tempcx=0x0604; - if(Sense(Part4Port,tempbx,tempcx)){ - if(Sense(Part4Port,tempbx,tempcx)){ + if (SiSSense(Part4Port,tempbx,tempcx)) { + if (SiSSense(Part4Port,tempbx,tempcx)) { tempah=tempah|SVIDEOSense; - //Skipped lines about HiTVSense, assuming not HiTV + /* Skipped lines about HiTVSense, assuming not HiTV */ } } - //Assuming not HiTV ,below is of ifndef HiVisionTV - if(OutputSelect&BoardTVType){ + /* Assuming not HiTV ,below is of ifndef HiVisionTV */ + if (OutputSelect&BoardTVType) { tempbx=VideoSenseData; tempcx=0x0804; - if(Sense(Part4Port,tempbx,tempcx)){ - if(Sense(Part4Port,tempbx,tempcx)){ + if (SiSSense(Part4Port,tempbx,tempcx)) { + if (SiSSense(Part4Port,tempbx,tempcx)) { tempah=tempah|AVIDEOSense; } } - }else{ - if(!(tempah&SVIDEOSense)){ + } else { + if (!(tempah&SVIDEOSense)) { tempbx=VideoSenseData; tempcx=0x0804; - if(Sense(Part4Port,tempbx,tempcx)){ - if(Sense(Part4Port,tempbx,tempcx)){ + if (SiSSense(Part4Port,tempbx,tempcx)) { + if (SiSSense(Part4Port,tempbx,tempcx)) { tempah=tempah|AVIDEOSense; } } } } - //end of ifndef HivisionTv - if(SenseLCD(HwDeviceExtension,Part4Port,ROMAddr)){ - if(SenseLCD(HwDeviceExtension,Part4Port,ROMAddr)){ + /* end of ifndef HivisionTv */ + if (SiSSenseLCD(HwDeviceExtension,Part4Port,ROMAddr)) { + if (SiSSenseLCD(HwDeviceExtension,Part4Port,ROMAddr)) { tempah=tempah|LCDSense; } } tempbx=0; tempcx=0; - Sense(Part4Port,tempbx,tempcx); + SiSSense(Part4Port,tempbx,tempcx); - SetRegANDOR(P3d4,0x32,~0x5F,tempah); //Set CR 32 - SetReg1(Part2Port,0x00,P2reg0); //recover Part2 reg index 0 + SiSSetRegANDOR(SiSP3d4,0x32,~0x5F,tempah); /* Set CR 32 */ + SiSSetReg1(Part2Port,0x00,P2reg0); /* recover Part2 reg index 0 */ - //here skipped lines about DisableCRT2Display + /* here skipped lines about DisableCRT2Display */ return 0; } -BOOLEAN Sense(USHORT Part4Port,USHORT inputbx,USHORT inputcx) +BOOLEAN SiSSense(USHORT Part4Port,USHORT inputbx,USHORT inputcx) { USHORT tempah,tempcl,tempch; tempah=inputbx&0xFF; - SetReg1(Part4Port,0x11,tempah);//Part4 index 11 + SiSSetReg1(Part4Port,0x11,tempah);/* Part4 index 11 */ tempah=(inputbx&0xFF00)>>8; tempcl=inputcx&0xFF; tempah=tempah|tempcl; - SetRegANDOR(Part4Port,0x10,~0x1F,tempah);//Part4 index 10 + SiSSetRegANDOR(Part4Port,0x10,~0x1F,tempah);/* Part4 index 10 */ tempch=(inputcx&0xFF00)>>8; tempch=tempch&0x7F; - //here skipped lines about call Delay - tempah=GetReg1(Part4Port,0x03); //Part4 index 03 + /* here skipped lines about call Delay */ + tempah=SiSGetReg1(Part4Port,0x03); /* Part4 index 03 */ tempah=tempah^(0x0E); tempah=tempah&tempch; - if(tempah>0) return 1; + if (tempah>0) return 1; else return 0; } -BOOLEAN SenseLCD(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT Part4Port,ULONG ROMAddr) +BOOLEAN SiSSenseLCD(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT Part4Port,ULONG ROMAddr) { USHORT SoftSetting; USHORT tempah; - SoftSetting=*((UCHAR *)(ROMAddr+0x52));//0:52 in rompost.asm - if(GetLCDDDCInfo(HwDeviceExtension)){ + SoftSetting=*((UCHAR *)(ROMAddr+0x52));/* 0:52 in rompost.asm */ + if (SiSGetLCDDDCInfo(HwDeviceExtension)) { return 1; } - if(SoftSetting&HotPlugFunction){ - tempah=GetReg1(Part4Port,0x0F); + if (SoftSetting&HotPlugFunction) { + tempah=SiSGetReg1(Part4Port,0x0F); tempah=tempah&0x3F; - SetReg1(Part4Port,0x0F,tempah); //Part4 index 0F - if(Sense(Part4Port,0x0,0x9010)){ + SiSSetReg1(Part4Port,0x0F,tempah); /* Part4 index 0F */ + if (SiSSense(Part4Port,0x0,0x9010)) { return 1; - }else{ + } else { return 0; } - }else{ + } else { return 0; } } -#endif -VOID SetRegANDOR(USHORT Port,USHORT Index,USHORT DataAND,USHORT DataOR) +VOID SiSSetRegANDOR(USHORT Port,USHORT Index,USHORT DataAND,USHORT DataOR) { USHORT temp1; - temp1=GetReg1(Port,Index); //part1port index 02 + temp1=SiSGetReg1(Port,Index); /* part1port index 02 */ temp1=(temp1&(DataAND))|DataOR; - SetReg1(Port,Index,temp1); + SiSSetReg1(Port,Index,temp1); } -BOOLEAN DetectMonitor(PHW_DEVICE_EXTENSION HwDeviceExtension) +BOOLEAN SiSDetectMonitor(PHW_DEVICE_EXTENSION HwDeviceExtension) { USHORT flag1 ; USHORT DAC_TEST_PARMS[3]={0x0F,0x0F,0x0F}; USHORT DAC_CLR_PARMS[3]={0x00,0x00,0x00}; - - flag1=GetReg1(P3c4,0x38); //call BridgeisOn - if((flag1&0x20)){ - SetReg1(P3d4,0x30,0x41); + + flag1=SiSGetReg1(SiSP3c4,0x38); /* call BridgeisOn */ + if ((flag1&0x20)) { + SiSSetReg1(SiSP3d4,0x30,0x41); } - SiSSetMode(HwDeviceExtension,0x2E); //set mode to 0x2E instead of 0x3 + SiSSetMode(HwDeviceExtension,0x2E); /* set mode to 0x2E instead of 0x3 */ - ClearDAC(P3c8); - ClearALLBuffer(HwDeviceExtension); + SiSClearDAC(SiSP3c8); + SiSClearALLBuffer(HwDeviceExtension); - LongWait(); //wait vertical retrace - LongWait(); + SiSLongWait(); /* wait vertical retrace */ + SiSLongWait(); - flag1=TestMonitorType(DAC_TEST_PARMS[0],DAC_TEST_PARMS[1], + flag1=SiSTestMonitorType(DAC_TEST_PARMS[0],DAC_TEST_PARMS[1], DAC_TEST_PARMS[2]); - if(flag1==0){ - flag1=TestMonitorType(DAC_TEST_PARMS[0],DAC_TEST_PARMS[1], + if (flag1==0) { + flag1=SiSTestMonitorType(DAC_TEST_PARMS[0],DAC_TEST_PARMS[1], DAC_TEST_PARMS[2]); } - if(flag1==1){ - SetRegANDOR(P3d4,0x32,~Monitor1Sense,Monitor1Sense); - }else{ - SetRegANDOR(P3d4,0x32,~Monitor1Sense,0x0); + if (flag1==1) { + SiSSetRegANDOR(SiSP3d4,0x32,~Monitor1Sense,Monitor1Sense); + } else { + SiSSetRegANDOR(SiSP3d4,0x32,~Monitor1Sense,0x0); } - TestMonitorType(DAC_CLR_PARMS[0],DAC_CLR_PARMS[1],DAC_CLR_PARMS[2]); + SiSTestMonitorType(DAC_CLR_PARMS[0],DAC_CLR_PARMS[1],DAC_CLR_PARMS[2]); - SetReg1(P3d4,0x34,0x4A); //Preset default CRT1 ModeNo =0x4A - //which is used in SetCRT2FIFO() + SiSSetReg1(SiSP3d4,0x34,0x4A); /* Preset default CRT1 ModeNo =0x4A */ + /* which is used in SiSSetCRT2FIFO() */ return 1; } -BOOLEAN TestMonitorType(USHORT d1,USHORT d2,USHORT d3) +BOOLEAN SiSTestMonitorType(USHORT d1,USHORT d2,USHORT d3) { USHORT temp; - SetReg3(P3c6,0xFF); - SetReg3(P3c8,0x00); - SetReg3(P3c9,d1); - SetReg3(P3c9,d2); - SetReg3(P3c9,d3); - WaitDisplay(); //wait horizontal retrace - temp=GetReg2(P3c2); - if(temp&0x10) return 1; + SiSSetReg3(SiSP3c6,0xFF); + SiSSetReg3(SiSP3c8,0x00); + SiSSetReg3(SiSP3c9,d1); + SiSSetReg3(SiSP3c9,d2); + SiSSetReg3(SiSP3c9,d3); + SiSWaitDisplay(); /* wait horizontal retrace */ + temp=SiSGetReg2(SiSP3c2); + if (temp&0x10) return 1; else return 0; } -VOID WaitDisplay(void) +VOID SiSWaitDisplay(VOID) { USHORT temp; - for(temp=0;temp==0;){ - temp=GetReg2(P3da); + for(temp=0;temp==0;) { + temp=SiSGetReg2(SiSP3da); temp=temp&0x01; } - for(;temp==1;){ - temp=GetReg2(P3da); + for(;temp==1;) { + temp=SiSGetReg2(SiSP3da); temp=temp&0x01; } } -VOID LongWait(void) +VOID SiSLongWait() { USHORT temp; - - for(temp=1;temp>0;){ - temp=GetReg2(P3da); - temp=temp&0x08; - } - for(;temp==0;){ - temp=GetReg2(P3da); - temp=temp&0x08; - } -} -#ifndef CONFIG_FB_SIS_LINUXBIOS + USHORT i; + for(i=0; i<0xFFFF; i++) { + temp=SiSGetReg2(SiSP3da); + if (!(temp&0x08)) + break; + } + for(i=0; i<0xFFFF; i++) { + temp=SiSGetReg2(SiSP3da); + if ((temp & 0x09) == 9) + break; + } +} -VOID VBLongWait(VOID) +VOID SiSVBLongWait() { USHORT regsr1f,tempah,temp; - regsr1f=GetReg1(P3c4,0x1F); + regsr1f=SiSGetReg1(SiSP3c4,0x1F); tempah=regsr1f&(~0xC0); - SetReg1(P3c4,0x1F,tempah); + SiSSetReg1(SiSP3c4,0x1F,tempah); - for(temp=1;temp>0;){ - temp=GetReg2(P3da); - temp=temp&0x08; + for(temp=1;temp>0;) { + temp=SiSGetReg2(SiSP3da); + temp=temp&0x08; } - for(;temp==0;){ - temp=GetReg2(P3da); - temp=temp&0x08; + for(;temp==0;) { + temp=SiSGetReg2(SiSP3da); + temp=temp&0x08; } - SetReg1(P3c4,0x1F,regsr1f); - return; + SiSSetReg1(SiSP3c4,0x1F,regsr1f); + return; } -BOOLEAN WaitVBRetrace(USHORT BaseAddr) +BOOLEAN SiSWaitVBRetrace(USHORT BaseAddr) { USHORT temp; USHORT Part1Port; Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - temp=GetReg1(Part1Port,0x00); - if(!(temp&0x80)){ + temp=SiSGetReg1(Part1Port,0x00); + if (!(temp&0x80)) { return 0; } - - for(temp=0;temp==0;){ - temp=GetReg1(Part1Port,0x25); - temp=temp&0x01; - } - for(;temp>0;){ - temp=GetReg1(Part1Port,0x25); - temp=temp&0x01; + + for(temp=0;temp==0;) { + temp=SiSGetReg1(Part1Port,0x25); + temp=temp&0x01; + } + for(;temp>0;) { + temp=SiSGetReg1(Part1Port,0x25); + temp=temp&0x01; } - return 1; + return 1; } -BOOLEAN GetPanelID(VOID) + +BOOLEAN SiSGetPanelID(VOID) { - USHORT PanelTypeTable[16]={ SyncPP|Panel800x600|PanelType00, - SyncPP|Panel1024x768|PanelType01, - SyncPP|Panel1024x768|PanelType02, - SyncPP|Panel1024x768|PanelType03, - SyncPP|Panel1024x768|PanelType04, - SyncPP|Panel1024x768|PanelType05, - SyncPP|Panel1024x768|PanelType06, - SyncPP|Panel1024x768|PanelType07, - SyncPP|Panel1024x768|PanelType08, - SyncPP|Panel1024x768|PanelType09, - SyncPP|Panel800x600|PanelType0A, - SyncPP|Panel1024x768|PanelType0B, - SyncPP|Panel1024x768|PanelType0C, - SyncPP|Panel1024x768|PanelType0D, - SyncPP|Panel1024x768|PanelType0E, - SyncPP|Panel1024x768|PanelType0F}; - // Bit 15 BPLVSPLTY - // Bit 14 BPLHSPLTY - // Bit 6-3 Panel Type - // Bit 2-0 Display Resolution(001:800x600 010:1024x768 011:1280x1024) + USHORT PanelTypeTable[16]={ + SyncPP|Panel800x600|PanelType00, + SyncPP|Panel1024x768|PanelType01, + SyncPP|Panel1024x768|PanelType02, + SyncPP|Panel1024x768|PanelType03, + SyncPP|Panel1024x768|PanelType04, + SyncPP|Panel1024x768|PanelType05, + SyncPP|Panel1024x768|PanelType06, + SyncPP|Panel1024x768|PanelType07, + SyncPP|Panel1024x768|PanelType08, + SyncPP|Panel1024x768|PanelType09, + SyncPP|Panel800x600|PanelType0A, + SyncPP|Panel1024x768|PanelType0B, + SyncPP|Panel1024x768|PanelType0C, + SyncPP|Panel1024x768|PanelType0D, + SyncPP|Panel1024x768|PanelType0E, + SyncPP|Panel1024x768|PanelType0F + }; + /* Bit 15 BPLVSPLTY */ + /* Bit 14 BPLHSPLTY */ + /* Bit 6-3 Panel Type */ + /* Bit 2-0 Display Resolution(001:800x600 010:1024x768 011:1280x1024) */ USHORT tempah,tempbx; USHORT return_flag; - tempah=GetReg1(P3c4,0x18); + tempah=SiSGetReg1(SiSP3c4,0x18); tempbx=tempah&0x0F; - if(tempah&0x10){ + if (tempah&0x10) { return_flag=1; - }else{ + } else { return_flag=0; } - if(return_flag==0){ - if(IF_DEF_LVDS==1){ + if (return_flag==0) { + if (SIS_IF_DEF_LVDS==1) { tempbx=0; - tempah=GetReg1(P3c4,0x38); - if(tempah&0x40) tempbx=tempbx|0x08; - if(tempah&0x20) tempbx=tempbx|0x02; - if(tempah&0x01) tempbx=tempbx|0x01; - tempah=GetReg1(P3c4,0x39); - if(tempah&0x80) tempbx=tempbx|0x04; - }else{ + tempah=SiSGetReg1(SiSP3c4,0x38); + if (tempah&0x40) tempbx=tempbx|0x08; + if (tempah&0x20) tempbx=tempbx|0x02; + if (tempah&0x01) tempbx=tempbx|0x01; + tempah=SiSGetReg1(SiSP3c4,0x39); + if (tempah&0x80) tempbx=tempbx|0x04; + } else { return 0; } } - if(IF_DEF_TRUMPION==1){ + if (SIS_IF_DEF_TRUMPION==1) { tempbx=1; } - tempbx=PanelTypeTable[tempbx]; //LVDS table entry + tempbx=PanelTypeTable[tempbx]; /* LVDS table entry */ tempbx=tempbx|(USHORT)(LCDSync<<8); tempah=tempbx&0x0FF; - SetReg1(P3d4,0x36,tempah); + SiSSetReg1(SiSP3d4,0x36,tempah); tempah=(tempbx&0xFF00)>>8; - SetRegANDOR(P3d4,0x37,~LCDSyncBit,tempah); + SiSSetRegANDOR(SiSP3d4,0x37,~LCDSyncBit,tempah); return 1; } -VOID ModCRT1CRTC(ULONG ROMAddr,USHORT ModeNo) +VOID SiSModCRT1CRTC(ULONG ROMAddr,USHORT ModeNo) { USHORT OldREFIndex,temp,tempah,i,modeflag1; - - OldREFIndex=(USHORT)REFIndex; - temp=GetLVDSCRT1Ptr(ROMAddr,ModeNo); - if(temp==0){ - REFIndex=OldREFIndex; + USHORT uSRData; + + OldREFIndex=(USHORT)SiSREFIndex; + temp=SiSGetLVDSCRT1Ptr(ROMAddr,ModeNo); + if (temp==0) { + SiSREFIndex=OldREFIndex; return; } - tempah=(UCHAR)GetReg1(P3d4,0x11);//unlock cr0-7 + tempah=(UCHAR)SiSGetReg1(SiSP3d4,0x11);/*unlock cr0-7 */ tempah=tempah&0x7F; - SetReg1(P3d4,0x11,tempah); - tempah=*((UCHAR *)(ROMAddr+REFIndex)); - SetReg1(P3d4,0x0,tempah); - REFIndex++; - for(i=0x02;i<=0x05;REFIndex++){ - tempah=*((UCHAR *)(ROMAddr+REFIndex)); - SetReg1(P3d4,i,tempah); - } - for(i=0x06;i<=0x07;REFIndex++){ - tempah=*((UCHAR *)(ROMAddr+REFIndex)); - SetReg1(P3d4,i,tempah); - } - for(i=0x10;i<=0x11;REFIndex++){ - tempah=*((UCHAR *)(ROMAddr+REFIndex)); - SetReg1(P3d4,i,tempah); - } - for(i=0x15;i<=0x16;REFIndex++){ - tempah=*((UCHAR *)(ROMAddr+REFIndex)); - SetReg1(P3d4,i,tempah); - } - - for(i=0x0A;i<=0x0C;REFIndex++){ - tempah=*((UCHAR *)(ROMAddr+REFIndex)); - SetReg1(P3c4,i,tempah); + SiSSetReg1(SiSP3d4,0x11,tempah); + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex)); + SiSSetReg1(SiSP3d4,0x0,tempah); + SiSREFIndex++; + for(i=0x02;i<=0x05;SiSREFIndex++,i++) { + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex)); + SiSSetReg1(SiSP3d4,i,tempah); + } + for(i=0x06;i<=0x07;SiSREFIndex++,i++) { + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex)); + SiSSetReg1(SiSP3d4,i,tempah); + } + for(i=0x10;i<=0x11;SiSREFIndex++,i++) { + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex)); + SiSSetReg1(SiSP3d4,i,tempah); + } + for(i=0x15;i<=0x16;SiSREFIndex++,i++) { + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex)); + SiSSetReg1(SiSP3d4,i,tempah); + } + + for(i=0x0A;i<=0x0C;SiSREFIndex++,i++) { + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex)); + SiSSetReg1(SiSP3c4,i,tempah); } - tempah=*((UCHAR *)(ROMAddr+REFIndex)); + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex)); tempah=tempah&0x0E0; - SetReg1(P3c4,0x0E,tempah); - - tempah=*((UCHAR *)(ROMAddr+REFIndex)); + uSRData=(UCHAR)SiSGetReg1(SiSP3c4,0x0E); + uSRData&=0x1F; + tempah |= uSRData; + SiSSetReg1(SiSP3c4,0x0E,tempah); + + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex)); tempah=tempah&0x01; tempah=tempah<<5; - modeflag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - if(modeflag1&DoubleScanMode){ + modeflag1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); /* si+St_ModeFlag */ + if (modeflag1&DoubleScanMode) { tempah=tempah|0x080; } - SetRegANDOR(P3d4,0x09,~0x020,tempah); - REFIndex=OldREFIndex; + SiSSetRegANDOR(SiSP3d4,0x09,~0x020,tempah); + SiSREFIndex=OldREFIndex; return; } -VOID SetCRT2ECLK(ULONG ROMAddr, USHORT ModeNo) +VOID SiSSetCRT2ECLK(ULONG ROMAddr, USHORT ModeNo) { USHORT OldREFIndex,tempah,tempal; - USHORT P3cc=P3c9+3; - OldREFIndex=(USHORT)REFIndex; - if(IF_DEF_TRUMPION==0){ //no trumpion - tempal=GetReg2(P3cc); + USHORT P3cc=SiSP3c9+3; + + OldREFIndex=(USHORT)SiSREFIndex; + if (SIS_IF_DEF_TRUMPION==0) { /*no trumpion */ + tempal=SiSGetReg2(P3cc); tempal=tempal&0x0C; - SetReg3(P3c2,tempal); - REFIndex=GetVCLKPtr(ROMAddr,ModeNo); - }else{ //trumpion - SetFlag=SetFlag&(~ProgrammingCRT2); - tempal=*((UCHAR *)(ROMAddr+REFIndex+0x03)); //di+Ext_CRTVCLK + SiSREFIndex=SiSGetVCLK2Ptr(ROMAddr,ModeNo); + } else { /*trumpion */ + SiSSetFlag=SiSSetFlag&(~ProgrammingCRT2); + tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+0x03)); /*&di+Ext_CRTVCLK */ tempal=tempal&0x03F; - if(tempal==0x02){ //31.5MHz - REFIndex=REFIndex-Ext2StructSize; + if (tempal==0x02) { /*31.5MHz */ + SiSREFIndex=SiSREFIndex-Ext2StructSize; } - REFIndex=GetVCLKPtr(ROMAddr,ModeNo); - SetFlag=SetFlag|ProgrammingCRT2; + SiSREFIndex=SiSGetVCLKPtr(ROMAddr,ModeNo); + SiSSetFlag=SiSSetFlag|ProgrammingCRT2; } tempal=0x02B; - if(!(VBInfo&SetInSlaveMode)){ - tempal=tempal+3; + if (!(SiSVBInfo&SetInSlaveMode)) { + tempal=tempal+3; } - tempah=*((UCHAR *)(ROMAddr+REFIndex)); - SetReg1(P3c4,tempal,tempah); - tempah=*((UCHAR *)(ROMAddr+REFIndex+1)); + SiSSetReg1(SiSP3c4,0x05,0x86); + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex)); + SiSSetReg1(SiSP3c4,tempal,tempah); + tempah=*((UCHAR *)(ROMAddr+SiSREFIndex+1)); tempal++; - SetReg1(P3c4,tempal,tempah); - REFIndex=OldREFIndex; + SiSSetReg1(SiSP3c4,tempal,tempah); + tempal++; + SiSSetReg1(SiSP3c4,tempal,0x80); + SiSREFIndex=OldREFIndex; return; } -USHORT GetLVDSDesPtr(ULONG ROMAddr,USHORT ModeNo) +USHORT SiSGetLVDSDesPtr(ULONG ROMAddr,USHORT ModeNo) { USHORT tempcl,tempbx,tempal,tempptr,LVDSDesPtrData; + USHORT Flag; + + Flag=1; + tempbx=0; + if (SIS_IF_DEF_CH7005==1) { + if (!(SiSVBInfo&SetCRT2ToLCD)) { + Flag=0; + tempbx=32; + if (SiSVBInfo&SetPALTV) tempbx=tempbx+2; + if (SiSVBInfo&SetCHTVOverScan) tempbx=tempbx+1; + } + } tempcl=LVDSDesDataLen; - tempbx=LCDTypeInfo; - if(LCDInfo&LCDNonExpanding){ - tempbx=tempbx+16; - } - if(ModeNo<=0x13){ - tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x04)); // si+St_CRT2CRTC - }else{ - tempal=*((UCHAR *)(ROMAddr+REFIndex+4)); //di+Ext_CRT2CRTC - } + if (Flag) { + tempbx=SiSLCDTypeInfo; + if (SiSLCDInfo&LCDNonExpanding) { + tempbx=tempbx+16; + } + } + if (ModeNo<=0x13) tempal=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x04)); /* si+St_CRT2CRTC */ + else tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+4)); /*di+Ext_CRT2CRTC */ tempal=tempal&0x1F; tempal=tempal*tempcl; tempbx=tempbx<<1; @@ -2830,39 +3106,321 @@ tempptr=*((USHORT *)(ROMAddr+LVDSDesPtrData+tempbx)); tempptr=tempptr+tempal; return(tempptr); - } -BOOLEAN GetLVDSCRT1Ptr(ULONG ROMAddr,USHORT ModeNo) +BOOLEAN SiSGetLVDSCRT1Ptr(ULONG ROMAddr,USHORT ModeNo) { USHORT tempal,tempbx,modeflag1; - USHORT LVDSCRT1DataPtr; + USHORT LVDSCRT1DataPtr,Flag; - if(!(VBInfo&SetInSlaveMode)){ - return 0; + if (!(SiSVBInfo&SetInSlaveMode)) { + /* return 0; */ } - if(ModeNo<=0x13){ - tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x04)); // si+St_CRT2CRTC - }else{ - tempal=*((UCHAR *)(ROMAddr+REFIndex+4)); //di+Ext_CRT2CRTC + + Flag=1; + tempbx=0; + if (SIS_IF_DEF_CH7005==1) { + if (!(SiSVBInfo&SetCRT2ToLCD)) { + Flag=0; + tempbx=12; + if (SiSVBInfo&SetPALTV) tempbx=tempbx+2; + if (SiSVBInfo&SetCHTVOverScan) tempbx=tempbx+1; + } + } + if (Flag) { + tempbx=SiSLCDResInfo; + tempbx=tempbx-Panel800x600; + if (SiSLCDInfo&LCDNonExpanding) tempbx=tempbx+6; + modeflag1=*((USHORT *)(ROMAddr+SiSModeIDOffset+0x01)); /* si+St_ModeFlag */ + if (modeflag1&HalfDCLK) tempbx=tempbx+3; } + if (ModeNo<=0x13) tempal=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x04)); /* si+St_CRT2CRTC */ + else tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+4)); /*di+Ext_CRT2CRTC */ tempal=tempal&0x3F; - tempbx=LCDResInfo; - tempbx=tempbx-Panel800x600; - if(LCDInfo&LCDNonExpanding){ - tempbx=tempbx+6; - } - modeflag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - if(modeflag1&HalfDCLK){ - tempbx=tempbx+3; - } tempbx=tempbx<<1; + LVDSCRT1DataPtr=*((USHORT *)(ROMAddr+ADR_LVDSCRT1DataPtr)); - REFIndex=*((USHORT *)(ROMAddr+LVDSCRT1DataPtr+tempbx)); + SiSREFIndex=*((USHORT *)(ROMAddr+LVDSCRT1DataPtr+tempbx)); tempal=tempal*LVDSCRT1Len; - REFIndex=REFIndex+tempal; + SiSREFIndex=SiSREFIndex+tempal; return 1; } -#endif +VOID SiSSetCHTVReg(ULONG ROMAddr,USHORT ModeNo) +{ + USHORT old_REFIndex,temp,tempbx,tempcl; + + old_REFIndex=(USHORT)SiSREFIndex; /*push di */ + SiSGetCHTVRegPtr(ROMAddr,ModeNo); + + if (SiSVBInfo&SetPALTV) { + SiSSetCH7005(0x4304); + SiSSetCH7005(0x6909); + } + else { + SiSSetCH7005(0x0304); + SiSSetCH7005(0x7109); + } + + temp=*((USHORT *)(ROMAddr+SiSREFIndex+0x00)); + tempbx=((temp&0x00FF)<<8)|0x00; + SiSSetCH7005(tempbx); + temp=*((USHORT *)(ROMAddr+SiSREFIndex+0x01)); + tempbx=((temp&0x00FF)<<8)|0x07; + SiSSetCH7005(tempbx); + temp=*((USHORT *)(ROMAddr+SiSREFIndex+0x02)); + tempbx=((temp&0x00FF)<<8)|0x08; + SiSSetCH7005(tempbx); + temp=*((USHORT *)(ROMAddr+SiSREFIndex+0x03)); + tempbx=((temp&0x00FF)<<8)|0x0A; + SiSSetCH7005(tempbx); + temp=*((USHORT *)(ROMAddr+SiSREFIndex+0x04)); + tempbx=((temp&0x00FF)<<8)|0x0B; + SiSSetCH7005(tempbx); + + SiSSetCH7005(0x2801); + SiSSetCH7005(0x3103); + SiSSetCH7005(0x003D); + SiSSetCHTVRegANDOR(0x0010,0x1F); + SiSSetCHTVRegANDOR(0x0211,0xF8); + SiSSetCHTVRegANDOR(0x001C,0xEF); + + if (!(SiSVBInfo&SetPALTV)) { + if (ModeNo<=0x13) tempcl=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x04)); /* si+St_CRT2CRTC */ + else tempcl=*((UCHAR *)(ROMAddr+SiSREFIndex+4)); /* di+Ext_CRT2CRTC */ + tempcl=tempcl&0x3F; + if (SiSVBInfo&SetCHTVOverScan) { + if (tempcl==0x04) { /* 640x480 underscan */ + SiSSetCHTVRegANDOR(0x0020,0xEF); + SiSSetCHTVRegANDOR(0x0121,0xFE); + } else { + if (tempcl==0x05) { /* 800x600 underscan */ + SiSSetCHTVRegANDOR(0x0118,0xF0); + SiSSetCHTVRegANDOR(0x0C19,0xF0); + SiSSetCHTVRegANDOR(0x001A,0xF0); + SiSSetCHTVRegANDOR(0x001B,0xF0); + SiSSetCHTVRegANDOR(0x001C,0xF0); + SiSSetCHTVRegANDOR(0x001D,0xF0); + SiSSetCHTVRegANDOR(0x001E,0xF0); + SiSSetCHTVRegANDOR(0x001F,0xF0); + SiSSetCHTVRegANDOR(0x0120,0xEF); + SiSSetCHTVRegANDOR(0x0021,0xFE); + } + } + } else { + if (tempcl==0x04) { /* 640x480 overscan */ + SiSSetCHTVRegANDOR(0x0020,0xEF); + SiSSetCHTVRegANDOR(0x0121,0xFE); + } else { + if (tempcl==0x05) { /* 800x600 overscan */ + SiSSetCHTVRegANDOR(0x0118,0xF0); + SiSSetCHTVRegANDOR(0x0F19,0xF0); + SiSSetCHTVRegANDOR(0x011A,0xF0); + SiSSetCHTVRegANDOR(0x0C1B,0xF0); + SiSSetCHTVRegANDOR(0x071C,0xF0); + SiSSetCHTVRegANDOR(0x011D,0xF0); + SiSSetCHTVRegANDOR(0x0C1E,0xF0); + SiSSetCHTVRegANDOR(0x071F,0xF0); + SiSSetCHTVRegANDOR(0x0120,0xEF); + SiSSetCHTVRegANDOR(0x0021,0xFE); + } + } + } + } + + SiSREFIndex=old_REFIndex; +} + +VOID SiSSetCHTVRegANDOR(USHORT tempax,USHORT tempbh) +{ + USHORT tempal,tempah,tempbl; + + tempal=tempax&0x00FF; + tempah=(tempax>>8)&0x00FF; + tempbl=SiSGetCH7005(tempal); + tempbl=(((tempbl&tempbh)|tempah)<<8|tempal); + SiSSetCH7005(tempbl); +} + +VOID SiSGetCHTVRegPtr(ULONG ROMAddr,USHORT ModeNo) +{ + USHORT tempbx,tempal,tempcl,CHTVRegDataPtr; + + if (SiSVBInfo&SetCRT2ToTV) { + tempbx=0; + if (SiSVBInfo&SetPALTV) tempbx=tempbx+2; + if (SiSVBInfo&SetCHTVOverScan) tempbx=tempbx+1; + + if (ModeNo<=0x13) tempal=*((UCHAR *)(ROMAddr+SiSModeIDOffset+0x04)); /* si+St_CRT2CRTC */ + else tempal=*((UCHAR *)(ROMAddr+SiSREFIndex+4)); /* di+Ext_CRT2CRTC */ + tempal=tempal&0x3F; + + tempcl=CHTVRegDataLen; + tempal=tempal*tempcl; + tempbx=tempbx<<1; + + CHTVRegDataPtr=*((USHORT *)(ROMAddr+ADR_CHTVRegDataPtr)); + SiSREFIndex=*((USHORT *)(ROMAddr+CHTVRegDataPtr+tempbx)); + SiSREFIndex=SiSREFIndex+tempal; + } +} + +VOID SiSSetCH7005(USHORT tempbx) +{ + USHORT tempah,temp; + + SiSDDC_Port=0x3c4; + SiSDDC_Index=0x11; + SiSDDC_DataShift=0x00; + SiSDDC_DeviceAddr=0xEA; + + SiSSetSwitchDDC2(); + SiSSetStart(); + tempah=SiSDDC_DeviceAddr; + temp=SiSWriteDDC2Data(tempah); + tempah=tempbx&0x00FF; + temp=SiSWriteDDC2Data(tempah); + tempah=(tempbx&0xFF00)>>8; + temp=SiSWriteDDC2Data(tempah); + SiSSetStop(); +} + +USHORT SiSGetCH7005(USHORT tempbx) +{ + USHORT tempah; + + SiSDDC_Port=0x3c4; + SiSDDC_Index=0x11; + SiSDDC_DataShift=0x00; + SiSDDC_DeviceAddr=0xEA; + SiSDDC_ReadAddr=tempbx; + + SiSSetSwitchDDC2(); + SiSSetStart(); + tempah=SiSDDC_DeviceAddr; + SiSWriteDDC2Data(tempah); + tempah=SiSDDC_ReadAddr; + SiSWriteDDC2Data(tempah); + + SiSSetStart(); + tempah=SiSDDC_DeviceAddr; + tempah=tempah|0x01; + if (SiSWriteDDC2Data(tempah)) { + } + tempah=SiSReadDDC2Data(tempah); + SiSSetStop(); + return(tempah); +} + +VOID SiSSetSwitchDDC2(VOID) +{ + USHORT i; + + SiSSetSCLKHigh(); + for(i=0;i<1000;i++) { + SiSGetReg1(SiSDDC_Port,0x05); + } + SiSSetSCLKLow(); + for(i=0;i<1000;i++) { + SiSGetReg1(SiSDDC_Port,0x05); + } +} + + +VOID SiSSetStart(VOID) +{ + SiSSetSCLKLow(); + SiSSetRegANDOR(SiSDDC_Port,SiSDDC_Index,0xFD,0x02); /* SetSDA(0x01); */ + SiSSetSCLKHigh(); + SiSSetRegANDOR(SiSDDC_Port,SiSDDC_Index,0xFD,0x00); /* SetSDA(0x00); */ + SiSSetSCLKHigh(); +} + +VOID SiSSetStop(VOID) +{ + SiSSetSCLKLow(); + SiSSetRegANDOR(SiSDDC_Port,SiSDDC_Index,0xFD,0x00); /* SetSDA(0x00); */ + SiSSetSCLKHigh(); + SiSSetRegANDOR(SiSDDC_Port,SiSDDC_Index,0xFD,0x02); /* SetSDA(0x01); */ + SiSSetSCLKHigh(); +} + +USHORT SiSWriteDDC2Data(USHORT tempax) +{ + USHORT i,flag; + + flag=0x80; + for(i=0;i<8;i++) { + SiSSetSCLKLow(); + if (tempax&flag) { + SiSSetRegANDOR(SiSDDC_Port,SiSDDC_Index,0xFD,0x02); + } else { + SiSSetRegANDOR(SiSDDC_Port,SiSDDC_Index,0xFD,0x00); + } + SiSSetSCLKHigh(); + flag=flag>>1; + } + return(SiSCheckACK()); +} + +USHORT SiSReadDDC2Data(USHORT tempax) +{ + USHORT i,temp,getdata; + + getdata=0; + for(i=0;i<8;i++) { + getdata=getdata<<1; + SiSSetSCLKLow(); + SiSSetRegANDOR(SiSDDC_Port,SiSDDC_Index,0xFD,0x02); + SiSSetSCLKHigh(); + temp=SiSGetReg1(SiSDDC_Port,SiSDDC_Index); + if (temp&0x02) getdata=getdata|0x01; + } + return(getdata); +} + +VOID SiSSetSCLKLow(VOID) +{ + SiSSetRegANDOR(SiSDDC_Port,SiSDDC_Index,0xFE,0x00); /* SiSSetSCLKLow() */ + SiSDDC2Delay(); +} + + +VOID SiSSetSCLKHigh(VOID) +{ + USHORT temp; + + SiSSetRegANDOR(SiSDDC_Port,SiSDDC_Index,0xFE,0x01); /* SiSSetSCLKLow() */ + do { + temp=SiSGetReg1(SiSDDC_Port,SiSDDC_Index); + } while(!(temp&0x01)); + SiSDDC2Delay(); +} + +VOID SiSDDC2Delay(VOID) +{ + USHORT i; + + for(i=0;i<DDC2DelayTime;i++) { + SiSGetReg1(SiSP3c4,0x05); + } +} + +USHORT SiSCheckACK(VOID) +{ + USHORT tempah; + + SiSSetSCLKLow(); + SiSSetRegANDOR(SiSDDC_Port,SiSDDC_Index,0xFD,0x02); + SiSSetSCLKHigh(); + tempah=SiSGetReg1(SiSDDC_Port,SiSDDC_Index); + SiSSetSCLKLow(); + if (tempah&0x01) return(1); + else return(0); +} + + + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/sis/sis_301.h linux.ac/drivers/video/sis/sis_301.h --- linux.vanilla/drivers/video/sis/sis_301.h Tue Apr 3 17:32:25 2001 +++ linux.ac/drivers/video/sis/sis_301.h Tue Apr 3 17:55:09 2001 @@ -1,22 +1,74 @@ -#include <linux/config.h> -#include "initdef.h" +#include "sis.h" -USHORT SetFlag,RVBHCFACT,RVBHCMAX,VGAVT,VGAHT,VT,HT,VGAVDE,VGAHDE; -USHORT VDE,HDE,RVBHRS,NewFlickerMode,RY1COE,RY2COE,RY3COE,RY4COE; -extern USHORT LCDResInfo,LCDTypeInfo,LCDInfo; -USHORT VCLKLen; -USHORT LCDHDES,LCDVDES; +USHORT SiSSetFlag,SiSRVBHCFACT,SiSRVBHCMAX,SiSVGAVT,SiSVGAHT,SiSVT,SiSHT,SiSVGAVDE,SiSVGAHDE; +USHORT SiSVDE,SiSHDE,SiSRVBHRS,SiSNewFlickerMode,SiSRY1COE,SiSRY2COE,SiSRY3COE,SiSRY4COE; +USHORT SiSVCLKLen; +USHORT SiSLCDHDES,SiSLCDVDES; +USHORT SiSDDC_Port; +USHORT SiSDDC_Index; +USHORT SiSDDC_DataShift; +USHORT SiSDDC_DeviceAddr; +USHORT SiSDDC_Flag; +USHORT SiSDDC_ReadAddr; +USHORT SiSDDC_Buffer; -USHORT StResInfo[5][2]={{640,400},{640,350},{720,400},{720,350},{640,480}}; +USHORT SiSStResInfo[5][2]={{640,400},{640,350},{720,400},{720,350},{640,480}}; -USHORT ModeResInfo[15][4]={{320,200,8,8},{320,240,8,8},{320,400,8,8}, +USHORT SiSModeResInfo[15][4]={{320,200,8,8},{320,240,8,8},{320,400,8,8}, {400,300,8,8},{512,384,8,8},{640,400,8,16}, {640,480,8,16},{800,600,8,16},{1024,768,8,16}, {1280,1024,8,16},{1600,1200,8,16},{1920,1440,8,16}, {720,480,8,16},{720,576,8,16},{1280,960,8,16}}; +USHORT SiSHiTVExtTiming[61]={0x32,0x65,0x2C,0x5F,0x08,0x31,0x3A,0x64, + 0x28,0x02,0x01,0x3D,0x06,0x3E,0x35,0x6D, + 0x06,0x14,0x3E,0x35,0x6D,0x00,0xC5,0x3F, + 0x64,0x90,0x33,0x8C,0x18,0x36,0x3E,0x13, + 0x2A,0xDE,0x2A,0x44,0x40,0x2A,0x44,0x40, + 0x8E,0x8E,0x82,0x07,0x0B, + 0x92,0x0F,0x40,0x60,0x80,0x14,0x90,0x8C, + 0x60,0x14,0x3D,0x63,0x4F, + 0x027,0xFFFC,0x6A}; +USHORT SiSHiTVSt1Timing[61]={0x32,0x65,0x2C,0x5F,0x08,0x31,0x3A,0x65, + 0x28,0x02,0x01,0x3D,0x06,0x3E,0x35,0x6D, + 0x06,0x14,0x3E,0x35,0x6D,0x00,0xC5,0x3F, + 0x65,0x90,0x7B,0xA8,0x03,0xF0,0x87,0x03, + 0x11,0x15,0x11,0xCF,0x10,0x11,0xCF,0x10, + 0x35,0x35,0x3B,0x69,0x1D, + 0x92,0x0F,0x40,0x60,0x80,0x14,0x90,0x8C, + 0x60,0x04,0x86,0xAF,0x5D, + 0xE,0xFFFC,0x2D}; + +USHORT SiSHiTVSt2Timing[61]={0x32,0x65,0x2C,0x5F,0x08,0x31,0x3A,0x64, + 0x28,0x02,0x01,0x3D,0x06,0x3E,0x35,0x6D, + 0x06,0x14,0x3E,0x35,0x6D,0x00,0xC5,0x3F, + 0x64,0x90,0x33,0x8C,0x18,0x36,0x3E,0x13, + 0x2A,0xDE,0x2A,0x44,0x40,0x2A,0x44,0x40, + 0x8E,0x8E,0x82,0x07,0x0B, + 0x92,0x0F,0x40,0x60,0x80,0x14,0x90,0x8C, + 0x60,0x14,0x3D,0x63,0x4F, + 0x27,0xFFFC,0x6A}; + +USHORT SiSHiTVTextTiming[61]={0x32,0x65,0x2C,0x5F,0x08,0x31,0x3A,0x65, + 0x28,0x02,0x01,0x3D,0x06,0x3E,0x35,0x6D, + 0x06,0x14,0x3E,0x35,0x6D,0x00,0xC5,0x3F, + 0x65,0x90,0xE7,0xBC,0x03,0x0C,0x97,0x03, + 0x14,0x78,0x14,0x08,0x20,0x14,0x08,0x20, + 0xC8,0xC8,0x3B,0xD2,0x26, + 0x92,0x0F,0x40,0x60,0x80,0x14,0x90,0x8C, + 0x60,0x04,0x96,0x72,0x5C, + 0x11,0xFFFC,0x32}; + +USHORT SiSHiTVGroup3Text[63]={0x00,0x1A,0x22,0x63,0x62,0x22,0x08,0xA7, + 0xF5,0x20,0xCE,0xCE,0x55,0x47,0x2A,0xA6, + 0x25,0x2F,0x47,0xFA,0xC8,0xFF,0x8E,0x20, + 0x8C,0x6E,0x60,0x18,0x2C,0x0C,0x20,0x22, + 0x56,0x36,0x4F,0x6E,0x3F,0x80,0x00,0x80, + 0x93,0x3C,0x01,0x50,0x2F,0x10,0xF4,0xCA, + 0x01,0x05,0x03,0x7E,0x65,0x31,0x14,0x75, + 0x18,0x05,0x18,0x05,0x4C,0xA8,0x01}; -USHORT NTSCTiming[61]={0x017,0x01D,0x003,0x009,0x005,0x006,0x00C,0x00C, +USHORT SiSNTSCTiming[61]={0x017,0x01D,0x003,0x009,0x005,0x006,0x00C,0x00C, 0x094,0x049,0x001,0x00A,0x006,0x00D,0x004,0x00A, 0x006,0x014,0x00D,0x004,0x00A,0x000,0x085,0x01B, 0x00C,0x050,0x000,0x099,0x000,0x0EC,0x04A,0x017, @@ -24,9 +76,9 @@ 0x003,0x00A,0x065,0x09D,0x008, 0x092,0x08F,0x040,0x060,0x080,0x014,0x090,0x08C, 0x060,0x014,0x050,0x000,0x040, - 0x00044,0x002DB,0x0003B};//Ajust xxx + 0x00044,0x002DB,0x0003B}; -USHORT PALTiming[61]={ 0x019,0x052,0x035,0x06E,0x004,0x038,0x03D,0x070, +USHORT SiSPALTiming[61]={ 0x019,0x052,0x035,0x06E,0x004,0x038,0x03D,0x070, 0x094,0x049,0x001,0x012,0x006,0x03E,0x035,0x06D, 0x006,0x014,0x03E,0x035,0x06D,0x000,0x045,0x02B, 0x070,0x050,0x000,0x097,0x000,0x0D7,0x05D,0x017, @@ -34,9 +86,9 @@ 0x00D,0x000,0x068,0x0B0,0x00B, 0x092,0x08F,0x040,0x060,0x080,0x014,0x090,0x08C, 0x060,0x014,0x063,0x000,0x040, - 0x0003E,0x002E1,0x00028};//Ajust xxx + 0x0003E,0x002E1,0x00028}; -USHORT HiTVTiming[61]={0x017,0x01D,0x003,0x009,0x005,0x006,0x00C,0x00C, +USHORT SiSHiTVTiming[61]={0x017,0x01D,0x003,0x009,0x005,0x006,0x00C,0x00C, 0x094,0x049,0x001,0x00A,0x006,0x00D,0x004,0x00A, 0x006,0x014,0x00D,0x004,0x00A,0x000,0x085,0x01B, 0x00C,0x050,0x000,0x099,0x000,0x0EC,0x04A,0x017, @@ -44,9 +96,9 @@ 0x003,0x00A,0x065,0x09D,0x008, 0x092,0x08F,0x040,0x060,0x080,0x014,0x090,0x08C, 0x060,0x014,0x050,0x000,0x040, - 0x00027,0x0FFFC,0x0003B};//Ajust xxx + 0x00027,0x0FFFC,0x0003B}; -USHORT HiTVTimingSimu[61]={0x020,0x054,0x02C,0x060,0x008,0x031,0x03A,0x061, +USHORT SiSHiTVTimingSimu[61]={0x020,0x054,0x02C,0x060,0x008,0x031,0x03A,0x061, 0x028,0x002,0x001,0x03D,0x006,0x00D,0x004,0x00A, 0x006,0x014,0x00D,0x004,0x00A,0x000,0x0C5,0x03F, 0x064,0x090,0x000,0x0AA,0x000,0x006,0x060,0x003, @@ -54,9 +106,9 @@ 0x005,0x005,0x034,0x034,0x008, 0x092,0x00F,0x040,0x060,0x080,0x014,0x090,0x08C, 0x060,0x004,0x05F,0x000,0x060, - 0x0000E,0x0FFFC,0x00042};//Ajust xxx + 0x0000E,0x0FFFC,0x00042}; -USHORT HiTVGroup3Data[63]={0x000,0x01A,0x022,0x063,0x062,0x022,0x008,0x05B, +USHORT SiSHiTVGroup3Data[63]={0x000,0x01A,0x022,0x063,0x062,0x022,0x008,0x05B, 0x0FF,0x021,0x0AD,0x0AD,0x055,0x077,0x02A,0x0A6, 0x025,0x02F,0x047,0x0FA,0x0C8,0x0FF,0x08E,0x020, 0x08C,0x06E,0x060,0x02D,0x056,0x047,0x070,0x044, @@ -65,7 +117,7 @@ 0x014,0x005,0x003,0x07E,0x064,0x031,0x014,0x075, 0x018,0x005,0x018,0x005,0x04C,0x0A8,0x001}; -USHORT HiTVGroup3Simu[63]={0x000,0x01A,0x022,0x063,0x062,0x022,0x008,0x094, +USHORT SiSHiTVGroup3Simu[63]={0x000,0x01A,0x022,0x063,0x062,0x022,0x008,0x094, 0x0DA,0x020,0x0B7,0x0B7,0x055,0x047,0x02A,0x0A6, 0x025,0x02F,0x047,0x0FA,0x0C8,0x0FF,0x08E,0x020, 0x08C,0x06E,0x060,0x015,0x026,0x0D3,0x0E4,0x011, @@ -74,7 +126,7 @@ 0x001,0x005,0x003,0x07E,0x065,0x031,0x014,0x075, 0x018,0x005,0x018,0x005,0x04C,0x0A8,0x001}; -USHORT NTSCGroup3Data[63]= {0x000,0x014,0x015,0x025,0x055,0x015,0x00B,0x089, +USHORT SiSNTSCGroup3Data[63]= {0x000,0x014,0x015,0x025,0x055,0x015,0x00B,0x089, 0x0D7,0x040,0x0B0,0x0B0,0x0FF,0x0C4,0x045,0x0A6, 0x025,0x02F,0x067,0x0F6,0x0BF,0x0FF,0x08E,0x020, 0x08C,0x0DA,0x060,0x092,0x0C8,0x055,0x08B,0x000, @@ -83,7 +135,7 @@ 0x000,0x051,0x00F,0x00F,0x008,0x00F,0x008,0x06F, 0x018,0x005,0x005,0x005,0x04C,0x0AA,0x001}; -USHORT PALGroup3Data[63]={0x000,0x01A,0x022,0x063,0x062,0x022,0x008,0x085, +USHORT SiSPALGroup3Data[63]={0x000,0x01A,0x022,0x063,0x062,0x022,0x008,0x085, 0x0C3,0x020,0x0A4,0x0A4,0x055,0x047,0x02A,0x0A6, 0x025,0x02F,0x047,0x0FA,0x0C8,0x0FF,0x08E,0x020, 0x08C,0x0DC,0x060,0x092,0x0C8,0x04F,0x085,0x000, @@ -92,133 +144,143 @@ 0x000,0x048,0x0FE,0x07E,0x008,0x040,0x008,0x091, 0x018,0x005,0x018,0x005,0x04C,0x0A8,0x001}; -VOID overwriteregs(ULONG ROMAddr, USHORT BaseAddr); -VOID SetDefCRT2ExtRegs(USHORT BaseAddr); -BOOLEAN SetCRT2Group(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, - PHW_DEVICE_EXTENSION HwDeviceExtension); -USHORT GetRatePtrCRT2(ULONG ROMAddr, USHORT ModeNo); -BOOLEAN AjustCRT2Rate(ULONG ROMAddr); -VOID SaveCRT2Info(USHORT ModeNo); -VOID DisableLockRegs(VOID); -VOID DisableCRT2(VOID); -VOID DisableBridge(USHORT BaseAddr); -VOID GetCRT2Data(ULONG ROMAddr,USHORT ModeNo); -VOID GetResInfo(ULONG ROMAddr,USHORT ModeNo); -VOID GetRAMDAC2DATA(ULONG ROMAddr,USHORT ModeNo); -VOID GetCRT2Ptr(ULONG ROMAddr,USHORT ModeNo); -VOID UnLockCRT2(USHORT BaseAddr); -VOID SetCRT2ModeRegs(USHORT BaseAddr,USHORT ModeNo); -VOID SetGroup1(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, - PHW_DEVICE_EXTENSION HwDeviceExtension); -VOID SetCRT2Offset(USHORT Part1Port,ULONG ROMAddr); -USHORT GetOffset(ULONG ROMAddr); -USHORT GetColorDepth(ULONG ROMAddr); -VOID SetCRT2FIFO(USHORT Part1Port,ULONG ROMAddr,USHORT ModeNo, - PHW_DEVICE_EXTENSION HwDeviceExtension); -USHORT GetVCLK(ULONG ROMAddr,USHORT ModeNo, - PHW_DEVICE_EXTENSION HwDeviceExtension); -USHORT GetVCLKPtr(ULONG ROMAddr,USHORT ModeNo); -USHORT GetColorTh(ULONG ROMAddr); -USHORT GetMCLK(ULONG ROMAddr); -USHORT GetMCLKPtr(ULONG ROMAddr); -USHORT GetDRAMType(ULONG ROMAddr); -#ifndef CONFIG_FB_SIS_LINUXBIOS -static USHORT CalcDelay(VOID); -#endif -USHORT GetVCLK2Ptr(ULONG ROMAddr,USHORT ModeNo); -VOID SetCRT2Sync(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo); -VOID GetCRT1Ptr(ULONG ROMAddr); -VOID SetRegANDOR(USHORT Port,USHORT Index,USHORT DataAND,USHORT DataOR); -USHORT GetVGAHT2(VOID); -VOID SetGroup2(USHORT BaseAddr,ULONG ROMAddr); -VOID SetGroup3(USHORT BaseAddr); -VOID SetGroup4(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo); -VOID SetCRT2VCLK(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo); -VOID SetGroup5(USHORT BaseAddr,ULONG ROMAddr); -VOID EnableCRT2(VOID); -VOID LoadDAC2(ULONG ROMAddr,USHORT Part5Port); -VOID WriteDAC2(USHORT Pdata,USHORT dl, USHORT ah, USHORT al, USHORT dh); -VOID LockCRT2(USHORT BaseAddr); -VOID SetLockRegs(VOID); -VOID EnableBridge(USHORT BaseAddr); -USHORT GetLockInfo(USHORT pattern); -VOID GetVBInfo(USHORT BaseAddr,ULONG ROMAddr); -BOOLEAN BridgeIsEnable(USHORT BaseAddr); -BOOLEAN BridgeInSlave(VOID); -BOOLEAN GetLCDResInfo(ULONG ROMAddr,USHORT P3d4); -VOID PresetScratchregister(USHORT P3d4,PHW_DEVICE_EXTENSION HwDeviceExtension); -BOOLEAN GetLCDDDCInfo(PHW_DEVICE_EXTENSION HwDeviceExtension); -VOID SetTVSystem(PHW_DEVICE_EXTENSION HwDeviceExtension,ULONG ROMAddr); -BOOLEAN GetSenseStatus(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr); -BOOLEAN Sense(USHORT Part4Port,USHORT inputbx,USHORT inputcx); -BOOLEAN SenseLCD(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT Part4Port,ULONG ROMAddr); -BOOLEAN TestMonitorType(USHORT d1,USHORT d2,USHORT d3); -VOID WaitDisplay(VOID); -BOOLEAN DetectMonitor(PHW_DEVICE_EXTENSION HwDeviceExtension); -VOID LongWait(VOID); -//VOID ClearALLBuffer(PHW_DEVICE_EXTENSION HwDeviceExtension); -USHORT GetQueueConfig(VOID); -VOID VBLongWait(VOID); -USHORT GetVCLKLen(ULONG ROMAddr); -BOOLEAN WaitVBRetrace(USHORT BaseAddr); -VOID GetLVDSDesData(ULONG ROMAddr,USHORT ModeNo); -VOID ModCRT1CRTC(ULONG ROMAddr,USHORT ModeNo); -VOID SetCRT2ECLK(ULONG ROMAddr, USHORT ModeNo); -VOID GetCRT2Data301(ULONG ROMAddr,USHORT ModeNo); -VOID GetCRT2DataLVDS(ULONG ROMAddr,USHORT ModeNo); -USHORT GetLVDSDesPtr(ULONG ROMAddr,USHORT ModeNo); -VOID SetGroup1_301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, - PHW_DEVICE_EXTENSION HwDeviceExtension); -VOID SetGroup1_LVDS(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, - PHW_DEVICE_EXTENSION HwDeviceExtension); -VOID SetTPData(VOID); -BOOLEAN GetPanelID(VOID); -BOOLEAN GetLVDSCRT1Ptr(ULONG ROMAddr,USHORT ModeNo); - -extern USHORT DRAMType[17][5]; -extern USHORT MDA_DAC[]; -extern USHORT CGA_DAC[]; -extern USHORT EGA_DAC[]; -extern USHORT VGA_DAC[]; - -extern USHORT P3c4,P3d4,P3c0,P3ce,P3c2,P3ca,P3c6,P3c7,P3c8,P3c9,P3da; -extern USHORT flag_clearbuffer; //0:no clear frame buffer 1:clear frame buffer -extern int RAMType; -extern int ModeIDOffset,StandTable,CRT1Table,ScreenOffset,VCLKData,MCLKData, ECLKData; -extern int REFIndex,ModeType; -extern USHORT VBInfo,LCDResInfo,LCDTypeInfo,LCDInfo; -extern USHORT IF_DEF_LVDS,IF_DEF_TRUMPION; - -extern VOID SetMemoryClock(ULONG); -extern VOID SetDRAMSize(PHW_DEVICE_EXTENSION); -extern BOOLEAN SearchModeID(ULONG, USHORT); -extern BOOLEAN CheckMemorySize(ULONG); -extern VOID GetModePtr(ULONG, USHORT); -extern BOOLEAN GetRatePtr(ULONG, USHORT); -extern VOID SetSeqRegs(ULONG); -extern VOID SetMiscRegs(ULONG); -extern VOID SetCRTCRegs(ULONG); -extern VOID SetATTRegs(ULONG); -extern VOID SetGRCRegs(ULONG); -extern VOID ClearExt1Regs(VOID); -extern VOID SetSync(ULONG); -extern VOID SetCRT1CRTC(ULONG); -extern VOID SetCRT1Offset(ULONG); -extern VOID SetCRT1FIFO(ULONG); -extern VOID SetCRT1VCLK(ULONG); -extern VOID LoadDAC(ULONG); -extern VOID DisplayOn(VOID); -extern VOID SetCRT1ModeRegs(ULONG, USHORT); -extern VOID SetVCLKState(ULONG, USHORT); -extern VOID WriteDAC(USHORT, USHORT, USHORT, USHORT); -extern VOID ClearBuffer(PHW_DEVICE_EXTENSION); -//extern VOID ClearDAC(ULONG); -extern void ClearDAC(u16 port); -extern BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension, - USHORT ModeNo); -extern void SetReg1(u16 port, u16 index, u16 data); -extern void SetReg3(u16 port, u16 data); -extern void SetReg4(u16 port, unsigned long data); -extern u8 GetReg1(u16 port, u16 index); -extern u8 GetReg2(u16 port); -extern u32 GetReg3(u16 port); +VOID SiSoverwriteregs(ULONG ROMAddr, USHORT BaseAddr); +VOID SiSSetDefCRT2ExtRegs(USHORT BaseAddr); +BOOLEAN SiSSetCRT2Group(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension); +USHORT SiSGetRatePtrCRT2(ULONG ROMAddr, USHORT ModeNo); +BOOLEAN SiSAjustCRT2Rate(ULONG ROMAddr); +VOID SiSSaveCRT2Info(USHORT ModeNo); +VOID SiSDisableLockRegs(VOID); +VOID SiSDisableCRT2(VOID); +VOID SiSDisableBridge(USHORT BaseAddr); +VOID SiSGetCRT2Data(ULONG ROMAddr,USHORT ModeNo); +VOID SiSGetResInfo(ULONG ROMAddr,USHORT ModeNo); +VOID SiSGetRAMDAC2DATA(ULONG ROMAddr,USHORT ModeNo); +VOID SiSGetCRT2Ptr(ULONG ROMAddr,USHORT ModeNo); +VOID SiSUnLockCRT2(USHORT BaseAddr); +VOID SiSSetCRT2ModeRegs(USHORT BaseAddr,USHORT ModeNo); +VOID SiSSetGroup1(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension); +VOID SiSSetCRT2Offset(USHORT Part1Port,ULONG ROMAddr); +USHORT SiSGetOffset(ULONG ROMAddr); +USHORT SiSGetColorDepth(ULONG ROMAddr); +VOID SiSSetCRT2FIFO(USHORT Part1Port,ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension); +USHORT SiSGetVCLK(ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension); +USHORT SiSGetVCLKPtr(ULONG ROMAddr,USHORT ModeNo); +USHORT SiSGetColorTh(ULONG ROMAddr); +USHORT SiSGetMCLK(ULONG ROMAddr); +USHORT SiSGetMCLKPtr(ULONG ROMAddr); +USHORT SiSGetDRAMType(ULONG ROMAddr); +USHORT SiSGetVCLK2Ptr(ULONG ROMAddr,USHORT ModeNo); +VOID SiSSetCRT2Sync(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo); +VOID SiSGetCRT1Ptr(ULONG ROMAddr); +VOID SiSSetRegANDOR(USHORT Port,USHORT Index,USHORT DataAND,USHORT DataOR); +USHORT SiSGetVGAHT2(VOID); +VOID SiSSetGroup2(USHORT BaseAddr,ULONG ROMAddr); +VOID SiSSetGroup3(USHORT BaseAddr,ULONG ROMAddr); +VOID SiSSetGroup4(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo); +VOID SiSSetCRT2VCLK(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo); +VOID SiSSetGroup5(USHORT BaseAddr,ULONG ROMAddr); +VOID SiSEnableCRT2(VOID); +VOID SiSLoadDAC2(ULONG ROMAddr,USHORT Part5Port); +VOID SiSWriteDAC2(USHORT Pdata,USHORT dl, USHORT ah, USHORT al, USHORT dh); +VOID SiSLockCRT2(USHORT BaseAddr); +VOID SiSSetLockRegs(VOID); +VOID SiSEnableBridge(USHORT BaseAddr); +USHORT SiSGetLockInfo(USHORT pattern); +VOID SiSGetVBInfo(USHORT BaseAddr,ULONG ROMAddr); +BOOLEAN SiSBridgeIsEnable(USHORT BaseAddr); +BOOLEAN SiSBridgeInSlave(VOID); +BOOLEAN SiSGetLCDResInfo(ULONG ROMAddr,USHORT SiSP3d4); +VOID SiSPresetScratchregister(USHORT SiSP3d4,PHW_DEVICE_EXTENSION HwDeviceExtension); +BOOLEAN SiSGetLCDDDCInfo(PHW_DEVICE_EXTENSION HwDeviceExtension); +VOID SiSSetTVSystem(PHW_DEVICE_EXTENSION HwDeviceExtension,ULONG ROMAddr); +BOOLEAN SiSGetSenseStatus(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr); +BOOLEAN SiSSense(USHORT Part4Port,USHORT inputbx,USHORT inputcx); +BOOLEAN SiSSenseLCD(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT Part4Port,ULONG ROMAddr); +BOOLEAN SiSTestMonitorType(USHORT d1,USHORT d2,USHORT d3); +VOID SiSWaitDisplay(VOID); +BOOLEAN SiSDetectMonitor(PHW_DEVICE_EXTENSION HwDeviceExtension); +VOID SiSLongWait(VOID); +USHORT SiSGetQueueConfig(VOID); +VOID SiSVBLongWait(VOID); +USHORT SiSGetVCLKLen(ULONG ROMAddr); +BOOLEAN SiSWaitVBRetrace(USHORT BaseAddr); +VOID SiSGetLVDSDesData(ULONG ROMAddr,USHORT ModeNo); +VOID SiSModCRT1CRTC(ULONG ROMAddr,USHORT ModeNo); +VOID SiSSetCRT2ECLK(ULONG ROMAddr, USHORT ModeNo); +VOID SiSGetCRT2Data301(ULONG ROMAddr,USHORT ModeNo); +VOID SiSGetCRT2DataLVDS(ULONG ROMAddr,USHORT ModeNo); +USHORT SiSGetLVDSDesPtr(ULONG ROMAddr,USHORT ModeNo); +VOID SiSSetGroup1_301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension); +VOID SiSSetGroup1_LVDS(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, + PHW_DEVICE_EXTENSION HwDeviceExtension); +VOID SiSSetTPData(VOID); +BOOLEAN SiSGetPanelID(VOID); +BOOLEAN SiSGetLVDSCRT1Ptr(ULONG ROMAddr,USHORT ModeNo); +VOID SiSSetCHTVReg(ULONG ROMAddr,USHORT ModeNo); +VOID SiSSetCHTVRegANDOR(USHORT tempax,USHORT tempbh); +VOID SiSGetCHTVRegPtr(ULONG ROMAddr,USHORT ModeNo); +VOID SiSSetCH7005(USHORT tempbx); +USHORT SiSGetCH7005(USHORT tempbx); +VOID SiSSetSwitchDDC2(VOID); +VOID SiSSetStart(VOID); +VOID SiSSetStop(VOID); +USHORT SiSWriteDDC2Data(USHORT tempax); +USHORT SiSReadDDC2Data(USHORT tempax); +VOID SiSSetSCLKLow(VOID); +VOID SiSSetSCLKHigh(VOID); +VOID SiSDDC2Delay(VOID); +USHORT SiSCheckACK(VOID); +USHORT SiSCalcDelayVB(VOID); + +extern USHORT SiSDRAMType[17][5]; +extern USHORT SIS_MDA_DAC[]; +extern USHORT SIS_CGA_DAC[]; +extern USHORT SIS_EGA_DAC[]; +extern USHORT SIS_VGA_DAC[]; + +extern USHORT SiSP3c4,SiSP3d4,SiSP3c0,SiSP3ce,SiSP3c2,SiSP3ca,SiSP3c6,SiSP3c7,SiSP3c8,SiSP3c9,SiSP3da; +extern USHORT SiS_flag_clearbuffer; +extern int SiSRAMType; +extern int SiSModeIDOffset,SiSStandTable,SiSCRT1Table,SiSScreenOffset,SiSVCLKData,SiSMCLKData, SiSECLKData; +extern int SiSREFIndex,SiSModeType; +extern USHORT SiSVBInfo,SiSLCDResInfo,SiSLCDTypeInfo,SiSLCDInfo; +extern USHORT SIS_IF_DEF_LVDS,SIS_IF_DEF_TRUMPION,SIS_IF_DEF_CH7005,SIS_IF_DEF_HiVision; + +extern VOID SiSSetMemoryClock(ULONG); +extern VOID SiSSetDRAMSize(PHW_DEVICE_EXTENSION); +extern BOOLEAN SiSSearchModeID(ULONG, USHORT); +extern BOOLEAN SiSCheckMemorySize(ULONG); +extern VOID SiSGetModePtr(ULONG, USHORT); +extern BOOLEAN SiSGetRatePtr(ULONG, USHORT); +extern VOID SiSSetSeqRegs(ULONG); +extern VOID SiSSetMiscRegs(ULONG); +extern VOID SiSSetCRTCRegs(ULONG); +extern VOID SiSSetATTRegs(ULONG); +extern VOID SiSSetGRCRegs(ULONG); +extern VOID SiSClearExt1Regs(VOID); +extern VOID SiSSetSync(ULONG); +extern VOID SiSSetCRT1CRTC(ULONG); +extern VOID SiSSetCRT1Offset(ULONG); +extern VOID SiSSetCRT1FIFO(ULONG); +extern VOID SiSSetCRT1VCLK(ULONG); +extern VOID SiSLoadDAC(ULONG); +extern VOID SiSDisplayOn(VOID); +extern VOID SiSSetCRT1ModeRegs(ULONG, USHORT); +extern VOID SiSSetVCLKState(ULONG, USHORT); +extern VOID SiSWriteDAC(USHORT, USHORT, USHORT, USHORT); +extern BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension, USHORT ModeNo); + +extern VOID sisfb_set_reg1(u16 port, u16 index, u16 data); +extern VOID sisfb_set_reg3(u16 port, u16 data); +extern VOID sisfb_set_reg4(u16 port, unsigned long data); +extern u8 sisfb_get_reg1(u16 port, u16 index); +extern u8 sisfb_get_reg2(u16 port); +extern u32 sisfb_get_reg3(u16 port); +extern VOID sisfb_clear_buffer(PHW_DEVICE_EXTENSION); +extern VOID sisfb_clear_DAC(u16 port); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/sis/sis_main.c linux.ac/drivers/video/sis/sis_main.c --- linux.vanilla/drivers/video/sis/sis_main.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/sis/sis_main.c Tue Apr 3 17:55:10 2001 @@ -1,5 +1,5 @@ /* - * SiS 300/630/540 frame buffer device For Kernal 2.4.x + * SiS 300/630/540/315H/315 frame buffer device For Kernal 2.4.x * * This driver is partly based on the VBE 2.0 compliant graphic * boards framebuffer driver, which is @@ -8,7 +8,6 @@ * */ -#define EXPORT_SYMTAB #undef SISFBDEBUG #include <linux/config.h> @@ -28,8 +27,8 @@ #include <linux/pci.h> #include <linux/vt_kern.h> #include <linux/capability.h> -#include <linux/sisfb.h> #include <linux/fs.h> +#include <linux/agp_backend.h> #include <asm/io.h> #include <asm/mtrr.h> @@ -41,237 +40,12 @@ #include <video/fbcon-cfb32.h> #include "sis.h" +#include "sis_main.h" #ifdef NOBIOS #include "bios.h" #endif -/* ------------------- Constant Definitions ------------------------- */ - -/* capabilities */ -#define TURBO_QUEUE_CAP 0x80 -#define HW_CURSOR_CAP 0x40 - -/* VGA register Offsets */ -#define SEQ_ADR (0x14) -#define SEQ_DATA (0x15) -#define DAC_ADR (0x18) -#define DAC_DATA (0x19) -#define CRTC_ADR (0x24) -#define CRTC_DATA (0x25) - -#define DAC2_ADR 0x16 - 0x30 -#define DAC2_DATA 0x17 - 0x30 - - -/* SiS indexed register indexes */ -#define IND_SIS_PASSWORD (0x05) -#define IND_SIS_DRAM_SIZE (0x14) -#define IND_SIS_MODULE_ENABLE (0x1E) -#define IND_SIS_PCI_ADDRESS_SET (0x20) -#define IND_SIS_TURBOQUEUE_ADR (0x26) -#define IND_SIS_TURBOQUEUE_SET (0x27) - -/* Sis register value */ -#define SIS_PASSWORD (0x86) - -#define SIS_2D_ENABLE (0x40) - -#define SIS_MEM_MAP_IO_ENABLE (0x01) -#define SIS_PCI_ADDR_ENABLE (0x80) - -//#define MMIO_SIZE 0x10000 /* 64K MMIO capability */ -#define MAX_ROM_SCAN 0x10000 - -#define RESERVED_MEM_SIZE_4M 0x400000 /* 4M */ -#define RESERVED_MEM_SIZE_8M 0x800000 /* 8M */ - -/* Mode set stuff */ -#define DEFAULT_MODE 0 /* 640x480x8 */ -#define DEFAULT_LCDMODE 9 /* 800x600x8 */ -#define DEFAULT_TVMODE 9 /* 800x600x8 */ - -/* heap stuff */ -#define OH_ALLOC_SIZE 4000 -#define SENTINEL 0x7fffffff - -#define TURBO_QUEUE_AREA_SIZE 0x80000 /* 512K */ -#define HW_CURSOR_AREA_SIZE 0x1000 /* 4K */ - -/* ------------------- Global Variables ----------------------------- */ - -struct video_info ivideo; -HW_DEVICE_EXTENSION HwExt={0,0,0,0,0,0}; - -struct GlyInfo { - unsigned char ch; - int fontwidth; - int fontheight; - u8 gmask[72]; - int ngmask; -}; - -/* Supported SiS Chips list */ -static struct board { - u16 vendor, device; - const char *name; -} dev_list[] = { - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"}, - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, "SIS 540"}, - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, "SIS 630"}, - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_730_VGA, "SIS 730"}, - {0, 0, NULL} -}; - -/* card parameters */ -unsigned long rom_base; -unsigned long rom_vbase; - -/* mode */ -static int video_type = FB_TYPE_PACKED_PIXELS; -static int video_linelength; -static int video_cmap_len; -static int sisfb_off = 0; -static int crt1off = 0; - -static struct fb_var_screeninfo default_var = { - 0, 0, 0, 0, - 0, 0, - 0, - 0, - {0, 8, 0}, - {0, 8, 0}, - {0, 8, 0}, - {0, 0, 0}, - 0, - FB_ACTIVATE_NOW, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, - FB_VMODE_NONINTERLACED, - {0, 0, 0, 0, 0, 0} -}; - -static struct display disp; -static struct fb_info fb_info; -static struct { - u16 blue, green, red, pad; -} palette[256]; -static union { -#ifdef FBCON_HAS_CFB16 - u16 cfb16[16]; -#endif -#ifdef FBCON_HAS_CFB24 - u32 cfb24[16]; -#endif -#ifdef FBCON_HAS_CFB32 - u32 cfb32[16]; -#endif -} fbcon_cmap; - -static int inverse = 0; -static int currcon = 0; - -static struct display_switch sisfb_sw; - -static u8 caps = 0; -static unsigned long MMIO_SIZE = 0; - -/* ModeSet stuff */ -unsigned char uDispType = 0; -int mode_idx = -1; -u8 mode_no = 0; -u8 rate_idx = 0; - -static const struct _sisbios_mode { - char name[15]; - u8 mode_no; - u16 xres; - u16 yres; - u16 bpp; - u16 rate_idx; - u16 cols; - u16 rows; -} sisbios_mode[] = { - {"640x480x8", 0x2E, 640, 480, 8, 1, 80, 30}, - {"640x480x16", 0x44, 640, 480, 16, 1, 80, 30}, - {"640x480x32", 0x62, 640, 480, 32, 1, 80, 30}, - {"720x480x8", 0x31, 720, 480, 8, 1, 90, 30}, /* NTSC TV */ - {"720x480x16", 0x33, 720, 480, 16, 1, 90, 30}, - {"720x480x32", 0x35, 720, 480, 32, 1, 90, 30}, - {"720x576x8", 0x32, 720, 576, 8, 1, 90, 36}, /* PAL TV */ - {"720x576x16", 0x34, 720, 576, 16, 1, 90, 36}, - {"720x576x32", 0x36, 720, 576, 32, 1, 90, 36}, - {"800x600x8", 0x30, 800, 600, 8, 2, 100, 37}, - {"800x600x16", 0x47, 800, 600, 16, 2, 100, 37}, - {"800x600x32", 0x63, 800, 600, 32, 2, 100, 37}, - {"1024x768x8", 0x38, 1024, 768, 8, 2, 128, 48}, - {"1024x768x16", 0x4A, 1024, 768, 16, 2, 128, 48}, - {"1024x768x32", 0x64, 1024, 768, 32, 2, 128, 48}, - {"1280x1024x8", 0x3A, 1280, 1024, 8, 2, 160, 64}, - {"1280x1024x16", 0x4D, 1280, 1024, 16, 2, 160, 64}, - {"1280x1024x32", 0x65, 1280, 1024, 32, 2, 160, 64}, - {"1600x1200x8", 0x3C, 1600, 1200, 8, 1, 200, 75}, - {"1600x1200x16", 0x3D, 1600, 1200, 16, 1, 200, 75}, - {"1600x1200x32", 0x66, 1600, 1200, 32, 1, 200, 75}, - {"1920x1440x8", 0x68, 1920, 1440, 8, 1, 240, 75}, - {"1920x1440x16", 0x69, 1920, 1440, 16, 1, 240, 75}, - {"1920x1440x32", 0x6B, 1920, 1440, 32, 1, 240, 75}, - {"\0", 0x00, 0, 0, 0, 0, 0, 0} -}; - -static struct _vrate { - u16 idx; - u16 xres; - u16 yres; - u16 refresh; -} vrate[] = { - {1, 640, 480, 60}, {2, 640, 480, 72}, {3, 640, 480, 75}, {4, 640, 480, 85}, - {5, 640, 480, 100}, {6, 640, 480, 120}, {7, 640, 480, 160}, {8, 640, 480, 200}, - {1, 720, 480, 60}, - {1, 720, 576, 50}, - {1, 800, 600, 56}, {2, 800, 600, 60}, {3, 800, 600, 72}, {4, 800, 600, 75}, - {5, 800, 600, 85}, {6, 800, 600, 100}, {7, 800, 600, 120}, {8, 800, 600, 160}, - {1, 1024, 768, 43}, {2, 1024, 768, 60}, {3, 1024, 768, 70}, {4, 1024, 768, 75}, - {5, 1024, 768, 85}, {6, 1024, 768, 100}, {7, 1024, 768, 120}, - {1, 1280, 1024, 43}, {2, 1280, 1024, 60}, {3, 1280, 1024, 75}, {4, 1280, 1024, 85}, - {1, 1600, 1200, 60}, {2, 1600, 1200, 65}, {3, 1600, 1200, 70}, {4, 1600, 1200, 75}, - {5, 1600, 1200, 85}, - {1, 1920, 1440, 60}, - {0, 0, 0, 0} -}; - - -/* HEAP stuff */ - -struct OH { - struct OH *pohNext; - struct OH *pohPrev; - unsigned long ulOffset; - unsigned long ulSize; -}; - -struct OHALLOC { - struct OHALLOC *pohaNext; - struct OH aoh[1]; -}; - -struct HEAP { - struct OH ohFree; - struct OH ohUsed; - struct OH *pohFreeList; - struct OHALLOC *pohaChain; - - unsigned long ulMaxFreeSize; -}; - -struct HEAP heap; -unsigned long heap_start; -unsigned long heap_end; -unsigned long heap_size; - -unsigned int tqueue_pos; -unsigned long hwcursor_vbase; - - -/* -------------------- Macro definitions --------------------------- */ +/* -------------------- Macro definitions ---------------------------- */ #ifdef SISFBDEBUG #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) @@ -288,305 +62,399 @@ #define vgarb(reg) \ (inb(ivideo.vga_base+reg)) -/* ---------------------- Routine Prototype ------------------------- */ - -/* Interface used by the world */ -int sisfb_setup(char *options); -static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *info); -static int sisfb_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info); -static int sisfb_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info); -static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); -static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); -static int sisfb_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, int con, - struct fb_info *info); - -/* Interface to the low level console driver */ -int sisfb_init(void); -static int sisfb_update_var(int con, struct fb_info *info); -static int sisfb_switch(int con, struct fb_info *info); -static void sisfb_blank(int blank, struct fb_info *info); +/* --------------- Hardware Access Routines -------------------------- */ -/* Internal routines */ -static void crtc_to_var(struct fb_var_screeninfo *var); -static void sisfb_set_disp(int con, struct fb_var_screeninfo *var); -static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, - unsigned *blue, unsigned *transp, - struct fb_info *fb_info); -static int sis_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *fb_info); -static void do_install_cmap(int con, struct fb_info *info); -static int do_set_var(struct fb_var_screeninfo *var, int isactive, - struct fb_info *info); - -/* set-mode routines */ -void SetReg1(u16 port, u16 index, u16 data); -void SetReg3(u16 port, u16 data); -void SetReg4(u16 port, unsigned long data); -u8 GetReg1(u16 port, u16 index); -u8 GetReg2(u16 port); -u32 GetReg3(u16 port); -extern BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension, - USHORT ModeNo); -extern BOOLEAN SiSInit300(PHW_DEVICE_EXTENSION HwDeviceExtension); -static void pre_setmode(void); -static void post_setmode(void); -static void search_mode(const char *name); -static u8 search_refresh_rate(unsigned int rate); - -/* heap routines */ -static int sisfb_heap_init(void); -static struct OH *poh_new_node(void); -static struct OH *poh_allocate(unsigned long size); -static struct OH *poh_free(unsigned long base); -static void delete_node(struct OH *poh); -static void insert_node(struct OH *pohList, struct OH *poh); -static void free_node(struct OH *poh); +void sisfb_set_reg1(u16 port, u16 index, u16 data) +{ + outb((u8) (index & 0xff), port); + port++; + outb((u8) (data & 0xff), port); +} -/* ---------------------- Internal Routines ------------------------- */ +void sisfb_set_reg3(u16 port, u16 data) +{ + outb((u8) (data & 0xff), port); +} -inline static u32 RD32(unsigned char *base, s32 off) +void sisfb_set_reg4(u16 port, unsigned long data) { - return readl(base + off); + outl((u32) (data & 0xffffffff), port); } -inline static void WR32(unsigned char *base, s32 off, u32 v) +u8 sisfb_get_reg1(u16 port, u16 index) { - writel(v, base + off); + u8 data; + + outb((u8) (index & 0xff), port); + port += 1; + data = inb(port); + return (data); } -inline static void WR16(unsigned char *base, s32 off, u16 v) +u8 sisfb_get_reg2(u16 port) { - writew(v, base + off); + u8 data; + + data = inb(port); + + return (data); } -inline static void WR8(unsigned char *base, s32 off, u8 v) +u32 sisfb_get_reg3(u16 port) { - writeb(v, base + off); + u32 data; + + data = inl(port); + return (data); } -inline static u32 regrl(s32 off) +void sisfb_clear_DAC(u16 port) { - return RD32(ivideo.mmio_vbase, off); + int i,j; + + vgawb(DAC_ADR, 0x00); + for(i=0; i<256; i++) + for(j=0; j<3; j++) + vgawb(DAC_DATA, 0); } -inline static void regwl(s32 off, u32 v) +void sisfb_clear_buffer(PHW_DEVICE_EXTENSION psishw_ext) { - WR32(ivideo.mmio_vbase, off, v); + memset((char *) ivideo.video_vbase, 0, + video_linelength * ivideo.video_height); } -inline static void regww(s32 off, u16 v) + +/* -------------------- Export functions ----------------------------- */ + +static void sis_get_glyph(SIS_GLYINFO *gly) { - WR16(ivideo.mmio_vbase, off, v); + struct display *p = &fb_display[currcon]; + u16 c; + u8 *cdat; + int widthb; + u8 *gbuf = gly->gmask; + int size; + + + gly->fontheight = fontheight(p); + gly->fontwidth = fontwidth(p); + widthb = (fontwidth(p) + 7) / 8; + + c = gly->ch & p->charmask; + if (fontwidth(p) <= 8) + cdat = p->fontdata + c * fontheight(p); + else + cdat = p->fontdata + (c * fontheight(p) << 1); + + size = fontheight(p) * widthb; + memcpy(gbuf, cdat, size); + gly->ngmask = size; } -inline static void regwb(s32 off, u8 v) +void sis_dispinfo(struct ap_data *rec) { - WR8(ivideo.mmio_vbase, off, v); + rec->minfo.bpp = ivideo.video_bpp; + rec->minfo.xres = ivideo.video_width; + rec->minfo.yres = ivideo.video_height; + rec->minfo.v_xres = ivideo.video_vwidth; + rec->minfo.v_yres = ivideo.video_vheight; + rec->minfo.org_x = ivideo.org_x; + rec->minfo.org_y = ivideo.org_y; + rec->minfo.vrate = ivideo.refresh_rate; + rec->iobase = ivideo.vga_base - 0x30; + rec->mem_size = ivideo.video_size; + rec->disp_state = ivideo.disp_state; + rec->version = (VER_MAJOR << 16) | VER_MINOR; + rec->hasVB = ivideo.hasVB; + rec->TV_type = ivideo.TV_type; + rec->TV_plug = ivideo.TV_plug; + rec->chip = ivideo.chip; } -/* - * Get CRTC registers to set var - */ -static void crtc_to_var(struct fb_var_screeninfo *var) +/* ------------------ Internal Routines ------------------------------ */ + +static void sisfb_search_mode(const char *name) { - u16 VRE, VBE, VRS, VBS, VDE, VT; - u16 HRE, HBE, HRS, HBS, HDE, HT; - u8 uSRdata, uCRdata, uCRdata2, uCRdata3, uMRdata; - int A, B, C, D, E, F, temp; - double hrate, drate; + int i = 0; - vgawb(SEQ_ADR, 0x6); - uSRdata = vgarb(SEQ_DATA); + if (name == NULL) + return; - if (uSRdata & 0x20) - var->vmode = FB_VMODE_INTERLACED; - else - var->vmode = FB_VMODE_NONINTERLACED; + while (sisbios_mode[i].mode_no != 0) { + if (!strcmp(name, sisbios_mode[i].name)) { + sisfb_mode_idx = i; + break; + } + i++; + } - switch ((uSRdata & 0x1c) >> 2) { - case 0: - var->bits_per_pixel = 8; - break; - case 2: - var->bits_per_pixel = 16; + if (sisfb_mode_idx < 0) + DPRINTK("Invalid user mode : %s\n", name); +} + +static void sisfb_validate_mode(void) +{ + switch (ivideo.disp_state & DISPTYPE_DISP2) { + case DISPTYPE_LCD: + switch (sishw_ext.usLCDType) { + case LCD1024: + if (sisbios_mode[sisfb_mode_idx].xres > 1024) + sisfb_mode_idx = -1; + break; + case LCD1280: + if (sisbios_mode[sisfb_mode_idx].xres > 1280) + sisfb_mode_idx = -1; + break; + case LCD2048: + if (sisbios_mode[sisfb_mode_idx].xres > 2048) + sisfb_mode_idx = -1; + break; + case LCD1920: + if (sisbios_mode[sisfb_mode_idx].xres > 1920) + sisfb_mode_idx = -1; + break; + case LCD1600: + if (sisbios_mode[sisfb_mode_idx].xres > 1600) + sisfb_mode_idx = -1; + break; + case LCD800: + if (sisbios_mode[sisfb_mode_idx].xres > 800) + sisfb_mode_idx = -1; + break; + case LCD640: + if (sisbios_mode[sisfb_mode_idx].xres > 640) + sisfb_mode_idx = -1; + break; + default: + sisfb_mode_idx = -1; + } + + if (sisbios_mode[sisfb_mode_idx].xres == 720) + sisfb_mode_idx = -1; break; - case 4: - var->bits_per_pixel = 32; + case DISPTYPE_TV: + switch (sisbios_mode[sisfb_mode_idx].xres) { + case 800: + case 640: + break; + case 720: + if (ivideo.TV_type == TVMODE_NTSC) { + if (sisbios_mode[sisfb_mode_idx].yres != 480) + sisfb_mode_idx = -1; + } else if (ivideo.TV_type == TVMODE_PAL) { + if (sisbios_mode[sisfb_mode_idx].yres != 576) + sisfb_mode_idx = -1; + } + break; + default: + sisfb_mode_idx = -1; + } break; } +} - switch (var->bits_per_pixel) { - case 8: - var->red.length = 6; - var->green.length = 6; - var->blue.length = 6; - video_cmap_len = 256; - break; - case 16: /* RGB 565 */ - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - video_cmap_len = 16; +static u8 sisfb_search_refresh_rate(unsigned int rate) +{ + u16 xres, yres; + int i = 0; - break; - case 24: /* RGB 888 */ - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - video_cmap_len = 16; - break; - case 32: - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 24; - var->transp.length = 8; - video_cmap_len = 16; - break; + xres = sisbios_mode[sisfb_mode_idx].xres; + yres = sisbios_mode[sisfb_mode_idx].yres; + + sisfb_rate_idx = 0; + while ((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) { + if ((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) { + if (sisfb_vrate[i].refresh == rate) { + sisfb_rate_idx = sisfb_vrate[i].idx; + break; + } else if (sisfb_vrate[i].refresh > rate) { + if ((sisfb_vrate[i].refresh - rate) <= 2) { + DPRINTK("Adjust rate from %d up to %d\n", rate, sisfb_vrate[i].refresh); + sisfb_rate_idx = sisfb_vrate[i].idx; + ivideo.refresh_rate = sisfb_vrate[i].refresh; + } else if (((rate - sisfb_vrate[i-1].refresh) <= 2) && (sisfb_vrate[i].idx != 1)) { + DPRINTK("Adjust rate from %d down to %d\n", rate, sisfb_vrate[i-1].refresh); + sisfb_rate_idx = sisfb_vrate[i-1].idx; + ivideo.refresh_rate = sisfb_vrate[i-1].refresh; + } + break; + } + } + i++; } - vgawb(SEQ_ADR, 0xa); - uSRdata = vgarb(SEQ_DATA); + if (sisfb_rate_idx > 0) { + return sisfb_rate_idx; + } else { + DPRINTK("Unsupported rate %d for %dx%d mode\n", rate, xres, yres); + return 0; + } - vgawb(CRTC_ADR, 0x6); - uCRdata = vgarb(CRTC_DATA); - vgawb(CRTC_ADR, 0x7); - uCRdata2 = vgarb(CRTC_DATA); - VT = - (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x01) << 8) | - ((u16) (uCRdata2 & 0x20) << 4) | ((u16) (uSRdata & 0x01) << - 10); - A = VT + 2; +} - vgawb(CRTC_ADR, 0x12); - uCRdata = vgarb(CRTC_DATA); - VDE = - (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x02) << 7) | - ((u16) (uCRdata2 & 0x40) << 3) | ((u16) (uSRdata & 0x02) << 9); - E = VDE + 1; +static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue, + unsigned *transp, struct fb_info *fb_info) +{ + if (regno >= video_cmap_len) + return 1; - vgawb(CRTC_ADR, 0x10); - uCRdata = vgarb(CRTC_DATA); - VRS = - (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x04) << 6) | - ((u16) (uCRdata2 & 0x80) << 2) | ((u16) (uSRdata & 0x08) << 7); - F = VRS + 1 - E; + *red = palette[regno].red; + *green = palette[regno].green; + *blue = palette[regno].blue; + *transp = 0; + return 0; +} - vgawb(CRTC_ADR, 0x15); - uCRdata = vgarb(CRTC_DATA); - vgawb(CRTC_ADR, 0x9); - uCRdata3 = vgarb(CRTC_DATA); - VBS = - (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x08) << 5) | - ((u16) (uCRdata3 & 0x20) << 4) | ((u16) (uSRdata & 0x04) << 8); +static int sis_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *fb_info) +{ - vgawb(CRTC_ADR, 0x16); - uCRdata = vgarb(CRTC_DATA); - VBE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x10) << 4); - temp = VBE - ((E - 1) & 511); - B = (temp > 0) ? temp : (temp + 512); + if (regno >= video_cmap_len) + return 1; - vgawb(CRTC_ADR, 0x11); - uCRdata = vgarb(CRTC_DATA); - VRE = (uCRdata & 0x0f) | ((uSRdata & 0x20) >> 1); - temp = VRE - ((E + F - 1) & 31); - C = (temp > 0) ? temp : (temp + 32); + palette[regno].red = red; + palette[regno].green = green; + palette[regno].blue = blue; - D = B - F - C; + switch (ivideo.video_bpp) { +#ifdef FBCON_HAS_CFB8 + case 8: + vgawb(DAC_ADR, regno); + vgawb(DAC_DATA, red >> 10); + vgawb(DAC_DATA, green >> 10); + vgawb(DAC_DATA, blue >> 10); + if (ivideo.disp_state & DISPTYPE_DISP2) { + vgawb(DAC2_ADR, regno); + vgawb(DAC2_DATA, red >> 8); + vgawb(DAC2_DATA, green >> 8); + vgawb(DAC2_DATA, blue >> 8); + } - var->yres = var->yres_virtual = E; - var->upper_margin = D; - var->lower_margin = F; - var->vsync_len = C; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 15: + case 16: + fbcon_cmap.cfb16[regno] = + ((red & 0xf800)) | + ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); + break; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: + red >>= 8; + green >>= 8; + blue >>= 8; + fbcon_cmap.cfb24[regno] = + (red << 16) | (green << 8) | (blue); + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + red >>= 8; + green >>= 8; + blue >>= 8; + fbcon_cmap.cfb32[regno] = + (red << 16) | (green << 8) | (blue); + break; +#endif + } + return 0; +} - vgawb(SEQ_ADR, 0xb); - uSRdata = vgarb(SEQ_DATA); +static int sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, + struct fb_info *info) +{ + unsigned int htotal = + var->left_margin + var->xres + var->right_margin + + var->hsync_len; + unsigned int vtotal = + var->upper_margin + var->yres + var->lower_margin + + var->vsync_len; + double drate = 0, hrate = 0; + int found_mode = 0; + int old_mode; - vgawb(CRTC_ADR, 0x0); - uCRdata = vgarb(CRTC_DATA); - HT = (uCRdata & 0xff) | ((u16) (uSRdata & 0x03) << 8); - A = HT + 5; + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) + vtotal <<= 1; + else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) + vtotal <<= 2; + else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) + var->yres <<= 1; - vgawb(CRTC_ADR, 0x1); - uCRdata = vgarb(CRTC_DATA); - HDE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x0C) << 6); - E = HDE + 1; + if (!htotal || !vtotal) { + DPRINTK("Invalid 'var' Information!\n"); + return -EINVAL; + } - vgawb(CRTC_ADR, 0x4); - uCRdata = vgarb(CRTC_DATA); - HRS = (uCRdata & 0xff) | ((u16) (uSRdata & 0xC0) << 2); - F = HRS - E - 3; + drate = 1E12 / var->pixclock; + hrate = drate / htotal; + ivideo.refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5); - vgawb(CRTC_ADR, 0x2); - uCRdata = vgarb(CRTC_DATA); - HBS = (uCRdata & 0xff) | ((u16) (uSRdata & 0x30) << 4); + old_mode = sisfb_mode_idx; + sisfb_mode_idx = 0; - vgawb(SEQ_ADR, 0xc); - uSRdata = vgarb(SEQ_DATA); - vgawb(CRTC_ADR, 0x3); - uCRdata = vgarb(CRTC_DATA); - vgawb(CRTC_ADR, 0x5); - uCRdata2 = vgarb(CRTC_DATA); - HBE = - (uCRdata & 0x1f) | ((u16) (uCRdata2 & 0x80) >> 2) | - ((u16) (uSRdata & 0x03) << 6); - HRE = (uCRdata2 & 0x1f) | ((uSRdata & 0x04) << 3); + while ((sisbios_mode[sisfb_mode_idx].mode_no != 0) + && (sisbios_mode[sisfb_mode_idx].xres <= var->xres)) { + if ((sisbios_mode[sisfb_mode_idx].xres == var->xres) + && (sisbios_mode[sisfb_mode_idx].yres == var->yres) + && (sisbios_mode[sisfb_mode_idx].bpp == var->bits_per_pixel)) { + sisfb_mode_no = sisbios_mode[sisfb_mode_idx].mode_no; + found_mode = 1; + break; + } + sisfb_mode_idx++; + } - temp = HBE - ((E - 1) & 255); - B = (temp > 0) ? temp : (temp + 256); + if (found_mode) + sisfb_validate_mode(); + else + sisfb_mode_idx = -1; - temp = HRE - ((E + F + 3) & 63); - C = (temp > 0) ? temp : (temp + 64); + if (sisfb_mode_idx < 0) { + DPRINTK("sisfb does not support mode %dx%d-%d\n", var->xres, + var->yres, var->bits_per_pixel); + sisfb_mode_idx = old_mode; + return -EINVAL; + } - D = B - F - C; + if (sisfb_search_refresh_rate(ivideo.refresh_rate) == 0) { + sisfb_rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx; + ivideo.refresh_rate = 60; + } - var->xres = var->xres_virtual = E * 8; - var->left_margin = D * 8; - var->right_margin = F * 8; - var->hsync_len = C * 8; + if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) { + sisfb_pre_setmode(); - var->activate = FB_ACTIVATE_NOW; +#ifdef CONFIG_FB_SIS_300 + if (SiSSetMode(&sishw_ext, sisfb_mode_no)) { + DPRINTK("set mode[0x%x]: failed\n", sisfb_mode_no); + return -1; + } +#endif - var->sync = 0; +#ifdef CONFIG_FB_SIS_315 + if (SiSSetMode310(&sishw_ext, sisfb_mode_no)) { + DPRINTK("set mode[0x%x]: failed\n", sisfb_mode_no); + return -1; + } - uMRdata = vgarb(0x1C); - if (uMRdata & 0x80) - var->sync &= ~FB_SYNC_VERT_HIGH_ACT; - else - var->sync |= FB_SYNC_VERT_HIGH_ACT; +#endif + sisfb_post_setmode(); - if (uMRdata & 0x40) - var->sync &= ~FB_SYNC_HOR_HIGH_ACT; - else - var->sync |= FB_SYNC_HOR_HIGH_ACT; + DPRINTK("Set New Mode : %dx%dx%d-%d \n", sisbios_mode[sisfb_mode_idx].xres, + sisbios_mode[sisfb_mode_idx].yres, sisbios_mode[sisfb_mode_idx].bpp, ivideo.refresh_rate); - VT += 2; - VT <<= 1; - HT = (HT + 5) * 8; + ivideo.video_bpp = sisbios_mode[sisfb_mode_idx].bpp; + ivideo.video_vwidth = ivideo.video_width = sisbios_mode[sisfb_mode_idx].xres; + ivideo.video_vheight = ivideo.video_height = sisbios_mode[sisfb_mode_idx].yres; + ivideo.org_x = ivideo.org_y = 0; + video_linelength = + ivideo.video_width * (ivideo.video_bpp >> 3); - hrate = (double) ivideo.refresh_rate * (double) VT / 2; - drate = hrate * HT; - var->pixclock = (u32) (1E12 / drate); + } + return 0; } static void sisfb_set_disp(int con, struct fb_var_screeninfo *var) @@ -599,7 +467,7 @@ if (con >= 0) display = &fb_display[con]; else - display = &disp; /* used during initialization */ + display = &disp; sisfb_get_fix(&fix, con, 0); @@ -611,9 +479,8 @@ display->ywrapstep = fix.ywrapstep; display->line_length = fix.line_length; display->next_line = fix.line_length; - /*display->can_soft_blank = 1; */ display->can_soft_blank = 0; - display->inverse = inverse; + display->inverse = sisfb_inverse; display->var = *var; save_flags(flags); @@ -652,311 +519,526 @@ display->scrollmode = SCROLL_YREDRAW; sisfb_sw.bmove = fbcon_redraw_bmove; - } -/* - * Read a single color register and split it into colors/transparent. - * Return != 0 for invalid regno. - */ -static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue, - unsigned *transp, struct fb_info *fb_info) +static void sisfb_do_install_cmap(int con, struct fb_info *info) { - if (regno >= video_cmap_len) - return 1; + if (con != currcon) + return; - *red = palette[regno].red; - *green = palette[regno].green; - *blue = palette[regno].blue; - *transp = 0; - return 0; + if (fb_display[con].cmap.len) + fb_set_cmap(&fb_display[con].cmap, 1, sis_setcolreg, info); + else + fb_set_cmap(fb_default_cmap(video_cmap_len), 1, + sis_setcolreg, info); } -/* - * Set a single color register. The values supplied are already - * rounded down to the hardware's capabilities (according to the - * entries in the var structure). Return != 0 for invalid regno. - */ -static int sis_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, - unsigned transp, struct fb_info *fb_info) -{ - - if (regno >= video_cmap_len) - return 1; - palette[regno].red = red; - palette[regno].green = green; - palette[regno].blue = blue; +/* --------------- Chip-dependent Routines --------------------------- */ - switch (ivideo.video_bpp) { -#ifdef FBCON_HAS_CFB8 - case 8: - vgawb(DAC_ADR, regno); - vgawb(DAC_DATA, red >> 10); - vgawb(DAC_DATA, green >> 10); - vgawb(DAC_DATA, blue >> 10); - if(uDispType & MASK_DISPTYPE_DISP2) - { - /* VB connected */ - vgawb(DAC2_ADR, regno); - vgawb(DAC2_DATA, red >> 8); - vgawb(DAC2_DATA, green >> 8); - vgawb(DAC2_DATA, blue >> 8); - } +#ifdef CONFIG_FB_SIS_300 /* for SiS 300/630/540/730 */ +static int sisfb_get_dram_size_300(void) +{ + struct pci_dev *pdev = NULL; + int pdev_valid = 0; + u8 pci_data, reg; + u16 nbridge_id; + switch (ivideo.chip) { + case SIS_Spartan: + nbridge_id = PCI_DEVICE_ID_SI_540; break; + case SIS_Trojan: + nbridge_id = PCI_DEVICE_ID_SI_630; break; + case SIS_730: + nbridge_id = PCI_DEVICE_ID_SI_730; break; + default: + nbridge_id = 0; break; -#endif -#ifdef FBCON_HAS_CFB16 - case 15: - case 16: - fbcon_cmap.cfb16[regno] = - ((red & 0xf800)) | - ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); - break; -#endif -#ifdef FBCON_HAS_CFB24 - case 24: - red >>= 8; - green >>= 8; - blue >>= 8; - fbcon_cmap.cfb24[regno] = - (red << 16) | (green << 8) | (blue); - break; -#endif -#ifdef FBCON_HAS_CFB32 - case 32: - red >>= 8; - green >>= 8; - blue >>= 8; - fbcon_cmap.cfb32[regno] = - (red << 16) | (green << 8) | (blue); - break; -#endif } + + if (nbridge_id == 0) { + vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE); + ivideo.video_size = ((unsigned int) ((vgarb(SEQ_DATA) & SIS_DRAM_SIZE_MASK) + 1) << 20); + } else { + pci_for_each_dev(pdev) { + if ((pdev->vendor == PCI_VENDOR_ID_SI) + && (pdev->device == PCI_DEVICE_ID_SI_630)) { + pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data); + pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4; + ivideo.video_size = (unsigned int)(1 << (pci_data+21)); + pdev_valid = 1; + + reg = SIS_DATA_BUS_64 << 6; + vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE); + switch (pci_data) { + case BRI_DRAM_SIZE_2MB: + reg |= SIS_DRAM_SIZE_2MB; break; + case BRI_DRAM_SIZE_4MB: + reg |= SIS_DRAM_SIZE_4MB; break; + case BRI_DRAM_SIZE_8MB: + reg |= SIS_DRAM_SIZE_8MB; break; + case BRI_DRAM_SIZE_16MB: + reg |= SIS_DRAM_SIZE_16MB; break; + case BRI_DRAM_SIZE_32MB: + reg |= SIS_DRAM_SIZE_32MB; break; + case BRI_DRAM_SIZE_64MB: + reg |= SIS_DRAM_SIZE_64MB; break; + } + vgawb(SEQ_DATA, reg); + break; + } + } + + if (!pdev_valid) + return -1; + } + return 0; } -static void do_install_cmap(int con, struct fb_info *info) +static void sisfb_detect_VB_connect_300() { - if (con != currcon) - return; + u8 sr16, sr17, cr32, temp; - if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, sis_setcolreg, info); - else - fb_set_cmap(fb_default_cmap(video_cmap_len), 1, - sis_setcolreg, info); -} + vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_17); + sr17 = vgarb(SEQ_DATA); + vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR32); + cr32 = vgarb(CRTC_DATA); -static int do_set_var(struct fb_var_screeninfo *var, int isactive, - struct fb_info *info) -{ - unsigned int htotal = - var->left_margin + var->xres + var->right_margin + - var->hsync_len; - unsigned int vtotal = - var->upper_margin + var->yres + var->lower_margin + - var->vsync_len; - double drate = 0, hrate = 0; - int found_mode = 0; - int old_mode; + ivideo.TV_plug = ivideo.TV_type = 0; + if ((sr17 & 0x0F) && (ivideo.chip != SIS_Glamour)) { + if ((sr17 & 0x01) && !sisfb_crt1off) + sisfb_crt1off = 0; + else { + if (sr17 & 0x0E) + sisfb_crt1off = 1; + else + sisfb_crt1off = 0; + } + + if (sr17 & 0x08 ) + ivideo.disp_state = DISPTYPE_CRT2; + else if (sr17 & 0x02) + ivideo.disp_state = DISPTYPE_LCD; + else if (sr17 & 0x04) { + ivideo.disp_state = DISPTYPE_TV; + if (sr17 & 0x20) + ivideo.TV_plug = TVPLUG_SVIDEO; + else if (sr17 & 0x10) + ivideo.TV_plug = TVPLUG_COMPOSITE; - if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) - vtotal <<= 1; - else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) - vtotal <<= 2; - else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) - var->yres <<= 1; + vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_16); + sr16 = vgarb(SEQ_DATA); + if (sr16 & 0x20) + ivideo.TV_type = TVMODE_PAL; + else + ivideo.TV_type = TVMODE_NTSC; + } else + ivideo.disp_state = 0; + } else { + if ((cr32 & SIS_CRT1) && !sisfb_crt1off) + sisfb_crt1off = 0; + else { + if (cr32 & 0x5F) + sisfb_crt1off = 1; + else + sisfb_crt1off = 0; + } + if (cr32 & SIS_VB_CRT2) + ivideo.disp_state = DISPTYPE_CRT2; + else if (cr32 & SIS_VB_LCD) + ivideo.disp_state = DISPTYPE_LCD; + else if (cr32 & SIS_VB_TV) { + ivideo.disp_state = DISPTYPE_TV; + if (cr32 & SIS_VB_HIVISION) { + ivideo.TV_type = TVMODE_HIVISION; + ivideo.TV_plug = TVPLUG_SVIDEO; + } + else if (cr32 & SIS_VB_SVIDEO) + ivideo.TV_plug = TVPLUG_SVIDEO; + else if (cr32 & SIS_VB_COMPOSITE) + ivideo.TV_plug = TVPLUG_COMPOSITE; + else if (cr32 & SIS_VB_SCART) + ivideo.TV_plug = TVPLUG_SCART; - if (!htotal || !vtotal) { - DPRINTK("Invalid 'var' Information!\n"); - return 1; + if (ivideo.TV_type == 0) { + temp = *((u8 *)(sishw_ext.VirtualRomBase+0x52)); + if (temp&0x40) { + temp=*((u8 *)(sishw_ext.VirtualRomBase+0x53)); + } else { + vgawb(SEQ_ADR, IND_SIS_POWER_ON_TRAP); + temp = vgarb(SEQ_DATA); + } + if (temp & 0x01) + ivideo.TV_type = TVMODE_PAL; + else + ivideo.TV_type = TVMODE_NTSC; + } + } else + ivideo.disp_state = 0; } +} - drate = 1E12 / var->pixclock; - hrate = drate / htotal; - ivideo.refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5); - - old_mode = mode_idx; - mode_idx = 0; +static void sisfb_get_VB_type_300(void) +{ + u8 reg; - while ((sisbios_mode[mode_idx].mode_no != 0) - && (sisbios_mode[mode_idx].xres <= var->xres)) { - if ((sisbios_mode[mode_idx].xres == var->xres) - && (sisbios_mode[mode_idx].yres == var->yres) - && (sisbios_mode[mode_idx].bpp == var->bits_per_pixel)) { - mode_no = sisbios_mode[mode_idx].mode_no; - found_mode = 1; - break; - } - mode_idx++; - } + if (ivideo.chip != SIS_Glamour) { + if (!sisfb_has_VB_300()) { + vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR37); + reg = vgarb(CRTC_DATA); - if(found_mode) - { - switch(uDispType & MASK_DISPTYPE_DISP2) - { - case MASK_DISPTYPE_LCD: - switch(HwExt.usLCDType) - { - case LCD1024: - if(var->xres > 1024) - found_mode = 0; - break; - case LCD1280: - if(var->xres > 1280) - found_mode = 0; - break; - case LCD2048: - if(var->xres > 2048) - found_mode = 0; - break; - case LCD1920: - if(var->xres > 1920) - found_mode = 0; - break; - case LCD1600: - if(var->xres > 1600) - found_mode = 0; + switch ((reg & SIS_EXTERNAL_CHIP_MASK) >> 1) { + case SIS_EXTERNAL_CHIP_LVDS: + ivideo.hasVB = HASVB_LVDS; break; - case LCD800: - if(var->xres > 800) - found_mode = 0; + case SIS_EXTERNAL_CHIP_TRUMPION: + ivideo.hasVB = HASVB_TRUMPION; break; - case LCD640: - if(var->xres > 640) - found_mode = 0; + case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL: + ivideo.hasVB = HASVB_LVDS_CHRONTEL; break; default: - found_mode = 0; - } - if(var->xres == 720) /* mode only for TV */ - found_mode = 0; - break; - case MASK_DISPTYPE_TV: - switch(var->xres) - { - case 800: - case 640: break; - case 720: - if(ivideo.TV_type == TVMODE_NTSC) - { - if(sisbios_mode[mode_idx].yres != 480) - found_mode = 0; - } - else if(ivideo.TV_type == TVMODE_PAL) - { - if(sisbios_mode[mode_idx].yres != 576) - found_mode = 0; - } - break; - default: - /* illegal mode */ - found_mode = 0; } - break; } + } else { + sisfb_has_VB_300(); } - if (!found_mode) { - printk("sisfb does not support mode %dx%d-%d\n", var->xres, - var->yres, var->bits_per_pixel); - mode_idx = old_mode; - return 1; - } + sishw_ext.hasVB = ivideo.hasVB; +} - if (search_refresh_rate(ivideo.refresh_rate) == 0) { - /* not supported rate */ - rate_idx = sisbios_mode[mode_idx].rate_idx; - ivideo.refresh_rate = 60; +static int sisfb_has_VB_300(void) +{ + u8 sr38, sr39, vb_chipid; + + vgawb(SEQ_ADR, IND_SIS_POWER_ON_TRAP); + sr38 = vgarb(SEQ_DATA); + vgawb(SEQ_ADR, IND_SIS_POWER_ON_TRAP2); + sr39 = vgarb(SEQ_DATA); + vgawb(VB_PART4_ADR, 0x0); + vb_chipid = vgarb(VB_PART4_DATA); + + if ( + ( (ivideo.chip == SIS_Glamour) && (sr38 & 0x20) ) + || + ( (ivideo.chip == SIS_Spartan) && (sr38 & 0x20) && (!(sr39 & 0x80)) ) + || + ( (ivideo.chip == SIS_Trojan ) && (sr38 & 0x20) && (!(sr39 & 0x80)) && + ((ivideo.revision_id & 0xf0) < 0x30) && (vb_chipid == 1) ) + || + ( (ivideo.chip == SIS_Trojan ) && ((ivideo.revision_id & 0xf0) >= 0x30) && + (vb_chipid == 1) ) + || + ( (ivideo.chip == SIS_730) && (vb_chipid == 1) ) /* 730 */ + ) { + ivideo.hasVB = HASVB_301; + return TRUE; + } else { + ivideo.hasVB = HASVB_NONE; + return FALSE; } +} - if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) { - pre_setmode(); +#endif /* CONFIG_FB_SIS_300 */ - if (SiSSetMode(&HwExt, mode_no)) { - DPRINTK("sisfb: set mode[0x%x]: failed\n", - mode_no); - return 1; - } +#ifdef CONFIG_FB_SIS_315 /* for SiS 315H/315 */ +static int sisfb_get_dram_size_315(void) +{ + struct pci_dev *pdev = NULL; + int pdev_valid = 0; + u8 pci_data, reg = 0; - post_setmode(); + if (ivideo.chip == SIS_550) { + pci_for_each_dev(pdev) { + if ((pdev->vendor == PCI_VENDOR_ID_SI) + && (pdev->device == PCI_DEVICE_ID_SI_550)) { + pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data); + pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4; + ivideo.video_size = (unsigned int)(1 << (pci_data+21)); + pdev_valid = 1; + + vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE); + reg = vgarb(SEQ_DATA) & 0x0F; + reg &= 0x0F; + + switch (pci_data) { + case BRI_DRAM_SIZE_2MB: + reg |= (SIS315_DRAM_SIZE_2MB << 4); break; + case BRI_DRAM_SIZE_4MB: + reg |= (SIS315_DRAM_SIZE_4MB << 4); break; + case BRI_DRAM_SIZE_8MB: + reg |= (SIS315_DRAM_SIZE_8MB << 4); break; + case BRI_DRAM_SIZE_16MB: + reg |= (SIS315_DRAM_SIZE_16MB << 4); break; + case BRI_DRAM_SIZE_32MB: + reg |= (SIS315_DRAM_SIZE_32MB << 4); break; + case BRI_DRAM_SIZE_64MB: + reg |= (SIS315_DRAM_SIZE_64MB << 4); break; + /* case BRI_DRAM_SIZE_128MB: + reg |= (SIS315_DRAM_SIZE_128MB << 4); break; */ + } - printk(KERN_DEBUG "Current Mode: %dx%dx%d-%d \n", sisbios_mode[mode_idx].xres, - sisbios_mode[mode_idx].yres, sisbios_mode[mode_idx].bpp, ivideo.refresh_rate); + /* TODO : set Dual channel and bus width bits here */ - ivideo.video_bpp = sisbios_mode[mode_idx].bpp; - ivideo.video_vwidth = ivideo.video_width = sisbios_mode[mode_idx].xres; - ivideo.video_vheight = ivideo.video_height = sisbios_mode[mode_idx].yres; - ivideo.org_x = ivideo.org_y = 0; - video_linelength = - ivideo.video_width * (ivideo.video_bpp >> 3); + vgawb(SEQ_DATA, reg); + break; + } + } + + if (!pdev_valid) + return -1; + + } else { + vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE); + reg = vgarb(SEQ_DATA); + switch ((reg & SIS315_DRAM_SIZE_MASK) >> 4) { + case SIS315_DRAM_SIZE_2MB: + ivideo.video_size = 0x200000; break; + case SIS315_DRAM_SIZE_4MB: + ivideo.video_size = 0x400000; break; + case SIS315_DRAM_SIZE_8MB: + ivideo.video_size = 0x800000; break; + case SIS315_DRAM_SIZE_16MB: + ivideo.video_size = 0x1000000; break; + case SIS315_DRAM_SIZE_32MB: + ivideo.video_size = 0x2000000; break; + case SIS315_DRAM_SIZE_64MB: + ivideo.video_size = 0x4000000; break; + case SIS315_DRAM_SIZE_128MB: + ivideo.video_size = 0x8000000; break; + default: + return -1; + } + } - DPRINTK("Current Mode: %dx%d-%d line_length=%d\n", - ivideo.video_width, ivideo.video_height, - ivideo.video_bpp, video_linelength); + reg &= SIS315_DUAL_CHANNEL_MASK; + reg >>= 2; + switch (reg) { + case SIS315_SINGLE_CHANNEL_2_RANK: + ivideo.video_size <<= 1; + break; + case SIS315_DUAL_CHANNEL_1_RANK: + ivideo.video_size <<= 1; + break; } return 0; } -/* ---------------------- Draw Funtions ----------------------------- */ - -static void sis_get_glyph(struct GlyInfo *gly) +static void sisfb_detect_VB_connect_315(void) { - struct display *p = &fb_display[currcon]; - u16 c; - u8 *cdat; - int widthb; - u8 *gbuf = gly->gmask; - int size; + u8 cr32, temp; + vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR32); + cr32 = vgarb(CRTC_DATA); - gly->fontheight = fontheight(p); - gly->fontwidth = fontwidth(p); - widthb = (fontwidth(p) + 7) / 8; + ivideo.TV_plug = ivideo.TV_type = 0; + if ((cr32 & SIS_CRT1) && !sisfb_crt1off) + sisfb_crt1off = 0; + else { + if (cr32 & 0x5F) + sisfb_crt1off = 1; + else + sisfb_crt1off = 0; + } - c = gly->ch & p->charmask; - if (fontwidth(p) <= 8) - cdat = p->fontdata + c * fontheight(p); - else - cdat = p->fontdata + (c * fontheight(p) << 1); + if (cr32 & SIS_VB_CRT2) + ivideo.disp_state = DISPTYPE_CRT2; + else if (cr32 & SIS_VB_LCD) + ivideo.disp_state = DISPTYPE_LCD; + else if (cr32 & SIS_VB_TV) { + ivideo.disp_state = DISPTYPE_TV; + + if (cr32 & SIS_VB_HIVISION) { + ivideo.TV_type = TVMODE_HIVISION; + ivideo.TV_plug = TVPLUG_SVIDEO; + } else if (cr32 & SIS_VB_SVIDEO) + ivideo.TV_plug = TVPLUG_SVIDEO; + else if (cr32 & SIS_VB_COMPOSITE) + ivideo.TV_plug = TVPLUG_COMPOSITE; + else if (cr32 & SIS_VB_SCART) + ivideo.TV_plug = TVPLUG_SCART; + + if (ivideo.TV_type == 0) { + vgawb(SEQ_ADR, IND_SIS_POWER_ON_TRAP); + temp = vgarb(SEQ_DATA); - size = fontheight(p) * widthb; - memcpy(gbuf, cdat, size); - gly->ngmask = size; + if (temp & 0x01) + ivideo.TV_type = TVMODE_PAL; + else + ivideo.TV_type = TVMODE_NTSC; + } + } else + ivideo.disp_state = 0; } +static void sisfb_get_VB_type_315(void) +{ + u8 vb_chipid; -/* ---------------------- HEAP Routines ----------------------------- */ + vgawb(VB_PART4_ADR, 0x0); + vb_chipid = vgarb(VB_PART4_DATA); -/* - * Heap Initialization - */ + switch (vb_chipid) { + case 0x01: + ivideo.hasVB = HASVB_301; break; + case 0x02: + ivideo.hasVB = HASVB_302; break; + case 0x03: + ivideo.hasVB = HASVB_303; break; + default: + ivideo.hasVB = HASVB_NONE; + } + sishw_ext.hasVB = ivideo.hasVB; +} +#endif /* CONFIG_FB_SIS_315 */ + +/* --------------------- Heap Routines ------------------------------- */ static int sisfb_heap_init(void) { - struct OH *poh; - u8 jTemp, tq_state; + SIS_OH *poh; + u8 temp=0; +#ifdef CONFIG_FB_SIS_315 + int agp_enabled = 0; + agp_kern_info *agp_info; + agp_memory *agp; + u32 agp_phys; + u32 agp_size; + unsigned long *cmdq_baseport = 0; + unsigned long *read_port = 0; + unsigned long *write_port = 0; + SIS_CMDTYPE cmd_type; +#endif + + if (ivideo.video_size > 0x800000) + sisfb_heap_start = (unsigned long) ivideo.video_vbase + 0x800000; + else + sisfb_heap_start = (unsigned long) ivideo.video_vbase + 0x400000; + + sisfb_heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size; + sisfb_heap_size = sisfb_heap_end - sisfb_heap_start; + +#ifdef CONFIG_FB_SIS_315 + + cmdq_baseport = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_PHYBASE); + write_port = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_WRITEPORT); + read_port = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_READPORT); + + DPRINTK("AGP base: 0x%p, read: 0x%p, write: 0x%p\n", cmdq_baseport, read_port, write_port); + + agp_enabled = 1; - if(ivideo.video_size > 0x800000) - /* video ram is large than 8M */ - heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_8M; + agp_size = COMMAND_QUEUE_AREA_SIZE; + agp_info = vmalloc(sizeof(agp_kern_info)); + memset((void*)agp_info, 0x00, sizeof(agp_kern_info)); + agp_copy_info(agp_info); + + agp_backend_acquire(); + + agp = agp_allocate_memory(COMMAND_QUEUE_AREA_SIZE/PAGE_SIZE, AGP_NORMAL_MEMORY); + if (agp == NULL) { + DPRINTK("Allocate AGP buffer failed.\n"); + agp_enabled = 0; + } else { + if (agp_bind_memory(agp, agp->pg_start) != 0) { + DPRINTK("AGP : can not bind memory\n"); + agp_enabled = 0; + } else { + agp_enable(0); + } + } + + if (agp_enabled) + cmd_type = AGP_CMD_QUEUE; + else if (sisfb_heap_size >= COMMAND_QUEUE_AREA_SIZE) + cmd_type = VM_CMD_QUEUE; else - heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_4M; + cmd_type = MMIO_CMD; + + switch (agp_size) { + case 0x80000: + temp = SIS_CMD_QUEUE_SIZE_512k; break; + case 0x100000: + temp = SIS_CMD_QUEUE_SIZE_1M; break; + case 0x200000: + temp = SIS_CMD_QUEUE_SIZE_2M; break; + case 0x400000: + temp = SIS_CMD_QUEUE_SIZE_4M; break; + } - heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size; - heap_size = heap_end - heap_start; + switch (cmd_type) { + case AGP_CMD_QUEUE: + DPRINTK("AGP buffer base:0x%lx, offset:0x%x, size is %dK\n", + agp_info->aper_base, agp->physical, agp_size/1024); + agp_phys = agp_info->aper_base + agp->physical; + + vgawb(CRTC_ADR, IND_SIS_AGP_IO_PAD); + vgawb(CRTC_DATA, 0); + vgawb(CRTC_DATA, SIS_AGP_2X); + + vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_THRESHOLD); + vgawb(SEQ_DATA, COMMAND_QUEUE_THRESHOLD); + + vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET); + vgawb(SEQ_DATA, SIS_CMD_QUEUE_RESET); + + *write_port = *read_port; + + temp |= SIS_AGP_CMDQUEUE_ENABLE; + vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET); + vgawb(SEQ_DATA, temp); + + *cmdq_baseport = agp_phys; + + sisfb_caps |= AGP_CMD_QUEUE_CAP; + + break; + + case VM_CMD_QUEUE: + sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE; + sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE; + + vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_THRESHOLD); + vgawb(SEQ_DATA, COMMAND_QUEUE_THRESHOLD); + + vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET); + vgawb(SEQ_DATA, SIS_CMD_QUEUE_RESET); + + *write_port = *read_port; + + temp |= SIS_VRAM_CMDQUEUE_ENABLE; + vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET); + vgawb(SEQ_DATA, temp); + + *cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE; + + sisfb_caps |= VM_CMD_QUEUE_CAP; + + DPRINTK("VM Cmd Queue offset = 0x%lx, size is %dK\n", + *cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024); + break; + default: + vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET); + vgawb(SEQ_DATA, SIS_MMIO_CMD_ENABLE); + break; + } + +#endif + +#ifdef CONFIG_FB_SIS_300 + if (sisfb_heap_size >= TURBO_QUEUE_AREA_SIZE) { + unsigned int tqueue_pos; + u8 tq_state; - /* Setting for Turbo Queue */ - if (heap_size >= TURBO_QUEUE_AREA_SIZE) { tqueue_pos = (ivideo.video_size - TURBO_QUEUE_AREA_SIZE) / (64 * 1024); - jTemp = (u8) (tqueue_pos & 0xff); + temp = (u8) (tqueue_pos & 0xff); vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_SET); tq_state = vgarb(SEQ_DATA); tq_state |= 0xf0; @@ -964,119 +1046,114 @@ tq_state |= (u8) (tqueue_pos >> 8); vgawb(SEQ_DATA, tq_state); vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_ADR); - vgawb(SEQ_DATA, jTemp); + vgawb(SEQ_DATA, temp); - caps |= TURBO_QUEUE_CAP; + sisfb_caps |= TURBO_QUEUE_CAP; - heap_end -= TURBO_QUEUE_AREA_SIZE; - heap_size -= TURBO_QUEUE_AREA_SIZE; + sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE; + sisfb_heap_size -= TURBO_QUEUE_AREA_SIZE; + DPRINTK("Turbo Queue: start at 0x%lx, size is %dK\n", + sisfb_heap_end, TURBO_QUEUE_AREA_SIZE/1024); } +#endif + + if (sisfb_heap_size >= HW_CURSOR_AREA_SIZE) { + sisfb_heap_end -= HW_CURSOR_AREA_SIZE; + sisfb_heap_size -= HW_CURSOR_AREA_SIZE; + sisfb_hwcursor_vbase = sisfb_heap_end; - /* Setting for HW cursor(4K) */ - if (heap_size >= HW_CURSOR_AREA_SIZE) { - heap_end -= HW_CURSOR_AREA_SIZE; - heap_size -= HW_CURSOR_AREA_SIZE; - hwcursor_vbase = heap_end; + sisfb_caps |= HW_CURSOR_CAP; - caps |= HW_CURSOR_CAP; + DPRINTK("Hardware Cursor: start at 0x%lx, size is %dK\n", + sisfb_heap_end, HW_CURSOR_AREA_SIZE/1024); } - heap.pohaChain = NULL; - heap.pohFreeList = NULL; - poh = poh_new_node(); + sisfb_heap.poha_chain = NULL; + sisfb_heap.poh_freelist = NULL; + + poh = sisfb_poh_new_node(); if (poh == NULL) return 1; - - /* The first node describles the entire heap size */ - poh->pohNext = &heap.ohFree; - poh->pohPrev = &heap.ohFree; - poh->ulSize = heap_end - heap_start + 1; - poh->ulOffset = heap_start - (unsigned long) ivideo.video_vbase; + + poh->poh_next = &sisfb_heap.oh_free; + poh->poh_prev = &sisfb_heap.oh_free; + poh->size = sisfb_heap_end - sisfb_heap_start + 1; + poh->offset = sisfb_heap_start - (unsigned long) ivideo.video_vbase; DPRINTK("sisfb:Heap start:0x%p, end:0x%p, len=%dk\n", - (char *) heap_start, (char *) heap_end, - (unsigned int) poh->ulSize / 1024); + (char *) sisfb_heap_start, (char *) sisfb_heap_end, + (unsigned int) poh->size / 1024); DPRINTK("sisfb:First Node offset:0x%x, size:%dk\n", - (unsigned int) poh->ulOffset, (unsigned int) poh->ulSize / 1024); - - /* The second node in our free list sentinel */ - heap.ohFree.pohNext = poh; - heap.ohFree.pohPrev = poh; - heap.ohFree.ulSize = 0; - heap.ulMaxFreeSize = poh->ulSize; - - /* Initialize the discardable list */ - heap.ohUsed.pohNext = &heap.ohUsed; - heap.ohUsed.pohPrev = &heap.ohUsed; - heap.ohUsed.ulSize = SENTINEL; + (unsigned int) poh->offset, (unsigned int) poh->size / 1024); + + sisfb_heap.oh_free.poh_next = poh; + sisfb_heap.oh_free.poh_prev = poh; + sisfb_heap.oh_free.size = 0; + sisfb_heap.max_freesize = poh->size; + + sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used; + sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used; + sisfb_heap.oh_used.size = SENTINEL; return 0; } -/* - * Allocates a basic memory unit in which we'll pack our data structures. - */ - -static struct OH *poh_new_node(void) +static SIS_OH *sisfb_poh_new_node(void) { int i; unsigned long cOhs; - struct OHALLOC *poha; - struct OH *poh; + SIS_OHALLOC *poha; + SIS_OH *poh; - if (heap.pohFreeList == NULL) { + if (sisfb_heap.poh_freelist == NULL) { poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL); - poha->pohaNext = heap.pohaChain; - heap.pohaChain = poha; + poha->poha_next = sisfb_heap.poha_chain; + sisfb_heap.poha_chain = poha; cOhs = (OH_ALLOC_SIZE - - sizeof(struct OHALLOC)) / sizeof(struct OH) + 1; + sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1; poh = &poha->aoh[0]; for (i = cOhs - 1; i != 0; i--) { - poh->pohNext = poh + 1; + poh->poh_next = poh + 1; poh = poh + 1; } - poh->pohNext = NULL; - heap.pohFreeList = &poha->aoh[0]; + poh->poh_next = NULL; + sisfb_heap.poh_freelist = &poha->aoh[0]; } - poh = heap.pohFreeList; - heap.pohFreeList = poh->pohNext; + poh = sisfb_heap.poh_freelist; + sisfb_heap.poh_freelist = poh->poh_next; return (poh); } -/* - * Allocates space, return NULL when failed - */ - -static struct OH *poh_allocate(unsigned long size) +static SIS_OH *sisfb_poh_allocate(unsigned long size) { - struct OH *pohThis; - struct OH *pohRoot; + SIS_OH *pohThis; + SIS_OH *pohRoot; int bAllocated = 0; - if (size > heap.ulMaxFreeSize) { + if (size > sisfb_heap.max_freesize) { DPRINTK("sisfb: Can't allocate %dk size on offscreen\n", (unsigned int) size / 1024); return (NULL); } - pohThis = heap.ohFree.pohNext; + pohThis = sisfb_heap.oh_free.poh_next; - while (pohThis != &heap.ohFree) { - if (size <= pohThis->ulSize) { + while (pohThis != &sisfb_heap.oh_free) { + if (size <= pohThis->size) { bAllocated = 1; break; } - pohThis = pohThis->pohNext; + pohThis = pohThis->poh_next; } if (!bAllocated) { @@ -1085,165 +1162,148 @@ return (NULL); } - if (size == pohThis->ulSize) { + if (size == pohThis->size) { pohRoot = pohThis; - delete_node(pohThis); + sisfb_delete_node(pohThis); } else { - pohRoot = poh_new_node(); + pohRoot = sisfb_poh_new_node(); if (pohRoot == NULL) { return (NULL); } - pohRoot->ulOffset = pohThis->ulOffset; - pohRoot->ulSize = size; + pohRoot->offset = pohThis->offset; + pohRoot->size = size; - pohThis->ulOffset += size; - pohThis->ulSize -= size; + pohThis->offset += size; + pohThis->size -= size; } - heap.ulMaxFreeSize -= size; + sisfb_heap.max_freesize -= size; - pohThis = &heap.ohUsed; - insert_node(pohThis, pohRoot); + pohThis = &sisfb_heap.oh_used; + sisfb_insert_node(pohThis, pohRoot); return (pohRoot); } -/* - * To remove a node from a list. - */ - -static void delete_node(struct OH *poh) +static void sisfb_delete_node(SIS_OH *poh) { - struct OH *pohPrev; - struct OH *pohNext; + SIS_OH *poh_prev; + SIS_OH *poh_next; - pohPrev = poh->pohPrev; - pohNext = poh->pohNext; + poh_prev = poh->poh_prev; + poh_next = poh->poh_next; - pohPrev->pohNext = pohNext; - pohNext->pohPrev = pohPrev; + poh_prev->poh_next = poh_next; + poh_next->poh_prev = poh_prev; return; } -/* - * To insert a node into a list. - */ - -static void insert_node(struct OH *pohList, struct OH *poh) +static void sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh) { - struct OH *pohTemp; + SIS_OH *pohTemp; - pohTemp = pohList->pohNext; + pohTemp = pohList->poh_next; - pohList->pohNext = poh; - pohTemp->pohPrev = poh; + pohList->poh_next = poh; + pohTemp->poh_prev = poh; - poh->pohPrev = pohList; - poh->pohNext = pohTemp; + poh->poh_prev = pohList; + poh->poh_next = pohTemp; } -/* - * Frees an off-screen heap allocation. - */ - -static struct OH *poh_free(unsigned long base) +static SIS_OH *sisfb_poh_free(unsigned long base) { - struct OH *pohThis; - struct OH *pohFreed; - struct OH *pohPrev; - struct OH *pohNext; + SIS_OH *pohThis; + SIS_OH *poh_freed; + SIS_OH *poh_prev; + SIS_OH *poh_next; unsigned long ulUpper; unsigned long ulLower; int foundNode = 0; - pohFreed = heap.ohUsed.pohNext; + poh_freed = sisfb_heap.oh_used.poh_next; - while (pohFreed != &heap.ohUsed) { - if (pohFreed->ulOffset == base) { + while (poh_freed != &sisfb_heap.oh_used) { + if (poh_freed->offset == base) { foundNode = 1; break; } - pohFreed = pohFreed->pohNext; + poh_freed = poh_freed->poh_next; } if (!foundNode) return (NULL); - heap.ulMaxFreeSize += pohFreed->ulSize; + sisfb_heap.max_freesize += poh_freed->size; - pohPrev = pohNext = NULL; - ulUpper = pohFreed->ulOffset + pohFreed->ulSize; - ulLower = pohFreed->ulOffset; + poh_prev = poh_next = NULL; + ulUpper = poh_freed->offset + poh_freed->size; + ulLower = poh_freed->offset; - pohThis = heap.ohFree.pohNext; + pohThis = sisfb_heap.oh_free.poh_next; - while (pohThis != &heap.ohFree) { - if (pohThis->ulOffset == ulUpper) { - pohNext = pohThis; + while (pohThis != &sisfb_heap.oh_free) { + if (pohThis->offset == ulUpper) { + poh_next = pohThis; } - else if ((pohThis->ulOffset + pohThis->ulSize) == + else if ((pohThis->offset + pohThis->size) == ulLower) { - pohPrev = pohThis; + poh_prev = pohThis; } - pohThis = pohThis->pohNext; + pohThis = pohThis->poh_next; } - delete_node(pohFreed); + sisfb_delete_node(poh_freed); - if (pohPrev && pohNext) { - pohPrev->ulSize += (pohFreed->ulSize + pohNext->ulSize); - delete_node(pohNext); - free_node(pohFreed); - free_node(pohNext); - return (pohPrev); + if (poh_prev && poh_next) { + poh_prev->size += (poh_freed->size + poh_next->size); + sisfb_delete_node(poh_next); + sisfb_free_node(poh_freed); + sisfb_free_node(poh_next); + return (poh_prev); } - if (pohPrev) { - pohPrev->ulSize += pohFreed->ulSize; - free_node(pohFreed); - return (pohPrev); + if (poh_prev) { + poh_prev->size += poh_freed->size; + sisfb_free_node(poh_freed); + return (poh_prev); } - if (pohNext) { - pohNext->ulSize += pohFreed->ulSize; - pohNext->ulOffset = pohFreed->ulOffset; - free_node(pohFreed); - return (pohNext); + if (poh_next) { + poh_next->size += poh_freed->size; + poh_next->offset = poh_freed->offset; + sisfb_free_node(poh_freed); + return (poh_next); } - insert_node(&heap.ohFree, pohFreed); + sisfb_insert_node(&sisfb_heap.oh_free, poh_freed); - return (pohFreed); + return (poh_freed); } -/* - * Frees our basic data structure allocation unit by adding it to a free - * list. - */ - -static void free_node(struct OH *poh) +static void sisfb_free_node(SIS_OH *poh) { if (poh == NULL) { return; } - poh->pohNext = heap.pohFreeList; - heap.pohFreeList = poh; + poh->poh_next = sisfb_heap.poh_freelist; + sisfb_heap.poh_freelist = poh; return; } void sis_malloc(struct sis_memreq *req) { - struct OH *poh; + SIS_OH *poh; - poh = poh_allocate(req->size); + poh = sisfb_poh_allocate(req->size); if (poh == NULL) { req->offset = 0; @@ -1251,245 +1311,412 @@ DPRINTK("sisfb: VMEM Allocation Failed\n"); } else { DPRINTK("sisfb: VMEM Allocation Successed : 0x%p\n", - (char *) (poh->ulOffset + + (char *) (poh->offset + (unsigned long) ivideo.video_vbase)); - req->offset = poh->ulOffset; - req->size = poh->ulSize; + req->offset = poh->offset; + req->size = poh->size; } } void sis_free(unsigned long base) { - struct OH *poh; + SIS_OH *poh; - poh = poh_free(base); + poh = sisfb_poh_free(base); if (poh == NULL) { - DPRINTK("sisfb: poh_free() failed at base 0x%x\n", + DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n", (unsigned int) base); } } -void sis_dispinfo(struct ap_data *rec) +/* ------------------ SetMode Routines ------------------------------- */ + +static void sisfb_pre_setmode(void) { - rec->minfo.bpp = ivideo.video_bpp; - rec->minfo.xres = ivideo.video_width; - rec->minfo.yres = ivideo.video_height; - rec->minfo.v_xres = ivideo.video_vwidth; - rec->minfo.v_yres = ivideo.video_vheight; - rec->minfo.org_x = ivideo.org_x; - rec->minfo.org_y = ivideo.org_y; - rec->minfo.vrate = ivideo.refresh_rate; - rec->iobase = ivideo.vga_base - 0x30; - rec->mem_size = ivideo.video_size; - rec->disp_state = ivideo.disp_state; - switch(HwExt.jChipID) - { - case SIS_Glamour: - rec->chip = SiS_300; + u8 cr30 = 0, cr31 = 0; + switch (ivideo.disp_state & DISPTYPE_DISP2) { + case DISPTYPE_CRT2: + cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE); + cr31 = SIS_DRIVER_MODE; + break; + case DISPTYPE_LCD: + cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE); + cr31 = SIS_DRIVER_MODE; + break; + case DISPTYPE_TV: + if (ivideo.TV_type == TVMODE_HIVISION) + cr30 = (SIS_VB_OUTPUT_HIVISION | SIS_SIMULTANEOUS_VIEW_ENABLE); + else if (ivideo.TV_plug == TVPLUG_SVIDEO) + cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE); + else if (ivideo.TV_plug == TVPLUG_COMPOSITE) + cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE); + else if (ivideo.TV_plug == TVPLUG_SCART) + cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE); + cr31 = SIS_DRIVER_MODE; break; - case SIS_Trojan: - if((HwExt.revision_id & 0xf0) == 0x30) - rec->chip = SiS_630S; - else - rec->chip = SiS_630; - break; - case SIS_Spartan: - rec->chip = SiS_540; + default: + cr30 = 0x00; + cr31 = (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE); + } + + vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR30); + vgawb(CRTC_DATA, cr30); + vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR31); + vgawb(CRTC_DATA, cr31); + vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR33); +/* + if (ivideo.disp_state & DISPTYPE_CRT2) { + sisfb_rate_idx &= 0x0F; + sisfb_rate_idx |= (sisfb_rate_idx << 4); + vgawb(CRTC_DATA, sisfb_rate_idx); + } else { + vgawb(CRTC_DATA, sisfb_rate_idx & 0x0F); + } +*/ + vgawb(CRTC_DATA, sisfb_rate_idx & 0x0F); +} + +static void sisfb_post_setmode(void) +{ + u8 reg; + + vgawb(CRTC_ADR, 0x17); + reg = vgarb(CRTC_DATA); + + if ((ivideo.hasVB == HASVB_LVDS) || (ivideo.hasVB == HASVB_LVDS_CHRONTEL)) + if (ivideo.video_bpp == 8) + sisfb_crt1off = 0; + + if (sisfb_crt1off) + reg &= ~0x80; + else + reg |= 0x80; + vgawb(CRTC_DATA, reg); + + vgawb(SEQ_ADR, IND_SIS_RAMDAC_CONTROL); + reg = vgarb(SEQ_DATA); + reg &= ~0x04; + vgawb(SEQ_DATA, reg); + + if ((ivideo.disp_state & DISPTYPE_TV) && (ivideo.hasVB == HASVB_301)) { + vgawb(VB_PART1_ADR, 0x24); + vgawb(VB_PART1_DATA, 0x1); + + if (ivideo.TV_type == TVMODE_NTSC) { + vgawb(VB_PART2_ADR, 0x3A); + reg = vgarb(VB_PART2_DATA); + reg &= 0x1F; + vgawb(VB_PART2_DATA, reg); + + if (ivideo.TV_plug == TVPLUG_SVIDEO) { + vgawb(VB_PART2_ADR, 0x30); + reg = vgarb(VB_PART2_DATA); + reg &= 0xDF; + vgawb(VB_PART2_DATA, reg); + } else if (ivideo.TV_plug == TVPLUG_COMPOSITE) { + vgawb(VB_PART2_ADR, 0x30); + reg = vgarb(VB_PART2_DATA); + reg |= 0x20; + vgawb(VB_PART2_DATA, reg); + + switch (ivideo.video_width) { + case 640: + vgawb(VB_PART2_ADR, 0x35); + vgawb(VB_PART2_DATA, 0xEB); + vgawb(VB_PART2_ADR, 0x36); + vgawb(VB_PART2_DATA, 0x04); + vgawb(VB_PART2_ADR, 0x37); + vgawb(VB_PART2_DATA, 0x25); + vgawb(VB_PART2_ADR, 0x38); + vgawb(VB_PART2_DATA, 0x18); + break; + case 720: + vgawb(VB_PART2_ADR, 0x35); + vgawb(VB_PART2_DATA, 0xEE); + vgawb(VB_PART2_ADR, 0x36); + vgawb(VB_PART2_DATA, 0x0C); + vgawb(VB_PART2_ADR, 0x37); + vgawb(VB_PART2_DATA, 0x22); + vgawb(VB_PART2_ADR, 0x38); + vgawb(VB_PART2_DATA, 0x08); + break; + case 800: + vgawb(VB_PART2_ADR, 0x35); + vgawb(VB_PART2_DATA, 0xEB); + vgawb(VB_PART2_ADR, 0x36); + vgawb(VB_PART2_DATA, 0x15); + vgawb(VB_PART2_ADR, 0x37); + vgawb(VB_PART2_DATA, 0x25); + vgawb(VB_PART2_ADR, 0x38); + vgawb(VB_PART2_DATA, 0xF6); + break; + } + } + } else if (ivideo.TV_type == TVMODE_PAL) { + vgawb(VB_PART2_ADR, 0x3A); + reg = vgarb(VB_PART2_DATA); + reg &= 0x1F; + vgawb(VB_PART2_DATA, reg); + + if (ivideo.TV_plug == TVPLUG_SVIDEO) { + vgawb(VB_PART2_ADR, 0x30); + reg = vgarb(VB_PART2_DATA); + reg &= 0xDF; + vgawb(VB_PART2_DATA, reg); + } else if (ivideo.TV_plug == TVPLUG_COMPOSITE) { + vgawb(VB_PART2_ADR, 0x30); + reg = vgarb(VB_PART2_DATA); + reg |= 0x20; + vgawb(VB_PART2_DATA, reg); + + switch (ivideo.video_width) { + case 640: + vgawb(VB_PART2_ADR, 0x35); + vgawb(VB_PART2_DATA, 0xF1); + vgawb(VB_PART2_ADR, 0x36); + vgawb(VB_PART2_DATA, 0xF7); + vgawb(VB_PART2_ADR, 0x37); + vgawb(VB_PART2_DATA, 0x1F); + vgawb(VB_PART2_ADR, 0x38); + vgawb(VB_PART2_DATA, 0x32); + break; + case 720: + vgawb(VB_PART2_ADR, 0x35); + vgawb(VB_PART2_DATA, 0xF3); + vgawb(VB_PART2_ADR, 0x36); + vgawb(VB_PART2_DATA, 0x00); + vgawb(VB_PART2_ADR, 0x37); + vgawb(VB_PART2_DATA, 0x1D); + vgawb(VB_PART2_ADR, 0x38); + vgawb(VB_PART2_DATA, 0x20); + break; + case 800: + vgawb(VB_PART2_ADR, 0x35); + vgawb(VB_PART2_DATA, 0xFC); + vgawb(VB_PART2_ADR, 0x36); + vgawb(VB_PART2_DATA, 0xFB); + vgawb(VB_PART2_ADR, 0x37); + vgawb(VB_PART2_DATA, 0x14); + vgawb(VB_PART2_ADR, 0x38); + vgawb(VB_PART2_DATA, 0x2A); + break; + } + } + } + } +} + +static void sisfb_crtc_to_var(struct fb_var_screeninfo *var) +{ + u16 VRE, VBE, VRS, VBS, VDE, VT; + u16 HRE, HBE, HRS, HBS, HDE, HT; + u8 sr_data, cr_data, cr_data2, cr_data3, mr_data; + int A, B, C, D, E, F, temp; + double hrate, drate; + + vgawb(SEQ_ADR, IND_SIS_COLOR_MODE); + sr_data = vgarb(SEQ_DATA); + + if (sr_data & SIS_INTERLACED_MODE) + var->vmode = FB_VMODE_INTERLACED; + else + var->vmode = FB_VMODE_NONINTERLACED; + + switch ((sr_data & 0x1C) >> 2) { + case SIS_8BPP_COLOR_MODE: + var->bits_per_pixel = 8; break; - case SIS_730: - rec->chip = SiS_730; + case SIS_16BPP_COLOR_MODE: + var->bits_per_pixel = 16; break; - default: - rec->chip = SiS_UNKNOWN; + case SIS_32BPP_COLOR_MODE: + var->bits_per_pixel = 32; break; } -} - - -/* ---------------------- SetMode Routines -------------------------- */ -void SetReg1(u16 port, u16 index, u16 data) -{ - outb((u8) (index & 0xff), port); - port++; - outb((u8) (data & 0xff), port); -} - -void SetReg3(u16 port, u16 data) -{ - outb((u8) (data & 0xff), port); -} + switch (var->bits_per_pixel) { + case 8: + var->red.length = 6; + var->green.length = 6; + var->blue.length = 6; + video_cmap_len = 256; + break; + case 16: + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + video_cmap_len = 16; -void SetReg4(u16 port, unsigned long data) -{ - outl((u32) (data & 0xffffffff), port); -} + break; + case 24: + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + video_cmap_len = 16; + break; + case 32: + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + video_cmap_len = 16; + break; + } -u8 GetReg1(u16 port, u16 index) -{ - u8 data; + vgawb(SEQ_ADR, 0xA); + sr_data = vgarb(SEQ_DATA); - outb((u8) (index & 0xff), port); - port += 1; - data = inb(port); - return (data); -} + vgawb(CRTC_ADR, 0x6); + cr_data = vgarb(CRTC_DATA); + vgawb(CRTC_ADR, 0x7); + cr_data2 = vgarb(CRTC_DATA); + VT = + (cr_data & 0xFF) | ((u16) (cr_data2 & 0x01) << 8) | + ((u16) (cr_data2 & 0x20) << 4) | ((u16) (sr_data & 0x01) << + 10); + A = VT + 2; -u8 GetReg2(u16 port) -{ - u8 data; + vgawb(CRTC_ADR, 0x12); + cr_data = vgarb(CRTC_DATA); + VDE = + (cr_data & 0xff) | ((u16) (cr_data2 & 0x02) << 7) | + ((u16) (cr_data2 & 0x40) << 3) | ((u16) (sr_data & 0x02) << 9); + E = VDE + 1; - data = inb(port); + vgawb(CRTC_ADR, 0x10); + cr_data = vgarb(CRTC_DATA); + VRS = + (cr_data & 0xff) | ((u16) (cr_data2 & 0x04) << 6) | + ((u16) (cr_data2 & 0x80) << 2) | ((u16) (sr_data & 0x08) << 7); + F = VRS + 1 - E; - return (data); -} + vgawb(CRTC_ADR, 0x15); + cr_data = vgarb(CRTC_DATA); + vgawb(CRTC_ADR, 0x9); + cr_data3 = vgarb(CRTC_DATA); + VBS = + (cr_data & 0xff) | ((u16) (cr_data2 & 0x08) << 5) | + ((u16) (cr_data3 & 0x20) << 4) | ((u16) (sr_data & 0x04) << 8); -u32 GetReg3(u16 port) -{ - u32 data; + vgawb(CRTC_ADR, 0x16); + cr_data = vgarb(CRTC_DATA); + VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4); + temp = VBE - ((E - 1) & 511); + B = (temp > 0) ? temp : (temp + 512); - data = inl(port); - return (data); -} + vgawb(CRTC_ADR, 0x11); + cr_data = vgarb(CRTC_DATA); + VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1); + temp = VRE - ((E + F - 1) & 31); + C = (temp > 0) ? temp : (temp + 32); -void ClearDAC(u16 port) -{ - int i,j; + D = B - F - C; - vgawb(DAC_ADR, 0x00); - for(i=0; i<256; i++) - for(j=0; j<3; j++) - vgawb(DAC_DATA, 0); -} + var->yres = var->yres_virtual = E; + var->upper_margin = D; + var->lower_margin = F; + var->vsync_len = C; -void ClearBuffer(PHW_DEVICE_EXTENSION pHwExt) -{ - memset((char *) ivideo.video_vbase, 0, - video_linelength * ivideo.video_height); -} + vgawb(SEQ_ADR, 0xb); + sr_data = vgarb(SEQ_DATA); -static void pre_setmode(void) -{ - unsigned char uCR30=0, uCR31=0; + vgawb(CRTC_ADR, 0x0); + cr_data = vgarb(CRTC_DATA); + HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8); + A = HT + 5; - switch(uDispType & MASK_DISPTYPE_DISP2) - { - case MASK_DISPTYPE_CRT2: - uCR30 = 0x41; - uCR31 = 0x40; - break; - case MASK_DISPTYPE_LCD: - uCR30 = 0x21; - uCR31 = 0x40; - break; - case MASK_DISPTYPE_TV: - if(ivideo.TV_type == TVMODE_HIVISION) - uCR30 = 0x81; - else if(ivideo.TV_plug == TVPLUG_SVIDEO) - uCR30 = 0x09; - else if(ivideo.TV_plug == TVPLUG_COMPOSITE) - uCR30 = 0x05; - else if(ivideo.TV_plug == TVPLUG_SCART) - uCR30 = 0x11; - uCR31 = 0x40; /* CR31[0] will be set in setmode() */ - break; - default: - uCR30 = 0x00; - uCR31 = 0x60; - } + vgawb(CRTC_ADR, 0x1); + cr_data = vgarb(CRTC_DATA); + HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6); + E = HDE + 1; - vgawb(CRTC_ADR, 0x30); - vgawb(CRTC_DATA, uCR30); - vgawb(CRTC_ADR, 0x31); - vgawb(CRTC_DATA, uCR31); - vgawb(CRTC_ADR, 0x33); - vgawb(CRTC_DATA, rate_idx & 0x0f); -} + vgawb(CRTC_ADR, 0x4); + cr_data = vgarb(CRTC_DATA); + HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2); + F = HRS - E - 3; -static void post_setmode(void) -{ - u8 uTemp; + vgawb(CRTC_ADR, 0x2); + cr_data = vgarb(CRTC_DATA); + HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4); - vgawb(CRTC_ADR, 0x17); - uTemp = vgarb(CRTC_DATA); + vgawb(SEQ_ADR, 0xc); + sr_data = vgarb(SEQ_DATA); + vgawb(CRTC_ADR, 0x3); + cr_data = vgarb(CRTC_DATA); + vgawb(CRTC_ADR, 0x5); + cr_data2 = vgarb(CRTC_DATA); + HBE = + (cr_data & 0x1f) | ((u16) (cr_data2 & 0x80) >> 2) | + ((u16) (sr_data & 0x03) << 6); + HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3); - if(crt1off) /* turn off CRT1 */ - uTemp &= ~0x80; - else /* turn on CRT1 */ - uTemp |= 0x80; - vgawb(CRTC_DATA, uTemp); - - /* disable 24-bit palette RAM and Gamma correction */ - vgawb(SEQ_ADR, 0x07); - uTemp = vgarb(SEQ_DATA); - uTemp &= ~0x04; - vgawb(SEQ_DATA, uTemp); -} + temp = HBE - ((E - 1) & 255); + B = (temp > 0) ? temp : (temp + 256); -static void search_mode(const char *name) -{ - int i = 0; + temp = HRE - ((E + F + 3) & 63); + C = (temp > 0) ? temp : (temp + 64); - if (name == NULL) - return; + D = B - F - C; - while (sisbios_mode[i].mode_no != 0) { - if (!strcmp(name, sisbios_mode[i].name)) { - mode_idx = i; - break; - } - i++; - } + var->xres = var->xres_virtual = E * 8; + var->left_margin = D * 8; + var->right_margin = F * 8; + var->hsync_len = C * 8; - if (mode_idx < 0) - DPRINTK("Invalid user mode : %s\n", name); -} + var->activate = FB_ACTIVATE_NOW; -static u8 search_refresh_rate(unsigned int rate) -{ - u16 xres, yres; - int i = 0; + var->sync = 0; - xres = sisbios_mode[mode_idx].xres; - yres = sisbios_mode[mode_idx].yres; + mr_data = vgarb(0x1C); + if (mr_data & 0x80) + var->sync &= ~FB_SYNC_VERT_HIGH_ACT; + else + var->sync |= FB_SYNC_VERT_HIGH_ACT; - while ((vrate[i].idx != 0) && (vrate[i].xres <= xres)) { - if ((vrate[i].xres == xres) && (vrate[i].yres == yres) - && (vrate[i].refresh == rate)) { - rate_idx = vrate[i].idx; - return rate_idx; - } - i++; - } + if (mr_data & 0x40) + var->sync &= ~FB_SYNC_HOR_HIGH_ACT; + else + var->sync |= FB_SYNC_HOR_HIGH_ACT; - DPRINTK("sisfb: Unsupported rate %d in %dx%d mode\n", rate, xres, - yres); + VT += 2; + VT <<= 1; + HT = (HT + 5) * 8; - return 0; + hrate = (double) ivideo.refresh_rate * (double) VT / 2; + drate = hrate * HT; + var->pixclock = (u32) (1E12 / drate); } -/* ------------------ Public Routines ------------------------------- */ - -/* - * Get the Fixed Part of the Display - */ +/* ------------------ Public Routines -------------------------------- */ static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) { - DPRINTK("sisfb: sisfb_get_fix:[%d]\n", con); - memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, fb_info.modename); fix->smem_start = ivideo.video_base; - if(ivideo.video_size > 0x800000) - fix->smem_len = RESERVED_MEM_SIZE_8M; /* reserved for Xserver */ + if (ivideo.video_size > 0x800000) + fix->smem_len = 0x800000; else - fix->smem_len = RESERVED_MEM_SIZE_4M; /* reserved for Xserver */ + fix->smem_len = 0x400000; fix->type = video_type; fix->type_aux = 0; @@ -1502,35 +1729,27 @@ fix->ywrapstep = 0; fix->line_length = video_linelength; fix->mmio_start = ivideo.mmio_base; - fix->mmio_len = MMIO_SIZE; + fix->mmio_len = sisfb_mmio_size; fix->accel = FB_ACCEL_SIS_GLAMOUR; fix->reserved[0] = ivideo.video_size & 0xFFFF; fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF; - fix->reserved[2] = caps; /* capabilities */ + fix->reserved[2] = sisfb_caps; return 0; -} -/* - * Get the User Defined Part of the Display - */ +} static int sisfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { - DPRINTK("sisfb: sisfb_get_var:[%d]\n", con); - if (con == -1) memcpy(var, &default_var, sizeof(struct fb_var_screeninfo)); else *var = fb_display[con].var; + return 0; } -/* - * Set the User Defined Part of the Display - */ - static int sisfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { @@ -1538,17 +1757,14 @@ unsigned int cols, rows; fb_display[con].var.activate = FB_ACTIVATE_NOW; - - /* Set mode */ - if (do_set_var(var, con == currcon, info)) { - crtc_to_var(var); /* return current mode to user */ + + if (sisfb_do_set_var(var, con == currcon, info)) { + sisfb_crtc_to_var(var); return -EINVAL; } - - /* get actual setting value */ - crtc_to_var(var); - - /* update display of current console */ + + sisfb_crtc_to_var(var); + sisfb_set_disp(con, var); if (info->changevar) @@ -1557,50 +1773,40 @@ if ((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0))) return err; - do_install_cmap(con, info); - - /* inform console to update struct display */ - cols = sisbios_mode[mode_idx].cols; - rows = sisbios_mode[mode_idx].rows; + sisfb_do_install_cmap(con, info); + + cols = sisbios_mode[sisfb_mode_idx].cols; + rows = sisbios_mode[sisfb_mode_idx].rows; vc_resize_con(rows, cols, fb_display[con].conp->vc_num); return 0; -} - -/* - * Get the Colormap - */ +} static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { - DPRINTK("sisfb: sisfb_get_cmap:[%d]\n", con); - if (con == currcon) return fb_get_cmap(cmap, kspc, sis_getcolreg, info); - else if (fb_display[con].cmap.len) /* non default colormap? */ + else if (fb_display[con].cmap.len) fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else fb_copy_cmap(fb_default_cmap(video_cmap_len), cmap, kspc ? 0 : 2); + return 0; } -/* - * Set the Colormap - */ - static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { int err; - if (!fb_display[con].cmap.len) { /* no colormap allocated */ + if (!fb_display[con].cmap.len) { err = fb_alloc_cmap(&fb_display[con].cmap, video_cmap_len, 0); if (err) return err; } - if (con == currcon) /* current console */ + if (con == currcon) return fb_set_cmap(cmap, kspc, sis_setcolreg, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); @@ -1613,24 +1819,24 @@ { switch (cmd) { case FBIO_ALLOC: - if(!capable(CAP_SYS_RAWIO)) + if (!capable(CAP_SYS_RAWIO)) return -EPERM; sis_malloc((struct sis_memreq *) arg); break; case FBIO_FREE: - if(!capable(CAP_SYS_RAWIO)) + if (!capable(CAP_SYS_RAWIO)) return -EPERM; sis_free(*(unsigned long *) arg); break; case FBIOGET_GLYPH: - sis_get_glyph((struct GlyInfo *) arg); + sis_get_glyph((SIS_GLYINFO *) arg); break; case FBIOGET_HWCINFO: { unsigned long *hwc_offset = (unsigned long *) arg; - if (caps & HW_CURSOR_CAP) - *hwc_offset = hwcursor_vbase - + if (sisfb_caps & HW_CURSOR_CAP) + *hwc_offset = sisfb_hwcursor_vbase - (unsigned long) ivideo.video_vbase; else *hwc_offset = 0; @@ -1638,10 +1844,9 @@ break; } case FBIOPUT_MODEINFO: - { + { struct mode_info *x = (struct mode_info *)arg; - - /* Set Mode Parameters by XServer */ + ivideo.video_bpp = x->bpp; ivideo.video_width = x->xres; ivideo.video_height = x->yres; @@ -1660,6 +1865,7 @@ return -EINVAL; } return 0; + } static int sisfb_mmap(struct fb_info *info, struct file *file, @@ -1673,19 +1879,17 @@ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; off = vma->vm_pgoff << PAGE_SHIFT; - - /* frame buffer memory */ + start = (unsigned long) ivideo.video_base; len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size); if (off >= len) { - /* memory mapped io */ off -= len; sisfb_get_var(&var, currcon, info); if (var.accel_flags) return -EINVAL; start = (unsigned long) ivideo.mmio_base; - len = PAGE_ALIGN((start & ~PAGE_MASK) + MMIO_SIZE); + len = PAGE_ALIGN((start & ~PAGE_MASK) + sisfb_mmio_size); } start &= PAGE_MASK; @@ -1700,96 +1904,54 @@ #endif if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot)) - return -EAGAIN; - return 0; -} - -static struct fb_ops sisfb_ops = { - owner: THIS_MODULE, - fb_get_fix: sisfb_get_fix, - fb_get_var: sisfb_get_var, - fb_set_var: sisfb_set_var, - fb_get_cmap: sisfb_get_cmap, - fb_set_cmap: sisfb_set_cmap, - fb_ioctl: sisfb_ioctl, - fb_mmap: sisfb_mmap, -}; - -int sisfb_setup(char *options) -{ - char *this_opt; - - fb_info.fontname[0] = '\0'; - ivideo.refresh_rate = 0; - - if (!options || !*options) - return 0; - - for (this_opt = strtok(options, ","); this_opt; - this_opt = strtok(NULL, ",")) { - if (!*this_opt) - continue; - - if (!strcmp(this_opt, "inverse")) { - inverse = 1; - fb_invert_cmaps(); - } else if (!strncmp(this_opt, "font:", 5)) { - strcpy(fb_info.fontname, this_opt + 5); - } else if (!strncmp(this_opt, "mode:", 5)) { - search_mode(this_opt + 5); - } else if (!strncmp(this_opt, "vrate:", 6)) { - ivideo.refresh_rate = - simple_strtoul(this_opt + 6, NULL, 0); - } else if (!strncmp(this_opt, "off", 3)) { - sisfb_off = 1; - } else if (!strncmp(this_opt, "crt1off", 7)) { - crt1off = 1; - } else - DPRINTK("invalid parameter %s\n", this_opt); - } + return -EAGAIN; return 0; + } +static struct fb_ops sisfb_ops = { + owner: THIS_MODULE, + fb_get_fix: sisfb_get_fix, + fb_get_var: sisfb_get_var, + fb_set_var: sisfb_set_var, + fb_get_cmap: sisfb_get_cmap, + fb_set_cmap: sisfb_set_cmap, + fb_ioctl: sisfb_ioctl, + fb_mmap: sisfb_mmap, +}; + +/* ------------ Interface to the low level console driver -------------*/ + static int sisfb_update_var(int con, struct fb_info *info) { return 0; } -/* - * Switch Console (called by fbcon.c) - */ - static int sisfb_switch(int con, struct fb_info *info) { int cols, rows; - DPRINTK("sisfb: switch console from [%d] to [%d]\n", currcon, con); - - /* update colormap of current console */ + if (fb_display[currcon].cmap.len) fb_get_cmap(&fb_display[currcon].cmap, 1, sis_getcolreg, info); fb_display[con].var.activate = FB_ACTIVATE_NOW; - /* same mode, needn't change mode actually */ - - if (!memcmp(&fb_display[con].var, &fb_display[currcon].var, sizeof(struct fb_var_screeninfo))) - { + if (!memcmp(&fb_display[con].var, &fb_display[currcon].var, sizeof(struct fb_var_screeninfo))) { currcon = con; return 1; } currcon = con; - do_set_var(&fb_display[con].var, 1, info); + sisfb_do_set_var(&fb_display[con].var, 1, info); sisfb_set_disp(con, &fb_display[con].var); + + sisfb_do_install_cmap(con, info); - /* Install new colormap */ - do_install_cmap(con, info); - - cols = sisbios_mode[mode_idx].cols; - rows = sisbios_mode[mode_idx].rows; + cols = sisbios_mode[sisfb_mode_idx].cols; + rows = sisbios_mode[sisfb_mode_idx].rows; vc_resize_con(rows, cols, fb_display[con].conp->vc_num); sisfb_update_var(con, info); @@ -1798,141 +1960,95 @@ } -/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ static void sisfb_blank(int blank, struct fb_info *info) { - u8 CRData; + u8 reg; vgawb(CRTC_ADR, 0x17); - CRData = vgarb(CRTC_DATA); + reg = vgarb(CRTC_DATA); - if (blank > 0) /* turn off CRT1 */ - CRData &= 0x7f; - else /* turn on CRT1 */ - CRData |= 0x80; + if (blank > 0) + reg &= 0x7f; + else + reg |= 0x80; vgawb(CRTC_ADR, 0x17); - vgawb(CRTC_DATA, CRData); -} - -int has_VB(void) -{ - u8 uSR38, uSR39, uVBChipID; - - vgawb(SEQ_ADR, 0x38); - uSR38 = vgarb(SEQ_DATA); - vgawb(SEQ_ADR, 0x39); - uSR39 = vgarb(SEQ_DATA); - vgawb(IND_SIS_CRT2_PORT_14, 0x0); - uVBChipID = vgarb(IND_SIS_CRT2_PORT_14+1); - - if ( - ( (HwExt.jChipID == SIS_Glamour) && (uSR38 & 0x20) ) /* 300 */ - || - ( (HwExt.jChipID >= SIS_Trojan ) && (uSR38 & 0x20) && (!(uSR39 & 0x80)) ) /* 630/540 */ - || - ( (HwExt.jChipID == SIS_Trojan ) && ((HwExt.revision_id & 0xf0) == 0x30) && (uVBChipID == 1) ) /* 630s */ - || - ( (HwExt.jChipID == SIS_730) && (uVBChipID == 1) ) /* 730 */ - ) - { - ivideo.hasVB = HASVB_301; - return TRUE; - } - else - { - ivideo.hasVB = HASVB_NONE; - return FALSE; - } + vgawb(CRTC_DATA, reg); } -void sis_get301info(void) +int sisfb_setup(char *options) { - u8 uCRData; - unsigned long disp_state=0; + char *this_opt; - if (HwExt.jChipID >= SIS_Trojan) - { - if (!has_VB()) - { - vgawb(CRTC_ADR, 0x37); - uCRData = vgarb(CRTC_DATA); + fb_info.fontname[0] = '\0'; + ivideo.refresh_rate = 0; - switch((uCRData >> 1) & 0x07) - { - case 2: - ivideo.hasVB = HASVB_LVDS; - break; - case 4: - ivideo.hasVB = HASVB_LVDS_CHRONTEL; - break; - case 3: - ivideo.hasVB = HASVB_TRUMPION; - break; - default: - break; - } - } - } - else - { - has_VB(); - } + if (!options || !*options) + return 0; - vgawb(CRTC_ADR, 0x32); - uCRData = vgarb(CRTC_DATA); - - switch(uDispType) - { - case MASK_DISPTYPE_CRT2: - disp_state = DISPTYPE_CRT2; - break; - case MASK_DISPTYPE_LCD: - disp_state = DISPTYPE_LCD; - break; - case MASK_DISPTYPE_TV: - disp_state = DISPTYPE_TV; - break; - } + for (this_opt = strtok(options, ","); this_opt; + this_opt = strtok(NULL, ",")) { + if (!*this_opt) + continue; - if(disp_state & 0x7) - { - if(crt1off) - disp_state |= DISPMODE_SINGLE; - else - disp_state |= (DISPMODE_MIRROR | DISPTYPE_CRT1); + if (!strcmp(this_opt, "inverse")) { + sisfb_inverse = 1; + fb_invert_cmaps(); + } else if (!strncmp(this_opt, "font:", 5)) { + strcpy(fb_info.fontname, this_opt + 5); + } else if (!strncmp(this_opt, "mode:", 5)) { + sisfb_search_mode(this_opt + 5); + } else if (!strncmp(this_opt, "vrate:", 6)) { + ivideo.refresh_rate = + simple_strtoul(this_opt + 6, NULL, 0); + } else if (!strncmp(this_opt, "off", 3)) { + sisfb_off = 1; + } else if (!strncmp(this_opt, "crt1off", 7)) { + sisfb_crt1off = 1; + } else + DPRINTK("invalid parameter %s\n", this_opt); } - else - disp_state = DISPMODE_SINGLE | DISPTYPE_CRT1; + return 0; - ivideo.disp_state = disp_state; } - int __init sisfb_init(void) { struct pci_dev *pdev = NULL; struct board *b; int pdev_valid = 0; - unsigned char jTemp; - u8 uSRData, uCRData; + unsigned long rom_vbase; + u32 reg32; + u16 reg16; + u8 reg; + outb(0x77, 0x80); +#if 0 + /* for DOC VB */ + sisfb_set_reg4(0xcf8,0x800000e0); + reg32 = sisfb_get_reg3(0xcfc); + reg32 = reg32 | 0x00001000; + sisfb_set_reg4(0xcfc,reg32); + } +#endif + if (sisfb_off) return -ENXIO; pci_for_each_dev(pdev) { - for (b = dev_list; b->vendor; b++) - { + for (b = sisdev_list; b->vendor; b++) { if ((b->vendor == pdev->vendor) - && (b->device == pdev->device)) - { + && (b->device == pdev->device)) { pdev_valid = 1; strcpy(fb_info.modename, b->name); ivideo.chip_id = pdev->device; - pci_read_config_byte(pdev, PCI_REVISION_ID, &HwExt.revision_id); + pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo.revision_id); + pci_read_config_word(pdev, PCI_COMMAND, ®16); + sishw_ext.uRevisionID = ivideo.revision_id; + sisvga_enabled = reg16 & 0x1; break; } } @@ -1944,368 +2060,276 @@ if (!pdev_valid) return -1; - switch(ivideo.chip_id) - { + switch (ivideo.chip_id) { case PCI_DEVICE_ID_SI_300: - HwExt.jChipID = SIS_Glamour; + ivideo.chip = SIS_Glamour; + sisvga_engine = SIS_300_VGA; break; case PCI_DEVICE_ID_SI_630_VGA: - HwExt.jChipID = SIS_Trojan; - break; + { + sisfb_set_reg4(0xCF8, 0x80000000); + reg32 = sisfb_get_reg3(0xCFC); + if (reg32 == 0x07301039) { + ivideo.chip = SIS_730; + strcpy(fb_info.modename, "SIS 730"); + } else + ivideo.chip = SIS_Trojan; + + sisvga_engine = SIS_300_VGA; + break; + } case PCI_DEVICE_ID_SI_540_VGA: - HwExt.jChipID = SIS_Spartan; + ivideo.chip = SIS_Spartan; + sisvga_engine = SIS_300_VGA; + break; + case PCI_DEVICE_ID_SI_315H: + ivideo.chip = SIS_GlamourII; + sisvga_engine = SIS_315_VGA; break; - case PCI_DEVICE_ID_SI_730_VGA: - HwExt.jChipID = SIS_730; + case PCI_DEVICE_ID_SI_315: + ivideo.chip = SIS_315; + sisvga_engine = SIS_315_VGA; + break; + case PCI_DEVICE_ID_SI_550_VGA: + ivideo.chip = SIS_550; + sisvga_engine = SIS_315_VGA; break; } + sishw_ext.jChipID = ivideo.chip; + + DPRINTK("%s is used as %s device(VGA Engine %d).\n", + fb_info.modename, sisvga_enabled ? "primary" : "secondary", sisvga_engine); + ivideo.video_base = pci_resource_start(pdev, 0); ivideo.mmio_base = pci_resource_start(pdev, 1); - ivideo.vga_base = pci_resource_start(pdev, 2) + 0x30; + sishw_ext.IOAddress = (unsigned short) ivideo.vga_base + = pci_resource_start(pdev, 2) + 0x30; - HwExt.IOAddress = (unsigned short)ivideo.vga_base; - rom_base = 0x000C0000; + sisfb_mmio_size = pci_resource_len(pdev, 1); - MMIO_SIZE = pci_resource_len(pdev, 1); + if (!sisvga_enabled) + if (pci_enable_device(pdev)) return -EIO; #ifdef NOBIOS - if (pci_enable_device(pdev)) - return -EIO; - /* Image file instead of VGA-bios */ - HwExt.VirtualRomBase = rom_vbase = (unsigned long) RomData; -#else -#ifdef CONFIG_FB_SIS_LINUXBIOS - if (pci_enable_device(pdev)) - return -EIO; - HwExt.VirtualRomBase = rom_vbase = 0; + sishw_ext.VirtualRomBase = rom_vbase = (unsigned long) rom_data; #else + { + unsigned long rom_base = 0x000C0000; + request_region(rom_base, 32, "sisfb"); - HwExt.VirtualRomBase = rom_vbase + sishw_ext.VirtualRomBase = rom_vbase = (unsigned long) ioremap(rom_base, MAX_ROM_SCAN); + } #endif -#endif - /* set passwd */ + vgawb(SEQ_ADR, IND_SIS_PASSWORD); vgawb(SEQ_DATA, SIS_PASSWORD); - /* Enable MMIO & PCI linear address */ vgawb(SEQ_ADR, IND_SIS_PCI_ADDRESS_SET); - jTemp = vgarb(SEQ_DATA); - jTemp |= SIS_PCI_ADDR_ENABLE; - jTemp |= SIS_MEM_MAP_IO_ENABLE; - vgawb(SEQ_DATA, jTemp); + reg = vgarb(SEQ_DATA); + reg |= SIS_PCI_ADDR_ENABLE; + reg |= SIS_MEM_MAP_IO_ENABLE; + vgawb(SEQ_DATA, reg); -#ifdef CONFIG_FB_SIS_LINUXBIOS - pdev_valid = 0; - pci_for_each_dev(pdev) { - u8 uPCIData=0; + vgawb(SEQ_ADR, IND_SIS_MODULE_ENABLE); + reg = vgarb(SEQ_DATA); + reg |= SIS_ENABLE_2D; + vgawb(SEQ_DATA, reg); - if ((pdev->vendor == PCI_VENDOR_ID_SI) && (pdev->device==0x630)) - { - pci_read_config_byte(pdev, 0x63, &uPCIData); - uPCIData = (uPCIData & 0x70) >> 4; - ivideo.video_size = (unsigned int)(1 << (uPCIData+21)); - pdev_valid = 1; - break; - } +#ifdef NOBIOS +#ifdef CONFIG_FB_SIS_300 + if (sisvga_engine == SIS_300_VGA) { + vgawb(SEQ_ADR, 0x28); + vgawb(SEQ_DATA, 0x37); + + vgawb(SEQ_ADR, 0x29); + vgawb(SEQ_DATA, 0x61); + + vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_1A); + reg = vgarb(SEQ_DATA); + reg |= SIS_SCRATCH_REG_1A_MASK; + vgawb(SEQ_DATA, reg); } - - if (!pdev_valid) - return -1; -#else - vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE); - ivideo.video_size = ((unsigned int) ((vgarb(SEQ_DATA) & 0x3f) + 1) << 20); +#endif +#ifdef CONFIG_FB_SIS_315 + if (ivideo.chip == SIS_550) { + /* TODO : Add 550 dummy codes for DOC */ + } +#endif #endif - - /* get CRT2 connection state */ - vgawb(SEQ_ADR, 0x17); - uSRData = vgarb(SEQ_DATA); - vgawb(CRTC_ADR, 0x32); - uCRData = vgarb(CRTC_DATA); - - ivideo.TV_plug = ivideo.TV_type = 0; - if((uSRData&0x0F) && (HwExt.jChipID>=SIS_Trojan)) - { - /* CRT1 connect detection */ - if((uSRData & 0x01) && !crt1off) - crt1off = 0; - else - { - if(uSRData&0x0E) /* DISP2 connected */ - crt1off = 1; + if (sisvga_engine == SIS_315_VGA) { + switch (ivideo.chip) { + case SIS_GlamourII: + case SIS_315: + sishw_ext.bIntegratedMMEnabled = TRUE; + break; + case SIS_550: + break; + default: + break; + } + } else if (sisvga_engine == SIS_300_VGA) { + if (ivideo.chip == SIS_Glamour) { + sishw_ext.bIntegratedMMEnabled = TRUE; + } else { + vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_1A); + reg = vgarb(SEQ_DATA); + if (reg & SIS_SCRATCH_REG_1A_MASK) + sishw_ext.bIntegratedMMEnabled = TRUE; else - crt1off = 0; + sishw_ext.bIntegratedMMEnabled = FALSE; } + } - /* detection priority : CRT2 > LCD > TV */ - if(uSRData & 0x08 ) - uDispType = MASK_DISPTYPE_CRT2; - else if(uSRData & 0x02) - uDispType = MASK_DISPTYPE_LCD; - else if(uSRData & 0x04) - { - if(uSRData & 0x80) - { - ivideo.TV_type = TVMODE_HIVISION; - ivideo.TV_plug = TVPLUG_SVIDEO; - } - else if(uSRData & 0x20) - ivideo.TV_plug = TVPLUG_SVIDEO; - else if(uSRData & 0x10) - ivideo.TV_plug = TVPLUG_COMPOSITE; - else if(uSRData & 0x40) - ivideo.TV_plug = TVPLUG_SCART; - - if(ivideo.TV_type == 0) - { - u8 uSR16; - vgawb(SEQ_ADR, 0x16); - uSR16 = vgarb(SEQ_DATA); - if(uSR16 & 0x20) - ivideo.TV_type = TVMODE_PAL; - else - ivideo.TV_type = TVMODE_NTSC; - } - uDispType = MASK_DISPTYPE_TV; +#ifdef CONFIG_FB_SIS_300 + if (sisvga_engine == SIS_300_VGA) { + if (!sisvga_enabled) { + SiSInit300(&sishw_ext); } - } - else - { - if((uCRData & 0x20) && !crt1off) - crt1off = 0; - else - { - if(uCRData&0x5F) /* DISP2 connected */ - crt1off = 1; - else - crt1off = 0; +#ifdef NOBIOS + else { + SiSInit300(&sishw_ext); } +#endif + sisfb_get_dram_size_300(); + } +#endif - if(uCRData & 0x10) - uDispType = MASK_DISPTYPE_CRT2; - else if(uCRData & 0x08) - uDispType = MASK_DISPTYPE_LCD; - else if(uCRData & 0x47) - { - uDispType = MASK_DISPTYPE_TV; - - if(uCRData & 0x40) - { - ivideo.TV_type = TVMODE_HIVISION; - ivideo.TV_plug = TVPLUG_SVIDEO; - } - else if(uCRData & 0x02) - ivideo.TV_plug = TVPLUG_SVIDEO; - else if(uCRData & 0x01) - ivideo.TV_plug = TVPLUG_COMPOSITE; - else if(uCRData & 0x04) - ivideo.TV_plug = TVPLUG_SCART; - - if(ivideo.TV_type == 0) - { - u8 uTemp; - uTemp = *((u8 *)(HwExt.VirtualRomBase+0x52)); - if(uTemp&0x40) - { - uTemp=*((u8 *)(HwExt.VirtualRomBase+0x53)); - } - else - { - vgawb(SEQ_ADR, 0x38); - uTemp = vgarb(SEQ_DATA); - } - if(uTemp & 0x01) - ivideo.TV_type = TVMODE_PAL; - else - ivideo.TV_type = TVMODE_NTSC; - } +#ifdef CONFIG_FB_SIS_315 + if (sisvga_engine == SIS_315_VGA) { + if (!sisvga_enabled) { + /* Mapping Max FB Size for 315 Init */ + sishw_ext.VirtualVideoMemoryAddress + = ioremap(ivideo.video_base, 0x8000000); + SiSInit310(&sishw_ext); } + sisfb_get_dram_size_315(); } +#endif - if(uDispType == MASK_DISPTYPE_LCD) // LCD conntected - { - // TODO: set LCDType by EDID - HwExt.usLCDType = LCD1024; + if (!request_mem_region(ivideo.video_base, ivideo.video_size, "sisfb FB")) { + printk(KERN_ERR "sisfb: cannot reserve frame buffer memory\n"); + return -ENODEV; } - if (HwExt.jChipID >= SIS_Trojan) - { - vgawb(SEQ_ADR, 0x1A); - uSRData = vgarb(SEQ_DATA); - if (uSRData & 0x10) - HwExt.bIntegratedMMEnabled = TRUE; - else - HwExt.bIntegratedMMEnabled = FALSE; + if (!request_mem_region(ivideo.mmio_base, sisfb_mmio_size, "sisfb MMIO")) { + printk(KERN_ERR "sisfb: cannot reserve MMIO region\n"); + release_mem_region(ivideo.video_base, ivideo.video_size); + return -ENODEV; } - if(mode_idx >= 0) /* mode found */ - { - /* Filtering mode for VB */ - switch(uDispType & MASK_DISPTYPE_DISP2) - { - case MASK_DISPTYPE_LCD: - switch(HwExt.usLCDType) - { - case LCD1024: - if(sisbios_mode[mode_idx].xres > 1024) - mode_idx = -1; - break; - case LCD1280: - if(sisbios_mode[mode_idx].xres > 1280) - mode_idx = -1; - break; - case LCD2048: - if(sisbios_mode[mode_idx].xres > 2048) - mode_idx = -1; - break; - case LCD1920: - if(sisbios_mode[mode_idx].xres > 1920) - mode_idx = -1; - break; - case LCD1600: - if(sisbios_mode[mode_idx].xres > 1600) - mode_idx = -1; - break; - case LCD800: - if(sisbios_mode[mode_idx].xres > 800) - mode_idx = -1; - break; - case LCD640: - if(sisbios_mode[mode_idx].xres > 640) - mode_idx = -1; - break; - default: - mode_idx = -1; - } + sishw_ext.VirtualVideoMemoryAddress = ivideo.video_vbase + = ioremap(ivideo.video_base, ivideo.video_size); + ivideo.mmio_vbase = ioremap(ivideo.mmio_base, sisfb_mmio_size); - if(sisbios_mode[mode_idx].xres == 720) /* only for TV */ - mode_idx = -1; - break; - case MASK_DISPTYPE_TV: - switch(sisbios_mode[mode_idx].xres) - { - case 800: - case 640: - break; - case 720: - if(ivideo.TV_type == TVMODE_NTSC) - { - if(sisbios_mode[mode_idx].yres != 480) - mode_idx = -1; - } - else if(ivideo.TV_type == TVMODE_PAL) - { - if(sisbios_mode[mode_idx].yres != 576) - mode_idx = -1; - } - break; + printk(KERN_INFO + "sisfb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", + ivideo.video_base, ivideo.video_vbase, + ivideo.video_size / 1024); + + printk(KERN_INFO + "sisfb: MMIO at 0x%lx, mapped to 0x%p, size %ldk\n", + ivideo.mmio_base, ivideo.mmio_vbase, + sisfb_mmio_size / 1024); + +#ifdef CONFIG_FB_SIS_300 + if (sisvga_engine == SIS_300_VGA) { + sisfb_get_VB_type_300(); + if (ivideo.hasVB != HASVB_NONE) + sisfb_detect_VB_connect_300(); + } +#endif + +#ifdef CONFIG_FB_SIS_315 + if (sisvga_engine == SIS_315_VGA) { + sisfb_get_VB_type_315(); + if (ivideo.hasVB != HASVB_NONE) + sisfb_detect_VB_connect_315(); + } +#endif + + if (ivideo.disp_state & DISPTYPE_DISP2) { + if (sisfb_crt1off) + ivideo.disp_state |= DISPMODE_SINGLE; + else + ivideo.disp_state |= (DISPMODE_MIRROR | DISPTYPE_CRT1); + } else + ivideo.disp_state = DISPMODE_SINGLE | DISPTYPE_CRT1; + + if (ivideo.disp_state & DISPTYPE_LCD) { + vgawb(CRTC_ADR, IND_SIS_LCD_PANEL); + reg = vgarb(CRTC_DATA); + switch (reg) { + case SIS_LCD_PANEL_800X600: + sishw_ext.usLCDType = LCD800; break; + case SIS_LCD_PANEL_1024X768: + sishw_ext.usLCDType = LCD1024; break; + case SIS_LCD_PANEL_1280X1024: + sishw_ext.usLCDType = LCD1280; break; + case SIS_LCD_PANEL_640X480: + sishw_ext.usLCDType = LCD640; break; default: - /* illegal mode */ - mode_idx = -1; - } - break; + sishw_ext.usLCDType = LCD1024; break; } - } - - if (mode_idx < 0) - { - switch(uDispType & MASK_DISPTYPE_DISP2) - { - case MASK_DISPTYPE_LCD: - mode_idx = DEFAULT_LCDMODE; - break; - case MASK_DISPTYPE_TV: - mode_idx = DEFAULT_TVMODE; - break; + } + + if (sisfb_mode_idx >= 0) + sisfb_validate_mode(); + + if (sisfb_mode_idx < 0) { + switch (ivideo.disp_state & DISPTYPE_DISP2) { + case DISPTYPE_LCD: + sisfb_mode_idx = DEFAULT_LCDMODE; break; + case DISPTYPE_TV: + sisfb_mode_idx = DEFAULT_TVMODE; break; default: - mode_idx = DEFAULT_MODE; + sisfb_mode_idx = DEFAULT_MODE; break; } } -#ifdef CONFIG_FB_SIS_LINUXBIOS - mode_idx = DEFAULT_MODE; - rate_idx = sisbios_mode[mode_idx].rate_idx; - /* set to default refresh rate 60MHz */ - ivideo.refresh_rate = 60; -#endif - - mode_no = sisbios_mode[mode_idx].mode_no; + sisfb_mode_no = sisbios_mode[sisfb_mode_idx].mode_no; if (ivideo.refresh_rate != 0) - search_refresh_rate(ivideo.refresh_rate); + sisfb_search_refresh_rate(ivideo.refresh_rate); - if (rate_idx == 0) { - rate_idx = sisbios_mode[mode_idx].rate_idx; - /* set to default refresh rate 60MHz */ + if (sisfb_rate_idx == 0) { + sisfb_rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx; ivideo.refresh_rate = 60; } - ivideo.video_bpp = sisbios_mode[mode_idx].bpp; - ivideo.video_vwidth = ivideo.video_width = sisbios_mode[mode_idx].xres; - ivideo.video_vheight = ivideo.video_height = sisbios_mode[mode_idx].yres; + ivideo.video_bpp = sisbios_mode[sisfb_mode_idx].bpp; + ivideo.video_vwidth = ivideo.video_width = sisbios_mode[sisfb_mode_idx].xres; + ivideo.video_vheight = ivideo.video_height = sisbios_mode[sisfb_mode_idx].yres; ivideo.org_x = ivideo.org_y = 0; video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3); - printk(KERN_DEBUG "FB base: 0x%lx, size: 0x%dK\n", - ivideo.video_base, (unsigned int)ivideo.video_size/1024); - printk(KERN_DEBUG "MMIO base: 0x%lx, size: 0x%dK\n", - ivideo.mmio_base, (unsigned int)MMIO_SIZE/1024); - - - if (!request_mem_region(ivideo.video_base, ivideo.video_size, "sisfb FB")) - { - printk(KERN_ERR "sisfb: cannot reserve frame buffer memory\n"); - return -ENODEV; - } - - if (!request_mem_region(ivideo.mmio_base, MMIO_SIZE, "sisfb MMIO")) - { - printk(KERN_ERR "sisfb: cannot reserve MMIO region\n"); - release_mem_region(ivideo.video_base, ivideo.video_size); - return -ENODEV; - } - - HwExt.VirtualVideoMemoryAddress = ivideo.video_vbase - = ioremap(ivideo.video_base, ivideo.video_size); - ivideo.mmio_vbase = ioremap(ivideo.mmio_base, MMIO_SIZE); - -#ifdef NOBIOS - SiSInit300(&HwExt); -#else -#ifdef CONFIG_FB_SIS_LINUXBIOS - SiSInit300(&HwExt); -#endif -#endif - printk(KERN_INFO - "sisfb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", - ivideo.video_base, ivideo.video_vbase, - ivideo.video_size / 1024); printk(KERN_INFO "sisfb: mode is %dx%dx%d, linelength=%d\n", ivideo.video_width, ivideo.video_height, ivideo.video_bpp, video_linelength); - /* enable 2D engine */ - vgawb(SEQ_ADR, IND_SIS_MODULE_ENABLE); - jTemp = vgarb(SEQ_DATA); - jTemp |= SIS_2D_ENABLE; - vgawb(SEQ_DATA, jTemp); - - pre_setmode(); - - if (SiSSetMode(&HwExt, mode_no)) { - DPRINTK("sisfb: set mode[0x%x]: failed\n", mode_no); - return -1; - } + sisfb_pre_setmode(); - post_setmode(); +#ifdef CONFIG_FB_SIS_300 + if (sisvga_engine == SIS_300_VGA) + if (SiSSetMode(&sishw_ext, sisfb_mode_no)) { + DPRINTK("set mode[0x%x]: failed\n", sisfb_mode_no); + return -1; + } +#endif - /* Get VB functions */ - sis_get301info(); +#ifdef CONFIG_FB_SIS_315 + if (sisvga_engine == SIS_315_VGA) + if (SiSSetMode310(&sishw_ext, sisfb_mode_no)) { + DPRINTK("set mode[0x%x]: failed\n", sisfb_mode_no); + return -1; + } +#endif + sisfb_post_setmode(); - crtc_to_var(&default_var); + sisfb_crtc_to_var(&default_var); fb_info.changevar = NULL; fb_info.node = -1; @@ -2322,7 +2346,6 @@ DPRINTK("sisfb: Failed to enable offscreen heap\n"); } - /* to avoid the inversed bgcolor bug of the initial state */ vc_resize_con(1, 1, 0); if (register_framebuffer(&fb_info) < 0) @@ -2342,19 +2365,19 @@ MODULE_PARM(mode, "s"); MODULE_PARM(rate, "i"); -MODULE_PARM(crt1, "i"); /* default: CRT1 enable */ +MODULE_PARM(crt1, "i"); int init_module(void) { if (mode) - search_mode(mode); + sisfb_search_mode(mode); ivideo.refresh_rate = rate; - if(crt1 == 0) - crt1off = 1; + if (crt1 == 0) + sisfb_crt1off = 1; else - crt1off = 0; + sisfb_crt1off = 0; sisfb_init(); @@ -2365,10 +2388,11 @@ { unregister_framebuffer(&fb_info); } -#endif /* MODULE */ +#endif EXPORT_SYMBOL(sis_malloc); EXPORT_SYMBOL(sis_free); EXPORT_SYMBOL(ivideo); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/sis/sis_main.h linux.ac/drivers/video/sis/sis_main.h --- linux.vanilla/drivers/video/sis/sis_main.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/sis/sis_main.h Tue Apr 3 17:55:10 2001 @@ -0,0 +1,431 @@ +#include <linux/config.h> +/* ------------------- Constant Definitions ------------------------- */ + +#define VER_MAJOR 1 +#define VER_MINOR 1 + +#define DEFAULT_MODE 0 +#define DEFAULT_LCDMODE 9 +#define DEFAULT_TVMODE 9 + +#define MAX_ROM_SCAN 0x10000 + +#define TURBO_QUEUE_CAP 0x80 +#define HW_CURSOR_CAP 0x40 +#define AGP_CMD_QUEUE_CAP 0x80 +#define VM_CMD_QUEUE_CAP 0x20 + +/* For 300 series */ +#ifdef CONFIG_FB_SIS_300 +#define TURBO_QUEUE_AREA_SIZE 0x80000 /* 512K */ +#define HW_CURSOR_AREA_SIZE 0x1000 /* 4K */ +#endif + +/* For 315 series */ +#ifdef CONFIG_FB_SIS_315 +#define COMMAND_QUEUE_AREA_SIZE 0x80000 /* 512K */ +#define HW_CURSOR_AREA_SIZE 0x4000 /* 16K */ +#define COMMAND_QUEUE_THRESHOLD 0x1F +#endif + +#define OH_ALLOC_SIZE 4000 +#define SENTINEL 0x7fffffff + +#define SEQ_ADR 0x14 +#define SEQ_DATA 0x15 +#define DAC_ADR 0x18 +#define DAC_DATA 0x19 +#define CRTC_ADR 0x24 +#define CRTC_DATA 0x25 +#define DAC2_ADR (0x16-0x30) +#define DAC2_DATA (0x17-0x30) +#define VB_PART1_ADR (0x04-0x30) +#define VB_PART1_DATA (0x05-0x30) +#define VB_PART2_ADR (0x10-0x30) +#define VB_PART2_DATA (0x11-0x30) +#define VB_PART3_ADR (0x12-0x30) +#define VB_PART3_DATA (0x13-0x30) +#define VB_PART4_ADR (0x14-0x30) +#define VB_PART4_DATA (0x15-0x30) + +#define IND_SIS_PASSWORD 0x05 /* SRs */ +#define IND_SIS_COLOR_MODE 0x06 +#define IND_SIS_RAMDAC_CONTROL 0x07 +#define IND_SIS_DRAM_SIZE 0x14 +#define IND_SIS_SCRATCH_REG_16 0x16 +#define IND_SIS_SCRATCH_REG_17 0x17 +#define IND_SIS_SCRATCH_REG_1A 0x1A +#define IND_SIS_MODULE_ENABLE 0x1E +#define IND_SIS_PCI_ADDRESS_SET 0x20 +#define IND_SIS_TURBOQUEUE_ADR 0x26 +#define IND_SIS_TURBOQUEUE_SET 0x27 +#define IND_SIS_POWER_ON_TRAP 0x38 +#define IND_SIS_POWER_ON_TRAP2 0x39 +#define IND_SIS_CMDQUEUE_SET 0x26 +#define IND_SIS_CMDQUEUE_THRESHOLD 0x27 + +#define IND_SIS_SCRATCH_REG_CR30 0x30 /* CRs */ +#define IND_SIS_SCRATCH_REG_CR31 0x31 +#define IND_SIS_SCRATCH_REG_CR32 0x32 +#define IND_SIS_SCRATCH_REG_CR33 0x33 +#define IND_SIS_LCD_PANEL 0x36 +#define IND_SIS_SCRATCH_REG_CR37 0x37 +#define IND_SIS_AGP_IO_PAD 0x48 + +#define IND_BRI_DRAM_STATUS 0x63 + +#define MMIO_QUEUE_PHYBASE 0x85C0 +#define MMIO_QUEUE_WRITEPORT 0x85C4 +#define MMIO_QUEUE_READPORT 0x85C8 + +#define SIS_PASSWORD 0x86 /* SR05 */ +#define SIS_INTERLACED_MODE 0x20 /* SR06 */ +#define SIS_8BPP_COLOR_MODE 0x0 +#define SIS_15BPP_COLOR_MODE 0x1 +#define SIS_16BPP_COLOR_MODE 0x2 +#define SIS_32BPP_COLOR_MODE 0x4 +#define SIS_DRAM_SIZE_MASK 0x3F /* SR14 */ +#define SIS_DRAM_SIZE_1MB 0x00 +#define SIS_DRAM_SIZE_2MB 0x01 +#define SIS_DRAM_SIZE_4MB 0x03 +#define SIS_DRAM_SIZE_8MB 0x07 +#define SIS_DRAM_SIZE_16MB 0x0F +#define SIS_DRAM_SIZE_32MB 0x1F +#define SIS_DRAM_SIZE_64MB 0x3F +#define SIS_DATA_BUS_MASK 0xC0 +#define SIS_DATA_BUS_32 0x00 +#define SIS_DATA_BUS_64 0x01 +#define SIS_DATA_BUS_128 0x02 +#define SIS315_DRAM_SIZE_MASK 0xF0 /* 315 SR14 */ +#define SIS315_DRAM_SIZE_2MB 0x01 +#define SIS315_DRAM_SIZE_4MB 0x02 +#define SIS315_DRAM_SIZE_8MB 0x03 +#define SIS315_DRAM_SIZE_16MB 0x04 +#define SIS315_DRAM_SIZE_32MB 0x05 +#define SIS315_DRAM_SIZE_64MB 0x06 +#define SIS315_DRAM_SIZE_128MB 0x07 +#define SIS315_DATA_BUS_MASK 0x02 +#define SIS315_DATA_BUS_64 0x00 +#define SIS315_DATA_BUS_128 0x01 +#define SIS315_DUAL_CHANNEL_MASK 0x0C +#define SIS315_SINGLE_CHANNEL_1_RANK 0x0 +#define SIS315_SINGLE_CHANNEL_2_RANK 0x1 +#define SIS315_DUAL_CHANNEL_1_RANK 0x3 +#define SIS_SCRATCH_REG_1A_MASK 0x10 +#define SIS_ENABLE_2D 0x40 /* SR1E */ +#define SIS_MEM_MAP_IO_ENABLE 0x01 /* SR20 */ +#define SIS_PCI_ADDR_ENABLE 0x80 +#define SIS_AGP_CMDQUEUE_ENABLE 0x80 /* 315 SR26 */ +#define SIS_VRAM_CMDQUEUE_ENABLE 0x40 +#define SIS_MMIO_CMD_ENABLE 0x20 +#define SIS_CMD_QUEUE_SIZE_512k 0x00 +#define SIS_CMD_QUEUE_SIZE_1M 0x04 +#define SIS_CMD_QUEUE_SIZE_2M 0x08 +#define SIS_CMD_QUEUE_SIZE_4M 0x0C +#define SIS_CMD_QUEUE_RESET 0x01 +#define SIS_SIMULTANEOUS_VIEW_ENABLE 0x01 /* CR30 */ +#define SIS_MODE_SELECT_CRT2 0x02 +#define SIS_VB_OUTPUT_COMPOSITE 0x04 +#define SIS_VB_OUTPUT_SVIDEO 0x08 +#define SIS_VB_OUTPUT_SCART 0x10 +#define SIS_VB_OUTPUT_LCD 0x20 +#define SIS_VB_OUTPUT_CRT2 0x40 +#define SIS_VB_OUTPUT_HIVISION 0x80 +#define SIS_VB_OUTPUT_DISABLE 0x20 /* CR31 */ +#define SIS_DRIVER_MODE 0x40 +#define SIS_VB_COMPOSITE 0x01 /* CR32 */ +#define SIS_VB_SVIDEO 0x02 +#define SIS_VB_SCART 0x04 +#define SIS_VB_LCD 0x08 +#define SIS_VB_CRT2 0x10 +#define SIS_CRT1 0x20 +#define SIS_VB_HIVISION 0x40 +#define SIS_VB_DVI 0x80 +#define SIS_VB_TV (SIS_VB_COMPOSITE | SIS_VB_SVIDEO | SIS_VB_SCART | SIS_VB_HIVISION) +#define SIS_LCD_PANEL_800X600 0x1 /* CR36 */ +#define SIS_LCD_PANEL_1024X768 0x2 +#define SIS_LCD_PANEL_1280X1024 0x3 +#define SIS_LCD_PANEL_1280X960 0x4 +#define SIS_LCD_PANEL_640X480 0x5 +#define SIS_EXTERNAL_CHIP_MASK 0x0E /* CR37 */ +#define SIS_EXTERNAL_CHIP_SIS301 0x01 +#define SIS_EXTERNAL_CHIP_LVDS 0x02 +#define SIS_EXTERNAL_CHIP_TRUMPION 0x03 +#define SIS_EXTERNAL_CHIP_LVDS_CHRONTEL 0x04 +#define SIS_AGP_2X 0x20 /* CR48 */ + +#define BRI_DRAM_SIZE_MASK 0x70 /* PCI bridge */ +#define BRI_DRAM_SIZE_2MB 0x00 +#define BRI_DRAM_SIZE_4MB 0x01 +#define BRI_DRAM_SIZE_8MB 0x02 +#define BRI_DRAM_SIZE_16MB 0x03 +#define BRI_DRAM_SIZE_32MB 0x04 +#define BRI_DRAM_SIZE_64MB 0x05 + +/* ------------------- Global Variables ----------------------------- */ + +/* Fbcon variables */ +static struct fb_info fb_info; +static struct display disp; +static int video_type = FB_TYPE_PACKED_PIXELS; +static int video_linelength; +static int video_cmap_len; +static struct display_switch sisfb_sw; +static struct fb_var_screeninfo default_var = { + 0, 0, 0, 0, + 0, 0, + 0, + 0, + {0, 8, 0}, + {0, 8, 0}, + {0, 8, 0}, + {0, 0, 0}, + 0, + FB_ACTIVATE_NOW, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, + FB_VMODE_NONINTERLACED, + {0, 0, 0, 0, 0, 0} +}; + +static struct { + u16 blue, green, red, pad; +} palette[256]; +static union { +#ifdef FBCON_HAS_CFB16 + u16 cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB24 + u32 cfb24[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u32 cfb32[16]; +#endif +} fbcon_cmap; + +/* display status */ +static int sisfb_off = 0; +static int sisfb_crt1off = 0; +static int sisfb_inverse = 0; +static int sisvga_enabled = 0; +static int currcon = 0; +static enum _VGA_ENGINE { + UNKNOWN_VGA = 0, + SIS_300_VGA, + SIS_315_VGA, +} sisvga_engine = UNKNOWN_VGA; + +/* mode-related variables */ +int sisfb_mode_idx = -1; +u8 sisfb_mode_no = 0; +u8 sisfb_rate_idx = 0; + +/* data for sis components*/ +struct video_info ivideo; +HW_DEVICE_EXTENSION sishw_ext = {0,0,0,0,0,0,0,0,0}; + +/* card parameters */ +static unsigned long sisfb_mmio_size = 0; +static u8 sisfb_caps = 0; + +typedef enum _SIS_CMDTYPE { + MMIO_CMD = 0, + AGP_CMD_QUEUE, + VM_CMD_QUEUE, +} SIS_CMDTYPE; + +/* Supported SiS Chips list */ +static struct board { + u16 vendor, device; + const char *name; +} sisdev_list[] = { + {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"}, + {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, "SIS 540"}, + {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, "SIS 630"}, + {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315H, "SIS 315H"}, + {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315, "SIS 315"}, + {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_550_VGA, "SIS 550"}, + {0, 0, NULL} +}; + +/* mode table */ +static const struct _sisbios_mode { + char name[15]; + u8 mode_no; + u16 xres; + u16 yres; + u16 bpp; + u16 rate_idx; + u16 cols; + u16 rows; +} sisbios_mode[] = { + {"640x480x8", 0x2E, 640, 480, 8, 1, 80, 30}, + {"640x480x16", 0x44, 640, 480, 16, 1, 80, 30}, + {"640x480x32", 0x62, 640, 480, 32, 1, 80, 30}, + {"720x480x8", 0x31, 720, 480, 8, 1, 90, 30}, + {"720x480x16", 0x33, 720, 480, 16, 1, 90, 30}, + {"720x480x32", 0x35, 720, 480, 32, 1, 90, 30}, + {"720x576x8", 0x32, 720, 576, 8, 1, 90, 36}, + {"720x576x16", 0x34, 720, 576, 16, 1, 90, 36}, + {"720x576x32", 0x36, 720, 576, 32, 1, 90, 36}, + {"800x600x8", 0x30, 800, 600, 8, 2, 100, 37}, + {"800x600x16", 0x47, 800, 600, 16, 2, 100, 37}, + {"800x600x32", 0x63, 800, 600, 32, 2, 100, 37}, + {"1024x768x8", 0x38, 1024, 768, 8, 2, 128, 48}, + {"1024x768x16", 0x4A, 1024, 768, 16, 2, 128, 48}, + {"1024x768x32", 0x64, 1024, 768, 32, 2, 128, 48}, + {"1280x1024x8", 0x3A, 1280, 1024, 8, 2, 160, 64}, + {"1280x1024x16", 0x4D, 1280, 1024, 16, 2, 160, 64}, + {"1280x1024x32", 0x65, 1280, 1024, 32, 2, 160, 64}, + {"1600x1200x8", 0x3C, 1600, 1200, 8, 1, 200, 75}, + {"1600x1200x16", 0x3D, 1600, 1200, 16, 1, 200, 75}, + {"1600x1200x32", 0x66, 1600, 1200, 32, 1, 200, 75}, + {"1920x1440x8", 0x68, 1920, 1440, 8, 1, 240, 75}, + {"1920x1440x16", 0x69, 1920, 1440, 16, 1, 240, 75}, + {"1920x1440x32", 0x6B, 1920, 1440, 32, 1, 240, 75}, + {"\0", 0x00, 0, 0, 0, 0, 0, 0} +}; + +static struct _sis_vrate { + u16 idx; + u16 xres; + u16 yres; + u16 refresh; +} sisfb_vrate[] = { + {1, 640, 480, 60}, {2, 640, 480, 72}, {3, 640, 480, 75}, {4, 640, 480, 85}, + {5, 640, 480, 100}, {6, 640, 480, 120}, {7, 640, 480, 160}, {8, 640, 480, 200}, + {1, 720, 480, 60}, + {1, 720, 576, 50}, + {1, 800, 600, 56}, {2, 800, 600, 60}, {3, 800, 600, 72}, {4, 800, 600, 75}, + {5, 800, 600, 85}, {6, 800, 600, 100}, {7, 800, 600, 120}, {8, 800, 600, 160}, + {1, 1024, 768, 43}, {2, 1024, 768, 60}, {3, 1024, 768, 70}, {4, 1024, 768, 75}, + {5, 1024, 768, 85}, {6, 1024, 768, 100}, {7, 1024, 768, 120}, + {1, 1280, 1024, 43}, {2, 1280, 1024, 60}, {3, 1280, 1024, 75}, {4, 1280, 1024, 85}, + {1, 1600, 1200, 60}, {2, 1600, 1200, 65}, {3, 1600, 1200, 70}, {4, 1600, 1200, 75}, + {5, 1600, 1200, 85}, + {1, 1920, 1440, 60}, + {0, 0, 0, 0} +}; + +/* Offscreen layout */ +typedef struct _SIS_GLYINFO { + unsigned char ch; + int fontwidth; + int fontheight; + u8 gmask[72]; + int ngmask; +} SIS_GLYINFO; + +typedef struct _SIS_OH { + struct _SIS_OH *poh_next; + struct _SIS_OH *poh_prev; + unsigned long offset; + unsigned long size; +} SIS_OH; + +typedef struct _SIS_OHALLOC { + struct _SIS_OHALLOC *poha_next; + SIS_OH aoh[1]; +} SIS_OHALLOC; + +typedef struct _SIS_HEAP { + SIS_OH oh_free; + SIS_OH oh_used; + SIS_OH *poh_freelist; + SIS_OHALLOC *poha_chain; + unsigned long max_freesize; +} SIS_HEAP; + +static unsigned long sisfb_hwcursor_vbase; + +static unsigned long sisfb_heap_start; +static unsigned long sisfb_heap_end; +static unsigned long sisfb_heap_size; +static SIS_HEAP sisfb_heap; + +/* ---------------------- Routine Prototype ------------------------- */ + +/* Interface used by the world */ +int sisfb_setup(char *options); +static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); +static int sisfb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int sisfb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int sisfb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con, + struct fb_info *info); + +/* Interface to the low level console driver */ +int sisfb_init(void); +static int sisfb_update_var(int con, struct fb_info *info); +static int sisfb_switch(int con, struct fb_info *info); +static void sisfb_blank(int blank, struct fb_info *info); + +/* hardware access routines */ +void sisfb_set_reg1(u16 port, u16 index, u16 data); +void sisfb_set_reg3(u16 port, u16 data); +void sisfb_set_reg4(u16 port, unsigned long data); +u8 sisfb_get_reg1(u16 port, u16 index); +u8 sisfb_get_reg2(u16 port); +u32 sisfb_get_reg3(u16 port); +void sisfb_clear_DAC(u16 port); +void sisfb_clear_buffer(PHW_DEVICE_EXTENSION psishw_ext); + +/* Internal routines */ +static void sisfb_search_mode(const char *name); +static void sisfb_validate_mode(void); +static u8 sisfb_search_refresh_rate(unsigned int rate); +static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, + struct fb_info *fb_info); +static int sis_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *fb_info); +static int sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, + struct fb_info *info); +static void sisfb_set_disp(int con, struct fb_var_screeninfo *var); +static void sisfb_do_install_cmap(int con, struct fb_info *info); + +/* Chip-dependent Routines */ +#ifdef CONFIG_FB_SIS_300 +static int sisfb_get_dram_size_300(void); +extern BOOLEAN SiSInit300(PHW_DEVICE_EXTENSION HwDeviceExtension); +static void sisfb_detect_VB_connect_300(void); +static void sisfb_get_VB_type_300(void); +static int sisfb_has_VB_300(void); +extern BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension, + USHORT ModeNo); +#endif +#ifdef CONFIG_FB_SIS_315 +static int sisfb_get_dram_size_315(void); +extern BOOLEAN SiSInit310(PHW_DEVICE_EXTENSION HwDeviceExtension); +static void sisfb_detect_VB_connect_315(void); +static void sisfb_get_VB_type_315(void); +extern BOOLEAN SiSSetMode310(PHW_DEVICE_EXTENSION HwDeviceExtension, + USHORT ModeNo); +#endif + +/* SetMode routines */ +static void sisfb_pre_setmode(void); +static void sisfb_post_setmode(void); +static void sisfb_crtc_to_var(struct fb_var_screeninfo *var); + +/* Export functions */ +static void sis_get_glyph(SIS_GLYINFO *gly); +void sis_dispinfo(struct ap_data *rec); +void sis_malloc(struct sis_memreq *req); +void sis_free(unsigned long base); + +/* heap routines */ +static int sisfb_heap_init(void); +static SIS_OH *sisfb_poh_new_node(void); +static SIS_OH *sisfb_poh_allocate(unsigned long size); +static void sisfb_delete_node(SIS_OH *poh); +static void sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh); +static SIS_OH *sisfb_poh_free(unsigned long base); +static void sisfb_free_node(SIS_OH *poh); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/sticon-bmode.c linux.ac/drivers/video/sticon-bmode.c --- linux.vanilla/drivers/video/sticon-bmode.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/sticon-bmode.c Tue Apr 3 17:55:10 2001 @@ -473,8 +473,9 @@ offset++; dest++; } - __flush_dcache_range(dest, count); - __flush_icache_range(dest, count); + + flush_kernel_dcache_range((unsigned long)dest, count); + flush_icache_range((unsigned long)dest, dest + count); } static void dump_sti_rom(struct sti_rom *rom) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/sticore.c linux.ac/drivers/video/sticore.c --- linux.vanilla/drivers/video/sticore.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/sticore.c Tue Apr 3 17:55:10 2001 @@ -208,8 +208,9 @@ offset++; dest++; } - __flush_dcache_range((unsigned long) dest, count); - __flush_icache_range((unsigned long) dest, count); + + flush_kernel_dcache_range((unsigned long)dest, count); + flush_icache_range((unsigned long)dest, dest + count); } static void dump_sti_rom(struct sti_rom *rom) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/sun3fb.c linux.ac/drivers/video/sun3fb.c --- linux.vanilla/drivers/video/sun3fb.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/sun3fb.c Tue Apr 3 17:55:10 2001 @@ -586,9 +586,11 @@ fb->cursor.hwsize.fbx = 32; fb->cursor.hwsize.fby = 32; - if (depth > 1 && !fb->color_map) + if (depth > 1 && !fb->color_map) { fb->color_map = kmalloc(256 * 3, GFP_ATOMIC); - + return -ENOMEM; + } + switch(fbtype) { #ifdef CONFIG_FB_CGSIX case FBTYPE_SUNFAST_COLOR: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/tdfxfb.c linux.ac/drivers/video/tdfxfb.c --- linux.vanilla/drivers/video/tdfxfb.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/tdfxfb.c Wed Apr 4 13:36:17 2001 @@ -88,6 +88,10 @@ #include <linux/spinlock.h> +#ifndef PCI_DEVICE_ID_3DFX_VOODOO5 +#define PCI_DEVICE_ID_3DFX_VOODOO5 0x0009 +#endif + /* membase0 register offsets */ #define STATUS 0x00 #define PCIINIT0 0x04 @@ -248,6 +252,7 @@ #define BANSHEE_MAX_PIXCLOCK 270000.0 #define VOODOO3_MAX_PIXCLOCK 300000.0 +#define VOODOO5_MAX_PIXCLOCK 350000.0 struct banshee_reg { /* VGA rubbish */ @@ -279,6 +284,7 @@ unsigned long clip1max; unsigned long srcbase; unsigned long dstbase; + unsigned long miscinit0; }; struct tdfxfb_par { @@ -646,12 +652,14 @@ static void do_flashcursor(unsigned long ptr) { struct fb_info_tdfx* i=(struct fb_info_tdfx *)ptr; - spin_lock(&i->DAClock); + unsigned long flags; + + spin_lock_irqsave(&i->DAClock, flags); banshee_make_room(1); tdfx_outl( VIDPROCCFG, tdfx_inl(VIDPROCCFG) ^ VIDCFG_HWCURSOR_ENABLE ); i->cursor.timer.expires=jiffies+HZ/2; add_timer(&i->cursor.timer); - spin_unlock(&i->DAClock); + spin_unlock_irqrestore(&i->DAClock, flags); } /* @@ -921,6 +929,7 @@ tdfx_outl(VIDDESKSTART, reg->startaddr); tdfx_outl(VIDPROCCFG, reg->vidcfg); tdfx_outl(VGAINIT1, reg->vgainit1); + tdfx_outl(MISCINIT0, reg->miscinit0); banshee_make_room(8); tdfx_outl(SRCBASE, reg->srcbase); @@ -942,19 +951,27 @@ u32 lfbsize = 0; int sgram_p = 0; - if(!((fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE) || - (fb_info.dev == PCI_DEVICE_ID_3DFX_VOODOO3))) - return 0; - draminit0 = tdfx_inl(DRAMINIT0); draminit1 = tdfx_inl(DRAMINIT1); - - sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1; + + if ((fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE) || + (fb_info.dev == PCI_DEVICE_ID_3DFX_VOODOO3)) { + sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1; - lfbsize = sgram_p ? - (((draminit0 & DRAMINIT0_SGRAM_NUM) ? 2 : 1) * - ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) : - 16 * 1024 * 1024; + lfbsize = sgram_p ? + (((draminit0 & DRAMINIT0_SGRAM_NUM) ? 2 : 1) * + ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) : + 16 * 1024 * 1024; + } else { + /* Voodoo4/5 */ + u32 chips, psize, banks; + + chips = ((draminit0 & (1 << 26)) == 0) ? 4 : 8; + psize = 1 << ((draminit0 & 0x38000000) >> 28); + banks = ((draminit0 & (1 << 30)) == 0) ? 2 : 4; + lfbsize = chips * psize * banks; + lfbsize <<= 20; + } /* disable block writes for SDRAM (why?) */ miscinit1 = tdfx_inl(MISCINIT1); @@ -1412,6 +1429,26 @@ reg.screensize = par->width | (par->height << 12); reg.vidcfg &= ~VIDCFG_HALF_MODE; + reg.miscinit0 = tdfx_inl(MISCINIT0); + +#if defined(__BIG_ENDIAN) + switch (par->bpp) { + case 8: + reg.miscinit0 &= ~(1 << 30); + reg.miscinit0 &= ~(1 << 31); + break; + case 16: + reg.miscinit0 |= (1 << 30); + reg.miscinit0 |= (1 << 31); + break; + case 24: + case 32: + reg.miscinit0 |= (1 << 30); + reg.miscinit0 &= ~(1 << 31); + break; + } +#endif + do_write_regs(®); i->current_par = *par; @@ -1462,6 +1499,7 @@ switch(i->dev) { case PCI_DEVICE_ID_3DFX_BANSHEE: case PCI_DEVICE_ID_3DFX_VOODOO3: + case PCI_DEVICE_ID_3DFX_VOODOO5: par->width = (var->xres + 15) & ~15; /* could sometimes be 8 */ par->width_virt = par->width; par->height = var->yres; @@ -1584,32 +1622,34 @@ switch(info->dev) { case PCI_DEVICE_ID_3DFX_BANSHEE: + strcpy(fix->id, "3Dfx Banshee"); + break; case PCI_DEVICE_ID_3DFX_VOODOO3: - strcpy(fix->id, - info->dev == PCI_DEVICE_ID_3DFX_BANSHEE - ? "3Dfx Banshee" - : "3Dfx Voodoo3"); - fix->smem_start = info->bufbase_phys; - fix->smem_len = info->bufbase_size; - fix->mmio_start = info->regbase_phys; - fix->mmio_len = info->regbase_size; - fix->accel = FB_ACCEL_3DFX_BANSHEE; - fix->type = FB_TYPE_PACKED_PIXELS; - fix->type_aux = 0; - fix->line_length = par->lpitch; - fix->visual = (par->bpp == 8) - ? FB_VISUAL_PSEUDOCOLOR - : FB_VISUAL_DIRECTCOLOR; - - fix->xpanstep = 0; - fix->ypanstep = nopan ? 0 : 1; - fix->ywrapstep = nowrap ? 0 : 1; - + strcpy(fix->id, "3Dfx Voodoo3"); + break; + case PCI_DEVICE_ID_3DFX_VOODOO5: + strcpy(fix->id, "3Dfx Voodoo5"); break; default: return -EINVAL; } + fix->smem_start = info->bufbase_phys; + fix->smem_len = info->bufbase_size; + fix->mmio_start = info->regbase_phys; + fix->mmio_len = info->regbase_size; + fix->accel = FB_ACCEL_3DFX_BANSHEE; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + fix->line_length = par->lpitch; + fix->visual = (par->bpp == 8) + ? FB_VISUAL_PSEUDOCOLOR + : FB_VISUAL_DIRECTCOLOR; + + fix->xpanstep = 0; + fix->ypanstep = nopan ? 0 : 1; + fix->ywrapstep = nowrap ? 0 : 1; + return 0; } @@ -1850,17 +1890,25 @@ while ((pdev = pci_find_device(PCI_VENDOR_ID_3DFX, PCI_ANY_ID, pdev))) { if(((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) && ((pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE) || - (pdev->device == PCI_DEVICE_ID_3DFX_VOODOO3))) { - char* name = pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE - ? "Banshee" - : "Voodoo3"; + (pdev->device == PCI_DEVICE_ID_3DFX_VOODOO3) || + (pdev->device == PCI_DEVICE_ID_3DFX_VOODOO5))) { + char *name; fb_info.dev = pdev->device; - fb_info.max_pixclock = - pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE - ? BANSHEE_MAX_PIXCLOCK - : VOODOO3_MAX_PIXCLOCK; - + switch (pdev->device) { + case PCI_DEVICE_ID_3DFX_BANSHEE: + fb_info.max_pixclock = BANSHEE_MAX_PIXCLOCK; + name = "Banshee"; + break; + case PCI_DEVICE_ID_3DFX_VOODOO3: + fb_info.max_pixclock = VOODOO3_MAX_PIXCLOCK; + name = "Voodoo3"; + break; + case PCI_DEVICE_ID_3DFX_VOODOO5: + fb_info.max_pixclock = VOODOO5_MAX_PIXCLOCK; + name = "Voodoo5"; + break; + } fb_info.regbase_phys = pci_resource_start(pdev, 0); fb_info.regbase_size = 1 << 24; fb_info.regbase_virt = ioremap_nocache(fb_info.regbase_phys, 1 << 24); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/tgafb.c linux.ac/drivers/video/tgafb.c --- linux.vanilla/drivers/video/tgafb.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/tgafb.c Tue Apr 3 17:55:10 2001 @@ -60,7 +60,7 @@ static int current_par_valid = 0; static struct display disp; -static char default_fontname[40] = { 0 }; +static char default_fontname[40] __initdata = { 0 }; static struct fb_var_screeninfo default_var; static int default_var_valid = 0; @@ -281,9 +281,9 @@ static void tgafb_set_disp(const void *fb_par, struct display *disp, struct fb_info_gen *info); +#ifndef MODULE int tgafb_setup(char*); -int tgafb_init(void); -void tgafb_cleanup(struct fb_info *info); +#endif static void tgafb_set_pll(int f); #if 1 @@ -879,6 +879,7 @@ }; +#ifndef MODULE /* * Setup */ @@ -910,6 +911,7 @@ } return 0; } +#endif /* @@ -990,9 +992,9 @@ * Cleanup */ -void tgafb_cleanup(struct fb_info *info) +void __exit tgafb_cleanup(void) { - unregister_framebuffer(info); + unregister_framebuffer(&fb_info.gen.info); } @@ -1001,14 +1003,7 @@ */ #ifdef MODULE -int init_module(void) -{ - return tgafb_init(); -} - -void cleanup_module(void) -{ - tgafb_cleanup(void); -} -#endif /* MODULE */ +module_init(tgafb_init); +#endif +module_exit(tgafb_cleanup); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/vesafb.c linux.ac/drivers/video/vesafb.c --- linux.vanilla/drivers/video/vesafb.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/vesafb.c Tue Apr 3 17:55:10 2001 @@ -2,7 +2,7 @@ * framebuffer driver for VBE 2.0 compliant graphic boards * * switching to graphics mode happens at boot time (while - * running in real mode, see arch/i386/video.S). + * running in real mode, see arch/i386/boot/video.S). * * (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de> * @@ -635,7 +635,12 @@ if (mtrr) { int temp_size = video_size; - while (mtrr_add(video_base, temp_size, MTRR_TYPE_WRCOMB, 1)==-EINVAL) { + /* Find the largest power-of-two */ + while (temp_size & (temp_size - 1)) + temp_size &= (temp_size - 1); + + /* Try and find a power of two to add */ + while (temp_size && mtrr_add(video_base, temp_size, MTRR_TYPE_WRCOMB, 1)==-EINVAL) { temp_size >>= 1; } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/vga16fb.c linux.ac/drivers/video/vga16fb.c --- linux.vanilla/drivers/video/vga16fb.c Fri Feb 9 19:30:23 2001 +++ linux.ac/drivers/video/vga16fb.c Tue Apr 3 17:55:10 2001 @@ -897,6 +897,10 @@ /* XXX share VGA_FB_PHYS region with vgacon */ vga16fb.video_vbase = ioremap(VGA_FB_PHYS, VGA_FB_PHYS_LEN); + if (!vga16fb.video_vbase) { + printk(KERN_ERR "vga16fb: unable to map device\n"); + return -ENOMEM; + } printk(KERN_INFO "vga16fb: mapped to 0x%p\n", vga16fb.video_vbase); vga16fb.isVGA = ORIG_VIDEO_ISVGA; @@ -931,8 +935,10 @@ vga16fb.fb_info.flags=FBINFO_FLAG_DEFAULT; vga16fb_set_disp(-1, &vga16fb); - if (register_framebuffer(&vga16fb.fb_info)<0) + if (register_framebuffer(&vga16fb.fb_info)<0) { + iounmap(vga16fb.video_vbase); return -EINVAL; + } printk(KERN_INFO "fb%d: %s frame buffer device\n", GET_FB_IDX(vga16fb.fb_info.node), vga16fb.fb_info.modename); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/Config.in linux.ac/fs/Config.in --- linux.vanilla/fs/Config.in Mon Jan 15 20:42:32 2001 +++ linux.ac/fs/Config.in Sat Apr 14 01:37:13 2001 @@ -20,6 +20,8 @@ dep_tristate 'BFS file system support (EXPERIMENTAL)' CONFIG_BFS_FS $CONFIG_EXPERIMENTAL +dep_tristate 'CMS file system support (EXPERIMENTAL)' CONFIG_CMS_FS $CONFIG_EXPERIMENTAL + # msdos file systems tristate 'DOS FAT fs support' CONFIG_FAT_FS dep_tristate ' MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS @@ -27,10 +29,11 @@ dep_tristate ' VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS dep_tristate 'EFS file system support (read only) (EXPERIMENTAL)' CONFIG_EFS_FS $CONFIG_EXPERIMENTAL dep_tristate 'Journalling Flash File System (JFFS) support (EXPERIMENTAL)' CONFIG_JFFS_FS $CONFIG_EXPERIMENTAL $CONFIG_MTD -if [ "$CONFIG_JFFS_FS" != "n" ] ; then - int 'JFFS debugging verbosity (0 = quiet, 3 = noisy)' CONFIG_JFFS_FS_VERBOSE 0 +if [ "$CONFIG_JFFS_FS" = "y" -o "$CONFIG_JFFS_FS" = "m" ] ; then + int 'JFFS debugging verbosity (0 = quiet, 3 = noisy)' CONFIG_JFFS_FS_VERBOSE 0 fi tristate 'Compressed ROM file system support' CONFIG_CRAMFS +bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS tristate 'Simple RAM-based file system support' CONFIG_RAMFS tristate 'ISO 9660 CDROM file system support' CONFIG_ISO9660_FS @@ -102,9 +105,9 @@ dep_tristate 'SMB file system support (to mount Windows shares etc.)' CONFIG_SMB_FS $CONFIG_INET if [ "$CONFIG_SMB_FS" != "n" ]; then - bool ' Use a default NLS' CONFIG_SMB_NLS_DEFAULT + bool ' Use a default NLS' CONFIG_SMB_NLS_DEFAULT if [ "$CONFIG_SMB_NLS_DEFAULT" = "y" ]; then - string ' Default Remote NLS Option' CONFIG_SMB_NLS_REMOTE "cp437" + string ' Default Remote NLS Option' CONFIG_SMB_NLS_REMOTE "cp437" fi fi if [ "$CONFIG_IPX" != "n" -o "$CONFIG_INET" != "n" ]; then diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/Makefile linux.ac/fs/Makefile --- linux.vanilla/fs/Makefile Tue Apr 3 17:32:25 2001 +++ linux.ac/fs/Makefile Tue Apr 3 17:55:10 2001 @@ -7,7 +7,7 @@ O_TARGET := fs.o -export-objs := filesystems.o dcache.o +export-objs := filesystems.o open.o dcache.o mod-subdirs := nls obj-y := open.o read_write.o devices.o file_table.o buffer.o \ @@ -61,9 +61,11 @@ subdir-$(CONFIG_REISERFS_FS) += reiserfs subdir-$(CONFIG_DEVPTS_FS) += devpts subdir-$(CONFIG_SUN_OPENPROMFS) += openpromfs +subdir-$(CONFIG_CMS_FS) += cmsfs obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o +obj-$(CONFIG_BINFMT_SOM) += binfmt_som.o obj-$(CONFIG_BINFMT_EM86) += binfmt_em86.o obj-$(CONFIG_BINFMT_MISC) += binfmt_misc.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/adfs/inode.c linux.ac/fs/adfs/inode.c --- linux.vanilla/fs/adfs/inode.c Fri Dec 29 22:07:57 2000 +++ linux.ac/fs/adfs/inode.c Tue Apr 3 17:55:10 2001 @@ -319,7 +319,11 @@ goto out; if (ia_valid & ATTR_SIZE) - vmtruncate(inode, attr->ia_size); + error = vmtruncate(inode, attr->ia_size); + + if (error) + goto out; + if (ia_valid & ATTR_MTIME) { inode->i_mtime = attr->ia_mtime; adfs_unix2adfs_time(inode, attr->ia_mtime); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/affs/inode.c linux.ac/fs/affs/inode.c --- linux.vanilla/fs/affs/inode.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/affs/inode.c Tue Apr 3 17:55:10 2001 @@ -261,8 +261,7 @@ if (attr->ia_valid & ATTR_MODE) inode->u.affs_i.i_protect = mode_to_prot(attr->ia_mode); - error = 0; - inode_setattr(inode, attr); + error = inode_setattr(inode, attr); out: return error; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/attr.c linux.ac/fs/attr.c --- linux.vanilla/fs/attr.c Mon Oct 16 21:00:53 2000 +++ linux.ac/fs/attr.c Tue Apr 3 17:55:10 2001 @@ -11,6 +11,7 @@ #include <linux/smp_lock.h> #include <linux/dnotify.h> #include <linux/fcntl.h> +#include <linux/quotaops.h> /* Taken over from the old code... */ @@ -57,16 +58,21 @@ return retval; } -void inode_setattr(struct inode * inode, struct iattr * attr) +int inode_setattr(struct inode * inode, struct iattr * attr) { unsigned int ia_valid = attr->ia_valid; + int error = 0; + + if (ia_valid & ATTR_SIZE) { + error = vmtruncate(inode, attr->ia_size); + if (error) + goto out; + } if (ia_valid & ATTR_UID) inode->i_uid = attr->ia_uid; if (ia_valid & ATTR_GID) inode->i_gid = attr->ia_gid; - if (ia_valid & ATTR_SIZE) - vmtruncate(inode, attr->ia_size); if (ia_valid & ATTR_ATIME) inode->i_atime = attr->ia_atime; if (ia_valid & ATTR_MTIME) @@ -79,6 +85,8 @@ inode->i_mode &= ~S_ISGID; } mark_inode_dirty(inode); +out: + return error; } static int setattr_mask(unsigned int ia_valid) @@ -124,8 +132,13 @@ error = inode->i_op->setattr(dentry, attr); else { error = inode_change_ok(inode, attr); - if (!error) - inode_setattr(inode, attr); + if (!error) { + if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || + (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) + error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0; + if (!error) + error = inode_setattr(inode, attr); + } } unlock_kernel(); if (!error) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/autofs/root.c linux.ac/fs/autofs/root.c --- linux.vanilla/fs/autofs/root.c Fri Aug 11 22:29:02 2000 +++ linux.ac/fs/autofs/root.c Mon Apr 16 00:19:43 2001 @@ -94,7 +94,7 @@ /* Turn this into a real negative dentry? */ if (status == -ENOENT) { dentry->d_time = jiffies + AUTOFS_NEGATIVE_TIMEOUT; - dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; + clear_bit(D_Autofs_Pending, &dentry->d_flags); return 1; } else if (status) { /* Return a negative dentry, but leave it "pending" */ @@ -129,7 +129,7 @@ autofs_update_usage(&sbi->dirhash,ent); } - dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; + clear_bit(D_Autofs_Pending, &dentry->d_flags); return 1; } @@ -152,7 +152,8 @@ sbi = autofs_sbi(dir->i_sb); /* Pending dentry */ - if ( dentry->d_flags & DCACHE_AUTOFS_PENDING ) { + if (test_bit(D_Autofs_Pending, &dentry->d_flags)) + { if (autofs_oz_mode(sbi)) res = 1; else @@ -219,7 +220,7 @@ * We need to do this before we release the directory semaphore. */ dentry->d_op = &autofs_dentry_operations; - dentry->d_flags |= DCACHE_AUTOFS_PENDING; + set_bit(D_Autofs_Pending, &dentry->d_flags); d_add(dentry, NULL); up(&dir->i_sem); @@ -230,7 +231,7 @@ * If we are still pending, check if we had to handle * a signal. If so we can force a restart.. */ - if (dentry->d_flags & DCACHE_AUTOFS_PENDING) { + if (test_bit(D_Autofs_Pending, &dentry->d_flags)) { if (signal_pending(current)) return ERR_PTR(-ERESTARTNOINTR); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/autofs4/autofs_i.h linux.ac/fs/autofs4/autofs_i.h --- linux.vanilla/fs/autofs4/autofs_i.h Thu Feb 22 00:09:58 2001 +++ linux.ac/fs/autofs4/autofs_i.h Tue Apr 17 18:46:07 2001 @@ -119,7 +119,7 @@ { struct autofs_info *inf = autofs4_dentry_ino(dentry); - return (dentry->d_flags & DCACHE_AUTOFS_PENDING) || + return (test_bit(D_Autofs_Pending, &dentry->d_flags)) || (inf != NULL && inf->flags & AUTOFS_INF_EXPIRING); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/autofs4/expire.c linux.ac/fs/autofs4/expire.c --- linux.vanilla/fs/autofs4/expire.c Tue Oct 24 05:57:38 2000 +++ linux.ac/fs/autofs4/expire.c Sun Apr 15 23:04:43 2001 @@ -194,7 +194,7 @@ } /* No point expiring a pending mount */ - if (dentry->d_flags & DCACHE_AUTOFS_PENDING) + if (test_bit(D_Autofs_Pending, &dentry->d_flags)) continue; if (!do_now) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/autofs4/root.c linux.ac/fs/autofs4/root.c --- linux.vanilla/fs/autofs4/root.c Tue Oct 24 05:57:38 2000 +++ linux.ac/fs/autofs4/root.c Sun Apr 15 23:04:43 2001 @@ -82,7 +82,7 @@ if (de_info && (de_info->flags & AUTOFS_INF_EXPIRING)) { DPRINTK(("try_to_fill_entry: waiting for expire %p name=%.*s, flags&PENDING=%s de_info=%p de_info->flags=%x\n", dentry, dentry->d_name.len, dentry->d_name.name, - dentry->d_flags & DCACHE_AUTOFS_PENDING?"t":"f", + test_bit(D_Autofs_Pending, &dentry->d_flags)?"t":"f", de_info, de_info?de_info->flags:0)); status = autofs4_wait(sbi, &dentry->d_name, NFY_NONE); @@ -109,7 +109,7 @@ /* Turn this into a real negative dentry? */ if (status == -ENOENT) { dentry->d_time = jiffies + AUTOFS_NEGATIVE_TIMEOUT; - dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; + clear_bit(D_Autofs_Pending, &dentry->d_flags); return 1; } else if (status) { /* Return a negative dentry, but leave it "pending" */ @@ -134,7 +134,7 @@ if (!autofs4_oz_mode(sbi)) autofs4_update_usage(dentry); - dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; + clear_bit(D_Autofs_Pending, &dentry->d_flags); return 1; } @@ -277,7 +277,7 @@ dentry->d_op = &autofs4_root_dentry_operations; if (!oz_mode) - dentry->d_flags |= DCACHE_AUTOFS_PENDING; + set_bit(D_Autofs_Pending, &dentry->d_flags); dentry->d_fsdata = NULL; d_add(dentry, NULL); @@ -291,7 +291,7 @@ * If we are still pending, check if we had to handle * a signal. If so we can force a restart.. */ - if (dentry->d_flags & DCACHE_AUTOFS_PENDING) { + if (test_bit(D_Autofs_Pending, &dentry->d_flags)) { if (signal_pending(current)) return ERR_PTR(-ERESTARTNOINTR); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/binfmt_aout.c linux.ac/fs/binfmt_aout.c --- linux.vanilla/fs/binfmt_aout.c Tue Apr 3 17:32:25 2001 +++ linux.ac/fs/binfmt_aout.c Mon Apr 9 23:25:02 2001 @@ -31,7 +31,8 @@ static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs); static int load_aout_library(struct file*); -static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file); +static int aout_core_dump(long signr, struct pt_regs * regs, + struct file *file, struct mm_struct * mm); extern void dump_thread(struct pt_regs *, struct user *); @@ -78,7 +79,8 @@ * dumping of the process results in another error.. */ -static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file) +static int aout_core_dump(long signr, struct pt_regs * regs, + struct file * file, struct mm_struct * mm) { mm_segment_t fs; int has_dumped = 0; @@ -90,7 +92,7 @@ # define START_DATA(u) ((u.u_tsize << PAGE_SHIFT) + u.start_code) #elif defined(__sparc__) # define START_DATA(u) (u.u_tsize) -#elif defined(__i386__) || defined(__mc68000__) +#elif defined(__i386__) || defined(__mc68000__) || defined(__arch_um__) # define START_DATA(u) (u.u_tsize << PAGE_SHIFT) #endif #ifdef __sparc__ @@ -219,7 +221,7 @@ envp = (char **) sp; sp -= argc+1; argv = (char **) sp; -#if defined(__i386__) || defined(__mc68000__) || defined(__arm__) +#if defined(__i386__) || defined(__mc68000__) || defined(__arm__) || defined(__arch_um__) put_user((unsigned long) envp,--sp); put_user((unsigned long) argv,--sp); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/binfmt_elf.c linux.ac/fs/binfmt_elf.c --- linux.vanilla/fs/binfmt_elf.c Tue Apr 3 17:32:25 2001 +++ linux.ac/fs/binfmt_elf.c Tue Apr 17 15:38:29 2001 @@ -36,7 +36,7 @@ #include <asm/param.h> #include <asm/pgalloc.h> -#define DLINFO_ITEMS 13 +#define DLINFO_ITEMS 14 #include <linux/elf.h> @@ -56,7 +56,8 @@ * don't even try. */ #ifdef USE_ELF_CORE_DUMP -static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file); +static int elf_core_dump(long signr, struct pt_regs * regs, + struct file * file, struct mm_struct * mm); #else #define elf_core_dump NULL #endif @@ -135,12 +136,13 @@ /* * Force 16 byte _final_ alignment here for generality. - * Leave an extra 16 bytes free so that on the PowerPC we - * can move the aux table up to start on a 16-byte boundary. */ - sp = (elf_addr_t *)((~15UL & (unsigned long)(u_platform)) - 16UL); + sp = (elf_addr_t *)(~15UL & (unsigned long)(u_platform)); csp = sp; - csp -= ((exec ? DLINFO_ITEMS*2 : 4) + (k_platform ? 2 : 0)); + csp -= DLINFO_ITEMS*2 + (k_platform ? 2 : 0); +#ifdef DLINFO_ARCH_ITEMS + csp -= DLINFO_ARCH_ITEMS*2; +#endif csp -= envc+1; csp -= argc+1; csp -= (!ibcs ? 3 : 1); /* argc itself */ @@ -160,25 +162,27 @@ sp -= 2; NEW_AUX_ENT(0, AT_PLATFORM, (elf_addr_t)(unsigned long) u_platform); } - sp -= 3*2; - NEW_AUX_ENT(0, AT_HWCAP, hwcap); - NEW_AUX_ENT(1, AT_PAGESZ, ELF_EXEC_PAGESIZE); - NEW_AUX_ENT(2, AT_CLKTCK, CLOCKS_PER_SEC); - - if (exec) { - sp -= 10*2; - - NEW_AUX_ENT(0, AT_PHDR, load_addr + exec->e_phoff); - NEW_AUX_ENT(1, AT_PHENT, sizeof (struct elf_phdr)); - NEW_AUX_ENT(2, AT_PHNUM, exec->e_phnum); - NEW_AUX_ENT(3, AT_BASE, interp_load_addr); - NEW_AUX_ENT(4, AT_FLAGS, 0); - NEW_AUX_ENT(5, AT_ENTRY, load_bias + exec->e_entry); - NEW_AUX_ENT(6, AT_UID, (elf_addr_t) current->uid); - NEW_AUX_ENT(7, AT_EUID, (elf_addr_t) current->euid); - NEW_AUX_ENT(8, AT_GID, (elf_addr_t) current->gid); - NEW_AUX_ENT(9, AT_EGID, (elf_addr_t) current->egid); - } + sp -= DLINFO_ITEMS*2; + NEW_AUX_ENT( 0, AT_HWCAP, hwcap); + NEW_AUX_ENT( 1, AT_PAGESZ, ELF_EXEC_PAGESIZE); + NEW_AUX_ENT( 2, AT_CLKTCK, CLOCKS_PER_SEC); + NEW_AUX_ENT( 3, AT_PHDR, load_addr + exec->e_phoff); + NEW_AUX_ENT( 4, AT_PHENT, sizeof (struct elf_phdr)); + NEW_AUX_ENT( 5, AT_PHNUM, exec->e_phnum); + NEW_AUX_ENT( 6, AT_BASE, interp_load_addr); + NEW_AUX_ENT( 7, AT_FLAGS, 0); + NEW_AUX_ENT( 8, AT_ENTRY, load_bias + exec->e_entry); + NEW_AUX_ENT( 9, AT_UID, (elf_addr_t) current->uid); + NEW_AUX_ENT(10, AT_EUID, (elf_addr_t) current->euid); + NEW_AUX_ENT(11, AT_GID, (elf_addr_t) current->gid); + NEW_AUX_ENT(12, AT_EGID, (elf_addr_t) current->egid); +#ifdef ARCH_DLINFO + /* + * ARCH_DLINFO must come last so platform specific code can enforce + * special alignment requirements on the AUXV if necessary (eg. PPC). + */ + ARCH_DLINFO; +#endif #undef NEW_AUX_ENT sp -= envc+1; @@ -694,7 +698,7 @@ create_elf_tables((char *)bprm->p, bprm->argc, bprm->envc, - (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL), + &elf_ex, load_addr, load_bias, interp_load_addr, (interpreter_type == INTERPRETER_AOUT ? 0 : 1)); @@ -981,7 +985,8 @@ * and then they are actually written out. If we run out of core limit * we just truncate. */ -static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) +static int elf_core_dump(long signr, struct pt_regs * regs, + struct file * file, struct mm_struct * mm) { int has_dumped = 0; mm_segment_t fs; @@ -998,7 +1003,7 @@ elf_fpregset_t fpu; /* NT_PRFPREG */ struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ - segs = current->mm->map_count; + segs = mm->map_count; #ifdef DEBUG printk("elf_core_dump: %d segs %lu limit\n", segs, limit); @@ -1158,7 +1163,7 @@ dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); /* Write program headers for segments dump */ - for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { + for(vma = mm->mmap; vma != NULL; vma = vma->vm_next) { struct elf_phdr phdr; size_t sz; @@ -1187,7 +1192,7 @@ DUMP_SEEK(dataoff); - for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { + for(vma = mm->mmap; vma != NULL; vma = vma->vm_next) { unsigned long addr; if (!maydump(vma)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/binfmt_misc.c linux.ac/fs/binfmt_misc.c --- linux.vanilla/fs/binfmt_misc.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/binfmt_misc.c Tue Apr 3 17:55:10 2001 @@ -13,165 +13,80 @@ * 1997-06-26 hpa: pass the real filename rather than argv[0] * 1997-06-30 minor cleanup * 1997-08-09 removed extension stripping, locking cleanup + * 2001-02-28 AV: rewritten into something that resembles C. Original didn't. */ -#include <linux/config.h> #include <linux/module.h> +#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/slab.h> #include <linux/binfmts.h> -#include <linux/init.h> -#include <linux/proc_fs.h> -#include <linux/string.h> +#include <linux/slab.h> #include <linux/ctype.h> #include <linux/file.h> -#include <linux/spinlock.h> +#include <linux/pagemap.h> + #include <asm/uaccess.h> -/* - * We should make this work with a "stub-only" /proc, - * which would just not be able to be configured. - * Right now the /proc-fs support is too black and white, - * though, so just remind people that this should be - * fixed.. - */ -#ifndef CONFIG_PROC_FS -#error You really need /proc support for binfmt_misc. Please reconfigure! -#endif - -#define VERBOSE_STATUS /* undef this to save 400 bytes kernel memory */ - -struct binfmt_entry { - struct binfmt_entry *next; - long id; +enum { + VERBOSE_STATUS = 1 /* make it zero to save 400 bytes kernel memory */ +}; + +static LIST_HEAD(entries); +static int enabled = 1; + +enum {Enabled, Magic}; + +typedef struct { + struct list_head list; int flags; /* type, status, etc. */ int offset; /* offset of magic */ int size; /* size of magic/mask */ char *magic; /* magic or filename extension */ char *mask; /* mask, NULL for exact match */ char *interpreter; /* filename of interpreter */ - char *proc_name; - struct proc_dir_entry *proc_dir; -}; - -#define ENTRY_ENABLED 1 /* the old binfmt_entry.enabled */ -#define ENTRY_MAGIC 8 /* not filename detection */ - -static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs); -static void entry_proc_cleanup(struct binfmt_entry *e); -static int entry_proc_setup(struct binfmt_entry *e); - -static struct linux_binfmt misc_format = { - NULL, THIS_MODULE, load_misc_binary, NULL, NULL, 0 -}; - -static struct proc_dir_entry *bm_dir; - -static struct binfmt_entry *entries; -static int free_id = 1; -static int enabled = 1; + char *name; + struct dentry *dentry; +} Node; static rwlock_t entries_lock __attribute__((unused)) = RW_LOCK_UNLOCKED; - -/* - * Unregister one entry - */ -static void clear_entry(int id) -{ - struct binfmt_entry **ep, *e; - - write_lock(&entries_lock); - ep = &entries; - while (*ep && ((*ep)->id != id)) - ep = &((*ep)->next); - if ((e = *ep)) - *ep = e->next; - write_unlock(&entries_lock); - - if (e) { - entry_proc_cleanup(e); - kfree(e); - } -} - -/* - * Clear all registered binary formats - */ -static void clear_entries(void) -{ - struct binfmt_entry *e, *n; - - write_lock(&entries_lock); - n = entries; - entries = NULL; - write_unlock(&entries_lock); - - while ((e = n)) { - n = e->next; - entry_proc_cleanup(e); - kfree(e); - } -} - -/* - * Find entry through id and lock it - */ -static struct binfmt_entry *get_entry(int id) -{ - struct binfmt_entry *e; - - read_lock(&entries_lock); - e = entries; - while (e && (e->id != id)) - e = e->next; - if (!e) - read_unlock(&entries_lock); - return e; -} - -/* - * unlock entry - */ -static inline void put_entry(struct binfmt_entry *e) -{ - if (e) - read_unlock(&entries_lock); -} - - /* * Check if we support the binfmt - * if we do, return the binfmt_entry, else NULL + * if we do, return the node, else NULL * locking is done in load_misc_binary */ -static struct binfmt_entry *check_file(struct linux_binprm *bprm) +static Node *check_file(struct linux_binprm *bprm) { - struct binfmt_entry *e; char *p = strrchr(bprm->filename, '.'); - int j; + struct list_head *l; - e = entries; - while (e) { - if (e->flags & ENTRY_ENABLED) { - if (!(e->flags & ENTRY_MAGIC)) { - if (p && !strcmp(e->magic, p + 1)) - return e; - } else { - j = 0; - while ((j < e->size) && - !((bprm->buf[e->offset + j] ^ e->magic[j]) - & (e->mask ? e->mask[j] : 0xff))) - j++; - if (j == e->size) - return e; - } + for (l = entries.next; l != &entries; l = l->next) { + Node *e = list_entry(l, Node, list); + char *s; + int j; + + if (!test_bit(Enabled, &e->flags)) + continue; + + if (!test_bit(Magic, &e->flags)) { + if (p && !strcmp(e->magic, p + 1)) + return e; + continue; } - e = e->next; - }; + + s = bprm->buf + e->offset; + if (e->mask) { + for (j = 0; j < e->size; j++) + if ((*s++ ^ e->magic[j]) & e->mask[j]) + break; + } else { + for (j = 0; j < e->size; j++) + if ((*s++ ^ e->magic[j])) + break; + } + if (j == e->size) + return e; + } return NULL; } @@ -180,7 +95,7 @@ */ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) { - struct binfmt_entry *fmt; + Node *fmt; struct file * file; char iname[BINPRM_BUF_SIZE]; char *iname_addr = iname; @@ -228,11 +143,7 @@ return retval; } - - -/* - * /proc handling routines - */ +/* Command parsers */ /* * parses and copies one argument enclosed in del from *sp to *dp, @@ -240,34 +151,38 @@ * returns pointer to the copied argument or NULL in case of an * error (and sets err) or null argument length. */ -static char *copyarg(char **dp, const char **sp, int *count, - char del, int special, int *err) +static char *scanarg(char *s, char del) { - char c = 0, *res = *dp; + char c; - while (!*err && ((c = *((*sp)++)), (*count)--) && (c != del)) { - switch (c) { - case '\\': - if (special && (**sp == 'x')) { - if (!isxdigit(c = toupper(*(++*sp)))) - *err = -EINVAL; - **dp = (c - (isdigit(c) ? '0' : 'A' - 10)) * 16; - if (!isxdigit(c = toupper(*(++*sp)))) - *err = -EINVAL; - *((*dp)++) += c - (isdigit(c) ? '0' : 'A' - 10); - ++*sp; - *count -= 3; - break; - } - default: - *((*dp)++) = c; + while ((c = *s++) != del) { + if (c == '\\' && *s == 'x') { + s++; + if (!isxdigit(*s++)) + return NULL; + if (!isxdigit(*s++)) + return NULL; } } - if (*err || (c != del) || (res == *dp)) - res = NULL; - else if (!special) - *((*dp)++) = '\0'; - return res; + return s; +} + +static int unquote(char *from) +{ + char c = 0, *s = from, *p = from; + + while ((c = *s++) != '\0') { + if (c == '\\' && *s == 'x') { + s++; + c = toupper(*s++); + *p = (c - (isdigit(c) ? '0' : 'A' - 10)) << 4; + c = toupper(*s++); + *p++ |= c - (isdigit(c) ? '0' : 'A' - 10); + continue; + } + *p++ = c; + } + return p - from; } /* @@ -275,242 +190,529 @@ * ':name:type:offset:magic:mask:interpreter:' * where the ':' is the IFS, that can be chosen with the first char */ -static int proc_write_register(struct file *file, const char *buffer, - unsigned long count, void *data) +static Node *create_entry(const char *buffer, size_t count) { - const char *sp; - char del, *dp; - struct binfmt_entry *e; - int memsize, cnt = count - 1, err; + Node *e; + int memsize, err; + char *buf, *p; + char del; /* some sanity checks */ err = -EINVAL; if ((count < 11) || (count > 256)) - goto _err; + goto out; err = -ENOMEM; - memsize = sizeof(struct binfmt_entry) + count; - if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER))) - goto _err; - - err = 0; - sp = buffer + 1; - del = buffer[0]; - dp = (char *)e + sizeof(struct binfmt_entry); - - e->proc_name = copyarg(&dp, &sp, &cnt, del, 0, &err); - - /* we can use bit 3 of type for ext/magic - flag due to the nice encoding of E and M */ - if ((*sp & ~('E' | 'M')) || (sp[1] != del)) - err = -EINVAL; - else - e->flags = (*sp++ & (ENTRY_MAGIC | ENTRY_ENABLED)); - cnt -= 2; sp++; - - e->offset = 0; - while (cnt-- && isdigit(*sp)) - e->offset = e->offset * 10 + *sp++ - '0'; - if (*sp++ != del) - err = -EINVAL; - - e->magic = copyarg(&dp, &sp, &cnt, del, (e->flags & ENTRY_MAGIC), &err); - e->size = dp - e->magic; - e->mask = copyarg(&dp, &sp, &cnt, del, 1, &err); - if (e->mask && ((dp - e->mask) != e->size)) - err = -EINVAL; - e->interpreter = copyarg(&dp, &sp, &cnt, del, 0, &err); - e->id = free_id++; - - /* more sanity checks */ - if (err || !(!cnt || (!(--cnt) && (*sp == '\n'))) || - (e->size < 1) || ((e->size + e->offset) > (BINPRM_BUF_SIZE - 1)) || - !(e->proc_name) || !(e->interpreter) || entry_proc_setup(e)) - goto free_err; + memsize = sizeof(Node) + count + 8; + e = (Node *) kmalloc(memsize, GFP_USER); + if (!e) + goto out; - write_lock(&entries_lock); - e->next = entries; - entries = e; - write_unlock(&entries_lock); + p = buf = (char *)e + sizeof(Node); - err = count; -_err: - return err; -free_err: + memset(e, 0, sizeof(Node)); + if (copy_from_user(buf, buffer, count)) + goto Efault; + + del = *p++; /* delimeter */ + + memset(buf+count, del, 8); + + e->name = p; + p = strchr(p, del); + if (!p) + goto Einval; + *p++ = '\0'; + if (!e->name[0] || + !strcmp(e->name, ".") || + !strcmp(e->name, "..") || + strchr(e->name, '/')) + goto Einval; + switch (*p++) { + case 'E': e->flags = 1<<Enabled; break; + case 'M': e->flags = (1<<Enabled) | (1<<Magic); break; + default: goto Einval; + } + if (*p++ != del) + goto Einval; + if (test_bit(Magic, &e->flags)) { + char *s = strchr(p, del); + if (!s) + goto Einval; + *s++ = '\0'; + e->offset = simple_strtoul(p, &p, 10); + if (*p++) + goto Einval; + e->magic = p; + p = scanarg(p, del); + if (!p) + goto Einval; + p[-1] = '\0'; + if (!e->magic[0]) + goto Einval; + e->mask = p; + p = scanarg(p, del); + if (!p) + goto Einval; + p[-1] = '\0'; + if (!e->mask[0]) + e->mask = NULL; + e->size = unquote(e->magic); + if (e->mask && unquote(e->mask) != e->size) + goto Einval; + if (e->size + e->offset > BINPRM_BUF_SIZE) + goto Einval; + } else { + p = strchr(p, del); + if (!p) + goto Einval; + *p++ = '\0'; + e->magic = p; + p = strchr(p, del); + if (!p) + goto Einval; + *p++ = '\0'; + if (!e->magic[0] || strchr(e->magic, '/')) + goto Einval; + p = strchr(p, del); + if (!p) + goto Einval; + *p++ = '\0'; + } + e->interpreter = p; + p = strchr(p, del); + if (!p) + goto Einval; + *p++ = '\0'; + if (!e->interpreter[0]) + goto Einval; + + if (*p == '\n') + p++; + if (p != buf + count) + goto Einval; + return e; + +out: + return ERR_PTR(err); + +Efault: kfree(e); - err = -EINVAL; - goto _err; + return ERR_PTR(-EFAULT); +Einval: + kfree(e); + return ERR_PTR(-EINVAL); } /* - * Get status of entry/binfmt_misc - * FIXME? should an entry be marked disabled if binfmt_misc is disabled though - * entry is enabled? + * Set status of entry/binfmt_misc: + * '1' enables, '0' disables and '-1' clears entry/binfmt_misc */ -static int proc_read_status(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int parse_command(const char *buffer, size_t count) +{ + char s[4]; + + if (!count) + return 0; + if (count > 3) + return -EINVAL; + if (copy_from_user(s, buffer, count)) + return -EFAULT; + if (s[count-1] == '\n') + count--; + if (count == 1 && s[0] == '0') + return 1; + if (count == 1 && s[0] == '1') + return 2; + if (count == 2 && s[0] == '-' && s[1] == '1') + return 3; + return -EINVAL; +} + +/* generic stuff */ + +static void entry_status(Node *e, char *page) { - struct binfmt_entry *e; char *dp; - int elen, i, err; + char *status = "disabled"; -#ifndef VERBOSE_STATUS - if (data) { - if (!(e = get_entry((int) data))) { - err = -ENOENT; - goto _err; - } - i = e->flags & ENTRY_ENABLED; - put_entry(e); + if (test_bit(Enabled, &e->flags)) + status = "enabled"; + + if (!VERBOSE_STATUS) { + sprintf(page, "%s\n", status); + return; + } + + sprintf(page, "%s\ninterpreter %s\n", status, e->interpreter); + dp = page + strlen(page); + if (!test_bit(Magic, &e->flags)) { + sprintf(dp, "extension .%s\n", e->magic); } else { - i = enabled; - } - sprintf(page, "%s\n", (i ? "enabled" : "disabled")); -#else - if (!data) - sprintf(page, "%s\n", (enabled ? "enabled" : "disabled")); - else { - if (!(e = get_entry((long) data))) { - err = -ENOENT; - goto _err; - } - sprintf(page, "%s\ninterpreter %s\n", - (e->flags & ENTRY_ENABLED ? "enabled" : "disabled"), - e->interpreter); + int i; + + sprintf(dp, "offset %i\nmagic ", e->offset); dp = page + strlen(page); - if (!(e->flags & ENTRY_MAGIC)) { - sprintf(dp, "extension .%s\n", e->magic); - dp = page + strlen(page); - } else { - sprintf(dp, "offset %i\nmagic ", e->offset); - dp = page + strlen(page); + for (i = 0; i < e->size; i++) { + sprintf(dp, "%02x", 0xff & (int) (e->magic[i])); + dp += 2; + } + if (e->mask) { + sprintf(dp, "\nmask "); + dp += 6; for (i = 0; i < e->size; i++) { - sprintf(dp, "%02x", 0xff & (int) (e->magic[i])); + sprintf(dp, "%02x", 0xff & (int) (e->mask[i])); dp += 2; } - if (e->mask) { - sprintf(dp, "\nmask "); - dp += 6; - for (i = 0; i < e->size; i++) { - sprintf(dp, "%02x", 0xff & (int) (e->mask[i])); - dp += 2; - } - } - *dp++ = '\n'; - *dp = '\0'; } - put_entry(e); + *dp++ = '\n'; + *dp = '\0'; } -#endif +} - elen = strlen(page) - off; - if (elen < 0) - elen = 0; - *eof = (elen <= count) ? 1 : 0; - *start = page + off; - err = elen; +static struct inode *bm_get_inode(struct super_block *sb, int mode) +{ + struct inode * inode = new_inode(sb); -_err: - return err; + if (inode) { + inode->i_mode = mode; + inode->i_uid = 0; + inode->i_gid = 0; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + } + return inode; } -/* - * Set status of entry/binfmt_misc: - * '1' enables, '0' disables and '-1' clears entry/binfmt_misc - */ -static int proc_write_status(struct file *file, const char *buffer, - unsigned long count, void *data) +static void bm_clear_inode(struct inode *inode) { - struct binfmt_entry *e; - int res = count; + Node *e = inode->u.generic_ip; - if (buffer[count-1] == '\n') - count--; - if ((count == 1) && !(buffer[0] & ~('0' | '1'))) { - if (data) { - if ((e = get_entry((long) data))) - e->flags = (e->flags & ~ENTRY_ENABLED) - | (int)(buffer[0] - '0'); - put_entry(e); + if (e) { + write_lock(&entries_lock); + list_del(&e->list); + write_unlock(&entries_lock); + kfree(e); + } +} + +static void kill_node(Node *e) +{ + struct dentry *dentry; + + write_lock(&entries_lock); + dentry = e->dentry; + if (dentry) { + list_del(&e->list); + INIT_LIST_HEAD(&e->list); + e->dentry = NULL; + } + write_unlock(&entries_lock); + + if (dentry) { + dentry->d_inode->i_nlink--; + d_drop(dentry); + dput(dentry); + } +} + +/* /<entry> */ + +static ssize_t +bm_entry_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos) +{ + Node *e = file->f_dentry->d_inode->u.generic_ip; + loff_t pos = *ppos; + ssize_t res; + char *page; + int len; + + if (!(page = (char*) __get_free_page(GFP_KERNEL))) + return -ENOMEM; + + entry_status(e, page); + len = strlen(page); + + res = -EINVAL; + if (pos < 0) + goto out; + res = 0; + if (pos >= len) + goto out; + if (len < pos + nbytes) + nbytes = len - pos; + res = -EFAULT; + if (copy_to_user(buf, page + pos, nbytes)) + goto out; + *ppos = pos + nbytes; + res = nbytes; +out: + free_page((unsigned long) page); + return res; +} + +static ssize_t bm_entry_write(struct file *file, const char *buffer, + size_t count, loff_t *ppos) +{ + struct dentry *root; + Node *e = file->f_dentry->d_inode->u.generic_ip; + int res = parse_command(buffer, count); + + switch (res) { + case 1: clear_bit(Enabled, &e->flags); + break; + case 2: set_bit(Enabled, &e->flags); + break; + case 3: root = dget(file->f_vfsmnt->mnt_sb->s_root); + down(&root->d_inode->i_sem); + down(&root->d_inode->i_zombie); + + kill_node(e); + + up(&root->d_inode->i_zombie); + up(&root->d_inode->i_sem); + dput(root); + break; + default: return res; + } + return count; +} + +static struct file_operations bm_entry_operations = { + read: bm_entry_read, + write: bm_entry_write, +}; + +/* /register */ + +static ssize_t bm_register_write(struct file *file, const char *buffer, + size_t count, loff_t *ppos) +{ + Node *e; + struct dentry *root, *dentry; + struct super_block *sb = file->f_vfsmnt->mnt_sb; + int err = 0; + + e = create_entry(buffer, count); + + if (IS_ERR(e)) + return PTR_ERR(e); + + root = dget(sb->s_root); + down(&root->d_inode->i_sem); + dentry = lookup_one(e->name, root); + err = PTR_ERR(dentry); + if (!IS_ERR(dentry)) { + down(&root->d_inode->i_zombie); + if (dentry->d_inode) { + err = -EEXIST; } else { - enabled = buffer[0] - '0'; + struct inode * inode = bm_get_inode(sb, S_IFREG | 0644); + err = -ENOMEM; + + if (inode) { + write_lock(&entries_lock); + + e->dentry = dget(dentry); + inode->u.generic_ip = e; + inode->i_fop = &bm_entry_operations; + d_instantiate(dentry, inode); + + list_add(&e->list, &entries); + write_unlock(&entries_lock); + + err = 0; + } } - } else if ((count == 2) && (buffer[0] == '-') && (buffer[1] == '1')) { - if (data) - clear_entry((long) data); - else - clear_entries(); - } else { - res = -EINVAL; + up(&root->d_inode->i_zombie); + dput(dentry); } - return res; + up(&root->d_inode->i_sem); + dput(root); + + if (err) { + kfree(e); + return -EINVAL; + } + return count; } -/* - * Remove the /proc-dir entries of one binfmt - */ -static void entry_proc_cleanup(struct binfmt_entry *e) +static struct file_operations bm_register_operations = { + write: bm_register_write, +}; + +/* /status */ + +static ssize_t +bm_status_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos) { - remove_proc_entry(e->proc_name, bm_dir); + char *s = enabled ? "enabled" : "disabled"; + int len = strlen(s); + loff_t pos = *ppos; + + if (pos < 0) + return -EINVAL; + if (pos >= len) + return 0; + if (len < pos + nbytes) + nbytes = len - pos; + if (copy_to_user(buf, s + pos, nbytes)) + return -EFAULT; + *ppos = pos + nbytes; + return nbytes; +} + +static ssize_t bm_status_write(struct file * file, const char * buffer, + size_t count, loff_t *ppos) +{ + int res = parse_command(buffer, count); + struct dentry *root; + + switch (res) { + case 1: enabled = 0; break; + case 2: enabled = 1; break; + case 3: root = dget(file->f_vfsmnt->mnt_sb->s_root); + down(&root->d_inode->i_sem); + down(&root->d_inode->i_zombie); + + while (!list_empty(&entries)) + kill_node(list_entry(entries.next, Node, list)); + + up(&root->d_inode->i_zombie); + up(&root->d_inode->i_sem); + dput(root); + default: return res; + } + return count; } -/* - * Create the /proc-dir entry for binfmt - */ -static int entry_proc_setup(struct binfmt_entry *e) +static struct file_operations bm_status_operations = { + read: bm_status_read, + write: bm_status_write, +}; + +/* / */ + +static struct dentry * bm_lookup(struct inode *dir, struct dentry *dentry) +{ + d_add(dentry, NULL); + return NULL; +} + +static struct file_operations bm_dir_operations = { + read: generic_read_dir, + readdir: dcache_readdir, +}; + +static struct inode_operations bm_dir_inode_operations = { + lookup: bm_lookup, +}; + +/* Superblock handling */ + +static int bm_statfs(struct super_block *sb, struct statfs *buf) { - if (!(e->proc_dir = create_proc_entry(e->proc_name, - S_IFREG | S_IRUGO | S_IWUSR, bm_dir))) - { - printk(KERN_WARNING "Unable to create /proc entry.\n"); - return -ENOENT; - } - e->proc_dir->data = (void *) (e->id); - e->proc_dir->read_proc = proc_read_status; - e->proc_dir->write_proc = proc_write_status; + buf->f_type = sb->s_magic; + buf->f_bsize = PAGE_CACHE_SIZE; + buf->f_namelen = 255; return 0; } -static int __init init_misc_binfmt(void) +static struct super_operations s_ops = { + statfs: bm_statfs, + put_inode: force_delete, + clear_inode: bm_clear_inode, +}; + +static struct super_block *bm_read_super(struct super_block * sb, void * data, int silent) { - int error = -ENOENT; - struct proc_dir_entry *status = NULL, *reg; + struct qstr names[2] = {{name:"status"}, {name:"register"}}; + struct inode * inode; + struct dentry * dentry[3]; + int i; + + for (i=0; i<sizeof(names)/sizeof(names[0]); i++) { + names[i].len = strlen(names[i].name); + names[i].hash = full_name_hash(names[i].name, names[i].len); + } - bm_dir = proc_mkdir("sys/fs/binfmt_misc", NULL); /* WTF??? */ - if (!bm_dir) - goto out; - bm_dir->owner = THIS_MODULE; + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = 0x42494e4d; + sb->s_op = &s_ops; + + inode = bm_get_inode(sb, S_IFDIR | 0755); + if (!inode) + return NULL; + inode->i_op = &bm_dir_inode_operations; + inode->i_fop = &bm_dir_operations; + dentry[0] = d_alloc_root(inode); + if (!dentry[0]) { + iput(inode); + return NULL; + } + dentry[1] = d_alloc(dentry[0], &names[0]); + if (!dentry[1]) + goto out1; + dentry[2] = d_alloc(dentry[0], &names[1]); + if (!dentry[2]) + goto out2; + inode = bm_get_inode(sb, S_IFREG | 0644); + if (!inode) + goto out3; + inode->i_fop = &bm_status_operations; + d_add(dentry[1], inode); + inode = bm_get_inode(sb, S_IFREG | 0400); + if (!inode) + goto out3; + inode->i_fop = &bm_register_operations; + d_add(dentry[2], inode); + + sb->s_root = dentry[0]; + return sb; + +out3: + dput(dentry[2]); +out2: + dput(dentry[1]); +out1: + dput(dentry[0]); + return NULL; +} + +static struct linux_binfmt misc_format = { + NULL, THIS_MODULE, load_misc_binary, NULL, NULL, 0 +}; - status = create_proc_entry("status", S_IFREG | S_IRUGO | S_IWUSR, - bm_dir); - if (!status) - goto cleanup_bm; - status->read_proc = proc_read_status; - status->write_proc = proc_write_status; - - reg = create_proc_entry("register", S_IFREG | S_IWUSR, bm_dir); - if (!reg) - goto cleanup_status; - reg->write_proc = proc_write_register; +static DECLARE_FSTYPE(bm_fs_type, "binfmt_misc", bm_read_super, FS_SINGLE|FS_LITTER); - error = register_binfmt(&misc_format); -out: - return error; +static struct vfsmount *bm_mnt; -cleanup_status: - remove_proc_entry("status", bm_dir); -cleanup_bm: - remove_proc_entry("sys/fs/binfmt_misc", NULL); - goto out; +static int __init init_misc_binfmt(void) +{ + int err = register_filesystem(&bm_fs_type); + if (!err) { + bm_mnt = kern_mount(&bm_fs_type); + err = PTR_ERR(bm_mnt); + if (IS_ERR(bm_mnt)) + unregister_filesystem(&bm_fs_type); + else { + err = register_binfmt(&misc_format); + if (err) { + unregister_filesystem(&bm_fs_type); + kern_umount(bm_mnt); + } + } + } + return err; } static void __exit exit_misc_binfmt(void) { unregister_binfmt(&misc_format); - remove_proc_entry("register", bm_dir); - remove_proc_entry("status", bm_dir); - clear_entries(); - remove_proc_entry("sys/fs/binfmt_misc", NULL); + unregister_filesystem(&bm_fs_type); + kern_umount(bm_mnt); } EXPORT_NO_SYMBOLS; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/binfmt_som.c linux.ac/fs/binfmt_som.c --- linux.vanilla/fs/binfmt_som.c Thu Jan 1 01:00:00 1970 +++ linux.ac/fs/binfmt_som.c Tue Apr 3 17:55:10 2001 @@ -0,0 +1,315 @@ +/* + * linux/fs/binfmt_som.c + * + * These are the functions used to load SOM format executables as used + * by HP-UX. + * + * Copyright 1999 Matthew Wilcox <willy@bofh.ai> + * based on binfmt_elf which is + * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com). + */ + +#include <linux/module.h> + +#include <linux/fs.h> +#include <linux/stat.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/binfmts.h> +#include <linux/som.h> +#include <linux/string.h> +#include <linux/file.h> +#include <linux/fcntl.h> +#include <linux/ptrace.h> +#include <linux/malloc.h> +#include <linux/shm.h> +#include <linux/personality.h> +#include <linux/init.h> + +#include <asm/uaccess.h> +#include <asm/pgtable.h> + +#include <linux/elf.h> + +static int load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs); +static int load_som_library(struct file *); + +/* + * If we don't support core dumping, then supply a NULL so we + * don't even try. + */ +#if 0 +static int som_core_dump(long signr, struct pt_regs * regs); +#else +#define som_core_dump NULL +#endif + +#define SOM_PAGESTART(_v) ((_v) & ~(unsigned long)(SOM_PAGESIZE-1)) +#define SOM_PAGEOFFSET(_v) ((_v) & (SOM_PAGESIZE-1)) +#define SOM_PAGEALIGN(_v) (((_v) + SOM_PAGESIZE - 1) & ~(SOM_PAGESIZE - 1)) + +static struct linux_binfmt som_format = { + NULL, THIS_MODULE, load_som_binary, load_som_library, som_core_dump, SOM_PAGESIZE +}; + +/* + * create_som_tables() parses the env- and arg-strings in new user + * memory and creates the pointer tables from them, and puts their + * addresses on the "stack", returning the new stack pointer value. + */ +static void create_som_tables(struct linux_binprm *bprm) +{ + char **argv, **envp; + int argc = bprm->argc; + int envc = bprm->envc; + unsigned long p; + unsigned long *sp; + + /* Word-align the stack pointer */ + sp = (unsigned long *)(bprm->p + 3 &~ 3); + + envp = (char **) sp; + sp += envc + 1; + argv = (char **) sp; + sp += argc + 1; + + __put_user((unsigned long) envp,++sp); + __put_user((unsigned long) argv,++sp); + + __put_user(argc, ++sp); + + bprm->p = (unsigned long) sp; + + p = current->mm->arg_start; + while (argc-- > 0) { + __put_user((char *)p,argv++); + p += strlen_user((char *)p); + } + __put_user(NULL, argv); + current->mm->arg_end = current->mm->env_start = p; + while (envc-- > 0) { + __put_user((char *)p,envp++); + p += strlen_user((char *)p); + } + __put_user(NULL, envp); + current->mm->env_end = p; +} + +static int check_som_header(struct som_hdr *som_ex) +{ + int *buf = (int *)som_ex; + int i, ck; + + if (som_ex->system_id != SOM_SID_PARISC_1_0 && + som_ex->system_id != SOM_SID_PARISC_1_1 && + som_ex->system_id != SOM_SID_PARISC_2_0) + return -ENOEXEC; + + if (som_ex->a_magic != SOM_EXEC_NONSHARE && + som_ex->a_magic != SOM_EXEC_SHARE && + som_ex->a_magic != SOM_EXEC_DEMAND) + return -ENOEXEC; + + if (som_ex->version_id != SOM_ID_OLD && + som_ex->version_id != SOM_ID_NEW) + return -ENOEXEC; + + ck = 0; + for (i=0; i<32; i++) + ck ^= buf[i]; + if (ck != 0) + return -ENOEXEC; + + return 0; +} + +static int map_som_binary(struct file *file, + const struct som_exec_auxhdr *hpuxhdr) +{ + unsigned long code_start, code_size, data_start, data_size; + unsigned long bss_start, som_brk; + int retval; + int prot = PROT_READ | PROT_EXEC; + int flags = MAP_FIXED|MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE; + + mm_segment_t old_fs = get_fs(); + set_fs(get_ds()); + + code_start = SOM_PAGESTART(hpuxhdr->exec_tmem); + code_size = SOM_PAGEALIGN(hpuxhdr->exec_tsize); + current->mm->start_code = code_start; + current->mm->end_code = code_start + code_size; + down(¤t->mm->mmap_sem); + retval = do_mmap(file, code_start, code_size, prot, + flags, SOM_PAGESTART(hpuxhdr->exec_tfile)); + up(¤t->mm->mmap_sem); + if (retval < 0 && retval > -1024) + goto out; + + data_start = SOM_PAGESTART(hpuxhdr->exec_dmem); + data_size = SOM_PAGEALIGN(hpuxhdr->exec_dsize); + current->mm->start_data = data_start; + current->mm->end_data = bss_start = data_start + data_size; + down(¤t->mm->mmap_sem); + retval = do_mmap(file, data_start, data_size, + prot | PROT_WRITE, flags, + SOM_PAGESTART(hpuxhdr->exec_dfile)); + up(¤t->mm->mmap_sem); + if (retval < 0 && retval > -1024) + goto out; + + som_brk = bss_start + SOM_PAGEALIGN(hpuxhdr->exec_bsize); + current->mm->start_brk = current->mm->brk = som_brk; + down(¤t->mm->mmap_sem); + retval = do_mmap(NULL, bss_start, som_brk - bss_start, + prot | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, 0); + up(¤t->mm->mmap_sem); + if (retval > 0 || retval < -1024) + retval = 0; +out: + set_fs(old_fs); + return retval; +} + + +/* + * These are the functions used to load SOM executables and shared + * libraries. There is no binary dependent code anywhere else. + */ + +static inline int +do_load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) +{ + int som_exec_fileno; + int retval, size; + unsigned long som_entry; + struct som_hdr *som_ex; + struct som_exec_auxhdr *hpuxhdr; + + sti(); + + /* Get the exec-header */ + som_ex = (struct som_hdr *) bprm->buf; + + retval = check_som_header(som_ex); + if (retval != 0) + goto out; + + /* Now read in the auxiliary header information */ + + retval = -ENOMEM; + size = som_ex->aux_header_size; + if (size > SOM_PAGESIZE) + goto out; + hpuxhdr = (struct som_exec_auxhdr *) kmalloc(size, GFP_KERNEL); + if (!hpuxhdr) + goto out; + + retval = kernel_read(bprm->file, som_ex->aux_header_location, + (char *) hpuxhdr, size); + if (retval < 0) + goto out_free; + + retval = get_unused_fd(); + if (retval < 0) + goto out_free; + get_file(bprm->file); + fd_install(som_exec_fileno = retval, bprm->file); + + /* Flush all traces of the currently running executable */ + retval = flush_old_exec(bprm); + if (retval) + goto out_free; + + /* OK, This is the point of no return */ + current->flags &= ~PF_FORKNOEXEC; + current->personality = PER_LINUX; /* I suspect we want a PER_HPUX */ + + retval = map_som_binary(bprm->file, hpuxhdr); + if (retval < 0) + goto out_free; + + som_entry = hpuxhdr->exec_entry; + kfree(hpuxhdr); + + set_binfmt(&som_format); + compute_creds(bprm); + setup_arg_pages(bprm); + + create_som_tables(bprm); + + current->mm->start_stack = bprm->p; + current->mm->rss = 0; + +#if 0 + printk("(start_brk) %08lx\n" , (unsigned long) current->mm->start_brk); + printk("(end_code) %08lx\n" , (unsigned long) current->mm->end_code); + printk("(start_code) %08lx\n" , (unsigned long) current->mm->start_code); + printk("(end_data) %08lx\n" , (unsigned long) current->mm->end_data); + printk("(start_stack) %08lx\n" , (unsigned long) current->mm->start_stack); + printk("(brk) %08lx\n" , (unsigned long) current->mm->brk); +#endif + flush_all_caches(); + + start_thread_som(regs, som_entry, bprm->p); + if (current->ptrace & PT_PTRACED) + send_sig(SIGTRAP, current, 0); + return 0; + + /* error cleanup */ +out_free: + kfree(hpuxhdr); +out: + return retval; +} + +static int +load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) +{ + int retval; + + MOD_INC_USE_COUNT; + retval = do_load_som_binary(bprm, regs); + MOD_DEC_USE_COUNT; + return retval; +} + +static inline int +do_load_som_library(struct file *f) +{ +/* No lib support in SOM yet. gizza chance.. */ + return -ENOEXEC; +} + +static int load_som_library(struct file *f) +{ + int retval; + + MOD_INC_USE_COUNT; + retval = do_load_som_library(f); + MOD_DEC_USE_COUNT; + return retval; +} + + /* Install the SOM loader. + * N.B. We *rely* on the table being the right size with the + * right number of free slots... + */ + +static int __init init_som_binfmt(void) +{ + return register_binfmt(&som_format); +} + +static void __exit exit_som_binfmt(void) +{ + /* Remove the SOM loader. */ + unregister_binfmt(&som_format); +} + +module_init(init_som_binfmt); +module_exit(exit_som_binfmt); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/block_dev.c linux.ac/fs/block_dev.c --- linux.vanilla/fs/block_dev.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/block_dev.c Tue Apr 3 17:55:10 2001 @@ -20,7 +20,6 @@ extern int *blk_size[]; extern int *blksize_size[]; -#define MAX_BUF_PER_PAGE (PAGE_SIZE / 512) #define NBUF 64 ssize_t block_write(struct file * filp, const char * buf, @@ -31,7 +30,7 @@ ssize_t block, blocks; loff_t offset; ssize_t chars; - ssize_t written; + ssize_t written, retval; struct buffer_head * bhlist[NBUF]; size_t size; kdev_t dev = inode->i_rdev; @@ -41,7 +40,7 @@ if (is_read_only(dev)) return -EPERM; - written = write_error = buffercount = 0; + retval = written = write_error = buffercount = 0; blocksize = BLOCK_SIZE; if (blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)]) blocksize = blksize_size[MAJOR(dev)][MINOR(dev)]; @@ -61,8 +60,10 @@ else size = INT_MAX; while (count>0) { - if (block >= size) - return written ? written : -ENOSPC; + if (block >= size) { + retval = -ENOSPC; + goto cleanup; + } chars = blocksize - offset; if (chars > count) chars=count; @@ -74,15 +75,19 @@ if (chars != blocksize) fn = bread; bh = fn(dev, block, blocksize); - if (!bh) - return written ? written : -EIO; + if (!bh) { + retval = -EIO; + goto cleanup; + } if (!buffer_uptodate(bh)) wait_on_buffer(bh); } #else bh = getblk(dev, block, blocksize); - if (!bh) - return written ? written : -EIO; + if (!bh) { + retval = -EIO; + goto cleanup; + } if (!buffer_uptodate(bh)) { @@ -106,7 +111,8 @@ if (!bhlist[i]) { while(i >= 0) brelse(bhlist[i--]); - return written ? written : -EIO; + retval = -EIO; + goto cleanup; } } } @@ -115,7 +121,8 @@ wait_on_buffer(bh); if (!buffer_uptodate(bh)) { brelse(bh); - return written ? written : -EIO; + retval = -EIO; + goto cleanup; } }; }; @@ -149,6 +156,7 @@ if (write_error) break; } + cleanup: if ( buffercount ){ ll_rw_block(WRITE, buffercount, bufferlist); for(i=0; i<buffercount; i++){ @@ -158,10 +166,11 @@ brelse(bufferlist[i]); } } - filp->f_reada = 1; + if(!retval) + filp->f_reada = 1; if(write_error) return -EIO; - return written; + return written ? written : retval; } ssize_t block_read(struct file * filp, char * buf, size_t count, loff_t *ppos) @@ -304,7 +313,7 @@ brelse(*bhe); if (++bhe == &buflist[NBUF]) bhe = buflist; - }; + } if (!read) return -EIO; filp->f_reada = 1; @@ -669,14 +678,11 @@ int ret = 0; kdev_t rdev = to_kdev_t(bdev->bd_dev); /* this should become bdev */ down(&bdev->bd_sem); - /* syncing will go here */ lock_kernel(); if (kind == BDEV_FILE || kind == BDEV_FS) fsync_dev(rdev); - if (atomic_dec_and_test(&bdev->bd_openers)) { - /* invalidating buffers will go here */ + if (atomic_dec_and_test(&bdev->bd_openers)) invalidate_buffers(rdev); - } if (bdev->bd_op->release) { struct inode * fake_inode = get_empty_inode(); ret = -ENOMEM; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/buffer.c linux.ac/fs/buffer.c --- linux.vanilla/fs/buffer.c Tue Apr 3 17:32:25 2001 +++ linux.ac/fs/buffer.c Sat Apr 14 01:58:20 2001 @@ -557,21 +557,14 @@ unsigned int get_hardblocksize(kdev_t dev) { + int blksize = 0; /* - * Get the hard sector size for the given device. If we don't know - * what it is, return 0. + * Get the hard sector size for the given device. + * If we don't know what it is, return 0. */ - if (hardsect_size[MAJOR(dev)] != NULL) { - int blksize = hardsect_size[MAJOR(dev)][MINOR(dev)]; - if (blksize != 0) - return blksize; - } - - /* - * We don't know what the hardware sector size for this device is. - * Return 0 indicating that we don't know. - */ - return 0; + if (hardsect_size[MAJOR(dev)] != NULL) + blksize = hardsect_size[MAJOR(dev)][MINOR(dev)]; + return blksize; } void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode) @@ -876,11 +869,10 @@ else { bh->b_inode = &tmp; list_add(&bh->b_inode_buffers, &tmp.i_dirty_buffers); + atomic_inc(&bh->b_count); if (buffer_dirty(bh)) { - atomic_inc(&bh->b_count); spin_unlock(&lru_list_lock); ll_rw_block(WRITE, 1, &bh); - brelse(bh); spin_lock(&lru_list_lock); } } @@ -889,7 +881,6 @@ while (!list_empty(&tmp.i_dirty_buffers)) { bh = BH_ENTRY(tmp.i_dirty_buffers.prev); remove_inode_queue(bh); - atomic_inc(&bh->b_count); spin_unlock(&lru_list_lock); wait_on_buffer(bh); if (!buffer_uptodate(bh)) @@ -936,9 +927,9 @@ atomic_inc(&bh->b_count); spin_unlock(&lru_list_lock); wait_on_buffer(bh); + brelse(bh); if (!buffer_uptodate(bh)) err = -EIO; - brelse(bh); spin_lock(&lru_list_lock); goto repeat; } @@ -954,6 +945,7 @@ * probably unmounting the fs, but that doesn't mean we have already * done a sync(). Just drop the buffers from the inode list. */ + void invalidate_inode_buffers(struct inode *inode) { struct list_head *list, *next; @@ -1036,7 +1028,6 @@ int balance_dirty_state(kdev_t dev) { unsigned long dirty, tot, hard_dirty_limit, soft_dirty_limit; - int shortage; dirty = size_buffers_type[BUF_DIRTY] >> PAGE_SHIFT; tot = nr_free_buffer_pages(); @@ -1052,16 +1043,6 @@ return 0; } - /* - * If we are about to get low on free pages and - * cleaning the inactive_dirty pages would help - * fix this, wake up bdflush. - */ - shortage = free_shortage(); - if (shortage && nr_inactive_dirty_pages > shortage && - nr_inactive_dirty_pages > freepages.high) - return 0; - return -1; } @@ -1141,7 +1122,7 @@ atomic_dec(&buf->b_count); return; } - printk("VFS: brelse: Trying to free free buffer\n"); + printk(KERN_ERR "VFS: brelse: Trying to free free buffer\n"); } /* @@ -1367,11 +1348,12 @@ { if (buffer_mapped(bh)) { mark_buffer_clean(bh); - wait_on_buffer(bh); + lock_buffer(bh); clear_bit(BH_Uptodate, &bh->b_state); clear_bit(BH_Mapped, &bh->b_state); clear_bit(BH_Req, &bh->b_state); clear_bit(BH_New, &bh->b_state); + unlock_buffer(bh); } } @@ -1498,6 +1480,7 @@ int err, i; unsigned long block; struct buffer_head *bh, *head; + int need_unlock = 1; if (!PageLocked(page)) BUG(); @@ -1542,6 +1525,7 @@ bh = bh->b_this_page; } while (bh != head); + SetPageUptodate(page); /* Stage 3: submit the IO */ do { submit_bh(WRITE, bh); @@ -1549,12 +1533,32 @@ } while (bh != head); /* Done - end_buffer_io_async will unlock */ - SetPageUptodate(page); return 0; out: ClearPageUptodate(page); - UnlockPage(page); + bh = head; + need_unlock = 1; + /* Recovery: lock and submit the mapped buffers */ + do { + if (buffer_mapped(bh)) { + lock_buffer(bh); + need_unlock = 0; + } + bh = bh->b_this_page; + } while (bh != head); + do { + if (buffer_mapped(bh)) { + bh->b_end_io = end_buffer_io_async; + atomic_inc(&bh->b_count); + set_bit(BH_Uptodate, &bh->b_state); + clear_bit(BH_Dirty, &bh->b_state); + submit_bh(WRITE, bh); + } + bh = bh->b_this_page; + } while(bh != head); + if (need_unlock) + UnlockPage(page); return err; } @@ -1625,6 +1629,17 @@ } return 0; out: + bh = head; + block_start = 0; + do { + if (buffer_new(bh) && !buffer_uptodate(bh)) { + memset(kaddr+block_start, 0, bh->b_size); + set_bit(BH_Uptodate, &bh->b_state); + mark_buffer_dirty(bh); + } + block_start += bh->b_size; + bh = bh->b_this_page; + } while (bh != head); return err; } @@ -2002,12 +2017,12 @@ static int wait_kio(int rw, int nr, struct buffer_head *bh[], int size) { - int iosize; + int iosize, err; int i; struct buffer_head *tmp; - iosize = 0; + err = 0; spin_lock(&unused_list_lock); for (i = nr; --i >= 0; ) { @@ -2024,13 +2039,16 @@ clearing iosize on error calculates the amount of IO before the first error. */ iosize = 0; + err = -EIO; } __put_unused_buffer_head(tmp); } spin_unlock(&unused_list_lock); - return iosize; + if (iosize) + return iosize; + return err; } /* @@ -2143,29 +2161,22 @@ } /* End of page loop */ } /* End of iovec loop */ + error: /* Is there any IO still left to submit? */ if (bhind) { - err = wait_kio(rw, bhind, bh, size); - if (err >= 0) - transferred += err; + int tmp_err; + tmp_err = wait_kio(rw, bhind, bh, size); + if (tmp_err >= 0) + transferred += tmp_err; else - goto finished; + if (!err) + err = tmp_err; } finished: if (transferred) return transferred; return err; - - error: - /* We got an error allocating the bh'es. Just free the current - buffer_heads and exit. */ - spin_lock(&unused_list_lock); - for (i = bhind; --i >= 0; ) { - __put_unused_buffer_head(bh[i]); - } - spin_unlock(&unused_list_lock); - goto finished; } /* @@ -2257,7 +2268,7 @@ int isize; if ((size & 511) || (size > PAGE_SIZE)) { - printk("VFS: grow_buffers: size = %d\n",size); + printk(KERN_ERR "VFS: grow_buffers: size = %d\n",size); return 0; } @@ -2583,8 +2594,11 @@ ll_rw_block(WRITE, 1, &bh); atomic_dec(&bh->b_count); - if (current->need_resched) + if (current->need_resched) { + /* kick what we've already pushed down */ + run_task_queue(&tq_disk); schedule(); + } goto restart; } out_unlock: @@ -2786,7 +2800,7 @@ goto stop_kupdate; } #ifdef DEBUG - printk("kupdate() activated...\n"); + printk(KERN_DEBUG "kupdate() activated...\n"); #endif sync_old_buffers(); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/cmsfs/CREDITS linux.ac/fs/cmsfs/CREDITS --- linux.vanilla/fs/cmsfs/CREDITS Thu Jan 1 01:00:00 1970 +++ linux.ac/fs/cmsfs/CREDITS Tue Apr 3 17:55:10 2001 @@ -0,0 +1,35 @@ +CREDITS <plaintext> 2001-Jan-30 (Tue) CMSFSWHO TXT + +Thanks to ... + + CMS minidisk (EDF) filesystem specifications taken from + http://www.vm.ibm.com/pubs/cmsdacb/FSTD.HTML, + http://www.vm.ibm.com/pubs/cmsdacb/ADTSECT.HTML, + and the Linux kernel patches supplied by IBM (mdisk driver). + + Thanks to Dave Hilbe for supporting this project. + + Thanks to Arty Ecock <ECKCU@CUNYVM.CUNY.EDU> for pointing me + back at ADT after I had misunderstood it in my first look. + + Thanks to Rob van der Heij for help with the logic. + + Thanks to Neale Ferguson for "cpint". + + Thanks to Willem Konynenberg <wfk@xos.nl> + for moral support and championing correct DASD I/O. + + Thanks to Alan Cox for help figuring out Linux VFS. + + Thanks to Reed Mullen for clarifying permission to use doc. + + Thanks to Marilyn Troth for advice about packaging, helping + me stay focused, and for putting up with all the late nights. + + ... and many others whom I am sorry to have omitted. + +I looked at every filesystem driver in the Linux 2.2.16 source +in researching the CMS FS driver, particularly ext2, isofs, and the +fat, vfat, and msdos family. I looked at GNU Fileutiles source +in researching the CMS FS utility. + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/cmsfs/Makefile linux.ac/fs/cmsfs/Makefile --- linux.vanilla/fs/cmsfs/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/fs/cmsfs/Makefile Tue Apr 3 17:55:10 2001 @@ -0,0 +1,15 @@ +# +# Makefile for the Linux cms filesystem routines. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile. + +O_TARGET := cms.o + +obj-y := cmsfsvfs.o +obj-m := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/cmsfs/aecs.h linux.ac/fs/cmsfs/aecs.h --- linux.vanilla/fs/cmsfs/aecs.h Thu Jan 1 01:00:00 1970 +++ linux.ac/fs/cmsfs/aecs.h Tue Apr 3 17:55:10 2001 @@ -0,0 +1,87 @@ +/* ----------------------------------------------------------------- ĆCS + * ASCII to EBCDIC and vice-versa code conversion tables. + * Tables included here are based on ASCII conforming to the ISO8859-1 + * Latin 1 character set and EBCDIC conforming to the IBM Code Page 37 + * Latin 1 character set (except for three pairs of characters in 037). + * This header file is included by AECS.C and others. + */ + +#ifndef AECS_HEADER +#define AECS_HEADER 1 + +/* ASCII ---> EBCDIC */ + +static unsigned char ebc8859[256] = { + 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, /* 00 */ + 0x16, 0x05, 0x25, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, + 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F, + 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, /* 20 */ + 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, + 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, /* 40 */ + 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, + 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, + 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D, + 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 60 */ + 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17, /* 80 */ + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x09, 0x0A, 0x1B, + 0x30, 0x31, 0x1A, 0x33, 0x34, 0x35, 0x36, 0x08, + 0x38, 0x39, 0x3A, 0x3B, 0x04, 0x14, 0x3E, 0xFF, + 0x41, 0xAA, 0x4A, 0xB1, 0x9F, 0xB2, 0x6A, 0xB5, /* a0 */ + 0xBB, 0xB4, 0x9A, 0x8A, 0xB0, 0xCA, 0xAF, 0xBC, + 0x90, 0x8F, 0xEA, 0xFA, 0xBE, 0xA0, 0xB6, 0xB3, + 0x9D, 0xDA, 0x9B, 0x8B, 0xB7, 0xB8, 0xB9, 0xAB, + 0x64, 0x65, 0x62, 0x66, 0x63, 0x67, 0x9E, 0x68, /* c0 */ + 0x74, 0x71, 0x72, 0x73, 0x78, 0x75, 0x76, 0x77, + 0xAC, 0x69, 0xED, 0xEE, 0xEB, 0xEF, 0xEC, 0xBF, + 0x80, 0xFD, 0xFE, 0xFB, 0xFC, 0xBA, 0xAE, 0x59, + 0x44, 0x45, 0x42, 0x46, 0x43, 0x47, 0x9C, 0x48, /* e0 */ + 0x54, 0x51, 0x52, 0x53, 0x58, 0x55, 0x56, 0x57, + 0x8C, 0x49, 0xCD, 0xCE, 0xCB, 0xCF, 0xCC, 0xE1, + 0x70, 0xDD, 0xDE, 0xDB, 0xDC, 0x8D, 0x8E, 0xDF}; + +/* EBCDIC ---> ASCII */ + +static unsigned char asc8859[256] = { + 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F, /* 00 */ + 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87, + 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B, /* 20 */ + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07, + 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, + 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A, + 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5, /* 40 */ + 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, + 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF, + 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E, + 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5, /* 60 */ + 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, + 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF, + 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, + 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 80 */ + 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1, + 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, + 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4, + 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, /* a0 */ + 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0x5B, 0xDE, 0xAE, + 0xAC, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC, + 0xBD, 0xBE, 0xDD, 0xA8, 0xAF, 0x5D, 0xB4, 0xD7, + 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* c0 */ + 0x48, 0x49, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5, + 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + 0x51, 0x52, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF, + 0x5C, 0xF7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, /* e0 */ + 0x59, 0x5A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F}; + +#define chratoem(c) ebc8859[(int)c] +#define chretoam(c) asc8859[(int)c] + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/cmsfs/cmsfs.h linux.ac/fs/cmsfs/cmsfs.h --- linux.vanilla/fs/cmsfs/cmsfs.h Thu Jan 1 01:00:00 1970 +++ linux.ac/fs/cmsfs/cmsfs.h Tue Apr 3 17:55:10 2001 @@ -0,0 +1,440 @@ +/* + * + * Name: linux/fs/cms/cmsfs.h (C source header file) + * preprocessor definitions for the CMS filesystem package + * Date: 2000-Jun-14 (Wed) + * Copyright Š 2001 + * Rick Troth <rtroth@bmc.com> + * BMC Software, Inc., Houston, Texas, USA + * + * Some specifications contained here were taken from + * http://www.vm.ibm.com/pubs/cmsdacb/FSTD.HTML, + * http://www.vm.ibm.com/pubs/cmsdacb/ADTSECT.HTML, + * and the Linux kernel patches supplied by IBM (mdisk driver). + * + * Some specifications contained here were taken from + * other filesystem drivers found in the Linux source tree. + * + */ + +/* should be changed to reflect the primary contact */ +#define CMSFS_AUTHOR "Rick Troth <rtroth@bmc.com>" +#define CMSFS_DESCRIPTION "CMS Minidisk Filesystem Support" +#define CMSFS_VERSION "1.0.2-ac" +#define CMSFS_DATE "2001-Mar-9" + +/* ----------------------------------------------------------- Constants + * Constants used by the CMS FS driver and utility. + * Most of these are beyond the low-order byte to avoid collisions + * though they are not intended for shared use with other constants. + */ +/* the following are for the flags member of the cms_inode struct */ +#define CMSFSANY 0x0000 +#define CMSFSBIN 0x0100 +#define CMSFSTXT 0x0200 +#define CMSFSRAW 0x0300 +#define CMSFSEXE 0x1000 + +/* + CMSFSANY - default + CMSFSBIN - no translation, ignore record boundaries + CMSFSTXT - A/E translation, NL at record boundaries + CMSFSRAW - two-byte length followed by untrans record + CMSFSEXE - execute bit set when copied (util) or mounted + */ + +/* the following are for the flags member of the cms_super struct */ +#define CMSFSFBA 0x0400 +#define CMSFSCKD 0x0800 + +/* ------------------------------------------------------------ CMSFSBKT + * CMS FS blocksize test array + * possible block sizes for a CMS "EDF" minidisk filesystem + * Should be in ascending order so that the volume type identifier + * (see CMSFSVSK) is not incorrectly found in a file in the FS. + */ +#define CMSFSBKT { 512 , 1024 , 2048 , 4096 , 0 } +/* logic will expect last item in array to be zero */ + +/* ------------------------------------------------------------ CMSFSVSK + * CMS FS volser key or magic number; always EBCDIC for "CMS1" + * four bytes (not NULL terminated when read from disk) + * It would be simply a 32-bit magic number, 0xC3D4E2F1, + * except that we want to be endian-ness immune + * and it really is a character string, not an integer. + */ +#define CMSFSVSK { 0xC3 , 0xD4 , 0xE2 , 0xF1 , 0 } +/* logic will expect last item in array to be zero */ + +/* ------------------------------------------------------------ CMSFSFST + * C-flavored FSTD for the CMS FS for Linux. + * Based on: http://www.vm.ibm.com/pubs/cmsdacb/FSTD.HTML + * I did not bother with the FSTDFNFT union to avoid clutter. + * If someone wants it, feel free to add it here. + */ +typedef struct CMSFSFST /* File Status Table DSECT */ +{ + char FSTFNAME[8] ; /* filename */ + char FSTFTYPE[8] ; /* filetype */ + char FSTDATEW[2] ; /* DATE LAST WRITTEN - MMDD */ + char FSTTIMEW[2] ; /* TIME LAST WRITTEN - HHMM */ + char FSTWRPNT[2] ; /* WRITE POINTER - ITEM NUMBER */ + char FSTRDPNT[2] ; /* READ POINTER - ITEM NUMBER */ + char FSTFMODE[2] ; /* FILE MODE - LETTER AND NUMBER */ + char FSTRECCT[2] ; /* NUMBER OF LOGICAL RECORDS */ + char FSTFCLPT[2] ; /* FIRST CHAIN LINK POINTER */ + char FSTRECFM[1] ; /* F*1 - RECORD FORMAT - F OR V */ +#define FSTDFIX 0xC6 /* C'F' - Fixed record format */ +#define FSTDVAR 0xE5 /* C'V' - Variable record format */ + char FSTFLAGS[1] ; /* F*2 - FST FLAG BYTE */ +#define FSTRWDSK 0x80 /* READ/WRITE DISK */ +#define FSTRODSK 0x00 /* READ/ONLY DISK */ +#define FSTDSFS 0x10 /* Shared File FST */ +#define FSTXRDSK 0x40 /* EXTENSION OF R/O DISK */ +#define FSTXWDSK 0xC0 /* EXTENSION OF R/W DISK */ +#define FSTEPL 0x20 /* EXTENDED PLIST */ +#define FSTDIA 0x40 /* ITEM AVAILABLE */ +#define FSTDRA 0x01 /* PREVIOUS RECORD NULL */ +#define FSTCNTRY 0x08 /* Century for date last + written (0=19, 1=20), corresponds + to FSTYEARW, FSTADATI. */ +#define FSTACTRD 0x04 /* ACTIVE FOR READING */ +#define FSTACTWR 0x02 /* ACTIVE FOR WRITING */ +#define FSTACTPT 0x01 /* ACTIVE FROM A POINT */ +#define FSTFILEA 0x07 /* THE FILE IS ACTIVE */ + char FSTLRECL[4] ; /* LOGICAL RECORD LENGTH */ + char FSTBLKCT[2] ; /* NUMBER OF 800 BYTE BLOCKS */ + char FSTYEARW[2] ; /* YEAR LAST WRITTEN */ + char FSTFOP[4] ; /* ALT. FILE ORIGIN POINTER */ + char FSTADBC[4] ; /* ALT. NUMBER OF DATA BLOCKS */ + char FSTAIC[4] ; /* ALT. ITEM COUNT */ + char FSTNLVL[1] ; /* NUMBER OF POINTER BLOCK LEVELS */ + char FSTPTRSZ[1] ; /* LENGTH OF A POINTER ELEMENT */ + char FSTADATI[6] ; /* ALT. DATE/TIME(YY MM DD HH MM SS) */ + char FSTREALM[1] ; /* Real filemode */ + char FSTFLAG2[1] ; /* F*3 - FST FLAG BYTE 2 FSTFLAG2 */ +#define FSTPIPEU 0x10 /* Reserved for CMS + PIPELINES usage */ + char reserved[2] ; +} FSTD ; /* File Status Table DSECT */ + +#define FSTDSIZE 0x00000040 /* FST SIZE IN BYTES */ + +/* + FSTD Storage Layout*** FSTD - File Status Table DSECT +* +* +-------------------------------------------------------+ +* 0 | FSTFNAME | +* +-------------------------------------------------------+ +* 8 | FSTFTYPE | +* +-------------+-------------+-------------+-------------+ +* 10 | FSTDATEW | FSTTIMEW | FSTWRPNT | FSTRDPNT | +* +-------------+-------------+-------------+------+------+ +* 18 | FSTFMODE | FSTRECCT | FSTFCLPT |:RECFM|:FLAGS| +* +-------------+-------------+-------------+------+------+ +* 20 | FSTLRECL | FSTBLKCT | FSTYEARW | +* +---------------------------+-------------+-------------+ +* 28 | FSTFOP | FSTADBC | +* +---------------------------+------+------+-------------+ +* 30 | FSTAIC |:NLVL |:PTRSZ| (036)- | +* +---------------------------+------+------+-------------+ +* 38 | -FSTADATI |:REALM|:FLAG2|/////////////| +* +---------------------------+------+------+-------------+ +* 40 +* + +This information is based on VM/ESA 2.4.0. +Last updated on 12 Aug 1999 at 11:21:05 EDT. +Copyright IBM Corporation, 1990, 1999 + + */ + +/* ------------------------------------------------------------ CMSFSADT + * Mock ADTSECT for the CMS FS for Linux. + * Based on: http://www.vm.ibm.com/pubs/cmsdacb/ADTSECT.HTML + * noting offset 144 (0x90) for 80 bytes (0x50) + */ +typedef struct CMSFSADT +{ + char ADTIDENT[4] ; /* VOL START / LABEL IDENTIFIER */ + char ADTID[6] ; /* VOL START / VOL IDENTIFIER */ + char ADTVER[2] ; /* VERSION LEVEL */ + char ADTDBSIZ[4] ; /* DISK BLOCK SIZE */ + char ADTDOP[4] ; /* DISK ORIGIN POINTER */ + char ADTCYL[4] ; /* NUM OF FORMATTED CYL ON DISK */ + char ADTMCYL[4] ; /* MAX NUM FORMATTED CYL ON DISK */ + char ADTNUM[4] ; /* Number of Blocks on disk */ + char ADTUSED[4] ; /* Number of Blocks used */ + char ADTFSTSZ[4] ; /* SIZE OF FST */ + char ADTNFST[4] ; /* NUMBER OF FST'S PER BLOCK */ + char ADTDCRED[6] ; /* DISK CREATION DATE (YYMMDDHHMMSS) */ + char ADTFLGL[1] ; /* LABEL FLAG BYTE (ADTFLGL) */ +#define ADTCNTRY 0x01 /* Century for disk creation + date (0=19, 1=20), corresponds to + ADTDCRED. */ + char reserved[1] ; + char ADTOFFST[4] ; /* DISK OFFSET WHEN RESERVED */ + char ADTAMNB[4] ; /* ALLOC MAP BLOCK WITH NEXT HOLE */ + char ADTAMND[4] ; /* DISP INTO HBLK DATA OF NEXT HOLE */ + char ADTAMUP[4] ; /* DISP INTO USER PART OF ALLOC MAP */ + char ADTOFCNT[4] ; /* Count of SFS open files for this ADT */ + char ADTSFNAM[8] ; /* NAME OF SHARED SEGMENT */ +} CMSFSADT ; + +#define ADTLABSZ 0x00000050 /* LENGTH OF THE LABEL PORTION */ + +/* + MAPPING OF VOLUME LABEL +0090 144 Dbl-Word 8 * (0) +0090 144 Character 4 ADTIDENT VOL START / LABEL IDENTIFIER +0094 148 Character 6 ADTID VOL START / VOL IDENTIFIER +009A 154 Character 2 ADTVER VERSION LEVEL +009C 156 Signed 4 ADTDBSIZ DISK BLOCK SIZE +00A0 160 Signed 4 ADTDOP DISK ORIGIN POINTER +00A4 164 Signed 4 ADTCYL NUM OF FORMATTED CYL ON DISK +00A8 168 Signed 4 ADTMCYL MAX NUM FORMATTED CYL ON DISK +00AC 172 Signed 4 ADTNUM Number of Blocks assigned to the + minidisk or, in the case of an + SFS top directory, the number of + blocks assigned to the containing + filespace. This field is not set + for SFS subdirectories except as + a byproduct of the ADT Lookup + function, which queries the space + values for subdirs and also + leaves these values in the ADT + space fields. +00B0 176 Signed 4 ADTUSED Number of Blocks used in the + minidisk or, in the case of an + SFS top directory, the number of + blocks consumed in the containing + filespace. This field is not set + for SFS subdirectories except as + a byproduct of the ADT Lookup + function, which queries the space + values for subdirs and also + leaves these values in the ADT + space fields. +00B4 180 Signed 4 ADTFSTSZ SIZE OF FST +00B8 184 Signed 4 ADTNFST NUMBER OF FST'S PER BLOCK +00BC 188 Character 6 ADTDCRED DISK CREATION DATE (YYMMDDHHMMSS) +00C2 194 Bitstring 1 ADTFLGL LABEL FLAG BYTE (ADTFLGL) + EQUATES FOR ADT LABEL FLAG BYTE (ADTFLGL) + .... ...1 ADTCNTRY X'01' Century for disk creation + date (0=19, 1=20), corresponds to + ADTDCRED. +00C3 195 Character 1 * RESERVED +00C4 196 Signed 4 ADTOFFST DISK OFFSET WHEN RESERVED +00C8 200 Signed 4 ADTAMNB ALLOC MAP BLOCK WITH NEXT HOLE +00CC 204 Signed 4 ADTAMND DISP INTO HBLK DATA OF NEXT HOLE +00D0 208 Signed 4 ADTAMUP DISP INTO USER PART OF ALLOC MAP +00D4 212 Signed 4 ADTOFCNT Count of SFS open files for this + ADT NOTE: ADTOFCNT IS NOT REALLY + PART OF THE VOLUME LABEL - IT IS + NOT USED FOR MINIDISKS. +00D8 216 Character 8 ADTSFNAM NAME OF SHARED SEGMENT + 00000050 ADTLABSZ *-ADTIDENT LENGTH OF THE LABEL + PORTION + +* +---------------------------+---------------------------+ +* 90 | ADTIDENT | ADTID- | +* +-------------+-------------+---------------------------+ +* 98 | -(094) | ADTVER | ADTDBSIZ | +* +-------------+-------------+---------------------------+ +* A0 | ADTDOP | ADTCYL | +* +---------------------------+---------------------------+ +* A8 | ADTMCYL | ADTNUM | +* +---------------------------+---------------------------+ +* B0 | ADTUSED | ADTFSTSZ | +* +---------------------------+---------------------------+ +* B8 | ADTNFST | ADTDCRED- | +* +-------------+------+------+---------------------------+ +* C0 | -(0BC) |:FLGL |//////| ADTOFFST | +* +-------------+------+------+---------------------------+ +* C8 | ADTAMNB | ADTAMND | +* +---------------------------+---------------------------+ +* D0 | ADTAMUP | ADTOFCNT | +* +---------------------------+---------------------------+ +* D8 | ADTSFNAM | +* +-------------------------------------------------------+ +* E0 +* + +This information is based on VM/ESA 2.4.0. +Last updated on 12 Aug 1999 at 11:17:01 EDT. +Copyright IBM Corporation, 1990, 1999 + + */ + +/* ------------------------------------------------------------ CMSFSEXT + * A structure for the file extension mapping table. + * Used for handling default translation based on filetype. + * The ftype (filetype) is actually only eight bytes, + * plus one for the string terminator, but then + * plus one more for easier alignment. + */ +typedef struct CMSFSEXT { + unsigned char ftype[10]; + u16 flags; +} CMSFSEXT ; + +/* ------------------------------------------------------------ CMSINODE + * An inode structure (non VFS) for the CMS FS driver and utility. + * This is used stand-alone by the utility, + * and used in concert with the VFS inode structure by the driver. + */ +struct cms_inode { + long magic; /* not used at this time */ + void *vfsinode; /* pointer to Linux VFS inode, if any */ + char name[18] , fname[9], ftype[9], fmode[2]; + int lrecl ; + char recfm[2] ; + int index ; /* index into directory of this file */ + /* (also serves as an inode number) */ + time_t ctime ; /* computed UNIX time from CMS timestamp */ + int bloks ; /* blocks in first-level */ + /* If there is only one level, + then this is the total number of blocks */ + int items ; /* number of records in this file */ + int origin; /* "base one" File Origin Pointer (FOP) */ + /* "base zero" offset is derived from FOP */ + + int level ; /* level of indirection */ + int psize ; /* size of indir pointers */ + int bytes ; /* Not "size", because the term is + ambiguous for IBM files which might have + "sizes" stated in terms of records, blocks, + tracks, or possibly even cylinders. + This must be computed, and recomputed ... */ + + int rdpnt; /* the current record */ + int rdblk; /* the current block */ + int rdoff; /* the offset into the current block */ + void *rdbuf; /* buffer storage for current block */ + + int rdoff2; /* the offset into the current record */ + void *rdbuf2; /* buffer storage for current record */ + + unsigned int flags ; /* V or F bit, binary or text bit, etc */ + /* CAREFUL HOW MUCH YOU PACK IN HERE. + This structure is intended for portability; + this field might not always be 32 bits!! */ + struct cms_super *cmssuper; /* the containing CMS superblock */ + int error; /* error code, if any */ +}; + +/* ------------------------------------------------------------ CMSSUPER + * A filesystem info structure for the CMS FS driver and utility. + * AKA: "superblock for CMS", therefore FKA: "CMSVOLID" + */ + +struct cms_super { + long magic; /* not used at this time */ + void *vfssuper; /* pointer to Linux VFS superblock, if any */ + char vtype[5]; /* volume type ID; "CMS1" for CMS filesystems */ + char volid[7]; /* volume label (volume serial number) */ + long blksz; /* statfs f_bsize + block size of this volume */ + int pbksz; /* physical blocksize */ + int origin; /* "base one" Directory Origin Pointer (DOP) */ + /* "base zero" offset is derived from DOP */ + int ncyls; /* number of cylinders used by filesystem */ + int mcyls; /* number of cylinders on the disk */ + /* CMS has a concept of "recomp" where + cylinders beyond the filesystem may be + used by other things, like a boot loader. */ + long blocks; /* statfs f_blocks + total number of blocks in the filesystem */ + long bkused; /* blocks used (per ADT) */ + long bkfree; /* statfs f_bfree + blocks free (computed) */ + int fstsz; /* size of each directory entry (of each FST) */ + int fstct; /* number of FSTs (FST count) per block */ + time_t ctime; /* time when this filesystem was created */ + int resoff; /* reserved offset */ + /* CMS has a concept of a "reserved disk" + where one file occupies the entire disk. + Additionally, that file is referenced by this + so that the filesystem (directory) mechanism + can be bypassed. */ + int devfd; /* when accessed from "user space" + (when run as a utility, not the driver), + the file descriptor of the file + containg this CMS filesystem */ + int devid; /* the Linux device ID, if available */ + int devno; /* the S/390 device number, if available */ + int subch; /* the S/390 sub-channel, if available */ + long files; /* statfs f_files + extracted from directory FST "items" */ + int inuse; /* number of files open at any time */ + /* (map to ADTOFCNT, perhaps) */ + unsigned int flags; /* FBA bit, and so forth */ + /* CAREFUL HOW MUCH YOU PACK IN HERE. + This structure is intended for portability; + this field might not always be 32 bits!! */ + struct cms_inode *cmsrooti; /* pointer to directory inode (CMS flavor) */ + /* (member 'cmssuper' must point back here) */ + struct CMSFSEXT *cmsfsext; /* pointer to exten map (type map) struct */ + int error; /* error code, if any */ +} ; + + +/* + The following struct taken from /usr/include/time.h: + + Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* Used by other time functions. */ +struct cmsfs_tm +{ + int tm_sec; /* Seconds. [0-60] (1 leap second) */ + int tm_min; /* Minutes. [0-59] */ + int tm_hour; /* Hours. [0-23] */ + int tm_mday; /* Day. [1-31] */ + int tm_mon; /* Month. [0-11] */ + int tm_year; /* Year - 1900. */ + int tm_wday; /* Day of week. [0-6] */ + int tm_yday; /* Days in year.[0-365] */ + int tm_isdst; /* DST. [-1/0/1]*/ + long tm_gmtoff; /* Seconds east of UTC. */ + __const char *tm_zone; /* Timezone abbreviation. */ +}; + + +/* ------------------------------------------------------------------ * + * Function Prototypes * + * ------------------------------------------------------------------ */ + +/* ------------------------------------------------------------------ * + * Function Prototypes used by all CMS FS implementations * + * ------------------------------------------------------------------ */ +static int cmsfs_bread(struct cms_super *,void *,int,int); + +static int cmsfs_map_ADT(struct cms_super *); +static int cmsfs_map_FST(struct cms_inode *,struct CMSFSFST *); +static void cmsfs_map_EXT(struct cms_inode *); +static struct cms_inode * cmsfs_lookup(struct cms_inode *,unsigned char *); +static ssize_t cmsfs_read(struct cms_inode *,void *,size_t); + + +/* ------------------------------------------------------------------ * + * Function Prototypes used by the driver are presently * + * all contained within one compilation unit. * + * ------------------------------------------------------------------ */ + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/cmsfs/cmsfsext.h linux.ac/fs/cmsfs/cmsfsext.h --- linux.vanilla/fs/cmsfs/cmsfsext.h Thu Jan 1 01:00:00 1970 +++ linux.ac/fs/cmsfs/cmsfsext.h Tue Apr 3 17:55:10 2001 @@ -0,0 +1,160 @@ +/* + * + * Name: cmsfsext.h + * CMS FS file EXTensions table + * Author: Rick Troth, BMC Software, Inc., Houston, Texas, USA + * Date: 2000-Sep-10 (Sun) + * + * Well-known ASCII (plain text) file extensions + * taken from linux/fs/fat/misc.c which was + * written 1992, 1993 by Werner Almesberger. + * The table structure is completely different. + * Expanded to 8-byte filetypes and then + * well-known IMAGE (binary) file extensions added + * by Rick Troth for the CMS FS util/driver. + * The table is ultimately replaceable via ioctl(). + * For the time being, replacement is not implemented. + * + * See cmsfs.h for constants, + * typically one of CMSFSTXT, CMSFSBIN, or CMSFSRAW. + * Use CMSFSANY elsewhere to indicate automatic selection. + * Do NOT use CMSFSANY in the table below. + * + */ + +/* ------------------------------------------------------------ CMSFSEXT + */ +static struct CMSFSEXT cmsfsext[] = { +/* Well-known ASCII (plain text) file extensions */ +/* text files */ + { "TXT ", CMSFSTXT}, + { "HTM ", CMSFSTXT}, + { "HTML ", CMSFSTXT}, + { "GML ", CMSFSTXT}, + { "SGML ", CMSFSTXT}, + { "LOG ", CMSFSTXT}, + { "ME ", CMSFSTXT}, /* as in "READ ME" or "read.me" */ + { "1ST ", CMSFSTXT}, /* "README 1ST" or "readme.1st" */ + { "FIRST ", CMSFSTXT}, /* "README FIRST" or "readme.first" */ + { "README ", CMSFSTXT}, +/* programming languages */ + { "C ", CMSFSTXT}, + { "H ", CMSFSTXT}, + { "CPP ", CMSFSTXT}, + { "LIS ", CMSFSTXT}, + { "LIST ", CMSFSTXT}, + { "LISTING ", CMSFSTXT}, + { "PS ", CMSFSTXT}, + { "FILELIST", CMSFSTXT}, + { "PAS ", CMSFSTXT}, + { "PASCAL ", CMSFSTXT}, + { "PLI ", CMSFSTXT}, + { "PLIOPT ", CMSFSTXT}, + { "FOR ", CMSFSTXT}, + { "FORT ", CMSFSTXT}, + { "FORTRAN ", CMSFSTXT}, + { "MACRO ", CMSFSTXT}, + { "ASSEMBLE", CMSFSTXT}, + { "ASM ", CMSFSTXT}, + { "COPY ", CMSFSTXT}, +/* programming languages and tools */ + { "F ", CMSFSTXT}, + { "MAK ", CMSFSTXT}, + { "MAKE ", CMSFSTXT}, + { "MAKEFILE", CMSFSTXT}, + { "CNTRL ", CMSFSTXT}, + { "AUX* ", CMSFSTXT}, + { "MAP ", CMSFSTXT}, + { "INC ", CMSFSTXT}, + { "INCLUDE ", CMSFSTXT}, + { "BAS ", CMSFSTXT}, + { "BASIC ", CMSFSTXT}, + { "HELP* ", CMSFSTXT}, + { "EPS ", CMSFSTXT}, +/* various scripting languages */ + { "BAT ", CMSFSTXT}, + { "CMD ", CMSFSTXT}, + { "SH ", CMSFSTXT | CMSFSEXE}, + { "EXEC ", CMSFSTXT}, + { "REXX ", CMSFSTXT}, + { "XEDIT ", CMSFSTXT}, + { "CGI ", CMSFSTXT}, + { "TCL ", CMSFSTXT | CMSFSEXE}, + { "TK ", CMSFSTXT | CMSFSEXE}, + { "PL ", CMSFSTXT | CMSFSEXE}, +/* config files */ + { "INI ", CMSFSTXT}, + { "CONFIG ", CMSFSTXT}, + { "CFG ", CMSFSTXT}, + { "TCPXLATE", CMSFSTXT}, + { "RTABLE ", CMSFSTXT}, + { "PSEG ", CMSFSTXT}, + { "DIRECT ", CMSFSTXT}, /* equiv to VMware "vmx" or "cfg" types */ + { "VMX ", CMSFSTXT}, /* yes, that's VMware, not VM/ESA */ +/* graphics */ + { "PBM ", CMSFSTXT}, + { "PGM ", CMSFSTXT}, + { "DXF ", CMSFSTXT}, +/* TeX */ + { "TEX ", CMSFSTXT}, + { "XML ", CMSFSTXT}, +/* databases */ + { "NAMES ", CMSFSTXT}, + { "NODES ", CMSFSTXT}, +/* more than I care to document ... */ + { "NOTE ", CMSFSTXT}, + { "MAIL ", CMSFSTXT}, + { "VCF ", CMSFSTXT}, /* VCard */ + { "VCARD ", CMSFSTXT}, + { "SYNONYM ", CMSFSTXT}, +/* documentation */ + { "1 ", CMSFSTXT}, + { "2 ", CMSFSTXT}, + { "3 ", CMSFSTXT}, + { "4 ", CMSFSTXT}, + { "5 ", CMSFSTXT}, + { "6 ", CMSFSTXT}, + { "7 ", CMSFSTXT}, + { "8 ", CMSFSTXT}, + { "9 ", CMSFSTXT}, + { "N ", CMSFSTXT}, +/* Well-known IMAGE (binary) file extensions */ + { "BIN ", CMSFSBIN}, + { "EXE ", CMSFSBIN}, + { "DLL ", CMSFSBIN}, + { "O ", CMSFSBIN}, + { "OBJ ", CMSFSBIN}, + { "BOO ", CMSFSBIN}, + { "BOOK ", CMSFSBIN}, + { "TXTLIB ", CMSFSBIN}, + { "TXT* ", CMSFSBIN}, /* hoping it's F 80 */ + { "TCPXLBIN", CMSFSBIN}, /* hoping it's F 256 */ + { "GIF ", CMSFSBIN}, + { "JPG ", CMSFSBIN}, + { "JPEG ", CMSFSBIN}, + { "MPG ", CMSFSBIN}, + { "MPEG ", CMSFSBIN}, + { "TIF ", CMSFSBIN}, + { "TIFF ", CMSFSBIN}, + { "MOV ", CMSFSBIN}, + { "MOVIE ", CMSFSBIN}, + { "AVI ", CMSFSBIN}, + { "VMARC ", CMSFSBIN}, /* hoping it's F 80 (!) */ + { "ZIP ", CMSFSBIN}, + { "Z ", CMSFSBIN}, + { "GZ ", CMSFSBIN}, + { "TAR ", CMSFSBIN}, + { "TAZ ", CMSFSBIN}, + { "TGZ ", CMSFSBIN}, + { "PGP ", CMSFSBIN}, + { "RPM ", CMSFSBIN}, +/* Well-known record-oriented file extensions */ + { "LIST3820", CMSFSRAW}, + { "MODULE ", CMSFSRAW}, + { "LOADLIB ", CMSFSRAW}, +/* the terminator */ + { "ALLOCMAP", CMSFSBIN}, + { "DIRECTOR", CMSFSBIN}, /* better be F 64! */ + + { " ", CMSFSANY} +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/cmsfs/cmsfsvfs.c linux.ac/fs/cmsfs/cmsfsvfs.c --- linux.vanilla/fs/cmsfs/cmsfsvfs.c Thu Jan 1 01:00:00 1970 +++ linux.ac/fs/cmsfs/cmsfsvfs.c Tue Apr 3 17:55:10 2001 @@ -0,0 +1,1688 @@ +/* + * + * Name: cmsfsvfs.c (C program source) + * CMS FS VFS interface routines (fs driver code) + * Date: 2000-Sep-14 (Thu) + * + * This source contains the routines and structures + * required when CMS FS is built as a driver. + * It interfaces between CMS FS' own structures, + * which read the CMS EDF format, and Linux VFS. + * + * 2001/03/09 Alan Cox <alan@redhat.com> + * Reformat into kernel style + * Remove static buffers + * Merge code together + * Throw out userspace tool support + * Switch to pure Linux errno codes + * + * So if it stopped working - blame me first + */ + +#include <linux/module.h> +#include <linux/version.h> +#include <linux/fs.h> +#include <linux/slab.h> +#include <linux/mm.h> +#include <linux/locks.h> +#include <linux/init.h> + +#include <asm/uaccess.h> + +#include "cmsfs.h" +#include "cmsfsext.h" +#include "aecs.h" + +#define CMSFS_HOST_ASCII + +/* ----------------------------------------------------------------- ĆCS + * ASCII to EBCDIC and vice-versa code conversion routines. + * Tables included here are based on ASCII conforming to the ISO8859-1 + * Latin 1 character set and EBCDIC conforming to the IBM Code Page 37 + * Latin 1 character set (except for three pairs of characters in 037). + */ + +#ifdef CMSFS_HOST_ASCII + +/* ------------------------------------------------------------- CHRATOE + * Translate an ASCII character into EBCDIC. + */ + +static inline int chratoe(unsigned int c) +{ + c &= 0xFF; + return (ebc8859[c]); +} + +/* ------------------------------------------------------------- STRATOE + * Translate an ASCII string into EBCDIC in place. Return length. + */ + +static void stratoe(unsigned char *string) +{ + int i; + + for (i = 0; string[i] != 0x00; i++) + string[i] = ebc8859[(int) string[i]]; + string[i] = ebc8859[(int) string[i]]; +} + +/* ------------------------------------------------------------- CHRETOA + * Translate an EBCDIC character into ASCII. + */ + +static inline int chretoa(unsigned int c) +{ + c &= 0xFF; + return asc8859[c]; +} + +/* ------------------------------------------------------------- STRETOA + * Translate an EBCDIC string into ASCII in place. Return length. + */ + +static void stretoa(unsigned char *s) +{ + int i; + + for (i = 0; s[i] != 0x00; i++) + s[i] = asc8859[(int) s[i]]; + s[i] = asc8859[(int) s[i]]; +} + +#else + +static inline void stretoa(unsigned char *s) {;} +static inline void stratoe(unsigned char *s) {;} +#define chretoa(x) (x) +#define chratoe(x) (x) + +#endif + +/* --------------------------------------------------------- CMSFS_BREAD + * The "b" here means "block", not "buffer". Do not confuse this with + * Linux VFS bread() function. This is CMS FS "block read" function. + */ + +static int cmsfs_bread(struct cms_super *vol,void *buf,int block,int blocksize) +{ + struct buffer_head * bh; + struct super_block * sb; + + /* for the moment, we only deal with physical blocks */ + if (blocksize != vol->pbksz) + BUG(); + + /* We could maybe handle that case by breaking-up this call into + multiple bread() calls, but that'll be a later driver rev. */ + + sb = (struct super_block *) vol->vfssuper; + + /* Call the system-level bread() */ + bh = bread(sb->s_dev,block,blocksize); + if (bh == NULL) + { + printk(KERN_WARNING "cmsfs_bread(): system bread() failed.\n"); + return -1; + } + + /* copy the data part, then release the VFS buffer */ + (void) memmove(buf,bh->b_data,blocksize); + (void) brelse(bh); + + return blocksize; +} + + +/* ------------------------------------------------------------ CMSFSBEX + * convert a big-endian integer into a local integer + * the slow (reliable) way + */ + +static int cmsfsbex(char *ivalue, int l) +{ + int i, ovalue; + ovalue = ivalue[0]; + for (i = 1; i < l; i++) { + ovalue = ovalue << 8; + ovalue += ivalue[i] & 0xFF; + } + return ovalue; +} + +/* ------------------------------------------------------------ CMSFSX2I + * CMS FS heXadecimal-to-Integer function + * The EDF filesystem uses several "packed decimal" fields. + * (Actually a visual approximation of packed decimal format + * lacking the sign nibble.) This is for converting them to int. + */ + +static int cmsfsx2i(char *ivalue, int l) +{ + int i, ovalue; + ovalue = (ivalue[0] & 0x0F) + ((ivalue[0] >> 4) & 0x0F) * 10; + for (i = 1; i < l; i++) { + ovalue = ovalue << 8; + ovalue += + (ivalue[i] & 0x0F) + ((ivalue[i] >> 4) & 0x0F) * 10; + } + return ovalue; +} + +/* ---------------------------------------------------- CMSFS_FIND_LABEL + * Look for the CMS volume label structure (ADT). + * If we don't find it, this ain't no CMS EDF filesystem. + * Returns the physical blocksize of the disk on success. + */ +static int cmsfs_find_label(struct cms_super *vol, struct CMSFSADT *adt) +{ + int i, rc; + unsigned char *cmsfsflb; + + /* (probably should compute) */ + + /* char array (4 bytes) "CMS1" filesystem identifier */ + char cmsfsvsk[8] = CMSFSVSK; + /* (a "magic number" by any other name) */ + + /* array of possible CMS FS blocksizes */ + int cmsfsbkt[8] = CMSFSBKT; + + cmsfsflb = (void *)get_free_page(GFP_KERNEL); + if(cmsfsflb==NULL) + { + if(vol->error == 0) + vol->error = EIO; + return -1; + } + + /* + * FBA DASDs are special. Physical blocsize is always 512 + * and the label is at physical offset 512 (second record), + * though the logical blocksize may be 512, 1K, 2K, or 4K. + */ + if (vol->pbksz == 0 || vol->pbksz == 512) { + /* read FBA block #1 (second record) */ + rc = cmsfs_bread(vol, cmsfsflb, 1, 512); + if (rc != 512) { + if (vol->error == 0) + vol->error = EIO; /* I/O error */ + free_page((unsigned long)cmsfsflb); + return -1; + } + (void) memcpy(adt, cmsfsflb, sizeof(*adt)); + + /* check for the CMS1 magic at the FBA offset */ + if (adt->ADTIDENT[0] == cmsfsvsk[0] + && adt->ADTIDENT[1] == cmsfsvsk[1] + && adt->ADTIDENT[2] == cmsfsvsk[2] + && adt->ADTIDENT[3] == cmsfsvsk[3]) + { + int blksz; + blksz = cmsfsbex(adt->ADTDBSIZ, 4); + if (blksz != 512) { + printk(KERN_WARNING "cmsfs_find_label(): FS blocksize %d does not match device blocksize %d.\n", blksz, 512); + } + vol->flags = CMSFSFBA; + vol->blksz = 512; + free_page((unsigned long)cmsfsflb); + return vol->blksz; + } + } + + /* not an FBA volume; try CKD blocksizes */ + /* + * CKD DASDs are C/H/S in nature and can have any blocksize + * that the utility or operating system decided to put there. + * OS/390 uses no particular blocksize, referring to tracks + * directly. For CMS CKD volumes, the physical blocksize + * should match logical, unless obscured by the access method. + */ + for (i = 0; cmsfsbkt[i] != 0; i++) { + if (vol->pbksz == 0 || vol->pbksz == cmsfsbkt[i]) { + /* read CKD block #2 (third record) */ + rc = cmsfs_bread(vol, cmsfsflb, 2, cmsfsbkt[i]); + if (rc != cmsfsbkt[i]) { + if (vol->error == 0) + vol->error = EIO; /* I/O error */ + free_page((unsigned long)cmsfsflb); + return -1; + } + (void) memcpy(adt, cmsfsflb, sizeof(*adt)); + + /* check for the CMS1 magic */ + if (adt->ADTIDENT[0] == cmsfsvsk[0] + && adt->ADTIDENT[1] == cmsfsvsk[1] + && adt->ADTIDENT[2] == cmsfsvsk[2] + && adt->ADTIDENT[3] == cmsfsvsk[3]) { + int blksz; + blksz = cmsfsbex(adt->ADTDBSIZ, 4); + if (blksz == cmsfsbkt[i]) { + vol->flags = CMSFSCKD; + vol->blksz = cmsfsbkt[i]; + free_page((unsigned long)cmsfsflb); + return vol->blksz; + + } + printk(KERN_ERR "cmsfs_find_label(): FS blocksize %d does not match device blocksize %d.\n", blksz, cmsfsbkt[i]); + } + } + } + + vol->error = ENOMEDIUM; /* "No medium found" */ + return -1; /* not a CMS volume */ +} + +/* + * The above routine presumes that even an FBA volume will be + * at least 12K. This is technically incorrect: FBA CMS formatting + * can use as little as 8K. But since such a volume would have + * only 1024 bytes for storage, I think this is a small exposure. + */ + +/* ------------------------------------------------------- CMSFS_MAP_ADT + * Map an ADT struct into our own cms_super superblock struct. + * CMS flavor superblock struct must be supplied. + * CMS flavor inode struct will be allocated, if this succeeeds. + */ + +static int cmsfs_map_ADT(struct cms_super *vol) +{ + int i, /* a counter */ + rc; /* a return code */ + + /* partial "ADT" structure (per IBM) */ + static struct CMSFSADT cmsvol; + unsigned char *cmsfsflb; + /* (probably should compute instead of always using max) */ + + /* should check that cms_super passed is non-NULL */ + /* should perhaps check that vol->inuse == 0 */ + + /* set this to zero now because it serves as a check later */ + vol->blksz = 0; + + /* look for the CMS volume label (aka VOLSER) */ + rc = cmsfs_find_label(vol, &cmsvol); + /* this also effects a load of the ADT struct to &cmsvol */ + /* and sets the blksz member to match the volume found */ + + /* did we find a CMS1 volume label? */ + if (rc <= 0) { + printk(KERN_WARNING "cmsfs_map_ADT(): cannot find a CMS1 label"); + return -1; + } + + /* extract volume label and translate */ + for (i = 0; i < 6; i++) + vol->volid[i] = cmsvol.ADTID[i]; + vol->volid[6] = 0x00; + + stretoa(vol->volid); + + /* extract "directory origin pointer" */ + vol->origin = cmsfsbex(cmsvol.ADTDOP, 4); + + /* extract number of cylinders used */ + vol->ncyls = cmsfsbex(cmsvol.ADTCYL, 4); + + /* extract max number of cylinders */ + vol->mcyls = cmsfsbex(cmsvol.ADTMCYL, 4); + + /* extract "total blocks on disk" count */ + vol->blocks = cmsfsbex(cmsvol.ADTNUM, 4); + + /* compute "blocks used" count */ + vol->bkused = cmsfsbex(cmsvol.ADTUSED, 4); + vol->bkused += 1; /* why??? */ + + /* compute "blocks free" count */ + vol->bkfree = vol->blocks - vol->bkused; + + /* compute time (as ctime) when this volume was created */ + { + struct cmsfs_tm temptime; /* temporary */ + temptime.tm_sec = cmsfsx2i(&cmsvol.ADTDCRED[5], 1); + temptime.tm_min = cmsfsx2i(&cmsvol.ADTDCRED[4], 1); + temptime.tm_hour = cmsfsx2i(&cmsvol.ADTDCRED[3], 1); + temptime.tm_mday = cmsfsx2i(&cmsvol.ADTDCRED[2], 1); + temptime.tm_mon = cmsfsx2i(&cmsvol.ADTDCRED[1], 1) - 1; + temptime.tm_year = cmsfsx2i(&cmsvol.ADTDCRED[0], 1); + if (cmsvol.ADTFLGL[0] & ADTCNTRY) + temptime.tm_year += 100; + vol->ctime = mktime(temptime.tm_year, temptime.tm_mon, + temptime.tm_mday, temptime.tm_hour, + temptime.tm_min, temptime.tm_sec); + } + + /* extract offset to reserved file, if any */ + vol->resoff = cmsfsbex(cmsvol.ADTOFFST, 4); + + /* extract size and number of FSTs */ + vol->fstsz = cmsfsbex(cmsvol.ADTFSTSZ, 4); + vol->fstct = cmsfsbex(cmsvol.ADTNFST, 4); + + /* initial filetype mapping table is NULL */ + vol->cmsfsext = NULL; + + cmsfsflb = (void *)get_free_page(GFP_KERNEL); + if(cmsfsflb==NULL) + { + printk(KERN_WARNING "cmfsfs_map_ADT(): out of memory for buffer.\n"); + return -1; + } + + /* allocate and map the directory inode from its FST */ + + vol->cmsrooti = kmalloc(sizeof(struct cms_inode), GFP_KERNEL); + if (vol->cmsrooti == NULL) { + printk(KERN_WARNING "cmsfs_map_ADT(): cannot allocate CMS directory inode.\n"); + free_page((unsigned long)cmsfsflb); + return -1; + } + + /* read in the first FST */ + rc = cmsfs_bread(vol, cmsfsflb, vol->origin - 1, vol->blksz); + if (rc != vol->blksz) { + kfree(vol->cmsrooti); + free_page((unsigned long)cmsfsflb); + vol->inuse = 0; /* we just deallocated that inode */ + return -1; + } + + vol->inuse = 1; /* we just allocated one inode */ + + /* point dir inode back to the superblock */ + vol->cmsrooti->cmssuper = vol; + /* must be set BEFORE calling cmsfs_map_FST() */ + + /* map the directory ADT into a the root directory inode */ + rc = cmsfs_map_FST(vol->cmsrooti, (struct CMSFSFST *) cmsfsflb); + if (rc != 0) { + printk(KERN_WARNING "cmsfs_map_ADT(): cmsfs_map_FST() of the directory returned %d.\n", rc); + kfree(vol->cmsrooti); + free_page((unsigned long)cmsfsflb); + vol->inuse = 0; /* we just deallocated that inode */ + return rc; + } + + vol->cmsrooti->flags = CMSFSBIN; /* directory is F 64 binary */ + + /* (announce if debugging) dir inode is now allocated and mapped */ + + /* sanity check: FOP in dir entry must match DOP in vol */ + + /* sanity check: RECFM of a directory must be "F" */ + if (vol->cmsrooti->recfm[0] != 'F') { + printk("cmsfs_map_ADT(): directory RECFM '%s' not 'F'.\n", vol->cmsrooti->recfm); + kfree(vol->cmsrooti); + free_page((unsigned long)cmsfsflb); + vol->inuse = 0; /* we just deallocated that inode */ + return -1; + } + + /* sanity check: LRECL of a directory must be 64 */ + if (vol->cmsrooti->lrecl != 64) { + printk(KERN_WARNING "cmsfs_map_ADT(): directory LRECL %d not 64.\n", vol->cmsrooti->lrecl); + kfree(vol->cmsrooti); + free_page((unsigned long)cmsfsflb); + vol->inuse = 0; /* we just deallocated that inode */ + return -1; + } + + vol->files = vol->cmsrooti->items; + + /* report */ + vol->error = 0; /* no error yet; this is a new superblock */ + + free_page((unsigned long)cmsfsflb); + return 0; +} + +/* ------------------------------------------------------- CMSFS_MAP_FST + * Map a CMS FS FST structure to our own cms_inode "inode" structure. + * Operation is function(target,source). + */ + +static int cmsfs_map_FST(struct cms_inode *finode, struct CMSFSFST *cmsfst) +{ + int i; + char *p, *q, *qq; + + /* extract and translate filename */ + p = cmsfst->FSTFNAME; + q = finode->name; + qq = finode->fname; + i = 0; + while (*p != 0x40 && *p != 0x00 && i < 8) { + *qq++ = *q++ = chretoa(*p++); + i++; + } + *q++ = '.'; + *qq++ = 0x00; + p = cmsfst->FSTFTYPE; + qq = finode->ftype; + i = 0; + while (*p != 0x40 && *p != 0x00 && i < 8) { + *qq++ = *q++ = chretoa(*p++); + i++; + } + *q++ = 0x00; + *qq++ = 0x00; + + /* extract and translate FMODE */ + p = cmsfst->FSTFMODE; + q = finode->fmode; + q[0] = chretoa(p[0]); + q[1] = chretoa(p[1]); + q[2] = 0x00; + + /* extract and translate RECFM */ + p = cmsfst->FSTRECFM; + q = finode->recfm; + q[0] = chretoa(p[0]); + q[1] = 0x00; + + /* extract LRECL */ + finode->lrecl = cmsfsbex(cmsfst->FSTLRECL, 4); + + /* extract "directory origin pointer" */ + finode->origin = cmsfsbex(cmsfst->FSTFOP, 4); + + /* extract block count */ + finode->bloks = cmsfsbex(cmsfst->FSTADBC, 4); + + /* extract item count */ + finode->items = cmsfsbex(cmsfst->FSTAIC, 4); + + /* conditionally report these CMS file attributes */ + + /* extract date and compute time stamp */ + { + struct cmsfs_tm temptime; /* temporary */ + temptime.tm_year = cmsfsx2i(&cmsfst->FSTADATI[0], 1); + if (cmsfst->FSTFLAGS[0] & FSTCNTRY) + temptime.tm_year += 100; + temptime.tm_mon = cmsfsx2i(&cmsfst->FSTADATI[1], 1) - 1; + temptime.tm_mday = cmsfsx2i(&cmsfst->FSTADATI[2], 1); + temptime.tm_hour = cmsfsx2i(&cmsfst->FSTADATI[3], 1); + temptime.tm_min = cmsfsx2i(&cmsfst->FSTADATI[4], 1); + temptime.tm_sec = cmsfsx2i(&cmsfst->FSTADATI[5], 1); + finode->ctime = mktime(temptime.tm_year, temptime.tm_mon, + temptime.tm_mday, temptime.tm_hour, + temptime.tm_min, temptime.tm_sec); + } + + /* levels of indirection and pointer size */ + finode->level = cmsfst->FSTNLVL[0] & 0xFF; + finode->psize = cmsfst->FSTPTRSZ[0] & 0xFF; + + /* conditionally report these CMS file attributes */ + + finode->rdpnt = finode->rdblk = finode->rdoff = 0; /* set read pointers to zero */ + finode->rdoff2 = 0; /* set read pointers to zero */ + + finode->rdbuf = NULL; /* no work buffer unless alloc later */ + finode->rdbuf2 = NULL; /* no span buffer unless alloc later */ + + finode->error = 0; /* no error yet; this is a new inode */ + finode->bytes = 0; /* don't bother about the size yet */ + finode->flags = 0x0000; + + return 0; +} + +/* ------------------------------------------------------- CMSFS_MAP_EXT + * Map a CMS filetype (sometimes called an "extension"). + * The terms "filetype" and "extension" are used interchangably here. + */ + +static void cmsfs_map_EXT(struct cms_inode *fi) +{ + int i; + unsigned char *p; + + /* sanity check: be sure supplied "inode" pointer is non-NULL */ + if (fi == NULL) + BUG(); + + /* sanity check: be sure inode referenced has a superblock */ + if (fi->cmssuper == NULL) + BUG(); + + /* silently return if this file has any flags already set */ + if (fi->flags != 0x0000) + return; + + /* possibly initialize the superblock's filetype mapping table */ + if (fi->cmssuper->cmsfsext == NULL) { + fi->cmssuper->cmsfsext = cmsfsext; + for (i = 0; fi->cmssuper->cmsfsext[i].ftype[0] != ' ' + && fi->cmssuper->cmsfsext[i].ftype[0] != ' '; i++) { + p = fi->cmssuper->cmsfsext[i].ftype; + while (*p != ' ' && *p != 0x00) + p++; + if (*p == ' ') + *p = 0x00; + } + } + + /* step through the known types list, looking for a match */ + for (i = 0; fi->cmssuper->cmsfsext[i].ftype[0] != ' '; i++) { + if (strncmp(fi->ftype, + fi->cmssuper->cmsfsext[i].ftype, 8) == 0x0000) + { + fi->flags = fi->cmssuper->cmsfsext[i].flags; + return; + } + } + + /* file is of a type we don't know how to canonicalize */ + return; +} + +/* ------------------------------------------------------------ CMSFSRD2 + * "Read Function number Two" -- read a block from a CMS file. + * This is a second attempt. THIS FUNCTION NEEDS A BETTER NAME. + */ + +static int cmsfsrd2(struct cms_inode *inode, void *buffer, int block) +{ + int ppb, i, j, b1, b2, rc; + void *bp; + + /* when no indirection, do a simple read */ + if (inode->level == 0) + return cmsfs_bread(inode->cmssuper, buffer, + inode->origin - 1 + block, + inode->cmssuper->blksz); + + /* pointers per block */ + if (inode->psize > 0) + ppb = inode->cmssuper->blksz / inode->psize; + else + ppb = inode->cmssuper->blksz / 4; + + /* read first block for indirection */ + b1 = block; + for (i = 0; i < inode->level; i++) + b1 = b1 / ppb; + rc = cmsfs_bread(inode->cmssuper, buffer, + inode->origin - 1 + b1, inode->cmssuper->blksz); + if (rc != inode->cmssuper->blksz) { + printk(KERN_WARNING + "cmsfsrd2(): cmsfs_bread(,,%d,%ld) returned %d.\n", + inode->origin - 1 + b1, + inode->cmssuper->blksz, rc); + return rc; + } + + for (j = 1; j <= inode->level; j++) { + /* read next block for indirection */ + b1 = block; + for (i = j; i < inode->level; i++) + b1 = b1 / ppb; + b1 = b1 % ppb; + bp = buffer; + bp += b1 * inode->psize; + b2 = cmsfsbex(bp, 4); + + /* read next block for indirection */ + rc = cmsfs_bread(inode->cmssuper, buffer, + b2 - 1, inode->cmssuper->blksz); + if (rc != inode->cmssuper->blksz) { + printk(KERN_WARNING "cmsfsrd2(): cmsfs_bread(,,%d,%ld) returned %d.\n", + inode->origin - 1 + b1, + inode->cmssuper->blksz, rc); + return rc; + } + } + return inode->cmssuper->blksz; +} + +/* -------------------------------------------------------- CMSFS_LOOKUP + * Lookup a file in the CMS directory. Allocates a cms_inode struct. + * After successful call to this function, the caller might + * possibly set the ->flags member. In kernel mode (VFS), + * the caller should also set the ->vfsinode member. + */ + +static struct cms_inode *cmsfs_lookup(struct cms_inode *di, unsigned char *fn) +{ + struct cms_inode *cmsinode; + int i, j, k, rc; + unsigned char *p, xmatch[18], umatch[18]; + unsigned char *buff; + + /* first things first: confirm superblock and root inode */ + if (di->cmssuper == NULL) + BUG(); + if (di->cmssuper->cmsrooti == NULL) + BUG(); + + /* gimme another CMS inode structure */ + cmsinode = kmalloc(sizeof(struct cms_inode), GFP_KERNEL); + if (cmsinode == NULL) { + printk(KERN_WARNING "cmsfs_lookup(): cannot allocate CMS inode.\n"); + return NULL; + } + + /* if we're opening the directory as a file, then ... */ + if (strncmp(fn, ".dir", 4) == 0) { + (void) memcpy(cmsinode, + di->cmssuper->cmsrooti, sizeof(*cmsinode)); + cmsinode->index = 0; /* the number of this inode */ + di->cmssuper->inuse += 1; /* another inode for this super */ + cmsinode->flags = CMSFSBIN; /* F 64 so, yes, binary */ + return cmsinode; /* return "success" */ + } + + /* set stuff up: fill-in the structure for this file */ + cmsinode->cmssuper = di->cmssuper; + + /* prepare to search: establish upper-case and exact matches */ + p = fn; + i = 0; + + /* first eight bytes (CMS filename) */ + while (i < 8 && *p != '.' && *p != 0x00) { + umatch[i] = xmatch[i] = chratoe(*p); + if (0x80 < umatch[i] && umatch[i] < 0xC0) + umatch[i] += 0x40; + i++; + p++; + } + + /* conditionally adjust pointer */ + if (*p != 0x00) + p++; + + /* possibly pad with blanks */ + while (i < 8) { + umatch[i] = xmatch[i] = 0x40; + i++; + } + + /* second eight bytes (CMS filetype) */ + while (i < 16 && *p != '.' && *p != 0x00) { + umatch[i] = xmatch[i] = chratoe(*p); + if (0x80 < umatch[i] && umatch[i] < 0xC0) + umatch[i] += 0x40; + i++; + p++; + } + + /* possibly pad with blanks */ + while (i < 16) { + umatch[i] = xmatch[i] = 0x40; + i++; + } + + /* terminate with NULL character */ + umatch[i] = xmatch[i] = 0x00; + + buff = (void *)get_free_page(GFP_KERNEL); + if(buff == NULL) + { + printk(KERN_WARNING "cmsfs_lookup: out of memory.\n"); + return NULL; + } + + /* find the file */ + j = di->cmssuper->fstct; + /* list the files */ + for (i = k = 0; i < di->cmssuper->files; i++) { + char *pp; + if (j >= di->cmssuper->fstct) { + (void) cmsfsrd2(di->cmssuper->cmsrooti, buff, k); + k += 1; /* increment block counter */ + j = 0; /* reset intermediate item counter */ + } + pp = &buff[j * di->cmssuper->fstsz]; + /* compare */ + rc = strncmp(pp, umatch, 16); + if (rc == 0) { /* found it?? */ + /* map the inode for the file */ + rc = cmsfs_map_FST(cmsinode, + (struct CMSFSFST *) pp); + if (rc != 0) { + printk(KERN_WARNING "cmsfs_lookup(): cannot map CMS inode (FST).\n"); + goto out; + } + cmsinode->index = i; /* the number of this inode */ + di->cmssuper->inuse += 1; /* another inode for super */ + cmsinode->flags = 0x0000; /* CALLER MUST APPLY */ + free_page((unsigned long)buff); + return cmsinode; /* return "success" */ + } + j += 1; /* increment intermediate item counter */ + } + di->cmssuper->error = di->cmssuper->cmsrooti->error = ENOENT; +out: + kfree(cmsinode); + di->cmssuper->inuse -= 1; + free_page((unsigned long)buff); + return NULL; +} + +/* ---------------------------------------------------------- CMSFS_READ + * Read a record at the current pointer in the CMS file. + * Simple: read the record, increment the record counter. + */ + +static ssize_t cmsfs_read(struct cms_inode * cmsfil, void *recbuf, size_t reclen) +{ + int i, l, rc; + char *bufi, *bufo; + + /* sanity check: file pointer must non-NULL */ + if (cmsfil == NULL) + BUG(); + /* sanity check: superblock pointer must non-NULL */ + if (cmsfil->cmssuper == NULL) + BUG(); + + /* can't read past end of file */ + if (cmsfil->rdpnt >= cmsfil->items) + return 0; /* zero means EOF */ + + /* possibly allocate a work buffer */ + if (cmsfil->rdbuf == NULL) + { + cmsfil->rdbuf = kmalloc(cmsfil->cmssuper->blksz, GFP_KERNEL); + if (cmsfil->rdbuf == NULL) { + printk(KERN_WARNING "cmsfs_read(): unable to allocate a work buffer.\n"); + return -ENOMEM; + } +#ifdef CMSFS_DEBUG + (void) sprintf(cmsfs_ermsg, + "cmsfs_read(): '%s' blk %d rec %d (#1)", + cmsfil->name, cmsfil->rdblk, cmsfil->rdpnt); + cmsfs_error(cmsfs_ermsg); +#endif + + /* now load-up a block into this new buffer */ + rc = cmsfsrd2(cmsfil, cmsfil->rdbuf, cmsfil->rdblk); + if (rc != cmsfil->cmssuper->blksz) { + printk(KERN_WARNING "cmsfs_read(): could not read block.\n"); + return -EIO; + } + cmsfil->rdblk += 1; + cmsfil->rdoff = 0; + } + + /* dereference VOID buffers to CHAR buffers */ + bufi = cmsfil->rdbuf; + bufo = recbuf; + + /* how big is this record? */ + switch (cmsfil->recfm[0]) { + case 'F': + l = cmsfil->lrecl; + break; + case 'V': + if (cmsfil->rdoff >= cmsfil->cmssuper->blksz) { + rc = cmsfsrd2(cmsfil, cmsfil->rdbuf, + cmsfil->rdblk); + if (rc != cmsfil->cmssuper->blksz) { + printk(KERN_ERR "cmsfs_read(): could not read block.\n"); + return -1; + } + cmsfil->rdblk += 1; + cmsfil->rdoff = 0; + } + l = bufi[cmsfil->rdoff++] & 0xFF; + if (cmsfil->rdoff >= cmsfil->cmssuper->blksz) { + rc = cmsfsrd2(cmsfil, cmsfil->rdbuf, + cmsfil->rdblk); + if (rc != cmsfil->cmssuper->blksz) { + printk(KERN_WARNING "cmsfs_read(): could not read block.\n"); + return -EIO; + } + cmsfil->rdblk += 1; + cmsfil->rdoff = 0; + } + l = (l * 256) + (bufi[cmsfil->rdoff++] & 0xFF); + break; + default: /* Bzzzttt!!! */ + printk(KERN_WARNING "cmsfs_read(): RECFM not 'F' or 'V'.\n"); + return -EOPNOTSUPP; + } + + if (l > reclen) { + printk(KERN_WARNING "cmsfs_read(): record (%d) is longer than buffer (%d).\n", l, reclen); + return -EMSGSIZE; + } + + /* copy bytes from work buffer to caller's buffer */ + for (i = 0; i < l; i++) { + if (cmsfil->rdoff >= cmsfil->cmssuper->blksz) { + rc = cmsfsrd2(cmsfil, cmsfil->rdbuf, + cmsfil->rdblk); + if (rc != cmsfil->cmssuper->blksz) { + printk(KERN_WARNING "cmsfs_read(): could not read block.\n"); + return -EIO; + } + cmsfil->rdblk += 1; + cmsfil->rdoff = 0; + } + bufo[i] = bufi[cmsfil->rdoff++]; + } + + /* terminate the record (with NULL and possibly also NL) */ + bufo[i] = 0x00; + if (cmsfil->flags & CMSFSTXT) { + stretoa(bufo); + bufo[i++] = '\n'; + bufo[i] = 0x00; + } + + cmsfil->rdpnt += 1; /* increment record pointer */ + + return i; /* return length of string copied */ +} + +/* --------------------------------------------------------- CMSFS_BYTES + * Return the size-in-bytes of a CMS file and stamp it in the struct. + */ +static long cmsfs_bytes(struct cms_inode *fi) +{ + int i, j, k, l; + + /* quick return if this function has been called before */ + if (fi->bytes != 0) + return fi->bytes; + + /* if there are no records, then there ain't no bytes */ + if (fi->items == 0) + return fi->bytes = 0; + + /* in case conversion is not already known, do this */ + if (fi->flags == 0x0000) + cmsfs_map_EXT(fi); + + /* how big is this file? "it depends" */ + switch (fi->recfm[0]) { + case 'F': /* for fixed-length, total size is easy */ + fi->bytes = fi->lrecl * fi->items; + /* for text files, add NL to each record */ + if (fi->flags & CMSFSTXT) + fi->bytes += fi->items; + break; + + case 'V': /* for variable-length, we must read content */ + l = fi->lrecl + 2; + /* allocated a work buffer of LRECL size (plus two) */ + if (fi->rdbuf2 == NULL) + fi->rdbuf2 = kmalloc(l, GFP_KERNEL); + if (fi->rdbuf2 == NULL) { + printk(KERN_WARNING "cmsfs_lookup(): cannot allocate CMS inode.\n"); + return -1; + } + k = 0; /* byte total starts at zero */ + fi->rdpnt = 0; /* record counter starts at zero */ + /* read every record, totalling up the bytes */ + for (i = 0; i < fi->items; i++) { + j = cmsfs_read(fi, fi->rdbuf2, l); + if (j < 0) + return j; + k = k + j; + } + fi->bytes = k; + break; + + default: + fi->error = EIO; /* internal error */ + return 0; + } + + return fi->bytes; +} + + +/* ----------------------------------------------------- CMSFS_FILE_READ + * CMS FS "read" function for VFS file. + * We prefer to work with inodes, so extract the inode + * from the file pointer, formally file->f_dentry->d_inode. + */ + +static ssize_t cmsfs_file_read(struct file * file, + char * buffer, size_t length, loff_t * offset) +{ + struct cms_inode * ci; + int rc; + + /* dereference CMS inode pointer */ + ci = file->f_dentry->d_inode->u.generic_ip; + if (ci->vfsinode != file->f_dentry->d_inode) + BUG(); + + /* if translation hasn't been determined, figure it out */ + cmsfs_map_EXT(ci); + /* default to text files for the time being */ + if (ci->flags == 0x0000) + ci->flags = CMSFSTXT; + + /* allocate a record buffer, if needed */ + if (ci->rdbuf2 == NULL) + ci->rdbuf2 = kmalloc(ci->lrecl+2, GFP_KERNEL); + if (ci->rdbuf2 == NULL) + { + printk(KERN_WARNING "cmsfs_file_read(): cannot allocate record buffer.\n"); + return -1; + } + + /* try reading the file */ + rc = cmsfs_read(ci,ci->rdbuf2,length); +#ifdef CMSFS_DEBUG + printk(KERN_DEBUG "cmsfs_file_read(): cmsfs_read() returned %d %d.\n",rc,length); +#endif + if (rc < 0) + return rc; + + /* copy from kernel storage to user storage */ + if (rc > 0) + (void) copy_to_user(buffer,ci->rdbuf2,rc); + + /* update file pointers */ + *offset = *offset + rc; + return rc; /* report how many bytes were read */ +} + +/* -------------------------------------------------- CMSFS_FILE_READDIR + * CMS FS "readdir" function for VFS directory. + * It took me a long time to figure out to code the right datatype + * for the fourth argument to filldir(). [sigh] + */ + +static int cmsfs_file_readdir(struct file * file, + void * dirent, filldir_t myfd) +{ + struct cms_inode *dirinode, *tmpinode; + int rc, i, j, k; + unsigned char *cmsfsflb; + if (file->f_pos != 0) + return 0; + + tmpinode = kmalloc(sizeof(struct cms_inode), GFP_KERNEL); + /* Not a good way to gracefully handle failure here, just give up */ + if(tmpinode==NULL) + return 0; + + cmsfsflb = (void *)get_free_page(GFP_KERNEL); + + dirinode = file->f_dentry->d_inode->u.generic_ip; + dirinode->rdpnt = 0; + file->f_pos = dirinode->rdpnt * dirinode->lrecl; + + rc = myfd(dirent,".",1,file->f_pos,0, DT_DIR); + + dirinode->rdpnt += 1; + file->f_pos = dirinode->rdpnt * dirinode->lrecl; + + rc = myfd(dirent,".",1,file->f_pos,0, DT_DIR); + + dirinode->rdpnt += 1; + file->f_pos = dirinode->rdpnt * dirinode->lrecl; + + /* prime the loop with the first block of the directory */ + j = 128; k = 0; + rc = cmsfsrd2(dirinode,cmsfsflb,k); + + /* skipping .DIRECTOR and .ALLOCMAP, fill VFS dir with files */ + for (i = 2 ; i < dirinode->items ; i++) + { + (void) cmsfs_map_FST(tmpinode, (struct CMSFSFST *)&cmsfsflb[j]); + /* No subdirs so all files are regular */ + rc = myfd(dirent,tmpinode->name, strlen(tmpinode->name),file->f_pos,i, DT_REG); + + /* if the filldir() call failed, get outta here */ + if (rc != 0) break; + + j += 64; + + if (j >= dirinode->cmssuper->blksz) + { + k++; + rc = cmsfsrd2(dirinode,cmsfsflb,k); + j = 0; + } + + dirinode->rdpnt += 1; + file->f_pos = dirinode->rdpnt * dirinode->lrecl; + } + + kfree(tmpinode); + free_page((unsigned long)cmsfsflb); + return 0; +} + +/* ----------------------------------------------------- CMSFS_FILE_OPEN + * CMS FS "open" function for VFS file. + * This is just a check in this implementation. + */ + +static ssize_t cmsfs_file_open(struct inode * in, struct file * file) +{ + struct cms_inode * ci; + + /* dereference CMS inode pointer and check cross-link */ + ci = in->u.generic_ip; + if (ci == NULL) + BUG(); + if (ci->vfsinode != in) + BUG(); + + /* reset CMS and VFS pointers */ + ci->rdpnt = ci->rdblk = ci->rdoff = 0; + file->f_pos = 0; + + return 0; +} + +/* ------------------------------------------------------------------ */ +static struct file_operations cmsfs_file_operations = { + read: cmsfs_file_read, + readdir: cmsfs_file_readdir, + open: cmsfs_file_open, +}; + +/* -------------------------------------------------- CMSFS_INODE_LOOKUP + * Search for the file in the CMS directory. + * Calls: cmsfs_lookup() to find the file, + * iget() to get a VFS inode for the file, if found, + * d_add() to add that inode to the VFS directory. + */ +static struct dentry *cmsfs_inode_lookup(struct inode * in, struct dentry *de) +{ + struct cms_inode * cmsinode; + struct inode * inode; + int n; + + /* + * On CMS minidisks, the directory entries (FST) serve as inodes. + * Here we allocate one in doing the search, and then free it. + * Not elegant, but works, and interfaces properly with VFS. + */ + + cmsinode = cmsfs_lookup((struct cms_inode *) in->u.generic_ip, + (unsigned char *) de->d_name.name); + if (cmsinode == NULL) + return NULL; + + /* it would be nice to be able to hand-off the CMS inode struct * + * rather than going through another allocation from iget(). */ + + n = cmsinode->index; + cmsinode->cmssuper->inuse -= 1; + kfree(cmsinode); + + /* iget() will allocate a VFS inode. * + * it will also call cmsfs_read_inode(), * + * thus re-allocating the CMS inode struct. */ + inode = iget(in->i_sb,n); + if (inode == NULL) + return NULL; + + d_add(de,inode); + return NULL; +} + +/* ------------------------------------------------------------------ */ + +static struct inode_operations cmsfs_inode_operations = { + lookup: cmsfs_inode_lookup, +}; + +/* ---------------------------------------------------- CMSFS_READ_INODE + * CMS FS inode numbers are base-zero index into the CMS directory. + * CMS FS (EDF) is flat, no sub-directories, so there is only + * one such directory into which we index, always the "root". + * If the inode we are reading is zero, we mark it as the directory. + * The CMS superblock struct must have already been allocated, + * although CMS inode structs will usually be allocated here. + */ + +static void cmsfs_read_inode(struct inode * in) +{ + struct cms_inode *cmsinode = NULL; + struct cms_super *cmssuper; + int rc, ct = 0; + + /* dummy values in case any of this fails */ + in->i_uid = 0; in->i_gid = 0; + in->i_mode = 0; in->i_nlink = 0; in->i_size = 0; + in->i_atime = in->i_mtime = in->i_ctime = 0; + in->i_blksize = 0; + + /* dereference pointer to CMS superblock from VFS superblock */ + cmssuper = (struct cms_super *) in->i_sb->u.generic_sbp; + /* and check it ... */ + if (cmssuper == NULL) + BUG(); + if (cmssuper->vfssuper != in->i_sb) + BUG(); + + /* allocate a CMS inode struct */ + if (in->u.generic_ip == NULL) + { + if (in->i_ino == 0 && cmssuper->cmsrooti != NULL) + { + cmsinode = cmssuper->cmsrooti; + /* and check it */ + if (cmsinode->cmssuper != cmssuper) + BUG(); + ct = 0; + } + else + { + cmsinode = kmalloc(sizeof(struct cms_inode), GFP_KERNEL); + if (cmsinode != NULL) + cmsinode->cmssuper = NULL; + ct = 1; + } + } + if (cmsinode == NULL) + { + printk(KERN_WARNING "cmsfs_read_inode(): error allocating CMS inode structure.\n"); + return; + } + + /* cross-link CMS and VFS inode structures */ + cmsinode->vfsinode = in; + in->u.generic_ip = cmsinode; + + /* Non-NULL CMS superblock pointer implies that we have * + * already mapped the CMS inode. A CMS superblock is * + * required for the cmsfs_map_FST() call to work. */ + + if (cmsinode->cmssuper == NULL) + { + unsigned char *cmsfsflb; + cmsfsflb = (void *)get_free_page(GFP_KERNEL); + cmsinode->cmssuper = cmssuper; + /* read the CMS "inode" (FST entry) indexed by in->i_ino , * + * map it to the newly allocated CMS inode struct, * + * and copy relevent content to the supplied VFS inode struct */ + /* RECHECK THIS LOGIC for block calc against different blocksizes */ + + rc = cmsfsrd2(cmssuper->cmsrooti,cmsfsflb, + ((in->i_ino)*64)/(in->i_sb->s_blocksize)); + (void) cmsfs_map_FST(cmsinode,(struct CMSFSFST *) + &cmsfsflb[(in->i_ino%(in->i_sb->s_blocksize/64))*64]); + + free_page((unsigned long)cmsfsflb); + } + + /* copy from CMS to VFS */ + in->i_uid = 0; in->i_gid = 0; + in->i_mode = S_IRUGO; /* set "r--r--r--" perms */ + in->i_nlink = 1; + in->i_op = &cmsfs_inode_operations; + in->i_fop = &cmsfs_file_operations; + + /* how big is this file? */ + in->i_size = cmsfs_bytes(cmsinode); + + /* CMS files have only one time stamp */ + in->i_atime = in->i_mtime = in->i_ctime = cmsinode->ctime; + + /* CMS file blocksize is by definition filesystem blocksize */ + in->i_blksize = cmsinode->cmssuper->blksz; + + /* may not be accurate for total */ + in->i_blocks = cmsinode->bloks; + + in->i_attr_flags = 0; + in->i_state = 0; + in->i_flags = 0; + in->i_generation = 0; + atomic_set(&in->i_writecount, 0); + + /* now point to our custom inode_operations struct */ + in->i_op = &cmsfs_inode_operations; + /* CMS FS uses the same i_op struct for files and the directory */ + + /* is this a directory?? */ + if (in->i_ino == 0) + { + in->i_mode |= S_IFDIR; /* mark it as a directory */ + /* CMS directory was created when the filesystem was made */ + in->i_ctime = cmssuper->ctime; + in->i_nlink += 1; + in->i_mode |= S_IXUGO; /* add "--x--x--x" perms */ + } + /* we know that inode zero is the CMS directory */ + else + in->i_mode |= S_IFREG; /* mark it as a regular file */ + + /* increment the "in use" counter */ + cmssuper->inuse += ct; + return; +} + +/* --------------------------------------------------- CMSFS_CLEAR_SUPER + * Clears the cross-links and frees the CMS superblock struct. + * Cannot lock/unlock the superblock at this stage of the game. + */ + +static void cmsfs_clear_super(struct super_block * sb) +{ + struct cms_super *cmssuper; + + /* dereference the CMS superblock pointer and check */ + cmssuper = sb->u.generic_sbp; + /* if we've already been here, then silently return */ + if (cmssuper == NULL) + return; + + /* sanity check, cross-reference CMS and VFS superblocks */ + if (cmssuper->vfssuper != sb) + BUG(); + + /* if superblock is still busy, then bail */ + if (cmssuper->inuse != 0) + { + printk(KERN_WARNING "cmsfs_clear_super(): CMS superblock at %p is busy.\n", cmssuper); + return; + } + + /* free the cms_super struct and mark it freed */ + cmssuper->vfssuper = NULL; + kfree(cmssuper); /* deref'd from sb->u.generic_sbp */ + sb->u.generic_sbp = NULL; + + /* one less instance of this driver */ + MOD_DEC_USE_COUNT; + /* don't do this until all storage is freed */ + + return; +} + +/* --------------------------------------------------- CMSFS_CLEAR_INODE + * Cleanly deallocate the CMS inode linked to this VFS inode. + * Because of the order in which VFS objects are released + * at umount() time, this function must clear the CMS superblock + * if the inode being cleared is the directory. + */ +static void cmsfs_clear_inode(struct inode * in) +{ + struct cms_inode * ck; + struct cms_super * cs; + struct super_block * sb; + + /* dereference the generic pointer to a CMS struct */ + ck = in->u.generic_ip; + + /* if no CMS inode to free, then silently return */ + if (ck == NULL) + return; + + /* if ->vfsinode doesn't point back to VFS inode, then error */ + if (ck->vfsinode != in) + BUG(); + + /* dereference VFS and CMS superblock pointers for shorthand */ + sb = in->i_sb; cs = ck->cmssuper; + + /* sanity check those, expecting them to be cross-linked */ + if (sb->u.generic_sbp != cs) + BUG(); + if (cs->vfssuper != sb) + BUG(); + + /* decrement the "in use" counter */ + cs->inuse -= 1; + + if (ck->rdbuf != NULL) + { + kfree(ck->rdbuf); + ck->rdbuf = NULL; + ck->rdoff = 0; + } + + if (ck->rdbuf2 != NULL) + { + kfree(ck->rdbuf2); + ck->rdbuf2 = NULL; + ck->rdoff2 = 0; + } + + /* reset some values to clean-up the storage */ + ck->vfsinode = NULL; + ck->cmssuper = NULL; + /* now free the storage */ + kfree(ck); + /* and clear the VFS ref to CMS */ + in->u.generic_ip = NULL; + + /* was that the root (CMS dir) inode? */ + if (ck != cs->cmsrooti) + return; + /* if it wasn't root, then we're done */ + + /* should be safe to free the CMS superblock (ref'd by VFS) */ + cmsfs_clear_super(sb); + + return; +} + +/* -------------------------------------------------------- CMSFS_UMOUNT + * This is called technically to "begin umount". + * Ordinarily a no-op because CMS FS is read-only. + * Cannot be used as the code path to free the superblock + * because of the order in which VFS comes down when unmounting. + + CLEAN THIS UP!!! Remove lock() unlock() + + */ + +static void cmsfs_umount(struct super_block * sb) +{ + struct cms_super *cmssuper; + + /* dereference the CMS superblock pointer and check */ + cmssuper = sb->u.generic_sbp; + /* if we've already been here, then silently return */ + if (cmssuper == NULL) + return; + + /* sanity check, cross-reference CMS and VFS superblocks */ + if (cmssuper->vfssuper != sb) + BUG(); + /* if superblock is still busy, then bail */ + if (cmssuper->inuse != 0) + { + printk(KERN_WARNING "cmsfs_umount(): CMS superblock at %p is busy.\n", cmssuper); + return; + } + + /* + * VFS doesn't free inodes and superblock in the order I expected. + * It calls cmsfs_put_super() first, and then clears inodes. + * The last inode cleared is root, which is as expected. + * But when should the superblock be cleared and freed? + * + * Since VFS will do a cmsfs_clear_inode() for the directory, + * DO NOT call it here, and DO NOT clear the CMS dir inode here. + */ + + /* if we still have a CMS dir inode, go ahead and sanity check */ + if (cmssuper->cmsrooti != NULL) + { + struct inode * in; + in = cmssuper->cmsrooti->vfsinode; + if (in->u.generic_ip != cmssuper->cmsrooti) + BUG(); + } + + /* free the cms_super struct and mark it freed */ + lock_super(sb); + cmssuper->vfssuper = NULL; + kfree(cmssuper); /* deref'd from sb->u.generic_sbp */ + sb->u.generic_sbp = NULL; + unlock_super(sb); + + /* one less instance of this driver */ + MOD_DEC_USE_COUNT; + /* don't do this until all storage is freed */ + + return; +} + +/* ----------------------------------------------------- CMSFS_PUT_SUPER + * Ordinarily a no-op because CMS FS is read-only. + * Cannot be used as the code path to free the superblock + * because of the order in which VFS comes down when unmounting. + */ + +static void cmsfs_put_super(struct super_block * sb) +{ + return; +} + +/* -------------------------------------------------------- CMSFS_STATFS + * Arguments: superblock, user-space statfs, length + * Returns zero for success, non-zero otherwise (typically -EFAULT). + */ + +static int cmsfs_statfs(struct super_block * sb,struct statfs *st) +{ + struct cms_super *cmssuper; + + /* what if superblock pointer is NULL? */ + if (sb == NULL) + BUG(); + + /* dereference CMS superblock for short-hand below */ + cmssuper = (struct cms_super *) sb->u.generic_sbp; + + /* what if CMS superblock pointer is NULL? */ + if (cmssuper == NULL) + BUG(); + + /* as always, sanity check the cross-link */ + if (cmssuper->vfssuper != sb) + BUG(); + + /* take data from CMS superblock */ + st->f_bsize = cmssuper->blksz; + st->f_blocks = cmssuper->blocks; + st->f_bfree = cmssuper->bkfree; + st->f_bavail = cmssuper->bkfree; + st->f_files = cmssuper->files; + /* st=?f_ffree = cmssuper->ffree; */ + st->f_ffree = 0; /* no files available on R/O media */ + return 0; +} + +/* ------------------------------------------------------- CMSFS_REMOUNT + * Remount a cms minidisk. If the flush seems odd remember you have multiple + * OS's running here and IBM people use minidisks rather like floppies + */ + +static int cmsfs_remount(struct super_block * sb,int *flags,char *data) +{ + /* Might be a convenient way to report FYI data on a CMS volume */ + /* XXX when we are writable we may need to sync data blocks too */ + invalidate_buffers(sb->s_dev); + return 0; +} + +/* ------------------------------------------------------------------ */ + +static struct super_operations cmsfs_super_operations = { + read_inode: cmsfs_read_inode, + put_super:cmsfs_put_super, + statfs: cmsfs_statfs, + remount_fs: cmsfs_remount, + clear_inode: cmsfs_clear_inode, + umount_begin: cmsfs_umount +}; + +/* --------------------------------------------------------- CMSFS_MOUNT + */ + +static struct super_block *cmsfs_mount(struct super_block * sb, void * data, int silent) +{ + struct cms_super *cmssuper; + int rc; + struct inode *vfsrooti; + + /* let the kernel know we're busy ... for the moment */ + MOD_INC_USE_COUNT; + lock_super(sb); + + /* -------------------------------------------------------------- * + * Fill-out the VFS superblock and allocate a CMS superblock. * + * -------------------------------------------------------------- */ + + cmssuper = kmalloc(sizeof(struct cms_super), GFP_KERNEL); + if (cmssuper == NULL) + { + printk(KERN_WARNING "cannot allocate CMS superblock.\n"); + sb->s_dev = 0; /* why? */ + unlock_super(sb); + MOD_DEC_USE_COUNT; + return NULL; + } + + /* cross-reference CMS superblock and VFS superblock */ + sb->u.generic_sbp = cmssuper; /* VFS to ref CMS */ + cmssuper->vfssuper = sb; /* CMS to ref VFS */ + + /* root inode not there yet */ + cmssuper->cmsrooti = NULL; + /* cmsfs_map_ADT() will see the NULL and give us one */ + + /* determine device blocksize */ + cmssuper->pbksz = get_hardblocksize(sb->s_dev); + /* This may be redundant. */ + set_blocksize(sb->s_dev,cmssuper->pbksz); + /* Got the following suggestion from Alan Cox. */ + sb->s_blocksize_bits = 12; /* probably should switch() */ + + /* + * Is there a generic VFS super_operations struct? + * Because this is not cleared before we get called. + * So we're overwriting something ... what? + */ + + sb->s_op = &cmsfs_super_operations; + + /* possibly correct the VFS superblock blocksize value */ + if (sb->s_blocksize != cmssuper->pbksz) + { + /* set filesystem blocksize to device blocksize */ + sb->s_blocksize = get_hardblocksize(sb->s_dev); + } + + /* -------------------------------------------------------------- * + * Map the CMS volume (ADT) to CMS superblock. * + * -------------------------------------------------------------- */ + + rc = cmsfs_map_ADT(cmssuper); + if (rc != 0) + { + printk(KERN_WARNING "cmsfs_mount(): cmsfs_map_ADT() returned %d.\n",rc); + kfree(cmssuper); + sb->s_dev = 0; /* why? */ + unlock_super(sb); + MOD_DEC_USE_COUNT; + return NULL; + } + + /* -------------------------------------------------------------- * + * Check CMS directory inode allocated in the previous section. * + * -------------------------------------------------------------- */ + if (cmssuper->cmsrooti == NULL) + { + printk(KERN_ERR "cmsfs_mount(): did not allocate CMS dir inode.\n"); + kfree(cmssuper); /* cmssuper == sb->u.generic_sbp */ + sb->u.generic_sbp = NULL; + sb->s_dev = 0; /* why? */ + unlock_super(sb); + MOD_DEC_USE_COUNT; + return NULL; + } + + if (cmssuper->cmsrooti->cmssuper != cmssuper) + BUG(); + + /* -------------------------------------------------------------- * + * Allocate and flesh-out a VFS inode for the directory. * + * This will be called "root" for this filesystem, * + * even though there will be no other directories. * + * This will be inode zero, and is always the first FST. * + * -------------------------------------------------------------- */ + + vfsrooti = iget(sb,0); + if (vfsrooti == NULL) + { + printk(KERN_ERR "cmsfs_mount(): cannot get directory (root) inode.\n"); + kfree(cmssuper); /* cmssuper == sb->u.generic_sbp */ + sb->u.generic_sbp = NULL; + sb->s_dev = 0; /* why? */ + unlock_super(sb); + MOD_DEC_USE_COUNT; + return NULL; + } + + /* + * Sanity check against iget()'s work: it should have called + * cmsfs_read_inode(), which in turn should have cross-linked + * the CMS and VFS inode structs and marked "inode zero" as root. + */ + + if (cmssuper->cmsrooti->vfsinode != vfsrooti) + BUG(); + if (vfsrooti->u.generic_ip != cmssuper->cmsrooti) + BUG(); + + /* -------------------------------------------------------------- * + * Allocate and flesh-out a directory entry (VFS dnode). * + * -------------------------------------------------------------- */ + + sb->s_root = d_alloc_root(cmssuper->cmsrooti->vfsinode); + if (sb->s_root == NULL) + { + printk(KERN_ERR "cmsfs_mount(): cannot allocate VFS directory structure.\n"); + kfree(cmssuper->cmsrooti->vfsinode); + kfree(cmssuper->cmsrooti); + cmssuper->cmsrooti = NULL; + kfree(cmssuper); /* cmssuper == sb->u.generic_sbp */ + sb->u.generic_sbp = NULL; + sb->s_dev = 0; /* why? */ + unlock_super(sb); + MOD_DEC_USE_COUNT; + return NULL; + } + + /* CMS FS mounts are always read-only to Linux */ + sb->s_flags |= MS_RDONLY; + sb->s_maxbytes = MAX_NON_LFS; + + unlock_super(sb); + return sb; +} + +/* ------------------------------------------------------------------ */ + +static struct file_system_type cms_fs_type = { + "cms" , + FS_REQUIRES_DEV , + cmsfs_mount , + NULL +} ; + +/* ---------------------------------------------------------- CMSFS_INIT + * filesystem init, especially useful for module init + */ + +static int cmsfs_init(void) +{ + printk(KERN_INFO "%s %s\n",CMSFS_DESCRIPTION,CMSFS_VERSION); + return register_filesystem(&cms_fs_type); +} + +/* ------------------------------------------------------- CMSFS_CLEANUP + * filesystem cleanup & shut down for module extraction + */ + +static void cmsfs_cleanup(void) +{ + unregister_filesystem(&cms_fs_type); + return; +} + + +/* -------------------------------------------------------- CMSFS_MODULE + * additional routines required when CMS FS is built as a module + */ + +MODULE_AUTHOR(CMSFS_AUTHOR); +MODULE_DESCRIPTION(CMSFS_DESCRIPTION); +EXPORT_NO_SYMBOLS; + +module_init(cmsfs_init); +module_exit(cmsfs_cleanup); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/coda/dir.c linux.ac/fs/coda/dir.c --- linux.vanilla/fs/coda/dir.c Fri Dec 29 22:07:57 2000 +++ linux.ac/fs/coda/dir.c Tue Apr 10 18:19:16 2001 @@ -92,7 +92,7 @@ /* inode operations for directories */ -/* acces routines: lookup, readlink, permission */ +/* access routines: lookup, readlink, permission */ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry) { struct inode *res_inode = NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/coda/psdev.c linux.ac/fs/coda/psdev.c --- linux.vanilla/fs/coda/psdev.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/coda/psdev.c Tue Apr 10 18:19:16 2001 @@ -195,7 +195,7 @@ goto out; } - /* adjust outsize. is this usefull ?? */ + /* adjust outsize. is this useful ?? */ req->uc_outSize = nbytes; req->uc_flags |= REQ_WRITE; count = nbytes; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/cramfs/inode.c linux.ac/fs/cramfs/inode.c --- linux.vanilla/fs/cramfs/inode.c Tue Apr 3 17:32:25 2001 +++ linux.ac/fs/cramfs/inode.c Tue Apr 3 17:55:10 2001 @@ -138,7 +138,7 @@ struct buffer_head * bh = bh_array[i]; if (bh) { memcpy(data, bh->b_data, PAGE_CACHE_SIZE); - bforget(bh); + brelse(bh); } else memset(data, 0, PAGE_CACHE_SIZE); data += PAGE_CACHE_SIZE; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/dcache.c linux.ac/fs/dcache.c --- linux.vanilla/fs/dcache.c Tue Apr 3 17:32:25 2001 +++ linux.ac/fs/dcache.c Sun Apr 15 23:05:19 2001 @@ -337,10 +337,9 @@ dentry = list_entry(tmp, struct dentry, d_lru); /* If the dentry was recently referenced, don't free it. */ - if (dentry->d_flags & DCACHE_REFERENCED) { - dentry->d_flags &= ~DCACHE_REFERENCED; + if (test_and_clear_bit(D_Referenced, &dentry->d_flags)) { list_add(&dentry->d_lru, &dentry_unused); - goto next; + continue; } dentry_stat.nr_unused--; @@ -349,7 +348,6 @@ BUG(); prune_one_dentry(dentry); - next: if (!--count) break; } @@ -734,7 +732,7 @@ continue; } __dget_locked(dentry); - dentry->d_flags |= DCACHE_REFERENCED; + set_bit(D_Referenced, &dentry->d_flags); spin_unlock(&dcache_lock); return dentry; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/devfs/base.c linux.ac/fs/devfs/base.c --- linux.vanilla/fs/devfs/base.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/devfs/base.c Tue Apr 3 17:55:10 2001 @@ -2343,7 +2343,8 @@ if (de == NULL) return -ENODEV; retval = inode_change_ok (inode, iattr); if (retval != 0) return retval; - inode_setattr (inode, iattr); + retval = inode_setattr (inode, iattr); + if (retval != 0) return retval; if ( iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID) ) devfsd_notify_one (de, DEVFSD_NOTIFY_CHANGE, inode->i_mode, inode->i_uid, inode->i_gid, fs_info); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/dquot.c linux.ac/fs/dquot.c --- linux.vanilla/fs/dquot.c Sat Feb 17 00:06:17 2001 +++ linux.ac/fs/dquot.c Tue Apr 3 17:55:11 2001 @@ -26,7 +26,7 @@ * dquot_incr_...() to calling functions. * invalidate_dquots() now writes modified dquots. * Serialized quota_off() and quota_on() for mount point. - * Fixed a few bugs in grow_dquots. + * Fixed a few bugs in grow_dquots(). * Fixed deadlock in write_dquot() - we no longer account quotas on * quota files * remove_dquot_ref() moved to inode.c - it now traverses through inodes @@ -34,36 +34,48 @@ * Added check for bogus uid and fixed check for group in quotactl. * Jan Kara, <jack@suse.cz>, sponsored by SuSE CR, 10-11/99 * + * Used struct list_head instead of own list struct + * Invalidation of dquots with dq_count > 0 no longer possible + * Improved free_dquots list management + * Quota and i_blocks are now updated in one place to avoid races + * Warnings are now delayed so we won't block in critical section + * Write updated not to require dquot lock + * Jan Kara, <jack@suse.cz>, 9/2000 + * + * New quotafile format + * Alocation units changed to bytes + * Jan Kara, <jack@suse.cz>, 2000 + * * (C) Copyright 1994 - 1997 Marco van Wieringen */ #include <linux/errno.h> #include <linux/kernel.h> +#include <linux/fs.h> #include <linux/sched.h> - #include <linux/types.h> #include <linux/string.h> #include <linux/fcntl.h> #include <linux/stat.h> #include <linux/tty.h> #include <linux/file.h> -#include <linux/slab.h> -#include <linux/mount.h> -#include <linux/smp.h> #include <linux/smp_lock.h> #include <linux/init.h> +#include <linux/slab.h> #include <asm/uaccess.h> +#include <asm/byteorder.h> -#define __DQUOT_VERSION__ "dquot_6.4.0" +#define __DQUOT_VERSION__ "dquot_6.5.0" +#define __DQUOT_PARANOIA int nr_dquots, nr_free_dquots; -int max_dquots = NR_DQUOTS; -static char quotamessage[MAX_QUOTA_MESSAGE]; -static char *quotatypes[] = INITQFNAMES; +static const char *quotatypes[] = INITQFNAMES; +static const uint quota_magics[] = INITQMAGICS; +static const uint quota_versions[] = INITQVERSIONS; -static inline struct quota_mount_options *sb_dqopt(struct super_block *sb) +static inline struct quota_info *sb_dqopt(struct super_block *sb) { return &sb->s_dquot; } @@ -74,33 +86,36 @@ * free_dquots, and dquot_hash[] array. A single dquot structure may be * on all three lists, depending on its current state. * - * All dquots are placed on the inuse_list when first created, and this + * All dquots are placed to the end of inuse_list when first created, and this * list is used for the sync and invalidate operations, which must look * at every dquot. * * Unused dquots (dq_count == 0) are added to the free_dquots list when * freed, and this list is searched whenever we need an available dquot. * Dquots are removed from the list as soon as they are used again, and - * nr_free_dquots gives the number of dquots on the list. + * nr_free_dquots gives the number of dquots on the list. When dquot is + * invalidated it's completely released from memory. * * Dquots with a specific identity (device, type and id) are placed on * one of the dquot_hash[] hash chains. The provides an efficient search - * mechanism to lcoate a specific dquot. + * mechanism to locate a specific dquot. */ -static struct dquot *inuse_list; +/* + * Note that any operation which operates on dquot data (ie. dq_dqb) mustn't + * block while it's updating/reading it. Otherwise races would occur. + */ + +static LIST_HEAD(inuse_list); static LIST_HEAD(free_dquots); -static struct dquot *dquot_hash[NR_DQHASH]; -static int dquot_updating[NR_DQHASH]; +static struct list_head dquot_hash[NR_DQHASH]; static struct dqstats dqstats; -static DECLARE_WAIT_QUEUE_HEAD(dquot_wait); -static DECLARE_WAIT_QUEUE_HEAD(update_wait); static void dqput(struct dquot *); static struct dquot *dqduplicate(struct dquot *); -static inline char is_enabled(struct quota_mount_options *dqopt, short type) +static inline char is_enabled(struct quota_info *dqopt, short type) { switch (type) { case USRQUOTA: @@ -123,38 +138,27 @@ static inline void insert_dquot_hash(struct dquot *dquot) { - struct dquot **htable; - - htable = &dquot_hash[hashfn(dquot->dq_dev, dquot->dq_id, dquot->dq_type)]; - if ((dquot->dq_hash_next = *htable) != NULL) - (*htable)->dq_hash_pprev = &dquot->dq_hash_next; - *htable = dquot; - dquot->dq_hash_pprev = htable; -} - -static inline void hash_dquot(struct dquot *dquot) -{ - insert_dquot_hash(dquot); + struct list_head *head = dquot_hash + hashfn(dquot->dq_dev, dquot->dq_id, dquot->dq_type); + list_add(&dquot->dq_hash, head); } -static inline void unhash_dquot(struct dquot *dquot) +static inline void remove_dquot_hash(struct dquot *dquot) { - if (dquot->dq_hash_pprev) { - if (dquot->dq_hash_next) - dquot->dq_hash_next->dq_hash_pprev = dquot->dq_hash_pprev; - *(dquot->dq_hash_pprev) = dquot->dq_hash_next; - dquot->dq_hash_pprev = NULL; - } + list_del(&dquot->dq_hash); + INIT_LIST_HEAD(&dquot->dq_hash); } static inline struct dquot *find_dquot(unsigned int hashent, kdev_t dev, unsigned int id, short type) { + struct list_head *head; struct dquot *dquot; - for (dquot = dquot_hash[hashent]; dquot; dquot = dquot->dq_hash_next) + for (head = dquot_hash[hashent].next; head != dquot_hash+hashent; head = head->next) { + dquot = list_entry(head, struct dquot, dq_hash); if (dquot->dq_dev == dev && dquot->dq_id == id && dquot->dq_type == type) - break; - return dquot; + return dquot; + } + return NODQUOT; } /* Add a dquot to the head of the free list */ @@ -171,13 +175,21 @@ nr_free_dquots++; } +/* Move dquot to the head of free list (it must be already on it) */ +static inline void move_dquot_head(struct dquot *dquot) +{ + list_del(&dquot->dq_free); + list_add(&dquot->dq_free, &free_dquots); +} + static inline void remove_free_dquot(struct dquot *dquot) { - /* sanity check */ +#ifdef __DQUOT_PARANOIA if (list_empty(&dquot->dq_free)) { - printk("remove_free_dquot: dquot not on the free list??\n"); + printk(KERN_ERR "remove_free_dquot: dquot not on the free list??\n"); return; /* J.K. Just don't do anything */ } +#endif list_del(&dquot->dq_free); INIT_LIST_HEAD(&dquot->dq_free); nr_free_dquots--; @@ -185,36 +197,30 @@ static inline void put_inuse(struct dquot *dquot) { - if ((dquot->dq_next = inuse_list) != NULL) - inuse_list->dq_pprev = &dquot->dq_next; - inuse_list = dquot; - dquot->dq_pprev = &inuse_list; + /* We add to the back of inuse list so we don't have to restart + * when traversing this list and we block */ + list_add(&dquot->dq_inuse, inuse_list.prev); + nr_dquots++; } -#if 0 /* currently not needed */ static inline void remove_inuse(struct dquot *dquot) { - if (dquot->dq_pprev) { - if (dquot->dq_next) - dquot->dq_next->dq_pprev = dquot->dq_pprev; - *dquot->dq_pprev = dquot->dq_next; - dquot->dq_pprev = NULL; - } + nr_dquots--; + list_del(&dquot->dq_inuse); } -#endif static void __wait_on_dquot(struct dquot *dquot) { DECLARE_WAITQUEUE(wait, current); - add_wait_queue(&dquot->dq_wait, &wait); + add_wait_queue(&dquot->dq_wait_lock, &wait); repeat: set_current_state(TASK_UNINTERRUPTIBLE); if (dquot->dq_flags & DQ_LOCKED) { schedule(); goto repeat; } - remove_wait_queue(&dquot->dq_wait, &wait); + remove_wait_queue(&dquot->dq_wait_lock, &wait); current->state = TASK_RUNNING; } @@ -233,7 +239,394 @@ static inline void unlock_dquot(struct dquot *dquot) { dquot->dq_flags &= ~DQ_LOCKED; - wake_up(&dquot->dq_wait); + wake_up(&dquot->dq_wait_lock); +} + +static void __wait_dquot_unused(struct dquot *dquot) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&dquot->dq_wait_free, &wait); +repeat: + set_current_state(TASK_UNINTERRUPTIBLE); + if (dquot->dq_count) { + schedule(); + goto repeat; + } + remove_wait_queue(&dquot->dq_wait_free, &wait); + current->state = TASK_RUNNING; +} + +/* + * IO operations on file + */ + +#define GETIDINDEX(id, depth) (((id) >> ((DQTREEDEPTH-(depth)-1)*8)) & 0xff) +#define GETENTRIES(buf) ((struct disk_dqblk *)(((char *)buf)+sizeof(struct disk_dqdbheader))) + +static inline void mark_quotafile_info_dirty(struct mem_dqinfo *info) +{ + info->dqi_flags |= DQF_DIRTY; +} + +static inline int quotafile_info_dirty(struct mem_dqinfo *info) +{ + return info->dqi_flags & DQF_DIRTY; +} + +/* Read information header from quota file */ +static int read_quotafile_info(struct super_block *sb, short type) +{ + mm_segment_t fs; + struct disk_dqinfo dinfo; + struct mem_dqinfo *info = sb_dqopt(sb)->info+type; + struct file *f = sb_dqopt(sb)->files[type]; + ssize_t size; + loff_t offset = DQINFOOFF; + + fs = get_fs(); + set_fs(KERNEL_DS); + size = f->f_op->read(f, (char *)&dinfo, sizeof(struct disk_dqinfo), &offset); + set_fs(fs); + if (size != sizeof(struct disk_dqinfo)) { + printk(KERN_WARNING "Can't read info structure on device %s.\n", + kdevname(f->f_dentry->d_sb->s_dev)); + return -1; + } + info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); + info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); + info->dqi_flags = le32_to_cpu(dinfo.dqi_flags); + info->dqi_blocks = le32_to_cpu(dinfo.dqi_blocks); + info->dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk); + info->dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry); + return 0; +} + +/* Write information header to quota file */ +static int write_quotafile_info(struct super_block *sb, short type) +{ + mm_segment_t fs; + struct disk_dqinfo dinfo; + struct mem_dqinfo *info = sb_dqopt(sb)->info+type; + struct file *f = sb_dqopt(sb)->files[type]; + ssize_t size; + loff_t offset = DQINFOOFF; + + info[type].dqi_flags &= ~DQF_DIRTY; + dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace); + dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace); + dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK); + dinfo.dqi_blocks = cpu_to_le32(info->dqi_blocks); + dinfo.dqi_free_blk = cpu_to_le32(info->dqi_free_blk); + dinfo.dqi_free_entry = cpu_to_le32(info->dqi_free_entry); + fs = get_fs(); + set_fs(KERNEL_DS); + size = f->f_op->write(f, (char *)&dinfo, sizeof(struct disk_dqinfo), &offset); + set_fs(fs); + if (size != sizeof(struct disk_dqinfo)) { + printk(KERN_WARNING "Can't write info structure on device %s.\n", + kdevname(f->f_dentry->d_sb->s_dev)); + return -1; + } + return 0; +} + +static void disk2memdqb(struct mem_dqblk *m, struct disk_dqblk *d) +{ + m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit); + m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit); + m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes); + m->dqb_itime = le64_to_cpu(d->dqb_itime); + m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit); + m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit); + m->dqb_curspace = le64_to_cpu(d->dqb_curspace); + m->dqb_btime = le64_to_cpu(d->dqb_btime); +} + +static void mem2diskdqb(struct disk_dqblk *d, struct mem_dqblk *m, qid_t id) +{ + d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit); + d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit); + d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes); + d->dqb_itime = cpu_to_le64(m->dqb_itime); + d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit); + d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit); + d->dqb_curspace = cpu_to_le64(m->dqb_curspace); + d->dqb_btime = cpu_to_le64(m->dqb_btime); + d->dqb_id = cpu_to_le32(id); +} + +static dqbuf_t getdqbuf(void) +{ + dqbuf_t buf = kmalloc(DQBLKSIZE, GFP_KERNEL); + if (!buf) + printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n"); + return buf; +} + +static inline void freedqbuf(dqbuf_t buf) +{ + kfree(buf); +} + +static ssize_t read_blk(struct file *filp, uint blk, dqbuf_t buf) +{ + mm_segment_t fs; + ssize_t ret; + loff_t offset = blk<<DQBLKSIZE_BITS; + + memset(buf, 0, DQBLKSIZE); + fs = get_fs(); + set_fs(KERNEL_DS); + ret = filp->f_op->read(filp, (char *)buf, DQBLKSIZE, &offset); + set_fs(fs); + return ret; +} + +static ssize_t write_blk(struct file *filp, uint blk, dqbuf_t buf) +{ + mm_segment_t fs; + ssize_t ret; + loff_t offset = blk<<DQBLKSIZE_BITS; + + fs = get_fs(); + set_fs(KERNEL_DS); + ret = filp->f_op->write(filp, (char *)buf, DQBLKSIZE, &offset); + set_fs(fs); + return ret; + +} + +/* Remove empty block from list and return it */ +static int get_free_dqblk(struct file *filp, struct mem_dqinfo *info) +{ + dqbuf_t buf = getdqbuf(); + struct disk_dqdbheader *dh = (struct disk_dqdbheader *)buf; + int ret, blk; + + if (!buf) + return -ENOMEM; + if (info->dqi_free_blk) { + blk = info->dqi_free_blk; + if ((ret = read_blk(filp, blk, buf)) < 0) + goto out_buf; + info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free); + } + else { + memset(buf, 0, DQBLKSIZE); + if ((ret = write_blk(filp, info->dqi_blocks, buf)) < 0) /* Assure block allocation... */ + goto out_buf; + blk = info->dqi_blocks++; + } + mark_quotafile_info_dirty(info); + ret = blk; +out_buf: + freedqbuf(buf); + return ret; +} + +/* Insert empty block to the list */ +static int put_free_dqblk(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk) +{ + struct disk_dqdbheader *dh = (struct disk_dqdbheader *)buf; + int err; + + dh->dqdh_next_free = cpu_to_le32(info->dqi_free_blk); + dh->dqdh_prev_free = cpu_to_le32(0); + dh->dqdh_entries = cpu_to_le16(0); + info->dqi_free_blk = blk; + mark_quotafile_info_dirty(info); + if ((err = write_blk(filp, blk, buf)) < 0) /* Some strange block. We had better leave it... */ + return err; + return 0; +} + +/* Remove given block from the list of blocks with free entries */ +static int remove_free_dqentry(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk) +{ + dqbuf_t tmpbuf = getdqbuf(); + struct disk_dqdbheader *dh = (struct disk_dqdbheader *)buf; + uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = le32_to_cpu(dh->dqdh_prev_free); + int err; + + if (!tmpbuf) + return -ENOMEM; + if (nextblk) { + if ((err = read_blk(filp, nextblk, tmpbuf)) < 0) + goto out_buf; + ((struct disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free; + if ((err = write_blk(filp, nextblk, tmpbuf)) < 0) + goto out_buf; + } + if (prevblk) { + if ((err = read_blk(filp, prevblk, tmpbuf)) < 0) + goto out_buf; + ((struct disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free; + if ((err = write_blk(filp, prevblk, tmpbuf)) < 0) + goto out_buf; + } + else { + info->dqi_free_entry = nextblk; + mark_quotafile_info_dirty(info); + } + freedqbuf(tmpbuf); + dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0); + if (write_blk(filp, blk, buf) < 0) /* No matter whether write succeeds block is out of list */ + printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk); + return 0; +out_buf: + freedqbuf(tmpbuf); + return err; +} + +/* Insert given block to the beginning of list with free entries */ +static int insert_free_dqentry(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk) +{ + dqbuf_t tmpbuf = getdqbuf(); + struct disk_dqdbheader *dh = (struct disk_dqdbheader *)buf; + int err; + + if (!tmpbuf) + return -ENOMEM; + dh->dqdh_next_free = cpu_to_le32(info->dqi_free_entry); + dh->dqdh_prev_free = cpu_to_le32(0); + if ((err = write_blk(filp, blk, buf)) < 0) + goto out_buf; + if (info->dqi_free_entry) { + if ((err = read_blk(filp, info->dqi_free_entry, tmpbuf)) < 0) + goto out_buf; + ((struct disk_dqdbheader *)tmpbuf)->dqdh_prev_free = cpu_to_le32(blk); + if ((err = write_blk(filp, info->dqi_free_entry, tmpbuf)) < 0) + goto out_buf; + } + freedqbuf(tmpbuf); + info->dqi_free_entry = blk; + mark_quotafile_info_dirty(info); + return 0; +out_buf: + freedqbuf(tmpbuf); + return err; +} + +/* Find space for dquot */ +static uint find_free_dqentry(struct dquot *dquot, int *err) +{ + struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; + struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info+dquot->dq_type; + uint blk, i; + struct disk_dqdbheader *dh; + struct disk_dqblk *ddquot; + struct disk_dqblk fakedquot; + dqbuf_t buf; + + *err = 0; + if (!(buf = getdqbuf())) { + *err = -ENOMEM; + return 0; + } + dh = (struct disk_dqdbheader *)buf; + ddquot = GETENTRIES(buf); + if (info->dqi_free_entry) { + blk = info->dqi_free_entry; + if ((*err = read_blk(filp, blk, buf)) < 0) + goto out_buf; + } + else { + blk = get_free_dqblk(filp, info); + if ((int)blk < 0) { + *err = blk; + return 0; + } + memset(buf, 0, DQBLKSIZE); + info->dqi_free_entry = blk; /* This is enough as block is already zeroed and entry list is empty... */ + mark_quotafile_info_dirty(info); + } + if (le16_to_cpu(dh->dqdh_entries)+1 >= DQSTRINBLK) /* Block will be full? */ + if ((*err = remove_free_dqentry(filp, info, buf, blk)) < 0) { + printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk); + goto out_buf; + } + dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)+1); + memset(&fakedquot, 0, sizeof(struct disk_dqblk)); + /* Find free structure in block */ + for (i = 0; i < DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct disk_dqblk)); i++); +#ifdef __DQUOT_PARANOIA + if (i == DQSTRINBLK) { + printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n"); + *err = -EIO; + goto out_buf; + } +#endif + if ((*err = write_blk(filp, blk, buf)) < 0) { + printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk); + goto out_buf; + } + dquot->dq_off = (blk<<DQBLKSIZE_BITS)+sizeof(struct disk_dqdbheader)+i*sizeof(struct disk_dqblk); + freedqbuf(buf); + return blk; +out_buf: + freedqbuf(buf); + return 0; +} + +/* Insert reference to structure into the trie */ +static int do_insert_tree(struct dquot *dquot, uint *treeblk, int depth) +{ + struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; + struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type; + dqbuf_t buf; + int ret = 0, newson = 0, newact = 0; + u32 *ref; + uint newblk; + + if (!(buf = getdqbuf())) + return -ENOMEM; + if (!*treeblk) { + ret = get_free_dqblk(filp, info); + if (ret < 0) + goto out_buf; + *treeblk = ret; + memset(buf, 0, DQBLKSIZE); + newact = 1; + } + else { + if ((ret = read_blk(filp, *treeblk, buf)) < 0) { + printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk); + goto out_buf; + } + } + ref = (u32 *)buf; + newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]); + if (!newblk) + newson = 1; + if (depth == DQTREEDEPTH-1) { +#ifdef __DQUOT_PARANOIA + if (newblk) { + printk(KERN_ERR "VFS: Inserting already present quota entry (block %u).\n", ref[GETIDINDEX(dquot->dq_id, depth)]); + ret = -EIO; + goto out_buf; + } +#endif + newblk = find_free_dqentry(dquot, &ret); + } + else + ret = do_insert_tree(dquot, &newblk, depth+1); + if (newson && ret >= 0) { + ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk); + ret = write_blk(filp, *treeblk, buf); + } + else if (newact && ret < 0) + put_free_dqblk(filp, info, buf, *treeblk); +out_buf: + freedqbuf(buf); + return ret; +} + +/* Wrapper for inserting quota structure into tree */ +static inline int dq_insert_tree(struct dquot *dquot) +{ + int tmp = DQTREEOFF; + return do_insert_tree(dquot, &tmp, 0); } /* @@ -246,37 +639,199 @@ mm_segment_t fs; loff_t offset; ssize_t ret; - struct semaphore *sem = &dquot->dq_sb->s_dquot.dqio_sem; + struct semaphore *sem = &sb_dqopt(dquot->dq_sb)->dqio_sem; + struct disk_dqblk ddquot; - lock_dquot(dquot); - if (!dquot->dq_sb) { /* Invalidated quota? */ - unlock_dquot(dquot); - return; - } down(sem); - filp = dquot->dq_sb->s_dquot.files[type]; - offset = dqoff(dquot->dq_id); + if (!dquot->dq_off) + if ((ret = dq_insert_tree(dquot)) < 0) { + printk(KERN_ERR "VFS: Error %d occurred while creating quota.\n", ret); + goto out_sem; + } + filp = sb_dqopt(dquot->dq_sb)->files[type]; + offset = dquot->dq_off; + mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id); fs = get_fs(); set_fs(KERNEL_DS); - - /* - * Note: clear the DQ_MOD flag unconditionally, - * so we don't loop forever on failure. - */ - dquot->dq_flags &= ~DQ_MOD; - ret = 0; - if (filp) - ret = filp->f_op->write(filp, (char *)&dquot->dq_dqb, - sizeof(struct dqblk), &offset); - if (ret != sizeof(struct dqblk)) + ret = filp->f_op->write(filp, (char *)&ddquot, sizeof(struct disk_dqblk), &offset); + set_fs(fs); + if (ret != sizeof(struct disk_dqblk)) printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", kdevname(dquot->dq_dev)); - - set_fs(fs); + dqstats.writes++; +out_sem: up(sem); - unlock_dquot(dquot); +} - dqstats.writes++; +/* Free dquot entry in data block */ +static int free_dqentry(struct dquot *dquot, uint blk) +{ + struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; + struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type; + struct disk_dqdbheader *dh; + dqbuf_t buf = getdqbuf(); + int ret = 0; + + if (!buf) + return -ENOMEM; + if (dquot->dq_off >> DQBLKSIZE_BITS != blk) { + printk(KERN_ERR "VFS: Quota structure has offset to other block (%u) than it should (%u).\n", blk, (uint)(dquot->dq_off >> DQBLKSIZE_BITS)); + goto out_buf; + } + if ((ret = read_blk(filp, blk, buf)) < 0) { + printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk); + goto out_buf; + } + dh = (struct disk_dqdbheader *)buf; + dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)-1); + if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */ + if ((ret = remove_free_dqentry(filp, info, buf, blk)) < 0 || + (ret = put_free_dqblk(filp, info, buf, blk)) < 0) { + printk(KERN_ERR "VFS: Can't move quota data block (%u) to free list.\n", blk); + goto out_buf; + } + } + else { + memset(buf+(dquot->dq_off & ((1 << DQBLKSIZE_BITS)-1)), 0, sizeof(struct disk_dqblk)); + if (le16_to_cpu(dh->dqdh_entries) == DQSTRINBLK-1) { + /* Insert will write block itself */ + if ((ret = insert_free_dqentry(filp, info, buf, blk)) < 0) { + printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk); + goto out_buf; + } + } + else + if ((ret = write_blk(filp, blk, buf)) < 0) { + printk(KERN_ERR "VFS: Can't write quota data block %u\n", blk); + goto out_buf; + } + } + dquot->dq_off = 0; /* Quota is now unattached */ +out_buf: + freedqbuf(buf); + return ret; +} + +/* Remove reference to dquot from tree */ +static int remove_tree(struct dquot *dquot, uint *blk, int depth) +{ + struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; + struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type; + dqbuf_t buf = getdqbuf(); + int ret = 0; + uint newblk; + u32 *ref = (u32 *)buf; + + if (!buf) + return -ENOMEM; + if ((ret = read_blk(filp, *blk, buf)) < 0) { + printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk); + goto out_buf; + } + newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]); + if (depth == DQTREEDEPTH-1) { + ret = free_dqentry(dquot, newblk); + newblk = 0; + } + else + ret = remove_tree(dquot, &newblk, depth+1); + if (ret >= 0 && !newblk) { + int i; + ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0); + for (i = 0; i < DQBLKSIZE && !buf[i]; i++); /* Block got empty? */ + if (i == DQBLKSIZE) { + put_free_dqblk(filp, info, buf, *blk); + *blk = 0; + } + else + if ((ret = write_blk(filp, *blk, buf)) < 0) + printk(KERN_ERR "VFS: Can't write quota tree block %u.\n", *blk); + } +out_buf: + freedqbuf(buf); + return ret; +} + +/* Delete dquot from tree */ +static void delete_dquot(struct dquot *dquot) +{ + uint tmp = DQTREEOFF; + + if (!dquot->dq_off) /* Even not allocated? */ + return; + down(&sb_dqopt(dquot->dq_sb)->dqio_sem); + remove_tree(dquot, &tmp, 0); + up(&sb_dqopt(dquot->dq_sb)->dqio_sem); +} + +/* Find entry in block */ +static loff_t find_block_dqentry(struct dquot *dquot, uint blk) +{ + struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; + dqbuf_t buf = getdqbuf(); + loff_t ret = 0; + int i; + struct disk_dqblk *ddquot = GETENTRIES(buf); + + if (!buf) + return -ENOMEM; + if ((ret = read_blk(filp, blk, buf)) < 0) { + printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); + goto out_buf; + } + if (dquot->dq_id) + for (i = 0; i < DQSTRINBLK && le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++); + else { /* ID 0 as a bit more complicated searching... */ + struct disk_dqblk fakedquot; + + memset(&fakedquot, 0, sizeof(struct disk_dqblk)); + for (i = 0; i < DQSTRINBLK; i++) + if (!le32_to_cpu(ddquot[i].dqb_id) && memcmp(&fakedquot, ddquot+i, sizeof(struct disk_dqblk))) + break; + } + if (i == DQSTRINBLK) { + printk(KERN_ERR "VFS: Quota for id %u referenced but not present.\n", dquot->dq_id); + ret = -EIO; + goto out_buf; + } + else + ret = (blk << DQBLKSIZE_BITS) + sizeof(struct disk_dqdbheader) + i * sizeof(struct disk_dqblk); +out_buf: + freedqbuf(buf); + return ret; +} + +/* Find entry for given id in the tree */ +static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth) +{ + struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; + dqbuf_t buf = getdqbuf(); + loff_t ret = 0; + u32 *ref = (u32 *)buf; + + if (!buf) + return -ENOMEM; + if ((ret = read_blk(filp, blk, buf)) < 0) { + printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); + goto out_buf; + } + ret = 0; + blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]); + if (!blk) /* No reference? */ + goto out_buf; + if (depth < DQTREEDEPTH-1) + ret = find_tree_dqentry(dquot, blk, depth+1); + else + ret = find_block_dqentry(dquot, blk); +out_buf: + freedqbuf(buf); + return ret; +} + +/* Find entry for given id in the tree - wrapper function */ +static inline loff_t find_dqentry(struct dquot *dquot) +{ + return find_tree_dqentry(dquot, DQTREEOFF, 0); } static void read_dquot(struct dquot *dquot) @@ -285,31 +840,61 @@ struct file *filp; mm_segment_t fs; loff_t offset; + struct disk_dqblk ddquot; - filp = dquot->dq_sb->s_dquot.files[type]; + filp = sb_dqopt(dquot->dq_sb)->files[type]; if (filp == (struct file *)NULL) return; lock_dquot(dquot); - if (!dquot->dq_sb) /* Invalidated quota? */ +#ifdef __DQUOT_PARANOIA + if (!dquot->dq_sb) { /* Invalidated quota? */ + printk(KERN_ERR "VFS: Quota invalidated while reading!\n"); goto out_lock; + } +#endif /* Now we are sure filp is valid - the dquot isn't invalidated */ - down(&dquot->dq_sb->s_dquot.dqio_sem); - offset = dqoff(dquot->dq_id); - fs = get_fs(); - set_fs(KERNEL_DS); - filp->f_op->read(filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk), &offset); - up(&dquot->dq_sb->s_dquot.dqio_sem); - set_fs(fs); - - if (dquot->dq_bhardlimit == 0 && dquot->dq_bsoftlimit == 0 && - dquot->dq_ihardlimit == 0 && dquot->dq_isoftlimit == 0) + down(&sb_dqopt(dquot->dq_sb)->dqio_sem); + offset = find_dqentry(dquot); + if (offset <= 0) { /* Entry not present? */ + if (offset < 0) + printk(KERN_ERR "VFS: Can't read quota structure for id %u.\n", dquot->dq_id); + dquot->dq_off = 0; dquot->dq_flags |= DQ_FAKE; + memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); + } + else { + dquot->dq_off = offset; + fs = get_fs(); + set_fs(KERNEL_DS); + filp->f_op->read(filp, (char *)&ddquot, sizeof(struct disk_dqblk), &offset); + set_fs(fs); + disk2memdqb(&dquot->dq_dqb, &ddquot); + } + up(&sb_dqopt(dquot->dq_sb)->dqio_sem); dqstats.reads++; out_lock: unlock_dquot(dquot); } +/* Commit changes of dquot to disk - it might also mean deleting it when quota became fake one and user has no blocks... */ +static void commit_dquot(struct dquot *dquot) +{ + lock_dquot(dquot); + /* We clear the flag everytime so we don't loop when there was an IO error... */ + dquot->dq_flags &= ~DQ_MOD; + if (dquot->dq_flags & DQ_FAKE && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace)) + delete_dquot(dquot); + else + write_dquot(dquot); + unlock_dquot(dquot); +} + +/* + * End of IO functions + */ + + /* * Unhash and selectively clear the dquot structure, * but preserve the use count, list pointers, and @@ -318,100 +903,101 @@ void clear_dquot(struct dquot *dquot) { /* unhash it first */ - unhash_dquot(dquot); - dquot->dq_sb = NULL; - dquot->dq_flags = 0; - dquot->dq_referenced = 0; - memset(&dquot->dq_dqb, 0, sizeof(struct dqblk)); + remove_dquot_hash(dquot); + dquot->dq_sb = NULL; + dquot->dq_id = 0; + dquot->dq_dev = NODEV; + dquot->dq_type = -1; + dquot->dq_flags = 0; + dquot->dq_off = 0; + dquot->dq_referenced = 0; + memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); } +/* Invalidate all dquots on the list, wait for all users. Note that this function is called + * after quota is disabled so no new quota might be created. As we only insert to the end of + * inuse list, we don't have to restart searching... */ void invalidate_dquots(kdev_t dev, short type) { - struct dquot *dquot, *next; - int need_restart; + struct dquot *dquot; + struct list_head *head; restart: - next = inuse_list; /* Here it is better. Otherwise the restart doesn't have any sense ;-) */ - need_restart = 0; - while ((dquot = next) != NULL) { - next = dquot->dq_next; + for (head = inuse_list.next; head != &inuse_list; head = head->next) { + dquot = list_entry(head, struct dquot, dq_inuse); if (dquot->dq_dev != dev) continue; if (dquot->dq_type != type) continue; if (!dquot->dq_sb) /* Already invalidated entry? */ continue; - if (dquot->dq_flags & DQ_LOCKED) { - __wait_on_dquot(dquot); - - /* Set the flag for another pass. */ - need_restart = 1; + if (dquot->dq_count) /* - * Make sure it's still the same dquot. + * Wait for any users of quota. As we have already cleared the flags in + * superblock and cleared all pointers from inodes we are assured + * that there will be no new users of this quota. */ - if (dquot->dq_dev != dev) - continue; - if (dquot->dq_type != type) - continue; - if (!dquot->dq_sb) - continue; - } - /* - * Because inodes needn't to be the only holders of dquot - * the quota needn't to be written to disk. So we write it - * ourselves before discarding the data just for sure... - */ - if (dquot->dq_flags & DQ_MOD && dquot->dq_sb) - { - write_dquot(dquot); - need_restart = 1; /* We slept on IO */ - } - clear_dquot(dquot); - } - /* - * If anything blocked, restart the operation - * to ensure we don't miss any dquots. - */ - if (need_restart) + __wait_dquot_unused(dquot); + /* Quota now have no users and it has been written on last dqput() */ + remove_dquot_hash(dquot); + remove_free_dquot(dquot); + remove_inuse(dquot); + kmem_cache_free(dquot_cachep, dquot); goto restart; + } } int sync_dquots(kdev_t dev, short type) { - struct dquot *dquot, *next, *ddquot; - int need_restart; + struct list_head *head; + struct dquot *dquot; restart: - next = inuse_list; - need_restart = 0; - while ((dquot = next) != NULL) { - next = dquot->dq_next; + for (head = inuse_list.next; head != &inuse_list; head = head->next) { + dquot = list_entry(head, struct dquot, dq_inuse); if (dev && dquot->dq_dev != dev) continue; if (type != -1 && dquot->dq_type != type) continue; if (!dquot->dq_sb) /* Invalidated? */ continue; - if (!(dquot->dq_flags & (DQ_LOCKED | DQ_MOD))) + if (!(dquot->dq_flags & (DQ_MOD | DQ_LOCKED))) continue; + /* Raise use count so quota won't be invalidated. We can't use dqduplicate() as it does too many tests */ + dquot->dq_count++; + if (dquot->dq_flags & DQ_LOCKED) + wait_on_dquot(dquot); + if (dquot->dq_flags & DQ_MOD) + commit_dquot(dquot); + dqput(dquot); + goto restart; + } + dqstats.syncs++; + return 0; +} - if ((ddquot = dqduplicate(dquot)) == NODQUOT) - continue; - if (ddquot->dq_flags & DQ_MOD) - write_dquot(ddquot); - dqput(ddquot); - /* Set the flag for another pass. */ - need_restart = 1; +/* Free unused dquots from cache */ +void prune_dqcache(int count) +{ + struct list_head *head; + struct dquot *dquot; + + head = free_dquots.prev; + while (head != &free_dquots && count) { + dquot = list_entry(head, struct dquot, dq_free); + remove_dquot_hash(dquot); + remove_free_dquot(dquot); + remove_inuse(dquot); + kmem_cache_free(dquot_cachep, dquot); + count--; + head = free_dquots.prev; } - /* - * If anything blocked, restart the operation - * to ensure we don't miss any dquots. - */ - if (need_restart) - goto restart; +} - dqstats.syncs++; - return(0); +void shrink_dqcache_memory(int priority, unsigned int gfp_mask) +{ + prune_dqcache(nr_free_dquots / (priority + 1)); + kmem_cache_shrink(dquot_cachep); } /* NOTE: If you change this function please check whether dqput_blocks() works right... */ @@ -420,166 +1006,76 @@ if (!dquot) return; if (!dquot->dq_count) { - printk("VFS: dqput: trying to free free dquot\n"); - printk("VFS: device %s, dquot of %s %d\n", + printk(KERN_ERR "VFS: dqput: trying to free free dquot\n"); + printk(KERN_ERR "VFS: device %s, dquot of %s %d\n", kdevname(dquot->dq_dev), quotatypes[dquot->dq_type], dquot->dq_id); return; } - /* - * If the dq_sb pointer isn't initialized this entry needs no - * checking and doesn't need to be written. It's just an empty - * dquot that is put back on to the freelist. - */ - if (dquot->dq_sb) - dqstats.drops++; + dqstats.drops++; we_slept: if (dquot->dq_count > 1) { /* We have more than one user... We can simply decrement use count */ dquot->dq_count--; return; } - if (dquot->dq_flags & DQ_LOCKED) { - printk(KERN_ERR "VFS: Locked quota to be put on the free list.\n"); - dquot->dq_flags &= ~DQ_LOCKED; - } - if (dquot->dq_sb && dquot->dq_flags & DQ_MOD) { - write_dquot(dquot); + if (dquot->dq_flags & DQ_MOD) { + commit_dquot(dquot); goto we_slept; } - /* sanity check */ +#ifdef __DQUOT_PARANOIA if (!list_empty(&dquot->dq_free)) { printk(KERN_ERR "dqput: dquot already on free list??\n"); dquot->dq_count--; /* J.K. Just decrementing use count seems safer... */ return; } +#endif dquot->dq_count--; - dquot->dq_flags &= ~DQ_MOD; /* Modified flag has no sense on free list */ /* Place at end of LRU free queue */ put_dquot_last(dquot); - wake_up(&dquot_wait); -} - -static int grow_dquots(void) -{ - struct dquot *dquot; - int cnt = 0; - - while (cnt < 32) { - dquot = kmem_cache_alloc(dquot_cachep, SLAB_KERNEL); - if(!dquot) - return cnt; - - nr_dquots++; - memset((caddr_t)dquot, 0, sizeof(struct dquot)); - init_waitqueue_head(&dquot->dq_wait); - /* all dquots go on the inuse_list */ - put_inuse(dquot); - put_dquot_head(dquot); - cnt++; - } - return cnt; -} - -static struct dquot *find_best_candidate_weighted(void) -{ - struct list_head *tmp = &free_dquots; - struct dquot *dquot, *best = NULL; - unsigned long myscore, bestscore = ~0U; - int limit = (nr_free_dquots > 128) ? nr_free_dquots >> 2 : 32; - - while ((tmp = tmp->next) != &free_dquots && --limit) { - dquot = list_entry(tmp, struct dquot, dq_free); - /* This should never happen... */ - if (dquot->dq_flags & (DQ_LOCKED | DQ_MOD)) - continue; - myscore = dquot->dq_referenced; - if (myscore < bestscore) { - bestscore = myscore; - best = dquot; - } - } - return best; -} - -static inline struct dquot *find_best_free(void) -{ - struct list_head *tmp = &free_dquots; - struct dquot *dquot; - int limit = (nr_free_dquots > 1024) ? nr_free_dquots >> 5 : 32; - - while ((tmp = tmp->next) != &free_dquots && --limit) { - dquot = list_entry(tmp, struct dquot, dq_free); - if (dquot->dq_referenced == 0) - return dquot; - } - return NULL; + wake_up(&dquot->dq_wait_free); } struct dquot *get_empty_dquot(void) { struct dquot *dquot; - int shrink = 8; /* Number of times we should try to shrink dcache and icache */ -repeat: - dquot = find_best_free(); - if (!dquot) - goto pressure; -got_it: - /* Sanity checks */ - if (dquot->dq_flags & DQ_LOCKED) - printk(KERN_ERR "VFS: Locked dquot on the free list\n"); - if (dquot->dq_count != 0) - printk(KERN_ERR "VFS: free dquot count=%d\n", dquot->dq_count); + dquot = kmem_cache_alloc(dquot_cachep, SLAB_KERNEL); + if(!dquot) + return NODQUOT; - remove_free_dquot(dquot); + memset((caddr_t)dquot, 0, sizeof(struct dquot)); + init_waitqueue_head(&dquot->dq_wait_free); + init_waitqueue_head(&dquot->dq_wait_lock); + INIT_LIST_HEAD(&dquot->dq_free); + INIT_LIST_HEAD(&dquot->dq_inuse); + INIT_LIST_HEAD(&dquot->dq_hash); dquot->dq_count = 1; - /* unhash and selectively clear the structure */ - clear_dquot(dquot); - return dquot; + /* all dquots go on the inuse_list */ + put_inuse(dquot); -pressure: - if (nr_dquots < max_dquots) - if (grow_dquots()) - goto repeat; - - dquot = find_best_candidate_weighted(); - if (dquot) - goto got_it; - /* - * Try pruning the dcache to free up some dquots ... - */ - if (shrink) { - printk(KERN_DEBUG "get_empty_dquot: pruning dcache and icache\n"); - prune_dcache(128); - prune_icache(128); - shrink--; - goto repeat; - } - - printk("VFS: No free dquots, contact mvw@planets.elm.net\n"); - sleep_on(&dquot_wait); - goto repeat; + return dquot; } static struct dquot *dqget(struct super_block *sb, unsigned int id, short type) { unsigned int hashent = hashfn(sb->s_dev, id, type); - struct dquot *dquot, *empty = NULL; - struct quota_mount_options *dqopt = sb_dqopt(sb); - - if (!is_enabled(dqopt, type)) - return(NODQUOT); + struct dquot *dquot, *empty = NODQUOT; + struct quota_info *dqopt = sb_dqopt(sb); we_slept: - if ((dquot = find_dquot(hashent, sb->s_dev, id, type)) == NULL) { - if (empty == NULL) { - dquot_updating[hashent]++; - empty = get_empty_dquot(); - if (!--dquot_updating[hashent]) - wake_up(&update_wait); + if (!is_enabled(dqopt, type)) { + if (empty) + dqput(empty); + return NODQUOT; + } + + if ((dquot = find_dquot(hashent, sb->s_dev, id, type)) == NODQUOT) { + if (empty == NODQUOT) { + if ((empty = get_empty_dquot()) == NODQUOT) + schedule(); /* Try to wait for a moment... */ goto we_slept; } dquot = empty; @@ -588,28 +1084,24 @@ dquot->dq_dev = sb->s_dev; dquot->dq_sb = sb; /* hash it first so it can be found */ - hash_dquot(dquot); + insert_dquot_hash(dquot); read_dquot(dquot); } else { - if (!dquot->dq_count++) { + if (!dquot->dq_count++) remove_free_dquot(dquot); - } else - dqstats.cache_hits++; + dqstats.cache_hits++; wait_on_dquot(dquot); if (empty) dqput(empty); } - while (dquot_updating[hashent]) - sleep_on(&update_wait); - +#ifdef __DQUOT_PARANOIA if (!dquot->dq_sb) { /* Has somebody invalidated entry under us? */ - /* - * Do it as if the quota was invalidated before we started - */ + printk(KERN_ERR "VFS: dqget(): Quota invalidated in dqget()!\n"); dqput(dquot); return NODQUOT; } +#endif dquot->dq_referenced++; dqstats.lookups++; @@ -618,14 +1110,18 @@ static struct dquot *dqduplicate(struct dquot *dquot) { - if (dquot == NODQUOT || !dquot->dq_sb) + if (dquot == NODQUOT) return NODQUOT; dquot->dq_count++; - wait_on_dquot(dquot); +#ifdef __DQUOT_PARANOIA if (!dquot->dq_sb) { + printk(KERN_ERR "VFS: dqduplicate(): Invalidated quota to be duplicated!\n"); dquot->dq_count--; return NODQUOT; } + if (dquot->dq_flags & DQ_LOCKED) + printk(KERN_ERR "VFS: dqduplicate(): Locked quota to be duplicated!\n"); +#endif dquot->dq_referenced++; dqstats.lookups++; return dquot; @@ -635,7 +1131,7 @@ static inline int is_quotafile(struct inode *inode) { int cnt; - struct quota_mount_options *dqopt = sb_dqopt(inode->i_sb); + struct quota_info *dqopt = sb_dqopt(inode->i_sb); struct file **files; if (!dqopt) @@ -717,9 +1213,9 @@ printk(KERN_WARNING "VFS: Adding dquot with dq_count %d to dispose list.\n", dquot->dq_count); list_add(&dquot->dq_free, tofree_head); /* As dquot must have currently users it can't be on the free list... */ return 1; - } else { - dqput(dquot); /* We have guaranteed we won't block */ } + else + dqput(dquot); /* We have guaranteed we won't block */ } return 0; } @@ -746,9 +1242,9 @@ dquot->dq_flags |= DQ_MOD; } -static inline void dquot_incr_blocks(struct dquot *dquot, unsigned long number) +static inline void dquot_incr_space(struct dquot *dquot, qsize_t number) { - dquot->dq_curblocks += number; + dquot->dq_curspace += number; dquot->dq_flags |= DQ_MOD; } @@ -764,13 +1260,13 @@ dquot->dq_flags |= DQ_MOD; } -static inline void dquot_decr_blocks(struct dquot *dquot, unsigned long number) +static inline void dquot_decr_space(struct dquot *dquot, qsize_t number) { - if (dquot->dq_curblocks > number) - dquot->dq_curblocks -= number; + if (dquot->dq_curspace > number) + dquot->dq_curspace -= number; else - dquot->dq_curblocks = 0; - if (dquot->dq_curblocks < dquot->dq_bsoftlimit) + dquot->dq_curspace = 0; + if (toqb(dquot->dq_curspace) < dquot->dq_bsoftlimit) dquot->dq_btime = (time_t) 0; dquot->dq_flags &= ~DQ_BLKS; dquot->dq_flags |= DQ_MOD; @@ -787,30 +1283,78 @@ return 0; } -static void print_warning(struct dquot *dquot, int flag, const char *fmtstr) -{ +/* Values of warnings */ +#define NOWARN 0 +#define IHARDWARN 1 +#define ISOFTLONGWARN 2 +#define ISOFTWARN 3 +#define BHARDWARN 4 +#define BSOFTLONGWARN 5 +#define BSOFTWARN 6 + +/* Print warning to user which exceeded quota */ +static void print_warning(struct dquot *dquot, const char warntype) +{ + char *msg = NULL; + int flag = (warntype == BHARDWARN || warntype == BSOFTLONGWARN) ? DQ_BLKS : + ((warntype == IHARDWARN || warntype == ISOFTLONGWARN) ? DQ_INODES : 0); + if (!need_print_warning(dquot, flag)) return; - sprintf(quotamessage, fmtstr, - bdevname(dquot->dq_sb->s_dev), quotatypes[dquot->dq_type]); - tty_write_message(current->tty, quotamessage); dquot->dq_flags |= flag; + tty_write_message(current->tty, (char *)bdevname(dquot->dq_sb->s_dev)); + if (warntype == ISOFTWARN || warntype == BSOFTWARN) + tty_write_message(current->tty, ": warning, "); + else + tty_write_message(current->tty, ": write failed, "); + tty_write_message(current->tty, (char *)quotatypes[dquot->dq_type]); + switch (warntype) { + case IHARDWARN: + msg = " file limit reached.\n"; + break; + case ISOFTLONGWARN: + msg = " file quota exceeded too long.\n"; + break; + case ISOFTWARN: + msg = " file quota exceeded.\n"; + break; + case BHARDWARN: + msg = " block limit reached.\n"; + break; + case BSOFTLONGWARN: + msg = " block quota exceeded too long.\n"; + break; + case BSOFTWARN: + msg = " block quota exceeded.\n"; + break; + } + tty_write_message(current->tty, msg); +} + +static inline void flush_warnings(struct dquot **dquots, char *warntype) +{ + int i; + + for (i = 0; i < MAXQUOTAS; i++) + if (dquots[i] != NODQUOT && warntype[i] != NOWARN) + print_warning(dquots[i], warntype[i]); } static inline char ignore_hardlimit(struct dquot *dquot) { - return capable(CAP_SYS_RESOURCE) && !dquot->dq_sb->s_dquot.rsquash[dquot->dq_type]; + return capable(CAP_SYS_RESOURCE); } -static int check_idq(struct dquot *dquot, u_long inodes) +static int check_idq(struct dquot *dquot, ulong inodes, char *warntype) { + *warntype = NOWARN; if (inodes <= 0 || dquot->dq_flags & DQ_FAKE) return QUOTA_OK; if (dquot->dq_ihardlimit && (dquot->dq_curinodes + inodes) > dquot->dq_ihardlimit && !ignore_hardlimit(dquot)) { - print_warning(dquot, DQ_INODES, "%s: write failed, %s file limit reached\n"); + *warntype = IHARDWARN; return NO_QUOTA; } @@ -818,48 +1362,49 @@ (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit && dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime && !ignore_hardlimit(dquot)) { - print_warning(dquot, DQ_INODES, "%s: warning, %s file quota exceeded too long.\n"); + *warntype = ISOFTLONGWARN; return NO_QUOTA; } if (dquot->dq_isoftlimit && (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit && dquot->dq_itime == 0) { - print_warning(dquot, 0, "%s: warning, %s file quota exceeded\n"); - dquot->dq_itime = CURRENT_TIME + dquot->dq_sb->s_dquot.inode_expire[dquot->dq_type]; + *warntype = ISOFTWARN; + dquot->dq_itime = CURRENT_TIME + (__kernel_time_t)(sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace); } return QUOTA_OK; } -static int check_bdq(struct dquot *dquot, u_long blocks, char prealloc) +static int check_bdq(struct dquot *dquot, qsize_t space, char prealloc, char *warntype) { - if (blocks <= 0 || dquot->dq_flags & DQ_FAKE) + *warntype = 0; + if (space <= 0 || dquot->dq_flags & DQ_FAKE) return QUOTA_OK; if (dquot->dq_bhardlimit && - (dquot->dq_curblocks + blocks) > dquot->dq_bhardlimit && + toqb(dquot->dq_curspace + space) > dquot->dq_bhardlimit && !ignore_hardlimit(dquot)) { if (!prealloc) - print_warning(dquot, DQ_BLKS, "%s: write failed, %s disk limit reached.\n"); + *warntype = BHARDWARN; return NO_QUOTA; } if (dquot->dq_bsoftlimit && - (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit && + toqb(dquot->dq_curspace + space) > dquot->dq_bsoftlimit && dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime && !ignore_hardlimit(dquot)) { if (!prealloc) - print_warning(dquot, DQ_BLKS, "%s: write failed, %s disk quota exceeded too long.\n"); + *warntype = BSOFTLONGWARN; return NO_QUOTA; } if (dquot->dq_bsoftlimit && - (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit && + toqb(dquot->dq_curspace + space) > dquot->dq_bsoftlimit && dquot->dq_btime == 0) { if (!prealloc) { - print_warning(dquot, 0, "%s: warning, %s disk quota exceeded\n"); - dquot->dq_btime = CURRENT_TIME + dquot->dq_sb->s_dquot.block_expire[dquot->dq_type]; + *warntype = BSOFTWARN; + dquot->dq_btime = CURRENT_TIME + (__kernel_time_t)(sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace); } else /* @@ -876,25 +1421,18 @@ * Initialize a dquot-struct with new quota info. This is used by the * system call interface functions. */ -static int set_dqblk(struct super_block *sb, int id, short type, int flags, struct dqblk *dqblk) +static int set_dqblk(struct super_block *sb, qid_t id, short type, int flags, struct mem_dqblk *dqblk) { struct dquot *dquot; int error = -EFAULT; - struct dqblk dq_dqblk; + struct mem_dqblk dq_dqblk; - if (dqblk == (struct dqblk *)NULL) + if (copy_from_user(&dq_dqblk, dqblk, sizeof(struct mem_dqblk))) return error; - if (flags & QUOTA_SYSCALL) { - if (copy_from_user(&dq_dqblk, dqblk, sizeof(struct dqblk))) - return(error); - } else - memcpy((caddr_t)&dq_dqblk, (caddr_t)dqblk, sizeof(struct dqblk)); - if (sb && (dquot = dqget(sb, id, type)) != NODQUOT) { - lock_dquot(dquot); - - if (id > 0 && ((flags & SET_QUOTA) || (flags & SET_QLIMIT))) { + /* We can't block while changing quota structure... */ + if ((flags & SET_QUOTA) || (flags & SET_QLIMIT)) { dquot->dq_bhardlimit = dq_dqblk.dqb_bhardlimit; dquot->dq_bsoftlimit = dq_dqblk.dqb_bsoftlimit; dquot->dq_ihardlimit = dq_dqblk.dqb_ihardlimit; @@ -905,22 +1443,22 @@ if (dquot->dq_isoftlimit && dquot->dq_curinodes < dquot->dq_isoftlimit && dq_dqblk.dqb_curinodes >= dquot->dq_isoftlimit) - dquot->dq_itime = CURRENT_TIME + dquot->dq_sb->s_dquot.inode_expire[type]; + dquot->dq_itime = CURRENT_TIME + (__kernel_time_t)(sb_dqopt(dquot->dq_sb)->info[type].dqi_igrace); dquot->dq_curinodes = dq_dqblk.dqb_curinodes; - if (dquot->dq_curinodes < dquot->dq_isoftlimit) - dquot->dq_flags &= ~DQ_INODES; if (dquot->dq_bsoftlimit && - dquot->dq_curblocks < dquot->dq_bsoftlimit && - dq_dqblk.dqb_curblocks >= dquot->dq_bsoftlimit) - dquot->dq_btime = CURRENT_TIME + dquot->dq_sb->s_dquot.block_expire[type]; - dquot->dq_curblocks = dq_dqblk.dqb_curblocks; - if (dquot->dq_curblocks < dquot->dq_bsoftlimit) - dquot->dq_flags &= ~DQ_BLKS; + toqb(dquot->dq_curspace) < dquot->dq_bsoftlimit && + toqb(dq_dqblk.dqb_curspace) >= dquot->dq_bsoftlimit) + dquot->dq_btime = CURRENT_TIME + (__kernel_time_t)(sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace); + dquot->dq_curspace = dq_dqblk.dqb_curspace; } - if (id == 0) { - dquot->dq_sb->s_dquot.block_expire[type] = dquot->dq_btime = dq_dqblk.dqb_btime; - dquot->dq_sb->s_dquot.inode_expire[type] = dquot->dq_itime = dq_dqblk.dqb_itime; + if (dquot->dq_curinodes < dquot->dq_isoftlimit || !dquot->dq_isoftlimit) { + dquot->dq_itime = 0; + dquot->dq_flags &= ~DQ_INODES; + } + if (toqb(dquot->dq_curspace) < dquot->dq_bsoftlimit || !dquot->dq_bsoftlimit) { + dquot->dq_btime = 0; + dquot->dq_flags &= ~DQ_BLKS; } if (dq_dqblk.dqb_bhardlimit == 0 && dq_dqblk.dqb_bsoftlimit == 0 && @@ -930,15 +1468,15 @@ dquot->dq_flags &= ~DQ_FAKE; dquot->dq_flags |= DQ_MOD; - unlock_dquot(dquot); dqput(dquot); } - return(0); + return 0; } -static int get_quota(struct super_block *sb, int id, short type, struct dqblk *dqblk) +static int get_quota(struct super_block *sb, qid_t id, short type, struct mem_dqblk *dqblk) { struct dquot *dquot; + struct mem_dqblk data; int error = -ESRCH; if (!sb || !sb_has_quota_enabled(sb, type)) @@ -947,12 +1485,11 @@ if (dquot == NODQUOT) goto out; - lock_dquot(dquot); /* We must protect against invalidating the quota */ + memcpy(&data, &dquot->dq_dqb, sizeof(struct mem_dqblk)); /* We copy data to preserve them from changing */ + dqput(dquot); error = -EFAULT; - if (dqblk && !copy_to_user(dqblk, &dquot->dq_dqb, sizeof(struct dqblk))) + if (dqblk && !copy_to_user(dqblk, &data, sizeof(struct mem_dqblk))) error = 0; - unlock_dquot(dquot); - dqput(dquot); out: return error; } @@ -972,43 +1509,47 @@ return error; } -static int quota_root_squash(struct super_block *sb, short type, int *addr) +static int get_info(struct super_block *sb, short type, struct mem_dqinfo *pinfo) { - int new_value, error; - - if (!sb) - return(-ENODEV); - - error = -EFAULT; - if (!copy_from_user(&new_value, addr, sizeof(int))) { - sb_dqopt(sb)->rsquash[type] = new_value; - error = 0; - } - return error; + struct mem_dqinfo kinfo; + + if (!sb || !sb_has_quota_enabled(sb, type)) + return -ESRCH; + /* Make our own copy so we can guarantee consistent structure */ + memcpy(&kinfo, sb_dqopt(sb)->info+type, sizeof(struct mem_dqinfo)); + kinfo.dqi_flags &= DQF_MASK; + if (copy_to_user(pinfo, &kinfo, sizeof(struct mem_dqinfo))) + return -EFAULT; + return 0; } -/* - * This is a simple algorithm that calculates the size of a file in blocks. - * This is only used on filesystems that do not have an i_blocks count. - */ -static u_long isize_to_blocks(loff_t isize, size_t blksize_bits) +static int set_info(int op, struct super_block *sb, short type, struct mem_dqinfo *pinfo) { - u_long blocks; - u_long indirect; + struct mem_dqinfo info; + struct quota_info *dqopt = sb_dqopt(sb); - if (!blksize_bits) - blksize_bits = BLOCK_SIZE_BITS; - blocks = (isize >> blksize_bits) + ((isize & ~((1 << blksize_bits)-1)) ? 1 : 0); - if (blocks > 10) { - indirect = ((blocks - 11) >> 8) + 1; /* single indirect blocks */ - if (blocks > (10 + 256)) { - indirect += ((blocks - 267) >> 16) + 1; /* double indirect blocks */ - if (blocks > (10 + 256 + (256 << 8))) - indirect++; /* triple indirect blocks */ - } - blocks += indirect; - } - return blocks; + if (!sb || !sb_has_quota_enabled(sb, type)) + return -ESRCH; + + if (copy_from_user(&info, pinfo, sizeof(struct mem_dqinfo))) + return -EFAULT; + + switch (op) { + case ISET_FLAGS: + dqopt->info[type].dqi_flags = (dqopt->info[type].dqi_flags & ~DQF_MASK) + | (info.dqi_flags & DQF_MASK); + break; + case ISET_GRACE: + dqopt->info[type].dqi_bgrace = info.dqi_bgrace; + dqopt->info[type].dqi_igrace = info.dqi_igrace; + break; + case ISET_ALL: + info.dqi_flags &= ~DQF_MASK; + memcpy(dqopt->info + type, &info, sizeof(struct mem_dqinfo)); + break; + } + mark_quotafile_info_dirty(dqopt->info + type); + return 0; } /* @@ -1018,26 +1559,23 @@ */ void dquot_initialize(struct inode *inode, short type) { - struct dquot *dquot; - unsigned int id = 0; + struct dquot *dquot[MAXQUOTAS]; + qid_t id = 0; short cnt; if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode) && !S_ISLNK(inode->i_mode)) return; - lock_kernel(); /* We don't want to have quotas on quota files - nasty deadlocks possible */ - if (is_quotafile(inode)) { - unlock_kernel(); + if (is_quotafile(inode)) return; - } + /* Build list of quotas to initialize... We can block here */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + dquot[cnt] = NODQUOT; if (type != -1 && cnt != type) continue; - if (!sb_has_quota_enabled(inode->i_sb, cnt)) continue; - if (inode->i_dquot[cnt] == NODQUOT) { switch (cnt) { case USRQUOTA: @@ -1047,18 +1585,22 @@ id = inode->i_gid; break; } - dquot = dqget(inode->i_sb, id, cnt); - if (dquot == NODQUOT) - continue; - if (inode->i_dquot[cnt] != NODQUOT) { - dqput(dquot); - continue; - } - inode->i_dquot[cnt] = dquot; - inode->i_flags |= S_QUOTA; + dquot[cnt] = dqget(inode->i_sb, id, cnt); } } - unlock_kernel(); + /* NOBLOCK START: Here we shouldn't block */ + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (dquot[cnt] == NODQUOT || !sb_has_quota_enabled(inode->i_sb, cnt) || inode->i_dquot[cnt] != NODQUOT) + continue; + inode->i_dquot[cnt] = dquot[cnt]; + dquot[cnt] = NODQUOT; + inode->i_flags |= S_QUOTA; + } + /* NOBLOCK END */ + /* Put quotas which we didn't use */ + for (cnt = 0; cnt < MAXQUOTAS; cnt++) + if (dquot[cnt] != NODQUOT) + dqput(dquot[cnt]); } /* @@ -1084,96 +1626,97 @@ } /* - * Note: this is a blocking operation. + * This operation can block, but only after everything is updated */ -int dquot_alloc_block(const struct inode *inode, unsigned long number, char warn) +int dquot_alloc_space(struct inode *inode, qsize_t number, char prealloc) { - int cnt; + int cnt, ret = NO_QUOTA; struct dquot *dquot[MAXQUOTAS]; + char warntype[MAXQUOTAS]; for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - dquot[cnt] = dqduplicate(inode->i_dquot[cnt]); - if (dquot[cnt] == NODQUOT) - continue; - lock_dquot(dquot[cnt]); - if (check_bdq(dquot[cnt], number, warn)) - goto put_all; + dquot[cnt] = NODQUOT; + warntype[cnt] = NOWARN; } - for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + dquot[cnt] = dqduplicate(inode->i_dquot[cnt]); if (dquot[cnt] == NODQUOT) continue; - dquot_incr_blocks(dquot[cnt], number); - unlock_dquot(dquot[cnt]); - dqput(dquot[cnt]); + if (check_bdq(dquot[cnt], number, prealloc, warntype+cnt) == NO_QUOTA) + goto warn_put_all; } - - return QUOTA_OK; -put_all: - for (; cnt >= 0; cnt--) { + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (dquot[cnt] == NODQUOT) continue; - unlock_dquot(dquot[cnt]); - dqput(dquot[cnt]); + dquot_incr_space(dquot[cnt], number); } - return NO_QUOTA; + inode_add_bytes(inode, number); + mark_inode_dirty(inode); + ret = QUOTA_OK; +warn_put_all: + flush_warnings(dquot, warntype); + for (cnt = 0; cnt < MAXQUOTAS; cnt++) + if (dquot[cnt] != NODQUOT) + dqput(dquot[cnt]); + return ret; } /* - * Note: this is a blocking operation. + * This operation can block, but only after everything is updated */ int dquot_alloc_inode(const struct inode *inode, unsigned long number) { - int cnt; + int cnt, ret = NO_QUOTA; struct dquot *dquot[MAXQUOTAS]; + char warntype[MAXQUOTAS]; for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + dquot[cnt] = NODQUOT; + warntype[cnt] = NOWARN; + } + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { dquot[cnt] = dqduplicate(inode -> i_dquot[cnt]); if (dquot[cnt] == NODQUOT) continue; - lock_dquot(dquot[cnt]); - if (check_idq(dquot[cnt], number)) - goto put_all; + if (check_idq(dquot[cnt], number, warntype+cnt) == NO_QUOTA) + goto warn_put_all; } for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (dquot[cnt] == NODQUOT) continue; dquot_incr_inodes(dquot[cnt], number); - unlock_dquot(dquot[cnt]); - dqput(dquot[cnt]); - } - - return QUOTA_OK; -put_all: - for (; cnt >= 0; cnt--) { - if (dquot[cnt] == NODQUOT) - continue; - unlock_dquot(dquot[cnt]); - dqput(dquot[cnt]); } - return NO_QUOTA; + ret = QUOTA_OK; +warn_put_all: + flush_warnings(dquot, warntype); + for (cnt = 0; cnt < MAXQUOTAS; cnt++) + if (dquot[cnt] != NODQUOT) + dqput(dquot[cnt]); + return ret; } /* - * Note: this is a blocking operation. + * This is a non-blocking operation. */ -void dquot_free_block(const struct inode *inode, unsigned long number) +void dquot_free_space(struct inode *inode, qsize_t number) { unsigned short cnt; struct dquot *dquot; for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - dquot = inode->i_dquot[cnt]; + dquot = dqduplicate(inode->i_dquot[cnt]); if (dquot == NODQUOT) continue; - wait_on_dquot(dquot); - dquot_decr_blocks(dquot, number); + dquot_decr_space(dquot, number); + dqput(dquot); } + inode_sub_bytes(inode, number); + mark_inode_dirty(inode); } /* - * Note: this is a blocking operation. + * This is a non-blocking operation. */ void dquot_free_inode(const struct inode *inode, unsigned long number) { @@ -1181,173 +1724,110 @@ struct dquot *dquot; for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - dquot = inode->i_dquot[cnt]; + dquot = dqduplicate(inode->i_dquot[cnt]); if (dquot == NODQUOT) continue; - wait_on_dquot(dquot); dquot_decr_inodes(dquot, number); + dqput(dquot); } } /* * Transfer the number of inode and blocks from one diskquota to an other. * - * Note: this is a blocking operation. + * This operation can block, but only after everything is updated */ -int dquot_transfer(struct dentry *dentry, struct iattr *iattr) +int dquot_transfer(struct inode *inode, struct iattr *iattr) { - struct inode *inode = dentry -> d_inode; - unsigned long blocks; + qsize_t space; struct dquot *transfer_from[MAXQUOTAS]; struct dquot *transfer_to[MAXQUOTAS]; - short cnt, disc; - int error = -EDQUOT; - - if (!inode) - return -ENOENT; - /* Arguably we could consider that as error, but... no fs - no quota */ - if (!inode->i_sb) - return 0; + int cnt, ret = NO_QUOTA, chuid = (iattr->ia_valid & ATTR_UID) && inode->i_uid != iattr->ia_uid, + chgid = (iattr->ia_valid & ATTR_GID) && inode->i_gid != iattr->ia_gid; + char warntype[MAXQUOTAS]; - lock_kernel(); - /* - * Build the transfer_from and transfer_to lists and check quotas to see - * if operation is permitted. - */ + /* Clear the arrays */ + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + transfer_to[cnt] = transfer_from[cnt] = NODQUOT; + warntype[cnt] = NOWARN; + } + /* First build the transfer_to list - here we can block on reading of dquots... */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - transfer_from[cnt] = NODQUOT; - transfer_to[cnt] = NODQUOT; - if (!sb_has_quota_enabled(inode->i_sb, cnt)) continue; - switch (cnt) { case USRQUOTA: - if (inode->i_uid == iattr->ia_uid) + if (!chuid) continue; - /* We can get transfer_from from inode, can't we? */ - transfer_from[cnt] = dqget(inode->i_sb, inode->i_uid, cnt); transfer_to[cnt] = dqget(inode->i_sb, iattr->ia_uid, cnt); break; case GRPQUOTA: - if (inode->i_gid == iattr->ia_gid) + if (!chgid) continue; - transfer_from[cnt] = dqget(inode->i_sb, inode->i_gid, cnt); transfer_to[cnt] = dqget(inode->i_sb, iattr->ia_gid, cnt); break; } - - /* Something bad (eg. quotaoff) happened while we were sleeping? */ - if (transfer_from[cnt] == NODQUOT || transfer_to[cnt] == NODQUOT) - { - if (transfer_from[cnt] != NODQUOT) { - dqput(transfer_from[cnt]); - transfer_from[cnt] = NODQUOT; - } - if (transfer_to[cnt] != NODQUOT) { - dqput(transfer_to[cnt]); - transfer_to[cnt] = NODQUOT; - } - continue; - } - /* - * We have to lock the quotas to prevent races... - */ - if (transfer_from[cnt] < transfer_to[cnt]) - { - lock_dquot(transfer_from[cnt]); - lock_dquot(transfer_to[cnt]); - } - else - { - lock_dquot(transfer_to[cnt]); - lock_dquot(transfer_from[cnt]); - } - - /* - * The entries might got invalidated while locking. The second - * dqget() could block and so the first structure might got - * invalidated or locked... - */ - if (!transfer_to[cnt]->dq_sb || !transfer_from[cnt]->dq_sb) { - cnt++; - goto put_all; - } } - - /* - * Find out if this filesystem uses i_blocks. - */ - if (!inode->i_sb->s_blocksize) - blocks = isize_to_blocks(inode->i_size, BLOCK_SIZE_BITS); - else - blocks = (inode->i_blocks >> 1); + /* NOBLOCK START: From now on we shouldn't block */ + space = inode_get_bytes(inode); + /* Build the transfer_from list and check the limits */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (!transfer_to[cnt]) + /* The second test can fail when quotaoff is in progress... */ + if (transfer_to[cnt] == NODQUOT || !sb_has_quota_enabled(inode->i_sb, cnt)) continue; - if (check_idq(transfer_to[cnt], 1) == NO_QUOTA || - check_bdq(transfer_to[cnt], blocks, 0) == NO_QUOTA) { - cnt = MAXQUOTAS; - goto put_all; - } + transfer_from[cnt] = dqduplicate(inode->i_dquot[cnt]); + if (transfer_from[cnt] == NODQUOT) /* Can happen on quotafiles (quota isn't initialized on them)... */ + continue; + if (check_idq(transfer_to[cnt], 1, warntype+cnt) == NO_QUOTA || + check_bdq(transfer_to[cnt], space, 0, warntype+cnt) == NO_QUOTA) + goto warn_put_all; } - if ((error = notify_change(dentry, iattr))) - goto put_all; /* - * Finally perform the needed transfer from transfer_from to transfer_to, - * and release any pointers to dquots not needed anymore. + * Finally perform the needed transfer from transfer_from to transfer_to */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { /* * Skip changes for same uid or gid or for non-existing quota-type. */ - if (transfer_from[cnt] == NODQUOT && transfer_to[cnt] == NODQUOT) + if (transfer_from[cnt] == NODQUOT || transfer_to[cnt] == NODQUOT) continue; dquot_decr_inodes(transfer_from[cnt], 1); - dquot_decr_blocks(transfer_from[cnt], blocks); + dquot_decr_space(transfer_from[cnt], space); dquot_incr_inodes(transfer_to[cnt], 1); - dquot_incr_blocks(transfer_to[cnt], blocks); + dquot_incr_space(transfer_to[cnt], space); - unlock_dquot(transfer_from[cnt]); - dqput(transfer_from[cnt]); - if (inode->i_dquot[cnt] != NODQUOT) { - struct dquot *temp = inode->i_dquot[cnt]; - inode->i_dquot[cnt] = transfer_to[cnt]; - unlock_dquot(transfer_to[cnt]); - dqput(temp); - } else { - unlock_dquot(transfer_to[cnt]); - dqput(transfer_to[cnt]); - } + if (inode->i_dquot[cnt] == NODQUOT) + BUG(); + inode->i_dquot[cnt] = transfer_to[cnt]; + /* + * We've got to release transfer_from[] twice - once for dquot_transfer() and + * once for inode. We don't want to release transfer_to[] as it's now placed in inode + */ + transfer_to[cnt] = transfer_from[cnt]; } - - unlock_kernel(); - return 0; -put_all: - for (disc = 0; disc < cnt; disc++) { - /* There should be none or both pointers set but... */ - if (transfer_to[disc] != NODQUOT) { - unlock_dquot(transfer_to[disc]); - dqput(transfer_to[disc]); - } - if (transfer_from[disc] != NODQUOT) { - unlock_dquot(transfer_from[disc]); - dqput(transfer_from[disc]); - } + /* NOBLOCK END. From now on we can block as we wish */ + ret = QUOTA_OK; +warn_put_all: + flush_warnings(transfer_to, warntype); + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (transfer_to[cnt] != NODQUOT) + dqput(transfer_to[cnt]); + if (transfer_from[cnt] != NODQUOT) + dqput(transfer_from[cnt]); } - unlock_kernel(); - return error; + return ret; } - void __init dquot_init_hash(void) { - printk(KERN_NOTICE "VFS: Diskquotas version %s initialized\n", __DQUOT_VERSION__); + int i; - memset(dquot_hash, 0, sizeof(dquot_hash)); + printk(KERN_NOTICE "VFS: Diskquotas version %s initialized\n", __DQUOT_VERSION__); + for (i = 0; i < NR_DQHASH; i++) + INIT_LIST_HEAD(dquot_hash + i); memset((caddr_t)&dqstats, 0, sizeof(dqstats)); } @@ -1357,14 +1837,14 @@ struct dquot_operations dquot_operations = { dquot_initialize, /* mandatory */ dquot_drop, /* mandatory */ - dquot_alloc_block, + dquot_alloc_space, dquot_alloc_inode, - dquot_free_block, + dquot_free_space, dquot_free_inode, dquot_transfer }; -static inline void set_enable_flags(struct quota_mount_options *dqopt, short type) +static inline void set_enable_flags(struct quota_info *dqopt, short type) { switch (type) { case USRQUOTA: @@ -1376,7 +1856,7 @@ } } -static inline void reset_enable_flags(struct quota_mount_options *dqopt, short type) +static inline void reset_enable_flags(struct quota_info *dqopt, short type) { switch (type) { case USRQUOTA: @@ -1398,8 +1878,7 @@ { struct file *filp; short cnt; - int enabled = 0; - struct quota_mount_options *dqopt = sb_dqopt(sb); + struct quota_info *dqopt = sb_dqopt(sb); if (!sb) goto out; @@ -1416,44 +1895,44 @@ /* Note: these are blocking operations */ remove_dquot_ref(sb->s_dev, cnt); invalidate_dquots(sb->s_dev, cnt); - - /* Wait for any pending IO - remove me as soon as invalidate is more polite */ - down(&dqopt->dqio_sem); + /* When invalidate is finished there are no users of any dquot of our interest... */ + if (quotafile_info_dirty(sb_dqopt(sb)->info+cnt)) + write_quotafile_info(sb, cnt); filp = dqopt->files[cnt]; dqopt->files[cnt] = (struct file *)NULL; - dqopt->inode_expire[cnt] = 0; - dqopt->block_expire[cnt] = 0; - up(&dqopt->dqio_sem); + memset(dqopt->info+cnt, 0, sizeof(struct mem_dqinfo)); fput(filp); } - - /* - * Check whether any quota is still enabled, - * and if not clear the dq_op pointer. - */ - for (cnt = 0; cnt < MAXQUOTAS; cnt++) - enabled |= is_enabled(dqopt, cnt); - if (!enabled) - sb->dq_op = NULL; up(&dqopt->dqoff_sem); out: - return(0); + return 0; } -static inline int check_quotafile_size(loff_t size) +static int check_quotafile(struct file *f, short type) { - ulong blocks = size >> BLOCK_SIZE_BITS; - size_t off = size & (BLOCK_SIZE - 1); - - return !(((blocks % sizeof(struct dqblk)) * BLOCK_SIZE + off % sizeof(struct dqblk)) % sizeof(struct dqblk)); + struct disk_dqheader dqhead; + mm_segment_t fs; + ssize_t size; + loff_t offset = 0; + + fs = get_fs(); + set_fs(KERNEL_DS); + size = f->f_op->read(f, (char *)&dqhead, sizeof(struct disk_dqheader), &offset); + set_fs(fs); + if (size != sizeof(struct disk_dqheader)) + return 0; + if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] || + le32_to_cpu(dqhead.dqh_version) != quota_versions[type]) + return 0; + return 1; } +/* Turn quotas of given type on */ static int quota_on(struct super_block *sb, short type, char *path) { struct file *f; struct inode *inode; - struct dquot *dquot; - struct quota_mount_options *dqopt = sb_dqopt(sb); + struct quota_info *dqopt = sb_dqopt(sb); char *tmp; int error; @@ -1480,24 +1959,21 @@ if (!S_ISREG(inode->i_mode)) goto out_f; error = -EINVAL; - if (inode->i_size == 0 || !check_quotafile_size(inode->i_size)) + if (inode->i_size == 0 || !check_quotafile(f, type)) goto out_f; - dquot_drop(inode); /* We don't want quota on quota files */ + dquot_drop(inode); /* We don't want quota on quota files - open might initialize the other quota type... */ - set_enable_flags(dqopt, type); dqopt->files[type] = f; - - dquot = dqget(sb, 0, type); - dqopt->inode_expire[type] = (dquot != NODQUOT) ? dquot->dq_itime : MAX_IQ_TIME; - dqopt->block_expire[type] = (dquot != NODQUOT) ? dquot->dq_btime : MAX_DQ_TIME; - dqput(dquot); - + if (read_quotafile_info(sb, type) < 0) /* Read header from file - OK? */ + goto out_f_tab; sb->dq_op = &dquot_operations; + set_enable_flags(dqopt, type); add_dquot_ref(sb, type); up(&dqopt->dqoff_sem); return 0; - +out_f_tab: + dqopt->files[type] = NULL; out_f: filp_close(f, NULL); out_lock: @@ -1512,7 +1988,7 @@ * calls. Maybe we need to add the process quotas etc. in the future, * but we probably should use rlimits for that. */ -asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr) +asmlinkage long sys_quotactl(int cmd, const char *special, qid_t id, __kernel_caddr_t addr) { int cmds = 0, type = 0, flags = 0; kdev_t dev; @@ -1523,9 +1999,9 @@ cmds = cmd >> SUBCMDSHIFT; type = cmd & SUBCMDMASK; - if ((u_int) type >= MAXQUOTAS) - goto out; - if (id & ~0xFFFF) + + if ((uint) type >= MAXQUOTAS || cmds > 0x0F00 || cmds < 0x100 || cmds == 0x0300 || + cmds == 0x0400 || cmds == 0x0500) goto out; ret = -EPERM; @@ -1536,15 +2012,14 @@ case Q_GETQUOTA: if (((type == USRQUOTA && current->euid != id) || (type == GRPQUOTA && !in_egroup_p(id))) && - !capable(CAP_SYS_RESOURCE)) + !capable(CAP_SYS_ADMIN)) goto out; break; default: - if (!capable(CAP_SYS_RESOURCE)) + if (!capable(CAP_SYS_ADMIN)) goto out; } - ret = -EINVAL; dev = NODEV; if (special != NULL || (cmds != Q_SYNC && cmds != Q_GETSTATS)) { mode_t mode; @@ -1561,19 +2036,22 @@ ret = -ENOTBLK; if (!S_ISBLK(mode)) goto out; + ret = -ENODEV; sb = get_super(dev); + if (!sb) + goto out; } ret = -EINVAL; switch (cmds) { case Q_QUOTAON: - ret = sb ? quota_on(sb, type, (char *) addr) : -ENODEV; + ret = quota_on(sb, type, (char *) addr); goto out; case Q_QUOTAOFF: ret = quota_off(sb, type); goto out; case Q_GETQUOTA: - ret = get_quota(sb, id, type, (struct dqblk *) addr); + ret = get_quota(sb, id, type, (struct mem_dqblk *) addr); goto out; case Q_SETQUOTA: flags |= SET_QUOTA; @@ -1590,18 +2068,25 @@ case Q_GETSTATS: ret = get_stats(addr); goto out; - case Q_RSQUASH: - ret = quota_root_squash(sb, type, (int *) addr); + case Q_GETINFO: + ret = get_info(sb, type, (struct mem_dqinfo *) addr); goto out; + case Q_SETFLAGS: + ret = set_info(ISET_FLAGS, sb, type, (struct mem_dqinfo *)addr); + goto out; + case Q_SETGRACE: + ret = set_info(ISET_GRACE, sb, type, (struct mem_dqinfo *)addr); + goto out; + case Q_SETINFO: + ret = set_info(ISET_ALL, sb, type, (struct mem_dqinfo *)addr); + goto out; default: goto out; } - flags |= QUOTA_SYSCALL; - - ret = -ESRCH; + ret = -NODEV; if (sb && sb_has_quota_enabled(sb, type)) - ret = set_dqblk(sb, id, type, flags, (struct dqblk *) addr); + ret = set_dqblk(sb, id, type, flags, (struct mem_dqblk *) addr); out: unlock_kernel(); return ret; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/exec.c linux.ac/fs/exec.c --- linux.vanilla/fs/exec.c Tue Apr 3 17:32:25 2001 +++ linux.ac/fs/exec.c Tue Apr 3 17:55:11 2001 @@ -262,7 +262,7 @@ pte_t * pte; if (page_count(page) != 1) - printk("mem_map disagrees with %p at %08lx\n", page, address); + printk(KERN_ERR "mem_map disagrees with %p at %08lx\n", page, address); pgd = pgd_offset(tsk->mm, address); spin_lock(&tsk->mm->page_table_lock); @@ -786,6 +786,9 @@ } } #endif + /* kernel module loader fixup */ + /* so we don't try to load run modprobe in kernel space. */ + set_fs(USER_DS); for (try=0; try<2; try++) { read_lock(&binfmt_lock); for (fmt = formats ; fmt ; fmt = fmt->next) { @@ -920,16 +923,18 @@ int do_coredump(long signr, struct pt_regs * regs) { + struct mm_struct *mm; struct linux_binfmt * binfmt; - char corename[6+sizeof(current->comm)]; + char corename[6+sizeof(current->comm)+10]; struct file * file; struct inode * inode; + int r; lock_kernel(); binfmt = current->binfmt; if (!binfmt || !binfmt->core_dump) goto fail; - if (!current->dumpable || atomic_read(¤t->mm->mm_users) != 1) + if (!current->dumpable) goto fail; current->dumpable = 0; if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump) @@ -941,6 +946,8 @@ #else corename[4] = '\0'; #endif + if (atomic_read(¤t->mm->mm_users) != 1) + sprintf(&corename[4], ".%d", current->pid); file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW, 0600); if (IS_ERR(file)) goto fail; @@ -958,10 +965,29 @@ goto close_fail; if (do_truncate(file->f_dentry, 0) != 0) goto close_fail; - if (!binfmt->core_dump(signr, regs, file)) + /* + * Copy the mm structure to avoid potential races with + * other threads + */ + if ((mm = kmem_cache_alloc(mm_cachep, SLAB_KERNEL)) == NULL) + goto close_fail; + memcpy(mm, current->mm, sizeof(*mm)); + if (!mm_init(mm)) { + kmem_cache_free(mm_cachep, mm); + goto close_fail; + } + down_write(¤t->mm->mmap_sem); + r = dup_mmap(mm); + up_write(¤t->mm->mmap_sem); + if (r) { + mmput(mm); goto close_fail; + } + r = binfmt->core_dump(signr, regs, file, mm); + mmput(mm); unlock_kernel(); - filp_close(file, NULL); + if (r) + filp_close(file, NULL); return 1; close_fail: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ext2/balloc.c linux.ac/fs/ext2/balloc.c --- linux.vanilla/fs/ext2/balloc.c Fri Dec 29 22:36:44 2000 +++ linux.ac/fs/ext2/balloc.c Tue Apr 3 17:55:11 2001 @@ -247,7 +247,8 @@ return slot; } -void ext2_free_blocks (const struct inode * inode, unsigned long block, +/* Free given blocks, update quota and i_blocks field */ +void ext2_free_blocks (struct inode * inode, unsigned long block, unsigned long count) { struct buffer_head * bh; @@ -318,7 +319,7 @@ "bit already cleared for block %lu", block); else { - DQUOT_FREE_BLOCK(sb, inode, 1); + DQUOT_FREE_BLOCK(inode, 1); gdp->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)+1); es->s_free_blocks_count = @@ -351,8 +352,9 @@ * is allocated. Otherwise a forward search is made for a free block; within * each block group the search first looks for an entire free byte in the block * bitmap, and then for any free bit if that fails. + * This function also updates quota and i_blocks field. */ -int ext2_new_block (const struct inode * inode, unsigned long goal, +int ext2_new_block (struct inode * inode, unsigned long goal, u32 * prealloc_count, u32 * prealloc_block, int * err) { struct buffer_head * bh; @@ -513,7 +515,7 @@ /* * Check quota for allocation of this block. */ - if(DQUOT_ALLOC_BLOCK(sb, inode, 1)) { + if(DQUOT_ALLOC_BLOCK(inode, 1)) { *err = -EDQUOT; goto out; } @@ -531,7 +533,7 @@ if (ext2_set_bit (j, bh->b_data)) { ext2_warning (sb, "ext2_new_block", "bit already set for block %d", j); - DQUOT_FREE_BLOCK(sb, inode, 1); + DQUOT_FREE_BLOCK(inode, 1); goto repeat; } @@ -554,13 +556,13 @@ for (k = 1; k < prealloc_goal && (j + k) < EXT2_BLOCKS_PER_GROUP(sb); k++, next_block++) { - if (DQUOT_PREALLOC_BLOCK(sb, inode, 1)) + if (DQUOT_PREALLOC_BLOCK(inode, 1)) break; /* Writer: ->i_prealloc* */ if (*prealloc_block + *prealloc_count != next_block || ext2_set_bit (j + k, bh->b_data)) { /* Writer: end */ - DQUOT_FREE_BLOCK(sb, inode, 1); + DQUOT_FREE_BLOCK(inode, 1); break; } (*prealloc_count)++; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ext2/file.c linux.ac/fs/ext2/file.c --- linux.vanilla/fs/ext2/file.c Wed Sep 27 21:41:33 2000 +++ linux.ac/fs/ext2/file.c Tue Apr 3 17:55:11 2001 @@ -22,51 +22,6 @@ #include <linux/ext2_fs.h> #include <linux/sched.h> -static loff_t ext2_file_lseek(struct file *, loff_t, int); -static int ext2_open_file (struct inode *, struct file *); - -#define EXT2_MAX_SIZE(bits) \ - (((EXT2_NDIR_BLOCKS + (1LL << (bits - 2)) + \ - (1LL << (bits - 2)) * (1LL << (bits - 2)) + \ - (1LL << (bits - 2)) * (1LL << (bits - 2)) * (1LL << (bits - 2))) * \ - (1LL << bits)) - 1) - -static long long ext2_max_sizes[] = { -0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -EXT2_MAX_SIZE(10), EXT2_MAX_SIZE(11), EXT2_MAX_SIZE(12), EXT2_MAX_SIZE(13) -}; - -/* - * Make sure the offset never goes beyond the 32-bit mark.. - */ -static loff_t ext2_file_lseek( - struct file *file, - loff_t offset, - int origin) -{ - struct inode *inode = file->f_dentry->d_inode; - - switch (origin) { - case 2: - offset += inode->i_size; - break; - case 1: - offset += file->f_pos; - } - if (offset<0) - return -EINVAL; - if (((unsigned long long) offset >> 32) != 0) { - if (offset > ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(inode->i_sb)]) - return -EINVAL; - } - if (offset != file->f_pos) { - file->f_pos = offset; - file->f_reada = 0; - file->f_version = ++event; - } - return offset; -} - /* * Called when an inode is released. Note that this is different * from ext2_file_open: open gets called at every open, but release @@ -80,30 +35,15 @@ } /* - * Called when an inode is about to be open. - * We use this to disallow opening RW large files on 32bit systems if - * the caller didn't specify O_LARGEFILE. On 64bit systems we force - * on this flag in sys_open. - */ -static int ext2_open_file (struct inode * inode, struct file * filp) -{ - if (!(filp->f_flags & O_LARGEFILE) && - inode->i_size > 0x7FFFFFFFLL) - return -EFBIG; - return 0; -} - -/* * We have mostly NULL's here: the current defaults are ok for * the ext2 filesystem. */ struct file_operations ext2_file_operations = { - llseek: ext2_file_lseek, read: generic_file_read, write: generic_file_write, ioctl: ext2_ioctl, mmap: generic_file_mmap, - open: ext2_open_file, + open: generic_file_open, release: ext2_release_file, fsync: ext2_sync_file, }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ext2/ialloc.c linux.ac/fs/ext2/ialloc.c --- linux.vanilla/fs/ext2/ialloc.c Tue Apr 3 17:32:25 2001 +++ linux.ac/fs/ext2/ialloc.c Tue Apr 3 17:55:11 2001 @@ -194,7 +194,7 @@ * Note: we must free any quota before locking the superblock, * as writing the quota to disk may need the lock as well. */ - DQUOT_FREE_INODE(sb, inode); + DQUOT_FREE_INODE(inode); DQUOT_DROP(inode); lock_super (sb); @@ -451,8 +451,8 @@ mark_inode_dirty(inode); unlock_super (sb); - if(DQUOT_ALLOC_INODE(sb, inode)) { - sb->dq_op->drop(inode); + if(DQUOT_ALLOC_INODE(inode)) { + DQUOT_DROP(inode); inode->i_nlink = 0; iput(inode); return ERR_PTR(-EDQUOT); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ext2/inode.c linux.ac/fs/ext2/inode.c --- linux.vanilla/fs/ext2/inode.c Tue Apr 3 17:32:25 2001 +++ linux.ac/fs/ext2/inode.c Thu Apr 12 12:04:49 2001 @@ -28,6 +28,7 @@ #include <linux/smp_lock.h> #include <linux/sched.h> #include <linux/highuid.h> +#include <linux/quotaops.h> static int ext2_update_inode(struct inode * inode, int do_sync); @@ -449,7 +450,7 @@ /* Verify that place we are splicing to is still there and vacant */ - /* Writer: pointers, ->i_next_alloc*, ->i_blocks */ + /* Writer: pointers, ->i_next_alloc* */ if (!verify_chain(chain, where-1) || *where->p) /* Writer: end */ goto changed; @@ -459,7 +460,6 @@ *where->p = where->key; inode->u.ext2_i.i_next_alloc_block = block; inode->u.ext2_i.i_next_alloc_goal = le32_to_cpu(where[num-1].key); - inode->i_blocks += num * inode->i_sb->s_blocksize/512; /* Writer: end */ @@ -568,7 +568,7 @@ changed: while (partial > chain) { - bforget(partial->bh); + brelse(partial->bh); partial--; } goto reread; @@ -782,7 +782,6 @@ */ static inline void ext2_free_data(struct inode *inode, u32 *p, u32 *q) { - int blocks = inode->i_sb->s_blocksize / 512; unsigned long block_to_free = 0, count = 0; unsigned long nr; @@ -796,11 +795,8 @@ else if (block_to_free == nr - count) count++; else { - /* Writer: ->i_blocks */ - inode->i_blocks -= blocks * count; - /* Writer: end */ - ext2_free_blocks (inode, block_to_free, count); mark_inode_dirty(inode); + ext2_free_blocks (inode, block_to_free, count); free_this: block_to_free = nr; count = 1; @@ -808,11 +804,8 @@ } } if (count > 0) { - /* Writer: ->i_blocks */ - inode->i_blocks -= blocks * count; - /* Writer: end */ - ext2_free_blocks (inode, block_to_free, count); mark_inode_dirty(inode); + ext2_free_blocks (inode, block_to_free, count); } } @@ -855,9 +848,6 @@ (u32*)bh->b_data + addr_per_block, depth); bforget(bh); - /* Writer: ->i_blocks */ - inode->i_blocks -= inode->i_sb->s_blocksize / 512; - /* Writer: end */ ext2_free_blocks(inode, nr, 1); mark_inode_dirty(inode); } @@ -1258,10 +1248,14 @@ goto out; retval = inode_change_ok(inode, iattr); - if (retval != 0) + if (retval != 0 || (((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) || + (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) && + DQUOT_TRANSFER(inode, iattr))) goto out; - inode_setattr(inode, iattr); + retval = inode_setattr(inode, iattr); + if (retval) + goto out; flags = iattr->ia_attr_flags; if (flags & ATTR_FLAG_SYNCRONOUS) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ext2/super.c linux.ac/fs/ext2/super.c --- linux.vanilla/fs/ext2/super.c Fri Dec 29 22:36:44 2000 +++ linux.ac/fs/ext2/super.c Tue Apr 3 17:55:11 2001 @@ -380,6 +380,23 @@ } #define log2(n) ffz(~(n)) + +/* + * Maximal file size. There is a direct, and {,double-,triple-}indirect + * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks. + * We need to be 1 filesystem block less than the 2^32 sector limit. + */ +static loff_t ext2_max_size(int bits) +{ + loff_t res = EXT2_NDIR_BLOCKS; + res += 1LL << (bits-2); + res += 1LL << (2*(bits-2)); + res += 1LL << (3*(bits-2)); + res <<= bits; + if (res > (512LL << 32) - (1 << bits)) + res = (512LL << 32) - (1 << bits); + return res; +} struct super_block * ext2_read_super (struct super_block * sb, void * data, int silent) @@ -392,7 +409,7 @@ unsigned long logic_sb_block = 1; unsigned long offset = 0; kdev_t dev = sb->s_dev; - int blocksize = BLOCK_SIZE; + int blocksize; int hblock; int db_count; int i, j; @@ -404,11 +421,10 @@ * This is important for devices that have a hardware * sectorsize that is larger than the default. */ - blocksize = get_hardblocksize(dev); - if( blocksize == 0 || blocksize < BLOCK_SIZE ) - { - blocksize = BLOCK_SIZE; - } + blocksize = BLOCK_SIZE; + hblock = get_hardblocksize(dev); + if (blocksize < hblock) + blocksize = hblock; sb->u.ext2_sb.s_mount_opt = 0; if (!parse_options ((char *) data, &sb_block, &resuid, &resgid, @@ -475,17 +491,17 @@ sb->s_blocksize_bits = le32_to_cpu(EXT2_SB(sb)->s_es->s_log_block_size) + 10; sb->s_blocksize = 1 << sb->s_blocksize_bits; - if (sb->s_blocksize != BLOCK_SIZE && + + sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits); + + if (sb->s_blocksize != blocksize && (sb->s_blocksize == 1024 || sb->s_blocksize == 2048 || sb->s_blocksize == 4096)) { /* * Make sure the blocksize for the filesystem is larger * than the hardware sectorsize for the machine. */ - hblock = get_hardblocksize(dev); - if( (hblock != 0) - && (sb->s_blocksize < hblock) ) - { + if (sb->s_blocksize < hblock) { printk("EXT2-fs: blocksize too small for device.\n"); goto failed_mount; } @@ -628,13 +644,19 @@ */ sb->s_op = &ext2_sops; sb->s_root = d_alloc_root(iget(sb, EXT2_ROOT_INO)); - if (!sb->s_root) { + if (!sb->s_root || !S_ISDIR(sb->s_root->d_inode->i_mode) || + !sb->s_root->d_inode->i_blocks || !sb->s_root->d_inode->i_size) { + if (sb->s_root) { + dput(sb->s_root); + sb->s_root = NULL; + printk("EXT2-fs: corrupt root inode, run e2fsck\n"); + } else + printk("EXT2-fs: get root inode failed\n"); for (i = 0; i < db_count; i++) if (sb->u.ext2_sb.s_group_desc[i]) brelse (sb->u.ext2_sb.s_group_desc[i]); kfree(sb->u.ext2_sb.s_group_desc); brelse (bh); - printk ("EXT2-fs: get root inode failed\n"); return NULL; } ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/fat/Makefile linux.ac/fs/fat/Makefile --- linux.vanilla/fs/fat/Makefile Fri Dec 29 22:07:23 2000 +++ linux.ac/fs/fat/Makefile Tue Apr 3 17:55:11 2001 @@ -11,7 +11,7 @@ export-objs := fatfs_syms.o -obj-y := buffer.o cache.o dir.o file.o inode.o misc.o tables.o cvf.o fatfs_syms.o +obj-y := buffer.o cache.o dir.o file.o inode.o misc.o cvf.o fatfs_syms.o obj-m := $(O_TARGET) include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/fat/dir.c linux.ac/fs/fat/dir.c --- linux.vanilla/fs/fat/dir.c Tue Sep 5 22:07:29 2000 +++ linux.ac/fs/fat/dir.c Tue Apr 3 17:55:11 2001 @@ -65,7 +65,7 @@ while (*ip) { ec = *ip++; - if ( (charlen = nls->uni2char(ec, op, 3)) > 0) { + if ( (charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE)) > 0) { op += charlen; } else { if (uni_xlate == 1) { @@ -114,20 +114,44 @@ } static inline int -fat_short2lower_uni(struct nls_table *t, unsigned char c, wchar_t *uni) +fat_short2uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni) { int charlen; - unsigned char nc = t->charset2lower[c]; - - if (!nc) - nc = c; - if ( (charlen = t->char2uni(&nc, 1, uni)) < 0) { + charlen = t->char2uni(c, clen, uni); + if (charlen < 0) { *uni = 0x003f; /* a question mark */ + charlen = 1; } return charlen; } +static inline int +fat_short2lower_uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni) +{ + int charlen; + wchar_t wc; + + charlen = t->char2uni(c, clen, &wc); + if (charlen < 0) { + *uni = 0x003f; /* a question mark */ + charlen = 1; + } else if (charlen <= 1) { + unsigned char nc = t->charset2lower[*c]; + + if (!nc) + nc = *c; + + if ( (charlen = t->char2uni(&nc, 1, uni)) < 0) { + *uni = 0x003f; /* a question mark */ + charlen = 1; + } + } else + *uni = wc; + + return charlen; +} + static int fat_strnicmp(struct nls_table *t, const unsigned char *s1, const unsigned char *s2, int len) @@ -153,10 +177,11 @@ struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk; wchar_t bufuname[14]; unsigned char xlate_len, long_slots, *unicode = NULL; - char c, bufname[260]; /* 256 + 4 */ + char work[8], bufname[260]; /* 256 + 4 */ int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate; int utf8 = MSDOS_SB(sb)->options.utf8; - int ino, i, i2, last, res = 0; + int nocase = MSDOS_SB(sb)->options.nocase; + int ino, chl, i, j, last_u, res = 0; loff_t cpos = 0; while(1) { @@ -237,27 +262,49 @@ long_slots = 0; } - for (i = 0, last = 0; i < 8;) { - if (!(c = de->name[i])) break; - if (c == 0x05) c = 0xE5; - fat_short2lower_uni(nls_disk, c, &bufuname[i++]); - if (c != ' ') - last = i; + for (i = 0; i < 8; i++) { + /* see namei.c, msdos_format_name */ + if (de->name[i] == 0x05) + work[i] = 0xE5; + else + work[i] = de->name[i]; } - i = last; - fat_short2lower_uni(nls_disk, '.', &bufuname[i++]); - for (i2 = 0; i2 < 3; i2++) { - if (!(c = de->ext[i2])) break; - fat_short2lower_uni(nls_disk, c, &bufuname[i++]); - if (c != ' ') - last = i; + for (i = 0, j = 0, last_u = 0; i < 8;) { + if (!work[i]) break; + if (nocase) + chl = fat_short2uni(nls_disk, &work[i], 8 - i, &bufuname[j++]); + else + chl = fat_short2lower_uni(nls_disk, &work[i], 8 - i, &bufuname[j++]); + if (chl <= 1) { + if (work[i] != ' ') + last_u = j; + } else { + last_u = j; + } + i += chl; } - if (!last) + j = last_u; + fat_short2uni(nls_disk, ".", 1, &bufuname[j++]); + for (i = 0; i < 3;) { + if (!de->ext[i]) break; + if (nocase) + chl = fat_short2uni(nls_disk, &de->ext[i], 3 - i, &bufuname[j++]); + else + chl = fat_short2lower_uni(nls_disk, &de->ext[i], 3 - i, &bufuname[j++]); + if (chl <= 1) { + if (de->ext[i] != ' ') + last_u = j; + } else { + last_u = j; + } + i += chl; + } + if (!last_u) continue; - memset(&bufuname[last], 0, sizeof(wchar_t)); + bufuname[last_u] = 0x0000; xlate_len = utf8 - ?utf8_wcstombs(bufname, bufuname, 260) + ?utf8_wcstombs(bufname, bufuname, sizeof(bufname)) :uni16_to_x8(bufname, bufuname, uni_xlate, nls_io); if (xlate_len == name_len) if ((!anycase && !memcmp(name, bufname, xlate_len)) || @@ -267,7 +314,7 @@ if (long_slots) { xlate_len = utf8 - ?utf8_wcstombs(bufname, (wchar_t *) unicode, 260) + ?utf8_wcstombs(bufname, (wchar_t *) unicode, sizeof(bufname)) :uni16_to_x8(bufname, (wchar_t *) unicode, uni_xlate, nls_io); if (xlate_len != name_len) continue; @@ -298,15 +345,15 @@ struct msdos_dir_entry *de; struct nls_table *nls_io = MSDOS_SB(sb)->nls_io; struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk; - wchar_t bufuname[14], *ptuname = &bufuname[0]; + wchar_t bufuname[14]; unsigned char long_slots, *unicode = NULL; - char c, bufname[56], *ptname = bufname; + char c, work[8], bufname[56], *ptname = bufname; unsigned long lpos, dummy, *furrfu = &lpos; int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate; int isvfat = MSDOS_SB(sb)->options.isvfat; int utf8 = MSDOS_SB(sb)->options.utf8; int nocase = MSDOS_SB(sb)->options.nocase; - int ino,inum,i,i2,last, dotoffset = 0; + int ino, inum, chi, chl, i, i2, j, last, last_u, dotoffset = 0; loff_t cpos; cpos = filp->f_pos; @@ -414,33 +461,67 @@ } if ((de->attr & ATTR_HIDDEN) && MSDOS_SB(sb)->options.dotsOK) { - fat_short2lower_uni(nls_disk, '.', ptuname); *ptname++ = '.'; dotoffset = 1; } - for (i = 0, last = 0; i < 8;) { - if (!(c = de->name[i])) break; + + for (i = 0; i < 8; i++) { /* see namei.c, msdos_format_name */ - if (c == 0x05) c = 0xE5; - fat_short2lower_uni(nls_disk, c, &ptuname[i]); - ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c; - if (c != ' ') - last = i; + if (de->name[i] == 0x05) + work[i] = 0xE5; + else + work[i] = de->name[i]; + } + for (i = 0, j = 0, last = 0, last_u = 0; i < 8;) { + if (!(c = work[i])) break; + if (nocase) + chl = fat_short2uni(nls_disk, &work[i], 8 - i, &bufuname[j++]); + else + chl = fat_short2lower_uni(nls_disk, &work[i], 8 - i, &bufuname[j++]); + if (chl <= 1) { + ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c; + if (c != ' ') { + last = i; + last_u = j; + } + } else { + last_u = j; + for (chi = 0; chi < chl && i < 8; chi++) { + ptname[i] = work[i]; + i++; last = i; + } + } } i = last; - fat_short2lower_uni(nls_disk, '.', &ptuname[i]); + j = last_u; + fat_short2uni(nls_disk, ".", 1, &bufuname[j++]); ptname[i++] = '.'; - for (i2 = 0; i2 < 3; i2++) { + for (i2 = 0; i2 < 3;) { if (!(c = de->ext[i2])) break; - fat_short2lower_uni(nls_disk, c, &ptuname[i]); - ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c; - if (c != ' ') - last = i; + if (nocase) + chl = fat_short2uni(nls_disk, &de->ext[i2], 3 - i2, &bufuname[j++]); + else + chl = fat_short2lower_uni(nls_disk, &de->ext[i2], 3 - i2, &bufuname[j++]); + if (chl <= 1) { + i2++; + ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c; + if (c != ' ') { + last = i; + last_u = j; + } + } else { + last_u = j; + for (chi = 0; chi < chl && i2 < 3; chi++) { + ptname[i++] = de->ext[i2++]; + last = i; + } + } } if (!last) goto RecEnd; i = last + dotoffset; + j = last_u; lpos = cpos - (long_slots+1)*sizeof(struct msdos_dir_entry); if (!memcmp(de->name,MSDOS_DOT,11)) @@ -458,8 +539,8 @@ } if (isvfat) { - memset(&bufuname[i], 0, sizeof(wchar_t)); - i = utf8 ? utf8_wcstombs(bufname, bufuname, 56) + bufuname[j] = 0x0000; + i = utf8 ? utf8_wcstombs(bufname, bufuname, sizeof(bufname)) : uni16_to_x8(bufname, bufuname, uni_xlate, nls_io); } @@ -471,8 +552,8 @@ goto FillFailed; } else { char longname[275]; - unsigned char long_len = utf8 - ? utf8_wcstombs(longname, (wchar_t *) unicode, 275) + int long_len = utf8 + ? utf8_wcstombs(longname, (wchar_t *) unicode, sizeof(longname)) : uni16_to_x8(longname, (wchar_t *) unicode, uni_xlate, nls_io); if (both) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/fat/fatfs_syms.c linux.ac/fs/fat/fatfs_syms.c --- linux.vanilla/fs/fat/fatfs_syms.c Sun Jul 9 03:38:30 2000 +++ linux.ac/fs/fat/fatfs_syms.c Thu Apr 12 17:38:51 2001 @@ -14,7 +14,6 @@ #include <linux/fat_cvf.h> #include "msbuffer.h" -#include "tables.h" EXPORT_SYMBOL(fat_new_dir); EXPORT_SYMBOL(fat_get_block); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/fat/inode.c linux.ac/fs/fat/inode.c --- linux.vanilla/fs/fat/inode.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/fat/inode.c Tue Apr 3 17:55:11 2001 @@ -434,7 +434,7 @@ char *p; int data_sectors,logical_sector_size,sector_mult,fat_clusters=0; int debug,error,fat,cp; - int blksize = 512; + int blksize; int fat32; struct fat_mount_options opts; char buf[50]; @@ -448,14 +448,14 @@ sbi->private_data = NULL; sbi->dir_ops = fs_dir_inode_ops; - sb->s_op = &fat_sops; - if (hardsect_size[MAJOR(sb->s_dev)] != NULL){ - blksize = hardsect_size[MAJOR(sb->s_dev)][MINOR(sb->s_dev)]; - if (blksize != 512){ - printk ("MSDOS: Hardware sector size is %d\n",blksize); - } - } + sb->s_maxbytes = MAX_NON_LFS; + sb->s_op = &fat_sops; + blksize = get_hardsect_size(sb->s_dev); + if (!blksize) + blksize = 512; + if (blksize != 512) + printk ("MSDOS: Hardware sector size is %d\n",blksize); opts.isvfat = sbi->options.isvfat; if (!parse_options((char *) data, &fat, &blksize, &debug, &opts, @@ -925,7 +925,9 @@ if (error) return MSDOS_SB(sb)->options.quiet ? 0 : error; - inode_setattr(inode, attr); + error = inode_setattr(inode, attr); + if (error) + return error; if (IS_NOEXEC(inode) && !S_ISDIR(inode->i_mode)) inode->i_mode &= S_IFMT | S_IRUGO | S_IWUGO; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/file_table.c linux.ac/fs/file_table.c --- linux.vanilla/fs/file_table.c Tue Dec 5 18:27:31 2000 +++ linux.ac/fs/file_table.c Tue Apr 3 17:55:11 2001 @@ -66,10 +66,10 @@ goto new_one; } /* Big problems... */ - printk("VFS: filp allocation failed\n"); + printk(KERN_WARNING "VFS: filp allocation failed\n"); } else if (files_stat.max_files > old_max) { - printk("VFS: file-max limit %d reached\n", files_stat.max_files); + printk(KERN_INFO "VFS: file-max limit %d reached\n", files_stat.max_files); old_max = files_stat.max_files; } file_list_unlock(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/hfs/inode.c linux.ac/fs/hfs/inode.c --- linux.vanilla/fs/hfs/inode.c Tue Feb 13 22:13:45 2001 +++ linux.ac/fs/hfs/inode.c Tue Apr 3 17:55:11 2001 @@ -169,7 +169,9 @@ attr->ia_valid &= ~ATTR_SIZE; } } - inode_setattr(inode, attr); + error = inode_setattr(inode, attr); + if (error) + return error; /* We wouldn't want to mess with the sizes of the other fork */ attr->ia_valid &= ~ATTR_SIZE; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/hpfs/file.c linux.ac/fs/hpfs/file.c --- linux.vanilla/fs/hpfs/file.c Fri Dec 29 22:07:57 2000 +++ linux.ac/fs/hpfs/file.c Tue Apr 3 17:55:11 2001 @@ -11,6 +11,8 @@ #include <linux/smp_lock.h> #include "hpfs_fn.h" +#define BLOCKS(size) (((size) + 511) >> 9) + /* HUH? */ int hpfs_open(struct inode *i, struct file *f) { @@ -46,7 +48,7 @@ unsigned n, disk_secno; struct fnode *fnode; struct buffer_head *bh; - if (((inode->i_size + 511) >> 9) <= file_secno) return 0; + if (BLOCKS(inode->u.hpfs_i.mmu_private) <= file_secno) return 0; n = file_secno - inode->i_hpfs_file_sec; if (n < inode->i_hpfs_n_secs) return inode->i_hpfs_disk_sec + n; if (!(fnode = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh))) return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/hpfs/inode.c linux.ac/fs/hpfs/inode.c --- linux.vanilla/fs/hpfs/inode.c Mon Jan 22 18:40:47 2001 +++ linux.ac/fs/hpfs/inode.c Tue Apr 3 17:55:11 2001 @@ -299,10 +299,12 @@ { struct inode *inode = dentry->d_inode; int error; - if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size > inode->i_size) return -EINVAL; + if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size > inode->i_size) + return -EINVAL; if (inode->i_sb->s_hpfs_root == inode->i_ino) return -EINVAL; if ((error = inode_change_ok(inode, attr))) return error; - inode_setattr(inode, attr); + error = inode_setattr(inode, attr); + if (error) return error; hpfs_write_inode(inode); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/inode.c linux.ac/fs/inode.c --- linux.vanilla/fs/inode.c Tue Apr 3 17:32:25 2001 +++ linux.ac/fs/inode.c Tue Apr 3 17:55:11 2001 @@ -123,8 +123,9 @@ /** * __mark_inode_dirty - internal function * @inode: inode to mark - * - * Mark an inode as dirty. Callers should use mark_inode_dirty. + * @flags: what kind of dirty (i.e. I_DIRTY_SYNC) + * Mark an inode as dirty. Callers should use mark_inode_dirty or + * mark_inode_dirty_sync. */ void __mark_inode_dirty(struct inode *inode, int flags) @@ -303,7 +304,7 @@ spin_unlock(&inode_lock); } else - printk("write_inode_now: no super block\n"); + printk(KERN_ERR "write_inode_now: no super block\n"); } /** @@ -607,6 +608,8 @@ inode->i_nlink = 1; atomic_set(&inode->i_writecount, 0); inode->i_size = 0; + inode->i_blocks = 0; + inode->i_bytes = 0; inode->i_generation = 0; memset(&inode->i_dquot, 0, sizeof(inode->i_dquot)); inode->i_pipe = NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ioctl.c linux.ac/fs/ioctl.c --- linux.vanilla/fs/ioctl.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/ioctl.c Tue Apr 3 17:55:11 2001 @@ -101,6 +101,15 @@ filp->f_flags &= ~FASYNC; break; + case FIOQSIZE: + if (S_ISDIR(filp->f_dentry->d_inode->i_mode) || + S_ISREG(filp->f_dentry->d_inode->i_mode) || + S_ISLNK(filp->f_dentry->d_inode->i_mode)) + *(loff_t *)arg = inode_get_bytes(filp->f_dentry->d_inode); + else + error = -ENOTTY; + break; + default: error = -ENOTTY; if (S_ISREG(filp->f_dentry->d_inode->i_mode)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/isofs/inode.c linux.ac/fs/isofs/inode.c --- linux.vanilla/fs/isofs/inode.c Tue Apr 3 17:32:25 2001 +++ linux.ac/fs/isofs/inode.c Wed Apr 4 13:38:10 2001 @@ -753,6 +753,7 @@ s->s_op = &isofs_sops; s->u.isofs_sb.s_mapping = opt.map; s->u.isofs_sb.s_rock = (opt.rock == 'y' ? 2 : 0); + s->u.isofs_sb.s_rock_offset = -1; /* initial offset, will guess until SP is found*/ s->u.isofs_sb.s_cruft = opt.cruft; s->u.isofs_sb.s_unhide = opt.unhide; s->u.isofs_sb.s_uid = opt.uid; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/isofs/joliet.c linux.ac/fs/isofs/joliet.c --- linux.vanilla/fs/isofs/joliet.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/isofs/joliet.c Tue Apr 3 17:55:11 2001 @@ -10,6 +10,7 @@ #include <linux/nls.h> #include <linux/slab.h> #include <linux/iso_fs.h> +#include <asm/unaligned.h> /* * Convert Unicode 16 to UTF8 or ASCII. @@ -17,15 +18,15 @@ static int uni16_to_x8(unsigned char *ascii, u16 *uni, int len, struct nls_table *nls) { - wchar_t *ip; + wchar_t *ip, ch; unsigned char *op; ip = uni; op = ascii; - while (*ip && len) { + while ((ch = get_unaligned(ip)) && len) { int llen; - wchar_t ch = be16_to_cpu(*ip); + ch = be16_to_cpu(ch); if ((llen = nls->uni2char(ch, op, NLS_MAX_CHARSET_SIZE)) > 0) op += llen; else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/isofs/rock.c linux.ac/fs/isofs/rock.c --- linux.vanilla/fs/isofs/rock.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/isofs/rock.c Wed Apr 4 13:38:10 2001 @@ -31,8 +31,8 @@ use fields that is compatible with Rock Ridge */ #define CHECK_SP(FAIL) \ if(rr->u.SP.magic[0] != 0xbe) FAIL; \ - if(rr->u.SP.magic[1] != 0xef) FAIL; - + if(rr->u.SP.magic[1] != 0xef) FAIL; \ + inode->i_sb->u.isofs_sb.s_rock_offset=rr->u.SP.skip; /* We define a series of macros because each function must do exactly the same thing in certain places. We use the macros to ensure that everything is done correctly */ @@ -50,7 +50,14 @@ {LEN= sizeof(struct iso_directory_record) + DE->name_len[0]; \ if(LEN & 1) LEN++; \ CHR = ((unsigned char *) DE) + LEN; \ - LEN = *((unsigned char *) DE) - LEN;} + LEN = *((unsigned char *) DE) - LEN; \ + if (inode->i_sb->u.isofs_sb.s_rock_offset!=-1) \ + { \ + LEN-=inode->i_sb->u.isofs_sb.s_rock_offset; \ + CHR+=inode->i_sb->u.isofs_sb.s_rock_offset; \ + if (LEN<0) LEN=0; \ + } \ +} #define MAYBE_CONTINUE(LABEL,DEV) \ {if (buffer) kfree(buffer); \ @@ -220,8 +227,8 @@ return 0; } -int parse_rock_ridge_inode(struct iso_directory_record * de, - struct inode * inode){ +int parse_rock_ridge_inode_internal(struct iso_directory_record * de, + struct inode * inode,int regard_xa){ int len; unsigned char * chr; int symlink_len = 0; @@ -230,6 +237,13 @@ if (!inode->i_sb->u.isofs_sb.s_rock) return 0; SETUP_ROCK_RIDGE(de, chr, len); + if (regard_xa) + { + chr+=14; + len-=14; + if (len<0) len=0; + }; + repeat: { int cnt, sig; @@ -416,7 +430,7 @@ * If there is another SL record, and this component * record isn't continued, then add a slash. */ - if ((rr->u.SL.flags & 1) && !(oldslp->flags & 1)) + if ((!rootflag) && (rr->u.SL.flags & 1) && !(oldslp->flags & 1)) *rpnt++='/'; break; } @@ -431,6 +445,20 @@ return rpnt; } +int parse_rock_ridge_inode(struct iso_directory_record * de, + struct inode * inode) +{ + int result=parse_rock_ridge_inode_internal(de,inode,0); + /* if rockridge flag was reset and we didn't look for attributes + * behind eventual XA attributes, have a look there */ + if ((inode->i_sb->u.isofs_sb.s_rock_offset==-1) + &&(inode->i_sb->u.isofs_sb.s_rock==2)) + { + printk(KERN_DEBUG"scanning for RockRidge behind XA attributes\n"); + result=parse_rock_ridge_inode_internal(de,inode,14); + }; + return result; +}; /* readpage() for symlinks: reads symlink contents into the page and either makes it uptodate and returns 0 or returns error (-EIO) */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/jffs/inode-v23.c linux.ac/fs/jffs/inode-v23.c --- linux.vanilla/fs/jffs/inode-v23.c Tue Apr 3 17:32:25 2001 +++ linux.ac/fs/jffs/inode-v23.c Tue Apr 3 17:55:11 2001 @@ -327,6 +327,7 @@ struct super_block * sb; struct inode * inode; struct jffs_control *c; + struct jffs_file *f; sb = dir->i_sb; inode = new_inode(sb); @@ -350,8 +351,10 @@ inode->i_blksize = PAGE_SIZE; inode->i_blocks = (inode->i_size + 511) >> 9; inode->i_version = 0; - inode->u.generic_ip = (void *)jffs_find_file(c, raw_inode->ino); + f = jffs_find_file(c, raw_inode->ino); + + inode->u.generic_ip = (void *)f; insert_inode_hash(inode); return inode; @@ -577,10 +580,13 @@ filp->f_pos++; } f = ((struct jffs_file *)inode->u.generic_ip)->children; - for (j = 2; (j < filp->f_pos) && f; j++) { - f = f->sibling_next; + + j=2; + while(f && (f->deleted || j++ < filp->f_pos )) { + f = f->sibling_next; } - for (; f ; f = f->sibling_next) { + + while (f) { D3(printk("jffs_readdir(): \"%s\" ino: %u\n", (f->name ? f->name : ""), f->ino)); if (filldir(dirent, f->name, f->nsize, @@ -590,6 +596,9 @@ return 0; } filp->f_pos++; + do { + f = f->sibling_next; + } while(f && f->deleted); } D3(printk (KERN_NOTICE "readdir(): up biglock\n")); up(&c->fmc->biglock); @@ -929,11 +938,15 @@ } if (S_ISDIR(type)) { - if (del_f->children) { - result = -ENOTEMPTY; - goto jffs_remove_end; + struct jffs_file *child = del_f->children; + while(child) { + if( !child->deleted ) { + result = -ENOTEMPTY; + goto jffs_remove_end; + } + child = child->sibling_next; } - } + } else if (S_ISDIR(del_f->mode)) { D(printk("jffs_remove(): node is a directory " "but it shouldn't be.\n")); @@ -1000,9 +1013,6 @@ dir->i_ctime = dir->i_mtime = CURRENT_TIME; mark_inode_dirty(dir); inode->i_nlink--; - if (inode->i_nlink == 0) { - inode->u.generic_ip = 0; - } inode->i_ctime = dir->i_ctime; mark_inode_dirty(inode); @@ -1321,11 +1331,10 @@ struct jffs_node *node; struct dentry *dentry = filp->f_dentry; struct inode *inode = dentry->d_inode; - unsigned char *vbuf; int recoverable = 0; size_t written = 0; __u32 thiscount = count; - loff_t pos; + loff_t pos = *ppos; int err; inode = filp->f_dentry->d_inode; @@ -1334,20 +1343,13 @@ "filp: 0x%p, buf: 0x%p, count: %d\n", inode, inode->i_ino, filp, buf, count)); - err = filp->f_error; - if (err) { - filp->f_error = 0; - return err; - } - - down(&inode->i_sem); - +#if 0 if (inode->i_sb->s_flags & MS_RDONLY) { D(printk("jffs_file_write(): MS_RDONLY\n")); err = -EROFS; goto out_isem; } - +#endif err = -EINVAL; if (!S_ISREG(inode->i_mode)) { @@ -1364,23 +1366,17 @@ c = f->c; - if (filp->f_flags & O_APPEND) - pos = inode->i_size; - else - pos = *ppos; - - if (pos < 0) { - goto out_isem; - } + /* + * This will never trigger with sane page sizes. leave it in anyway, + * since I'm thinking about how to merge larger writes (the current idea + * is to poke a thread that does the actual I/O and starts by doing a + * down(&inode->i_sem). then we would need to get the page cache pages + * and have a list of I/O requests and do write-merging here. + * -- prumpf + */ thiscount = jffs_min(c->fmc->max_chunk_size - sizeof(struct jffs_raw_inode), count); - if (!(vbuf = kmalloc(thiscount, GFP_KERNEL))) { - D(printk("jffs_file_write(): failed to allocate bounce buffer. Fix me to use page cache\n")); - err = -ENOMEM; - goto out_isem; - } - D3(printk (KERN_NOTICE "file_write(): down biglock\n")); down(&c->fmc->biglock); @@ -1391,17 +1387,6 @@ * <_Anarchy_> posix and reality are not interconnected on this issue */ while (count) { - - /* FIXME: This is entirely gratuitous use of bounce buffers. - Get a clue and use the page cache. - /me wanders off to get a crash course on Linux VFS - dwmw2 - */ - if (copy_from_user(vbuf, buf, thiscount)) { - err = -EFAULT; - goto out; - } - /* Things are going to be written so we could allocate and initialize the necessary data structures now. */ if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node), @@ -1456,10 +1441,11 @@ smaller node than we were expecting. There's no need for it to waste the space at the end of the flash just because it's a little smaller than what we asked for. But that's a whole - new can of worms which I'm not going to open this week. dwmw2. + new can of worms which I'm not going to open this week. + -- dwmw2. */ if ((err = jffs_write_node(c, node, &raw_inode, f->name, - (const unsigned char *)vbuf, + (const unsigned char *)buf, recoverable, f)) < 0) { D(printk("jffs_file_write(): jffs_write_node() failed.\n")); kfree(node); @@ -1484,8 +1470,6 @@ out: D3(printk (KERN_NOTICE "file_write(): up biglock\n")); up(&c->fmc->biglock); - *ppos = pos; - kfree(vbuf); /* Fix things in the real inode. */ if (pos > inode->i_size) { @@ -1497,15 +1481,28 @@ invalidate_inode_pages(inode); out_isem: - up(&inode->i_sem); - - /* What if there was an error, _and_ we've written some data. */ - if (written) - return written; - else - return err; + return err; } /* jffs_file_write() */ +static ssize_t +jffs_prepare_write(struct file *filp, struct page *page, + unsigned from, unsigned to) +{ + /* FIXME: we should detect some error conditions here */ + + return 0; +} /* jffs_prepare_write() */ + +static ssize_t +jffs_commit_write(struct file *filp, struct page *page, + unsigned from, unsigned to) +{ + void *addr = page_address(page) + from; + /* XXX: PAGE_CACHE_SHIFT or PAGE_SHIFT */ + loff_t pos = (page->index<<PAGE_CACHE_SHIFT) + from; + + return jffs_file_write(filp, addr, to-from, &pos); +} /* jffs_commit_write() */ /* This is our ioctl() routine. */ static int @@ -1573,6 +1570,8 @@ static struct address_space_operations jffs_address_operations = { readpage: jffs_readpage, + prepare_write: jffs_prepare_write, + commit_write: jffs_commit_write, }; static int jffs_fsync(struct file *f, struct dentry *d, int datasync) @@ -1587,9 +1586,10 @@ static struct file_operations jffs_file_operations = { read: generic_file_read, /* read */ - write: jffs_file_write, /* write */ + write: generic_file_write, /* write */ ioctl: jffs_ioctl, /* ioctl */ mmap: generic_file_mmap, /* mmap */ + open: generic_file_open, fsync: jffs_fsync, }; @@ -1677,6 +1677,7 @@ jffs_read_data(f, (char *)&rdev, 0, sizeof(kdev_t)); init_special_inode(inode, inode->i_mode, kdev_t_to_nr(rdev)); } + D3(printk (KERN_NOTICE "read_inode(): up biglock\n")); up(&c->fmc->biglock); } @@ -1685,13 +1686,23 @@ void jffs_delete_inode(struct inode *inode) { - D3(printk("jffs_delete_inode(): inode->i_ino == %lu\n", + struct jffs_file *f; + struct jffs_control *c; + D1(printk("jffs_delete_inode(): inode->i_ino == %lu\n", inode->i_ino)); lock_kernel(); + inode->i_size = 0; inode->i_blocks = 0; + inode->u.generic_ip = 0; clear_inode(inode); + if (inode->i_nlink == 0) { + c = (struct jffs_control *) inode->i_sb->u.generic_sbp; + f = (struct jffs_file *) jffs_find_file (c, inode->i_ino); + jffs_possibly_delete_file(f); + } + unlock_kernel(); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/jffs/intrep.c linux.ac/fs/jffs/intrep.c --- linux.vanilla/fs/jffs/intrep.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/jffs/intrep.c Tue Apr 3 17:55:11 2001 @@ -10,8 +10,7 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * - Based on Id: intrep.c,v 1.71 2000/10/27 16:51:29 dwmw2 Exp - * - With the ctype() changes from v1.77. + * $Id: intrep.c,v 1.71.2.4 2001/01/08 23:27:02 dwmw2 Exp $ * * Ported to Linux 2.3.x and MTD: * Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB @@ -655,10 +654,10 @@ (or from start) */ if (start < (pos & ~(fmc->sector_size-1))) { - D1(printk("Reducing start to 0x%x from 0x%x\n", pos & ~(fmc->sector_size-1), start)); + D1(printk("Reducing start to 0x%lx from 0x%lx\n", (unsigned long)pos & ~(fmc->sector_size-1), (unsigned long)start)); start = pos & ~(fmc->sector_size-1); } - D1(printk("Dirty space: 0x%x for 0x%x bytes\n", start, (pos - start))); + D1(printk("Dirty space: 0x%lx for 0x%lx bytes\n", (unsigned long)start, (unsigned long)(pos - start))); jffs_fmalloced(fmc, (__u32) start, (__u32) (pos - start), 0); } @@ -1018,12 +1017,11 @@ f->atime = raw_inode->atime; f->mtime = raw_inode->mtime; f->ctime = raw_inode->ctime; - f->deleted = raw_inode->deleted; } else if ((f->highest_version < node->version) || (node->version == 0)) { /* Insert at the end of the list. I.e. this node is the - oldest one so far. */ + newest one so far. */ node->version_prev = f->version_tail; node->version_next = 0; f->version_tail->version_next = node; @@ -1037,7 +1035,6 @@ f->atime = raw_inode->atime; f->mtime = raw_inode->mtime; f->ctime = raw_inode->ctime; - f->deleted = raw_inode->deleted; } else if (f->version_head->version > node->version) { /* Insert at the bottom of the list. */ @@ -1048,9 +1045,6 @@ if (!f->name) { update_name = 1; } - if (raw_inode->deleted) { - f->deleted = raw_inode->deleted; - } } else { struct jffs_node *n; @@ -1074,6 +1068,11 @@ } } + /* Deletion is irreversible. If any 'deleted' node is ever + written, the file is deleted */ + if (raw_inode->deleted) + f->deleted = raw_inode->deleted; + /* Perhaps update the name. */ if (raw_inode->nsize && update_name && name && *name && (name != f->name)) { if (f->name) { @@ -1098,16 +1097,15 @@ if (insert_into_tree) { jffs_insert_file_into_tree(f); } - if (f->deleted) { - /* Mark all versions of the node as obsolete. */ - jffs_possibly_delete_file(f); - } - else { - if (node->data_size || node->removed_size) { - jffs_update_file(f, node); - } - jffs_remove_redundant_nodes(f); + /* Once upon a time, we would call jffs_possibly_delete_file() + here. That causes an oops if someone's still got the file + open, so now we only do it in jffs_delete_inode() + -- dwmw2 + */ + if (node->data_size || node->removed_size) { + jffs_update_file(f, node); } + jffs_remove_redundant_nodes(f); jffs_garbage_collect_trigger(c); @@ -1346,7 +1344,7 @@ D3(printk("jffs_find_child()\n")); for (f = dir->children; f; f = f->sibling_next) { - if (f->name + if (!f->deleted && f->name && !strncmp(f->name, name, len) && f->name[len] == '\0') { break; @@ -1588,6 +1586,8 @@ } pos += total_name_size; } + if (raw_inode->deleted) + f->deleted = 1; /* Step 3: Append the actual data, if any. */ if (raw_inode->dsize) { @@ -2669,8 +2669,8 @@ what's available */ if (size > JFFS_PAD(node->data_size) + total_name_size + sizeof(struct jffs_raw_inode) + extra_available) { - D1(printk("Reducing size of new node from %d to %ld to avoid " - "catching our tail\n", size, + D1(printk("Reducing size of new node from %d to %d to avoid " + "catching our tail\n", size, JFFS_PAD(node->data_size) + JFFS_PAD(node->name_size) + sizeof(struct jffs_raw_inode) + extra_available)); D1(printk("space_needed = %d, extra_available = %d\n", diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/lockd/clntlock.c linux.ac/fs/lockd/clntlock.c --- linux.vanilla/fs/lockd/clntlock.c Tue Nov 7 18:18:57 2000 +++ linux.ac/fs/lockd/clntlock.c Tue Apr 3 17:55:11 2001 @@ -138,7 +138,7 @@ void nlmclnt_recovery(struct nlm_host *host, u32 newstate) { - if (!host->h_reclaiming++) { + if (host->h_reclaiming++) { if (host->h_nsmstate == newstate) return; printk(KERN_WARNING diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/lockd/clntproc.c linux.ac/fs/lockd/clntproc.c --- linux.vanilla/fs/lockd/clntproc.c Mon Dec 4 02:01:01 2000 +++ linux.ac/fs/lockd/clntproc.c Tue Apr 3 17:55:11 2001 @@ -142,7 +142,11 @@ /* If we're cleaning up locks because the process is exiting, * perform the RPC call asynchronously. */ - if ((cmd == F_SETLK || cmd == F_SETLKW) + if ((cmd == F_SETLK || cmd == F_SETLKW +#if BITS_PER_LONG == 32 + || cmd == F_SETLK64 || cmd == F_SETLKW64 +#endif + ) && fl->fl_type == F_UNLCK && (current->flags & PF_EXITING)) { sigfillset(¤t->blocked); /* Mask all signals */ @@ -166,13 +170,29 @@ /* Set up the argument struct */ nlmclnt_setlockargs(call, fl); - if (cmd == F_GETLK) { + if (cmd == F_GETLK +#if BITS_PER_LONG == 32 + || cmd == F_GETLK64 +#endif + ) { status = nlmclnt_test(call, fl); - } else if ((cmd == F_SETLK || cmd == F_SETLKW) + } else if ((cmd == F_SETLK || cmd == F_SETLKW +#if BITS_PER_LONG == 32 + || cmd == F_SETLK64 || cmd == F_SETLKW64 +#endif + ) && fl->fl_type == F_UNLCK) { status = nlmclnt_unlock(call, fl); - } else if (cmd == F_SETLK || cmd == F_SETLKW) { - call->a_args.block = (cmd == F_SETLKW)? 1 : 0; + } else if (cmd == F_SETLK || cmd == F_SETLKW +#if BITS_PER_LONG == 32 + || cmd == F_SETLK64 || cmd == F_SETLKW64 +#endif + ) { + call->a_args.block = (cmd == F_SETLKW +#if BITS_PER_LONG == 32 + || cmd == F_SETLKW64 +#endif + )? 1 : 0; status = nlmclnt_lock(call, fl); } else { status = -EINVAL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/lockd/host.c linux.ac/fs/lockd/host.c --- linux.vanilla/fs/lockd/host.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/lockd/host.c Tue Apr 3 17:55:11 2001 @@ -51,7 +51,8 @@ struct nlm_host * nlmsvc_lookup_host(struct svc_rqst *rqstp) { - return nlm_lookup_host(rqstp->rq_client, &rqstp->rq_addr, 0, 0); + return nlm_lookup_host(rqstp->rq_client, &rqstp->rq_addr, + rqstp->rq_prot, rqstp->rq_vers); } /* @@ -97,7 +98,9 @@ nlm_gc_hosts(); for (hp = &nlm_hosts[hash]; (host = *hp); hp = &host->h_next) { - if (host->h_version != version || host->h_proto != proto) + if (proto && host->h_proto != proto) + continue; + if (version && host->h_version != version) continue; if (nlm_match_host(host, clnt, sin)) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/lockd/mon.c linux.ac/fs/lockd/mon.c --- linux.vanilla/fs/lockd/mon.c Mon Oct 16 20:58:51 2000 +++ linux.ac/fs/lockd/mon.c Tue Apr 3 17:55:11 2001 @@ -43,7 +43,7 @@ args.addr = host->h_addr.sin_addr.s_addr; args.prog = NLM_PROGRAM; - args.vers = 1; + args.vers = host->h_version; args.proc = NLMPROC_NSM_NOTIFY; memset(res, 0, sizeof(*res)); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/lockd/svc.c linux.ac/fs/lockd/svc.c --- linux.vanilla/fs/lockd/svc.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/lockd/svc.c Tue Apr 3 22:47:08 2001 @@ -76,9 +76,7 @@ nlmsvc_pid = current->pid; up(&lockd_start); - exit_mm(current); - current->session = 1; - current->pgrp = 1; + daemonize(); sprintf(current->comm, "lockd"); /* Process request with signals blocked. */ @@ -105,10 +103,10 @@ nlmsvc_grace_period = 10 * HZ; #else if (nlm_grace_period) { - nlmsvc_grace_period += (1 + nlm_grace_period / nlm_timeout) + nlmsvc_grace_period = (1 + nlm_grace_period / nlm_timeout) * nlm_timeout * HZ; } else { - nlmsvc_grace_period += 5 * nlm_timeout * HZ; + nlmsvc_grace_period = 5 * nlm_timeout * HZ; } #endif @@ -135,10 +133,12 @@ * (Theoretically, there shouldn't even be blocked locks * during grace period). */ - if (!nlmsvc_grace_period) { + if (!grace_period_expire) { timeout = nlmsvc_retry_blocked(); - } else if (time_before(nlmsvc_grace_period, jiffies)) + } else if (time_before(grace_period_expire, jiffies)) { + grace_period_expire = 0; nlmsvc_grace_period = 0; + } /* * Find a socket with data available and call its @@ -339,7 +339,7 @@ * Define NLM program and procedures */ static struct svc_version nlmsvc_version1 = { - 1, 16, nlmsvc_procedures, NULL + 1, 17, nlmsvc_procedures, NULL }; static struct svc_version nlmsvc_version3 = { 3, 24, nlmsvc_procedures, NULL diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/lockd/svc4proc.c linux.ac/fs/lockd/svc4proc.c --- linux.vanilla/fs/lockd/svc4proc.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/lockd/svc4proc.c Tue Apr 3 17:55:11 2001 @@ -420,6 +420,8 @@ void *resp) { struct sockaddr_in saddr = rqstp->rq_addr; + int vers = rqstp->rq_vers; + int prot = rqstp->rq_prot; struct nlm_host *host; dprintk("lockd: SM_NOTIFY called\n"); @@ -436,7 +438,7 @@ * reclaim all locks we hold on this server. */ saddr.sin_addr.s_addr = argp->addr; - if ((host = nlm_lookup_host(NULL, &saddr, IPPROTO_UDP, 1)) != NULL) { + if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) { nlmclnt_recovery(host, argp->state); nlm_release_host(host); } @@ -549,7 +551,8 @@ PROC(cancel_res, cancelres, norep, res, void), PROC(unlock_res, unlockres, norep, res, void), PROC(granted_res, grantedres, norep, res, void), - PROC(none, void, void, void, void), + /* statd callback */ + PROC(sm_notify, reboot, void, reboot, void), PROC(none, void, void, void, void), PROC(none, void, void, void, void), PROC(none, void, void, void, void), @@ -558,6 +561,4 @@ PROC(nm_lock, lockargs, res, args, res), PROC(free_all, notify, void, args, void), - /* statd callback */ - PROC(sm_notify, reboot, void, reboot, void), }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/lockd/svclock.c linux.ac/fs/lockd/svclock.c --- linux.vanilla/fs/lockd/svclock.c Tue Nov 7 18:18:57 2000 +++ linux.ac/fs/lockd/svclock.c Tue Apr 3 17:55:11 2001 @@ -237,6 +237,15 @@ if (unlock && block->b_granted) { dprintk("lockd: deleting granted lock\n"); fl->fl_type = F_UNLCK; + + /* If the filesystem defined its own lock operation, invoke it. */ + if ((block->b_file->f_file.f_op) && (block->b_file->f_file.f_op->lock)) + { + int error; + error = block->b_file->f_file.f_op->lock(&block->b_file->f_file, F_SETLK, fl); + dprintk("nlmsvc_delete_block: filesystem (un)lock operation returned %d\n", error); + } + posix_lock_file(&block->b_file->f_file, fl, 0); block->b_granted = 0; } else { @@ -319,7 +328,17 @@ again: if (!(conflock = posix_test_lock(&file->f_file, &lock->fl))) { - error = posix_lock_file(&file->f_file, &lock->fl, 0); + + /* If the filesystem defined its own lock operation, invoke it. */ + error = 0; + if ((file->f_file.f_op) && (file->f_file.f_op->lock)) + { + error = file->f_file.f_op->lock(&file->f_file, F_SETLK, &lock->fl); + dprintk("nlmsvc_lock: filesystem lock operation returned %d\n", error); + } + + if (error == 0) + error = posix_lock_file(&file->f_file, &lock->fl, 0); if (block) nlmsvc_delete_block(block, 0); @@ -348,6 +367,12 @@ return nlm_lck_denied; } + if (posix_locks_deadlock(&lock->fl, conflock)) + { + up(&file->f_sema); + return nlm_lck_denied; /* EDEADLK */ + } + /* If we don't have a block, create and initialize it. Then * retry because we may have slept in kmalloc. */ if (block == NULL) { @@ -357,6 +382,12 @@ goto again; } + if (!conflock) + { + printk("nlmsvc_lock: BUG! Trying to block without a conflock!\n"); + BUG(); + } + /* Append to list of blocked */ nlmsvc_insert_block(block, NLM_NEVER); @@ -387,6 +418,23 @@ (long long)lock->fl.fl_start, (long long)lock->fl.fl_end); + /* If the filesystem defined its own lock operation, invoke it. */ + if ((file->f_file.f_op) && (file->f_file.f_op->lock)) + { + int error; + + error = file->f_file.f_op->lock(&file->f_file, F_GETLK, &lock->fl); + if ((!error) && (lock->fl.fl_type != F_UNLCK)) + { + conflock->caller = "somehost"; /* FIXME */ + conflock->oh.len = 0; /* don't return OH info */ + conflock->fl = lock->fl; + dprintk("nlmsvc_testlock: filesystem (get)lock operation returned error %d type %d pid %d start %Ld end %Ld\n", + error, lock->fl.fl_type, lock->fl.fl_pid, lock->fl.fl_start, lock->fl.fl_end); + return nlm_lck_denied; + } + } + if ((fl = posix_test_lock(&file->f_file, &lock->fl)) != NULL) { dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n", fl->fl_type, (long long)fl->fl_start, @@ -423,7 +471,17 @@ nlmsvc_cancel_blocked(file, lock); lock->fl.fl_type = F_UNLCK; - error = posix_lock_file(&file->f_file, &lock->fl, 0); + + /* If the filesystem defined its own lock operation, invoke it. */ + error = 0; + if ((file->f_file.f_op) && (file->f_file.f_op->lock)) + { + error = file->f_file.f_op->lock(&file->f_file, F_SETLK, &lock->fl); + dprintk("nlmsvc_unlock: filesystem (un)lock operation returned error %d\n", error); + } + + if (error == 0) + error = posix_lock_file(&file->f_file, &lock->fl, 0); return (error < 0)? nlm_lck_denied_nolocks : nlm_granted; } @@ -515,6 +573,54 @@ } /* Try the lock operation again */ + + /* If the filesystem defined its own lock operation, invoke it. */ + if ((file->f_file.f_op) && (file->f_file.f_op->lock)) + { + struct file_lock getlock; + + /* save requestor lock inforation since GETLK will overwrite it */ + getlock.fl_pid = lock->fl.fl_pid; + getlock.fl_type = lock->fl.fl_type; + getlock.fl_start = lock->fl.fl_start; + getlock.fl_end = lock->fl.fl_end; + + error = file->f_file.f_op->lock(&file->f_file, F_GETLK, &lock->fl); + + /* restore requestor lock inforation. */ + lock->fl.fl_pid = getlock.fl_pid; + lock->fl.fl_type = getlock.fl_type; + lock->fl.fl_start = getlock.fl_start; + lock->fl.fl_end = getlock.fl_end; + + if ((!error) && (lock->fl.fl_type != F_UNLCK)) + { + dprintk("nlmsvc_grant_blocked: filesystem (get)lock operation returned error %d type %d pid %d start %Ld end %Ld\n", + error, lock->fl.fl_type, lock->fl.fl_pid, lock->fl.fl_start, lock->fl.fl_end); + dprintk("lockd: lock still blocked\n"); + + /* If the blocker is local and recorded in the vfs lock structures, use its + conflock to wait on. If the lock is denied due to the filesystem call, we + don't have a conflicting lock so retry in a while. */ + + if ((conflock = posix_test_lock(&file->f_file, &lock->fl)) != NULL) + { + nlmsvc_insert_block(block, NLM_NEVER); + posix_block_lock(conflock, &lock->fl); + up(&file->f_sema); + return; + } + else + { + dprintk("nlmsvc_grant_blocked: NO conflock RECORDED IN THE VFS!\n"); + nlmsvc_insert_block(block, jiffies + 30 * HZ); + up(&file->f_sema); + return; + } + + } + } + if ((conflock = posix_test_lock(&file->f_file, &lock->fl)) != NULL) { /* Bummer, we blocked again */ dprintk("lockd: lock still blocked\n"); @@ -528,6 +634,22 @@ * following yields an error, this is most probably due to low * memory. Retry the lock in a few seconds. */ + + /* If the filesystem defined its own lock operation, invoke it. */ + if ((file->f_file.f_op) && (file->f_file.f_op->lock)) + { + error = file->f_file.f_op->lock(&file->f_file, F_SETLK, &lock->fl); + dprintk("nlmsvc_grant_blocked: filesystem lock operation returned error %d\n", error); + if (error) + { + printk(KERN_WARNING "lockd: unexpected error %d in %s!\n", + error, __FUNCTION__); + nlmsvc_insert_block(block, jiffies + 10 * HZ); + up(&file->f_sema); + return; + } + } + if ((error = posix_lock_file(&file->f_file, &lock->fl, 0)) < 0) { printk(KERN_WARNING "lockd: unexpected error %d in %s!\n", -error, __FUNCTION__); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/lockd/svcproc.c linux.ac/fs/lockd/svcproc.c --- linux.vanilla/fs/lockd/svcproc.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/lockd/svcproc.c Tue Apr 3 17:55:11 2001 @@ -445,6 +445,8 @@ void *resp) { struct sockaddr_in saddr = rqstp->rq_addr; + int vers = rqstp->rq_vers; + int prot = rqstp->rq_prot; struct nlm_host *host; dprintk("lockd: SM_NOTIFY called\n"); @@ -460,8 +462,8 @@ /* Obtain the host pointer for this NFS server and try to * reclaim all locks we hold on this server. */ - saddr.sin_addr.s_addr = argp->addr; - if ((host = nlm_lookup_host(NULL, &saddr, IPPROTO_UDP, 1)) != NULL) { + saddr.sin_addr.s_addr = htonl(argp->addr); + if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) { nlmclnt_recovery(host, argp->state); nlm_release_host(host); } @@ -574,7 +576,8 @@ PROC(cancel_res, cancelres, norep, res, void), PROC(unlock_res, unlockres, norep, res, void), PROC(granted_res, grantedres, norep, res, void), - PROC(none, void, void, void, void), + /* statd callback */ + PROC(sm_notify, reboot, void, reboot, void), PROC(none, void, void, void, void), PROC(none, void, void, void, void), PROC(none, void, void, void, void), @@ -583,6 +586,4 @@ PROC(nm_lock, lockargs, res, args, res), PROC(free_all, notify, void, args, void), - /* statd callback */ - PROC(sm_notify, reboot, void, reboot, void), }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/locks.c linux.ac/fs/locks.c --- linux.vanilla/fs/locks.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/locks.c Tue Apr 3 17:55:11 2001 @@ -112,7 +112,7 @@ * * Leases and LOCK_MAND * Matthew Wilcox <willy@linuxcare.com>, June, 2000. - * Stephen Rothwell <sfr@linuxcare.com>, June, 2000. + * Stephen Rothwell <sfr@canb.auug.org.au>, June, 2000. */ #include <linux/slab.h> @@ -257,7 +257,7 @@ static int flock_to_posix_lock(struct file *filp, struct file_lock *fl, struct flock *l) { - loff_t start; + off_t start, end; switch (l->l_whence) { case 0: /*SEEK_SET*/ @@ -270,17 +270,16 @@ start = filp->f_dentry->d_inode->i_size; break; default: - return (0); + return -EINVAL; } if (((start += l->l_start) < 0) || (l->l_len < 0)) - return (0); - fl->fl_end = start + l->l_len - 1; - if (l->l_len > 0 && fl->fl_end < 0) - return (0); - if (fl->fl_end > OFFT_OFFSET_MAX) - return 0; + return -EINVAL; + end = start + l->l_len - 1; + if (l->l_len > 0 && end < 0) + return -EOVERFLOW; fl->fl_start = start; /* we record the absolute position */ + fl->fl_end = end; if (l->l_len == 0) fl->fl_end = OFFSET_MAX; @@ -292,7 +291,7 @@ fl->fl_insert = NULL; fl->fl_remove = NULL; - return (assign_type(fl, l->l_type) == 0); + return assign_type(fl, l->l_type); } #if BITS_PER_LONG == 32 @@ -312,14 +311,14 @@ start = filp->f_dentry->d_inode->i_size; break; default: - return (0); + return -EINVAL; } if (((start += l->l_start) < 0) || (l->l_len < 0)) - return (0); + return -EINVAL; fl->fl_end = start + l->l_len - 1; if (l->l_len > 0 && fl->fl_end < 0) - return (0); + return -EOVERFLOW; fl->fl_start = start; /* we record the absolute position */ if (l->l_len == 0) fl->fl_end = OFFSET_MAX; @@ -339,10 +338,10 @@ fl->fl_type = l->l_type; break; default: - return (0); + return -EINVAL; } - return (1); + return (0); } #endif @@ -532,7 +531,7 @@ return (1); default: - printk("locks_conflict(): impossible lock type - %d\n", + printk(KERN_ERR "locks_conflict(): impossible lock type - %d\n", caller_fl->fl_type); break; } @@ -644,7 +643,7 @@ * from a broken NFS client. But broken NFS clients have a lot more to * worry about than proper deadlock detection anyway... --okir */ -static int posix_locks_deadlock(struct file_lock *caller_fl, +int posix_locks_deadlock(struct file_lock *caller_fl, struct file_lock *block_fl) { struct list_head *tmp; @@ -1352,8 +1351,8 @@ if (!filp) goto out; - error = -EINVAL; - if (!flock_to_posix_lock(filp, &file_lock, &flock)) + error = flock_to_posix_lock(filp, &file_lock, &flock); + if (error) goto out_putf; if (filp->f_op && filp->f_op->lock) { @@ -1442,8 +1441,8 @@ } } - error = -EINVAL; - if (!flock_to_posix_lock(filp, file_lock, &flock)) + error = flock_to_posix_lock(filp, file_lock, &flock); + if (error) goto out_putf; error = -EBADF; @@ -1517,8 +1516,8 @@ if (!filp) goto out; - error = -EINVAL; - if (!flock64_to_posix_lock(filp, &file_lock, &flock)) + error = flock64_to_posix_lock(filp, &file_lock, &flock); + if (error) goto out_putf; if (filp->f_op && filp->f_op->lock) { @@ -1595,8 +1594,8 @@ } } - error = -EINVAL; - if (!flock64_to_posix_lock(filp, file_lock, &flock)) + error = flock64_to_posix_lock(filp, file_lock, &flock); + if (error) goto out_putf; error = -EBADF; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/minix/itree_common.c linux.ac/fs/minix/itree_common.c --- linux.vanilla/fs/minix/itree_common.c Thu Sep 28 03:23:40 2000 +++ linux.ac/fs/minix/itree_common.c Thu Apr 12 12:04:49 2001 @@ -201,7 +201,7 @@ changed: while (partial > chain) { - bforget(partial->bh); + brelse(partial->bh); partial--; } goto reread; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/msdos/namei.c linux.ac/fs/msdos/namei.c --- linux.vanilla/fs/msdos/namei.c Tue Sep 5 22:07:29 2000 +++ linux.ac/fs/msdos/namei.c Tue Apr 3 17:55:11 2001 @@ -389,7 +389,7 @@ return res; mkdir_error: - printk("msdos_mkdir: error=%d, attempting cleanup\n", res); + printk(KERN_WARNING "msdos_mkdir: error=%d, attempting cleanup\n", res); inode->i_nlink = 0; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; dir->i_nlink--; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/namei.c linux.ac/fs/namei.c --- linux.vanilla/fs/namei.c Tue Apr 3 17:32:25 2001 +++ linux.ac/fs/namei.c Tue Apr 3 17:55:11 2001 @@ -113,7 +113,7 @@ if ((unsigned long) filename >= TASK_SIZE) { if (!segment_eq(get_fs(), KERNEL_DS)) return -EFAULT; - } else if (TASK_SIZE - (unsigned long) filename < PAGE_SIZE) + } else if (TASK_SIZE - (unsigned long) filename < PATH_MAX + 1) len = TASK_SIZE - (unsigned long) filename; retval = strncpy_from_user((char *)page, filename, len); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ncpfs/inode.c linux.ac/fs/ncpfs/inode.c --- linux.vanilla/fs/ncpfs/inode.c Tue Apr 3 17:32:25 2001 +++ linux.ac/fs/ncpfs/inode.c Tue Apr 3 17:55:12 2001 @@ -693,7 +693,7 @@ ncp_inode_close(inode); result = ncp_make_closed(inode); if (!result) - vmtruncate(inode, attr->ia_size); + result = vmtruncate(inode, attr->ia_size); } out: return result; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfs/dir.c linux.ac/fs/nfs/dir.c --- linux.vanilla/fs/nfs/dir.c Tue Apr 3 17:32:25 2001 +++ linux.ac/fs/nfs/dir.c Sun Apr 15 23:04:43 2001 @@ -567,7 +567,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_flags); - if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { + if (test_bit(D_NFS_Renamed, &dentry->d_flags)) { /* Unhash it, so that ->d_iput() would be called */ return 1; } @@ -581,7 +581,7 @@ */ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) { - if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { + if (test_bit(D_NFS_Renamed, &dentry->d_flags)) { lock_kernel(); nfs_complete_unlink(dentry); unlock_kernel(); @@ -785,7 +785,7 @@ * We don't allow a dentry to be silly-renamed twice. */ error = -EBUSY; - if (dentry->d_flags & DCACHE_NFSFS_RENAMED) + if (test_bit(D_NFS_Renamed, &dentry->d_flags)) goto out; sprintf(silly, ".nfs%*.*lx", @@ -859,7 +859,7 @@ } /* If the dentry was sillyrenamed, we simply call d_delete() */ - if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { + if (test_bit(D_NFS_Renamed, &dentry->d_flags)) { error = 0; goto out_delete; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfs/flushd.c linux.ac/fs/nfs/flushd.c --- linux.vanilla/fs/nfs/flushd.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/nfs/flushd.c Tue Apr 10 18:19:26 2001 @@ -174,17 +174,17 @@ */ NFS_FLAGS(inode) |= NFS_INO_FLUSH; atomic_inc(&inode->i_count); - out: +out:; } +/* Protect me using the BKL */ void inode_remove_flushd(struct inode *inode) { struct nfs_reqlist *cache = NFS_REQUESTLIST(inode); struct inode **q; - lock_kernel(); if (!(NFS_FLAGS(inode) & NFS_INO_FLUSH)) - goto out; + return; q = &cache->inodes; while (*q && *q != inode) @@ -194,8 +194,6 @@ NFS_FLAGS(inode) &= ~NFS_INO_FLUSH; iput(inode); } - out: - unlock_kernel(); } void inode_schedule_scan(struct inode *inode, unsigned long time) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfs/inode.c linux.ac/fs/nfs/inode.c --- linux.vanilla/fs/nfs/inode.c Tue Apr 3 17:32:25 2001 +++ linux.ac/fs/nfs/inode.c Tue Apr 3 17:55:12 2001 @@ -240,7 +240,7 @@ struct nfs_server *server; struct rpc_xprt *xprt = NULL; struct rpc_clnt *clnt = NULL; - struct nfs_fh *root = &data->root, fh; + struct nfs_fh fh; struct inode *root_inode = NULL; unsigned int authflavor; struct sockaddr_in srvaddr; @@ -252,7 +252,6 @@ if (!data) goto out_miss_args; - memset(&fh, 0, sizeof(fh)); if (data->version != NFS_MOUNT_VERSION) { printk("nfs warning: mount version %s than kernel\n", data->version < NFS_MOUNT_VERSION ? "older" : "newer"); @@ -260,12 +259,21 @@ data->namlen = 0; if (data->version < 3) data->bsize = 0; - if (data->version < 4) { + if (data->version < 4) data->flags &= ~NFS_MOUNT_VER3; - root = &fh; - root->size = NFS2_FHSIZE; - memcpy(root->data, data->old_root.data, NFS2_FHSIZE); + } + + memset(&fh, 0, sizeof(fh)); + if (data->version < 4) { + fh.size = NFS2_FHSIZE; + memcpy(fh.data, data->old_root.data, NFS2_FHSIZE); + } else { + fh.size = (data->flags & NFS_MOUNT_VER3) ? data->root.size : NFS2_FHSIZE; + if (fh.size > sizeof(fh.data)) { + printk(KERN_WARNING "NFS: mount program passes invalid filehandle!\n"); + goto out_no_remote; } + memcpy(fh.data, data->root.data, fh.size); } /* We now require that the mount process passes the remote address */ @@ -364,9 +372,10 @@ * the root fh attributes. */ /* Did getting the root inode fail? */ - if (!(root_inode = nfs_get_root(sb, root)) + if (!(root_inode = nfs_get_root(sb, &fh)) && (data->flags & NFS_MOUNT_VER3)) { data->flags &= ~NFS_MOUNT_VER3; + fh.size = NFS2_FHSIZE; rpciod_down(); rpc_shutdown_client(server->client); goto nfsv3_try_again; @@ -381,7 +390,7 @@ sb->s_root->d_op = &nfs_dentry_operations; /* Get some general file system info */ - if (server->rpc_ops->statfs(server, root, &fsinfo) >= 0) { + if (server->rpc_ops->statfs(server, &fh, &fsinfo) >= 0) { if (server->namelen == 0) server->namelen = fsinfo.namelen; } else { @@ -439,6 +448,16 @@ else sb->s_maxbytes = ~0ULL; /* Unlimited on NFSv3 */ + if(version == 2) + sb->s_maxbytes = MAX_NON_LFS; + else + sb->s_maxbytes = ~0ULL; /* Unlimited on NFSv3 */ + + if(version == 2) + sb->s_maxbytes = MAX_NON_LFS; + else + sb->s_maxbytes = ~0ULL; /* Unlimited on NFSv3 */ + /* Fire up the writeback cache */ if (nfs_reqlist_alloc(server) < 0) { printk(KERN_NOTICE "NFS: cannot initialize writeback cache.\n"); @@ -739,7 +758,9 @@ if (attr->ia_size != fattr.size) printk("nfs_notify_change: attr=%Ld, fattr=%Ld??\n", (long long) attr->ia_size, (long long)fattr.size); - vmtruncate(inode, attr->ia_size); + error = vmtruncate(inode, attr->ia_size); + if (error) + goto out; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfs/mount_clnt.c linux.ac/fs/nfs/mount_clnt.c --- linux.vanilla/fs/nfs/mount_clnt.c Thu Apr 13 15:54:19 2000 +++ linux.ac/fs/nfs/mount_clnt.c Tue Apr 3 17:55:12 2001 @@ -31,32 +31,32 @@ */ static int nfs_gen_mount(struct sockaddr_in *, - char *, struct nfs_fh *, int); + char *, struct nfs3_fh *, int); static struct rpc_clnt * mnt_create(char *, struct sockaddr_in *, int); extern struct rpc_program mnt_program; struct mnt_fhstatus { unsigned int status; - struct nfs_fh * fh; + struct nfs3_fh * fh; }; /* * Obtain an NFS file handle for the given host and path */ int -nfs_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh) +nfs_mount(struct sockaddr_in *addr, char *path, struct nfs3_fh *fh) { return nfs_gen_mount(addr, path, fh, NFS_MNT_VERSION); } int -nfs3_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh) +nfs3_mount(struct sockaddr_in *addr, char *path, struct nfs3_fh *fh) { return nfs_gen_mount(addr, path, fh, NFS_MNT3_VERSION); } static int -nfs_gen_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, int version) +nfs_gen_mount(struct sockaddr_in *addr, char *path, struct nfs3_fh *fh, int version) { struct rpc_clnt *mnt_clnt; struct mnt_fhstatus result = { 0, fh }; @@ -120,7 +120,7 @@ static int xdr_decode_fhstatus(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res) { - struct nfs_fh *fh = res->fh; + struct nfs3_fh *fh = res->fh; memset((void *)fh, 0, sizeof(*fh)); if ((res->status = ntohl(*p++)) == 0) { @@ -133,7 +133,7 @@ static int xdr_decode_fhstatus3(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res) { - struct nfs_fh *fh = res->fh; + struct nfs3_fh *fh = res->fh; memset((void *)fh, 0, sizeof(*fh)); if ((res->status = ntohl(*p++)) == 0) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfs/read.c linux.ac/fs/nfs/read.c --- linux.vanilla/fs/nfs/read.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/nfs/read.c Tue Apr 10 18:19:32 2001 @@ -335,7 +335,9 @@ rpc_clnt_sigmask(clnt, &oldset); rpc_call_setup(task, &msg, 0); + lock_kernel(); rpc_execute(task); + unlock_kernel(); rpc_clnt_sigunmask(clnt, &oldset); return 0; out_bad: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfs/unlink.c linux.ac/fs/nfs/unlink.c --- linux.vanilla/fs/nfs/unlink.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/nfs/unlink.c Sun Apr 15 23:04:43 2001 @@ -179,7 +179,7 @@ task->tk_action = nfs_async_unlink_init; task->tk_release = nfs_async_unlink_release; - dentry->d_flags |= DCACHE_NFSFS_RENAMED; + set_bit(D_NFS_Renamed, &dentry->d_flags); data->cred = rpcauth_lookupcred(clnt->cl_auth, 0); rpc_sleep_on(&nfs_delete_queue, task, NULL, NULL); @@ -209,7 +209,7 @@ return; data->count++; nfs_copy_dname(dentry, data); - dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; + clear_bit(D_NFS_Renamed, &dentry->d_flags); if (data->task.tk_rpcwait == &nfs_delete_queue) rpc_wake_up_task(&data->task); nfs_put_unlinkdata(data); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfs/write.c linux.ac/fs/nfs/write.c --- linux.vanilla/fs/nfs/write.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/nfs/write.c Tue Apr 10 18:19:37 2001 @@ -183,7 +183,6 @@ if (file) cred = nfs_file_cred(file); - lock_kernel(); dprintk("NFS: nfs_writepage_sync(%x/%Ld %d@%Ld)\n", inode->i_dev, (long long)NFS_FILEID(inode), count, (long long)(page_offset(page) + offset)); @@ -228,7 +227,6 @@ io_error: kunmap(page); - unlock_kernel(); return written? written : result; } @@ -282,16 +280,17 @@ if (page->index >= end_index+1 || !offset) goto out; do_it: - if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) { + lock_kernel(); + if (NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) { err = nfs_writepage_async(NULL, inode, page, 0, offset); if (err >= 0) - goto out_ok; - } - err = nfs_writepage_sync(NULL, inode, page, 0, offset); - if ( err == offset) { -out_ok: - err = 0; + err = 0; + } else { + err = nfs_writepage_sync(NULL, inode, page, 0, offset); + if (err == offset) + err = 0; } + unlock_kernel(); out: UnlockPage(page); return err; @@ -1172,7 +1171,9 @@ rpc_clnt_sigmask(clnt, &oldset); rpc_call_setup(task, &msg, 0); + lock_kernel(); rpc_execute(task); + unlock_kernel(); rpc_clnt_sigunmask(clnt, &oldset); return 0; out_bad: @@ -1394,7 +1395,9 @@ dprintk("NFS: %4d initiated commit call\n", task->tk_pid); rpc_clnt_sigmask(clnt, &oldset); rpc_call_setup(task, &msg, 0); + lock_kernel(); rpc_execute(task); + unlock_kernel(); rpc_clnt_sigunmask(clnt, &oldset); return 0; out_bad: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfsd/nfsfh.c linux.ac/fs/nfsd/nfsfh.c --- linux.vanilla/fs/nfsd/nfsfh.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/nfsd/nfsfh.c Mon Apr 16 15:22:23 2001 @@ -154,7 +154,7 @@ spin_lock(&dcache_lock); for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) { result = list_entry(lp,struct dentry, d_alias); - if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) { + if (!test_bit(D_Disconnected, &result->d_flags)) { dget_locked(result); spin_unlock(&dcache_lock); iput(inode); @@ -167,7 +167,7 @@ iput(inode); return ERR_PTR(-ENOMEM); } - result->d_flags |= DCACHE_NFSD_DISCONNECTED; + set_bit(D_Disconnected, &result->d_flags); d_rehash(result); /* so a dput won't loose it */ return result; } @@ -182,7 +182,7 @@ #ifdef NFSD_PARANOIA if (!IS_ROOT(target)) printk("nfsd: d_splice with no-root target: %s/%s\n", parent->d_name.name, name->name); - if (!(target->d_flags & DCACHE_NFSD_DISCONNECTED)) + if (!test_bit(D_Disconnected, &target->d_flags)) printk("nfsd: d_splice with non-DISCONNECTED target: %s/%s\n", parent->d_name.name, name->name); #endif name->hash = full_name_hash(name->name, name->len); @@ -205,9 +205,9 @@ * the children are connected, but it must be a singluar (non-forking) * branch */ - if (!(parent->d_flags & DCACHE_NFSD_DISCONNECTED)) { + if (!test_bit(D_Disconnected, &parent->d_flags)) { while (target) { - target->d_flags &= ~DCACHE_NFSD_DISCONNECTED; + clear_bit(D_Disconnected, &target->d_flags); parent = target; spin_lock(&dcache_lock); if (list_empty(&parent->d_subdirs)) @@ -266,7 +266,7 @@ if (pdentry == NULL) { pdentry = d_alloc_root(igrab(tdentry->d_inode)); if (pdentry) { - pdentry->d_flags |= DCACHE_NFSD_DISCONNECTED; + set_bit(D_Disconnected, &pdentry->d_flags); d_rehash(pdentry); } } @@ -363,14 +363,14 @@ down(&sb->s_nfsd_free_path_sem); result = nfsd_iget(sb, ino, generation); if (IS_ERR(result) - || !(result->d_flags & DCACHE_NFSD_DISCONNECTED) + || !test_bit(D_Disconnected, &result->d_flags) || (!S_ISDIR(result->d_inode->i_mode) && ! needpath)) { up(&sb->s_nfsd_free_path_sem); err = PTR_ERR(result); if (IS_ERR(result)) goto err_out; - if ((result->d_flags & DCACHE_NFSD_DISCONNECTED)) + if (test_bit(D_Disconnected, &result->d_flags)) nfsdstats.fh_anon++; return result; } @@ -396,7 +396,7 @@ || !S_ISDIR(dentry->d_inode->i_mode)) { goto err_dentry; } - if (!(dentry->d_flags & DCACHE_NFSD_DISCONNECTED)) + if (!test_bit(D_Disconnected, &dentry->d_flags)) found = 1; tmp = splice(result, dentry); err = PTR_ERR(tmp); @@ -407,7 +407,7 @@ d_drop(result); dput(result); result = tmp; - /* If !found, then this is really wierd, but it shouldn't hurt */ + /* If !found, then this is really weird, but it shouldn't hurt */ } } } else { @@ -434,7 +434,7 @@ goto err_dentry; } - if (!(dentry->d_flags & DCACHE_NFSD_DISCONNECTED)) + if (!test_bit(D_Disconnected, &dentry->d_flags)) found = 1; tmp = splice(dentry, pdentry); @@ -603,7 +603,7 @@ } #ifdef NFSD_PARANOIA if (S_ISDIR(dentry->d_inode->i_mode) && - (dentry->d_flags & DCACHE_NFSD_DISCONNECTED)) { + test_bit(D_Disconnected, &dentry->d_flags)) { printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfsd/nfssvc.c linux.ac/fs/nfsd/nfssvc.c --- linux.vanilla/fs/nfsd/nfssvc.c Tue Apr 3 17:32:25 2001 +++ linux.ac/fs/nfsd/nfssvc.c Tue Apr 3 17:55:12 2001 @@ -117,7 +117,7 @@ return error; } -static void inline +static inline void update_thread_usage(int busy_threads) { unsigned long prev_call; @@ -253,7 +253,7 @@ return 0; case RC_REPLY: return 1; - case RC_DOIT: + case RC_DOIT:; /* do it */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfsd/vfs.c linux.ac/fs/nfsd/vfs.c --- linux.vanilla/fs/nfsd/vfs.c Tue Apr 3 17:32:26 2001 +++ linux.ac/fs/nfsd/vfs.c Tue Apr 3 17:55:12 2001 @@ -293,27 +293,11 @@ iap->ia_valid |= ATTR_CTIME; -#ifdef CONFIG_QUOTA - /* DQUOT_TRANSFER needs both ia_uid and ia_gid defined */ - if (iap->ia_valid & (ATTR_UID|ATTR_GID)) { - if (! (iap->ia_valid & ATTR_UID)) - iap->ia_uid = inode->i_uid; - if (! (iap->ia_valid & ATTR_GID)) - iap->ia_gid = inode->i_gid; - iap->ia_valid |= ATTR_UID|ATTR_GID; - } -#endif /* CONFIG_QUOTA */ - if (iap->ia_valid & ATTR_SIZE) { fh_lock(fhp); size_change = 1; } -#ifdef CONFIG_QUOTA - if (iap->ia_valid & (ATTR_UID|ATTR_GID)) - err = DQUOT_TRANSFER(dentry, iap); - else -#endif - err = notify_change(dentry, iap); + err = notify_change(dentry, iap); if (size_change) { fh_unlock(fhp); put_write_access(inode); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nls/Config.in linux.ac/fs/nls/Config.in --- linux.vanilla/fs/nls/Config.in Fri Dec 29 22:35:47 2000 +++ linux.ac/fs/nls/Config.in Tue Apr 10 18:19:53 2001 @@ -37,23 +37,26 @@ tristate 'Codepage 865 (Norwegian, Danish)' CONFIG_NLS_CODEPAGE_865 tristate 'Codepage 866 (Cyrillic/Russian)' CONFIG_NLS_CODEPAGE_866 tristate 'Codepage 869 (Greek)' CONFIG_NLS_CODEPAGE_869 - tristate 'Codepage 874 (Thai)' CONFIG_NLS_CODEPAGE_874 - tristate 'Codepage 932 (Shift-JIS, EUC-JP)' CONFIG_NLS_CODEPAGE_932 - tristate 'Codepage 936 (GBK)' CONFIG_NLS_CODEPAGE_936 - tristate 'Codepage 949 (UnifiedHangul)' CONFIG_NLS_CODEPAGE_949 - tristate 'Codepage 950 (Big5)' CONFIG_NLS_CODEPAGE_950 + tristate 'Simplified Chinese charset (CP936, GB2312)' CONFIG_NLS_CODEPAGE_936 + tristate 'Traditional Chinese charset (Big5)' CONFIG_NLS_CODEPAGE_950 + tristate 'Japanese charsets (Shift-JIS, EUC-JP)' CONFIG_NLS_CODEPAGE_932 + tristate 'Korean charset (CP949, EUC-KR)' CONFIG_NLS_CODEPAGE_949 + tristate 'Thai charset (CP874, TIS-620)' CONFIG_NLS_CODEPAGE_874 + tristate 'Hebrew charsets (ISO-8859-8, CP1255)' CONFIG_NLS_ISO8859_8 + tristate 'Windows CP1251 (Bulgarian, Belarussian)' CONFIG_NLS_CODEPAGE_1251 tristate 'NLS ISO 8859-1 (Latin 1; Western European Languages)' CONFIG_NLS_ISO8859_1 tristate 'NLS ISO 8859-2 (Latin 2; Slavic/Central European Languages)' CONFIG_NLS_ISO8859_2 tristate 'NLS ISO 8859-3 (Latin 3; Esperanto, Galician, Maltese, Turkish)' CONFIG_NLS_ISO8859_3 - tristate 'NLS ISO 8859-4 (Latin 4; Estonian, Latvian, Lithuanian)' CONFIG_NLS_ISO8859_4 + tristate 'NLS ISO 8859-4 (Latin 4; old Baltic charset)' CONFIG_NLS_ISO8859_4 tristate 'NLS ISO 8859-5 (Cyrillic)' CONFIG_NLS_ISO8859_5 tristate 'NLS ISO 8859-6 (Arabic)' CONFIG_NLS_ISO8859_6 tristate 'NLS ISO 8859-7 (Modern Greek)' CONFIG_NLS_ISO8859_7 - tristate 'NLS ISO 8859-8 (Hebrew)' CONFIG_NLS_ISO8859_8 tristate 'NLS ISO 8859-9 (Latin 5; Turkish)' CONFIG_NLS_ISO8859_9 + tristate 'NLS ISO 8859-13 (Latin 7; Baltic)' CONFIG_NLS_ISO8859_13 tristate 'NLS ISO 8859-14 (Latin 8; Celtic)' CONFIG_NLS_ISO8859_14 tristate 'NLS ISO 8859-15 (Latin 9; Western European Languages with Euro)' CONFIG_NLS_ISO8859_15 tristate 'NLS KOI8-R (Russian)' CONFIG_NLS_KOI8_R + tristate 'NLS KOI8-U (Ukrainian)' CONFIG_NLS_KOI8_U tristate 'NLS UTF8' CONFIG_NLS_UTF8 endmenu fi diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nls/Makefile linux.ac/fs/nls/Makefile --- linux.vanilla/fs/nls/Makefile Fri Dec 29 22:07:23 2000 +++ linux.ac/fs/nls/Makefile Tue Apr 10 18:19:53 2001 @@ -22,7 +22,7 @@ obj-$(CONFIG_NLS_CODEPAGE_865) += nls_cp865.o obj-$(CONFIG_NLS_CODEPAGE_866) += nls_cp866.o obj-$(CONFIG_NLS_CODEPAGE_869) += nls_cp869.o -obj-$(CONFIG_NLS_CODEPAGE_874) += nls_cp874.o +obj-$(CONFIG_NLS_CODEPAGE_874) += nls_cp874.o nls_tis-620.o obj-$(CONFIG_NLS_CODEPAGE_932) += nls_cp932.o nls_sjis.o nls_euc-jp.o obj-$(CONFIG_NLS_CODEPAGE_936) += nls_cp936.o nls_gb2312.o obj-$(CONFIG_NLS_CODEPAGE_949) += nls_cp949.o nls_euc-kr.o @@ -32,7 +32,6 @@ obj-$(CONFIG_NLS_CODEPAGE_1252) += nls_cp1252.o obj-$(CONFIG_NLS_CODEPAGE_1253) += nls_cp1253.o obj-$(CONFIG_NLS_CODEPAGE_1254) += nls_cp1254.o -obj-$(CONFIG_NLS_CODEPAGE_1255) += nls_cp1255.o obj-$(CONFIG_NLS_CODEPAGE_1256) += nls_cp1256.o obj-$(CONFIG_NLS_CODEPAGE_1257) += nls_cp1257.o obj-$(CONFIG_NLS_CODEPAGE_1258) += nls_cp1258.o @@ -43,12 +42,14 @@ obj-$(CONFIG_NLS_ISO8859_5) += nls_iso8859-5.o obj-$(CONFIG_NLS_ISO8859_6) += nls_iso8859-6.o obj-$(CONFIG_NLS_ISO8859_7) += nls_iso8859-7.o -obj-$(CONFIG_NLS_ISO8859_8) += nls_iso8859-8.o +obj-$(CONFIG_NLS_ISO8859_8) += nls_cp1255.o nls_iso8859-8.o obj-$(CONFIG_NLS_ISO8859_9) += nls_iso8859-9.o obj-$(CONFIG_NLS_ISO8859_10) += nls_iso8859-10.o +obj-$(CONFIG_NLS_ISO8859_13) += nls_iso8859-13.o obj-$(CONFIG_NLS_ISO8859_14) += nls_iso8859-14.o obj-$(CONFIG_NLS_ISO8859_15) += nls_iso8859-15.o obj-$(CONFIG_NLS_KOI8_R) += nls_koi8-r.o +obj-$(CONFIG_NLS_KOI8_U) += nls_koi8-u.o obj-$(CONFIG_NLS_ABC) += nls_abc.o obj-$(CONFIG_NLS_UTF8) += nls_utf8.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nls/nls_cp1251.c linux.ac/fs/nls/nls_cp1251.c --- linux.vanilla/fs/nls/nls_cp1251.c Thu Jan 1 01:00:00 1970 +++ linux.ac/fs/nls/nls_cp1251.c Tue Apr 10 18:19:53 2001 @@ -0,0 +1,317 @@ +/* + * linux/fs/nls_cp1251.c + * + * Charset cp1251 translation tables. + * Generated automatically from the Unicode and charset + * tables from the Unicode Organization (www.unicode.org). + * The Unicode to charset table has only exact mappings. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/nls.h> +#include <linux/errno.h> + +static wchar_t charset2uni[256] = { + /* 0x00*/ + 0x0000, 0x0001, 0x0002, 0x0003, + 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000a, 0x000b, + 0x000c, 0x000d, 0x000e, 0x000f, + /* 0x10*/ + 0x0010, 0x0011, 0x0012, 0x0013, + 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001a, 0x001b, + 0x001c, 0x001d, 0x001e, 0x001f, + /* 0x20*/ + 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, + 0x002c, 0x002d, 0x002e, 0x002f, + /* 0x30*/ + 0x0030, 0x0031, 0x0032, 0x0033, + 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, + 0x003c, 0x003d, 0x003e, 0x003f, + /* 0x40*/ + 0x0040, 0x0041, 0x0042, 0x0043, + 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, + 0x004c, 0x004d, 0x004e, 0x004f, + /* 0x50*/ + 0x0050, 0x0051, 0x0052, 0x0053, + 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, + 0x005c, 0x005d, 0x005e, 0x005f, + /* 0x60*/ + 0x0060, 0x0061, 0x0062, 0x0063, + 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, + 0x006c, 0x006d, 0x006e, 0x006f, + /* 0x70*/ + 0x0070, 0x0071, 0x0072, 0x0073, + 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, + 0x007c, 0x007d, 0x007e, 0x007f, + /* 0x80*/ + 0x0402, 0x0403, 0x201a, 0x0453, + 0x201e, 0x2026, 0x2020, 0x2021, + 0x20ac, 0x2030, 0x0409, 0x2039, + 0x040a, 0x040c, 0x040b, 0x040f, + /* 0x90*/ + 0x0452, 0x2018, 0x2019, 0x201c, + 0x201d, 0x2022, 0x2013, 0x2014, + 0x0000, 0x2122, 0x0459, 0x203a, + 0x045a, 0x045c, 0x045b, 0x045f, + /* 0xa0*/ + 0x00a0, 0x040e, 0x045e, 0x0408, + 0x00a4, 0x0490, 0x00a6, 0x00a7, + 0x0401, 0x00a9, 0x0404, 0x00ab, + 0x00ac, 0x00ad, 0x00ae, 0x0407, + /* 0xb0*/ + 0x00b0, 0x00b1, 0x0406, 0x0456, + 0x0491, 0x00b5, 0x00b6, 0x00b7, + 0x0451, 0x2116, 0x0454, 0x00bb, + 0x0458, 0x0405, 0x0455, 0x0457, + /* 0xc0*/ + 0x0410, 0x0411, 0x0412, 0x0413, + 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041a, 0x041b, + 0x041c, 0x041d, 0x041e, 0x041f, + /* 0xd0*/ + 0x0420, 0x0421, 0x0422, 0x0423, + 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042a, 0x042b, + 0x042c, 0x042d, 0x042e, 0x042f, + /* 0xe0*/ + 0x0430, 0x0431, 0x0432, 0x0433, + 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043a, 0x043b, + 0x043c, 0x043d, 0x043e, 0x043f, + /* 0xf0*/ + 0x0440, 0x0441, 0x0442, 0x0443, + 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044a, 0x044b, + 0x044c, 0x044d, 0x044e, 0x044f, +}; + +static unsigned char page00[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */ + 0x00, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0x00, 0x00, 0x00, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ + 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ + 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ + 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ + 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ + 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ + 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ +}; + +static unsigned char page04[256] = { + 0x00, 0xa8, 0x80, 0x81, 0xaa, 0xbd, 0xb2, 0xaf, /* 0x00-0x07 */ + 0xa3, 0x8a, 0x8c, 0x8e, 0x8d, 0x00, 0xa1, 0x8f, /* 0x08-0x0f */ + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0x10-0x17 */ + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0x18-0x1f */ + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0x20-0x27 */ + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0x28-0x2f */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0x30-0x37 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0x38-0x3f */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0x40-0x47 */ + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0x48-0x4f */ + 0x00, 0xb8, 0x90, 0x83, 0xba, 0xbe, 0xb3, 0xbf, /* 0x50-0x57 */ + 0xbc, 0x9a, 0x9c, 0x9e, 0x9d, 0x00, 0xa2, 0x9f, /* 0x58-0x5f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0xa5, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ +}; + +static unsigned char page20[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x91, 0x92, 0x82, 0x00, 0x93, 0x94, 0x84, 0x00, /* 0x18-0x1f */ + 0x86, 0x87, 0x95, 0x00, 0x00, 0x00, 0x85, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x8b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ +}; + +static unsigned char page21[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x00, /* 0x10-0x17 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ +}; + +static unsigned char *page_uni2charset[256] = { + page00, NULL, NULL, NULL, page04, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + page20, page21, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +static unsigned char charset2lower[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ + 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + 0x90, 0x83, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ + 0x88, 0x89, 0x9a, 0x8b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x88-0x8f */ + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ + 0xa0, 0xa2, 0xa2, 0xbc, 0xa4, 0xb4, 0xa6, 0xa7, /* 0xa0-0xa7 */ + 0xb8, 0xa9, 0xba, 0xab, 0xac, 0xad, 0xae, 0xbf, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0xb3, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbe, 0xbe, 0xbf, /* 0xb8-0xbf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xd0-0xd7 */ + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xd8-0xdf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ +}; + +static unsigned char charset2upper[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ + 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + 0x80, 0x81, 0x82, 0x81, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ + 0x80, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ + 0x98, 0x99, 0x8a, 0x9b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x98-0x9f */ + 0xa0, 0xa1, 0xa1, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0xb2, 0xb2, 0xa5, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ + 0xa8, 0xb9, 0xaa, 0xbb, 0xa3, 0xbd, 0xbd, 0xaf, /* 0xb8-0xbf */ + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xf0-0xf7 */ + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xf8-0xff */ +}; + +static int uni2char(wchar_t uni, unsigned char *out, int boundlen) +{ + unsigned char *uni2charset; + unsigned char cl = uni & 0x00ff; + unsigned char ch = (uni & 0xff00) >> 8; + + if (boundlen <= 0) + return -ENAMETOOLONG; + + uni2charset = page_uni2charset[ch]; + if (uni2charset && uni2charset[cl]) + out[0] = uni2charset[cl]; + else + return -EINVAL; + return 1; +} + +static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) +{ + *uni = charset2uni[*rawstring]; + if (*uni == 0x0000) + return -EINVAL; + return 1; +} + +static struct nls_table table = { + "cp1251", + uni2char, + char2uni, + charset2lower, + charset2upper, + THIS_MODULE, +}; + +static int __init init_nls_cp1251(void) +{ + return register_nls(&table); +} + +static void __exit exit_nls_cp1251(void) +{ + unregister_nls(&table); +} + +module_init(init_nls_cp1251) +module_exit(exit_nls_cp1251) + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nls/nls_cp1255.c linux.ac/fs/nls/nls_cp1255.c --- linux.vanilla/fs/nls/nls_cp1255.c Thu Jan 1 01:00:00 1970 +++ linux.ac/fs/nls/nls_cp1255.c Tue Apr 10 18:19:53 2001 @@ -0,0 +1,398 @@ +/* + * linux/fs/nls_cp1255.c + * + * Charset cp1255 translation tables. + * The Unicode to charset table has only exact mappings. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/nls.h> +#include <linux/errno.h> + +static wchar_t charset2uni[256] = { + /* 0x00*/ + 0x0000, 0x0001, 0x0002, 0x0003, + 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000a, 0x000b, + 0x000c, 0x000d, 0x000e, 0x000f, + /* 0x10*/ + 0x0010, 0x0011, 0x0012, 0x0013, + 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001a, 0x001b, + 0x001c, 0x001d, 0x001e, 0x001f, + /* 0x20*/ + 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, + 0x002c, 0x002d, 0x002e, 0x002f, + /* 0x30*/ + 0x0030, 0x0031, 0x0032, 0x0033, + 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, + 0x003c, 0x003d, 0x003e, 0x003f, + /* 0x40*/ + 0x0040, 0x0041, 0x0042, 0x0043, + 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, + 0x004c, 0x004d, 0x004e, 0x004f, + /* 0x50*/ + 0x0050, 0x0051, 0x0052, 0x0053, + 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, + 0x005c, 0x005d, 0x005e, 0x005f, + /* 0x60*/ + 0x0060, 0x0061, 0x0062, 0x0063, + 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, + 0x006c, 0x006d, 0x006e, 0x006f, + /* 0x70*/ + 0x0070, 0x0071, 0x0072, 0x0073, + 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, + 0x007c, 0x007d, 0x007e, 0x007f, + /* 0x80*/ + 0x20ac, 0x0000, 0x201a, 0x0192, + 0x201e, 0x2026, 0x2020, 0x2021, + 0x02c6, 0x2030, 0x0000, 0x2039, + 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x90*/ + 0x0000, 0x2018, 0x2019, 0x201c, + 0x201d, 0x2022, 0x2013, 0x2014, + 0x02dc, 0x2122, 0x0000, 0x203a, + 0x0000, 0x0000, 0x0000, 0x0000, + /* 0xa0*/ + 0x00a0, 0x00a1, 0x00a2, 0x00a3, + 0x20aa, 0x00a5, 0x00a6, 0x00a7, + 0x00a8, 0x00a9, 0x00d7, 0x00ab, + 0x00ac, 0x00ad, 0x00ae, 0x203e, + /* 0xb0*/ + 0x00b0, 0x00b1, 0x00b2, 0x00b3, + 0x00b4, 0x00b5, 0x00b6, 0x00b7, + 0x00b8, 0x00b9, 0x00f7, 0x00bb, + 0x00bc, 0x00bd, 0x00be, 0x00bf, + /* 0xc0*/ + 0x05b0, 0x05b1, 0x05b2, 0x05b3, + 0x05b4, 0x05b5, 0x05b6, 0x05b7, + 0x05b8, 0x05b9, 0x0000, 0x05bb, + 0x05bc, 0x05bd, 0x05be, 0x05bf, + /* 0xd0*/ + 0x05c0, 0x05c1, 0x05c2, 0x05c3, + 0x05f0, 0x05f1, 0x05f2, 0x05f3, + 0x05f4, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x2017, + /* 0xe0*/ + 0x05d0, 0x05d1, 0x05d2, 0x05d3, + 0x05d4, 0x05d5, 0x05d6, 0x05d7, + 0x05d8, 0x05d9, 0x05da, 0x05db, + 0x05dc, 0x05dd, 0x05de, 0x05df, + /* 0xf0*/ + 0x05e0, 0x05e1, 0x05e2, 0x05e3, + 0x05e4, 0x05e5, 0x05e6, 0x05e7, + 0x05e8, 0x05e9, 0x05ea, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static unsigned char page00[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0xa0, 0x00, 0xa2, 0xa3, 0x00, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ + 0xa8, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ + 0xb8, 0xb9, 0x00, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, /* 0xd0-0xd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, /* 0xf0-0xf7 */ +}; + +static unsigned char page01[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ +}; + +static unsigned char page02[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ + 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ +}; + +static unsigned char page05[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xb0-0xb7 */ + 0xc8, 0xc9, 0x00, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xb8-0xbf */ + 0xd0, 0xd1, 0xd2, 0xd3, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xd0-0xd7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xd8-0xdf */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xe0-0xe7 */ + 0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ + 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ +}; + +static unsigned char page20[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xfe, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x91, 0x92, 0x82, 0x00, 0x93, 0x94, 0x84, 0x00, /* 0x18-0x1f */ + 0x86, 0x87, 0x95, 0x00, 0x00, 0x00, 0x85, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x8b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ + 0x00, 0x00, 0xa4, 0x00, 0x80, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ +}; + +static unsigned char page21[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x00, /* 0x10-0x17 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ +}; + +static unsigned char *page_uni2charset[256] = { + page00, NULL, NULL, NULL, NULL, page05, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + page20, page21, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +static unsigned char charset2lower[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ + 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ + 0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ +}; + +static unsigned char charset2upper[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ + 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0x00, 0xb6, 0xb7, /* 0xb0-0xb7 */ + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ + 0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ +}; + +static int uni2char(wchar_t uni, unsigned char *out, int boundlen) +{ + unsigned char *uni2charset; + unsigned char cl = uni & 0x00ff; + unsigned char ch = (uni & 0xff00) >> 8; + + if (boundlen <= 0) + return -ENAMETOOLONG; + + uni2charset = page_uni2charset[ch]; + if (uni2charset && uni2charset[cl]) + out[0] = uni2charset[cl]; + else + return -EINVAL; + return 1; +} + +static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) +{ + *uni = charset2uni[*rawstring]; + if (*uni == 0x0000) + return -EINVAL; + return 1; +} + +static struct nls_table table = { + "cp1255", + uni2char, + char2uni, + charset2lower, + charset2upper, + THIS_MODULE, +}; + +static int __init init_nls_cp1255(void) +{ + return register_nls(&table); +} + +static void __exit exit_nls_cp1255(void) +{ + unregister_nls(&table); +} + +module_init(init_nls_cp1255) +module_exit(exit_nls_cp1255) + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nls/nls_cp932.c linux.ac/fs/nls/nls_cp932.c --- linux.vanilla/fs/nls/nls_cp932.c Fri Jul 21 23:19:51 2000 +++ linux.ac/fs/nls/nls_cp932.c Tue Apr 10 18:19:53 2001 @@ -7819,73 +7819,68 @@ }; static int uni2char(const wchar_t uni, - unsigned char *out, int boundlen) + unsigned char *out, int boundlen) { unsigned char *uni2charset; unsigned char cl = uni&0xFF; unsigned char ch = (uni>>8)&0xFF; - int n; if (boundlen <= 0) return -ENAMETOOLONG; if (ch == 0xFF && 0x61 <= cl && cl <= 0x9F) { out[0] = cl + 0x40; - n = 1; - return n; + return 1; } uni2charset = page_uni2charset[ch]; if (uni2charset) { - if (boundlen <= 1) + if (boundlen < 2) return -ENAMETOOLONG; + out[0] = uni2charset[cl*2]; out[1] = uni2charset[cl*2+1]; if (out[0] == 0x00 && out[1] == 0x00) return -EINVAL; - n = 2; - } else if (ch==0 && cl) { + return 2; + } else if ((ch == 0) && (cl <= 0x7F)) { out[0] = cl; - n = 1; + return 1; } else return -EINVAL; - - return n; } static int char2uni(const unsigned char *rawstring, int boundlen, - wchar_t *uni) + wchar_t *uni) { unsigned char ch, cl; wchar_t *charset2uni; - int n; if (boundlen <= 0) return -ENAMETOOLONG; - if (boundlen == 1) { + if (rawstring[0] <= 0x7F) { *uni = rawstring[0]; return 1; } + if (0xA1 <= rawstring[0] && rawstring[0] <= 0xDF) { + *uni = 0xFF00 | (rawstring[0] - 0x40); + return 1; + } + if (boundlen < 2) + return -ENAMETOOLONG; ch = rawstring[0]; cl = rawstring[1]; - if (0xA1 <= ch && ch <= 0xDF) { - *uni = 0xFF00 | (ch - 0x40); - n = 1; - return n; - } charset2uni = page_charset2uni[ch]; if (charset2uni && cl) { *uni = charset2uni[cl]; if (*uni == 0x0000) return -EINVAL; - n = 2; - } else{ - *uni = ch; - n = 1; + return 2; } - return n; + else + return -EINVAL; } static struct nls_table table = { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nls/nls_euc-jp.c linux.ac/fs/nls/nls_euc-jp.c --- linux.vanilla/fs/nls/nls_euc-jp.c Mon Oct 16 20:58:51 2000 +++ linux.ac/fs/nls/nls_euc-jp.c Tue Apr 10 18:19:53 2001 @@ -1,5 +1,9 @@ /* * linux/fs/nls_euc-jp.c + * + * Added `OSF/JVC Recommended Code Set Conversion Specification + * between Japanese EUC and Shift-JIS' support: <hirofumi@mail.parknet.co.jp> + * (http://www.opengroup.or.jp/jvc/cde/sjis-euc-e.html) */ #include <linux/module.h> @@ -10,49 +14,463 @@ static struct nls_table *p_nls; +#define IS_SJIS_LOW_BYTE(l) ((0x40 <= (l)) && ((l) <= 0xFC) && ((l) != 0x7F)) +/* JIS X 0208 (include NEC spesial characters) */ +#define IS_SJIS_JISX0208(h, l) ((((0x81 <= (h)) && ((h) <= 0x9F)) \ + || ((0xE0 <= (h)) && ((h) <= 0xEA))) \ + && IS_SJIS_LOW_BYTE(l)) +#define IS_SJIS_JISX0201KANA(c) ((0xA1 <= (c)) && ((c) <= 0xDF)) +#define IS_SJIS_UDC_LOW(h, l) (((0xF0 <= (h)) && ((h) <= 0xF4)) \ + && IS_SJIS_LOW_BYTE(l)) +#define IS_SJIS_UDC_HI(h, l) (((0xF5 <= (h)) && ((h) <= 0xF9)) \ + && IS_SJIS_LOW_BYTE(l)) +#define IS_SJIS_IBM(h, l) (((0xFA <= (h)) && ((h) <= 0xFC)) \ + && IS_SJIS_LOW_BYTE(l)) +#define IS_SJIS_NECIBM(h, l) (((0xED <= (h)) && ((h) <= 0xEE)) \ + && IS_SJIS_LOW_BYTE(l)) +#define MAP_SJIS2EUC(sjis_hi, sjis_lo, sjis_p, euc_hi, euc_lo, euc_p) { \ + if ((sjis_lo) >= 0x9F) { \ + (euc_hi) = (sjis_hi) * 2 - (((sjis_p) * 2 - (euc_p)) - 1); \ + (euc_lo) = (sjis_lo) + 2; \ + } else { \ + (euc_hi) = (sjis_hi) * 2 - ((sjis_p) * 2 - (euc_p)); \ + (euc_lo) = (sjis_lo) + ((sjis_lo) >= 0x7F ? 0x60 : 0x61); \ + } \ +} while(0) #define SS2 (0x8E) /* Single Shift 2 */ #define SS3 (0x8F) /* Single Shift 3 */ +#define IS_EUC_BYTE(c) ((0xA1 <= (c)) && ((c) <= 0xFE)) +#define IS_EUC_JISX0208(h, l) (IS_EUC_BYTE(h) && IS_EUC_BYTE(l)) +#define IS_EUC_JISX0201KANA(h, l) (((h) == SS2) && (0xA1 <= (l) && (l) <= 0xDF)) +#define IS_EUC_UDC_LOW(h, l) (((0xF5 <= (h)) && ((h) <= 0xFE)) \ + && IS_EUC_BYTE(l)) +#define IS_EUC_UDC_HI(h, l) IS_EUC_UDC_LOW(h, l) /* G3 block */ +#define MAP_EUC2SJIS(euc_hi, euc_lo, euc_p, sjis_hi, sjis_lo, sjis_p) { \ + if ((euc_hi) & 1) { \ + (sjis_hi) = (euc_hi) / 2 + ((sjis_p) - (euc_p) / 2); \ + (sjis_lo) = (euc_lo) - ((euc_lo) >= 0xE0 ? 0x60 : 0x61); \ + } else { \ + (sjis_hi) = (euc_hi) / 2 + (((sjis_p) - (euc_p) / 2) - 1); \ + (sjis_lo) = (euc_lo) - 2; \ + } \ +} while(0) + +/* SJIS IBM extended characters to EUC map */ +static unsigned char sjisibm2euc_map[][2] = { + {0xF3, 0xF3}, {0xF3, 0xF4}, {0xF3, 0xF5}, {0xF3, 0xF6}, {0xF3, 0xF7}, + {0xF3, 0xF8}, {0xF3, 0xF9}, {0xF3, 0xFA}, {0xF3, 0xFB}, {0xF3, 0xFC}, + {0xF3, 0xFD}, {0xF3, 0xFE}, {0xF4, 0xA1}, {0xF4, 0xA2}, {0xF4, 0xA3}, + {0xF4, 0xA4}, {0xF4, 0xA5}, {0xF4, 0xA6}, {0xF4, 0xA7}, {0xF4, 0xA8}, + {0xA2, 0xCC}, {0xA2, 0xC3}, {0xF4, 0xA9}, {0xF4, 0xAA}, {0xF4, 0xAB}, + {0xF4, 0xAC}, {0xF4, 0xAD}, {0xA2, 0xE8}, {0xD4, 0xE3}, {0xDC, 0xDF}, + {0xE4, 0xE9}, {0xE3, 0xF8}, {0xD9, 0xA1}, {0xB1, 0xBB}, {0xF4, 0xAE}, + {0xC2, 0xAD}, {0xC3, 0xFC}, {0xE4, 0xD0}, {0xC2, 0xBF}, {0xBC, 0xF4}, + {0xB0, 0xA9}, {0xB0, 0xC8}, {0xF4, 0xAF}, {0xB0, 0xD2}, {0xB0, 0xD4}, + {0xB0, 0xE3}, {0xB0, 0xEE}, {0xB1, 0xA7}, {0xB1, 0xA3}, {0xB1, 0xAC}, + {0xB1, 0xA9}, {0xB1, 0xBE}, {0xB1, 0xDF}, {0xB1, 0xD8}, {0xB1, 0xC8}, + {0xB1, 0xD7}, {0xB1, 0xE3}, {0xB1, 0xF4}, {0xB1, 0xE1}, {0xB2, 0xA3}, + {0xF4, 0xB0}, {0xB2, 0xBB}, {0xB2, 0xE6}, {0x00, 0x00}, {0xB2, 0xED}, + {0xB2, 0xF5}, {0xB2, 0xFC}, {0xF4, 0xB1}, {0xB3, 0xB5}, {0xB3, 0xD8}, + {0xB3, 0xDB}, {0xB3, 0xE5}, {0xB3, 0xEE}, {0xB3, 0xFB}, {0xF4, 0xB2}, + {0xF4, 0xB3}, {0xB4, 0xC0}, {0xB4, 0xC7}, {0xB4, 0xD0}, {0xB4, 0xDE}, + {0xF4, 0xB4}, {0xB5, 0xAA}, {0xF4, 0xB5}, {0xB5, 0xAF}, {0xB5, 0xC4}, + {0xB5, 0xE8}, {0xF4, 0xB6}, {0xB7, 0xC2}, {0xB7, 0xE4}, {0xB7, 0xE8}, + {0xB7, 0xE7}, {0xF4, 0xB7}, {0xF4, 0xB8}, {0xF4, 0xB9}, {0xB8, 0xCE}, + {0xB8, 0xE1}, {0xB8, 0xF5}, {0xB8, 0xF7}, {0xB8, 0xF8}, {0xB8, 0xFC}, + {0xB9, 0xAF}, {0xB9, 0xB7}, {0xBA, 0xBE}, {0xBA, 0xDB}, {0xCD, 0xAA}, + {0xBA, 0xE1}, {0xF4, 0xBA}, {0xBA, 0xEB}, {0xBB, 0xB3}, {0xBB, 0xB8}, + {0xF4, 0xBB}, {0xBB, 0xCA}, {0xF4, 0xBC}, {0xF4, 0xBD}, {0xBB, 0xD0}, + {0xBB, 0xDE}, {0xBB, 0xF4}, {0xBB, 0xF5}, {0xBB, 0xF9}, {0xBC, 0xE4}, + {0xBC, 0xED}, {0xBC, 0xFE}, {0xF4, 0xBE}, {0xBD, 0xC2}, {0xBD, 0xE7}, + {0xF4, 0xBF}, {0xBD, 0xF0}, {0xBE, 0xB0}, {0xBE, 0xAC}, {0xF4, 0xC0}, + {0xBE, 0xB3}, {0xBE, 0xBD}, {0xBE, 0xCD}, {0xBE, 0xC9}, {0xBE, 0xE4}, + {0xBF, 0xA8}, {0xBF, 0xC9}, {0xC0, 0xC4}, {0xC0, 0xE4}, {0xC0, 0xF4}, + {0xC1, 0xA6}, {0xF4, 0xC1}, {0xC1, 0xF5}, {0xC1, 0xFC}, {0xF4, 0xC2}, + {0xC1, 0xF8}, {0xC2, 0xAB}, {0xC2, 0xA1}, {0xC2, 0xA5}, {0xF4, 0xC3}, + {0xC2, 0xB8}, {0xC2, 0xBA}, {0xF4, 0xC4}, {0xC2, 0xC4}, {0xC2, 0xD2}, + {0xC2, 0xD7}, {0xC2, 0xDB}, {0xC2, 0xDE}, {0xC2, 0xED}, {0xC2, 0xF0}, + {0xF4, 0xC5}, {0xC3, 0xA1}, {0xC3, 0xB5}, {0xC3, 0xC9}, {0xC3, 0xB9}, + {0xF4, 0xC6}, {0xC3, 0xD8}, {0xC3, 0xFE}, {0xF4, 0xC7}, {0xC4, 0xCC}, + {0xF4, 0xC8}, {0xC4, 0xD9}, {0xC4, 0xEA}, {0xC4, 0xFD}, {0xF4, 0xC9}, + {0xC5, 0xA7}, {0xC5, 0xB5}, {0xC5, 0xB6}, {0xF4, 0xCA}, {0xC5, 0xD5}, + {0xC6, 0xB8}, {0xC6, 0xD7}, {0xC6, 0xE0}, {0xC6, 0xEA}, {0xC6, 0xE3}, + {0xC7, 0xA1}, {0xC7, 0xAB}, {0xC7, 0xC7}, {0xC7, 0xC3}, {0xC7, 0xCB}, + {0xC7, 0xCF}, {0xC7, 0xD9}, {0xF4, 0xCB}, {0xF4, 0xCC}, {0xC7, 0xE6}, + {0xC7, 0xEE}, {0xC7, 0xFC}, {0xC7, 0xEB}, {0xC7, 0xF0}, {0xC8, 0xB1}, + {0xC8, 0xE5}, {0xC8, 0xF8}, {0xC9, 0xA6}, {0xC9, 0xAB}, {0xC9, 0xAD}, + {0xF4, 0xCD}, {0xC9, 0xCA}, {0xC9, 0xD3}, {0xC9, 0xE9}, {0xC9, 0xE3}, + {0xC9, 0xFC}, {0xC9, 0xF4}, {0xC9, 0xF5}, {0xF4, 0xCE}, {0xCA, 0xB3}, + {0xCA, 0xBD}, {0xCA, 0xEF}, {0xCA, 0xF1}, {0xCB, 0xAE}, {0xF4, 0xCF}, + {0xCB, 0xCA}, {0xCB, 0xE6}, {0xCB, 0xEA}, {0xCB, 0xF0}, {0xCB, 0xF4}, + {0xCB, 0xEE}, {0xCC, 0xA5}, {0xCB, 0xF9}, {0xCC, 0xAB}, {0xCC, 0xAE}, + {0xCC, 0xAD}, {0xCC, 0xB2}, {0xCC, 0xC2}, {0xCC, 0xD0}, {0xCC, 0xD9}, + {0xF4, 0xD0}, {0xCD, 0xBB}, {0xF4, 0xD1}, {0xCE, 0xBB}, {0xF4, 0xD2}, + {0xCE, 0xBA}, {0xCE, 0xC3}, {0xF4, 0xD3}, {0xCE, 0xF2}, {0xB3, 0xDD}, + {0xCF, 0xD5}, {0xCF, 0xE2}, {0xCF, 0xE9}, {0xCF, 0xED}, {0xF4, 0xD4}, + {0xF4, 0xD5}, {0xF4, 0xD6}, {0x00, 0x00}, {0xF4, 0xD7}, {0xD0, 0xE5}, + {0xF4, 0xD8}, {0xD0, 0xE9}, {0xD1, 0xE8}, {0xF4, 0xD9}, {0xF4, 0xDA}, + {0xD1, 0xEC}, {0xD2, 0xBB}, {0xF4, 0xDB}, {0xD3, 0xE1}, {0xD3, 0xE8}, + {0xD4, 0xA7}, {0xF4, 0xDC}, {0xF4, 0xDD}, {0xD4, 0xD4}, {0xD4, 0xF2}, + {0xD5, 0xAE}, {0xF4, 0xDE}, {0xD7, 0xDE}, {0xF4, 0xDF}, {0xD8, 0xA2}, + {0xD8, 0xB7}, {0xD8, 0xC1}, {0xD8, 0xD1}, {0xD8, 0xF4}, {0xD9, 0xC6}, + {0xD9, 0xC8}, {0xD9, 0xD1}, {0xF4, 0xE0}, {0xF4, 0xE1}, {0xF4, 0xE2}, + {0xF4, 0xE3}, {0xF4, 0xE4}, {0xDC, 0xD3}, {0xDD, 0xC8}, {0xDD, 0xD4}, + {0xDD, 0xEA}, {0xDD, 0xFA}, {0xDE, 0xA4}, {0xDE, 0xB0}, {0xF4, 0xE5}, + {0xDE, 0xB5}, {0xDE, 0xCB}, {0xF4, 0xE6}, {0xDF, 0xB9}, {0xF4, 0xE7}, + {0xDF, 0xC3}, {0xF4, 0xE8}, {0xF4, 0xE9}, {0xE0, 0xD9}, {0xF4, 0xEA}, + {0xF4, 0xEB}, {0xE1, 0xE2}, {0xF4, 0xEC}, {0xF4, 0xED}, {0xF4, 0xEE}, + {0xE2, 0xC7}, {0xE3, 0xA8}, {0xE3, 0xA6}, {0xE3, 0xA9}, {0xE3, 0xAF}, + {0xE3, 0xB0}, {0xE3, 0xAA}, {0xE3, 0xAB}, {0xE3, 0xBC}, {0xE3, 0xC1}, + {0xE3, 0xBF}, {0xE3, 0xD5}, {0xE3, 0xD8}, {0xE3, 0xD6}, {0xE3, 0xDF}, + {0xE3, 0xE3}, {0xE3, 0xE1}, {0xE3, 0xD4}, {0xE3, 0xE9}, {0xE4, 0xA6}, + {0xE3, 0xF1}, {0xE3, 0xF2}, {0xE4, 0xCB}, {0xE4, 0xC1}, {0xE4, 0xC3}, + {0xE4, 0xBE}, {0xF4, 0xEF}, {0xE4, 0xC0}, {0xE4, 0xC7}, {0xE4, 0xBF}, + {0xE4, 0xE0}, {0xE4, 0xDE}, {0xE4, 0xD1}, {0xF4, 0xF0}, {0xE4, 0xDC}, + {0xE4, 0xD2}, {0xE4, 0xDB}, {0xE4, 0xD4}, {0xE4, 0xFA}, {0xE4, 0xEF}, + {0xE5, 0xB3}, {0xE5, 0xBF}, {0xE5, 0xC9}, {0xE5, 0xD0}, {0xE5, 0xE2}, + {0xE5, 0xEA}, {0xE5, 0xEB}, {0xF4, 0xF1}, {0xF4, 0xF2}, {0xF4, 0xF3}, + {0xE6, 0xE8}, {0xE6, 0xEF}, {0xE7, 0xAC}, {0xF4, 0xF4}, {0xE7, 0xAE}, + {0xF4, 0xF5}, {0xE7, 0xB1}, {0xF4, 0xF6}, {0xE7, 0xB2}, {0xE8, 0xB1}, + {0xE8, 0xB6}, {0xF4, 0xF7}, {0xF4, 0xF8}, {0xE8, 0xDD}, {0xF4, 0xF9}, + {0xF4, 0xFA}, {0xE9, 0xD1}, {0xF4, 0xFB}, {0xE9, 0xED}, {0xEA, 0xCD}, + {0xF4, 0xFC}, {0xEA, 0xDB}, {0xEA, 0xE6}, {0xEA, 0xEA}, {0xEB, 0xA5}, + {0xEB, 0xFB}, {0xEB, 0xFA}, {0xF4, 0xFD}, {0xEC, 0xD6}, {0xF4, 0xFE}, +}; + +#define IS_EUC_IBM2JISX0208(h, l) \ + (((h) == 0xA2 && (l) == 0xCC) || ((h) == 0xA2 && (l) == 0xE8)) + +/* EUC to SJIS IBM extended characters map (G3 JIS X 0212 block) */ +static struct { + unsigned short euc; + unsigned char sjis[2]; +} euc2sjisibm_jisx0212_map[] = { + {0xA2C3, {0xFA, 0x55}}, {0xB0A9, {0xFA, 0x68}}, {0xB0C8, {0xFA, 0x69}}, + {0xB0D2, {0xFA, 0x6B}}, {0xB0D4, {0xFA, 0x6C}}, {0xB0E3, {0xFA, 0x6D}}, + {0xB0EE, {0xFA, 0x6E}}, {0xB1A3, {0xFA, 0x70}}, {0xB1A7, {0xFA, 0x6F}}, + {0xB1A9, {0xFA, 0x72}}, {0xB1AC, {0xFA, 0x71}}, {0xB1BB, {0xFA, 0x61}}, + {0xB1BE, {0xFA, 0x73}}, {0xB1C8, {0xFA, 0x76}}, {0xB1D7, {0xFA, 0x77}}, + {0xB1D8, {0xFA, 0x75}}, {0xB1DF, {0xFA, 0x74}}, {0xB1E1, {0xFA, 0x7A}}, + {0xB1E3, {0xFA, 0x78}}, {0xB1F4, {0xFA, 0x79}}, {0xB2A3, {0xFA, 0x7B}}, + {0xB2BB, {0xFA, 0x7D}}, {0xB2E6, {0xFA, 0x7E}}, {0xB2ED, {0xFA, 0x80}}, + {0xB2F5, {0xFA, 0x81}}, {0xB2FC, {0xFA, 0x82}}, {0xB3B5, {0xFA, 0x84}}, + {0xB3D8, {0xFA, 0x85}}, {0xB3DB, {0xFA, 0x86}}, {0xB3DD, {0xFB, 0x77}}, + {0xB3E5, {0xFA, 0x87}}, {0xB3EE, {0xFA, 0x88}}, {0xB3FB, {0xFA, 0x89}}, + {0xB4C0, {0xFA, 0x8C}}, {0xB4C7, {0xFA, 0x8D}}, {0xB4D0, {0xFA, 0x8E}}, + {0xB4DE, {0xFA, 0x8F}}, {0xB5AA, {0xFA, 0x91}}, {0xB5AF, {0xFA, 0x93}}, + {0xB5C4, {0xFA, 0x94}}, {0xB5E8, {0xFA, 0x95}}, {0xB7C2, {0xFA, 0x97}}, + {0xB7E4, {0xFA, 0x98}}, {0xB7E7, {0xFA, 0x9A}}, {0xB7E8, {0xFA, 0x99}}, + {0xB8CE, {0xFA, 0x9E}}, {0xB8E1, {0xFA, 0x9F}}, {0xB8F5, {0xFA, 0xA0}}, + {0xB8F7, {0xFA, 0xA1}}, {0xB8F8, {0xFA, 0xA2}}, {0xB8FC, {0xFA, 0xA3}}, + {0xB9AF, {0xFA, 0xA4}}, {0xB9B7, {0xFA, 0xA5}}, {0xBABE, {0xFA, 0xA6}}, + {0xBADB, {0xFA, 0xA7}}, {0xBAE1, {0xFA, 0xA9}}, {0xBAEB, {0xFA, 0xAB}}, + {0xBBB3, {0xFA, 0xAC}}, {0xBBB8, {0xFA, 0xAD}}, {0xBBCA, {0xFA, 0xAF}}, + {0xBBD0, {0xFA, 0xB2}}, {0xBBDE, {0xFA, 0xB3}}, {0xBBF4, {0xFA, 0xB4}}, + {0xBBF5, {0xFA, 0xB5}}, {0xBBF9, {0xFA, 0xB6}}, {0xBCE4, {0xFA, 0xB7}}, + {0xBCED, {0xFA, 0xB8}}, {0xBCF4, {0xFA, 0x67}}, {0xBCFE, {0xFA, 0xB9}}, + {0xBDC2, {0xFA, 0xBB}}, {0xBDE7, {0xFA, 0xBC}}, {0xBDF0, {0xFA, 0xBE}}, + {0xBEAC, {0xFA, 0xC0}}, {0xBEB0, {0xFA, 0xBF}}, {0xBEB3, {0xFA, 0xC2}}, + {0xBEBD, {0xFA, 0xC3}}, {0xBEC9, {0xFA, 0xC5}}, {0xBECD, {0xFA, 0xC4}}, + {0xBEE4, {0xFA, 0xC6}}, {0xBFA8, {0xFA, 0xC7}}, {0xBFC9, {0xFA, 0xC8}}, + {0xC0C4, {0xFA, 0xC9}}, {0xC0E4, {0xFA, 0xCA}}, {0xC0F4, {0xFA, 0xCB}}, + {0xC1A6, {0xFA, 0xCC}}, {0xC1F5, {0xFA, 0xCE}}, {0xC1F8, {0xFA, 0xD1}}, + {0xC1FC, {0xFA, 0xCF}}, {0xC2A1, {0xFA, 0xD3}}, {0xC2A5, {0xFA, 0xD4}}, + {0xC2AB, {0xFA, 0xD2}}, {0xC2AD, {0xFA, 0x63}}, {0xC2B8, {0xFA, 0xD6}}, + {0xC2BA, {0xFA, 0xD7}}, {0xC2BF, {0xFA, 0x66}}, {0xC2C4, {0xFA, 0xD9}}, + {0xC2D2, {0xFA, 0xDA}}, {0xC2D7, {0xFA, 0xDB}}, {0xC2DB, {0xFA, 0xDC}}, + {0xC2DE, {0xFA, 0xDD}}, {0xC2ED, {0xFA, 0xDE}}, {0xC2F0, {0xFA, 0xDF}}, + {0xC3A1, {0xFA, 0xE1}}, {0xC3B5, {0xFA, 0xE2}}, {0xC3B9, {0xFA, 0xE4}}, + {0xC3C9, {0xFA, 0xE3}}, {0xC3D8, {0xFA, 0xE6}}, {0xC3FC, {0xFA, 0x64}}, + {0xC3FE, {0xFA, 0xE7}}, {0xC4CC, {0xFA, 0xE9}}, {0xC4D9, {0xFA, 0xEB}}, + {0xC4EA, {0xFA, 0xEC}}, {0xC4FD, {0xFA, 0xED}}, {0xC5A7, {0xFA, 0xEF}}, + {0xC5B5, {0xFA, 0xF0}}, {0xC5B6, {0xFA, 0xF1}}, {0xC5D5, {0xFA, 0xF3}}, + {0xC6B8, {0xFA, 0xF4}}, {0xC6D7, {0xFA, 0xF5}}, {0xC6E0, {0xFA, 0xF6}}, + {0xC6E3, {0xFA, 0xF8}}, {0xC6EA, {0xFA, 0xF7}}, {0xC7A1, {0xFA, 0xF9}}, + {0xC7AB, {0xFA, 0xFA}}, {0xC7C3, {0xFA, 0xFC}}, {0xC7C7, {0xFA, 0xFB}}, + {0xC7CB, {0xFB, 0x40}}, {0xC7CF, {0xFB, 0x41}}, {0xC7D9, {0xFB, 0x42}}, + {0xC7E6, {0xFB, 0x45}}, {0xC7EB, {0xFB, 0x48}}, {0xC7EE, {0xFB, 0x46}}, + {0xC7F0, {0xFB, 0x49}}, {0xC7FC, {0xFB, 0x47}}, {0xC8B1, {0xFB, 0x4A}}, + {0xC8E5, {0xFB, 0x4B}}, {0xC8F8, {0xFB, 0x4C}}, {0xC9A6, {0xFB, 0x4D}}, + {0xC9AB, {0xFB, 0x4E}}, {0xC9AD, {0xFB, 0x4F}}, {0xC9CA, {0xFB, 0x51}}, + {0xC9D3, {0xFB, 0x52}}, {0xC9E3, {0xFB, 0x54}}, {0xC9E9, {0xFB, 0x53}}, + {0xC9F4, {0xFB, 0x56}}, {0xC9F5, {0xFB, 0x57}}, {0xC9FC, {0xFB, 0x55}}, + {0xCAB3, {0xFB, 0x59}}, {0xCABD, {0xFB, 0x5A}}, {0xCAEF, {0xFB, 0x5B}}, + {0xCAF1, {0xFB, 0x5C}}, {0xCBAE, {0xFB, 0x5D}}, {0xCBCA, {0xFB, 0x5F}}, + {0xCBE6, {0xFB, 0x60}}, {0xCBEA, {0xFB, 0x61}}, {0xCBEE, {0xFB, 0x64}}, + {0xCBF0, {0xFB, 0x62}}, {0xCBF4, {0xFB, 0x63}}, {0xCBF9, {0xFB, 0x66}}, + {0xCCA5, {0xFB, 0x65}}, {0xCCAB, {0xFB, 0x67}}, {0xCCAD, {0xFB, 0x69}}, + {0xCCAE, {0xFB, 0x68}}, {0xCCB2, {0xFB, 0x6A}}, {0xCCC2, {0xFB, 0x6B}}, + {0xCCD0, {0xFB, 0x6C}}, {0xCCD9, {0xFB, 0x6D}}, {0xCDAA, {0xFA, 0xA8}}, + {0xCDBB, {0xFB, 0x6F}}, {0xCEBA, {0xFB, 0x73}}, {0xCEBB, {0xFB, 0x71}}, + {0xCEC3, {0xFB, 0x74}}, {0xCEF2, {0xFB, 0x76}}, {0xCFD5, {0xFB, 0x78}}, + {0xCFE2, {0xFB, 0x79}}, {0xCFE9, {0xFB, 0x7A}}, {0xCFED, {0xFB, 0x7B}}, + {0xD0E5, {0xFB, 0x81}}, {0xD0E9, {0xFB, 0x83}}, {0xD1E8, {0xFB, 0x84}}, + {0xD1EC, {0xFB, 0x87}}, {0xD2BB, {0xFB, 0x88}}, {0xD3E1, {0xFB, 0x8A}}, + {0xD3E8, {0xFB, 0x8B}}, {0xD4A7, {0xFB, 0x8C}}, {0xD4D4, {0xFB, 0x8F}}, + {0xD4E3, {0xFA, 0x5C}}, {0xD4F2, {0xFB, 0x90}}, {0xD5AE, {0xFB, 0x91}}, + {0xD7DE, {0xFB, 0x93}}, {0xD8A2, {0xFB, 0x95}}, {0xD8B7, {0xFB, 0x96}}, + {0xD8C1, {0xFB, 0x97}}, {0xD8D1, {0xFB, 0x98}}, {0xD8F4, {0xFB, 0x99}}, + {0xD9A1, {0xFA, 0x60}}, {0xD9C6, {0xFB, 0x9A}}, {0xD9C8, {0xFB, 0x9B}}, + {0xD9D1, {0xFB, 0x9C}}, {0xDCD3, {0xFB, 0xA2}}, {0xDCDF, {0xFA, 0x5D}}, + {0xDDC8, {0xFB, 0xA3}}, {0xDDD4, {0xFB, 0xA4}}, {0xDDEA, {0xFB, 0xA5}}, + {0xDDFA, {0xFB, 0xA6}}, {0xDEA4, {0xFB, 0xA7}}, {0xDEB0, {0xFB, 0xA8}}, + {0xDEB5, {0xFB, 0xAA}}, {0xDECB, {0xFB, 0xAB}}, {0xDFB9, {0xFB, 0xAD}}, + {0xDFC3, {0xFB, 0xAF}}, {0xE0D9, {0xFB, 0xB2}}, {0xE1E2, {0xFB, 0xB5}}, + {0xE2C7, {0xFB, 0xB9}}, {0xE3A6, {0xFB, 0xBB}}, {0xE3A8, {0xFB, 0xBA}}, + {0xE3A9, {0xFB, 0xBC}}, {0xE3AA, {0xFB, 0xBF}}, {0xE3AB, {0xFB, 0xC0}}, + {0xE3AF, {0xFB, 0xBD}}, {0xE3B0, {0xFB, 0xBE}}, {0xE3BC, {0xFB, 0xC1}}, + {0xE3BF, {0xFB, 0xC3}}, {0xE3C1, {0xFB, 0xC2}}, {0xE3D4, {0xFB, 0xCA}}, + {0xE3D5, {0xFB, 0xC4}}, {0xE3D6, {0xFB, 0xC6}}, {0xE3D8, {0xFB, 0xC5}}, + {0xE3DF, {0xFB, 0xC7}}, {0xE3E1, {0xFB, 0xC9}}, {0xE3E3, {0xFB, 0xC8}}, + {0xE3E9, {0xFB, 0xCB}}, {0xE3F1, {0xFB, 0xCD}}, {0xE3F2, {0xFB, 0xCE}}, + {0xE3F8, {0xFA, 0x5F}}, {0xE4A6, {0xFB, 0xCC}}, {0xE4BE, {0xFB, 0xD2}}, + {0xE4BF, {0xFB, 0xD6}}, {0xE4C0, {0xFB, 0xD4}}, {0xE4C1, {0xFB, 0xD0}}, + {0xE4C3, {0xFB, 0xD1}}, {0xE4C7, {0xFB, 0xD5}}, {0xE4CB, {0xFB, 0xCF}}, + {0xE4D0, {0xFA, 0x65}}, {0xE4D1, {0xFB, 0xD9}}, {0xE4D2, {0xFB, 0xDC}}, + {0xE4D4, {0xFB, 0xDE}}, {0xE4DB, {0xFB, 0xDD}}, {0xE4DC, {0xFB, 0xDB}}, + {0xE4DE, {0xFB, 0xD8}}, {0xE4E0, {0xFB, 0xD7}}, {0xE4E9, {0xFA, 0x5E}}, + {0xE4EF, {0xFB, 0xE0}}, {0xE4FA, {0xFB, 0xDF}}, {0xE5B3, {0xFB, 0xE1}}, + {0xE5BF, {0xFB, 0xE2}}, {0xE5C9, {0xFB, 0xE3}}, {0xE5D0, {0xFB, 0xE4}}, + {0xE5E2, {0xFB, 0xE5}}, {0xE5EA, {0xFB, 0xE6}}, {0xE5EB, {0xFB, 0xE7}}, + {0xE6E8, {0xFB, 0xEB}}, {0xE6EF, {0xFB, 0xEC}}, {0xE7AC, {0xFB, 0xED}}, + {0xE7AE, {0xFB, 0xEF}}, {0xE7B1, {0xFB, 0xF1}}, {0xE7B2, {0xFB, 0xF3}}, + {0xE8B1, {0xFB, 0xF4}}, {0xE8B6, {0xFB, 0xF5}}, {0xE8DD, {0xFB, 0xF8}}, + {0xE9D1, {0xFB, 0xFB}}, {0xE9ED, {0xFC, 0x40}}, {0xEACD, {0xFC, 0x41}}, + {0xEADB, {0xFC, 0x43}}, {0xEAE6, {0xFC, 0x44}}, {0xEAEA, {0xFC, 0x45}}, + {0xEBA5, {0xFC, 0x46}}, {0xEBFA, {0xFC, 0x48}}, {0xEBFB, {0xFC, 0x47}}, + {0xECD6, {0xFC, 0x4A}}, +}; + +/* EUC to SJIS IBM extended characters map (G3 Upper block) */ +static unsigned char euc2sjisibm_g3upper_map[][2] = { + {0xFA, 0x40}, {0xFA, 0x41}, {0xFA, 0x42}, {0xFA, 0x43}, {0xFA, 0x44}, + {0xFA, 0x45}, {0xFA, 0x46}, {0xFA, 0x47}, {0xFA, 0x48}, {0xFA, 0x49}, + {0xFA, 0x4A}, {0xFA, 0x4B}, {0xFA, 0x4C}, {0xFA, 0x4D}, {0xFA, 0x4E}, + {0xFA, 0x4F}, {0xFA, 0x50}, {0xFA, 0x51}, {0xFA, 0x52}, {0xFA, 0x53}, + {0xFA, 0x56}, {0xFA, 0x57}, {0xFA, 0x58}, {0xFA, 0x59}, {0xFA, 0x5A}, + {0xFA, 0x62}, {0xFA, 0x6A}, {0xFA, 0x7C}, {0xFA, 0x83}, {0xFA, 0x8A}, + {0xFA, 0x8B}, {0xFA, 0x90}, {0xFA, 0x92}, {0xFA, 0x96}, {0xFA, 0x9B}, + {0xFA, 0x9C}, {0xFA, 0x9D}, {0xFA, 0xAA}, {0xFA, 0xAE}, {0xFA, 0xB0}, + {0xFA, 0xB1}, {0xFA, 0xBA}, {0xFA, 0xBD}, {0xFA, 0xC1}, {0xFA, 0xCD}, + {0xFA, 0xD0}, {0xFA, 0xD5}, {0xFA, 0xD8}, {0xFA, 0xE0}, {0xFA, 0xE5}, + {0xFA, 0xE8}, {0xFA, 0xEA}, {0xFA, 0xEE}, {0xFA, 0xF2}, {0xFB, 0x43}, + {0xFB, 0x44}, {0xFB, 0x50}, {0xFB, 0x58}, {0xFB, 0x5E}, {0xFB, 0x6E}, + {0xFB, 0x70}, {0xFB, 0x72}, {0xFB, 0x75}, {0xFB, 0x7C}, {0xFB, 0x7D}, + {0xFB, 0x7E}, {0xFB, 0x80}, {0xFB, 0x82}, {0xFB, 0x85}, {0xFB, 0x86}, + {0xFB, 0x89}, {0xFB, 0x8D}, {0xFB, 0x8E}, {0xFB, 0x92}, {0xFB, 0x94}, + {0xFB, 0x9D}, {0xFB, 0x9E}, {0xFB, 0x9F}, {0xFB, 0xA0}, {0xFB, 0xA1}, + {0xFB, 0xA9}, {0xFB, 0xAC}, {0xFB, 0xAE}, {0xFB, 0xB0}, {0xFB, 0xB1}, + {0xFB, 0xB3}, {0xFB, 0xB4}, {0xFB, 0xB6}, {0xFB, 0xB7}, {0xFB, 0xB8}, + {0xFB, 0xD3}, {0xFB, 0xDA}, {0xFB, 0xE8}, {0xFB, 0xE9}, {0xFB, 0xEA}, + {0xFB, 0xEE}, {0xFB, 0xF0}, {0xFB, 0xF2}, {0xFB, 0xF6}, {0xFB, 0xF7}, + {0xFB, 0xF9}, {0xFB, 0xFA}, {0xFB, 0xFC}, {0xFC, 0x42}, {0xFC, 0x49}, + {0xFC, 0x4B}, +}; + +#define MAP_ELEMENT_OF(map) (sizeof(map) / sizeof(map[0])) + +static inline int sjisibm2euc(unsigned char *euc, const unsigned char sjis_hi, + const unsigned char sjis_lo); +static inline int euc2sjisibm_jisx0212(unsigned char *sjis, const unsigned char euc_hi, + const unsigned char euc_lo); +static inline int euc2sjisibm_g3upper(unsigned char *sjis, const unsigned char euc_hi, + const unsigned char euc_lo); +static inline int euc2sjisibm(unsigned char *sjis, const unsigned char euc_hi, + const unsigned char euc_lo); +static inline int sjisnec2sjisibm(unsigned char *sjisibm, + const unsigned char sjisnec_hi, + const unsigned char sjisnec_lo); + +/* SJIS IBM extended characters to EUC */ +static inline int sjisibm2euc(unsigned char *euc, const unsigned char sjis_hi, + const unsigned char sjis_lo) +{ + int index; + + index = ((sjis_hi - 0xFA) * (0xFD - 0x40)) + (sjis_lo - 0x40); + if (IS_EUC_IBM2JISX0208(sjisibm2euc_map[index][0], + sjisibm2euc_map[index][1])) { + euc[0] = sjisibm2euc_map[index][0]; + euc[1] = sjisibm2euc_map[index][1]; + return 2; + } else { + euc[0] = SS3; + euc[1] = sjisibm2euc_map[index][0]; + euc[2] = sjisibm2euc_map[index][1]; + return 3; + } +} + +/* EUC to SJIS IBM extended characters (G3 JIS X 0212 block) */ +static inline int euc2sjisibm_jisx0212(unsigned char *sjis, const unsigned char euc_hi, + const unsigned char euc_lo) +{ + int index, min_index, max_index; + unsigned short euc; + + min_index = 0; + max_index = MAP_ELEMENT_OF(euc2sjisibm_jisx0212_map) - 1; + euc = (euc_hi << 8) | euc_lo; + + while (min_index <= max_index) { + index = (min_index + max_index) / 2; + if (euc < euc2sjisibm_jisx0212_map[index].euc) + max_index = index - 1; + else + min_index = index + 1; + if (euc == euc2sjisibm_jisx0212_map[index].euc) { + sjis[0] = euc2sjisibm_jisx0212_map[index].sjis[0]; + sjis[1] = euc2sjisibm_jisx0212_map[index].sjis[1]; + return 3; + } + } + return 0; +} + +/* EUC to SJIS IBM extended characters (G3 Upper block) */ +static inline int euc2sjisibm_g3upper(unsigned char *sjis, const unsigned char euc_hi, + const unsigned char euc_lo) +{ + int index; + + if (euc_hi == 0xF3) + index = ((euc_hi << 8) | euc_lo) - 0xF3F3; + else + index = ((euc_hi << 8) | euc_lo) - 0xF4A1 + 12; + + if ((index < 0) || (index >= MAP_ELEMENT_OF(euc2sjisibm_g3upper_map))) + return 0; + + sjis[0] = euc2sjisibm_g3upper_map[index][0]; + sjis[1] = euc2sjisibm_g3upper_map[index][1]; + + return 3; +} + +/* EUC to SJIS IBM extended characters (G3 block) */ +static inline int euc2sjisibm(unsigned char *sjis, const unsigned char euc_hi, + const unsigned char euc_lo) +{ + int n; + +#if 0 + if ((euc_hi == 0xA2) && (euc_lo == 0xCC)) { + sjis[0] = 0xFA; + sjis[1] = 0x54; + return 2; + } else if ((euc_hi == 0xA2) && (euc_lo == 0xE8)) { + sjis[0] = 0xFA; + sjis[1] = 0x5B; + return 2; + } +#endif + if ((n = euc2sjisibm_g3upper(sjis, euc_hi, euc_lo))) { + return n; + } else if ((n = euc2sjisibm_jisx0212(sjis, euc_hi, euc_lo))) { + return n; + } + + return 0; +} + +/* NEC/IBM extended characters to IBM extended characters */ +static inline int sjisnec2sjisibm(unsigned char *sjisibm, + const unsigned char sjisnec_hi, + const unsigned char sjisnec_lo) +{ + int count; + + if (! IS_SJIS_NECIBM(sjisnec_hi, sjisnec_lo)) + return 0; + + if ((sjisnec_hi == 0xEE) && (sjisnec_lo == 0xF9)) { + sjisibm[0] = 0x81; + sjisibm[1] = 0xCA; + return 2; + } + + if ((sjisnec_hi == 0xEE) && (sjisnec_lo >= 0xEF)) { + count = (sjisnec_hi << 8 | sjisnec_lo) + - (sjisnec_lo <= 0xF9 ? 0xEEEF : (0xEEEF - 10)); + } else { + count = (sjisnec_hi - 0xED) * (0xFC - 0x40) + + (sjisnec_lo - 0x40) + (0x5C - 0x40); + if (sjisnec_lo >= 0x7F) + count--; + } + + sjisibm[0] = 0xFA + (count / (0xFC - 0x40)); + sjisibm[1] = 0x40 + (count % (0xFC - 0x40)); + if (sjisibm[1] >= 0x7F) + sjisibm[1]++; + + return 2; +} static int uni2char(const wchar_t uni, - unsigned char *out, int boundlen) + unsigned char *out, int boundlen) { int n; - if ( !p_nls ) - return -EINVAL; - if ( (n = p_nls->uni2char(uni, out, boundlen)) < 0) + if (!p_nls) + return -EINVAL; + if ((n = p_nls->uni2char(uni, out, boundlen)) < 0) return n; - + /* translate SJIS into EUC-JP */ if (n == 1) { - /* JIS X 201 KANA */ - if (0xA1 <= out[0] && out[0] <= 0xDF) { - if (boundlen <= 1) + if (IS_SJIS_JISX0201KANA(out[0])) { + /* JIS X 0201 KANA */ + if (boundlen < 2) return -ENAMETOOLONG; + out[1] = out[0]; out[0] = SS2; - n = 2; + return 2; } - } else if (n == 2) { - /* JIS X 208 */ + } else if (n == 2) { + /* NEC/IBM extended characters to IBM extended characters */ + sjisnec2sjisibm(out, out[0], out[1]); + + if (IS_SJIS_UDC_LOW(out[0], out[1])) { + /* User defined characters half low */ + MAP_SJIS2EUC(out[0], out[1], 0xF0, out[0], out[1], 0xF5); + } else if (IS_SJIS_UDC_HI(out[0], out[1])) { + /* User defined characters half high */ + unsigned char ch, cl; - /* SJIS codes 0xF0xx to 0xFFxx are machine-dependent codes and user-defining characters */ - if (out[0] >= 0xF0) { - out[0] = 0x81; /* 'GETA' with SJIS coding */ - out[1] = 0xAC; - } + if (boundlen < 3) + return -ENAMETOOLONG; - out[0] = (out[0]^0xA0)*2 + 0x5F; - if (out[1] > 0x9E) - out[0]++; - - if (out[1] < 0x7F) - out[1] = out[1] + 0x61; - else if (out[1] < 0x9F) - out[1] = out[1] + 0x60; - else - out[1] = out[1] + 0x02; + n = 3; ch = out[0]; cl = out[1]; + out[0] = SS3; + MAP_SJIS2EUC(ch, cl, 0xF5, out[1], out[2], 0xF5); + } else if (IS_SJIS_IBM(out[0], out[1])) { + /* IBM extended characters */ + unsigned char euc[3], i; + + n = sjisibm2euc(euc, out[0], out[1]); + if (boundlen < n) + return -ENAMETOOLONG; + for (i = 0; i < n; i++) + out[i] = euc[i]; + } else if (IS_SJIS_JISX0208(out[0], out[1])) { + /* JIS X 0208 (include NEC special characters) */ + out[0] = (out[0]^0xA0)*2 + 0x5F; + if (out[1] > 0x9E) + out[0]++; + + if (out[1] < 0x7F) + out[1] = out[1] + 0x61; + else if (out[1] < 0x9F) + out[1] = out[1] + 0x60; + else + out[1] = out[1] + 0x02; + } else { + /* Invalid characters */ + return -EINVAL; + } } else return -EINVAL; @@ -61,52 +479,73 @@ } static int char2uni(const unsigned char *rawstring, int boundlen, - wchar_t *uni) + wchar_t *uni) { unsigned char sjis_temp[2]; int euc_offset, n; - + if ( !p_nls ) return -EINVAL; if (boundlen <= 0) return -ENAMETOOLONG; - if (boundlen == 1) { - *uni = rawstring[0]; - return 1; - } - /* translate EUC-JP into SJIS */ if (rawstring[0] > 0x7F) { - if (rawstring[0] == SS2) { - /* JIS X 201 KANA */ - sjis_temp[0] = rawstring[1]; - sjis_temp[1] = 0x00; - euc_offset = 2; - } else if (rawstring[0] == SS3) { - /* JIS X 212 */ - sjis_temp[0] = 0x81; /* 'GETA' with SJIS coding */ - sjis_temp[1] = 0xAC; + if (rawstring[0] == SS3) { + if (boundlen < 3) + return -EINVAL; euc_offset = 3; - } else { - /* JIS X 208 */ - sjis_temp[0] = ((rawstring[0]-0x5f)/2) ^ 0xA0; - if (!(rawstring[0]&1)) - sjis_temp[1] = rawstring[1] - 0x02; - else if (rawstring[1] < 0xE0) - sjis_temp[1] = rawstring[1] - 0x61; - else - sjis_temp[1] = rawstring[1] - 0x60; + + if (IS_EUC_UDC_HI(rawstring[1], rawstring[2])) { + /* User defined characters half high */ + MAP_EUC2SJIS(rawstring[1], rawstring[2], 0xF5, + sjis_temp[0], sjis_temp[1], 0xF5); + } else if (euc2sjisibm(sjis_temp,rawstring[1],rawstring[2])) { + /* IBM extended characters */ + } else { + /* JIS X 0212 and Invalid characters*/ + return -EINVAL; + + /* 'GETA' with SJIS coding */ + /* sjis_temp[0] = 0x81; */ + /* sjis_temp[1] = 0xAC; */ + } + } else { + if (boundlen < 2) + return -EINVAL; euc_offset = 2; + + if (IS_EUC_JISX0201KANA(rawstring[0], rawstring[1])) { + /* JIS X 0201 KANA */ + sjis_temp[0] = rawstring[1]; + sjis_temp[1] = 0x00; + } else if (IS_EUC_UDC_LOW(rawstring[0], rawstring[1])) { + /* User defined characters half low */ + MAP_EUC2SJIS(rawstring[0], rawstring[1], 0xF5, + sjis_temp[0], sjis_temp[1], 0xF0); + } else if (IS_EUC_JISX0208(rawstring[0], rawstring[1])) { + /* JIS X 0208 (include NEC spesial characters) */ + sjis_temp[0] = ((rawstring[0]-0x5f)/2) ^ 0xA0; + if (!(rawstring[0] & 1)) + sjis_temp[1] = rawstring[1] - 0x02; + else if (rawstring[1] < 0xE0) + sjis_temp[1] = rawstring[1] - 0x61; + else + sjis_temp[1] = rawstring[1] - 0x60; + } else { + /* Invalid characters */ + return -EINVAL; + } } - } else { - /* JIS X 201 ROMAJI */ - sjis_temp[0] = rawstring[0]; - sjis_temp[1] = rawstring[1]; + } else { euc_offset = 1; + + /* JIS X 0201 ROMAJI */ + sjis_temp[0] = rawstring[0]; + sjis_temp[1] = 0x00; } - if ( (n = p_nls->char2uni(sjis_temp, boundlen, uni)) < 0) + if ( (n = p_nls->char2uni(sjis_temp, sizeof(sjis_temp), uni)) < 0) return n; return euc_offset; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nls/nls_iso8859-13.c linux.ac/fs/nls/nls_iso8859-13.c --- linux.vanilla/fs/nls/nls_iso8859-13.c Thu Jan 1 01:00:00 1970 +++ linux.ac/fs/nls/nls_iso8859-13.c Tue Apr 10 18:19:53 2001 @@ -0,0 +1,330 @@ +/* + * linux/fs/nls_iso8859-13.c + * + * Charset iso8859-13 translation tables. + * The Unicode to charset table has only exact mappings. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/nls.h> +#include <linux/errno.h> + +static wchar_t charset2uni[256] = { + /* 0x00*/ + 0x0000, 0x0001, 0x0002, 0x0003, + 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000a, 0x000b, + 0x000c, 0x000d, 0x000e, 0x000f, + /* 0x10*/ + 0x0010, 0x0011, 0x0012, 0x0013, + 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001a, 0x001b, + 0x001c, 0x001d, 0x001e, 0x001f, + /* 0x20*/ + 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, + 0x002c, 0x002d, 0x002e, 0x002f, + /* 0x30*/ + 0x0030, 0x0031, 0x0032, 0x0033, + 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, + 0x003c, 0x003d, 0x003e, 0x003f, + /* 0x40*/ + 0x0040, 0x0041, 0x0042, 0x0043, + 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, + 0x004c, 0x004d, 0x004e, 0x004f, + /* 0x50*/ + 0x0050, 0x0051, 0x0052, 0x0053, + 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, + 0x005c, 0x005d, 0x005e, 0x005f, + /* 0x60*/ + 0x0060, 0x0061, 0x0062, 0x0063, + 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, + 0x006c, 0x006d, 0x006e, 0x006f, + /* 0x70*/ + 0x0070, 0x0071, 0x0072, 0x0073, + 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, + 0x007c, 0x007d, 0x007e, 0x007f, + /* 0x80*/ + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x90*/ + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + /* 0xa0*/ + 0x00a0, 0x201d, 0x00a2, 0x00a3, + 0x00a4, 0x201e, 0x00a6, 0x00a7, + 0x00d8, 0x00a9, 0x0156, 0x00ab, + 0x00ac, 0x00ad, 0x00ae, 0x00c6, + /* 0xb0*/ + 0x00b0, 0x00b1, 0x00b2, 0x00b3, + 0x201c, 0x00b5, 0x00b6, 0x00b7, + 0x00f8, 0x00b9, 0x0157, 0x00bb, + 0x00bc, 0x00bd, 0x00be, 0x00e6, + /* 0xc0*/ + 0x0104, 0x012e, 0x0100, 0x0106, + 0x00c4, 0x00c5, 0x0118, 0x0112, + 0x010c, 0x00c9, 0x0179, 0x0116, + 0x0122, 0x0136, 0x012a, 0x013b, + /* 0xd0*/ + 0x0160, 0x0143, 0x0145, 0x00d3, + 0x014c, 0x00d5, 0x00d6, 0x00d7, + 0x0172, 0x0141, 0x015a, 0x016a, + 0x00dc, 0x017b, 0x017d, 0x00df, + /* 0xe0*/ + 0x0105, 0x012f, 0x0101, 0x0107, + 0x00e4, 0x00e5, 0x0119, 0x0113, + 0x010d, 0x00e9, 0x017a, 0x0117, + 0x0123, 0x0137, 0x012b, 0x013c, + /* 0xf0*/ + 0x0161, 0x0144, 0x0146, 0x00f3, + 0x014d, 0x00f5, 0x00f6, 0x00f7, + 0x0173, 0x0142, 0x015b, 0x016b, + 0x00fc, 0x017c, 0x017e, 0x2019, +}; + +static unsigned char page00[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */ + 0x00, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0xb2, 0xb3, 0x00, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ + 0x00, 0xb9, 0x00, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0xc4, 0xc5, 0xaf, 0x00, /* 0xc0-0xc7 */ + 0x00, 0xc9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0xd3, 0x00, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ + 0xa8, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */ + 0x00, 0x00, 0x00, 0x00, 0xe4, 0xe5, 0xbf, 0x00, /* 0xe0-0xe7 */ + 0x00, 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ + 0x00, 0x00, 0x00, 0xf3, 0x00, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ + 0xb8, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, /* 0xf8-0xff */ +}; + +static unsigned char page01[256] = { + 0xc2, 0xe2, 0x00, 0x00, 0xc0, 0xe0, 0xc3, 0xe3, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0xc7, 0xe7, 0x00, 0x00, 0xcb, 0xeb, /* 0x10-0x17 */ + 0xc6, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x00, 0x00, 0xcc, 0xec, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0xce, 0xee, 0x00, 0x00, 0xc1, 0xe1, /* 0x28-0x2f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcd, 0xed, /* 0x30-0x37 */ + 0x00, 0x00, 0x00, 0xcf, 0xef, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0x00, 0xd9, 0xf9, 0xd1, 0xf1, 0xd2, 0xf2, 0x00, /* 0x40-0x47 */ + 0x00, 0x00, 0x00, 0x00, 0xd4, 0xf4, 0x00, 0x00, /* 0x48-0x4f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xba, /* 0x50-0x57 */ + 0x00, 0x00, 0xda, 0xfa, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ + 0xd0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0xdb, 0xfb, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0xd8, 0xf8, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0xca, 0xea, 0xdd, 0xfd, 0xde, 0xfe, 0x00, /* 0x78-0x7f */ +}; + +static unsigned char page02[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x00, 0xff, 0x00, 0x00, 0xb4, 0xa1, 0xa5, 0x00, /* 0x18-0x1f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ +}; + +static unsigned char page20[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x00, 0xff, 0x00, 0x00, 0xb4, 0xa1, 0xa5, 0x00, /* 0x18-0x1f */ +}; + +static unsigned char *page_uni2charset[256] = { + page00, page01, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + page20, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +static unsigned char charset2lower[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ + 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0xa0, 0xb1, 0xa2, 0xb3, 0xa4, 0xb5, 0xb6, 0xa7, /* 0xa0-0xa7 */ + 0xa8, 0xb9, 0xba, 0xbb, 0xbc, 0xad, 0xbe, 0xaf, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbf, 0xbe, 0xbf, /* 0xb8-0xbf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* 0xd0-0xd7 */ + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* 0xd8-0xdf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ +}; + +static unsigned char charset2upper[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ + 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ + 0xb0, 0xa1, 0xb2, 0xa3, 0xb4, 0xa5, 0xa6, 0xb7, /* 0xb0-0xb7 */ + 0xb8, 0xa9, 0xaa, 0xab, 0xac, 0xbd, 0xae, 0xbd, /* 0xb8-0xbf */ + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xf7, /* 0xf0-0xf7 */ + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xff, /* 0xf8-0xff */ +}; + +static int uni2char(wchar_t uni, unsigned char *out, int boundlen) +{ + unsigned char *uni2charset; + unsigned char cl = uni & 0x00ff; + unsigned char ch = (uni & 0xff00) >> 8; + + if (boundlen <= 0) + return -ENAMETOOLONG; + + uni2charset = page_uni2charset[ch]; + if (uni2charset && uni2charset[cl]) + out[0] = uni2charset[cl]; + else + return -EINVAL; + return 1; +} + +static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) +{ + *uni = charset2uni[*rawstring]; + if (*uni == 0x0000) + return -EINVAL; + return 1; +} + +static struct nls_table table = { + "iso8859-13", + uni2char, + char2uni, + charset2lower, + charset2upper, + THIS_MODULE, +}; + +static int __init init_nls_iso8859_13(void) +{ + return register_nls(&table); +} + +static void __exit exit_nls_iso8859_13(void) +{ + unregister_nls(&table); +} + +module_init(init_nls_iso8859_13) +module_exit(exit_nls_iso8859_13) + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nls/nls_iso8859-8.c linux.ac/fs/nls/nls_iso8859-8.c --- linux.vanilla/fs/nls/nls_iso8859-8.c Fri Jul 21 23:19:51 2000 +++ linux.ac/fs/nls/nls_iso8859-8.c Tue Apr 10 18:19:53 2001 @@ -1,10 +1,5 @@ /* * linux/fs/nls_iso8859-8.c - * - * Charset iso8859-8 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. */ #include <linux/module.h> @@ -13,291 +8,36 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - /* 0x90*/ - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - /* 0xa0*/ - 0x00a0, 0x0000, 0x00a2, 0x00a3, - 0x00a4, 0x00a5, 0x00a6, 0x00a7, - 0x00a8, 0x00a9, 0x00d7, 0x00ab, - 0x00ac, 0x00ad, 0x00ae, 0x203e, - /* 0xb0*/ - 0x00b0, 0x00b1, 0x00b2, 0x00b3, - 0x00b4, 0x00b5, 0x00b6, 0x00b7, - 0x00b8, 0x00b9, 0x00f7, 0x00bb, - 0x00bc, 0x00bd, 0x00be, 0x0000, - /* 0xc0*/ - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - /* 0xd0*/ - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x2017, - /* 0xe0*/ - 0x05d0, 0x05d1, 0x05d2, 0x05d3, - 0x05d4, 0x05d5, 0x05d6, 0x05d7, - 0x05d8, 0x05d9, 0x05da, 0x05db, - 0x05dc, 0x05dd, 0x05de, 0x05df, - /* 0xf0*/ - 0x05e0, 0x05e1, 0x05e2, 0x05e3, - 0x05e4, 0x05e5, 0x05e6, 0x05e7, - 0x05e8, 0x05e9, 0x05ea, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, -}; - -static unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0x00, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, /* 0xf0-0xf7 */ -}; - -static unsigned char page05[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xd0-0xd7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xd8-0xdf */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xe0-0xe7 */ - 0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ -}; - -static unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x00, /* 0x38-0x3f */ -}; - -static unsigned char *page_uni2charset[256] = { - page00, NULL, NULL, NULL, NULL, page05, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0x00, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} +static struct nls_table *p_nls; static struct nls_table table = { "iso8859-8", - uni2char, - char2uni, - charset2lower, - charset2upper, + NULL, + NULL, + NULL, + NULL, THIS_MODULE, }; static int __init init_nls_iso8859_8(void) { - return register_nls(&table); + p_nls = load_nls("cp1255"); + + if (p_nls) { + table.uni2char = p_nls->uni2char; + table.char2uni = p_nls->char2uni; + table.charset2upper = p_nls->charset2upper; + table.charset2lower = p_nls->charset2lower; + return register_nls(&table); + } + + return -EINVAL; } static void __exit exit_nls_iso8859_8(void) { unregister_nls(&table); + unload_nls(p_nls); } module_init(init_nls_iso8859_8) @@ -308,7 +48,8 @@ * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only. This must remain at the end * of the file. - * --------------------------------------------------------------------------- + * +--------------------------------------------------------------------------- * Local variables: * c-indent-level: 8 * c-brace-imaginary-offset: 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nls/nls_koi8-u.c linux.ac/fs/nls/nls_koi8-u.c --- linux.vanilla/fs/nls/nls_koi8-u.c Thu Jan 1 01:00:00 1970 +++ linux.ac/fs/nls/nls_koi8-u.c Tue Apr 10 18:19:53 2001 @@ -0,0 +1,345 @@ +/* + * linux/fs/nls_koi8-u.c + * + * Charset koi8-u translation tables. + * The Unicode to charset table has only exact mappings. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/nls.h> +#include <linux/errno.h> + +static wchar_t charset2uni[256] = { + /* 0x00*/ + 0x0000, 0x0001, 0x0002, 0x0003, + 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000a, 0x000b, + 0x000c, 0x000d, 0x000e, 0x000f, + /* 0x10*/ + 0x0010, 0x0011, 0x0012, 0x0013, + 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001a, 0x001b, + 0x001c, 0x001d, 0x001e, 0x001f, + /* 0x20*/ + 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, + 0x002c, 0x002d, 0x002e, 0x002f, + /* 0x30*/ + 0x0030, 0x0031, 0x0032, 0x0033, + 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, + 0x003c, 0x003d, 0x003e, 0x003f, + /* 0x40*/ + 0x0040, 0x0041, 0x0042, 0x0043, + 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, + 0x004c, 0x004d, 0x004e, 0x004f, + /* 0x50*/ + 0x0050, 0x0051, 0x0052, 0x0053, + 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, + 0x005c, 0x005d, 0x005e, 0x005f, + /* 0x60*/ + 0x0060, 0x0061, 0x0062, 0x0063, + 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, + 0x006c, 0x006d, 0x006e, 0x006f, + /* 0x70*/ + 0x0070, 0x0071, 0x0072, 0x0073, + 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, + 0x007c, 0x007d, 0x007e, 0x007f, + /* 0x80*/ + 0x2500, 0x2502, 0x250c, 0x2510, + 0x2514, 0x2518, 0x251c, 0x2524, + 0x252c, 0x2534, 0x253c, 0x2580, + 0x2584, 0x2588, 0x258c, 0x2590, + /* 0x90*/ + 0x2591, 0x2592, 0x2593, 0x2320, + 0x25a0, 0x2219, 0x221a, 0x2248, + 0x2264, 0x2265, 0x00a0, 0x2321, + 0x00b0, 0x00b2, 0x00b7, 0x00f7, + /* 0xa0*/ + 0x2550, 0x2551, 0x2552, 0x0451, + 0x0454, 0x2554, 0x0456, 0x0457, + 0x2557, 0x2558, 0x2559, 0x255a, + 0x255b, 0x0491, 0x255d, 0x255e, + /* 0xb0*/ + 0x255f, 0x2560, 0x2561, 0x0401, + 0x0404, 0x2563, 0x0406, 0x0407, + 0x2566, 0x2567, 0x2568, 0x2569, + 0x256a, 0x0490, 0x256c, 0x00a9, + /* 0xc0*/ + 0x044e, 0x0430, 0x0431, 0x0446, + 0x0434, 0x0435, 0x0444, 0x0433, + 0x0445, 0x0438, 0x0439, 0x043a, + 0x043b, 0x043c, 0x043d, 0x043e, + /* 0xd0*/ + 0x043f, 0x044f, 0x0440, 0x0441, + 0x0442, 0x0443, 0x0436, 0x0432, + 0x044c, 0x044b, 0x0437, 0x0448, + 0x044d, 0x0449, 0x0447, 0x044a, + /* 0xe0*/ + 0x042e, 0x0410, 0x0411, 0x0426, + 0x0414, 0x0415, 0x0424, 0x0413, + 0x0425, 0x0418, 0x0419, 0x041a, + 0x041b, 0x041c, 0x041d, 0x041e, + /* 0xf0*/ + 0x041f, 0x042f, 0x0420, 0x0421, + 0x0422, 0x0423, 0x0416, 0x0412, + 0x042c, 0x042b, 0x0417, 0x0428, + 0x042d, 0x0429, 0x0427, 0x042a, +}; + +static unsigned char page00[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ + 0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ + 0x9c, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xb0-0xb7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, /* 0xf0-0xf7 */ +}; + +static unsigned char page04[256] = { + 0x00, 0xb3, 0x00, 0x00, 0xb4, 0x00, 0xb6, 0xb7, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0xe1, 0xe2, 0xf7, 0xe7, 0xe4, 0xe5, 0xf6, 0xfa, /* 0x10-0x17 */ + 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, /* 0x18-0x1f */ + 0xf2, 0xf3, 0xf4, 0xf5, 0xe6, 0xe8, 0xe3, 0xfe, /* 0x20-0x27 */ + 0xfb, 0xfd, 0xff, 0xf9, 0xf8, 0xfc, 0xe0, 0xf1, /* 0x28-0x2f */ + 0xc1, 0xc2, 0xd7, 0xc7, 0xc4, 0xc5, 0xd6, 0xda, /* 0x30-0x37 */ + 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, /* 0x38-0x3f */ + 0xd2, 0xd3, 0xd4, 0xd5, 0xc6, 0xc8, 0xc3, 0xde, /* 0x40-0x47 */ + 0xdb, 0xdd, 0xdf, 0xd9, 0xd8, 0xdc, 0xc0, 0xd1, /* 0x48-0x4f */ + 0x00, 0xa3, 0x00, 0x00, 0xa4, 0x00, 0xa6, 0xa7, /* 0x50-0x57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0xbd, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ +}; + +static unsigned char page22[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x00, 0x95, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ + 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ + 0x00, 0x00, 0x00, 0x00, 0x98, 0x99, 0x00, 0x00, /* 0x60-0x67 */ +}; + +static unsigned char page23[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x93, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ +}; + +static unsigned char page25[256] = { + 0x80, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x83, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x85, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x00, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ + 0xa0, 0xa1, 0xa2, 0x00, 0xa5, 0x00, 0x00, 0xa8, /* 0x50-0x57 */ + 0xa9, 0xaa, 0xab, 0xac, 0x00, 0xae, 0xaf, 0xb0, /* 0x58-0x5f */ + 0xb1, 0xb2, 0x00, 0xb5, 0x00, 0x00, 0xb8, 0xb9, /* 0x60-0x67 */ + 0xba, 0xbb, 0xbc, 0x00, 0xbe, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0x8b, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x8d, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x8f, 0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ +}; + +static unsigned char *page_uni2charset[256] = { + page00, NULL, NULL, NULL, page04, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, page22, page23, NULL, page25, NULL, NULL, +}; + +static unsigned char charset2lower[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ + 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0xb2, 0xa3, 0xa4, 0xb5, 0xa6, 0xa7, /* 0xb0-0xb7 */ + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xad, 0xbe, 0xbf, /* 0xb8-0xbf */ + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xf0-0xf7 */ + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xf8-0xff */ +}; + +static unsigned char charset2upper[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ + 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ + 0xa0, 0xa1, 0xa2, 0xb3, 0xb4, 0xa5, 0xb6, 0xb7, /* 0xa0-0xa7 */ + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xbd, 0xae, 0xaf, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xd0-0xd7 */ + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xd8-0xdf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ +}; + +static int uni2char(wchar_t uni, unsigned char *out, int boundlen) +{ + unsigned char *uni2charset; + unsigned char cl = uni & 0x00ff; + unsigned char ch = (uni & 0xff00) >> 8; + + if (boundlen <= 0) + return -ENAMETOOLONG; + + uni2charset = page_uni2charset[ch]; + if (uni2charset && uni2charset[cl]) + out[0] = uni2charset[cl]; + else + return -EINVAL; + return 1; +} + +static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) +{ + *uni = charset2uni[*rawstring]; + if (*uni == 0x0000) + return -EINVAL; + return 1; +} + +static struct nls_table table = { + "koi8-u", + uni2char, + char2uni, + charset2lower, + charset2upper, + THIS_MODULE, +}; + +static int __init init_nls_koi8_u(void) +{ + return register_nls(&table); +} + +static void __exit exit_nls_koi8_u(void) +{ + unregister_nls(&table); +} + +module_init(init_nls_koi8_u) +module_exit(exit_nls_koi8_u) + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nls/nls_tis-620.c linux.ac/fs/nls/nls_tis-620.c --- linux.vanilla/fs/nls/nls_tis-620.c Thu Jan 1 01:00:00 1970 +++ linux.ac/fs/nls/nls_tis-620.c Tue Apr 10 18:19:53 2001 @@ -0,0 +1,62 @@ +/* + * linux/fs/nls_tis-620.c + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/nls.h> +#include <linux/errno.h> + +static struct nls_table *p_nls; + +static struct nls_table table = { + "tis-620", + NULL, + NULL, + NULL, + NULL, + THIS_MODULE, +}; + +static int __init init_nls_tis_620(void) +{ + p_nls = load_nls("cp874"); + + if (p_nls) { + table.uni2char = p_nls->uni2char; + table.char2uni = p_nls->char2uni; + table.charset2upper = p_nls->charset2upper; + table.charset2lower = p_nls->charset2lower; + return register_nls(&table); + } + + return -EINVAL; +} + +static void __exit exit_nls_tis_620(void) +{ + unregister_nls(&table); + unload_nls(p_nls); +} + +module_init(init_nls_tis_620) +module_exit(exit_nls_tis_620) + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * +--------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/noquot.c linux.ac/fs/noquot.c --- linux.vanilla/fs/noquot.c Fri May 12 19:21:20 2000 +++ linux.ac/fs/noquot.c Tue Apr 3 17:55:12 2001 @@ -13,3 +13,8 @@ { return(-ENOSYS); } + +void shrink_dqcache_memory(int priority, unsigned int gfp_mask) +{ + ; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ntfs/Makefile linux.ac/fs/ntfs/Makefile --- linux.vanilla/fs/ntfs/Makefile Fri Dec 29 22:07:23 2000 +++ linux.ac/fs/ntfs/Makefile Tue Apr 3 17:55:12 2001 @@ -4,7 +4,8 @@ obj-y := fs.o sysctl.o support.o util.o inode.o dir.o super.o attr.o obj-m := $(O_TARGET) -EXTRA_CFLAGS = -DNTFS_IN_LINUX_KERNEL -DNTFS_VERSION=\"000607\" +# Version format: YYMMDD +EXTRA_CFLAGS = -DNTFS_IN_LINUX_KERNEL -DNTFS_VERSION=\"010116\" include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ntfs/attr.c linux.ac/fs/ntfs/attr.c --- linux.vanilla/fs/ntfs/attr.c Mon Apr 12 18:05:58 1999 +++ linux.ac/fs/ntfs/attr.c Tue Apr 3 17:55:12 2001 @@ -1,10 +1,10 @@ -/* - * attr.c +/* attr.c * * Copyright (C) 1996-1999 Martin von Löwis * Copyright (C) 1996-1997 Régis Duchesne * Copyright (C) 1998 Joseph Malicki * Copyright (C) 1999 Steve Dodd + * Copyright (C) 2001 Anton Altaparmakov (AIA) */ #include "ntfstypes.h" @@ -12,401 +12,389 @@ #include "attr.h" #include <linux/errno.h> -#ifdef HAVE_STRING_H -#include <string.h> -#endif #include "macros.h" #include "support.h" #include "util.h" #include "super.h" #include "inode.h" -/* Look if an attribute already exists in the inode, and if not, create it */ -int -ntfs_new_attr(ntfs_inode *ino,int type,void *name,int namelen,int *pos, - int *found, int do_search ) +/* Look if an attribute already exists in the inode, and if not, create it. */ +int ntfs_new_attr(ntfs_inode *ino, int type, void *name, int namelen, int *pos, + int *found, int do_search) { - int do_insert=0; + int do_insert = 0; int i; - for(i=0;i<ino->attr_count;i++) + for (i = 0; i < ino->attr_count; i++) { - int n=min(namelen,ino->attrs[i].namelen); - int s=ntfs_uni_strncmp(ino->attrs[i].name,name,n); - if( do_search ) { - /* - * We assume that each attribute can be uniquely - * identified by inode - * number, attribute type and attribute name. - */ - if(ino->attrs[i].type==type && ino->attrs[i].namelen==namelen && !s){ - *found=1; - *pos=i; + int n = min(namelen, ino->attrs[i].namelen); + int s = ntfs_uni_strncmp(ino->attrs[i].name, name, n); + if (do_search) { + /* We assume that each attribute can be uniquely + * identified by inode number, attribute type and + * attribute name. */ + if (ino->attrs[i].type == type && + ino->attrs[i].namelen == namelen && !s) { + *found = 1; + *pos = i; return 0; } } - /* attributes are ordered by type, then by name */ - if(ino->attrs[i].type>type || (ino->attrs[i].type==type && s==1)){ - do_insert=1; + /* Attributes are ordered by type, then by name. */ + if (ino->attrs[i].type > type || + (ino->attrs[i].type == type && s == 1)) { + do_insert = 1; break; } } - /* re-allocate space */ - if(ino->attr_count % 8 ==0) + /* Re-allocate space. */ + if (ino->attr_count % 8 == 0) { ntfs_attribute* new; - new = (ntfs_attribute*)ntfs_malloc((ino->attr_count+8)* - sizeof(ntfs_attribute)); - if( !new ) - return ENOMEM; - if( ino->attrs ) { - ntfs_memcpy( new, ino->attrs, ino->attr_count*sizeof(ntfs_attribute) ); - ntfs_free( ino->attrs ); + new = (ntfs_attribute*)ntfs_malloc((ino->attr_count + 8) * + sizeof(ntfs_attribute)); + if (!new) + return -ENOMEM; + if (ino->attrs) { + ntfs_memcpy(new, ino->attrs, ino->attr_count * + sizeof(ntfs_attribute)); + ntfs_free(ino->attrs); } ino->attrs = new; } - if(do_insert) - ntfs_memmove(ino->attrs+i+1,ino->attrs+i,(ino->attr_count-i)* - sizeof(ntfs_attribute)); - + if (do_insert) + ntfs_memmove(ino->attrs + i + 1, ino->attrs + i, + (ino->attr_count - i) * sizeof(ntfs_attribute)); ino->attr_count++; - ino->attrs[i].type=type; - ino->attrs[i].namelen=namelen; - ino->attrs[i].name=name; - *pos=i; - *found=0; + ino->attrs[i].type = type; + ino->attrs[i].namelen = namelen; + ino->attrs[i].name = name; + *pos = i; + *found = 0; return 0; } -int -ntfs_make_attr_resident(ntfs_inode *ino,ntfs_attribute *attr) +int ntfs_make_attr_resident(ntfs_inode *ino, ntfs_attribute *attr) { - int size=attr->size; - if(size>0){ + int size = attr->size; + if (size > 0) { /* FIXME: read data, free clusters */ - return EOPNOTSUPP; + return -EOPNOTSUPP; } - attr->resident=1; + attr->resident = 1; return 0; } -/* Store in the inode readable information about a run */ -void -ntfs_insert_run(ntfs_attribute *attr,int cnum,ntfs_cluster_t cluster,int len) +/* Store in the inode readable information about a run. */ +void ntfs_insert_run(ntfs_attribute *attr, int cnum, ntfs_cluster_t cluster, + int len) { - /* (re-)allocate space if necessary */ - if(attr->d.r.len % 8 == 0) { + /* (re-)allocate space if necessary. */ + if (attr->d.r.len % 8 == 0) { ntfs_runlist* new; - new = ntfs_malloc((attr->d.r.len+8)*sizeof(ntfs_runlist)); - if( !new ) + new = ntfs_malloc((attr->d.r.len + 8) * sizeof(ntfs_runlist)); + if (!new) return; - if( attr->d.r.runlist ) { + if (attr->d.r.runlist) { ntfs_memcpy(new, attr->d.r.runlist, attr->d.r.len - *sizeof(ntfs_runlist)); - ntfs_free( attr->d.r.runlist ); + * sizeof(ntfs_runlist)); + ntfs_free(attr->d.r.runlist); } attr->d.r.runlist = new; } - if(attr->d.r.len>cnum) - ntfs_memmove(attr->d.r.runlist+cnum+1,attr->d.r.runlist+cnum, - (attr->d.r.len-cnum)*sizeof(ntfs_runlist)); - attr->d.r.runlist[cnum].cluster=cluster; - attr->d.r.runlist[cnum].len=len; + if (attr->d.r.len > cnum) + ntfs_memmove(attr->d.r.runlist + cnum + 1, + attr->d.r.runlist + cnum, + (attr->d.r.len - cnum) * sizeof(ntfs_runlist)); + attr->d.r.runlist[cnum].cluster = cluster; + attr->d.r.runlist[cnum].len = len; attr->d.r.len++; } -/* Extends an attribute. Another run will be added if necessary, - * but we try to extend the last run in the runlist first. +/* Extends an attribute. Another run will be added if necessary, but we try to + * extend the last run in the runlist first. * FIXME: what if there isn't enough contiguous space, we don't create * multiple runs? * * *len: the desired new length of the attr (_not_ the amount to extend by) */ -int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, int *len, - int flags) +int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, int *len, int flags) { - int error=0; + int error = 0; ntfs_runlist *rl; int rlen; ntfs_cluster_t cluster; int clen; - if(attr->compressed)return EOPNOTSUPP; - if(ino->record_count>1)return EOPNOTSUPP; - - if(attr->resident) { - error = ntfs_make_attr_nonresident(ino,attr); - if(error) + if (attr->compressed || ino->record_count > 1) + return -EOPNOTSUPP; + if (attr->resident) { + error = ntfs_make_attr_nonresident(ino, attr); + if (error) return error; } - - if( *len <= attr->allocated ) - return 0; /* truely stupid things do sometimes happen */ - - rl=attr->d.r.runlist; - rlen=attr->d.r.len-1; - - if(rlen>=0) - cluster=rl[rlen].cluster+rl[rlen].len; + if (*len <= attr->allocated) + return 0; /* Truely stupid things do sometimes happen. */ + rl = attr->d.r.runlist; + rlen = attr->d.r.len - 1; + if (rlen >= 0) + cluster = rl[rlen].cluster + rl[rlen].len; else - /* no preference for allocation space */ - cluster=0; - - /* calculate the extra space we need, and round up to multiple of cluster - * size to get number of new clusters needed */ - - clen=( (*len - attr->allocated ) + ino->vol->clustersize - 1 ) / + /* No preference for allocation space. */ + cluster = 0; + /* Calculate the extra space we need, and round up to multiple of + * cluster size to get number of new clusters needed */ + clen = ((*len - attr->allocated) + ino->vol->clustersize - 1) / ino->vol->clustersize; - if(clen==0) + if (clen == 0) return 0; - /* FIXME: try to allocate smaller pieces */ - error=ntfs_allocate_clusters(ino->vol,&cluster,&clen, - flags|ALLOC_REQUIRE_SIZE); - if(error)return error; - attr->allocated += clen*ino->vol->clustersize; + error = ntfs_allocate_clusters(ino->vol, &cluster, &clen, + flags | ALLOC_REQUIRE_SIZE); + if (error) + return error; + attr->allocated += clen * ino->vol->clustersize; *len = attr->allocated; - - /* contiguous chunk */ - if(rlen>=0 && cluster==rl[rlen].cluster+rl[rlen].len){ + /* Contiguous chunk. */ + if (rlen >= 0 && cluster == rl[rlen].cluster + rl[rlen].len) { rl[rlen].len += clen; return 0; } - ntfs_insert_run(attr,rlen+1,cluster,clen); + ntfs_insert_run(attr, rlen + 1, cluster, clen); return 0; } -int -ntfs_make_attr_nonresident(ntfs_inode *ino, ntfs_attribute *attr) +int ntfs_make_attr_nonresident(ntfs_inode *ino, ntfs_attribute *attr) { - void *data=attr->d.data; - int len=attr->size; - int error,alen; + void *data = attr->d.data; + int len = attr->size; + int error, alen; ntfs_io io; - attr->d.r.len=0; - attr->d.r.runlist=0; - attr->resident=0; - attr->allocated=attr->initialized=0; - alen=len; - error=ntfs_extend_attr(ino,attr,&alen,ALLOC_REQUIRE_SIZE); - if(error)return error;/* FIXME: On error, restore old values */ - io.fn_put=ntfs_put; - io.fn_get=ntfs_get; - io.param=data; - io.size=len; - io.do_read=0; - return ntfs_readwrite_attr(ino,attr,0,&io); + attr->d.r.len = 0; + attr->d.r.runlist = 0; + attr->resident = 0; + attr->allocated=attr->initialized = 0; + alen = len; + error = ntfs_extend_attr(ino, attr, &alen, ALLOC_REQUIRE_SIZE); + if (error) + return error; /* FIXME: On error, restore old values. */ + io.fn_put = ntfs_put; + io.fn_get = ntfs_get; + io.param = data; + io.size = len; + io.do_read = 0; + return ntfs_readwrite_attr(ino, attr, 0, &io); } -int -ntfs_attr_allnonresident(ntfs_inode *ino) +int ntfs_attr_allnonresident(ntfs_inode *ino) { - int i, error=0; + int i, error = 0; ntfs_volume *vol = ino->vol; - for (i=0; !error && i<ino->attr_count; i++) + for (i = 0; !error && i < ino->attr_count; i++) { - if (ino->attrs[i].type != vol->at_security_descriptor - && ino->attrs[i].type != vol->at_data) + if (ino->attrs[i].type != vol->at_security_descriptor && + ino->attrs[i].type != vol->at_data) continue; - error = ntfs_make_attr_nonresident (ino, ino->attrs+i); + error = ntfs_make_attr_nonresident(ino, ino->attrs + i); } return error; } -/* Resize the attribute to a newsize */ +/* Resize the attribute to a newsize. */ int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, int newsize) { - int error=0; - int oldsize=attr->size; - int clustersize=ino->vol->clustersize; - int i,count,newlen,newcount; + int error = 0; + int oldsize = attr->size; + int clustersize = ino->vol->clustersize; + int i, count, newlen, newcount; ntfs_runlist *rl; - if(newsize==oldsize) + if (newsize == oldsize) return 0; - /* modifying compressed attributes not supported yet */ - if(attr->compressed) - /* extending is easy: just insert sparse runs */ - return EOPNOTSUPP; - if(attr->resident){ + /* FIXME: Modifying compressed attributes not supported yet. */ + if (attr->compressed) + /* FIXME: Extending is easy: just insert sparse runs. */ + return -EOPNOTSUPP; + if (attr->resident) { void *v; - if(newsize>ino->vol->mft_recordsize){ - error=ntfs_make_attr_nonresident(ino,attr); - if(error)return error; - return ntfs_resize_attr(ino,attr,newsize); + if (newsize > ino->vol->mft_recordsize) { + error = ntfs_make_attr_nonresident(ino, attr); + if (error) + return error; + return ntfs_resize_attr(ino, attr, newsize); } - v=attr->d.data; - if(newsize){ - attr->d.data=ntfs_malloc(newsize); - if(!attr->d.data) { + v = attr->d.data; + if (newsize) { + attr->d.data = ntfs_malloc(newsize); + if (!attr->d.data) { ntfs_free(v); - return ENOMEM; + return -ENOMEM; } - if(newsize>oldsize) - ntfs_bzero((char*)attr->d.data+oldsize, - newsize-oldsize); - ntfs_memcpy((char*)attr->d.data,v,min(newsize,oldsize)); - }else - attr->d.data=0; + if (newsize > oldsize) + ntfs_bzero((char*)attr->d.data + oldsize, + newsize - oldsize); + ntfs_memcpy((char*)attr->d.data, v, + min(newsize, oldsize)); + } else + attr->d.data = 0; ntfs_free(v); - attr->size=newsize; + attr->size = newsize; return 0; } - /* non-resident attribute */ - rl=attr->d.r.runlist; - if(newsize<oldsize){ - for(i=0,count=0;i<attr->d.r.len;i++){ - if((count+rl[i].len)*clustersize>newsize) + /* Non-resident attribute. */ + rl = attr->d.r.runlist; + if (newsize < oldsize) { + for (i = 0, count = 0; i < attr->d.r.len; i++) { + if ((count + rl[i].len) * clustersize > newsize) break; - count+=(int)rl[i].len; + count += (int)rl[i].len; } - newlen=i+1; - /* free unused clusters in current run, unless sparse */ - newcount=count; - if(rl[i].cluster!=MAX_CLUSTER_T){ - int rounded=newsize-count*clustersize; - rounded=(rounded+clustersize-1)/clustersize; - error=ntfs_deallocate_clusters(ino->vol,rl[i].cluster+rounded, - (int)rl[i].len-rounded); - if(error) - return error; /* FIXME: incomplete operation */ - rl[i].len=rounded; - newcount=count+rounded; + newlen = i + 1; + /* Free unused clusters in current run, unless sparse. */ + newcount = count; + if (rl[i].cluster != MAX_CLUSTER_T) { + int rounded = newsize - count * clustersize; + rounded = (rounded + clustersize - 1) / clustersize; + error = ntfs_deallocate_clusters(ino->vol, + rl[i].cluster + rounded, + (int)rl[i].len - rounded); + if (error) + return error; /* FIXME: Incomplete operation. */ + rl[i].len = rounded; + newcount = count + rounded; } - /* free all other runs */ - for(i++;i<attr->d.r.len;i++) - if(rl[i].cluster!=MAX_CLUSTER_T){ - error=ntfs_deallocate_clusters(ino->vol,rl[i].cluster,(int)rl[i].len); - if(error) - return error; /* FIXME: incomplete operation */ + /* Free all other runs. */ + for (i++; i < attr->d.r.len; i++) + if (rl[i].cluster != MAX_CLUSTER_T) { + error = ntfs_deallocate_clusters(ino->vol, + rl[i].cluster, + (int)rl[i].len); + if (error) + return error; /* FIXME: Incomplete + * operation */ } - /* FIXME? free space for extra runs in memory */ - attr->d.r.len=newlen; - }else{ - newlen=newsize; - error=ntfs_extend_attr(ino,attr,&newlen,ALLOC_REQUIRE_SIZE); - if(error)return error; /* FIXME: incomplete */ - newcount=newlen/clustersize; + /* FIXME: Free space for extra runs in memory? */ + attr->d.r.len = newlen; + } else { + newlen = newsize; + error = ntfs_extend_attr(ino, attr, &newlen, + ALLOC_REQUIRE_SIZE); + if (error) + return error; /* FIXME: Incomplete operation. */ + newcount = newlen / clustersize; } - /* fill in new sizes */ - attr->allocated = newcount*clustersize; + /* Fill in new sizes. */ + attr->allocated = newcount * clustersize; attr->size = newsize; /* attr->initialized does not change. */ - if(!newsize) - error=ntfs_make_attr_resident(ino,attr); + if (!newsize) + error = ntfs_make_attr_resident(ino, attr); return error; } int ntfs_create_attr(ntfs_inode *ino, int anum, char *aname, void *data, - int dsize, ntfs_attribute **rattr) + int dsize, ntfs_attribute **rattr) { void *name; int namelen; - int found,i; + int found, i; int error; ntfs_attribute *attr; - if(dsize>ino->vol->mft_recordsize) - /* FIXME: non-resident attributes */ - return EOPNOTSUPP; - if(aname){ - namelen=strlen(aname); - name=ntfs_malloc(2*namelen); - if( !name ) - return ENOMEM; - ntfs_ascii2uni(name,aname,namelen); - }else{ - name=0; - namelen=0; - } - - error = ntfs_new_attr(ino,anum,name,namelen,&i,&found,1); - if( error ) { - ntfs_free( name ); + + if (dsize > ino->vol->mft_recordsize) + /* FIXME: Non-resident attributes. */ + return -EOPNOTSUPP; + if (aname) { + namelen = strlen(aname); + name = ntfs_malloc(2 * namelen); + if (!name) + return -ENOMEM; + ntfs_ascii2uni(name, aname, namelen); + } else { + name = 0; + namelen = 0; + } + error = ntfs_new_attr(ino, anum, name, namelen, &i, &found, 1); + if (error) { + ntfs_free(name); return error; } - - if(found){ + if (found) { ntfs_free(name); - return EEXIST; + return -EEXIST; } - *rattr=attr=ino->attrs+i; - /* allocate a new number. - FIXME: Should this happen on inode writeback? - FIXME: extensions records not supported */ - error=ntfs_allocate_attr_number(ino,&i); - if(error) + *rattr = attr = ino->attrs + i; + /* Allocate a new number. + * FIXME: Should this happen on inode writeback? + * FIXME: Extension records not supported. */ + error = ntfs_allocate_attr_number(ino, &i); + if (error) return error; - attr->attrno=i; - - attr->resident=1; - attr->compressed=attr->cengine=0; - attr->size=attr->allocated=attr->initialized=dsize; + attr->attrno = i; + attr->resident = 1; + attr->compressed = attr->cengine = 0; + attr->size = attr->allocated = attr->initialized = dsize; /* FIXME: INDEXED information should come from $AttrDef - Currently, only file names are indexed */ - if(anum==ino->vol->at_file_name){ - attr->indexed=1; - }else - attr->indexed=0; - attr->d.data=ntfs_malloc(dsize); - - if( !attr->d.data ) - return ENOMEM; - - ntfs_memcpy(attr->d.data,data,dsize); + * Currently, only file names are indexed. As of NTFS v3.0 (Win2k), + * this is no longer true. Different attributes can be indexed now. */ + if (anum == ino->vol->at_file_name) { + attr->indexed = 1; + } else + attr->indexed = 0; + attr->d.data = ntfs_malloc(dsize); + if (!attr->d.data) + return -ENOMEM; + ntfs_memcpy(attr->d.data, data, dsize); return 0; } /* Non-resident attributes are stored in runs (intervals of clusters). * * This function stores in the inode readable information about a non-resident - * attribute. - */ -static int -ntfs_process_runs(ntfs_inode *ino,ntfs_attribute* attr,unsigned char *data) + * attribute. */ +static int ntfs_process_runs(ntfs_inode *ino, ntfs_attribute* attr, + unsigned char *data) { - int startvcn,endvcn; - int vcn,cnum; + int startvcn, endvcn; + int vcn, cnum; ntfs_cluster_t cluster; - int len,ctype; - startvcn = NTFS_GETU64(data+0x10); - endvcn = NTFS_GETU64(data+0x18); - - /* check whether this chunk really belongs to the end */ - for(cnum=0,vcn=0;cnum<attr->d.r.len;cnum++) - vcn+=attr->d.r.runlist[cnum].len; - if(vcn!=startvcn) - { + int len, ctype; + startvcn = NTFS_GETU64(data + 0x10); + endvcn = NTFS_GETU64(data + 0x18); + + /* Check whether this chunk really belongs to the end. */ + for (cnum = 0, vcn = 0; cnum < attr->d.r.len; cnum++) + vcn += attr->d.r.runlist[cnum].len; + if (vcn != startvcn) { ntfs_error("Problem with runlist in extended record\n"); return -1; } - if(!endvcn) - { - endvcn = NTFS_GETU64(data+0x28)-1; /* allocated length */ + if (!endvcn) { + endvcn = NTFS_GETU64(data + 0x28) - 1; /* Allocated length. */ endvcn /= ino->vol->clustersize; } - data=data+NTFS_GETU16(data+0x20); - cnum=attr->d.r.len; - cluster=0; - for(vcn=startvcn; vcn<=endvcn; vcn+=len) - { - if(ntfs_decompress_run(&data,&len,&cluster,&ctype)) + data = data + NTFS_GETU16(data + 0x20); + cnum = attr->d.r.len; + cluster = 0; + for (vcn = startvcn; vcn <= endvcn; vcn += len) { + if (ntfs_decompress_run(&data, &len, &cluster, &ctype)) return -1; - if(ctype) - ntfs_insert_run(attr,cnum,-1,len); + if (ctype) + ntfs_insert_run(attr, cnum, -1, len); else - ntfs_insert_run(attr,cnum,cluster,len); + ntfs_insert_run(attr, cnum, cluster, len); cnum++; } return 0; } -/* Insert the attribute starting at attr in the inode ino */ +/* Insert the attribute starting at attr in the inode ino. */ int ntfs_insert_attribute(ntfs_inode *ino, unsigned char* attrdata) { - int i,found; + int i, found; int type; short int *name; int namelen; @@ -415,208 +403,207 @@ int error; type = NTFS_GETU32(attrdata); - namelen = NTFS_GETU8(attrdata+9); - /* read the attribute's name if it has one */ - if(!namelen) - name=0; - else - { - /* 1 Unicode character fits in 2 bytes */ - name=ntfs_malloc(2*namelen); - if( !name ) - return ENOMEM; - - ntfs_memcpy(name,attrdata+NTFS_GETU16(attrdata+10),2*namelen); - } - - error = ntfs_new_attr(ino,type,name,namelen,&i,&found,1); - if( error ) { - if( name ) ntfs_free( name ); + namelen = NTFS_GETU8(attrdata + 9); + /* Read the attribute's name if it has one. */ + if (!namelen) + name = 0; + else { + /* 1 Unicode character fits in 2 bytes. */ + name = ntfs_malloc(2 * namelen); + if (!name) + return -ENOMEM; + ntfs_memcpy(name, attrdata + NTFS_GETU16(attrdata + 10), + 2 * namelen); + } + error = ntfs_new_attr(ino, type, name, namelen, &i, &found, 1); + if (error) { + if (name) + ntfs_free(name); return error; } - - /* We can have in one inode two attributes with type 0x00000030 (File Name) - and without name */ - if(found && /*FIXME*/type!=ino->vol->at_file_name) + /* We can have in one inode two attributes with type 0x00000030 (File + * Name) and without name. FIXME: We can have a lot more than two! + * That is how hard links are implemented. (AIA) */ + if (found && /*FIXME*/ type != ino->vol->at_file_name) { - ntfs_process_runs(ino,ino->attrs+i,attrdata); + ntfs_process_runs(ino, ino->attrs + i, attrdata); return 0; - } else if( found ) { - /* Don't understand the above, but I know it leaks memory below - as it overwrites a found entry without freeing it. So here we - call ntfs_new_attr again but this time ask it to always allocate a - new entry */ - ntfs_new_attr(ino,type,name,namelen,&i,&found,0); - } - attr=ino->attrs+i; - attr->resident=NTFS_GETU8(attrdata+8)==0; - attr->compressed=NTFS_GETU16(attrdata+0xC); - attr->attrno=NTFS_GETU16(attrdata+0xE); + } else if (found) { + /* Don't understand the above, but I know it leaks memory below + * as it overwrites a found entry without freeing it. So here + * we call ntfs_new_attr again but this time ask it to always + * allocate a new entry. */ + ntfs_new_attr(ino, type, name, namelen, &i, &found, 0); + } + attr = ino->attrs + i; + attr->resident = NTFS_GETU8(attrdata + 8) == 0; + attr->compressed = NTFS_GETU16(attrdata + 0xC); + attr->attrno = NTFS_GETU16(attrdata + 0xE); - if(attr->resident) { - attr->size=NTFS_GETU16(attrdata+0x10); - data=attrdata+NTFS_GETU16(attrdata+0x14); + if (attr->resident) { + attr->size = NTFS_GETU16(attrdata + 0x10); + data = attrdata + NTFS_GETU16(attrdata + 0x14); attr->d.data = (void*)ntfs_malloc(attr->size); - if( !attr->d.data ) - return ENOMEM; - ntfs_memcpy(attr->d.data,data,attr->size); - attr->indexed=NTFS_GETU16(attrdata+0x16); - }else{ - attr->allocated=NTFS_GETU32(attrdata+0x28); - attr->size=NTFS_GETU32(attrdata+0x30); - attr->initialized=NTFS_GETU32(attrdata+0x38); - attr->cengine=NTFS_GETU16(attrdata+0x22); - if(attr->compressed) - attr->compsize=NTFS_GETU32(attrdata+0x40); - ino->attrs[i].d.r.runlist=0; - ino->attrs[i].d.r.len=0; - ntfs_process_runs(ino,attr,attrdata); + if (!attr->d.data) + return -ENOMEM; + ntfs_memcpy(attr->d.data, data, attr->size); + attr->indexed = NTFS_GETU16(attrdata + 0x16); + } else { + attr->allocated = NTFS_GETU32(attrdata + 0x28); + attr->size = NTFS_GETU32(attrdata + 0x30); + attr->initialized = NTFS_GETU32(attrdata + 0x38); + attr->cengine = NTFS_GETU16(attrdata + 0x22); + if (attr->compressed) + attr->compsize = NTFS_GETU32(attrdata + 0x40); + ino->attrs[i].d.r.runlist = 0; + ino->attrs[i].d.r.len = 0; + ntfs_process_runs(ino, attr, attrdata); } return 0; } -int -ntfs_read_zero(ntfs_io *dest,int size) +int ntfs_read_zero(ntfs_io *dest, int size) { - char *sparse=ntfs_calloc(512); - if(!sparse) - return ENOMEM; - while(size){ - int i=min(size,512); - dest->fn_put(dest,sparse,i); - size-=i; + char *sparse = ntfs_calloc(512); + if (!sparse) + return -ENOMEM; + while (size) { + int i = min(size, 512); + dest->fn_put(dest, sparse, i); + size -= i; } ntfs_free(sparse); return 0; } -/* process compressed attributes */ +/* Process compressed attributes. */ int ntfs_read_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset, - ntfs_io *dest) + ntfs_io *dest) { - int error=0; - int clustersize,l; - int s_vcn,rnum,vcn,len,chunk,got,l1,offs1,copied; - ntfs_cluster_t cluster,cl1; - char *comp=0,*comp1; - char *decomp=0; + int error = 0; + int clustersize, l; + int s_vcn, rnum, vcn, len, chunk, got, l1, offs1, copied; + ntfs_cluster_t cluster, cl1; + char *comp = 0, *comp1; + char *decomp = 0; ntfs_io io; ntfs_runlist *rl; - l=dest->size; - clustersize=ino->vol->clustersize; - /* starting cluster of potential chunk - there are three situations: - a) in a large uncompressible or sparse chunk, - s_vcn is in the middle of a run - b) s_vcn is right on a run border - c) when several runs make a chunk, s_vcn is before the chunks - */ - s_vcn=offset/clustersize; - /* round down to multiple of 16 */ + l = dest->size; + clustersize = ino->vol->clustersize; + /* Starting cluster of potential chunk. There are three situations: + a) In a large uncompressible or sparse chunk, s_vcn is in the middle + of a run. + b) s_vcn is right on a run border. + c) When several runs make a chunk, s_vcn is before the chunks. */ + s_vcn = offset / clustersize; + /* Round down to multiple of 16. */ s_vcn &= ~15; - rl=attr->d.r.runlist; - for(rnum=vcn=0;rnum<attr->d.r.len && vcn+rl->len<=s_vcn;rnum++,rl++) - vcn+=rl->len; - if(rnum==attr->d.r.len){ - /* beyond end of file */ - /* FIXME: check allocated/initialized */ - dest->size=0; + rl = attr->d.r.runlist; + for (rnum = vcn = 0; rnum < attr->d.r.len && vcn + rl->len <= s_vcn; + rnum++, rl++) + vcn += rl->len; + if (rnum == attr->d.r.len) { + /* Beyond end of file. */ + /* FIXME: Check allocated / initialized. */ + dest->size = 0; return 0; } - io.do_read=1; - io.fn_put=ntfs_put; - io.fn_get=0; - cluster=rl->cluster; - len=rl->len; - copied=0; - while(l){ - chunk=0; - if(cluster==MAX_CLUSTER_T){ - /* sparse cluster */ + io.do_read = 1; + io.fn_put = ntfs_put; + io.fn_get = 0; + cluster = rl->cluster; + len = rl->len; + copied = 0; + while (l) { + chunk = 0; + if (cluster == MAX_CLUSTER_T) { + /* Sparse cluster. */ int l1; - if((len-(s_vcn-vcn)) & 15) - ntfs_error("unexpected sparse chunk size"); - l1=chunk = min((vcn+len)*clustersize-offset,l); - error = ntfs_read_zero(dest,l1); - if(error) + if ((len - (s_vcn - vcn)) & 15) + ntfs_error("Unexpected sparse chunk size."); + l1 = chunk = min((vcn + len) * clustersize - offset, l); + error = ntfs_read_zero(dest, l1); + if (error) goto out; - }else if(dest->do_read){ - if(!comp){ - comp=ntfs_malloc(16*clustersize); - if(!comp){ - error=ENOMEM; + } else if (dest->do_read) { + if (!comp) { + comp = ntfs_malloc(16 * clustersize); + if (!comp) { + error = -ENOMEM; goto out; } } - got=0; - /* we might need to start in the middle of a run */ - cl1=cluster+s_vcn-vcn; - comp1=comp; - do{ - io.param=comp1; - l1=min(len-max(s_vcn-vcn,0),16-got); - io.size=l1*clustersize; - error=ntfs_getput_clusters(ino->vol,cl1,0,&io); - if(error)goto out; - if(l1+max(s_vcn-vcn,0)==len){ - rnum++;rl++; - vcn+=len; - cluster=cl1=rl->cluster; - len=rl->len; + got = 0; + /* We might need to start in the middle of a run. */ + cl1 = cluster + s_vcn - vcn; + comp1 = comp; + do { + io.param = comp1; + l1 = min(len - max(s_vcn - vcn, 0), 16 - got); + io.size = l1 * clustersize; + error = ntfs_getput_clusters(ino->vol, cl1, 0, + &io); + if (error) + goto out; + if (l1 + max(s_vcn - vcn, 0) == len) { + rnum++; + rl++; + vcn += len; + cluster = cl1 = rl->cluster; + len = rl->len; } - got+=l1; - comp1+=l1*clustersize; - }while(cluster!=MAX_CLUSTER_T && got<16); /* until empty run */ - chunk=16*clustersize; - if(cluster!=MAX_CLUSTER_T || got==16) - /* uncompressible */ - comp1=comp; - else{ - if(!decomp){ - decomp=ntfs_malloc(16*clustersize); - if(!decomp){ - error=ENOMEM; + got += l1; + comp1 += l1 * clustersize; + } while (cluster != MAX_CLUSTER_T && got < 16); + /* Until empty run. */ + chunk = 16 * clustersize; + if (cluster != MAX_CLUSTER_T || got == 16) + /* Uncompressible */ + comp1 = comp; + else { + if (!decomp) { + decomp = ntfs_malloc(16 * clustersize); + if (!decomp) { + error = -ENOMEM; goto out; } } - /* make sure there are null bytes - after the last block */ - *(ntfs_u32*)comp1=0; - ntfs_decompress(decomp,comp,chunk); - comp1=decomp; + /* Make sure there are null bytes after the + * last block. */ + *(ntfs_u32*)comp1 = 0; + ntfs_decompress(decomp, comp, chunk); + comp1 = decomp; } - offs1=offset-s_vcn*clustersize; - chunk=min(16*clustersize-offs1,chunk); - chunk=min(l,chunk); - dest->fn_put(dest,comp1+offs1,chunk); + offs1 = offset - s_vcn * clustersize; + chunk = min(16 * clustersize - offs1, chunk); + chunk = min(l, chunk); + dest->fn_put(dest, comp1 + offs1, chunk); } - l-=chunk; - copied+=chunk; - offset+=chunk; - s_vcn=offset/clustersize & ~15; - if(l && offset>=((vcn+len)*clustersize)){ - rnum++;rl++; - vcn+=len; - cluster=rl->cluster; - len=rl->len; + l -= chunk; + copied += chunk; + offset += chunk; + s_vcn = offset / clustersize & ~15; + if (l && offset >= ((vcn + len) * clustersize)) { + rnum++; + rl++; + vcn += len; + cluster = rl->cluster; + len = rl->len; } } out: - if(comp)ntfs_free(comp); - if(decomp)ntfs_free(decomp); - dest->size=copied; + if (comp) + ntfs_free(comp); + if (decomp) + ntfs_free(decomp); + dest->size = copied; return error; } int ntfs_write_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset, - ntfs_io *dest) + ntfs_io *dest) { - return EOPNOTSUPP; + return -EOPNOTSUPP; } -/* - * Local variables: - * c-file-style: "linux" - * End: - */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ntfs/attr.h linux.ac/fs/ntfs/attr.h --- linux.vanilla/fs/ntfs/attr.h Mon Apr 12 18:05:58 1999 +++ linux.ac/fs/ntfs/attr.h Tue Apr 3 17:55:12 2001 @@ -1,24 +1,33 @@ -/* - * attr.h - * Header file for attr.c +/* attr.h - Header file for attr.c * * Copyright (C) 1997 Régis Duchesne */ int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, int *len, - int flags); + int flags); + int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, int newsize); + int ntfs_insert_attribute(ntfs_inode *ino, unsigned char* attrdata); + int ntfs_read_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset, - ntfs_io *dest); + ntfs_io *dest); + int ntfs_write_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset, - ntfs_io *dest); + ntfs_io *dest); + int ntfs_create_attr(ntfs_inode *ino, int anum, char *aname, void *data, - int dsize, ntfs_attribute **rattr); -int ntfs_read_zero(ntfs_io *dest,int size); + int dsize, ntfs_attribute **rattr); + +int ntfs_read_zero(ntfs_io *dest, int size); + int ntfs_make_attr_nonresident(ntfs_inode *ino, ntfs_attribute *attr); + int ntfs_attr_allnonresident(ntfs_inode *ino); -int ntfs_new_attr( ntfs_inode *ino, int type, void *name, int namelen, - int *pos, int *found, int do_search ); -void ntfs_insert_run( ntfs_attribute *attr, int cnum, ntfs_cluster_t cluster, - int len ); + +int ntfs_new_attr(ntfs_inode *ino, int type, void *name, int namelen, + int *pos, int *found, int do_search ); + +void ntfs_insert_run(ntfs_attribute *attr, int cnum, ntfs_cluster_t cluster, + int len ); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ntfs/dir.c linux.ac/fs/ntfs/dir.c --- linux.vanilla/fs/ntfs/dir.c Mon Apr 12 18:05:58 1999 +++ linux.ac/fs/ntfs/dir.c Tue Apr 3 17:55:13 2001 @@ -1,9 +1,9 @@ -/* - * dir.c +/* dir.c * * Copyright (C) 1995-1997, 1999 Martin von Löwis * Copyright (C) 1999 Steve Dodd * Copyright (C) 1999 Joseph Malicki + * Copyright (C) 2001 Anton Altaparmakov (AIA) */ #include "ntfstypes.h" @@ -20,39 +20,44 @@ static char I30[]="$I30"; -/* An index record should start with INDX, and the last word in each - block should contain the check value. If it passes, the original - values need to be restored */ +/* An index record should start with INDX, and the last word in each block + * should contain the check value. If it passes, the original values need to + * be restored. */ int ntfs_check_index_record(ntfs_inode *ino, char *record) { - return ntfs_fixup_record(ino->vol, record, "INDX", + return ntfs_fixup_record(ino->vol, record, "INDX", ino->u.index.recordsize); } static inline int ntfs_is_top(ntfs_u64 stack) { - return stack==14; + return stack == 14; } static int ntfs_pop(ntfs_u64 *stack) { - static int width[16]={1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,-1}; - int res=-1; - switch(width[*stack & 15]) - { - case 1:res=(int)((*stack&15)>>1); - *stack>>=4; + static int width[16] = {1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,-1}; + int res = -1; + + switch (width[*stack & 15]) { + case 1: + res = (int)((*stack & 15) >> 1); + *stack >>= 4; break; - case 2:res=(int)(((*stack&63)>>2)+7); - *stack>>=6; + case 2: + res = (int)(((*stack & 63) >> 2) + 7); + *stack >>= 6; break; - case 3:res=(int)(((*stack & 255)>>3)+23); - *stack>>=8; + case 3: + res = (int)(((*stack & 255) >> 3) + 23); + *stack >>= 8; break; - case 4:res=(int)(((*stack & 1023)>>4)+55); - *stack>>=10; + case 4: + res = (int)(((*stack & 1023) >> 4) + 55); + *stack >>= 10; break; - default:ntfs_error("Unknown encoding\n"); + default: + ntfs_error("Unknown encoding\n"); } return res; } @@ -62,12 +67,16 @@ return 14; } -static ntfs_u64 ntfs_push(ntfs_u64 stack,int i) +static ntfs_u64 ntfs_push(ntfs_u64 stack, int i) { - if(i<7)return (stack<<4)|(i<<1); - if(i<23)return (stack<<6)|((i-7)<<2)|1; - if(i<55)return (stack<<8)|((i-23)<<3)|3; - if(i<120)return (stack<<10)|((i-55)<<4)|7; + if (i < 7) + return (stack << 4) | (i << 1); + if (i < 23) + return (stack << 6) | ((i - 7) << 2) | 1; + if (i < 55) + return (stack << 8) | ((i - 23) << 3) | 3; + if (i < 120) + return (stack << 10) | ((i - 55) << 4) | 7; ntfs_error("Too many entries\n"); return ~((ntfs_u64)0); } @@ -77,133 +86,136 @@ { while(!ntfs_is_top(stack)) { - printf("%d ",ntfs_pop(&stack)); + printf("%d ", ntfs_pop(&stack)); } printf("\n"); } #endif -/* True if the entry points to another block of entries */ +/* True if the entry points to another block of entries. */ static inline int ntfs_entry_has_subnodes(char* entry) { - return (int)NTFS_GETU8(entry+12)&1; + return (int)NTFS_GETU8(entry + 12) & 1; } -/* True if it is not the 'end of dir' entry */ +/* True if it is not the 'end of dir' entry. */ static inline int ntfs_entry_is_used(char* entry) { - return (int)(NTFS_GETU8(entry+12)&2)==0; + return (int)(NTFS_GETU8(entry + 12) & 2) == 0; } static int ntfs_allocate_index_block(ntfs_iterate_s *walk) { - ntfs_attribute *allocation=0,*bitmap=0; - int error,size,i,bit; + ntfs_attribute *allocation = 0, *bitmap = 0; + int error, size, i, bit; ntfs_u8 *bmap; ntfs_io io; - ntfs_volume *vol=walk->dir->vol; + ntfs_volume *vol = walk->dir->vol; - /* check for allocation attribute */ - allocation=ntfs_find_attr(walk->dir,vol->at_index_allocation,I30); - if(!allocation){ + /* Check for allocation attribute. */ + allocation = ntfs_find_attr(walk->dir, vol->at_index_allocation, I30); + if (!allocation) { ntfs_u8 bmp[8]; - /* create index allocation attribute */ - error=ntfs_create_attr(walk->dir,vol->at_index_allocation,I30, - 0,0,&allocation); - if(error)return error; - ntfs_bzero(bmp,sizeof(bmp)); - error=ntfs_create_attr(walk->dir,vol->at_bitmap,I30, - bmp,sizeof(bmp),&bitmap); - if(error)return error; - }else - bitmap=ntfs_find_attr(walk->dir,vol->at_bitmap,I30); - if(!bitmap){ + /* Create index allocation attribute. */ + error = ntfs_create_attr(walk->dir, vol->at_index_allocation, + I30, 0, 0, &allocation); + if (error) + return error; + ntfs_bzero(bmp, sizeof(bmp)); + error = ntfs_create_attr(walk->dir, vol->at_bitmap, I30, bmp, + sizeof(bmp), &bitmap); + if (error) + return error; + } else + bitmap = ntfs_find_attr(walk->dir, vol->at_bitmap, I30); + if (!bitmap) { ntfs_error("Directory w/o bitmap\n"); - return EINVAL; + return -EINVAL; } - size=bitmap->size; - bmap=ntfs_malloc(size); - if(!bmap)return ENOMEM; - io.fn_put=ntfs_put; - io.fn_get=ntfs_get; - io.param=bmap; - io.size=size; - error=ntfs_read_attr(walk->dir,vol->at_bitmap,I30,0,&io); - if(error){ + size = bitmap->size; + bmap = ntfs_malloc(size); + if (!bmap) + return -ENOMEM; + io.fn_put = ntfs_put; + io.fn_get = ntfs_get; + io.param = bmap; + io.size = size; + error = ntfs_read_attr(walk->dir, vol->at_bitmap, I30, 0, &io); + if (error) { ntfs_free(bmap); return error; } - if(io.size!=size){ + if (io.size != size) { ntfs_free(bmap); - return EIO; + return -EIO; } - - /* allocate a bit */ - for(i=bit=0;i<size;i++){ - if(bmap[i]==0xFF)continue; - for(bit=0;bit<8;bit++) - if(((bmap[i]>>bit) & 1) == 0) + /* Allocate a bit. */ + for (i = bit = 0; i < size; i++) { + if (bmap[i] == 0xFF) + continue; + for (bit = 0; bit < 8; bit++) + if (((bmap[i] >> bit) & 1) == 0) break; - if(bit!=8)break; + if (bit != 8) + break; } - if(i==size) - /* FIXME: extend bitmap */ - return EOPNOTSUPP; - walk->newblock=(i*8+bit)*walk->dir->u.index.clusters_per_record; - bmap[i]|= 1<<bit; - io.param=bmap; - io.size=size; - error=ntfs_write_attr(walk->dir,vol->at_bitmap,I30,0,&io); - if(error || io.size!=size){ + if (i == size) + /* FIXME: Extend bitmap. */ + return -EOPNOTSUPP; + walk->newblock = (i * 8 + bit) * walk->dir->u.index.clusters_per_record; + bmap[i] |= 1 << bit; + io.param = bmap; + io.size = size; + error = ntfs_write_attr(walk->dir, vol->at_bitmap, I30, 0, &io); + if (error || io.size != size) { ntfs_free(bmap); - return error?error:EIO; + return error ? error : -EIO; } ntfs_free(bmap); - - /* check whether record is out of allocated range */ - size=allocation->size; - if(walk->newblock * vol->clustersize >= size){ - /* build index record */ - int s1=walk->dir->u.index.recordsize; - int nr_fix = s1/vol->blocksize+1; + /* Check whether record is out of allocated range. */ + size = allocation->size; + if (walk->newblock * vol->clustersize >= size) { + /* Build index record. */ + int s1 = walk->dir->u.index.recordsize; + int nr_fix = s1/vol->blocksize + 1; int hsize; - char *record=ntfs_malloc(s1); - if( !record ) - return ENOMEM; - ntfs_bzero(record,s1); - /* magic */ - ntfs_memcpy(record,"INDX",4); - /* offset to fixups */ - NTFS_PUTU16(record+4,0x28); - /* number of fixups */ - NTFS_PUTU16(record+6,nr_fix); - /* FIXME: log file number */ + char *record = ntfs_malloc(s1); + if (!record) + return -ENOMEM; + ntfs_bzero(record, s1); + /* Magic */ + ntfs_memcpy(record, "INDX", 4); + /* Offset to fixups */ + NTFS_PUTU16(record + 4, 0x28); + /* Number of fixups. */ + NTFS_PUTU16(record + 6, nr_fix); + /* Log file sequence number - We don't do journalling so we + * just set it to zero which should be the Right Thing. (AIA) */ + NTFS_PUTU64(record + 8, 0); /* VCN of buffer */ - NTFS_PUTU64(record+0x10,walk->newblock); - /* header size. */ - hsize = 0x10+2*nr_fix; - hsize = (hsize+7) & ~7; /* Align. */ - NTFS_PUTU16(record+0x18, hsize); - /* total size of record */ - NTFS_PUTU32(record+0x20,s1-0x18); + NTFS_PUTU64(record + 0x10, walk->newblock); + /* Header size. */ + hsize = 0x10 + 2 * nr_fix; + hsize = (hsize + 7) & ~7; /* Align. */ + NTFS_PUTU16(record + 0x18, hsize); + /* Total size of record. */ + NTFS_PUTU32(record + 0x20, s1 - 0x18); /* Writing the data will extend the attribute. */ - io.param=record; - io.size=s1; - io.do_read=0; - error=ntfs_readwrite_attr(walk->dir, allocation, size, &io); - if(error || io.size!=s1){ + io.param = record; + io.size = s1; + io.do_read = 0; + error = ntfs_readwrite_attr(walk->dir, allocation, size, &io); + if (error || io.size != s1) { ntfs_free(record); - return error?error:EIO; + return error ? error : -EIO; } ntfs_free(record); } - return 0; } /* Write an index block (root or allocation) back to storage. - used is the total number of bytes in buf, including all headers. */ - + * Used is the total number of bytes in buf, including all headers. */ static int ntfs_index_writeback(ntfs_iterate_s *walk, ntfs_u8 *buf, int block, int used) { @@ -212,231 +224,235 @@ ntfs_attribute *a; ntfs_volume *vol = walk->dir->vol; - io.fn_put=0; - io.fn_get=ntfs_get; - io.param=buf; - if(block==-1){ - NTFS_PUTU16(buf+0x14,used-0x10); - /* 0x18 is a copy thereof */ - NTFS_PUTU16(buf+0x18,used-0x10); - io.size=used; - error=ntfs_write_attr(walk->dir,vol->at_index_root, - I30,0,&io); - if(error)return error; - if(io.size!=used)return EIO; - /* shrink if necessary */ + io.fn_put = 0; + io.fn_get = ntfs_get; + io.param = buf; + if (block == -1) { + NTFS_PUTU16(buf + 0x14, used - 0x10); + /* 0x18 is a copy thereof. */ + NTFS_PUTU16(buf + 0x18, used - 0x10); + io.size = used; + error = ntfs_write_attr(walk->dir, vol->at_index_root, I30, 0, + &io); + if (error) + return error; + if (io.size != used) + return -EIO; + /* Shrink if necessary. */ a = ntfs_find_attr(walk->dir, vol->at_index_root, I30); ntfs_resize_attr(walk->dir, a, used); - }else{ - NTFS_PUTU16(buf+0x1C,used-0x18); - ntfs_insert_fixups(buf,vol->blocksize); - io.size=walk->dir->u.index.recordsize; - error=ntfs_write_attr(walk->dir,vol->at_index_allocation,I30, - block*vol->clustersize, - &io); - if(error)return error; - if(io.size!=walk->dir->u.index.recordsize) - return EIO; + } else { + NTFS_PUTU16(buf + 0x1C, used - 0x18); + ntfs_insert_fixups(buf, vol->blocksize); + io.size = walk->dir->u.index.recordsize; + error = ntfs_write_attr(walk->dir, vol->at_index_allocation, + I30, block*vol->clustersize, &io); + if (error) + return error; + if (io.size != walk->dir->u.index.recordsize) + return -EIO; } return 0; } static int ntfs_split_record(ntfs_iterate_s *walk, char *start, int bsize, - int usize) + int usize) { - char *entry,*prev; - ntfs_u8 *newbuf=0,*middle=0; - int error,othersize,mlen; + char *entry, *prev; + ntfs_u8 *newbuf = 0, *middle = 0; + int error, othersize, mlen; ntfs_io io; - ntfs_volume *vol=walk->dir->vol; + ntfs_volume *vol = walk->dir->vol; int oldblock; - error=ntfs_allocate_index_block(walk); - if(error) + error = ntfs_allocate_index_block(walk); + if (error) return error; - /* This should not happen */ - if(walk->block == -1){ + /* This should not happen. */ + if (walk->block == -1) { ntfs_error("Trying to split root"); - return EOPNOTSUPP; + return -EOPNOTSUPP; } - entry = start+NTFS_GETU16(start+0x18)+0x18; - for(prev=entry; entry-start<usize/2; entry += NTFS_GETU16(entry+8)) - prev=entry; - - newbuf=ntfs_malloc(vol->index_recordsize); - if(!newbuf) - return ENOMEM; - io.fn_put=ntfs_put; - io.fn_get=ntfs_get; - io.param=newbuf; - io.size=vol->index_recordsize; - /* read in old header. FIXME: reading everything is overkill */ - error=ntfs_read_attr(walk->dir,vol->at_index_allocation,I30, - walk->newblock*vol->clustersize,&io); - if(error)goto out; - if(io.size!=vol->index_recordsize){ - error=EIO; - goto out; - } - /* FIXME: adjust header */ - /* copy everything from entry to new block */ - othersize=usize-(entry-start); - ntfs_memcpy(newbuf+NTFS_GETU16(newbuf+0x18)+0x18,entry,othersize); + entry = start + NTFS_GETU16(start + 0x18) + 0x18; + for (prev = entry; entry - start < usize / 2; + entry += NTFS_GETU16(entry + 8)) + prev = entry; + newbuf = ntfs_malloc(vol->index_recordsize); + if (!newbuf) + return -ENOMEM; + io.fn_put = ntfs_put; + io.fn_get = ntfs_get; + io.param = newbuf; + io.size = vol->index_recordsize; + /* Read in old header. FIXME: Reading everything is overkill. */ + error = ntfs_read_attr(walk->dir, vol->at_index_allocation, I30, + walk->newblock * vol->clustersize, &io); + if (error) + goto out; + if (io.size != vol->index_recordsize) { + error = -EIO; + goto out; + } + /* FIXME: Adjust header. */ + /* Copy everything from entry to new block. */ + othersize = usize - (entry - start); + ntfs_memcpy(newbuf + NTFS_GETU16(newbuf + 0x18) + 0x18, entry, + othersize); /* Copy flags. */ - NTFS_PUTU32(newbuf+0x24, NTFS_GETU32(start+0x24)); - error=ntfs_index_writeback(walk,newbuf,walk->newblock, - othersize+NTFS_GETU16(newbuf+0x18)+0x18); - if(error)goto out; - - /* move prev to walk */ - mlen=NTFS_GETU16(prev+0x8); + NTFS_PUTU32(newbuf + 0x24, NTFS_GETU32(start + 0x24)); + error = ntfs_index_writeback(walk, newbuf, walk->newblock, + othersize + NTFS_GETU16(newbuf + 0x18) + 0x18); + if (error) + goto out; + /* Move prev to walk. */ + mlen = NTFS_GETU16(prev + 0x8); /* Remember old child node. */ - if(ntfs_entry_has_subnodes(prev)) - oldblock = NTFS_GETU32(prev+mlen-8); + if (ntfs_entry_has_subnodes(prev)) + oldblock = NTFS_GETU32(prev + mlen - 8); else oldblock = -1; - /* allow for pointer to subnode */ - middle=ntfs_malloc(ntfs_entry_has_subnodes(prev)?mlen:mlen+8); - if(!middle){ - error=ENOMEM; + /* Allow for pointer to subnode. */ + middle = ntfs_malloc(ntfs_entry_has_subnodes(prev) ? mlen : mlen + 8); + if (!middle){ + error = -ENOMEM; goto out; } - ntfs_memcpy(middle,prev,mlen); - /* set has_subnodes flag */ - NTFS_PUTU8(middle+0xC, NTFS_GETU8(middle+0xC) | 1); - /* middle entry points to block, parent entry will point to newblock */ - NTFS_PUTU64(middle+mlen-8,walk->block); - if(walk->new_entry) - ntfs_error("entry not reset"); - walk->new_entry=middle; - walk->u.flags|=ITERATE_SPLIT_DONE; + ntfs_memcpy(middle, prev, mlen); + /* Set has_subnodes flag. */ + NTFS_PUTU8(middle + 0xC, NTFS_GETU8(middle + 0xC) | 1); + /* Middle entry points to block, parent entry will point to newblock. */ + NTFS_PUTU64(middle + mlen - 8, walk->block); + if (walk->new_entry) + ntfs_error("Entry not reset"); + walk->new_entry = middle; + walk->u.flags |= ITERATE_SPLIT_DONE; /* Terminate old block. */ - othersize = usize-(prev-start); + othersize = usize - (prev-start); NTFS_PUTU64(prev, 0); - if(oldblock==-1){ - NTFS_PUTU32(prev+8, 0x10); - NTFS_PUTU32(prev+0xC, 2); + if (oldblock == -1) { + NTFS_PUTU32(prev + 8, 0x10); + NTFS_PUTU32(prev + 0xC, 2); othersize += 0x10; - }else{ - NTFS_PUTU32(prev+8, 0x18); - NTFS_PUTU32(prev+0xC, 3); - NTFS_PUTU64(prev+0x10, oldblock); + } else { + NTFS_PUTU32(prev + 8, 0x18); + NTFS_PUTU32(prev + 0xC, 3); + NTFS_PUTU64(prev + 0x10, oldblock); othersize += 0x18; } - /* write back original block */ - error=ntfs_index_writeback(walk,start,walk->block,othersize); + /* Write back original block. */ + error = ntfs_index_writeback(walk, start, walk->block, othersize); out: - if(newbuf)ntfs_free(newbuf); - if(middle)ntfs_free(middle); + if (newbuf) + ntfs_free(newbuf); + if (middle) + ntfs_free(middle); return error; } static int ntfs_dir_insert(ntfs_iterate_s *walk, char *start, char* entry) { - int blocksize,usedsize,error,offset; - int do_split=0; - offset=entry-start; - if(walk->block==-1){ /*index root */ - blocksize=walk->dir->vol->mft_recordsize; - usedsize=NTFS_GETU16(start+0x14)+0x10; - }else{ - blocksize=walk->dir->u.index.recordsize; - usedsize=NTFS_GETU16(start+0x1C)+0x18; - } - if(usedsize+walk->new_entry_size > blocksize){ - char* s1=ntfs_malloc(blocksize+walk->new_entry_size); - if(!s1)return ENOMEM; - ntfs_memcpy(s1,start,usedsize); - do_split=1; - /* adjust entry to s1 */ - entry=s1+(entry-start); - start=s1; - } - ntfs_memmove(entry+walk->new_entry_size,entry,usedsize-offset); - ntfs_memcpy(entry,walk->new_entry,walk->new_entry_size); - usedsize+=walk->new_entry_size; + int blocksize, usedsize, error, offset; + int do_split = 0; + offset = entry - start; + if (walk->block == -1) { /* index root */ + blocksize = walk->dir->vol->mft_recordsize; + usedsize = NTFS_GETU16(start + 0x14) + 0x10; + } else { + blocksize = walk->dir->u.index.recordsize; + usedsize = NTFS_GETU16(start + 0x1C) + 0x18; + } + if (usedsize + walk->new_entry_size > blocksize) { + char* s1 = ntfs_malloc(blocksize + walk->new_entry_size); + if (!s1) + return -ENOMEM; + ntfs_memcpy(s1, start, usedsize); + do_split = 1; + /* Adjust entry to s1. */ + entry = s1 + (entry - start); + start = s1; + } + ntfs_memmove(entry + walk->new_entry_size, entry, usedsize - offset); + ntfs_memcpy(entry, walk->new_entry, walk->new_entry_size); + usedsize += walk->new_entry_size; ntfs_free(walk->new_entry); - walk->new_entry=0; - if(do_split){ - error=ntfs_split_record(walk,start,blocksize,usedsize); + walk->new_entry = 0; + if (do_split) { + error = ntfs_split_record(walk, start, blocksize, usedsize); ntfs_free(start); - }else{ - error=ntfs_index_writeback(walk,start,walk->block,usedsize); - if(error)return error; + } else { + error = ntfs_index_writeback(walk, start, walk->block,usedsize); + if (error) + return error; } return 0; } -/* Try to split INDEX_ROOT attributes. Return E2BIG if nothing changed. */ - -int -ntfs_split_indexroot(ntfs_inode *ino) +/* Try to split INDEX_ROOT attributes. Return -E2BIG if nothing changed. */ +int ntfs_split_indexroot(ntfs_inode *ino) { ntfs_attribute *ra; - ntfs_u8 *root=0, *index=0; + ntfs_u8 *root = 0, *index = 0; ntfs_io io; int error, off, i, bsize, isize; ntfs_iterate_s walk; ra = ntfs_find_attr(ino, ino->vol->at_index_root, I30); - if(!ra) - return E2BIG; + if (!ra) + return -E2BIG; bsize = ino->vol->mft_recordsize; root = ntfs_malloc(bsize); - if(!root) - return E2BIG; + if (!root) + return -E2BIG; io.fn_put = ntfs_put; io.param = root; io.size = bsize; error = ntfs_read_attr(ino, ino->vol->at_index_root, I30, 0, &io); - if(error) + if (error) goto out; off = 0x20; /* Count number of entries. */ - for(i = 0; ntfs_entry_is_used(root+off); i++) - off += NTFS_GETU16(root+off+8); - if(i<=2){ + for (i = 0; ntfs_entry_is_used(root + off); i++) + off += NTFS_GETU16(root + off + 8); + if (i <= 2) { /* We don't split small index roots. */ - error = E2BIG; + error = -E2BIG; goto out; } index = ntfs_malloc(ino->vol->index_recordsize); - if(!index) { - error = ENOMEM; goto out; + if (!index) { + error = -ENOMEM; + goto out; } walk.dir = ino; walk.block = -1; walk.result = walk.new_entry = 0; walk.name = 0; error = ntfs_allocate_index_block(&walk); - if(error) + if (error) goto out; - /* Write old root to new index block. */ io.param = index; io.size = ino->vol->index_recordsize; error = ntfs_read_attr(ino, ino->vol->at_index_allocation, I30, - walk.newblock*ino->vol->clustersize, &io); - if(error) + walk.newblock * ino->vol->clustersize, &io); + if (error) goto out; - isize = NTFS_GETU16(root+0x18) - 0x10; - ntfs_memcpy(index+NTFS_GETU16(index+0x18)+0x18, root+0x20, isize); + isize = NTFS_GETU16(root + 0x18) - 0x10; + ntfs_memcpy(index + NTFS_GETU16(index + 0x18) + 0x18, root+0x20, isize); /* Copy flags. */ - NTFS_PUTU32(index+0x24, NTFS_GETU32(root+0x1C)); - + NTFS_PUTU32(index + 0x24, NTFS_GETU32(root + 0x1C)); error = ntfs_index_writeback(&walk, index, walk.newblock, - isize+NTFS_GETU16(index+0x18)+0x18); + isize + NTFS_GETU16(index + 0x18) + 0x18); if(error) goto out; - /* Mark root as split. */ - NTFS_PUTU32(root+0x1C, 1); + NTFS_PUTU32(root + 0x1C, 1); /* Truncate index root. */ - NTFS_PUTU64(root+0x20, 0); - NTFS_PUTU32(root+0x28, 0x18); - NTFS_PUTU32(root+0x2C, 3); - NTFS_PUTU64(root+0x30, walk.newblock); - error = ntfs_index_writeback(&walk,root,-1,0x38); + NTFS_PUTU64(root + 0x20, 0); + NTFS_PUTU32(root + 0x28, 0x18); + NTFS_PUTU32(root + 0x2C, 3); + NTFS_PUTU64(root + 0x30, walk.newblock); + error = ntfs_index_writeback(&walk, root, -1, 0x38); out: ntfs_free(root); ntfs_free(index); @@ -451,422 +467,428 @@ return 1; } -/* use $UpCase some day */ +/* Use $UpCase some day. */ static inline unsigned short ntfs_my_toupper(ntfs_volume *vol, ntfs_u16 x) { - /* we should read any pending rest of $UpCase here */ - if(x >= vol->upcase_length) + /* We should read any pending rest of $UpCase here. */ + if (x >= vol->upcase_length) return x; return vol->upcase[x]; } -/* everything passed in walk and entry */ +/* Everything passed in walk and entry. */ static int ntfs_my_strcmp(ntfs_iterate_s *walk, const unsigned char *entry) { - int lu=*(entry+0x50); + int lu = *(entry + 0x50); int i; - ntfs_u16* name=(ntfs_u16*)(entry+0x52); - ntfs_volume *vol=walk->dir->vol; - for(i=0;i<lu && i<walk->namelen;i++) - if(ntfs_my_toupper(vol,NTFS_GETU16(name+i))!=ntfs_my_toupper(vol,NTFS_GETU16(walk->name+i))) + ntfs_u16* name = (ntfs_u16*)(entry + 0x52); + ntfs_volume *vol = walk->dir->vol; + for (i = 0; i < lu && i < walk->namelen; i++) + if (ntfs_my_toupper(vol, NTFS_GETU16(name + i)) != + ntfs_my_toupper(vol, NTFS_GETU16(walk->name + i))) break; - if(i==lu && i==walk->namelen)return 0; - if(i==lu)return 1; - if(i==walk->namelen)return -1; - if(ntfs_my_toupper(vol,NTFS_GETU16(name+i))<ntfs_my_toupper(vol,NTFS_GETU16(walk->name+i)))return 1; + if (i == lu && i == walk->namelen) + return 0; + if (i == lu) + return 1; + if (i == walk->namelen) + return -1; + if (ntfs_my_toupper(vol, NTFS_GETU16(name + i)) < + ntfs_my_toupper(vol, NTFS_GETU16(walk->name + i))) + return 1; return -1; } -/* Necessary forward declaration */ +/* Necessary forward declaration. */ static int ntfs_getdir_iterate(ntfs_iterate_s *walk, char *start, char *entry); -/* Parse a block of entries. Load the block, fix it up, and iterate - over the entries. The block is given as virtual cluster number */ +/* Parse a block of entries. Load the block, fix it up, and iterate over the + * entries. The block is given as virtual cluster number. */ static int ntfs_getdir_record(ntfs_iterate_s *walk, int block) { - int length=walk->dir->u.index.recordsize; - char *record=(char*)ntfs_malloc(length); + int length = walk->dir->u.index.recordsize; + char *record = (char*)ntfs_malloc(length); char *offset; int retval,error; int oldblock; ntfs_io io; - if( !record ) - return ENOMEM; - - io.fn_put=ntfs_put; - io.param=record; - io.size=length; - /* Read the block from the index allocation attribute */ - error=ntfs_read_attr(walk->dir,walk->dir->vol->at_index_allocation,I30, - block*walk->dir->vol->clustersize,&io); - if(error || io.size!=length){ + if (!record) + return -ENOMEM; + io.fn_put = ntfs_put; + io.param = record; + io.size = length; + /* Read the block from the index allocation attribute. */ + error = ntfs_read_attr(walk->dir, walk->dir->vol->at_index_allocation, + I30, block * walk->dir->vol->clustersize, &io); + if (error || io.size != length) { ntfs_error("read failed\n"); ntfs_free(record); return 0; } - if(!ntfs_check_index_record(walk->dir,record)){ - ntfs_error("%x is not an index record\n",block); + if (!ntfs_check_index_record(walk->dir, record)) { + ntfs_error("%x is not an index record\n", block); ntfs_free(record); return 0; } - offset=record+NTFS_GETU16(record+0x18)+0x18; - oldblock=walk->block; - walk->block=block; - retval=ntfs_getdir_iterate(walk,record,offset); - walk->block=oldblock; + offset = record + NTFS_GETU16(record + 0x18) + 0x18; + oldblock = walk->block; + walk->block = block; + retval = ntfs_getdir_iterate(walk, record, offset); + walk->block = oldblock; ntfs_free(record); return retval; } -/* go down to the next block of entries. These collate before - the current entry */ +/* Go down to the next block of entries. These collate before the current + * entry. */ static int ntfs_descend(ntfs_iterate_s *walk, ntfs_u8 *start, ntfs_u8 *entry) { - int length=NTFS_GETU16(entry+8); + int length = NTFS_GETU16(entry + 8); int nextblock=NTFS_GETU32(entry+length-8); int error; - if(!ntfs_entry_has_subnodes(entry)) { + if (!ntfs_entry_has_subnodes(entry)) { ntfs_error("illegal ntfs_descend call\n"); return 0; } - error=ntfs_getdir_record(walk,nextblock); - if(!error && walk->type==DIR_INSERT && - (walk->u.flags & ITERATE_SPLIT_DONE)){ + error = ntfs_getdir_record(walk, nextblock); + if (!error && walk->type == DIR_INSERT && + (walk->u.flags & ITERATE_SPLIT_DONE)) { /* Split has occurred. Adjust entry, insert new_entry. */ - NTFS_PUTU32(entry+length-8,walk->newblock); + NTFS_PUTU32(entry + length - 8, walk->newblock); /* Reset flags, as the current block might be split again. */ walk->u.flags &= ~ITERATE_SPLIT_DONE; - error=ntfs_dir_insert(walk,start,entry); + error = ntfs_dir_insert(walk, start, entry); } return error; } -static int -ntfs_getdir_iterate_byposition(ntfs_iterate_s *walk,char* start,char *entry) +static int ntfs_getdir_iterate_byposition(ntfs_iterate_s *walk, char* start, + char *entry) { - int retval=0; - int curpos=0,destpos=0; + int retval = 0; + int curpos = 0, destpos = 0; int length; - if(walk->u.pos!=0){ - if(ntfs_is_top(walk->u.pos))return 0; - destpos=ntfs_pop(&walk->u.pos); - } - while(1){ - if(walk->u.pos==0) - { - if(ntfs_entry_has_subnodes(entry)) - ntfs_descend(walk,start,entry); + if (walk->u.pos != 0) { + if (ntfs_is_top(walk->u.pos)) + return 0; + destpos = ntfs_pop(&walk->u.pos); + } + while (1) { + if (walk->u.pos == 0) { + if (ntfs_entry_has_subnodes(entry)) + ntfs_descend(walk, start, entry); else - walk->u.pos=ntfs_top(); - if(ntfs_is_top(walk->u.pos) && !ntfs_entry_is_used(entry)) - { + walk->u.pos = ntfs_top(); + if (ntfs_is_top(walk->u.pos) && + !ntfs_entry_is_used(entry)) return 1; - } - walk->u.pos=ntfs_push(walk->u.pos,curpos); + walk->u.pos = ntfs_push(walk->u.pos, curpos); return 1; } - if(curpos==destpos) - { - if(!ntfs_is_top(walk->u.pos) && ntfs_entry_has_subnodes(entry)) - { - retval=ntfs_descend(walk,start,entry); - if(retval){ - walk->u.pos=ntfs_push(walk->u.pos,curpos); + if (curpos == destpos) { + if (!ntfs_is_top(walk->u.pos) && + ntfs_entry_has_subnodes(entry)) { + retval = ntfs_descend(walk, start, entry); + if (retval) { + walk->u.pos = ntfs_push(walk->u.pos, + curpos); return retval; - }else{ - if(!ntfs_entry_is_used(entry)) - return 0; - walk->u.pos=0; } + if (!ntfs_entry_is_used(entry)) + return 0; + walk->u.pos = 0; } - if(ntfs_entry_is_used(entry)) - { - retval=ntfs_copyresult(walk->result,entry); - walk->u.pos=0; - }else{ - walk->u.pos=ntfs_top(); + if (ntfs_entry_is_used(entry)) { + retval = ntfs_copyresult(walk->result, entry); + walk->u.pos = 0; + } else { + walk->u.pos = ntfs_top(); return 0; } } curpos++; - if(!ntfs_entry_is_used(entry))break; - length=NTFS_GETU16(entry+8); - if(!length){ + if (!ntfs_entry_is_used(entry)) + break; + length = NTFS_GETU16(entry + 8); + if (!length) { ntfs_error("infinite loop\n"); break; } - entry+=length; + entry += length; } return -1; } -/* Iterate over a list of entries, either from an index block, or from - the index root. - If searching BY_POSITION, pop the top index from the position. If the - position stack is empty then, return the item at the index and set the - position to the next entry. If the position stack is not empty, - recursively proceed for subnodes. If the entry at the position is the - 'end of dir' entry, return 'not found' and the empty stack. - If searching BY_NAME, walk through the items until found or until - one item is collated after the requested item. In the former case, return - the result. In the latter case, recursively proceed to the subnodes. - If 'end of dir' is reached, the name is not in the directory */ +/* Iterate over a list of entries, either from an index block, or from the + * index root. + * If searching BY_POSITION, pop the top index from the position. If the + * position stack is empty then, return the item at the index and set the + * position to the next entry. If the position stack is not empty, + * recursively proceed for subnodes. If the entry at the position is the + * 'end of dir' entry, return 'not found' and the empty stack. + * If searching BY_NAME, walk through the items until found or until + * one item is collated after the requested item. In the former case, return + * the result. In the latter case, recursively proceed to the subnodes. + * If 'end of dir' is reached, the name is not in the directory */ static int ntfs_getdir_iterate(ntfs_iterate_s *walk, char *start, char *entry) { int length; int cmp; - if(walk->type==BY_POSITION) - return ntfs_getdir_iterate_byposition(walk,start,entry); - do{ - /* if the current entry is a real one, compare with the - requested item. If the current entry is the last item, - it is always larger than the requested item */ - cmp = ntfs_entry_is_used(entry) ? ntfs_my_strcmp(walk,entry) : -1; - switch(walk->type){ + if (walk->type == BY_POSITION) + return ntfs_getdir_iterate_byposition(walk, start, entry); + do { + /* If the current entry is a real one, compare with the + * requested item. If the current entry is the last item, it + * is always larger than the requested item. */ + cmp = ntfs_entry_is_used(entry) ? + ntfs_my_strcmp(walk,entry) : -1; + switch (walk->type) { case BY_NAME: - switch(cmp) - { - case -1:return ntfs_entry_has_subnodes(entry)? - ntfs_descend(walk,start,entry):0; - case 0:return ntfs_copyresult(walk->result,entry); - case 1:break; + switch (cmp) { + case -1: + return ntfs_entry_has_subnodes(entry) ? + ntfs_descend(walk,start,entry) : + 0; + case 0: + return ntfs_copyresult(walk->result, + entry); + case 1: + break; } break; case DIR_INSERT: - switch(cmp){ - case -1:return ntfs_entry_has_subnodes(entry)? - ntfs_descend(walk,start,entry): - ntfs_dir_insert(walk,start,entry); - case 0:return EEXIST; - case 1:break; + switch (cmp) { + case -1: + return ntfs_entry_has_subnodes(entry) ? + ntfs_descend(walk, start, entry) : + ntfs_dir_insert(walk, start, entry); + case 0: + return -EEXIST; + case 1: + break; } break; default: - ntfs_error("TODO\n"); + ntfs_error("TODO\n"); /* FIXME: ? */ } - if(!ntfs_entry_is_used(entry))break; - length=NTFS_GETU16(entry+8); - if(!length){ + if (!ntfs_entry_is_used(entry)) + break; + length = NTFS_GETU16(entry + 8); + if (!length) { ntfs_error("infinite loop\n"); break; } - entry+=length; - }while(1); + entry += length; + } while (1); return 0; } -/* Tree walking is done using position numbers. The following numbers have - a special meaning: - 0 start (.) - -1 no more entries - -2 .. - All other numbers encode sequences of indices. The sequence a,b,c is - encoded as <stop><c><b><a>, where <foo> is the encoding of foo. The - first few integers are encoded as follows: - 0: 0000 1: 0010 2: 0100 3: 0110 - 4: 1000 5: 1010 6: 1100 stop: 1110 - 7: 000001 8: 000101 9: 001001 10: 001101 - The least significant bits give the width of this encoding, the - other bits encode the value, starting from the first value of the - interval. - tag width first value last value - 0 3 0 6 - 01 4 7 22 - 011 5 23 54 - 0111 6 55 119 - More values are hopefully not needed, as the file position has currently - 64 bits in total. -*/ +/* Tree walking is done using position numbers. The following numbers have a + * special meaning: + * 0 start (.) + * -1 no more entries + * -2 .. + * All other numbers encode sequences of indices. The sequence a, b, c is + * encoded as <stop><c><b><a>, where <foo> is the encoding of foo. The + * first few integers are encoded as follows: + * 0: 0000 1: 0010 2: 0100 3: 0110 + * 4: 1000 5: 1010 6: 1100 stop: 1110 + * 7: 000001 8: 000101 9: 001001 10: 001101 + * The least significant bits give the width of this encoding, the other bits + * encode the value, starting from the first value of the interval. + * tag width first value last value + * 0 3 0 6 + * 01 4 7 22 + * 011 5 23 54 + * 0111 6 55 119 + * More values are hopefully not needed, as the file position has currently + * 64 bits in total. */ -/* Find an entry in the directory. Return 0 if not found, otherwise copy - the entry to the result buffer. */ +/* Find an entry in the directory. Return 0 if not found, otherwise copy the + * entry to the result buffer. */ int ntfs_getdir(ntfs_iterate_s* walk) { - int length=walk->dir->vol->mft_recordsize; - int retval,error; - /* start at the index root.*/ - char *root=ntfs_malloc(length); + int length = walk->dir->vol->mft_recordsize; + int retval, error; + /* Start at the index root. */ + char *root = ntfs_malloc(length); ntfs_io io; - if( !root ) - return ENOMEM; - - io.fn_put=ntfs_put; - io.param=root; - io.size=length; - error=ntfs_read_attr(walk->dir,walk->dir->vol->at_index_root, - I30,0,&io); - if(error) - { + if (!root) + return -ENOMEM; + io.fn_put = ntfs_put; + io.param = root; + io.size = length; + error = ntfs_read_attr(walk->dir, walk->dir->vol->at_index_root, I30, + 0, &io); + if (error) { ntfs_error("Not a directory\n"); return 0; } - walk->block=-1; - /* FIXME: move these to walk */ - walk->dir->u.index.recordsize = NTFS_GETU32(root+0x8); - walk->dir->u.index.clusters_per_record = NTFS_GETU32(root+0xC); - /* FIXME: consistency check */ - /* skip header */ - retval = ntfs_getdir_iterate(walk,root,root+0x20); + walk->block = -1; + /* FIXME: Move these to walk. */ + walk->dir->u.index.recordsize = NTFS_GETU32(root + 0x8); + walk->dir->u.index.clusters_per_record = NTFS_GETU32(root + 0xC); + /* FIXME: Consistency check. */ + /* Skip header. */ + retval = ntfs_getdir_iterate(walk, root, root + 0x20); ntfs_free(root); return retval; } /* Find an entry in the directory by its position stack. Iteration starts - if the stack is 0, in which case the position is set to the first item - in the directory. If the position is nonzero, return the item at the - position and change the position to the next item. The position is -1 - if there are no more items */ + * if the stack is 0, in which case the position is set to the first item + * in the directory. If the position is nonzero, return the item at the + * position and change the position to the next item. The position is -1 + * if there are no more items. */ int ntfs_getdir_byposition(ntfs_iterate_s *walk) { - walk->type=BY_POSITION; + walk->type = BY_POSITION; return ntfs_getdir(walk); } -/* Find an entry in the directory by its name. Return 0 if not found */ +/* Find an entry in the directory by its name. Return 0 if not found. */ int ntfs_getdir_byname(ntfs_iterate_s *walk) { - walk->type=BY_NAME; + walk->type = BY_NAME; return ntfs_getdir(walk); } -int ntfs_getdir_unsorted(ntfs_inode *ino,ntfs_u32 *p_high,ntfs_u32* p_low, - int(*cb)(ntfs_u8*,void*),void *param) +int ntfs_getdir_unsorted(ntfs_inode *ino, ntfs_u32 *p_high, ntfs_u32* p_low, + int (*cb)(ntfs_u8*, void*), void *param) { - char *buf=0,*entry=0; + char *buf = 0, *entry = 0; ntfs_io io; int length; int block; int start; ntfs_attribute *attr; - ntfs_volume *vol=ino->vol; - int byte,bit; - int error=0; + ntfs_volume *vol = ino->vol; + int byte, bit; + int error = 0; - if(!ino){ + if (!ino) { ntfs_error("No inode passed to getdir_unsorted\n"); - return EINVAL; + return -EINVAL; } - if(!vol){ - ntfs_error("Inode %d has no volume\n",ino->i_number); - return EINVAL; - } - ntfs_debug(DEBUG_DIR3,"unsorted 1\n"); - /* are we still in the index root */ - if(*p_high==0){ - buf=ntfs_malloc(length=vol->mft_recordsize); - if( !buf ) - return ENOMEM; - io.fn_put=ntfs_put; - io.param=buf; - io.size=length; - error=ntfs_read_attr(ino,vol->at_index_root,I30,0,&io); - if(error){ + if (!vol) { + ntfs_error("Inode %d has no volume\n", ino->i_number); + return -EINVAL; + } + ntfs_debug(DEBUG_DIR3, "unsorted 1\n"); + /* Are we still in the index root? */ + if (*p_high == 0) { + buf = ntfs_malloc(length = vol->mft_recordsize); + if (!buf) + return -ENOMEM; + io.fn_put = ntfs_put; + io.param = buf; + io.size = length; + error = ntfs_read_attr(ino, vol->at_index_root, I30, 0, &io); + if (error) { ntfs_free(buf); return error; } - ino->u.index.recordsize = NTFS_GETU32(buf+0x8); - ino->u.index.clusters_per_record = NTFS_GETU32(buf+0xC); - entry=buf+0x20; - ntfs_debug(DEBUG_DIR3,"unsorted 2\n"); - }else{ /* we are in an index record */ - length=ino->u.index.recordsize; - buf=ntfs_malloc(length); - if( !buf ) - return ENOMEM; - io.fn_put=ntfs_put; - io.param=buf; - io.size=length; - /* 0 is index root, index allocation starts with 4 */ + ino->u.index.recordsize = NTFS_GETU32(buf + 0x8); + ino->u.index.clusters_per_record = NTFS_GETU32(buf + 0xC); + entry = buf + 0x20; + ntfs_debug(DEBUG_DIR3, "unsorted 2\n"); + } else { /* we are in an index record */ + length = ino->u.index.recordsize; + buf = ntfs_malloc(length); + if (!buf) + return -ENOMEM; + io.fn_put = ntfs_put; + io.param = buf; + io.size = length; + /* 0 is index root, index allocation starts with 4. */ block = *p_high - ino->u.index.clusters_per_record; - error=ntfs_read_attr(ino,vol->at_index_allocation,I30, - block*vol->clustersize,&io); - if(!error && io.size!=length)error=EIO; - if(error){ + error = ntfs_read_attr(ino, vol->at_index_allocation, I30, + block*vol->clustersize, &io); + if (!error && io.size != length) + error = -EIO; + if (error) { ntfs_error("read failed\n"); ntfs_free(buf); return error; } - if(!ntfs_check_index_record(ino,buf)){ - ntfs_error("%x is not an index record\n",block); + if (!ntfs_check_index_record(ino, buf)) { + ntfs_error("%x is not an index record\n", block); ntfs_free(buf); - return ENOTDIR; + return -ENOTDIR; } - entry=buf+NTFS_GETU16(buf+0x18)+0x18; - ntfs_debug(DEBUG_DIR3,"unsorted 3\n"); + entry = buf + NTFS_GETU16(buf + 0x18) + 0x18; + ntfs_debug(DEBUG_DIR3, "unsorted 3\n"); } - - /* process the entries */ - start=*p_low; - while(ntfs_entry_is_used(entry)){ - ntfs_debug(DEBUG_DIR3,"unsorted 4\n"); - if(start) - start--; /* skip entries that were already processed */ - else{ - ntfs_debug(DEBUG_DIR3,"unsorted 5\n"); - if((error=cb(entry,param))) - /* the entry could not be processed */ + /* Process the entries. */ + start = *p_low; + while (ntfs_entry_is_used(entry)) { + ntfs_debug(DEBUG_DIR3, "unsorted 4\n"); + if (start) + start--; /* Skip entries that were already processed. */ + else { + ntfs_debug(DEBUG_DIR3, "unsorted 5\n"); + if ((error = cb(entry, param))) + /* The entry could not be processed. */ break; (*p_low)++; } - entry+=NTFS_GETU16(entry+8); + entry += NTFS_GETU16(entry + 8); } - - ntfs_debug(DEBUG_DIR3,"unsorted 6\n"); - /* caller did not process all entries */ - if(error){ + ntfs_debug(DEBUG_DIR3, "unsorted 6\n"); + /* Caller did not process all entries. */ + if (error) { ntfs_free(buf); - ntfs_debug(DEBUG_DIR3,"unsorted 7\n"); + ntfs_debug(DEBUG_DIR3, "unsorted 7\n"); return error; } - - /* we have to locate the next record */ + /* We have to locate the next record. */ ntfs_free(buf); - buf=0; - *p_low=0; - attr=ntfs_find_attr(ino,vol->at_bitmap,I30); - if(!attr){ - /* directory does not have index allocation */ - *p_high=0xFFFFFFFF; - *p_low=0; - ntfs_debug(DEBUG_DIR3,"unsorted 8\n"); + buf = 0; + *p_low = 0; + attr = ntfs_find_attr(ino, vol->at_bitmap, I30); + if (!attr) { + /* Directory does not have index allocation. */ + *p_high = 0xFFFFFFFF; + *p_low = 0; + ntfs_debug(DEBUG_DIR3, "unsorted 8\n"); return 0; } - buf=ntfs_malloc(length=attr->size); - if( !buf ) - return ENOMEM; - - io.param=buf; - io.size=length; - error=ntfs_read_attr(ino,vol->at_bitmap,I30,0,&io); - if(!error && io.size!=length)error=EIO; - if(error){ + buf = ntfs_malloc(length = attr->size); + if (!buf) + return -ENOMEM; + io.param = buf; + io.size = length; + error = ntfs_read_attr(ino, vol->at_bitmap, I30, 0, &io); + if (!error && io.size != length) + error = -EIO; + if (error) { ntfs_free(buf); - ntfs_debug(DEBUG_DIR3,"unsorted 9\n"); - return EIO; + ntfs_debug(DEBUG_DIR3, "unsorted 9\n"); + return -EIO; } - attr=ntfs_find_attr(ino,vol->at_index_allocation,I30); - while(1){ - if(*p_high*vol->clustersize > attr->size){ - /* no more index records */ - *p_high=0xFFFFFFFF; + attr = ntfs_find_attr(ino, vol->at_index_allocation, I30); + while (1) { + if (*p_high * vol->clustersize > attr->size) { + /* No more index records. */ + *p_high = 0xFFFFFFFF; ntfs_free(buf); - ntfs_debug(DEBUG_DIR3,"unsorted 10\n"); + ntfs_debug(DEBUG_DIR3, "unsorted 10\n"); return 0; } - *p_high+=ino->u.index.clusters_per_record; - byte=*p_high/ino->u.index.clusters_per_record-1; + *p_high += ino->u.index.clusters_per_record; + byte = *p_high / ino->u.index.clusters_per_record - 1; bit = 1 << (byte & 7); byte = byte >> 3; - /* this record is allocated */ - if(buf[byte] & bit) + /* This record is allocated. */ + if (buf[byte] & bit) break; } - ntfs_debug(DEBUG_DIR3,"unsorted 11\n"); + ntfs_debug(DEBUG_DIR3, "unsorted 11\n"); ntfs_free(buf); return 0; } @@ -874,116 +896,120 @@ int ntfs_dir_add(ntfs_inode *dir, ntfs_inode *new, ntfs_attribute *name) { ntfs_iterate_s walk; - int nsize,esize; - ntfs_u8* entry,*ndata; + int nsize, esize; + ntfs_u8* entry, *ndata; int error; - walk.type=DIR_INSERT; - walk.dir=dir; - walk.u.flags=0; + walk.type = DIR_INSERT; + walk.dir = dir; + walk.u.flags = 0; nsize = name->size; ndata = name->d.data; - walk.name=(ntfs_u16*)(ndata+0x42); - walk.namelen=NTFS_GETU8(ndata+0x40); - walk.new_entry_size = esize = ((nsize+0x18)/8)*8; - walk.new_entry=entry=ntfs_malloc(esize); - if(!entry)return ENOMEM; - ntfs_bzero(entry,esize); - NTFS_PUTINUM(entry,new); - NTFS_PUTU16(entry+0x8,esize); /* size of entry */ - NTFS_PUTU16(entry+0xA,nsize); /* size of original name attribute */ - NTFS_PUTU32(entry+0xC,0); /* FIXME: D-F? */ - ntfs_memcpy(entry+0x10,ndata,nsize); - error=ntfs_getdir(&walk); - if(walk.new_entry) + walk.name = (ntfs_u16*)(ndata + 0x42); + walk.namelen = NTFS_GETU8(ndata + 0x40); + walk.new_entry_size = esize = ((nsize + 0x18) / 8) * 8; + walk.new_entry = entry = ntfs_malloc(esize); + if (!entry) + return -ENOMEM; + ntfs_bzero(entry, esize); + NTFS_PUTINUM(entry, new); + NTFS_PUTU16(entry + 0x8, esize); /* Size of entry. */ + NTFS_PUTU16(entry + 0xA, nsize); /* Size of original name attribute. */ + NTFS_PUTU32(entry + 0xC, 0); /* FIXME: D-F? */ + ntfs_memcpy(entry + 0x10, ndata, nsize); + error = ntfs_getdir(&walk); + if (walk.new_entry) ntfs_free(walk.new_entry); return error; } #if 0 -int ntfs_dir_add1(ntfs_inode *dir,const char* name,int namelen,ntfs_inode *ino) +int ntfs_dir_add1(ntfs_inode *dir, const char* name, int namelen, + ntfs_inode *ino) { ntfs_iterate_s walk; int error; int nsize; char *entry; ntfs_attribute *name_attr; - error=ntfs_decodeuni(dir->vol,name,namelen,&walk.name,&walk.namelen); - if(error) + error = ntfs_decodeuni(dir->vol, name, namelen, &walk.name, + &walk.namelen); + if (error) return error; - /* FIXME: set flags */ - walk.type=DIR_INSERT; - walk.dir=dir; - /*walk.new=ino;*/ - /* prepare new entry */ - /* round up to a multiple of 8 */ - walk.new_entry_size = nsize = ((0x52+2*walk.namelen+7)/8)*8; - walk.new_entry=entry=ntfs_malloc(nsize); - if(!entry) - return ENOMEM; - ntfs_bzero(entry,nsize); - NTFS_PUTINUM(entry,ino); - NTFS_PUTU16(entry+8,nsize); - NTFS_PUTU16(entry+0xA,0x42+2*namelen); /*FIXME: size of name attr*/ - NTFS_PUTU32(entry+0xC,0); /*FIXME: D-F? */ - name_attr=ntfs_find_attr(ino,vol->at_file_name,0); /* FIXME:multiple names */ - if(!name_attr || !name_attr->resident) - return EIDRM; - /* directory, file stamps, sizes, filename */ - ntfs_memcpy(entry+0x10,name_attr->d.data,0x42+2*namelen); - error=ntfs_getdir(&walk); + /* FIXME: Set flags. */ + walk.type = DIR_INSERT; + walk.dir = dir; + /* walk.new = ino; */ + /* Prepare new entry. */ + /* Round up to a multiple of 8. */ + walk.new_entry_size = nsize = ((0x52 + 2 * walk.namelen + 7) / 8) * 8; + walk.new_entry = entry = ntfs_malloc(nsize); + if (!entry) + return -ENOMEM; + ntfs_bzero(entry, nsize); + NTFS_PUTINUM(entry, ino); + NTFS_PUTU16(entry + 8, nsize); + NTFS_PUTU16(entry + 0xA, 0x42 + 2 * namelen); /* FIXME: Size of name + * attribute. */ + NTFS_PUTU32(entry + 0xC, 0); /* FIXME: D-F? */ + name_attr = ntfs_find_attr(ino, vol->at_file_name, 0); + /* FIXME: multiple names */ + if (!name_attr || !name_attr->resident) + return -EIDRM; + /* Directory, file stamps, sizes, filename. */ + ntfs_memcpy(entry + 0x10, name_attr->d.data, 0x42 + 2 * namelen); + error = ntfs_getdir(&walk); ntfs_free(walk.name); return error; } #endif /* Fills out and creates an INDEX_ROOT attribute. */ - -int -ntfs_add_index_root (ntfs_inode *ino, int type) +int ntfs_add_index_root(ntfs_inode *ino, int type) { ntfs_attribute *da; - ntfs_u8 data[0x30]; /* 0x20 header, 0x10 last entry */ + ntfs_u8 data[0x30]; /* 0x20 header, 0x10 last entry. */ char name[10]; NTFS_PUTU32(data, type); - /* ??? */ - NTFS_PUTU32(data+4, 1); - NTFS_PUTU32(data+8, ino->vol->index_recordsize); - NTFS_PUTU32(data+0xC, ino->vol->index_clusters_per_record); - /* ??? */ - NTFS_PUTU32(data+0x10, 0x10); + /* FIXME: ??? */ + NTFS_PUTU32(data + 4, 1); + NTFS_PUTU32(data + 8, ino->vol->index_recordsize); + NTFS_PUTU32(data + 0xC, ino->vol->index_clusters_per_record); + /* FXIME: ??? */ + NTFS_PUTU32(data + 0x10, 0x10); /* Size of entries, including header. */ - NTFS_PUTU32(data+0x14, 0x20); - NTFS_PUTU32(data+0x18, 0x20); + NTFS_PUTU32(data + 0x14, 0x20); + NTFS_PUTU32(data + 0x18, 0x20); /* No index allocation, yet. */ - NTFS_PUTU32(data+0x1C, 0); - /* add last entry. */ - /* indexed MFT record. */ - NTFS_PUTU64(data+0x20, 0); - /* size of entry */ - NTFS_PUTU32(data+0x28, 0x10); - /* flags: last entry, no child nodes. */ - NTFS_PUTU32(data+0x2C, 2); - /* compute name */ + NTFS_PUTU32(data + 0x1C, 0); + /* Add last entry. */ + /* Indexed MFT record. */ + NTFS_PUTU64(data + 0x20, 0); + /* Size of entry. */ + NTFS_PUTU32(data + 0x28, 0x10); + /* Flags: Last entry, no child nodes. */ + NTFS_PUTU32(data + 0x2C, 2); + /* Compute name. */ ntfs_indexname(name, type); return ntfs_create_attr(ino, ino->vol->at_index_root, name, data, sizeof(data), &da); } -int -ntfs_mkdir(ntfs_inode* dir,const char* name,int namelen, ntfs_inode *result) +int ntfs_mkdir(ntfs_inode* dir, const char* name, int namelen, + ntfs_inode *result) { int error; + error = ntfs_alloc_inode(dir, result, name, namelen, NTFS_AFLAG_DIR); - if(error) + if (error) goto out; error = ntfs_add_index_root(result, 0x30); if (error) goto out; - /* Set directory bit */ + /* Set directory bit. */ result->attr[0x16] |= 2; - error = ntfs_update_inode (dir); + error = ntfs_update_inode(dir); if (error) goto out; error = ntfs_update_inode (result); @@ -993,8 +1019,3 @@ return error; } -/* - * Local variables: - * c-file-style: "linux" - * End: - */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ntfs/dir.h linux.ac/fs/ntfs/dir.h --- linux.vanilla/fs/ntfs/dir.h Mon Apr 12 18:05:58 1999 +++ linux.ac/fs/ntfs/dir.h Tue Apr 3 17:55:13 2001 @@ -1,6 +1,4 @@ -/* - * dir.h - * Header file for dir.c +/* dir.h - Header file for dir.c * * Copyright (C) 1997 Régis Duchesne */ @@ -32,11 +30,19 @@ } ntfs_iterate_s; int ntfs_getdir_unsorted(ntfs_inode *ino, ntfs_u32 *p_high, ntfs_u32* p_low, - int(*cb)(ntfs_u8*,void*), void *param); + int (*cb)(ntfs_u8*, void*), void *param); + int ntfs_getdir_byname(ntfs_iterate_s *walk); + int ntfs_dir_add(ntfs_inode *dir, ntfs_inode *new, ntfs_attribute *name); + int ntfs_check_index_record(ntfs_inode *ino, char *record); + int ntfs_getdir_byposition(ntfs_iterate_s *walk); + int ntfs_mkdir(ntfs_inode* dir,const char* name,int namelen, ntfs_inode *ino); + int ntfs_split_indexroot(ntfs_inode *ino); -int ntfs_add_index_root( ntfs_inode *ino, int type ); + +int ntfs_add_index_root(ntfs_inode *ino, int type); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ntfs/fs.c linux.ac/fs/ntfs/fs.c --- linux.vanilla/fs/ntfs/fs.c Fri Dec 29 22:07:57 2000 +++ linux.ac/fs/ntfs/fs.c Tue Apr 3 17:55:13 2001 @@ -1,19 +1,12 @@ -/* - * fs.c - * NTFS driver for Linux 2.3.x +/* fs.c - NTFS driver for Linux 2.4.x * * Copyright (C) 1995-1997, 1999 Martin von Löwis * Copyright (C) 1996 Richard Russon * Copyright (C) 1996-1997 Régis Duchesne - * Copyright (C) 2000, Anton Altaparmakov + * Copyright (C) 2000-2001, Anton Altaparmakov (AIA) */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#ifdef NTFS_IN_LINUX_KERNEL #include <linux/config.h> -#endif #include "ntfstypes.h" #include "struct.h" @@ -30,66 +23,67 @@ #include <linux/locks.h> #include <linux/init.h> #include <linux/smp_lock.h> +#include <asm/page.h> -/* Forward declarations */ +/* Forward declarations. */ static struct inode_operations ntfs_dir_inode_operations; static struct file_operations ntfs_dir_operations; #define ITEM_SIZE 2040 -/* io functions to user space */ -static void ntfs_putuser(ntfs_io* dest,void *src,ntfs_size_t len) +/* Io functions to user space. */ +static void ntfs_putuser(ntfs_io* dest, void *src, ntfs_size_t len) { - copy_to_user(dest->param,src,len); - dest->param+=len; + copy_to_user(dest->param, src, len); + dest->param += len; } #ifdef CONFIG_NTFS_RW -struct ntfs_getuser_update_vm_s{ +struct ntfs_getuser_update_vm_s { const char *user; struct inode *ino; loff_t off; }; -static void ntfs_getuser_update_vm (void *dest, ntfs_io *src, ntfs_size_t len) +static void ntfs_getuser_update_vm(void *dest, ntfs_io *src, ntfs_size_t len) { struct ntfs_getuser_update_vm_s *p = src->param; - copy_from_user (dest, p->user, len); + + copy_from_user(dest, p->user, len); p->user += len; p->off += len; } #endif -static ssize_t -ntfs_read(struct file * filp, char *buf, size_t count, loff_t *off) +static ssize_t ntfs_read(struct file *filp, char *buf, size_t count,loff_t *off) { int error; ntfs_io io; - ntfs_inode *ino=NTFS_LINO2NINO(filp->f_dentry->d_inode); + ntfs_inode *ino = NTFS_LINO2NINO(filp->f_dentry->d_inode); - /* inode is not properly initialized */ - if(!ino)return -EINVAL; + /* Inode is not properly initialized. */ + if (!ino) + return -EINVAL; ntfs_debug(DEBUG_OTHER, "ntfs_read %x,%x,%x ->", - (unsigned)ino->i_number,(unsigned)*off,(unsigned)count); - /* inode has no unnamed data attribute */ - if(!ntfs_find_attr(ino,ino->vol->at_data,NULL)) + (unsigned)ino->i_number, (unsigned)*off, (unsigned)count); + /* Inode has no unnamed data attribute. */ + if(!ntfs_find_attr(ino, ino->vol->at_data, NULL)) return -EINVAL; - - /* read the data */ - io.fn_put=ntfs_putuser; - io.fn_get=0; - io.param=buf; - io.size=count; - error=ntfs_read_attr(ino,ino->vol->at_data,NULL,*off,&io); - if(error && !io.size)return -error; - - *off+=io.size; + /* Read the data. */ + io.fn_put = ntfs_putuser; + io.fn_get = 0; + io.param = buf; + io.size = count; + error = ntfs_read_attr(ino, ino->vol->at_data, NULL, *off, &io); + if (error && !io.size) + return error; + *off += io.size; return io.size; } #ifdef CONFIG_NTFS_RW -static ssize_t -ntfs_write(struct file *filp,const char* buf,size_t count,loff_t *pos) +static ssize_t ntfs_write(struct file *filp, const char* buf, size_t count, + loff_t *pos) { int ret; ntfs_io io; @@ -99,14 +93,13 @@ if (!ino) return -EINVAL; - ntfs_debug (DEBUG_LINUX, "ntfs_write %x,%x,%x ->\n", - (unsigned)ino->i_number, (unsigned)*pos, (unsigned)count); - /* Allows to lock fs ro at any time */ + ntfs_debug(DEBUG_LINUX, "ntfs_write %x, %x, %x ->\n", + (unsigned)ino->i_number, (unsigned)*pos, (unsigned)count); + /* Allows to lock fs ro at any time. */ if (inode->i_sb->s_flags & MS_RDONLY) return -ENOSPC; - if (!ntfs_find_attr(ino,ino->vol->at_data,NULL)) + if (!ntfs_find_attr(ino, ino->vol->at_data, NULL)) return -EINVAL; - /* Evaluating O_APPEND is the file system's job... */ if (filp->f_flags & O_APPEND) *pos = inode->i_size; @@ -117,15 +110,14 @@ io.fn_get = ntfs_getuser_update_vm; io.param = ¶m; io.size = count; - ret = ntfs_write_attr (ino, ino->vol->at_data, NULL, *pos, &io); - ntfs_debug (DEBUG_LINUX, "write -> %x\n", ret); - if(ret<0) + ret = ntfs_write_attr(ino, ino->vol->at_data, NULL, *pos, &io); + ntfs_debug(DEBUG_LINUX, "write -> %x\n", ret); + if (ret < 0) return -EINVAL; - *pos += io.size; if (*pos > inode->i_size) inode->i_size = *pos; - mark_inode_dirty (filp->f_dentry->d_inode); + mark_inode_dirty(filp->f_dentry->d_inode); return io.size; } #endif @@ -140,269 +132,273 @@ int namelen; }; -static int ntfs_printcb(ntfs_u8 *entry,void *param) +static int ntfs_printcb(ntfs_u8 *entry, void *param) { - struct ntfs_filldir* nf=param; - int flags=NTFS_GETU8(entry+0x51); - int show_hidden=0; - int length=NTFS_GETU8(entry+0x50); - int inum=NTFS_GETU32(entry); + struct ntfs_filldir *nf = param; + int flags = NTFS_GETU8(entry + 0x51); + int show_hidden = 0; + int length = NTFS_GETU8(entry + 0x50); + int inum = NTFS_GETU32(entry); int error; #ifdef NTFS_NGT_NT_DOES_LOWER - int i,to_lower=0; + int i, to_lower = 0; #endif - switch(nf->type){ + switch (nf->type) { case ngt_dos: - /* Don't display long names */ - if((flags & 2)==0) + /* Don't display long names. */ + if ((flags & 2) == 0) return 0; break; case ngt_nt: - /* Don't display short-only names */ - switch(flags&3){ - case 2: return 0; + /* Don't display short-only names. */ + switch (flags & 3) { + case 2: + return 0; #ifdef NTFS_NGT_NT_DOES_LOWER - case 3: to_lower=1; + case 3: + to_lower = 1; #endif } break; case ngt_posix: break; case ngt_full: - show_hidden=1; + show_hidden = 1; break; } - if(!show_hidden && ((NTFS_GETU8(entry+0x48) & 2)==2)){ - ntfs_debug(DEBUG_OTHER,"Skipping hidden file\n"); + if (!show_hidden && ((NTFS_GETU8(entry + 0x48) & 2) == 2)) { + ntfs_debug(DEBUG_OTHER, "Skipping hidden file\n"); return 0; } - nf->name=0; - if(ntfs_encodeuni(NTFS_INO2VOL(nf->dir),(ntfs_u16*)(entry+0x52), - length,&nf->name,&nf->namelen)){ - ntfs_debug(DEBUG_OTHER,"Skipping unrepresentable file\n"); - if(nf->name)ntfs_free(nf->name); + nf->name = 0; + if (ntfs_encodeuni(NTFS_INO2VOL(nf->dir), (ntfs_u16*)(entry + 0x52), + length, &nf->name, &nf->namelen)){ + ntfs_debug(DEBUG_OTHER, "Skipping unrepresentable file\n"); + if (nf->name) + ntfs_free(nf->name); return 0; } - /* Do not return ".", as this is faked */ - if(length==1 && *nf->name=='.') + /* Do not return ".", as this is faked. */ + if (length == 1 && *nf->name == '.') return 0; #ifdef NTFS_NGT_NT_DOES_LOWER - if(to_lower) - for(i=0;i<nf->namelen;i++) - /* This supports ASCII only. Since only DOS-only - names get converted, and since those are restricted - to ASCII, this should be correct */ - if(nf->name[i]>='A' && nf->name[i]<='Z') - nf->name[i]+='a'-'A'; -#endif - nf->name[nf->namelen]=0; - ntfs_debug(DEBUG_OTHER, "readdir got %s,len %d\n",nf->name,nf->namelen); - /* filldir expects an off_t rather than an loff_t. - Hope we don't have more than 65535 index records */ - error=nf->filldir(nf->dirent,nf->name,nf->namelen, - (nf->ph<<16)|nf->pl,inum,DT_UNKNOWN); + if (to_lower) + for(i = 0; i < nf->namelen; i++) + /* This supports ASCII only. Since only DOS-only names + * get converted, and since those are restricted to + * ASCII, this should be correct. */ + if (nf->name[i] >= 'A' && nf->name[i] <= 'Z') + nf->name[i] += 'a' - 'A'; +#endif + nf->name[nf->namelen] = 0; + ntfs_debug(DEBUG_OTHER, "readdir got %s, len %d\n", nf->name, + nf->namelen); + /* filldir expects an off_t rather than an loff_t. Hope we don't have + * more than 65535 index records. */ + error = nf->filldir(nf->dirent, nf->name, nf->namelen, + (nf->ph << 16) | nf->pl, inum, DT_UNKNOWN); ntfs_free(nf->name); - /* Linux filldir errors are negative, other errors positive */ return error; } -/* readdir returns '..', then '.', then the directory entries in sequence - As the root directory contains a entry for itself, '.' is not emulated - for the root directory */ +/* readdir returns '..', then '.', then the directory entries in sequence. + * As the root directory contains a entry for itself, '.' is not emulated for + * the root directory. */ static int ntfs_readdir(struct file* filp, void *dirent, filldir_t filldir) { struct ntfs_filldir cb; int error; - struct inode *dir=filp->f_dentry->d_inode; + struct inode *dir = filp->f_dentry->d_inode; ntfs_debug(DEBUG_OTHER, "ntfs_readdir ino %x mode %x\n", - (unsigned)dir->i_ino,(unsigned int)dir->i_mode); + (unsigned)dir->i_ino, (unsigned int)dir->i_mode); ntfs_debug(DEBUG_OTHER, "readdir: Looking for file %x dircount %d\n", - (unsigned)filp->f_pos,atomic_read(&dir->i_count)); - cb.pl=filp->f_pos & 0xFFFF; - cb.ph=filp->f_pos >> 16; - /* end of directory */ - if(cb.ph==0xFFFF){ - /* FIXME: Maybe we can return those with the previous call */ - switch(cb.pl){ - case 0: filldir(dirent,".",1,filp->f_pos,dir->i_ino,DT_DIR); - filp->f_pos=0xFFFF0001; + (unsigned)filp->f_pos, atomic_read(&dir->i_count)); + cb.pl = filp->f_pos & 0xFFFF; + cb.ph = filp->f_pos >> 16; + /* End of directory. */ + if (cb.ph == 0xFFFF) { + /* FIXME: Maybe we can return those with the previous call. */ + switch (cb.pl) { + case 0: + filldir(dirent, ".", 1, filp->f_pos, dir->i_ino,DT_DIR); + filp->f_pos = 0xFFFF0001; return 0; - /* FIXME: parent directory */ - case 1: filldir(dirent,"..",2,filp->f_pos,0,DT_DIR); - filp->f_pos=0xFFFF0002; + /* FIXME: Parent directory. */ + case 1: + filldir(dirent, "..", 2, filp->f_pos, 0, DT_DIR); + filp->f_pos = 0xFFFF0002; return 0; } ntfs_debug(DEBUG_OTHER, "readdir: EOD\n"); return 0; } - cb.dir=dir; - cb.filldir=filldir; - cb.dirent=dirent; - cb.type=NTFS_INO2VOL(dir)->ngt; - do{ + cb.dir = dir; + cb.filldir = filldir; + cb.dirent = dirent; + cb.type = NTFS_INO2VOL(dir)->ngt; + do { ntfs_debug(DEBUG_OTHER,"looking for next file\n"); - error=ntfs_getdir_unsorted(NTFS_LINO2NINO(dir),&cb.ph,&cb.pl, - ntfs_printcb,&cb); - }while(!error && cb.ph!=0xFFFFFFFF); - filp->f_pos=(cb.ph<<16)|cb.pl; - ntfs_debug(DEBUG_OTHER, "new position %x\n",(unsigned)filp->f_pos); - /* -EINVAL is on user buffer full. This is not considered - as an error by sys_getdents */ - if(error<0) - error=0; - /* Otherwise (device error, inconsistent data), switch the sign */ - return -error; + error = ntfs_getdir_unsorted(NTFS_LINO2NINO(dir), &cb.ph, + &cb.pl, ntfs_printcb, &cb); + } while (!error && cb.ph != 0xFFFFFFFF); + filp->f_pos = (cb.ph << 16) | cb.pl; + ntfs_debug(DEBUG_OTHER, "new position %x\n", (unsigned)filp->f_pos); + /* -EINVAL is on user buffer full. This is not considered as an error + * by sys_getdents. */ + if (error == -EINVAL) + error = 0; + /* Otherwise (device error, inconsistent data) return the error code. */ + return error; } -/* Copied from vfat driver */ +/* Copied from vfat driver. */ static int simple_getbool(char *s, int *setval) { if (s) { - if (!strcmp(s,"1") || !strcmp(s,"yes") || !strcmp(s,"true")) { + if (!strcmp(s, "1") || !strcmp(s, "yes") || !strcmp(s, "true")) *setval = 1; - } else if (!strcmp(s,"0") || !strcmp(s,"no") || !strcmp(s,"false")) { + else if (!strcmp(s, "0") || !strcmp(s, "no") || + !strcmp(s, "false")) *setval = 0; - } else { + else return 0; - } - } else { + } else *setval = 1; - } return 1; } -/* Parse the (re)mount options */ -static int parse_options(ntfs_volume* vol,char *opt) +/* Parse the (re)mount options. */ +static int parse_options(ntfs_volume* vol, char *opt) { char *value; - vol->uid=vol->gid=0; - vol->umask=0077; - vol->ngt=ngt_nt; - vol->nls_map=0; - vol->nct=0; - if(!opt)goto done; - - for(opt = strtok(opt,",");opt;opt=strtok(NULL,",")) + vol->uid = vol->gid = 0; + vol->umask = 0077; + vol->ngt = ngt_nt; + vol->nls_map = 0; + vol->nct = 0; + if (!opt) + goto done; + for (opt = strtok(opt, ","); opt; opt = strtok(NULL, ",")) { if ((value = strchr(opt, '=')) != NULL) - *value++='\0'; - if(strcmp(opt,"uid")==0) - { - if(!value || !*value)goto needs_arg; - vol->uid=simple_strtoul(value,&value,0); - if(*value){ + *value ++= '\0'; + if (strcmp(opt, "uid") == 0) { + if (!value || !*value) + goto needs_arg; + vol->uid = simple_strtoul(value, &value, 0); + if (*value) { printk(KERN_ERR "NTFS: uid invalid argument\n"); return 0; } - }else if(strcmp(opt, "gid") == 0) - { - if(!value || !*value)goto needs_arg; - vol->gid=simple_strtoul(value,&value,0); - if(*value){ - printk(KERN_ERR "gid invalid argument\n"); + } else if (strcmp(opt, "gid") == 0) { + if (!value || !*value) + goto needs_arg; + vol->gid = simple_strtoul(value, &value, 0); + if (*value) { + printk(KERN_ERR "NTFS: gid invalid argument\n"); return 0; } - }else if(strcmp(opt, "umask") == 0) - { - if(!value || !*value)goto needs_arg; - vol->umask=simple_strtoul(value,&value,0); - if(*value){ - printk(KERN_ERR "umask invalid argument\n"); + } else if (strcmp(opt, "umask") == 0) { + if (!value || !*value) + goto needs_arg; + vol->umask = simple_strtoul(value, &value, 0); + if (*value) { + printk(KERN_ERR "NTFS: umask invalid " + "argument\n"); return 0; } - }else if(strcmp(opt, "iocharset") == 0){ - if(!value || !*value)goto needs_arg; - vol->nls_map=load_nls(value); + } else if (strcmp(opt, "iocharset") == 0) { + if (!value || !*value) + goto needs_arg; + vol->nls_map = load_nls(value); vol->nct |= nct_map; - if(!vol->nls_map){ + if (!vol->nls_map) { printk(KERN_ERR "NTFS: charset not found"); return 0; } - }else if(strcmp(opt, "posix") == 0){ + } else if (strcmp(opt, "posix") == 0) { int val; - if(!value || !*value)goto needs_arg; - if(!simple_getbool(value,&val)) + if (!value || !*value) + goto needs_arg; + if (!simple_getbool(value, &val)) goto needs_bool; - vol->ngt=val?ngt_posix:ngt_nt; - }else if(strcmp(opt,"utf8") == 0){ - int val=0; - if(!value || !*value) - val=1; - else if(!simple_getbool(value,&val)) + vol->ngt = val ? ngt_posix : ngt_nt; + } else if (strcmp(opt, "utf8") == 0) { + int val = 0; + if (!value || !*value) + val = 1; + else if (!simple_getbool(value, &val)) goto needs_bool; - if(val) - vol->nct|=nct_utf8; - }else if(strcmp(opt,"uni_xlate") == 0){ - int val=0; - /* no argument: uni_vfat. - boolean argument: uni_vfat. - "2": uni. - */ - if(!value || !*value) - val=1; - else if(strcmp(value,"2")==0) + if (val) + vol->nct |= nct_utf8; + } else if (strcmp(opt, "uni_xlate") == 0) { + int val = 0; + /* No argument: uni_vfat. boolean argument: uni_vfat. + * "2": uni. */ + if (!value || !*value) + val = 1; + else if (strcmp(value, "2") == 0) vol->nct |= nct_uni_xlate; - else if(!simple_getbool(value,&val)) + else if (!simple_getbool(value, &val)) goto needs_bool; - if(val) + if (val) vol->nct |= nct_uni_xlate_vfat | nct_uni_xlate; - }else{ + } else { printk(KERN_ERR "NTFS: unkown option '%s'\n", opt); return 0; } } - if(vol->nct & nct_utf8 & (nct_map | nct_uni_xlate)){ - printk(KERN_ERR "utf8 cannot be combined with iocharset or uni_xlate\n"); + if (vol->nct & nct_utf8 & (nct_map | nct_uni_xlate)) { + printk(KERN_ERR "utf8 cannot be combined with iocharset or " + "uni_xlate\n"); return 0; } done: - if((vol->nct & (nct_uni_xlate | nct_map | nct_utf8))==0) + if ((vol->nct & (nct_uni_xlate | nct_map | nct_utf8)) == 0) /* default to UTF-8 */ - vol->nct=nct_utf8; - if(!vol->nls_map){ - vol->nls_map=load_nls_default(); + vol->nct = nct_utf8; + if (!vol->nls_map) { + vol->nls_map = load_nls_default(); if (vol->nls_map) - vol->nct=nct_map | (vol->nct&nct_uni_xlate); + vol->nct = nct_map | (vol->nct&nct_uni_xlate); } return 1; - needs_arg: - printk(KERN_ERR "NTFS: %s needs an argument",opt); + printk(KERN_ERR "NTFS: %s needs an argument", opt); return 0; needs_bool: - printk(KERN_ERR "NTFS: %s needs boolean argument",opt); + printk(KERN_ERR "NTFS: %s needs boolean argument", opt); return 0; } static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *d) { - struct inode *res=0; - char *item=0; + struct inode *res = 0; + char *item = 0; ntfs_iterate_s walk; int error; - ntfs_debug(DEBUG_NAME1, "Looking up %s in %x\n",d->d_name.name, + + ntfs_debug(DEBUG_NAME1, "Looking up %s in %x\n", d->d_name.name, (unsigned)dir->i_ino); - /* convert to wide string */ - error=ntfs_decodeuni(NTFS_INO2VOL(dir),(char*)d->d_name.name, - d->d_name.len,&walk.name,&walk.namelen); - if(error) - return ERR_PTR(-error); - item=ntfs_malloc(ITEM_SIZE); - if( !item ) + /* Convert to wide string. */ + error = ntfs_decodeuni(NTFS_INO2VOL(dir), (char*)d->d_name.name, + d->d_name.len, &walk.name, &walk.namelen); + if (error) + return ERR_PTR(error); + item = ntfs_malloc(ITEM_SIZE); + if (!item) return ERR_PTR(-ENOMEM); - /* ntfs_getdir will place the directory entry into item, - and the first long long is the MFT record number */ - walk.type=BY_NAME; - walk.dir=NTFS_LINO2NINO(dir); - walk.result=item; - if(ntfs_getdir_byname(&walk)) - { - res=iget(dir->i_sb,NTFS_GETU32(item)); - } - d_add(d,res); + /* ntfs_getdir will place the directory entry into item, and the first + * long long is the MFT record number. */ + walk.type = BY_NAME; + walk.dir = NTFS_LINO2NINO(dir); + walk.result = item; + if (ntfs_getdir_byname(&walk)) + res = iget(dir->i_sb, NTFS_GETU32(item)); + d_add(d, res); ntfs_free(item); ntfs_free(walk.name); /* Always return success, the dcache will handle negative entries. */ @@ -419,74 +415,61 @@ static struct inode_operations ntfs_inode_operations_nobmap; #ifdef CONFIG_NTFS_RW -static int -ntfs_create(struct inode* dir,struct dentry *d,int mode) +static int ntfs_create(struct inode* dir, struct dentry *d, int mode) { - struct inode *r=0; - ntfs_inode *ino=0; + struct inode *r = 0; + ntfs_inode *ino = 0; ntfs_volume *vol; - int error=0; + int error = 0; ntfs_attribute *si; - r=new_inode(dir->i_sb); - if(!r){ - error=ENOMEM; + r = new_inode(dir->i_sb); + if (!r) { + error = -ENOMEM; goto fail; } - - ntfs_debug(DEBUG_OTHER, "ntfs_create %s\n",d->d_name.name); - vol=NTFS_INO2VOL(dir); -#ifdef NTFS_IN_LINUX_KERNEL - ino=NTFS_LINO2NINO(r); -#else - ino=ntfs_malloc(sizeof(ntfs_inode)); - if(!ino){ - error=ENOMEM; + ntfs_debug(DEBUG_OTHER, "ntfs_create %s\n", d->d_name.name); + vol = NTFS_INO2VOL(dir); + ino = NTFS_LINO2NINO(r); + error = ntfs_alloc_file(NTFS_LINO2NINO(dir), ino, (char*)d->d_name.name, + d->d_name.len); + if (error) goto fail; - } - r->u.generic_ip=ino; -#endif - error=ntfs_alloc_file(NTFS_LINO2NINO(dir),ino,(char*)d->d_name.name, - d->d_name.len); - if(error)goto fail; - error=ntfs_update_inode(ino); - if(error)goto fail; - error=ntfs_update_inode(NTFS_LINO2NINO(dir)); - if(error)goto fail; - - r->i_uid=vol->uid; - r->i_gid=vol->gid; + error = ntfs_update_inode(ino); + if (error) + goto fail; + error = ntfs_update_inode(NTFS_LINO2NINO(dir)); + if (error) + goto fail; + r->i_uid = vol->uid; + r->i_gid = vol->gid; /* FIXME: dirty? dev? */ - /* get the file modification times from the standard information */ - si=ntfs_find_attr(ino,vol->at_standard_information,NULL); - if(si){ - char *attr=si->d.data; - r->i_atime=ntfs_ntutc2unixutc(NTFS_GETU64(attr+0x18)); - r->i_ctime=ntfs_ntutc2unixutc(NTFS_GETU64(attr)); - r->i_mtime=ntfs_ntutc2unixutc(NTFS_GETU64(attr+8)); + /* Get the file modification times from the standard information. */ + si = ntfs_find_attr(ino, vol->at_standard_information, NULL); + if (si) { + char *attr = si->d.data; + r->i_atime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 0x18)); + r->i_ctime = ntfs_ntutc2unixutc(NTFS_GETU64(attr)); + r->i_mtime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 8)); } /* It's not a directory */ - r->i_op=&ntfs_inode_operations_nobmap; - r->i_fop=&ntfs_file_operations_nommap, - r->i_mode=S_IFREG|S_IRUGO; + r->i_op = &ntfs_inode_operations_nobmap; + r->i_fop = &ntfs_file_operations_nommap, + r->i_mode = S_IFREG | S_IRUGO; #ifdef CONFIG_NTFS_RW - r->i_mode|=S_IWUGO; + r->i_mode |= S_IWUGO; #endif r->i_mode &= ~vol->umask; - insert_inode_hash(r); - d_instantiate(d,r); + d_instantiate(d, r); return 0; fail: - #ifndef NTFS_IN_LINUX_KERNEL - if(ino)ntfs_free(ino); - #endif - if(r)iput(r); - return -error; + if (r) + iput(r); + return error; } -static int -_linux_ntfs_mkdir(struct inode *dir, struct dentry* d, int mode) +static int _linux_ntfs_mkdir(struct inode *dir, struct dentry* d, int mode) { int error; struct inode *r = 0; @@ -494,45 +477,35 @@ ntfs_inode *ino; ntfs_attribute *si; - ntfs_debug (DEBUG_DIR1, "mkdir %s in %x\n",d->d_name.name, dir->i_ino); - error = ENAMETOOLONG; - if (d->d_name.len > /* FIXME */255) + ntfs_debug (DEBUG_DIR1, "mkdir %s in %x\n", d->d_name.name, dir->i_ino); + error = -ENAMETOOLONG; + if (d->d_name.len > /* FIXME: */ 255) goto out; - - error = EIO; + error = -EIO; r = new_inode(dir->i_sb); if (!r) goto out; - vol = NTFS_INO2VOL(dir); -#ifdef NTFS_IN_LINUX_KERNEL ino = NTFS_LINO2NINO(r); -#else - ino = ntfs_malloc(sizeof(ntfs_inode)); - error = ENOMEM; - if(!ino) - goto out; - r->u.generic_ip = ino; -#endif - error = ntfs_mkdir(NTFS_LINO2NINO(dir), - d->d_name.name, d->d_name.len, ino); - if(error) + error = ntfs_mkdir(NTFS_LINO2NINO(dir), d->d_name.name, d->d_name.len, + ino); + if (error) goto out; r->i_uid = vol->uid; r->i_gid = vol->gid; - si = ntfs_find_attr(ino,vol->at_standard_information,NULL); - if(si){ + si = ntfs_find_attr(ino, vol->at_standard_information, NULL); + if (si) { char *attr = si->d.data; - r->i_atime = ntfs_ntutc2unixutc(NTFS_GETU64(attr+0x18)); + r->i_atime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 0x18)); r->i_ctime = ntfs_ntutc2unixutc(NTFS_GETU64(attr)); - r->i_mtime = ntfs_ntutc2unixutc(NTFS_GETU64(attr+8)); + r->i_mtime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 8)); } - /* It's a directory */ + /* It's a directory. */ r->i_op = &ntfs_dir_inode_operations; r->i_fop = &ntfs_dir_operations; - r->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; + r->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; #ifdef CONFIG_NTFS_RW - r->i_mode|=S_IWUGO; + r->i_mode |= S_IWUGO; #endif r->i_mode &= ~vol->umask; @@ -540,24 +513,23 @@ d_instantiate(d, r); error = 0; out: - ntfs_debug (DEBUG_DIR1, "mkdir returns %d\n", -error); - return -error; + ntfs_debug (DEBUG_DIR1, "mkdir returns %d\n", error); + return error; } #endif #if 0 -static int -ntfs_bmap(struct inode *ino,int block) +static int ntfs_bmap(struct inode *ino, int block) { - int ret=ntfs_vcn_to_lcn(NTFS_LINO2NINO(ino),block); - ntfs_debug(DEBUG_OTHER, "bmap of %lx,block %x is %x\n", - ino->i_ino,block,ret); - return (ret==-1) ? 0:ret; + int ret = ntfs_vcn_to_lcn(NTFS_LINO2NINO(ino), block); + ntfs_debug(DEBUG_OTHER, "bmap of %lx, block %x is %x\n", ino->i_ino, + block, ret); + return (ret == -1) ? 0 : ret; } #endif /* It's fscking broken. */ -/* FIXME: [bm]map code is disabled until ntfs_get_block gets sorted! */ +/* FIXME: [bm]map code is disabled until ntfs_get_block() gets sorted! */ /* static int ntfs_get_block(struct inode *inode, long block, struct buffer_head *bh, int create) { @@ -594,19 +566,24 @@ { return block_write_full_page(page,ntfs_get_block); } + static int ntfs_readpage(struct file *file, struct page *page) { return block_read_full_page(page,ntfs_get_block); } -static int ntfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) + +static int ntfs_prepare_write(struct file *file, struct page *page, + unsigned from, unsigned to) { - return cont_prepare_write(page,from,to,ntfs_get_block, - &page->mapping->host->u.ntfs_i.mmu_private); + return cont_prepare_write(page, from, to, ntfs_get_block, + &page->mapping->host->u.ntfs_i.mmu_private); } + static int _ntfs_bmap(struct address_space *mapping, long block) { - return generic_block_bmap(mapping,block,ntfs_get_block); + return generic_block_bmap(mapping, block, ntfs_get_block); } + struct address_space_operations ntfs_aops = { readpage: ntfs_readpage, writepage: ntfs_writepage, @@ -617,84 +594,69 @@ }; */ -/* ntfs_read_inode is called by the Virtual File System (the kernel layer that - * deals with filesystems) when iget is called requesting an inode not already - * present in the inode table. Typically filesystems have separate - * inode_operations for directories, files and symlinks. - */ +/* ntfs_read_inode() is called by the Virtual File System (the kernel layer + * that deals with filesystems) when iget is called requesting an inode not + * already present in the inode table. Typically filesystems have separate + * inode_operations for directories, files and symlinks. */ static void ntfs_read_inode(struct inode* inode) { ntfs_volume *vol; - int can_mmap=0; + int can_mmap = 0; ntfs_inode *ino; ntfs_attribute *data; ntfs_attribute *si; - vol=NTFS_INO2VOL(inode); - inode->i_mode=0; - ntfs_debug(DEBUG_OTHER, "ntfs_read_inode %x\n",(unsigned)inode->i_ino); - - switch(inode->i_ino) - { - /* those are loaded special files */ - case FILE_MFT: - ntfs_error("Trying to open MFT\n");return; + vol = NTFS_INO2VOL(inode); + inode->i_mode = 0; + ntfs_debug(DEBUG_OTHER, "ntfs_read_inode %x\n", (unsigned)inode->i_ino); + switch (inode->i_ino) { + /* Those are loaded special files. */ + case FILE_$Mft: + ntfs_error("Trying to open MFT\n"); + return; default: - #ifdef NTFS_IN_LINUX_KERNEL - ino=&inode->u.ntfs_i; - #else - /* FIXME: check for ntfs_malloc failure */ - ino=(ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode)); - inode->u.generic_ip=ino; - #endif - if(!ino || ntfs_init_inode(ino, - NTFS_INO2VOL(inode),inode->i_ino)) + ino = &inode->u.ntfs_i; + if (!ino || ntfs_init_inode(ino, NTFS_INO2VOL(inode), + inode->i_ino)) { - ntfs_debug(DEBUG_OTHER, "NTFS:Error loading inode %x\n", - (unsigned int)inode->i_ino); + ntfs_debug(DEBUG_OTHER, "NTFS :Error loading inode " + "%x\n", (unsigned int)inode->i_ino); return; } } /* Set uid/gid from mount options */ - inode->i_uid=vol->uid; - inode->i_gid=vol->gid; - inode->i_nlink=1; + inode->i_uid = vol->uid; + inode->i_gid = vol->gid; + inode->i_nlink = 1; /* Use the size of the data attribute as file size */ - data = ntfs_find_attr(ino,vol->at_data,NULL); - if(!data) - { - inode->i_size=0; - can_mmap=0; - } - else - { - inode->i_size=data->size; + data = ntfs_find_attr(ino, vol->at_data, NULL); + if (!data) { + inode->i_size = 0; + can_mmap = 0; + } else { + inode->i_size = data->size; /* FIXME: once ntfs_get_block is implemented, uncomment the - * next line and remove the can_mmap = 0; */ - /* can_mmap=!data->resident && !data->compressed;*/ + * next line and remove the "can_mmap = 0;". (AIA) */ + /* can_mmap = !data->resident && !data->compressed; */ can_mmap = 0; } - /* get the file modification times from the standard information */ - si=ntfs_find_attr(ino,vol->at_standard_information,NULL); - if(si){ - char *attr=si->d.data; - inode->i_atime=ntfs_ntutc2unixutc(NTFS_GETU64(attr+0x18)); - inode->i_ctime=ntfs_ntutc2unixutc(NTFS_GETU64(attr)); - inode->i_mtime=ntfs_ntutc2unixutc(NTFS_GETU64(attr+8)); + /* Get the file modification times from the standard information. */ + si = ntfs_find_attr(ino,vol->at_standard_information, NULL); + if (si) { + char *attr = si->d.data; + inode->i_atime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 0x18)); + inode->i_ctime = ntfs_ntutc2unixutc(NTFS_GETU64(attr)); + inode->i_mtime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 8)); } - /* if it has an index root, it's a directory */ - if(ntfs_find_attr(ino,vol->at_index_root,"$I30")) - { + /* If it has an index root, it's a directory. */ + if (ntfs_find_attr(ino, vol->at_index_root, "$I30")) { ntfs_attribute *at; - at = ntfs_find_attr (ino, vol->at_index_allocation, "$I30"); + at = ntfs_find_attr(ino, vol->at_index_allocation, "$I30"); inode->i_size = at ? at->size : 0; - - inode->i_op=&ntfs_dir_inode_operations; - inode->i_fop=&ntfs_dir_operations; - inode->i_mode=S_IFDIR|S_IRUGO|S_IXUGO; - } - else - { + inode->i_op = &ntfs_dir_inode_operations; + inode->i_fop = &ntfs_dir_operations; + inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; + } else { /* As long as ntfs_get_block() is just a call to BUG() do not * define any [bm]map ops or we get the BUG() whenever someone * runs mc or mpg123 on an ntfs partition! @@ -706,25 +668,24 @@ inode->i_mapping->a_ops = &ntfs_aops; inode->u.ntfs_i.mmu_private = inode->i_size; } else */ { - inode->i_op=&ntfs_inode_operations_nobmap; - inode->i_fop=&ntfs_file_operations_nommap; + inode->i_op = &ntfs_inode_operations_nobmap; + inode->i_fop = &ntfs_file_operations_nommap; } - inode->i_mode=S_IFREG|S_IRUGO; + inode->i_mode = S_IFREG | S_IRUGO; } #ifdef CONFIG_NTFS_RW - if(!data || !data->compressed) - inode->i_mode|=S_IWUGO; + if (!data || !data->compressed) + inode->i_mode |= S_IWUGO; #endif inode->i_mode &= ~vol->umask; } #ifdef CONFIG_NTFS_RW -static void -ntfs_write_inode (struct inode *ino, int unused) +static void ntfs_write_inode(struct inode *ino, int unused) { lock_kernel(); - ntfs_debug (DEBUG_LINUX, "ntfs:write inode %x\n", ino->i_ino); - ntfs_update_inode (NTFS_LINO2NINO (ino)); + ntfs_debug(DEBUG_LINUX, "ntfs_write_inode %x\n", ino->i_ino); + ntfs_update_inode(NTFS_LINO2NINO(ino)); unlock_kernel(); } #endif @@ -732,41 +693,27 @@ static void _ntfs_clear_inode(struct inode *ino) { lock_kernel(); - ntfs_debug(DEBUG_OTHER, "ntfs_clear_inode %lx\n",ino->i_ino); -#ifdef NTFS_IN_LINUX_KERNEL - if(ino->i_ino!=FILE_MFT) + ntfs_debug(DEBUG_OTHER, "ntfs_clear_inode %lx\n", ino->i_ino); + if (ino->i_ino != FILE_$Mft) ntfs_clear_inode(&ino->u.ntfs_i); -#else - if(ino->i_ino!=FILE_MFT && ino->u.generic_ip) - { - ntfs_clear_inode(ino->u.generic_ip); - ntfs_free(ino->u.generic_ip); - ino->u.generic_ip=0; - } -#endif unlock_kernel(); return; } -/* Called when umounting a filesystem by do_umount() in fs/super.c */ +/* Called when umounting a filesystem by do_umount() in fs/super.c. */ static void ntfs_put_super(struct super_block *sb) { ntfs_volume *vol; ntfs_debug(DEBUG_OTHER, "ntfs_put_super\n"); - - vol=NTFS_SB2VOL(sb); - + vol = NTFS_SB2VOL(sb); ntfs_release_volume(vol); - if(vol->nls_map) + if (vol->nls_map) unload_nls(vol->nls_map); -#ifndef NTFS_IN_LINUX_KERNEL - ntfs_free(vol); -#endif ntfs_debug(DEBUG_OTHER, "ntfs_put_super: done\n"); } -/* Called by the kernel when asking for stats */ +/* Called by the kernel when asking for stats. */ static int ntfs_statfs(struct super_block *sb, struct statfs *sf) { struct inode *mft; @@ -775,34 +722,31 @@ int error; ntfs_debug(DEBUG_OTHER, "ntfs_statfs\n"); - vol=NTFS_SB2VOL(sb); - sf->f_type=NTFS_SUPER_MAGIC; - sf->f_bsize=vol->clustersize; - - error = ntfs_get_volumesize( NTFS_SB2VOL( sb ), &size ); - if( error ) - return -error; - sf->f_blocks = size; /* volumesize is in clusters */ - sf->f_bfree=ntfs_get_free_cluster_count(vol->bitmap); - sf->f_bavail=sf->f_bfree; - - mft=iget(sb,FILE_MFT); + vol = NTFS_SB2VOL(sb); + sf->f_type = NTFS_SUPER_MAGIC; + sf->f_bsize = vol->clustersize; + error = ntfs_get_volumesize(NTFS_SB2VOL(sb), &size); + if (error) + return error; + sf->f_blocks = size; /* Volumesize is in clusters. */ + sf->f_bfree = ntfs_get_free_cluster_count(vol->bitmap); + sf->f_bavail = sf->f_bfree; + mft = iget(sb, FILE_$Mft); if (!mft) return -EIO; - /* So ... we lie... thus this following cast of loff_t value - is ok here.. */ + /* So ... we lie... thus this following cast of loff_t value is ok + * here.. */ sf->f_files = (unsigned long)mft->i_size / vol->mft_recordsize; iput(mft); - - /* should be read from volume */ - sf->f_namelen=255; + /* Should be read from volume. */ + sf->f_namelen = 255; return 0; } -/* Called when remounting a filesystem by do_remount_sb() in fs/super.c */ +/* Called when remounting a filesystem by do_remount_sb() in fs/super.c. */ static int ntfs_remount_fs(struct super_block *sb, int *flags, char *options) { - if(!parse_options(NTFS_SB2VOL(sb), options)) + if (!parse_options(NTFS_SB2VOL(sb), options)) return -EINVAL; return 0; } @@ -819,144 +763,133 @@ clear_inode: _ntfs_clear_inode, }; -/* Called to mount a filesystem by read_super() in fs/super.c - * Return a super block, the main structure of a filesystem +/* Called to mount a filesystem by read_super() in fs/super.c. + * Return a super block, the main structure of a filesystem. * * NOTE : Don't store a pointer to an option, as the page containing the * options is freed after ntfs_read_super() returns. * * NOTE : A context switch can happen in kernel code only if the code blocks - * (= calls schedule() in kernel/sched.c). - */ -struct super_block * ntfs_read_super(struct super_block *sb, - void *options, int silent) + * (= calls schedule() in kernel/sched.c). */ +struct super_block * ntfs_read_super(struct super_block *sb, void *options, + int silent) { ntfs_volume *vol; struct buffer_head *bh; int i; ntfs_debug(DEBUG_OTHER, "ntfs_read_super\n"); - -#ifdef NTFS_IN_LINUX_KERNEL vol = NTFS_SB2VOL(sb); -#else - if(!(vol = ntfs_malloc(sizeof(ntfs_volume)))) - goto ntfs_read_super_dec; - NTFS_SB2VOL(sb)=vol; -#endif - - if(!parse_options(vol,(char*)options)) + if (!parse_options(vol, (char*)options)) goto ntfs_read_super_vol; - #if 0 /* Set to read only, user option might reset it */ sb->s_flags |= MS_RDONLY; #endif - - /* Assume a 512 bytes block device for now */ + /* Assume a 512 bytes block device for now. */ set_blocksize(sb->s_dev, 512); - /* Read the super block (boot block) */ - if(!(bh=bread(sb->s_dev,0,512))) { + /* Read the super block (boot block). */ + if (!(bh = bread(sb->s_dev, 0, 512))) { ntfs_error("Reading super block failed\n"); goto ntfs_read_super_unl; } ntfs_debug(DEBUG_OTHER, "Done reading boot block\n"); - /* Check for 'NTFS' magic number */ - if(!IS_NTFS_VOLUME(bh->b_data)){ + if (!IS_NTFS_VOLUME(bh->b_data)) { ntfs_debug(DEBUG_OTHER, "Not a NTFS volume\n"); brelse(bh); goto ntfs_read_super_unl; } - ntfs_debug(DEBUG_OTHER, "Going to init volume\n"); - ntfs_init_volume(vol,bh->b_data); - ntfs_debug(DEBUG_OTHER, "MFT record at cluster 0x%X\n",vol->mft_cluster); + if (ntfs_init_volume(vol, bh->b_data) < 0) { + ntfs_debug(DEBUG_OTHER, "Init volume failed.\n"); + brelse(bh); + goto ntfs_read_super_unl; + } + ntfs_debug(DEBUG_OTHER, "$Mft at cluster 0x%Lx\n", vol->mft_cluster); brelse(bh); - NTFS_SB(vol)=sb; + NTFS_SB(vol) = sb; ntfs_debug(DEBUG_OTHER, "Done to init volume\n"); - - /* Inform the kernel that a device block is a NTFS cluster */ - sb->s_blocksize=vol->clustersize; - for(i=sb->s_blocksize,sb->s_blocksize_bits=0;i != 1;i>>=1) + /* Inform the kernel that a device block is a NTFS cluster. */ + sb->s_blocksize = vol->clustersize; + if (sb->s_blocksize > PAGE_SIZE) { + ntfs_error("Partition cluster size is not supported yet (too " + "large for kernel blocksize).\n"); + goto ntfs_read_super_unl; + } + for (i = sb->s_blocksize, sb->s_blocksize_bits = 0; i != 1; i >>= 1) sb->s_blocksize_bits++; - set_blocksize(sb->s_dev,sb->s_blocksize); + set_blocksize(sb->s_dev, sb->s_blocksize); ntfs_debug(DEBUG_OTHER, "set_blocksize\n"); - /* Allocate a MFT record (MFT record can be smaller than a cluster) */ - if(!(vol->mft=ntfs_malloc(max(vol->mft_recordsize,vol->clustersize)))) + /* Allocate a MFT record (MFT record can be smaller than a cluster). */ + if (!(vol->mft = ntfs_malloc(max(vol->mft_recordsize, + vol->clustersize)))) goto ntfs_read_super_unl; - /* Read at least the MFT record for $MFT */ - for(i=0;i<max(vol->mft_clusters_per_record,1);i++){ - if(!(bh=bread(sb->s_dev,vol->mft_cluster+i,vol->clustersize))) { - ntfs_error("Could not read MFT record 0\n"); + /* Read at least the MFT record for $Mft. */ + for (i = 0; i < max(vol->mft_clusters_per_record, 1); i++) { + if (!(bh = bread(sb->s_dev, vol->mft_cluster + i, + vol->clustersize))) { + ntfs_error("Could not read $Mft record 0\n"); goto ntfs_read_super_mft; } - ntfs_memcpy(vol->mft+i*vol->clustersize,bh->b_data,vol->clustersize); + ntfs_memcpy(vol->mft + i * vol->clustersize, bh->b_data, + vol->clustersize); brelse(bh); - ntfs_debug(DEBUG_OTHER, "Read cluster %x\n",vol->mft_cluster+i); + ntfs_debug(DEBUG_OTHER, "Read cluster %x\n", + vol->mft_cluster + i); } - /* Check and fixup this MFT record */ - if(!ntfs_check_mft_record(vol,vol->mft)){ - ntfs_error("Invalid MFT record 0\n"); + if (!ntfs_check_mft_record(vol, vol->mft)){ + ntfs_error("Invalid $Mft record 0\n"); goto ntfs_read_super_mft; } - - /* Inform the kernel about which super operations are available */ + /* Inform the kernel about which super operations are available. */ sb->s_op = &ntfs_super_operations; sb->s_magic = NTFS_SUPER_MAGIC; - + sb->s_maxbytes = ~0ULL; ntfs_debug(DEBUG_OTHER, "Reading special files\n"); - if(ntfs_load_special_files(vol)){ + if (ntfs_load_special_files(vol)) { ntfs_error("Error loading special files\n"); goto ntfs_read_super_mft; } - ntfs_debug(DEBUG_OTHER, "Getting RootDir\n"); - /* Get the root directory */ - if(!(sb->s_root=d_alloc_root(iget(sb,FILE_ROOT)))){ + /* Get the root directory. */ + if (!(sb->s_root = d_alloc_root(iget(sb, FILE_$root)))) { ntfs_error("Could not get root dir inode\n"); goto ntfs_read_super_mft; } ntfs_debug(DEBUG_OTHER, "read_super: done\n"); return sb; - ntfs_read_super_mft: ntfs_free(vol->mft); ntfs_read_super_unl: ntfs_read_super_vol: - #ifndef NTFS_IN_LINUX_KERNEL - ntfs_free(vol); -ntfs_read_super_dec: - #endif ntfs_debug(DEBUG_OTHER, "read_super: done\n"); return NULL; } -/* Define the filesystem - */ +/* Define the filesystem */ static DECLARE_FSTYPE_DEV(ntfs_fs_type, "ntfs", ntfs_read_super); static int __init init_ntfs_fs(void) { - /* Comment this if you trust klogd. There are reasons not to trust it - */ + /* Comment this if you trust klogd. There are reasons not to trust it */ #if defined(DEBUG) && !defined(MODULE) console_verbose(); #endif printk(KERN_NOTICE "NTFS version " NTFS_VERSION "\n"); SYSCTL(1); - ntfs_debug(DEBUG_OTHER, "registering %s\n",ntfs_fs_type.name); - /* add this filesystem to the kernel table of filesystems */ + ntfs_debug(DEBUG_OTHER, "registering %s\n", ntfs_fs_type.name); + /* Add this filesystem to the kernel table of filesystems. */ return register_filesystem(&ntfs_fs_type); } static void __exit exit_ntfs_fs(void) { SYSCTL(0); - ntfs_debug(DEBUG_OTHER, "unregistering %s\n",ntfs_fs_type.name); + ntfs_debug(DEBUG_OTHER, "unregistering %s\n", ntfs_fs_type.name); unregister_filesystem(&ntfs_fs_type); } @@ -970,8 +903,4 @@ module_init(init_ntfs_fs) module_exit(exit_ntfs_fs) -/* - * Local variables: - * c-file-style: "linux" - * End: - */ + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ntfs/inode.c linux.ac/fs/ntfs/inode.c --- linux.vanilla/fs/ntfs/inode.c Fri Nov 17 19:35:27 2000 +++ linux.ac/fs/ntfs/inode.c Tue Apr 3 17:55:13 2001 @@ -1,23 +1,18 @@ -/* - * inode.c +/* inode.c * * Copyright (C) 1995-1999 Martin von Löwis * Copyright (C) 1996 Albert D. Cahalan * Copyright (C) 1996-1997 Régis Duchesne * Copyright (C) 1998 Joseph Malicki * Copyright (C) 1999 Steve Dodd - * Copyright (C) 2000 Anton Altaparmakov + * Copyright (C) 2000-2001 Anton Altaparmakov (AIA) */ #include "ntfstypes.h" #include "ntfsendian.h" #include "struct.h" #include "inode.h" - #include <linux/errno.h> -#ifdef HAVE_STRING_H -#include <string.h> -#endif #include "macros.h" #include "attr.h" #include "super.h" @@ -27,210 +22,229 @@ typedef struct { int recno; - unsigned char* record; + unsigned char *record; } ntfs_mft_record; typedef struct { int size; int count; - ntfs_mft_record* records; + ntfs_mft_record *records; } ntfs_disk_inode; -void -ntfs_fill_mft_header(ntfs_u8*mft,int record_size,int blocksize, - int sequence_number) +void ntfs_fill_mft_header(ntfs_u8 *mft, int record_size, int blocksize, + int sequence_number) { int fixup_count = record_size / blocksize + 1; int attr_offset = (0x2a + (2 * fixup_count) + 7) & ~7; int fixup_offset = 0x2a; NTFS_PUTU32(mft + 0x00, 0x454c4946); /* FILE */ - NTFS_PUTU16(mft + 0x04, 0x2a); /* offset to fixup */ - NTFS_PUTU16(mft + 0x06, fixup_count); /* Number of fixups */ - NTFS_PUTU16(mft + 0x10, sequence_number); - NTFS_PUTU16(mft + 0x12, 1); /* hard link count */ - NTFS_PUTU16(mft + 0x14, attr_offset); /* Offset to attributes */ - NTFS_PUTU16(mft + 0x16, 1); /*FIXME: flags ?? */ - NTFS_PUTU32(mft + 0x18, attr_offset + 0x08); /* In use */ - NTFS_PUTU32(mft + 0x1c, record_size); /* Total size */ - - NTFS_PUTU16(mft + fixup_offset, 1); /* Fixup word */ - NTFS_PUTU32(mft + attr_offset, 0xffffffff); /* End marker */ -} - -/* Search in an inode an attribute by type and name */ -ntfs_attribute* -ntfs_find_attr(ntfs_inode *ino,int type,char *name) + NTFS_PUTU16(mft + 0x04, 0x2a); /* Offset to fixup. */ + NTFS_PUTU16(mft + 0x06, fixup_count); /* Number of fixups. */ + NTFS_PUTU16(mft + 0x10, sequence_number); /* Sequence number. */ + NTFS_PUTU16(mft + 0x12, 1); /* Hard link count. */ + NTFS_PUTU16(mft + 0x14, attr_offset); /* Offset to attributes. */ + NTFS_PUTU16(mft + 0x16, 1); /* Flags: 1 = In use, + 2 = Directory. */ + NTFS_PUTU32(mft + 0x18, attr_offset + 0x08); /* Bytes in use. */ + NTFS_PUTU32(mft + 0x1c, record_size); /* Total allocated size. */ + NTFS_PUTU16(mft + fixup_offset, 1); /* Fixup word. */ + NTFS_PUTU32(mft + attr_offset, 0xffffffff); /* End marker. */ +} + +/* Search in an inode an attribute by type and name. + * FIXME: Check that when attributes are inserted all attribute list + * attributes are expanded otherwise need to modify this function to deal + * with attribute lists. (AIA) */ +ntfs_attribute *ntfs_find_attr(ntfs_inode *ino, int type, char *name) { int i; - if(!ino){ + + if (!ino) { ntfs_error("ntfs_find_attr: NO INODE!\n"); return 0; } - for(i=0;i<ino->attr_count;i++) - { - if(type==ino->attrs[i].type) - { - if(!name && !ino->attrs[i].name) - return ino->attrs+i; - if(name && !ino->attrs[i].name) - return 0; - if(!name && ino->attrs[i].name) - return 0; - if(ntfs_ua_strncmp(ino->attrs[i].name,name,strlen(name))==0) - return ino->attrs+i; - } - if(type<ino->attrs[i].type) + for (i = 0; i < ino->attr_count; i++) { + if (type < ino->attrs[i].type) return 0; + if (type == ino->attrs[i].type) { + if (!name) { + if (!ino->attrs[i].name) + return ino->attrs + i; + } else if (ino->attrs[i].name && + !ntfs_ua_strncmp(ino->attrs[i].name, name, + strlen(name))) + return ino->attrs + i; + } } return 0; } -/* FIXME: need better strategy to extend the MFT */ -static int -ntfs_extend_mft(ntfs_volume *vol) -{ - /* Try to allocate at least 0.1% of the remaining disk space - for inodes. If the disk is almost full, make sure at least one - inode is requested. - */ - int size,rcount,error,block; - ntfs_attribute* mdata,*bmp; +/* FIXME: Need better strategy to extend the MFT. */ +static int ntfs_extend_mft(ntfs_volume *vol) +{ + /* Try to allocate at least 0.1% of the remaining disk space for + * inodes. If the disk is almost full, make sure at least one inode is + * requested. */ + int size, rcount, error, block; + ntfs_attribute *mdata, *bmp; ntfs_u8 *buf; ntfs_io io; - mdata=ntfs_find_attr(vol->mft_ino,vol->at_data,0); - /* first check whether there is uninitialized space */ - if(mdata->allocated<mdata->size+vol->mft_recordsize){ - size=ntfs_get_free_cluster_count(vol->bitmap)*vol->clustersize; - block=vol->mft_recordsize; - size=max(size/1000,mdata->size+vol->mft_recordsize); - size=((size+block-1)/block)*block; - /* require this to be a single chunk */ - error=ntfs_extend_attr(vol->mft_ino,mdata,&size, - ALLOC_REQUIRE_SIZE); - /* Try again, now we have the largest available fragment */ - if(error==ENOSPC){ - /* round down to multiple of mft record size */ - size=(size/vol->mft_recordsize)*vol->mft_recordsize; - if(!size)return ENOSPC; - error=ntfs_extend_attr(vol->mft_ino,mdata,&size, - ALLOC_REQUIRE_SIZE); + mdata = ntfs_find_attr(vol->mft_ino, vol->at_data, 0); + /* First check whether there is uninitialized space. */ + if (mdata->allocated < mdata->size + vol->mft_recordsize) { + size = ntfs_get_free_cluster_count(vol->bitmap) * + vol->clustersize; + block = vol->mft_recordsize; + size = max(size / 1000, mdata->size + vol->mft_recordsize); + size = ((size + block - 1) / block) * block; + /* Require this to be a single chunk. */ + error = ntfs_extend_attr(vol->mft_ino, mdata, &size, + ALLOC_REQUIRE_SIZE); + /* Try again, now we have the largest available fragment. */ + if (error == -ENOSPC) { + /* Round down to multiple of mft record size. */ + size = (size / vol->mft_recordsize) * + vol->mft_recordsize; + if (!size) + return -ENOSPC; + error = ntfs_extend_attr(vol->mft_ino, mdata, &size, + ALLOC_REQUIRE_SIZE); } - if(error) + if (error) return error; } - /* even though we might have allocated more than needed, - we initialize only one record */ - mdata->size+=vol->mft_recordsize; - - /* now extend the bitmap if necessary*/ - rcount=mdata->size/vol->mft_recordsize; - bmp=ntfs_find_attr(vol->mft_ino,vol->at_bitmap,0); - if(bmp->size*8<rcount){ /* less bits than MFT records */ + /* Even though we might have allocated more than needed, we initialize + * only one record. */ + mdata->size += vol->mft_recordsize; + /* Now extend the bitmap if necessary. */ + rcount = mdata->size / vol->mft_recordsize; + bmp = ntfs_find_attr(vol->mft_ino, vol->at_bitmap, 0); + if (bmp->size * 8 < rcount) { /* Less bits than MFT records. */ ntfs_u8 buf[1]; - /* extend bitmap by one byte */ - error=ntfs_resize_attr(vol->mft_ino,bmp,bmp->size+1); - if(error)return error; - /* write the single byte */ - buf[0]=0; - io.fn_put=ntfs_put; - io.fn_get=ntfs_get; - io.param=buf; - io.size=1; - error=ntfs_write_attr(vol->mft_ino,vol->at_bitmap,0, - bmp->size-1,&io); - if(error)return error; - if(io.size!=1)return EIO; - } - - /* now fill in the MFT header for the new block */ - buf=ntfs_calloc(vol->mft_recordsize); - if(!buf)return ENOMEM; - ntfs_fill_mft_header(buf,vol->mft_recordsize,vol->blocksize,0); - ntfs_insert_fixups(buf,vol->blocksize); - io.param=buf; - io.size=vol->mft_recordsize; + /* Extend bitmap by one byte. */ + error = ntfs_resize_attr(vol->mft_ino, bmp, bmp->size + 1); + if (error) + return error; + /* Write the single byte. */ + buf[0] = 0; + io.fn_put = ntfs_put; + io.fn_get = ntfs_get; + io.param = buf; + io.size = 1; + error = ntfs_write_attr(vol->mft_ino, vol->at_bitmap, 0, + bmp->size - 1, &io); + if (error) + return error; + if (io.size != 1) + return -EIO; + } + /* Now fill in the MFT header for the new block. */ + buf = ntfs_calloc(vol->mft_recordsize); + if (!buf) + return -ENOMEM; + ntfs_fill_mft_header(buf, vol->mft_recordsize, vol->blocksize, 0); + ntfs_insert_fixups(buf, vol->blocksize); + io.param = buf; + io.size = vol->mft_recordsize; io.fn_put = ntfs_put; io.fn_get = ntfs_get; - error=ntfs_write_attr(vol->mft_ino,vol->at_data,0, - (rcount-1)*vol->mft_recordsize,&io); - if(error)return error; - if(io.size!=vol->mft_recordsize)return EIO; - error=ntfs_update_inode(vol->mft_ino); - if(error)return error; + error = ntfs_write_attr(vol->mft_ino, vol->at_data, 0, + (rcount - 1) * vol->mft_recordsize, &io); + if (error) + return error; + if (io.size != vol->mft_recordsize) + return -EIO; + error = ntfs_update_inode(vol->mft_ino); + if (error) + return error; return 0; } -/* Insert all attributes from the record mftno of the MFT in the inode ino */ -void ntfs_insert_mft_attributes(ntfs_inode* ino,char *mft,int mftno) +/* Insert all attributes from the record mftno of the MFT in the inode ino. + * FIXME: We should be performing structural consistency checks. (AIA) + * Return 0 on success or -errno on error. */ +static int ntfs_insert_mft_attributes(ntfs_inode* ino, char *mft, int mftno) { - int i; + int i, error, type, len; char *it; - int type,len; - /* check for duplicate */ - for(i=0;i<ino->record_count;i++) - if(ino->records[i]==mftno) - return; - /* (re-)allocate space if necessary */ - if(ino->record_count % 8==0) - { + + /* Check for duplicate. */ + for(i = 0; i < ino->record_count; i++) + if (ino->records[i] == mftno) + return 0; + /* (re-)allocate space if necessary. */ + if (ino->record_count % 8 == 0) { int *new; - new = ntfs_malloc((ino->record_count+8)*sizeof(int)); - if( !new ) - return; - if( ino->records ) { - for(i=0;i<ino->record_count;i++) + + new = ntfs_malloc((ino->record_count + 8) * sizeof(int)); + if (!new) + return -ENOMEM; + if (ino->records) { + for (i = 0; i < ino->record_count; i++) new[i] = ino->records[i]; - ntfs_free( ino->records ); + ntfs_free(ino->records); } ino->records = new; } - ino->records[ino->record_count]=mftno; + ino->records[ino->record_count] = mftno; ino->record_count++; it = mft + NTFS_GETU16(mft + 0x14); - do{ - type=NTFS_GETU32(it); - len=NTFS_GETU32(it+4); - if(type!=-1) { - /* FIXME: check ntfs_insert_attribute for failure (e.g. no mem)? */ - ntfs_insert_attribute(ino,it); - } - it+=len; - }while(type!=-1); /* attribute list ends with type -1 */ + do { + type = NTFS_GETU32(it); + len = NTFS_GETU32(it + 4); + if (type != -1) { + error = ntfs_insert_attribute(ino, it); + if (error) + return error; + } + it += len; + } while (type != -1); /* Attribute list ends with type -1. */ + return 0; } -/* Read and insert all the attributes of an 'attribute list' attribute - Return the number of remaining bytes in *plen -*/ +/* Read and insert all the attributes of an 'attribute list' attribute. + * Return the number of remaining bytes in *plen. */ static int parse_attributes(ntfs_inode *ino, ntfs_u8 *alist, int *plen) { char *mft; - int mftno,l,error; - int last_mft=-1; - int len=*plen; - mft=ntfs_malloc(ino->vol->mft_recordsize); - if( !mft ) - return ENOMEM; - while(len>8) - { - l=NTFS_GETU16(alist+4); - if(l>len)break; - /* process an attribute description */ - mftno=NTFS_GETU32(alist+0x10); /* BUG: this is u64 */ - if(mftno!=last_mft){ - last_mft=mftno; - /* FIXME: avoid loading record if it's - already processed */ - error=ntfs_read_mft_record(ino->vol,mftno,mft); - if(error)return error; - ntfs_insert_mft_attributes(ino,mft,mftno); + int mftno, l, error; + int last_mft = -1; + int len = *plen; + + mft = ntfs_malloc(ino->vol->mft_recordsize); + if (!mft) + return -ENOMEM; + while (len > 8) { + l = NTFS_GETU16(alist + 4); + if (l > len) + break; + /* Process an attribute description. */ + mftno = NTFS_GETU32(alist + 0x10); + /* FIXME: The mft reference (alist + 0x10) is __u64. + * - Not a problem unless we encounter a huge partition. + * - Should be consistency checking the sequence numbers + * though! This should maybe happen in + * ntfs_read_mft_record() itself and a hotfix could + * then occur there or the user notified to run + * ntfsck. (AIA) */ + if (mftno != last_mft){ + last_mft = mftno; + /* FIXME: Avoid loading record if it's already + * processed. */ + error = ntfs_read_mft_record(ino->vol, mftno, mft); + if (error) + return error; + error = ntfs_insert_mft_attributes(ino, mft, mftno); + if (error) + return error; } - len-=l; - alist+=l; + len -= l; + alist += l; } ntfs_free(mft); - *plen=len; + *plen = len; return 0; } @@ -238,167 +252,176 @@ { ntfs_attribute *alist; int datasize; - int offset,len,delta; + int offset, len, delta; char *buf; - ntfs_volume *vol=ino->vol; - ntfs_debug(DEBUG_FILE2, "load_attributes %x 1\n",ino->i_number); - ntfs_insert_mft_attributes(ino,ino->attr,ino->i_number); - ntfs_debug(DEBUG_FILE2, "load_attributes %x 2\n",ino->i_number); - alist=ntfs_find_attr(ino,vol->at_attribute_list,0); - ntfs_debug(DEBUG_FILE2, "load_attributes %x 3\n",ino->i_number); - if(!alist) + ntfs_volume *vol = ino->vol; + + ntfs_debug(DEBUG_FILE2, "load_attributes %x 1\n", ino->i_number); + if (ntfs_insert_mft_attributes(ino, ino->attr, ino->i_number)) return; - ntfs_debug(DEBUG_FILE2, "load_attributes %x 4\n",ino->i_number); - datasize=alist->size; - if(alist->resident) - { - parse_attributes(ino,alist->d.data,&datasize); + ntfs_debug(DEBUG_FILE2, "load_attributes %x 2\n", ino->i_number); + alist = ntfs_find_attr(ino, vol->at_attribute_list, 0); + ntfs_debug(DEBUG_FILE2, "load_attributes %x 3\n", ino->i_number); + if (!alist) + return; + ntfs_debug(DEBUG_FILE2, "load_attributes %x 4\n", ino->i_number); + datasize = alist->size; + if (alist->resident) { + parse_attributes(ino, alist->d.data, &datasize); return; } - buf=ntfs_malloc(1024); - if( !buf ) + buf = ntfs_malloc(1024); + if (!buf) /* FIXME: Should be passing error code to caller. (AIA) */ return; - delta=0; - for(offset=0;datasize;datasize-=len,offset+=len) - { + delta = 0; + for (offset = 0; datasize; datasize -= len, offset += len) { ntfs_io io; - io.fn_put=ntfs_put; - io.fn_get=0; - io.param=buf+delta; - io.size=len=min(datasize,1024-delta); - if(ntfs_read_attr(ino,vol->at_attribute_list,0,offset,&io)){ + + io.fn_put = ntfs_put; + io.fn_get = 0; + io.param = buf + delta; + io.size = len = min(datasize, 1024 - delta); + if (ntfs_read_attr(ino, vol->at_attribute_list, 0, offset, + &io)) ntfs_error("error in load_attributes\n"); - } - delta+=len; - parse_attributes(ino,buf,&delta); - if(delta) - /* move remaining bytes to buffer start */ - ntfs_memmove(buf,buf+len-delta,delta); + delta += len; + parse_attributes(ino, buf, &delta); + if (delta) + /* Move remaining bytes to buffer start. */ + ntfs_memmove(buf, buf + len - delta, delta); } - ntfs_debug(DEBUG_FILE2, "load_attributes %x 5\n",ino->i_number); + ntfs_debug(DEBUG_FILE2, "load_attributes %x 5\n", ino->i_number); ntfs_free(buf); } -int ntfs_init_inode(ntfs_inode *ino,ntfs_volume *vol,int inum) +int ntfs_init_inode(ntfs_inode *ino, ntfs_volume *vol, int inum) { char *buf; int error; - ntfs_debug(DEBUG_FILE1, "Initializing inode %x\n",inum); - if(!vol) + ntfs_debug(DEBUG_FILE1, "Initializing inode %x\n", inum); + if (!vol) ntfs_error("NO VOLUME!\n"); - ino->i_number=inum; - ino->vol=vol; - ino->attr=buf=ntfs_malloc(vol->mft_recordsize); - if( !buf ) - return ENOMEM; - error=ntfs_read_mft_record(vol,inum,ino->attr); - if(error){ - ntfs_debug(DEBUG_OTHER, "init inode: %x failed\n",inum); + ino->i_number = inum; + ino->vol = vol; + ino->attr = buf = ntfs_malloc(vol->mft_recordsize); + if (!buf) + return -ENOMEM; + error = ntfs_read_mft_record(vol, inum, ino->attr); + if (error) { + ntfs_debug(DEBUG_OTHER, "Init inode: %x failed\n", inum); return error; } - ntfs_debug(DEBUG_FILE2, "Init: got mft %x\n",inum); - ino->sequence_number=NTFS_GETU16(buf+0x10); - ino->attr_count=0; - ino->record_count=0; - ino->records=0; - ino->attrs=0; + ntfs_debug(DEBUG_FILE2, "Init inode: got mft %x\n", inum); + ino->sequence_number = NTFS_GETU16(buf + 0x10); + ino->attr_count = 0; + ino->record_count = 0; + ino->records = 0; + ino->attrs = 0; ntfs_load_attributes(ino); - ntfs_debug(DEBUG_FILE2, "Init: done %x\n",inum); + ntfs_debug(DEBUG_FILE2, "Init inode: done %x\n", inum); return 0; } void ntfs_clear_inode(ntfs_inode *ino) { int i; - if(!ino->attr){ + if (!ino->attr) { ntfs_error("ntfs_clear_inode: double free\n"); return; } ntfs_free(ino->attr); - ino->attr=0; + ino->attr = 0; ntfs_free(ino->records); - ino->records=0; - for(i=0;i<ino->attr_count;i++) - { - if(ino->attrs[i].name) + ino->records = 0; + for (i = 0; i < ino->attr_count; i++) { + if (ino->attrs[i].name) ntfs_free(ino->attrs[i].name); - if(ino->attrs[i].resident) - { - if(ino->attrs[i].d.data) + if (ino->attrs[i].resident) { + if (ino->attrs[i].d.data) ntfs_free(ino->attrs[i].d.data); - }else{ - if(ino->attrs[i].d.r.runlist) + } else { + if (ino->attrs[i].d.r.runlist) ntfs_free(ino->attrs[i].d.r.runlist); } } ntfs_free(ino->attrs); - ino->attrs=0; + ino->attrs = 0; } -/* Check and fixup a MFT record */ -int ntfs_check_mft_record(ntfs_volume *vol,char *record) +/* Check and fixup a MFT record. */ +int ntfs_check_mft_record(ntfs_volume *vol, char *record) { return ntfs_fixup_record(vol, record, "FILE", vol->mft_recordsize); } /* Return (in result) the value indicating the next available attribute - chunk number. Works for inodes w/o extension records only */ + * chunk number. Works for inodes w/o extension records only. */ int ntfs_allocate_attr_number(ntfs_inode *ino, int *result) { - if(ino->record_count!=1) - return EOPNOTSUPP; - *result=NTFS_GETU16(ino->attr+0x28); - NTFS_PUTU16(ino->attr+0x28, (*result)+1); + if (ino->record_count != 1) + return -EOPNOTSUPP; + *result = NTFS_GETU16(ino->attr + 0x28); + NTFS_PUTU16(ino->attr + 0x28, (*result) + 1); return 0; } -/* find the location of an attribute in the inode. A name of NULL indicates - unnamed attributes. Return pointer to attribute or NULL if not found */ -char * -ntfs_get_attr(ntfs_inode *ino,int attr,char *name) +/* Find the location of an attribute in the inode. A name of NULL indicates + * unnamed attributes. Return pointer to attribute or NULL if not found. */ +char *ntfs_get_attr(ntfs_inode *ino, int attr, char *name) { - /* location of first attribute */ - char *it= ino->attr + NTFS_GETU16(ino->attr + 0x14); + /* Location of first attribute. */ + char *it = ino->attr + NTFS_GETU16(ino->attr + 0x14); int type; int len; - /* Only check for magic DWORD here, fixup should have happened before */ - if(!IS_MFT_RECORD(ino->attr))return 0; - do{ - type=NTFS_GETU32(it); - len=NTFS_GETU16(it+4); + + /* Only check for magic DWORD here, fixup should have happened before.*/ + if (!IS_MFT_RECORD(ino->attr)) + return 0; + do { + type = NTFS_GETU32(it); + len = NTFS_GETU16(it + 4); /* We found the attribute type. Is the name correct, too? */ - if(type==attr) - { - int namelen=NTFS_GETU8(it+9); - char *name_it; - /* match given name and attribute name if present, - make sure attribute name is Unicode */ - for(name_it=it+NTFS_GETU16(it+10);namelen; - name++,name_it+=2,namelen--) - if(*name_it!=*name || name_it[1])break; - if(!namelen)break; - } - it+=len; - }while(type!=-1); /* attribute list end with type -1 */ - if(type==-1)return 0; + if (type == attr) { + int namelen = NTFS_GETU8(it + 9); + char *name_it, *n = name; + /* Match given name and attribute name if present. + Make sure attribute name is Unicode. */ + if (!name) { + goto check_namelen; + } else if (namelen) { + for (name_it = it + NTFS_GETU16(it + 10); + namelen; n++, name_it += 2, namelen--) + if (*name_it != *n || name_it[1]) + break; +check_namelen: + if (!namelen) + break; + } + } + it += len; + } while (type != -1); /* List of attributes ends with type -1. */ + if (type == -1) + return 0; return it; } -int -ntfs_get_attr_size(ntfs_inode*ino,int type,char*name) +int ntfs_get_attr_size(ntfs_inode *ino, int type, char *name) { - ntfs_attribute *attr=ntfs_find_attr(ino,type,name); - if(!attr)return 0; - return attr->size; + ntfs_attribute *attr = ntfs_find_attr(ino, type, name); + if (!attr) + return 0; + return + attr->size; } -int -ntfs_attr_is_resident(ntfs_inode*ino,int type,char*name) +int ntfs_attr_is_resident(ntfs_inode *ino, int type, char *name) { - ntfs_attribute *attr=ntfs_find_attr(ino,type,name); - if(!attr)return 0; - return attr->resident; + ntfs_attribute *attr = ntfs_find_attr(ino, type, name); + if (!attr) + return 0; + return + attr->resident; } /* @@ -413,489 +436,520 @@ * This function decodes a run. Length is an output parameter, data and cluster * are in/out parameters. */ -int ntfs_decompress_run(unsigned char **data, int *length, ntfs_cluster_t *cluster, - int *ctype) +int ntfs_decompress_run(unsigned char **data, int *length, + ntfs_cluster_t *cluster, int *ctype) { - unsigned char type=*(*data)++; - *ctype=0; - switch(type & 0xF) - { - case 1: *length=NTFS_GETU8(*data);break; - case 2: *length=NTFS_GETU16(*data);break; - case 3: *length=NTFS_GETU24(*data);break; - case 4: *length=NTFS_GETU32(*data);break; - /* Note: cases 5-8 are probably pointless to code, - since how many runs > 4GB of length are there? - at the most, cases 5 and 6 are probably necessary, - and would also require making length 64-bit - throughout */ + unsigned char type = *(*data)++; + *ctype = 0; + switch (type & 0xF) { + case 1: + *length = NTFS_GETS8(*data); + break; + case 2: + *length = NTFS_GETS16(*data); + break; + case 3: + *length = NTFS_GETS24(*data); + break; + case 4: + *length = NTFS_GETS32(*data); + break; + /* Note: cases 5-8 are probably pointless to code, since how + * many runs > 4GB of length are there? At the most, cases 5 + * and 6 are probably necessary, and would also require making + * length 64-bit throughout. */ default: - ntfs_error("Can't decode run type field %x\n",type); + ntfs_error("Can't decode run type field %x\n", type); return -1; } - *data+=(type & 0xF); - - switch(type & 0xF0) + if (*length < 0) { - case 0: *ctype=2; break; - case 0x10: *cluster += NTFS_GETS8(*data);break; - case 0x20: *cluster += NTFS_GETS16(*data);break; - case 0x30: *cluster += NTFS_GETS24(*data);break; - case 0x40: *cluster += NTFS_GETS32(*data);break; -#if 0 /* Keep for future, in case ntfs_cluster_t ever becomes 64bit */ - case 0x50: *cluster += NTFS_GETS40(*data);break; - case 0x60: *cluster += NTFS_GETS48(*data);break; - case 0x70: *cluster += NTFS_GETS56(*data);break; - case 0x80: *cluster += NTFS_GETS64(*data);break; + ntfs_error("Negative run length decoded\n"); + return -1; + } + *data += (type & 0xF); + switch (type & 0xF0) { + case 0: + *ctype = 2; + break; + case 0x10: + *cluster += NTFS_GETS8(*data); + break; + case 0x20: + *cluster += NTFS_GETS16(*data); + break; + case 0x30: + *cluster += NTFS_GETS24(*data); + break; + case 0x40: + *cluster += NTFS_GETS32(*data); + break; +#if 0 /* Keep for future, in case ntfs_cluster_t ever becomes 64bit. */ + case 0x50: + *cluster += NTFS_GETS40(*data); + break; + case 0x60: + *cluster += NTFS_GETS48(*data); + break; + case 0x70: + *cluster += NTFS_GETS56(*data); + break; + case 0x80: + *cluster += NTFS_GETS64(*data); + break; #endif default: - ntfs_error("Can't decode run type field %x\n",type); + ntfs_error("Can't decode run type field %x\n", type); return -1; } - *data+=(type >> 4); + *data += (type >> 4); return 0; } -/* Reads l bytes of the attribute (attr,name) of ino starting at offset - on vol into buf. Returns the number of bytes read in the ntfs_io struct. - Returns 0 on success, errno on failure */ +/* + * FIXME: ntfs_readwrite_attr() has the effect of writing @dest to @offset of + * the attribute value of the attribute @attr in the in memory inode @ino. + * If the attribute value of @attr is non-resident the value's contents at + * @offset are actually written to disk (from @dest). The on disk mft record + * describing the non-resident attribute value is not updated! + * If the attribute value is resident then the value is written only in + * memory. The on disk mft record containing the value is not written to disk. + * A possible fix would be to call ntfs_update_inode() before returning. (AIA) + */ +/* Reads l bytes of the attribute (attr, name) of ino starting at offset on + * vol into buf. Returns the number of bytes read in the ntfs_io struct. + * Returns 0 on success, errno on failure */ int ntfs_readwrite_attr(ntfs_inode *ino, ntfs_attribute *attr, int offset, - ntfs_io *dest) + ntfs_io *dest) { int rnum; - ntfs_cluster_t cluster,s_cluster,vcn,len; - int l,chunk,copied; + ntfs_cluster_t cluster, s_cluster, vcn, len; + int l, chunk, copied; int s_vcn; int clustersize; int error; - clustersize=ino->vol->clustersize; - l=dest->size; - if(l==0) + clustersize = ino->vol->clustersize; + l = dest->size; + if (l == 0) return 0; - if(dest->do_read) - { - /* if read _starts_ beyond end of stream, return nothing */ - if(offset>=attr->size){ - dest->size=0; + if (dest->do_read) { + /* If read _starts_ beyond end of stream, return nothing. */ + if (offset >= attr->size) { + dest->size = 0; return 0; } - - /* if read _extends_ beyond end of stream, return as much - initialised data as we have */ - if(offset+l>=attr->size) - l=dest->size=attr->size-offset; - - }else { - /* fixed by CSA: if writing beyond end, extend attribute */ - - /* if write extends beyond _allocated_ size, extend attrib */ - if (offset+l>attr->allocated) { - error=ntfs_resize_attr(ino,attr,offset+l); - if(error) + /* If read _extends_ beyond end of stream, return as much + * initialised data as we have. */ + if (offset + l >= attr->size) + l = dest->size = attr->size - offset; + } else { + /* Fixed by CSA: If writing beyond end, extend attribute. */ + /* If write extends beyond _allocated_ size, extend attrib. */ + if (offset + l > attr->allocated) { + error = ntfs_resize_attr(ino, attr, offset + l); + if (error) return error; } - - /* the amount of initialised data has increased; update */ - /* FIXME: shouldn't we zero-out the section between the old - initialised length and the write start? */ - if (offset+l > attr->initialized) { - attr->initialized = offset+l; - attr->size = offset+l; + /* The amount of initialised data has increased: update. */ + /* FIXME: Shouldn't we zero-out the section between the old + * initialised length and the write start? */ + if (offset + l > attr->initialized) { + attr->initialized = offset + l; + attr->size = offset + l; } } - if(attr->resident) - { - if(dest->do_read) - dest->fn_put(dest,(ntfs_u8*)attr->d.data+offset,l); + if (attr->resident) { + if (dest->do_read) + dest->fn_put(dest, (ntfs_u8*)attr->d.data + offset, l); else - dest->fn_get((ntfs_u8*)attr->d.data+offset,dest,l); - dest->size=l; + dest->fn_get((ntfs_u8*)attr->d.data + offset, dest, l); + dest->size = l; return 0; } - /* read uninitialized data */ - if(offset>=attr->initialized && dest->do_read) - return ntfs_read_zero(dest,l); - if(offset+l>attr->initialized && dest->do_read) - { - dest->size = chunk = offset+l - attr->initialized; - error = ntfs_readwrite_attr(ino,attr,offset,dest); - if(error) + /* Read uninitialized data. */ + if (offset >= attr->initialized && dest->do_read) + return ntfs_read_zero(dest, l); + if (offset + l > attr->initialized && dest->do_read) { + dest->size = chunk = offset + l - attr->initialized; + error = ntfs_readwrite_attr(ino, attr, offset, dest); + if (error) return error; - return ntfs_read_zero(dest,l-chunk); + return ntfs_read_zero(dest, l - chunk); } - if(attr->compressed){ - if(dest->do_read) - return ntfs_read_compressed(ino,attr,offset,dest); + if (attr->compressed) { + if (dest->do_read) + return ntfs_read_compressed(ino, attr, offset, dest); else - return ntfs_write_compressed(ino,attr,offset,dest); + return ntfs_write_compressed(ino, attr, offset, dest); } - vcn=0; - s_vcn = offset/clustersize; - for(rnum=0;rnum<attr->d.r.len && - vcn+attr->d.r.runlist[rnum].len<=s_vcn;rnum++) - vcn+=attr->d.r.runlist[rnum].len; - if(rnum==attr->d.r.len) - /*FIXME: should extend runlist */ - return EOPNOTSUPP; - - copied=0; - while(l) - { - s_vcn = offset/clustersize; - cluster=attr->d.r.runlist[rnum].cluster; - len=attr->d.r.runlist[rnum].len; - - s_cluster = cluster+s_vcn-vcn; - - chunk=min((vcn+len)*clustersize-offset,l); - dest->size=chunk; - error=ntfs_getput_clusters(ino->vol,s_cluster, - offset-s_vcn*clustersize,dest); - if(error) - { - ntfs_error("Read error\n"); - dest->size=copied; + vcn = 0; + s_vcn = offset / clustersize; + for (rnum = 0; rnum < attr->d.r.len && + vcn + attr->d.r.runlist[rnum].len <= s_vcn; rnum++) + vcn += attr->d.r.runlist[rnum].len; + if (rnum == attr->d.r.len) + /*FIXME: Should extend runlist. */ + return -EOPNOTSUPP; + copied = 0; + while (l) { + s_vcn = offset / clustersize; + cluster = attr->d.r.runlist[rnum].cluster; + len = attr->d.r.runlist[rnum].len; + s_cluster = cluster + s_vcn - vcn; + chunk = min((vcn + len) * clustersize - offset, l); + dest->size = chunk; + error = ntfs_getput_clusters(ino->vol, s_cluster, + offset - s_vcn * clustersize, dest); + if (error) { + ntfs_error("Read/write error\n"); + dest->size = copied; return error; } - l-=chunk; - copied+=chunk; - offset+=chunk; - if(l && offset>=((vcn+len)*clustersize)) - { + l -= chunk; + copied += chunk; + offset += chunk; + if (l && offset >= ((vcn + len) * clustersize)) { rnum++; - vcn+=len; + vcn += len; cluster = attr->d.r.runlist[rnum].cluster; len = attr->d.r.runlist[rnum].len; } } - dest->size=copied; + dest->size = copied; return 0; } int ntfs_read_attr(ntfs_inode *ino, int type, char *name, int offset, - ntfs_io *buf) + ntfs_io *buf) { ntfs_attribute *attr; - buf->do_read=1; - attr=ntfs_find_attr(ino,type,name); - if(!attr) - return EINVAL; - return ntfs_readwrite_attr(ino,attr,offset,buf); + + buf->do_read = 1; + attr = ntfs_find_attr(ino, type, name); + if (!attr) + return -EINVAL; + return ntfs_readwrite_attr(ino, attr, offset, buf); } int ntfs_write_attr(ntfs_inode *ino, int type, char *name, int offset, - ntfs_io *buf) + ntfs_io *buf) { ntfs_attribute *attr; - buf->do_read=0; - attr=ntfs_find_attr(ino,type,name); - if(!attr) - return EINVAL; - return ntfs_readwrite_attr(ino,attr,offset,buf); + + buf->do_read = 0; + attr = ntfs_find_attr(ino, type, name); + if (!attr) + return -EINVAL; + return ntfs_readwrite_attr(ino, attr, offset, buf); } -int ntfs_vcn_to_lcn(ntfs_inode *ino,int vcn) +int ntfs_vcn_to_lcn(ntfs_inode *ino, int vcn) { int rnum; ntfs_attribute *data; - data=ntfs_find_attr(ino,ino->vol->at_data,0); - /* It's hard to give an error code */ - if(!data)return -1; - if(data->resident)return -1; - if(data->compressed)return -1; - if(data->size <= vcn*ino->vol->clustersize)return -1; - - + + data = ntfs_find_attr(ino, ino->vol->at_data, 0); + /* It's hard to give an error code. */ + if (!data || data->resident || data->compressed) + return -1; + if (data->size <= vcn*ino->vol->clustersize) + return -1; /* For Linux, block number 0 represents a hole. - Hopefully, nobody will attempt to bmap $Boot. */ - if(data->initialized <= vcn*ino->vol->clustersize) + * Hopefully, nobody will attempt to bmap $Boot. */ + if (data->initialized <= vcn * ino->vol->clustersize) return 0; - - for(rnum=0;rnum<data->d.r.len && - vcn>=data->d.r.runlist[rnum].len;rnum++) - vcn-=data->d.r.runlist[rnum].len; - - return data->d.r.runlist[rnum].cluster+vcn; + for (rnum = 0; rnum < data->d.r.len && + vcn >= data->d.r.runlist[rnum].len; rnum++) + vcn -= data->d.r.runlist[rnum].len; + return data->d.r.runlist[rnum].cluster + vcn; } -static int -allocate_store(ntfs_volume *vol,ntfs_disk_inode *store,int count) +static int allocate_store(ntfs_volume *vol, ntfs_disk_inode *store, int count) { int i; - if(store->count>count) + + if (store->count > count) return 0; - if(store->size<count){ - ntfs_mft_record* n=ntfs_malloc((count+4)*sizeof(ntfs_mft_record)); - if(!n) - return ENOMEM; - if(store->size){ - for(i=0;i<store->size;i++) - n[i]=store->records[i]; + if (store->size < count) { + ntfs_mft_record *n = ntfs_malloc((count + 4) * + sizeof(ntfs_mft_record)); + if (!n) + return -ENOMEM; + if (store->size) { + for (i = 0; i < store->size; i++) + n[i] = store->records[i]; ntfs_free(store->records); } - store->size=count+4; - store->records=n; + store->size = count + 4; + store->records = n; } - for(i=store->count;i<count;i++){ - store->records[i].record=ntfs_malloc(vol->mft_recordsize); - if(!store->records[i].record) - return ENOMEM; + for (i = store->count; i < count; i++) { + store->records[i].record = ntfs_malloc(vol->mft_recordsize); + if (!store->records[i].record) + return -ENOMEM; store->count++; } return 0; } -static void -deallocate_store(ntfs_disk_inode* store) +static void deallocate_store(ntfs_disk_inode* store) { int i; - for(i=0;i<store->count;i++) + + for (i = 0; i < store->count; i++) ntfs_free(store->records[i].record); ntfs_free(store->records); - store->count=store->size=0; - store->records=0; + store->count = store->size = 0; + store->records = 0; } -int -layout_runs(ntfs_attribute *attr,char* rec,int* offs,int size) +/** + * layout_runs - compress runlist into mapping pairs array + * @attr: attribute containing the runlist to compress + * @rec: destination buffer to hold the mapping pairs array + * @offs: current position in @rec (in/out variable) + * @size: size of the buffer @rec + * + * layout_runs walks the runlist in @attr, compresses it and writes it out the + * resulting mapping pairs array into @rec (up to a maximum of @size bytes are + * written). On entry @offs is the offset in @rec at which to begin writting the + * mapping pairs array. On exit, it contains the offset in @rec of the first + * byte after the end of the mapping pairs array. + */ +static int layout_runs(ntfs_attribute *attr, char* rec, int* offs, int size) { - int i,len,offset,coffs; - ntfs_cluster_t cluster,rclus; - ntfs_runlist *rl=attr->d.r.runlist; - cluster=0; - offset=*offs; - for(i=0;i<attr->d.r.len;i++){ - rclus=rl[i].cluster-cluster; - len=rl[i].len; - rec[offset]=0; - if(offset+8>size) - return E2BIG; /* it might still fit, but this simplifies testing */ - if(len<0x100){ - NTFS_PUTU8(rec+offset+1,len); - coffs=1; - }else if(len<0x10000){ - NTFS_PUTU16(rec+offset+1,len); - coffs=2; - }else if(len<0x1000000){ - NTFS_PUTU24(rec+offset+1,len); - coffs=3; - }else{ - NTFS_PUTU32(rec+offset+1,len); - coffs=4; - } - - *(rec+offset)|=coffs++; - - if(rl[i].cluster==MAX_CLUSTER_T) /*compressed run*/ - /*nothing*/; - else if(rclus>-0x80 && rclus<0x7F){ - *(rec+offset)|=0x10; - NTFS_PUTS8(rec+offset+coffs,rclus); - coffs+=1; - }else if(rclus>-0x8000 && rclus<0x7FFF){ - *(rec+offset)|=0x20; - NTFS_PUTS16(rec+offset+coffs,rclus); - coffs+=2; - }else if(rclus>-0x800000 && rclus<0x7FFFFF){ - *(rec+offset)|=0x30; - NTFS_PUTS24(rec+offset+coffs,rclus); - coffs+=3; - }else -#if 0 /* In case ntfs_cluster_t ever becomes 64bit */ - if (rclus>-0x80000000LL && rclus<0x7FFFFFFF) + int i, len, offset, coffs; + ntfs_cluster_t cluster, rclus; + ntfs_runlist *rl = attr->d.r.runlist; + cluster = 0; + offset = *offs; + for (i = 0; i < attr->d.r.len; i++) { + rclus = rl[i].cluster - cluster; + len = rl[i].len; + rec[offset] = 0; + if (offset + 9 > size) + return -E2BIG; /* It might still fit, but this + * simplifies testing. */ + /* Run length is stored as signed number. */ + if (len <= 0x7F) { + NTFS_PUTU8(rec + offset + 1, len); + coffs = 1; + } else if (len <= 0x7FFF) { + NTFS_PUTU16(rec + offset + 1, len); + coffs = 2; + } else if (len <= 0x7FFFFF) { + NTFS_PUTU24(rec + offset + 1, len); + coffs = 3; + } else { + NTFS_PUTU32(rec + offset + 1, len); + coffs = 4; + } + *(rec + offset) |= coffs++; + if (rl[i].cluster == MAX_CLUSTER_T) /* Compressed run. */ + /* Nothing */; + else if (rclus >= -0x80 && rclus <= 0x7F) { + *(rec + offset) |= 0x10; + NTFS_PUTS8(rec + offset + coffs, rclus); + coffs += 1; + } else if(rclus >= -0x8000 && rclus <= 0x7FFF) { + *(rec + offset) |= 0x20; + NTFS_PUTS16(rec + offset + coffs, rclus); + coffs += 2; + } else if(rclus >= -0x800000 && rclus <= 0x7FFFFF) { + *(rec + offset) |= 0x30; + NTFS_PUTS24(rec + offset + coffs, rclus); + coffs += 3; + } else +#if 0 /* In case ntfs_cluster_t ever becomes 64bit. */ + if (rclus >= -0x80000000LL && rclus <= 0x7FFFFFFF) #endif { - *(rec+offset)|=0x40; - NTFS_PUTS32(rec+offset+coffs,rclus); - coffs+=4; + *(rec + offset) |= 0x40; + NTFS_PUTS32(rec + offset + coffs, rclus); + coffs += 4; } #if 0 /* For 64-bit ntfs_cluster_t */ - else if (rclus>-0x8000000000 && rclus<0x7FFFFFFFFF){ - *(rec+offset)|=0x50; - NTFS_PUTS40(rec+offset+coffs,rclus); - coffs+=5; - }else if (rclus>-0x800000000000 && rclus<0x7FFFFFFFFFFF){ - *(rec+offset)|=0x60; - NTFS_PUTS48(rec+offset+coffs,rclus); - coffs+=6; - }else if (rclus>-0x80000000000000 && rclus<0x7FFFFFFFFFFFFF){ - *(rec+offset)|=0x70; - NTFS_PUTS56(rec+offset+coffs,rclus); - coffs+=7; - }else{ - *(rec+offset)|=0x80; - NTFS_PUTS64(rec+offset+coffs,rclus); - coffs+=8; + else if (rclus >= -0x8000000000 && rclus <= 0x7FFFFFFFFF) { + *(rec + offset) |= 0x50; + NTFS_PUTS40(rec + offset + coffs, rclus); + coffs += 5; + } else if (rclus >= -0x800000000000 && + rclus <= 0x7FFFFFFFFFFF) { + *(rec + offset) |= 0x60; + NTFS_PUTS48(rec + offset + coffs, rclus); + coffs += 6; + } else if (rclus >= -0x80000000000000 && + rclus <= 0x7FFFFFFFFFFFFF) { + *(rec + offset) |= 0x70; + NTFS_PUTS56(rec + offset + coffs, rclus); + coffs += 7; + } else { + *(rec + offset) |= 0x80; + NTFS_PUTS64(rec + offset + coffs, rclus); + coffs += 8; } #endif - offset+=coffs; - if(rl[i].cluster) - cluster=rl[i].cluster; - } - if(offset>=size) - return E2BIG; - /* terminating null */ - *(rec+offset++)=0; - *offs=offset; + offset += coffs; + if (rl[i].cluster) + cluster = rl[i].cluster; + } + if (offset >= size) + return -E2BIG; + /* Terminating null. */ + *(rec + offset++) = 0; + *offs = offset; return 0; } -static void -count_runs(ntfs_attribute *attr,char *buf) +static void count_runs(ntfs_attribute *attr, char *buf) { - ntfs_u32 first,count,last,i; - first=0; - for(i=0,count=0;i<attr->d.r.len;i++) - count+=attr->d.r.runlist[i].len; - last=first+count-1; - - NTFS_PUTU64(buf+0x10,first); - NTFS_PUTU64(buf+0x18,last); + ntfs_u32 first, count, last, i; + + first = 0; + for (i = 0, count = 0; i < attr->d.r.len; i++) + count += attr->d.r.runlist[i].len; + last = first + count - 1; + NTFS_PUTU64(buf + 0x10, first); + NTFS_PUTU64(buf + 0x18, last); } -static int -layout_attr(ntfs_attribute* attr,char*buf, int size,int *psize) +/** + * layout_attr - convert in memory attribute to on disk attribute record + * @attr: in memory attribute to convert + * @buf: destination buffer for on disk attribute record + * @size: size of the destination buffer + * @psize: size of converted on disk attribute record (out variable) + * + * layout_attr takes the attribute @attr and converts it into the appropriate + * on disk structure, writing it into @buf (up to @size bytes are written). + * On return, @psize contains the actual size of the on disk attribute written + * into @buf. + */ +static int layout_attr(ntfs_attribute* attr, char *buf, int size, int *psize) { - int asize,error; - if(size<10)return E2BIG; - NTFS_PUTU32(buf,attr->type); - /* fill in length later */ - NTFS_PUTU8(buf+8,attr->resident ? 0:1); - NTFS_PUTU8(buf+9,attr->namelen); - /* fill in offset to name later */ - NTFS_PUTU16(buf+0xA,0); - NTFS_PUTU16(buf+0xC,attr->compressed); - /* FIXME: assign attribute ID??? */ - NTFS_PUTU16(buf+0xE,attr->attrno); - if(attr->resident){ - if(size<attr->size+0x18+attr->namelen)return E2BIG; - asize=0x18; - NTFS_PUTU32(buf+0x10,attr->size); - NTFS_PUTU16(buf+0x16,attr->indexed); - if(attr->name){ - ntfs_memcpy(buf+asize,attr->name,2*attr->namelen); - NTFS_PUTU16(buf+0xA,asize); - asize+=2*attr->namelen; - asize=(asize+7) & ~7; - } - NTFS_PUTU16(buf+0x14,asize); - ntfs_memcpy(buf+asize,attr->d.data,attr->size); - asize+=attr->size; - }else{ + int asize, error; + if (size < 10) + return -E2BIG; + NTFS_PUTU32(buf, attr->type); + /* Fill in length later. */ + NTFS_PUTU8(buf + 8, attr->resident ? 0 : 1); + NTFS_PUTU8(buf + 9, attr->namelen); + /* Fill in offset to name later. */ + NTFS_PUTU16(buf + 0xA, 0); + NTFS_PUTU16(buf + 0xC, attr->compressed); + /* Assign attribute instance. */ + NTFS_PUTU16(buf + 0xE, attr->attrno); + if (attr->resident) { + if (size < attr->size + 0x18 + attr->namelen) + return -E2BIG; + asize = 0x18; + NTFS_PUTU32(buf + 0x10, attr->size); + NTFS_PUTU16(buf + 0x16, attr->indexed); + if (attr->name) { + ntfs_memcpy(buf + asize, attr->name, 2 * attr->namelen); + NTFS_PUTU16(buf + 0xA, asize); + asize += 2 * attr->namelen; + asize = (asize + 7) & ~7; + } + NTFS_PUTU16(buf + 0x14, asize); + ntfs_memcpy(buf + asize, attr->d.data, attr->size); + asize += attr->size; + } else { /* FIXME: fragments */ - count_runs(attr,buf); - /* offset to data is added later */ - NTFS_PUTU16(buf+0x22,attr->cengine); - NTFS_PUTU32(buf+0x24,0); - NTFS_PUTU64(buf+0x28,attr->allocated); - NTFS_PUTU64(buf+0x30,attr->size); - NTFS_PUTU64(buf+0x38,attr->initialized); - if(attr->compressed){ - NTFS_PUTU64(buf+0x40,attr->compsize); - asize=0x48; - }else - asize=0x40; - if(attr->name){ - NTFS_PUTU16(buf+0xA,asize); - ntfs_memcpy(buf+asize,attr->name,2*attr->namelen); - asize+=2*attr->namelen; - /* SRD: you whaaa? - asize=(asize+7) & ~7;*/ - } - /* asize points at the beginning of the data */ - NTFS_PUTU16(buf+0x20,asize); - error=layout_runs(attr,buf,&asize,size); - /* now asize pointes at the end of the data */ - if(error) + count_runs(attr, buf); + /* Offset to data is added later. */ + NTFS_PUTU16(buf + 0x22, attr->cengine); + NTFS_PUTU32(buf + 0x24, 0); + NTFS_PUTU64(buf + 0x28, attr->allocated); + NTFS_PUTU64(buf + 0x30, attr->size); + NTFS_PUTU64(buf + 0x38, attr->initialized); + if (attr->compressed) { + NTFS_PUTU64(buf + 0x40, attr->compsize); + asize = 0x48; + } else + asize = 0x40; + if (attr->name) { + NTFS_PUTU16(buf + 0xA, asize); + ntfs_memcpy(buf + asize, attr->name, 2 * attr->namelen); + asize += 2 * attr->namelen; + /* SRD: you whaaa? - AIA: Align to next 8 byte boundary + * as required by NTFS design and implementation. */ + asize = (asize + 7) & ~7; + } + /* asize points at the beginning of the data. */ + NTFS_PUTU16(buf + 0x20, asize); + error = layout_runs(attr, buf, &asize, size); + /* Now asize points at the end of the data. */ + if (error) return error; } - asize=(asize+7) & ~7; - NTFS_PUTU32(buf+4,asize); - *psize=asize; + asize = (asize + 7) & ~7; + NTFS_PUTU32(buf + 4, asize); + *psize = asize; return 0; } - - -/* Try to layout ino into store. Return 0 on success, - E2BIG if it does not fit, - ENOMEM if memory allocation problem, - EOPNOTSUP if beyond our capabilities -*/ -int -layout_inode(ntfs_inode *ino,ntfs_disk_inode *store) +/** + * layout_inode - convert an in memory inode into on disk mft record(s) + * @ino: in memory inode to convert + * @store: on disk inode, contain buffers for the on disk mft record(s) + * + * layout_inode takes the in memory inode @ino, converts it into a (sequence of) + * mft record(s) and writes them to the appropriate buffers in the @store. + * + * Return 0 on success, + * the required mft record count (>0) if the inode does not fit, + * -ENOMEM if memory allocation problem or + * -EOPNOTSUP if beyond our capabilities. + */ +int layout_inode(ntfs_inode *ino, ntfs_disk_inode *store) { - int offset,i; + int offset, i; ntfs_attribute *attr; unsigned char *rec; - int size,psize; + int size, psize; int error; - if(ino->record_count>1) - { + if (ino->record_count > 1) { ntfs_error("layout_inode: attribute lists not supported\n"); - return EOPNOTSUPP; + return -EOPNOTSUPP; } - error=allocate_store(ino->vol,store,1); - if(error) + error = allocate_store(ino->vol, store, 1); + if (error) return error; - rec=store->records[0].record; - size=ino->vol->mft_recordsize; - store->records[0].recno=ino->records[0]; - /* copy header */ - offset=NTFS_GETU16(ino->attr+0x14); - ntfs_memcpy(rec,ino->attr,offset); - for(i=0;i<ino->attr_count;i++){ - attr=ino->attrs+i; - error=layout_attr(attr,rec+offset,size-offset,&psize); - if(error)return error; - offset+=psize; -#if 0 - /* copy attribute header */ - ntfs_memcpy(rec+offset,attr->header, - min(sizeof(attr->header),size-offset)); /* consider overrun */ - if(attr->namelen) - /* named attributes are added later */ - return EOPNOTSUPP; - /* FIXME: assign attribute ID??? */ - if(attr->resident){ - asize=attr->size; - aoffset=NTFS_GETU16(rec+offset+0x14); - if(offset+aoffset+asize>size) - return E2BIG; - ntfs_memcpy(rec+offset+aoffset,attr->d.data,asize); - next=offset+aoffset+asize; - }else{ - count_runs(attr,rec+offset); - aoffset=NTFS_GETU16(rec+offset+0x20); - next=offset+aoffset; - error=layout_runs(attr,rec,&next,size); - if(error) - return error; - } - /* SRD: umm.. - next=(next+7) & ~7; */ - /* is this setting the length? if so maybe we could get - away with rounding up so long as we set the length first.. - ..except, is the length the only way to get to the next attr? - */ - NTFS_PUTU16(rec+offset+4,next-offset); - offset=next; -#endif + rec = store->records[0].record; + size = ino->vol->mft_recordsize; + store->records[0].recno = ino->records[0]; + /* Copy header. */ + offset = NTFS_GETU16(ino->attr + 0x14); + ntfs_memcpy(rec, ino->attr, offset); + for (i = 0; i < ino->attr_count; i++) { + attr = ino->attrs + i; + error = layout_attr(attr, rec + offset, size - offset, &psize); + if (error) + return error; + offset += psize; } - /* terminating attribute */ - if(offset+8<size){ - NTFS_PUTU32(rec+offset,0xFFFFFFFF); - offset+=4; - NTFS_PUTU32(rec+offset,0); - offset+=4; - }else - return E2BIG; - NTFS_PUTU32(rec+0x18,offset); + /* Terminating attribute. */ + if (offset + 8 < size) { + NTFS_PUTU32(rec + offset, 0xFFFFFFFF); + offset += 4; + NTFS_PUTU32(rec + offset, 0); + offset += 4; + } else + return -E2BIG; + NTFS_PUTU32(rec + 0x18, offset); return 0; } - + +/* + * FIXME: ntfs_update_inode() calls layout_inode() to create the mft record on + * disk structure corresponding to the inode @ino. After that, ntfs_write_attr() + * is called to write out the created mft record to disk. + * We shouldn't need to re-layout every single time we are updating an mft + * record. No wonder the ntfs driver is slow like hell. (AIA) + */ int ntfs_update_inode(ntfs_inode *ino) { int error; @@ -903,218 +957,217 @@ ntfs_io io; int i; - store.count=store.size=0; - store.records=0; - error=layout_inode(ino,&store); - if(error==E2BIG){ + store.count = store.size = 0; + store.records = 0; + error = layout_inode(ino, &store); + if (error == -E2BIG) { error = ntfs_split_indexroot(ino); - if(!error) - error = layout_inode(ino,&store); + if (!error) + error = layout_inode(ino, &store); } - if(error == E2BIG){ + if (error == -E2BIG) { error = ntfs_attr_allnonresident(ino); - if(!error) - error = layout_inode(ino,&store); + if (!error) + error = layout_inode(ino, &store); } - if(error == E2BIG){ - /* should try: - introduce extension records - */ - ntfs_error("cannot handle saving inode %x\n",ino->i_number); + if (error == -E2BIG) { + /* FIXME: should try: introduce extension records */ + ntfs_error("cannot handle saving inode %x\n", ino->i_number); deallocate_store(&store); - return EOPNOTSUPP; + return -EOPNOTSUPP; } - if(error){ + if (error) { deallocate_store(&store); return error; } - io.fn_get=ntfs_get; - io.fn_put=0; - for(i=0;i<store.count;i++){ - ntfs_insert_fixups(store.records[i].record,ino->vol->blocksize); - io.param=store.records[i].record; - io.size=ino->vol->mft_recordsize; - /* FIXME: is this the right way? */ - error=ntfs_write_attr( - ino->vol->mft_ino,ino->vol->at_data,0, - store.records[i].recno*ino->vol->mft_recordsize,&io); - if(error || io.size!=ino->vol->mft_recordsize){ - /* big trouble, partially written file */ - ntfs_error("Please unmount: write error in inode %x\n",ino->i_number); + io.fn_get = ntfs_get; + io.fn_put = 0; + for (i = 0; i < store.count; i++) { + ntfs_insert_fixups(store.records[i].record, + ino->vol->blocksize); + io.param = store.records[i].record; + io.size = ino->vol->mft_recordsize; + /* FIXME: Is this the right way? */ + error = ntfs_write_attr(ino->vol->mft_ino, ino->vol->at_data, + 0, store.records[i].recno * + ino->vol->mft_recordsize, &io); + if (error || io.size != ino->vol->mft_recordsize) { + /* Big trouble, partially written file. */ + ntfs_error("Please unmount: Write error in inode %x\n", + ino->i_number); deallocate_store(&store); - return error?error:EIO; + return error ? error : -EIO; } } return 0; } - void ntfs_decompress(unsigned char *dest, unsigned char *src, ntfs_size_t l) { - int head,comp; - int copied=0; + int head, comp; + int copied = 0; unsigned char *stop; int bits; - int tag=0; + int tag = 0; int clear_pos; - while(1) - { + + while (1) { head = NTFS_GETU16(src) & 0xFFF; - /* high bit indicates that compression was performed */ + /* High bit indicates that compression was performed. */ comp = NTFS_GETU16(src) & 0x8000; src += 2; - stop = src+head; + stop = src + head; bits = 0; - clear_pos=0; - if(head==0) - /* block is not used */ + clear_pos = 0; + if (head == 0) + /* Block is not used. */ return;/* FIXME: copied */ - if(!comp) /* uncompressible */ - { - ntfs_memcpy(dest,src,0x1000); - dest+=0x1000; - copied+=0x1000; - src+=0x1000; - if(l==copied) + if (!comp) { /* uncompressible */ + ntfs_memcpy(dest, src, 0x1000); + dest += 0x1000; + copied += 0x1000; + src += 0x1000; + if (l == copied) return; continue; } - while(src<=stop) - { - if(clear_pos>4096) - { + while (src <= stop) { + if (clear_pos > 4096) { ntfs_error("Error 1 in decompress\n"); return; } - if(!bits){ - tag=NTFS_GETU8(src); - bits=8; + if (!bits) { + tag = NTFS_GETU8(src); + bits = 8; src++; - if(src>stop) + if (src > stop) break; } - if(tag & 1){ - int i,len,delta,code,lmask,dshift; + if (tag & 1) { + int i, len, delta, code, lmask, dshift; code = NTFS_GETU16(src); - src+=2; - if(!clear_pos) - { + src += 2; + if (!clear_pos) { ntfs_error("Error 2 in decompress\n"); return; } - for(i=clear_pos-1,lmask=0xFFF,dshift=12;i>=0x10;i>>=1) - { + for (i = clear_pos - 1, lmask = 0xFFF, + dshift = 12; i >= 0x10; i >>= 1) { lmask >>= 1; dshift--; } delta = code >> dshift; len = (code & lmask) + 3; - for(i=0; i<len; i++) - { - dest[clear_pos]=dest[clear_pos-delta-1]; + for (i = 0; i < len; i++) { + dest[clear_pos] = dest[clear_pos - + delta - 1]; clear_pos++; copied++; - if(copied==l) + if (copied==l) return; } - }else{ - dest[clear_pos++]=NTFS_GETU8(src); + } else { + dest[clear_pos++] = NTFS_GETU8(src); src++; copied++; - if(copied==l) + if (copied==l) return; } - tag>>=1; + tag >>= 1; bits--; } - dest+=clear_pos; + dest += clear_pos; } } -/* Caveat: No range checking in either ntfs_set_bit or ntfs_clear_bit */ -void -ntfs_set_bit (unsigned char *byte, int bit) +/* Caveat: No range checking in either ntfs_set_bit or ntfs_clear_bit. */ +void ntfs_set_bit(unsigned char *byte, int bit) { byte += (bit >> 3); bit &= 7; *byte |= (1 << bit); } -void -ntfs_clear_bit (unsigned char *byte, int bit) +void ntfs_clear_bit(unsigned char *byte, int bit) { byte += (bit >> 3); bit &= 7; *byte &= ~(1 << bit); } -/* We have to skip the 16 metafiles and the 8 reserved entries */ -static int -ntfs_new_inode (ntfs_volume* vol,int* result) +/** + * ntfs_new_inode - allocate an mft record + * @vol: volume to allocate an mft record on + * @result: the mft record number allocated + * + * Allocate a new mft record on disk by finding the first free mft record + * and allocating it in the mft bitmap. + * Return 0 on success or -ERRNO on error. + * + * TODO(AIA): Implement mft bitmap caching. Replace function by race safe one. + */ +static int ntfs_new_inode(ntfs_volume* vol, int* result) { - int byte,error; + int byte, error; int bit; - int size,length; + int size, length; unsigned char value; ntfs_u8 *buffer; ntfs_io io; ntfs_attribute *data; - buffer=ntfs_malloc(2048); - if(!buffer)return ENOMEM; - io.fn_put=ntfs_put; - io.fn_get=ntfs_get; - io.param=buffer; - /* FIXME: bitmaps larger than 2048 bytes */ - io.size=2048; - error=ntfs_read_attr(vol->mft_ino,vol->at_bitmap,0,0,&io); - if(error){ + buffer = ntfs_malloc(2048); + if (!buffer) + return -ENOMEM; + io.fn_put = ntfs_put; + io.fn_get = ntfs_get; + io.param = buffer; + /* FIXME: Bitmaps larger than 2048 bytes. */ + io.size = 2048; + error = ntfs_read_attr(vol->mft_ino, vol->at_bitmap, 0, 0, &io); + if (error) { ntfs_free(buffer); return error; } - size=io.size; - data=ntfs_find_attr(vol->mft_ino,vol->at_data,0); - length=data->size/vol->mft_recordsize; - - /* SRD: start at byte 0: bits for system files _are_ already set in bitmap */ - for (byte = 0; 8*byte < length; byte++) - { + size = io.size; + data = ntfs_find_attr(vol->mft_ino, vol->at_data, 0); + length = data->size / vol->mft_recordsize; + /* SRD: Start at byte 0: bits for system files _are_ already set in + * bitmap. AIA: This includes the reserved entries as well. */ + for (byte = 0; 8 * byte < length; byte++) { value = buffer[byte]; - if(value==0xFF) + if (value == 0xFF) continue; - for (bit = 0; (bit < 8) && (8*byte+bit<length); - bit++, value >>= 1) - { - if (!(value & 1)){ - *result=byte*8+bit; + for (bit = 0; (bit < 8) && (8 * byte + bit < length); + bit++, value >>= 1) { + if (!(value & 1)) { + *result = byte * 8 + bit; return 0; } } } - /* There is no free space. We must first extend the MFT. */ - return ENOSPC; + /* There is no free space. We must first extend the MFT. */ + return -ENOSPC; } -static int -add_mft_header (ntfs_inode *ino) +static int add_mft_header(ntfs_inode *ino) { - unsigned char* mft; - ntfs_volume *vol=ino->vol; - mft=ino->attr; + unsigned char *mft; + ntfs_volume *vol = ino->vol; + mft = ino->attr; ntfs_bzero(mft, vol->mft_recordsize); - ntfs_fill_mft_header(mft,vol->mft_recordsize,vol->blocksize, - ino->sequence_number); + ntfs_fill_mft_header(mft, vol->mft_recordsize, vol->blocksize, + ino->sequence_number); return 0; } -/* We need 0x48 bytes in total */ -static int -add_standard_information (ntfs_inode *ino) +/* We need 0x48 bytes in total. */ +static int add_standard_information(ntfs_inode *ino) { ntfs_time64_t now; char data[0x30]; - char *position=data; + char *position = data; int error; ntfs_attribute *si; @@ -1123,66 +1176,63 @@ NTFS_PUTU64(position + 0x08, now); /* Last modification */ NTFS_PUTU64(position + 0x10, now); /* Last mod for MFT */ NTFS_PUTU64(position + 0x18, now); /* Last access */ - - NTFS_PUTU64(position + 0x20, 0x00); /* MSDOS file perms */ - NTFS_PUTU64(position + 0x28, 0); /* unknown */ - error=ntfs_create_attr(ino,ino->vol->at_standard_information,0, - data,sizeof(data),&si); - + NTFS_PUTU64(position + 0x20, 0); /* MSDOS file perms */ + NTFS_PUTU64(position + 0x28, 0); /* unknown */ + error = ntfs_create_attr(ino, ino->vol->at_standard_information, 0, + data, sizeof(data), &si); return error; } -static int -add_filename (ntfs_inode* ino, ntfs_inode* dir, - const unsigned char *filename, int length, ntfs_u32 flags) -{ - unsigned char *position; - unsigned int size; - ntfs_time64_t now; - int count; - int error; +/* FIXME: Need to pass in the size of the file (Data size) as well as the + * allocated size for file data on disk (Allocated size). (AIA) */ +static int add_filename(ntfs_inode* ino, ntfs_inode* dir, + const unsigned char *filename, int length, + ntfs_u32 flags) +{ + unsigned char *position; + unsigned int size; + ntfs_time64_t now; + int count, error; unsigned char* data; ntfs_attribute *fn; - /* work out the size */ + /* Work out the size. */ size = 0x42 + 2 * length; data = ntfs_malloc(size); - if( !data ) - return ENOMEM; - ntfs_bzero(data,size); - - /* search for a position */ + if (!data) + return -ENOMEM; + ntfs_bzero(data, size); + /* Search for a position. */ position = data; - - NTFS_PUTINUM(position, dir); /* Inode num of dir */ - + NTFS_PUTINUM(position, dir); /* Inode num of dir */ now = ntfs_now(); NTFS_PUTU64(position + 0x08, now); /* File creation */ NTFS_PUTU64(position + 0x10, now); /* Last modification */ NTFS_PUTU64(position + 0x18, now); /* Last mod for MFT */ NTFS_PUTU64(position + 0x20, now); /* Last access */ - - /* Don't know */ - NTFS_PUTU32(position+0x38, flags); - - NTFS_PUTU8(position + 0x40, length); /* Filename length */ - NTFS_PUTU8(position + 0x41, 0x0); /* only long name */ - + /*NTFS_PUTU64(position + 0x28, 0);*/ /* Allocated size */ + /*NTFS_PUTU64(position + 0x30, 0);*/ /* Data size */ + NTFS_PUTU32(position + 0x38, flags); /* File flags */ + /*NTFS_PUTU32(position + 0x3c, 0);*/ /* We don't use these + * features yet. */ + NTFS_PUTU8(position + 0x40, length); /* Filename length */ + NTFS_PUTU8(position + 0x41, 0); /* Only long name */ + /* FIXME: This is madness. We are defining the POSIX namespace + * for the filename here which can mean that the file will be + * invisible when in Windows NT/2k! )-: (AIA) */ position += 0x42; - for (count = 0; count < length; count++) - { + for (count = 0; count < length; count++) { NTFS_PUTU16(position + 2 * count, filename[count]); } - - error=ntfs_create_attr(ino,ino->vol->at_file_name,0,data,size,&fn); - if(!error) - error=ntfs_dir_add(dir,ino,fn); + error = ntfs_create_attr(ino, ino->vol->at_file_name, 0, data, size, + &fn); + if (!error) + error = ntfs_dir_add(dir, ino, fn); ntfs_free(data); return error; } -int -add_security (ntfs_inode* ino, ntfs_inode* dir) +int add_security(ntfs_inode* ino, ntfs_inode* dir) { int error; char *buf; @@ -1191,133 +1241,138 @@ ntfs_io io; ntfs_attribute *se; - attr=ntfs_find_attr(dir,ino->vol->at_security_descriptor,0); - if(!attr) - return EOPNOTSUPP; /* need security in directory */ + attr = ntfs_find_attr(dir, ino->vol->at_security_descriptor, 0); + if (!attr) + return -EOPNOTSUPP; /* Need security in directory. */ size = attr->size; - if(size>512) - return EOPNOTSUPP; - buf=ntfs_malloc(size); - if(!buf) - return ENOMEM; - io.fn_get=ntfs_get; - io.fn_put=ntfs_put; - io.param=buf; - io.size=size; - error=ntfs_read_attr(dir,ino->vol->at_security_descriptor,0,0,&io); - if(!error && io.size!=size)ntfs_error("wrong size in add_security"); - if(error){ + if (size > 512) + return -EOPNOTSUPP; + buf = ntfs_malloc(size); + if (!buf) + return -ENOMEM; + io.fn_get = ntfs_get; + io.fn_put = ntfs_put; + io.param = buf; + io.size = size; + error = ntfs_read_attr(dir, ino->vol->at_security_descriptor, 0, 0,&io); + if (!error && io.size != size) + ntfs_error("wrong size in add_security"); + if (error) { ntfs_free(buf); return error; } - /* FIXME: consider ACL inheritance */ - error=ntfs_create_attr(ino,ino->vol->at_security_descriptor, - 0,buf,size,&se); + /* FIXME: Consider ACL inheritance. */ + error = ntfs_create_attr(ino, ino->vol->at_security_descriptor, + 0, buf, size, &se); ntfs_free(buf); return error; } -static int -add_data (ntfs_inode* ino, unsigned char *data, int length) +static int add_data(ntfs_inode* ino, unsigned char *data, int length) { int error; ntfs_attribute *da; - error=ntfs_create_attr(ino,ino->vol->at_data,0,data,length,&da); + + error = ntfs_create_attr(ino, ino->vol->at_data, 0, data, length, &da); return error; } -/* We _could_ use 'dir' to help optimise inode allocation */ -int ntfs_alloc_inode (ntfs_inode *dir, ntfs_inode *result, - const char *filename, int namelen, ntfs_u32 flags) +/* We _could_ use 'dir' to help optimise inode allocation. */ +int ntfs_alloc_inode(ntfs_inode *dir, ntfs_inode *result, const char *filename, + int namelen, ntfs_u32 flags) { ntfs_io io; int error; ntfs_u8 buffer[2]; - ntfs_volume* vol=dir->vol; - int byte,bit; + ntfs_volume *vol = dir->vol; + int byte, bit; - error=ntfs_new_inode (vol,&(result->i_number)); - if(error==ENOSPC){ - error=ntfs_extend_mft(vol); - if(error)return error; - error=ntfs_new_inode(vol,&(result->i_number)); + error = ntfs_new_inode(vol, &(result->i_number)); + if (error == -ENOSPC) { + error = ntfs_extend_mft(vol); + if (error) + return error; + error = ntfs_new_inode(vol, &(result->i_number)); } - if(error){ - ntfs_error ("ntfs_get_empty_inode: no free inodes\n"); + if (error) { + ntfs_error("ntfs_get_empty_inode: no free inodes\n"); return error; } - byte=result->i_number/8; - bit=result->i_number & 7; - + byte = result->i_number / 8; + bit = result->i_number & 7; io.fn_put = ntfs_put; io.fn_get = ntfs_get; io.param = buffer; - io.size=1; - /* set a single bit */ - error=ntfs_read_attr(vol->mft_ino,vol->at_bitmap,0,byte,&io); - if(error)return error; - if(io.size!=1) - return EIO; - ntfs_set_bit (buffer, bit); + io.size = 1; + /* Set a single bit. */ + error = ntfs_read_attr(vol->mft_ino, vol->at_bitmap, 0, byte, &io); + if (error) + return error; + if (io.size != 1) + return -EIO; + ntfs_set_bit(buffer, bit); io.param = buffer; io.size = 1; - error = ntfs_write_attr (vol->mft_ino, vol->at_bitmap, 0, byte, &io); - if(error)return error; + error = ntfs_write_attr(vol->mft_ino, vol->at_bitmap, 0, byte, &io); + if (error) + return error; if (io.size != 1) - return EIO; - /*FIXME: Should change MFT on disk - error=ntfs_update_inode(vol->mft_ino); - if(error)return error; - */ - /* get the sequence number */ + return -EIO; + /* FIXME: Should change $Mft on disk. + * error = ntfs_update_inode(vol->mft_ino); + * if (error) + * return error; + * FIXME: And don't forget $MftMirr, though this probably belongs + * in ntfs_update_inode() (or even deeper). (AIA) */ + /* Get the sequence number. */ io.param = buffer; io.size = 2; error = ntfs_read_attr(vol->mft_ino, vol->at_data, 0, - result->i_number*vol->mft_recordsize+0x10,&io); - if(error) + result->i_number * vol->mft_recordsize + 0x10, + &io); + if (error) return error; - result->sequence_number=NTFS_GETU16(buffer)+1; - result->vol=vol; - result->attr=ntfs_malloc(vol->mft_recordsize); - if( !result->attr ) - return ENOMEM; - result->attr_count=0; - result->attrs=0; - result->record_count=1; - result->records=ntfs_malloc(8*sizeof(int)); - if( !result->records ) { - ntfs_free( result->attr ); + /* Increment the sequence number skipping zero. */ + if (NTFS_GETU16(buffer) == 0xffff) + result->sequence_number = 1; + else + result->sequence_number = NTFS_GETU16(buffer) + 1; + result->vol = vol; + result->attr = ntfs_malloc(vol->mft_recordsize); + if (!result->attr) + return -ENOMEM; + result->attr_count = 0; + result->attrs = 0; + result->record_count = 1; + result->records = ntfs_malloc(8 * sizeof(int)); + if (!result->records) { + ntfs_free(result->attr); result->attr = 0; - return ENOMEM; + return -ENOMEM; } - result->records[0]=result->i_number; - error=add_mft_header(result); - if(error) + result->records[0] = result->i_number; + error = add_mft_header(result); + if (error) + return error; + error = add_standard_information(result); + if (error) return error; - error=add_standard_information(result); - if(error) + error = add_filename(result, dir, filename, namelen, flags); + if (error) return error; - error=add_filename(result,dir,filename,namelen,flags); - if(error) + error = add_security(result, dir); + if (error) return error; - error=add_security(result,dir); - /*FIXME: check error */ return 0; } -int -ntfs_alloc_file(ntfs_inode *dir, ntfs_inode *result, char *filename, - int namelen) +int ntfs_alloc_file(ntfs_inode *dir, ntfs_inode *result, char *filename, + int namelen) { - int error = ntfs_alloc_inode(dir,result,filename,namelen,0); - if(error) + int error = ntfs_alloc_inode(dir, result, filename, namelen, 0); + if (error) return error; - error = add_data(result,0,0); + error = add_data(result, 0, 0); return error; } -/* - * Local variables: - * c-file-style: "linux" - * End: - */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ntfs/inode.h linux.ac/fs/ntfs/inode.h --- linux.vanilla/fs/ntfs/inode.h Mon Apr 12 18:05:58 1999 +++ linux.ac/fs/ntfs/inode.h Tue Apr 3 17:55:13 2001 @@ -1,30 +1,43 @@ -/* - * inode.h - * Header file for inode.c +/* inode.h - Header file for inode.c * * Copyright (C) 1997 Régis Duchesne * Copyright (C) 1998 Martin von Löwis */ ntfs_attribute *ntfs_find_attr(ntfs_inode *ino, int type, char *name); + int ntfs_read_attr(ntfs_inode *ino, int type, char *name, int offset, ntfs_io *buf); + int ntfs_write_attr(ntfs_inode *ino, int type, char *name, int offset, ntfs_io *buf); -int ntfs_init_inode(ntfs_inode *ino,ntfs_volume *vol,int inum); + +int ntfs_init_inode(ntfs_inode *ino, ntfs_volume *vol, int inum); + void ntfs_clear_inode(ntfs_inode *ino); -int ntfs_check_mft_record(ntfs_volume *vol,char *record); -int ntfs_alloc_inode (ntfs_inode *dir, ntfs_inode *result, - const char *filename, int namelen,ntfs_u32); -int ntfs_alloc_file (ntfs_inode *dir, ntfs_inode *result, - char *filename, int namelen); + +int ntfs_check_mft_record(ntfs_volume *vol, char *record); + +int ntfs_alloc_inode(ntfs_inode *dir, ntfs_inode *result, const char *filename, + int namelen, ntfs_u32); + +int ntfs_alloc_file(ntfs_inode *dir, ntfs_inode *result, char *filename, + int namelen); + int ntfs_update_inode(ntfs_inode *ino); + int ntfs_vcn_to_lcn(ntfs_inode *ino, int vcn); + int ntfs_readwrite_attr(ntfs_inode *ino, ntfs_attribute *attr, int offset, ntfs_io *dest); + int ntfs_allocate_attr_number(ntfs_inode *ino, int *result); -int ntfs_decompress_run(unsigned char **data, int *length, ntfs_cluster_t *cluster, - int *ctype); + +int ntfs_decompress_run(unsigned char **data, int *length, + ntfs_cluster_t *cluster, int *ctype); + void ntfs_decompress(unsigned char *dest, unsigned char *src, ntfs_size_t l); -void ntfs_fill_mft_header( ntfs_u8 *mft, int recordsize, int blocksize, - int sequence_number ); + +void ntfs_fill_mft_header(ntfs_u8 *mft, int recordsize, int blocksize, + int sequence_number); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ntfs/macros.h linux.ac/fs/ntfs/macros.h --- linux.vanilla/fs/ntfs/macros.h Sat Jan 2 18:24:46 1999 +++ linux.ac/fs/ntfs/macros.h Tue Apr 3 17:55:13 2001 @@ -1,5 +1,4 @@ -/* - * macros.h +/* macros.h * * Copyright (C) 1995 Martin von Löwis * Copyright (C) 1996 Régis Duchesne @@ -7,23 +6,10 @@ #define NTFS_FD(vol) ((vol)->u.fd) -/* Linux */ -#ifdef NTFS_IN_LINUX_KERNEL #define NTFS_SB(vol) ((struct super_block*)(vol)->sb) #define NTFS_SB2VOL(sb) (&(sb)->u.ntfs_sb) #define NTFS_INO2VOL(ino) (&((ino)->i_sb->u.ntfs_sb)) #define NTFS_LINO2NINO(ino) (&((ino)->u.ntfs_i)) -#else -#define NTFS_SB(vol) ((struct super_block*)(vol)->u.sb) -#define NTFS_SB2VOL(sb) ((ntfs_volume*)(sb)->u.generic_sbp) -#define NTFS_INO2VOL(ino) ((ntfs_volume*)((ino)->i_sb->u.generic_sbp)) -#define NTFS_LINO2NINO(ino) ((ntfs_inode*)((ino)->u.generic_ip)) -#endif - -/* BSD */ -#define NTFS_MNT(vol) ((struct mount*)(vol)->u.sb) -#define NTFS_MNT2VOL(sb) ((ntfs_volume*)(sb)->mnt_data) -#define NTFS_V2INO(ino) ((ntfs_inode*)((ino)->v_data)) /* Classical min and max macros still missing in standard headers... */ #ifndef min @@ -31,9 +17,9 @@ #define max(a,b) ((a) >= (b) ? (a) : (b)) #endif -#define IS_MAGIC(a,b) (*(int*)(a)==*(int*)(b)) +#define IS_MAGIC(a,b) (*(int*)(a) == *(int*)(b)) #define IS_MFT_RECORD(a) IS_MAGIC((a),"FILE") -#define IS_NTFS_VOLUME(a) IS_MAGIC((a)+3,"NTFS") +#define IS_NTFS_VOLUME(a) IS_MAGIC((a) + 3,"NTFS") #define IS_INDEX_RECORD(a) IS_MAGIC((a),"INDX") /* 'NTFS' in little endian */ @@ -46,8 +32,3 @@ #define NTFS_AFLAG_COMPRESSED 0x800 #define NTFS_AFLAG_DIR 0x10000000 -/* - * Local variables: - * c-file-style: "linux" - * End: - */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ntfs/ntfsendian.h linux.ac/fs/ntfs/ntfsendian.h --- linux.vanilla/fs/ntfs/ntfsendian.h Mon Dec 11 21:26:39 2000 +++ linux.ac/fs/ntfs/ntfsendian.h Tue Apr 3 19:17:53 2001 @@ -1,17 +1,13 @@ -/* - * ntfsendian.h +/* ntfsendian.h * * Copyright (C) 1998, 1999 Martin von Löwis * Copyright (C) 1998 Joseph Malicki * Copyright (C) 1999 Werner Seiler + * Copyright (C) 2001 Anton Altaparmakov (AIA) */ -#ifdef __linux__ -/* This defines __cpu_to_le16 on Linux 2.1 and higher. */ #include <asm/byteorder.h> -#endif -#ifdef __cpu_to_le16 #define CPU_TO_LE16(a) __cpu_to_le16(a) #define CPU_TO_LE32(a) __cpu_to_le32(a) #define CPU_TO_LE64(a) __cpu_to_le64(a) @@ -20,68 +16,44 @@ #define LE32_TO_CPU(a) __cpu_to_le32(a) #define LE64_TO_CPU(a) __cpu_to_le64(a) -#else - -#ifdef __LITTLE_ENDIAN - -#define CPU_TO_LE16(a) (a) -#define CPU_TO_LE32(a) (a) -#define CPU_TO_LE64(a) (a) -#define LE16_TO_CPU(a) (a) -#define LE32_TO_CPU(a) (a) -#define LE64_TO_CPU(a) (a) - -#else - -/* Routines for big-endian machines */ -#ifdef __BIG_ENDIAN - -/* We hope its big-endian, not PDP-endian :) */ -#define CPU_TO_LE16(a) ((((a)&0xFF) << 8)|((a) >> 8)) -#define CPU_TO_LE32(a) ((((a) & 0xFF) << 24) | (((a) & 0xFF00) << 8) | \ - (((a) & 0xFF0000) >> 8) | ((a) >> 24)) -#define CPU_TO_LE64(a) ((CPU_TO_LE32(a)<<32)|CPU_TO_LE32((a)>>32) - -#define LE16_TO_CPU(a) CPU_TO_LE16(a) -#define LE32_TO_CPU(a) CPU_TO_LE32(a) -#define LE64_TO_CPU(a) CPU_TO_LE64(a) - -#else - -#error Please define Endianness - __BIG_ENDIAN or __LITTLE_ENDIAN or add OS-specific macros - -#endif /* __BIG_ENDIAN */ -#endif /* __LITTLE_ENDIAN */ -#endif /* __cpu_to_le16 */ - #define NTFS_GETU8(p) (*(ntfs_u8*)(p)) #define NTFS_GETU16(p) ((ntfs_u16)LE16_TO_CPU(*(ntfs_u16*)(p))) -#define NTFS_GETU24(p) ((ntfs_u32)NTFS_GETU16(p) | ((ntfs_u32)NTFS_GETU8(((char*)(p))+2)<<16)) +#define NTFS_GETU24(p) ((ntfs_u32)NTFS_GETU16(p) | \ + ((ntfs_u32)NTFS_GETU8(((char*)(p)) + 2) << 16)) #define NTFS_GETU32(p) ((ntfs_u32)LE32_TO_CPU(*(ntfs_u32*)(p))) -#define NTFS_GETU40(p) ((ntfs_u64)NTFS_GETU32(p)|(((ntfs_u64)NTFS_GETU8(((char*)(p))+4))<<32)) -#define NTFS_GETU48(p) ((ntfs_u64)NTFS_GETU32(p)|(((ntfs_u64)NTFS_GETU16(((char*)(p))+4))<<32)) -#define NTFS_GETU56(p) ((ntfs_u64)NTFS_GETU32(p)|(((ntfs_u64)NTFS_GETU24(((char*)(p))+4))<<32)) +#define NTFS_GETU40(p) ((ntfs_u64)NTFS_GETU32(p) | \ + (((ntfs_u64)NTFS_GETU8(((char*)(p)) + 4)) << 32)) +#define NTFS_GETU48(p) ((ntfs_u64)NTFS_GETU32(p) | \ + (((ntfs_u64)NTFS_GETU16(((char*)(p)) + 4)) << 32)) +#define NTFS_GETU56(p) ((ntfs_u64)NTFS_GETU32(p) | \ + (((ntfs_u64)NTFS_GETU24(((char*)(p)) + 4)) << 32)) #define NTFS_GETU64(p) ((ntfs_u64)LE64_TO_CPU(*(ntfs_u64*)(p))) /* Macros writing unsigned integers */ -#define NTFS_PUTU8(p,v) ((*(ntfs_u8*)(p))=(v)) -#define NTFS_PUTU16(p,v) ((*(ntfs_u16*)(p))=CPU_TO_LE16(v)) -#define NTFS_PUTU24(p,v) NTFS_PUTU16(p,(v) & 0xFFFF);\ - NTFS_PUTU8(((char*)(p))+2,(v)>>16) -#define NTFS_PUTU32(p,v) ((*(ntfs_u32*)(p))=CPU_TO_LE32(v)) -#define NTFS_PUTU64(p,v) ((*(ntfs_u64*)(p))=CPU_TO_LE64(v)) +#define NTFS_PUTU8(p,v) ((*(ntfs_u8*)(p)) = (v)) +#define NTFS_PUTU16(p,v) ((*(ntfs_u16*)(p)) = CPU_TO_LE16(v)) +#define NTFS_PUTU24(p,v) NTFS_PUTU16(p, (v) & 0xFFFF);\ + NTFS_PUTU8(((char*)(p)) + 2, (v) >> 16) +#define NTFS_PUTU32(p,v) ((*(ntfs_u32*)(p)) = CPU_TO_LE32(v)) +#define NTFS_PUTU64(p,v) ((*(ntfs_u64*)(p)) = CPU_TO_LE64(v)) /* Macros reading signed integers */ #define NTFS_GETS8(p) ((*(ntfs_s8*)(p))) #define NTFS_GETS16(p) ((ntfs_s16)LE16_TO_CPU(*(short*)(p))) -#define NTFS_GETS24(p) (NTFS_GETU24(p) < 0x800000 ? (int)NTFS_GETU24(p) : (int)(NTFS_GETU24(p) - 0x1000000)) +#define NTFS_GETS24(p) (NTFS_GETU24(p) < 0x800000 ? \ + (int)NTFS_GETU24(p) : \ + (int)(NTFS_GETU24(p) - 0x1000000)) #define NTFS_GETS32(p) ((ntfs_s32)LE32_TO_CPU(*(int*)(p))) -#define NTFS_GETS40(p) (((ntfs_s64)NTFS_GETU32(p)) | (((ntfs_s64)NTFS_GETS8(((char*)(p))+4)) << 32)) -#define NTFS_GETS48(p) (((ntfs_s64)NTFS_GETU32(p)) | (((ntfs_s64)NTFS_GETS16(((char*)(p))+4)) << 32)) -#define NTFS_GETS56(p) (((ntfs_s64)NTFS_GETU32(p)) | (((ntfs_s64)NTFS_GETS24(((char*)(p))+4)) << 32)) +#define NTFS_GETS40(p) (((ntfs_s64)NTFS_GETU32(p)) | \ + (((ntfs_s64)NTFS_GETS8(((char*)(p)) + 4)) << 32)) +#define NTFS_GETS48(p) (((ntfs_s64)NTFS_GETU32(p)) | \ + (((ntfs_s64)NTFS_GETS16(((char*)(p)) + 4)) << 32)) +#define NTFS_GETS56(p) (((ntfs_s64)NTFS_GETU32(p)) | \ + (((ntfs_s64)NTFS_GETS24(((char*)(p)) + 4)) << 32)) #define NTFS_GETS64(p) ((ntfs_s64)NTFS_GETU64(p)) #define NTFS_PUTS8(p,v) NTFS_PUTU8(p,v) #define NTFS_PUTS16(p,v) NTFS_PUTU16(p,v) #define NTFS_PUTS24(p,v) NTFS_PUTU24(p,v) #define NTFS_PUTS32(p,v) NTFS_PUTU32(p,v) + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ntfs/ntfstypes.h linux.ac/fs/ntfs/ntfstypes.h --- linux.vanilla/fs/ntfs/ntfstypes.h Mon Dec 11 21:26:39 2000 +++ linux.ac/fs/ntfs/ntfstypes.h Mon Apr 16 00:24:00 2001 @@ -1,26 +1,21 @@ -/* - * ntfstypes.h - * This file defines four things: - * - generic platform independent fixed-size types (e.g. ntfs_u32) - * - specific fixed-size types (e.g. ntfs_offset_t) - * - macros that read and write those types from and to byte arrays - * - types derived from OS specific ones +/* ntfstypes.h - This file defines four things: + * - Generic platform independent fixed-size types (e.g. ntfs_u32). + * - Specific fixed-size types (e.g. ntfs_offset_t). + * - Macros that read and write those types from and to byte arrays. + * - Types derived from OS specific ones. * - * Copyright (C) 1996,1998, 1999 Martin von Löwis + * Copyright (C) 1996, 1998, 1999 Martin von Löwis + * Copyright (C) 2001 Anton Altaparmakov (AIA) */ -#ifdef NTFS_IN_LINUX_KERNEL -/* get installed types if we compile the kernel*/ #include <linux/fs.h> -#endif /* We don't need to define __LITTLE_ENDIAN, as we use <asm/byteorder>. */ - #include "ntfsendian.h" #include <asm/types.h> -/* integral types */ +/* Integral types */ #ifndef NTFS_INTEGRAL_TYPES #define NTFS_INTEGRAL_TYPES typedef u8 ntfs_u8; @@ -33,12 +28,12 @@ typedef s64 ntfs_s64; #endif -/* unicode character type */ +/* Unicode character type */ #ifndef NTFS_WCHAR_T #define NTFS_WCHAR_T typedef u16 ntfs_wchar_t; #endif -/* file offset */ +/* File offset */ #ifndef NTFS_OFFSET_T #define NTFS_OFFSET_T typedef u64 ntfs_offset_t; @@ -48,7 +43,7 @@ #define NTFS_TIME64_T typedef u64 ntfs_time64_t; #endif -/* This is really unsigned long long. So we support only volumes up to 2 TB */ +/* This is really unsigned long long. So we support only volumes up to 2Tb. */ #ifndef NTFS_CLUSTER_T #define NTFS_CLUSTER_T typedef u32 ntfs_cluster_t; @@ -58,13 +53,13 @@ #define MAX_CLUSTER_T (~((ntfs_cluster_t)0)) #endif -/* architecture independent macros */ +/* Architecture independent macros. */ -/* PUTU32 would not clear all bytes */ -#define NTFS_PUTINUM(p,i) NTFS_PUTU64(p,i->i_number);\ - NTFS_PUTU16(((char*)p)+6,i->sequence_number) +/* PUTU32 would not clear all bytes. */ +#define NTFS_PUTINUM(p,i) NTFS_PUTU64(p, i->i_number); \ + NTFS_PUTU16(((char*)p) + 6, i->sequence_number) -/* system dependent types */ +/* System dependent types. */ #include <asm/posix_types.h> #ifndef NTMODE_T #define NTMODE_T @@ -87,8 +82,3 @@ typedef __kernel_time_t ntfs_time_t; #endif -/* - * Local variables: - * c-file-style: "linux" - * End: - */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ntfs/struct.h linux.ac/fs/ntfs/struct.h --- linux.vanilla/fs/ntfs/struct.h Tue May 2 21:46:53 2000 +++ linux.ac/fs/ntfs/struct.h Tue Apr 3 17:55:13 2001 @@ -1,143 +1,50 @@ -/* - * struct.h - * Structure definitions +/* struct.h - Structure definitions * * Copyright (C) 1997 Régis Duchesne - * Copyright (C) 2000 Anton Altaparmakov + * Copyright (C) 2000-2001 Anton Altaparmakov (AIA) */ -/* Necessary forward definition */ +/* Necessary forward definition. */ struct ntfs_inode; -#ifdef __FreeBSD__ -#include <sys/queue.h> -/* Define the struct ntfs_head type */ -LIST_HEAD(ntfs_head,ntfs_inode); -#endif +/* Which files should be returned from a director listing. */ +#define ngt_dos 1 /* only short names, no hidden files */ +#define ngt_nt 2 /* only long names, all-uppercase becomes + * all-lowercase, no hidden files */ +#define ngt_posix 3 /* all names except hidden files */ +#define ngt_full 4 /* all entries */ -/* which files should be returned from a director listing */ -/* only short names, no hidden files */ -#define ngt_dos 1 -/* only long names, all-uppercase becomes all-lowercase, no hidden files */ -#define ngt_nt 2 -/* all names except hidden files */ -#define ngt_posix 3 -/* all entries */ -#define ngt_full 4 -#ifdef NTFS_IN_LINUX_KERNEL typedef struct ntfs_sb_info ntfs_volume; -#else -typedef struct _ntfs_volume{ - /* NTFS_SB_INFO_START */ - /* Configuration provided by user at mount time */ - ntfs_uid_t uid; - ntfs_gid_t gid; - ntmode_t umask; - unsigned int nct; - void *nls_map; - unsigned int ngt; - /* Configuration provided by user with ntfstools */ - ntfs_size_t partition_bias; /* for access to underlying device */ - /* Attribute definitions */ - ntfs_u32 at_standard_information; - ntfs_u32 at_attribute_list; - ntfs_u32 at_file_name; - ntfs_u32 at_volume_version; - ntfs_u32 at_security_descriptor; - ntfs_u32 at_volume_name; - ntfs_u32 at_volume_information; - ntfs_u32 at_data; - ntfs_u32 at_index_root; - ntfs_u32 at_index_allocation; - ntfs_u32 at_bitmap; - ntfs_u32 at_symlink; /* aka SYMBOLIC_LINK or REPARSE_POINT */ - /* Data read from the boot file */ - int blocksize; - int clusterfactor; - int clustersize; - int mft_recordsize; - int mft_clusters_per_record; - int index_recordsize; - int index_clusters_per_record; - int mft_cluster; - /* data read from special files */ - unsigned char *mft; - unsigned short *upcase; - unsigned int upcase_length; - /* inodes we always hold onto */ - struct ntfs_inode *mft_ino; - struct ntfs_inode *mftmirr; - struct ntfs_inode *bitmap; - /* NTFS_SB_INFO_END */ - union{ - int fd; /* file descriptor for the tools */ - void *sb; /* pointer to super block for the kernel */ - }u; -#ifdef __FreeBSD__ - dev_t rdev; - struct vnode *devvp; - struct ntfs_head *inode_hash; /* not really a hash */ -#endif -}ntfs_volume; -#endif typedef struct { ntfs_cluster_t cluster; ntfs_cluster_t len; -}ntfs_runlist; +} ntfs_runlist; typedef struct ntfs_attribute{ int type; ntfs_u16 *name; int namelen; int attrno; - int size,allocated,initialized,compsize; - int compressed,resident,indexed; + int size, allocated, initialized, compsize; + int compressed, resident, indexed; int cengine; - union{ + union { void *data; /* if resident */ struct { ntfs_runlist *runlist; int len; - }r; - }d; -}ntfs_attribute; - -/* Structure to define IO to user buffer. do_read means that - the destination has to be written using fn_put, do_write means - that the destination has to read using fn_get. So, do_read is - from a user's point of view, while put and get are from the driver's - point of view. The first argument is always the destination of the IO -*/ -#ifdef NTFS_IN_LINUX_KERNEL + } r; + } d; +} ntfs_attribute; + +/* Structure to define IO to user buffer. do_read means that the destination + * has to be written using fn_put, do_write means that the destination has to + * read using fn_get. So, do_read is from a user's point of view, while put and + * get are from the driver's point of view. The first argument is always the + * destination of the IO. */ typedef struct ntfs_inode_info ntfs_inode; -#else -typedef struct ntfs_inode{ - ntfs_volume *vol; - /* NTFS_INODE_INFO_START */ - int i_number; /* should be really 48 bits */ - unsigned sequence_number; - unsigned char* attr; /* array of the attributes */ - int attr_count; /* size of attrs[] */ - struct ntfs_attribute *attrs; - int record_count; /* size of records[] */ - /* array of the record numbers of the MFT - whose attributes have been inserted in the inode */ - int *records; - union{ - struct{ - int recordsize; - int clusters_per_record; - }index; - } u; - /* NTFS_INODE_INFO_END */ -#ifdef __FreeBSD__ - struct vnode *vp; - LIST_ENTRY(ntfs_inode) h_next; -#endif -}ntfs_inode; -#endif typedef struct ntfs_io{ int do_read; @@ -145,7 +52,7 @@ void (*fn_get)(void *buf, struct ntfs_io *src, ntfs_size_t len); void *param; int size; -}ntfs_io; +} ntfs_io; #if 0 typedef struct { @@ -157,3 +64,4 @@ int start_vcn; } ntfs_attrlist_item; #endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ntfs/super.c linux.ac/fs/ntfs/super.c --- linux.vanilla/fs/ntfs/super.c Tue Nov 7 19:22:35 2000 +++ linux.ac/fs/ntfs/super.c Wed Apr 4 13:41:41 2001 @@ -1,10 +1,9 @@ -/* - * super.c +/* super.c * * Copyright (C) 1995-1997, 1999 Martin von Löwis * Copyright (C) 1996-1997 Régis Duchesne * Copyright (C) 1999 Steve Dodd - * Copyright (C) 2000 Anton Altparmakov + * Copyright (C) 2000-2001 Anton Altparmakov (AIA) */ #include "ntfstypes.h" @@ -12,13 +11,13 @@ #include "super.h" #include <linux/errno.h> +#include <linux/bitops.h> #include "macros.h" #include "inode.h" #include "support.h" #include "util.h" -/* - * All important structures in NTFS use 2 consistency checks : +/* All important structures in NTFS use 2 consistency checks: * . a magic structure identifier (FILE, INDX, RSTR, RCRD...) * . a fixup technique : the last word of each sector (called a fixup) of a * structure's record should end with the word at offset <n> of the first @@ -36,188 +35,204 @@ int start, count, offset; ntfs_u16 fixup; - if(!IS_MAGIC(record,magic)) + if (!IS_MAGIC(record, magic)) return 0; - start=NTFS_GETU16(record+4); - count=NTFS_GETU16(record+6); + start = NTFS_GETU16(record + 4); + count = NTFS_GETU16(record + 6); count--; - if(size && vol->blocksize*count != size) + if(size && vol->blocksize * count != size) return 0; - fixup = NTFS_GETU16(record+start); - start+=2; - offset=vol->blocksize-2; - while(count--){ - if(NTFS_GETU16(record+offset)!=fixup) + fixup = NTFS_GETU16(record + start); + start += 2; + offset = vol->blocksize - 2; + while (count--){ + if (NTFS_GETU16(record + offset) != fixup) return 0; - NTFS_PUTU16(record+offset, NTFS_GETU16(record+start)); - start+=2; - offset+=vol->blocksize; + NTFS_PUTU16(record + offset, NTFS_GETU16(record + start)); + start += 2; + offset += vol->blocksize; } return 1; } -/* Get vital informations about the ntfs partition from the boot sector */ -int ntfs_init_volume(ntfs_volume *vol,char *boot) +/* + * Get vital informations about the ntfs partition from the boot sector. + * Return 0 on success or -1 on error. + */ +int ntfs_init_volume(ntfs_volume *vol, char *boot) { - /* Historical default values, in case we don't load $AttrDef */ - vol->at_standard_information=0x10; - vol->at_attribute_list=0x20; - vol->at_file_name=0x30; - vol->at_volume_version=0x40; - vol->at_security_descriptor=0x50; - vol->at_volume_name=0x60; - vol->at_volume_information=0x70; - vol->at_data=0x80; - vol->at_index_root=0x90; - vol->at_index_allocation=0xA0; - vol->at_bitmap=0xB0; - vol->at_symlink=0xC0; - + /* Historical default values, in case we don't load $AttrDef. */ + vol->at_standard_information = 0x10; + vol->at_attribute_list = 0x20; + vol->at_file_name = 0x30; + vol->at_volume_version = 0x40; + vol->at_security_descriptor = 0x50; + vol->at_volume_name = 0x60; + vol->at_volume_information = 0x70; + vol->at_data = 0x80; + vol->at_index_root = 0x90; + vol->at_index_allocation = 0xA0; + vol->at_bitmap = 0xB0; + vol->at_symlink = 0xC0; /* Sector size */ - vol->blocksize=NTFS_GETU16(boot+0xB); - vol->clusterfactor=NTFS_GETU8(boot+0xD); - vol->mft_clusters_per_record=NTFS_GETS8(boot+0x40); - vol->index_clusters_per_record=NTFS_GETS8(boot+0x44); - - /* Just some consistency checks */ - if(NTFS_GETU32(boot+0x40)>256) + vol->blocksize = NTFS_GETU16(boot + 0xB); + vol->clusterfactorbits = ffs(NTFS_GETU8(boot + 0xD)) - 1; + vol->mft_clusters_per_record = NTFS_GETS8(boot + 0x40); + vol->index_clusters_per_record = NTFS_GETS8(boot + 0x44); + /* Just some consistency checks. */ + if (NTFS_GETU32(boot + 0x40) > 256) ntfs_error("Unexpected data #1 in boot block\n"); - if(NTFS_GETU32(boot+0x44)>256) + if (NTFS_GETU32(boot+ 0x44) > 256) ntfs_error("Unexpected data #2 in boot block\n"); - if(vol->index_clusters_per_record<0){ - ntfs_error("Unexpected data #3 in boot block\n"); - /* If this really means a fraction, setting it to 1 - should be safe. */ - vol->index_clusters_per_record=1; - } - /* in some cases, 0xF6 meant 1024 bytes. Other strange values have not - been observed */ - if(vol->mft_clusters_per_record<0 && vol->mft_clusters_per_record!=-10) - ntfs_error("Unexpected data #4 in boot block\n"); - - vol->clustersize=vol->blocksize*vol->clusterfactor; - if(vol->mft_clusters_per_record>0) - vol->mft_recordsize= - vol->clustersize*vol->mft_clusters_per_record; - else - vol->mft_recordsize=1<<(-vol->mft_clusters_per_record); - vol->index_recordsize=vol->clustersize*vol->index_clusters_per_record; + vol->clustersize = vol->blocksize << vol->clusterfactorbits; + if (vol->mft_clusters_per_record > 0) + vol->mft_recordsize = + vol->clustersize * vol->mft_clusters_per_record; + else { + /* If mft_recordsize < clustersize then mft_clusters_per_record + = -log2(mft_recordsize) bytes. Mft_recordsize normaly equals + 1024 bytes, which is encoded as 0xF6. */ + if (vol->mft_clusters_per_record < -31 || + -9 < vol->mft_clusters_per_record) { + ntfs_error("Unexpected mft clusters per record value " + "in boot block.\n"); + return -1; + } + vol->mft_recordsize = 1 << (-vol->mft_clusters_per_record); + } + if (vol->index_clusters_per_record > 0) + vol->index_recordsize = + vol->clustersize * vol->index_clusters_per_record; + else { + /* If index_recordsize < clustersize then + index_clusters_per_record = -log2(index_recordsize) bytes. + Index_recordsize normaly equals 1024 bytes, which is + encoded as 0xF6. */ + if (vol->index_clusters_per_record < -31 || + -9 < vol->index_clusters_per_record) { + ntfs_error("Unexpected index clusters per record " + "value in boot block.\n"); + return -1; + } + vol->index_recordsize = 1 << (-vol->index_clusters_per_record); + } + if (NTFS_GETU64(boot + 0x30) >= (1ULL << 32)) { + ntfs_error("Would require 64-bit inodes to mount partition."); + return -1; + } /* FIXME: long long value */ - vol->mft_cluster=NTFS_GETU64(boot+0x30); - - /* This will be initialized later */ - vol->upcase=0; - vol->upcase_length=0; - vol->mft_ino=0; + vol->mft_cluster = NTFS_GETU64(boot + 0x30); + /* This will be initialized later. */ + vol->upcase = 0; + vol->upcase_length = 0; + vol->mft_ino = 0; return 0; } -static void -ntfs_init_upcase(ntfs_inode *upcase) +static void ntfs_init_upcase(ntfs_inode *upcase) { ntfs_io io; #define UPCASE_LENGTH 256 - upcase->vol->upcase = ntfs_malloc(2*UPCASE_LENGTH); - if( !upcase->vol->upcase ) + upcase->vol->upcase = ntfs_malloc(UPCASE_LENGTH << 1); + if (!upcase->vol->upcase) return; - io.fn_put=ntfs_put; - io.fn_get=0; - io.param=(char*)upcase->vol->upcase; - io.size=2*UPCASE_LENGTH; - ntfs_read_attr(upcase,upcase->vol->at_data,0,0,&io); - upcase->vol->upcase_length = io.size / 2; + io.fn_put = ntfs_put; + io.fn_get = 0; + io.param = (char*)upcase->vol->upcase; + io.size = UPCASE_LENGTH << 1; + ntfs_read_attr(upcase, upcase->vol->at_data, 0, 0, &io); + upcase->vol->upcase_length = io.size >> 1; } -static int -process_attrdef(ntfs_inode* attrdef,ntfs_u8* def) +static int process_attrdef(ntfs_inode* attrdef, ntfs_u8* def) { int type = NTFS_GETU32(def+0x80); int check_type = 0; - ntfs_volume *vol=attrdef->vol; + ntfs_volume *vol = attrdef->vol; ntfs_u16* name = (ntfs_u16*)def; - if(ntfs_ua_strncmp(name,"$STANDARD_INFORMATION",64)==0){ - vol->at_standard_information=type; - check_type=0x10; - }else if(ntfs_ua_strncmp(name,"$ATTRIBUTE_LIST",64)==0){ - vol->at_attribute_list=type; - check_type=0x20; - }else if(ntfs_ua_strncmp(name,"$FILE_NAME",64)==0){ - vol->at_file_name=type; - check_type=0x30; - }else if(ntfs_ua_strncmp(name,"$VOLUME_VERSION",64)==0){ - vol->at_volume_version=type; - check_type=0x40; - }else if(ntfs_ua_strncmp(name,"$SECURITY_DESCRIPTOR",64)==0){ - vol->at_security_descriptor=type; - check_type=0x50; - }else if(ntfs_ua_strncmp(name,"$VOLUME_NAME",64)==0){ - vol->at_volume_name=type; - check_type=0x60; - }else if(ntfs_ua_strncmp(name,"$VOLUME_INFORMATION",64)==0){ - vol->at_volume_information=type; - check_type=0x70; - }else if(ntfs_ua_strncmp(name,"$DATA",64)==0){ - vol->at_data=type; - check_type=0x80; - }else if(ntfs_ua_strncmp(name,"$INDEX_ROOT",64)==0){ - vol->at_index_root=type; - check_type=0x90; - }else if(ntfs_ua_strncmp(name,"$INDEX_ALLOCATION",64)==0){ - vol->at_index_allocation=type; - check_type=0xA0; - }else if(ntfs_ua_strncmp(name,"$BITMAP",64)==0){ - vol->at_bitmap=type; - check_type=0xB0; - }else if(ntfs_ua_strncmp(name,"$SYMBOLIC_LINK",64)==0 || - ntfs_ua_strncmp(name,"$REPARSE_POINT",64)==0){ - vol->at_symlink=type; - check_type=0xC0; - } - if(check_type && check_type!=type){ - ntfs_error("Unexpected type %x for %x\n",type,check_type); - return EINVAL; + if (ntfs_ua_strncmp(name, "$STANDARD_INFORMATION", 64) == 0) { + vol->at_standard_information = type; + check_type = 0x10; + } else if (ntfs_ua_strncmp(name, "$ATTRIBUTE_LIST", 64) == 0) { + vol->at_attribute_list = type; + check_type = 0x20; + } else if (ntfs_ua_strncmp(name, "$FILE_NAME", 64) == 0) { + vol->at_file_name = type; + check_type = 0x30; + } else if (ntfs_ua_strncmp(name, "$VOLUME_VERSION", 64) == 0) { + vol->at_volume_version = type; + check_type = 0x40; + } else if (ntfs_ua_strncmp(name, "$SECURITY_DESCRIPTOR", 64) == 0) { + vol->at_security_descriptor = type; + check_type = 0x50; + } else if (ntfs_ua_strncmp(name, "$VOLUME_NAME", 64) == 0) { + vol->at_volume_name = type; + check_type = 0x60; + } else if (ntfs_ua_strncmp(name, "$VOLUME_INFORMATION", 64) == 0) { + vol->at_volume_information = type; + check_type = 0x70; + } else if (ntfs_ua_strncmp(name, "$DATA", 64) == 0) { + vol->at_data = type; + check_type = 0x80; + } else if (ntfs_ua_strncmp(name, "$INDEX_ROOT", 64) == 0) { + vol->at_index_root = type; + check_type = 0x90; + } else if (ntfs_ua_strncmp(name, "$INDEX_ALLOCATION", 64) == 0) { + vol->at_index_allocation = type; + check_type = 0xA0; + } else if (ntfs_ua_strncmp(name, "$BITMAP", 64) == 0) { + vol->at_bitmap = type; + check_type = 0xB0; + } else if (ntfs_ua_strncmp(name, "$SYMBOLIC_LINK", 64) == 0 || + ntfs_ua_strncmp(name, "$REPARSE_POINT", 64) == 0) { + vol->at_symlink = type; + check_type = 0xC0; + } + if (check_type && check_type != type) { + ntfs_error("Unexpected type %x for %x\n", type, check_type); + return -EINVAL; } return 0; } -int -ntfs_init_attrdef(ntfs_inode* attrdef) +int ntfs_init_attrdef(ntfs_inode* attrdef) { ntfs_u8 *buf; ntfs_io io; - int offset,error,i; + int offset, error,i; ntfs_attribute *data; - buf=ntfs_malloc(4050); /* 90*45 */ - if(!buf)return ENOMEM; - io.fn_put=ntfs_put; - io.fn_get=ntfs_get; - io.do_read=1; - offset=0; - data=ntfs_find_attr(attrdef,attrdef->vol->at_data,0); - if(!data){ + + buf = ntfs_malloc(4050); /* 90*45 */ + if (!buf) + return -ENOMEM; + io.fn_put = ntfs_put; + io.fn_get = ntfs_get; + io.do_read = 1; + offset = 0; + data = ntfs_find_attr(attrdef, attrdef->vol->at_data, 0); + if (!data) { ntfs_free(buf); - return EINVAL; + return -EINVAL; } - do{ - io.param=buf; - io.size=4050; - error=ntfs_readwrite_attr(attrdef,data,offset,&io); - for(i=0;!error && i<io.size-0xA0;i+=0xA0) - error=process_attrdef(attrdef,buf+i); - offset+=4096; - }while(!error && io.size); + do { + io.param = buf; + io.size = 4050; + error = ntfs_readwrite_attr(attrdef, data, offset, &io); + for (i = 0; !error && i < io.size - 0xA0; i += 0xA0) + error = process_attrdef(attrdef, buf + i); + offset += 4096; + } while (!error && io.size); ntfs_free(buf); return error; } -/* ntfs_get_version will determine the NTFS version of the - volume and will return the version in a BCD format, with - the MSB being the major version number and the LSB the - minor one. Otherwise return <0 on error. - Example: version 3.1 will be returned as 0x0301. - This has the obvious limitation of not coping with version - numbers above 0x80 but that shouldn't be a problem... */ +/* ntfs_get_version will determine the NTFS version of the volume and will + * return the version in a BCD format, with the MSB being the major version + * number and the LSB the minor one. Otherwise return <0 on error. + * Example: version 3.1 will be returned as 0x0301. This has the obvious + * limitation of not coping with version numbers above 0x80 but that shouldn't + * be a problem... */ int ntfs_get_version(ntfs_inode* volume) { ntfs_attribute *volinfo; @@ -229,7 +244,8 @@ ntfs_error("Volume information attribute is not resident!\n"); return -EINVAL; } - return ((ntfs_u8*)volinfo->d.data)[8] << 8 | ((ntfs_u8*)volinfo->d.data)[9]; + return ((ntfs_u8*)volinfo->d.data)[8] << 8 | + ((ntfs_u8*)volinfo->d.data)[9]; } int ntfs_load_special_files(ntfs_volume *vol) @@ -237,119 +253,120 @@ int error; ntfs_inode upcase, attrdef, volume; - vol->mft_ino=(ntfs_inode*)ntfs_calloc(3*sizeof(ntfs_inode)); - error=ENOMEM; - ntfs_debug(DEBUG_BSD,"Going to load MFT\n"); - if(!vol->mft_ino || (error=ntfs_init_inode(vol->mft_ino,vol,FILE_MFT))) + vol->mft_ino = (ntfs_inode*)ntfs_calloc(3 * sizeof(ntfs_inode)); + error = -ENOMEM; + ntfs_debug(DEBUG_BSD, "Going to load MFT\n"); + if (!vol->mft_ino || (error = ntfs_init_inode(vol->mft_ino, vol, + FILE_$Mft))) { ntfs_error("Problem loading MFT\n"); return error; } - ntfs_debug(DEBUG_BSD,"Going to load MIRR\n"); - vol->mftmirr=vol->mft_ino+1; - if((error=ntfs_init_inode(vol->mftmirr,vol,FILE_MFTMIRR))){ - ntfs_error("Problem %d loading MFTMirr\n",error); + ntfs_debug(DEBUG_BSD, "Going to load MIRR\n"); + vol->mftmirr = vol->mft_ino + 1; + if ((error = ntfs_init_inode(vol->mftmirr, vol, FILE_$MftMirr))) { + ntfs_error("Problem %d loading MFTMirr\n", error); return error; } - ntfs_debug(DEBUG_BSD,"Going to load BITMAP\n"); - vol->bitmap=vol->mft_ino+2; - if((error=ntfs_init_inode(vol->bitmap,vol,FILE_BITMAP))){ + ntfs_debug(DEBUG_BSD, "Going to load BITMAP\n"); + vol->bitmap = vol->mft_ino + 2; + if ((error = ntfs_init_inode(vol->bitmap, vol, FILE_$BitMap))) { ntfs_error("Problem loading Bitmap\n"); return error; } - ntfs_debug(DEBUG_BSD,"Going to load UPCASE\n"); - error=ntfs_init_inode(&upcase,vol,FILE_UPCASE); - if(error)return error; + ntfs_debug(DEBUG_BSD, "Going to load UPCASE\n"); + error = ntfs_init_inode(&upcase, vol, FILE_$UpCase); + if (error) + return error; ntfs_init_upcase(&upcase); ntfs_clear_inode(&upcase); - ntfs_debug(DEBUG_BSD,"Going to load ATTRDEF\n"); - error=ntfs_init_inode(&attrdef,vol,FILE_ATTRDEF); - if(error)return error; - error=ntfs_init_attrdef(&attrdef); + ntfs_debug(DEBUG_BSD, "Going to load ATTRDEF\n"); + error = ntfs_init_inode(&attrdef, vol, FILE_$AttrDef); + if (error) + return error; + error = ntfs_init_attrdef(&attrdef); ntfs_clear_inode(&attrdef); - if(error)return error; + if (error) + return error; - /* Check for NTFS version and if Win2k version (ie. 3.0+) - do not allow write access since the driver write support - is broken, especially for Win2k. */ - ntfs_debug(DEBUG_BSD,"Going to load VOLUME\n"); - error = ntfs_init_inode(&volume,vol,FILE_VOLUME); - if (error) return error; - if ((error = ntfs_get_version(&volume)) >= 0x0300) { + /* Check for NTFS version and if Win2k version (ie. 3.0+) do not allow + * write access since the driver write support is broken. */ + ntfs_debug(DEBUG_BSD, "Going to load VOLUME\n"); + error = ntfs_init_inode(&volume, vol, FILE_$Volume); + if (error) + return error; + if ((error = ntfs_get_version(&volume)) >= 0x0300 && + !(NTFS_SB(vol)->s_flags & MS_RDONLY)) { NTFS_SB(vol)->s_flags |= MS_RDONLY; - ntfs_error("Warning! NTFS volume version is Win2k+: Mounting read-only\n"); + ntfs_error("Warning! NTFS volume version is Win2k+: Mounting " + "read-only\n"); } ntfs_clear_inode(&volume); - if (error < 0) return error; - ntfs_debug(DEBUG_BSD, "NTFS volume is version %d.%d\n", error >> 8, error & 0xff); - + if (error < 0) + return error; + ntfs_debug(DEBUG_BSD, "NTFS volume is version %d.%d\n", error >> 8, + error & 0xff); return 0; } int ntfs_release_volume(ntfs_volume *vol) { - if(vol->mft_ino){ + if (vol->mft_ino) { ntfs_clear_inode(vol->mft_ino); ntfs_clear_inode(vol->mftmirr); ntfs_clear_inode(vol->bitmap); ntfs_free(vol->mft_ino); - vol->mft_ino=0; + vol->mft_ino = 0; } ntfs_free(vol->mft); ntfs_free(vol->upcase); return 0; } -/* - * Writes the volume size into vol_size. Returns 0 if successful - * or error. - */ -int ntfs_get_volumesize(ntfs_volume *vol, ntfs_u64 *vol_size ) +/* Writes the volume size into vol_size. Returns 0 if successful or error. */ +int ntfs_get_volumesize(ntfs_volume *vol, ntfs_u64 *vol_size) { ntfs_io io; char *cluster0; - if( !vol_size ) - return EFAULT; - - cluster0=ntfs_malloc(vol->clustersize); - if( !cluster0 ) - return ENOMEM; - - io.fn_put=ntfs_put; - io.fn_get=ntfs_get; - io.param=cluster0; - io.do_read=1; - io.size=vol->clustersize; - ntfs_getput_clusters(vol,0,0,&io); - *vol_size = NTFS_GETU64(cluster0+0x28); + if (!vol_size) + return -EFAULT; + cluster0 = ntfs_malloc(vol->clustersize); + if (!cluster0) + return -ENOMEM; + io.fn_put = ntfs_put; + io.fn_get = ntfs_get; + io.param = cluster0; + io.do_read = 1; + io.size = vol->clustersize; + ntfs_getput_clusters(vol, 0, 0, &io); + *vol_size = NTFS_GETU64(cluster0 + 0x28) >> vol->clusterfactorbits; ntfs_free(cluster0); return 0; } static int nc[16]={4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0}; -int -ntfs_get_free_cluster_count(ntfs_inode *bitmap) +int ntfs_get_free_cluster_count(ntfs_inode *bitmap) { unsigned char bits[2048]; - int offset,error; - int clusters=0; + int offset, error; + int clusters = 0; ntfs_io io; - offset=0; - io.fn_put=ntfs_put; - io.fn_get=ntfs_get; - while(1) - { + offset = 0; + io.fn_put = ntfs_put; + io.fn_get = ntfs_get; + while (1) { register int i; - io.param=bits; - io.size=2048; - error=ntfs_read_attr(bitmap,bitmap->vol->at_data,0, - offset,&io); - if(error || io.size==0)break; + io.param = bits; + io.size = 2048; + error = ntfs_read_attr(bitmap, bitmap->vol->at_data, 0, offset, + &io); + if (error || io.size == 0) + break; /* I never thought I would do loop unrolling some day */ - for(i=0;i<io.size-8;){ + for (i = 0; i < io.size - 8; ) { clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF]; clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF]; clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF]; @@ -359,261 +376,263 @@ clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF]; clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF]; } - for(;i<io.size;){ - clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF]; + while (i < io.size) { + clusters += nc[bits[i] >> 4]; + clusters += nc[bits[i++] & 0xF]; } - offset+=io.size; + offset += io.size; } return clusters; } -/* Insert the fixups for the record. The number and location of the fixes - is obtained from the record header */ +/* Insert the fixups for the record. The number and location of the fixes + * is obtained from the record header */ void ntfs_insert_fixups(unsigned char *rec, int secsize) { - int first=NTFS_GETU16(rec+4); - int count=NTFS_GETU16(rec+6); - int offset=-2; - ntfs_u16 fix=NTFS_GETU16(rec+first); - fix=fix+1; - NTFS_PUTU16(rec+first,fix); + int first = NTFS_GETU16(rec + 4); + int count = NTFS_GETU16(rec + 6); + int offset = -2; + ntfs_u16 fix = NTFS_GETU16(rec + first); + + fix++; + if (fix == 0xffff || !fix) + fix = 1; + NTFS_PUTU16(rec + first, fix); count--; - while(count--){ - first+=2; - offset+=secsize; - NTFS_PUTU16(rec+first,NTFS_GETU16(rec+offset)); - NTFS_PUTU16(rec+offset,fix); + while (count--) { + first += 2; + offset += secsize; + NTFS_PUTU16(rec + first, NTFS_GETU16(rec + offset)); + NTFS_PUTU16(rec + offset, fix); }; } -/* search the bitmap bits of l bytes for *cnt zero bits. Return the bit - number in *loc, which is initially set to the number of the first bit. - Return the largest block found in *cnt. Return 0 on success, ENOSPC if - all bits are used */ -static int -search_bits(unsigned char* bits,ntfs_cluster_t *loc,int *cnt,int l) -{ - unsigned char c=0; - int bc=0; - int bstart=0,bstop=0,found=0; - int start,stop=0,in=0; +/* Search the bitmap bits of l bytes for *cnt zero bits. Return the bit number + * in *loc, which is initially set to the number of the first bit. Return the + * largest block found in *cnt. Return 0 on success, -ENOSPC if all bits are + * used. */ +static int search_bits(unsigned char* bits, ntfs_cluster_t *loc, int *cnt,int l) +{ + unsigned char c = 0; + int bc = 0; + int bstart = 0, bstop = 0, found = 0; + int start, stop = 0, in = 0; /* special case searching for a single block */ - if(*cnt==1){ - while(l && *bits==0xFF){ + if (*cnt == 1) { + while (l && *bits == 0xFF) { bits++; - *loc+=8; + *loc += 8; l--; } - if(!l)return ENOSPC; - for(c=*bits;c & 1;c>>=1) + if (!l) + return -ENOSPC; + for (c = *bits; c & 1; c >>= 1) (*loc)++; return 0; } - start=*loc; - while(l || bc){ - if(bc==0){ - c=*bits; - if(l){ - l--;bits++; + start = *loc; + while (l || bc) { + if (bc == 0) { + c = *bits; + if (l) { + l--; + bits++; } - bc=8; + bc = 8; } - if(in){ - if((c&1)==0) + if (in) { + if ((c & 1) == 0) stop++; - else{ /* end of sequence of zeroes */ - in=0; - if(!found || bstop-bstart<stop-start){ - bstop=stop;bstart=start;found=1; - if(bstop-bstart>*cnt) + else { /* end of sequence of zeroes */ + in = 0; + if (!found || bstop-bstart < stop-start) { + bstop = stop; bstart = start; + found = 1; + if (bstop - bstart > *cnt) break; } - start=stop+1; + start = stop + 1; } - }else{ - if(c&1) + } else { + if (c & 1) start++; - else{ /*start of sequence*/ - in=1; - stop=start+1; + else { /*start of sequence*/ + in = 1; + stop = start + 1; } } bc--; - c>>=1; + c >>= 1; } - if(in && (!found || bstop-bstart<stop-start)){ - bstop=stop;bstart=start;found=1; + if (in && (!found || bstop - bstart < stop - start)) { + bstop = stop; bstart = start; found = 1; } - if(!found)return ENOSPC; - *loc=bstart; - if(*cnt>bstop-bstart) - *cnt=bstop-bstart; + if (!found) + return -ENOSPC; + *loc = bstart; + if (*cnt > bstop - bstart) + *cnt = bstop - bstart; return 0; } -int -ntfs_set_bitrange(ntfs_inode* bitmap,ntfs_cluster_t loc,int cnt,int bit) +int ntfs_set_bitrange(ntfs_inode* bitmap, ntfs_cluster_t loc, int cnt, int bit) { - int bsize,locit,error; - unsigned char *bits,*it; + int bsize, locit, error; + unsigned char *bits, *it; ntfs_io io; - io.fn_put=ntfs_put; - io.fn_get=ntfs_get; - bsize=(cnt+(loc & 7)+7) >> 3; /* round up to multiple of 8*/ - bits=ntfs_malloc(bsize); - io.param=bits; - io.size=bsize; - if(!bits) - return ENOMEM; - error=ntfs_read_attr(bitmap,bitmap->vol->at_data,0,loc>>3,&io); - if(error || io.size!=bsize){ + io.fn_put = ntfs_put; + io.fn_get = ntfs_get; + bsize = (cnt + (loc & 7) + 7) >> 3; /* round up to multiple of 8*/ + bits = ntfs_malloc(bsize); + if (!bits) + return -ENOMEM; + io.param = bits; + io.size = bsize; + error = ntfs_read_attr(bitmap, bitmap->vol->at_data, 0, loc >> 3, &io); + if (error || io.size != bsize){ ntfs_free(bits); - return error?error:EIO; + return error ? error : -EIO; } - /* now set the bits */ - it=bits; - locit=loc; - while(locit%8 && cnt){ /* process first byte */ - if(bit) - *it |= 1<<(locit%8); + /* Now set the bits. */ + it = bits; + locit = loc; + while (locit % 8 && cnt) { /* process first byte */ + if (bit) + *it |= 1 << (locit % 8); else - *it &= ~(1<<(locit%8)); - cnt--;locit++; - if(locit%8==0) + *it &= ~(1 << (locit % 8)); + cnt--; + locit++; + if (locit % 8 == 0) it++; } - while(cnt>8){ /*process full bytes */ - *it= bit ? 0xFF : 0; - cnt-=8; - locit+=8; + while (cnt > 8) { /*process full bytes */ + *it = bit ? 0xFF : 0; + cnt -= 8; + locit += 8; it++; } - while(cnt){ /*process last byte */ - if(bit) - *it |= 1<<(locit%8); + while (cnt) { /*process last byte */ + if (bit) + *it |= 1 << (locit % 8); else - *it &= ~(1<<(locit%8)); - cnt--;locit++; + *it &= ~(1 << (locit % 8)); + cnt--; + locit++; } /* reset to start */ - io.param=bits; - io.size=bsize; - error=ntfs_write_attr(bitmap,bitmap->vol->at_data,0,loc>>3,&io); + io.param = bits; + io.size = bsize; + error = ntfs_write_attr(bitmap, bitmap->vol->at_data, 0, loc >> 3, &io); ntfs_free(bits); - if(error)return error; - if(io.size!=bsize) - return EIO; + if (error) + return error; + if (io.size != bsize) + return -EIO; return 0; } - - -/* allocate count clusters around location. If location is -1, - it does not matter where the clusters are. Result is 0 if - success, in which case location and count says what they really got */ -int -ntfs_search_bits(ntfs_inode* bitmap, ntfs_cluster_t *location, int *count, int flags) +/* Allocate count clusters around location. If location is -1, it does not + * matter where the clusters are. Result is 0 if success, in which case + * location and count says what they really got. */ +int ntfs_search_bits(ntfs_inode* bitmap, ntfs_cluster_t *location, int *count, + int flags) { unsigned char *bits; ntfs_io io; - int error=0,found=0; - int cnt,bloc=-1,bcnt=0; + int error = 0, found = 0; + int cnt, bloc = -1, bcnt = 0; int start; ntfs_cluster_t loc; - bits=ntfs_malloc(2048); - if( !bits ) - return ENOMEM; - io.fn_put=ntfs_put; - io.fn_get=ntfs_get; - io.param=bits; + bits = ntfs_malloc(2048); + if (!bits) + return -ENOMEM; + io.fn_put = ntfs_put; + io.fn_get = ntfs_get; + io.param = bits; /* first search within +/- 8192 clusters */ - start=*location>>3; - start= start>1024 ? start-1024 : 0; - io.size=2048; - error=ntfs_read_attr(bitmap,bitmap->vol->at_data,0,start,&io); - if(error)goto fail; - loc=start*8; - cnt=*count; - error=search_bits(bits,&loc,&cnt,io.size); - if(error) + start = *location >> 3; + start = start > 1024 ? start - 1024 : 0; + io.size = 2048; + error = ntfs_read_attr(bitmap, bitmap->vol->at_data, 0, start, &io); + if (error) goto fail; - if(*count==cnt){ - bloc=loc; - bcnt=cnt; + loc = start * 8; + cnt = *count; + error = search_bits(bits, &loc, &cnt, io.size); + if (error) + goto fail; + if (*count == cnt){ + bloc = loc; + bcnt = cnt; goto success; } - - /* now search from the beginning */ - for(start=0;1;start+=2048) - { - io.param=bits; - io.size=2048; - error=ntfs_read_attr(bitmap,bitmap->vol->at_data, - 0,start,&io); - if(error)goto fail; - if(io.size==0){ + /* Now search from the beginning. */ + for (start = 0; 1; start += 2048) { + io.param = bits; + io.size = 2048; + error = ntfs_read_attr(bitmap, bitmap->vol->at_data, 0, start, + &io); + if (error) + goto fail; + if (io.size == 0) { if(found) goto success; - else{ - error=ENOSPC; + else { + error = -ENOSPC; goto fail; } } - loc=start*8; - cnt=*count; - error=search_bits(bits,&loc,&cnt,io.size); - if(error) + loc = start * 8; + cnt = *count; + error = search_bits(bits, &loc, &cnt, io.size); + if (error) goto fail; - if(*count==cnt) + if (*count == cnt) goto success; - if(bcnt<cnt){ - bcnt=cnt; - bloc=loc; - found=1; + if (bcnt < cnt) { + bcnt = cnt; + bloc = loc; + found = 1; } } success: ntfs_free(bits); /* check flags */ - if((flags & ALLOC_REQUIRE_LOCATION) && *location!=bloc) - error=ENOSPC; - else if((flags & ALLOC_REQUIRE_SIZE) && *count!=bcnt) - error=ENOSPC; - else ntfs_set_bitrange(bitmap,bloc,bcnt,1); - /* If allocation failed due to the flags, tell the caller what he - could have gotten */ - *location=bloc; - *count=bcnt; + if ((flags & ALLOC_REQUIRE_LOCATION) && *location != bloc) + error = -ENOSPC; + else if ((flags & ALLOC_REQUIRE_SIZE) && *count != bcnt) + error = -ENOSPC; + else + ntfs_set_bitrange(bitmap, bloc, bcnt, 1); + /* If allocation failed due to the flags, tell the caller what he could + * have gotten */ + *location = bloc; + *count = bcnt; return 0; fail: - *location=-1; - *count=0; + *location = -1; + *count = 0; ntfs_free(bits); return error; } -int ntfs_allocate_clusters(ntfs_volume *vol, ntfs_cluster_t *location, int *count, - int flags) +int ntfs_allocate_clusters(ntfs_volume *vol, ntfs_cluster_t *location, + int *count, int flags) { int error; - error=ntfs_search_bits(vol->bitmap,location,count,flags); + error = ntfs_search_bits(vol->bitmap, location, count, flags); return error; } -int ntfs_deallocate_clusters(ntfs_volume *vol, ntfs_cluster_t location, int count) +int ntfs_deallocate_clusters(ntfs_volume *vol, ntfs_cluster_t location, + int count) { int error; - error=ntfs_set_bitrange(vol->bitmap,location,count,0); + error = ntfs_set_bitrange(vol->bitmap, location, count, 0); return error; } - -/* - * Local variables: - * c-file-style: "linux" - * End: - */ - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ntfs/super.h linux.ac/fs/ntfs/super.h --- linux.vanilla/fs/ntfs/super.h Thu Dec 9 21:14:30 1999 +++ linux.ac/fs/ntfs/super.h Tue Apr 3 17:55:13 2001 @@ -1,6 +1,4 @@ -/* - * super.h - * Header file for super.c +/* super.h - Header file for super.c * * Copyright (C) 1995-1997 Martin von Löwis * Copyright (C) 1996-1997 Régis Duchesne @@ -10,12 +8,22 @@ #define ALLOC_REQUIRE_SIZE 2 int ntfs_get_free_cluster_count(ntfs_inode *bitmap); + int ntfs_get_volumesize(ntfs_volume *vol, ntfs_u64 *vol_size ); -int ntfs_init_volume(ntfs_volume *vol,char *boot); + +int ntfs_init_volume(ntfs_volume *vol, char *boot); + int ntfs_load_special_files(ntfs_volume *vol); + int ntfs_release_volume(ntfs_volume *vol); + void ntfs_insert_fixups(unsigned char *rec, int secsize); + int ntfs_fixup_record(ntfs_volume *vol, char *record, char *magic, int size); -int ntfs_allocate_clusters(ntfs_volume *vol, ntfs_cluster_t *location, int *count, - int flags); -int ntfs_deallocate_clusters(ntfs_volume *vol, ntfs_cluster_t location, int count); + +int ntfs_allocate_clusters(ntfs_volume *vol, ntfs_cluster_t *location, + int *count, int flags); + +int ntfs_deallocate_clusters(ntfs_volume *vol, ntfs_cluster_t location, + int count); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ntfs/support.c linux.ac/fs/ntfs/support.c --- linux.vanilla/fs/ntfs/support.c Tue Sep 5 22:07:30 2000 +++ linux.ac/fs/ntfs/support.c Tue Apr 3 17:55:13 2001 @@ -1,15 +1,10 @@ -/* - * support.c - * Specific support functions +/* support.c - Specific support functions * * Copyright (C) 1997 Martin von Löwis * Copyright (C) 1997 Régis Duchesne - * + * Copyright (C) 2001 Anton Altaparmakov (AIA) */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif #include "ntfstypes.h" #include "struct.h" #include "support.h" @@ -64,7 +59,7 @@ kfree(block); } #endif -#else +#else /* End of DEBUG functions. Normal ones below... */ void ntfs_debug(int mask, const char *fmt, ...) { } @@ -102,7 +97,7 @@ memmove(dest, src, n); } -/* Warn that an error occured. */ +/* Warn that an error occurred. */ void ntfs_error(const char *fmt,...) { va_list ap; @@ -120,68 +115,72 @@ ntfs_io io; ntfs_debug(DEBUG_OTHER, "read_mft_record %x\n",mftno); - if(mftno==FILE_MFT) + if(mftno == FILE_$Mft) { - ntfs_memcpy(buf,vol->mft,vol->mft_recordsize); + ntfs_memcpy(buf, vol->mft, vol->mft_recordsize); return 0; } if(!vol->mft_ino) { - printk("ntfs:something is terribly wrong here\n"); - return ENODATA; + printk(KERN_ERR "NTFS: mft_ino is NULL. Something is terribly " + "wrong here!\n"); + return -ENODATA; } - io.fn_put=ntfs_put; - io.fn_get=0; - io.param=buf; - io.size=vol->mft_recordsize; - error=ntfs_read_attr(vol->mft_ino,vol->at_data,NULL, - mftno*vol->mft_recordsize,&io); - if(error || (io.size!=vol->mft_recordsize)) + io.fn_put = ntfs_put; + io.fn_get = 0; + io.param = buf; + io.size = vol->mft_recordsize; + error = ntfs_read_attr(vol->mft_ino, vol->at_data, NULL, + mftno * vol->mft_recordsize, &io); + if (error || (io.size != vol->mft_recordsize)) { - ntfs_debug(DEBUG_OTHER, "read_mft_record: read %x failed (%d,%d,%d)\n", - mftno,error,io.size,vol->mft_recordsize); - return error?error:ENODATA; + ntfs_debug(DEBUG_OTHER, "read_mft_record: read %x failed " + "(%d,%d,%d)\n", mftno, error, io.size, + vol->mft_recordsize); + return error ? error : -ENODATA; } - ntfs_debug(DEBUG_OTHER, "read_mft_record: finished read %x\n",mftno); - if(!ntfs_check_mft_record(vol,buf)) + ntfs_debug(DEBUG_OTHER, "read_mft_record: finished read %x\n", mftno); + if(!ntfs_check_mft_record(vol, buf)) { - printk("Invalid MFT record for %x\n",mftno); - return EINVAL; + /* FIXME: This is incomplete behaviour. We might be able to + * recover at this stage. ntfs_check_mft_record() is too + * conservative at aborting it's operations. It is OK for + * now as we just can't handle some on disk structures + * this way. (AIA) */ + printk(KERN_WARNING "NTFS: Invalid MFT record for %x\n", mftno); + return -EINVAL; } - ntfs_debug(DEBUG_OTHER, "read_mft_record: Done %x\n",mftno); + ntfs_debug(DEBUG_OTHER, "read_mft_record: Done %x\n", mftno); return 0; } int ntfs_getput_clusters(ntfs_volume *vol, int cluster, ntfs_size_t start_offs, - ntfs_io *buf) + ntfs_io *buf) { - struct super_block *sb=NTFS_SB(vol); + struct super_block *sb = NTFS_SB(vol); struct buffer_head *bh; ntfs_size_t to_copy; - int length=buf->size; - if(buf->do_read) - ntfs_debug(DEBUG_OTHER, "get_clusters %d %d %d\n",cluster,start_offs,length); - else - ntfs_debug(DEBUG_OTHER, "put_clusters %d %d %d\n",cluster,start_offs,length); - while(length) - { - if(!(bh=bread(sb->s_dev,cluster,vol->clustersize))) - { - ntfs_debug(DEBUG_OTHER, "%s failed\n", buf->do_read?"Reading":"Writing"); - return EIO; + int length = buf->size; + + ntfs_debug(DEBUG_OTHER, "%s_clusters %d %d %d\n", + buf->do_read ? "get" : "put", cluster, start_offs, length); + while (length) { + if (!(bh = bread(sb->s_dev, cluster, vol->clustersize))) { + ntfs_debug(DEBUG_OTHER, "%s failed\n", + buf->do_read ? "Reading" : "Writing"); + return -EIO; } - to_copy=min(vol->clustersize-start_offs,length); + to_copy = min(vol->clustersize - start_offs, length); lock_buffer(bh); - if(buf->do_read) - buf->fn_put(buf,bh->b_data+start_offs,to_copy); - else - { - buf->fn_get(bh->b_data+start_offs,buf,to_copy); + if (buf->do_read) + buf->fn_put(buf, bh->b_data + start_offs, to_copy); + else { + buf->fn_get(bh->b_data + start_offs, buf, to_copy); mark_buffer_dirty(bh); } unlock_buffer(bh); - length-=to_copy; - start_offs=0; + length -= to_copy; + start_offs = 0; cluster++; brelse(bh); } @@ -193,152 +192,147 @@ return ntfs_unixutc2ntutc(CURRENT_TIME); } -/* when printing unicode characters base64, use this table. - It is not strictly base64, but the Linux vfat encoding. - base64 has the disadvantage of using the slash. -*/ -static char uni2esc[64]= - "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+-"; - -static unsigned char -esc2uni(char c) -{ - if(c<'0')return 255; - if(c<='9')return c-'0'; - if(c<'A')return 255; - if(c<='Z')return c-'A'+10; - if(c<'a')return 255; - if(c<='z')return c-'a'+36; - if(c=='+')return 62; - if(c=='-')return 63; +/* When printing unicode characters base64, use this table. It is not strictly + * base64, but the Linux vfat encoding. base64 has the disadvantage of using + * the slash. */ +static char uni2esc[64] = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+-"; + +static unsigned char esc2uni(char c) +{ + if (c < '0') return 255; + if (c <= '9') return c - '0'; + if (c < 'A') return 255; + if (c <= 'Z') return c - 'A' + 10; + if (c < 'a') return 255; + if (c <= 'z') return c - 'a' + 36; + if (c == '+') return 62; + if (c == '-') return 63; return 255; } int ntfs_dupuni2map(ntfs_volume *vol, ntfs_u16 *in, int in_len, char **out, - int *out_len) + int *out_len) { - int i,o,val,chl, chi; - char *result,*buf,charbuf[NLS_MAX_CHARSET_SIZE]; - struct nls_table* nls=vol->nls_map; - - result=ntfs_malloc(in_len+1); - if(!result)return ENOMEM; - *out_len=in_len; - result[in_len]='\0'; - for(i=o=0;i<in_len;i++){ - int cl,ch; + int i, o, val, chl, chi; + char *result, *buf, charbuf[NLS_MAX_CHARSET_SIZE]; + struct nls_table* nls = vol->nls_map; + + result = ntfs_malloc(in_len + 1); + if (!result) + return -ENOMEM; + *out_len = in_len; + result[in_len] = '\0'; + for (i = o = 0; i < in_len; i++) { + int cl, ch; /* FIXME: byte order? */ - cl=in[i] & 0xFF; - ch=(in[i] >> 8) & 0xFF; - if(!nls){ - if(!ch){ - result[o++]=cl; + cl = in[i] & 0xFF; + ch = (in[i] >> 8) & 0xFF; + if (!nls) { + if (!ch) { + result[o++] = cl; continue; } - }else{ + } else { /* FIXME: byte order? */ wchar_t uni = in[i]; - if ( (chl = nls->uni2char(uni, charbuf, NLS_MAX_CHARSET_SIZE)) > 0){ + if ((chl = nls->uni2char(uni, charbuf, + NLS_MAX_CHARSET_SIZE)) > 0) { /* adjust result buffer */ - if (chl > 1){ - buf=ntfs_malloc(*out_len + chl - 1); + if (chl > 1) { + buf = ntfs_malloc(*out_len + chl - 1); memcpy(buf, result, o); ntfs_free(result); - result=buf; - *out_len+=(chl-1); + result = buf; + *out_len += (chl - 1); } - for (chi=0;chi<chl;chi++) + for (chi = 0; chi < chl; chi++) result[o++] = charbuf[chi]; } else result[o++] = '?'; continue; - } - if(!(vol->nct & nct_uni_xlate))goto inval; + if (!(vol->nct & nct_uni_xlate)) + goto inval; /* realloc */ - buf=ntfs_malloc(*out_len+3); - if( !buf ) { - ntfs_free( result ); - return ENOMEM; + buf = ntfs_malloc(*out_len + 3); + if (!buf) { + ntfs_free(result); + return -ENOMEM; } - memcpy(buf,result,o); + memcpy(buf, result, o); ntfs_free(result); - result=buf; - *out_len+=3; - result[o++]=':'; - if(vol->nct & nct_uni_xlate_vfat){ - val=(cl<<8)+ch; - result[o+2]=uni2esc[val & 0x3f]; - val>>=6; - result[o+1]=uni2esc[val & 0x3f]; - val>>=6; - result[o]=uni2esc[val & 0x3f]; - o+=3; - }else{ - val=(ch<<8)+cl; - result[o++]=uni2esc[val & 0x3f]; - val>>=6; - result[o++]=uni2esc[val & 0x3f]; - val>>=6; - result[o++]=uni2esc[val & 0x3f]; + result = buf; + *out_len += 3; + result[o++] = ':'; + if (vol->nct & nct_uni_xlate_vfat) { + val = (cl << 8) + ch; + result[o+2] = uni2esc[val & 0x3f]; + val >>= 6; + result[o+1] = uni2esc[val & 0x3f]; + val >>= 6; + result[o] = uni2esc[val & 0x3f]; + o += 3; + } else { + val = (ch << 8) + cl; + result[o++] = uni2esc[val & 0x3f]; + val >>= 6; + result[o++] = uni2esc[val & 0x3f]; + val >>= 6; + result[o++] = uni2esc[val & 0x3f]; } } - *out=result; + *out = result; return 0; inval: ntfs_free(result); - *out=0; - return EILSEQ; + *out = 0; + return -EILSEQ; } int ntfs_dupmap2uni(ntfs_volume *vol, char* in, int in_len, ntfs_u16 **out, - int *out_len) + int *out_len) { - int i,o; + int i, o; ntfs_u16* result; - struct nls_table* nls=vol->nls_map; + struct nls_table* nls = vol->nls_map; - *out=result=ntfs_malloc(2*in_len); - if(!result)return ENOMEM; - *out_len=in_len; - for(i=o=0;i<in_len;i++,o++){ + *out=result = ntfs_malloc(2 * in_len); + if (!result) + return -ENOMEM; + *out_len = in_len; + for (i = o = 0; i < in_len; i++, o++){ wchar_t uni; - if(in[i]!=':' || (vol->nct & nct_uni_xlate)==0){ + if (in[i] != ':' || (vol->nct & nct_uni_xlate) == 0){ int charlen; - /* FIXME: is this error handling ok? */ charlen = nls->char2uni(&in[i], in_len-i, &uni); if (charlen < 0) return charlen; - *out_len -= (charlen-1); - i += (charlen-1); - }else{ - unsigned char c1,c2,c3; - *out_len-=3; - c1=esc2uni(in[++i]); - c2=esc2uni(in[++i]); - c3=esc2uni(in[++i]); - if(c1==255 || c2==255 || c3==255) + *out_len -= (charlen - 1); + i += (charlen - 1); + } else { + unsigned char c1, c2, c3; + *out_len -= 3; + c1 = esc2uni(in[++i]); + c2 = esc2uni(in[++i]); + c3 = esc2uni(in[++i]); + if (c1 == 255 || c2 == 255 || c3 == 255) uni = 0; - else if(vol->nct & nct_uni_xlate_vfat){ + else if (vol->nct & nct_uni_xlate_vfat) { uni = (((c2 & 0x3) << 6) + c3) << 8 | - ((c1 << 4) + (c2 >> 2)); - }else{ + ((c1 << 4) + (c2 >> 2)); + } else { uni = ((c3 << 4) + (c2 >> 2)) << 8 | - (((c2 & 0x3) << 6) + c1); + (((c2 & 0x3) << 6) + c1); } } /* FIXME: byte order? */ result[o] = uni; - if(!result[o]){ + if (!result[o]) { ntfs_free(result); - return EILSEQ; + return -EILSEQ; } } return 0; } -/* - * Local variables: - * c-file-style: "linux" - * End: - */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ntfs/support.h linux.ac/fs/ntfs/support.h --- linux.vanilla/fs/ntfs/support.h Mon Dec 11 21:26:39 2000 +++ linux.ac/fs/ntfs/support.h Tue Apr 17 18:50:29 2001 @@ -1,6 +1,4 @@ -/* - * support.h - * Header file for specific support.c +/* support.h - Header file for specific support.c * * Copyright (C) 1997 Régis Duchesne */ @@ -20,29 +18,31 @@ #define DEBUG_NAME2 2048 void ntfs_debug(int mask, const char *fmt, ...); -#ifdef NTFS_IN_LINUX_KERNEL + #include <linux/slab.h> -#define ntfs_malloc(size) kmalloc(size,GFP_KERNEL) + +#define ntfs_malloc(size) kmalloc(size, GFP_KERNEL) + #define ntfs_free(ptr) kfree(ptr) -#else -void *ntfs_malloc(int size); -void ntfs_free(void *block); -#endif + void ntfs_bzero(void *s, int n); + void ntfs_memcpy(void *dest, const void *src, ntfs_size_t n); + void ntfs_memmove(void *dest, const void *src, ntfs_size_t n); + void ntfs_error(const char *fmt,...); + int ntfs_read_mft_record(ntfs_volume *vol, int mftno, char *buf); + int ntfs_getput_clusters(ntfs_volume *pvol, int cluster, ntfs_size_t offs, - ntfs_io *buf); + ntfs_io *buf); + ntfs_time64_t ntfs_now(void); + int ntfs_dupuni2map(ntfs_volume *vol, ntfs_u16 *in, int in_len, char **out, - int *out_len); + int *out_len); + int ntfs_dupmap2uni(ntfs_volume *vol, char* in, int in_len, ntfs_u16 **out, - int *out_len); + int *out_len); -/* - * Local variables: - * c-file-style: "linux" - * End: - */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ntfs/sysctl.h linux.ac/fs/ntfs/sysctl.h --- linux.vanilla/fs/ntfs/sysctl.h Sat Jan 2 18:24:46 1999 +++ linux.ac/fs/ntfs/sysctl.h Tue Apr 3 17:55:13 2001 @@ -1,28 +1,17 @@ -/* - * sysctl.h - * Header file for sysctl.c +/* sysctl.h - Header file for sysctl.c * * Copyright (C) 1997 Martin von Löwis * Copyright (C) 1997 Régis Duchesne * */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #ifdef DEBUG -extern int ntdebug; + extern int ntdebug; -void ntfs_sysctl(int add); + void ntfs_sysctl(int add); -#define SYSCTL(x) ntfs_sysctl(x) + #define SYSCTL(x) ntfs_sysctl(x) #else -#define SYSCTL(x) + #define SYSCTL(x) #endif /* DEBUG */ -/* - * Local variables: - * c-file-style: "linux" - * End: - */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ntfs/util.c linux.ac/fs/ntfs/util.c --- linux.vanilla/fs/ntfs/util.c Tue May 2 21:46:53 2000 +++ linux.ac/fs/ntfs/util.c Tue Apr 3 17:55:13 2001 @@ -1,9 +1,8 @@ -/* - * util.c - * Miscellaneous support +/* util.c - Miscellaneous support * * Copyright (C) 1997,1999 Martin von Löwis * Copyright (C) 1997 Régis Duchesne + * Copyright (C) 2001 Anton Altaparmakov (AIA) * * The utf8 routines are copied from Python wstrop module. */ @@ -14,75 +13,66 @@ #include <linux/string.h> #include <linux/errno.h> -/* FreeBSD doesn't seem to have EILSEQ in errno.h */ -#ifndef EILSEQ -# define EILSEQ EINVAL -#endif #include "support.h" /* Converts a single wide character to a sequence of utf8 bytes. * The character is represented in host byte order. - * Returns the number of bytes, or 0 on error. - */ -static int -to_utf8(ntfs_u16 c,unsigned char* buf) + * Returns the number of bytes, or 0 on error. */ +static int to_utf8(ntfs_u16 c, unsigned char* buf) { - if(c==0) - return 0; /* No support for embedded 0 runes */ - if(c<0x80){ - if(buf)buf[0]=(unsigned char)c; + if (c == 0) + return 0; /* No support for embedded 0 runes. */ + if (c < 0x80) { + if (buf) + buf[0] = (unsigned char)c; return 1; } - if(c<0x800){ - if(buf){ - buf[0] = 0xc0 | (c>>6); + if (c < 0x800) { + if (buf) { + buf[0] = 0xc0 | (c >> 6); buf[1] = 0x80 | (c & 0x3f); } return 2; } - if(c<0x10000){ - if(buf){ - buf[0] = 0xe0 | (c>>12); - buf[1] = 0x80 | ((c>>6) & 0x3f); + if (c < 0x10000) { + if (buf) { + buf[0] = 0xe0 | (c >> 12); + buf[1] = 0x80 | ((c >> 6) & 0x3f); buf[2] = 0x80 | (c & 0x3f); } return 3; } - /* We don't support characters above 0xFFFF in NTFS */ + /* We don't support characters above 0xFFFF in NTFS. */ return 0; } /* Decodes a sequence of utf8 bytes into a single wide character. * The character is returned in host byte order. - * Returns the number of bytes consumed, or 0 on error. - */ -static int -from_utf8(const unsigned char* str,ntfs_u16 *c) + * Returns the number of bytes consumed, or 0 on error. */ +static int from_utf8(const unsigned char* str, ntfs_u16 *c) { - int l=0,i; + int l = 0, i; - if(*str<0x80){ + if (*str < 0x80) { *c = *str; return 1; } - if(*str<0xc0) /* lead byte must not be 10xxxxxx */ - return 0; /* is c0 a possible lead byte? */ - if(*str<0xe0){ /* 110xxxxx */ + if (*str < 0xc0) /* Lead byte must not be 10xxxxxx. */ + return 0; /* Is c0 a possible lead byte? */ + if (*str < 0xe0) { /* 110xxxxx */ *c = *str & 0x1f; - l=2; - }else if(*str<0xf0){ /* 1110xxxx */ + l = 2; + } else if (*str < 0xf0) { /* 1110xxxx */ *c = *str & 0xf; - l=3; - }else if(*str<0xf8){ /* 11110xxx */ + l = 3; + } else if (*str < 0xf8) { /* 11110xxx */ *c = *str & 7; - l=4; - }else /* We don't support characters above 0xFFFF in NTFS */ + l = 4; + } else /* We don't support characters above 0xFFFF in NTFS. */ return 0; - - - for(i=1;i<l;i++){ - /* all other bytes must be 10xxxxxx */ - if((str[i] & 0xc0) != 0x80) + for (i = 1; i < l; i++) { + /* All other bytes must be 10xxxxxx. */ + if ((str[i] & 0xc0) != 0x80) return 0; *c <<= 6; *c |= str[i] & 0x3f; @@ -93,196 +83,195 @@ /* Converts wide string to UTF-8. Expects two in- and two out-parameters. * Returns 0 on success, or error code. * The caller has to free the result string. - * There is no support for UTF-16, yet - */ -static int ntfs_dupuni2utf8(ntfs_u16* in, int in_len,char **out,int *out_len) + * There is no support for UTF-16, yet. */ +static int ntfs_dupuni2utf8(ntfs_u16* in, int in_len, char **out, int *out_len) { - int i,tmp; + int i, tmp; int len8; unsigned char *result; - ntfs_debug(DEBUG_NAME1,"converting l=%d\n",in_len); - /* count the length of the resulting UTF-8 */ - for(i=len8=0;i<in_len;i++){ - tmp=to_utf8(NTFS_GETU16(in+i),0); - if(!tmp) + ntfs_debug(DEBUG_NAME1, "converting l = %d\n", in_len); + /* Count the length of the resulting UTF-8. */ + for (i = len8 = 0; i < in_len; i++){ + tmp = to_utf8(NTFS_GETU16(in + i), 0); + if (!tmp) /* invalid character */ - return EILSEQ; - len8+=tmp; + return -EILSEQ; + len8 += tmp; } - *out=result=ntfs_malloc(len8+1); /* allow for zero-termination */ + *out = result = ntfs_malloc(len8 + 1); /* allow for zero-termination */ - if(!result) - return ENOMEM; - result[len8]='\0'; - *out_len=len8; - for(i=len8=0;i<in_len;i++) - len8+=to_utf8(NTFS_GETU16(in+i),result+len8); - ntfs_debug(DEBUG_NAME1,"result %p:%s\n",result,result); + if (!result) + return -ENOMEM; + result[len8] = '\0'; + *out_len = len8; + for (i = len8 = 0; i < in_len; i++) + len8 += to_utf8(NTFS_GETU16(in + i), result + len8); + ntfs_debug(DEBUG_NAME1, "result %p:%s\n", result, result); return 0; } /* Converts an UTF-8 sequence to a wide string. Same conventions as the - * previous function - */ -static int ntfs_duputf82uni(unsigned char* in, int in_len,ntfs_u16** out,int *out_len) + * previous function. */ +static int ntfs_duputf82uni(unsigned char* in, int in_len, ntfs_u16** out, + int *out_len) { - int i,tmp; + int i, tmp; int len16; - ntfs_u16* result; ntfs_u16 wtmp; - for(i=len16=0;i<in_len;i+=tmp,len16++){ - tmp=from_utf8(in+i,&wtmp); - if(!tmp) - return EILSEQ; - } - *out=result=ntfs_malloc(2*(len16+1)); - if(!result) - return ENOMEM; - result[len16]=0; - *out_len=len16; - for(i=len16=0;i<in_len;i+=tmp,len16++) + + for (i = len16 = 0; i < in_len; i += tmp, len16++) { + tmp = from_utf8(in + i, &wtmp); + if (!tmp) + return -EILSEQ; + } + *out = result = ntfs_malloc(2 * (len16 + 1)); + if (!result) + return -ENOMEM; + result[len16] = 0; + *out_len = len16; + for (i = len16 = 0; i < in_len; i += tmp, len16++) { - tmp=from_utf8(in+i, &wtmp); - NTFS_PUTU16(result+len16, wtmp); + tmp = from_utf8(in + i, &wtmp); + NTFS_PUTU16(result + len16, wtmp); } return 0; } -/* See above. Produces ISO-8859-1 from wide strings */ -static int ntfs_dupuni288591(ntfs_u16* in,int in_len,char** out,int *out_len) +/* See above. Produces ISO-8859-1 from wide strings. */ +static int ntfs_dupuni288591(ntfs_u16* in, int in_len, char** out, int *out_len) { int i; char *result; - /* check for characters out of range */ - for(i=0;i<in_len;i++) - if(NTFS_GETU16(in+i)>=256) - return EILSEQ; - *out=result=ntfs_malloc(in_len+1); - if(!result) - return ENOMEM; - result[in_len]='\0'; - *out_len=in_len; - for(i=0;i<in_len;i++) - result[i]=(unsigned char)NTFS_GETU16(in+i); + /* Check for characters out of range. */ + for (i = 0; i < in_len; i++) + if (NTFS_GETU16(in + i) >= 256) + return -EILSEQ; + *out = result = ntfs_malloc(in_len + 1); + if (!result) + return -ENOMEM; + result[in_len] = '\0'; + *out_len = in_len; + for (i = 0; i < in_len; i++) + result[i] = (unsigned char)NTFS_GETU16(in + i); return 0; } -/* See above */ -static int ntfs_dup885912uni(unsigned char* in,int in_len,ntfs_u16 **out,int *out_len) +/* See above. */ +static int ntfs_dup885912uni(unsigned char* in, int in_len, ntfs_u16 **out, + int *out_len) { int i; ntfs_u16* result; - *out=result=ntfs_malloc(2*in_len); - if(!result) - return ENOMEM; - *out_len=in_len; - for(i=0;i<in_len;i++) - NTFS_PUTU16(result+i,in[i]); + *out = result = ntfs_malloc(2 * in_len); + if (!result) + return -ENOMEM; + *out_len = in_len; + for (i = 0; i < in_len; i++) + NTFS_PUTU16(result + i, in[i]); return 0; } /* Encodings dispatcher */ -int ntfs_encodeuni(ntfs_volume *vol,ntfs_u16 *in, int in_len, - char **out, int *out_len) +int ntfs_encodeuni(ntfs_volume *vol, ntfs_u16 *in, int in_len, char **out, + int *out_len) { - if(vol->nct & nct_utf8) - return ntfs_dupuni2utf8(in,in_len,out,out_len); - else if(vol->nct & nct_iso8859_1) - return ntfs_dupuni288591(in,in_len,out,out_len); - else if(vol->nct & (nct_map|nct_uni_xlate)) - /* uni_xlate is handled inside map */ - return ntfs_dupuni2map(vol,in,in_len,out,out_len); + if (vol->nct & nct_utf8) + return ntfs_dupuni2utf8(in, in_len, out, out_len); + else if (vol->nct & nct_iso8859_1) + return ntfs_dupuni288591(in, in_len, out, out_len); + else if(vol->nct & (nct_map | nct_uni_xlate)) + /* uni_xlate is handled inside map. */ + return ntfs_dupuni2map(vol, in, in_len, out, out_len); else - return EINVAL; /* unknown encoding */ + return -EINVAL; /* unknown encoding */ } -int ntfs_decodeuni(ntfs_volume *vol,char *in, int in_len, - ntfs_u16 **out, int *out_len) +int ntfs_decodeuni(ntfs_volume *vol, char *in, int in_len, ntfs_u16 **out, + int *out_len) { - if(vol->nct & nct_utf8) - return ntfs_duputf82uni(in,in_len,out,out_len); - else if(vol->nct & nct_iso8859_1) - return ntfs_dup885912uni(in,in_len,out,out_len); - else if(vol->nct & (nct_map | nct_uni_xlate)) - return ntfs_dupmap2uni(vol,in,in_len,out,out_len); + if (vol->nct & nct_utf8) + return ntfs_duputf82uni(in, in_len, out, out_len); + else if (vol->nct & nct_iso8859_1) + return ntfs_dup885912uni(in, in_len, out, out_len); + else if (vol->nct & (nct_map | nct_uni_xlate)) + return ntfs_dupmap2uni(vol, in, in_len, out, out_len); else - return EINVAL; + return -EINVAL; } -/* Same address space copies */ -void ntfs_put(ntfs_io *dest,void *src,ntfs_size_t n) +/* Same address space copies. */ +void ntfs_put(ntfs_io *dest, void *src, ntfs_size_t n) { - ntfs_memcpy(dest->param,src,n); - ((char*)dest->param)+=n; + ntfs_memcpy(dest->param, src, n); + ((char*)dest->param) += n; } -void ntfs_get(void* dest,ntfs_io *src,ntfs_size_t n) +void ntfs_get(void* dest, ntfs_io *src, ntfs_size_t n) { - ntfs_memcpy(dest,src->param,n); - ((char*)src->param)+=n; + ntfs_memcpy(dest, src->param, n); + ((char*)src->param) += n; } void *ntfs_calloc(int size) { - void *result=ntfs_malloc(size); - if(result) - ntfs_bzero(result,size); + void *result = ntfs_malloc(size); + if (result) + ntfs_bzero(result, size); return result; } #if 0 -/* copy len unicode characters from from to to :) */ -void ntfs_uni2ascii(char *to,char *from,int len) +/* Copy len unicode characters from from to to. :) */ +void ntfs_uni2ascii(char *to, short int *from, int len) { int i; - for(i=0;i<len;i++) - to[i]=from[2*i]; - to[i]='\0'; + for (i = 0; i < len; i++) + to[i] = NTFS_GETU16(from + i); + to[i] = '\0'; } #endif -/* copy len asci characters from from to to :) */ -void ntfs_ascii2uni(short int *to,char *from,int len) +/* Copy len ascii characters from from to to. :) */ +void ntfs_ascii2uni(short int *to, char *from, int len) { int i; - for(i=0;i<len;i++) - to[i]=from[i]; - to[i]=0; + for (i = 0; i < len; i++) + NTFS_PUTU16(to + i, from[i]); + to[i] = 0; } -/* strncmp for Unicode strings */ -int ntfs_uni_strncmp(short int* a,short int *b,int n) +/* strncmp for Unicode strings. */ +int ntfs_uni_strncmp(short int* a, short int *b, int n) { int i; - for(i=0;i<n;i++) + for(i = 0; i < n; i++) { - if(a[i]<b[i]) + if (NTFS_GETU16(a + i) < NTFS_GETU16(b + i)) return -1; - if(b[i]<a[i]) + if (NTFS_GETU16(b + i) < NTFS_GETU16(a + i)) return 1; - if (a[i] == 0) + if (NTFS_GETU16(a + i) == 0) return 0; } return 0; } -/* strncmp between Unicode and ASCII strings */ -int ntfs_ua_strncmp(short int* a,char* b,int n) +/* strncmp between Unicode and ASCII strings. */ +int ntfs_ua_strncmp(short int* a, char* b, int n) { int i; - for(i=0;i<n;i++) - { - if(NTFS_GETU16(a+i)<b[i]) + for (i = 0; i < n; i++) { + if(NTFS_GETU16(a + i) < b[i]) return -1; - if(b[i]<NTFS_GETU16(a+i)) + if(b[i] < NTFS_GETU16(a + i)) return 1; if (b[i] == 0) return 0; @@ -291,16 +280,13 @@ } /* Convert the NT UTC (based 1.1.1601, in hundred nanosecond units) - * into Unix UTC (based 1.1.1970, in seconds) - */ + * into Unix UTC (based 1.1.1970, in seconds). */ ntfs_time_t ntfs_ntutc2unixutc(ntfs_time64_t ntutc) { -/* - * This is very gross because - * 1: We must do 64-bit division on a 32-bit machine - * 2: We can't use libgcc for long long operations in the kernel - * 3: Floating point math in the kernel would corrupt user data - */ +/* This is very gross because: + * 1: We must do 64-bit division on a 32-bit machine. + * 2: We can't use libgcc for long long operations in the kernel. + * 3: Floating point math in the kernel would corrupt user data. */ const unsigned int D = 10000000; unsigned int H = (unsigned int)(ntutc >> 32); unsigned int L = (unsigned int)ntutc; @@ -310,63 +296,55 @@ /* It is best to subtract 0x019db1ded53e8000 first. */ /* Then the 1601-based date becomes a 1970-based date. */ - if(L < (unsigned)0xd53e8000) H--; + if (L < (unsigned)0xd53e8000) + H--; L -= (unsigned)0xd53e8000; H -= (unsigned)0x019db1de; - /* - * Now divide 64-bit numbers on a 32-bit machine :-) + /* Now divide 64-bit numbers on a 32-bit machine. :-) * With the subtraction already done, the result fits in 32 bits. * The numerator fits in 56 bits and the denominator fits - * in 24 bits, so we can shift by 8 bits to make this work. - */ + * in 24 bits, so we can shift by 8 bits to make this work. */ - numerator2 = (H<<8) | (L>>24); + numerator2 = (H << 8) | (L >> 24); result = (numerator2 / D); /* shifted 24 right!! */ lowseconds = result << 24; - numerator2 = ((numerator2-result*D)<<8) | ((L>>16)&0xff); + numerator2 = ((numerator2 - result * D) << 8) | ((L >> 16) & 0xff); result = (numerator2 / D); /* shifted 16 right!! */ lowseconds |= result << 16; - numerator2 = ((numerator2-result*D)<<8) | ((L>>8)&0xff); + numerator2 = ((numerator2 - result * D) << 8) | ((L >> 8) & 0xff); result = (numerator2 / D); /* shifted 8 right!! */ lowseconds |= result << 8; - numerator2 = ((numerator2-result*D)<<8) | (L&0xff); + numerator2 = ((numerator2 - result * D) << 8) | (L & 0xff); result = (numerator2 / D); /* not shifted */ lowseconds |= result; return lowseconds; } -/* Convert the Unix UTC into NT UTC */ +/* Convert the Unix UTC into NT UTC. */ ntfs_time64_t ntfs_unixutc2ntutc(ntfs_time_t t) { - return ((t + (ntfs_time64_t)(369*365+89)*24*3600) * 10000000); + return ((t + (ntfs_time64_t)(369 * 365 + 89) * 24 * 3600) * 10000000); } /* Fill index name. */ - -void -ntfs_indexname(char *buf, int type) +void ntfs_indexname(char *buf, int type) { - char hex[]="0123456789ABCDEF"; + char hex[] = "0123456789ABCDEF"; int index; - *buf++='$'; - *buf++='I'; - for (index=24; index>0; index-=4) - if((0xF << index) & type) + *buf++ = '$'; + *buf++ = 'I'; + for (index = 24; index > 0; index -= 4) + if ((0xF << index) & type) break; - while(index>=0) { + while (index >= 0) { *buf++ = hex[(type >> index) & 0xF]; - index-=4; + index -= 4; } - *buf='\0'; + *buf = '\0'; } -/* - * Local variables: - * c-file-style: "linux" - * End: - */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ntfs/util.h linux.ac/fs/ntfs/util.h --- linux.vanilla/fs/ntfs/util.h Sat Jan 2 18:24:46 1999 +++ linux.ac/fs/ntfs/util.h Tue Apr 3 17:55:13 2001 @@ -1,55 +1,64 @@ -/* - * util.h - * Header file for util.c +/* util.h - Header file for util.c * * Copyright (C) 1997 Régis Duchesne + * Copyright (C) 2001 Anton Altaparmakov */ -/* Which character set is used for file names */ -/* Translate everything to UTF-8 */ +/* Which character set is used for file names. */ +/* Translate everything to UTF-8. */ #define nct_utf8 1 -/* Translate to 8859-1 */ +/* Translate to 8859-1. */ #define nct_iso8859_1 2 -/* Quote unprintables with : */ +/* Quote unprintables with ":". */ #define nct_uni_xlate 4 -/* Do that in the vfat way instead of the documented way */ +/* Do that in the vfat way instead of the documented way. */ #define nct_uni_xlate_vfat 8 -/* Use a mapping table to determine printables */ +/* Use a mapping table to determine printables. */ #define nct_map 16 -/* The first 11 inodes correspond to special files */ -#define FILE_MFT 0 -#define FILE_MFTMIRR 1 -#define FILE_LOGFILE 2 -#define FILE_VOLUME 3 -#define FILE_ATTRDEF 4 -#define FILE_ROOT 5 -#define FILE_BITMAP 6 -#define FILE_BOOT 7 -#define FILE_BADCLUS 8 -#define FILE_QUOTA 9 -#define FILE_UPCASE 10 - +/* The first 16 inodes correspond to NTFS special files */ +typedef enum { + FILE_$Mft = 0, + FILE_$MftMirr = 1, + FILE_$LogFile = 2, + FILE_$Volume = 3, + FILE_$AttrDef = 4, + FILE_$root = 5, + FILE_$BitMap = 6, + FILE_$Boot = 7, + FILE_$BadClus = 8, + FILE_$Secure = 9, + FILE_$UpCase = 10, + FILE_$Extend = 11, + FILE_Reserved12 = 12, + FILE_Reserved13 = 13, + FILE_Reserved14 = 14, + FILE_Reserved15 = 15, +} NTFS_SYSTEM_FILES; + /* Memory management */ void *ntfs_calloc(int size); /* String operations */ /* Copy Unicode <-> ASCII */ #if 0 -void ntfs_uni2ascii(char *to,char *from,int len); +void ntfs_uni2ascii(char *to, char *from, int len); #endif -void ntfs_ascii2uni(short int *to,char *from,int len); +void ntfs_ascii2uni(short int *to, char *from, int len); + /* Comparison */ -int ntfs_uni_strncmp(short int* a,short int *b,int n); -int ntfs_ua_strncmp(short int* a,char* b,int n); +int ntfs_uni_strncmp(short int* a, short int *b, int n); +int ntfs_ua_strncmp(short int* a, char* b, int n); /* Same address space copies */ void ntfs_put(ntfs_io *dest, void *src, ntfs_size_t n); void ntfs_get(void* dest, ntfs_io *src, ntfs_size_t n); /* Charset conversion */ -int ntfs_encodeuni(ntfs_volume *vol,ntfs_u16 *in, int in_len,char **out, int *out_len); -int ntfs_decodeuni(ntfs_volume *vol,char *in, int in_len, ntfs_u16 **out, int *out_len); +int ntfs_encodeuni(ntfs_volume *vol, ntfs_u16 *in, int in_len, char **out, + int *out_len); +int ntfs_decodeuni(ntfs_volume *vol, char *in, int in_len, ntfs_u16 **out, + int *out_len); /* Time conversion */ /* NT <-> Unix */ @@ -59,8 +68,3 @@ /* Attribute names */ void ntfs_indexname(char *buf, int type); -/* - * Local variables: - * c-file-style: "linux" - * End: - */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/open.c linux.ac/fs/open.c --- linux.vanilla/fs/open.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/open.c Tue Apr 3 17:55:13 2001 @@ -14,6 +14,7 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/tty.h> +#include <linux/pagemap.h> #include <asm/uaccess.h> @@ -75,7 +76,7 @@ struct inode *inode = dentry->d_inode; int error; struct iattr newattrs; - + /* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */ if (length < 0) return -EINVAL; @@ -103,7 +104,12 @@ goto out; inode = nd.dentry->d_inode; - error = -EACCES; + /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ + error = -EISDIR; + if (S_ISDIR(inode->i_mode)) + goto dput_and_out; + + error = -EINVAL; if (!S_ISREG(inode->i_mode)) goto dput_and_out; @@ -111,12 +117,8 @@ if (error) goto dput_and_out; - error = -EROFS; - if (IS_RDONLY(inode)) - goto dput_and_out; - error = -EPERM; - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + if (IS_APPEND(inode)) goto dput_and_out; /* @@ -145,10 +147,11 @@ asmlinkage long sys_truncate(const char * path, unsigned long length) { - return do_sys_truncate(path, length); + /* on 32-bit boxen it will cut the range 2^31--2^32-1 off */ + return do_sys_truncate(path, (long)length); } -static inline long do_sys_ftruncate(unsigned int fd, loff_t length) +static inline long do_sys_ftruncate(unsigned int fd, loff_t length, int small) { struct inode * inode; struct dentry *dentry; @@ -162,13 +165,24 @@ file = fget(fd); if (!file) goto out; + + /* explicitly opened as large or we are on 64-bit box */ + if (file->f_flags & O_LARGEFILE) + small = 0; + dentry = file->f_dentry; inode = dentry->d_inode; - error = -EACCES; + error = -EINVAL; if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) goto out_putf; + + error = -EINVAL; + /* Cannot ftruncate over 2^31 bytes without large file support */ + if (small && length > MAX_NON_LFS) + goto out_putf; + error = -EPERM; - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + if (IS_APPEND(inode)) goto out_putf; error = locks_verify_truncate(inode, file, length); @@ -182,7 +196,7 @@ asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length) { - return do_sys_ftruncate(fd, length); + return do_sys_ftruncate(fd, length, 1); } /* LFS versions of truncate are only needed on 32 bit machines */ @@ -194,7 +208,7 @@ asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length) { - return do_sys_ftruncate(fd, length); + return do_sys_ftruncate(fd, length, 0); } #endif @@ -506,7 +520,7 @@ error = -ENOENT; if (!(inode = dentry->d_inode)) { - printk("chown_common: NULL inode\n"); + printk(KERN_ERR "chown_common: NULL inode\n"); goto out; } error = -EROFS; @@ -553,7 +567,7 @@ newattrs.ia_mode &= ~S_ISGID; newattrs.ia_valid |= ATTR_MODE; } - error = DQUOT_TRANSFER(dentry, &newattrs); + error = notify_change(dentry, &newattrs); out: return error; } @@ -730,7 +744,7 @@ #if 1 /* Sanity check */ if (files->fd[fd] != NULL) { - printk("get_unused_fd: slot %d not NULL!\n", fd); + printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd); files->fd[fd] = NULL; } #endif @@ -793,7 +807,7 @@ int retval; if (!file_count(filp)) { - printk("VFS: Close: file count is 0\n"); + printk(KERN_ERR "VFS: Close: file count is 0\n"); return 0; } retval = 0; @@ -847,3 +861,20 @@ } return -EPERM; } + +/* + * Called when an inode is about to be open. + * We use this to disallow opening RW large files on 32bit systems if + * the caller didn't specify O_LARGEFILE. On 64bit systems we force + * on this flag in sys_open. + */ + +int generic_file_open (struct inode * inode, struct file * filp) +{ + if (!(filp->f_flags & O_LARGEFILE) && + inode->i_size > MAX_NON_LFS) + return -EFBIG; + return 0; +} + +EXPORT_SYMBOL(generic_file_open); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/partitions/Makefile linux.ac/fs/partitions/Makefile --- linux.vanilla/fs/partitions/Makefile Fri Dec 29 22:07:23 2000 +++ linux.ac/fs/partitions/Makefile Mon Apr 9 23:46:07 2001 @@ -9,7 +9,7 @@ O_TARGET := partitions.o -export-objs := check.o +export-objs := check.o ibm.o obj-y := check.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/partitions/ibm.c linux.ac/fs/partitions/ibm.c --- linux.vanilla/fs/partitions/ibm.c Sat Feb 17 00:02:37 2001 +++ linux.ac/fs/partitions/ibm.c Mon Apr 9 23:46:07 2001 @@ -1,14 +1,17 @@ /* * File...........: linux/fs/partitions/ibm.c * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> + * Volker Sameske <sameske@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * History of changes (starts July 2000) - * 07/10/00 Fixed detection of CMS formatted disks - + * 07/10/00 Fixed detection of CMS formatted disks + * 02/13/00 VTOC partition support added */ +#include <linux/config.h> +#include <linux/module.h> #include <linux/fs.h> #include <linux/genhd.h> #include <linux/kernel.h> @@ -25,145 +28,177 @@ #include "ibm.h" #include "check.h" +#include <asm/vtoc.h> #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) /* We hook in when DASD is a module... */ int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL; +int (*genhd_dasd_fillgeo)(int,struct hd_geometry *) = NULL; +EXPORT_SYMBOL(genhd_dasd_fillgeo); +EXPORT_SYMBOL(genhd_dasd_name); #endif /* LINUX_IS_24 */ typedef enum { - ibm_partition_none = 0, - ibm_partition_lnx1 = 1, - ibm_partition_vol1 = 3, - ibm_partition_cms1 = 4 + ibm_partition_lnx1 = 0, + ibm_partition_vol1 = 1, + ibm_partition_cms1 = 2, + ibm_partition_none = 3 } ibm_partition_t; +static char* part_names[] = { [ibm_partition_lnx1] = "LNX1", + [ibm_partition_vol1] = "VOL1", + [ibm_partition_cms1] = "CMS1", + [ibm_partition_none] = "(nonl)" +}; + static ibm_partition_t get_partition_type ( char * type ) { - static char lnx[5]="LNX1"; - static char vol[5]="VOL1"; - static char cms[5]="CMS1"; - if ( ! strncmp ( lnx, "LNX1",4 ) ) { - ASCEBC(lnx,4); - ASCEBC(vol,4); - ASCEBC(cms,4); - } - if ( ! strncmp (type,lnx,4) || - ! strncmp (type,"LNX1",4) ) - return ibm_partition_lnx1; - if ( ! strncmp (type,vol,4) ) - return ibm_partition_vol1; - if ( ! strncmp (type,cms,4) ) - return ibm_partition_cms1; - return ibm_partition_none; + int i; + for ( i = 0; i < 3; i ++) { + if ( ! strncmp (type,part_names[i],4) ) + break; + } + return i; +} + +/* + * add the two default partitions + * - whole dasd + * - whole dasd without "offset" + */ +static inline void +two_partitions(struct gendisk *hd, + int minor, + int blocksize, + int offset, + int size) { + + add_gd_partition( hd, minor, 0,size); + add_gd_partition( hd, minor + 1, + offset * (blocksize >> 9), + size-offset*(blocksize>>9)); +} + + +/* + * compute the block number from a + * cyl-cyl-head-head structure + */ +static inline int +cchh2blk (cchh_t *ptr, struct hd_geometry *geo) { + return ptr->cc * geo->heads * geo->sectors + + ptr->hh * geo->sectors; +} + + +/* + * compute the block number from a + * cyl-cyl-head-head-block structure + */ +static inline int +cchhb2blk (cchhb_t *ptr, struct hd_geometry *geo) { + return ptr->cc * geo->heads * geo->sectors + + ptr->hh * geo->sectors + + ptr->b; } int ibm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int first_part_minor) { - struct buffer_head *bh; + struct buffer_head *bh, *buf; ibm_partition_t partition_type; char type[5] = {0,}; char name[7] = {0,}; struct hd_geometry geo; - mm_segment_t old_fs; int blocksize; - struct file *filp = NULL; - struct inode *inode = NULL; - int offset, size; + int offset=0, size=0, psize=0, counter=0; + unsigned int blk; + format1_label_t f1; + volume_label_t vlabel; + if ( first_sector != 0 ) { + BUG(); + } + if ( !genhd_dasd_fillgeo ) { + return 0; + } + genhd_dasd_fillgeo(dev,&geo); blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)]; if ( blocksize <= 0 ) { return 0; } - set_blocksize(dev, blocksize); /* OUCH !! */ - - /* find out offset of volume label (partn table) */ - inode = get_empty_inode(); - inode -> i_rdev = dev; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - inode -> i_bdev = bdget(kdev_t_to_nr(dev)); -#endif /* KERNEL_VERSION */ - filp = (struct file *)kmalloc (sizeof(struct file),GFP_KERNEL); - if (!filp) - return 0; - memset(filp,0,sizeof(struct file)); - filp ->f_mode = 1; /* read only */ - blkdev_open(inode,filp); - old_fs=get_fs(); - set_fs(KERNEL_DS); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - inode-> i_bdev -> bd_op->ioctl (inode, filp, HDIO_GETGEO, (unsigned long)(&geo)); -#else - filp->f_op->ioctl (inode, filp, HDIO_GETGEO, (unsigned long)(&geo)); -#endif /* KERNEL_VERSION */ - set_fs(old_fs); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) - blkdev_put(inode->i_bdev,BDEV_FILE); -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - blkdev_close(inode,filp); -#else - blkdev_release(inode); -#endif /* LINUX_VERSION_CODE */ - size = hd -> sizes[MINOR(dev)]<<1; + set_blocksize(dev, blocksize); /* OUCH !! */ if ( ( bh = bread( dev, geo.start, blocksize) ) != NULL ) { - strncpy ( type,bh -> b_data, 4); + strncpy ( type,bh -> b_data + 0, 4); strncpy ( name,bh -> b_data + 4, 6); + memcpy (&vlabel, bh->b_data, sizeof(volume_label_t)); } else { return 0; } - if ( (*(char *)bh -> b_data) & 0x80 ) { - EBCASC(name,6); - } - switch ( partition_type = get_partition_type(type) ) { - case ibm_partition_lnx1: - offset = (geo.start + 1); - printk ( "(LNX1)/%6s:",name); - break; - case ibm_partition_vol1: - offset = 0; - size = 0; - printk ( "(VOL1)/%6s:",name); - break; + EBCASC(type,4); + EBCASC(name,6); + + partition_type = get_partition_type(type); + printk ( "%6s/%6s:",part_names[partition_type],name); + switch ( partition_type ) { case ibm_partition_cms1: - printk ( "(CMS1)/%6s:",name); - if (* (((long *)bh->b_data) + 13) == 0) { - /* disk holds a CMS filesystem */ - offset = (geo.start + 1); - printk ("(CMS)"); - } else { + if (* (((long *)bh->b_data) + 13) != 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)"); + } else { + offset = (geo.start + 1); + size = hd -> sizes[MINOR(dev)]<<1; } + two_partitions( hd, MINOR(dev), blocksize, + offset, size); break; + case ibm_partition_lnx1: case ibm_partition_none: - printk ( "(nonl)/ :"); - offset = (geo.start+1); + offset = (geo.start + 1); + size = hd -> sizes[MINOR(dev)]<<1; + two_partitions( hd, MINOR(dev), blocksize, + offset, size); + break; + case ibm_partition_vol1: + add_gd_partition(hd, MINOR(dev), 0, size); + + /* get block number and read then first format1 label */ + blk = cchhb2blk(&vlabel.vtoc, &geo) + 1; + if ((buf = bread( dev, blk, blocksize)) != NULL) { + memcpy (&f1, buf->b_data, sizeof(format1_label_t)); + bforget(buf); + } + + while (f1.DS1FMTID == _ascebc['1']) { + offset = cchh2blk(&f1.DS1EXT1.llimit, &geo); + psize = cchh2blk(&f1.DS1EXT1.ulimit, &geo) - + offset + 1; + + counter++; + add_gd_partition(hd, MINOR(dev) + counter, + offset * (blocksize >> 9), + psize * (blocksize >> 9)); + + blk++; + if ((buf = bread( dev, blk, blocksize)) != NULL) { + memcpy (&f1, buf->b_data, + sizeof(format1_label_t)); + bforget(buf); + } + } break; default: - offset = 0; - size = 0; - + add_gd_partition( hd, MINOR(dev), 0, 0); + add_gd_partition( hd, MINOR(dev) + 1, 0, 0); } -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - add_gd_partition( hd, MINOR(dev), 0,size); - add_gd_partition( hd, MINOR(dev) + 1, offset * (blocksize >> 9), - size-offset*(blocksize>>9)); -#else - add_partition( hd, MINOR(dev), 0,size,0); - add_partition( hd, MINOR(dev) + 1, offset * (blocksize >> 9), - size-offset*(blocksize>>9) ,0 ); -#endif /* LINUX_VERSION */ + printk ( "\n" ); bforget(bh); return 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/proc/array.c linux.ac/fs/proc/array.c --- linux.vanilla/fs/proc/array.c Tue Apr 3 17:32:26 2001 +++ linux.ac/fs/proc/array.c Tue Apr 10 18:20:00 2001 @@ -273,9 +273,6 @@ { char * orig = buffer; struct mm_struct *mm; -#if defined(CONFIG_ARCH_S390) - int line,len; -#endif buffer = task_name(task, buffer); buffer = task_state(task, buffer); @@ -291,8 +288,7 @@ buffer = task_sig(task, buffer); buffer = task_cap(task, buffer); #if defined(CONFIG_ARCH_S390) - for(line=0;(len=sprintf_regs(line,buffer,task,NULL,NULL))!=0;line++) - buffer+=len; + buffer = task_show_regs(task, buffer); #endif return buffer - orig; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/proc/generic.c linux.ac/fs/proc/generic.c --- linux.vanilla/fs/proc/generic.c Mon Dec 11 21:45:42 2000 +++ linux.ac/fs/proc/generic.c Tue Apr 10 00:47:42 2001 @@ -192,13 +192,22 @@ static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8]; +spinlock_t proc_alloc_map_lock = SPIN_LOCK_UNLOCKED; + static int make_inode_number(void) { - int i = find_first_zero_bit((void *) proc_alloc_map, PROC_NDYNAMIC); - if (i<0 || i>=PROC_NDYNAMIC) - return -1; + int i; + spin_lock(&proc_alloc_map_lock); + i = find_first_zero_bit((void *) proc_alloc_map, PROC_NDYNAMIC); + if (i<0 || i>=PROC_NDYNAMIC) { + i = -1; + goto out; + } set_bit(i, (void *) proc_alloc_map); - return PROC_DYNAMIC_FIRST + i; + i += PROC_DYNAMIC_FIRST; +out: + spin_unlock(&proc_alloc_map_lock); + return i; } static int proc_readlink(struct dentry *dentry, char *buffer, int buflen) @@ -428,7 +437,7 @@ ent->data = kmalloc((ent->size=strlen(dest))+1, GFP_KERNEL); if (!ent->data) { kfree(ent); - goto out; + return NULL; } strcpy((char*)ent->data,dest); @@ -531,6 +540,8 @@ proc_register(parent, ent); out: + if (ent == NULL) + printk(KERN_EMERG "create_proc_entry: failed to create entry for %s\n", name); return ent; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/proc/kmsg.c linux.ac/fs/proc/kmsg.c --- linux.vanilla/fs/proc/kmsg.c Sun Feb 27 04:33:07 2000 +++ linux.ac/fs/proc/kmsg.c Tue Apr 3 17:55:13 2001 @@ -14,7 +14,6 @@ #include <asm/uaccess.h> #include <asm/io.h> -extern unsigned long log_size; extern wait_queue_head_t log_wait; extern int do_syslog(int type, char * bug, int count); @@ -39,7 +38,7 @@ static unsigned int kmsg_poll(struct file *file, poll_table * wait) { poll_wait(file, &log_wait, wait); - if (log_size) + if (do_syslog(9, 0, 0)) return POLLIN | POLLRDNORM; return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/proc/proc_misc.c linux.ac/fs/proc/proc_misc.c --- linux.vanilla/fs/proc/proc_misc.c Tue Apr 3 17:32:26 2001 +++ linux.ac/fs/proc/proc_misc.c Tue Apr 3 17:55:13 2001 @@ -274,8 +274,10 @@ user += kstat.per_cpu_user[cpu]; nice += kstat.per_cpu_nice[cpu]; system += kstat.per_cpu_system[cpu]; +#if !defined(CONFIG_ARCH_S390) for (j = 0 ; j < NR_IRQS ; j++) sum += kstat.irqs[cpu][j]; +#endif } len = sprintf(page, "cpu %u %u %u %lu\n", user, nice, system, @@ -299,8 +301,10 @@ kstat.pswpout, sum ); +#if !defined(CONFIG_ARCH_S390) for (i = 0 ; i < NR_IRQS ; i++) len += sprintf(page + len, " %u", kstat_irqs(i)); +#endif len += sprintf(page + len, "\ndisk_io: "); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/proc/procfs_syms.c linux.ac/fs/proc/procfs_syms.c --- linux.vanilla/fs/proc/procfs_syms.c Mon Sep 11 16:41:07 2000 +++ linux.ac/fs/proc/procfs_syms.c Tue Apr 3 17:55:13 2001 @@ -19,6 +19,7 @@ EXPORT_SYMBOL(proc_net); EXPORT_SYMBOL(proc_bus); EXPORT_SYMBOL(proc_root_driver); +EXPORT_SYMBOL(proc_get_inode); static DECLARE_FSTYPE(proc_fs_type, "proc", proc_read_super, FS_SINGLE); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/proc/root.c linux.ac/fs/proc/root.c --- linux.vanilla/fs/proc/root.c Thu Nov 23 17:07:36 2000 +++ linux.ac/fs/proc/root.c Tue Apr 3 17:55:13 2001 @@ -32,6 +32,10 @@ #ifdef CONFIG_SYSCTL proc_sys_root = proc_mkdir("sys", 0); #endif +#if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE) + proc_mkdir("sys/fs", 0); + proc_mkdir("sys/fs/binfmt_misc", 0); +#endif proc_root_fs = proc_mkdir("fs", 0); proc_root_driver = proc_mkdir("driver", 0); #if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE) @@ -41,6 +45,9 @@ proc_tty_init(); #ifdef CONFIG_PROC_DEVICETREE proc_device_tree_init(); +#endif +#ifdef CONFIG_PPC_RTAS + proc_rtas_init(); #endif proc_bus = proc_mkdir("bus", 0); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ramfs/inode.c linux.ac/fs/ramfs/inode.c --- linux.vanilla/fs/ramfs/inode.c Sat Jan 6 07:06:19 2001 +++ linux.ac/fs/ramfs/inode.c Tue Apr 3 17:55:13 2001 @@ -4,6 +4,7 @@ * Copyright (C) 2000 Linus Torvalds. * 2000 Transmeta Corp. * + * Usage limits added by David Gibson, Linuxcare Australia. * This file is released under the GPL. */ @@ -28,8 +29,18 @@ #include <linux/init.h> #include <linux/string.h> #include <linux/locks.h> +#include <linux/highmem.h> +#include <linux/malloc.h> #include <asm/uaccess.h> +#include <linux/spinlock.h> + +#if PAGE_CACHE_SIZE % 1024 +#error Oh no, PAGE_CACHE_SIZE is not divisible by 1k! I cannot cope. +#endif + +#define IBLOCKS_PER_PAGE (PAGE_CACHE_SIZE / 512) +#define K_PER_PAGE (PAGE_CACHE_SIZE / 1024) /* some random number */ #define RAMFS_MAGIC 0x858458f6 @@ -40,8 +51,173 @@ static struct file_operations ramfs_file_operations; static struct inode_operations ramfs_dir_inode_operations; +/* + * ramfs super-block data in memory + */ +struct ramfs_sb_info { + /* Prevent races accessing the used block + * counts. Conceptually, this could probably be a semaphore, + * but the only thing we do while holding the lock is + * arithmetic, so there's no point */ + spinlock_t ramfs_lock; + + /* It is important that at least the free counts below be + signed. free_XXX may become negative if a limit is changed + downwards (by a remount) below the current usage. */ + + /* maximum number of pages in a file */ + long max_file_pages; + + /* max total number of data pages */ + long max_pages; + /* free_pages = max_pages - total number of pages currently in use */ + long free_pages; + + /* max number of inodes */ + long max_inodes; + /* free_inodes = max_inodes - total number of inodes currently in use */ + long free_inodes; + + /* max number of dentries */ + long max_dentries; + /* free_dentries = max_dentries - total number of dentries in use */ + long free_dentries; +}; + +#define RAMFS_SB(sb) ((struct ramfs_sb_info *)((sb)->u.generic_sbp)) + +/* + * Resource limit helper functions + */ + +static inline void lock_rsb(struct ramfs_sb_info *rsb) +{ + spin_lock(&(rsb->ramfs_lock)); +} + +static inline void unlock_rsb(struct ramfs_sb_info *rsb) +{ + spin_unlock(&(rsb->ramfs_lock)); +} + +/* Decrements the free inode count and returns true, or returns false + * if there are no free inodes */ +static int ramfs_alloc_inode(struct super_block *sb) +{ + struct ramfs_sb_info *rsb = RAMFS_SB(sb); + int ret = 1; + + lock_rsb(rsb); + if (!rsb->max_inodes || rsb->free_inodes > 0) + rsb->free_inodes--; + else + ret = 0; + unlock_rsb(rsb); + + return ret; +} + +/* Increments the free inode count */ +static void ramfs_dealloc_inode(struct super_block *sb) +{ + struct ramfs_sb_info *rsb = RAMFS_SB(sb); + + lock_rsb(rsb); + rsb->free_inodes++; + unlock_rsb(rsb); +} + +/* Decrements the free dentry count and returns true, or returns false + * if there are no free dentries */ +static int ramfs_alloc_dentry(struct super_block *sb) +{ + struct ramfs_sb_info *rsb = RAMFS_SB(sb); + int ret = 1; + + lock_rsb(rsb); + if (!rsb->max_dentries || rsb->free_dentries > 0) + rsb->free_dentries--; + else + ret = 0; + unlock_rsb(rsb); + + return ret; +} + +/* Increments the free dentry count */ +static void ramfs_dealloc_dentry(struct super_block *sb) +{ + struct ramfs_sb_info *rsb = RAMFS_SB(sb); + + lock_rsb(rsb); + rsb->free_dentries++; + unlock_rsb(rsb); +} + +/* If the given page can be added to the give inode for ramfs, return + * true and update the filesystem's free page count and the inode's + * i_blocks field. Always returns true if the file is already used by + * ramfs (ie. PageDirty(page) is true) */ +int ramfs_alloc_page(struct inode *inode, struct page *page) +{ + struct ramfs_sb_info *rsb = RAMFS_SB(inode->i_sb); + int ret = 1; + + if (PageDirty(page)) /* It's already been allocated */ + return 1; + + lock_rsb(rsb); + + if ( (rsb->free_pages > 0) && + ( !rsb->max_file_pages || + (inode->i_data.nrpages <= rsb->max_file_pages) ) ) { + inode->i_blocks += IBLOCKS_PER_PAGE; + rsb->free_pages--; + } else + ret = 0; + + unlock_rsb(rsb); + + return ret; +} + +void ramfs_dealloc_page(struct inode *inode, struct page *page) +{ + struct ramfs_sb_info *rsb = RAMFS_SB(inode->i_sb); + + if (! PageDirty(page)) /* The page was never allocated + this can happen if it was only read */ + return; + + lock_rsb(rsb); + + ClearPageDirty(page); + + rsb->free_pages++; + inode->i_blocks -= IBLOCKS_PER_PAGE; + + if (rsb->free_pages > rsb->max_pages) { + printk(KERN_ERR "ramfs: Error in page allocation, free_pages (%ld) > max_pages (%ld)\n", rsb->free_pages, rsb->max_pages); + } + + unlock_rsb(rsb); +} + + + static int ramfs_statfs(struct super_block *sb, struct statfs *buf) { + struct ramfs_sb_info *rsb = RAMFS_SB(sb); + + lock_rsb(rsb); + buf->f_blocks = rsb->max_pages; + buf->f_files = rsb->max_inodes; + + buf->f_bfree = rsb->free_pages; + buf->f_bavail = buf->f_bfree; + buf->f_ffree = rsb->free_inodes; + unlock_rsb(rsb); + buf->f_type = RAMFS_MAGIC; buf->f_bsize = PAGE_CACHE_SIZE; buf->f_namelen = 255; @@ -87,7 +263,13 @@ static int ramfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) { - void *addr = kmap(page); + struct inode *inode = (struct inode *)page->mapping->host; + void *addr; + + if (! ramfs_alloc_page(inode, page)) + return -ENOSPC; + + addr = (void *) kmap(page); if (!Page_Uptodate(page)) { memset(addr, 0, PAGE_CACHE_SIZE); flush_dcache_page(page); @@ -108,9 +290,21 @@ return 0; } +static void ramfs_truncatepage(struct page *page) +{ + struct inode *inode = (struct inode *)page->mapping->host; + + ramfs_dealloc_page(inode, page); +} + struct inode *ramfs_get_inode(struct super_block *sb, int mode, int dev) { - struct inode * inode = new_inode(sb); + struct inode * inode; + + if (! ramfs_alloc_inode(sb)) + return NULL; + + inode = new_inode(sb); if (inode) { inode->i_mode = mode; @@ -136,23 +330,35 @@ inode->i_op = &page_symlink_inode_operations; break; } - } + } else + ramfs_dealloc_inode(sb); + return inode; } /* - * File creation. Allocate an inode, and we're done.. + * File creation. Allocate an inode, update free inode and dentry counts + * and we're done.. */ static int ramfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev) { - struct inode * inode = ramfs_get_inode(dir->i_sb, mode, dev); + struct super_block *sb = dir->i_sb; + struct inode * inode; int error = -ENOSPC; + if (! ramfs_alloc_dentry(sb)) + return error; + + inode = ramfs_get_inode(dir->i_sb, mode, dev); + if (inode) { d_instantiate(dentry, inode); dget(dentry); /* Extra count - pin the dentry in core */ error = 0; + } else { + ramfs_dealloc_dentry(sb); } + return error; } @@ -171,11 +377,15 @@ */ static int ramfs_link(struct dentry *old_dentry, struct inode * dir, struct dentry * dentry) { + struct super_block *sb = dir->i_sb; struct inode *inode = old_dentry->d_inode; if (S_ISDIR(inode->i_mode)) return -EPERM; + if (! ramfs_alloc_dentry(sb)) + return -ENOSPC; + inode->i_nlink++; atomic_inc(&inode->i_count); /* New dentry reference */ dget(dentry); /* Extra pinning count for the created dentry */ @@ -222,6 +432,7 @@ */ static int ramfs_unlink(struct inode * dir, struct dentry *dentry) { + struct super_block *sb = dir->i_sb; int retval = -ENOTEMPTY; if (ramfs_empty(dentry)) { @@ -229,6 +440,9 @@ inode->i_nlink--; dput(dentry); /* Undo the count from "create" - this does all the work */ + + ramfs_dealloc_dentry(sb); + retval = 0; } return retval; @@ -244,6 +458,8 @@ */ static int ramfs_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir,struct dentry *new_dentry) { + struct super_block *sb = new_dir->i_sb; + int error = -ENOTEMPTY; if (ramfs_empty(new_dentry)) { @@ -251,6 +467,7 @@ if (inode) { inode->i_nlink--; dput(new_dentry); + ramfs_dealloc_dentry(sb); } error = 0; } @@ -270,6 +487,169 @@ return error; } +static void ramfs_delete_inode(struct inode *inode) +{ + ramfs_dealloc_inode(inode->i_sb); + + clear_inode(inode); +} + +static void ramfs_put_super(struct super_block *sb) +{ + kfree(sb->u.generic_sbp); +} + +struct ramfs_params { + long pages; + long filepages; + long inodes; + long dentries; +}; + +static int parse_options(char * options, struct ramfs_params *p) +{ + char save = 0, *savep = NULL, *optname, *value; + + p->pages = -1; + p->filepages = -1; + p->inodes = -1; + p->dentries = -1; + + for (optname = strtok(options,","); optname; + optname = strtok(NULL,",")) { + if ((value = strchr(optname,'=')) != NULL) { + save = *value; + savep = value; + *value++ = 0; + } + + if (!strcmp(optname, "maxfilesize") && value) { + p->filepages = simple_strtoul(value, &value, 0) + / K_PER_PAGE; + if (*value) + return -EINVAL; + } else if (!strcmp(optname, "maxsize") && value) { + p->pages = simple_strtoul(value, &value, 0) + / K_PER_PAGE; + if (*value) + return -EINVAL; + } else if (!strcmp(optname, "maxinodes") && value) { + p->inodes = simple_strtoul(value, &value, 0); + if (*value) + return -EINVAL; + } else if (!strcmp(optname, "maxdentries") && value) { + p->dentries = simple_strtoul(value, &value, 0); + if (*value) + return -EINVAL; + } + + if (optname != options) + *(optname-1) = ','; + if (value) + *savep = save; +/* if (ret == 0) */ +/* break; */ + } + + return 0; +} + +static void init_limits(struct ramfs_sb_info *rsb, struct ramfs_params *p) +{ + struct sysinfo si; + + si_meminfo(&si); + + /* By default we set the limits to be: + - Allow this ramfs to take up to half of all available RAM + - No limit on filesize (except no file may be bigger that + the total max size, obviously) + - dentries limited to one per 4k of data space + - No limit to the number of inodes (except that there + are never more inodes than dentries). + */ + rsb->max_pages = (si.totalram / 2); + + if (p->pages >= 0) + rsb->max_pages = p->pages; + + rsb->max_file_pages = 0; + if (p->filepages >= 0) + rsb->max_file_pages = p->filepages; + + rsb->max_dentries = rsb->max_pages * K_PER_PAGE / 4; + if (p->dentries >= 0) + rsb->max_dentries = p->dentries; + + rsb->max_inodes = 0; + if (p->inodes >= 0) + rsb->max_inodes = p->inodes; + + rsb->free_pages = rsb->max_pages; + rsb->free_inodes = rsb->max_inodes; + rsb->free_dentries = rsb->max_dentries; + + return; +} + +/* reset_limits is called during a remount to change the usage limits. + + This will suceed, even if the new limits are lower than current + usage. This is the intended behaviour - new allocations will fail + until usage falls below the new limit */ +static void reset_limits(struct ramfs_sb_info *rsb, struct ramfs_params *p) +{ + lock_rsb(rsb); + + if (p->pages >= 0) { + int used_pages = rsb->max_pages - rsb->free_pages; + + rsb->max_pages = p->pages; + rsb->free_pages = rsb->max_pages - used_pages; + } + + if (p->filepages >= 0) { + rsb->max_file_pages = p->filepages; + } + + + if (p->dentries >= 0) { + int used_dentries = rsb->max_dentries - rsb->free_dentries; + + rsb->max_dentries = p->dentries; + rsb->free_dentries = rsb->max_dentries - used_dentries; + } + + if (p->inodes >= 0) { + int used_inodes = rsb->max_inodes - rsb->free_inodes; + + rsb->max_inodes = p->inodes; + rsb->free_inodes = rsb->max_inodes - used_inodes; + } + + unlock_rsb(rsb); +} + +static int ramfs_remount(struct super_block * sb, int * flags, char * data) +{ + struct ramfs_params params; + struct ramfs_sb_info * rsb = RAMFS_SB(sb); + + if (parse_options((char *)data, ¶ms) != 0) + return -EINVAL; + + reset_limits(rsb, ¶ms); + + printk(KERN_DEBUG "ramfs: remounted with options: %s\n", + data ? (char *)data : "<defaults>" ); + printk(KERN_DEBUG "ramfs: max_pages=%ld max_file_pages=%ld \ +max_inodes=%ld max_dentries=%ld\n", + rsb->max_pages, rsb->max_file_pages, + rsb->max_inodes, rsb->max_dentries); + + return 0; +} + static int ramfs_sync_file(struct file * file, struct dentry *dentry, int datasync) { return 0; @@ -279,7 +659,8 @@ readpage: ramfs_readpage, writepage: ramfs_writepage, prepare_write: ramfs_prepare_write, - commit_write: ramfs_commit_write + commit_write: ramfs_commit_write, + truncatepage: ramfs_truncatepage, }; static struct file_operations ramfs_file_operations = { @@ -310,17 +691,40 @@ static struct super_operations ramfs_ops = { statfs: ramfs_statfs, put_inode: force_delete, + delete_inode: ramfs_delete_inode, + put_super: ramfs_put_super, + remount_fs: ramfs_remount, }; +/* + * Initialisation + */ + static struct super_block *ramfs_read_super(struct super_block * sb, void * data, int silent) { struct inode * inode; struct dentry * root; + struct ramfs_sb_info * rsb; + struct ramfs_params params; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = RAMFS_MAGIC; sb->s_op = &ramfs_ops; + sb->s_maxbytes = MAX_NON_LFS; /* Why? */ + + rsb = kmalloc(sizeof(struct ramfs_sb_info), GFP_KERNEL); + RAMFS_SB(sb) = rsb; + if (!rsb) + return NULL; + + spin_lock_init(&rsb->ramfs_lock); + + if (parse_options((char *)data, ¶ms) != 0) + return NULL; + + init_limits(rsb, ¶ms); + inode = ramfs_get_inode(sb, S_IFDIR | 0755, 0); if (!inode) return NULL; @@ -331,6 +735,13 @@ return NULL; } sb->s_root = root; + + printk(KERN_DEBUG "ramfs: mounted with options: %s\n", + data ? (char *)data : "<defaults>" ); + printk(KERN_DEBUG "ramfs: max_pages=%ld max_file_pages=%ld \ +max_inodes=%ld max_dentries=%ld\n", + rsb->max_pages, rsb->max_file_pages, + rsb->max_inodes, rsb->max_dentries); return sb; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/read_write.c linux.ac/fs/read_write.c --- linux.vanilla/fs/read_write.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/read_write.c Tue Apr 3 17:55:13 2001 @@ -36,7 +36,7 @@ offset += file->f_pos; } retval = -EINVAL; - if (offset >= 0) { + if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) { if (offset != file->f_pos) { file->f_pos = offset; file->f_reada = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/reiserfs/fix_node.c linux.ac/fs/reiserfs/fix_node.c --- linux.vanilla/fs/reiserfs/fix_node.c Tue Apr 3 17:32:26 2001 +++ linux.ac/fs/reiserfs/fix_node.c Tue Apr 3 17:55:13 2001 @@ -479,7 +479,7 @@ // do not count last 'end_bytes' units of 'end_item'-th item end_bytes = (to_bytes != -1) ? to_bytes : 0; - /* go through all item begining from the start_item-th item and ending by + /* go through all item beginning from the start_item-th item and ending by the end_item-th item. Do not count first 'start_bytes' units of 'start_item'-th item and last 'end_bytes' of 'end_item'-th item */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/reiserfs/prints.c linux.ac/fs/reiserfs/prints.c --- linux.vanilla/fs/reiserfs/prints.c Mon Jan 15 23:31:19 2001 +++ linux.ac/fs/reiserfs/prints.c Tue Apr 3 17:55:13 2001 @@ -259,14 +259,14 @@ { do_reiserfs_warning; /* console_print (error_buf); */ - printk ("%s", error_buf); + printk (KERN_WARNING "%s", error_buf); } void reiserfs_debug (struct super_block *s, int level, const char * fmt, ...) { #ifdef CONFIG_REISERFS_CHECK do_reiserfs_warning; - printk ("%s", error_buf); + printk (KERN_DEBUG "%s", error_buf); #else ; #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/reiserfs/stree.c linux.ac/fs/reiserfs/stree.c --- linux.vanilla/fs/reiserfs/stree.c Tue Apr 3 17:32:26 2001 +++ linux.ac/fs/reiserfs/stree.c Tue Apr 3 17:55:13 2001 @@ -380,7 +380,7 @@ /* Parent at the path is not in the tree now. */ if ( ! B_IS_IN_TREE(p_s_parent = PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)) ) return &MIN_KEY; - /* Check whether position in the parrent is correct. */ + /* Check whether position in the parent is correct. */ if ( (n_position = PATH_OFFSET_POSITION(p_s_chk_path, n_path_offset)) > B_NR_ITEMS(p_s_parent) ) return &MIN_KEY; /* Check whether parent at the path really points to the child. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/reiserfs/super.c linux.ac/fs/reiserfs/super.c --- linux.vanilla/fs/reiserfs/super.c Tue Apr 3 17:32:26 2001 +++ linux.ac/fs/reiserfs/super.c Tue Apr 3 17:55:13 2001 @@ -412,6 +412,7 @@ SB_BUFFER_WITH_SB (s) = bh; SB_DISK_SUPER_BLOCK (s) = rs; s->s_op = &reiserfs_sops; + s->s_maxbytes = MAX_NON_LFS; return 0; } #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/romfs/inode.c linux.ac/fs/romfs/inode.c --- linux.vanilla/fs/romfs/inode.c Tue Apr 3 17:32:26 2001 +++ linux.ac/fs/romfs/inode.c Tue Apr 3 17:55:13 2001 @@ -403,9 +403,11 @@ void *buf; int result = -EIO; + page_cache_get(page); lock_kernel(); - get_page(page); - buf = page_address(page); + buf = kmap(page); + if (!buf) + goto err_out; /* 32 bit warning -- but not for us :) */ offset = page->index << PAGE_CACHE_SHIFT; @@ -428,7 +430,9 @@ UnlockPage(page); - __free_page(page); + kunmap(page); +err_out: + page_cache_release(page); unlock_kernel(); return result; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/smbfs/inode.c linux.ac/fs/smbfs/inode.c --- linux.vanilla/fs/smbfs/inode.c Tue Apr 3 17:32:26 2001 +++ linux.ac/fs/smbfs/inode.c Tue Apr 3 17:55:13 2001 @@ -549,7 +549,9 @@ attr->ia_size); if (error) goto out; - vmtruncate(inode, attr->ia_size); + error = vmtruncate(inode, attr->ia_size); + if (error) + goto out; refresh = 1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/smbfs/ioctl.c linux.ac/fs/smbfs/ioctl.c --- linux.vanilla/fs/smbfs/ioctl.c Wed Jul 19 06:30:34 2000 +++ linux.ac/fs/smbfs/ioctl.c Tue Apr 3 17:55:13 2001 @@ -45,7 +45,7 @@ if (!copy_from_user(&opt, (void *)arg, sizeof(opt))) result = smb_newconn(server, &opt); break; - default: + default:; } return result; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/smbfs/proc.c linux.ac/fs/smbfs/proc.c --- linux.vanilla/fs/smbfs/proc.c Tue Apr 3 17:32:26 2001 +++ linux.ac/fs/smbfs/proc.c Tue Apr 3 17:55:13 2001 @@ -697,7 +697,7 @@ #else /* * We don't want to be interrupted. For example, what if 'current' - * already has recieved a signal? sleep_on would terminate immediately + * already has received a signal? sleep_on would terminate immediately * and smbmount would not be able to re-establish connection. * * smbmount should be able to reconnect later, but it can't because @@ -712,7 +712,7 @@ if (server->state == CONN_VALID) { /* This should be changed to VERBOSE, except many smbfs problems is with the userspace daemon not reconnecting. */ - PARANOIA("sucessful, new pid=%d, generation=%d\n", + PARANOIA("successful, new pid=%d, generation=%d\n", server->conn_pid, server->generation); result = 1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/stat.c linux.ac/fs/stat.c --- linux.vanilla/fs/stat.c Tue Dec 5 20:29:39 2000 +++ linux.ac/fs/stat.c Tue Apr 3 17:55:13 2001 @@ -4,6 +4,7 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ +#include <linux/config.h> #include <linux/mm.h> #include <linux/errno.h> #include <linux/file.h> @@ -25,7 +26,7 @@ } -#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__) +#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) /* * For backward compatibility? Maybe this should be moved @@ -38,7 +39,7 @@ if (warncount > 0) { warncount--; - printk("VFS: Warning: %s using old stat() call. Recompile your binary.\n", + printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n", current->comm); } else if (warncount < 0) { /* it's laughable, but... */ @@ -53,7 +54,7 @@ SET_OLDSTAT_GID(tmp, inode->i_gid); tmp.st_rdev = kdev_t_to_nr(inode->i_rdev); #if BITS_PER_LONG == 32 - if (inode->i_size > 0x7fffffff) + if (inode->i_size > MAX_NON_LFS) return -EOVERFLOW; #endif tmp.st_size = inode->i_size; @@ -79,7 +80,7 @@ SET_STAT_GID(tmp, inode->i_gid); tmp.st_rdev = kdev_t_to_nr(inode->i_rdev); #if BITS_PER_LONG == 32 - if (inode->i_size > 0x7fffffff) + if (inode->i_size > MAX_NON_LFS) return -EOVERFLOW; #endif tmp.st_size = inode->i_size; @@ -126,7 +127,7 @@ } -#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__) +#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) /* * For backward compatibility? Maybe this should be moved * into arch/i386 instead? @@ -162,7 +163,7 @@ return error; } -#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__) +#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) /* * For backward compatibility? Maybe this should be moved @@ -200,7 +201,7 @@ return error; } -#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__) +#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) /* * For backward compatibility? Maybe this should be moved @@ -267,7 +268,7 @@ /* ---------- LFS-64 ----------- */ -#if !defined(__alpha__) && !defined (__ia64__) && !defined(__mips64) +#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips64) && !defined(CONFIG_ARCH_S390X) static long cp_new_stat64(struct inode * inode, struct stat64 * statbuf) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/super.c linux.ac/fs/super.c --- linux.vanilla/fs/super.c Tue Apr 3 17:32:26 2001 +++ linux.ac/fs/super.c Sat Apr 14 01:37:37 2001 @@ -282,6 +282,8 @@ static LIST_HEAD(vfsmntlist); +static char nomem_name [] = "ENOMEM"; + /** * add_vfsmnt - add a new mount node * @nd: location of mountpoint or %NULL if we want a root node @@ -304,7 +306,6 @@ * will have to pass the visibility flag explicitly, so if we will add * support for such beasts we'll have to change prototype. */ - static struct vfsmount *add_vfsmnt(struct nameidata *nd, struct dentry *root, const char *dev_name) @@ -327,7 +328,8 @@ if (name) { strcpy(name, dev_name); mnt->mnt_devname = name; - } + } else + mnt->mnt_devname = nomem_name; } mnt->mnt_owner = current->uid; atomic_set(&mnt->mnt_count,1); @@ -355,7 +357,7 @@ return mnt; fail: spin_unlock(&dcache_lock); - if (mnt->mnt_devname) + if (mnt->mnt_devname != nomem_name) kfree(mnt->mnt_devname); kfree(mnt); return NULL; @@ -374,6 +376,8 @@ new_devname = kmalloc(strlen(dev_name)+1, GFP_KERNEL); if (new_devname) strcpy(new_devname, dev_name); + else + new_devname = nomem_name; } spin_lock(&dcache_lock); @@ -382,7 +386,7 @@ /* flip names */ if (new_devname) { - if (mnt->mnt_devname) + if (mnt->mnt_devname != nomem_name) kfree(mnt->mnt_devname); mnt->mnt_devname = new_devname; } @@ -424,7 +428,7 @@ dput(mnt->mnt_mountpoint); dput(mnt->mnt_root); - if (mnt->mnt_devname) + if (mnt->mnt_devname != nomem_name) kfree(mnt->mnt_devname); kfree(mnt); } @@ -702,7 +706,7 @@ continue; if (!s->s_lock) return s; - printk("VFS: empty superblock %p locked!\n", s); + printk(KERN_WARNING "VFS: empty superblock %p locked!\n", s); } /* Need a new one... */ if (nr_super_blocks >= max_super_blocks) @@ -780,7 +784,7 @@ return; if (test_and_clear_bit(MINOR(dev), unnamed_dev_in_use)) return; - printk("VFS: put_unnamed_dev: freeing unused device %s\n", + printk(KERN_ERR "VFS: put_unnamed_dev: freeing unused device %s\n", kdevname(dev)); } @@ -898,9 +902,9 @@ /* Need to clean after the sucker */ if (fs->fs_flags & FS_LITTER) d_genocide(root); - if (fs->fs_flags & (FS_SINGLE|FS_LITTER)) - shrink_dcache_parent(root); + shrink_dcache_parent(root); dput(root); + fsync_dev(sb->s_dev); lock_super(sb); if (sop) { if (sop->write_super && sb->s_dirt) @@ -911,7 +915,7 @@ /* Forget any remaining inodes */ if (invalidate_inodes(sb)) { - printk("VFS: Busy inodes after unmount. " + printk(KERN_CRIT "VFS: Busy inodes after unmount. " "Self-destruct in 5 seconds. Have a nice day...\n"); } @@ -1074,20 +1078,6 @@ if( (flags&MNT_FORCE) && sb->s_op->umount_begin) sb->s_op->umount_begin(sb); - /* - * Shrink dcache, then fsync. This guarantees that if the - * filesystem is quiescent at this point, then (a) only the - * root entry should be in use and (b) that root entry is - * clean. - */ - shrink_dcache_sb(sb); - fsync_dev(sb->s_dev); - - if (sb->s_root->d_inode->i_state) { - mntput(mnt); - return -EBUSY; - } - /* Something might grab it again - redo checks */ spin_lock(&dcache_lock); @@ -1268,7 +1258,7 @@ int i; unsigned long page; unsigned long size; - + *where = 0; if (!data) return 0; @@ -1566,9 +1556,9 @@ * Allow the user to distinguish between failed open * and bad superblock on root device. */ - printk ("VFS: Cannot open root device \"%s\" or %s\n", + printk (KERN_CRIT "VFS: Cannot open root device \"%s\" or %s\n", root_device_name, kdevname (ROOT_DEV)); - printk ("Please append a correct \"root=\" boot option\n"); + printk (KERN_CRIT "Please append a correct \"root=\" boot option\n"); panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV)); } @@ -1597,7 +1587,7 @@ panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV)); mount_it: - printk ("VFS: Mounted root (%s filesystem)%s.\n", + printk (KERN_INFO "VFS: Mounted root (%s filesystem)%s.\n", fs_type->name, (sb->s_flags & MS_RDONLY) ? " readonly" : ""); if (path_start >= 0) { @@ -1777,7 +1767,7 @@ mount_root(); #if 1 shrink_dcache(); - printk("change_root: old root has d_count=%d\n", + printk(KERN_DEBUG "change_root: old root has d_count=%d\n", atomic_read(&old_rootmnt->mnt_root->d_count)); #endif mount_devfs_fs (); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/sysv/inode.c linux.ac/fs/sysv/inode.c --- linux.vanilla/fs/sysv/inode.c Tue Apr 3 17:32:26 2001 +++ linux.ac/fs/sysv/inode.c Tue Apr 3 17:55:13 2001 @@ -1074,9 +1074,7 @@ if (attr->ia_mode == COH_KLUDGE_SYMLINK_MODE) attr->ia_mode = COH_KLUDGE_NOT_SYMLINK; - inode_setattr(inode, attr); - - return 0; + return inode_setattr(inode, attr); } static struct buffer_head * sysv_update_inode(struct inode * inode) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/udf/balloc.c linux.ac/fs/udf/balloc.c --- linux.vanilla/fs/udf/balloc.c Tue Sep 5 22:07:30 2000 +++ linux.ac/fs/udf/balloc.c Tue Apr 3 17:55:13 2001 @@ -202,7 +202,7 @@ return slot; } -static void udf_bitmap_free_blocks(const struct inode * inode, Uint32 bitmap, +static void udf_bitmap_free_blocks(struct inode * inode, Uint32 bitmap, lb_addr bloc, Uint32 offset, Uint32 count) { struct buffer_head * bh = NULL; @@ -260,7 +260,7 @@ } else { - DQUOT_FREE_BLOCK(sb, inode, 1); + DQUOT_FREE_BLOCK(inode, 1); if (UDF_SB_LVIDBH(sb)) { UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] = @@ -283,7 +283,7 @@ return; } -static int udf_bitmap_prealloc_blocks(const struct inode * inode, Uint32 bitmap, +static int udf_bitmap_prealloc_blocks(struct inode * inode, Uint32 bitmap, Uint16 partition, Uint32 first_block, Uint32 block_count) { int alloc_count = 0; @@ -321,12 +321,12 @@ { if (!udf_test_bit(bit, bh->b_data)) goto out; - else if (DQUOT_PREALLOC_BLOCK(sb, inode, 1)) + else if (DQUOT_PREALLOC_BLOCK(inode, 1)) goto out; else if (!udf_clear_bit(bit, bh->b_data)) { udf_debug("bit already cleared for block %d\n", bit); - DQUOT_FREE_BLOCK(sb, inode, 1); + DQUOT_FREE_BLOCK(inode, 1); goto out; } block_count --; @@ -349,7 +349,7 @@ return alloc_count; } -static int udf_bitmap_new_block(const struct inode * inode, Uint32 bitmap, +static int udf_bitmap_new_block(struct inode * inode, Uint32 bitmap, Uint16 partition, Uint32 goal, int *err) { int tmp, newbit, bit=0, block, block_group, group_start; @@ -461,7 +461,7 @@ /* * Check quota for allocation of this block. */ - if (DQUOT_ALLOC_BLOCK(sb, inode, 1)) + if (DQUOT_ALLOC_BLOCK(inode, 1)) { unlock_super(sb); *err = -EDQUOT; @@ -497,7 +497,7 @@ return 0; } -inline void udf_free_blocks(const struct inode * inode, lb_addr bloc, +inline void udf_free_blocks(struct inode * inode, lb_addr bloc, Uint32 offset, Uint32 count) { if (UDF_SB_PARTFLAGS(inode->i_sb, bloc.partitionReferenceNum) & UDF_PART_FLAG_UNALLOC_BITMAP) @@ -516,7 +516,7 @@ return; } -inline int udf_prealloc_blocks(const struct inode * inode, Uint16 partition, +inline int udf_prealloc_blocks(struct inode * inode, Uint16 partition, Uint32 first_block, Uint32 block_count) { if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP) @@ -535,7 +535,7 @@ return 0; } -inline int udf_new_block(const struct inode * inode, Uint16 partition, +inline int udf_new_block(struct inode * inode, Uint16 partition, Uint32 goal, int *err) { if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/udf/ialloc.c linux.ac/fs/udf/ialloc.c --- linux.vanilla/fs/udf/ialloc.c Fri Nov 17 19:35:27 2000 +++ linux.ac/fs/udf/ialloc.c Tue Apr 3 17:55:13 2001 @@ -44,7 +44,7 @@ * Note: we must free any quota before locking the superblock, * as writing the quota to disk may need the lock as well. */ - DQUOT_FREE_INODE(sb, inode); + DQUOT_FREE_INODE(inode); DQUOT_DROP(inode); lock_super(sb); @@ -70,7 +70,7 @@ udf_free_blocks(inode, UDF_I_LOCATION(inode), 0, 1); } -struct inode * udf_new_inode (const struct inode *dir, int mode, int * err) +struct inode * udf_new_inode (struct inode *dir, int mode, int * err) { struct super_block *sb; struct inode * inode; @@ -149,9 +149,9 @@ mark_inode_dirty(inode); unlock_super(sb); - if (DQUOT_ALLOC_INODE(sb, inode)) + if (DQUOT_ALLOC_INODE(inode)) { - sb->dq_op->drop(inode); + DQUOT_DROP(inode); inode->i_nlink = 0; iput(inode); *err = -EDQUOT; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/udf/partition.c linux.ac/fs/udf/partition.c --- linux.vanilla/fs/udf/partition.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/udf/partition.c Tue Apr 3 17:55:13 2001 @@ -162,6 +162,10 @@ mapsize = (rtl * sizeof(Uint32)) + ((partlen/(1 << sdata->s_spar_pshift)) * sizeof(Uint8) * num); sdata->s_spar_map = kmalloc(mapsize, GFP_KERNEL); + if (!sdata->s_spar_map) { + printk("couldnt allocate UDF s_spar_map!\n"); + return; + } sdata->s_spar_remap.s_spar_remap32 = &sdata->s_spar_map[rtl]; memset(sdata->s_spar_map, 0xFF, mapsize); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/udf/udfdecl.h linux.ac/fs/udf/udfdecl.h --- linux.vanilla/fs/udf/udfdecl.h Mon Dec 11 21:27:05 2000 +++ linux.ac/fs/udf/udfdecl.h Mon Apr 16 00:25:21 2001 @@ -172,16 +172,16 @@ /* ialloc.c */ extern void udf_free_inode(struct inode *); -extern struct inode * udf_new_inode (const struct inode *, int, int *); +extern struct inode * udf_new_inode (struct inode *, int, int *); /* truncate.c */ extern void udf_trunc(struct inode *); extern void udf_truncate(struct inode *); /* balloc.c */ -extern void udf_free_blocks(const struct inode *, lb_addr, Uint32, Uint32); -extern int udf_prealloc_blocks(const struct inode *, Uint16, Uint32, Uint32); -extern int udf_new_block(const struct inode *, Uint16, Uint32, int *); +extern void udf_free_blocks(struct inode *, lb_addr, Uint32, Uint32); +extern int udf_prealloc_blocks(struct inode *, Uint16, Uint32, Uint32); +extern int udf_new_block(struct inode *, Uint16, Uint32, int *); /* fsync.c */ extern int udf_sync_file(struct file *, struct dentry *, int); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ufs/balloc.c linux.ac/fs/ufs/balloc.c --- linux.vanilla/fs/ufs/balloc.c Tue Sep 5 22:07:30 2000 +++ linux.ac/fs/ufs/balloc.c Tue Apr 3 17:55:13 2001 @@ -85,7 +85,7 @@ "bit already cleared for fragment %u", i); } - DQUOT_FREE_BLOCK (sb, inode, count); + DQUOT_FREE_BLOCK (inode, count); ADD_SWAB32(ucg->cg_cs.cs_nffree, count); ADD_SWAB32(usb1->fs_cstotal.cs_nffree, count); ADD_SWAB32(sb->fs_cs(cgno).cs_nffree, count); @@ -187,7 +187,7 @@ ubh_setblock(UCPI_UBH, ucpi->c_freeoff, blkno); if ((sb->u.ufs_sb.s_flags & UFS_CG_MASK) == UFS_CG_44BSD) ufs_clusteracct (sb, ucpi, blkno, 1); - DQUOT_FREE_BLOCK(sb, inode, uspi->s_fpb); + DQUOT_FREE_BLOCK(inode, uspi->s_fpb); INC_SWAB32(ucg->cg_cs.cs_nbfree); INC_SWAB32(usb1->fs_cstotal.cs_nbfree); INC_SWAB32(sb->fs_cs(cgno).cs_nbfree); @@ -271,6 +271,7 @@ if (!tmp) { ufs_error (sb, "ufs_new_fragments", "internal error, " "fragment %u, tmp %u\n", fragment, tmp); + unlock_super (sb); return (unsigned)-1; } if (fragment < inode->u.ufs_i.i_lastfrag) { @@ -450,7 +451,7 @@ INC_SWAB32(ucg->cg_frsum[fragsize - count]); for (i = oldcount; i < newcount; i++) ubh_clrbit (UCPI_UBH, ucpi->c_freeoff, fragno + i); - if(DQUOT_ALLOC_BLOCK(sb, inode, count)) { + if(DQUOT_ALLOC_BLOCK(inode, count)) { *err = -EDQUOT; return 0; } @@ -557,7 +558,7 @@ for (i = count; i < uspi->s_fpb; i++) ubh_setbit (UCPI_UBH, ucpi->c_freeoff, goal + i); i = uspi->s_fpb - count; - DQUOT_FREE_BLOCK(sb, inode, i); + DQUOT_FREE_BLOCK(inode, i); ADD_SWAB32(ucg->cg_cs.cs_nffree, i); ADD_SWAB32(usb1->fs_cstotal.cs_nffree, i); ADD_SWAB32(sb->fs_cs(cgno).cs_nffree, i); @@ -568,7 +569,7 @@ result = ufs_bitmap_search (sb, ucpi, goal, allocsize); if (result == (unsigned)-1) return 0; - if(DQUOT_ALLOC_BLOCK(sb, inode, count)) { + if(DQUOT_ALLOC_BLOCK(inode, count)) { *err = -EDQUOT; return 0; } @@ -638,7 +639,7 @@ ubh_clrblock (UCPI_UBH, ucpi->c_freeoff, blkno); if ((sb->u.ufs_sb.s_flags & UFS_CG_MASK) == UFS_CG_44BSD) ufs_clusteracct (sb, ucpi, blkno, -1); - if(DQUOT_ALLOC_BLOCK(sb, inode, uspi->s_fpb)) { + if(DQUOT_ALLOC_BLOCK(inode, uspi->s_fpb)) { *err = -EDQUOT; return (unsigned)-1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ufs/file.c linux.ac/fs/ufs/file.c --- linux.vanilla/fs/ufs/file.c Sun Feb 27 04:33:08 2000 +++ linux.ac/fs/ufs/file.c Tue Apr 3 17:55:13 2001 @@ -71,11 +71,13 @@ * We have mostly NULL's here: the current defaults are ok for * the ufs filesystem. */ + struct file_operations ufs_file_operations = { llseek: ufs_file_lseek, read: generic_file_read, write: generic_file_write, mmap: generic_file_mmap, + open: generic_file_open, }; struct inode_operations ufs_file_inode_operations = { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ufs/ialloc.c linux.ac/fs/ufs/ialloc.c --- linux.vanilla/fs/ufs/ialloc.c Thu Nov 16 21:18:26 2000 +++ linux.ac/fs/ufs/ialloc.c Tue Apr 3 17:55:13 2001 @@ -100,7 +100,7 @@ is_directory = S_ISDIR(inode->i_mode); - DQUOT_FREE_INODE(sb, inode); + DQUOT_FREE_INODE(inode); DQUOT_DROP(inode); clear_inode (inode); @@ -278,8 +278,8 @@ unlock_super (sb); - if(DQUOT_ALLOC_INODE(sb, inode)) { - sb->dq_op->drop(inode); + if(DQUOT_ALLOC_INODE(inode)) { + DQUOT_DROP(inode); inode->i_nlink = 0; iput(inode); *err = -EDQUOT; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/umsdos/inode.c linux.ac/fs/umsdos/inode.c --- linux.vanilla/fs/umsdos/inode.c Mon Oct 16 20:58:51 2000 +++ linux.ac/fs/umsdos/inode.c Tue Apr 3 17:55:13 2001 @@ -171,7 +171,7 @@ ret = umsdos_notify_change_locked(dentry, attr); up(&dir->i_sem); if (ret == 0) - inode_setattr (inode, attr); + ret = inode_setattr (inode, attr); out: return ret; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/umsdos/ioctl.c linux.ac/fs/umsdos/ioctl.c --- linux.vanilla/fs/umsdos/ioctl.c Tue Sep 5 22:05:46 2000 +++ linux.ac/fs/umsdos/ioctl.c Tue Apr 3 17:55:13 2001 @@ -95,7 +95,7 @@ && cmd != UMSDOS_DOS_SETUP) return fat_dir_ioctl (dir, filp, cmd, data_ptr); - /* #Specification: ioctl / acces + /* #Specification: ioctl / access * Only root (effective id) is allowed to do IOCTL on directory * in UMSDOS. EPERM is returned for other user. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/vfat/namei.c linux.ac/fs/vfat/namei.c --- linux.vanilla/fs/vfat/namei.c Fri Feb 9 19:29:44 2001 +++ linux.ac/fs/vfat/namei.c Tue Apr 10 18:20:00 2001 @@ -10,6 +10,9 @@ * the problem, send a script that demonstrates it. * * Short name translation 1999 by Wolfram Pienkoss <wp@bszh.de> + * + * Support Multibyte character and cleanup by + * OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> */ #define __NO_VERSION__ @@ -154,7 +157,7 @@ } return 1; } - +#if 0 /* not used functions */ static inline unsigned char vfat_getlower(struct nls_table *t, unsigned char c) { @@ -162,62 +165,185 @@ } static inline unsigned char -vfat_tolower(struct nls_table *t, unsigned char c) -{ - unsigned char nc = t->charset2lower[c]; - - return nc ? nc : c; -} - -static inline unsigned char vfat_getupper(struct nls_table *t, unsigned char c) { return t->charset2upper[c]; } -static inline unsigned char -vfat_toupper(struct nls_table *t, unsigned char c) +static inline int +vfat_uni2short(struct nls_table *t, wchar_t uc, unsigned char *op, int bound) { - unsigned char nc = t->charset2upper[c]; + int charlen; - return nc ? nc : c; + if ( (charlen = t->uni2char(uc, op, bound)) < 0) + charlen = 0; + + return charlen; } -static int -vfat_strnicmp(struct nls_table *t, const unsigned char *s1, - const unsigned char *s2, int len) +static int vfat_valid_shortname(struct nls_table *nls, wchar_t *name, int len) { - while(len--) - if (vfat_tolower(t, *s1++) != vfat_tolower(t, *s2++)) - return 1; + wchar_t *walk; + unsigned char c, charbuf[NLS_MAX_CHARSET_SIZE]; + int chl, chi; + int space; + + if (vfat_uni2upper_short(nls, *name, charbuf, NLS_MAX_CHARSET_SIZE) == 0) + return -EINVAL; + + if (IS_FREE(charbuf)) + return -EINVAL; + + chl = 0; + c = 0; + space = 1; /* disallow names starting with a dot */ + for (walk = name; len && walk-name < 8;) { + len--; + chl = nls->uni2char(*walk++, charbuf, NLS_MAX_CHARSET_SIZE); + if (chl < 0) + return -EINVAL; + + for (chi = 0; chi < chl; chi++) { + c = vfat_getupper(nls, charbuf[chi]); + if (!c) return -EINVAL; + if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL; + if (strchr(replace_chars,c)) return -EINVAL; + if (c < ' '|| c==':') return -EINVAL; + if (c == '.') goto dot; + space = c == ' '; + } + } +dot:; + if (space) return -EINVAL; + if (len && c != '.') { + len--; + if (vfat_uni2upper_short(nls, *walk++, charbuf, NLS_MAX_CHARSET_SIZE) == 1) { + if (charbuf[0] != '.') return -EINVAL; + } else + return -EINVAL; + c = '.'; + } + if (c == '.') { + if (len >= 4) return -EINVAL; + while (len > 0) { + len--; + chl = nls->uni2char(*walk++, charbuf, NLS_MAX_CHARSET_SIZE); + if (chl < 0) + return -EINVAL; + for (chi = 0; chi < chl; chi++) { + c = vfat_getupper(nls, charbuf[chi]); + if (!c) return -EINVAL; + if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL; + if (strchr(replace_chars,c)) + return -EINVAL; + if (c < ' ' || c == '.'|| c==':') + return -EINVAL; + space = c == ' '; + } + } + if (space) return -EINVAL; + } return 0; } -static inline int -vfat_uni2short(struct nls_table *t, wchar_t uc, unsigned char *op, int bound) +static int vfat_format_name(struct nls_table *nls, wchar_t *name, + int len, char *res) { - int charlen; + char *walk; + unsigned char charbuf[NLS_MAX_CHARSET_SIZE]; + int chi, chl; + int space; - if ( (charlen = t->uni2char(uc, op, bound)) < 0) - charlen = 0; + if (vfat_uni2upper_short(nls, *name, charbuf, NLS_MAX_CHARSET_SIZE) == 0) + return -EINVAL; - return charlen; + if (IS_FREE(charbuf)) + return -EINVAL; + + space = 1; /* disallow names starting with a dot */ + for (walk = res; len--; ) { + chl = vfat_uni2upper_short(nls, *name++, charbuf, NLS_MAX_CHARSET_SIZE); + if (chl == 0) + return -EINVAL; + for (chi = 0; chi < chl; chi++){ + if (charbuf[chi] == '.') goto dot; + if (!charbuf[chi]) return -EINVAL; + if (walk-res == 8) return -EINVAL; + if (strchr(replace_chars,charbuf[chi])) return -EINVAL; + if (charbuf[chi] < ' '|| charbuf[chi]==':') return -EINVAL; + space = charbuf[chi] == ' '; + *walk = charbuf[chi]; + walk++; + } + } +dot:; + if (space) return -EINVAL; + if (len >= 0) { + while (walk-res < 8) *walk++ = ' '; + while (len > 0 && walk-res < MSDOS_NAME) { + chl = vfat_uni2upper_short(nls, *name++, charbuf, NLS_MAX_CHARSET_SIZE); + if (len < chl) + chl = len; + len -= chl; + for (chi = 0; chi < chl; chi++){ + if (!charbuf[chi]) return -EINVAL; + if (strchr(replace_chars,charbuf[chi])) + return -EINVAL; + if (charbuf[chi] < ' ' || charbuf[chi] == '.'|| charbuf[chi]==':') + return -EINVAL; + space = charbuf[chi] == ' '; + *walk++ = charbuf[chi]; + } + } + if (space) return -EINVAL; + if (len) return -EINVAL; + } + while (walk-res < MSDOS_NAME) *walk++ = ' '; + + return 0; } static inline int vfat_uni2upper_short(struct nls_table *t, wchar_t uc, char *op, int bound) { - int chi, chl; + int chl; if ( (chl = t->uni2char(uc, op, bound)) < 0) chl = 0; - for (chi = 0; chi < chl; chi++) - op[chi] = vfat_toupper(t, op[chi]); + if (chl == 1) + op[0] = vfat_toupper(t, op[0]); return chl; } +#endif +static inline unsigned char +vfat_tolower(struct nls_table *t, unsigned char c) +{ + unsigned char nc = t->charset2lower[c]; + + return nc ? nc : c; +} + +static inline unsigned char +vfat_toupper(struct nls_table *t, unsigned char c) +{ + unsigned char nc = t->charset2upper[c]; + + return nc ? nc : c; +} + +static int +vfat_strnicmp(struct nls_table *t, const unsigned char *s1, + const unsigned char *s2, int len) +{ + while(len--) + if (vfat_tolower(t, *s1++) != vfat_tolower(t, *s2++)) + return 1; + + return 0; +} /* * Compute the hash for the vfat name corresponding to the dentry. @@ -383,8 +509,35 @@ /* Characters that are undesirable in an MS-DOS file name */ -static char bad_chars[] = "*?<>|\":/\\"; -static char replace_chars[] = "[];,+="; +static wchar_t bad_chars[] = { + /* `*' `?' `<' `>' `|' `"' `:' `/' `\' */ + 0x002A, 0x003F, 0x003C, 0x003E, 0x007C, 0x0022, 0x003A, 0x002F, 0x005C, 0, +}; +#define IS_BADCHAR(uni) (vfat_unistrchr(bad_chars, (uni)) != NULL) + +static wchar_t replace_chars[] = { + /* `[' `]' `;' `,' `+' `=' */ + 0x005B, 0x005D, 0x003B, 0x002C, 0x002B, 0x003D, 0, +}; +#define IS_REPLACECHAR(uni) (vfat_unistrchr(replace_chars, (uni)) != NULL) + +static inline wchar_t *vfat_unistrchr(const wchar_t *s, const wchar_t c) +{ + for(; *s != c; ++s) + if (*s == 0) + return NULL; + return (wchar_t *) s; +} + +static inline int vfat_is_used_badchars(const wchar_t *s, int len) +{ + int i; + + for (i = 0; i < len; i++) + if (s[i] < 0x0020 || IS_BADCHAR(s[i])) + return -EINVAL; + return 0; +} /* Checks the validity of a long MS-DOS filename */ /* Returns negative number on error, 0 for a normal @@ -393,18 +546,10 @@ static int vfat_valid_longname(const char *name, int len, int xlate) { const char **reserved, *walk; - unsigned char c; - int i, baselen; + int baselen; if (len && name[len-1] == ' ') return -EINVAL; if (len >= 256) return -EINVAL; - for (i = 0; i < len; i++) { - c = name[i]; - if (xlate && c == ':') continue; - if (strchr(bad_chars,c)) { - return -EINVAL; - } - } if (len < 3) return 0; for (walk = name; *walk != 0 && *walk != '.'; walk++); @@ -424,72 +569,6 @@ return 0; } -static int vfat_valid_shortname(struct nls_table *nls, wchar_t *name, int len) -{ - wchar_t *walk; - unsigned char c, charbuf[NLS_MAX_CHARSET_SIZE]; - int chl, chi; - int space; - - if (vfat_uni2upper_short(nls, *name, charbuf, NLS_MAX_CHARSET_SIZE) == 0) - return -EINVAL; - - if (IS_FREE(charbuf)) - return -EINVAL; - - chl = 0; - c = 0; - space = 1; /* disallow names starting with a dot */ - for (walk = name; len && walk-name < 8;) { - len--; - chl = nls->uni2char(*walk++, charbuf, NLS_MAX_CHARSET_SIZE); - if (chl < 0) - return -EINVAL; - - for (chi = 0; chi < chl; chi++) { - c = vfat_getupper(nls, charbuf[chi]); - if (!c) return -EINVAL; - if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL; - if (strchr(replace_chars,c)) return -EINVAL; - if (c < ' '|| c==':') return -EINVAL; - if (c == '.') goto dot; - space = c == ' '; - } - } -dot:; - if (space) return -EINVAL; - if (len && c != '.') { - len--; - if (vfat_uni2upper_short(nls, *walk++, charbuf, NLS_MAX_CHARSET_SIZE) == 1) { - if (charbuf[0] != '.') return -EINVAL; - } else - return -EINVAL; - c = '.'; - } - if (c == '.') { - if (len >= 4) return -EINVAL; - while (len > 0) { - len--; - chl = nls->uni2char(*walk++, charbuf, NLS_MAX_CHARSET_SIZE); - if (chl < 0) - return -EINVAL; - for (chi = 0; chi < chl; chi++) { - c = vfat_getupper(nls, charbuf[chi]); - if (!c) return -EINVAL; - if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL; - if (strchr(replace_chars,c)) - return -EINVAL; - if (c < ' ' || c == '.'|| c==':') - return -EINVAL; - space = c == ' '; - } - } - if (space) return -EINVAL; - } - - return 0; -} - static int vfat_find_form(struct inode *dir,char *name) { struct msdos_dir_entry *de; @@ -503,127 +582,62 @@ return 0; } -static int vfat_format_name(struct nls_table *nls, wchar_t *name, - int len, char *res) -{ - char *walk; - unsigned char charbuf[NLS_MAX_CHARSET_SIZE]; - int chi, chl; - int space; - - if (vfat_uni2upper_short(nls, *name, charbuf, NLS_MAX_CHARSET_SIZE) == 0) - return -EINVAL; - - if (IS_FREE(charbuf)) - return -EINVAL; - - space = 1; /* disallow names starting with a dot */ - for (walk = res; len--; ) { - chl = vfat_uni2upper_short(nls, *name++, charbuf, NLS_MAX_CHARSET_SIZE); - if (chl == 0) - return -EINVAL; - for (chi = 0; chi < chl; chi++){ - if (charbuf[chi] == '.') goto dot; - if (!charbuf[chi]) return -EINVAL; - if (walk-res == 8) return -EINVAL; - if (strchr(replace_chars,charbuf[chi])) return -EINVAL; - if (charbuf[chi] < ' '|| charbuf[chi]==':') return -EINVAL; - space = charbuf[chi] == ' '; - *walk = charbuf[chi]; - walk++; - } - } -dot:; - if (space) return -EINVAL; - if (len >= 0) { - while (walk-res < 8) *walk++ = ' '; - while (len > 0 && walk-res < MSDOS_NAME) { - chl = vfat_uni2upper_short(nls, *name++, charbuf, NLS_MAX_CHARSET_SIZE); - if (len < chl) - chl = len; - len -= chl; - for (chi = 0; chi < chl; chi++){ - if (!charbuf[chi]) return -EINVAL; - if (strchr(replace_chars,charbuf[chi])) - return -EINVAL; - if (charbuf[chi] < ' ' || charbuf[chi] == '.'|| charbuf[chi]==':') - return -EINVAL; - space = charbuf[chi] == ' '; - *walk++ = charbuf[chi]; - } - } - if (space) return -EINVAL; - if (len) return -EINVAL; - } - while (walk-res < MSDOS_NAME) *walk++ = ' '; - - return 0; -} - -static char skip_chars[] = ".:\"?<>| "; +static wchar_t skip_chars[] = { + /* `.' ` ' */ + 0x002E, 0x0020, 0, +}; +#define IS_SKIPCHAR(uni) \ + ((wchar_t)(uni) == skip_chars[0] || (wchar_t)(uni) == skip_chars[1]) /* Given a valid longname, create a unique shortname. Make sure the * shortname does not exist + * Returns negative number on error, 0 for a normal + * return, and 1 for valid shortname */ static int vfat_create_shortname(struct inode *dir, struct nls_table *nls, - wchar_t *name, int len, - char *name_res) + wchar_t *uname, int ulen, + char *name_res) { - wchar_t *ip, *op, *ext_start, *end, *name_start; - wchar_t msdos_name[13]; - char base[9], ext[4], buf[8], *p; + wchar_t *ip, *ext_start, *end, *name_start; + unsigned char base[9], ext[4], buf[8], *p; unsigned char charbuf[NLS_MAX_CHARSET_SIZE]; int chl, chi; - int sz, extlen, baselen, i; - - PRINTK2(("Entering vfat_create_shortname\n")); - chl = 0; - sz = 0; /* Make compiler happy */ - if (len <= 12) { - /* Do a case insensitive search if the name would be a valid - * shortname if is were all capitalized. However, do not - * allow spaces in short names because Win95 scandisk does - * not like that */ - for (i = 0, op = &msdos_name[0], ip = name; ; i++, ip++, op++) { - if (i == len) { - if (vfat_format_name(nls, &msdos_name[0], len, - name_res) < 0) - break; - PRINTK3(("vfat_create_shortname 1\n")); - if (vfat_find_form(dir, name_res) < 0) - return 0; - return -EEXIST; - } - chl = vfat_uni2upper_short(nls, *ip, charbuf, NLS_MAX_CHARSET_SIZE); - for (chi = 0; chi < chl; chi++){ - if (charbuf[chi] == ' ') - break; - } - if (chi < chl) - break; + int sz = 0, extlen, baselen, i, numtail_baselen, numtail2_baselen; + int is_uppercase, is_shortname; - *op = *ip; - } - } + /* + * 1) Valid characters for the 8.3 format alias are any + * combination of letters, uppercase alphabets, digits, any of + * the following special characters: + * $ % ' ` - @ { } ~ ! # ( ) & _ ^ + * In this case Longfilename is not stored in disk. + * + * 2) File name is 8.3 format, but it contain the lowercase + * alphabet etc. In this case numtail is not added, but + * Longfilename is stored. + * + * 3) When the one except for the above, or the following special + * character are contained: + * . [ ] ; , + = + * numtail is added, and Longfilename must be stored in disk . + */ + is_uppercase = 1; + is_shortname = 1; - PRINTK3(("vfat_create_shortname 3\n")); /* Now, we need to create a shortname from the long name */ - ext_start = end = &name[len]; - while (--ext_start >= name) { - chl = vfat_uni2upper_short(nls, *ext_start, charbuf, NLS_MAX_CHARSET_SIZE); - for (chi = 0; chi < chl; chi++) { - if (charbuf[chi] == '.') { - if (ext_start == end - 1) { - sz = len; - ext_start = NULL; - } - goto stop0; + ext_start = end = &uname[ulen]; + while (--ext_start >= uname) { + if (*ext_start == 0x002E) { /* is `.' */ + if (ext_start == end - 1) { + sz = ulen; + ext_start = NULL; } + break; } } -stop0:; - if (ext_start == name - 1) { - sz = len; + + if (ext_start == uname - 1) { + sz = ulen; ext_start = NULL; } else if (ext_start) { /* @@ -631,45 +645,63 @@ * an extension eg. "...test". In this case Win95 * uses the extension as the name and sets no extension. */ - name_start = &name[0]; - while (name_start < ext_start) - { - chl = vfat_uni2upper_short(nls, *name_start, charbuf, NLS_MAX_CHARSET_SIZE); - if (chl == 0) + name_start = &uname[0]; + while (name_start < ext_start) { + if (!IS_SKIPCHAR(*name_start)) break; - for (chi = 0; chi < chl; chi++) - if (!strchr(skip_chars, charbuf[chi])) { - goto stop1; - } name_start++; } -stop1:; if (name_start != ext_start) { - sz = ext_start - name; + sz = ext_start - uname; ext_start++; } else { - sz = len; + sz = ulen; ext_start=NULL; } } - for (baselen = i = 0, p = base, ip = name; i < sz && baselen < 8; i++, ip++) + numtail_baselen = 6; + numtail2_baselen = 2; + for (baselen = i = 0, p = base, ip = uname; i < sz; i++, ip++) { - chl = vfat_uni2upper_short(nls, *ip, charbuf, NLS_MAX_CHARSET_SIZE); - if (chl == 0){ - *p++ = '_'; - baselen++; + if (IS_SKIPCHAR(*ip)) { + is_shortname = 0; continue; } + if (IS_REPLACECHAR(*ip)) { + is_shortname = 0; + charbuf[0] = '_'; + chl = 1; + } else { + chl = nls->uni2char(*ip, charbuf, sizeof(charbuf)); + if (chl <= 0) { + is_shortname = 0; + charbuf[0] = '_'; + chl = 1; + } else if (chl == 1) { + unsigned char c = charbuf[0]; + charbuf[0] = vfat_toupper(nls, charbuf[0]); + if (c >= 0x7F || charbuf[0] != c) + is_uppercase = 0; + } else { + is_uppercase = 0; + } + } + if (baselen < 2 && (baselen + chl) > 2) + numtail2_baselen = baselen; + if (baselen < 6 && (baselen + chl) > 6) + numtail_baselen = baselen; for (chi = 0; chi < chl; chi++){ - if (!strchr(skip_chars, charbuf[chi])){ - if (strchr(replace_chars, charbuf[chi])) - *p = '_'; - else - *p = charbuf[chi]; - p++; baselen++; - } + *p++ = charbuf[chi]; + baselen++; + if (baselen >= 8) + break; + } + if (baselen >= 8) { + if ((chi < chl - 1) || (ip + 1) - uname < sz) + is_shortname = 0; + break; } } if (baselen == 0) { @@ -679,30 +711,51 @@ extlen = 0; if (ext_start) { for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) { - chl = vfat_uni2upper_short(nls, *ip, charbuf, NLS_MAX_CHARSET_SIZE); - if (chl == 0) { - *p++ = '_'; - extlen++; + if (IS_SKIPCHAR(*ip)) { + is_shortname = 0; continue; } - - for (chi = 0; chi < chl; chi++) { - if (!strchr(skip_chars, charbuf[chi])) { - if (strchr(replace_chars, charbuf[chi])) - *p = '_'; - else - *p = charbuf[chi]; - p++; extlen++; + if (IS_REPLACECHAR(*ip)) { + is_shortname = 0; + charbuf[0] = '_'; + chl = 1; + } else { + chl = nls->uni2char(*ip, charbuf, sizeof(charbuf)); + if (chl <= 0) { + is_shortname = 0; + charbuf[0] = '_'; + chl = 1; + } else if (chl == 1) { + unsigned char c = charbuf[0]; + charbuf[0] = vfat_toupper(nls, charbuf[0]); + if (c >= 0x7F || charbuf[0] != c) + is_uppercase = 0; + } else { + is_uppercase = 0; } } + + if ((extlen + chl) > 3) { + is_shortname = 0; + break; + } + for (chi = 0; chi < chl; chi++) { + *p++ = charbuf[chi]; + extlen++; + } + if (extlen >= 3) { + if (ip + 1 != end) + is_shortname = 0; + break; + } } } ext[extlen] = '\0'; base[baselen] = '\0'; /* Yes, it can happen. ".\xe5" would do it. */ - if (IS_FREE(base)) - base[0]='_'; + if (base[0] == DELETED_FLAG) + base[0] = 0x05; /* OK, at this point we know that base is not longer than 8 symbols, * ext is not longer than 3, base is nonempty, both don't contain @@ -712,6 +765,14 @@ memset(name_res, ' ', MSDOS_NAME); memcpy(name_res,base,baselen); memcpy(name_res+8,ext,extlen); + + if (is_shortname) { + if (vfat_find_form(dir, name_res) < 0) + return is_uppercase; + else + return -EEXIST; + } + if (MSDOS_SB(dir->i_sb)->options.numtail == 0) if (vfat_find_form(dir, name_res) < 0) return 0; @@ -724,8 +785,10 @@ * values for part of the base. */ - if (baselen>6) - baselen = 6; + if (baselen>6) { + baselen = numtail_baselen; + name_res[7] = ' '; + } name_res[baselen] = '~'; for (i = 1; i < 10; i++) { name_res[baselen+1] = i + '0'; @@ -735,8 +798,10 @@ i = jiffies & 0xffff; sz = (jiffies >> 16) & 0x7; - if (baselen>2) - baselen = 2; + if (baselen>2) { + baselen = numtail2_baselen; + name_res[7] = ' '; + } name_res[baselen+4] = '~'; name_res[baselen+5] = '1' + sz; while (1) { @@ -868,15 +933,18 @@ goto out_free; uname = (wchar_t *) page; - if (vfat_valid_shortname(nls_disk, uname, ulen) >= 0) { - res = vfat_format_name(nls_disk, uname, ulen, de->name); - if (!res) - goto out_free; - } + res = vfat_is_used_badchars(uname, ulen); + if (res < 0) + goto out_free; res = vfat_create_shortname(dir, nls_disk, uname, ulen, msdos_name); - if (res) + if (res < 0) + goto out_free; + else if (res == 1) { + strncpy(de->name, msdos_name, MSDOS_NAME); + res = 0; goto out_free; + } *slots = unilen / 13; for (cksum = i = 0; i < 11; i++) { @@ -956,7 +1024,8 @@ goto cleanup; res = vfat_build_slots(dir, qname->name, len, ds, &slots); - if (res < 0) goto cleanup; + if (res < 0) + goto cleanup; offset = fat_add_entries(dir, slots, &bh1, &de1, &ino); if (offset < 0) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/bitops.h linux.ac/include/asm-alpha/bitops.h --- linux.vanilla/include/asm-alpha/bitops.h Mon Dec 4 01:45:20 2000 +++ linux.ac/include/asm-alpha/bitops.h Tue Apr 3 17:55:13 2001 @@ -20,12 +20,31 @@ * bit 0 is the LSB of addr; bit 64 is the LSB of (addr+1). */ -extern __inline__ void -set_bit(unsigned long nr, volatile void * addr) +#define BITOPS_NO_BRANCH + +extern __inline__ void set_bit(unsigned long nr, volatile void * addr) { +#ifndef BITOPS_NO_BRANCH + unsigned long oldbit; +#endif unsigned long temp; - int *m = ((int *) addr) + (nr >> 5); + unsigned int * m = ((unsigned int *) addr) + (nr >> 5); +#ifndef BITOPS_NO_BRANCH + __asm__ __volatile__( + "1: ldl_l %0,%4\n" + " and %0,%3,%2\n" + " bne %2,2f\n" + " xor %0,%3,%0\n" + " stl_c %0,%1\n" + " beq %0,3f\n" + "2:\n" + ".subsection 2\n" + "3: br 1b\n" + ".previous" + :"=&r" (temp), "=m" (*m), "=&r" (oldbit) + :"Ir" (1UL << (nr & 31)), "m" (*m)); +#else __asm__ __volatile__( "1: ldl_l %0,%3\n" " bis %0,%2,%0\n" @@ -36,28 +55,58 @@ ".previous" :"=&r" (temp), "=m" (*m) :"Ir" (1UL << (nr & 31)), "m" (*m)); +#endif } /* * WARNING: non atomic version. */ -extern __inline__ void -__set_bit(unsigned long nr, volatile void * addr) +extern __inline__ void __set_bit(unsigned long nr, volatile void * addr) { - int *m = ((int *) addr) + (nr >> 5); + unsigned int * m = ((unsigned int *) addr) + (nr >> 5); + /* + * Asm and C produces the same thing so let + * the compiler to do its good work. + */ +#if 0 + int tmp; + __asm__ __volatile__( + "ldl %0,%3\n\t" + "bis %0,%2,%0\n\t" + "stl %0,%1" + : "=&r" (tmp), "=m" (*m) + : "Ir" (1UL << (nr & 31)), "m" (*m)); +#else *m |= 1UL << (nr & 31); +#endif } #define smp_mb__before_clear_bit() smp_mb() #define smp_mb__after_clear_bit() smp_mb() - -extern __inline__ void -clear_bit(unsigned long nr, volatile void * addr) +extern __inline__ void clear_bit(unsigned long nr, volatile void * addr) { +#ifndef BITOPS_NO_BRANCH + unsigned long oldbit; +#endif unsigned long temp; - int *m = ((int *) addr) + (nr >> 5); + unsigned int * m = ((unsigned int *) addr) + (nr >> 5); +#ifndef BITOPS_NO_BRANCH + __asm__ __volatile__( + "1: ldl_l %0,%4\n" + " and %0,%3,%2\n" + " beq %2,2f\n" + " xor %0,%3,%0\n" + " stl_c %0,%1\n" + " beq %0,3f\n" + "2:\n" + ".subsection 2\n" + "3: br 1b\n" + ".previous" + :"=&r" (temp), "=m" (*m), "=&r" (oldbit) + :"Ir" (1UL << (nr & 31)), "m" (*m)); +#else __asm__ __volatile__( "1: ldl_l %0,%3\n" " and %0,%2,%0\n" @@ -68,13 +117,13 @@ ".previous" :"=&r" (temp), "=m" (*m) :"Ir" (~(1UL << (nr & 31))), "m" (*m)); +#endif } -extern __inline__ void -change_bit(unsigned long nr, volatile void * addr) +extern __inline__ void change_bit(unsigned long nr, volatile void * addr) { unsigned long temp; - int *m = ((int *) addr) + (nr >> 5); + unsigned int * m = ((unsigned int *) addr) + (nr >> 5); __asm__ __volatile__( "1: ldl_l %0,%3\n" @@ -88,12 +137,12 @@ :"Ir" (1UL << (nr & 31)), "m" (*m)); } -extern __inline__ int -test_and_set_bit(unsigned long nr, volatile void *addr) +extern __inline__ int test_and_set_bit(unsigned long nr, + volatile void * addr) { unsigned long oldbit; unsigned long temp; - int *m = ((int *) addr) + (nr >> 5); + unsigned int * m = ((unsigned int *) addr) + (nr >> 5); __asm__ __volatile__( "1: ldl_l %0,%4\n" @@ -102,10 +151,10 @@ " xor %0,%3,%0\n" " stl_c %0,%1\n" " beq %0,3f\n" - "2:\n" #ifdef CONFIG_SMP " mb\n" #endif + "2:\n" ".subsection 2\n" "3: br 1b\n" ".previous" @@ -118,23 +167,32 @@ /* * WARNING: non atomic version. */ -extern __inline__ int -__test_and_set_bit(unsigned long nr, volatile void * addr) +extern __inline__ int __test_and_set_bit(unsigned long nr, + volatile void * addr) { - unsigned long mask = 1 << (nr & 0x1f); - int *m = ((int *) addr) + (nr >> 5); - int old = *m; + unsigned long oldbit; + unsigned long temp; + unsigned int * m = ((unsigned int *) addr) + (nr >> 5); + + __asm__ __volatile__( + " ldl %0,%4\n" + " and %0,%3,%2\n" + " bne %2,1f\n" + " xor %0,%3,%0\n" + " stl %0,%1\n" + "1:\n" + :"=&r" (temp), "=m" (*m), "=&r" (oldbit) + :"Ir" (1UL << (nr & 31)), "m" (*m)); - *m = old | mask; - return (old & mask) != 0; + return oldbit != 0; } -extern __inline__ int -test_and_clear_bit(unsigned long nr, volatile void * addr) +extern __inline__ int test_and_clear_bit(unsigned long nr, + volatile void * addr) { unsigned long oldbit; unsigned long temp; - int *m = ((int *) addr) + (nr >> 5); + unsigned int * m = ((unsigned int *) addr) + (nr >> 5); __asm__ __volatile__( "1: ldl_l %0,%4\n" @@ -143,10 +201,10 @@ " xor %0,%3,%0\n" " stl_c %0,%1\n" " beq %0,3f\n" - "2:\n" #ifdef CONFIG_SMP " mb\n" #endif + "2:\n" ".subsection 2\n" "3: br 1b\n" ".previous" @@ -159,23 +217,32 @@ /* * WARNING: non atomic version. */ -extern __inline__ int -__test_and_clear_bit(unsigned long nr, volatile void * addr) +extern __inline__ int __test_and_clear_bit(unsigned long nr, + volatile void * addr) { - unsigned long mask = 1 << (nr & 0x1f); - int *m = ((int *) addr) + (nr >> 5); - int old = *m; + unsigned long oldbit; + unsigned long temp; + unsigned int * m = ((unsigned int *) addr) + (nr >> 5); - *m = old & ~mask; - return (old & mask) != 0; + __asm__ __volatile__( + " ldl %0,%4\n" + " and %0,%3,%2\n" + " beq %2,1f\n" + " xor %0,%3,%0\n" + " stl %0,%1\n" + "1:\n" + :"=&r" (temp), "=m" (*m), "=&r" (oldbit) + :"Ir" (1UL << (nr & 31)), "m" (*m)); + + return oldbit != 0; } -extern __inline__ int -test_and_change_bit(unsigned long nr, volatile void * addr) +extern __inline__ int test_and_change_bit(unsigned long nr, + volatile void * addr) { unsigned long oldbit; unsigned long temp; - int *m = ((int *) addr) + (nr >> 5); + unsigned int * m = ((unsigned int *) addr) + (nr >> 5); __asm__ __volatile__( "1: ldl_l %0,%4\n" @@ -195,8 +262,7 @@ return oldbit != 0; } -extern __inline__ int -test_bit(int nr, volatile void * addr) +extern __inline__ int test_bit(int nr, volatile void * addr) { return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; } @@ -223,7 +289,7 @@ extern inline unsigned long ffz(unsigned long word) { #if defined(__alpha_cix__) && defined(__alpha_fix__) - /* Whee. EV67 can calculate it directly. */ + /* Whee. EV6 can calculate it directly. */ unsigned long result; __asm__("cttz %1,%0" : "=r"(result) : "r"(~word)); return result; @@ -259,7 +325,7 @@ */ #if defined(__alpha_cix__) && defined(__alpha_fix__) -/* Whee. EV67 can calculate it directly. */ +/* Whee. EV6 can calculate it directly. */ extern __inline__ unsigned long hweight64(unsigned long w) { unsigned long result; @@ -281,8 +347,7 @@ /* * Find next zero bit in a bitmap reasonably efficiently.. */ -extern inline unsigned long -find_next_zero_bit(void * addr, unsigned long size, unsigned long offset) +extern inline unsigned long find_next_zero_bit(void * addr, unsigned long size, unsigned long offset) { unsigned long * p = ((unsigned long *) addr) + (offset >> 6); unsigned long result = offset & ~63UL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/byteorder.h linux.ac/include/asm-alpha/byteorder.h --- linux.vanilla/include/asm-alpha/byteorder.h Mon Dec 4 01:45:20 2000 +++ linux.ac/include/asm-alpha/byteorder.h Tue Apr 3 17:55:13 2001 @@ -3,44 +3,6 @@ #include <asm/types.h> -#ifdef __GNUC__ - -static __inline __u32 __attribute__((__const)) __arch__swab32(__u32 x) -{ - /* - * Unfortunately, we can't use the 6 instruction sequence - * on ev6 since the latency of the UNPKBW is 3, which is - * pretty hard to hide. Just in case a future implementation - * has a lower latency, here's the sequence (also by Mike Burrows) - * - * UNPKBW a0, v0 v0: 00AA00BB00CC00DD - * SLL v0, 24, a0 a0: BB00CC00DD000000 - * BIS v0, a0, a0 a0: BBAACCBBDDCC00DD - * EXTWL a0, 6, v0 v0: 000000000000BBAA - * ZAP a0, 0xf3, a0 a0: 00000000DDCC0000 - * ADDL a0, v0, v0 v0: ssssssssDDCCBBAA - */ - - __u64 t0, t1, t2, t3; - - __asm__("inslh %1, 7, %0" /* t0 : 0000000000AABBCC */ - : "=r"(t0) : "r"(x)); - __asm__("inswl %1, 3, %0" /* t1 : 000000CCDD000000 */ - : "=r"(t1) : "r"(x)); - - t1 |= t0; /* t1 : 000000CCDDAABBCC */ - t2 = t1 >> 16; /* t2 : 0000000000CCDDAA */ - t0 = t1 & 0xFF00FF00; /* t0 : 00000000DD00BB00 */ - t3 = t2 & 0x00FF00FF; /* t3 : 0000000000CC00AA */ - t1 = t0 + t3; /* t1 : ssssssssDDCCBBAA */ - - return t1; -} - -#define __arch__swab32 __arch__swab32 - -#endif /* __GNUC__ */ - #define __BYTEORDER_HAS_U64__ #include <linux/byteorder/little_endian.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/fpu.h linux.ac/include/asm-alpha/fpu.h --- linux.vanilla/include/asm-alpha/fpu.h Mon Dec 4 01:45:20 2000 +++ linux.ac/include/asm-alpha/fpu.h Tue Apr 3 17:55:13 2001 @@ -131,19 +131,17 @@ unsigned long tmp, ret; #if defined(__alpha_cix__) || defined(__alpha_fix__) - __asm__ __volatile__ ( - "ftoit $f0,%0\n\t" - "mf_fpcr $f0\n\t" - "ftoit $f0,%1\n\t" - "itoft %0,$f0" - : "=r"(tmp), "=r"(ret)); + __asm__ ("ftoit $f0,%0\n\t" + "mf_fpcr $f0\n\t" + "ftoit $f0,%1\n\t" + "itoft %0,$f0" + : "=r"(tmp), "=r"(ret)); #else - __asm__ __volatile__ ( - "stt $f0,%0\n\t" - "mf_fpcr $f0\n\t" - "stt $f0,%1\n\t" - "ldt $f0,%0" - : "=m"(tmp), "=m"(ret)); + __asm__ ("stt $f0,%0\n\t" + "mf_fpcr $f0\n\t" + "stt $f0,%1\n\t" + "ldt $f0,%0" + : "=m"(tmp), "=m"(ret)); #endif return ret; @@ -155,12 +153,11 @@ unsigned long tmp; #if defined(__alpha_cix__) || defined(__alpha_fix__) - __asm__ __volatile__ ( - "ftoit $f0,%0\n\t" - "itoft %1,$f0\n\t" - "mt_fpcr $f0\n\t" - "itoft %0,$f0" - : "=&r"(tmp) : "r"(val)); + __asm__ __volatile__ ("ftoit $f0,%0\n\t" + "itoft %1,$f0\n\t" + "mt_fpcr $f0\n\t" + "itoft %0,$f0" + : "=&r"(tmp) : "r"(val)); #else __asm__ __volatile__ ( "stt $f0,%0\n\t" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/hw_irq.h linux.ac/include/asm-alpha/hw_irq.h --- linux.vanilla/include/asm-alpha/hw_irq.h Mon Feb 28 15:18:20 2000 +++ linux.ac/include/asm-alpha/hw_irq.h Tue Apr 3 17:55:13 2001 @@ -5,6 +5,8 @@ static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {} +extern volatile unsigned long irq_err_count; + #ifdef CONFIG_ALPHA_GENERIC #define ACTUAL_NR_IRQS alpha_mv.nr_irqs #else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/io.h linux.ac/include/asm-alpha/io.h --- linux.vanilla/include/asm-alpha/io.h Tue Apr 3 17:32:26 2001 +++ linux.ac/include/asm-alpha/io.h Thu Apr 12 17:44:15 2001 @@ -1,10 +1,6 @@ #ifndef __ALPHA_IO_H #define __ALPHA_IO_H -#include <linux/config.h> -#include <linux/kernel.h> -#include <asm/system.h> - /* We don't use IO slowdowns on the Alpha, but.. */ #define __SLOW_DOWN_IO do { } while (0) #define SLOW_DOWN_IO do { } while (0) @@ -19,6 +15,9 @@ #endif #ifdef __KERNEL__ +#include <linux/config.h> +#include <linux/kernel.h> +#include <asm/system.h> #include <asm/machvec.h> /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/ioctls.h linux.ac/include/asm-alpha/ioctls.h --- linux.vanilla/include/asm-alpha/ioctls.h Fri Jan 28 00:40:09 2000 +++ linux.ac/include/asm-alpha/ioctls.h Tue Apr 3 17:55:13 2001 @@ -9,6 +9,7 @@ #define FIONBIO _IOW('f', 126, int) #define FIONREAD _IOR('f', 127, int) #define TIOCINQ FIONREAD +#define FIOQSIZE _IOR('f', 128, loff_t) #define TIOCGETP _IOR('t', 8, struct sgttyb) #define TIOCSETP _IOW('t', 9, struct sgttyb) @@ -106,5 +107,7 @@ #define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ +#define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ #endif /* _ASM_ALPHA_IOCTLS_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/linux_logo.h linux.ac/include/asm-alpha/linux_logo.h --- linux.vanilla/include/asm-alpha/linux_logo.h Thu Oct 1 18:02:22 1998 +++ linux.ac/include/asm-alpha/linux_logo.h Tue Apr 3 17:55:13 2001 @@ -40,9 +40,6 @@ extern unsigned char linux_logo_blue[]; extern unsigned char linux_logo[]; extern unsigned char linux_logo_bw[]; -extern unsigned char linux_logo16_red[]; -extern unsigned char linux_logo16_green[]; -extern unsigned char linux_logo16_blue[]; extern unsigned char linux_logo16[]; #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/pgalloc.h linux.ac/include/asm-alpha/pgalloc.h --- linux.vanilla/include/asm-alpha/pgalloc.h Fri Dec 29 22:07:23 2000 +++ linux.ac/include/asm-alpha/pgalloc.h Wed Apr 4 13:31:54 2001 @@ -241,6 +241,9 @@ #define pte_quicklist (quicklists.pte_cache) #define pgtable_cache_size (quicklists.pgtable_cache_sz) +#define pmd_populate(mm, pmd, pte) pmd_set(pmd, pte) +#define pgd_populate(mm, pgd, pmd) pgd_set(pgd, pmd) + extern pgd_t *get_pgd_slow(void); static inline pgd_t *get_pgd_fast(void) @@ -268,9 +271,15 @@ free_page((unsigned long)pgd); } -extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long address_premasked); +static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pmd_t *ret = (pmd_t *)__get_free_page(GFP_KERNEL); + if (ret) + clear_page(ret); + return ret; +} -static inline pmd_t *get_pmd_fast(void) +static inline pmd_t *pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address) { unsigned long *ret; @@ -282,21 +291,27 @@ return (pmd_t *)ret; } -static inline void free_pmd_fast(pmd_t *pmd) +static inline void pmd_free_fast(pmd_t *pmd) { *(unsigned long *)pmd = (unsigned long) pte_quicklist; pte_quicklist = (unsigned long *) pmd; pgtable_cache_size++; } -static inline void free_pmd_slow(pmd_t *pmd) +static inline void pmd_free_slow(pmd_t *pmd) { free_page((unsigned long)pmd); } -extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted); +static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL); + if (pte) + clear_page(pte); + return pte; +} -static inline pte_t *get_pte_fast(void) +static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) { unsigned long *ret; @@ -308,66 +323,22 @@ return (pte_t *)ret; } -static inline void free_pte_fast(pte_t *pte) +static inline void pte_free_fast(pte_t *pte) { *(unsigned long *)pte = (unsigned long) pte_quicklist; pte_quicklist = (unsigned long *) pte; pgtable_cache_size++; } -static inline void free_pte_slow(pte_t *pte) +static inline void pte_free_slow(pte_t *pte) { free_page((unsigned long)pte); } -extern void __bad_pte(pmd_t *pmd); -extern void __bad_pmd(pgd_t *pgd); - -#define pte_free_kernel(pte) free_pte_fast(pte) -#define pte_free(pte) free_pte_fast(pte) -#define pmd_free_kernel(pmd) free_pmd_fast(pmd) -#define pmd_free(pmd) free_pmd_fast(pmd) +#define pte_free(pte) pte_free_fast(pte) +#define pmd_free(pmd) pmd_free_fast(pmd) #define pgd_free(pgd) free_pgd_fast(pgd) #define pgd_alloc() get_pgd_fast() - -static inline pte_t * pte_alloc(pmd_t *pmd, unsigned long address) -{ - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - pte_t *page = get_pte_fast(); - - if (!page) - return get_pte_slow(pmd, address); - pmd_set(pmd, page); - return page + address; - } - if (pmd_bad(*pmd)) { - __bad_pte(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + address; -} - -static inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address) -{ - address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1); - if (pgd_none(*pgd)) { - pmd_t *page = get_pmd_fast(); - - if (!page) - return get_pmd_slow(pgd, address); - pgd_set(pgd, page); - return page + address; - } - if (pgd_bad(*pgd)) { - __bad_pmd(pgd); - return NULL; - } - return (pmd_t *) pgd_page(*pgd) + address; -} - -#define pte_alloc_kernel pte_alloc -#define pmd_alloc_kernel pmd_alloc extern int do_check_pgt_cache(int, int); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/pgtable.h linux.ac/include/asm-alpha/pgtable.h --- linux.vanilla/include/asm-alpha/pgtable.h Mon Dec 4 01:45:20 2000 +++ linux.ac/include/asm-alpha/pgtable.h Tue Apr 3 17:55:14 2001 @@ -59,11 +59,6 @@ #define _PAGE_FOW 0x0004 /* used for page protection (fault on write) */ #define _PAGE_FOE 0x0008 /* used for page protection (fault on exec) */ #define _PAGE_ASM 0x0010 -#if defined(CONFIG_ALPHA_EV6) && !defined(CONFIG_SMP) -#define _PAGE_MBE 0x0080 /* MB disable bit for EV6. */ -#else -#define _PAGE_MBE 0x0000 -#endif #define _PAGE_KRE 0x0100 /* xxx - see below on the "accessed" bit */ #define _PAGE_URE 0x0200 /* xxx */ #define _PAGE_KWE 0x1000 /* used to do the dirty bit in software */ @@ -90,20 +85,19 @@ #define _PFN_MASK 0xFFFFFFFF00000000 #define _PAGE_TABLE (_PAGE_VALID | __DIRTY_BITS | __ACCESS_BITS) -#define _PAGE_CHG_MASK (_PFN_MASK | __DIRTY_BITS | __ACCESS_BITS | _PAGE_MBE) +#define _PAGE_CHG_MASK (_PFN_MASK | __DIRTY_BITS | __ACCESS_BITS) /* - * All the normal masks have the "page accessed" bits on, as any time they - * are used, the page is accessed. They are cleared only by the page-out - * routines. + * All the normal masks have the "page accessed" bits on, as any time they are used, + * the page is accessed. They are cleared only by the page-out routines */ #define PAGE_NONE __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOR | _PAGE_FOW | _PAGE_FOE) #define PAGE_SHARED __pgprot(_PAGE_VALID | __ACCESS_BITS) #define PAGE_COPY __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW) #define PAGE_READONLY __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW) -#define PAGE_KERNEL __pgprot(_PAGE_VALID | _PAGE_ASM | _PAGE_KRE | _PAGE_KWE | _PAGE_MBE) +#define PAGE_KERNEL __pgprot(_PAGE_VALID | _PAGE_ASM | _PAGE_KRE | _PAGE_KWE) -#define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_MBE | (x)) +#define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | __ACCESS_BITS | (x)) #define _PAGE_P(x) _PAGE_NORMAL((x) | (((x) & _PAGE_FOW)?0:_PAGE_FOW)) #define _PAGE_S(x) _PAGE_NORMAL(x) @@ -195,7 +189,6 @@ * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. */ - #define mk_pte(page, pgprot) \ ({ \ pte_t pte; \ @@ -206,7 +199,7 @@ }) extern inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot) -{ pte_t pte; pte_val(pte) = (PHYS_TWIDDLE(physpage) << (32-PAGE_SHIFT)) | (pgprot_val(pgprot) & ~_PAGE_MBE); return pte; } +{ pte_t pte; pte_val(pte) = (PHYS_TWIDDLE(physpage) << (32-PAGE_SHIFT)) | pgprot_val(pgprot); return pte; } extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/tlb.h linux.ac/include/asm-alpha/tlb.h --- linux.vanilla/include/asm-alpha/tlb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-alpha/tlb.h Tue Apr 3 17:55:14 2001 @@ -0,0 +1 @@ +#include <asm-generic/tlb.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-arc/hardware.h linux.ac/include/asm-arm/arch-arc/hardware.h --- linux.vanilla/include/asm-arm/arch-arc/hardware.h Mon Sep 18 23:15:22 2000 +++ linux.ac/include/asm-arm/arch-arc/hardware.h Sat Apr 14 01:37:50 2001 @@ -46,21 +46,28 @@ #define SCREEN_BASE 0x02000000 +#define EXPMASK_BASE 0x03360000 +#define IOEB_BASE 0x03350000 +#define VIDC_BASE 0x03400000 +#define LATCHA_BASE 0x03250040 +#define LATCHB_BASE 0x03250018 +#define IOC_BASE 0x03200000 +#define FLOPPYDMA_BASE 0x0302a000 +#define PCIO_BASE 0x03010000 + +#define vidc_writel(val) __raw_writel(val, VIDC_BASE) + #ifndef __ASSEMBLY__ /* * for use with inb/outb */ -#define IO_VIDC_BASE 0x80100000 #ifdef CONFIG_ARCH_A5K -#define IOEB_VID_CTL 0x800d4012 -#define IOEB_PRESENT 0x800d4014 -#define IOEB_PSCLR 0x800d4016 -#define IOEB_MONTYPE 0x800d401c +#define IOEB_VID_CTL (IOEB_BASE + 0x48) +#define IOEB_PRESENT (IOEB_BASE + 0x50) +#define IOEB_PSCLR (IOEB_BASE + 0x58) +#define IOEB_MONTYPE (IOEB_BASE + 0x70) #endif -#define LATCHAADDR 0x80094010 -#define LATCHBADDR 0x80094006 -#define IOC_BASE 0x80080000 #define IO_EC_IOC4_BASE 0x8009c000 #define IO_EC_IOC_BASE 0x80090000 @@ -74,36 +81,9 @@ #define SCSI_BASE 0x03100000 #endif -/* - * IO definitions - */ -#define EXPMASK_BASE ((volatile unsigned char *)0x03360000) -#define IOEB_BASE ((volatile unsigned char *)0x03350050) -#define PCIO_FLOPPYDMABASE ((volatile unsigned char *)0x0302a000) -#define PCIO_BASE 0x03010000 - -/* - * RAM definitions - */ -#define GET_MEMORY_END(p) (PAGE_OFFSET + (p->u1.s.page_size) * (p->u1.s.nr_pages)) -#define PARAMS_OFFSET 0x7c000 - -#else - -#define IOEB_BASE 0x03350050 -#define IOC_BASE 0x03200000 -#define PCIO_FLOPPYDMABASE 0x0302a000 -#define PCIO_BASE 0x03010000 - -#endif - -#ifndef __ASSEMBLY__ -#define __EXPMASK(offset) (((volatile unsigned char *)EXPMASK_BASE)[offset]) -#else -#define __EXPMASK(offset) offset #endif -#define EXPMASK_STATUS __EXPMASK(0x00) -#define EXPMASK_ENABLE __EXPMASK(0x04) +#define EXPMASK_STATUS (EXPMASK_BASE + 0x00) +#define EXPMASK_ENABLE (EXPMASK_BASE + 0x04) #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-arc/irq.h linux.ac/include/asm-arm/arch-arc/irq.h --- linux.vanilla/include/asm-arm/arch-arc/irq.h Mon Sep 18 23:15:22 2000 +++ linux.ac/include/asm-arm/arch-arc/irq.h Sat Apr 14 01:37:50 2001 @@ -16,6 +16,7 @@ */ #include <linux/config.h> #include <asm/hardware/ioc.h> +#include <asm/io.h> #ifdef CONFIG_ARCH_ARC #define a_clf() clf() @@ -29,105 +30,81 @@ static void arc_mask_irq_ack_a(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; + mask = 1 << irq; a_clf(); - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]\n" -" strb %1, [%3]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKA)), - "r" (ioaddr(IOC_IRQCLRA))); + val = ioc_readb(IOC_IRQMASKA); + ioc_writeb(val & ~mask, IOC_IRQMASKA); + ioc_writeb(mask, IOC_IRQCLRA); a_stf(); } static void arc_mask_irq_a(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; + mask = 1 << irq; a_clf(); - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKA))); + val = ioc_readb(IOC_IRQMASKA); + ioc_writeb(val & ~mask, IOC_IRQMASKA); a_stf(); } static void arc_unmask_irq_a(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; + mask = 1 << irq; a_clf(); - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKA))); + val = ioc_readb(IOC_IRQMASKA); + ioc_writeb(val | mask, IOC_IRQMASKA); a_stf(); } static void arc_mask_irq_b(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKB))); + mask = 1 << (irq & 7); + val = ioc_readb(IOC_IRQMASKB); + ioc_writeb(val & ~mask, IOC_IRQMASKB); } static void arc_unmask_irq_b(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKB))); + mask = 1 << (irq & 7); + val = ioc_readb(IOC_IRQMASKB); + ioc_writeb(val | mask, IOC_IRQMASKB); } static void arc_mask_irq_fiq(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOC_FIQMASK))); + mask = 1 << (irq & 7); + val = ioc_readb(IOC_FIQMASK); + ioc_writeb(val & ~mask, IOC_FIQMASK); } static void arc_unmask_irq_fiq(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOC_FIQMASK))); + mask = 1 << (irq & 7); + val = ioc_readb(IOC_FIQMASK); + ioc_writeb(val | mask, IOC_FIQMASK); } static __inline__ void irq_init_irq(void) { - extern void ecard_disableirq(unsigned int irq); - extern void ecard_enableirq(unsigned int irq); int irq; - outb(0, IOC_IRQMASKA); - outb(0, IOC_IRQMASKB); - outb(0, IOC_FIQMASK); + ioc_writeb(0, IOC_IRQMASKA); + ioc_writeb(0, IOC_IRQMASKB); + ioc_writeb(0, IOC_FIQMASK); for (irq = 0; irq < NR_IRQS; irq++) { switch (irq) { @@ -154,13 +131,6 @@ irq_desc[irq].mask_ack = arc_mask_irq_b; irq_desc[irq].mask = arc_mask_irq_b; irq_desc[irq].unmask = arc_unmask_irq_b; - break; - - case 32 ... 40: - irq_desc[irq].valid = 1; - irq_desc[irq].mask_ack = ecard_disableirq; - irq_desc[irq].mask = ecard_disableirq; - irq_desc[irq].unmask = ecard_enableirq; break; case 64 ... 72: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-arc/system.h linux.ac/include/asm-arm/arch-arc/system.h --- linux.vanilla/include/asm-arm/arch-arc/system.h Mon Sep 18 23:15:22 2000 +++ linux.ac/include/asm-arm/arch-arc/system.h Sat Apr 14 01:37:50 2001 @@ -15,13 +15,6 @@ extern __inline__ void arch_reset(char mode) { - extern void ecard_reset(int card); - - /* - * Reset all expansion cards. - */ - ecard_reset(-1); - /* * copy branch instruction to reset location and call it */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-cl7500/hardware.h linux.ac/include/asm-arm/arch-cl7500/hardware.h --- linux.vanilla/include/asm-arm/arch-cl7500/hardware.h Mon Sep 18 23:15:22 2000 +++ linux.ac/include/asm-arm/arch-cl7500/hardware.h Sat Apr 14 01:37:50 2001 @@ -49,47 +49,18 @@ #define FLUSH_BASE 0xdf000000 - -#ifndef __ASSEMBLY__ - -/* - * for use with inb/outb - */ -#define IO_VIDC_AUDIO_BASE 0x80140000 -#define IO_VIDC_BASE 0x80100000 -#define IO_IOMD_BASE 0x80080000 -#define IOC_BASE 0x80080000 - -/* - * IO definitions - */ -#define EXPMASK_BASE ((volatile unsigned char *)0xe0360000) -#define IOEB_BASE ((volatile unsigned char *)0xe0350050) -#define PCIO_FLOPPYDMABASE ((volatile unsigned char *)0xe002a000) +#define VIDC_BASE 0xe0400000 +#define IOMD_BASE 0xe0200000 +#define IOC_BASE 0xe0200000 +#define FLOPPYDMA_BASE 0xe002a000 #define PCIO_BASE 0xe0010000 -/* in/out bias for the ISA slot region */ -#define ISASLOT_IO 0x80400000 - -/* - * RAM definitions - */ -#define GET_MEMORY_END(p) (PAGE_OFFSET + p->u1.s.page_size * \ - (p->u1.s.pages_in_bank[0] + \ - p->u1.s.pages_in_bank[1] + \ - p->u1.s.pages_in_bank[2] + \ - p->u1.s.pages_in_bank[3])) #define FLUSH_BASE_PHYS 0x00000000 /* ROM */ -#else +#define vidc_writel(val) __raw_writel(val, VIDC_BASE) -#define VIDC_SND_BASE 0xe0500000 -#define VIDC_BASE 0xe0400000 -#define IOMD_BASE 0xe0200000 -#define IOC_BASE 0xe0200000 -#define PCIO_FLOPPYDMABASE 0xe002a000 -#define PCIO_BASE 0xe0010000 +/* in/out bias for the ISA slot region */ +#define ISASLOT_IO 0x80400000 -#endif #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-cl7500/irq.h linux.ac/include/asm-arm/arch-cl7500/irq.h --- linux.vanilla/include/asm-arm/arch-cl7500/irq.h Mon Sep 18 23:15:22 2000 +++ linux.ac/include/asm-arm/arch-cl7500/irq.h Sat Apr 14 01:37:50 2001 @@ -2,14 +2,16 @@ * include/asm-arm/arch-cl7500/irq.h * * Copyright (C) 1996 Russell King - * Copyright (C) 1999 Nexus Electronics Ltd. + * Copyright (C) 1999, 2001 Nexus Electronics Ltd. * * Changelog: * 10-10-1996 RMK Brought up to date with arch-sa110eval * 22-08-1998 RMK Restructured IRQ routines * 11-08-1999 PJB Created ARM7500 version, derived from RiscPC code */ + #include <asm/hardware/iomd.h> +#include <asm/io.h> static inline int fixup_irq(unsigned int irq) { @@ -19,7 +21,7 @@ printk("Spurious ISA IRQ!\n"); return irq; } - irq = 40; + irq = IRQ_ISA_BASE; while (!(isabits & 1)) { irq++; isabits >>= 1; @@ -31,161 +33,121 @@ static void cl7500_mask_irq_ack_a(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]\n" -" strb %1, [%3]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA)), - "r" (ioaddr(IOMD_IRQCLRA))); + mask = 1 << irq; + val = iomd_readb(IOMD_IRQMASKA); + iomd_writeb(val & ~mask, IOMD_IRQMASKA); + iomd_writeb(mask, IOMD_IRQCLRA); } static void cl7500_mask_irq_a(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA))); + mask = 1 << irq; + val = iomd_readb(IOMD_IRQMASKA); + iomd_writeb(val & ~mask, IOMD_IRQMASKA); } static void cl7500_unmask_irq_a(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA))); + mask = 1 << irq; + val = iomd_readb(IOMD_IRQMASKA); + iomd_writeb(val | mask, IOMD_IRQMASKA); } static void cl7500_mask_irq_b(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKB))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_IRQMASKB); + iomd_writeb(val & ~mask, IOMD_IRQMASKB); } static void cl7500_unmask_irq_b(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKB))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_IRQMASKB); + iomd_writeb(val | mask, IOMD_IRQMASKB); } static void cl7500_mask_irq_c(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKC))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_IRQMASKC); + iomd_writeb(val & ~mask, IOMD_IRQMASKC); } static void cl7500_unmask_irq_c(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKC))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_IRQMASKC); + iomd_writeb(val | mask, IOMD_IRQMASKC); } static void cl7500_mask_irq_d(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKD))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_IRQMASKD); + iomd_writeb(val & ~mask, IOMD_IRQMASKD); } static void cl7500_unmask_irq_d(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKD))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_IRQMASKD); + iomd_writeb(val | mask, IOMD_IRQMASKD); } static void cl7500_mask_irq_dma(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_DMAMASK))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_DMAMASK); + iomd_writeb(val & ~mask, IOMD_DMAMASK); } static void cl7500_unmask_irq_dma(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_DMAMASK))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_DMAMASK); + iomd_writeb(val | mask, IOMD_DMAMASK); } static void cl7500_mask_irq_fiq(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_FIQMASK))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_FIQMASK); + iomd_writeb(val & ~mask, IOMD_FIQMASK); } static void cl7500_unmask_irq_fiq(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_FIQMASK))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_FIQMASK); + iomd_writeb(val | mask, IOMD_FIQMASK); } static void no_action(int cpl, void *dev_id, struct pt_regs *regs) @@ -196,14 +158,12 @@ static __inline__ void irq_init_irq(void) { - extern void ecard_disableirq(unsigned int irq); - extern void ecard_enableirq(unsigned int irq); int irq; - outb(0, IOMD_IRQMASKA); - outb(0, IOMD_IRQMASKB); - outb(0, IOMD_FIQMASK); - outb(0, IOMD_DMAMASK); + iomd_writeb(0, IOMD_IRQMASKA); + iomd_writeb(0, IOMD_IRQMASKB); + iomd_writeb(0, IOMD_FIQMASK); + iomd_writeb(0, IOMD_DMAMASK); for (irq = 0; irq < NR_IRQS; irq++) { switch (irq) { @@ -239,14 +199,14 @@ irq_desc[irq].unmask = cl7500_unmask_irq_c; break; - case 32 ... 39: + case 40 ... 47: irq_desc[irq].valid = 1; irq_desc[irq].mask_ack = cl7500_mask_irq_d; irq_desc[irq].mask = cl7500_mask_irq_d; irq_desc[irq].unmask = cl7500_unmask_irq_d; break; - case 40 ... 47: + case 48 ... 55: irq_desc[irq].valid = 1; irq_desc[irq].probe_ok = 1; irq_desc[irq].mask_ack = no_action; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-cl7500/irqs.h linux.ac/include/asm-arm/arch-cl7500/irqs.h --- linux.vanilla/include/asm-arm/arch-cl7500/irqs.h Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-arm/arch-cl7500/irqs.h Sat Apr 14 01:37:50 2001 @@ -35,20 +35,22 @@ #define IRQ_IOP5 29 #define IRQ_IOP6 30 #define IRQ_IOP7 31 -#define IRQ_MOUSERX 32 -#define IRQ_MOUSETX 33 -#define IRQ_ADC 34 -#define IRQ_EVENT1 35 -#define IRQ_EVENT2 36 -#define IRQ_ISA_3 40 -#define IRQ_ISA_4 41 -#define IRQ_ISA_5 42 -#define IRQ_ISA_7 43 -#define IRQ_ISA_9 44 -#define IRQ_ISA_10 45 -#define IRQ_ISA_11 46 -#define IRQ_ISA_14 47 +#define IRQ_MOUSERX 40 +#define IRQ_MOUSETX 41 +#define IRQ_ADC 42 +#define IRQ_EVENT1 43 +#define IRQ_EVENT2 44 + +#define IRQ_ISA_BASE 48 +#define IRQ_ISA_3 48 +#define IRQ_ISA_4 49 +#define IRQ_ISA_5 50 +#define IRQ_ISA_7 51 +#define IRQ_ISA_9 52 +#define IRQ_ISA_10 53 +#define IRQ_ISA_11 54 +#define IRQ_ISA_14 55 #define FIQ_INT9 0 #define FIQ_INT5 1 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-cl7500/shmparam.h linux.ac/include/asm-arm/arch-cl7500/shmparam.h --- linux.vanilla/include/asm-arm/arch-cl7500/shmparam.h Wed Nov 24 06:23:11 1999 +++ linux.ac/include/asm-arm/arch-cl7500/shmparam.h Thu Jan 1 01:00:00 1970 @@ -1,8 +0,0 @@ -/* - * linux/include/asm-arm/arch-cl7500/shmparam.h - * - * Copyright (c) 1999 Nexus Electronics Ltd - */ - -/* The processor-centric definitions are OK. */ - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-cl7500/system.h linux.ac/include/asm-arm/arch-cl7500/system.h --- linux.vanilla/include/asm-arm/arch-cl7500/system.h Mon Sep 18 23:15:22 2000 +++ linux.ac/include/asm-arm/arch-cl7500/system.h Sat Apr 14 01:37:50 2001 @@ -11,12 +11,12 @@ static void arch_idle(void) { while (!current->need_resched && !hlt_counter) - outb(0, IOMD_SUSMODE); + iomd_writeb(0, IOMD_SUSMODE); } #define arch_reset(mode) \ do { \ - outb (0, IOMD_ROMCR0); \ + iomd_writeb(0, IOMD_ROMCR0); \ cpu_reset(0); \ } while (0); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-cl7500/time.h linux.ac/include/asm-arm/arch-cl7500/time.h --- linux.vanilla/include/asm-arm/arch-cl7500/time.h Sun Aug 13 17:54:15 2000 +++ linux.ac/include/asm-arm/arch-cl7500/time.h Sat Apr 14 01:37:50 2001 @@ -13,18 +13,17 @@ { do_timer(regs); do_set_rtc(); + do_profile(regs); { /* Twinkle the lights. */ - static int count, state = 0xff; + static int count, state = 0xff00; if (count-- == 0) { - state ^= 1; + state ^= 0x100; count = 25; - *((volatile unsigned int *)(0xe002ba00)) = state; + *((volatile unsigned int *)LED_ADDRESS) = state; } } - - do_profile(regs); } /* @@ -32,6 +31,9 @@ */ extern __inline__ void setup_timer(void) { + extern void ioctime_init(void); + ioctime_init(); + timer_irq.handler = timer_interrupt; setup_arm_irq(IRQ_TIMER, &timer_irq); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-cl7500/uncompress.h linux.ac/include/asm-arm/arch-cl7500/uncompress.h --- linux.vanilla/include/asm-arm/arch-cl7500/uncompress.h Sun Aug 13 17:54:15 2000 +++ linux.ac/include/asm-arm/arch-cl7500/uncompress.h Sat Apr 14 01:37:50 2001 @@ -1,11 +1,11 @@ /* * linux/include/asm-arm/arch-cl7500/uncompress.h * - * Copyright (C) 1999 Nexus Electronics Ltd. + * Copyright (C) 1999, 2000 Nexus Electronics Ltd. */ #define BASE 0x03010000 -#define SERBASE (BASE + (0x3f8 << 2)) +#define SERBASE (BASE + (0x2f8 << 2)) static __inline__ void putc(char c) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-ebsa110/hardware.h linux.ac/include/asm-arm/arch-ebsa110/hardware.h --- linux.vanilla/include/asm-arm/arch-ebsa110/hardware.h Mon Sep 18 23:15:22 2000 +++ linux.ac/include/asm-arm/arch-ebsa110/hardware.h Sat Apr 14 01:37:50 2001 @@ -12,41 +12,55 @@ #ifndef __ASM_ARCH_HARDWARE_H #define __ASM_ARCH_HARDWARE_H -#ifndef __ASSEMBLY__ - /* - * IO definitions + * The EBSA110 has a weird "ISA IO" region: + * + * Region 0 (addr = 0xf0000000 + io << 2) + * -------------------------------------------------------- + * Physical region IO region + * f0000fe0 - f0000ffc 3f8 - 3ff ttyS0 + * f0000e60 - f0000e64 398 - 399 + * f0000de0 - f0000dfc 378 - 37f lp0 + * f0000be0 - f0000bfc 2f8 - 2ff ttyS1 + * + * Region 1 (addr = 0xf0000000 + (io & ~1) << 1 + (io & 1)) + * -------------------------------------------------------- + * Physical region IO region + * f00014f1 a79 pnp write data + * f00007c0 - f00007c1 3e0 - 3e1 pcmcia + * f00004f1 279 pnp address + * f0000440 - f000046c 220 - 236 eth0 + * f0000405 203 pnp read data */ -#define PIT_CTRL ((volatile unsigned char *)0xf200000d) -#define PIT_T2 ((volatile unsigned char *)0xf2000009) -#define PIT_T1 ((volatile unsigned char *)0xf2000005) -#define PIT_T0 ((volatile unsigned char *)0xf2000001) -/* - * Mapping areas - */ -#define IO_BASE 0xe0000000 +#define ISAMEM_PHYS 0xe0000000 +#define ISAMEM_SIZE 0x10000000 -/* - * RAM definitions - */ -#define FLUSH_BASE_PHYS 0x40000000 +#define ISAIO_PHYS 0xf0000000 +#define ISAIO_SIZE PGDIR_SIZE -#else /* __ASSEMBLY__ */ +#define TRICK0_PHYS 0xf2000000 +#define TRICK1_PHYS 0xf2400000 +#define TRICK2_PHYS 0xf2800000 +#define TRICK3_PHYS 0xf2c00000 +#define TRICK4_PHYS 0xf3000000 +#define TRICK5_PHYS 0xf3400000 +#define TRICK6_PHYS 0xf3800000 +#define TRICK7_PHYS 0xf3c00000 -#define IO_BASE 0 +#define ISAMEM_BASE 0xe0000000 +#define ISAIO_BASE 0xf0000000 -#endif /* __ASSEMBLY__ */ - -#define IO_SIZE 0x20000000 -#define IO_START 0xe0000000 +#define PIT_BASE 0xfc000000 +#define SOFT_BASE 0xfd000000 +/* + * RAM definitions + */ +#define FLUSH_BASE_PHYS 0x40000000 #define FLUSH_BASE 0xdf000000 -#define PCIO_BASE 0xf0000000 - -#define UNCACHEABLE_ADDR 0xf3000000 -#define PARAMS_OFFSET 0x400 +#define UNCACHEABLE_ADDR 0xff000000 /* IRQ_STAT */ #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-ebsa110/io.h linux.ac/include/asm-arm/arch-ebsa110/io.h --- linux.vanilla/include/asm-arm/arch-ebsa110/io.h Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-arm/arch-ebsa110/io.h Sat Apr 14 01:37:50 2001 @@ -13,7 +13,7 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H -#define IO_SPACE_LIMIT 0xffffffff +#define IO_SPACE_LIMIT 0xffff /* * Generic virtual read/write @@ -21,6 +21,39 @@ #define __arch_getw(a) (*(volatile unsigned short *)(a)) #define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v)) -#define __io(p) (ISAIO_BASE + ((p) << 2)) +u8 __inb(int port); +u16 __inw(int port); +u32 __inl(int port); + +#define inb(p) __inb(p) +#define inw(p) __inw(p) +#define inl(p) __inl(p) + +void __outb(u8 val, int port); +void __outw(u16 val, int port); +void __outl(u32 val, int port); + +#define outb(v,p) __outb(v,p) +#define outw(v,p) __outw(v,p) +#define outl(v,p) __outl(v,p) + +u8 __readb(void *addr); +u16 __readw(void *addr); +u32 __readl(void *addr); + +#define readb(b) __readb(b) +#define readw(b) __readw(b) +#define readl(b) __readl(b) + +void __writeb(u8 val, void *addr); +void __writew(u16 val, void *addr); +void __writel(u32 val, void *addr); + +#define writeb(v,b) __writeb(v,b) +#define writew(v,b) __writew(v,b) +#define writel(v,b) __writel(v,b) + +#define __arch_ioremap(off,sz,c) ((void *)(off)) +#define __arch_iounmap(virt) do { } while (0) #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-ebsa110/irq.h linux.ac/include/asm-arm/arch-ebsa110/irq.h --- linux.vanilla/include/asm-arm/arch-ebsa110/irq.h Mon Sep 18 23:15:23 2000 +++ linux.ac/include/asm-arm/arch-ebsa110/irq.h Sat Apr 14 01:37:50 2001 @@ -10,47 +10,4 @@ * Changelog: * 22-08-1998 RMK Restructured IRQ routines */ - -#define IRQ_MCLR ((volatile unsigned char *)0xf3000000) -#define IRQ_MSET ((volatile unsigned char *)0xf2c00000) -#define IRQ_MASK ((volatile unsigned char *)0xf2c00000) - -#define fixup_irq(x) (x) - -static void ebsa110_mask_and_ack_irq(unsigned int irq) -{ - *IRQ_MCLR = 1 << irq; -} - -static void ebsa110_mask_irq(unsigned int irq) -{ - *IRQ_MCLR = 1 << irq; -} - -static void ebsa110_unmask_irq(unsigned int irq) -{ - *IRQ_MSET = 1 << irq; -} - -static __inline__ void irq_init_irq(void) -{ - unsigned long flags; - int irq; - - save_flags_cli (flags); - *IRQ_MCLR = 0xff; - *IRQ_MSET = 0x55; - *IRQ_MSET = 0x00; - if (*IRQ_MASK != 0x55) - while (1); - *IRQ_MCLR = 0xff; /* clear all interrupt enables */ - restore_flags (flags); - - for (irq = 0; irq < NR_IRQS; irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - irq_desc[irq].mask_ack = ebsa110_mask_and_ack_irq; - irq_desc[irq].mask = ebsa110_mask_irq; - irq_desc[irq].unmask = ebsa110_unmask_irq; - } -} +#define fixup_irq(i) (i) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-ebsa110/memory.h linux.ac/include/asm-arm/arch-ebsa110/memory.h --- linux.vanilla/include/asm-arm/arch-ebsa110/memory.h Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-arm/arch-ebsa110/memory.h Sat Apr 14 01:37:50 2001 @@ -35,13 +35,17 @@ #define PHYS_OFFSET (0x00000000UL) #define __virt_to_phys__is_a_macro -#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET) +#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET) #define __phys_to_virt__is_a_macro -#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET) +#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET) +/* + * We keep this 1:1 so that we don't interfere + * with the PCMCIA memory regions + */ #define __virt_to_bus__is_a_macro -#define __virt_to_bus(x) __virt_to_phys(x) +#define __virt_to_bus(x) (x) #define __bus_to_virt__is_a_macro -#define __bus_to_virt(x) __phys_to_virt(x) +#define __bus_to_virt(x) (x) #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-ebsa110/time.h linux.ac/include/asm-arm/arch-ebsa110/time.h --- linux.vanilla/include/asm-arm/arch-ebsa110/time.h Mon Sep 18 23:15:23 2000 +++ linux.ac/include/asm-arm/arch-ebsa110/time.h Sat Apr 14 01:37:50 2001 @@ -18,39 +18,16 @@ #include <asm/leds.h> -#define MCLK_47_8 - -#if defined(MCLK_42_3) -#define PIT1_COUNT 0xecbe -#elif defined(MCLK_47_8) -/* - * This should be 0x10B43, but that doesn't exactly fit. - * We run the timer interrupt at 5ms, and then divide it by - * two in software... This is so that the user processes - * see exactly the same model whichever ARM processor they're - * running on. - */ -#define PIT1_COUNT 0x85A1 -#define DIVISOR 2 -#endif +extern int ebsa110_reset_timer(void); +extern void ebsa110_setup_timer(void); static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - *PIT_T1 = (PIT1_COUNT) & 0xff; - *PIT_T1 = (PIT1_COUNT) >> 8; - -#ifdef DIVISOR - { - static unsigned int divisor; - - if (divisor--) - return; - divisor = DIVISOR - 1; + if (ebsa110_reset_timer()) { + do_leds(); + do_timer(regs); + do_profile(regs); } -#endif - do_leds(); - do_timer(regs); - do_profile(regs); } /* @@ -58,17 +35,7 @@ */ extern __inline__ void setup_timer(void) { - /* - * Timer 1, mode 0, 16-bit, autoreload - */ - *PIT_CTRL = 0x70; - - /* - * Refresh counter clocked at 47.8MHz/7 = 146.4ns - * We want centi-second interrupts - */ - *PIT_T1 = (PIT1_COUNT) & 0xff; - *PIT_T1 = (PIT1_COUNT) >> 8; + ebsa110_setup_timer(); timer_irq.handler = timer_interrupt; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-ebsa110/uncompress.h linux.ac/include/asm-arm/arch-ebsa110/uncompress.h --- linux.vanilla/include/asm-arm/arch-ebsa110/uncompress.h Mon Sep 18 23:15:23 2000 +++ linux.ac/include/asm-arm/arch-ebsa110/uncompress.h Sat Apr 14 01:37:50 2001 @@ -28,7 +28,11 @@ ldrb %0, [%2], #1 teq %0, #0 bne 1b -3: " : : "r" (0), "r" (0), "r" (s), "r" (0xf0000be0) : "cc"); +3: ldrb %1, [%3, #0x14] + and %1, %1, #0x60 + teq %1, #0x60 + bne 3b + " : : "r" (0), "r" (0), "r" (s), "r" (0xf0000be0) : "cc"); } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-ebsa285/irq.h linux.ac/include/asm-arm/arch-ebsa285/irq.h --- linux.vanilla/include/asm-arm/arch-ebsa285/irq.h Mon Sep 18 23:15:23 2000 +++ linux.ac/include/asm-arm/arch-ebsa285/irq.h Sat Apr 14 01:37:50 2001 @@ -19,34 +19,7 @@ #include <asm/irq.h> #include <asm/mach-types.h> -/* - * Footbridge IRQ translation table - * Converts from our IRQ numbers into FootBridge masks - */ -static const int dc21285_irq_mask[] = { - IRQ_MASK_UART_RX, /* 0 */ - IRQ_MASK_UART_TX, /* 1 */ - IRQ_MASK_TIMER1, /* 2 */ - IRQ_MASK_TIMER2, /* 3 */ - IRQ_MASK_TIMER3, /* 4 */ - IRQ_MASK_IN0, /* 5 */ - IRQ_MASK_IN1, /* 6 */ - IRQ_MASK_IN2, /* 7 */ - IRQ_MASK_IN3, /* 8 */ - IRQ_MASK_DOORBELLHOST, /* 9 */ - IRQ_MASK_DMA1, /* 10 */ - IRQ_MASK_DMA2, /* 11 */ - IRQ_MASK_PCI, /* 12 */ - IRQ_MASK_SDRAMPARITY, /* 13 */ - IRQ_MASK_I2OINPOST, /* 14 */ - IRQ_MASK_PCI_ABORT, /* 15 */ - IRQ_MASK_PCI_SERR, /* 16 */ - IRQ_MASK_DISCARD_TIMER, /* 17 */ - IRQ_MASK_PCI_DPERR, /* 18 */ - IRQ_MASK_PCI_PERR, /* 19 */ -}; - -static int isa_irq = -1; +int isa_irq = -1; static inline int fixup_irq(unsigned int irq) { @@ -58,166 +31,3 @@ return irq; } -static void dc21285_mask_irq(unsigned int irq) -{ - *CSR_IRQ_DISABLE = dc21285_irq_mask[_DC21285_INR(irq)]; -} - -static void dc21285_unmask_irq(unsigned int irq) -{ - *CSR_IRQ_ENABLE = dc21285_irq_mask[_DC21285_INR(irq)]; -} - -static void isa_mask_pic_lo_irq(unsigned int irq) -{ - unsigned int mask = 1 << (irq & 7); - - outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO); -} - -static void isa_mask_ack_pic_lo_irq(unsigned int irq) -{ - unsigned int mask = 1 << (irq & 7); - - outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO); - outb(0x20, PIC_LO); -} - -static void isa_unmask_pic_lo_irq(unsigned int irq) -{ - unsigned int mask = 1 << (irq & 7); - - outb(inb(PIC_MASK_LO) & ~mask, PIC_MASK_LO); -} - -static void isa_mask_pic_hi_irq(unsigned int irq) -{ - unsigned int mask = 1 << (irq & 7); - - outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI); -} - -static void isa_mask_ack_pic_hi_irq(unsigned int irq) -{ - unsigned int mask = 1 << (irq & 7); - - outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI); - outb(0x62, PIC_LO); - outb(0x20, PIC_HI); -} - -static void isa_unmask_pic_hi_irq(unsigned int irq) -{ - unsigned int mask = 1 << (irq & 7); - - outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI); -} - -static void no_action(int cpl, void *dev_id, struct pt_regs *regs) -{ -} - -static struct irqaction irq_cascade = { no_action, 0, 0, "cascade", NULL, NULL }; -static struct resource pic1_resource = { "pic1", 0x20, 0x3f }; -static struct resource pic2_resource = { "pic2", 0xa0, 0xbf }; - -static __inline__ void irq_init_irq(void) -{ - int irq; - - /* - * setup DC21285 IRQs - */ - *CSR_IRQ_DISABLE = -1; - *CSR_FIQ_DISABLE = -1; - - for (irq = _DC21285_IRQ(0); irq < _DC21285_IRQ(20); irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - irq_desc[irq].mask_ack = dc21285_mask_irq; - irq_desc[irq].mask = dc21285_mask_irq; - irq_desc[irq].unmask = dc21285_unmask_irq; - } - - /* - * Determine the ISA settings for - * the machine we're running on. - */ - isa_irq = -1; - - if (footbridge_cfn_mode()) { - if (machine_is_ebsa285()) - /* The following is dependent on which slot - * you plug the Southbridge card into. We - * currently assume that you plug it into - * the right-hand most slot. - */ - isa_irq = IRQ_PCI; - - if (machine_is_cats()) - isa_irq = IRQ_IN2; - - if (machine_is_netwinder()) - isa_irq = IRQ_IN3; - } - - if (isa_irq != -1) { - /* - * Setup, and then probe for an ISA PIC - * If the PIC is not there, then we - * ignore the PIC. - */ - outb(0x11, PIC_LO); - outb(_ISA_IRQ(0), PIC_MASK_LO); /* IRQ number */ - outb(0x04, PIC_MASK_LO); /* Slave on Ch2 */ - outb(0x01, PIC_MASK_LO); /* x86 */ - outb(0xf5, PIC_MASK_LO); /* pattern: 11110101 */ - - outb(0x11, PIC_HI); - outb(_ISA_IRQ(8), PIC_MASK_HI); /* IRQ number */ - outb(0x02, PIC_MASK_HI); /* Slave on Ch1 */ - outb(0x01, PIC_MASK_HI); /* x86 */ - outb(0xfa, PIC_MASK_HI); /* pattern: 11111010 */ - - outb(0x0b, PIC_LO); - outb(0x0b, PIC_HI); - - if (inb(PIC_MASK_LO) == 0xf5 && inb(PIC_MASK_HI) == 0xfa) { - outb(0xff, PIC_MASK_LO);/* mask all IRQs */ - outb(0xff, PIC_MASK_HI);/* mask all IRQs */ - } else - isa_irq = -1; - } - - if (isa_irq != -1) { - for (irq = _ISA_IRQ(0); irq < _ISA_IRQ(8); irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - irq_desc[irq].mask_ack = isa_mask_ack_pic_lo_irq; - irq_desc[irq].mask = isa_mask_pic_lo_irq; - irq_desc[irq].unmask = isa_unmask_pic_lo_irq; - } - - for (irq = _ISA_IRQ(8); irq < _ISA_IRQ(16); irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - irq_desc[irq].mask_ack = isa_mask_ack_pic_hi_irq; - irq_desc[irq].mask = isa_mask_pic_hi_irq; - irq_desc[irq].unmask = isa_unmask_pic_hi_irq; - } - - request_resource(&ioport_resource, &pic1_resource); - request_resource(&ioport_resource, &pic2_resource); - setup_arm_irq(IRQ_ISA_CASCADE, &irq_cascade); - setup_arm_irq(isa_irq, &irq_cascade); - - /* - * On the NetWinder, don't automatically - * enable ISA IRQ11 when it is requested. - * There appears to be a missing pull-up - * resistor on this line. - */ - if (machine_is_netwinder()) - irq_desc[_ISA_IRQ(11)].noautoenable = 1; - } -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-l7200/aux_reg.h linux.ac/include/asm-arm/arch-l7200/aux_reg.h --- linux.vanilla/include/asm-arm/arch-l7200/aux_reg.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-arm/arch-l7200/aux_reg.h Sat Apr 14 01:37:50 2001 @@ -0,0 +1,28 @@ +/* + * linux/include/asm-arm/arch-l7200/aux_reg.h + * + * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) + * + * Changelog: + * 08-02-2000 SJH Created file + */ +#ifndef _ASM_ARCH_AUXREG_H +#define _ASM_ARCH_AUXREG_H + +#include <asm/arch/hardware.h> + +#define l7200aux_reg *((volatile unsigned int *) (AUX_BASE)) + +/* + * Auxillary register values + */ +#define AUX_CLEAR 0x00000000 +#define AUX_DIAG_LED_ON 0x00000002 +#define AUX_RTS_UART1 0x00000004 +#define AUX_DTR_UART1 0x00000008 +#define AUX_KBD_COLUMN_12_HIGH 0x00000010 +#define AUX_KBD_COLUMN_12_OFF 0x00000020 +#define AUX_KBD_COLUMN_13_HIGH 0x00000040 +#define AUX_KBD_COLUMN_13_OFF 0x00000080 + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-l7200/dma.h linux.ac/include/asm-arm/arch-l7200/dma.h --- linux.vanilla/include/asm-arm/arch-l7200/dma.h Wed Jul 19 06:43:25 2000 +++ linux.ac/include/asm-arm/arch-l7200/dma.h Sat Apr 14 01:37:50 2001 @@ -1,26 +1,24 @@ /* * linux/include/asm-arm/arch-l7200/dma.h + * + * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) + * + * Changelog: + * 08-29-2000 SJH Created */ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H +/* DMA is not yet implemented! It should be the same as acorn, copy over.. */ + /* * This is the maximum DMA address that can be DMAd to. * There should not be more than (0xd0000000 - 0xc0000000) * bytes of RAM. */ -#define MAX_DMA_ADDRESS 0xd0000000 -#define MAX_DMA_CHANNELS 8 - -#define DMA_0 0 -#define DMA_1 1 -#define DMA_2 2 -#define DMA_3 3 -#define DMA_S0 4 -#define DMA_S1 5 -#define DMA_VIRTUAL_FLOPPY 6 -#define DMA_VIRTUAL_SOUND 7 +#define MAX_DMA_ADDRESS 0xd0000000 +#define MAX_DMA_CHANNELS 0 -#define DMA_FLOPPY DMA_VIRTUAL_FLOPPY +#define DMA_S0 0 -#endif +#endif /* _ASM_ARCH_DMA_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-l7200/gp_timers.h linux.ac/include/asm-arm/arch-l7200/gp_timers.h --- linux.vanilla/include/asm-arm/arch-l7200/gp_timers.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-arm/arch-l7200/gp_timers.h Sat Apr 14 01:37:50 2001 @@ -0,0 +1,42 @@ +/* + * linux/include/asm-arm/arch-l7200/gp_timers.h + * + * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) + * + * Changelog: + * 07-28-2000 SJH Created file + * 08-02-2000 SJH Used structure for registers + */ +#ifndef _ASM_ARCH_GPTIMERS_H +#define _ASM_ARCH_GPTIMERS_H + +#include <asm/arch/hardware.h> + +/* + * Layout of L7200 general purpose timer registers + */ +struct GPT_Regs { + unsigned int TIMERLOAD; + unsigned int TIMERVALUE; + unsigned int TIMERCONTROL; + unsigned int TIMERCLEAR; +}; + +#define GPT_BASE (IO_BASE_2 + 0x3000) +#define l7200_timer1_regs ((volatile struct GPT_Regs *) (GPT_BASE)) +#define l7200_timer2_regs ((volatile struct GPT_Regs *) (GPT_BASE + 0x20)) + +/* + * General register values + */ +#define GPT_PRESCALE_1 0x00000000 +#define GPT_PRESCALE_16 0x00000004 +#define GPT_PRESCALE_256 0x00000008 +#define GPT_MODE_FREERUN 0x00000000 +#define GPT_MODE_PERIODIC 0x00000040 +#define GPT_ENABLE 0x00000080 +#define GPT_BZTOG 0x00000100 +#define GPT_BZMOD 0x00000200 +#define GPT_LOAD_MASK 0x0000ffff + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-l7200/gpio.h linux.ac/include/asm-arm/arch-l7200/gpio.h --- linux.vanilla/include/asm-arm/arch-l7200/gpio.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-arm/arch-l7200/gpio.h Sat Apr 14 01:37:50 2001 @@ -0,0 +1,105 @@ +/****************************************************************************/ +/* + * linux/include/asm-arm/arch-l7200/gpio.h + * + * Registers and helper functions for the L7200 Link-Up Systems + * GPIO. + * + * (C) Copyright 2000, S A McConnell (samcconn@cotw.com) + * + * 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. + */ + +/****************************************************************************/ + +#define GPIO_OFF 0x00005000 /* Offset from IO_START to the GPIO reg's. */ + +/* IO_START and IO_BASE are defined in hardware.h */ + +#define GPIO_START (IO_START_2 + GPIO_OFF) /* Physical addr of the GPIO reg. */ +#define GPIO_BASE (IO_BASE_2 + GPIO_OFF) /* Virtual addr of the GPIO reg. */ + +/* Offsets from the start of the GPIO for all the registers. */ +#define PADR_OFF 0x000 +#define PADDR_OFF 0x004 +#define PASBSR_OFF 0x008 +#define PAEENR_OFF 0x00c +#define PAESNR_OFF 0x010 +#define PAESTR_OFF 0x014 +#define PAIMR_OFF 0x018 +#define PAINT_OFF 0x01c + +#define PBDR_OFF 0x020 +#define PBDDR_OFF 0x024 +#define PBSBSR_OFF 0x028 +#define PBIMR_OFF 0x038 +#define PBINT_OFF 0x03c + +#define PCDR_OFF 0x040 +#define PCDDR_OFF 0x044 +#define PCSBSR_OFF 0x048 +#define PCIMR_OFF 0x058 +#define PCINT_OFF 0x05c + +#define PDDR_OFF 0x060 +#define PDDDR_OFF 0x064 +#define PDSBSR_OFF 0x068 +#define PDEENR_OFF 0x06c +#define PDESNR_OFF 0x070 +#define PDESTR_OFF 0x074 +#define PDIMR_OFF 0x078 +#define PDINT_OFF 0x07c + +#define PEDR_OFF 0x080 +#define PEDDR_OFF 0x084 +#define PESBSR_OFF 0x088 +#define PEEENR_OFF 0x08c +#define PEESNR_OFF 0x090 +#define PEESTR_OFF 0x094 +#define PEIMR_OFF 0x098 +#define PEINT_OFF 0x09c + +/* Define the GPIO registers for use by device drivers and the kernel. */ +#define PADR (*(volatile unsigned long *)(GPIO_BASE+PADR_OFF)) +#define PADDR (*(volatile unsigned long *)(GPIO_BASE+PADDR_OFF)) +#define PASBSR (*(volatile unsigned long *)(GPIO_BASE+PASBSR_OFF)) +#define PAEENR (*(volatile unsigned long *)(GPIO_BASE+PAEENR_OFF)) +#define PAESNR (*(volatile unsigned long *)(GPIO_BASE+PAESNR_OFF)) +#define PAESTR (*(volatile unsigned long *)(GPIO_BASE+PAESTR_OFF)) +#define PAIMR (*(volatile unsigned long *)(GPIO_BASE+PAIMR_OFF)) +#define PAINT (*(volatile unsigned long *)(GPIO_BASE+PAINT_OFF)) + +#define PBDR (*(volatile unsigned long *)(GPIO_BASE+PBDR_OFF)) +#define PBDDR (*(volatile unsigned long *)(GPIO_BASE+PBDDR_OFF)) +#define PBSBSR (*(volatile unsigned long *)(GPIO_BASE+PBSBSR_OFF)) +#define PBIMR (*(volatile unsigned long *)(GPIO_BASE+PBIMR_OFF)) +#define PBINT (*(volatile unsigned long *)(GPIO_BASE+PBINT_OFF)) + +#define PCDR (*(volatile unsigned long *)(GPIO_BASE+PCDR_OFF)) +#define PCDDR (*(volatile unsigned long *)(GPIO_BASE+PCDDR_OFF)) +#define PCSBSR (*(volatile unsigned long *)(GPIO_BASE+PCSBSR_OFF)) +#define PCIMR (*(volatile unsigned long *)(GPIO_BASE+PCIMR_OFF)) +#define PCINT (*(volatile unsigned long *)(GPIO_BASE+PCINT_OFF)) + +#define PDDR (*(volatile unsigned long *)(GPIO_BASE+PDDR_OFF)) +#define PDDDR (*(volatile unsigned long *)(GPIO_BASE+PDDDR_OFF)) +#define PDSBSR (*(volatile unsigned long *)(GPIO_BASE+PDSBSR_OFF)) +#define PDEENR (*(volatile unsigned long *)(GPIO_BASE+PDEENR_OFF)) +#define PDESNR (*(volatile unsigned long *)(GPIO_BASE+PDESNR_OFF)) +#define PDESTR (*(volatile unsigned long *)(GPIO_BASE+PDESTR_OFF)) +#define PDIMR (*(volatile unsigned long *)(GPIO_BASE+PDIMR_OFF)) +#define PDINT (*(volatile unsigned long *)(GPIO_BASE+PDINT_OFF)) + +#define PEDR (*(volatile unsigned long *)(GPIO_BASE+PEDR_OFF)) +#define PEDDR (*(volatile unsigned long *)(GPIO_BASE+PEDDR_OFF)) +#define PESBSR (*(volatile unsigned long *)(GPIO_BASE+PESBSR_OFF)) +#define PEEENR (*(volatile unsigned long *)(GPIO_BASE+PEEENR_OFF)) +#define PEESNR (*(volatile unsigned long *)(GPIO_BASE+PEESNR_OFF)) +#define PEESTR (*(volatile unsigned long *)(GPIO_BASE+PEESTR_OFF)) +#define PEIMR (*(volatile unsigned long *)(GPIO_BASE+PEIMR_OFF)) +#define PEINT (*(volatile unsigned long *)(GPIO_BASE+PEINT_OFF)) + +#define VEE_EN 0x02 +#define BACKLIGHT_EN 0x04 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-l7200/hardware.h linux.ac/include/asm-arm/arch-l7200/hardware.h --- linux.vanilla/include/asm-arm/arch-l7200/hardware.h Tue Nov 28 01:07:59 2000 +++ linux.ac/include/asm-arm/arch-l7200/hardware.h Sat Apr 14 01:37:50 2001 @@ -13,6 +13,8 @@ * 04-21-2000 RS Changed mapping of I/O in virtual space * 04-25-2000 SJH Removed unused symbols and such * 05-05-2000 SJH Complete rewrite + * 07-31-2000 SJH Added undocumented debug auxillary port to + * get at last two columns for keyboard driver */ #ifndef __ASM_ARCH_HARDWARE_H #define __ASM_ARCH_HARDWARE_H @@ -33,6 +35,18 @@ #define IO_START_2 0x90000000 /* I/O */ #define IO_SIZE_2 0x01000000 #define IO_BASE_2 0xd1000000 + +#define AUX_START 0x1a000000 /* AUX PORT */ +#define AUX_SIZE 0x01000000 +#define AUX_BASE 0xd2000000 + +#define FLASH1_START 0x00000000 /* FLASH BANK 1 */ +#define FLASH1_SIZE 0x01000000 +#define FLASH1_BASE 0xd3000000 + +#define FLASH2_START 0x10000000 /* FLASH BANK 2 */ +#define FLASH2_SIZE 0x01000000 +#define FLASH2_BASE 0xd4000000 #define ISA_START 0x20000000 /* ISA */ #define ISA_SIZE 0x20000000 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-l7200/io.h linux.ac/include/asm-arm/arch-l7200/io.h --- linux.vanilla/include/asm-arm/arch-l7200/io.h Sun Aug 13 17:54:15 2000 +++ linux.ac/include/asm-arm/arch-l7200/io.h Sat Apr 14 01:37:50 2001 @@ -3,8 +3,9 @@ * * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) * - * Modifications: + * Changelog: * 03-21-2000 SJH Created from linux/include/asm-arm/arch-nexuspci/io.h + * 08-31-2000 SJH Added in IO functions necessary for new drivers */ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H @@ -14,16 +15,49 @@ #define IO_SPACE_LIMIT 0xffffffff /* + * There are not real ISA nor PCI buses, so we fake it. + */ +#define __io_pci(a) (PCIO_BASE + (a)) +#define __mem_pci(a) ((unsigned long)(a)) +#define __mem_isa(a) ((unsigned long)(a)) + +#define __ioaddr(p) __io_pci(p) + +/* + * Generic virtual read/write + */ +#define __arch_getb(a) (*(volatile unsigned char *)(a)) +#define __arch_getl(a) (*(volatile unsigned int *)(a)) + +extern __inline__ unsigned int __arch_getw(unsigned long a) +{ + unsigned int value; + __asm__ __volatile__("ldr%?h %0, [%1, #0] @ getw" + : "=&r" (value) + : "r" (a)); + return value; +} + +#define __arch_putb(v,a) (*(volatile unsigned char *)(a) = (v)) +#define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v)) + +extern __inline__ void __arch_putw(unsigned int value, unsigned long a) +{ + __asm__ __volatile__("str%?h %0, [%1, #0] @ putw" + : : "r" (value), "r" (a)); +} + +/* * Translated address IO functions * * IO address has already been translated to a virtual address */ -#define outb_t(v,p) (*(volatile unsigned char *)(p) = (v)) -#define inb_t(p) (*(volatile unsigned char *)(p)) -#define outw_t(v,p) (*(volatile unsigned int *)(p) = (v)) -#define inw_t(p) (*(volatile unsigned int *)(p)) -#define outl_t(v,p) (*(volatile unsigned long *)(p) = (v)) -#define inl_t(p) (*(volatile unsigned long *)(p)) +#define outb_t(v,p) (*(volatile unsigned char *)(p) = (v)) +#define inb_t(p) (*(volatile unsigned char *)(p)) +#define outw_t(v,p) (*(volatile unsigned int *)(p) = (v)) +#define inw_t(p) (*(volatile unsigned int *)(p)) +#define outl_t(v,p) (*(volatile unsigned long *)(p) = (v)) +#define inl_t(p) (*(volatile unsigned long *)(p)) /* * FIXME - These are to allow for linking. On all the other @@ -32,11 +66,13 @@ * macros will eventually become more involved. Use * with caution and don't be surprised by kernel oopses!!! */ -#define inb(p) inb_t(p) -#define inw(p) inw_t(p) -#define inl(p) inl_t(p) -#define outb(v,p) outb_t(v,p) -#define outw(v,p) outw_t(v,p) -#define outl(v,p) outl_t(v,p) +#define inb(p) inb_t(p) +#define inw(p) inw_t(p) +#define inl(p) inl_t(p) +#define outb(v,p) outb_t(v,p) +#define outw(v,p) outw_t(v,p) +#define outl(v,p) outl_t(v,p) + +#define __arch_ioremap __ioremap #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-l7200/irq.h linux.ac/include/asm-arm/arch-l7200/irq.h --- linux.vanilla/include/asm-arm/arch-l7200/irq.h Mon May 15 20:00:33 2000 +++ linux.ac/include/asm-arm/arch-l7200/irq.h Sat Apr 14 01:37:50 2001 @@ -10,6 +10,8 @@ * 05-05-2000 SJH Complete rewrite */ +#include <asm/arch/hardware.h> + /* * IRQ base register */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-l7200/irqs.h linux.ac/include/asm-arm/arch-l7200/irqs.h --- linux.vanilla/include/asm-arm/arch-l7200/irqs.h Mon May 15 20:00:33 2000 +++ linux.ac/include/asm-arm/arch-l7200/irqs.h Sat Apr 14 01:37:50 2001 @@ -7,6 +7,12 @@ * Changelog: * 01-02-2000 RS Create l7200 version * 03-28-2000 SJH Removed unused interrupt + * 07-28-2000 SJH Added pseudo-keyboard interrupt + */ + +/* + * NOTE: The second timer (Timer 2) is used as the keyboard + * interrupt when the keyboard driver is enabled. */ #define NR_IRQS 32 @@ -16,7 +22,7 @@ #define IRQ_DEBUG_RX 2 /* Comm Rx debug */ #define IRQ_DEBUG_TX 3 /* Comm Tx debug */ #define IRQ_GCTC1 4 /* Timer 1 */ -#define IRQ_GCTC2 5 /* Timer 2 */ +#define IRQ_GCTC2 5 /* Timer 2 / Keyboard */ #define IRQ_DMA 6 /* DMA controller */ #define IRQ_CLCD 7 /* Color LCD controller */ #define IRQ_SM_RX 8 /* Smart card */ @@ -40,6 +46,11 @@ #define IRQ_INT0 26 /* External active low interrupt */ #define IRQ_INT1 27 /* External active low interrupt */ #define IRQ_INT2 28 /* External active low interrupt */ -#define IRQ_INT3 29 /* External active low interrupt */ +#define IRQ_UCB1200 29 /* Interrupt generated by UCB1200*/ #define IRQ_BAT_LO 30 /* Low batery or external power */ #define IRQ_MEDIA_CHG 31 /* Media change interrupt */ + +/* + * This is the offset of the FIQ "IRQ" numbers + */ +#define FIQ_START 64 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-l7200/keyboard.h linux.ac/include/asm-arm/arch-l7200/keyboard.h --- linux.vanilla/include/asm-arm/arch-l7200/keyboard.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-arm/arch-l7200/keyboard.h Sat Apr 14 01:37:50 2001 @@ -0,0 +1,49 @@ +/* + * linux/include/asm-arm/arch-l7200/keyboard.h + * + * Keyboard driver definitions for LinkUp Systems L7200 architecture + * + * Copyright (C) 2000 Scott A McConnell (samcconn@cotw.com) + * Steve Hill (sjhill@cotw.com) + * + * 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. + * + * Changelog: + * 07-18-2000 SAM Created file + * 07-28-2000 SJH Complete rewrite + */ + +#include <asm/irq.h> + +/* + * Layout of L7200 keyboard registers + */ +struct KBD_Port { + unsigned int KBDR; + unsigned int KBDMR; + unsigned int KBSBSR; + unsigned int Reserved; + unsigned int KBKSR; +}; + +#define KBD_BASE IO_BASE_2 + 0x4000 +#define l7200kbd_hwregs ((volatile struct KBD_Port *) (KBD_BASE)) + +extern void l7200kbd_init_hw(void); +extern int l7200kbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); + +#define kbd_setkeycode(sc,kc) (-EINVAL) +#define kbd_getkeycode(sc) (-EINVAL) + +#define kbd_translate(sc, kcp, rm) ({ *(kcp) = (sc); 1; }) +#define kbd_unexpected_up(kc) (0200) +#define kbd_leds(leds) do {} while (0) +#define kbd_init_hw() l7200kbd_init_hw() +#define kbd_sysrq_xlate do {} while (0) +#define kbd_disable_irq() disable_irq(IRQ_GCTC2) +#define kbd_enable_irq() enable_irq(IRQ_GCTC2) + +#define SYSRQ_KEY 13 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-l7200/pmpcon.h linux.ac/include/asm-arm/arch-l7200/pmpcon.h --- linux.vanilla/include/asm-arm/arch-l7200/pmpcon.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-arm/arch-l7200/pmpcon.h Sat Apr 14 01:37:50 2001 @@ -0,0 +1,46 @@ +/****************************************************************************/ +/* + * linux/include/asm-arm/arch-l7200/pmpcon.h + * + * Registers and helper functions for the L7200 Link-Up Systems + * DC/DC converter register. + * + * (C) Copyright 2000, S A McConnell (samcconn@cotw.com) + * + * 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. + */ + +/****************************************************************************/ + +#define PMPCON_OFF 0x00006000 /* Offset from IO_START_2. */ + +/* IO_START_2 and IO_BASE_2 are defined in hardware.h */ + +#define PMPCON_START (IO_START_2 + PMPCON_OFF) /* Physical address of reg. */ +#define PMPCON_BASE (IO_BASE_2 + PMPCON_OFF) /* Virtual address of reg. */ + + +#define PMPCON (*(volatile unsigned int *)(PMPCON_BASE)) + +#define PWM2_50CYCLE 0x800 +#define CONTRAST 0x9 + +#define PWM1H (CONTRAST) +#define PWM1L (CONTRAST << 4) + +#define PMPCON_VALUE (PWM2_50CYCLE | PWM1L | PWM1H) + +/* PMPCON = 0x811; // too light and fuzzy + * PMPCON = 0x844; + * PMPCON = 0x866; // better color poor depth + * PMPCON = 0x888; // Darker but better depth + * PMPCON = 0x899; // Darker even better depth + * PMPCON = 0x8aa; // too dark even better depth + * PMPCON = 0X8cc; // Way too dark + */ + +/* As CONTRAST value increases the greater the depth perception and + * the darker the colors. + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-l7200/pmu.h linux.ac/include/asm-arm/arch-l7200/pmu.h --- linux.vanilla/include/asm-arm/arch-l7200/pmu.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-arm/arch-l7200/pmu.h Sat Apr 14 01:37:50 2001 @@ -0,0 +1,125 @@ +/****************************************************************************/ +/* + * linux/include/asm-arm/arch-l7200/pmu.h + * + * Registers and helper functions for the L7200 Link-Up Systems + * Power Management Unit (PMU). + * + * (C) Copyright 2000, S A McConnell (samcconn@cotw.com) + * + * 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. + */ + +/****************************************************************************/ + +#define PMU_OFF 0x00050000 /* Offset from IO_START to the PMU registers. */ + +/* IO_START and IO_BASE are defined in hardware.h */ + +#define PMU_START (IO_START + PMU_OFF) /* Physical addr. of the PMU reg. */ +#define PMU_BASE (IO_BASE + PMU_OFF) /* Virtual addr. of the PMU reg. */ + + +/* Define the PMU registers for use by device drivers and the kernel. */ + +typedef struct { + unsigned int CURRENT; /* Current configuration register */ + unsigned int NEXT; /* Next configuration register */ + unsigned int reserved; + unsigned int RUN; /* Run configuration register */ + unsigned int COMM; /* Configuration command register */ + unsigned int SDRAM; /* SDRAM configuration bypass register */ +} pmu_interface; + +#define PMU ((volatile pmu_interface *)(PMU_BASE)) + + +/* Macro's for reading the common register fields. */ + +#define GET_TRANSOP(reg) ((reg >> 25) & 0x03) /* Bits 26-25 */ +#define GET_OSCEN(reg) ((reg >> 16) & 0x01) +#define GET_OSCMUX(reg) ((reg >> 15) & 0x01) +#define GET_PLLMUL(reg) ((reg >> 9) & 0x3f) /* Bits 14-9 */ +#define GET_PLLEN(reg) ((reg >> 8) & 0x01) +#define GET_PLLMUX(reg) ((reg >> 7) & 0x01) +#define GET_BCLK_DIV(reg) ((reg >> 3) & 0x03) /* Bits 4-3 */ +#define GET_SDRB_SEL(reg) ((reg >> 2) & 0x01) +#define GET_SDRF_SEL(reg) ((reg >> 1) & 0x01) +#define GET_FASTBUS(reg) (reg & 0x1) + +/* CFG_NEXT register */ + +#define CFG_NEXT_CLOCKRECOVERY ((PMU->NEXT >> 18) & 0x7f) /* Bits 24-18 */ +#define CFG_NEXT_INTRET ((PMU->NEXT >> 17) & 0x01) +#define CFG_NEXT_SDR_STOP ((PMU->NEXT >> 6) & 0x01) +#define CFG_NEXT_SYSCLKEN ((PMU->NEXT >> 5) & 0x01) + +/* Useful field values that can be used to construct the + * CFG_NEXT and CFG_RUN registers. + */ + +#define TRANSOP_NOP 0<<25 /* NOCHANGE_NOSTALL */ +#define NOCHANGE_STALL 1<<25 +#define CHANGE_NOSTALL 2<<25 +#define CHANGE_STALL 3<<25 + +#define INTRET 1<<17 +#define OSCEN 1<<16 +#define OSCMUX 1<<15 + +/* PLL frequencies */ + +#define PLLMUL_0 0<<9 /* 3.6864 MHz */ +#define PLLMUL_1 1<<9 /* ?????? MHz */ +#define PLLMUL_5 5<<9 /* 18.432 MHz */ +#define PLLMUL_10 10<<9 /* 36.864 MHz */ +#define PLLMUL_18 18<<9 /* ?????? MHz */ +#define PLLMUL_20 20<<9 /* 73.728 MHz */ +#define PLLMUL_32 32<<9 /* ?????? MHz */ +#define PLLMUL_35 35<<9 /* 129.024 MHz */ +#define PLLMUL_36 36<<9 /* ?????? MHz */ +#define PLLMUL_39 39<<9 /* ?????? MHz */ +#define PLLMUL_40 40<<9 /* 147.456 MHz */ + +/* Clock recovery times */ + +#define CRCLOCK_1 1<<18 +#define CRCLOCK_2 2<<18 +#define CRCLOCK_4 4<<18 +#define CRCLOCK_8 8<<18 +#define CRCLOCK_16 16<<18 +#define CRCLOCK_32 32<<18 +#define CRCLOCK_63 63<<18 +#define CRCLOCK_127 127<<18 + +#define PLLEN 1<<8 +#define PLLMUX 1<<7 +#define SDR_STOP 1<<6 +#define SYSCLKEN 1<<5 + +#define BCLK_DIV_4 2<<3 +#define BCLK_DIV_2 1<<3 +#define BCLK_DIV_1 0<<3 + +#define SDRB_SEL 1<<2 +#define SDRF_SEL 1<<1 +#define FASTBUS 1<<0 + + +/* CFG_SDRAM */ + +#define SDRREFFQ 1<<0 /* Only if SDRSTOPRQ is not set. */ +#define SDRREFACK 1<<1 /* Read-only */ +#define SDRSTOPRQ 1<<2 /* Only if SDRREFFQ is not set. */ +#define SDRSTOPACK 1<<3 /* Read-only */ +#define PICEN 1<<4 /* Enable Co-procesor */ +#define PICTEST 1<<5 + +#define GET_SDRREFFQ ((PMU->SDRAM >> 0) & 0x01) +#define GET_SDRREFACK ((PMU->SDRAM >> 1) & 0x01) /* Read-only */ +#define GET_SDRSTOPRQ ((PMU->SDRAM >> 2) & 0x01) +#define GET_SDRSTOPACK ((PMU->SDRAM >> 3) & 0x01) /* Read-only */ +#define GET_PICEN ((PMU->SDRAM >> 4) & 0x01) +#define GET_PICTEST ((PMU->SDRAM >> 5) & 0x01) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-l7200/serial.h linux.ac/include/asm-arm/arch-l7200/serial.h --- linux.vanilla/include/asm-arm/arch-l7200/serial.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-arm/arch-l7200/serial.h Sat Apr 14 01:37:50 2001 @@ -0,0 +1,39 @@ +/* + * linux/include/asm-arm/arch-l7200/serial.h + * + * Copyright (c) 2000 Rob Scott (rscott@mtrob.fdns.net) + * Steve Hill (sjhill@cotw.com) + * + * Changelog: + * 03-20-2000 SJH Created + * 03-26-2000 SJH Added flags for serial ports + * 03-27-2000 SJH Corrected BASE_BAUD value + * 04-14-2000 RS Made register addr dependent on IO_BASE + * 05-03-2000 SJH Complete rewrite + * 05-09-2000 SJH Stripped out architecture specific serial stuff + * and placed it in a separate file + * 07-28-2000 SJH Moved base baud rate variable + */ +#ifndef __ASM_ARCH_SERIAL_H +#define __ASM_ARCH_SERIAL_H + +/* + * This assumes you have a 3.6864 MHz clock for your UART. + */ +#define BASE_BAUD 3686400 + +/* + * Standard COM flags + */ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) + +#define RS_TABLE_SIZE 2 + +#define STD_SERIAL_PORT_DEFNS \ + /* MAGIC UART CLK PORT IRQ FLAGS */ \ + { 0, BASE_BAUD, UART1_BASE, IRQ_UART_1, STD_COM_FLAGS }, /* ttyLU0 */ \ + { 0, BASE_BAUD, UART2_BASE, IRQ_UART_2, STD_COM_FLAGS }, /* ttyLU1 */ \ + +#define EXTRA_SERIAL_PORT_DEFNS + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-l7200/sib.h linux.ac/include/asm-arm/arch-l7200/sib.h --- linux.vanilla/include/asm-arm/arch-l7200/sib.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-arm/arch-l7200/sib.h Sat Apr 14 01:37:50 2001 @@ -0,0 +1,119 @@ +/****************************************************************************/ +/* + * linux/include/asm-arm/arch-l7200/sib.h + * + * Registers and helper functions for the Serial Interface Bus. + * + * (C) Copyright 2000, S A McConnell (samcconn@cotw.com) + * + * 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. + */ + +/****************************************************************************/ + +#define SIB_OFF 0x00040000 /* Offset from IO_START to the SIB reg's. */ + +/* IO_START and IO_BASE are defined in hardware.h */ + +#define SIB_START (IO_START + SIB_OFF) /* Physical addr of the SIB reg. */ +#define SIB_BASE (IO_BASE + SIB_OFF) /* Virtual addr of the SIB reg. */ + +/* Offsets from the start of the SIB for all the registers. */ + +/* Define the SIB registers for use by device drivers and the kernel. */ + +typedef struct +{ + unsigned int MCCR; /* SIB Control Register Offset: 0x00 */ + unsigned int RES1; /* Reserved Offset: 0x04 */ + unsigned int MCDR0; /* SIB Data Register 0 Offset: 0x08 */ + unsigned int MCDR1; /* SIB Data Register 1 Offset: 0x0c */ + unsigned int MCDR2; /* SIB Data Register 2 (UCB1x00) Offset: 0x10 */ + unsigned int RES2; /* Reserved Offset: 0x14 */ + unsigned int MCSR; /* SIB Status Register Offset: 0x18 */ +} SIB_Interface; + +#define SIB ((volatile SIB_Interface *) (SIB_BASE)) + +/* MCCR */ + +#define INTERNAL_FREQ 9216000 /* Hertz */ +#define AUDIO_FREQ 5000 /* Hertz */ +#define TELECOM_FREQ 5000 /* Hertz */ + +#define AUDIO_DIVIDE (INTERNAL_FREQ / (32 * AUDIO_FREQ)) +#define TELECOM_DIVIDE (INTERNAL_FREQ / (32 * TELECOM_FREQ)) + +#define MCCR_ASD57 AUDIO_DIVIDE +#define MCCR_TSD57 (TELECOM_DIVIDE << 8) +#define MCCR_MCE (1 << 16) /* SIB enable */ +#define MCCR_ECS (1 << 17) /* External Clock Select */ +#define MCCR_ADM (1 << 18) /* A/D Data Sampling */ +#define MCCR_PMC (1 << 26) /* PIN Multiplexer Control */ + + +#define GET_ASD ((SIB->MCCR >> 0) & 0x3f) /* Audio Sample Rate Div. */ +#define GET_TSD ((SIB->MCCR >> 8) & 0x3f) /* Telcom Sample Rate Div. */ +#define GET_MCE ((SIB->MCCR >> 16) & 0x01) /* SIB Enable */ +#define GET_ECS ((SIB->MCCR >> 17) & 0x01) /* External Clock Select */ +#define GET_ADM ((SIB->MCCR >> 18) & 0x01) /* A/D Data Sampling Mode */ +#define GET_TTM ((SIB->MCCR >> 19) & 0x01) /* Telco Trans. FIFO I mask */ +#define GET_TRM ((SIB->MCCR >> 20) & 0x01) /* Telco Recv. FIFO I mask */ +#define GET_ATM ((SIB->MCCR >> 21) & 0x01) /* Audio Trans. FIFO I mask */ +#define GET_ARM ((SIB->MCCR >> 22) & 0x01) /* Audio Recv. FIFO I mask */ +#define GET_LBM ((SIB->MCCR >> 23) & 0x01) /* Loop Back Mode */ +#define GET_ECP ((SIB->MCCR >> 24) & 0x03) /* Extern. Clck Prescale sel */ +#define GET_PMC ((SIB->MCCR >> 26) & 0x01) /* PIN Multiplexer Control */ +#define GET_ERI ((SIB->MCCR >> 27) & 0x01) /* External Read Interrupt */ +#define GET_EWI ((SIB->MCCR >> 28) & 0x01) /* External Write Interrupt */ + +/* MCDR0 */ + +#define AUDIO_RECV ((SIB->MCDR0 >> 4) & 0xfff) +#define AUDIO_WRITE(v) ((SIB->MCDR0 = (v & 0xfff) << 4)) + +/* MCDR1 */ + +#define TELECOM_RECV ((SIB->MCDR1 >> 2) & 032fff) +#define TELECOM_WRITE(v) ((SIB->MCDR1 = (v & 0x3fff) << 2)) + + +/* MCSR */ + +#define MCSR_ATU (1 << 4) /* Audio Transmit FIFO Underrun */ +#define MCSR_ARO (1 << 5) /* Audio Receive FIFO Underrun */ +#define MCSR_TTU (1 << 6) /* TELECOM Transmit FIFO Underrun */ +#define MCSR_TRO (1 << 7) /* TELECOM Receive FIFO Underrun */ + +#define MCSR_CLEAR_UNDERUN_BITS (MCSR_ATU | MCSR_ARO | MCSR_TTU | MCSR_TRO) + + +#define GET_ATS ((SIB->MCSR >> 0) & 0x01) /* Audio Transmit FIFO Service Req*/ +#define GET_ARS ((SIB->MCSR >> 1) & 0x01) /* Audio Recv FIFO Service Request*/ +#define GET_TTS ((SIB->MCSR >> 2) & 0x01) /* TELECOM Transmit FIFO Flag */ +#define GET_TRS ((SIB->MCSR >> 3) & 0x01) /* TELECOM Recv FIFO Service Req. */ +#define GET_ATU ((SIB->MCSR >> 4) & 0x01) /* Audio Transmit FIFO Underrun */ +#define GET_ARO ((SIB->MCSR >> 5) & 0x01) /* Audio Receive FIFO Underrun */ +#define GET_TTU ((SIB->MCSR >> 6) & 0x01) /* TELECOM Transmit FIFO Underrun */ +#define GET_TRO ((SIB->MCSR >> 7) & 0x01) /* TELECOM Receive FIFO Underrun */ +#define GET_ANF ((SIB->MCSR >> 8) & 0x01) /* Audio Transmit FIFO not full */ +#define GET_ANE ((SIB->MCSR >> 9) & 0x01) /* Audio Receive FIFO not empty */ +#define GET_TNF ((SIB->MCSR >> 10) & 0x01) /* Telecom Transmit FIFO not full */ +#define GET_TNE ((SIB->MCSR >> 11) & 0x01) /* Telecom Receive FIFO not empty */ +#define GET_CWC ((SIB->MCSR >> 12) & 0x01) /* Codec Write Complete */ +#define GET_CRC ((SIB->MCSR >> 13) & 0x01) /* Codec Read Complete */ +#define GET_ACE ((SIB->MCSR >> 14) & 0x01) /* Audio Codec Enabled */ +#define GET_TCE ((SIB->MCSR >> 15) & 0x01) /* Telecom Codec Enabled */ + +/* MCDR2 */ + +#define MCDR2_rW (1 << 16) + +#define WRITE_MCDR2(reg, data) (SIB->MCDR2 =((reg<<17)|MCDR2_rW|(data&0xffff))) +#define MCDR2_WRITE_COMPLETE GET_CWC + +#define INITIATE_MCDR2_READ(reg) (SIB->MCDR2 = (reg << 17)) +#define MCDR2_READ_COMPLETE GET_CRC +#define MCDR2_READ (SIB->MCDR2 & 0xffff) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-l7200/sys-clock.h linux.ac/include/asm-arm/arch-l7200/sys-clock.h --- linux.vanilla/include/asm-arm/arch-l7200/sys-clock.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-arm/arch-l7200/sys-clock.h Sat Apr 14 01:37:50 2001 @@ -0,0 +1,67 @@ +/****************************************************************************/ +/* + * linux/include/asm-arm/arch-l7200/sys-clock.h + * + * Registers and helper functions for the L7200 Link-Up Systems + * System clocks. + * + * (C) Copyright 2000, S A McConnell (samcconn@cotw.com) + * + * 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. + */ + +/****************************************************************************/ + +#define SYS_CLOCK_OFF 0x00050030 /* Offset from IO_START. */ + +/* IO_START and IO_BASE are defined in hardware.h */ + +#define SYS_CLOCK_START (IO_START + SYS_CLCOK_OFF) /* Physical address */ +#define SYS_CLOCK_BASE (IO_BASE + SYS_CLOCK_OFF) /* Virtual address */ + +/* Define the interface to the SYS_CLOCK */ + +typedef struct +{ + unsigned int ENABLE; + unsigned int ESYNC; + unsigned int SELECT; +} sys_clock_interface; + +#define SYS_CLOCK ((volatile sys_clock_interface *)(SYS_CLOCK_BASE)) + +//#define CLOCK_EN (*(volatile unsigned long *)(PMU_BASE+CLOCK_EN_OFF)) +//#define CLOCK_ESYNC (*(volatile unsigned long *)(PMU_BASE+CLOCK_ESYNC_OFF)) +//#define CLOCK_SEL (*(volatile unsigned long *)(PMU_BASE+CLOCK_SEL_OFF)) + +/* SYS_CLOCK -> ENABLE */ + +#define SYN_EN 1<<0 +#define B18M_EN 1<<1 +#define CLK3M6_EN 1<<2 +#define BUART_EN 1<<3 +#define CLK18MU_EN 1<<4 +#define FIR_EN 1<<5 +#define MIRN_EN 1<<6 +#define UARTM_EN 1<<7 +#define SIBADC_EN 1<<8 +#define ALTD_EN 1<<9 +#define CLCLK_EN 1<<10 + +/* SYS_CLOCK -> SELECT */ + +#define CLK18M_DIV 1<<0 +#define MIR_SEL 1<<1 +#define SSP_SEL 1<<4 +#define MM_DIV 1<<5 +#define MM_SEL 1<<6 +#define ADC_SEL_2 0<<7 +#define ADC_SEL_4 1<<7 +#define ADC_SEL_8 3<<7 +#define ADC_SEL_16 7<<7 +#define ADC_SEL_32 0x0f<<7 +#define ADC_SEL_64 0x1f<<7 +#define ADC_SEL_128 0x3f<<7 +#define ALTD_SEL 1<<13 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-l7200/system.h linux.ac/include/asm-arm/arch-l7200/system.h --- linux.vanilla/include/asm-arm/arch-l7200/system.h Sun Aug 13 17:54:15 2000 +++ linux.ac/include/asm-arm/arch-l7200/system.h Sat Apr 14 01:37:50 2001 @@ -14,9 +14,8 @@ static void arch_idle(void) { - while (!current->need_resched && !hlt_counter) { - cpu_do_idle(IDLE_WAIT_SLOW); - } + /* fixme: this needs to be cleaned up (converted from ASM code) --rmk */ + *(unsigned long *)(IO_BASE + 0x50004) = 1; /* idle mode */ } extern inline void arch_reset(char mode) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-l7200/time.h linux.ac/include/asm-arm/arch-l7200/time.h --- linux.vanilla/include/asm-arm/arch-l7200/time.h Sun Aug 13 17:54:15 2000 +++ linux.ac/include/asm-arm/arch-l7200/time.h Sat Apr 14 01:37:50 2001 @@ -40,7 +40,7 @@ #define RTC_EN_STWDOG 0x08 /* Enable watchdog */ /* - * Handler for timer interrupt + * Handler for RTC timer interrupt */ static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { @@ -50,7 +50,7 @@ } /* - * Set up timer interrupt, and return the current time in seconds. + * Set up RTC timer interrupt, and return the current time in seconds. */ extern __inline__ void setup_timer(void) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-rpc/hardware.h linux.ac/include/asm-arm/arch-rpc/hardware.h --- linux.vanilla/include/asm-arm/arch-rpc/hardware.h Mon Sep 18 23:15:23 2000 +++ linux.ac/include/asm-arm/arch-rpc/hardware.h Sat Apr 14 01:37:50 2001 @@ -43,66 +43,27 @@ #define FLUSH_BASE 0xdf000000 #define UNCACHEABLE_ADDR 0xdf010000 - -#ifndef __ASSEMBLY__ - -/* - * for use with inb/outb - */ -#define IO_VIDC_AUDIO_BASE 0x80140000 -#define IO_VIDC_BASE 0x80100000 -#define IO_IOMD_BASE 0x80080000 -#define IOC_BASE 0x80080000 - -#define IO_EC_EASI_BASE 0x81400000 -#define IO_EC_IOC4_BASE 0x8009c000 -#define IO_EC_IOC_BASE 0x80090000 -#define IO_EC_MEMC8_BASE 0x8000ac00 -#define IO_EC_MEMC_BASE 0x80000000 - -/* - * IO definitions - */ -#define EXPMASK_BASE ((volatile unsigned char *)0xe0360000) -#define IOEB_BASE ((volatile unsigned char *)0xe0350050) -#define PCIO_FLOPPYDMABASE ((volatile unsigned char *)0xe002a000) -#define PCIO_BASE 0xe0010000 - /* - * Offsets from RAM base + * IO Addresses */ -#define PARAMS_OFFSET 0x0100 - -/* - * RAM definitions - */ -#define GET_MEMORY_END(p) (PAGE_OFFSET + p->u1.s.page_size * \ - (p->u1.s.pages_in_bank[0] + \ - p->u1.s.pages_in_bank[1] + \ - p->u1.s.pages_in_bank[2] + \ - p->u1.s.pages_in_bank[3])) - -#define Z_PARAMS_BASE (RAM_START + PARAMS_OFFSET) -#define FLUSH_BASE_PHYS 0x00000000 /* ROM */ - -#else - -#define VIDC_SND_BASE 0xe0500000 #define VIDC_BASE 0xe0400000 +#define EXPMASK_BASE 0xe0360000 #define IOMD_BASE 0xe0200000 #define IOC_BASE 0xe0200000 -#define PCIO_FLOPPYDMABASE 0xe002a000 #define PCIO_BASE 0xe0010000 +#define FLOPPYDMA_BASE 0xe002a000 -#endif +#define FLUSH_BASE_PHYS 0x00000000 /* ROM */ + +#define vidc_writel(val) __raw_writel(val, VIDC_BASE) -#ifndef __ASSEMBLY__ -#define __EXPMASK(offset) (((volatile unsigned char *)EXPMASK_BASE)[offset]) -#else -#define __EXPMASK(offset) offset -#endif +#define IO_EC_EASI_BASE 0x81400000 +#define IO_EC_IOC4_BASE 0x8009c000 +#define IO_EC_IOC_BASE 0x80090000 +#define IO_EC_MEMC8_BASE 0x8000ac00 +#define IO_EC_MEMC_BASE 0x80000000 -#define EXPMASK_STATUS __EXPMASK(0x00) -#define EXPMASK_ENABLE __EXPMASK(0x04) +#define EXPMASK_STATUS (EXPMASK_BASE + 0x00) +#define EXPMASK_ENABLE (EXPMASK_BASE + 0x04) #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-rpc/irq.h linux.ac/include/asm-arm/arch-rpc/irq.h --- linux.vanilla/include/asm-arm/arch-rpc/irq.h Mon Sep 18 23:15:23 2000 +++ linux.ac/include/asm-arm/arch-rpc/irq.h Sat Apr 14 01:37:50 2001 @@ -12,129 +12,100 @@ * 22-08-1998 RMK Restructured IRQ routines */ #include <asm/hardware/iomd.h> +#include <asm/io.h> #define fixup_irq(x) (x) static void rpc_mask_irq_ack_a(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]\n" -" strb %1, [%3]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA)), - "r" (ioaddr(IOMD_IRQCLRA))); + mask = 1 << irq; + val = iomd_readb(IOMD_IRQMASKA); + iomd_writeb(val & ~mask, IOMD_IRQMASKA); + iomd_writeb(mask, IOMD_IRQCLRA); } static void rpc_mask_irq_a(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA))); + mask = 1 << irq; + val = iomd_readb(IOMD_IRQMASKA); + iomd_writeb(val & ~mask, IOMD_IRQMASKA); } static void rpc_unmask_irq_a(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA))); + mask = 1 << irq; + val = iomd_readb(IOMD_IRQMASKA); + iomd_writeb(val | mask, IOMD_IRQMASKA); } static void rpc_mask_irq_b(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKB))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_IRQMASKB); + iomd_writeb(val & ~mask, IOMD_IRQMASKB); } static void rpc_unmask_irq_b(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKB))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_IRQMASKB); + iomd_writeb(val | mask, IOMD_IRQMASKB); } static void rpc_mask_irq_dma(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_DMAMASK))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_DMAMASK); + iomd_writeb(val & ~mask, IOMD_DMAMASK); } static void rpc_unmask_irq_dma(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_DMAMASK))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_DMAMASK); + iomd_writeb(val | mask, IOMD_DMAMASK); } static void rpc_mask_irq_fiq(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_FIQMASK))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_FIQMASK); + iomd_writeb(val & ~mask, IOMD_FIQMASK); } static void rpc_unmask_irq_fiq(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_FIQMASK))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_FIQMASK); + iomd_writeb(val | mask, IOMD_FIQMASK); } static __inline__ void irq_init_irq(void) { - extern void ecard_disableirq(unsigned int irq); - extern void ecard_enableirq(unsigned int irq); int irq; - outb(0, IOMD_IRQMASKA); - outb(0, IOMD_IRQMASKB); - outb(0, IOMD_FIQMASK); - outb(0, IOMD_DMAMASK); + iomd_writeb(0, IOMD_IRQMASKA); + iomd_writeb(0, IOMD_IRQMASKB); + iomd_writeb(0, IOMD_FIQMASK); + iomd_writeb(0, IOMD_DMAMASK); for (irq = 0; irq < NR_IRQS; irq++) { switch (irq) { @@ -156,19 +127,14 @@ irq_desc[irq].unmask = rpc_unmask_irq_b; break; - case 16 ... 21: - irq_desc[irq].valid = 1; + case 16 ... 19: + case 21: irq_desc[irq].noautoenable = 1; + case 20: + irq_desc[irq].valid = 1; irq_desc[irq].mask_ack = rpc_mask_irq_dma; irq_desc[irq].mask = rpc_mask_irq_dma; irq_desc[irq].unmask = rpc_unmask_irq_dma; - break; - - case 32 ... 39: - irq_desc[irq].valid = 1; - irq_desc[irq].mask_ack = ecard_disableirq; - irq_desc[irq].mask = ecard_disableirq; - irq_desc[irq].unmask = ecard_enableirq; break; case 64 ... 71: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-rpc/system.h linux.ac/include/asm-arm/arch-rpc/system.h --- linux.vanilla/include/asm-arm/arch-rpc/system.h Mon Sep 18 23:15:23 2000 +++ linux.ac/include/asm-arm/arch-rpc/system.h Sat Apr 14 01:37:50 2001 @@ -35,11 +35,7 @@ extern __inline__ void arch_reset(char mode) { - extern void ecard_reset(int card); - - ecard_reset(-1); - - outb(0, IOMD_ROMCR0); + iomd_writeb(0, IOMD_ROMCR0); /* * Jump into the ROM diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-sa1100/SA-1100.h linux.ac/include/asm-arm/arch-sa1100/SA-1100.h --- linux.vanilla/include/asm-arm/arch-sa1100/SA-1100.h Mon Sep 18 23:15:23 2000 +++ linux.ac/include/asm-arm/arch-sa1100/SA-1100.h Sat Apr 14 01:37:50 2001 @@ -271,6 +271,7 @@ #define UDCCR_UDD 0x00000001 /* UDC Disable */ #define UDCCR_UDA 0x00000002 /* UDC Active (read) */ +#define UDCCR_RESIM 0x00000004 /* Resume Interrupt Mask, per errata */ #define UDCCR_EIM 0x00000008 /* End-point 0 Interrupt Mask */ /* (disable) */ #define UDCCR_RIM 0x00000010 /* Receive Interrupt Mask */ @@ -279,6 +280,7 @@ /* (disable) */ #define UDCCR_SRM 0x00000040 /* Suspend/Resume interrupt Mask */ /* (disable) */ +#define UDCCR_SUSIM UDCCR_SRM /* Per errata, SRM just masks suspend */ #define UDCCR_REM 0x00000080 /* REset interrupt Mask (disable) */ #define UDCAR_ADD Fld (7, 0) /* function ADDress */ @@ -502,6 +504,32 @@ #define Ser3UTSR1 /* Ser. port 3 UART Status Reg. 1 */ \ (*((volatile Word *) io_p2v (_Ser3UTSR1))) +#elif LANGUAGE == Assembly +#define Ser1UTCR0 ( io_p2v (_Ser1UTCR0)) +#define Ser1UTCR1 ( io_p2v (_Ser1UTCR1)) +#define Ser1UTCR2 ( io_p2v (_Ser1UTCR2)) +#define Ser1UTCR3 ( io_p2v (_Ser1UTCR3)) +#define Ser1UTDR ( io_p2v (_Ser1UTDR)) +#define Ser1UTSR0 ( io_p2v (_Ser1UTSR0)) +#define Ser1UTSR1 ( io_p2v (_Ser1UTSR1)) + +#define Ser2UTCR0 ( io_p2v (_Ser2UTCR0)) +#define Ser2UTCR1 ( io_p2v (_Ser2UTCR1)) +#define Ser2UTCR2 ( io_p2v (_Ser2UTCR2)) +#define Ser2UTCR3 ( io_p2v (_Ser2UTCR3)) +#define Ser2UTCR4 ( io_p2v (_Ser2UTCR4)) +#define Ser2UTDR ( io_p2v (_Ser2UTDR)) +#define Ser2UTSR0 ( io_p2v (_Ser2UTSR0)) +#define Ser2UTSR1 ( io_p2v (_Ser2UTSR1)) + +#define Ser3UTCR0 ( io_p2v (_Ser3UTCR0)) +#define Ser3UTCR1 ( io_p2v (_Ser3UTCR1)) +#define Ser3UTCR2 ( io_p2v (_Ser3UTCR2)) +#define Ser3UTCR3 ( io_p2v (_Ser3UTCR3)) +#define Ser3UTDR ( io_p2v (_Ser3UTDR)) +#define Ser3UTSR0 ( io_p2v (_Ser3UTSR0)) +#define Ser3UTSR1 ( io_p2v (_Ser3UTSR1)) + #endif /* LANGUAGE == C */ #define UTCR0_PE 0x00000001 /* Parity Enable */ @@ -1229,6 +1257,17 @@ (*((volatile Word *) io_p2v (_PGSR))) #define POSR /* PM Oscillator Status Reg. */ \ (*((volatile Word *) io_p2v (_POSR))) + +#elif LANGUAGE == Assembly +#define PMCR (io_p2v (_PMCR)) +#define PSSR (io_p2v (_PSSR)) +#define PSPR (io_p2v (_PSPR)) +#define PWER (io_p2v (_PWER)) +#define PCFR (io_p2v (_PCFR)) +#define PPCR (io_p2v (_PPCR)) +#define PGSR (io_p2v (_PGSR)) +#define POSR (io_p2v (_POSR)) + #endif /* LANGUAGE == C */ #define PMCR_SF 0x00000001 /* Sleep Force (set only) */ @@ -1481,6 +1520,17 @@ (*((volatile Word *) io_p2v (_GEDR))) #define GAFR /* GPIO Alternate Function Reg. */ \ (*((volatile Word *) io_p2v (_GAFR))) +#elif LANGUAGE == Assembly + +#define GPLR (io_p2v (_GPLR)) +#define GPDR (io_p2v (_GPDR)) +#define GPSR (io_p2v (_GPSR)) +#define GPCR (io_p2v (_GPCR)) +#define GRER (io_p2v (_GRER)) +#define GFER (io_p2v (_GFER)) +#define GEDR (io_p2v (_GEDR)) +#define GAFR (io_p2v (_GAFR)) + #endif /* LANGUAGE == C */ #define GPIO_MIN (0) @@ -1784,6 +1834,11 @@ #define MDCAS0 (MDCAS [0]) /* DRAM CAS shift reg. 0 */ #define MDCAS1 (MDCAS [1]) /* DRAM CAS shift reg. 1 */ #define MDCAS2 (MDCAS [2]) /* DRAM CAS shift reg. 2 */ + +#elif LANGUAGE == Assembly + +#define MDCNFG (io_p2v(_MDCNFG)) + #endif /* LANGUAGE == C */ /* SA1100 MDCNFG values */ @@ -1870,6 +1925,13 @@ ((volatile Word *) io_p2v (_MSC (0))) #define MSC0 (MSC [0]) /* Static memory Control reg. 0 */ #define MSC1 (MSC [1]) /* Static memory Control reg. 1 */ + +#elif LANGUAGE == Assembly + +#define MSC0 io_p2v(0xa0000010) +#define MSC1 io_p2v(0xa0000014) +#define MSC2 io_p2v(0xa000002c) + #endif /* LANGUAGE == C */ #define MSC_Bnk(Nb) /* static memory Bank [0..3] */ \ @@ -1895,32 +1957,32 @@ /* First access - 1(.5) [Tmem] */ #define MSC_1stRdAcc(Tcpu) /* 1st Read Access time (burst */ \ /* static memory) [3..65 Tcpu] */ \ - (((Tcpu) - 3)/2 << FShft (MSC_RDF)) + ((((Tcpu) - 3)/2) << FShft (MSC_RDF)) #define MSC_Ceil1stRdAcc(Tcpu) /* Ceil. of 1stRdAcc [3..65 Tcpu] */ \ - (((Tcpu) - 2)/2 << FShft (MSC_RDF)) + ((((Tcpu) - 2)/2) << FShft (MSC_RDF)) #define MSC_RdAcc(Tcpu) /* Read Access time (non-burst */ \ /* static memory) [2..64 Tcpu] */ \ - (((Tcpu) - 2)/2 << FShft (MSC_RDF)) + ((((Tcpu) - 2)/2) << FShft (MSC_RDF)) #define MSC_CeilRdAcc(Tcpu) /* Ceil. of RdAcc [2..64 Tcpu] */ \ - (((Tcpu) - 1)/2 << FShft (MSC_RDF)) + ((((Tcpu) - 1)/2) << FShft (MSC_RDF)) #define MSC_RDN Fld (5, 8) /* ROM/static memory read Delay */ /* Next access - 1 [Tmem] */ #define MSC_NxtRdAcc(Tcpu) /* Next Read Access time (burst */ \ /* static memory) [2..64 Tcpu] */ \ - (((Tcpu) - 2)/2 << FShft (MSC_RDN)) + ((((Tcpu) - 2)/2) << FShft (MSC_RDN)) #define MSC_CeilNxtRdAcc(Tcpu) /* Ceil. of NxtRdAcc [2..64 Tcpu] */ \ - (((Tcpu) - 1)/2 << FShft (MSC_RDN)) + ((((Tcpu) - 1)/2) << FShft (MSC_RDN)) #define MSC_WrAcc(Tcpu) /* Write Access time (non-burst */ \ /* static memory) [2..64 Tcpu] */ \ - (((Tcpu) - 2)/2 << FShft (MSC_RDN)) + ((((Tcpu) - 2)/2) << FShft (MSC_RDN)) #define MSC_CeilWrAcc(Tcpu) /* Ceil. of WrAcc [2..64 Tcpu] */ \ - (((Tcpu) - 1)/2 << FShft (MSC_RDN)) + ((((Tcpu) - 1)/2) << FShft (MSC_RDN)) #define MSC_RRR Fld (3, 13) /* ROM/static memory RecoveRy */ /* time/2 [Tmem] */ #define MSC_Rec(Tcpu) /* Recovery time [0..28 Tcpu] */ \ - ((Tcpu)/4 << FShft (MSC_RRR)) + (((Tcpu)/4) << FShft (MSC_RRR)) #define MSC_CeilRec(Tcpu) /* Ceil. of Rec [0..28 Tcpu] */ \ - (((Tcpu) + 3)/4 << FShft (MSC_RRR)) + ((((Tcpu) + 3)/4) << FShft (MSC_RRR)) /* @@ -1955,20 +2017,20 @@ #define MECR_BSIO Fld (5, 0) /* BCLK Select I/O - 1 [Tmem] */ #define MECR_IOClk(Tcpu) /* I/O Clock [2..64 Tcpu] */ \ - (((Tcpu) - 2)/2 << FShft (MECR_BSIO)) + ((((Tcpu) - 2)/2) << FShft (MECR_BSIO)) #define MECR_CeilIOClk(Tcpu) /* Ceil. of IOClk [2..64 Tcpu] */ \ - (((Tcpu) - 1)/2 << FShft (MECR_BSIO)) + ((((Tcpu) - 1)/2) << FShft (MECR_BSIO)) #define MECR_BSA Fld (5, 5) /* BCLK Select Attribute - 1 */ /* [Tmem] */ #define MECR_AttrClk(Tcpu) /* Attribute Clock [2..64 Tcpu] */ \ - (((Tcpu) - 2)/2 << FShft (MECR_BSA)) + ((((Tcpu) - 2)/2) << FShft (MECR_BSA)) #define MECR_CeilAttrClk(Tcpu) /* Ceil. of AttrClk [2..64 Tcpu] */ \ - (((Tcpu) - 1)/2 << FShft (MECR_BSA)) + ((((Tcpu) - 1)/2) << FShft (MECR_BSA)) #define MECR_BSM Fld (5, 10) /* BCLK Select Memory - 1 [Tmem] */ #define MECR_MemClk(Tcpu) /* Memory Clock [2..64 Tcpu] */ \ - (((Tcpu) - 2)/2 << FShft (MECR_BSM)) + ((((Tcpu) - 2)/2) << FShft (MECR_BSM)) #define MECR_CeilMemClk(Tcpu) /* Ceil. of MemClk [2..64 Tcpu] */ \ - (((Tcpu) - 1)/2 << FShft (MECR_BSM)) + ((((Tcpu) - 1)/2) << FShft (MECR_BSM)) /* * On SA1110 only @@ -1981,6 +2043,10 @@ #define MDREFR \ (*((volatile Word *) io_p2v (_MDREFR))) +#elif LANGUAGE == Assembly + +#define MDREFR (io_p2v(_MDREFR)) + #endif /* LANGUAGE == C */ #define MDREFR_TRASR Fld (4, 0) @@ -2456,18 +2522,18 @@ (DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \ DDAR_Ser3UARTRc + DDAR_DevAdd (_Ser3UTDR)) #define DDAR_Ser4MCP0Wr /* Ser. port 4 MCP 0 Write (audio) */ \ - (DDAR_DevWr + DDAR_Brst8 + DDAR_16BitDev + \ + (DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \ DDAR_Ser4MCP0Tr + DDAR_DevAdd (_Ser4MCDR0)) #define DDAR_Ser4MCP0Rd /* Ser. port 4 MCP 0 Read (audio) */ \ - (DDAR_DevRd + DDAR_Brst8 + DDAR_16BitDev + \ + (DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \ DDAR_Ser4MCP0Rc + DDAR_DevAdd (_Ser4MCDR0)) #define DDAR_Ser4MCP1Wr /* Ser. port 4 MCP 1 Write */ \ /* (telecom) */ \ - (DDAR_DevWr + DDAR_Brst8 + DDAR_16BitDev + \ + (DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \ DDAR_Ser4MCP1Tr + DDAR_DevAdd (_Ser4MCDR1)) #define DDAR_Ser4MCP1Rd /* Ser. port 4 MCP 1 Read */ \ /* (telecom) */ \ - (DDAR_DevRd + DDAR_Brst8 + DDAR_16BitDev + \ + (DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \ DDAR_Ser4MCP1Rc + DDAR_DevAdd (_Ser4MCDR1)) #define DDAR_Ser4SSPWr /* Ser. port 4 SSP Write (16 bits) */ \ (DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-sa1100/assabet.h linux.ac/include/asm-arm/arch-sa1100/assabet.h --- linux.vanilla/include/asm-arm/arch-sa1100/assabet.h Mon Sep 18 23:15:23 2000 +++ linux.ac/include/asm-arm/arch-sa1100/assabet.h Sat Apr 14 01:38:05 2001 @@ -32,7 +32,7 @@ #define BCR (*(volatile unsigned int *)(BCR_BASE)) #define BCR_DB1110 (0x00A07410) -#define BCR_DB1111 (0x00A07462) +#define BCR_DB1111 (0x00A074E2) #define BCR_CF_PWR (1<<0) /* Compact Flash Power (1 = 3.3v, 0 = off) */ #define BCR_CF_RST (1<<1) /* Compact Flash Reset (1 = power up reset) */ @@ -89,6 +89,7 @@ #define IRQ_GPIO_CF_IRQ IRQ_GPIO21 #define IRQ_GPIO_CF_CD IRQ_GPIO22 +#define IRQ_GPIO_MBREQ IRQ_GPIO22 #define IRQ_GPIO_UCB1300_IRQ IRQ_GPIO23 #define IRQ_GPIO_CF_BVD2 IRQ_GPIO24 #define IRQ_GPIO_CF_BVD1 IRQ_GPIO25 @@ -139,6 +140,9 @@ #define IRR_ETHERNET (1<<0) #define IRR_USAR (1<<1) #define IRR_SA1111 (1<<2) + +#define AUD_SEL_1341 (1<<0) +#define AUD_MUTE_1341 (1<<1) #define NCR_GP01_OFF (1<<0) #define NCR_TP_PWR_EN (1<<1) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-sa1100/bitsy.h linux.ac/include/asm-arm/arch-sa1100/bitsy.h --- linux.vanilla/include/asm-arm/arch-sa1100/bitsy.h Mon Sep 18 23:15:23 2000 +++ linux.ac/include/asm-arm/arch-sa1100/bitsy.h Sat Apr 14 01:38:05 2001 @@ -1,6 +1,9 @@ #ifndef _INCLUDE_BITSY_H_ #define _INCLUDE_BITSY_H_ +#define GPIO_BITSY_NPOWER_BUTTON GPIO_GPIO (0) +#define GPIO_BITSY_ACTION_BUTTON GPIO_GPIO (18) + #define GPIO_BITSY_PCMCIA_CD0 GPIO_GPIO (17) #define GPIO_BITSY_PCMCIA_CD1 GPIO_GPIO (10) #define GPIO_BITSY_PCMCIA_IRQ0 GPIO_GPIO (21) @@ -15,6 +18,9 @@ #define GPIO_BITSY_L3_MODE GPIO_GPIO (15) + +#define IRQ_GPIO_BITSY_NPOWER_BUTTON IRQ_GPIO0 +#define IRQ_GPIO_BITSY_ACTION_BUTTON IRQ_GPIO18 #define IRQ_GPIO_BITSY_PCMCIA_CD0 IRQ_GPIO17 #define IRQ_GPIO_BITSY_PCMCIA_CD1 IRQ_GPIO10 #define IRQ_GPIO_BITSY_PCMCIA_IRQ0 IRQ_GPIO21 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-sa1100/dma.h linux.ac/include/asm-arm/arch-sa1100/dma.h --- linux.vanilla/include/asm-arm/arch-sa1100/dma.h Wed Jul 19 06:43:25 2000 +++ linux.ac/include/asm-arm/arch-sa1100/dma.h Sat Apr 14 01:38:05 2001 @@ -1,12 +1,107 @@ /* * linux/include/asm-arm/arch-sa1100/dma.h + * + * Generic SA1100 DMA support + * + * Copyright (C) 2000 Nicolas Pitre + * */ + #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H +#include <linux/config.h> +#include "hardware.h" + + +/* + * This is the maximum DMA address that can be DMAd to. + */ #define MAX_DMA_ADDRESS 0xffffffff -/* No DMA (strictly, a lie :-) ) */ + +/* + * The regular generic DMA interface is inappropriate for the + * SA1100 DMA model. None of the SA1100 specific drivers using + * DMA are portable anyway so it's pointless to try to twist the + * regular DMA API to accommodate them. + */ #define MAX_DMA_CHANNELS 0 + + +/* + * The SA1100 has six internal DMA channels. + */ +#define SA1100_DMA_CHANNELS 6 + + +/* + * The SA-1111 SAC has two DMA channels. + */ +#define SA1111_SAC_DMA_CHANNELS 2 +#define SA1111_SAC_XMT_CHANNEL 0 +#define SA1111_SAC_RCV_CHANNEL 1 + + +/* + * The SA-1111 SAC channels will reside in the same index space as + * the built-in SA-1100 channels, and will take on the next available + * identifiers after the 1100. + */ +#define SA1111_SAC_DMA_BASE SA1100_DMA_CHANNELS + +#ifdef CONFIG_SA1111 +# define MAX_SA1100_DMA_CHANNELS (SA1100_DMA_CHANNELS + SA1111_SAC_DMA_CHANNELS) +#else +# define MAX_SA1100_DMA_CHANNELS SA1100_DMA_CHANNELS +#endif + + +/* + * All possible SA1100 devices a DMA channel can be attached to. + */ +typedef enum { + DMA_Ser0UDCWr = DDAR_Ser0UDCWr, /* Ser. port 0 UDC Write */ + DMA_Ser0UDCRd = DDAR_Ser0UDCRd, /* Ser. port 0 UDC Read */ + DMA_Ser1UARTWr = DDAR_Ser1UARTWr, /* Ser. port 1 UART Write */ + DMA_Ser1UARTRd = DDAR_Ser1UARTRd, /* Ser. port 1 UART Read */ + DMA_Ser1SDLCWr = DDAR_Ser1SDLCWr, /* Ser. port 1 SDLC Write */ + DMA_Ser1SDLCRd = DDAR_Ser1SDLCRd, /* Ser. port 1 SDLC Read */ + DMA_Ser2UARTWr = DDAR_Ser2UARTWr, /* Ser. port 2 UART Write */ + DMA_Ser2UARTRd = DDAR_Ser2UARTRd, /* Ser. port 2 UART Read */ + DMA_Ser2HSSPWr = DDAR_Ser2HSSPWr, /* Ser. port 2 HSSP Write */ + DMA_Ser2HSSPRd = DDAR_Ser2HSSPRd, /* Ser. port 2 HSSP Read */ + DMA_Ser3UARTWr = DDAR_Ser3UARTWr, /* Ser. port 3 UART Write */ + DMA_Ser3UARTRd = DDAR_Ser3UARTRd, /* Ser. port 3 UART Read */ + DMA_Ser4MCP0Wr = DDAR_Ser4MCP0Wr, /* Ser. port 4 MCP 0 Write (audio) */ + DMA_Ser4MCP0Rd = DDAR_Ser4MCP0Rd, /* Ser. port 4 MCP 0 Read (audio) */ + DMA_Ser4MCP1Wr = DDAR_Ser4MCP1Wr, /* Ser. port 4 MCP 1 Write */ + DMA_Ser4MCP1Rd = DDAR_Ser4MCP1Rd, /* Ser. port 4 MCP 1 Read */ + DMA_Ser4SSPWr = DDAR_Ser4SSPWr, /* Ser. port 4 SSP Write (16 bits) */ + DMA_Ser4SSPRd = DDAR_Ser4SSPRd /* Ser. port 4 SSP Read (16 bits) */ +} dma_device_t; + + +typedef void (*dma_callback_t)( void *buf_id, int size ); + + +/* SA1100 DMA API */ +extern int sa1100_request_dma( dmach_t *channel, const char *device_id ); +extern int sa1100_dma_set_callback( dmach_t channel, dma_callback_t cb ); +extern int sa1100_dma_set_device( dmach_t channel, dma_device_t device ); +extern int sa1100_dma_set_spin( dmach_t channel, dma_addr_t addr, int size ); +extern int sa1100_dma_queue_buffer( dmach_t channel, void *buf_id, + dma_addr_t data, int size ); +extern int sa1100_dma_get_current( dmach_t channel, void **buf_id, dma_addr_t *addr ); +extern int sa1100_dma_stop( dmach_t channel ); +extern int sa1100_dma_resume( dmach_t channel ); +extern int sa1100_dma_flush_all( dmach_t channel ); +extern void sa1100_free_dma( dmach_t channel ); + +/* Sa1111 DMA interface (all but registration uses the above) */ +extern int sa1111_sac_request_dma( dmach_t *channel, const char *device_id, + unsigned int direction ); +extern int sa1111_check_dma_bug( dma_addr_t addr ); + #endif /* _ASM_ARCH_DMA_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-sa1100/keyboard.h linux.ac/include/asm-arm/arch-sa1100/keyboard.h --- linux.vanilla/include/asm-arm/arch-sa1100/keyboard.h Wed Jul 19 06:43:25 2000 +++ linux.ac/include/asm-arm/arch-sa1100/keyboard.h Sat Apr 14 01:38:05 2001 @@ -10,7 +10,9 @@ #include <linux/config.h> -#ifdef CONFIG_SA1100_BRUTUS +// #ifdef CONFIG_SA1100_BRUTUS +/* need fixing... */ +#if 0 extern int Brutus_kbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode); @@ -32,6 +34,113 @@ #define SYSRQ_KEY 0x54 +#elif CONFIG_SA1100_GRAPHICSCLIENT +extern int gc_kbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode); +extern void gc_kbd_leds(unsigned char leds); +extern void gc_kbd_init_hw(void); +extern void gc_kbd_enable_irq(void); +extern void gc_kbd_disable_irq(void); +extern unsigned char gc_kbd_sysrq_xlate[128]; + +#define kbd_setkeycode(x...) (-ENOSYS) +#define kbd_getkeycode(x...) (-ENOSYS) +#define kbd_translate gc_kbd_translate +#define kbd_unexpected_up(x...) (1) +#define kbd_leds gc_kbd_leds +#define kbd_init_hw gc_kbd_init_hw +#define kbd_enable_irq gc_kbd_enable_irq +#define kbd_disable_irq gc_kbd_disable_irq +#define kbd_sysrq_xlate gc_kbd_sysrq_xlate + +#elif defined(CONFIG_SA1111) /*@@@@@*/ + +#define KEYBOARD_IRQ TPRXINT +#define DISABLE_KBD_DURING_INTERRUPTS 0 + +/* redefine some macros */ +#ifdef KBD_DATA_REG +#undef KBD_DATA_REG +#endif +#ifdef KBD_STATUS_REG +#undef KBD_STATUS_REG +#endif +#ifdef KBD_CNTL_REG +#undef KBD_CNTL_REG +#endif +#define KBD_DATA_REG KBDDATA +#define KBD_STATUS_REG KBDSTAT +#define KBD_CNTL_REG KBDCR + +extern int sa1111_setkeycode(unsigned int scancode, unsigned int keycode); +extern int sa1111_getkeycode(unsigned int scancode); +extern int sa1111_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); +extern char sa1111_unexpected_up(unsigned char keycode); +extern void sa1111_leds(unsigned char leds); +extern void sa1111_init_hw(void); +extern unsigned char sa1111_sysrq_xlate[128]; + +#define kbd_setkeycode sa1111_setkeycode +#define kbd_getkeycode sa1111_getkeycode +#define kbd_translate sa1111_translate +#define kbd_unexpected_up sa1111_unexpected_up +#define kbd_leds sa1111_leds +#define kbd_init_hw sa1111_init_hw +#define kbd_sysrq_xlate sa1111_sysrq_xlate +#define kbd_disable_irq(x...) do{;}while(0) +#define kbd_enable_irq(x...) do{;}while(0) + +#define SYSRQ_KEY 0x54 + +/* resource allocation */ +#define kbd_request_region() +#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \ + "keyboard", NULL) + +/* How to access the keyboard macros on this platform. */ +#define kbd_read_input() (*KBDDATA & 0x00ff) +#define kbd_read_status() (*KBDSTAT & 0x01ff) +#define kbd_write_output(val) (*KBDDATA = (val)) +#define kbd_write_command(val) (*KBDCR = (val)) + +/* Some stoneage hardware needs delays after some operations. */ +#define kbd_pause() do {;} while(0) + +/* bit definitions for some registers */ +#define KBD_CR_ENA (1<<3) + +#define KBD_STAT_RXB (1<<4) +#define KBD_STAT_RXF (1<<5) +#define KBD_STAT_TXB (1<<6) +#define KBD_STAT_TXE (1<<7) +#define KBD_STAT_STP (1<<8) + +/* + * Machine specific bits for the PS/2 driver + */ + +#define AUX_IRQ MSRXINT + +#define aux_request_irq(hand, dev_id) \ + request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id) +#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id) + +/* How to access the mouse macros on this platform. */ +#define mse_read_input() (*MSEDATA & 0x00ff) +#define mse_read_status() (*MSESTAT & 0x01ff) +#define mse_write_output(val) (*MSEDATA = (val)) +#define mse_write_command(val) (*MSECR = (val)) + +/* bit definitions for some registers */ +#define MSE_CR_ENA (1<<3) + +#define MSE_STAT_RXB (1<<4) +#define MSE_STAT_RXF (1<<5) +#define MSE_STAT_TXB (1<<6) +#define MSE_STAT_TXE (1<<7) +#define MSE_STAT_STP (1<<8) + + #else /* dummy i.e. no real keyboard */ @@ -39,11 +148,18 @@ #define kbd_getkeycode(x...) (-ENOSYS) #define kbd_translate(x...) (0) #define kbd_unexpected_up(x...) (1) -#define kbd_leds(x...) do { } while (0) -#define kbd_init_hw(x...) do { } while (0) -#define kbd_enable_irq(x...) do { } while (0) -#define kbd_disable_irq(x...) do { } while (0) +#define kbd_leds(x...) do {;} while (0) +#define kbd_init_hw(x...) do {;} while (0) +#define kbd_enable_irq(x...) do {;} while (0) +#define kbd_disable_irq(x...) do {;} while (0) + +#endif + +/* needed if MAGIC_SYSRQ is enabled for serial console */ +#ifndef SYSRQ_KEY +#define SYSRQ_KEY -1 +#define kbd_sysrq_xlate ((unsigned char *)NULL) #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-sa1100/mmzone.h linux.ac/include/asm-arm/arch-sa1100/mmzone.h --- linux.vanilla/include/asm-arm/arch-sa1100/mmzone.h Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-arm/arch-sa1100/mmzone.h Sat Apr 14 01:38:05 2001 @@ -21,21 +21,7 @@ * node 3: 0xd8000000 - 0xdfffffff */ - -/* - * Currently defined in arch/arm/mm/mm-sa1100.c - */ -extern pg_data_t sa1100_node_data[]; - -/* - * Return a pointer to the node data for node n. - */ -#define NODE_DATA(nid) (&sa1100_node_data[nid]) - -/* - * NODE_MEM_MAP gives the kaddr for the mem_map of the node. - */ -#define NODE_MEM_MAP(nid) (NODE_DATA(nid)->node_mem_map) +#define NR_NODES 4 /* * Given a kernel address, find the home node of the underlying memory. @@ -71,7 +57,7 @@ */ #define VALID_PAGE(page) \ ({ unsigned int node = KVADDR_TO_NID(page); \ - ( (node < 4) && \ + ( (node < NR_NODES) && \ ((unsigned)((page) - NODE_MEM_MAP(node)) < NODE_DATA(node)->node_size) ); \ }) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-sa1100/pcmcia.h linux.ac/include/asm-arm/arch-sa1100/pcmcia.h --- linux.vanilla/include/asm-arm/arch-sa1100/pcmcia.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-arm/arch-sa1100/pcmcia.h Sat Apr 14 01:38:05 2001 @@ -0,0 +1,70 @@ +/* + * linux/include/asm/arch/pcmcia.h + * + * Copyright (C) 2000 John G Dorsey <john+@cs.cmu.edu> + * + * This file contains definitions for the low-level SA-1100 kernel PCMCIA + * interface. Please see linux/Documentation/arm/SA1100/PCMCIA for details. + */ + +#ifndef _ASM_ARCH_PCMCIA +#define _ASM_ARCH_PCMCIA + + +/* Ideally, we'd support up to MAX_SOCK sockets, but the SA-1100 only + * has support for two. This shows up in lots of hardwired ways, such + * as the fact that MECR only has enough bits to configure two sockets. + * Since it's so entrenched in the hardware, limiting the software + * in this way doesn't seem too terrible. + */ +#define SA1100_PCMCIA_MAX_SOCK (2) + + +#ifndef __ASSEMBLY__ + +struct pcmcia_init { + void (*handler)(int irq, void *dev, struct pt_regs *regs); +}; + +struct pcmcia_state { + unsigned detect: 1, + ready: 1, + bvd1: 1, + bvd2: 1, + wrprot: 1, + vs_3v: 1, + vs_Xv: 1; +}; + +struct pcmcia_state_array { + unsigned int size; + struct pcmcia_state *state; +}; + +struct pcmcia_configure { + unsigned sock: 8, + vcc: 8, + vpp: 8, + output: 1, + speaker: 1, + reset: 1; +}; + +struct pcmcia_irq_info { + unsigned int sock; + unsigned int irq; +}; + +struct pcmcia_low_level { + int (*init)(struct pcmcia_init *); + int (*shutdown)(void); + int (*socket_state)(struct pcmcia_state_array *); + int (*get_irq_info)(struct pcmcia_irq_info *); + int (*configure_socket)(const struct pcmcia_configure *); +}; + +extern struct pcmcia_low_level *pcmcia_low_level; + +#endif /* __ASSEMBLY__ */ + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-sa1100/serial.h linux.ac/include/asm-arm/arch-sa1100/serial.h --- linux.vanilla/include/asm-arm/arch-sa1100/serial.h Thu Jan 13 21:30:31 2000 +++ linux.ac/include/asm-arm/arch-sa1100/serial.h Sat Apr 14 01:38:05 2001 @@ -22,11 +22,18 @@ #define RS_TABLE_SIZE 4 -#define STD_SERIAL_PORT_DEFNS \ - /* UART CLK PORT IRQ FLAGS */ \ - { 0, BASE_BAUD, 0x3F8, IRQ_GPIO3, STD_COM_FLAGS }, /* ttyS0 */ \ - { 0, BASE_BAUD, 0x2F8, IRQ_GPIO3, STD_COM_FLAGS }, /* ttyS1 */ \ - { 0, BASE_BAUD, 0x3E8, IRQ_GPIO3, STD_COM_FLAGS }, /* ttyS2 */ \ - { 0, BASE_BAUD, 0x2E8, IRQ_GPIO3, STD_COM4_FLAGS } /* ttyS3 */ +/* + * Rather empty table... + * Hardwired serial ports should be defined here. + * PCMCIA will fill it dynamically. + */ +#define STD_SERIAL_PORT_DEFNS \ + /* UART CLK PORT IRQ FLAGS */ \ + { 0, BASE_BAUD, 0, 0, STD_COM_FLAGS }, \ + { 0, BASE_BAUD, 0, 0, STD_COM_FLAGS }, \ + { 0, BASE_BAUD, 0, 0, STD_COM_FLAGS }, \ + { 0, BASE_BAUD, 0, 0, STD_COM_FLAGS } + +#define EXTRA_SERIAL_PORT_DEFNS diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-sa1100/system.h linux.ac/include/asm-arm/arch-sa1100/system.h --- linux.vanilla/include/asm-arm/arch-sa1100/system.h Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-arm/arch-sa1100/system.h Sat Apr 14 01:38:05 2001 @@ -7,7 +7,7 @@ static inline void arch_idle(void) { - while (!current->need_resched && !hlt_counter) + if (!hlt_counter) cpu_do_idle(0); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-shark/dma.h linux.ac/include/asm-arm/arch-shark/dma.h --- linux.vanilla/include/asm-arm/arch-shark/dma.h Mon Mar 27 19:46:29 2000 +++ linux.ac/include/asm-arm/arch-shark/dma.h Sat Apr 14 01:38:05 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/arch-shark/dma.h * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> */ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-shark/hardware.h linux.ac/include/asm-arm/arch-shark/hardware.h --- linux.vanilla/include/asm-arm/arch-shark/hardware.h Mon Sep 18 23:15:23 2000 +++ linux.ac/include/asm-arm/arch-shark/hardware.h Sat Apr 14 01:38:05 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/arch-shark/hardware.h * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> * * derived from: * linux/include/asm-arm/arch-ebsa110/hardware.h @@ -40,14 +40,16 @@ /* defines for the Framebuffer */ #define FB_START 0x06000000 -/* Registers for Framebuffer */ -/*#define FBREG_START 0x06800000*/ - #define UNCACHEABLE_ADDR 0xdf010000 #define SEQUOIA_LED_GREEN (1<<6) #define SEQUOIA_LED_AMBER (1<<5) #define SEQUOIA_LED_BACK (1<<7) + +#define pcibios_assign_all_busses() 1 + +#define PCIBIOS_MIN_IO 0x6000 +#define PCIBIOS_MIN_MEM 0x50000000 #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-shark/ide.h linux.ac/include/asm-arm/arch-shark/ide.h --- linux.vanilla/include/asm-arm/arch-shark/ide.h Mon Jun 26 20:04:42 2000 +++ linux.ac/include/asm-arm/arch-shark/ide.h Sat Apr 14 01:38:05 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/arch-shark/ide.h * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> * * derived from: * linux/include/asm-arm/arch-ebsa285/ide.h diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-shark/io.h linux.ac/include/asm-arm/arch-shark/io.h --- linux.vanilla/include/asm-arm/arch-shark/io.h Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-arm/arch-shark/io.h Sat Apr 14 01:38:05 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/arch-shark/io.h * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> * * derived from: * linux/include/asm-arm/arch-ebsa110/io.h diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-shark/irq.h linux.ac/include/asm-arm/arch-shark/irq.h --- linux.vanilla/include/asm-arm/arch-shark/irq.h Mon Mar 27 19:46:29 2000 +++ linux.ac/include/asm-arm/arch-shark/irq.h Sat Apr 14 01:38:05 2001 @@ -1,13 +1,14 @@ /* * linux/include/asm-arm/arch-shark/irq.h * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> * * derived from linux/arch/ppc/kernel/i8259.c and: * include/asm-arm/arch-ebsa110/irq.h * Copyright (C) 1996-1998 Russell King */ +#include <asm/io.h> #define fixup_irq(x) (x) /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-shark/irqs.h linux.ac/include/asm-arm/arch-shark/irqs.h --- linux.vanilla/include/asm-arm/arch-shark/irqs.h Mon Mar 27 19:46:29 2000 +++ linux.ac/include/asm-arm/arch-shark/irqs.h Sat Apr 14 01:38:05 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/arch-shark/irqs.h * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> */ #define NR_IRQS 16 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-shark/keyboard.h linux.ac/include/asm-arm/arch-shark/keyboard.h --- linux.vanilla/include/asm-arm/arch-shark/keyboard.h Mon Sep 18 23:15:23 2000 +++ linux.ac/include/asm-arm/arch-shark/keyboard.h Sat Apr 14 01:38:05 2001 @@ -1,6 +1,6 @@ /* * linux/include/asm-arm/arch-shark/keyboard.h - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> * * Derived from linux/include/asm-arm/arch-ebsa285/keyboard.h * (C) 1998 Russell King diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-shark/memory.h linux.ac/include/asm-arm/arch-shark/memory.h --- linux.vanilla/include/asm-arm/arch-shark/memory.h Tue Nov 28 01:07:59 2000 +++ linux.ac/include/asm-arm/arch-shark/memory.h Sat Apr 14 01:38:05 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/arch-shark/memory.h * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> * * derived from: * linux/include/asm-arm/arch-ebsa110/memory.h diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-shark/param.h linux.ac/include/asm-arm/arch-shark/param.h --- linux.vanilla/include/asm-arm/arch-shark/param.h Mon Mar 27 19:46:29 2000 +++ linux.ac/include/asm-arm/arch-shark/param.h Sat Apr 14 01:38:05 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/arch-shark/param.h * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> */ /* This must be a power of 2 because the RTC diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-shark/system.h linux.ac/include/asm-arm/arch-shark/system.h --- linux.vanilla/include/asm-arm/arch-shark/system.h Mon Sep 18 23:15:23 2000 +++ linux.ac/include/asm-arm/arch-shark/system.h Sat Apr 14 01:38:05 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/arch-shark/system.h * - * Copyright (c) 1996-1998 Russell King. + * by Alexander Schulz <aschulz@netwinder.org> */ #ifndef __ASM_ARCH_SYSTEM_H #define __ASM_ARCH_SYSTEM_H diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-shark/time.h linux.ac/include/asm-arm/arch-shark/time.h --- linux.vanilla/include/asm-arm/arch-shark/time.h Mon Sep 18 23:15:23 2000 +++ linux.ac/include/asm-arm/arch-shark/time.h Sat Apr 14 01:38:05 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/arch-shark/time.h * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> * * Uses the real time clock because you can't run * the timer with level triggered interrupts and diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-shark/timex.h linux.ac/include/asm-arm/arch-shark/timex.h --- linux.vanilla/include/asm-arm/arch-shark/timex.h Mon Mar 27 19:46:29 2000 +++ linux.ac/include/asm-arm/arch-shark/timex.h Sat Apr 14 01:38:05 2001 @@ -1,5 +1,5 @@ /* * linux/include/asm-arm/arch-shark/timex.h * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-shark/uncompress.h linux.ac/include/asm-arm/arch-shark/uncompress.h --- linux.vanilla/include/asm-arm/arch-shark/uncompress.h Mon Mar 27 19:46:29 2000 +++ linux.ac/include/asm-arm/arch-shark/uncompress.h Sat Apr 14 01:38:05 2001 @@ -1,31 +1,57 @@ /* - * linux/include/asm-arm/arch-ebsa110/uncompress.h + * linux/include/asm-arm/arch-shark/uncompress.h + * by Alexander Schulz <aschulz@netwinder.org> * + * derived from: + * linux/include/asm-arm/arch-ebsa285/uncompress.h * Copyright (C) 1996,1997,1998 Russell King */ +#define SERIAL_BASE ((volatile unsigned char *)0x400003f8) + +static __inline__ void putc(char c) +{ + int t; + + SERIAL_BASE[0] = c; + t=0x10000; + while (t--); +} + /* * This does not append a newline */ static void puts(const char *s) { - __asm__ __volatile__(" - ldrb %0, [%2], #1 - teq %0, #0 - beq 3f -1: strb %0, [%3] -2: ldrb %1, [%3, #0x14] - and %1, %1, #0x60 - teq %1, #0x60 - bne 2b - teq %0, #'\n' - moveq %0, #'\r' - beq 1b - ldrb %0, [%2], #1 - teq %0, #0 - bne 1b -3: " : : "r" (0), "r" (0), "r" (s), "r" (0xf0000be0) : "cc"); + while (*s) { + putc(*s); + if (*s == '\n') + putc('\r'); + s++; + } +} + +#ifdef DEBUG +static void putn(unsigned long z) +{ + int i; + char x; + + putc('0'); + putc('x'); + for (i=0;i<8;i++) { + x='0'+((z>>((7-i)*4))&0xf); + if (x>'9') x=x-'0'+'A'-10; + putc(x); + } +} + +static void putr() +{ + putc('\n'); + putc('\r'); } +#endif /* * nothing to do diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/arch-tbox/time.h linux.ac/include/asm-arm/arch-tbox/time.h --- linux.vanilla/include/asm-arm/arch-tbox/time.h Mon Sep 18 23:15:23 2000 +++ linux.ac/include/asm-arm/arch-tbox/time.h Sat Apr 14 01:38:05 2001 @@ -8,6 +8,13 @@ * our soft copy. */ +/* + * 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 <asm/io.h> #include <asm/hardware.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/byteorder.h linux.ac/include/asm-arm/byteorder.h --- linux.vanilla/include/asm-arm/byteorder.h Fri Oct 27 18:55:01 2000 +++ linux.ac/include/asm-arm/byteorder.h Sat Apr 14 01:38:05 2001 @@ -1,6 +1,21 @@ +/* + * linux/include/asm-arm/byteorder.h + * + * ARM Endian-ness. In little endian mode, the data bus is connected such + * that byte accesses appear as: + * 0 = d0...d7, 1 = d8...d15, 2 = d16...d23, 3 = d24...d31 + * and word accesses (data or instruction) appear as: + * d0...d31 + * + * When in big endian mode, byte accesses appear as: + * 0 = d24...d31, 1 = d16...d23, 2 = d8...d15, 3 = d0...d7 + * and word accesses (data or instruction) appear as: + * d0...d31 + */ #ifndef __ASM_ARM_BYTEORDER_H #define __ASM_ARM_BYTEORDER_H + #include <asm/types.h> #if !defined(__STRICT_ANSI__) || defined(__KERNEL__) @@ -8,7 +23,11 @@ # define __SWAB_64_THRU_32__ #endif +#ifdef __ARMEB__ +#include <linux/byteorder/big_endian.h> +#else #include <linux/byteorder/little_endian.h> +#endif #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/elf.h linux.ac/include/asm-arm/elf.h --- linux.vanilla/include/asm-arm/elf.h Thu Oct 21 00:29:08 1999 +++ linux.ac/include/asm-arm/elf.h Sat Apr 14 01:38:05 2001 @@ -30,7 +30,7 @@ */ #define ELF_CLASS ELFCLASS32 #ifdef __ARMEB__ -#define ELF_DATA ELFDATA2LSB; +#define ELF_DATA ELFDATA2MSB; #else #define ELF_DATA ELFDATA2LSB; #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/hardware/clps7111.h linux.ac/include/asm-arm/hardware/clps7111.h --- linux.vanilla/include/asm-arm/hardware/clps7111.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-arm/hardware/clps7111.h Sat Apr 14 01:38:20 2001 @@ -0,0 +1,181 @@ +/* + * linux/include/asm-arm/hardware/clps7111.h + * + * This file contains the hardware definitions of the CLPS7111 internal + * registers. + * + * Copyright (C) 2000 Deep Blue Solutions 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_HARDWARE_CLPS7111_H +#define __ASM_HARDWARE_CLPS7111_H + +#define CLPS7111_PHYS_BASE (0x80000000) + +#ifndef __ASSEMBLY__ +#define clps_readb(off) __raw_readb(CLPS7111_BASE + (off)) +#define clps_readl(off) __raw_readl(CLPS7111_BASE + (off)) +#define clps_writeb(val,off) __raw_writeb(val, CLPS7111_BASE + (off)) +#define clps_writel(val,off) __raw_writel(val, CLPS7111_BASE + (off)) +#endif + +#define PADR (0x0000) +#define PBDR (0x0001) +#define PDDR (0x0003) +#define PADDR (0x0040) +#define PBDDR (0x0041) +#define PDDDR (0x0043) +#define PEDR (0x0080) +#define PEDDR (0x00c0) +#define SYSCON1 (0x0100) +#define SYSFLG1 (0x0140) +#define MEMCFG1 (0x0180) +#define MEMCFG2 (0x01c0) +#define DRFPR (0x0200) +#define INTSR1 (0x0240) +#define INTMR1 (0x0280) +#define LCDCON (0x02c0) +#define TC2D (0x0340) +#define RTCDR (0x0380) +#define RTCMR (0x03c0) +#define PMPCON (0x0400) +#define CODR (0x0440) +#define UARTDR1 (0x0480) +#define UBRLCR1 (0x04c0) +#define SYNCIO (0x0500) +#define PALLSW (0x0540) +#define PALMSW (0x0580) +#define STFCLR (0x05c0) +#define BLEOI (0x0600) +#define MCEOI (0x0640) +#define TEOI (0x0680) +#define TC1EOI (0x06c0) +#define TC2EOI (0x0700) +#define RTCEOI (0x0740) +#define UMSEOI (0x0780) +#define COEOI (0x07c0) +#define HALT (0x0800) +#define STDBY (0x0840) + +#define FBADDR (0x1000) +#define SYSCON2 (0x1100) +#define SYSFLG2 (0x1140) +#define INTSR2 (0x1240) +#define INTMR2 (0x1280) +#define UARTDR2 (0x1480) +#define UBRLCR2 (0x14c0) +#define SS2DR (0x1500) +#define SRXEOF (0x1600) +#define SS2POP (0x16c0) +#define KBDEOI (0x1700) + +/* common bits: SYSCON1 / SYSCON2 */ +#define SYSCON_UARTEN (1 << 8) + +#define SYSCON1_KBDSCAN(x) ((x) & 15) +#define SYSCON1_KBDSCANMASK (15) +#define SYSCON1_TC1M (1 << 4) +#define SYSCON1_TC1S (1 << 5) +#define SYSCON1_TC2M (1 << 6) +#define SYSCON1_TC2S (1 << 7) +#define SYSCON1_UART1EN SYSCON_UARTEN +#define SYSCON1_BZTOG (1 << 9) +#define SYSCON1_BZMOD (1 << 10) +#define SYSCON1_DBGEN (1 << 11) +#define SYSCON1_LCDEN (1 << 12) +#define SYSCON1_CDENTX (1 << 13) +#define SYSCON1_CDENRX (1 << 14) +#define SYSCON1_SIREN (1 << 15) +#define SYSCON1_ADCKSEL(x) (((x) & 3) << 16) +#define SYSCON1_ADCKSEL_MASK (3 << 16) +#define SYSCON1_EXCKEN (1 << 18) +#define SYSCON1_WAKEDIS (1 << 19) +#define SYSCON1_IRTXM (1 << 20) + +/* common bits: SYSFLG1 / SYSFLG2 */ +#define SYSFLG_UBUSY (1 << 11) +#define SYSFLG_URXFE (1 << 22) +#define SYSFLG_UTXFF (1 << 23) + +#define SYSFLG1_MCDR (1 << 0) +#define SYSFLG1_DCDET (1 << 1) +#define SYSFLG1_WUDR (1 << 2) +#define SYSFLG1_WUON (1 << 3) +#define SYSFLG1_CTS (1 << 8) +#define SYSFLG1_DSR (1 << 9) +#define SYSFLG1_DCD (1 << 10) +#define SYSFLG1_UBUSY SYSFLG_UBUSY +#define SYSFLG1_NBFLG (1 << 12) +#define SYSFLG1_RSTFLG (1 << 13) +#define SYSFLG1_PFFLG (1 << 14) +#define SYSFLG1_CLDFLG (1 << 15) +#define SYSFLG1_URXFE SYSFLG_URXFE +#define SYSFLG1_UTXFF SYSFLG_UTXFF +#define SYSFLG1_CRXFE (1 << 24) +#define SYSFLG1_CTXFF (1 << 25) +#define SYSFLG1_SSIBUSY (1 << 26) +#define SYSFLG1_ID (1 << 29) + +#define SYSFLG2_SSRXOF (1 << 0) +#define SYSFLG2_RESVAL (1 << 1) +#define SYSFLG2_RESFRM (1 << 2) +#define SYSFLG2_SS2RXFE (1 << 3) +#define SYSFLG2_SS2TXFF (1 << 4) +#define SYSFLG2_SS2TXUF (1 << 5) +#define SYSFLG2_CKMODE (1 << 6) +#define SYSFLG2_UBUSY SYSFLG_UBUSY +#define SYSFLG2_URXFE SYSFLG_URXFE +#define SYSFLG2_UTXFF SYSFLG_UTXFF + +#define LCDCON_GSEN (1 << 30) +#define LCDCON_GSMD (1 << 31) + +#define SYSCON2_SERSEL (1 << 0) +#define SYSCON2_KBD6 (1 << 1) +#define SYSCON2_DRAMZ (1 << 2) +#define SYSCON2_KBWEN (1 << 3) +#define SYSCON2_SS2TXEN (1 << 4) +#define SYSCON2_PCCARD1 (1 << 5) +#define SYSCON2_PCCARD2 (1 << 6) +#define SYSCON2_SS2RXEN (1 << 7) +#define SYSCON2_UART2EN SYSCON_UARTEN +#define SYSCON2_SS2MAEN (1 << 9) +#define SYSCON2_OSTB (1 << 12) +#define SYSCON2_CLKENSL (1 << 13) +#define SYSCON2_BUZFREQ (1 << 14) + +/* common bits: UARTDR1 / UARTDR2 */ +#define UARTDR_FRMERR (1 << 8) +#define UARTDR_PARERR (1 << 9) +#define UARTDR_OVERR (1 << 10) + +/* common bits: UBRLCR1 / UBRLCR2 */ +#define UBRLCR_BAUD_MASK ((1 << 12) - 1) +#define UBRLCR_BREAK (1 << 12) +#define UBRLCR_PRTEN (1 << 13) +#define UBRLCR_EVENPRT (1 << 14) +#define UBRLCR_XSTOP (1 << 15) +#define UBRLCR_FIFOEN (1 << 16) +#define UBRLCR_WRDLEN5 (0 << 17) +#define UBRLCR_WRDLEN6 (1 << 17) +#define UBRLCR_WRDLEN7 (2 << 17) +#define UBRLCR_WRDLEN8 (3 << 17) +#define UBRLCR_WRDLEN_MASK (3 << 17) + +#define SYNCIO_SMCKEN (1 << 13) +#define SYNCIO_TXFRMEN (1 << 14) + +#endif /* __ASM_HARDWARE_CLPS7111_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/hardware/ep7212.h linux.ac/include/asm-arm/hardware/ep7212.h --- linux.vanilla/include/asm-arm/hardware/ep7212.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-arm/hardware/ep7212.h Sat Apr 14 01:38:20 2001 @@ -0,0 +1,84 @@ +/* + * linux/include/asm-arm/hardware/ep7212.h + * + * This file contains the hardware definitions of the EP7212 internal + * registers. + * + * Copyright (C) 2000 Deep Blue Solutions 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_HARDWARE_EP7212_H +#define __ASM_HARDWARE_EP7212_H + +/* + * define EP7212_BASE to be the base address of the region + * you want to access. + */ + +#define EP7212_PHYS_BASE (0x80000000) + +#ifndef __ASSEMBLY__ +#define ep_readl(off) __raw_readl(EP7212_BASE + (off)) +#define ep_writel(val,off) __raw_writel(val, EP7212_BASE + (off)) +#endif + +/* + * These registers are specific to the EP7212 only + */ +#define DAIR 0x2000 +#define DAIR0 0x2040 +#define DAIDR1 0x2080 +#define DAIDR2 0x20c0 +#define DAISR 0x2100 +#define SYSCON3 0x2200 +#define INTSR3 0x2240 +#define INTMR3 0x2280 +#define LEDFLSH 0x22c0 + +#define DAIR_DAIEN (1 << 16) +#define DAIR_ECS (1 << 17) +#define DAIR_LCTM (1 << 19) +#define DAIR_LCRM (1 << 20) +#define DAIR_RCTM (1 << 21) +#define DAIR_RCRM (1 << 22) +#define DAIR_LBM (1 << 23) + +#define DAIDR2_FIFOEN (1 << 15) +#define DAIDR2_FIFOLEFT (0x0d << 16) +#define DAIDR2_FIFORIGHT (0x11 << 16) + +#define DAISR_RCTS (1 << 0) +#define DAISR_RCRS (1 << 1) +#define DAISR_LCTS (1 << 2) +#define DAISR_LCRS (1 << 3) +#define DAISR_RCTU (1 << 4) +#define DAISR_RCRO (1 << 5) +#define DAISR_LCTU (1 << 6) +#define DAISR_LCRO (1 << 7) +#define DAISR_RCNF (1 << 8) +#define DAISR_RCNE (1 << 9) +#define DAISR_LCNF (1 << 10) +#define DAISR_LCNE (1 << 11) +#define DAISR_FIFO (1 << 12) + +#define SYSCON3_ADCCON (1 << 0) +#define SYSCON3_DAISEL (1 << 3) +#define SYSCON3_ADCCKNSEN (1 << 4) +#define SYSCON3_FASTWAKE (1 << 8) +#define SYSCON3_DAIEN (1 << 9) + + +#endif /* __ASM_HARDWARE_EP7212_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/hardware/ioc.h linux.ac/include/asm-arm/hardware/ioc.h --- linux.vanilla/include/asm-arm/hardware/ioc.h Mon Sep 18 23:15:23 2000 +++ linux.ac/include/asm-arm/hardware/ioc.h Sat Apr 14 01:38:20 2001 @@ -10,58 +10,63 @@ * Use these macros to read/write the IOC. All it does is perform the actual * read/write. */ - -#ifndef IOC_CONTROL +#ifndef __ASMARM_HARDWARE_IOC_H +#define __ASMARM_HARDWARE_IOC_H #ifndef __ASSEMBLY__ -#define __IOC(offset) (IOC_BASE + (offset >> 2)) -#else -#define __IOC(offset) offset + +/* + * We use __raw_base variants here so that we give the compiler the + * chance to keep IOC_BASE in a register. + */ +#define ioc_readb(off) __raw_base_readb(IOC_BASE, (off)) +#define ioc_writeb(val,off) __raw_base_writeb(val, IOC_BASE, (off)) + #endif -#define IOC_CONTROL __IOC(0x00) -#define IOC_KARTTX __IOC(0x04) -#define IOC_KARTRX __IOC(0x04) - -#define IOC_IRQSTATA __IOC(0x10) -#define IOC_IRQREQA __IOC(0x14) -#define IOC_IRQCLRA __IOC(0x14) -#define IOC_IRQMASKA __IOC(0x18) - -#define IOC_IRQSTATB __IOC(0x20) -#define IOC_IRQREQB __IOC(0x24) -#define IOC_IRQMASKB __IOC(0x28) - -#define IOC_FIQSTAT __IOC(0x30) -#define IOC_FIQREQ __IOC(0x34) -#define IOC_FIQMASK __IOC(0x38) - -#define IOC_T0CNTL __IOC(0x40) -#define IOC_T0LTCHL __IOC(0x40) -#define IOC_T0CNTH __IOC(0x44) -#define IOC_T0LTCHH __IOC(0x44) -#define IOC_T0GO __IOC(0x48) -#define IOC_T0LATCH __IOC(0x4c) - -#define IOC_T1CNTL __IOC(0x50) -#define IOC_T1LTCHL __IOC(0x50) -#define IOC_T1CNTH __IOC(0x54) -#define IOC_T1LTCHH __IOC(0x54) -#define IOC_T1GO __IOC(0x58) -#define IOC_T1LATCH __IOC(0x5c) - -#define IOC_T2CNTL __IOC(0x60) -#define IOC_T2LTCHL __IOC(0x60) -#define IOC_T2CNTH __IOC(0x64) -#define IOC_T2LTCHH __IOC(0x64) -#define IOC_T2GO __IOC(0x68) -#define IOC_T2LATCH __IOC(0x6c) - -#define IOC_T3CNTL __IOC(0x70) -#define IOC_T3LTCHL __IOC(0x70) -#define IOC_T3CNTH __IOC(0x74) -#define IOC_T3LTCHH __IOC(0x74) -#define IOC_T3GO __IOC(0x78) -#define IOC_T3LATCH __IOC(0x7c) +#define IOC_CONTROL (0x00) +#define IOC_KARTTX (0x04) +#define IOC_KARTRX (0x04) + +#define IOC_IRQSTATA (0x10) +#define IOC_IRQREQA (0x14) +#define IOC_IRQCLRA (0x14) +#define IOC_IRQMASKA (0x18) + +#define IOC_IRQSTATB (0x20) +#define IOC_IRQREQB (0x24) +#define IOC_IRQMASKB (0x28) + +#define IOC_FIQSTAT (0x30) +#define IOC_FIQREQ (0x34) +#define IOC_FIQMASK (0x38) + +#define IOC_T0CNTL (0x40) +#define IOC_T0LTCHL (0x40) +#define IOC_T0CNTH (0x44) +#define IOC_T0LTCHH (0x44) +#define IOC_T0GO (0x48) +#define IOC_T0LATCH (0x4c) + +#define IOC_T1CNTL (0x50) +#define IOC_T1LTCHL (0x50) +#define IOC_T1CNTH (0x54) +#define IOC_T1LTCHH (0x54) +#define IOC_T1GO (0x58) +#define IOC_T1LATCH (0x5c) + +#define IOC_T2CNTL (0x60) +#define IOC_T2LTCHL (0x60) +#define IOC_T2CNTH (0x64) +#define IOC_T2LTCHH (0x64) +#define IOC_T2GO (0x68) +#define IOC_T2LATCH (0x6c) + +#define IOC_T3CNTL (0x70) +#define IOC_T3LTCHL (0x70) +#define IOC_T3CNTH (0x74) +#define IOC_T3LTCHH (0x74) +#define IOC_T3GO (0x78) +#define IOC_T3LATCH (0x7c) #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/hardware/iomd.h linux.ac/include/asm-arm/hardware/iomd.h --- linux.vanilla/include/asm-arm/hardware/iomd.h Mon Sep 18 23:15:23 2000 +++ linux.ac/include/asm-arm/hardware/iomd.h Sat Apr 14 01:38:20 2001 @@ -1,5 +1,5 @@ /* - * linux/include/asm-arm/iomd.h + * linux/include/asm-arm/hardware/iomd.h * * Copyright (C) 1999 Russell King * @@ -10,111 +10,121 @@ * This file contains information out the IOMD ASIC used in the * Acorn RiscPC and subsequently integrated into the CLPS7500 chips. */ +#ifndef __ASMARM_HARDWARE_IOMD_H +#define __ASMARM_HARDWARE_IOMD_H + #include <linux/config.h> #ifndef __ASSEMBLY__ -#define __IOMD(offset) (IO_IOMD_BASE + (offset >> 2)) -#else -#define __IOMD(offset) offset + +/* + * We use __raw_base variants here so that we give the compiler the + * chance to keep IOC_BASE in a register. + */ +#define iomd_readb(off) __raw_base_readb(IOMD_BASE, (off)) +#define iomd_readl(off) __raw_base_readl(IOMD_BASE, (off)) +#define iomd_writeb(val,off) __raw_base_writeb(val, IOMD_BASE, (off)) +#define iomd_writel(val,off) __raw_base_writel(val, IOMD_BASE, (off)) + #endif -#define IOMD_CONTROL __IOMD(0x000) -#define IOMD_KARTTX __IOMD(0x004) -#define IOMD_KARTRX __IOMD(0x004) -#define IOMD_KCTRL __IOMD(0x008) +#define IOMD_CONTROL (0x000) +#define IOMD_KARTTX (0x004) +#define IOMD_KARTRX (0x004) +#define IOMD_KCTRL (0x008) #ifdef CONFIG_ARCH_CLPS7500 -#define IOMD_IOLINES __IOMD(0x00C) +#define IOMD_IOLINES (0x00C) #endif -#define IOMD_IRQSTATA __IOMD(0x010) -#define IOMD_IRQREQA __IOMD(0x014) -#define IOMD_IRQCLRA __IOMD(0x014) -#define IOMD_IRQMASKA __IOMD(0x018) +#define IOMD_IRQSTATA (0x010) +#define IOMD_IRQREQA (0x014) +#define IOMD_IRQCLRA (0x014) +#define IOMD_IRQMASKA (0x018) #ifdef CONFIG_ARCH_CLPS7500 -#define IOMD_SUSMODE __IOMD(0x01C) +#define IOMD_SUSMODE (0x01C) #endif -#define IOMD_IRQSTATB __IOMD(0x020) -#define IOMD_IRQREQB __IOMD(0x024) -#define IOMD_IRQMASKB __IOMD(0x028) +#define IOMD_IRQSTATB (0x020) +#define IOMD_IRQREQB (0x024) +#define IOMD_IRQMASKB (0x028) -#define IOMD_FIQSTAT __IOMD(0x030) -#define IOMD_FIQREQ __IOMD(0x034) -#define IOMD_FIQMASK __IOMD(0x038) +#define IOMD_FIQSTAT (0x030) +#define IOMD_FIQREQ (0x034) +#define IOMD_FIQMASK (0x038) #ifdef CONFIG_ARCH_CLPS7500 -#define IOMD_CLKCTL __IOMD(0x03C) +#define IOMD_CLKCTL (0x03C) #endif -#define IOMD_T0CNTL __IOMD(0x040) -#define IOMD_T0LTCHL __IOMD(0x040) -#define IOMD_T0CNTH __IOMD(0x044) -#define IOMD_T0LTCHH __IOMD(0x044) -#define IOMD_T0GO __IOMD(0x048) -#define IOMD_T0LATCH __IOMD(0x04c) +#define IOMD_T0CNTL (0x040) +#define IOMD_T0LTCHL (0x040) +#define IOMD_T0CNTH (0x044) +#define IOMD_T0LTCHH (0x044) +#define IOMD_T0GO (0x048) +#define IOMD_T0LATCH (0x04c) -#define IOMD_T1CNTL __IOMD(0x050) -#define IOMD_T1LTCHL __IOMD(0x050) -#define IOMD_T1CNTH __IOMD(0x054) -#define IOMD_T1LTCHH __IOMD(0x054) -#define IOMD_T1GO __IOMD(0x058) -#define IOMD_T1LATCH __IOMD(0x05c) +#define IOMD_T1CNTL (0x050) +#define IOMD_T1LTCHL (0x050) +#define IOMD_T1CNTH (0x054) +#define IOMD_T1LTCHH (0x054) +#define IOMD_T1GO (0x058) +#define IOMD_T1LATCH (0x05c) #ifdef CONFIG_ARCH_CLPS7500 -#define IOMD_IRQSTATC __IOMD(0x060) -#define IOMD_IRQREQC __IOMD(0x064) -#define IOMD_IRQMASKC __IOMD(0x068) +#define IOMD_IRQSTATC (0x060) +#define IOMD_IRQREQC (0x064) +#define IOMD_IRQMASKC (0x068) -#define IOMD_VIDMUX __IOMD(0x06c) +#define IOMD_VIDMUX (0x06c) -#define IOMD_IRQSTATD __IOMD(0x070) -#define IOMD_IRQREQD __IOMD(0x074) -#define IOMD_IRQMASKD __IOMD(0x078) +#define IOMD_IRQSTATD (0x070) +#define IOMD_IRQREQD (0x074) +#define IOMD_IRQMASKD (0x078) #endif -#define IOMD_ROMCR0 __IOMD(0x080) -#define IOMD_ROMCR1 __IOMD(0x084) +#define IOMD_ROMCR0 (0x080) +#define IOMD_ROMCR1 (0x084) #ifdef CONFIG_ARCH_RPC -#define IOMD_DRAMCR __IOMD(0x088) +#define IOMD_DRAMCR (0x088) #endif -#define IOMD_REFCR __IOMD(0x08C) +#define IOMD_REFCR (0x08C) -#define IOMD_FSIZE __IOMD(0x090) -#define IOMD_ID0 __IOMD(0x094) -#define IOMD_ID1 __IOMD(0x098) -#define IOMD_VERSION __IOMD(0x09C) +#define IOMD_FSIZE (0x090) +#define IOMD_ID0 (0x094) +#define IOMD_ID1 (0x098) +#define IOMD_VERSION (0x09C) #ifdef CONFIG_ARCH_RPC -#define IOMD_MOUSEX __IOMD(0x0A0) -#define IOMD_MOUSEY __IOMD(0x0A4) +#define IOMD_MOUSEX (0x0A0) +#define IOMD_MOUSEY (0x0A4) #endif #ifdef CONFIG_ARCH_CLPS7500 -#define IOMD_MSEDAT __IOMD(0x0A8) -#define IOMD_MSECTL __IOMD(0x0Ac) +#define IOMD_MSEDAT (0x0A8) +#define IOMD_MSECTL (0x0Ac) #endif #ifdef CONFIG_ARCH_RPC -#define IOMD_DMATCR __IOMD(0x0C0) +#define IOMD_DMATCR (0x0C0) #endif -#define IOMD_IOTCR __IOMD(0x0C4) -#define IOMD_ECTCR __IOMD(0x0C8) +#define IOMD_IOTCR (0x0C4) +#define IOMD_ECTCR (0x0C8) #ifdef CONFIG_ARCH_RPC -#define IOMD_DMAEXT __IOMD(0x0CC) +#define IOMD_DMAEXT (0x0CC) #endif #ifdef CONFIG_ARCH_CLPS7500 -#define IOMD_ASTCR __IOMD(0x0CC) -#define IOMD_DRAMCR __IOMD(0x0D0) -#define IOMD_SELFREF __IOMD(0x0D4) -#define IOMD_ATODICR __IOMD(0x0E0) -#define IOMD_ATODSR __IOMD(0x0E4) -#define IOMD_ATODCC __IOMD(0x0E8) -#define IOMD_ATODCNT1 __IOMD(0x0EC) -#define IOMD_ATODCNT2 __IOMD(0x0F0) -#define IOMD_ATODCNT3 __IOMD(0x0F4) -#define IOMD_ATODCNT4 __IOMD(0x0F8) +#define IOMD_ASTCR (0x0CC) +#define IOMD_DRAMCR (0x0D0) +#define IOMD_SELFREF (0x0D4) +#define IOMD_ATODICR (0x0E0) +#define IOMD_ATODSR (0x0E4) +#define IOMD_ATODCC (0x0E8) +#define IOMD_ATODCNT1 (0x0EC) +#define IOMD_ATODCNT2 (0x0F0) +#define IOMD_ATODCNT3 (0x0F4) +#define IOMD_ATODCNT4 (0x0F8) #endif #ifdef CONFIG_ARCH_RPC @@ -123,63 +133,63 @@ #define DMA_EXT_IO2 4 #define DMA_EXT_IO3 8 -#define IOMD_IO0CURA __IOMD(0x100) -#define IOMD_IO0ENDA __IOMD(0x104) -#define IOMD_IO0CURB __IOMD(0x108) -#define IOMD_IO0ENDB __IOMD(0x10C) -#define IOMD_IO0CR __IOMD(0x110) -#define IOMD_IO0ST __IOMD(0x114) - -#define IOMD_IO1CURA __IOMD(0x120) -#define IOMD_IO1ENDA __IOMD(0x124) -#define IOMD_IO1CURB __IOMD(0x128) -#define IOMD_IO1ENDB __IOMD(0x12C) -#define IOMD_IO1CR __IOMD(0x130) -#define IOMD_IO1ST __IOMD(0x134) - -#define IOMD_IO2CURA __IOMD(0x140) -#define IOMD_IO2ENDA __IOMD(0x144) -#define IOMD_IO2CURB __IOMD(0x148) -#define IOMD_IO2ENDB __IOMD(0x14C) -#define IOMD_IO2CR __IOMD(0x150) -#define IOMD_IO2ST __IOMD(0x154) - -#define IOMD_IO3CURA __IOMD(0x160) -#define IOMD_IO3ENDA __IOMD(0x164) -#define IOMD_IO3CURB __IOMD(0x168) -#define IOMD_IO3ENDB __IOMD(0x16C) -#define IOMD_IO3CR __IOMD(0x170) -#define IOMD_IO3ST __IOMD(0x174) -#endif - -#define IOMD_SD0CURA __IOMD(0x180) -#define IOMD_SD0ENDA __IOMD(0x184) -#define IOMD_SD0CURB __IOMD(0x188) -#define IOMD_SD0ENDB __IOMD(0x18C) -#define IOMD_SD0CR __IOMD(0x190) -#define IOMD_SD0ST __IOMD(0x194) - -#ifdef CONFIG_ARCH_RPC -#define IOMD_SD1CURA __IOMD(0x1A0) -#define IOMD_SD1ENDA __IOMD(0x1A4) -#define IOMD_SD1CURB __IOMD(0x1A8) -#define IOMD_SD1ENDB __IOMD(0x1AC) -#define IOMD_SD1CR __IOMD(0x1B0) -#define IOMD_SD1ST __IOMD(0x1B4) -#endif - -#define IOMD_CURSCUR __IOMD(0x1C0) -#define IOMD_CURSINIT __IOMD(0x1C4) - -#define IOMD_VIDCUR __IOMD(0x1D0) -#define IOMD_VIDEND __IOMD(0x1D4) -#define IOMD_VIDSTART __IOMD(0x1D8) -#define IOMD_VIDINIT __IOMD(0x1DC) -#define IOMD_VIDCR __IOMD(0x1E0) - -#define IOMD_DMASTAT __IOMD(0x1F0) -#define IOMD_DMAREQ __IOMD(0x1F4) -#define IOMD_DMAMASK __IOMD(0x1F8) +#define IOMD_IO0CURA (0x100) +#define IOMD_IO0ENDA (0x104) +#define IOMD_IO0CURB (0x108) +#define IOMD_IO0ENDB (0x10C) +#define IOMD_IO0CR (0x110) +#define IOMD_IO0ST (0x114) + +#define IOMD_IO1CURA (0x120) +#define IOMD_IO1ENDA (0x124) +#define IOMD_IO1CURB (0x128) +#define IOMD_IO1ENDB (0x12C) +#define IOMD_IO1CR (0x130) +#define IOMD_IO1ST (0x134) + +#define IOMD_IO2CURA (0x140) +#define IOMD_IO2ENDA (0x144) +#define IOMD_IO2CURB (0x148) +#define IOMD_IO2ENDB (0x14C) +#define IOMD_IO2CR (0x150) +#define IOMD_IO2ST (0x154) + +#define IOMD_IO3CURA (0x160) +#define IOMD_IO3ENDA (0x164) +#define IOMD_IO3CURB (0x168) +#define IOMD_IO3ENDB (0x16C) +#define IOMD_IO3CR (0x170) +#define IOMD_IO3ST (0x174) +#endif + +#define IOMD_SD0CURA (0x180) +#define IOMD_SD0ENDA (0x184) +#define IOMD_SD0CURB (0x188) +#define IOMD_SD0ENDB (0x18C) +#define IOMD_SD0CR (0x190) +#define IOMD_SD0ST (0x194) + +#ifdef CONFIG_ARCH_RPC +#define IOMD_SD1CURA (0x1A0) +#define IOMD_SD1ENDA (0x1A4) +#define IOMD_SD1CURB (0x1A8) +#define IOMD_SD1ENDB (0x1AC) +#define IOMD_SD1CR (0x1B0) +#define IOMD_SD1ST (0x1B4) +#endif + +#define IOMD_CURSCUR (0x1C0) +#define IOMD_CURSINIT (0x1C4) + +#define IOMD_VIDCUR (0x1D0) +#define IOMD_VIDEND (0x1D4) +#define IOMD_VIDSTART (0x1D8) +#define IOMD_VIDINIT (0x1DC) +#define IOMD_VIDCR (0x1E0) + +#define IOMD_DMASTAT (0x1F0) +#define IOMD_DMAREQ (0x1F4) +#define IOMD_DMAMASK (0x1F8) #define DMA_END_S (1 << 31) #define DMA_END_L (1 << 30) @@ -192,39 +202,6 @@ #define DMA_ST_INT 2 #define DMA_ST_AB 1 -#ifndef IOC_CONTROL -/* - * IOC compatability - */ -#define IOC_CONTROL IOMD_CONTROL -#define IOC_IRQSTATA IOMD_IRQSTATA -#define IOC_IRQREQA IOMD_IRQREQA -#define IOC_IRQCLRA IOMD_IRQCLRA -#define IOC_IRQMASKA IOMD_IRQMASKA - -#define IOC_IRQSTATB IOMD_IRQSTATB -#define IOC_IRQREQB IOMD_IRQREQB -#define IOC_IRQMASKB IOMD_IRQMASKB - -#define IOC_FIQSTAT IOMD_FIQSTAT -#define IOC_FIQREQ IOMD_FIQREQ -#define IOC_FIQMASK IOMD_FIQMASK - -#define IOC_T0CNTL IOMD_T0CNTL -#define IOC_T0LTCHL IOMD_T0LTCHL -#define IOC_T0CNTH IOMD_T0CNTH -#define IOC_T0LTCHH IOMD_T0LTCHH -#define IOC_T0GO IOMD_T0GO -#define IOC_T0LATCH IOMD_T0LATCH - -#define IOC_T1CNTL IOMD_T1CNTL -#define IOC_T1LTCHL IOMD_T1LTCHL -#define IOC_T1CNTH IOMD_T1CNTH -#define IOC_T1LTCHH IOMD_T1LTCHH -#define IOC_T1GO IOMD_T1GO -#define IOC_T1LATCH IOMD_T1LATCH -#endif - /* * DMA (MEMC) compatability */ @@ -247,3 +224,4 @@ } while (0) #endif +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/io.h linux.ac/include/asm-arm/io.h --- linux.vanilla/include/asm-arm/io.h Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-arm/io.h Sat Apr 14 01:38:20 2001 @@ -104,11 +104,13 @@ _ret = __ioremap(iomem_to_phys(_off),_size,0); \ _ret; \ }) + +#define __arch_iounmap __iounmap #endif #define ioremap(off,sz) __arch_ioremap((off),(sz),0) #define ioremap_nocache(off,sz) __arch_ioremap((off),(sz),1) -#define iounmap(_addr) __iounmap(_addr) +#define iounmap(_addr) __arch_iounmap(_addr) /* * DMA-consistent mapping functions. These allocate/free a region of @@ -188,7 +190,7 @@ return retval; } -#else /* __mem_pci */ +#elif !defined(readb) #define readb(addr) (__readwrite_bug("readb"),0) #define readw(addr) (__readwrite_bug("readw"),0) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/mmzone.h linux.ac/include/asm-arm/mmzone.h --- linux.vanilla/include/asm-arm/mmzone.h Mon Sep 18 23:15:24 2000 +++ linux.ac/include/asm-arm/mmzone.h Sat Apr 14 01:38:20 2001 @@ -10,6 +10,21 @@ #ifndef __ASM_MMZONE_H #define __ASM_MMZONE_H +/* + * Currently defined in arch/arm/mm/discontig.c + */ +extern pg_data_t discontig_node_data[]; + +/* + * Return a pointer to the node data for node n. + */ +#define NODE_DATA(nid) (&discontig_node_data[nid]) + +/* + * NODE_MEM_MAP gives the kaddr for the mem_map of the node. + */ +#define NODE_MEM_MAP(nid) (NODE_DATA(nid)->node_mem_map) + #include <asm/arch/mmzone.h> #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/pgalloc.h linux.ac/include/asm-arm/pgalloc.h --- linux.vanilla/include/asm-arm/pgalloc.h Mon Sep 18 23:15:24 2000 +++ linux.ac/include/asm-arm/pgalloc.h Sat Apr 14 01:38:20 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/pgalloc.h * - * Copyright (C) 2000 Russell King + * Copyright (C) 2000-2001 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 @@ -25,6 +25,11 @@ #define flush_tlb_pgtables(mm,start,end) do { } while (0) /* + * Processor specific parts... + */ +#include <asm/proc/pgalloc.h> + +/* * Page table cache stuff */ #ifndef CONFIG_NO_PGT_CACHE @@ -68,20 +73,13 @@ pgtable_cache_size++; } -/* We don't use pmd cache, so this is a dummy routine */ -#define get_pmd_fast() ((pmd_t *)0) - -extern __inline__ void free_pmd_fast(pmd_t *pmd) -{ -} - -extern __inline__ pte_t *get_pte_fast(void) +static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) { unsigned long *ret; if((ret = pte_quicklist) != NULL) { pte_quicklist = (unsigned long *)__pte_next(ret); - ret[0] = ret[1]; + ret[0] = 0; clean_dcache_entry(ret); pgtable_cache_size--; } @@ -97,119 +95,47 @@ #else /* CONFIG_NO_PGT_CACHE */ -#define pgd_quicklist ((unsigned long *)0) -#define pmd_quicklist ((unsigned long *)0) -#define pte_quicklist ((unsigned long *)0) +#define pgd_quicklist ((unsigned long *)0) +#define pmd_quicklist ((unsigned long *)0) +#define pte_quicklist ((unsigned long *)0) -#define get_pgd_fast() ((pgd_t *)0) -#define get_pmd_fast() ((pmd_t *)0) -#define get_pte_fast() ((pte_t *)0) - -#define free_pgd_fast(pgd) free_pgd_slow(pgd) -#define free_pmd_fast(pmd) free_pmd_slow(pmd) -#define free_pte_fast(pte) free_pte_slow(pte) +#define get_pgd_fast() ((pgd_t *)0) +#define pte_alloc_one_fast(mm,addr) ((pte_t *)0) -#endif /* CONFIG_NO_PGT_CACHE */ +#define free_pgd_fast(pgd) free_pgd_slow(pgd) +#define free_pte_fast(pte) pte_free_slow(pte) -extern pgd_t *get_pgd_slow(void); -extern void free_pgd_slow(pgd_t *pgd); +#endif /* CONFIG_NO_PGT_CACHE */ -#define free_pmd_slow(pmd) do { } while (0) +#define pte_free(pte) free_pte_fast(pte) -extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long addr_preadjusted); -extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long addr_preadjusted); -extern void free_pte_slow(pte_t *pte); /* - * Allocate and free page tables. The xxx_kernel() versions are - * used to allocate a kernel page table - this turns on ASN bits - * if any. + * Since we have only two-level page tables, these are trivial */ -#define pte_free_kernel(pte) free_pte_fast(pte) -#define pte_free(pte) free_pte_fast(pte) +#define pmd_alloc_one_fast(mm,addr) ({ BUG(); ((pmd_t *)1); }) +#define pmd_alloc_one(mm,addr) ({ BUG(); ((pmd_t *)2); }) +#define pmd_free_slow(pmd) do { } while (0) +#define pmd_free_fast(pmd) do { } while (0) +#define pmd_free(pmd) do { } while (0) +#define pgd_populate(mm,pmd,pte) BUG() -#ifndef pte_alloc_kernel -extern __inline__ pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address) -{ - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - pte_t *page = (pte_t *) get_pte_fast(); - - if (!page) - return get_pte_kernel_slow(pmd, address); - set_pmd(pmd, mk_kernel_pmd(page)); - return page + address; - } - if (pmd_bad(*pmd)) { - __handle_bad_pmd_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + address; -} -#endif - -extern __inline__ pte_t *pte_alloc(pmd_t * pmd, unsigned long address) -{ - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - pte_t *page = (pte_t *) get_pte_fast(); - - if (!page) - return get_pte_slow(pmd, address); - set_pmd(pmd, mk_user_pmd(page)); - return page + address; - } - if (pmd_bad(*pmd)) { - __handle_bad_pmd(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + address; -} - -#define pmd_free_kernel pmd_free -#define pmd_free(pmd) do { } while (0) - -#define pmd_alloc_kernel pmd_alloc -extern __inline__ pmd_t *pmd_alloc(pgd_t *pgd, unsigned long address) -{ - return (pmd_t *) pgd; -} - -#define pgd_free(pgd) free_pgd_fast(pgd) +extern pgd_t *get_pgd_slow(struct mm_struct *mm); +extern void free_pgd_slow(pgd_t *pgd); -extern __inline__ pgd_t *pgd_alloc(void) +extern __inline__ pgd_t *pgd_alloc(struct mm_struct *mm) { pgd_t *pgd; pgd = get_pgd_fast(); if (!pgd) - pgd = get_pgd_slow(); + pgd = get_pgd_slow(mm); return pgd; } -extern int do_check_pgt_cache(int, int); +#define pgd_free(pgd) free_pgd_fast(pgd) -extern __inline__ void set_pgdir(unsigned long address, pgd_t entry) -{ - struct task_struct * p; - - read_lock(&tasklist_lock); - for_each_task(p) { - if (!p->mm) - continue; - *pgd_offset(p->mm,address) = entry; - } - read_unlock(&tasklist_lock); - -#ifndef CONFIG_NO_PGT_CACHE - { - pgd_t *pgd; - for (pgd = (pgd_t *)pgd_quicklist; pgd; - pgd = (pgd_t *)__pgd_next(pgd)) - pgd[address >> PGDIR_SHIFT] = entry; - } -#endif -} +extern int do_check_pgt_cache(int, int); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/pgtable.h linux.ac/include/asm-arm/pgtable.h --- linux.vanilla/include/asm-arm/pgtable.h Tue Apr 3 17:32:26 2001 +++ linux.ac/include/asm-arm/pgtable.h Sat Apr 14 01:38:20 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/pgtable.h * - * Copyright (C) 2000 Russell King + * Copyright (C) 2000-2001 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 @@ -75,12 +75,6 @@ extern struct page *empty_zero_page; #define ZERO_PAGE(vaddr) (empty_zero_page) -/* - * Handling allocation failures during page table setup. - */ -extern void __handle_bad_pmd(pmd_t *pmd); -extern void __handle_bad_pmd_kernel(pmd_t *pmd); - #define pte_none(pte) (!pte_val(pte)) #define pte_clear(ptep) set_pte((ptep), __pte(0)) @@ -98,6 +92,7 @@ #endif #define pmd_none(pmd) (!pmd_val(pmd)) +#define pmd_present(pmd) (pmd_val(pmd)) #define pmd_clear(pmdp) set_pmd(pmdp, __pmd(0)) /* @@ -163,8 +158,6 @@ } extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; - -#define update_mmu_cache(vma,address,pte) do { } while (0) /* Encode and decode a swap entry. * diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/proc-armo/cache.h linux.ac/include/asm-arm/proc-armo/cache.h --- linux.vanilla/include/asm-arm/proc-armo/cache.h Mon Sep 18 23:15:24 2000 +++ linux.ac/include/asm-arm/proc-armo/cache.h Sat Apr 14 01:38:20 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/proc-armo/cache.h * - * Copyright (C) 1999-2000 Russell King + * Copyright (C) 1999-2001 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 @@ -37,8 +37,9 @@ * - flush_tlb_range(mm, start, end) flushes a range of pages */ #define flush_tlb_all() memc_update_all() -#define flush_tlb_mm(mm) do { } while (0) -#define flush_tlb_range(mm, start, end) do { (void)(start); (void)(end); } while (0) +#define flush_tlb_mm(mm) memc_update_mm(mm) +#define flush_tlb_range(mm,start,end) \ + do { memc_update_mm(mm); (void)(start); (void)(end); } while (0) #define flush_tlb_page(vma, vmaddr) do { } while (0) /* @@ -57,7 +58,7 @@ processor._set_pgd(current->active_mm->pgd); } -extern __inline__ void memc_update_mm(struct mm_struct *mm) +static inline void memc_update_mm(struct mm_struct *mm) { cpu_memc_update_all(mm->pgd); @@ -66,19 +67,26 @@ } extern __inline__ void -memc_update_addr(struct mm_struct *mm, pte_t pte, unsigned long vaddr) +memc_clear(struct mm_struct *mm, struct page *page) { - cpu_memc_update_entry(mm->pgd, pte_val(pte), vaddr); + cpu_memc_update_entry(mm->pgd, (unsigned long) page_address(page), 0); if (mm == current->active_mm) processor._set_pgd(mm->pgd); } -extern __inline__ void -memc_clear(struct mm_struct *mm, struct page *page) +static inline void +memc_update_addr(struct mm_struct *mm, pte_t pte, unsigned long vaddr) { - cpu_memc_update_entry(mm->pgd, (unsigned long) page_address(page), 0); + cpu_memc_update_entry(mm->pgd, pte_val(pte), vaddr); if (mm == current->active_mm) processor._set_pgd(mm->pgd); +} + +static inline void +update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte) +{ + struct mm_struct *mm = vma->vm_mm; + memc_update_addr(mm, pte, addr); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/proc-armo/pgalloc.h linux.ac/include/asm-arm/proc-armo/pgalloc.h --- linux.vanilla/include/asm-arm/proc-armo/pgalloc.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-arm/proc-armo/pgalloc.h Sat Apr 14 01:38:20 2001 @@ -0,0 +1,47 @@ +/* + * linux/include/asm-arm/proc-armo/pgalloc.h + * + * Copyright (C) 2001 Russell King + * + * Page table allocation/freeing primitives for 26-bit ARM processors. + */ + +/* unfortunately, this includes linux/mm.h and the rest of the universe. */ +#include <linux/slab.h> + +extern kmem_cache_t *pte_cache; + +/* + * Allocate one PTE table. + * + * Note that we keep the processor copy of the PTE entries separate + * from the Linux copy. The processor copies are offset by -PTRS_PER_PTE + * words from the Linux copy. + */ +static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) +{ + return kmem_cache_alloc(pte_cache, GFP_KERNEL); +} + +/* + * Free one PTE table. + */ +static inline void pte_free_slow(pte_t *pte) +{ + if (pte) + kmem_cache_free(pte_cache, pte); +} + +/* + * Populate the pmdp entry with a pointer to the pte. This pmd is part + * of the mm address space. + * + * If 'mm' is the init tasks mm, then we are doing a vmalloc, and we + * need to set stuff up correctly for it. + */ +#define pmd_populate(mm,pmdp,pte) \ + do { \ + set_pmd(pmdp, __mk_pmd(pte, _PAGE_TABLE)); \ + } while (0) + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/proc-armo/pgtable.h linux.ac/include/asm-arm/proc-armo/pgtable.h --- linux.vanilla/include/asm-arm/proc-armo/pgtable.h Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-arm/proc-armo/pgtable.h Sat Apr 14 01:38:20 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/proc-armo/pgtable.h * - * Copyright (C) 1995-1999 Russell King + * Copyright (C) 1995-2001 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 @@ -33,7 +33,7 @@ #define pmd_bad(pmd) ((pmd_val(pmd) & 0xfc000002)) #define set_pmd(pmdp,pmd) ((*(pmdp)) = (pmd)) -extern __inline__ pmd_t __mk_pmd(pte_t *ptep, unsigned long prot) +static inline pmd_t __mk_pmd(pte_t *ptep, unsigned long prot) { unsigned long pte_ptr = (unsigned long)ptep; pmd_t pmd; @@ -43,11 +43,7 @@ return pmd; } -/* these are aliases for the above function */ -#define mk_user_pmd(ptep) __mk_pmd(ptep, _PAGE_TABLE) -#define mk_kernel_pmd(ptep) __mk_pmd(ptep, _PAGE_TABLE) - -extern __inline__ unsigned long pmd_page(pmd_t pmd) +static inline unsigned long pmd_page(pmd_t pmd) { return __phys_to_virt(pmd_val(pmd) & ~_PAGE_TABLE); } @@ -81,7 +77,6 @@ #define pte_dirty(pte) (!(pte_val(pte) & _PAGE_CLEAN)) #define pte_young(pte) (!(pte_val(pte) & _PAGE_OLD)) -extern inline pte_t pte_nocache(pte_t pte) { return pte; } extern inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) |= _PAGE_READONLY; return pte; } extern inline pte_t pte_rdprotect(pte_t pte) { pte_val(pte) |= _PAGE_NOT_USER; return pte; } extern inline pte_t pte_exprotect(pte_t pte) { pte_val(pte) |= _PAGE_NOT_USER; return pte; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/proc-armo/ptrace.h linux.ac/include/asm-arm/proc-armo/ptrace.h --- linux.vanilla/include/asm-arm/proc-armo/ptrace.h Mon Sep 18 23:15:24 2000 +++ linux.ac/include/asm-arm/proc-armo/ptrace.h Sat Apr 14 01:38:20 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/proc-armo/ptrace.h * - * Copyright (C) 1996-1999 Russell King + * Copyright (C) 1996-2001 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 @@ -14,6 +14,10 @@ #define FIQ26_MODE 0x01 #define IRQ26_MODE 0x02 #define SVC26_MODE 0x03 +#define USR_MODE USR26_MODE +#define FIQ_MODE FIQ26_MODE +#define IRQ_MODE IRQ26_MODE +#define SVC_MODE SVC26_MODE #define MODE_MASK 0x03 #define F_BIT (1 << 26) #define I_BIT (1 << 27) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/proc-armv/cache.h linux.ac/include/asm-arm/proc-armv/cache.h --- linux.vanilla/include/asm-arm/proc-armv/cache.h Mon Sep 18 23:15:24 2000 +++ linux.ac/include/asm-arm/proc-armv/cache.h Sat Apr 14 01:38:20 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/proc-armv/cache.h * - * Copyright (C) 1999-2000 Russell King + * Copyright (C) 1999-2001 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 @@ -154,3 +154,9 @@ cpu_tlb_invalidate_page((_page), \ ((_vma)->vm_flags & VM_EXEC)); \ } while (0) + +/* + * 32-bit ARM Processors don't have any MMU cache + */ +#define update_mmu_cache(vma,address,pte) do { } while (0) + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/proc-armv/pgalloc.h linux.ac/include/asm-arm/proc-armv/pgalloc.h --- linux.vanilla/include/asm-arm/proc-armv/pgalloc.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-arm/proc-armv/pgalloc.h Sat Apr 14 01:38:20 2001 @@ -0,0 +1,58 @@ +/* + * linux/include/asm-arm/proc-armv/pgalloc.h + * + * Copyright (C) 2001 Russell King + * + * Page table allocation/freeing primitives for 32-bit ARM processors. + */ + +/* unfortunately, this includes linux/mm.h and the rest of the universe. */ +#include <linux/slab.h> + +extern kmem_cache_t *pte_cache; + +/* + * Allocate one PTE table. + * + * Note that we keep the processor copy of the PTE entries separate + * from the Linux copy. The processor copies are offset by -PTRS_PER_PTE + * words from the Linux copy. + */ +static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pte_t *pte; + + pte = kmem_cache_alloc(pte_cache, GFP_KERNEL); + if (pte) + pte += PTRS_PER_PTE; + return pte; +} + +/* + * Free one PTE table. + */ +static inline void pte_free_slow(pte_t *pte) +{ + if (pte) { + pte -= PTRS_PER_PTE; + kmem_cache_free(pte_cache, pte); + } +} + +/* + * Populate the pmdp entry with a pointer to the pte. This pmd is part + * of the mm address space. + * + * If 'mm' is the init tasks mm, then we are doing a vmalloc, and we + * need to set stuff up correctly for it. + */ +#define pmd_populate(mm,pmdp,pte) \ + do { \ + unsigned long __prot; \ + if (mm == &init_mm) \ + __prot = _PAGE_KERNEL_TABLE; \ + else \ + __prot = _PAGE_USER_TABLE; \ + set_pmd(pmdp, __mk_pmd(pte, __prot)); \ + } while (0) + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/proc-armv/pgtable.h linux.ac/include/asm-arm/proc-armv/pgtable.h --- linux.vanilla/include/asm-arm/proc-armv/pgtable.h Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-arm/proc-armv/pgtable.h Sat Apr 14 01:38:20 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/proc-armv/pgtable.h * - * Copyright (C) 1995-1999 Russell King + * Copyright (C) 1995-2001 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 @@ -48,7 +48,7 @@ #define pmd_bad(pmd) (pmd_val(pmd) & 2) #define set_pmd(pmdp,pmd) cpu_set_pmd(pmdp,pmd) -extern __inline__ pmd_t __mk_pmd(pte_t *ptep, unsigned long prot) +static inline pmd_t __mk_pmd(pte_t *ptep, unsigned long prot) { unsigned long pte_ptr = (unsigned long)ptep; pmd_t pmd; @@ -64,11 +64,7 @@ return pmd; } -/* these are aliases for the above function */ -#define mk_user_pmd(ptep) __mk_pmd(ptep, _PAGE_USER_TABLE) -#define mk_kernel_pmd(ptep) __mk_pmd(ptep, _PAGE_KERNEL_TABLE) - -extern __inline__ unsigned long pmd_page(pmd_t pmd) +static inline unsigned long pmd_page(pmd_t pmd) { unsigned long ptr; @@ -161,7 +157,6 @@ PTE_BIT_FUNC(mkdirty, |= L_PTE_DIRTY); PTE_BIT_FUNC(mkold, &= ~L_PTE_YOUNG); PTE_BIT_FUNC(mkyoung, |= L_PTE_YOUNG); -PTE_BIT_FUNC(nocache, &= ~L_PTE_CACHEABLE); /* * Mark the prot value as uncacheable and unbufferable. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/proc-armv/uaccess.h linux.ac/include/asm-arm/proc-armv/uaccess.h --- linux.vanilla/include/asm-arm/proc-armv/uaccess.h Tue Apr 3 17:32:27 2001 +++ linux.ac/include/asm-arm/proc-armv/uaccess.h Sat Apr 14 01:38:20 2001 @@ -91,7 +91,7 @@ " .align 3\n" \ " .long 1b, 3b\n" \ " .previous" \ - : "=r" (err), "=r" (x) \ + : "=r" (err), "=&r" (x) \ : "r" (addr), "i" (-EFAULT), "0" (err)) #define __get_user_asm_half(x,addr,err) \ @@ -117,7 +117,7 @@ " .align 3\n" \ " .long 1b, 3b\n" \ " .previous" \ - : "=r" (err), "=r" (x) \ + : "=r" (err), "=&r" (x) \ : "r" (addr), "i" (-EFAULT), "0" (err)) extern unsigned long __arch_copy_from_user(void *to, const void *from, unsigned long n); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/processor.h linux.ac/include/asm-arm/processor.h --- linux.vanilla/include/asm-arm/processor.h Sat Dec 30 17:35:40 2000 +++ linux.ac/include/asm-arm/processor.h Sat Apr 14 01:38:20 2001 @@ -38,6 +38,7 @@ #define EISA_bus 0 #define MCA_bus 0 +#define MCA_bus__is_a_macro #include <asm/atomic.h> #include <asm/ptrace.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/procinfo.h linux.ac/include/asm-arm/procinfo.h --- linux.vanilla/include/asm-arm/procinfo.h Mon Sep 18 23:15:24 2000 +++ linux.ac/include/asm-arm/procinfo.h Sat Apr 14 01:38:20 2001 @@ -46,10 +46,13 @@ #endif /* __ASSEMBLY__ */ -#define HWCAP_SWP 1 -#define HWCAP_HALF 2 -#define HWCAP_THUMB 4 -#define HWCAP_26BIT 8 /* Play it safe */ +#define HWCAP_SWP 1 +#define HWCAP_HALF 2 +#define HWCAP_THUMB 4 +#define HWCAP_26BIT 8 /* Play it safe */ +#define HWCAP_FAST_MULT 16 +#define HWCAP_FPA 32 +#define HWCAP_VFP 64 +#define HWCAP_EDSP 128 #endif - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/setup.h linux.ac/include/asm-arm/setup.h --- linux.vanilla/include/asm-arm/setup.h Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-arm/setup.h Sat Apr 14 01:38:20 2001 @@ -207,7 +207,7 @@ /* * Memory map description */ -#define NR_BANKS 4 +#define NR_BANKS 8 struct meminfo { int nr_banks; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/tlb.h linux.ac/include/asm-arm/tlb.h --- linux.vanilla/include/asm-arm/tlb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-arm/tlb.h Tue Apr 3 17:55:14 2001 @@ -0,0 +1 @@ +#include <asm-generic/tlb.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/unistd.h linux.ac/include/asm-arm/unistd.h --- linux.vanilla/include/asm-arm/unistd.h Tue Apr 3 17:32:27 2001 +++ linux.ac/include/asm-arm/unistd.h Sat Apr 14 01:38:20 2001 @@ -224,6 +224,10 @@ #define __NR_setfsuid32 (__NR_SYSCALL_BASE+215) #define __NR_setfsgid32 (__NR_SYSCALL_BASE+216) #define __NR_getdents64 (__NR_SYSCALL_BASE+217) +#define __NR_pivot_root (__NR_SYSCALL_BASE+218) +#define __NR_mincore (__NR_SYSCALL_BASE+219) +#define __NR_madvise (__NR_SYSCALL_BASE+220) +#define __NR_fcntl64 (__NR_SYSCALL_BASE+221) #define __sys2(x) #x #define __sys1(x) __sys2(x) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/xor.h linux.ac/include/asm-arm/xor.h --- linux.vanilla/include/asm-arm/xor.h Tue Apr 3 17:32:27 2001 +++ linux.ac/include/asm-arm/xor.h Sat Apr 14 01:38:20 2001 @@ -8,7 +8,289 @@ * published by the Free Software Foundation. */ +/* + * linux/include/asm-arm/xor.h + * + * Copyright (C) 2001 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. + */ + +/* + * linux/include/asm-arm/xor.h + * + * Copyright (C) 2001 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 <asm-generic/xor.h> + +#define __XOR(a1, a2) a1 ^= a2 + +#define GET_BLOCK_2(dst) \ + __asm__("ldmia %0, {%1, %2}" \ + : "=r" (dst), "=r" (a1), "=r" (a2) \ + : "0" (dst)) + +#define GET_BLOCK_4(dst) \ + __asm__("ldmia %0, {%1, %2, %3, %4}" \ + : "=r" (dst), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (a4) \ + : "0" (dst)) + +#define XOR_BLOCK_2(src) \ + __asm__("ldmia %0!, {%1, %2}" \ + : "=r" (src), "=r" (b1), "=r" (b2) \ + : "0" (src)); \ + __XOR(a1, b1); __XOR(a2, b2); + +#define XOR_BLOCK_4(src) \ + __asm__("ldmia %0!, {%1, %2, %3, %4}" \ + : "=r" (src), "=r" (b1), "=r" (b2), "=r" (b3), "=r" (b4) \ + : "0" (src)); \ + __XOR(a1, b1); __XOR(a2, b2); __XOR(a3, b3); __XOR(a4, b4) + +#define PUT_BLOCK_2(dst) \ + __asm__ __volatile__("stmia %0!, {%2, %3}" \ + : "=r" (dst) \ + : "0" (dst), "r" (a1), "r" (a2)) + +#define PUT_BLOCK_4(dst) \ + __asm__ __volatile__("stmia %0!, {%2, %3, %4, %5}" \ + : "=r" (dst) \ + : "0" (dst), "r" (a1), "r" (a2), "r" (a3), "r" (a4)) + +static void +xor_arm4regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 4; + register unsigned int a1 __asm__("r4"); + register unsigned int a2 __asm__("r5"); + register unsigned int a3 __asm__("r6"); + register unsigned int a4 __asm__("r7"); + register unsigned int b1 __asm__("r8"); + register unsigned int b2 __asm__("r9"); + register unsigned int b3 __asm__("ip"); + register unsigned int b4 __asm__("lr"); + + do { + GET_BLOCK_4(p1); + XOR_BLOCK_4(p2); + PUT_BLOCK_4(p1); + } while (--lines); +} + +static void +xor_arm4regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 4; + register unsigned int a1 __asm__("r4"); + register unsigned int a2 __asm__("r5"); + register unsigned int a3 __asm__("r6"); + register unsigned int a4 __asm__("r7"); + register unsigned int b1 __asm__("r8"); + register unsigned int b2 __asm__("r9"); + register unsigned int b3 __asm__("ip"); + register unsigned int b4 __asm__("lr"); + + do { + GET_BLOCK_4(p1); + XOR_BLOCK_4(p2); + XOR_BLOCK_4(p3); + PUT_BLOCK_4(p1); + } while (--lines); +} + +static void +xor_arm4regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 2; + register unsigned int a1 __asm__("r8"); + register unsigned int a2 __asm__("r9"); + register unsigned int b1 __asm__("ip"); + register unsigned int b2 __asm__("lr"); + + do { + GET_BLOCK_2(p1); + XOR_BLOCK_2(p2); + XOR_BLOCK_2(p3); + XOR_BLOCK_2(p4); + PUT_BLOCK_2(p1); + } while (--lines); +} + +static void +xor_arm4regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4, unsigned long *p5) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 2; + register unsigned int a1 __asm__("r8"); + register unsigned int a2 __asm__("r9"); + register unsigned int b1 __asm__("ip"); + register unsigned int b2 __asm__("lr"); + + do { + GET_BLOCK_2(p1); + XOR_BLOCK_2(p2); + XOR_BLOCK_2(p3); + XOR_BLOCK_2(p4); + XOR_BLOCK_2(p5); + PUT_BLOCK_2(p1); + } while (--lines); +} + +static struct xor_block_template xor_block_arm4regs = { + name: "arm4regs", + do_2: xor_arm4regs_2, + do_3: xor_arm4regs_3, + do_4: xor_arm4regs_4, + do_5: xor_arm4regs_5, +}; + +#undef XOR_TRY_TEMPLATES +#define XOR_TRY_TEMPLATES \ + do { \ + xor_speed(&xor_block_arm4regs); \ + xor_speed(&xor_block_8regs); \ + xor_speed(&xor_block_32regs); \ + } while (0) + +#define __XOR(a1, a2) a1 ^= a2 + +#define GET_BLOCK_2(dst) \ + __asm__("ldmia %0, {%1, %2}" \ + : "=r" (dst), "=r" (a1), "=r" (a2) \ + : "0" (dst)) + +#define GET_BLOCK_4(dst) \ + __asm__("ldmia %0, {%1, %2, %3, %4}" \ + : "=r" (dst), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (a4) \ + : "0" (dst)) + +#define XOR_BLOCK_2(src) \ + __asm__("ldmia %0!, {%1, %2}" \ + : "=r" (src), "=r" (b1), "=r" (b2) \ + : "0" (src)); \ + __XOR(a1, b1); __XOR(a2, b2); + +#define XOR_BLOCK_4(src) \ + __asm__("ldmia %0!, {%1, %2, %3, %4}" \ + : "=r" (src), "=r" (b1), "=r" (b2), "=r" (b3), "=r" (b4) \ + : "0" (src)); \ + __XOR(a1, b1); __XOR(a2, b2); __XOR(a3, b3); __XOR(a4, b4) + +#define PUT_BLOCK_2(dst) \ + __asm__ __volatile__("stmia %0!, {%2, %3}" \ + : "=r" (dst) \ + : "0" (dst), "r" (a1), "r" (a2)) + +#define PUT_BLOCK_4(dst) \ + __asm__ __volatile__("stmia %0!, {%2, %3, %4, %5}" \ + : "=r" (dst) \ + : "0" (dst), "r" (a1), "r" (a2), "r" (a3), "r" (a4)) + +static void +xor_arm4regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 4; + register unsigned int a1 __asm__("r4"); + register unsigned int a2 __asm__("r5"); + register unsigned int a3 __asm__("r6"); + register unsigned int a4 __asm__("r7"); + register unsigned int b1 __asm__("r8"); + register unsigned int b2 __asm__("r9"); + register unsigned int b3 __asm__("ip"); + register unsigned int b4 __asm__("lr"); + + do { + GET_BLOCK_4(p1); + XOR_BLOCK_4(p2); + PUT_BLOCK_4(p1); + } while (--lines); +} + +static void +xor_arm4regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 4; + register unsigned int a1 __asm__("r4"); + register unsigned int a2 __asm__("r5"); + register unsigned int a3 __asm__("r6"); + register unsigned int a4 __asm__("r7"); + register unsigned int b1 __asm__("r8"); + register unsigned int b2 __asm__("r9"); + register unsigned int b3 __asm__("ip"); + register unsigned int b4 __asm__("lr"); + + do { + GET_BLOCK_4(p1); + XOR_BLOCK_4(p2); + XOR_BLOCK_4(p3); + PUT_BLOCK_4(p1); + } while (--lines); +} + +static void +xor_arm4regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 2; + register unsigned int a1 __asm__("r8"); + register unsigned int a2 __asm__("r9"); + register unsigned int b1 __asm__("ip"); + register unsigned int b2 __asm__("lr"); + + do { + GET_BLOCK_2(p1); + XOR_BLOCK_2(p2); + XOR_BLOCK_2(p3); + XOR_BLOCK_2(p4); + PUT_BLOCK_2(p1); + } while (--lines); +} + +static void +xor_arm4regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4, unsigned long *p5) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 2; + register unsigned int a1 __asm__("r8"); + register unsigned int a2 __asm__("r9"); + register unsigned int b1 __asm__("ip"); + register unsigned int b2 __asm__("lr"); + + do { + GET_BLOCK_2(p1); + XOR_BLOCK_2(p2); + XOR_BLOCK_2(p3); + XOR_BLOCK_2(p4); + XOR_BLOCK_2(p5); + PUT_BLOCK_2(p1); + } while (--lines); +} + +static struct xor_block_template xor_block_arm4regs = { + name: "arm4regs", + do_2: xor_arm4regs_2, + do_3: xor_arm4regs_3, + do_4: xor_arm4regs_4, + do_5: xor_arm4regs_5, +}; + +#undef XOR_TRY_TEMPLATES +#define XOR_TRY_TEMPLATES \ + do { \ + xor_speed(&xor_block_arm4regs); \ + xor_speed(&xor_block_8regs); \ + xor_speed(&xor_block_32regs); \ + } while (0) #define __XOR(a1, a2) a1 ^= a2 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-cris/bitops.h linux.ac/include/asm-cris/bitops.h --- linux.vanilla/include/asm-cris/bitops.h Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-cris/bitops.h Tue Apr 10 18:20:15 2001 @@ -1,9 +1,12 @@ -/* $Id: bitops.h,v 1.3 2000/10/17 14:56:27 bjornw Exp $ */ +/* $Id: bitops.h,v 1.4 2001/02/28 04:26:11 hp Exp $ */ /* all of these should probably be rewritten in assembler for speed. */ #ifndef _CRIS_BITOPS_H #define _CRIS_BITOPS_H +/* Currently this is unsuitable for consumption outside the kernel. */ +#ifdef __KERNEL__ + #include <asm/system.h> /* @@ -163,8 +166,6 @@ #define find_first_zero_bit(addr, size) \ find_next_zero_bit((addr), (size), 0) - -#ifdef __KERNEL__ #define ext2_set_bit test_and_set_bit #define ext2_clear_bit test_and_clear_bit diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-cris/delay.h linux.ac/include/asm-cris/delay.h --- linux.vanilla/include/asm-cris/delay.h Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-cris/delay.h Tue Apr 10 18:20:15 2001 @@ -1,4 +1,4 @@ -/* $Id: delay.h,v 1.2 2000/08/08 16:36:41 bjornw Exp $ */ +/* $Id: delay.h,v 1.3 2001/02/23 13:47:33 bjornw Exp $ */ #ifndef _CRIS_DELAY_H #define _CRIS_DELAY_H diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-cris/eshlibld.h linux.ac/include/asm-cris/eshlibld.h --- linux.vanilla/include/asm-cris/eshlibld.h Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-cris/eshlibld.h Tue Apr 10 18:20:15 2001 @@ -12,7 +12,7 @@ *! (C) Copyright 1998, 1999 Axis Communications AB, LUND, SWEDEN *! *!**************************************************************************/ -/* $Id: eshlibld.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ */ +/* $Id: eshlibld.h,v 1.2 2001/02/23 13:47:33 bjornw Exp $ */ #ifndef _cris_relocate_h #define _cris_relocate_h diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-cris/etraxgpio.h linux.ac/include/asm-cris/etraxgpio.h --- linux.vanilla/include/asm-cris/etraxgpio.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-cris/etraxgpio.h Tue Apr 10 18:20:15 2001 @@ -0,0 +1,32 @@ +#ifndef _ASM_ETRAXGPIO_H +#define _ASM_ETRAXGPIO_H + +/* etraxgpio _IOC_TYPE, bits 8 to 15 in ioctl cmd */ + +#define ETRAXGPIO_IOCTYPE 43 + +/* supported ioctl _IOC_NR's */ + +#define IO_READBITS 0x1 /* read and return current port bits */ +#define IO_SETBITS 0x2 /* set the bits marked by 1 in the argument */ +#define IO_CLRBITS 0x3 /* clear the bits marked by 1 in the argument */ + +/* the alarm is waited for by select() */ + +#define IO_HIGHALARM 0x4 /* set alarm on high for bits marked by 1 */ +#define IO_LOWALARM 0x5 /* set alarm on low for bits marked by 1 */ +#define IO_CLRALARM 0x6 /* clear alarm for bits marked by 1 */ + +/* LED ioctl */ +#define IO_LEDACTIVE_SET 0x7 /* set active led + * 0=off, 1=green, 2=red, 3=yellow */ + +/* GPIO direction ioctl's */ +#define IO_READDIR 0x8 /* Read direction 0=input 1=output */ +#define IO_SETINPUT 0x9 /* Set direction 0=unchanged 1=input, + returns current dir */ +#define IO_SETOUTPUT 0xA /* Set direction 0=unchanged 1=output, + returns current dir */ + +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-cris/etraxi2c.h linux.ac/include/asm-cris/etraxi2c.h --- linux.vanilla/include/asm-cris/etraxi2c.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-cris/etraxi2c.h Tue Apr 10 18:20:15 2001 @@ -0,0 +1,36 @@ +/* $Id: etraxi2c.h,v 1.1 2001/01/18 15:49:57 bjornw Exp $ */ + +#ifndef _LINUX_ETRAXI2C_H +#define _LINUX_ETRAXI2C_H + +/* etraxi2c _IOC_TYPE, bits 8 to 15 in ioctl cmd */ + +#define ETRAXI2C_IOCTYPE 44 + +/* supported ioctl _IOC_NR's */ + +/* in write operations, the argument contains both i2c + * slave, register and value. + */ + +#define I2C_WRITEARG(slave, reg, value) (((slave) << 16) | ((reg) << 8) | (value)) +#define I2C_READARG(slave, reg) (((slave) << 16) | ((reg) << 8)) + +#define I2C_ARGSLAVE(arg) ((arg) >> 16) +#define I2C_ARGREG(arg) (((arg) >> 8) & 0xff) +#define I2C_ARGVALUE(arg) ((arg) & 0xff) + +#define I2C_WRITEREG 0x1 /* write to an i2c register */ +#define I2C_READREG 0x2 /* read from an i2c register */ + +/* +EXAMPLE usage: + + i2c_arg = I2C_WRITEARG(STA013_WRITE_ADDR, reg, val); + ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_WRITEREG), i2c_arg); + + i2c_arg = I2C_READARG(STA013_READ_ADDR, reg); + val = ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_READREG), i2c_arg); + +*/ +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-cris/io.h linux.ac/include/asm-cris/io.h --- linux.vanilla/include/asm-cris/io.h Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-cris/io.h Tue Apr 10 18:20:15 2001 @@ -9,9 +9,9 @@ use will be evident. */ #ifdef CONFIG_SVINTO_SIM /* Let's use the ucsim interface since it lets us do write(2, ...) */ -#define SIMCOUT(s,len) asm ("moveq 4,r1\n\tmoveq 2,r10\n\tmove.d %0,r11\n\tmove.d %1,r12\ +#define SIMCOUT(s,len) asm ("moveq 4,r9\n\tmoveq 2,r10\n\tmove.d %0,r11\n\tmove.d %1,r12\ \n\tpush irp\n\t.word 0xae3f\n\t.dword 0f\n\tjump -6809\n0:\n\tpop irp" \ - : : "rm" (s), "rm" (len) : "r1","r10","r11","r12","memory") + : : "rm" (s), "rm" (len) : "r9","r10","r11","r12","memory") #define TRACE_ON() __extension__ \ ({ int _Foofoo; __asm__ volatile ("bmod [%0],%0" : "=r" (_Foofoo) : "0" \ (255)); _Foofoo; }) @@ -127,6 +127,13 @@ static inline void * phys_to_virt(unsigned long address) { return __va(address); +} + +extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags); + +extern inline void * ioremap (unsigned long offset, unsigned long size) +{ + return __ioremap(offset, size, 0); } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-cris/irq.h linux.ac/include/asm-cris/irq.h --- linux.vanilla/include/asm-cris/irq.h Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-cris/irq.h Tue Apr 10 18:20:15 2001 @@ -19,7 +19,7 @@ #include <asm/sv_addr_ag.h> -#define NR_IRQS 26 /* TODO: what is this for Etrax100/LX ? */ +#define NR_IRQS 32 extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-cris/processor.h linux.ac/include/asm-cris/processor.h --- linux.vanilla/include/asm-cris/processor.h Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-cris/processor.h Tue Apr 10 18:20:15 2001 @@ -1,7 +1,7 @@ /* * include/asm-cris/processor.h * - * Copyright (C) 2000 Axis Communications AB + * Copyright (C) 2000, 2001 Axis Communications AB * * Authors: Bjorn Wesen Initial version * @@ -57,9 +57,6 @@ /* saved stack-frame upon syscall entry, points to registers */ #define current_regs() (current->thread.esp0) - -/* this lives in process.c */ -asmlinkage void set_esp0(unsigned long ssp); /* INIT_MMAP is the kernels map of memory, between KSEG_C and KSEG_D */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-cris/ptrace.h linux.ac/include/asm-cris/ptrace.h --- linux.vanilla/include/asm-cris/ptrace.h Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-cris/ptrace.h Tue Apr 10 18:20:15 2001 @@ -23,9 +23,8 @@ #define PT_DCCR 17 #define PT_SRP 18 #define PT_IRP 19 -#define PT_MAX 19 - -#define PT_USP 42 /* special case - USP is not in the pt_regs */ +#define PT_USP 20 /* special case - USP is not in the pt_regs */ +#define PT_MAX 20 /* Frame types */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-cris/socket.h linux.ac/include/asm-cris/socket.h --- linux.vanilla/include/asm-cris/socket.h Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-cris/socket.h Tue Apr 10 18:20:15 2001 @@ -45,6 +45,8 @@ #define SO_TIMESTAMP 29 #define SCM_TIMESTAMP SO_TIMESTAMP +#define SO_ACCEPTCONN 30 + #if defined(__KERNEL__) /* Socket types. */ #define SOCK_STREAM 1 /* stream (connection) socket */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-cris/sv_addr.agh linux.ac/include/asm-cris/sv_addr.agh --- linux.vanilla/include/asm-cris/sv_addr.agh Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-cris/sv_addr.agh Tue Apr 10 18:20:15 2001 @@ -1,8 +1,8 @@ /* !* This file was automatically generated by /n/asic/bin/reg_macro_gen -!* from the file `etrax_ng_regs.rd'. +!* from the file `/n/asic/projects/etrax_ng/doc/work/etrax_ng_regs.rd'. !* Editing within this file is thus not recommended, -!* make the changes in `etrax_ng_regs.rd' instead. +!* make the changes in `/n/asic/projects/etrax_ng/doc/work/etrax_ng_regs.rd' instead. !*/ @@ -103,6 +103,10 @@ #define R_BUS_STATUS__flashw__bw16 0 #define R_DRAM_TIMING (IO_TYPECAST_UDWORD 0xb0000008) +#define R_DRAM_TIMING__sdram__BITNR 31 +#define R_DRAM_TIMING__sdram__WIDTH 1 +#define R_DRAM_TIMING__sdram__enable 1 +#define R_DRAM_TIMING__sdram__disable 0 #define R_DRAM_TIMING__ref__BITNR 14 #define R_DRAM_TIMING__ref__WIDTH 2 #define R_DRAM_TIMING__ref__e52us 0 @@ -683,10 +687,6 @@ #define R_GEN_CONFIG__usb1__WIDTH 1 #define R_GEN_CONFIG__usb1__select 1 #define R_GEN_CONFIG__usb1__disable 0 -#define R_GEN_CONFIG__p21__BITNR 28 -#define R_GEN_CONFIG__p21__WIDTH 1 -#define R_GEN_CONFIG__p21__select 1 -#define R_GEN_CONFIG__p21__disable 0 #define R_GEN_CONFIG__g24dir__BITNR 27 #define R_GEN_CONFIG__g24dir__WIDTH 1 #define R_GEN_CONFIG__g24dir__in 0 @@ -2331,6 +2331,10 @@ #define R_NETWORK_GA_1__ga_high__WIDTH 32 #define R_NETWORK_REC_CONFIG (IO_TYPECAST_UDWORD 0xb0000094) +#define R_NETWORK_REC_CONFIG__max_size__BITNR 10 +#define R_NETWORK_REC_CONFIG__max_size__WIDTH 1 +#define R_NETWORK_REC_CONFIG__max_size__size1518 0 +#define R_NETWORK_REC_CONFIG__max_size__size1522 1 #define R_NETWORK_REC_CONFIG__duplex__BITNR 9 #define R_NETWORK_REC_CONFIG__duplex__WIDTH 1 #define R_NETWORK_REC_CONFIG__duplex__full 1 @@ -2535,6 +2539,10 @@ #define R_PAR0_STATUS_DATA__mode__ecp_fwd 5 #define R_PAR0_STATUS_DATA__mode__ecp_rev 6 #define R_PAR0_STATUS_DATA__mode__off 7 +#define R_PAR0_STATUS_DATA__mode__epp_wr1 5 +#define R_PAR0_STATUS_DATA__mode__epp_wr2 6 +#define R_PAR0_STATUS_DATA__mode__epp_wr3 7 +#define R_PAR0_STATUS_DATA__mode__epp_rd 0 #define R_PAR0_STATUS_DATA__perr__BITNR 28 #define R_PAR0_STATUS_DATA__perr__WIDTH 1 #define R_PAR0_STATUS_DATA__perr__active 1 @@ -2555,6 +2563,14 @@ #define R_PAR0_STATUS_DATA__sel__WIDTH 1 #define R_PAR0_STATUS_DATA__sel__active 1 #define R_PAR0_STATUS_DATA__sel__inactive 0 +#define R_PAR0_STATUS_DATA__ext_mode__BITNR 23 +#define R_PAR0_STATUS_DATA__ext_mode__WIDTH 1 +#define R_PAR0_STATUS_DATA__ext_mode__enable 1 +#define R_PAR0_STATUS_DATA__ext_mode__disable 0 +#define R_PAR0_STATUS_DATA__ecp_16__BITNR 22 +#define R_PAR0_STATUS_DATA__ecp_16__WIDTH 1 +#define R_PAR0_STATUS_DATA__ecp_16__active 1 +#define R_PAR0_STATUS_DATA__ecp_16__inactive 0 #define R_PAR0_STATUS_DATA__tr_rdy__BITNR 17 #define R_PAR0_STATUS_DATA__tr_rdy__WIDTH 1 #define R_PAR0_STATUS_DATA__tr_rdy__ready 1 @@ -2570,7 +2586,59 @@ #define R_PAR0_STATUS_DATA__data__BITNR 0 #define R_PAR0_STATUS_DATA__data__WIDTH 8 -#define R_PAR_ECP16_DATA (IO_TYPECAST_RO_UWORD 0xb0000040) +#define R_PAR0_STATUS (IO_TYPECAST_RO_UWORD 0xb0000042) +#define R_PAR0_STATUS__mode__BITNR 13 +#define R_PAR0_STATUS__mode__WIDTH 3 +#define R_PAR0_STATUS__mode__manual 0 +#define R_PAR0_STATUS__mode__centronics 1 +#define R_PAR0_STATUS__mode__fastbyte 2 +#define R_PAR0_STATUS__mode__nibble 3 +#define R_PAR0_STATUS__mode__byte 4 +#define R_PAR0_STATUS__mode__ecp_fwd 5 +#define R_PAR0_STATUS__mode__ecp_rev 6 +#define R_PAR0_STATUS__mode__off 7 +#define R_PAR0_STATUS__mode__epp_wr1 5 +#define R_PAR0_STATUS__mode__epp_wr2 6 +#define R_PAR0_STATUS__mode__epp_wr3 7 +#define R_PAR0_STATUS__mode__epp_rd 0 +#define R_PAR0_STATUS__perr__BITNR 12 +#define R_PAR0_STATUS__perr__WIDTH 1 +#define R_PAR0_STATUS__perr__active 1 +#define R_PAR0_STATUS__perr__inactive 0 +#define R_PAR0_STATUS__ack__BITNR 11 +#define R_PAR0_STATUS__ack__WIDTH 1 +#define R_PAR0_STATUS__ack__active 0 +#define R_PAR0_STATUS__ack__inactive 1 +#define R_PAR0_STATUS__busy__BITNR 10 +#define R_PAR0_STATUS__busy__WIDTH 1 +#define R_PAR0_STATUS__busy__active 1 +#define R_PAR0_STATUS__busy__inactive 0 +#define R_PAR0_STATUS__fault__BITNR 9 +#define R_PAR0_STATUS__fault__WIDTH 1 +#define R_PAR0_STATUS__fault__active 0 +#define R_PAR0_STATUS__fault__inactive 1 +#define R_PAR0_STATUS__sel__BITNR 8 +#define R_PAR0_STATUS__sel__WIDTH 1 +#define R_PAR0_STATUS__sel__active 1 +#define R_PAR0_STATUS__sel__inactive 0 +#define R_PAR0_STATUS__ext_mode__BITNR 7 +#define R_PAR0_STATUS__ext_mode__WIDTH 1 +#define R_PAR0_STATUS__ext_mode__enable 1 +#define R_PAR0_STATUS__ext_mode__disable 0 +#define R_PAR0_STATUS__ecp_16__BITNR 6 +#define R_PAR0_STATUS__ecp_16__WIDTH 1 +#define R_PAR0_STATUS__ecp_16__active 1 +#define R_PAR0_STATUS__ecp_16__inactive 0 +#define R_PAR0_STATUS__tr_rdy__BITNR 1 +#define R_PAR0_STATUS__tr_rdy__WIDTH 1 +#define R_PAR0_STATUS__tr_rdy__ready 1 +#define R_PAR0_STATUS__tr_rdy__busy 0 +#define R_PAR0_STATUS__dav__BITNR 0 +#define R_PAR0_STATUS__dav__WIDTH 1 +#define R_PAR0_STATUS__dav__data 1 +#define R_PAR0_STATUS__dav__nodata 0 + +#define R_PAR_ECP16_DATA (IO_TYPECAST_UWORD 0xb0000040) #define R_PAR_ECP16_DATA__data__BITNR 0 #define R_PAR_ECP16_DATA__data__WIDTH 16 @@ -2669,6 +2737,10 @@ #define R_PAR0_CONFIG__mode__ecp_fwd 5 #define R_PAR0_CONFIG__mode__ecp_rev 6 #define R_PAR0_CONFIG__mode__off 7 +#define R_PAR0_CONFIG__mode__epp_wr1 5 +#define R_PAR0_CONFIG__mode__epp_wr2 6 +#define R_PAR0_CONFIG__mode__epp_wr3 7 +#define R_PAR0_CONFIG__mode__epp_rd 0 #define R_PAR0_DELAY (IO_TYPECAST_UDWORD 0xb0000048) #define R_PAR0_DELAY__fine_hold__BITNR 21 @@ -2731,6 +2803,10 @@ #define R_PAR1_STATUS_DATA__mode__ecp_fwd 5 #define R_PAR1_STATUS_DATA__mode__ecp_rev 6 #define R_PAR1_STATUS_DATA__mode__off 7 +#define R_PAR1_STATUS_DATA__mode__epp_wr1 5 +#define R_PAR1_STATUS_DATA__mode__epp_wr2 6 +#define R_PAR1_STATUS_DATA__mode__epp_wr3 7 +#define R_PAR1_STATUS_DATA__mode__epp_rd 0 #define R_PAR1_STATUS_DATA__perr__BITNR 28 #define R_PAR1_STATUS_DATA__perr__WIDTH 1 #define R_PAR1_STATUS_DATA__perr__active 1 @@ -2751,6 +2827,10 @@ #define R_PAR1_STATUS_DATA__sel__WIDTH 1 #define R_PAR1_STATUS_DATA__sel__active 1 #define R_PAR1_STATUS_DATA__sel__inactive 0 +#define R_PAR1_STATUS_DATA__ext_mode__BITNR 23 +#define R_PAR1_STATUS_DATA__ext_mode__WIDTH 1 +#define R_PAR1_STATUS_DATA__ext_mode__enable 1 +#define R_PAR1_STATUS_DATA__ext_mode__disable 0 #define R_PAR1_STATUS_DATA__tr_rdy__BITNR 17 #define R_PAR1_STATUS_DATA__tr_rdy__WIDTH 1 #define R_PAR1_STATUS_DATA__tr_rdy__ready 1 @@ -2766,6 +2846,54 @@ #define R_PAR1_STATUS_DATA__data__BITNR 0 #define R_PAR1_STATUS_DATA__data__WIDTH 8 +#define R_PAR1_STATUS (IO_TYPECAST_RO_UWORD 0xb0000052) +#define R_PAR1_STATUS__mode__BITNR 13 +#define R_PAR1_STATUS__mode__WIDTH 3 +#define R_PAR1_STATUS__mode__manual 0 +#define R_PAR1_STATUS__mode__centronics 1 +#define R_PAR1_STATUS__mode__fastbyte 2 +#define R_PAR1_STATUS__mode__nibble 3 +#define R_PAR1_STATUS__mode__byte 4 +#define R_PAR1_STATUS__mode__ecp_fwd 5 +#define R_PAR1_STATUS__mode__ecp_rev 6 +#define R_PAR1_STATUS__mode__off 7 +#define R_PAR1_STATUS__mode__epp_wr1 5 +#define R_PAR1_STATUS__mode__epp_wr2 6 +#define R_PAR1_STATUS__mode__epp_wr3 7 +#define R_PAR1_STATUS__mode__epp_rd 0 +#define R_PAR1_STATUS__perr__BITNR 12 +#define R_PAR1_STATUS__perr__WIDTH 1 +#define R_PAR1_STATUS__perr__active 1 +#define R_PAR1_STATUS__perr__inactive 0 +#define R_PAR1_STATUS__ack__BITNR 11 +#define R_PAR1_STATUS__ack__WIDTH 1 +#define R_PAR1_STATUS__ack__active 0 +#define R_PAR1_STATUS__ack__inactive 1 +#define R_PAR1_STATUS__busy__BITNR 10 +#define R_PAR1_STATUS__busy__WIDTH 1 +#define R_PAR1_STATUS__busy__active 1 +#define R_PAR1_STATUS__busy__inactive 0 +#define R_PAR1_STATUS__fault__BITNR 9 +#define R_PAR1_STATUS__fault__WIDTH 1 +#define R_PAR1_STATUS__fault__active 0 +#define R_PAR1_STATUS__fault__inactive 1 +#define R_PAR1_STATUS__sel__BITNR 8 +#define R_PAR1_STATUS__sel__WIDTH 1 +#define R_PAR1_STATUS__sel__active 1 +#define R_PAR1_STATUS__sel__inactive 0 +#define R_PAR1_STATUS__ext_mode__BITNR 7 +#define R_PAR1_STATUS__ext_mode__WIDTH 1 +#define R_PAR1_STATUS__ext_mode__enable 1 +#define R_PAR1_STATUS__ext_mode__disable 0 +#define R_PAR1_STATUS__tr_rdy__BITNR 1 +#define R_PAR1_STATUS__tr_rdy__WIDTH 1 +#define R_PAR1_STATUS__tr_rdy__ready 1 +#define R_PAR1_STATUS__tr_rdy__busy 0 +#define R_PAR1_STATUS__dav__BITNR 0 +#define R_PAR1_STATUS__dav__WIDTH 1 +#define R_PAR1_STATUS__dav__data 1 +#define R_PAR1_STATUS__dav__nodata 0 + #define R_PAR1_CONFIG (IO_TYPECAST_UDWORD 0xb0000054) #define R_PAR1_CONFIG__ioe__BITNR 25 #define R_PAR1_CONFIG__ioe__WIDTH 1 @@ -2857,6 +2985,10 @@ #define R_PAR1_CONFIG__mode__ecp_fwd 5 #define R_PAR1_CONFIG__mode__ecp_rev 6 #define R_PAR1_CONFIG__mode__off 7 +#define R_PAR1_CONFIG__mode__epp_wr1 5 +#define R_PAR1_CONFIG__mode__epp_wr2 6 +#define R_PAR1_CONFIG__mode__epp_wr3 7 +#define R_PAR1_CONFIG__mode__epp_rd 0 #define R_PAR1_DELAY (IO_TYPECAST_UDWORD 0xb0000058) #define R_PAR1_DELAY__fine_hold__BITNR 21 @@ -3437,10 +3569,6 @@ #define R_IRQ_MASK0_RD__ata_irq2__WIDTH 1 #define R_IRQ_MASK0_RD__ata_irq2__active 1 #define R_IRQ_MASK0_RD__ata_irq2__inactive 0 -#define R_IRQ_MASK0_RD__p21_irq2__BITNR 10 -#define R_IRQ_MASK0_RD__p21_irq2__WIDTH 1 -#define R_IRQ_MASK0_RD__p21_irq2__active 1 -#define R_IRQ_MASK0_RD__p21_irq2__inactive 0 #define R_IRQ_MASK0_RD__par0_data__BITNR 9 #define R_IRQ_MASK0_RD__par0_data__WIDTH 1 #define R_IRQ_MASK0_RD__par0_data__active 1 @@ -3449,10 +3577,6 @@ #define R_IRQ_MASK0_RD__ata_irq1__WIDTH 1 #define R_IRQ_MASK0_RD__ata_irq1__active 1 #define R_IRQ_MASK0_RD__ata_irq1__inactive 0 -#define R_IRQ_MASK0_RD__p21_irq1__BITNR 9 -#define R_IRQ_MASK0_RD__p21_irq1__WIDTH 1 -#define R_IRQ_MASK0_RD__p21_irq1__active 1 -#define R_IRQ_MASK0_RD__p21_irq1__inactive 0 #define R_IRQ_MASK0_RD__par0_ready__BITNR 8 #define R_IRQ_MASK0_RD__par0_ready__WIDTH 1 #define R_IRQ_MASK0_RD__par0_ready__active 1 @@ -3469,10 +3593,6 @@ #define R_IRQ_MASK0_RD__scsi0__WIDTH 1 #define R_IRQ_MASK0_RD__scsi0__active 1 #define R_IRQ_MASK0_RD__scsi0__inactive 0 -#define R_IRQ_MASK0_RD__p21_irq0__BITNR 8 -#define R_IRQ_MASK0_RD__p21_irq0__WIDTH 1 -#define R_IRQ_MASK0_RD__p21_irq0__active 1 -#define R_IRQ_MASK0_RD__p21_irq0__inactive 0 #define R_IRQ_MASK0_RD__ata_dmaend__BITNR 7 #define R_IRQ_MASK0_RD__ata_dmaend__WIDTH 1 #define R_IRQ_MASK0_RD__ata_dmaend__active 1 @@ -3599,10 +3719,6 @@ #define R_IRQ_MASK0_CLR__ata_irq2__WIDTH 1 #define R_IRQ_MASK0_CLR__ata_irq2__clr 1 #define R_IRQ_MASK0_CLR__ata_irq2__nop 0 -#define R_IRQ_MASK0_CLR__p21_irq2__BITNR 10 -#define R_IRQ_MASK0_CLR__p21_irq2__WIDTH 1 -#define R_IRQ_MASK0_CLR__p21_irq2__clr 1 -#define R_IRQ_MASK0_CLR__p21_irq2__nop 0 #define R_IRQ_MASK0_CLR__par0_data__BITNR 9 #define R_IRQ_MASK0_CLR__par0_data__WIDTH 1 #define R_IRQ_MASK0_CLR__par0_data__clr 1 @@ -3611,10 +3727,6 @@ #define R_IRQ_MASK0_CLR__ata_irq1__WIDTH 1 #define R_IRQ_MASK0_CLR__ata_irq1__clr 1 #define R_IRQ_MASK0_CLR__ata_irq1__nop 0 -#define R_IRQ_MASK0_CLR__p21_irq1__BITNR 9 -#define R_IRQ_MASK0_CLR__p21_irq1__WIDTH 1 -#define R_IRQ_MASK0_CLR__p21_irq1__clr 1 -#define R_IRQ_MASK0_CLR__p21_irq1__nop 0 #define R_IRQ_MASK0_CLR__par0_ready__BITNR 8 #define R_IRQ_MASK0_CLR__par0_ready__WIDTH 1 #define R_IRQ_MASK0_CLR__par0_ready__clr 1 @@ -3631,10 +3743,6 @@ #define R_IRQ_MASK0_CLR__scsi0__WIDTH 1 #define R_IRQ_MASK0_CLR__scsi0__clr 1 #define R_IRQ_MASK0_CLR__scsi0__nop 0 -#define R_IRQ_MASK0_CLR__p21_irq0__BITNR 8 -#define R_IRQ_MASK0_CLR__p21_irq0__WIDTH 1 -#define R_IRQ_MASK0_CLR__p21_irq0__clr 1 -#define R_IRQ_MASK0_CLR__p21_irq0__nop 0 #define R_IRQ_MASK0_CLR__ata_dmaend__BITNR 7 #define R_IRQ_MASK0_CLR__ata_dmaend__WIDTH 1 #define R_IRQ_MASK0_CLR__ata_dmaend__clr 1 @@ -3761,10 +3869,6 @@ #define R_IRQ_READ0__ata_irq2__WIDTH 1 #define R_IRQ_READ0__ata_irq2__active 1 #define R_IRQ_READ0__ata_irq2__inactive 0 -#define R_IRQ_READ0__p21_irq2__BITNR 10 -#define R_IRQ_READ0__p21_irq2__WIDTH 1 -#define R_IRQ_READ0__p21_irq2__active 1 -#define R_IRQ_READ0__p21_irq2__inactive 0 #define R_IRQ_READ0__par0_data__BITNR 9 #define R_IRQ_READ0__par0_data__WIDTH 1 #define R_IRQ_READ0__par0_data__active 1 @@ -3773,10 +3877,6 @@ #define R_IRQ_READ0__ata_irq1__WIDTH 1 #define R_IRQ_READ0__ata_irq1__active 1 #define R_IRQ_READ0__ata_irq1__inactive 0 -#define R_IRQ_READ0__p21_irq1__BITNR 9 -#define R_IRQ_READ0__p21_irq1__WIDTH 1 -#define R_IRQ_READ0__p21_irq1__active 1 -#define R_IRQ_READ0__p21_irq1__inactive 0 #define R_IRQ_READ0__par0_ready__BITNR 8 #define R_IRQ_READ0__par0_ready__WIDTH 1 #define R_IRQ_READ0__par0_ready__active 1 @@ -3793,10 +3893,6 @@ #define R_IRQ_READ0__scsi0__WIDTH 1 #define R_IRQ_READ0__scsi0__active 1 #define R_IRQ_READ0__scsi0__inactive 0 -#define R_IRQ_READ0__p21_irq0__BITNR 8 -#define R_IRQ_READ0__p21_irq0__WIDTH 1 -#define R_IRQ_READ0__p21_irq0__active 1 -#define R_IRQ_READ0__p21_irq0__inactive 0 #define R_IRQ_READ0__ata_dmaend__BITNR 7 #define R_IRQ_READ0__ata_dmaend__WIDTH 1 #define R_IRQ_READ0__ata_dmaend__active 1 @@ -3923,10 +4019,6 @@ #define R_IRQ_MASK0_SET__ata_irq2__WIDTH 1 #define R_IRQ_MASK0_SET__ata_irq2__set 1 #define R_IRQ_MASK0_SET__ata_irq2__nop 0 -#define R_IRQ_MASK0_SET__p21_irq2__BITNR 10 -#define R_IRQ_MASK0_SET__p21_irq2__WIDTH 1 -#define R_IRQ_MASK0_SET__p21_irq2__set 1 -#define R_IRQ_MASK0_SET__p21_irq2__nop 0 #define R_IRQ_MASK0_SET__par0_data__BITNR 9 #define R_IRQ_MASK0_SET__par0_data__WIDTH 1 #define R_IRQ_MASK0_SET__par0_data__set 1 @@ -3935,10 +4027,6 @@ #define R_IRQ_MASK0_SET__ata_irq1__WIDTH 1 #define R_IRQ_MASK0_SET__ata_irq1__set 1 #define R_IRQ_MASK0_SET__ata_irq1__nop 0 -#define R_IRQ_MASK0_SET__p21_irq1__BITNR 9 -#define R_IRQ_MASK0_SET__p21_irq1__WIDTH 1 -#define R_IRQ_MASK0_SET__p21_irq1__set 1 -#define R_IRQ_MASK0_SET__p21_irq1__nop 0 #define R_IRQ_MASK0_SET__par0_ready__BITNR 8 #define R_IRQ_MASK0_SET__par0_ready__WIDTH 1 #define R_IRQ_MASK0_SET__par0_ready__set 1 @@ -3955,10 +4043,6 @@ #define R_IRQ_MASK0_SET__scsi0__WIDTH 1 #define R_IRQ_MASK0_SET__scsi0__set 1 #define R_IRQ_MASK0_SET__scsi0__nop 0 -#define R_IRQ_MASK0_SET__p21_irq0__BITNR 8 -#define R_IRQ_MASK0_SET__p21_irq0__WIDTH 1 -#define R_IRQ_MASK0_SET__p21_irq0__set 1 -#define R_IRQ_MASK0_SET__p21_irq0__nop 0 #define R_IRQ_MASK0_SET__ata_dmaend__BITNR 7 #define R_IRQ_MASK0_SET__ata_dmaend__WIDTH 1 #define R_IRQ_MASK0_SET__ata_dmaend__set 1 @@ -4953,10 +5037,6 @@ #define R_VECT_MASK_RD__mio__WIDTH 1 #define R_VECT_MASK_RD__mio__active 1 #define R_VECT_MASK_RD__mio__inactive 0 -#define R_VECT_MASK_RD__p21__BITNR 4 -#define R_VECT_MASK_RD__p21__WIDTH 1 -#define R_VECT_MASK_RD__p21__active 1 -#define R_VECT_MASK_RD__p21__inactive 0 #define R_VECT_MASK_RD__timer1__BITNR 3 #define R_VECT_MASK_RD__timer1__WIDTH 1 #define R_VECT_MASK_RD__timer1__active 1 @@ -5075,10 +5155,6 @@ #define R_VECT_MASK_CLR__mio__WIDTH 1 #define R_VECT_MASK_CLR__mio__clr 1 #define R_VECT_MASK_CLR__mio__nop 0 -#define R_VECT_MASK_CLR__p21__BITNR 4 -#define R_VECT_MASK_CLR__p21__WIDTH 1 -#define R_VECT_MASK_CLR__p21__clr 1 -#define R_VECT_MASK_CLR__p21__nop 0 #define R_VECT_MASK_CLR__timer1__BITNR 3 #define R_VECT_MASK_CLR__timer1__WIDTH 1 #define R_VECT_MASK_CLR__timer1__clr 1 @@ -5197,10 +5273,6 @@ #define R_VECT_READ__mio__WIDTH 1 #define R_VECT_READ__mio__active 1 #define R_VECT_READ__mio__inactive 0 -#define R_VECT_READ__p21__BITNR 4 -#define R_VECT_READ__p21__WIDTH 1 -#define R_VECT_READ__p21__active 1 -#define R_VECT_READ__p21__inactive 0 #define R_VECT_READ__timer1__BITNR 3 #define R_VECT_READ__timer1__WIDTH 1 #define R_VECT_READ__timer1__active 1 @@ -5319,10 +5391,6 @@ #define R_VECT_MASK_SET__mio__WIDTH 1 #define R_VECT_MASK_SET__mio__set 1 #define R_VECT_MASK_SET__mio__nop 0 -#define R_VECT_MASK_SET__p21__BITNR 4 -#define R_VECT_MASK_SET__p21__WIDTH 1 -#define R_VECT_MASK_SET__p21__set 1 -#define R_VECT_MASK_SET__p21__nop 0 #define R_VECT_MASK_SET__timer1__BITNR 3 #define R_VECT_MASK_SET__timer1__WIDTH 1 #define R_VECT_MASK_SET__timer1__set 1 @@ -5997,6 +6065,10 @@ #define R_USB_COMMAND__port_cmd__disable 1 #define R_USB_COMMAND__port_cmd__suspend 2 #define R_USB_COMMAND__port_cmd__resume 3 +#define R_USB_COMMAND__busy__BITNR 3 +#define R_USB_COMMAND__busy__WIDTH 1 +#define R_USB_COMMAND__busy__no 0 +#define R_USB_COMMAND__busy__yes 1 #define R_USB_COMMAND__ctrl_cmd__BITNR 0 #define R_USB_COMMAND__ctrl_cmd__WIDTH 3 #define R_USB_COMMAND__ctrl_cmd__nop 0 @@ -6004,15 +6076,47 @@ #define R_USB_COMMAND__ctrl_cmd__deconfig 2 #define R_USB_COMMAND__ctrl_cmd__host_config 3 #define R_USB_COMMAND__ctrl_cmd__dev_config 4 -#define R_USB_COMMAND__ctrl_cmd__host_reset 5 +#define R_USB_COMMAND__ctrl_cmd__host_nop 5 #define R_USB_COMMAND__ctrl_cmd__host_run 6 #define R_USB_COMMAND__ctrl_cmd__host_stop 7 +#define R_USB_COMMAND_DEV (IO_TYPECAST_BYTE 0xb0000201) +#define R_USB_COMMAND_DEV__port_sel__BITNR 6 +#define R_USB_COMMAND_DEV__port_sel__WIDTH 2 +#define R_USB_COMMAND_DEV__port_sel__nop 0 +#define R_USB_COMMAND_DEV__port_sel__dummy1 1 +#define R_USB_COMMAND_DEV__port_sel__dummy2 2 +#define R_USB_COMMAND_DEV__port_sel__any 3 +#define R_USB_COMMAND_DEV__port_cmd__BITNR 4 +#define R_USB_COMMAND_DEV__port_cmd__WIDTH 2 +#define R_USB_COMMAND_DEV__port_cmd__active 0 +#define R_USB_COMMAND_DEV__port_cmd__passive 1 +#define R_USB_COMMAND_DEV__port_cmd__nop 2 +#define R_USB_COMMAND_DEV__port_cmd__wakeup 3 +#define R_USB_COMMAND_DEV__busy__BITNR 3 +#define R_USB_COMMAND_DEV__busy__WIDTH 1 +#define R_USB_COMMAND_DEV__busy__no 0 +#define R_USB_COMMAND_DEV__busy__yes 1 +#define R_USB_COMMAND_DEV__ctrl_cmd__BITNR 0 +#define R_USB_COMMAND_DEV__ctrl_cmd__WIDTH 3 +#define R_USB_COMMAND_DEV__ctrl_cmd__nop 0 +#define R_USB_COMMAND_DEV__ctrl_cmd__reset 1 +#define R_USB_COMMAND_DEV__ctrl_cmd__deconfig 2 +#define R_USB_COMMAND_DEV__ctrl_cmd__host_config 3 +#define R_USB_COMMAND_DEV__ctrl_cmd__dev_config 4 +#define R_USB_COMMAND_DEV__ctrl_cmd__dev_active 5 +#define R_USB_COMMAND_DEV__ctrl_cmd__dev_passive 6 +#define R_USB_COMMAND_DEV__ctrl_cmd__dev_nop 7 + #define R_USB_STATUS (IO_TYPECAST_RO_BYTE 0xb0000202) -#define R_USB_STATUS__busy__BITNR 7 -#define R_USB_STATUS__busy__WIDTH 1 -#define R_USB_STATUS__busy__no 0 -#define R_USB_STATUS__busy__yes 1 +#define R_USB_STATUS__ourun__BITNR 5 +#define R_USB_STATUS__ourun__WIDTH 1 +#define R_USB_STATUS__ourun__no 0 +#define R_USB_STATUS__ourun__yes 1 +#define R_USB_STATUS__perror__BITNR 4 +#define R_USB_STATUS__perror__WIDTH 1 +#define R_USB_STATUS__perror__no 0 +#define R_USB_STATUS__perror__yes 1 #define R_USB_STATUS__device_mode__BITNR 3 #define R_USB_STATUS__device_mode__WIDTH 1 #define R_USB_STATUS__device_mode__no 0 @@ -6031,30 +6135,34 @@ #define R_USB_STATUS__running__yes 1 #define R_USB_IRQ_MASK_SET (IO_TYPECAST_UWORD 0xb0000204) -#define R_USB_IRQ_MASK_SET__intr_eof__BITNR 13 -#define R_USB_IRQ_MASK_SET__intr_eof__WIDTH 1 -#define R_USB_IRQ_MASK_SET__intr_eof__nop 0 -#define R_USB_IRQ_MASK_SET__intr_eof__set 1 -#define R_USB_IRQ_MASK_SET__iso_eof__BITNR 12 +#define R_USB_IRQ_MASK_SET__iso_eof__BITNR 13 #define R_USB_IRQ_MASK_SET__iso_eof__WIDTH 1 #define R_USB_IRQ_MASK_SET__iso_eof__nop 0 #define R_USB_IRQ_MASK_SET__iso_eof__set 1 -#define R_USB_IRQ_MASK_SET__bulk_eot__BITNR 11 -#define R_USB_IRQ_MASK_SET__bulk_eot__WIDTH 1 -#define R_USB_IRQ_MASK_SET__bulk_eot__nop 0 -#define R_USB_IRQ_MASK_SET__bulk_eot__set 1 -#define R_USB_IRQ_MASK_SET__ctl_eot__BITNR 10 -#define R_USB_IRQ_MASK_SET__ctl_eot__WIDTH 1 -#define R_USB_IRQ_MASK_SET__ctl_eot__nop 0 -#define R_USB_IRQ_MASK_SET__ctl_eot__set 1 -#define R_USB_IRQ_MASK_SET__intr_eot__BITNR 9 -#define R_USB_IRQ_MASK_SET__intr_eot__WIDTH 1 -#define R_USB_IRQ_MASK_SET__intr_eot__nop 0 -#define R_USB_IRQ_MASK_SET__intr_eot__set 1 -#define R_USB_IRQ_MASK_SET__iso_eot__BITNR 8 +#define R_USB_IRQ_MASK_SET__intr_eof__BITNR 12 +#define R_USB_IRQ_MASK_SET__intr_eof__WIDTH 1 +#define R_USB_IRQ_MASK_SET__intr_eof__nop 0 +#define R_USB_IRQ_MASK_SET__intr_eof__set 1 +#define R_USB_IRQ_MASK_SET__iso_eot__BITNR 11 #define R_USB_IRQ_MASK_SET__iso_eot__WIDTH 1 #define R_USB_IRQ_MASK_SET__iso_eot__nop 0 #define R_USB_IRQ_MASK_SET__iso_eot__set 1 +#define R_USB_IRQ_MASK_SET__intr_eot__BITNR 10 +#define R_USB_IRQ_MASK_SET__intr_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET__intr_eot__nop 0 +#define R_USB_IRQ_MASK_SET__intr_eot__set 1 +#define R_USB_IRQ_MASK_SET__ctl_eot__BITNR 9 +#define R_USB_IRQ_MASK_SET__ctl_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET__ctl_eot__nop 0 +#define R_USB_IRQ_MASK_SET__ctl_eot__set 1 +#define R_USB_IRQ_MASK_SET__bulk_eot__BITNR 8 +#define R_USB_IRQ_MASK_SET__bulk_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET__bulk_eot__nop 0 +#define R_USB_IRQ_MASK_SET__bulk_eot__set 1 +#define R_USB_IRQ_MASK_SET__epid_attn__BITNR 3 +#define R_USB_IRQ_MASK_SET__epid_attn__WIDTH 1 +#define R_USB_IRQ_MASK_SET__epid_attn__nop 0 +#define R_USB_IRQ_MASK_SET__epid_attn__set 1 #define R_USB_IRQ_MASK_SET__sof__BITNR 2 #define R_USB_IRQ_MASK_SET__sof__WIDTH 1 #define R_USB_IRQ_MASK_SET__sof__nop 0 @@ -6069,30 +6177,34 @@ #define R_USB_IRQ_MASK_SET__ctl_status__set 1 #define R_USB_IRQ_MASK_READ (IO_TYPECAST_RO_UWORD 0xb0000204) -#define R_USB_IRQ_MASK_READ__intr_eof__BITNR 13 -#define R_USB_IRQ_MASK_READ__intr_eof__WIDTH 1 -#define R_USB_IRQ_MASK_READ__intr_eof__no_pend 0 -#define R_USB_IRQ_MASK_READ__intr_eof__pend 1 -#define R_USB_IRQ_MASK_READ__iso_eof__BITNR 12 +#define R_USB_IRQ_MASK_READ__iso_eof__BITNR 13 #define R_USB_IRQ_MASK_READ__iso_eof__WIDTH 1 #define R_USB_IRQ_MASK_READ__iso_eof__no_pend 0 #define R_USB_IRQ_MASK_READ__iso_eof__pend 1 -#define R_USB_IRQ_MASK_READ__bulk_eot__BITNR 11 -#define R_USB_IRQ_MASK_READ__bulk_eot__WIDTH 1 -#define R_USB_IRQ_MASK_READ__bulk_eot__no_pend 0 -#define R_USB_IRQ_MASK_READ__bulk_eot__pend 1 -#define R_USB_IRQ_MASK_READ__ctl_eot__BITNR 10 -#define R_USB_IRQ_MASK_READ__ctl_eot__WIDTH 1 -#define R_USB_IRQ_MASK_READ__ctl_eot__no_pend 0 -#define R_USB_IRQ_MASK_READ__ctl_eot__pend 1 -#define R_USB_IRQ_MASK_READ__intr_eot__BITNR 9 -#define R_USB_IRQ_MASK_READ__intr_eot__WIDTH 1 -#define R_USB_IRQ_MASK_READ__intr_eot__no_pend 0 -#define R_USB_IRQ_MASK_READ__intr_eot__pend 1 -#define R_USB_IRQ_MASK_READ__iso_eot__BITNR 8 +#define R_USB_IRQ_MASK_READ__intr_eof__BITNR 12 +#define R_USB_IRQ_MASK_READ__intr_eof__WIDTH 1 +#define R_USB_IRQ_MASK_READ__intr_eof__no_pend 0 +#define R_USB_IRQ_MASK_READ__intr_eof__pend 1 +#define R_USB_IRQ_MASK_READ__iso_eot__BITNR 11 #define R_USB_IRQ_MASK_READ__iso_eot__WIDTH 1 #define R_USB_IRQ_MASK_READ__iso_eot__no_pend 0 #define R_USB_IRQ_MASK_READ__iso_eot__pend 1 +#define R_USB_IRQ_MASK_READ__intr_eot__BITNR 10 +#define R_USB_IRQ_MASK_READ__intr_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ__intr_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ__intr_eot__pend 1 +#define R_USB_IRQ_MASK_READ__ctl_eot__BITNR 9 +#define R_USB_IRQ_MASK_READ__ctl_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ__ctl_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ__ctl_eot__pend 1 +#define R_USB_IRQ_MASK_READ__bulk_eot__BITNR 8 +#define R_USB_IRQ_MASK_READ__bulk_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ__bulk_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ__bulk_eot__pend 1 +#define R_USB_IRQ_MASK_READ__epid_attn__BITNR 3 +#define R_USB_IRQ_MASK_READ__epid_attn__WIDTH 1 +#define R_USB_IRQ_MASK_READ__epid_attn__no_pend 0 +#define R_USB_IRQ_MASK_READ__epid_attn__pend 1 #define R_USB_IRQ_MASK_READ__sof__BITNR 2 #define R_USB_IRQ_MASK_READ__sof__WIDTH 1 #define R_USB_IRQ_MASK_READ__sof__no_pend 0 @@ -6107,30 +6219,34 @@ #define R_USB_IRQ_MASK_READ__ctl_status__pend 1 #define R_USB_IRQ_MASK_CLR (IO_TYPECAST_UWORD 0xb0000206) -#define R_USB_IRQ_MASK_CLR__intr_eof__BITNR 13 -#define R_USB_IRQ_MASK_CLR__intr_eof__WIDTH 1 -#define R_USB_IRQ_MASK_CLR__intr_eof__nop 0 -#define R_USB_IRQ_MASK_CLR__intr_eof__clr 1 -#define R_USB_IRQ_MASK_CLR__iso_eof__BITNR 12 +#define R_USB_IRQ_MASK_CLR__iso_eof__BITNR 13 #define R_USB_IRQ_MASK_CLR__iso_eof__WIDTH 1 #define R_USB_IRQ_MASK_CLR__iso_eof__nop 0 #define R_USB_IRQ_MASK_CLR__iso_eof__clr 1 -#define R_USB_IRQ_MASK_CLR__bulk_eot__BITNR 11 -#define R_USB_IRQ_MASK_CLR__bulk_eot__WIDTH 1 -#define R_USB_IRQ_MASK_CLR__bulk_eot__nop 0 -#define R_USB_IRQ_MASK_CLR__bulk_eot__clr 1 -#define R_USB_IRQ_MASK_CLR__ctl_eot__BITNR 10 -#define R_USB_IRQ_MASK_CLR__ctl_eot__WIDTH 1 -#define R_USB_IRQ_MASK_CLR__ctl_eot__nop 0 -#define R_USB_IRQ_MASK_CLR__ctl_eot__clr 1 -#define R_USB_IRQ_MASK_CLR__intr_eot__BITNR 9 -#define R_USB_IRQ_MASK_CLR__intr_eot__WIDTH 1 -#define R_USB_IRQ_MASK_CLR__intr_eot__nop 0 -#define R_USB_IRQ_MASK_CLR__intr_eot__clr 1 -#define R_USB_IRQ_MASK_CLR__iso_eot__BITNR 8 +#define R_USB_IRQ_MASK_CLR__intr_eof__BITNR 12 +#define R_USB_IRQ_MASK_CLR__intr_eof__WIDTH 1 +#define R_USB_IRQ_MASK_CLR__intr_eof__nop 0 +#define R_USB_IRQ_MASK_CLR__intr_eof__clr 1 +#define R_USB_IRQ_MASK_CLR__iso_eot__BITNR 11 #define R_USB_IRQ_MASK_CLR__iso_eot__WIDTH 1 #define R_USB_IRQ_MASK_CLR__iso_eot__nop 0 #define R_USB_IRQ_MASK_CLR__iso_eot__clr 1 +#define R_USB_IRQ_MASK_CLR__intr_eot__BITNR 10 +#define R_USB_IRQ_MASK_CLR__intr_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR__intr_eot__nop 0 +#define R_USB_IRQ_MASK_CLR__intr_eot__clr 1 +#define R_USB_IRQ_MASK_CLR__ctl_eot__BITNR 9 +#define R_USB_IRQ_MASK_CLR__ctl_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR__ctl_eot__nop 0 +#define R_USB_IRQ_MASK_CLR__ctl_eot__clr 1 +#define R_USB_IRQ_MASK_CLR__bulk_eot__BITNR 8 +#define R_USB_IRQ_MASK_CLR__bulk_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR__bulk_eot__nop 0 +#define R_USB_IRQ_MASK_CLR__bulk_eot__clr 1 +#define R_USB_IRQ_MASK_CLR__epid_attn__BITNR 3 +#define R_USB_IRQ_MASK_CLR__epid_attn__WIDTH 1 +#define R_USB_IRQ_MASK_CLR__epid_attn__nop 0 +#define R_USB_IRQ_MASK_CLR__epid_attn__clr 1 #define R_USB_IRQ_MASK_CLR__sof__BITNR 2 #define R_USB_IRQ_MASK_CLR__sof__WIDTH 1 #define R_USB_IRQ_MASK_CLR__sof__nop 0 @@ -6145,30 +6261,34 @@ #define R_USB_IRQ_MASK_CLR__ctl_status__clr 1 #define R_USB_IRQ_READ (IO_TYPECAST_RO_UWORD 0xb0000206) -#define R_USB_IRQ_READ__intr_eof__BITNR 13 -#define R_USB_IRQ_READ__intr_eof__WIDTH 1 -#define R_USB_IRQ_READ__intr_eof__no_pend 0 -#define R_USB_IRQ_READ__intr_eof__pend 1 -#define R_USB_IRQ_READ__iso_eof__BITNR 12 +#define R_USB_IRQ_READ__iso_eof__BITNR 13 #define R_USB_IRQ_READ__iso_eof__WIDTH 1 #define R_USB_IRQ_READ__iso_eof__no_pend 0 #define R_USB_IRQ_READ__iso_eof__pend 1 -#define R_USB_IRQ_READ__bulk_eot__BITNR 11 -#define R_USB_IRQ_READ__bulk_eot__WIDTH 1 -#define R_USB_IRQ_READ__bulk_eot__no_pend 0 -#define R_USB_IRQ_READ__bulk_eot__pend 1 -#define R_USB_IRQ_READ__ctl_eot__BITNR 10 -#define R_USB_IRQ_READ__ctl_eot__WIDTH 1 -#define R_USB_IRQ_READ__ctl_eot__no_pend 0 -#define R_USB_IRQ_READ__ctl_eot__pend 1 -#define R_USB_IRQ_READ__intr_eot__BITNR 9 -#define R_USB_IRQ_READ__intr_eot__WIDTH 1 -#define R_USB_IRQ_READ__intr_eot__no_pend 0 -#define R_USB_IRQ_READ__intr_eot__pend 1 -#define R_USB_IRQ_READ__iso_eot__BITNR 8 +#define R_USB_IRQ_READ__intr_eof__BITNR 12 +#define R_USB_IRQ_READ__intr_eof__WIDTH 1 +#define R_USB_IRQ_READ__intr_eof__no_pend 0 +#define R_USB_IRQ_READ__intr_eof__pend 1 +#define R_USB_IRQ_READ__iso_eot__BITNR 11 #define R_USB_IRQ_READ__iso_eot__WIDTH 1 #define R_USB_IRQ_READ__iso_eot__no_pend 0 #define R_USB_IRQ_READ__iso_eot__pend 1 +#define R_USB_IRQ_READ__intr_eot__BITNR 10 +#define R_USB_IRQ_READ__intr_eot__WIDTH 1 +#define R_USB_IRQ_READ__intr_eot__no_pend 0 +#define R_USB_IRQ_READ__intr_eot__pend 1 +#define R_USB_IRQ_READ__ctl_eot__BITNR 9 +#define R_USB_IRQ_READ__ctl_eot__WIDTH 1 +#define R_USB_IRQ_READ__ctl_eot__no_pend 0 +#define R_USB_IRQ_READ__ctl_eot__pend 1 +#define R_USB_IRQ_READ__bulk_eot__BITNR 8 +#define R_USB_IRQ_READ__bulk_eot__WIDTH 1 +#define R_USB_IRQ_READ__bulk_eot__no_pend 0 +#define R_USB_IRQ_READ__bulk_eot__pend 1 +#define R_USB_IRQ_READ__epid_attn__BITNR 3 +#define R_USB_IRQ_READ__epid_attn__WIDTH 1 +#define R_USB_IRQ_READ__epid_attn__no_pend 0 +#define R_USB_IRQ_READ__epid_attn__pend 1 #define R_USB_IRQ_READ__sof__BITNR 2 #define R_USB_IRQ_READ__sof__WIDTH 1 #define R_USB_IRQ_READ__sof__no_pend 0 @@ -6182,7 +6302,159 @@ #define R_USB_IRQ_READ__ctl_status__no_pend 0 #define R_USB_IRQ_READ__ctl_status__pend 1 -#define R_USB_FM_NUMBER (IO_TYPECAST_RO_UDWORD 0xb000020c) +#define R_USB_IRQ_MASK_SET_DEV (IO_TYPECAST_UWORD 0xb0000204) +#define R_USB_IRQ_MASK_SET_DEV__out_eot__BITNR 12 +#define R_USB_IRQ_MASK_SET_DEV__out_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__out_eot__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__out_eot__set 1 +#define R_USB_IRQ_MASK_SET_DEV__ep3_in_eot__BITNR 11 +#define R_USB_IRQ_MASK_SET_DEV__ep3_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__ep3_in_eot__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__ep3_in_eot__set 1 +#define R_USB_IRQ_MASK_SET_DEV__ep2_in_eot__BITNR 10 +#define R_USB_IRQ_MASK_SET_DEV__ep2_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__ep2_in_eot__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__ep2_in_eot__set 1 +#define R_USB_IRQ_MASK_SET_DEV__ep1_in_eot__BITNR 9 +#define R_USB_IRQ_MASK_SET_DEV__ep1_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__ep1_in_eot__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__ep1_in_eot__set 1 +#define R_USB_IRQ_MASK_SET_DEV__ep0_in_eot__BITNR 8 +#define R_USB_IRQ_MASK_SET_DEV__ep0_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__ep0_in_eot__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__ep0_in_eot__set 1 +#define R_USB_IRQ_MASK_SET_DEV__epid_attn__BITNR 3 +#define R_USB_IRQ_MASK_SET_DEV__epid_attn__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__epid_attn__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__epid_attn__set 1 +#define R_USB_IRQ_MASK_SET_DEV__sof__BITNR 2 +#define R_USB_IRQ_MASK_SET_DEV__sof__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__sof__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__sof__set 1 +#define R_USB_IRQ_MASK_SET_DEV__port_status__BITNR 1 +#define R_USB_IRQ_MASK_SET_DEV__port_status__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__port_status__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__port_status__set 1 +#define R_USB_IRQ_MASK_SET_DEV__ctl_status__BITNR 0 +#define R_USB_IRQ_MASK_SET_DEV__ctl_status__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__ctl_status__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__ctl_status__set 1 + +#define R_USB_IRQ_MASK_READ_DEV (IO_TYPECAST_RO_UWORD 0xb0000204) +#define R_USB_IRQ_MASK_READ_DEV__out_eot__BITNR 12 +#define R_USB_IRQ_MASK_READ_DEV__out_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__out_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__out_eot__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__ep3_in_eot__BITNR 11 +#define R_USB_IRQ_MASK_READ_DEV__ep3_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__ep3_in_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__ep3_in_eot__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__ep2_in_eot__BITNR 10 +#define R_USB_IRQ_MASK_READ_DEV__ep2_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__ep2_in_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__ep2_in_eot__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__ep1_in_eot__BITNR 9 +#define R_USB_IRQ_MASK_READ_DEV__ep1_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__ep1_in_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__ep1_in_eot__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__ep0_in_eot__BITNR 8 +#define R_USB_IRQ_MASK_READ_DEV__ep0_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__ep0_in_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__ep0_in_eot__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__epid_attn__BITNR 3 +#define R_USB_IRQ_MASK_READ_DEV__epid_attn__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__epid_attn__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__epid_attn__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__sof__BITNR 2 +#define R_USB_IRQ_MASK_READ_DEV__sof__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__sof__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__sof__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__port_status__BITNR 1 +#define R_USB_IRQ_MASK_READ_DEV__port_status__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__port_status__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__port_status__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__ctl_status__BITNR 0 +#define R_USB_IRQ_MASK_READ_DEV__ctl_status__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__ctl_status__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__ctl_status__pend 1 + +#define R_USB_IRQ_MASK_CLR_DEV (IO_TYPECAST_UWORD 0xb0000206) +#define R_USB_IRQ_MASK_CLR_DEV__out_eot__BITNR 12 +#define R_USB_IRQ_MASK_CLR_DEV__out_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__out_eot__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__out_eot__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep3_in_eot__BITNR 11 +#define R_USB_IRQ_MASK_CLR_DEV__ep3_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep3_in_eot__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__ep3_in_eot__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep2_in_eot__BITNR 10 +#define R_USB_IRQ_MASK_CLR_DEV__ep2_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep2_in_eot__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__ep2_in_eot__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep1_in_eot__BITNR 9 +#define R_USB_IRQ_MASK_CLR_DEV__ep1_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep1_in_eot__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__ep1_in_eot__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep0_in_eot__BITNR 8 +#define R_USB_IRQ_MASK_CLR_DEV__ep0_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep0_in_eot__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__ep0_in_eot__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__epid_attn__BITNR 3 +#define R_USB_IRQ_MASK_CLR_DEV__epid_attn__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__epid_attn__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__epid_attn__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__sof__BITNR 2 +#define R_USB_IRQ_MASK_CLR_DEV__sof__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__sof__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__sof__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__port_status__BITNR 1 +#define R_USB_IRQ_MASK_CLR_DEV__port_status__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__port_status__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__port_status__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__ctl_status__BITNR 0 +#define R_USB_IRQ_MASK_CLR_DEV__ctl_status__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__ctl_status__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__ctl_status__clr 1 + +#define R_USB_IRQ_READ_DEV (IO_TYPECAST_RO_UWORD 0xb0000206) +#define R_USB_IRQ_READ_DEV__out_eot__BITNR 12 +#define R_USB_IRQ_READ_DEV__out_eot__WIDTH 1 +#define R_USB_IRQ_READ_DEV__out_eot__no_pend 0 +#define R_USB_IRQ_READ_DEV__out_eot__pend 1 +#define R_USB_IRQ_READ_DEV__ep3_in_eot__BITNR 11 +#define R_USB_IRQ_READ_DEV__ep3_in_eot__WIDTH 1 +#define R_USB_IRQ_READ_DEV__ep3_in_eot__no_pend 0 +#define R_USB_IRQ_READ_DEV__ep3_in_eot__pend 1 +#define R_USB_IRQ_READ_DEV__ep2_in_eot__BITNR 10 +#define R_USB_IRQ_READ_DEV__ep2_in_eot__WIDTH 1 +#define R_USB_IRQ_READ_DEV__ep2_in_eot__no_pend 0 +#define R_USB_IRQ_READ_DEV__ep2_in_eot__pend 1 +#define R_USB_IRQ_READ_DEV__ep1_in_eot__BITNR 9 +#define R_USB_IRQ_READ_DEV__ep1_in_eot__WIDTH 1 +#define R_USB_IRQ_READ_DEV__ep1_in_eot__no_pend 0 +#define R_USB_IRQ_READ_DEV__ep1_in_eot__pend 1 +#define R_USB_IRQ_READ_DEV__ep0_in_eot__BITNR 8 +#define R_USB_IRQ_READ_DEV__ep0_in_eot__WIDTH 1 +#define R_USB_IRQ_READ_DEV__ep0_in_eot__no_pend 0 +#define R_USB_IRQ_READ_DEV__ep0_in_eot__pend 1 +#define R_USB_IRQ_READ_DEV__epid_attn__BITNR 3 +#define R_USB_IRQ_READ_DEV__epid_attn__WIDTH 1 +#define R_USB_IRQ_READ_DEV__epid_attn__no_pend 0 +#define R_USB_IRQ_READ_DEV__epid_attn__pend 1 +#define R_USB_IRQ_READ_DEV__sof__BITNR 2 +#define R_USB_IRQ_READ_DEV__sof__WIDTH 1 +#define R_USB_IRQ_READ_DEV__sof__no_pend 0 +#define R_USB_IRQ_READ_DEV__sof__pend 1 +#define R_USB_IRQ_READ_DEV__port_status__BITNR 1 +#define R_USB_IRQ_READ_DEV__port_status__WIDTH 1 +#define R_USB_IRQ_READ_DEV__port_status__no_pend 0 +#define R_USB_IRQ_READ_DEV__port_status__pend 1 +#define R_USB_IRQ_READ_DEV__ctl_status__BITNR 0 +#define R_USB_IRQ_READ_DEV__ctl_status__WIDTH 1 +#define R_USB_IRQ_READ_DEV__ctl_status__no_pend 0 +#define R_USB_IRQ_READ_DEV__ctl_status__pend 1 + +#define R_USB_FM_NUMBER (IO_TYPECAST_UDWORD 0xb000020c) #define R_USB_FM_NUMBER__value__BITNR 0 #define R_USB_FM_NUMBER__value__WIDTH 32 @@ -6200,22 +6472,26 @@ #define R_USB_FM_PSTART__value__BITNR 0 #define R_USB_FM_PSTART__value__WIDTH 14 -#define R_USB_LS_THRESHOLD (IO_TYPECAST_UWORD 0xb0000216) -#define R_USB_LS_THRESHOLD__value__BITNR 0 -#define R_USB_LS_THRESHOLD__value__WIDTH 14 - #define R_USB_RH_STATUS (IO_TYPECAST_RO_BYTE 0xb0000203) +#define R_USB_RH_STATUS__babble2__BITNR 7 +#define R_USB_RH_STATUS__babble2__WIDTH 1 +#define R_USB_RH_STATUS__babble2__no 0 +#define R_USB_RH_STATUS__babble2__yes 1 +#define R_USB_RH_STATUS__babble1__BITNR 6 +#define R_USB_RH_STATUS__babble1__WIDTH 1 +#define R_USB_RH_STATUS__babble1__no 0 +#define R_USB_RH_STATUS__babble1__yes 1 #define R_USB_RH_STATUS__bus1__BITNR 4 #define R_USB_RH_STATUS__bus1__WIDTH 2 #define R_USB_RH_STATUS__bus1__SE0 0 #define R_USB_RH_STATUS__bus1__Diff0 1 -#define R_USB_RH_STATUS__bus1__Diff1 1 +#define R_USB_RH_STATUS__bus1__Diff1 2 #define R_USB_RH_STATUS__bus1__SE1 3 #define R_USB_RH_STATUS__bus2__BITNR 2 #define R_USB_RH_STATUS__bus2__WIDTH 2 #define R_USB_RH_STATUS__bus2__SE0 0 #define R_USB_RH_STATUS__bus2__Diff0 1 -#define R_USB_RH_STATUS__bus2__Diff1 1 +#define R_USB_RH_STATUS__bus2__Diff1 2 #define R_USB_RH_STATUS__bus2__SE1 3 #define R_USB_RH_STATUS__nports__BITNR 0 #define R_USB_RH_STATUS__nports__WIDTH 2 @@ -6231,10 +6507,10 @@ #define R_USB_RH_PORT_STATUS_1__reset__WIDTH 1 #define R_USB_RH_PORT_STATUS_1__reset__no 0 #define R_USB_RH_PORT_STATUS_1__reset__yes 1 -#define R_USB_RH_PORT_STATUS_1__overcurent__BITNR 3 -#define R_USB_RH_PORT_STATUS_1__overcurent__WIDTH 1 -#define R_USB_RH_PORT_STATUS_1__overcurent__no 0 -#define R_USB_RH_PORT_STATUS_1__overcurent__yes 1 +#define R_USB_RH_PORT_STATUS_1__overcurrent__BITNR 3 +#define R_USB_RH_PORT_STATUS_1__overcurrent__WIDTH 1 +#define R_USB_RH_PORT_STATUS_1__overcurrent__no 0 +#define R_USB_RH_PORT_STATUS_1__overcurrent__yes 1 #define R_USB_RH_PORT_STATUS_1__suspended__BITNR 2 #define R_USB_RH_PORT_STATUS_1__suspended__WIDTH 1 #define R_USB_RH_PORT_STATUS_1__suspended__no 0 @@ -6259,10 +6535,10 @@ #define R_USB_RH_PORT_STATUS_2__reset__WIDTH 1 #define R_USB_RH_PORT_STATUS_2__reset__no 0 #define R_USB_RH_PORT_STATUS_2__reset__yes 1 -#define R_USB_RH_PORT_STATUS_2__overcurent__BITNR 3 -#define R_USB_RH_PORT_STATUS_2__overcurent__WIDTH 1 -#define R_USB_RH_PORT_STATUS_2__overcurent__no 0 -#define R_USB_RH_PORT_STATUS_2__overcurent__yes 1 +#define R_USB_RH_PORT_STATUS_2__overcurrent__BITNR 3 +#define R_USB_RH_PORT_STATUS_2__overcurrent__WIDTH 1 +#define R_USB_RH_PORT_STATUS_2__overcurrent__no 0 +#define R_USB_RH_PORT_STATUS_2__overcurrent__yes 1 #define R_USB_RH_PORT_STATUS_2__suspended__BITNR 2 #define R_USB_RH_PORT_STATUS_2__suspended__WIDTH 1 #define R_USB_RH_PORT_STATUS_2__suspended__no 0 @@ -6308,7 +6584,7 @@ #define R_USB_EPT_DATA__error_code__no_error 0 #define R_USB_EPT_DATA__error_code__stall 1 #define R_USB_EPT_DATA__error_code__bus_error 2 -#define R_USB_EPT_DATA__error_code__TBD3 3 +#define R_USB_EPT_DATA__error_code__buffer_error 3 #define R_USB_EPT_DATA__t_out__BITNR 21 #define R_USB_EPT_DATA__t_out__WIDTH 1 #define R_USB_EPT_DATA__error_count_out__BITNR 19 @@ -6357,10 +6633,10 @@ #define R_USB_EPT_DATA_DEV__stall__WIDTH 1 #define R_USB_EPT_DATA_DEV__stall__no 0 #define R_USB_EPT_DATA_DEV__stall__yes 1 -#define R_USB_EPT_DATA_DEV__quiet__BITNR 28 -#define R_USB_EPT_DATA_DEV__quiet__WIDTH 1 -#define R_USB_EPT_DATA_DEV__quiet__no 0 -#define R_USB_EPT_DATA_DEV__quiet__yes 1 +#define R_USB_EPT_DATA_DEV__iso_resp__BITNR 28 +#define R_USB_EPT_DATA_DEV__iso_resp__WIDTH 1 +#define R_USB_EPT_DATA_DEV__iso_resp__quiet 0 +#define R_USB_EPT_DATA_DEV__iso_resp__yes 1 #define R_USB_EPT_DATA_DEV__ctrl__BITNR 27 #define R_USB_EPT_DATA_DEV__ctrl__WIDTH 1 #define R_USB_EPT_DATA_DEV__ctrl__no 0 @@ -6371,6 +6647,8 @@ #define R_USB_EPT_DATA_DEV__iso__yes 1 #define R_USB_EPT_DATA_DEV__port__BITNR 24 #define R_USB_EPT_DATA_DEV__port__WIDTH 2 +#define R_USB_EPT_DATA_DEV__control_phase__BITNR 22 +#define R_USB_EPT_DATA_DEV__control_phase__WIDTH 1 #define R_USB_EPT_DATA_DEV__t__BITNR 21 #define R_USB_EPT_DATA_DEV__t__WIDTH 1 #define R_USB_EPT_DATA_DEV__max_len__BITNR 11 @@ -6384,6 +6662,22 @@ #define R_USB_SNMP_TERROR__value__BITNR 0 #define R_USB_SNMP_TERROR__value__WIDTH 32 +#define R_USB_EPID_ATTN (IO_TYPECAST_RO_UDWORD 0xb0000224) +#define R_USB_EPID_ATTN__value__BITNR 0 +#define R_USB_EPID_ATTN__value__WIDTH 32 + +#define R_USB_PORT1_DISABLE (IO_TYPECAST_BYTE 0xb000006a) +#define R_USB_PORT1_DISABLE__disable__BITNR 0 +#define R_USB_PORT1_DISABLE__disable__WIDTH 1 +#define R_USB_PORT1_DISABLE__disable__yes 0 +#define R_USB_PORT1_DISABLE__disable__no 1 + +#define R_USB_PORT2_DISABLE (IO_TYPECAST_BYTE 0xb0000052) +#define R_USB_PORT2_DISABLE__disable__BITNR 0 +#define R_USB_PORT2_DISABLE__disable__WIDTH 1 +#define R_USB_PORT2_DISABLE__disable__yes 0 +#define R_USB_PORT2_DISABLE__disable__no 1 + /* !* MMU registers !*/ @@ -6615,6 +6909,10 @@ #define R_MMU_CAUSE__we_excp__WIDTH 1 #define R_MMU_CAUSE__we_excp__yes 1 #define R_MMU_CAUSE__we_excp__no 0 +#define R_MMU_CAUSE__wr_rd__BITNR 8 +#define R_MMU_CAUSE__wr_rd__WIDTH 1 +#define R_MMU_CAUSE__wr_rd__write 1 +#define R_MMU_CAUSE__wr_rd__read 0 #define R_MMU_CAUSE__page_id__BITNR 0 #define R_MMU_CAUSE__page_id__WIDTH 6 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-cris/sync_serial.h linux.ac/include/asm-cris/sync_serial.h --- linux.vanilla/include/asm-cris/sync_serial.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-cris/sync_serial.h Tue Apr 10 18:20:15 2001 @@ -0,0 +1,97 @@ +/* + * ioctl defines for synchrnous serial port driver + * + * Copyright (c) 2001 Axis Communications AB + * + * Author: Mikael Starvik + * + */ + +#ifndef SYNC_SERIAL_H +#define SYNC_SERIAL_H + +#include <linux/ioctl.h> + +#define SSP_SPEED _IOR('S', 0, unsigned int) +#define SSP_MODE _IOR('S', 1, unsigned int) +#define SSP_FRAME_SYNC _IOR('S', 2, unsigned int) +#define SSP_IPOLARITY _IOR('S', 3, unsigned int) +#define SSP_OPOLARITY _IOR('S', 4, unsigned int) +#define SSP_SPI _IOR('S', 5, unsigned int) + +/* Values for SSP_SPEED */ +#define SSP150 0 +#define SSP300 1 +#define SSP600 2 +#define SSP1200 3 +#define SSP2400 4 +#define SSP4800 5 +#define SSP9600 6 +#define SSP19200 7 +#define SSP28800 8 +#define SSP57600 9 +#define SSP115200 10 +#define SSP230400 11 +#define SSP460800 12 +#define SSP921600 13 +#define SSP3125000 14 +#define CODEC 15 + +#define FREQ_4MHz 0 +#define FREQ_2MHz 1 +#define FREQ_1MHz 2 +#define FREQ_512kHz 3 +#define FREQ_256kHz 4 +#define FREQ_128kHz 5 +#define FREQ_64kHz 6 +#define FREQ_32kHz 7 + +/* Used by application to set CODEC divider, word rate and frame rate */ +#define CODEC_VAL(freq, word, frame) (CODEC | (freq << 8) | (word << 16) | (frame << 28)) + +/* Used by driver to extract speed */ +#define GET_SPEED(x) (x & 0xff) +#define GET_FREQ(x) ((x & 0xff00) >> 8) +#define GET_WORD_RATE(x) (((x & 0x0fff0000) >> 16) - 1) +#define GET_FRAME_RATE(x) (((x & 0xf0000000) >> 28) - 1) + +/* Values for SSP_MODE */ +#define MASTER_OUTPUT 0 +#define SLAVE_OUTPUT 1 +#define MASTER_INPUT 2 +#define SLAVE_INPUT 3 +#define MASTER_BIDIR 4 +#define SLAVE_BIDIR 5 + +/* Values for SSP_FRAME_SYNC */ +#define NORMAL_SYNC 1 +#define EARLY_SYNC 2 +#define BIT_SYNC 4 +#define WORD_SYNC 8 +#define EXTENDED_SYNC 0x10 +#define SYNC_OFF 0x20 +#define SYNC_ON 0x40 +#define WORD_SIZE_8 0x80 +#define WORD_SIZE_12 0x100 +#define WORD_SIZE_16 0x200 +#define WORD_SIZE_24 0x300 +#define WORD_SIZE_32 0x800 +#define BIT_ORDER_LSB 0x1000 +#define BIT_ORDER_MSB 0x2000 +#define FLOW_CONTROL_ENABLE 0x4000 +#define FLOW_CONTROL_DISABLE 0x8000 +#define CLOCK_GATED 0x10000 +#define CLOCK_NOT_GATED 0x20000 + +/* Values for SSP_IPOLARITY and SSP_OPOLARITY */ +#define CLOCK_NORMAL 1 +#define CLOCK_INVERT 2 +#define FRAME_NORMAL 4 +#define FRAME_INVERT 8 +#define STATUS_NORMAL 0x10 +#define STATUS_INVERT 0x20 + +/* Values for SSP_SPI */ +#define SPI_MASTER 0 +#define SPI_SLAVE 1 +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-cris/termios.h linux.ac/include/asm-cris/termios.h --- linux.vanilla/include/asm-cris/termios.h Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-cris/termios.h Tue Apr 10 18:20:15 2001 @@ -51,7 +51,7 @@ #define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave@mvhi.com> */ -#define N_IRDA 11 /* Linux IR - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_IRDA 11 /* Linux IR - http://irda.sourceforge.net/ */ #define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #define N_HDLC 13 /* synchronous HDLC */ #define N_SYNC_PPP 14 /* synchronous PPP */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-cris/tlb.h linux.ac/include/asm-cris/tlb.h --- linux.vanilla/include/asm-cris/tlb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-cris/tlb.h Tue Apr 3 17:55:14 2001 @@ -0,0 +1 @@ +#include <asm-generic/tlb.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-cris/unistd.h linux.ac/include/asm-cris/unistd.h --- linux.vanilla/include/asm-cris/unistd.h Fri Feb 9 00:32:44 2001 +++ linux.ac/include/asm-cris/unistd.h Tue Apr 10 18:20:15 2001 @@ -233,28 +233,28 @@ type name(void) \ { \ register long __a __asm__ ("r10"); \ - __asm__ __volatile__ ("move.d %1,r1\n\tbreak 13" \ + __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \ : "=r" (__a) \ : "g" (__NR_##name) \ - : "r10", "r1"); \ + : "r10", "r9"); \ if(__a >= 0) \ return (type) __a; \ errno = -__a; \ - return -1; \ + return (type) -1; \ } #define _syscall1(type,name,type1,arg1) \ type name(type1 arg1) \ { \ register long __a __asm__ ("r10") = (long) arg1; \ - __asm__ __volatile__ ("move.d %1,r1\n\tbreak 13" \ + __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \ : "=r" (__a) \ : "g" (__NR_##name), "0" (__a) \ - : "r10", "r1"); \ + : "r10", "r9"); \ if(__a >= 0) \ return (type) __a; \ errno = -__a; \ - return -1; \ + return (type) -1; \ } #define _syscall2(type,name,type1,arg1,type2,arg2) \ @@ -262,14 +262,14 @@ { \ register long __a __asm__ ("r10") = (long) arg1; \ register long __b __asm__ ("r11") = (long) arg2; \ - __asm__ __volatile__ ("move.d %1,r1\n\tbreak 13" \ + __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \ : "=r" (__a) \ : "g" (__NR_##name), "0" (__a), "r" (__b) \ - : "r10", "r1"); \ + : "r10", "r9"); \ if(__a >= 0) \ return (type) __a; \ errno = -__a; \ - return -1; \ + return (type) -1; \ } #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ @@ -278,14 +278,14 @@ register long __a __asm__ ("r10") = (long) arg1; \ register long __b __asm__ ("r11") = (long) arg2; \ register long __c __asm__ ("r12") = (long) arg3; \ - __asm__ __volatile__ ("move.d %1,r1\n\tbreak 13" \ + __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \ : "=r" (__a) \ : "g" (__NR_##name), "0" (__a), "r" (__b), "r" (__c) \ - : "r10", "r1"); \ + : "r10", "r9"); \ if(__a >= 0) \ return (type) __a; \ errno = -__a; \ - return -1; \ + return (type) -1; \ } #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ @@ -295,15 +295,15 @@ register long __b __asm__ ("r11") = (long) arg2; \ register long __c __asm__ ("r12") = (long) arg3; \ register long __d __asm__ ("r13") = (long) arg4; \ - __asm__ __volatile__ ("move.d %1,r1\n\tbreak 13" \ + __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \ : "=r" (__a) \ : "g" (__NR_##name), "0" (__a), "r" (__b), \ "r" (__c), "r" (__d) \ - : "r10", "r1"); \ + : "r10", "r9"); \ if(__a >= 0) \ return (type) __a; \ errno = -__a; \ - return -1; \ + return (type) -1; \ } #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ @@ -314,16 +314,36 @@ register long __b __asm__ ("r11") = (long) arg2; \ register long __c __asm__ ("r12") = (long) arg3; \ register long __d __asm__ ("r13") = (long) arg4; \ - register long __e __asm__ ("r0") = (long) arg5; \ - __asm__ __volatile__ ("move.d %1,r1\n\tbreak 13" \ + __asm__ __volatile__ ("move %6,$mof\n\t" \ + "movu.w %1,$r9\n\tbreak 13" \ : "=r" (__a) \ : "g" (__NR_##name), "0" (__a), "r" (__b), \ - "r" (__c), "r" (__d), "r" (__e) \ - : "r10", "r1"); \ + "r" (__c), "r" (__d), "g" (arg5) \ + : "r10", "r9"); \ if(__a >= 0) \ return (type) __a; \ errno = -__a; \ - return -1; \ + return (type) -1; \ +} + +#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ +type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ +{ \ + register long __a __asm__ ("r10") = (long) arg1; \ + register long __b __asm__ ("r11") = (long) arg2; \ + register long __c __asm__ ("r12") = (long) arg3; \ + register long __d __asm__ ("r13") = (long) arg4; \ + __asm__ __volatile__ ("move %6,$mof\n\tmove %7,$srp\n\t" \ + "movu.w %1,$r9\n\tbreak 13" \ + : "=r" (__a) \ + : "g" (__NR_##name), "0" (__a), "r" (__b), \ + "r" (__c), "r" (__d), "g" (arg5), "g" (arg6)\ + : "r10", "r9", "srp"); \ + if(__a >= 0) \ + return (type) __a; \ + errno = -__a; \ + return (type) -1; \ } #ifdef __KERNEL_SYSCALLS__ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-generic/tlb.h linux.ac/include/asm-generic/tlb.h --- linux.vanilla/include/asm-generic/tlb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-generic/tlb.h Tue Apr 3 17:55:14 2001 @@ -0,0 +1,113 @@ +/* asm-generic/tlb.h + * + * Generic TLB shootdown code + * + * Copyright 2001 Red Hat, Inc. + * Based on code from mm/memory.c Copyright Linus Torvalds and others. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _ASM_GENERIC__TLB_H +#define _ASM_GENERIC__TLB_H + +#include <linux/config.h> + +#ifdef CONFIG_SMP +/* aim for something that fits in the L1 cache */ +#define FREE_PTE_NR 508 + +/* mmu_gather_t is an opaque type used by the mm code for passing around any + * data needed by arch specific code for tlb_remove_page. This structure can + * be per-CPU or per-MM as the page table lock is held for the duration of TLB + * shootdown. + */ +typedef struct free_pte_ctx { + struct mm_struct *mm; + unsigned long nr; /* set to ~0UL means fast mode */ + unsigned long start_addr, end_addr; + pte_t ptes[FREE_PTE_NR]; +} mmu_gather_t; + +/* Users of the generic TLB shootdown code must declare this storage space. */ +extern mmu_gather_t mmu_gathers[NR_CPUS]; + +/* tlb_gather_mmu + * Return a pointer to an initialized mmu_gather_t. + */ +static inline mmu_gather_t *tlb_gather_mmu(struct mm_struct *mm) +{ + mmu_gather_t *tlb = &mmu_gathers[smp_processor_id()]; + + tlb->mm = mm; + /* Use fast mode if there is only one user of this mm (this process) */ + tlb->nr = (atomic_read(&(mm)->mm_users) == 1) ? ~0UL : 0UL; + return tlb; +} + +/* void tlb_remove_page(mmu_gather_t *tlb, pte_t *ptep, unsigned long addr) + * Must perform the equivalent to __free_pte(pte_get_and_clear(ptep)), while + * handling the additional races in SMP caused by other CPUs caching valid + * mappings in their TLBs. + */ +#define tlb_remove_page(ctxp, pte, addr) do {\ + /* Handle the common case fast, first. */\ + if ((ctxp)->nr == ~0UL) {\ + __free_pte(*(pte));\ + pte_clear((pte));\ + break;\ + }\ + if (!(ctxp)->nr) \ + (ctxp)->start_addr = (addr);\ + (ctxp)->ptes[(ctxp)->nr++] = ptep_get_and_clear(pte);\ + (ctxp)->end_addr = (addr) + PAGE_SIZE;\ + if ((ctxp)->nr >= FREE_PTE_NR)\ + tlb_finish_mmu((ctxp), 0, 0);\ + } while (0) + +/* tlb_finish_mmu + * Called at the end of the shootdown operation to free up any resources + * that were required. The page talbe lock is still held at this point. + */ +static inline void tlb_finish_mmu(struct free_pte_ctx *ctx, unsigned long start, unsigned long end) +{ + unsigned long i, nr; + + /* Handle the fast case first. */ + if (ctx->nr == ~0UL) { + flush_tlb_range(ctx->mm, start, end); + return; + } + nr = ctx->nr; + ctx->nr = 0; + if (nr) + flush_tlb_range(ctx->mm, ctx->start_addr, ctx->end_addr); + for (i=0; i < nr; i++) { + pte_t pte = ctx->ptes[i]; + __free_pte(pte); + } +} + +#else + +/* The uniprocessor functions are quite simple and are inline macros in an + * attempt to get gcc to generate optimal code since this code is run on each + * page in a process at exit. + */ +typedef struct mm_struct mmu_gather_t; + +#define tlb_gather_mmu(mm) (mm) +#define tlb_finish_mmu(tlb, start, end) flush_tlb_range(tlb, start, end) +#define tlb_remove_page(tlb, ptep, addr) do {\ + pte_t __pte = *(ptep);\ + pte_clear(ptep);\ + __free_pte(__pte);\ + } while (0) + +#endif + + +#endif /* _ASM_GENERIC__TLB_H */ + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/apic.h linux.ac/include/asm-i386/apic.h --- linux.vanilla/include/asm-i386/apic.h Thu Feb 22 00:09:57 2001 +++ linux.ac/include/asm-i386/apic.h Sat Apr 14 15:05:37 2001 @@ -2,13 +2,14 @@ #define __ASM_APIC_H #include <linux/config.h> +#include <linux/pm.h> #include <asm/apicdef.h> #include <asm/system.h> -#define APIC_DEBUG 1 - #ifdef CONFIG_X86_LOCAL_APIC +#define APIC_DEBUG 0 + #if APIC_DEBUG #define Dprintk(x...) printk(x) #else @@ -39,8 +40,6 @@ do { } while ( apic_read( APIC_ICR ) & APIC_ICR_BUSY ); } -extern unsigned int apic_timer_irqs [NR_CPUS]; - #ifdef CONFIG_X86_GOOD_APIC # define FORCE_READ_AROUND_WRITE 0 # define apic_read_around(x) @@ -70,11 +69,28 @@ extern void disable_local_APIC (void); extern int verify_local_APIC (void); extern void cache_APIC_registers (void); -extern void sync_Arb_IDs(void); +extern void sync_Arb_IDs (void); +extern void init_bsp_APIC (void); extern void setup_local_APIC (void); -extern void init_apic_mappings(void); -extern void smp_local_timer_interrupt(struct pt_regs * regs); -extern void setup_APIC_clocks(void); -#endif +extern void init_apic_mappings (void); +extern void smp_local_timer_interrupt (struct pt_regs * regs); +extern void setup_APIC_clocks (void); +extern void setup_apic_nmi_watchdog (void); +extern inline void nmi_watchdog_tick (struct pt_regs * regs); +extern int APIC_init_uniprocessor (void); -#endif +extern struct pm_dev *apic_pm_register(pm_dev_t, unsigned long, pm_callback); +extern void apic_pm_unregister(struct pm_dev*); + +extern unsigned int apic_timer_irqs [NR_CPUS]; +extern int check_nmi_watchdog (void); + +extern unsigned int nmi_watchdog; +#define NMI_NONE 0 +#define NMI_IO_APIC 1 +#define NMI_LOCAL_APIC 2 +#define NMI_INVALID 3 + +#endif /* CONFIG_X86_LOCAL_APIC */ + +#endif /* __ASM_APIC_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/apicdef.h linux.ac/include/asm-i386/apicdef.h --- linux.vanilla/include/asm-i386/apicdef.h Fri Aug 18 17:30:51 2000 +++ linux.ac/include/asm-i386/apicdef.h Tue Apr 3 17:55:14 2001 @@ -33,6 +33,8 @@ #define APIC_ALL_CPUS 0xFF #define APIC_DFR 0xE0 #define APIC_SPIV 0xF0 +#define APIC_SPIV_FOCUS_DISABLED (1<<9) +#define APIC_SPIV_APIC_ENABLED (1<<8) #define APIC_ISR 0x100 #define APIC_TMR 0x180 #define APIC_IRR 0x200 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/atomic.h linux.ac/include/asm-i386/atomic.h --- linux.vanilla/include/asm-i386/atomic.h Tue Apr 3 17:32:27 2001 +++ linux.ac/include/asm-i386/atomic.h Tue Apr 10 18:20:26 2001 @@ -75,7 +75,7 @@ } /** - * atomic_sub_and_test - test variable then subtract + * atomic_sub_and_test - subtract value from variable and test result * @i: integer value to subtract * @v: pointer of type atomic_t * @@ -111,7 +111,7 @@ } /** - * atomic_dec - decrement the atomic variable + * atomic_dec - decrement atomic variable * @v: pointer of type atomic_t * * Atomically decrements @v by 1. Note that the guaranteed @@ -126,7 +126,7 @@ } /** - * atomic_dec_and_test - decrement by 1 and test + * atomic_dec_and_test - decrement and test * @v: pointer of type atomic_t * * Atomically decrements @v by 1 and @@ -146,7 +146,7 @@ } /** - * atomic_inc_and_test - increment by 1 and test + * atomic_inc_and_test - increment and test * @v: pointer of type atomic_t * * Atomically increments @v by 1 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/bitops.h linux.ac/include/asm-i386/bitops.h --- linux.vanilla/include/asm-i386/bitops.h Thu Feb 22 00:09:56 2001 +++ linux.ac/include/asm-i386/bitops.h Tue Apr 10 18:20:26 2001 @@ -23,6 +23,16 @@ #define ADDR (*(volatile long *) addr) +/** + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. See __set_bit() + * if you do not require the atomic guarantees. + * Note that @nr may be almost arbitrarily large; this function is not + * restricted to acting on a single-word quantity. + */ static __inline__ void set_bit(int nr, volatile void * addr) { __asm__ __volatile__( LOCK_PREFIX @@ -31,7 +41,15 @@ :"Ir" (nr)); } -/* WARNING: non atomic and it can be reordered! */ +/** + * __set_bit - Set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * Unlike set_bit(), this function is non-atomic and may be reordered. + * If it's called on the same region of memory simultaneously, the effect + * may be that only one operation succeeds. + */ static __inline__ void __set_bit(int nr, volatile void * addr) { __asm__( @@ -40,11 +58,16 @@ :"Ir" (nr)); } -/* - * clear_bit() doesn't provide any barrier for the compiler. +/** + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. However, it does + * not contain a memory barrier, so if it is used for locking purposes, + * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() + * in order to ensure changes are visible on other processors. */ -#define smp_mb__before_clear_bit() barrier() -#define smp_mb__after_clear_bit() barrier() static __inline__ void clear_bit(int nr, volatile void * addr) { __asm__ __volatile__( LOCK_PREFIX @@ -52,7 +75,18 @@ :"=m" (ADDR) :"Ir" (nr)); } +#define smp_mb__before_clear_bit() barrier() +#define smp_mb__after_clear_bit() barrier() +/** + * change_bit - Toggle a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * change_bit() is atomic and may not be reordered. + * Note that @nr may be almost arbitrarily large; this function is not + * restricted to acting on a single-word quantity. + */ static __inline__ void change_bit(int nr, volatile void * addr) { __asm__ __volatile__( LOCK_PREFIX @@ -61,10 +95,13 @@ :"Ir" (nr)); } -/* - * It will also imply a memory barrier, thus it must clobber memory - * to make sure to reload anything that was cached into registers - * outside _this_ critical section. +/** + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. */ static __inline__ int test_and_set_bit(int nr, volatile void * addr) { @@ -77,7 +114,15 @@ return oldbit; } -/* WARNING: non atomic and it can be reordered! */ +/** + * __test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ static __inline__ int __test_and_set_bit(int nr, volatile void * addr) { int oldbit; @@ -89,6 +134,14 @@ return oldbit; } +/** + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ static __inline__ int test_and_clear_bit(int nr, volatile void * addr) { int oldbit; @@ -100,7 +153,15 @@ return oldbit; } -/* WARNING: non atomic and it can be reordered! */ +/** + * __test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ static __inline__ int __test_and_clear_bit(int nr, volatile void * addr) { int oldbit; @@ -112,6 +173,14 @@ return oldbit; } +/** + * test_and_change_bit - Change a bit and return its new value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ static __inline__ int test_and_change_bit(int nr, volatile void * addr) { int oldbit; @@ -123,9 +192,15 @@ return oldbit; } -/* - * This routine doesn't need to be atomic. +#if 0 /* Fool kernel-doc since it doesn't do macros yet */ +/** + * test_bit - Determine whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from */ +static int test_bit(int nr, const volatile void * addr); +#endif + static __inline__ int constant_test_bit(int nr, const volatile void * addr) { return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0; @@ -147,8 +222,13 @@ constant_test_bit((nr),(addr)) : \ variable_test_bit((nr),(addr))) -/* - * Find-bit routines.. +/** + * find_first_zero_bit - find the first zero bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit-number of the first zero bit, not the number of the byte + * containing a bit. */ static __inline__ int find_first_zero_bit(void * addr, unsigned size) { @@ -174,6 +254,12 @@ return res; } +/** + * find_next_zero_bit - find the first zero bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search + */ static __inline__ int find_next_zero_bit (void * addr, int size, int offset) { unsigned long * p = ((unsigned long *) addr) + (offset >> 5); @@ -201,9 +287,11 @@ return (offset + set + res); } -/* - * ffz = Find First Zero in word. Undefined if no zero exists, - * so code should check against ~0UL first.. +/** + * ffz - find first zero in word. + * @word: The word to search + * + * Undefined if no zero exists, so code should check against ~0UL first. */ static __inline__ unsigned long ffz(unsigned long word) { @@ -215,12 +303,14 @@ #ifdef __KERNEL__ -/* - * ffs: find first bit set. This is defined the same way as +/** + * ffs - find first bit set + * @x: the word to search + * + * This is defined the same way as * the libc and compiler builtin ffs routines, therefore * differs in spirit from the above ffz (man ffs). */ - static __inline__ int ffs(int x) { int r; @@ -232,9 +322,11 @@ return r+1; } -/* - * hweightN: returns the hamming weight (i.e. the number - * of bits set) of a N-bit word +/** + * hweightN - returns the hamming weight of a N-bit word + * @x: the word to weigh + * + * The Hamming Weight of a number is the total number of bits set in it. */ #define hweight32(x) generic_hweight32(x) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/desc.h linux.ac/include/asm-i386/desc.h --- linux.vanilla/include/asm-i386/desc.h Fri Dec 29 22:07:23 2000 +++ linux.ac/include/asm-i386/desc.h Tue Apr 17 16:01:39 2001 @@ -18,23 +18,31 @@ * 9 - APM BIOS support * 10 - APM BIOS support * 11 - APM BIOS support + * 12 - PNPBIOS support + * 13 - PNPBIOS support + * 14 - PNPBIOS support + * 15 - PNPBIOS support + * 16 - PNPBIOS support + * 17 - not used + * 18 - not used + * 19 - not used * * The TSS+LDT descriptors are spread out a bit so that every CPU * has an exclusive cacheline for the per-CPU TSS and LDT: * - * 12 - CPU#0 TSS <-- new cacheline - * 13 - CPU#0 LDT - * 14 - not used - * 15 - not used - * 16 - CPU#1 TSS <-- new cacheline - * 17 - CPU#1 LDT - * 18 - not used - * 19 - not used + * 20 - CPU#0 TSS <-- new cacheline + * 21 - CPU#0 LDT + * 22 - not used + * 23 - not used + * 24 - CPU#1 TSS <-- new cacheline + * 25 - CPU#1 LDT + * 26 - not used + * 27 - not used * ... NR_CPUS per-CPU TSS+LDT's if on SMP * * Entry into gdt where to find first TSS. */ -#define __FIRST_TSS_ENTRY 12 +#define __FIRST_TSS_ENTRY 20 #define __FIRST_LDT_ENTRY (__FIRST_TSS_ENTRY+1) #define __TSS(n) (((n)<<2) + __FIRST_TSS_ENTRY) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/hw_irq.h linux.ac/include/asm-i386/hw_irq.h --- linux.vanilla/include/asm-i386/hw_irq.h Thu Feb 22 00:09:56 2001 +++ linux.ac/include/asm-i386/hw_irq.h Tue Apr 10 19:56:02 2001 @@ -13,6 +13,7 @@ */ #include <linux/config.h> +#include <asm/atomic.h> #include <asm/irq.h> /* @@ -83,7 +84,9 @@ extern void send_IPI(int dest, int vector); extern unsigned long io_apic_irqs; -extern volatile unsigned long irq_err_count; + +extern atomic_t irq_err_count; +extern atomic_t irq_mis_count; extern char _stext, _etext; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/io.h linux.ac/include/asm-i386/io.h --- linux.vanilla/include/asm-i386/io.h Thu Feb 22 00:10:16 2001 +++ linux.ac/include/asm-i386/io.h Tue Apr 17 17:44:38 2001 @@ -1,6 +1,8 @@ #ifndef _ASM_IO_H #define _ASM_IO_H +#include <linux/config.h> + /* * This file contains the definitions for the x86 IO instructions * inb/inw/inl/outb/outw/outl and the "string versions" of the same @@ -111,7 +113,7 @@ * Temporary debugging check to catch old code using * unmapped ISA addresses. Will be removed in 2.4. */ -#if 1 +#if CONFIG_DEBUG_IOVIRT extern void *__io_virt_debug(unsigned long x, const char *file, int line); extern unsigned long __io_phys_debug(unsigned long x, const char *file, int line); #define __io_virt(x) __io_virt_debug((unsigned long)(x), __FILE__, __LINE__) @@ -245,11 +247,31 @@ return retval; } +/* + * Cache management + */ + +#ifdef CONFIG_X86_OOSTORE + +static inline void flush_write_buffers(void) +{ + __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory"); +} + +#define dma_cache_inv(_start,_size) flush_write_buffers() +#define dma_cache_wback(_start,_size) flush_write_buffers() +#define dma_cache_wback_inv(_start,_size) flush_write_buffers() + +#else + /* Nothing to do */ #define dma_cache_inv(_start,_size) do { } while (0) #define dma_cache_wback(_start,_size) do { } while (0) #define dma_cache_wback_inv(_start,_size) do { } while (0) +#define flush_write_buffers() + +#endif #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/io_apic.h linux.ac/include/asm-i386/io_apic.h --- linux.vanilla/include/asm-i386/io_apic.h Thu Feb 22 00:09:56 2001 +++ linux.ac/include/asm-i386/io_apic.h Tue Apr 3 18:11:11 2001 @@ -12,6 +12,8 @@ #ifdef CONFIG_X86_IO_APIC +#define APIC_MISMATCH_DEBUG + #define IO_APIC_BASE(idx) \ ((volatile int *)__fix_to_virt(FIX_IO_APIC_BASE_0 + idx)) @@ -128,10 +130,8 @@ (void) *(IO_APIC_BASE(apic)+4); } -extern int nmi_watchdog; /* 1 if "noapic" boot option passed */ extern int skip_ioapic_setup; -extern void IO_APIC_init_uniprocessor (void); /* * If we use the IO-APIC for IRQ routing, disable automatic diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/ioctls.h linux.ac/include/asm-i386/ioctls.h --- linux.vanilla/include/asm-i386/ioctls.h Fri Jul 24 19:10:16 1998 +++ linux.ac/include/asm-i386/ioctls.h Tue Apr 3 17:55:14 2001 @@ -67,6 +67,7 @@ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ #define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ #define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ +#define FIOQSIZE 0x5460 /* Used for packet mode */ #define TIOCPKT_DATA 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/irq.h linux.ac/include/asm-i386/irq.h --- linux.vanilla/include/asm-i386/irq.h Thu Oct 7 18:17:09 1999 +++ linux.ac/include/asm-i386/irq.h Tue Apr 3 18:11:11 2001 @@ -10,6 +10,8 @@ * <tomsoft@informatik.tu-chemnitz.de> */ +#include <linux/config.h> + #define TIMER_IRQ 0 /* @@ -31,5 +33,9 @@ extern void disable_irq(unsigned int); extern void disable_irq_nosync(unsigned int); extern void enable_irq(unsigned int); + +#ifdef CONFIG_X86_LOCAL_APIC +#define ARCH_HAS_NMI_WATCHDOG /* See include/linux/irq.h */ +#endif #endif /* _ASM_IRQ_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/kmap_types.h linux.ac/include/asm-i386/kmap_types.h --- linux.vanilla/include/asm-i386/kmap_types.h Thu Nov 11 18:33:42 1999 +++ linux.ac/include/asm-i386/kmap_types.h Sat Apr 14 01:38:27 2001 @@ -4,6 +4,8 @@ enum km_type { KM_BOUNCE_READ, KM_BOUNCE_WRITE, + KM_SKB_DATA, + KM_SKB_DATA_SOFTIRQ, KM_TYPE_NR }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/linux_logo.h linux.ac/include/asm-i386/linux_logo.h --- linux.vanilla/include/asm-i386/linux_logo.h Thu Feb 22 00:11:44 2001 +++ linux.ac/include/asm-i386/linux_logo.h Sat Apr 14 15:09:45 2001 @@ -40,9 +40,6 @@ extern unsigned char linux_logo_blue[]; extern unsigned char linux_logo[]; extern unsigned char linux_logo_bw[]; -extern unsigned char linux_logo16_red[]; -extern unsigned char linux_logo16_green[]; -extern unsigned char linux_logo16_blue[]; extern unsigned char linux_logo16[]; #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/mpspec.h linux.ac/include/asm-i386/mpspec.h --- linux.vanilla/include/asm-i386/mpspec.h Fri Sep 8 15:37:08 2000 +++ linux.ac/include/asm-i386/mpspec.h Tue Apr 3 17:55:14 2001 @@ -182,6 +182,7 @@ extern int mp_current_pci_id; extern unsigned long mp_lapic_addr; extern int pic_mode; +extern int using_apic_timer; #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/msr.h linux.ac/include/asm-i386/msr.h --- linux.vanilla/include/asm-i386/msr.h Mon Dec 11 21:42:08 2000 +++ linux.ac/include/asm-i386/msr.h Tue Apr 3 17:55:14 2001 @@ -1,3 +1,6 @@ +#ifndef __ASM_MSR_H +#define __ASM_MSR_H + /* * Access to machine-specific registers (available on 586 and better only) * Note: the rd* operations modify the parameters directly (without using @@ -5,9 +8,9 @@ */ #define rdmsr(msr,val1,val2) \ - __asm__ __volatile__("rdmsr" \ - : "=a" (val1), "=d" (val2) \ - : "c" (msr)) + __asm__ __volatile__("rdmsr" \ + : "=a" (val1), "=d" (val2) \ + : "c" (msr)) #define wrmsr(msr,val1,val2) \ __asm__ __volatile__("wrmsr" \ @@ -18,10 +21,10 @@ __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) #define rdtscl(low) \ - __asm__ __volatile__ ("rdtsc" : "=a" (low) : : "edx") + __asm__ __volatile__("rdtsc" : "=a" (low) : : "edx") #define rdtscll(val) \ - __asm__ __volatile__ ("rdtsc" : "=A" (val)) + __asm__ __volatile__("rdtsc" : "=A" (val)) #define write_tsc(val1,val2) wrmsr(0x10, val1, val2) @@ -31,6 +34,40 @@ : "c" (counter)) /* symbolic names for some interesting MSRs */ -#define MSR_IA32_PLATFORM_ID 0x17 -#define MSR_IA32_UCODE_WRITE 0x79 -#define MSR_IA32_UCODE_REV 0x8B +#define MSR_IA32_PLATFORM_ID 0x017 + +#define MSR_IA32_APICBASE 0x01b +#define MSR_IA32_APICBASE_BSP (1<<8) +#define MSR_IA32_APICBASE_ENABLE (1<<11) +#define MSR_IA32_APICBASE_BASE (0xfffff<<12) + +#define MSR_IA32_UCODE_WRITE 0x079 +#define MSR_IA32_UCODE_REV 0x08b + +#define MSR_IA32_PERFCTR0 0x0c1 +#define MSR_IA32_PERFCTR1 0x0c2 + +#define MSR_IA32_MCG_CAP 0x179 +#define MSR_IA32_MCG_STATUS 0x17a +#define MSR_IA32_MCG_CTL 0x17b + +#define MSR_IA32_EVNTSEL0 0x186 +#define MSR_IA32_EVNTSEL1 0x187 + +#define MSR_IA32_DEBUGCTLMSR 0x1d9 +#define MSR_IA32_LASTBRANCHFROMIP 0x1db +#define MSR_IA32_LASTBRANCHTOIP 0x1dc +#define MSR_IA32_LASTINTFROMIP 0x1dd +#define MSR_IA32_LASTINTTOIP 0x1de + +#define MSR_IA32_MC0_BASE 0x400 +#define MSR_IA32_MC0_CTL_OFFSET 0x0 +#define MSR_IA32_MC0_STATUS_OFFSET 0x1 +#define MSR_IA32_MC0_ADDR_OFFSET 0x2 +#define MSR_IA32_MC0_MISC_OFFSET 0x3 +#define MSR_IA32_MC0_BANK_COUNT 0x4 + +#define MSR_K7_EVNTSEL0 0xC0010000 +#define MSR_K7_PERFCTR0 0xC0010004 + +#endif /* __ASM_MSR_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/mtrr.h linux.ac/include/asm-i386/mtrr.h --- linux.vanilla/include/asm-i386/mtrr.h Thu Feb 22 00:09:56 2001 +++ linux.ac/include/asm-i386/mtrr.h Fri Apr 13 18:01:39 2001 @@ -88,6 +88,7 @@ unsigned int type, char increment); extern int mtrr_del (int reg, unsigned long base, unsigned long size); extern int mtrr_del_page (int reg, unsigned long base, unsigned long size); +extern void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi); # else static __inline__ int mtrr_add (unsigned long base, unsigned long size, unsigned int type, char increment) @@ -109,6 +110,9 @@ { return -ENODEV; } + +static __inline__ void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) {;} + # endif /* The following functions are for initialisation: don't use them! */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/page.h linux.ac/include/asm-i386/page.h --- linux.vanilla/include/asm-i386/page.h Thu Feb 22 00:09:56 2001 +++ linux.ac/include/asm-i386/page.h Tue Apr 3 18:11:10 2001 @@ -86,10 +86,16 @@ * Tell the user there is some problem. Beep too, so we can * see^H^H^Hhear bugs in early bootup as well! */ -#define BUG() do { \ - printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ - __asm__ __volatile__(".byte 0x0f,0x0b"); \ + +#ifdef CONFIG_DEBUG_BUGVERBOSE +extern void do_BUG(const char *file, int line); +#define BUG() do { \ + do_BUG(__FILE__, __LINE__); \ + __asm__ __volatile__(".byte 0x0f,0x0b"); \ } while (0) +#else +#define BUG() __asm__ __volatile__(".byte 0x0f,0x0b") +#endif #define PAGE_BUG(page) do { \ BUG(); \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/pci.h linux.ac/include/asm-i386/pci.h --- linux.vanilla/include/asm-i386/pci.h Tue Apr 3 17:32:27 2001 +++ linux.ac/include/asm-i386/pci.h Tue Apr 17 17:44:38 2001 @@ -59,6 +59,7 @@ { if (direction == PCI_DMA_NONE) BUG(); + flush_write_buffers(); return virt_to_bus(ptr); } @@ -97,6 +98,7 @@ { if (direction == PCI_DMA_NONE) BUG(); + flush_write_buffers(); return nents; } @@ -127,7 +129,7 @@ { if (direction == PCI_DMA_NONE) BUG(); - /* Nothing to do */ + flush_write_buffers(); } /* Make physical memory consistent for a set of streaming @@ -142,7 +144,7 @@ { if (direction == PCI_DMA_NONE) BUG(); - /* Nothing to do */ + flush_write_buffers(); } /* Return whether the given PCI device DMA address mask can diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/pgalloc.h linux.ac/include/asm-i386/pgalloc.h --- linux.vanilla/include/asm-i386/pgalloc.h Tue Apr 3 17:32:27 2001 +++ linux.ac/include/asm-i386/pgalloc.h Sat Apr 14 15:05:37 2001 @@ -20,13 +20,19 @@ #if CONFIG_X86_PAE -extern void *kmalloc(size_t, int); -extern void kfree(const void *); +struct kmem_cache_s; + +extern struct kmem_cache_s *pae_pgd_cachep; + +extern void *kmem_cache_alloc(struct kmem_cache_s *, int); +extern void kmem_cache_free(struct kmem_cache_s *, void *); + +extern void init_pae_pgd_cache(void); extern __inline__ pgd_t *get_pgd_slow(void) { int i; - pgd_t *pgd = kmalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL); + pgd_t *pgd = kmem_cache_alloc(pae_pgd_cachep, GFP_KERNEL); if (pgd) { for (i = 0; i < USER_PTRS_PER_PGD; i++) { @@ -42,7 +48,7 @@ out_oom: for (i--; i >= 0; i--) free_page((unsigned long)__va(pgd_val(pgd[i])-1)); - kfree(pgd); + kmem_cache_free(pae_pgd_cachep, pgd); return NULL; } @@ -88,7 +94,7 @@ for (i = 0; i < USER_PTRS_PER_PGD; i++) free_page((unsigned long)__va(pgd_val(pgd[i])-1)); - kfree(pgd); + kmem_cache_free(pae_pgd_cachep, pgd); #else free_page((unsigned long)pgd); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/processor.h linux.ac/include/asm-i386/processor.h --- linux.vanilla/include/asm-i386/processor.h Thu Feb 22 00:09:57 2001 +++ linux.ac/include/asm-i386/processor.h Tue Apr 3 18:11:10 2001 @@ -44,6 +44,7 @@ char x86_model_id[64]; int x86_cache_size; /* in KB - valid for CPUS which support this call */ + __u16 clockmul; /* Clock multiplier */ int fdiv_bug; int f00f_bug; int coma_bug; @@ -88,6 +89,7 @@ #define cpu_has_fxsr (test_bit(X86_FEATURE_FXSR, boot_cpu_data.x86_capability)) #define cpu_has_xmm (test_bit(X86_FEATURE_XMM, boot_cpu_data.x86_capability)) #define cpu_has_fpu (test_bit(X86_FEATURE_FPU, boot_cpu_data.x86_capability)) +#define cpu_has_apic (test_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability)) extern char ignore_irq13; @@ -471,5 +473,33 @@ { __asm__ __volatile__("rep;nop"); } + +/* Prefetch instructions for Pentium III and AMD Athlon */ +#ifdef CONFIG_M686FXSR + +#define ARCH_HAS_PREFETCH +extern inline void prefetch(void *x) +{ + __asm__ __volatile__ ("prefetchnta (%0)" : : "r"(x)); +} + +#elif CONFIG_X86_USE_3DNOW + +#define ARCH_HAS_PREFETCH +#define ARCH_HAS_PREFETCHW +#define ARCH_HAS_SPINLOCK_PREFETCH + +extern inline void prefetch(void *x) +{ + __asm__ __volatile__ ("prefetch (%0)" : : "r"(x)); +} + +extern inline void prefetchw(void *x) +{ + __asm__ __volatile__ ("prefetch (%0)" : : "r"(x)); +} +#define spin_lock_prefetch(x) prefetchw(x) + +#endif #endif /* __ASM_I386_PROCESSOR_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/ptrace.h linux.ac/include/asm-i386/ptrace.h --- linux.vanilla/include/asm-i386/ptrace.h Mon Oct 30 22:46:53 2000 +++ linux.ac/include/asm-i386/ptrace.h Tue Apr 3 17:55:15 2001 @@ -58,6 +58,7 @@ #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs)) #define instruction_pointer(regs) ((regs)->eip) extern void show_regs(struct pt_regs *); +extern void show_registers(struct pt_regs *regs); #endif #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/rwsem-spin.h linux.ac/include/asm-i386/rwsem-spin.h --- linux.vanilla/include/asm-i386/rwsem-spin.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-i386/rwsem-spin.h Sat Apr 14 19:12:38 2001 @@ -0,0 +1,324 @@ +/* rwsem.h: R/W semaphores based on spinlocks + * + * Written by David Howells (dhowells@redhat.com). + * + * Derived from asm-i386/semaphore.h and asm-i386/spinlock.h + */ + +#ifndef _I386_RWSEM_SPIN_H +#define _I386_RWSEM_SPIN_H + +#include <linux/config.h> + +#ifndef _LINUX_RWSEM_H +#error please dont include asm/rwsem-spin.h directly, use linux/rwsem.h instead +#endif + +#include <linux/spinlock.h> + +#ifdef __KERNEL__ + +#define CONFIG_USING_SPINLOCK_BASED_RWSEM 1 + +/* + * the semaphore definition + */ +struct rw_semaphore { + signed long count; +#define RWSEM_UNLOCKED_VALUE 0x00000000 +#define RWSEM_ACTIVE_BIAS 0x00000001 +#define RWSEM_ACTIVE_MASK 0x0000ffff +#define RWSEM_WAITING_BIAS (-0x00010000) +#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS +#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) + spinlock_t lock; +#define RWSEM_SPINLOCK_OFFSET_STR "4" /* byte offset of spinlock */ + wait_queue_head_t wait; +#define RWSEM_WAITING_FOR_READ WQ_FLAG_CONTEXT_0 /* bits to use in wait_queue_t.flags */ +#define RWSEM_WAITING_FOR_WRITE WQ_FLAG_CONTEXT_1 +#if RWSEM_DEBUG + int debug; +#endif +#if RWSEM_DEBUG_MAGIC + long __magic; + atomic_t readers; + atomic_t writers; +#endif +}; + +/* + * initialisation + */ +#if RWSEM_DEBUG +#define __RWSEM_DEBUG_INIT , 0 +#else +#define __RWSEM_DEBUG_INIT /* */ +#endif +#if RWSEM_DEBUG_MAGIC +#define __RWSEM_DEBUG_MINIT(name) , (int)&(name).__magic, ATOMIC_INIT(0), ATOMIC_INIT(0) +#else +#define __RWSEM_DEBUG_MINIT(name) /* */ +#endif + +#define __RWSEM_INITIALIZER(name,count) \ +{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \ + __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ + __RWSEM_DEBUG_INIT __RWSEM_DEBUG_MINIT(name) } + +#define __DECLARE_RWSEM_GENERIC(name,count) \ + struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) + +#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS) +#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1) +#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0) + +static inline void init_rwsem(struct rw_semaphore *sem) +{ + sem->count = RWSEM_UNLOCKED_VALUE; + spin_lock_init(&sem->lock); + init_waitqueue_head(&sem->wait); +#if RWSEM_DEBUG + sem->debug = 0; +#endif +#if RWSEM_DEBUG_MAGIC + sem->__magic = (long)&sem->__magic; + atomic_set(&sem->readers, 0); + atomic_set(&sem->writers, 0); +#endif +} + +/* + * lock for reading + */ +static inline void __down_read(struct rw_semaphore *sem) +{ + __asm__ __volatile__( + "# beginning down_read\n\t" +#ifdef CONFIG_SMP +LOCK_PREFIX " decb "RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* try to grab the spinlock */ + " js 3f\n" /* jump if failed */ + "1:\n\t" +#endif + " incl (%%eax)\n\t" /* adds 0x00000001, returns the old value */ +#ifdef CONFIG_SMP + " movb $1,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* release the spinlock */ +#endif + " js 4f\n\t" /* jump if we weren't granted the lock */ + "2:\n" + ".section .text.lock,\"ax\"\n" +#ifdef CONFIG_SMP + "3:\n\t" /* spin on the spinlock till we get it */ + " cmpb $0,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" + " rep;nop \n\t" + " jle 3b\n\t" + " jmp 1b\n" +#endif + "4:\n\t" + " call __rwsem_down_read_failed\n\t" + " jmp 2b\n" + ".previous" + "# ending __down_read\n\t" + : "=m"(sem->count), "=m"(sem->lock) + : "a"(sem), "m"(sem->count), "m"(sem->lock) + : "memory"); +} + +/* + * lock for writing + */ +static inline void __down_write(struct rw_semaphore *sem) +{ + int tmp; + + tmp = RWSEM_ACTIVE_WRITE_BIAS; + __asm__ __volatile__( + "# beginning down_write\n\t" +#ifdef CONFIG_SMP +LOCK_PREFIX " decb "RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* try to grab the spinlock */ + " js 3f\n" /* jump if failed */ + "1:\n\t" +#endif + " xchg %0,(%%eax)\n\t" /* retrieve the old value */ + " add %0,(%%eax)\n\t" /* add 0xffff0001, result in memory */ +#ifdef CONFIG_SMP + " movb $1,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* release the spinlock */ +#endif + " testl %0,%0\n\t" /* was the count 0 before? */ + " jnz 4f\n\t" /* jump if we weren't granted the lock */ + "2:\n\t" + ".section .text.lock,\"ax\"\n" +#ifdef CONFIG_SMP + "3:\n\t" /* spin on the spinlock till we get it */ + " cmpb $0,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" + " rep;nop \n\t" + " jle 3b\n\t" + " jmp 1b\n" +#endif + "4:\n\t" + " call __rwsem_down_write_failed\n\t" + " jmp 2b\n" + ".previous\n" + "# ending down_write" + : "+r"(tmp), "=m"(sem->count), "=m"(sem->lock) + : "a"(sem), "m"(sem->count), "m"(sem->lock) + : "memory"); +} + +/* + * unlock after reading + */ +static inline void __up_read(struct rw_semaphore *sem) +{ + int tmp; + + tmp = -RWSEM_ACTIVE_READ_BIAS; + __asm__ __volatile__( + "# beginning __up_read\n\t" +#ifdef CONFIG_SMP +LOCK_PREFIX " decb "RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* try to grab the spinlock */ + " js 3f\n" /* jump if failed */ + "1:\n\t" +#endif + " xchg %0,(%%eax)\n\t" /* retrieve the old value */ + " addl %0,(%%eax)\n\t" /* subtract 1, result in memory */ +#ifdef CONFIG_SMP + " movb $1,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* release the spinlock */ +#endif + " js 4f\n\t" /* jump if the lock is being waited upon */ + "2:\n\t" + ".section .text.lock,\"ax\"\n" +#ifdef CONFIG_SMP + "3:\n\t" /* spin on the spinlock till we get it */ + " cmpb $0,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" + " rep;nop \n\t" + " jle 3b\n\t" + " jmp 1b\n" +#endif + "4:\n\t" + " decl %0\n\t" /* xchg gave us the old count */ + " testl %4,%0\n\t" /* do nothing if still outstanding active readers */ + " jnz 2b\n\t" + " call __rwsem_wake\n\t" + " jmp 2b\n" + ".previous\n" + "# ending __up_read\n" + : "+r"(tmp), "=m"(sem->count), "=m"(sem->lock) + : "a"(sem), "i"(RWSEM_ACTIVE_MASK), "m"(sem->count), "m"(sem->lock) + : "memory"); +} + +/* + * unlock after writing + */ +static inline void __up_write(struct rw_semaphore *sem) +{ + __asm__ __volatile__( + "# beginning __up_write\n\t" +#ifdef CONFIG_SMP +LOCK_PREFIX " decb "RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* try to grab the spinlock */ + " js 3f\n" /* jump if failed */ + "1:\n\t" +#endif + " addl %3,(%%eax)\n\t" /* adds 0x00010001 */ +#ifdef CONFIG_SMP + " movb $1,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* release the spinlock */ +#endif + " js 4f\n\t" /* jump if the lock is being waited upon */ + "2:\n\t" + ".section .text.lock,\"ax\"\n" +#ifdef CONFIG_SMP + "3:\n\t" /* spin on the spinlock till we get it */ + " cmpb $0,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" + " rep;nop \n\t" + " jle 3b\n\t" + " jmp 1b\n" +#endif + "4:\n\t" + " call __rwsem_wake\n\t" + " jmp 2b\n" + ".previous\n" + "# ending __up_write\n" + : "=m"(sem->count), "=m"(sem->lock) + : "a"(sem), "i"(-RWSEM_ACTIVE_WRITE_BIAS), "m"(sem->count), "m"(sem->lock) + : "memory"); +} + +/* + * implement exchange and add functionality + */ +static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) +{ + int tmp = delta; + + __asm__ __volatile__( + "# beginning rwsem_atomic_update\n\t" +#ifdef CONFIG_SMP +LOCK_PREFIX " decb "RWSEM_SPINLOCK_OFFSET_STR"(%1)\n\t" /* try to grab the spinlock */ + " js 3f\n" /* jump if failed */ + "1:\n\t" +#endif + " xchgl %0,(%1)\n\t" /* retrieve the old value */ + " addl %0,(%1)\n\t" /* add 0xffff0001, result in memory */ +#ifdef CONFIG_SMP + " movb $1,"RWSEM_SPINLOCK_OFFSET_STR"(%1)\n\t" /* release the spinlock */ +#endif + ".section .text.lock,\"ax\"\n" +#ifdef CONFIG_SMP + "3:\n\t" /* spin on the spinlock till we get it */ + " cmpb $0,"RWSEM_SPINLOCK_OFFSET_STR"(%1)\n\t" + " rep;nop \n\t" + " jle 3b\n\t" + " jmp 1b\n" +#endif + ".previous\n" + "# ending rwsem_atomic_update\n\t" + : "+r"(tmp) + : "r"(sem) + : "memory"); + + return tmp+delta; +} + +/* + * implement compare and exchange functionality on the rw-semaphore count LSW + */ +static inline __u16 rwsem_cmpxchgw(struct rw_semaphore *sem, __u16 old, __u16 new) +{ + __u16 prev; + + __asm__ __volatile__( + "# beginning rwsem_cmpxchgw\n\t" +#ifdef CONFIG_SMP +LOCK_PREFIX " decb "RWSEM_SPINLOCK_OFFSET_STR"(%3)\n\t" /* try to grab the spinlock */ + " js 3f\n" /* jump if failed */ + "1:\n\t" +#endif + " cmpw %w1,(%3)\n\t" + " jne 4f\n\t" /* jump if old doesn't match sem->count LSW */ + " movw %w2,(%3)\n\t" /* replace sem->count LSW with the new value */ + "2:\n\t" +#ifdef CONFIG_SMP + " movb $1,"RWSEM_SPINLOCK_OFFSET_STR"(%3)\n\t" /* release the spinlock */ +#endif + ".section .text.lock,\"ax\"\n" +#ifdef CONFIG_SMP + "3:\n\t" /* spin on the spinlock till we get it */ + " cmpb $0,"RWSEM_SPINLOCK_OFFSET_STR"(%3)\n\t" + " rep;nop \n\t" + " jle 3b\n\t" + " jmp 1b\n" +#endif + "4:\n\t" + " movw (%3),%w0\n" /* we'll want to return the current value */ + " jmp 2b\n" + ".previous\n" + "# ending rwsem_cmpxchgw\n\t" + : "=r"(prev) + : "r0"(old), "r"(new), "r"(sem) + : "memory"); + + return prev; +} + +#endif /* __KERNEL__ */ +#endif /* _I386_RWSEM_SPIN_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/rwsem-xadd.h linux.ac/include/asm-i386/rwsem-xadd.h --- linux.vanilla/include/asm-i386/rwsem-xadd.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-i386/rwsem-xadd.h Sat Apr 14 01:38:33 2001 @@ -0,0 +1,198 @@ +/* rwsem-xadd.h: R/W semaphores implemented using XADD/CMPXCHG + * + * Written by David Howells (dhowells@redhat.com), 2001. + * Derived from asm-i386/semaphore.h + */ + +#ifndef _I386_RWSEM_XADD_H +#define _I386_RWSEM_XADD_H + +#ifndef _LINUX_RWSEM_H +#error please dont include asm/rwsem-xadd.h directly, use linux/rwsem.h instead +#endif + +#ifdef __KERNEL__ + +/* + * the semaphore definition + */ +struct rw_semaphore { + signed long count; +#define RWSEM_UNLOCKED_VALUE 0x00000000 +#define RWSEM_ACTIVE_BIAS 0x00000001 +#define RWSEM_ACTIVE_MASK 0x0000ffff +#define RWSEM_WAITING_BIAS (-0x00010000) +#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS +#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) + wait_queue_head_t wait; +#define RWSEM_WAITING_FOR_READ WQ_FLAG_CONTEXT_0 /* bits to use in wait_queue_t.flags */ +#define RWSEM_WAITING_FOR_WRITE WQ_FLAG_CONTEXT_1 +#if RWSEM_DEBUG + int debug; +#endif +#if RWSEM_DEBUG_MAGIC + long __magic; + atomic_t readers; + atomic_t writers; +#endif +}; + +/* + * initialisation + */ +#if RWSEM_DEBUG +#define __RWSEM_DEBUG_INIT , 0 +#else +#define __RWSEM_DEBUG_INIT /* */ +#endif +#if RWSEM_DEBUG_MAGIC +#define __RWSEM_DEBUG_MINIT(name) , (int)&(name).__magic, ATOMIC_INIT(0), ATOMIC_INIT(0) +#else +#define __RWSEM_DEBUG_MINIT(name) /* */ +#endif + +#define __RWSEM_INITIALIZER(name,count) \ +{ RWSEM_UNLOCKED_VALUE, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ + __RWSEM_DEBUG_INIT __RWSEM_DEBUG_MINIT(name) } + +#define __DECLARE_RWSEM_GENERIC(name,count) \ + struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) + +#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS) +#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1) +#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0) + +static inline void init_rwsem(struct rw_semaphore *sem) +{ + sem->count = RWSEM_UNLOCKED_VALUE; + init_waitqueue_head(&sem->wait); +#if RWSEM_DEBUG + sem->debug = 0; +#endif +#if RWSEM_DEBUG_MAGIC + sem->__magic = (long)&sem->__magic; + atomic_set(&sem->readers, 0); + atomic_set(&sem->writers, 0); +#endif +} + +/* + * lock for reading + */ +static inline void __down_read(struct rw_semaphore *sem) +{ + __asm__ __volatile__( + "# beginning down_read\n\t" +LOCK_PREFIX " incl (%%eax)\n\t" /* adds 0x00000001, returns the old value */ + " js 2f\n\t" /* jump if we weren't granted the lock */ + "1:\n\t" + ".section .text.lock,\"ax\"\n" + "2:\n\t" + " call __rwsem_down_read_failed\n\t" + " jmp 1b\n" + ".previous" + "# ending down_read\n\t" + : "=m"(sem->count) + : "a"(sem), "m"(sem->count) + : "memory"); +} + +/* + * lock for writing + */ +static inline void __down_write(struct rw_semaphore *sem) +{ + int tmp; + + tmp = RWSEM_ACTIVE_WRITE_BIAS; + __asm__ __volatile__( + "# beginning down_write\n\t" +LOCK_PREFIX " xadd %0,(%%eax)\n\t" /* subtract 0x00010001, returns the old value */ + " testl %0,%0\n\t" /* was the count 0 before? */ + " jnz 2f\n\t" /* jump if we weren't granted the lock */ + "1:\n\t" + ".section .text.lock,\"ax\"\n" + "2:\n\t" + " call __rwsem_down_write_failed\n\t" + " jmp 1b\n" + ".previous\n" + "# ending down_write" + : "+r"(tmp), "=m"(sem->count) + : "a"(sem), "m"(sem->count) + : "memory"); +} + +/* + * unlock after reading + */ +static inline void __up_read(struct rw_semaphore *sem) +{ + int tmp; + + tmp = -RWSEM_ACTIVE_READ_BIAS; + __asm__ __volatile__( + "# beginning __up_read\n\t" +LOCK_PREFIX " xadd %0,(%%eax)\n\t" /* subtracts 1, returns the old value */ + " js 2f\n\t" /* jump if the lock is being waited upon */ + "1:\n\t" + ".section .text.lock,\"ax\"\n" + "2:\n\t" + " decl %0\n\t" /* xadd gave us the old count */ + " testl %3,%0\n\t" /* do nothing if still outstanding active readers */ + " jnz 1b\n\t" + " call __rwsem_wake\n\t" + " jmp 1b\n" + ".previous\n" + "# ending __up_read\n" + : "+r"(tmp), "=m"(sem->count) + : "a"(sem), "i"(RWSEM_ACTIVE_MASK), "m"(sem->count) + : "memory"); +} + +/* + * unlock after writing + */ +static inline void __up_write(struct rw_semaphore *sem) +{ + __asm__ __volatile__( + "# beginning __up_write\n\t" +LOCK_PREFIX " addl %2,(%%eax)\n\t" /* adds 0x0000ffff */ + " js 2f\n\t" /* jump if the lock is being waited upon */ + "1:\n\t" + ".section .text.lock,\"ax\"\n" + "2:\n\t" + " call __rwsem_wake\n\t" + " jmp 1b\n" + ".previous\n" + "# ending __up_write\n" + : "=m"(sem->count) + : "a"(sem), "i"(-RWSEM_ACTIVE_WRITE_BIAS), "m"(sem->count) + : "memory"); +} + +/* + * implement exchange and add functionality + */ +static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) +{ + int tmp = delta; + + __asm__ __volatile__( + LOCK_PREFIX "xadd %0,(%1)" + : "+r"(tmp) + : "r"(sem) + : "memory"); + + return tmp+delta; +} + +/* + * implement compare and exchange functionality on the rw-semaphore count LSW + */ +static inline __u16 rwsem_cmpxchgw(struct rw_semaphore *sem, __u16 old, __u16 new) +{ + return cmpxchg((__u16*)&sem->count,0,RWSEM_ACTIVE_BIAS); +} + +#endif /* __KERNEL__ */ +#endif /* _I386_RWSEM_XADD_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/rwsem.h linux.ac/include/asm-i386/rwsem.h --- linux.vanilla/include/asm-i386/rwsem.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-i386/rwsem.h Sat Apr 14 19:12:38 2001 @@ -0,0 +1,30 @@ +/* rwsem.h: R/W semaphores based on spinlocks + * + * Written by David Howells (dhowells@redhat.com). + * + * Derived from asm-i386/semaphore.h + */ + +#ifndef _I386_RWSEM_H +#define _I386_RWSEM_H + +#ifndef _LINUX_RWSEM_H +#error please dont include asm/rwsem.h directly, use linux/rwsem.h instead +#endif + +#ifdef __KERNEL__ + +#define __HAVE_ARCH_SPECIFIC_RWSEM_IMPLEMENTATION 1 +#ifdef CONFIG_X86_XADD +#include <asm/rwsem-xadd.h> /* use XADD based semaphores if possible */ +#else +#include <asm/rwsem-spin.h> /* use optimised spinlock based semaphores otherwise */ +#endif + +/* we use FASTCALL convention for the helpers */ +extern struct rw_semaphore *FASTCALL(__rwsem_down_read_failed(struct rw_semaphore *sem)); +extern struct rw_semaphore *FASTCALL(__rwsem_down_write_failed(struct rw_semaphore *sem)); +extern struct rw_semaphore *FASTCALL(__rwsem_wake(struct rw_semaphore *sem)); + +#endif /* __KERNEL__ */ +#endif /* _I386_RWSEM_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/semaphore.h linux.ac/include/asm-i386/semaphore.h --- linux.vanilla/include/asm-i386/semaphore.h Thu Feb 22 00:09:57 2001 +++ linux.ac/include/asm-i386/semaphore.h Sat Apr 14 19:12:38 2001 @@ -38,8 +38,8 @@ #include <asm/system.h> #include <asm/atomic.h> -#include <asm/rwlock.h> #include <linux/wait.h> +#include <linux/rwsem.h> struct semaphore { atomic_t count; @@ -131,6 +131,10 @@ :"memory"); } +/* + * Interruptible try to acquire a semaphore. If we obtained + * it, return zero. If we were interrupted, returns -EINTR + */ static inline int down_interruptible(struct semaphore * sem) { int result; @@ -155,6 +159,10 @@ return result; } +/* + * Non-blockingly attempt to down() a semaphore. + * Returns zero if we acquired it + */ static inline int down_trylock(struct semaphore * sem) { int result; @@ -202,184 +210,6 @@ :"=m" (sem->count) :"c" (sem) :"memory"); -} - -/* rw mutexes (should that be mutices? =) -- throw rw - * spinlocks and semaphores together, and this is what we - * end up with... - * - * The lock is initialized to BIAS. This way, a writer - * subtracts BIAS ands gets 0 for the case of an uncontended - * lock. Readers decrement by 1 and see a positive value - * when uncontended, negative if there are writers waiting - * (in which case it goes to sleep). - * - * The value 0x01000000 supports up to 128 processors and - * lots of processes. BIAS must be chosen such that subl'ing - * BIAS once per CPU will result in the long remaining - * negative. - * - * In terms of fairness, this should result in the lock - * flopping back and forth between readers and writers - * under heavy use. - * - * -ben - */ -struct rw_semaphore { - atomic_t count; - volatile unsigned char write_bias_granted; - volatile unsigned char read_bias_granted; - volatile unsigned char pad1; - volatile unsigned char pad2; - wait_queue_head_t wait; - wait_queue_head_t write_bias_wait; -#if WAITQUEUE_DEBUG - long __magic; - atomic_t readers; - atomic_t writers; -#endif -}; - -#if WAITQUEUE_DEBUG -#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0) -#else -#define __RWSEM_DEBUG_INIT /* */ -#endif - -#define __RWSEM_INITIALIZER(name,count) \ -{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ - __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \ - __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT } - -#define __DECLARE_RWSEM_GENERIC(name,count) \ - struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) - -#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS) -#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1) -#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0) - -static inline void init_rwsem(struct rw_semaphore *sem) -{ - atomic_set(&sem->count, RW_LOCK_BIAS); - sem->read_bias_granted = 0; - sem->write_bias_granted = 0; - init_waitqueue_head(&sem->wait); - init_waitqueue_head(&sem->write_bias_wait); -#if WAITQUEUE_DEBUG - sem->__magic = (long)&sem->__magic; - atomic_set(&sem->readers, 0); - atomic_set(&sem->writers, 0); -#endif -} - -/* we use FASTCALL convention for the helpers */ -extern struct rw_semaphore *FASTCALL(__down_read_failed(struct rw_semaphore *sem)); -extern struct rw_semaphore *FASTCALL(__down_write_failed(struct rw_semaphore *sem)); -extern struct rw_semaphore *FASTCALL(__rwsem_wake(struct rw_semaphore *sem)); - -static inline void down_read(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (sem->__magic != (long)&sem->__magic) - BUG(); -#endif - __build_read_lock(sem, "__down_read_failed"); -#if WAITQUEUE_DEBUG - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_inc(&sem->readers); -#endif -} - -static inline void down_write(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (sem->__magic != (long)&sem->__magic) - BUG(); -#endif - __build_write_lock(sem, "__down_write_failed"); -#if WAITQUEUE_DEBUG - if (atomic_read(&sem->writers)) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (sem->read_bias_granted) - BUG(); - if (sem->write_bias_granted) - BUG(); - atomic_inc(&sem->writers); -#endif -} - -/* When a reader does a release, the only significant - * case is when there was a writer waiting, and we've - * bumped the count to 0: we must wake the writer up. - */ -static inline void __up_read(struct rw_semaphore *sem) -{ - __asm__ __volatile__( - "# up_read\n\t" - LOCK "incl %0\n\t" - "jz 2f\n" /* only do the wake if result == 0 (ie, a writer) */ - "1:\n\t" - ".section .text.lock,\"ax\"\n" - "2:\tcall __rwsem_wake\n\t" - "jmp 1b\n" - ".previous" - :"=m" (sem->count) - :"a" (sem) - :"memory" - ); -} - -/* releasing the writer is easy -- just release it and - * wake up any sleepers. - */ -static inline void __up_write(struct rw_semaphore *sem) -{ - __asm__ __volatile__( - "# up_write\n\t" - LOCK "addl $" RW_LOCK_BIAS_STR ",%0\n" - "jc 2f\n" /* only do the wake if the result was -'ve to 0/+'ve */ - "1:\n\t" - ".section .text.lock,\"ax\"\n" - "2:\tcall __rwsem_wake\n\t" - "jmp 1b\n" - ".previous" - :"=m" (sem->count) - :"a" (sem) - :"memory" - ); -} - -static inline void up_read(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_dec(&sem->readers); -#endif - __up_read(sem); -} - -static inline void up_write(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (sem->read_bias_granted) - BUG(); - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (atomic_read(&sem->writers) != 1) - BUG(); - atomic_dec(&sem->writers); -#endif - __up_write(sem); } #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/spinlock.h linux.ac/include/asm-i386/spinlock.h --- linux.vanilla/include/asm-i386/spinlock.h Thu Feb 22 00:09:57 2001 +++ linux.ac/include/asm-i386/spinlock.h Tue Apr 10 19:56:02 2001 @@ -4,6 +4,7 @@ #include <asm/atomic.h> #include <asm/rwlock.h> #include <asm/page.h> +#include <linux/config.h> extern int printk(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); @@ -12,7 +13,11 @@ * initialize their spinlocks properly, tsk tsk. * Remember to turn this off in 2.4. -ben */ +#if defined(CONFIG_DEBUG_SPINLOCK) +#define SPINLOCK_DEBUG 1 +#else #define SPINLOCK_DEBUG 0 +#endif /* * Your basic SMP spinlocks, allowing only a single CPU anywhere diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/string.h linux.ac/include/asm-i386/string.h --- linux.vanilla/include/asm-i386/string.h Tue Apr 3 17:32:27 2001 +++ linux.ac/include/asm-i386/string.h Fri Apr 13 18:37:31 2001 @@ -446,34 +446,8 @@ /* end of additional stuff */ #define __HAVE_ARCH_STRSTR -static inline char * strstr(const char * cs,const char * ct) -{ -int d0, d1; -register char * __res; -__asm__ __volatile__( - "movl %6,%%edi\n\t" - "repne\n\t" - "scasb\n\t" - "notl %%ecx\n\t" - "decl %%ecx\n\t" /* NOTE! This also sets Z if searchstring='' */ - "movl %%ecx,%%edx\n" - "1:\tmovl %6,%%edi\n\t" - "movl %%esi,%%eax\n\t" - "movl %%edx,%%ecx\n\t" - "repe\n\t" - "cmpsb\n\t" - "je 2f\n\t" /* also works for empty string, see above */ - "xchgl %%eax,%%esi\n\t" - "incl %%esi\n\t" - "cmpb $0,-1(%%eax)\n\t" - "jne 1b\n\t" - "xorl %%eax,%%eax\n\t" - "2:" - :"=a" (__res), "=&c" (d0), "=&S" (d1) - :"0" (0), "1" (0xffffffff), "2" (cs), "g" (ct) - :"dx", "di"); -return __res; -} + +extern char *strstr(const char *cs, const char *ct); /* * This looks horribly ugly, but the compiler can optimize it totally, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/system.h linux.ac/include/asm-i386/system.h --- linux.vanilla/include/asm-i386/system.h Tue Apr 3 17:32:27 2001 +++ linux.ac/include/asm-i386/system.h Sat Apr 14 15:05:37 2001 @@ -157,7 +157,7 @@ : "ax","dx","memory"); } -extern void inline __set_64bit_constant (unsigned long long *ptr, +extern inline void __set_64bit_constant (unsigned long long *ptr, unsigned long long value) { __set_64bit(ptr,(unsigned int)(value), (unsigned int)((value)>>32ULL)); @@ -165,7 +165,7 @@ #define ll_low(x) *(((unsigned int*)&(x))+0) #define ll_high(x) *(((unsigned int*)&(x))+1) -extern void inline __set_64bit_var (unsigned long long *ptr, +extern inline void __set_64bit_var (unsigned long long *ptr, unsigned long long value) { __set_64bit(ptr,ll_low(value), ll_high(value)); @@ -268,10 +268,19 @@ * I expect future Intel CPU's to have a weaker ordering, * but I'd also expect them to finally get their act together * and add some real memory barriers if so. + * + * Some non intel clones support out of order store. wmb() ceases to be a + * nop for these. */ + #define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory") #define rmb() mb() + +#ifdef CONFIG_X86_OOSTORE +#define wmb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory") +#else #define wmb() __asm__ __volatile__ ("": : :"memory") +#endif #ifdef CONFIG_SMP #define smp_mb() mb() @@ -326,5 +335,9 @@ #define HAVE_DISABLE_HLT void disable_hlt(void); void enable_hlt(void); + +#ifndef abs +#define abs(x) ((x)<0 ? -x : x) +#endif #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/timex.h linux.ac/include/asm-i386/timex.h --- linux.vanilla/include/asm-i386/timex.h Thu Feb 22 00:09:56 2001 +++ linux.ac/include/asm-i386/timex.h Sat Apr 14 20:38:32 2001 @@ -45,4 +45,6 @@ #endif } +extern unsigned long cpu_khz; + #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/tlb.h linux.ac/include/asm-i386/tlb.h --- linux.vanilla/include/asm-i386/tlb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-i386/tlb.h Tue Apr 3 17:55:15 2001 @@ -0,0 +1 @@ +#include <asm-generic/tlb.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/uaccess.h linux.ac/include/asm-i386/uaccess.h --- linux.vanilla/include/asm-i386/uaccess.h Thu Feb 22 00:09:58 2001 +++ linux.ac/include/asm-i386/uaccess.h Sun Apr 15 23:20:10 2001 @@ -542,6 +542,8 @@ { if (access_ok(VERIFY_READ, from, n)) __constant_copy_user_zeroing(to,from,n); + else + memset(to, 0, n); return n; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/a.out.h linux.ac/include/asm-ia64/a.out.h --- linux.vanilla/include/asm-ia64/a.out.h Thu Jan 4 20:50:17 2001 +++ linux.ac/include/asm-ia64/a.out.h Tue Apr 10 18:20:49 2001 @@ -30,7 +30,8 @@ #define N_TXTOFF(x) 0 #ifdef __KERNEL__ -# define STACK_TOP (0x8000000000000000UL + (1UL << (4*PAGE_SHIFT - 12))) +# include <asm/page.h> +# define STACK_TOP (0x8000000000000000UL + (1UL << (4*PAGE_SHIFT - 12)) - PAGE_SIZE) # define IA64_RBS_BOT (STACK_TOP - 0x80000000L) /* bottom of register backing store */ #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/acpikcfg.h linux.ac/include/asm-ia64/acpikcfg.h --- linux.vanilla/include/asm-ia64/acpikcfg.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/acpikcfg.h Tue Apr 10 18:20:49 2001 @@ -1,4 +1,5 @@ #include <linux/config.h> + #ifdef CONFIG_ACPI_KERNEL_CONFIG /* * acpikcfg.h - ACPI based Kernel Configuration Manager External Interfaces diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/asmmacro.h linux.ac/include/asm-ia64/asmmacro.h --- linux.vanilla/include/asm-ia64/asmmacro.h Sat Aug 12 03:09:06 2000 +++ linux.ac/include/asm-ia64/asmmacro.h Tue Apr 10 18:20:49 2001 @@ -2,26 +2,10 @@ #define _ASM_IA64_ASMMACRO_H /* - * Copyright (C) 2000 Hewlett-Packard Co - * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 2000-2001 Hewlett-Packard Co + * Copyright (C) 2000-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ -#if 1 - -/* - * This is a hack that's necessary as long as we support old versions - * of gas, that have no unwind support. - */ -#include <linux/config.h> - -#ifdef CONFIG_IA64_NEW_UNWIND -# define UNW(args...) args -#else -# define UNW(args...) -#endif - -#endif - #define ENTRY(name) \ .align 32; \ .proc name; \ @@ -44,5 +28,28 @@ #define ASM_UNW_PRLG_PSP 0x2 #define ASM_UNW_PRLG_PR 0x1 #define ASM_UNW_PRLG_GRSAVE(ninputs) (32+(ninputs)) + +/* + * Helper macros for accessing user memory. + */ + + .section "__ex_table", "a" // declare section & section attributes + .previous + +#if __GNUC__ >= 3 +# define EX(y,x...) \ + .xdata4 "__ex_table", @gprel(99f), @gprel(y); \ + [99:] x +# define EXCLR(y,x...) \ + .xdata4 "__ex_table", @gprel(99f), @gprel(y)+4; \ + [99:] x +#else +# define EX(y,x...) \ + .xdata4 "__ex_table", @gprel(99f), @gprel(y); \ + 99: x +# define EXCLR(y,x...) \ + .xdata4 "__ex_table", @gprel(99f), @gprel(y)+4; \ + 99: x +#endif #endif /* _ASM_IA64_ASMMACRO_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/bitops.h linux.ac/include/asm-ia64/bitops.h --- linux.vanilla/include/asm-ia64/bitops.h Tue Oct 10 01:54:57 2000 +++ linux.ac/include/asm-ia64/bitops.h Tue Apr 10 18:20:49 2001 @@ -158,6 +158,7 @@ __asm__ ("getf.exp %0=%1" : "=r"(exp) : "f"(d)); return exp - 0xffff; } + /* * ffs: find first bit set. This is defined the same way as * the libc and compiler builtin ffs routines, therefore diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/byteorder.h linux.ac/include/asm-ia64/byteorder.h --- linux.vanilla/include/asm-ia64/byteorder.h Mon Feb 7 02:42:40 2000 +++ linux.ac/include/asm-ia64/byteorder.h Tue Apr 10 18:20:49 2001 @@ -20,18 +20,18 @@ static __inline__ __const__ __u32 __ia64_swab32 (__u32 x) { - return __ia64_swab64 (x) >> 32; + return __ia64_swab64(x) >> 32; } static __inline__ __const__ __u16 __ia64_swab16(__u16 x) { - return __ia64_swab64 (x) >> 48; + return __ia64_swab64(x) >> 48; } -#define __arch__swab64(x) __ia64_swab64 (x) -#define __arch__swab32(x) __ia64_swab32 (x) -#define __arch__swab16(x) __ia64_swab16 (x) +#define __arch__swab64(x) __ia64_swab64(x) +#define __arch__swab32(x) __ia64_swab32(x) +#define __arch__swab16(x) __ia64_swab16(x) #define __BYTEORDER_HAS_U64__ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/cache.h linux.ac/include/asm-ia64/cache.h --- linux.vanilla/include/asm-ia64/cache.h Thu Jan 4 20:50:17 2001 +++ linux.ac/include/asm-ia64/cache.h Tue Apr 10 18:20:49 2001 @@ -9,7 +9,7 @@ */ /* Bytes per L1 (data) cache line. */ -#define L1_CACHE_SHIFT 6 +#define L1_CACHE_SHIFT CONFIG_IA64_L1_CACHE_SHIFT #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) #ifdef CONFIG_SMP diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/delay.h linux.ac/include/asm-ia64/delay.h --- linux.vanilla/include/asm-ia64/delay.h Thu Jan 4 20:50:17 2001 +++ linux.ac/include/asm-ia64/delay.h Tue Apr 10 18:20:49 2001 @@ -34,13 +34,9 @@ } static __inline__ void -ia64_set_itv (unsigned char vector, unsigned char masked) +ia64_set_itv (unsigned long val) { - if (masked > 1) - masked = 1; - - __asm__ __volatile__("mov cr.itv=%0;; srlz.d;;" - :: "r"((masked << 16) | vector) : "memory"); + __asm__ __volatile__("mov cr.itv=%0;; srlz.d;;" :: "r"(val) : "memory"); } static __inline__ void @@ -79,16 +75,11 @@ static __inline__ void udelay (unsigned long usecs) { -#ifdef CONFIG_IA64_SOFTSDV_HACKS - while (usecs--) - ; -#else unsigned long start = ia64_get_itc(); - unsigned long cycles = usecs*my_cpu_data.cyc_per_usec; + unsigned long cycles = usecs*local_cpu_data->cyc_per_usec; while (ia64_get_itc() - start < cycles) /* skip */; -#endif /* CONFIG_IA64_SOFTSDV_HACKS */ } #endif /* _ASM_IA64_DELAY_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/dma.h linux.ac/include/asm-ia64/dma.h --- linux.vanilla/include/asm-ia64/dma.h Thu Jun 22 15:09:45 2000 +++ linux.ac/include/asm-ia64/dma.h Tue Apr 10 18:20:49 2001 @@ -2,35 +2,20 @@ #define _ASM_IA64_DMA_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/config.h> -#include <linux/spinlock.h> /* And spinlocks */ -#include <linux/delay.h> #include <asm/io.h> /* need byte IO */ -#ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER -#define dma_outb outb_p -#else -#define dma_outb outb -#endif - -#define dma_inb inb - -#define MAX_DMA_CHANNELS 8 -#define MAX_DMA_ADDRESS 0xffffffffUL - -extern spinlock_t dma_spin_lock; - -/* From PCI */ +extern unsigned long MAX_DMA_ADDRESS; #ifdef CONFIG_PCI -extern int isa_dma_bridge_buggy; + extern int isa_dma_bridge_buggy; #else -#define isa_dma_bridge_buggy (0) +# define isa_dma_bridge_buggy (0) #endif #endif /* _ASM_IA64_DMA_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/efi.h linux.ac/include/asm-ia64/efi.h --- linux.vanilla/include/asm-ia64/efi.h Thu Jan 4 20:50:17 2001 +++ linux.ac/include/asm-ia64/efi.h Tue Apr 10 18:20:49 2001 @@ -4,7 +4,7 @@ /* * Extensible Firmware Interface * Based on 'Extensible Firmware Interface Specification' version 0.9, April 30, 1999 - * + * * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> * Copyright (C) 1999 Hewlett-Packard Co. @@ -20,9 +20,12 @@ #include <asm/system.h> #define EFI_SUCCESS 0 -#define EFI_INVALID_PARAMETER 2 -#define EFI_UNSUPPORTED 3 -#define EFI_BUFFER_TOO_SMALL 4 +#define EFI_LOAD_ERROR (1L | (1L << 63)) +#define EFI_INVALID_PARAMETER (2L | (1L << 63)) +#define EFI_UNSUPPORTED (3L | (1L << 63)) +#define EFI_BAD_BUFFER_SIZE (4L | (1L << 63)) +#define EFI_BUFFER_TOO_SMALL (5L | (1L << 63)) +#define EFI_NOT_FOUND (14L | (1L << 63)) typedef unsigned long efi_status_t; typedef u8 efi_bool_t; @@ -173,7 +176,7 @@ #define SMBIOS_TABLE_GUID \ ((efi_guid_t) { 0xeb9d2d31, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }}) - + #define SAL_SYSTEM_TABLE_GUID \ ((efi_guid_t) { 0xeb9d2d32, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }}) @@ -183,7 +186,7 @@ } efi_config_table_t; #define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249 -#define EFI_SYSTEM_TABLE_REVISION ((0 << 16) | (92)) +#define EFI_SYSTEM_TABLE_REVISION ((1 << 16) | 00) typedef struct { efi_table_hdr_t hdr; @@ -234,5 +237,13 @@ extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg); extern void efi_gettimeofday (struct timeval *tv); extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */ + + +/* + * Variable Attributes + */ +#define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001 +#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002 +#define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004 #endif /* _ASM_IA64_EFI_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/hardirq.h linux.ac/include/asm-ia64/hardirq.h --- linux.vanilla/include/asm-ia64/hardirq.h Mon Dec 4 01:45:23 2000 +++ linux.ac/include/asm-ia64/hardirq.h Tue Apr 10 18:22:36 2001 @@ -2,8 +2,8 @@ #define _ASM_IA64_HARDIRQ_H /* - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/config.h> @@ -11,36 +11,38 @@ #include <linux/threads.h> #include <linux/irq.h> -/* entry.S is sensitive to the offsets of these fields */ -typedef struct { - unsigned int __softirq_active; - unsigned int __softirq_mask; - unsigned int __local_irq_count; - unsigned int __local_bh_count; - unsigned int __syscall_count; - unsigned int __nmi_count; /* arch dependent */ -} ____cacheline_aligned irq_cpustat_t; - -#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */ +#include <asm/processor.h> /* - * Are we in an interrupt context? Either doing bottom half - * or hardware interrupt processing? + * No irq_cpustat_t for IA-64. The data is held in the per-CPU data structure. */ -#define in_interrupt() \ -({ \ - int __cpu = smp_processor_id(); \ - (local_irq_count(__cpu) + local_bh_count(__cpu)) != 0; \ -}) +#define softirq_active(cpu) (cpu_data[cpu].softirq.active) +#define softirq_mask(cpu) (cpu_data[cpu].softirq.mask) +#define irq_count(cpu) (cpu_data[cpu].irq_stat.f.irq_count) +#define bh_count(cpu) (cpu_data[cpu].irq_stat.f.bh_count) +#define syscall_count(cpu) /* unused on IA-64 */ +#define nmi_count(cpu) 0 + +#define local_softirq_active() (local_cpu_data->softirq.active) +#define local_softirq_mask() (local_cpu_data->softirq.mask) +#define local_irq_count() (local_cpu_data->irq_stat.f.irq_count) +#define local_bh_count() (local_cpu_data->irq_stat.f.bh_count) +#define local_syscall_count() /* unused on IA-64 */ +#define local_nmi_count() 0 -#define in_irq() (local_irq_count(smp_processor_id()) != 0) +/* + * Are we in an interrupt context? Either doing bottom half or hardware interrupt + * processing? + */ +#define in_interrupt() (local_cpu_data->irq_stat.irq_and_bh_counts != 0) +#define in_irq() (local_cpu_data->irq_stat.f.irq_count != 0) #ifndef CONFIG_SMP -# define hardirq_trylock(cpu) (local_irq_count(cpu) == 0) -# define hardirq_endlock(cpu) do { } while (0) +# define local_hardirq_trylock() (local_irq_count() == 0) +# define local_hardirq_endlock() do { } while (0) -# define irq_enter(cpu, irq) (local_irq_count(cpu)++) -# define irq_exit(cpu, irq) (local_irq_count(cpu)--) +# define local_irq_enter(irq) (local_irq_count()++) +# define local_irq_exit(irq) (local_irq_count()--) # define synchronize_irq() barrier() #else @@ -51,17 +53,19 @@ extern unsigned int global_irq_holder; extern volatile unsigned long global_irq_lock; -static inline int irqs_running (void) +static inline int +irqs_running (void) { int i; for (i = 0; i < smp_num_cpus; i++) - if (local_irq_count(i)) + if (irq_count(i)) return 1; return 0; } -static inline void release_irqlock(int cpu) +static inline void +release_irqlock (int cpu) { /* if we didn't own the irq lock, just ignore.. */ if (global_irq_holder == cpu) { @@ -70,28 +74,31 @@ } } -static inline void irq_enter(int cpu, int irq) +static inline void +local_irq_enter (int irq) { - local_irq_count(cpu)++; + local_irq_count()++; while (test_bit(0,&global_irq_lock)) { /* nothing */; } } -static inline void irq_exit(int cpu, int irq) +static inline void +local_irq_exit (int irq) { - local_irq_count(cpu)--; + local_irq_count()--; } -static inline int hardirq_trylock(int cpu) +static inline int +local_hardirq_trylock (void) { - return !local_irq_count(cpu) && !test_bit(0,&global_irq_lock); + return !local_irq_count() && !test_bit(0,&global_irq_lock); } -#define hardirq_endlock(cpu) do { } while (0) +#define local_hardirq_endlock() do { } while (0) -extern void synchronize_irq(void); +extern void synchronize_irq (void); #endif /* CONFIG_SMP */ #endif /* _ASM_IA64_HARDIRQ_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/hw_irq.h linux.ac/include/asm-ia64/hw_irq.h --- linux.vanilla/include/asm-ia64/hw_irq.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/hw_irq.h Tue Apr 10 18:22:36 2001 @@ -2,8 +2,8 @@ #define _ASM_IA64_HW_IRQ_H /* - * Copyright (C) 2000 Hewlett-Packard Co - * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 2001 Hewlett-Packard Co + * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/sched.h> @@ -13,6 +13,8 @@ #include <asm/ptrace.h> #include <asm/smp.h> +typedef u8 ia64_vector; + /* * 0 special * @@ -26,31 +28,32 @@ * * 15 classes of 16 interrupts each. */ -#define IA64_MIN_VECTORED_IRQ 16 -#define IA64_MAX_VECTORED_IRQ 255 +#define IA64_MIN_VECTORED_IRQ 16 +#define IA64_MAX_VECTORED_IRQ 255 +#define IA64_NUM_VECTORS 256 -#define IA64_SPURIOUS_INT 0x0f +#define IA64_SPURIOUS_INT_VECTOR 0x0f /* * Vectors 0x10-0x1f are used for low priority interrupts, e.g. CMCI. */ -#define PCE_IRQ 0x1e /* platform corrected error interrupt vector */ -#define CMC_IRQ 0x1f /* correctable machine-check interrupt vector */ +#define IA64_PCE_VECTOR 0x1e /* platform corrected error interrupt vector */ +#define IA64_CMC_VECTOR 0x1f /* correctable machine-check interrupt vector */ /* * Vectors 0x20-0x2f are reserved for legacy ISA IRQs. */ -#define FIRST_DEVICE_IRQ 0x30 -#define LAST_DEVICE_IRQ 0xe7 +#define IA64_FIRST_DEVICE_VECTOR 0x30 +#define IA64_LAST_DEVICE_VECTOR 0xe7 -#define MCA_RENDEZ_IRQ 0xe8 /* MCA rendez interrupt */ -#define PERFMON_IRQ 0xee /* performanc monitor interrupt vector */ -#define TIMER_IRQ 0xef /* use highest-prio group 15 interrupt for timer */ -#define MCA_WAKEUP_IRQ 0xf0 /* MCA wakeup interrupt (must be higher than MCA_RENDEZ_IRQ) */ -#define IPI_IRQ 0xfe /* inter-processor interrupt vector */ +#define IA64_MCA_RENDEZ_VECTOR 0xe8 /* MCA rendez interrupt */ +#define IA64_PERFMON_VECTOR 0xee /* performanc monitor interrupt vector */ +#define IA64_TIMER_VECTOR 0xef /* use highest-prio group 15 interrupt for timer */ +#define IA64_MCA_WAKEUP_VECTOR 0xf0 /* MCA wakeup (must be >MCA_RENDEZ_VECTOR) */ +#define IA64_IPI_VECTOR 0xfe /* inter-processor interrupt vector */ /* IA64 inter-cpu interrupt related definitions */ -#define IPI_DEFAULT_BASE_ADDR 0xfee00000 +#define IA64_IPI_DEFAULT_BASE_ADDR 0xfee00000 /* Delivery modes for inter-cpu interrupts */ enum { @@ -61,9 +64,6 @@ IA64_IPI_DM_EXTINT = 0x7, /* pend an 8259-compatible interrupt. */ }; -#define IA64_BUS_ID(cpu) (cpu >> 8) -#define IA64_LOCAL_ID(cpu) (cpu & 0xff) - extern __u8 isa_irq_to_vector_map[16]; #define isa_irq_to_vector(x) isa_irq_to_vector_map[(x)] @@ -73,11 +73,71 @@ extern int ia64_alloc_irq (void); /* allocate a free irq */ extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect); +extern void register_percpu_irq (ia64_vector vec, struct irqaction *action); static inline void hw_resend_irq (struct hw_interrupt_type *h, unsigned int vector) { platform_send_ipi(smp_processor_id(), vector, IA64_IPI_DM_INT, 0); +} + +/* + * Default implementations for the irq-descriptor API: + */ + +extern struct irq_desc _irq_desc[NR_IRQS]; + +static inline struct irq_desc * +__ia64_irq_desc (unsigned int irq) +{ + return _irq_desc + irq; +} + +static inline ia64_vector +__ia64_irq_to_vector (unsigned int irq) +{ + return (ia64_vector) irq; +} + +static inline unsigned int +__ia64_local_vector_to_irq (ia64_vector vec) +{ + return (unsigned int) vec; +} + +/* + * Next follows the irq descriptor interface. On IA-64, each CPU supports 256 interrupt + * vectors. On smaller systems, there is a one-to-one correspondence between interrupt + * vectors and the Linux irq numbers. However, larger systems may have multiple interrupt + * domains meaning that the translation from vector number to irq number depends on the + * interrupt domain that a CPU belongs to. This API abstracts such platform-dependent + * differences and provides a uniform means to translate between vector and irq numbers + * and to obtain the irq descriptor for a given irq number. + */ + +/* Return a pointer to the irq descriptor for IRQ. */ +static inline struct irq_desc * +irq_desc (int irq) +{ + return platform_irq_desc(irq); +} + +/* Extract the IA-64 vector that corresponds to IRQ. */ +static inline ia64_vector +irq_to_vector (int irq) +{ + return platform_irq_to_vector(irq); +} + +/* + * Convert the local IA-64 vector to the corresponding irq number. This translation is + * done in the context of the interrupt domain that the currently executing CPU belongs + * to. + */ +static inline unsigned int +local_vector_to_irq (ia64_vector vec) +{ + return platform_local_vector_to_irq(vec); } #endif /* _ASM_IA64_HW_IRQ_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/ia32.h linux.ac/include/asm-ia64/ia32.h --- linux.vanilla/include/asm-ia64/ia32.h Thu Jan 4 20:50:17 2001 +++ linux.ac/include/asm-ia64/ia32.h Tue Apr 10 18:22:36 2001 @@ -355,7 +355,7 @@ (granularity << IA32_SEG_G) | \ (((base >> 24) & 0xFF) << IA32_SEG_HIGH_BASE)) -#define IA32_IOBASE 0x2000000000000000 /* Virtual addres for I/O space */ +#define IA32_IOBASE 0x2000000000000000 /* Virtual address for I/O space */ #define IA32_CR0 0x80000001 /* Enable PG and PE bits */ #define IA32_CR4 0 /* No architectural extensions */ @@ -378,9 +378,10 @@ ia64_psr(regs)->ri = 0; /* clear return slot number */ \ ia64_psr(regs)->is = 1; /* IA-32 instruction set */ \ regs->cr_iip = new_ip; \ - regs->r12 = new_sp; \ + regs->ar_rsc = 0xc; /* enforced lazy mode, priv. level 3 */ \ regs->ar_rnat = 0; \ regs->loadrs = 0; \ + regs->r12 = new_sp; \ } while (0) extern void ia32_gdt_init (void); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/io.h linux.ac/include/asm-ia64/io.h --- linux.vanilla/include/asm-ia64/io.h Thu Jan 4 20:50:17 2001 +++ linux.ac/include/asm-ia64/io.h Tue Apr 10 18:22:36 2001 @@ -13,8 +13,8 @@ * over and over again with slight variations and possibly making a * mistake somewhere. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com> * Copyright (C) 1999 Don Dugger <don.dugger@intel.com> */ @@ -82,21 +82,11 @@ } /* - * For the in/out instructions, we need to do: - * - * o "mf" _before_ doing the I/O access to ensure that all prior - * accesses to memory occur before the I/O access - * o "mf.a" _after_ doing the I/O access to ensure that the access - * has completed before we're doing any other I/O accesses - * - * The former is necessary because we might be doing normal (cached) memory - * accesses, e.g., to set up a DMA descriptor table and then do an "outX()" - * to tell the DMA controller to start the DMA operation. The "mf" ahead - * of the I/O operation ensures that the DMA table is correct when the I/O - * access occurs. - * - * The mf.a is necessary to ensure that all I/O access occur in program - * order. --davidm 99/12/07 + * For the in/out routines, we need to do "mf.a" _after_ doing the I/O access to ensure + * that the access has completed before executing other I/O accesses. Since we're doing + * the accesses through an uncachable (UC) translation, the CPU will execute them in + * program order. However, we still need to tell the compiler not to shuffle them around + * during optimization, which is why we use "volatile" pointers. */ static inline unsigned int @@ -378,17 +368,16 @@ #endif /* - * An "address" in IO memory space is not clearly either an integer - * or a pointer. We will accept both, thus the casts. + * An "address" in IO memory space is not clearly either an integer or a pointer. We will + * accept both, thus the casts. * - * On ia-64, we access the physical I/O memory space through the - * uncached kernel region. + * On ia-64, we access the physical I/O memory space through the uncached kernel region. */ static inline void * ioremap (unsigned long offset, unsigned long size) { return (void *) (__IA64_UNCACHED_OFFSET | (offset)); -} +} static inline void iounmap (void *addr) @@ -412,75 +401,6 @@ __ia64_memcpy_toio((unsigned long)(to),(from),(len)) #define memset_io(addr,c,len) \ __ia64_memset_c_io((unsigned long)(addr),0x0101010101010101UL*(u8)(c),(len)) - -#define __HAVE_ARCH_MEMSETW_IO -#define memsetw_io(addr,c,len) \ - _memset_c_io((unsigned long)(addr),0x0001000100010001UL*(u16)(c),(len)) - -/* - * XXX - We don't have csum_partial_copy_fromio() yet, so we cheat here and - * just copy it. The net code will then do the checksum later. Presently - * only used by some shared memory 8390 Ethernet cards anyway. - */ - -#define eth_io_copy_and_sum(skb,src,len,unused) memcpy_fromio((skb)->data,(src),(len)) - -#if 0 - -/* - * XXX this is the kind of legacy stuff we want to get rid of with IA-64... --davidm 99/12/02 - */ - -/* - * This is used for checking BIOS signatures. It's not clear at all - * why this is here. This implementation seems to be the same on - * all architectures. Strange. - */ -static inline int -check_signature (unsigned long io_addr, const unsigned char *signature, int length) -{ - int retval = 0; - do { - if (readb(io_addr) != *signature) - goto out; - io_addr++; - signature++; - length--; - } while (length); - retval = 1; -out: - return retval; -} - -#define RTC_PORT(x) (0x70 + (x)) -#define RTC_ALWAYS_BCD 0 - -#endif - -/* - * The caches on some architectures aren't DMA-coherent and have need - * to handle this in software. There are two types of operations that - * can be applied to dma buffers. - * - * - dma_cache_inv(start, size) invalidates the affected parts of the - * caches. Dirty lines of the caches may be written back or simply - * be discarded. This operation is necessary before dma operations - * to the memory. - * - * - dma_cache_wback(start, size) makes caches and memory coherent - * by writing the content of the caches back to memory, if necessary - * (cache flush). - * - * - dma_cache_wback_inv(start, size) Like dma_cache_wback() but the - * function also invalidates the affected part of the caches as - * necessary before DMA transfers from outside to memory. - * - * Fortunately, the IA-64 architecture mandates cache-coherent DMA, so - * these functions can be implemented as no-ops. - */ -#define dma_cache_inv(_start,_size) do { } while (0) -#define dma_cache_wback(_start,_size) do { } while (0) -#define dma_cache_wback_inv(_start,_size) do { } while (0) # endif /* __KERNEL__ */ #endif /* _ASM_IA64_IO_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/ioctls.h linux.ac/include/asm-ia64/ioctls.h --- linux.vanilla/include/asm-ia64/ioctls.h Mon Feb 7 02:42:40 2000 +++ linux.ac/include/asm-ia64/ioctls.h Tue Apr 3 17:55:15 2001 @@ -72,6 +72,7 @@ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ #define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ #define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ +#define FIOQSIZE 0x5460 /* Used for packet mode */ #define TIOCPKT_DATA 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/kregs.h linux.ac/include/asm-ia64/kregs.h --- linux.vanilla/include/asm-ia64/kregs.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-ia64/kregs.h Tue Apr 10 18:22:36 2001 @@ -0,0 +1,33 @@ +#ifndef _ASM_IA64_KREGS_H +#define _ASM_IA64_KREGS_H + +/* + * Copyright (C) 2001 Hewlett-Packard Co + * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com> + */ +/* + * This file defines the kernel register usage convention used by Linux/ia64. + */ + +/* + * Kernel registers: + */ +#define IA64_KR_IO_BASE 0 /* ar.k0: legacy I/O base address */ +#define IA64_KR_CURRENT_STACK 4 /* ar.k4: what's mapped in IA64_TR_CURRENT_STACK */ +#define IA64_KR_FPU_OWNER 5 /* ar.k5: fpu-owner (UP only, at the moment) */ +#define IA64_KR_CURRENT 6 /* ar.k6: "current" task pointer */ +#define IA64_KR_PT_BASE 7 /* ar.k7: page table base address (physical) */ + +#define _IA64_KR_PASTE(x,y) x##y +#define _IA64_KR_PREFIX(n) _IA64_KR_PASTE(ar.k, n) +#define IA64_KR(n) _IA64_KR_PREFIX(IA64_KR_##n) + +/* + * Translation registers: + */ +#define IA64_TR_KERNEL 0 /* itr0, dtr0: maps kernel image (code & data) */ +#define IA64_TR_PALCODE 1 /* itr1: maps PALcode as required by EFI */ +#define IA64_TR_PERCPU_DATA 1 /* dtr1: percpu data */ +#define IA64_TR_CURRENT_STACK 2 /* dtr2: maps kernel memory & register stacks */ + +#endif /* _ASM_IA64_kREGS_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/linux_logo.h linux.ac/include/asm-ia64/linux_logo.h --- linux.vanilla/include/asm-ia64/linux_logo.h Mon Feb 7 02:42:40 2000 +++ linux.ac/include/asm-ia64/linux_logo.h Tue Apr 3 17:55:15 2001 @@ -41,9 +41,6 @@ extern unsigned char linux_logo_blue[]; extern unsigned char linux_logo[]; extern unsigned char linux_logo_bw[]; -extern unsigned char linux_logo16_red[]; -extern unsigned char linux_logo16_green[]; -extern unsigned char linux_logo16_blue[]; extern unsigned char linux_logo16[]; #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/machvec.h linux.ac/include/asm-ia64/machvec.h --- linux.vanilla/include/asm-ia64/machvec.h Thu Jan 4 20:50:17 2001 +++ linux.ac/include/asm-ia64/machvec.h Tue Apr 10 18:22:36 2001 @@ -4,8 +4,8 @@ * Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) Srinivasa Thirumalachar <sprasad@engr.sgi.com> * Copyright (C) Vijay Chander <vijay@engr.sgi.com> - * Copyright (C) 1999-2000 Hewlett-Packard Co. - * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1999-2001 Hewlett-Packard Co. + * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #ifndef _ASM_IA64_MACHVEC_H #define _ASM_IA64_MACHVEC_H @@ -17,6 +17,7 @@ struct pci_dev; struct pt_regs; struct scatterlist; +struct irq_desc; typedef void ia64_mv_setup_t (char **); typedef void ia64_mv_irq_init_t (void); @@ -27,6 +28,9 @@ typedef void ia64_mv_cmci_handler_t (int, void *, struct pt_regs *); typedef void ia64_mv_log_print_t (void); typedef void ia64_mv_send_ipi_t (int, int, int, int); +typedef struct irq_desc *ia64_mv_irq_desc (unsigned int); +typedef u8 ia64_mv_irq_to_vector (u8); +typedef unsigned int ia64_mv_local_vector_to_irq (u8 vector); /* PCI-DMA interface: */ typedef void ia64_mv_pci_dma_init (void); @@ -88,6 +92,9 @@ # define platform_pci_dma_sync_single ia64_mv.sync_single # define platform_pci_dma_sync_sg ia64_mv.sync_sg # define platform_pci_dma_address ia64_mv.dma_address +# define platform_irq_desc ia64_mv.irq_desc +# define platform_irq_to_vector ia64_mv.irq_to_vector +# define platform_local_vector_to_irq ia64_mv.local_vector_to_irq # define platform_inb ia64_mv.inb # define platform_inw ia64_mv.inw # define platform_inl ia64_mv.inl @@ -117,6 +124,9 @@ ia64_mv_pci_dma_sync_single *sync_single; ia64_mv_pci_dma_sync_sg *sync_sg; ia64_mv_pci_dma_address *dma_address; + ia64_mv_irq_desc *irq_desc; + ia64_mv_irq_to_vector *irq_to_vector; + ia64_mv_local_vector_to_irq *local_vector_to_irq; ia64_mv_inb_t *inb; ia64_mv_inw_t *inw; ia64_mv_inl_t *inl; @@ -147,6 +157,9 @@ platform_pci_dma_sync_single, \ platform_pci_dma_sync_sg, \ platform_pci_dma_address, \ + platform_irq_desc, \ + platform_irq_to_vector, \ + platform_local_vector_to_irq, \ platform_inb, \ platform_inw, \ platform_inl, \ @@ -233,6 +246,15 @@ #endif #ifndef platform_pci_dma_address # define platform_pci_dma_address swiotlb_dma_address +#endif +#ifndef platform_irq_desc +# define platform_irq_desc __ia64_irq_desc +#endif +#ifndef platform_irq_to_vector +# define platform_irq_to_vector __ia64_irq_to_vector +#endif +#ifndef platform_local_vector_to_irq +# define platform_local_vector_to_irq __ia64_local_vector_to_irq #endif #ifndef platform_inb # define platform_inb __ia64_inb diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/machvec_sn1.h linux.ac/include/asm-ia64/machvec_sn1.h --- linux.vanilla/include/asm-ia64/machvec_sn1.h Thu Jan 4 20:50:17 2001 +++ linux.ac/include/asm-ia64/machvec_sn1.h Tue Apr 10 18:22:36 2001 @@ -41,6 +41,7 @@ #define platform_outb sn1_outb #define platform_outw sn1_outw #define platform_outl sn1_outl +#define platform_pci_dma_init machvec_noop #define platform_pci_alloc_consistent sn1_pci_alloc_consistent #define platform_pci_free_consistent sn1_pci_free_consistent #define platform_pci_map_single sn1_pci_map_single diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/mca.h linux.ac/include/asm-ia64/mca.h --- linux.vanilla/include/asm-ia64/mca.h Thu Jan 4 20:50:17 2001 +++ linux.ac/include/asm-ia64/mca.h Tue Apr 10 18:22:36 2001 @@ -1,6 +1,6 @@ /* - * File: mca.h - * Purpose: Machine check handling specific defines + * File: mca.h + * Purpose: Machine check handling specific defines * * Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) Vijay Chander (vijay@engr.sgi.com) @@ -18,7 +18,6 @@ #include <asm/param.h> #include <asm/sal.h> #include <asm/processor.h> -#include <asm/hw_irq.h> /* These are the return codes from all the IA64_MCA specific interfaces */ typedef int ia64_mca_return_code_t; @@ -30,11 +29,6 @@ #define IA64_MCA_RENDEZ_TIMEOUT (100 * HZ) /* 1000 milliseconds */ -/* Interrupt vectors reserved for MC handling. */ -#define IA64_MCA_RENDEZ_INT_VECTOR MCA_RENDEZ_IRQ /* Rendez interrupt */ -#define IA64_MCA_WAKEUP_INT_VECTOR MCA_WAKEUP_IRQ /* Wakeup interrupt */ -#define IA64_MCA_CMC_INT_VECTOR CMC_IRQ /* Correctable machine check interrupt */ - #define IA64_CMC_INT_DISABLE 0 #define IA64_CMC_INT_ENABLE 1 @@ -45,7 +39,7 @@ typedef union cmcv_reg_u { u64 cmcv_regval; struct { - u64 cmcr_vector : 8; + u64 cmcr_vector : 8; u64 cmcr_reserved1 : 4; u64 cmcr_ignored1 : 1; u64 cmcr_reserved2 : 3; @@ -63,15 +57,15 @@ #define IA64_INIT_HANDLER_SIZE 0x10 enum { - IA64_MCA_RENDEZ_CHECKIN_NOTDONE = 0x0, - IA64_MCA_RENDEZ_CHECKIN_DONE = 0x1 + IA64_MCA_RENDEZ_CHECKIN_NOTDONE = 0x0, + IA64_MCA_RENDEZ_CHECKIN_DONE = 0x1 }; #define IA64_MAXCPUS 64 /* Need to do something about this */ /* Information maintained by the MC infrastructure */ typedef struct ia64_mc_info_s { - u64 imi_mca_handler; + u64 imi_mca_handler; size_t imi_mca_handler_size; u64 imi_monarch_init_handler; size_t imi_monarch_init_handler_size; @@ -85,7 +79,7 @@ * handoff */ enum { - IA64_MCA_RENDEZ_NOT_RQD = 0x0, + IA64_MCA_RENDEZ_NOT_RQD = 0x0, IA64_MCA_RENDEZ_DONE_WITHOUT_INIT = 0x1, IA64_MCA_RENDEZ_DONE_WITH_INIT = 0x2, IA64_MCA_RENDEZ_FAILURE = -1 @@ -103,12 +97,12 @@ } ia64_mca_sal_to_os_state_t; enum { - IA64_MCA_CORRECTED = 0x0, /* Error has been corrected by OS_MCA */ + IA64_MCA_CORRECTED = 0x0, /* Error has been corrected by OS_MCA */ IA64_MCA_WARM_BOOT = -1, /* Warm boot of the system need from SAL */ IA64_MCA_COLD_BOOT = -2, /* Cold boot of the system need from SAL */ IA64_MCA_HALT = -3 /* System to be halted by SAL */ }; - + typedef struct ia64_mca_os_to_sal_state_s { u64 imots_os_status; /* OS status to SAL as to what happened * with the MCA handling. @@ -138,7 +132,7 @@ #define PLATFORM_CALL(fn, args) printk("Platform call TBD\n") -#undef MCA_TEST +#undef MCA_TEST #define IA64_MCA_DEBUG_INFO 1 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/mca_asm.h linux.ac/include/asm-ia64/mca_asm.h --- linux.vanilla/include/asm-ia64/mca_asm.h Fri Apr 21 23:21:24 2000 +++ linux.ac/include/asm-ia64/mca_asm.h Tue Apr 10 18:22:36 2001 @@ -72,7 +72,7 @@ ;; \ dep old_psr = 0, old_psr, 32, 32; \ \ - mov ar.rsc = r0 ; \ + mov ar.rsc = 0 ; \ ;; \ mov temp2 = ar.bspstore; \ ;; \ @@ -148,7 +148,7 @@ dep temp2 = 0, temp2, PSR_IC, 2; \ ;; \ mov psr.l = temp2; \ - mov ar.rsc = r0; \ + mov ar.rsc = 0; \ ;; \ srlz.d; \ mov temp2 = ar.bspstore; \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/mmu_context.h linux.ac/include/asm-ia64/mmu_context.h --- linux.vanilla/include/asm-ia64/mmu_context.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/mmu_context.h Tue Apr 10 18:22:36 2001 @@ -2,35 +2,32 @@ #define _ASM_IA64_MMU_CONTEXT_H /* - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ -#include <linux/sched.h> -#include <linux/spinlock.h> - -#include <asm/processor.h> - /* - * Routines to manage the allocation of task context numbers. Task - * context numbers are used to reduce or eliminate the need to perform - * TLB flushes due to context switches. Context numbers are - * implemented using ia-64 region ids. Since ia-64 TLBs do not - * guarantee that the region number is checked when performing a TLB - * lookup, we need to assign a unique region id to each region in a - * process. We use the least significant three bits in a region id - * for this purpose. On processors where the region number is checked - * in TLB lookups, we can get back those two bits by defining - * CONFIG_IA64_TLB_CHECKS_REGION_NUMBER. The macro - * IA64_REGION_ID_BITS gives the number of bits in a region id. The - * architecture manual guarantees this number to be in the range - * 18-24. + * Routines to manage the allocation of task context numbers. Task context numbers are + * used to reduce or eliminate the need to perform TLB flushes due to context switches. + * Context numbers are implemented using ia-64 region ids. Since the IA-64 TLB does not + * consider the region number when performing a TLB lookup, we need to assign a unique + * region id to each region in a process. We use the least significant three bits in a + * region id for this purpose. * - * Copyright (C) 1998 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #define IA64_REGION_ID_KERNEL 0 /* the kernel's region id (tlb.c depends on this being 0) */ +#define ia64_rid(ctx,addr) (((ctx) << 3) | (addr >> 61)) + +# ifndef __ASSEMBLY__ + +#include <linux/sched.h> +#include <linux/spinlock.h> + +#include <asm/processor.h> + struct ia64_ctx { spinlock_t lock; unsigned int next; /* next context number to use */ @@ -47,12 +44,6 @@ { } -static inline unsigned long -ia64_rid (unsigned long context, unsigned long region_addr) -{ - return context << 3 | (region_addr >> 61); -} - static inline void get_new_mmu_context (struct mm_struct *mm) { @@ -123,11 +114,12 @@ * We may get interrupts here, but that's OK because interrupt * handlers cannot touch user-space. */ - __asm__ __volatile__ ("mov ar.k7=%0" :: "r"(__pa(next->pgd))); + ia64_set_kr(IA64_KR_PT_BASE, __pa(next->pgd)); get_mmu_context(next); reload_context(next); } #define switch_mm(prev_mm,next_mm,next_task,cpu) activate_mm(prev_mm, next_mm) +# endif /* ! __ASSEMBLY__ */ #endif /* _ASM_IA64_MMU_CONTEXT_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/module.h linux.ac/include/asm-ia64/module.h --- linux.vanilla/include/asm-ia64/module.h Thu Jan 4 20:50:17 2001 +++ linux.ac/include/asm-ia64/module.h Sat Apr 14 01:39:02 2001 @@ -7,7 +7,6 @@ * Copyright (C) 2000 Mike Stephens <mike.stephens@intel.com> */ -#include <linux/config.h> #include <linux/module.h> #include <linux/vmalloc.h> #include <asm/unwind.h> @@ -35,7 +34,6 @@ static inline int ia64_module_init(struct module *mod) { -#ifdef CONFIG_IA64_NEW_UNWIND struct archdata *archdata; if (!mod_member_present(mod, archdata_start) || !mod->archdata_start) @@ -79,14 +77,12 @@ (unsigned long) archdata->segment_base, (unsigned long) archdata->gp, archdata->unw_start, archdata->unw_end); -#endif /* CONFIG_IA64_NEW_UNWIND */ return 0; } static inline void ia64_module_unmap(void * addr) { -#ifdef CONFIG_IA64_NEW_UNWIND struct module *mod = (struct module *) addr; struct archdata *archdata; @@ -100,7 +96,6 @@ if (archdata->unw_table != NULL) unw_remove_unwind_table((void *) archdata->unw_table); } -#endif /* CONFIG_IA64_NEW_UNWIND */ vfree(addr); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/offsets.h linux.ac/include/asm-ia64/offsets.h --- linux.vanilla/include/asm-ia64/offsets.h Thu Jan 4 20:50:18 2001 +++ linux.ac/include/asm-ia64/offsets.h Tue Apr 10 18:22:36 2001 @@ -11,10 +11,11 @@ #define PT_PTRACED_BIT 0 #define PT_TRACESYS_BIT 1 -#define IA64_TASK_SIZE 3376 /* 0xd30 */ +#define IA64_TASK_SIZE 3904 /* 0xf40 */ #define IA64_PT_REGS_SIZE 400 /* 0x190 */ #define IA64_SWITCH_STACK_SIZE 560 /* 0x230 */ #define IA64_SIGINFO_SIZE 128 /* 0x80 */ +#define IA64_CPU_SIZE 16384 /* 0x4000 */ #define UNW_FRAME_INFO_SIZE 448 /* 0x1c0 */ #define IA64_TASK_PTRACE_OFFSET 48 /* 0x30 */ @@ -23,7 +24,8 @@ #define IA64_TASK_PROCESSOR_OFFSET 100 /* 0x64 */ #define IA64_TASK_THREAD_OFFSET 1456 /* 0x5b0 */ #define IA64_TASK_THREAD_KSP_OFFSET 1456 /* 0x5b0 */ -#define IA64_TASK_THREAD_SIGMASK_OFFSET 3224 /* 0xc98 */ +#define IA64_TASK_THREAD_SIGMASK_OFFSET 3752 /* 0xea8 */ +#define IA64_TASK_PFM_NOTIFY_OFFSET 3648 /* 0xe40 */ #define IA64_TASK_PID_OFFSET 196 /* 0xc4 */ #define IA64_TASK_MM_OFFSET 88 /* 0x58 */ #define IA64_PT_REGS_CR_IPSR_OFFSET 0 /* 0x0 */ @@ -123,5 +125,10 @@ #define IA64_SIGCONTEXT_FR6_OFFSET 560 /* 0x230 */ #define IA64_CLONE_VFORK 16384 /* 0x4000 */ #define IA64_CLONE_VM 256 /* 0x100 */ +#define IA64_CPU_IRQ_COUNT_OFFSET 8 /* 0x8 */ +#define IA64_CPU_BH_COUNT_OFFSET 12 /* 0xc */ +#define IA64_CPU_SOFTIRQ_ACTIVE_OFFSET 0 /* 0x0 */ +#define IA64_CPU_SOFTIRQ_MASK_OFFSET 4 /* 0x4 */ +#define IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET 16 /* 0x10 */ #endif /* _ASM_IA64_OFFSETS_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/page.h linux.ac/include/asm-ia64/page.h --- linux.vanilla/include/asm-ia64/page.h Thu Jan 4 20:50:18 2001 +++ linux.ac/include/asm-ia64/page.h Tue Apr 10 18:22:36 2001 @@ -40,43 +40,6 @@ extern void clear_page (void *page); extern void copy_page (void *to, void *from); -# ifdef STRICT_MM_TYPECHECKS -/* - * These are used to make use of C type-checking.. - */ -typedef struct { unsigned long pte; } pte_t; -typedef struct { unsigned long pmd; } pmd_t; -typedef struct { unsigned long pgd; } pgd_t; -typedef struct { unsigned long pgprot; } pgprot_t; - -#define pte_val(x) ((x).pte) -#define pmd_val(x) ((x).pmd) -#define pgd_val(x) ((x).pgd) -#define pgprot_val(x) ((x).pgprot) - -#define __pte(x) ((pte_t) { (x) } ) -#define __pgprot(x) ((pgprot_t) { (x) } ) - -# else /* !STRICT_MM_TYPECHECKS */ -/* - * .. while these make it easier on the compiler - */ -typedef unsigned long pte_t; -typedef unsigned long pmd_t; -typedef unsigned long pgd_t; -typedef unsigned long pgprot_t; - -#define pte_val(x) (x) -#define pmd_val(x) (x) -#define pgd_val(x) (x) -#define pgprot_val(x) (x) - -#define __pte(x) (x) -#define __pgd(x) (x) -#define __pgprot(x) (x) - -# endif /* !STRICT_MM_TYPECHECKS */ - /* * Note: the MAP_NR_*() macro can't use __pa() because MAP_NR_*(X) MUST * map to something >= max_mapnr if X is outside the identity mapped @@ -133,7 +96,7 @@ { double d = size - 1; long order; - + __asm__ ("getf.exp %0=%1" : "=r"(order) : "f"(d)); order = order - PAGE_SHIFT - 0xffff + 1; if (order < 0) @@ -142,7 +105,45 @@ } # endif /* __KERNEL__ */ -#endif /* !ASSEMBLY */ +#endif /* !__ASSEMBLY__ */ + +#ifdef STRICT_MM_TYPECHECKS + /* + * These are used to make use of C type-checking.. + */ + typedef struct { unsigned long pte; } pte_t; + typedef struct { unsigned long pmd; } pmd_t; + typedef struct { unsigned long pgd; } pgd_t; + typedef struct { unsigned long pgprot; } pgprot_t; + +# define pte_val(x) ((x).pte) +# define pmd_val(x) ((x).pmd) +# define pgd_val(x) ((x).pgd) +# define pgprot_val(x) ((x).pgprot) + +# define __pte(x) ((pte_t) { (x) } ) +# define __pgprot(x) ((pgprot_t) { (x) } ) + +#else /* !STRICT_MM_TYPECHECKS */ + /* + * .. while these make it easier on the compiler + */ +# ifndef __ASSEMBLY__ + typedef unsigned long pte_t; + typedef unsigned long pmd_t; + typedef unsigned long pgd_t; + typedef unsigned long pgprot_t; +# endif + +# define pte_val(x) (x) +# define pmd_val(x) (x) +# define pgd_val(x) (x) +# define pgprot_val(x) (x) + +# define __pte(x) (x) +# define __pgd(x) (x) +# define __pgprot(x) (x) +#endif /* !STRICT_MM_TYPECHECKS */ #define PAGE_OFFSET 0xe000000000000000 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/pal.h linux.ac/include/asm-ia64/pal.h --- linux.vanilla/include/asm-ia64/pal.h Tue Oct 10 01:54:59 2000 +++ linux.ac/include/asm-ia64/pal.h Tue Apr 10 18:22:36 2001 @@ -1267,7 +1267,7 @@ ia64_pal_version (pal_version_u_t *pal_min_version, pal_version_u_t *pal_cur_version) { struct ia64_pal_retval iprv; - PAL_CALL(iprv, PAL_VERSION, 0, 0, 0); + PAL_CALL_PHYS(iprv, PAL_VERSION, 0, 0, 0); if (pal_min_version) pal_min_version->pal_version_val = iprv.v0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/param.h linux.ac/include/asm-ia64/param.h --- linux.vanilla/include/asm-ia64/param.h Fri Oct 27 19:04:43 2000 +++ linux.ac/include/asm-ia64/param.h Tue Apr 10 18:22:36 2001 @@ -10,7 +10,7 @@ #include <linux/config.h> -#if defined(CONFIG_IA64_HP_SIM) || defined(CONFIG_IA64_SOFTSDV_HACKS) +#ifdef CONFIG_IA64_HP_SIM /* * Yeah, simulating stuff is slow, so let us catch some breath between * timer interrupts... diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/perfmon.h linux.ac/include/asm-ia64/perfmon.h --- linux.vanilla/include/asm-ia64/perfmon.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-ia64/perfmon.h Tue Apr 10 18:22:36 2001 @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2001 Hewlett-Packard Co + * Copyright (C) 2001 Stephane Eranian <eranian@hpl.hp.com> + */ + +#ifndef _ASM_IA64_PERFMON_H +#define _ASM_IA64_PERFMON_H + +#include <linux/types.h> + +/* + * Structure used to define a context + */ +typedef struct { + unsigned long smpl_entries; /* how many entries in sampling buffer */ + unsigned long smpl_regs; /* which pmds to record on overflow */ + void *smpl_vaddr; /* returns address of BTB buffer */ + + pid_t notify_pid; /* which process to notify on overflow */ + int notify_sig; /* XXX: not used anymore */ + + int flags; /* NOBLOCK/BLOCK/ INHERIT flags (will replace API flags) */ +} pfreq_context_t; + +/* + * Structure used to configure a PMC or PMD + */ +typedef struct { + unsigned long reg_num; /* which register */ + unsigned long reg_value; /* configuration (PMC) or initial value (PMD) */ + unsigned long reg_smpl_reset; /* reset of sampling buffer overflow (large) */ + unsigned long reg_ovfl_reset; /* reset on counter overflow (small) */ + int reg_flags; /* (PMD): notify/don't notify */ +} pfreq_reg_t; + +/* + * main request structure passed by user + */ +typedef union { + pfreq_context_t pfr_ctx; /* request to configure a context */ + pfreq_reg_t pfr_reg; /* request to configure a PMD/PMC */ +} perfmon_req_t; + +extern void pfm_save_regs (struct task_struct *); +extern void pfm_load_regs (struct task_struct *); + +extern int pfm_inherit (struct task_struct *); +extern void pfm_context_exit (struct task_struct *); +extern void pfm_flush_regs (struct task_struct *); + +#endif /* _ASM_IA64_PERFMON_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/pgalloc.h linux.ac/include/asm-ia64/pgalloc.h --- linux.vanilla/include/asm-ia64/pgalloc.h Thu Jan 4 20:50:18 2001 +++ linux.ac/include/asm-ia64/pgalloc.h Tue Apr 10 18:22:36 2001 @@ -8,8 +8,8 @@ * This hopefully works with any (fixed) ia-64 page-size, as defined * in <asm/page.h> (currently 8192). * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 2000, Goutham Rao <goutham.rao@intel.com> */ @@ -28,68 +28,60 @@ * a lot of work and caused unnecessary memory traffic. How broken... * We fix this by caching them. */ -#define pgd_quicklist (my_cpu_data.pgd_quick) -#define pmd_quicklist (my_cpu_data.pmd_quick) -#define pte_quicklist (my_cpu_data.pte_quick) -#define pgtable_cache_size (my_cpu_data.pgtable_cache_sz) - -static __inline__ pgd_t* -get_pgd_slow (void) -{ - pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL); - if (ret) - clear_page(ret); - return ret; -} +#define pgd_quicklist (local_cpu_data->pgd_quick) +#define pmd_quicklist (local_cpu_data->pmd_quick) +#define pte_quicklist (local_cpu_data->pte_quick) +#define pgtable_cache_size (local_cpu_data->pgtable_cache_sz) -static __inline__ pgd_t* -get_pgd_fast (void) +static inline pgd_t* +pgd_alloc_one_fast (void) { unsigned long *ret = pgd_quicklist; - if (ret != NULL) { + if (__builtin_expect(ret != NULL, 1)) { pgd_quicklist = (unsigned long *)(*ret); ret[0] = 0; --pgtable_cache_size; - } - return (pgd_t *)ret; + } else + ret = NULL; + return (pgd_t *) ret; } -static __inline__ pgd_t* +static inline pgd_t* pgd_alloc (void) { - pgd_t *pgd; + /* the VM system never calls pgd_alloc_one_fast(), so we do it here. */ + pgd_t *pgd = pgd_alloc_one_fast(); - pgd = get_pgd_fast(); - if (!pgd) - pgd = get_pgd_slow(); + if (__builtin_expect(pgd == NULL, 0)) { + pgd = (pgd_t *)__get_free_page(GFP_KERNEL); + if (__builtin_expect(pgd != NULL, 1)) + clear_page(pgd); + } return pgd; } -static __inline__ void -free_pgd_fast (pgd_t *pgd) +static inline void +pgd_free (pgd_t *pgd) { *(unsigned long *)pgd = (unsigned long) pgd_quicklist; pgd_quicklist = (unsigned long *) pgd; ++pgtable_cache_size; } -static __inline__ pmd_t * -get_pmd_slow (void) +static inline void +pgd_populate (struct mm_struct *mm, pgd_t *pgd_entry, pmd_t *pmd) { - pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL); - - if (pmd) - clear_page(pmd); - return pmd; + pgd_val(*pgd_entry) = __pa(pmd); } -static __inline__ pmd_t * -get_pmd_fast (void) + +static inline pmd_t* +pmd_alloc_one_fast (struct mm_struct *mm, unsigned long addr) { unsigned long *ret = (unsigned long *)pmd_quicklist; - if (ret != NULL) { + if (__builtin_expect(ret != NULL, 1)) { pmd_quicklist = (unsigned long *)(*ret); ret[0] = 0; --pgtable_cache_size; @@ -97,28 +89,36 @@ return (pmd_t *)ret; } -static __inline__ void -free_pmd_fast (pmd_t *pmd) +static inline pmd_t* +pmd_alloc_one (struct mm_struct *mm, unsigned long addr) +{ + pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL); + + if (__builtin_expect(pmd != NULL, 1)) + clear_page(pmd); + return pmd; +} + +static inline void +pmd_free (pmd_t *pmd) { *(unsigned long *)pmd = (unsigned long) pmd_quicklist; pmd_quicklist = (unsigned long *) pmd; ++pgtable_cache_size; } -static __inline__ void -free_pmd_slow (pmd_t *pmd) +static inline void +pmd_populate (struct mm_struct *mm, pmd_t *pmd_entry, pte_t *pte) { - free_page((unsigned long)pmd); + pmd_val(*pmd_entry) = __pa(pte); } -extern pte_t *get_pte_slow (pmd_t *pmd, unsigned long address_preadjusted); - -static __inline__ pte_t * -get_pte_fast (void) +static inline pte_t* +pte_alloc_one_fast (struct mm_struct *mm, unsigned long addr) { unsigned long *ret = (unsigned long *)pte_quicklist; - if (ret != NULL) { + if (__builtin_expect(ret != NULL, 1)) { pte_quicklist = (unsigned long *)(*ret); ret[0] = 0; --pgtable_cache_size; @@ -126,71 +126,25 @@ return (pte_t *)ret; } -static __inline__ void -free_pte_fast (pte_t *pte) + +static inline pte_t* +pte_alloc_one (struct mm_struct *mm, unsigned long addr) { - *(unsigned long *)pte = (unsigned long) pte_quicklist; - pte_quicklist = (unsigned long *) pte; - ++pgtable_cache_size; -} + pte_t *pte = (pte_t *) __get_free_page(GFP_KERNEL); -#define pte_free_kernel(pte) free_pte_fast(pte) -#define pte_free(pte) free_pte_fast(pte) -#define pmd_free_kernel(pmd) free_pmd_fast(pmd) -#define pmd_free(pmd) free_pmd_fast(pmd) -#define pgd_free(pgd) free_pgd_fast(pgd) - -extern void __handle_bad_pgd (pgd_t *pgd); -extern void __handle_bad_pmd (pmd_t *pmd); - -static __inline__ pte_t* -pte_alloc (pmd_t *pmd, unsigned long vmaddr) -{ - unsigned long offset; - - offset = (vmaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - pte_t *pte_page = get_pte_fast(); - - if (!pte_page) - return get_pte_slow(pmd, offset); - pmd_set(pmd, pte_page); - return pte_page + offset; - } - if (pmd_bad(*pmd)) { - __handle_bad_pmd(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; + if (__builtin_expect(pte != NULL, 1)) + clear_page(pte); + return pte; } -static __inline__ pmd_t* -pmd_alloc (pgd_t *pgd, unsigned long vmaddr) +static inline void +pte_free (pte_t *pte) { - unsigned long offset; - - offset = (vmaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1); - if (pgd_none(*pgd)) { - pmd_t *pmd_page = get_pmd_fast(); - - if (!pmd_page) - pmd_page = get_pmd_slow(); - if (pmd_page) { - pgd_set(pgd, pmd_page); - return pmd_page + offset; - } else - return NULL; - } - if (pgd_bad(*pgd)) { - __handle_bad_pgd(pgd); - return NULL; - } - return (pmd_t *) pgd_page(*pgd) + offset; + *(unsigned long *)pte = (unsigned long) pte_quicklist; + pte_quicklist = (unsigned long *) pte; + ++pgtable_cache_size; } -#define pte_alloc_kernel(pmd, addr) pte_alloc(pmd, addr) -#define pmd_alloc_kernel(pgd, addr) pmd_alloc(pgd, addr) - extern int do_check_pgt_cache (int, int); /* @@ -219,7 +173,7 @@ /* * Flush a specified user mapping */ -static __inline__ void +static inline void flush_tlb_mm (struct mm_struct *mm) { if (mm) { @@ -237,7 +191,7 @@ /* * Page-granular tlb flush. */ -static __inline__ void +static inline void flush_tlb_page (struct vm_area_struct *vma, unsigned long addr) { #ifdef CONFIG_SMP @@ -300,20 +254,22 @@ * that may be necessary. */ static inline void -update_mmu_cache (struct vm_area_struct *vma, unsigned long address, pte_t pte) +update_mmu_cache (struct vm_area_struct *vma, unsigned long vaddr, pte_t pte) { + unsigned long addr; struct page *page; if (!pte_exec(pte)) return; /* not an executable page... */ page = pte_page(pte); - address &= PAGE_MASK; + /* don't use VADDR: it may not be mapped on this CPU (or may have just been flushed): */ + addr = (unsigned long) page_address(page); if (test_bit(PG_arch_1, &page->flags)) return; /* i-cache is already coherent with d-cache */ - flush_icache_range(address, address + PAGE_SIZE); + flush_icache_range(addr, addr + PAGE_SIZE); set_bit(PG_arch_1, &page->flags); /* mark page as clean */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/pgtable.h linux.ac/include/asm-ia64/pgtable.h --- linux.vanilla/include/asm-ia64/pgtable.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/pgtable.h Sat Apr 14 01:39:02 2001 @@ -8,11 +8,12 @@ * This hopefully works with any (fixed) IA-64 page-size, as defined * in <asm/page.h> (currently 8192). * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/config.h> + #include <asm/mman.h> #include <asm/page.h> #include <asm/processor.h> @@ -103,12 +104,6 @@ */ #define PTRS_PER_PTE (__IA64_UL(1) << (PAGE_SHIFT-3)) -# ifndef __ASSEMBLY__ - -#include <asm/bitops.h> -#include <asm/mmu_context.h> -#include <asm/system.h> - /* * All the normal masks have the "page accessed" bits on, as any time * they are used, the page is accessed. They are cleared only by the @@ -126,6 +121,12 @@ #define PAGE_GATE __pgprot(__ACCESS_BITS | _PAGE_PL_0 | _PAGE_AR_X_RX) #define PAGE_KERNEL __pgprot(__DIRTY_BITS | _PAGE_PL_0 | _PAGE_AR_RWX) +# ifndef __ASSEMBLY__ + +#include <asm/bitops.h> +#include <asm/mmu_context.h> +#include <asm/system.h> + /* * Next come the mappings that determine how mmap() protection bits * (PROT_EXEC, PROT_READ, PROT_WRITE, PROT_NONE) get implemented. The @@ -173,7 +174,7 @@ static inline long ia64_phys_addr_valid (unsigned long addr) { - return (addr & (my_cpu_data.unimpl_pa_mask)) == 0; + return (addr & (local_cpu_data->unimpl_pa_mask)) == 0; } /* @@ -203,25 +204,12 @@ #define set_pte(ptep, pteval) (*(ptep) = (pteval)) #define RGN_SIZE (1UL << 61) -#define RGN_MAP_LIMIT (1UL << (4*PAGE_SHIFT - 12)) /* limit of mappable area in region */ +#define RGN_MAP_LIMIT ((1UL << (4*PAGE_SHIFT - 12)) - PAGE_SIZE) /* per region addr limit */ #define RGN_KERNEL 7 -#define VMALLOC_START (0xa000000000000000 + 2*PAGE_SIZE) +#define VMALLOC_START (0xa000000000000000 + 3*PAGE_SIZE) #define VMALLOC_VMADDR(x) ((unsigned long)(x)) -#define VMALLOC_END (0xa000000000000000 + RGN_MAP_LIMIT) - -/* - * BAD_PAGETABLE is used when we need a bogus page-table, while - * BAD_PAGE is used for a bogus page. - * - * ZERO_PAGE is a global shared page that is always zero: used - * for zero-mapped memory areas etc.. - */ -extern pte_t ia64_bad_page (void); -extern pmd_t *ia64_bad_pagetable (void); - -#define BAD_PAGETABLE ia64_bad_pagetable() -#define BAD_PAGE ia64_bad_page() +#define VMALLOC_END (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) /* * Conversion functions: convert a page and protection to a page entry, @@ -251,14 +239,12 @@ /* pte_page() returns the "struct page *" corresponding to the PTE: */ #define pte_page(pte) (mem_map + (unsigned long) ((pte_val(pte) & _PFN_MASK) >> PAGE_SHIFT)) -#define pmd_set(pmdp, ptep) (pmd_val(*(pmdp)) = __pa(ptep)) #define pmd_none(pmd) (!pmd_val(pmd)) #define pmd_bad(pmd) (!ia64_phys_addr_valid(pmd_val(pmd))) #define pmd_present(pmd) (pmd_val(pmd) != 0UL) #define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0UL) #define pmd_page(pmd) ((unsigned long) __va(pmd_val(pmd) & _PFN_MASK)) -#define pgd_set(pgdp, pmdp) (pgd_val(*(pgdp)) = __pa(pmdp)) #define pgd_none(pgd) (!pgd_val(pgd)) #define pgd_bad(pgd) (!ia64_phys_addr_valid(pgd_val(pgd))) #define pgd_present(pgd) (pgd_val(pgd) != 0UL) @@ -301,7 +287,11 @@ * works bypasses the caches, but does allow for consecutive writes to * be combined into single (but larger) write transactions. */ -#define pgprot_writecombine(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WC) +#ifdef CONFIG_MCKINLEY_A0_SPECIFIC +# define pgprot_writecombine(prot) prot +#else +# define pgprot_writecombine(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WC) +#endif /* * Return the region index for virtual address ADDRESS. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/processor.h linux.ac/include/asm-ia64/processor.h --- linux.vanilla/include/asm-ia64/processor.h Thu Jan 4 20:50:18 2001 +++ linux.ac/include/asm-ia64/processor.h Sat Apr 14 01:39:15 2001 @@ -2,9 +2,9 @@ #define _ASM_IA64_PROCESSOR_H /* - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> - * Copyright (C) 1998-2000 Stephane Eranian <eranian@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Stephane Eranian <eranian@hpl.hp.com> * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com> * Copyright (C) 1999 Don Dugger <don.dugger@intel.com> * @@ -16,6 +16,8 @@ #include <linux/config.h> #include <asm/ptrace.h> +#include <asm/kregs.h> +#include <asm/system.h> #include <asm/types.h> #define IA64_NUM_DBG_REGS 8 @@ -27,6 +29,9 @@ #define IA64_NUM_PMD_REGS 32 #define IA64_NUM_PMD_COUNTERS 4 +#define DEFAULT_MAP_BASE 0x2000000000000000 +#define DEFAULT_TASK_SIZE 0xa000000000000000 + /* * TASK_SIZE really is a mis-named. It really is the maximum user * space address (plus one). On IA-64, there are five regions of 2TB @@ -163,15 +168,21 @@ #define IA64_THREAD_UAC_NOPRINT (__IA64_UL(1) << 3) /* don't log unaligned accesses */ #define IA64_THREAD_UAC_SIGBUS (__IA64_UL(1) << 4) /* generate SIGBUS on unaligned acc. */ #define IA64_THREAD_KRBS_SYNCED (__IA64_UL(1) << 5) /* krbs synced with process vm? */ -#define IA64_THREAD_MAP_SHARED (__IA64_UL(1) << 6) /* ugly: just a tmp flag for mmap() */ #define IA64_KERNEL_DEATH (__IA64_UL(1) << 63) /* see die_if_kernel()... */ #define IA64_THREAD_UAC_SHIFT 3 #define IA64_THREAD_UAC_MASK (IA64_THREAD_UAC_NOPRINT | IA64_THREAD_UAC_SIGBUS) + +/* + * This shift should be large enough to be able to represent + * 1000000/itc_freq with good accuracy while being small enough to fit + * 1000000<<IA64_USEC_PER_CYC_SHIFT in 64 bits. + */ +#define IA64_USEC_PER_CYC_SHIFT 41 + #ifndef __ASSEMBLY__ -#include <linux/smp.h> #include <linux/threads.h> #include <asm/fpu.h> @@ -220,16 +231,26 @@ }; /* - * This shift should be large enough to be able to represent - * 1000000/itc_freq with good accuracy while being small enough to fit - * 1000000<<IA64_USEC_PER_CYC_SHIFT in 64 bits. - */ -#define IA64_USEC_PER_CYC_SHIFT 41 - -/* - * CPU type, hardware bug flags, and per-CPU state. + * CPU type, hardware bug flags, and per-CPU state. Frequently used + * state comes earlier: */ struct cpuinfo_ia64 { + /* irq_stat and softirq should be 64-bit aligned */ + struct { + __u32 active; + __u32 mask; + } softirq; + union { + struct { + __u32 irq_count; + __u32 bh_count; + } f; + __u64 irq_and_bh_counts; + } irq_stat; + __u32 phys_stacked_size_p8; /* size of physical stacked registers + 8 */ + __u32 pad0; + __u64 itm_delta; /* # of clock cycles between clock ticks */ + __u64 itm_next; /* interval timer mask value to use for next clock tick */ __u64 *pgd_quick; __u64 *pmd_quick; __u64 *pte_quick; @@ -257,10 +278,15 @@ __u64 ipi_count; __u64 prof_counter; __u64 prof_multiplier; + __u64 ipi_operation; #endif -}; +} __attribute__ ((aligned (PAGE_SIZE))) ; -#define my_cpu_data cpu_data[smp_processor_id()] +/* + * The "local" data pointer. It points to the per-CPU data of the currently executing + * CPU, much like "current" points to the per-task data of the currently executing task. + */ +#define local_cpu_data ((struct cpuinfo_ia64 *) PERCPU_ADDR) extern struct cpuinfo_ia64 cpu_data[NR_CPUS]; @@ -294,13 +320,9 @@ #ifdef CONFIG_PERFMON __u64 pmc[IA64_NUM_PMC_REGS]; __u64 pmd[IA64_NUM_PMD_REGS]; - struct { - __u64 val; /* virtual 64bit counter */ - __u64 rval; /* reset value on overflow */ - int sig; /* signal used to notify */ - int pid; /* process to notify */ - } pmu_counters[IA64_NUM_PMD_COUNTERS]; -# define INIT_THREAD_PM {0, }, {0, }, {{ 0, 0, 0, 0}, }, + unsigned long pfm_pend_notify; /* non-zero if we need to notify and block */ + void *pfm_context; /* pointer to detailed PMU context */ +# define INIT_THREAD_PM {0, }, {0, }, 0, 0, #else # define INIT_THREAD_PM #endif @@ -338,25 +360,53 @@ {0, }, /* dbr */ \ {0, }, /* ibr */ \ INIT_THREAD_PM \ - 0x2000000000000000, /* map_base */ \ - 0xa000000000000000, /* task_size */ \ + DEFAULT_MAP_BASE, /* map_base */ \ + DEFAULT_TASK_SIZE, /* task_size */ \ INIT_THREAD_IA32 \ 0 /* siginfo */ \ } -#define start_thread(regs,new_ip,new_sp) do { \ - set_fs(USER_DS); \ - ia64_psr(regs)->dfh = 1; /* disable fph */ \ - ia64_psr(regs)->mfh = 0; /* clear mfh */ \ - ia64_psr(regs)->cpl = 3; /* set user mode */ \ - ia64_psr(regs)->ri = 0; /* clear return slot number */ \ - ia64_psr(regs)->is = 0; /* IA-64 instruction set */ \ - regs->cr_iip = new_ip; \ - regs->ar_rsc = 0xf; /* eager mode, privilege level 3 */ \ - regs->r12 = new_sp - 16; /* allocate 16 byte scratch area */ \ - regs->ar_bspstore = IA64_RBS_BOT; \ - regs->ar_rnat = 0; \ - regs->loadrs = 0; \ +#define start_thread(regs,new_ip,new_sp) do { \ + set_fs(USER_DS); \ + ia64_psr(regs)->dfh = 1; /* disable fph */ \ + ia64_psr(regs)->mfh = 0; /* clear mfh */ \ + ia64_psr(regs)->cpl = 3; /* set user mode */ \ + ia64_psr(regs)->ri = 0; /* clear return slot number */ \ + ia64_psr(regs)->is = 0; /* IA-64 instruction set */ \ + regs->cr_iip = new_ip; \ + regs->ar_rsc = 0xf; /* eager mode, privilege level 3 */ \ + regs->ar_rnat = 0; \ + regs->ar_bspstore = IA64_RBS_BOT; \ + regs->ar_fpsr = FPSR_DEFAULT; \ + regs->loadrs = 0; \ + regs->r8 = current->dumpable; /* set "don't zap registers" flag */ \ + regs->r12 = new_sp - 16; /* allocate 16 byte scratch area */ \ + if (!__builtin_expect (current->dumpable, 1)) { \ + /* \ + * Zap scratch regs to avoid leaking bits between processes with different \ + * uid/privileges. \ + */ \ + regs->ar_pfs = 0; \ + regs->pr = 0; \ + /* \ + * XXX fix me: everything below can go away once we stop preserving scratch \ + * regs on a system call. \ + */ \ + regs->b6 = 0; \ + regs->r1 = 0; regs->r2 = 0; regs->r3 = 0; \ + regs->r13 = 0; regs->r14 = 0; regs->r15 = 0; \ + regs->r9 = 0; regs->r11 = 0; \ + regs->r16 = 0; regs->r17 = 0; regs->r18 = 0; regs->r19 = 0; \ + regs->r20 = 0; regs->r21 = 0; regs->r22 = 0; regs->r23 = 0; \ + regs->r24 = 0; regs->r25 = 0; regs->r26 = 0; regs->r27 = 0; \ + regs->r28 = 0; regs->r29 = 0; regs->r30 = 0; regs->r31 = 0; \ + regs->ar_ccv = 0; \ + regs->b0 = 0; regs->b7 = 0; \ + regs->f6.u.bits[0] = 0; regs->f6.u.bits[1] = 0; \ + regs->f7.u.bits[0] = 0; regs->f7.u.bits[1] = 0; \ + regs->f8.u.bits[0] = 0; regs->f8.u.bits[1] = 0; \ + regs->f9.u.bits[0] = 0; regs->f9.u.bits[1] = 0; \ + } \ } while (0) /* Forward declarations, a strange C thing... */ @@ -368,7 +418,11 @@ * parent of DEAD_TASK has collected the exist status of the task via * wait(). This is a no-op on IA-64. */ -#define release_thread(dead_task) +#ifdef CONFIG_PERFMON + extern void release_thread (struct task_struct *task); +#else +# define release_thread(dead_task) +#endif /* * This is the mechanism for creating a new kernel thread. @@ -403,20 +457,51 @@ /* Return stack pointer of blocked task TSK. */ #define KSTK_ESP(tsk) ((tsk)->thread.ksp) +static inline unsigned long +ia64_get_kr (unsigned long regnum) +{ + unsigned long r; + + switch (regnum) { + case 0: asm volatile ("mov %0=ar.k0" : "=r"(r)); break; + case 1: asm volatile ("mov %0=ar.k1" : "=r"(r)); break; + case 2: asm volatile ("mov %0=ar.k2" : "=r"(r)); break; + case 3: asm volatile ("mov %0=ar.k3" : "=r"(r)); break; + case 4: asm volatile ("mov %0=ar.k4" : "=r"(r)); break; + case 5: asm volatile ("mov %0=ar.k5" : "=r"(r)); break; + case 6: asm volatile ("mov %0=ar.k6" : "=r"(r)); break; + case 7: asm volatile ("mov %0=ar.k7" : "=r"(r)); break; + } + return r; +} + +static inline void +ia64_set_kr (unsigned long regnum, unsigned long r) +{ + switch (regnum) { + case 0: asm volatile ("mov ar.k0=%0" :: "r"(r)); break; + case 1: asm volatile ("mov ar.k1=%0" :: "r"(r)); break; + case 2: asm volatile ("mov ar.k2=%0" :: "r"(r)); break; + case 3: asm volatile ("mov ar.k3=%0" :: "r"(r)); break; + case 4: asm volatile ("mov ar.k4=%0" :: "r"(r)); break; + case 5: asm volatile ("mov ar.k5=%0" :: "r"(r)); break; + case 6: asm volatile ("mov ar.k6=%0" :: "r"(r)); break; + case 7: asm volatile ("mov ar.k7=%0" :: "r"(r)); break; + } +} + #ifndef CONFIG_SMP static inline struct task_struct * ia64_get_fpu_owner (void) { - struct task_struct *t; - __asm__ ("mov %0=ar.k5" : "=r"(t)); - return t; + return (struct task_struct *) ia64_get_kr(IA64_KR_FPU_OWNER); } static inline void ia64_set_fpu_owner (struct task_struct *t) { - __asm__ __volatile__ ("mov ar.k5=%0" :: "r"(t)); + ia64_set_kr(IA64_KR_FPU_OWNER, (unsigned long) t); } #endif /* !CONFIG_SMP */ @@ -437,8 +522,8 @@ extern void ia64_load_pm_regs (struct task_struct *task); #endif -#define ia64_fph_enable() __asm__ __volatile__ (";; rsm psr.dfh;; srlz.d;;" ::: "memory"); -#define ia64_fph_disable() __asm__ __volatile__ (";; ssm psr.dfh;; srlz.d;;" ::: "memory"); +#define ia64_fph_enable() asm volatile (";; rsm psr.dfh;; srlz.d;;" ::: "memory"); +#define ia64_fph_disable() asm volatile (";; ssm psr.dfh;; srlz.d;;" ::: "memory"); /* load fp 0.0 into fph */ static inline void @@ -467,53 +552,53 @@ static inline void ia64_fc (void *addr) { - __asm__ __volatile__ ("fc %0" :: "r"(addr) : "memory"); + asm volatile ("fc %0" :: "r"(addr) : "memory"); } static inline void ia64_sync_i (void) { - __asm__ __volatile__ (";; sync.i" ::: "memory"); + asm volatile (";; sync.i" ::: "memory"); } static inline void ia64_srlz_i (void) { - __asm__ __volatile__ (";; srlz.i ;;" ::: "memory"); + asm volatile (";; srlz.i ;;" ::: "memory"); } static inline void ia64_srlz_d (void) { - __asm__ __volatile__ (";; srlz.d" ::: "memory"); + asm volatile (";; srlz.d" ::: "memory"); } static inline __u64 ia64_get_rr (__u64 reg_bits) { __u64 r; - __asm__ __volatile__ ("mov %0=rr[%1]" : "=r"(r) : "r"(reg_bits) : "memory"); + asm volatile ("mov %0=rr[%1]" : "=r"(r) : "r"(reg_bits) : "memory"); return r; } static inline void ia64_set_rr (__u64 reg_bits, __u64 rr_val) { - __asm__ __volatile__ ("mov rr[%0]=%1" :: "r"(reg_bits), "r"(rr_val) : "memory"); + asm volatile ("mov rr[%0]=%1" :: "r"(reg_bits), "r"(rr_val) : "memory"); } static inline __u64 ia64_get_dcr (void) { __u64 r; - __asm__ ("mov %0=cr.dcr" : "=r"(r)); + asm volatile ("mov %0=cr.dcr" : "=r"(r)); return r; } static inline void ia64_set_dcr (__u64 val) { - __asm__ __volatile__ ("mov cr.dcr=%0;;" :: "r"(val) : "memory"); + asm volatile ("mov cr.dcr=%0;;" :: "r"(val) : "memory"); ia64_srlz_d(); } @@ -521,14 +606,14 @@ ia64_get_lid (void) { __u64 r; - __asm__ ("mov %0=cr.lid" : "=r"(r)); + asm volatile ("mov %0=cr.lid" : "=r"(r)); return r; } static inline void ia64_invala (void) { - __asm__ __volatile__ ("invala" ::: "memory"); + asm volatile ("invala" ::: "memory"); } /* @@ -536,7 +621,7 @@ * interrupt collection and interrupt enable bits. */ #define ia64_clear_ic(flags) \ - __asm__ __volatile__ ("mov %0=psr;; rsm psr.i | psr.ic;; srlz.i;;" \ + asm volatile ("mov %0=psr;; rsm psr.i | psr.ic;; srlz.i;;" \ : "=r"(flags) :: "memory"); /* @@ -548,13 +633,13 @@ __u64 vmaddr, __u64 pte, __u64 log_page_size) { - __asm__ __volatile__ ("mov cr.itir=%0" :: "r"(log_page_size << 2) : "memory"); - __asm__ __volatile__ ("mov cr.ifa=%0;;" :: "r"(vmaddr) : "memory"); + asm volatile ("mov cr.itir=%0" :: "r"(log_page_size << 2) : "memory"); + asm volatile ("mov cr.ifa=%0;;" :: "r"(vmaddr) : "memory"); if (target_mask & 0x1) - __asm__ __volatile__ ("itr.i itr[%0]=%1" + asm volatile ("itr.i itr[%0]=%1" :: "r"(tr_num), "r"(pte) : "memory"); if (target_mask & 0x2) - __asm__ __volatile__ (";;itr.d dtr[%0]=%1" + asm volatile (";;itr.d dtr[%0]=%1" :: "r"(tr_num), "r"(pte) : "memory"); } @@ -566,13 +651,13 @@ ia64_itc (__u64 target_mask, __u64 vmaddr, __u64 pte, __u64 log_page_size) { - __asm__ __volatile__ ("mov cr.itir=%0" :: "r"(log_page_size << 2) : "memory"); - __asm__ __volatile__ ("mov cr.ifa=%0;;" :: "r"(vmaddr) : "memory"); + asm volatile ("mov cr.itir=%0" :: "r"(log_page_size << 2) : "memory"); + asm volatile ("mov cr.ifa=%0;;" :: "r"(vmaddr) : "memory"); /* as per EAS2.6, itc must be the last instruction in an instruction group */ if (target_mask & 0x1) - __asm__ __volatile__ ("itc.i %0;;" :: "r"(pte) : "memory"); + asm volatile ("itc.i %0;;" :: "r"(pte) : "memory"); if (target_mask & 0x2) - __asm__ __volatile__ (";;itc.d %0;;" :: "r"(pte) : "memory"); + asm volatile (";;itc.d %0;;" :: "r"(pte) : "memory"); } /* @@ -583,16 +668,16 @@ ia64_ptr (__u64 target_mask, __u64 vmaddr, __u64 log_size) { if (target_mask & 0x1) - __asm__ __volatile__ ("ptr.i %0,%1" :: "r"(vmaddr), "r"(log_size << 2)); + asm volatile ("ptr.i %0,%1" :: "r"(vmaddr), "r"(log_size << 2)); if (target_mask & 0x2) - __asm__ __volatile__ ("ptr.d %0,%1" :: "r"(vmaddr), "r"(log_size << 2)); + asm volatile ("ptr.d %0,%1" :: "r"(vmaddr), "r"(log_size << 2)); } /* Set the interrupt vector address. The address must be suitably aligned (32KB). */ static inline void ia64_set_iva (void *ivt_addr) { - __asm__ __volatile__ ("mov cr.iva=%0;; srlz.i;;" :: "r"(ivt_addr) : "memory"); + asm volatile ("mov cr.iva=%0;; srlz.i;;" :: "r"(ivt_addr) : "memory"); } /* Set the page table address and control bits. */ @@ -600,7 +685,7 @@ ia64_set_pta (__u64 pta) { /* Note: srlz.i implies srlz.d */ - __asm__ __volatile__ ("mov cr.pta=%0;; srlz.i;;" :: "r"(pta) : "memory"); + asm volatile ("mov cr.pta=%0;; srlz.i;;" :: "r"(pta) : "memory"); } static inline __u64 @@ -608,41 +693,33 @@ { __u64 r; - __asm__ ("mov %0=cpuid[%r1]" : "=r"(r) : "rO"(regnum)); + asm ("mov %0=cpuid[%r1]" : "=r"(r) : "rO"(regnum)); return r; } static inline void ia64_eoi (void) { - __asm__ ("mov cr.eoi=r0;; srlz.d;;" ::: "memory"); + asm ("mov cr.eoi=r0;; srlz.d;;" ::: "memory"); } static inline void -ia64_set_lrr0 (__u8 vector, __u8 masked) +ia64_set_lrr0 (unsigned long val) { - if (masked > 1) - masked = 1; - - __asm__ __volatile__ ("mov cr.lrr0=%0;; srlz.d" - :: "r"((masked << 16) | vector) : "memory"); + asm volatile ("mov cr.lrr0=%0;; srlz.d" :: "r"(val) : "memory"); } static inline void -ia64_set_lrr1 (__u8 vector, __u8 masked) +ia64_set_lrr1 (unsigned long val) { - if (masked > 1) - masked = 1; - - __asm__ __volatile__ ("mov cr.lrr1=%0;; srlz.d" - :: "r"((masked << 16) | vector) : "memory"); + asm volatile ("mov cr.lrr1=%0;; srlz.d" :: "r"(val) : "memory"); } static inline void ia64_set_pmv (__u64 val) { - __asm__ __volatile__ ("mov cr.pmv=%0" :: "r"(val) : "memory"); + asm volatile ("mov cr.pmv=%0" :: "r"(val) : "memory"); } static inline __u64 @@ -650,14 +727,14 @@ { __u64 retval; - __asm__ __volatile__ ("mov %0=pmc[%1]" : "=r"(retval) : "r"(regnum)); + asm volatile ("mov %0=pmc[%1]" : "=r"(retval) : "r"(regnum)); return retval; } static inline void ia64_set_pmc (__u64 regnum, __u64 value) { - __asm__ __volatile__ ("mov pmc[%0]=%1" :: "r"(regnum), "r"(value)); + asm volatile ("mov pmc[%0]=%1" :: "r"(regnum), "r"(value)); } static inline __u64 @@ -665,14 +742,14 @@ { __u64 retval; - __asm__ __volatile__ ("mov %0=pmd[%1]" : "=r"(retval) : "r"(regnum)); + asm volatile ("mov %0=pmd[%1]" : "=r"(retval) : "r"(regnum)); return retval; } static inline void ia64_set_pmd (__u64 regnum, __u64 value) { - __asm__ __volatile__ ("mov pmd[%0]=%1" :: "r"(regnum), "r"(value)); + asm volatile ("mov pmd[%0]=%1" :: "r"(regnum), "r"(value)); } /* @@ -722,7 +799,7 @@ * Get the current instruction/program counter value. */ #define current_text_addr() \ - ({ void *_pc; __asm__ ("mov %0=ip" : "=r" (_pc)); _pc; }) + ({ void *_pc; asm volatile ("mov %0=ip" : "=r" (_pc)); _pc; }) #define THREAD_SIZE IA64_STK_OFFSET /* NOTE: The task struct and the stacks are allocated together. */ @@ -740,7 +817,7 @@ static inline void ia64_set_cmcv (__u64 val) { - __asm__ __volatile__ ("mov cr.cmcv=%0" :: "r"(val) : "memory"); + asm volatile ("mov cr.cmcv=%0" :: "r"(val) : "memory"); } /* @@ -751,7 +828,7 @@ { __u64 val; - __asm__ ("mov %0=cr.cmcv" : "=r"(val) :: "memory"); + asm volatile ("mov %0=cr.cmcv" : "=r"(val) :: "memory"); return val; } @@ -759,28 +836,28 @@ ia64_get_ivr (void) { __u64 r; - __asm__ __volatile__ ("srlz.d;; mov %0=cr.ivr;; srlz.d;;" : "=r"(r)); + asm volatile ("srlz.d;; mov %0=cr.ivr;; srlz.d;;" : "=r"(r)); return r; } static inline void ia64_set_tpr (__u64 val) { - __asm__ __volatile__ ("mov cr.tpr=%0" :: "r"(val)); + asm volatile ("mov cr.tpr=%0" :: "r"(val)); } static inline __u64 ia64_get_tpr (void) { __u64 r; - __asm__ ("mov %0=cr.tpr" : "=r"(r)); + asm volatile ("mov %0=cr.tpr" : "=r"(r)); return r; } static inline void ia64_set_irr0 (__u64 val) { - __asm__ __volatile__("mov cr.irr0=%0;;" :: "r"(val) : "memory"); + asm volatile("mov cr.irr0=%0;;" :: "r"(val) : "memory"); ia64_srlz_d(); } @@ -790,14 +867,14 @@ __u64 val; /* this is volatile because irr may change unbeknownst to gcc... */ - __asm__ __volatile__("mov %0=cr.irr0" : "=r"(val)); + asm volatile("mov %0=cr.irr0" : "=r"(val)); return val; } static inline void ia64_set_irr1 (__u64 val) { - __asm__ __volatile__("mov cr.irr1=%0;;" :: "r"(val) : "memory"); + asm volatile("mov cr.irr1=%0;;" :: "r"(val) : "memory"); ia64_srlz_d(); } @@ -807,14 +884,14 @@ __u64 val; /* this is volatile because irr may change unbeknownst to gcc... */ - __asm__ __volatile__("mov %0=cr.irr1" : "=r"(val)); + asm volatile("mov %0=cr.irr1" : "=r"(val)); return val; } static inline void ia64_set_irr2 (__u64 val) { - __asm__ __volatile__("mov cr.irr2=%0;;" :: "r"(val) : "memory"); + asm volatile("mov cr.irr2=%0;;" :: "r"(val) : "memory"); ia64_srlz_d(); } @@ -824,14 +901,14 @@ __u64 val; /* this is volatile because irr may change unbeknownst to gcc... */ - __asm__ __volatile__("mov %0=cr.irr2" : "=r"(val)); + asm volatile("mov %0=cr.irr2" : "=r"(val)); return val; } static inline void ia64_set_irr3 (__u64 val) { - __asm__ __volatile__("mov cr.irr3=%0;;" :: "r"(val) : "memory"); + asm volatile("mov cr.irr3=%0;;" :: "r"(val) : "memory"); ia64_srlz_d(); } @@ -841,7 +918,7 @@ __u64 val; /* this is volatile because irr may change unbeknownst to gcc... */ - __asm__ __volatile__("mov %0=cr.irr3" : "=r"(val)); + asm volatile ("mov %0=cr.irr3" : "=r"(val)); return val; } @@ -850,7 +927,7 @@ { __u64 val; - __asm__ ("mov %0=gp" : "=r"(val)); + asm ("mov %0=gp" : "=r"(val)); return val; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/ptrace.h linux.ac/include/asm-ia64/ptrace.h --- linux.vanilla/include/asm-ia64/ptrace.h Thu Jan 4 20:50:18 2001 +++ linux.ac/include/asm-ia64/ptrace.h Tue Apr 10 18:22:36 2001 @@ -2,8 +2,8 @@ #define _ASM_IA64_PTRACE_H /* - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com> * * 12/07/98 S. Eranian added pt_regs & switch_stack @@ -67,7 +67,7 @@ # define IA64_TASK_STRUCT_LOG_NUM_PAGES 0 #endif -#define IA64_RBS_OFFSET ((IA64_TASK_SIZE + 15) & ~15) +#define IA64_RBS_OFFSET ((IA64_TASK_SIZE + 15) & ~15) #define IA64_STK_OFFSET ((1 << IA64_TASK_STRUCT_LOG_NUM_PAGES)*PAGE_SIZE) #define INIT_TASK_SIZE IA64_STK_OFFSET @@ -96,11 +96,11 @@ unsigned long cr_iip; /* interrupted task's instruction pointer */ unsigned long cr_ifs; /* interrupted task's function state */ - unsigned long ar_unat; /* interrupted task's NaT register (preserved) */ + unsigned long ar_unat; /* interrupted task's NaT register (preserved) */ unsigned long ar_pfs; /* prev function state */ unsigned long ar_rsc; /* RSE configuration */ /* The following two are valid only if cr_ipsr.cpl > 0: */ - unsigned long ar_rnat; /* RSE NaT */ + unsigned long ar_rnat; /* RSE NaT */ unsigned long ar_bspstore; /* RSE bspstore */ unsigned long pr; /* 64 predicate registers (1 bit each) */ @@ -160,7 +160,7 @@ * "preserved" registers. */ struct switch_stack { - unsigned long caller_unat; /* user NaT collection register (preserved) */ + unsigned long caller_unat; /* user NaT collection register (preserved) */ unsigned long ar_fpsr; /* floating-point status register */ struct ia64_fpreg f2; /* preserved */ @@ -206,7 +206,7 @@ unsigned long ar_pfs; /* previous function state */ unsigned long ar_lc; /* loop counter (preserved) */ unsigned long ar_unat; /* NaT bits for r4-r7 */ - unsigned long ar_rnat; /* RSE NaT collection register */ + unsigned long ar_rnat; /* RSE NaT collection register */ unsigned long ar_bspstore; /* RSE dirty base (preserved) */ unsigned long pr; /* 64 predicate registers (1 bit each) */ }; @@ -220,22 +220,16 @@ struct task_struct; /* forward decl */ extern void show_regs (struct pt_regs *); - extern long ia64_peek (struct pt_regs *, struct task_struct *, unsigned long addr, long *val); - extern long ia64_poke (struct pt_regs *, struct task_struct *, unsigned long addr, long val); - extern void ia64_flush_fph (struct task_struct *t); - extern void ia64_sync_fph (struct task_struct *t); + extern unsigned long ia64_get_user_bsp (struct task_struct *, struct pt_regs *); + extern long ia64_peek (struct task_struct *, unsigned long, unsigned long, long *); + extern long ia64_poke (struct task_struct *, unsigned long, unsigned long, long); + extern void ia64_flush_fph (struct task_struct *); + extern void ia64_sync_fph (struct task_struct *); -#ifdef CONFIG_IA64_NEW_UNWIND /* get nat bits for scratch registers such that bit N==1 iff scratch register rN is a NaT */ extern unsigned long ia64_get_scratch_nat_bits (struct pt_regs *pt, unsigned long scratch_unat); /* put nat bits for scratch registers such that scratch register rN is a NaT iff bit N==1 */ extern unsigned long ia64_put_scratch_nat_bits (struct pt_regs *pt, unsigned long nat); -#else - /* get nat bits for r1-r31 such that bit N==1 iff rN is a NaT */ - extern long ia64_get_nat_bits (struct pt_regs *pt, struct switch_stack *sw); - /* put nat bits for r1-r31 such that rN is a NaT iff bit N==1 */ - extern void ia64_put_nat_bits (struct pt_regs *pt, struct switch_stack *sw, unsigned long nat); -#endif extern void ia64_increment_ip (struct pt_regs *pt); extern void ia64_decrement_ip (struct pt_regs *pt); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sal.h linux.ac/include/asm-ia64/sal.h --- linux.vanilla/include/asm-ia64/sal.h Thu Jan 4 20:50:18 2001 +++ linux.ac/include/asm-ia64/sal.h Sat Apr 14 01:39:15 2001 @@ -16,7 +16,6 @@ * (plus examples of platform error info structures from smariset @ Intel) */ -#include <linux/config.h> #include <linux/spinlock.h> #include <asm/pal.h> @@ -28,15 +27,12 @@ #define __SAL_CALL(result,a0,a1,a2,a3,a4,a5,a6,a7) \ result = (*ia64_sal)(a0,a1,a2,a3,a4,a5,a6,a7) -#ifdef CONFIG_SMP -# define SAL_CALL(result,args...) do { \ - spin_lock(&sal_lock); \ - __SAL_CALL(result,args); \ - spin_unlock(&sal_lock); \ +# define SAL_CALL(result,args...) do { \ + unsigned long flags; \ + spin_lock_irqsave(&sal_lock, flags); \ + __SAL_CALL(result,args); \ + spin_unlock_irqrestore(&sal_lock, flags); \ } while (0) -#else -# define SAL_CALL(result,args...) __SAL_CALL(result,args) -#endif #define SAL_SET_VECTORS 0x01000000 #define SAL_GET_STATE_INFO 0x01000001 @@ -440,11 +436,10 @@ * machine state at the time of MCA's, INITs or CMCs */ static inline s64 -ia64_sal_clear_state_info (u64 sal_info_type, u64 sal_info_sub_type) +ia64_sal_clear_state_info (u64 sal_info_type) { struct ia64_sal_retval isrv; - SAL_CALL(isrv, SAL_CLEAR_STATE_INFO, sal_info_type, sal_info_sub_type, - 0, 0, 0, 0, 0); + SAL_CALL(isrv, SAL_CLEAR_STATE_INFO, sal_info_type, 0, 0, 0, 0, 0, 0); return isrv.status; } @@ -453,10 +448,10 @@ * state at the time of the MCAs, INITs or CMCs. */ static inline u64 -ia64_sal_get_state_info (u64 sal_info_type, u64 sal_info_sub_type, u64 *sal_info) +ia64_sal_get_state_info (u64 sal_info_type, u64 *sal_info) { struct ia64_sal_retval isrv; - SAL_CALL(isrv, SAL_GET_STATE_INFO, sal_info_type, sal_info_sub_type, + SAL_CALL(isrv, SAL_GET_STATE_INFO, sal_info_type, 0, sal_info, 0, 0, 0, 0); if (isrv.status) return 0; @@ -466,11 +461,10 @@ * state at the time of MCAs, INITs or CMCs */ static inline u64 -ia64_sal_get_state_info_size (u64 sal_info_type, u64 sal_info_sub_type) +ia64_sal_get_state_info_size (u64 sal_info_type) { struct ia64_sal_retval isrv; - SAL_CALL(isrv, SAL_GET_STATE_INFO_SIZE, sal_info_type, sal_info_sub_type, - 0, 0, 0, 0, 0); + SAL_CALL(isrv, SAL_GET_STATE_INFO_SIZE, sal_info_type, 0, 0, 0, 0, 0, 0); if (isrv.status) return 0; return isrv.v0; @@ -492,11 +486,10 @@ * non-monarch processor at the end of machine check processing. */ static inline s64 -ia64_sal_mc_set_params (u64 param_type, u64 i_or_m, u64 i_or_m_val, u64 timeout) +ia64_sal_mc_set_params (u64 param_type, u64 i_or_m, u64 i_or_m_val, u64 timeout, u64 rz_always) { struct ia64_sal_retval isrv; - SAL_CALL(isrv, SAL_MC_SET_PARAMS, param_type, i_or_m, i_or_m_val, timeout, - 0, 0, 0); + SAL_CALL(isrv, SAL_MC_SET_PARAMS, param_type, i_or_m, i_or_m_val, timeout, rz_always, 0, 0); return isrv.status; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/segment.h linux.ac/include/asm-ia64/segment.h --- linux.vanilla/include/asm-ia64/segment.h Mon Feb 7 02:42:40 2000 +++ linux.ac/include/asm-ia64/segment.h Tue Apr 10 18:22:36 2001 @@ -3,4 +3,4 @@ /* Only here because we have some old header files that expect it.. */ -#endif /* __ALPHA_SEGMENT_H */ +#endif /* _ASM_IA64_SEGMENT_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/semaphore.h linux.ac/include/asm-ia64/semaphore.h --- linux.vanilla/include/asm-ia64/semaphore.h Tue Oct 10 01:55:00 2000 +++ linux.ac/include/asm-ia64/semaphore.h Tue Apr 10 18:22:36 2001 @@ -116,7 +116,7 @@ #endif if (atomic_inc_return(&sem->count) <= 0) __up(sem); -} +} /* * rw mutexes (should that be mutices? =) -- throw rw spinlocks and diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sigcontext.h linux.ac/include/asm-ia64/sigcontext.h --- linux.vanilla/include/asm-ia64/sigcontext.h Mon Feb 7 02:42:40 2000 +++ linux.ac/include/asm-ia64/sigcontext.h Tue Apr 10 18:22:36 2001 @@ -36,6 +36,7 @@ unsigned long sc_ar_lc; /* loop count register */ unsigned long sc_pr; /* predicate registers */ unsigned long sc_br[8]; /* branch registers */ + /* Note: sc_gr[0] is used as the "uc_link" member of ucontext_t */ unsigned long sc_gr[32]; /* general registers (static partition) */ struct ia64_fpreg sc_fr[128]; /* floating-point registers */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/siginfo.h linux.ac/include/asm-ia64/siginfo.h --- linux.vanilla/include/asm-ia64/siginfo.h Tue Oct 10 01:55:00 2000 +++ linux.ac/include/asm-ia64/siginfo.h Tue Apr 10 18:22:36 2001 @@ -2,8 +2,8 @@ #define _ASM_IA64_SIGINFO_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/types.h> @@ -66,6 +66,12 @@ long _band; /* POLL_IN, POLL_OUT, POLL_MSG (XPG requires a "long") */ int _fd; } _sigpoll; + /* SIGPROF */ + struct { + pid_t _pid; /* which child */ + uid_t _uid; /* sender's uid */ + unsigned long _pfm_ovfl_counters; /* which PMU counter overflowed */ + } _sigprof; } _sifields; } siginfo_t; @@ -85,6 +91,7 @@ #define si_isr _sifields._sigfault._isr /* valid if si_code==FPE_FLTxxx */ #define si_band _sifields._sigpoll._band #define si_fd _sifields._sigpoll._fd +#define si_pfm_ovfl _sifields._sigprof._pfm_ovfl_counters /* * si_code values @@ -98,6 +105,7 @@ #define __SI_FAULT (3 << 16) #define __SI_CHLD (4 << 16) #define __SI_RT (5 << 16) +#define __SI_PROF (6 << 16) #define __SI_CODE(T,N) ((T) << 16 | ((N) & 0xffff)) #else #define __SI_KILL 0 @@ -201,12 +209,16 @@ #define NSIGPOLL 6 /* + * SIGPROF si_codes + */ +#define PROF_OVFL (__SI_PROF|1) /* some counters overflowed */ + +/* * sigevent definitions - * - * It seems likely that SIGEV_THREAD will have to be handled from - * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the - * thread manager then catches and does the appropriate nonsense. - * However, everything is written out here so as to not get lost. + * + * It seems likely that SIGEV_THREAD will have to be handled from userspace, libpthread + * transmuting it to SIGEV_SIGNAL, which the thread manager then catches and does the + * appropriate nonsense. However, everything is written out here so as to not get lost. */ #define SIGEV_SIGNAL 0 /* notify via signal */ #define SIGEV_NONE 1 /* other notification: meaningless */ @@ -246,6 +258,7 @@ } extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from); +extern int copy_siginfo_from_user(siginfo_t *to, siginfo_t *from); #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/smp.h linux.ac/include/asm-ia64/smp.h --- linux.vanilla/include/asm-ia64/smp.h Tue Oct 10 01:55:00 2000 +++ linux.ac/include/asm-ia64/smp.h Tue Apr 10 18:22:36 2001 @@ -3,6 +3,8 @@ * * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> + * Copyright (C) 2001 Hewlett-Packard Co + * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #ifndef _ASM_IA64_SMP_H #define _ASM_IA64_SMP_H @@ -15,13 +17,14 @@ #include <linux/threads.h> #include <linux/kernel.h> -#include <asm/ptrace.h> #include <asm/io.h> +#include <asm/processor.h> +#include <asm/ptrace.h> #define XTP_OFFSET 0x1e0008 -#define SMP_IRQ_REDIRECTION (1 << 0) -#define SMP_IPI_REDIRECTION (1 << 1) +#define SMP_IRQ_REDIRECTION (1 << 0) +#define SMP_IPI_REDIRECTION (1 << 1) #define smp_processor_id() (current->processor) @@ -30,15 +33,15 @@ int cpu_phys_id[NR_CPUS]; } smp_boot_data __initdata; +extern char no_int_routing __initdata; + extern unsigned long cpu_present_map; extern unsigned long cpu_online_map; extern unsigned long ipi_base_addr; -extern int bootstrap_processor; -extern volatile int __cpu_physical_id[NR_CPUS]; +extern int __cpu_physical_id[NR_CPUS]; extern unsigned char smp_int_redirect; -extern char no_int_routing; extern int smp_num_cpus; - + #define cpu_physical_id(i) __cpu_physical_id[i] #define cpu_number_map(i) (i) #define cpu_logical_map(i) (i) @@ -54,54 +57,55 @@ { int i; - for (i=0; i<smp_num_cpus; i++) { - if (cpu_physical_id(i) == cpuid) + for (i = 0; i < smp_num_cpus; ++i) + if (cpu_physical_id(i) == (__u32) cpuid) break; - } return i; } /* * XTP control functions: - * min_xtp : route all interrupts to this CPU - * normal_xtp: nominal XTP value - * max_xtp : never deliver interrupts to this CPU. + * min_xtp : route all interrupts to this CPU + * normal_xtp: nominal XTP value + * max_xtp : never deliver interrupts to this CPU. */ static inline void -min_xtp(void) +min_xtp (void) { if (smp_int_redirect & SMP_IRQ_REDIRECTION) writeb(0x00, ipi_base_addr | XTP_OFFSET); /* XTP to min */ } static inline void -normal_xtp(void) +normal_xtp (void) { if (smp_int_redirect & SMP_IRQ_REDIRECTION) writeb(0x08, ipi_base_addr | XTP_OFFSET); /* XTP normal */ } static inline void -max_xtp(void) +max_xtp (void) { if (smp_int_redirect & SMP_IRQ_REDIRECTION) writeb(0x0f, ipi_base_addr | XTP_OFFSET); /* Set XTP to max */ } static inline unsigned int -hard_smp_processor_id(void) +hard_smp_processor_id (void) { - struct { - unsigned long reserved : 16; - unsigned long eid : 8; - unsigned long id : 8; - unsigned long ignored : 32; + union { + struct { + unsigned long reserved : 16; + unsigned long eid : 8; + unsigned long id : 8; + unsigned long ignored : 32; + } f; + unsigned long bits; } lid; - __asm__ ("mov %0=cr.lid" : "=r" (lid)); - - return lid.id << 8 | lid.eid; + lid.bits = ia64_get_lid(); + return lid.f.id << 8 | lid.f.eid; } #define NO_PROC_ID (-1) @@ -111,7 +115,7 @@ extern void smp_do_timer (struct pt_regs *regs); extern int smp_call_function_single (int cpuid, void (*func) (void *info), void *info, - int retry, int wait); + int retry, int wait); #endif /* CONFIG_SMP */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/smplock.h linux.ac/include/asm-ia64/smplock.h --- linux.vanilla/include/asm-ia64/smplock.h Thu Mar 23 20:50:09 2000 +++ linux.ac/include/asm-ia64/smplock.h Tue Apr 10 18:22:36 2001 @@ -3,10 +3,12 @@ * * Default SMP lock implementation */ -#include <linux/sched.h> #include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/sched.h> -#include <asm/spinlock.h> +#include <asm/current.h> +#include <asm/hardirq.h> extern spinlock_t kernel_flag; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/addrs.h linux.ac/include/asm-ia64/sn/addrs.h --- linux.vanilla/include/asm-ia64/sn/addrs.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/addrs.h Tue Apr 10 18:22:36 2001 @@ -11,6 +11,7 @@ #define _ASM_SN_ADDRS_H #include <linux/config.h> + #if _LANGUAGE_C #include <linux/types.h> #endif /* _LANGUAGE_C */ @@ -21,22 +22,15 @@ #include <asm/sn/kldir.h> #endif /* CONFIG_IA64_SGI_SN1 */ -#if defined(CONFIG_IA64_SGI_IO) #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) #include <asm/sn/sn1/addrs.h> #endif -#endif /* CONFIG_IA64_SGI_IO */ #if _LANGUAGE_C -#if defined(CONFIG_IA64_SGI_IO) /* FIXME */ #define PS_UINT_CAST (__psunsigned_t) #define UINT64_CAST (uint64_t) -#else /* CONFIG_IA64_SGI_IO */ -#define PS_UINT_CAST (unsigned long) -#define UINT64_CAST (unsigned long) -#endif /* CONFIG_IA64_SGI_IO */ #define HUBREG_CAST (volatile hubreg_t *) @@ -138,6 +132,8 @@ #define UALIAS_BASE HSPEC_BASE #define UALIAS_SIZE 0x10000000 /* 256 Megabytes */ +#define CPU_UALIAS 0x20000 /* 128 Kilobytes */ +#define UALIAS_CPU_SIZE (CPU_UALIAS / CPUS_PER_NODE) #define UALIAS_LIMIT (UALIAS_BASE + UALIAS_SIZE) /* @@ -408,24 +404,19 @@ #define PHYS_RAMBASE 0x0 #define K0_RAMBASE PHYS_TO_K0(PHYS_RAMBASE) -#define EX_HANDLER_OFFSET(slice) ((slice) << 16) -#define EX_HANDLER_ADDR(nasid, slice) \ - PHYS_TO_K0(NODE_OFFSET(nasid) | EX_HANDLER_OFFSET(slice)) -#define EX_HANDLER_SIZE 0x0400 - -#define EX_FRAME_OFFSET(slice) ((slice) << 16 | 0x400) -#define EX_FRAME_ADDR(nasid, slice) \ - PHYS_TO_K0(NODE_OFFSET(nasid) | EX_FRAME_OFFSET(slice)) -#define EX_FRAME_SIZE 0x0c00 - #define ARCS_SPB_OFFSET 0x1000 #define ARCS_SPB_ADDR(nasid) \ PHYS_TO_K0(NODE_OFFSET(nasid) | ARCS_SPB_OFFSET) #define ARCS_SPB_SIZE 0x0400 #define KLDIR_OFFSET 0x2000 +#ifndef __ia64 #define KLDIR_ADDR(nasid) \ TO_NODE_UNCAC((nasid), KLDIR_OFFSET) +#else +#define KLDIR_ADDR(nasid) \ + TO_NODE_CAC((nasid), KLDIR_OFFSET) +#endif #define KLDIR_SIZE 0x0400 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/agent.h linux.ac/include/asm-ia64/sn/agent.h --- linux.vanilla/include/asm-ia64/sn/agent.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/agent.h Tue Apr 10 18:22:36 2001 @@ -13,6 +13,7 @@ #define _ASM_SGI_SN_AGENT_H #include <linux/config.h> + #include <asm/sn/addrs.h> #include <asm/sn/arch.h> //#include <asm/sn/io.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/arc/hinv.h linux.ac/include/asm-ia64/sn/arc/hinv.h --- linux.vanilla/include/asm-ia64/sn/arc/hinv.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/arc/hinv.h Tue Apr 10 18:22:36 2001 @@ -89,7 +89,7 @@ PCIAdapter, GIOAdapter, TPUAdapter, - + TernaryCache, Anonymous } CONFIGTYPE; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/arch.h linux.ac/include/asm-ia64/sn/arch.h --- linux.vanilla/include/asm-ia64/sn/arch.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/arch.h Tue Apr 10 18:22:36 2001 @@ -15,12 +15,10 @@ #include <linux/types.h> #include <linux/config.h> -#if defined(CONFIG_IA64_SGI_IO) #include <asm/sn/types.h> #if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_SGI_IP37) || defined(CONFIG_IA64_GENERIC) #include <asm/sn/sn1/arch.h> #endif -#endif /* CONFIG_IA64_SGI_IO */ #if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) @@ -68,7 +66,7 @@ * cputolocalslice - returns a number 0..1 that identifies the local slice of * the cpu within it's PI interface. */ -#ifdef notyet +#ifdef LATER /* These are dummied up for now ..... */ #define cputocnode(cpu) \ (pdaindr[(cpu)].p_nodeid) @@ -86,7 +84,7 @@ #define cputoslice(cpu) 0 #define cputolocalslice(cpu) 0 #define cputosubnode(cpu) 0 -#endif /* notyet */ +#endif /* LATER */ #endif /* CONFIG_SGI_IP35 */ #if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) @@ -131,6 +129,7 @@ ((nnode) >> \ (is_fine_dirmode() ? NASID_TO_FINEREG_SHFT : NASID_TO_COARSEREG_SHFT)) +#ifndef __ia64 extern cnodeid_t nasid_to_compact_node[MAX_NASIDS]; extern nasid_t compact_to_nasid_node[MAX_COMPACT_NODES]; extern cnodeid_t cpuid_to_compact_node[MAXCPUS]; @@ -153,6 +152,17 @@ #define COMPACT_TO_NASID_NODEID(cnode) compact_to_nasid_nodeid(cnode) #define CPUID_TO_COMPACT_NODEID(cpu) (cpuid_to_compact_node[(cpu)]) #endif + +#else + +/* + * IA64 specific nasid and cnode ids. + */ +#define NASID_TO_COMPACT_NODEID(nasid) (nasid_to_cnodeid(nasid)) +#define COMPACT_TO_NASID_NODEID(cnode) (cnodeid_to_nasid(cnode)) +#define CPUID_TO_COMPACT_NODEID(cpu) (cpuid_to_cnodeid(cpu)) + +#endif /* #ifndef __ia64 */ extern int node_getlastslot(cnodeid_t); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/cdl.h linux.ac/include/asm-ia64/sn/cdl.h --- linux.vanilla/include/asm-ia64/sn/cdl.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/cdl.h Tue Apr 10 18:22:36 2001 @@ -30,6 +30,15 @@ cdl_iter_f (devfs_handle_t vhdl); /* + * cdl_drv_f is the type for the functions + * that are called by cdl_add_driver and + * cdl_del_driver. + */ + +typedef void +cdl_drv_f (devfs_handle_t vhdl, int key1, int key2, int error); + +/* * If CDL_PRI_HI is specified in the flags * parameter for cdl_add_driver, then that driver's * attach routine will be called for future connect @@ -73,8 +82,10 @@ * * Calls the driver's attach routine with all * connection points on the list that have the same - * key information as the driver; then places the - * driver on the list so that any connection points + * key information as the driver; call-back the + * specified function to notify the driver of the + * attach status for each device. Place the driver + * on the list so that any connection points * discovered in the future that match the driver * can be handed off to the driver's attach * routine. @@ -86,14 +97,17 @@ int key1, int key2, char *prefix, - int flags); + int flags, + cdl_drv_f *func); /* * cdl_del_driver: remove a device driver * * Calls the driver's detach routine with all * connection points on the list that match the - * driver; then forgets about the driver. Future + * driver; call-back the specified function to + * notify the driver of the detach status for each + * device. Then forget about the driver. Future * calls to cdl_add_connpt with connections that * would match this driver no longer trigger calls * to the driver's attach routine. @@ -107,7 +121,8 @@ * was successful. */ extern void cdl_del_driver(cdl_p reg, - char *prefix); + char *prefix, + cdl_drv_f *func); /* * cdl_add_connpt: add a connection point @@ -124,7 +139,8 @@ extern int cdl_add_connpt(cdl_p reg, int key1, int key2, - devfs_handle_t conn); + devfs_handle_t conn, + int drv_flags); /* * cdl_del_connpt: delete a connection point @@ -138,10 +154,11 @@ * NOTE: Same caveat here about the detach calls as * in the cdl_del_driver() comment above. */ -extern void cdl_del_connpt(cdl_p reg, +extern int cdl_del_connpt(cdl_p reg, int key1, int key2, - devfs_handle_t conn); + devfs_handle_t conn, + int drv_flags); /* * cdl_iterate: find all verticies in the registry @@ -162,7 +179,7 @@ */ struct async_attach_s { - sema_t async_sema; + struct semaphore async_sema; int async_count; }; typedef struct async_attach_s *async_attach_t; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/cmn_err.h linux.ac/include/asm-ia64/sn/cmn_err.h --- linux.vanilla/include/asm-ia64/sn/cmn_err.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/cmn_err.h Thu Jan 1 01:00:00 1970 @@ -1,120 +0,0 @@ -/* $Id$ - * - * 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) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam - */ -#ifndef _ASM_SN_CMN_ERR_H -#define _ASM_SN_CMN_ERR_H - -/* -** Common error handling severity levels. Converted to be -** represented by the associated 4.3BSD syslog priorities. -*/ - -#define CE_DEBUG KERN_DEBUG /* debug */ -#define CE_CONT KERN_INFO /* continuation */ -#define CE_NOTE KERN_NOTICE /* notice */ -#define CE_WARN KERN_WARNING /* warning */ -#define CE_ALERT KERN_ALERT /* alert */ -#define CE_PANIC KERN_EMERG /* panic */ - -#define CE_LEVELMASK LOG_PRIMASK /* mask for severity level */ -#define CE_CPUID 0x8 /* prepend CPU id to output */ -#define CE_PHYSID 0x10 /* prepend CPU phys location */ -#define CE_SYNC 0x20 /* wait for uart to drain before returning */ - -/* Flags for Availmon Monitoring - * When a developer or's these bits into the cmn_err flags above, - * and they have availmon installed, certain "actions" will take - * place depending upon how they have the availmon software configured. - */ -#define CE_TOOKACTIONS 0x0100 /* Actions taken by some error */ -#define CE_RUNNINGPOOR 0x0200 /* System running degraded */ -#define CE_MAINTENANCE 0x0400 /* System needs maintenance */ -#define CE_CONFIGERROR 0x0800 /* System configured incorrectly */ - -/* Bitmasks for separating subtasks from priority levels */ -#define CE_PRIOLEVELMASK 0x00ff /* bitmask for severity levels of cmn_err */ -#define CE_SUBTASKMASK 0xff00 /* bitmask for availmon actions of cmn_err */ -#define CE_AVAILMONALL (CE_TOOKACTIONS|CE_RUNNINGPOOR| \ - CE_MAINTENANCE|CE_CONFIGERROR) - -#ifdef __KERNEL__ - -#define CE_PBPANIC KERN_CRIT /* Special define used to manipulate - * putbufndx in kernel */ - -/* Console output flushing flag and routine */ - -extern int constrlen; /* Length of current console string, if zero, - there are no characters to flush */ -#define CONBUF_LOCKED 0 /* conbuf is already locked */ -#define CONBUF_UNLOCKED 1 /* need to reacquire lock */ -#define CONBUF_DRAIN 2 /* ensure output before returning */ - -/* - * bit field descriptions for printf %r and %R formats - * - * printf("%r %R", val, reg_descp); - * struct reg_desc *reg_descp; - * - * the %r and %R formats allow formatted print of bit fields. individual - * bit fields are described by a struct reg_desc, multiple bit fields within - * a single word can be described by multiple reg_desc structures. - * %r outputs a string of the format "<bit field descriptions>" - * %R outputs a string of the format "0x%x<bit field descriptions>" - * - * The fields in a reg_desc are: - * __psunsigned_t rd_mask; An appropriate mask to isolate the bit field - * within a word, and'ed with val - * - * int rd_shift; A shift amount to be done to the isolated - * bit field. done before printing the isolate - * bit field with rd_format and before searching - * for symbolic value names in rd_values - * - * char *rd_name; If non-null, a bit field name to label any - * out from rd_format or searching rd_values. - * if neither rd_format or rd_values is non-null - * rd_name is printed only if the isolated - * bit field is non-null. - * - * char *rd_format; If non-null, the shifted bit field value - * is printed using this format. - * - * struct reg_values *rd_values; If non-null, a pointer to a table - * matching numeric values with symbolic names. - * rd_values are searched and the symbolic - * value is printed if a match is found, if no - * match is found "???" is printed. - * - */ - - -/* - * register values - * map between numeric values and symbolic values - */ -struct reg_values { - __psunsigned_t rv_value; - char *rv_name; -}; - -/* - * register descriptors are used for formatted prints of register values - * rd_mask and rd_shift must be defined, other entries may be null - */ -struct reg_desc { - k_machreg_t rd_mask; /* mask to extract field */ - int rd_shift; /* shift for extracted value, - >>, + << */ - char *rd_name; /* field name */ - char *rd_format; /* format to print field */ - struct reg_values *rd_values; /* symbolic names of values */ -}; - -#endif /* __KERNEL__ */ -#endif /* _ASM_SN_CMN_ERR_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/dmamap.h linux.ac/include/asm-ia64/sn/dmamap.h --- linux.vanilla/include/asm-ia64/sn/dmamap.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/dmamap.h Tue Apr 10 18:22:36 2001 @@ -10,6 +10,8 @@ #ifndef _ASM_SN_DMAMAP_H #define _ASM_SN_DMAMAP_H +#include <asm/sn/sv.h> + #ifdef __cplusplus extern "C" { #endif @@ -53,7 +55,7 @@ extern int dma_map(dmamap_t *, caddr_t, int); extern int dma_map2(dmamap_t *, caddr_t, caddr_t, int); extern paddr_t dma_mapaddr(dmamap_t *, caddr_t); -#ifdef IRIX +#ifdef LATER extern int dma_mapbp(dmamap_t *, buf_t *, int); #endif extern int dma_map_alenlist(dmamap_t *, struct alenlist_s *, size_t); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/eeprom.h linux.ac/include/asm-ia64/sn/eeprom.h --- linux.vanilla/include/asm-ia64/sn/eeprom.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/eeprom.h Tue Apr 10 18:22:37 2001 @@ -349,7 +349,7 @@ * is ignored. */ -#ifdef IRIX +#ifdef LATER char *eeprom_vertex_info_set( int component, int nasid, devfs_handle_t v, net_vec_t path ); #endif @@ -363,7 +363,7 @@ * if the part and mfg numbers stored there indicate that this widget * is an XBridge (and so must be part of a brick). */ -#ifdef IRIX +#ifdef LATER int is_iobrick( int nasid, int widget_num ); #endif @@ -371,11 +371,7 @@ * address passed to it and uses is_iobrick to determine whether * the widget in question is part of an SN1 IO brick. */ -#ifdef IRIX #define IS_IOBRICK(rg) is_iobrick( NASID_GET((rg)), SWIN_WIDGETNUM((rg)) ) -#else -#define IS_IOBRICK(rg) 1 -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/gda.h linux.ac/include/asm-ia64/sn/gda.h --- linux.vanilla/include/asm-ia64/sn/gda.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/gda.h Tue Apr 10 18:22:37 2001 @@ -61,7 +61,7 @@ /* Pointer to a mask of nodes with copies * of the kernel. */ char g_padding[56]; /* pad out to 128 bytes */ - nasid_t g_nasidtable[MAX_COMPACT_NODES]; /* NASID of each node, + nasid_t g_nasidtable[MAX_COMPACT_NODES+1]; /* NASID of each node, * indexed by cnodeid. */ } gda_t; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/hack.h linux.ac/include/asm-ia64/sn/hack.h --- linux.vanilla/include/asm-ia64/sn/hack.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/hack.h Tue Apr 10 18:22:37 2001 @@ -22,6 +22,10 @@ typedef int cred_t; /* This is for compilation reasons */ struct cred { int x; }; + +#define mrlock(_s, _t, _u) +#define mrunlock(_s) + /* * Hardware Graph routines that are currently stubbed! */ @@ -34,50 +38,26 @@ * Routines redefined to use linux equivalents. * ************************************************/ -#define FIXME(s) printk("FIXME: [ %s ] in %s at %s:%d\n", s, __FUNCTION__, __FILE__, __LINE__) +/* #define FIXME(s) printk("FIXME: [ %s ] in %s at %s:%d\n", s, __FUNCTION__, __FILE__, __LINE__) */ -#define sv_init(a,b,c) FIXME("Fixme: sv_init : no-op") -#define sv_wait(a,b,c,d) FIXME("Fixme: sv_wait : no-op") -#define sv_broadcast(a) FIXME("Fixme: sv_broadcast : no-op") -#define sv_destroy(a) FIXME("Fixme: sv_destroy : no-op") +#define FIXME(s) extern devfs_handle_t dummy_vrtx; #define cpuid_to_vertex(cpuid) dummy_vrtx /* (pdaindr[cpuid].pda->p_vertex) */ #define PUTBUF_LOCK(a) { FIXME("PUTBUF_LOCK"); } #define PUTBUF_UNLOCK(a) { FIXME("PUTBUF_UNLOCK"); } -static inline int sv_signal(sv_t *a) {FIXME("sv_signal : return 0"); return (0); } - -#define cmn_err(x,y...) { FIXME("cmn_err : use printk"); printk(x y); } typedef int (*splfunc_t)(void); -extern int badaddr_val(volatile void *, int , volatile void *); - -extern int cap_able_cred(uint64_t a, uint64_t b); - -#define _CAP_CRABLE(cr,c) (cap_able_cred(cr,c)) -#define CAP_MEMORY_MGT (0x01LL << 25) -#define CAP_DEVICE_MGT (0x01LL << 37) - -#define io_splock(l) l -#define io_spunlock(l,s) /* move to stubs.c yet */ -#define spinlock_destroy(a) /* needed by pcibr_detach() */ -#define mutex_spinlock(a) 0 -#define mutex_spinunlock(a,b) -#define mutex_spinlock_spl(x,y) y -#define mutex_init(a,b,c) ; -#define mutex_lock(a,b) ; -#define mutex_unlock(a) ; #define dev_to_vhdl(dev) 0 #define get_timestamp() 0 #define us_delay(a) -#define v_mapphys(a,b,c) printk("Fixme: v_mapphys - soft->base 0x%p\n", b); +#define v_mapphys(a,b,c) 0 // printk("Fixme: v_mapphys - soft->base 0x%p\n", b); #define splhi() 0 #define spl7 splhi() #define splx(s) -#define spinlock_init(x,name) mutex_init(x, MUTEX_DEFAULT, name); extern void * kmem_alloc_node(register size_t, register int, cnodeid_t); extern void * kmem_zalloc(size_t, int); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/hcl.h linux.ac/include/asm-ia64/sn/hcl.h --- linux.vanilla/include/asm-ia64/sn/hcl.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/hcl.h Tue Apr 10 18:22:37 2001 @@ -13,6 +13,7 @@ extern spinlock_t hcl_spinlock; extern devfs_handle_t hcl_handle; /* HCL driver */ extern devfs_handle_t hwgraph_root; +extern devfs_handle_t linux_busnum; typedef long labelcl_info_place_t; @@ -22,7 +23,6 @@ /* Support for INVENTORY */ struct inventory_s; struct invplace_s; -extern struct invplace_s invplace_none; /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/hwcntrs.h linux.ac/include/asm-ia64/sn/hwcntrs.h --- linux.vanilla/include/asm-ia64/sn/hwcntrs.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/hwcntrs.h Tue Apr 10 18:22:37 2001 @@ -73,7 +73,6 @@ } rcb_slot_t; #if defined(__KERNEL__) -// #include <sys/immu.h> typedef struct sn0_refcnt_args_32 { uint64_t vaddr; uint64_t len; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/intr.h linux.ac/include/asm-ia64/sn/intr.h --- linux.vanilla/include/asm-ia64/sn/intr.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/intr.h Tue Apr 10 18:22:37 2001 @@ -10,6 +10,9 @@ #ifndef _ASM_SN_INTR_H #define _ASM_SN_INTR_H +/* Subnode wildcard */ +#define SUBNODE_ANY -1 + /* Number of interrupt levels associated with each interrupt register. */ #define N_INTPEND_BITS 64 @@ -24,8 +27,6 @@ #if LANGUAGE_C -#if defined(CONFIG_IA64_SGI_IO) - #define II_NAMELEN 24 /* @@ -36,7 +37,7 @@ intr_func_t iv_func; /* Interrupt handler function */ intr_func_t iv_prefunc; /* Interrupt handler prologue func */ void *iv_arg; /* Argument to pass to handler */ -#ifdef IRIX +#ifdef LATER thd_int_t iv_tinfo; /* Thread info */ #endif cpuid_t iv_mustruncpu; /* Where we must run. */ @@ -93,7 +94,7 @@ call an intr routine. */ intr_info_t info[N_INTPEND_BITS]; /* information needed only to maintain interrupts. */ - lock_t vector_lock; /* Lock for this and the + spinlock_t vector_lock; /* Lock for this and the masks in the PDA. */ splfunc_t vector_spl; /* vector_lock req'd spl */ int vector_state; /* Initialized to zero. @@ -122,15 +123,12 @@ #define hub_intrinfo0 private.p_intmasks.dispatch0->info #define hub_intrinfo1 private.p_intmasks.dispatch1->info -#endif /* CONFIG_IA64_SGI_IO */ - /* * Macros to manipulate the interrupt register on the calling hub chip. */ #define LOCAL_HUB_SEND_INTR(_level) LOCAL_HUB_S(PI_INT_PEND_MOD, \ (0x100|(_level))) -#if defined(CONFIG_IA64_SGI_IO) #define REMOTE_HUB_PI_SEND_INTR(_hub, _sn, _level) \ REMOTE_HUB_PI_S((_hub), _sn, PI_INT_PEND_MOD, (0x100|(_level))) @@ -138,7 +136,6 @@ REMOTE_HUB_PI_S(cputonasid(_cpuid), \ SUBNODE(cputoslice(_cpuid)), \ PI_INT_PEND_MOD, (0x100|(_level))) -#endif /* CONFIG_IA64_SGI_IO*/ /* * When clearing the interrupt, make sure this clear does make it @@ -153,7 +150,6 @@ REMOTE_HUB_PI_S((_hub), (_sn), PI_INT_PEND_MOD, (_level)), \ REMOTE_HUB_PI_L((_hub), (_sn), PI_INT_PEND0) -#if defined(CONFIG_IA64_SGI_IO) /* Special support for use by gfx driver only. Supports special gfx hub interrupt. */ extern void install_gfxintr(cpuid_t cpu, ilvl_t swlevel, intr_func_t intr_func, void *intr_arg); @@ -164,7 +160,6 @@ */ extern void intr_block_bit(cpuid_t cpu, int bit); extern void intr_unblock_bit(cpuid_t cpu, int bit); -#endif /* CONFIG_IA64_SGI_IO */ #endif /* LANGUAGE_C */ @@ -246,6 +241,13 @@ # define IO_ERROR_INTR 38 /* set up by prom */ # define DEBUG_INTR_B 37 /* used by symmon to stop all cpus */ # define DEBUG_INTR_A 36 +#endif + +#ifdef CONFIG_IA64_SGI_SN1 +// These aren't strictly accurate or complete. See the +// Synergy Spec. for details. +#define SGI_UART_IRQ (65) +#define SGI_HUB_ERROR_IRQ (182) #endif #endif /* _ASM_SN_INTR_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/intr_public.h linux.ac/include/asm-ia64/sn/intr_public.h --- linux.vanilla/include/asm-ia64/sn/intr_public.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/intr_public.h Tue Apr 10 18:22:37 2001 @@ -7,9 +7,10 @@ * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. * Copyright (C) 2000 by Colin Ngam */ -#ifndef __SYS_SN_INTR_PUBLIC_H__ -#define __SYS_SN_INTR_PUBLIC_H__ +#ifndef _ASM_SN_INTR_PUBLIC_H__ +#define _ASM_SN_INTR_PUBLIC_H__ +#include <linux/config.h> /* REMEMBER: If you change these, the whole world needs to be recompiled. * It would also require changing the hubspl.s code and SN0/intr.c @@ -22,7 +23,6 @@ #define INTPEND0_MAXMASK (N_INTPEND0_MASKS - 1) #define INTPEND1_MAXMASK (N_INTPEND1_MASKS - 1) -#include <linux/config.h> #if _LANGUAGE_C #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) #include <asm/sn/sn1/arch.h> @@ -56,5 +56,4 @@ } hub_intmasks_t; #endif /* _LANGUAGE_C */ -#endif /* __SYS_SN_INTR_PUBLIC_H__ */ - +#endif /* _ASM_SN_INTR_PUBLIC_H__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/invent.h linux.ac/include/asm-ia64/sn/invent.h --- linux.vanilla/include/asm-ia64/sn/invent.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/invent.h Tue Apr 10 18:22:37 2001 @@ -30,6 +30,10 @@ #define app32_ptr_t unsigned long #define graph_vertex_place_t long #define GRAPH_VERTEX_NONE ((devfs_handle_t)-1) +#define GRAPH_EDGE_PLACE_NONE ((graph_edge_place_t)0) +#define GRAPH_INFO_PLACE_NONE ((graph_info_place_t)0) +#define GRAPH_VERTEX_PLACE_NONE ((graph_vertex_place_t)0) + typedef struct inventory_s { struct inventory_s *inv_next; /* next inventory record in list */ @@ -105,6 +109,8 @@ #define INV_RPS 23 /* redundant power source */ #define INV_TPU 24 /* Tensor Processing Unit */ #define INV_FCNODE 25 /* Helper class for SCSI classes, not in classes[] */ +#define INV_USB 26 /* Universal Serial Bus */ +#define INV_1394NODE 27 /* helper class for 1394/SPB2 classes, not in classes[] */ /* types for class processor */ #define INV_CPUBOARD 1 @@ -187,8 +193,11 @@ #define INV_QL_12160 17 /* qlogic 12160 */ #define INV_QL_2100 18 /* qLogic 2100 Fibrechannel */ #define INV_QL_2200 19 /* qLogic 2200 Fibrechannel */ -#define INV_SBP2 20 /* SBP2 protocol over OHCI on 1394 */ - +#define INV_PR_HIO_D 20 /* Prisa HIO Dual channel */ +#define INV_PR_PCI64_D 21 /* Prisa PCI-64 Dual channel */ +#define INV_QL_2200A 22 /* qLogic 2200A Fibrechannel */ +#define INV_SBP2 23 /* SBP2 protocol over OHCI on 1394 */ +#define INV_QL_2300 24 /* qLogic 2300 Fibrechannel */ /* states for INV_SCSIDRIVE type of class disk */ @@ -215,6 +224,7 @@ #define INV_SIDCACHE 8 #define INV_MAIN_MB 9 #define INV_HUBSPC 10 /* HUBSPC */ +#define INV_TIDCACHE 11 /* types for class serial */ #define INV_CDSIO 1 /* Central Data serial board */ @@ -405,6 +415,7 @@ #define INV_NET_ISDN_PRI 8 /* PRI ISDN */ #define INV_NET_HIPPIS 9 /* HIPPI-Serial */ #define INV_NET_GSN 10 /* GSN (aka HIPPI-6400) */ +#define INV_NET_MYRINET 11 /* Myricom PCI network */ /* controllers for network types, unique within class network */ #define INV_ETHER_EC 0 /* IP6 integral controller */ @@ -463,6 +474,7 @@ #define INV_OPTICAL 7 /* optical disks (read-write) */ #define INV_CHANGER 8 /* jukebox's for CDROMS, for example */ #define INV_COMM 9 /* Communications device */ +#define INV_STARCTLR 12 /* Storage Array Controller */ #define INV_RAIDCTLR 32 /* RAID ctlr actually gives type 0 */ /* bit definitions for state field for class INV_SCSI */ @@ -495,6 +507,7 @@ #define INV_VIDEO_RACER 11 /* SpeedRacer Pro Video */ #define INV_VIDEO_EVO 12 /* EVO Personal Video */ #define INV_VIDEO_XTHD 13 /* XIO XT-HDTV video */ +#define INV_VIDEO_XTDIGVID 14 /* XIO XT-HDDIGVID video */ /* states for video class INV_VIDEO_EXPRESS */ @@ -568,10 +581,7 @@ #define INV_7of9_PANEL 5 /* 7of9 flatpanel board and panel */ /* types for class INV_IEEE1394 */ -#define INV_OHCI 0 /* Ohci IEEE1394 pci card */ -#define INV_RAWISO1394 10 /* Raw Isochronous IEEE 1394 protocol driver */ -#define INV_RAWASYNC1394 11 /* Raw Asynchronous IEEE 1394 protocol driver */ -#define INV_AVC1394 12 /* Audio, Video & Control (AV/C) IEEE 1394 protocol driver */ +#define INV_OHCI 0 /* Ohci IEEE1394 pci card */ /* state for class INV_IEEE1394 & type INV_OHCI */ #define INV_IEEE1394_STATE_TI_REV_1 0 @@ -583,6 +593,51 @@ #define INV_TPU_EXT 0 /* External XIO Tensor Processing Unit */ #define INV_TPU_XIO 1 /* Internal XIO Tensor Processing Unit */ +/* + * USB Types. The upper 8 bits contain general usb device class and are used to + * qualify the lower 8 bits which contain device type within a usb class. + * Use USB_INV_DEVCLASS and USB_INV_DEVTYPE to to decode an i_type, and + * USB_INV_TYPE to set it. + */ + +#define USB_INV_DEVCLASS(invtype) ((invtype) >> 8) +#define USB_INV_DEVTYPE(invtype) ((invtype) & 0xf) +#define USB_INV_TYPE(usbclass, usbtype) (((usbclass) << 8) | (usbtype)) + +/* + * USB device classes. These classes might not match the classes as defined + * by the usb spec, but where possible we will try. + */ + +#define USB_INV_CLASS_RH 0x00 /* root hub (ie. controller) */ +#define USB_INV_CLASS_HID 0x03 /* human interface device */ +#define USB_INV_CLASS_HUB 0x09 /* hub device */ + +/* + * USB device types within a class. These will not match USB device types, + * as the usb is not consistent on how specific types are defined (sometimes + * they are found in the interface subclass, sometimes (as in HID devices) they + * are found within data generated by the device (hid report descriptors for + * example). + */ + +/* + * RH types + */ + +#define USB_INV_RH_OHCI 0x01 /* ohci root hub */ + +/* + * HID types + */ + +#define USB_INV_HID_KEYBOARD 0x01 /* kbd (HID class) */ +#define USB_INV_HID_MOUSE 0x02 /* mouse (HID class) */ + +/* + * HUB types - none yet + */ + typedef struct invent_generic_s { unsigned short ig_module; unsigned short ig_slot; @@ -618,6 +673,8 @@ cpu_inv_t ic_cpu_info; unsigned short ic_cpuid; unsigned short ic_slice; + unsigned short ic_cpumode; + } invent_cpuinfo_t; typedef struct invent_rpsinfo { @@ -659,9 +716,14 @@ inventory_t *invplace_inv; /* place in inv list on vertex */ } invplace_t; /* Magic cookie placeholder in inventory list */ +extern invplace_t invplace_none; +#define INVPLACE_NONE invplace_none + extern void add_to_inventory(int, int, int, int, int); extern void replace_in_inventory(inventory_t *, int, int, int, int, int); +extern void start_scan_inventory(invplace_t *); extern inventory_t *get_next_inventory(invplace_t *); +extern void end_scan_inventory(invplace_t *); extern inventory_t *find_inventory(inventory_t *, int, int, int, int, int); extern int scaninvent(int (*)(inventory_t *, void *), void *); extern int get_sizeof_inventory(int); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/io.h linux.ac/include/asm-ia64/sn/io.h --- linux.vanilla/include/asm-ia64/sn/io.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/io.h Tue Apr 10 18:22:37 2001 @@ -12,20 +12,12 @@ #define _ASM_SN_IO_H #include <linux/config.h> + #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) #include <asm/sn/sn1/addrs.h> #endif -#define IO_SPACE_BASE IO_BASE - /* Because we only have PCI I/O ports. */ -#if !defined(CONFIG_IA64_SGI_IO) -#define IO_SPACE_LIMIT 0xffffffff - -/* No isa_* versions, the Origin doesn't have ISA / EISA bridges. */ - -#else /* CONFIG_IA64_SGI_IO */ - #define IIO_ITTE_BASE 0x400160 /* base of translation table entries */ #define IIO_ITTE(bigwin) (IIO_ITTE_BASE + 8*(bigwin)) @@ -71,7 +63,5 @@ #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) #include <asm/sn/sn1/hubio.h> #endif - -#endif /* CONFIG_IA64_SGI_IO */ #endif /* _ASM_SN_IO_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/ioerror.h linux.ac/include/asm-ia64/sn/ioerror.h --- linux.vanilla/include/asm-ia64/sn/ioerror.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/ioerror.h Tue Apr 10 18:22:37 2001 @@ -10,6 +10,7 @@ #ifndef _ASM_SN_IOERROR_H #define _ASM_SN_IOERROR_H +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) /* * Macros defining the various Errors to be handled as part of @@ -177,6 +178,7 @@ MODE_DEVREENABLE /* Reenable pass */ } ioerror_mode_t; +#endif /* C || C++ */ typedef int error_handler_f(void *, int, ioerror_mode_t, ioerror_t *); typedef void *error_handler_arg_t; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/ioerror_handling.h linux.ac/include/asm-ia64/sn/ioerror_handling.h --- linux.vanilla/include/asm-ia64/sn/ioerror_handling.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/ioerror_handling.h Tue Apr 10 18:22:37 2001 @@ -12,7 +12,7 @@ #include <linux/config.h> -#ifdef __KERNEL__ +#if __KERNEL__ /* * Basic types required for io error handling interfaces. @@ -255,7 +255,7 @@ int code = 0; /* Check if we have a valid hwgraph vertex */ -#ifdef IRIX +#ifdef LATER if (!dev_is_vertex(v)) return(code); #endif @@ -276,18 +276,6 @@ } ASSERT(v_error_skip_env_get(v, error_env) == GRAPH_SUCCESS); code = setjmp(*error_env); -#ifdef IRIX - /* NOTE: It might be OK to leave the allocated jump buffer on the - * vertex. This can be used for later purposes. - */ - if (code) { - /* This is the case where a long jump has been taken from one - * one of the error handling interfaces. - */ - if (v_error_skip_env_clear(v, error_env) == GRAPH_SUCCESS) - kfree(error_env); - } -#endif return(code); } #endif /* CONFIG_SGI_IO_ERROR_HANDLING */ @@ -309,8 +297,6 @@ * thru the calls the io error handling layer. */ #if defined(CONFIG_SGI_IO_ERROR_HANDLING) -#define IS_DEVICE_SHUTDOWN(_d) (error_state_get(_d) == ERROR_STATE_SHUTDOWN) -#else extern boolean_t is_device_shutdown(devfs_handle_t); #define IS_DEVICE_SHUTDOWN(_d) (is_device_shutdown(_d)) #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/iograph.h linux.ac/include/asm-ia64/sn/iograph.h --- linux.vanilla/include/asm-ia64/sn/iograph.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/iograph.h Tue Apr 10 18:22:37 2001 @@ -90,6 +90,7 @@ #define EDGE_LBL_PROM "prom" #define EDGE_LBL_RACK "rack" #define EDGE_LBL_RDISK "rdisk" +#define EDGE_LBL_REPEATER_ROUTER "repeaterrouter" #define EDGE_LBL_ROUTER "router" #define EDGE_LBL_RPOS "bay" /* Position in rack */ #define EDGE_LBL_SCSI "scsi" @@ -117,9 +118,9 @@ #define EDGE_LBL_RPS "rps" /* redundant power supply */ #define EDGE_LBL_XBOX_RPS "xbox_rps" /* redundant power supply for xbox unit */ #define EDGE_LBL_IOBRICK "iobrick" -#define EDGE_LBL_PBRICK "pbrick" -#define EDGE_LBL_IBRICK "ibrick" -#define EDGE_LBL_XBRICK "xbrick" +#define EDGE_LBL_PBRICK "Pbrick" +#define EDGE_LBL_IBRICK "Ibrick" +#define EDGE_LBL_XBRICK "Xbrick" #define EDGE_LBL_CPUBUS "cpubus" /* CPU Interfaces (SysAd) */ /* vertex info labels in hwgraph */ @@ -134,6 +135,8 @@ #define INFO_LBL_DKIOTIME "_dkiotime" #define INFO_LBL_DRIVER "_driver" /* points to attached device_driver_t */ #define INFO_LBL_ELSC "_elsc" +#define INFO_LBL_SUBCH "_subch" /* system controller subchannel */ +#define INFO_LBL_L1SCP "_l1scp" /* points to l1sc_t */ #define INFO_LBL_FC_PORTNAME "_fc_portname" #define INFO_LBL_GIOIO "_gioio" #define INFO_LBL_GFUNCS "_gioio_ops" /* ops vector for gio providers */ @@ -196,5 +199,21 @@ #if defined(__KERNEL__) void init_all_devices(void); #endif /* __KERNEL__ */ + +#include <asm/sn/xtalk/xbow.h> /* For get MAX_PORT_NUM */ + +int io_brick_map_widget(char, int); +int io_path_map_widget(devfs_handle_t); + +/* + * Map a brick's widget number to a meaningful int + */ + +struct io_brick_map_s { + char ibm_type; /* brick type, e.g. */ + /* 'I' for Ibrick */ + int ibm_map_wid[MAX_PORT_NUM]; /* wid to int map */ +}; + #endif /* _ASM_SN_IOGRAPH_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/klconfig.h linux.ac/include/asm-ia64/sn/klconfig.h --- linux.vanilla/include/asm-ia64/sn/klconfig.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/klconfig.h Tue Apr 10 18:22:37 2001 @@ -12,6 +12,8 @@ #ifndef _ASM_SN_KLCONFIG_H #define _ASM_SN_KLCONFIG_H +#include <linux/config.h> + /* * klconfig.h */ @@ -32,7 +34,6 @@ * that offsets of existing fields do not change. */ -#include <linux/config.h> #include <linux/types.h> #include <asm/sn/types.h> #include <asm/sn/slotnum.h> @@ -60,11 +61,10 @@ #define SIZE_PAD 4096 /* 4k padding for structures */ #if (defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)) && defined(BRINGUP) /* MAX_SLOTS_PER_NODE??? */ /* - * 1 NODE brick, 2 Router bricks (1 local, 1 meta), 6 XIO Widgets, - * 1 Midplane (midplane will likely become IO brick when Bruce cleans - * up IP35 klconfig) + * 1 NODE brick, 3 Router bricks (1 local, 1 meta, 1 repeater), + * 6 XIO Widgets, 1 Xbow, 1 gfx */ -#define MAX_SLOTS_PER_NODE (1 + 2 + 6 + 1) +#define MAX_SLOTS_PER_NODE (1 + 3 + 6 + 1 + 1) #else /* * 1 NODE brd, 2 Router brd (1 8p, 1 meta), 6 Widgets, @@ -88,7 +88,7 @@ #define VISITED_BOARD 0x08 /* Used for compact hub numbering. */ #define LOCAL_MASTER_IO6 0x10 /* master io6 for that node */ #define GLOBAL_MASTER_IO6 0x20 -#define THIRD_NIC_PRESENT 0x40 /* for future use */ +#define GLOBAL_MASTER_EXT 0x40 /* extend master io6 to other bus on ibrick */ #define SECOND_NIC_PRESENT 0x80 /* addons like MIO are present */ /* klinfo->flags fields */ @@ -119,15 +119,9 @@ typedef struct console_s { -#if defined(CONFIG_IA64_SGI_IO) /* FIXME */ __psunsigned_t uart_base; __psunsigned_t config_base; __psunsigned_t memory_base; -#else - unsigned long uart_base; - unsigned long config_base; - unsigned long memory_base; -#endif short baud; short flag; int type; @@ -164,18 +158,20 @@ #define KL_CONFIG_INFO_SET_OFFSET(_nasid, _off) \ (KL_CONFIG_HDR(_nasid)->ch_board_info = (_off)) -#if !defined(SIMULATED_KLGRAPH) +#ifndef __ia64 #define KL_CONFIG_INFO(_nasid) \ (lboard_t *)((KL_CONFIG_HDR(_nasid)->ch_board_info) ? \ NODE_OFFSET_TO_K0((_nasid), KL_CONFIG_HDR(_nasid)->ch_board_info) : \ 0) #else -/* - * For Fake klgraph info. - */ -extern kl_config_hdr_t *linux_klcfg; -#define KL_CONFIG_INFO(_nasid) (lboard_t *)((ulong)linux_klcfg->ch_board_info | 0xe000000000000000) -#endif /* CONFIG_IA64_SGI_IO */ +#define NODE_OFFSET_TO_LBOARD(nasid,off) (lboard_t*)(NODE_CAC_BASE(nasid) + (off)) + +#define KL_CONFIG_INFO(_nasid) \ + (lboard_t *)((KL_CONFIG_HDR(_nasid)->ch_board_info) ? \ + NODE_OFFSET_TO_LBOARD((_nasid), KL_CONFIG_HDR(_nasid)->ch_board_info) : \ + NULL) + +#endif /* __ia64 */ #define KL_CONFIG_MAGIC(_nasid) (KL_CONFIG_HDR(_nasid)->ch_magic) @@ -187,23 +183,13 @@ /* --- New Macros for the changed kl_config_hdr_t structure --- */ -#if defined(CONFIG_IA64_SGI_IO) #define PTR_CH_MALLOC_HDR(_k) ((klc_malloc_hdr_t *)\ ((__psunsigned_t)_k + (_k->ch_malloc_hdr_off))) -#else -#define PTR_CH_MALLOC_HDR(_k) ((klc_malloc_hdr_t *)\ - (unsigned long)_k + (_k->ch_malloc_hdr_off))) -#endif #define KL_CONFIG_CH_MALLOC_HDR(_n) PTR_CH_MALLOC_HDR(KL_CONFIG_HDR(_n)) -#if defined(CONFIG_IA64_SGI_IO) #define PTR_CH_CONS_INFO(_k) ((console_t *)\ ((__psunsigned_t)_k + (_k->ch_cons_off))) -#else -#define PTR_CH_CONS_INFO(_k) ((console_t *)\ - ((unsigned long)_k + (_k->ch_cons_off))) -#endif #define KL_CONFIG_CH_CONS_INFO(_n) PTR_CH_CONS_INFO(KL_CONFIG_HDR(_n)) @@ -374,6 +360,7 @@ #define KLTYPE_IP27 (KLCLASS_CPU | 0x1) /* 2 CPUs(R10K) per board */ #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) #define KLTYPE_IP35 KLTYPE_IP27 +#define KLTYPE_IP37 KLTYPE_IP35 #endif #define KLTYPE_WEIRDIO (KLCLASS_IO | 0x0) @@ -394,6 +381,8 @@ #define KLTYPE_TPU (KLCLASS_IO | 0xB) /* Tensor Processing Unit */ #define KLTYPE_GSN_A (KLCLASS_IO | 0xC) /* Main GSN board */ #define KLTYPE_GSN_B (KLCLASS_IO | 0xD) /* Auxiliary GSN board */ +#define KLTYPE_SHOEHORN (KLCLASS_IO | 0xE) +#define KLTYPE_SERIAL_HIPPI (KLCLASS_IO | 0xF) #define KLTYPE_GFX (KLCLASS_GFX | 0x0) /* unknown graphics type */ #define KLTYPE_GFX_KONA (KLCLASS_GFX | 0x1) /* KONA graphics on IP27 */ @@ -404,11 +393,12 @@ #define KLTYPE_ROUTER2 KLTYPE_ROUTER /* Obsolete! */ #define KLTYPE_NULL_ROUTER (KLCLASS_ROUTER | 0x2) #define KLTYPE_META_ROUTER (KLCLASS_ROUTER | 0x3) +#define KLTYPE_REPEATER_ROUTER (KLCLASS_ROUTER | 0x4) #define KLTYPE_WEIRDMIDPLANE (KLCLASS_MIDPLANE | 0x0) #define KLTYPE_MIDPLANE8 (KLCLASS_MIDPLANE | 0x1) /* 8 slot backplane */ #define KLTYPE_MIDPLANE KLTYPE_MIDPLANE8 -#define KLTYPE_PBRICK_XBOW (KLCLASS_MIDPLANE | 0x2) +#define KLTYPE_IOBRICK_XBOW (KLCLASS_MIDPLANE | 0x2) #define KLTYPE_IOBRICK (KLCLASS_IOBRICK | 0x0) #define KLTYPE_IBRICK (KLCLASS_IOBRICK | 0x1) @@ -485,7 +475,7 @@ #define KLCF_NUM_COMPS(_brd) ((_brd)->brd_numcompts) #define KLCF_MODULE_ID(_brd) ((_brd)->brd_module) -#ifndef SIMULATED_KLGRAPH +#ifndef __ia64 #define KLCF_NEXT(_brd) ((_brd)->brd_next ? (lboard_t *)((_brd)->brd_next): NULL) #define KLCF_COMP(_brd, _ndx) \ (klinfo_t *)(NODE_OFFSET_TO_K0(NASID_GET(_brd), \ @@ -494,14 +484,18 @@ (NODE_OFFSET_TO_K0(NASID_GET(_brd), (_comp)->errinfo)) #else -/* - * For fake klgraph info. - */ -#define KLCF_COMP(_brd, _ndx) (klinfo_t *)((ulong) 0xe000000000000000 |((_brd)->brd_compts[(_ndx)])) -#define KLCF_NEXT(_brd) ((_brd)->brd_next ? (lboard_t *)((ulong) 0xe000000000000000 | (_brd->brd_next)) : NULL) -#define KLCF_COMP_ERROR(_brd, _comp) (_brd = _brd , (_comp)->errinfo) -#endif /* SIMULATED_KLGRAPH */ +#define NODE_OFFSET_TO_KLINFO(n,off) ((klinfo_t*) TO_NODE_CAC(n,off)) +#define KLCF_NEXT(_brd) \ + ((_brd)->brd_next ? \ + (NODE_OFFSET_TO_LBOARD(NASID_GET(_brd), (_brd)->brd_next)): NULL) +#define KLCF_COMP(_brd, _ndx) \ + (NODE_OFFSET_TO_KLINFO(NASID_GET(_brd), (_brd)->brd_compts[(_ndx)])) + +#define KLCF_COMP_ERROR(_brd, _comp) \ + (NODE_OFFSET_TO_K0(NASID_GET(_brd), (_comp)->errinfo)) + +#endif /* __ia64 */ #define KLCF_COMP_TYPE(_comp) ((_comp)->struct_type) #define KLCF_BRIDGE_W_ID(_comp) ((_comp)->physid) /* Widget ID */ @@ -581,6 +575,11 @@ #define KLSTRUCT_GSN_A 29 #define KLSTRUCT_GSN_B 30 #define KLSTRUCT_XTHD 31 +#define KLSTRUCT_QLFIBRE 32 +#define KLSTRUCT_1394 33 +#define KLSTRUCT_USB 34 +#define KLSTRUCT_USBKBD 35 +#define KLSTRUCT_USBMS 36 /* * These are the indices of various components within a lboard structure. @@ -845,6 +844,15 @@ mio_t mio_specific ; } klmio_t ; +/* + * USB info + */ + +typedef struct klusb_s { + klinfo_t usb_info; /* controller info */ + void *usb_bus; /* handle to usb_bus_t */ + uint64_t usb_controller; /* ptr to controller info */ +} klusb_t ; typedef union klcomp_s { klcpu_t kc_cpu; @@ -862,6 +870,7 @@ klfddi_t kc_fddi; klmio_t kc_mio; klmod_serial_num_t kc_snum ; + klusb_t kc_usb; } klcomp_t; typedef union kldev_s { /* for device structure allocation */ @@ -925,7 +934,6 @@ extern klcpu_t *nasid_slice_to_cpuinfo(nasid_t, int); -#if defined(CONFIG_IA64_SGI_IO) extern xwidgetnum_t nodevertex_widgetnum_get(devfs_handle_t node_vtx); extern devfs_handle_t nodevertex_xbow_peer_get(devfs_handle_t node_vtx); extern lboard_t *find_gfxpipe(int pipenum); @@ -954,8 +962,5 @@ extern int is_master_baseio(nasid_t,moduleid_t,slotid_t); extern nasid_t get_actual_nasid(lboard_t *brd) ; extern net_vec_t klcfg_discover_route(lboard_t *, lboard_t *, int); -#else /* CONFIG_IA64_SGI_IO */ -extern klcpu_t *sn_get_cpuinfo(cpuid_t cpu); -#endif /* CONFIG_IA64_SGI_IO */ #endif /* _ASM_SN_KLCONFIG_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/kldir.h linux.ac/include/asm-ia64/sn/kldir.h --- linux.vanilla/include/asm-ia64/sn/kldir.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/kldir.h Tue Apr 10 18:22:37 2001 @@ -13,9 +13,7 @@ #define _ASM_SN_KLDIR_H #include <linux/config.h> -#if defined(CONFIG_IA64_SGI_IO) #include <asm/sn/sgi.h> -#endif /* * The kldir memory area resides at a fixed place in each node's memory and @@ -136,88 +134,11 @@ #define KLDIR_OFF_STRIDE 0x28 #endif /* LANGUAGE_ASSEMBLY */ -#if !defined(CONFIG_IA64_SGI_IO) - -/* - * This is defined here because IP27_SYMMON_STK_SIZE must be at least what - * we define here. Since it's set up in the prom. We can't redefine it later - * and expect more space to be allocated. The way to find out the true size - * of the symmon stacks is to divide SYMMON_STK_SIZE by SYMMON_STK_STRIDE - * for a particular node. - */ -#define SYMMON_STACK_SIZE 0x8000 - -#if defined (PROM) || defined (SABLE) - -/* - * These defines are prom version dependent. No code other than the IP27 - * prom should attempt to use these values. - */ -#define IP27_LAUNCH_OFFSET 0x2400 -#define IP27_LAUNCH_SIZE 0x400 -#define IP27_LAUNCH_COUNT 2 -#define IP27_LAUNCH_STRIDE 0x200 - -#define IP27_KLCONFIG_OFFSET 0x4000 -#define IP27_KLCONFIG_SIZE 0xc000 -#define IP27_KLCONFIG_COUNT 1 -#define IP27_KLCONFIG_STRIDE 0 - -#define IP27_NMI_OFFSET 0x3000 -#define IP27_NMI_SIZE 0x40 -#define IP27_NMI_COUNT 2 -#define IP27_NMI_STRIDE 0x40 - -#define IP27_PI_ERROR_OFFSET 0x12000 -#define IP27_PI_ERROR_SIZE 0x4000 -#define IP27_PI_ERROR_COUNT 1 -#define IP27_PI_ERROR_STRIDE 0 - -#define IP27_SYMMON_STK_OFFSET 0x25000 -#define IP27_SYMMON_STK_SIZE 0xe000 -#define IP27_SYMMON_STK_COUNT 2 -/* IP27_SYMMON_STK_STRIDE must be >= SYMMON_STACK_SIZE */ -#define IP27_SYMMON_STK_STRIDE 0x7000 - -#define IP27_FREEMEM_OFFSET 0x19000 -#define IP27_FREEMEM_SIZE -1 -#define IP27_FREEMEM_COUNT 1 -#define IP27_FREEMEM_STRIDE 0 - -#endif /* PROM || SABLE*/ -/* - * There will be only one of these in a partition so the IO6 must set it up. - */ -#define IO6_GDA_OFFSET 0x11000 -#define IO6_GDA_SIZE 0x400 -#define IO6_GDA_COUNT 1 -#define IO6_GDA_STRIDE 0 - -/* - * save area of kernel nmi regs in the prom format - */ -#define IP27_NMI_KREGS_OFFSET 0x11400 -#define IP27_NMI_KREGS_CPU_SIZE 0x200 -/* - * save area of kernel nmi regs in eframe format - */ -#define IP27_NMI_EFRAME_OFFSET 0x11800 -#define IP27_NMI_EFRAME_SIZE 0x200 - -#define KLDIR_ENT_SIZE 0x40 -#define KLDIR_MAX_ENTRIES (0x400 / 0x40) - -#endif /* !CONFIG_IA64_SGI_IO */ - #ifdef _LANGUAGE_C typedef struct kldir_ent_s { u64 magic; /* Indicates validity of entry */ off_t offset; /* Offset from start of node space */ -#if defined(CONFIG_IA64_SGI_IO) /* FIXME */ __psunsigned_t pointer; /* Pointer to area in some cases */ -#else - unsigned long pointer; /* Pointer to area in some cases */ -#endif size_t size; /* Size in bytes */ u64 count; /* Repeat count if array, 1 if not */ size_t stride; /* Stride if array, 0 if not */ @@ -227,7 +148,6 @@ } kldir_ent_t; #endif /* _LANGUAGE_C */ -#if defined(CONFIG_IA64_SGI_IO) #define KLDIR_ENT_SIZE 0x40 #define KLDIR_MAX_ENTRIES (0x400 / 0x40) @@ -240,7 +160,5 @@ #else #error "kldir.h is currently defined for IP27 and IP35 platforms only" #endif - -#endif /* CONFIG_IA64_SGI_IO */ #endif /* _ASM_SN_KLDIR_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/ksys/elsc.h linux.ac/include/asm-ia64/sn/ksys/elsc.h --- linux.vanilla/include/asm-ia64/sn/ksys/elsc.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/ksys/elsc.h Tue Apr 10 18:22:37 2001 @@ -11,6 +11,7 @@ #define _ASM_SN_KSYS_ELSC_H #include <linux/config.h> + #if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) #include <asm/sn/ksys/l1.h> #endif @@ -48,7 +49,7 @@ int elsc_msg_callback(elsc_t *e, void (*callback)(void *callback_data, char *msg), void *callback_data); -#if 0 +#ifdef LATER char *elsc_errmsg(int code); int elsc_nvram_write(elsc_t *e, int addr, char *buf, int len); @@ -68,7 +69,7 @@ */ int elsc_version(elsc_t *e, char *result); -#if 0 +#ifdef LATER int elsc_debug_set(elsc_t *e, u_char byte1, u_char byte2); int elsc_debug_get(elsc_t *e, u_char *byte1, u_char *byte2); #endif @@ -90,7 +91,7 @@ int elsc_unlock(elsc_t *e); int elsc_display_char(elsc_t *e, int led, int chr); int elsc_display_digit(elsc_t *e, int led, int num, int l_case); -#if 0 +#ifdef LATER int elsc_display_mesg(elsc_t *e, char *chr); /* 8-char input */ int elsc_password_set(elsc_t *e, char *password); /* 4-char input */ int elsc_password_get(elsc_t *e, char *password); /* 4-char output */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/ksys/l1.h linux.ac/include/asm-ia64/sn/ksys/l1.h --- linux.vanilla/include/asm-ia64/sn/ksys/l1.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/ksys/l1.h Tue Apr 10 18:22:37 2001 @@ -80,11 +80,11 @@ * use == BRL1_SUBCH_FREE */ uint target; /* type, rack and slot of component to * which this subchannel is directed */ - int packet_arrived; /* true if packet arrived on + atomic_t packet_arrived; /* true if packet arrived on * this subchannel */ sc_cq_t * iqp; /* input queue for this subchannel */ sv_t arrive_sv; /* used to wait for a packet */ - lock_t data_lock; /* synchronize access to input queues and + spinlock_t data_lock; /* synchronize access to input queues and * other fields of the brl1_sch_s struct */ brl1_notif_t tx_notify; /* notify higher layer that transmission may * continue */ @@ -118,9 +118,7 @@ brl1_uartf_t putc_f; /* pointer to UART putc function */ brl1_uartf_t getc_f; /* pointer to UART getc function */ - lock_t send_lock; /* arbitrates send synchronization */ - lock_t recv_lock; /* arbitrates uart receive access */ - lock_t subch_lock; /* arbitrates subchannel allocation */ + spinlock_t subch_lock; /* arbitrates subchannel allocation */ cpuid_t intr_cpu; /* cpu that receives L1 interrupts */ u_char send_in_use; /* non-zero if send buffer contains an @@ -223,6 +221,7 @@ #define L1_RESP_REQC (-101) /* bad request code */ #define L1_RESP_NAVAIL (-104) /* requested data not available */ #define L1_RESP_ARGVAL (-105) /* arg value out of range */ +#define L1_RESP_INVAL (-107) /* requested data invalid */ /* L1 general requests */ @@ -239,16 +238,19 @@ #define L1_REQ_PORTSPEED 0x000a /* get ioport speed */ #define L1_REQ_CONS_SUBCH 0x1002 /* select this node's console - * subchannel */ + subchannel */ #define L1_REQ_CONS_NODE 0x1003 /* volunteer to be the master - * (console-hosting) node */ + (console-hosting) node */ #define L1_REQ_DISP1 0x1004 /* write line 1 of L1 display */ #define L1_REQ_DISP2 0x1005 /* write line 2 of L1 display */ #define L1_REQ_PARTITION_SET 0x1006 /* set partition id */ #define L1_REQ_EVENT_SUBCH 0x1007 /* set the subchannel for system controller event transmission */ -#define L1_REQ_RESET 0x2001 /* request a full system reset */ +#define L1_REQ_RESET 0x2000 /* request a full system reset */ +#define L1_REQ_PCI_UP 0x2001 /* power up pci slot or bus */ +#define L1_REQ_PCI_DOWN 0x2002 /* power down pci slot or bus */ +#define L1_REQ_PCI_RESET 0x2003 /* reset pci bus or slot */ /* L1 command interpreter requests */ @@ -325,18 +327,6 @@ void sc_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ); void sc_intr_enable( l1sc_t *sc ); -#if 0 -int sc_portspeed_get( l1sc_t *sc ); -#endif - -int l1_cons_poll( l1sc_t *sc ); -int l1_cons_getc( l1sc_t *sc ); -void l1_cons_init( l1sc_t *sc ); -int l1_cons_read( l1sc_t *sc, char *buf, int avail ); -int l1_cons_write( l1sc_t *sc, char *msg, int len, int wait ); -void l1_cons_tx_notif( l1sc_t *sc, brl1_notif_t func ); -void l1_cons_rx_notif( l1sc_t *sc, brl1_notif_t func ); - int _elscuart_putc( l1sc_t *sc, int c ); int _elscuart_getc( l1sc_t *sc ); int _elscuart_poll( l1sc_t *sc ); @@ -354,11 +344,7 @@ int elsc_display_line(l1sc_t *e, char *line, int lnum); extern l1sc_t *get_elsc( void ); -extern void set_elsc( l1sc_t *e ); - #define get_l1sc get_elsc -#define set_l1sc(e) set_elsc(e) - #define get_master_l1sc get_l1sc int router_module_get( nasid_t nasid, net_vec_t path ); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/mmzone.h linux.ac/include/asm-ia64/sn/mmzone.h --- linux.vanilla/include/asm-ia64/sn/mmzone.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/mmzone.h Tue Apr 10 18:22:37 2001 @@ -6,6 +6,7 @@ #define _LINUX_ASM_SN_MMZONE_H #include <linux/config.h> + #include <asm/sn/mmzone_sn1.h> #include <asm/sn/sn_cpuid.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/mmzone_sn1.h linux.ac/include/asm-ia64/sn/mmzone_sn1.h --- linux.vanilla/include/asm-ia64/sn/mmzone_sn1.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/mmzone_sn1.h Tue Apr 10 18:22:37 2001 @@ -1,12 +1,11 @@ #ifndef _ASM_IA64_MMZONE_SN1_H #define _ASM_IA64_MMZONE_SN1_H +#include <linux/config.h> + /* * Copyright, 2000, Silicon Graphics, sprasad@engr.sgi.com */ - -#include <linux/config.h> - /* Maximum configuration supported by SNIA hardware. There are other * restrictions that may limit us to a smaller max configuration. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/module.h linux.ac/include/asm-ia64/sn/module.h --- linux.vanilla/include/asm-ia64/sn/module.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/module.h Tue Apr 10 18:22:37 2001 @@ -15,6 +15,7 @@ #endif #include <linux/config.h> + #include <asm/sn/systeminfo.h> #include <asm/sn/klconfig.h> #include <asm/sn/ksys/elsc.h> @@ -178,22 +179,24 @@ int disable_alert; int count_down; + + /* System serial number info (used by SN1) */ + char sys_snum[MAX_SERIAL_NUM_SIZE]; + int sys_snum_valid; }; /* module.c */ extern module_t *modules[MODULE_MAX]; /* Indexed by cmoduleid_t */ extern int nummodules; -#ifndef CONFIG_IA64_SGI_IO -/* Clashes with LINUX stuff */ -extern void module_init(void); -#endif extern module_t *module_lookup(moduleid_t id); extern elsc_t *get_elsc(void); extern int get_kmod_info(cmoduleid_t cmod, module_info_t *mod_info); +extern int get_kmod_sys_snum(cmoduleid_t cmod, + char *snum); extern void format_module_id(char *buffer, moduleid_t m, int fmt); extern int parse_module_id(char *buffer); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/nodemask.h linux.ac/include/asm-ia64/sn/nodemask.h --- linux.vanilla/include/asm-ia64/sn/nodemask.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/nodemask.h Tue Apr 10 18:22:37 2001 @@ -13,6 +13,7 @@ #if defined(__KERNEL__) || defined(_KMEMUSER) #include <linux/config.h> + #if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC #include <asm/sn/sn1/arch.h> /* needed for MAX_COMPACT_NODES */ #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/nodepda.h linux.ac/include/asm-ia64/sn/nodepda.h --- linux.vanilla/include/asm-ia64/sn/nodepda.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/nodepda.h Tue Apr 10 18:22:37 2001 @@ -15,11 +15,13 @@ #endif #include <linux/config.h> + #include <asm/sn/agent.h> #include <asm/sn/intr.h> #include <asm/sn/router.h> +#include <asm/sn/synergy.h> /* #include <SN/klkernvars.h> */ -#ifdef IRIX +#ifdef LATER typedef struct module_s module_t; /* Avoids sys/SN/module.h */ #else #include <asm/sn/module.h> @@ -54,6 +56,10 @@ struct ptpool_s; +#if defined(CONFIG_IA64_SGI_SYNERGY_PERF) +struct synergy_perf_s; +#endif + /* * Node-specific data structure. @@ -67,7 +73,8 @@ */ -#ifndef CONFIG_IA64_SGI_IO + +#ifdef LATER /* * The following structure is contained in the nodepda & contains * a lock & queue-head for sanon pages that belong to the node. @@ -78,9 +85,6 @@ plist_t sal_listhead; } sanon_list_head_t; #endif - - - struct nodepda_s { #ifdef NUMA_BASE @@ -133,7 +137,7 @@ * Each node gets its own syswait counter to remove contention * on the global one. */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER struct syswait syswait; #endif @@ -141,7 +145,7 @@ /* * Node-specific Zone structures. */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER zoneset_element_t node_zones; pg_data_t node_pg_data; /* VM page data structures */ plist_t error_discard_plist; @@ -154,7 +158,7 @@ /* Information needed for SN Hub chip interrupt handling. */ subnode_pda_t snpda[NUM_SUBNODES]; /* Distributed kernel support */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER kern_vars_t kern_vars; #endif /* Vector operation support */ @@ -173,6 +177,17 @@ nodepda_router_info_t *npda_rip_first; nodepda_router_info_t **npda_rip_last; int dependent_routers; + +#if defined(CONFIG_IA64_SGI_SYNERGY_PERF) + int synergy_perf_enabled; + int synergy_perf_freq; + spinlock_t synergy_perf_lock; + uint64_t synergy_inactive_intervals; + uint64_t synergy_active_intervals; + struct synergy_perf_s *synergy_perf_data; + struct synergy_perf_s *synergy_perf_first; /* reporting consistency .. */ +#endif /* CONFIG_IA64_SGI_SYNERGY_PERF */ + devfs_handle_t xbow_vhdl; nasid_t xbow_peer; /* NASID of our peer hub on xbow */ struct semaphore xbow_sema; /* Sema for xbow synchronization */ @@ -189,13 +204,13 @@ char ni_error_print; /* For printing ni error state * only once during system panic */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER md_perf_monitor_t node_md_perfmon; hubstat_t hubstats; int hubticks; - int huberror_ticks; sbe_info_t *sbe_info; /* ECC single-bit error statistics */ -#endif /* !CONFIG_IA64_SGI_IO */ +#endif /* LATER */ + int huberror_ticks; router_queue_t *visited_router_q; router_queue_t *bfs_router_q; @@ -218,11 +233,9 @@ void *pdinfo; /* Platform-dependent per-node info */ uint64_t *dump_stack; /* Dump stack during nmi handling */ int dump_count; /* To allow only one cpu-per-node */ -#if defined BRINGUP -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER io_perf_monitor_t node_io_perfmon; #endif -#endif /* * Each node gets its own pdcount counter to remove contention @@ -235,7 +248,7 @@ void *cached_global_pool; /* pointer to cached vmpool */ #endif /* NUMA_BASE */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER sanon_list_head_t sanon_list_head; /* head for sanon pages */ #endif #ifdef NUMA_BASE @@ -246,7 +259,7 @@ * The BTEs on this node are shared by the local cpus */ #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER bteinfo_t *node_bte_info[BTES_PER_NODE]; #endif #endif @@ -273,7 +286,7 @@ * SUBNODEPDA(x,s) -> to access subnode PDA for cnodeid/slice 'x' */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER #define nodepda private.p_nodepda /* Ptr to this node's PDA */ #if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC #define subnodepda private.p_subnodepda /* Ptr to this node's subnode PDA */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/pci/pci_bus_cvlink.h linux.ac/include/asm-ia64/sn/pci/pci_bus_cvlink.h --- linux.vanilla/include/asm-ia64/sn/pci/pci_bus_cvlink.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/pci/pci_bus_cvlink.h Tue Apr 10 18:22:37 2001 @@ -26,4 +26,23 @@ int isa64; }; +struct sn1_dma_maps_s{ + struct pcibr_dmamap_s dma_map; + dma_addr_t dma_addr; +}; + +struct ioports_to_tlbs_s { + unsigned long p:1, + rv_1:1, + ma:3, + a:1, + d:1, + pl:2, + ar:3, + ppn:38, + rv_2:2, + ed:1, + ig:11; +}; + #endif /* _ASM_SN_PCI_CVLINK_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/pci/pciba.h linux.ac/include/asm-ia64/sn/pci/pciba.h --- linux.vanilla/include/asm-ia64/sn/pci/pciba.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-ia64/sn/pci/pciba.h Tue Apr 10 18:22:37 2001 @@ -0,0 +1,103 @@ +/* $Id$ + * + * 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) 1992 - 1997, 2000 Silicon Graphics, Inc. + * Copyright (C) 2000 by Colin Ngam + */ +#ifndef _ASM_SN_PCI_PCIBA_H +#define _ASM_SN_PCI_PCIBA_H + +/* + * These are all the HACKS from ioccom.h .. + */ +#define IOCPARM_MASK 0xff /* parameters must be < 256 bytes */ +#define IOC_VOID 0x20000000 /* no parameters */ + +/* + * The above needs to be modified and follow LINUX ... + */ + +/* /hw/.../pci/[slot]/config accepts ioctls to read + * and write specific registers as follows: + * + * "t" is the native type (char, short, uint32, uint64) + * to read from CFG space; results will be arranged in + * byte significance (ie. first byte from PCI is lowest + * or last byte in result). + * + * "r" is the byte offset in PCI CFG space of the first + * byte of the register (it's least significant byte, + * in the little-endian PCI numbering). This can actually + * be as much as 16 bits wide, and is intended to match + * the layout of a "Type 1 Configuration Space" address: + * the register number in the low eight bits, then three + * bits for the function number and five bits for the + * slot number. + */ +#define PCIIOCCFGRD(t,r) _IOR(0,(r),t) +#define PCIIOCCFGWR(t,r) _IOW(0,(r),t) + +/* Some common config register access commands. + * Use these as examples of how to construct + * values for other registers you want to access. + */ + +/* PCIIOCGETID: arg is ptr to 32-bit int, + * returns the 32-bit ID value with VENDOR + * in the bottom 16 bits and DEVICE in the top. + */ +#define PCIIOCGETID PCIIOCCFGRD(uint32_t,PCI_CFG_VENDOR_ID) + +/* PCIIOCSETCMD: arg is ptr to a 16-bit short, + * which will be written to the CMD register. + */ +#define PCIIOCSETCMD PCIIOCCFGWR(uint16_t,PCI_CFG_COMMAND) + +/* PCIIOCGETREV: arg is ptr to an 8-bit char, + * which will get the 8-bit revision number. + */ +#define PCIIOCGETREV PCIIOCCFGRD(uint8_t,PCI_CFG_REV_ID) + +/* PCIIOCGETHTYPE: arg is ptr to an 8-bit char, + * which will get the 8-bit header type. + */ +#define PCIIOCGETHTYPE PCIIOCCFGRD(uint8_t,PCI_CFG_HEADER_TYPE) + +/* PCIIOCGETBASE(n): arg is ptr to a 32-bit int, + * which will get the value of the BASE<n> register. + */ +#define PCIIOCGETBASE(n) PCIIOCCFGRD(uint32_t,PCI_CFG_BASE_ADDR(n)) + +/* /hw/.../pci/[slot]/intr accepts an ioctl to + * set up user level interrupt handling as follows: + * + * "n" is a bitmap of which of the four PCI interrupt + * lines are of interest, using PCIIO_INTR_LINE_[ABCD]. + */ +#define PCIIOCSETULI(n) _IOWR(1,n,struct uliargs) +#if _KERNEL +#define PCIIOCSETULI32(n) _IOWR(1,n,struct uliargs32) +#endif + +/* /hw/.../pci/[slot]/dma accepts ioctls to allocate + * and free physical memory for use in user-triggered + * DMA operations. + */ +#define PCIIOCDMAALLOC _IOWR(0,1,uint64_t) +#define PCIIOCDMAFREE _IOW(0,1,uint64_t) + +/* The parameter for PCIIOCDMAALLOC needs to contain + * both the size of the request and the flag values + * to be used in setting up the DMA. + * + * Any flags normally useful in pciio_dmamap + * or pciio_dmatrans function calls can6 be used here. + */ +#define PCIIOCDMAALLOC_REQUEST_PACK(flags,size) \ + ((((uint64_t)(flags))<<32)| \ + (((uint64_t)(size))&0xFFFFFFFF)) + +#endif /* _ASM_SN_PCI_PCIBA_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/pci/pcibr.h linux.ac/include/asm-ia64/sn/pci/pcibr.h --- linux.vanilla/include/asm-ia64/sn/pci/pcibr.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/pci/pcibr.h Tue Apr 10 18:22:37 2001 @@ -143,6 +143,14 @@ extern void pcibr_dmamap_done(pcibr_dmamap_t dmamap); +/* + * pcibr_get_dmatrans_node() will return the compact node id to which + * all 32-bit Direct Mapping memory accesses will be directed. + * (This node id can be different for each PCI bus.) + */ + +extern cnodeid_t pcibr_get_dmatrans_node(devfs_handle_t pconn_vhdl); + extern iopaddr_t pcibr_dmatrans_addr(devfs_handle_t dev, device_desc_t dev_desc, paddr_t paddr, @@ -215,10 +223,6 @@ pciio_space_t *spacep, iopaddr_t *addrp); -extern int pcibr_rrb_alloc(devfs_handle_t pconn_vhdl, - int *count_vchan0, - int *count_vchan1); - extern int pcibr_wrb_flush(devfs_handle_t pconn_vhdl); extern int pcibr_rrb_check(devfs_handle_t pconn_vhdl, int *count_vchan0, @@ -241,7 +245,7 @@ void pcibr_set_rrb_callback(devfs_handle_t xconn_vhdl, rrb_alloc_funct_f *func); -extern void pcibr_device_unregister(devfs_handle_t); +extern int pcibr_device_unregister(devfs_handle_t); extern int pcibr_dma_enabled(devfs_handle_t); /* * Bridge-specific flags that can be set via pcibr_device_flags_set @@ -337,7 +341,7 @@ extern void pcibr_hints_fix_rrbs(devfs_handle_t); extern void pcibr_hints_dualslot(devfs_handle_t, pciio_slot_t, pciio_slot_t); -extern void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, uint64_t); +extern void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, ulong); extern void pcibr_hints_handsoff(devfs_handle_t); typedef unsigned pcibr_intr_bits_f(pciio_info_t, pciio_intr_line_t); @@ -353,8 +357,104 @@ #define PCIBR 'p' #define _PCIBR(x) ((PCIBR << 8) | (x)) -#define PCIBR_SLOT_POWERUP _PCIBR(1) -#define PCIBR_SLOT_SHUTDOWN _PCIBR(2) -#define PCIBR_SLOT_INQUIRY _PCIBR(3) +#define PCIBR_SLOT_STARTUP _PCIBR(1) +#define PCIBR_SLOT_SHUTDOWN _PCIBR(2) +#define PCIBR_SLOT_QUERY _PCIBR(3) + +/* + * Bit defintions for variable slot_status in struct + * pcibr_soft_slot_s. They are here so that both + * the pcibr driver and the pciconfig command can + * reference them. + */ +#define SLOT_STARTUP_CMPLT 0x01 +#define SLOT_STARTUP_INCMPLT 0x02 +#define SLOT_SHUTDOWN_CMPLT 0x04 +#define SLOT_SHUTDOWN_INCMPLT 0x08 +#define SLOT_POWER_UP 0x10 +#define SLOT_POWER_DOWN 0x20 +#define SLOT_IS_SYS_CRITICAL 0x40 + +#define SLOT_STATUS_MASK (SLOT_STARTUP_CMPLT | SLOT_STARTUP_INCMPLT | \ + SLOT_SHUTDOWN_CMPLT | SLOT_SHUTDOWN_INCMPLT) +#define SLOT_POWER_MASK (SLOT_POWER_UP | SLOT_POWER_DOWN) + +/* + * Bit definitions for variable resp_f_staus. + * They are here so that both the pcibr driver + * and the pciconfig command can reference them. + */ +#define FUNC_IS_VALID 0x01 +#define FUNC_IS_SYS_CRITICAL 0x02 + +/* + * Structures for requesting PCI bridge information and receiving a response + */ +typedef struct pcibr_slot_info_req_s *pcibr_slot_info_req_t; +typedef struct pcibr_slot_info_resp_s *pcibr_slot_info_resp_t; +typedef struct pcibr_slot_func_info_resp_s *pcibr_slot_func_info_resp_t; + +struct pcibr_slot_info_req_s { + int req_slot; + pcibr_slot_info_resp_t req_respp; + int req_size; +}; + +struct pcibr_slot_info_resp_s { + int resp_has_host; + char resp_host_slot; + devfs_handle_t resp_slot_conn; + char resp_slot_conn_name[MAXDEVNAME]; + int resp_slot_status; + int resp_l1_bus_num; + int resp_bss_ninfo; + char resp_bss_devio_bssd_space[16]; + iopaddr_t resp_bss_devio_bssd_base; + bridgereg_t resp_bss_device; + int resp_bss_pmu_uctr; + int resp_bss_d32_uctr; + int resp_bss_d64_uctr; + iopaddr_t resp_bss_d64_base; + unsigned resp_bss_d64_flags; + iopaddr_t resp_bss_d32_base; + unsigned resp_bss_d32_flags; + int resp_bss_ext_ates_active; + volatile unsigned *resp_bss_cmd_pointer; + unsigned resp_bss_cmd_shadow; + int resp_bs_rrb_valid; + int resp_bs_rrb_valid_v; + int resp_bs_rrb_res; + bridgereg_t resp_b_resp; + bridgereg_t resp_b_int_device; + bridgereg_t resp_b_int_enable; + bridgereg_t resp_b_int_host; + + struct pcibr_slot_func_info_resp_s { + int resp_f_status; + char resp_f_slot_name[MAXDEVNAME]; + char resp_f_bus; + char resp_f_slot; + char resp_f_func; + char resp_f_master_name[MAXDEVNAME]; + void *resp_f_pops; + error_handler_f *resp_f_efunc; + error_handler_arg_t resp_f_einfo; + int resp_f_vendor; + int resp_f_device; + + struct { + char resp_w_space[16]; + iopaddr_t resp_w_base; + size_t resp_w_size; + } resp_f_window[6]; + + unsigned resp_f_rbase; + unsigned resp_f_rsize; + int resp_f_ibit[4]; + int resp_f_att_det_error; + + } resp_func[8]; + +}; #endif /* _ASM_SN_PCI_PCIBR_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/pci/pcibr_private.h linux.ac/include/asm-ia64/sn/pci/pcibr_private.h --- linux.vanilla/include/asm-ia64/sn/pci/pcibr_private.h Tue Apr 3 17:32:27 2001 +++ linux.ac/include/asm-ia64/sn/pci/pcibr_private.h Tue Apr 10 18:22:37 2001 @@ -17,6 +17,7 @@ */ #include <asm/sn/pci/pciio_private.h> +#include <asm/sn/ksys/l1.h> /* * convenience typedefs @@ -31,6 +32,7 @@ typedef struct pcibr_hints_s *pcibr_hints_t; typedef struct pcibr_intr_list_s *pcibr_intr_list_t; typedef struct pcibr_intr_wrap_s *pcibr_intr_wrap_t; +typedef struct pcibr_intr_cbuf_s *pcibr_intr_cbuf_t; /* * Bridge sets up PIO using this information. @@ -50,7 +52,7 @@ xtalk_piomap_t bp_xtalk_pio; /* corresponding xtalk resource */ pcibr_piomap_t bp_next; /* Next piomap on the list */ pcibr_soft_t bp_soft; /* backpointer to bridge soft data */ - int bp_toc[1]; /* PCI timeout counter */ + atomic_t bp_toc[1]; /* PCI timeout counter */ }; @@ -77,6 +79,18 @@ bridge_ate_t bd_ate_prime; /* value of 1st ATE written */ }; +#define IBUFSIZE 5 /* size of circular buffer (holds 4) */ + +/* + * Circular buffer used for interrupt processing + */ +struct pcibr_intr_cbuf_s { + spinlock_t ib_lock; /* cbuf 'put' lock */ + int ib_in; /* index of next free entry */ + int ib_out; /* index of next full entry */ + pcibr_intr_wrap_t ib_cbuf[IBUFSIZE]; /* circular buffer of wrap */ +}; + /* * Bridge sets up interrupts using this information. */ @@ -94,6 +108,7 @@ #define bi_cpu bi_pi.pi_cpu /* cpu assigned. */ unsigned bi_ibits; /* which Bridge interrupt bit(s) */ pcibr_soft_t bi_soft; /* shortcut to soft info */ + struct pcibr_intr_cbuf_s bi_ibuf; /* circular buffer of wrap ptrs */ }; /* @@ -121,6 +136,7 @@ /* pcibr-specific connection state */ int f_ibit[4]; /* Bridge bit for each INTx */ pcibr_piomap_t f_piomap; + int f_att_det_error; }; /* ===================================================================== @@ -139,8 +155,11 @@ struct pcibr_intr_wrap_s { pcibr_soft_t iw_soft; /* which bridge */ volatile bridgereg_t *iw_stat; /* ptr to b_int_status */ - bridgereg_t iw_intr; /* bits in b_int_status */ + bridgereg_t iw_intr; /* bit in b_int_status */ pcibr_intr_list_t iw_list; /* ghostbusters! */ + int iw_hdlrcnt; /* running handler count */ + int iw_shared; /* if Bridge bit is shared */ + int iw_connected; /* if already connected */ }; #define PCIBR_ISR_ERR_START 8 @@ -175,11 +194,14 @@ unsigned bs_dma_flags; /* revision-implied DMA flags */ + l1sc_t *bs_l1sc; /* io brick l1 system cntr */ + moduleid_t bs_moduleid; /* io brick moduleid */ + /* * Lock used primarily to get mutual exclusion while managing any * bridge resources.. */ - lock_t bs_lock; + spinlock_t bs_lock; devfs_handle_t bs_noslot_conn; /* NO-SLOT connection point */ pcibr_info_t bs_noslot_info; @@ -199,6 +221,9 @@ int has_host; pciio_slot_t host_slot; devfs_handle_t slot_conn; + + int slot_status; + /* Potentially several connection points * for this slot. bss_ninfo is how many, * and bss_infos is a pointer to @@ -265,7 +290,7 @@ /* Shadow information used for implementing * Bridge Hardware WAR #484930 */ - int bss_ext_ates_active; + atomic_t bss_ext_ates_active; volatile unsigned *bss_cmd_pointer; unsigned bss_cmd_shadow; @@ -295,13 +320,10 @@ */ xtalk_intr_t bsi_xtalk_intr; /* - * We do not like sharing PCI interrrupt lines - * between devices, but the Origin 200 PCI - * layout forces us to do so. + * A wrapper structure is associated with each + * Bridge interrupt bit. */ - pcibr_intr_list_t bsi_pcibr_intr_list; - pcibr_intr_wrap_t bsi_pcibr_intr_wrap; - int bsi_pcibr_wrap_set; + struct pcibr_intr_wrap_s bsi_pcibr_intr_wrap; } bs_intr[8]; @@ -325,7 +347,7 @@ */ struct br_errintr_info { int bserr_toutcnt; -#ifdef IRIX +#ifdef LATER toid_t bserr_toutid; /* Timeout started by errintr */ #endif iopaddr_t bserr_addr; /* Address where error occurred */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/pci/pciio.h linux.ac/include/asm-ia64/sn/pci/pciio.h --- linux.vanilla/include/asm-ia64/sn/pci/pciio.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/pci/pciio.h Tue Apr 10 18:22:37 2001 @@ -35,15 +35,9 @@ #define PCIIO_DEVICE_ID_NONE -1 -#ifdef colin -typedef char pciio_bus_t; /* PCI bus number (0..255) */ -typedef char pciio_slot_t; /* PCI slot number (0..31, 255) */ -typedef char pciio_function_t; /* PCI func number (0..7, 255) */ -#else typedef uint8_t pciio_bus_t; /* PCI bus number (0..255) */ typedef uint8_t pciio_slot_t; /* PCI slot number (0..31, 255) */ typedef uint8_t pciio_function_t; /* PCI func number (0..7, 255) */ -#endif #define PCIIO_SLOTS ((pciio_slot_t)32) #define PCIIO_FUNCS ((pciio_function_t)8) @@ -446,6 +440,24 @@ pciio_space_t *spacep, iopaddr_t *addrp); +typedef void +pciio_driver_reg_callback_f (devfs_handle_t conn, + int key1, + int key2, + int error); + +typedef void +pciio_driver_unreg_callback_f (devfs_handle_t conn, /* pci connection point */ + int key1, + int key2, + int error); + +typedef int +pciio_device_unregister_f (devfs_handle_t conn); + +typedef int +pciio_dma_enabled_f (devfs_handle_t conn); + /* * Adapters that provide a PCI interface adhere to this software interface. */ @@ -491,6 +503,12 @@ /* Error handling interface */ pciio_error_devenable_f *error_devenable; pciio_error_extract_f *error_extract; + + /* Callback support */ + pciio_driver_reg_callback_f *driver_reg_callback; + pciio_driver_unreg_callback_f *driver_unreg_callback; + pciio_device_unregister_f *device_unregister; + pciio_dma_enabled_f *dma_enabled; } pciio_provider_t; /* PCI devices use these standard PCI provider interfaces */ @@ -540,13 +558,8 @@ #define PCIIO_WIDGETDEV_SLOT_MASK 0x1f #define PCIIO_WIDGETDEV_FUNC_MASK 0x7 -#ifdef IRIX -#define pciio_widgetdev_create(slot,func) \ - ((slot) << PCIIO_WIDGETDEV_SLOT_SHFT + (func)) -#else #define pciio_widgetdev_create(slot,func) \ (((slot) << PCIIO_WIDGETDEV_SLOT_SHFT) + (func)) -#endif #define pciio_widgetdev_slot_get(wdev) \ (((wdev) >> PCIIO_WIDGETDEV_SLOT_SHFT) & PCIIO_WIDGETDEV_SLOT_MASK) @@ -612,8 +625,14 @@ pciio_info_t pciio_info); /* details about conn point */ -extern int pciio_device_attach(devfs_handle_t pcicard); /* vertex created by pciio_device_register */ -extern int pciio_device_detach(devfs_handle_t pcicard); /* vertex created by pciio_device_register */ +extern int +pciio_device_attach( + devfs_handle_t pcicard, /* vertex created by pciio_device_register */ + int drv_flags); +extern int +pciio_device_detach( + devfs_handle_t pcicard, /* vertex created by pciio_device_register */ + int drv_flags); /* * Generic PCI interface, for use with all PCI providers @@ -632,7 +651,7 @@ extern ulong pciio_pio_mapsz_get(pciio_piomap_t pciio_piomap); extern caddr_t pciio_pio_kvaddr_get(pciio_piomap_t pciio_piomap); -#ifdef IRIX +#ifdef LATER #ifdef USE_PCI_PIO extern uint8_t pciio_pio_read8(volatile uint8_t *addr); extern uint16_t pciio_pio_read16(volatile uint16_t *addr); @@ -676,7 +695,7 @@ *addr = val; } #endif /* USE_PCI_PIO */ -#endif +#endif /* LATER */ /* Generic PCI dma interfaces */ extern devfs_handle_t pciio_dma_dev_get(pciio_dmamap_t pciio_dmamap); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/pci/pciio_private.h linux.ac/include/asm-ia64/sn/pci/pciio_private.h --- linux.vanilla/include/asm-ia64/sn/pci/pciio_private.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/pci/pciio_private.h Tue Apr 10 18:22:37 2001 @@ -10,10 +10,6 @@ #ifndef _ASM_SN_PCI_PCIIO_PRIVATE_H #define _ASM_SN_PCI_PCIIO_PRIVATE_H -#ifdef colin -#include <ksys/xthread.h> -#endif - /* * pciio_private.h -- private definitions for pciio * PCI drivers should NOT include this file. @@ -54,12 +50,12 @@ pciio_intr_line_t pi_lines; /* which interrupt line(s) */ intr_func_t pi_func; /* handler function (when connected) */ intr_arg_t pi_arg; /* handler parameter (when connected) */ -#ifdef IRIX +#ifdef LATER thd_int_t pi_tinfo; /* Thread info (when connected) */ #endif cpuid_t pi_mustruncpu; /* Where we must run. */ - int pi_irq; /* IRQ assigned */ - int pi_cpu; /* cpu assigned */ + int pi_irq; /* IRQ assigned */ + int pi_cpu; /* cpu assigned */ }; /* PCIIO_INTR (pi_flags) flags */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/pio.h linux.ac/include/asm-ia64/sn/pio.h --- linux.vanilla/include/asm-ia64/sn/pio.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/pio.h Tue Apr 10 18:22:37 2001 @@ -33,7 +33,7 @@ typedef struct piomap { uint pio_bus; uint pio_adap; -#ifdef IRIX +#ifdef LATER iospace_t pio_iospace; #endif int pio_flag; @@ -41,7 +41,7 @@ char pio_name[7]; /* to identify the mapped device */ struct piomap *pio_next; /* dlist to link active piomap's */ struct piomap *pio_prev; /* for debug and error reporting */ -#ifdef IRIX +#ifdef LATER void (*pio_errfunc)(); /* Pointer to an error function */ /* Used only for piomaps allocated * in user level vme driver */ @@ -50,6 +50,10 @@ iobush_t pio_bushandle; /* bus-level handle */ } piomap_t; +#define pio_type pio_iospace.ios_type +#define pio_iopaddr pio_iospace.ios_iopaddr +#define pio_size pio_iospace.ios_size +#define pio_vaddr pio_iospace.ios_vaddr /* Macro to get/set PIO error function */ #define pio_seterrf(p,f) (p)->pio_errfunc = (f) @@ -64,7 +68,7 @@ * pio_mapfree() - frees the mapping as specified in the piomap handle. * pio_mapaddr() - returns the kv address that maps to piomap'ed io address. */ -#ifdef IRIX +#ifdef LATER extern piomap_t *pio_mapalloc(uint,uint,iospace_t*,int,char*); extern void pio_mapfree(piomap_t*); extern caddr_t pio_mapaddr(piomap_t*,iopaddr_t); @@ -101,7 +105,7 @@ extern void andb_rmw(volatile void*, unsigned int); extern void andh_rmw(volatile void*, unsigned int); extern void andw_rmw(volatile void*, unsigned int); -#endif /* IRIX */ +#endif /* LATER */ /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/router.h linux.ac/include/asm-ia64/sn/router.h --- linux.vanilla/include/asm-ia64/sn/router.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/router.h Tue Apr 10 18:22:37 2001 @@ -11,6 +11,7 @@ #define _ASM_SN_ROUTER_H #include <linux/config.h> + #if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC #include <asm/sn/sn1/router.h> #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/sgi.h linux.ac/include/asm-ia64/sn/sgi.h --- linux.vanilla/include/asm-ia64/sn/sgi.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/sgi.h Tue Apr 10 18:22:37 2001 @@ -13,6 +13,7 @@ #define _ASM_SN_SGI_H #include <linux/config.h> + #include <asm/sn/types.h> #include <asm/uaccess.h> /* for copy_??_user */ #include <linux/mm.h> @@ -121,18 +122,6 @@ GRAPH_IN_USE /* 7 */ } graph_error_t; -#define SV_FIFO 0x0 /* sv_t is FIFO type */ -#define SV_LIFO 0x2 /* sv_t is LIFO type */ -#define SV_PRIO 0x4 /* sv_t is PRIO type */ -#define SV_KEYED 0x6 /* sv_t is KEYED type */ -#define SV_DEFAULT SV_FIFO - - -#define MUTEX_DEFAULT 0x0 /* needed by mutex_init() calls */ -#define PZERO 25 /* needed by mutex_lock(), sv_wait() - * psema() calls */ - -#define sema_t uint64_t /* FIXME */ #define KM_SLEEP 0x0000 #define KM_NOSLEEP 0x0001 /* needed by kmem_alloc_node(), kmem_zalloc() * calls */ @@ -140,10 +129,6 @@ * calls */ #define XG_WIDGET_PART_NUM 0xC102 /* KONA/xt_regs.h XG_XT_PART_NUM_VALUE */ -#ifndef K1BASE -#define K1BASE 0xA0000000 -#endif - #ifndef TO_PHYS_MASK #define TO_PHYS_MASK 0x0000000fffffffff #endif @@ -171,8 +156,6 @@ #define _PAGESZ 4096 #endif -typedef uint64_t k_machreg_t; /* needed by cmn_err.h */ - typedef uint64_t mrlock_t; /* needed by devsupport.c */ #define HUB_PIO_CONVEYOR 0x1 @@ -188,44 +171,64 @@ #define POFFMASK (NBPP - 1) #define poff(X) ((__psunsigned_t)(X) & POFFMASK) -#define initnsema(a,b,c) sema_init(a,b) - #define BZERO(a,b) memset(a, 0, b) -#define kern_malloc(x) kmalloc(x, GFP_KERNEL) -#define kern_free(x) kfree(x) +#define kern_malloc(x) kmalloc(x, GFP_KERNEL) +#define kern_free(x) kfree(x) typedef cpuid_t cpu_cookie_t; #define CPU_NONE -1 +/* + * mutext support mapping + */ + +#define mutex_spinlock_init(s) spin_lock_init(s) +inline static unsigned long +mutex_spinlock(spinlock_t *sem) { + unsigned long flags = 0; +// spin_lock_irqsave(sem, flags); + spin_lock(sem); + return(flags); +} +// #define mutex_spinunlock(s,t) spin_unlock_irqrestore(s,t) +#define mutex_spinunlock(s,t) spin_unlock(s) + + +#define mutex_t struct semaphore +#define mutex_init(s) init_MUTEX(s) +#define mutex_init_locked(s) init_MUTEX_LOCKED(s) +#define mutex_lock(s) down(s) +#define mutex_unlock(s) up(s) + +#define io_splock(s) mutex_spinlock(s) +#define io_spunlock(s,t) spin_unlock(s) + +#define spin_lock_destroy(s) #if defined(DISABLE_ASSERT) #define ASSERT(expr) #define ASSERT_ALWAYS(expr) #else -#define ASSERT(expr) \ +#define ASSERT(expr) do { \ if(!(expr)) { \ printk( "Assertion [%s] failed! %s:%s(line=%d)\n",\ #expr,__FILE__,__FUNCTION__,__LINE__); \ panic("Assertion panic\n"); \ - } + } } while(0) -#define ASSERT_ALWAYS(expr) \ +#define ASSERT_ALWAYS(expr) do {\ if(!(expr)) { \ printk( "Assertion [%s] failed! %s:%s(line=%d)\n",\ #expr,__FILE__,__FUNCTION__,__LINE__); \ panic("Assertion always panic\n"); \ - } + } } while(0) #endif /* DISABLE_ASSERT */ -/* These are defined as cmn_err() replacements */ -#define PRINT_WARNING(x...) { printk("WARNING : "); printk(x); } -#define PRINT_NOTICE(x...) { printk("NOTICE : "); printk(x); } -#define PRINT_ALERT(x...) { printk("ALERT : "); printk(x); } +#define PRINT_WARNING(x...) do { printk("WARNING : "); printk(x); } while(0) +#define PRINT_NOTICE(x...) do { printk("NOTICE : "); printk(x); } while(0) +#define PRINT_ALERT(x...) do { printk("ALERT : "); printk(x); } while(0) #define PRINT_PANIC panic - -#define mutex_t int -#define spinlock_init(x,name) mutex_init(x, MUTEX_DEFAULT, name); #ifdef CONFIG_SMP #define cpu_enabled(cpu) (test_bit(cpu, &cpu_online_map)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/slotnum.h linux.ac/include/asm-ia64/sn/slotnum.h --- linux.vanilla/include/asm-ia64/sn/slotnum.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/slotnum.h Tue Apr 10 18:22:37 2001 @@ -10,9 +10,10 @@ #ifndef _ASM_SN_SLOTNUM_H #define _ASM_SN_SLOTNUM_H +#include <linux/config.h> + typedef unsigned char slotid_t; -#include <linux/config.h> #if defined (CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) #include <asm/sn/sn1/slotnum.h> #else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/sn1/addrs.h linux.ac/include/asm-ia64/sn/sn1/addrs.h --- linux.vanilla/include/asm-ia64/sn/sn1/addrs.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/sn1/addrs.h Tue Apr 10 18:22:37 2001 @@ -43,22 +43,19 @@ #if defined(_RUN_UNCACHED) #define CAC_BASE 0x9600000000000000 #else +#ifndef __ia64 #define CAC_BASE 0xa800000000000000 +#else +#define CAC_BASE 0xe000000000000000 +#endif #endif -#ifdef Colin -#define HSPEC_BASE 0x9000000000000000 -#define IO_BASE 0x9200000000000000 -#define MSPEC_BASE 0x9400000000000000 -#define UNCAC_BASE 0x9600000000000000 -#else #define HSPEC_BASE 0xc0000b0000000000 #define HSPEC_SWIZ_BASE 0xc000030000000000 #define IO_BASE 0xc0000a0000000000 #define IO_SWIZ_BASE 0xc000020000000000 #define MSPEC_BASE 0xc000000000000000 #define UNCAC_BASE 0xc000000000000000 -#endif #define TO_PHYS(x) ( ((x) & TO_PHYS_MASK)) #define TO_CAC(x) (CAC_BASE | ((x) & TO_PHYS_MASK)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/sn1/bedrock.h linux.ac/include/asm-ia64/sn/sn1/bedrock.h --- linux.vanilla/include/asm-ia64/sn/sn1/bedrock.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/sn1/bedrock.h Tue Apr 10 18:22:37 2001 @@ -11,6 +11,8 @@ #ifndef _ASM_SN_SN1_BEDROCK_H #define _ASM_SN_SN1_BEDROCK_H +#include <linux/config.h> + /* The secret password; used to release protection */ #define HUB_PASSWORD 0x53474972756c6573ull @@ -22,7 +24,6 @@ #define MAX_HUB_PATH 80 -#include <linux/config.h> #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) #include <asm/sn/arch.h> #include <asm/sn/sn1/addrs.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/sn1/hubio_next.h linux.ac/include/asm-ia64/sn/sn1/hubio_next.h --- linux.vanilla/include/asm-ia64/sn/sn1/hubio_next.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/sn1/hubio_next.h Tue Apr 10 18:22:37 2001 @@ -43,6 +43,8 @@ #define IIO_IOPRB_0 IIO_IPRB0 #define IIO_PRTE_0 IIO_IPRTE0 /* PIO Read address table entry 0 */ #define IIO_PRTE(_x) (IIO_PRTE_0 + (8 * (_x))) +#define IIO_NUM_IPRBS (9) +#define IIO_WIDPRTE(x) IIO_PRTE(((x) - 8)) /* widget ID to its PRTE num */ #define IIO_LLP_CSR_IS_UP 0x00002000 #define IIO_LLP_CSR_LLP_STAT_MASK 0x00003000 @@ -192,6 +194,21 @@ #define HUBII_XBOW_CREDIT 3 #define HUBII_XBOW_REV2_CREDIT 4 +/* + * Number of credits that xtalk devices should use when communicating + * with a Bedrock (depth of Bedrock's queue). + */ +#define HUB_CREDIT 4 + +/* + * Some IIO_PRB fields + */ +#define IIO_PRB_MULTI_ERR (1LL << 63) +#define IIO_PRB_SPUR_RD (1LL << 51) +#define IIO_PRB_SPUR_WR (1LL << 50) +#define IIO_PRB_RD_TO (1LL << 49) +#define IIO_PRB_ERROR (1LL << 48) + /************************************************************************* Some of the IIO field masks and shifts are defined here. @@ -245,6 +262,29 @@ #define IBCT_ZFIL_MODE (0x1 << 0) /* + * IIO Incoming Error Packet Header (IIO_IIEPH1/IIO_IIEPH2) + */ +#define IIEPH1_VALID (1 << 44) +#define IIEPH1_OVERRUN (1 << 40) +#define IIEPH1_ERR_TYPE_SHFT 32 +#define IIEPH1_ERR_TYPE_MASK 0xf +#define IIEPH1_SOURCE_SHFT 20 +#define IIEPH1_SOURCE_MASK 11 +#define IIEPH1_SUPPL_SHFT 8 +#define IIEPH1_SUPPL_MASK 11 +#define IIEPH1_CMD_SHFT 0 +#define IIEPH1_CMD_MASK 7 + +#define IIEPH2_TAIL (1 << 40) +#define IIEPH2_ADDRESS_SHFT 0 +#define IIEPH2_ADDRESS_MASK 38 + +#define IIEPH1_ERR_SHORT_REQ 2 +#define IIEPH1_ERR_SHORT_REPLY 3 +#define IIEPH1_ERR_LONG_REQ 4 +#define IIEPH1_ERR_LONG_REPLY 5 + +/* * IO Error Clear register bit field definitions */ #define IECLR_PI1_FWD_INT (1 << 31) /* clear PI1_FORWARD_INT in iidsr */ @@ -363,6 +403,10 @@ /* A few more #defines for backwards compatibility */ #define iprb_t ii_iprb0_u_t #define iprb_regval ii_iprb0_regval +#define iprb_mult_err ii_iprb0_fld_s.i_mult_err +#define iprb_spur_rd ii_iprb0_fld_s.i_spur_rd +#define iprb_spur_wr ii_iprb0_fld_s.i_spur_wr +#define iprb_rd_to ii_iprb0_fld_s.i_rd_to #define iprb_ovflow ii_iprb0_fld_s.i_of_cnt #define iprb_error ii_iprb0_fld_s.i_error #define iprb_ff ii_iprb0_fld_s.i_f @@ -385,7 +429,6 @@ #define IO_PERF_SETS 32 -#ifdef BRINGUP #if __KERNEL__ #if _LANGUAGE_C /* XXX moved over from SN/SN0/hubio.h -- each should be checked for SN1 */ @@ -646,6 +689,11 @@ device_desc_t dev_desc, /* device descriptor */ devfs_handle_t owner_dev); /* owner of this interrupt */ +extern hub_intr_t +hub_intr_alloc_nothd(devfs_handle_t dev, /* which device */ + device_desc_t dev_desc, /* device descriptor */ + devfs_handle_t owner_dev); /* owner of this interrupt */ + extern void hub_intr_free(hub_intr_t intr_hdl); @@ -710,5 +758,4 @@ #endif /* _LANGUAGE_C */ #endif /* _KERNEL */ -#endif /* BRINGUP */ #endif /* _ASM_SN_SN1_HUBIO_NEXT_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/sn1/hubpi_next.h linux.ac/include/asm-ia64/sn/sn1/hubpi_next.h --- linux.vanilla/include/asm-ia64/sn/sn1/hubpi_next.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/sn1/hubpi_next.h Tue Apr 10 18:22:37 2001 @@ -274,7 +274,9 @@ * The following three macros define all possible error int pends. */ -#define PI_FATAL_ERR_CPU_A (PI_ERR_SYSAD_BAD_DATA_A | \ +#define PI_FATAL_ERR_CPU_A (PI_ERR_IRB_TIMEOUT_A | \ + PI_ERR_IRB_ERR_A | \ + PI_ERR_PKT_LEN_ERR_A | \ PI_ERR_SYSSTATE_TAG_A | \ PI_ERR_BAD_SPOOL_A | \ PI_ERR_SYSCMD_ADDR_A | \ @@ -283,17 +285,17 @@ PI_ERR_SYSAD_DATA_A | \ PI_ERR_SYSSTATE_A) -#define PI_MISC_ERR_CPU_A (PI_ERR_IRB_TIMEOUT_A | \ - PI_ERR_IRB_ERR_A | \ - PI_ERR_PKT_LEN_ERR_A | \ - PI_ERR_UE_CACHED_A | \ +#define PI_MISC_ERR_CPU_A (PI_ERR_UE_CACHED_A | \ + PI_ERR_SYSAD_BAD_DATA_A| \ PI_ERR_UNCAC_UNCORR_A | \ PI_ERR_WRB_WERR_A | \ PI_ERR_WRB_TERR_A | \ PI_ERR_SPUR_MSG_A | \ PI_ERR_SPOOL_CMP_A) -#define PI_FATAL_ERR_CPU_B (PI_ERR_SYSAD_BAD_DATA_B | \ +#define PI_FATAL_ERR_CPU_B (PI_ERR_IRB_TIMEOUT_B | \ + PI_ERR_IRB_ERR_B | \ + PI_ERR_PKT_LEN_ERR_B | \ PI_ERR_SYSSTATE_TAG_B | \ PI_ERR_BAD_SPOOL_B | \ PI_ERR_SYSCMD_ADDR_B | \ @@ -302,11 +304,9 @@ PI_ERR_SYSAD_DATA_B | \ PI_ERR_SYSSTATE_B) -#define PI_MISC_ERR_CPU_B (PI_ERR_IRB_TIMEOUT_B | \ - PI_ERR_IRB_ERR_B | \ - PI_ERR_PKT_LEN_ERR_B | \ - PI_ERR_UE_CACHED_B | \ - PI_ERR_UNCAC_UNCORR_B | \ +#define PI_MISC_ERR_CPU_B (PI_ERR_UE_CACHED_B | \ + PI_ERR_SYSAD_BAD_DATA_B| \ + PI_ERR_UNCAC_UNCORR_B | \ PI_ERR_WRB_WERR_B | \ PI_ERR_WRB_TERR_B | \ PI_ERR_SPUR_MSG_B | \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/sn1/hubxb_next.h linux.ac/include/asm-ia64/sn/sn1/hubxb_next.h --- linux.vanilla/include/asm-ia64/sn/sn1/hubxb_next.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/sn1/hubxb_next.h Tue Apr 10 18:22:37 2001 @@ -28,5 +28,6 @@ /* XB_PARMS fields */ #define XBP_RESET_DEFAULTS 0x0008000080000021LL +#define XBP_ACTIVE_DEFAULTS 0x00080000fffff021LL #endif /* _ASM_SN_SN1_HUBXB_NEXT_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/sn1/ip27config.h linux.ac/include/asm-ia64/sn/sn1/ip27config.h --- linux.vanilla/include/asm-ia64/sn/sn1/ip27config.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/sn1/ip27config.h Tue Apr 10 18:22:37 2001 @@ -188,6 +188,10 @@ #define IP27C_R10000_SCCD_MASK (7 << IP27C_R10000_SCCD_SHFT) #define IP27C_R10000_SCCD(_B) ((_B) << IP27C_R10000_SCCD_SHFT) +#define IP27C_R10000_DDR_SHFT 23 +#define IP27C_R10000_DDR_MASK (1 << IP27C_R10000_DDR_SHFT) +#define IP27C_R10000_DDR(_B) ((_B) << IP27C_R10000_DDR_SHFT) + #define IP27C_R10000_SCCT_SHFT 25 #define IP27C_R10000_SCCT_MASK (0xf << IP27C_R10000_SCCT_SHFT) #define IP27C_R10000_SCCT(_B) ((_B) << IP27C_R10000_SCCT_SHFT) @@ -375,6 +379,7 @@ IP27C_R10000_SCCE(0) + \ IP27C_R10000_ME(1) + \ IP27C_R10000_SCS(4) + \ + IP27C_R10000_DDR(1) + \ IP27C_R10000_SCCD(3) + \ IP27C_R10000_SCCT(0xa) + \ IP27C_R10000_ODSC(0) + \ @@ -503,12 +508,7 @@ * for building hex images (as required by start.s) */ #ifdef IP27_CONFIG_SN00_4MB_100_200_133 -#ifdef IRIX -/* Set PrcReqMax to 0 to reduce memory problems */ -#define BRINGUP_PRM_VAL 0 -#else #define BRINGUP_PRM_VAL 3 -#endif #define CONFIG_CPU_MODE \ (IP27C_R10000_KSEG0CA(5) + \ IP27C_R10000_DEVNUM(0) + \ @@ -593,6 +593,7 @@ IP27C_R10000_ME(1) + \ IP27C_R10000_SCS(4) + \ IP27C_R10000_SCCD(3) + \ + IP27C_R10000_DDR(1) + \ IP27C_R10000_SCCT(0xa) + \ IP27C_R10000_ODSC(0) + \ IP27C_R10000_ODSYS(1) + \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/sn1/leds.h linux.ac/include/asm-ia64/sn/sn1/leds.h --- linux.vanilla/include/asm-ia64/sn/sn1/leds.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/sn1/leds.h Tue Apr 10 18:22:37 2001 @@ -25,7 +25,7 @@ long *ledp; int eid; - eid = hard_processor_sapicid() & 3; + eid = hard_smp_processor_id() & 3; ledp = (long*) (LED0 + (eid<<3)); *ledp = val; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/sn1/router.h linux.ac/include/asm-ia64/sn/sn1/router.h --- linux.vanilla/include/asm-ia64/sn/sn1/router.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/sn1/router.h Tue Apr 10 18:22:37 2001 @@ -513,7 +513,7 @@ #ifdef DEBUG int64_t ri_deltatime; /* Time it took to sample */ #endif - lock_t ri_lock; /* Lock for access to router info */ + spinlock_t ri_lock; /* Lock for access to router info */ net_vec_t *ri_vecarray; /* Pointer to array of vectors */ struct lboard_s *ri_brd; /* Pointer to board structure */ char * ri_name; /* This board's hwg path */ @@ -566,6 +566,7 @@ #define NORMAL_ROUTER_NAME "normal_router" #define NULL_ROUTER_NAME "null_router" #define META_ROUTER_NAME "meta_router" +#define REPEATER_ROUTER_NAME "repeater_router" #define UNKNOWN_ROUTER_NAME "unknown_router" /* The following definitions are needed by the router traversing @@ -630,7 +631,7 @@ */ #define RRM_RESETOK(_L) (UINT64_CAST 1 << ((_L) - 1)) -#define RRM_RESETOK_ALL (UINT64_CAST 0x3f) +#define RRM_RESETOK_ALL ALL_PORTS /* * RR_META_TABLE(_x) and RR_LOCAL_TABLE(_x) mask and shift definitions diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/sn1/slotnum.h linux.ac/include/asm-ia64/sn/sn1/slotnum.h --- linux.vanilla/include/asm-ia64/sn/sn1/slotnum.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/sn1/slotnum.h Tue Apr 10 18:22:37 2001 @@ -14,8 +14,7 @@ #define SLOTNUM_MAXLENGTH 16 /* - * This file attempts to define a slot number space across all slots - * a IP27 module. Here, we deal with the top level slots. + * This file attempts to define a slot number space across all slots. * * Node slots * Router slots @@ -24,16 +23,20 @@ * Other slots are children of their parent crosstalk slot: * PCI slots * VME slots + * + * The PCI class has been added since the XBridge ASIC on SN-MIPS + * has built-in PCI bridges (2). On IBricks, widget E & F serve + * PCI busses, and on PBricks all widgets serve as PCI busses + * with the use of the super-bridge mode of the XBridge ASIC. */ -// #include <slotnum.h> -// #ifdef NOTDEF /* moved to sys/slotnum.h */ #define SLOTNUM_NODE_CLASS 0x00 /* Node */ #define SLOTNUM_ROUTER_CLASS 0x10 /* Router */ #define SLOTNUM_XTALK_CLASS 0x20 /* Xtalk */ #define SLOTNUM_MIDPLANE_CLASS 0x30 /* Midplane */ #define SLOTNUM_XBOW_CLASS 0x40 /* Xbow */ #define SLOTNUM_KNODE_CLASS 0x50 /* Kego node */ +#define SLOTNUM_PCI_CLASS 0x60 /* PCI widgets on XBridge */ #define SLOTNUM_INVALID_CLASS 0xf0 /* Invalid */ #define SLOTNUM_CLASS_MASK 0xf0 @@ -41,7 +44,6 @@ #define SLOTNUM_GETCLASS(_sn) ((_sn) & SLOTNUM_CLASS_MASK) #define SLOTNUM_GETSLOT(_sn) ((_sn) & SLOTNUM_SLOT_MASK) -// #endif /* NOTDEF */ /* This determines module to pnode mapping. */ /* NODESLOTS_PER_MODULE has changed from 4 to 6 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/sn1/uart16550.h linux.ac/include/asm-ia64/sn/sn1/uart16550.h --- linux.vanilla/include/asm-ia64/sn/sn1/uart16550.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/sn1/uart16550.h Tue Apr 10 18:22:37 2001 @@ -1,3 +1,16 @@ +/* $Id$ + * + * 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) 1992 - 1997, 2000 Silicon Graphics, Inc. + * Copyright (C) 2000 by Colin Ngam + */ + +#ifndef _ASM_SN_SN1_UART16550_H +#define _ASM_SN_SN1_UART16550_H + /* * Definitions for 16550 chip @@ -212,3 +225,4 @@ #define INC_RING_POINTER(x) \ ( ((x & 0xffe0) < 4064) ? (x += 32) : 0 ) +#endif /* _ASM_SN_SN1_UART16550_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/sn1/war.h linux.ac/include/asm-ia64/sn/sn1/war.h --- linux.vanilla/include/asm-ia64/sn/sn1/war.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/sn1/war.h Thu Jan 1 01:00:00 1970 @@ -1,25 +0,0 @@ -/* $Id$ - * - * 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) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam - */ -#ifndef _ASM_SN_SN1_WAR_H -#define _ASM_SN_SN1_WAR_H - -/**************************************************************************** - * Support macros and defitions for hardware workarounds in * - * early chip versions. * - ****************************************************************************/ - -/* - * This is the bitmap of runtime-switched workarounds. - */ -typedef short warbits_t; - -extern int warbits_override; - -#endif /* _ASM_SN_SN1_WAR_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/sn_cpuid.h linux.ac/include/asm-ia64/sn/sn_cpuid.h --- linux.vanilla/include/asm-ia64/sn/sn_cpuid.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/sn_cpuid.h Tue Apr 10 18:22:37 2001 @@ -13,6 +13,7 @@ #define _ASM_IA64_SN_SN_CPUID_H #include <linux/config.h> +#include <asm/processor.h> #include <asm/sn/mmzone_sn1.h> /* @@ -26,18 +27,35 @@ /* - * The following assumes the following mappings for LID register values: + * Definitions of terms (these definitions are for IA64 ONLY. Other architectures + * use cpuid/cpunum quite defferently): + * + * CPUID - a number in range of 0..NR_CPUS-1 that uniquely identifies + * the cpu. The value cpuid has no significance on IA64 other than + * the boot cpu is 0. + * smp_processor_id() returns the cpuid of the current cpu. + * + * CPUNUM - On IA64, a cpunum and cpuid are the same. This is NOT true + * on other architectures like IA32. + * + * CPU_PHYSICAL_ID (also known as HARD_PROCESSOR_ID) + * This is the same as 31:24 of the processor LID register + * hard_smp_processor_id()- cpu_physical_id of current processor + * cpu_physical_id(cpuid) - convert a <cpuid> to a <physical_cpuid> + * cpu_logical_id(phy_id) - convert a <physical_cpuid> to a <cpuid> + * * not real efficient - dont use in perf critical code * - * LID + * LID - processor defined register (see PRM V2). * 31:24 - id Contains the NASID * 23:16 - eid Contains 0-3 to identify the cpu on the node * bit 17 - synergy number - * bit 16 - FSB number + * bit 16 - FSB slot number + * * - * SAPICID - * This is the same as 31:24 of LID * - * The macros convert between cpuid & slice/fsb/synergy/nasid/cnodeid. + * The following assumes the following mappings for LID register values: + * + * The macros convert between cpu physical ids & slice/fsb/synergy/nasid/cnodeid. * These terms are described below: * * @@ -46,7 +64,7 @@ * ----- ----- ----- ----- * | | | | * | | | | - * 0 | | 1 0 | | 1 FSB + * 0 | | 1 0 | | 1 FSB SLOT * ------- ------- * | | * | | @@ -68,25 +86,27 @@ * */ +#ifndef CONFIG_SMP +#define cpu_logical_id(cpu) 0 +#define cpu_physical_id(cpuid) ((ia64_get_lid() >> 16) & 0xffff) +#endif - -#define sapicid_to_nasid(sid) ((sid) >> 8) -#define sapicid_to_synergy(sid) (((sid) >> 1) & 1) -#define sapicid_to_fsb(sid) ((sid) & 1) -#define sapicid_to_slice(sid) ((sid) & 3) +#define cpu_physical_id_to_nasid(cpi) ((cpi) >> 8) +#define cpu_physical_id_to_synergy(cpi) (((cpi) >> 1) & 1) +#define cpu_physical_id_to_fsb_slot(cpi) ((cpi) & 1) +#define cpu_physical_id_to_slice(cpi) ((cpi) & 3) /* * NOTE: id & eid refer to Intels definitions of the LID register * (id = NASID, eid = slice) * NOTE: on non-MP systems, only cpuid 0 exists */ -#define id_eid_to_sapicid(id,eid) (((id)<<8) | (eid)) -#define id_eid_to_cpuid(id,eid) ((NASID_TO_CNODEID(id)<<2) | (eid)) +#define id_eid_to_cpu_physical_id(id,eid) (((id)<<8) | (eid)) +#define id_eid_to_cpuid(id,eid) (cpu_logical_id(id_eid_to_cpu_physical_id((id),(eid)))) /* - * The following table/struct is for translating between sapicid and cpuids. - * It is also used for managing PTC coherency domains. + * The following table/struct is used for managing PTC coherency domains. */ typedef struct { u8 domain; @@ -99,28 +119,13 @@ /* - * cpuid_to_spaicid - Convert a cpuid to a SAPIC id of the cpu. - * The SAPIC id is the same as bits 31:16 of the LID register. - */ -static __inline__ int -cpuid_to_spaicid(int cpuid) -{ -#ifdef CONFIG_SMP - return cpu_physical_id(cpuid); -#else - return ((ia64_get_lid() >> 16) & 0xffff); -#endif -} - - -/* * cpuid_to_fsb_slot - convert a cpuid to the fsb slot number that it is in. * (there are 2 cpus per FSB. This function returns 0 or 1) */ static __inline__ int cpuid_to_fsb_slot(int cpuid) { - return sapicid_to_fsb(cpuid_to_spaicid(cpuid)); + return cpu_physical_id_to_fsb_slot(cpu_physical_id(cpuid)); } @@ -132,7 +137,7 @@ static __inline__ int cpuid_to_synergy(int cpuid) { - return sapicid_to_synergy(cpuid_to_spaicid(cpuid)); + return cpu_physical_id_to_synergy(cpu_physical_id(cpuid)); } @@ -143,7 +148,7 @@ static __inline__ int cpuid_to_slice(int cpuid) { - return sapicid_to_slice(cpuid_to_spaicid(cpuid)); + return cpu_physical_id_to_slice(cpu_physical_id(cpuid)); } @@ -153,7 +158,7 @@ static __inline__ int cpuid_to_nasid(int cpuid) { - return sapicid_to_nasid(cpuid_to_spaicid(cpuid)); + return cpu_physical_id_to_nasid(cpu_physical_id(cpuid)); } @@ -166,23 +171,42 @@ return nasid_map[cpuid_to_nasid(cpuid)]; } +/* + * cnodeid_to_nasid - convert a cnodeid to a NASID + */ static __inline__ int cnodeid_to_nasid(int cnodeid) { - int i; - for (i = 0; i < MAXNASIDS; i++) { - if (nasid_map[i] == cnodeid) { - return(i); - } - } - return(-1); + if (nasid_map[cnodeid_map[cnodeid]] != cnodeid) + panic("cnodeid_to_nasid, cnode = %d", cnodeid); + return cnodeid_map[cnodeid]; } +/* + * nasid_to_cnodeid - convert a NASID to a cnodeid + */ +static __inline__ int +nasid_to_cnodeid(int nasid) +{ + if (cnodeid_map[nasid_map[nasid]] != nasid) + panic("nasid_to_cnodeid"); + return nasid_map[nasid]; +} + + +/* + * cnode_slice_to_cpuid - convert a codeid & slice to a cpuid + */ static __inline__ int cnode_slice_to_cpuid(int cnodeid, int slice) { return(id_eid_to_cpuid(cnodeid_to_nasid(cnodeid),slice)); } +/* + * cpuid_to_subnode - convert a cpuid to the subnode it resides on. + * slice 0 & 1 are on subnode 0 + * slice 2 & 3 are on subnode 1. + */ static __inline__ int cpuid_to_subnode(int cpuid) { int ret = cpuid_to_slice(cpuid); @@ -190,9 +214,27 @@ else return 1; } +/* + * cpuid_to_localslice - convert a cpuid to a local slice + * slice 0 & 2 are local slice 0 + * slice 1 & 3 are local slice 1 + */ static __inline__ int cpuid_to_localslice(int cpuid) { return(cpuid_to_slice(cpuid) & 1); +} + +static __inline__ int +cnodeid_to_cpuid(int cnode) { + int cpu; + + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + if (cpuid_to_cnodeid(cpu) == cnode) { + break; + } + } + if (cpu == smp_num_cpus) cpu = -1; + return cpu; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/sn_fru.h linux.ac/include/asm-ia64/sn/sn_fru.h --- linux.vanilla/include/asm-ia64/sn/sn_fru.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/sn_fru.h Tue Apr 10 18:22:37 2001 @@ -1,16 +1,14 @@ -/************************************************************************** - * * - * Copyright (C) 1992-1997, Silicon Graphics, Inc. * - * * - * These coded instructions, statements, and computer programs contain * - * unpublished proprietary information of Silicon Graphics, Inc., and * - * are protected by Federal copyright law. They may not be disclosed * - * to third parties or copied or duplicated in any form, in whole or * - * in part, without the prior written consent of Silicon Graphics, Inc. * - * * - **************************************************************************/ -#ifndef __SYS_SN_SN0_FRU_H__ -#define __SYS_SN_SN0_FRU_H__ +/* $Id$ + * + * 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) 1992 - 1997, 1999-2000 Silicon Graphics, Inc. + * Copyright (C) 2000 by Patrick Gefre + */ +#ifndef _ASM_SN_SN_FRU_H +#define _ASM_SN_SN_FRU_H #define MAX_DIMMS 8 /* max # of dimm banks */ #define MAX_PCIDEV 8 /* max # of pci devices on a pci bus */ @@ -44,6 +42,5 @@ } kf_pci_bus_t; - -#endif /* #ifdef __SYS_SN_SN0_FRU_H__ */ +#endif /* _ASM_SN_SN_FRU_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/sn_private.h linux.ac/include/asm-ia64/sn/sn_private.h --- linux.vanilla/include/asm-ia64/sn/sn_private.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/sn_private.h Tue Apr 10 18:22:37 2001 @@ -10,7 +10,6 @@ #ifndef _ASM_SN_PRIVATE_H #define _ASM_SN_PRIVATE_H -#include <linux/config.h> #include <asm/sn/nodepda.h> #include <asm/sn/xtalk/xwidget.h> #include <asm/sn/xtalk/xtalk_private.h> @@ -20,12 +19,12 @@ extern hubreg_t get_region(cnodeid_t); extern hubreg_t nasid_to_region(nasid_t); /* promif.c */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER extern cpuid_t cpu_node_probe(cpumask_t *cpumask, int *numnodes); #endif extern void he_arcs_set_vectors(void); extern void mem_init(void); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER extern int cpu_enabled(cpuid_t); #endif extern void cpu_unenable(cpuid_t); @@ -35,7 +34,7 @@ extern int check_nasid_equiv(nasid_t, nasid_t); extern nasid_t get_console_nasid(void); extern char get_console_pcislot(void); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER extern void intr_init_vecblk(nodepda_t *npda, cnodeid_t, int); #endif @@ -112,19 +111,19 @@ /* init.c */ extern cnodeid_t get_compact_nodeid(void); /* get compact node id */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER extern void init_platform_nodepda(nodepda_t *npda, cnodeid_t node); extern void init_platform_pda(pda_t *ppda, cpuid_t cpu); #endif extern void per_cpu_init(void); extern void per_hub_init(cnodeid_t); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER extern cpumask_t boot_cpumask; #endif extern int is_fine_dirmode(void); extern void update_node_information(cnodeid_t); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* clksupport.c */ extern void early_counter_intr(eframe_t *); #endif @@ -251,7 +250,7 @@ /* IP27 cpu-specific information stored under INFO_LBL_CPU_INFO */ /* TBD: IP27-dependent stuff currently in pda.h should be here */ typedef struct cpuinfo_s { -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER pda_t *ci_cpupda; /* pointer to CPU's private data area */ #endif cpuid_t ci_cpuid; /* CPU ID */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/sn_sal.h linux.ac/include/asm-ia64/sn/sn_sal.h --- linux.vanilla/include/asm-ia64/sn/sn_sal.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-ia64/sn/sn_sal.h Tue Apr 10 18:22:37 2001 @@ -0,0 +1,25 @@ +#ifndef _ASM_IA64_SN_SAL_H +#define _ASM_IA64_SN_SAL_H + +/* + * System Abstraction Layer definitions for IA64 + * + * + * Copyright (C) 2000, Silicon Graphics. + * Copyright (C) 2000. Jack Steiner (steiner@sgi.com) + */ + + +#include <asm/sal.h> + + +// SGI Specific Calls +#define SN_SAL_POD_MODE 0x02000001 +#define SN_SAL_SYSTEM_RESET 0x02000002 +#define SN_SAL_PROBE 0x02000003 + + +u64 ia64_sn_probe_io_slot(long paddr, long size, void *data_ptr); + + +#endif /* _ASM_IA64_SN_SN1_SAL_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/sv.h linux.ac/include/asm-ia64/sn/sv.h --- linux.vanilla/include/asm-ia64/sn/sv.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-ia64/sn/sv.h Tue Apr 10 18:22:37 2001 @@ -0,0 +1,153 @@ +/* + * 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) 2000 Silicon Graphics, Inc. All rights reserved + * + * This implemenation of synchronization variables is heavily based on + * one done by Steve Lord <lord@sgi.com> + * + * Paul Cassella <pwc@sgi.com> + */ + +#ifndef SV_H +#define SV_H + +#include <linux/spinlock.h> +#include <asm/semaphore.h> + +#ifndef ASSERT + +#define ASSERT(x) do { \ + if(!(x)) { \ + printk(KERN_ERR "%s\n", "Assertion failed: " # x); \ + BUG(); \ + } \ + } while(0) +#define _SV_ASSERT +#endif + +typedef void sv_mon_lock_t; +typedef void (*sv_mon_unlock_func_t)(sv_mon_lock_t *lock); + +/* sv_flags values: */ + +#define SV_ORDER_FIFO 0x001 +#define SV_ORDER_FILO 0x002 +#define SV_ORDER_LIFO SV_ORDER_FILO + +/* If at some point one order becomes preferable to others, we can + switch to it if the caller of sv_init doesn't specify. */ +#define SV_ORDER_DEFAULT SV_ORDER_FIFO + +#define SV_ORDER_MASK 0x00f + + +#define SV_MON_SEMA 0x010 +#define SV_MON_SPIN 0x020 + +#define SV_MON_MASK 0x0f0 + + +/* + If the monitor lock can be aquired from interrupts. Note that this + is a superset of the cases in which the sv can be touched from + interrupts. + + This is currently only valid when the monitor lock is a spinlock. + + If this is used, sv_wait, sv_signal, and sv_broadcast must all be + called with interrupts disabled, which has to happen anyway to have + acquired the monitor spinlock. + */ +#define SV_INTS 0x100 + +/* ditto for bottom halves */ +#define SV_BHS 0x200 + + + +/* sv_wait_flag values: */ +#define SV_WAIT_SIG 0x001 /* Allow sv_wait to be interrupted by a signal */ + +typedef struct sv_s { + wait_queue_head_t sv_waiters; + sv_mon_lock_t *sv_mon_lock; /* Lock held for exclusive access to monitor. */ + sv_mon_unlock_func_t sv_mon_unlock_func; + spinlock_t sv_lock; /* Spinlock protecting the sv itself. */ + int sv_flags; +} sv_t; + +#define DECLARE_SYNC_VARIABLE(sv, l, f) sv_t sv = sv_init(&sv, l, f) + +/* + * @sv the sync variable to initialize + * @monitor_lock the lock enforcing exclusive running in the monitor + * @flags one of + * SV_MON_SEMA monitor_lock is a semaphore + * SV_MON_SPIN monitor_lock is a spinlock + * and a bitwise or of some subset of + * SV_INTS - the monitor lock can be acquired from interrupts (and + * hence, whenever we hold it, interrupts are disabled or + * we're in an interrupt.) This is only valid when + * SV_MON_SPIN is set. + */ +void sv_init(sv_t *sv, sv_mon_lock_t *monitor_lock, int flags); + +/* + * Set SV_WAIT_SIG in sv_wait_flags to let the sv_wait be interrupted by signals. + * + * timeout is how long to wait before giving up, or 0 to wait + * indefinately. It is given in jiffies, and is relative. + * + * The associated lock must be locked on entry. It is unlocked on return. + * + * Return values: + * + * n < 0 : interrupted, -n jiffies remaining on timeout, or -1 if timeout == 0 + * n = 0 : timeout expired + * n > 0 : sv_signal()'d, n jiffies remaining on timeout, or 1 if timeout == 0 + */ +extern signed long sv_wait(sv_t *sv, int sv_wait_flags, + unsigned long timeout /* relative jiffies */); + +static inline int sv_wait_compat(sv_t *sv, sv_mon_lock_t *lock, int sv_wait_flags, + unsigned long timeout, int sv_mon_type) +{ + ASSERT(sv_mon_type == (sv->sv_flags & SV_MON_MASK)); + if(sv->sv_mon_lock) + ASSERT(lock == sv->sv_mon_lock); + else + sv->sv_mon_lock = lock; + + return sv_wait(sv, sv_wait_flags, timeout); +} + + +/* These work like Irix's sv_wait() and sv_wait_sig(), except the + caller must call the one correpsonding to the type of the monitor + lock. */ +#define sv_spin_wait(sv, lock) \ + sv_wait_compat(sv, lock, 0, 0, SV_MON_SPIN) +#define sv_spin_wait_sig(sv, lock) \ + sv_wait_compat(sv, lock, SV_WAIT_SIG, 0, SV_MON_SPIN) + +#define sv_sema_wait(sv, lock) \ + sv_wait_compat(sv, lock, 0, 0, SV_MON_SEMA) +#define sv_sema_wait_sig(sv, lock) \ + sv_wait_compat(sv, lock, SV_WAIT_SIG, 0, SV_MON_SEMA) + +/* These work as in Irix. */ +void sv_signal(sv_t *sv); +void sv_broadcast(sv_t *sv); + +/* This works as in Irix. */ +void sv_destroy(sv_t *sv); + +#ifdef _SV_ASSERT +#undef ASSERT +#undef _SV_ASSERT +#endif + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/synergy.h linux.ac/include/asm-ia64/sn/synergy.h --- linux.vanilla/include/asm-ia64/sn/synergy.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/synergy.h Sat Apr 14 01:39:15 2001 @@ -1,7 +1,10 @@ #ifndef ASM_IA64_SN_SYNERGY_H #define ASM_IA64_SN_SYNERGY_H +#include <linux/config.h> + #include "asm/io.h" +#include "asm/sn/nodepda.h" #include "asm/sn/intr_public.h" @@ -41,47 +44,52 @@ #define WRITE_LOCAL_SYNERGY_REG(addr, value) __synergy_out(addr, value) #define HUBREG_CAST (volatile hubreg_t *) -#define NODE_OFFSET(_n) (UINT64_CAST (_n) << NODE_SIZE_BITS) -#define SYN_UNCACHED_SPACE 0xc000000000000000 -#define NODE_HSPEC_BASE(_n) (HSPEC_BASE + NODE_OFFSET(_n)) -#define NODE_LREG_BASE(_n) (NODE_HSPEC_BASE(_n) + 0x30000000) -#define RREG_BASE(_n) (NODE_LREG_BASE(_n)) +#define HUB_L(_a) *(_a) +#define HUB_S(_a, _d) *(_a) = (_d) + +#define HSPEC_SYNERGY0_0 0x04000000 /* Synergy0 Registers */ +#define HSPEC_SYNERGY1_0 0x05000000 /* Synergy1 Registers */ +#define HS_SYNERGY_STRIDE (HSPEC_SYNERGY1_0 - HSPEC_SYNERGY0_0) #define REMOTE_HSPEC(_n, _x) (HUBREG_CAST (RREG_BASE(_n) + (_x))) -#define HSPEC_SYNERGY0_0 0x04000000 /* Synergy0 Registers */ -#define HSPEC_SYNERGY1_0 0x05000000 /* Synergy1 Registers */ -#define HS_SYNERGY_STRIDE (HSPEC_SYNERGY1_0 - HSPEC_SYNERGY0_0) +#define RREG_BASE(_n) (NODE_LREG_BASE(_n)) +#define NODE_LREG_BASE(_n) (NODE_HSPEC_BASE(_n) + 0x30000000) +#define NODE_HSPEC_BASE(_n) (HSPEC_BASE + NODE_OFFSET(_n)) +#ifndef HSPEC_BASE +#define HSPEC_BASE (SYN_UNCACHED_SPACE | HSPEC_BASE_SYN) +#endif +#define SYN_UNCACHED_SPACE 0xc000000000000000 +#define HSPEC_BASE_SYN 0x00000b0000000000 +#define NODE_OFFSET(_n) (UINT64_CAST (_n) << NODE_SIZE_BITS) +#define NODE_SIZE_BITS 33 -#define HUB_L(_a) *(_a) -#define HUB_S(_a, _d) *(_a) = (_d) +#define RSYN_REG_OFFSET(fsb, reg) (((fsb) ? HSPEC_SYNERGY1_0 : HSPEC_SYNERGY0_0) | (reg)) #define REMOTE_SYNERGY_LOAD(nasid, fsb, reg) __remote_synergy_in(nasid, fsb, reg) #define REMOTE_SYNERGY_STORE(nasid, fsb, reg, val) __remote_synergy_out(nasid, fsb, reg, val) -extern inline void -__remote_synergy_out(int nasid, int fsb, unsigned long reg, unsigned long val) { - unsigned long addr = ((RREG_BASE(nasid)) + - ((HSPEC_SYNERGY0_0 | (fsb)*HS_SYNERGY_STRIDE) | ((reg) << 2))); - - HUB_S((unsigned long *)(addr), (val) >> 48); - HUB_S((unsigned long *)(addr+0x08), (val) >> 32); - HUB_S((unsigned long *)(addr+0x10), (val) >> 16); - HUB_S((unsigned long *)(addr+0x18), (val) ); - __ia64_mf_a(); +extern inline uint64_t +__remote_synergy_in(int nasid, int fsb, uint64_t reg) { + volatile uint64_t *addr; + + addr = (uint64_t *)(RREG_BASE(nasid) + RSYN_REG_OFFSET(fsb, reg)); + return (*addr); } -extern inline unsigned long -__remote_synergy_in(int nasid, int fsb, unsigned long reg) { - volatile unsigned long *addr = (unsigned long *) ((RREG_BASE(nasid)) + - ((HSPEC_SYNERGY0_0 | (fsb)*HS_SYNERGY_STRIDE) | (reg))); - unsigned long ret; +extern inline void +__remote_synergy_out(int nasid, int fsb, uint64_t reg, uint64_t value) { + volatile uint64_t *addr; - ret = *addr; - __ia64_mf_a(); - return ret; + addr = (uint64_t *)(RREG_BASE(nasid) + RSYN_REG_OFFSET(fsb, (reg<<2))); + *(addr+0) = value >> 48; + *(addr+1) = value >> 32; + *(addr+2) = value >> 16; + *(addr+3) = value; + __ia64_mf_a(); } +/* XX this doesn't make a lot of sense. Which fsb? */ extern inline void __synergy_out(unsigned long addr, unsigned long value) { @@ -94,6 +102,7 @@ #define READ_LOCAL_SYNERGY_REG(addr) __synergy_in(addr) +/* XX this doesn't make a lot of sense. Which fsb? */ extern inline unsigned long __synergy_in(unsigned long addr) { @@ -120,7 +129,39 @@ spinlock_t action_list_lock; struct sn1_intr_action *action_list; }; - + +#if defined(CONFIG_IA64_SGI_SYNERGY_PERF) + +/* multiplex the counters every 10 timer interrupts */ +#define SYNERGY_PERF_FREQ_DEFAULT 10 + +/* synergy perf control registers */ +#define PERF_CNTL0_A 0xab0UL /* control A on FSB0 */ +#define PERF_CNTL0_B 0xab8UL /* control B on FSB0 */ +#define PERF_CNTL1_A 0xac0UL /* control A on FSB1 */ +#define PERF_CNTL1_B 0xac8UL /* control B on FSB1 */ + +/* synergy perf counters */ +#define PERF_CNTR0_A 0xad0UL /* counter A on FSB0 */ +#define PERF_CNTR0_B 0xad8UL /* counter B on FSB0 */ +#define PERF_CNTR1_A 0xaf0UL /* counter A on FSB1 */ +#define PERF_CNTR1_B 0xaf8UL /* counter B on FSB1 */ + +/* Synergy perf data. Each nodepda keeps a list of these */ +struct synergy_perf_s { + uint64_t intervals; /* count of active intervals for this event */ + uint64_t modesel; /* mode and sel bits, both A and B registers */ + struct synergy_perf_s *next; /* next in circular linked list */ + uint64_t counts[2]; /* [0] is synergy-A counter, [1] synergy-B counter */ +}; + +typedef struct synergy_perf_s synergy_perf_t; + +extern void synergy_perf_init(void); +extern void synergy_perf_update(int); + +#endif /* CONFIG_IA64_SGI_SYNERGY_PERF */ + /* Temporary defintions for testing: */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/types.h linux.ac/include/asm-ia64/sn/types.h --- linux.vanilla/include/asm-ia64/sn/types.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/types.h Tue Apr 10 18:22:37 2001 @@ -9,7 +9,6 @@ #ifndef _ASM_SN_TYPES_H #define _ASM_SN_TYPES_H -#include <linux/config.h> #include <linux/types.h> typedef unsigned long cpuid_t; @@ -22,15 +21,12 @@ typedef signed short cmoduleid_t; /* kernel compact module id type */ typedef unsigned char clusterid_t; /* Clusterid of the cell */ -#if defined(CONFIG_IA64_SGI_IO) #define __psunsigned_t uint64_t #define lock_t uint64_t -#define sv_t uint64_t typedef unsigned long iopaddr_t; typedef unsigned char uchar_t; typedef unsigned long paddr_t; typedef unsigned long pfn_t; -#endif /* CONFIG_IA64_SGI_IO */ #endif /* _ASM_SN_TYPES_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/war.h linux.ac/include/asm-ia64/sn/war.h --- linux.vanilla/include/asm-ia64/sn/war.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/war.h Thu Jan 1 01:00:00 1970 @@ -1,18 +0,0 @@ -/* $Id$ - * - * 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) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam - */ -#ifndef _ASM_SN_WAR_H -#define _ASM_SN_WAR_H - -#include <linux/config.h> -#if defined (CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) -#include <asm/sn/sn1/war.h> -#endif - -#endif /* _ASM_SN_WAR_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/xtalk/xtalk.h linux.ac/include/asm-ia64/sn/xtalk/xtalk.h --- linux.vanilla/include/asm-ia64/sn/xtalk/xtalk.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/xtalk/xtalk.h Tue Apr 10 18:22:37 2001 @@ -278,6 +278,7 @@ /* INTERRUPT MANAGEMENT */ xtalk_intr_alloc_f *intr_alloc; + xtalk_intr_alloc_f *intr_alloc_nothd; xtalk_intr_free_f *intr_free; xtalk_intr_connect_f *intr_connect; xtalk_intr_disconnect_f *intr_disconnect; @@ -308,6 +309,7 @@ extern xtalk_dmaaddr_drain_f xtalk_dmaaddr_drain; extern xtalk_dmalist_drain_f xtalk_dmalist_drain; extern xtalk_intr_alloc_f xtalk_intr_alloc; +extern xtalk_intr_alloc_f xtalk_intr_alloc_nothd; extern xtalk_intr_free_f xtalk_intr_free; extern xtalk_intr_connect_f xtalk_intr_connect; extern xtalk_intr_disconnect_f xtalk_intr_disconnect; @@ -342,10 +344,6 @@ extern iopaddr_t xtalk_intr_addr_get(xtalk_intr_t xtalk_intr); extern devfs_handle_t xtalk_intr_cpu_get(xtalk_intr_t xtalk_intr); extern void *xtalk_intr_sfarg_get(xtalk_intr_t xtalk_intr); - -extern int xtalk_intr_flags_get(xtalk_intr_t xtalk_intr); -/* XTALK_INTR flags */ -#define XTALK_INTR_NOTHREAD 1 /* interrupt handler wants to be called at interrupt level */ /* Generic crosstalk pio interfaces */ extern devfs_handle_t xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/xtalk/xtalk_private.h linux.ac/include/asm-ia64/sn/xtalk/xtalk_private.h --- linux.vanilla/include/asm-ia64/sn/xtalk/xtalk_private.h Thu Jan 4 21:00:15 2001 +++ linux.ac/include/asm-ia64/sn/xtalk/xtalk_private.h Tue Apr 10 18:22:37 2001 @@ -10,11 +10,7 @@ #ifndef _ASM_SN_XTALK_XTALK_PRIVATE_H #define _ASM_SN_XTALK_XTALK_PRIVATE_H -#ifdef IRIX -#include <sys/ioerror.h> /* for error function and arg types */ -#else #include <asm/sn/ioerror.h> /* for error function and arg types */ -#endif /* * xtalk_private.h -- private definitions for xtalk @@ -44,7 +40,6 @@ * All Crosstalk providers set up interrupts using this information. */ struct xtalk_intr_s { - int xi_flags; /* XTALK_INTR flags */ devfs_handle_t xi_dev; /* requestor of this intr */ xwidgetnum_t xi_target; /* master's widget number */ xtalk_intr_vector_t xi_vector; /* 8-bit interrupt vector */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/sn/xtalk/xtalkaddrs.h linux.ac/include/asm-ia64/sn/xtalk/xtalkaddrs.h --- linux.vanilla/include/asm-ia64/sn/xtalk/xtalkaddrs.h Thu Jan 4 23:25:55 2001 +++ linux.ac/include/asm-ia64/sn/xtalk/xtalkaddrs.h Tue Apr 10 18:22:37 2001 @@ -10,6 +10,8 @@ #ifndef _ASM_SN_XTALK_XTALKADDRS_H #define _ASM_SN_XTALK_XTALKADDRS_H +#include <linux/config.h> + /* * CrossTalk to SN0 Hub addressing support * @@ -58,8 +60,6 @@ * This looks very much like a REMOTE_HUB access, except the nodeID * is in a different place, and the highest xtalk bit is set. */ - -#include <linux/config.h> /* Hub-specific xtalk definitions */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/softirq.h linux.ac/include/asm-ia64/softirq.h --- linux.vanilla/include/asm-ia64/softirq.h Fri Mar 10 23:24:02 2000 +++ linux.ac/include/asm-ia64/softirq.h Tue Apr 10 18:22:37 2001 @@ -2,17 +2,14 @@ #define _ASM_IA64_SOFTIRQ_H /* - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <asm/hardirq.h> -#define cpu_bh_disable(cpu) do { local_bh_count(cpu)++; barrier(); } while (0) -#define cpu_bh_enable(cpu) do { barrier(); local_bh_count(cpu)--; } while (0) +#define local_bh_disable() do { local_bh_count()++; barrier(); } while (0) +#define local_bh_enable() do { barrier(); local_bh_count()--; } while (0) -#define local_bh_disable() cpu_bh_disable(smp_processor_id()) -#define local_bh_enable() cpu_bh_enable(smp_processor_id()) - -#define in_softirq() (local_bh_count(smp_processor_id()) != 0) +#define in_softirq() (local_bh_count() != 0) #endif /* _ASM_IA64_SOFTIRQ_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/system.h linux.ac/include/asm-ia64/system.h --- linux.vanilla/include/asm-ia64/system.h Tue Apr 3 17:32:27 2001 +++ linux.ac/include/asm-ia64/system.h Tue Apr 10 18:22:37 2001 @@ -7,8 +7,8 @@ * on information published in the Processor Abstraction Layer * and the System Abstraction Layer manual. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com> * Copyright (C) 1999 Don Dugger <don.dugger@intel.com> */ @@ -16,16 +16,18 @@ #include <asm/page.h> -#define KERNEL_START (PAGE_OFFSET + 0x500000) +#define KERNEL_START (PAGE_OFFSET + 68*1024*1024) /* * The following #defines must match with vmlinux.lds.S: */ +#define IVT_ADDR (KERNEL_START) #define IVT_END_ADDR (KERNEL_START + 0x8000) -#define ZERO_PAGE_ADDR (IVT_END_ADDR + 0*PAGE_SIZE) -#define SWAPPER_PGD_ADDR (IVT_END_ADDR + 1*PAGE_SIZE) +#define ZERO_PAGE_ADDR PAGE_ALIGN(IVT_END_ADDR) +#define SWAPPER_PGD_ADDR (ZERO_PAGE_ADDR + 1*PAGE_SIZE) #define GATE_ADDR (0xa000000000000000 + PAGE_SIZE) +#define PERCPU_ADDR (0xa000000000000000 + 2*PAGE_SIZE) #if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \ || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC) @@ -62,12 +64,10 @@ __u16 orig_x; /* cursor's x position */ __u16 orig_y; /* cursor's y position */ } console_info; - __u16 num_pci_vectors; /* number of ACPI derived PCI IRQ's*/ - __u64 pci_vectors; /* physical address of PCI data (pci_vector_struct)*/ __u64 fpswa; /* physical address of the fpswa interface */ __u64 initrd_start; __u64 initrd_size; -} ia64_boot_param; +} *ia64_boot_param; static inline void ia64_insn_group_barrier (void) @@ -181,50 +181,9 @@ #define __save_flags(flags) __asm__ __volatile__ ("mov %0=psr" : "=r" (flags) :: "memory") #define __save_and_cli(flags) local_irq_save(flags) #define save_and_cli(flags) __save_and_cli(flags) - - -#ifdef CONFIG_IA64_SOFTSDV_HACKS -/* - * Yech. SoftSDV has a slight probem with psr.i and itc/itm. If - * PSR.i = 0 and ITC == ITM, you don't get the timer tick posted. So, - * I'll check if ITC is larger than ITM here and reset if neccessary. - * I may miss a tick to two. - * - * Don't include asm/delay.h; it causes include loops that are - * mind-numbingly hard to follow. - */ - -#define get_itc(x) __asm__ __volatile__("mov %0=ar.itc" : "=r"((x)) :: "memory") -#define get_itm(x) __asm__ __volatile__("mov %0=cr.itm" : "=r"((x)) :: "memory") -#define set_itm(x) __asm__ __volatile__("mov cr.itm=%0" :: "r"((x)) : "memory") - -#define __restore_flags(x) \ -do { \ - unsigned long itc, itm; \ - local_irq_restore(x); \ - get_itc(itc); \ - get_itm(itm); \ - if (itc > itm) \ - set_itm(itc + 10); \ -} while (0) - -#define __sti() \ -do { \ - unsigned long itc, itm; \ - local_irq_enable(); \ - get_itc(itc); \ - get_itm(itm); \ - if (itc > itm) \ - set_itm(itc + 10); \ -} while (0) - -#else /* !CONFIG_IA64_SOFTSDV_HACKS */ - #define __sti() local_irq_enable () #define __restore_flags(flags) local_irq_restore(flags) -#endif /* !CONFIG_IA64_SOFTSDV_HACKS */ - #ifdef CONFIG_SMP extern void __global_cli (void); extern void __global_sti (void); @@ -325,7 +284,7 @@ #define xchg(ptr,x) \ ((__typeof__(*(ptr))) __xchg ((unsigned long) (x), (ptr), sizeof(*(ptr)))) -/* +/* * Atomic compare and exchange. Compare OLD with MEM, if identical, * store NEW in MEM. Return the initial value in MEM. Success is * indicated by comparing RETURN with OLD. @@ -350,7 +309,7 @@ case 2: _o_ = (__u16) (long) (old); break; \ case 4: _o_ = (__u32) (long) (old); break; \ case 8: _o_ = (__u64) (long) (old); break; \ - default: \ + default: break; \ } \ __asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO"(_o_)); \ switch (size) { \ @@ -439,7 +398,7 @@ (last) = ia64_switch_to((next)); \ } while (0) -#ifdef CONFIG_SMP +#ifdef CONFIG_SMP /* * In the SMP case, we save the fph state when context-switching * away from a thread that modified fph. This way, when the thread diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/timex.h linux.ac/include/asm-ia64/timex.h --- linux.vanilla/include/asm-ia64/timex.h Mon Feb 7 02:42:40 2000 +++ linux.ac/include/asm-ia64/timex.h Tue Apr 10 18:22:37 2001 @@ -2,14 +2,15 @@ #define _ASM_IA64_TIMEX_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> + */ +/* + * 2001/01/18 davidm Removed CLOCK_TICK_RATE. It makes no sense on IA-64. + * Also removed cacheflush_time as it's entirely unused. */ - -#define CLOCK_TICK_RATE 1193180 /* Underlying HZ XXX fix me! */ typedef unsigned long cycles_t; -extern cycles_t cacheflush_time; static inline cycles_t get_cycles (void) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/tlb.h linux.ac/include/asm-ia64/tlb.h --- linux.vanilla/include/asm-ia64/tlb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-ia64/tlb.h Tue Apr 3 17:55:15 2001 @@ -0,0 +1 @@ +#include <asm-generic/tlb.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/uaccess.h linux.ac/include/asm-ia64/uaccess.h --- linux.vanilla/include/asm-ia64/uaccess.h Thu Jan 4 20:50:18 2001 +++ linux.ac/include/asm-ia64/uaccess.h Tue Apr 10 18:22:37 2001 @@ -25,14 +25,16 @@ * handler checks to see whether the faulting instruction has a fixup * associated and, if so, sets r8 to -EFAULT and clears r9 to 0 and * then resumes execution at the continuation point. - * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co + * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/errno.h> #include <linux/sched.h> +#include <asm/pgtable.h> + /* * For historical reasons, the following macros are grossly misnamed: */ @@ -49,16 +51,13 @@ #define segment_eq(a,b) ((a).seg == (b).seg) /* - * When accessing user memory, we need to make sure the entire area - * really is in user-level space. In order to do this efficiently, we - * make sure that the page at address TASK_SIZE is never valid (we do - * this by selecting VMALLOC_START as TASK_SIZE+PAGE_SIZE). This way, - * we can simply check whether the starting address is < TASK_SIZE - * and, if so, start accessing the memory. If the user specified bad - * length, we will fault on the NaT page and then return the - * appropriate error. + * When accessing user memory, we need to make sure the entire area really is in + * user-level space. In order to do this efficiently, we make sure that the page at + * address TASK_SIZE is never valid. We also need to make sure that the address doesn't + * point inside the virtually mapped linear page table. */ -#define __access_ok(addr,size,segment) (((unsigned long) (addr)) <= (segment).seg) +#define __access_ok(addr,size,segment) (((unsigned long) (addr)) <= (segment).seg \ + && ((segment).seg == KERNEL_DS.seg || rgn_offset((unsigned long) (addr)) < RGN_MAP_LIMIT)) #define access_ok(type,addr,size) __access_ok((addr),(size),get_fs()) static inline int @@ -85,28 +84,28 @@ */ #define __put_user(x,ptr) __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) #define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr))) - + extern void __get_user_unknown (void); -#define __get_user_nocheck(x,ptr,size) \ -({ \ - register long __gu_err __asm__ ("r8") = 0; \ - register long __gu_val __asm__ ("r9") = 0; \ - switch (size) { \ - case 1: __get_user_8(ptr); break; \ - case 2: __get_user_16(ptr); break; \ - case 4: __get_user_32(ptr); break; \ - case 8: __get_user_64(ptr); break; \ - default: __get_user_unknown(); break; \ - } \ - (x) = (__typeof__(*(ptr))) __gu_val; \ - __gu_err; \ +#define __get_user_nocheck(x,ptr,size) \ +({ \ + register long __gu_err asm ("r8") = 0; \ + register long __gu_val asm ("r9") = 0; \ + switch (size) { \ + case 1: __get_user_8(ptr); break; \ + case 2: __get_user_16(ptr); break; \ + case 4: __get_user_32(ptr); break; \ + case 8: __get_user_64(ptr); break; \ + default: __get_user_unknown(); break; \ + } \ + (x) = (__typeof__(*(ptr))) __gu_val; \ + __gu_err; \ }) #define __get_user_check(x,ptr,size,segment) \ ({ \ - register long __gu_err __asm__ ("r8") = -EFAULT; \ - register long __gu_val __asm__ ("r9") = 0; \ + register long __gu_err asm ("r8") = -EFAULT; \ + register long __gu_val asm ("r9") = 0; \ const __typeof__(*(ptr)) *__gu_addr = (ptr); \ if (__access_ok((long)__gu_addr,size,segment)) { \ __gu_err = 0; \ @@ -126,46 +125,60 @@ #define __m(x) (*(struct __large_struct *)(x)) /* We need to declare the __ex_table section before we can use it in .xdata. */ -__asm__ (".section \"__ex_table\", \"a\"\n\t.previous"); +asm (".section \"__ex_table\", \"a\"\n\t.previous"); + +#if __GNUC__ >= 3 +# define GAS_HAS_LOCAL_TAGS /* define if gas supports local tags a la [1:] */ +#endif + +#ifdef GAS_HAS_LOCAL_TAGS +# define _LL "[1:]" +#else +# define _LL "1:" +#endif #define __get_user_64(addr) \ - __asm__ ("\n1:\tld8 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ - "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)|1\n" \ - : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); + asm ("\n"_LL"\tld8 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ + "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)+4\n" \ + _LL \ + : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); #define __get_user_32(addr) \ - __asm__ ("\n1:\tld4 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ - "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)|1\n" \ - : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); + asm ("\n"_LL"\tld4 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ + "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)+4\n" \ + _LL \ + : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); #define __get_user_16(addr) \ - __asm__ ("\n1:\tld2 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ - "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)|1\n" \ - : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); + asm ("\n"_LL"\tld2 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ + "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)+4\n" \ + _LL \ + : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); #define __get_user_8(addr) \ - __asm__ ("\n1:\tld1 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ - "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)|1\n" \ - : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); + asm ("\n"_LL"\tld1 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ + "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)+4\n" \ + _LL \ + : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); extern void __put_user_unknown (void); -#define __put_user_nocheck(x,ptr,size) \ -({ \ - register long __pu_err __asm__ ("r8") = 0; \ - switch (size) { \ - case 1: __put_user_8(x,ptr); break; \ - case 2: __put_user_16(x,ptr); break; \ - case 4: __put_user_32(x,ptr); break; \ - case 8: __put_user_64(x,ptr); break; \ - default: __put_user_unknown(); break; \ - } \ - __pu_err; \ +#define __put_user_nocheck(x,ptr,size) \ +({ \ + register long __pu_err asm ("r8") = 0; \ + switch (size) { \ + case 1: __put_user_8(x,ptr); break; \ + case 2: __put_user_16(x,ptr); break; \ + case 4: __put_user_32(x,ptr); break; \ + case 8: __put_user_64(x,ptr); break; \ + default: __put_user_unknown(); break; \ + } \ + __pu_err; \ }) #define __put_user_check(x,ptr,size,segment) \ ({ \ - register long __pu_err __asm__ ("r8") = -EFAULT; \ + register long __pu_err asm ("r8") = -EFAULT; \ __typeof__(*(ptr)) *__pu_addr = (ptr); \ if (__access_ok((long)__pu_addr,size,segment)) { \ __pu_err = 0; \ @@ -186,27 +199,31 @@ * any memory gcc knows about, so there are no aliasing issues */ #define __put_user_64(x,addr) \ - __asm__ __volatile__ ( \ - "\n1:\tst8 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ - "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)\n" \ + asm volatile ( \ + "\n"_LL"\tst8 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ + "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)\n" \ + _LL \ : "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err)) #define __put_user_32(x,addr) \ - __asm__ __volatile__ ( \ - "\n1:\tst4 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ - "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)\n" \ + asm volatile ( \ + "\n"_LL"\tst4 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ + "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)\n" \ + _LL \ : "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err)) #define __put_user_16(x,addr) \ - __asm__ __volatile__ ( \ - "\n1:\tst2 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ - "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)\n" \ + asm volatile ( \ + "\n"_LL"\tst2 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ + "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)\n" \ + _LL \ : "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err)) #define __put_user_8(x,addr) \ - __asm__ __volatile__ ( \ - "\n1:\tst1 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ - "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)\n" \ + asm volatile ( \ + "\n"_LL"\tst1 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ + "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)\n" \ + _LL \ : "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err)) /* @@ -215,7 +232,7 @@ extern unsigned long __copy_user (void *to, const void *from, unsigned long count); #define __copy_to_user(to,from,n) __copy_user((to), (from), (n)) -#define __copy_from_user(to,from,n) __copy_user((to), (from), (n)) +#define __copy_from_user(to,from,n) __copy_user((to), (from), (n)) #define copy_to_user(to,from,n) __copy_tofrom_user((to), (from), (n), 1) #define copy_from_user(to,from,n) __copy_tofrom_user((to), (from), (n), 0) @@ -293,10 +310,14 @@ struct exception_table_entry { int addr; /* gp-relative address of insn this fixup is for */ - int skip; /* number of bytes to skip to get to the continuation point. - Bit 0 tells us if r9 should be cleared to 0*/ + int cont; /* gp-relative continuation address; if bit 2 is set, r9 is set to 0 */ +}; + +struct exception_fixup { + unsigned long cont; /* continuation point (bit 2: clear r9 if set) */ }; -extern const struct exception_table_entry *search_exception_table (unsigned long addr); +extern struct exception_fixup search_exception_table (unsigned long addr); +extern void handle_exception (struct pt_regs *regs, struct exception_fixup fixup); #endif /* _ASM_IA64_UACCESS_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/ucontext.h linux.ac/include/asm-ia64/ucontext.h --- linux.vanilla/include/asm-ia64/ucontext.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-ia64/ucontext.h Tue Apr 10 18:22:37 2001 @@ -0,0 +1,12 @@ +#ifndef _ASM_IA64_UCONTEXT_H +#define _ASM_IA64_UCONTEXT_H + +struct ucontext { + struct sigcontext uc_mcontext; +}; + +#define uc_link uc_mcontext.sc_gr[0] /* wrong type; nobody cares */ +#define uc_sigmask uc_mcontext.sc_sigmask +#define uc_stack uc_mcontext.sc_stack + +#endif /* _ASM_IA64_UCONTEXT_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ia64/unwind.h linux.ac/include/asm-ia64/unwind.h --- linux.vanilla/include/asm-ia64/unwind.h Tue Oct 10 01:55:01 2000 +++ linux.ac/include/asm-ia64/unwind.h Tue Apr 10 18:22:37 2001 @@ -109,22 +109,6 @@ struct switch_stack *sw); /* - * Prepare to unwind the current task. For this to work, the kernel - * stack identified by REGS must look like this: - * - * // // - * | | - * | kernel stack | - * | | - * +=====================+ - * | struct pt_regs | - * +---------------------+ <--- REGS - * | struct switch_stack | - * +---------------------+ - */ -extern void unw_init_from_current (struct unw_frame_info *info, struct pt_regs *regs); - -/* * Prepare to unwind the currently running thread. */ extern void unw_init_running (void (*callback)(struct unw_frame_info *info, void *arg), void *arg); @@ -144,42 +128,42 @@ #define unw_is_intr_frame(info) (((info)->flags & UNW_FLAG_INTERRUPT_FRAME) != 0) -static inline unsigned long +static inline int unw_get_ip (struct unw_frame_info *info, unsigned long *valp) { *valp = (info)->ip; return 0; } -static inline unsigned long +static inline int unw_get_sp (struct unw_frame_info *info, unsigned long *valp) { *valp = (info)->sp; return 0; } -static inline unsigned long +static inline int unw_get_psp (struct unw_frame_info *info, unsigned long *valp) { *valp = (info)->psp; return 0; } -static inline unsigned long +static inline int unw_get_bsp (struct unw_frame_info *info, unsigned long *valp) { *valp = (info)->bsp; return 0; } -static inline unsigned long +static inline int unw_get_cfm (struct unw_frame_info *info, unsigned long *valp) { *valp = *(info)->cfm_loc; return 0; } -static inline unsigned long +static inline int unw_set_cfm (struct unw_frame_info *info, unsigned long val) { *(info)->cfm_loc = val; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-m68k/bootinfo.h linux.ac/include/asm-m68k/bootinfo.h --- linux.vanilla/include/asm-m68k/bootinfo.h Wed Jan 26 20:44:21 2000 +++ linux.ac/include/asm-m68k/bootinfo.h Tue Apr 3 17:55:15 2001 @@ -163,7 +163,7 @@ #define BI_MAC_SCCTYPE 0x801c /* Mac SCC serial type (normal, IOP) */ #define BI_MAC_ETHTYPE 0x801d /* Mac builtin ethernet type (Sonic, MACE */ #define BI_MAC_ETHBASE 0x801e /* Mac builtin ethernet base address */ -#define BI_MAC_PMU 0x801f /* Mac power managment / poweroff hardware */ +#define BI_MAC_PMU 0x801f /* Mac power management / poweroff hardware */ #define BI_MAC_IOP_SWIM 0x8020 /* Mac SWIM floppy IOP */ #define BI_MAC_IOP_ADB 0x8021 /* Mac ADB IOP */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-m68k/ioctls.h linux.ac/include/asm-m68k/ioctls.h --- linux.vanilla/include/asm-m68k/ioctls.h Fri Feb 13 00:25:04 1998 +++ linux.ac/include/asm-m68k/ioctls.h Tue Apr 3 17:55:15 2001 @@ -65,6 +65,7 @@ #define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define FIOQSIZE 0x545E /* Used for packet mode */ #define TIOCPKT_DATA 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-m68k/linux_logo.h linux.ac/include/asm-m68k/linux_logo.h --- linux.vanilla/include/asm-m68k/linux_logo.h Mon Oct 5 21:54:39 1998 +++ linux.ac/include/asm-m68k/linux_logo.h Tue Apr 3 17:55:15 2001 @@ -900,9 +900,6 @@ extern unsigned char linux_logo_blue[]; extern unsigned char linux_logo[]; extern unsigned char linux_logo_bw[]; -extern unsigned char linux_logo16_red[]; -extern unsigned char linux_logo16_green[]; -extern unsigned char linux_logo16_blue[]; extern unsigned char linux_logo16[]; #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-m68k/mac_iop.h linux.ac/include/asm-m68k/mac_iop.h --- linux.vanilla/include/asm-m68k/mac_iop.h Sat Sep 4 21:06:41 1999 +++ linux.ac/include/asm-m68k/mac_iop.h Tue Apr 3 17:55:15 2001 @@ -54,7 +54,7 @@ #define IOP_MSGSTATUS_COMPLETE 3 /* message complete and reply rcvd */ #define IOP_MSGSTATUS_UNSOL 6 /* message is unsolicited */ -/* IOP memory addresses of the members of the the mac_iop_kernel structure. */ +/* IOP memory addresses of the members of the mac_iop_kernel structure. */ #define IOP_ADDR_MAX_SEND_CHAN 0x0200 #define IOP_ADDR_SEND_STATE 0x0201 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-m68k/serial.h linux.ac/include/asm-m68k/serial.h --- linux.vanilla/include/asm-m68k/serial.h Thu Jan 4 21:00:55 2001 +++ linux.ac/include/asm-m68k/serial.h Tue Apr 3 17:55:15 2001 @@ -1,7 +1,7 @@ /* * include/asm-m68k/serial.h * - * currently this seems usefull only for a Q40, + * currently this seems useful only for a Q40, * its an almost exact copy of ../asm/alpha/serial.h * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-m68k/tlb.h linux.ac/include/asm-m68k/tlb.h --- linux.vanilla/include/asm-m68k/tlb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-m68k/tlb.h Tue Apr 3 17:55:15 2001 @@ -0,0 +1 @@ +#include <asm-generic/tlb.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/bootinfo.h linux.ac/include/asm-mips/bootinfo.h --- linux.vanilla/include/asm-mips/bootinfo.h Tue Jul 11 19:15:02 2000 +++ linux.ac/include/asm-mips/bootinfo.h Tue Apr 3 17:55:15 2001 @@ -1,16 +1,13 @@ -/* $Id: bootinfo.h,v 1.11 2000/03/06 11:14:32 raiko Exp $ - * - * bootinfo.h -- Definition of the Linux/MIPS boot information structure - * - * Copyright (C) 1995, 1996 by Ralf Baechle, Andreas Busse, - * Stoned Elipot and Paul M. Antoine. - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive * for more details. + * + * Copyright (C) 1995, 1996 by Ralf Baechle, Andreas Busse, + * Stoned Elipot and Paul M. Antoine. */ -#ifndef __ASM_MIPS_BOOTINFO_H -#define __ASM_MIPS_BOOTINFO_H +#ifndef _ASM_BOOTINFO_H +#define _ASM_BOOTINFO_H /* * Values for machgroup @@ -105,8 +102,9 @@ * Valid machtype for group NEC DDB */ #define MACH_NEC_DDB5074 0 /* NEC DDB Vrc-5074 */ +#define MACH_NEC_DDB5476 1 /* NEC DDB Vrc-5476 */ -#define GROUP_NEC_DDB_NAMES { "Vrc-5074" } +#define GROUP_NEC_DDB_NAMES { "Vrc-5074", "Vrc-5476"} /* * Valid machtype for group BAGET diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/ioctls.h linux.ac/include/asm-mips/ioctls.h --- linux.vanilla/include/asm-mips/ioctls.h Sat May 13 16:31:25 2000 +++ linux.ac/include/asm-mips/ioctls.h Tue Apr 3 17:55:15 2001 @@ -58,6 +58,7 @@ #define FIONCLEX 0x6602 /* these numbers need to be adjusted. */ #define FIOASYNC 0x667d #define FIONBIO 0x667e +#define FIOQSIZE 0x667f #if defined(__USE_MISC) || defined (__KERNEL__) #define TIOCGLTC (tIOC | 116) /* get special local chars */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/it8172/it8172.h linux.ac/include/asm-mips/it8172/it8172.h --- linux.vanilla/include/asm-mips/it8172/it8172.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-mips/it8172/it8172.h Tue Apr 3 17:55:15 2001 @@ -0,0 +1,406 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * IT8172 system controller defines. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.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. + * + * 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. + * + * 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 __IT8172__H__ +#define __IT8172__H__ + +#include <asm/addrspace.h> + +#define IT8172_BASE 0x18000000 +#define IT8172_PCI_IO_BASE 0x14000000 +#define IT8172_PCI_MEM_BASE 0x10000000 + +// System registers offsets from IT8172_BASE +#define IT_CMFPCR 0x0 +#define IT_DSRR 0x2 +#define IT_PCDCR 0x4 +#define IT_SPLLCR 0x6 +#define IT_CIDR 0x10 +#define IT_CRNR 0x12 +#define IT_CPUTR 0x14 +#define IT_CTCR 0x16 +#define IT_SDPR 0xF0 + +// Power management register offset from IT8172_PCI_IO_BASE +// Power Management Device Standby Register +#define IT_PM_DSR 0x15800 + +#define IT_PM_DSR_TMR0SB 0x0001 +#define IT_PM_DSR_TMR1SB 0x0002 +#define IT_PM_DSR_CIR0SB 0x0004 +#define IT_PM_DSR_CIR1SB 0x0008 +#define IT_PM_DSR_SCR0SB 0x0010 +#define IT_PM_DSR_SCR1SB 0x0020 +#define IT_PM_DSR_PPSB 0x0040 +#define IT_PM_DSR_I2CSB 0x0080 +#define IT_PM_DSR_UARTSB 0x0100 +#define IT_PM_DSR_IDESB 0x0200 +#define IT_PM_DSR_ACSB 0x0400 +#define IT_PM_DSR_M68KSB 0x0800 + +// Power Management PCI Device Software Reset Register +#define IT_PM_PCISR 0x15802 + +#define IT_PM_PCISR_IDESR 0x0001 +#define IT_PM_PCISR_CDMASR 0x0002 +#define IT_PM_PCISR_USBSR 0x0004 +#define IT_PM_PCISR_DMASR 0x0008 +#define IT_PM_PCISR_ACSR 0x0010 +#define IT_PM_PCISR_MEMSR 0x0020 +#define IT_PM_PCISR_68KSR 0x0040 + + +// PCI Configuration address and data register offsets +// from IT8172_BASE +#define IT_CONFADDR 0x4000 +#define IT_BUSNUM_SHF 16 +#define IT_DEVNUM_SHF 11 +#define IT_FUNCNUM_SHF 8 +#define IT_REGNUM_SHF 2 + +#define IT_CONFDATA 0x4004 + +// PCI configuration header common register offsets +#define IT_VID 0x00 +#define IT_DID 0x02 +#define IT_PCICMD 0x04 +#define IT_PCISTS 0x06 +#define IT_RID 0x08 +#define IT_CLASSC 0x09 +#define IT_HEADT 0x0E +#define IT_SERIRQC 0x49 + +// PCI to Internal/LPC Bus Bridge configuration header register offset +#define IT_P2I_BCR 0x4C +#define IT_P2I_D0IOSC 0x50 +#define IT_P2I_D1IOSC 0x54 +#define IT_P2I_D2IOSC 0x58 +#define IT_P2I_D3IOSC 0x5C +#define IT_P2I_D4IOSC 0x60 +#define IT_P2I_D5IOSC 0x64 +#define IT_P2I_D6IOSC 0x68 +#define IT_P2I_D7IOSC 0x6C +#define IT_P2I_D8IOSC 0x70 +#define IT_P2I_D9IOSC 0x74 +#define IT_P2I_D10IOSC 0x78 +#define IT_P2I_D11IOSC 0x7C + +// Memory controller register offsets from IT8172_BASE +#define IT_MC_SDRMR 0x1000 +#define IT_MC_SDRTR 0x1004 +#define IT_MC_MCR 0x1008 +#define IT_MC_SDTYPE 0x100C +#define IT_MC_WPBA 0x1010 +#define IT_MC_WPTA 0x1014 +#define IT_MC_HATR 0x1018 +#define IT_MC_PCICR 0x101C + +// Flash/ROM control register offsets from IT8172_BASE +#define IT_FC_BRCR 0x2000 +#define IT_FC_FCR 0x2004 +#define IT_FC_DCR 0x2008 + +// M68K interface bridge configuration header register offset +#define IT_M68K_MBCSR 0x54 +#define IT_M68K_TMR 0x58 +#define IT_M68K_BCR 0x5C +#define IT_M68K_BSR 0x5D +#define IT_M68K_DTR 0x5F + +// Register offset from IT8172_PCI_IO_BASE +// These registers are accessible through 8172 PCI IO window. + +// INTC +#define IT_INTC_BASE 0x10000 +#define IT_INTC_LBDNIRR 0x10000 +#define IT_INTC_LBDNIMR 0x10002 +#define IT_INTC_LBDNITR 0x10004 +#define IT_INTC_LBDNIAR 0x10006 +#define IT_INTC_LPCNIRR 0x10010 +#define IT_INTC_LPCNIMR 0x10012 +#define IT_INTC_LPCNITR 0x10014 +#define IT_INTC_LPCNIAR 0x10016 +#define IT_INTC_PDNIRR 0x10020 +#define IT_INTC_PDNIMR 0x10022 +#define IT_INTC_PDNITR 0x10024 +#define IT_INTC_PDNIAR 0x10026 +#define IT_INTC_UMNIRR 0x10030 +#define IT_INTC_UMNITR 0x10034 +#define IT_INTC_UMNIAR 0x10036 +#define IT_INTC_TYPER 0x107FE + +// IT8172 PCI device number +#define IT_C2P_DEVICE 0 +#define IT_AUDIO_DEVICE 1 +#define IT_DMAC_DEVICE 1 +#define IT_CDMAC_DEVICE 1 +#define IT_USB_DEVICE 1 +#define IT_P2I_DEVICE 1 +#define IT_IDE_DEVICE 1 +#define IT_M68K_DEVICE 1 + +// IT8172 PCI function number +#define IT_C2P_FUNCION 0 +#define IT_AUDIO_FUNCTION 0 +#define IT_DMAC_FUNCTION 1 +#define IT_CDMAC_FUNCTION 2 +#define IT_USB_FUNCTION 3 +#define IT_P2I_FUNCTION 4 +#define IT_IDE_FUNCTION 5 +#define IT_M68K_FUNCTION 6 + +// IT8172 GPIO +#define IT_GPADR 0x13800 +#define IT_GPBDR 0x13808 +#define IT_GPCDR 0x13810 +#define IT_GPACR 0x13802 +#define IT_GPBCR 0x1380A +#define IT_GPCCR 0x13812 +#define IT_GPAICR 0x13804 +#define IT_GPBICR 0x1380C +#define IT_GPCICR 0x13814 +#define IT_GPAISR 0x13806 +#define IT_GPBISR 0x1380E +#define IT_GPCISR 0x13816 +#define IT_GCR 0x13818 + +// IT8172 RTC +#define IT_RTC_BASE 0x14800 +#define IT_RTC_RIR0 0x00 +#define IT_RTC_RTR0 0x01 +#define IT_RTC_RIR1 0x02 +#define IT_RTC_RTR1 0x03 +#define IT_RTC_RIR2 0x04 +#define IT_RTC_RTR2 0x05 +#define IT_RTC_RCTR 0x08 +#define IT_RTC_RA 0x0A +#define IT_RTC_RB 0x0B +#define IT_RTC_RC 0x0C +#define IT_RTC_RD 0x0D + +#define RTC_SEC_INDEX 0x00 +#define RTC_MIN_INDEX 0x02 +#define RTC_HOUR_INDEX 0x04 +#define RTC_DAY_INDEX 0x06 +#define RTC_DATE_INDEX 0x07 +#define RTC_MONTH_INDEX 0x08 +#define RTC_YEAR_INDEX 0x09 + +// IT8172 internal device registers +#define IT_TIMER_BASE 0x10800 +#define IT_CIR0_BASE 0x11000 +#define IT_UART_BASE 0x11800 +#define IT_SCR0_BASE 0x12000 +#define IT_SCR1_BASE 0x12800 +#define IT_PP_BASE 0x13000 +#define IT_I2C_BASE 0x14000 +#define IT_CIR1_BASE 0x15000 + +// IT8172 Smart Card Reader offsets from IT_SCR*_BASE +#define IT_SCR_SFR 0x08 +#define IT_SCR_SCDR 0x09 + +// IT8172 IT_SCR_SFR bit definition & mask +#define IT_SCR_SFR_GATE_UART 0x40 +#define IT_SCR_SFR_GATE_UART_BIT 6 +#define IT_SCR_SFR_GATE_UART_OFF 0 +#define IT_SCR_SFR_GATE_UART_ON 1 +#define IT_SCR_SFR_FET_CHARGE 0x30 +#define IT_SCR_SFR_FET_CHARGE_BIT 4 +#define IT_SCR_SFR_FET_CHARGE_3_3_US 3 +#define IT_SCR_SFR_FET_CHARGE_13_US 2 +#define IT_SCR_SFR_FET_CHARGE_53_US 1 +#define IT_SCR_SFR_FET_CHARGE_213_US 0 +#define IT_SCR_SFR_CARD_FREQ 0x0C +#define IT_SCR_SFR_CARD_FREQ_BIT 2 +#define IT_SCR_SFR_CARD_FREQ_STOP 3 +#define IT_SCR_SFR_CARD_FREQ_3_5_MHZ 0 +#define IT_SCR_SFR_CARD_FREQ_7_1_MHZ 2 +#define IT_SCR_SFR_CARD_FREQ_96_DIV_MHZ 1 +#define IT_SCR_SFR_FET_ACTIVE 0x02 +#define IT_SCR_SFR_FET_ACTIVE_BIT 1 +#define IT_SCR_SFR_FET_ACTIVE_INVERT 0 +#define IT_SCR_SFR_FET_ACTIVE_NONINVERT 1 +#define IT_SCR_SFR_ENABLE 0x01 +#define IT_SCR_SFR_ENABLE_BIT 0 +#define IT_SCR_SFR_ENABLE_OFF 0 +#define IT_SCR_SFR_ENABLE_ON 1 + +// IT8172 IT_SCR_SCDR bit definition & mask +#define IT_SCR_SCDR_RESET_MODE 0x80 +#define IT_SCR_SCDR_RESET_MODE_BIT 7 +#define IT_SCR_SCDR_RESET_MODE_ASYNC 0 +#define IT_SCR_SCDR_RESET_MODE_SYNC 1 +#define IT_SCR_SCDR_DIVISOR 0x7F +#define IT_SCR_SCDR_DIVISOR_BIT 0 +#define IT_SCR_SCDR_DIVISOR_STOP_VAL_1 0x00 +#define IT_SCR_SCDR_DIVISOR_STOP_VAL_2 0x01 +#define IT_SCR_SCDR_DIVISOR_STOP_VAL_3 0x7F + +// IT8172 DMA +#define IT_DMAC_BASE 0x16000 +#define IT_DMAC_BCAR0 0x00 +#define IT_DMAC_BCAR1 0x04 +#define IT_DMAC_BCAR2 0x08 +#define IT_DMAC_BCAR3 0x0C +#define IT_DMAC_BCCR0 0x02 +#define IT_DMAC_BCCR1 0x06 +#define IT_DMAC_BCCR2 0x0a +#define IT_DMAC_BCCR3 0x0e +#define IT_DMAC_CR 0x10 +#define IT_DMAC_SR 0x12 +#define IT_DMAC_ESR 0x13 +#define IT_DMAC_RQR 0x14 +#define IT_DMAC_MR 0x16 +#define IT_DMAC_EMR 0x17 +#define IT_DMAC_MKR 0x18 +#define IT_DMAC_PAR0 0x20 +#define IT_DMAC_PAR1 0x22 +#define IT_DMAC_PAR2 0x24 +#define IT_DMAC_PAR3 0x26 + +// IT8172 IDE +#define IT_IDE_BASE 0x17800 +#define IT_IDE_STATUS 0x1F7 + +// IT8172 Audio Controller +#define IT_AC_BASE 0x17000 +#define IT_AC_PCMOV 0x00 +#define IT_AC_FMOV 0x02 +#define IT_AC_I2SV 0x04 +#define IT_AC_DRSS 0x06 +#define IT_AC_PCC 0x08 +#define IT_AC_PCDL 0x0A +#define IT_AC_PCB1STA 0x0C +#define IT_AC_PCB2STA 0x10 +#define IT_AC_CAPCC 0x14 +#define IT_AC_CAPCDL 0x16 +#define IT_AC_CAPB1STA 0x18 +#define IT_AC_CAPB2STA 0x1C +#define IT_AC_CODECC 0x22 +#define IT_AC_I2SMC 0x24 +#define IT_AC_VS 0x26 +#define IT_AC_SRCS 0x28 +#define IT_AC_CIRCP 0x2A +#define IT_AC_CIRDP 0x2C +#define IT_AC_TM 0x4A +#define IT_AC_PFDP 0x4C +#define IT_AC_GC 0x54 +#define IT_AC_IMC 0x56 +#define IT_AC_ISC 0x5B +#define IT_AC_OPL3SR 0x68 +#define IT_AC_OPL3DWDR 0x69 +#define IT_AC_OPL3AB1W 0x6A +#define IT_AC_OPL3DW 0x6B +#define IT_AC_BPDC 0x70 + +// Audio : IT_AC_PCC bit definition & mask +#define PCC_SM 0x8000 +#define PCC_SM_BIT 15 +#define PCC_SM_STEREO 1 +#define PCC_SM_MONO 0 + +#define PCC_DF 0x4000 +#define PCC_DF_BIT 14 +#define PCC_DF_8 0 +#define PCC_DF_16 1 + +#define PCC_CF 0x3000 +#define PCC_CF_BIT 12 +#define PCC_CF_2 0 +#define PCC_CF_4 1 +#define PCC_CF_6 2 + +#define PCC_SR 0x0F00 +#define PCC_SR_BIT 8 +#define PCC_SR_5500 0 +#define PCC_SR_8000 1 +#define PCC_SR_9600 2 +#define PCC_SR_11025 3 +#define PCC_SR_16000 4 +#define PCC_SR_19200 5 +#define PCC_SR_22050 6 +#define PCC_SR_32000 7 +#define PCC_SR_38400 8 +#define PCC_SR_44100 9 +#define PCC_SR_48000 10 + +#define PCC_CSP 0x0080 +#define PCC_CSP_BIT 7 +#define PCC_CSP_STOP 0 +#define PCC_CSP_STOP_NOW 1 + +#define PCC_CP 0x0040 +#define PCC_CP_BIT 6 +#define PCC_CP_NORMAL 0 +#define PCC_CP_PAUSE 1 + +#define PCC_CA 0x0020 +#define PCC_CA_BIT 5 +#define PCC_CA_NO_START 0 +#define PCC_CA_START 1 + +#define PCC_CB2L 0x0004 +#define PCC_CB2L_BIT 2 +#define PCC_CB2L_NO 0 +#define PCC_CB2L_YES 1 + +#define PCC_CB1L 0x0002 +#define PCC_CB1L_BIT 1 +#define PCC_CB1L_NO 0 +#define PCC_CB1L_YES 1 + +#define PCC_DE 0x0001 +#define PCC_DE_BIT 0 +#define PCC_DE_NOT_EMPTY 0 +#define PCC_DE_EMPTY 1 + +// IT8172 Timer +#define IT_TIMER_BASE 0x10800 +#define TIMER_TCVR0 0x00 +#define TIMER_TRVR0 0x02 +#define TIMER_TCR0 0x04 +#define TIMER_TIRR 0x06 +#define TIMER_TCVR1 0x08 +#define TIMER_TRVR1 0x0A +#define TIMER_TCR1 0x0C +#define TIMER_TIDR 0x0E + + +#define IT_WRITE(ofs, data) *(volatile u32 *)KSEG1ADDR((IT8172_BASE+ofs)) = data +#define IT_READ(ofs, data) data = *(volatile u32 *)KSEG1ADDR((IT8172_BASE+ofs)) + +#define IT_IO_WRITE(ofs, data) *(volatile u32 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) = data +#define IT_IO_READ(ofs, data) data = *(volatile u32 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) + +#define IT_IO_WRITE16(ofs, data) *(volatile u16 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) = data +#define IT_IO_READ16(ofs, data) data = *(volatile u16 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/it8172/it8172_cir.h linux.ac/include/asm-mips/it8172/it8172_cir.h --- linux.vanilla/include/asm-mips/it8172/it8172_cir.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-mips/it8172/it8172_cir.h Tue Apr 3 17:55:15 2001 @@ -0,0 +1,140 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * IT8172 Consumer IR port defines. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.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. + * + * 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. + * + * 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 NUM_CIR_PORTS 2 + +/* Master Control Register */ +#define CIR_RESET 0x1 +#define CIR_FIFO_CLEAR 0x2 +#define CIR_SET_FIFO_TL(x) (((x)&0x3)<<2) +#define CIR_ILE 0x10 +#define CIR_ILSEL 0x20 + +/* Interrupt Enable Register */ +#define CIR_TLDLIE 0x1 +#define CIR_RDAIE 0x2 +#define CIR_RFOIE 0x4 +#define CIR_IEC 0x80 + +/* Interrupt Identification Register */ +#define CIR_TLDLI 0x1 +#define CIR_RDAI 0x2 +#define CIR_RFOI 0x4 +#define CIR_NIP 0x80 + +/* Carrier Frequency Register */ +#define CIR_SET_CF(x) ((x)&0x1f) + #define CFQ_38_480 0xB /* 38 KHz low, 480 KHz high */ +#define CIR_HCFS 0x20 + #define CIR_SET_HS(x) (((x)&0x1)<<5) + + +/* Receiver Control Register */ +#define CIR_SET_RXDCR(x) ((x)&0x7) +#define CIR_RXACT 0x8 +#define CIR_RXEND 0x10 +#define CIR_RDWOS 0x20 + #define CIR_SET_RDWOS(x) (((x)&0x1)<<5) +#define CIR_RXEN 0x80 + +/* Transmitter Control Register */ +#define CIR_SET_TXMPW(x) ((x)&0x7) +#define CIR_SET_TXMPM(x) (((x)&0x3)<<3) +#define CIR_TXENDF 0x20 +#define CIR_TXRLE 0x40 + +/* Receiver FIFO Status Register */ +#define CIR_RXFBC_MASK 0x3f +#define CIR_RXFTO 0x80 + +/* Wakeup Code Length Register */ +#define CIR_SET_WCL ((x)&0x3f) +#define CIR_WCL_MASK(x) ((x)&0x3f) + +/* Wakeup Power Control/Status Register */ +#define CIR_BTMON 0x2 +#define CIR_CIRON 0x4 +#define CIR_RCRST 0x10 +#define CIR_WCRST 0x20 + +struct cir_port { + int port; + unsigned short baud_rate; + unsigned char fifo_tl; + unsigned char cfq; + unsigned char hcfs; + unsigned char rdwos; + unsigned char rxdcr; +}; + +struct it8172_cir_regs { + unsigned char dr; /* data */ + char pad; + unsigned char mstcr; /* master control */ + char pad1; + unsigned char ier; /* interrupt enable */ + char pad2; + unsigned char iir; /* interrupt identification */ + char pad3; + unsigned char cfr; /* carrier frequency */ + char pad4; + unsigned char rcr; /* receiver control */ + char pad5; + unsigned char tcr; /* transmitter control */ + char pad6; + char pad7; + char pad8; + unsigned char bdlr; /* baud rate divisor low byte */ + char pad9; + unsigned char bdhr; /* baud rate divisor high byte */ + char pad10; + unsigned char tfsr; /* tx fifo byte count */ + char pad11; + unsigned char rfsr; /* rx fifo status */ + char pad12; + unsigned char wcl; /* wakeup code length */ + char pad13; + unsigned char wcr; /* wakeup code read/write */ + char pad14; + unsigned char wps; /* wakeup power control/status */ +}; + +int cir_port_init(struct cir_port *cir); +extern void clear_fifo(struct cir_port *cir); +extern void enable_receiver(struct cir_port *cir); +extern void disable_receiver(struct cir_port *cir); +extern void enable_rx_demodulation(struct cir_port *cir); +extern void disable_rx_demodulation(struct cir_port *cir); +extern void set_rx_active(struct cir_port *cir); +extern void int_enable(struct cir_port *cir); +extern void rx_int_enable(struct cir_port *cir); +extern char get_int_status(struct cir_port *cir); +extern int cir_get_rx_count(struct cir_port *cir); +extern char cir_read_data(struct cir_port *cir); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/it8172/it8172_dbg.h linux.ac/include/asm-mips/it8172/it8172_dbg.h --- linux.vanilla/include/asm-mips/it8172/it8172_dbg.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-mips/it8172/it8172_dbg.h Tue Apr 3 17:55:15 2001 @@ -0,0 +1,38 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Function prototypes for low level uart routines to + * directly access a 16550 uart. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.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. + * + * 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. + * + * 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 <linux/types.h> + +extern void putch(const unsigned char c); +extern void puts(unsigned char *cp); +extern void fputs(unsigned char *cp); +extern void put64(uint64_t ul); +extern void put32(unsigned u); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/it8172/it8172_int.h linux.ac/include/asm-mips/it8172/it8172_int.h --- linux.vanilla/include/asm-mips/it8172/it8172_int.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-mips/it8172/it8172_int.h Tue Apr 3 17:55:15 2001 @@ -0,0 +1,146 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * ITE 8172 Interrupt Numbering + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.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. + * + * 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. + * + * 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 _MIPS_ITEINT_H +#define _MIPS_ITEINT_H + +/* + * Here's the "strategy": + * We number the LPC serial irqs from 0 to 15, + * the local bus irqs from 16 to 31, + * the pci dev register interrupts from 32 to 47, + * and the non-maskable ints from 48 to 53. + */ + +#define IT8172_LPC_IRQ_BASE 0 /* first LPC int number */ +#define IT8172_SERIRQ_0 (IT8172_LPC_IRQ_BASE + 0) +#define IT8172_SERIRQ_1 (IT8172_LPC_IRQ_BASE + 1) +#define IT8172_SERIRQ_2 (IT8172_LPC_IRQ_BASE + 2) +#define IT8172_SERIRQ_3 (IT8172_LPC_IRQ_BASE + 3) +#define IT8172_SERIRQ_4 (IT8172_LPC_IRQ_BASE + 4) +#define IT8172_SERIRQ_5 (IT8172_LPC_IRQ_BASE + 5) +#define IT8172_SERIRQ_6 (IT8172_LPC_IRQ_BASE + 6) +#define IT8172_SERIRQ_7 (IT8172_LPC_IRQ_BASE + 7) +#define IT8172_SERIRQ_8 (IT8172_LPC_IRQ_BASE + 8) +#define IT8172_SERIRQ_9 (IT8172_LPC_IRQ_BASE + 9) +#define IT8172_SERIRQ_10 (IT8172_LPC_IRQ_BASE + 10) +#define IT8172_SERIRQ_11 (IT8172_LPC_IRQ_BASE + 11) +#define IT8172_SERIRQ_12 (IT8172_LPC_IRQ_BASE + 12) +#define IT8172_SERIRQ_13 (IT8172_LPC_IRQ_BASE + 13) +#define IT8172_SERIRQ_14 (IT8172_LPC_IRQ_BASE + 14) +#define IT8172_SERIRQ_15 (IT8172_LPC_IRQ_BASE + 15) + +#define IT8172_LB_IRQ_BASE 16 /* first local bus int number */ +#define IT8172_PPR_IRQ (IT8172_LB_IRQ_BASE + 0) /* parallel port */ +#define IT8172_TIMER0_IRQ (IT8172_LB_IRQ_BASE + 1) +#define IT8172_TIMER1_IRQ (IT8172_LB_IRQ_BASE + 2) +#define IT8172_I2C_IRQ (IT8172_LB_IRQ_BASE + 3) +#define IT8172_GPIO_IRQ (IT8172_LB_IRQ_BASE + 4) +#define IT8172_CIR0_IRQ (IT8172_LB_IRQ_BASE + 5) +#define IT8172_CIR1_IRQ (IT8172_LB_IRQ_BASE + 6) +#define IT8172_UART_IRQ (IT8172_LB_IRQ_BASE + 7) +#define IT8172_SCR0_IRQ (IT8172_LB_IRQ_BASE + 8) +#define IT8172_SCR1_IRQ (IT8172_LB_IRQ_BASE + 9) +#define IT8172_RTC_IRQ (IT8172_LB_IRQ_BASE + 10) +#define IT8172_IOCHK_IRQ (IT8172_LB_IRQ_BASE + 11) +/* 12 - 15 reserved */ + +/* + * Note here that the pci dev registers includes bits for more than + * just the pci devices. + */ +#define IT8172_PCI_DEV_IRQ_BASE 32 /* first pci dev irq */ +#define IT8172_AC97_IRQ (IT8172_PCI_DEV_IRQ_BASE + 0) +#define IT8172_MC68K_IRQ (IT8172_PCI_DEV_IRQ_BASE + 1) +#define IT8172_IDE_IRQ (IT8172_PCI_DEV_IRQ_BASE + 2) +#define IT8172_USB_IRQ (IT8172_PCI_DEV_IRQ_BASE + 3) +#define IT8172_BRIDGE_MASTER_IRQ (IT8172_PCI_DEV_IRQ_BASE + 4) +#define IT8172_BRIDGE_TARGET_IRQ (IT8172_PCI_DEV_IRQ_BASE + 5) +#define IT8172_PCI_INTA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 6) +#define IT8172_PCI_INTB_IRQ (IT8172_PCI_DEV_IRQ_BASE + 7) +#define IT8172_PCI_INTC_IRQ (IT8172_PCI_DEV_IRQ_BASE + 8) +#define IT8172_PCI_INTD_IRQ (IT8172_PCI_DEV_IRQ_BASE + 9) +#define IT8172_S_INTA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 10) +#define IT8172_S_INTB_IRQ (IT8172_PCI_DEV_IRQ_BASE + 11) +#define IT8172_S_INTC_IRQ (IT8172_PCI_DEV_IRQ_BASE + 12) +#define IT8172_S_INTD_IRQ (IT8172_PCI_DEV_IRQ_BASE + 13) +#define IT8172_CDMA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 14) +#define IT8172_DMA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 15) + +#define IT8172_NMI_IRQ_BASE 48 +#define IT8172_SER_NMI_IRQ (IT8172_NMI_IRQ_BASE + 0) +#define IT8172_PCI_NMI_IRQ (IT8172_NMI_IRQ_BASE + 1) +#define IT8172_RTC_NMI_IRQ (IT8172_NMI_IRQ_BASE + 2) +#define IT8172_CPUIF_NMI_IRQ (IT8172_NMI_IRQ_BASE + 3) +#define IT8172_PMER_NMI_IRQ (IT8172_NMI_IRQ_BASE + 4) +#define IT8172_POWER_NMI_IRQ (IT8172_NMI_IRQ_BASE + 5) + +/* Finally, let's move over here the mips cpu timer interrupt. + * This is more or less strictly for statistics. + */ +#define MIPS_CPU_TIMER_IRQ (IT8172_NMI_IRQ_BASE + 6) + +#define IT8172_INT_END MIPS_CPU_TIMER_IRQ + +/* + * IT8172 Interrupt Controller Registers + */ +struct it8172_intc_regs { + volatile unsigned short lb_req; /* offset 0 */ + volatile unsigned short lb_mask; + volatile unsigned short lb_trigger; + volatile unsigned short lb_level; + unsigned char pad0[8]; + + volatile unsigned short lpc_req; /* offset 0x10 */ + volatile unsigned short lpc_mask; + volatile unsigned short lpc_trigger; + volatile unsigned short lpc_level; + unsigned char pad1[8]; + + volatile unsigned short pci_req; /* offset 0x20 */ + volatile unsigned short pci_mask; + volatile unsigned short pci_trigger; + volatile unsigned short pci_level; + unsigned char pad2[8]; + + volatile unsigned short nmi_req; /* offset 0x30 */ + volatile unsigned short nmi_mask; + volatile unsigned short nmi_trigger; + volatile unsigned short nmi_level; + unsigned char pad3[6]; + + volatile unsigned short nmi_redir; /* offset 0x3E */ + unsigned char pad4[0xBE]; + + volatile unsigned short intstatus; /* offset 0xFE */ +}; + +#endif /* _MIPS_ITEINT_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/it8172/it8172_lpc.h linux.ac/include/asm-mips/it8172/it8172_lpc.h --- linux.vanilla/include/asm-mips/it8172/it8172_lpc.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-mips/it8172/it8172_lpc.h Tue Apr 3 17:55:15 2001 @@ -0,0 +1,29 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * IT8172 system controller defines. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.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. + * + * 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. + * + * 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. + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/it8172/it8172_pci.h linux.ac/include/asm-mips/it8172/it8172_pci.h --- linux.vanilla/include/asm-mips/it8172/it8172_pci.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-mips/it8172/it8172_pci.h Tue Apr 3 17:55:15 2001 @@ -0,0 +1,108 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * IT8172 system controller specific pci defines. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.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. + * + * 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. + * + * 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 _8172PCI_H_ +#define _8172PCI_H_ + +// PCI configuration space Type0 +#define PCI_IDREG 0x00 +#define PCI_CMDSTSREG 0x04 +#define PCI_CLASSREG 0x08 +#define PCI_BHLCREG 0x0C +#define PCI_BASE1REG 0x10 +#define PCI_BASE2REG 0x14 +#define PCI_BASE3REG 0x18 +#define PCI_BASE4REG 0x1C +#define PCI_BASE5REG 0x20 +#define PCI_BASE6REG 0x24 +#define PCI_ROMBASEREG 0x30 +#define PCI_INTRREG 0x3C + +// PCI configuration space Type1 +#define PCI_BUSNOREG 0x18 + +#define IT_PCI_VENDORID(x) ((x) & 0xFFFF) +#define IT_PCI_DEVICEID(x) (((x)>>16) & 0xFFFF) + +// Command register +#define PCI_CMD_IOEN 0x00000001 +#define PCI_CMD_MEMEN 0x00000002 +#define PCI_CMD_BUSMASTER 0x00000004 +#define PCI_CMD_SPCYCLE 0x00000008 +#define PCI_CMD_WRINV 0x00000010 +#define PCI_CMD_VGASNOOP 0x00000020 +#define PCI_CMD_PERR 0x00000040 +#define PCI_CMD_WAITCTRL 0x00000080 +#define PCI_CMD_SERR 0x00000100 +#define PCI_CMD_FAST_BACKTOBACK 0x00000200 + +// Status register +#define PCI_STS_66MHZ 0x00200000 +#define PCI_STS_SUPPORT_UDF 0x00400000 +#define PCI_STS_FAST_BACKTOBACK 0x00800000 +#define PCI_STS_DATA_PERR 0x01000000 +#define PCI_STS_DEVSEL0 0x02000000 +#define PCI_STS_DEVSEL1 0x04000000 +#define PCI_STS_SIG_TGTABORT 0x08000000 +#define PCI_STS_RCV_TGTABORT 0x10000000 +#define PCI_STS_RCV_MSTABORT 0x20000000 +#define PCI_STS_SYSERR 0x40000000 +#define PCI_STS_DETCT_PERR 0x80000000 + +#define IT_PCI_CLASS(x) (((x)>>24) & 0xFF) +#define IT_PCI_SUBCLASS(x) (((x)>>16) & 0xFF) +#define IT_PCI_INTERFACE(x) (((x)>>8) & 0xFF) +#define IT_PCI_REVISION(x) ((x) & 0xFF) + +// PCI class code +#define PCI_CLASS_BRIDGE 0x06 + +// bridge subclass +#define PCI_SUBCLASS_BRIDGE_HOST 0x00 +#define PCI_SUBCLASS_BRIDGE_PCI 0x04 + +// BHLCREG +#define IT_PCI_BIST(x) (((x)>>24) & 0xFF) +#define IT_PCI_HEADERTYPE(x) (((x)>>16) & 0xFF) +#define IT_PCI_LATENCYTIMER(x) (((x)>>8) & 0xFF) +#define IT_PCI_CACHELINESIZE(x) ((x) & 0xFF) + +#define PCI_MULTIFUNC 0x80 + +// INTRREG +#define IT_PCI_MAXLAT(x) (((x)>>24) & 0xFF) +#define IT_PCI_MINGNT(x) (((x)>>16) & 0xFF) +#define IT_PCI_INTRPIN(x) (((x)>>8) & 0xFF) +#define IT_PCI_INTRLINE(x) ((x) & 0xFF) + +#define PCI_VENDOR_NEC 0x1033 +#define PCI_VENDOR_DEC 0x1101 + +#endif // _8172PCI_H_ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/it8712.h linux.ac/include/asm-mips/it8712.h --- linux.vanilla/include/asm-mips/it8712.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-mips/it8712.h Tue Apr 3 17:55:15 2001 @@ -0,0 +1,28 @@ + +#ifndef __IT8712_H__ +#define __IT8712_H__ + +#define LPC_BASE_ADDR 0x14000000 + +// MB PnP configuration register +#define LPC_KEY_ADDR 0x1400002E +#define LPC_DATA_ADDR 0x1400002F + +// Device LDN +#define LDN_SERIAL1 0x01 +#define LDN_SERIAL2 0x02 +#define LDN_PARALLEL 0x03 +#define LDN_KEYBOARD 0x05 +#define LDN_MOUSE 0x06 + +#define IT8712_UART1_PORT 0x3F8 +#define IT8712_UART2_PORT 0x2F8 + +#ifndef ASM_ONLY + +void LPCSetConfig(char LdnNumber, char Index, char data); +char LPCGetConfig(char LdnNumber, char Index); + +#endif + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/keyboard.h linux.ac/include/asm-mips/keyboard.h --- linux.vanilla/include/asm-mips/keyboard.h Mon Jul 10 06:18:15 2000 +++ linux.ac/include/asm-mips/keyboard.h Tue Apr 3 17:55:15 2001 @@ -45,7 +45,7 @@ void (*kbd_request_region)(void); int (*kbd_request_irq)(void (*handler)(int, void *, struct pt_regs *)); - /* PSaux driver resource managment */ + /* PSaux driver resource management */ int (*aux_request_irq)(void (*handler)(int, void *, struct pt_regs *)); void (*aux_free_irq)(void); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/linux_logo.h linux.ac/include/asm-mips/linux_logo.h --- linux.vanilla/include/asm-mips/linux_logo.h Sat May 13 16:31:25 2000 +++ linux.ac/include/asm-mips/linux_logo.h Tue Apr 3 17:55:15 2001 @@ -933,9 +933,6 @@ extern unsigned char linux_logo_blue[]; extern unsigned char linux_logo[]; extern unsigned char linux_logo_bw[]; -extern unsigned char linux_logo16_red[]; -extern unsigned char linux_logo16_green[]; -extern unsigned char linux_logo16_blue[]; extern unsigned char linux_logo16[]; #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/mipsregs.h linux.ac/include/asm-mips/mipsregs.h --- linux.vanilla/include/asm-mips/mipsregs.h Mon Jul 10 06:18:15 2000 +++ linux.ac/include/asm-mips/mipsregs.h Tue Apr 3 17:55:15 2001 @@ -292,7 +292,7 @@ /* * Bitfields and bit numbers in the coprocessor 0 cause register. * - * Refer to to your MIPS R4xx0 manual, chapter 5 for explanation. + * Refer to your MIPS R4xx0 manual, chapter 5 for explanation. */ #define CAUSEB_EXCCODE 2 #define CAUSEF_EXCCODE (31 << 2) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/pci.h linux.ac/include/asm-mips/pci.h --- linux.vanilla/include/asm-mips/pci.h Thu Jun 22 15:17:16 2000 +++ linux.ac/include/asm-mips/pci.h Tue Apr 3 17:55:15 2001 @@ -40,7 +40,7 @@ #include <linux/string.h> #include <asm/io.h> -#ifdef CONFIG_DDB5074 +#if (defined(CONFIG_DDB5074) || defined(CONFIG_DDB5476)) #undef PCIBIOS_MIN_IO #undef PCIBIOS_MIN_MEM #define PCIBIOS_MIN_IO 0x0100000 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/processor.h linux.ac/include/asm-mips/processor.h --- linux.vanilla/include/asm-mips/processor.h Sat Dec 30 17:35:40 2000 +++ linux.ac/include/asm-mips/processor.h Tue Apr 3 17:55:15 2001 @@ -98,15 +98,20 @@ #define NUM_FPU_REGS 32 struct mips_fpu_hard_struct { - unsigned int fp_regs[NUM_FPU_REGS]; + double fp_regs[NUM_FPU_REGS]; unsigned int control; -} __attribute__((aligned(8))); +}; /* - * FIXME: no fpu emulator yet (but who cares anyway?) + * It would be nice to add some more fields for emulator statistics, but there + * are a number of fixed offsets in offset.h and elsewhere that would have to + * be recalculated by hand. So the additional information will be private to + * the FPU emulator for now. See asm-mips/fpu_emulator.h. */ +typedef u64 fpureg_t; struct mips_fpu_soft_struct { - long dummy; + fpureg_t regs[NUM_FPU_REGS]; + unsigned int sr; }; union mips_fpu_union { @@ -148,6 +153,21 @@ mm_segment_t current_ds; unsigned long irix_trampoline; /* Wheee... */ unsigned long irix_oldctx; + + /* + * These are really only needed if the full FPU emulator is configured. + * Would be made conditional on MIPS_FPU_EMULATOR if it weren't for the + * fact that having offset.h rebuilt differently for different config + * options would be asking for trouble. + * + * Saved EPC during delay-slot emulation (see math-emu/cp1emu.c) + */ + unsigned long dsemul_epc; + + /* + * Pointer to instruction used to induce address error + */ + unsigned long dsemul_aerpc; }; #endif /* !defined (_LANGUAGE_ASSEMBLY) */ @@ -176,7 +196,12 @@ /* \ * For now the default is to fix address errors \ */ \ - MF_FIXADE, { 0 }, 0, 0 \ + MF_FIXADE, { 0 }, 0, 0, \ + /* \ + * dsemul_epc and dsemul_aerpc should never be used uninitialized, \ + * but... \ + */ \ + 0 ,0 \ } #ifdef __KERNEL__ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/semaphore.h linux.ac/include/asm-mips/semaphore.h --- linux.vanilla/include/asm-mips/semaphore.h Sat May 13 16:31:25 2000 +++ linux.ac/include/asm-mips/semaphore.h Tue Apr 3 17:55:15 2001 @@ -215,7 +215,7 @@ atomic_t count; /* bit 0 means read bias granted; bit 1 means write bias granted. */ - unsigned granted; + unsigned long granted; /* pedant: long req'd for set_bit */ wait_queue_head_t wait; wait_queue_head_t write_bias_wait; #if WAITQUEUE_DEBUG diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/sgi/sgimc.h linux.ac/include/asm-mips/sgi/sgimc.h --- linux.vanilla/include/asm-mips/sgi/sgimc.h Sat May 13 16:31:25 2000 +++ linux.ac/include/asm-mips/sgi/sgimc.h Tue Apr 3 17:55:15 2001 @@ -200,7 +200,7 @@ u32 _unused7; volatile u32 dmamode; /* DMA mode config bit settings */ u32 _unused8; - volatile u32 dmacount; /* Zoom and byte count for DMA */ + volatile u32 dmaccount; /* Zoom and byte count for DMA */ u32 _unused9; volatile u32 dmastart; /* Pedal to the metal. */ u32 _unused10; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/shmiq.h linux.ac/include/asm-mips/shmiq.h --- linux.vanilla/include/asm-mips/shmiq.h Tue Dec 16 20:46:13 1997 +++ linux.ac/include/asm-mips/shmiq.h Tue Apr 3 17:55:15 2001 @@ -146,7 +146,7 @@ /* get time since last event */ #define QIOCGETITIME _IOR('Q', 11, time_t) -/* set curent screen */ +/* set current screen */ #define QIOCSETSCRN _IOW('Q',6,int) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/tlb.h linux.ac/include/asm-mips/tlb.h --- linux.vanilla/include/asm-mips/tlb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-mips/tlb.h Tue Apr 3 17:55:15 2001 @@ -0,0 +1 @@ +#include <asm-generic/tlb.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips64/errno.h linux.ac/include/asm-mips64/errno.h --- linux.vanilla/include/asm-mips64/errno.h Mon Feb 5 05:48:46 2001 +++ linux.ac/include/asm-mips64/errno.h Tue Apr 10 18:21:50 2001 @@ -142,7 +142,6 @@ */ #define ENOMEDIUM 159 /* No medium found */ #define EMEDIUMTYPE 160 /* Wrong medium type */ -#define EHASHCOLLISION 125 /* Number of hash collisons exceeds maximum generation counter value. */ #define EDQUOT 1133 /* Quota exceeded */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips64/ioctls.h linux.ac/include/asm-mips64/ioctls.h --- linux.vanilla/include/asm-mips64/ioctls.h Sat May 13 16:31:25 2000 +++ linux.ac/include/asm-mips64/ioctls.h Tue Apr 3 17:55:15 2001 @@ -58,6 +58,7 @@ #define FIONCLEX 0x6602 /* these numbers need to be adjusted. */ #define FIOASYNC 0x667d #define FIONBIO 0x667e +#define FIOQSIZE 0x667f #if defined(__USE_MISC) || defined (__KERNEL__) #define TIOCGLTC (tIOC | 116) /* get special local chars */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips64/keyboard.h linux.ac/include/asm-mips64/keyboard.h --- linux.vanilla/include/asm-mips64/keyboard.h Mon Feb 28 15:18:20 2000 +++ linux.ac/include/asm-mips64/keyboard.h Tue Apr 3 17:55:15 2001 @@ -44,7 +44,7 @@ void (*kbd_request_region)(void); int (*kbd_request_irq)(void (*handler)(int, void *, struct pt_regs *)); - /* PSaux driver resource managment */ + /* PSaux driver resource management */ int (*aux_request_irq)(void (*handler)(int, void *, struct pt_regs *)); void (*aux_free_irq)(void); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips64/linux_logo.h linux.ac/include/asm-mips64/linux_logo.h --- linux.vanilla/include/asm-mips64/linux_logo.h Sat May 13 16:31:25 2000 +++ linux.ac/include/asm-mips64/linux_logo.h Tue Apr 3 17:55:15 2001 @@ -933,9 +933,6 @@ extern unsigned char linux_logo_blue[]; extern unsigned char linux_logo[]; extern unsigned char linux_logo_bw[]; -extern unsigned char linux_logo16_red[]; -extern unsigned char linux_logo16_green[]; -extern unsigned char linux_logo16_blue[]; extern unsigned char linux_logo16[]; #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips64/mipsregs.h linux.ac/include/asm-mips64/mipsregs.h --- linux.vanilla/include/asm-mips64/mipsregs.h Wed Nov 29 05:42:04 2000 +++ linux.ac/include/asm-mips64/mipsregs.h Tue Apr 3 17:55:15 2001 @@ -216,7 +216,7 @@ /* * Bitfields and bit numbers in the coprocessor 0 cause register. * - * Refer to to your MIPS R4xx0 manual, chapter 5 for explanation. + * Refer to your MIPS R4xx0 manual, chapter 5 for explanation. */ #define CAUSEB_EXCCODE 2 #define CAUSEF_EXCCODE (31 << 2) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips64/mmzone.h linux.ac/include/asm-mips64/mmzone.h --- linux.vanilla/include/asm-mips64/mmzone.h Wed Aug 9 21:46:02 2000 +++ linux.ac/include/asm-mips64/mmzone.h Tue Apr 3 17:55:15 2001 @@ -58,7 +58,7 @@ /* * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory - * and returns the the mem_map of that node. + * and returns the mem_map of that node. */ #define ADDR_TO_MAPBASE(kaddr) \ NODE_MEM_MAP(KVADDR_TO_NID((unsigned long)(kaddr))) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips64/pci/bridge.h linux.ac/include/asm-mips64/pci/bridge.h --- linux.vanilla/include/asm-mips64/pci/bridge.h Sat May 13 16:31:25 2000 +++ linux.ac/include/asm-mips64/pci/bridge.h Tue Apr 3 17:55:15 2001 @@ -276,7 +276,7 @@ ds:2, /* Data size */ gbr:1, /* GBR enable */ vbpm:1, /* VBPM message */ - error:1, /* Error occured */ + error:1, /* Error occurred */ barr:1, /* Barrier op */ rsvd:8; } berr_st; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips64/semaphore.h linux.ac/include/asm-mips64/semaphore.h --- linux.vanilla/include/asm-mips64/semaphore.h Wed Nov 29 05:42:04 2000 +++ linux.ac/include/asm-mips64/semaphore.h Tue Apr 3 17:55:15 2001 @@ -195,7 +195,7 @@ atomic_t count; /* bit 0 means read bias granted; bit 1 means write bias granted. */ - unsigned long granted; + unsigned long granted; /* long req'd for set_bit --RR */ wait_queue_head_t wait; wait_queue_head_t write_bias_wait; #if WAITQUEUE_DEBUG diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips64/sgi/sgimc.h linux.ac/include/asm-mips64/sgi/sgimc.h --- linux.vanilla/include/asm-mips64/sgi/sgimc.h Sat May 13 16:31:25 2000 +++ linux.ac/include/asm-mips64/sgi/sgimc.h Tue Apr 3 17:55:15 2001 @@ -200,7 +200,7 @@ u32 _unused7; volatile u32 dmamode; /* DMA mode config bit settings */ u32 _unused8; - volatile u32 dmacount; /* Zoom and byte count for DMA */ + volatile u32 dmaccount; /* Zoom and byte count for DMA */ u32 _unused9; volatile u32 dmastart; /* Pedal to the metal. */ u32 _unused10; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips64/shmiq.h linux.ac/include/asm-mips64/shmiq.h --- linux.vanilla/include/asm-mips64/shmiq.h Sat May 13 16:31:25 2000 +++ linux.ac/include/asm-mips64/shmiq.h Tue Apr 3 17:55:15 2001 @@ -153,7 +153,7 @@ /* get time since last event */ #define QIOCGETITIME _IOR('Q', 11, time_t) -/* set curent screen */ +/* set current screen */ #define QIOCSETSCRN _IOW('Q',6,int) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips64/tlb.h linux.ac/include/asm-mips64/tlb.h --- linux.vanilla/include/asm-mips64/tlb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-mips64/tlb.h Tue Apr 3 17:55:15 2001 @@ -0,0 +1 @@ +#include <asm-generic/tlb.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/assembly.h linux.ac/include/asm-parisc/assembly.h --- linux.vanilla/include/asm-parisc/assembly.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/assembly.h Tue Apr 3 17:55:15 2001 @@ -339,7 +339,17 @@ mtctl %r0, %cr18 SAVE_CR (%cr18, PT_IAOQ1(\regs)) +#ifdef __LP64__ + /* cr11 (sar) is a funny one. 5 bits on PA1.1 and 6 bit on PA2.0 + * For PA2.0 mtsar or mtctl always write 6 bits, but mfctl only + * reads 5 bits. Use mfctl,w to read all six bits. Otherwise + * we loose the 6th bit on a save/restore over interrupt. + */ + mfctl,w %cr11, %r1 + STREG %r1, PT_SAR (\regs) +#else SAVE_CR (%cr11, PT_SAR (\regs)) +#endif SAVE_CR (%cr22, PT_PSW (\regs)) SAVE_CR (%cr19, PT_IIR (\regs)) SAVE_CR (%cr28, PT_GR1 (\regs)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/atomic.h linux.ac/include/asm-parisc/atomic.h --- linux.vanilla/include/asm-parisc/atomic.h Wed Dec 6 19:46:39 2000 +++ linux.ac/include/asm-parisc/atomic.h Tue Apr 3 17:55:15 2001 @@ -15,10 +15,12 @@ */ #ifdef CONFIG_SMP -/* we have an array of spinlocks for our atomic_ts, and a hash function - * to get the right index */ -# define ATOMIC_HASH_SIZE 1 -# define ATOMIC_HASH(a) (&__atomic_hash[0]) +/* Use an array of spinlocks for our atomic_ts. +** Hash function to index into a different SPINLOCK. +** Since "a" is usually an address, ">>8" makes one spinlock per 64-bytes. +*/ +# define ATOMIC_HASH_SIZE 4 +# define ATOMIC_HASH(a) (&__atomic_hash[(((unsigned long) a)>>8)&(ATOMIC_HASH_SIZE-1)]) extern spinlock_t __atomic_hash[ATOMIC_HASH_SIZE]; /* copied from <asm/spinlock.h> and modified */ @@ -44,12 +46,101 @@ /* Note that we need not lock read accesses - aligned word writes/reads * are atomic, so a reader never sees unconsistent values. * - * Cache-line alignment would conflict with, for example, linux/module.h */ + * Cache-line alignment would conflict with, for example, linux/module.h + */ typedef struct { volatile int counter; } atomic_t; + +/* +** xchg/cmpxchg moved from asm/system.h - ggg +*/ + +#if 1 +/* This should get optimized out since it's never called. +** Or get a link error if xchg is used "wrong". +*/ +extern void __xchg_called_with_bad_pointer(void); +#else +static inline void __xchg_called_with_bad_pointer(void) +{ + extern void panic(const char * fmt, ...); + panic("xchg called with bad pointer"); +} +#endif + +/* __xchg32/64 defined in arch/parisc/lib/bitops.c */ +extern unsigned long __xchg8(char, char *); +extern unsigned long __xchg32(int, int *); +#ifdef __LP64__ +extern unsigned long __xchg64(unsigned long, unsigned long *); +#endif + +/* optimizer better get rid of switch since size is a constant */ +static __inline__ unsigned long __xchg(unsigned long x, __volatile__ void * ptr, + int size) +{ + + switch(size) { +#ifdef __LP64__ + case 8: return __xchg64(x,(unsigned long *) ptr); +#endif + case 4: return __xchg32((int) x, (int *) ptr); + case 1: return __xchg8((char) x, (char *) ptr); + } + __xchg_called_with_bad_pointer(); + return x; +} + + +/* +** REVISIT - Abandoned use of LDCW in xchg() for now: +** o need to test sizeof(*ptr) to avoid clearing adjacent bytes +** o and while we are at it, could __LP64__ code use LDCD too? +** +** if (__builtin_constant_p(x) && (x == NULL)) +** if (((unsigned long)p & 0xf) == 0) +** return __ldcw(p); +*/ +#define xchg(ptr,x) \ + ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) + + +#define __HAVE_ARCH_CMPXCHG 1 + +/* bug catcher for when unsupported size is used - won't link */ +extern void __cmpxchg_called_with_bad_pointer(void); + +/* __cmpxchg_u32/u64 defined in arch/parisc/lib/bitops.c */ +extern unsigned long __cmpxchg_u32(volatile int *m, int old, int new); +extern unsigned long __cmpxchg_u64(volatile long *ptr, unsigned long old, unsigned long new); + +/* don't worry...optimizer will get rid of most of this */ +static __inline__ unsigned long +__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) +{ + switch(size) { +#ifdef __LP64__ + case 8: return __cmpxchg_u64(ptr, old, new); +#endif + case 4: return __cmpxchg_u32((int *)ptr, (int) old, (int) new); + } + __cmpxchg_called_with_bad_pointer(); + return old; +} + +#define cmpxchg(ptr,o,n) \ + ({ \ + __typeof__(*(ptr)) _o_ = (o); \ + __typeof__(*(ptr)) _n_ = (n); \ + (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ + (unsigned long)_n_, sizeof(*(ptr))); \ + }) + + + /* It's possible to reduce all atomic operations to either * __atomic_add_return, __atomic_set and __atomic_ret (the latter * is there only for consistency). */ @@ -75,7 +166,7 @@ SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(v), flags); } - + static __inline__ int __atomic_read(atomic_t *v) { return v->counter; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/bitops.h linux.ac/include/asm-parisc/bitops.h --- linux.vanilla/include/asm-parisc/bitops.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/bitops.h Tue Apr 3 17:55:15 2001 @@ -182,8 +182,13 @@ * test_and_{set,clear}_bit guarantee atomicity without * disabling interrupts. */ +#ifdef __LP64__ +#define ext2_set_bit(nr, addr) test_and_set_bit((nr) ^ 0x38, addr) +#define ext2_clear_bit(nr, addr) test_and_clear_bit((nr) ^ 0x38, addr) +#else #define ext2_set_bit(nr, addr) test_and_set_bit((nr) ^ 0x18, addr) #define ext2_clear_bit(nr, addr) test_and_clear_bit((nr) ^ 0x18, addr) +#endif #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/cache.h linux.ac/include/asm-parisc/cache.h --- linux.vanilla/include/asm-parisc/cache.h Wed Dec 6 19:46:39 2000 +++ linux.ac/include/asm-parisc/cache.h Tue Apr 3 17:55:15 2001 @@ -5,6 +5,7 @@ #ifndef __ARCH_PARISC_CACHE_H #define __ARCH_PARISC_CACHE_H +#ifndef __ASSEMBLY__ /* ** XXX FIXME : L1_CACHE_BYTES (cacheline size) should be a boot time thing. ** @@ -25,7 +26,7 @@ ** While it improves I/O throughput, you gotta know the device driver ** is well behaved and can deal with the issues.) */ -#if defined(__LP64__) +#ifdef __LP64__ #define L1_CACHE_BYTES 64 #else #define L1_CACHE_BYTES 32 @@ -37,22 +38,38 @@ #define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES))) -extern void init_cache(void); /* initializes cache-flushing */ + +extern void cache_init(void); /* initializes cache-flushing */ extern void flush_data_cache(void); /* flushes data-cache only */ extern void flush_instruction_cache(void);/* flushes code-cache only */ -extern void flush_all_caches(void); /* flushes code and data-cache */ - +extern void flush_all_caches(void); /* flush everything (tlb & cache) */ extern int get_cache_info(char *); - +extern void flush_user_icache_range_asm(unsigned long, unsigned long); +extern void flush_kernel_icache_range_asm(unsigned long, unsigned long); +extern void flush_user_dcache_range_asm(unsigned long, unsigned long); +extern void flush_kernel_dcache_range_asm(unsigned long, unsigned long); +extern void flush_kernel_dcache_page(void *); +extern void disable_sr_hashing(void); /* turns off space register hashing */ +extern void disable_sr_hashing_asm(int); /* low level support for above */ +extern void free_sid(unsigned long); +unsigned long alloc_sid(void); + +extern int split_tlb; +extern int dcache_stride; +extern int icache_stride; extern struct pdc_cache_info cache_info; +#endif /* __ASSEMBLY__ */ -#define fdce(addr) asm volatile("fdce 0(%0)" : : "r" (addr)) -#define fice(addr) asm volatile("fice 0(%%sr1,%0)" : : "r" (addr)) +/* Classes of processor wrt: disabling space register hashing */ -#define pdtlbe(addr) asm volatile("pdtlbe 0(%%sr1,%0)" : : "r" (addr)) -#define pdtlb_kernel(addr) asm volatile("pdtlb 0(%0)" : : "r" (addr)); -#define pitlbe(addr) asm volatile("pitlbe 0(%%sr1,%0)" : : "r" (addr)) +#define SRHASH_PCXST 0 /* pcxs, pcxt, pcxt_ */ +#define SRHASH_PCXL 1 /* pcxl */ +#define SRHASH_PA20 2 /* pcxu, pcxu_, pcxw, pcxw_ */ -#define kernel_fdc(addr) asm volatile("fdc 0(%%sr0, %0)" : : "r" (addr)) +#ifndef __ASSEMBLY__ +#define pdtlb(addr) asm volatile("pdtlb 0(%%sr1,%0)" : : "r" (addr)); +#define pitlb(addr) asm volatile("pitlb 0(%%sr1,%0)" : : "r" (addr)); +#define pdtlb_kernel(addr) asm volatile("pdtlb 0(%0)" : : "r" (addr)); +#endif /* __ASSEMBLY__ */ #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/current.h linux.ac/include/asm-parisc/current.h --- linux.vanilla/include/asm-parisc/current.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/current.h Tue Apr 3 17:55:15 2001 @@ -7,11 +7,8 @@ static inline struct task_struct * get_current(void) { - struct task_struct *current; - - asm("copy 30,%0" : "=r" (current)); - - return (struct task_struct *)((long) current & ~(THREAD_SIZE-1)); + register unsigned long sp asm ("%r30"); + return (struct task_struct *)(sp & ~(THREAD_SIZE-1)); } #define current get_current() diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/delay.h linux.ac/include/asm-parisc/delay.h --- linux.vanilla/include/asm-parisc/delay.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/delay.h Tue Apr 3 17:55:15 2001 @@ -11,8 +11,6 @@ * Delay routines */ -extern unsigned long loops_per_sec; - static __inline__ void __delay(unsigned long loops) { asm volatile( " .balignl 64,0x34000034 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/dma.h linux.ac/include/asm-parisc/dma.h --- linux.vanilla/include/asm-parisc/dma.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-parisc/dma.h Tue Apr 3 17:55:15 2001 @@ -0,0 +1,106 @@ +/* $Id: dma.h,v 1.2 1999/04/27 00:46:18 deller Exp $ + * linux/include/asm/dma.h: Defines for using and allocating dma channels. + * Written by Hennus Bergman, 1992. + * High DMA channel support & info by Hannu Savolainen + * and John Boyd, Nov. 1992. + * (c) Copyright 2000, Grant Grundler + */ + +#ifndef _ASM_DMA_H +#define _ASM_DMA_H + +#include <linux/config.h> +#include <asm/io.h> /* need byte IO */ +#include <asm/system.h> + +/* +** DMA_CHUNK_SIZE is used by the SCSI mid-layer to break up +** (or rather not merge) DMA's into managable chunks. +** On parisc, this is more of the software/tuning constraint +** rather than the HW. I/O MMU allocation alogorithms can be +** faster with smaller size is (to some degree). +*/ +#define DMA_CHUNK_SIZE (BITS_PER_LONG*PAGE_SIZE) + +/* The maximum address that we can perform a DMA transfer to on this platform +** New dynamic DMA interfaces should obsolete this.... +*/ +#define MAX_DMA_ADDRESS (~0UL) + + +/* +** We don't have DMA channels... well V-class does but the +** Dynamic DMA Mapping interface will support them... right? :^) +*/ +#undef MAX_DMA_CHANNELS + + +/* enable/disable a specific DMA channel */ +static __inline__ void enable_dma(unsigned int dmanr) +{ +} + +static __inline__ void disable_dma(unsigned int dmanr) +{ +} + +/* Clear the 'DMA Pointer Flip Flop'. + * Write 0 for LSB/MSB, 1 for MSB/LSB access. + * Use this once to initialize the FF to a known state. + * After that, keep track of it. :-) + * --- In order to do that, the DMA routines below should --- + * --- only be used while holding the DMA lock ! --- + */ +static __inline__ void clear_dma_ff(unsigned int dmanr) +{ +} + +/* set mode (above) for a specific DMA channel */ +static __inline__ void set_dma_mode(unsigned int dmanr, char mode) +{ +} + +/* Set only the page register bits of the transfer address. + * This is used for successive transfers when we know the contents of + * the lower 16 bits of the DMA current address register, but a 64k boundary + * may have been crossed. + */ +static __inline__ void set_dma_page(unsigned int dmanr, char pagenr) +{ +} + + +/* Set transfer address & page bits for specific DMA channel. + * Assumes dma flipflop is clear. + */ +static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a) +{ +} + + +/* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for + * a specific DMA channel. + * You must ensure the parameters are valid. + * NOTE: from a manual: "the number of transfers is one more + * than the initial word count"! This is taken into account. + * Assumes dma flip-flop is clear. + * NOTE 2: "count" represents _bytes_ and must be even for channels 5-7. + */ +static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count) +{ +} + + + +/* These are in kernel/dma.c: */ +extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */ +extern int free_dma(unsigned int dmanr); /* release it again */ +extern int get_dma_list(char *buf); /* proc/dma support */ + +#ifdef CONFIG_PCI +extern int isa_dma_bridge_buggy; +#else +#define isa_dma_bridge_buggy (0) +#endif + +#endif /* _ASM_DMA_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/elf.h linux.ac/include/asm-parisc/elf.h --- linux.vanilla/include/asm-parisc/elf.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/elf.h Tue Apr 3 17:55:15 2001 @@ -9,7 +9,8 @@ #define EM_PARISC 15 -#define ELF_NGREG 32 +#define ELF_NGREG 80 /* We only need 64 at present, but leave space + for expansion. */ #define ELF_NFPREG 32 typedef unsigned long elf_greg_t; @@ -18,10 +19,9 @@ typedef double elf_fpreg_t; typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; -#define ELF_CORE_COPY_REGS(gregs, regs) \ - memcpy(gregs, regs, \ - sizeof(struct pt_regs) < sizeof(elf_gregset_t)? \ - sizeof(struct pt_regs): sizeof(elf_gregset_t)); +struct pt_regs; /* forward declaration... */ +extern void parisc_elf_core_copy_regs (struct pt_regs *src, elf_gregset_t dst); +#define ELF_CORE_COPY_REGS(_dest,_regs) parisc_elf_core_copy_regs(_regs, _dest); /* * This is used to ensure we don't load something for the wrong architecture. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/fixmap.h linux.ac/include/asm-parisc/fixmap.h --- linux.vanilla/include/asm-parisc/fixmap.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/fixmap.h Tue Apr 3 17:55:15 2001 @@ -1,8 +1,14 @@ #ifndef _ASM_FIXMAP_H #define _ASM_FIXMAP_H -#define FIXADDR_TOP (0xffffe000UL) -#define FIXADDR_SIZE (0 << PAGE_SHIFT) -#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) +/* + * Allocate a 8 Mb temporary mapping area for copy_user_page/clear_user_page. + * This area needs to be aligned on a 8 Mb boundary. We also don't want + * to use the page that includes 0xfffff000-0xffffffff, so we leave 8 Mb + * unused at the top, and take the next 8 Mb section below that. + */ + +#define TMPALIAS_MAP_START 0xff000000 +#define FIXADDR_START ((unsigned long)TMPALIAS_MAP_START) #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/floppy.h linux.ac/include/asm-parisc/floppy.h --- linux.vanilla/include/asm-parisc/floppy.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-parisc/floppy.h Tue Apr 3 17:55:15 2001 @@ -0,0 +1,266 @@ +/* + * Architecture specific parts of the Floppy driver + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995 + */ +#ifndef __ASM_PARISC_FLOPPY_H +#define __ASM_PARISC_FLOPPY_H + +#include <linux/vmalloc.h> + + +/* + * The DMA channel used by the floppy controller cannot access data at + * addresses >= 16MB + * + * Went back to the 1MB limit, as some people had problems with the floppy + * driver otherwise. It doesn't matter much for performance anyway, as most + * floppy accesses go through the track buffer. + */ +#define _CROSS_64KB(a,s,vdma) \ +(!vdma && ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64)) + +#define CROSS_64KB(a,s) _CROSS_64KB(a,s,use_virtual_dma & 1) + + +#define SW fd_routine[use_virtual_dma&1] +#define CSW fd_routine[can_use_virtual_dma & 1] + + +#define fd_inb(port) inb_p(port) +#define fd_outb(port,value) outb_p(port,value) + +#define fd_request_dma() CSW._request_dma(FLOPPY_DMA,"floppy") +#define fd_free_dma() CSW._free_dma(FLOPPY_DMA) +#define fd_enable_irq() enable_irq(FLOPPY_IRQ) +#define fd_disable_irq() disable_irq(FLOPPY_IRQ) +#define fd_free_irq() free_irq(FLOPPY_IRQ, NULL) +#define fd_get_dma_residue() SW._get_dma_residue(FLOPPY_DMA) +#define fd_dma_mem_alloc(size) SW._dma_mem_alloc(size) +#define fd_dma_setup(addr, size, mode, io) SW._dma_setup(addr, size, mode, io) + +#define FLOPPY_CAN_FALLBACK_ON_NODMA + +static int virtual_dma_count=0; +static int virtual_dma_residue=0; +static char *virtual_dma_addr=0; +static int virtual_dma_mode=0; +static int doing_pdma=0; + +static void floppy_hardint(int irq, void *dev_id, struct pt_regs * regs) +{ + register unsigned char st; + +#undef TRACE_FLPY_INT +#define NO_FLOPPY_ASSEMBLER + +#ifdef TRACE_FLPY_INT + static int calls=0; + static int bytes=0; + static int dma_wait=0; +#endif + if(!doing_pdma) { + floppy_interrupt(irq, dev_id, regs); + return; + } + +#ifdef TRACE_FLPY_INT + if(!calls) + bytes = virtual_dma_count; +#endif + + { + register int lcount; + register char *lptr; + + st = 1; + for(lcount=virtual_dma_count, lptr=virtual_dma_addr; + lcount; lcount--, lptr++) { + st=inb(virtual_dma_port+4) & 0xa0 ; + if(st != 0xa0) + break; + if(virtual_dma_mode) + outb_p(*lptr, virtual_dma_port+5); + else + *lptr = inb_p(virtual_dma_port+5); + } + virtual_dma_count = lcount; + virtual_dma_addr = lptr; + st = inb(virtual_dma_port+4); + } + +#ifdef TRACE_FLPY_INT + calls++; +#endif + if(st == 0x20) + return; + if(!(st & 0x20)) { + virtual_dma_residue += virtual_dma_count; + virtual_dma_count=0; +#ifdef TRACE_FLPY_INT + printk("count=%x, residue=%x calls=%d bytes=%d dma_wait=%d\n", + virtual_dma_count, virtual_dma_residue, calls, bytes, + dma_wait); + calls = 0; + dma_wait=0; +#endif + doing_pdma = 0; + floppy_interrupt(irq, dev_id, regs); + return; + } +#ifdef TRACE_FLPY_INT + if(!virtual_dma_count) + dma_wait++; +#endif +} + +static void fd_disable_dma(void) +{ + if(! (can_use_virtual_dma & 1)) + disable_dma(FLOPPY_DMA); + doing_pdma = 0; + virtual_dma_residue += virtual_dma_count; + virtual_dma_count=0; +} + +static int vdma_request_dma(unsigned int dmanr, const char * device_id) +{ + return 0; +} + +static void vdma_nop(unsigned int dummy) +{ +} + + +static int vdma_get_dma_residue(unsigned int dummy) +{ + return virtual_dma_count + virtual_dma_residue; +} + + +static int fd_request_irq(void) +{ + if(can_use_virtual_dma) + return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT, + "floppy", NULL); + else + return request_irq(FLOPPY_IRQ, floppy_interrupt, + SA_INTERRUPT|SA_SAMPLE_RANDOM, + "floppy", NULL); + +} + +static unsigned long dma_mem_alloc(unsigned long size) +{ + return __get_dma_pages(GFP_KERNEL,__get_order(size)); +} + + +static unsigned long vdma_mem_alloc(unsigned long size) +{ + return (unsigned long) vmalloc(size); + +} + +#define nodma_mem_alloc(size) vdma_mem_alloc(size) + +static void _fd_dma_mem_free(unsigned long addr, unsigned long size) +{ + if((unsigned int) addr >= (unsigned int) high_memory) + return vfree((void *)addr); + else + free_pages(addr, __get_order(size)); +} + +#define fd_dma_mem_free(addr, size) _fd_dma_mem_free(addr, size) + +static void _fd_chose_dma_mode(char *addr, unsigned long size) +{ + if(can_use_virtual_dma == 2) { + if((unsigned int) addr >= (unsigned int) high_memory || + virt_to_bus(addr) >= 0x1000000 || + _CROSS_64KB(addr, size, 0)) + use_virtual_dma = 1; + else + use_virtual_dma = 0; + } else { + use_virtual_dma = can_use_virtual_dma & 1; + } +} + +#define fd_chose_dma_mode(addr, size) _fd_chose_dma_mode(addr, size) + + +static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io) +{ + doing_pdma = 1; + virtual_dma_port = io; + virtual_dma_mode = (mode == DMA_MODE_WRITE); + virtual_dma_addr = addr; + virtual_dma_count = size; + virtual_dma_residue = 0; + return 0; +} + +static int hard_dma_setup(char *addr, unsigned long size, int mode, int io) +{ +#ifdef FLOPPY_SANITY_CHECK + if (CROSS_64KB(addr, size)) { + printk("DMA crossing 64-K boundary %p-%p\n", addr, addr+size); + return -1; + } +#endif + /* actual, physical DMA */ + doing_pdma = 0; + clear_dma_ff(FLOPPY_DMA); + set_dma_mode(FLOPPY_DMA,mode); + set_dma_addr(FLOPPY_DMA,virt_to_bus(addr)); + set_dma_count(FLOPPY_DMA,size); + enable_dma(FLOPPY_DMA); + return 0; +} + +struct fd_routine_l { + int (*_request_dma)(unsigned int dmanr, const char * device_id); + void (*_free_dma)(unsigned int dmanr); + int (*_get_dma_residue)(unsigned int dummy); + unsigned long (*_dma_mem_alloc) (unsigned long size); + int (*_dma_setup)(char *addr, unsigned long size, int mode, int io); +} fd_routine[] = { + { + request_dma, + free_dma, + get_dma_residue, + dma_mem_alloc, + hard_dma_setup + }, + { + vdma_request_dma, + vdma_nop, + vdma_get_dma_residue, + vdma_mem_alloc, + vdma_dma_setup + } +}; + + +static int FDC1 = 0x3f0; +static int FDC2 = -1; + +#define FLOPPY0_TYPE ((CMOS_READ(0x10) >> 4) & 15) +#define FLOPPY1_TYPE (CMOS_READ(0x10) & 15) + +#define N_FDC 1 +#define N_DRIVE 8 + +#define FLOPPY_MOTOR_MASK 0xf0 + +#define AUTO_DMA + + +#endif /* __ASM_PARISC_FLOPPY_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/hardirq.h linux.ac/include/asm-parisc/hardirq.h --- linux.vanilla/include/asm-parisc/hardirq.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/hardirq.h Tue Apr 3 17:55:15 2001 @@ -42,15 +42,26 @@ #else +#include <asm/system.h> #include <asm/atomic.h> #include <linux/spinlock.h> -#include <asm/system.h> #include <asm/smp.h> -extern unsigned char global_irq_holder; +extern int global_irq_holder; extern spinlock_t global_irq_lock; extern atomic_t global_irq_count; +static inline int irqs_running (void) +{ + int i; + + for (i = 0; i < smp_num_cpus; i++) + if (local_irq_count(i)) + return 1; + return 0; +} + + static inline void release_irqlock(int cpu) { /* if we didn't own the irq lock, just ignore.. */ @@ -60,13 +71,13 @@ } } -static inline void irq_enter(int cpu) +static inline void irq_enter(int cpu, int irq) { ++local_irq_count(cpu); atomic_inc(&global_irq_count); } -static inline void irq_exit(int cpu) +static inline void irq_exit(int cpu, int irq) { atomic_dec(&global_irq_count); --local_irq_count(cpu); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/hardware.h linux.ac/include/asm-parisc/hardware.h --- linux.vanilla/include/asm-parisc/hardware.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/hardware.h Tue Apr 3 17:55:15 2001 @@ -2,34 +2,40 @@ #define _PARISC_HP_MACHINES_H_ struct hp_hardware { - unsigned short hw_type:5; /* HPHW_xxx */ - unsigned short hversion; - unsigned long sversion:28; - unsigned short opt; - char *name; + unsigned short hw_type:5; /* HPHW_xxx */ + unsigned short hversion; + unsigned long sversion:28; + unsigned short opt; + char *name; }; + +#define MAX_ADD_ADDRS 5 /* 5 additional address ranges should be sufficient */ + struct hp_device { - unsigned short hw_type:5; /* HPHW_xxx */ - unsigned short hversion; /* HP-UX uses hv_model:12 */ - unsigned int sversion; /* HP-UX uses sv_model:20 sv_opt:8 */ - unsigned short opt; - unsigned int hversion_rev; - unsigned int sversion_rev; - struct hp_hardware * reference; /* This is a pointer to the + void *hpa; + unsigned short hw_type:5; /* HPHW_xxx */ + unsigned short hversion; /* HP-UX uses hv_model:12 */ + unsigned int sversion; /* HP-UX uses sv_model:20 sv_opt:8 */ + unsigned short opt; + unsigned int hversion_rev; + unsigned int sversion_rev; + struct hp_hardware *reference; /* This is a pointer to the reference */ - unsigned int managed; /* this is if the device has a driver for it */ - void * hpa; + unsigned int managed; /* this is if the device has a driver for it */ + unsigned int num_addrs; /* some devices have additional address ranges, */ + unsigned long addr[MAX_ADD_ADDRS]; /* which will be stored here */ + #ifdef __LP64__ /* parms for pdc_pat_cell_module() call */ - unsigned long pcell_loc; /* Physical Cell location */ - unsigned long mod_index; /* PAT specific - Misc Module info */ + unsigned long pcell_loc; /* Physical Cell location */ + unsigned long mod_index; /* PAT specific - Misc Module info */ /* generic info returned from pdc_pat_cell_module() */ - unsigned long mod_info; /* PAT specific - Misc Module info */ - unsigned long pmod_loc; /* physical Module location */ - unsigned long mod_path; /* Module HW path */ + unsigned long mod_info; /* PAT specific - Misc Module info */ + unsigned long pmod_loc; /* physical Module location */ + unsigned long mod_path; /* Module HW path */ #endif }; @@ -49,16 +55,17 @@ extern char *cpu_name_version[][2]; /* mapping from enum cpu_type to strings */ struct pa_iodc_driver { - unsigned short hw_type:5; /* HPHW_xxx */ - unsigned short hversion; - unsigned short hversion_rev; - unsigned long sversion:28; - unsigned short sversion_rev; - unsigned short opt; - unsigned int check; /* Components that are significant */ - char *name; - char *version; + unsigned short hw_type:5; /* HPHW_xxx */ + unsigned short hversion; + unsigned short hversion_rev; + unsigned long sversion:28; + unsigned short sversion_rev; + unsigned short opt; + unsigned int check; /* Components that are significant */ + char *name; + char *version; int (* callback)(struct hp_device *d, struct pa_iodc_driver *dri); + struct pa_iodc_driver *next; }; #define DRIVER_CHECK_HWTYPE 1 @@ -88,16 +95,26 @@ #define HPHW_FABRIC 14 #define HPHW_FAULTY 31 -extern struct hp_hardware hp_hardware_list[]; - -char *parisc_getHWtype( unsigned short hw_type ); -/* Attention: first hversion, then sversion...! */ -char *parisc_getHWdescription( unsigned short hw_type, - unsigned long hversion, /* have to be long ! */ - unsigned long sversion ); +/* hardware.c: */ +extern char *parisc_getHWtype(unsigned short hw_type); +extern char *parisc_getHWdescription(unsigned short hw_type, + unsigned long hversion, unsigned long sversion); +extern enum cpu_type parisc_get_cpu_type(unsigned long hversion); +extern struct hp_hardware *parisc_get_reference( + unsigned short hw_type, unsigned long hversion, + unsigned long sversion); + + +/* drivers.c: */ +extern struct hp_device *alloc_pa_dev(unsigned long hpa); +extern int register_pa_dev(struct hp_device *hp_device); +extern int add_pa_dev_addr(struct hp_device *hp_device, unsigned long addr); +extern struct hp_device *get_pa_dev(unsigned int index); +extern void print_pa_devices(char * buf); +extern int register_driver(struct pa_iodc_driver *driver); -enum cpu_type parisc_get_cpu_type( unsigned long hversion ); +/* inventory.c: */ +extern void do_inventory(void); -extern int register_driver(struct pa_iodc_driver *driver); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/led.h linux.ac/include/asm-parisc/led.h --- linux.vanilla/include/asm-parisc/led.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/led.h Tue Apr 3 17:55:15 2001 @@ -1,7 +1,6 @@ #ifndef LED_H #define LED_H - #define LED7 0x80 /* top (or furthest right) LED */ #define LED6 0x40 #define LED5 0x20 @@ -16,18 +15,27 @@ #define LED_DISK_IO LED2 /* for disk activity */ #define LED_HEARTBEAT LED3 /* heartbeat */ +/* values for pdc_chassis_lcd_info_ret_block.model: */ +#define DISPLAY_MODEL_LCD 0 /* KittyHawk LED or LCD */ +#define DISPLAY_MODEL_NONE 1 /* no LED or LCD */ +#define DISPLAY_MODEL_LASI 2 /* LASI style 8 bit LED */ +#define DISPLAY_MODEL_OLD_ASP 0x7F /* faked: ASP style 8 x 1 bit LED (only very old ASP versions) */ + +#define LED_CMD_REG_NONE NULL /* NULL == no addr for the cmd register */ /* irq function */ -extern void led_interrupt_func(void); +extern void led_interrupt_func(void); -/* LASI & ASP specific LED initialization funcs */ -extern void __init lasi_led_init( unsigned long lasi_hpa ); -extern void __init asp_led_init( unsigned long led_ptr ); +/* register_led_driver() */ +extern int __init register_led_driver( int model, char *cmd_reg, char *data_reg ); /* registers the LED regions for procfs */ extern void __init register_led_regions(void); -/* main LED initialization function (uses the PDC) */ +/* writes a string to the LCD display (if available) */ +extern int lcd_print(char *str); + +/* main LED initialization function (uses PDC) */ extern int __init led_init(void); #endif /* LED_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/linux_logo.h linux.ac/include/asm-parisc/linux_logo.h --- linux.vanilla/include/asm-parisc/linux_logo.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/linux_logo.h Tue Apr 3 17:55:15 2001 @@ -40,9 +40,6 @@ extern unsigned char linux_logo_blue[]; extern unsigned char linux_logo[]; extern unsigned char linux_logo_bw[]; -extern unsigned char linux_logo16_red[]; -extern unsigned char linux_logo16_green[]; -extern unsigned char linux_logo16_blue[]; extern unsigned char linux_logo16[]; #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/md.h linux.ac/include/asm-parisc/md.h --- linux.vanilla/include/asm-parisc/md.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/md.h Thu Jan 1 01:00:00 1970 @@ -1,13 +0,0 @@ -/* $Id: md.h,v 1.1.1.1 1999/03/15 19:41:02 pjlahaie Exp $ - * md.h: High speed xor_block operation for RAID4/5 - * - */ - -#ifndef __ASM_MD_H -#define __ASM_MD_H - -/* #define HAVE_ARCH_XORBLOCK */ - -#define MD_XORBLOCK_ALIGNMENT sizeof(long) - -#endif /* __ASM_MD_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/module.h linux.ac/include/asm-parisc/module.h --- linux.vanilla/include/asm-parisc/module.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-parisc/module.h Tue Apr 3 17:55:15 2001 @@ -0,0 +1,11 @@ +#ifndef _ASM_PARISC_MODULE_H +#define _ASM_PARISC_MODULE_H +/* + * This file contains the parisc architecture specific module code. + */ + +#define module_map(x) vmalloc(x) +#define module_unmap(x) vfree(x) +#define module_arch_init(x) (0) + +#endif /* _ASM_PARISC_MODULE_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/page.h linux.ac/include/asm-parisc/page.h --- linux.vanilla/include/asm-parisc/page.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/page.h Tue Apr 3 17:55:15 2001 @@ -12,8 +12,23 @@ #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) #define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) -#define clear_user_page(page, vaddr) clear_page(page) -#define copy_user_page(to, from, vaddr) copy_page(to, from) +extern void purge_kernel_dcache_page(unsigned long); +extern void copy_user_page_asm(void *, void *, unsigned long); +extern void clear_user_page_asm(void *, unsigned long); + +static inline void +copy_user_page(void *to, void *from, unsigned long vaddr) +{ + purge_kernel_dcache_page((unsigned long)to); + copy_user_page_asm(to, from, vaddr); +} + +static inline void +clear_user_page(void *page, unsigned long vaddr) +{ + purge_kernel_dcache_page((unsigned long)page); + clear_user_page_asm(page, vaddr); +} /* * These are used to make use of C type-checking.. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/pci.h linux.ac/include/asm-parisc/pci.h --- linux.vanilla/include/asm-parisc/pci.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/pci.h Tue Apr 3 17:55:15 2001 @@ -155,7 +155,9 @@ */ static inline int pci_dma_panic(char *msg) { + extern void panic(const char *, ...); /* linux/kernel.h */ panic(msg); + /* NOTREACHED */ return -1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/pdc.h linux.ac/include/asm-parisc/pdc.h --- linux.vanilla/include/asm-parisc/pdc.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/pdc.h Tue Apr 3 17:55:15 2001 @@ -42,6 +42,9 @@ #define PDC_HPA_PROCESSOR 0 #define PDC_HPA_MODULES 1 +#define PDC_COPROC 7 /* Co-Processor (usually FP unit(s)) */ +#define PDC_COPROC_CFG 0 /* Co-Processor Cfg (FP unit(s) enabled?) */ + #define PDC_IODC 8 /* talk to IODC */ #define PDC_IODC_READ 0 /* read IODC entry point */ /* PDC_IODC_RI_* INDEX parameter of PDC_IODC_READ */ @@ -82,8 +85,16 @@ #define PDC_TLB_INFO 0 /* returns parameter */ #define PDC_TLB_SETUP 1 /* set up miss handling */ +#define PDC_PSW 21 /* Get/Set default System Mask */ +#define PDC_PSW_MASK 0 /* Return mask */ +#define PDC_PSW_GET_DEFAULTS 1 /* Return defaults */ +#define PDC_PSW_SET_DEFAULTS 2 /* Set default */ +#define PDC_PSW_ENDIAN_BIT 1 /* set for big endian */ +#define PDC_PSW_WIDE_BIT 2 /* set for wide mode */ + #define PDC_SYSTEM_MAP 22 /* find system modules */ #define PDC_FIND_MODULE 0 +#define PDC_FIND_ADDRESS 1 /* HVERSION dependent */ @@ -204,7 +215,7 @@ #ifdef __LP64__ cc_padW:32, #endif - cc_alias:4, /* alias boundaries for virtual adresses */ + cc_alias:4, /* alias boundaries for virtual addresses */ cc_block: 4, /* to determine most efficient stride */ cc_line : 3, /* maximum amount written back as a result of store (multiple of 16 bytes) */ cc_pad0 : 2, /* reserved */ @@ -269,7 +280,7 @@ struct pdc_hpa { /* PDC_HPA */ unsigned long hpa; - unsigned long filler[31]; + unsigned long pad[31]; } __attribute__((aligned(8))) ; #if 0 @@ -287,10 +298,10 @@ unsigned char rev; unsigned char dep; unsigned char features; - unsigned char filler1; + unsigned char pad1; unsigned int checksum:16; unsigned int length:16; - unsigned int filler[15]; + unsigned int pad[15]; } __attribute__((aligned(8))) ; #endif @@ -318,11 +329,17 @@ unsigned long pad[32-2]; } __attribute__((aligned(8))) ; -struct pdc_system_map { /* PDC_SYTEM_MAP/FIND_MODULE */ +struct pdc_system_map_mod_info { /* PDC_SYSTEM_MAP/FIND_MODULE */ void * mod_addr; unsigned long mod_pgs; unsigned long add_addrs; - unsigned long filler[29]; + unsigned long pad[32-3]; +} __attribute__((aligned(8))) ; + +struct pdc_system_map_addr_info { /* PDC_SYSTEM_MAP/FIND_ADDRESS */ + void * mod_addr; + unsigned long mod_pgs; + unsigned long pad[32-2]; } __attribute__((aligned(8))) ; /* @@ -334,13 +351,15 @@ /* I/O adaptor (< 0 means none, > 63 resvd) */ char mod; /* fixed field of specified module */ unsigned int layers[6]; /* device-specific info (ctlr #, unit # ...) */ + unsigned long pad[32-2]; } __attribute__((aligned(8))) ; #ifndef __LP64__ /* Probably needs 64-bit porting -PB */ -struct pdc_memory_map { /* PDC_MEMORY_MAP */ +struct pdc_memory_map { /* PDC_MEMORY_MAP */ unsigned int hpa; /* mod's register set address */ unsigned int more_pgs; /* number of additional I/O pgs */ + int pad1[30]; } __attribute__((aligned(8))) ; struct pdc_lan_station_id { /* PDC_LAN_STATION_ID */ @@ -566,7 +585,8 @@ extern void pdc_console_init(void); -extern int pdc_getc(void); /* wait for char */ +/* pdc_get/put are NOT SMP safe - use at your own risk! */ +extern int pdc_getc(void); /* wait for char */ extern void pdc_putc(unsigned char); /* print char */ @@ -577,9 +597,14 @@ #if 0 int pdc_hpa_modules(void *address); #endif +int pdc_coproc_cfg(void *address); int pdc_iodc_read(void *address, void *hpa, unsigned int index, void *iodc_data, unsigned int iodc_data_size); -int pdc_system_map_find_mods(void *pdc_mod_info, void *mod_path, int index); +int pdc_psw_get_mask(void *address); +int pdc_psw_get_defaults(void *address); +int pdc_psw_set_defaults(unsigned long val); +int pdc_system_map_find_mods(void *pdc_mod_info, void *mod_path, long mod_index); +int pdc_system_map_find_addrs(void *pdc_addr_info, long mod_index, long addr_index); int pdc_model_info(struct pdc_model *model); int pdc_model_sysmodel(char *name); int pdc_model_cpuid(struct pdc_model_cpuid *cpu_id); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/pdcpat.h linux.ac/include/asm-parisc/pdcpat.h --- linux.vanilla/include/asm-parisc/pdcpat.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/pdcpat.h Tue Apr 3 17:55:15 2001 @@ -99,7 +99,7 @@ ** Monarch Processor */ #define PDC_PAT_HPMC_RENDEZ_CPU 0L /* go into spin loop */ #define PDC_PAT_HPMC_SET_PARAMS 1L /* Allows OS to specify intr which PDC - * will use to interupt OS during machine + * will use to interrupt OS during machine * check rendezvous */ /* parameters for PDC_PAT_HPMC_SET_PARAMS: */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/pgalloc.h linux.ac/include/asm-parisc/pgalloc.h --- linux.vanilla/include/asm-parisc/pgalloc.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/pgalloc.h Tue Apr 3 17:55:15 2001 @@ -11,196 +11,177 @@ #include <asm/pgtable.h> #include <asm/cache.h> +#define flush_kernel_dcache_range(start,size) \ + flush_kernel_dcache_range_asm((start), (start)+(size)); -/* Internal use D/I cache flushing routines... */ -/* XXX: these functions must not access memory between f[di]ce instructions. */ - -static inline void __flush_dcache_range(unsigned long start, unsigned long size) +static inline void +flush_page_to_ram(struct page *page) { -#if 0 - register unsigned long count = (size / L1_CACHE_BYTES); - register unsigned long loop = cache_info.dc_loop; - register unsigned long i, j; +} - if (size > 64 * 1024) { - /* Just punt and clear the whole damn thing */ - flush_data_cache(); - return; - } +#define flush_cache_mm(mm) flush_cache_all() - for(i = 0; i <= count; i++, start += L1_CACHE_BYTES) - for(j = 0; j < loop; j++) - fdce(start); -#else +static inline void flush_cache_all(void) +{ + flush_instruction_cache(); flush_data_cache(); -#endif } +/* The following value needs to be tuned and probably scaled with the + * cache size. + */ + +#define FLUSH_THRESHOLD 0x80000 -static inline void __flush_icache_range(unsigned long start, unsigned long size) +static inline void +flush_user_dcache_range(unsigned long start, unsigned long end) { -#if 0 - register unsigned long count = (size / L1_CACHE_BYTES); - register unsigned long loop = cache_info.ic_loop; - register unsigned long i, j; + if ((end - start) < FLUSH_THRESHOLD) + flush_user_dcache_range_asm(start,end); + else + flush_data_cache(); +} - if (size > 64 * 1024) { - /* Just punt and clear the whole damn thing */ +static inline void +flush_user_icache_range(unsigned long start, unsigned long end) +{ + if ((end - start) < FLUSH_THRESHOLD) + flush_user_icache_range_asm(start,end); + else flush_instruction_cache(); - return; - } - - for(i = 0; i <= count; i++, start += L1_CACHE_BYTES) - for(j = 0; j < loop; j++) - fice(start); -#else - flush_instruction_cache(); -#endif } static inline void -flush_kernel_dcache_range(unsigned long start, unsigned long size) +flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end) { - register unsigned long end = start + size; - register unsigned long i; + int sr3; - start &= ~(L1_CACHE_BYTES - 1); - for (i = start; i < end; i += L1_CACHE_BYTES) { - kernel_fdc(i); + if (!mm->context) { + BUG(); + return; } - asm volatile("sync" : : ); - asm volatile("syncdma" : : ); -} - -extern void __flush_page_to_ram(unsigned long address); -#define flush_cache_all() flush_all_caches() -#define flush_cache_mm(foo) flush_all_caches() - -#if 0 -/* This is how I think the cache flushing should be done -- mrw */ -extern inline void flush_cache_mm(struct mm_struct *mm) { - if (mm == current->mm) { - flush_user_dcache_range(mm->start_data, mm->end_data); - flush_user_icache_range(mm->start_code, mm->end_code); + sr3 = mfsp(3); + if (mm->context == sr3) { + flush_user_dcache_range(start,end); + flush_user_icache_range(start,end); } else { - flush_other_dcache_range(mm->context, mm->start_data, mm->end_data); - flush_other_icache_range(mm->context, mm->start_code, mm->end_code); + flush_data_cache(); + flush_instruction_cache(); } } -#endif - -#define flush_cache_range(mm, start, end) do { \ - __flush_dcache_range(start, (unsigned long)end - (unsigned long)start); \ - __flush_icache_range(start, (unsigned long)end - (unsigned long)start); \ -} while(0) - -#define flush_cache_page(vma, vmaddr) do { \ - __flush_dcache_range(vmaddr, PAGE_SIZE); \ - __flush_icache_range(vmaddr, PAGE_SIZE); \ -} while(0) - -#define flush_page_to_ram(page) \ - __flush_page_to_ram((unsigned long)page_address(page)) - -#define flush_icache_range(start, end) \ - __flush_icache_range(start, end - start) - -#define flush_icache_page(vma, page) \ - __flush_icache_range(page_address(page), PAGE_SIZE) - -#define flush_dcache_page(page) \ - __flush_dcache_range(page_address(page), PAGE_SIZE) - -/* TLB flushing routines.... */ - -extern void flush_data_tlb(void); -extern void flush_instruction_tlb(void); -#define flush_tlb() do { \ - flush_data_tlb(); \ - flush_instruction_tlb(); \ -} while(0); +static inline void +flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr) +{ + int sr3; -#define flush_tlb_all() flush_tlb() /* XXX p[id]tlb */ + if (!vma->vm_mm->context) { + BUG(); + return; + } -extern __inline__ void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start, unsigned long end) -{ -} - -static inline void flush_instruction_tlb_range(unsigned long start, - unsigned long size) -{ -#if 0 - register unsigned long count = (size / PAGE_SIZE); - register unsigned long loop = cache_info.it_loop; - register unsigned long i, j; - - for(i = 0; i <= count; i++, start += PAGE_SIZE) - for(j = 0; j < loop; j++) - pitlbe(start); -#else - flush_instruction_tlb(); -#endif + sr3 = mfsp(3); + if (vma->vm_mm->context == sr3) { + flush_user_dcache_range(vmaddr,vmaddr + PAGE_SIZE); + if (vma->vm_flags & VM_EXEC) + flush_user_icache_range(vmaddr,vmaddr + PAGE_SIZE); + } else { + flush_data_cache(); + if (vma->vm_flags & VM_EXEC) + flush_instruction_cache(); + } } -static inline void flush_data_tlb_range(unsigned long start, - unsigned long size) +static inline void flush_dcache_page(struct page *page) { -#if 0 - register unsigned long count = (size / PAGE_SIZE); - register unsigned long loop = cache_info.dt_loop; - register unsigned long i, j; - - for(i = 0; i <= count; i++, start += PAGE_SIZE) - for(j = 0; j < loop; j++) - pdtlbe(start); -#else - flush_data_tlb(); -#endif + if (page->mapping && !page->mapping->i_mmap && + !page->mapping->i_mmap_shared) { + set_bit(PG_dcache_dirty, &page->flags); + } else { + flush_kernel_dcache_page(page_address(page)); + } } +#define flush_icache_page(vma,page) +#define flush_icache_range flush_kernel_icache_range_asm -static inline void __flush_tlb_range(unsigned long space, unsigned long start, - unsigned long size) -{ - unsigned long old_sr1; - - if(!size) - return; - - old_sr1 = mfsp(1); - mtsp(space, 1); - - flush_data_tlb_range(start, size); - flush_instruction_tlb_range(start, size); +/* TLB flushing routines.... */ - mtsp(old_sr1, 1); -} +extern void flush_tlb_all(void); -extern void __flush_tlb_space(unsigned long space); +/* + * flush_tlb_mm() + * + * XXX This code is NOT valid for HP-UX compatibility processes, + * (although it will probably work 99% of the time). HP-UX + * processes are free to play with the space id's and save them + * over long periods of time, etc. so we have to preserve the + * space and just flush the entire tlb. We need to check the + * personality in order to do that, but the personality is not + * currently being set correctly. + * + * Of course, Linux processes could do the same thing, but + * we don't support that (and the compilers, dynamic linker, + * etc. do not do that). + */ static inline void flush_tlb_mm(struct mm_struct *mm) { -#if 0 - __flush_tlb_space(mm->context); + if (mm == &init_mm) BUG(); /* Should never happen */ + +#if 1 + if (mm) { + if (mm->context != 0) + free_sid(mm->context); + mm->context = alloc_sid(); + if (mm == current->active_mm) + mtsp(mm->context, 3); + } #else - flush_tlb(); + flush_tlb_all(); #endif } +extern __inline__ void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start, unsigned long end) +{ +} + static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) { - __flush_tlb_range(vma->vm_mm->context, addr, PAGE_SIZE); - + /* For one page, it's not worth testing the split_tlb variable */ + + mtsp(vma->vm_mm->context,1); + pdtlb(addr); + pitlb(addr); } static inline void flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { - __flush_tlb_range(mm->context, start, end - start); + unsigned long npages; + + npages = ((end - (start & PAGE_MASK)) + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + if (npages >= 512) /* XXX arbitrary, should be tuned */ + flush_tlb_all(); + else { + + mtsp(mm->context,1); + if (split_tlb) { + while (npages--) { + pdtlb(start); + pitlb(start); + start += PAGE_SIZE; + } + } else { + while (npages--) { + pdtlb(start); + start += PAGE_SIZE; + } + } + } } /* @@ -252,11 +233,9 @@ pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL); if (ret) { - memset (ret, 0, PTRS_PER_PGD * sizeof(pgd_t)); - - /* Install HP-UX and Linux gateway page translations */ - - pgd_val(*(ret + gateway_pgd_offset)) = gateway_pgd_entry; + memset (ret, 0, PTRS_PER_PGD * sizeof(pgd_t)); + /* Install HP-UX and Linux gateway page translations */ + pgd_val(*(ret + gateway_pgd_offset)) = gateway_pgd_entry; } return ret; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/pgtable.h linux.ac/include/asm-parisc/pgtable.h --- linux.vanilla/include/asm-parisc/pgtable.h Wed Dec 6 19:46:39 2000 +++ linux.ac/include/asm-parisc/pgtable.h Tue Apr 3 17:55:15 2001 @@ -1,43 +1,17 @@ #ifndef _PARISC_PGTABLE_H #define _PARISC_PGTABLE_H +#include <asm/fixmap.h> + #ifndef __ASSEMBLY__ /* * we simulate an x86-style page table for the linux mm code */ #include <asm/processor.h> -#include <asm/fixmap.h> #include <asm/cache.h> -/* To make 53c7xx.c happy */ - -#define IOMAP_FULL_CACHING 2 /* used for 'what' below */ -#define IOMAP_NOCACHE_SER 3 - -extern void kernel_set_cachemode(unsigned long addr, - unsigned long size, int what); - -/* - * cache_clear() semantics: Clear any cache entries for the area in question, - * without writing back dirty entries first. This is useful if the data will - * be overwritten anyway, e.g. by DMA to memory. The range is defined by a - * _physical_ address. - */ -#define cache_clear(paddr, len) do { } while (0) -/* - * cache_push() semantics: Write back any dirty cache data in the given area, - * and invalidate the range in the instruction cache. It needs not (but may) - * invalidate those entries also in the data cache. The range is defined by a - * _physical_ address. - */ -#define cache_push(paddr, len) \ - do { \ - unsigned long vaddr = phys_to_virt(paddr); \ - flush_cache_range(&init_mm, vaddr, vaddr + len); \ - } while(0) -#define cache_push_v(vaddr, len) \ - flush_cache_range(&init_mm, vaddr, vaddr + len) +#define ARCH_STACK_GROWSUP /* * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel @@ -63,8 +37,6 @@ *(pteptr) = (pteval); \ } while(0) - - #endif /* !__ASSEMBLY__ */ #define pte_ERROR(e) \ @@ -306,10 +278,11 @@ extern void paging_init (void); -extern inline void update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) -{ -} +/* Used for deferring calls to flush_dcache_page() */ + +#define PG_dcache_dirty PG_arch_1 + +extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t); /* Encode and de-code a swap entry */ @@ -322,9 +295,6 @@ #define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define swp_entry_to_pte(x) ((pte_t) { (x).val }) -#define module_map vmalloc -#define module_unmap vfree - #include <asm-generic/pgtable.h> #endif /* !__ASSEMBLY__ */ @@ -334,4 +304,4 @@ #define io_remap_page_range remap_page_range -#endif /* _PARISC_PAGE_H */ +#endif /* _PARISC_PGTABLE_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/processor.h linux.ac/include/asm-parisc/processor.h --- linux.vanilla/include/asm-parisc/processor.h Sat Dec 30 17:35:41 2000 +++ linux.ac/include/asm-parisc/processor.h Tue Apr 3 17:55:15 2001 @@ -2,12 +2,14 @@ * include/asm-parisc/processor.h * * Copyright (C) 1994 Linus Torvalds + * Copyright (C) 2001 Grant Grundler */ #ifndef __ASM_PARISC_PROCESSOR_H #define __ASM_PARISC_PROCESSOR_H #ifndef __ASSEMBLY__ +#include <linux/config.h> #include <linux/threads.h> #include <asm/hardware.h> @@ -68,29 +70,37 @@ ** Per CPU data structure - ie varies per CPU. */ struct cpuinfo_parisc { - unsigned cpuid; struct irq_region *region; - - unsigned long it_value; /* Interval Timer value at last timer interrupt */ + unsigned long it_value; /* Interval Timer value at last timer Intr */ unsigned long it_delta; /* Interval Timer delta (tic_10ms / HZ * 100) */ - - unsigned long hpa; /* Host Physical address */ - unsigned long txn_addr; /* External Interrupt Register or id_eid */ - - unsigned long bh_count; /* number of times bh was invoked */ unsigned long irq_count; /* number of IRQ's since boot */ unsigned long irq_max_cr16; /* longest time to handle a single IRQ */ + unsigned long bh_count; /* number of times bh was invoked */ + + unsigned long cpuid; /* aka slot_number or set to NO_PROC_ID */ + unsigned long hpa; /* Host Physical address */ + unsigned long txn_addr; /* MMIO addr of EIR or id_eid */ + unsigned long pending_ipi; /* bitmap of type ipi_message_type */ + unsigned long ipi_count; /* number ipi Interrupts */ + unsigned long prof_counter; /* per CPU profiling support */ + unsigned long prof_multiplier; /* per CPU profiling support */ + unsigned long fp_rev; + unsigned long fp_model; + unsigned int state; + struct hp_device *dev; }; extern struct system_cpuinfo_parisc boot_cpu_data; extern struct cpuinfo_parisc cpu_data[NR_CPUS]; #define current_cpu_data cpu_data[smp_processor_id()] +#define CPU_HVERSION ((boot_cpu_data.hversion >> 4) & 0x0FFF) + extern void identify_cpu(struct cpuinfo_parisc *); -#define EISA_bus 0 /* we don't have ISA support yet */ -#define EISA_bus__is_a_macro /* for versions in ksyms.c */ +extern int EISA_bus; + #define MCA_bus 0 #define MCA_bus__is_a_macro /* for versions in ksyms.c */ @@ -148,50 +158,7 @@ * implementation, not for the architecture). */ -/* The ELF abi wants things done a "wee bit" differently than - * som does. Supporting this behavior here avoids - * having our own version of create_elf_tables. - * - * Oh, and yes, that is not a typo, we are really passing argc in r25 - * and argv in r24 (rather than r26 and r25). This is because that's - * where __libc_start_main wants them. - * - * Duplicated from dl-machine.h for the benefit of readers: - * - * Our initial stack layout is rather different from everyone else's - * due to the unique PA-RISC ABI. As far as I know it looks like - * this: - - ----------------------------------- (user startup code creates this frame) - | 32 bytes of magic | - |---------------------------------| - | 32 bytes argument/sp save area | - |---------------------------------| ((current->mm->env_end) + 63 & ~63) - | N bytes of slack | - |---------------------------------| - | envvar and arg strings | - |---------------------------------| - | ELF auxiliary info | - | (up to 28 words) | - |---------------------------------| - | Environment variable pointers | - | upwards to NULL | - |---------------------------------| - | Argument pointers | - | upwards to NULL | - |---------------------------------| - | argc (1 word) | - ----------------------------------- - - * The pleasant part of this is that if we need to skip arguments we - * can just decrement argc and move argv, because the stack pointer - * is utterly unrelated to the location of the environment and - * argument vectors. - * - * Note that the S/390 people took the easy way out and hacked their - * GCC to make the stack grow downwards. */ - -#define start_thread_som(regs, new_pc, new_sp) do { \ +#define start_thread_som(regs, new_pc, new_sp) do { \ unsigned long *sp = (unsigned long *)new_sp; \ __u32 spaceid = (__u32)current->mm->context; \ unsigned long pc = (unsigned long)new_pc; \ @@ -221,60 +188,77 @@ regs->cr30 = (u32) current; \ } while(0) +/* The ELF abi wants things done a "wee bit" differently than + * som does. Supporting this behavior here avoids + * having our own version of create_elf_tables. + * + * Oh, and yes, that is not a typo, we are really passing argc in r25 + * and argv in r24 (rather than r26 and r25). This is because that's + * where __libc_start_main wants them. + * + * Duplicated from dl-machine.h for the benefit of readers: + * + * Our initial stack layout is rather different from everyone else's + * due to the unique PA-RISC ABI. As far as I know it looks like + * this: -#define start_thread(regs, new_pc, new_sp) do { \ - unsigned long *sp = (unsigned long *)new_sp; \ - __u32 spaceid = (__u32)current->mm->context; \ - unsigned long pc = (unsigned long)new_pc; \ - /* offset pc for priv. level */ \ - pc |= 3; \ - \ - \ - set_fs(USER_DS); \ - regs->iasq[0] = spaceid; \ - regs->iasq[1] = spaceid; \ - regs->iaoq[0] = pc; \ - regs->iaoq[1] = pc; \ - regs->sr[2] = LINUX_GATEWAY_SPACE; \ - regs->sr[3] = 0xffff; \ - regs->sr[4] = spaceid; \ - regs->sr[5] = spaceid; \ - regs->sr[6] = spaceid; \ - regs->sr[7] = spaceid; \ - regs->gr[ 0] = USER_INIT_PSW; \ - regs->fr[ 0] = 0LL; \ - regs->fr[ 1] = 0LL; \ - regs->fr[ 2] = 0LL; \ - regs->fr[ 3] = 0LL; \ - regs->gr[30] = ((current->mm->env_end)+63)&~63; \ - regs->gr[31] = pc; \ - \ - get_user(regs->gr[25],&sp[0]); \ - regs->gr[24] = (unsigned long) &sp[1]; \ - regs->gr[23] = 0; \ - \ - regs->cr30 = (u32) current; \ -} while(0) - -#ifdef __LP64__ + ----------------------------------- (user startup code creates this frame) + | 32 bytes of magic | + |---------------------------------| + | 32 bytes argument/sp save area | + |---------------------------------| (bprm->p) + | ELF auxiliary info | + | (up to 28 words) | + |---------------------------------| + | NULL | + |---------------------------------| + | Environment pointers | + |---------------------------------| + | NULL | + |---------------------------------| + | Argument pointers | + |---------------------------------| <- argv + | argc (1 word) | + |---------------------------------| <- bprm->exec (HACK!) + | N bytes of slack | + |---------------------------------| + | filename passed to execve | + |---------------------------------| (mm->env_end) + | env strings | + |---------------------------------| (mm->env_start, mm->arg_end) + | arg strings | + |---------------------------------| + | additional faked arg strings if | + | we're invoked via binfmt_script | + |---------------------------------| (mm->arg_start) + stack base is at 0xC000'0000 - rlim_max. + +on downward growing arches, it looks like this: + stack base at 0xC000'0000 + | filename passed to execve + | env strings + | arg strings + | faked arg strings + | slack + | ELF + | envps + | argvs + | argc -/* - * For 64 bit kernels we need a version of start thread for 32 bit - * elf files. + * The pleasant part of this is that if we need to skip arguments we + * can just decrement argc and move argv, because the stack pointer + * is utterly unrelated to the location of the environment and + * argument vectors. * - * FIXME: It should be possible to not duplicate the above code - * by playing games with concatenation to form both - * macros at compile time. The only difference between - * this macro and the above is the name and the types - * for sp and pc. + * Note that the S/390 people took the easy way out and hacked their + * GCC to make the stack grow downwards. */ -#define start_thread32(regs, new_pc, new_sp) do { \ - __u32 *sp = (__u32 *)new_sp; \ +#define start_thread(regs, new_pc, new_sp) do { \ + elf_addr_t *sp = (elf_addr_t *)new_sp; \ __u32 spaceid = (__u32)current->mm->context; \ - __u32 pc = (__u32)new_pc; \ - /* offset pc for priv. level */ \ - pc |= 3; \ + elf_addr_t pc = (elf_addr_t)new_pc | 3; \ + elf_caddr_t *argv = (elf_caddr_t *)bprm->exec + 1; \ \ set_fs(USER_DS); \ regs->iasq[0] = spaceid; \ @@ -292,18 +276,16 @@ regs->fr[ 1] = 0LL; \ regs->fr[ 2] = 0LL; \ regs->fr[ 3] = 0LL; \ - regs->gr[30] = ((current->mm->env_end)+63)&~63; \ + regs->gr[30] = ((unsigned long)sp + 63) &~ 63; \ regs->gr[31] = pc; \ \ - get_user(regs->gr[25],&sp[0]); \ - regs->gr[24] = (unsigned long) &sp[1]; \ - regs->gr[23] = 0; \ + get_user(regs->gr[25], (argv - 1)); \ + regs->gr[24] = argv; \ + regs->gr[23] = 0; \ \ regs->cr30 = (u32) current; \ } while(0) -#endif - struct task_struct; /* Free all resources held by a thread. */ @@ -321,10 +303,21 @@ #define KSTK_EIP(tsk) (0xdeadbeef) #define KSTK_ESP(tsk) (0xdeadbeef) -/* Be sure to hunt all references to this down when you change the size of - * the kernel stack */ +#ifdef CONFIG_PA8X00 + +#define ARCH_HAS_PREFETCH +#define ARCH_HAS_PREFETCHW +#define prefetchw(addr) __asm__("ldd 0(%0), %%r0" : : "r" (addr)) +#define prefetch(addr) __asm__("ldw 0(%0), %%r0" : : "r" (addr)) + +#endif + + #endif /* __ASSEMBLY__ */ + +/* Be sure to hunt all references to this down when you change the size of + * the kernel stack */ #define THREAD_SIZE (4*PAGE_SIZE) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/psw.h linux.ac/include/asm-parisc/psw.h --- linux.vanilla/include/asm-parisc/psw.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/psw.h Tue Apr 3 17:55:15 2001 @@ -9,6 +9,8 @@ #define PSW_G 0x00000040 /* PA1.x only */ #define PSW_O 0x00000080 /* PA2.0 only */ +#define PSW_CB 0x0000ff00 + #define PSW_M 0x00010000 #define PSW_V 0x00020000 #define PSW_C 0x00040000 @@ -43,12 +45,12 @@ # define USER_PSW (PSW_C | PSW_D | PSW_Q | PSW_I) # define USER_INIT_PSW (PSW_C | PSW_D | PSW_Q | PSW_I | PSW_N) # define KERNEL_PSW (PSW_C | PSW_D | PSW_Q | PSW_W) -# define PDC_PSW (PSW_Q | PSW_W) +# define REAL_MODE_PSW (PSW_Q | PSW_W) #else # define USER_PSW (PSW_C | PSW_D | PSW_Q | PSW_I | PSW_P) # define USER_INIT_PSW (PSW_C | PSW_D | PSW_Q | PSW_I | PSW_N) # define KERNEL_PSW (PSW_C | PSW_D | PSW_Q) -# define PDC_PSW (PSW_Q) +# define REAL_MODE_PSW (PSW_Q) #endif #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/semaphore.h linux.ac/include/asm-parisc/semaphore.h --- linux.vanilla/include/asm-parisc/semaphore.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/semaphore.h Tue Apr 3 17:55:15 2001 @@ -17,7 +17,7 @@ */ #include <linux/spinlock.h> - +#include <linux/wait.h> #include <asm/system.h> #include <asm/atomic.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/shmparam.h linux.ac/include/asm-parisc/shmparam.h --- linux.vanilla/include/asm-parisc/shmparam.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/shmparam.h Tue Apr 3 17:55:15 2001 @@ -1,6 +1,6 @@ #ifndef _ASMPARISC_SHMPARAM_H #define _ASMPARISC_SHMPARAM_H -#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */ +#define SHMLBA 0x00400000 /* attach addr needs to be 4 Mb aligned */ #endif /* _ASMPARISC_SHMPARAM_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/smp.h linux.ac/include/asm-parisc/smp.h --- linux.vanilla/include/asm-parisc/smp.h Wed Dec 6 19:46:39 2000 +++ linux.ac/include/asm-parisc/smp.h Tue Apr 3 17:55:15 2001 @@ -3,8 +3,85 @@ #include <linux/config.h> -#ifdef CONFIG_SMP -extern volatile unsigned long cpu_online_map; /* Bitmap of available cpu's */ -#endif +#if defined(CONFIG_SMP) + +/* Page Zero Location PDC will look for the address to branch to when we poke +** slave CPUs still in "Icache loop". +*/ +#define PDC_OS_BOOT_RENDEZVOUS 0x10 +#define PDC_OS_BOOT_RENDEZVOUS_HI 0x28 + +#ifndef ASSEMBLY +#include <linux/threads.h> /* for NR_CPUS */ +#include <linux/sched.h> /* for struct task_struct */ +#include <asm/current.h> /* for "current" macro */ + +typedef unsigned long address_t; + +/* + * Private routines/data + */ + +extern int smp_found_config; +extern unsigned long smp_alloc_memory(unsigned long mem_base); +extern unsigned long smp_pdc_entry(unsigned long cpuid); +extern void smp_pdc_setup(int cpuid,unsigned long entry_point); +extern unsigned char boot_cpu_id; +extern unsigned long cpu_present_map; +extern unsigned long cpu_online_map; +extern volatile int __cpu_number_map[NR_CPUS]; +static inline int cpu_number_map(int cpu) +{ + return __cpu_number_map[cpu]; +} +extern volatile unsigned long smp_invalidate_needed; +extern void smp_flush_tlb(void); +extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs); +extern void smp_send_reschedule(int cpu); +extern unsigned long ipi_count; +extern void smp_invalidate_rcv(void); /* Process an NMI */ +extern void smp_local_timer_interrupt(struct pt_regs * regs); +extern void (*mtrr_hook) (void); +extern void setup_APIC_clock (void); +extern volatile int __cpu_logical_map[NR_CPUS]; +static inline int cpu_logical_map(int cpu) +{ + return __cpu_logical_map[cpu]; +} + +#endif /* !ASSEMBLY */ + +/* + * This magic constant controls our willingness to transfer + * a process across CPUs. Such a transfer incurs misses on the L1 + * cache, and on a P6 or P5 with multiple L2 caches L2 hits. My + * gut feeling is this will vary by board in value. For a board + * with separate L2 cache it probably depends also on the RSS, and + * for a board with shared L2 cache it ought to decay fast as other + * processes are run. + */ + +#define PROC_CHANGE_PENALTY 15 /* Schedule penalty */ + +#undef ENTRY_SYS_CPUS +#ifdef ENTRY_SYS_CPUS +#define STATE_RENDEZVOUS 0 +#define STATE_STOPPED 1 +#define STATE_RUNNING 2 +#define STATE_HALTED 3 #endif + + +#define IPI_FUNC_FLUSHTLB 0 +#define IPI_FUNC_PROBE 1 +#define IPI_FUNC_PRINTREGS 2 + +#define smp_processor_id() (current->processor) + +#endif /* CONFIG_SMP */ + +#define NO_PROC_ID 0xFF /* No processor magic marker */ +#define ANY_PROC_ID 0xFF /* Any processor magic marker */ + +#endif /* __ASM_SMP_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/smplock.h linux.ac/include/asm-parisc/smplock.h --- linux.vanilla/include/asm-parisc/smplock.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/smplock.h Tue Apr 3 17:55:15 2001 @@ -8,6 +8,8 @@ extern spinlock_t kernel_flag; +#define kernel_locked() spin_is_locked(&kernel_flag) + /* * Release global kernel lock and global interrupt lock */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/som.h linux.ac/include/asm-parisc/som.h --- linux.vanilla/include/asm-parisc/som.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/som.h Tue Apr 3 17:55:15 2001 @@ -5,4 +5,4 @@ #include <linux/som.h> -#endif /* _ASM_PARISC_SOM_H +#endif /* _ASM_PARISC_SOM_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/spinlock.h linux.ac/include/asm-parisc/spinlock.h --- linux.vanilla/include/asm-parisc/spinlock.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/spinlock.h Tue Apr 3 17:55:15 2001 @@ -3,27 +3,33 @@ #include <asm/system.h> -/* if you're going to use out-of-line slowpaths, use .section .lock.text, - * not .text.lock or the -ffunction-sections monster will eat you alive +/* Note that PA-RISC has to use `1' to mean unlocked and `0' to mean locked + * since it only has load-and-zero. */ -/* we seem to be the only architecture that uses 0 to mean locked - but we - * have to. prumpf */ - #undef SPIN_LOCK_UNLOCKED #define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 } #define spin_lock_init(x) do { (x)->lock = 1; } while(0) +#define spin_is_locked(x) ((x)->lock == 0) + #define spin_unlock_wait(x) do { barrier(); } while(((volatile spinlock_t *)(x))->lock == 1) +#if 1 +#define spin_lock(x) do { \ + while (__ldcw (&(x)->lock) == 0) \ + while (((x)->lock) == 0) ; } while (0) + +#else #define spin_lock(x) \ do { while(__ldcw(&(x)->lock) == 0); } while(0) +#endif #define spin_unlock(x) \ do { (x)->lock = 1; } while(0) -#define spin_trylock(x) (__ldcw(&(x)->lock) == 1) +#define spin_trylock(x) (__ldcw(&(x)->lock) != 0) /* * Read-write spinlocks, allowing multiple readers diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/system.h linux.ac/include/asm-parisc/system.h --- linux.vanilla/include/asm-parisc/system.h Wed Dec 6 19:46:39 2000 +++ linux.ac/include/asm-parisc/system.h Tue Apr 3 17:55:15 2001 @@ -46,20 +46,7 @@ (last) = _switch_to(prev, next); \ } while(0) -/* borrowed this from sparc64 -- probably the SMP case is hosed for us */ -#ifdef CONFIG_SMP -#define smp_mb() mb() -#define smp_rmb() rmb() -#define smp_wmb() wmb() -#else -/* This is simply the barrier() macro from linux/kernel.h but when serial.c - * uses tqueue.h uses smp_mb() defined using barrier(), linux/kernel.h - * hasn't yet been included yet so it fails, thus repeating the macro here. - */ -#define smp_mb() __asm__ __volatile__("":::"memory"); -#define smp_rmb() __asm__ __volatile__("":::"memory"); -#define smp_wmb() __asm__ __volatile__("":::"memory"); -#endif + /* interrupt control */ #define __save_flags(x) __asm__ __volatile__("ssm 0, %0" : "=r" (x) : : "memory") @@ -75,11 +62,23 @@ #define local_irq_enable() __sti() #ifdef CONFIG_SMP +extern void __global_cli(void); +extern void __global_sti(void); +extern unsigned long __global_save_flags(void); +extern void __global_restore_flags(unsigned long); + +#define cli() __global_cli() +#define sti() __global_sti() +#define save_flags(x) ((x)=__global_save_flags()) +#define restore_flags(x) __global_restore_flags(x) + #else + #define cli() __cli() #define sti() __sti() #define save_flags(x) __save_flags(x) #define restore_flags(x) __restore_flags(x) + #endif @@ -120,20 +119,41 @@ : "r" (gr), "i" (cr)) -#define mb() __asm__ __volatile__ ("sync" : : :"memory") -#define wmb() mb() +/* +** This is simply the barrier() macro from linux/kernel.h but when serial.c +** uses tqueue.h uses smp_mb() defined using barrier(), linux/kernel.h +** hasn't yet been included yet so it fails, thus repeating the macro here. +** +** PA-RISC architecture allows for weakly ordered memory accesses although +** none of the processors use it. There is a strong ordered bit that is +** set in the O-bit of the page directory entry. Operating systems that +** can not tolerate out of order accesses should set this bit when mapping +** pages. The O-bit of the PSW should also be set to 1 (I don't believe any +** of the processor implemented the PSW O-bit). The PCX-W ERS states that +** the TLB O-bit is not implemented so the page directory does not need to +** have the O-bit set when mapping pages (section 3.1). This section also +** states that the PSW Y, Z, G, and O bits are not implemented. +** So it looks like nothing needs to be done for parisc-linux (yet). +** (thanks to chada for the above comment -ggg) +** +** The __asm__ op below simple prevents gcc/ld from reordering +** instructions across the mb() "call". +*/ +#define mb() __asm__ __volatile__("":::"memory"); /* barrier() */ +#define wmb() mb() +#define smp_mb() mb() +#define smp_wmb() mb() -extern unsigned long __xchg(unsigned long, unsigned long *, int); +#define set_mb(var, value) do { var = value; mb(); } while (0) -#define xchg(ptr,x) \ - (__typeof__(*(ptr)))__xchg((unsigned long)(x),(unsigned long*)(ptr),sizeof(*(ptr))) -/* LDCW, the only atomic read-write operation PA-RISC has. Sigh. */ +/* LDCW, the only atomic read-write operation PA-RISC has. *sigh*. */ #define __ldcw(a) ({ \ unsigned __ret; \ __asm__ __volatile__("ldcw 0(%1),%0" : "=r" (__ret) : "r" (a)); \ __ret; \ }) + #ifdef CONFIG_SMP /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/tlb.h linux.ac/include/asm-parisc/tlb.h --- linux.vanilla/include/asm-parisc/tlb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-parisc/tlb.h Tue Apr 3 17:55:15 2001 @@ -0,0 +1 @@ +#include <asm-generic/tlb.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/uaccess.h linux.ac/include/asm-parisc/uaccess.h --- linux.vanilla/include/asm-parisc/uaccess.h Wed Dec 6 19:46:39 2000 +++ linux.ac/include/asm-parisc/uaccess.h Tue Apr 3 17:55:15 2001 @@ -46,7 +46,7 @@ struct exception_table_entry { unsigned long addr; /* address of insn that is allowed to fault. */ - int skip; /* pcoq skip | r9 clear flag | r8 -EFAULT flag */ + long skip; /* pcoq skip | r9 clear flag | r8 -EFAULT flag */ }; extern const struct exception_table_entry @@ -80,6 +80,27 @@ __gu_err; \ }) +#ifdef __LP64__ +#define __get_kernel_asm(ldx,ptr) \ + __asm__("\n1:\t" ldx "\t0(%2),%0\n" \ + "2:\n" \ + "\t.section __ex_table,\"a\"\n" \ + "\t.dword\t1b\n" \ + "\t.dword\t(2b-1b)+3\n" \ + "\t.previous" \ + : "=r"(__gu_val), "=r"(__gu_err) \ + : "r"(ptr), "1"(__gu_err)); + +#define __get_user_asm(ldx,ptr) \ + __asm__("\n1:\t" ldx "\t0(%%sr3,%2),%0\n" \ + "2:\n" \ + "\t.section __ex_table,\"a\"\n" \ + "\t.dword\t1b\n" \ + "\t.dword\t(2b-1b)+3\n" \ + "\t.previous" \ + : "=r"(__gu_val), "=r"(__gu_err) \ + : "r"(ptr), "1"(__gu_err)); +#else #define __get_kernel_asm(ldx,ptr) \ __asm__("\n1:\t" ldx "\t0(%2),%0\n" \ "2:\n" \ @@ -99,7 +120,7 @@ "\t.previous" \ : "=r"(__gu_val), "=r"(__gu_err) \ : "r"(ptr), "1"(__gu_err)); - +#endif #define __put_user(x,ptr) \ ({ \ @@ -133,6 +154,29 @@ * gcc knows about, so there are no aliasing issues. */ +#ifdef __LP64__ +#define __put_kernel_asm(stx,x,ptr) \ + __asm__ __volatile__ ( \ + "\n1:\t" stx "\t%2,0(%1)\n" \ + "2:\n" \ + "\t.section __ex_table,\"a\"\n" \ + "\t.dword\t1b\n" \ + "\t.dword\t(2b-1b)+1\n" \ + "\t.previous" \ + : "=r"(__pu_err) \ + : "r"(ptr), "r"(x), "0"(__pu_err)) + +#define __put_user_asm(stx,x,ptr) \ + __asm__ __volatile__ ( \ + "\n1:\t" stx "\t%2,0(%%sr3,%1)\n" \ + "2:\n" \ + "\t.section __ex_table,\"a\"\n" \ + "\t.dword\t1b\n" \ + "\t.dword\t(2b-1b)+1\n" \ + "\t.previous" \ + : "=r"(__pu_err) \ + : "r"(ptr), "r"(x), "0"(__pu_err)) +#else #define __put_kernel_asm(stx,x,ptr) \ __asm__ __volatile__ ( \ "\n1:\t" stx "\t%2,0(%1)\n" \ @@ -154,6 +198,7 @@ "\t.previous" \ : "=r"(__pu_err) \ : "r"(ptr), "r"(x), "0"(__pu_err)) +#endif /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/unistd.h linux.ac/include/asm-parisc/unistd.h --- linux.vanilla/include/asm-parisc/unistd.h Tue Dec 5 20:29:39 2000 +++ linux.ac/include/asm-parisc/unistd.h Tue Apr 3 17:55:15 2001 @@ -694,7 +694,8 @@ #define HPUX_GATEWAY_ADDR 0xC0000004 #define LINUX_GATEWAY_ADDR 0x100 -#define LINUX_GATEWAY_STR "0x100" + +#ifndef __ASSEMBLY__ /* The old syscall code here didn't work, and it looks like it's only used * by applications such as fdisk which for some reason need to produce @@ -895,6 +896,8 @@ } #endif + +#endif /* __ASSEMBLY__ */ #undef STR diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-parisc/xor.h linux.ac/include/asm-parisc/xor.h --- linux.vanilla/include/asm-parisc/xor.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-parisc/xor.h Tue Apr 3 17:55:15 2001 @@ -0,0 +1 @@ +#include <asm-generic/xor.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/bseip.h linux.ac/include/asm-ppc/bseip.h --- linux.vanilla/include/asm-ppc/bseip.h Sat Nov 27 23:42:33 1999 +++ linux.ac/include/asm-ppc/bseip.h Tue Apr 3 23:32:59 2001 @@ -8,6 +8,7 @@ #ifndef __MACH_BSEIP_DEFS #define __MACH_BSEIP_DEFS +#ifndef __ASSEMBLY__ /* A Board Information structure that is given to a program when * prom starts it up. */ @@ -29,6 +30,7 @@ #define IMAP_SIZE ((uint)(64 * 1024)) #define PCMCIA_MEM_ADDR ((uint)0x04000000) #define PCMCIA_MEM_SIZE ((uint)(64 * 1024)) +#endif /* !__ASSEMBLY__ */ /* We don't use the 8259. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/elf.h linux.ac/include/asm-ppc/elf.h --- linux.vanilla/include/asm-ppc/elf.h Mon Jan 22 23:41:15 2001 +++ linux.ac/include/asm-ppc/elf.h Tue Apr 17 15:38:29 2001 @@ -74,20 +74,46 @@ * We need to put in some extra aux table entries to tell glibc what * the cache block size is, so it can use the dcbz instruction safely. */ -#define AT_DCACHEBSIZE 17 -#define AT_ICACHEBSIZE 18 -#define AT_UCACHEBSIZE 19 +#define AT_DCACHEBSIZE 19 +#define AT_ICACHEBSIZE 20 +#define AT_UCACHEBSIZE 21 +/* A special ignored type value for PPC, for glibc compatibility. */ +#define AT_IGNOREPPC 22 extern int dcache_bsize; extern int icache_bsize; extern int ucache_bsize; -#define DLINFO_EXTRA_ITEMS 3 -#define EXTRA_DLINFO do { \ - NEW_AUX_ENT(0, AT_DCACHEBSIZE, dcache_bsize); \ - NEW_AUX_ENT(1, AT_ICACHEBSIZE, icache_bsize); \ - NEW_AUX_ENT(2, AT_UCACHEBSIZE, ucache_bsize); \ -} while (0) +/* + * The requirements here are: + * - keep the final alignment of sp (sp & 0xf) + * - make sure the 32-bit value at the first 16 byte aligned position of + * AUXV is greater than 16 for glibc compatibility. + * AT_IGNOREPPC is used for that. + * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC, + * even if DLINFO_ARCH_ITEMS goes to zero or is undefined. + */ +#define DLINFO_ARCH_ITEMS 3 +#define ARCH_DLINFO \ +do { \ + sp -= DLINFO_ARCH_ITEMS * 2; \ + NEW_AUX_ENT(0, AT_DCACHEBSIZE, dcache_bsize); \ + NEW_AUX_ENT(1, AT_ICACHEBSIZE, icache_bsize); \ + NEW_AUX_ENT(2, AT_UCACHEBSIZE, ucache_bsize); \ + /* \ + * Keep the final alignment of sp. \ + */ \ + if (DLINFO_ARCH_ITEMS & 1) { \ + sp -= 2; \ + NEW_AUX_ENT(0, AT_IGNOREPPC, AT_IGNOREPPC); \ + } \ + /* \ + * Now handle glibc compatibility. \ + */ \ + sp -= 2*2; \ + NEW_AUX_ENT(0, AT_IGNOREPPC, AT_IGNOREPPC); \ + NEW_AUX_ENT(1, AT_IGNOREPPC, AT_IGNOREPPC); \ + } while (0) #endif /* __KERNEL__ */ #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/fads.h linux.ac/include/asm-ppc/fads.h --- linux.vanilla/include/asm-ppc/fads.h Sat Nov 27 23:42:33 1999 +++ linux.ac/include/asm-ppc/fads.h Tue Apr 3 23:32:59 2001 @@ -8,6 +8,7 @@ #ifndef __MACH_FADS_DEFS #define __MACH_FADS_DEFS +#ifndef __ASSEMBLY__ /* A Board Information structure that is given to a program when * prom starts it up. */ @@ -35,5 +36,6 @@ #define IMAP_SIZE ((uint)(64 * 1024)) #define PCMCIA_MEM_ADDR ((uint)0x04000000) #define PCMCIA_MEM_SIZE ((uint)(64 * 1024)) +#endif /* !__ASSEMBLY__ */ #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/gemini.h linux.ac/include/asm-ppc/gemini.h --- linux.vanilla/include/asm-ppc/gemini.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-ppc/gemini.h Tue Apr 3 23:32:59 2001 @@ -0,0 +1,168 @@ +/* + * include/asm-ppc/gemini.h + * + * + * Onboard registers and descriptions for Synergy Microsystems' + * "Gemini" boards. + * + */ +#ifdef __KERNEL__ +#ifndef __PPC_GEMINI_H +#define __PPC_GEMINI_H + +/* Registers */ + +#define GEMINI_SERIAL_B (0xffeffb00) +#define GEMINI_SERIAL_A (0xffeffb08) +#define GEMINI_USWITCH (0xffeffd00) +#define GEMINI_BREV (0xffeffe00) +#define GEMINI_BECO (0xffeffe08) +#define GEMINI_FEAT (0xffeffe10) +#define GEMINI_BSTAT (0xffeffe18) +#define GEMINI_CPUSTAT (0xffeffe20) +#define GEMINI_L2CFG (0xffeffe30) +#define GEMINI_MEMCFG (0xffeffe38) +#define GEMINI_FLROM (0xffeffe40) +#define GEMINI_P0PCI (0xffeffe48) +#define GEMINI_FLWIN (0xffeffe50) +#define GEMINI_P0INTMASK (0xffeffe60) +#define GEMINI_P0INTAP (0xffeffe68) +#define GEMINI_PCIERR (0xffeffe70) +#define GEMINI_LEDBASE (0xffeffe80) +#define GEMINI_RTC (0xffe9fff8) +#define GEMINI_LEDS 8 +#define GEMINI_SWITCHES 8 + + +/* Flash ROM bit definitions */ +#define GEMINI_FLS_WEN (1<<0) +#define GEMINI_FLS_JMP (1<<6) +#define GEMINI_FLS_BOOT (1<<7) + +/* Memory bit definitions */ +#define GEMINI_MEM_TYPE_MASK 0xc0 +#define GEMINI_MEM_SIZE_MASK 0x38 +#define GEMINI_MEM_BANK_MASK 0x07 + +/* L2 cache bit definitions */ +#define GEMINI_L2_SIZE_MASK 0xc0 +#define GEMINI_L2_RATIO_MASK 0x03 + +/* Timebase register bit definitons */ +#define GEMINI_TIMEB0_EN (1<<0) +#define GEMINI_TIMEB1_EN (1<<1) +#define GEMINI_TIMEB2_EN (1<<2) +#define GEMINI_TIMEB3_EN (1<<3) + +/* CPU status bit definitions */ +#define GEMINI_CPU_ID_MASK 0x03 +#define GEMINI_CPU_COUNT_MASK 0x0c +#define GEMINI_CPU0_HALTED (1<<4) +#define GEMINI_CPU1_HALTED (1<<5) +#define GEMINI_CPU2_HALTED (1<<6) +#define GEMINI_CPU3_HALTED (1<<7) + +/* Board status bit definitions */ +#define GEMINI_BRD_FAIL (1<<0) /* FAIL led is lit */ +#define GEMINI_BRD_BUS_MASK 0x0c /* PowerPC bus speed */ + +/* Board family/feature bit descriptions */ +#define GEMINI_FEAT_HAS_FLASH (1<<0) +#define GEMINI_FEAT_HAS_ETH (1<<1) +#define GEMINI_FEAT_HAS_SCSI (1<<2) +#define GEMINI_FEAT_HAS_P0 (1<<3) +#define GEMINI_FEAT_FAM_MASK 0xf0 + +/* Mod/ECO bit definitions */ +#define GEMINI_ECO_LEVEL_MASK 0x0f +#define GEMINI_MOD_MASK 0xf0 + +/* Type/revision bit definitions */ +#define GEMINI_REV_MASK 0x0f +#define GEMINI_TYPE_MASK 0xf0 + +/* User switch definitions */ +#define GEMINI_SWITCH_VERBOSE 1 /* adds "debug" to boot cmd line */ +#define GEMINI_SWITCH_SINGLE_USER 7 /* boots into "single-user" mode */ + +#define SGS_RTC_CONTROL 0 +#define SGS_RTC_SECONDS 1 +#define SGS_RTC_MINUTES 2 +#define SGS_RTC_HOURS 3 +#define SGS_RTC_DAY 4 +#define SGS_RTC_DAY_OF_MONTH 5 +#define SGS_RTC_MONTH 6 +#define SGS_RTC_YEAR 7 + +#define SGS_RTC_SET 0x80 +#define SGS_RTC_IS_STOPPED 0x80 + +#define GRACKLE_CONFIG_ADDR_ADDR (0xfec00000) +#define GRACKLE_CONFIG_DATA_ADDR (0xfee00000) + +#define GEMINI_BOOT_INIT (0xfff00100) + +#ifndef __ASSEMBLY__ + +static inline void grackle_write( unsigned long addr, unsigned long data ) +{ + __asm__ __volatile__( + " stwbrx %1, 0, %0\n \ + sync\n \ + stwbrx %3, 0, %2\n \ + sync " + : /* no output */ + : "r" (GRACKLE_CONFIG_ADDR_ADDR), "r" (addr), + "r" (GRACKLE_CONFIG_DATA_ADDR), "r" (data)); +} + +static inline unsigned long grackle_read( unsigned long addr ) +{ + unsigned long val; + + __asm__ __volatile__( + " stwbrx %1, 0, %2\n \ + sync\n \ + lwbrx %0, 0, %3\n \ + sync " + : "=r" (val) + : "r" (addr), "r" (GRACKLE_CONFIG_ADDR_ADDR), + "r" (GRACKLE_CONFIG_DATA_ADDR)); + + return val; +} + +static inline void gemini_led_on( int led ) +{ + if (led >= 0 && led < GEMINI_LEDS) + *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 1; +} + +static inline void gemini_led_off(int led) +{ + if (led >= 0 && led < GEMINI_LEDS) + *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 0; +} + +static inline int gemini_led_val(int led) +{ + int val = 0; + if (led >= 0 && led < GEMINI_LEDS) + val = *(unsigned char *)(GEMINI_LEDBASE + (led<<3)); + return (val & 0x1); +} + +/* returns processor id from the board */ +static inline int gemini_processor(void) +{ + unsigned char cpu = *(unsigned char *)(GEMINI_CPUSTAT); + return (int) ((cpu == 0) ? 4 : (cpu & GEMINI_CPU_ID_MASK)); +} + + +extern void _gemini_reboot(void); +extern void gemini_prom_init(void); +extern void gemini_init_l2(void); +#endif /* __ASSEMBLY__ */ +#endif +#endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/gemini_serial.h linux.ac/include/asm-ppc/gemini_serial.h --- linux.vanilla/include/asm-ppc/gemini_serial.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-ppc/gemini_serial.h Tue Apr 3 23:32:59 2001 @@ -0,0 +1,41 @@ +#ifdef __KERNEL__ +#ifndef __ASMPPC_GEMINI_SERIAL_H +#define __ASMPPC_GEMINI_SERIAL_H + +#include <linux/config.h> +#include <asm/gemini.h> + +#ifdef CONFIG_SERIAL_MANY_PORTS +#define RS_TABLE_SIZE 64 +#else +#define RS_TABLE_SIZE 4 +#endif + +/* Rate for the 24.576 Mhz clock for the onboard serial chip */ +#define BASE_BAUD (24576000 / 16) + +#ifdef CONFIG_SERIAL_DETECT_IRQ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) +#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ) +#else +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) +#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF) +#endif + +#define STD_SERIAL_PORT_DEFNS \ + { 0, BASE_BAUD, GEMINI_SERIAL_A, 15, STD_COM_FLAGS }, /* ttyS0 */ \ + { 0, BASE_BAUD, GEMINI_SERIAL_B, 14, STD_COM_FLAGS }, /* ttyS1 */ \ + +#ifdef CONFIG_GEMINI_PU32 +#define PU32_SERIAL_PORT_DEFNS \ + { 0, BASE_BAUD, NULL, 0, STD_COM_FLAGS }, +#else +#define PU32_SERIAL_PORT_DEFNS +#endif + +#define SERIAL_PORT_DFNS \ + STD_SERIAL_PORT_DEFNS \ + PU32_SERIAL_PORT_DEFNS + +#endif +#endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/hw_irq.h linux.ac/include/asm-ppc/hw_irq.h --- linux.vanilla/include/asm-ppc/hw_irq.h Mon Jan 22 23:41:15 2001 +++ linux.ac/include/asm-ppc/hw_irq.h Tue Apr 3 23:32:59 2001 @@ -9,10 +9,6 @@ struct int_control_struct { - void (*int_cli)(void); - void (*int_sti)(void); - void (*int_restore_flags)(unsigned long); - void (*int_save_flags)(unsigned long *); void (*int_set_lost)(unsigned long); }; extern struct int_control_struct int_control; @@ -20,16 +16,14 @@ extern unsigned long do_IRQ_intercept; int timer_interrupt(struct pt_regs *); -extern void __no_use_sti(void); -extern void __no_use_cli(void); -extern void __no_use_restore_flags(unsigned long); -extern void __no_use_save_flags(unsigned long *); -extern void __no_use_set_lost(unsigned long); +extern void __sti(void); +extern void __cli(void); +extern void __restore_flags(unsigned long); +extern void __save_flags_ptr(unsigned long *); +extern void __set_lost(unsigned long); +extern unsigned long __sti_end, __cli_end, __restore_flags_end, __save_flags_ptr_end; -#define __cli() int_control.int_cli() -#define __sti() int_control.int_sti() -#define __save_flags(flags) int_control.int_save_flags((unsigned long *)&flags) -#define __restore_flags(flags) int_control.int_restore_flags((unsigned long)flags) +#define __save_flags(flags) __save_flags_ptr((unsigned long *)&flags) #define __save_and_cli(flags) ({__save_flags(flags);__cli();}) #define __set_lost(irq) ({ if ((unsigned long)int_control.int_set_lost) int_control.int_set_lost(irq); }) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/kmap_types.h linux.ac/include/asm-ppc/kmap_types.h --- linux.vanilla/include/asm-ppc/kmap_types.h Sun Nov 12 02:23:10 2000 +++ linux.ac/include/asm-ppc/kmap_types.h Sat Apr 14 01:39:14 2001 @@ -5,6 +5,8 @@ enum km_type { KM_BOUNCE_READ, KM_BOUNCE_WRITE, + KM_SKB_DATA, + KM_SKB_DATA_SOFTIRQ, KM_TYPE_NR }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/machdep.h linux.ac/include/asm-ppc/machdep.h --- linux.vanilla/include/asm-ppc/machdep.h Mon Jan 22 23:41:15 2001 +++ linux.ac/include/asm-ppc/machdep.h Tue Apr 3 23:33:00 2001 @@ -22,7 +22,6 @@ unsigned int (*irq_cannonicalize)(unsigned int irq); void (*init_IRQ)(void); int (*get_irq)(struct pt_regs *); - void (*post_irq)( struct pt_regs *, int ); /* A general init function, called by ppc_init in init/main.c. May be NULL. */ @@ -41,6 +40,7 @@ unsigned long heartbeat_reset; unsigned long heartbeat_count; + unsigned long (*find_end_of_memory)(void); void (*progress)(char *, unsigned short); unsigned char (*nvram_read_val)(int addr); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/mbx.h linux.ac/include/asm-ppc/mbx.h --- linux.vanilla/include/asm-ppc/mbx.h Sun Nov 12 02:23:11 2000 +++ linux.ac/include/asm-ppc/mbx.h Tue Apr 3 23:33:01 2001 @@ -11,6 +11,7 @@ #ifndef __MACH_MBX_DEFS #define __MACH_MBX_DEFS +#ifndef __ASSEMBLY__ /* A Board Information structure that is given to a program when * EPPC-Bug starts it up. */ @@ -78,6 +79,7 @@ #define ISA_BRIDGE_INT SIU_IRQ3 /* All those PC things */ #define COMM_L_INT SIU_IRQ6 /* MBX Comm expansion connector pin */ #define STOP_ABRT_INT SIU_IRQ7 /* Stop/Abort header pin */ +#endif /* !__ASSEMBLY__ */ /* The MBX uses the 8259. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/mpc8xx.h linux.ac/include/asm-ppc/mpc8xx.h --- linux.vanilla/include/asm-ppc/mpc8xx.h Tue Apr 3 17:32:27 2001 +++ linux.ac/include/asm-ppc/mpc8xx.h Tue Apr 3 23:33:01 2001 @@ -68,6 +68,7 @@ #define PCI_DRAM_OFFSET 0 #endif +#ifndef __ASSEMBLY__ extern unsigned long isa_io_base; extern unsigned long isa_mem_base; extern unsigned long pci_dram_offset; @@ -82,6 +83,7 @@ unsigned long flags, const char *device, void *dev_id); +#endif /* !__ASSEMBLY__ */ #endif /* CONFIG_8xx */ #endif #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/pci-bridge.h linux.ac/include/asm-ppc/pci-bridge.h --- linux.vanilla/include/asm-ppc/pci-bridge.h Mon Jan 22 23:41:15 2001 +++ linux.ac/include/asm-ppc/pci-bridge.h Tue Apr 3 23:33:01 2001 @@ -27,6 +27,11 @@ extern struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node); +/* Fill up host controller resources from the OF node */ +extern void +pci_process_bridge_OF_ranges(struct pci_controller *hose, + struct device_node *dev, int primary); + /* * Structure of a PCI controller (host bridge) */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/processor.h linux.ac/include/asm-ppc/processor.h --- linux.vanilla/include/asm-ppc/processor.h Tue Apr 3 17:32:27 2001 +++ linux.ac/include/asm-ppc/processor.h Tue Apr 3 23:33:01 2001 @@ -12,6 +12,7 @@ #include <asm/ptrace.h> #include <asm/types.h> +#include <asm/mpc8xx.h> /* Machine State Register (MSR) Fields */ @@ -509,15 +510,15 @@ #define _MACH_rpxlite 0x00000040 /* RPCG RPX-Lite 8xx board */ #define _MACH_bseip 0x00000080 /* Bright Star Engineering ip-Engine */ #define _MACH_unused0 0x00000100 /* Now free to be used */ -#define _MACH_unused1 0x00000200 /* Now free to be used */ +#define _MACH_gemini 0x00000200 /* Synergy Microsystems gemini board */ #define _MACH_classic 0x00000400 /* RPCG RPX-Classic 8xx board */ #define _MACH_oak 0x00000800 /* IBM "Oak" 403 eval. board */ #define _MACH_walnut 0x00001000 /* IBM "Walnut" 405GP eval. board */ #define _MACH_8260 0x00002000 /* Generic 8260 */ #define _MACH_tqm860 0x00004000 /* TQM860/L */ #define _MACH_tqm8xxL 0x00008000 /* TQM8xxL */ -#define _MACH_spd8xxL 0x00010000 /* SPD8xx */ -#define _MACH_ibms8 0x00020000 /* IVMS8 */ +#define _MACH_spd8xx 0x00010000 /* SPD8xx */ +#define _MACH_ivms8 0x00020000 /* IVMS8 */ /* see residual.h for these */ #define _PREP_Motorola 0x01 /* motorola prep */ @@ -711,6 +712,9 @@ #define have_of 0 #elif defined(CONFIG_APUS) #define _machine _MACH_apus +#define have_of 0 +#elif defined(CONFIG_GEMINI) +#define _machine _MACH_gemini #define have_of 0 #elif defined(CONFIG_8260) #define _machine _MACH_8260 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/rpxclassic.h linux.ac/include/asm-ppc/rpxclassic.h --- linux.vanilla/include/asm-ppc/rpxclassic.h Sun Nov 12 02:23:11 2000 +++ linux.ac/include/asm-ppc/rpxclassic.h Tue Apr 3 23:33:01 2001 @@ -11,6 +11,7 @@ #include <linux/config.h> +#ifndef __ASSEMBLY__ /* A Board Information structure that is given to a program when * prom starts it up. */ @@ -73,6 +74,7 @@ /* Interrupt level assignments. */ #define FEC_INTERRUPT SIU_LEVEL1 /* FEC interrupt */ +#endif /* !__ASSEMBLY__ */ /* We don't use the 8259. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/rpxlite.h linux.ac/include/asm-ppc/rpxlite.h --- linux.vanilla/include/asm-ppc/rpxlite.h Sun Nov 12 02:23:11 2000 +++ linux.ac/include/asm-ppc/rpxlite.h Tue Apr 3 23:33:01 2001 @@ -9,6 +9,7 @@ #ifndef __MACH_RPX_DEFS #define __MACH_RPX_DEFS +#ifndef __ASSEMBLY__ /* A Board Information structure that is given to a program when * prom starts it up. */ @@ -56,6 +57,7 @@ */ #define HIOX_CSR_ENAUDIO ((uint)0x00000200) #define HIOX_CSR_RSTAUDIO ((uint)0x00000100) /* 0 == reset */ +#endif /* !__ASSEMBLY__ */ /* We don't use the 8259. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/serial.h linux.ac/include/asm-ppc/serial.h --- linux.vanilla/include/asm-ppc/serial.h Mon Jan 22 23:41:15 2001 +++ linux.ac/include/asm-ppc/serial.h Tue Apr 3 23:33:01 2001 @@ -5,6 +5,10 @@ #ifdef __KERNEL__ #include <linux/config.h> +#ifdef CONFIG_GEMINI +#include <asm/gemini_serial.h> +#else + /* * This assumes you have a 1.8432 MHz clock for your UART. * @@ -123,4 +127,5 @@ HUB6_SERIAL_PORT_DFNS \ MCA_SERIAL_PORT_DFNS +#endif /* CONFIG_GEMINI */ #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/smp.h linux.ac/include/asm-ppc/smp.h --- linux.vanilla/include/asm-ppc/smp.h Mon Jan 22 23:41:15 2001 +++ linux.ac/include/asm-ppc/smp.h Tue Apr 3 23:33:02 2001 @@ -1,8 +1,11 @@ /* smp.h: PPC specific SMP stuff. * - * Taken from asm-sparc/smp.h + * Original was a copy of sparc smp.h. Now heavily modified + * for PPC. + * + * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996-2001 Cort Dougan <cort@fsmlabs.com> */ - #ifdef __KERNEL__ #ifndef _PPC_SMP_H #define _PPC_SMP_H @@ -21,9 +24,11 @@ unsigned long *pte_cache; unsigned long pgtable_cache_sz; }; -extern struct cpuinfo_PPC cpu_data[NR_CPUS]; +extern struct cpuinfo_PPC cpu_data[NR_CPUS]; +extern unsigned long cpu_online_map; extern unsigned long smp_proc_in_lock[NR_CPUS]; +extern volatile unsigned long cpu_callin_map[NR_CPUS]; extern void smp_store_cpu_info(int id); extern void smp_send_tlb_invalidate(int); @@ -37,7 +42,6 @@ /* 1 to 1 mapping on PPC -- Cort */ #define cpu_logical_map(cpu) (cpu) #define cpu_number_map(x) (x) -extern volatile unsigned long cpu_callin_map[NR_CPUS]; #define smp_processor_id() (current->processor) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/system.h linux.ac/include/asm-ppc/system.h --- linux.vanilla/include/asm-ppc/system.h Tue Apr 3 17:32:27 2001 +++ linux.ac/include/asm-ppc/system.h Tue Apr 3 23:33:02 2001 @@ -3,7 +3,6 @@ * * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu> */ -#ifdef __KERNEL__ #ifndef __PPC_SYSTEM_H #define __PPC_SYSTEM_H @@ -47,6 +46,7 @@ #define smp_wmb() __asm__ __volatile__("": : :"memory") #endif /* CONFIG_SMP */ +#ifdef __KERNEL__ extern void xmon_irq(int, void *, struct pt_regs *); extern void xmon(struct pt_regs *excp); extern void print_backtrace(unsigned long *); @@ -115,6 +115,8 @@ #define local_irq_save(flags) __save_and_cli(flags) #define local_irq_restore(flags) __restore_flags(flags) +#endif /* __KERNEL__ */ + #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) static __inline__ unsigned long @@ -216,4 +218,3 @@ }) #endif /* __PPC_SYSTEM_H */ -#endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/tqm8xx.h linux.ac/include/asm-ppc/tqm8xx.h --- linux.vanilla/include/asm-ppc/tqm8xx.h Tue Apr 3 17:32:27 2001 +++ linux.ac/include/asm-ppc/tqm8xx.h Sat Apr 14 01:39:23 2001 @@ -12,6 +12,8 @@ #ifndef __MACH_TQM8xx_DEFS #define __MACH_TQM8xx_DEFS +#include <linux/config.h> + #ifndef __ASSEMBLY__ typedef void (interrupt_handler_t)(void *); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/atomic.h linux.ac/include/asm-s390/atomic.h --- linux.vanilla/include/asm-s390/atomic.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/atomic.h Thu Apr 12 12:06:16 2001 @@ -25,6 +25,15 @@ #define atomic_eieio() __asm__ __volatile__ ("BCR 15,0") +#define __CS_LOOP(old, new, ptr, op_val, op_string) \ + __asm__ __volatile__(" l %0,0(%2)\n" \ + "0: lr %1,%0\n" \ + op_string " %1,%3\n" \ + " cs %0,%1,0(%2)\n" \ + " jl 0b" \ + : "=&d" (old), "=&d" (new) \ + : "a" (ptr), "d" (op_val) : "cc" ); + static __inline__ int atomic_read(atomic_t *v) { int retval; @@ -43,150 +52,80 @@ static __inline__ void atomic_add(int i, atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,%0\n" - "0: lr 1,0\n" - " ar 1,%1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : "d" (i) : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, i, "ar"); } static __inline__ int atomic_add_return (int i, atomic_t *v) { - int newval; - __asm__ __volatile__(" la 1,%0\n" - " l 0,%0\n" - "0: lr %1,0\n" - " ar %1,%2\n" - " cs 0,%1,0(1)\n" - " jl 0b" - : "+m" (*v), "=&d" (newval) - : "d" (i) : "0", "1", "cc" ); - return newval; + int old, new; + __CS_LOOP(old, new, v, i, "ar"); + return new; } static __inline__ int atomic_add_negative(int i, atomic_t *v) { - int newval; - __asm__ __volatile__(" la 1,%0\n" - " l 0,%0\n" - "0: lr %1,0\n" - " ar %1,%2\n" - " cs 0,%1,0(1)\n" - " jl 0b\n" - : "+m" (*v), "=&d" (newval) - : "d" (i) : "0", "1", "cc" ); - return newval < 0; + int old, new; + __CS_LOOP(old, new, v, i, "ar"); + return new < 0; } static __inline__ void atomic_sub(int i, atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,%0\n" - "0: lr 1,0\n" - " sr 1,%1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : "d" (i) : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, i, "sr"); } static __inline__ void atomic_inc(volatile atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,%0\n" - "0: lr 1,0\n" - " ahi 1,1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, 1, "ar"); } static __inline__ int atomic_inc_return(volatile atomic_t *v) { - int i; - __asm__ __volatile__(" la 1,%0\n" - " l 0,%0\n" - "0: lr %1,0\n" - " ahi %1,1\n" - " cs 0,%1,0(1)\n" - " jl 0b" - : "+m" (*v), "=&d" (i) : : "0", "1", "cc" ); - return i; + int old, new; + __CS_LOOP(old, new, v, 1, "ar"); + return new; } static __inline__ int atomic_inc_and_test(volatile atomic_t *v) { - int i; - - __asm__ __volatile__(" la 1,%0\n" - " l 0,%0\n" - "0: lr %1,0\n" - " ahi %1,1\n" - " cs 0,%1,0(1)\n" - " jl 0b" - : "+m" (*v), "=&d" (i) : : "0", "1", "cc" ); - return i != 0; + int old, new; + __CS_LOOP(old, new, v, 1, "ar"); + return new != 0; } static __inline__ void atomic_dec(volatile atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,%0\n" - "0: lr 1,0\n" - " ahi 1,-1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, 1, "sr"); } static __inline__ int atomic_dec_return(volatile atomic_t *v) { - int i; - __asm__ __volatile__(" la 1,%0\n" - " l 0,%0\n" - "0: lr %1,0\n" - " ahi %1,-1\n" - " cs 0,%1,0(1)\n" - " jl 0b" - : "+m" (*v), "=&d" (i) : : "0", "1", "cc" ); - return i; + int old, new; + __CS_LOOP(old, new, v, 1, "sr"); + return new; } static __inline__ int atomic_dec_and_test(volatile atomic_t *v) { - int i; - __asm__ __volatile__(" la 1,%0\n" - " l 0,%0\n" - "0: lr %1,0\n" - " ahi %1,-1\n" - " cs 0,%1,0(1)\n" - " jl 0b" - : "+m" (*v), "=&d" (i) : : "0", "1", "cc" ); - return i == 0; + int old, new; + __CS_LOOP(old, new, v, 1, "sr"); + return new == 0; } static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,%0\n" - "0: lr 1,0\n" - " nr 1,%1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : "d" (~(mask)) - : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, ~mask, "nr"); } static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,%0\n" - "0: lr 1,0\n" - " or 1,%1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : "d" (mask) : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, mask, "or"); } /* @@ -199,15 +138,14 @@ int retval; __asm__ __volatile__( - " la 1,%1\n" " lr 0,%2\n" - " cs 0,%3,0(1)\n" + " cs 0,%3,0(%1)\n" " ipm %0\n" " srl %0,28\n" "0:" - : "=&r" (retval), "+m" (*v) - : "d" (expected_oldval) , "d" (new_val) - : "0", "1", "cc"); + : "=&d" (retval) + : "a" (v), "d" (expected_oldval) , "d" (new_val) + : "0", "cc"); return retval; } @@ -218,13 +156,11 @@ atomic_compare_and_swap_spin(int expected_oldval,int new_val,atomic_t *v) { __asm__ __volatile__( - " la 2,%0\n" - "0: lr 1,%1\n" - " cs 1,%2,0(2)\n" + "0: lr 0,%1\n" + " cs 0,%2,0(%0)\n" " jl 0b\n" - : "+m" (*v) - : "d" (expected_oldval) , "d" (new_val) - : "cc", "1", "2"); + : : "a" (v), "d" (expected_oldval) , "d" (new_val) + : "cc", "0" ); } #define atomic_compare_and_swap_debug(where,from,to) \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/bitops.h linux.ac/include/asm-s390/bitops.h --- linux.vanilla/include/asm-s390/bitops.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/bitops.h Thu Apr 12 12:06:16 2001 @@ -475,9 +475,9 @@ " lhi 2,7\n" " xr 1,%1\n" " nr 2,1\n" - " srl 1,3(0)\n" + " srl 1,3\n" " la 1,0(1,%2)\n" - " ic %0,0(0,1)\n" + " ic %0,0(1)\n" " srl %0,0(2)\n" " n %0,%4\n" " la 2,0(2,%3)\n" @@ -501,9 +501,9 @@ " lhi 2,7\n" " xr 1,%1\n" " nr 2,1\n" - " srl 1,3(0)\n" + " srl 1,3\n" " la 1,0(1,%2)\n" - " ic %0,0(0,1)\n" + " ic %0,0(1)\n" " srl %0,0(2)\n" " n %0,%4\n" " la 2,0(2,%3)\n" @@ -527,9 +527,9 @@ " lhi 2,7\n" " xr 1,%1\n" " nr 2,1\n" - " srl 1,3(0)\n" + " srl 1,3\n" " la 1,0(1,%2)\n" - " ic %0,0(0,1)\n" + " ic %0,0(1)\n" " srl %0,0(2)\n" " n %0,%4\n" " la 2,0(2,%3)\n" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/ccwcache.h linux.ac/include/asm-s390/ccwcache.h --- linux.vanilla/include/asm-s390/ccwcache.h Tue Apr 3 17:32:27 2001 +++ linux.ac/include/asm-s390/ccwcache.h Thu Apr 12 12:06:16 2001 @@ -62,6 +62,7 @@ #define CQR_STATUS_DONE 0x04 /* request is completed successfully */ #define CQR_STATUS_ERROR 0x05 /* request is completed with error */ #define CQR_STATUS_FAILED 0x06 /* request is finally failed */ +#define CQR_STATUS_PENDING 0x07 /* request is waiting for interrupt - ERP only */ #define CQR_FLAGS_CHAINED 0x01 /* request is chained by another (last CCW is TIC) */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/chandev.h linux.ac/include/asm-s390/chandev.h --- linux.vanilla/include/asm-s390/chandev.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/chandev.h Thu Apr 12 12:06:16 2001 @@ -66,6 +66,12 @@ unsigned long irqflags, const char *devname, void *dev_id); +/* + * I originally believed this function wouldn't be necessary + * I subsequently found that reprobing failed in certain cases :-(, + * It is just a wrapper for free irq. + */ +void chandev_free_irq(unsigned int irq, void *dev_id); typedef enum { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/checksum.h linux.ac/include/asm-s390/checksum.h --- linux.vanilla/include/asm-s390/checksum.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/checksum.h Thu Apr 12 12:06:16 2001 @@ -36,14 +36,14 @@ extern inline unsigned int csum_partial_inline(const unsigned char * buff, int len, unsigned int sum) { + register_pair rp; + + rp.subreg.even = (unsigned long) buff; + rp.subreg.odd = (unsigned long) len; __asm__ __volatile__ ( - " lr 2,%1\n" /* address in gpr 2 */ - " lr 3,%2\n" /* length in gpr 3 */ - "0: cksm %0,2\n" /* do checksum on longs */ + "0: cksm %0,%1\n" /* do checksum on longs */ " jo 0b\n" - : "+&d" (sum) - : "d" (buff), "d" (len) - : "cc", "2", "3" ); + : "+&d" (sum), "+&a" (rp) : : "cc" ); return sum; } @@ -97,14 +97,16 @@ extern inline unsigned short csum_fold(unsigned int sum) { + register_pair rp; + __asm__ __volatile__ ( - " sr 3,3\n" /* %0 = H*65536 + L */ - " lr 2,%0\n" /* %0 = H L, R2/R3 = H L / 0 0 */ - " srdl 2,16\n" /* %0 = H L, R2/R3 = 0 H / L 0 */ - " alr 2,3\n" /* %0 = H L, R2/R3 = L H / L 0 */ - " alr %0,2\n" /* %0 = H+L+C L+H */ - " srl %0,16\n" /* %0 = H+L+C */ - : "+&d" (sum) : : "cc", "2", "3"); + " slr %N1,%N1\n" /* %0 = H L */ + " lr %1,%0\n" /* %0 = H L, %1 = H L 0 0 */ + " srdl %1,16\n" /* %0 = H L, %1 = 0 H L 0 */ + " alr %1,%N1\n" /* %0 = H L, %1 = L H L 0 */ + " alr %0,%1\n" /* %0 = H+L+C L+H */ + " srl %0,16\n" /* %0 = H+L+C */ + : "+&d" (sum), "=d" (rp) : : "cc" ); return ((unsigned short) ~sum); } #endif @@ -117,17 +119,16 @@ extern inline unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl) { + register_pair rp; unsigned long sum; + rp.subreg.even = (unsigned long) iph; + rp.subreg.odd = (unsigned long) ihl*4; __asm__ __volatile__ ( " sr %0,%0\n" /* set sum to zero */ - " lr 2,%1\n" /* address in gpr 2 */ - " lr 3,%2\n" /* length in gpr 3 */ - "0: cksm %0,2\n" /* do checksum on longs */ + "0: cksm %0,%1\n" /* do checksum on longs */ " jo 0b\n" - : "=&d" (sum) - : "d" (iph), "d" (ihl*4) - : "cc", "2", "3" ); + : "=&d" (sum), "+&a" (rp) : : "cc" ); return csum_fold(sum); } @@ -144,16 +145,21 @@ " alr %0,%1\n" /* sum += saddr */ " brc 12,0f\n" " ahi %0,1\n" /* add carry */ - "0: alr %0,%2\n" /* sum += daddr */ + "0:" + : "+&d" (sum) : "d" (saddr) : "cc" ); + __asm__ __volatile__ ( + " alr %0,%1\n" /* sum += daddr */ " brc 12,1f\n" " ahi %0,1\n" /* add carry */ - "1: alr %0,%3\n" /* sum += (len<<16) + (proto<<8) */ + "1:" + : "+&d" (sum) : "d" (daddr) : "cc" ); + __asm__ __volatile__ ( + " alr %0,%1\n" /* sum += (len<<16) + (proto<<8) */ " brc 12,2f\n" " ahi %0,1\n" /* add carry */ "2:" : "+&d" (sum) - : "d" (saddr), "d" (daddr), - "d" (((unsigned int) len<<16) + (unsigned int) proto) + : "d" (((unsigned int) len<<16) + (unsigned int) proto) : "cc" ); return sum; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/cpcmd.h linux.ac/include/asm-s390/cpcmd.h --- linux.vanilla/include/asm-s390/cpcmd.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-s390/cpcmd.h Thu Apr 12 12:06:16 2001 @@ -0,0 +1,14 @@ +/* + * arch/s390/kernel/cpcmd.h + * + * S390 version + * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), + */ + +#ifndef __CPCMD__ +#define __CPCMD__ + +extern void cpcmd(char *cmd, char *response, int rlen); + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/dasd.h linux.ac/include/asm-s390/dasd.h --- linux.vanilla/include/asm-s390/dasd.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/dasd.h Thu Apr 12 12:06:16 2001 @@ -5,11 +5,16 @@ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * * History of changes (starts July 2000) + * 02/01/01 added dynamic registration of ioctls */ #ifndef DASD_H #define DASD_H +#undef ERP_DEBUG /* enable debug messages */ +#undef ERP_FULL_ERP /* enable full ERP - experimental code !!!! */ +#define CONFIG_DASD_DYNAMIC + #include <linux/ioctl.h> #include <asm/irq.h> @@ -29,6 +34,10 @@ /* translate blocknumber of partition to absolute */ #define BIODASDRWTB _IOWR(IOCTL_LETTER,0,int) +typedef int(*dasd_ioctl_fn_t) (struct inode *inp, int no, long args); +int dasd_ioctl_no_register(int no, dasd_ioctl_fn_t handler); +int dasd_ioctl_no_unregister(int no, dasd_ioctl_fn_t handler); + #define DASD_NAME "dasd" #define DASD_PARTN_BITS 2 #define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS)) @@ -49,6 +58,10 @@ #define DASD_FORMAT_DEFAULT_BLOCKSIZE -1 #define DASD_FORMAT_DEFAULT_INTENSITY -1 +#define DASD_FORMAT_INTENS_WRITE_RECZERO 0x01 +#define DASD_FORMAT_INTENS_WRITE_HOMEADR 0x02 +#define DASD_FORMAT_INTENS_INVALIDATE 0x04 +#define DASD_FORMAT_INTENS_CDL 0x08 #ifdef __KERNEL__ #include <linux/version.h> #include <linux/major.h> @@ -135,9 +148,15 @@ typedef struct dasd_devreg_t { devreg_t devreg; /* the devreg itself */ /* build a linked list of devregs, needed for cleanup */ - struct dasd_devreg_t *next; + struct list_head list; } dasd_devreg_t; +typedef struct { + struct list_head list; + int no; + dasd_ioctl_fn_t handler; +} dasd_ioctl_list_t; + typedef enum { dasd_era_fatal = -1, /* no chance to recover */ dasd_era_none = 0, /* don't recover, everything alright */ @@ -168,7 +187,7 @@ int d_major = MAJOR(d_device->kdev); \ int d_minor = MINOR(d_device->kdev); \ printk(d_loglevel PRINTK_HEADER \ - "/dev/%s(%d:%d), 0x%04X on SCH 0x%x:" \ + "/dev/%s(%d:%d),%04X IRQ0x%x:" \ d_string "\n",d_name,d_major,d_minor,d_devno,d_irq,d_args ); \ } while(0) @@ -181,6 +200,7 @@ unsigned long blocks; /* size of volume in blocks */ unsigned int bp_block; /* bytes per block */ unsigned int s2b_shift; /* log2 (bp_block/512) */ + unsigned int pt_block; /* from which block to read the partn table */ } dasd_sizes_t; /* @@ -193,6 +213,38 @@ ccw_req_t *tail; } dasd_chanq_t; +#define DASD_DEVICE_FORMAT_STRING "Device: %p" +#define DASD_DEVICE_DEBUG_EVENT(d_level, d_device, d_str, d_data...)\ +do {\ + if ( d_device->debug_area != NULL )\ + debug_sprintf_event(d_device->debug_area,d_level,\ + DASD_DEVICE_FORMAT_STRING d_str "\n",\ + d_device, d_data);\ +} while(0); +#define DASD_DEVICE_DEBUG_EXCEPTION(d_level, d_device, d_str, d_data...)\ +do {\ + if ( d_device->debug_area != NULL )\ + debug_sprintf_exception(d_device->debug_area,d_level,\ + DASD_DEVICE_FORMAT_STRING d_str "\n",\ + d_device, d_data);\ +} while(0); + +#define DASD_DRIVER_FORMAT_STRING "Driver: <[%p]>" +#define DASD_DRIVER_DEBUG_EVENT(d_level, d_fn, d_str, d_data...)\ +do {\ + if ( dasd_debug_area != NULL )\ + debug_sprintf_event(dasd_debug_area, d_level,\ + DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\ + d_fn, d_data);\ +} while(0); +#define DASD_DRIVER_DEBUG_EXCEPTION(d_level, d_fn, d_str, d_data...)\ +do {\ + if ( dasd_debug_area != NULL )\ + debug_sprintf_exception(dasd_debug_area, d_level,\ + DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\ + d_fn, d_data);\ +} while(0); + struct dasd_device_t; struct request; @@ -230,7 +282,7 @@ typedef struct dasd_discipline_t { char ebcname[8]; /* a name used for tagging and printks */ char name[8]; /* a name used for tagging and printks */ - + int max_blocks; /* maximum number of blocks to be chained */ dasd_ck_id_fn_t id_check; /* to check sense data */ dasd_ck_characteristics_fn_t check_characteristics; /* to check the characteristics */ dasd_init_analysis_fn_t init_analysis; /* to start the analysis of the volume */ @@ -251,9 +303,13 @@ struct dasd_discipline_t *next; /* used for list of disciplines */ } dasd_discipline_t; +#define DASD_MAJOR_INFO_REGISTERED 1 +#define DASD_MAJOR_INFO_IS_STATIC 2 + typedef struct major_info_t { - struct major_info_t *next; + struct list_head list; struct dasd_device_t **dasd_device; + int flags; struct gendisk gendisk; /* actually contains the major number */ } __attribute__ ((packed)) major_info_t; @@ -278,6 +334,7 @@ struct dasd_chanq_t queue; wait_queue_head_t wait_q; request_queue_t request_queue; + struct timer_list timer; devstat_t dev_status; /* needed ONLY!! for request_irq */ dasd_sizes_t sizes; char name[16]; /* The name of the device in /dev */ @@ -300,7 +357,7 @@ #define DASD_DEVICE_LEVEL_ANALYSIS_PENDING 0x02 #define DASD_DEVICE_LEVEL_ANALYSIS_PREPARED 0x04 #define DASD_DEVICE_LEVEL_ANALYSED 0x08 -#define DASD_DEVICE_LEVEL_PARTITIONED 0x10 +#define DASD_DEVICE_LEVEL_ONLINE 0x10 int dasd_init (void); void dasd_discipline_enq (dasd_discipline_t *); @@ -312,8 +369,12 @@ int dasd_chanq_deq (dasd_chanq_t *, ccw_req_t *); 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 *); +extern int (*genhd_dasd_name) (char *, int, int, struct gendisk *); +extern int (*genhd_dasd_fillgeo) (int, struct hd_geometry *); int dasd_oper_handler (int irq, devreg_t * devreg); +void dasd_schedule_bh (dasd_device_t *); + +debug_info_t *dasd_debug_area; #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/debug.h linux.ac/include/asm-s390/debug.h --- linux.vanilla/include/asm-s390/debug.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/debug.h Thu Apr 12 12:06:16 2001 @@ -19,9 +19,8 @@ struct { unsigned long long clock:52; unsigned long long exception:1; - unsigned long long used:1; - unsigned long long unused:1; - unsigned long long cpuid:9; + unsigned long long level:3; + unsigned long long cpuid:8; } fields; unsigned long long stck; @@ -29,6 +28,9 @@ void* caller; } __attribute__((packed)); + +#define __DEBUG_FEATURE_VERSION 1 /* version of debug feature */ + #ifdef __KERNEL__ #include <linux/version.h> #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) @@ -45,7 +47,6 @@ #define DEBUG_MAX_VIEWS 10 /* max number of views in proc fs */ #define DEBUG_MAX_PROCF_LEN 16 /* max length for a proc file name */ #define DEBUG_DEFAULT_LEVEL 3 /* initial debug level */ -#define DEBUG_FEATURE_VERSION 1 /* version of debug feature */ #define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */ @@ -103,43 +104,98 @@ debug_header_proc_t* header_proc; debug_format_proc_t* format_proc; debug_input_proc_t* input_proc; + void* private_data; }; extern struct debug_view debug_hex_ascii_view; extern struct debug_view debug_raw_view; +extern struct debug_view debug_sprintf_view; + +/* do NOT use the _common functions */ + +debug_entry_t* debug_event_common(debug_info_t* id, int level, + const void* data, int length); + +debug_entry_t* debug_exception_common(debug_info_t* id, int level, + const void* data, int length); + +/* Debug Feature API: */ debug_info_t* debug_register(char* name, int pages_index, int nr_areas, - int buf_size); + int buf_size); + void debug_unregister(debug_info_t* id); void debug_set_level(debug_info_t* id, int new_level); -debug_entry_t* debug_event(debug_info_t* id, int level, void* data, - int length); -debug_entry_t* debug_int_event(debug_info_t* id, int level, - unsigned int tag); -debug_entry_t* debug_text_event(debug_info_t* id, int level, - const char* txt); - -debug_entry_t* debug_exception(debug_info_t* id, int level, void* data, - int length); -debug_entry_t* debug_int_exception(debug_info_t* id, int level, - unsigned int tag); -debug_entry_t* debug_text_exception(debug_info_t* id, int level, - const char* txt); +extern inline debug_entry_t* +debug_event(debug_info_t* id, int level, void* data, int length) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,data,length); +} + +extern inline debug_entry_t* +debug_int_event(debug_info_t* id, int level, unsigned int tag) +{ + unsigned int t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,&t,sizeof(unsigned int)); +} -static inline debug_entry_t * +extern inline debug_entry_t * debug_long_event (debug_info_t* id, int level, unsigned long tag) { - unsigned long t=tag; - return debug_event(id,level,&t,sizeof(unsigned long)); + unsigned long t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,&t,sizeof(unsigned long)); +} + +extern inline debug_entry_t* +debug_text_event(debug_info_t* id, int level, const char* txt) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,txt,strlen(txt)); } -static inline debug_entry_t * + +extern debug_entry_t * +debug_sprintf_event(debug_info_t* id,int level,char *string,...); + + +extern inline debug_entry_t* +debug_exception(debug_info_t* id, int level, void* data, int length) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,data,length); +} + +extern inline debug_entry_t* +debug_int_exception(debug_info_t* id, int level, unsigned int tag) +{ + unsigned int t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,&t,sizeof(unsigned int)); +} + +extern inline debug_entry_t * debug_long_exception (debug_info_t* id, int level, unsigned long tag) { - unsigned long t=tag; - return debug_exception(id,level,&t,sizeof(unsigned long)); + unsigned long t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,&t,sizeof(unsigned long)); +} + +extern inline debug_entry_t* +debug_text_exception(debug_info_t* id, int level, const char* txt) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,txt,strlen(txt)); } + + +extern debug_entry_t * +debug_sprintf_exception(debug_info_t* id,int level,char *string,...); + int debug_register_view(debug_info_t* id, struct debug_view* view); int debug_unregister_view(debug_info_t* id, struct debug_view* view); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/delay.h linux.ac/include/asm-s390/delay.h --- linux.vanilla/include/asm-s390/delay.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/delay.h Thu Apr 12 12:06:16 2001 @@ -8,7 +8,7 @@ * Derived from "include/asm-i386/delay.h" * Copyright (C) 1993 Linus Torvalds * - * Delay routines calling functions in arch/i386/lib/delay.c + * Delay routines calling functions in arch/s390/lib/delay.c */ #ifndef _S390_DELAY_H diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/div64.h linux.ac/include/asm-s390/div64.h --- linux.vanilla/include/asm-s390/div64.h Fri May 12 19:41:44 2000 +++ linux.ac/include/asm-s390/div64.h Thu Apr 12 12:06:16 2001 @@ -1,10 +1,44 @@ #ifndef __S390_DIV64 #define __S390_DIV64 -#define do_div(n,base) ({ \ -int __res; \ -__res = ((unsigned long) n) % (unsigned) base; \ -n = ((unsigned long) n) / (unsigned) base; \ -__res; }) +/* for do_div "base" needs to be smaller than 2^31-1 */ + +#define do_div(n, base) ({ \ + unsigned long long __n = (n); \ + unsigned long __r; \ + \ + asm (" slr 0,0\n" \ + " l 1,%1\n" \ + " srdl 0,1\n" \ + " dr 0,%2\n" \ + " alr 1,1\n" \ + " alr 0,0\n" \ + " lhi 2,1\n" \ + " n 2,%1\n" \ + " alr 0,2\n" \ + " clr 0,%2\n" \ + " jl 0f\n" \ + " slr 0,%2\n" \ + " ahi 1,1\n" \ + "0: st 1,%1\n" \ + " l 1,4+%1\n" \ + " srdl 0,1\n" \ + " dr 0,%2\n" \ + " alr 1,1\n" \ + " alr 0,0\n" \ + " lhi 2,1\n" \ + " n 2,4+%1\n" \ + " alr 0,2\n" \ + " clr 0,%2\n" \ + " jl 1f\n" \ + " slr 0,%2\n" \ + " ahi 1,1\n" \ + "1: st 1,4+%1\n" \ + " lr %0,0" \ + : "=d" (__r), "+m" (__n) \ + : "d" (base) : "0", "1", "2" ); \ + (n) = (__n); \ + __r; \ +}) #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/ebcdic.h linux.ac/include/asm-s390/ebcdic.h --- linux.vanilla/include/asm-s390/ebcdic.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/ebcdic.h Thu Apr 12 12:06:16 2001 @@ -24,24 +24,18 @@ extern __inline__ void codepage_convert(const __u8 *codepage, volatile __u8 * addr, int nr) { - static const __u16 tr_op[] = { 0xDC00, 0x1000,0x3000 }; + if (nr <= 0) + return; __asm__ __volatile__( - " lr 1,%0\n" - " lr 2,%1\n" - " lr 3,%2\n" - " ahi 2,-256\n" - " jm 1f\n" - "0: tr 0(256,1),0(3)\n" - " ahi 1,256\n" - " ahi 2,-256\n" - " jp 0b\n" - "1: ahi 2,255\n" - " jm 2f\n" - " ex 2,%3\n" - "2:" - : /* no output */ - : "a" (addr), "d" (nr), "a" (codepage), "m" (tr_op[0]) - : "cc", "memory", "1", "2", "3" ); + " bras 1,1f\n" + " tr 0(1,%0),0(%2)\n" + "0: la %0,256(%0)\n" + " tr 0(256,%0),0(%2)\n" + "1: ahi %1,-256\n" + " jp 0b\n" + " ex %1,0(1)" + : "+&a" (addr), "+&a" (nr-1) + : "a" (codepage) : "cc", "memory", "1" ); } #define ASCEBC(addr,nr) codepage_convert(_ascebc, addr, nr) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/elf.h linux.ac/include/asm-s390/elf.h --- linux.vanilla/include/asm-s390/elf.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/elf.h Thu Apr 12 12:06:16 2001 @@ -31,7 +31,8 @@ * This is used to ensure we don't load something for the wrong architecture. */ #define elf_check_arch(x) \ - ((x)->e_machine == ELF_ARCH && (x)->e_ident[EI_CLASS] == ELF_CLASS) + (((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \ + && (x)->e_ident[EI_CLASS] == ELF_CLASS) /* For SVR4/S390 the function pointer to be registered with `atexit` is passed in R14. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/irq.h linux.ac/include/asm-s390/irq.h --- linux.vanilla/include/asm-s390/irq.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/irq.h Thu Apr 12 12:06:16 2001 @@ -1,5 +1,5 @@ -#ifndef __irq_h -#define __irq_h +#ifndef _ASM_IRQ_H +#define _ASM_IRQ_H #include <linux/config.h> #ifdef __KERNEL__ @@ -19,28 +19,6 @@ extern int enable_irq(unsigned int); /* - * Interrupt controller descriptor. This is all we need - * to describe about the low-level hardware. - */ -struct hw_interrupt_type { - const __u8 *typename; - int (*handle)(unsigned int irq, - int cpu, - struct pt_regs * regs); - int (*enable) (unsigned int irq); - int (*disable)(unsigned int irq); -}; - -/* - * Status: reason for being disabled: somebody has - * done a "disable_irq()" or we must not re-enter the - * already executing irq.. - */ -#define IRQ_INPROGRESS 1 -#define IRQ_DISABLED 2 -#define IRQ_PENDING 4 - -/* * path management control word */ typedef struct { @@ -86,7 +64,7 @@ __u32 pfch : 1; /* prefetch */ __u32 isic : 1; /* initial-status interruption control */ __u32 alcc : 1; /* address-limit checking control */ - __u32 ssi : 1; /* suppress-suspended interruption */ + __u32 ssi : 1; /* supress-suspended interruption */ __u32 zcc : 1; /* zero condition code */ __u32 ectl : 1; /* extended control */ __u32 pno : 1; /* path not operational */ @@ -186,7 +164,7 @@ typedef struct { __u8 cmd_code;/* command code */ - __u8 flags; /* flags, like IDA addressing, etc. */ + __u8 flags; /* flags, like IDA adressing, etc. */ __u16 count; /* byte count */ __u32 cda; /* data address */ } __attribute__ ((packed,aligned(8))) ccw1_t; @@ -456,24 +434,10 @@ typedef int (* adapter_int_handler_t)( __u32 intparm ); -struct s390_irqaction { - io_handler_func_t handler; - unsigned long flags; - const char *name; - devstat_t *dev_id; -}; - -/* - * This is the "IRQ descriptor", which contains various information - * about the irq, including what kind of hardware handling it has, - * whether it is disabled etc etc. - * - * Pad this out to 32 bytes for cache and indexing reasons. - */ typedef struct { - unsigned int status; /* IRQ status - IRQ_INPROGRESS, IRQ_DISABLED */ - struct hw_interrupt_type *handler; /* handle/enable/disable functions */ - struct s390_irqaction *action; /* IRQ action list */ + io_handler_func_t handler; /* interrupt handler routine */ + const char *name; /* device name */ + devstat_t *dev_id; /* device status block */ } irq_desc_t; typedef struct { @@ -531,9 +495,8 @@ /* * do_IO() * - * Start a S/390 channel program. When the interrupt arrives - * handle_IRQ_event() is called, which eventually calls the - * IRQ handler, either immediately, delayed (dev-end missing, + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, * or sense required) or never (no IRQ handler registered - * should never occur, as the IRQ (subchannel ID) should be * disabled if no handler is present. Depending on the action @@ -606,8 +569,6 @@ const char *devname, void *dev_id); -extern int handle_IRQ_event( unsigned int irq, int cpu, struct pt_regs *); - extern int set_cons_dev(int irq); extern int reset_cons_dev(int irq); extern int wait_cons_dev(int irq); @@ -621,16 +582,13 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "STSCH 0(%2)\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr) - : "cc", "1" ); + " lr 1,%1\n" + " stsch 0(%2)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000), "a" (addr) + : "cc", "1" ); return ccode; } @@ -639,15 +597,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "MSCH 0(%2)\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr) + " lr 1,%1\n" + " msch 0(%2)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L), "a" (addr) : "cc", "1" ); return ccode; } @@ -657,12 +612,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - " lgr 1,%1\n" + " lr 1,%1\n" " msch 0(%2)\n" "0: ipm %0\n" " srl %0,28\n" "1:\n" +#ifdef CONFIG_ARCH_S390X ".section .fixup,\"ax\"\n" "2: l %0,%3\n" " jg 1b\n" @@ -671,12 +626,12 @@ " .align 8\n" " .quad 0b,2b\n" ".previous" -#else " lr 1,%1\n" " msch 0(%2)\n" "0: ipm %0\n" " srl %0,28\n" "1:\n" +#else ".section .fixup,\"ax\"\n" "2: l %0,%3\n" " bras 1,3f\n" @@ -690,7 +645,7 @@ ".previous" #endif : "=d" (ccode) - : "r" (irq | 0x10000L), "a" (addr), "i" (__LC_PGM_ILC) + : "d" (irq | 0x10000L), "a" (addr), "i" (__LC_PGM_ILC) : "cc", "1" ); return ccode; } @@ -700,15 +655,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "TSCH 0(%2)\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr) + " lr 1,%1\n" + " tsch 0(%2)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L), "a" (addr) : "cc", "1" ); return ccode; } @@ -718,10 +670,11 @@ int ccode; __asm__ __volatile__( - "TPI 0(%1)\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "a" (addr) + " tpi 0(%1)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "a" (addr) : "cc", "1" ); return ccode; } @@ -731,15 +684,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "SSCH 0(%2)\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr) + " lr 1,%1\n" + " ssch 0(%2)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L), "a" (addr) : "cc", "1" ); return ccode; } @@ -749,15 +699,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "RSCH\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L) + " lr 1,%1\n" + " rsch\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L) : "cc", "1" ); return ccode; } @@ -767,15 +714,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "CSCH\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L) + " lr 1,%1\n" + " csch\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L) : "cc", "1" ); return ccode; } @@ -785,15 +729,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "HSCH\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L) + " lr 1,%1\n" + " hsch\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L) : "cc", "1" ); return ccode; } @@ -803,9 +744,9 @@ int ccode; __asm__ __volatile__( - "IAC 1\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" + " iac 1\n" + " ipm %0\n" + " srl %0,28" : "=d" (ccode) : : "cc", "1" ); return ccode; } @@ -815,15 +756,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "RCHP\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (chpid) + " lr 1,%1\n" + " rchp\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (chpid) : "cc", "1" ); return ccode; } @@ -850,16 +788,16 @@ __asm__ __volatile__( #ifdef CONFIG_ARCH_S390X - "SAM31\n\t" - "DIAG %1,0,0x210\n\t" - "SAM64\n\t" -#else - "LR 1,%1\n\t" - ".long 0x83110210\n\t" -#endif - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "a" (addr) + " sam31\n" + " diag %1,0,0x210\n" + " sam64\n" +#else + " diag %1,0,0x210\n" +#endif + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "a" (addr) : "cc" ); return ccode; } @@ -885,15 +823,9 @@ static inline void irq_enter(int cpu, unsigned int irq) { hardirq_enter(cpu); -#ifdef CONFIG_ARCH_S390X while (atomic_read(&global_irq_lock) != 0) { eieio(); } -#else - while (test_bit(0,&global_irq_lock)) { - eieio(); - } -#endif } static inline void irq_exit(int cpu, unsigned int irq) @@ -957,6 +889,9 @@ spin_lock_irqsave(&(ioinfo[irq]->irq_lock), flags) #define s390irq_spin_unlock_irqrestore(irq,flags) \ spin_unlock_irqrestore(&(ioinfo[irq]->irq_lock), flags) + +#define touch_nmi_watchdog() do { } while(0) + #endif /* __KERNEL__ */ #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/irqextras390.h linux.ac/include/asm-s390/irqextras390.h --- linux.vanilla/include/asm-s390/irqextras390.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/irqextras390.h Thu Jan 1 01:00:00 1970 @@ -1,151 +0,0 @@ -/* - * include/asm-s390/irqextras390.h - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - */ - -#ifndef __irqextras390_h -#define __irqextras390_h - -/* - irqextras390.h by D.J. Barrow - if you are a bitfield fan & are paranoid that ansi dosen't - give hard definitions about the size of an int or long you might - prefer these definitions as an alternative. - -*/ - -#include <linux/types.h> - -typedef struct -{ - unsigned key:4; - unsigned s:1; - unsigned l:1; - unsigned cc:2; - unsigned f:1; - unsigned p:1; - unsigned i:1; - unsigned a:1; - unsigned u:1; - unsigned z:1; - unsigned e:1; - unsigned n:1; - unsigned zero:1; - - unsigned fc_start:1; - unsigned fc_halt:1; - unsigned fc_clear:1; - - unsigned ac_resume_pending:1; - unsigned ac_start_pending:1; - unsigned ac_halt_pending:1; - unsigned ac_clear_pending:1; - unsigned ac_subchannel_active:1; - unsigned ac_device_active:1; - unsigned ac_suspended:1; - - unsigned sc_alert:1; - unsigned sc_intermediate:1; - unsigned sc_primary:1; - unsigned sc_seconary:1; - unsigned sc_status_pending:1; - - __u32 ccw_address; - - unsigned dev_status_attention:1; - unsigned dev_status_modifier:1; - unsigned dev_status_control_unit_end:1; - unsigned dev_status_busy:1; - unsigned dev_status_channel_end:1; - unsigned dev_status_device_end:1; - unsigned dev_status_unit_check:1; - unsigned dev_status_unit_exception:1; - - unsigned sch_status_program_cont_int:1; - unsigned sch_status_incorrect_length:1; - unsigned sch_status_program_check:1; - unsigned sch_status_protection_check:1; - unsigned sch_status_channel_data_check:1; - unsigned sch_status_channel_control_check:1; - unsigned sch_status_interface_control_check:1; - unsigned sch_status_chaining_check:1; - - __u16 byte_count; -} scsw_bits_t __attribute__((packed)); - -typedef struct -{ - __u32 flags; - __u32 ccw_address; - __u8 dev_status; - __u8 sch_status; - __u16 byte_count; -} scsw_words_t __attribute__((packed)); - -typedef struct -{ - __u8 cmd_code; - - unsigned cd:1; - unsigned cc:1; - unsigned sli:1; - unsigned skip:1; - unsigned pci:1; - unsigned ida:1; - unsigned s:1; - unsigned res1:1; - - __u16 count; - - __u32 ccw_data_address; -} ccw1_bits_t __attribute__((packed,aligned(8))); - -typedef struct -{ - __u32 interruption_parm; - unsigned key:4; - unsigned s:1; - unsigned res1:3; - unsigned f:1; - unsigned p:1; - unsigned i:1; - unsigned a:1; - unsigned u:1; - __u8 lpm; - unsigned l:1; - unsigned res2:7; - ccw1_bits_t *ccw_program_address; -} orb_bits_t __attribute__((packed)); - -void fixchannelprogram(orb_bits_t *orbptr); -void fixccws(ccw1_bits_t *ccwptr); -enum -{ - ccw_write=0x1, - ccw_read=0x2, - ccw_read_backward=0xc, - ccw_control=0x3, - ccw_sense=0x4, - ccw_sense_id=0xe4, - ccw_transfer_in_channel0=0x8, - ccw_transfer_in_channel1=0x8, - ccw_set_x_mode=0xc3, // according to uli's lan notes - ccw_nop=0x3 // according to uli's notes again - // n.b. ccw_control clashes with this - // so I presume its a special case of - // control -}; - - - -#endif - - - - - - - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/major.h linux.ac/include/asm-s390/major.h --- linux.vanilla/include/asm-s390/major.h Fri May 12 19:41:44 2000 +++ linux.ac/include/asm-s390/major.h Thu Jan 1 01:00:00 1970 @@ -1,150 +0,0 @@ -#ifndef _LINUX_MAJOR_H -#define _LINUX_MAJOR_H - -/* - * This file has definitions for major device numbers. - * For the device number assignments, see Documentation/devices.txt. - */ - -/* limits */ - -/* - * Important: Don't change this to 256. Major number 255 is and must be - * reserved for future expansion into a larger dev_t space. - */ -#define MAX_CHRDEV 255 -#define MAX_BLKDEV 255 - -#define UNNAMED_MAJOR 0 -#define MEM_MAJOR 1 -#define RAMDISK_MAJOR 1 -#define FLOPPY_MAJOR 2 -#define PTY_MASTER_MAJOR 2 -#define IDE0_MAJOR 3 -#define PTY_SLAVE_MAJOR 3 -#define HD_MAJOR IDE0_MAJOR -#define TTY_MAJOR 4 -#define TTYAUX_MAJOR 5 -#define LP_MAJOR 6 -#define VCS_MAJOR 7 -#define LOOP_MAJOR 7 -#define SCSI_DISK0_MAJOR 8 -#define SCSI_TAPE_MAJOR 9 -#define MD_MAJOR 9 -#define MISC_MAJOR 10 -#define SCSI_CDROM_MAJOR 11 -#define QIC02_TAPE_MAJOR 12 -#define XT_DISK_MAJOR 13 -#define SOUND_MAJOR 14 -#define CDU31A_CDROM_MAJOR 15 -#define JOYSTICK_MAJOR 15 -#define GOLDSTAR_CDROM_MAJOR 16 -#define OPTICS_CDROM_MAJOR 17 -#define SANYO_CDROM_MAJOR 18 -#define CYCLADES_MAJOR 19 -#define CYCLADESAUX_MAJOR 20 -#define MITSUMI_X_CDROM_MAJOR 20 -#define MFM_ACORN_MAJOR 21 /* ARM Linux /dev/mfm */ -#define SCSI_GENERIC_MAJOR 21 -#define Z8530_MAJOR 34 -#define DIGI_MAJOR 23 -#define IDE1_MAJOR 22 -#define DIGICU_MAJOR 22 -#define MITSUMI_CDROM_MAJOR 23 -#define CDU535_CDROM_MAJOR 24 -#define STL_SERIALMAJOR 24 -#define MATSUSHITA_CDROM_MAJOR 25 -#define STL_CALLOUTMAJOR 25 -#define MATSUSHITA_CDROM2_MAJOR 26 -#define QIC117_TAPE_MAJOR 27 -#define MATSUSHITA_CDROM3_MAJOR 27 -#define MATSUSHITA_CDROM4_MAJOR 28 -#define STL_SIOMEMMAJOR 28 -#define ACSI_MAJOR 28 -#define AZTECH_CDROM_MAJOR 29 -#define GRAPHDEV_MAJOR 29 /* SparcLinux & Linux/68k /dev/fb */ -#define SHMIQ_MAJOR 85 /* Linux/mips, SGI /dev/shmiq */ -#define CM206_CDROM_MAJOR 32 -#define IDE2_MAJOR 33 -#define IDE3_MAJOR 34 -#define NETLINK_MAJOR 36 -#define PS2ESDI_MAJOR 36 -#define IDETAPE_MAJOR 37 -#define Z2RAM_MAJOR 37 -#define APBLOCK_MAJOR 38 /* AP1000 Block device */ -#define DDV_MAJOR 39 /* AP1000 DDV block device */ -#define NBD_MAJOR 43 /* Network block device */ -#define RISCOM8_NORMAL_MAJOR 48 -#define DAC960_MAJOR 48 /* 48..55 */ -#define RISCOM8_CALLOUT_MAJOR 49 -#define MKISS_MAJOR 55 -#define DSP56K_MAJOR 55 /* DSP56001 processor device */ - -#define IDE4_MAJOR 56 -#define IDE5_MAJOR 57 - -#define SCSI_DISK1_MAJOR 65 -#define SCSI_DISK2_MAJOR 66 -#define SCSI_DISK3_MAJOR 67 -#define SCSI_DISK4_MAJOR 68 -#define SCSI_DISK5_MAJOR 69 -#define SCSI_DISK6_MAJOR 70 -#define SCSI_DISK7_MAJOR 71 - - -#define LVM_BLK_MAJOR 58 /* Logical Volume Manager */ - -#define COMPAQ_SMART2_MAJOR 72 -#define COMPAQ_SMART2_MAJOR1 73 -#define COMPAQ_SMART2_MAJOR2 74 -#define COMPAQ_SMART2_MAJOR3 75 -#define COMPAQ_SMART2_MAJOR4 76 -#define COMPAQ_SMART2_MAJOR5 77 -#define COMPAQ_SMART2_MAJOR6 78 -#define COMPAQ_SMART2_MAJOR7 79 - -#define SPECIALIX_NORMAL_MAJOR 75 -#define SPECIALIX_CALLOUT_MAJOR 76 - -#define DASD_MAJOR 94 - -#define LVM_CHAR_MAJOR 109 /* Logical Volume Manager */ - -#define MDISK_MAJOR 64 - -#define I2O_MAJOR 80 /* 80->87 */ - -#define IDE6_MAJOR 88 -#define IDE7_MAJOR 89 -#define IDE8_MAJOR 90 -#define IDE9_MAJOR 91 - -#define AURORA_MAJOR 79 - -#define RTF_MAJOR 150 -#define RAW_MAJOR 162 - -#define USB_ACM_MAJOR 166 -#define USB_ACM_AUX_MAJOR 167 -#define USB_CHAR_MAJOR 180 - -#define UNIX98_PTY_MASTER_MAJOR 128 -#define UNIX98_PTY_MAJOR_COUNT 8 -#define UNIX98_PTY_SLAVE_MAJOR (UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT) - -/* - * Tests for SCSI devices. - */ - -#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ - ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR)) - -#define SCSI_BLK_MAJOR(M) \ - (SCSI_DISK_MAJOR(M) \ - || (M) == SCSI_CDROM_MAJOR) - -static __inline__ int scsi_blk_major(int m) { - return SCSI_BLK_MAJOR(m); -} - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/mathemu.h linux.ac/include/asm-s390/mathemu.h --- linux.vanilla/include/asm-s390/mathemu.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/mathemu.h Thu Apr 12 12:06:16 2001 @@ -22,28 +22,6 @@ extern int math_emu_stfpc(__u8 *, struct pt_regs *); extern int math_emu_srnm(__u8 *, struct pt_regs *); - -extern __u64 __adddf3(__u64,__u64); -extern __u64 __subdf3(__u64,__u64); -extern __u64 __muldf3(__u64,__u64); -extern __u64 __divdf3(__u64,__u64); -extern long __cmpdf2(__u64,__u64); -extern __u64 __negdf2(__u64); -extern __u64 __absdf2(__u64); -extern __u32 __addsf3(__u32,__u32); -extern __u32 __subsf3(__u32,__u32); -extern __u32 __mulsf3(__u32,__u32); -extern __u32 __divsf3(__u32,__u32); -extern __u32 __negsf2(__u32); -extern __u32 __abssf2(__u32); -extern long __cmpsf2(__u32,__u32); -extern __u32 __truncdfsf2(__u64); -extern __u32 __fixsfsi(__u32); -extern __u32 __fixdfsi(__u64); -extern __u64 __floatsidf(__u32); -extern __u32 __floatsisf(__u32); -extern __u64 __extendsfdf2(__u32); - #endif /* __MATHEMU__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/misc390.h linux.ac/include/asm-s390/misc390.h --- linux.vanilla/include/asm-s390/misc390.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/misc390.h Thu Jan 1 01:00:00 1970 @@ -1,15 +0,0 @@ -/* - * include/asm-s390/misc390.h - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - */ - -#define allocaligned2(type,name,number,align) \ - __u8 name##buff[(sizeof(type)*(number+1))-1]; \ - type *name=(type *)(((__u32)(&name##buff[align-1]))&(-align)) - -#define allocaligned(type,name,number) allocaligned2(type,name,number,__alignof__(type)) - -extern void s390_daemonize(char *name,unsigned long mask,int use_init_fs); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/page.h linux.ac/include/asm-s390/page.h --- linux.vanilla/include/asm-s390/page.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/page.h Thu Apr 12 12:06:16 2001 @@ -9,6 +9,9 @@ #ifndef _S390_PAGE_H #define _S390_PAGE_H +#include <asm/setup.h> +#include <asm/types.h> + /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 12 #define PAGE_SIZE (1UL << PAGE_SHIFT) @@ -17,12 +20,44 @@ #ifdef __KERNEL__ #ifndef __ASSEMBLY__ -/* - * gcc uses builtin, i.e. MVCLE for both operations - */ +static inline void clear_page(void *page) +{ + register_pair rp; + + rp.subreg.even = (unsigned long) page; + rp.subreg.odd = (unsigned long) 4096; + asm volatile (" slr 1,1\n" + " mvcl %0,0" + : "+&a" (rp) : : "memory", "1" ); +} -#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) -#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) +static inline void copy_page(void *to, void *from) +{ + if (MACHINE_HAS_MVPG) + asm volatile (" sr 0,0\n" + " mvpg %0,%1" + : : "a" ((void *)(to)), "a" ((void *)(from)) + : "memory", "0" ); + else + asm volatile (" mvc 0(256,%0),0(%1)\n" + " mvc 256(256,%0),256(%1)\n" + " mvc 512(256,%0),512(%1)\n" + " mvc 768(256,%0),768(%1)\n" + " mvc 1024(256,%0),1024(%1)\n" + " mvc 1280(256,%0),1280(%1)\n" + " mvc 1536(256,%0),1536(%1)\n" + " mvc 1792(256,%0),1792(%1)\n" + " mvc 2048(256,%0),2048(%1)\n" + " mvc 2304(256,%0),2304(%1)\n" + " mvc 2560(256,%0),2560(%1)\n" + " mvc 2816(256,%0),2816(%1)\n" + " mvc 3072(256,%0),3072(%1)\n" + " mvc 3328(256,%0),3328(%1)\n" + " mvc 3584(256,%0),3584(%1)\n" + " mvc 3840(256,%0),3840(%1)\n" + : : "a"((void *)(to)),"a"((void *)(from)) + : "memory" ); +} #define clear_user_page(page, vaddr) clear_page(page) #define copy_user_page(to, from, vaddr) copy_page(to, from) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/pgalloc.h linux.ac/include/asm-s390/pgalloc.h --- linux.vanilla/include/asm-s390/pgalloc.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/pgalloc.h Thu Apr 12 12:06:16 2001 @@ -30,12 +30,14 @@ extern __inline__ pgd_t* get_pgd_slow(void) { + pgd_t *ret; int i; - pgd_t *pgd,*ret = (pgd_t *)__get_free_pages(GFP_KERNEL,1); - if (ret) - for (i=0,pgd=ret;i<USER_PTRS_PER_PGD;i++,pgd++) - pmd_clear(pmd_offset(pgd,i*PGDIR_SIZE)); - return ret; + + ret = (pgd_t *) __get_free_pages(GFP_KERNEL,1); + if (ret != NULL) + for (i = 0; i < USER_PTRS_PER_PGD; i++) + pmd_clear(pmd_offset(ret + i, i*PGDIR_SIZE)); + return ret; } extern __inline__ pgd_t* get_pgd_fast(void) @@ -76,40 +78,40 @@ /* * page middle directory allocation/free routines. - * We don't use pmd cache, so these are dummy routines. + * We don't use pmd cache, so these are dummy routines. This + * code never triggers because the pgd will always be present. */ -extern __inline__ pmd_t *get_pmd_fast(void) -{ - return (pmd_t *)0; -} - -extern __inline__ void free_pmd_fast(pmd_t *pmd) -{ -} - -extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address) -{ - return (pmd_t *) pgd; -} - -extern __inline__ void free_pmd_slow(pmd_t *pmd) -{ +#define pmd_alloc_one_fast(mm, address) ({ BUG(); ((pmd_t *)1); }) +#define pmd_alloc_one(mm,address) ({ BUG(); ((pmd_t *)2); }) +#define pmd_free(x) do { } while (0) +#define pgd_populate(mm, pmd, pte) BUG() + +extern inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, pte_t *pte) +{ + pmd_val(pmd[0]) = _PAGE_TABLE + __pa(pte); + pmd_val(pmd[1]) = _PAGE_TABLE + __pa(pte+256); + pmd_val(pmd[2]) = _PAGE_TABLE + __pa(pte+512); + pmd_val(pmd[3]) = _PAGE_TABLE + __pa(pte+768); } -extern inline void pmd_free(pmd_t * pmd) -{ -} - -#define pmd_free_kernel pmd_free -#define pmd_alloc_kernel pmd_alloc - /* * page table entry allocation/free routines. */ -extern pte_t empty_bad_pte_table[]; -extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted); +extern inline pte_t * pte_alloc_one(struct mm_struct *mm, unsigned long vmaddr) +{ + pte_t *pte; + int i; -extern __inline__ pte_t* get_pte_fast(void) + pte = (pte_t *) __get_free_page(GFP_KERNEL); + if (pte != NULL) { + for (i=0; i < PTRS_PER_PTE; i++) + pte_clear(pte+i); + } + return pte; +} + +extern __inline__ pte_t * +pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) { unsigned long *ret = (unsigned long *) pte_quicklist; @@ -121,44 +123,19 @@ return (pte_t *)ret; } -extern __inline__ void free_pte_fast(pte_t *pte) +extern __inline__ void pte_free_fast(pte_t *pte) { - if (pte == empty_bad_pte_table) - return; *(unsigned long *)pte = (unsigned long) pte_quicklist; pte_quicklist = (unsigned long *) pte; pgtable_cache_size++; } -extern __inline__ void free_pte_slow(pte_t *pte) +extern __inline__ void pte_free_slow(pte_t *pte) { free_page((unsigned long) pte); } -extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long vmaddr) -{ - unsigned long offset; - - offset = (vmaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - unsigned long page = (unsigned long) get_pte_fast(); - - if (!page) - return get_pte_slow(pmd, offset); - pmd_val(pmd[0]) = _PAGE_TABLE + __pa(page); - pmd_val(pmd[1]) = _PAGE_TABLE + __pa(page+1024); - pmd_val(pmd[2]) = _PAGE_TABLE + __pa(page+2048); - pmd_val(pmd[3]) = _PAGE_TABLE + __pa(page+3072); - return (pte_t *) page + offset; - } - if (pmd_bad(*pmd)) - BUG(); - return (pte_t *) pmd_page(*pmd) + offset; -} - -#define pte_alloc_kernel(pmd, addr) pte_alloc(pmd, addr) -#define pte_free_kernel(pte) free_pte_fast(pte) -#define pte_free(pte) free_pte_fast(pte) +#define pte_free(pte) pte_free_fast(pte) extern int do_check_pgt_cache(int, int); @@ -200,11 +177,28 @@ * on each context switch */ -#define flush_tlb() local_flush_tlb() -#define flush_tlb_all() local_flush_tlb() -#define flush_tlb_mm(mm) local_flush_tlb() -#define flush_tlb_page(vma, va) local_flush_tlb() -#define flush_tlb_range(mm, start, end) local_flush_tlb() +static inline void flush_tlb(void) +{ + local_flush_tlb(); +} +static inline void flush_tlb_all(void) +{ + local_flush_tlb(); +} +static inline void flush_tlb_mm(struct mm_struct *mm) +{ + local_flush_tlb(); +} +static inline void flush_tlb_page(struct vm_area_struct *vma, + unsigned long addr) +{ + local_flush_tlb(); +} +static inline void flush_tlb_range(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + local_flush_tlb(); +} #else @@ -251,11 +245,28 @@ } } -#define flush_tlb() __flush_tlb_mm(current->mm) -#define flush_tlb_all() global_flush_tlb() -#define flush_tlb_mm(mm) __flush_tlb_mm(mm) -#define flush_tlb_page(vma, va) __flush_tlb_mm((vma)->vm_mm) -#define flush_tlb_range(mm, start, end) __flush_tlb_mm(mm) +static inline void flush_tlb(void) +{ + __flush_tlb_mm(current->mm); +} +static inline void flush_tlb_all(void) +{ + global_flush_tlb(); +} +static inline void flush_tlb_mm(struct mm_struct *mm) +{ + __flush_tlb_mm(mm); +} +static inline void flush_tlb_page(struct vm_area_struct *vma, + unsigned long addr) +{ + __flush_tlb_mm(vma->vm_mm); +} +static inline void flush_tlb_range(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + __flush_tlb_mm(mm); +} #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/ptrace.h linux.ac/include/asm-s390/ptrace.h --- linux.vanilla/include/asm-s390/ptrace.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/ptrace.h Thu Apr 12 12:06:16 2001 @@ -8,63 +8,220 @@ #ifndef _S390_PTRACE_H #define _S390_PTRACE_H + +/* + * Offsets in the user_regs_struct. They are used for the ptrace + * system call and in entry.S + */ +#define PT_PSWMASK 0x00 +#define PT_PSWADDR 0x04 +#define PT_GPR0 0x08 +#define PT_GPR1 0x0C +#define PT_GPR2 0x10 +#define PT_GPR3 0x14 +#define PT_GPR4 0x18 +#define PT_GPR5 0x1C +#define PT_GPR6 0x20 +#define PT_GPR7 0x24 +#define PT_GPR8 0x28 +#define PT_GPR9 0x2C +#define PT_GPR10 0x30 +#define PT_GPR11 0x34 +#define PT_GPR12 0x38 +#define PT_GPR13 0x3C +#define PT_GPR14 0x40 +#define PT_GPR15 0x44 +#define PT_ACR0 0x48 +#define PT_ACR1 0x4C +#define PT_ACR2 0x50 +#define PT_ACR3 0x54 +#define PT_ACR4 0x58 +#define PT_ACR5 0x5C +#define PT_ACR6 0x60 +#define PT_ACR7 0x64 +#define PT_ACR8 0x68 +#define PT_ACR9 0x6C +#define PT_ACR10 0x70 +#define PT_ACR11 0x74 +#define PT_ACR12 0x78 +#define PT_ACR13 0x7C +#define PT_ACR14 0x80 +#define PT_ACR15 0x84 +#define PT_ORIGGPR2 0x88 +#define PT_FPC 0x90 +/* + * A nasty fact of life that the ptrace api + * only supports passing of longs. + */ +#define PT_FPR0_HI 0x98 +#define PT_FPR0_LO 0x9C +#define PT_FPR1_HI 0xA0 +#define PT_FPR1_LO 0xA4 +#define PT_FPR2_HI 0xA8 +#define PT_FPR2_LO 0xAC +#define PT_FPR3_HI 0xB0 +#define PT_FPR3_LO 0xB4 +#define PT_FPR4_HI 0xB8 +#define PT_FPR4_LO 0xBC +#define PT_FPR5_HI 0xC0 +#define PT_FPR5_LO 0xC4 +#define PT_FPR6_HI 0xC8 +#define PT_FPR6_LO 0xCC +#define PT_FPR7_HI 0xD0 +#define PT_FPR7_LO 0xD4 +#define PT_FPR8_HI 0xD8 +#define PT_FPR8_LO 0XDC +#define PT_FPR9_HI 0xE0 +#define PT_FPR9_LO 0xE4 +#define PT_FPR10_HI 0xE8 +#define PT_FPR10_LO 0xEC +#define PT_FPR11_HI 0xF0 +#define PT_FPR11_LO 0xF4 +#define PT_FPR12_HI 0xF8 +#define PT_FPR12_LO 0xFC +#define PT_FPR13_HI 0x100 +#define PT_FPR13_LO 0x104 +#define PT_FPR14_HI 0x108 +#define PT_FPR14_LO 0x10C +#define PT_FPR15_HI 0x110 +#define PT_FPR15_LO 0x114 +#define PT_CR_9 0x118 +#define PT_CR_10 0x11C +#define PT_CR_11 0x120 +#define PT_IEEE_IP 0x13C +#define PT_LASTOFF PT_IEEE_IP +#define PT_ENDREGS 0x140-1 + +#define NUM_GPRS 16 +#define NUM_FPRS 16 +#define NUM_CRS 16 +#define NUM_ACRS 16 +#define GPR_SIZE 4 +#define FPR_SIZE 8 +#define FPC_SIZE 4 +#define FPC_PAD_SIZE 4 /* gcc insists on aligning the fpregs */ +#define CR_SIZE 4 +#define ACR_SIZE 4 + +#define STACK_FRAME_OVERHEAD 96 /* size of minimum stack frame */ + +#ifndef __ASSEMBLY__ #include <linux/config.h> -#include <asm/s390-regs-common.h> -#include <asm/current.h> +#include <linux/stddef.h> #include <linux/types.h> + +#include <asm/current.h> #include <asm/setup.h> -#include <linux/stddef.h> +/* this typedef defines how a Program Status Word looks like */ +typedef struct +{ + __u32 mask; + __u32 addr; +} psw_t __attribute__ ((aligned(8))); + +#ifdef __KERNEL__ +#define FIX_PSW(addr) ((unsigned long)(addr)|0x80000000UL) +#define ADDR_BITS_REMOVE(addr) ((addr)&0x7fffffff) +#endif -#define S390_REGS \ -S390_REGS_COMMON \ -__u32 orig_gpr2; +typedef union +{ + float f; + double d; + __u64 ui; + struct + { + __u32 hi; + __u32 lo; + } fp; +} freg_t; + +typedef struct +{ + __u32 fpc; + freg_t fprs[NUM_FPRS]; +} s390_fp_regs; + +#define FPC_EXCEPTION_MASK 0xF8000000 +#define FPC_FLAGS_MASK 0x00F80000 +#define FPC_DXC_MASK 0x0000FF00 +#define FPC_RM_MASK 0x00000003 +#define FPC_VALID_MASK 0xF8F8FF03 +/* + * The first entries in pt_regs, gdb_pt_regs and user_regs_struct + * are common for all three structures. The s390_regs structure + * covers the common parts. It simplifies copying the common part + * between the three structures. + */ typedef struct { - S390_REGS + psw_t psw; + __u32 gprs[NUM_GPRS]; + __u32 acrs[NUM_ACRS]; + __u32 orig_gpr2; } s390_regs; +/* + * The pt_regs struct defines the way the registers are stored on + * the stack during a system call. + */ struct pt_regs { - S390_REGS + psw_t psw; + __u32 gprs[NUM_GPRS]; + __u32 acrs[NUM_ACRS]; + __u32 orig_gpr2; __u32 trap; + __u32 old_ilc; }; +/* + * The gdb_pt_regs struct is used instead of the pt_regs structure + * if kernel remote debugging is used. + */ #if CONFIG_REMOTE_DEBUG -typedef struct +struct gdb_pt_regs { - S390_REGS + psw_t psw; + __u32 gprs[NUM_GPRS]; + __u32 acrs[NUM_ACRS]; + __u32 orig_gpr2; __u32 trap; __u32 crs[16]; s390_fp_regs fp_regs; -} gdb_pt_regs; +}; #endif - +/* + * Now for the program event recording (trace) definitions. + */ typedef struct { - __u32 cr[3]; + __u32 cr[3]; } per_cr_words __attribute__((packed)); #define PER_EM_MASK 0xE8000000 + typedef struct { - unsigned em_branching:1; - unsigned em_instruction_fetch:1; - /* Switching on storage alteration automatically fixes - the storage alteration event bit in the users std. */ - unsigned em_storage_alteration:1; - unsigned em_gpr_alt_unused:1; - unsigned em_store_real_address:1; - unsigned :3; - unsigned branch_addr_ctl:1; - unsigned :1; - unsigned storage_alt_space_ctl:1; - unsigned :5; - unsigned :16; - addr_t starting_addr; - addr_t ending_addr; + unsigned em_branching : 1; + unsigned em_instruction_fetch : 1; + /* + * Switching on storage alteration automatically fixes + * the storage alteration event bit in the users std. + */ + unsigned em_storage_alteration : 1; + unsigned em_gpr_alt_unused : 1; + unsigned em_store_real_address : 1; + unsigned : 3; + unsigned branch_addr_ctl : 1; + unsigned : 1; + unsigned storage_alt_space_ctl : 1; + unsigned : 21; + addr_t starting_addr; + addr_t ending_addr; } per_cr_bits __attribute__((packed)); typedef struct @@ -76,228 +233,59 @@ typedef struct { - unsigned perc_branching:1; /* 0x096 */ - unsigned perc_instruction_fetch:1; - unsigned perc_storage_alteration:1; - unsigned perc_gpr_alt_unused:1; - unsigned perc_store_real_address:1; - unsigned :3; - unsigned :1; - unsigned atmid_validity_bit:1; - unsigned atmid_psw_bit_32:1; - unsigned atmid_psw_bit_5:1; - unsigned atmid_psw_bit_16:1; - unsigned atmid_psw_bit_17:1; - unsigned si:2; - addr_t address; /* 0x098 */ - unsigned :4; /* 0x0a1 */ - unsigned access_id:4; + unsigned perc_branching : 1; /* 0x096 */ + unsigned perc_instruction_fetch : 1; + unsigned perc_storage_alteration : 1; + unsigned perc_gpr_alt_unused : 1; + unsigned perc_store_real_address : 1; + unsigned : 4; + unsigned atmid_validity_bit : 1; + unsigned atmid_psw_bit_32 : 1; + unsigned atmid_psw_bit_5 : 1; + unsigned atmid_psw_bit_16 : 1; + unsigned atmid_psw_bit_17 : 1; + unsigned si : 2; + addr_t address; /* 0x098 */ + unsigned : 4; /* 0x0a1 */ + unsigned access_id : 4; } per_lowcore_bits __attribute__((packed)); -typedef enum -{ - primary_asce, - ar_asce, - secondary_asce, - home_space_asce -} per_ai_codes; - typedef struct { - union - { + union { per_cr_words words; per_cr_bits bits; } control_regs __attribute__((packed)); - /* Use these flags instead of setting em_instruction_fetch */ - /* directly they are used so that single stepping can be */ - /* switched on & off while not affecting other tracing */ - unsigned single_step:1; - unsigned instruction_fetch:1; - unsigned :30; - /* These addresses are copied into cr10 & cr11 if single stepping - is switched off */ + /* + * Use these flags instead of setting em_instruction_fetch + * directly they are used so that single stepping can be + * switched on & off while not affecting other tracing + */ + unsigned single_step : 1; + unsigned instruction_fetch : 1; + unsigned : 30; + /* + * These addresses are copied into cr10 & cr11 if single + * stepping is switched off + */ __u32 starting_addr; __u32 ending_addr; - union - { + union { per_lowcore_words words; per_lowcore_bits bits; } lowcore; } per_struct __attribute__((packed)); - - -/* this struct defines the way the registers are stored on the - stack during a system call. If you change the pt_regs structure, - you'll need to change user.h too. - - N.B. if you modify the pt_regs struct the strace command also has to be - modified & recompiled ( just wait till we have gdb going ). - -*/ - -struct user_regs_struct -{ - S390_REGS - s390_fp_regs fp_regs; -/* These per registers are in here so that gdb can modify them itself - * as there is no "official" ptrace interface for hardware watchpoints. - * this is the way intel does it - */ - per_struct per_info; - addr_t ieee_instruction_pointer; - /* Used to give failing instruction back to user for ieee exceptions */ -}; - -typedef struct user_regs_struct user_regs_struct; - -typedef struct pt_regs pt_regs; - -#ifdef __KERNEL__ -#define user_mode(regs) (((regs)->psw.mask & PSW_PROBLEM_STATE) != 0) -#define instruction_pointer(regs) ((regs)->psw.addr) -extern void show_regs(struct pt_regs * regs); -extern char *task_show_regs(struct task_struct *task, char *buffer); -#endif - - - - - -#define FIX_PSW(addr) ((unsigned long)(addr)|0x80000000UL) - -#define MULT_PROCPTR_TYPES ((CONFIG_BINFMT_ELF)&&(CONFIG_BINFMT_TOC)) - -typedef struct -{ - long addr; - long toc; -} routine_descriptor; -extern void fix_routine_descriptor_regs(routine_descriptor *rdes,pt_regs *regs); -extern __inline__ void -fix_routine_descriptor_regs(routine_descriptor *rdes,pt_regs *regs) -{ - regs->psw.addr=FIX_PSW(rdes->addr); - regs->gprs[12]=rdes->toc; -} - -/* - * Compiler optimisation should save this stuff from being non optimal - * & remove uneccessary code ( isnt gcc great DJB. ) - */ - -/*I'm just using this an indicator of what binformat we are using - * (DJB) N.B. this needs to stay a macro unfortunately as I am otherwise - * dereferencing incomplete pointer types in with load_toc_binary - */ -#if MULT_PROCPTR_TYPES -#define uses_routine_descriptors() \ -(current->binfmt->load_binary==load_toc_binary) -#else -#if CONFIG_BINFMT_TOC -#define uses_routine_descriptors() 1 -#else -#define uses_routine_descriptors() 0 -#endif -#endif - -#define pt_off(ptreg) offsetof(user_regs_struct,ptreg) -enum -{ - PT_PSWMASK=pt_off(psw.mask), - PT_PSWADDR=pt_off(psw.addr), - PT_GPR0=pt_off(gprs[0]), - PT_GPR1=pt_off(gprs[1]), - PT_GPR2=pt_off(gprs[2]), - PT_GPR3=pt_off(gprs[3]), - PT_GPR4=pt_off(gprs[4]), - PT_GPR5=pt_off(gprs[5]), - PT_GPR6=pt_off(gprs[6]), - PT_GPR7=pt_off(gprs[7]), - PT_GPR8=pt_off(gprs[8]), - PT_GPR9=pt_off(gprs[9]), - PT_GPR10=pt_off(gprs[10]), - PT_GPR11=pt_off(gprs[11]), - PT_GPR12=pt_off(gprs[12]), - PT_GPR13=pt_off(gprs[13]), - PT_GPR14=pt_off(gprs[14]), - PT_GPR15=pt_off(gprs[15]), - PT_ACR0=pt_off(acrs[0]), - PT_ACR1=pt_off(acrs[1]), - PT_ACR2=pt_off(acrs[2]), - PT_ACR3=pt_off(acrs[3]), - PT_ACR4=pt_off(acrs[4]), - PT_ACR5=pt_off(acrs[5]), - PT_ACR6=pt_off(acrs[6]), - PT_ACR7=pt_off(acrs[7]), - PT_ACR8=pt_off(acrs[8]), - PT_ACR9=pt_off(acrs[9]), - PT_ACR10=pt_off(acrs[10]), - PT_ACR11=pt_off(acrs[11]), - PT_ACR12=pt_off(acrs[12]), - PT_ACR13=pt_off(acrs[13]), - PT_ACR14=pt_off(acrs[14]), - PT_ACR15=pt_off(acrs[15]), - PT_ORIGGPR2=pt_off(orig_gpr2), - PT_FPC=pt_off(fp_regs.fpc), -/* - * A nasty fact of life that the ptrace api - * only supports passing of longs. - */ - PT_FPR0_HI=pt_off(fp_regs.fprs[0].fp.hi), - PT_FPR0_LO=pt_off(fp_regs.fprs[0].fp.lo), - PT_FPR1_HI=pt_off(fp_regs.fprs[1].fp.hi), - PT_FPR1_LO=pt_off(fp_regs.fprs[1].fp.lo), - PT_FPR2_HI=pt_off(fp_regs.fprs[2].fp.hi), - PT_FPR2_LO=pt_off(fp_regs.fprs[2].fp.lo), - PT_FPR3_HI=pt_off(fp_regs.fprs[3].fp.hi), - PT_FPR3_LO=pt_off(fp_regs.fprs[3].fp.lo), - PT_FPR4_HI=pt_off(fp_regs.fprs[4].fp.hi), - PT_FPR4_LO=pt_off(fp_regs.fprs[4].fp.lo), - PT_FPR5_HI=pt_off(fp_regs.fprs[5].fp.hi), - PT_FPR5_LO=pt_off(fp_regs.fprs[5].fp.lo), - PT_FPR6_HI=pt_off(fp_regs.fprs[6].fp.hi), - PT_FPR6_LO=pt_off(fp_regs.fprs[6].fp.lo), - PT_FPR7_HI=pt_off(fp_regs.fprs[7].fp.hi), - PT_FPR7_LO=pt_off(fp_regs.fprs[7].fp.lo), - PT_FPR8_HI=pt_off(fp_regs.fprs[8].fp.hi), - PT_FPR8_LO=pt_off(fp_regs.fprs[8].fp.lo), - PT_FPR9_HI=pt_off(fp_regs.fprs[9].fp.hi), - PT_FPR9_LO=pt_off(fp_regs.fprs[9].fp.lo), - PT_FPR10_HI=pt_off(fp_regs.fprs[10].fp.hi), - PT_FPR10_LO=pt_off(fp_regs.fprs[10].fp.lo), - PT_FPR11_HI=pt_off(fp_regs.fprs[11].fp.hi), - PT_FPR11_LO=pt_off(fp_regs.fprs[11].fp.lo), - PT_FPR12_HI=pt_off(fp_regs.fprs[12].fp.hi), - PT_FPR12_LO=pt_off(fp_regs.fprs[12].fp.lo), - PT_FPR13_HI=pt_off(fp_regs.fprs[13].fp.hi), - PT_FPR13_LO=pt_off(fp_regs.fprs[13].fp.lo), - PT_FPR14_HI=pt_off(fp_regs.fprs[14].fp.hi), - PT_FPR14_LO=pt_off(fp_regs.fprs[14].fp.lo), - PT_FPR15_HI=pt_off(fp_regs.fprs[15].fp.hi), - PT_FPR15_LO=pt_off(fp_regs.fprs[15].fp.lo), - PT_CR_9=pt_off(per_info.control_regs.words.cr[0]), - PT_CR_10=pt_off(per_info.control_regs.words.cr[1]), - PT_CR_11=pt_off(per_info.control_regs.words.cr[2]), - PT_IEEE_IP=pt_off(ieee_instruction_pointer), - PT_LASTOFF=PT_IEEE_IP, - PT_ENDREGS=sizeof(user_regs_struct)-1 -}; - -#define PTRACE_AREA \ -__u32 len; \ -addr_t kernel_addr; \ -addr_t process_addr; - typedef struct { - PTRACE_AREA + __u32 len; + addr_t kernel_addr; + addr_t process_addr; } ptrace_area; /* - 390 specific non posix ptrace requests - I chose unusual values so they are unlikely to clash with future ptrace definitions. + * S/390 specific non posix ptrace requests. I chose unusual values so + * they are unlikely to clash with future ptrace definitions. */ #define PTRACE_PEEKUSR_AREA 0x5000 #define PTRACE_POKEUSR_AREA 0x5001 @@ -305,7 +293,10 @@ #define PTRACE_PEEKDATA_AREA 0x5003 #define PTRACE_POKETEXT_AREA 0x5004 #define PTRACE_POKEDATA_AREA 0x5005 -/* PT_PROT definition is loosely based on hppa bsd definition in gdb/hppab-nat.c */ +/* + * PT_PROT definition is loosely based on hppa bsd definition in + * gdb/hppab-nat.c + */ #define PTRACE_PROT 21 typedef enum @@ -321,18 +312,41 @@ addr_t hiaddr; ptprot_flags prot; } ptprot_area; -#endif - - - - - - - - - +/* Sequence of bytes for breakpoint illegal instruction. */ +#define S390_BREAKPOINT {0x0,0x1} +#define S390_BREAKPOINT_U16 ((__u16)0x0001) +#define S390_SYSCALL_OPCODE ((__u16)0x0a00) +#define S390_SYSCALL_SIZE 2 +/* + * The user_regs_struct defines the way the user registers are + * store on the stack for signal handling. + */ +struct user_regs_struct +{ + psw_t psw; + __u32 gprs[NUM_GPRS]; + __u32 acrs[NUM_ACRS]; + __u32 orig_gpr2; + s390_fp_regs fp_regs; + /* + * These per registers are in here so that gdb can modify them + * itself as there is no "official" ptrace interface for hardware + * watchpoints. This is the way intel does it. + */ + per_struct per_info; + addr_t ieee_instruction_pointer; + /* Used to give failing instruction back to user for ieee exceptions */ +}; +#ifdef __KERNEL__ +#define user_mode(regs) (((regs)->psw.mask & PSW_PROBLEM_STATE) != 0) +#define instruction_pointer(regs) ((regs)->psw.addr) +extern void show_regs(struct pt_regs * regs); +extern char *task_show_regs(struct task_struct *task, char *buffer); +#endif +#endif /* __ASSEMBLY__ */ +#endif /* _S390_PTRACE_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/queue.h linux.ac/include/asm-s390/queue.h --- linux.vanilla/include/asm-s390/queue.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/queue.h Thu Apr 12 12:06:16 2001 @@ -7,8 +7,8 @@ * * A little set of queue utilies. */ + #include <linux/stddef.h> -#include <asm/types.h> typedef struct queue { @@ -105,8 +105,8 @@ for(curr=lhead;curr!=NULL;curr=curr->next) if(curr==member) - return(TRUE); - return(FALSE); + return(1); + return(0); } static __inline__ int get_prev(list *lhead,list *member,list **prev) @@ -117,11 +117,11 @@ for(curr=lhead;curr!=NULL;curr=curr->next) { if(curr==member) - return(TRUE); + return(1); *prev=curr; } *prev=NULL; - return(FALSE); + return(0); } @@ -137,9 +137,9 @@ prev->next=member->next; else *lhead=member->next; - return(TRUE); + return(1); } - return(FALSE); + return(0); } static __inline__ int remove_from_queue(qheader *qhead,queue *member) @@ -161,9 +161,9 @@ qhead->tail=NULL; qhead->head=member->next; } - return(TRUE); + return(1); } - return(FALSE); + return(0); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/s390-regs-common.h linux.ac/include/asm-s390/s390-regs-common.h --- linux.vanilla/include/asm-s390/s390-regs-common.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/s390-regs-common.h Thu Jan 1 01:00:00 1970 @@ -1,112 +0,0 @@ -/* - * include/asm-s390/s390-regs-common.h - * - * S390 version - * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - * - * this file is designed to keep as much compatibility between - * gdb's representation of registers & the kernels representation of registers - * as possible so as to minimise translation between gdb registers & - * kernel registers please keep this matched with gdb & strace - */ - -#ifndef _S390_REGS_COMMON_H -#define _S390_REGS_COMMON_H -#ifndef __ASSEMBLY__ -#include <asm/types.h> -#endif -#if defined(WANT_S390_TGT_DEFS) || defined(__KERNEL__) -#define REGISTER_SIZE 4 -#endif -#define NUM_GPRS 16 -#define GPR_SIZE 4 -#define PSW_MASK_SIZE 4 -#define PSW_ADDR_SIZE 4 -#define NUM_FPRS 16 -#define FPR_SIZE 8 -#define FPC_SIZE 4 -#define FPC_PAD_SIZE 4 /* gcc insists on aligning the fpregs */ -#define NUM_CRS 16 -#define CR_SIZE 4 -#define NUM_ACRS 16 -#define ACR_SIZE 4 - -#define STACK_FRAME_OVERHEAD 96 /* size of minimum stack frame */ - -#ifndef __ASSEMBLY__ -/* this typedef defines how a Program Status Word looks like */ -typedef struct -{ - __u32 mask; - __u32 addr; -} psw_t __attribute__ ((aligned(8))); - -/* 2 __u32's are used for floats instead to compile with a __STRICT_ANSI__ defined */ -typedef union -{ -#ifdef __KERNEL__ - __u64 d; /* mathemu.h gets upset otherwise */ -#else - double d; /* ansi c dosen't like long longs & make sure that */ - /* alignments are identical for both compiles */ -#endif - struct - { - __u32 hi; - __u32 lo; - } fp; - __u32 f; -} freg_t; - -typedef struct -{ -/* - The compiler appears to like aligning freg_t on an 8 byte boundary - so I always access fpregs, this was causing fun when I was doing - coersions. - */ - __u32 fpc; - freg_t fprs[NUM_FPRS]; -} s390_fp_regs; - -#define FPC_EXCEPTION_MASK 0xF8000000 -#define FPC_FLAGS_MASK 0x00F80000 -#define FPC_DXC_MASK 0x0000FF00 -#define FPC_RM_MASK 0x00000003 -#define FPC_VALID_MASK ((FPC_EXCEPTION_MASK|FPC_FLAGS_MASK| \ - FPC_DXC_MASK|FPC_RM_MASK)) - -/* - gdb structures & the kernel have this much always in common - */ -#define S390_REGS_COMMON \ -psw_t psw; \ -__u32 gprs[NUM_GPRS]; \ -__u32 acrs[NUM_ACRS]; \ - -typedef struct -{ - S390_REGS_COMMON -} s390_regs_common; - - -/* Sequence of bytes for breakpoint illegal instruction. */ -#define S390_BREAKPOINT {0x0,0x1} -#define S390_BREAKPOINT_U16 ((__u16)0x0001) -#define S390_SYSCALL_OPCODE ((__u16)0x0a00) -#define S390_SYSCALL_SIZE 2 -#if defined(WANT_S390_TGT_DEFS) || defined(__KERNEL__) -#define ADDR_BITS_REMOVE(addr) ((addr)&0x7fffffff) -#endif -#endif -#endif - - - - - - - - - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/s390dyn.h linux.ac/include/asm-s390/s390dyn.h --- linux.vanilla/include/asm-s390/s390dyn.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/s390dyn.h Thu Apr 12 12:06:16 2001 @@ -10,6 +10,10 @@ #ifndef __s390dyn_h #define __s390dyn_h +#ifndef _LINUX_LIST_H +#include <linux/list.h> +#endif + struct _devreg; typedef int (* oper_handler_func_t)( int irq, @@ -23,6 +27,7 @@ } __attribute__ ((packed)) devreg_hc_t; typedef struct _devreg { + struct list_head list; union { int devno; devreg_hc_t hc; /* has controller info */ @@ -30,8 +35,6 @@ int flag; oper_handler_func_t oper_func; - struct _devreg *prev; - struct _devreg *next; } devreg_t; #define DEVREG_EXACT_MATCH 0x00000001 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/s390io.h linux.ac/include/asm-s390/s390io.h --- linux.vanilla/include/asm-s390/s390io.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/s390io.h Thu Apr 12 12:06:16 2001 @@ -75,7 +75,6 @@ unsigned long qintparm; /* queued interruption parameter */ unsigned long qflag; /* queued flags */ __u8 qlpm; /* queued logical path mask */ - __u32 syncnt; /* sync I/O recursive usage count */ } __attribute__ ((aligned(8))) ioinfo_t; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/semaphore-helper.h linux.ac/include/asm-s390/semaphore-helper.h --- linux.vanilla/include/asm-s390/semaphore-helper.h Fri May 12 19:41:44 2000 +++ linux.ac/include/asm-s390/semaphore-helper.h Thu Jan 1 01:00:00 1970 @@ -1,100 +0,0 @@ -/* - * include/asm-s390/semaphore-helper.h - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * - * Derived from "include/asm-i386/semaphore-helper.h" - * (C) Copyright 1996 Linus Torvalds - * (C) Copyright 1999 Andrea Arcangeli - */ - -#ifndef _S390_SEMAPHORE_HELPER_H -#define _S390_SEMAPHORE_HELPER_H - -/* - * These two _must_ execute atomically wrt each other. - * - * This is trivially done with load_locked/store_cond, - * but on the x86 we need an external synchronizer. - */ -static inline void wake_one_more(struct semaphore * sem) -{ - unsigned long flags; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - sem->waking++; - spin_unlock_irqrestore(&semaphore_wake_lock, flags); -} - -static inline int waking_non_zero(struct semaphore *sem) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking > 0) { - sem->waking--; - ret = 1; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_interruptible: - * 1 got the lock - * 0 go to sleep - * -EINTR interrupted - * - * If we give up we must undo our count-decrease we previously did in down(). - * Subtle: up() can continue to happens and increase the semaphore count - * even during our critical section protected by the spinlock. So - * we must remeber to undo the sem->waking that will be run from - * wake_one_more() some time soon, if the semaphore count become > 0. - */ -static inline int waking_non_zero_interruptible(struct semaphore *sem, - struct task_struct *tsk) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking > 0) { - sem->waking--; - ret = 1; - } else if (signal_pending(tsk)) { - if (atomic_inc_and_test_greater_zero(&sem->count)) - sem->waking--; - ret = -EINTR; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_trylock: - * 1 failed to lock - * 0 got the lock - * - * Implementation details are the same of the interruptible case. - */ -static inline int waking_non_zero_trylock(struct semaphore *sem) -{ - unsigned long flags; - int ret = 1; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking <= 0) - { - if (atomic_inc_and_test_greater_zero(&sem->count)) - sem->waking--; - } else { - sem->waking--; - ret = 0; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/setup.h linux.ac/include/asm-s390/setup.h --- linux.vanilla/include/asm-s390/setup.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/setup.h Thu Apr 12 12:06:16 2001 @@ -8,46 +8,36 @@ #ifndef _ASM_S390_SETUP_H #define _ASM_S390_SETUP_H -#define PARMAREA 0x10400 +#define PARMAREA 0x10400 +#define COMMAND_LINE_SIZE 896 +#define RAMDISK_ORIGIN 0x800000 +#define RAMDISK_SIZE 0x800000 #ifndef __ASSEMBLER__ -#define ORIG_ROOT_DEV (*(unsigned long *) (0x10400)) -#define MOUNT_ROOT_RDONLY (*(unsigned short *) (0x10404)) -#define MEMORY_SIZE (*(unsigned long *) (0x10406)) -#define MACHINE_FLAGS (*(unsigned long *) (0x1040a)) -#define INITRD_START (*(unsigned long *) (0x1040e)) -#define INITRD_SIZE (*(unsigned long *) (0x10412)) -#define RAMDISK_FLAGS (*(unsigned short *) (0x10416)) +#define IPL_DEVICE (*(unsigned long *) (0x10404)) +#define INITRD_START (*(unsigned long *) (0x1040C)) +#define INITRD_SIZE (*(unsigned long *) (0x10414)) #define COMMAND_LINE ((char *) (0x10480)) +/* + * Machine features detected in head.S + */ +extern unsigned long machine_flags; + +#define MACHINE_IS_VM (machine_flags & 1) +#define MACHINE_HAS_IEEE (machine_flags & 2) +#define MACHINE_IS_P390 (machine_flags & 4) +#define MACHINE_HAS_CSP (machine_flags & 8) +#define MACHINE_HAS_MVPG (machine_flags & 16) + #else -#define ORIG_ROOT_DEV 0x10400 -#define MOUNT_ROOT_RDONLY 0x10404 -#define MEMORY_SIZE 0x10406 -#define MACHINE_FLAGS 0x1040a -#define INITRD_START 0x1040e -#define INITRD_SIZE 0x10412 -#define RAMDISK_FLAGS 0x10416 +#define IPL_DEVICE 0x10404 +#define INITRD_START 0x1040C +#define INITRD_SIZE 0x10414 #define COMMAND_LINE 0x10480 #endif - -#define COMMAND_LINE_SIZE 896 -/* - * Machine features detected in head.S - */ -#define MACHINE_IS_VM (MACHINE_FLAGS & 1) -#define MACHINE_HAS_IEEE (MACHINE_FLAGS & 2) -#define MACHINE_IS_P390 (MACHINE_FLAGS & 4) -#define MACHINE_HAS_CSP (MACHINE_FLAGS & 8) - -#define RAMDISK_ORIGIN 0x800000 -#define RAMDISK_BLKSIZE 0x1000 -#define RAMDISK_IMAGE_START_MASK 0x07FF -#define RAMDISK_PROMPT_FLAG 0x8000 -#define RAMDISK_LOAD_FLAG 0x4000 - #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/sfp-machine.h linux.ac/include/asm-s390/sfp-machine.h --- linux.vanilla/include/asm-s390/sfp-machine.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-s390/sfp-machine.h Thu Apr 12 12:06:16 2001 @@ -0,0 +1,139 @@ +/* Machine-dependent software floating-point definitions. + S/390 kernel version. + Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson (rth@cygnus.com), + Jakub Jelinek (jj@ultra.linux.cz), + David S. Miller (davem@redhat.com) and + Peter Maydell (pmaydell@chiark.greenend.org.uk). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _SFP_MACHINE_H +#define _SFP_MACHINE_H + +#include <linux/config.h> + +#define _FP_W_TYPE_SIZE 32 +#define _FP_W_TYPE unsigned long +#define _FP_WS_TYPE signed long +#define _FP_I_TYPE long + +#define _FP_MUL_MEAT_S(R,X,Y) \ + _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm) +#define _FP_MUL_MEAT_D(R,X,Y) \ + _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm) +#define _FP_MUL_MEAT_Q(R,X,Y) \ + _FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm) + +#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y) +#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv(D,R,X,Y) +#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_4_udiv(Q,R,X,Y) + +#define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1) +#define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1), -1 +#define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1 +#define _FP_NANSIGN_S 0 +#define _FP_NANSIGN_D 0 +#define _FP_NANSIGN_Q 0 + +#define _FP_KEEPNANFRACP 1 + +/* + * If one NaN is signaling and the other is not, + * we choose that one, otherwise we choose X. + */ +#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \ + do { \ + if ((_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs) \ + && !(_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs)) \ + { \ + R##_s = Y##_s; \ + _FP_FRAC_COPY_##wc(R,Y); \ + } \ + else \ + { \ + R##_s = X##_s; \ + _FP_FRAC_COPY_##wc(R,X); \ + } \ + R##_c = FP_CLS_NAN; \ + } while (0) + +/* Some assembly to speed things up. */ +#define __FP_FRAC_ADD_3(r2,r1,r0,x2,x1,x0,y2,y1,y0) ({ \ + unsigned int __r2 = (x2) + (y2); \ + unsigned int __r1 = (x1); \ + unsigned int __r0 = (x0); \ + __asm__ (" alr %2,%3\n" \ + " brc 12,0f\n" \ + " lhi 0,1\n" \ + " alr %1,0\n" \ + " brc 12,0f\n" \ + " alr %0,0\n" \ + "0:" \ + : "+&d" (__r2), "+&d" (__r1), "+&d" (__r0) \ + : "d" (y0), "i" (1) : "cc", "0" ); \ + __asm__ (" alr %1,%2\n" \ + " brc 12,0f\n" \ + " ahi %0,1\n" \ + "0:" \ + : "+&d" (__r2), "+&d" (__r1) \ + : "d" (y1) : "cc" ); \ + (r2) = __r2; \ + (r1) = __r1; \ + (r0) = __r0; \ +}) + +#define __FP_FRAC_SUB_3(r2,r1,r0,x2,x1,x0,y2,y1,y0) ({ \ + unsigned int __r2 = (x2) - (y2); \ + unsigned int __r1 = (x1); \ + unsigned int __r0 = (x0); \ + __asm__ (" slr %2,%3\n" \ + " brc 3,0f\n" \ + " lhi 0,1\n" \ + " slr %1,0\n" \ + " brc 3,0f\n" \ + " slr %0,0\n" \ + "0:" \ + : "+&d" (__r2), "+&d" (__r1), "+&d" (__r0) \ + : "d" (y0) : "cc", "0" ); \ + __asm__ (" slr %1,%2\n" \ + " brc 3,0f\n" \ + " ahi %0,-1\n" \ + "0:" \ + : "+&d" (__r2), "+&d" (__r1) \ + : "d" (y1) : "cc" ); \ + (r2) = __r2; \ + (r1) = __r1; \ + (r0) = __r0; \ +}) + +#define __FP_FRAC_DEC_3(x2,x1,x0,y2,y1,y0) __FP_FRAC_SUB_3(x2,x1,x0,x2,x1,x0,y2,y1,y0) + +/* Obtain the current rounding mode. */ +#define FP_ROUNDMODE mode + +/* Exception flags. */ +#define FP_EX_INVALID 0x800000 +#define FP_EX_DIVZERO 0x400000 +#define FP_EX_OVERFLOW 0x200000 +#define FP_EX_UNDERFLOW 0x100000 +#define FP_EX_INEXACT 0x080000 + +/* We write the results always */ +#define FP_INHIBIT_RESULTS 0 + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/signal.h linux.ac/include/asm-s390/signal.h --- linux.vanilla/include/asm-s390/signal.h Fri May 12 19:41:44 2000 +++ linux.ac/include/asm-s390/signal.h Thu Apr 12 12:06:16 2001 @@ -71,6 +71,7 @@ #define SIGLOST 29 */ #define SIGPWR 30 +#define SIGSYS 31 #define SIGUNUSED 31 /* These should not be considered constants from userland. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/sigp.h linux.ac/include/asm-s390/sigp.h --- linux.vanilla/include/asm-s390/sigp.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/sigp.h Thu Apr 12 12:06:16 2001 @@ -15,7 +15,6 @@ #define __SIGP__ #include <asm/ptrace.h> -#include <asm/misc390.h> #include <asm/atomic.h> /* get real cpu address from logical cpu number */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/smp.h linux.ac/include/asm-s390/smp.h --- linux.vanilla/include/asm-s390/smp.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/smp.h Thu Apr 12 12:06:16 2001 @@ -8,15 +8,24 @@ */ #ifndef __ASM_SMP_H #define __ASM_SMP_H + #include <linux/config.h> -#ifdef CONFIG_SMP -#ifndef __ASSEMBLY__ + +#if defined(__KERNEL__) && defined(CONFIG_SMP) && !defined(__ASSEMBLY__) #include <asm/lowcore.h> -#include <linux/threads.h> // FOR NR_CPUS definition only. -#include <linux/kernel.h> // FOR FASTCALL definition -#define smp_processor_id() (current->processor) +/* + s390 specific smp.c headers + */ +typedef struct +{ + int intresting; + sigp_ccode ccode; + __u32 status; + __u16 cpu; +} sigp_info; + #define NO_PROC_ID 0xFF /* No processor magic marker */ /* @@ -31,7 +40,7 @@ #define PROC_CHANGE_PENALTY 20 /* Schedule penalty */ -extern void count_cpus(void); +#define smp_processor_id() (current->processor) extern __inline__ int cpu_logical_map(int cpu) { @@ -55,25 +64,12 @@ void smp_local_timer_interrupt(struct pt_regs * regs); -/* - s390 specific smp.c headers - */ -typedef struct -{ - int intresting; - sigp_ccode ccode; - __u32 status; - __u16 cpu; -} sigp_info; - -sigp_ccode -smp_ext_call(int cpu, void (*callback)(void *info), void *info, int wait); -void smp_ext_call_others(void (*callback)(void *info), void *info, int wait); +sigp_ccode smp_ext_call(int cpu, void (*cb)(void *info), void *info, int wait); +void smp_ext_call_others(void (*cb)(void *info), void *info, int wait); sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig); void smp_ext_bitcall_others(ec_bit_sig sig); int smp_signal_others(sigp_order_code order_code,__u32 parameter, int spin,sigp_info *info); -#endif #endif #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/spinlock.h linux.ac/include/asm-s390/spinlock.h --- linux.vanilla/include/asm-s390/spinlock.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/spinlock.h Thu Apr 12 12:06:16 2001 @@ -73,6 +73,8 @@ #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } +#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) + #define read_lock(rw) \ asm volatile(" l 2,%0\n" \ " j 1f\n" \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/system.h linux.ac/include/asm-s390/system.h --- linux.vanilla/include/asm-s390/system.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/system.h Thu Apr 12 12:06:16 2001 @@ -12,7 +12,6 @@ #define __ASM_SYSTEM_H #include <linux/config.h> -#include <asm/types.h> #ifdef __KERNEL__ #include <asm/lowcore.h> #endif @@ -33,6 +32,8 @@ #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) +extern void __misaligned_u16(void); +extern void __misaligned_u32(void); static inline unsigned long __xchg(unsigned long x, void * ptr, int size) { @@ -43,14 +44,14 @@ " nr 1,%0\n" /* isolate last 2 bits */ " xr %0,1\n" /* align ptr */ " bras 2,0f\n" - " icm 1,8,%1\n" /* for ptr&3 == 0 */ - " stcm 0,8,%1\n" - " icm 1,4,%1\n" /* for ptr&3 == 1 */ - " stcm 0,4,%1\n" - " icm 1,2,%1\n" /* for ptr&3 == 2 */ - " stcm 0,2,%1\n" - " icm 1,1,%1\n" /* for ptr&3 == 3 */ - " stcm 0,1,%1\n" + " icm 1,8,3(%1)\n" /* for ptr&3 == 0 */ + " stcm 0,8,3(%1)\n" + " icm 1,4,3(%1)\n" /* for ptr&3 == 1 */ + " stcm 0,4,3(%1)\n" + " icm 1,2,3(%1)\n" /* for ptr&3 == 2 */ + " stcm 0,2,3(%1)\n" + " icm 1,1,3(%1)\n" /* for ptr&3 == 3 */ + " stcm 0,1,3(%1)\n" "0: sll 1,3\n" " la 2,0(1,2)\n" /* r2 points to an icm */ " l 0,0(%0)\n" /* get fullword */ @@ -59,20 +60,21 @@ " cs 0,1,0(%0)\n" " jl 1b\n" " ex 0,4(2)" /* store *ptr to x */ - : "+a&" (ptr), "+m" (x) : + : "+a&" (ptr) : "a" (&x) : "memory", "0", "1", "2"); + break; case 2: if(((__u32)ptr)&1) - panic("misaligned (__u16 *) in __xchg\n"); + __misaligned_u16(); asm volatile ( " lhi 1,2\n" " nr 1,%0\n" /* isolate bit 2^1 */ " xr %0,1\n" /* align ptr */ " bras 2,0f\n" - " icm 1,12,%1\n" /* for ptr&2 == 0 */ - " stcm 0,12,%1\n" - " icm 1,3,%1\n" /* for ptr&2 == 1 */ - " stcm 0,3,%1\n" + " icm 1,12,2(%1)\n" /* for ptr&2 == 0 */ + " stcm 0,12,2(%1)\n" + " icm 1,3,2(%1)\n" /* for ptr&2 == 1 */ + " stcm 0,3,2(%1)\n" "0: sll 1,2\n" " la 2,0(1,2)\n" /* r2 points to an icm */ " l 0,0(%0)\n" /* get fullword */ @@ -81,12 +83,12 @@ " cs 0,1,0(%0)\n" " jl 1b\n" " ex 0,4(2)" /* store *ptr to x */ - : "+a&" (ptr), "+m" (x) : + : "+a&" (ptr) : "a" (&x) : "memory", "0", "1", "2"); break; case 4: if(((__u32)ptr)&3) - panic("misaligned (__u32 *) in __xchg\n"); + __misaligned_u32(); asm volatile ( " l 0,0(%1)\n" "0: cs 0,%0,0(%1)\n" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/tlb.h linux.ac/include/asm-s390/tlb.h --- linux.vanilla/include/asm-s390/tlb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-s390/tlb.h Tue Apr 3 17:55:16 2001 @@ -0,0 +1 @@ +#include <asm-generic/tlb.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/todclk.h linux.ac/include/asm-s390/todclk.h --- linux.vanilla/include/asm-s390/todclk.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/todclk.h Thu Apr 12 12:06:16 2001 @@ -10,10 +10,14 @@ #ifndef __ASM_TODCLK_H #define __ASM_TODCLK_H +#ifdef __KERNEL__ + #define TOD_uSEC (0x1000ULL) #define TOD_mSEC (1000 * TOD_uSEC) #define TOD_SEC (1000 * TOD_mSEC) #define TOD_MIN (60 * TOD_SEC) #define TOD_HOUR (60 * TOD_MIN) + +#endif #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/types.h linux.ac/include/asm-s390/types.h --- linux.vanilla/include/asm-s390/types.h Fri May 12 19:41:44 2000 +++ linux.ac/include/asm-s390/types.h Thu Apr 12 12:06:16 2001 @@ -55,12 +55,13 @@ typedef u32 dma_addr_t; -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif +typedef union { + unsigned long long pair; + struct { + unsigned long even; + unsigned long odd; + } subreg; +} register_pair; #endif /* __KERNEL__ */ #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/uaccess.h linux.ac/include/asm-s390/uaccess.h --- linux.vanilla/include/asm-s390/uaccess.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390/uaccess.h Thu Apr 12 12:06:16 2001 @@ -15,9 +15,7 @@ * User space memory access functions */ #include <linux/sched.h> -#if 0 -#include <asm/segment.h> -#endif + #define VERIFY_READ 0 #define VERIFY_WRITE 1 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/vtoc.h linux.ac/include/asm-s390/vtoc.h --- linux.vanilla/include/asm-s390/vtoc.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-s390/vtoc.h Thu Apr 12 12:06:16 2001 @@ -0,0 +1,234 @@ +#ifndef __KERNEL__ +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <ctype.h> +#include <time.h> +#include <fcntl.h> +#include <unistd.h> + +#include <sys/stat.h> +#include <sys/ioctl.h> + +#include <linux/fs.h> +#include <linux/types.h> +#include <linux/hdreg.h> +#include <linux/version.h> +#endif +#include <asm/dasd.h> + +#define LINE_LENGTH 80 +#define VTOC_START_CC 0x0 +#define VTOC_START_HH 0x1 + +enum failure {unable_to_open, + unable_to_seek, + unable_to_write, + unable_to_read}; + +typedef struct ttr { + __u16 tt; + __u8 r; +} __attribute__ ((packed)) ttr_t; + +typedef struct cchhb { + __u16 cc; + __u16 hh; + __u8 b; +} __attribute__ ((packed)) cchhb_t; + +typedef struct cchh { + __u16 cc; + __u16 hh; +} __attribute__ ((packed)) cchh_t; + +typedef struct labeldate { + __u8 year; + __u16 day; +} __attribute__ ((packed)) labeldate_t; + + +typedef struct volume_label { + char volkey[4]; /* volume key = volume label */ + char vollbl[4]; /* volume label */ + char volid[6]; /* volume identifier */ + __u8 security; /* security byte */ + cchhb_t vtoc; /* VTOC address */ + char res1[5]; /* reserved */ + char cisize[4]; /* CI-size for FBA,... */ + /* ...blanks for CKD */ + char blkperci[4]; /* no of blocks per CI (FBA), blanks for CKD */ + char labperci[4]; /* no of labels per CI (FBA), blanks for CKD */ + char res2[4]; /* reserved */ + char lvtoc[14]; /* owner code for LVTOC */ + char res3[29]; /* reserved */ +} __attribute__ ((packed)) volume_label_t; + + +typedef struct extent { + __u8 typeind; /* extent type indicator */ + __u8 seqno; /* extent sequence number */ + cchh_t llimit; /* starting point of this extent */ + cchh_t ulimit; /* ending point of this extent */ +} __attribute__ ((packed)) extent_t; + + +typedef struct dev_const { + __u16 DS4DSCYL; /* number of logical cyls */ + __u16 DS4DSTRK; /* number of tracks in a logical cylinder */ + __u16 DS4DEVTK; /* device track length */ + __u8 DS4DEVI; /* non-last keyed record overhead */ + __u8 DS4DEVL; /* last keyed record overhead */ + __u8 DS4DEVK; /* non-keyed record overhead differential */ + __u8 DS4DEVFG; /* flag byte */ + __u16 DS4DEVTL; /* device tolerance */ + __u8 DS4DEVDT; /* number of DSCB's per track */ + __u8 DS4DEVDB; /* number of directory blocks per track */ +} __attribute__ ((packed)) dev_const_t; + + +typedef struct format1_label { + char DS1DSNAM[44]; /* data set name */ + __u8 DS1FMTID; /* format identifier */ + char DS1DSSN[6]; /* data set serial number */ + __u16 DS1VOLSQ; /* volume sequence number */ + labeldate_t DS1CREDT; /* creation date: ydd */ + labeldate_t DS1EXPDT; /* expiration date */ + __u8 DS1NOEPV; /* number of extents on volume */ + __u8 DS1NOBDB; /* no. of bytes used in last direction blk */ + __u8 DS1FLAG1; /* flag 1 */ + char DS1SYSCD[13]; /* system code */ + labeldate_t DS1REFD; /* date last referenced */ + __u8 DS1SMSFG; /* system managed storage indicators */ + __u8 DS1SCXTF; /* sec. space extension flag byte */ + __u16 DS1SCXTV; /* secondary space extension value */ + __u8 DS1DSRG1; /* data set organisation byte 1 */ + __u8 DS1DSRG2; /* data set organisation byte 2 */ + __u8 DS1RECFM; /* record format */ + __u8 DS1OPTCD; /* option code */ + __u16 DS1BLKL; /* block length */ + __u16 DS1LRECL; /* record length */ + __u8 DS1KEYL; /* key length */ + __u16 DS1RKP; /* relative key position */ + __u8 DS1DSIND; /* data set indicators */ + __u8 DS1SCAL1; /* secondary allocation flag byte */ + char DS1SCAL3[3]; /* secondary allocation quantity */ + ttr_t DS1LSTAR; /* last used track and block on track */ + __u16 DS1TRBAL; /* space remaining on last used track */ + __u16 res1; /* reserved */ + extent_t DS1EXT1; /* first extent description */ + extent_t DS1EXT2; /* second extent description */ + extent_t DS1EXT3; /* third extent description */ + cchhb_t DS1PTRDS; /* possible pointer to f2 or f3 DSCB */ +} __attribute__ ((packed)) format1_label_t; + + +typedef struct format4_label { + char DS4KEYCD[44]; /* key code for VTOC labels: 44 times 0x04 */ + __u8 DS4IDFMT; /* format identifier */ + cchhb_t DS4HPCHR; /* highest address of a format 1 DSCB */ + __u16 DS4DSREC; /* number of available DSCB's */ + cchh_t DS4HCCHH; /* CCHH of next available alternate track */ + __u16 DS4NOATK; /* number of remaining alternate tracks */ + __u8 DS4VTOCI; /* VTOC indicators */ + __u8 DS4NOEXT; /* number of extents in VTOC */ + __u8 DS4SMSFG; /* system managed storage indicators */ + __u8 DS4DEVAC; /* number of alternate cylinders. + Subtract from first two bytes of + DS4DEVSZ to get number of usable + cylinders. can be zero. valid + only if DS4DEVAV on. */ + dev_const_t DS4DEVCT; /* device constants */ + char DS4AMTIM[8]; /* VSAM time stamp */ + char DS4AMCAT[3]; /* VSAM catalog indicator */ + char DS4R2TIM[8]; /* VSAM volume/catalog match time stamp */ + char res1[5]; /* reserved */ + char DS4F6PTR[5]; /* pointer to first format 6 DSCB */ + extent_t DS4VTOCE; /* VTOC extent description */ + char res2[10]; /* reserved */ + __u8 DS4EFLVL; /* extended free-space management level */ + cchhb_t DS4EFPTR; /* pointer to extended free-space info */ + char res3[9]; /* reserved */ +} __attribute__ ((packed)) format4_label_t; + + +char * vtoc_ebcdic_enc ( + unsigned char source[LINE_LENGTH], + unsigned char target[LINE_LENGTH], + int l); +char * vtoc_ebcdic_dec ( + unsigned char source[LINE_LENGTH], + unsigned char target[LINE_LENGTH], + int l); +void vtoc_set_extent ( + extent_t * ext, + __u8 typeind, + __u8 seqno, + cchh_t * lower, + cchh_t * upper); +void vtoc_set_cchh ( + cchh_t * addr, + __u16 cc, + __u16 hh); +void vtoc_set_cchhb ( + cchhb_t * addr, + __u16 cc, + __u16 hh, + __u8 b); +void vtoc_set_date ( + labeldate_t * d, + __u8 year, + __u16 day); + + +int vtoc_read_volume_label ( + char * device, + unsigned long vlabel_start, + volume_label_t * vlabel); +int vtoc_write_volume_label ( + char * device, + unsigned long vlabel_start, + volume_label_t * vlabel); +void vtoc_read_label ( + char *device, + unsigned long position, + format4_label_t *f4, + format1_label_t *f1); +void vtoc_write_label ( + char *device, + unsigned long position, + format4_label_t *f4, + format1_label_t *f1); +void vtoc_init_format4_label ( + struct hd_geometry *geo, + format4_label_t *f4lbl, + unsigned int usable_partitions, + unsigned int cylinders, + unsigned int tracks, + unsigned int blocks); +void vtoc_init_format1_label ( + char *volid, + unsigned int blksize, + extent_t *part_extent, + format1_label_t *f1); +void vtoc_update_format4_label ( + format4_label_t *f4, + cchhb_t *highest_f1, + __u8 unused_update, + __u16 freespace_update); + + + + + + + + + + + + + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/atomic.h linux.ac/include/asm-s390x/atomic.h --- linux.vanilla/include/asm-s390x/atomic.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/atomic.h Thu Apr 12 12:06:16 2001 @@ -5,7 +5,7 @@ * include/asm-s390x/atomic.h * * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), * Denis Joseph Barrow * @@ -25,6 +25,15 @@ #define atomic_eieio() __asm__ __volatile__ ("BCR 15,0") +#define __CS_LOOP(old, new, ptr, op_val, op_string) \ + __asm__ __volatile__(" l %0,0(%2)\n" \ + "0: lr %1,%0\n" \ + op_string " %1,%3\n" \ + " cs %0,%1,0(%2)\n" \ + " jl 0b" \ + : "=&d" (old), "=&d" (new) \ + : "a" (ptr), "d" (op_val) : "cc" ); + static __inline__ int atomic_read(atomic_t *v) { int retval; @@ -43,149 +52,80 @@ static __inline__ void atomic_add(int i, atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,0(2)\n" - "0: lr 1,0\n" - " ar 1,%1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : "d" (i) : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, i, "ar"); } static __inline__ int atomic_add_return (int i, atomic_t *v) { - int newval; - __asm__ __volatile__(" la 1,%0\n" - " l 0,0(1)\n" - "0: lr %1,0\n" - " ar %1,%2\n" - " cs 0,%1,0(1)\n" - " jl 0b" - : "+m" (*v), "=&d" (newval) - : "d" (i) : "0", "1", "cc" ); - return newval; -} - -static __inline__ int atomic_inc_and_test(volatile atomic_t *v) -{ - int i; - - __asm__ __volatile__(" l 0,%0\n" - "0: lr %1,0\n" - " ahi %1,1\n" - " cs 0,%1,%0\n" - " jl 0b" - : "+m" (*v), "=&d" (i) : : "0", "cc" ); - return i != 0; + int old, new; + __CS_LOOP(old, new, v, i, "ar"); + return new; } static __inline__ int atomic_add_negative(int i, atomic_t *v) { - int newval; - __asm__ __volatile__(" la 1,%0\n" - " l 0,0(1)\n" - "0: lr %1,0\n" - " ar %1,%2\n" - " cs 0,%1,0(1)\n" - " jl 0b\n" - : "+m" (*v), "=&d" (newval) - : "d" (i) : "0", "1", "cc" ); - return newval < 0; + int old, new; + __CS_LOOP(old, new, v, i, "ar"); + return new < 0; } static __inline__ void atomic_sub(int i, atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,0(2)\n" - "0: lr 1,0\n" - " sr 1,%1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : "d" (i) : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, i, "sr"); } static __inline__ void atomic_inc(volatile atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,0(2)\n" - "0: lr 1,0\n" - " ahi 1,1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, 1, "ar"); } static __inline__ int atomic_inc_return(volatile atomic_t *v) { - int i; - __asm__ __volatile__(" la 1,%0\n" - " l 0,0(1)\n" - "0: lr %1,0\n" - " ahi %1,1\n" - " cs 0,%1,0(1)\n" - " jl 0b" - : "+m" (*v), "=&d" (i) : : "0", "1", "cc" ); - return i; + int old, new; + __CS_LOOP(old, new, v, 1, "ar"); + return new; +} + +static __inline__ int atomic_inc_and_test(volatile atomic_t *v) +{ + int old, new; + __CS_LOOP(old, new, v, 1, "ar"); + return new != 0; } static __inline__ void atomic_dec(volatile atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,0(2)\n" - "0: lr 1,0\n" - " ahi 1,-1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, 1, "sr"); } static __inline__ int atomic_dec_return(volatile atomic_t *v) { - int i; - __asm__ __volatile__(" la 1,%0\n" - " l 0,0(1)\n" - "0: lr %1,0\n" - " ahi %1,-1\n" - " cs 0,%1,0(1)\n" - " jl 0b" - : "+m" (*v), "=&d" (i) : : "0", "1", "cc" ); - return i; + int old, new; + __CS_LOOP(old, new, v, 1, "sr"); + return new; } static __inline__ int atomic_dec_and_test(volatile atomic_t *v) { - int i; - __asm__ __volatile__(" la 1,%0\n" - " l 0,0(1)\n" - "0: lr %1,0\n" - " ahi %1,-1\n" - " cs 0,%1,0(1)\n" - " jl 0b" - : "+m" (*v), "=&d" (i) : : "0", "1", "cc"); - return i == 0; + int old, new; + __CS_LOOP(old, new, v, 1, "sr"); + return new == 0; } static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,0(2)\n" - "0: lr 1,0\n" - " nr 1,%1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : "d" (~(mask)) - : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, ~mask, "nr"); } static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,0(2)\n" - "0: lr 1,0\n" - " or 1,%1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : "d" (mask) : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, mask, "or"); } /* @@ -198,14 +138,14 @@ int retval; __asm__ __volatile__( - " la 1,%1\n" " lr 0,%2\n" - " cs 0,%3,0(1)\n" + " cs 0,%3,0(%1)\n" " ipm %0\n" - " srl %0,28" - : "=&r" (retval), "+m" (*v) - : "d" (expected_oldval) , "d" (new_val) - : "0", "1", "cc"); + " srl %0,28\n" + "0:" + : "=&d" (retval) + : "a" (v), "d" (expected_oldval) , "d" (new_val) + : "0", "cc"); return retval; } @@ -216,13 +156,11 @@ atomic_compare_and_swap_spin(int expected_oldval,int new_val,atomic_t *v) { __asm__ __volatile__( - " la 1,%0\n" "0: lr 0,%1\n" - " cs 0,%2,0(1)\n" + " cs 0,%2,0(%0)\n" " jl 0b\n" - : "+m" (*v) - : "d" (expected_oldval) , "d" (new_val) - : "cc", "0", "1"); + : : "a" (v), "d" (expected_oldval) , "d" (new_val) + : "cc", "0" ); } #define atomic_compare_and_swap_debug(where,from,to) \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/ccwcache.h linux.ac/include/asm-s390x/ccwcache.h --- linux.vanilla/include/asm-s390x/ccwcache.h Tue Apr 3 17:32:27 2001 +++ linux.ac/include/asm-s390x/ccwcache.h Thu Apr 12 12:06:16 2001 @@ -62,6 +62,7 @@ #define CQR_STATUS_DONE 0x04 /* request is completed successfully */ #define CQR_STATUS_ERROR 0x05 /* request is completed with error */ #define CQR_STATUS_FAILED 0x06 /* request is finally failed */ +#define CQR_STATUS_PENDING 0x07 /* request is waiting for interrupt - ERP only */ #define CQR_FLAGS_CHAINED 0x01 /* request is chained by another (last CCW is TIC) */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/chandev.h linux.ac/include/asm-s390x/chandev.h --- linux.vanilla/include/asm-s390x/chandev.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/chandev.h Thu Apr 12 12:06:16 2001 @@ -66,6 +66,12 @@ unsigned long irqflags, const char *devname, void *dev_id); +/* + * I originally believed this function wouldn't be necessary + * I subsequently found that reprobing failed in certain cases :-(, + * It is just a wrapper for free irq. + */ +void chandev_free_irq(unsigned int irq, void *dev_id); typedef enum { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/cpcmd.h linux.ac/include/asm-s390x/cpcmd.h --- linux.vanilla/include/asm-s390x/cpcmd.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-s390x/cpcmd.h Thu Apr 12 12:06:16 2001 @@ -0,0 +1,14 @@ +/* + * arch/s390/kernel/cpcmd.h + * + * S390 version + * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), + */ + +#ifndef __CPCMD__ +#define __CPCMD__ + +extern void cpcmd(char *cmd, char *response, int rlen); + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/dasd.h linux.ac/include/asm-s390x/dasd.h --- linux.vanilla/include/asm-s390x/dasd.h Tue Apr 3 17:32:27 2001 +++ linux.ac/include/asm-s390x/dasd.h Thu Apr 12 12:06:16 2001 @@ -5,11 +5,16 @@ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * * History of changes (starts July 2000) + * 02/01/01 added dynamic registration of ioctls */ #ifndef DASD_H #define DASD_H +#undef ERP_DEBUG /* enable debug messages */ +#undef ERP_FULL_ERP /* enable full ERP - experimental code !!!! */ +#define CONFIG_DASD_DYNAMIC + #include <linux/ioctl.h> #include <asm/irq.h> @@ -29,6 +34,10 @@ /* translate blocknumber of partition to absolute */ #define BIODASDRWTB _IOWR(IOCTL_LETTER,0,int) +typedef int(*dasd_ioctl_fn_t) (struct inode *inp, int no, long args); +int dasd_ioctl_no_register(int no, dasd_ioctl_fn_t handler); +int dasd_ioctl_no_unregister(int no, dasd_ioctl_fn_t handler); + #define DASD_NAME "dasd" #define DASD_PARTN_BITS 2 #define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS)) @@ -49,6 +58,10 @@ #define DASD_FORMAT_DEFAULT_BLOCKSIZE -1 #define DASD_FORMAT_DEFAULT_INTENSITY -1 +#define DASD_FORMAT_INTENS_WRITE_RECZERO 0x01 +#define DASD_FORMAT_INTENS_WRITE_HOMEADR 0x02 +#define DASD_FORMAT_INTENS_INVALIDATE 0x04 +#define DASD_FORMAT_INTENS_CDL 0x08 #ifdef __KERNEL__ #include <linux/version.h> #include <linux/major.h> @@ -135,9 +148,15 @@ typedef struct dasd_devreg_t { devreg_t devreg; /* the devreg itself */ /* build a linked list of devregs, needed for cleanup */ - struct dasd_devreg_t *next; + struct list_head list; } dasd_devreg_t; +typedef struct { + struct list_head list; + int no; + dasd_ioctl_fn_t handler; +} dasd_ioctl_list_t; + typedef enum { dasd_era_fatal = -1, /* no chance to recover */ dasd_era_none = 0, /* don't recover, everything alright */ @@ -168,7 +187,7 @@ int d_major = MAJOR(d_device->kdev); \ int d_minor = MINOR(d_device->kdev); \ printk(d_loglevel PRINTK_HEADER \ - "/dev/%s(%d:%d), 0x%04X on SCH 0x%x:" \ + "/dev/%s(%d:%d),%04X IRQ0x%x:" \ d_string "\n",d_name,d_major,d_minor,d_devno,d_irq,d_args ); \ } while(0) @@ -181,6 +200,7 @@ unsigned long blocks; /* size of volume in blocks */ unsigned int bp_block; /* bytes per block */ unsigned int s2b_shift; /* log2 (bp_block/512) */ + unsigned int pt_block; /* from which block to read the partn table */ } dasd_sizes_t; /* @@ -193,6 +213,38 @@ ccw_req_t *tail; } dasd_chanq_t; +#define DASD_DEVICE_FORMAT_STRING "Device: %p" +#define DASD_DEVICE_DEBUG_EVENT(d_level, d_device, d_str, d_data...)\ +do {\ + if ( d_device->debug_area != NULL )\ + debug_sprintf_event(d_device->debug_area,d_level,\ + DASD_DEVICE_FORMAT_STRING d_str "\n",\ + d_device, d_data);\ +} while(0); +#define DASD_DEVICE_DEBUG_EXCEPTION(d_level, d_device, d_str, d_data...)\ +do {\ + if ( d_device->debug_area != NULL )\ + debug_sprintf_exception(d_device->debug_area,d_level,\ + DASD_DEVICE_FORMAT_STRING d_str "\n",\ + d_device, d_data);\ +} while(0); + +#define DASD_DRIVER_FORMAT_STRING "Driver: <[%p]>" +#define DASD_DRIVER_DEBUG_EVENT(d_level, d_fn, d_str, d_data...)\ +do {\ + if ( dasd_debug_area != NULL )\ + debug_sprintf_event(dasd_debug_area, d_level,\ + DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\ + d_fn, d_data);\ +} while(0); +#define DASD_DRIVER_DEBUG_EXCEPTION(d_level, d_fn, d_str, d_data...)\ +do {\ + if ( dasd_debug_area != NULL )\ + debug_sprintf_exception(dasd_debug_area, d_level,\ + DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\ + d_fn, d_data);\ +} while(0); + struct dasd_device_t; struct request; @@ -230,7 +282,7 @@ typedef struct dasd_discipline_t { char ebcname[8]; /* a name used for tagging and printks */ char name[8]; /* a name used for tagging and printks */ - + int max_blocks; /* maximum number of blocks to be chained */ dasd_ck_id_fn_t id_check; /* to check sense data */ dasd_ck_characteristics_fn_t check_characteristics; /* to check the characteristics */ dasd_init_analysis_fn_t init_analysis; /* to start the analysis of the volume */ @@ -251,9 +303,13 @@ struct dasd_discipline_t *next; /* used for list of disciplines */ } dasd_discipline_t; +#define DASD_MAJOR_INFO_REGISTERED 1 +#define DASD_MAJOR_INFO_IS_STATIC 2 + typedef struct major_info_t { - struct major_info_t *next; + struct list_head list; struct dasd_device_t **dasd_device; + int flags; struct gendisk gendisk; /* actually contains the major number */ } __attribute__ ((packed)) major_info_t; @@ -278,6 +334,7 @@ struct dasd_chanq_t queue; wait_queue_head_t wait_q; request_queue_t request_queue; + struct timer_list timer; devstat_t dev_status; /* needed ONLY!! for request_irq */ dasd_sizes_t sizes; char name[16]; /* The name of the device in /dev */ @@ -300,7 +357,7 @@ #define DASD_DEVICE_LEVEL_ANALYSIS_PENDING 0x02 #define DASD_DEVICE_LEVEL_ANALYSIS_PREPARED 0x04 #define DASD_DEVICE_LEVEL_ANALYSED 0x08 -#define DASD_DEVICE_LEVEL_PARTITIONED 0x10 +#define DASD_DEVICE_LEVEL_ONLINE 0x10 int dasd_init (void); void dasd_discipline_enq (dasd_discipline_t *); @@ -312,8 +369,12 @@ int dasd_chanq_deq (dasd_chanq_t *, ccw_req_t *); 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 *); +extern int (*genhd_dasd_name) (char *, int, int, struct gendisk *); +extern int (*genhd_dasd_fillgeo) (int, struct hd_geometry *); int dasd_oper_handler (int irq, devreg_t * devreg); +void dasd_schedule_bh (dasd_device_t *); + +debug_info_t *dasd_debug_area; #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/debug.h linux.ac/include/asm-s390x/debug.h --- linux.vanilla/include/asm-s390x/debug.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/debug.h Thu Apr 12 12:06:16 2001 @@ -19,9 +19,8 @@ struct { unsigned long long clock:52; unsigned long long exception:1; - unsigned long long used:1; - unsigned long long unused:1; - unsigned long long cpuid:9; + unsigned long long level:3; + unsigned long long cpuid:8; } fields; unsigned long long stck; @@ -29,6 +28,9 @@ void* caller; } __attribute__((packed)); + +#define __DEBUG_FEATURE_VERSION 1 /* version of debug feature */ + #ifdef __KERNEL__ #include <linux/version.h> #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) @@ -45,7 +47,6 @@ #define DEBUG_MAX_VIEWS 10 /* max number of views in proc fs */ #define DEBUG_MAX_PROCF_LEN 16 /* max length for a proc file name */ #define DEBUG_DEFAULT_LEVEL 3 /* initial debug level */ -#define DEBUG_FEATURE_VERSION 1 /* version of debug feature */ #define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */ @@ -103,43 +104,98 @@ debug_header_proc_t* header_proc; debug_format_proc_t* format_proc; debug_input_proc_t* input_proc; + void* private_data; }; extern struct debug_view debug_hex_ascii_view; extern struct debug_view debug_raw_view; +extern struct debug_view debug_sprintf_view; + +/* do NOT use the _common functions */ + +debug_entry_t* debug_event_common(debug_info_t* id, int level, + const void* data, int length); + +debug_entry_t* debug_exception_common(debug_info_t* id, int level, + const void* data, int length); + +/* Debug Feature API: */ debug_info_t* debug_register(char* name, int pages_index, int nr_areas, - int buf_size); + int buf_size); + void debug_unregister(debug_info_t* id); void debug_set_level(debug_info_t* id, int new_level); -debug_entry_t* debug_event(debug_info_t* id, int level, void* data, - int length); -debug_entry_t* debug_int_event(debug_info_t* id, int level, - unsigned int tag); -debug_entry_t* debug_text_event(debug_info_t* id, int level, - const char* txt); - -debug_entry_t* debug_exception(debug_info_t* id, int level, void* data, - int length); -debug_entry_t* debug_int_exception(debug_info_t* id, int level, - unsigned int tag); -debug_entry_t* debug_text_exception(debug_info_t* id, int level, - const char* txt); +extern inline debug_entry_t* +debug_event(debug_info_t* id, int level, void* data, int length) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,data,length); +} + +extern inline debug_entry_t* +debug_int_event(debug_info_t* id, int level, unsigned int tag) +{ + unsigned int t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,&t,sizeof(unsigned int)); +} -static inline debug_entry_t * +extern inline debug_entry_t * debug_long_event (debug_info_t* id, int level, unsigned long tag) { - unsigned long t=tag; - return debug_event(id,level,&t,sizeof(unsigned long)); + unsigned long t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,&t,sizeof(unsigned long)); +} + +extern inline debug_entry_t* +debug_text_event(debug_info_t* id, int level, const char* txt) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,txt,strlen(txt)); } -static inline debug_entry_t * + +extern debug_entry_t * +debug_sprintf_event(debug_info_t* id,int level,char *string,...); + + +extern inline debug_entry_t* +debug_exception(debug_info_t* id, int level, void* data, int length) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,data,length); +} + +extern inline debug_entry_t* +debug_int_exception(debug_info_t* id, int level, unsigned int tag) +{ + unsigned int t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,&t,sizeof(unsigned int)); +} + +extern inline debug_entry_t * debug_long_exception (debug_info_t* id, int level, unsigned long tag) { - unsigned long t=tag; - return debug_exception(id,level,&t,sizeof(unsigned long)); + unsigned long t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,&t,sizeof(unsigned long)); +} + +extern inline debug_entry_t* +debug_text_exception(debug_info_t* id, int level, const char* txt) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,txt,strlen(txt)); } + + +extern debug_entry_t * +debug_sprintf_exception(debug_info_t* id,int level,char *string,...); + int debug_register_view(debug_info_t* id, struct debug_view* view); int debug_unregister_view(debug_info_t* id, struct debug_view* view); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/delay.h linux.ac/include/asm-s390x/delay.h --- linux.vanilla/include/asm-s390x/delay.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/delay.h Thu Apr 12 12:06:16 2001 @@ -8,7 +8,7 @@ * Derived from "include/asm-i386/delay.h" * Copyright (C) 1993 Linus Torvalds * - * Delay routines calling functions in arch/i386/lib/delay.c + * Delay routines calling functions in arch/s390x/lib/delay.c */ #ifndef _S390_DELAY_H diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/ebcdic.h linux.ac/include/asm-s390x/ebcdic.h --- linux.vanilla/include/asm-s390x/ebcdic.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/ebcdic.h Thu Apr 12 12:06:16 2001 @@ -24,24 +24,18 @@ extern __inline__ void codepage_convert(const __u8 *codepage, volatile __u8 * addr, unsigned long nr) { - static const __u16 tr_op[] = { 0xDC00, 0x1000,0x3000 }; + if (nr <= 0) + return; __asm__ __volatile__( - " lgr 1,%0\n" - " lgr 2,%1\n" - " lgr 3,%2\n" - " aghi 2,-256\n" - " jm 1f\n" - "0: tr 0(256,1),0(3)\n" - " aghi 1,256\n" - " aghi 2,-256\n" - " jp 0b\n" - "1: aghi 2,255\n" - " jm 2f\n" - " ex 2,%3\n" - "2:" - : /* no output */ - : "a" (addr), "d" (nr), "a" (codepage), "m" (tr_op[0]) - : "cc", "memory", "1", "2", "3" ); + " bras 1,1f\n" + " tr 0(1,%0),0(%2)\n" + "0: la %0,256(%0)\n" + " tr 0(256,%0),0(%2)\n" + "1: ahi %1,-256\n" + " jp 0b\n" + " ex %1,0(1)" + : "+&a" (addr), "+&a" (nr-1) + : "a" (codepage) : "cc", "memory", "1" ); } #define ASCEBC(addr,nr) codepage_convert(_ascebc, addr, nr) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/elf.h linux.ac/include/asm-s390x/elf.h --- linux.vanilla/include/asm-s390x/elf.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/elf.h Thu Apr 12 12:06:16 2001 @@ -31,7 +31,8 @@ * This is used to ensure we don't load something for the wrong architecture. */ #define elf_check_arch(x) \ - ((x)->e_machine == ELF_ARCH && (x)->e_ident[EI_CLASS] == ELF_CLASS) + (((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \ + && (x)->e_ident[EI_CLASS] == ELF_CLASS) /* For SVR4/S390 the function pointer to be registered with `atexit` is passed in R14. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/irq.h linux.ac/include/asm-s390x/irq.h --- linux.vanilla/include/asm-s390x/irq.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/irq.h Thu Apr 12 12:06:16 2001 @@ -1,5 +1,5 @@ -#ifndef __irq_h -#define __irq_h +#ifndef _ASM_IRQ_H +#define _ASM_IRQ_H #include <linux/config.h> #ifdef __KERNEL__ @@ -19,28 +19,6 @@ extern int enable_irq(unsigned int); /* - * Interrupt controller descriptor. This is all we need - * to describe about the low-level hardware. - */ -struct hw_interrupt_type { - const __u8 *typename; - int (*handle)(unsigned int irq, - int cpu, - struct pt_regs * regs); - int (*enable) (unsigned int irq); - int (*disable)(unsigned int irq); -}; - -/* - * Status: reason for being disabled: somebody has - * done a "disable_irq()" or we must not re-enter the - * already executing irq.. - */ -#define IRQ_INPROGRESS 1 -#define IRQ_DISABLED 2 -#define IRQ_PENDING 4 - -/* * path management control word */ typedef struct { @@ -86,7 +64,7 @@ __u32 pfch : 1; /* prefetch */ __u32 isic : 1; /* initial-status interruption control */ __u32 alcc : 1; /* address-limit checking control */ - __u32 ssi : 1; /* suppress-suspended interruption */ + __u32 ssi : 1; /* supress-suspended interruption */ __u32 zcc : 1; /* zero condition code */ __u32 ectl : 1; /* extended control */ __u32 pno : 1; /* path not operational */ @@ -186,7 +164,7 @@ typedef struct { __u8 cmd_code;/* command code */ - __u8 flags; /* flags, like IDA addressing, etc. */ + __u8 flags; /* flags, like IDA adressing, etc. */ __u16 count; /* byte count */ __u32 cda; /* data address */ } __attribute__ ((packed,aligned(8))) ccw1_t; @@ -456,24 +434,10 @@ typedef int (* adapter_int_handler_t)( __u32 intparm ); -struct s390_irqaction { - io_handler_func_t handler; - unsigned long flags; - const char *name; - devstat_t *dev_id; -}; - -/* - * This is the "IRQ descriptor", which contains various information - * about the irq, including what kind of hardware handling it has, - * whether it is disabled etc etc. - * - * Pad this out to 32 bytes for cache and indexing reasons. - */ typedef struct { - unsigned int status; /* IRQ status - IRQ_INPROGRESS, IRQ_DISABLED */ - struct hw_interrupt_type *handler; /* handle/enable/disable functions */ - struct s390_irqaction *action; /* IRQ action list */ + io_handler_func_t handler; /* interrupt handler routine */ + const char *name; /* device name */ + devstat_t *dev_id; /* device status block */ } irq_desc_t; typedef struct { @@ -531,9 +495,8 @@ /* * do_IO() * - * Start a S/390 channel program. When the interrupt arrives - * handle_IRQ_event() is called, which eventually calls the - * IRQ handler, either immediately, delayed (dev-end missing, + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, * or sense required) or never (no IRQ handler registered - * should never occur, as the IRQ (subchannel ID) should be * disabled if no handler is present. Depending on the action @@ -606,8 +569,6 @@ const char *devname, void *dev_id); -extern int handle_IRQ_event( unsigned int irq, int cpu, struct pt_regs *); - extern int set_cons_dev(int irq); extern int reset_cons_dev(int irq); extern int wait_cons_dev(int irq); @@ -621,16 +582,13 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "STSCH 0(%2)\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr) - : "cc", "1" ); + " lr 1,%1\n" + " stsch 0(%2)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000), "a" (addr) + : "cc", "1" ); return ccode; } @@ -639,15 +597,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "MSCH 0(%2)\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr) + " lr 1,%1\n" + " msch 0(%2)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L), "a" (addr) : "cc", "1" ); return ccode; } @@ -657,12 +612,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - " lgr 1,%1\n" + " lr 1,%1\n" " msch 0(%2)\n" "0: ipm %0\n" " srl %0,28\n" "1:\n" +#ifdef CONFIG_ARCH_S390X ".section .fixup,\"ax\"\n" "2: l %0,%3\n" " jg 1b\n" @@ -671,12 +626,12 @@ " .align 8\n" " .quad 0b,2b\n" ".previous" -#else " lr 1,%1\n" " msch 0(%2)\n" "0: ipm %0\n" " srl %0,28\n" "1:\n" +#else ".section .fixup,\"ax\"\n" "2: l %0,%3\n" " bras 1,3f\n" @@ -690,7 +645,7 @@ ".previous" #endif : "=d" (ccode) - : "r" (irq | 0x10000L), "a" (addr), "i" (__LC_PGM_ILC) + : "d" (irq | 0x10000L), "a" (addr), "i" (__LC_PGM_ILC) : "cc", "1" ); return ccode; } @@ -700,15 +655,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "TSCH 0(%2)\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr) + " lr 1,%1\n" + " tsch 0(%2)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L), "a" (addr) : "cc", "1" ); return ccode; } @@ -718,10 +670,11 @@ int ccode; __asm__ __volatile__( - "TPI 0(%1)\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "a" (addr) + " tpi 0(%1)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "a" (addr) : "cc", "1" ); return ccode; } @@ -731,15 +684,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "SSCH 0(%2)\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr) + " lr 1,%1\n" + " ssch 0(%2)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L), "a" (addr) : "cc", "1" ); return ccode; } @@ -749,15 +699,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "RSCH\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L) + " lr 1,%1\n" + " rsch\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L) : "cc", "1" ); return ccode; } @@ -767,15 +714,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "CSCH\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L) + " lr 1,%1\n" + " csch\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L) : "cc", "1" ); return ccode; } @@ -785,15 +729,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "HSCH\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L) + " lr 1,%1\n" + " hsch\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L) : "cc", "1" ); return ccode; } @@ -803,9 +744,9 @@ int ccode; __asm__ __volatile__( - "IAC 1\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" + " iac 1\n" + " ipm %0\n" + " srl %0,28" : "=d" (ccode) : : "cc", "1" ); return ccode; } @@ -815,15 +756,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "RCHP\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (chpid) + " lr 1,%1\n" + " rchp\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (chpid) : "cc", "1" ); return ccode; } @@ -850,16 +788,16 @@ __asm__ __volatile__( #ifdef CONFIG_ARCH_S390X - "SAM31\n\t" - "DIAG %1,0,0x210\n\t" - "SAM64\n\t" -#else - "LR 1,%1\n\t" - ".long 0x83110210\n\t" -#endif - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "a" (addr) + " sam31\n" + " diag %1,0,0x210\n" + " sam64\n" +#else + " diag %1,0,0x210\n" +#endif + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "a" (addr) : "cc" ); return ccode; } @@ -885,15 +823,9 @@ static inline void irq_enter(int cpu, unsigned int irq) { hardirq_enter(cpu); -#ifdef CONFIG_ARCH_S390X while (atomic_read(&global_irq_lock) != 0) { eieio(); } -#else - while (test_bit(0,&global_irq_lock)) { - eieio(); - } -#endif } static inline void irq_exit(int cpu, unsigned int irq) @@ -958,5 +890,8 @@ #define s390irq_spin_unlock_irqrestore(irq,flags) \ spin_unlock_irqrestore(&(ioinfo[irq]->irq_lock), flags) #endif /* __KERNEL__ */ + +#define touch_nmi_watchdog() do { } while(0) + #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/irqextras390.h linux.ac/include/asm-s390x/irqextras390.h --- linux.vanilla/include/asm-s390x/irqextras390.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/irqextras390.h Thu Jan 1 01:00:00 1970 @@ -1,151 +0,0 @@ -/* - * include/asm-s390/irqextras390.h - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - */ - -#ifndef __irqextras390_h -#define __irqextras390_h - -/* - irqextras390.h by D.J. Barrow - if you are a bitfield fan & are paranoid that ansi dosen't - give hard definitions about the size of an int or long you might - prefer these definitions as an alternative. - -*/ - -#include <linux/types.h> - -typedef struct -{ - unsigned key:4; - unsigned s:1; - unsigned l:1; - unsigned cc:2; - unsigned f:1; - unsigned p:1; - unsigned i:1; - unsigned a:1; - unsigned u:1; - unsigned z:1; - unsigned e:1; - unsigned n:1; - unsigned zero:1; - - unsigned fc_start:1; - unsigned fc_halt:1; - unsigned fc_clear:1; - - unsigned ac_resume_pending:1; - unsigned ac_start_pending:1; - unsigned ac_halt_pending:1; - unsigned ac_clear_pending:1; - unsigned ac_subchannel_active:1; - unsigned ac_device_active:1; - unsigned ac_suspended:1; - - unsigned sc_alert:1; - unsigned sc_intermediate:1; - unsigned sc_primary:1; - unsigned sc_seconary:1; - unsigned sc_status_pending:1; - - __u32 ccw_address; - - unsigned dev_status_attention:1; - unsigned dev_status_modifier:1; - unsigned dev_status_control_unit_end:1; - unsigned dev_status_busy:1; - unsigned dev_status_channel_end:1; - unsigned dev_status_device_end:1; - unsigned dev_status_unit_check:1; - unsigned dev_status_unit_exception:1; - - unsigned sch_status_program_cont_int:1; - unsigned sch_status_incorrect_length:1; - unsigned sch_status_program_check:1; - unsigned sch_status_protection_check:1; - unsigned sch_status_channel_data_check:1; - unsigned sch_status_channel_control_check:1; - unsigned sch_status_interface_control_check:1; - unsigned sch_status_chaining_check:1; - - __u16 byte_count; -} scsw_bits_t __attribute__((packed)); - -typedef struct -{ - __u32 flags; - __u32 ccw_address; - __u8 dev_status; - __u8 sch_status; - __u16 byte_count; -} scsw_words_t __attribute__((packed)); - -typedef struct -{ - __u8 cmd_code; - - unsigned cd:1; - unsigned cc:1; - unsigned sli:1; - unsigned skip:1; - unsigned pci:1; - unsigned ida:1; - unsigned s:1; - unsigned res1:1; - - __u16 count; - - __u32 ccw_data_address; -} ccw1_bits_t __attribute__((packed,aligned(8))); - -typedef struct -{ - __u32 interruption_parm; - unsigned key:4; - unsigned s:1; - unsigned res1:3; - unsigned f:1; - unsigned p:1; - unsigned i:1; - unsigned a:1; - unsigned u:1; - __u8 lpm; - unsigned l:1; - unsigned res2:7; - ccw1_bits_t *ccw_program_address; -} orb_bits_t __attribute__((packed)); - -void fixchannelprogram(orb_bits_t *orbptr); -void fixccws(ccw1_bits_t *ccwptr); -enum -{ - ccw_write=0x1, - ccw_read=0x2, - ccw_read_backward=0xc, - ccw_control=0x3, - ccw_sense=0x4, - ccw_sense_id=0xe4, - ccw_transfer_in_channel0=0x8, - ccw_transfer_in_channel1=0x8, - ccw_set_x_mode=0xc3, // according to uli's lan notes - ccw_nop=0x3 // according to uli's notes again - // n.b. ccw_control clashes with this - // so I presume its a special case of - // control -}; - - - -#endif - - - - - - - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/major.h linux.ac/include/asm-s390x/major.h --- linux.vanilla/include/asm-s390x/major.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/major.h Thu Jan 1 01:00:00 1970 @@ -1,150 +0,0 @@ -#ifndef _LINUX_MAJOR_H -#define _LINUX_MAJOR_H - -/* - * This file has definitions for major device numbers. - * For the device number assignments, see Documentation/devices.txt. - */ - -/* limits */ - -/* - * Important: Don't change this to 256. Major number 255 is and must be - * reserved for future expansion into a larger dev_t space. - */ -#define MAX_CHRDEV 255 -#define MAX_BLKDEV 255 - -#define UNNAMED_MAJOR 0 -#define MEM_MAJOR 1 -#define RAMDISK_MAJOR 1 -#define FLOPPY_MAJOR 2 -#define PTY_MASTER_MAJOR 2 -#define IDE0_MAJOR 3 -#define PTY_SLAVE_MAJOR 3 -#define HD_MAJOR IDE0_MAJOR -#define TTY_MAJOR 4 -#define TTYAUX_MAJOR 5 -#define LP_MAJOR 6 -#define VCS_MAJOR 7 -#define LOOP_MAJOR 7 -#define SCSI_DISK0_MAJOR 8 -#define SCSI_TAPE_MAJOR 9 -#define MD_MAJOR 9 -#define MISC_MAJOR 10 -#define SCSI_CDROM_MAJOR 11 -#define QIC02_TAPE_MAJOR 12 -#define XT_DISK_MAJOR 13 -#define SOUND_MAJOR 14 -#define CDU31A_CDROM_MAJOR 15 -#define JOYSTICK_MAJOR 15 -#define GOLDSTAR_CDROM_MAJOR 16 -#define OPTICS_CDROM_MAJOR 17 -#define SANYO_CDROM_MAJOR 18 -#define CYCLADES_MAJOR 19 -#define CYCLADESAUX_MAJOR 20 -#define MITSUMI_X_CDROM_MAJOR 20 -#define MFM_ACORN_MAJOR 21 /* ARM Linux /dev/mfm */ -#define SCSI_GENERIC_MAJOR 21 -#define Z8530_MAJOR 34 -#define DIGI_MAJOR 23 -#define IDE1_MAJOR 22 -#define DIGICU_MAJOR 22 -#define MITSUMI_CDROM_MAJOR 23 -#define CDU535_CDROM_MAJOR 24 -#define STL_SERIALMAJOR 24 -#define MATSUSHITA_CDROM_MAJOR 25 -#define STL_CALLOUTMAJOR 25 -#define MATSUSHITA_CDROM2_MAJOR 26 -#define QIC117_TAPE_MAJOR 27 -#define MATSUSHITA_CDROM3_MAJOR 27 -#define MATSUSHITA_CDROM4_MAJOR 28 -#define STL_SIOMEMMAJOR 28 -#define ACSI_MAJOR 28 -#define AZTECH_CDROM_MAJOR 29 -#define GRAPHDEV_MAJOR 29 /* SparcLinux & Linux/68k /dev/fb */ -#define SHMIQ_MAJOR 85 /* Linux/mips, SGI /dev/shmiq */ -#define CM206_CDROM_MAJOR 32 -#define IDE2_MAJOR 33 -#define IDE3_MAJOR 34 -#define NETLINK_MAJOR 36 -#define PS2ESDI_MAJOR 36 -#define IDETAPE_MAJOR 37 -#define Z2RAM_MAJOR 37 -#define APBLOCK_MAJOR 38 /* AP1000 Block device */ -#define DDV_MAJOR 39 /* AP1000 DDV block device */ -#define NBD_MAJOR 43 /* Network block device */ -#define RISCOM8_NORMAL_MAJOR 48 -#define DAC960_MAJOR 48 /* 48..55 */ -#define RISCOM8_CALLOUT_MAJOR 49 -#define MKISS_MAJOR 55 -#define DSP56K_MAJOR 55 /* DSP56001 processor device */ - -#define IDE4_MAJOR 56 -#define IDE5_MAJOR 57 - -#define SCSI_DISK1_MAJOR 65 -#define SCSI_DISK2_MAJOR 66 -#define SCSI_DISK3_MAJOR 67 -#define SCSI_DISK4_MAJOR 68 -#define SCSI_DISK5_MAJOR 69 -#define SCSI_DISK6_MAJOR 70 -#define SCSI_DISK7_MAJOR 71 - - -#define LVM_BLK_MAJOR 58 /* Logical Volume Manager */ - -#define COMPAQ_SMART2_MAJOR 72 -#define COMPAQ_SMART2_MAJOR1 73 -#define COMPAQ_SMART2_MAJOR2 74 -#define COMPAQ_SMART2_MAJOR3 75 -#define COMPAQ_SMART2_MAJOR4 76 -#define COMPAQ_SMART2_MAJOR5 77 -#define COMPAQ_SMART2_MAJOR6 78 -#define COMPAQ_SMART2_MAJOR7 79 - -#define SPECIALIX_NORMAL_MAJOR 75 -#define SPECIALIX_CALLOUT_MAJOR 76 - -#define DASD_MAJOR 94 - -#define LVM_CHAR_MAJOR 109 /* Logical Volume Manager */ - -#define MDISK_MAJOR 64 - -#define I2O_MAJOR 80 /* 80->87 */ - -#define IDE6_MAJOR 88 -#define IDE7_MAJOR 89 -#define IDE8_MAJOR 90 -#define IDE9_MAJOR 91 - -#define AURORA_MAJOR 79 - -#define RTF_MAJOR 150 -#define RAW_MAJOR 162 - -#define USB_ACM_MAJOR 166 -#define USB_ACM_AUX_MAJOR 167 -#define USB_CHAR_MAJOR 180 - -#define UNIX98_PTY_MASTER_MAJOR 128 -#define UNIX98_PTY_MAJOR_COUNT 8 -#define UNIX98_PTY_SLAVE_MAJOR (UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT) - -/* - * Tests for SCSI devices. - */ - -#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ - ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR)) - -#define SCSI_BLK_MAJOR(M) \ - (SCSI_DISK_MAJOR(M) \ - || (M) == SCSI_CDROM_MAJOR) - -static __inline__ int scsi_blk_major(int m) { - return SCSI_BLK_MAJOR(m); -} - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/misc390.h linux.ac/include/asm-s390x/misc390.h --- linux.vanilla/include/asm-s390x/misc390.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/misc390.h Thu Jan 1 01:00:00 1970 @@ -1,15 +0,0 @@ -/* - * include/asm-s390/misc390.h - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - */ - -#define allocaligned2(type,name,number,align) \ - __u8 name##buff[(sizeof(type)*(number+1))-1]; \ - type *name=(type *)(((__u32)(&name##buff[align-1]))&(-align)) - -#define allocaligned(type,name,number) allocaligned2(type,name,number,__alignof__(type)) - -extern void s390_daemonize(char *name,unsigned long mask,int use_init_fs); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/page.h linux.ac/include/asm-s390x/page.h --- linux.vanilla/include/asm-s390x/page.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/page.h Thu Apr 12 12:06:16 2001 @@ -9,6 +9,8 @@ #ifndef _S390_PAGE_H #define _S390_PAGE_H +#include <asm/setup.h> + /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 12 #define PAGE_SIZE (1UL << PAGE_SHIFT) @@ -17,12 +19,43 @@ #ifdef __KERNEL__ #ifndef __ASSEMBLY__ -/* - * gcc uses builtin, i.e. MVCLE for both operations - */ +static inline void clear_page(void *page) +{ + asm volatile (" lgr 2,%0\n" + " lghi 3,4096\n" + " slgr 1,1\n" + " mvcl 2,0" + : : "a" ((void *) (page)) + : "memory", "1", "2", "3" ); +} -#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) -#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) +static inline void copy_page(void *to, void *from) +{ + if (MACHINE_HAS_MVPG) + asm volatile (" sgr 0,0\n" + " mvpg %0,%1" + : : "a" ((void *)(to)), "a" ((void *)(from)) + : "memory", "0" ); + else + asm volatile (" mvc 0(256,%0),0(%1)\n" + " mvc 256(256,%0),256(%1)\n" + " mvc 512(256,%0),512(%1)\n" + " mvc 768(256,%0),768(%1)\n" + " mvc 1024(256,%0),1024(%1)\n" + " mvc 1280(256,%0),1280(%1)\n" + " mvc 1536(256,%0),1536(%1)\n" + " mvc 1792(256,%0),1792(%1)\n" + " mvc 2048(256,%0),2048(%1)\n" + " mvc 2304(256,%0),2304(%1)\n" + " mvc 2560(256,%0),2560(%1)\n" + " mvc 2816(256,%0),2816(%1)\n" + " mvc 3072(256,%0),3072(%1)\n" + " mvc 3328(256,%0),3328(%1)\n" + " mvc 3584(256,%0),3584(%1)\n" + " mvc 3840(256,%0),3840(%1)\n" + : : "a"((void *)(to)),"a"((void *)(from)) + : "memory" ); +} #define clear_user_page(page, vaddr) clear_page(page) #define copy_user_page(to, from, vaddr) copy_page(to, from) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/pgalloc.h linux.ac/include/asm-s390x/pgalloc.h --- linux.vanilla/include/asm-s390x/pgalloc.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/pgalloc.h Thu Apr 12 12:06:16 2001 @@ -33,9 +33,11 @@ */ extern __inline__ pgd_t *get_pgd_slow (void) { + pgd_t *ret; int i; - pgd_t *ret = (pgd_t *)__get_free_pages(GFP_KERNEL,2); - if (ret) + + ret = (pgd_t *) __get_free_pages(GFP_KERNEL, 2); + if (ret != NULL) for (i = 0; i < PTRS_PER_PGD; i++) pgd_clear(ret + i); return ret; @@ -77,15 +79,32 @@ #define pgd_free(pgd) free_pgd_fast(pgd) +extern inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd) +{ + pgd_val(*pgd) = _PGD_ENTRY | __pa(pmd); +} + /* * page middle directory allocation/free routines. */ -extern pmd_t empty_bad_pmd_table[]; -extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long address); +extern inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr) +{ + pmd_t *pmd; + int i; -extern __inline__ pmd_t *get_pmd_fast (void) + pmd = (pmd_t *) __get_free_pages(GFP_KERNEL, 2); + if (pmd != NULL) { + for (i=0; i < PTRS_PER_PMD; i++) + pmd_clear(pmd+i); + } + return pmd; +} + +extern __inline__ pmd_t * +pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address) { unsigned long *ret = (unsigned long *) pmd_quicklist; + if (ret != NULL) { pmd_quicklist = (unsigned long *)(*ret); ret[0] = ret[1]; @@ -94,95 +113,67 @@ return (pmd_t *) ret; } -extern __inline__ void free_pmd_fast (pmd_t *pmd) +extern __inline__ void pmd_free_fast (pmd_t *pmd) { - if (pmd == empty_bad_pmd_table) - return; *(unsigned long *) pmd = (unsigned long) pmd_quicklist; pmd_quicklist = (unsigned long *) pmd; pgtable_cache_size += 4; } -extern __inline__ void free_pmd_slow (pmd_t *pmd) +extern __inline__ void pmd_free_slow (pmd_t *pmd) { free_pages((unsigned long) pmd, 2); } -extern __inline__ pmd_t *pmd_alloc (pgd_t *pgd, unsigned long vmaddr) -{ - unsigned long offset; +#define pmd_free(pmd) pmd_free_fast(pmd) - offset = (vmaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1); - if (pgd_none(*pgd)) { - pmd_t *pmd_page = get_pmd_fast(); - - if (!pmd_page) - return get_pmd_slow(pgd, offset); - pgd_set(pgd, pmd_page); - return pmd_page + offset; - } - if (pgd_bad(*pgd)) - BUG(); - return (pmd_t *) pgd_page(*pgd) + offset; +extern inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, pte_t *pte) +{ + pmd_val(*pmd) = _PMD_ENTRY | __pa(pte); + pmd_val1(*pmd) = _PMD_ENTRY | __pa(pte+256); } -#define pmd_alloc_kernel(pgd, addr) pmd_alloc(pgd, addr) -#define pmd_free_kernel(pmd) free_pmd_fast(pmd) -#define pmd_free(pmd) free_pmd_fast(pmd) - /* * page table entry allocation/free routines. */ -extern pte_t empty_bad_pte_table[]; -extern pte_t *get_pte_slow (pmd_t *pmd, unsigned long address_preadjusted); - -extern __inline__ pte_t *get_pte_fast (void) +extern inline pte_t * pte_alloc_one(struct mm_struct *mm, unsigned long vmaddr) { - unsigned long *ret = (unsigned long *) pte_quicklist; + pte_t *pte; + int i; - if (ret != NULL) { - pte_quicklist = (unsigned long *)(*ret); - ret[0] = ret[1]; - pgtable_cache_size--; + pte = (pte_t *) __get_free_page(GFP_KERNEL); + if (pte != NULL) { + for (i=0; i < PTRS_PER_PTE; i++) + pte_clear(pte+i); } - return (pte_t *) ret; + return pte; } -extern __inline__ void free_pte_fast (pte_t *pte) +extern __inline__ pte_t* pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) +{ + unsigned long *ret = (unsigned long *) pte_quicklist; + + if (ret != NULL) { + pte_quicklist = (unsigned long *)(*ret); + ret[0] = ret[1]; + pgtable_cache_size--; + } + return (pte_t *)ret; +} + +extern __inline__ void pte_free_fast (pte_t *pte) { - if (pte == empty_bad_pte_table) - return; *(unsigned long *) pte = (unsigned long) pte_quicklist; pte_quicklist = (unsigned long *) pte; pgtable_cache_size++; } -extern __inline__ void free_pte_slow (pte_t *pte) +extern __inline__ void pte_free_slow (pte_t *pte) { free_page((unsigned long) pte); } -extern __inline__ pte_t *pte_alloc (pmd_t *pmd, unsigned long vmaddr) -{ - unsigned long offset; - - offset = (vmaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - pte_t *pte_page = get_pte_fast(); - - if (!pte_page) - return get_pte_slow(pmd, offset); - pmd_set(pmd, pte_page); - return pte_page + offset; - } - if (pmd_bad(*pmd)) - BUG(); - return (pte_t *) pmd_page(*pmd) + offset; -} - -#define pte_alloc_kernel(pmd, addr) pte_alloc(pmd, addr) -#define pte_free_kernel(pte) free_pte_fast(pte) -#define pte_free(pte) free_pte_fast(pte) +#define pte_free(pte) pte_free_fast(pte) extern int do_check_pgt_cache (int, int); @@ -224,11 +215,28 @@ * on each context switch */ -#define flush_tlb() local_flush_tlb() -#define flush_tlb_all() local_flush_tlb() -#define flush_tlb_mm(mm) local_flush_tlb() -#define flush_tlb_page(vma, va) local_flush_tlb() -#define flush_tlb_range(mm, start, end) local_flush_tlb() +static inline void flush_tlb(void) +{ + local_flush_tlb(); +} +static inline void flush_tlb_all(void) +{ + local_flush_tlb(); +} +static inline void flush_tlb_mm(struct mm_struct *mm) +{ + local_flush_tlb(); +} +static inline void flush_tlb_page(struct vm_area_struct *vma, + unsigned long addr) +{ + local_flush_tlb(); +} +static inline void flush_tlb_range(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + local_flush_tlb(); +} #else @@ -266,11 +274,28 @@ } } -#define flush_tlb() __flush_tlb_mm(current->mm) -#define flush_tlb_all() global_flush_tlb() -#define flush_tlb_mm(mm) __flush_tlb_mm(mm) -#define flush_tlb_page(vma, va) __flush_tlb_mm((vma)->vm_mm) -#define flush_tlb_range(mm, start, end) __flush_tlb_mm(mm) +static inline void flush_tlb(void) +{ + __flush_tlb_mm(current->mm); +} +static inline void flush_tlb_all(void) +{ + global_flush_tlb(); +} +static inline void flush_tlb_mm(struct mm_struct *mm) +{ + __flush_tlb_mm(mm); +} +static inline void flush_tlb_page(struct vm_area_struct *vma, + unsigned long addr) +{ + __flush_tlb_mm(vma->vm_mm); +} +static inline void flush_tlb_range(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + __flush_tlb_mm(mm); +} #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/pgtable.h linux.ac/include/asm-s390x/pgtable.h --- linux.vanilla/include/asm-s390x/pgtable.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/pgtable.h Thu Apr 12 12:06:16 2001 @@ -228,21 +228,41 @@ /* * pgd/pmd/pte query functions */ -extern inline int pgd_present(pgd_t pgd) { return pgd_val(pgd) != 0; } -extern inline int pgd_none(pgd_t pgd) { return pgd_val(pgd) & _PGD_ENTRY_INV; } +extern inline int pgd_present(pgd_t pgd) +{ + return (pgd_val(pgd) & ~PAGE_MASK) == _PGD_ENTRY; +} + +extern inline int pgd_none(pgd_t pgd) +{ + return pgd_val(pgd) & _PGD_ENTRY_INV; +} + extern inline int pgd_bad(pgd_t pgd) { return (pgd_val(pgd) & (~PAGE_MASK & ~_PGD_ENTRY_INV)) != _PGD_ENTRY; } -extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) != 0; } -extern inline int pmd_none(pmd_t pmd) { return pmd_val(pmd) & _PMD_ENTRY_INV; } +extern inline int pmd_present(pmd_t pmd) +{ + return (pmd_val(pmd) & ~PAGE_MASK) == _PMD_ENTRY; +} + +extern inline int pmd_none(pmd_t pmd) +{ + return pmd_val(pmd) & _PMD_ENTRY_INV; +} + extern inline int pmd_bad(pmd_t pmd) { return (pmd_val(pmd) & (~PAGE_MASK & ~_PMD_ENTRY_INV)) != _PMD_ENTRY; } -extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; } +extern inline int pte_present(pte_t pte) +{ + return pte_val(pte) & _PAGE_PRESENT; +} + extern inline int pte_none(pte_t pte) { return ((pte_val(pte) & @@ -411,17 +431,6 @@ #define mk_pte(page,pgprot) mk_pte_phys(__pa(((page)-mem_map)<<PAGE_SHIFT),pgprot) #define pte_page(x) (mem_map+(unsigned long)((pte_val(x) >> PAGE_SHIFT))) - -extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep) -{ - pmd_val(*pmdp) = _PMD_ENTRY | __pa(ptep); - pmd_val1(*pmdp) = _PMD_ENTRY | __pa(ptep+256); -} - -extern inline void pgd_set(pgd_t * pgdp, pmd_t * pmdp) -{ - pgd_val(*pgdp) = _PGD_ENTRY | __pa(pmdp); -} #define pmd_page(pmd) \ ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/ptrace.h linux.ac/include/asm-s390x/ptrace.h --- linux.vanilla/include/asm-s390x/ptrace.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/ptrace.h Thu Apr 12 12:06:16 2001 @@ -8,284 +8,266 @@ #ifndef _S390_PTRACE_H #define _S390_PTRACE_H + +/* + * Offsets in the user_regs_struct. They are used for the ptrace + * system call and in entry.S + */ +#define PT_PSWMASK 0x00 +#define PT_PSWADDR 0x08 +#define PT_GPR0 0x10 +#define PT_GPR1 0x18 +#define PT_GPR2 0x20 +#define PT_GPR3 0x28 +#define PT_GPR4 0x30 +#define PT_GPR5 0x38 +#define PT_GPR6 0x40 +#define PT_GPR7 0x48 +#define PT_GPR8 0x50 +#define PT_GPR9 0x58 +#define PT_GPR10 0x60 +#define PT_GPR11 0x68 +#define PT_GPR12 0x70 +#define PT_GPR13 0x78 +#define PT_GPR14 0x80 +#define PT_GPR15 0x88 +#define PT_ACR0 0x90 +#define PT_ACR1 0x94 +#define PT_ACR2 0x98 +#define PT_ACR3 0x9C +#define PT_ACR4 0xA0 +#define PT_ACR5 0xA4 +#define PT_ACR6 0xA8 +#define PT_ACR7 0xAC +#define PT_ACR8 0xB0 +#define PT_ACR9 0xB4 +#define PT_ACR10 0xB8 +#define PT_ACR11 0xBC +#define PT_ACR12 0xC0 +#define PT_ACR13 0xC4 +#define PT_ACR14 0xC8 +#define PT_ACR15 0xCC +#define PT_ORIGGPR2 0xD0 +#define PT_FPC 0xD8 +#define PT_FPR0 0xE0 +#define PT_FPR1 0xE8 +#define PT_FPR2 0xF0 +#define PT_FPR3 0xF8 +#define PT_FPR4 0x100 +#define PT_FPR5 0x108 +#define PT_FPR6 0x110 +#define PT_FPR7 0x118 +#define PT_FPR8 0x120 +#define PT_FPR9 0x128 +#define PT_FPR10 0x130 +#define PT_FPR11 0x138 +#define PT_FPR12 0x140 +#define PT_FPR13 0x148 +#define PT_FPR14 0x150 +#define PT_FPR15 0x158 +#define PT_CR_9 0x160 +#define PT_CR_10 0x168 +#define PT_CR_11 0x170 +#define PT_IEEE_IP 0x1A8 +#define PT_LASTOFF PT_IEEE_IP +#define PT_ENDREGS 0x1B0-1 + +#define NUM_GPRS 16 +#define NUM_FPRS 16 +#define NUM_CRS 16 +#define NUM_ACRS 16 +#define GPR_SIZE 8 +#define FPR_SIZE 8 +#define FPC_SIZE 4 +#define FPC_PAD_SIZE 4 /* gcc insists on aligning the fpregs */ +#define CR_SIZE 8 +#define ACR_SIZE 4 + +#define STACK_FRAME_OVERHEAD 160 /* size of minimum stack frame */ + +#ifndef __ASSEMBLY__ #include <linux/config.h> -#include <asm/s390-regs-common.h> -#include <asm/current.h> +#include <linux/stddef.h> #include <linux/types.h> + +#include <asm/current.h> #include <asm/setup.h> -#include <linux/stddef.h> +/* this typedef defines how a Program Status Word looks like */ +typedef struct +{ + __u64 mask; + __u64 addr; +} psw_t __attribute__ ((aligned(8))); -#define S390_REGS \ -S390_REGS_COMMON \ -addr_t orig_gpr2; +#ifdef __KERNEL__ +#define FIX_PSW(addr) ((unsigned long)(addr)) +#define ADDR_BITS_REMOVE(addr) ((addr)) +#endif +typedef union +{ + float f; + double d; + __u64 ui; + struct + { + __u32 hi; + __u32 lo; + } fp; +} freg_t; + +typedef struct +{ + __u32 fpc; + freg_t fprs[NUM_FPRS]; +} s390_fp_regs; + +#define FPC_EXCEPTION_MASK 0xF8000000 +#define FPC_FLAGS_MASK 0x00F80000 +#define FPC_DXC_MASK 0x0000FF00 +#define FPC_RM_MASK 0x00000003 +#define FPC_VALID_MASK 0xF8F8FF03 + +/* + * The first entries in pt_regs, gdb_pt_regs and user_regs_struct + * are common for all three structures. The s390_regs structure + * covers the common parts. It simplifies copying the common part + * between the three structures. + */ typedef struct { - S390_REGS -} __attribute__ ((packed)) s390_regs; + psw_t psw; + __u64 gprs[NUM_GPRS]; + __u32 acrs[NUM_ACRS]; + __u64 orig_gpr2; +} s390_regs; +/* + * The pt_regs struct defines the way the registers are stored on + * the stack during a system call. + */ struct pt_regs { - S390_REGS + psw_t psw; + __u64 gprs[NUM_GPRS]; + __u32 acrs[NUM_ACRS]; + __u64 orig_gpr2; __u32 trap; + __u32 old_ilc; } __attribute__ ((packed)); +/* + * The gdb_pt_regs struct is used instead of the pt_regs structure + * if kernel remote debugging is used. + */ #if CONFIG_REMOTE_DEBUG -typedef struct +struct gdb_pt_regs { - S390_REGS + psw_t psw; + __u64 gprs[NUM_GPRS]; + __u32 acrs[NUM_ACRS]; + __u64 orig_gpr2; __u32 trap; - addr_t crs[16]; + __u32 crs[16]; s390_fp_regs fp_regs; -} __attribute__ ((packed)) gdb_pt_regs; +}; #endif - +/* + * Now for the program event recording (trace) definitions. + */ typedef struct { - addr_t cr[3]; + __u64 cr[3]; } per_cr_words __attribute__((packed)); #define PER_EM_MASK 0x00000000E8000000UL + typedef struct { - unsigned :32; - unsigned em_branching:1; - unsigned em_instruction_fetch:1; - /* Switching on storage alteration automatically fixes - the storage alteration event bit in the users std. */ - unsigned em_storage_alteration:1; - unsigned em_gpr_alt_unused:1; - unsigned em_store_real_address:1; - unsigned :3; - unsigned branch_addr_ctl:1; - unsigned :1; - unsigned storage_alt_space_ctl:1; - unsigned :5; - unsigned :16; - addr_t starting_addr; - addr_t ending_addr; + unsigned : 32; + unsigned em_branching : 1; + unsigned em_instruction_fetch : 1; + /* + * Switching on storage alteration automatically fixes + * the storage alteration event bit in the users std. + */ + unsigned em_storage_alteration : 1; + unsigned em_gpr_alt_unused : 1; + unsigned em_store_real_address : 1; + unsigned : 3; + unsigned branch_addr_ctl : 1; + unsigned : 1; + unsigned storage_alt_space_ctl : 1; + unsigned : 21; + addr_t starting_addr; + addr_t ending_addr; } per_cr_bits __attribute__((packed)); typedef struct { - __u16 perc_atmid; /* 0x096 */ - addr_t address; /* 0x098 */ - __u8 access_id; /* 0x0a1 */ + __u16 perc_atmid; + addr_t address; + __u8 access_id; } per_lowcore_words __attribute__((packed)); typedef struct { - unsigned perc_branching:1; /* 0x096 */ - unsigned perc_instruction_fetch:1; - unsigned perc_storage_alteration:1; - unsigned perc_gpr_alt_unused:1; - unsigned perc_store_real_address:1; - unsigned :3; - unsigned atmid_psw_bit_31:1; - unsigned atmid_validity_bit:1; - unsigned atmid_psw_bit_32:1; - unsigned atmid_psw_bit_5:1; - unsigned atmid_psw_bit_16:1; - unsigned atmid_psw_bit_17:1; - unsigned ai:2; - addr_t address; /* 0x098 */ - unsigned :4; /* 0x0a1 */ - unsigned access_id:4; + unsigned perc_branching : 1; /* 0x096 */ + unsigned perc_instruction_fetch : 1; + unsigned perc_storage_alteration : 1; + unsigned perc_gpr_alt_unused : 1; + unsigned perc_store_real_address : 1; + unsigned : 3; + unsigned atmid_psw_bit_31 : 1; + unsigned atmid_validity_bit : 1; + unsigned atmid_psw_bit_32 : 1; + unsigned atmid_psw_bit_5 : 1; + unsigned atmid_psw_bit_16 : 1; + unsigned atmid_psw_bit_17 : 1; + unsigned si : 2; + addr_t address; /* 0x098 */ + unsigned : 4; /* 0x0a1 */ + unsigned access_id : 4; } per_lowcore_bits __attribute__((packed)); - -typedef enum -{ - primary_asce, - ar_asce, - secondary_asce, - home_space_asce -} per_ai_codes; - - - typedef struct { - union - { + union { per_cr_words words; per_cr_bits bits; } control_regs __attribute__((packed)); - /* Use these flags instead of setting em_instruction_fetch */ - /* directly they are used so that single stepping can be */ - /* switched on & off while not affecting other tracing */ - unsigned single_step:1; - unsigned instruction_fetch:1; - unsigned :30; - /* These addresses are copied into cr10 & cr11 if single stepping - is switched off */ - addr_t starting_addr; - addr_t ending_addr; - union - { + /* + * Use these flags instead of setting em_instruction_fetch + * directly they are used so that single stepping can be + * switched on & off while not affecting other tracing + */ + unsigned single_step : 1; + unsigned instruction_fetch : 1; + unsigned : 30; + /* + * These addresses are copied into cr10 & cr11 if single + * stepping is switched off + */ + addr_t starting_addr; + addr_t ending_addr; + union { per_lowcore_words words; per_lowcore_bits bits; } lowcore; } per_struct __attribute__((packed)); - - -/* this struct defines the way the registers are stored on the - stack during a system call. If you change the pt_regs structure, - you'll need to change user.h too. - - N.B. if you modify the pt_regs struct the strace command also has to be - modified & recompiled ( just wait till we have gdb going ). - -*/ - -struct user_regs_struct -{ - S390_REGS - s390_fp_regs fp_regs; -/* These per registers are in here so that gdb can modify them itself - * as there is no "official" ptrace interface for hardware watchpoints. - * this is the way intel does it - */ - per_struct per_info; - addr_t ieee_instruction_pointer; - /* Used to give failing instruction back to user for ieee exceptions */ -}; - -typedef struct user_regs_struct user_regs_struct; - -typedef struct pt_regs pt_regs; - -#ifdef __KERNEL__ -#define user_mode(regs) (((regs)->psw.mask & PSW_PROBLEM_STATE) != 0) -#define instruction_pointer(regs) ((regs)->psw.addr) -extern void show_regs(struct pt_regs * regs); -extern char *task_show_regs(struct task_struct *task, char *buffer); -#endif - - - - - -#define FIX_PSW(addr) ((unsigned long)(addr)) - -#define MULT_PROCPTR_TYPES ((CONFIG_BINFMT_ELF)&&(CONFIG_BINFMT_TOC)) - -typedef struct -{ - long addr; - long toc; -} routine_descriptor; -extern void fix_routine_descriptor_regs(routine_descriptor *rdes,pt_regs *regs); -extern __inline__ void -fix_routine_descriptor_regs(routine_descriptor *rdes,pt_regs *regs) -{ - regs->psw.addr=FIX_PSW(rdes->addr); - regs->gprs[12]=rdes->toc; -} - -/* - * Compiler optimisation should save this stuff from being non optimal - * & remove uneccessary code ( isnt gcc great DJB. ) - */ - -/*I'm just using this an indicator of what binformat we are using - * (DJB) N.B. this needs to stay a macro unfortunately as I am otherwise - * dereferencing incomplete pointer types in with load_toc_binary - */ -#if MULT_PROCPTR_TYPES -#define uses_routine_descriptors() \ -(current->binfmt->load_binary==load_toc_binary) -#else -#if CONFIG_BINFMT_TOC -#define uses_routine_descriptors() 1 -#else -#define uses_routine_descriptors() 0 -#endif -#endif - -#define pt_off(ptreg) offsetof(user_regs_struct,ptreg) -enum -{ - PT_PSWMASK=pt_off(psw.mask), - PT_PSWADDR=pt_off(psw.addr), - PT_GPR0=pt_off(gprs[0]), - PT_GPR1=pt_off(gprs[1]), - PT_GPR2=pt_off(gprs[2]), - PT_GPR3=pt_off(gprs[3]), - PT_GPR4=pt_off(gprs[4]), - PT_GPR5=pt_off(gprs[5]), - PT_GPR6=pt_off(gprs[6]), - PT_GPR7=pt_off(gprs[7]), - PT_GPR8=pt_off(gprs[8]), - PT_GPR9=pt_off(gprs[9]), - PT_GPR10=pt_off(gprs[10]), - PT_GPR11=pt_off(gprs[11]), - PT_GPR12=pt_off(gprs[12]), - PT_GPR13=pt_off(gprs[13]), - PT_GPR14=pt_off(gprs[14]), - PT_GPR15=pt_off(gprs[15]), - PT_ACR0=pt_off(acrs[0]), - PT_ACR1=pt_off(acrs[1]), - PT_ACR2=pt_off(acrs[2]), - PT_ACR3=pt_off(acrs[3]), - PT_ACR4=pt_off(acrs[4]), - PT_ACR5=pt_off(acrs[5]), - PT_ACR6=pt_off(acrs[6]), - PT_ACR7=pt_off(acrs[7]), - PT_ACR8=pt_off(acrs[8]), - PT_ACR9=pt_off(acrs[9]), - PT_ACR10=pt_off(acrs[10]), - PT_ACR11=pt_off(acrs[11]), - PT_ACR12=pt_off(acrs[12]), - PT_ACR13=pt_off(acrs[13]), - PT_ACR14=pt_off(acrs[14]), - PT_ACR15=pt_off(acrs[15]), - PT_ORIGGPR2=pt_off(orig_gpr2), - PT_FPC=pt_off(fp_regs.fpc), -/* - * A nasty fact of life that the ptrace api - * only supports passing of longs. - */ - PT_FPR0=pt_off(fp_regs.fprs[0].d), - PT_FPR1=pt_off(fp_regs.fprs[1].d), - PT_FPR2=pt_off(fp_regs.fprs[2].d), - PT_FPR3=pt_off(fp_regs.fprs[3].d), - PT_FPR4=pt_off(fp_regs.fprs[4].d), - PT_FPR5=pt_off(fp_regs.fprs[5].d), - PT_FPR6=pt_off(fp_regs.fprs[6].d), - PT_FPR7=pt_off(fp_regs.fprs[7].d), - PT_FPR8=pt_off(fp_regs.fprs[8].d), - PT_FPR9=pt_off(fp_regs.fprs[9].d), - PT_FPR10=pt_off(fp_regs.fprs[10].d), - PT_FPR11=pt_off(fp_regs.fprs[11].d), - PT_FPR12=pt_off(fp_regs.fprs[12].d), - PT_FPR13=pt_off(fp_regs.fprs[13].d), - PT_FPR14=pt_off(fp_regs.fprs[14].d), - PT_FPR15=pt_off(fp_regs.fprs[15].d), - PT_CR_9=pt_off(per_info.control_regs.words.cr[0]), - PT_CR_10=pt_off(per_info.control_regs.words.cr[1]), - PT_CR_11=pt_off(per_info.control_regs.words.cr[2]), - PT_IEEE_IP=pt_off(ieee_instruction_pointer), - PT_LASTOFF=PT_IEEE_IP, - PT_ENDREGS=sizeof(user_regs_struct)-1 -}; - -#define PTRACE_AREA \ -__u32 len; \ -addr_t kernel_addr; \ -addr_t process_addr; - typedef struct { - PTRACE_AREA + __u32 len; + addr_t kernel_addr; + addr_t process_addr; } ptrace_area; /* - 390 specific non posix ptrace requests - I chose unusual values so they are unlikely to clash with future ptrace definitions. + * S/390 specific non posix ptrace requests. I chose unusual values so + * they are unlikely to clash with future ptrace definitions. */ #define PTRACE_PEEKUSR_AREA 0x5000 #define PTRACE_POKEUSR_AREA 0x5001 @@ -293,7 +275,10 @@ #define PTRACE_PEEKDATA_AREA 0x5003 #define PTRACE_POKETEXT_AREA 0x5004 #define PTRACE_POKEDATA_AREA 0x5005 -/* PT_PROT definition is loosely based on hppa bsd definition in gdb/hppab-nat.c */ +/* + * PT_PROT definition is loosely based on hppa bsd definition in + * gdb/hppab-nat.c + */ #define PTRACE_PROT 21 typedef enum @@ -309,18 +294,41 @@ addr_t hiaddr; ptprot_flags prot; } ptprot_area; -#endif - - - - - - - - - +/* Sequence of bytes for breakpoint illegal instruction. */ +#define S390_BREAKPOINT {0x0,0x1} +#define S390_BREAKPOINT_U16 ((__u16)0x0001) +#define S390_SYSCALL_OPCODE ((__u16)0x0a00) +#define S390_SYSCALL_SIZE 2 +/* + * The user_regs_struct defines the way the user registers are + * store on the stack for signal handling. + */ +struct user_regs_struct +{ + psw_t psw; + __u64 gprs[NUM_GPRS]; + __u32 acrs[NUM_ACRS]; + __u64 orig_gpr2; + s390_fp_regs fp_regs; + /* + * These per registers are in here so that gdb can modify them + * itself as there is no "official" ptrace interface for hardware + * watchpoints. This is the way intel does it. + */ + per_struct per_info; + addr_t ieee_instruction_pointer; + /* Used to give failing instruction back to user for ieee exceptions */ +}; +#ifdef __KERNEL__ +#define user_mode(regs) (((regs)->psw.mask & PSW_PROBLEM_STATE) != 0) +#define instruction_pointer(regs) ((regs)->psw.addr) +extern void show_regs(struct pt_regs * regs); +extern char *task_show_regs(struct task_struct *task, char *buffer); +#endif +#endif /* __ASSEMBLY__ */ +#endif /* _S390X_PTRACE_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/queue.h linux.ac/include/asm-s390x/queue.h --- linux.vanilla/include/asm-s390x/queue.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/queue.h Thu Apr 12 12:06:16 2001 @@ -7,8 +7,8 @@ * * A little set of queue utilies. */ + #include <linux/stddef.h> -#include <asm/types.h> typedef struct queue { @@ -105,8 +105,8 @@ for(curr=lhead;curr!=NULL;curr=curr->next) if(curr==member) - return(TRUE); - return(FALSE); + return(1); + return(0); } static __inline__ int get_prev(list *lhead,list *member,list **prev) @@ -117,11 +117,11 @@ for(curr=lhead;curr!=NULL;curr=curr->next) { if(curr==member) - return(TRUE); + return(1); *prev=curr; } *prev=NULL; - return(FALSE); + return(0); } @@ -137,9 +137,9 @@ prev->next=member->next; else *lhead=member->next; - return(TRUE); + return(1); } - return(FALSE); + return(0); } static __inline__ int remove_from_queue(qheader *qhead,queue *member) @@ -161,9 +161,9 @@ qhead->tail=NULL; qhead->head=member->next; } - return(TRUE); + return(1); } - return(FALSE); + return(0); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/s390dyn.h linux.ac/include/asm-s390x/s390dyn.h --- linux.vanilla/include/asm-s390x/s390dyn.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/s390dyn.h Thu Apr 12 12:06:16 2001 @@ -10,6 +10,10 @@ #ifndef __s390dyn_h #define __s390dyn_h +#ifndef _LINUX_LIST_H +#include <linux/list.h> +#endif + struct _devreg; typedef int (* oper_handler_func_t)( int irq, @@ -23,6 +27,7 @@ } __attribute__ ((packed)) devreg_hc_t; typedef struct _devreg { + struct list_head list; union { int devno; devreg_hc_t hc; /* has controller info */ @@ -30,8 +35,6 @@ int flag; oper_handler_func_t oper_func; - struct _devreg *prev; - struct _devreg *next; } devreg_t; #define DEVREG_EXACT_MATCH 0x00000001 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/s390io.h linux.ac/include/asm-s390x/s390io.h --- linux.vanilla/include/asm-s390x/s390io.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/s390io.h Thu Apr 12 12:06:16 2001 @@ -75,7 +75,6 @@ unsigned long qintparm; /* queued interruption parameter */ unsigned long qflag; /* queued flags */ __u8 qlpm; /* queued logical path mask */ - __u32 syncnt; /* sync I/O recursive usage count */ } __attribute__ ((aligned(8))) ioinfo_t; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/semaphore-helper.h linux.ac/include/asm-s390x/semaphore-helper.h --- linux.vanilla/include/asm-s390x/semaphore-helper.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/semaphore-helper.h Thu Jan 1 01:00:00 1970 @@ -1,100 +0,0 @@ -/* - * include/asm-s390/semaphore-helper.h - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * - * Derived from "include/asm-i386/semaphore-helper.h" - * (C) Copyright 1996 Linus Torvalds - * (C) Copyright 1999 Andrea Arcangeli - */ - -#ifndef _S390_SEMAPHORE_HELPER_H -#define _S390_SEMAPHORE_HELPER_H - -/* - * These two _must_ execute atomically wrt each other. - * - * This is trivially done with load_locked/store_cond, - * but on the x86 we need an external synchronizer. - */ -static inline void wake_one_more(struct semaphore * sem) -{ - unsigned long flags; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - sem->waking++; - spin_unlock_irqrestore(&semaphore_wake_lock, flags); -} - -static inline int waking_non_zero(struct semaphore *sem) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking > 0) { - sem->waking--; - ret = 1; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_interruptible: - * 1 got the lock - * 0 go to sleep - * -EINTR interrupted - * - * If we give up we must undo our count-decrease we previously did in down(). - * Subtle: up() can continue to happens and increase the semaphore count - * even during our critical section protected by the spinlock. So - * we must remeber to undo the sem->waking that will be run from - * wake_one_more() some time soon, if the semaphore count become > 0. - */ -static inline int waking_non_zero_interruptible(struct semaphore *sem, - struct task_struct *tsk) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking > 0) { - sem->waking--; - ret = 1; - } else if (signal_pending(tsk)) { - if (atomic_inc_and_test_greater_zero(&sem->count)) - sem->waking--; - ret = -EINTR; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_trylock: - * 1 failed to lock - * 0 got the lock - * - * Implementation details are the same of the interruptible case. - */ -static inline int waking_non_zero_trylock(struct semaphore *sem) -{ - unsigned long flags; - int ret = 1; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking <= 0) - { - if (atomic_inc_and_test_greater_zero(&sem->count)) - sem->waking--; - } else { - sem->waking--; - ret = 0; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/setup.h linux.ac/include/asm-s390x/setup.h --- linux.vanilla/include/asm-s390x/setup.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/setup.h Thu Apr 12 12:06:16 2001 @@ -8,45 +8,34 @@ #ifndef _ASM_S390_SETUP_H #define _ASM_S390_SETUP_H -#define PARMAREA 0x10400 +#define PARMAREA 0x10400 +#define COMMAND_LINE_SIZE 896 +#define RAMDISK_ORIGIN 0x800000 +#define RAMDISK_SIZE 0x800000 #ifndef __ASSEMBLER__ -#define ORIG_ROOT_DEV (*(unsigned long *) (0x10400)) -#define MOUNT_ROOT_RDONLY (*(unsigned short *) (0x10408)) -#define MEMORY_SIZE (*(unsigned long *) (0x1040a)) -#define MACHINE_FLAGS (*(unsigned long *) (0x10412)) -#define INITRD_START (*(unsigned long *) (0x1041a)) -#define INITRD_SIZE (*(unsigned long *) (0x10422)) -#define RAMDISK_FLAGS (*(unsigned short *) (0x1042a)) +#define IPL_DEVICE (*(unsigned long *) (0x10400)) +#define INITRD_START (*(unsigned long *) (0x10408)) +#define INITRD_SIZE (*(unsigned long *) (0x10410)) #define COMMAND_LINE ((char *) (0x10480)) -#else - -#define ORIG_ROOT_DEV 0x10400 -#define MOUNT_ROOT_RDONLY 0x10408 -#define MEMORY_SIZE 0x1040a -#define MACHINE_FLAGS 0x10412 -#define INITRD_START 0x1041a -#define INITRD_SIZE 0x10422 -#define RAMDISK_FLAGS 0x1042a -#define COMMAND_LINE 0x10480 - -#endif - -#define COMMAND_LINE_SIZE 896 /* * Machine features detected in head.S */ -#define MACHINE_IS_VM (MACHINE_FLAGS & 1) -#define MACHINE_IS_P390 (MACHINE_FLAGS & 4) +extern unsigned long machine_flags; -#define RAMDISK_ORIGIN 0x800000 -#define RAMDISK_SIZE 0x800000 -#define RAMDISK_BLKSIZE 0x1000 -#define RAMDISK_IMAGE_START_MASK 0x07FF -#define RAMDISK_PROMPT_FLAG 0x8000 -#define RAMDISK_LOAD_FLAG 0x4000 +#define MACHINE_IS_VM (machine_flags & 1) +#define MACHINE_IS_P390 (machine_flags & 4) +#define MACHINE_HAS_MVPG (machine_flags & 16) +#else + +#define IPL_DEVICE 0x10400 +#define INITRD_START 0x10408 +#define INITRD_SIZE 0x10410 +#define COMMAND_LINE 0x10480 + +#endif #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/signal.h linux.ac/include/asm-s390x/signal.h --- linux.vanilla/include/asm-s390x/signal.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/signal.h Thu Apr 12 12:06:16 2001 @@ -71,6 +71,7 @@ #define SIGLOST 29 */ #define SIGPWR 30 +#define SIGSYS 31 #define SIGUNUSED 31 /* These should not be considered constants from userland. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/sigp.h linux.ac/include/asm-s390x/sigp.h --- linux.vanilla/include/asm-s390x/sigp.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/sigp.h Thu Apr 12 12:06:16 2001 @@ -15,7 +15,6 @@ #define __SIGP__ #include <asm/ptrace.h> -#include <asm/misc390.h> #include <asm/atomic.h> /* get real cpu address from logical cpu number */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/smp.h linux.ac/include/asm-s390x/smp.h --- linux.vanilla/include/asm-s390x/smp.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/smp.h Thu Apr 12 12:06:16 2001 @@ -8,14 +8,24 @@ */ #ifndef __ASM_SMP_H #define __ASM_SMP_H + #include <linux/config.h> -#ifdef CONFIG_SMP -#ifndef __ASSEMBLY__ + +#if defined(__KERNEL__) && defined(CONFIG_SMP) && !defined(__ASSEMBLY__) #include <asm/lowcore.h> -#include <linux/kernel.h> // FOR FASTCALL definition -#define smp_processor_id() (current->processor) +/* + s390 specific smp.c headers + */ +typedef struct +{ + int intresting; + sigp_ccode ccode; + __u32 status; + __u16 cpu; +} sigp_info; + #define NO_PROC_ID 0xFF /* No processor magic marker */ /* @@ -30,7 +40,7 @@ #define PROC_CHANGE_PENALTY 20 /* Schedule penalty */ -extern void count_cpus(void); +#define smp_processor_id() (current->processor) extern __inline__ int cpu_logical_map(int cpu) { @@ -54,25 +64,12 @@ void smp_local_timer_interrupt(struct pt_regs * regs); -/* - s390 specific smp.c headers - */ -typedef struct -{ - int intresting; - sigp_ccode ccode; - __u32 status; - __u16 cpu; -} sigp_info; - -sigp_ccode -smp_ext_call(int cpu, void (*callback)(void *info), void *info, int wait); -void smp_ext_call_others(void (*callback)(void *info), void *info, int wait); +sigp_ccode smp_ext_call(int cpu, void (*cb)(void *info), void *info, int wait); +void smp_ext_call_others(void (*cb)(void *info), void *info, int wait); sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig); void smp_ext_bitcall_others(ec_bit_sig sig); int smp_signal_others(sigp_order_code order_code,__u32 parameter, int spin,sigp_info *info); -#endif #endif #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/spinlock.h linux.ac/include/asm-s390x/spinlock.h --- linux.vanilla/include/asm-s390x/spinlock.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/spinlock.h Thu Apr 12 12:06:16 2001 @@ -73,6 +73,8 @@ #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } +#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) + #define read_lock(rw) \ asm volatile(" la 1,%0\n" \ " lg 2,0(1)\n" \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/system.h linux.ac/include/asm-s390x/system.h --- linux.vanilla/include/asm-s390x/system.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/system.h Thu Apr 12 12:06:16 2001 @@ -33,6 +33,9 @@ #define xchg(ptr,x) \ ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(void *)(ptr),sizeof(*(ptr)))) +extern void __misaligned_u16(void); +extern void __misaligned_u32(void); +extern void __misaligned_u64(void); static inline unsigned long __xchg(unsigned long x, void * ptr, int size) { @@ -43,14 +46,14 @@ " nr 1,%0\n" /* isolate last 2 bits */ " xr %0,1\n" /* align ptr */ " bras 2,0f\n" - " icm 1,8,%1\n" /* for ptr&3 == 0 */ - " stcm 0,8,%1\n" - " icm 1,4,%1\n" /* for ptr&3 == 1 */ - " stcm 0,4,%1\n" - " icm 1,2,%1\n" /* for ptr&3 == 2 */ - " stcm 0,2,%1\n" - " icm 1,1,%1\n" /* for ptr&3 == 3 */ - " stcm 0,1,%1\n" + " icm 1,8,7(%1)\n" /* for ptr&3 == 0 */ + " stcm 0,8,7(%1)\n" + " icm 1,4,7(%1)\n" /* for ptr&3 == 1 */ + " stcm 0,4,7(%1)\n" + " icm 1,2,7(%1)\n" /* for ptr&3 == 2 */ + " stcm 0,2,7(%1)\n" + " icm 1,1,7(%1)\n" /* for ptr&3 == 3 */ + " stcm 0,1,7(%1)\n" "0: sll 1,3\n" " la 2,0(1,2)\n" /* r2 points to an icm */ " l 0,0(%0)\n" /* get fullword */ @@ -59,20 +62,21 @@ " cs 0,1,0(%0)\n" " jl 1b\n" " ex 0,4(2)" /* store *ptr to x */ - : "+&a" (ptr), "+m" (x) : + : "+&a" (ptr) : "a" (&x) : "memory", "0", "1", "2"); + break; case 2: if(((addr_t)ptr)&1) - panic("misaligned (__u16 *) in __xchg\n"); + __misaligned_u16(); asm volatile ( " lghi 1,2\n" " nr 1,%0\n" /* isolate bit 2^1 */ " xr %0,1\n" /* align ptr */ " bras 2,0f\n" - " icm 1,12,%1\n" /* for ptr&2 == 0 */ - " stcm 0,12,%1\n" - " icm 1,3,%1\n" /* for ptr&2 == 1 */ - " stcm 0,3,%1\n" + " icm 1,12,6(%1)\n" /* for ptr&2 == 0 */ + " stcm 0,12,6(%1)\n" + " icm 1,3,2(%1)\n" /* for ptr&2 == 1 */ + " stcm 0,3,2(%1)\n" "0: sll 1,2\n" " la 2,0(1,2)\n" /* r2 points to an icm */ " l 0,0(%0)\n" /* get fullword */ @@ -81,12 +85,12 @@ " cs 0,1,0(%0)\n" " jl 1b\n" " ex 0,4(2)" /* store *ptr to x */ - : "+&a" (ptr), "+m" (x) : + : "+&a" (ptr) : "a" (&x) : "memory", "0", "1", "2"); break; case 4: if(((addr_t)ptr)&3) - panic("misaligned (__u32 *) in __xchg\n"); + __misaligned_u32(); asm volatile ( " l 0,0(%1)\n" "0: cs 0,%0,0(%1)\n" @@ -97,7 +101,7 @@ break; case 8: if(((addr_t)ptr)&7) - panic("misaligned (__u64 *) in __xchg\n"); + __misaligned_u64(); asm volatile ( " lg 0,0(%1)\n" "0: csg 0,%0,0(%1)\n" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/termios.h linux.ac/include/asm-s390x/termios.h --- linux.vanilla/include/asm-s390x/termios.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/termios.h Thu Apr 12 12:06:16 2001 @@ -60,7 +60,7 @@ #define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave@mvhi.com> */ -#define N_IRDA 11 /* Linux IR - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_IRDA 11 /* Linux IR - http://irda.sourceforge.net/ */ #define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #define N_HDLC 13 /* synchronous HDLC */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/tlb.h linux.ac/include/asm-s390x/tlb.h --- linux.vanilla/include/asm-s390x/tlb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-s390x/tlb.h Tue Apr 3 17:55:16 2001 @@ -0,0 +1 @@ +#include <asm-generic/tlb.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/todclk.h linux.ac/include/asm-s390x/todclk.h --- linux.vanilla/include/asm-s390x/todclk.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/todclk.h Thu Apr 12 12:06:16 2001 @@ -10,10 +10,14 @@ #ifndef __ASM_TODCLK_H #define __ASM_TODCLK_H +#ifdef __KERNEL__ + #define TOD_uSEC (0x1000ULL) #define TOD_mSEC (1000 * TOD_uSEC) #define TOD_SEC (1000 * TOD_mSEC) #define TOD_MIN (60 * TOD_SEC) #define TOD_HOUR (60 * TOD_MIN) + +#endif #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/types.h linux.ac/include/asm-s390x/types.h --- linux.vanilla/include/asm-s390x/types.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/types.h Thu Apr 12 12:06:16 2001 @@ -41,14 +41,6 @@ */ #ifdef __KERNEL__ -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - typedef signed char s8; typedef unsigned char u8; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/uaccess.h linux.ac/include/asm-s390x/uaccess.h --- linux.vanilla/include/asm-s390x/uaccess.h Tue Feb 13 22:13:44 2001 +++ linux.ac/include/asm-s390x/uaccess.h Thu Apr 12 12:06:16 2001 @@ -432,21 +432,20 @@ " sacf 512\n" "0: ic 3,0(%0,4)\n" "1: stc 3,0(%0,2)\n" + " ltr 3,3\n" + " jz 2f\n" " aghi %0,1\n" " cgr %0,%3\n" - " je 2f\n" - " ltr 3,3\n" - " jne 0b\n" + " jl 0b\n" "2: sacf 0\n" - "3:\n" ".section .fixup,\"ax\"\n" - "4: lghi %0,%h4\n" - " jg 3b\n" + "3: lghi %0,%h4\n" + " jg 2b\n" ".previous\n" ".section __ex_table,\"a\"\n" " .align 8\n" - " .quad 0b,4b\n" - " .quad 1b,4b\n" + " .quad 0b,3b\n" + " .quad 1b,3b\n" ".previous" : "=&a" (len) : "a" (dst), "d" (src), "d" (count), diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390x/vtoc.h linux.ac/include/asm-s390x/vtoc.h --- linux.vanilla/include/asm-s390x/vtoc.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-s390x/vtoc.h Thu Apr 12 12:06:16 2001 @@ -0,0 +1,234 @@ +#ifndef __KERNEL__ +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <ctype.h> +#include <time.h> +#include <fcntl.h> +#include <unistd.h> + +#include <sys/stat.h> +#include <sys/ioctl.h> + +#include <linux/fs.h> +#include <linux/types.h> +#include <linux/hdreg.h> +#include <linux/version.h> +#endif +#include <asm/dasd.h> + +#define LINE_LENGTH 80 +#define VTOC_START_CC 0x0 +#define VTOC_START_HH 0x1 + +enum failure {unable_to_open, + unable_to_seek, + unable_to_write, + unable_to_read}; + +typedef struct ttr { + __u16 tt; + __u8 r; +} __attribute__ ((packed)) ttr_t; + +typedef struct cchhb { + __u16 cc; + __u16 hh; + __u8 b; +} __attribute__ ((packed)) cchhb_t; + +typedef struct cchh { + __u16 cc; + __u16 hh; +} __attribute__ ((packed)) cchh_t; + +typedef struct labeldate { + __u8 year; + __u16 day; +} __attribute__ ((packed)) labeldate_t; + + +typedef struct volume_label { + char volkey[4]; /* volume key = volume label */ + char vollbl[4]; /* volume label */ + char volid[6]; /* volume identifier */ + __u8 security; /* security byte */ + cchhb_t vtoc; /* VTOC address */ + char res1[5]; /* reserved */ + char cisize[4]; /* CI-size for FBA,... */ + /* ...blanks for CKD */ + char blkperci[4]; /* no of blocks per CI (FBA), blanks for CKD */ + char labperci[4]; /* no of labels per CI (FBA), blanks for CKD */ + char res2[4]; /* reserved */ + char lvtoc[14]; /* owner code for LVTOC */ + char res3[29]; /* reserved */ +} __attribute__ ((packed)) volume_label_t; + + +typedef struct extent { + __u8 typeind; /* extent type indicator */ + __u8 seqno; /* extent sequence number */ + cchh_t llimit; /* starting point of this extent */ + cchh_t ulimit; /* ending point of this extent */ +} __attribute__ ((packed)) extent_t; + + +typedef struct dev_const { + __u16 DS4DSCYL; /* number of logical cyls */ + __u16 DS4DSTRK; /* number of tracks in a logical cylinder */ + __u16 DS4DEVTK; /* device track length */ + __u8 DS4DEVI; /* non-last keyed record overhead */ + __u8 DS4DEVL; /* last keyed record overhead */ + __u8 DS4DEVK; /* non-keyed record overhead differential */ + __u8 DS4DEVFG; /* flag byte */ + __u16 DS4DEVTL; /* device tolerance */ + __u8 DS4DEVDT; /* number of DSCB's per track */ + __u8 DS4DEVDB; /* number of directory blocks per track */ +} __attribute__ ((packed)) dev_const_t; + + +typedef struct format1_label { + char DS1DSNAM[44]; /* data set name */ + __u8 DS1FMTID; /* format identifier */ + char DS1DSSN[6]; /* data set serial number */ + __u16 DS1VOLSQ; /* volume sequence number */ + labeldate_t DS1CREDT; /* creation date: ydd */ + labeldate_t DS1EXPDT; /* expiration date */ + __u8 DS1NOEPV; /* number of extents on volume */ + __u8 DS1NOBDB; /* no. of bytes used in last direction blk */ + __u8 DS1FLAG1; /* flag 1 */ + char DS1SYSCD[13]; /* system code */ + labeldate_t DS1REFD; /* date last referenced */ + __u8 DS1SMSFG; /* system managed storage indicators */ + __u8 DS1SCXTF; /* sec. space extension flag byte */ + __u16 DS1SCXTV; /* secondary space extension value */ + __u8 DS1DSRG1; /* data set organisation byte 1 */ + __u8 DS1DSRG2; /* data set organisation byte 2 */ + __u8 DS1RECFM; /* record format */ + __u8 DS1OPTCD; /* option code */ + __u16 DS1BLKL; /* block length */ + __u16 DS1LRECL; /* record length */ + __u8 DS1KEYL; /* key length */ + __u16 DS1RKP; /* relative key position */ + __u8 DS1DSIND; /* data set indicators */ + __u8 DS1SCAL1; /* secondary allocation flag byte */ + char DS1SCAL3[3]; /* secondary allocation quantity */ + ttr_t DS1LSTAR; /* last used track and block on track */ + __u16 DS1TRBAL; /* space remaining on last used track */ + __u16 res1; /* reserved */ + extent_t DS1EXT1; /* first extent description */ + extent_t DS1EXT2; /* second extent description */ + extent_t DS1EXT3; /* third extent description */ + cchhb_t DS1PTRDS; /* possible pointer to f2 or f3 DSCB */ +} __attribute__ ((packed)) format1_label_t; + + +typedef struct format4_label { + char DS4KEYCD[44]; /* key code for VTOC labels: 44 times 0x04 */ + __u8 DS4IDFMT; /* format identifier */ + cchhb_t DS4HPCHR; /* highest address of a format 1 DSCB */ + __u16 DS4DSREC; /* number of available DSCB's */ + cchh_t DS4HCCHH; /* CCHH of next available alternate track */ + __u16 DS4NOATK; /* number of remaining alternate tracks */ + __u8 DS4VTOCI; /* VTOC indicators */ + __u8 DS4NOEXT; /* number of extents in VTOC */ + __u8 DS4SMSFG; /* system managed storage indicators */ + __u8 DS4DEVAC; /* number of alternate cylinders. + Subtract from first two bytes of + DS4DEVSZ to get number of usable + cylinders. can be zero. valid + only if DS4DEVAV on. */ + dev_const_t DS4DEVCT; /* device constants */ + char DS4AMTIM[8]; /* VSAM time stamp */ + char DS4AMCAT[3]; /* VSAM catalog indicator */ + char DS4R2TIM[8]; /* VSAM volume/catalog match time stamp */ + char res1[5]; /* reserved */ + char DS4F6PTR[5]; /* pointer to first format 6 DSCB */ + extent_t DS4VTOCE; /* VTOC extent description */ + char res2[10]; /* reserved */ + __u8 DS4EFLVL; /* extended free-space management level */ + cchhb_t DS4EFPTR; /* pointer to extended free-space info */ + char res3[9]; /* reserved */ +} __attribute__ ((packed)) format4_label_t; + + +char * vtoc_ebcdic_enc ( + unsigned char source[LINE_LENGTH], + unsigned char target[LINE_LENGTH], + int l); +char * vtoc_ebcdic_dec ( + unsigned char source[LINE_LENGTH], + unsigned char target[LINE_LENGTH], + int l); +void vtoc_set_extent ( + extent_t * ext, + __u8 typeind, + __u8 seqno, + cchh_t * lower, + cchh_t * upper); +void vtoc_set_cchh ( + cchh_t * addr, + __u16 cc, + __u16 hh); +void vtoc_set_cchhb ( + cchhb_t * addr, + __u16 cc, + __u16 hh, + __u8 b); +void vtoc_set_date ( + labeldate_t * d, + __u8 year, + __u16 day); + + +int vtoc_read_volume_label ( + char * device, + unsigned long vlabel_start, + volume_label_t * vlabel); +int vtoc_write_volume_label ( + char * device, + unsigned long vlabel_start, + volume_label_t * vlabel); +void vtoc_read_label ( + char *device, + unsigned long position, + format4_label_t *f4, + format1_label_t *f1); +void vtoc_write_label ( + char *device, + unsigned long position, + format4_label_t *f4, + format1_label_t *f1); +void vtoc_init_format4_label ( + struct hd_geometry *geo, + format4_label_t *f4lbl, + unsigned int usable_partitions, + unsigned int cylinders, + unsigned int tracks, + unsigned int blocks); +void vtoc_init_format1_label ( + char *volid, + unsigned int blksize, + extent_t *part_extent, + format1_label_t *f1); +void vtoc_update_format4_label ( + format4_label_t *f4, + cchhb_t *highest_f1, + __u8 unused_update, + __u16 freespace_update); + + + + + + + + + + + + + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/bugs.h linux.ac/include/asm-sh/bugs.h --- linux.vanilla/include/asm-sh/bugs.h Thu Jan 4 21:19:13 2001 +++ linux.ac/include/asm-sh/bugs.h Sat Apr 14 01:39:22 2001 @@ -34,6 +34,10 @@ *p++ = '4'; printk("CPU: SH7750\n"); break; + case CPU_ST40STB1: + *p++ = '4'; + printk("CPU: ST40STB1\n"); + break; default: printk("CPU: ??????\n"); break; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/ec3104.h linux.ac/include/asm-sh/ec3104.h --- linux.vanilla/include/asm-sh/ec3104.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-sh/ec3104.h Sat Apr 14 01:39:30 2001 @@ -0,0 +1,43 @@ +#ifndef __ASM_EC3104_H +#define __ASM_EC3104_H + + +/* + * Most of the register set is at 0xb0ec0000 - 0xb0ecffff. + * + * as far as I've figured it out the register map is: + * 0xb0ec0000 - id string + * 0xb0ec0XXX - power management + * 0xb0ec1XXX - interrupt control + * 0xb0ec3XXX - ps2 port (touch pad on aero 8000) + * 0xb0ec6XXX - i2c + * 0xb0ec7000 - first serial port (proprietary connector on aero 8000) + * 0xb0ec8000 - second serial port + * 0xb0ec9000 - third serial port + * 0xb0eca000 - fourth serial port (keyboard controller on aero 8000) + * 0xb0eccXXX - GPIO + * 0xb0ecdXXX - GPIO + */ + +#define EC3104_BASE 0xb0ec0000 + +#define EC3104_SER4_DATA (EC3104_BASE+0xa000) +#define EC3104_SER4_IIR (EC3104_BASE+0xa008) +#define EC3104_SER4_MCR (EC3104_BASE+0xa010) +#define EC3104_SER4_LSR (EC3104_BASE+0xa014) +#define EC3104_SER4_MSR (EC3104_BASE+0xa018) + +/* + * our ISA bus. this seems to be real ISA. + */ +#define EC3104_ISA_BASE 0xa5000000 + +#define EC3104_IRQ 11 +#define EC3104_IRQBASE 64 + +#define EC3104_IRQ_SER1 EC3104_IRQBASE + 7 +#define EC3104_IRQ_SER2 EC3104_IRQBASE + 8 +#define EC3104_IRQ_SER3 EC3104_IRQBASE + 9 +#define EC3104_IRQ_SER4 EC3104_IRQBASE + 10 + +#endif /* __ASM_EC3104_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/hd64461.h linux.ac/include/asm-sh/hd64461.h --- linux.vanilla/include/asm-sh/hd64461.h Wed Aug 9 21:59:04 2000 +++ linux.ac/include/asm-sh/hd64461.h Sat Apr 14 01:39:30 2001 @@ -11,10 +11,22 @@ #define HD64461_SYSCR 0x10002 #define HD64461_SCPUCR 0x10004 -#define HD64461_CPTWAR 0x11030 -#define HD64461_CPTWDR 0x11032 -#define HD64461_CPTRAR 0x11034 -#define HD64461_CPTRDR 0x11036 +#define HD64461_LCDCBAR 0x11000 +#define HD64461_LCDCLOR 0x11002 +#define HD64461_LCDCCRR 0x11004 +#define HD64461_LDR1 0x11010 +#define HD64461_LDR2 0x11012 +#define HD64461_LDHNCR 0x11014 +#define HD64461_LDHNSR 0x11016 +#define HD64461_LDVNTR 0x11018 +#define HD64461_LDVNDR 0x1101a +#define HD64461_LDVSPR 0x1101c +#define HD64461_LDR3 0x1101e + +#define HD64461_CPTWAR 0x11030 +#define HD64461_CPTWDR 0x11032 +#define HD64461_CPTRAR 0x11034 +#define HD64461_CPTRDR 0x11036 #define HD64461_PCC0ISR 0x12000 #define HD64461_PCC0GCR 0x12002 @@ -30,6 +42,23 @@ #define HD64461_P1OCR 0x1202c #define HD64461_PGCR 0x1202e +#define HD64461_GPACR 0x14000 +#define HD64461_GPBCR 0x14002 +#define HD64461_GPCCR 0x14004 +#define HD64461_GPDCR 0x14006 +#define HD64461_GPADR 0x14010 +#define HD64461_GPBDR 0x14012 +#define HD64461_GPCDR 0x14014 +#define HD64461_GPDDR 0x14016 +#define HD64461_GPAICR 0x14020 +#define HD64461_GPBICR 0x14022 +#define HD64461_GPCICR 0x14024 +#define HD64461_GPDICR 0x14026 +#define HD64461_GPAISR 0x14040 +#define HD64461_GPBISR 0x14042 +#define HD64461_GPCISR 0x14044 +#define HD64461_GPDISR 0x14046 + #define HD64461_NIRR 0x15000 #define HD64461_NIMR 0x15002 @@ -40,6 +69,6 @@ #define CONFIG_HD64461_IRQ 36 #endif -#define HD64461_IRQBASE 64 +#define HD64461_IRQBASE OFFCHIP_IRQ_BASE #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/hd64465.h linux.ac/include/asm-sh/hd64465.h --- linux.vanilla/include/asm-sh/hd64465.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-sh/hd64465.h Sat Apr 14 01:39:30 2001 @@ -0,0 +1,257 @@ +#ifndef _ASM_SH_HD64465_ +#define _ASM_SH_HD64465_ 1 +/* + * $Id: hd64465.h,v 1.3 2001/02/07 18:31:20 stuart_menefy Exp $ + * + * Hitachi HD64465 companion chip support + * + * by Greg Banks <gbanks@pocketpenguins.com> + * (c) 2000 PocketPenguins Inc. + * + * Derived from <asm/hd64461.h> which bore the message: + * Copyright (C) 2000 YAEGASHI Takeshi + */ +#include <linux/config.h> +#include <asm/io.h> +#include <asm/irq.h> + +/* + * Note that registers are defined here as virtual port numbers, + * which have no meaning except to get translated by hd64465_isa_port2addr() + * to an address in the range 0xb0000000-0xb3ffffff. Note that + * this translation happens to consist of adding the lower 16 bits + * of the virtual port number to 0xb0000000. Note also that the manual + * shows addresses as absolute physical addresses starting at 0x10000000, + * so e.g. the NIRR register is listed as 0x15000 here, 0x10005000 in the + * manual, and accessed using address 0xb0005000 - Greg. + */ + +/* System registers */ +#define HD64465_REG_SRR 0x1000c /* System Revision Register */ +#define HD64465_REG_SDID 0x10010 /* System Device ID Reg */ +#define HD64465_SDID 0x8122 /* 64465 device ID */ + +/* Power Management registers */ +#define HD64465_REG_SMSCR 0x10000 /* System Module Standby Control Reg */ +#define HD64465_SMSCR_PS2ST 0x4000 /* PS/2 Standby */ +#define HD64465_SMSCR_ADCST 0x1000 /* ADC Standby */ +#define HD64465_SMSCR_UARTST 0x0800 /* UART Standby */ +#define HD64465_SMSCR_SCDIST 0x0200 /* Serial Codec Standby */ +#define HD64465_SMSCR_PPST 0x0100 /* Parallel Port Standby */ +#define HD64465_SMSCR_PC0ST 0x0040 /* PCMCIA0 Standby */ +#define HD64465_SMSCR_PC1ST 0x0020 /* PCMCIA1 Standby */ +#define HD64465_SMSCR_AFEST 0x0010 /* AFE Standby */ +#define HD64465_SMSCR_TM0ST 0x0008 /* Timer0 Standby */ +#define HD64465_SMSCR_TM1ST 0x0004 /* Timer1 Standby */ +#define HD64465_SMSCR_IRDAST 0x0002 /* IRDA Standby */ +#define HD64465_SMSCR_KBCST 0x0001 /* Keyboard Controller Standby */ + +/* Interrupt Controller registers */ +#define HD64465_REG_NIRR 0x15000 /* Interrupt Request Register */ +#define HD64465_REG_NIMR 0x15002 /* Interrupt Mask Register */ +#define HD64465_REG_NITR 0x15004 /* Interrupt Trigger Mode Register */ + +/* Timer registers */ +#define HD64465_REG_TCVR1 0x16000 /* Timer 1 constant value register */ +#define HD64465_REG_TCVR0 0x16002 /* Timer 0 constant value register */ +#define HD64465_REG_TRVR1 0x16004 /* Timer 1 read value register */ +#define HD64465_REG_TRVR0 0x16006 /* Timer 0 read value register */ +#define HD64465_REG_TCR1 0x16008 /* Timer 1 control register */ +#define HD64465_REG_TCR0 0x1600A /* Timer 0 control register */ +#define HD64465_TCR_EADT 0x10 /* Enable ADTRIG# signal */ +#define HD64465_TCR_ETMO 0x08 /* Enable TMO signal */ +#define HD64465_TCR_PST_MASK 0x06 /* Clock Prescale */ +#define HD64465_TCR_PST_1 0x06 /* 1:1 */ +#define HD64465_TCR_PST_4 0x04 /* 1:4 */ +#define HD64465_TCR_PST_8 0x02 /* 1:8 */ +#define HD64465_TCR_PST_16 0x00 /* 1:16 */ +#define HD64465_TCR_TSTP 0x01 /* Start/Stop timer */ +#define HD64465_REG_TIRR 0x1600C /* Timer interrupt request register */ +#define HD64465_REG_TIDR 0x1600E /* Timer interrupt disable register */ +#define HD64465_REG_PWM1CS 0x16010 /* PWM 1 clock scale register */ +#define HD64465_REG_PWM1LPC 0x16012 /* PWM 1 low pulse width counter register */ +#define HD64465_REG_PWM1HPC 0x16014 /* PWM 1 high pulse width counter register */ +#define HD64465_REG_PWM0CS 0x16018 /* PWM 0 clock scale register */ +#define HD64465_REG_PWM0LPC 0x1601A /* PWM 0 low pulse width counter register */ +#define HD64465_REG_PWM0HPC 0x1601C /* PWM 0 high pulse width counter register */ + +/* Analog/Digital Converter registers */ +#define HD64465_REG_ADDRA 0x1E000 /* A/D data register A */ +#define HD64465_REG_ADDRB 0x1E002 /* A/D data register B */ +#define HD64465_REG_ADDRC 0x1E004 /* A/D data register C */ +#define HD64465_REG_ADDRD 0x1E006 /* A/D data register D */ +#define HD64465_REG_ADCSR 0x1E008 /* A/D control/status register */ +#define HD64465_ADCSR_ADF 0x80 /* A/D End Flag */ +#define HD64465_ADCSR_ADST 0x40 /* A/D Start Flag */ +#define HD64465_ADCSR_ADIS 0x20 /* A/D Interrupt Status */ +#define HD64465_ADCSR_TRGE 0x10 /* A/D Trigger Enable */ +#define HD64465_ADCSR_ADIE 0x08 /* A/D Interrupt Enable */ +#define HD64465_ADCSR_SCAN 0x04 /* A/D Scan Mode */ +#define HD64465_ADCSR_CH_MASK 0x03 /* A/D Channel */ +#define HD64465_REG_ADCALCR 0x1E00A /* A/D calibration sample control */ +#define HD64465_REG_ADCAL 0x1E00C /* A/D calibration data register */ + + +/* General Purpose I/O ports registers */ +#define HD64465_REG_GPACR 0x14000 /* Port A Control Register */ +#define HD64465_REG_GPBCR 0x14002 /* Port B Control Register */ +#define HD64465_REG_GPCCR 0x14004 /* Port C Control Register */ +#define HD64465_REG_GPDCR 0x14006 /* Port D Control Register */ +#define HD64465_REG_GPECR 0x14008 /* Port E Control Register */ +#define HD64465_REG_GPADR 0x14010 /* Port A Data Register */ +#define HD64465_REG_GPBDR 0x14012 /* Port B Data Register */ +#define HD64465_REG_GPCDR 0x14014 /* Port C Data Register */ +#define HD64465_REG_GPDDR 0x14016 /* Port D Data Register */ +#define HD64465_REG_GPEDR 0x14018 /* Port E Data Register */ +#define HD64465_REG_GPAICR 0x14020 /* Port A Interrupt Control Register */ +#define HD64465_REG_GPBICR 0x14022 /* Port B Interrupt Control Register */ +#define HD64465_REG_GPCICR 0x14024 /* Port C Interrupt Control Register */ +#define HD64465_REG_GPDICR 0x14026 /* Port D Interrupt Control Register */ +#define HD64465_REG_GPEICR 0x14028 /* Port E Interrupt Control Register */ +#define HD64465_REG_GPAISR 0x14040 /* Port A Interrupt Status Register */ +#define HD64465_REG_GPBISR 0x14042 /* Port B Interrupt Status Register */ +#define HD64465_REG_GPCISR 0x14044 /* Port C Interrupt Status Register */ +#define HD64465_REG_GPDISR 0x14046 /* Port D Interrupt Status Register */ +#define HD64465_REG_GPEISR 0x14048 /* Port E Interrupt Status Register */ + +/* PCMCIA bridge interface */ +#define HD64465_REG_PCC0ISR 0x12000 /* socket 0 interface status */ +#define HD64465_PCCISR_PREADY 0x80 /* mem card ready / io card IREQ */ +#define HD64465_PCCISR_PIREQ 0x80 +#define HD64465_PCCISR_PMWP 0x40 /* mem card write-protected */ +#define HD64465_PCCISR_PVS2 0x20 /* voltage select pin 2 */ +#define HD64465_PCCISR_PVS1 0x10 /* voltage select pin 1 */ +#define HD64465_PCCISR_PCD_MASK 0x0c /* card detect */ +#define HD64465_PCCISR_PBVD_MASK 0x03 /* battery voltage */ +#define HD64465_PCCISR_PBVD_BATGOOD 0x03 /* battery good */ +#define HD64465_PCCISR_PBVD_BATWARN 0x01 /* battery low warning */ +#define HD64465_PCCISR_PBVD_BATDEAD1 0x02 /* battery dead */ +#define HD64465_PCCISR_PBVD_BATDEAD2 0x00 /* battery dead */ +#define HD64465_REG_PCC0GCR 0x12002 /* socket 0 general control */ +#define HD64465_PCCGCR_PDRV 0x80 /* output drive */ +#define HD64465_PCCGCR_PCCR 0x40 /* PC card reset */ +#define HD64465_PCCGCR_PCCT 0x20 /* PC card type, 1=IO&mem, 0=mem */ +#define HD64465_PCCGCR_PVCC0 0x10 /* voltage control pin VCC0SEL0 */ +#define HD64465_PCCGCR_PMMOD 0x08 /* memory mode */ +#define HD64465_PCCGCR_PPA25 0x04 /* pin A25 */ +#define HD64465_PCCGCR_PPA24 0x02 /* pin A24 */ +#define HD64465_PCCGCR_PREG 0x01 /* ping PCC0REG# */ +#define HD64465_REG_PCC0CSCR 0x12004 /* socket 0 card status change */ +#define HD64465_PCCCSCR_PSCDI 0x80 /* sw card detect intr */ +#define HD64465_PCCCSCR_PSWSEL 0x40 /* power select */ +#define HD64465_PCCCSCR_PIREQ 0x20 /* IREQ intr req */ +#define HD64465_PCCCSCR_PSC 0x10 /* STSCHG (status change) pin */ +#define HD64465_PCCCSCR_PCDC 0x08 /* CD (card detect) change */ +#define HD64465_PCCCSCR_PRC 0x04 /* ready change */ +#define HD64465_PCCCSCR_PBW 0x02 /* battery warning change */ +#define HD64465_PCCCSCR_PBD 0x01 /* battery dead change */ +#define HD64465_REG_PCC0CSCIER 0x12006 /* socket 0 card status change interrupt enable */ +#define HD64465_PCCCSCIER_PCRE 0x80 /* change reset enable */ +#define HD64465_PCCCSCIER_PIREQE_MASK 0x60 /* IREQ enable */ +#define HD64465_PCCCSCIER_PIREQE_DISABLED 0x00 /* IREQ disabled */ +#define HD64465_PCCCSCIER_PIREQE_LEVEL 0x20 /* IREQ level-triggered */ +#define HD64465_PCCCSCIER_PIREQE_FALLING 0x40 /* IREQ falling-edge-trig */ +#define HD64465_PCCCSCIER_PIREQE_RISING 0x60 /* IREQ rising-edge-trig */ +#define HD64465_PCCCSCIER_PSCE 0x10 /* status change enable */ +#define HD64465_PCCCSCIER_PCDE 0x08 /* card detect change enable */ +#define HD64465_PCCCSCIER_PRE 0x04 /* ready change enable */ +#define HD64465_PCCCSCIER_PBWE 0x02 /* battery warn change enable */ +#define HD64465_PCCCSCIER_PBDE 0x01 /* battery dead change enable*/ +#define HD64465_REG_PCC0SCR 0x12008 /* socket 0 software control */ +#define HD64465_PCCSCR_SHDN 0x10 /* TPS2206 SHutDowN pin */ +#define HD64465_PCCSCR_SWP 0x01 /* write protect */ +#define HD64465_REG_PCCPSR 0x1200A /* serial power switch control */ +#define HD64465_REG_PCC1ISR 0x12010 /* socket 1 interface status */ +#define HD64465_REG_PCC1GCR 0x12012 /* socket 1 general control */ +#define HD64465_REG_PCC1CSCR 0x12014 /* socket 1 card status change */ +#define HD64465_REG_PCC1CSCIER 0x12016 /* socket 1 card status change interrupt enable */ +#define HD64465_REG_PCC1SCR 0x12018 /* socket 1 software control */ + + +/* PS/2 Keyboard and mouse controller -- *not* register compatible */ +#define HD64465_REG_KBCSR 0x1dc00 /* Keyboard Control/Status reg */ +#define HD64465_KBCSR_KBCIE 0x8000 /* KBCK Input Enable */ +#define HD64465_KBCSR_KBCOE 0x4000 /* KBCK Output Enable */ +#define HD64465_KBCSR_KBDOE 0x2000 /* KB DATA Output Enable */ +#define HD64465_KBCSR_KBCD 0x1000 /* KBCK Driven */ +#define HD64465_KBCSR_KBDD 0x0800 /* KB DATA Driven */ +#define HD64465_KBCSR_KBCS 0x0400 /* KBCK pin Status */ +#define HD64465_KBCSR_KBDS 0x0200 /* KB DATA pin Status */ +#define HD64465_KBCSR_KBDP 0x0100 /* KB DATA Parity bit */ +#define HD64465_KBCSR_KBD_MASK 0x00ff /* KD DATA shift reg */ +#define HD64465_REG_KBISR 0x1dc04 /* Keyboard Interrupt Status reg */ +#define HD64465_KBISR_KBRDF 0x0001 /* KB Received Data Full */ +#define HD64465_REG_MSCSR 0x1dc10 /* Mouse Control/Status reg */ +#define HD64465_REG_MSISR 0x1dc14 /* Mouse Interrupt Status reg */ + + +/* + * Logical address at which the HD64465 is mapped. Note that this + * should always be in the P2 segment (uncached and untranslated). + */ +#ifndef CONFIG_HD64465_IOBASE +#define CONFIG_HD64465_IOBASE 0xb0000000 +#endif +/* + * The HD64465 multiplexes all its modules' interrupts onto + * this single interrupt. + */ +#ifndef CONFIG_HD64465_IRQ +#define CONFIG_HD64465_IRQ 5 +#endif + + +#define _HD64465_IO_MASK 0xf8000000 +#define is_hd64465_addr(addr) \ + ((addr & _HD64465_IO_MASK) == (CONFIG_HD64465_IOBASE & _HD64465_IO_MASK)) + +/* + * A range of 16 virtual interrupts generated by + * demuxing the HD64465 muxed interrupt. + */ +#define HD64465_IRQ_BASE OFFCHIP_IRQ_BASE +#define HD64465_IRQ_NUM 16 +#define HD64465_IRQ_ADC (HD64465_IRQ_BASE+0) +#define HD64465_IRQ_USB (HD64465_IRQ_BASE+1) +#define HD64465_IRQ_SCDI (HD64465_IRQ_BASE+2) +#define HD64465_IRQ_PARALLEL (HD64465_IRQ_BASE+3) +/* bit 4 is reserved */ +#define HD64465_IRQ_UART (HD64465_IRQ_BASE+5) +#define HD64465_IRQ_IRDA (HD64465_IRQ_BASE+6) +#define HD64465_IRQ_PS2MOUSE (HD64465_IRQ_BASE+7) +#define HD64465_IRQ_KBC (HD64465_IRQ_BASE+8) +#define HD64465_IRQ_TIMER1 (HD64465_IRQ_BASE+9) +#define HD64465_IRQ_TIMER0 (HD64465_IRQ_BASE+10) +#define HD64465_IRQ_GPIO (HD64465_IRQ_BASE+11) +#define HD64465_IRQ_AFE (HD64465_IRQ_BASE+12) +#define HD64465_IRQ_PCMCIA1 (HD64465_IRQ_BASE+13) +#define HD64465_IRQ_PCMCIA0 (HD64465_IRQ_BASE+14) +#define HD64465_IRQ_PS2KBD (HD64465_IRQ_BASE+15) + +/* Constants for PCMCIA mappings */ +#define HD64465_PCC_WINDOW 0x01000000 + +#define HD64465_PCC0_BASE 0xb8000000 /* area 6 */ +#define HD64465_PCC0_ATTR (HD64465_PCC0_BASE) +#define HD64465_PCC0_COMM (HD64465_PCC0_BASE+HD64465_PCC_WINDOW) +#define HD64465_PCC0_IO (HD64465_PCC0_BASE+2*HD64465_PCC_WINDOW) + +#define HD64465_PCC1_BASE 0xb4000000 /* area 5 */ +#define HD64465_PCC1_ATTR (HD64465_PCC1_BASE) +#define HD64465_PCC1_COMM (HD64465_PCC1_BASE+HD64465_PCC_WINDOW) +#define HD64465_PCC1_IO (HD64465_PCC1_BASE+2*HD64465_PCC_WINDOW) + +/* + * Base of USB controller interface (as memory) + */ +#define HD64465_USB_BASE (CONFIG_HD64465_IOBASE+0xb000) +#define HD64465_USB_LEN 0x1000 +/* + * Base of embedded SRAM, used for USB controller. + */ +#define HD64465_SRAM_BASE (CONFIG_HD64465_IOBASE+0x9000) +#define HD64465_SRAM_LEN 0x1000 + + + +#endif /* _ASM_SH_HD64465_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/hd64465_gpio.h linux.ac/include/asm-sh/hd64465_gpio.h --- linux.vanilla/include/asm-sh/hd64465_gpio.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-sh/hd64465_gpio.h Sat Apr 14 01:39:30 2001 @@ -0,0 +1,47 @@ +#ifndef _ASM_SH_HD64465_GPIO_ +#define _ASM_SH_HD64465_GPIO_ 1 +/* + * $Id: hd64465_gpio.h,v 1.1 2001/01/02 15:35:22 mjd Exp $ + * + * Hitachi HD64465 companion chip: General Purpose IO pins support. + * This layer enables other device drivers to configure GPIO + * pins, get and set their values, and register an interrupt + * routine for when input pins change in hardware. + * + * by Greg Banks <gbanks@pocketpenguins.com> + * (c) 2000 PocketPenguins Inc. + */ +#include <linux/config.h> +#include <asm/hd64465.h> + +/* Macro to construct a portpin number (used in all + * subsequent functions) from a port letter and a pin + * number, e.g. HD64465_GPIO_PORTPIN('A', 5). + */ +#define HD64465_GPIO_PORTPIN(port,pin) (((port)-'A')<<3|(pin)) + +/* Pin configuration constants for _configure() */ +#define HD64465_GPIO_FUNCTION2 0 /* use the pin's *other* function */ +#define HD64465_GPIO_OUT 1 /* output */ +#define HD64465_GPIO_IN_PULLUP 2 /* input, pull-up MOS on */ +#define HD64465_GPIO_IN 3 /* input */ + +/* Configure a pin's direction */ +extern void hd64465_gpio_configure(int portpin, int direction); + +/* Get, set value */ +extern void hd64465_gpio_set_pin(int portpin, unsigned int value); +extern unsigned int hd64465_gpio_get_pin(int portpin); +extern void hd64465_gpio_set_port(int port, unsigned int value); +extern unsigned int hd64465_gpio_get_port(int port); + +/* mode constants for _register_irq() */ +#define HD64465_GPIO_FALLING 0 +#define HD64465_GPIO_RISING 1 + +/* Interrupt on external value change */ +extern void hd64465_gpio_register_irq(int portpin, int mode, + void (*handler)(int portpin, void *dev), void *dev); +extern void hd64465_gpio_unregister_irq(int portpin); + +#endif /* _ASM_SH_HD64465_GPIO_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/hitachi_se.h linux.ac/include/asm-sh/hitachi_se.h --- linux.vanilla/include/asm-sh/hitachi_se.h Tue Jun 20 01:59:38 2000 +++ linux.ac/include/asm-sh/hitachi_se.h Tue Apr 3 17:55:16 2001 @@ -38,7 +38,7 @@ #define PA_LED 0xb0c00000 /* LED */ #define PA_BCR 0xb1400000 /* FPGA */ -#define PA_MRSHPC 0xb83fffe0 /* MR-SHPC-01 PCMCIA controler */ +#define PA_MRSHPC 0xb83fffe0 /* MR-SHPC-01 PCMCIA controller */ #define PA_MRSHPC_MW1 0xb8400000 /* MR-SHPC-01 memory window base */ #define PA_MRSHPC_MW2 0xb8500000 /* MR-SHPC-01 attribute window base */ #define PA_MRSHPC_IO 0xb8600000 /* MR-SHPC-01 I/O window base */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/ide.h linux.ac/include/asm-sh/ide.h --- linux.vanilla/include/asm-sh/ide.h Mon Oct 2 19:57:34 2000 +++ linux.ac/include/asm-sh/ide.h Sat Apr 14 01:39:30 2001 @@ -28,7 +28,7 @@ { switch (base) { case 0x01f0: return 77; - case 0x0170: return 77; + case 0x0170: return 78; default: return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/io.h linux.ac/include/asm-sh/io.h --- linux.vanilla/include/asm-sh/io.h Wed Aug 9 21:59:04 2000 +++ linux.ac/include/asm-sh/io.h Sat Apr 14 01:39:38 2001 @@ -35,7 +35,7 @@ */ #ifdef __KERNEL__ -#ifdef CONFIG_SH_GENERIC +#if defined(CONFIG_SH_GENERIC) || defined(CONFIG_SH_CQREEK) || defined(CONFIG_SH_UNKNOWN) /* In a generic kernel, we always go through the machine vector. */ @@ -70,7 +70,6 @@ # define __writel(v,a) sh_mv.mv_writel((v),(a)) # define __ioremap(a,s) sh_mv.mv_ioremap((a), (s)) -# define __ioremap_nocache(a,s) sh_mv.mv_ioremap_nocache((a), (s)) # define __iounmap(a) sh_mv.mv_iounmap((a)) # define __isa_port2addr(a) sh_mv.mv_isa_port2addr(a) @@ -110,10 +109,20 @@ # if defined(CONFIG_SH_HP600) # include <asm/io_hd64461.h> -# elif defined(CONFIG_SH_OVERDRIVE) +# elif defined(CONFIG_SH_7750_OVERDRIVE) # include <asm/io_od.h> # elif defined(CONFIG_SH_SOLUTION_ENGINE) # include <asm/io_se.h> +# elif defined(CONFIG_SH_DMIDA) || \ + defined(CONFIG_SH_STB1_HARP) || \ + defined(CONFIG_SH_STB1_OVERDRIVE) +# include <asm/io_hd64465.h> +# elif defined(CONFIG_SH_EC3104) +# include <asm/io_ec3104.h> +# elif defined(CONFIG_SH_DREAMCAST) +# include <asm/io_dc.h> +# elif defined(CONFIG_SH_CAT68701) +# include <asm/io_cat68701.h> # elif defined(CONFIG_SH_UNKNOWN) # include <asm/io_unknown.h> # else @@ -126,40 +135,38 @@ #endif /* __KERNEL__ */ /* These are always function calls, in both kernel and user space */ -extern unsigned int _inb (unsigned long port); -extern unsigned int _inw (unsigned long port); +extern unsigned char _inb (unsigned long port); +extern unsigned short _inw (unsigned long port); extern unsigned int _inl (unsigned long port); -extern void _outb (unsigned char b,unsigned long port); -extern void _outw (unsigned short w,unsigned long port); -extern void _outl (unsigned int l,unsigned long port); -extern unsigned int _inb_p (unsigned long port); -extern unsigned int _inw_p (unsigned long port); +extern void _outb (unsigned char b, unsigned long port); +extern void _outw (unsigned short w, unsigned long port); +extern void _outl (unsigned int l, unsigned long port); +extern unsigned char _inb_p (unsigned long port); +extern unsigned short _inw_p (unsigned long port); extern unsigned int _inl_p (unsigned long port); -extern void _outb_p (unsigned char b,unsigned long port); -extern void _outw_p (unsigned short w,unsigned long port); -extern void _outl_p (unsigned int l,unsigned long port); +extern void _outb_p (unsigned char b, unsigned long port); +extern void _outw_p (unsigned short w, unsigned long port); +extern void _outl_p (unsigned int l, unsigned long port); extern void _insb (unsigned long port, void *dst, unsigned long count); extern void _insw (unsigned long port, void *dst, unsigned long count); extern void _insl (unsigned long port, void *dst, unsigned long count); extern void _outsb (unsigned long port, const void *src, unsigned long count); extern void _outsw (unsigned long port, const void *src, unsigned long count); extern void _outsl (unsigned long port, const void *src, unsigned long count); -extern unsigned long _readb(unsigned long addr); -extern unsigned long _readw(unsigned long addr); -extern unsigned long _readl(unsigned long addr); +extern unsigned char _readb(unsigned long addr); +extern unsigned short _readw(unsigned long addr); +extern unsigned int _readl(unsigned long addr); extern void _writeb(unsigned char b, unsigned long addr); extern void _writew(unsigned short b, unsigned long addr); extern void _writel(unsigned int b, unsigned long addr); #ifdef __KERNEL__ -extern unsigned long ___raw_readb(unsigned long addr); -extern unsigned long ___raw_readw(unsigned long addr); -extern unsigned long ___raw_readl(unsigned long addr); -extern unsigned long ___raw_readq(unsigned long addr); +extern unsigned char ___raw_readb(unsigned long addr); +extern unsigned short ___raw_readw(unsigned long addr); +extern unsigned int ___raw_readl(unsigned long addr); extern void ___raw_writeb(unsigned char b, unsigned long addr); extern void ___raw_writew(unsigned short b, unsigned long addr); extern void ___raw_writel(unsigned int b, unsigned long addr); -extern void ___raw_writeq(unsigned long b, unsigned long addr); #endif #ifdef __KERNEL__ @@ -291,20 +298,20 @@ /* Userspace declarations. */ -extern unsigned int inb(unsigned long port); -extern unsigned int inw(unsigned long port); +extern unsigned char inb(unsigned long port); +extern unsigned short inw(unsigned long port); extern unsigned int inl(unsigned long port); -extern void outb(unsigned char b,unsigned long port); -extern void outw(unsigned short w,unsigned long port); -extern void outl(unsigned int l,unsigned long port); -extern void insb (unsigned long port, void *dst, unsigned long count); -extern void insw (unsigned long port, void *dst, unsigned long count); -extern void insl (unsigned long port, void *dst, unsigned long count); -extern void outsb (unsigned long port, const void *src, unsigned long count); -extern void outsw (unsigned long port, const void *src, unsigned long count); -extern void outsl (unsigned long port, const void *src, unsigned long count); -extern unsigned long readb(unsigned long addr); -extern unsigned long readw(unsigned long addr); +extern void outb(unsigned char b, unsigned long port); +extern void outw(unsigned short w, unsigned long port); +extern void outl(unsigned int l, unsigned long port); +extern void insb(unsigned long port, void *dst, unsigned long count); +extern void insw(unsigned long port, void *dst, unsigned long count); +extern void insl(unsigned long port, void *dst, unsigned long count); +extern void outsb(unsigned long port, const void *src, unsigned long count); +extern void outsw(unsigned long port, const void *src, unsigned long count); +extern void outsl(unsigned long port, const void *src, unsigned long count); +extern unsigned char readb(unsigned long addr); +extern unsigned short readw(unsigned long addr); extern unsigned long readl(unsigned long addr); extern void writeb(unsigned char b, unsigned long addr); extern void writew(unsigned short b, unsigned long addr); @@ -342,17 +349,17 @@ extern void memset_io(unsigned long, int, unsigned long); /* SuperH on-chip I/O functions */ -extern __inline__ unsigned long ctrl_inb(unsigned long addr) +extern __inline__ unsigned char ctrl_inb(unsigned long addr) { return *(volatile unsigned char*)addr; } -extern __inline__ unsigned long ctrl_inw(unsigned long addr) +extern __inline__ unsigned short ctrl_inw(unsigned long addr) { return *(volatile unsigned short*)addr; } -extern __inline__ unsigned long ctrl_inl(unsigned long addr) +extern __inline__ unsigned int ctrl_inl(unsigned long addr) { return *(volatile unsigned long*)addr; } @@ -412,20 +419,12 @@ return __ioremap(offset, size); } -/* - * This one maps high address device memory and turns off caching for that area. - * it's useful if some control registers are in such an area and write combining - * or read caching is not desirable: - */ -static __inline__ void * ioremap_nocache (unsigned long offset, unsigned long size) -{ - return __ioremap_nocache(offset, size); -} - static __inline__ void iounmap(void *addr) { return __iounmap(addr); } + +#define ioremap_nocache(off,size) ioremap(off,size) static __inline__ int check_signature(unsigned long io_addr, const unsigned char *signature, int length) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/io_cat68701.h linux.ac/include/asm-sh/io_cat68701.h --- linux.vanilla/include/asm-sh/io_cat68701.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-sh/io_cat68701.h Sat Apr 14 01:39:38 2001 @@ -0,0 +1,89 @@ +/* + * include/asm-sh/io_cat68701.h + * + * Copyright 2000 Stuart Menefy (stuart.menefy@st.com) + * 2001 Yutarou Ebihar (ebihara@si-linux.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * IO functions for an AONE Corp. CAT-68701 SH7708 Borad + */ + +#ifndef _ASM_SH_IO_CAT68701_H +#define _ASM_SH_IO_CAT68701_H + +#include <asm/io_generic.h> + +extern unsigned char cat68701_inb(unsigned long port); +extern unsigned short cat68701_inw(unsigned long port); +extern unsigned int cat68701_inl(unsigned long port); + +extern void cat68701_outb(unsigned char value, unsigned long port); +extern void cat68701_outw(unsigned short value, unsigned long port); +extern void cat68701_outl(unsigned int value, unsigned long port); + +extern unsigned char cat68701_inb_p(unsigned long port); +extern void cat68701_outb_p(unsigned char value, unsigned long port); + +extern void cat68701_insb(unsigned long port, void *addr, unsigned long count); +extern void cat68701_insw(unsigned long port, void *addr, unsigned long count); +extern void cat68701_insl(unsigned long port, void *addr, unsigned long count); +extern void cat68701_outsb(unsigned long port, const void *addr, unsigned long count); +extern void cat68701_outsw(unsigned long port, const void *addr, unsigned long count); +extern void cat68701_outsl(unsigned long port, const void *addr, unsigned long count); + +extern unsigned char cat68701_readb(unsigned long addr); +extern unsigned short cat68701_readw(unsigned long addr); +extern unsigned int cat68701_readl(unsigned long addr); +extern void cat68701_writeb(unsigned char b, unsigned long addr); +extern void cat68701_writew(unsigned short b, unsigned long addr); +extern void cat68701_writel(unsigned int b, unsigned long addr); + +extern void * cat68701_ioremap(unsigned long offset, unsigned long size); +extern void cat68701_iounmap(void *addr); + +extern unsigned long cat68701_isa_port2addr(unsigned long offset); +extern int cat68701_irq_demux(int irq); + +extern void setup_cat68701(void); +extern void init_cat68701_IRQ(void); +extern void heartbeat_cat68701(void); + +#ifdef __WANT_IO_DEF + +# define __inb cat68701_inb +# define __inw cat68701_inw +# define __inl cat68701_inl +# define __outb cat68701_outb +# define __outw cat68701_outw +# define __outl cat68701_outl + +# define __inb_p cat68701_inb_p +# define __inw_p cat68701_inw +# define __inl_p cat68701_inl +# define __outb_p cat68701_outb_p +# define __outw_p cat68701_outw +# define __outl_p cat68701_outl + +# define __insb cat68701_insb +# define __insw cat68701_insw +# define __insl cat68701_insl +# define __outsb cat68701_outsb +# define __outsw cat68701_outsw +# define __outsl cat68701_outsl + +# define __readb cat68701_readb +# define __readw cat68701_readw +# define __readl cat68701_readl +# define __writeb cat68701_writeb +# define __writew cat68701_writew +# define __writel cat68701_writel + +# define __isa_port2addr cat68701_isa_port2addr +# define __ioremap generic_ioremap +# define __iounmap generic_iounmap + +#endif + +#endif /* _ASM_SH_IO_CAT68701_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/io_dc.h linux.ac/include/asm-sh/io_dc.h --- linux.vanilla/include/asm-sh/io_dc.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-sh/io_dc.h Sat Apr 14 01:39:38 2001 @@ -0,0 +1,49 @@ +/* + * $Id: io_dc.h,v 1.1 2001/04/01 15:02:56 yaegashi Exp $ + * IO functions for SEGA Dreamcast + */ + +#ifndef _ASM_SH_IO_DREAMCAST_H +#define _ASM_SH_IO_DREAMCAST_H + +#include <asm/io_generic.h> + +unsigned long dreamcast_isa_port2addr(unsigned long offset); + +#ifdef __WANT_IO_DEF + +# define __inb generic_inb +# define __inw generic_inw +# define __inl generic_inl +# define __outb generic_outb +# define __outw generic_outw +# define __outl generic_outl + +# define __inb_p generic_inb_p +# define __inw_p generic_inw +# define __inl_p generic_inl +# define __outb_p generic_outb_p +# define __outw_p generic_outw +# define __outl_p generic_outl + +# define __insb generic_insb +# define __insw generic_insw +# define __insl generic_insl +# define __outsb generic_outsb +# define __outsw generic_outsw +# define __outsl generic_outsl + +# define __readb generic_readb +# define __readw generic_readw +# define __readl generic_readl +# define __writeb generic_writeb +# define __writew generic_writew +# define __writel generic_writel + +# define __isa_port2addr dreamcast_isa_port2addr +# define __ioremap generic_ioremap +# define __iounmap generic_iounmap + +#endif + +#endif /* _ASM_SH_IO_DREAMCAST_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/io_ec3104.h linux.ac/include/asm-sh/io_ec3104.h --- linux.vanilla/include/asm-sh/io_ec3104.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-sh/io_ec3104.h Sat Apr 14 01:39:38 2001 @@ -0,0 +1,54 @@ +#ifndef _ASM_SH_IO_EC3104_H +#define _ASM_SH_IO_EC3104_H + +#include <asm/io_generic.h> +#include <linux/types.h> + +extern unsigned char ec3104_inb(unsigned long port); +extern unsigned short ec3104_inw(unsigned long port); +extern unsigned long ec3104_inl(unsigned long port); + +extern void ec3104_outb(unsigned char value, unsigned long port); +extern void ec3104_outw(unsigned short value, unsigned long port); +extern void ec3104_outl(unsigned long value, unsigned long port); + +extern int ec3104_irq_demux(int irq); + +#ifdef __WANT_IO_DEF + +# define __inb ec3104_inb +# define __inw ec3104_inw +# define __inl ec3104_inl +# define __outb ec3104_outb +# define __outw ec3104_outw +# define __outl ec3104_outl + +# define __inb_p ec3104_inb +# define __inw_p ec3104_inw +# define __inl_p ec3104_inl +# define __outb_p ec3104_outb +# define __outw_p ec3104_outw +# define __outl_p ec3104_outl + +# define __insb generic_insb +# define __insw generic_insw +# define __insl generic_insl +# define __outsb generic_outsb +# define __outsw generic_outsw +# define __outsl generic_outsl + +# define __readb generic_readb +# define __readw generic_readw +# define __readl generic_readl +# define __writeb generic_writeb +# define __writew generic_writew +# define __writel generic_writel + +# define __isa_port2addr generic_isa_port2addr +# define __ioremap generic_ioremap +# define __ioremap_nocache generic_ioremap_nocache +# define __iounmap generic_iounmap + +#endif + +#endif /* _ASM_SH_IO_EC3104_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/io_generic.h linux.ac/include/asm-sh/io_generic.h --- linux.vanilla/include/asm-sh/io_generic.h Wed Aug 9 21:59:04 2000 +++ linux.ac/include/asm-sh/io_generic.h Sat Apr 14 01:39:38 2001 @@ -14,37 +14,36 @@ extern unsigned long generic_io_base; -extern unsigned long generic_inb(unsigned int port); -extern unsigned long generic_inw(unsigned int port); -extern unsigned long generic_inl(unsigned int port); +extern unsigned char generic_inb(unsigned long port); +extern unsigned short generic_inw(unsigned long port); +extern unsigned int generic_inl(unsigned long port); -extern void generic_outb(unsigned long value, unsigned int port); -extern void generic_outw(unsigned long value, unsigned int port); -extern void generic_outl(unsigned long value, unsigned int port); +extern void generic_outb(unsigned char value, unsigned long port); +extern void generic_outw(unsigned short value, unsigned long port); +extern void generic_outl(unsigned int value, unsigned long port); -extern unsigned long generic_inb_p(unsigned int port); -extern unsigned long generic_inw_p(unsigned int port); -extern unsigned long generic_inl_p(unsigned int port); -extern void generic_outb_p(unsigned long value, unsigned int port); -extern void generic_outw_p(unsigned long value, unsigned int port); -extern void generic_outl_p(unsigned long value, unsigned int port); +extern unsigned char generic_inb_p(unsigned long port); +extern unsigned short generic_inw_p(unsigned long port); +extern unsigned int generic_inl_p(unsigned long port); +extern void generic_outb_p(unsigned char value, unsigned long port); +extern void generic_outw_p(unsigned short value, unsigned long port); +extern void generic_outl_p(unsigned int value, unsigned long port); -extern void generic_insb(unsigned int port, void *addr, unsigned long count); -extern void generic_insw(unsigned int port, void *addr, unsigned long count); -extern void generic_insl(unsigned int port, void *addr, unsigned long count); -extern void generic_outsb(unsigned int port, const void *addr, unsigned long count); -extern void generic_outsw(unsigned int port, const void *addr, unsigned long count); -extern void generic_outsl(unsigned int port, const void *addr, unsigned long count); +extern void generic_insb(unsigned long port, void *addr, unsigned long count); +extern void generic_insw(unsigned long port, void *addr, unsigned long count); +extern void generic_insl(unsigned long port, void *addr, unsigned long count); +extern void generic_outsb(unsigned long port, const void *addr, unsigned long count); +extern void generic_outsw(unsigned long port, const void *addr, unsigned long count); +extern void generic_outsl(unsigned long port, const void *addr, unsigned long count); -extern unsigned long generic_readb(unsigned long addr); -extern unsigned long generic_readw(unsigned long addr); -extern unsigned long generic_readl(unsigned long addr); +extern unsigned char generic_readb(unsigned long addr); +extern unsigned short generic_readw(unsigned long addr); +extern unsigned int generic_readl(unsigned long addr); extern void generic_writeb(unsigned char b, unsigned long addr); extern void generic_writew(unsigned short b, unsigned long addr); extern void generic_writel(unsigned int b, unsigned long addr); extern void *generic_ioremap(unsigned long offset, unsigned long size); -extern void *generic_ioremap_nocache (unsigned long offset, unsigned long size); extern void generic_iounmap(void *addr); extern unsigned long generic_isa_port2addr(unsigned long offset); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/io_hd64461.h linux.ac/include/asm-sh/io_hd64461.h --- linux.vanilla/include/asm-sh/io_hd64461.h Mon Oct 2 19:57:34 2000 +++ linux.ac/include/asm-sh/io_hd64461.h Sat Apr 14 01:39:38 2001 @@ -14,23 +14,24 @@ #include <asm/io_generic.h> -extern unsigned long hd64461_inb(unsigned int port); -extern unsigned long hd64461_inw(unsigned int port); -extern unsigned long hd64461_inl(unsigned int port); - -extern void hd64461_outb(unsigned long value, unsigned int port); -extern void hd64461_outw(unsigned long value, unsigned int port); -extern void hd64461_outl(unsigned long value, unsigned int port); - -extern unsigned long hd64461_inb_p(unsigned int port); -extern void hd64461_outb_p(unsigned long value, unsigned int port); - -extern void hd64461_insb(unsigned int port, void *addr, unsigned long count); -extern void hd64461_insw(unsigned int port, void *addr, unsigned long count); -extern void hd64461_insl(unsigned int port, void *addr, unsigned long count); -extern void hd64461_outsb(unsigned int port, const void *addr, unsigned long count); -extern void hd64461_outsw(unsigned int port, const void *addr, unsigned long count); -extern void hd64461_outsl(unsigned int port, const void *addr, unsigned long count); +extern unsigned char hd64461_inb(unsigned long port); +extern unsigned short hd64461_inw(unsigned long port); +extern unsigned int hd64461_inl(unsigned long port); + +extern void hd64461_outb(unsigned char value, unsigned long port); +extern void hd64461_outw(unsigned short value, unsigned long port); +extern void hd64461_outl(unsigned int value, unsigned long port); + +extern unsigned char hd64461_inb_p(unsigned long port); +extern void hd64461_outb_p(unsigned char value, unsigned long port); + +extern void hd64461_insb(unsigned long port, void *addr, unsigned long count); +extern void hd64461_insw(unsigned long port, void *addr, unsigned long count); +extern void hd64461_insl(unsigned long port, void *addr, unsigned long count); +extern void hd64461_outsb(unsigned long port, const void *addr, unsigned long count); +extern void hd64461_outsw(unsigned long port, const void *addr, unsigned long count); +extern void hd64461_outsl(unsigned long port, const void *addr, unsigned long count); +extern int hd64461_irq_demux(int irq); #ifdef __WANT_IO_DEF @@ -64,6 +65,7 @@ # define __isa_port2addr generic_isa_port2addr # define __ioremap generic_ioremap +# define __ioremap_nocache generic_ioremap_nocache # define __iounmap generic_iounmap #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/io_hd64465.h linux.ac/include/asm-sh/io_hd64465.h --- linux.vanilla/include/asm-sh/io_hd64465.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-sh/io_hd64465.h Sat Apr 14 01:39:38 2001 @@ -0,0 +1,90 @@ +/* + * include/asm-sh/io_hd64465.h + * + * By Greg Banks <gbanks@pocketpenguins.com> + * (c) 2000 PocketPenguins Inc. + * + * Derived from io_hd64461.h, which bore the message: + * Copyright 2000 Stuart Menefy (stuart.menefy@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * IO functions for an HD64465 "Windows CE Intelligent Peripheral Controller". + */ + +#ifndef _ASM_SH_IO_HD64465_H +#define _ASM_SH_IO_HD64465_H + +#include <asm/io_generic.h> + +extern unsigned char hd64465_inb(unsigned long port); +extern unsigned short hd64465_inw(unsigned long port); +extern unsigned int hd64465_inl(unsigned long port); + +extern void hd64465_outb(unsigned char value, unsigned long port); +extern void hd64465_outw(unsigned short value, unsigned long port); +extern void hd64465_outl(unsigned int value, unsigned long port); + +extern unsigned char hd64465_inb_p(unsigned long port); +extern void hd64465_outb_p(unsigned char value, unsigned long port); + +extern void hd64465_insb(unsigned long port, void *addr, unsigned long count); +extern void hd64465_insw(unsigned long port, void *addr, unsigned long count); +extern void hd64465_insl(unsigned long port, void *addr, unsigned long count); +extern void hd64465_outsb(unsigned long port, const void *addr, unsigned long count); +extern void hd64465_outsw(unsigned long port, const void *addr, unsigned long count); +extern void hd64465_outsl(unsigned long port, const void *addr, unsigned long count); +extern unsigned long hd64465_isa_port2addr(unsigned long offset); +extern int hd64465_irq_demux(int irq); +/* Provision for generic secondary demux step -- used by PCMCIA code */ +extern void hd64465_register_irq_demux(int irq, + int (*demux)(int irq, void *dev), void *dev); +extern void hd64465_unregister_irq_demux(int irq); +/* Set this variable to 1 to see port traffic */ +extern int hd64465_io_debug; +/* Map a range of ports to a range of kernel virtual memory. + */ +extern void hd64465_port_map(unsigned short baseport, unsigned int nports, + unsigned long addr, unsigned char shift); +extern void hd64465_port_unmap(unsigned short baseport, unsigned int nports); + + +#ifdef __WANT_IO_DEF + +# define __inb hd64465_inb +# define __inw hd64465_inw +# define __inl hd64465_inl +# define __outb hd64465_outb +# define __outw hd64465_outw +# define __outl hd64465_outl + +# define __inb_p hd64465_inb_p +# define __inw_p hd64465_inw +# define __inl_p hd64465_inl +# define __outb_p hd64465_outb_p +# define __outw_p hd64465_outw +# define __outl_p hd64465_outl + +# define __insb hd64465_insb +# define __insw hd64465_insw +# define __insl hd64465_insl +# define __outsb hd64465_outsb +# define __outsw hd64465_outsw +# define __outsl hd64465_outsl + +# define __readb generic_readb +# define __readw generic_readw +# define __readl generic_readl +# define __writeb generic_writeb +# define __writew generic_writew +# define __writel generic_writel + +# define __isa_port2addr hd64465_isa_port2addr +# define __ioremap generic_ioremap +# define __iounmap generic_iounmap + + +#endif + +#endif /* _ASM_SH_IO_HD64465_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/io_od.h linux.ac/include/asm-sh/io_od.h --- linux.vanilla/include/asm-sh/io_od.h Wed Aug 9 21:59:04 2000 +++ linux.ac/include/asm-sh/io_od.h Sat Apr 14 01:39:38 2001 @@ -14,27 +14,27 @@ #include <asm/io_generic.h> -extern unsigned long od_inb(unsigned int port); -extern unsigned long od_inw(unsigned int port); -extern unsigned long od_inl(unsigned int port); - -extern void od_outb(unsigned long value, unsigned int port); -extern void od_outw(unsigned long value, unsigned int port); -extern void od_outl(unsigned long value, unsigned int port); - -extern unsigned long od_inb_p(unsigned int port); -extern unsigned long od_inw_p(unsigned int port); -extern unsigned long od_inl_p(unsigned int port); -extern void od_outb_p(unsigned long value, unsigned int port); -extern void od_outw_p(unsigned long value, unsigned int port); -extern void od_outl_p(unsigned long value, unsigned int port); - -extern void od_insb(unsigned int port, void *addr, unsigned long count); -extern void od_insw(unsigned int port, void *addr, unsigned long count); -extern void od_insl(unsigned int port, void *addr, unsigned long count); -extern void od_outsb(unsigned int port, const void *addr, unsigned long count); -extern void od_outsw(unsigned int port, const void *addr, unsigned long count); -extern void od_outsl(unsigned int port, const void *addr, unsigned long count); +extern unsigned char od_inb(unsigned long port); +extern unsigned short od_inw(unsigned long port); +extern unsigned int od_inl(unsigned long port); + +extern void od_outb(unsigned char value, unsigned long port); +extern void od_outw(unsigned short value, unsigned long port); +extern void od_outl(unsigned int value, unsigned long port); + +extern unsigned char od_inb_p(unsigned long port); +extern unsigned short od_inw_p(unsigned long port); +extern unsigned int od_inl_p(unsigned long port); +extern void od_outb_p(unsigned char value, unsigned long port); +extern void od_outw_p(unsigned short value, unsigned long port); +extern void od_outl_p(unsigned int value, unsigned long port); + +extern void od_insb(unsigned long port, void *addr, unsigned long count); +extern void od_insw(unsigned long port, void *addr, unsigned long count); +extern void od_insl(unsigned long port, void *addr, unsigned long count); +extern void od_outsb(unsigned long port, const void *addr, unsigned long count); +extern void od_outsw(unsigned long port, const void *addr, unsigned long count); +extern void od_outsl(unsigned long port, const void *addr, unsigned long count); extern unsigned long od_isa_port2addr(unsigned long offset); @@ -70,7 +70,6 @@ # define __isa_port2addr od_isa_port2addr # define __ioremap generic_ioremap -# define __ioremap_nocache generic_ioremap_nocache # define __iounmap generic_iounmap #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/io_se.h linux.ac/include/asm-sh/io_se.h --- linux.vanilla/include/asm-sh/io_se.h Wed Aug 9 21:59:04 2000 +++ linux.ac/include/asm-sh/io_se.h Sat Apr 14 01:39:38 2001 @@ -14,27 +14,27 @@ #include <asm/io_generic.h> -extern unsigned long se_inb(unsigned int port); -extern unsigned long se_inw(unsigned int port); -extern unsigned long se_inl(unsigned int port); - -extern void se_outb(unsigned long value, unsigned int port); -extern void se_outw(unsigned long value, unsigned int port); -extern void se_outl(unsigned long value, unsigned int port); - -extern unsigned long se_inb_p(unsigned int port); -extern void se_outb_p(unsigned long value, unsigned int port); - -extern void se_insb(unsigned int port, void *addr, unsigned long count); -extern void se_insw(unsigned int port, void *addr, unsigned long count); -extern void se_insl(unsigned int port, void *addr, unsigned long count); -extern void se_outsb(unsigned int port, const void *addr, unsigned long count); -extern void se_outsw(unsigned int port, const void *addr, unsigned long count); -extern void se_outsl(unsigned int port, const void *addr, unsigned long count); - -extern unsigned long se_readb(unsigned long addr); -extern unsigned long se_readw(unsigned long addr); -extern unsigned long se_readl(unsigned long addr); +extern unsigned char se_inb(unsigned long port); +extern unsigned short se_inw(unsigned long port); +extern unsigned int se_inl(unsigned long port); + +extern void se_outb(unsigned char value, unsigned long port); +extern void se_outw(unsigned short value, unsigned long port); +extern void se_outl(unsigned int value, unsigned long port); + +extern unsigned char se_inb_p(unsigned long port); +extern void se_outb_p(unsigned char value, unsigned long port); + +extern void se_insb(unsigned long port, void *addr, unsigned long count); +extern void se_insw(unsigned long port, void *addr, unsigned long count); +extern void se_insl(unsigned long port, void *addr, unsigned long count); +extern void se_outsb(unsigned long port, const void *addr, unsigned long count); +extern void se_outsw(unsigned long port, const void *addr, unsigned long count); +extern void se_outsl(unsigned long port, const void *addr, unsigned long count); + +extern unsigned char se_readb(unsigned long addr); +extern unsigned short se_readw(unsigned long addr); +extern unsigned int se_readl(unsigned long addr); extern void se_writeb(unsigned char b, unsigned long addr); extern void se_writew(unsigned short b, unsigned long addr); extern void se_writel(unsigned int b, unsigned long addr); @@ -73,7 +73,6 @@ # define __isa_port2addr se_isa_port2addr # define __ioremap generic_ioremap -# define __ioremap_nocache generic_ioremap_nocache # define __iounmap generic_iounmap #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/io_unknown.h linux.ac/include/asm-sh/io_unknown.h --- linux.vanilla/include/asm-sh/io_unknown.h Wed Aug 9 21:59:04 2000 +++ linux.ac/include/asm-sh/io_unknown.h Sat Apr 14 01:39:38 2001 @@ -12,38 +12,37 @@ #ifndef _ASM_SH_IO_UNKNOWN_H #define _ASM_SH_IO_UNKNOWN_H -extern unsigned long unknown_inb(unsigned int port); -extern unsigned long unknown_inw(unsigned int port); -extern unsigned long unknown_inl(unsigned int port); - -extern void unknown_outb(unsigned long value, unsigned int port); -extern void unknown_outw(unsigned long value, unsigned int port); -extern void unknown_outl(unsigned long value, unsigned int port); - -extern unsigned long unknown_inb_p(unsigned int port); -extern unsigned long unknown_inw_p(unsigned int port); -extern unsigned long unknown_inl_p(unsigned int port); -extern void unknown_outb_p(unsigned long value, unsigned int port); -extern void unknown_outw_p(unsigned long value, unsigned int port); -extern void unknown_outl_p(unsigned long value, unsigned int port); - -extern void unknown_insb(unsigned int port, void *addr, unsigned long count); -extern void unknown_insw(unsigned int port, void *addr, unsigned long count); -extern void unknown_insl(unsigned int port, void *addr, unsigned long count); -extern void unknown_outsb(unsigned int port, const void *addr, unsigned long count); -extern void unknown_outsw(unsigned int port, const void *addr, unsigned long count); -extern void unknown_outsl(unsigned int port, const void *addr, unsigned long count); - -extern unsigned long unknown_readb(unsigned long addr); -extern unsigned long unknown_readw(unsigned long addr); -extern unsigned long unknown_readl(unsigned long addr); +extern unsigned char unknown_inb(unsigned long port); +extern unsigned short unknown_inw(unsigned long port); +extern unsigned int unknown_inl(unsigned long port); + +extern void unknown_outb(unsigned char value, unsigned long port); +extern void unknown_outw(unsigned short value, unsigned long port); +extern void unknown_outl(unsigned int value, unsigned long port); + +extern unsigned char unknown_inb_p(unsigned long port); +extern unsigned short unknown_inw_p(unsigned long port); +extern unsigned int unknown_inl_p(unsigned long port); +extern void unknown_outb_p(unsigned char value, unsigned long port); +extern void unknown_outw_p(unsigned short value, unsigned long port); +extern void unknown_outl_p(unsigned int value, unsigned long port); + +extern void unknown_insb(unsigned long port, void *addr, unsigned long count); +extern void unknown_insw(unsigned long port, void *addr, unsigned long count); +extern void unknown_insl(unsigned long port, void *addr, unsigned long count); +extern void unknown_outsb(unsigned long port, const void *addr, unsigned long count); +extern void unknown_outsw(unsigned long port, const void *addr, unsigned long count); +extern void unknown_outsl(unsigned long port, const void *addr, unsigned long count); + +extern unsigned char unknown_readb(unsigned long addr); +extern unsigned short unknown_readw(unsigned long addr); +extern unsigned int unknown_readl(unsigned long addr); extern void unknown_writeb(unsigned char b, unsigned long addr); extern void unknown_writew(unsigned short b, unsigned long addr); extern void unknown_writel(unsigned int b, unsigned long addr); extern unsigned long unknown_isa_port2addr(unsigned long offset); -extern void * unknown_ioremap(unsigned long offset, unsigned long size); -extern void * unknown_ioremap_nocache (unsigned long offset, unsigned long size); +extern void *unknown_ioremap(unsigned long offset, unsigned long size); extern void unknown_iounmap(void *addr); #ifdef __WANT_IO_DEF @@ -78,7 +77,6 @@ # define __isa_port2addr unknown_isa_port2addr # define __ioremap unknown_ioremap -# define __ioremap_nocache unknown_ioremap_nocache # define __iounmap unknown_iounmap #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/ioctls.h linux.ac/include/asm-sh/ioctls.h --- linux.vanilla/include/asm-sh/ioctls.h Sat Nov 6 18:40:31 1999 +++ linux.ac/include/asm-sh/ioctls.h Tue Apr 3 17:55:16 2001 @@ -9,6 +9,7 @@ #define FIONBIO _IOW('f', 126, int) #define FIONREAD _IOR('f', 127, int) #define TIOCINQ FIONREAD +#define FIOQSIZE _IOR('f', 128, loff_t) #define TCGETS 0x5401 #define TCSETS 0x5402 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/irq.h linux.ac/include/asm-sh/irq.h --- linux.vanilla/include/asm-sh/irq.h Mon Oct 2 19:57:34 2000 +++ linux.ac/include/asm-sh/irq.h Sat Apr 14 01:39:38 2001 @@ -12,6 +12,7 @@ #include <linux/config.h> #include <asm/machvec.h> +#include <asm/ptrace.h> /* for pt_regs */ #if defined(__sh3__) #define INTC_IPRA 0xfffffee2UL @@ -32,12 +33,24 @@ #define RTC_IPR_POS 0 #define RTC_PRIORITY TIMER_PRIORITY +#define DMTE0_IRQ 34 +#define DMTE1_IRQ 35 +#define DMTE2_IRQ 36 +#define DMTE3_IRQ 37 +#define DMAE_IRQ 38 +#define DMA_IPR_ADDR INTC_IPRC +#define DMA_IPR_POS 2 +#define DMA_PRIORITY 7 + +#if defined (CONFIG_CPU_SUBTYPE_SH7707) || defined (CONFIG_CPU_SUBTYPE_SH7708) || \ + defined (CONFIG_CPU_SUBTYPE_SH7709) || defined (CONFIG_CPU_SUBTYPE_SH7750) #define SCI_ERI_IRQ 23 #define SCI_RXI_IRQ 24 #define SCI_TXI_IRQ 25 #define SCI_IPR_ADDR INTC_IPRB #define SCI_IPR_POS 1 #define SCI_PRIORITY 3 +#endif #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) #define SCIF_ERI_IRQ 56 @@ -55,7 +68,7 @@ #define IRDA_IPR_ADDR INTC_IPRE #define IRDA_IPR_POS 2 #define IRDA_PRIORITY 3 -#elif defined(CONFIG_CPU_SUBTYPE_SH7750) +#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_ST40STB1) #define SCIF_ERI_IRQ 40 #define SCIF_RXI_IRQ 41 #define SCIF_BRI_IRQ 42 @@ -63,38 +76,87 @@ #define SCIF_IPR_ADDR INTC_IPRC #define SCIF_IPR_POS 1 #define SCIF_PRIORITY 3 +#if defined(CONFIG_CPU_SUBTYPE_ST40STB1) +#define SCIF1_ERI_IRQ 23 +#define SCIF1_RXI_IRQ 24 +#define SCIF1_BRI_IRQ 25 +#define SCIF1_TXI_IRQ 26 +#define SCIF1_IPR_ADDR INTC_IPRB +#define SCIF1_IPR_POS 1 +#define SCIF1_PRIORITY 3 +#endif #endif -#ifdef CONFIG_SH_GENERIC -/* In a generic kernel, NR_IRQS is an upper bound, and we should use - * ACTUAL_NR_IRQS (which uses the machine vector) to get the correct value. +/* NR_IRQS is made from three components: + * 1. ONCHIP_NR_IRQS - number of IRLS + on-chip peripherial modules + * 2. PINT_NR_IRQS - number of PINT interrupts + * 3. OFFCHIP_NR_IRQS - numbe of IRQs from off-chip peripherial modules */ -#define NR_IRQS 80 -#define ACTUAL_NR_IRQS (sh_mv.mv_nr_irqs) + +/* 1. ONCHIP_NR_IRQS */ +#ifdef CONFIG_SH_GENERIC +# define ONCHIP_NR_IRQS 89 #else -#if defined(__SH4__) -/* - * 48 = 32+16 - * - * 32 for on chip support modules. - * 16 for external interrupts. - * - */ -#define NR_IRQS 48 -#elif defined(CONFIG_CPU_SUBTYPE_SH7707) -#define NR_IRQS 64 -#elif defined(CONFIG_CPU_SUBTYPE_SH7708) -#define NR_IRQS 32 -#elif defined(CONFIG_CPU_SUBTYPE_SH7709) -#ifdef CONFIG_HD64461 -#define NR_IRQS 80 /* HD64461_IRQBASE+16, see hd64461.h */ +# if defined(CONFIG_CPU_SUBTYPE_SH7707) +# define ONCHIP_NR_IRQS 64 +# define PINT_NR_IRQS 16 +# elif defined(CONFIG_CPU_SUBTYPE_SH7708) +# define ONCHIP_NR_IRQS 32 +# elif defined(CONFIG_CPU_SUBTYPE_SH7709) +# define ONCHIP_NR_IRQS 64 // Actually 61 +# define PINT_NR_IRQS 16 +# elif defined(CONFIG_CPU_SUBTYPE_SH7750) +# define ONCHIP_NR_IRQS 48 // Actually 44 +# elif defined(CONFIG_CPU_SUBTYPE_ST40STB1) +# define ONCHIP_NR_IRQS 89 +# endif +#endif + +/* 2. PINT_NR_IRQS */ +#ifdef CONFIG_SH_GENERIC +# define PINT_NR_IRQS 16 #else -#define NR_IRQS 61 +# ifndef PINT_NR_IRQS +# define PINT_NR_IRQS 0 +# endif #endif + +#if PINT_NR_IRQS > 0 +# define PINT_IRQ_BASE ONCHIP_NR_IRQS #endif -#define ACTUAL_NR_IRQS NR_IRQS + +/* 3. OFFCHIP_NR_IRQS */ +#ifdef CONFIG_SH_GENERIC +# define OFFCHIP_NR_IRQS 16 +#else +# if defined(CONFIG_HD64461) +# define OFFCHIP_NR_IRQS 16 +# elif defined(CONFIG_HD64465) +# define OFFCHIP_NR_IRQS 16 +# elif defined (CONFIG_SH_EC3104) +# define OFFCHIP_NR_IRQS 16 +# else +# define OFFCHIP_NR_IRQS 0 +# endif #endif +#if OFFCHIP_NR_IRQS > 0 +# define OFFCHIP_IRQ_BASE (ONCHIP_NR_IRQS + PINT_NR_IRQS) +#endif + +/* NR_IRQS. 1+2+3 */ +#define NR_IRQS (ONCHIP_NR_IRQS + PINT_NR_IRQS + OFFCHIP_NR_IRQS) + +/* In a generic kernel, NR_IRQS is an upper bound, and we should use + * ACTUAL_NR_IRQS (which uses the machine vector) to get the correct value. + */ +#ifdef CONFIG_SH_GENERIC +# define ACTUAL_NR_IRQS (sh_mv.mv_nr_irqs) +#else +# define ACTUAL_NR_IRQS NR_IRQS +#endif + + extern void disable_irq(unsigned int); extern void disable_irq_nosync(unsigned int); extern void enable_irq(unsigned int); @@ -123,6 +185,15 @@ #define INTC_IPRF 0xa400001cUL #endif +#define PORT_PACR 0xa4000100UL +#define PORT_PBCR 0xa4000102UL +#define PORT_PCCR 0xa4000104UL +#define PORT_PFCR 0xa400010aUL +#define PORT_PADR 0xa4000120UL +#define PORT_PBDR 0xa4000122UL +#define PORT_PCDR 0xa4000124UL +#define PORT_PFDR 0xa400012aUL + #define IRQ0_IRQ 32 #define IRQ1_IRQ 33 #define IRQ2_IRQ 34 @@ -130,19 +201,19 @@ #define IRQ4_IRQ 36 #define IRQ5_IRQ 37 -#define IRQ0_IRP_ADDR INTC_IPRC -#define IRQ1_IRP_ADDR INTC_IPRC -#define IRQ2_IRP_ADDR INTC_IPRC -#define IRQ3_IRP_ADDR INTC_IPRC -#define IRQ4_IRP_ADDR INTC_IPRD -#define IRQ5_IRP_ADDR INTC_IPRD - -#define IRQ0_IRP_POS 0 -#define IRQ1_IRP_POS 1 -#define IRQ2_IRP_POS 2 -#define IRQ3_IRP_POS 3 -#define IRQ4_IRP_POS 0 -#define IRQ5_IRP_POS 1 +#define IRQ0_IPR_ADDR INTC_IPRC +#define IRQ1_IPR_ADDR INTC_IPRC +#define IRQ2_IPR_ADDR INTC_IPRC +#define IRQ3_IPR_ADDR INTC_IPRC +#define IRQ4_IPR_ADDR INTC_IPRD +#define IRQ5_IPR_ADDR INTC_IPRD + +#define IRQ0_IPR_POS 0 +#define IRQ1_IPR_POS 1 +#define IRQ2_IPR_POS 2 +#define IRQ3_IPR_POS 3 +#define IRQ4_IPR_POS 0 +#define IRQ5_IPR_POS 1 #define IRQ0_PRIORITY 1 #define IRQ1_PRIORITY 1 @@ -150,21 +221,77 @@ #define IRQ3_PRIORITY 1 #define IRQ4_PRIORITY 1 #define IRQ5_PRIORITY 1 -#endif -extern int hd64461_irq_demux(int irq); +#define PINT0_IRQ 40 +#define PINT8_IRQ 41 + +#define PINT0_IPR_ADDR INTC_IPRD +#define PINT8_IPR_ADDR INTC_IPRD + +#define PINT0_IPR_POS 3 +#define PINT8_IPR_POS 2 +#define PINT0_PRIORITY 2 +#define PINT8_PRIORITY 2 +extern int ipr_irq_demux(int irq); +#define __irq_demux(irq) ipr_irq_demux(irq) + +#else +#define __irq_demux(irq) irq +#endif /* CONFIG_CPU_SUBTYPE_SH7707 || CONFIG_CPU_SUBTYPE_SH7709 */ + +#ifdef CONFIG_CPU_SUBTYPE_ST40STB1 +#define INTC2_FIRST_IRQ 64 +#define NR_INTC2_IRQS 25 + +#define INTC2_BASE0 0xfe080000 +#define INTC2_INTC2MODE (INTC2_BASE0+0x80) + +#define INTC2_INTPRI_OFFSET 0x00 +#define INTC2_INTREQ_OFFSET 0x20 +#define INTC2_INTMSK_OFFSET 0x40 +#define INTC2_INTMSKCLR_OFFSET 0x60 + +extern void make_intc2_irq(unsigned int irq,unsigned int addr, + unsigned int group,int pos,int priority); + +#endif + #ifdef CONFIG_SH_GENERIC + extern __inline__ int irq_demux(int irq) { if (sh_mv.mv_irq_demux) { irq = sh_mv.mv_irq_demux(irq); } - return irq; + return __irq_demux(irq); } + #elif defined(CONFIG_HD64461) + +extern int hd64461_irq_demux(int irq); #define irq_demux(irq) hd64461_irq_demux(irq) + +#elif defined(CONFIG_HD64465) + +extern int hd64465_irq_demux(int irq); +#define irq_demux(irq) hd64465_irq_demux(irq) + +#elif defined(CONFIG_SH_EC3104) + +extern int ec3104_irq_demux(int irq); +#define irq_demux ec3104_irq_demux + +#elif defined(CONFIG_SH_CAT68701) + +extern int cat68701_irq_demux(int irq); +#define irq_demux cat68701_irq_demux + #else -#define irq_demux(irq) irq + +#define irq_demux(irq) __irq_demux(irq) + #endif + + #endif /* __ASM_SH_IRQ_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/keyboard-ec3104.h linux.ac/include/asm-sh/keyboard-ec3104.h --- linux.vanilla/include/asm-sh/keyboard-ec3104.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-sh/keyboard-ec3104.h Sat Apr 14 01:39:38 2001 @@ -0,0 +1,17 @@ +extern unsigned char ec3104_kbd_sysrq_xlate[]; +extern int ec3104_kbd_setkeycode(unsigned int scancode, unsigned int keycode); +extern int ec3104_kbd_getkeycode(unsigned int scancode); +extern int ec3104_kbd_translate(unsigned char, unsigned char *, char); +extern char ec3104_kbd_unexpected_up(unsigned char); +extern void ec3104_kbd_leds(unsigned char); +extern void ec3104_kbd_init_hw(void); + +#define SYSRQ_KEY 0x54 + +#define kbd_sysrq_xlate ec3104_kbd_sysrq_xlate +#define kbd_setkeycode ec3104_kbd_setkeycode +#define kbd_getkeycode ec3104_kbd_getkeycode +#define kbd_translate ec3104_kbd_translate +#define kbd_unexpected_up ec3104_kbd_unexpected_up +#define kbd_leds ec3104_kbd_leds +#define kbd_init_hw ec3104_kbd_init_hw diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/keyboard.h linux.ac/include/asm-sh/keyboard.h --- linux.vanilla/include/asm-sh/keyboard.h Wed Aug 9 21:59:04 2000 +++ linux.ac/include/asm-sh/keyboard.h Sat Apr 14 01:39:38 2001 @@ -4,8 +4,12 @@ * $Id: keyboard.h,v 1.1 2000/06/10 21:45:48 yaegashi Exp $ */ +#include <linux/config.h> #include <asm/machvec.h> +#ifdef CONFIG_SH_EC3104 +#include <asm/keyboard-ec3104.h> +#else static __inline__ int kbd_setkeycode(unsigned int scancode, unsigned int keycode) { @@ -34,6 +38,7 @@ } extern void hp600_kbd_init_hw(void); +extern void dreamcast_kbd_init_hw(void); static __inline__ void kbd_init_hw(void) { @@ -42,4 +47,5 @@ } } +#endif #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/linux_logo.h linux.ac/include/asm-sh/linux_logo.h --- linux.vanilla/include/asm-sh/linux_logo.h Tue Jun 20 01:59:38 2000 +++ linux.ac/include/asm-sh/linux_logo.h Tue Apr 3 17:55:16 2001 @@ -40,9 +40,6 @@ extern unsigned char linux_logo_blue[]; extern unsigned char linux_logo[]; extern unsigned char linux_logo_bw[]; -extern unsigned char linux_logo16_red[]; -extern unsigned char linux_logo16_green[]; -extern unsigned char linux_logo16_blue[]; extern unsigned char linux_logo16[]; #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/machvec.h linux.ac/include/asm-sh/machvec.h --- linux.vanilla/include/asm-sh/machvec.h Wed Aug 9 21:59:04 2000 +++ linux.ac/include/asm-sh/machvec.h Sat Apr 14 01:39:38 2001 @@ -13,45 +13,45 @@ #include <linux/config.h> #include <linux/types.h> +struct timeval; + struct sh_machine_vector { const char *mv_name; int mv_nr_irqs; - unsigned long (*mv_inb)(unsigned int); - unsigned long (*mv_inw)(unsigned int); - unsigned long (*mv_inl)(unsigned int); - void (*mv_outb)(unsigned long, unsigned int); - void (*mv_outw)(unsigned long, unsigned int); - void (*mv_outl)(unsigned long, unsigned int); - - unsigned long (*mv_inb_p)(unsigned int); - unsigned long (*mv_inw_p)(unsigned int); - unsigned long (*mv_inl_p)(unsigned int); - void (*mv_outb_p)(unsigned long, unsigned int); - void (*mv_outw_p)(unsigned long, unsigned int); - void (*mv_outl_p)(unsigned long, unsigned int); - - void (*mv_insb)(unsigned int port, void *addr, unsigned long count); - void (*mv_insw)(unsigned int port, void *addr, unsigned long count); - void (*mv_insl)(unsigned int port, void *addr, unsigned long count); - void (*mv_outsb)(unsigned int port, const void *addr, unsigned long count); - void (*mv_outsw)(unsigned int port, const void *addr, unsigned long count); - void (*mv_outsl)(unsigned int port, const void *addr, unsigned long count); - - unsigned long (*mv_readb)(unsigned long); - unsigned long (*mv_readw)(unsigned long); - unsigned long (*mv_readl)(unsigned long); + unsigned char (*mv_inb)(unsigned long); + unsigned short (*mv_inw)(unsigned long); + unsigned int (*mv_inl)(unsigned long); + void (*mv_outb)(unsigned char, unsigned long); + void (*mv_outw)(unsigned short, unsigned long); + void (*mv_outl)(unsigned int, unsigned long); + + unsigned char (*mv_inb_p)(unsigned long); + unsigned short (*mv_inw_p)(unsigned long); + unsigned int (*mv_inl_p)(unsigned long); + void (*mv_outb_p)(unsigned char, unsigned long); + void (*mv_outw_p)(unsigned short, unsigned long); + void (*mv_outl_p)(unsigned int, unsigned long); + + void (*mv_insb)(unsigned long port, void *addr, unsigned long count); + void (*mv_insw)(unsigned long port, void *addr, unsigned long count); + void (*mv_insl)(unsigned long port, void *addr, unsigned long count); + void (*mv_outsb)(unsigned long port, const void *addr, unsigned long count); + void (*mv_outsw)(unsigned long port, const void *addr, unsigned long count); + void (*mv_outsl)(unsigned long port, const void *addr, unsigned long count); + + unsigned char (*mv_readb)(unsigned long); + unsigned short (*mv_readw)(unsigned long); + unsigned int (*mv_readl)(unsigned long); void (*mv_writeb)(unsigned char, unsigned long); void (*mv_writew)(unsigned short, unsigned long); void (*mv_writel)(unsigned int, unsigned long); void* (*mv_ioremap)(unsigned long offset, unsigned long size); - void* (*mv_ioremap_nocache)(unsigned long offset, unsigned long size); void (*mv_iounmap)(void *addr); - unsigned long (*mv_port2addr)(unsigned long offset); unsigned long (*mv_isa_port2addr)(unsigned long offset); int (*mv_irq_demux)(int irq); @@ -63,9 +63,17 @@ void (*mv_heartbeat)(void); + void (*mv_rtc_gettimeofday)(struct timeval *tv); + int (*mv_rtc_settimeofday)(const struct timeval *tv); + unsigned int mv_hw_se : 1; unsigned int mv_hw_hp600 : 1; + unsigned int mv_hw_hp620 : 1; + unsigned int mv_hw_hp680 : 1; + unsigned int mv_hw_hp690 : 1; unsigned int mv_hw_hd64461 : 1; + unsigned int mv_hw_hd64465 : 1; + unsigned int mv_hw_dreamcast : 1; }; extern struct sh_machine_vector sh_mv; @@ -74,7 +82,12 @@ #ifdef CONFIG_SH_GENERIC #define MACH_SE (sh_mv.mv_hw_se) #define MACH_HP600 (sh_mv.mv_hw_hp600) +#define MACH_HP620 (sh_mv.mv_hw_hp620) +#define MACH_HP680 (sh_mv.mv_hw_hp680) +#define MACH_HP690 (sh_mv.mv_hw_hp690) #define MACH_HD64461 (sh_mv.mv_hw_hd64461) +#define MACH_HD64465 (sh_mv.mv_hw_hd64465) +#define MACH_DREAMCAST (sh_mv.mv_hw_dreamcast) #else # ifdef CONFIG_SH_SOLUTION_ENGINE # define MACH_SE 1 @@ -86,10 +99,40 @@ # else # define MACH_HP600 0 # endif +# ifdef CONFIG_SH_HP620 +# define MACH_HP620 1 +# else +# define MACH_HP620 0 +# endif +# ifdef CONFIG_SH_HP680 +# define MACH_HP680 1 +# else +# define MACH_HP680 0 +# endif +# ifdef CONFIG_SH_HP690 +# define MACH_HP690 1 +# else +# define MACH_HP690 0 +# endif # ifdef CONFIG_HD64461 # define MACH_HD64461 1 # else # define MACH_HD64461 0 +# endif +# ifdef CONFIG_HD64465 +# define MACH_HD64465 1 +# else +# define MACH_HD64465 0 +# endif +# ifdef CONFIG_SH_EC3104 +# define MACH_EC3104 1 +# else +# define MACH_EC3104 0 +# endif +# ifdef CONFIG_SH_DREAMCAST +# define MACH_DREAMCAST 1 +# else +# define MACH_DREAMCAST 0 # endif #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/pci.h linux.ac/include/asm-sh/pci.h --- linux.vanilla/include/asm-sh/pci.h Mon Oct 2 19:57:34 2000 +++ linux.ac/include/asm-sh/pci.h Sat Apr 14 01:39:38 2001 @@ -7,13 +7,13 @@ already-configured bus numbers - to be used for buggy BIOSes or architectures with incomplete PCI setup by the loader */ -#define pcibios_assign_all_busses() 0 +#define pcibios_assign_all_busses() 1 /* These are currently the correct values for the STM overdrive board. * We need some way of setting this on a board specific way, it will * not be the same on other boards I think */ -#if 1 /* def CONFIG_SH_OVERDRIVE */ +#if 1 /* def CONFIG_SH_7750_OVERDRIVE || def CONFIG_CPU_SUBTYPE_ST40STB1 */ #define PCIBIOS_MIN_IO 0x2000 #define PCIBIOS_MIN_MEM 0x10000000 #endif @@ -70,6 +70,8 @@ static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size,int directoin) { + + flush_cache_all(); return virt_to_bus(ptr); } @@ -104,6 +106,7 @@ static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,int direction) { + flush_cache_all(); return nents; } @@ -145,6 +148,19 @@ { /* Nothing to do */ } + + +/* Return whether the given PCI device DMA address mask can + * be supported properly. For example, if your device can + * only drive the low 24-bits during PCI bus mastering, then + * you would pass 0x00ffffff as the mask to this function. + */ +extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +{ + return 1; +} + + /* These macros should be used after a pci_map_sg call has been done * to get bus addresses of each of the SG entries and their lengths. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/pgalloc-2level.h linux.ac/include/asm-sh/pgalloc-2level.h --- linux.vanilla/include/asm-sh/pgalloc-2level.h Fri Oct 13 20:06:52 2000 +++ linux.ac/include/asm-sh/pgalloc-2level.h Thu Jan 1 01:00:00 1970 @@ -1,23 +0,0 @@ -#ifndef __ASM_SH_PGALLOC_2LEVEL_H -#define __ASM_SH_PGALLOC_2LEVEL_H - -/* - * traditional two-level paging, page table allocation routines: - */ - -static __inline__ pmd_t *get_pmd_fast(void) -{ - return (pmd_t *)0; -} - -static __inline__ void free_pmd_fast(pmd_t *pmd) { } -static __inline__ void free_pmd_slow(pmd_t *pmd) { } - -static __inline__ pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address) -{ - if (!pgd) - BUG(); - return (pmd_t *) pgd; -} - -#endif /* __ASM_SH_PGALLOC_2LEVEL_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/pgalloc.h linux.ac/include/asm-sh/pgalloc.h --- linux.vanilla/include/asm-sh/pgalloc.h Fri Oct 13 20:06:52 2000 +++ linux.ac/include/asm-sh/pgalloc.h Sat Apr 14 01:39:38 2001 @@ -10,23 +10,22 @@ #define pte_quicklist (current_cpu_data.pte_quick) #define pgtable_cache_size (current_cpu_data.pgtable_cache_sz) -#include <asm/pgalloc-2level.h> +#define pmd_populate(mm, pmd, pte) \ + set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))) /* - * Allocate and free page tables. The xxx_kernel() versions are - * used to allocate a kernel page table - this turns on ASN bits - * if any. + * Allocate and free page tables. */ static __inline__ pgd_t *get_pgd_slow(void) { unsigned int pgd_size = (USER_PTRS_PER_PGD * sizeof(pgd_t)); - pgd_t *ret = (pgd_t *)kmalloc(pgd_size, GFP_KERNEL); + pgd_t *pgd = (pgd_t *)kmalloc(pgd_size, GFP_KERNEL); - if (ret) - memset(ret, 0, pgd_size); + if (pgd) + memset(pgd, 0, pgd_size); - return ret; + return pgd; } static __inline__ pgd_t *get_pgd_fast(void) @@ -54,14 +53,21 @@ kfree(pgd); } -extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted); -extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted); +static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pte_t *pte; + + pte = (pte_t *) __get_free_page(GFP_KERNEL); + if (pte) + clear_page(pte); + return pte; +} -static __inline__ pte_t *get_pte_fast(void) +static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) { unsigned long *ret; - if((ret = (unsigned long *)pte_quicklist) != NULL) { + if ((ret = (unsigned long *)pte_quicklist) != NULL) { pte_quicklist = (unsigned long *)(*ret); ret[0] = ret[1]; pgtable_cache_size--; @@ -69,65 +75,21 @@ return (pte_t *)ret; } -static __inline__ void free_pte_fast(pte_t *pte) +static __inline__ void pte_free_fast(pte_t *pte) { *(unsigned long *)pte = (unsigned long) pte_quicklist; pte_quicklist = (unsigned long *) pte; pgtable_cache_size++; } -static __inline__ void free_pte_slow(pte_t *pte) +static __inline__ void pte_free_slow(pte_t *pte) { free_page((unsigned long)pte); } -#define pte_free_kernel(pte) free_pte_slow(pte) -#define pte_free(pte) free_pte_slow(pte) -#define pgd_free(pgd) free_pgd_slow(pgd) -#define pgd_alloc() get_pgd_fast() - -static __inline__ pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address) -{ - if (!pmd) - BUG(); - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - pte_t * page = (pte_t *) get_pte_fast(); - - if (!page) - return get_pte_kernel_slow(pmd, address); - set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(page))); - return page + address; - } - if (pmd_bad(*pmd)) { - __handle_bad_pmd_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + address; -} - -static __inline__ pte_t * pte_alloc(pmd_t * pmd, unsigned long address) -{ - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - - if (pmd_none(*pmd)) - goto getnew; - if (pmd_bad(*pmd)) - goto fix; - return (pte_t *)pmd_page(*pmd) + address; -getnew: -{ - unsigned long page = (unsigned long) get_pte_fast(); - - if (!page) - return get_pte_slow(pmd, address); - set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(page))); - return (pte_t *)page + address; -} -fix: - __handle_bad_pmd(pmd); - return NULL; -} +#define pte_free(pte) pte_free_slow(pte) +#define pgd_free(pgd) free_pgd_slow(pgd) +#define pgd_alloc() get_pgd_fast() /* * allocating and freeing a pmd is trivial: the 1-entry pmd is @@ -137,8 +99,12 @@ { } -#define pmd_free_kernel pmd_free -#define pmd_alloc_kernel pmd_alloc +#define pmd_alloc_one_fast(mm, addr) ({ BUG(); ((pmd_t *)1); }) +#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); }) +#define pmd_free_slow(x) do { } while (0) +#define pmd_free_fast(x) do { } while (0) +#define pmd_free(x) do { } while (0) +#define pgd_populate(mm, pmd, pte) BUG() extern int do_check_pgt_cache(int, int); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/pgtable-2level.h linux.ac/include/asm-sh/pgtable-2level.h --- linux.vanilla/include/asm-sh/pgtable-2level.h Thu Jan 4 21:19:13 2001 +++ linux.ac/include/asm-sh/pgtable-2level.h Sat Apr 14 01:39:38 2001 @@ -32,7 +32,7 @@ static inline int pgd_none(pgd_t pgd) { return 0; } static inline int pgd_bad(pgd_t pgd) { return 0; } static inline int pgd_present(pgd_t pgd) { return 1; } -#define pgd_clear(xp) do { } while (0) +static inline void pgd_clear (pgd_t * pgd) { } /* * Certain architectures need to do special things when PTEs diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/pgtable.h linux.ac/include/asm-sh/pgtable.h --- linux.vanilla/include/asm-sh/pgtable.h Mon Jan 29 02:56:00 2001 +++ linux.ac/include/asm-sh/pgtable.h Sat Apr 14 01:39:38 2001 @@ -166,12 +166,6 @@ #define __S110 PAGE_SHARED #define __S111 PAGE_SHARED -/* - * Handling allocation failures during page table setup. - */ -extern void __handle_bad_pmd(pmd_t * pmd); -extern void __handle_bad_pmd_kernel(pmd_t * pmd); - #define pte_none(x) (!pte_val(x)) #define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE)) #define pte_clear(xp) do { set_pte(xp, __pte(0)); } while (0) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/processor.h linux.ac/include/asm-sh/processor.h --- linux.vanilla/include/asm-sh/processor.h Thu Jan 4 21:19:13 2001 +++ linux.ac/include/asm-sh/processor.h Sat Apr 14 01:39:38 2001 @@ -24,6 +24,7 @@ CPU_SH7708, /* Represents 7707, 7708, 7708S, 7708R, 7709 */ CPU_SH7729, /* Represents 7709A, 7729 */ CPU_SH7750, + CPU_ST40STB1, CPU_SH_NONE }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/semaphore.h linux.ac/include/asm-sh/semaphore.h --- linux.vanilla/include/asm-sh/semaphore.h Sun Mar 5 17:33:55 2000 +++ linux.ac/include/asm-sh/semaphore.h Tue Apr 3 17:55:16 2001 @@ -13,7 +13,7 @@ */ #include <linux/spinlock.h> - +#include <linux/wait.h> #include <asm/system.h> #include <asm/atomic.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/serial-ec3104.h linux.ac/include/asm-sh/serial-ec3104.h --- linux.vanilla/include/asm-sh/serial-ec3104.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-sh/serial-ec3104.h Sat Apr 14 01:39:38 2001 @@ -0,0 +1,24 @@ +#include <asm/ec3104.h> +/* Naturally we don't know the exact value but 115200 baud has a divisor + * of 9 and 19200 baud has a divisor of 52, so this seems like a good + * guess. */ +#define BASE_BAUD (16800000 / 16) + +#define RS_TABLE_SIZE 3 + +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) + +/* there is a fourth serial port with the expected values as well, but + * it's got the keyboard controller behind it so we can't really use it + * (without moving the keyboard driver to userspace, which doesn't sound + * like a very good idea) */ +#define STD_SERIAL_PORT_DEFNS \ + /* UART CLK PORT IRQ FLAGS */ \ + { 0, BASE_BAUD, 0x11C00, EC3104_IRQBASE+7, STD_COM_FLAGS }, /* ttyS0 */ \ + { 0, BASE_BAUD, 0x12000, EC3104_IRQBASE+8, STD_COM_FLAGS }, /* ttyS1 */ \ + { 0, BASE_BAUD, 0x12400, EC3104_IRQBASE+9, STD_COM_FLAGS }, /* ttyS2 */ + +#define SERIAL_PORT_DFNS STD_SERIAL_PORT_DEFNS + +/* XXX: This should be moved ino irq.h */ +#define irq_cannonicalize(x) (x) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/serial.h linux.ac/include/asm-sh/serial.h --- linux.vanilla/include/asm-sh/serial.h Sat Jul 22 15:42:06 2000 +++ linux.ac/include/asm-sh/serial.h Sat Apr 14 01:39:51 2001 @@ -7,6 +7,13 @@ #ifndef _ASM_SERIAL_H #define _ASM_SERIAL_H +#include <linux/config.h> +#include <linux/kernel.h> + +#ifdef CONFIG_SH_EC3104 +#include <asm/serial-ec3104.h> +#else + /* * This assumes you have a 1.8432 MHz clock for your UART. * @@ -16,18 +23,32 @@ */ #define BASE_BAUD ( 1843200 / 16 ) -#define RS_TABLE_SIZE 2 - #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) +#ifdef CONFIG_HD64465 +#include <asm/hd64465.h> + +#define RS_TABLE_SIZE 1 + +#define STD_SERIAL_PORT_DEFNS \ + /* UART CLK PORT IRQ FLAGS */ \ + { 0, BASE_BAUD, 0x3F8, HD64465_IRQ_UART, STD_COM_FLAGS } /* ttyS0 */ + +#else + +#define RS_TABLE_SIZE 2 + #define STD_SERIAL_PORT_DEFNS \ /* UART CLK PORT IRQ FLAGS */ \ { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \ { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS } /* ttyS1 */ +#endif + #define SERIAL_PORT_DFNS STD_SERIAL_PORT_DEFNS /* XXX: This should be moved ino irq.h */ #define irq_cannonicalize(x) (x) +#endif #endif /* _ASM_SERIAL_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/sigcontext.h linux.ac/include/asm-sh/sigcontext.h --- linux.vanilla/include/asm-sh/sigcontext.h Mon Apr 24 21:54:17 2000 +++ linux.ac/include/asm-sh/sigcontext.h Sat Apr 14 01:39:51 2001 @@ -16,7 +16,7 @@ #if defined(__SH4__) /* FPU registers */ unsigned long sc_fpregs[16]; - unsigned long long sc_xdregs[8]; + unsigned long sc_xfpregs[16]; unsigned int sc_fpscr; unsigned int sc_fpul; unsigned int sc_ownedfp; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sh/tlb.h linux.ac/include/asm-sh/tlb.h --- linux.vanilla/include/asm-sh/tlb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-sh/tlb.h Tue Apr 3 17:55:16 2001 @@ -0,0 +1 @@ +#include <asm-generic/tlb.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc/hardirq.h linux.ac/include/asm-sparc/hardirq.h --- linux.vanilla/include/asm-sparc/hardirq.h Tue Aug 29 05:20:03 2000 +++ linux.ac/include/asm-sparc/hardirq.h Tue Apr 3 17:55:16 2001 @@ -1,7 +1,7 @@ /* hardirq.h: 32-bit Sparc hard IRQ support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1998-2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 1998-2000 Anton Blanchard (anton@samba.org) */ #ifndef __SPARC_HARDIRQ_H diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc/ioctls.h linux.ac/include/asm-sparc/ioctls.h --- linux.vanilla/include/asm-sparc/ioctls.h Sun Oct 4 18:22:44 1998 +++ linux.ac/include/asm-sparc/ioctls.h Tue Apr 3 17:55:16 2001 @@ -86,6 +86,7 @@ #define FIONBIO _IOW('f', 126, int) #define FIONREAD _IOR('f', 127, int) #define TIOCINQ FIONREAD +#define FIOQSIZE _IOR('f', 128, loff_t) /* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it * someday. This is completely bogus, I know... diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc/kmap_types.h linux.ac/include/asm-sparc/kmap_types.h --- linux.vanilla/include/asm-sparc/kmap_types.h Sat Aug 5 02:16:11 2000 +++ linux.ac/include/asm-sparc/kmap_types.h Sat Apr 14 01:39:56 2001 @@ -4,6 +4,8 @@ enum km_type { KM_BOUNCE_READ, KM_BOUNCE_WRITE, + KM_SKB_DATA, + KM_SKB_DATA_SOFTIRQ, KM_TYPE_NR }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc/linux_logo.h linux.ac/include/asm-sparc/linux_logo.h --- linux.vanilla/include/asm-sparc/linux_logo.h Wed Sep 30 22:16:33 1998 +++ linux.ac/include/asm-sparc/linux_logo.h Tue Apr 3 17:55:16 2001 @@ -1026,9 +1026,6 @@ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; -unsigned char linux_logo16_red[1]; -unsigned char linux_logo16_green[1]; -unsigned char linux_logo16_blue[1]; unsigned char linux_logo16[1]; #else @@ -1039,9 +1036,6 @@ extern unsigned char linux_logo_blue[]; extern unsigned char linux_logo[]; extern unsigned char linux_logo_bw[]; -extern unsigned char linux_logo16_red[]; -extern unsigned char linux_logo16_green[]; -extern unsigned char linux_logo16_blue[]; extern unsigned char linux_logo16[]; #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc/perfctr.h linux.ac/include/asm-sparc/perfctr.h --- linux.vanilla/include/asm-sparc/perfctr.h Tue Oct 27 17:52:21 1998 +++ linux.ac/include/asm-sparc/perfctr.h Sat Apr 14 01:40:08 2001 @@ -60,10 +60,10 @@ #ifndef __KERNEL__ #define PRIV 0x00000001 -#define USR 0x00000002 -#define SYS 0x00000004 +#define SYS 0x00000002 +#define USR 0x00000004 -/* Pic.S0 Selection Bit Field Encoding */ +/* Pic.S0 Selection Bit Field Encoding, Ultra-I/II */ #define CYCLE_CNT 0x00000000 #define INSTR_CNT 0x00000010 #define DISPATCH0_IC_MISS 0x00000020 @@ -77,7 +77,38 @@ #define EC_SNOOP_INV 0x000000E0 #define EC_RD_HIT 0x000000F0 -/* Pic.S1 Selection Bit Field Encoding */ +/* Pic.S0 Selection Bit Field Encoding, Ultra-III */ +#define US3_CYCLE_CNT 0x00000000 +#define US3_INSTR_CNT 0x00000010 +#define US3_DISPATCH0_IC_MISS 0x00000020 +#define US3_DISPATCH0_BR_TGT 0x00000030 +#define US3_DISPATCH0_2ND_BR 0x00000040 +#define US3_RSTALL_STOREQ 0x00000050 +#define US3_RSTALL_IU_USE 0x00000060 +#define US3_IC_REF 0x00000080 +#define US3_DC_RD 0x00000090 +#define US3_DC_WR 0x000000a0 +#define US3_EC_REF 0x000000c0 +#define US3_EC_WR_HIT_RTO 0x000000d0 +#define US3_EC_SNOOP_INV 0x000000e0 +#define US3_EC_RD_MISS 0x000000f0 +#define US3_PC_PORT0_RD 0x00000100 +#define US3_SI_SNOOP 0x00000110 +#define US3_SI_CIQ_FLOW 0x00000120 +#define US3_SI_OWNED 0x00000130 +#define US3_SW_COUNT_0 0x00000140 +#define US3_IU_BR_MISS_TAKEN 0x00000150 +#define US3_IU_BR_COUNT_TAKEN 0x00000160 +#define US3_DISP_RS_MISPRED 0x00000170 +#define US3_FA_PIPE_COMPL 0x00000180 +#define US3_MC_READS_0 0x00000200 +#define US3_MC_READS_1 0x00000210 +#define US3_MC_READS_2 0x00000220 +#define US3_MC_READS_3 0x00000230 +#define US3_MC_STALLS_0 0x00000240 +#define US3_MC_STALLS_2 0x00000250 + +/* Pic.S1 Selection Bit Field Encoding, Ultra-I/II */ #define CYCLE_CNT_D1 0x00000000 #define INSTR_CNT_D1 0x00000800 #define DISPATCH0_IC_MISPRED 0x00001000 @@ -90,6 +121,47 @@ #define EC_WB 0x00006800 #define EC_SNOOP_CB 0x00007000 #define EC_IT_HIT 0x00007800 + +/* Pic.S1 Selection Bit Field Encoding, Ultra-III */ +#define US3_CYCLE_CNT_D1 0x00000000 +#define US3_INSTR_CNT_D1 0x00000800 +#define US3_DISPATCH0_MISPRED 0x00001000 +#define US3_IC_MISS_CANCELLED 0x00001800 +#define US3_RE_ENDIAN_MISS 0x00002000 +#define US3_RE_FPU_BYPASS 0x00002800 +#define US3_RE_DC_MISS 0x00003000 +#define US3_RE_EC_MISS 0x00003800 +#define US3_IC_MISS 0x00004000 +#define US3_DC_RD_MISS 0x00004800 +#define US3_DC_WR_MISS 0x00005000 +#define US3_RSTALL_FP_USE 0x00005800 +#define US3_EC_MISSES 0x00006000 +#define US3_EC_WB 0x00006800 +#define US3_EC_SNOOP_CB 0x00007000 +#define US3_EC_IC_MISS 0x00007800 +#define US3_RE_PC_MISS 0x00008000 +#define US3_ITLB_MISS 0x00008800 +#define US3_DTLB_MISS 0x00009000 +#define US3_WC_MISS 0x00009800 +#define US3_WC_SNOOP_CB 0x0000a000 +#define US3_WC_SCRUBBED 0x0000a800 +#define US3_WC_WB_WO_READ 0x0000b000 +#define US3_PC_SOFT_HIT 0x0000c000 +#define US3_PC_SNOOP_INV 0x0000c800 +#define US3_PC_HARD_HIT 0x0000d000 +#define US3_PC_PORT1_RD 0x0000d800 +#define US3_SW_COUNT_1 0x0000e000 +#define US3_IU_STAT_BR_MIS_UNTAKEN 0x0000e800 +#define US3_IU_STAT_BR_COUNT_UNTAKEN 0x0000f000 +#define US3_PC_MS_MISSES 0x0000f800 +#define US3_MC_WRITES_0 0x00010800 +#define US3_MC_WRITES_1 0x00011000 +#define US3_MC_WRITES_2 0x00011800 +#define US3_MC_WRITES_3 0x00012000 +#define US3_MC_STALLS_1 0x00012800 +#define US3_MC_STALLS_3 0x00013000 +#define US3_RE_RAW_MISS 0x00013800 +#define US3_FM_PIPE_COMPLETION 0x00014000 struct vcounter_struct { unsigned long long vcnt0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc/processor.h linux.ac/include/asm-sparc/processor.h --- linux.vanilla/include/asm-sparc/processor.h Mon Jan 1 18:37:41 2001 +++ linux.ac/include/asm-sparc/processor.h Sat Apr 14 01:40:08 2001 @@ -1,4 +1,4 @@ -/* $Id: processor.h,v 1.80 2000/12/31 10:05:43 davem Exp $ +/* $Id: processor.h,v 1.81 2001/03/27 02:36:37 davem Exp $ * include/asm-sparc/processor.h * * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) @@ -90,7 +90,6 @@ #define SPARC_FLAG_KTHREAD 0x1 /* task is a kernel thread */ #define SPARC_FLAG_UNALIGNED 0x2 /* is allowed to do unaligned accesses */ -#define SPARC_FLAG_MMAPSHARED 0x4 /* task wants a shared mmap */ #define INIT_MMAP { &init_mm, (0), (0), \ NULL, __pgprot(0x0) , VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc/tlb.h linux.ac/include/asm-sparc/tlb.h --- linux.vanilla/include/asm-sparc/tlb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-sparc/tlb.h Tue Apr 3 17:55:16 2001 @@ -0,0 +1 @@ +#include <asm-generic/tlb.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc/vaddrs.h linux.ac/include/asm-sparc/vaddrs.h --- linux.vanilla/include/asm-sparc/vaddrs.h Sat Aug 5 02:16:11 2000 +++ linux.ac/include/asm-sparc/vaddrs.h Tue Apr 3 17:55:16 2001 @@ -9,7 +9,7 @@ * which important things will be mapped. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 2000 Anton Blanchard (anton@samba.org) */ #define SRMMU_MAXMEM 0x0c000000 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/asi.h linux.ac/include/asm-sparc64/asi.h --- linux.vanilla/include/asm-sparc64/asi.h Tue Apr 3 17:32:28 2001 +++ linux.ac/include/asm-sparc64/asi.h Sat Apr 14 01:40:15 2001 @@ -1,4 +1,4 @@ -/* $Id: asi.h,v 1.4 2001/03/15 02:08:46 davem Exp $ */ +/* $Id: asi.h,v 1.5 2001/03/29 11:47:47 davem Exp $ */ #ifndef _SPARC64_ASI_H #define _SPARC64_ASI_H @@ -80,6 +80,7 @@ #define ASI_BRPRED_ARRAY 0x6f /* (III) Branch Prediction RAM diag */ #define ASI_BLK_AIUP 0x70 /* Primary, user, block load/store */ #define ASI_BLK_AIUS 0x71 /* Secondary, user, block load/store */ +#define ASI_MCU_CTRL_REG 0x72 /* (III) Memory controller registers */ #define ASI_EC_DATA 0x74 /* (III) E-cache data staging register */ #define ASI_EC_CTRL 0x75 /* (III) E-cache control register */ #define ASI_EC_W 0x76 /* E-cache diag write access */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/bbc.h linux.ac/include/asm-sparc64/bbc.h --- linux.vanilla/include/asm-sparc64/bbc.h Tue Apr 3 17:32:28 2001 +++ linux.ac/include/asm-sparc64/bbc.h Sat Apr 14 01:40:15 2001 @@ -1,4 +1,4 @@ -/* $Id: bbc.h,v 1.1 2001/03/24 06:03:03 davem Exp $ +/* $Id: bbc.h,v 1.2 2001/03/26 23:47:18 davem Exp $ * bbc.h: Defines for BootBus Controller found on UltraSPARC-III * systems. * @@ -89,7 +89,7 @@ * is asserted can be controlled by this regiser. */ #define BBC_WDACTION_RST 0x01 /* When set, watchdog causes system reset. - * When clear, all cpus receive XIR reset. + * When clear, BBC ignores watchdog signal. */ #define BBC_WDACTION_RESV 0xfe /* Reserved */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/chafsr.h linux.ac/include/asm-sparc64/chafsr.h --- linux.vanilla/include/asm-sparc64/chafsr.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-sparc64/chafsr.h Sat Apr 14 01:40:15 2001 @@ -0,0 +1,150 @@ +/* $Id: chafsr.h,v 1.1 2001/03/28 10:56:34 davem Exp $ */ +#ifndef _SPARC64_CHAFSR_H +#define _SPARC64_CHAFSR_H + +/* Cheetah Asynchronous Fault Status register, ASI=0x4C VA<63:0>=0x0 */ + +/* All bits of this register except M_SYNDROME and E_SYNDROME are + * read, write 1 to clear. M_SYNDROME and E_SYNDROME are read-only. + */ + +/* Multiple errors of the same type have occurred. This bit is set when + * an uncorrectable error or a SW correctable error occurs and the status + * bit to report that error is already set. When multiple errors of + * different types are indicated by setting multiple status bits. + * + * This bit is not set if multiple HW corrected errors with the same + * status bit occur, only uncorrectable and SW correctable ones have + * this behavior. + * + * This bit is not set when multiple ECC errors happen within a single + * 64-byte system bus transaction. Only the first ECC error in a 16-byte + * subunit will be logged. All errors in subsequent 16-byte subunits + * from the same 64-byte transaction are ignored. + */ +#define CHAFSR_ME 0x0020000000000000 + +/* Privileged state error has occurred. This is a capture of PSTATE.PRIV + * at the time the error is detected. + */ +#define CHAFSR_PRIV 0x0010000000000000 + +/* The following bits 51 (CHAFSR_PERR) to 33 (CHAFSR_CE) are sticky error + * bits and record the most recently detected errors. Bits accumulate + * errors that have been detected since the last write to clear the bit. + */ + +/* System interface protocol error. The processor asserts its' ERROR + * pin when this event occurs and it also logs a specific cause code + * into a JTAG scannable flop. + */ +#define CHAFSR_PERR 0x0008000000000000 + +/* Internal processor error. The processor asserts its' ERROR + * pin when this event occurs and it also logs a specific cause code + * into a JTAG scannable flop. + */ +#define CHAFSR_IERR 0x0004000000000000 + +/* System request parity error on incoming address */ +#define CHAFSR_ISAP 0x0002000000000000 + +/* HW Corrected system bus MTAG ECC error */ +#define CHAFSR_EMC 0x0001000000000000 + +/* Uncorrectable system bus MTAG ECC error */ +#define CHAFSR_EMU 0x0000800000000000 + +/* HW Corrected system bus data ECC error for read of interrupt vector */ +#define CHAFSR_IVC 0x0000400000000000 + +/* Uncorrectable system bus data ECC error for read of interrupt vector */ +#define CHAFSR_IVU 0x0000200000000000 + +/* Unmappeed error from system bus */ +#define CHAFSR_TO 0x0000100000000000 + +/* Bus error response from system bus */ +#define CHAFSR_BERR 0x0000080000000000 + +/* SW Correctable E-cache ECC error for instruction fetch or data access + * other than block load. + */ +#define CHAFSR_UCC 0x0000040000000000 + +/* Uncorrectable E-cache ECC error for instruction fetch or data access + * other than block load. + */ +#define CHAFSR_UCU 0x0000020000000000 + +/* Copyout HW Corrected ECC error */ +#define CHAFSR_CPC 0x0000010000000000 + +/* Copyout Uncorrectable ECC error */ +#define CHAFSR_CPU 0x0000008000000000 + +/* HW Corrected ECC error from E-cache for writeback */ +#define CHAFSR_WDC 0x0000004000000000 + +/* Uncorrectable ECC error from E-cache for writeback */ +#define CHAFSR_WDU 0x0000002000000000 + +/* HW Corrected ECC error from E-cache for store merge or block load */ +#define CHAFSR_EDC 0x0000001000000000 + +/* Uncorrectable ECC error from E-cache for store merge or block load */ +#define CHAFSR_EDU 0x0000000800000000 + +/* Uncorrectable system bus data ECC error for read of memory or I/O */ +#define CHAFSR_UE 0x0000000400000000 + +/* HW Corrected system bus data ECC error for read of memory or I/O */ +#define CHAFSR_CE 0x0000000200000000 + +#define CHAFSR_ERRORS (CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP | CHAFSR_EMC | \ + CHAFSR_EMU | CHAFSR_IVC | CHAFSR_IVU | CHAFSR_TO | \ + CHAFSR_BERR | CHAFSR_UCC | CHAFSR_UCU | CHAFSR_CPC | \ + CHAFSR_CPU | CHAFSR_WDC | CHAFSR_WDU | CHAFSR_EDC | \ + CHAFSR_EDU | CHAFSR_UE | CHAFSR_CE) + +/* System bus MTAG ECC syndrome. This field captures the status of the + * first occurrence of the highest-priority error according to the M_SYND + * overwrite policy. After the AFSR sticky bit, corresponding to the error + * for which the M_SYND is reported, is cleared, the contents of the M_SYND + * field will be unchanged by will be unfrozen for further error capture. + */ +#define CHAFSR_M_SYNDROME 0x00000000000f0000 +#define CHAFSR_M_SYNDROME_SHIFT 16 + +/* System bus or E-cache data ECC syndrome. This field captures the status + * of the first occurrence of the highest-priority error according to the + * E_SYND overwrite policy. After the AFSR sticky bit, corresponding to the + * error for which the E_SYND is reported, is cleare, the contents of the E_SYND + * field will be unchanged but will be unfrozen for further error capture. + */ +#define CHAFSR_E_SYNDROME 0x00000000000001ff +#define CHAFSR_E_SYNDROME_SHIFT 0 + +/* The AFSR must be explicitly cleared by software, it is not cleared automatically + * by a read. Writes to bits <51:33> with bits set will clear the corresponding + * bits in the AFSR. Bits assosciated with disrupting traps must be cleared before + * interrupts are re-enabled to prevent multiple traps for the same error. I.e. + * PSTATE.IE and AFSR bits control delivery of disrupting traps. + * + * Since there is only one AFAR, when multiple events have been logged by the + * bits in the AFSR, at most one of these events will have its status captured + * in the AFAR. The highest priority of those event bits will get AFAR logging. + * The AFAR will be unlocked and available to capture the address of another event + * as soon as the one bit in AFSR that corresponds to the event logged in AFAR is + * cleared. For example, if AFSR.CE is detected, then AFSR.UE (which overwrites + * the AFAR), and AFSR.UE is cleared by not AFSR.CE, then the AFAR will be unlocked + * and ready for another event, even though AFSR.CE is still set. The same rules + * also apply to the M_SYNDROME and E_SYNDROME fields of the AFSR. + */ + +/* Software bit set by linux trap handlers to indicate that the trap was + * signalled at %tl >= 1. + */ +#define CHAFSR_TL1 0x8000000000000000 + +#endif /* _SPARC64_CHAFSR_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/chmctrl.h linux.ac/include/asm-sparc64/chmctrl.h --- linux.vanilla/include/asm-sparc64/chmctrl.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-sparc64/chmctrl.h Sat Apr 14 01:40:15 2001 @@ -0,0 +1,184 @@ +/* $Id: chmctrl.h,v 1.1 2001/03/29 11:43:28 davem Exp $ */ +#ifndef _SPARC64_CHMCTRL_H +#define _SPARC64_CHMCTRL_H + +/* Cheetah memory controller programmable registers. */ +#define CHMCTRL_TCTRL1 0x00 /* Memory Timing Control I */ +#define CHMCTRL_TCTRL2 0x08 /* Memory Timing Control II */ +#define CHMCTRL_TCTRL3 0x38 /* Memory Timing Control III */ +#define CHMCTRL_TCTRL4 0x40 /* Memory Timing Control IV */ +#define CHMCTRL_DECODE1 0x10 /* Memory Address Decode I */ +#define CHMCTRL_DECODE2 0x18 /* Memory Address Decode II */ +#define CHMCTRL_DECODE3 0x20 /* Memory Address Decode III */ +#define CHMCTRL_DECODE4 0x28 /* Memory Address Decode IV */ +#define CHMCTRL_MACTRL 0x30 /* Memory Address Control */ + +/* Memory Timing Control I */ +#define TCTRL1_SDRAMCTL_DLY 0xf000000000000000 +#define TCTRL1_SDRAMCTL_DLY_SHIFT 60 +#define TCTRL1_SDRAMCLK_DLY 0x0e00000000000000 +#define TCTRL1_SDRAMCLK_DLY_SHIFT 57 +#define TCTRL1_R 0x0100000000000000 +#define TCTRL1_R_SHIFT 56 +#define TCTRL1_AUTORFR_CYCLE 0x00fe000000000000 +#define TCTRL1_AUTORFR_CYCLE_SHIFT 49 +#define TCTRL1_RD_WAIT 0x0001f00000000000 +#define TCTRL1_RD_WAIT_SHIFT 44 +#define TCTRL1_PC_CYCLE 0x00000fc000000000 +#define TCTRL1_PC_CYCLE_SHIFT 38 +#define TCTRL1_WR_MORE_RAS_PW 0x0000003f00000000 +#define TCTRL1_WR_MORE_RAS_PW_SHIFT 32 +#define TCTRL1_RD_MORE_RAW_PW 0x00000000fc000000 +#define TCTRL1_RD_MORE_RAS_PW_SHIFT 26 +#define TCTRL1_ACT_WR_DLY 0x0000000003f00000 +#define TCTRL1_ACT_WR_DLY_SHIFT 20 +#define TCTRL1_ACT_RD_DLY 0x00000000000fc000 +#define TCTRL1_ACT_RD_DLY_SHIFT 14 +#define TCTRL1_BANK_PRESENT 0x0000000000003000 +#define TCTRL1_BANK_PRESENT_SHIFT 12 +#define TCTRL1_RFR_INT 0x0000000000000ff8 +#define TCTRL1_RFR_INT_SHIFT 3 +#define TCTRL1_SET_MODE_REG 0x0000000000000004 +#define TCTRL1_SET_MODE_REG_SHIFT 2 +#define TCTRL1_RFR_ENABLE 0x0000000000000002 +#define TCTRL1_RFR_ENABLE_SHIFT 1 +#define TCTRL1_PRECHG_ALL 0x0000000000000001 +#define TCTRL1_PRECHG_ALL_SHIFT 0 + +/* Memory Timing Control II */ +#define TCTRL2_WR_MSEL_DLY 0xfc00000000000000 +#define TCTRL2_WR_MSEL_DLY_SHIFT 58 +#define TCTRL2_RD_MSEL_DLY 0x03f0000000000000 +#define TCTRL2_RD_MSEL_DLY_SHIFT 52 +#define TCTRL2_WRDATA_THLD 0x000c000000000000 +#define TCTRL2_WRDATA_THLD_SHIFT 50 +#define TCTRL2_RDWR_RD_TI_DLY 0x0003f00000000000 +#define TCTRL2_RDWR_RD_TI_DLY_SHIFT 44 +#define TCTRL2_AUTOPRECHG_ENBL 0x0000080000000000 +#define TCTRL2_AUTOPRECHG_ENBL_SHIFT 43 +#define TCTRL2_RDWR_PI_MORE_DLY 0x000007c000000000 +#define TCTRL2_RDWR_PI_MORE_DLY_SHIFT 38 +#define TCTRL2_RDWR_1_DLY 0x0000003f00000000 +#define TCTRL2_RDWR_1_DLY_SHIFT 32 +#define TCTRL2_WRWR_PI_MORE_DLY 0x00000000f8000000 +#define TCTRL2_WRWR_PI_MORE_DLY_SHIFT 27 +#define TCTRL2_WRWR_1_DLY 0x0000000007e00000 +#define TCTRL2_WRWR_1_DLY_SHIFT 21 +#define TCTRL2_RDWR_RD_PI_MORE_DLY 0x00000000001f0000 +#define TCTRL2_RDWR_RD_PI_MORE_DLY_SHIFT 16 +#define TCTRL2_R 0x0000000000008000 +#define TCTRL2_R_SHIFT 15 +#define TCTRL2_SDRAM_MODE_REG_DATA 0x0000000000007fff +#define TCTRL2_SDRAM_MODE_REG_DATA_SHIFT 0 + +/* Memory Timing Control III */ +#define TCTRL3_SDRAM_CTL_DLY 0xf000000000000000 +#define TCTRL3_SDRAM_CTL_DLY_SHIFT 60 +#define TCTRL3_SDRAM_CLK_DLY 0x0e00000000000000 +#define TCTRL3_SDRAM_CLK_DLY_SHIFT 57 +#define TCTRL3_R 0x0100000000000000 +#define TCTRL3_R_SHIFT 56 +#define TCTRL3_AUTO_RFR_CYCLE 0x00fe000000000000 +#define TCTRL3_AUTO_RFR_CYCLE_SHIFT 49 +#define TCTRL3_RD_WAIT 0x0001f00000000000 +#define TCTRL3_RD_WAIT_SHIFT 44 +#define TCTRL3_PC_CYCLE 0x00000fc000000000 +#define TCTRL3_PC_CYCLE_SHIFT 38 +#define TCTRL3_WR_MORE_RAW_PW 0x0000003f00000000 +#define TCTRL3_WR_MORE_RAW_PW_SHIFT 32 +#define TCTRL3_RD_MORE_RAW_PW 0x00000000fc000000 +#define TCTRL3_RD_MORE_RAW_PW_SHIFT 26 +#define TCTRL3_ACT_WR_DLY 0x0000000003f00000 +#define TCTRL3_ACT_WR_DLY_SHIFT 20 +#define TCTRL3_ACT_RD_DLY 0x00000000000fc000 +#define TCTRL3_ACT_RD_DLY_SHIFT 14 +#define TCTRL3_BANK_PRESENT 0x0000000000003000 +#define TCTRL3_BANK_PRESENT_SHIFT 12 +#define TCTRL3_RFR_INT 0x0000000000000ff8 +#define TCTRL3_RFR_INT_SHIFT 3 +#define TCTRL3_SET_MODE_REG 0x0000000000000004 +#define TCTRL3_SET_MODE_REG_SHIFT 2 +#define TCTRL3_RFR_ENABLE 0x0000000000000002 +#define TCTRL3_RFR_ENABLE_SHIFT 1 +#define TCTRL3_PRECHG_ALL 0x0000000000000001 +#define TCTRL3_PRECHG_ALL_SHIFT 0 + +/* Memory Timing Control IV */ +#define TCTRL4_WR_MSEL_DLY 0xfc00000000000000 +#define TCTRL4_WR_MSEL_DLY_SHIFT 58 +#define TCTRL4_RD_MSEL_DLY 0x03f0000000000000 +#define TCTRL4_RD_MSEL_DLY_SHIFT 52 +#define TCTRL4_WRDATA_THLD 0x000c000000000000 +#define TCTRL4_WRDATA_THLD_SHIFT 50 +#define TCTRL4_RDWR_RD_RI_DLY 0x0003f00000000000 +#define TCTRL4_RDWR_RD_RI_DLY_SHIFT 44 +#define TCTRL4_AUTO_PRECHG_ENBL 0x0000080000000000 +#define TCTRL4_AUTO_PRECHG_ENBL_SHIFT 43 +#define TCTRL4_RD_WR_PI_MORE_DLY 0x000007c000000000 +#define TCTRL4_RD_WR_PI_MORE_DLY_SHIFT 38 +#define TCTRL4_RD_WR_TI_DLY 0x0000003f00000000 +#define TCTRL4_RD_WR_TI_DLY_SHIFT 32 +#define TCTRL4_WR_WR_PI_MORE_DLY 0x00000000f8000000 +#define TCTRL4_WR_WR_PI_MORE_DLY_SHIFT 27 +#define TCTRL4_WR_WR_TI_DLY 0x0000000007e00000 +#define TCTRL4_WR_WR_TI_DLY_SHIFT 21 +#define TCTRL4_RDWR_RD_PI_MORE_DLY 0x00000000001f0000 +#define TCTRL4_RDWR_RD_PI_MORE_DLY_SHIFT 16 +#define TCTRL4_R 0x0000000000008000 +#define TCTRL4_R_SHIFT 15 +#define TCTRL4_SDRAM_MODE_REG_DATA 0x0000000000007fff +#define TCTRL4_SDRAM_MODE_REG_DATA_SHIFT 0 + +/* All 4 memory address decoding registers have the + * same layout. + */ +#define MEM_DECODE_VALID 0x8000000000000000 /* Valid */ +#define MEM_DECODE_VALID_SHIFT 63 +#define MEM_DECODE_UK 0x001ffe0000000000 /* Upper mask */ +#define MEM_DECODE_UK_SHIFT 41 +#define MEM_DECODE_UM 0x0000001ffff00000 /* Upper match */ +#define MEM_DECODE_UM_SHIFT 20 +#define MEM_DECODE_LK 0x000000000003c000 /* Lower mask */ +#define MEM_DECODE_LK_SHIFT 14 +#define MEM_DECODE_LM 0x0000000000000f00 /* Lower match */ +#define MEM_DECODE_LM_SHIFT 8 + +#define PA_UPPER_BITS 0x000007fffc000000 +#define PA_UPPER_BITS_SHIFT 26 +#define PA_LOWER_BITS 0x00000000000003c0 +#define PA_LOWER_BITS_SHIFT 6 + +#define MACTRL_R0 0x8000000000000000 +#define MACTRL_R0_SHIFT 63 +#define MACTRL_ADDR_LE_PW 0x7000000000000000 +#define MACTRL_ADDR_LE_PW_SHIFT 60 +#define MACTRL_CMD_PW 0x0f00000000000000 +#define MACTRL_CMD_PW_SHIFT 56 +#define MACTRL_HALF_MODE_WR_MSEL_DLY 0x00fc000000000000 +#define MACTRL_HALF_MODE_WR_MSEL_DLY_SHIFT 50 +#define MACTRL_HALF_MODE_RD_MSEL_DLY 0x0003f00000000000 +#define MACTRL_HALF_MODE_RD_MSEL_DLY_SHIFT 44 +#define MACTRL_HALF_MODE_SDRAM_CTL_DLY 0x00000f0000000000 +#define MACTRL_HALF_MODE_SDRAM_CTL_DLY_SHIFT 40 +#define MACTRL_HALF_MODE_SDRAM_CLK_DLY 0x000000e000000000 +#define MACTRL_HALF_MODE_SDRAM_CLK_DLY_SHIFT 37 +#define MACTRL_R1 0x0000001000000000 +#define MACTRL_R1_SHIFT 36 +#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B3 0x0000000f00000000 +#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B3_SHIFT 32 +#define MACTRL_ENC_INTLV_B3 0x00000000f8000000 +#define MACTRL_ENC_INTLV_B3_SHIFT 27 +#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B2 0x0000000007800000 +#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B2_SHIFT 23 +#define MACTRL_ENC_INTLV_B2 0x00000000007c0000 +#define MACTRL_ENC_INTLV_B2_SHIFT 18 +#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B1 0x000000000003c000 +#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B1_SHIFT 14 +#define MACTRL_ENC_INTLV_B1 0x0000000000003e00 +#define MACTRL_ENC_INTLV_B1_SHIFT 9 +#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B0 0x00000000000001e0 +#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B0_SHIFT 5 +#define MACTRL_ENC_INTLV_B0 0x000000000000001f +#define MACTRL_ENC_INTLV_B0_SHIFT 0 + +#endif /* _SPARC64_CHMCTRL_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/elf.h linux.ac/include/asm-sparc64/elf.h --- linux.vanilla/include/asm-sparc64/elf.h Tue Apr 3 17:32:28 2001 +++ linux.ac/include/asm-sparc64/elf.h Sat Apr 14 01:40:15 2001 @@ -1,4 +1,4 @@ -/* $Id: elf.h,v 1.28 2001/03/24 09:36:02 davem Exp $ */ +/* $Id: elf.h,v 1.29 2001/03/30 07:10:48 davem Exp $ */ #ifndef __ASM_SPARC64_ELF_H #define __ASM_SPARC64_ELF_H diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/estate.h linux.ac/include/asm-sparc64/estate.h --- linux.vanilla/include/asm-sparc64/estate.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-sparc64/estate.h Sat Apr 14 01:40:24 2001 @@ -0,0 +1,50 @@ +/* $Id: estate.h,v 1.1 2001/03/28 10:56:34 davem Exp $ */ +#ifndef _SPARC64_ESTATE_H +#define _SPARC64_ESTATE_H + +/* UltraSPARC-III E-cache Error Enable */ +#define ESTATE_ERROR_FMT 0x0000000000040000 /* Force MTAG ECC */ +#define ESTATE_ERROR_FMESS 0x000000000003c000 /* Forced MTAG ECC val */ +#define ESTATE_ERROR_FMD 0x0000000000002000 /* Force DATA ECC */ +#define ESTATE_ERROR_FDECC 0x0000000000001ff0 /* Forced DATA ECC val */ +#define ESTATE_ERROR_UCEEN 0x0000000000000008 /* See below */ +#define ESTATE_ERROR_NCEEN 0x0000000000000002 /* See below */ +#define ESTATE_ERROR_CEEN 0x0000000000000001 /* See below */ + +/* UCEEN enables the fast_ECC_error trap for: 1) software correctable E-cache + * errors 2) uncorrectable E-cache errors. Such events only occur on reads + * of the E-cache by the local processor for: 1) data loads 2) instruction + * fetches 3) atomic operations. Such events _cannot_ occur for: 1) merge + * 2) writeback 2) copyout. The AFSR bits assosciated with these traps are + * UCC and UCU. + */ + +/* NCEEN enables instruction_access_error, data_access_error, and ECC_error traps + * for uncorrectable ECC errors and system errors. + * + * Uncorrectable system bus data error or MTAG ECC error, system bus TimeOUT, + * or system bus BusERR: + * 1) As the result of an instruction fetch, will generate instruction_access_error + * 2) As the result of a load etc. will generate data_access_error. + * 3) As the result of store merge completion, writeback, or copyout will + * generate a disrupting ECC_error trap. + * 4) As the result of such errors on instruction vector fetch can generate any + * of the 3 trap types. + * + * The AFSR bits assosciated with these traps are EMU, EDU, WDU, CPU, IVU, UE, + * BERR, and TO. + */ + +/* CEEN enables the ECC_error trap for hardware corrected ECC errors. System bus + * reads resulting in a hardware corrected data or MTAG ECC error will generate an + * ECC_error disrupting trap with this bit enabled. + * + * This same trap will also be generated when a hardware corrected ECC error results + * during store merge, writeback, and copyout operations. + */ + +/* In general, if the trap enable bits above are disabled the AFSR bits will still + * log the events even though the trap will not be generated by the processor. + */ + +#endif /* _SPARC64_ESTATE_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/ioctls.h linux.ac/include/asm-sparc64/ioctls.h --- linux.vanilla/include/asm-sparc64/ioctls.h Wed Apr 15 01:44:24 1998 +++ linux.ac/include/asm-sparc64/ioctls.h Tue Apr 3 17:55:16 2001 @@ -87,6 +87,7 @@ #define FIONBIO _IOW('f', 126, int) #define FIONREAD _IOR('f', 127, int) #define TIOCINQ FIONREAD +#define FIOQSIZE _IOR('f', 128, loff_t) /* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it * someday. This is completely bogus, I know... diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/linux_logo.h linux.ac/include/asm-sparc64/linux_logo.h --- linux.vanilla/include/asm-sparc64/linux_logo.h Wed Aug 5 00:03:35 1998 +++ linux.ac/include/asm-sparc64/linux_logo.h Tue Apr 3 17:55:16 2001 @@ -1026,9 +1026,6 @@ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; -unsigned char linux_logo16_red[0]; -unsigned char linux_logo16_green[0]; -unsigned char linux_logo16_blue[0]; unsigned char linux_logo16[0]; #else @@ -1039,9 +1036,6 @@ extern unsigned char linux_logo_blue[]; extern unsigned char linux_logo[]; extern unsigned char linux_logo_bw[]; -extern unsigned char linux_logo16_red[]; -extern unsigned char linux_logo16_green[]; -extern unsigned char linux_logo16_blue[]; extern unsigned char linux_logo16[]; #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/mc146818rtc.h linux.ac/include/asm-sparc64/mc146818rtc.h --- linux.vanilla/include/asm-sparc64/mc146818rtc.h Tue Apr 3 17:32:28 2001 +++ linux.ac/include/asm-sparc64/mc146818rtc.h Sat Apr 14 01:40:24 2001 @@ -4,6 +4,7 @@ #ifndef __ASM_SPARC64_MC146818RTC_H #define __ASM_SPARC64_MC146818RTC_H +#include <linux/config.h> #include <asm/io.h> #ifndef RTC_PORT diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/perfctr.h linux.ac/include/asm-sparc64/perfctr.h --- linux.vanilla/include/asm-sparc64/perfctr.h Tue Oct 27 17:52:21 1998 +++ linux.ac/include/asm-sparc64/perfctr.h Sat Apr 14 01:40:24 2001 @@ -60,10 +60,10 @@ #ifndef __KERNEL__ #define PRIV 0x00000001 -#define USR 0x00000002 -#define SYS 0x00000004 +#define SYS 0x00000002 +#define USR 0x00000004 -/* Pic.S0 Selection Bit Field Encoding */ +/* Pic.S0 Selection Bit Field Encoding, Ultra-I/II */ #define CYCLE_CNT 0x00000000 #define INSTR_CNT 0x00000010 #define DISPATCH0_IC_MISS 0x00000020 @@ -77,7 +77,38 @@ #define EC_SNOOP_INV 0x000000E0 #define EC_RD_HIT 0x000000F0 -/* Pic.S1 Selection Bit Field Encoding */ +/* Pic.S0 Selection Bit Field Encoding, Ultra-III */ +#define US3_CYCLE_CNT 0x00000000 +#define US3_INSTR_CNT 0x00000010 +#define US3_DISPATCH0_IC_MISS 0x00000020 +#define US3_DISPATCH0_BR_TGT 0x00000030 +#define US3_DISPATCH0_2ND_BR 0x00000040 +#define US3_RSTALL_STOREQ 0x00000050 +#define US3_RSTALL_IU_USE 0x00000060 +#define US3_IC_REF 0x00000080 +#define US3_DC_RD 0x00000090 +#define US3_DC_WR 0x000000a0 +#define US3_EC_REF 0x000000c0 +#define US3_EC_WR_HIT_RTO 0x000000d0 +#define US3_EC_SNOOP_INV 0x000000e0 +#define US3_EC_RD_MISS 0x000000f0 +#define US3_PC_PORT0_RD 0x00000100 +#define US3_SI_SNOOP 0x00000110 +#define US3_SI_CIQ_FLOW 0x00000120 +#define US3_SI_OWNED 0x00000130 +#define US3_SW_COUNT_0 0x00000140 +#define US3_IU_BR_MISS_TAKEN 0x00000150 +#define US3_IU_BR_COUNT_TAKEN 0x00000160 +#define US3_DISP_RS_MISPRED 0x00000170 +#define US3_FA_PIPE_COMPL 0x00000180 +#define US3_MC_READS_0 0x00000200 +#define US3_MC_READS_1 0x00000210 +#define US3_MC_READS_2 0x00000220 +#define US3_MC_READS_3 0x00000230 +#define US3_MC_STALLS_0 0x00000240 +#define US3_MC_STALLS_2 0x00000250 + +/* Pic.S1 Selection Bit Field Encoding, Ultra-I/II */ #define CYCLE_CNT_D1 0x00000000 #define INSTR_CNT_D1 0x00000800 #define DISPATCH0_IC_MISPRED 0x00001000 @@ -90,6 +121,47 @@ #define EC_WB 0x00006800 #define EC_SNOOP_CB 0x00007000 #define EC_IT_HIT 0x00007800 + +/* Pic.S1 Selection Bit Field Encoding, Ultra-III */ +#define US3_CYCLE_CNT_D1 0x00000000 +#define US3_INSTR_CNT_D1 0x00000800 +#define US3_DISPATCH0_MISPRED 0x00001000 +#define US3_IC_MISS_CANCELLED 0x00001800 +#define US3_RE_ENDIAN_MISS 0x00002000 +#define US3_RE_FPU_BYPASS 0x00002800 +#define US3_RE_DC_MISS 0x00003000 +#define US3_RE_EC_MISS 0x00003800 +#define US3_IC_MISS 0x00004000 +#define US3_DC_RD_MISS 0x00004800 +#define US3_DC_WR_MISS 0x00005000 +#define US3_RSTALL_FP_USE 0x00005800 +#define US3_EC_MISSES 0x00006000 +#define US3_EC_WB 0x00006800 +#define US3_EC_SNOOP_CB 0x00007000 +#define US3_EC_IC_MISS 0x00007800 +#define US3_RE_PC_MISS 0x00008000 +#define US3_ITLB_MISS 0x00008800 +#define US3_DTLB_MISS 0x00009000 +#define US3_WC_MISS 0x00009800 +#define US3_WC_SNOOP_CB 0x0000a000 +#define US3_WC_SCRUBBED 0x0000a800 +#define US3_WC_WB_WO_READ 0x0000b000 +#define US3_PC_SOFT_HIT 0x0000c000 +#define US3_PC_SNOOP_INV 0x0000c800 +#define US3_PC_HARD_HIT 0x0000d000 +#define US3_PC_PORT1_RD 0x0000d800 +#define US3_SW_COUNT_1 0x0000e000 +#define US3_IU_STAT_BR_MIS_UNTAKEN 0x0000e800 +#define US3_IU_STAT_BR_COUNT_UNTAKEN 0x0000f000 +#define US3_PC_MS_MISSES 0x0000f800 +#define US3_MC_WRITES_0 0x00010800 +#define US3_MC_WRITES_1 0x00011000 +#define US3_MC_WRITES_2 0x00011800 +#define US3_MC_WRITES_3 0x00012000 +#define US3_MC_STALLS_1 0x00012800 +#define US3_MC_STALLS_3 0x00013000 +#define US3_RE_RAW_MISS 0x00013800 +#define US3_FM_PIPE_COMPLETION 0x00014000 struct vcounter_struct { unsigned long long vcnt0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/pgalloc.h linux.ac/include/asm-sparc64/pgalloc.h --- linux.vanilla/include/asm-sparc64/pgalloc.h Tue Apr 3 17:32:28 2001 +++ linux.ac/include/asm-sparc64/pgalloc.h Sat Apr 14 01:40:24 2001 @@ -1,4 +1,4 @@ -/* $Id: pgalloc.h,v 1.18 2001/03/24 09:36:01 davem Exp $ */ +/* $Id: pgalloc.h,v 1.19 2001/03/30 07:10:48 davem Exp $ */ #ifndef _SPARC64_PGALLOC_H #define _SPARC64_PGALLOC_H diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/pgtable.h linux.ac/include/asm-sparc64/pgtable.h --- linux.vanilla/include/asm-sparc64/pgtable.h Tue Apr 3 17:32:28 2001 +++ linux.ac/include/asm-sparc64/pgtable.h Sat Apr 14 01:40:24 2001 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.138 2001/03/08 09:55:56 davem Exp $ +/* $Id: pgtable.h,v 1.139 2001/03/27 02:36:37 davem Exp $ * pgtable.h: SpitFire page table operations. * * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -302,9 +302,15 @@ #include <asm-generic/pgtable.h> -#endif /* !(__ASSEMBLY__) */ - /* We provide our own get_unmapped_area to cope with VA holes for userland */ #define HAVE_ARCH_UNMAPPED_AREA + +/* We provide a special get_unmapped_area for framebuffer mmaps to try and use + * the largest alignment possible such that larget PTEs can be used. + */ +extern unsigned long get_fb_unmapped_area(struct file *filp, unsigned long, unsigned long, unsigned long, unsigned long); +#define HAVE_ARCH_FB_UNMAPPED_AREA + +#endif /* !(__ASSEMBLY__) */ #endif /* !(_SPARC64_PGTABLE_H) */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/processor.h linux.ac/include/asm-sparc64/processor.h --- linux.vanilla/include/asm-sparc64/processor.h Tue Apr 3 17:32:28 2001 +++ linux.ac/include/asm-sparc64/processor.h Sat Apr 14 01:40:24 2001 @@ -1,4 +1,4 @@ -/* $Id: processor.h,v 1.69 2001/03/08 22:08:51 davem Exp $ +/* $Id: processor.h,v 1.70 2001/03/27 02:36:38 davem Exp $ * include/asm-sparc64/processor.h * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -79,7 +79,6 @@ #define SPARC_FLAG_32BIT 0x04 /* task is older 32-bit binary */ #define SPARC_FLAG_NEWCHILD 0x08 /* task is just-spawned child process */ #define SPARC_FLAG_PERFCTR 0x10 /* task has performance counters active */ -#define SPARC_FLAG_MMAPSHARED 0x20 /* task wants a shared mmap */ #define FAULT_CODE_WRITE 0x01 /* Write access, implies D-TLB */ #define FAULT_CODE_DTLB 0x02 /* Miss happened in D-TLB */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/spitfire.h linux.ac/include/asm-sparc64/spitfire.h --- linux.vanilla/include/asm-sparc64/spitfire.h Tue Apr 3 17:32:28 2001 +++ linux.ac/include/asm-sparc64/spitfire.h Sat Apr 14 01:40:24 2001 @@ -1,4 +1,4 @@ -/* $Id: spitfire.h,v 1.14 2001/03/22 07:26:04 davem Exp $ +/* $Id: spitfire.h,v 1.15 2001/03/27 00:10:15 davem Exp $ * spitfire.h: SpitFire/BlackBird/Cheetah inline MMU operations. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -13,10 +13,15 @@ * and ASI_IMMU, that is there is a distinct and unique copy of * each these registers for each TLB. */ -#define TSB_TAG_TARGET 0x0000000000000000 -#define TLB_SFSR 0x0000000000000018 -#define TSB_REG 0x0000000000000028 -#define TLB_TAG_ACCESS 0x0000000000000030 +#define TSB_TAG_TARGET 0x0000000000000000 /* All chips */ +#define TLB_SFSR 0x0000000000000018 /* All chips */ +#define TSB_REG 0x0000000000000028 /* All chips */ +#define TLB_TAG_ACCESS 0x0000000000000030 /* All chips */ +#define VIRT_WATCHPOINT 0x0000000000000038 /* All chips */ +#define PHYS_WATCHPOINT 0x0000000000000040 /* All chips */ +#define TSB_EXTENSION_P 0x0000000000000048 /* Ultra-III and later */ +#define TSB_EXTENSION_S 0x0000000000000050 /* Ultra-III and later, D-TLB only */ +#define TSB_EXTENSION_N 0x0000000000000058 /* Ultra-III and later */ /* These registers only exist as one entity, and are accessed * via ASI_DMMU only. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/starfire.h linux.ac/include/asm-sparc64/starfire.h --- linux.vanilla/include/asm-sparc64/starfire.h Tue Oct 3 17:24:41 2000 +++ linux.ac/include/asm-sparc64/starfire.h Tue Apr 3 17:55:16 2001 @@ -1,7 +1,7 @@ /* $Id: starfire.h,v 1.1 2000/09/21 06:18:53 anton Exp $ * starfire.h: Group all starfire specific code together. * - * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 2000 Anton Blanchard (anton@samba.org) */ #ifndef _SPARC64_STARFIRE_H diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/tlb.h linux.ac/include/asm-sparc64/tlb.h --- linux.vanilla/include/asm-sparc64/tlb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-sparc64/tlb.h Tue Apr 3 17:55:16 2001 @@ -0,0 +1 @@ +#include <asm-generic/tlb.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/ttable.h linux.ac/include/asm-sparc64/ttable.h --- linux.vanilla/include/asm-sparc64/ttable.h Wed Apr 12 17:12:35 2000 +++ linux.ac/include/asm-sparc64/ttable.h Sat Apr 14 01:40:24 2001 @@ -1,4 +1,4 @@ -/* $Id: ttable.h,v 1.15 2000/04/03 10:36:42 davem Exp $ */ +/* $Id: ttable.h,v 1.16 2001/03/28 10:56:34 davem Exp $ */ #ifndef _SPARC64_TTABLE_H #define _SPARC64_TTABLE_H @@ -54,13 +54,6 @@ clr %l6; \ nop; -#define TRAPTL1_CEE \ - ldxa [%g0] ASI_AFSR, %g1; \ - membar #Sync; \ - stxa %g1, [%g0] ASI_AFSR; \ - membar #Sync; \ - retry; nop; nop; nop; - #define TRAP_ARG(routine, arg) \ sethi %hi(109f), %g7; \ ba,pt %xcc, etrap; \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/a.out.h linux.ac/include/asm-um/a.out.h --- linux.vanilla/include/asm-um/a.out.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/a.out.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,12 @@ +#ifndef __UM_A_OUT_H +#define __UM_A_OUT_H + +#include "asm/arch/a.out.h" + +#undef STACK_TOP + +extern unsigned long stacksizelim; + +#define STACK_TOP (TASK_SIZE - (stacksizelim * (NESTING + 1))) + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/atomic.h linux.ac/include/asm-um/atomic.h --- linux.vanilla/include/asm-um/atomic.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/atomic.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_ATOMIC_H +#define __UM_ATOMIC_H + +#include "asm/arch/atomic.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/bitops.h linux.ac/include/asm-um/bitops.h --- linux.vanilla/include/asm-um/bitops.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/bitops.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_BITOPS_H +#define __UM_BITOPS_H + +#include "asm/arch/bitops.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/boot.h linux.ac/include/asm-um/boot.h --- linux.vanilla/include/asm-um/boot.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/boot.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_BOOT_H +#define __UM_BOOT_H + +#include "asm/arch/boot.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/bugs.h linux.ac/include/asm-um/bugs.h --- linux.vanilla/include/asm-um/bugs.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/bugs.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_BUGS_H +#define __UM_BUGS_H + +void check_bugs(void); + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/byteorder.h linux.ac/include/asm-um/byteorder.h --- linux.vanilla/include/asm-um/byteorder.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/byteorder.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_BYTEORDER_H +#define __UM_BYTEORDER_H + +#include "asm/arch/byteorder.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/cache.h linux.ac/include/asm-um/cache.h --- linux.vanilla/include/asm-um/cache.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/cache.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_CACHE_H +#define __UM_CACHE_H + +#define L1_CACHE_BYTES 32 + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/checksum.h linux.ac/include/asm-um/checksum.h --- linux.vanilla/include/asm-um/checksum.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/checksum.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_CHECKSUM_H +#define __UM_CHECKSUM_H + +#include "asm/arch/checksum.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/cobalt.h linux.ac/include/asm-um/cobalt.h --- linux.vanilla/include/asm-um/cobalt.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/cobalt.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_COBALT_H +#define __UM_COBALT_H + +#include "asm/arch/cobalt.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/current.h linux.ac/include/asm-um/current.h --- linux.vanilla/include/asm-um/current.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/current.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,20 @@ +#ifndef __UM_CURRENT_H +#define __UM_CURRENT_H + +struct task_struct; + +#ifdef __SMP__ +extern struct task_struct *current_task[]; + +#define CURRENT_TASK(dummy) (((unsigned long) &dummy) & (PAGE_MASK << 2)) + +#define current ({ int dummy; (struct task_struct *) CURRENT_TASK(dummy); }) + +#else + +extern struct task_struct *current_task; +#define current current_task + +#endif + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/delay.h linux.ac/include/asm-um/delay.h --- linux.vanilla/include/asm-um/delay.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/delay.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_DELAY_H +#define __UM_DELAY_H + +#include "asm/arch/delay.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/desc.h linux.ac/include/asm-um/desc.h --- linux.vanilla/include/asm-um/desc.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/desc.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_DESC_H +#define __UM_DESC_H + +#include "asm/arch/desc.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/div64.h linux.ac/include/asm-um/div64.h --- linux.vanilla/include/asm-um/div64.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/div64.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef _UM_DIV64_H +#define _UM_DIV64_H + +#include "asm/arch/div64.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/dma.h linux.ac/include/asm-um/dma.h --- linux.vanilla/include/asm-um/dma.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/dma.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,10 @@ +#ifndef __UM_DMA_H +#define __UM_DMA_H + +#include "asm/arch/dma.h" + +#undef MAX_DMA_ADDRESS + +#define MAX_DMA_ADDRESS (physmem) + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/elf.h linux.ac/include/asm-um/elf.h --- linux.vanilla/include/asm-um/elf.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/elf.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,23 @@ +#ifndef __UM_ELF_H +#define __UM_ELF_H + +#define ELF_HWCAP (0) + +#define ELF_PLATFORM "i586" + +#define SET_PERSONALITY(ex, ibcs2) do ; while(0) + +#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) + +typedef int elf_gregset_t; +typedef int elf_fpregset_t; + +#define ELF_EXEC_PAGESIZE 4096 + +#define elf_check_arch(x) (1) + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_386 + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/errno.h linux.ac/include/asm-um/errno.h --- linux.vanilla/include/asm-um/errno.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/errno.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_ERRNO_H +#define __UM_ERRNO_H + +#include "asm/arch/errno.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/fcntl.h linux.ac/include/asm-um/fcntl.h --- linux.vanilla/include/asm-um/fcntl.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/fcntl.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_FCNTL_H +#define __UM_FCNTL_H + +#include "asm/arch/fcntl.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/fixmap.h linux.ac/include/asm-um/fixmap.h --- linux.vanilla/include/asm-um/fixmap.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/fixmap.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_FIXMAP_H +#define __UM_FIXMAP_H + +#define FIXADDR_START (0xffff0000) + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/floppy.h linux.ac/include/asm-um/floppy.h --- linux.vanilla/include/asm-um/floppy.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/floppy.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_FLOPPY_H +#define __UM_FLOPPY_H + +#include "asm/arch/floppy.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/hardirq.h linux.ac/include/asm-um/hardirq.h --- linux.vanilla/include/asm-um/hardirq.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/hardirq.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,8 @@ +#ifndef __UM_HARDIRQ_H +#define __UM_HARDIRQ_H + +#include "linux/spinlock.h" +#include "asm/smp.h" +#include "asm/arch/hardirq.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/hdreg.h linux.ac/include/asm-um/hdreg.h --- linux.vanilla/include/asm-um/hdreg.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/hdreg.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_HDREG_H +#define __UM_HDREG_H + +#include "asm/arch/hdreg.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/highmem.h linux.ac/include/asm-um/highmem.h --- linux.vanilla/include/asm-um/highmem.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/highmem.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_HIGHMEM_H +#define __UM_HIGHMEM_H + +#include "asm/arch/highmem.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/hw_irq.h linux.ac/include/asm-um/hw_irq.h --- linux.vanilla/include/asm-um/hw_irq.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/hw_irq.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,9 @@ +#ifndef _ASM_UM_HW_IRQ_H +#define _ASM_UM_HW_IRQ_H + +#include "asm/irq.h" + +static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) +{} + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/ide.h linux.ac/include/asm-um/ide.h --- linux.vanilla/include/asm-um/ide.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/ide.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_IDE_H +#define __UM_IDE_H + +#include "asm/arch/ide.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/init.h linux.ac/include/asm-um/init.h --- linux.vanilla/include/asm-um/init.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/init.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,11 @@ +#ifndef _UM_INIT_H +#define _UM_INIT_H + +#ifdef notdef +#define __init +#define __initdata +#define __initfunc(__arginit) __arginit +#define __cacheline_aligned +#endif + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/io.h linux.ac/include/asm-um/io.h --- linux.vanilla/include/asm-um/io.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/io.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_IO_H +#define __UM_IO_H + +#include "asm/arch/io.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/ioctl.h linux.ac/include/asm-um/ioctl.h --- linux.vanilla/include/asm-um/ioctl.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/ioctl.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_IOCTL_H +#define __UM_IOCTL_H + +#include "asm/arch/ioctl.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/ioctls.h linux.ac/include/asm-um/ioctls.h --- linux.vanilla/include/asm-um/ioctls.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/ioctls.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_IOCTLS_H +#define __UM_IOCTLS_H + +#include "asm/arch/ioctls.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/ipc.h linux.ac/include/asm-um/ipc.h --- linux.vanilla/include/asm-um/ipc.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/ipc.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_IPC_H +#define __UM_IPC_H + +#include "asm/arch/ipc.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/ipcbuf.h linux.ac/include/asm-um/ipcbuf.h --- linux.vanilla/include/asm-um/ipcbuf.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/ipcbuf.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_IPCBUF_H +#define __UM_IPCBUF_H + +#include "asm/arch/ipcbuf.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/irq.h linux.ac/include/asm-um/irq.h --- linux.vanilla/include/asm-um/irq.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/irq.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,26 @@ +#ifndef __UM_IRQ_H +#define __UM_IRQ_H + +#include "asm/arch/irq.h" +#include "asm/ptrace.h" + +#undef NR_IRQS + + +#define TIMER_IRQ 0 +#define UMN_IRQ 1 +#define CONSOLE_IRQ 2 +#define UBD_IRQ 3 +#define UM_ETH_IRQ 4 +#define SSL_IRQ 5 +#define ACCEPT_IRQ 6 + +#define LAST_IRQ ACCEPT_IRQ +#define NR_IRQS (LAST_IRQ + 1) + +extern int um_request_irq(unsigned int irq, int fd, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, const char * devname, + void *dev_id); + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/keyboard.h linux.ac/include/asm-um/keyboard.h --- linux.vanilla/include/asm-um/keyboard.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/keyboard.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_KEYBOARD_H +#define __UM_KEYBOARD_H + +#include "asm/arch/keyboard.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/linux_logo.h linux.ac/include/asm-um/linux_logo.h --- linux.vanilla/include/asm-um/linux_logo.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/linux_logo.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_LINUX_LOGO_H +#define __UM_LINUX_LOGO_H + +#include "asm/arch/linux_logo.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/locks.h linux.ac/include/asm-um/locks.h --- linux.vanilla/include/asm-um/locks.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/locks.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_LOCKS_H +#define __UM_LOCKS_H + +#include "asm/arch/locks.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/mca_dma.h linux.ac/include/asm-um/mca_dma.h --- linux.vanilla/include/asm-um/mca_dma.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/mca_dma.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef mca___UM_DMA_H +#define mca___UM_DMA_H + +#include "asm/arch/mca_dma.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/mman.h linux.ac/include/asm-um/mman.h --- linux.vanilla/include/asm-um/mman.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/mman.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_MMAN_H +#define __UM_MMAN_H + +#include "asm/arch/mman.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/mmu.h linux.ac/include/asm-um/mmu.h --- linux.vanilla/include/asm-um/mmu.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/mmu.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __MMU_H +#define __MMU_H + +#include "asm/arch/mmu.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/mmu_context.h linux.ac/include/asm-um/mmu_context.h --- linux.vanilla/include/asm-um/mmu_context.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/mmu_context.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,30 @@ +#ifndef __UM_MMU_CONTEXT_H +#define __UM_MMU_CONTEXT_H + +#include "linux/sched.h" + +#define CHANGES_PAGES(c) (sizeof((c)->pages) / sizeof((c)->pages[0])) +#define CHANGES_PAGE(c, n) ((c)->pages[(n) % CHANGES_PAGES(c)]) +#define ADD_CHANGE(c, p) (CHANGES_PAGE(c, (c)->count++) = (p)) + +struct mm_changes { + int count; + int barrier; + unsigned long pages[(PAGE_SIZE - 2*sizeof(int))/sizeof(unsigned long)]; +}; + +#define init_new_context(task, mm) (0) +#define get_mmu_context(task) do ; while(0) +#define activate_context(tsk) do ; while(0) +#define destroy_context(mm) do ; while(0) + +extern void activate_mm(struct mm_struct *old, struct mm_struct *new); +extern void switch_mm(struct mm_struct *prev, struct mm_struct *next, + struct task_struct *tsk, unsigned cpu); + +static inline void enter_lazy_tlb(struct mm_struct *mm, + struct task_struct *tsk, unsigned cpu) +{ +} + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/module.h linux.ac/include/asm-um/module.h --- linux.vanilla/include/asm-um/module.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/module.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_MODULE_H +#define __UM_MODULE_H + +#include "asm/arch/module.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/msgbuf.h linux.ac/include/asm-um/msgbuf.h --- linux.vanilla/include/asm-um/msgbuf.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/msgbuf.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_MSGBUF_H +#define __UM_MSGBUF_H + +#include "asm/arch/msgbuf.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/mtrr.h linux.ac/include/asm-um/mtrr.h --- linux.vanilla/include/asm-um/mtrr.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/mtrr.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_MTRR_H +#define __UM_MTRR_H + +#include "asm/arch/mtrr.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/namei.h linux.ac/include/asm-um/namei.h --- linux.vanilla/include/asm-um/namei.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/namei.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_NAMEI_H +#define __UM_NAMEI_H + +#include "asm/arch/namei.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/page.h linux.ac/include/asm-um/page.h --- linux.vanilla/include/asm-um/page.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/page.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,41 @@ +#ifndef __UM_PAGE_H +#define __UM_PAGE_H + +struct page; + +#include "asm/arch/page.h" + +#undef BUG +#undef PAGE_BUG +#undef PAGE_OFFSET +#undef __pa +#undef __va + +#ifndef __ASSEMBLY__ + +extern void stop(void); + +#define BUG() do { \ + printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ + stop(); \ +} while (0) + +#define PAGE_BUG(page) do { \ + BUG(); \ +} while (0) + +#endif /* __ASSEMBLY__ */ + +extern unsigned long physmem; + +#define PAGE_OFFSET (physmem) + +#define __va_space (8*1024*1024) + +#define __pa(x) ((unsigned long) (x) - (physmem)) +#define __va(x) ((void *) ((unsigned long) (x) + (physmem))) + +#define virt_to_page(kaddr) (mem_map + (__pa(kaddr) >> PAGE_SHIFT)) +#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/param.h linux.ac/include/asm-um/param.h --- linux.vanilla/include/asm-um/param.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/param.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,24 @@ +#ifndef _UM_PARAM_H +#define _UM_PARAM_H + +#ifndef HZ +#define HZ 20 +#endif + +#define EXEC_PAGESIZE 4096 + +#ifndef NGROUPS +#define NGROUPS 32 +#endif + +#ifndef NOGROUP +#define NOGROUP (-1) +#endif + +#define MAXHOSTNAMELEN 64 /* max length of hostname */ + +#ifdef __KERNEL__ +# define CLOCKS_PER_SEC 100 /* frequency at which times() counts */ +#endif + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/pci.h linux.ac/include/asm-um/pci.h --- linux.vanilla/include/asm-um/pci.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/pci.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_PCI_H +#define __UM_PCI_H + +#include "asm/arch/pci.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/pgalloc.h linux.ac/include/asm-um/pgalloc.h --- linux.vanilla/include/asm-um/pgalloc.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/pgalloc.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Derived from include/asm-i386/pgalloc.h and include/asm-i386/pgtable.h + * Licensed under the GPL + */ + +#ifndef __UM_PGALLOC_H +#define __UM_PGALLOC_H + +#include "linux/mm.h" + +#define pgd_quicklist (current_cpu_data.pgd_quick) +#define pmd_quicklist (current_cpu_data.pmd_quick) +#define pte_quicklist (current_cpu_data.pte_quick) +#define pgtable_cache_size (current_cpu_data.pgtable_cache_sz) + +#define pmd_populate(mm, pmd, pte) \ + set_pmd(pmd, __pmd(_PAGE_TABLE + (unsigned long) pte)) + +/* + * Allocate and free page tables. + */ + +extern __inline__ pgd_t *get_pgd_slow(void) +{ + pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL); + + if (pgd) { + memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); + memcpy(pgd + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + } + return pgd; +} + +extern __inline__ pgd_t *get_pgd_fast(void) +{ + unsigned long *ret; + + if ((ret = pgd_quicklist) != NULL) { + pgd_quicklist = (unsigned long *)(*ret); + ret[0] = 0; + pgtable_cache_size--; + } else + ret = (unsigned long *)get_pgd_slow(); + return (pgd_t *)ret; +} + +extern __inline__ void free_pgd_fast(pgd_t *pgd) +{ + *(unsigned long *)pgd = (unsigned long) pgd_quicklist; + pgd_quicklist = (unsigned long *) pgd; + pgtable_cache_size++; +} + +extern __inline__ void free_pgd_slow(pgd_t *pgd) +{ + free_page((unsigned long)pgd); +} + +static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pte_t *pte; + + pte = (pte_t *) __get_free_page(GFP_KERNEL); + if (pte) + clear_page(pte); + return pte; +} + +static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) +{ + unsigned long *ret; + + if ((ret = (unsigned long *)pte_quicklist) != NULL) { + pte_quicklist = (unsigned long *)(*ret); + ret[0] = ret[1]; + pgtable_cache_size--; + } + return (pte_t *)ret; +} + +extern __inline__ void pte_free_pte_fast(pte_t *pte) +{ + *(unsigned long *)pte = (unsigned long) pte_quicklist; + pte_quicklist = (unsigned long *) pte; + pgtable_cache_size++; +} + +extern __inline__ void pte_free_slow(pte_t *pte) +{ + free_page((unsigned long)pte); +} + +#define pte_free(pte) pte_free_slow(pte) +#define pgd_free(pgd) free_pgd_slow(pgd) +#define pgd_alloc() get_pgd_fast() + +/* + * allocating and freeing a pmd is trivial: the 1-entry pmd is + * inside the pgd, so has no extra memory associated with it. + */ + +#define pmd_alloc_one_fast(mm, addr) ({ BUG(); ((pmd_t *)1); }) +#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); }) +#define pmd_free_slow(x) do { } while (0) +#define pmd_free_fast(x) do { } while (0) +#define pmd_free(x) do { } while (0) +#define pgd_populate(mm, pmd, pte) BUG() + +/* + * TLB flushing: + * + * - flush_tlb() flushes the current mm struct TLBs + * - flush_tlb_all() flushes all processes TLBs + * - flush_tlb_mm(mm) flushes the specified mm context TLB's + * - flush_tlb_page(vma, vmaddr) flushes one page + * - flush_tlb_range(mm, start, end) flushes a range of pages + * - flush_tlb_pgtables(mm, start, end) flushes a range of page tables + */ + +extern void flush_tlb_all(void); +extern void flush_tlb_mm(struct mm_struct *mm); +extern void flush_tlb_kernel_vm(void); +extern void flush_tlb_range(struct mm_struct *mm, unsigned long start, + unsigned long end); +extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr); + +extern inline void flush_tlb_pgtables(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ +} + +#endif +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/pgtable.h linux.ac/include/asm-um/pgtable.h --- linux.vanilla/include/asm-um/pgtable.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/pgtable.h Sun Apr 15 22:52:23 2001 @@ -0,0 +1,377 @@ +#ifndef __UM_PGTABLE_H +#define __UM_PGTABLE_H + +#include "asm/processor.h" +#include "asm/page.h" +#include "asm/fixmap.h" + +extern pgd_t swapper_pg_dir[1024]; + +#define flush_cache_all() do ; while (0) +#define flush_cache_mm(mm) do ; while (0) +#define flush_cache_range(mm, start, end) do ; while (0) +#define flush_cache_page(vma, vmaddr) do ; while (0) +#define flush_page_to_ram(page) do ; while (0) +#define flush_dcache_page(page) do ; while (0) +#define flush_icache_range(from, to) do ; while (0) +#define flush_icache_page(vma,pg) do ; while (0) + +extern void pte_free(pte_t *pte); + +extern void pgd_free(pgd_t *pgd); + +extern int do_check_pgt_cache(int, int); + +/* zero page used for uninitialized stuff */ +extern unsigned long *empty_zero_page; + +/* PMD_SHIFT determines the size of the area a second-level page table can map */ +#define PMD_SHIFT 22 +#define PMD_SIZE (1UL << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE-1)) + +/* PGDIR_SHIFT determines what a third-level page table entry can map */ +#define PGDIR_SHIFT 22 +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) + +/* + * entries per page directory level: the i386 is two-level, so + * we don't really have any PMD directory physically. + */ +#define PTRS_PER_PTE 1024 +#define PTRS_PER_PMD 1 +#define PTRS_PER_PGD 1024 +#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) +#define FIRST_USER_PGD_NR 0 + +#define pte_ERROR(e) \ + printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e)) +#define pmd_ERROR(e) \ + printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e)) +#define pgd_ERROR(e) \ + printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) + +/* + * pgd entries used up by user/kernel: + */ + +#define USER_PGD_PTRS (TASK_SIZE >> PGDIR_SHIFT) +#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS) + +#ifndef __ASSEMBLY__ +/* Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +extern unsigned long high_physmem; + +#define VMALLOC_OFFSET (__va_space) +#define VMALLOC_START (((unsigned long) high_physmem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (FIXADDR_START) + +/* + * The 4MB page is guessing.. Detailed in the infamous "Chapter H" + * of the Pentium details, but assuming intel did the straightforward + * thing, this bit set in the page directory entry just means that + * the page directory entry points directly to a 4MB-aligned block of + * memory. + */ +#define _PAGE_PRESENT 0x001 +#define _PAGE_RW 0x002 +#define _PAGE_USER 0x004 +#define _PAGE_PCD 0x008 +#define _PAGE_NEWPAGE 0x010 +#define _PAGE_ACCESSED 0x020 +#define _PAGE_DIRTY 0x040 +#define _PAGE_NEWPROT 0x100 + +#define _PAGE_PROTNONE 0x080 /* If not present */ + +#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY) +#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) +#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) + +#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED) +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED) +#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) +#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) +#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED) + +/* + * The i386 can't do page protection for execute, and considers that the same are read. + * Also, write permissions imply read permissions. This is the closest we can get.. + */ +#define __P000 PAGE_NONE +#define __P001 PAGE_READONLY +#define __P010 PAGE_COPY +#define __P011 PAGE_COPY +#define __P100 PAGE_READONLY +#define __P101 PAGE_READONLY +#define __P110 PAGE_COPY +#define __P111 PAGE_COPY + +#define __S000 PAGE_NONE +#define __S001 PAGE_READONLY +#define __S010 PAGE_SHARED +#define __S011 PAGE_SHARED +#define __S100 PAGE_READONLY +#define __S101 PAGE_READONLY +#define __S110 PAGE_SHARED +#define __S111 PAGE_SHARED + +/* + * Define this if things work differently on an i386 and an i486: + * it will (on an i486) warn about kernel memory accesses that are + * done without a 'verify_area(VERIFY_WRITE,..)' + */ +#undef TEST_VERIFY_AREA + +/* page table for 0-4MB for everybody */ +extern unsigned long pg0[1024]; + +/* + * BAD_PAGETABLE is used when we need a bogus page-table, while + * BAD_PAGE is used for a bogus page. + * + * ZERO_PAGE is a global shared page that is always zero: used + * for zero-mapped memory areas etc.. + */ +extern pte_t __bad_page(void); +extern pte_t * __bad_pagetable(void); + +#define BAD_PAGETABLE __bad_pagetable() +#define BAD_PAGE __bad_page() +#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) + +/* number of bits that fit into a memory pointer */ +#define BITS_PER_PTR (8*sizeof(unsigned long)) + +/* to align the pointer to a pointer address */ +#define PTR_MASK (~(sizeof(void*)-1)) + +/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */ +/* 64-bit machines, beware! SRB. */ +#define SIZEOF_PTR_LOG2 2 + +/* to find an entry in a page-table */ +#define PAGE_PTR(address) \ +((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK) + +#define pte_none(x) !(pte_val(x)) +#define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE)) +#define pte_clear(xp) do { pte_val(*(xp)) = 0; } while (0) + +#define pmd_none(x) (!(pmd_val(x) & ~_PAGE_NEWPAGE)) +#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) +#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) +#define pmd_clear(xp) do { pmd_val(*(xp)) = _PAGE_NEWPAGE; } while (0) + +#define pmd_newpage(x) (pmd_val(x) & _PAGE_NEWPAGE) +#define pmd_mkuptodate(x) (pmd_val(x) &= ~_PAGE_NEWPAGE) + +/* + * The "pgd_xxx()" functions here are trivial for a folded two-level + * setup: the pgd is never bad, and a pmd always exists (as it's folded + * into the pgd entry) + */ +extern inline int pgd_none(pgd_t pgd) { return 0; } +extern inline int pgd_bad(pgd_t pgd) { return 0; } +extern inline int pgd_present(pgd_t pgd) { return 1; } +extern inline void pgd_clear(pgd_t * pgdp) { } + + +/* + * Permanent address of a page. Obviously must never be + * called on a highmem page. + */ +#define page_address(page) ({ if (!(page)->virtual) BUG(); (page)->virtual; }) +#define __page_address(page) ({ PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT); }) +#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) +#define pte_page(x) \ + (mem_map+((unsigned long)((__pa(pte_val(x)) >> PAGE_SHIFT)))) + +extern inline pte_t pte_mknewprot(pte_t pte) +{ + pte_val(pte) |= _PAGE_NEWPROT; + return(pte); +} + +extern inline pte_t pte_mknewpage(pte_t pte) +{ + pte_val(pte) |= _PAGE_NEWPAGE; + return(pte); +} + +extern inline void set_pte(pte_t *pteptr, pte_t pteval) +{ + *pteptr = pteval; + if(pte_present(*pteptr)) + *pteptr = pte_mknewpage(pte_mknewprot(*pteptr)); +} + +/* + * (pmds are folded into pgds so this doesnt get actually called, + * but the define is needed for a generic inline function.) + */ +#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval) +#define set_pgd(pgdptr, pgdval) (*(pgdptr) = pgdval) + +/* + * The following only work if pte_present() is true. + * Undefined behaviour if not.. + */ +extern inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_USER; } +extern inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_USER; } +extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } +extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } +extern inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; } +extern inline int pte_newpage(pte_t pte) { return pte_val(pte) & _PAGE_NEWPAGE; } +extern inline int pte_newprot(pte_t pte) { return pte_val(pte) & _PAGE_NEWPROT; } + +extern inline pte_t pte_rdprotect(pte_t pte) +{ + pte_val(pte) &= ~_PAGE_USER; + return(pte_mknewprot(pte)); +} + +extern inline pte_t pte_exprotect(pte_t pte) +{ + pte_val(pte) &= ~_PAGE_USER; + return(pte_mknewprot(pte)); +} + +extern inline pte_t pte_mkclean(pte_t pte) +{ + pte_val(pte) &= ~_PAGE_DIRTY; + return(pte); +} + +extern inline pte_t pte_mkold(pte_t pte) +{ + pte_val(pte) &= ~_PAGE_ACCESSED; + return(pte); +} + +extern inline pte_t pte_wrprotect(pte_t pte) +{ + pte_val(pte) &= ~_PAGE_RW; + return(pte_mknewprot(pte)); +} + +extern inline pte_t pte_mkread(pte_t pte) +{ + pte_val(pte) |= _PAGE_USER; + return(pte_mknewprot(pte)); +} + +extern inline pte_t pte_mkexec(pte_t pte) +{ + pte_val(pte) |= _PAGE_USER; + return(pte_mknewprot(pte)); +} + +extern inline pte_t pte_mkdirty(pte_t pte) +{ + pte_val(pte) |= _PAGE_DIRTY; + return(pte); +} + +extern inline pte_t pte_mkyoung(pte_t pte) +{ + pte_val(pte) |= _PAGE_ACCESSED; + return(pte); +} + +extern inline pte_t pte_mkwrite(pte_t pte) +{ + pte_val(pte) |= _PAGE_RW; + return(pte_mknewprot(pte)); +} + +extern inline pte_t pte_mkuptodate(pte_t pte) +{ + pte_val(pte) &= ~(_PAGE_NEWPROT | _PAGE_NEWPAGE); + return(pte); +} + +/* + * Conversion functions: convert a page and protection to a page entry, + * and a page entry and page directory to the page they refer to. + */ + +#define mk_pte(page, pgprot) \ +({ \ + pte_t __pte; \ + \ + pte_val(__pte) = ((unsigned long) __va((page-mem_map)*(unsigned long)PAGE_SIZE + pgprot_val(pgprot))); \ + if(pte_present(__pte)) pte_mknewprot(pte_mknewpage(__pte)); \ + __pte; \ +}) + +/* This takes a physical page address that is used by the remapping functions */ +#define mk_pte_phys(physpage, pgprot) \ +({ pte_t __pte; pte_val(__pte) = physpage + pgprot_val(pgprot); __pte; }) + +extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +{ + pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); + if(pte_present(pte)) pte = pte_mknewpage(pte_mknewprot(pte)); + return pte; +} + +#define pmd_page(pmd) \ +(pmd_val(pmd) & PAGE_MASK) + +/* to find an entry in a page-table-directory. */ +#define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) + +/* to find an entry in a page-table-directory */ +#define pgd_offset(mm, address) \ +((mm)->pgd + ((address) >> PGDIR_SHIFT)) + +/* to find an entry in a kernel page-table-directory */ +#define pgd_offset_k(address) pgd_offset(&init_mm, address) + +/* Find an entry in the second-level page table.. */ +extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) +{ + return (pmd_t *) dir; +} + +/* Find an entry in the third-level page table.. */ +#define pte_offset(pmd, address) \ +((pte_t *) (pmd_page(*pmd) + ((address>>10) & ((PTRS_PER_PTE-1)<<2)))) + +#define update_mmu_cache(vma,address,pte) do ; while (0) + +/* Encode and de-code a swap entry */ +#define SWP_TYPE(x) (((x).val >> 1) & 0x3f) +#define SWP_OFFSET(x) ((x).val >> 8) +#define SWP_ENTRY(type, offset) ((swp_entry_t) { ((type) << 1) | ((offset) << 8) }) +#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define swp_entry_to_pte(x) ((pte_t) { (x).val }) + +#define PageSkip(x) (0) +#define kern_addr_valid(addr) (1) + +#include <asm-generic/pgtable.h> + +#endif + +#endif +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/poll.h linux.ac/include/asm-um/poll.h --- linux.vanilla/include/asm-um/poll.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/poll.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_POLL_H +#define __UM_POLL_H + +#include "asm/arch/poll.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/posix_types.h linux.ac/include/asm-um/posix_types.h --- linux.vanilla/include/asm-um/posix_types.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/posix_types.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_POSIX_TYPES_H +#define __UM_POSIX_TYPES_H + +#include "asm/arch/posix_types.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/processor.h linux.ac/include/asm-um/processor.h --- linux.vanilla/include/asm-um/processor.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/processor.h Sun Apr 15 22:56:45 2001 @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __UM_PROCESSOR_H +#define __UM_PROCESSOR_H + +struct pt_regs; + +struct task_struct; + +#include "asm/segment.h" +#include "asm/ptrace.h" +#include "asm/arch/signal.h" + +struct mm_struct; + +#define current_text_addr() ((void *) 0) + +struct thread_struct { + int extern_pid; + int tracing; + int forking; + unsigned long kernel_stack; + int starting_exec; + struct { + int signal; + unsigned long sp; + unsigned long handler; + } signal; + int npending; + sigset_t saved_sigs; + int nsyscalls; + struct sys_pt_regs process_regs; + struct sys_pt_regs syscall_regs; + struct sys_pt_regs altstack_regs; + void *altstack; + int altstack_size; + unsigned long cr2; + int err; + int repeat_syscall; + int mm_changes; + void *fault_addr; + void *brk; + int sigreturn_syscall; + struct { + int op; + union { + struct { + int pid; + } fork, exec; + struct { + struct task_struct *to; + struct task_struct *from; + } cswitch; + struct { + int (*proc)(void *); + void *arg; + int flags; + int new_pid; + struct task_struct *new_task; + int cpu; + } thread; + struct { + unsigned long stack; + struct sys_pt_regs regs; + struct task_struct *from; + } fork_finish; + struct { + void (*proc)(void *); + void *arg; + } cb; + struct { + int restore_regs; + } tracing; + } u; + } request; +}; + +#define EMPTY_MM \ +{ \ + mmap: NULL, \ + mmap_avl: NULL, \ + mmap_cache: NULL, \ + pgd: NULL, \ + mm_users: { 0 }, \ + mm_count: { 0 }, \ + map_count: 0, \ + page_table_lock:{ }, \ + mmlist: { }, \ + start_code: 0, \ + end_code: 0, \ + start_data: 0, \ + end_data: 0, \ + start_brk: 0, \ + brk: 0, \ + start_stack: 0, \ + arg_start: 0, \ + arg_end: 0, \ + env_start: 0, \ + env_end: 0, \ + rss: 0, \ + total_vm: 0, \ + locked_vm: 0, \ + def_flags: 0, \ + cpu_vm_mask: 0, \ + swap_address: 0, \ + context: { NULL } \ +} + +#define INIT_MMAP \ +{ \ + vm_mm: &init_mm, \ + vm_start: 0, \ + vm_end: 0, \ + vm_next: NULL, \ + vm_page_prot: PAGE_SHARED, \ + vm_flags: VM_READ | VM_WRITE | VM_EXEC, \ + vm_avl_height: 0, \ + vm_avl_left: NULL, \ + vm_avl_right: NULL, \ + vm_next_share: NULL, \ + vm_pprev_share: NULL, \ + vm_ops: NULL, \ + vm_pgoff: 0, \ + vm_file: NULL, \ + vm_raend: 0, \ + vm_private_data:NULL \ +} + +#define INIT_THREAD \ +{ \ + extern_pid: -1, \ + tracing: 0, \ + forking: 0, \ + kernel_stack: 0, \ + starting_exec: 0, \ + signal: { \ + signal: 0, \ + sp: 0, \ + handler:0 \ + }, \ + npending: 0, \ + saved_sigs: { { 0 } }, \ + nsyscalls: 0, \ + process_regs: EMPTY_REGS, \ + syscall_regs: EMPTY_REGS, \ + altstack_regs: EMPTY_REGS, \ + altstack: NULL, \ + altstack_size: 0, \ + cr2: 0, \ + err: 0, \ + repeat_syscall: 0, \ + mm_changes: 0, \ + fault_addr: NULL, \ + brk: NULL, \ + sigreturn_syscall: 0, \ + request: { 0 } \ +} + +#define THREAD_SIZE (2*PAGE_SIZE) + +typedef struct { + unsigned long seg; +} mm_segment_t; + +extern struct task_struct *alloc_task_struct(void); +extern void free_task_struct(struct task_struct *task); + +#define get_task_struct(tsk) atomic_inc(&virt_to_page(tsk)->count) + +extern void release_thread(struct task_struct *); +extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); + +extern void copy_segments(struct task_struct *p, struct mm_struct * mm); +extern void release_segments(struct mm_struct * mm); + +#define forget_segments() do ; while(0) + +extern unsigned long thread_saved_pc(struct thread_struct *t); + +/* +extern unsigned long init_task_ptr; + +#define init_task_u (*((union task_union *) init_task_ptr)) +*/ +#define init_task (init_task_union.task) +#define init_stack (init_task_union.stack) + +/* + * User space process size: 3GB (default). + */ +#define TASK_SIZE (0xc0000000) + +/* This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE (TASK_SIZE / 3) + +extern void start_thread(struct pt_regs *regs, unsigned long entry, + unsigned long stack); + +#ifndef ARCH_CPUINFO +struct cpuinfo_um { + unsigned long loops_per_sec; + unsigned long *pgd_quick; + unsigned long *pmd_quick; + unsigned long *pte_quick; + unsigned long pgtable_cache_sz; +}; +#endif + +extern struct cpuinfo_um boot_cpu_data; + +#define my_cpu_data cpu_data[smp_processor_id()] + +#ifdef __SMP__ +extern struct cpuinfo_um cpu_data[]; +#define current_cpu_data cpu_data[smp_processor_id()] +#else +#define cpu_data (&boot_cpu_data) +#define current_cpu_data boot_cpu_data +#endif + +#define KSTK_EIP(tsk) (0) +#define KSTK_ESP(tsk) (0) +#define get_wchan(p) (0) + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/ptrace.h linux.ac/include/asm-um/ptrace.h --- linux.vanilla/include/asm-um/ptrace.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/ptrace.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,28 @@ +#ifndef __UM_PTRACE_H +#define __UM_PTRACE_H + +#include "asm/current.h" + +#define pt_regs pt_regs_subarch + +#include "asm/arch/ptrace.h" + +#undef pt_regs +#undef user_mode +#undef instruction_pointer + +#include "../../arch/um/include/sysdep/ptrace.h" + +struct pt_regs { int user_mode; }; + +#define user_mode(regs) ((regs)->user_mode) + +struct task_struct; + +extern int putreg(struct task_struct *child, unsigned long regno, + unsigned long value); +unsigned long getreg(struct task_struct *child, unsigned long regno); + +#define INIT_TASK_SIZE (4 * PAGE_SIZE) + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/resource.h linux.ac/include/asm-um/resource.h --- linux.vanilla/include/asm-um/resource.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/resource.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_RESOURCE_H +#define __UM_RESOURCE_H + +#include "asm/arch/resource.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/rwlock.h linux.ac/include/asm-um/rwlock.h --- linux.vanilla/include/asm-um/rwlock.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/rwlock.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_RWLOCK_H +#define __UM_RWLOCK_H + +#include "asm/arch/rwlock.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/scatterlist.h linux.ac/include/asm-um/scatterlist.h --- linux.vanilla/include/asm-um/scatterlist.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/scatterlist.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_SCATTERLIST_H +#define __UM_SCATTERLIST_H + +#include "asm/arch/scatterlist.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/segment.h linux.ac/include/asm-um/segment.h --- linux.vanilla/include/asm-um/segment.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/segment.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,4 @@ +#ifndef __UM_SEGMENT_H +#define __UM_SEGMENT_H + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/semaphore.h linux.ac/include/asm-um/semaphore.h --- linux.vanilla/include/asm-um/semaphore.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/semaphore.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_SEMAPHORE_H +#define __UM_SEMAPHORE_H + +#include "asm/arch/semaphore.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/sembuf.h linux.ac/include/asm-um/sembuf.h --- linux.vanilla/include/asm-um/sembuf.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/sembuf.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_SEMBUF_H +#define __UM_SEMBUF_H + +#include "asm/arch/sembuf.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/serial.h linux.ac/include/asm-um/serial.h --- linux.vanilla/include/asm-um/serial.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/serial.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_SERIAL_H +#define __UM_SERIAL_H + +#include "asm/arch/serial.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/shmbuf.h linux.ac/include/asm-um/shmbuf.h --- linux.vanilla/include/asm-um/shmbuf.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/shmbuf.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_SHMBUF_H +#define __UM_SHMBUF_H + +#include "asm/arch/shmbuf.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/shmparam.h linux.ac/include/asm-um/shmparam.h --- linux.vanilla/include/asm-um/shmparam.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/shmparam.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_SHMPARAM_H +#define __UM_SHMPARAM_H + +#include "asm/arch/shmparam.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/sigcontext.h linux.ac/include/asm-um/sigcontext.h --- linux.vanilla/include/asm-um/sigcontext.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/sigcontext.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_SIGCONTEXT_H +#define __UM_SIGCONTEXT_H + +#include "asm/arch/sigcontext.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/siginfo.h linux.ac/include/asm-um/siginfo.h --- linux.vanilla/include/asm-um/siginfo.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/siginfo.h Mon Apr 9 23:25:02 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_SIGINFO_H +#define __UM_SIGINFO_H + +#include "asm/arch/siginfo.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/signal.h linux.ac/include/asm-um/signal.h --- linux.vanilla/include/asm-um/signal.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/signal.h Mon Apr 9 23:25:03 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_SIGNAL_H +#define __UM_SIGNAL_H + +#include "asm/arch/signal.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/smp.h linux.ac/include/asm-um/smp.h --- linux.vanilla/include/asm-um/smp.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/smp.h Mon Apr 9 23:25:03 2001 @@ -0,0 +1,22 @@ +#ifndef __UM_SMP_H +#define __UM_SMP_H + +#include "asm/current.h" + +#ifdef __SMP__ + +#define smp_processor_id() (current->processor) + +#define cpu_logical_map(n) (n) + +extern int cpu_number_map[]; + +#define PROC_CHANGE_PENALTY 15 /* Pick a number, any number */ + +extern int hard_smp_processor_id(void); + +#define NO_PROC_ID -1 + +#endif + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/smplock.h linux.ac/include/asm-um/smplock.h --- linux.vanilla/include/asm-um/smplock.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/smplock.h Mon Apr 9 23:25:03 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_SMPLOCK_H +#define __UM_SMPLOCK_H + +#include "asm/arch/smplock.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/socket.h linux.ac/include/asm-um/socket.h --- linux.vanilla/include/asm-um/socket.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/socket.h Mon Apr 9 23:25:03 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_SOCKET_H +#define __UM_SOCKET_H + +#include "asm/arch/socket.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/sockios.h linux.ac/include/asm-um/sockios.h --- linux.vanilla/include/asm-um/sockios.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/sockios.h Mon Apr 9 23:25:03 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_SOCKIOS_H +#define __UM_SOCKIOS_H + +#include "asm/arch/sockios.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/softirq.h linux.ac/include/asm-um/softirq.h --- linux.vanilla/include/asm-um/softirq.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/softirq.h Mon Apr 9 23:25:03 2001 @@ -0,0 +1,13 @@ +#ifndef __UM_SOFTIRQ_H +#define __UM_SOFTIRQ_H + +#include "linux/smp.h" +#include "asm/system.h" +#include "asm/processor.h" + +/* A gratuitous name change */ +#define i386_bh_lock um_bh_lock +#include "asm/arch/softirq.h" +#undef i386_bh_lock + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/spinlock.h linux.ac/include/asm-um/spinlock.h --- linux.vanilla/include/asm-um/spinlock.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/spinlock.h Mon Apr 9 23:25:03 2001 @@ -0,0 +1,8 @@ +#ifndef __UM_SPINLOCK_H +#define __UM_SPINLOCK_H + +#ifdef __SMP__ +#include "asm/arch/spinlock.h" +#endif + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/stat.h linux.ac/include/asm-um/stat.h --- linux.vanilla/include/asm-um/stat.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/stat.h Mon Apr 9 23:25:03 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_STAT_H +#define __UM_STAT_H + +#include "asm/arch/stat.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/statfs.h linux.ac/include/asm-um/statfs.h --- linux.vanilla/include/asm-um/statfs.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/statfs.h Mon Apr 9 23:25:03 2001 @@ -0,0 +1,6 @@ +#ifndef _UM_STATFS_H +#define _UM_STATFS_H + +#include "asm/arch/statfs.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/string.h linux.ac/include/asm-um/string.h --- linux.vanilla/include/asm-um/string.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/string.h Mon Apr 9 23:25:03 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_STRING_H +#define __UM_STRING_H + +#include "asm/arch/string.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/system.h linux.ac/include/asm-um/system.h --- linux.vanilla/include/asm-um/system.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/system.h Mon Apr 9 23:25:03 2001 @@ -0,0 +1,49 @@ +#ifndef __UM_SYSTEM_H +#define __UM_SYSTEM_H + +#include "asm/arch/system.h" + +#undef prepare_to_switch +#undef switch_to +#undef __save_flags +#undef save_flags +#undef __restore_flags +#undef restore_flags +#undef __cli +#undef __sti +#undef cli +#undef sti +#undef local_irq_save +#undef local_irq_restore +#undef local_irq_disable +#undef local_irq_enable + +#define prepare_to_switch() do ; while(0) + +void *_switch_to(void *prev, void *next); + +#define switch_to(prev, next, last) prev = _switch_to(prev, next) + +extern int set_signals(int enable); +extern void block_signals(void); +extern void unblock_signals(void); + +#define local_irq_save(flags) do { (flags) = set_signals(0); } while(0) + +#define local_irq_restore(flags) do { set_signals(flags); } while(0) + +#define local_irq_enable() unblock_signals() +#define local_irq_disable() block_signals() + +#define __sti() unblock_signals() +#define sti() unblock_signals() +#define __cli() block_signals() +#define cli() block_signals() + +#define __save_flags(x) local_irq_save(x) +#define save_flags(x) __save_flags(x) + +#define __restore_flags(x) local_irq_restore(x) +#define restore_flags(x) __restore_flags(x) + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/termbits.h linux.ac/include/asm-um/termbits.h --- linux.vanilla/include/asm-um/termbits.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/termbits.h Mon Apr 9 23:25:03 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_TERMBITS_H +#define __UM_TERMBITS_H + +#include "asm/arch/termbits.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/termios.h linux.ac/include/asm-um/termios.h --- linux.vanilla/include/asm-um/termios.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/termios.h Mon Apr 9 23:25:03 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_TERMIOS_H +#define __UM_TERMIOS_H + +#include "asm/arch/termios.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/timex.h linux.ac/include/asm-um/timex.h --- linux.vanilla/include/asm-um/timex.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/timex.h Mon Apr 9 23:25:03 2001 @@ -0,0 +1,15 @@ +#ifndef __UM_TIMEX_H +#define __UM_TIMEX_H + +#include "linux/time.h" + +typedef unsigned long cycles_t; + +#define cacheflush_time (0) + +static inline cycles_t get_cycles (void) +{ + return 0; +} + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/tlb.h linux.ac/include/asm-um/tlb.h --- linux.vanilla/include/asm-um/tlb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/tlb.h Thu Apr 12 17:43:20 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_TLB_H +#define __UM_TLB_H + +#include "asm-generic/tlb.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/types.h linux.ac/include/asm-um/types.h --- linux.vanilla/include/asm-um/types.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/types.h Mon Apr 9 23:25:03 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_TYPES_H +#define __UM_TYPES_H + +#include "asm/arch/types.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/uaccess.h linux.ac/include/asm-um/uaccess.h --- linux.vanilla/include/asm-um/uaccess.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/uaccess.h Mon Apr 9 23:25:03 2001 @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __UM_UACCESS_H +#define __UM_UACCESS_H + +#include "linux/string.h" +#include "asm/processor.h" +#include "asm/errno.h" + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +/* + * The fs value determines whether argument validity checking should be + * performed or not. If get_fs() == USER_DS, checking is performed, with + * get_fs() == KERNEL_DS, checking is bypassed. + * + * For historical reasons, these macros are grossly misnamed. + */ + +#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) + + +#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) +#define USER_DS MAKE_MM_SEG(PAGE_OFFSET) + +#define get_ds() (KERNEL_DS) +#define get_fs() (current->addr_limit) +#define set_fs(x) (current->addr_limit = (x)) + +extern unsigned long end_vm; +extern unsigned long physmem; + +#define overlaps_kernel(addr, size) \ + ((((addr) <= physmem) && ((addr) + (size) > physmem)) || \ + ((physmem <= (addr)) && (end_vm > (addr)))) + +#define access_ok(type, addr, size) \ + (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \ + ((unsigned long) (addr) < TASK_SIZE) && \ + (((unsigned long) (addr) + (size)) < TASK_SIZE)) + +static inline int verify_area(int type, const void * addr, unsigned long size) +{ + return(access_ok(type, addr, size) ? 0 : -EFAULT); +} + +#define segment_eq(a, b) (1) + +extern void *get_fault_addr(void); +extern void set_fault_addr(void *addr); + +static inline int __copy_from_user(void *to, const void *from, int n) +{ + int ret = 0; + + set_fault_addr(&&error); + memcpy(to, from, n); + goto out; + error: + ret = n - ((unsigned long) get_fault_addr() - (unsigned long) from); + out: + set_fault_addr(NULL); + return(ret); +} + +static inline int copy_from_user(void *to, const void *from, int n) +{ + return(access_ok(VERIFY_READ, from, n) ? + __copy_from_user(to, from, n) : \ + n); +} + +static inline int __copy_to_user(void *to, const void *from, int n) +{ + int ret = 0; + + set_fault_addr(&&error); + memcpy(to, from, n); + goto out; + error: + ret = n - ((unsigned long) get_fault_addr() - (unsigned long) to); + out: + set_fault_addr(NULL); + return(ret); +} + +static inline int copy_to_user(void *to, const void *from, int n) +{ + return(access_ok(VERIFY_WRITE, to, n) ? + __copy_from_user(to, from, n) : \ + n); +} + +#define __get_user(x, ptr) \ +({ \ + __label__ out; \ + __typeof__(ptr) __private_ptr = ptr; \ + __typeof__(*(__private_ptr)) __private_val; \ + int __private_ret = -EFAULT; \ + (x) = 0; \ + current->thread.fault_addr = &&out; \ + memcpy(&__private_val, (__private_ptr), sizeof(*(__private_ptr))); \ + (x) = (__typeof__(*(__private_ptr))) __private_val; \ + __private_ret = 0; \ + out: \ + current->thread.fault_addr = NULL; \ + __private_ret; \ +}) + +#define get_user(x, ptr) \ +({ \ + __typeof__((*ptr)) *private_ptr = (ptr); \ + (access_ok(VERIFY_READ, private_ptr, sizeof(x)) ? \ + __get_user(x, private_ptr) : ((x) = 0, -EFAULT)); \ +}) + +#define __put_user(x, ptr) \ +({ \ + __label__ out; \ + __typeof__(ptr) __private_ptr = ptr; \ + __typeof__(*(__private_ptr)) __private_val; \ + int __private_ret = -EFAULT; \ + current->thread.fault_addr = &&out; \ + __private_val = (__typeof__(*(__private_ptr))) (x); \ + memcpy((__private_ptr), &__private_val, sizeof(*(__private_ptr))); \ + __private_ret = 0; \ + out: \ + current->thread.fault_addr = NULL; \ + __private_ret; \ +}) + +#define put_user(x, ptr) \ +({ \ + __typeof__(*(ptr)) *private_ptr = (ptr); \ + (access_ok(VERIFY_WRITE, private_ptr, sizeof(x)) ? \ + __put_user(x, private_ptr) : -EFAULT); \ +}) + +#define __strncpy_from_user(dst, src, count) \ +({ __label__ out; \ + int __private_ret = -EFAULT; \ + current->thread.fault_addr = &&out; \ + strncpy(dst, src, count); \ + __private_ret = strlen(dst); \ + out: \ + current->thread.fault_addr = NULL; \ + __private_ret; \ +}) + +#define strncpy_from_user(dst, src, count) \ + (access_ok(VERIFY_READ, src, 1) ? \ + __strncpy_from_user(dst, src, count) : \ + -EFAULT) + +#define __clear_user(mem, len) \ +({ __label__ error, out; \ + int __private_ret = 0; \ + current->thread.fault_addr = &&error; \ + memset((mem), 0, (len)); \ + goto out; \ + error: \ + __private_ret = (len) - ((unsigned long) current->thread.fault_addr - \ + (unsigned long) (mem)); \ + out: \ + current->thread.fault_addr = NULL; \ + __private_ret; \ +}) + +#define clear_user(mem, len) \ + (access_ok(VERIFY_WRITE, mem, len) ? __clear_user(mem, len) : len) + +#define strnlen_user(str, n) \ +({ __label__ out, error; \ + int __private_ret = 0; \ + current->thread.fault_addr = &&error; \ + __private_ret = strlen(str) + 1; \ + goto out; \ + error: \ + __private_ret = (unsigned long) current->thread.fault_addr - \ + (unsigned long) str; \ + out: \ + current->thread.fault_addr = NULL; \ + __private_ret; \ +}) + + +#define strlen_user(str) strnlen_user(str, ~0UL >> 1) + +struct exception_table_entry +{ + unsigned long unused; +}; + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/unaligned.h linux.ac/include/asm-um/unaligned.h --- linux.vanilla/include/asm-um/unaligned.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/unaligned.h Mon Apr 9 23:25:03 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_UNALIGNED_H +#define __UM_UNALIGNED_H + +#include "asm/arch/unaligned.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/unistd.h linux.ac/include/asm-um/unistd.h --- linux.vanilla/include/asm-um/unistd.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/unistd.h Mon Apr 9 23:25:03 2001 @@ -0,0 +1,53 @@ +#ifndef _UM_UNISTD_H_ +#define _UM_UNISTD_H_ + +#include "linux/types.h" + +extern void start_kernel(void); +extern int idle(void); +extern int um_execve(char *file, char **argv, char **env); +#define execve(file, argv, env) um_execve(file, argv, env) + +extern long sys_open(const char *file, int flags, int mode); + +static inline long open(const char *file, int flags, int mode) +{ + return(sys_open(file, flags, mode)); +} + +extern int sys_dup(unsigned int fd); + +static inline long dup(unsigned int fd) +{ + return(sys_dup(fd)); +} + +extern long sys_close(unsigned int fd); + +static inline long um_close(unsigned int fd) +{ + return(sys_close(fd)); +} + +#define close(fd) um_close(fd) + +extern long sys_waitpid(pid_t pid, unsigned int * stat_addr, int options); + +static inline long waitpid(pid_t pid, unsigned int * stat_addr, int options) +{ + return(sys_waitpid(pid, stat_addr, options)); +} + +#ifdef __KERNEL_SYSCALLS__ +#define __SAVE_KERNEL_SYSCALLS__ __KERNEL_SYSCALLS__ +#endif + +#undef __KERNEL_SYSCALLS__ + +#include "asm/arch/unistd.h" + +#ifdef __SAVE_KERNEL_SYSCALLS__ +#define __KERNEL_SYSCALLS__ __SAVE_KERNEL_SYSCALLS__ +#endif + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/user.h linux.ac/include/asm-um/user.h --- linux.vanilla/include/asm-um/user.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/user.h Mon Apr 9 23:25:03 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_USER_H +#define __UM_USER_H + +#include "asm/arch/user.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-um/vga.h linux.ac/include/asm-um/vga.h --- linux.vanilla/include/asm-um/vga.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-um/vga.h Mon Apr 9 23:25:03 2001 @@ -0,0 +1,6 @@ +#ifndef __UM_VGA_H +#define __UM_VGA_H + +#include "asm/arch/vga.h" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/ac97_codec.h linux.ac/include/linux/ac97_codec.h --- linux.vanilla/include/linux/ac97_codec.h Thu Feb 22 00:11:22 2001 +++ linux.ac/include/linux/ac97_codec.h Tue Apr 10 18:22:56 2001 @@ -133,7 +133,15 @@ SOUND_MASK_LINE1| SOUND_MASK_LINE|\ SOUND_MASK_PHONEIN) -#define supported_mixer(CODEC,FOO) ((CODEC)->supported_mixers & (1<<FOO) ) +/* original check is not good enough in case FOO is greater than + * SOUND_MIXER_NRDEVICES because the supported_mixers has exactly + * SOUND_MIXER_NRDEVICES elements. + * before matching the given mixer against the bitmask in supported_mixers we + * check if mixer number exceeds maximum allowed size which is as mentioned + * above SOUND_MIXER_NRDEVICES */ +#define supported_mixer(CODEC,FOO) ((FOO >= 0) && \ + (FOO < SOUND_MIXER_NRDEVICES) && \ + (CODEC)->supported_mixers & (1<<FOO) ) struct ac97_codec { /* AC97 controller connected with */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/apm_bios.h linux.ac/include/linux/apm_bios.h --- linux.vanilla/include/linux/apm_bios.h Thu Dec 7 05:00:13 2000 +++ linux.ac/include/linux/apm_bios.h Tue Apr 10 18:22:56 2001 @@ -3,7 +3,7 @@ /* * Include file for the interface to an APM BIOS - * Copyright 1994-2000 Stephen Rothwell (sfr@linuxcare.com) + * Copyright 1994-2001 Stephen Rothwell (sfr@canb.auug.org.au) * * 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 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/binfmts.h linux.ac/include/linux/binfmts.h --- linux.vanilla/include/linux/binfmts.h Thu Feb 22 00:09:58 2001 +++ linux.ac/include/linux/binfmts.h Sun Apr 15 23:20:10 2001 @@ -41,7 +41,8 @@ struct module *module; int (*load_binary)(struct linux_binprm *, struct pt_regs * regs); int (*load_shlib)(struct file *); - int (*core_dump)(long signr, struct pt_regs * regs, struct file * file); + int (*core_dump)(long signr, struct pt_regs * regs, + struct file * file, struct mm_struct *mm); unsigned long min_coredump; /* minimal dump size */ }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/blk.h linux.ac/include/linux/blk.h --- linux.vanilla/include/linux/blk.h Thu Feb 22 00:10:37 2001 +++ linux.ac/include/linux/blk.h Tue Apr 17 17:44:38 2001 @@ -42,7 +42,6 @@ extern int swimiop_init(void); extern int amiga_floppy_init(void); extern int atari_floppy_init(void); -extern int nbd_init(void); extern int ez_init(void); extern int bpcd_init(void); extern int ps2esdi_init(void); @@ -51,6 +50,7 @@ #if defined(CONFIG_ARCH_S390) extern int mdisk_init(void); extern int dasd_init(void); +extern int xpram_init(void); #endif /* CONFIG_ARCH_S390 */ extern void set_device_ro(kdev_t dev,int flag); @@ -320,6 +320,15 @@ #define TIMEOUT_VALUE (25*HZ) #define DEVICE_REQUEST do_ida_request #define DEVICE_NR(device) (MINOR(device) >> 4) + +#elif (MAJOR_NR == UBD_MAJOR) + +#define DEVICE_NAME "User-mode block device" +#define DEVICE_INTR do_ubd +#define DEVICE_REQUEST do_ubd_request +#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) #endif /* MAJOR_NR == whatever */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/blkdev.h linux.ac/include/linux/blkdev.h --- linux.vanilla/include/linux/blkdev.h Tue Apr 3 17:32:28 2001 +++ linux.ac/include/linux/blkdev.h Sun Apr 15 23:20:10 2001 @@ -146,7 +146,6 @@ */ #define BLK_DEFAULT_QUEUE(_MAJOR) &blk_dev[_MAJOR].request_queue -extern struct sec_size * blk_sec[MAX_BLKDEV]; extern struct blk_dev_struct blk_dev[MAX_BLKDEV]; extern void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size); extern void register_disk(struct gendisk *dev, kdev_t first, unsigned minors, struct block_device_operations *ops, long size); @@ -161,7 +160,6 @@ extern void blk_init_queue(request_queue_t *, request_fn_proc *); extern void blk_cleanup_queue(request_queue_t *); extern void blk_queue_headactive(request_queue_t *, int); -extern void blk_queue_pluggable(request_queue_t *, plug_device_fn *); extern void blk_queue_make_request(request_queue_t *, make_request_fn *); extern void generic_unplug_device(void *); @@ -174,8 +172,6 @@ extern int * max_readahead[MAX_BLKDEV]; extern int * max_sectors[MAX_BLKDEV]; - -extern int * max_segments[MAX_BLKDEV]; extern atomic_t queued_sectors; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/cdrom.h linux.ac/include/linux/cdrom.h --- linux.vanilla/include/linux/cdrom.h Tue Apr 3 17:32:28 2001 +++ linux.ac/include/linux/cdrom.h Sun Apr 15 23:20:46 2001 @@ -128,8 +128,13 @@ #define CDROM_DEBUG 0x5330 /* Turn debug messages on/off */ #define CDROM_GET_CAPABILITY 0x5331 /* get capabilities */ +/* Note that scsi/scsi_ioctl.h also uses 0x5382 - 0x5386. + * Future CDROM ioctls should be kept below 0x537F + */ + /* This ioctl is only used by sbpcd at the moment */ #define CDROMAUDIOBUFSIZ 0x5382 /* set the audio buffer size */ + /* conflict with SCSI_IOCTL_GET_IDLUN */ /* DVD-ROM Specific ioctls */ #define DVD_READ_STRUCT 0x5390 /* Read structure */ @@ -785,8 +790,8 @@ } tracktype; extern void cdrom_count_tracks(struct cdrom_device_info *cdi,tracktype* tracks); -extern int cdrom_get_next_writable(kdev_t dev, long *next_writable); -extern int cdrom_get_last_written(kdev_t dev, long *last_written); +extern int cdrom_get_next_writable(kdev_t dev, unsigned int *next_writable); +extern int cdrom_get_last_written(kdev_t dev, unsigned int *last_written); extern int cdrom_number_of_slots(struct cdrom_device_info *cdi); extern int cdrom_select_disc(struct cdrom_device_info *cdi, int slot); extern int cdrom_mode_select(struct cdrom_device_info *cdi, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/coff.h linux.ac/include/linux/coff.h --- linux.vanilla/include/linux/coff.h Wed Aug 10 17:26:42 1994 +++ linux.ac/include/linux/coff.h Tue Apr 10 18:22:56 2001 @@ -1,5 +1,5 @@ /* This file is derived from the GAS 2.1.4 assembler control file. - The GAS product is under the GNU Public License, version 2 or later. + The GAS product is under the GNU General Public License, version 2 or later. As such, this file is also under that license. If the file format changes in the COFF object, this file should be diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/com20020.h linux.ac/include/linux/com20020.h --- linux.vanilla/include/linux/com20020.h Tue May 2 20:36:09 2000 +++ linux.ac/include/linux/com20020.h Tue Apr 10 18:22:56 2001 @@ -15,7 +15,7 @@ * skeleton.c Written 1993 by Donald Becker. * Copyright 1993 United States Government as represented by the * Director, National Security Agency. This software may only be used - * and distributed according to the terms of the GNU Public License as + * and distributed according to the terms of the GNU General Public License as * modified by SRC, incorporated herein by reference. * * ********************** diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/console.h linux.ac/include/linux/console.h --- linux.vanilla/include/linux/console.h Thu Feb 22 00:09:57 2001 +++ linux.ac/include/linux/console.h Sat Apr 14 15:05:48 2001 @@ -91,8 +91,6 @@ #define CON_CONSDEV (2) /* Last on the command line */ #define CON_ENABLED (4) -extern spinlock_t console_lock; - struct console { char name[8]; @@ -111,6 +109,9 @@ extern void register_console(struct console *); extern int unregister_console(struct console *); extern struct console *console_drivers; +extern void acquire_console_sem(void); +extern void release_console_sem(void); +extern void console_conditional_schedule(void); /* VESA Blanking Levels */ #define VESA_NO_BLANKING 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/dcache.h linux.ac/include/linux/dcache.h --- linux.vanilla/include/linux/dcache.h Tue Apr 3 17:32:28 2001 +++ linux.ac/include/linux/dcache.h Sun Apr 15 23:04:43 2001 @@ -65,7 +65,7 @@ struct dentry { atomic_t d_count; - unsigned int d_flags; + unsigned long d_flags; struct inode * d_inode; /* Where the name belongs to - NULL is negative */ struct dentry * d_parent; /* parent directory */ struct list_head d_vfsmnt; @@ -111,18 +111,20 @@ */ /* d_flags entries */ -#define DCACHE_AUTOFS_PENDING 0x0001 /* autofs: "under construction" */ -#define DCACHE_NFSFS_RENAMED 0x0002 /* this dentry has been "silly - * renamed" and has to be - * deleted on the last dput() - */ -#define DCACHE_NFSD_DISCONNECTED 0x0004 /* This dentry is not currently connected to the - * dcache tree. Its parent will either be itself, - * or will have this flag as well. - * If this dentry points to a directory, then - * s_nfsd_free_path semaphore will be down - */ -#define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */ +enum { + D_Autofs_Pending, /* autofs: "under construction" */ + D_NFS_Renamed, /* this dentry has been "silly + * renamed" and has to be + * deleted on the last dput() + */ + D_Disconnected, /* This dentry is not currently connected to + * the dcache tree. Its parent will either be + * itself, or will have this flag as well. + * If this dentry points to a directory, then + * s_nfsd_free_path semaphore will be down + */ + D_Referenced, /* Recently used, don't discard. */ +}; extern spinlock_t dcache_lock; @@ -177,6 +179,10 @@ /* icache memory management (defined in linux/fs/inode.c) */ extern void shrink_icache_memory(int, int); extern void prune_icache(int); + +/* quota cache memory management (defined in linux/fs/dquot.c) */ +extern void shrink_dqcache_memory(int, unsigned int); +extern void prune_dqcache(int); /* only used at mount-time */ extern struct dentry * d_alloc_root(struct inode *); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/elf.h linux.ac/include/linux/elf.h --- linux.vanilla/include/linux/elf.h Tue Apr 3 17:32:28 2001 +++ linux.ac/include/linux/elf.h Mon Apr 9 23:39:31 2001 @@ -16,8 +16,10 @@ typedef __u16 Elf64_Half; typedef __s16 Elf64_SHalf; typedef __u64 Elf64_Off; -typedef __s64 Elf64_Sword; -typedef __u64 Elf64_Word; +typedef __s32 Elf64_Sword; +typedef __u32 Elf64_Word; +typedef __u64 Elf64_Xword; +typedef __s64 Elf64_Sxword; /* These constants are for the segment types stored in the image headers */ #define PT_NULL 0 @@ -74,6 +76,8 @@ #define EM_X8664 62 /* AMD x86-64 */ +#define EM_S390 22 /* IBM S/390 */ + #define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ /* @@ -83,9 +87,9 @@ #define EM_ALPHA 0x9026 /* - * This is an interim value for S390 architecture + * This is the old interim value for S/390 architecture */ -#define EM_S390 0xA390 +#define EM_S390_OLD 0xA390 /* This is the info that is needed to parse the dynamic section of the file */ #define DT_NULL 0 @@ -178,10 +182,10 @@ } Elf32_Dyn; typedef struct { - Elf64_Word d_tag; /* entry tag value */ + Elf64_Sxword d_tag; /* entry tag value */ union { - Elf64_Word d_val; - Elf64_Word d_ptr; + Elf64_Xword d_val; + Elf64_Addr d_ptr; } d_un; } Elf64_Dyn; @@ -227,7 +231,7 @@ #define R_MIPS_GOT_PAGE 20 #define R_MIPS_GOT_OFST 21 /* - * The following two relocation types are specified in the the MIPS ABI + * The following two relocation types are specified in the MIPS ABI * conformance guide version 1.2 but not yet in the psABI. */ #define R_MIPS_GOTHI16 22 @@ -239,7 +243,7 @@ #define R_MIPS_HIGHER 28 #define R_MIPS_HIGHEST 29 /* - * The following two relocation types are specified in the the MIPS ABI + * The following two relocation types are specified in the MIPS ABI * conformance guide version 1.2 but not yet in the psABI. */ #define R_MIPS_CALLHI16 30 @@ -372,7 +376,7 @@ typedef struct elf64_rel { Elf64_Addr r_offset; /* Location at which to apply the action */ - Elf64_Word r_info; /* index and type of relocation */ + Elf64_Xword r_info; /* index and type of relocation */ } Elf64_Rel; typedef struct elf32_rela{ @@ -383,8 +387,8 @@ typedef struct elf64_rela { Elf64_Addr r_offset; /* Location at which to apply the action */ - Elf64_Word r_info; /* index and type of relocation */ - Elf64_Word r_addend; /* Constant addend used to compute value */ + Elf64_Xword r_info; /* index and type of relocation */ + Elf64_Sxword r_addend; /* Constant addend used to compute value */ } Elf64_Rela; typedef struct elf32_sym{ @@ -397,12 +401,12 @@ } Elf32_Sym; typedef struct elf64_sym { - Elf32_Word st_name; /* Symbol name, index in string tbl (yes, Elf32) */ + Elf64_Word st_name; /* Symbol name, index in string tbl */ unsigned char st_info; /* Type and binding attributes */ unsigned char st_other; /* No defined meaning, 0 */ Elf64_Half st_shndx; /* Associated section index */ Elf64_Addr st_value; /* Value of the symbol */ - Elf64_Word st_size; /* Associated symbol size */ + Elf64_Xword st_size; /* Associated symbol size */ } Elf64_Sym; @@ -427,19 +431,19 @@ typedef struct elf64_hdr { unsigned char e_ident[16]; /* ELF "magic number" */ - Elf64_SHalf e_type; + Elf64_Half e_type; Elf64_Half e_machine; - __s32 e_version; + Elf64_Word e_version; Elf64_Addr e_entry; /* Entry point virtual address */ Elf64_Off e_phoff; /* Program header table file offset */ Elf64_Off e_shoff; /* Section header table file offset */ - __s32 e_flags; - Elf64_SHalf e_ehsize; - Elf64_SHalf e_phentsize; - Elf64_SHalf e_phnum; - Elf64_SHalf e_shentsize; - Elf64_SHalf e_shnum; - Elf64_SHalf e_shstrndx; + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; } Elf64_Ehdr; /* These constants define the permissions on sections in the program @@ -460,14 +464,14 @@ } Elf32_Phdr; typedef struct elf64_phdr { - __s32 p_type; - __s32 p_flags; + Elf64_Word p_type; + Elf64_Word p_flags; Elf64_Off p_offset; /* Segment file offset */ Elf64_Addr p_vaddr; /* Segment virtual address */ Elf64_Addr p_paddr; /* Segment physical address */ - Elf64_Word p_filesz; /* Segment size in file */ - Elf64_Word p_memsz; /* Segment size in memory */ - Elf64_Word p_align; /* Segment alignment, file & memory */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment, file & memory */ } Elf64_Phdr; /* sh_type */ @@ -524,16 +528,16 @@ } Elf32_Shdr; typedef struct elf64_shdr { - Elf32_Word sh_name; /* Section name, index in string tbl (yes Elf32) */ - Elf32_Word sh_type; /* Type of section (yes Elf32) */ - Elf64_Word sh_flags; /* Miscellaneous section attributes */ + Elf64_Word sh_name; /* Section name, index in string tbl */ + Elf64_Word sh_type; /* Type of section */ + Elf64_Xword sh_flags; /* Miscellaneous section attributes */ Elf64_Addr sh_addr; /* Section virtual addr at execution */ Elf64_Off sh_offset; /* Section file offset */ - Elf64_Word sh_size; /* Size of section in bytes */ - Elf32_Word sh_link; /* Index of another section (yes Elf32) */ - Elf32_Word sh_info; /* Additional section information (yes Elf32) */ - Elf64_Word sh_addralign; /* Section alignment */ - Elf64_Word sh_entsize; /* Entry size if section holds table */ + Elf64_Xword sh_size; /* Size of section in bytes */ + Elf64_Word sh_link; /* Index of another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ } Elf64_Shdr; #define EI_MAG0 0 /* e_ident[] indexes */ @@ -580,15 +584,10 @@ } Elf32_Nhdr; /* Note header in a PT_NOTE section */ -/* - * For now we use the 32 bit version of the structure until we figure - * out whether we need anything better. Note - on the Alpha, "unsigned int" - * is only 32 bits. - */ typedef struct elf64_note { - Elf32_Word n_namesz; /* Name size */ - Elf32_Word n_descsz; /* Content size */ - Elf32_Word n_type; /* Content type */ + Elf64_Word n_namesz; /* Name size */ + Elf64_Word n_descsz; /* Content size */ + Elf64_Word n_type; /* Content type */ } Elf64_Nhdr; #if ELF_CLASS == ELFCLASS32 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/ext2_fs.h linux.ac/include/linux/ext2_fs.h --- linux.vanilla/include/linux/ext2_fs.h Thu Feb 22 00:09:57 2001 +++ linux.ac/include/linux/ext2_fs.h Tue Apr 3 18:11:45 2001 @@ -538,9 +538,9 @@ /* balloc.c */ extern int ext2_bg_has_super(struct super_block *sb, int group); extern unsigned long ext2_bg_num_gdb(struct super_block *sb, int group); -extern int ext2_new_block (const struct inode *, unsigned long, +extern int ext2_new_block (struct inode *, unsigned long, __u32 *, __u32 *, int *); -extern void ext2_free_blocks (const struct inode *, unsigned long, +extern void ext2_free_blocks (struct inode *, unsigned long, unsigned long); extern unsigned long ext2_count_free_blocks (struct super_block *); extern void ext2_check_blocks_bitmap (struct super_block *); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/fs.h linux.ac/include/linux/fs.h --- linux.vanilla/include/linux/fs.h Tue Apr 3 17:32:28 2001 +++ linux.ac/include/linux/fs.h Sun Apr 15 23:20:10 2001 @@ -23,7 +23,6 @@ #include <linux/string.h> #include <asm/atomic.h> -#include <asm/bitops.h> struct poll_table_struct; @@ -198,6 +197,7 @@ #include <asm/semaphore.h> #include <asm/byteorder.h> +#include <asm/bitops.h> extern void update_atime (struct inode *); #define UPDATE_ATIME(inode) update_atime (inode) @@ -367,6 +367,7 @@ int (*sync_page)(struct page *); int (*prepare_write)(struct file *, struct page *, unsigned, unsigned); int (*commit_write)(struct file *, struct page *, unsigned, unsigned); + void (*truncatepage)(struct page *); /* called from truncate_complete_page */ /* Unfortunately this kludge is needed for FIBMAP. Don't use it */ int (*bmap)(struct address_space *, long); }; @@ -416,6 +417,7 @@ unsigned long i_blksize; unsigned long i_blocks; unsigned long i_version; + unsigned short i_bytes; struct semaphore i_sem; struct semaphore i_zombie; struct inode_operations *i_op; @@ -572,6 +574,7 @@ extern struct file_lock *posix_test_lock(struct file *, struct file_lock *); extern int posix_lock_file(struct file *, struct file_lock *, unsigned int); extern void posix_block_lock(struct file_lock *, struct file_lock *); +extern int posix_locks_deadlock(struct file_lock *, struct file_lock *); extern void posix_unblock_lock(struct file_lock *); extern int __get_lease(struct inode *inode, unsigned int flags); extern time_t lease_get_mtime(struct inode *); @@ -605,15 +608,13 @@ #define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */ #define DQUOT_GRP_ENABLED 0x02 /* Group diskquotas enabled */ -struct quota_mount_options +struct quota_info { unsigned int flags; /* Flags for diskquotas on this device */ struct semaphore dqio_sem; /* lock device while I/O in progress */ struct semaphore dqoff_sem; /* serialize quota_off() and quota_on() on device */ struct file *files[MAXQUOTAS]; /* fp's to quotafiles */ - time_t inode_expire[MAXQUOTAS]; /* expiretime for inode-quota */ - time_t block_expire[MAXQUOTAS]; /* expiretime for block-quota */ - char rsquash[MAXQUOTAS]; /* for quotas threat root as any other user */ + struct mem_dqinfo info[MAXQUOTAS]; /* Information for each quota type */ }; /* @@ -668,7 +669,7 @@ struct block_device *s_bdev; struct list_head s_mounts; /* vfsmount(s) of this one */ - struct quota_mount_options s_dquot; /* Diskquota specific options */ + struct quota_info s_dquot; /* Diskquota specific options */ union { struct minix_sb_info minix_sb; @@ -774,6 +775,8 @@ int (*lock) (struct file *, int, struct file_lock *); ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); + ssize_t (*writepage) (struct file *, struct page *, int, size_t, loff_t *, int); + unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); }; struct inode_operations { @@ -845,6 +848,39 @@ __mark_inode_dirty(inode, I_DIRTY_SYNC); } +static inline void inode_add_bytes(struct inode *inode, loff_t bytes) +{ + inode->i_blocks += bytes >> 9; + bytes &= 511; + inode->i_bytes += bytes; + if (inode->i_bytes >= 512) { + inode->i_blocks++; + inode->i_bytes -= 512; + } +} + +static inline void inode_sub_bytes(struct inode *inode, loff_t bytes) +{ + inode->i_blocks -= bytes >> 9; + bytes &= 511; + if (inode->i_bytes < bytes) { + inode->i_blocks--; + inode->i_bytes += 512; + } + inode->i_bytes -= bytes; +} + +static inline loff_t inode_get_bytes(struct inode *inode) +{ + return (((loff_t)inode->i_blocks) << 9) + inode->i_bytes; +} + +static inline void inode_set_bytes(struct inode *inode, loff_t bytes) +{ + inode->i_blocks = bytes >> 9; + inode->i_bytes = bytes & 511; +} + static inline void mark_inode_dirty_pages(struct inode *inode) { __mark_inode_dirty(inode, I_DIRTY_PAGES); @@ -853,11 +889,11 @@ struct dquot_operations { void (*initialize) (struct inode *, short); void (*drop) (struct inode *); - int (*alloc_block) (const struct inode *, unsigned long, char); + int (*alloc_space) (struct inode *, qsize_t, char); int (*alloc_inode) (const struct inode *, unsigned long); - void (*free_block) (const struct inode *, unsigned long); + void (*free_space) (struct inode *, qsize_t); void (*free_inode) (const struct inode *, unsigned long); - int (*transfer) (struct dentry *, struct iattr *); + int (*transfer) (struct inode *, struct iattr *); }; struct file_system_type { @@ -1225,6 +1261,7 @@ } return inode; } +extern void remove_suid(struct inode *inode); extern void insert_inode_hash(struct inode *); extern void remove_inode_hash(struct inode *); @@ -1272,11 +1309,13 @@ int block_truncate_page(struct address_space *, loff_t, get_block_t *); extern int generic_file_mmap(struct file *, struct vm_area_struct *); +extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size); extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *); extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *); extern void do_generic_file_read(struct file *, loff_t *, read_descriptor_t *, read_actor_t); extern ssize_t generic_read_dir(struct file *, char *, size_t, loff_t *); +extern int generic_file_open(struct inode *, struct file *); extern struct file_operations generic_ro_fops; @@ -1319,7 +1358,7 @@ extern int generic_osync_inode(struct inode *, int); extern int inode_change_ok(struct inode *, struct iattr *); -extern void inode_setattr(struct inode *, struct iattr *); +extern int inode_setattr(struct inode *, struct iattr *); /* * Common dentry functions for inclusion in the VFS diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/genhd.h linux.ac/include/linux/genhd.h --- linux.vanilla/include/linux/genhd.h Tue Apr 3 17:32:28 2001 +++ linux.ac/include/linux/genhd.h Sun Apr 15 23:20:10 2001 @@ -82,22 +82,22 @@ struct solaris_x86_slice { ushort s_tag; /* ID tag of partition */ - ushort s_flag; /* permision flags */ - daddr_t s_start; /* start sector no of partition */ - long s_size; /* # of blocks in partition */ + ushort s_flag; /* permission flags */ + unsigned int s_start; /* start sector no of partition */ + unsigned int s_size; /* # of blocks in partition */ }; struct solaris_x86_vtoc { - unsigned long v_bootinfo[3]; /* info needed by mboot (unsupported) */ - unsigned long v_sanity; /* to verify vtoc sanity */ - unsigned long v_version; /* layout version */ + unsigned int v_bootinfo[3]; /* info needed by mboot (unsupported) */ + unsigned int v_sanity; /* to verify vtoc sanity */ + unsigned int v_version; /* layout version */ char v_volume[8]; /* volume name */ ushort v_sectorsz; /* sector size in bytes */ ushort v_nparts; /* number of partitions */ - unsigned long v_reserved[10]; /* free space */ + unsigned int v_reserved[10]; /* free space */ struct solaris_x86_slice v_slice[SOLARIS_X86_NUMSLICE]; /* slice headers */ - time_t timestamp[SOLARIS_X86_NUMSLICE]; /* timestamp (unsupported) */ + unsigned int timestamp[SOLARIS_X86_NUMSLICE]; /* timestamp (unsupported) */ char v_asciilabel[128]; /* for compatibility */ }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/i2o.h linux.ac/include/linux/i2o.h --- linux.vanilla/include/linux/i2o.h Mon Dec 11 21:20:00 2000 +++ linux.ac/include/linux/i2o.h Sat Apr 14 19:38:45 2001 @@ -69,6 +69,7 @@ struct i2o_controller *controller; /* Controlling IOP */ struct i2o_device *next; /* Chain */ + struct i2o_device *prev; char dev_name[8]; /* linux /dev name if available */ }; @@ -78,6 +79,7 @@ struct i2o_pci { int irq; + int fc920:1; #ifdef CONFIG_MTRR int mtrr_reg0; int mtrr_reg1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/icmp.h linux.ac/include/linux/icmp.h --- linux.vanilla/include/linux/icmp.h Thu Feb 22 00:09:57 2001 +++ linux.ac/include/linux/icmp.h Sat Apr 14 01:40:52 2001 @@ -80,30 +80,6 @@ } un; }; -#ifdef __KERNEL__ - -#include <linux/ip.h> - -/* - * Build xmit assembly blocks - */ - -struct icmp_bxm -{ - void *data_ptr; - int data_len; - struct icmphdr icmph; - unsigned long csum; - struct ip_options replyopts; - unsigned char optbuf[40]; -}; - -struct sk_buff; - -extern void icmp_reply(struct icmp_bxm *, struct sk_buff *); - -#endif - /* * constants for (set|get)sockopt */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/icmpv6.h linux.ac/include/linux/icmpv6.h --- linux.vanilla/include/linux/icmpv6.h Thu Feb 22 00:10:24 2001 +++ linux.ac/include/linux/icmpv6.h Tue Apr 17 17:44:38 2001 @@ -143,7 +143,7 @@ int *err); extern void icmpv6_cleanup(void); extern void icmpv6_param_prob(struct sk_buff *skb, - int code, void *pos); + int code, int pos); #endif #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/ide.h linux.ac/include/linux/ide.h --- linux.vanilla/include/linux/ide.h Thu Feb 22 00:11:02 2001 +++ linux.ac/include/linux/ide.h Tue Apr 17 17:47:40 2001 @@ -648,6 +648,7 @@ extern ide_module_t *ide_modules; extern ide_module_t *ide_probe; #endif +extern int noautodma; /* * We need blk.h, but we replace its end_request by our own version. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/if_arp.h linux.ac/include/linux/if_arp.h --- linux.vanilla/include/linux/if_arp.h Tue Apr 3 17:32:28 2001 +++ linux.ac/include/linux/if_arp.h Tue Apr 17 17:44:38 2001 @@ -73,7 +73,7 @@ #define ARPHRD_ECONET 782 /* Acorn Econet */ #define ARPHRD_IRDA 783 /* Linux-IrDA */ /* ARP works differently on different FC media .. so */ -#define ARPHRD_FCPP 784 /* Point to point fibrechanel */ +#define ARPHRD_FCPP 784 /* Point to point fibrechannel */ #define ARPHRD_FCAL 785 /* Fibrechannel arbitrated loop */ #define ARPHRD_FCPL 786 /* Fibrechannel public loop */ #define ARPHRD_FCFABRIC 787 /* Fibrechannel fabric */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/if_ec.h linux.ac/include/linux/if_ec.h --- linux.vanilla/include/linux/if_ec.h Thu Mar 9 14:57:17 2000 +++ linux.ac/include/linux/if_ec.h Tue Apr 3 17:55:16 2001 @@ -60,9 +60,6 @@ unsigned char station, net; /* Econet protocol address */ }; -extern struct sock *ec_listening_socket(unsigned char port, unsigned char - station, unsigned char net); - #endif #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/if_packet.h linux.ac/include/linux/if_packet.h --- linux.vanilla/include/linux/if_packet.h Thu Aug 10 21:01:26 2000 +++ linux.ac/include/linux/if_packet.h Sat Apr 14 01:41:00 2001 @@ -53,6 +53,7 @@ #define TP_STATUS_USER 1 #define TP_STATUS_COPY 2 #define TP_STATUS_LOSING 4 +#define TP_STATUS_CSUMNOTREADY 8 unsigned int tp_len; unsigned int tp_snaplen; unsigned short tp_mac; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/if_wanpipe.h linux.ac/include/linux/if_wanpipe.h --- linux.vanilla/include/linux/if_wanpipe.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/linux/if_wanpipe.h Sat Apr 14 19:14:22 2001 @@ -0,0 +1,128 @@ +/***************************************************************************** +* if_wanpipe.h Header file for the Sangoma AF_WANPIPE Socket +* +* Author: Nenad Corbic +* +* Copyright: (c) 2000 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* +* Jan 28, 2000 Nenad Corbic Initial Version +* +*****************************************************************************/ + +#ifndef __LINUX_IF_WAN_PACKET_H +#define __LINUX_IF_WAN_PACKET_H + +struct wan_sockaddr_ll +{ + unsigned short sll_family; + unsigned short sll_protocol; + int sll_ifindex; + unsigned short sll_hatype; + unsigned char sll_pkttype; + unsigned char sll_halen; + unsigned char sll_addr[8]; + unsigned char sll_device[14]; + unsigned char sll_card[14]; +}; + +typedef struct +{ + unsigned char free; + unsigned char sk_state; + int rcvbuf; + int sndbuf; + int rmem; + int wmem; + int sk_count; + unsigned char bound; + char name[14]; + unsigned char d_state; + unsigned char svc; + unsigned short lcn; + unsigned char mbox; + unsigned char cmd_busy; + unsigned char command; + unsigned poll; + unsigned poll_cnt; + int rblock; +} wan_debug_hdr_t; + +#define MAX_NUM_DEBUG 10 +#define X25_PROT 0x16 +#define PVC_PROT 0x17 + +typedef struct +{ + wan_debug_hdr_t debug[MAX_NUM_DEBUG]; +}wan_debug_t; + +#define SIOC_WANPIPE_GET_CALL_DATA (SIOCPROTOPRIVATE + 0) +#define SIOC_WANPIPE_SET_CALL_DATA (SIOCPROTOPRIVATE + 1) +#define SIOC_WANPIPE_ACCEPT_CALL (SIOCPROTOPRIVATE + 2) +#define SIOC_WANPIPE_CLEAR_CALL (SIOCPROTOPRIVATE + 3) +#define SIOC_WANPIPE_RESET_CALL (SIOCPROTOPRIVATE + 4) +#define SIOC_WANPIPE_DEBUG (SIOCPROTOPRIVATE + 5) +#define SIOC_WANPIPE_SET_NONBLOCK (SIOCPROTOPRIVATE + 6) +#define SIOC_WANPIPE_CHECK_TX (SIOCPROTOPRIVATE + 7) +#define SIOC_WANPIPE_SOCK_STATE (SIOCPROTOPRIVATE + 8) + +/* Packet types */ + +#define WAN_PACKET_HOST 0 /* To us */ +#define WAN_PACKET_BROADCAST 1 /* To all */ +#define WAN_PACKET_MULTICAST 2 /* To group */ +#define WAN_PACKET_OTHERHOST 3 /* To someone else */ +#define WAN_PACKET_OUTGOING 4 /* Outgoing of any type */ +/* These ones are invisible by user level */ +#define WAN_PACKET_LOOPBACK 5 /* MC/BRD frame looped back */ +#define WAN_PACKET_FASTROUTE 6 /* Fastrouted frame */ + + +/* X25 specific */ +#define WAN_PACKET_DATA 7 +#define WAN_PACKET_CMD 8 +#define WAN_PACKET_ASYNC 9 +#define WAN_PACKET_ERR 10 + +/* Packet socket options */ + +#define WAN_PACKET_ADD_MEMBERSHIP 1 +#define WAN_PACKET_DROP_MEMBERSHIP 2 + +#define WAN_PACKET_MR_MULTICAST 0 +#define WAN_PACKET_MR_PROMISC 1 +#define WAN_PACKET_MR_ALLMULTI 2 + +#ifdef __KERNEL__ +#ifndef netdevice_t +#include <linux/version.h> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + #define netdevice_t struct net_device +#else + #define netdevice_t struct device +#endif +#endif + +/* Private wanpipe socket structures. */ +struct wanpipe_opt +{ + void *mbox; /* Mail box */ + void *card; /* Card bouded to */ + netdevice_t *dev; /* Bounded device */ + unsigned short lcn; /* Binded LCN */ + unsigned char svc; /* 0=pvc, 1=svc */ + unsigned char timer; /* flag for delayed transmit*/ + struct timer_list tx_timer; + unsigned poll_cnt; + unsigned char force; /* Used to force sock release */ + atomic_t packet_sent; +}; +#endif + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/if_wanpipe_common.h linux.ac/include/linux/if_wanpipe_common.h --- linux.vanilla/include/linux/if_wanpipe_common.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/linux/if_wanpipe_common.h Mon Apr 16 14:40:09 2001 @@ -0,0 +1,67 @@ +/***************************************************************************** +* if_wanipe_common.h Sangoma Driver/Socket common area definitions. +* +* Author: Nenad Corbic <ncorbic@sangoma.com> +* +* Copyright: (c) 2000 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jan 13, 2000 Nenad Corbic Initial version +*****************************************************************************/ + + +#ifndef _WANPIPE_SOCK_DRIVER_COMMON_H +#define _WANPIPE_SOCK_DRIVER_COMMON_H + +#include <linux/version.h> + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + #define netdevice_t struct net_device +#else + #define netdevice_t struct device +#endif + + +typedef struct { + netdevice_t *slave; + atomic_t packet_sent; + atomic_t receive_block; + atomic_t command; + atomic_t disconnect; + atomic_t driver_busy; + unsigned char common_critical; + struct timer_list *tx_timer; + struct sock *sk; /* Wanpipe Sock bind's here */ + int (*func) (struct sk_buff *, netdevice_t *, + struct sock *); + + struct tq_struct wanpipe_task; /* Immediate BH handler task */ + unsigned char rw_bind; /* Sock bind state */ + unsigned char usedby; + unsigned char state; + unsigned char svc; + unsigned short lcn; + void *mbox; +} wanpipe_common_t; + + +enum { + WANSOCK_UNCONFIGURED, /* link/channel is not configured */ + WANSOCK_DISCONNECTED, /* link/channel is disconnected */ + WANSOCK_CONNECTING, /* connection is in progress */ + WANSOCK_CONNECTED, /* link/channel is operational */ + WANSOCK_LIMIT, /* for verification only */ + WANSOCK_DUALPORT, /* for Dual Port cards */ + WANSOCK_DISCONNECTING, + WANSOCK_BINDED, + WANSOCK_BIND_LISTEN, + WANSOCK_LISTEN +}; + +#endif + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/igmp.h linux.ac/include/linux/igmp.h --- linux.vanilla/include/linux/igmp.h Mon Aug 23 18:01:02 1999 +++ linux.ac/include/linux/igmp.h Sat Apr 14 01:41:14 2001 @@ -104,7 +104,7 @@ }; extern int ip_check_mc(struct in_device *dev, u32 mc_addr); -extern int igmp_rcv(struct sk_buff *, unsigned short); +extern int igmp_rcv(struct sk_buff *); extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr); extern int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr); extern void ip_mc_drop_socket(struct sock *sk); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/iobuf.h linux.ac/include/linux/iobuf.h --- linux.vanilla/include/linux/iobuf.h Thu Feb 22 00:10:12 2001 +++ linux.ac/include/linux/iobuf.h Tue Apr 17 17:44:38 2001 @@ -64,6 +64,7 @@ void unmap_kiobuf(struct kiobuf *iobuf); int lock_kiovec(int nr, struct kiobuf *iovec[], int wait); int unlock_kiovec(int nr, struct kiobuf *iovec[]); +void mark_dirty_kiobuf(struct kiobuf *iobuf, int bytes); /* fs/iobuf.c */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/irq.h linux.ac/include/linux/irq.h --- linux.vanilla/include/linux/irq.h Thu Feb 22 00:09:57 2001 +++ linux.ac/include/linux/irq.h Sat Apr 14 15:05:37 2001 @@ -1,6 +1,8 @@ #ifndef __irq_h #define __irq_h +#if !defined(CONFIG_ARCH_S390) + #include <linux/cache.h> #include <linux/spinlock.h> @@ -56,13 +58,25 @@ #include <asm/hw_irq.h> /* the arch dependent stuff */ +/** + * touch_nmi_watchdog - restart NMI watchdog timeout. + * + * If the architecture supports the NMI watchdog, touch_nmi_watchdog() + * may be used to reset the timeout - for code which intentionally + * disables interrupts for a long time. This call is stateless. + */ +#ifdef ARCH_HAS_NMI_WATCHDOG +extern void touch_nmi_watchdog(void); +#else +# define touch_nmi_watchdog() do { } while(0) +#endif + extern int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); extern int setup_irq(unsigned int , struct irqaction * ); extern hw_irq_controller no_irq_type; /* needed in every arch ? */ extern void no_action(int cpl, void *dev_id, struct pt_regs *regs); -extern volatile unsigned long irq_err_count; +#endif #endif /* __asm_h */ - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/isdn.h linux.ac/include/linux/isdn.h --- linux.vanilla/include/linux/isdn.h Fri Feb 9 19:29:44 2001 +++ linux.ac/include/linux/isdn.h Tue Apr 17 18:05:24 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn.h,v 1.111.6.1 2001/02/07 11:31:31 kai Exp $ +/* $Id: isdn.h,v 1.111.6.4 2001/04/15 07:59:57 kai Exp $ * Main header for the Linux ISDN subsystem (linklevel). * @@ -104,6 +104,12 @@ #define IIOCDRVCTL _IO('I',128) +/* cisco hdlck device private ioctls */ +#define SIOCGKEEPPERIOD (SIOCDEVPRIVATE + 0) +#define SIOCSKEEPPERIOD (SIOCDEVPRIVATE + 1) +#define SIOCGDEBSERINT (SIOCDEVPRIVATE + 2) +#define SIOCSDEBSERINT (SIOCDEVPRIVATE + 3) + /* Packet encapsulations for net-interfaces */ #define ISDN_NET_ENCAP_ETHER 0 #define ISDN_NET_ENCAP_RAWIP 1 @@ -264,9 +270,9 @@ ((x & ISDN_USAGE_MASK)==ISDN_USAGE_VOICE) ) /* Timer-delays and scheduling-flags */ -#define ISDN_TIMER_RES 3 /* Main Timer-Resolution */ -#define ISDN_TIMER_02SEC (HZ/(ISDN_TIMER_RES+1)/5) /* Slow-Timer1 .2 sec */ -#define ISDN_TIMER_1SEC (HZ/(ISDN_TIMER_RES+1)) /* Slow-Timer2 1 sec */ +#define ISDN_TIMER_RES 4 /* Main Timer-Resolution */ +#define ISDN_TIMER_02SEC (HZ/ISDN_TIMER_RES/5) /* Slow-Timer1 .2 sec */ +#define ISDN_TIMER_1SEC (HZ/ISDN_TIMER_RES) /* Slow-Timer2 1 sec */ #define ISDN_TIMER_RINGING 5 /* tty RINGs = ISDN_TIMER_1SEC * this factor */ #define ISDN_TIMER_KEEPINT 10 /* Cisco-Keepalive = ISDN_TIMER_1SEC * this factor */ #define ISDN_TIMER_MODEMREAD 1 @@ -275,13 +281,11 @@ #define ISDN_TIMER_MODEMXMIT 8 #define ISDN_TIMER_NETDIAL 16 #define ISDN_TIMER_NETHANGUP 32 -#define ISDN_TIMER_KEEPALIVE 128 /* Cisco-Keepalive */ #define ISDN_TIMER_CARRIER 256 /* Wait for Carrier */ #define ISDN_TIMER_FAST (ISDN_TIMER_MODEMREAD | ISDN_TIMER_MODEMPLUS | \ ISDN_TIMER_MODEMXMIT) #define ISDN_TIMER_SLOW (ISDN_TIMER_MODEMRING | ISDN_TIMER_NETHANGUP | \ - ISDN_TIMER_NETDIAL | ISDN_TIMER_KEEPALIVE | \ - ISDN_TIMER_CARRIER) + ISDN_TIMER_NETDIAL | ISDN_TIMER_CARRIER) /* Timeout-Values for isdn_net_dial() */ #define ISDN_TIMER_DTIMEOUT10 (10*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1))) @@ -403,9 +407,15 @@ #ifdef CONFIG_ISDN_X25 struct concap_device_ops *dops; /* callbacks used by encapsulator */ #endif - int cisco_loop; /* Loop counter for Cisco-SLARP */ + /* use an own struct for that in later versions */ ulong cisco_myseq; /* Local keepalive seq. for Cisco */ + ulong cisco_mineseen; /* returned keepalive seq. from remote */ ulong cisco_yourseq; /* Remote keepalive seq. for Cisco */ + int cisco_keepalive_period; /* keepalive period */ + ulong cisco_last_slarp_in; /* jiffie of last keepalive packet we received */ + char cisco_line_state; /* state of line according to keepalive packets */ + char cisco_debserint; /* debugging flag of cisco hdlc with slarp */ + struct timer_list cisco_timer; struct tq_struct tqueue; } isdn_net_local; @@ -420,7 +430,7 @@ struct net_device dev; /* interface to upper levels */ #ifdef CONFIG_ISDN_PPP ippp_bundle * pb; /* pointer to the common bundle structure - * with the the per-bundle data */ + * with the per-bundle data */ #endif #ifdef CONFIG_ISDN_X25 struct concap_proto *cprot; /* connection oriented encapsulation protocol */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/iso_fs_sb.h linux.ac/include/linux/iso_fs_sb.h --- linux.vanilla/include/linux/iso_fs_sb.h Wed Aug 26 17:54:41 1998 +++ linux.ac/include/linux/iso_fs_sb.h Wed Apr 4 13:38:10 2001 @@ -13,6 +13,7 @@ unsigned char s_high_sierra; /* A simple flag */ unsigned char s_mapping; + int s_rock_offset; /* offset of SUSP fields within SU area */ unsigned char s_rock; unsigned char s_joliet_level; unsigned char s_utf8; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/joystick.h linux.ac/include/linux/joystick.h --- linux.vanilla/include/linux/joystick.h Wed Jun 21 16:22:21 2000 +++ linux.ac/include/linux/joystick.h Sun Apr 15 23:39:44 2001 @@ -2,7 +2,7 @@ #define _LINUX_JOYSTICK_H /* - * $Id: joystick.h,v 1.2 2000/05/29 10:54:53 vojtech Exp $ + * $Id: joystick.h,v 1.3 2000/11/30 11:07:05 vojtech Exp $ * * Copyright (C) 1996-2000 Vojtech Pavlik * @@ -30,12 +30,13 @@ */ #include <asm/types.h> +#include <linux/input.h> /* * Version */ -#define JS_VERSION 0x020000 +#define JS_VERSION 0x020100 /* * Types and constants for reading from /dev/js @@ -46,7 +47,7 @@ #define JS_EVENT_INIT 0x80 /* initial state of device */ 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 */ @@ -56,14 +57,19 @@ * IOCTL commands for joystick driver */ -#define JSIOCGVERSION _IOR('j', 0x01, __u32) /* get driver version */ +#define JSIOCGVERSION _IOR('j', 0x01, __u32) /* get driver version */ -#define JSIOCGAXES _IOR('j', 0x11, __u8) /* get number of axes */ -#define JSIOCGBUTTONS _IOR('j', 0x12, __u8) /* get number of buttons */ -#define JSIOCGNAME(len) _IOC(_IOC_READ, 'j', 0x13, len) /* get identifier string */ - -#define JSIOCSCORR _IOW('j', 0x21, struct js_corr) /* set correction values */ -#define JSIOCGCORR _IOR('j', 0x22, struct js_corr) /* get correction values */ +#define JSIOCGAXES _IOR('j', 0x11, __u8) /* get number of axes */ +#define JSIOCGBUTTONS _IOR('j', 0x12, __u8) /* get number of buttons */ +#define JSIOCGNAME(len) _IOC(_IOC_READ, 'j', 0x13, len) /* get identifier string */ + +#define JSIOCSCORR _IOW('j', 0x21, struct js_corr) /* set correction values */ +#define JSIOCGCORR _IOR('j', 0x22, struct js_corr) /* get correction values */ + +#define JSIOCSAXMAP _IOW('j', 0x31, __u8[ABS_MAX]) /* set axis mapping */ +#define JSIOCGAXMAP _IOR('j', 0x32, __u8[ABS_MAX]) /* get axis mapping */ +#define JSIOCSBTNMAP _IOW('j', 0x33, __u16[KEY_MAX - BTN_MISC]) /* set button mapping */ +#define JSIOCGBTNMAP _IOR('j', 0x34, __u16[KEY_MAX - BTN_MISC]) /* get button mapping */ /* * Types and constants for get/set correction diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/kbd_kern.h linux.ac/include/linux/kbd_kern.h --- linux.vanilla/include/linux/kbd_kern.h Thu Feb 22 00:11:45 2001 +++ linux.ac/include/linux/kbd_kern.h Sat Apr 14 15:07:03 2001 @@ -69,23 +69,12 @@ extern unsigned char getledstate(void); extern void setledstate(struct kbd_struct *kbd, unsigned int led); -extern struct tasklet_struct console_tasklet; - extern int do_poke_blanked_console; extern void (*kbd_ledfunc)(unsigned int led); -extern inline void show_console(void) -{ - do_poke_blanked_console = 1; - tasklet_schedule(&console_tasklet); -} - -extern inline void set_console(int nr) -{ - want_console = nr; - tasklet_schedule(&console_tasklet); -} +extern void set_console(int nr); +extern void schedule_console_callback(void); extern inline void set_leds(void) { @@ -159,12 +148,9 @@ /* console.c */ -extern task_queue con_task_queue; - extern inline void con_schedule_flip(struct tty_struct *t) { - queue_task(&t->flip.tqueue, &con_task_queue); - tasklet_schedule(&console_tasklet); + schedule_task(&t->flip.tqueue); } #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/kernel.h linux.ac/include/linux/kernel.h --- linux.vanilla/include/linux/kernel.h Mon Dec 11 20:49:54 2000 +++ linux.ac/include/linux/kernel.h Sat Apr 14 01:41:24 2001 @@ -62,9 +62,7 @@ extern int vsprintf(char *buf, const char *, va_list); extern int get_option(char **str, int *pint); extern char *get_options(char *str, int nints, int *ints); -extern unsigned long memparse(char *ptr, char **retptr); -extern void dev_probe_lock(void); -extern void dev_probe_unlock(void); +extern unsigned long long memparse(char *ptr, char **retptr); extern int session_of_pgrp(int pgrp); @@ -83,6 +81,9 @@ if (console_loglevel) console_loglevel = 15; } + +extern void bust_spinlocks(int yes); +extern int oops_in_progress; /* If set, an oops, panic(), BUG() or die() is in progress */ #if DEBUG #define pr_debug(fmt,arg...) \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/kernel_stat.h linux.ac/include/linux/kernel_stat.h --- linux.vanilla/include/linux/kernel_stat.h Thu Feb 22 00:09:58 2001 +++ linux.ac/include/linux/kernel_stat.h Sat Apr 14 15:05:37 2001 @@ -12,7 +12,7 @@ * used by rstatd/perfmeter */ -#define DK_MAX_MAJOR 16 +#define DK_MAX_MAJOR 99 #define DK_MAX_DISK 16 struct kernel_stat { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/kmod.h linux.ac/include/linux/kmod.h --- linux.vanilla/include/linux/kmod.h Thu Feb 22 00:09:57 2001 +++ linux.ac/include/linux/kmod.h Tue Apr 3 18:11:19 2001 @@ -34,5 +34,7 @@ #ifdef CONFIG_HOTPLUG extern char hotplug_path []; #endif +extern void dev_probe_lock(void); +extern void dev_probe_unlock(void); #endif /* __LINUX_KMOD_H__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/linux_logo.h linux.ac/include/linux/linux_logo.h --- linux.vanilla/include/linux/linux_logo.h Wed Sep 30 22:16:33 1998 +++ linux.ac/include/linux/linux_logo.h Tue Apr 3 17:55:17 2001 @@ -1024,422 +1024,407 @@ #ifdef INCLUDE_LINUX_LOGO16 -unsigned char linux_logo16_red[] __initdata = { - 0x00, 0x90, 0xb0, 0x9c, 0xf7, 0x35, 0x83, 0xa5, - 0x65, 0x8f, 0x98, 0xc9, 0xdb, 0xe1, 0xe7, 0xf8 -}; - -unsigned char linux_logo16_green[] __initdata = { - 0x00, 0x90, 0xb0, 0x9c, 0xf7, 0x2e, 0x83, 0xa5, - 0x65, 0x6e, 0x98, 0x89, 0xbf, 0xac, 0xda, 0xf8 -}; - -unsigned char linux_logo16_blue[] __initdata = { - 0x00, 0x90, 0xaf, 0x9c, 0xf7, 0x2b, 0x82, 0xa5, - 0x65, 0x41, 0x97, 0x1e, 0x60, 0x29, 0xa5, 0xf8 -}; - unsigned char linux_logo16[] __initdata = { - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa1, 0x11, 0x11, - 0x61, 0x16, 0x66, 0x66, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x1a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0x33, 0xa8, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x87, 0x77, 0x77, 0x77, 0x77, - 0x77, 0x77, 0x73, 0x33, 0x33, 0x3a, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xa3, 0x33, 0x33, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, 0x77, - 0x77, 0x27, 0x77, 0x77, 0x77, 0x33, 0x3a, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xa3, 0x33, 0x33, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x55, 0x50, 0x08, 0x33, 0x77, 0x77, - 0x77, 0x72, 0x72, 0x27, 0x77, 0x77, 0x33, 0x33, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xa3, 0x33, 0x33, 0x77, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x58, 0x85, 0x00, 0x11, 0x11, 0xaa, - 0xa3, 0x37, 0x77, 0x72, 0x22, 0x22, 0x77, 0x73, - 0x33, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa3, - 0x33, 0x37, 0x77, 0x33, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x56, 0x85, 0x00, 0x06, 0x66, 0x11, - 0x11, 0x1a, 0xa3, 0x37, 0x77, 0x72, 0x22, 0x77, - 0x73, 0x33, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x33, - 0x33, 0x33, 0x33, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x55, 0x00, 0x00, 0x06, 0x66, 0x66, - 0x66, 0x66, 0x11, 0x1a, 0xa3, 0x77, 0x72, 0x22, - 0x77, 0x73, 0x3a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x33, 0x33, - 0x33, 0x33, 0x33, 0xa0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, - 0x66, 0x66, 0x66, 0x66, 0x11, 0xa3, 0x77, 0x22, - 0x22, 0x77, 0x33, 0x33, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x33, 0x33, 0x33, - 0x33, 0x3a, 0xa1, 0x10, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x33, - 0xaa, 0x11, 0x16, 0x66, 0x66, 0x61, 0x1a, 0x37, - 0x22, 0x22, 0x77, 0x33, 0x3a, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xa3, 0x33, 0x33, 0x33, - 0x3a, 0xa1, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x22, - 0x22, 0x77, 0x3a, 0x11, 0x66, 0x66, 0x66, 0x1a, - 0x37, 0x22, 0x22, 0x77, 0x33, 0x3a, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0x33, 0x33, 0x33, 0x3a, - 0xa1, 0x11, 0x11, 0x10, 0x00, 0x00, 0x50, 0x00, - 0x00, 0x05, 0x80, 0x50, 0x00, 0x00, 0x07, 0x72, - 0x22, 0x22, 0x22, 0x73, 0xa1, 0x66, 0x66, 0x61, - 0x1a, 0x77, 0x22, 0x27, 0x73, 0x33, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0x33, 0x33, 0x3a, 0xaa, - 0x11, 0x11, 0x1a, 0xa0, 0x08, 0x71, 0x05, 0x00, - 0x00, 0x12, 0x22, 0x50, 0x00, 0x00, 0x07, 0x77, - 0x77, 0x72, 0x22, 0x22, 0x27, 0x31, 0x16, 0x66, - 0x61, 0x13, 0x77, 0x22, 0x77, 0x33, 0x3a, 0xaa, - 0xaa, 0xaa, 0xaa, 0xa3, 0x33, 0x33, 0xaa, 0xa1, - 0x11, 0x1a, 0x33, 0x70, 0x07, 0x2e, 0x70, 0x00, - 0x01, 0x44, 0x42, 0x60, 0x00, 0x00, 0x02, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x27, 0x31, 0x66, - 0x66, 0x61, 0xa3, 0x72, 0x22, 0x77, 0x33, 0xaa, - 0xaa, 0xaa, 0xa3, 0x33, 0x33, 0xaa, 0xaa, 0x11, - 0x1a, 0x33, 0x77, 0x30, 0x04, 0x82, 0x40, 0x00, - 0x54, 0x48, 0x54, 0x40, 0x00, 0x00, 0x01, 0xaa, - 0x32, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x31, - 0x66, 0x66, 0x11, 0x37, 0x22, 0x27, 0x73, 0x3a, - 0xaa, 0xaa, 0xa3, 0x33, 0x3a, 0xaa, 0xaa, 0xaa, - 0xa3, 0x77, 0xaa, 0x10, 0x50, 0x08, 0x46, 0x05, - 0x54, 0x80, 0x50, 0x42, 0x00, 0x00, 0x08, 0x66, - 0x66, 0x1a, 0x32, 0x22, 0x22, 0x22, 0x22, 0x27, - 0x31, 0x66, 0x66, 0x13, 0x72, 0x22, 0x77, 0x33, - 0xaa, 0xaa, 0xaa, 0x33, 0xaa, 0xa1, 0xaa, 0xa3, - 0x37, 0xa1, 0x1a, 0x30, 0x50, 0x06, 0x26, 0x00, - 0x54, 0x00, 0x00, 0x44, 0x00, 0x00, 0x08, 0xe2, - 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x22, 0x22, - 0x27, 0xa6, 0x66, 0x61, 0xa7, 0x72, 0x27, 0x73, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x33, - 0x31, 0x11, 0x37, 0x70, 0x02, 0x00, 0xab, 0xbb, - 0xb6, 0x00, 0x00, 0xf4, 0x00, 0x00, 0xee, 0xee, - 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x22, - 0x22, 0x23, 0x16, 0x66, 0x1a, 0x37, 0x22, 0x77, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa3, 0x3a, - 0x11, 0xa7, 0x33, 0x10, 0x04, 0x09, 0xbd, 0xdd, - 0xbd, 0xd0, 0x04, 0x45, 0x00, 0x0e, 0xee, 0xee, - 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x22, - 0x22, 0x22, 0x71, 0x66, 0x66, 0x13, 0x72, 0x27, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x33, 0x11, - 0xa3, 0x73, 0xa1, 0x60, 0x08, 0xbd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdb, 0x90, 0x00, 0x02, 0xec, 0xee, - 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xce, 0x22, - 0x22, 0x22, 0x27, 0xa6, 0x66, 0x61, 0x37, 0x27, - 0x1a, 0xaa, 0xaa, 0xaa, 0xaa, 0xa3, 0xa1, 0x1a, - 0x33, 0xa1, 0x16, 0x60, 0x0b, 0xbd, 0xdd, 0xdd, - 0xcd, 0xdd, 0xdd, 0xd9, 0x00, 0x00, 0xec, 0xcc, - 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0xa2, - 0x22, 0x22, 0x22, 0x7a, 0x66, 0x66, 0x13, 0x77, - 0x1a, 0xaa, 0xaa, 0xaa, 0xaa, 0x3a, 0x11, 0x33, - 0xaa, 0x11, 0x66, 0x60, 0x9b, 0xdd, 0xdd, 0xdd, - 0xcd, 0xdd, 0xdb, 0xb9, 0x00, 0x00, 0xec, 0xcc, - 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xee, 0x61, - 0x72, 0x22, 0x22, 0x22, 0xa1, 0x66, 0x61, 0x37, - 0x1a, 0xaa, 0xaa, 0xaa, 0xa3, 0xa1, 0x13, 0x3a, - 0x11, 0x11, 0x11, 0x10, 0x5b, 0xdd, 0xdd, 0xdc, - 0xdd, 0xdd, 0xbd, 0xd9, 0x00, 0x00, 0xec, 0xcc, - 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xee, 0x86, - 0x17, 0x22, 0x22, 0x22, 0x23, 0x16, 0x66, 0xaa, - 0xaa, 0xa3, 0x3a, 0xaa, 0xaa, 0x1a, 0x3a, 0xa1, - 0x11, 0x11, 0x1a, 0x70, 0x05, 0xbd, 0xdd, 0xdd, - 0xdb, 0x5b, 0xdd, 0xb0, 0x00, 0x60, 0x2e, 0xcc, - 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xe6, 0x88, - 0x66, 0x32, 0x22, 0x22, 0x22, 0x36, 0x66, 0x11, - 0x33, 0x33, 0x3a, 0xaa, 0x11, 0xaa, 0xaa, 0xa1, - 0x11, 0x1a, 0x3a, 0x60, 0x02, 0x99, 0xbb, 0xb9, - 0x9b, 0xbb, 0xbc, 0x22, 0x00, 0x86, 0x5e, 0xcc, - 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xe1, 0x68, - 0x86, 0x63, 0x22, 0x22, 0x22, 0x2a, 0x66, 0x66, - 0x33, 0x33, 0xaa, 0xaa, 0x1a, 0xaa, 0xaa, 0x11, - 0x1a, 0xa7, 0x68, 0x80, 0x02, 0x2b, 0xbd, 0xbb, - 0xbb, 0xb9, 0x22, 0x22, 0x00, 0x06, 0x6e, 0xcc, - 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xc7, 0xa6, - 0x88, 0x86, 0x32, 0x22, 0x22, 0x27, 0xa6, 0x66, - 0x33, 0x3a, 0xaa, 0xa1, 0xaa, 0xaa, 0xa1, 0x11, - 0xa3, 0xa6, 0x88, 0x80, 0x02, 0x22, 0x9b, 0xbb, - 0xbb, 0x22, 0x24, 0xf4, 0x60, 0x00, 0x0c, 0xcc, - 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xc2, 0x21, - 0x68, 0x88, 0x63, 0x22, 0x22, 0x22, 0x71, 0x66, - 0x33, 0x3a, 0x11, 0x11, 0xaa, 0xaa, 0x11, 0xaa, - 0x71, 0x88, 0x88, 0x00, 0x02, 0xe2, 0x26, 0x99, - 0x22, 0x22, 0x4f, 0xf4, 0x40, 0x00, 0x0c, 0xcc, - 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x22, 0x22, - 0x16, 0x88, 0x86, 0xa2, 0x22, 0x22, 0x27, 0x11, - 0x33, 0xa1, 0x11, 0x11, 0xaa, 0x31, 0x1a, 0xa3, - 0x68, 0x88, 0x81, 0x00, 0x54, 0x42, 0x22, 0x22, - 0x22, 0x44, 0xff, 0xff, 0x48, 0x00, 0x00, 0x99, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x22, 0x22, - 0x21, 0x88, 0x88, 0x6a, 0x22, 0x22, 0x22, 0x31, - 0x3a, 0xa1, 0x11, 0x1a, 0xa3, 0x11, 0x33, 0x36, - 0x88, 0x86, 0x30, 0x00, 0x4f, 0x44, 0x22, 0x22, - 0x24, 0xff, 0xff, 0xff, 0x44, 0x00, 0x00, 0x99, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x95, 0x22, 0x72, - 0x22, 0x18, 0x88, 0x86, 0x32, 0x22, 0x22, 0x27, - 0xaa, 0x11, 0x11, 0x1a, 0x31, 0x13, 0x33, 0x68, - 0x88, 0x6a, 0x00, 0x02, 0x4f, 0x4f, 0x42, 0x24, - 0x4f, 0xff, 0xff, 0xff, 0xf4, 0x50, 0x00, 0x99, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x22, 0x73, - 0x72, 0x26, 0x88, 0x88, 0x63, 0x22, 0x22, 0x22, - 0x11, 0x11, 0x11, 0xa3, 0xa1, 0x73, 0xa6, 0x88, - 0x81, 0xa5, 0x00, 0x04, 0x4f, 0x4f, 0x44, 0x4f, - 0xff, 0xff, 0xff, 0xff, 0xf4, 0x40, 0x00, 0x99, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x12, 0x27, - 0xaa, 0x22, 0x68, 0x55, 0x86, 0x72, 0x22, 0x22, - 0x11, 0x11, 0x1a, 0x33, 0x13, 0x3a, 0x18, 0x88, - 0x1a, 0x10, 0x00, 0x44, 0x4f, 0x4f, 0xff, 0x4f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x99, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x61, 0x22, - 0x3a, 0xa2, 0x26, 0x85, 0x58, 0x67, 0x22, 0x22, - 0x61, 0x61, 0x1a, 0x7a, 0x37, 0x31, 0x88, 0x81, - 0x11, 0x00, 0x05, 0xe4, 0x44, 0xff, 0xff, 0xff, - 0x4f, 0xf4, 0x44, 0xff, 0xff, 0xf5, 0x00, 0x99, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x88, 0x12, - 0x2a, 0xaa, 0x72, 0x68, 0x55, 0x81, 0x22, 0x22, - 0x66, 0x61, 0xa3, 0x33, 0x73, 0x16, 0x88, 0x11, - 0x10, 0x00, 0x08, 0x74, 0x44, 0x4f, 0x44, 0x44, - 0xf4, 0xf4, 0x44, 0x44, 0xe2, 0x44, 0x00, 0x99, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x88, 0x81, - 0x22, 0xaa, 0xa7, 0x26, 0x85, 0x88, 0x12, 0x22, - 0x66, 0x61, 0x37, 0xa7, 0x3a, 0x66, 0x66, 0x11, - 0x80, 0x00, 0x0a, 0x72, 0x44, 0x4f, 0x44, 0x4f, - 0xff, 0x44, 0x44, 0x22, 0x22, 0x24, 0x00, 0x99, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x85, 0x88, - 0x12, 0x2a, 0xaa, 0x22, 0x68, 0x58, 0x63, 0x22, - 0x66, 0x1a, 0x73, 0x77, 0x31, 0x66, 0x61, 0x11, - 0x00, 0x00, 0x07, 0x44, 0xff, 0x4f, 0xf4, 0x4f, - 0xff, 0x4f, 0x44, 0xf4, 0x42, 0x22, 0x40, 0x9b, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xb9, 0x85, 0x55, - 0x81, 0x27, 0xaa, 0xa2, 0x78, 0x88, 0x86, 0x72, - 0x66, 0x13, 0x77, 0x73, 0x11, 0x66, 0x61, 0x76, - 0x00, 0x50, 0x84, 0xf4, 0xff, 0x4f, 0xf4, 0xff, - 0xff, 0x4f, 0x44, 0xff, 0x4f, 0x42, 0x40, 0x9b, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xb9, 0x68, 0x55, - 0x58, 0x12, 0x3a, 0xaa, 0x23, 0x88, 0x88, 0xa7, - 0x66, 0xa7, 0x77, 0x7a, 0x16, 0x66, 0x1a, 0x15, - 0x05, 0x00, 0x4f, 0xf4, 0xff, 0x4f, 0xf4, 0xff, - 0xff, 0x4f, 0x44, 0xff, 0x4f, 0x44, 0x24, 0x9b, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xb9, 0x26, 0x55, - 0x55, 0x81, 0x23, 0xaa, 0x32, 0x18, 0x88, 0x6a, - 0x61, 0x37, 0x77, 0x31, 0x66, 0x66, 0x17, 0x60, - 0x05, 0x08, 0x4f, 0xf4, 0xff, 0x4f, 0xf4, 0xff, - 0xff, 0x4f, 0x44, 0xff, 0x4f, 0x4f, 0x4e, 0x99, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0xa2, 0x65, - 0x55, 0x58, 0xa2, 0x7a, 0xa2, 0x26, 0x88, 0x61, - 0x61, 0x32, 0x27, 0xa1, 0x66, 0x61, 0x31, 0x60, - 0x00, 0x04, 0x4f, 0xf4, 0xff, 0x44, 0x44, 0xff, - 0xff, 0x4f, 0x44, 0xff, 0x4f, 0x44, 0xf4, 0x99, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x9b, 0xaa, 0x26, - 0x55, 0x55, 0x87, 0x27, 0x33, 0x27, 0x68, 0x61, - 0x1a, 0x72, 0x27, 0xa6, 0x66, 0x6a, 0x71, 0x00, - 0x80, 0x84, 0xff, 0xf4, 0xff, 0x44, 0x44, 0xff, - 0xff, 0x4f, 0x44, 0xff, 0x4f, 0x44, 0xf4, 0x99, - 0x9b, 0x9b, 0x99, 0xb9, 0xb9, 0x99, 0xaa, 0xa2, - 0x85, 0x55, 0x56, 0x22, 0x27, 0x22, 0x36, 0x66, - 0x13, 0x22, 0x23, 0x16, 0x86, 0x63, 0x73, 0x00, - 0x00, 0x44, 0xf4, 0xf4, 0xff, 0x44, 0x44, 0xff, - 0xff, 0x4f, 0x44, 0xff, 0x4f, 0x4f, 0x4f, 0x99, - 0x9b, 0x99, 0x99, 0x99, 0xb9, 0x99, 0xaa, 0xaa, - 0x28, 0x55, 0x58, 0x12, 0x22, 0x22, 0x21, 0x11, - 0xa3, 0x27, 0x7a, 0x66, 0x86, 0x17, 0x75, 0x05, - 0x05, 0xff, 0xf4, 0xf4, 0xff, 0x44, 0x44, 0xff, - 0xff, 0x4f, 0x44, 0x4f, 0x4f, 0x44, 0x4f, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x3a, 0xaa, - 0xa2, 0x85, 0x58, 0x67, 0x72, 0x22, 0x27, 0xa1, - 0x37, 0x27, 0x7a, 0x68, 0x86, 0xa2, 0x70, 0x00, - 0x02, 0xff, 0xf4, 0xf4, 0xff, 0x44, 0x44, 0x4f, - 0xff, 0x4f, 0x44, 0xf4, 0xf4, 0xf4, 0xf4, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x23, 0xaa, - 0xa7, 0x78, 0x88, 0x81, 0x77, 0x22, 0x27, 0x3a, - 0x72, 0x73, 0x71, 0x68, 0x66, 0x32, 0x50, 0x00, - 0x04, 0x4f, 0xf4, 0xf4, 0xff, 0x44, 0x44, 0x4f, - 0xff, 0x4f, 0x44, 0xf4, 0xf4, 0xf4, 0x44, 0x95, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x55, 0x12, 0x3a, - 0xaa, 0x21, 0x88, 0x81, 0x77, 0x27, 0x73, 0x73, - 0x72, 0x33, 0x36, 0x86, 0x61, 0x72, 0x00, 0x00, - 0x04, 0x44, 0xf4, 0xf4, 0xf4, 0x44, 0x44, 0x4f, - 0xff, 0x4f, 0x44, 0xff, 0x4f, 0x4f, 0x44, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x8a, 0x27, - 0xaa, 0x77, 0x68, 0x61, 0x23, 0x71, 0x11, 0x3a, - 0x27, 0xa3, 0x36, 0x86, 0x61, 0x20, 0x00, 0x00, - 0x04, 0xf4, 0xf4, 0xf4, 0xf4, 0x44, 0x44, 0x4f, - 0xff, 0x4f, 0x44, 0xff, 0x4f, 0x4f, 0x41, 0x59, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x95, 0x58, 0x77, - 0x27, 0x32, 0x36, 0x63, 0x23, 0x71, 0x66, 0x11, - 0x27, 0x13, 0xa6, 0x86, 0x6a, 0x20, 0x00, 0x50, - 0x04, 0x4f, 0x4f, 0x4f, 0x4f, 0x44, 0x44, 0x4f, - 0xff, 0x4f, 0x44, 0xff, 0x4f, 0x4f, 0x41, 0x99, - 0x9b, 0xbb, 0xbb, 0xbb, 0xb9, 0x99, 0x68, 0x13, - 0x32, 0x22, 0x73, 0xa7, 0x2a, 0x31, 0x88, 0x66, - 0x7a, 0x13, 0x18, 0x66, 0x63, 0x20, 0x00, 0x06, - 0x0f, 0x4f, 0x4f, 0x4f, 0x4f, 0x44, 0x44, 0x4f, - 0xff, 0x4f, 0x44, 0xff, 0x4f, 0x4f, 0x49, 0x95, - 0xa9, 0xa9, 0x99, 0x97, 0x92, 0x99, 0x65, 0x6a, - 0x17, 0x22, 0x23, 0x72, 0x27, 0xaa, 0x88, 0x88, - 0xa1, 0x17, 0x68, 0x66, 0x67, 0x70, 0x00, 0x05, - 0x0f, 0x4f, 0x4f, 0x4f, 0x4f, 0x44, 0x44, 0x4f, - 0xff, 0x4f, 0x44, 0xff, 0xf4, 0xf4, 0x49, 0x9c, - 0x2e, 0xee, 0xee, 0xee, 0xee, 0xa9, 0x65, 0x8a, - 0x1a, 0xaa, 0x37, 0x72, 0x27, 0x37, 0x88, 0x88, - 0x11, 0x17, 0x68, 0x66, 0x67, 0x10, 0x9d, 0xd0, - 0x84, 0x44, 0xff, 0x4f, 0x4f, 0x44, 0xf4, 0x4f, - 0xff, 0x4f, 0x44, 0xff, 0xf4, 0xf4, 0x4f, 0x69, - 0xcc, 0xee, 0xee, 0xee, 0xec, 0x99, 0x88, 0x63, - 0x61, 0x68, 0x61, 0x72, 0x22, 0x7a, 0x68, 0x88, - 0x11, 0x17, 0x88, 0x66, 0x12, 0x1b, 0xdd, 0xdd, - 0x02, 0x44, 0x4f, 0x4f, 0x4f, 0x44, 0x44, 0x4f, - 0xff, 0x4f, 0x44, 0xff, 0xff, 0x4f, 0x4c, 0xc5, - 0x0c, 0xc1, 0x11, 0x1c, 0xc0, 0x26, 0x66, 0x17, - 0x66, 0x88, 0x88, 0x12, 0x22, 0x23, 0xa8, 0x88, - 0x11, 0x13, 0x88, 0x66, 0x17, 0xbb, 0xdd, 0xdd, - 0xd0, 0x8f, 0xff, 0xf4, 0xf4, 0x44, 0xf4, 0x4f, - 0xff, 0x4f, 0x44, 0xf4, 0x4f, 0x44, 0xdd, 0xdd, - 0x00, 0x00, 0x00, 0x05, 0x9d, 0x21, 0x66, 0x27, - 0xa6, 0x65, 0x58, 0x67, 0x22, 0x27, 0x28, 0x88, - 0x11, 0xaa, 0x86, 0x68, 0x1a, 0xbb, 0xdd, 0xdd, - 0xdb, 0x05, 0xf4, 0xf4, 0xf4, 0xf4, 0x44, 0x4f, - 0xff, 0x4f, 0x44, 0xf4, 0xf4, 0xf4, 0xdd, 0xdb, - 0x00, 0x00, 0x00, 0x00, 0xdd, 0xda, 0x66, 0x22, - 0x71, 0x15, 0x55, 0x81, 0x22, 0x22, 0x76, 0x88, - 0x11, 0x31, 0x88, 0x88, 0xab, 0xbd, 0xdd, 0xdd, - 0xdd, 0x00, 0x04, 0x44, 0xff, 0xff, 0x4f, 0x4f, - 0xff, 0x4f, 0x44, 0xf4, 0xf4, 0x44, 0xdd, 0xdb, - 0x00, 0x00, 0x00, 0x0b, 0xdd, 0xda, 0x11, 0x22, - 0x23, 0x68, 0x55, 0x86, 0x22, 0x22, 0x7a, 0x88, - 0x1a, 0x71, 0x88, 0x89, 0xbb, 0xdd, 0xdd, 0xdd, - 0xdd, 0xd0, 0x00, 0x4f, 0x44, 0xff, 0x4f, 0x4f, - 0xff, 0x4f, 0x44, 0xf4, 0xff, 0xe2, 0xdd, 0xdb, - 0x90, 0x00, 0x05, 0xbd, 0xdd, 0xb8, 0x63, 0x22, - 0x27, 0xa6, 0x55, 0x88, 0x77, 0x22, 0x22, 0x88, - 0x1a, 0x28, 0xbd, 0xdb, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdb, 0x00, 0x07, 0x44, 0x4f, 0x4f, 0x4f, - 0xff, 0x4f, 0x44, 0x4f, 0x4f, 0x22, 0xdd, 0xdb, - 0xbb, 0x9b, 0xbb, 0xbd, 0xdd, 0xd5, 0x86, 0x22, - 0x22, 0x77, 0x85, 0x88, 0x17, 0x22, 0x22, 0x88, - 0xaa, 0x2b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0x00, 0x00, 0x54, 0x4f, 0x4f, 0x4f, - 0xff, 0x4f, 0x44, 0xf4, 0x44, 0x22, 0xbd, 0xdd, - 0xbb, 0xbb, 0xbb, 0xdd, 0xdd, 0xdd, 0x88, 0x72, - 0x27, 0x22, 0x88, 0x88, 0x67, 0x72, 0x22, 0x18, - 0x33, 0x2d, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xd0, 0x00, 0x05, 0x4f, 0x4f, 0x4f, - 0xff, 0x4f, 0x44, 0x44, 0x4f, 0x22, 0xbd, 0xdd, - 0xdb, 0xbb, 0xdd, 0xdd, 0xdd, 0xdd, 0x88, 0x17, - 0x27, 0x72, 0x68, 0x88, 0x87, 0x32, 0x22, 0x36, - 0x37, 0x2d, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xd5, 0x00, 0x00, 0x4f, 0x4f, 0x4f, - 0xff, 0xf4, 0xf4, 0xf4, 0xf4, 0x22, 0xbb, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xd8, 0x67, - 0x72, 0x77, 0x38, 0x88, 0x83, 0x37, 0x22, 0x26, - 0x72, 0x2b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0x00, 0x00, 0x4f, 0x4f, 0x4f, - 0xff, 0xf4, 0xf4, 0xf4, 0x44, 0x25, 0xbb, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xd3, - 0x32, 0x73, 0x76, 0x88, 0x81, 0x33, 0x22, 0x2a, - 0x22, 0x2b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xb0, 0x54, 0x4f, 0x4f, 0x4f, - 0xff, 0xf4, 0xf4, 0xff, 0x44, 0x00, 0xbb, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xa7, 0x73, 0x26, 0x88, 0x86, 0x7a, 0x72, 0x27, - 0x22, 0x2b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdb, 0x44, 0xff, 0x4f, 0x4f, - 0xff, 0xf4, 0xf4, 0x44, 0x40, 0x05, 0xbb, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0x13, 0x23, 0x21, 0x68, 0x86, 0x17, 0x72, 0x22, - 0x22, 0x2b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdb, 0x44, 0x4f, 0x4f, 0x4f, - 0xff, 0xff, 0x44, 0x42, 0x00, 0x05, 0xbd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0x87, 0x27, 0x27, 0x16, 0x66, 0x67, 0x22, 0x22, - 0x72, 0x7b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0x94, 0x44, 0x44, 0x44, - 0x44, 0x44, 0x44, 0x00, 0x00, 0x05, 0xbb, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xb8, - 0x86, 0x22, 0x22, 0x7a, 0x68, 0x81, 0x22, 0x22, - 0x37, 0x7b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdb, 0xb5, 0x44, 0x44, 0x44, - 0x44, 0x47, 0x00, 0x00, 0x00, 0x05, 0xbd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xd8, 0x68, - 0x58, 0x72, 0x22, 0x27, 0x18, 0x86, 0x72, 0x22, - 0x1a, 0xbb, 0xbd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdb, 0xb5, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xbb, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xb9, 0x18, 0x85, - 0x58, 0x12, 0x22, 0x36, 0x18, 0x88, 0x32, 0x22, - 0x61, 0x3b, 0xbb, 0xbb, 0xbd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdb, 0xb9, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xbb, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xb9, 0x7a, 0x68, 0x85, - 0x88, 0x62, 0x27, 0x16, 0x18, 0x88, 0x12, 0x27, - 0x86, 0x18, 0x9b, 0xbb, 0xbb, 0xbb, 0xbb, 0xbd, - 0xdd, 0xdd, 0xdd, 0xbb, 0xb5, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xbb, 0xbd, - 0xdd, 0xdd, 0xdb, 0xbb, 0x87, 0x31, 0x68, 0x65, - 0x88, 0x82, 0x23, 0x16, 0x18, 0x88, 0x12, 0x23, - 0x88, 0x67, 0x27, 0xa8, 0x9b, 0xbb, 0xbb, 0xbb, - 0xbd, 0xdd, 0xbb, 0xbb, 0x95, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x9b, 0xbb, - 0xbb, 0xbb, 0xbb, 0x96, 0x87, 0x16, 0x68, 0x18, - 0x88, 0x62, 0x31, 0x66, 0x18, 0x88, 0x62, 0x73, - 0x88, 0x63, 0x27, 0x33, 0x65, 0x55, 0x99, 0x9b, - 0xbb, 0xbb, 0xbb, 0x99, 0x55, 0x0a, 0xa1, 0x86, - 0x81, 0x68, 0x88, 0x55, 0x58, 0x85, 0x9b, 0xbb, - 0xbb, 0xbb, 0x95, 0x88, 0x83, 0x66, 0x66, 0x18, - 0x66, 0x82, 0xa1, 0x66, 0x18, 0x88, 0x62, 0x33, - 0x88, 0x81, 0x27, 0x7a, 0x18, 0x58, 0x86, 0x85, - 0x99, 0x99, 0x99, 0x95, 0x53, 0x2a, 0xaa, 0x88, - 0x67, 0x31, 0x68, 0x55, 0x58, 0x85, 0x59, 0xbb, - 0xbb, 0xb9, 0x58, 0x68, 0x83, 0x66, 0x61, 0x16, - 0x66, 0x62, 0x16, 0x66, 0x68, 0x88, 0x62, 0xaa, - 0x88, 0x86, 0x27, 0x77, 0x78, 0x55, 0x88, 0x22, - 0x25, 0x55, 0x95, 0x55, 0x6a, 0xa2, 0x2a, 0x88, - 0x62, 0x27, 0x37, 0x38, 0x88, 0x87, 0x55, 0x59, - 0x95, 0x58, 0x16, 0x88, 0x8a, 0x66, 0x63, 0x68, - 0x86, 0x67, 0x66, 0x66, 0x68, 0x88, 0x12, 0x11, - 0x88, 0x88, 0x72, 0x77, 0x78, 0x85, 0x58, 0x17, - 0x23, 0x32, 0x55, 0x55, 0x81, 0x13, 0x73, 0x66, - 0x62, 0x7a, 0xaa, 0x38, 0x88, 0x58, 0x27, 0x55, - 0x58, 0x32, 0x38, 0x88, 0x81, 0x66, 0xa2, 0x88, - 0x86, 0x61, 0x66, 0x61, 0x66, 0x68, 0x13, 0x11, - 0x88, 0x88, 0x12, 0x22, 0x71, 0x85, 0x58, 0x62, - 0x23, 0xa2, 0x68, 0x88, 0x81, 0x66, 0x88, 0x88, - 0x63, 0x2a, 0xaa, 0x28, 0x88, 0x55, 0x86, 0x61, - 0x66, 0x66, 0x68, 0x88, 0x66, 0x66, 0x77, 0x88, - 0x68, 0x16, 0x66, 0x62, 0x66, 0x68, 0xa1, 0x61, - 0x88, 0x88, 0x62, 0x22, 0x22, 0x85, 0x55, 0x83, - 0x72, 0x37, 0xa8, 0x88, 0x61, 0x66, 0x85, 0x55, - 0x86, 0x23, 0xaa, 0x71, 0x88, 0x85, 0x88, 0x66, - 0x88, 0x86, 0x88, 0x88, 0x16, 0x61, 0x21, 0x88, - 0x66, 0xa6, 0x86, 0x17, 0x66, 0x66, 0x31, 0x61, - 0x88, 0x88, 0x87, 0x72, 0x22, 0x68, 0x55, 0x86, - 0x77, 0x77, 0x36, 0x88, 0x13, 0x68, 0x85, 0x55, - 0x58, 0x12, 0x73, 0x72, 0x76, 0x88, 0x88, 0x68, - 0x88, 0x88, 0x88, 0x66, 0x36, 0x63, 0x26, 0x86, - 0x86, 0x36, 0x86, 0x11, 0x66, 0x66, 0x76, 0x61, - 0x88, 0x88, 0x81, 0x22, 0x22, 0x38, 0x85, 0x58, - 0x37, 0x22, 0x21, 0x68, 0xa2, 0x31, 0x68, 0x55, - 0x55, 0x81, 0x22, 0x22, 0xa8, 0x88, 0x88, 0x68, - 0x86, 0x88, 0x68, 0x81, 0x36, 0x17, 0x21, 0x68, - 0x86, 0x16, 0x66, 0x26, 0x66, 0x61, 0x36, 0x66, - 0x68, 0x88, 0x86, 0x27, 0x22, 0x28, 0x88, 0x88, - 0x17, 0x72, 0x2a, 0x66, 0xa2, 0x22, 0x36, 0x55, - 0x55, 0x58, 0x37, 0x3a, 0x16, 0x66, 0x66, 0x66, - 0x66, 0x18, 0x88, 0x67, 0x16, 0x12, 0x71, 0x68, - 0x81, 0x68, 0x61, 0x76, 0x66, 0x6a, 0x16, 0x66, - 0x88, 0x88, 0x86, 0x77, 0x22, 0x26, 0x88, 0x88, - 0x13, 0x37, 0x71, 0x66, 0xa2, 0x33, 0x2a, 0x85, - 0x55, 0x55, 0x17, 0x73, 0x16, 0x66, 0x66, 0x68, - 0x63, 0x88, 0x88, 0xa2, 0x66, 0xa2, 0xa6, 0x88, - 0x61, 0x68, 0x6a, 0x76, 0x66, 0x6a, 0x66, 0x6a + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x78, 0x00, 0x00, 0x00, 0x08, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x88, 0x00, + 0x87, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x88, 0x80, + 0x07, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x88, 0x00, + 0x00, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x87, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x88, 0x08, 0x00, + 0x00, 0x08, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x00, + 0x77, 0x70, 0x00, 0x00, 0x87, 0x77, 0x78, 0x00, + 0x00, 0x08, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x08, + 0x7F, 0xF7, 0x00, 0x08, 0x7F, 0xFF, 0xF7, 0x00, + 0x00, 0x00, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x07, + 0x78, 0x7F, 0x00, 0x08, 0xF7, 0x08, 0x7F, 0x00, + 0x00, 0x00, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x07, + 0x88, 0x8F, 0x80, 0x88, 0xF8, 0x08, 0x8F, 0x80, + 0x00, 0x00, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x07, + 0x00, 0x87, 0x00, 0x08, 0xF0, 0x00, 0x0F, 0x80, + 0x00, 0x00, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x07, + 0x80, 0x06, 0x66, 0x66, 0x78, 0x00, 0x8F, 0x80, + 0x00, 0x00, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x08, + 0xF8, 0x66, 0xEE, 0x66, 0xE6, 0x68, 0xFF, 0x00, + 0x00, 0x00, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x00, + 0x76, 0x6E, 0xEE, 0xEE, 0xEE, 0xEE, 0xE6, 0x00, + 0x00, 0x00, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x00, + 0x66, 0x6E, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x80, + 0x00, 0x00, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x06, + 0x66, 0xEE, 0xEE, 0xEE, 0xEE, 0xE6, 0x66, 0x80, + 0x00, 0x00, 0x87, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x06, + 0x66, 0xEE, 0xEE, 0xEE, 0xEE, 0x66, 0x66, 0x80, + 0x00, 0x00, 0x07, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x00, + 0x66, 0xEE, 0xEE, 0xEE, 0x66, 0x66, 0x66, 0x00, + 0x08, 0x00, 0x07, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x00, + 0x76, 0x66, 0x66, 0x66, 0x66, 0x6C, 0x77, 0x80, + 0x08, 0x78, 0x08, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x00, + 0x77, 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x70, + 0x00, 0x88, 0x00, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x00, + 0x77, 0x76, 0x66, 0x66, 0x67, 0x77, 0xFF, 0xF8, + 0x00, 0x00, 0x00, 0x87, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x70, 0x08, + 0xF7, 0x77, 0x77, 0x77, 0x77, 0x7F, 0xFF, 0xF7, + 0x00, 0x00, 0x00, 0x07, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x80, 0x07, + 0xFF, 0x77, 0x77, 0x77, 0x7F, 0xFF, 0xFF, 0xFF, + 0x80, 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x00, 0x8F, + 0xFF, 0x77, 0x77, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, + 0x70, 0x00, 0x00, 0x00, 0x87, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x70, 0x00, 0xFF, + 0xFF, 0xFF, 0x77, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF8, 0x00, 0x00, 0x00, 0x07, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x00, 0x07, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF8, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x78, 0x00, 0x0F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF7, 0x00, 0x00, 0x00, 0x00, 0x07, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x80, 0x00, 0x8F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x78, 0x00, 0x00, 0x87, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x87, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x70, 0x00, 0x00, 0x87, 0x7F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x77, + 0x77, 0x70, 0x00, 0x00, 0x00, 0x00, 0x07, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x70, 0x00, 0x00, 0x7F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x77, 0xF7, 0x00, 0x00, 0x00, 0x00, 0x08, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x80, 0x00, 0x08, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x7F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x00, 0x80, 0x0F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF7, 0x70, 0x00, 0x00, 0x00, 0x00, 0x87, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x00, 0x00, 0x7F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF8, 0x08, 0x08, 0x00, 0x00, 0x07, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x78, 0x08, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF7, 0x08, 0x80, 0x00, 0x00, 0x07, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x70, 0x00, 0x07, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF7, 0x00, 0x00, 0x80, 0x00, 0x08, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x70, 0x80, 0x0F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x80, 0x00, 0x8F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x87, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x70, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x87, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x70, 0x08, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x00, 0x08, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x00, 0x08, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x00, 0x08, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x80, 0x08, 0x00, 0x00, 0x00, + 0x07, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x08, 0x80, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x87, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x6E, 0xE6, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x80, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x7E, 0xEE, 0xEE, 0x60, 0x8F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFE, 0x60, 0x00, 0x00, 0x00, 0x80, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x76, 0x6E, 0xEE, 0xE6, 0x08, 0x7F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x6E, 0x60, 0x00, 0x00, 0x00, 0x06, + 0xE7, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x66, 0xEE, 0xEE, 0xEE, 0x60, 0x07, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x6E, 0x60, 0x00, 0x00, 0x00, 0x8E, + 0xEE, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x76, 0x66, 0x66, + 0x6E, 0xEE, 0xEE, 0xEE, 0x60, 0x00, 0x7F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xE6, 0x60, 0x00, 0x00, 0x00, 0xCE, + 0xEE, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x66, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xE6, 0x00, 0x08, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF6, 0xE6, 0x66, 0x00, 0x00, 0x66, 0x6E, + 0xEE, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x66, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x80, 0x00, 0x8F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x76, 0x66, 0x66, 0x66, 0x66, 0x66, 0xEE, + 0xEE, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x66, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x60, 0x00, 0x00, + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF7, 0x76, 0x6E, 0x66, 0x66, 0x66, 0x6E, 0xEE, + 0xEE, 0xE7, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x66, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xE6, 0x00, 0x00, + 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF7, 0x76, 0x6E, 0xE6, 0x66, 0x66, 0xEE, 0xEE, + 0xEE, 0xEE, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x66, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x60, 0x00, + 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF7, 0x86, 0x6E, 0xEE, 0xEE, 0x6E, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0xC6, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x68, 0x00, + 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF8, 0x06, 0x6E, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x76, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xE6, 0x00, + 0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x80, 0x86, 0x6E, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xE7, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0xC6, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xE6, 0x7F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, + 0x00, 0x86, 0x6E, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xE7, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x66, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x67, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x00, + 0x00, 0x86, 0x6E, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0xE6, 0xE7, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x6E, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x68, + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x00, 0x00, + 0x00, 0x66, 0x6E, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0xEE, 0xE6, 0xC7, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x66, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xE6, 0x66, + 0x08, 0x87, 0x77, 0x77, 0x88, 0x00, 0x00, 0x00, + 0x00, 0x66, 0x6E, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0xE6, 0xC7, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x76, 0x66, 0x66, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xE6, 0x66, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x66, 0x6E, 0xEE, 0xEE, 0xEE, 0xE6, 0x66, + 0x67, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, + 0x66, 0x66, 0xEE, 0xEE, 0xEE, 0xEE, 0xE6, 0x66, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x66, 0x66, 0xEE, 0xEE, 0xEE, 0x66, 0x6C, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x76, 0x66, + 0x66, 0x66, 0x66, 0x6E, 0xEE, 0xEE, 0x66, 0x66, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x66, 0x66, 0x6E, 0xE6, 0x66, 0x66, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x76, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x00, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x76, 0x66, 0x66, 0x66, 0x66, 0x67, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x76, 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, }; #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/list.h linux.ac/include/linux/list.h --- linux.vanilla/include/linux/list.h Sat Feb 17 00:06:17 2001 +++ linux.ac/include/linux/list.h Tue Apr 3 18:11:10 2001 @@ -3,6 +3,8 @@ #if defined(__KERNEL__) || defined(_LVM_H_INCLUDE) +#include <linux/prefetch.h> + /* * Simple doubly linked list implementation. * @@ -147,8 +149,9 @@ * @head: the head for your list. */ #define list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - + for (pos = (head)->next, prefetch(pos->next); pos != (head); \ + pos = pos->next, prefetch(pos->next)) + #endif /* __KERNEL__ || _LVM_H_INCLUDE */ #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/lockd/nlm.h linux.ac/include/linux/lockd/nlm.h --- linux.vanilla/include/linux/lockd/nlm.h Mon Dec 11 21:25:38 2000 +++ linux.ac/include/linux/lockd/nlm.h Tue Apr 3 19:15:37 2001 @@ -49,10 +49,10 @@ #define NLMPROC_CANCEL_RES 13 #define NLMPROC_UNLOCK_RES 14 #define NLMPROC_GRANTED_RES 15 +#define NLMPROC_NSM_NOTIFY 16 /* statd callback */ #define NLMPROC_SHARE 20 #define NLMPROC_UNSHARE 21 #define NLMPROC_NM_LOCK 22 #define NLMPROC_FREE_ALL 23 -#define NLMPROC_NSM_NOTIFY 24 /* statd callback */ #endif /* LINUX_LOCKD_NLM_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/major.h linux.ac/include/linux/major.h --- linux.vanilla/include/linux/major.h Sat Dec 30 19:23:14 2000 +++ linux.ac/include/linux/major.h Sat Apr 14 01:41:24 2001 @@ -128,6 +128,8 @@ #define IDE8_MAJOR 90 #define IDE9_MAJOR 91 +#define UBD_MAJOR 98 + #define AURORA_MAJOR 79 #define JSFD_MAJOR 99 @@ -155,6 +157,9 @@ #define CPUID_MAJOR 203 #define OSST_MAJOR 206 /* OnStream-SCx0 SCSI tape */ + +#define IBM_TTY3270_MAJOR 227 /* Official allocations now */ +#define IBM_FS3270_MAJOR 228 /* * Tests for SCSI devices. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/miscdevice.h linux.ac/include/linux/miscdevice.h --- linux.vanilla/include/linux/miscdevice.h Thu Feb 22 00:10:00 2001 +++ linux.ac/include/linux/miscdevice.h Sun Apr 15 23:21:15 2001 @@ -21,6 +21,7 @@ #define NVRAM_MINOR 144 #define I2O_MINOR 166 #define MICROCODE_MINOR 184 +#define MPT_MINOR 220 #define MISC_DYNAMIC_MINOR 255 #define SGI_GRAPHICS_MINOR 146 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/mm.h linux.ac/include/linux/mm.h --- linux.vanilla/include/linux/mm.h Tue Apr 3 17:32:28 2001 +++ linux.ac/include/linux/mm.h Tue Apr 17 17:29:22 2001 @@ -39,32 +39,38 @@ * library, the executable area etc). */ struct vm_area_struct { - struct mm_struct * vm_mm; /* VM area parameters */ - unsigned long vm_start; - unsigned long vm_end; + struct mm_struct * vm_mm; /* The address space we belong to. */ + unsigned long vm_start; /* Our start address within vm_mm. */ + unsigned long vm_end; /* The first byte after our end address + within vm_mm. */ /* linked list of VM areas per task, sorted by address */ struct vm_area_struct *vm_next; - pgprot_t vm_page_prot; - unsigned long vm_flags; + pgprot_t vm_page_prot; /* Access permissions of this VMA. */ + unsigned long vm_flags; /* Flags, listed below. */ /* AVL tree of VM areas per task, sorted by address */ short vm_avl_height; struct vm_area_struct * vm_avl_left; struct vm_area_struct * vm_avl_right; - /* For areas with an address space and backing store, + /* + * For areas with an address space and backing store, * one of the address_space->i_mmap{,shared} lists, * for shm areas, the list of attaches, otherwise unused. */ struct vm_area_struct *vm_next_share; struct vm_area_struct **vm_pprev_share; + /* Function pointers to deal with this struct. */ struct vm_operations_struct * vm_ops; - unsigned long vm_pgoff; /* offset in PAGE_SIZE units, *not* PAGE_CACHE_SIZE */ - struct file * vm_file; - unsigned long vm_raend; + + /* Information about our backing store: */ + unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE + units, *not* PAGE_CACHE_SIZE */ + struct file * vm_file; /* File we map to (can be NULL). */ + unsigned long vm_raend; /* XXX: put full readahead info here. */ void * vm_private_data; /* was vm_pte (shared mem) */ }; @@ -90,6 +96,7 @@ #define VM_LOCKED 0x00002000 #define VM_IO 0x00004000 /* Memory mapped I/O or similar */ + /* Used by sys_madvise() */ #define VM_SEQ_READ 0x00008000 /* App will access data sequentially */ #define VM_RAND_READ 0x00010000 /* App will not benefit from clustered reads */ @@ -124,37 +131,145 @@ }; /* + * Each physical page in the system has a struct page associated with + * it to keep track of whatever it is we are using the page for at the + * moment. Note that we have no way to track which tasks are using + * a page. + * * Try to keep the most commonly accessed fields in single cache lines * here (16 bytes or greater). This ordering should be particularly * beneficial on 32-bit processors. * * The first line is data used in page cache lookup, the second line * is used for linear searches (eg. clock algorithm scans). + * + * TODO: make this structure smaller, it could be as small as 32 bytes. */ typedef struct page { - struct list_head list; - struct address_space *mapping; - unsigned long index; - struct page *next_hash; - atomic_t count; - unsigned long flags; /* atomic flags, some possibly updated asynchronously */ - struct list_head lru; - unsigned long age; - wait_queue_head_t wait; - struct page **pprev_hash; - struct buffer_head * buffers; - void *virtual; /* non-NULL if kmapped */ - struct zone_struct *zone; + struct list_head list; /* ->mapping has some page lists. */ + struct address_space *mapping; /* The inode (or ...) we belong to. */ + unsigned long index; /* Our offset within mapping, in + units of PAGE_CACHE_SIZE. */ + struct page *next_hash; /* Next page sharing our hash bucket in + the page cache hash table. */ + atomic_t count; /* Usage count, see below. */ + unsigned long flags; /* atomic flags, some possibly + updated asynchronously */ + struct list_head lru; /* Pageout list, eg active_list; + protected by pagemap_lru_lock !! */ + unsigned long age; /* Page aging counter. */ + wait_queue_head_t wait; /* Page locked? Stand in line... */ + struct page **pprev_hash; /* Complement to *next_hash. */ + struct buffer_head * buffers; /* Buffer maps us to a disk block. */ + void *virtual; /* Kernel virtual address (NULL if + not kmapped, ie highmem) */ + struct zone_struct *zone; /* Memory zone we are in. */ } mem_map_t; +/* + * Methods to modify the page usage count. + * + * What counts for a page usage: + * - cache mapping (page->mapping) + * - disk mapping (page->buffers) + * - page mapped in a task's page tables, each mapping + * is counted separately + * + * Also, many kernel routines increase the page count before a critical + * routine so they can be sure the page doesn't go away from under them. + */ #define get_page(p) atomic_inc(&(p)->count) #define put_page(p) __free_page(p) #define put_page_testzero(p) atomic_dec_and_test(&(p)->count) #define page_count(p) atomic_read(&(p)->count) #define set_page_count(p,v) atomic_set(&(p)->count, v) -/* Page flag bit values */ -#define PG_locked 0 +/* + * Various page->flags bits: + * + * PG_reserved is set for special pages, which can never be swapped + * out. Some of them might not even exist (eg empty_bad_page)... + * + * Multiple processes may "see" the same page. E.g. for untouched + * mappings of /dev/null, all processes see the same page full of + * zeroes, and text pages of executables and shared libraries have + * only one copy in memory, at most, normally. + * + * For the non-reserved pages, page->count denotes a reference count. + * page->count == 0 means the page is free. + * page->count == 1 means the page is used for exactly one purpose + * (e.g. a private data page of one process). + * + * A page may be used for kmalloc() or anyone else who does a + * __get_free_page(). In this case the page->count is at least 1, and + * all other fields are unused but should be 0 or NULL. The + * management of this page is the responsibility of the one who uses + * it. + * + * The other pages (we may call them "process pages") are completely + * managed by the Linux memory manager: I/O, buffers, swapping etc. + * The following discussion applies only to them. + * + * A page may belong to an inode's memory mapping. In this case, + * page->mapping is the pointer to the inode, and page->index is the + * file offset of the page, in units of PAGE_CACHE_SIZE. + * + * A page may have buffers allocated to it. In this case, + * page->buffers is a circular list of these buffer heads. Else, + * page->buffers == NULL. + * + * For pages belonging to inodes, the page->count is the number of + * attaches, plus 1 if buffers are allocated to the page, plus one + * for the page cache itself. + * + * All pages belonging to an inode are in these doubly linked lists: + * mapping->clean_pages, mapping->dirty_pages and mapping->locked_pages; + * using the page->list list_head. These fields are also used for + * freelist managemet (when page->count==0). + * + * There is also a hash table mapping (mapping,index) to the page + * in memory if present. The lists for this hash table use the fields + * page->next_hash and page->pprev_hash. + * + * All process pages can do I/O: + * - inode pages may need to be read from disk, + * - inode pages which have been modified and are MAP_SHARED may need + * to be written to disk, + * - private pages which have been modified may need to be swapped out + * to swap space and (later) to be read back into memory. + * During disk I/O, PG_locked is used. This bit is set before I/O + * and reset when I/O completes. page->wait is a wait queue of all + * tasks waiting for the I/O on this page to complete. + * PG_uptodate tells whether the page's contents is valid. + * When a read completes, the page becomes uptodate, unless a disk I/O + * error happened. + * + * For choosing which pages to swap out, inode pages carry a + * PG_referenced bit, which is set any time the system accesses + * that page through the (mapping,index) hash table. This referenced + * bit, together with the referenced bit in the page tables, is used + * to manipulate page->age and move the page across the active, + * inactive_dirty and inactive_clean lists. + * + * Note that the referenced bit, the page->lru list_head and the + * active, inactive_dirty and inactive_clean lists are protected by + * the pagemap_lru_lock, and *NOT* by the usual PG_locked bit! + * + * PG_skip is used on sparc/sparc64 architectures to "skip" certain + * parts of the address space. + * + * PG_error is set to indicate that an I/O error occurred on this page. + * + * PG_arch_1 is an architecture specific page state bit. The generic + * code guarantees that this bit is cleared for a page when it first + * is entered into the page cache. + * + * PG_highmem pages are not permanently mapped into the kernel virtual + * address space, they need to be kmapped separately for doing IO on + * the pages. The struct page (these bits with information) are always + * mapped into kernel address space... + */ +#define PG_locked 0 /* Page is locked. Don't touch. */ #define PG_error 1 #define PG_referenced 2 #define PG_uptodate 3 @@ -254,81 +369,7 @@ #define NOPAGE_SIGBUS (NULL) #define NOPAGE_OOM ((struct page *) (-1)) - -/* - * Various page->flags bits: - * - * PG_reserved is set for a page which must never be accessed (which - * may not even be present). - * - * PG_DMA has been removed, page->zone now tells exactly wether the - * page is suited to do DMAing into. - * - * Multiple processes may "see" the same page. E.g. for untouched - * mappings of /dev/null, all processes see the same page full of - * zeroes, and text pages of executables and shared libraries have - * only one copy in memory, at most, normally. - * - * For the non-reserved pages, page->count denotes a reference count. - * page->count == 0 means the page is free. - * page->count == 1 means the page is used for exactly one purpose - * (e.g. a private data page of one process). - * - * A page may be used for kmalloc() or anyone else who does a - * __get_free_page(). In this case the page->count is at least 1, and - * all other fields are unused but should be 0 or NULL. The - * management of this page is the responsibility of the one who uses - * it. - * - * The other pages (we may call them "process pages") are completely - * managed by the Linux memory manager: I/O, buffers, swapping etc. - * The following discussion applies only to them. - * - * A page may belong to an inode's memory mapping. In this case, - * page->inode is the pointer to the inode, and page->offset is the - * file offset of the page (not necessarily a multiple of PAGE_SIZE). - * - * A page may have buffers allocated to it. In this case, - * page->buffers is a circular list of these buffer heads. Else, - * page->buffers == NULL. - * - * For pages belonging to inodes, the page->count is the number of - * attaches, plus 1 if buffers are allocated to the page. - * - * All pages belonging to an inode make up a doubly linked list - * inode->i_pages, using the fields page->next and page->prev. (These - * fields are also used for freelist management when page->count==0.) - * There is also a hash table mapping (inode,offset) to the page - * in memory if present. The lists for this hash table use the fields - * page->next_hash and page->pprev_hash. - * - * All process pages can do I/O: - * - inode pages may need to be read from disk, - * - inode pages which have been modified and are MAP_SHARED may need - * to be written to disk, - * - private pages which have been modified may need to be swapped out - * to swap space and (later) to be read back into memory. - * During disk I/O, PG_locked is used. This bit is set before I/O - * and reset when I/O completes. page->wait is a wait queue of all - * tasks waiting for the I/O on this page to complete. - * PG_uptodate tells whether the page's contents is valid. - * When a read completes, the page becomes uptodate, unless a disk I/O - * error happened. - * - * For choosing which pages to swap out, inode pages carry a - * PG_referenced bit, which is set any time the system accesses - * that page through the (inode,offset) hash table. - * - * PG_skip is used on sparc/sparc64 architectures to "skip" certain - * parts of the address space. - * - * PG_error is set to indicate that an I/O error occurred on this page. - * - * PG_arch_1 is an architecture specific page state bit. The generic - * code guarentees that this bit is cleared for a page when it first - * is entered into the page cache. - */ - +/* The array of struct pages */ extern mem_map_t * mem_map; /* @@ -394,7 +435,7 @@ extern int remap_page_range(unsigned long from, unsigned long to, unsigned long size, pgprot_t prot); extern int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t prot); -extern void vmtruncate(struct inode * inode, loff_t offset); +extern int vmtruncate(struct inode * inode, loff_t offset); extern pmd_t *FASTCALL(__pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address)); extern pte_t *FASTCALL(pte_alloc(struct mm_struct *mm, pmd_t *pmd, unsigned long address)); extern int handle_mm_fault(struct mm_struct *mm,struct vm_area_struct *vma, unsigned long address, int write_access); @@ -407,6 +448,8 @@ * On a two-level page table, this ends up being trivial. Thus the * inlining and the symmetry break with pte_alloc() that does all * of this out-of-line. + * + * __pmd_alloc() requires that mm->page_table_lock be held, so we do too. */ static inline pmd_t *pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address) { @@ -434,7 +477,8 @@ extern void __insert_vm_struct(struct mm_struct *, struct vm_area_struct *); extern void build_mmap_avl(struct mm_struct *); extern void exit_mmap(struct mm_struct *); -extern unsigned long get_unmapped_area(unsigned long, unsigned long); + +extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, unsigned long len, unsigned long prot, @@ -480,8 +524,10 @@ #define __GFP_HIGHMEM 0x0 /* noop */ #endif #define __GFP_VM 0x20 +#define __GFP_FAIL 0x40 +#define GFP_BOUNCE (__GFP_HIGH | __GFP_FAIL) #define GFP_BUFFER (__GFP_HIGH | __GFP_WAIT) #define GFP_ATOMIC (__GFP_HIGH) #define GFP_USER ( __GFP_WAIT | __GFP_IO) @@ -533,11 +579,6 @@ } extern struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr); - -#define buffer_under_min() (atomic_read(&buffermem_pages) * 100 < \ - buffer_mem.min_percent * num_physpages) -#define pgcache_under_min() (atomic_read(&page_cache_size) * 100 < \ - page_cache.min_percent * num_physpages) #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/mroute.h linux.ac/include/linux/mroute.h --- linux.vanilla/include/linux/mroute.h Thu Feb 22 00:09:59 2001 +++ linux.ac/include/linux/mroute.h Sat Apr 14 01:42:01 2001 @@ -215,8 +215,8 @@ __u32 flags; }; -extern int pim_rcv(struct sk_buff * , unsigned short); -extern int pim_rcv_v1(struct sk_buff * , unsigned short len); +extern int pim_rcv(struct sk_buff *); +extern int pim_rcv_v1(struct sk_buff *); struct rtmsg; extern int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/msdos_fs.h linux.ac/include/linux/msdos_fs.h --- linux.vanilla/include/linux/msdos_fs.h Mon Dec 11 21:25:10 2000 +++ linux.ac/include/linux/msdos_fs.h Mon Apr 16 00:20:57 2001 @@ -54,8 +54,7 @@ #define SCAN_NOTANY 3 /* test name, then use SCAN_HID or SCAN_NOTHID */ #define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */ -#define IS_FREE(n) (!*(n) || *(const unsigned char *) (n) == DELETED_FLAG || \ - *(const unsigned char *) (n) == FD_FILL_BYTE) +#define IS_FREE(n) (!*(n) || *(const unsigned char *) (n) == DELETED_FLAG) #define MSDOS_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO) /* valid file mode bits */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/nbd.h linux.ac/include/linux/nbd.h --- linux.vanilla/include/linux/nbd.h Mon Dec 11 20:50:42 2000 +++ linux.ac/include/linux/nbd.h Tue Apr 17 17:57:33 2001 @@ -31,35 +31,27 @@ extern int requests_out; #endif -static int +static void nbd_end_request(struct request *req) { + struct buffer_head *bh; + unsigned nsect; unsigned long flags; - int ret = 0; + int uptodate = (req->errors == 0) ? 1 : 0; #ifdef PARANOIA requests_out++; #endif - /* - * This is a very dirty hack that we have to do to handle - * merged requests because end_request stuff is a bit - * broken. The fact we have to do this only if there - * aren't errors looks even more silly. - */ - if (!req->errors) { - req->sector += req->current_nr_sectors; - req->nr_sectors -= req->current_nr_sectors; - } - spin_lock_irqsave(&io_request_lock, flags); - if (end_that_request_first( req, !req->errors, "nbd" )) - goto out; - ret = 1; - end_that_request_last( req ); - -out: + while((bh = req->bh) != NULL) { + nsect = bh->b_size >> 9; + blk_finished_io(nsect); + req->bh = bh->b_reqnext; + bh->b_reqnext = NULL; + bh->b_end_io(bh, uptodate); + } + blkdev_release_request(req); spin_unlock_irqrestore(&io_request_lock, flags); - return ret; } #define MAX_NBD 128 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/net.h linux.ac/include/linux/net.h --- linux.vanilla/include/linux/net.h Thu Feb 22 00:09:58 2001 +++ linux.ac/include/linux/net.h Sat Apr 14 15:05:37 2001 @@ -82,6 +82,7 @@ struct scm_cookie; struct vm_area_struct; +struct page; struct proto_ops { int family; @@ -108,6 +109,7 @@ int (*sendmsg) (struct socket *sock, struct msghdr *m, int total_len, struct scm_cookie *scm); int (*recvmsg) (struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm); int (*mmap) (struct file *file, struct socket *sock, struct vm_area_struct * vma); + ssize_t (*sendpage) (struct socket *sock, struct page *page, int offset, size_t size, int flags); }; struct net_proto_family diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/netdevice.h linux.ac/include/linux/netdevice.h --- linux.vanilla/include/linux/netdevice.h Tue Apr 3 17:32:29 2001 +++ linux.ac/include/linux/netdevice.h Tue Apr 17 17:44:38 2001 @@ -653,6 +653,7 @@ extern unsigned long netdev_fc_xoff; extern atomic_t netdev_dropping; extern int netdev_set_master(struct net_device *dev, struct net_device *master); +extern struct sk_buff * skb_checksum_help(struct sk_buff *skb); #ifdef CONFIG_NET_FASTROUTE extern int netdev_fastroute; extern int netdev_fastroute_obstacles; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/nfs.h linux.ac/include/linux/nfs.h --- linux.vanilla/include/linux/nfs.h Sat Apr 1 17:04:27 2000 +++ linux.ac/include/linux/nfs.h Tue Apr 3 17:55:17 2001 @@ -93,8 +93,8 @@ */ #define NFS_MAXFHSIZE 64 struct nfs_fh { - unsigned short size; - unsigned char data[NFS_MAXFHSIZE]; + unsigned int size; + unsigned int data[NFS_MAXFHSIZE / sizeof(int)]; }; /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/nfs3.h linux.ac/include/linux/nfs3.h --- linux.vanilla/include/linux/nfs3.h Sat Apr 1 17:04:27 2000 +++ linux.ac/include/linux/nfs3.h Tue Apr 3 17:55:17 2001 @@ -58,6 +58,11 @@ NF3BAD = 8 }; +struct nfs3_fh { + unsigned short size; + unsigned char data[NFS3_FHSIZE]; +}; + #define NFS3_VERSION 3 #define NFS3PROC_NULL 0 #define NFS3PROC_GETATTR 1 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/nfs_fs.h linux.ac/include/linux/nfs_fs.h --- linux.vanilla/include/linux/nfs_fs.h Thu Feb 22 00:11:03 2001 +++ linux.ac/include/linux/nfs_fs.h Tue Apr 17 17:44:59 2001 @@ -260,8 +260,8 @@ * linux/fs/mount_clnt.c * (Used only by nfsroot module) */ -extern int nfs_mount(struct sockaddr_in *, char *, struct nfs_fh *); -extern int nfs3_mount(struct sockaddr_in *, char *, struct nfs_fh *); +extern int nfs_mount(struct sockaddr_in *, char *, struct nfs3_fh *); +extern int nfs3_mount(struct sockaddr_in *, char *, struct nfs3_fh *); /* * inline functions diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/nfs_mount.h linux.ac/include/linux/nfs_mount.h --- linux.vanilla/include/linux/nfs_mount.h Thu Feb 22 00:10:45 2001 +++ linux.ac/include/linux/nfs_mount.h Tue Apr 3 18:25:32 2001 @@ -9,7 +9,8 @@ * structure passed from user-space to kernel-space during an nfs mount */ #include <linux/in.h> -#include <linux/nfs.h> +#include <linux/nfs2.h> +#include <linux/nfs3.h> /* * WARNING! Do not delete or change the order of these fields. If @@ -37,7 +38,7 @@ char hostname[256]; /* 1 */ int namlen; /* 2 */ unsigned int bsize; /* 3 */ - struct nfs_fh root; /* 4 */ + struct nfs3_fh root; /* 4 */ }; /* bits in the flags field */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/nfsd/nfsfh.h linux.ac/include/linux/nfsd/nfsfh.h --- linux.vanilla/include/linux/nfsd/nfsfh.h Thu Feb 22 00:10:23 2001 +++ linux.ac/include/linux/nfsd/nfsfh.h Mon Apr 16 00:22:28 2001 @@ -31,7 +31,7 @@ * ino/dev of the exported inode. */ struct nfs_fhbase_old { - struct dentry * fb_dentry; /* dentry cookie - always 0xfeebbaca */ + __u32 fb_dcookie; /* dentry cookie - always 0xfeebbaca */ __u32 fb_ino; /* our inode number */ __u32 fb_dirino; /* dir inode number, 0 for directories */ __u32 fb_dev; /* our device */ @@ -101,7 +101,7 @@ } fh_base; }; -#define ofh_dcookie fh_base.fh_old.fb_dentry +#define ofh_dcookie fh_base.fh_old.fb_dcookie #define ofh_ino fh_base.fh_old.fb_ino #define ofh_dirino fh_base.fh_old.fb_dirino #define ofh_dev fh_base.fh_old.fb_dev diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/ntfs_fs_i.h linux.ac/include/linux/ntfs_fs_i.h --- linux.vanilla/include/linux/ntfs_fs_i.h Thu Feb 10 20:17:00 2000 +++ linux.ac/include/linux/ntfs_fs_i.h Tue Apr 3 17:55:17 2001 @@ -60,24 +60,23 @@ typedef unsigned int ntfs_cluster_t; #endif -/* Definition of NTFS in-memory inode structure */ +/* Definition of the NTFS in-memory inode structure. */ struct ntfs_inode_info{ unsigned long mmu_private; struct ntfs_sb_info *vol; - int i_number; /* should be really 48 bits */ - unsigned sequence_number; - unsigned char* attr; /* array of the attributes */ - int attr_count; /* size of attrs[] */ + int i_number; /* Should be really 48 bits. */ + __u16 sequence_number; /* The current sequence number. */ + unsigned char* attr; /* Array of the attributes. */ + int attr_count; /* Size of attrs[]. */ struct ntfs_attribute *attrs; - int record_count; /* size of records[] */ - /* array of the record numbers of the MFT - whose attributes have been inserted in the inode */ - int *records; - union{ - struct{ + int record_count; /* Size of records[]. */ + int *records; /* Array of the record numbers of the $Mft whose + * attributes have been inserted in the inode. */ + union { + struct { int recordsize; int clusters_per_record; - }index; + } index; } u; }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/ntfs_fs_sb.h linux.ac/include/linux/ntfs_fs_sb.h --- linux.vanilla/include/linux/ntfs_fs_sb.h Tue May 2 21:46:53 2000 +++ linux.ac/include/linux/ntfs_fs_sb.h Tue Apr 3 17:55:17 2001 @@ -2,16 +2,17 @@ #define _LINUX_NTFS_FS_SB_H struct ntfs_sb_info{ - /* Configuration provided by user at mount time */ + /* Configuration provided by user at mount time. */ ntfs_uid_t uid; ntfs_gid_t gid; ntmode_t umask; unsigned int nct; void *nls_map; unsigned int ngt; - /* Configuration provided by user with ntfstools */ - ntfs_size_t partition_bias; /* for access to underlying device */ - /* Attribute definitions */ + /* Configuration provided by user with the ntfstools. + * FIXME: This is no longer possible. What is this good for? (AIA) */ + ntfs_size_t partition_bias; /* For access to underlying device. */ + /* Attribute definitions. */ ntfs_u32 at_standard_information; ntfs_u32 at_attribute_list; ntfs_u32 at_file_name; @@ -24,20 +25,20 @@ ntfs_u32 at_index_allocation; ntfs_u32 at_bitmap; ntfs_u32 at_symlink; /* aka SYMBOLIC_LINK or REPARSE_POINT */ - /* Data read from the boot file */ + /* Data read / calculated from the boot file. */ int blocksize; - int clusterfactor; + int clusterfactorbits; int clustersize; int mft_recordsize; int mft_clusters_per_record; int index_recordsize; int index_clusters_per_record; int mft_cluster; - /* data read from special files */ + /* Data read from special files. */ unsigned char *mft; unsigned short *upcase; unsigned int upcase_length; - /* inodes we always hold onto */ + /* Inodes we always hold onto. */ struct ntfs_inode_info *mft_ino; struct ntfs_inode_info *mftmirr; struct ntfs_inode_info *bitmap; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/pagemap.h linux.ac/include/linux/pagemap.h --- linux.vanilla/include/linux/pagemap.h Tue Apr 3 17:32:29 2001 +++ linux.ac/include/linux/pagemap.h Tue Apr 17 17:44:38 2001 @@ -34,7 +34,7 @@ static inline struct page *page_cache_alloc(struct address_space *x) { - return alloc_pages(x->gfp_mask, 0); + return alloc_pages(x ? x->gfp_mask : GFP_HIGHUSER, 0); } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/parport.h linux.ac/include/linux/parport.h --- linux.vanilla/include/linux/parport.h Thu Feb 8 18:40:25 2001 +++ linux.ac/include/linux/parport.h Tue Apr 17 17:57:35 2001 @@ -11,8 +11,8 @@ /* Start off with user-visible constants */ -/* Maximum of 8 ports per machine */ -#define PARPORT_MAX 8 +/* Maximum of 16 ports per machine */ +#define PARPORT_MAX 16 /* Magic numbers */ #define PARPORT_IRQ_NONE -1 @@ -91,6 +91,10 @@ /* Flags for block transfer operations. */ #define PARPORT_EPP_FAST (1<<0) /* Unreliable counts. */ +struct parport_device_id { + const char *pattern; +}; + /* The rest is for the kernel only */ #ifdef __KERNEL__ @@ -229,7 +233,7 @@ unsigned long int time; unsigned long int timeslice; volatile long int timeout; - unsigned long waiting; /* long req'd for set_bit --RR */ + unsigned long waiting; struct pardevice *waitprev; struct pardevice *waitnext; void * sysctl_table; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/pci.h linux.ac/include/linux/pci.h --- linux.vanilla/include/linux/pci.h Tue Apr 3 17:32:29 2001 +++ linux.ac/include/linux/pci.h Tue Apr 17 17:44:38 2001 @@ -302,8 +302,6 @@ #define pci_present pcibios_present -#define pci_for_each_dev(dev) \ - for(dev = pci_dev_g(pci_devices.next); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.next)) #define pci_for_each_dev_reverse(dev) \ for(dev = pci_dev_g(pci_devices.prev); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.prev)) @@ -460,6 +458,9 @@ /* these external functions are only available when PCI support is enabled */ #ifdef CONFIG_PCI +#define pci_for_each_dev(dev) \ + for(dev = pci_dev_g(pci_devices.next); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.next)) + void pcibios_init(void); void pcibios_fixup_bus(struct pci_bus *); int pcibios_enable_device(struct pci_dev *); @@ -525,7 +526,9 @@ int pci_write_config_word(struct pci_dev *dev, int where, u16 val); int pci_write_config_dword(struct pci_dev *dev, int where, u32 val); +#define HAVE_PCI_DISABLE_DEVICE int pci_enable_device(struct pci_dev *dev); +void pci_disable_device(struct pci_dev *dev); void pci_set_master(struct pci_dev *dev); int pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask); int pci_set_power_state(struct pci_dev *dev, int state); @@ -594,12 +597,17 @@ static inline void pci_set_master(struct pci_dev *dev) { } static inline int pci_enable_device(struct pci_dev *dev) { return -EIO; } +static inline void pci_disable_device(struct pci_dev *dev) { } static inline int pci_module_init(struct pci_driver *drv) { return -ENODEV; } static inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUSY;} static inline int pci_register_driver(struct pci_driver *drv) { return 0;} static inline void pci_unregister_driver(struct pci_driver *drv) { } static inline int scsi_to_pci_dma_dir(unsigned char scsi_dir) { return scsi_dir; } static inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; } +static inline const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev) { return NULL; } + +#define pci_for_each_dev(dev) \ + for(dev = NULL; 0; ) #else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/pci_ids.h linux.ac/include/linux/pci_ids.h --- linux.vanilla/include/linux/pci_ids.h Tue Apr 3 17:32:29 2001 +++ linux.ac/include/linux/pci_ids.h Tue Apr 3 17:55:17 2001 @@ -174,14 +174,63 @@ #define PCI_DEVICE_ID_ATI_215LG 0x4c47 #define PCI_DEVICE_ID_ATI_264LT 0x4c54 #define PCI_DEVICE_ID_ATI_264VT 0x5654 +/* Rage128 Pro GL */ +#define PCI_DEVICE_ID_ATI_Rage128_PA 0x5041 +#define PCI_DEVICE_ID_ATI_Rage128_PB 0x5042 +#define PCI_DEVICE_ID_ATI_Rage128_PC 0x5043 +#define PCI_DEVICE_ID_ATI_Rage128_PD 0x5044 +#define PCI_DEVICE_ID_ATI_Rage128_PE 0x5045 +#define PCI_DEVICE_ID_ATI_RAGE128_PF 0x5046 +/* Rage128 Pro VR */ +#define PCI_DEVICE_ID_ATI_RAGE128_PG 0x5047 +#define PCI_DEVICE_ID_ATI_RAGE128_PH 0x5048 +#define PCI_DEVICE_ID_ATI_RAGE128_PI 0x5049 +#define PCI_DEVICE_ID_ATI_RAGE128_PJ 0x504A +#define PCI_DEVICE_ID_ATI_RAGE128_PK 0x504B +#define PCI_DEVICE_ID_ATI_RAGE128_PL 0x504C +#define PCI_DEVICE_ID_ATI_RAGE128_PM 0x504D +#define PCI_DEVICE_ID_ATI_RAGE128_PN 0x504E +#define PCI_DEVICE_ID_ATI_RAGE128_PO 0x504F +#define PCI_DEVICE_ID_ATI_RAGE128_PP 0x5050 +#define PCI_DEVICE_ID_ATI_RAGE128_PQ 0x5051 +#define PCI_DEVICE_ID_ATI_RAGE128_PR 0x5052 +#define PCI_DEVICE_ID_ATI_RAGE128_TR 0x5452 +#define PCI_DEVICE_ID_ATI_RAGE128_PS 0x5053 +#define PCI_DEVICE_ID_ATI_RAGE128_PT 0x5054 +#define PCI_DEVICE_ID_ATI_RAGE128_PU 0x5055 +#define PCI_DEVICE_ID_ATI_RAGE128_PV 0x5056 +#define PCI_DEVICE_ID_ATI_RAGE128_PW 0x5057 +#define PCI_DEVICE_ID_ATI_RAGE128_PX 0x5058 +/* Rage128 GL */ #define PCI_DEVICE_ID_ATI_RAGE128_RE 0x5245 #define PCI_DEVICE_ID_ATI_RAGE128_RF 0x5246 +#define PCI_DEVICE_ID_ATI_RAGE128_RG 0x534b +#define PCI_DEVICE_ID_ATI_RAGE128_RH 0x534c +#define PCI_DEVICE_ID_ATI_RAGE128_RI 0x534d +/* Rage128 VR */ #define PCI_DEVICE_ID_ATI_RAGE128_RK 0x524b #define PCI_DEVICE_ID_ATI_RAGE128_RL 0x524c -#define PCI_DEVICE_ID_ATI_RAGE128_PF 0x5046 -#define PCI_DEVICE_ID_ATI_RAGE128_PR 0x5052 +#define PCI_DEVICE_ID_ATI_RAGE128_RM 0x5345 +#define PCI_DEVICE_ID_ATI_RAGE128_RN 0x5346 +#define PCI_DEVICE_ID_ATI_RAGE128_RO 0x5347 +/* Rage128 M3 */ #define PCI_DEVICE_ID_ATI_RAGE128_LE 0x4c45 #define PCI_DEVICE_ID_ATI_RAGE128_LF 0x4c46 +/* Rage128 Pro Ultra */ +#define PCI_DEVICE_ID_ATI_RAGE128_U1 0x5446 +#define PCI_DEVICE_ID_ATI_RAGE128_U2 0x544C +#define PCI_DEVICE_ID_ATI_RAGE128_U3 0x5452 +/* Radeon M4 */ +#define PCI_DEVICE_ID_ATI_RADEON_LE 0x4d45 +#define PCI_DEVICE_ID_ATI_RADEON_LF 0x4d46 +/* Radeon NV-100 */ +#define PCI_DEVICE_ID_ATI_RADEON_N1 0x5159 +#define PCI_DEVICE_ID_ATI_RADEON_N2 0x515a +/* Radeon */ +#define PCI_DEVICE_ID_ATI_RADEON_RA 0x5144 +#define PCI_DEVICE_ID_ATI_RADEON_RB 0x5145 +#define PCI_DEVICE_ID_ATI_RADEON_RC 0x5146 +#define PCI_DEVICE_ID_ATI_RADEON_RD 0x5147 #define PCI_VENDOR_ID_VLSI 0x1004 #define PCI_DEVICE_ID_VLSI_82C592 0x0005 @@ -338,6 +387,7 @@ #define PCI_VENDOR_ID_NEC 0x1033 #define PCI_DEVICE_ID_NEC_PCX2 0x0046 #define PCI_DEVICE_ID_NEC_NILE4 0x005a +#define PCI_DEVICE_ID_NEC_VRC5476 0x009b #define PCI_VENDOR_ID_FD 0x1036 #define PCI_DEVICE_ID_FD_36C70 0x0000 @@ -352,9 +402,13 @@ #define PCI_DEVICE_ID_SI_501 0x0406 #define PCI_DEVICE_ID_SI_496 0x0496 #define PCI_DEVICE_ID_SI_300 0x0300 +#define PCI_DEVICE_ID_SI_315H 0x0310 +#define PCI_DEVICE_ID_SI_315 0x0315 #define PCI_DEVICE_ID_SI_530 0x0530 #define PCI_DEVICE_ID_SI_540 0x0540 +#define PCI_DEVICE_ID_SI_550 0x0550 #define PCI_DEVICE_ID_SI_540_VGA 0x5300 +#define PCI_DEVICE_ID_SI_550_VGA 0x5315 #define PCI_DEVICE_ID_SI_601 0x0601 #define PCI_DEVICE_ID_SI_620 0x0620 #define PCI_DEVICE_ID_SI_630 0x0630 @@ -376,8 +430,15 @@ #define PCI_DEVICE_ID_SI_7001 0x7001 #define PCI_VENDOR_ID_HP 0x103c +#define PCI_DEVICE_ID_HP_DONNER_GFX 0x1008 +#define PCI_DEVICE_ID_HP_TACHYON 0x1028 +#define PCI_DEVICE_ID_HP_TACHLITE 0x1029 #define PCI_DEVICE_ID_HP_J2585A 0x1030 #define PCI_DEVICE_ID_HP_J2585B 0x1031 +#define PCI_DEVICE_ID_HP_SAS 0x1048 +#define PCI_DEVICE_ID_HP_DIVA1 0x1049 +#define PCI_DEVICE_ID_HP_DIVA2 0x104A +#define PCI_DEVICE_ID_HP_SP2_0 0x104B #define PCI_VENDOR_ID_PCTECH 0x1042 #define PCI_DEVICE_ID_PCTECH_RZ1000 0x1000 @@ -408,6 +469,10 @@ #define PCI_DEVICE_ID_ELSA_MICROLINK 0x1000 #define PCI_DEVICE_ID_ELSA_QS3000 0x3000 +#define PCI_VENDOR_ID_ELSA 0x1048 +#define PCI_DEVICE_ID_ELSA_MICROLINK 0x1000 +#define PCI_DEVICE_ID_ELSA_QS3000 0x3000 + #define PCI_VENDOR_ID_SGS 0x104a #define PCI_DEVICE_ID_SGS_2000 0x0008 #define PCI_DEVICE_ID_SGS_1764 0x0009 @@ -658,6 +723,11 @@ #define PCI_DEVICE_ID_AL_M1531 0x1531 #define PCI_DEVICE_ID_AL_M1533 0x1533 #define PCI_DEVICE_ID_AL_M1541 0x1541 +#define PCI_DEVICE_ID_AL_M1621 0x1621 +#define PCI_DEVICE_ID_AL_M1631 0x1631 +#define PCI_DEVICE_ID_AL_M1641 0x1641 +#define PCI_DEVICE_ID_AL_M1647 0x1647 +#define PCI_DEVICE_ID_AL_M1651 0x1651 #define PCI_DEVICE_ID_AL_M1543 0x1543 #define PCI_DEVICE_ID_AL_M3307 0x3307 #define PCI_DEVICE_ID_AL_M4803 0x5215 @@ -811,6 +881,9 @@ #define PCI_DEVICE_ID_VIA_8633_1 0xB091 #define PCI_DEVICE_ID_VIA_8367_1 0xB099 +#define PCI_VENDOR_ID_SIEMENS 0x110A +#define PCI_DEVICE_ID_SIEMENS_DSCC4 0x2102 + #define PCI_VENDOR_ID_SMC2 0x1113 #define PCI_DEVICE_ID_SMC2_1211TX 0x1211 @@ -962,6 +1035,10 @@ #define PCI_VENDOR_ID_OMEGA 0x119b #define PCI_DEVICE_ID_OMEGA_82C092G 0x1221 +#define PCI_VENDOR_ID_FUJITSU_ME 0x119e +#define PCI_DEVICE_ID_FUJITSU_FS155 0x0001 +#define PCI_DEVICE_ID_FUJITSU_FS50 0x0003 + #define PCI_SUBVENDOR_ID_KEYSPAN 0x11a9 #define PCI_SUBDEVICE_ID_KEYSPAN_SX2 0x5334 @@ -993,6 +1070,9 @@ #define PCI_VENDOR_ID_AURAVISION 0x11d1 #define PCI_DEVICE_ID_AURAVISION_VXP524 0x01f7 +#define PCI_VENDOR_ID_ANALOG_DEVICES 0x11d4 +#define PCI_DEVICE_ID_AD1889JS 0x1889 + #define PCI_VENDOR_ID_IKON 0x11d5 #define PCI_DEVICE_ID_IKON_10115 0x0115 #define PCI_DEVICE_ID_IKON_10117 0x0117 @@ -1087,10 +1167,14 @@ #define PCI_DEVICE_ID_HUGHES_DIRECPC 0x0002 #define PCI_VENDOR_ID_ENSONIQ 0x1274 -#define PCI_DEVICE_ID_ENSONIQ_AUDIOPCI 0x5000 +#define PCI_DEVICE_ID_ENSONIQ_CT5880 0x5880 +#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000 #define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371 #define PCI_VENDOR_ID_ROCKWELL 0x127A + +#define PCI_VENDOR_ID_ITE 0x1283 +#define PCI_DEVICE_ID_ITE_IT8172G 0x8172 /* formerly Platform Tech */ #define PCI_VENDOR_ID_ESS_OLD 0x1285 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/pnp_bios.h linux.ac/include/linux/pnp_bios.h --- linux.vanilla/include/linux/pnp_bios.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/linux/pnp_bios.h Tue Apr 17 16:02:14 2001 @@ -0,0 +1,130 @@ +/* + * Include file for the interface to a PnP BIOS + * + * Original BIOS code (C) 1998 Christian Schmidt (chr.schmidt@tu-bs.de) + * PnP handler parts (c) 1998 Tom Lees <tom@lpsg.demon.co.uk> + * Minor reorganizations by David Hinds <dhinds@zen.stanford.edu> + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Original Id: pnp-bios.h,v 0.1 1998/03/19 23:00:00 cs Exp $ + * pnp_bios.h,v 1.1 1999/08/04 15:56:03 root Exp + */ + +#ifndef _LINUX_PNP_BIOS_H +#define _LINUX_PNP_BIOS_H + +#include <linux/types.h> + +/* + * Status codes (warnings and errors) + */ +#define PNP_SUCCESS 0x00 +#define PNP_NOT_SET_STATICALLY 0x7f +#define PNP_UNKNOWN_FUNCTION 0x81 +#define PNP_FUNCTION_NOT_SUPPORTED 0x82 +#define PNP_INVALID_HANDLE 0x83 +#define PNP_BAD_PARAMETER 0x84 +#define PNP_SET_FAILED 0x85 +#define PNP_EVENTS_NOT_PENDING 0x86 +#define PNP_SYSTEM_NOT_DOCKED 0x87 +#define PNP_NO_ISA_PNP_CARDS 0x88 +#define PNP_UNABLE_TO_DETERMINE_DOCK_CAPABILITIES 0x89 +#define PNP_CONFIG_CHANGE_FAILED_NO_BATTERY 0x8a +#define PNP_CONFIG_CHANGE_FAILED_RESOURCE_CONFLICT 0x8b +#define PNP_BUFFER_TOO_SMALL 0x8c +#define PNP_USE_ESCD_SUPPORT 0x8d +#define PNP_MESSAGE_NOT_SUPPORTED 0x8e +#define PNP_HARDWARE_ERROR 0x8f + +#define ESCD_SUCCESS 0x00 +#define ESCD_IO_ERROR_READING 0x55 +#define ESCD_INVALID 0x56 +#define ESCD_BUFFER_TOO_SMALL 0x59 +#define ESCD_NVRAM_TOO_SMALL 0x5a +#define ESCD_FUNCTION_NOT_SUPPORTED 0x81 + +/* + * Events that can be received by "get event" + */ +#define PNPEV_ABOUT_TO_CHANGE_CONFIG 0x0001 +#define PNPEV_DOCK_CHANGED 0x0002 +#define PNPEV_SYSTEM_DEVICE_CHANGED 0x0003 +#define PNPEV_CONFIG_CHANGED_FAILED 0x0004 +#define PNPEV_UNKNOWN_SYSTEM_EVENT 0xffff +/* 0x8000 through 0xfffe are OEM defined */ + +/* + * Messages that should be sent through "send message" + */ +#define PNPMSG_OK 0x00 +#define PNPMSG_ABORT 0x01 +#define PNPMSG_UNDOCK_DEFAULT_ACTION 0x40 +#define PNPMSG_POWER_OFF 0x41 +#define PNPMSG_PNP_OS_ACTIVE 0x42 +#define PNPMSG_PNP_OS_INACTIVE 0x43 +/* 0x8000 through 0xffff are OEM defined */ + +#pragma pack(1) +struct pnp_dev_node_info { + __u16 no_nodes; + __u16 max_node_size; +}; +struct pnp_docking_station_info { + __u32 location_id; + __u32 serial; + __u16 capabilities; +}; +struct pnp_isa_config_struc { + __u8 revision; + __u8 no_csns; + __u16 isa_rd_data_port; + __u16 reserved; +}; +struct escd_info_struc { + __u16 min_escd_write_size; + __u16 escd_size; + __u32 nv_storage_base; +}; +struct pnp_bios_node { + __u16 size; + __u8 handle; + __u32 eisa_id; + __u8 type_code[3]; + __u16 flags; + __u8 data[0]; +}; +#pragma pack() + +#ifdef __KERNEL__ +extern void pnp_bios_init (void); +extern int pnp_bios_dev_node_info (struct pnp_dev_node_info *data); +extern int pnp_bios_get_dev_node (u8 *nodenum, char config, struct pnp_bios_node *data); +extern int pnp_bios_set_dev_node (u8 nodenum, char config, struct pnp_bios_node *data); +extern int pnp_bios_get_event (u16 *message); +extern int pnp_bios_send_message (u16 message); +extern int pnp_bios_dock_station_info (struct pnp_docking_station_info *data); +extern int pnp_bios_set_stat_res (char *info); +extern int pnp_bios_get_stat_res (char *info); +extern int pnp_bios_apm_id_table (char *table, u16 *size); +extern int pnp_bios_isapnp_config (struct pnp_isa_config_struc *data); +extern int pnp_bios_escd_info (struct escd_info_struc *data); +extern int pnp_bios_read_escd (char *data, u32 nvram_base); +extern int pnp_bios_write_escd (char *data, u32 nvram_base); +extern int pnp_bios_present (void); +extern struct pci_dev *pnpbios_find_device(char *pnpid, struct pci_dev *dev); +#endif /* __KERNEL__ */ + +#endif /* _LINUX_PNP_BIOS_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/pnp_resource.h linux.ac/include/linux/pnp_resource.h --- linux.vanilla/include/linux/pnp_resource.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/linux/pnp_resource.h Tue Apr 17 16:02:14 2001 @@ -0,0 +1,148 @@ +#ifndef LINUX_PNP_RESOURCE +#define LINUX_PNP_RESOURCE + +/* ISA Plug and Play Resource Definitions */ + +#define PNP_RES_LARGE_ITEM 0x80 + +/* Small resource items */ +#define PNP_RES_SMTAG_VERSION 0x01 +#define PNP_RES_SMTAG_LDID 0x02 +#define PNP_RES_SMTAG_CDID 0x03 +#define PNP_RES_SMTAG_IRQ 0x04 +#define PNP_RES_SMTAG_DMA 0x05 +#define PNP_RES_SMTAG_DEP_START 0x06 +#define PNP_RES_SMTAG_DEP_END 0x07 +#define PNP_RES_SMTAG_IO 0x08 +#define PNP_RES_SMTAG_IO_FIXED 0x09 +#define PNP_RES_SMTAG_VENDOR 0x0e +#define PNP_RES_SMTAG_END 0x0f + +/* Large resource items */ +#define PNP_RES_LGTAG_MEM 0x01 +#define PNP_RES_LGTAG_ID_ANSI 0x02 +#define PNP_RES_LGTAG_ID_UNICODE 0x03 +#define PNP_RES_LGTAG_VENDOR 0x04 +#define PNP_RES_LGTAG_MEM32 0x05 +#define PNP_RES_LGTAG_MEM32_FIXED 0x06 + +/* Logical device ID flags */ +#define PNP_RES_LDID_BOOT 0x01 + +/* IRQ information */ +#define PNP_RES_IRQ_HIGH_EDGE 0x01 +#define PNP_RES_IRQ_LOW_EDGE 0x02 +#define PNP_RES_IRQ_HIGH_LEVEL 0x04 +#define PNP_RES_IRQ_LOW_LEVEL 0x08 + +/* DMA information */ +#define PNP_RES_DMA_WIDTH_MASK 0x03 +#define PNP_RES_DMA_WIDTH_8 0x00 +#define PNP_RES_DMA_WIDTH_8_16 0x01 +#define PNP_RES_DMA_WIDTH_16 0x02 +#define PNP_RES_DMA_BUSMASTER 0x04 +#define PNP_RES_DMA_COUNT_BYTE 0x08 +#define PNP_RES_DMA_COUNT_WORD 0x10 +#define PNP_RES_DMA_SPEED_MASK 0x60 +#define PNP_RES_DMA_SPEED_COMPAT 0x00 +#define PNP_RES_DMA_SPEED_TYPEA 0x20 +#define PNP_RES_DMA_SPEED_TYPEB 0x40 +#define PNP_RES_DMA_SPEED_TYPEF 0x60 + +/* Resource group priority */ +#define PNP_RES_CONFIG_GOOD 0x00 +#define PNP_RES_CONFIG_ACCEPTABLE 0x01 +#define PNP_RES_CONFIG_SUBOPTIMAL 0x02 + +/* IO information */ +#define PNP_RES_IO_DECODE_16 0x01 + +/* Memory information */ +#define PNP_RES_MEM_WRITEABLE 0x01 +#define PNP_RES_MEM_CACHEABLE 0x02 +#define PNP_RES_MEM_HIGH_ADDRESS 0x04 +#define PNP_RES_MEM_WIDTH_MASK 0x18 +#define PNP_RES_MEM_WIDTH_8 0x00 +#define PNP_RES_MEM_WIDTH_16 0x08 +#define PNP_RES_MEM_WIDTH_8_16 0x10 +#define PNP_RES_MEM_WIDTH_32 0x18 +#define PNP_RES_MEM_SHADOWABLE 0x20 +#define PNP_RES_MEM_EXPANSION_ROM 0x40 + +/* + note: multi-byte data types in these structures are little endian, + and have to be byte swapped before use on big endian platforms. +*/ + +#pragma pack(1) +union pnp_small_resource { + struct { + __u8 pnp, vendor; + } version; + struct { + __u32 id; + __u8 flag0, flag1; + } ldid; + struct { + __u32 id; + } gdid; + struct { + __u16 mask; + __u8 info; + } irq; + struct { + __u8 mask, info; + } dma; + struct { + __u8 priority; + } dep_start; + struct { + __u8 info; + __u16 min, max; + __u8 align, len; + } io; + struct { + __u16 base; + __u8 len; + } io_fixed; + struct { + __u8 checksum; + } end; +}; + +union pnp_large_resource { + struct { + __u8 info; + __u16 min, max, align, len; + } mem; + struct { + __u8 str[0]; + } ansi; + struct { + __u16 country; + __u8 str[0]; + } unicode; + struct { + __u8 info; + __u32 min, max, align, len; + } mem32; + struct { + __u8 info; + __u32 base, len; + } mem32_fixed; +}; + +union pnp_resource { + struct { + __u8 tag; + union pnp_small_resource d; + } sm; + struct { + __u8 tag; + __u16 sz; + union pnp_large_resource d; + } lg; +}; +#pragma pack() + +#endif /* LINUX_PNP_RESOURCE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/prefetch.h linux.ac/include/linux/prefetch.h --- linux.vanilla/include/linux/prefetch.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/linux/prefetch.h Tue Apr 3 18:11:10 2001 @@ -0,0 +1,57 @@ +/* + * Generic cache management functions. Everything is arch-specific, + * but this header exists to make sure the defines/functions can be + * used in a generic way. + * + * 2000-11-13 Arjan van de Ven <arjan@fenrus.demon.nl> + * + */ + +#ifndef _LINUX_PREFETCH_H +#define _LINUX_PREFETCH_H + +#include <asm/processor.h> +#include <asm/cache.h> + +/* + prefetch(x) attempts to pre-emptively get the memory pointed to + by address "x" into the CPU L1 cache. + prefetch(x) should not cause any kind of exception, prefetch(0) is + specifically ok. + + prefetch() should be defined by the architecture, if not, the + #define below provides a no-op define. + + There are 3 prefetch() macros: + + prefetch(x) - prefetches the cacheline at "x" for read + prefetchw(x) - prefetches the cacheline at "x" for write + spin_lock_prefetch(x) - prefectches the spinlock *x for taking + + there is also PREFETCH_STRIDE which is the architecure-prefered + "lookahead" size for prefetching streamed operations. + +*/ + +/* + * These cannot be do{}while(0) macros. See the mental gymnastics in + * the loop macro. + */ + +#ifndef ARCH_HAS_PREFETCH +static inline void prefetch(void *x) {;} +#endif + +#ifndef ARCH_HAS_PREFETCHW +static inline void prefetchw(void *x) {;} +#endif + +#ifndef ARCH_HAS_SPINLOCK_PREFETCH +#define spin_lock_prefetch(x) prefetchw(x) +#endif + +#ifndef PREFETCH_STRIDE +#define PREFETCH_STRIDE (4*L1_CACHE_BYTE) +#endif + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/proc_fs.h linux.ac/include/linux/proc_fs.h --- linux.vanilla/include/linux/proc_fs.h Thu Feb 22 00:10:01 2001 +++ linux.ac/include/linux/proc_fs.h Tue Apr 17 17:44:38 2001 @@ -126,6 +126,11 @@ */ extern void proc_device_tree_init(void); +/* + * proc_rtas.c + */ +extern void proc_rtas_init(void); + extern struct proc_dir_entry *proc_symlink(const char *, struct proc_dir_entry *, const char *); extern struct proc_dir_entry *proc_mknod(const char *,mode_t, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/quota.h linux.ac/include/linux/quota.h --- linux.vanilla/include/linux/quota.h Fri Feb 9 22:46:13 2001 +++ linux.ac/include/linux/quota.h Tue Apr 3 18:11:10 2001 @@ -40,30 +40,10 @@ #define _LINUX_QUOTA_ #include <linux/errno.h> +#include <linux/types.h> -/* - * Convert diskblocks to blocks and the other way around. - */ -#define dbtob(num) (num << BLOCK_SIZE_BITS) -#define btodb(num) (num >> BLOCK_SIZE_BITS) - -/* - * Convert count of filesystem blocks to diskquota blocks, meant - * for filesystems where i_blksize != BLOCK_SIZE - */ -#define fs_to_dq_blocks(num, blksize) (((num) * (blksize)) / BLOCK_SIZE) - -/* - * Definitions for disk quotas imposed on the average user - * (big brother finally hits Linux). - * - * The following constants define the amount of time given a user - * before the soft limits are treated as hard limits (usually resulting - * in an allocation failure). The timer is started when the user crosses - * their soft limit, it is reset when they go below their soft limit. - */ -#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */ -#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */ +typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */ +typedef __u64 qsize_t; /* Type in which we store size limitations */ #define MAXQUOTAS 2 #define USRQUOTA 0 /* element used for user quotas */ @@ -76,17 +56,32 @@ "user", /* USRQUOTA */ \ "group", /* GRPQUOTA */ \ "undefined", \ -}; +} -#define QUOTAFILENAME "quota" -#define QUOTAGROUP "staff" +/* + * Definitions of magics and versions of current quota files + */ +#define INITQMAGICS {\ + 0xd9c01f11, /* USRQUOTA */\ + 0xd9c01927 /* GRPQUOTA */\ +} -extern int nr_dquots, nr_free_dquots; -extern int max_dquots; -extern int dquot_root_squash; +#define INITQVERSIONS {\ + 0, /* USRQUOTA */\ + 0 /* GRPQUOTA */\ +} -#define NR_DQHASH 43 /* Just an arbitrary number */ -#define NR_DQUOTS 1024 /* Maximum number of quotas active at one time (Configurable from /proc/sys/fs) */ +#define QUOTAFILENAME "aquota" +#define QUOTAGROUP "staff" + +/* Size of blocks in which are counted size limits */ +#define QUOTABLOCK_BITS 10 +#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) + +/* Conversion routines from and to quota blocks */ +#define qb2kb(x) ((x) << (QUOTABLOCK_BITS-10)) +#define kb2qb(x) ((x) >> (QUOTABLOCK_BITS-10)) +#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS) /* * Command definitions for the 'quotactl' system call. @@ -100,43 +95,106 @@ #define Q_QUOTAON 0x0100 /* enable quotas */ #define Q_QUOTAOFF 0x0200 /* disable quotas */ -#define Q_GETQUOTA 0x0300 /* get limits and usage */ -#define Q_SETQUOTA 0x0400 /* set limits and usage */ -#define Q_SETUSE 0x0500 /* set usage */ +/* GETQUOTA, SETQUOTA and SETUSE which were at 0x0300-0x0500 has now other parameteres */ #define Q_SYNC 0x0600 /* sync disk copy of a filesystems quotas */ #define Q_SETQLIM 0x0700 /* set limits */ #define Q_GETSTATS 0x0800 /* get collected stats */ -#define Q_RSQUASH 0x1000 /* set root_squash option */ +#define Q_GETINFO 0x0900 /* get info about quotas - graces, flags... */ +#define Q_SETINFO 0x0A00 /* set info about quotas */ +#define Q_SETGRACE 0x0B00 /* set inode and block grace */ +#define Q_SETFLAGS 0x0C00 /* set flags for quota */ +#define Q_GETQUOTA 0x0D00 /* get limits and usage */ +#define Q_SETQUOTA 0x0E00 /* set limits and usage */ +#define Q_SETUSE 0x0F00 /* set usage */ +/* 0x1000 used by old RSQUASH */ /* * The following structure defines the format of the disk quota file - * (as it appears on disk) - the file is an array of these structures - * indexed by user or group number. + * (as it appears on disk) - the file is a hash table whose entries points + * to blocks of these structures. */ -struct dqblk { - __u32 dqb_bhardlimit; /* absolute limit on disk blks alloc */ - __u32 dqb_bsoftlimit; /* preferred limit on disk blks */ - __u32 dqb_curblocks; /* current block count */ +struct disk_dqblk { + __u32 dqb_id; /* id this quota applies to */ __u32 dqb_ihardlimit; /* absolute limit on allocated inodes */ __u32 dqb_isoftlimit; /* preferred inode limit */ __u32 dqb_curinodes; /* current # allocated inodes */ - time_t dqb_btime; /* time limit for excessive disk use */ - time_t dqb_itime; /* time limit for excessive inode use */ + __u32 dqb_bhardlimit; /* absolute limit on disk space (in QUOTABLOCK_SIZE) */ + __u32 dqb_bsoftlimit; /* preferred limit on disk space (in QUOTABLOCK_SIZE) */ + __u64 dqb_curspace; /* current space occupied (in bytes) */ + __u64 dqb_btime; /* time limit for excessive disk use */ + __u64 dqb_itime; /* time limit for excessive inode use */ +}; + +/* This is in-memory copy of quota block. See meaning of entries above */ +struct mem_dqblk { + unsigned int dqb_ihardlimit; + unsigned int dqb_isoftlimit; + unsigned int dqb_curinodes; + unsigned int dqb_bhardlimit; + unsigned int dqb_bsoftlimit; + qsize_t dqb_curspace; + __kernel_time_t dqb_btime; + __kernel_time_t dqb_itime; }; /* - * Shorthand notation. + * Here are header structures as written on disk and their in-memory copies */ -#define dq_bhardlimit dq_dqb.dqb_bhardlimit -#define dq_bsoftlimit dq_dqb.dqb_bsoftlimit -#define dq_curblocks dq_dqb.dqb_curblocks -#define dq_ihardlimit dq_dqb.dqb_ihardlimit -#define dq_isoftlimit dq_dqb.dqb_isoftlimit -#define dq_curinodes dq_dqb.dqb_curinodes -#define dq_btime dq_dqb.dqb_btime -#define dq_itime dq_dqb.dqb_itime +/* First generic header */ +struct disk_dqheader { + __u32 dqh_magic; /* Magic number identifying file */ + __u32 dqh_version; /* File version */ +}; -#define dqoff(UID) ((loff_t)((UID) * sizeof (struct dqblk))) +/* Header with type and version specific information */ +struct disk_dqinfo { + __u32 dqi_bgrace; /* Time before block soft limit becomes hard limit */ + __u32 dqi_igrace; /* Time before inode soft limit becomes hard limit */ + __u32 dqi_flags; /* Flags for quotafile (DQF_*) */ + __u32 dqi_blocks; /* Number of blocks in file */ + __u32 dqi_free_blk; /* Number of first free block in the list */ + __u32 dqi_free_entry; /* Number of block with at least one free entry */ +}; + +/* Inmemory copy of version specific information */ +struct mem_dqinfo { + unsigned int dqi_bgrace; + unsigned int dqi_igrace; + unsigned int dqi_flags; + unsigned int dqi_blocks; + unsigned int dqi_free_blk; + unsigned int dqi_free_entry; +}; + +/* Flags for version specific files */ +#define DQF_MASK 0x0000 /* Mask for all valid ondisk flags */ + +#ifdef __KERNEL__ +#define DQF_DIRTY 0x0010 /* Is info dirty? */ +extern inline void mark_info_dirty(struct mem_dqinfo *info) +{ + info->dqi_flags |= DQF_DIRTY; +} +#define info_dirty(info) ((info)->dqi_flags & DQF_DIRTY) +#endif +/* + * Structure of header of block with quota structures. It is padded to 16 bytes so + * there will be space for exactly 18 quota-entries in a block + */ +struct disk_dqdbheader { + __u32 dqdh_next_free; /* Number of next block with free entry */ + __u32 dqdh_prev_free; /* Number of previous block with free entry */ + __u16 dqdh_entries; /* Number of valid entries in block */ + __u16 dqdh_pad1; + __u32 dqdh_pad2; +}; + +#define DQINFOOFF sizeof(struct disk_dqheader) /* Offset of info header in file */ +#define DQBLKSIZE_BITS 10 +#define DQBLKSIZE (1 << DQBLKSIZE_BITS) /* Size of block with quota structures */ +#define DQTREEOFF 1 /* Offset of tree in file in blocks */ +#define DQTREEDEPTH 4 /* Depth of quota tree */ +#define DQSTRINBLK ((DQBLKSIZE - sizeof(struct disk_dqdbheader)) / sizeof(struct disk_dqblk)) /* Number of entries in one blocks */ struct dqstats { __u32 lookups; @@ -151,58 +209,72 @@ #ifdef __KERNEL__ -/* - * Maximum length of a message generated in the quota system, - * that needs to be kicked onto the tty. - */ -#define MAX_QUOTA_MESSAGE 75 +extern int nr_dquots, nr_free_dquots; -#define DQ_LOCKED 0x01 /* locked for update */ -#define DQ_WANT 0x02 /* wanted for update */ -#define DQ_MOD 0x04 /* dquot modified since read */ +#define NR_DQHASH 43 /* Just an arbitrary number */ + +#define DQ_LOCKED 0x01 /* dquot under IO */ +#define DQ_MOD 0x02 /* dquot modified since read */ #define DQ_BLKS 0x10 /* uid/gid has been warned about blk limit */ #define DQ_INODES 0x20 /* uid/gid has been warned about inode limit */ #define DQ_FAKE 0x40 /* no limits only usage */ struct dquot { - struct dquot *dq_next; /* Pointer to next dquot */ - struct dquot **dq_pprev; - struct list_head dq_free; /* free list element */ - struct dquot *dq_hash_next; /* Pointer to next in dquot_hash */ - struct dquot **dq_hash_pprev; /* Pointer to previous in dquot_hash */ - wait_queue_head_t dq_wait; /* Pointer to waitqueue */ + struct list_head dq_hash; /* Hash list in memory */ + struct list_head dq_inuse; /* List of all quotas */ + struct list_head dq_free; /* Free list element */ + wait_queue_head_t dq_wait_lock; /* Pointer to waitqueue on dquot lock */ + wait_queue_head_t dq_wait_free; /* Pointer to waitqueue for quota to be unused */ int dq_count; /* Reference count */ /* fields after this point are cleared when invalidating */ struct super_block *dq_sb; /* superblock this applies to */ - unsigned int dq_id; /* ID this applies to (uid, gid) */ + qid_t dq_id; /* ID this applies to (uid, gid) */ kdev_t dq_dev; /* Device this applies to */ short dq_type; /* Type of quota */ short dq_flags; /* See DQ_* */ + loff_t dq_off; /* Offset of structure in file (0 for not allocated) */ unsigned long dq_referenced; /* Number of times this dquot was referenced during its lifetime */ - struct dqblk dq_dqb; /* Diskquota usage */ + struct mem_dqblk dq_dqb; /* Diskquota usage */ }; #define NODQUOT (struct dquot *)NULL +#define dq_curspace dq_dqb.dqb_curspace +#define dq_curinodes dq_dqb.dqb_curinodes +#define dq_isoftlimit dq_dqb.dqb_isoftlimit +#define dq_ihardlimit dq_dqb.dqb_ihardlimit +#define dq_bsoftlimit dq_dqb.dqb_bsoftlimit +#define dq_bhardlimit dq_dqb.dqb_bhardlimit +#define dq_itime dq_dqb.dqb_itime +#define dq_btime dq_dqb.dqb_btime + /* * Flags used for set_dqblk. */ -#define QUOTA_SYSCALL 0x01 -#define SET_QUOTA 0x02 -#define SET_USE 0x04 -#define SET_QLIMIT 0x08 +#define SET_QUOTA 0x01 +#define SET_USE 0x02 +#define SET_QLIMIT 0x04 + +/* + * Flags used for set_info + */ +#define ISET_GRACE 0x01 +#define ISET_FLAGS 0x02 +#define ISET_ALL 0x03 #define QUOTA_OK 0 #define NO_QUOTA 1 +typedef char *dqbuf_t; + #else # /* nodep */ include <sys/cdefs.h> __BEGIN_DECLS -long quotactl __P ((int, const char *, int, caddr_t)); +long quotactl __P ((int, const char *, qid_t, __kernel_caddr_t)); __END_DECLS #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/quotaops.h linux.ac/include/linux/quotaops.h --- linux.vanilla/include/linux/quotaops.h Thu Feb 22 00:10:55 2001 +++ linux.ac/include/linux/quotaops.h Sun Apr 15 23:22:14 2001 @@ -11,10 +11,11 @@ #define _LINUX_QUOTAOPS_ #include <linux/config.h> +#include <linux/smp_lock.h> #if defined(CONFIG_QUOTA) -#include <linux/smp_lock.h> +#include <linux/fs.h> /* * declaration of quota_function calls in kernel. @@ -25,83 +26,121 @@ extern int quota_off(struct super_block *sb, short type); extern int sync_dquots(kdev_t dev, short type); -extern int dquot_alloc_block(const struct inode *inode, unsigned long number, char prealloc); +extern int dquot_alloc_space(struct inode *inode, qsize_t number, char prealloc); extern int dquot_alloc_inode(const struct inode *inode, unsigned long number); -extern void dquot_free_block(const struct inode *inode, unsigned long number); +extern void dquot_free_space(struct inode *inode, qsize_t number); extern void dquot_free_inode(const struct inode *inode, unsigned long number); -extern int dquot_transfer(struct dentry *dentry, struct iattr *iattr); +extern int dquot_transfer(struct inode *inode, struct iattr *iattr); /* * Operations supported for diskquotas. */ +#define sb_any_quota_enabled(sb) ((sb)->s_dquot.flags & (DQUOT_USR_ENABLED | DQUOT_GRP_ENABLED)) + extern __inline__ void DQUOT_INIT(struct inode *inode) { - if (inode->i_sb && inode->i_sb->dq_op) + if (!inode->i_sb) + BUG(); + lock_kernel(); + if (sb_any_quota_enabled(inode->i_sb)) inode->i_sb->dq_op->initialize(inode, -1); + unlock_kernel(); } extern __inline__ void DQUOT_DROP(struct inode *inode) { - if (IS_QUOTAINIT(inode)) { - if (inode->i_sb && inode->i_sb->dq_op) - inode->i_sb->dq_op->drop(inode); - } + if (!inode->i_sb) + BUG(); + lock_kernel(); + if (IS_QUOTAINIT(inode)) + inode->i_sb->dq_op->drop(inode); /* Ops must be set when there's any quota... */ + unlock_kernel(); } -extern __inline__ int DQUOT_PREALLOC_BLOCK(struct super_block *sb, const struct inode *inode, int nr) -{ - if (sb->dq_op) { - if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize), 1) == NO_QUOTA) +extern __inline__ int DQUOT_PREALLOC_SPACE(struct inode *inode, qsize_t nr) +{ + lock_kernel(); + if (sb_any_quota_enabled(inode->i_sb)) { + /* Number of used blocks is updated in alloc_block() */ + if (inode->i_sb->dq_op->alloc_space(inode, nr, 1) == NO_QUOTA) { + unlock_kernel(); return 1; + } + } + else { + inode_add_bytes(inode, nr); + mark_inode_dirty(inode); } + unlock_kernel(); return 0; } -extern __inline__ int DQUOT_ALLOC_BLOCK(struct super_block *sb, const struct inode *inode, int nr) +extern __inline__ int DQUOT_ALLOC_SPACE(struct inode *inode, qsize_t nr) { - if (sb->dq_op) { - if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize), 0) == NO_QUOTA) + lock_kernel(); + if (sb_any_quota_enabled(inode->i_sb)) { + /* Number of used blocks is updated in alloc_block() */ + if (inode->i_sb->dq_op->alloc_space(inode, nr, 0) == NO_QUOTA) { + unlock_kernel(); return 1; + } + } + else { + inode_add_bytes(inode, nr); + mark_inode_dirty(inode); } + unlock_kernel(); return 0; } -extern __inline__ int DQUOT_ALLOC_INODE(struct super_block *sb, struct inode *inode) +extern __inline__ int DQUOT_ALLOC_INODE(struct inode *inode) { - if (sb->dq_op) { - sb->dq_op->initialize (inode, -1); - if (sb->dq_op->alloc_inode (inode, 1)) + lock_kernel(); + if (sb_any_quota_enabled(inode->i_sb)) { + inode->i_sb->dq_op->initialize(inode, -1); + if (inode->i_sb->dq_op->alloc_inode(inode, 1) == NO_QUOTA) { + unlock_kernel(); return 1; + } } - inode->i_flags |= S_QUOTA; + unlock_kernel(); return 0; } -extern __inline__ void DQUOT_FREE_BLOCK(struct super_block *sb, const struct inode *inode, int nr) +extern __inline__ void DQUOT_FREE_SPACE(struct inode *inode, qsize_t nr) { - if (sb->dq_op) - sb->dq_op->free_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize)); + lock_kernel(); + if (sb_any_quota_enabled(inode->i_sb)) + inode->i_sb->dq_op->free_space(inode, nr); + else { + inode_sub_bytes(inode, nr); + mark_inode_dirty(inode); + } + unlock_kernel(); } -extern __inline__ void DQUOT_FREE_INODE(struct super_block *sb, struct inode *inode) +extern __inline__ void DQUOT_FREE_INODE(struct inode *inode) { - if (sb->dq_op) - sb->dq_op->free_inode(inode, 1); + lock_kernel(); + if (sb_any_quota_enabled(inode->i_sb)) + inode->i_sb->dq_op->free_inode(inode, 1); + unlock_kernel(); } -extern __inline__ int DQUOT_TRANSFER(struct dentry *dentry, struct iattr *iattr) +extern __inline__ int DQUOT_TRANSFER(struct inode *inode, struct iattr *iattr) { - int error = -EDQUOT; - - if (dentry->d_inode->i_sb->dq_op) { - dentry->d_inode->i_sb->dq_op->initialize(dentry->d_inode, -1); - error = dentry->d_inode->i_sb->dq_op->transfer(dentry, iattr); - } else { - error = notify_change(dentry, iattr); + lock_kernel(); + if (sb_any_quota_enabled(inode->i_sb)) { + inode->i_sb->dq_op->initialize(inode, -1); + if (inode->i_sb->dq_op->transfer(inode, iattr) == NO_QUOTA) { + unlock_kernel(); + return 1; + } } - return error; + unlock_kernel(); + return 0; } #define DQUOT_SYNC(dev) sync_dquots(dev, -1) @@ -114,18 +153,41 @@ */ #define DQUOT_INIT(inode) do { } while(0) #define DQUOT_DROP(inode) do { } while(0) -#define DQUOT_PREALLOC_BLOCK(sb, inode, nr) (0) -#define DQUOT_ALLOC_BLOCK(sb, inode, nr) (0) -#define DQUOT_ALLOC_INODE(sb, inode) (0) -#define DQUOT_FREE_BLOCK(sb, inode, nr) do { } while(0) -#define DQUOT_FREE_INODE(sb, inode) do { } while(0) +#define DQUOT_ALLOC_INODE(inode) (0) +#define DQUOT_FREE_INODE(inode) do { } while(0) #define DQUOT_SYNC(dev) do { } while(0) #define DQUOT_OFF(sb) do { } while(0) +#define DQUOT_TRANSFER(inode, iattr) (0) +extern __inline__ int DQUOT_PREALLOC_SPACE(struct inode *inode, qsize_t nr) +{ + lock_kernel(); + inode_add_bytes(inode, nr); + unlock_kernel(); + mark_inode_dirty(inode); + return 0; +} -/* - * Special case expands to a simple notify_change. - */ -#define DQUOT_TRANSFER(dentry, iattr) notify_change(dentry, iattr) +extern __inline__ int DQUOT_ALLOC_SPACE(struct inode *inode, qsize_t nr) +{ + lock_kernel(); + inode_add_bytes(inode, nr); + unlock_kernel(); + mark_inode_dirty(inode); + return 0; +} + +extern __inline__ void DQUOT_FREE_SPACE(struct inode *inode, qsize_t nr) +{ + lock_kernel(); + inode_sub_bytes(inode, nr); + unlock_kernel(); + mark_inode_dirty(inode); +} #endif /* CONFIG_QUOTA */ + +#define DQUOT_ALLOC_BLOCK(inode, nr) DQUOT_ALLOC_SPACE((inode), ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits) +#define DQUOT_PREALLOC_BLOCK(inode, nr) DQUOT_ALLOC_SPACE((inode), ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits) +#define DQUOT_FREE_BLOCK(inode, nr) DQUOT_FREE_SPACE((inode), ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits) + #endif /* _LINUX_QUOTAOPS_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/raid/md_k.h linux.ac/include/linux/raid/md_k.h --- linux.vanilla/include/linux/raid/md_k.h Fri Dec 29 22:07:24 2000 +++ linux.ac/include/linux/raid/md_k.h Sat Apr 14 15:05:37 2001 @@ -15,6 +15,8 @@ #ifndef _MD_K_H #define _MD_K_H +#include <linux/kernel.h> // for panic() + #define MD_RESERVED 0UL #define LINEAR 1UL #define STRIPED 2UL @@ -36,6 +38,7 @@ case RAID5: return 5; } panic("pers_to_level()"); + return 0; } extern inline int level_to_pers (int level) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/rwsem-spinlock.h linux.ac/include/linux/rwsem-spinlock.h --- linux.vanilla/include/linux/rwsem-spinlock.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/linux/rwsem-spinlock.h Sat Apr 14 19:12:38 2001 @@ -0,0 +1,174 @@ +/* rwsem-spinlock.h: fallback C implementation + * + * Copyright (c) 2001 David Howells (dhowells@redhat.com). + */ + +#ifndef _LINUX_RWSEM_SPINLOCK_H +#define _LINUX_RWSEM_SPINLOCK_H + +#ifndef _LINUX_RWSEM_H +#error please dont include asm/rwsem-spinlock.h directly, use linux/rwsem.h instead +#endif + +#include <linux/spinlock.h> + +#ifdef __KERNEL__ + +#define CONFIG_USING_SPINLOCK_BASED_RWSEM 1 + +/* + * the semaphore definition + */ +struct rw_semaphore { + signed long count; +#define RWSEM_UNLOCKED_VALUE 0x00000000 +#define RWSEM_ACTIVE_BIAS 0x00000001 +#define RWSEM_ACTIVE_MASK 0x0000ffff +#define RWSEM_WAITING_BIAS (-0x00010000) +#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS +#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) + spinlock_t lock; +#define RWSEM_SPINLOCK_OFFSET_STR "4" /* byte offset of spinlock */ + wait_queue_head_t wait; +#define RWSEM_WAITING_FOR_READ WQ_FLAG_CONTEXT_0 /* bits to use in wait_queue_t.flags */ +#define RWSEM_WAITING_FOR_WRITE WQ_FLAG_CONTEXT_1 +#if RWSEM_DEBUG + int debug; +#endif +#if RWSEM_DEBUG_MAGIC + long __magic; + atomic_t readers; + atomic_t writers; +#endif +}; + +/* + * initialisation + */ +#if RWSEM_DEBUG +#define __RWSEM_DEBUG_INIT , 0 +#else +#define __RWSEM_DEBUG_INIT /* */ +#endif +#if RWSEM_DEBUG_MAGIC +#define __RWSEM_DEBUG_MINIT(name) , (int)&(name).__magic, ATOMIC_INIT(0), ATOMIC_INIT(0) +#else +#define __RWSEM_DEBUG_MINIT(name) /* */ +#endif + +#define __RWSEM_INITIALIZER(name,count) \ +{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \ + __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ + __RWSEM_DEBUG_INIT __RWSEM_DEBUG_MINIT(name) } + +#define __DECLARE_RWSEM_GENERIC(name,count) \ + struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) + +#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS) +#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1) +#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0) + +static inline void init_rwsem(struct rw_semaphore *sem) +{ + sem->count = RWSEM_UNLOCKED_VALUE; + spin_lock_init(&sem->lock); + init_waitqueue_head(&sem->wait); +#if RWSEM_DEBUG + sem->debug = 0; +#endif +#if RWSEM_DEBUG_MAGIC + sem->__magic = (long)&sem->__magic; + atomic_set(&sem->readers, 0); + atomic_set(&sem->writers, 0); +#endif +} + +/* + * lock for reading + */ +static inline void __down_read(struct rw_semaphore *sem) +{ + int count; + spin_lock(&sem->lock); + sem->count += RWSEM_ACTIVE_READ_BIAS; + count = sem->count; + spin_unlock(&sem->lock); + if (count<0) + rwsem_down_read_failed(sem); +} + +/* + * lock for writing + */ +static inline void __down_write(struct rw_semaphore *sem) +{ + int count; + spin_lock(&sem->lock); + count = sem->count; + sem->count += RWSEM_ACTIVE_WRITE_BIAS; + spin_unlock(&sem->lock); + if (count) + rwsem_down_write_failed(sem); +} + +/* + * unlock after reading + */ +static inline void __up_read(struct rw_semaphore *sem) +{ + int count; + spin_lock(&sem->lock); + count = sem->count; + sem->count -= RWSEM_ACTIVE_READ_BIAS; + spin_unlock(&sem->lock); + if (count<0 && !((count-RWSEM_ACTIVE_READ_BIAS)&RWSEM_ACTIVE_MASK)) + rwsem_wake(sem); +} + +/* + * unlock after writing + */ +static inline void __up_write(struct rw_semaphore *sem) +{ + int count; + spin_lock(&sem->lock); + sem->count -= RWSEM_ACTIVE_WRITE_BIAS; + count = sem->count; + spin_unlock(&sem->lock); + if (count<0) + rwsem_wake(sem); +} + +/* + * implement exchange and add functionality + */ +static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) +{ + int count; + + spin_lock(&sem->lock); + sem->count += delta; + count = sem->count; + spin_unlock(&sem->lock); + + return count; +} + +/* + * implement compare and exchange functionality on the rw-semaphore count LSW + */ +static inline __u16 rwsem_cmpxchgw(struct rw_semaphore *sem, __u16 old, __u16 new) +{ + __u16 prev; + + spin_lock(&sem->lock); + prev = sem->count & RWSEM_ACTIVE_MASK; + if (prev==old) + sem->count = (sem->count & ~RWSEM_ACTIVE_MASK) | new; + spin_unlock(&sem->lock); + + return prev; +} + +#endif /* __KERNEL__ */ +#endif /* _LINUX_RWSEM_SPINLOCK_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/rwsem.h linux.ac/include/linux/rwsem.h --- linux.vanilla/include/linux/rwsem.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/linux/rwsem.h Sat Apr 14 19:12:38 2001 @@ -0,0 +1,148 @@ +/* rwsem.h: R/W semaphores, public interface + * + * Written by David Howells (dhowells@redhat.com). + * Derived from asm-i386/semaphore.h + * + * + * The MSW of the count is the negated number of active writers and waiting + * lockers, and the LSW is the total number of active locks + * + * The lock count is initialized to 0 (no active and no waiting lockers). + * + * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an + * uncontended lock. This can be determined because XADD returns the old value. + * Readers increment by 1 and see a positive value when uncontended, negative + * if there are writers (and maybe) readers waiting (in which case it goes to + * sleep). + * + * The value of WAITING_BIAS supports up to 32766 waiting processes. This can + * be extended to 65534 by manually checking the whole MSW rather than relying + * on the S flag. + * + * The value of ACTIVE_BIAS supports up to 65535 active processes. + * + * This should be totally fair - if anything is waiting, a process that wants a + * lock will go to the back of the queue. When the currently active lock is + * released, if there's a writer at the front of the queue, then that and only + * that will be woken up; if there's a bunch of consequtive readers at the + * front, then they'll all be woken up, but no other readers will be. + */ + +#ifndef _LINUX_RWSEM_H +#define _LINUX_RWSEM_H + +#include <linux/linkage.h> + +#define RWSEM_DEBUG 0 +#define RWSEM_DEBUG_MAGIC 0 + +#ifdef __KERNEL__ + +#include <asm/system.h> +#include <asm/atomic.h> +#include <linux/wait.h> + +#if RWSEM_DEBUG +#define rwsemdebug(FMT, ARGS...) do { if (sem->debug) printk(FMT,##ARGS); } while(0) +#else +#define rwsemdebug(FMT, ARGS...) +#endif + +/* we use FASTCALL convention for the helpers */ +extern struct rw_semaphore *FASTCALL(rwsem_down_read_failed(struct rw_semaphore *sem)); +extern struct rw_semaphore *FASTCALL(rwsem_down_write_failed(struct rw_semaphore *sem)); +extern struct rw_semaphore *FASTCALL(rwsem_wake(struct rw_semaphore *sem)); + +#include <asm/rwsem.h> /* find the arch specific bits */ + +#ifndef __HAVE_ARCH_SPECIFIC_RWSEM_IMPLEMENTATION +#include <linux/rwsem-spinlock.h> +#endif + +/* + * lock for reading + */ +static inline void down_read(struct rw_semaphore *sem) +{ + rwsemdebug("Entering down_read(count=%08lx)\n",sem->count); + +#if RWSEM_DEBUG_MAGIC + if (sem->__magic != (long)&sem->__magic) + BUG(); +#endif + + __down_read(sem); + +#if RWSEM_DEBUG_MAGIC + if (atomic_read(&sem->writers)) + BUG(); + atomic_inc(&sem->readers); +#endif + + rwsemdebug("Leaving down_read(count=%08lx)\n",sem->count); +} + +/* + * lock for writing + */ +static inline void down_write(struct rw_semaphore *sem) +{ + rwsemdebug("Entering down_write(count=%08lx)\n",sem->count); + +#if RWSEM_DEBUG_MAGIC + if (sem->__magic != (long)&sem->__magic) + BUG(); +#endif + + __down_write(sem); + +#if RWSEM_DEBUG_MAGIC + if (atomic_read(&sem->writers)) + BUG(); + if (atomic_read(&sem->readers)) + BUG(); + atomic_inc(&sem->writers); +#endif + + rwsemdebug("Leaving down_write(count=%08lx)\n",sem->count); +} + +/* + * release a read lock + */ +static inline void up_read(struct rw_semaphore *sem) +{ + rwsemdebug("Entering up_read(count=%08lx)\n",sem->count); + +#if RWSEM_DEBUG_MAGIC + if (atomic_read(&sem->writers)) + BUG(); + atomic_dec(&sem->readers); +#endif + __up_read(sem); + + rwsemdebug("Leaving up_read(count=%08lx)\n",sem->count); +} + +/* + * release a write lock + */ +static inline void up_write(struct rw_semaphore *sem) +{ + rwsemdebug("Entering up_write(count=%08lx)\n",sem->count); + +#if RWSEM_DEBUG_MAGIC + if (atomic_read(&sem->readers)) + BUG(); + if (atomic_read(&sem->writers) != 1) + BUG(); + atomic_dec(&sem->writers); +#endif + __up_write(sem); + + rwsemdebug("Leaving up_write(count=%08lx)\n",sem->count); +} + + +#endif /* __KERNEL__ */ +#endif /* _LINUX_RWSEM_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/scc.h linux.ac/include/linux/scc.h --- linux.vanilla/include/linux/scc.h Thu Jan 4 20:50:12 2001 +++ linux.ac/include/linux/scc.h Sat Apr 14 01:42:21 2001 @@ -213,8 +213,6 @@ /* SCC channel structure */ struct scc_channel { - int magic; /* magic word */ - int init; /* channel exists? */ struct net_device *dev; /* link to device control structure */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/sched.h linux.ac/include/linux/sched.h --- linux.vanilla/include/linux/sched.h Tue Apr 3 17:32:29 2001 +++ linux.ac/include/linux/sched.h Sun Apr 15 23:20:10 2001 @@ -195,7 +195,9 @@ } /* Maximum number of active map areas.. This is a random (large) number */ -#define MAX_MAP_COUNT (65536) +#define DEFAULT_MAX_MAP_COUNT (65536) + +extern int max_map_count; /* Number of map areas at which the AVL tree is activated. This is arbitrary. */ #define AVL_MIN_MAP_COUNT 32 @@ -548,6 +550,8 @@ extern void FASTCALL(__wake_up(wait_queue_head_t *q, unsigned int mode, int nr)); extern void FASTCALL(__wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr)); +extern int FASTCALL(__wake_up_ctx(wait_queue_head_t *q, unsigned int mode, int count, int bit)); +extern int FASTCALL(__wake_up_sync_ctx(wait_queue_head_t *q, unsigned int mode, int count, int bit)); extern void FASTCALL(sleep_on(wait_queue_head_t *q)); extern long FASTCALL(sleep_on_timeout(wait_queue_head_t *q, signed long timeout)); @@ -566,6 +570,8 @@ #define wake_up_interruptible_all(x) __wake_up((x),TASK_INTERRUPTIBLE, 0) #define wake_up_interruptible_sync(x) __wake_up_sync((x),TASK_INTERRUPTIBLE, 1) #define wake_up_interruptible_sync_nr(x) __wake_up_sync((x),TASK_INTERRUPTIBLE, nr) +#define wake_up_ctx(x,count,bit) __wake_up_ctx((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE,count,bit) +#define wake_up_sync_ctx(x,count,bit) __wake_up_ctx((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE,count,bit) asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru); extern int in_group_p(gid_t); @@ -710,6 +716,8 @@ /* * Routines for handling mm_structs */ +extern struct mm_struct * mm_init(struct mm_struct * mm); +extern int dup_mmap(struct mm_struct * mm); extern struct mm_struct * mm_alloc(void); extern struct mm_struct * start_lazy_tlb(void); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/sdla_asy.h linux.ac/include/linux/sdla_asy.h --- linux.vanilla/include/linux/sdla_asy.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/linux/sdla_asy.h Sat Apr 14 01:42:30 2001 @@ -0,0 +1,226 @@ +/***************************************************************************** +* sdla_asy.h Header file for the Sangoma S508/S514 asynchronous code API +* +* Author: Gideon Hack +* +* Copyright: (c) 2000 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* +* Jan 28, 2000 Gideon Hack Initial Version +* +*****************************************************************************/ + + +#ifndef _WANPIPE_ASYNC_H +#define _WANPIPE_ASYNC_H + +/* ---------------------------------------------------------------------------- + * Interface commands + * --------------------------------------------------------------------------*/ + +#define SET_ASY_CONFIGURATION 0xE2 /* set the asychronous operational configuration */ +#define READ_ASY_CONFIGURATION 0xE3 /* read the current asychronous operational configuration */ +#define ENABLE_ASY_COMMUNICATIONS 0xE4 /* enable asychronous communications */ +#define DISABLE_ASY_COMMUNICATIONS 0xE5 /* disable asychronous communications */ +#define READ_ASY_OPERATIONAL_STATS 0xE7 /* retrieve the asychronous operational statistics */ +#define FLUSH_ASY_OPERATIONAL_STATS 0xE8 /* flush the asychronous operational statistics */ +#define TRANSMIT_ASY_BREAK_SIGNAL 0xEC /* transmit an asychronous break signal */ + + + +/* ---------------------------------------------------------------------------- + * Return codes from interface commands + * --------------------------------------------------------------------------*/ + +#define COMMAND_INVALID_FOR_PORT 0x50 /* the command is invalid for the selected port */ +#define DISABLE_ASY_COMMS_BEFORE_CFG 0xE1 /* communications must be disabled before setting the configuration */ +#define ASY_COMMS_ENABLED 0xE1 /* communications are currently enabled */ +#define ASY_COMMS_DISABLED 0xE1 /* communications are currently disabled */ +#define ASY_CFG_BEFORE_COMMS_ENABLED 0xE2 /* perform a SET_ASY_CONFIGURATION before enabling comms */ +#define LGTH_ASY_CFG_DATA_INVALID 0xE2 /* the length of the passed configuration data is invalid */ +#define INVALID_ASY_CFG_DATA 0xE3 /* the passed configuration data is invalid */ +#define ASY_BREAK_SIGNAL_BUSY 0xEC /* a break signal is being transmitted */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the SET_ASY_CONFIGURATION/READ_ASY_CONFIGURATION command + * --------------------------------------------------------------------------*/ + +/* the asynchronous configuration structure */ +typedef struct { + unsigned long baud_rate PACKED; /* the baud rate */ + unsigned short line_config_options PACKED; /* line configuration options */ + unsigned short modem_config_options PACKED; /* modem configuration options */ + unsigned short asy_API_options PACKED; /* asynchronous API options */ + unsigned short asy_protocol_options PACKED; /* asynchronous protocol options */ + unsigned short Tx_bits_per_char PACKED; /* number of bits per tx character */ + unsigned short Rx_bits_per_char PACKED; /* number of bits per received character */ + unsigned short stop_bits PACKED; /* number of stop bits per character */ + unsigned short parity PACKED; /* parity definition */ + unsigned short break_timer PACKED; /* the break signal timer */ + unsigned short asy_Rx_inter_char_timer PACKED; /* the receive inter-character timer */ + unsigned short asy_Rx_complete_length PACKED; /* the receive 'buffer complete' length */ + unsigned short XON_char PACKED; /* the XON character */ + unsigned short XOFF_char PACKED; /* the XOFF character */ + unsigned short asy_statistics_options PACKED; /* async operational stat options */ + unsigned long ptr_shared_mem_info_struct PACKED;/* ptr to the shared memory area information structure */ + unsigned long ptr_asy_Tx_stat_el_cfg_struct PACKED;/* ptr to the transmit status element configuration structure */ + unsigned long ptr_asy_Rx_stat_el_cfg_struct PACKED;/* ptr to the receive status element configuration structure */ +} ASY_CONFIGURATION_STRUCT; + +/* permitted minimum and maximum values for setting the asynchronous configuration */ +#define MIN_ASY_BAUD_RATE 50 /* maximum baud rate */ +#define MAX_ASY_BAUD_RATE 250000 /* minimum baud rate */ +#define MIN_ASY_BITS_PER_CHAR 5 /* minimum number of bits per character */ +#define MAX_ASY_BITS_PER_CHAR 8 /* maximum number of bits per character */ +#define MIN_BREAK_TMR_VAL 0 /* minimum break signal timer */ +#define MAX_BREAK_TMR_VAL 5000 /* maximum break signal timer */ +#define MIN_ASY_RX_INTER_CHAR_TMR 0 /* minimum receive inter-character timer */ +#define MAX_ASY_RX_INTER_CHAR_TMR 30000 /* maximum receive inter-character timer */ +#define MIN_ASY_RX_CPLT_LENGTH 0 /* minimum receive 'length complete' value */ +#define MAX_ASY_RX_CPLT_LENGTH 2000 /* maximum receive 'length complete' value */ + +/* bit settings for the 'asy_API_options' */ +#define ASY_RX_DATA_TRANSPARENT 0x0001 /* do not strip parity and unused bits from received characters */ + +/* bit settings for the 'asy_protocol_options' */ +#define ASY_RTS_HS_FOR_RX 0x0001 /* RTS handshaking is used for reception control */ +#define ASY_XON_XOFF_HS_FOR_RX 0x0002 /* XON/XOFF handshaking is used for reception control */ +#define ASY_XON_XOFF_HS_FOR_TX 0x0004 /* XON/XOFF handshaking is used for transmission control */ +#define ASY_DCD_HS_FOR_TX 0x0008 /* DCD handshaking is used for transmission control */ +#define ASY_CTS_HS_FOR_TX 0x0020 /* CTS handshaking is used for transmission control */ + +/* bit settings for the 'stop_bits' definition */ +#define ONE_STOP_BIT 1 /* representation for 1 stop bit */ +#define TWO_STOP_BITS 2 /* representation for 2 stop bits */ +#define ONE_AND_A_HALF_STOP_BITS 3 /* representation for 1.5 stop bits */ + +/* bit settings for the 'parity' definition */ +#define NO_PARITY 0 /* representation for no parity */ +#define ODD_PARITY 1 /* representation for odd parity */ +#define EVEN_PARITY 2 /* representation for even parity */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_COMMS_ERROR_STATS command (asynchronous mode) + * --------------------------------------------------------------------------*/ + +/* the communications error statistics structure */ +typedef struct { + unsigned short Rx_overrun_err_count PACKED; /* receiver overrun error count */ + unsigned short Rx_parity_err_count PACKED; /* parity errors received count */ + unsigned short Rx_framing_err_count PACKED; /* framing errors received count */ + unsigned short comms_err_stat_reserved_1 PACKED;/* reserved for later use */ + unsigned short comms_err_stat_reserved_2 PACKED;/* reserved for later use */ + unsigned short comms_err_stat_reserved_3 PACKED;/* reserved for later use */ + unsigned short comms_err_stat_reserved_4 PACKED;/* reserved for later use */ + unsigned short comms_err_stat_reserved_5 PACKED;/* reserved for later use */ + unsigned short DCD_state_change_count PACKED; /* DCD state change count */ + unsigned short CTS_state_change_count PACKED; /* CTS state change count */ +} ASY_COMMS_ERROR_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_ASY_OPERATIONAL_STATS command + * --------------------------------------------------------------------------*/ + +/* the asynchronous operational statistics structure */ +typedef struct { + + /* Data transmission statistics */ + unsigned long Data_blocks_Tx_count PACKED;/* number of blocks transmitted */ + unsigned long Data_bytes_Tx_count PACKED;/* number of bytes transmitted */ + unsigned long Data_Tx_throughput PACKED;/* transmit throughput */ + unsigned long no_ms_for_Data_Tx_thruput_comp PACKED;/* millisecond time used for the Tx throughput computation */ + unsigned long Tx_Data_discard_lgth_err_count PACKED;/* number of Data blocks discarded (length error) */ + unsigned long reserved_Data_frm_Tx_stat1 PACKED;/* reserved for later use */ + unsigned long reserved_Data_frm_Tx_stat2 PACKED;/* reserved for later use */ + unsigned long reserved_Data_frm_Tx_stat3 PACKED;/* reserved for later use */ + + /* Data reception statistics */ + unsigned long Data_blocks_Rx_count PACKED;/* number of blocks received */ + unsigned long Data_bytes_Rx_count PACKED;/* number of bytes received */ + unsigned long Data_Rx_throughput PACKED;/* receive throughput */ + unsigned long no_ms_for_Data_Rx_thruput_comp PACKED;/* millisecond time used for the Rx throughput computation */ + unsigned long Rx_Data_bytes_discard_count PACKED;/* received Data bytes discarded */ + unsigned long reserved_Data_frm_Rx_stat1 PACKED;/* reserved for later use */ + + /* handshaking protocol statistics */ + unsigned short XON_chars_Tx_count PACKED; /* number of XON characters transmitted */ + unsigned short XOFF_chars_Tx_count PACKED; /* number of XOFF characters transmitted */ + unsigned short XON_chars_Rx_count PACKED; /* number of XON characters received */ + unsigned short XOFF_chars_Rx_count PACKED; /* number of XOFF characters received */ + unsigned short Tx_halt_modem_low_count PACKED; /* number of times Tx halted (modem line low) */ + unsigned short Rx_halt_RTS_low_count PACKED; /* number of times Rx halted by setting RTS low */ + unsigned long reserved_handshaking_stat1 PACKED;/* reserved for later use */ + + /* break statistics */ + unsigned short break_Tx_count PACKED; /* number of break sequences transmitted */ + unsigned short break_Rx_count PACKED; /* number of break sequences received */ + unsigned long reserved_break_stat1 PACKED;/* reserved for later use */ + + /* miscellaneous statistics */ + unsigned long reserved_misc_stat1 PACKED; /* reserved for later use */ + unsigned long reserved_misc_stat2 PACKED; /* reserved for later use */ + +} ASY_OPERATIONAL_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for Data transmission + * --------------------------------------------------------------------------*/ + +/* the Data block transmit status element configuration structure */ +typedef struct { + unsigned short number_Tx_status_elements PACKED; /* number of transmit status elements */ + unsigned long base_addr_Tx_status_elements PACKED; /* base address of the transmit element list */ + unsigned long next_Tx_status_element_to_use PACKED; /* pointer to the next transmit element to be used */ +} ASY_TX_STATUS_EL_CFG_STRUCT; + + +/* the Data block transmit status element structure */ +typedef struct { + unsigned char opp_flag PACKED; /* opp flag */ + unsigned short data_length PACKED; /* length of the block to be transmitted */ + unsigned char reserved_1 PACKED; /* reserved for internal use */ + unsigned long reserved_2 PACKED; /* reserved for internal use */ + unsigned long reserved_3 PACKED; /* reserved for internal use */ + unsigned long ptr_data_bfr PACKED; /* pointer to the data area */ +} ASY_DATA_TX_STATUS_EL_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for Data reception + * --------------------------------------------------------------------------*/ + +/* the Data block receive status element configuration structure */ +typedef struct { + unsigned short number_Rx_status_elements PACKED;/* number of receive status elements */ + unsigned long base_addr_Rx_status_elements PACKED;/* base address of the receive element list */ + unsigned long next_Rx_status_element_to_use PACKED;/* pointer to the next receive element to be used */ + unsigned long base_addr_Rx_buffer PACKED;/* base address of the receive data buffer */ + unsigned long end_addr_Rx_buffer PACKED;/* end address of the receive data buffer */ +} ASY_RX_STATUS_EL_CFG_STRUCT; + +/* the Data block receive status element structure */ +typedef struct { + unsigned char opp_flag PACKED; /* opp flag */ + unsigned short data_length PACKED; /* length of the received data block */ + unsigned char reserved_1 PACKED; /* reserved for internal use */ + unsigned short time_stamp PACKED; /* receive time stamp (HDLC_STREAMING_MODE) */ + unsigned short data_buffered PACKED; /* the number of data bytes still buffered */ + unsigned long reserved_2 PACKED; /* reserved for internal use */ + unsigned long ptr_data_bfr PACKED; /* pointer to the data area */ +} ASY_DATA_RX_STATUS_EL_STRUCT; + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/sdla_chdlc.h linux.ac/include/linux/sdla_chdlc.h --- linux.vanilla/include/linux/sdla_chdlc.h Wed Jan 26 21:25:58 2000 +++ linux.ac/include/linux/sdla_chdlc.h Sat Apr 14 01:42:45 2001 @@ -4,7 +4,7 @@ Author: Gideon Hack Nenad Corbic <ncorbic@sangoma.com> - Copyright: (c) 1995-1999 Sangoma Technologies Inc. + Copyright: (c) 1995-2000 Sangoma Technologies Inc. This program is free software; you can redistribute it and/or modify it under the term of the GNU General Public License @@ -137,6 +137,8 @@ #define TRACE_PROT 0x01 #define TRACE_DATA 0x02 +#define DISCARD_RX_ERROR_FRAMES 0x0001 + /* ---------------------------------------------------------------------------- * Return codes from interface commands * --------------------------------------------------------------------------*/ @@ -358,6 +360,9 @@ #define IGNORE_KPALV_FOR_LINK_STAT 0x0004 /* ignore keepalive frames in determining the CHDLC link status */ +#define SINGLE_TX_BUFFER 0x4000 +/* configure a single transmit buffer */ + #define HDLC_STREAMING_MODE 0x8000 /* settings for the 'CHDLC_statistics_options' */ @@ -469,7 +474,7 @@ unsigned long reserved_CDP_stat5 PACKED; /* reserved for later */ unsigned long reserved_CDP_stat6 PACKED; /* reserved for later */ - /* Incomming frames with a format error statistics */ + /* Incoming frames with a format error statistics */ unsigned short Rx_frm_incomp_CHDLC_hdr_count PACKED; /* frames received of with incomplete Cisco HDLC header */ unsigned short Rx_frms_too_long_count PACKED; /* frames received of excessive length count */ unsigned short Rx_invalid_CHDLC_addr_count PACKED; /* frames received with an invalid CHDLC address count */ @@ -484,7 +489,7 @@ unsigned long reserved_frm_format_err4 PACKED; /* reserved for later */ /* CHDLC timeout/retry statistics */ - unsigned short SLARP_Rx_keepalive_TO_count PACKED; /* timeout count for incomming SLARP frames */ + unsigned short SLARP_Rx_keepalive_TO_count PACKED; /* timeout count for incoming SLARP frames */ unsigned short SLARP_Request_TO_count PACKED; /* timeout count for SLARP Request frames */ unsigned long To_retry_reserved_stat1 PACKED; /* reserved for later */ unsigned long To_retry_reserved_stat2 PACKED; /* reserved for later */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/sdla_fr.h linux.ac/include/linux/sdla_fr.h --- linux.vanilla/include/linux/sdla_fr.h Wed Jan 26 21:25:58 2000 +++ linux.ac/include/linux/sdla_fr.h Sat Apr 14 01:42:30 2001 @@ -4,7 +4,7 @@ * Author: Gideon Hack * Nenad Corbic <ncorbic@sangoma.com> * -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* Copyright: (c) 1995-2000 Sangoma Technologies Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -541,7 +541,7 @@ } fr_encap_hdr_t; typedef struct { - fr_encap_hdr_t fr_encap_hdr PACKED; +// fr_encap_hdr_t fr_encap_hdr PACKED; ip_pkt_t ip_pkt PACKED; udp_pkt_t udp_pkt PACKED; wp_mgmt_t wp_mgmt PACKED; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/sdla_ppp.h linux.ac/include/linux/sdla_ppp.h --- linux.vanilla/include/linux/sdla_ppp.h Wed Jan 26 21:25:58 2000 +++ linux.ac/include/linux/sdla_ppp.h Sat Apr 14 01:42:30 2001 @@ -1,7 +1,7 @@ /***************************************************************************** * sdla_ppp.h Sangoma PPP firmware API definitions. * -* Author: Gene Kozin <74604.152@compuserve.com> +* Author: Nenad Corbic <ncorbic@sangoma.com> * * Copyright: (c) 1995-1997 Sangoma Technologies Inc. * @@ -10,6 +10,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Feb 24, 2000 Nenad Corbic v2.1.2 * Jan 06, 1997 Gene Kozin v2.0 * Apr 11, 1996 Gene Kozin Initial version. *****************************************************************************/ @@ -214,7 +215,8 @@ { unsigned short txb_num PACKED; /* 00: number of transmit buffers */ unsigned long txb_ptr PACKED; /* 02: pointer to the buffer ctl. */ - unsigned char rsrv1[26] PACKED; + unsigned long txb_nxt PACKED; + unsigned char rsrv1[22] PACKED; unsigned short rxb_num PACKED; /* 20: number of receive buffers */ unsigned long rxb_ptr PACKED; /* 22: pointer to the buffer ctl. */ unsigned long rxb1_ptr PACKED; /* 26: pointer to the first buf.ctl. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/sdla_x25.h linux.ac/include/linux/sdla_x25.h --- linux.vanilla/include/linux/sdla_x25.h Wed Jun 24 22:34:44 1998 +++ linux.ac/include/linux/sdla_x25.h Sat Apr 14 01:42:30 2001 @@ -1,15 +1,16 @@ /***************************************************************************** * sdla_x25.h Sangoma X.25 firmware API definitions. * -* Author: Gene Kozin <74604.152@compuserve.com> +* Author: Nenad Corbic <ncorbic@sangoma.com> * -* Copyright: (c) 1995-1996 Sangoma Technologies Inc. +* Copyright: (c) 1995-2000 Sangoma Technologies Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version -* 2 of the License, or (at your option) any later version. + 2 of the License, or (at your option) any later version. * ============================================================================ +* Feb 28, 2000 Nenad Corbic Updated for socket based x25api * Dec 13, 1996 Gene Kozin Initial version *****************************************************************************/ #ifndef _SDLA_X25_H @@ -18,39 +19,35 @@ /*---------------------------------------------------------------------------- * Notes: * ------ - * 1. All structures defined in this file are byte-aligned. To ensure - * portability of this code between different platforms and compilers, one - * of the following defines must be defined before including this file: - * - * Compiler Platform Define Use option - * -------- -------- ------ ---------- - * GNU C Linux _GNUC_ - - * Microsoft C DOS/Windows _MSC_ - + * 1. All structures defined in this file are byte-alined. + * Compiler Platform + * -------- -------- + * GNU C Linux * */ -#ifdef _GNUC_ -# ifndef PACKED -# define PACKED __attribute__((packed)) -# endif /* PACKED */ -#else -# define PACKED -#endif -#ifdef _MSC_ -# pragma pack(1) -#endif +#ifndef PACKED +# define PACKED __attribute__((packed)) +#endif /* PACKED */ /****** CONSTANTS DEFINITIONS ***********************************************/ #define X25_MAX_CHAN 255 /* max number of open X.25 circuits */ #define X25_MAX_DATA 1024 /* max length of X.25 data buffer */ - /* * X.25 shared memory layout. */ #define X25_MBOX_OFFS 0x16B0 /* general mailbox block */ #define X25_RXMBOX_OFFS 0x1AD0 /* receive mailbox */ #define X25_STATUS_OFFS 0x1EF0 /* X.25 status structure */ +#define X25_MB_VECTOR 0xE000 /* S514 mailbox window vecotr */ +#define X25_MISC_HDLC_BITS 0x1F00 /*X.25 miscallaneous HDLC bits */ + +/* code levels */ +#define HDLC_LEVEL 0x01 +#define X25_LEVEL 0x02 +#define X25_AND_HDLC_LEVEL 0x03 +#define DO_HDLC_LEVEL_ERROR_CHECKING 0x04 /****** DATA STRUCTURES *****************************************************/ @@ -100,11 +97,12 @@ #define X25_HDLC_READ 0x21 /* read HDLC information frame */ #define X25_HDLC_READ_CONFIG 0x12 /* read HDLC configuration */ #define X25_HDLC_SET_CONFIG 0x13 /* set HDLC configuration */ +#define SET_PROTOCOL_LEVEL 0x1F /* set protocol level */ /*----- X.25-level commands -----------*/ #define X25_READ 0x22 /* read X.25 packet */ #define X25_WRITE 0x23 /* send X.25 packet */ #define X25_PLACE_CALL 0x30 /* place a call on SVC */ -#define X25_ACCEPT_CALL 0x31 /* accept incoming call */ +#define X25_ACCEPT_CALL 0x31 /* accept incomming call */ #define X25_CLEAR_CALL 0x32 /* clear call */ #define X25_CLEAR_CONFRM 0x33 /* send clear confirmation packet */ #define X25_RESET 0x34 /* send reset request packet */ @@ -116,14 +114,14 @@ #define X25_REGISTRATION_RQST 0x3A /* send registration request packet */ #define X25_REGISTRATION_CONFRM 0x3B /* send registration confirmation */ #define X25_IS_DATA_AVAILABLE 0x40 /* querry receive queue */ -#define X25_INCOMING_CALL_CTL 0x41 /* select incoming call options */ +#define X25_INCOMMING_CALL_CTL 0x41 /* select incomming call options */ #define X25_CONFIGURE_PVC 0x42 /* configure PVC */ #define X25_GET_ACTIVE_CHANNELS 0x43 /* get a list of active circuits */ #define X25_READ_CHANNEL_CONFIG 0x44 /* read virt. circuit configuration */ #define X25_FLUSH_DATA_BUFFERS 0x45 /* flush X.25-level data buffers */ #define X25_READ_HISTORY_TABLE 0x46 /* read asynchronous event log */ #define X25_HISTORY_TABLE_CTL 0x47 /* control asynchronous event log */ -#define X25_GET_TX_D_BIT_STATUS 0x48 /* is packet with D-bit acknowledged */ +#define X25_GET_TX_D_BIT_STATUS 0x48 /* is packet with D-bit acknowleged */ #define X25_READ_STATISTICS 0x49 /* read X.25-level statistics */ #define X25_FLUSH_STATISTICS 0x4A /* flush X.25-level statistics */ #define X25_READ_CONFIGURATION 0x50 /* read HDLC & X.25 configuration */ @@ -139,7 +137,7 @@ #define X25RES_LINK_CLOSED 0x03 #define X25RES_INVAL_LENGTH 0x04 #define X25RES_INVAL_CMD 0x05 -#define X25RES_UNNUMBERED_FRAME 0x06 /* unnumbered frame received */ +#define X25RES_UNNUMBERED_FRAME 0x06 /* unnunbered frame received */ #define X25RES_FRM_REJECT_MODE 0x07 /* link is in Frame Reject mode */ #define X25RES_MODEM_FAILURE 0x08 /* DCD and/or CTS dropped */ #define X25RES_N2_RETRY_LIMIT 0x09 /* N2 retry limit has been exceeded */ @@ -153,13 +151,13 @@ #define X25RES_INVAL_FORMAT 0x37 /* invalid packet format */ #define X25RES_D_BIT_NOT_SUPPRT 0x38 /* D-bit pragmatics not supported */ #define X25RES_FACIL_NOT_SUPPRT 0x39 /* Call facility not supported */ -#define X25RES_INVAL_CALL_ARG 0x3A /* erroneous call arguments */ -#define X25RES_INVAL_CALL_DATA 0x3B /* erroneous call user data */ +#define X25RES_INVAL_CALL_ARG 0x3A /* errorneous call arguments */ +#define X25RES_INVAL_CALL_DATA 0x3B /* errorneous call user data */ #define X25RES_ASYNC_PACKET 0x40 /* asynchronous packet received */ -#define X25RES_PROTO_VIOLATION 0x41 /* protocol violation occurred */ +#define X25RES_PROTO_VIOLATION 0x41 /* protocol violation occured */ #define X25RES_PKT_TIMEOUT 0x42 /* X.25 packet time out */ #define X25RES_PKT_RETRY_LIMIT 0x43 /* X.25 packet retry limit exceeded */ -/*----- Command-dependent results -----*/ +/*----- Command-dependant results -----*/ #define X25RES_LINK_DISC 0x00 /* HDLC_LINK_STATUS */ #define X25RES_LINK_IN_ABM 0x01 /* HDLC_LINK_STATUS */ #define X25RES_NO_DATA 0x01 /* HDLC_READ/READ_TRACE_DATA*/ @@ -167,7 +165,7 @@ #define X25RES_LINK_IS_OPEN 0x01 /* HDLC_LINK_OPEN */ #define X25RES_LINK_IS_DISC 0x02 /* HDLC_LINK_DISC */ #define X25RES_LINK_IS_CLOSED 0x03 /* HDLC_LINK_CLOSE */ -#define X25RES_INVAL_PARAM 0x31 /* INCOMING_CALL_CTL */ +#define X25RES_INVAL_PARAM 0x31 /* INCOMMING_CALL_CTL */ #define X25RES_INVAL_CONFIG 0x35 /* REGISTR_RQST/CONFRM */ /* @@ -207,6 +205,22 @@ #define PVE_RESTART_RQST 0x34 #define PVE_DIAGNOSTIC 0x37 +#define INTR_ON_RX_FRAME 0x01 +#define INTR_ON_TX_FRAME 0x02 +#define INTR_ON_MODEM_STATUS_CHANGE 0x04 +#define INTR_ON_COMMAND_COMPLETE 0x08 +#define INTR_ON_X25_ASY_TRANSACTION 0x10 +#define INTR_ON_TIMER 0x40 +#define DIRECT_RX_INTR_USAGE 0x80 + +#define NO_INTR_PENDING 0x00 +#define RX_INTR_PENDING 0x01 +#define TX_INTR_PENDING 0x02 +#define MODEM_INTR_PENDING 0x04 +#define COMMAND_COMPLETE_INTR_PENDING 0x08 +#define X25_ASY_TRANS_INTR_PENDING 0x10 +#define TIMER_INTR_PENDING 0x40 + /*---------------------------------------------------------------------------- * X.25 Mailbox. * This structure is located at offsets X25_MBOX_OFFS and X25_RXMBOX_OFFS @@ -239,7 +253,7 @@ typedef struct X25Status { unsigned short pvc_map PACKED; /* 00h: PVC map */ - unsigned short icc_map PACKED; /* 02h: Incoming Chan. map */ + unsigned short icc_map PACKED; /* 02h: Incomming Chan. map */ unsigned short twc_map PACKED; /* 04h: Two-way Cnan. map */ unsigned short ogc_map PACKED; /* 06h: Outgoing Chan. map */ TX25TimeStamp tstamp PACKED; /* 08h: timestamp (BCD) */ @@ -256,7 +270,7 @@ #define X25_RX_INTR 0x01 /* receive interrupt */ #define X25_TX_INTR 0x02 /* transmit interrupt */ #define X25_MODEM_INTR 0x04 /* modem status interrupt (CTS/DCD) */ -#define X25_EVENT_INTR 0x10 /* asynchronous event encountered */ +#define X25_EVENT_INTR 0x10 /* asyncronous event encountered */ #define X25_CMD_INTR 0x08 /* interface command complete */ /* @@ -374,7 +388,7 @@ */ typedef struct X25Config { - unsigned char baudRate PACKED; /* 00h: */ +unsigned char baudRate PACKED; /* 00h: */ unsigned char t1 PACKED; /* 01h: */ unsigned char t2 PACKED; /* 02h: */ unsigned char n2 PACKED; /* 03h: */ @@ -390,8 +404,8 @@ unsigned short pktMTU PACKED; /* 0Fh: */ unsigned short loPVC PACKED; /* 11h: */ unsigned short hiPVC PACKED; /* 13h: */ - unsigned short loIncomingSVC PACKED; /* 15h: */ - unsigned short hiIncomingSVC PACKED; /* 17h: */ + unsigned short loIncommingSVC PACKED; /* 15h: */ + unsigned short hiIncommingSVC PACKED; /* 17h: */ unsigned short loTwoWaySVC PACKED; /* 19h: */ unsigned short hiTwoWaySVC PACKED; /* 1Bh: */ unsigned short loOutgoingSVC PACKED; /* 1Dh: */ @@ -421,8 +435,8 @@ { unsigned short loPVC PACKED; /* 00h: lowest PVC number */ unsigned short hiPVC PACKED; /* 02h: highest PVC number */ - unsigned short loIncomingSVC PACKED; /* 04h: lowest incoming SVC */ - unsigned short hiIncomingSVC PACKED; /* 06h: highest incoming SVC */ + unsigned short loIncommingSVC PACKED; /* 04h: lowest incoming SVC */ + unsigned short hiIncommingSVC PACKED; /* 06h: highest incoming SVC */ unsigned short loTwoWaySVC PACKED; /* 08h: lowest two-way SVC */ unsigned short hiTwoWaySVC PACKED; /* 0Ah: highest two-way SVC */ unsigned short loOutgoingSVC PACKED; /* 0Ch: lowest outgoing SVC */ @@ -499,7 +513,7 @@ /* * Defines for the 'type' field. */ -#define X25LOG_INCOMING 0x00 +#define X25LOG_INCOMMING 0x00 #define X25LOG_APPLICATION 0x01 #define X25LOG_AUTOMATIC 0x02 #define X25LOG_ERROR 0x04 @@ -568,7 +582,7 @@ #define X25_TRCERR_RX_BADCRC 0x20 /* receive CRC error */ #define X25_TRCERR_RX_OVERRUN 0x30 /* receiver overrun error */ #define X25_TRCERR_RX_TOO_LONG 0x40 /* excessive frame length error */ -#define X25_TRCERR_TX_ABORT 0x70 /* aborted frame transmission error */ +#define X25_TRCERR_TX_ABORT 0x70 /* aborted frame transmittion error */ #define X25_TRCERR_TX_UNDERRUN 0x80 /* transmit underrun error */ /***************************************************************************** @@ -582,7 +596,7 @@ unsigned char data[0] PACKED; } THDLCFrame; -typedef struct X25Pkt /*----- X.25 Packet Format ----------*/ +typedef struct X25Pkt /*----- X.25 Paket Format ----------*/ { unsigned char lcn_hi PACKED; /* 4 MSB of Logical Channel Number */ unsigned char lcn_lo PACKED; /* 8 LSB of Logical Channel Number */ @@ -619,7 +633,140 @@ #define X25PKT_RR_MASKED 0x01 /* Receive Ready packet after masking */ #define X25PKT_RNR_MASKED 0x05 /* Receive Not Ready after masking */ -#ifdef _MSC_ -# pragma pack() -#endif + +typedef struct { + TX25Cmd cmd PACKED; + char data[X25_MAX_DATA] PACKED; +} mbox_cmd_t; + + +typedef struct { + unsigned char qdm PACKED; /* Q/D/M bits */ + unsigned char cause PACKED; /* cause field */ + unsigned char diagn PACKED; /* diagnostics */ + unsigned char pktType PACKED; + unsigned short length PACKED; + unsigned char result PACKED; + unsigned short lcn PACKED; + char reserved[7] PACKED; +}x25api_hdr_t; + + +typedef struct { + x25api_hdr_t hdr PACKED; + char data[X25_MAX_DATA] PACKED; +}x25api_t; + + +/* + * XPIPEMON Definitions + */ + +/* valid ip_protocol for UDP management */ +#define UDPMGMT_UDP_PROTOCOL 0x11 +#define UDPMGMT_XPIPE_SIGNATURE "XLINK8ND" +#define UDPMGMT_DRVRSTATS_SIGNATURE "DRVSTATS" + +/* values for request/reply byte */ +#define UDPMGMT_REQUEST 0x01 +#define UDPMGMT_REPLY 0x02 +#define UDP_OFFSET 12 + + +typedef struct { + unsigned char opp_flag PACKED; /* the opp flag */ + unsigned char command PACKED; /* command code */ + unsigned short length PACKED; /* transfer data length */ + unsigned char result PACKED; /* return code */ + unsigned char pf PACKED; /* P/F bit */ + unsigned short lcn PACKED; /* logical channel */ + unsigned char qdm PACKED; /* Q/D/M bits */ + unsigned char cause PACKED; /* cause field */ + unsigned char diagn PACKED; /* diagnostics */ + unsigned char pktType PACKED; /* packet type */ + unsigned char resrv[4] PACKED; /* reserved */ +} cblock_t; + +typedef struct { + ip_pkt_t ip_pkt PACKED; + udp_pkt_t udp_pkt PACKED; + wp_mgmt_t wp_mgmt PACKED; + cblock_t cblock PACKED; + unsigned char data[4080] PACKED; +} x25_udp_pkt_t; + + +typedef struct read_hdlc_stat { + unsigned short inf_frames_rx_ok PACKED; + unsigned short inf_frames_rx_out_of_seq PACKED; + unsigned short inf_frames_rx_no_data PACKED; + unsigned short inf_frames_rx_dropped PACKED; + unsigned short inf_frames_rx_data_too_long PACKED; + unsigned short inf_frames_rx_invalid_addr PACKED; + unsigned short inf_frames_tx_ok PACKED; + unsigned short inf_frames_tx_retransmit PACKED; + unsigned short T1_timeouts PACKED; + unsigned short SABM_frames_rx PACKED; + unsigned short DISC_frames_rx PACKED; + unsigned short DM_frames_rx PACKED; + unsigned short FRMR_frames_rx PACKED; + unsigned short SABM_frames_tx PACKED; + unsigned short DISC_frames_tx PACKED; + unsigned short DM_frames_tx PACKED; + unsigned short FRMR_frames_tx PACKED; +} read_hdlc_stat_t; + +typedef struct read_comms_err_stats{ + unsigned char overrun_err_rx PACKED; + unsigned char CRC_err PACKED; + unsigned char abort_frames_rx PACKED; + unsigned char frames_dropped_buf_full PACKED; + unsigned char abort_frames_tx PACKED; + unsigned char transmit_underruns PACKED; + unsigned char missed_tx_underruns_intr PACKED; + unsigned char reserved PACKED; + unsigned char DCD_drop PACKED; + unsigned char CTS_drop PACKED; +} read_comms_err_stats_t; + +typedef struct trace_data { + unsigned short length PACKED; + unsigned char type PACKED; + unsigned char trace_dropped PACKED; + unsigned char reserved[5] PACKED; + unsigned short timestamp PACKED; + unsigned char data PACKED; +} trace_data_t; + +enum {UDP_XPIPE_TYPE}; + +#define XPIPE_ENABLE_TRACING 0x14 +#define XPIPE_DISABLE_TRACING 0x14 +#define XPIPE_GET_TRACE_INFO 0x16 +#define XPIPE_FT1_READ_STATUS 0x74 +#define XPIPE_DRIVER_STAT_IFSEND 0x75 +#define XPIPE_DRIVER_STAT_INTR 0x76 +#define XPIPE_DRIVER_STAT_GEN 0x77 +#define XPIPE_FLUSH_DRIVER_STATS 0x78 +#define XPIPE_ROUTER_UP_TIME 0x79 +#define XPIPE_SET_FT1_MODE 0x81 +#define XPIPE_FT1_STATUS_CTRL 0x80 + + +/* error messages */ +#define NO_BUFFS_OR_CLOSED_WIN 0x33 +#define DATA_LENGTH_TOO_BIG 0x32 +#define NO_DATA_AVAILABLE 0x33 +#define Z80_TIMEOUT_ERROR 0x0a +#define NO_BUFFS 0x08 + + +/* Trace options */ +#define TRACE_DEFAULT 0x03 +#define TRACE_SUPERVISOR_FRMS 0x10 +#define TRACE_ASYNC_FRMS 0x20 +#define TRACE_ALL_HDLC_FRMS 0x40 +#define TRACE_DATA_FRMS 0x08 + + #endif /* _SDLA_X25_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/sdladrv.h linux.ac/include/linux/sdladrv.h --- linux.vanilla/include/linux/sdladrv.h Mon Dec 11 21:00:00 2000 +++ linux.ac/include/linux/sdladrv.h Mon Apr 16 14:40:07 2001 @@ -3,7 +3,7 @@ * * Author: Gideon Hack * -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* Copyright: (c) 1995-2000 Sangoma Technologies Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,13 +20,21 @@ #define _SDLADRV_H #include <linux/version.h> -#if LINUX_VERSION_CODE >= 0x020100 + +#ifndef KERNEL_VERSION + #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) +#define LINUX_2_4 +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) #define LINUX_2_1 +#else +#define LINUX_2_0 #endif #define SDLA_MAXIORANGE 4 /* maximum I/O port range */ #define SDLA_WINDOWSIZE 0x2000 /* default dual-port memory window size */ - /****** Data Structures *****************************************************/ /*---------------------------------------------------------------------------- @@ -41,7 +49,8 @@ int irq; /* interrupt request level */ char S514_cpu_no[1]; /* PCI CPU Number */ unsigned char S514_slot_no; /* PCI Slot Number */ -#ifdef LINUX_2_1 + char auto_pci_cfg; /* Autodetect PCI Slot */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) struct pci_dev *pci_dev; /* PCI device */ #else unsigned char pci_bus; /* PCI bus number */ @@ -73,5 +82,7 @@ extern int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len); extern int sdla_exec (void* opflag); + +extern unsigned wanpipe_hw_probe(void); #endif /* _SDLADRV_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/sdlapci.h linux.ac/include/linux/sdlapci.h --- linux.vanilla/include/linux/sdlapci.h Wed Jan 26 21:25:58 2000 +++ linux.ac/include/linux/sdlapci.h Sat Apr 14 01:42:30 2001 @@ -4,7 +4,7 @@ * * Author: Gideon Hack <ghack@sangoma.com> * -* Copyright: (c) 1999 Sangoma Technologies Inc. +* Copyright: (c) 1999-2000 Sangoma Technologies Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -62,7 +62,11 @@ #define S514_CPU_START 0x01 /* The maximum number of S514 adapters supported */ -#define MAX_S514_CARDS 8 +#define MAX_S514_CARDS 20 + +#define PCI_CARD_TYPE 0x2E +#define S514_DUAL_CPU 0x12 +#define S514_SINGLE_CPU 0x11 #endif /* _SDLAPCI_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/serialP.h linux.ac/include/linux/serialP.h --- linux.vanilla/include/linux/serialP.h Tue Apr 3 17:32:29 2001 +++ linux.ac/include/linux/serialP.h Sat Apr 14 15:07:28 2001 @@ -181,7 +181,7 @@ #define SPCI_FL_IRQBASE4 (0x0004 << 4) #define SPCI_FL_GET_IRQBASE(x) ((x & SPCI_FL_IRQ_MASK) >> 4) -/* Use sucessive BARs (PCI base address registers), +/* Use successive BARs (PCI base address registers), else use offset into some specified BAR */ #define SPCI_FL_BASE_TABLE 0x0100 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/serial_reg.h linux.ac/include/linux/serial_reg.h --- linux.vanilla/include/linux/serial_reg.h Tue Apr 3 17:32:29 2001 +++ linux.ac/include/linux/serial_reg.h Tue Apr 3 17:55:17 2001 @@ -260,8 +260,8 @@ #define UART_RSA_SRR_Rx_FIFO_NEMP (1 << 3) /* Rx FIFO is not empty (1) */ #define UART_RSA_SRR_Rx_FIFO_NHFL (1 << 4) /* Rx FIFO is not half full (1) */ #define UART_RSA_SRR_Rx_FIFO_NFUL (1 << 5) /* Rx FIFO is not full (1) */ -#define UART_RSA_SRR_Rx_TOUT (1 << 6) /* Character reception timeout occured (1) */ -#define UART_RSA_SRR_TIMER (1 << 7) /* Timer interrupt occured */ +#define UART_RSA_SRR_Rx_TOUT (1 << 6) /* Character reception timeout occurred (1) */ +#define UART_RSA_SRR_TIMER (1 << 7) /* Timer interrupt occurred */ #define UART_RSA_FRR ((UART_RSA_BASE) + 2) /* OUT: FIFO Reset Register */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/serio.h linux.ac/include/linux/serio.h --- linux.vanilla/include/linux/serio.h Wed Jun 21 16:22:21 2000 +++ linux.ac/include/linux/serio.h Sat Apr 14 01:43:17 2001 @@ -2,7 +2,7 @@ #define _SERIO_H /* - * $Id: serio.h,v 1.7 2000/06/01 11:39:46 vojtech Exp $ + * $Id: serio.h,v 1.8 2000/07/17 10:42:14 vojtech Exp $ * * Copyright (C) 1999 Vojtech Pavlik * @@ -103,6 +103,7 @@ #define SERIO_SPACEBALL 0x1b #define SERIO_GUNZE 0x1c #define SERIO_IFORCE 0x1d +#define SERIO_STINGER 0x1e #define SERIO_ID 0xff00UL #define SERIO_EXTRA 0xff0000UL diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/shmem_fs.h linux.ac/include/linux/shmem_fs.h --- linux.vanilla/include/linux/shmem_fs.h Fri Dec 29 22:07:24 2000 +++ linux.ac/include/linux/shmem_fs.h Sat Apr 14 01:43:22 2001 @@ -19,6 +19,7 @@ struct shmem_inode_info { spinlock_t lock; + unsigned long max_index; swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* for the first blocks */ swp_entry_t **i_indirect; /* doubly indirect blocks */ unsigned long swapped; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/sisfb.h linux.ac/include/linux/sisfb.h --- linux.vanilla/include/linux/sisfb.h Thu Nov 9 01:15:13 2000 +++ linux.ac/include/linux/sisfb.h Tue Apr 3 17:55:17 2001 @@ -1,12 +1,6 @@ #ifndef _LINUX_SISFB #define _LINUX_SISFB -/* CRT2 connection */ -#define MASK_DISPTYPE_CRT2 0x04 /* Connect CRT2 */ -#define MASK_DISPTYPE_LCD 0x02 /* Connect LCD */ -#define MASK_DISPTYPE_TV 0x01 /* Connect TV */ -#define MASK_DISPTYPE_DISP2 (MASK_DISPTYPE_LCD | MASK_DISPTYPE_TV | MASK_DISPTYPE_CRT2) - #define DISPTYPE_CRT1 0x00000008L #define DISPTYPE_CRT2 0x00000004L #define DISPTYPE_LCD 0x00000002L @@ -17,73 +11,72 @@ #define DISPMODE_MIRROR 0x00000010L #define DISPMODE_DUALVIEW 0x00000040L -#define HASVB_NONE 0 -#define HASVB_301 1 -#define HASVB_LVDS 2 -#define HASVB_TRUMPION 3 -#define HASVB_LVDS_CHRONTEL 4 -#define HASVB_LVDS_ALL (HASVB_LVDS | HASVB_TRUMPION | HASVB_LVDS_CHRONTEL) +#define HASVB_NONE 0x00 +#define HASVB_301 0x01 +#define HASVB_LVDS 0x02 +#define HASVB_TRUMPION 0x04 +#define HASVB_LVDS_CHRONTEL 0x10 +#define HASVB_302 0x20 +#define HASVB_303 0x40 +#define HASVB_LVDS_ALL (HASVB_LVDS | HASVB_TRUMPION | HASVB_LVDS_CHRONTEL) + +typedef enum CHIPTYPE { + SIS_UNKNOWN = 0, + SIS_Glamour, + SIS_Trojan, + SIS_Spartan, + SIS_730, + SIS_GlamourII, + SIS_315, + SIS_550, + MAX_SIS_CHIP +} CHIP_TYPE; -enum _TVMODE -{ +typedef enum _TVTYPE { TVMODE_NTSC = 0, TVMODE_PAL, TVMODE_HIVISION, TVMODE_TOTAL -}; +} TV_TYPE; -enum _TVPLUGTYPE -{ +typedef enum _TVPLUGTYPE { TVPLUG_UNKNOWN = 0, TVPLUG_COMPOSITE, TVPLUG_SVIDEO, TVPLUG_SCART, TVPLUG_TOTAL -}; - -enum CHIPTYPE -{ - SiS_UNKNOWN = 0, - SiS_300, - SiS_540, - SiS_630, - SiS_630S, - SiS_730 -}; - -struct sis_memreq -{ - unsigned long offset; - unsigned long size; -}; - -/* Data for AP */ -struct mode_info -{ - int bpp; - int xres; - int yres; - int v_xres; - int v_yres; - int org_x; - int org_y; - unsigned int vrate; -}; +} TV_PLUG; -struct ap_data -{ - struct mode_info minfo; - unsigned long iobase; - unsigned int mem_size; - unsigned long disp_state; - enum CHIPTYPE chip; +struct sis_memreq { + unsigned long offset; + unsigned long size; +}; + +struct mode_info { + int bpp; + int xres; + int yres; + int v_xres; + int v_yres; + int org_x; + int org_y; + unsigned int vrate; +}; + +struct ap_data { + struct mode_info minfo; + unsigned long iobase; + unsigned int mem_size; + unsigned long disp_state; + CHIP_TYPE chip; + unsigned char hasVB; + TV_TYPE TV_type; + TV_PLUG TV_plug; + unsigned long version; + char reserved[256]; }; - -/* Data for kernel */ -struct video_info -{ - /* card parameters */ +struct video_info { int chip_id; unsigned int video_size; unsigned long video_base; @@ -92,21 +85,24 @@ char *mmio_vbase; unsigned long vga_base; - /* mode */ - int video_bpp; - int video_width; - int video_height; - int video_vwidth; - int video_vheight; - int org_x; - int org_y; - unsigned int refresh_rate; + int video_bpp; + int video_width; + int video_height; + int video_vwidth; + int video_vheight; + int org_x; + int org_y; + unsigned int refresh_rate; - /* VB functions */ unsigned long disp_state; unsigned char hasVB; unsigned char TV_type; unsigned char TV_plug; + + CHIP_TYPE chip; + unsigned char revision_id; + + char reserved[256]; }; #ifdef __KERNEL__ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/skbuff.h linux.ac/include/linux/skbuff.h --- linux.vanilla/include/linux/skbuff.h Thu Feb 22 00:10:12 2001 +++ linux.ac/include/linux/skbuff.h Tue Apr 17 17:44:38 2001 @@ -18,10 +18,13 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/time.h> +#include <linux/cache.h> #include <asm/atomic.h> #include <asm/types.h> #include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/highmem.h> #define HAVE_ALLOC_SKB /* For the drivers to know */ #define HAVE_ALIGNABLE_SKB /* Ditto 8) */ @@ -31,6 +34,47 @@ #define CHECKSUM_HW 1 #define CHECKSUM_UNNECESSARY 2 +#define SKB_DATA_ALIGN(X) (((X) + (SMP_CACHE_BYTES-1)) & ~(SMP_CACHE_BYTES-1)) +#define SKB_MAX_HEAD(X) ((PAGE_SIZE - (X) - sizeof(struct skb_shared_info))&~(SMP_CACHE_BYTES-1)) + +/* A. Checksumming of received packets by device. + * + * NONE: device failed to checksum this packet. + * skb->csum is undefined. + * + * UNNECESSARY: device parsed packet and wouldbe verified checksum. + * skb->csum is undefined. + * It is bad option, but, unfortunately, many of vendors do this. + * Apparently with secret goal to sell you new device, when you + * will add new protocol to your host. F.e. IPv6. 8) + * + * HW: the most generic way. Device supplied checksum of _all_ + * the packet as seen by netif_rx in skb->csum. + * NOTE: Even if device supports only some protocols, but + * is able to produce some skb->csum, it MUST use HW, + * not UNNECESSARY. + * + * B. Checksumming on output. + * + * NONE: skb is checksummed by protocol or csum is not required. + * + * HW: device is required to csum packet as seen by hard_start_xmit + * from skb->h.raw to the end and to record the checksum + * at skb->h.raw+skb->csum. + * + * Device must show its capabilities in dev->features, set + * at device setup time. + * NETIF_F_HW_CSUM - it is clever device, it is able to checksum + * everything. + * NETIF_F_NO_CSUM - loopback or reliable single hop media. + * NETIF_F_IP_CSUM - device is dumb. It is able to csum only + * TCP/UDP over IPv4. Sigh. Vendors like this + * way by an unknown reason. Though, see comment above + * about CHECKSUM_UNNECESSARY. 8) + * + * Any questions? No questions, good. --ANK + */ + #ifdef __i386__ #define NET_CALLER(arg) (*(((void**)&arg)-1)) #else @@ -57,6 +101,29 @@ spinlock_t lock; }; +struct sk_buff; + +#define MAX_SKB_FRAGS 6 + +typedef struct skb_frag_struct skb_frag_t; + +struct skb_frag_struct +{ + struct page *page; + __u16 page_offset; + __u16 size; +}; + +/* This data is invariant across clones and lives at + * the end of the header data, ie. at skb->end. + */ +struct skb_shared_info { + atomic_t dataref; + unsigned int nr_frags; + struct sk_buff *frag_list; + skb_frag_t frags[MAX_SKB_FRAGS]; +}; + struct sk_buff { /* These two members must be first. */ struct sk_buff * next; /* Next buffer in list */ @@ -107,9 +174,10 @@ char cb[48]; unsigned int len; /* Length of actual data */ + unsigned int data_len; unsigned int csum; /* Checksum */ - volatile char used; /* Data moved to user and not MSG_PEEK */ - unsigned char cloned, /* head may be cloned (check refcnt to be sure). */ + unsigned char __unused, /* Dead field, may be reused */ + cloned, /* head may be cloned (check refcnt to be sure). */ pkt_type, /* Packet class */ ip_summed; /* Driver fed us an IP checksum */ __u32 priority; /* Packet queueing priority */ @@ -122,6 +190,7 @@ unsigned char *data; /* Data head pointer */ unsigned char *tail; /* Tail pointer */ unsigned char *end; /* End pointer */ + void (*destructor)(struct sk_buff *); /* Destruct function */ #ifdef CONFIG_NETFILTER /* Can be used for communication between hooks. */ @@ -158,11 +227,13 @@ #include <asm/system.h> extern void __kfree_skb(struct sk_buff *skb); -extern struct sk_buff * skb_peek_copy(struct sk_buff_head *list); extern struct sk_buff * alloc_skb(unsigned int size, int priority); extern void kfree_skbmem(struct sk_buff *skb); extern struct sk_buff * skb_clone(struct sk_buff *skb, int priority); extern struct sk_buff * skb_copy(const struct sk_buff *skb, int priority); +extern struct sk_buff * pskb_copy(struct sk_buff *skb, int gfp_mask); +extern int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, int gfp_mask); +extern struct sk_buff * skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom); extern struct sk_buff * skb_copy_expand(const struct sk_buff *skb, int newheadroom, int newtailroom, @@ -171,14 +242,8 @@ extern void skb_over_panic(struct sk_buff *skb, int len, void *here); extern void skb_under_panic(struct sk_buff *skb, int len, void *here); -/* Backwards compatibility */ -#define skb_realloc_headroom(skb, nhr) skb_copy_expand(skb, nhr, skb_tailroom(skb), GFP_ATOMIC) - /* Internal */ -static inline atomic_t *skb_datarefp(struct sk_buff *skb) -{ - return (atomic_t *)(skb->end); -} +#define skb_shinfo(SKB) ((struct skb_shared_info *)((SKB)->end)) /** * skb_queue_empty - check if a queue is empty @@ -243,7 +308,7 @@ static inline int skb_cloned(struct sk_buff *skb) { - return skb->cloned && atomic_read(skb_datarefp(skb)) != 1; + return skb->cloned && atomic_read(&skb_shinfo(skb)->dataref) != 1; } /** @@ -679,6 +744,20 @@ return result; } +static inline int skb_is_nonlinear(const struct sk_buff *skb) +{ + return skb->data_len; +} + +static inline int skb_headlen(const struct sk_buff *skb) +{ + return skb->len - skb->data_len; +} + +#define SKB_PAGE_ASSERT(skb) do { if (skb_shinfo(skb)->nr_frags) BUG(); } while (0) +#define SKB_FRAG_ASSERT(skb) do { if (skb_shinfo(skb)->frag_list) BUG(); } while (0) +#define SKB_LINEAR_ASSERT(skb) do { if (skb_is_nonlinear(skb)) BUG(); } while (0) + /* * Add data to an sk_buff */ @@ -686,6 +765,7 @@ static inline unsigned char *__skb_put(struct sk_buff *skb, unsigned int len) { unsigned char *tmp=skb->tail; + SKB_LINEAR_ASSERT(skb); skb->tail+=len; skb->len+=len; return tmp; @@ -704,6 +784,7 @@ static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len) { unsigned char *tmp=skb->tail; + SKB_LINEAR_ASSERT(skb); skb->tail+=len; skb->len+=len; if(skb->tail>skb->end) { @@ -742,6 +823,8 @@ static inline char *__skb_pull(struct sk_buff *skb, unsigned int len) { skb->len-=len; + if (skb->len < skb->data_len) + BUG(); return skb->data+=len; } @@ -763,6 +846,33 @@ return __skb_pull(skb,len); } +extern unsigned char * __pskb_pull_tail(struct sk_buff *skb, int delta); + +static inline char *__pskb_pull(struct sk_buff *skb, unsigned int len) +{ + if (len > skb_headlen(skb) && + __pskb_pull_tail(skb, len-skb_headlen(skb)) == NULL) + return NULL; + skb->len -= len; + return skb->data += len; +} + +static inline unsigned char * pskb_pull(struct sk_buff *skb, unsigned int len) +{ + if (len > skb->len) + return NULL; + return __pskb_pull(skb,len); +} + +static inline int pskb_may_pull(struct sk_buff *skb, unsigned int len) +{ + if (len <= skb_headlen(skb)) + return 1; + if (len > skb->len) + return 0; + return (__pskb_pull_tail(skb, len-skb_headlen(skb)) != NULL); +} + /** * skb_headroom - bytes at buffer head * @skb: buffer to check @@ -784,7 +894,7 @@ static inline int skb_tailroom(const struct sk_buff *skb) { - return skb->end-skb->tail; + return skb_is_nonlinear(skb) ? 0 : skb->end-skb->tail; } /** @@ -802,11 +912,16 @@ skb->tail+=len; } +extern int ___pskb_trim(struct sk_buff *skb, unsigned int len, int realloc); static inline void __skb_trim(struct sk_buff *skb, unsigned int len) { - skb->len = len; - skb->tail = skb->data+len; + if (!skb->data_len) { + skb->len = len; + skb->tail = skb->data+len; + } else { + ___pskb_trim(skb, len, 0); + } } /** @@ -825,6 +940,25 @@ } } + +static inline int __pskb_trim(struct sk_buff *skb, unsigned int len) +{ + if (!skb->data_len) { + skb->len = len; + skb->tail = skb->data+len; + return 0; + } else { + return ___pskb_trim(skb, len, 1); + } +} + +static inline int pskb_trim(struct sk_buff *skb, unsigned int len) +{ + if (len < skb->len) + return __pskb_trim(skb, len); + return 0; +} + /** * skb_orphan - orphan a buffer * @skb: buffer to orphan @@ -920,32 +1054,57 @@ } /** - * skb_cow - copy a buffer if need be - * @skb: buffer to copy + * skb_cow - copy header of skb when it is required + * @skb: buffer to cow * @headroom: needed headroom * - * If the buffer passed lacks sufficient headroom or is a clone then - * it is copied and the additional headroom made available. If there - * is no free memory %NULL is returned. The new buffer is returned if - * a copy was made (and the old one dropped a reference). The existing - * buffer is returned otherwise. + * If the skb passed lacks sufficient headroom or its data part + * is shared, data is reallocated. If reallocation fails, an error + * is returned and original skb is not changed. * - * This function primarily exists to avoid making two copies when making - * a writable copy of a buffer and then growing the headroom. + * The result is skb with writable area skb->head...skb->tail + * and at least @headroom of space at head. */ - -static inline struct sk_buff * +static inline int skb_cow(struct sk_buff *skb, unsigned int headroom) { - headroom = (headroom+15)&~15; + int delta = headroom - skb_headroom(skb); - if ((unsigned)skb_headroom(skb) < headroom || skb_cloned(skb)) { - struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom); - kfree_skb(skb); - skb = skb2; - } - return skb; + if (delta < 0) + delta = 0; + + if (delta || skb_cloned(skb)) + return pskb_expand_head(skb, (delta+15)&~15, 0, GFP_ATOMIC); + return 0; +} + +/** + * skb_linearize - convert paged skb to linear one + * @skb: buffer to linarize + * @gfp_mask: allocation mode + * + * If there is no free memory -ENOMEM is returned, otherwise zero + * is returned and the old skb data released. */ +int skb_linearize(struct sk_buff *skb, int gfp); + +static inline void *kmap_skb_frag(const skb_frag_t *frag) +{ +#ifdef CONFIG_HIGHMEM + if (in_irq()) + BUG(); + + local_bh_disable(); +#endif + return kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ); +} + +static inline void kunmap_skb_frag(void *vaddr) +{ + kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ); +#ifdef CONFIG_HIGHMEM + local_bh_enable(); +#endif } #define skb_queue_walk(queue, skb) \ @@ -956,9 +1115,15 @@ extern struct sk_buff * skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err); extern unsigned int datagram_poll(struct file *file, struct socket *sock, struct poll_table_struct *wait); -extern int skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size); -extern int skb_copy_datagram_iovec(struct sk_buff *from, int offset, struct iovec *to,int size); +extern int skb_copy_datagram(const struct sk_buff *from, int offset, char *to,int size); +extern int skb_copy_datagram_iovec(const struct sk_buff *from, int offset, struct iovec *to,int size); +extern int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, u8 *to, int len, unsigned int *csump); +extern int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, int hlen, struct iovec *iov); extern void skb_free_datagram(struct sock * sk, struct sk_buff *skb); + +extern unsigned int skb_checksum(const struct sk_buff *skb, int offset, int len, unsigned int csum); +extern int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len); +extern unsigned int skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, int len, unsigned int csum); extern void skb_init(void); extern void skb_add_mtu(int mtu); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/slab.h linux.ac/include/linux/slab.h --- linux.vanilla/include/linux/slab.h Thu Feb 22 00:09:58 2001 +++ linux.ac/include/linux/slab.h Tue Apr 17 17:44:38 2001 @@ -36,6 +36,7 @@ #define SLAB_NO_REAP 0x00001000UL /* never reap from the cache */ #define SLAB_HWCACHE_ALIGN 0x00002000UL /* align objs on a h/w cache lines */ #define SLAB_CACHE_DMA 0x00004000UL /* use GFP_DMA memory */ +#define SLAB_MUST_HWCACHE_ALIGN 0x00008000UL /* force alignment */ /* flags passed to a constructor func */ #define SLAB_CTOR_CONSTRUCTOR 0x001UL /* if not set, then deconstructor */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/socket.h linux.ac/include/linux/socket.h --- linux.vanilla/include/linux/socket.h Thu Feb 22 00:09:56 2001 +++ linux.ac/include/linux/socket.h Sat Apr 14 01:43:29 2001 @@ -155,6 +155,7 @@ #define AF_SNA 22 /* Linux SNA Project (nutters!) */ #define AF_IRDA 23 /* IRDA sockets */ #define AF_PPPOX 24 /* PPPoX sockets */ +#define AF_WANPIPE 25 /* Wanpipe API Sockets */ #define AF_MAX 32 /* For now.. */ /* Protocol families, same as address families. */ @@ -184,6 +185,7 @@ #define PF_SNA AF_SNA #define PF_IRDA AF_IRDA #define PF_PPPOX AF_PPPOX +#define PF_WANPIPE AF_WANPIPE #define PF_MAX AF_MAX /* Maximum queue length specifiable by listen. */ @@ -209,6 +211,7 @@ #define MSG_RST 0x1000 #define MSG_ERRQUEUE 0x2000 /* Fetch message from error queue */ #define MSG_NOSIGNAL 0x4000 /* Do not generate SIGPIPE */ +#define MSG_MORE 0x8000 /* Sender will send more */ #define MSG_EOF MSG_FIN diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/som.h linux.ac/include/linux/som.h --- linux.vanilla/include/linux/som.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/linux/som.h Tue Apr 3 17:55:17 2001 @@ -0,0 +1,154 @@ +#ifndef _LINUX_SOM_H +#define _LINUX_SOM_H + +/* File format definition for SOM executables / shared libraries */ + +/* we need struct timespec */ +#include <linux/time.h> + +#define SOM_PAGESIZE 4096 + +/* this is the SOM header */ +struct som_hdr { + short system_id; /* magic number - system */ + short a_magic; /* magic number - file type */ + unsigned int version_id; /* versiod ID: YYMMDDHH */ + struct timespec file_time; /* system clock */ + unsigned int entry_space; /* space for entry point */ + unsigned int entry_subspace; /* subspace for entry point */ + unsigned int entry_offset; /* offset of entry point */ + unsigned int aux_header_location; /* auxiliary header location */ + unsigned int aux_header_size; /* auxiliary header size */ + unsigned int som_length; /* length of entire SOM */ + unsigned int presumed_dp; /* compiler's DP value */ + unsigned int space_location; /* space dictionary location */ + unsigned int space_total; /* number of space entries */ + unsigned int subspace_location; /* subspace entries location */ + unsigned int subspace_total; /* number of subspace entries */ + unsigned int loader_fixup_location; /* MPE/iX loader fixup */ + unsigned int loader_fixup_total; /* number of fixup records */ + unsigned int space_strings_location; /* (sub)space names */ + unsigned int space_strings_size; /* size of strings area */ + unsigned int init_array_location; /* reserved */ + unsigned int init_array_total; /* reserved */ + unsigned int compiler_location; /* module dictionary */ + unsigned int compiler_total; /* number of modules */ + unsigned int symbol_location; /* symbol dictionary */ + unsigned int symbol_total; /* number of symbols */ + unsigned int fixup_request_location; /* fixup requests */ + unsigned int fixup_request_total; /* number of fixup requests */ + unsigned int symbol_strings_location;/* module & symbol names area */ + unsigned int symbol_strings_size; /* size of strings area */ + unsigned int unloadable_sp_location; /* unloadable spaces location */ + unsigned int unloadable_sp_size; /* size of data */ + unsigned int checksum; +}; + +/* values for system_id */ + +#define SOM_SID_PARISC_1_0 0x020b +#define SOM_SID_PARISC_1_1 0x0210 +#define SOM_SID_PARISC_2_0 0x0214 + +/* values for a_magic */ + +#define SOM_LIB_EXEC 0x0104 +#define SOM_RELOCATABLE 0x0106 +#define SOM_EXEC_NONSHARE 0x0107 +#define SOM_EXEC_SHARE 0x0108 +#define SOM_EXEC_DEMAND 0x010B +#define SOM_LIB_DYN 0x010D +#define SOM_LIB_SHARE 0x010E +#define SOM_LIB_RELOC 0x0619 + +/* values for version_id. Decimal not hex, yes. Grr. */ + +#define SOM_ID_OLD 85082112 +#define SOM_ID_NEW 87102412 + +struct aux_id { + unsigned int mandatory :1; /* the linker must understand this */ + unsigned int copy :1; /* Must be copied by the linker */ + unsigned int append :1; /* Must be merged by the linker */ + unsigned int ignore :1; /* Discard section if unknown */ + unsigned int reserved :12; + unsigned int type :16; /* Header type */ + unsigned int length; /* length of _following_ data */ +}; + +/* The Exec Auxiliary Header. Called The HP-UX Header within HP apparently. */ +struct som_exec_auxhdr { + struct aux_id som_auxhdr; + int exec_tsize; /* Text size in bytes */ + int exec_tmem; /* Address to load text at */ + int exec_tfile; /* Location of text in file */ + int exec_dsize; /* Data size in bytes */ + int exec_dmem; /* Address to load data at */ + int exec_dfile; /* Location of data in file */ + int exec_bsize; /* Uninitialised data (bss) */ + int exec_entry; /* Address to start executing */ + int exec_flags; /* loader flags */ + int exec_bfill; /* initialisation value for bss */ +}; + +/* Oh, the things people do to avoid casts. Shame it'll break with gcc's + * new aliasing rules really. + */ +union name_pt { + char * n_name; + unsigned int n_strx; +}; + +/* The Space Dictionary */ +struct space_dictionary_record { + union name_pt name; /* index to subspace name */ + unsigned int is_loadable :1; /* loadable */ + unsigned int is_defined :1; /* defined within file */ + unsigned int is_private :1; /* not sharable */ + unsigned int has_intermediate_code :1; /* contains intermediate code */ + unsigned int is_tspecific :1; /* thread specific */ + unsigned int reserved :11; /* for future expansion */ + unsigned int sort_key :8; /* for linker */ + unsigned int reserved2 :8; /* for future expansion */ + + int space_number; /* index */ + int subspace_index; /* index into subspace dict */ + unsigned int subspace_quantity; /* number of subspaces */ + int loader_fix_index; /* for loader */ + unsigned int loader_fix_quantity; /* for loader */ + int init_pointer_index; /* data pointer array index */ + unsigned int init_pointer_quantity; /* number of data pointers */ +}; + +/* The Subspace Dictionary */ +struct subspace_dictionary_record { + int space_index; + unsigned int access_control_bits :7; + unsigned int memory_resident :1; + unsigned int dup_common :1; + unsigned int is_common :1; + unsigned int quadrant :2; + unsigned int initially_frozen :1; + unsigned int is_first :1; + unsigned int code_only :1; + unsigned int sort_key :8; + unsigned int replicate_init :1; + unsigned int continuation :1; + unsigned int is_tspecific :1; + unsigned int is_comdat :1; + unsigned int reserved :4; + + int file_loc_init_value; + unsigned int initialization_length; + unsigned int subspace_start; + unsigned int subspace_length; + + unsigned int reserved2 :5; + unsigned int alignment :27; + + union name_pt name; + int fixup_request_index; + unsigned int fixup_request_quantity; +}; + +#endif /* _LINUX_SOM_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/spinlock.h linux.ac/include/linux/spinlock.h --- linux.vanilla/include/linux/spinlock.h Thu Feb 22 00:09:57 2001 +++ linux.ac/include/linux/spinlock.h Sat Apr 14 15:05:37 2001 @@ -34,7 +34,8 @@ #ifdef CONFIG_SMP #include <asm/spinlock.h> -#else /* !SMP */ +#elif !defined(spin_lock_init) /* !SMP and spin_lock_init not previously + defined (e.g. by including asm/spinlock.h */ #define DEBUG_SPINLOCKS 0 /* 0 == no debugging, 1 == maintain lock state, 2 == full debug */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/string.h linux.ac/include/linux/string.h --- linux.vanilla/include/linux/string.h Thu Feb 22 00:09:58 2001 +++ linux.ac/include/linux/string.h Fri Apr 13 18:37:31 2001 @@ -1,6 +1,10 @@ #ifndef _LINUX_STRING_H_ #define _LINUX_STRING_H_ +/* We don't want strings.h stuff being user by user stuff by accident */ + +#ifdef __KERNEL__ + #include <linux/types.h> /* for size_t */ #include <linux/stddef.h> /* for NULL */ @@ -80,4 +84,5 @@ } #endif +#endif #endif /* _LINUX_STRING_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/swap.h linux.ac/include/linux/swap.h --- linux.vanilla/include/linux/swap.h Thu Feb 22 00:09:57 2001 +++ linux.ac/include/linux/swap.h Tue Apr 17 17:44:54 2001 @@ -1,6 +1,7 @@ #ifndef _LINUX_SWAP_H #define _LINUX_SWAP_H +#include <linux/pagemap.h> #include <linux/spinlock.h> #include <asm/page.h> @@ -10,11 +11,23 @@ #define MAX_SWAPFILES 8 +/* + * Magic header for a swap area. The first part of the union is + * what the swap magic looks like for the old (limited to 128MB) + * swap area format, the second part of the union adds - in the + * old reserved area - some extra information. Note that the first + * kilobyte is reserved for boot loader or disk label stuff... + * + * Having the magic at the end of the PAGE_SIZE makes detecting swap + * areas somewhat tricky on machines that support multiple page sizes. + * For 2.5 we'll probably want to move the magic to just beyond the + * bootbits... + */ union swap_header { struct { char reserved[PAGE_SIZE - 10]; - char magic[10]; + char magic[10]; /* SWAP-SPACE or SWAPSPACE2 */ } magic; struct { @@ -46,6 +59,9 @@ #define SWAP_MAP_MAX 0x7fff #define SWAP_MAP_BAD 0x8000 +/* + * The in-memory structure used to track swap areas. + */ struct swap_info_struct { unsigned int flags; kdev_t swap_device; @@ -65,7 +81,9 @@ extern int nr_swap_pages; FASTCALL(unsigned int nr_free_pages(void)); +FASTCALL(unsigned int nr_free_pages_zone(int)); FASTCALL(unsigned int nr_inactive_clean_pages(void)); +FASTCALL(unsigned int nr_inactive_clean_pages_zone(int)); FASTCALL(unsigned int nr_free_buffer_pages(void)); extern int nr_active_pages; extern int nr_inactive_dirty_pages; @@ -134,7 +152,6 @@ extern void __delete_from_swap_cache(struct page *page); extern void delete_from_swap_cache(struct page *page); extern void delete_from_swap_cache_nolock(struct page *page); -extern void free_page_and_swap_cache(struct page *page); /* linux/mm/swapfile.c */ extern unsigned int nr_swapfiles; @@ -167,23 +184,6 @@ extern unsigned long swap_cache_find_success; #endif -/* - * Work out if there are any other processes sharing this page, ignoring - * any page reference coming from the swap cache, or from outstanding - * swap IO on this page. (The page cache _does_ count as another valid - * reference to the page, however.) - */ -static inline int is_page_shared(struct page *page) -{ - unsigned int count; - if (PageReserved(page)) - return 1; - count = page_count(page); - if (PageSwapCache(page)) - count += swap_count(page) - 2 - !!page->buffers; - return count > 1; -} - extern spinlock_t pagemap_lru_lock; /* @@ -282,7 +282,7 @@ #endif #define page_ramdisk(page) \ - (page->buffers && (MAJOR(page->buffers->b_dev) == RAMDISK_MAJOR)) + (page->buffers && (MAJOR(page->buffers->b_dev) == RAMDISK_MAJOR) && buffer_protected(page->buffers)) extern spinlock_t swaplock; @@ -292,6 +292,22 @@ #define swap_device_unlock(p) spin_unlock(&p->sdev_lock) extern void shmem_unuse(swp_entry_t entry, struct page *page); + +/* Helper function for TLB shootdown that frees a present pte. + */ +static inline void __free_pte(pte_t pte) +{ + struct page *page = pte_page(pte); + if ((!VALID_PAGE(page)) || PageReserved(page)) + return; + /* + * free_page() used to be able to clear swap cache + * entries. We may now have to do it manually. + */ + if (pte_dirty(pte) && page->mapping) + set_page_dirty(page); + page_cache_release(page); +} #endif /* __KERNEL__*/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/synclink.h linux.ac/include/linux/synclink.h --- linux.vanilla/include/linux/synclink.h Tue Apr 3 17:32:29 2001 +++ linux.ac/include/linux/synclink.h Sun Apr 15 23:11:26 2001 @@ -1,17 +1,17 @@ /* * SyncLink Multiprotocol Serial Adapter Driver * - * $Id: synclink.h,v 3.2 2000/11/06 22:34:38 paul Exp $ + * $Id: synclink.h,v 3.5 2001/03/26 17:04:36 ez Exp $ * * Copyright (C) 1998-2000 by Microgate Corporation * * Redistribution of this file is permitted under - * the terms of the GNU General Public License (GPL) + * the terms of the GNU Public License (GPL) */ #ifndef _SYNCLINK_H_ #define _SYNCLINK_H_ -#define SYNCLINK_H_VERSION 3.2 +#define SYNCLINK_H_VERSION 3.5 #define BOOLEAN int #define TRUE 1 @@ -84,6 +84,11 @@ #define HDLC_CRC_NONE 0 #define HDLC_CRC_16_CCITT 1 #define HDLC_CRC_32_CCITT 2 +#define HDLC_CRC_MASK 0x00ff +#define HDLC_CRC_RETURN_EX 0x8000 + +#define RX_OK 0 +#define RX_CRC_ERROR 1 #define HDLC_TXIDLE_FLAGS 0 #define HDLC_TXIDLE_ALT_ZEROS_ONES 1 @@ -117,6 +122,7 @@ #define MGSL_MODE_ASYNC 1 #define MGSL_MODE_HDLC 2 +#define MGSL_MODE_RAW 6 #define MGSL_BUS_TYPE_ISA 1 #define MGSL_BUS_TYPE_EISA 2 @@ -150,6 +156,8 @@ #define MICROGATE_VENDOR_ID 0x13c0 #define SYNCLINK_DEVICE_ID 0x0010 +#define MGSCC_DEVICE_ID 0x0020 +#define SYNCLINK_SCA_DEVICE_ID 0x0030 #define MGSL_MAX_SERIAL_NUMBER 30 /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/sysctl.h linux.ac/include/linux/sysctl.h --- linux.vanilla/include/linux/sysctl.h Tue Apr 3 17:32:29 2001 +++ linux.ac/include/linux/sysctl.h Sat Apr 14 01:43:58 2001 @@ -117,6 +117,8 @@ KERN_OVERFLOWGID=47, /* int: overflow GID */ KERN_SHMPATH=48, /* string: path to shm fs */ KERN_HOTPLUG=49, /* string: path to hotplug policy agent */ + KERN_IEEE_EMULATION_WARNINGS=50, /* int: unimplemented ieee instructions */ + KERN_S390_USER_DEBUG_LOGGING=51 /* int: dumps of user faults */ }; @@ -132,7 +134,8 @@ VM_PAGECACHE=7, /* struct: Set cache memory thresholds */ VM_PAGERDAEMON=8, /* struct: Control kswapd behaviour */ VM_PGT_CACHE=9, /* struct: Set page table cache parameters */ - VM_PAGE_CLUSTER=10 /* int: set number of pages to swap together */ + VM_PAGE_CLUSTER=10, /* int: set number of pages to swap together */ + VM_MAX_MAP_COUNT=11, /* int: Maximum number of active map areas */ }; @@ -644,43 +647,6 @@ extern ctl_handler sysctl_intvec; extern ctl_handler sysctl_jiffies; - -/* - * Register a set of sysctl names by calling register_sysctl_table - * with an initialised array of ctl_table's. An entry with zero - * ctl_name terminates the table. table->de will be set up by the - * registration and need not be initialised in advance. - * - * sysctl names can be mirrored automatically under /proc/sys. The - * procname supplied controls /proc naming. - * - * The table's mode will be honoured both for sys_sysctl(2) and - * proc-fs access. - * - * Leaf nodes in the sysctl tree will be represented by a single file - * under /proc; non-leaf nodes will be represented by directories. A - * null procname disables /proc mirroring at this node. - * - * sysctl(2) can automatically manage read and write requests through - * the sysctl table. The data and maxlen fields of the ctl_table - * struct enable minimal validation of the values being written to be - * performed, and the mode field allows minimal authentication. - * - * More sophisticated management can be enabled by the provision of a - * strategy routine with the table entry. This will be called before - * any automatic read or write of the data is performed. - * - * The strategy routine may return: - * <0: Error occurred (error is passed to user process) - * 0: OK - proceed with automatic read or write. - * >0: OK - read or write has been done by the strategy routine, so - * return immediately. - * - * There must be a proc_handler routine for any terminal nodes - * mirrored under /proc/sys (non-terminals are handled by a built-in - * directory handler). Several default handlers are available to - * cover common cases. - */ /* A sysctl table is an array of struct ctl_table: */ struct ctl_table diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/sysrq.h linux.ac/include/linux/sysrq.h --- linux.vanilla/include/linux/sysrq.h Thu Feb 22 00:09:57 2001 +++ linux.ac/include/linux/sysrq.h Tue Apr 17 15:46:03 2001 @@ -5,6 +5,10 @@ * Linux Magic System Request Key Hacks * * (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz> + * + * (c) 2000 Crutcher Dunnavant <crutcher@redhat.com> + * overhauled to use key registration + * based upon discusions in irc://irc.openprojects.net/#kernelnewbies */ #include <linux/config.h> @@ -13,12 +17,71 @@ struct kbd_struct; struct tty_struct; +struct sysrq_key_op { + void (*handler)(int, struct pt_regs *, + struct kbd_struct *, struct tty_struct *); + char *help_msg; + char *action_msg; +}; + /* Generic SysRq interface -- you may call it from any device driver, supplying * ASCII code of the key, pointer to registers and kbd/tty structs (if they * are available -- else NULL's). */ -void handle_sysrq(int, struct pt_regs *, struct kbd_struct *, struct tty_struct *); +void handle_sysrq(int, struct pt_regs *, + struct kbd_struct *, struct tty_struct *); + + +/* + * Nonlocking version of handle sysrq, used by sysrq handlers that need to + * call sysrq handlers + */ + +void __handle_sysrq_nolock(int, struct pt_regs *, + struct kbd_struct *, struct tty_struct *); + +/* + * Sysrq registration manipulation functions + */ + +void __sysrq_lock_table (void); +void __sysrq_unlock_table (void); +struct sysrq_key_op *__sysrq_get_key_op (int key); +void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p); + +extern __inline__ int +__sysrq_swap_key_ops_nolock(int key, struct sysrq_key_op *insert_op_p, + struct sysrq_key_op *remove_op_p) { + int retval; + if (__sysrq_get_key_op(key) == remove_op_p) { + __sysrq_put_key_op(key, insert_op_p); + retval = 0; + } else { + retval = -1; + } + return retval; +} + +extern __inline__ int +__sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p, + struct sysrq_key_op *remove_op_p) { + int retval; + __sysrq_lock_table(); + retval = __sysrq_swap_key_ops_nolock(key, insert_op_p, remove_op_p); + __sysrq_unlock_table(); + return retval; +} + +static inline int register_sysrq_key(int key, struct sysrq_key_op *op_p) +{ + return __sysrq_swap_key_ops(key, op_p, NULL); +} + +static inline int unregister_sysrq_key(int key, struct sysrq_key_op *op_p) +{ + return __sysrq_swap_key_ops(key, NULL, op_p); +} /* Deferred actions */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/tcp.h linux.ac/include/linux/tcp.h --- linux.vanilla/include/linux/tcp.h Thu Feb 22 00:09:57 2001 +++ linux.ac/include/linux/tcp.h Sat Apr 14 01:43:58 2001 @@ -126,6 +126,7 @@ #define TCP_DEFER_ACCEPT 9 /* Wake up listener only when data arrive */ #define TCP_WINDOW_CLAMP 10 /* Bound advertised window */ #define TCP_INFO 11 /* Information about this connection. */ +#define TCP_QUICKACK 12 /* Block/reenable quick acks */ #define TCPI_OPT_TIMESTAMPS 1 #define TCPI_OPT_SACK 2 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/timer.h linux.ac/include/linux/timer.h --- linux.vanilla/include/linux/timer.h Thu Feb 22 00:09:56 2001 +++ linux.ac/include/linux/timer.h Tue Apr 3 18:11:11 2001 @@ -5,17 +5,13 @@ #include <linux/list.h> /* - * This is completely separate from the above, and is the - * "new and improved" way of handling timers more dynamically. - * Hopefully efficient and general enough for most things. + * In Linux 2.4, static timers have been removed from the kernel. + * Timers may be dynamically created and destroyed, and should be initialized + * by a call to init_timer() upon creation. * - * The "hardcoded" timers above are still useful for well- - * defined problems, but the timer-list is probably better - * when you need multiple outstanding timers or similar. - * - * The "data" field is in case you want to use the same - * timeout function for several timeouts. You can use this - * to distinguish between the different invocations. + * The "data" field enables use of a common timeout function for several + * timeouts. You can use this field to distinguish between the different + * invocations. */ struct timer_list { struct list_head list; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/timex.h linux.ac/include/linux/timex.h --- linux.vanilla/include/linux/timex.h Thu Feb 22 00:09:57 2001 +++ linux.ac/include/linux/timex.h Sat Apr 14 20:38:32 2001 @@ -60,7 +60,9 @@ * OSF/1 kernel. The SHIFT_HZ define expresses the same value as the * nearest power of two in order to avoid hardware multiply operations. */ -#if HZ >= 24 && HZ < 48 +#if HZ >= 12 && HZ < 24 +# define SHIFT_HZ 4 +#elif HZ >= 24 && HZ < 48 # define SHIFT_HZ 5 #elif HZ >= 48 && HZ < 96 # define SHIFT_HZ 6 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/tlb.h linux.ac/include/linux/tlb.h --- linux.vanilla/include/linux/tlb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/linux/tlb.h Tue Apr 3 17:55:17 2001 @@ -0,0 +1 @@ +#include <asm-generic/tlb.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/tpqic02.h linux.ac/include/linux/tpqic02.h --- linux.vanilla/include/linux/tpqic02.h Thu Feb 22 00:11:45 2001 +++ linux.ac/include/linux/tpqic02.h Sat Apr 14 01:44:04 2001 @@ -588,7 +588,7 @@ */ #define TP_REWCLOSE(d) ((MINOR(d)&0x01) == 1) /* rewind bit */ - /* rewind is only done if data has been transfered */ + /* rewind is only done if data has been transferred */ #define TP_DENS(dev) ((MINOR(dev) >> 1) & 0x07) /* tape density */ #define TP_UNIT(dev) ((MINOR(dev) >> 4) & 0x07) /* unit number */ @@ -633,8 +633,8 @@ #define EXC_WP 3 /* Write protected */ #define EXC_EOM 4 /* EOM */ #define EXC_RWA 5 /* read/write abort */ -#define EXC_XBAD 6 /* read error, bad block transfered */ -#define EXC_XFILLER 7 /* read error, filler block transfered */ +#define EXC_XBAD 6 /* read error, bad block transferred */ +#define EXC_XFILLER 7 /* read error, filler block transferred */ #define EXC_NDT 8 /* read error, no data */ #define EXC_NDTEOM 9 /* read error, no data & EOM */ #define EXC_NDTBOM 10 /* read error, no data & BOM */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/tty.h linux.ac/include/linux/tty.h --- linux.vanilla/include/linux/tty.h Tue Apr 3 17:32:29 2001 +++ linux.ac/include/linux/tty.h Sun Apr 15 23:20:10 2001 @@ -366,6 +366,7 @@ extern int specialix_init(void); extern int espserial_init(void); extern int macserial_init(void); +extern int stdio_init(void); extern int tty_paranoia_check(struct tty_struct *tty, kdev_t device, const char *routine); @@ -419,6 +420,8 @@ extern int vt_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg); + +extern void stdio_console_init(void); #endif /* __KERNEL__ */ #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/tty_ldisc.h linux.ac/include/linux/tty_ldisc.h --- linux.vanilla/include/linux/tty_ldisc.h Thu Feb 22 00:09:58 2001 +++ linux.ac/include/linux/tty_ldisc.h Sun Apr 15 23:20:10 2001 @@ -2,22 +2,22 @@ #define _LINUX_TTY_LDISC_H /* - * This structure defines the interface between the tty line discpline + * This structure defines the interface between the tty line discipline * implementation and the tty routines. The following routines can be * defined; unless noted otherwise, they are optional, and can be * filled in with a null pointer. * * int (*open)(struct tty_struct *); * - * This function is called when the line discpline is associated - * with the tty. The line discpline can use this as an + * This function is called when the line discipline is associated + * with the tty. The line discipline can use this as an * opportunity to initialize any state needed by the ldisc routines. * * void (*close)(struct tty_struct *); * - * This function is called when the line discpline is being + * This function is called when the line discipline is being * shutdown, either because the tty is being closed or because - * the tty is being changed to use a new line discpline + * the tty is being changed to use a new line discipline * * void (*flush_buffer)(struct tty_struct *tty); * @@ -28,14 +28,14 @@ * ssize_t (*chars_in_buffer)(struct tty_struct *tty); * * This function returns the number of input characters the line - * iscpline may have queued up to be delivered to the user mode + * discipline may have queued up to be delivered to the user mode * process. * * ssize_t (*read)(struct tty_struct * tty, struct file * file, * unsigned char * buf, size_t nr); * * This function is called when the user requests to read from - * the tty. The line discpline will return whatever characters + * the tty. The line discipline will return whatever characters * it has buffered up for the user. If this function is not * defined, the user will receive an EIO error. * @@ -43,7 +43,7 @@ * const unsigned char * buf, size_t nr); * * This function is called when the user requests to write to the - * tty. The line discpline will deliver the characters to the + * tty. The line discipline will deliver the characters to the * low-level tty device for transmission, optionally performing * some processing on the characters first. If this function is * not defined, the user will receive an EIO error. @@ -54,7 +54,7 @@ * This function is called when the user requests an ioctl which * is not handled by the tty layer or the low-level tty driver. * It is intended for ioctls which affect line discpline - * operation. Not that the search order for ioctls is (1) tty + * operation. Note that the search order for ioctls is (1) tty * layer, (2) tty low-level driver, (3) line discpline. So a * low-level driver can "grab" an ioctl request before the line * discpline has a chance to see it. @@ -62,7 +62,7 @@ * void (*set_termios)(struct tty_struct *tty, struct termios * old); * * This function notifies the line discpline that a change has - * been made to the termios stucture. + * been made to the termios structure. * * int (*poll)(struct tty_struct * tty, struct file * file, * poll_table *wait); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/usb.h linux.ac/include/linux/usb.h --- linux.vanilla/include/linux/usb.h Tue Apr 3 17:32:29 2001 +++ linux.ac/include/linux/usb.h Sun Apr 15 23:38:08 2001 @@ -585,11 +585,23 @@ struct list_head inodes; }; -#define USB_MAXCHILDREN (16) /* This is arbitrary */ +/* This is arbitrary. + * From USB 2.0 spec Table 11-13, offset 7, a hub can + * have up to 255 ports. The most yet reported is 10. + */ +#define USB_MAXCHILDREN (16) struct usb_device { int devnum; /* Device number on USB bus */ - int slow; /* Slow device? */ + + enum { + USB_SPEED_UNKNOWN = 0, /* enumerating */ + USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */ + USB_SPEED_HIGH /* usb 2.0 */ + } speed; + + struct usb_device *tt; /* usb1.1 device on usb2.0 bus */ + int ttport; /* device/hub port on that tt */ atomic_t refcnt; /* Reference count */ @@ -699,6 +711,9 @@ * up to us. This one happens to share a lot of bit positions with the UHCI * specification, so that much of the uhci driver can just mask the bits * appropriately. + * + * NOTE: there's no encoding (yet?) for a "high speed" endpoint; treat them + * like like full speed devices. */ #define PIPE_ISOCHRONOUS 0 @@ -739,12 +754,13 @@ static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint) { - return (dev->devnum << 8) | (endpoint << 15) | (dev->slow << 26); + return (dev->devnum << 8) | (endpoint << 15) | + ((dev->speed == USB_SPEED_LOW) << 26); } static inline unsigned int __default_pipe(struct usb_device *dev) { - return (dev->slow << 26); + return ((dev->speed == USB_SPEED_LOW) << 26); } /* Create various pipes... */ @@ -835,6 +851,7 @@ extern struct list_head usb_driver_list; extern struct list_head usb_bus_list; +extern rwlock_t usb_bus_list_lock; /* * USB device fs stuff diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/videodev.h linux.ac/include/linux/videodev.h --- linux.vanilla/include/linux/videodev.h Tue Apr 3 17:32:29 2001 +++ linux.ac/include/linux/videodev.h Tue Apr 17 18:11:01 2001 @@ -373,6 +373,8 @@ #define VID_HARDWARE_ZR36067 26 /* Zoran ZR36067/36060 */ #define VID_HARDWARE_OV511 27 #define VID_HARDWARE_ZR356700 28 /* Zoran 36700 series */ +#define VID_HARDWARE_W9966 29 + /* * Initialiser list diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/vmalloc.h linux.ac/include/linux/vmalloc.h --- linux.vanilla/include/linux/vmalloc.h Thu Feb 22 00:09:58 2001 +++ linux.ac/include/linux/vmalloc.h Tue Apr 17 17:44:38 2001 @@ -4,6 +4,7 @@ #include <linux/sched.h> #include <linux/mm.h> #include <linux/spinlock.h> +#include <linux/highmem.h> #include <asm/pgtable.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/wait.h linux.ac/include/linux/wait.h --- linux.vanilla/include/linux/wait.h Thu Feb 22 00:09:57 2001 +++ linux.ac/include/linux/wait.h Sat Apr 14 15:05:37 2001 @@ -14,6 +14,7 @@ #include <linux/list.h> #include <linux/stddef.h> #include <linux/spinlock.h> +#include <linux/config.h> #include <asm/page.h> #include <asm/processor.h> @@ -21,11 +22,23 @@ /* * Debug control. Slow but useful. */ +#if defined(CONFIG_DEBUG_WAITQ) +#define WAITQUEUE_DEBUG 1 +#else #define WAITQUEUE_DEBUG 0 +#endif struct __wait_queue { unsigned int flags; #define WQ_FLAG_EXCLUSIVE 0x01 +#define WQ_FLAG_CONTEXT_0 8 /* context specific flag bit numbers */ +#define WQ_FLAG_CONTEXT_1 9 +#define WQ_FLAG_CONTEXT_2 10 +#define WQ_FLAG_CONTEXT_3 11 +#define WQ_FLAG_CONTEXT_4 12 +#define WQ_FLAG_CONTEXT_5 13 +#define WQ_FLAG_CONTEXT_6 14 +#define WQ_FLAG_CONTEXT_7 15 struct task_struct * task; struct list_head task_list; #if WAITQUEUE_DEBUG diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/wanpipe.h linux.ac/include/linux/wanpipe.h --- linux.vanilla/include/linux/wanpipe.h Mon Dec 11 21:00:10 2000 +++ linux.ac/include/linux/wanpipe.h Tue Apr 17 18:31:34 2001 @@ -5,13 +5,17 @@ * Author: Nenad Corbic <ncorbic@sangoma.com> * Gideon Hack * -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* Copyright: (c) 1995-2000 Sangoma Technologies Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Nov 3, 2000 Nenad Corbic Added config_id to sdla_t structure. +* Used to determine the protocol running. +* Jul 13, 2000 Nenad Corbic Added SyncPPP Support +* Feb 24, 2000 Nenad Corbic Added support for x25api driver * Oct 04, 1999 Nenad Corbic New CHDLC and FRAME RELAY code, SMP support * Jun 02, 1999 Gideon Hack Added 'update_call_count' for Cisco HDLC * support @@ -35,10 +39,58 @@ #ifndef _WANPIPE_H #define _WANPIPE_H -#include <linux/config.h> +#include <linux/version.h> -#ifdef CONFIG_SMP -#include <asm/spinlock.h> /* Support for SMP Locking */ +#ifndef KERNEL_VERSION + #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + + #define LINUX_2_4 + #define netdevice_t struct net_device + + #define FREE_READ 1 + #define FREE_WRITE 0 + + #define stop_net_queue(a) netif_stop_queue(a) + #define start_net_queue(a) netif_start_queue(a) + #define is_queue_stopped(a) netif_queue_stopped(a) + #define wake_net_dev(a) netif_wake_queue(a) + #define is_dev_running(a) netif_running(a) + #define wan_dev_kfree_skb(a,b) dev_kfree_skb_any(a) + + +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) + + #define LINUX_2_1 + #define netdevice_t struct device + #define FREE_READ 1 + #define FREE_WRITE 0 + + #define stop_net_queue(a) (set_bit(0, &##a->tbusy)) + #define start_net_queue(a) (clear_bit(0,&##a->tbusy)) + #define is_queue_stopped(a) (##a->tbusy) + #define wake_net_dev(a) {clear_bit(0,&##a->tbusy);mark_bh(NET_BH);} + #define is_dev_running(a) (test_bit(0,&##a->start)) + #define wan_dev_kfree_skb(a,b) dev_kfree_skb(a) + +#else + #define LINUX_2_0 + #define netdevice_t struct device + + #define test_and_set_bit set_bit + #define net_ratelimit() 1 + + #define stop_net_queue(a) (set_bit(0, &##a->tbusy)) + #define start_net_queue(a) (clear_bit(0,&##a->tbusy)) + #define is_queue_stopped(a) (##a->tbusy) + #define wake_net_dev(a) {clear_bit(0,&##a->tbusy);mark_bh(NET_BH);} + #define is_dev_running(a) (test_bit(0,(void*)&##a->start)) + #define wan_dev_kfree_skb(a,b) dev_kfree_skb(a,b) + #define spin_lock_init(a) + #define spin_lock(a) + #define spin_unlock(a) #endif #include <linux/wanrouter.h> @@ -49,7 +101,7 @@ #define PACKED __attribute__((packed)) #endif -#define WANPIPE_MAGIC 0x414C4453L /* signatire: 'SDLA' reversed */ +#define WANPIPE_MAGIC 0x414C4453L /* signature: 'SDLA' reversed */ /* IOCTL numbers (up to 16) */ #define WANPIPE_DUMP (ROUTER_USER+0) /* dump adapter's memory */ @@ -64,6 +116,51 @@ #define UDPMGMT_REPLY 0x02 #define UDP_OFFSET 12 +#define MAX_CMD_BUFF 10 +#define MAX_X25_LCN 255 /* Maximum number of x25 channels */ +#define MAX_LCN_NUM 4095 /* Maximum lcn number */ +#define MAX_FT1_RETRY 100 + +#ifdef LINUX_2_4 + #ifndef AF_WANPIPE + #define AF_WANPIPE 25 + #ifndef PF_WANPIPE + #define PF_WANPIPE AF_WANPIPE + #endif + #endif + +#else + #ifndef AF_WANPIPE + #define AF_WANPIPE 24 + #ifndef PF_WANPIPE + #define PF_WANPIPE AF_WANPIPE + #endif + #endif +#endif + + +#define TX_TIMEOUT 5*HZ + +/* General Critical Flags */ +#define SEND_CRIT 0x00 +#define PERI_CRIT 0x01 + +/* Chdlc and PPP polling critical flag */ +#define POLL_CRIT 0x03 + +/* Frame Relay Tx IRQ send critical flag */ +#define SEND_TXIRQ_CRIT 0x02 + +/* Frame Relay ARP critical flag */ +#define ARP_CRIT 0x03 + +/* Bit maps for dynamic interface configuration + * DYN_OPT_ON : turns this option on/off + * DEV_DOWN : device was shutdown by the driver not + * by user + */ +#define DYN_OPT_ON 0x00 +#define DEV_DOWN 0x01 /* * Data structures for IOCTL calls. @@ -197,6 +294,9 @@ } pipe_mgmt_stat_t; +typedef struct { + struct sk_buff *skb; +} bh_data_t, cmd_data_t; #define MAX_LGTH_UDP_MGNT_PKT 2000 @@ -210,11 +310,27 @@ #define WUM_KILL 0x50 #define WUM_EXEC 0x51 +#define WANPIPE 0x00 +#define API 0x01 +#define BRIDGE 0x02 +#define BRIDGE_NODE 0x03 + #ifdef __KERNEL__ /****** Kernel Interface ****************************************************/ #include <linux/sdladrv.h> /* SDLA support module API definitions */ #include <linux/sdlasfm.h> /* SDLA firmware module definitions */ +#include <linux/tqueue.h> +#ifdef LINUX_2_4 + #include <linux/serial.h> + #include <linux/serialP.h> + #include <linux/serial_reg.h> + #include <asm/serial.h> +#endif +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> + #ifndef min #define min(a,b) (((a)<(b))?(a):(b)) @@ -230,6 +346,7 @@ ((ch)>=(unsigned)'a'&&(ch)<=(unsigned)'f')||\ ((ch)>=(unsigned)'A'&&(ch)<=(unsigned)'F'))?1:0) + /****** Data Structures *****************************************************/ /* Adapter Data Space. @@ -241,6 +358,7 @@ char devname[WAN_DRVNAME_SZ+1]; /* card name */ sdlahw_t hw; /* hardware configuration */ wan_device_t wandev; /* WAN device data space */ + unsigned open_cnt; /* number of open interfaces */ unsigned long state_tick; /* link state timestamp */ unsigned intr_mode; /* Type of Interrupt Mode */ @@ -248,30 +366,71 @@ char buff_int_mode_unbusy; /* flag for carrying out dev_tint */ char dlci_int_mode_unbusy; /* flag for carrying out dev_tint */ char configured; /* flag for previous configurations */ + unsigned short irq_dis_if_send_count; /* Disabling irqs in if_send*/ unsigned short irq_dis_poll_count; /* Disabling irqs in poll routine*/ unsigned short force_enable_irq; char TracingEnabled; /* flag for enabling trace */ global_stats_t statistics; /* global statistics */ -#ifdef CONFIG_SMP - spinlock_t lock; /* Support for SMP Locking */ -#endif void* mbox; /* -> mailbox */ void* rxmb; /* -> receive mailbox */ void* flags; /* -> adapter status flags */ void (*isr)(struct sdla* card); /* interrupt service routine */ void (*poll)(struct sdla* card); /* polling routine */ int (*exec)(struct sdla* card, void* u_cmd, void* u_data); - - struct sdla *next; /* Secondary Port Device: Piggibacking */ + /* Used by the listen() system call */ + /* Wanpipe Socket Interface */ + int (*func) (struct sk_buff *, struct sock *); + struct sock *sk; + + /* Shutdown function */ + void (*disable_comm) (struct sdla *card); + + /* Secondary Port Device: Piggibacking */ + struct sdla *next; + + /* TTY driver variables */ + unsigned char tty_opt; + struct tty_struct *tty; + unsigned int tty_minor; + unsigned int tty_open; + unsigned char *tty_buf; + unsigned char *tty_rx; + struct tq_struct tty_task_queue; + union { struct { /****** X.25 specific data **********/ - unsigned lo_pvc; - unsigned hi_pvc; - unsigned lo_svc; - unsigned hi_svc; + u32 lo_pvc; + u32 hi_pvc; + u32 lo_svc; + u32 hi_svc; + netdevice_t *svc_to_dev_map[MAX_X25_LCN]; + netdevice_t *pvc_to_dev_map[MAX_X25_LCN]; + netdevice_t *tx_dev; + netdevice_t *cmd_dev; + u32 no_dev; + volatile u8 *hdlc_buf_status; + u32 tx_interrupts_pending; + u16 timer_int_enabled; + netdevice_t *poll_device; + atomic_t command_busy; + + u16 udp_pkt_lgth; + u32 udp_type; + u8 udp_pkt_src; + u32 udp_lcn; + netdevice_t * udp_dev; + s8 udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; + + u8 LAPB_hdlc; /* Option to turn off X25 and run only LAPB */ + u8 logging; /* Option to log call messages */ + u8 oob_on_modem; /* Option to send modem status to the api */ + u16 num_of_ch; /* Number of channels configured by the user */ + + struct tq_struct x25_poll_task; + struct timer_list x25_timer; } x; struct { /****** frame relay specific data ***/ @@ -281,7 +440,7 @@ unsigned rx_top; /* S508 receive buffer end */ unsigned short node_dlci[100]; unsigned short dlci_num; - struct net_device *dlci_to_dev_map[991 + 1]; + netdevice_t *dlci_to_dev_map[991 + 1]; unsigned tx_interrupts_pending; unsigned short timer_int_enabled; unsigned short udp_pkt_lgth; @@ -289,11 +448,13 @@ char udp_pkt_src; unsigned udp_dlci; char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; - void* trc_el_base; /* first trace element */ - void* trc_el_last; /* last trace element */ - void *curr_trc_el; /* current trace element */ - unsigned short trc_bfr_space; /* trace buffer space */ + void* trc_el_base; /* first trace element */ + void* trc_el_last; /* last trace element */ + void *curr_trc_el; /* current trace element */ + unsigned short trc_bfr_space; /* trace buffer space */ unsigned char update_comms_stats; + netdevice_t *arp_dev; + spinlock_t if_send_lock; } f; struct /****** PPP-specific data ***********/ { @@ -307,6 +468,10 @@ unsigned rx_top; /* S508 receive buffer end */ char ip_mode; /* STATIC/HOST/PEER IP Mode */ char authenticator; /* Authenticator for PAP/CHAP */ + unsigned char comm_enabled; /* Is comm enabled or not */ + unsigned char peer_route; /* Process Peer Route */ + unsigned long *txbuf_next; /* Next Tx buffer to use */ + unsigned long *rxbuf_next; /* Next Rx buffer to use */ } p; struct /* Cisco HDLC-specific data */ { @@ -324,6 +489,7 @@ void* rxbuf_last; /* -> last Rx buffer */ unsigned rx_base; /* S508 receive buffer base */ unsigned rx_top; /* S508 receive buffer end */ + unsigned char receive_only; /* high speed receivers */ unsigned short protocol_options; unsigned short kpalv_tx; /* Tx kpalv timer */ unsigned short kpalv_rx; /* Rx kpalv timer */ @@ -332,6 +498,19 @@ unsigned state; /* state of the link */ unsigned char api_status; unsigned char update_call_count; + unsigned short api_options; /* for async config */ + unsigned char async_mode; + unsigned short tx_bits_per_char; + unsigned short rx_bits_per_char; + unsigned short stop_bits; + unsigned short parity; + unsigned short break_timer; + unsigned short inter_char_timer; + unsigned short rx_complete_length; + unsigned short xon_char; + unsigned short xoff_char; + unsigned char comm_enabled; /* Is comm enabled or not */ + unsigned char backup; } c; struct { @@ -368,6 +547,18 @@ int bsc_init (sdla_t* card, wandev_conf_t* conf); /* BSC streaming */ int hdlc_init(sdla_t* card, wandev_conf_t* conf); /* HDLC support */ int wpft1_init (sdla_t* card, wandev_conf_t* conf); /* FT1 Config support */ +int wsppp_init (sdla_t* card, wandev_conf_t* conf); /* Sync PPP on top of RAW CHDLC */ + +extern sdla_t * wanpipe_find_card(char *); +extern sdla_t * wanpipe_find_card_num (int); + +extern void wanpipe_queue_tq (struct tq_struct *); +extern void wanpipe_mark_bh (void); +extern void wakeup_sk_bh (netdevice_t *); +extern int change_dev_flags (netdevice_t *, unsigned); +extern unsigned long get_ip_address (netdevice_t *dev, int option); +extern void add_gateway(sdla_t *, netdevice_t *); + #endif /* __KERNEL__ */ #endif /* _WANPIPE_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/wanrouter.h linux.ac/include/linux/wanrouter.h --- linux.vanilla/include/linux/wanrouter.h Thu Feb 22 00:11:55 2001 +++ linux.ac/include/linux/wanrouter.h Tue Apr 17 17:55:16 2001 @@ -5,15 +5,18 @@ * * Author: Nenad Corbic <ncorbic@sangoma.com> * Gideon Hack -* Additions: Arnaldo Carvalho de Melo <acme@conectiva.com.br> +* Additions: Arnaldo Melo * -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* Copyright: (c) 1995-2000 Sangoma Technologies Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Jul 21, 2000 Nenad Corbic Added WAN_FT1_READY State +* Feb 24, 2000 Nenad Corbic Added support for socket based x25api +* Jan 28, 2000 Nenad Corbic Added support for the ASYNC protocol. * Oct 04, 1999 Nenad Corbic Updated for 2.1.0 release * Jun 02, 1999 Gideon Hack Added support for the S514 adapter. * May 23, 1999 Arnaldo Melo Added local_addr to wanif_conf_t @@ -42,8 +45,24 @@ *****************************************************************************/ #include <linux/version.h> -#if LINUX_VERSION_CODE >= 0x020100 -#define LINUX_2_1 +#ifndef KERNEL_VERSION + #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + #define LINUX_2_4 + #define netdevice_t struct net_device + #include <linux/spinlock.h> /* Support for SMP Locking */ + +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) + #define LINUX_2_1 + #define netdevice_t struct device + #include <asm/spinlock.h> /* Support for SMP Locking */ + +#else + #define LINUX_2_0 + #define netdevice_t struct device + #define spinlock_t int #endif #ifndef _ROUTER_H @@ -135,6 +154,10 @@ unsigned r12_r22; /* RESET retransmission limit (0..250) */ unsigned r13_r23; /* CLEAR retransmission limit (0..250) */ unsigned ccitt_compat; /* compatibility mode: 1988/1984/1980 */ + unsigned x25_conf_opt; /* User defined x25 config optoins */ + unsigned char LAPB_hdlc_only; /* Run in HDLC only mode */ + unsigned char logging; /* Control connection logging */ + unsigned char oob_on_modem; /* Whether to send modem status to the user app */ } wan_x25_conf_t; /*---------------------------------------------------------------------------- @@ -182,6 +205,7 @@ unsigned char ignore_cts; /* Ignore these to determine */ unsigned char ignore_keepalive; /* link status (Yes or No) */ unsigned char hdlc_streaming; /* hdlc_streaming mode (Y/N) */ + unsigned char receive_only; /* no transmit buffering (Y/N) */ unsigned keepalive_tx_tmr; /* transmit keepalive timer */ unsigned keepalive_rx_tmr; /* receive keepalive timer */ unsigned keepalive_err_margin; /* keepalive_error_tolerance */ @@ -204,6 +228,7 @@ int dma; /* DMA request level */ char S514_CPU_no[1]; /* S514 PCI adapter CPU number ('A' or 'B') */ unsigned PCI_slot_no; /* S514 PCI adapter slot number */ + char auto_pci_cfg; /* S515 PCI automatic slot detection */ char comm_port; /* Communication Port (PRI=0, SEC=1) */ unsigned bps; /* data transfer rate */ unsigned mtu; /* maximum transmit unit size */ @@ -216,6 +241,12 @@ char station; /* DTE/DCE, primary/secondary, etc. */ char connection; /* permanent/switched/on-demand */ char read_mode; /* read mode: Polling or interrupt */ + char receive_only; /* disable tx buffers */ + char tty; /* Create a fake tty device */ + unsigned tty_major; /* Major number for wanpipe tty device */ + unsigned tty_minor; /* Minor number for wanpipe tty device */ + unsigned tty_mode; /* TTY operation mode SYNC or ASYNC */ + char backup; /* Backup Mode */ unsigned hw_opt[4]; /* other hardware options */ unsigned reserved[4]; /****** arbitrary data ***************/ @@ -237,6 +268,7 @@ #define WANCONFIG_CHDLC 104 /* Cisco HDLC Link */ #define WANCONFIG_BSC 105 /* BiSync Streaming */ #define WANCONFIG_HDLC 106 /* HDLC Support */ +#define WANCONFIG_MPPP 107 /* Multi Port PPP over RAW CHDLC */ /* * Configuration options defines. @@ -288,6 +320,15 @@ #define WANOPT_PPP_HOST 1 #define WANOPT_PPP_PEER 2 +/* ASY Mode Options */ +#define WANOPT_ONE 1 +#define WANOPT_TWO 2 +#define WANOPT_ONE_AND_HALF 3 + +#define WANOPT_NONE 0 +#define WANOPT_ODD 1 +#define WANOPT_EVEN 2 + /* CHDLC Protocol Options */ /* DF Commmented out for now. @@ -303,6 +344,9 @@ #define WANOPT_INTR 0 #define WANOPT_POLL 1 + +#define WANOPT_TTY_SYNC 0 +#define WANOPT_TTY_ASYNC 1 /*---------------------------------------------------------------------------- * WAN Link Status Info (for ROUTER_STAT IOCTL). */ @@ -345,7 +389,15 @@ WAN_CONNECTED, /* link/channel is operational */ WAN_LIMIT, /* for verification only */ WAN_DUALPORT, /* for Dual Port cards */ - WAN_DISCONNECTING /* link/channel is disconnecting */ + WAN_DISCONNECTING, + WAN_FT1_READY /* FT1 Configurator Ready */ +}; + +enum { + WAN_LOCAL_IP, + WAN_POINTOPOINT_IP, + WAN_NETMASK_IP, + WAN_BROADCAST_IP }; /* 'modem_status' masks */ @@ -395,6 +447,27 @@ char clocking; /* external/internal */ unsigned bps; /* data transfer rate */ unsigned mtu; /* maximum transmit unit size */ + unsigned char if_down; /* brind down interface when disconnected */ + unsigned char gateway; /* Is this interface a gateway */ + unsigned char true_if_encoding; /* Set the dev->type to true board protocol */ + + unsigned char asy_data_trans; /* async API options */ + unsigned char rts_hs_for_receive; /* async Protocol options */ + unsigned char xon_xoff_hs_for_receive; + unsigned char xon_xoff_hs_for_transmit; + unsigned char dcd_hs_for_transmit; + unsigned char cts_hs_for_transmit; + unsigned char async_mode; + unsigned tx_bits_per_char; + unsigned rx_bits_per_char; + unsigned stop_bits; + unsigned char parity; + unsigned break_timer; + unsigned inter_char_timer; + unsigned rx_complete_length; + unsigned xon_char; + unsigned xoff_char; + unsigned char receive_only; /* no transmit buffering (Y/N) */ } wanif_conf_t; #ifdef __KERNEL__ @@ -440,30 +513,40 @@ /****** status and statistics *******/ char state; /* device state */ char api_status; /* device api status */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) struct net_device_stats stats; /* interface statistics */ +#else + struct enet_statistics stats; /* interface statistics */ +#endif unsigned reserved[16]; /* reserved for future use */ unsigned long critical; /* critical section flag */ + spinlock_t lock; /* Support for SMP Locking */ + /****** device management methods ***/ int (*setup) (struct wan_device *wandev, wandev_conf_t *conf); int (*shutdown) (struct wan_device *wandev); int (*update) (struct wan_device *wandev); int (*ioctl) (struct wan_device *wandev, unsigned cmd, unsigned long arg); - int (*new_if) (struct wan_device *wandev, struct net_device *dev, + int (*new_if) (struct wan_device *wandev, netdevice_t *dev, wanif_conf_t *conf); - int (*del_if) (struct wan_device *wandev, struct net_device *dev); + int (*del_if) (struct wan_device *wandev, netdevice_t *dev); /****** maintained by the router ****/ struct wan_device* next; /* -> next device */ - struct net_device* dev; /* list of network interfaces */ + netdevice_t* dev; /* list of network interfaces */ unsigned ndev; /* number of interfaces */ +#ifdef LINUX_2_4 struct proc_dir_entry *dent; /* proc filesystem entry */ +#else + struct proc_dir_entry dent; /* proc filesystem entry */ +#endif } wan_device_t; /* Public functions available for device drivers */ extern int register_wan_device(wan_device_t *wandev); extern int unregister_wan_device(char *name); -unsigned short wanrouter_type_trans(struct sk_buff *skb, struct net_device *dev); -int wanrouter_encapsulate(struct sk_buff *skb, struct net_device *dev); +unsigned short wanrouter_type_trans(struct sk_buff *skb, netdevice_t *dev); +int wanrouter_encapsulate(struct sk_buff *skb, netdevice_t *dev,unsigned short type); /* Proc interface functions. These must not be called by the drivers! */ extern int wanrouter_proc_init(void); @@ -471,6 +554,11 @@ extern int wanrouter_proc_add(wan_device_t *wandev); extern int wanrouter_proc_delete(wan_device_t *wandev); extern int wanrouter_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); + +extern void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags); +extern void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags); + + /* Public Data */ extern wan_device_t *router_devlist; /* list of registered devices */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/wavefront.h linux.ac/include/linux/wavefront.h --- linux.vanilla/include/linux/wavefront.h Mon Jan 4 19:42:43 1999 +++ linux.ac/include/linux/wavefront.h Sat Apr 14 01:44:23 2001 @@ -31,7 +31,7 @@ member, which has the same semantics anyway. */ -#endif __GNUC__ +#endif /* __GNUC__ */ /***************************** WARNING ******************************** PLEASE DO NOT MODIFY THIS FILE IN ANY WAY THAT AFFECTS ITS ABILITY TO @@ -40,11 +40,11 @@ #ifndef NUM_MIDIKEYS #define NUM_MIDIKEYS 128 -#endif NUM_MIDIKEYS +#endif /* NUM_MIDIKEYS */ #ifndef NUM_MIDICHANNELS #define NUM_MIDICHANNELS 16 -#endif NUM_MIDICHANNELS +#endif /* NUM_MIDICHANNELS */ /* These are very useful/important. the original wavefront interface was developed on a 16 bit system, where sizeof(int) = 2 @@ -667,9 +667,9 @@ /* Allow direct user-space control over FX memory/coefficient data. In theory this could be used to download the FX microprogram, - but it would be a little slower, and involve some wierd code. + but it would be a little slower, and involve some weird code. */ #define WFFX_MEMSET 69 -#endif __wavefront_h__ +#endif /* __wavefront_h__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/wireless.h linux.ac/include/linux/wireless.h --- linux.vanilla/include/linux/wireless.h Thu Feb 22 00:09:59 2001 +++ linux.ac/include/linux/wireless.h Sat Apr 14 15:12:44 2001 @@ -1,7 +1,7 @@ /* * This file define a set of standard wireless extensions * - * Version : 9 16.10.99 + * Version : 11 28.3.01 * * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> */ @@ -63,7 +63,7 @@ * (there is some stuff that will be added in the future...) * I just plan to increment with each new version. */ -#define WIRELESS_EXT 10 +#define WIRELESS_EXT 11 /* * Changes : @@ -111,6 +111,11 @@ * - Add PM modifier : MAX/MIN/RELATIVE * - Add encoding option : IW_ENCODE_NOKEY * - Add TxPower ioctls (work like TxRate) + * + * V10 to V11 + * ---------- + * - Add WE version in range (help backward/forward compatibility) + * - Add retry ioctls (work like PM) */ /* -------------------------- IOCTL LIST -------------------------- */ @@ -153,7 +158,7 @@ * The "flags" member indicate if the ESSID is active or not (promiscuous). */ -/* Other parameters usefull in 802.11 and some other devices */ +/* Other parameters useful in 802.11 and some other devices */ #define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */ #define SIOCGIWRATE 0x8B21 /* get default bit rate (bps) */ #define SIOCSIWRTS 0x8B22 /* set RTS/CTS threshold (bytes) */ @@ -162,6 +167,8 @@ #define SIOCGIWFRAG 0x8B25 /* get fragmentation thr (bytes) */ #define SIOCSIWTXPOW 0x8B26 /* set transmit power (dBm) */ #define SIOCGIWTXPOW 0x8B27 /* get transmit power (dBm) */ +#define SIOCSIWRETRY 0x8B28 /* set retry limits and lifetime */ +#define SIOCGIWRETRY 0x8B29 /* get retry limits and lifetime */ /* Encoding stuff (scrambling, hardware security, WEP...) */ #define SIOCSIWENCODE 0x8B2A /* set encoding token & mode */ @@ -272,6 +279,16 @@ #define IW_TXPOW_DBM 0x0000 /* Value is in dBm */ #define IW_TXPOW_MWATT 0x0001 /* Value is in mW */ +/* Retry limits and lifetime flags available */ +#define IW_RETRY_ON 0x0000 /* No details... */ +#define IW_RETRY_TYPE 0xF000 /* Type of parameter */ +#define IW_RETRY_LIMIT 0x1000 /* Maximum number of retries*/ +#define IW_RETRY_LIFETIME 0x2000 /* Maximum duration of retries in us */ +#define IW_RETRY_MODIFIER 0x000F /* Modify a parameter */ +#define IW_RETRY_MIN 0x0001 /* Value is a minimum */ +#define IW_RETRY_MAX 0x0002 /* Value is a maximum */ +#define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ + /****************************** TYPES ******************************/ /* --------------------------- SUBTYPES --------------------------- */ @@ -288,7 +305,7 @@ /* * For all data larger than 16 octets, we need to use a - * pointer to memory alocated in user space. + * pointer to memory allocated in user space. */ struct iw_point { @@ -385,6 +402,7 @@ struct iw_param rts; /* RTS threshold threshold */ struct iw_param frag; /* Fragmentation threshold */ __u32 mode; /* Operation mode */ + struct iw_param retry; /* Retry limits & lifetime */ struct iw_point encoding; /* Encoding stuff : tokens */ struct iw_param power; /* PM duration/timeout */ @@ -462,6 +480,19 @@ __u16 txpower_capa; /* What options are supported */ __u8 num_txpower; /* Number of entries in the list */ __s32 txpower[IW_MAX_TXPOWER]; /* list, in bps */ + + /* Wireless Extension version info */ + __u8 we_version_compiled; /* Must be WIRELESS_EXT */ + __u8 we_version_source; /* Last update of source */ + + /* Retry limits and lifetime */ + __u16 retry_capa; /* What retry options are supported */ + __u16 retry_flags; /* How to decode max/min retry limit */ + __u16 r_time_flags; /* How to decode max/min retry life */ + __s32 min_retry; /* Minimal number of retries */ + __s32 max_retry; /* Maximal number of retries */ + __s32 min_r_time; /* Minimal retry lifetime */ + __s32 max_r_time; /* Maximal retry lifetime */ }; /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/net/icmp.h linux.ac/include/net/icmp.h --- linux.vanilla/include/net/icmp.h Thu Feb 22 00:11:56 2001 +++ linux.ac/include/net/icmp.h Tue Apr 17 17:48:44 2001 @@ -35,9 +35,8 @@ #define ICMP_INC_STATS_BH(field) SNMP_INC_STATS_BH(icmp_statistics, field) #define ICMP_INC_STATS_USER(field) SNMP_INC_STATS_USER(icmp_statistics, field) -extern void icmp_send(struct sk_buff *skb_in, int type, int code, - unsigned long info); -extern int icmp_rcv(struct sk_buff *skb, unsigned short len); +extern void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info); +extern int icmp_rcv(struct sk_buff *skb); extern int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg); extern void icmp_init(struct net_proto_family *ops); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/net/ip.h linux.ac/include/net/ip.h --- linux.vanilla/include/net/ip.h Thu Feb 22 00:10:38 2001 +++ linux.ac/include/net/ip.h Tue Apr 17 17:44:38 2001 @@ -188,11 +188,16 @@ extern void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst); -static inline void ip_select_ident(struct iphdr *iph, struct dst_entry *dst) +static inline void ip_select_ident(struct iphdr *iph, struct dst_entry *dst, struct sock *sk) { - if (iph->frag_off&__constant_htons(IP_DF)) - iph->id = 0; - else + if (iph->frag_off&__constant_htons(IP_DF)) { + /* This is only to work around buggy Windows95/2000 + * VJ compression implementations. If the ID field + * does not change, they drop every other packet in + * a TCP stream using header compression. + */ + iph->id = ((sk && sk->daddr) ? htons(sk->protinfo.af_inet.id++) : 0); + } else __ip_select_ident(iph, dst); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/net/ipip.h linux.ac/include/net/ipip.h --- linux.vanilla/include/net/ipip.h Sat Aug 5 02:18:49 2000 +++ linux.ac/include/net/ipip.h Sat Apr 14 01:44:33 2001 @@ -29,8 +29,9 @@ int err; \ int pkt_len = skb->len; \ \ + skb->ip_summed = CHECKSUM_NONE; \ iph->tot_len = htons(skb->len); \ - ip_select_ident(iph, &rt->u.dst); \ + ip_select_ident(iph, &rt->u.dst, NULL); \ ip_send_check(iph); \ \ err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, do_ip_send); \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/net/ipv6.h linux.ac/include/net/ipv6.h --- linux.vanilla/include/net/ipv6.h Thu Feb 22 00:12:00 2001 +++ linux.ac/include/net/ipv6.h Tue Apr 17 17:53:06 2001 @@ -4,7 +4,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: ipv6.h,v 1.22 2000/09/18 05:54:13 davem Exp $ + * $Id: ipv6.h,v 1.23 2000/12/13 18:31:48 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -181,11 +181,11 @@ extern int ip6_call_ra_chain(struct sk_buff *skb, int sel); -extern u8 * ipv6_reassembly(struct sk_buff **skb, u8 *nhptr); +extern int ipv6_reassembly(struct sk_buff **skb, int); -extern u8 * ipv6_parse_hopopts(struct sk_buff *skb, u8 *nhptr); +extern int ipv6_parse_hopopts(struct sk_buff *skb, int); -extern u8 * ipv6_parse_exthdrs(struct sk_buff **skb, u8 *nhptr); +extern int ipv6_parse_exthdrs(struct sk_buff **skb, int); extern struct ipv6_txoptions * ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt); @@ -303,8 +303,10 @@ struct ipv6_txoptions *opt, u8 *proto); -extern u8 * ipv6_skip_exthdr(struct ipv6_opt_hdr *hdr, +extern int ipv6_skip_exthdr(struct sk_buff *, int start, u8 *nexthdrp, int len); + +extern int ipv6_ext_hdr(u8 nexthdr); extern struct ipv6_txoptions * ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/net/irda/irda-usb.h linux.ac/include/net/irda/irda-usb.h --- linux.vanilla/include/net/irda/irda-usb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/net/irda/irda-usb.h Tue Apr 17 18:27:24 2001 @@ -0,0 +1,120 @@ +/***************************************************************************** + * + * Filename: irda-usb.h + * Version: 0.8 + * Description: IrDA-USB Driver + * Status: Experimental + * Author: Dag Brattli <dag@brattli.net> + * + * Copyright (C) 2001, Dag Brattli <dag@brattli.net> + * Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at> + * + * 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 <linux/time.h> + +#include <net/irda/irda.h> +#include <net/irda/irlap.h> +#include <net/irda/irda_device.h> + +#define RX_COPY_THRESHOLD 200 +#define IRDA_USB_MAX_MTU 2051 +#define IRDA_USB_SPEED_MTU 64 /* Weird, but work like this */ + +/* + * Maximum number of URB on the Rx and Tx path, a number larger than 1 + * is required for handling back-to-back (brickwalled) frames + */ +#define IU_MAX_ACTIVE_RX_URBS 1 +#define IU_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + 1) +#define IU_MAX_TX_URBS 1 + +/* Inbound header */ +#define MEDIA_BUSY 0x80 + +#define SPEED_2400 0x01 +#define SPEED_9600 0x02 +#define SPEED_19200 0x03 +#define SPEED_38400 0x04 +#define SPEED_57600 0x05 +#define SPEED_115200 0x06 +#define SPEED_576000 0x07 +#define SPEED_1152000 0x08 +#define SPEED_4000000 0x09 + +/* device_info flags in struct usb_device_id */ +#define IUC_DEFAULT 0x00 /* Basic device compliant with 1.0 spec */ +#define IUC_SPEED_BUG 0x01 /* Device doesn't set speed after the frame */ +#define IUC_SIR_ONLY 0x02 /* Device doesn't behave at FIR speeds */ +#define IUC_SMALL_PKT 0x04 /* Device doesn't behave with big Rx packets */ +#define IUC_NO_WINDOW 0x08 /* Device doesn't behave with big Rx window */ +#define IUC_MAX_WINDOW 0x10 /* Device underestimate the Rx window */ +#define IUC_MAX_XBOFS 0x20 /* Device need more xbofs than advertised */ + +#define USB_IRDA_HEADER 0x01 +#define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */ +#define USB_DT_IRDA 0x21 + +struct irda_class_desc { + __u8 bLength; + __u8 bDescriptorType; + __u16 bcdSpecRevision; + __u8 bmDataSize; + __u8 bmWindowSize; + __u8 bmMinTurnaroundTime; + __u16 wBaudRate; + __u8 bmAdditionalBOFs; + __u8 bIrdaRateSniff; + __u8 bMaxUnicastList; +} __attribute__ ((packed)); + +struct irda_usb_cb { + struct irda_class_desc *irda_desc; + struct usb_device *usbdev; /* init: probe_irda */ + unsigned int ifnum; /* Interface number of the USB dev. */ + int netopen; /* Device is active for network */ + int present; /* Device is present on the bus */ + __u32 capability; /* Capability of the hardware */ + __u8 bulk_in_ep, bulk_out_ep; /* Endpoint assignments */ + __u16 bulk_out_mtu; + + wait_queue_head_t wait_q; /* for timeouts */ + + struct urb rx_urb[IU_MAX_RX_URBS]; /* URBs used to receive data frames */ + struct urb *rx_idle_urb; /* Pointer to idle URB in Rx path */ + struct urb tx_urb; /* URB used to send data frames */ + struct urb speed_urb; /* URB used to send speed commands */ + + struct net_device *netdev; /* Yes! we are some kind of netdev. */ + struct net_device_stats stats; + struct irlap_cb *irlap; /* The link layer we are binded to */ + struct qos_info qos; + hashbin_t *tx_list; /* Queued transmit skb's */ + + struct timeval stamp; + struct timeval now; + + spinlock_t lock; /* For serializing operations */ + + __u16 xbofs; /* Current xbofs setting */ + __s16 new_xbofs; /* xbofs we need to set */ + __u32 speed; /* Current speed */ + __s32 new_speed; /* speed we need to set */ + __u32 flags; /* Interface flags */ +}; + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/net/irda/irda.h linux.ac/include/net/irda/irda.h --- linux.vanilla/include/net/irda/irda.h Thu Feb 22 00:10:24 2001 +++ linux.ac/include/net/irda/irda.h Tue Apr 17 17:44:38 2001 @@ -71,7 +71,9 @@ func } #else #define IRDA_DEBUG(n, args...) -#define ASSERT(expr, func) +#define ASSERT(expr, func) \ +if(!(expr)) do { \ + func } while (0) #endif /* CONFIG_IRDA_DEBUG */ #define WARNING(args...) printk(KERN_WARNING args) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/net/ndisc.h linux.ac/include/net/ndisc.h --- linux.vanilla/include/net/ndisc.h Thu Feb 22 00:11:56 2001 +++ linux.ac/include/net/ndisc.h Tue Apr 17 17:53:06 2001 @@ -60,7 +60,7 @@ extern void ndisc_cleanup(void); -extern int ndisc_rcv(struct sk_buff *skb, unsigned long len); +extern int ndisc_rcv(struct sk_buff *skb); extern void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, @@ -91,13 +91,9 @@ extern void igmp6_cleanup(void); -extern int igmp6_event_query(struct sk_buff *skb, - struct icmp6hdr *hdr, - int len); - -extern int igmp6_event_report(struct sk_buff *skb, - struct icmp6hdr *hdr, - int len); +extern int igmp6_event_query(struct sk_buff *skb); + +extern int igmp6_event_report(struct sk_buff *skb); extern void igmp6_cleanup(void); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/net/protocol.h linux.ac/include/net/protocol.h --- linux.vanilla/include/net/protocol.h Thu Feb 22 00:09:57 2001 +++ linux.ac/include/net/protocol.h Sat Apr 14 01:44:33 2001 @@ -36,8 +36,8 @@ /* This is used to register protocols. */ struct inet_protocol { - int (*handler)(struct sk_buff *skb, unsigned short len); - void (*err_handler)(struct sk_buff *skb, unsigned char *dp, int len); + int (*handler)(struct sk_buff *skb); + void (*err_handler)(struct sk_buff *skb, u32 info); struct inet_protocol *next; unsigned char protocol; unsigned char copy:1; @@ -48,12 +48,11 @@ #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) struct inet6_protocol { - int (*handler)(struct sk_buff *skb, - unsigned long len); + int (*handler)(struct sk_buff *skb); - void (*err_handler)(struct sk_buff *skb, struct ipv6hdr *hdr, + void (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, unsigned char *buff, + int type, int code, int offset, __u32 info); struct inet6_protocol *next; unsigned char protocol; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/net/raw.h linux.ac/include/net/raw.h --- linux.vanilla/include/net/raw.h Mon Aug 23 18:01:02 1999 +++ linux.ac/include/net/raw.h Sat Apr 14 01:44:33 2001 @@ -21,7 +21,7 @@ extern struct proto raw_prot; -extern void raw_err(struct sock *, struct sk_buff *); +extern void raw_err(struct sock *, struct sk_buff *, u32 info); extern int raw_rcv(struct sock *, struct sk_buff *); /* Note: v4 ICMP wants to get at this stuff, if you change the diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/net/rawv6.h linux.ac/include/net/rawv6.h --- linux.vanilla/include/net/rawv6.h Mon Aug 23 18:01:02 1999 +++ linux.ac/include/net/rawv6.h Sat Apr 14 01:44:54 2001 @@ -8,23 +8,21 @@ extern rwlock_t raw_v6_lock; extern struct sock * ipv6_raw_deliver(struct sk_buff *skb, - int nexthdr, unsigned long len); + int nexthdr); extern struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num, struct in6_addr *loc_addr, struct in6_addr *rmt_addr); extern int rawv6_rcv(struct sock *sk, - struct sk_buff *skb, - unsigned long len); + struct sk_buff *skb); extern void rawv6_err(struct sock *sk, struct sk_buff *skb, - struct ipv6hdr *hdr, struct inet6_skb_parm *opt, int type, int code, - unsigned char *buff, u32 info); + int offset, u32 info); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/net/sock.h linux.ac/include/net/sock.h --- linux.vanilla/include/net/sock.h Thu Feb 22 00:10:24 2001 +++ linux.ac/include/net/sock.h Tue Apr 17 17:44:38 2001 @@ -56,6 +56,10 @@ #if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE) #include <net/x25.h> #endif +#if defined(CONFIG_WAN_ROUTER) || defined(CONFIG_WAN_ROUTER_MODULE) +#include <linux/if_wanpipe.h> +#endif + #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) #include <net/ax25.h> #if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE) @@ -204,6 +208,7 @@ __u8 mc_loop; /* Loopback */ unsigned recverr : 1, freebind : 1; + __u16 id; /* ID counter for DF pkts */ __u8 pmtudisc; int mc_index; /* Multicast device index */ __u32 mc_addr; @@ -331,6 +336,8 @@ struct tcp_func *af_specific; /* Operations which are AF_INET{4,6} specific */ struct sk_buff *send_head; /* Front of stuff to transmit */ + struct page *sndmsg_page; /* Cached page for sendmsg */ + u32 sndmsg_off; /* Cached offset for sendmsg */ __u32 rcv_wnd; /* Current receiver window */ __u32 rcv_wup; /* rcv_nxt on last window update sent */ @@ -381,8 +388,6 @@ * the first SYN. */ __u32 undo_marker; /* tracking retrans started here. */ int undo_retrans; /* number of undoable retransmissions. */ - __u32 syn_seq; /* Seq of received SYN. */ - __u32 fin_seq; /* Seq of received FIN. */ __u32 urg_seq; /* Seq of received urgent pointer */ __u16 urg_data; /* Saved octet of OOB data and control flags */ __u8 pending; /* Scheduled timer event */ @@ -535,6 +540,7 @@ unsigned char debug; unsigned char rcvtstamp; unsigned char userlocks; + int route_caps; int proc; unsigned long lingertime; @@ -645,6 +651,9 @@ #if defined(CONFIG_IRDA) || defined(CONFIG_IRDA_MODULE) struct irda_sock *irda; #endif +#if defined(CONFIG_WAN_ROUTER) || defined(CONFIG_WAN_ROUTER_MODULE) + struct wanpipe_opt *af_wanpipe; +#endif } protinfo; @@ -730,12 +739,12 @@ }; /* Called with local bh disabled */ -static void __inline__ sock_prot_inc_use(struct proto *prot) +static __inline__ void sock_prot_inc_use(struct proto *prot) { prot->stats[smp_processor_id()].inuse++; } -static void __inline__ sock_prot_dec_use(struct proto *prot) +static __inline__ void sock_prot_dec_use(struct proto *prot) { prot->stats[smp_processor_id()].inuse--; } @@ -833,14 +842,11 @@ int *optlen); extern struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, - unsigned long fallback, int noblock, int *errcode); extern void *sock_kmalloc(struct sock *sk, int size, int priority); extern void sock_kfree_s(struct sock *sk, void *mem, int size); -extern int copy_and_csum_toiovec(struct iovec *iov, struct sk_buff *skb, int hlen); - /* * Functions to fill in entries in struct proto_ops when a protocol * does not implement a particular function. @@ -877,6 +883,10 @@ extern int sock_no_mmap(struct file *file, struct socket *sock, struct vm_area_struct *vma); +extern ssize_t sock_no_sendpage(struct socket *sock, + struct page *page, + int offset, size_t size, + int flags); /* * Default socket callbacks and setup code diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/net/tcp.h linux.ac/include/net/tcp.h --- linux.vanilla/include/net/tcp.h Thu Feb 22 00:10:40 2001 +++ linux.ac/include/net/tcp.h Tue Apr 17 17:48:44 2001 @@ -19,10 +19,7 @@ #define _TCP_H #define TCP_DEBUG 1 -#define FASTRETRANS_DEBUG 1 - -/* Be paranoid about data immediately beyond right edge of window. */ -#undef TCP_FORMAL_WINDOW +#define FASTRETRANS_DEBUG 2 /* Cancel timers, when they are not required. */ #undef TCP_CLEAR_TIMERS @@ -182,7 +179,6 @@ __u32 rcv_nxt; __u32 snd_nxt; __u32 rcv_wnd; - __u32 syn_seq; __u32 ts_recent; long ts_recent_stamp; unsigned long ttd; @@ -357,7 +353,7 @@ #define TCP_TWKILL_PERIOD (TCP_TIMEWAIT_LEN/TCP_TWKILL_SLOTS) #define TCP_SYNQ_INTERVAL (HZ/5) /* Period of SYNACK timer */ -#define TCP_SYNQ_HSIZE 64 /* Size of SYNACK hash table */ +#define TCP_SYNQ_HSIZE 512 /* Size of SYNACK hash table */ #define TCP_PAWS_24DAYS (60 * 60 * 24 * 24) #define TCP_PAWS_MSL 60 /* Per-host timestamps are invalidated @@ -632,19 +628,18 @@ extern void __tcp_put_port(struct sock *sk); extern void tcp_inherit_port(struct sock *sk, struct sock *child); -extern void tcp_v4_err(struct sk_buff *skb, - unsigned char *, int); +extern void tcp_v4_err(struct sk_buff *skb, u32); extern void tcp_shutdown (struct sock *sk, int how); -extern int tcp_v4_rcv(struct sk_buff *skb, - unsigned short len); +extern int tcp_v4_rcv(struct sk_buff *skb); extern int tcp_v4_remember_stamp(struct sock *sk); extern int tcp_v4_tw_remember_stamp(struct tcp_tw_bucket *tw); extern int tcp_sendmsg(struct sock *sk, struct msghdr *msg, int size); +extern ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags); extern int tcp_ioctl(struct sock *sk, int cmd, @@ -799,7 +794,7 @@ /* tcp_output.c */ -extern int tcp_write_xmit(struct sock *); +extern int tcp_write_xmit(struct sock *, int nonagle); extern int tcp_retransmit_skb(struct sock *, struct sk_buff *); extern void tcp_xmit_retransmit_queue(struct sock *); extern void tcp_simple_retransmit(struct sock *); @@ -812,6 +807,7 @@ extern int tcp_send_synack(struct sock *); extern int tcp_transmit_skb(struct sock *, struct sk_buff *); extern void tcp_send_skb(struct sock *, struct sk_buff *, int force_queue, unsigned mss_now); +extern void tcp_push_one(struct sock *, unsigned mss_now); extern void tcp_send_ack(struct sock *sk); extern void tcp_send_delayed_ack(struct sock *sk); @@ -942,6 +938,15 @@ __tcp_fast_path_on(tp, tp->snd_wnd>>tp->snd_wscale); } +static inline void tcp_fast_path_check(struct sock *sk, struct tcp_opt *tp) +{ + if (skb_queue_len(&tp->out_of_order_queue) == 0 && + tp->rcv_wnd && + atomic_read(&sk->rmem_alloc) < sk->rcvbuf && + !tp->urg_data) + tcp_fast_path_on(tp); +} + /* Compute the actual receive window we are currently advertising. * Rcv_nxt can be after the window if our peer push more data * than the offered window. @@ -1084,6 +1089,13 @@ return max(tp->snd_ssthresh, (tp->snd_cwnd>>1)+(tp->snd_cwnd>>2)); } +static inline void tcp_sync_left_out(struct tcp_opt *tp) +{ + if (tp->sack_ok && tp->sacked_out >= tp->packets_out - tp->lost_out) + tp->sacked_out = tp->packets_out - tp->lost_out; + tp->left_out = tp->sacked_out + tp->lost_out; +} + extern void tcp_cwnd_application_limited(struct sock *sk); /* Congestion window validation. (RFC2861) */ @@ -1229,7 +1241,7 @@ if (!tcp_skb_is_last(sk, skb)) nonagle = 1; if (!tcp_snd_test(tp, skb, cur_mss, nonagle) || - tcp_write_xmit(sk)) + tcp_write_xmit(sk, nonagle)) tcp_check_probe_timer(sk, tp); } tcp_cwnd_validate(sk, tp); @@ -1275,7 +1287,7 @@ static __inline__ int __tcp_checksum_complete(struct sk_buff *skb) { - return (unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum)); + return (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); } static __inline__ int tcp_checksum_complete(struct sk_buff *skb) @@ -1299,23 +1311,31 @@ * idea (VJ's mail "Re: query about TCP header on tcp-ip" of 07 Sep 93) * failed somewhere. Latency? Burstiness? Well, at least now we will * see, why it failed. 8)8) --ANK + * + * NOTE: is this not too big to inline? */ static __inline__ int tcp_prequeue(struct sock *sk, struct sk_buff *skb) { struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; if (tp->ucopy.task) { - if ((tp->ucopy.memory += skb->truesize) <= (sk->rcvbuf<<1)) { - __skb_queue_tail(&tp->ucopy.prequeue, skb); - if (skb_queue_len(&tp->ucopy.prequeue) == 1) { - wake_up_interruptible(sk->sleep); - if (!tcp_ack_scheduled(tp)) - tcp_reset_xmit_timer(sk, TCP_TIME_DACK, (3*TCP_RTO_MIN)/4); + __skb_queue_tail(&tp->ucopy.prequeue, skb); + tp->ucopy.memory += skb->truesize; + if (tp->ucopy.memory > sk->rcvbuf) { + struct sk_buff *skb1; + + if (sk->lock.users) BUG(); + + while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) { + sk->backlog_rcv(sk, skb1); + NET_INC_STATS_BH(TCPPrequeueDropped); } - } else { - NET_INC_STATS_BH(TCPPrequeueDropped); - tp->ucopy.memory -= skb->truesize; - __kfree_skb(skb); + + tp->ucopy.memory = 0; + } else if (skb_queue_len(&tp->ucopy.prequeue) == 1) { + wake_up_interruptible(sk->sleep); + if (!tcp_ack_scheduled(tp)) + tcp_reset_xmit_timer(sk, TCP_TIME_DACK, (3*TCP_RTO_MIN)/4); } return 1; } @@ -1677,19 +1697,40 @@ } } -static inline struct sk_buff *tcp_alloc_skb(struct sock *sk, int size, int gfp) +static inline struct sk_buff *tcp_alloc_pskb(struct sock *sk, int size, int mem, int gfp) { - struct sk_buff *skb = alloc_skb(size, gfp); + struct sk_buff *skb = alloc_skb(size+MAX_TCP_HEADER, gfp); if (skb) { + skb->truesize += mem; if (sk->forward_alloc >= (int)skb->truesize || - tcp_mem_schedule(sk, skb->truesize, 0)) + tcp_mem_schedule(sk, skb->truesize, 0)) { + skb_reserve(skb, MAX_TCP_HEADER); return skb; + } __kfree_skb(skb); } else { tcp_enter_memory_pressure(); tcp_moderate_sndbuf(sk); } + return NULL; +} + +static inline struct sk_buff *tcp_alloc_skb(struct sock *sk, int size, int gfp) +{ + return tcp_alloc_pskb(sk, size, 0, gfp); +} + +static inline struct page * tcp_alloc_page(struct sock *sk) +{ + if (sk->forward_alloc >= (int)PAGE_SIZE || + tcp_mem_schedule(sk, PAGE_SIZE, 0)) { + struct page *page = alloc_pages(sk->allocation, 0); + if (page) + return page; + } + tcp_enter_memory_pressure(); + tcp_moderate_sndbuf(sk); return NULL; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/net/udp.h linux.ac/include/net/udp.h --- linux.vanilla/include/net/udp.h Thu Feb 22 00:11:55 2001 +++ linux.ac/include/net/udp.h Tue Apr 17 17:52:33 2001 @@ -59,13 +59,13 @@ extern struct proto udp_prot; -extern void udp_err(struct sk_buff *, unsigned char *, int); +extern void udp_err(struct sk_buff *, u32); extern int udp_connect(struct sock *sk, struct sockaddr *usin, int addr_len); extern int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len); -extern int udp_rcv(struct sk_buff *skb, unsigned short len); +extern int udp_rcv(struct sk_buff *skb); extern int udp_ioctl(struct sock *sk, int cmd, unsigned long arg); extern int udp_disconnect(struct sock *sk, int flags); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/scsi/scsi.h linux.ac/include/scsi/scsi.h --- linux.vanilla/include/scsi/scsi.h Tue Sep 5 22:08:55 2000 +++ linux.ac/include/scsi/scsi.h Thu Apr 12 12:06:44 2001 @@ -196,8 +196,9 @@ * Here are some scsi specific ioctl commands which are sometimes useful. */ /* These are a few other constants only used by scsi devices */ +/* Note that include/linux/cdrom.h also defines IOCTL 0x5300 - 0x5395 */ -#define SCSI_IOCTL_GET_IDLUN 0x5382 +#define SCSI_IOCTL_GET_IDLUN 0x5382 /* conflicts with CDROMAUDIOBUFSIZ */ /* Used to turn on and off tagged queuing for scsi devices */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/video/macmodes.h linux.ac/include/video/macmodes.h --- linux.vanilla/include/video/macmodes.h Thu Feb 10 03:43:57 2000 +++ linux.ac/include/video/macmodes.h Tue Apr 3 17:55:18 2001 @@ -38,7 +38,9 @@ #define VMODE_1152_870_75 18 /* 1152x870, 75Hz */ #define VMODE_1280_960_75 19 /* 1280x960, 75Hz */ #define VMODE_1280_1024_75 20 /* 1280x1024, 75Hz */ -#define VMODE_MAX 20 +#define VMODE_1152_768_60 21 /* 1152x768, 60Hz Titanium PowerBook */ +#define VMODE_1600_1024_60 22 /* 1600x1024, 60Hz 22" Cinema Display */ +#define VMODE_MAX 22 #define VMODE_CHOOSE 99 #define CMODE_NVRAM -1 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/video/newport.h linux.ac/include/video/newport.h --- linux.vanilla/include/video/newport.h Fri Feb 25 18:30:57 2000 +++ linux.ac/include/video/newport.h Sat Apr 14 01:45:32 2001 @@ -486,7 +486,7 @@ * DCBMODE register defines: */ -/* Widht of the data being transfered for each DCBDATA[01] word */ +/* Width of the data being transferred for each DCBDATA[01] word */ #define DCB_DATAWIDTH_4 0x0 #define DCB_DATAWIDTH_1 0x1 #define DCB_DATAWIDTH_2 0x2 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/init/main.c linux.ac/init/main.c --- linux.vanilla/init/main.c Tue Apr 3 17:32:29 2001 +++ linux.ac/init/main.c Tue Apr 17 16:02:14 2001 @@ -31,6 +31,11 @@ #include <asm/io.h> #include <asm/bugs.h> +#if defined(CONFIG_ARCH_S390) +#include <asm/s390mach.h> +#include <asm/ccwcache.h> +#endif + #ifdef CONFIG_PCI #include <linux/pci.h> #endif @@ -47,10 +52,6 @@ # include <asm/mtrr.h> #endif -#ifdef CONFIG_3215_CONSOLE -extern int con3215_activate(void); -#endif - #ifdef CONFIG_NUBUS #include <linux/nubus.h> #endif @@ -59,11 +60,15 @@ #include <linux/isapnp.h> #endif +#ifdef CONFIG_PNPBIOS +#include <linux/pnp_bios.h> +#endif + #ifdef CONFIG_IRDA #include <net/irda/irda_device.h> #endif -#ifdef CONFIG_X86_IO_APIC +#ifdef CONFIG_X86_LOCAL_APIC #include <asm/smp.h> #endif @@ -87,6 +92,7 @@ extern void sock_init(void); extern void fork_init(unsigned long); extern void mca_init(void); +extern void gsc_init(void); extern void sbus_init(void); extern void ppc_init(void); extern void sysctl_init(void); @@ -214,6 +220,7 @@ { "pf", 0x2f00 }, { "apblock", APBLOCK_MAJOR << 8}, { "ddv", DDV_MAJOR << 8}, + { "ubd", UBD_MAJOR << 8 }, { "jsfd", JSFD_MAJOR << 8}, #ifdef CONFIG_MDISK { "mnda", (MDISK_MAJOR << MINORBITS)}, @@ -234,8 +241,75 @@ { "dasdf", (DASD_MAJOR << MINORBITS) + (5 << 2) }, { "dasdg", (DASD_MAJOR << MINORBITS) + (6 << 2) }, { "dasdh", (DASD_MAJOR << MINORBITS) + (7 << 2) }, -#endif -#if defined(CONFIG_BLK_CPQ_DA) || defined(CONFIG_BLK_CPQ_DA_MODULE) + { "dasdi", (DASD_MAJOR << MINORBITS) + (8 << 2) }, + { "dasdj", (DASD_MAJOR << MINORBITS) + (9 << 2) }, + { "dasdk", (DASD_MAJOR << MINORBITS) + (10 << 2) }, + { "dasdl", (DASD_MAJOR << MINORBITS) + (11 << 2) }, + { "dasdm", (DASD_MAJOR << MINORBITS) + (12 << 2) }, + { "dasdn", (DASD_MAJOR << MINORBITS) + (13 << 2) }, + { "dasdo", (DASD_MAJOR << MINORBITS) + (14 << 2) }, + { "dasdp", (DASD_MAJOR << MINORBITS) + (15 << 2) }, + { "dasdq", (DASD_MAJOR << MINORBITS) + (16 << 2) }, + { "dasdr", (DASD_MAJOR << MINORBITS) + (17 << 2) }, + { "dasds", (DASD_MAJOR << MINORBITS) + (18 << 2) }, + { "dasdt", (DASD_MAJOR << MINORBITS) + (19 << 2) }, + { "dasdu", (DASD_MAJOR << MINORBITS) + (20 << 2) }, + { "dasdv", (DASD_MAJOR << MINORBITS) + (21 << 2) }, + { "dasdw", (DASD_MAJOR << MINORBITS) + (22 << 2) }, + { "dasdx", (DASD_MAJOR << MINORBITS) + (23 << 2) }, + { "dasdy", (DASD_MAJOR << MINORBITS) + (24 << 2) }, + { "dasdz", (DASD_MAJOR << MINORBITS) + (25 << 2) }, +#endif +#ifdef CONFIG_BLK_DEV_XPRAM + { "xpram0", (XPRAM_MAJOR << MINORBITS) }, + { "xpram1", (XPRAM_MAJOR << MINORBITS) + 1 }, + { "xpram2", (XPRAM_MAJOR << MINORBITS) + 2 }, + { "xpram3", (XPRAM_MAJOR << MINORBITS) + 3 }, + { "xpram4", (XPRAM_MAJOR << MINORBITS) + 4 }, + { "xpram5", (XPRAM_MAJOR << MINORBITS) + 5 }, + { "xpram6", (XPRAM_MAJOR << MINORBITS) + 6 }, + { "xpram7", (XPRAM_MAJOR << MINORBITS) + 7 }, + { "xpram8", (XPRAM_MAJOR << MINORBITS) + 8 }, + { "xpram9", (XPRAM_MAJOR << MINORBITS) + 9 }, + { "xpram10", (XPRAM_MAJOR << MINORBITS) + 10 }, + { "xpram11", (XPRAM_MAJOR << MINORBITS) + 11 }, + { "xpram12", (XPRAM_MAJOR << MINORBITS) + 12 }, + { "xpram13", (XPRAM_MAJOR << MINORBITS) + 13 }, + { "xpram14", (XPRAM_MAJOR << MINORBITS) + 14 }, + { "xpram15", (XPRAM_MAJOR << MINORBITS) + 15 }, + { "xpram16", (XPRAM_MAJOR << MINORBITS) + 16 }, + { "xpram17", (XPRAM_MAJOR << MINORBITS) + 17 }, + { "xpram18", (XPRAM_MAJOR << MINORBITS) + 18 }, + { "xpram19", (XPRAM_MAJOR << MINORBITS) + 19 }, + { "xpram20", (XPRAM_MAJOR << MINORBITS) + 20 }, + { "xpram21", (XPRAM_MAJOR << MINORBITS) + 21 }, + { "xpram22", (XPRAM_MAJOR << MINORBITS) + 22 }, + { "xpram23", (XPRAM_MAJOR << MINORBITS) + 23 }, + { "xpram24", (XPRAM_MAJOR << MINORBITS) + 24 }, + { "xpram25", (XPRAM_MAJOR << MINORBITS) + 25 }, + { "xpram26", (XPRAM_MAJOR << MINORBITS) + 26 }, + { "xpram27", (XPRAM_MAJOR << MINORBITS) + 27 }, + { "xpram28", (XPRAM_MAJOR << MINORBITS) + 28 }, + { "xpram29", (XPRAM_MAJOR << MINORBITS) + 29 }, + { "xpram30", (XPRAM_MAJOR << MINORBITS) + 30 }, + { "xpram31", (XPRAM_MAJOR << MINORBITS) + 31 }, +#endif + { "rd/c0d0p",0x3000 }, + { "rd/c0d1p",0x3008 }, + { "rd/c0d2p",0x3010 }, + { "rd/c0d3p",0x3018 }, + { "rd/c0d4p",0x3020 }, + { "rd/c0d5p",0x3028 }, + { "rd/c0d6p",0x3030 }, + { "rd/c0d7p",0x3038 }, + { "rd/c0d8p",0x3040 }, + { "rd/c0d9p",0x3048 }, + { "rd/c0d10p",0x3050 }, + { "rd/c0d11p",0x3058 }, + { "rd/c0d12p",0x3060 }, + { "rd/c0d13p",0x3068 }, + { "rd/c0d14p",0x3070 }, + { "rd/c0d15p",0x3078 }, { "ida/c0d0p",0x4800 }, { "ida/c0d1p",0x4810 }, { "ida/c0d2p",0x4820 }, @@ -252,8 +326,6 @@ { "ida/c0d13p",0x48D0 }, { "ida/c0d14p",0x48E0 }, { "ida/c0d15p",0x48F0 }, -#endif -#if defined(CONFIG_BLK_CPQ_CISS_DA) || defined(CONFIG_BLK_CPQ_CISS_DA_MODULE) { "cciss/c0d0p",0x6800 }, { "cciss/c0d1p",0x6810 }, { "cciss/c0d2p",0x6820 }, @@ -270,10 +342,15 @@ { "cciss/c0d13p",0x68D0 }, { "cciss/c0d14p",0x68E0 }, { "cciss/c0d15p",0x68F0 }, -#endif -#ifdef CONFIG_NFTL + { "mtdblock", 0x1f00 }, { "nftla", 0x5d00 }, -#endif + { "nftlb", 0x5d10 }, + { "nftlc", 0x5d20 }, + { "nftld", 0x5d30 }, + { "ftla", 0x2c00 }, + { "ftlb", 0x2c08 }, + { "ftlc", 0x2c10 }, + { "ftld", 0x2c18 }, { NULL, 0 } }; @@ -492,10 +569,10 @@ #ifndef CONFIG_SMP -#ifdef CONFIG_X86_IO_APIC +#ifdef CONFIG_X86_LOCAL_APIC static void __init smp_init(void) { - IO_APIC_init_uniprocessor(); + APIC_init_uniprocessor(); } #else #define smp_init() do { } while (0) @@ -570,8 +647,8 @@ #endif mem_init(); kmem_cache_sizes_init(); -#ifdef CONFIG_3215_CONSOLE - con3215_activate(); +#if CONFIG_X86_PAE + init_pae_pgd_cache(); #endif #ifdef CONFIG_PROC_FS proc_root_init(); @@ -583,6 +660,9 @@ vfs_caches_init(mempages); buffer_init(mempages); page_cache_init(mempages); +#if defined(CONFIG_ARCH_S390) + ccwcache_init(); +#endif kiobuf_setup(); signals_init(); bdev_init(); @@ -679,6 +759,17 @@ * Ok, at this point all CPU's should be initialized, so * we can start looking into devices.. */ +#if defined(CONFIG_ARCH_S390) + s390_init_machine_check(); +#endif + +#ifdef CONFIG_GSC + /* + * GSC must initialise before PCI. On may HPPA boxes the PCI + * hangs off GSC. PCI is not the primary host bus + */ + gsc_init(); +#endif #ifdef CONFIG_PCI pci_init(); #endif @@ -706,6 +797,10 @@ #ifdef CONFIG_ISAPNP isapnp_init(); #endif +#ifdef CONFIG_PNPBIOS + pnp_bios_init(); +#endif + #ifdef CONFIG_TC tc_init(); #endif @@ -727,6 +822,7 @@ filesystem_setup(); #ifdef CONFIG_IRDA + irda_proto_init(); irda_device_init(); /* Must be done after protocol initialization */ #endif #ifdef CONFIG_PCMCIA diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/ipc/msg.c linux.ac/ipc/msg.c --- linux.vanilla/ipc/msg.c Mon Feb 19 18:18:18 2001 +++ linux.ac/ipc/msg.c Tue Apr 3 17:55:18 2001 @@ -123,7 +123,7 @@ if (!msq) return -ENOMEM; id = ipc_addid(&msg_ids, &msq->q_perm, msg_ctlmni); - if(id == -1) { + if (id == -1) { kfree(msq); return -ENOSPC; } @@ -148,7 +148,7 @@ struct msg_msgseg* seg; seg = msg->next; kfree(msg); - while(seg != NULL) { + while (seg) { struct msg_msgseg* tmp = seg->next; kfree(seg); seg = tmp; @@ -163,11 +163,11 @@ int alen; alen = len; - if(alen > DATALEN_MSG) + if (alen > DATALEN_MSG) alen = DATALEN_MSG; msg = (struct msg_msg *) kmalloc (sizeof(*msg) + alen, GFP_KERNEL); - if(msg==NULL) + if (!msg) return ERR_PTR(-ENOMEM); msg->next = NULL; @@ -180,19 +180,19 @@ len -= alen; src = ((char*)src)+alen; pseg = &msg->next; - while(len > 0) { + while (len > 0) { struct msg_msgseg* seg; alen = len; - if(alen > DATALEN_SEG) + if (alen > DATALEN_SEG) alen = DATALEN_SEG; seg = (struct msg_msgseg *) kmalloc (sizeof(*seg) + alen, GFP_KERNEL); - if(seg==NULL) { - err=-ENOMEM; + if (!seg) { + err = -ENOMEM; goto out_err; } *pseg = seg; seg->next = NULL; - if(copy_from_user (seg+1, src, alen)) { + if (copy_from_user (seg+1, src, alen)) { err = -EFAULT; goto out_err; } @@ -213,37 +213,37 @@ struct msg_msgseg *seg; alen = len; - if(alen > DATALEN_MSG) + if (alen > DATALEN_MSG) alen = DATALEN_MSG; - if(copy_to_user (dest, msg+1, alen)) + if (copy_to_user (dest, msg+1, alen)) return -1; len -= alen; dest = ((char*)dest)+alen; seg = msg->next; - while(len > 0) { + while (len > 0) { alen = len; - if(alen > DATALEN_SEG) + if (alen > DATALEN_SEG) alen = DATALEN_SEG; - if(copy_to_user (dest, seg+1, alen)) + if (copy_to_user (dest, seg+1, alen)) return -1; len -= alen; dest = ((char*)dest)+alen; - seg=seg->next; + seg = seg->next; } return 0; } static inline void ss_add(struct msg_queue* msq, struct msg_sender* mss) { - mss->tsk=current; - current->state=TASK_INTERRUPTIBLE; + mss->tsk = current; + current->state = TASK_INTERRUPTIBLE; list_add_tail(&mss->list,&msq->q_senders); } static inline void ss_del(struct msg_sender* mss) { - if(mss->list.next != NULL) + if (mss->list.next) list_del(&mss->list); } @@ -257,8 +257,8 @@ mss = list_entry(tmp,struct msg_sender,list); tmp = tmp->next; - if(kill) - mss->list.next=NULL; + if (kill) + mss->list.next = NULL; wake_up_process(mss->tsk); } } @@ -290,7 +290,7 @@ msg_unlock(id); tmp = msq->q_messages.next; - while(tmp != &msq->q_messages) { + while (tmp != &msq->q_messages) { struct msg_msg* msg = list_entry(tmp,struct msg_msg,m_list); tmp = tmp->next; atomic_dec(&msg_hdrs); @@ -317,7 +317,7 @@ ret = -EEXIST; } else { msq = msg_lock(id); - if(msq==NULL) + if (!msq) BUG(); if (ipcperms(&msq->q_perm, msgflg)) ret = -EACCES; @@ -346,18 +346,18 @@ out.msg_rtime = in->msg_rtime; out.msg_ctime = in->msg_ctime; - if(in->msg_cbytes > USHRT_MAX) + if (in->msg_cbytes > USHRT_MAX) out.msg_cbytes = USHRT_MAX; else out.msg_cbytes = in->msg_cbytes; out.msg_lcbytes = in->msg_cbytes; - if(in->msg_qnum > USHRT_MAX) + if (in->msg_qnum > USHRT_MAX) out.msg_qnum = USHRT_MAX; else out.msg_qnum = in->msg_qnum; - if(in->msg_qbytes > USHRT_MAX) + if (in->msg_qbytes > USHRT_MAX) out.msg_qbytes = USHRT_MAX; else out.msg_qbytes = in->msg_qbytes; @@ -408,7 +408,7 @@ out->gid = tbuf_old.msg_perm.gid; out->mode = tbuf_old.msg_perm.mode; - if(tbuf_old.msg_qbytes == 0) + if (!tbuf_old.msg_qbytes) out->qbytes = tbuf_old.msg_lqbytes; else out->qbytes = tbuf_old.msg_qbytes; @@ -473,16 +473,16 @@ int success_return; if (!buf) return -EFAULT; - if(cmd == MSG_STAT && msqid >= msg_ids.size) + if (cmd == MSG_STAT && msqid >= msg_ids.size) return -EINVAL; memset(&tbuf,0,sizeof(tbuf)); msq = msg_lock(msqid); - if (msq == NULL) + if (!msq) return -EINVAL; - if(cmd == MSG_STAT) { + if (cmd == MSG_STAT) { success_return = msg_buildid(msqid, msq->q_perm.seq); } else { err = -EIDRM; @@ -522,8 +522,8 @@ down(&msg_ids.sem); msq = msg_lock(msqid); - err=-EINVAL; - if (msq == NULL) + err = -EINVAL; + if (!msq) goto out_up; err = -EIDRM; @@ -582,22 +582,22 @@ case SEARCH_ANY: return 1; case SEARCH_LESSEQUAL: - if(msg->m_type <=type) + if (msg->m_type <= type) return 1; break; case SEARCH_EQUAL: - if(msg->m_type == type) + if (msg->m_type == type) return 1; break; case SEARCH_NOTEQUAL: - if(msg->m_type != type) + if (msg->m_type != type) return 1; break; } return 0; } -int inline pipelined_send(struct msg_queue* msq, struct msg_msg* msg) +inline int pipelined_send(struct msg_queue* msq, struct msg_msg* msg) { struct list_head* tmp; @@ -606,9 +606,9 @@ struct msg_receiver* msr; msr = list_entry(tmp,struct msg_receiver,r_list); tmp = tmp->next; - if(testmsg(msg,msr->r_msgtype,msr->r_mode)) { + if (testmsg(msg,msr->r_msgtype,msr->r_mode)) { list_del(&msr->r_list); - if(msr->r_maxsize < msg->m_ts) { + if (msr->r_maxsize < msg->m_ts) { msr->r_msg = ERR_PTR(-E2BIG); wake_up_process(msr->r_tsk); } else { @@ -638,52 +638,52 @@ return -EINVAL; msg = load_msg(msgp->mtext, msgsz); - if(IS_ERR(msg)) + if (IS_ERR(msg)) return PTR_ERR(msg); msg->m_type = mtype; msg->m_ts = msgsz; msq = msg_lock(msqid); - err=-EINVAL; - if(msq==NULL) + err = -EINVAL; + if (!msq) goto out_free; retry: - err= -EIDRM; + err = -EIDRM; if (msg_checkid(msq,msqid)) goto out_unlock_free; - err=-EACCES; + err = -EACCES; if (ipcperms(&msq->q_perm, S_IWUGO)) goto out_unlock_free; - if(msgsz + msq->q_cbytes > msq->q_qbytes || + if (msgsz + msq->q_cbytes > msq->q_qbytes || 1 + msq->q_qnum > msq->q_qbytes) { struct msg_sender s; - if(msgflg&IPC_NOWAIT) { - err=-EAGAIN; + if (msgflg&IPC_NOWAIT) { + err = -EAGAIN; goto out_unlock_free; } ss_add(msq, &s); msg_unlock(msqid); schedule(); - current->state= TASK_RUNNING; + current->state = TASK_RUNNING; msq = msg_lock(msqid); err = -EIDRM; - if(msq==NULL) + if (!msq) goto out_free; ss_del(&s); if (signal_pending(current)) { - err=-EINTR; + err = -EINTR; goto out_unlock_free; } goto retry; } - if(!pipelined_send(msq,msg)) { + if (!pipelined_send(msq,msg)) { /* noone is waiting for this message, enqueue it */ list_add_tail(&msg->m_list,&msq->q_messages); msq->q_cbytes += msgsz; @@ -700,12 +700,12 @@ out_unlock_free: msg_unlock(msqid); out_free: - if(msg!=NULL) + if (msg) free_msg(msg); return err; } -int inline convert_mode(long* msgtyp, int msgflg) +inline int convert_mode(long* msgtyp, int msgflg) { /* * find message of correct type. @@ -713,13 +713,13 @@ * msgtyp > 0 => get first message of matching type. * msgtyp < 0 => get message with least type must be < abs(msgtype). */ - if(*msgtyp==0) + if (!*msgtyp) return SEARCH_ANY; - if(*msgtyp<0) { - *msgtyp=-(*msgtyp); + if (*msgtyp < 0) { + *msgtyp = -*msgtyp; return SEARCH_LESSEQUAL; } - if(msgflg & MSG_EXCEPT) + if (msgflg & MSG_EXCEPT) return SEARCH_NOTEQUAL; return SEARCH_EQUAL; } @@ -739,33 +739,33 @@ mode = convert_mode(&msgtyp,msgflg); msq = msg_lock(msqid); - if(msq==NULL) + if (!msq) return -EINVAL; retry: - err=-EACCES; + err = -EACCES; if (ipcperms (&msq->q_perm, S_IRUGO)) goto out_unlock; tmp = msq->q_messages.next; - found_msg=NULL; + found_msg = NULL; while (tmp != &msq->q_messages) { msg = list_entry(tmp,struct msg_msg,m_list); - if(testmsg(msg,msgtyp,mode)) { + if (testmsg(msg,msgtyp,mode)) { found_msg = msg; - if(mode == SEARCH_LESSEQUAL && msg->m_type != 1) { - found_msg=msg; - msgtyp=msg->m_type-1; + if (mode == SEARCH_LESSEQUAL && msg->m_type != 1) { + found_msg = msg; + msgtyp = msg->m_type - 1; } else { - found_msg=msg; + found_msg = msg; break; } } tmp = tmp->next; } - if(found_msg) { - msg=found_msg; + if (found_msg) { + msg = found_msg; if ((msgsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) { - err=-E2BIG; + err = -E2BIG; goto out_unlock; } list_del(&msg->m_list); @@ -792,14 +792,14 @@ * receive. */ if (msgflg & IPC_NOWAIT) { - err=-ENOMSG; + err = -ENOMSG; goto out_unlock; } list_add_tail(&msr_d.r_list,&msq->q_receivers); msr_d.r_tsk = current; msr_d.r_msgtype = msgtyp; msr_d.r_mode = mode; - if(msgflg & MSG_NOERROR) + if (msgflg & MSG_NOERROR) msr_d.r_maxsize = INT_MAX; else msr_d.r_maxsize = msgsz; @@ -811,34 +811,34 @@ current->state = TASK_RUNNING; msg = (struct msg_msg*) msr_d.r_msg; - if(!IS_ERR(msg)) + if (!IS_ERR(msg)) goto out_success; t = msg_lock(msqid); - if(t==NULL) - msqid=-1; + if (!t) + msqid = -1; msg = (struct msg_msg*)msr_d.r_msg; - if(!IS_ERR(msg)) { + if (!IS_ERR(msg)) { /* our message arived while we waited for * the spinlock. Process it. */ - if(msqid!=-1) + if (msqid != -1) msg_unlock(msqid); goto out_success; } err = PTR_ERR(msg); - if(err == -EAGAIN) { - if(msqid==-1) + if (err == -EAGAIN) { + if (msqid == -1) BUG(); list_del(&msr_d.r_list); if (signal_pending(current)) - err=-EINTR; + err = -EINTR; else goto retry; } } out_unlock: - if(msqid!=-1) + if (msqid != -1) msg_unlock(msqid); return err; } @@ -853,10 +853,10 @@ down(&msg_ids.sem); len += sprintf(buffer, " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n"); - for(i = 0; i <= msg_ids.max_id; i++) { + for (i = 0; i <= msg_ids.max_id; i++) { struct msg_queue * msq; msq = msg_lock(i); - if(msq != NULL) { + if (msq) { len += sprintf(buffer + len, "%10d %10d %4o %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n", msq->q_perm.key, msg_buildid(i,msq->q_perm.seq), @@ -875,11 +875,11 @@ msg_unlock(i); pos += len; - if(pos < offset) { + if (pos < offset) { len = 0; begin = pos; } - if(pos > offset + length) + if (pos > offset + length) goto done; } @@ -889,9 +889,9 @@ up(&msg_ids.sem); *start = buffer + (offset - begin); len -= (offset - begin); - if(len > length) + if (len > length) len = length; - if(len < 0) + if (len < 0) len = 0; return len; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/ipc/sem.c linux.ac/ipc/sem.c --- linux.vanilla/ipc/sem.c Mon Feb 19 18:18:18 2001 +++ linux.ac/ipc/sem.c Tue Apr 3 17:55:18 2001 @@ -122,12 +122,11 @@ size = sizeof (*sma) + nsems * sizeof (struct sem); sma = (struct sem_array *) ipc_alloc(size); - if (!sma) { + if (!sma) return -ENOMEM; - } memset (sma, 0, size); id = ipc_addid(&sem_ids, &sma->sem_perm, sc_semmni); - if(id == -1) { + if (id == -1) { ipc_free(sma, size); return -ENOSPC; } @@ -167,7 +166,7 @@ err = -EEXIST; } else { sma = sem_lock(id); - if(sma==NULL) + if (!sma) BUG(); if (nsems > sma->sem_nsems) err = -EINVAL; @@ -188,9 +187,9 @@ struct sem_array* smanew; smanew = sem_lock(semid); - if(smanew==NULL) + if (!smanew) return -EIDRM; - if(smanew != sma || sem_checkid(sma,semid) || sma->sem_nsems != nsems) { + if (smanew != sma || sem_checkid(sma,semid) || sma->sem_nsems != nsems) { sem_unlock(semid); return -EIDRM; } @@ -249,27 +248,31 @@ for (sop = sops; sop < sops + nsops; sop++) { curr = sma->sem_base + sop->sem_num; sem_op = sop->sem_op; + result = curr->semval; - if (!sem_op && curr->semval) + if (!sem_op && result) goto would_block; - curr->sempid = (curr->sempid << 16) | pid; - curr->semval += sem_op; - if (sop->sem_flg & SEM_UNDO) - un->semadj[sop->sem_num] -= sem_op; - - if (curr->semval < 0) + result += sem_op; + if (result < 0) goto would_block; - if (curr->semval > SEMVMX) + if (result > SEMVMX) goto out_of_range; + curr->semval = result; } if (do_undo) { - sop--; result = 0; goto undo; } + sop--; + while (sop >= sops) { + sma->sem_base[sop->sem_num].sempid = pid; + if (sop->sem_flg & SEM_UNDO) + un->semadj[sop->sem_num] -= sop->sem_op; + sop--; + } sma->sem_otime = CURRENT_TIME; return 0; @@ -285,13 +288,9 @@ result = 1; undo: + sop--; while (sop >= sops) { - curr = sma->sem_base + sop->sem_num; - curr->semval -= sop->sem_op; - curr->sempid >>= 16; - - if (sop->sem_flg & SEM_UNDO) - un->semadj[sop->sem_num] += sop->sem_op; + sma->sem_base[sop->sem_num].semval -= sop->sem_op; sop--; } @@ -318,7 +317,7 @@ if (error <= 0) { /* Found one, wake it up */ wake_up_process(q->sleeper); - if (error == 0 && q->alter) { + if (!error && q->alter) { /* if q-> alter let it self try */ q->status = 1; return; @@ -368,7 +367,7 @@ int i; for (i = 0; i < nsops; i++) if (sops[i].sem_num == semnum - && (sops[i].sem_op == 0) + && !sops[i].sem_op && !(sops[i].sem_flg & IPC_NOWAIT)) semzcnt++; } @@ -467,13 +466,13 @@ struct semid64_ds tbuf; int id; - if(semid >= sem_ids.size) + if (semid >= sem_ids.size) return -EINVAL; memset(&tbuf,0,sizeof(tbuf)); sma = sem_lock(semid); - if(sma == NULL) + if (!sma) return -EINVAL; err = -EACCES; @@ -509,12 +508,12 @@ int nsems; sma = sem_lock(semid); - if(sma==NULL) + if (!sma) return -EINVAL; nsems = sma->sem_nsems; - err=-EIDRM; + err = -EIDRM; if (sem_checkid(sma,semid)) goto out_unlock; @@ -528,13 +527,13 @@ ushort *array = arg.array; int i; - if(nsems > SEMMSL_FAST) { + if (nsems > SEMMSL_FAST) { sem_unlock(semid); sem_io = ipc_alloc(sizeof(ushort)*nsems); - if(sem_io == NULL) + if (!sem_io) return -ENOMEM; err = sem_revalidate(semid, sma, nsems, S_IRUGO); - if(err) + if (err) goto out_free; } @@ -542,7 +541,7 @@ sem_io[i] = sma->sem_base[i].semval; sem_unlock(semid); err = 0; - if(copy_to_user(array, sem_io, nsems*sizeof(ushort))) + if (copy_to_user(array, sem_io, nsems*sizeof(ushort))) err = -EFAULT; goto out_free; } @@ -553,9 +552,9 @@ sem_unlock(semid); - if(nsems > SEMMSL_FAST) { + if (nsems > SEMMSL_FAST) { sem_io = ipc_alloc(sizeof(ushort)*nsems); - if(sem_io == NULL) + if (!sem_io) return -ENOMEM; } @@ -571,7 +570,7 @@ } } err = sem_revalidate(semid, sma, nsems, S_IWUGO); - if(err) + if (err) goto out_free; for (i = 0; i < nsems; i++) @@ -601,7 +600,7 @@ /* GETVAL, GETPID, GETNCTN, GETZCNT, SETVAL: fall-through */ } err = -EINVAL; - if(semnum < 0 || semnum >= nsems) + if (semnum < 0 || semnum >= nsems) goto out_unlock; curr = &sma->sem_base[semnum]; @@ -611,7 +610,7 @@ err = curr->semval; goto out_unlock; case GETPID: - err = curr->sempid & 0xffff; + err = curr->sempid; goto out_unlock; case GETNCNT: err = count_semncnt(sma,semnum); @@ -640,7 +639,7 @@ out_unlock: sem_unlock(semid); out_free: - if(sem_io != fast_sem_io) + if (sem_io != fast_sem_io) ipc_free(sem_io, sizeof(ushort)*nsems); return err; } @@ -658,7 +657,7 @@ { struct semid64_ds tbuf; - if(copy_from_user(&tbuf, buf, sizeof(tbuf))) + if (copy_from_user(&tbuf, buf, sizeof(tbuf))) return -EFAULT; out->uid = tbuf.sem_perm.uid; @@ -671,7 +670,7 @@ { struct semid_ds tbuf_old; - if(copy_from_user(&tbuf_old, buf, sizeof(tbuf_old))) + if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old))) return -EFAULT; out->uid = tbuf_old.sem_perm.uid; @@ -692,23 +691,23 @@ struct sem_setbuf setbuf; struct kern_ipc_perm *ipcp; - if(cmd == IPC_SET) { - if(copy_semid_from_user (&setbuf, arg.buf, version)) + if (cmd == IPC_SET) { + if (copy_semid_from_user (&setbuf, arg.buf, version)) return -EFAULT; } sma = sem_lock(semid); - if(sma==NULL) + if (!sma) return -EINVAL; if (sem_checkid(sma,semid)) { - err=-EIDRM; + err = -EIDRM; goto out_unlock; } ipcp = &sma->sem_perm; if (current->euid != ipcp->cuid && current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) { - err=-EPERM; + err = -EPERM; goto out_unlock; } @@ -777,17 +776,15 @@ static struct sem_undo* freeundos(struct sem_array *sma, struct sem_undo* un) { - struct sem_undo* u; - struct sem_undo** up; + struct sem_undo *u, **up; - for(up = ¤t->semundo;(u=*up);up=&u->proc_next) { - if(un==u) { - un=u->proc_next; - *up=un; + for (up = ¤t->semundo; (u = *up); up = &u->proc_next) + if (un == u) { + un = u->proc_next; + *up = un; kfree(u); return un; } - } printk ("freeundos undo list error id=%d\n", un->semid); return un->proc_next; } @@ -808,7 +805,7 @@ memset(un, 0, size); error = sem_revalidate(semid, sma, nsems, alter ? S_IWUGO : S_IRUGO); - if(error) { + if (error) { kfree(un); return error; } @@ -837,18 +834,18 @@ return -EINVAL; if (nsops > sc_semopm) return -E2BIG; - if(nsops > SEMOPM_FAST) { + if (nsops > SEMOPM_FAST) { sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL); - if(sops==NULL) + if (!sops) return -ENOMEM; } if (copy_from_user (sops, tsops, nsops * sizeof(*tsops))) { - error=-EFAULT; + error = -EFAULT; goto out_free; } sma = sem_lock(semid); - error=-EINVAL; - if(sma==NULL) + error = -EINVAL; + if (!sma) goto out_free; error = -EIDRM; if (sem_checkid(sma,semid)) @@ -873,18 +870,18 @@ /* Make sure we have an undo structure * for this process and this semaphore set. */ - un=current->semundo; - while(un != NULL) { - if(un->semid==semid) + un = current->semundo; + while (un) { + if (un->semid == semid) break; - if(un->semid==-1) - un=freeundos(sma,un); + if (un->semid == -1) + un = freeundos(sma,un); else - un=un->proc_next; + un = un->proc_next; } if (!un) { error = alloc_undo(sma,&un,semid,alter); - if(error) + if (error) goto out_free; } } else @@ -921,8 +918,8 @@ schedule(); tmp = sem_lock(semid); - if(tmp==NULL) { - if(queue.prev != NULL) + if (!tmp) { + if (queue.prev != NULL) BUG(); current->semsleeping = NULL; error = -EIDRM; @@ -958,7 +955,7 @@ out_unlock_free: sem_unlock(semid); out_free: - if(sops != fast_sops) + if (sops != fast_sops) kfree(sops); return error; } @@ -991,20 +988,20 @@ current->semsleeping = NULL; if (q->prev) { - if(sma==NULL) + if (!sma) BUG(); remove_from_queue(q->sma,q); } - if(sma!=NULL) + if (sma) sem_unlock(semid); } for (up = ¤t->semundo; (u = *up); *up = u->proc_next, kfree(u)) { int semid = u->semid; - if(semid == -1) + if (semid == -1) continue; sma = sem_lock(semid); - if (sma == NULL) + if (!sma) continue; if (u->semid == -1) @@ -1050,10 +1047,10 @@ len += sprintf(buffer, " key semid perms nsems uid gid cuid cgid otime ctime\n"); down(&sem_ids.sem); - for(i = 0; i <= sem_ids.max_id; i++) { + for (i = 0; i <= sem_ids.max_id; i++) { struct sem_array *sma; sma = sem_lock(i); - if(sma) { + if (sma) { len += sprintf(buffer + len, "%10d %10d %4o %10lu %5u %5u %5u %5u %10lu %10lu\n", sma->sem_perm.key, sem_buildid(i,sma->sem_perm.seq), @@ -1068,11 +1065,11 @@ sem_unlock(i); pos += len; - if(pos < offset) { + if (pos < offset) { len = 0; begin = pos; } - if(pos > offset + length) + if (pos > offset + length) goto done; } } @@ -1081,9 +1078,9 @@ up(&sem_ids.sem); *start = buffer + (offset - begin); len -= (offset - begin); - if(len > length) + if (len > length) len = length; - if(len < 0) + if (len < 0) len = 0; return len; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/ipc/shm.c linux.ac/ipc/shm.c --- linux.vanilla/ipc/shm.c Tue Apr 3 17:32:29 2001 +++ linux.ac/ipc/shm.c Wed Apr 4 13:44:32 2001 @@ -497,14 +497,21 @@ if (shp == NULL) goto out_up; err = shm_checkid(shp, shmid); - if (err == 0) { - if (shp->shm_nattch){ - shp->shm_flags |= SHM_DEST; - /* Do not find it any more */ - shp->shm_perm.key = IPC_PRIVATE; - } else - shm_destroy (shp); + if(err) + goto out_unlock_up; + if (current->euid != shp->shm_perm.uid && + current->euid != shp->shm_perm.cuid && + !capable(CAP_SYS_ADMIN)) { + err=-EPERM; + goto out_unlock_up; } + if (shp->shm_nattch){ + shp->shm_flags |= SHM_DEST; + /* Do not find it any more */ + shp->shm_perm.key = IPC_PRIVATE; + } else + shm_destroy (shp); + /* Unlock */ shm_unlock(shmid); up(&shm_ids.sem); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/ipc/util.c linux.ac/ipc/util.c --- linux.vanilla/ipc/util.c Mon Feb 19 18:18:18 2001 +++ linux.ac/ipc/util.c Tue Apr 3 17:55:18 2001 @@ -54,7 +54,7 @@ int i; sema_init(&ids->sem,1); - if(size > IPCMNI) + if (size > IPCMNI) size = IPCMNI; ids->size = size; ids->in_use = 0; @@ -62,20 +62,19 @@ ids->seq = 0; { int seq_limit = INT_MAX/SEQ_MULTIPLIER; - if(seq_limit > USHRT_MAX) + if (seq_limit > USHRT_MAX) ids->seq_max = USHRT_MAX; else ids->seq_max = seq_limit; } ids->entries = ipc_alloc(sizeof(struct ipc_id)*size); - - if(ids->entries == NULL) { + if (!ids->entries) { printk(KERN_ERR "ipc_init_ids() failed, ipc service disabled.\n"); ids->size = 0; } ids->ary = SPIN_LOCK_UNLOCKED; - for(i=0;i<size;i++) + for (i = 0; i < size; i++) ids->entries[i].p = NULL; } @@ -94,7 +93,7 @@ for (id = 0; id <= ids->max_id; id++) { p = ids->entries[id].p; - if(p==NULL) + if (!p) continue; if (key == p->key) return id; @@ -108,18 +107,17 @@ struct ipc_id* old; int i; - if(newsize > IPCMNI) + if (newsize > IPCMNI) newsize = IPCMNI; - if(newsize <= ids->size) + if (newsize <= ids->size) return newsize; new = ipc_alloc(sizeof(struct ipc_id)*newsize); - if(new == NULL) + if (!new) return ids->size; memcpy(new, ids->entries, sizeof(struct ipc_id)*ids->size); - for(i=ids->size;i<newsize;i++) { + for (i = ids->size; i < newsize; i++) new[i].p = NULL; - } spin_lock(&ids->ary); old = ids->entries; @@ -148,10 +146,9 @@ int id; size = grow_ary(ids,size); - for (id = 0; id < size; id++) { - if(ids->entries[id].p == NULL) + for (id = 0; id < size; id++) + if (!ids->entries[id].p) goto found; - } return -1; found: ids->in_use++; @@ -162,7 +159,7 @@ new->gid = new->cgid = current->egid; new->seq = ids->seq++; - if(ids->seq > ids->seq_max) + if (ids->seq > ids->seq_max) ids->seq = 0; spin_lock(&ids->ary); @@ -185,20 +182,20 @@ { struct kern_ipc_perm* p; int lid = id % SEQ_MULTIPLIER; - if(lid >= ids->size) + if (lid >= ids->size) BUG(); p = ids->entries[lid].p; ids->entries[lid].p = NULL; - if(p==NULL) + if (!p) BUG(); ids->in_use--; if (lid == ids->max_id) { do { lid--; - if(lid == -1) + if (lid == -1) break; - } while (ids->entries[lid].p == NULL); + } while (!ids->entries[lid].p); ids->max_id = lid; } return p; @@ -214,8 +211,8 @@ void* ipc_alloc(int size) { - void* out; - if(size > PAGE_SIZE) + void *out; + if (size > PAGE_SIZE) out = vmalloc(size); else out = kmalloc(size, GFP_KERNEL); @@ -233,7 +230,7 @@ void ipc_free(void* ptr, int size) { - if(size > PAGE_SIZE) + if (size > PAGE_SIZE) vfree(ptr); else kfree(ptr); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/ipc/util.h linux.ac/ipc/util.h --- linux.vanilla/ipc/util.h Mon Feb 19 18:18:18 2001 +++ linux.ac/ipc/util.h Tue Apr 3 17:55:18 2001 @@ -54,7 +54,7 @@ { struct kern_ipc_perm* out; int lid = id % SEQ_MULTIPLIER; - if(lid >= ids->size) + if (lid >= ids->size) return NULL; out = ids->entries[lid].p; @@ -69,12 +69,12 @@ { struct kern_ipc_perm* out; int lid = id % SEQ_MULTIPLIER; - if(lid >= ids->size) + if (lid >= ids->size) return NULL; spin_lock(&ids->ary); out = ids->entries[lid].p; - if(out==NULL) + if (!out) spin_unlock(&ids->ary); return out; } @@ -91,7 +91,7 @@ extern inline int ipc_checkid(struct ipc_ids* ids, struct kern_ipc_perm* ipcp, int uid) { - if(uid/SEQ_MULTIPLIER != ipcp->seq) + if (uid/SEQ_MULTIPLIER != ipcp->seq) return 1; return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/Makefile linux.ac/kernel/Makefile --- linux.vanilla/kernel/Makefile Fri Dec 29 22:07:24 2000 +++ linux.ac/kernel/Makefile Tue Apr 3 17:55:18 2001 @@ -9,7 +9,7 @@ O_TARGET := kernel.o -export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o +export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o printk.o fork.o obj-y = sched.o dma.o fork.o exec_domain.o panic.o printk.o \ module.o exit.o itimer.o info.o time.o softirq.o resource.o \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/context.c linux.ac/kernel/context.c --- linux.vanilla/kernel/context.c Fri Jan 12 17:52:41 2001 +++ linux.ac/kernel/context.c Sun Apr 15 23:01:31 2001 @@ -101,8 +101,10 @@ if (signal_pending(curtask)) { while (waitpid(-1, (unsigned int *)0, __WALL|WNOHANG) > 0) ; + spin_lock_irq(&curtask->sigmask_lock); flush_signals(curtask); recalc_sigpending(curtask); + spin_unlock_irq(&curtask->sigmask_lock); } } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/fork.c linux.ac/kernel/fork.c --- linux.vanilla/kernel/fork.c Tue Apr 3 17:32:29 2001 +++ linux.ac/kernel/fork.c Sat Apr 14 01:45:39 2001 @@ -39,7 +39,7 @@ unsigned long flags; wq_write_lock_irqsave(&q->lock, flags); - wait->flags = 0; + wait->flags &= ~WQ_FLAG_EXCLUSIVE; __add_wait_queue(q, wait); wq_write_unlock_irqrestore(&q->lock, flags); } @@ -49,7 +49,7 @@ unsigned long flags; wq_write_lock_irqsave(&q->lock, flags); - wait->flags = WQ_FLAG_EXCLUSIVE; + wait->flags |= WQ_FLAG_EXCLUSIVE; __add_wait_queue_tail(q, wait); wq_write_unlock_irqrestore(&q->lock, flags); } @@ -122,7 +122,7 @@ return last_pid; } -static inline int dup_mmap(struct mm_struct * mm) +int dup_mmap(struct mm_struct * mm) { struct vm_area_struct * mpnt, *tmp, **pprev; int retval; @@ -191,13 +191,15 @@ return retval; } +EXPORT_SYMBOL(dup_mmap); + spinlock_t mmlist_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; int mmlist_nr; #define allocate_mm() (kmem_cache_alloc(mm_cachep, SLAB_KERNEL)) #define free_mm(mm) (kmem_cache_free(mm_cachep, (mm))) -static struct mm_struct * mm_init(struct mm_struct * mm) +struct mm_struct * mm_init(struct mm_struct * mm) { atomic_set(&mm->mm_users, 1); atomic_set(&mm->mm_count, 1); @@ -210,6 +212,7 @@ return NULL; } +EXPORT_SYMBOL(mm_init); /* * Allocate and initialize an mm_struct. @@ -666,15 +669,17 @@ p->pdeath_signal = 0; /* - * "share" dynamic priority between parent and child, thus the - * total amount of dynamic priorities in the system doesnt change, - * more scheduling fairness. This is only important in the first - * timeslice, on the long run the scheduling behaviour is unchanged. + * Give the parent's dynamic priority entirely to the child. The + * total amount of dynamic priorities in the system doesn't change + * (more scheduling fairness), but the child will run first, which + * is especially useful in avoiding a lot of copy-on-write faults + * if the child for a fork() just wants to do a few simple things + * and then exec(). This is only important in the first timeslice. + * In the long run, the scheduling behavior is unchanged. */ - p->counter = (current->counter + 1) >> 1; - current->counter >>= 1; - if (!current->counter) - current->need_resched = 1; + p->counter = current->counter; + current->counter = 0; + current->need_resched = 1; /* * Ok, add it to the run-queues and make it diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/info.c linux.ac/kernel/info.c --- linux.vanilla/kernel/info.c Tue Sep 5 21:57:57 2000 +++ linux.ac/kernel/info.c Tue Apr 3 17:55:18 2001 @@ -33,41 +33,46 @@ si_swapinfo(&val); { - /* If the sum of all the available memory (i.e. ram + swap + - * highmem) is less then can be stored in a 32 bit unsigned long - * then we can be binary compatible with 2.2.x kernels. If not, - * well, who cares since in that case 2.2.x was broken anyways... + unsigned long mem_total, sav_total; + unsigned int mem_unit, bitcount; + + /* If the sum of all the available memory (i.e. ram + swap) + * is less than can be stored in a 32 bit unsigned long then + * we can be binary compatible with 2.2.x kernels. If not, + * well, in that case 2.2.x was broken anyways... * * -Erik Andersen <andersee@debian.org> */ - unsigned long mem_total = val.totalram + val.totalswap; - if ( !(mem_total < val.totalram || mem_total < val.totalswap)) { - unsigned long mem_total2 = mem_total + val.totalhigh; - if (!(mem_total2 < mem_total || mem_total2 < val.totalhigh)) - { - /* If mem_total did not overflow. Divide all memory values by - * mem_unit and set mem_unit=1. This leaves things compatible with - * 2.2.x, and also retains compatibility with earlier 2.4.x - * kernels... */ - - int bitcount = 0; - while (val.mem_unit > 1) - { - bitcount++; - val.mem_unit >>= 1; - } - val.totalram <<= bitcount; - val.freeram <<= bitcount; - val.sharedram <<= bitcount; - val.bufferram <<= bitcount; - val.totalswap <<= bitcount; - val.freeswap <<= bitcount; - val.totalhigh <<= bitcount; - val.freehigh <<= bitcount; - } + mem_total = val.totalram + val.totalswap; + if (mem_total < val.totalram || mem_total < val.totalswap) + goto out; + bitcount = 0; + mem_unit = val.mem_unit; + while (mem_unit > 1) { + bitcount++; + mem_unit >>= 1; + sav_total = mem_total; + mem_total <<= 1; + if (mem_total < sav_total) + goto out; } - } + /* If mem_total did not overflow, multiply all memory values by + * val.mem_unit and set it to 1. This leaves things compatible + * with 2.2.x, and also retains compatibility with earlier 2.4.x + * kernels... */ + + val.mem_unit = 1; + val.totalram <<= bitcount; + val.freeram <<= bitcount; + val.sharedram <<= bitcount; + val.bufferram <<= bitcount; + val.totalswap <<= bitcount; + val.freeswap <<= bitcount; + val.totalhigh <<= bitcount; + val.freehigh <<= bitcount; + } +out: if (copy_to_user(info, &val, sizeof(struct sysinfo))) return -EFAULT; return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/kmod.c linux.ac/kernel/kmod.c --- linux.vanilla/kernel/kmod.c Sun Dec 31 02:16:13 2000 +++ linux.ac/kernel/kmod.c Tue Apr 3 17:55:18 2001 @@ -157,19 +157,18 @@ } /** - * request_module - try to load a kernel module - * @module_name: Name of module + * request_module - try to load a kernel module + * @module_name: Name of module * - * Load a module using the user mode module loader. The function returns - * zero on success or a negative errno code on failure. Note that a - * successful module load does not mean the module did not then unload - * and exit on an error of its own. Callers must check that the service - * they requested is now available not blindly invoke it. + * Load a module using the user mode module loader. The function returns + * zero on success or a negative errno code on failure. Note that a + * successful module load does not mean the module did not then unload + * and exit on an error of its own. Callers must check that the service + * they requested is now available not blindly invoke it. * - * If module auto-loading support is disabled then this function - * becomes a no-operation. + * If module auto-loading support is disabled then this function + * becomes a no-operation. */ - int request_module(const char * module_name) { pid_t pid; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/ksyms.c linux.ac/kernel/ksyms.c --- linux.vanilla/kernel/ksyms.c Tue Apr 3 17:32:29 2001 +++ linux.ac/kernel/ksyms.c Tue Apr 17 15:44:32 2001 @@ -7,6 +7,10 @@ * - External symbol table support added (December 1994) * - Versions on symbols added (December 1994) * by Bjorn Ekwall <bj0rn@blox.se> + * + * Added sysrq interface for dynamic sysrq (2000) + * Crutcher Dunnavant <crutcher@redhat.com> + * */ #include <linux/config.h> @@ -46,6 +50,9 @@ #include <linux/brlock.h> #include <linux/fs.h> #include <linux/tty.h> +#include <linux/sysrq.h> +#include <linux/in6.h> +#include <asm/checksum.h> #if defined(CONFIG_PROC_FS) #include <linux/proc_fs.h> @@ -55,7 +62,6 @@ #endif extern void set_device_ro(kdev_t dev,int flag); - extern void *sys_call_table; extern int sys_tz; @@ -217,6 +223,7 @@ EXPORT_SYMBOL(posix_test_lock); EXPORT_SYMBOL(posix_block_lock); EXPORT_SYMBOL(posix_unblock_lock); +EXPORT_SYMBOL(posix_locks_deadlock); EXPORT_SYMBOL(locks_mandatory_area); EXPORT_SYMBOL(dput); EXPORT_SYMBOL(have_submounts); @@ -256,6 +263,8 @@ EXPORT_SYMBOL(lock_may_read); EXPORT_SYMBOL(lock_may_write); EXPORT_SYMBOL(dcache_readdir); +EXPORT_SYMBOL(buffer_insert_inode_queue); +EXPORT_SYMBOL(fsync_inode_buffers); /* for stackable file systems (lofs, wrapfs, cryptfs, etc.) */ EXPORT_SYMBOL(default_llseek); @@ -307,8 +316,6 @@ EXPORT_SYMBOL(tty_flip_buffer_push); EXPORT_SYMBOL(tty_get_baud_rate); EXPORT_SYMBOL(do_SAK); -EXPORT_SYMBOL(console_print); -EXPORT_SYMBOL(console_loglevel); /* filesystem registration */ EXPORT_SYMBOL(register_filesystem); @@ -433,23 +440,21 @@ EXPORT_SYMBOL(xtime); EXPORT_SYMBOL(do_gettimeofday); EXPORT_SYMBOL(do_settimeofday); - -#if !defined(__ia64__) +#ifndef __ia64__ EXPORT_SYMBOL(loops_per_jiffy); #endif - EXPORT_SYMBOL(kstat); EXPORT_SYMBOL(nr_running); /* misc */ EXPORT_SYMBOL(panic); -EXPORT_SYMBOL(printk); EXPORT_SYMBOL(sprintf); EXPORT_SYMBOL(vsprintf); EXPORT_SYMBOL(kdevname); EXPORT_SYMBOL(bdevname); EXPORT_SYMBOL(cdevname); EXPORT_SYMBOL(simple_strtoul); +EXPORT_SYMBOL(simple_strtoull); EXPORT_SYMBOL(system_utsname); /* UTS data */ EXPORT_SYMBOL(uts_sem); /* UTS semaphore */ #ifndef __mips__ @@ -464,6 +469,7 @@ EXPORT_SYMBOL(securebits); EXPORT_SYMBOL(cap_bset); EXPORT_SYMBOL(daemonize); +EXPORT_SYMBOL(csum_partial); /* for networking and md */ /* Program loader interfaces */ EXPORT_SYMBOL(setup_arg_pages); @@ -480,7 +486,6 @@ EXPORT_SYMBOL(sys_tz); EXPORT_SYMBOL(__wait_on_super); EXPORT_SYMBOL(file_fsync); -EXPORT_SYMBOL(fsync_inode_buffers); EXPORT_SYMBOL(clear_inode); EXPORT_SYMBOL(nr_async_pages); EXPORT_SYMBOL(___strtok); @@ -490,7 +495,6 @@ EXPORT_SYMBOL(get_empty_inode); EXPORT_SYMBOL(insert_inode_hash); EXPORT_SYMBOL(remove_inode_hash); -EXPORT_SYMBOL(buffer_insert_inode_queue); EXPORT_SYMBOL(make_bad_inode); EXPORT_SYMBOL(is_bad_inode); EXPORT_SYMBOL(event); @@ -512,10 +516,6 @@ /* binfmt_aout */ EXPORT_SYMBOL(get_write_access); -/* dynamic registering of consoles */ -EXPORT_SYMBOL(register_console); -EXPORT_SYMBOL(unregister_console); - /* time */ EXPORT_SYMBOL(get_fast_time); @@ -540,3 +540,12 @@ EXPORT_SYMBOL(tasklist_lock); EXPORT_SYMBOL(pidhash); + +/* dynamic sysrq registration */ +EXPORT_SYMBOL(handle_sysrq); +EXPORT_SYMBOL(__handle_sysrq_nolock); +EXPORT_SYMBOL(__sysrq_lock_table); +EXPORT_SYMBOL(__sysrq_unlock_table); +EXPORT_SYMBOL(__sysrq_get_key_op); +EXPORT_SYMBOL(__sysrq_put_key_op); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/module.c linux.ac/kernel/module.c --- linux.vanilla/kernel/module.c Sat Feb 17 00:02:37 2001 +++ linux.ac/kernel/module.c Tue Apr 3 17:55:18 2001 @@ -554,8 +554,8 @@ put_mod_name(name); /* Initialize the module. */ - mod->flags |= MOD_INITIALIZING; atomic_set(&mod->uc.usecount,1); + mod->flags |= MOD_INITIALIZING; if (mod->init && (error = mod->init()) != 0) { atomic_set(&mod->uc.usecount,0); mod->flags &= ~MOD_INITIALIZING; @@ -613,11 +613,6 @@ if (name_user) { if ((error = get_mod_name(name_user, &name)) < 0) goto out; - if (error == 0) { - error = -EINVAL; - put_mod_name(name); - goto out; - } error = -ENOENT; if ((mod = find_module(name)) == NULL) { put_mod_name(name); @@ -847,7 +842,6 @@ bufsize -= len; space += len; } - if (put_user(i, ret)) return -EFAULT; else @@ -876,8 +870,11 @@ info.addr = (unsigned long)mod; info.size = mod->size; info.flags = mod->flags; + + /* usecount is one too high here - report appropriately to + compensate for locking */ info.usecount = (mod_member_present(mod, can_unload) - && mod->can_unload ? -1 : atomic_read(&mod->uc.usecount)); + && mod->can_unload ? -1 : atomic_read(&mod->uc.usecount)-1); if (copy_to_user(buf, &info, sizeof(struct module_info))) return -EFAULT; @@ -909,15 +906,17 @@ goto out; } err = -ENOENT; - if (namelen == 0) - mod = &kernel_module; - else if ((mod = find_module(name)) == NULL) { + if ((mod = find_module(name)) == NULL) { put_mod_name(name); goto out; } put_mod_name(name); } + /* __MOD_ touches the flags. We must avoid that */ + + atomic_inc(&mod->uc.usecount); + switch (which) { case 0: @@ -942,6 +941,8 @@ err = -EINVAL; break; } + atomic_dec(&mod->uc.usecount); + out: unlock_kernel(); return err; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/panic.c linux.ac/kernel/panic.c --- linux.vanilla/kernel/panic.c Mon Oct 16 20:58:51 2000 +++ linux.ac/kernel/panic.c Tue Apr 3 17:55:18 2001 @@ -18,7 +18,6 @@ #include <linux/interrupt.h> asmlinkage void sys_sync(void); /* it's really int */ -extern void unblank_console(void); int panic_timeout; @@ -36,9 +35,8 @@ * panic - halt the system * @fmt: The text string to print * - * Display a message, then unblank the console and perform - * cleanups. Functions in the panic notifier list are called - * after the filesystem cache is flushed (when possible). + * Display a message, then perform cleanups. Functions in the panic + * notifier list are called after the filesystem cache is flushed (when possible). * * This function never returns. */ @@ -51,6 +49,7 @@ unsigned long caller = (unsigned long) __builtin_return_address(0); #endif + bust_spinlocks(1); va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); @@ -61,8 +60,7 @@ printk(KERN_EMERG "In idle task - not syncing\n"); else sys_sync(); - - unblank_console(); + bust_spinlocks(0); #ifdef CONFIG_SMP smp_send_stop(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/pm.c linux.ac/kernel/pm.c --- linux.vanilla/kernel/pm.c Tue Apr 3 17:32:29 2001 +++ linux.ac/kernel/pm.c Tue Apr 10 18:23:10 2001 @@ -22,6 +22,7 @@ #include <linux/spinlock.h> #include <linux/slab.h> #include <linux/pm.h> +#include <linux/interrupt.h> int pm_active; @@ -49,6 +50,9 @@ * Add a device to the list of devices that wish to be notified about * power management events. A &pm_dev structure is returned on success, * on failure the return is %NULL. + * + * The callback function will be called in process context and + * it may sleep. */ struct pm_dev *pm_register(pm_dev_t type, @@ -150,6 +154,10 @@ { int status = 0; int prev_state, next_state; + + if (in_interrupt()) + BUG(); + switch (rqst) { case PM_SUSPEND: case PM_RESUME: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/printk.c linux.ac/kernel/printk.c --- linux.vanilla/kernel/printk.c Tue Feb 13 21:15:05 2001 +++ linux.ac/kernel/printk.c Tue Apr 3 17:55:18 2001 @@ -12,6 +12,8 @@ * Modified for sysctl support, 1/8/97, Chris Horn. * Fixed SMP synchronization, 08/08/99, Manfred Spraul * manfreds@colorfullife.com + * Rewrote bits to get rid of console_lock + * 01Mar01 Andrew Morton <andrewm@uow.edu.au> */ #include <linux/mm.h> @@ -20,14 +22,14 @@ #include <linux/smp_lock.h> #include <linux/console.h> #include <linux/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> /* For in_interrupt() */ #include <asm/uaccess.h> -#define LOG_BUF_LEN (16384) +#define LOG_BUF_LEN (16384) /* This must be a power of two */ #define LOG_BUF_MASK (LOG_BUF_LEN-1) -static char buf[1024]; - /* printk's without a loglevel use this.. */ #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */ @@ -35,7 +37,6 @@ #define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */ #define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */ -unsigned long log_size; DECLARE_WAIT_QUEUE_HEAD(log_wait); /* Keep together for sysctl support */ @@ -44,15 +45,41 @@ int minimum_console_loglevel = MINIMUM_CONSOLE_LOGLEVEL; int default_console_loglevel = DEFAULT_CONSOLE_LOGLEVEL; -spinlock_t console_lock = SPIN_LOCK_UNLOCKED; +int oops_in_progress; +/* + * console_sem protects the console_drivers list, and also + * provides serialisation for access to the entire console + * driver system. + */ +static DECLARE_MUTEX(console_sem); struct console *console_drivers; + +/* + * logbuf_lock protects log_buf, log_start, log_end, con_start and logged_chars + * It is also used in interesting ways to provide interlocking in + * release_console_sem(). + */ +static spinlock_t logbuf_lock = SPIN_LOCK_UNLOCKED; + static char log_buf[LOG_BUF_LEN]; -static unsigned long log_start; -static unsigned long logged_chars; +#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK]) + +/* + * The indices into log_buf are not constrained to LOG_BUF_LEN - they + * must be masked before subscripting + */ +static unsigned long log_start; /* Index into log_buf: next char to be read by syslog() */ +static unsigned long con_start; /* Index into log_buf: next char to be sent to consoles */ +static unsigned long log_end; /* Index into log_buf: most-recently-written-char + 1 */ +static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */ + struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]; static int preferred_console = -1; +/* Flag: console code may call schedule() */ +static int console_may_schedule; + /* * Setup a list of consoles. Called from init/main.c */ @@ -120,6 +147,7 @@ * 6 -- Disable printk's to console * 7 -- Enable printk's to console * 8 -- Set level of messages printed to console + * 9 -- Return number of unread characters in the log buffer */ int do_syslog(int type, char * buf, int len) { @@ -143,22 +171,21 @@ error = verify_area(VERIFY_WRITE,buf,len); if (error) goto out; - error = wait_event_interruptible(log_wait, log_size); + error = wait_event_interruptible(log_wait, (log_start - log_end)); if (error) goto out; i = 0; - spin_lock_irq(&console_lock); - while (log_size && i < len) { - c = log_buf[log_start & LOG_BUF_MASK]; + spin_lock_irq(&logbuf_lock); + while ((log_start != log_end) && i < len) { + c = LOG_BUF(log_start); log_start++; - log_size--; - spin_unlock_irq(&console_lock); + spin_unlock_irq(&logbuf_lock); __put_user(c,buf); buf++; i++; - spin_lock_irq(&console_lock); + spin_lock_irq(&logbuf_lock); } - spin_unlock_irq(&console_lock); + spin_unlock_irq(&logbuf_lock); error = i; break; case 4: /* Read/clear last kernel messages */ @@ -177,12 +204,12 @@ count = len; if (count > LOG_BUF_LEN) count = LOG_BUF_LEN; - spin_lock_irq(&console_lock); + spin_lock_irq(&logbuf_lock); if (count > logged_chars) count = logged_chars; if (do_clear) logged_chars = 0; - limit = log_start + log_size; + limit = log_end; /* * __put_user() could sleep, and while we sleep * printk() could overwrite the messages @@ -191,14 +218,14 @@ */ for(i=0;i < count;i++) { j = limit-1-i; - if (j+LOG_BUF_LEN < log_start+log_size) + if (j+LOG_BUF_LEN < log_end) break; - c = log_buf[ j & LOG_BUF_MASK ]; - spin_unlock_irq(&console_lock); + c = LOG_BUF(j); + spin_unlock_irq(&logbuf_lock); __put_user(c,&buf[count-1-i]); - spin_lock_irq(&console_lock); + spin_lock_irq(&logbuf_lock); } - spin_unlock_irq(&console_lock); + spin_unlock_irq(&logbuf_lock); error = i; if(i != count) { int offset = count-error; @@ -211,31 +238,36 @@ break; case 5: /* Clear ring buffer */ - spin_lock_irq(&console_lock); + spin_lock_irq(&logbuf_lock); logged_chars = 0; - spin_unlock_irq(&console_lock); + spin_unlock_irq(&logbuf_lock); break; case 6: /* Disable logging to console */ - spin_lock_irq(&console_lock); + spin_lock_irq(&logbuf_lock); console_loglevel = minimum_console_loglevel; - spin_unlock_irq(&console_lock); + spin_unlock_irq(&logbuf_lock); break; case 7: /* Enable logging to console */ - spin_lock_irq(&console_lock); + spin_lock_irq(&logbuf_lock); console_loglevel = default_console_loglevel; - spin_unlock_irq(&console_lock); + spin_unlock_irq(&logbuf_lock); break; - case 8: + case 8: /* Set level of messages printed to console */ error = -EINVAL; if (len < 1 || len > 8) goto out; if (len < minimum_console_loglevel) len = minimum_console_loglevel; - spin_lock_irq(&console_lock); + spin_lock_irq(&logbuf_lock); console_loglevel = len; - spin_unlock_irq(&console_lock); + spin_unlock_irq(&logbuf_lock); error = 0; break; + case 9: /* Number of chars in the log buffer */ + spin_lock_irq(&logbuf_lock); + error = log_end - log_start; + spin_unlock_irq(&logbuf_lock); + break; default: error = -EINVAL; break; @@ -251,98 +283,258 @@ return do_syslog(type, buf, len); } -asmlinkage int printk(const char *fmt, ...) +/* + * Call the console drivers on a range of log_buf + */ +static void __call_console_drivers(unsigned long start, unsigned long end) { - va_list args; - int i; - char *msg, *p, *buf_end; - int line_feed; - static signed char msg_level = -1; - long flags; + struct console *con; - spin_lock_irqsave(&console_lock, flags); - va_start(args, fmt); - i = vsprintf(buf + 3, fmt, args); /* hopefully i < sizeof(buf)-4 */ - buf_end = buf + 3 + i; - va_end(args); - for (p = buf + 3; p < buf_end; p++) { - msg = p; - if (msg_level < 0) { - if ( - p[0] != '<' || - p[1] < '0' || - p[1] > '7' || - p[2] != '>' - ) { - p -= 3; - p[0] = '<'; - p[1] = default_message_loglevel + '0'; - p[2] = '>'; - } else - msg += 3; - msg_level = p[1] - '0'; + for (con = console_drivers; con; con = con->next) { + if ((con->flags & CON_ENABLED) && con->write) + con->write(con, &LOG_BUF(start), end - start); + } +} + +/* + * Write out chars from start to end - 1 inclusive + */ +static void _call_console_drivers(unsigned long start, unsigned long end, int msg_log_level) +{ + if (msg_log_level < console_loglevel && console_drivers && start != end) { + if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) { + /* wrapped write */ + __call_console_drivers(start & LOG_BUF_MASK, LOG_BUF_LEN); + __call_console_drivers(0, end & LOG_BUF_MASK); + } else { + __call_console_drivers(start, end); } - line_feed = 0; - for (; p < buf_end; p++) { - log_buf[(log_start+log_size) & LOG_BUF_MASK] = *p; - if (log_size < LOG_BUF_LEN) - log_size++; - else - log_start++; - - logged_chars++; - if (*p == '\n') { - line_feed = 1; + } +} + +/* + * Call the console drivers, asking them to write out + * log_buf[start] to log_buf[end - 1]. + * The console_sem must be held. + */ +static void call_console_drivers(unsigned long start, unsigned long end) +{ + unsigned long cur_index, start_print; + static int msg_level = -1; + + if (((long)(start - end)) > 0) + BUG(); + + cur_index = start; + start_print = start; + while (cur_index != end) { + if ( msg_level < 0 && + ((end - cur_index) > 2) && + LOG_BUF(cur_index + 0) == '<' && + LOG_BUF(cur_index + 1) >= '0' && + LOG_BUF(cur_index + 1) <= '7' && + LOG_BUF(cur_index + 2) == '>') + { + msg_level = LOG_BUF(cur_index + 1) - '0'; + cur_index += 3; + start_print = cur_index; + } + while (cur_index != end) { + char c = LOG_BUF(cur_index); + cur_index++; + + if (c == '\n') { + if (msg_level < 0) { + /* + * printk() has already given us loglevel tags in + * the buffer. This code is here in case the + * log buffer has wrapped right round and scribbled + * on those tags + */ + msg_level = default_message_loglevel; + } + _call_console_drivers(start_print, cur_index, msg_level); + msg_level = -1; + start_print = cur_index; break; } } - if (msg_level < console_loglevel && console_drivers) { - struct console *c = console_drivers; - while(c) { - if ((c->flags & CON_ENABLED) && c->write) - c->write(c, msg, p - msg + line_feed); - c = c->next; + } + _call_console_drivers(start_print, end, msg_level); +} + +static void emit_log_char(char c) +{ + LOG_BUF(log_end) = c; + log_end++; + if (log_end - log_start > LOG_BUF_LEN) + log_start = log_end - LOG_BUF_LEN; + if (log_end - con_start > LOG_BUF_LEN) + con_start = log_end - LOG_BUF_LEN; + if (logged_chars < LOG_BUF_LEN) + logged_chars++; +} + +/* + * This is printk. It can be called from any context. We want it to work. + * + * We try to grab the console_sem. If we succeed, it's easy - we log the output and + * call the console drivers. If we fail to get the semaphore we place the output + * into the log buffer and return. The current holder of the console_sem will + * notice the new output in release_console_sem() and will send it to the + * consoles before releasing the semaphore. + * + * One effect of this deferred printing is that code which calls printk() and + * then changes console_loglevel may break. This is because console_loglevel + * is inspected when the actual printing occurs. + */ +asmlinkage int printk(const char *fmt, ...) +{ + va_list args; + unsigned long flags; + int printed_len; + char *p; + unsigned long sr_copy; + static struct { + char buf[1024]; + unsigned long semi_random; + } printk_buf; + static int log_level_unknown = 1; + + if (oops_in_progress) { + /* If a crash is occurring, make sure we can't deadlock */ + spin_lock_init(&logbuf_lock); + /* And make sure that we print immediately */ + init_MUTEX(&console_sem); + } + + /* This stops the holder of console_sem just where we want him */ + spin_lock_irqsave(&logbuf_lock, flags); + + /* Emit the output into the temporary buffer */ + printk_buf.semi_random += jiffies; + sr_copy = printk_buf.semi_random; + va_start(args, fmt); + printed_len = vsprintf(printk_buf.buf, fmt, args); + va_end(args); + if (sr_copy != printk_buf.semi_random) + panic("buffer overrun in printk()"); + + /* + * Copy the output into log_buf. If the caller didn't provide + * appropriate log level tags, we insert them here + */ + for (p = printk_buf.buf; *p; p++) { + if (log_level_unknown) { + if (p[0] != '<' || p[1] < '0' || p[1] > '7' || p[2] != '>') { + emit_log_char('<'); + emit_log_char(default_message_loglevel + '0'); + emit_log_char('>'); } + log_level_unknown = 0; } - if (line_feed) - msg_level = -1; + emit_log_char(*p); + if (*p == '\n') + log_level_unknown = 1; + } + + if (!down_trylock(&console_sem)) { + /* + * We own the drivers. We can drop the spinlock and let + * release_console_sem() print the text + */ + spin_unlock_irqrestore(&logbuf_lock, flags); + console_may_schedule = 0; + release_console_sem(); + } else { + /* + * Someone else owns the drivers. We drop the spinlock, which + * allows the semaphore holder to proceed and to call the + * console drivers with the output which we just produced. + */ + spin_unlock_irqrestore(&logbuf_lock, flags); } - spin_unlock_irqrestore(&console_lock, flags); - wake_up_interruptible(&log_wait); - return i; + return printed_len; } +EXPORT_SYMBOL(printk); -void console_print(const char *s) +/** + * acquire_console_sem - lock the console system for exclusive use. + * + * Acquires a semaphore which guarantees that the caller has + * exclusive access to the console system and the console_drivers list. + * + * Can sleep, returns nothing. + */ +void acquire_console_sem(void) +{ + if (in_interrupt()) + BUG(); + down(&console_sem); + console_may_schedule = 1; +} +EXPORT_SYMBOL(acquire_console_sem); + +/** + * release_console_sem - unlock the console system + * + * Releases the semaphore which the caller holds on the console system + * and the console driver list. + * + * While the semaphore was held, console output may have been buffered + * by printk(). If this is the case, release_console_sem() emits + * the output prior to releasing the semaphore. + * + * If there is output waiting for klogd, we wake it up. + * + * release_console_sem() may be called from any context. + */ +void release_console_sem(void) { - struct console *c; unsigned long flags; - int len = strlen(s); + unsigned long _con_start, _log_end; + unsigned long must_wake_klogd = 0; - spin_lock_irqsave(&console_lock, flags); - c = console_drivers; - while(c) { - if ((c->flags & CON_ENABLED) && c->write) - c->write(c, s, len); - c = c->next; + for ( ; ; ) { + spin_lock_irqsave(&logbuf_lock, flags); + must_wake_klogd |= log_start - log_end; + if (con_start == log_end) + break; /* Nothing to print */ + _con_start = con_start; + _log_end = log_end; + con_start = log_end; /* Flush */ + spin_unlock_irqrestore(&logbuf_lock, flags); + call_console_drivers(_con_start, _log_end); } - spin_unlock_irqrestore(&console_lock, flags); + console_may_schedule = 0; + up(&console_sem); + spin_unlock_irqrestore(&logbuf_lock, flags); + if (must_wake_klogd && !oops_in_progress) + wake_up_interruptible(&log_wait); } -void unblank_console(void) +/** console_conditional_schedule - yield the CPU if required + * + * If the console code is currently allowed to sleep, and + * if this CPU should yield the CPU to another task, do + * so here. + * + * Must be called within acquire_console_sem(). + */ +void console_conditional_schedule(void) { - struct console *c; - unsigned long flags; - - spin_lock_irqsave(&console_lock, flags); - c = console_drivers; - while(c) { - if ((c->flags & CON_ENABLED) && c->unblank) - c->unblank(); - c = c->next; + if (console_may_schedule && current->need_resched) { + set_current_state(TASK_RUNNING); + schedule(); } - spin_unlock_irqrestore(&console_lock, flags); } +void console_print(const char *s) +{ + printk(KERN_EMERG "%s", s); +} +EXPORT_SYMBOL(console_print); + /* * The console driver calls this routine during kernel initialization * to register the console printing procedure with printk() and to @@ -351,11 +543,7 @@ */ void register_console(struct console * console) { - int i, j,len; - int p; - char buf[16]; - signed char msg_level = -1; - char *q; + int i; unsigned long flags; /* @@ -402,7 +590,7 @@ * Put this console in the list - keep the * preferred driver at the head of the list. */ - spin_lock_irqsave(&console_lock, flags); + acquire_console_sem(); if ((console->flags & CON_CONSDEV) || console_drivers == NULL) { console->next = console_drivers; console_drivers = console; @@ -410,57 +598,28 @@ console->next = console_drivers->next; console_drivers->next = console; } - if ((console->flags & CON_PRINTBUFFER) == 0) - goto done; - /* - * Print out buffered log messages. - */ - p = log_start & LOG_BUF_MASK; - - for (i=0,j=0; i < log_size; i++) { - buf[j++] = log_buf[p]; - p = (p+1) & LOG_BUF_MASK; - if (buf[j-1] != '\n' && i < log_size - 1 && j < sizeof(buf)-1) - continue; - buf[j] = 0; - q = buf; - len = j; - if (msg_level < 0) { - if(buf[0] == '<' && - buf[1] >= '0' && - buf[1] <= '7' && - buf[2] == '>') { - msg_level = buf[1] - '0'; - q = buf + 3; - len -= 3; - } else - { - msg_level = default_message_loglevel; - } - } - if (msg_level < console_loglevel) - console->write(console, q, len); - if (buf[j-1] == '\n') - msg_level = -1; - j = 0; + if (console->flags & CON_PRINTBUFFER) { + /* + * release_cosole_sem() will print out the buffered messages for us. + */ + spin_lock_irqsave(&logbuf_lock, flags); + con_start = log_start; + spin_unlock_irqrestore(&logbuf_lock, flags); } -done: - spin_unlock_irqrestore(&console_lock, flags); + release_console_sem(); } - +EXPORT_SYMBOL(register_console); int unregister_console(struct console * console) { struct console *a,*b; - unsigned long flags; int res = 1; - spin_lock_irqsave(&console_lock, flags); + acquire_console_sem(); if (console_drivers == console) { console_drivers=console->next; res = 0; - } else - { + } else { for (a=console_drivers->next, b=console_drivers ; a; b=a, a=b->next) { if (a == console) { @@ -479,13 +638,15 @@ preferred_console = -1; - spin_unlock_irqrestore(&console_lock, flags); + release_console_sem(); return res; } +EXPORT_SYMBOL(unregister_console); -/* - * Write a message to a certain tty, not just the console. This is used for - * messages that need to be redirected to a specific tty. +/** + * tty_write_message - write a message to a certain tty, not just the console. + * + * This is used for messages that need to be redirected to a specific tty. * We don't put it into the syslog queue right now maybe in the future if * really needed. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/sched.c linux.ac/kernel/sched.c --- linux.vanilla/kernel/sched.c Tue Apr 3 17:32:29 2001 +++ linux.ac/kernel/sched.c Sat Apr 14 01:45:45 2001 @@ -23,8 +23,10 @@ #include <linux/mm.h> #include <linux/init.h> #include <linux/smp_lock.h> +#include <linux/irq.h> #include <linux/interrupt.h> #include <linux/kernel_stat.h> +#include <linux/prefetch.h> #include <asm/uaccess.h> #include <asm/mmu_context.h> @@ -533,6 +535,9 @@ struct list_head *tmp; int this_cpu, c; + + spin_lock_prefetch(&runqueue_lock); + if (!current->active_mm) BUG(); need_resched_back: prev = current; @@ -739,7 +744,7 @@ state = p->state; if (state & mode) { WQ_NOTE_WAKER(curr); - if (try_to_wake_up(p, sync) && curr->flags && !--nr_exclusive) + if (try_to_wake_up(p, sync) && (curr->flags&WQ_FLAG_EXCLUSIVE) && !--nr_exclusive) break; } } @@ -765,6 +770,75 @@ } } +/* + * wake up processes in the wait queue depending on the state of a context bit in the flags + * - wakes up a process if the specified bit is set in the flags member + * - the context bit is cleared if the process is woken up + * - if the bit number is negative, then the loop stops at the first unset context bit encountered + * - returns the number of processes woken + */ +static inline int __wake_up_ctx_common (wait_queue_head_t *q, + int count, int bit, const int sync) +{ + struct list_head *tmp, *head; + struct task_struct *p; + int stop, woken; + + woken = 0; + stop = bit<0; + if (bit<0) bit = -bit; + + CHECK_MAGIC_WQHEAD(q); + head = &q->task_list; + WQ_CHECK_LIST_HEAD(head); + tmp = head->next; + while (tmp != head) { + wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list); + + tmp = tmp->next; + CHECK_MAGIC(curr->__magic); + p = curr->task; + if (!test_and_clear_bit(bit,&curr->flags)) { + if (stop) + break; + continue; + } + + WQ_NOTE_WAKER(curr); + try_to_wake_up(p,sync); + + woken++; + if (woken>=count) + break; + } + + return woken; +} + +int __wake_up_ctx(wait_queue_head_t *q, unsigned int mode, int count, int bit) +{ + int woken = 0; + if (q && count) { + unsigned long flags; + wq_read_lock_irqsave(&q->lock, flags); + woken = __wake_up_ctx_common(q, count, bit, 0); + wq_read_unlock_irqrestore(&q->lock, flags); + } + return woken; +} + +int __wake_up_ctx_sync(wait_queue_head_t *q, unsigned int mode, int count, int bit) +{ + int woken = 0; + if (q && count) { + unsigned long flags; + wq_read_lock_irqsave(&q->lock, flags); + woken = __wake_up_ctx_common(q, count, bit, 1); + wq_read_unlock_irqrestore(&q->lock, flags); + } + return woken; +} + #define SLEEP_ON_VAR \ unsigned long flags; \ wait_queue_t wait; \ @@ -1024,9 +1098,11 @@ int i; // Substract non-idle processes running on other CPUs. - for (i = 0; i < smp_num_cpus; i++) - if (aligned_data[i].schedule_data.curr != idle_task(i)) + for (i = 0; i < smp_num_cpus; i++) { + int cpu = cpu_logical_map(i); + if (aligned_data[cpu].schedule_data.curr != idle_task(cpu)) nr_pending--; + } #else // on UP this process is on the runqueue as well nr_pending--; @@ -1181,8 +1257,14 @@ printk(" task PC stack pid father child younger older\n"); #endif read_lock(&tasklist_lock); - for_each_task(p) + for_each_task(p) { + /* + * reset the NMI-timeout, listing all files on a slow + * console might take alot of time: + */ + touch_nmi_watchdog(); show_task(p); + } read_unlock(&tasklist_lock); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/sys.c linux.ac/kernel/sys.c --- linux.vanilla/kernel/sys.c Tue Apr 3 17:32:29 2001 +++ linux.ac/kernel/sys.c Tue Apr 3 17:55:18 2001 @@ -1089,7 +1089,7 @@ ? -EFAULT : 0; } -#if !defined(__ia64__) && !defined(__s390__) +#if !defined(__ia64__) /* * Back compatibility for getrlimit. Needed for some apps. @@ -1119,8 +1119,6 @@ return -EINVAL; if(copy_from_user(&new_rlim, rlim, sizeof(*rlim))) return -EFAULT; - if (new_rlim.rlim_cur < 0 || new_rlim.rlim_max < 0) - return -EINVAL; old_rlim = current->rlim + resource; if (((new_rlim.rlim_cur > old_rlim->rlim_max) || (new_rlim.rlim_max > old_rlim->rlim_max)) && diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/sysctl.c linux.ac/kernel/sysctl.c --- linux.vanilla/kernel/sysctl.c Sat Feb 17 00:02:37 2001 +++ linux.ac/kernel/sysctl.c Mon Apr 9 23:36:14 2001 @@ -77,7 +77,7 @@ #endif #ifdef CONFIG_ARCH_S390 -#ifdef CONFIG_IEEEFPU_EMULATION +#ifdef CONFIG_MATHEMU extern int sysctl_ieee_emulation_warnings; #endif extern int sysctl_userprocess_debug; @@ -242,7 +242,7 @@ &proc_dointvec_minmax, &sysctl_intvec, NULL, &minolduid, &maxolduid}, #ifdef CONFIG_ARCH_S390 -#ifdef CONFIG_IEEEFPU_EMULATION +#ifdef CONFIG_MATHEMU {KERN_IEEE_EMULATION_WARNINGS,"ieee_emulation_warnings", &sysctl_ieee_emulation_warnings,sizeof(int),0644,NULL,&proc_dointvec}, #endif @@ -270,6 +270,8 @@ &pgt_cache_water, 2*sizeof(int), 0644, NULL, &proc_dointvec}, {VM_PAGE_CLUSTER, "page-cluster", &page_cluster, sizeof(int), 0644, NULL, &proc_dointvec}, + {VM_MAX_MAP_COUNT, "max_map_count", + &max_map_count, sizeof(int), 0644, NULL, &proc_dointvec}, {0} }; @@ -292,8 +294,6 @@ 0644, NULL, &proc_dointvec}, {FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int), 0444, NULL, &proc_dointvec}, - {FS_MAXDQUOT, "dquot-max", &max_dquots, sizeof(int), - 0644, NULL, &proc_dointvec}, {FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int), 0444, NULL, &proc_dointvec}, {FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/timer.c linux.ac/kernel/timer.c --- linux.vanilla/kernel/timer.c Sun Dec 10 17:53:19 2000 +++ linux.ac/kernel/timer.c Tue Apr 3 17:55:18 2001 @@ -719,6 +719,12 @@ asmlinkage long sys_getpid(void) { /* This is SMP safe - current->pid doesn't change */ + /* This is crap because current->tgid can clash with a real + pid and a million other stupid problems + Fortunately you have to turn idiot mode on so you get what + you deserve. An exec also cleans up the mess so its not a + security risk, just a happy suprise for people dumb enough to + use it */ return current->tgid; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/lib/Makefile linux.ac/lib/Makefile --- linux.vanilla/lib/Makefile Fri Dec 29 22:07:24 2000 +++ linux.ac/lib/Makefile Sat Apr 14 15:23:35 2001 @@ -8,9 +8,9 @@ L_TARGET := lib.a -export-objs := cmdline.o +export-objs := cmdline.o rwsem.o -obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o +obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o bust_spinlocks.o rwsem.o ifneq ($(CONFIG_HAVE_DEC_LOCK),y) obj-y += dec_and_lock.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/lib/bust_spinlocks.c linux.ac/lib/bust_spinlocks.c --- linux.vanilla/lib/bust_spinlocks.c Thu Jan 1 01:00:00 1970 +++ linux.ac/lib/bust_spinlocks.c Wed Apr 11 23:49:02 2001 @@ -0,0 +1,41 @@ +/* + * lib/bust_spinlocks.c + * + * Provides a minimal bust_spinlocks for architectures which don't have one of their own. + * + * bust_spinlocks() clears any spinlocks which would prevent oops, die(), BUG() + * and panic() information from reaching the user. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/tty.h> +#include <linux/wait.h> +#include <linux/vt_kern.h> + +extern spinlock_t timerlist_lock; + +void bust_spinlocks(int yes) +{ + spin_lock_init(&timerlist_lock); + if (yes) { + oops_in_progress = 1; + } else { + int loglevel_save = console_loglevel; +#ifdef CONFIG_VT + unblank_screen(); +#endif + oops_in_progress = 0; + /* + * OK, the message is on the console. Now we call printk() + * without oops_in_progress set so that printk() will give klogd + * and the blanked console a poke. Hold onto your hats... + */ + console_loglevel = 15; /* NMI oopser may have shut the console up */ + printk(" "); + console_loglevel = loglevel_save; + } +} + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/lib/cmdline.c linux.ac/lib/cmdline.c --- linux.vanilla/lib/cmdline.c Sat Aug 12 03:14:46 2000 +++ linux.ac/lib/cmdline.c Sat Apr 14 01:46:37 2001 @@ -93,9 +93,9 @@ * megabyte, or one gigabyte, respectively. */ -unsigned long memparse (char *ptr, char **retptr) +unsigned long long memparse (char *ptr, char **retptr) { - unsigned long ret = simple_strtoul (ptr, retptr, 0); + unsigned long long ret = simple_strtoull (ptr, retptr, 0); switch (**retptr) { case 'G': diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/lib/rwsem.c linux.ac/lib/rwsem.c --- linux.vanilla/lib/rwsem.c Thu Jan 1 01:00:00 1970 +++ linux.ac/lib/rwsem.c Sat Apr 14 01:46:44 2001 @@ -0,0 +1,156 @@ +/* rwsem.c: R/W semaphores: contention handling functions + * + * Written by David Howells (dhowells@redhat.com). + * Derived from arch/i386/kernel/semaphore.c + */ +#include <linux/rwsem.h> +#include <linux/sched.h> +#include <linux/module.h> + +/* + * wait for the read lock to be granted + * - need to repeal the increment made inline by the caller + * - need to throw a write-lock style spanner into the works (sub 0x00010000 from count) + */ +struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait,tsk); + signed long count; + + rwsemdebug("[%d] Entering rwsem_down_read_failed(%08lx)\n",current->pid,sem->count); + + /* this waitqueue context flag will be cleared when we are granted the lock */ + __set_bit(RWSEM_WAITING_FOR_READ,&wait.flags); + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + + add_wait_queue_exclusive(&sem->wait, &wait); /* FIFO */ + + /* note that we're now waiting on the lock, but no longer actively read-locking */ + count = rwsem_atomic_update(RWSEM_WAITING_BIAS-RWSEM_ACTIVE_BIAS,sem); + rwsemdebug("X(%08lx)\n",count); + + /* if there are no longer active locks, wake the front queued process(es) up + * - it might even be this process, since the waker takes a more active part + */ + if (!(count & RWSEM_ACTIVE_MASK)) + rwsem_wake(sem); + + /* wait to be given the lock */ + for (;;) { + if (!test_bit(RWSEM_WAITING_FOR_READ,&wait.flags)) + break; + schedule(); + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + } + + remove_wait_queue(&sem->wait,&wait); + tsk->state = TASK_RUNNING; + + rwsemdebug("[%d] Leaving rwsem_down_read_failed(%08lx)\n",current->pid,sem->count); + + return sem; +} + +/* + * wait for the write lock to be granted + */ +struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait,tsk); + signed long count; + + rwsemdebug("[%d] Entering rwsem_down_write_failed(%08lx)\n",current->pid,sem->count); + + /* this waitqueue context flag will be cleared when we are granted the lock */ + __set_bit(RWSEM_WAITING_FOR_WRITE,&wait.flags); + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + + add_wait_queue_exclusive(&sem->wait, &wait); /* FIFO */ + + /* note that we're waiting on the lock, but no longer actively locking */ + count = rwsem_atomic_update(-RWSEM_ACTIVE_BIAS,sem); + rwsemdebug("[%d] updated(%08lx)\n",current->pid,count); + + /* if there are no longer active locks, wake the front queued process(es) up + * - it might even be this process, since the waker takes a more active part + */ + if (!(count & RWSEM_ACTIVE_MASK)) + rwsem_wake(sem); + + /* wait to be given the lock */ + for (;;) { + if (!test_bit(RWSEM_WAITING_FOR_WRITE,&wait.flags)) + break; + schedule(); + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + } + + remove_wait_queue(&sem->wait,&wait); + tsk->state = TASK_RUNNING; + + rwsemdebug("[%d] Leaving rwsem_down_write_failed(%08lx)\n",current->pid,sem->count); + + return sem; +} + +/* + * handle the lock being released whilst there are processes blocked on it that can now run + * - if we come here, then: + * - the 'active part' of the count (&0x0000ffff) reached zero (but may no longer be zero) + * - the 'waiting part' of the count (&0xffff0000) is negative (and will still be so) + */ +struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem) +{ + signed long count; + int woken; + + rwsemdebug("[%d] Entering rwsem_wake(%08lx)\n",current->pid,sem->count); + + try_again: + /* try to grab an 'activity' marker + * - need to make sure two copies of rwsem_wake() don't do this for two separate processes + * simultaneously + * - be horribly naughty, and only deal with the LSW of the atomic counter + */ + if (rwsem_cmpxchgw(sem,0,RWSEM_ACTIVE_BIAS)!=0) { + rwsemdebug("[%d] rwsem_wake: abort wakeup due to renewed activity\n",current->pid); + goto out; + } + + /* try to grant a single write lock if there's a writer at the front of the queue + * - note we leave the 'active part' of the count incremented by 1 and the waiting part + * incremented by 0x00010000 + */ + if (wake_up_ctx(&sem->wait,1,-RWSEM_WAITING_FOR_WRITE)==1) + goto out; + + /* grant an infinite number of read locks to the readers at the front of the queue + * - note we increment the 'active part' of the count by the number of readers just woken, + * less one for the activity decrement we've already done + */ + woken = wake_up_ctx(&sem->wait,65535,-RWSEM_WAITING_FOR_READ); + if (woken<=0) + goto counter_correction; + + woken *= RWSEM_ACTIVE_BIAS-RWSEM_WAITING_BIAS; + woken -= RWSEM_ACTIVE_BIAS; + rwsem_atomic_update(woken,sem); + + out: + rwsemdebug("[%d] Leaving rwsem_wake(%08lx)\n",current->pid,sem->count); + return sem; + + /* come here if we need to correct the counter for odd SMP-isms */ + counter_correction: + count = rwsem_atomic_update(-RWSEM_ACTIVE_BIAS,sem); + rwsemdebug("[%d] corrected(%08lx)\n",current->pid,count); + if (!(count & RWSEM_ACTIVE_MASK)) + goto try_again; + goto out; +} + +EXPORT_SYMBOL(rwsem_down_read_failed); +EXPORT_SYMBOL(rwsem_down_write_failed); +EXPORT_SYMBOL(rwsem_wake); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/lib/string.c linux.ac/lib/string.c --- linux.vanilla/lib/string.c Tue Apr 3 17:32:29 2001 +++ linux.ac/lib/string.c Tue Apr 10 18:23:18 2001 @@ -350,6 +350,8 @@ * @s: Pointer to the start of the area. * @c: The byte to fill the area with * @count: The size of the area. + * + * Do not use memset() to access IO space, use memset_io() instead. */ void * memset(void * s,int c,size_t count) { @@ -369,11 +371,11 @@ * @dest: Where to copy to * @count: The size of the area. * - * When using copies for I/O remember that bcopy and memcpy are entitled - * to do out of order writes and may well exactly that. + * Note that this is the same as memcpy(), with the arguments reversed. + * memcpy() is the standard, bcopy() is a legacy BSD function. * - * Note that this is the same as memcpy, with the arguments reversed. memcpy - * is the standard, bcopy is a legacy BSD function. + * You should not use this function to access IO space, use memcpy_toio() + * or memcpy_fromio() instead. */ char * bcopy(const char * src, char * dest, int count) { @@ -393,8 +395,8 @@ * @src: Where to copy from * @count: The size of the area. * - * When using copies for I/O remember that bcopy and memcpy are entitled - * to do out of order writes and may well exactly that. + * You should not use this function to access IO space, use memcpy_toio() + * or memcpy_fromio() instead. */ void * memcpy(void * dest,const void *src,size_t count) { @@ -414,7 +416,7 @@ * @src: Where to copy from * @count: The size of the area. * - * memmove copes with overlapping areas. + * Unlike memcpy(), memmove() copes with overlapping areas. */ void * memmove(void * dest,const void *src,size_t count) { @@ -439,7 +441,7 @@ #ifndef __HAVE_ARCH_MEMCMP /** - * memmove - Compare two areas of memory + * memcmp - Compare two areas of memory * @cs: One area of memory * @ct: Another area of memory * @count: The size of the area. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/lib/vsprintf.c linux.ac/lib/vsprintf.c --- linux.vanilla/lib/vsprintf.c Tue Apr 3 17:32:29 2001 +++ linux.ac/lib/vsprintf.c Tue Apr 3 17:55:18 2001 @@ -377,7 +377,7 @@ * sprintf - Format a string and place it in a buffer * @buf: The buffer to place the result into * @fmt: The format string to use - * @args: Arguments for the format string + * @...: Arguments for the format string */ int sprintf(char * buf, const char *fmt, ...) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/Makefile linux.ac/mm/Makefile --- linux.vanilla/mm/Makefile Fri Dec 29 22:07:24 2000 +++ linux.ac/mm/Makefile Tue Apr 3 17:55:18 2001 @@ -9,6 +9,8 @@ O_TARGET := mm.o +export-objs := shmem.o + obj-y := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \ vmalloc.o slab.o bootmem.o swap.o vmscan.o page_io.o \ page_alloc.o swap_state.o swapfile.o numa.o oom_kill.o \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/bootmem.c linux.ac/mm/bootmem.c --- linux.vanilla/mm/bootmem.c Wed Oct 18 23:18:41 2000 +++ linux.ac/mm/bootmem.c Tue Apr 3 17:55:18 2001 @@ -18,6 +18,7 @@ #include <linux/bootmem.h> #include <linux/mmzone.h> #include <asm/dma.h> +#include <asm/io.h> /* * Access to this subsystem has to be serialized externally. (this is @@ -176,6 +177,7 @@ preferred = 0; goto restart_scan; } + return NULL; found: if (start >= eidx) BUG(); @@ -316,7 +318,8 @@ /* * Whoops, we cannot satisfy the allocation request. */ - BUG(); + printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size); + panic("Out of memory"); return NULL; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/filemap.c linux.ac/mm/filemap.c --- linux.vanilla/mm/filemap.c Tue Apr 3 17:32:29 2001 +++ linux.ac/mm/filemap.c Sat Apr 14 01:47:09 2001 @@ -108,7 +108,6 @@ if (PageDirty(page)) BUG(); remove_page_from_inode_queue(page); remove_page_from_hash_queue(page); - page->mapping = NULL; } void remove_inode_page(struct page *page) @@ -206,6 +205,9 @@ if (!page->buffers || block_flushpage(page, 0)) lru_cache_del(page); + if (page->mapping->a_ops->truncatepage) + page->mapping->a_ops->truncatepage(page); + /* * We remove the page from the page cache _after_ we have * destroyed all buffer-cache references to it. Otherwise some @@ -285,6 +287,34 @@ spin_unlock(&pagecache_lock); } +/* + * This function is pretty much like __find_page_nolock(), but it only + * requires 2 arguments and doesn't mark the page as touched, making it + * ideal for ->writepage() clustering and other places where you don't + * want to mark the page referenced. + * + * The caller needs to hold the pagecache_lock. + */ +struct page * __find_page_simple(struct address_space *mapping, unsigned long index) +{ + struct page * page = *page_hash(mapping, index); + goto inside; + + for (;;) { + page = page->next_hash; +inside: + if (!page) + goto not_found; + if (page->mapping != mapping) + continue; + if (page->index == index) + break; + } + +not_found: + return page; +} + static inline struct page * __find_page_nolock(struct address_space *mapping, unsigned long offset, struct page *page) { goto inside; @@ -300,13 +330,14 @@ break; } /* - * Touching the page may move it to the active list. - * If we end up with too few inactive pages, we wake - * up kswapd. - */ - age_page_up(page); - if (inactive_shortage() > inactive_target / 2 && free_shortage()) - wakeup_kswapd(); + * Mark the page referenced, moving inactive pages to the + * active list. + */ + if (!PageActive(page)) + activate_page(page); + else + SetPageReferenced(page); + not_found: return page; } @@ -701,7 +732,7 @@ lock_page(page); /* Is the page still hashed? Ok, good.. */ - if (page->mapping) + if (page->mapping == mapping) return page; /* Nope: we raced. Release and try again.. */ @@ -735,7 +766,6 @@ { struct inode *inode = file->f_dentry->d_inode; struct address_space *mapping = inode->i_mapping; - struct page **hash; struct page *page; unsigned long start; @@ -756,8 +786,7 @@ */ spin_lock(&pagecache_lock); while (--index >= start) { - hash = page_hash(mapping, index); - page = __find_page_nolock(mapping, index, *hash); + page = __find_page_simple(mapping, index); if (!page) break; deactivate_page(page); @@ -1062,7 +1091,7 @@ for (;;) { struct page *page, **hash; - unsigned long end_index, nr; + unsigned long end_index, nr, ret; end_index = inode->i_size >> PAGE_CACHE_SHIFT; if (index > end_index) @@ -1110,13 +1139,13 @@ * "pos" here (the actor routine has to update the user buffer * pointers and the remaining count). */ - nr = actor(desc, page, offset, nr); - offset += nr; + ret = actor(desc, page, offset, nr); + offset += ret; index += offset >> PAGE_CACHE_SHIFT; offset &= ~PAGE_CACHE_MASK; page_cache_release(page); - if (nr && desc->count) + if (ret == nr && desc->count) continue; break; @@ -1209,7 +1238,7 @@ UPDATE_ATIME(inode); } -static int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size) +int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size) { char *kaddr; unsigned long left, count = desc->count; @@ -1262,21 +1291,29 @@ static int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset , unsigned long size) { - char *kaddr; ssize_t written; unsigned long count = desc->count; struct file *file = (struct file *) desc->buf; - mm_segment_t old_fs; if (size > count) size = count; - old_fs = get_fs(); - set_fs(KERNEL_DS); - kaddr = kmap(page); - written = file->f_op->write(file, kaddr + offset, size, &file->f_pos); - kunmap(page); - set_fs(old_fs); + if (file->f_op->writepage) { + written = file->f_op->writepage(file, page, offset, + size, &file->f_pos, size<count); + } else { + char *kaddr; + mm_segment_t old_fs; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + kaddr = kmap(page); + written = file->f_op->write(file, kaddr + offset, size, &file->f_pos); + kunmap(page); + + set_fs(old_fs); + } if (written < 0) { desc->error = written; written = 0; @@ -1659,7 +1696,7 @@ unsigned long end = address + size; int error = 0; - /* Aquire the lock early; it may be possible to avoid dropping + /* Acquire the lock early; it may be possible to avoid dropping * and reaquiring it repeatedly. */ spin_lock(&vma->vm_mm->page_table_lock); @@ -1923,7 +1960,7 @@ int error = 0; /* This caps the number of vma's this process can own */ - if (vma->vm_mm->map_count > MAX_MAP_COUNT) + if (vma->vm_mm->map_count > max_map_count) return -ENOMEM; if (start == vma->vm_start) { @@ -2023,9 +2060,7 @@ if (vma->vm_flags & VM_LOCKED) return -EINVAL; - flush_cache_range(vma->vm_mm, start, end); zap_page_range(vma->vm_mm, start, end - start); - flush_tlb_range(vma->vm_mm, start, end); return 0; } @@ -2408,7 +2443,7 @@ return page; } -static inline void remove_suid(struct inode *inode) +inline void remove_suid(struct inode *inode) { unsigned int mode; @@ -2449,9 +2484,13 @@ unsigned long written; long status; int err; + unsigned bytes; cached_page = NULL; + if (!access_ok(VERIFY_READ, buf, count)) + return -EFAULT; + down(&inode->i_sem); pos = *ppos; @@ -2474,26 +2513,64 @@ * Check whether we've reached the file size limit. */ err = -EFBIG; + if (limit != RLIM_INFINITY) { if (pos >= limit) { send_sig(SIGXFSZ, current, 0); goto out; } - if (count > limit - pos) { + if (pos > 0xFFFFFFFFULL || count > limit - (u32)pos) { + /* send_sig(SIGXFSZ, current, 0); */ + count = limit - (u32)pos; + } + } + + /* + * LFS rule + */ + if ( pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) { + if (pos >= MAX_NON_LFS) { send_sig(SIGXFSZ, current, 0); - count = limit - pos; + goto out; + } + if (count > MAX_NON_LFS - (u32)pos) { + /* send_sig(SIGXFSZ, current, 0); */ + count = MAX_NON_LFS - (u32)pos; } } - status = 0; - if (count) { - remove_suid(inode); - inode->i_ctime = inode->i_mtime = CURRENT_TIME; - mark_inode_dirty_sync(inode); + /* + * Are we about to exceed the fs block limit ? + * + * If we have written data it becomes a short write + * If we have exceeded without writing data we send + * a signal and give them an EFBIG. + * + * Linus frestrict idea will clean these up nicely.. + */ + + if (pos > inode->i_sb->s_maxbytes) + { + send_sig(SIGXFSZ, current, 0); + err = -EFBIG; + goto out; } + if (pos + count > inode->i_sb->s_maxbytes) + count = inode->i_sb->s_maxbytes - pos; + + if (count == 0) { + err = 0; + goto out; + } + + status = 0; + remove_suid(inode); + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + mark_inode_dirty_sync(inode); + while (count) { - unsigned long bytes, index, offset; + unsigned long index, offset; char *kaddr; int deactivate = 1; @@ -2503,12 +2580,13 @@ */ offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */ index = pos >> PAGE_CACHE_SHIFT; + bytes = PAGE_CACHE_SIZE - offset; if (bytes > count) { bytes = count; deactivate = 0; } - + /* * Bring in the user page that we will copy from _first_. * Otherwise there's a nasty deadlock on copying from the @@ -2532,9 +2610,9 @@ status = mapping->a_ops->prepare_write(file, page, offset, offset+bytes); if (status) - goto unlock; + goto sync_failure; kaddr = page_address(page); - status = copy_from_user(kaddr+offset, buf, bytes); + status = __copy_from_user(kaddr+offset, buf, bytes); flush_dcache_page(page); if (status) goto fail_write; @@ -2558,6 +2636,7 @@ if (status < 0) break; } +done: *ppos = pos; if (cached_page) @@ -2565,6 +2644,10 @@ /* For now, when the user asks for O_SYNC, we'll actually * provide O_DSYNC. */ + + /* [FIXME] Is this right - this will not sync partial writes that are + truncated by limits... */ + if ((status >= 0) && (file->f_flags & O_SYNC)) status = generic_osync_inode(inode, 1); /* 1 means datasync */ @@ -2578,6 +2661,13 @@ ClearPageUptodate(page); kunmap(page); goto unlock; +sync_failure: + UnlockPage(page); + deactivate_page(page); + page_cache_release(page); + if (pos + bytes > inode->i_size) + vmtruncate(inode, inode->i_size); + goto done; } void __init page_cache_init(unsigned long mempages) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/highmem.c linux.ac/mm/highmem.c --- linux.vanilla/mm/highmem.c Tue Nov 28 20:31:02 2000 +++ linux.ac/mm/highmem.c Tue Apr 17 17:37:09 2001 @@ -159,6 +159,19 @@ spin_unlock(&kmap_lock); } +#define POOL_SIZE 32 + +/* + * This lock gets no contention at all, normally. + */ +static spinlock_t emergency_lock = SPIN_LOCK_UNLOCKED; + +int nr_emergency_pages; +static LIST_HEAD(emergency_pages); + +int nr_emergency_bhs; +static LIST_HEAD(emergency_bhs); + /* * Simple bounce buffer support for highmem pages. * This will be moved to the block layer in 2.5. @@ -203,11 +216,44 @@ static inline void bounce_end_io (struct buffer_head *bh, int uptodate) { + struct page *page; + unsigned long flags; + struct list_head *tmp; struct buffer_head *bh_orig = (struct buffer_head *)(bh->b_private); bh_orig->b_end_io(bh_orig, uptodate); - __free_page(bh->b_page); - kmem_cache_free(bh_cachep, bh); + + page = bh->b_page; + /* + * No need to protect by spinlock - test doesnt + * have to be absolutely sharp. + */ + if (nr_emergency_pages >= POOL_SIZE) + __free_page(page); + else { + tmp = &emergency_pages; + spin_lock_irqsave(&emergency_lock, flags); + /* + * We are abusing page->list to manage + * the highmem emergency pool: + */ + list_add(&page->list, &emergency_pages); + nr_emergency_pages++; + spin_unlock_irqrestore(&emergency_lock, flags); + } + + if (nr_emergency_pages >= POOL_SIZE) + kmem_cache_free(bh_cachep, bh); + else { + tmp = &emergency_bhs; + spin_lock_irqsave(&emergency_lock, flags); + /* + * Ditto in the bh case, here we abuse b_inode_buffers: + */ + list_add(&bh->b_inode_buffers, &emergency_bhs); + nr_emergency_bhs++; + spin_unlock_irqrestore(&emergency_lock, flags); + } } static void bounce_end_io_write (struct buffer_head *bh, int uptodate) @@ -224,6 +270,84 @@ bounce_end_io(bh, uptodate); } +struct page *alloc_bounce_page (void) +{ + struct list_head *tmp; + struct page *page; + +repeat_alloc: + page = alloc_page(GFP_BOUNCE); + if (page) + return page; + /* + * No luck. First, kick the VM so it doesnt idle around while + * we are using up our emergency rations. + */ + wakeup_bdflush(0); + + /* + * Try to allocate from the emergency pool. + */ + tmp = &emergency_pages; + spin_lock_irq(&emergency_lock); + if (!list_empty(tmp)) { + page = list_entry(tmp->next, struct page, list); + list_del(tmp->next); + nr_emergency_pages--; + } + spin_unlock_irq(&emergency_lock); + if (page) + return page; + + printk(KERN_WARNING "mm: critical shortage of bounce buffers.\n"); + + run_task_queue(&tq_disk); + + current->policy |= SCHED_YIELD; + __set_current_state(TASK_RUNNING); + schedule_timeout(1); + goto repeat_alloc; +} + +struct buffer_head *alloc_bounce_bh (void) +{ + struct list_head *tmp; + struct buffer_head *bh; + +repeat_alloc: + bh = kmem_cache_alloc(bh_cachep, SLAB_BUFFER); + if (bh) + return bh; + /* + * No luck. First, kick the VM so it doesnt idle around while + * we are using up our emergency rations. + */ + wakeup_bdflush(0); + + /* + * Try to allocate from the emergency pool. + */ + tmp = &emergency_bhs; + spin_lock_irq(&emergency_lock); + if (!list_empty(tmp)) { + bh = list_entry(tmp->next, struct buffer_head, b_inode_buffers); + list_del(tmp->next); + nr_emergency_bhs--; + } + spin_unlock_irq(&emergency_lock); + if (bh) + return bh; + + printk(KERN_WARNING "mm: critical shortage of bounce bh's.\n"); + + run_task_queue(&tq_disk); + + current->policy |= SCHED_YIELD; + __set_current_state(TASK_RUNNING); + schedule_timeout(1); + goto repeat_alloc; +} + struct buffer_head * create_bounce(int rw, struct buffer_head * bh_orig) { struct page *page; @@ -232,24 +356,15 @@ if (!PageHighMem(bh_orig->b_page)) return bh_orig; -repeat_bh: - bh = kmem_cache_alloc(bh_cachep, SLAB_BUFFER); - if (!bh) { - wakeup_bdflush(1); /* Sets task->state to TASK_RUNNING */ - goto repeat_bh; - } + bh = alloc_bounce_bh(); /* * This is wasteful for 1k buffers, but this is a stopgap measure * and we are being ineffective anyway. This approach simplifies * things immensly. On boxes with more than 4GB RAM this should * not be an issue anyway. */ -repeat_page: - page = alloc_page(GFP_BUFFER); - if (!page) { - wakeup_bdflush(1); /* Sets task->state to TASK_RUNNING */ - goto repeat_page; - } + page = alloc_bounce_page(); + set_bh_page(bh, page, 0); bh->b_next = NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/memory.c linux.ac/mm/memory.c --- linux.vanilla/mm/memory.c Tue Apr 3 17:32:29 2001 +++ linux.ac/mm/memory.c Tue Apr 10 22:38:50 2001 @@ -38,15 +38,16 @@ #include <linux/mm.h> #include <linux/mman.h> +#include <linux/pagemap.h> #include <linux/swap.h> #include <linux/smp_lock.h> #include <linux/swapctl.h> #include <linux/iobuf.h> #include <linux/highmem.h> -#include <linux/pagemap.h> #include <asm/pgalloc.h> #include <asm/uaccess.h> +#include <asm/tlb.h> unsigned long max_mapnr; unsigned long num_physpages; @@ -262,37 +263,19 @@ /* * Return indicates whether a page was freed so caller can adjust rss */ -static inline int free_pte(pte_t pte) -{ - if (pte_present(pte)) { - struct page *page = pte_page(pte); - if ((!VALID_PAGE(page)) || PageReserved(page)) - return 0; - /* - * free_page() used to be able to clear swap cache - * entries. We may now have to do it manually. - */ - if (pte_dirty(pte) && page->mapping) - set_page_dirty(page); - free_page_and_swap_cache(page); - return 1; - } - swap_free(pte_to_swp_entry(pte)); - return 0; -} - static inline void forget_pte(pte_t page) { if (!pte_none(page)) { printk("forget_pte: old mapping existed!\n"); - free_pte(page); + BUG(); } } -static inline int zap_pte_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size) +static inline int zap_pte_range(mmu_gather_t *tlb, pmd_t * pmd, unsigned long address, unsigned long size) { - pte_t * pte; - int freed; + unsigned long offset; + pte_t * ptep; + int freed = 0; if (pmd_none(*pmd)) return 0; @@ -301,27 +284,29 @@ pmd_clear(pmd); return 0; } - pte = pte_offset(pmd, address); + ptep = pte_offset(pmd, address); address &= ~PMD_MASK; if (address + size > PMD_SIZE) size = PMD_SIZE - address; - size >>= PAGE_SHIFT; - freed = 0; - for (;;) { - pte_t page; - if (!size) - break; - page = ptep_get_and_clear(pte); - pte++; - size--; - if (pte_none(page)) + size &= PAGE_MASK; + for (offset=0; offset < size; ptep++, offset += PAGE_SIZE) { + pte_t pte = *ptep; + if (pte_none(pte)) continue; - freed += free_pte(page); + if (pte_present(pte)) { + freed ++; + /* This will eventually call __free_pte on the pte. */ + tlb_remove_page(tlb, ptep, address + offset); + } else { + swap_free(pte_to_swp_entry(pte)); + pte_clear(ptep); + } } + return freed; } -static inline int zap_pmd_range(struct mm_struct *mm, pgd_t * dir, unsigned long address, unsigned long size) +static inline int zap_pmd_range(mmu_gather_t *tlb, pgd_t * dir, unsigned long address, unsigned long size) { pmd_t * pmd; unsigned long end; @@ -341,7 +326,7 @@ end = PGDIR_SIZE; freed = 0; do { - freed += zap_pte_range(mm, pmd, address, end - address); + freed += zap_pte_range(tlb, pmd, address, end - address); address = (address + PMD_SIZE) & PMD_MASK; pmd++; } while (address < end); @@ -353,8 +338,9 @@ */ void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size) { + mmu_gather_t *tlb; pgd_t * dir; - unsigned long end = address + size; + unsigned long start = address, end = address + size; int freed = 0; dir = pgd_offset(mm, address); @@ -369,11 +355,18 @@ if (address >= end) BUG(); spin_lock(&mm->page_table_lock); + flush_cache_range(mm, address, end); + tlb = tlb_gather_mmu(mm); + do { - freed += zap_pmd_range(mm, dir, address, end - address); + freed += zap_pmd_range(tlb, dir, address, end - address); address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; } while (address && (address < end)); + + /* this will flush any remaining tlb entries */ + tlb_finish_mmu(tlb, start, end); + /* * Update rss for the mm_struct (not necessarily current->mm) * Notice that rss is an unsigned long. @@ -389,20 +382,33 @@ /* * Do a quick page-table lookup for a single page. */ -static struct page * follow_page(unsigned long address) +static struct page * follow_page(unsigned long address, int write) { pgd_t *pgd; pmd_t *pmd; + pte_t *ptep, pte; pgd = pgd_offset(current->mm, address); + if (pgd_none(*pgd) || pgd_bad(*pgd)) + goto out; + pmd = pmd_offset(pgd, address); - if (pmd) { - pte_t * pte = pte_offset(pmd, address); - if (pte && pte_present(*pte)) - return pte_page(*pte); + if (pmd_none(*pmd) || pmd_bad(*pmd)) + goto out; + + ptep = pte_offset(pmd, address); + if (!ptep) + goto out; + + pte = *ptep; + if (pte_present(pte)) { + if (!write || + (pte_write(pte) && pte_dirty(pte))) + return pte_page(pte); } - - return NULL; + +out: + return 0; } /* @@ -432,7 +438,7 @@ struct vm_area_struct * vma = 0; struct page * map; int i; - int datain = (rw == READ); + int to_user = (rw == READ); /* Make sure the iobuf is not already mapped somewhere. */ if (iobuf->nr_pages) @@ -455,13 +461,18 @@ iobuf->length = len; i = 0; + + spin_lock(&mm->page_table_lock); /* * First of all, try to fault in all of the necessary pages */ while (ptr < end) { if (!vma || ptr >= vma->vm_end) { + + spin_unlock(&mm->page_table_lock); vma = find_vma(current->mm, ptr); + if (!vma) goto out_unlock; if (vma->vm_start > ptr) { @@ -470,34 +481,49 @@ if (expand_stack(vma, ptr)) goto out_unlock; } - if (((datain) && (!(vma->vm_flags & VM_WRITE))) || - (!(vma->vm_flags & VM_READ))) { + if (((to_user) && (!(vma->vm_flags & VM_WRITE))) || + (!(vma->vm_flags & VM_READ))) { err = -EACCES; goto out_unlock; } + + spin_lock(&mm->page_table_lock); } - if (handle_mm_fault(current->mm, vma, ptr, datain) <= 0) - goto out_unlock; - spin_lock(&mm->page_table_lock); - map = follow_page(ptr); - if (!map) { + while (1) { + int ret; + + map = follow_page(ptr, to_user); + if (map) { + map = get_page_map(map); + if (map) { + flush_dcache_page(map); + atomic_inc(&map->count); + } else + printk (KERN_INFO + "Mapped page missing [%d]\n", + i); + break; + } + spin_unlock(&mm->page_table_lock); - dprintk (KERN_ERR "Missing page in map_user_kiobuf\n"); - goto out_unlock; + + ret = handle_mm_fault(current->mm, vma, ptr, to_user); + if (ret <= 0) { + if (ret) + err = -ENOMEM; + goto out_unlock; + } + + spin_lock(&mm->page_table_lock); } - map = get_page_map(map); - if (map) { - flush_dcache_page(map); - atomic_inc(&map->count); - } else - printk (KERN_INFO "Mapped page missing [%d]\n", i); - spin_unlock(&mm->page_table_lock); + iobuf->maplist[i] = map; iobuf->nr_pages = ++i; ptr += PAGE_SIZE; } + spin_unlock(&mm->page_table_lock); up_write(&mm->mmap_sem); dprintk ("map_user_kiobuf: end OK\n"); return 0; @@ -535,6 +561,39 @@ /* + * Mark all of the pages in a kiobuf as dirty + * + * We need to be able to deal with short reads from disk: if an IO error + * occurs, the number of bytes read into memory may be less than the + * size of the kiobuf, so we have to stop marking pages dirty once the + * requested byte count has been reached. + */ + +void mark_dirty_kiobuf(struct kiobuf *iobuf, int bytes) +{ + int index, offset, remaining; + struct page *page; + + index = iobuf->offset >> PAGE_SHIFT; + offset = iobuf->offset & ~PAGE_MASK; + remaining = bytes; + if (remaining > iobuf->length) + remaining = iobuf->length; + + while (remaining > 0 && index < iobuf->nr_pages) { + page = iobuf->maplist[index]; + + if (!PageReserved(page)) + SetPageDirty(page); + + remaining -= (PAGE_SIZE - offset); + offset = 0; + index++; + } +} + + +/* * Lock down all of the pages of a kiovec for IO. * * If any page is mapped twice in the kiovec, we return the error -EINVAL. @@ -655,6 +714,7 @@ } while (address && (address < end)); } +/* mm->page_table_lock must be held */ static inline int zeromap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size, pgprot_t prot) { @@ -734,6 +794,7 @@ } while (address && (address < end)); } +/* mm->page_table_lock must be held */ static inline int remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size, unsigned long phys_addr, pgprot_t prot) { @@ -815,6 +876,23 @@ } /* + * Work out if there are any other processes sharing this + * swap cache page. Never mind the buffers. + */ +static inline int exclusive_swap_page(struct page *page) +{ + unsigned int count; + + if (!PageLocked(page)) + BUG(); + if (!PageSwapCache(page)) + return 0; + count = page_count(page) - !!page->buffers; /* 2: us + swap cache */ + count += swap_count(page); /* +1: just swap cache */ + return count == 3; /* =3: total */ +} + +/* * This routine handles present pages, when users try to write * to a shared page. It is done by copying the page to a new address * and decrementing the shared-page counter for the old page. @@ -842,7 +920,10 @@ old_page = pte_page(pte); if (!VALID_PAGE(old_page)) goto bad_wp_page; - + + if (old_page == ZERO_PAGE(address)) + goto copy; + /* * We can avoid the copy if: * - we're the only user (count == 1) @@ -853,23 +934,23 @@ * marked dirty). */ switch (page_count(old_page)) { + int can_reuse; + case 3: + if (!old_page->buffers) + break; + /* FallThrough */ case 2: - /* - * Lock the page so that no one can look it up from - * the swap cache, grab a reference and start using it. - * Can not do lock_page, holding page_table_lock. - */ - if (!PageSwapCache(old_page) || TryLockPage(old_page)) + if (!PageSwapCache(old_page)) break; - if (is_page_shared(old_page)) { - UnlockPage(old_page); + if (TryLockPage(old_page)) break; - } + /* Recheck swapcachedness once the page is locked */ + can_reuse = exclusive_swap_page(old_page); UnlockPage(old_page); + if (!can_reuse) + break; /* FallThrough */ case 1: - if (PageReserved(old_page)) - break; flush_cache_page(vma, address); establish_pte(vma, address, page_table, pte_mkyoung(pte_mkdirty(pte_mkwrite(pte)))); return 1; /* Minor fault */ @@ -878,6 +959,8 @@ /* * Ok, we need to copy. Oh, well.. */ +copy: + set_pte(page_table, pte); spin_unlock(&mm->page_table_lock); new_page = alloc_page(GFP_HIGHUSER); spin_lock(&mm->page_table_lock); @@ -888,6 +971,11 @@ * Re-check the pte - we dropped the lock */ if (pte_same(*page_table, pte)) { + /* We are changing the pte, so get rid of the old + * one to avoid races with the hardware, this really + * only affects the accessed bit here. + */ + pte = ptep_get_and_clear(page_table); if (PageReserved(old_page)) ++mm->rss; break_cow(vma, old_page, new_page, address, page_table); @@ -903,8 +991,7 @@ return -1; } -static void vmtruncate_list(struct vm_area_struct *mpnt, - unsigned long pgoff, unsigned long partial) +static void vmtruncate_list(struct vm_area_struct *mpnt, unsigned long pgoff) { do { struct mm_struct *mm = mpnt->vm_mm; @@ -915,9 +1002,7 @@ /* mapping wholly truncated? */ if (mpnt->vm_pgoff >= pgoff) { - flush_cache_range(mm, start, end); zap_page_range(mm, start, len); - flush_tlb_range(mm, start, end); continue; } @@ -930,9 +1015,7 @@ /* Ok, partially affected.. */ start += diff << PAGE_SHIFT; len = (len - diff) << PAGE_SHIFT; - flush_cache_range(mm, start, end); zap_page_range(mm, start, len); - flush_tlb_range(mm, start, end); } while ((mpnt = mpnt->vm_next_share) != NULL); } @@ -945,9 +1028,9 @@ * between the file and the memory map for a potential last * incomplete page. Ugly, but necessary. */ -void vmtruncate(struct inode * inode, loff_t offset) +int vmtruncate(struct inode * inode, loff_t offset) { - unsigned long partial, pgoff; + unsigned long pgoff; struct address_space *mapping = inode->i_mapping; unsigned long limit; @@ -959,21 +1042,20 @@ goto out_unlock; pgoff = (offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; - partial = (unsigned long)offset & (PAGE_CACHE_SIZE - 1); if (mapping->i_mmap != NULL) - vmtruncate_list(mapping->i_mmap, pgoff, partial); + vmtruncate_list(mapping->i_mmap, pgoff); if (mapping->i_mmap_shared != NULL) - vmtruncate_list(mapping->i_mmap_shared, pgoff, partial); + vmtruncate_list(mapping->i_mmap_shared, pgoff); out_unlock: spin_unlock(&mapping->i_shared_lock); truncate_inode_pages(mapping, offset); - if (inode->i_op && inode->i_op->truncate) - inode->i_op->truncate(inode); - return; - + goto out_truncate; + do_expand: + if (offset > inode->i_sb->s_maxbytes) + goto out; limit = current->rlim[RLIMIT_FSIZE].rlim_cur; if (limit != RLIM_INFINITY) { if (inode->i_size >= limit) { @@ -987,13 +1069,23 @@ } inode->i_size = offset; if (inode->i_op && inode->i_op->truncate) + { + /* This doesnt scale but it is meant to be a 2.4 invariant */ + lock_kernel(); inode->i_op->truncate(inode); + unlock_kernel(); + } +out_truncate: + if (inode->i_op && inode->i_op->truncate) { + lock_kernel(); + inode->i_op->truncate(inode); + unlock_kernel(); + } + return 0; out: - return; + return -EFBIG; } - - /* * Primitive swap readahead code. We simply read an aligned block of * (1 << page_cluster) entries in the swap area. This method is chosen @@ -1037,6 +1129,7 @@ { struct page *page; pte_t pte; + int ret = 1; spin_unlock(&mm->page_table_lock); page = lookup_swap_cache(entry); @@ -1050,6 +1143,9 @@ return -1; } + /* Had to read the page from swap area: Major fault */ + ret = 2; + flush_page_to_ram(page); flush_icache_page(vma, page); } @@ -1077,7 +1173,7 @@ pte = mk_pte(page, vma->vm_page_prot); swap_free(entry); - if (write_access && !is_page_shared(page)) + if (write_access && exclusive_swap_page(page)) pte = pte_mkwrite(pte_mkdirty(pte)); UnlockPage(page); @@ -1085,7 +1181,7 @@ /* No need to invalidate - it was non-present before */ update_mmu_cache(vma, address, pte); - return 1; /* Minor fault */ + return ret; } /* @@ -1230,12 +1326,14 @@ return do_swap_page(mm, vma, address, pte, pte_to_swp_entry(entry), write_access); } + entry = ptep_get_and_clear(pte); if (write_access) { if (!pte_write(entry)) return do_wp_page(mm, vma, address, pte, entry); entry = pte_mkdirty(entry); } + entry = pte_mkyoung(entry); establish_pte(vma, address, pte, entry); return 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/mmap.c linux.ac/mm/mmap.c --- linux.vanilla/mm/mmap.c Tue Apr 3 17:32:29 2001 +++ linux.ac/mm/mmap.c Sat Apr 14 01:59:55 2001 @@ -38,6 +38,7 @@ }; int sysctl_overcommit_memory; +int max_map_count = DEFAULT_MAX_MAP_COUNT; /* Check that a process has enough memory to allocate a * new virtual mapping. @@ -64,6 +65,15 @@ free += atomic_read(&page_cache_size); free += nr_free_pages(); free += nr_swap_pages; + + /* + * This double-counts: the nrpages are both in the page-cache + * and in the swapper space. At the same time, this compensates + * for the swap-space over-allocation (ie "nr_swap_pages" being + * too small. + */ + free += swapper_space.nrpages; + /* * The code below doesn't account for free space in the inode * and dentry slab cache, slab cache fragmentation, inodes and @@ -158,10 +168,6 @@ if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE)) goto out; - /* Check if we have enough memory.. */ - if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT)) - goto out; - /* Ok, looks good - let it rip. */ if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk) goto out; @@ -218,20 +224,15 @@ return -EINVAL; /* Too many mappings? */ - if (mm->map_count > MAX_MAP_COUNT) + if (mm->map_count > max_map_count) return -ENOMEM; /* Obtain the address to map to. we verify (or select) it and ensure * that it represents a valid section of the address space. */ - if (flags & MAP_FIXED) { - if (addr & ~PAGE_MASK) - return -EINVAL; - } else { - addr = get_unmapped_area(addr, len); - if (!addr) - return -ENOMEM; - } + addr = get_unmapped_area(file, addr, len, pgoff, flags); + if (addr & ~PAGE_MASK) + return addr; /* Do simple checking here so the lower-level routines won't have * to. we assume access permissions have been handled by the open @@ -375,39 +376,58 @@ vma->vm_file = NULL; fput(file); /* Undo any partial mapping done by a device driver. */ - flush_cache_range(mm, vma->vm_start, vma->vm_end); zap_page_range(mm, vma->vm_start, vma->vm_end - vma->vm_start); - flush_tlb_range(mm, vma->vm_start, vma->vm_end); free_vma: kmem_cache_free(vm_area_cachep, vma); return error; } /* Get an address range which is currently unmapped. - * For mmap() without MAP_FIXED and shmat() with addr=0. - * Return value 0 means ENOMEM. + * For shmat() with addr=0. + * + * Ugly calling convention alert: + * Return value with the low bits set means error value, + * ie + * if (ret & ~PAGE_MASK) + * error = ret; + * + * This function "knows" that -ENOMEM has the bits set. */ #ifndef HAVE_ARCH_UNMAPPED_AREA -unsigned long get_unmapped_area(unsigned long addr, unsigned long len) +static inline unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { - struct vm_area_struct * vmm; + struct vm_area_struct *vma; if (len > TASK_SIZE) - return 0; + return -ENOMEM; if (!addr) addr = TASK_UNMAPPED_BASE; addr = PAGE_ALIGN(addr); - for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { - /* At this point: (!vmm || addr < vmm->vm_end). */ + for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) { + /* At this point: (!vma || addr < vma->vm_end). */ if (TASK_SIZE - len < addr) - return 0; - if (!vmm || addr + len <= vmm->vm_start) + return -ENOMEM; + if (!vma || addr + len <= vma->vm_start) return addr; - addr = vmm->vm_end; + addr = vma->vm_end; + } +} +#endif + +unsigned long get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) +{ + if (flags & MAP_FIXED) { + if (addr & ~PAGE_MASK) + return -EINVAL; + return addr; } + + if (file && file->f_op && file->f_op->get_unmapped_area) + return file->f_op->get_unmapped_area(file, addr, len, pgoff, flags); + + return arch_get_unmapped_area(file, addr, len, pgoff, flags); } -#endif #define vm_avl_empty (struct vm_area_struct *) NULL @@ -703,7 +723,7 @@ /* If we'll make "hole", check the vm areas limit */ if ((mpnt->vm_start < addr && mpnt->vm_end > addr+len) - && mm->map_count >= MAX_MAP_COUNT) + && mm->map_count >= max_map_count) return -ENOMEM; /* @@ -752,9 +772,7 @@ remove_shared_vm_struct(mpnt); mm->map_count--; - flush_cache_range(mm, st, end); zap_page_range(mm, st, size); - flush_tlb_range(mm, st, end); /* * Fix the mapping, and free the old area if it wasn't reused. @@ -821,7 +839,7 @@ > current->rlim[RLIMIT_AS].rlim_cur) return -ENOMEM; - if (mm->map_count > MAX_MAP_COUNT) + if (mm->map_count > max_map_count) return -ENOMEM; if (!vm_enough_memory(len >> PAGE_SHIFT)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/mremap.c linux.ac/mm/mremap.c --- linux.vanilla/mm/mremap.c Tue Apr 3 17:32:30 2001 +++ linux.ac/mm/mremap.c Sat Apr 14 01:47:19 2001 @@ -15,6 +15,11 @@ extern int vm_enough_memory(long pages); +/* + * Throughout all the following functions, mm->mmap_sem must be held for + * writing, and mm->page_table_lock must be held + */ + static inline pte_t *get_one_pte(struct mm_struct *mm, unsigned long addr) { pgd_t * pgd; @@ -119,7 +124,6 @@ while ((offset += PAGE_SIZE) < len) move_one_page(mm, new_addr + offset, old_addr + offset); zap_page_range(mm, new_addr, len); - flush_tlb_range(mm, new_addr, new_addr + len); return -1; } @@ -276,8 +280,13 @@ ret = -ENOMEM; if (flags & MREMAP_MAYMOVE) { if (!(flags & MREMAP_FIXED)) { - new_addr = get_unmapped_area(0, new_len); - if (!new_addr) + unsigned long map_flags = 0; + if (vma->vm_flags & VM_SHARED) + map_flags |= MAP_SHARED; + + new_addr = get_unmapped_area(vma->vm_file, 0, new_len, vma->vm_pgoff, map_flags); + ret = new_addr; + if (new_addr & ~PAGE_MASK) goto out; } ret = move_vma(vma, addr, old_len, new_len, new_addr); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/oom_kill.c linux.ac/mm/oom_kill.c --- linux.vanilla/mm/oom_kill.c Tue Nov 14 18:56:46 2000 +++ linux.ac/mm/oom_kill.c Tue Apr 3 17:55:19 2001 @@ -188,13 +188,17 @@ * * Returns 0 if there is still enough memory left, * 1 when we are out of memory (otherwise). + * + * Note that since __alloc_pages() never lets user + * allocations go below freepages.min, we have to + * use a slightly higher threshold here... */ int out_of_memory(void) { struct sysinfo swp_info; /* Enough free memory? Not OOM. */ - if (nr_free_pages() > freepages.min) + if (nr_free_pages() > freepages.min + 4) return 0; if (nr_free_pages() + nr_inactive_clean_pages() > freepages.low) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/page_alloc.c linux.ac/mm/page_alloc.c --- linux.vanilla/mm/page_alloc.c Tue Apr 3 17:32:30 2001 +++ linux.ac/mm/page_alloc.c Tue Apr 17 17:22:41 2001 @@ -299,21 +299,6 @@ !(current->flags & PF_MEMALLOC)) direct_reclaim = 1; - /* - * If we are about to get low on free pages and we also have - * an inactive page shortage, wake up kswapd. - */ - if (inactive_shortage() > inactive_target / 2 && free_shortage()) - wakeup_kswapd(); - /* - * If we are about to get low on free pages and cleaning - * the inactive_dirty pages would fix the situation, - * wake up bdflush. - */ - else if (free_shortage() && nr_inactive_dirty_pages > free_shortage() - && nr_inactive_dirty_pages >= freepages.high) - wakeup_bdflush(0); - try_again: /* * First, see if we have any zones with lots of free memory. @@ -397,6 +382,14 @@ page = __alloc_pages_limit(zonelist, order, PAGES_MIN, direct_reclaim); if (page) return page; + + /* + * If we dont want to try too hard then we can give up + * now + */ + + if(gfp_mask & __GFP_FAIL) + return NULL; /* * Damn, we didn't succeed. @@ -561,6 +554,23 @@ } /* + * Total amount of free (allocatable) RAM in a given zone. + */ +unsigned int nr_free_pages_zone (int zone_type) +{ + pg_data_t *pgdat; + unsigned int sum; + + sum = 0; + pgdat = pgdat_list; + while (pgdat) { + sum += (pgdat->node_zones+zone_type)->free_pages; + pgdat = pgdat->node_next; + } + return sum; +} + +/* * Total amount of inactive_clean (allocatable) RAM: */ unsigned int nr_inactive_clean_pages (void) @@ -579,14 +589,43 @@ } /* + * Total amount of inactive_clean (allocatable) RAM in a given zone. + */ +unsigned int nr_inactive_clean_pages_zone (int zone_type) +{ + pg_data_t *pgdat; + unsigned int sum; + + sum = 0; + pgdat = pgdat_list; + while (pgdat) { + sum += (pgdat->node_zones+zone_type)->inactive_clean_pages; + pgdat = pgdat->node_next; + } + return sum; +} + + +/* * Amount of free RAM allocatable as buffer memory: + * + * For HIGHMEM systems don't count HIGHMEM pages. + * This is function is still far from perfect for HIGHMEM systems, but + * it is close enough for the time being. */ unsigned int nr_free_buffer_pages (void) { unsigned int sum; - sum = nr_free_pages(); - sum += nr_inactive_clean_pages(); +#if CONFIG_HIGHMEM + sum = nr_free_pages_zone(ZONE_NORMAL) + + nr_free_pages_zone(ZONE_DMA) + + nr_inactive_clean_pages_zone(ZONE_NORMAL) + + nr_inactive_clean_pages_zone(ZONE_DMA); +#else + sum = nr_free_pages() + + nr_inactive_clean_pages(); +#endif sum += nr_inactive_dirty_pages; /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/page_io.c linux.ac/mm/page_io.c --- linux.vanilla/mm/page_io.c Mon Dec 4 23:38:02 2000 +++ linux.ac/mm/page_io.c Tue Apr 3 17:55:19 2001 @@ -42,11 +42,6 @@ int block_size; struct inode *swapf = 0; - /* Don't allow too many pending pages in flight.. */ - if ((rw == WRITE) && atomic_read(&nr_async_pages) > - pager_daemon.swap_cluster * (1 << page_cluster)) - wait = 1; - if (rw == READ) { ClearPageUptodate(page); kstat.pswpin++; @@ -74,7 +69,7 @@ } else { return 0; } - if (!wait) { + if (!wait && rw == WRITE) { SetPageDecrAfter(page); atomic_inc(&nr_async_pages); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/shmem.c linux.ac/mm/shmem.c --- linux.vanilla/mm/shmem.c Tue Apr 3 17:32:30 2001 +++ linux.ac/mm/shmem.c Sat Apr 14 01:47:25 2001 @@ -1,5 +1,5 @@ /* - * Resizable simple shmem filesystem for Linux. + * Resizable virtual memory filesystem for Linux. * * Copyright (C) 2000 Linus Torvalds. * 2000 Transmeta Corp. @@ -9,14 +9,12 @@ */ /* - * This shared memory handling is heavily based on the ramfs. It - * extends the ramfs by the ability to use swap which would makes it a - * completely usable filesystem. - * - * But read and write are not supported (yet) - * + * This virtual memory filesystem is heavily based on the ramfs. It + * extends ramfs by the ability to use swap and honor resource limits + * which makes it a completely usable filesystem. */ +#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/devfs_fs_kernel.h> @@ -31,7 +29,8 @@ #include <asm/uaccess.h> -#define SHMEM_MAGIC 0x01021994 +/* This magic number is used in glibc for posix shared memory */ +#define TMPFS_MAGIC 0x01021994 #define ENTRIES_PER_PAGE (PAGE_SIZE/sizeof(unsigned long)) #define NR_SINGLE (ENTRIES_PER_PAGE + SHMEM_NR_DIRECT) @@ -42,33 +41,74 @@ static struct inode_operations shmem_inode_operations; static struct file_operations shmem_dir_operations; static struct inode_operations shmem_dir_inode_operations; -static struct vm_operations_struct shmem_shared_vm_ops; -static struct vm_operations_struct shmem_private_vm_ops; +static struct inode_operations shmem_symlink_inode_operations; +static struct vm_operations_struct shmem_vm_ops; LIST_HEAD (shmem_inodes); static spinlock_t shmem_ilock = SPIN_LOCK_UNLOCKED; +#define BLOCKS_PER_PAGE (PAGE_SIZE/512) + +/* + * shmem_recalc_inode - recalculate the size of an inode + * + * @inode: inode to recalc + * + * We have to calculate the free blocks since the mm can drop pages + * behind our back + * + * But we know that normally + * inodes->i_blocks/BLOCKS_PER_PAGE == + * inode->i_mapping->nrpages + info->swapped + * + * So the mm freed + * inodes->i_blocks/BLOCKS_PER_PAGE - + * (inode->i_mapping->nrpages + info->swapped) + * + * It has to be called with the spinlock held. + */ + +static void shmem_recalc_inode(struct inode * inode) +{ + unsigned long freed; + + freed = (inode->i_blocks/BLOCKS_PER_PAGE) - + (inode->i_mapping->nrpages + inode->u.shmem_i.swapped); + if (freed){ + struct shmem_sb_info * info = &inode->i_sb->u.shmem_sb; + inode->i_blocks -= freed*BLOCKS_PER_PAGE; + spin_lock (&info->stat_lock); + info->free_blocks += freed; + spin_unlock (&info->stat_lock); + } +} + static swp_entry_t * shmem_swp_entry (struct shmem_inode_info *info, unsigned long index) { + unsigned long offset; + if (index < SHMEM_NR_DIRECT) return info->i_direct+index; index -= SHMEM_NR_DIRECT; - if (index >= ENTRIES_PER_PAGE*ENTRIES_PER_PAGE) - return NULL; + offset = index % ENTRIES_PER_PAGE; + index /= ENTRIES_PER_PAGE; + + if (index >= ENTRIES_PER_PAGE) + return ERR_PTR(-EFBIG); if (!info->i_indirect) { info->i_indirect = (swp_entry_t **) get_zeroed_page(GFP_USER); if (!info->i_indirect) - return NULL; + return ERR_PTR(-ENOMEM); } - if(!(info->i_indirect[index/ENTRIES_PER_PAGE])) { - info->i_indirect[index/ENTRIES_PER_PAGE] = (swp_entry_t *) get_zeroed_page(GFP_USER); - if (!info->i_indirect[index/ENTRIES_PER_PAGE]) - return NULL; + if(!(info->i_indirect[index])) { + info->i_indirect[index] = (swp_entry_t *) get_zeroed_page(GFP_USER); + if (!info->i_indirect[index]) + return ERR_PTR(-ENOMEM); } - return info->i_indirect[index/ENTRIES_PER_PAGE]+index%ENTRIES_PER_PAGE; + return info->i_indirect[index]+offset; } static int shmem_free_swp(swp_entry_t *dir, unsigned int count) @@ -81,13 +121,13 @@ if (!ptr->val) continue; entry = *ptr; - swap_free (entry); *ptr = (swp_entry_t){0}; freed++; - if (!(page = lookup_swap_cache(entry))) - continue; - delete_from_swap_cache(page); - page_cache_release(page); + if ((page = lookup_swap_cache(entry)) != NULL) { + delete_from_swap_cache(page); + page_cache_release(page); + } + swap_free (entry); } return freed; } @@ -98,7 +138,6 @@ * @dir: pointer to swp_entries * @size: number of entries in dir * @start: offset to start from - * @inode: inode for statistics * @freed: counter for freed pages * * It frees the swap entries from dir+start til dir+size @@ -108,7 +147,7 @@ static unsigned long shmem_truncate_part (swp_entry_t * dir, unsigned long size, - unsigned long start, struct inode * inode, unsigned long *freed) { + unsigned long start, unsigned long *freed) { if (start > size) return start - size; if (dir) @@ -117,56 +156,28 @@ return 0; } -/* - * shmem_recalc_inode - recalculate the size of an inode - * - * @inode: inode to recalc - * - * We have to calculate the free blocks since the mm can drop pages - * behind our back - * - * But we know that normally - * inodes->i_blocks == inode->i_mapping->nrpages + info->swapped - * - * So the mm freed - * inodes->i_blocks - (inode->i_mapping->nrpages + info->swapped) - * - * It has to be called with the spinlock held. - */ - -static void shmem_recalc_inode(struct inode * inode) -{ - unsigned long freed; - - freed = inode->i_blocks - - (inode->i_mapping->nrpages + inode->u.shmem_i.swapped); - if (freed){ - struct shmem_sb_info * info = &inode->i_sb->u.shmem_sb; - inode->i_blocks -= freed; - spin_lock (&info->stat_lock); - info->free_blocks += freed; - spin_unlock (&info->stat_lock); - } -} - static void shmem_truncate (struct inode * inode) { int clear_base; - unsigned long start; + unsigned long index, start; unsigned long freed = 0; - swp_entry_t **base, **ptr; + swp_entry_t **base, **ptr, **last; struct shmem_inode_info * info = &inode->u.shmem_i; + inode->i_ctime = inode->i_mtime = CURRENT_TIME; spin_lock (&info->lock); - start = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + index = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + if (index > info->max_index) + goto out; - start = shmem_truncate_part (info->i_direct, SHMEM_NR_DIRECT, start, inode, &freed); + start = shmem_truncate_part (info->i_direct, SHMEM_NR_DIRECT, index, &freed); if (!(base = info->i_indirect)) - goto out;; + goto out; clear_base = 1; - for (ptr = base; ptr < base + ENTRIES_PER_PAGE; ptr++) { + last = base + ((info->max_index - SHMEM_NR_DIRECT + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE); + for (ptr = base; ptr < last; ptr++) { if (!start) { if (!*ptr) continue; @@ -176,16 +187,16 @@ continue; } clear_base = 0; - start = shmem_truncate_part (*ptr, ENTRIES_PER_PAGE, start, inode, &freed); + start = shmem_truncate_part (*ptr, ENTRIES_PER_PAGE, start, &freed); } - if (!clear_base) - goto out; - - free_page ((unsigned long)base); - info->i_indirect = 0; + if (clear_base) { + free_page ((unsigned long)base); + info->i_indirect = 0; + } out: + info->max_index = index; info->swapped -= freed; shmem_recalc_inode(inode); spin_unlock (&info->lock); @@ -207,15 +218,29 @@ } /* - * Move the page from the page cache to the swap cache + * Move the page from the page cache to the swap cache. + * + * The page lock prevents multiple occurences of shmem_writepage at + * once. We still need to guard against racing with + * shmem_getpage_locked(). */ static int shmem_writepage(struct page * page) { - int error; + int error = 0; struct shmem_inode_info *info; swp_entry_t *entry, swap; + struct inode *inode; - info = &page->mapping->host->u.shmem_i; + if (!PageLocked(page)) + BUG(); + + /* Only move to the swap cache if there are no other users of + * the page. */ + if (atomic_read(&page->count) > 2) + goto out; + + inode = page->mapping->host; + info = &inode->u.shmem_i; swap = __get_swap_page(2); if (!swap.val) { set_page_dirty(page); @@ -224,17 +249,15 @@ } spin_lock(&info->lock); - shmem_recalc_inode(page->mapping->host); - entry = shmem_swp_entry (info, page->index); - if (!entry) /* this had been allocted on page allocation */ + entry = shmem_swp_entry(info, page->index); + if (IS_ERR(entry)) /* this had been allocted on page allocation */ BUG(); + shmem_recalc_inode(page->mapping->host); error = -EAGAIN; - if (entry->val) { - __swap_free(swap, 2); - goto out; - } + if (entry->val) + BUG(); - *entry = swap; + *entry = swap; error = 0; /* Remove the from the page cache */ lru_cache_del(page); @@ -245,97 +268,185 @@ page_cache_release(page); set_page_dirty(page); info->swapped++; -out: + spin_unlock(&info->lock); +out: UnlockPage(page); return error; } /* - * shmem_nopage - either get the page from swap or allocate a new one + * shmem_getpage_locked - either get the page from swap or allocate a new one * * If we allocate a new one we do not mark it dirty. That's up to the * vm. If we swap it in we mark it dirty since we also free the swap * entry since a page cannot live in both the swap and page cache + * + * Called with the inode locked, so it cannot race with itself, but we + * still need to guard against racing with shm_writepage(), which might + * be trying to move the page to the swap cache as we run. */ -struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int no_share) +static struct page * shmem_getpage_locked(struct inode * inode, unsigned long idx) { - unsigned long size; - struct page * page; - unsigned int idx; - swp_entry_t *entry; - struct inode * inode = vma->vm_file->f_dentry->d_inode; struct address_space * mapping = inode->i_mapping; struct shmem_inode_info *info; + struct page * page; + swp_entry_t *entry; - idx = (address - vma->vm_start) >> PAGE_SHIFT; - idx += vma->vm_pgoff; - - down (&inode->i_sem); - size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; - page = NOPAGE_SIGBUS; - if ((idx >= size) && (vma->vm_mm == current->mm)) - goto out; + info = &inode->u.shmem_i; - /* retry, we may have slept */ - page = __find_lock_page(mapping, idx, page_hash (mapping, idx)); +repeat: + page = find_lock_page(mapping, idx); if (page) - goto cached_page; + return page; - info = &inode->u.shmem_i; entry = shmem_swp_entry (info, idx); - if (!entry) - goto oom; + if (IS_ERR(entry)) + return (void *)entry; + spin_lock (&info->lock); - shmem_recalc_inode(inode); - spin_unlock (&info->lock); + + /* The shmem_swp_entry() call may have blocked, and + * shmem_writepage may have been moving a page between the page + * cache and swap cache. We need to recheck the page cache + * under the protection of the info->lock spinlock. */ + + page = __find_get_page(mapping, idx, page_hash(mapping, idx)); + if (page) { + if (TryLockPage(page)) + goto wait_retry; + spin_unlock (&info->lock); + return page; + } + if (entry->val) { unsigned long flags; /* Look it up and read it in.. */ - page = lookup_swap_cache(*entry); + page = __find_get_page(&swapper_space, entry->val, + page_hash(&swapper_space, entry->val)); if (!page) { + spin_unlock (&info->lock); lock_kernel(); swapin_readahead(*entry); page = read_swap_cache(*entry); unlock_kernel(); if (!page) - goto oom; + return ERR_PTR(-ENOMEM); + if (!Page_Uptodate(page)) { + page_cache_release(page); + return ERR_PTR(-EIO); + } + + /* Too bad we can't trust this page, because we + * dropped the info->lock spinlock */ + page_cache_release(page); + goto repeat; } /* We have to this with page locked to prevent races */ - spin_lock (&info->lock); + if (TryLockPage(page)) + goto wait_retry; + + if (swap_count(page) > 2) + BUG(); + swap_free(*entry); - lock_page(page); - delete_from_swap_cache_nolock(page); *entry = (swp_entry_t) {0}; + delete_from_swap_cache_nolock(page); flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_referenced) | (1 << PG_arch_1)); page->flags = flags | (1 << PG_dirty); add_to_page_cache_locked(page, mapping, idx); info->swapped--; spin_unlock (&info->lock); } else { + spin_unlock (&info->lock); spin_lock (&inode->i_sb->u.shmem_sb.stat_lock); if (inode->i_sb->u.shmem_sb.free_blocks == 0) goto no_space; inode->i_sb->u.shmem_sb.free_blocks--; spin_unlock (&inode->i_sb->u.shmem_sb.stat_lock); - /* Ok, get a new page */ + + /* Ok, get a new page. We don't have to worry about the + * info->lock spinlock here: we cannot race against + * shm_writepage because we have already verified that + * there is no page present either in memory or in the + * swap cache, so we are guaranteed to be populating a + * new shm entry. The inode semaphore we already hold + * is enough to make this atomic. */ page = page_cache_alloc(mapping); if (!page) - goto oom; - clear_user_highpage(page, address); - inode->i_blocks++; + return ERR_PTR(-ENOMEM); + clear_highpage(page); + inode->i_blocks += BLOCKS_PER_PAGE; add_to_page_cache (page, mapping, idx); } + /* We have the page */ - SetPageUptodate (page); + SetPageUptodate(page); if (info->locked) page_cache_get(page); + return page; +no_space: + spin_unlock (&inode->i_sb->u.shmem_sb.stat_lock); + return ERR_PTR(-ENOSPC); -cached_page: - UnlockPage (page); - up(&inode->i_sem); +wait_retry: + spin_unlock (&info->lock); + wait_on_page(page); + page_cache_release(page); + goto repeat; +} + +static int shmem_getpage(struct inode * inode, unsigned long idx, struct page **ptr) +{ + struct address_space * mapping = inode->i_mapping; + int error; + + *ptr = NOPAGE_SIGBUS; + if (inode->i_size <= (loff_t) idx * PAGE_CACHE_SIZE) + return -EFAULT; + + *ptr = __find_get_page(mapping, idx, page_hash(mapping, idx)); + if (*ptr) { + if (Page_Uptodate(*ptr)) + return 0; + page_cache_release(*ptr); + } + + down (&inode->i_sem); + /* retest we may have slept */ + if (inode->i_size < (loff_t) idx * PAGE_CACHE_SIZE) + goto sigbus; + *ptr = shmem_getpage_locked(inode, idx); + if (IS_ERR (*ptr)) + goto failed; + UnlockPage(*ptr); + up (&inode->i_sem); + return 0; +failed: + up (&inode->i_sem); + error = PTR_ERR(*ptr); + *ptr = NOPAGE_OOM; + if (error != -EFBIG) + *ptr = NOPAGE_SIGBUS; + return error; +sigbus: + *ptr = NOPAGE_SIGBUS; + return -EFAULT; +} + +struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int no_share) +{ + struct page * page; + unsigned int idx; + struct inode * inode = vma->vm_file->f_dentry->d_inode; + + idx = (address - vma->vm_start) >> PAGE_SHIFT; + idx += vma->vm_pgoff; + + if (shmem_getpage(inode, idx, &page)) + return page; if (no_share) { struct page *new_page = page_cache_alloc(inode->i_mapping); @@ -351,13 +462,45 @@ flush_page_to_ram (page); return(page); -no_space: - spin_unlock (&inode->i_sb->u.shmem_sb.stat_lock); -oom: - page = NOPAGE_OOM; -out: +} + +void shmem_lock(struct file * file, int lock) +{ + struct inode * inode = file->f_dentry->d_inode; + struct shmem_inode_info * info = &inode->u.shmem_i; + struct page * page; + unsigned long idx, size; + + if (info->locked == lock) + return; + down(&inode->i_sem); + info->locked = lock; + size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + for (idx = 0; idx < size; idx++) { + page = find_lock_page(inode->i_mapping, idx); + if (!page) + continue; + if (!lock) { + /* release the extra count and our reference */ + page_cache_release(page); + page_cache_release(page); + } + UnlockPage(page); + } up(&inode->i_sem); - return page; +} + +static int shmem_mmap(struct file * file, struct vm_area_struct * vma) +{ + struct vm_operations_struct * ops; + struct inode *inode = file->f_dentry->d_inode; + + ops = &shmem_vm_ops; + if (!inode->i_sb || !S_ISREG(inode->i_mode)) + return -EACCES; + UPDATE_ATIME(inode); + vma->vm_ops = ops; + return 0; } struct inode *shmem_get_inode(struct super_block *sb, int mode, int dev) @@ -392,11 +535,13 @@ inode->i_fop = &shmem_file_operations; break; case S_IFDIR: + inode->i_nlink++; inode->i_op = &shmem_dir_inode_operations; inode->i_fop = &shmem_dir_operations; break; case S_IFLNK: - BUG(); + inode->i_op = &shmem_symlink_inode_operations; + break; } spin_lock (&shmem_ilock); list_add (&inode->u.shmem_i.list, &shmem_inodes); @@ -405,49 +550,242 @@ return inode; } +#ifdef CONFIG_TMPFS +static ssize_t +shmem_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur; + loff_t pos; + struct page *page; + unsigned long written; + long status; + int err; + + + down(&inode->i_sem); + + pos = *ppos; + err = -EINVAL; + if (pos < 0) + goto out; + + err = file->f_error; + if (err) { + file->f_error = 0; + goto out; + } + + written = 0; + + if (file->f_flags & O_APPEND) + pos = inode->i_size; + + /* + * Check whether we've reached the file size limit. + */ + err = -EFBIG; + if (limit != RLIM_INFINITY) { + if (pos >= limit) { + send_sig(SIGXFSZ, current, 0); + goto out; + } + if (count > limit - pos) { + send_sig(SIGXFSZ, current, 0); + count = limit - pos; + } + } + + status = 0; + if (count) { + remove_suid(inode); + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + } + + while (count) { + unsigned long bytes, index, offset; + char *kaddr; + int deactivate = 1; + + /* + * Try to find the page in the cache. If it isn't there, + * allocate a free page. + */ + offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */ + index = pos >> PAGE_CACHE_SHIFT; + bytes = PAGE_CACHE_SIZE - offset; + if (bytes > count) { + bytes = count; + deactivate = 0; + } + + /* + * Bring in the user page that we will copy from _first_. + * Otherwise there's a nasty deadlock on copying from the + * same page as we're writing to, without it being marked + * up-to-date. + */ + { volatile unsigned char dummy; + __get_user(dummy, buf); + __get_user(dummy, buf+bytes-1); + } + + page = shmem_getpage_locked(inode, index); + status = PTR_ERR(page); + if (IS_ERR(page)) + break; + + /* We have exclusive IO access to the page.. */ + if (!PageLocked(page)) { + PAGE_BUG(page); + } + + kaddr = kmap(page); +// can this do a truncated write? cr + status = copy_from_user(kaddr+offset, buf, bytes); + kunmap(page); + if (status) + goto fail_write; + + flush_dcache_page(page); + if (bytes > 0) { + SetPageDirty(page); + written += bytes; + count -= bytes; + pos += bytes; + buf += bytes; + if (pos > inode->i_size) + inode->i_size = pos; + if (inode->u.shmem_i.max_index <= index) + inode->u.shmem_i.max_index = index+1; + + } +unlock: + /* Mark it unlocked again and drop the page.. */ + UnlockPage(page); + if (deactivate) + deactivate_page(page); + page_cache_release(page); + + if (status < 0) + break; + } + *ppos = pos; + + err = written ? written : status; +out: + up(&inode->i_sem); + return err; +fail_write: + status = -EFAULT; + ClearPageUptodate(page); + kunmap(page); + goto unlock; +} + +static void do_shmem_file_read(struct file * filp, loff_t *ppos, read_descriptor_t * desc) +{ + struct inode *inode = filp->f_dentry->d_inode; + struct address_space *mapping = inode->i_mapping; + unsigned long index, offset; + int nr = 1; + + index = *ppos >> PAGE_CACHE_SHIFT; + offset = *ppos & ~PAGE_CACHE_MASK; + + while (nr && desc->count) { + struct page *page; + unsigned long end_index, nr; + + end_index = inode->i_size >> PAGE_CACHE_SHIFT; + if (index > end_index) + break; + nr = PAGE_CACHE_SIZE; + if (index == end_index) { + nr = inode->i_size & ~PAGE_CACHE_MASK; + if (nr <= offset) + break; + } + + nr = nr - offset; + + if ((desc->error = shmem_getpage(inode, index, &page))) + break; + + if (mapping->i_mmap_shared != NULL) + flush_dcache_page(page); + + /* + * Ok, we have the page, and it's up-to-date, so + * now we can copy it to user space... + * + * The actor routine returns how many bytes were actually used.. + * NOTE! This may not be the same as how much of a user buffer + * we filled up (we may be padding etc), so we can only update + * "pos" here (the actor routine has to update the user buffer + * pointers and the remaining count). + */ + nr = file_read_actor(desc, page, offset, nr); + offset += nr; + index += offset >> PAGE_CACHE_SHIFT; + offset &= ~PAGE_CACHE_MASK; + + page_cache_release(page); + } + + *ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset; + UPDATE_ATIME(inode); +} + +static ssize_t shmem_file_read(struct file * filp, char * buf, size_t count, loff_t *ppos) +{ + ssize_t retval; + + retval = -EFAULT; + if (access_ok(VERIFY_WRITE, buf, count)) { + retval = 0; + + if (count) { + read_descriptor_t desc; + + desc.written = 0; + desc.count = count; + desc.buf = buf; + desc.error = 0; + do_shmem_file_read(filp, ppos, &desc); + + retval = desc.written; + if (!retval) + retval = desc.error; + } + } + return retval; +} + static int shmem_statfs(struct super_block *sb, struct statfs *buf) { - buf->f_type = SHMEM_MAGIC; + buf->f_type = TMPFS_MAGIC; buf->f_bsize = PAGE_CACHE_SIZE; spin_lock (&sb->u.shmem_sb.stat_lock); - if (sb->u.shmem_sb.max_blocks != ULONG_MAX || - sb->u.shmem_sb.max_inodes != ULONG_MAX) { + if (sb->u.shmem_sb.max_blocks == ULONG_MAX) { + /* + * This is only a guestimate and not honoured. + * We need it to make some programs happy which like to + * test the free space of a file system. + */ + buf->f_bavail = buf->f_bfree = nr_free_pages() + nr_swap_pages + atomic_read(&buffermem_pages); + buf->f_blocks = buf->f_bfree + ULONG_MAX - sb->u.shmem_sb.free_blocks; + } else { buf->f_blocks = sb->u.shmem_sb.max_blocks; buf->f_bavail = buf->f_bfree = sb->u.shmem_sb.free_blocks; - buf->f_files = sb->u.shmem_sb.max_inodes; - buf->f_ffree = sb->u.shmem_sb.free_inodes; } + buf->f_files = sb->u.shmem_sb.max_inodes; + buf->f_ffree = sb->u.shmem_sb.free_inodes; spin_unlock (&sb->u.shmem_sb.stat_lock); buf->f_namelen = 255; return 0; } -void shmem_lock(struct file * file, int lock) -{ - struct inode * inode = file->f_dentry->d_inode; - struct shmem_inode_info * info = &inode->u.shmem_i; - struct page * page; - unsigned long idx, size; - - if (info->locked == lock) - return; - down(&inode->i_sem); - info->locked = lock; - size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; - for (idx = 0; idx < size; idx++) { - page = find_lock_page(inode->i_mapping, idx); - if (!page) - continue; - if (!lock) { - /* release the extra count and our reference */ - page_cache_release(page); - page_cache_release(page); - } - UnlockPage(page); - } - up(&inode->i_sem); -} - /* * Lookup the data. This is trivial - if the dentry didn't already * exist, we know it is negative. @@ -466,6 +804,7 @@ struct inode * inode = shmem_get_inode(dir->i_sb, mode, dev); int error = -ENOSPC; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; if (inode) { d_instantiate(dentry, inode); dget(dentry); /* Extra count - pin the dentry in core */ @@ -476,7 +815,12 @@ static int shmem_mkdir(struct inode * dir, struct dentry * dentry, int mode) { - return shmem_mknod(dir, dentry, mode | S_IFDIR, 0); + int error; + + if ((error = shmem_mknod(dir, dentry, mode | S_IFDIR, 0))) + return error; + dir->i_nlink++; + return 0; } static int shmem_create(struct inode *dir, struct dentry *dentry, int mode) @@ -494,6 +838,7 @@ if (S_ISDIR(inode->i_mode)) return -EPERM; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; inode->i_nlink++; atomic_inc(&inode->i_count); /* New dentry reference */ dget(dentry); /* Extra pinning count for the created dentry */ @@ -534,26 +879,24 @@ return 1; } -/* - * This works for both directories and regular files. - * (non-directories will always have empty subdirs) - */ static int shmem_unlink(struct inode * dir, struct dentry *dentry) { - int retval = -ENOTEMPTY; + struct inode *inode = dentry->d_inode; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + inode->i_nlink--; + dput(dentry); /* Undo the count from "create" - this does all the work */ + return 0; +} - if (shmem_empty(dentry)) { - struct inode *inode = dentry->d_inode; +static int shmem_rmdir(struct inode * dir, struct dentry *dentry) +{ + if (!shmem_empty(dentry)) + return -ENOTEMPTY; - inode->i_nlink--; - dput(dentry); /* Undo the count from "create" - this does all the work */ - retval = 0; - } - return retval; + dir->i_nlink--; + return shmem_unlink(dir, dentry); } -#define shmem_rmdir shmem_unlink - /* * The VFS layer already does all the dentry stuff for rename, * we just have to decrement the usage count for the target if @@ -567,27 +910,77 @@ if (shmem_empty(new_dentry)) { struct inode *inode = new_dentry->d_inode; if (inode) { + inode->i_ctime = CURRENT_TIME; inode->i_nlink--; dput(new_dentry); } error = 0; + old_dentry->d_inode->i_ctime = old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; } return error; } -static int shmem_mmap(struct file * file, struct vm_area_struct * vma) +static int shmem_symlink(struct inode * dir, struct dentry *dentry, const char * symname) { - struct vm_operations_struct * ops; - struct inode *inode = file->f_dentry->d_inode; + int error; + int len; + struct inode *inode; + struct page *page; + char *kaddr; - ops = &shmem_private_vm_ops; - if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) - ops = &shmem_shared_vm_ops; - if (!inode->i_sb || !S_ISREG(inode->i_mode)) - return -EACCES; - UPDATE_ATIME(inode); - vma->vm_ops = ops; + error = shmem_mknod(dir, dentry, S_IFLNK | S_IRWXUGO, 0); + if (error) + return error; + + len = strlen(symname); + if (len > PAGE_SIZE) + return -ENAMETOOLONG; + + inode = dentry->d_inode; + down(&inode->i_sem); + page = shmem_getpage_locked(inode, 0); + if (IS_ERR(page)) + goto fail; + kaddr = kmap(page); + memcpy(kaddr, symname, len); + kunmap(page); + inode->i_size = len; + SetPageDirty(page); + UnlockPage(page); + page_cache_release(page); + up(&inode->i_sem); + dir->i_ctime = dir->i_mtime = CURRENT_TIME; return 0; +fail: + up(&inode->i_sem); + return PTR_ERR(page); +} + +static int shmem_readlink(struct dentry *dentry, char *buffer, int buflen) +{ + struct page * page; + int res = shmem_getpage(dentry->d_inode, 0, &page); + + if (res) + return res; + + res = vfs_readlink(dentry,buffer,buflen, kmap(page)); + kunmap(page); + page_cache_release(page); + return res; +} + +static int shmem_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct page * page; + int res = shmem_getpage(dentry->d_inode, 0, &page); + if (res) + return res; + + res = vfs_follow_link(nd, kmap(page)); + kunmap(page); + page_cache_release(page); + return res; } static int shmem_parse_options(char *options, int *mode, unsigned long * blocks, unsigned long *inodes) @@ -600,16 +993,24 @@ for ( ; this_char; this_char = strtok(NULL,",")) { if ((value = strchr(this_char,'=')) != NULL) *value++ = 0; - if (!strcmp(this_char,"nr_blocks")) { + if (!strcmp(this_char,"size")) { + unsigned long long size; if (!value || !*value || !blocks) return 1; - *blocks = simple_strtoul(value,&value,0); + size = memparse(value,&value); + if (*value) + return 1; + *blocks = size >> PAGE_CACHE_SHIFT; + } else if (!strcmp(this_char,"nr_blocks")) { + if (!value || !*value || !blocks) + return 1; + *blocks = memparse(value,&value); if (*value) return 1; } else if (!strcmp(this_char,"nr_inodes")) { if (!value || !*value || !inodes) return 1; - *inodes = simple_strtoul(value,&value,0); + *inodes = memparse(value,&value); if (*value) return 1; } else if (!strcmp(this_char,"mode")) { @@ -622,9 +1023,42 @@ else return 1; } + return 0; +} + +static int shmem_remount_fs (struct super_block *sb, int *flags, char *data) +{ + int error; + unsigned long max_blocks, blocks; + unsigned long max_inodes, inodes; + struct shmem_sb_info *info = &sb->u.shmem_sb; + + if (shmem_parse_options (data, NULL, &max_blocks, &max_inodes)) + return -EINVAL; + + spin_lock(&info->stat_lock); + blocks = info->max_blocks - info->free_blocks; + inodes = info->max_inodes - info->free_inodes; + error = -EINVAL; + if (max_blocks < blocks) + goto out; + if (max_inodes < inodes) + goto out; + error = 0; + info->max_blocks = max_blocks; + info->free_blocks = max_blocks - blocks; + info->max_inodes = max_inodes; + info->free_inodes = max_inodes - inodes; +out: + spin_unlock(&info->stat_lock); + return error; +} +int shmem_sync_file(struct file * file, struct dentry *dentry, int datasync) +{ return 0; } +#endif static struct super_block *shmem_read_super(struct super_block * sb, void * data, int silent) { @@ -634,19 +1068,22 @@ unsigned long inodes = ULONG_MAX; /* unlimited */ int mode = S_IRWXUGO | S_ISVTX; +#ifdef CONFIG_TMPFS if (shmem_parse_options (data, &mode, &blocks, &inodes)) { - printk(KERN_ERR "shmem fs invalid option\n"); + printk(KERN_ERR "tmpfs invalid option\n"); return NULL; } +#endif spin_lock_init (&sb->u.shmem_sb.stat_lock); sb->u.shmem_sb.max_blocks = blocks; sb->u.shmem_sb.free_blocks = blocks; sb->u.shmem_sb.max_inodes = inodes; sb->u.shmem_sb.free_inodes = inodes; + sb->s_maxbytes = (unsigned long long)(SHMEM_NR_DIRECT + (ENTRIES_PER_PAGE*ENTRIES_PER_PAGE)) << PAGE_CACHE_SHIFT; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; - sb->s_magic = SHMEM_MAGIC; + sb->s_magic = TMPFS_MAGIC; sb->s_op = &shmem_ops; inode = shmem_get_inode(sb, S_IFDIR | mode, 0); if (!inode) @@ -661,103 +1098,108 @@ return sb; } -static int shmem_remount_fs (struct super_block *sb, int *flags, char *data) -{ - int error; - unsigned long max_blocks, blocks; - unsigned long max_inodes, inodes; - struct shmem_sb_info *info = &sb->u.shmem_sb; - if (shmem_parse_options (data, NULL, &max_blocks, &max_inodes)) - return -EINVAL; - - spin_lock(&info->stat_lock); - blocks = info->max_blocks - info->free_blocks; - inodes = info->max_inodes - info->free_inodes; - error = -EINVAL; - if (max_blocks < blocks) - goto out; - if (max_inodes < inodes) - goto out; - error = 0; - info->max_blocks = max_blocks; - info->free_blocks = max_blocks - blocks; - info->max_inodes = max_inodes; - info->free_inodes = max_inodes - inodes; -out: - spin_unlock(&info->stat_lock); - return error; -} static struct address_space_operations shmem_aops = { writepage: shmem_writepage }; static struct file_operations shmem_file_operations = { - mmap: shmem_mmap + mmap: shmem_mmap, +#ifdef CONFIG_TMPFS + read: shmem_file_read, + write: shmem_file_write, + fsync: shmem_sync_file, +#endif }; static struct inode_operations shmem_inode_operations = { truncate: shmem_truncate, }; +static struct inode_operations shmem_symlink_inode_operations = { + truncate: shmem_truncate, +#ifdef CONFIG_TMPFS + readlink: shmem_readlink, + follow_link: shmem_follow_link, +#endif +}; + static struct file_operations shmem_dir_operations = { read: generic_read_dir, readdir: dcache_readdir, +#ifdef CONFIG_TMPFS + fsync: shmem_sync_file, +#endif }; static struct inode_operations shmem_dir_inode_operations = { +#ifdef CONFIG_TMPFS create: shmem_create, lookup: shmem_lookup, link: shmem_link, unlink: shmem_unlink, + symlink: shmem_symlink, mkdir: shmem_mkdir, rmdir: shmem_rmdir, mknod: shmem_mknod, rename: shmem_rename, +#endif }; static struct super_operations shmem_ops = { +#ifdef CONFIG_TMPFS statfs: shmem_statfs, remount_fs: shmem_remount_fs, +#endif delete_inode: shmem_delete_inode, put_inode: force_delete, }; -static struct vm_operations_struct shmem_private_vm_ops = { - nopage: shmem_nopage, -}; - -static struct vm_operations_struct shmem_shared_vm_ops = { +static struct vm_operations_struct shmem_vm_ops = { nopage: shmem_nopage, }; +#ifdef CONFIG_TMPFS +/* type "shm" will be tagged obsolete in 2.5 */ static DECLARE_FSTYPE(shmem_fs_type, "shm", shmem_read_super, FS_LITTER); +static DECLARE_FSTYPE(tmpfs_fs_type, "tmpfs", shmem_read_super, FS_LITTER); +#else +static DECLARE_FSTYPE(tmpfs_fs_type, "tmpfs", shmem_read_super, FS_LITTER|FS_NOMOUNT); +#endif static int __init init_shmem_fs(void) { int error; struct vfsmount * res; + if ((error = register_filesystem(&tmpfs_fs_type))) { + printk (KERN_ERR "Could not register tmpfs\n"); + return error; + } +#ifdef CONFIG_TMPFS if ((error = register_filesystem(&shmem_fs_type))) { - printk (KERN_ERR "Could not register shmem fs\n"); + printk (KERN_ERR "Could not register shm fs\n"); return error; } - - res = kern_mount(&shmem_fs_type); + devfs_mk_dir (NULL, "shm", NULL); +#endif + res = kern_mount(&tmpfs_fs_type); if (IS_ERR (res)) { - printk (KERN_ERR "could not kern_mount shmem fs\n"); - unregister_filesystem(&shmem_fs_type); + printk (KERN_ERR "could not kern_mount tmpfs\n"); + unregister_filesystem(&tmpfs_fs_type); return PTR_ERR(res); } - devfs_mk_dir (NULL, "shm", NULL); return 0; } static void __exit exit_shmem_fs(void) { +#ifdef CONFIG_TMPFS unregister_filesystem(&shmem_fs_type); +#endif + unregister_filesystem(&tmpfs_fs_type); } module_init(init_shmem_fs) @@ -853,7 +1295,7 @@ this.name = name; this.len = strlen(name); this.hash = 0; /* will go */ - root = shmem_fs_type.kern_mnt->mnt_root; + root = tmpfs_fs_type.kern_mnt->mnt_root; dentry = d_alloc(root, &this); if (!dentry) goto out; @@ -870,7 +1312,8 @@ d_instantiate(dentry, inode); dentry->d_inode->i_size = size; - file->f_vfsmnt = mntget(shmem_fs_type.kern_mnt); + shmem_truncate(inode); + file->f_vfsmnt = mntget(tmpfs_fs_type.kern_mnt); file->f_dentry = dentry; file->f_op = &shmem_file_operations; file->f_mode = FMODE_WRITE | FMODE_READ; @@ -901,6 +1344,8 @@ if (vma->vm_file) fput (vma->vm_file); vma->vm_file = file; - vma->vm_ops = &shmem_shared_vm_ops; + vma->vm_ops = &shmem_vm_ops; return 0; } + +EXPORT_SYMBOL(shmem_file_setup); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/slab.c linux.ac/mm/slab.c --- linux.vanilla/mm/slab.c Tue Apr 3 17:32:30 2001 +++ linux.ac/mm/slab.c Thu Apr 12 18:23:01 2001 @@ -85,9 +85,15 @@ * FORCED_DEBUG - 1 enables SLAB_RED_ZONE and SLAB_POISON (if possible) */ +#ifdef CONFIG_DEBUG_SLAB +#define DEBUG 1 +#define STATS 1 +#define FORCED_DEBUG 1 +#else #define DEBUG 0 #define STATS 0 #define FORCED_DEBUG 0 +#endif /* * Parameters for kmem_cache_reap @@ -102,9 +108,11 @@ #if DEBUG # define CREATE_MASK (SLAB_DEBUG_INITIAL | SLAB_RED_ZONE | \ SLAB_POISON | SLAB_HWCACHE_ALIGN | \ - SLAB_NO_REAP | SLAB_CACHE_DMA) + SLAB_NO_REAP | SLAB_CACHE_DMA | \ + SLAB_MUST_HWCACHE_ALIGN) #else -# define CREATE_MASK (SLAB_HWCACHE_ALIGN | SLAB_NO_REAP | SLAB_CACHE_DMA) +# define CREATE_MASK (SLAB_HWCACHE_ALIGN | SLAB_NO_REAP | \ + SLAB_CACHE_DMA | SLAB_MUST_HWCACHE_ALIGN) #endif /* @@ -641,7 +649,7 @@ flags &= ~SLAB_POISON; } #if FORCED_DEBUG - if (size < (PAGE_SIZE>>3)) + if ((size < (PAGE_SIZE>>3)) && !(flags & SLAB_MUST_HWCACHE_ALIGN)) /* * do not red zone large object, causes severe * fragmentation. @@ -814,6 +822,33 @@ return cachep; } + +#if DEBUG +/* + * This check if the kmem_cache_t pointer is chained in the cache_cache + * list. -arca + */ +static int is_chained_kmem_cache(kmem_cache_t * cachep) +{ + struct list_head *p; + int ret = 0; + + /* Find the cache in the chain of caches. */ + down(&cache_chain_sem); + list_for_each(p, &cache_chain) { + if (p == &cachep->next) { + ret = 1; + break; + } + } + up(&cache_chain_sem); + + return ret; +} +#else +#define is_chained_kmem_cache(x) 1 +#endif + #ifdef CONFIG_SMP /* * Waits for all CPUs to execute func(). @@ -916,7 +951,7 @@ */ int kmem_cache_shrink(kmem_cache_t *cachep) { - if (!cachep || in_interrupt()) + if (!cachep || in_interrupt() || !is_chained_kmem_cache(cachep)) BUG(); return __kmem_cache_shrink(cachep); @@ -1492,20 +1527,20 @@ * @flags: the type of memory to allocate. * * kmalloc is the normal method of allocating memory - * in the kernel. The @flags argument may be one of: - * - * %GFP_BUFFER - XXX + * in the kernel. * - * %GFP_ATOMIC - allocation will not sleep. Use inside interrupt handlers. + * The @flags argument may be one of: * - * %GFP_USER - allocate memory on behalf of user. May sleep. + * %GFP_USER - Allocate memory on behalf of user. May sleep. * - * %GFP_KERNEL - allocate normal kernel ram. May sleep. + * %GFP_KERNEL - Allocate normal kernel ram. May sleep. * - * %GFP_NFS - has a slightly lower probability of sleeping than %GFP_KERNEL. - * Don't use unless you're in the NFS code. + * %GFP_ATOMIC - Allocation will not sleep. Use inside interrupt handlers. * - * %GFP_KSWAPD - Don't use unless you're modifying kswapd. + * Additionally, the %GFP_DMA flag may be set to indicate the memory + * must be suitable for DMA. This can mean different things on different + * platforms. For example, on i386, it means that the memory must come + * from the first 16MB. */ void * kmalloc (size_t size, int flags) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/swap_state.c linux.ac/mm/swap_state.c --- linux.vanilla/mm/swap_state.c Fri Dec 29 23:04:27 2000 +++ linux.ac/mm/swap_state.c Tue Apr 10 18:27:11 2001 @@ -17,8 +17,23 @@ #include <asm/pgtable.h> +/* + * We may have stale swap cache pages in memory: notice + * them here and get rid of the unnecessary final write. + */ static int swap_writepage(struct page *page) { + /* One for the page cache, one for this user, one for page->buffers */ + if (page_count(page) > 2 + !!page->buffers) + goto in_use; + if (swap_count(page) > 1) + goto in_use; + + /* We could remove it here, but page_launder will do it anyway */ + UnlockPage(page); + return 0; + +in_use: rw_swap_page(WRITE, page, 0); return 0; } @@ -129,26 +144,6 @@ delete_from_swap_cache_nolock(page); UnlockPage(page); } - -/* - * Perform a free_page(), also freeing any swap cache associated with - * this page if it is the last user of the page. Can not do a lock_page, - * as we are holding the page_table_lock spinlock. - */ -void free_page_and_swap_cache(struct page *page) -{ - /* - * If we are the only user, then try to free up the swap cache. - */ - if (PageSwapCache(page) && !TryLockPage(page)) { - if (!is_page_shared(page)) { - delete_from_swap_cache_nolock(page); - } - UnlockPage(page); - } - page_cache_release(page); -} - /* * Lookup a swap entry in the swap cache. A found page will be returned diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/swapfile.c linux.ac/mm/swapfile.c --- linux.vanilla/mm/swapfile.c Tue Apr 3 17:32:30 2001 +++ linux.ac/mm/swapfile.c Tue Apr 3 17:55:19 2001 @@ -90,8 +90,12 @@ int type, wrapped = 0; entry.val = 0; /* Out of memory */ - if (count >= SWAP_MAP_MAX) - goto bad_count; + if (count >= SWAP_MAP_MAX) { + printk(KERN_ERR "get_swap_page: bad count %hd from %p\n", + count, __builtin_return_address(0)); + return entry; + } + swap_list_lock(); type = swap_list.next; if (type < 0) @@ -130,11 +134,6 @@ out: swap_list_unlock(); return entry; - -bad_count: - printk(KERN_ERR "get_swap_page: bad count %hd from %p\n", - count, __builtin_return_address(0)); - goto out; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/vmscan.c linux.ac/mm/vmscan.c --- linux.vanilla/mm/vmscan.c Tue Apr 3 17:32:30 2001 +++ linux.ac/mm/vmscan.c Sat Apr 14 01:47:38 2001 @@ -285,7 +285,7 @@ retval = swap_out_mm(mm, swap_amount(mm)); /* Then, look at the other mm's */ - counter = mmlist_nr >> priority; + counter = (mmlist_nr << SWAP_SHIFT) >> priority; do { struct list_head *p; @@ -417,14 +417,17 @@ * * This code is heavily inspired by the FreeBSD source code. Thanks * go out to Matthew Dillon. + * + * XXX: restrict number of pageouts in flight by ->writepage... */ -#define MAX_LAUNDER (4 * (1 << page_cluster)) -int page_launder(int gfp_mask, int sync) +#define MAX_LAUNDER (1 << page_cluster) +int page_launder(int gfp_mask, int user) { - int launder_loop, maxscan, cleaned_pages, maxlaunder; - int can_get_io_locks; + int launder_loop, maxscan, flushed_pages, freed_pages, maxlaunder; + int can_get_io_locks, sync, target, shortage; struct list_head * page_lru; struct page * page; + struct zone_struct * zone; /* * We can only grab the IO locks (eg. for flushing dirty @@ -432,9 +435,13 @@ */ can_get_io_locks = gfp_mask & __GFP_IO; + target = free_shortage(); + + sync = 0; launder_loop = 0; maxlaunder = 0; - cleaned_pages = 0; + flushed_pages = 0; + freed_pages = 0; dirty_page_rescan: spin_lock(&pagemap_lru_lock); @@ -442,13 +449,14 @@ while ((page_lru = inactive_dirty_list.prev) != &inactive_dirty_list && maxscan-- > 0) { page = list_entry(page_lru, struct page, lru); + zone = page->zone; /* Wrong page on list?! (list corruption, should not happen) */ if (!PageInactiveDirty(page)) { printk("VM: page_launder, wrong page on list.\n"); list_del(page_lru); nr_inactive_dirty_pages--; - page->zone->inactive_dirty_pages--; + zone->inactive_dirty_pages--; continue; } @@ -462,10 +470,26 @@ } /* + * Disk IO is really expensive, so we make sure we + * don't do more work than needed. + * Note that clean pages from zones with enough free + * pages still get recycled and dirty pages from these + * zones can get flushed due to IO clustering. + */ + if (freed_pages + flushed_pages > target && !free_shortage()) + break; + if (launder_loop && !maxlaunder) + break; + if (launder_loop && zone->inactive_clean_pages + + zone->free_pages > zone->pages_high) + goto skip_page; + + /* * The page is locked. IO in progress? * Move it to the back of the list. */ if (TryLockPage(page)) { +skip_page: list_del(page_lru); list_add(page_lru, &inactive_dirty_list); continue; @@ -495,6 +519,10 @@ spin_unlock(&pagemap_lru_lock); writepage(page); + /* XXX: all ->writepage()s should use nr_async_pages */ + if (!PageSwapCache(page)) + flushed_pages++; + maxlaunder--; page_cache_release(page); /* And re-start the thing.. */ @@ -513,7 +541,6 @@ */ if (page->buffers) { int wait, clearedbuf; - int freed_page = 0; /* * Since we might be doing disk IO, we have to * drop the spinlock and take an extra reference @@ -544,12 +571,13 @@ /* The buffers were not freed. */ if (!clearedbuf) { add_page_to_inactive_dirty_list(page); + if (wait) + flushed_pages++; /* The page was only in the buffer cache. */ } else if (!page->mapping) { atomic_dec(&buffermem_pages); - freed_page = 1; - cleaned_pages++; + freed_pages++; /* The page has more users besides the cache and us. */ } else if (page_count(page) > 2) { @@ -558,24 +586,17 @@ /* OK, we "created" a freeable page. */ } else /* page->mapping && page_count(page) == 2 */ { add_page_to_inactive_clean_list(page); - cleaned_pages++; + freed_pages++; } /* * Unlock the page and drop the extra reference. - * We can only do it here because we ar accessing + * We can only do it here because we are accessing * the page struct above. */ UnlockPage(page); page_cache_release(page); - /* - * If we're freeing buffer cache pages, stop when - * we've got enough free memory. - */ - if (freed_page && !free_shortage()) - break; - continue; } else if (page->mapping && !PageDirty(page)) { /* * If a page had an extra reference in @@ -586,7 +607,8 @@ del_page_from_inactive_dirty_list(page); add_page_to_inactive_clean_list(page); UnlockPage(page); - cleaned_pages++; + freed_pages++; + } else { page_active: /* @@ -612,20 +634,53 @@ * loads, flush out the dirty pages before we have to wait on * IO. */ - if (can_get_io_locks && !launder_loop && free_shortage()) { + shortage = free_shortage(); + if (can_get_io_locks && !launder_loop && shortage) { launder_loop = 1; - /* If we cleaned pages, never do synchronous IO. */ - if (cleaned_pages) - sync = 0; - /* We only do a few "out of order" flushes. */ - maxlaunder = MAX_LAUNDER; - /* Kflushd takes care of the rest. */ - wakeup_bdflush(0); + + /* + * User programs can run page_launder() in parallel so + * we only flush a few pages at a time to avoid big IO + * storms. Kswapd, OTOH, is expected usually keep up + * with the paging load in the system and doesn't have + * the IO storm problem, so it just flushes all pages + * needed to fix the free shortage. + */ + maxlaunder = shortage; + maxlaunder -= flushed_pages; + maxlaunder -= atomic_read(&nr_async_pages); + + if (maxlaunder <= 0) + goto out; + + if (user && maxlaunder > MAX_LAUNDER) + maxlaunder = MAX_LAUNDER; + + /* + * If we are called by a user program, we need to free + * some pages. If we couldn't, we'll do the last page IO + * synchronously to be sure + */ + if (user && !freed_pages) + sync = 1; + goto dirty_page_rescan; } - /* Return the number of pages moved to the inactive_clean list. */ - return cleaned_pages; + /* + * If data was queued for IO, we have to make sure its + * actually written to the disk now, otherwise we'll never + * get enough clean pages and the system will keep queueing + * dirty pages for flushing. + */ + if (launder_loop) + run_task_queue(&tq_disk); + + /* + * Return the amount of pages we freed or made freeable. + */ +out: + return freed_pages + flushed_pages; } /** @@ -636,16 +691,16 @@ * This function will scan a portion of the active list to find * unused pages, those pages will then be moved to the inactive list. */ -int refill_inactive_scan(unsigned int priority, int oneshot) +int refill_inactive_scan(int priority, int target) { struct list_head * page_lru; struct page * page; int maxscan, page_active = 0; - int ret = 0; + int nr_deactivated = 0; /* Take the lock while messing with the list... */ spin_lock(&pagemap_lru_lock); - maxscan = nr_active_pages >> priority; + maxscan = nr_active_pages; while (maxscan-- > 0 && (page_lru = active_list.prev) != &active_list) { page = list_entry(page_lru, struct page, lru); @@ -673,31 +728,38 @@ * * SUBTLE: we can have buffer pages with count 1. */ - if (page->age == 0 && page_count(page) <= - (page->buffers ? 2 : 1)) { - deactivate_page_nolock(page); - page_active = 0; + if (page->age == 0) { + int maxcount = (page->buffers ? 2 : 1); + if (page_count(page) <= maxcount) { + deactivate_page_nolock(page); + page_active = 0; + } else { + /* Page still in somebody's RSS? */ + page_active = 1; + /* XXX: should we call swap_out() if + * this happens too often ? */ + } } else { page_active = 1; } } /* * If the page is still on the active list, move it - * to the other end of the list. Otherwise it was - * deactivated by age_page_down and we exit successfully. + * to the end of the list. Otherwise we successfully + * deactivated a page. */ if (page_active || PageActive(page)) { list_del(page_lru); list_add(page_lru, &active_list); } else { - ret = 1; - if (oneshot) + nr_deactivated++; + if (nr_deactivated >= target) break; } } spin_unlock(&pagemap_lru_lock); - return ret; + return nr_deactivated; } /* @@ -709,7 +771,7 @@ pg_data_t *pgdat = pgdat_list; int sum = 0; int freeable = nr_free_pages() + nr_inactive_clean_pages(); - int freetarget = freepages.high + inactive_target / 3; + int freetarget = freepages.high; /* Are we low on free pages globally? */ if (freeable < freetarget) @@ -777,38 +839,46 @@ } /* - * We need to make the locks finer granularity, but right - * now we need this so that we can do page allocations - * without holding the kernel lock etc. + * Refill_inactive is the function used to scan and age the pages in + * the processes and the active pages, and to move little-used pages + * to the inactive list. * - * We want to try to free "count" pages, and we want to - * cluster them so that we get good swap-out behaviour. + * When called by kswapd, we try to just deactivate as many pages as + * needed. This makes it easy for kswapd to keep up with memory + * demand. * - * OTOH, if we're a user process (and not kswapd), we - * really care about latency. In that case we don't try - * to free too many pages. + * However, when we are called by a user process we have to limit the + * amount of work done. This way the process can do its allocation and + * continue with its real work sooner. It also helps balancing when we + * have multiple processes in try_to_free_pages simultaneously. */ -#define DEF_PRIORITY (6) +#define DEF_PRIORITY (4) static int refill_inactive(unsigned int gfp_mask, int user) { int count, start_count, maxtry; - count = inactive_shortage() + free_shortage(); - if (user) + if (user) { + /* user process */ count = (1 << page_cluster); - start_count = count; + maxtry = 6; + } else { + /* kswapd */ + count = (inactive_shortage() + free_shortage()) >> 2; + maxtry = 1 << DEF_PRIORITY; + } - maxtry = 6; + start_count = count; do { if (current->need_resched) { __set_current_state(TASK_RUNNING); schedule(); + if (!inactive_shortage()) + return 1; } - while (refill_inactive_scan(DEF_PRIORITY, 1)) { - if (--count <= 0) - goto done; - } + count -= refill_inactive_scan(DEF_PRIORITY, count); + if (--count <= 0) + goto done; /* If refill_inactive_scan failed, try to page stuff out.. */ swap_out(DEF_PRIORITY, gfp_mask); @@ -884,6 +954,7 @@ * If there are applications that are active memory-allocators * (most normal use), this basically shouldn't matter. */ + int kswapd(void *unused) { struct task_struct *tsk = current; @@ -912,7 +983,7 @@ * Kswapd main loop. */ for (;;) { - static int recalc = 0; + static long recalc = 0; /* If needed, try to free some memory. */ if (inactive_shortage() || free_shortage()) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/802/TODO linux.ac/net/802/TODO --- linux.vanilla/net/802/TODO Thu Dec 12 14:54:22 1996 +++ linux.ac/net/802/TODO Tue Apr 10 18:27:30 2001 @@ -9,7 +9,7 @@ 2. The code is currently able to handle one connection only, there is more work in register_cl2llc_client() to make a chain of llc structures and in mac_data_indicate() to find back -the llc structure addressed by an incomming frame. +the llc structure addressed by an incoming frame. According to IEEE, connections are identified by (remote mac + local mac + dsap + ssap). dsap and ssap do not seem important: existing applications always use the same dsap/ssap. Its probably sufficient to index on diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/802/cl2llc.c linux.ac/net/802/cl2llc.c --- linux.vanilla/net/802/cl2llc.c Fri Feb 9 19:34:13 2001 +++ linux.ac/net/802/cl2llc.c Tue Apr 10 18:27:30 2001 @@ -162,7 +162,7 @@ * Interpret_pseudo_code() executes the actions in the connection component * state transition table. Table 4 in document on p88. * - * If this function is called to handle an incomming pdu, skb will point + * If this function is called to handle an incoming pdu, skb will point * to the buffer with the pdu and type will contain the decoded pdu type. * * If called by data_request skb points to an skb that was skb_alloc-ed by diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/802/cl2llc.pre linux.ac/net/802/cl2llc.pre --- linux.vanilla/net/802/cl2llc.pre Sat Nov 29 18:41:10 1997 +++ linux.ac/net/802/cl2llc.pre Tue Apr 10 18:27:30 2001 @@ -162,7 +162,7 @@ * Interpret_pseudo_code() executes the actions in the connection component * state transition table. Table 4 in document on p88. * - * If this function is called to handle an incomming pdu, skb will point + * If this function is called to handle an incoming pdu, skb will point * to the buffer with the pdu and type will contain the decoded pdu type. * * If called by data_request skb points to an skb that was skb_alloc-ed by diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/802/llc_sendpdu.c linux.ac/net/802/llc_sendpdu.c --- linux.vanilla/net/802/llc_sendpdu.c Fri Feb 9 19:29:44 2001 +++ linux.ac/net/802/llc_sendpdu.c Tue Apr 10 18:27:30 2001 @@ -98,7 +98,7 @@ /* * Sendpdu() constructs an output frame in a new skb and - * gives it to the MAC layer for transmision. + * gives it to the MAC layer for transmission. * This function is not used to send I pdus. * No queues are updated here, nothing is saved for retransmission. * @@ -186,7 +186,7 @@ /* * llc_sendipdu() Completes an I pdu in an existing skb and gives it - * to the MAC layer for transmision. + * to the MAC layer for transmission. * Parameter "type" must be either I_CMD or I_RSP. * The skb is not freed after xmit, it is kept in case a retransmission * is requested. If needed it can be picked up again from the rtq. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/802/pseudo/pseudocode linux.ac/net/802/pseudo/pseudocode --- linux.vanilla/net/802/pseudo/pseudocode Thu Dec 12 14:54:22 1996 +++ linux.ac/net/802/pseudo/pseudocode Tue Apr 10 18:27:30 2001 @@ -246,7 +246,7 @@ START_REJ_TIMER ; ; the order of opcodes in NORMAL8 is changed. -; the transition table will execute NORMAL8A for incomming pdus +; the transition table will execute NORMAL8A for incoming pdus ; with p/f 1, pdus with pf 0 are treated in NORMAL8B. ; NORMAL8A V(R):=V(R)+1 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/802/transit/pdutr.pre linux.ac/net/802/transit/pdutr.pre --- linux.vanilla/net/802/transit/pdutr.pre Thu Dec 12 14:54:22 1996 +++ linux.ac/net/802/transit/pdutr.pre Tue Apr 10 18:27:30 2001 @@ -1,6 +1,6 @@ COMPILE pdutr INDEX ; -; Transition tables for incomming pdu events. +; Transition tables for incoming pdu events. ; translate this thing into C with ; awk -f ./compile.awk pdu.trans > pdutr.h ; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/appletalk/ddp.c linux.ac/net/appletalk/ddp.c --- linux.vanilla/net/appletalk/ddp.c Mon Jan 22 21:32:10 2001 +++ linux.ac/net/appletalk/ddp.c Sat Apr 14 01:47:37 2001 @@ -1672,7 +1672,7 @@ sk, size, dev->name); size += dev->hard_header_len; - skb = sock_alloc_send_skb(sk, size, 0, (flags & MSG_DONTWAIT), &err); + skb = sock_alloc_send_skb(sk, size, (flags & MSG_DONTWAIT), &err); if (!skb) return err; @@ -1913,6 +1913,7 @@ sendmsg: atalk_sendmsg, recvmsg: atalk_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #include <linux/smp_lock.h> @@ -1988,7 +1989,7 @@ * Use counts are incremented/decremented when * sockets are created/deleted. * - * AppleTalk interfaces are not incremented untill atalkd is run + * AppleTalk interfaces are not incremented until atalkd is run * and are only decremented when they are downed. * * Ergo, before the AppleTalk module can be removed, all AppleTalk diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/atm/addr.c linux.ac/net/atm/addr.c --- linux.vanilla/net/atm/addr.c Fri Dec 29 22:35:47 2000 +++ linux.ac/net/atm/addr.c Tue Apr 10 18:27:30 2001 @@ -52,25 +52,26 @@ sigd_enq(NULL,as_itf_notify,NULL,&pvc,NULL); } +/* + * This is called from atm_ioctl only. You must hold the lock as a caller + */ -void reset_addr(struct atm_dev *dev) +void atm_reset_addr(struct atm_dev *dev) { struct atm_dev_addr *this; down(&local_lock); - spin_lock (&atm_dev_lock); while (dev->local) { this = dev->local; dev->local = this->next; kfree(this); } up(&local_lock); - spin_unlock (&atm_dev_lock); notify_sigd(dev); } -int add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr) +int atm_add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr) { struct atm_dev_addr **walk; int error; @@ -96,7 +97,7 @@ } -int del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr) +int atm_del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr) { struct atm_dev_addr **walk,*this; int error; @@ -119,7 +120,7 @@ } -int get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size) +int atm_get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size) { struct atm_dev_addr *walk; int total; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/atm/addr.h linux.ac/net/atm/addr.h --- linux.vanilla/net/atm/addr.h Mon Dec 11 21:33:43 2000 +++ linux.ac/net/atm/addr.h Tue Apr 17 17:51:56 2001 @@ -10,9 +10,9 @@ #include <linux/atmdev.h> -void reset_addr(struct atm_dev *dev); -int add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); -int del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); -int get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size); +void atm_reset_addr(struct atm_dev *dev); +int atm_add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); +int atm_del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); +int atm_get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/atm/common.c linux.ac/net/atm/common.c --- linux.vanilla/net/atm/common.c Fri Feb 9 19:34:13 2001 +++ linux.ac/net/atm/common.c Thu Apr 12 18:18:08 2001 @@ -867,7 +867,7 @@ ret_val = -EPERM; goto done; } - reset_addr(dev); + atm_reset_addr(dev); break; case ATM_ADDADDR: case ATM_DELADDR: @@ -883,13 +883,13 @@ goto done; } if (cmd == ATM_ADDADDR) - ret_val = add_addr(dev,&addr); + ret_val = atm_add_addr(dev,&addr); else - ret_val = del_addr(dev,&addr); + ret_val = atm_del_addr(dev,&addr); goto done; } case ATM_GETADDR: - size = get_addr(dev,buf,len); + size = atm_get_addr(dev,buf,len); if (size < 0) ret_val = size; else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/atm/pvc.c linux.ac/net/atm/pvc.c --- linux.vanilla/net/atm/pvc.c Sun Nov 12 02:53:33 2000 +++ linux.ac/net/atm/pvc.c Sat Apr 14 01:47:46 2001 @@ -95,6 +95,7 @@ sendmsg: atm_sendmsg, recvmsg: atm_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/atm/svc.c linux.ac/net/atm/svc.c --- linux.vanilla/net/atm/svc.c Wed Nov 15 08:41:03 2000 +++ linux.ac/net/atm/svc.c Sat Apr 14 01:47:46 2001 @@ -408,6 +408,7 @@ sendmsg: atm_sendmsg, recvmsg: atm_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ax25/af_ax25.c linux.ac/net/ax25/af_ax25.c --- linux.vanilla/net/ax25/af_ax25.c Fri Feb 9 19:34:13 2001 +++ linux.ac/net/ax25/af_ax25.c Sat Apr 14 01:47:46 2001 @@ -1451,7 +1451,7 @@ /* Assume the worst case */ size = len + 3 + ax25_addr_size(dp) + AX25_BPQ_HEADER_LEN; - if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) + if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) return err; skb_reserve(skb, size - len); @@ -1805,6 +1805,7 @@ sendmsg: ax25_sendmsg, recvmsg: ax25_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #include <linux/smp_lock.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/core/datagram.c linux.ac/net/core/datagram.c --- linux.vanilla/net/core/datagram.c Sat Feb 3 18:39:12 2001 +++ linux.ac/net/core/datagram.c Sat Apr 14 01:47:59 2001 @@ -36,6 +36,7 @@ #include <linux/inet.h> #include <linux/netdevice.h> #include <linux/poll.h> +#include <linux/highmem.h> #include <net/ip.h> #include <net/protocol.h> @@ -192,26 +193,216 @@ * Copy a datagram to a linear buffer. */ -int skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size) +int skb_copy_datagram(const struct sk_buff *skb, int offset, char *to, int size) { - int err = -EFAULT; + struct iovec iov = { to, size }; - if (!copy_to_user(to, skb->h.raw + offset, size)) - err = 0; - return err; + return skb_copy_datagram_iovec(skb, offset, &iov, size); } - /* * Copy a datagram to an iovec. * Note: the iovec is modified during the copy. */ - -int skb_copy_datagram_iovec(struct sk_buff *skb, int offset, struct iovec *to, - int size) +int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, struct iovec *to, + int len) +{ + int i, copy; + int start = skb->len - skb->data_len; + + /* Copy header. */ + if ((copy = start-offset) > 0) { + if (copy > len) + copy = len; + if (memcpy_toiovec(to, skb->data + offset, copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + } + + /* Copy paged appendix. Hmm... why does this look so complicated? */ + for (i=0; i<skb_shinfo(skb)->nr_frags; i++) { + int end; + + BUG_TRAP(start <= offset+len); + + end = start + skb_shinfo(skb)->frags[i].size; + if ((copy = end-offset) > 0) { + int err; + u8 *vaddr; + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + struct page *page = frag->page; + + if (copy > len) + copy = len; + vaddr = kmap(page); + err = memcpy_toiovec(to, vaddr + frag->page_offset + + offset-start, copy); + kunmap(page); + if (err) + goto fault; + if (!(len -= copy)) + return 0; + offset += copy; + } + start = end; + } + + if (skb_shinfo(skb)->frag_list) { + struct sk_buff *list; + + for (list = skb_shinfo(skb)->frag_list; list; list=list->next) { + int end; + + BUG_TRAP(start <= offset+len); + + end = start + list->len; + if ((copy = end-offset) > 0) { + if (copy > len) + copy = len; + if (skb_copy_datagram_iovec(list, offset-start, to, copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + } + start = end; + } + } + if (len == 0) + return 0; + +fault: + return -EFAULT; +} + +int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, u8 *to, int len, unsigned int *csump) +{ + int i, copy; + int start = skb->len - skb->data_len; + int pos = 0; + + /* Copy header. */ + if ((copy = start-offset) > 0) { + int err = 0; + if (copy > len) + copy = len; + *csump = csum_and_copy_to_user(skb->data+offset, to, copy, *csump, &err); + if (err) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + to += copy; + pos = copy; + } + + for (i=0; i<skb_shinfo(skb)->nr_frags; i++) { + int end; + + BUG_TRAP(start <= offset+len); + + end = start + skb_shinfo(skb)->frags[i].size; + if ((copy = end-offset) > 0) { + unsigned int csum2; + int err = 0; + u8 *vaddr; + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + struct page *page = frag->page; + + if (copy > len) + copy = len; + vaddr = kmap(page); + csum2 = csum_and_copy_to_user(vaddr + frag->page_offset + + offset-start, to, copy, 0, &err); + kunmap(page); + if (err) + goto fault; + *csump = csum_block_add(*csump, csum2, pos); + if (!(len -= copy)) + return 0; + offset += copy; + to += copy; + pos += copy; + } + start = end; + } + + if (skb_shinfo(skb)->frag_list) { + struct sk_buff *list; + + for (list = skb_shinfo(skb)->frag_list; list; list=list->next) { + int end; + + BUG_TRAP(start <= offset+len); + + end = start + list->len; + if ((copy = end-offset) > 0) { + unsigned int csum2 = 0; + if (copy > len) + copy = len; + if (skb_copy_and_csum_datagram(list, offset-start, to, copy, &csum2)) + goto fault; + *csump = csum_block_add(*csump, csum2, pos); + if ((len -= copy) == 0) + return 0; + offset += copy; + to += copy; + pos += copy; + } + start = end; + } + } + if (len == 0) + return 0; + +fault: + return -EFAULT; +} + +/* Copy and checkum skb to user iovec. Caller _must_ check that + skb will fit to this iovec. + + Returns: 0 - success. + -EINVAL - checksum failure. + -EFAULT - fault during copy. Beware, in this case iovec can be + modified! + */ + +int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, int hlen, struct iovec *iov) { - return memcpy_toiovec(to, skb->h.raw + offset, size); + unsigned int csum; + int chunk = skb->len - hlen; + + /* Skip filled elements. Pretty silly, look at memcpy_toiovec, though 8) */ + while (iov->iov_len == 0) + iov++; + + if (iov->iov_len < chunk) { + if ((unsigned short)csum_fold(skb_checksum(skb, 0, chunk+hlen, skb->csum))) + goto csum_error; + if (skb_copy_datagram_iovec(skb, hlen, iov, chunk)) + goto fault; + } else { + csum = csum_partial(skb->data, hlen, skb->csum); + if (skb_copy_and_csum_datagram(skb, hlen, iov->iov_base, chunk, &csum)) + goto fault; + if ((unsigned short)csum_fold(csum)) + goto csum_error; + iov->iov_len -= chunk; + iov->iov_base += chunk; + } + return 0; + +csum_error: + return -EINVAL; + +fault: + return -EFAULT; } + + /* * Datagram poll: Again totally generic. This also handles diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/core/dev.c linux.ac/net/core/dev.c --- linux.vanilla/net/core/dev.c Tue Apr 3 17:32:30 2001 +++ linux.ac/net/core/dev.c Sat Apr 14 01:47:59 2001 @@ -91,6 +91,8 @@ #include <net/dst.h> #include <net/pkt_sched.h> #include <net/profile.h> +#include <net/checksum.h> +#include <linux/highmem.h> #include <linux/init.h> #include <linux/kmod.h> #include <linux/module.h> @@ -503,7 +505,7 @@ } /** - * dev_getbyhwaddr - find a device by its hardware addres + * dev_getbyhwaddr - find a device by its hardware address * @type: media type of device * @ha: hardware address * @@ -871,12 +873,10 @@ */ skb2->mac.raw = skb2->data; - if (skb2->nh.raw < skb2->data || skb2->nh.raw >= skb2->tail) { + if (skb2->nh.raw < skb2->data || skb2->nh.raw > skb2->tail) { if (net_ratelimit()) printk(KERN_DEBUG "protocol %04x is buggy, dev %s\n", skb2->protocol, dev->name); skb2->nh.raw = skb2->data; - if (dev->hard_header) - skb2->nh.raw += dev->hard_header_len; } skb2->h.raw = skb2->nh.raw; @@ -887,6 +887,55 @@ br_read_unlock(BR_NETPROTO_LOCK); } +/* Calculate csum in the case, when packet is misrouted. + * If it failed by some reason, ignore and send skb with wrong + * checksum. + */ +struct sk_buff * skb_checksum_help(struct sk_buff *skb) +{ + int offset; + unsigned int csum; + + offset = skb->h.raw - skb->data; + if (offset > (int)skb->len) + BUG(); + csum = skb_checksum(skb, offset, skb->len-offset, 0); + + offset = skb->tail - skb->h.raw; + if (offset <= 0) + BUG(); + if (skb->csum+2 > offset) + BUG(); + + *(u16*)(skb->h.raw + skb->csum) = csum_fold(csum); + skb->ip_summed = CHECKSUM_NONE; + return skb; +} + +#ifdef CONFIG_HIGHMEM +/* Actually, we should eliminate this check as soon as we know, that: + * 1. IOMMU is present and allows to map all the memory. + * 2. No high memory really exists on this machine. + */ + +static inline int +illegal_highdma(struct net_device *dev, struct sk_buff *skb) +{ + int i; + + if (dev->features&NETIF_F_HIGHDMA) + return 0; + + for (i=0; i<skb_shinfo(skb)->nr_frags; i++) + if (skb_shinfo(skb)->frags[i].page >= highmem_start_page) + return 1; + + return 0; +} +#else +#define illegal_highdma(dev, skb) (0) +#endif + /** * dev_queue_xmit - transmit a buffer * @skb: buffer to transmit @@ -899,12 +948,41 @@ * guarantee the frame will be transmitted as it may be dropped due * to congestion or traffic shaping. */ - + int dev_queue_xmit(struct sk_buff *skb) { struct net_device *dev = skb->dev; struct Qdisc *q; + if (skb_shinfo(skb)->frag_list && + !(dev->features&NETIF_F_FRAGLIST) && + skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + return -ENOMEM; + } + + /* Fragmented skb is linearized if device does not support SG, + * or if at least one of fragments is in highmem and device + * does not support DMA from it. + */ + if (skb_shinfo(skb)->nr_frags && + (!(dev->features&NETIF_F_SG) || illegal_highdma(dev, skb)) && + skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + return -ENOMEM; + } + + /* If packet is not checksummed and device does not support + * checksumming for this protocol, complete checksumming here. + */ + if (skb->ip_summed == CHECKSUM_HW && + (!(dev->features&(NETIF_F_HW_CSUM|NETIF_F_NO_CSUM)) && + (!(dev->features&NETIF_F_IP_CSUM) || + skb->protocol != htons(ETH_P_IP)))) { + if ((skb = skb_checksum_help(skb)) == NULL) + return -ENOMEM; + } + /* Grab device queue */ spin_lock_bh(&dev->queue_lock); q = dev->qdisc; @@ -1183,6 +1261,10 @@ if (skb == NULL) return ret; } + if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + return ret; + } /* The assumption (correct one) is that old protocols did not depened on BHs different of NET_BH and TIMER_BH. @@ -1281,7 +1363,7 @@ void (*br_handle_frame_hook)(struct sk_buff *skb) = NULL; #endif -static int __inline__ handle_bridge(struct sk_buff *skb, +static __inline__ int handle_bridge(struct sk_buff *skb, struct packet_type *pt_prev) { int ret = NET_RX_DROP; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/core/filter.c linux.ac/net/core/filter.c --- linux.vanilla/net/core/filter.c Sun Apr 2 23:38:54 2000 +++ linux.ac/net/core/filter.c Sat Apr 14 01:47:59 2001 @@ -72,7 +72,7 @@ /* len is UNSIGNED. Byte wide insns relies only on implicit type casts to prevent reading arbitrary memory locations. */ - unsigned int len = skb->len; + unsigned int len = skb->len-skb->data_len; struct sock_filter *fentry; /* We walk down these */ u32 A = 0; /* Accumulator */ u32 X = 0; /* Index Register */ @@ -201,7 +201,7 @@ case BPF_LD|BPF_W|BPF_ABS: k = fentry->k; load_w: - if(k+sizeof(u32) <= len) { + if(k >= 0 && (unsigned int)(k+sizeof(u32)) <= len) { A = ntohl(*(u32*)&data[k]); continue; } @@ -214,13 +214,19 @@ A = ntohl(*(u32*)ptr); continue; } + } else { + u32 tmp; + if (!skb_copy_bits(skb, k, &tmp, 4)) { + A = ntohl(tmp); + continue; + } } return 0; case BPF_LD|BPF_H|BPF_ABS: k = fentry->k; load_h: - if(k + sizeof(u16) <= len) { + if(k >= 0 && (unsigned int) (k + sizeof(u16)) <= len) { A = ntohs(*(u16*)&data[k]); continue; } @@ -233,13 +239,19 @@ A = ntohs(*(u16*)ptr); continue; } + } else { + u16 tmp; + if (!skb_copy_bits(skb, k, &tmp, 2)) { + A = ntohs(tmp); + continue; + } } return 0; case BPF_LD|BPF_B|BPF_ABS: k = fentry->k; load_b: - if(k < len) { + if(k >= 0 && (unsigned int)k < len) { A = data[k]; continue; } @@ -252,6 +264,12 @@ A = *ptr; continue; } + } else { + u8 tmp; + if (!skb_copy_bits(skb, k, &tmp, 1)) { + A = tmp; + continue; + } } return 0; @@ -277,7 +295,7 @@ case BPF_LDX|BPF_B|BPF_MSH: k = fentry->k; - if(k >= len) + if(k >= 0 && (unsigned int)k >= len) return (0); X = (data[k] & 0xf) << 2; continue; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/core/iovec.c linux.ac/net/core/iovec.c --- linux.vanilla/net/core/iovec.c Fri Feb 9 19:29:44 2001 +++ linux.ac/net/core/iovec.c Sat Apr 14 01:47:59 2001 @@ -102,48 +102,6 @@ return err; } -/* Copy and checkum skb to user iovec. Caller _must_ check that - skb will fit to this iovec. - - Returns: 0 - success. - -EINVAL - checksum failure. - -EFAULT - fault during copy. Beware, in this case iovec can be - modified! - */ - -int copy_and_csum_toiovec(struct iovec *iov, struct sk_buff *skb, int hlen) -{ - unsigned int csum; - int chunk = skb->len - hlen; - - /* Skip filled elements. Pretty silly, look at memcpy_toiovec, though 8) */ - while (iov->iov_len == 0) - iov++; - - if (iov->iov_len < chunk) { - if ((unsigned short)csum_fold(csum_partial(skb->h.raw, chunk+hlen, skb->csum))) - goto csum_error; - if (memcpy_toiovec(iov, skb->h.raw + hlen, chunk)) - goto fault; - } else { - int err = 0; - csum = csum_partial(skb->h.raw, hlen, skb->csum); - csum = csum_and_copy_to_user(skb->h.raw+hlen, iov->iov_base, - chunk, csum, &err); - if (err || ((unsigned short)csum_fold(csum))) - goto csum_error; - iov->iov_len -= chunk; - iov->iov_base += chunk; - } - return 0; - -csum_error: - return -EINVAL; - -fault: - return -EFAULT; -} - /* * In kernel copy to iovec. Returns -EFAULT on error. * diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/core/netfilter.c linux.ac/net/core/netfilter.c --- linux.vanilla/net/core/netfilter.c Mon Jan 22 21:30:21 2001 +++ linux.ac/net/core/netfilter.c Sat Apr 14 01:47:59 2001 @@ -451,6 +451,19 @@ unsigned int verdict; int ret = 0; + /* This stopgap cannot be removed until all the hooks are audited. */ + if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + return -ENOMEM; + } + if (skb->ip_summed == CHECKSUM_HW) { + if (outdev == NULL) { + skb->ip_summed = CHECKSUM_NONE; + } else { + skb_checksum_help(skb); + } + } + /* We may already have this, but read-locks nest anyway */ br_read_lock_bh(BR_NETPROTO_LOCK); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/core/skbuff.c linux.ac/net/core/skbuff.c --- linux.vanilla/net/core/skbuff.c Sat Feb 17 00:06:17 2001 +++ linux.ac/net/core/skbuff.c Sat Apr 14 01:47:59 2001 @@ -4,7 +4,7 @@ * Authors: Alan Cox <iiitac@pyr.swan.ac.uk> * Florian La Roche <rzsfl@rz.uni-sb.de> * - * Version: $Id: skbuff.c,v 1.75 2000/12/08 17:15:53 davem Exp $ + * Version: $Id: skbuff.c,v 1.87 2001/03/06 22:09:50 davem Exp $ * * Fixes: * Alan Cox : Fixed the worst of the load balancer bugs. @@ -50,6 +50,7 @@ #include <linux/skbuff.h> #include <linux/cache.h> #include <linux/init.h> +#include <linux/highmem.h> #include <net/ip.h> #include <net/protocol.h> @@ -185,8 +186,8 @@ } /* Get the DATA. Size must match skb_add_mtu(). */ - size = ((size + 15) & ~15); - data = kmalloc(size + sizeof(atomic_t), gfp_mask); + size = SKB_DATA_ALIGN(size); + data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask); if (data == NULL) goto nodata; @@ -202,9 +203,12 @@ /* Set up other state */ skb->len = 0; skb->cloned = 0; + skb->data_len = 0; atomic_set(&skb->users, 1); - atomic_set(skb_datarefp(skb), 1); + atomic_set(&(skb_shinfo(skb)->dataref), 1); + skb_shinfo(skb)->nr_frags = 0; + skb_shinfo(skb)->frag_list = NULL; return skb; nodata: @@ -248,14 +252,50 @@ #endif } +static void skb_drop_fraglist(struct sk_buff *skb) +{ + struct sk_buff *list = skb_shinfo(skb)->frag_list; + + skb_shinfo(skb)->frag_list = NULL; + + do { + struct sk_buff *this = list; + list = list->next; + kfree_skb(this); + } while (list); +} + +static void skb_clone_fraglist(struct sk_buff *skb) +{ + struct sk_buff *list; + + for (list = skb_shinfo(skb)->frag_list; list; list=list->next) + skb_get(list); +} + +static void skb_release_data(struct sk_buff *skb) +{ + if (!skb->cloned || + atomic_dec_and_test(&(skb_shinfo(skb)->dataref))) { + if (skb_shinfo(skb)->nr_frags) { + int i; + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) + put_page(skb_shinfo(skb)->frags[i].page); + } + + if (skb_shinfo(skb)->frag_list) + skb_drop_fraglist(skb); + + kfree(skb->head); + } +} + /* * Free an skbuff by memory without cleaning the state. */ void kfree_skbmem(struct sk_buff *skb) { - if (!skb->cloned || atomic_dec_and_test(skb_datarefp(skb))) - kfree(skb->head); - + skb_release_data(skb); skb_head_to_pool(skb); } @@ -316,18 +356,53 @@ return NULL; } - memcpy(n, skb, sizeof(*n)); - atomic_inc(skb_datarefp(skb)); - skb->cloned = 1; - - dst_clone(n->dst); - n->cloned = 1; +#define C(x) n->x = skb->x + n->next = n->prev = NULL; n->list = NULL; n->sk = NULL; + C(stamp); + C(dev); + C(h); + C(nh); + C(mac); + C(dst); + dst_clone(n->dst); + memcpy(n->cb, skb->cb, sizeof(skb->cb)); + C(len); + C(data_len); + C(csum); + n->cloned = 1; + C(pkt_type); + C(ip_summed); + C(priority); atomic_set(&n->users, 1); + C(protocol); + C(security); + C(truesize); + C(head); + C(data); + C(tail); + C(end); n->destructor = NULL; #ifdef CONFIG_NETFILTER + C(nfmark); + C(nfcache); + C(nfct); +#ifdef CONFIG_NETFILTER_DEBUG + C(nf_debug); +#endif +#endif /*CONFIG_NETFILTER*/ +#if defined(CONFIG_HIPPI) + C(private); +#endif +#ifdef CONFIG_NET_SCHED + C(tc_index); +#endif + + atomic_inc(&(skb_shinfo(skb)->dataref)); + skb->cloned = 1; +#ifdef CONFIG_NETFILTER nf_conntrack_get(skb->nfct); #endif return n; @@ -350,7 +425,6 @@ new->nh.raw=old->nh.raw+offset; new->mac.raw=old->mac.raw+offset; memcpy(new->cb, old->cb, sizeof(old->cb)); - new->used=old->used; atomic_set(&new->users, 1); new->pkt_type=old->pkt_type; new->stamp=old->stamp; @@ -371,7 +445,7 @@ } /** - * skb_copy - copy an sk_buff + * skb_copy - create private copy of an sk_buff * @skb: buffer to copy * @gfp_mask: allocation priority * @@ -380,18 +454,115 @@ * data to alter. Returns %NULL on failure or the pointer to the buffer * on success. The returned buffer has a reference count of 1. * - * You must pass %GFP_ATOMIC as the allocation priority if this function - * is called from an interrupt. + * As by-product this function converts non-linear &sk_buff to linear + * one, so that &sk_buff becomes completely private and caller is allowed + * to modify all the data of returned buffer. This means that this + * function is not recommended for use in circumstances when only + * header is going to be modified. Use pskb_copy() instead. */ struct sk_buff *skb_copy(const struct sk_buff *skb, int gfp_mask) { struct sk_buff *n; + int headerlen = skb->data-skb->head; + + /* + * Allocate the copy buffer + */ + n=alloc_skb(skb->end - skb->head + skb->data_len, gfp_mask); + if(n==NULL) + return NULL; + + /* Set the data pointer */ + skb_reserve(n,headerlen); + /* Set the tail pointer and length */ + skb_put(n,skb->len); + n->csum = skb->csum; + n->ip_summed = skb->ip_summed; + + if (skb_copy_bits(skb, -headerlen, n->head, headerlen+skb->len)) + BUG(); + + copy_skb_header(n, skb); + + return n; +} + +/* Keep head the same: replace data */ +int skb_linearize(struct sk_buff *skb, int gfp_mask) +{ + unsigned int size; + u8 *data; + long offset; + int headerlen = skb->data - skb->head; + int expand = (skb->tail+skb->data_len) - skb->end; + + if (skb_shared(skb)) + BUG(); + + if (expand <= 0) + expand = 0; + + size = (skb->end - skb->head + expand); + size = SKB_DATA_ALIGN(size); + data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask); + if (data == NULL) + return -ENOMEM; + + /* Copy entire thing */ + if (skb_copy_bits(skb, -headerlen, data, headerlen+skb->len)) + BUG(); + + /* Offset between the two in bytes */ + offset = data - skb->head; + + /* Free old data. */ + skb_release_data(skb); + + skb->head = data; + skb->end = data + size; + + /* Set up new pointers */ + skb->h.raw += offset; + skb->nh.raw += offset; + skb->mac.raw += offset; + skb->tail += offset; + skb->data += offset; + + /* Set up shinfo */ + atomic_set(&(skb_shinfo(skb)->dataref), 1); + skb_shinfo(skb)->nr_frags = 0; + skb_shinfo(skb)->frag_list = NULL; + + /* We are no longer a clone, even if we were. */ + skb->cloned = 0; + + skb->tail += skb->data_len; + skb->data_len = 0; + return 0; +} + + +/** + * pskb_copy - create copy of an sk_buff with private head. + * @skb: buffer to copy + * @gfp_mask: allocation priority + * + * Make a copy of both an &sk_buff and part of its data, located + * in header. Fragmented data remain shared. This is used when + * the caller wishes to modify only header of &sk_buff and needs + * private copy of the header to alter. Returns %NULL on failure + * or the pointer to the buffer on success. + * The returned buffer has a reference count of 1. + */ + +struct sk_buff *pskb_copy(struct sk_buff *skb, int gfp_mask) +{ + struct sk_buff *n; /* * Allocate the copy buffer */ - n=alloc_skb(skb->end - skb->head, gfp_mask); if(n==NULL) return NULL; @@ -399,16 +570,120 @@ /* Set the data pointer */ skb_reserve(n,skb->data-skb->head); /* Set the tail pointer and length */ - skb_put(n,skb->len); + skb_put(n,skb_headlen(skb)); /* Copy the bytes */ - memcpy(n->head,skb->head,skb->end-skb->head); + memcpy(n->data, skb->data, n->len); n->csum = skb->csum; + n->ip_summed = skb->ip_summed; + + n->data_len = skb->data_len; + n->len = skb->len; + + if (skb_shinfo(skb)->nr_frags) { + int i; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i]; + get_page(skb_shinfo(n)->frags[i].page); + } + skb_shinfo(n)->nr_frags = i; + } + + if (skb_shinfo(skb)->frag_list) { + skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list; + skb_clone_fraglist(n); + } + copy_skb_header(n, skb); return n; } /** + * pskb_expand_head - reallocate header of &sk_buff + * @skb: buffer to reallocate + * @nhead: room to add at head + * @ntail: room to add at tail + * @gfp_mask: allocation priority + * + * Expands (or creates identical copy, if &nhead and &ntail are zero) + * header of skb. &sk_buff itself is not changed. &sk_buff MUST have + * reference count of 1. Returns zero in the case of success or error, + * if expansion failed. In the last case, &sk_buff is not changed. + * + * All the pointers pointing into skb header may change and must be + * reloaded after call to this function. + */ + +int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, int gfp_mask) +{ + int i; + u8 *data; + int size = nhead + (skb->end - skb->head) + ntail; + long off; + + if (skb_shared(skb)) + BUG(); + + size = SKB_DATA_ALIGN(size); + + data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask); + if (data == NULL) + goto nodata; + + /* Copy only real data... and, alas, header. This should be + * optimized for the cases when header is void. */ + memcpy(data+nhead, skb->head, skb->tail-skb->head); + memcpy(data+size, skb->end, sizeof(struct skb_shared_info)); + + for (i=0; i<skb_shinfo(skb)->nr_frags; i++) + get_page(skb_shinfo(skb)->frags[i].page); + + if (skb_shinfo(skb)->frag_list) + skb_clone_fraglist(skb); + + skb_release_data(skb); + + off = (data+nhead) - skb->head; + + skb->head = data; + skb->end = data+size; + + skb->data += off; + skb->tail += off; + skb->mac.raw += off; + skb->h.raw += off; + skb->nh.raw += off; + skb->cloned = 0; + atomic_set(&skb_shinfo(skb)->dataref, 1); + return 0; + +nodata: + return -ENOMEM; +} + +/* Make private copy of skb with writable head and some headroom */ + +struct sk_buff * +skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom) +{ + struct sk_buff *skb2; + int delta = headroom - skb_headroom(skb); + + if (delta <= 0) + return pskb_copy(skb, GFP_ATOMIC); + + skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2 == NULL || + !pskb_expand_head(skb2, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) + return skb2; + + kfree_skb(skb2); + return NULL; +} + + +/** * skb_copy_expand - copy and expand sk_buff * @skb: buffer to copy * @newheadroom: new free bytes at head @@ -439,7 +714,7 @@ * Allocate the copy buffer */ - n=alloc_skb(newheadroom + (skb->tail - skb->data) + newtailroom, + n=alloc_skb(newheadroom + skb->len + newtailroom, gfp_mask); if(n==NULL) return NULL; @@ -450,12 +725,431 @@ skb_put(n,skb->len); /* Copy the data only. */ - memcpy(n->data, skb->data, skb->len); + if (skb_copy_bits(skb, 0, n->data, skb->len)) + BUG(); copy_skb_header(n, skb); return n; } +/* Trims skb to length len. It can change skb pointers, if "realloc" is 1. + * If realloc==0 and trimming is impossible without change of data, + * it is BUG(). + */ + +int ___pskb_trim(struct sk_buff *skb, unsigned int len, int realloc) +{ + int offset = skb_headlen(skb); + int nfrags = skb_shinfo(skb)->nr_frags; + int i; + + for (i=0; i<nfrags; i++) { + int end = offset + skb_shinfo(skb)->frags[i].size; + if (end > len) { + if (skb_cloned(skb)) { + if (!realloc) + BUG(); + if (!pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) + return -ENOMEM; + } + if (len <= offset) { + put_page(skb_shinfo(skb)->frags[i].page); + skb_shinfo(skb)->nr_frags--; + } else { + skb_shinfo(skb)->frags[i].size = len-offset; + } + } + offset = end; + } + + if (offset < len) { + skb->data_len -= skb->len - len; + skb->len = len; + } else { + if (len <= skb_headlen(skb)) { + skb->len = len; + skb->data_len = 0; + skb->tail = skb->data + len; + if (skb_shinfo(skb)->frag_list && !skb_cloned(skb)) + skb_drop_fraglist(skb); + } else { + skb->data_len -= skb->len - len; + skb->len = len; + } + } + + return 0; +} + +/** + * __pskb_pull_tail - advance tail of skb header + * @skb: buffer to reallocate + * @delta: number of bytes to advance tail + * + * The function makes a sense only on a fragmented &sk_buff, + * it expands header moving its tail forward and copying necessary + * data from fragmented part. + * + * &sk_buff MUST have reference count of 1. + * + * Returns %NULL (and &sk_buff does not change) if pull failed + * or value of new tail of skb in the case of success. + * + * All the pointers pointing into skb header may change and must be + * reloaded after call to this function. + */ + +/* Moves tail of skb head forward, copying data from fragmented part, + * when it is necessary. + * 1. It may fail due to malloc failure. + * 2. It may change skb pointers. + * + * It is pretty complicated. Luckily, it is called only in exceptional cases. + */ +unsigned char * __pskb_pull_tail(struct sk_buff *skb, int delta) +{ + int i, k, eat; + + /* If skb has not enough free space at tail, get new one + * plus 128 bytes for future expansions. If we have enough + * room at tail, reallocate without expansion only if skb is cloned. + */ + eat = (skb->tail+delta) - skb->end; + + if (eat > 0 || skb_cloned(skb)) { + if (pskb_expand_head(skb, 0, eat>0 ? eat+128 : 0, GFP_ATOMIC)) + return NULL; + } + + if (skb_copy_bits(skb, skb_headlen(skb), skb->tail, delta)) + BUG(); + + /* Optimization: no fragments, no reasons to preestimate + * size of pulled pages. Superb. + */ + if (skb_shinfo(skb)->frag_list == NULL) + goto pull_pages; + + /* Estimate size of pulled pages. */ + eat = delta; + for (i=0; i<skb_shinfo(skb)->nr_frags; i++) { + if (skb_shinfo(skb)->frags[i].size >= eat) + goto pull_pages; + eat -= skb_shinfo(skb)->frags[i].size; + } + + /* If we need update frag list, we are in troubles. + * Certainly, it possible to add an offset to skb data, + * but taking into account that pulling is expected to + * be very rare operation, it is worth to fight against + * further bloating skb head and crucify ourselves here instead. + * Pure masohism, indeed. 8)8) + */ + if (eat) { + struct sk_buff *list = skb_shinfo(skb)->frag_list; + struct sk_buff *clone = NULL; + struct sk_buff *insp = NULL; + + do { + if (list == NULL) + BUG(); + + if (list->len <= eat) { + /* Eaten as whole. */ + eat -= list->len; + list = list->next; + insp = list; + } else { + /* Eaten partially. */ + + if (skb_shared(list)) { + /* Sucks! We need to fork list. :-( */ + clone = skb_clone(list, GFP_ATOMIC); + if (clone == NULL) + return NULL; + insp = list->next; + list = clone; + } else { + /* This may be pulled without + * problems. */ + insp = list; + } + if (pskb_pull(list, eat) == NULL) { + if (clone) + kfree_skb(clone); + return NULL; + } + break; + } + } while (eat); + + /* Free pulled out fragments. */ + while ((list = skb_shinfo(skb)->frag_list) != insp) { + skb_shinfo(skb)->frag_list = list->next; + kfree_skb(list); + } + /* And insert new clone at head. */ + if (clone) { + clone->next = list; + skb_shinfo(skb)->frag_list = clone; + } + } + /* Success! Now we may commit changes to skb data. */ + +pull_pages: + eat = delta; + k = 0; + for (i=0; i<skb_shinfo(skb)->nr_frags; i++) { + if (skb_shinfo(skb)->frags[i].size <= eat) { + put_page(skb_shinfo(skb)->frags[i].page); + eat -= skb_shinfo(skb)->frags[i].size; + } else { + skb_shinfo(skb)->frags[k] = skb_shinfo(skb)->frags[i]; + if (eat) { + skb_shinfo(skb)->frags[k].page_offset += eat; + skb_shinfo(skb)->frags[k].size -= eat; + eat = 0; + } + k++; + } + } + skb_shinfo(skb)->nr_frags = k; + + skb->tail += delta; + skb->data_len -= delta; + + return skb->tail; +} + +/* Copy some data bits from skb to kernel buffer. */ + +int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len) +{ + int i, copy; + int start = skb->len - skb->data_len; + + if (offset > (int)skb->len-len) + goto fault; + + /* Copy header. */ + if ((copy = start-offset) > 0) { + if (copy > len) + copy = len; + memcpy(to, skb->data + offset, copy); + if ((len -= copy) == 0) + return 0; + offset += copy; + to += copy; + } + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + int end; + + BUG_TRAP(start <= offset+len); + + end = start + skb_shinfo(skb)->frags[i].size; + if ((copy = end-offset) > 0) { + u8 *vaddr; + + if (copy > len) + copy = len; + + vaddr = kmap_skb_frag(&skb_shinfo(skb)->frags[i]); + memcpy(to, vaddr+skb_shinfo(skb)->frags[i].page_offset+ + offset-start, copy); + kunmap_skb_frag(vaddr); + + if ((len -= copy) == 0) + return 0; + offset += copy; + to += copy; + } + start = end; + } + + if (skb_shinfo(skb)->frag_list) { + struct sk_buff *list; + + for (list = skb_shinfo(skb)->frag_list; list; list=list->next) { + int end; + + BUG_TRAP(start <= offset+len); + + end = start + list->len; + if ((copy = end-offset) > 0) { + if (copy > len) + copy = len; + if (skb_copy_bits(list, offset-start, to, copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + to += copy; + } + start = end; + } + } + if (len == 0) + return 0; + +fault: + return -EFAULT; +} + +/* Checksum skb data. */ + +unsigned int skb_checksum(const struct sk_buff *skb, int offset, int len, unsigned int csum) +{ + int i, copy; + int start = skb->len - skb->data_len; + int pos = 0; + + /* Checksum header. */ + if ((copy = start-offset) > 0) { + if (copy > len) + copy = len; + csum = csum_partial(skb->data+offset, copy, csum); + if ((len -= copy) == 0) + return csum; + offset += copy; + pos = copy; + } + + for (i=0; i<skb_shinfo(skb)->nr_frags; i++) { + int end; + + BUG_TRAP(start <= offset+len); + + end = start + skb_shinfo(skb)->frags[i].size; + if ((copy = end-offset) > 0) { + unsigned int csum2; + u8 *vaddr; + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + if (copy > len) + copy = len; + vaddr = kmap_skb_frag(frag); + csum2 = csum_partial(vaddr + frag->page_offset + + offset-start, copy, 0); + kunmap_skb_frag(vaddr); + csum = csum_block_add(csum, csum2, pos); + if (!(len -= copy)) + return csum; + offset += copy; + pos += copy; + } + start = end; + } + + if (skb_shinfo(skb)->frag_list) { + struct sk_buff *list; + + for (list = skb_shinfo(skb)->frag_list; list; list=list->next) { + int end; + + BUG_TRAP(start <= offset+len); + + end = start + list->len; + if ((copy = end-offset) > 0) { + unsigned int csum2; + if (copy > len) + copy = len; + csum2 = skb_checksum(list, offset-start, copy, 0); + csum = csum_block_add(csum, csum2, pos); + if ((len -= copy) == 0) + return csum; + offset += copy; + pos += copy; + } + start = end; + } + } + if (len == 0) + return csum; + + BUG(); + return csum; +} + +/* Both of above in one bottle. */ + +unsigned int skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, int len, unsigned int csum) +{ + int i, copy; + int start = skb->len - skb->data_len; + int pos = 0; + + /* Copy header. */ + if ((copy = start-offset) > 0) { + if (copy > len) + copy = len; + csum = csum_partial_copy_nocheck(skb->data+offset, to, copy, csum); + if ((len -= copy) == 0) + return csum; + offset += copy; + to += copy; + pos = copy; + } + + for (i=0; i<skb_shinfo(skb)->nr_frags; i++) { + int end; + + BUG_TRAP(start <= offset+len); + + end = start + skb_shinfo(skb)->frags[i].size; + if ((copy = end-offset) > 0) { + unsigned int csum2; + u8 *vaddr; + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + if (copy > len) + copy = len; + vaddr = kmap_skb_frag(frag); + csum2 = csum_partial_copy_nocheck(vaddr + frag->page_offset + + offset-start, to, copy, 0); + kunmap_skb_frag(vaddr); + csum = csum_block_add(csum, csum2, pos); + if (!(len -= copy)) + return csum; + offset += copy; + to += copy; + pos += copy; + } + start = end; + } + + if (skb_shinfo(skb)->frag_list) { + struct sk_buff *list; + + for (list = skb_shinfo(skb)->frag_list; list; list=list->next) { + unsigned int csum2; + int end; + + BUG_TRAP(start <= offset+len); + + end = start + list->len; + if ((copy = end-offset) > 0) { + if (copy > len) + copy = len; + csum2 = skb_copy_and_csum_bits(list, offset-start, to, copy, 0); + csum = csum_block_add(csum, csum2, pos); + if ((len -= copy) == 0) + return csum; + offset += copy; + to += copy; + pos += copy; + } + start = end; + } + } + if (len == 0) + return csum; + + BUG(); + return csum; +} + + #if 0 /* * Tune the memory allocator for a new MTU size. @@ -463,7 +1157,7 @@ void skb_add_mtu(int mtu) { /* Must match allocation in alloc_skb */ - mtu = ((mtu + 15) & ~15) + sizeof(atomic_t); + mtu = SKB_DATA_ALIGN(mtu) + sizeof(struct skb_shared_info); kmem_add_cache_size(mtu); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/core/sock.c linux.ac/net/core/sock.c --- linux.vanilla/net/core/sock.c Sat Feb 3 19:26:44 2001 +++ linux.ac/net/core/sock.c Sat Apr 14 01:47:59 2001 @@ -7,7 +7,7 @@ * handler for protocols to use and generic option handler. * * - * Version: $Id: sock.c,v 1.104 2001/01/30 07:48:30 davem Exp $ + * Version: $Id: sock.c,v 1.109 2001/03/03 01:20:10 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -79,6 +79,7 @@ * Jay Schulist : Added SO_ATTACH_FILTER and SO_DETACH_FILTER. * Andi Kleen : Add sock_kmalloc()/sock_kfree_s() * Andi Kleen : Fix write_space callback + * Chris Evans : Security fixes - signedness again * * To Fix: * @@ -425,11 +426,13 @@ struct timeval tm; } v; - int lv=sizeof(int),len; + unsigned int lv=sizeof(int),len; if(get_user(len,optlen)) return -EFAULT; - + if(len < 0) + return -EINVAL; + switch(optname) { case SO_DEBUG: @@ -727,6 +730,8 @@ clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); add_wait_queue(sk->sleep, &wait); for (;;) { + if (!timeo) + break; if (signal_pending(current)) break; set_bit(SOCK_NOSPACE, &sk->socket->flags); @@ -750,7 +755,7 @@ */ struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, - unsigned long fallback, int noblock, int *errcode) + int noblock, int *errcode) { int err; struct sk_buff *skb; @@ -780,15 +785,6 @@ goto failure; if (atomic_read(&sk->wmem_alloc) < sk->sndbuf) { - if (fallback) { - /* The buffer get won't block, or use the atomic queue. - * It does produce annoying no free page messages still. - */ - skb = alloc_skb(size, GFP_BUFFER); - if (skb) - break; - try_size = fallback; - } skb = alloc_skb(try_size, sk->allocation); if (skb) break; @@ -1064,6 +1060,36 @@ { /* Mirror missing mmap method error code */ return -ENODEV; +} + +ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags) +{ + ssize_t res; + struct msghdr msg; + struct iovec iov; + mm_segment_t old_fs; + char *kaddr; + + kaddr = kmap(page); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = flags; + + iov.iov_base = kaddr + offset; + iov.iov_len = size; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + res = sock_sendmsg(sock, &msg, size); + set_fs(old_fs); + + kunmap(page); + return res; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/decnet/af_decnet.c linux.ac/net/decnet/af_decnet.c --- linux.vanilla/net/decnet/af_decnet.c Tue Apr 3 17:32:30 2001 +++ linux.ac/net/decnet/af_decnet.c Sat Apr 14 01:48:10 2001 @@ -2128,6 +2128,7 @@ sendmsg: dn_sendmsg, recvmsg: dn_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #ifdef CONFIG_SYSCTL diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/econet/Makefile linux.ac/net/econet/Makefile --- linux.vanilla/net/econet/Makefile Fri Dec 29 22:07:24 2000 +++ linux.ac/net/econet/Makefile Tue Apr 3 17:55:19 2001 @@ -9,7 +9,8 @@ O_TARGET := econet.o -obj-y := af_econet.o sysctl_net_ec.o +obj-y := af_econet.o obj-m := $(O_TARGET) include $(TOPDIR)/Rules.make + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/econet/af_econet.c linux.ac/net/econet/af_econet.c --- linux.vanilla/net/econet/af_econet.c Mon Oct 16 20:42:54 2000 +++ linux.ac/net/econet/af_econet.c Sat Apr 14 01:48:10 2001 @@ -297,7 +297,7 @@ #ifdef CONFIG_ECONET_NATIVE atomic_inc(&dev->refcnt); - skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0, + skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, msg->msg_flags & MSG_DONTWAIT, &err); if (skb==NULL) goto out_unlock; @@ -410,7 +410,7 @@ } /* Get a skbuff (no data, just holds our cb information) */ - if ((skb = sock_alloc_send_skb(sk, 0, 0, + if ((skb = sock_alloc_send_skb(sk, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) return err; @@ -695,8 +695,8 @@ } static struct net_proto_family econet_family_ops = { - PF_ECONET, - econet_create + family: PF_ECONET, + create: econet_create, }; static struct proto_ops SOCKOPS_WRAPPED(econet_ops) = { @@ -717,6 +717,7 @@ sendmsg: econet_sendmsg, recvmsg: econet_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #include <linux/smp_lock.h> @@ -726,7 +727,7 @@ * Find the listening socket, if any, for the given data. */ -struct sock *ec_listening_socket(unsigned char port, unsigned char +static struct sock *ec_listening_socket(unsigned char port, unsigned char station, unsigned char net) { struct sock *sk = econet_sklist; @@ -1064,18 +1065,13 @@ hdr->port); } -struct packet_type econet_packet_type= -{ - 0, - NULL, - econet_rcv, - NULL, - NULL +static struct packet_type econet_packet_type = { + type: __constant_htons(ETH_P_ECONET), + func: econet_rcv, }; static void econet_hw_initialise(void) { - econet_packet_type.type = htons(ETH_P_ECONET); dev_add_pack(&econet_packet_type); } @@ -1104,15 +1100,12 @@ return NOTIFY_DONE; } -struct notifier_block econet_netdev_notifier={ - econet_notifier, - NULL, - 0 +static struct notifier_block econet_netdev_notifier = { + notifier_call: econet_notifier, }; -void __exit econet_proto_exit(void) +static void __exit econet_proto_exit(void) { - extern void econet_sysctl_unregister(void); #ifdef CONFIG_ECONET_AUNUDP del_timer(&ab_cleanup_timer); if (udpsock) @@ -1120,14 +1113,10 @@ #endif unregister_netdevice_notifier(&econet_netdev_notifier); sock_unregister(econet_family_ops.family); -#ifdef CONFIG_SYSCTL - econet_sysctl_unregister(); -#endif } -int __init econet_proto_init(void) +static int __init econet_proto_init(void) { - extern void econet_sysctl_register(void); sock_register(&econet_family_ops); #ifdef CONFIG_ECONET_AUNUDP spin_lock_init(&aun_queue_lock); @@ -1137,9 +1126,6 @@ econet_hw_initialise(); #endif register_netdevice_notifier(&econet_netdev_notifier); -#ifdef CONFIG_SYSCTL - econet_sysctl_register(); -#endif return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/econet/sysctl_net_ec.c linux.ac/net/econet/sysctl_net_ec.c --- linux.vanilla/net/econet/sysctl_net_ec.c Thu Mar 9 14:57:17 2000 +++ linux.ac/net/econet/sysctl_net_ec.c Thu Jan 1 01:00:00 1970 @@ -1,43 +0,0 @@ -/* - * An implementation of the Acorn Econet and AUN protocols. - * Philip Blundell <philb@gnu.org> - * - * Fixes: - * - * 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 <linux/mm.h> -#include <linux/sysctl.h> - -ctl_table econet_table[] = { - {0} -}; - -static struct ctl_table_header *econet_sysctl_header; - -static ctl_table econet_net_table[] = { - {NET_ECONET, "econet", NULL, 0, 0555, econet_table}, - {0} -}; - -static ctl_table econet_root_table[] = { - {CTL_NET, "net", NULL, 0, 0555, econet_net_table}, - {0} -}; - -void econet_sysctl_register(void) -{ - econet_sysctl_header = register_sysctl_table(econet_root_table, 0); -} - -#ifdef MODULE -void econet_sysctl_unregister(void) -{ - unregister_sysctl_table(econet_sysctl_header); -} -#endif /* MODULE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/af_inet.c linux.ac/net/ipv4/af_inet.c --- linux.vanilla/net/ipv4/af_inet.c Fri Dec 29 22:07:24 2000 +++ linux.ac/net/ipv4/af_inet.c Sat Apr 14 01:49:50 2001 @@ -5,7 +5,7 @@ * * PF_INET protocol family socket handler. * - * Version: $Id: af_inet.c,v 1.127 2000/12/22 19:51:50 davem Exp $ + * Version: $Id: af_inet.c,v 1.129 2001/03/02 03:13:05 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -355,6 +355,8 @@ else sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_WANT; + sk->protinfo.af_inet.id = 0; + sock_init_data(sock,sk); sk->destruct = inet_sock_destruct; @@ -934,7 +936,8 @@ getsockopt: inet_getsockopt, sendmsg: inet_sendmsg, recvmsg: inet_recvmsg, - mmap: sock_no_mmap + mmap: sock_no_mmap, + sendpage: tcp_sendpage }; struct proto_ops inet_dgram_ops = { @@ -955,6 +958,7 @@ sendmsg: inet_sendmsg, recvmsg: inet_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; struct net_proto_family inet_family_ops = { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/arp.c linux.ac/net/ipv4/arp.c --- linux.vanilla/net/ipv4/arp.c Fri Feb 9 19:34:13 2001 +++ linux.ac/net/ipv4/arp.c Sat Apr 14 01:49:50 2001 @@ -1,6 +1,6 @@ /* linux/net/inet/arp.c * - * Version: $Id: arp.c,v 1.90 2000/10/04 09:20:56 anton Exp $ + * Version: $Id: arp.c,v 1.96 2001/02/02 08:42:59 davem Exp $ * * Copyright (C) 1994 by Florian La Roche * @@ -590,6 +590,13 @@ if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) goto out_of_mem; + if (skb_is_nonlinear(skb)) { + if (skb_linearize(skb, GFP_ATOMIC) != 0) + goto freeskb; + arp = skb->nh.arph; + arp_ptr= (unsigned char *)(arp+1); + } + switch (dev_type) { default: if (arp->ar_pro != __constant_htons(ETH_P_IP)) @@ -796,9 +803,10 @@ } out: - kfree_skb(skb); if (in_dev) in_dev_put(in_dev); +freeskb: + kfree_skb(skb); out_of_mem: return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/icmp.c linux.ac/net/ipv4/icmp.c --- linux.vanilla/net/ipv4/icmp.c Sat Aug 5 02:18:49 2000 +++ linux.ac/net/ipv4/icmp.c Tue Apr 17 15:30:37 2001 @@ -3,7 +3,7 @@ * * Alan Cox, <alan@redhat.com> * - * Version: $Id: icmp.c,v 1.71 2000/08/02 06:01:48 davem Exp $ + * Version: $Id: icmp.c,v 1.73 2000/12/13 18:31:48 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -58,197 +58,6 @@ * - Should use skb_pull() instead of all the manual checking. * This would also greatly simply some upper layer error handlers. --AK * - * RFC1122 (Host Requirements -- Comm. Layer) Status: - * (boy, are there a lot of rules for ICMP) - * 3.2.2 (Generic ICMP stuff) - * MUST discard messages of unknown type. (OK) - * MUST copy at least the first 8 bytes from the offending packet - * when sending ICMP errors. (OBSOLETE -- see RFC1812) - * MUST pass received ICMP errors up to protocol level. (OK) - * SHOULD send ICMP errors with TOS == 0. (OBSOLETE -- see RFC1812) - * MUST NOT send ICMP errors in reply to: - * ICMP errors (OK) - * Broadcast/multicast datagrams (OK) - * MAC broadcasts (OK) - * Non-initial fragments (OK) - * Datagram with a source address that isn't a single host. (OK) - * 3.2.2.1 (Destination Unreachable) - * All the rules govern the IP layer, and are dealt with in ip.c, not here. - * 3.2.2.2 (Redirect) - * Host SHOULD NOT send ICMP_REDIRECTs. (OK) - * MUST update routing table in response to host or network redirects. - * (host OK, network OBSOLETE) - * SHOULD drop redirects if they're not from directly connected gateway - * (OK -- we drop it if it's not from our old gateway, which is close - * enough) - * 3.2.2.3 (Source Quench) - * MUST pass incoming SOURCE_QUENCHs to transport layer (OK) - * Other requirements are dealt with at the transport layer. - * 3.2.2.4 (Time Exceeded) - * MUST pass TIME_EXCEEDED to transport layer (OK) - * Other requirements dealt with at IP (generating TIME_EXCEEDED). - * 3.2.2.5 (Parameter Problem) - * SHOULD generate these (OK) - * MUST pass received PARAMPROBLEM to transport layer (NOT YET) - * [Solaris 2.X seems to assert EPROTO when this occurs] -- AC - * 3.2.2.6 (Echo Request/Reply) - * MUST reply to ECHO_REQUEST, and give app to do ECHO stuff (OK, OK) - * MAY discard broadcast ECHO_REQUESTs. (Configurable with a sysctl.) - * MUST reply using same source address as the request was sent to. - * We're OK for unicast ECHOs, and it doesn't say anything about - * how to handle broadcast ones, since it's optional. - * MUST copy data from REQUEST to REPLY (OK) - * unless it would require illegal fragmentation (OK) - * MUST pass REPLYs to transport/user layer (OK) - * MUST use any provided source route (reversed) for REPLY. (NOT YET) - * 3.2.2.7 (Information Request/Reply) - * MUST NOT implement this. (I guess that means silently discard...?) (OK) - * 3.2.2.8 (Timestamp Request/Reply) - * MAY implement (OK) - * SHOULD be in-kernel for "minimum variability" (OK) - * MAY discard broadcast REQUESTs. (OK, but see source for inconsistency) - * MUST reply using same source address as the request was sent to. (OK) - * MUST reverse source route, as per ECHO (NOT YET) - * MUST pass REPLYs to transport/user layer (requires RAW, just like - * ECHO) (OK) - * MUST update clock for timestamp at least 15 times/sec (OK) - * MUST be "correct within a few minutes" (OK) - * 3.2.2.9 (Address Mask Request/Reply) - * MAY implement (OK) - * MUST send a broadcast REQUEST if using this system to set netmask - * (OK... we don't use it) - * MUST discard received REPLYs if not using this system (OK) - * MUST NOT send replies unless specifically made agent for this sort - * of thing. (OK) - * - * - * RFC 1812 (IPv4 Router Requirements) Status (even longer): - * 4.3.2.1 (Unknown Message Types) - * MUST pass messages of unknown type to ICMP user iface or silently discard - * them (OK) - * 4.3.2.2 (ICMP Message TTL) - * MUST initialize TTL when originating an ICMP message (OK) - * 4.3.2.3 (Original Message Header) - * SHOULD copy as much data from the offending packet as possible without - * the length of the ICMP datagram exceeding 576 bytes (OK) - * MUST leave original IP header of the offending packet, but we're not - * required to undo modifications made (OK) - * 4.3.2.4 (Original Message Source Address) - * MUST use one of addresses for the interface the orig. packet arrived as - * source address (OK) - * 4.3.2.5 (TOS and Precedence) - * SHOULD leave TOS set to the same value unless the packet would be - * discarded for that reason (OK) - * MUST use TOS=0 if not possible to leave original value (OK) - * MUST leave IP Precedence for Source Quench messages (OK -- not sent - * at all) - * SHOULD use IP Precedence = 6 (Internetwork Control) or 7 (Network Control) - * for all other error messages (OK, we use 6) - * MAY allow configuration of IP Precedence (OK -- not done) - * MUST leave IP Precedence and TOS for reply messages (OK) - * 4.3.2.6 (Source Route) - * SHOULD use reverse source route UNLESS sending Parameter Problem on source - * routing and UNLESS the packet would be immediately discarded (NOT YET) - * 4.3.2.7 (When Not to Send ICMP Errors) - * MUST NOT send ICMP errors in reply to: - * ICMP errors (OK) - * Packets failing IP header validation tests unless otherwise noted (OK) - * Broadcast/multicast datagrams (OK) - * MAC broadcasts (OK) - * Non-initial fragments (OK) - * Datagram with a source address that isn't a single host. (OK) - * 4.3.2.8 (Rate Limiting) - * SHOULD be able to limit error message rate (OK) - * SHOULD allow setting of rate limits (OK, in the source) - * 4.3.3.1 (Destination Unreachable) - * All the rules govern the IP layer, and are dealt with in ip.c, not here. - * 4.3.3.2 (Redirect) - * MAY ignore ICMP Redirects if running a routing protocol or if forwarding - * is enabled on the interface (OK -- ignores) - * 4.3.3.3 (Source Quench) - * SHOULD NOT originate SQ messages (OK) - * MUST be able to limit SQ rate if originates them (OK as we don't - * send them) - * MAY ignore SQ messages it receives (OK -- we don't) - * 4.3.3.4 (Time Exceeded) - * Requirements dealt with at IP (generating TIME_EXCEEDED). - * 4.3.3.5 (Parameter Problem) - * MUST generate these for all errors not covered by other messages (OK) - * MUST include original value of the value pointed by (OK) - * 4.3.3.6 (Echo Request) - * MUST implement echo server function (OK) - * MUST process at ER of at least max(576, MTU) (OK) - * MAY reject broadcast/multicast ER's (We don't, but that's OK) - * SHOULD have a config option for silently ignoring ER's (OK) - * MUST have a default value for the above switch = NO (OK) - * MUST have application layer interface for Echo Request/Reply (OK) - * MUST reply using same source address as the request was sent to. - * We're OK for unicast ECHOs, and it doesn't say anything about - * how to handle broadcast ones, since it's optional. - * MUST copy data from Request to Reply (OK) - * SHOULD update Record Route / Timestamp options (??) - * MUST use reversed Source Route for Reply if possible (NOT YET) - * 4.3.3.7 (Information Request/Reply) - * SHOULD NOT originate or respond to these (OK) - * 4.3.3.8 (Timestamp / Timestamp Reply) - * MAY implement (OK) - * MUST reply to every Timestamp message received (OK) - * MAY discard broadcast REQUESTs. (OK, but see source for inconsistency) - * MUST reply using same source address as the request was sent to. (OK) - * MUST use reversed Source Route if possible (NOT YET) - * SHOULD update Record Route / Timestamp options (??) - * MUST pass REPLYs to transport/user layer (requires RAW, just like - * ECHO) (OK) - * MUST update clock for timestamp at least 16 times/sec (OK) - * MUST be "correct within a few minutes" (OK) - * 4.3.3.9 (Address Mask Request/Reply) - * MUST have support for receiving AMRq and responding with AMRe (OK, - * but only as a compile-time option) - * SHOULD have option for each interface for AMRe's, MUST default to - * NO (NOT YET) - * MUST NOT reply to AMRq before knows the correct AM (OK) - * MUST NOT respond to AMRq with source address 0.0.0.0 on physical - * interfaces having multiple logical i-faces with different masks - * (NOT YET) - * SHOULD examine all AMRe's it receives and check them (NOT YET) - * SHOULD log invalid AMRe's (AM+sender) (NOT YET) - * MUST NOT use contents of AMRe to determine correct AM (OK) - * MAY broadcast AMRe's after having configured address masks (OK -- doesn't) - * MUST NOT do broadcast AMRe's if not set by extra option (OK, no option) - * MUST use the { <NetPrefix>, -1 } form of broadcast addresses (OK) - * 4.3.3.10 (Router Advertisement and Solicitations) - * MUST support router part of Router Discovery Protocol on all networks we - * support broadcast or multicast addressing. (OK -- done by gated) - * MUST have all config parameters with the respective defaults (OK) - * 5.2.7.1 (Destination Unreachable) - * MUST generate DU's (OK) - * SHOULD choose a best-match response code (OK) - * SHOULD NOT generate Host Isolated codes (OK) - * SHOULD use Communication Administratively Prohibited when administratively - * filtering packets (NOT YET -- bug-to-bug compatibility) - * MAY include config option for not generating the above and silently - * discard the packets instead (OK) - * MAY include config option for not generating Precedence Violation and - * Precedence Cutoff messages (OK as we don't generate them at all) - * MUST use Host Unreachable or Dest. Host Unknown codes whenever other hosts - * on the same network might be reachable (OK -- no net unreach's at all) - * MUST use new form of Fragmentation Needed and DF Set messages (OK) - * 5.2.7.2 (Redirect) - * MUST NOT generate network redirects (OK) - * MUST be able to generate host redirects (OK) - * SHOULD be able to generate Host+TOS redirects (NO as we don't use TOS) - * MUST have an option to use Host redirects instead of Host+TOS ones (OK as - * no Host+TOS Redirects are used) - * MUST NOT generate redirects unless forwarding to the same i-face and the - * dest. address is on the same subnet as the src. address and no source - * routing is in use. (OK) - * MUST NOT follow redirects when using a routing protocol (OK) - * MAY use redirects if not using a routing protocol (OK, compile-time option) - * MUST comply to Host Requirements when not acting as a router (OK) - * 5.2.7.3 (Time Exceeded) - * MUST generate Time Exceeded Code 0 when discarding packet due to TTL=0 (OK) - * MAY have a per-interface option to disable origination of TE messages, but - * it MUST default to "originate" (OK -- we don't support it) */ #include <linux/config.h> @@ -282,6 +91,26 @@ #define min(a,b) ((a)<(b)?(a):(b)) /* + * Build xmit assembly blocks + */ + +struct icmp_bxm +{ + struct sk_buff *skb; + int offset; + int data_len; + + unsigned int csum; + struct { + struct icmphdr icmph; + __u32 times[3]; + } data; + int head_len; + struct ip_options replyopts; + unsigned char optbuf[40]; +}; + +/* * Statistics */ @@ -324,7 +153,7 @@ { unsigned long *output; /* Address to increment on output */ unsigned long *input; /* Address to increment on input */ - void (*handler)(struct icmphdr *icmph, struct sk_buff *skb, int len); + void (*handler)(struct sk_buff *skb); short error; /* This ICMP is classed as an error message */ int *timeout; /* Rate limit */ }; @@ -466,11 +295,12 @@ { struct icmp_bxm *icmp_param = (struct icmp_bxm *)p; struct icmphdr *icmph; - unsigned long csum; + unsigned int csum; if (offset) { - icmp_param->csum=csum_partial_copy_nocheck(icmp_param->data_ptr+offset-sizeof(struct icmphdr), - to, fraglen,icmp_param->csum); + icmp_param->csum=skb_copy_and_csum_bits(icmp_param->skb, + icmp_param->offset+(offset-icmp_param->head_len), + to, fraglen,icmp_param->csum); return 0; } @@ -479,22 +309,24 @@ * the other fragments first, so that we get the checksum * for the whole packet here. */ - csum = csum_partial_copy_nocheck((void *)&icmp_param->icmph, - to, sizeof(struct icmphdr), + csum = csum_partial_copy_nocheck((void *)&icmp_param->data, + to, icmp_param->head_len, icmp_param->csum); - csum = csum_partial_copy_nocheck(icmp_param->data_ptr, - to+sizeof(struct icmphdr), - fraglen-sizeof(struct icmphdr), csum); + csum=skb_copy_and_csum_bits(icmp_param->skb, + icmp_param->offset, + to+icmp_param->head_len, + fraglen-icmp_param->head_len, + csum); icmph=(struct icmphdr *)to; icmph->checksum = csum_fold(csum); return 0; } - + /* * Driving logic for building and sending ICMP messages. */ -void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) +static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) { struct sock *sk=icmp_socket->sk; struct ipcm_cookie ipc; @@ -507,9 +339,9 @@ if (icmp_xmit_lock_bh()) return; - icmp_param->icmph.checksum=0; + icmp_param->data.icmph.checksum=0; icmp_param->csum=0; - icmp_out_count(icmp_param->icmph.type); + icmp_out_count(icmp_param->data.icmph.type); sk->protinfo.af_inet.tos = skb->nh.iph->tos; daddr = ipc.addr = rt->rt_src; @@ -521,10 +353,10 @@ } if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0)) goto out; - if (icmpv4_xrlim_allow(rt, icmp_param->icmph.type, - icmp_param->icmph.code)) { + if (icmpv4_xrlim_allow(rt, icmp_param->data.icmph.type, + icmp_param->data.icmph.code)) { ip_build_xmit(sk, icmp_glue_bits, icmp_param, - icmp_param->data_len+sizeof(struct icmphdr), + icmp_param->data_len+icmp_param->head_len, &ipc, rt, MSG_DONTWAIT); } ip_rt_put(rt); @@ -543,10 +375,9 @@ * MUST reply to only the first fragment. */ -void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info) +void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info) { struct iphdr *iph; - struct icmphdr *icmph; int room; struct icmp_bxm icmp_param; struct rtable *rt = (struct rtable*)skb_in->dst; @@ -558,10 +389,15 @@ return; /* - * Find the original header + * Find the original header. It is expected to be valid, of course. + * Check this, icmp_send is called from the most obscure devices + * sometimes. */ iph = skb_in->nh.iph; + if ((u8*)iph < skb_in->head || (u8*)(iph+1) > skb_in->tail) + return; + /* * No replies to physical multicast/broadcast */ @@ -589,17 +425,24 @@ * We are an error, check if we are replying to an ICMP error */ if (iph->protocol==IPPROTO_ICMP) { - icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2)); + u8 inner_type; + + if (skb_copy_bits(skb_in, + skb_in->nh.raw + (iph->ihl<<2) + + offsetof(struct icmphdr, type) + - skb_in->data, + &inner_type, 1)) + return; + /* * Assume any unknown ICMP type is an error. This isn't * specified by the RFC, but think about it.. */ - if (icmph->type>NR_ICMP_TYPES || icmp_pointers[icmph->type].error) + if (inner_type>NR_ICMP_TYPES || icmp_pointers[inner_type].error) return; } } - if (icmp_xmit_lock()) return; @@ -625,12 +468,6 @@ ((iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL) : iph->tos; - /* XXX: use a more aggressive expire for routes created by - * this call (not longer than the rate limit timeout). - * It could be also worthwhile to not put them into ipv4 - * fast routing cache at first. Otherwise an attacker can - * grow the routing table. - */ if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0)) goto out; @@ -642,13 +479,14 @@ * Prepare data for ICMP header. */ - icmp_param.icmph.type=type; - icmp_param.icmph.code=code; - icmp_param.icmph.un.gateway = info; - icmp_param.icmph.checksum=0; + icmp_param.data.icmph.type=type; + icmp_param.data.icmph.code=code; + icmp_param.data.icmph.un.gateway = info; + icmp_param.data.icmph.checksum=0; icmp_param.csum=0; - icmp_param.data_ptr=iph; - icmp_out_count(icmp_param.icmph.type); + icmp_param.skb=skb_in; + icmp_param.offset=skb_in->nh.raw - skb_in->data; + icmp_out_count(icmp_param.data.icmph.type); icmp_socket->sk->protinfo.af_inet.tos = tos; ipc.addr = iph->saddr; ipc.opt = &icmp_param.replyopts; @@ -669,10 +507,11 @@ room -= sizeof(struct iphdr) + icmp_param.replyopts.optlen; room -= sizeof(struct icmphdr); - icmp_param.data_len=(skb_in->tail-(u8*)iph); + icmp_param.data_len=skb_in->len-icmp_param.offset; if (icmp_param.data_len > room) icmp_param.data_len = room; - + icmp_param.head_len = sizeof(struct icmphdr); + ip_build_xmit(icmp_socket->sk, icmp_glue_bits, &icmp_param, icmp_param.data_len+sizeof(struct icmphdr), &ipc, rt, MSG_DONTWAIT); @@ -688,28 +527,35 @@ * Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, and ICMP_QUENCH. */ -static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb, int len) +static void icmp_unreach(struct sk_buff *skb) { struct iphdr *iph; - int hash; + struct icmphdr *icmph; + int hash, protocol; struct inet_protocol *ipprot; - unsigned char *dp; struct sock *raw_sk; - + u32 info = 0; + /* * Incomplete header ? * Only checks for the IP header, there should be an * additional check for longer headers in upper levels. */ - if(len<sizeof(struct iphdr)) { + if (!pskb_may_pull(skb, sizeof(struct iphdr))) { ICMP_INC_STATS_BH(IcmpInErrors); return; } - - iph = (struct iphdr *) (icmph + 1); - dp = (unsigned char*)iph; - + + icmph = skb->h.icmph; + iph = (struct iphdr *) skb->data; + + if (iph->ihl<5) { + /* Mangled header, drop. */ + ICMP_INC_STATS_BH(IcmpInErrors); + return; + } + if(icmph->type==ICMP_DEST_UNREACH) { switch(icmph->code & 15) { case ICMP_NET_UNREACH: @@ -726,11 +572,9 @@ printk(KERN_INFO "ICMP: %u.%u.%u.%u: fragmentation needed and DF set.\n", NIPQUAD(iph->daddr)); } else { - unsigned short new_mtu; - new_mtu = ip_rt_frag_needed(iph, ntohs(icmph->un.frag.mtu)); - if (!new_mtu) - return; - icmph->un.frag.mtu = htons(new_mtu); + info = ip_rt_frag_needed(iph, ntohs(icmph->un.frag.mtu)); + if (!info) + goto out; } break; case ICMP_SR_FAILED: @@ -740,10 +584,12 @@ default: break; } - if (icmph->code>NR_ICMP_UNREACH) - return; + if (icmph->code>NR_ICMP_UNREACH) + goto out; + } else if (icmph->type == ICMP_PARAMETERPROB) { + info = ntohl(icmph->un.gateway)>>24; } - + /* * Throw it at our lower layers * @@ -751,7 +597,7 @@ * RFC 1122: 3.2.2.1 MUST pass ICMP unreach messages to the transport layer. * RFC 1122: 3.2.2.2 MUST pass ICMP time expired messages to transport layer. */ - + /* * Check the other end isnt violating RFC 1122. Some routers send * bogus responses to broadcast frames. If you see this message @@ -767,23 +613,33 @@ if (net_ratelimit()) printk(KERN_WARNING "%u.%u.%u.%u sent an invalid ICMP error to a broadcast.\n", NIPQUAD(skb->nh.iph->saddr)); - return; + goto out; } } + /* Checkin full IP header plus 8 bytes of protocol to + * avoid additional coding at protocol handlers. + */ + if (!pskb_may_pull(skb, iph->ihl*4+8)) + goto out; + + iph = (struct iphdr *) skb->data; + protocol = iph->protocol; + /* * Deliver ICMP message to raw sockets. Pretty useless feature? */ /* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */ - hash = iph->protocol & (MAX_INET_PROTOS - 1); + hash = protocol & (MAX_INET_PROTOS - 1); read_lock(&raw_v4_lock); if ((raw_sk = raw_v4_htable[hash]) != NULL) { - while ((raw_sk = __raw_v4_lookup(raw_sk, iph->protocol, iph->saddr, + while ((raw_sk = __raw_v4_lookup(raw_sk, protocol, iph->saddr, iph->daddr, skb->dev->ifindex)) != NULL) { - raw_err(raw_sk, skb); + raw_err(raw_sk, skb, info); raw_sk = raw_sk->next; + iph = (struct iphdr *)skb->data; } } read_unlock(&raw_v4_lock); @@ -807,11 +663,12 @@ /* RFC1122: OK. Passes appropriate ICMP errors to the */ /* appropriate protocol layer (MUST), as per 3.2.2. */ - if (iph->protocol == ipprot->protocol && ipprot->err_handler) - ipprot->err_handler(skb, dp, len); + if (protocol == ipprot->protocol && ipprot->err_handler) + ipprot->err_handler(skb, info); ipprot = nextip; } +out:; } @@ -819,24 +676,26 @@ * Handle ICMP_REDIRECT. */ -static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, int len) +static void icmp_redirect(struct sk_buff *skb) { struct iphdr *iph; unsigned long ip; - if (len < sizeof(struct iphdr)) { + if (skb->len < sizeof(struct iphdr)) { ICMP_INC_STATS_BH(IcmpInErrors); return; } - + /* * Get the copied header of the packet that caused the redirect */ - - iph = (struct iphdr *) (icmph + 1); + if (!pskb_may_pull(skb, sizeof(struct iphdr))) + return; + + iph = (struct iphdr *) skb->data; ip = iph->daddr; - switch(icmph->code & 7) { + switch(skb->h.icmph->code & 7) { case ICMP_REDIR_NET: case ICMP_REDIR_NETTOS: /* @@ -846,7 +705,7 @@ case ICMP_REDIR_HOST: case ICMP_REDIR_HOSTTOS: - ip_rt_redirect(skb->nh.iph->saddr, ip, icmph->un.gateway, iph->saddr, iph->tos, skb->dev); + ip_rt_redirect(skb->nh.iph->saddr, ip, skb->h.icmph->un.gateway, iph->saddr, iph->tos, skb->dev); break; default: break; @@ -862,15 +721,17 @@ * See also WRT handling of options once they are done and working. */ -static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, int len) +static void icmp_echo(struct sk_buff *skb) { if (!sysctl_icmp_echo_ignore_all) { struct icmp_bxm icmp_param; - icmp_param.icmph=*icmph; - icmp_param.icmph.type=ICMP_ECHOREPLY; - icmp_param.data_ptr=(icmph+1); - icmp_param.data_len=len; + icmp_param.data.icmph=*skb->h.icmph; + icmp_param.data.icmph.type=ICMP_ECHOREPLY; + icmp_param.skb=skb; + icmp_param.offset=0; + icmp_param.data_len=skb->len; + icmp_param.head_len=sizeof(struct icmphdr); icmp_reply(&icmp_param, skb); } } @@ -883,34 +744,35 @@ * MUST be updated at least at 15Hz. */ -static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, int len) +static void icmp_timestamp(struct sk_buff *skb) { struct timeval tv; - __u32 times[3]; /* So the new timestamp works on ALPHA's.. */ struct icmp_bxm icmp_param; /* * Too short. */ - if(len<12) { + if(skb->len<4) { ICMP_INC_STATS_BH(IcmpInErrors); return; } - + /* * Fill in the current time as ms since midnight UT: */ - do_gettimeofday(&tv); - times[1] = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000); - times[2] = times[1]; - memcpy((void *)×[0], icmph+1, 4); /* Incoming stamp */ - icmp_param.icmph=*icmph; - icmp_param.icmph.type=ICMP_TIMESTAMPREPLY; - icmp_param.icmph.code=0; - icmp_param.data_ptr=× - icmp_param.data_len=12; + icmp_param.data.times[1] = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000); + icmp_param.data.times[2] = icmp_param.data.times[1]; + if (skb_copy_bits(skb, 0, &icmp_param.data.times[0], 4)) + BUG(); + icmp_param.data.icmph=*skb->h.icmph; + icmp_param.data.icmph.type=ICMP_TIMESTAMPREPLY; + icmp_param.data.icmph.code=0; + icmp_param.skb=skb; + icmp_param.offset=0; + icmp_param.data_len=0; + icmp_param.head_len=sizeof(struct icmphdr)+12; icmp_reply(&icmp_param, skb); } @@ -948,7 +810,7 @@ * anyway... */ -static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, int len) +static void icmp_address(struct sk_buff *skb) { #if 0 if (net_ratelimit()) @@ -961,7 +823,7 @@ * loudly if an inconsistency is found. */ -static void icmp_address_reply(struct icmphdr *icmph, struct sk_buff *skb, int len) +static void icmp_address_reply(struct sk_buff *skb) { struct rtable *rt = (struct rtable*)skb->dst; struct net_device *dev = skb->dev; @@ -969,7 +831,7 @@ struct in_ifaddr *ifa; u32 mask; - if (len < 4 || !(rt->rt_flags&RTCF_DIRECTSRC)) + if (skb->len < 4 || !(rt->rt_flags&RTCF_DIRECTSRC)) return; in_dev = in_dev_get(dev); @@ -979,8 +841,8 @@ if (in_dev->ifa_list && IN_DEV_LOG_MARTIANS(in_dev) && IN_DEV_FORWARD(in_dev)) { - - mask = *(u32*)&icmph[1]; + if (skb_copy_bits(skb, 0, &mask, 4)) + BUG(); for (ifa=in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { if (mask == ifa->ifa_mask && inet_ifa_match(rt->rt_src, ifa)) break; @@ -994,7 +856,7 @@ in_dev_put(in_dev); } -static void icmp_discard(struct icmphdr *icmph, struct sk_buff *skb, int len) +static void icmp_discard(struct sk_buff *skb) { } @@ -1002,23 +864,36 @@ * Deal with incoming ICMP packets. */ -int icmp_rcv(struct sk_buff *skb, unsigned short len) +int icmp_rcv(struct sk_buff *skb) { struct icmphdr *icmph = skb->h.icmph; struct rtable *rt = (struct rtable*)skb->dst; ICMP_INC_STATS_BH(IcmpInMsgs); + switch (skb->ip_summed) { + case CHECKSUM_HW: + if ((u16)csum_fold(skb->csum) == 0) + break; + NETDEBUG(printk(KERN_DEBUG "icmp v4 hw csum failure\n")); + case CHECKSUM_NONE: + if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))) + goto error; + default:; + } + + if (!pskb_pull(skb, sizeof(struct icmphdr))) + goto error; + /* * 18 is the highest 'known' ICMP type. Anything else is a mystery * * RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently discarded. */ - if(len < sizeof(struct icmphdr) || - ip_compute_csum((unsigned char *) icmph, len) || - icmph->type > NR_ICMP_TYPES) + if (icmph->type > NR_ICMP_TYPES) goto error; - + + /* * Parse the ICMP message */ @@ -1042,9 +917,8 @@ } } - len -= sizeof(struct icmphdr); icmp_pointers[icmph->type].input[smp_processor_id()*2*sizeof(struct icmp_mib)/sizeof(unsigned long)]++; - (icmp_pointers[icmph->type].handler)(icmph, skb, len); + (icmp_pointers[icmph->type].handler)(skb); drop: kfree_skb(skb); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/igmp.c linux.ac/net/ipv4/igmp.c --- linux.vanilla/net/ipv4/igmp.c Tue Jan 9 18:54:57 2001 +++ linux.ac/net/ipv4/igmp.c Sat Apr 14 01:49:52 2001 @@ -8,7 +8,7 @@ * the older version didn't come out right using gcc 2.5.8, the newer one * seems to fall out with gcc 2.6.2. * - * Version: $Id: igmp.c,v 1.41 2000/08/31 23:39:12 davem Exp $ + * Version: $Id: igmp.c,v 1.45 2001/02/23 06:32:11 davem Exp $ * * Authors: * Alan Cox <Alan.Cox@linux.org> @@ -235,7 +235,7 @@ iph->saddr = rt->rt_src; iph->protocol = IPPROTO_IGMP; iph->tot_len = htons(IGMP_SIZE); - ip_select_ident(iph, &rt->u.dst); + ip_select_ident(iph, &rt->u.dst, NULL); ((u8*)&iph[1])[0] = IPOPT_RA; ((u8*)&iph[1])[1] = 4; ((u8*)&iph[1])[2] = 0; @@ -341,23 +341,32 @@ read_unlock(&in_dev->lock); } -int igmp_rcv(struct sk_buff *skb, unsigned short len) +int igmp_rcv(struct sk_buff *skb) { /* This basically follows the spec line by line -- see RFC1112 */ struct igmphdr *ih = skb->h.igmph; struct in_device *in_dev = in_dev_get(skb->dev); + int len = skb->len; if (in_dev==NULL) { kfree_skb(skb); return 0; } + if (skb_is_nonlinear(skb)) { + if (skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + return -ENOMEM; + } + ih = skb->h.igmph; + } + if (len < sizeof(struct igmphdr) || ip_compute_csum((void *)ih, len)) { in_dev_put(in_dev); kfree_skb(skb); return 0; } - + switch (ih->type) { case IGMP_HOST_MEMBERSHIP_QUERY: igmp_heard_query(in_dev, ih->code, ih->group); @@ -372,7 +381,7 @@ case IGMP_PIM: #ifdef CONFIG_IP_PIMSM_V1 in_dev_put(in_dev); - return pim_rcv_v1(skb, len); + return pim_rcv_v1(skb); #endif case IGMP_DVMRP: case IGMP_TRACE: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/ip_forward.c linux.ac/net/ipv4/ip_forward.c --- linux.vanilla/net/ipv4/ip_forward.c Fri Oct 27 19:03:14 2000 +++ linux.ac/net/ipv4/ip_forward.c Sat Apr 14 01:49:52 2001 @@ -5,7 +5,7 @@ * * The IP forwarding functionality. * - * Version: $Id: ip_forward.c,v 1.47 2000/10/24 22:54:26 davem Exp $ + * Version: $Id: ip_forward.c,v 1.48 2000/12/13 18:31:48 davem Exp $ * * Authors: see ip.c * @@ -83,6 +83,8 @@ if (skb->pkt_type != PACKET_HOST) goto drop; + + skb->ip_summed = CHECKSUM_NONE; /* * According to the RFC, we must first decrease the TTL field. If @@ -116,10 +118,9 @@ ip_rt_send_redirect(skb); /* We are about to mangle packet. Copy it! */ - if ((skb = skb_cow(skb, dev2->hard_header_len)) == NULL) - return NET_RX_DROP; + if (skb_cow(skb, dev2->hard_header_len)) + goto drop; iph = skb->nh.iph; - opt = &(IPCB(skb)->opt); /* Decrease ttl after skb cow done */ ip_decrease_ttl(iph); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/ip_fragment.c linux.ac/net/ipv4/ip_fragment.c --- linux.vanilla/net/ipv4/ip_fragment.c Tue Apr 3 17:32:30 2001 +++ linux.ac/net/ipv4/ip_fragment.c Sat Apr 14 01:49:52 2001 @@ -5,7 +5,7 @@ * * The IP fragmentation functionality. * - * Version: $Id: ip_fragment.c,v 1.53 2000/12/08 17:15:53 davem Exp $ + * Version: $Id: ip_fragment.c,v 1.57 2001/03/07 22:00:57 davem Exp $ * * Authors: Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG> * Alan Cox <Alan.Cox@linux.org> @@ -83,7 +83,8 @@ atomic_t refcnt; struct timer_list timer; /* when will this queue expire? */ struct ipq **pprev; - int iif; /* Device index - for icmp replies */ + int iif; + struct timeval stamp; }; /* Hash table. */ @@ -255,7 +256,6 @@ if ((qp->last_in&FIRST_IN) && qp->fragments != NULL) { struct sk_buff *head = qp->fragments; - /* Send an ICMP "Fragment Reassembly Timeout" message. */ if ((head->dev = dev_get_by_index(qp->iif)) != NULL) { icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); @@ -370,7 +370,6 @@ /* Add new segment to existing queue. */ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb) { - struct iphdr *iph = skb->nh.iph; struct sk_buff *prev, *next; int flags, offset; int ihl, end; @@ -378,14 +377,14 @@ if (qp->last_in & COMPLETE) goto err; - offset = ntohs(iph->frag_off); + offset = ntohs(skb->nh.iph->frag_off); flags = offset & ~IP_OFFSET; offset &= IP_OFFSET; offset <<= 3; /* offset is in 8-byte chunks */ - ihl = iph->ihl * 4; + ihl = skb->nh.iph->ihl * 4; /* Determine the position of this fragment. */ - end = offset + (ntohs(iph->tot_len) - ihl); + end = offset + skb->len - ihl; /* Is this the final fragment? */ if ((flags & IP_MF) == 0) { @@ -413,9 +412,10 @@ if (end == offset) goto err; - /* Point into the IP datagram 'data' part. */ - skb_pull(skb, (skb->nh.raw+ihl) - skb->data); - skb_trim(skb, end - offset); + if (pskb_pull(skb, ihl) == NULL) + goto err; + if (pskb_trim(skb, end-offset)) + goto err; /* Find out which fragments are in front and at the back of us * in the chain of fragments so far. We must know where to put @@ -439,7 +439,8 @@ offset += i; if (end <= offset) goto err; - skb_pull(skb, i); + if (!pskb_pull(skb, i)) + goto err; if (skb->ip_summed != CHECKSUM_UNNECESSARY) skb->ip_summed = CHECKSUM_NONE; } @@ -452,8 +453,9 @@ /* Eat head of the next overlapped fragment * and leave the loop. The next ones cannot overlap. */ + if (!pskb_pull(next, i)) + goto err; FRAG_CB(next)->offset += i; - skb_pull(next, i); qp->meat -= i; if (next->ip_summed != CHECKSUM_UNNECESSARY) next->ip_summed = CHECKSUM_NONE; @@ -485,9 +487,10 @@ else qp->fragments = skb; - if (skb->dev) - qp->iif = skb->dev->ifindex; + if (skb->dev) + qp->iif = skb->dev->ifindex; skb->dev = NULL; + qp->stamp = skb->stamp; qp->meat += skb->len; atomic_add(skb->truesize, &ip_frag_mem); if (offset == 0) @@ -500,15 +503,10 @@ } -/* Build a new IP datagram from all its fragments. - * - * FIXME: We copy here because we lack an effective way of handling lists - * of bits on input. Until the new skb data handling is in I'm not going - * to touch this with a bargepole. - */ +/* Build a new IP datagram from all its fragments. */ + static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev) { - struct sk_buff *skb; struct iphdr *iph; struct sk_buff *fp, *head = qp->fragments; int len; @@ -526,61 +524,58 @@ if(len > 65535) goto out_oversize; - skb = dev_alloc_skb(len); - if (!skb) + /* Head of list must not be cloned. */ + if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC)) goto out_nomem; - /* Fill in the basic details. */ - skb->mac.raw = skb->data; - skb->nh.raw = skb->data; - FRAG_CB(skb)->h = FRAG_CB(head)->h; - skb->ip_summed = head->ip_summed; - skb->csum = 0; - - /* Copy the original IP headers into the new buffer. */ - memcpy(skb_put(skb, ihlen), head->nh.iph, ihlen); - - /* Copy the data portions of all fragments into the new buffer. */ - for (fp=head; fp; fp = fp->next) { - memcpy(skb_put(skb, fp->len), fp->data, fp->len); - - if (skb->ip_summed != fp->ip_summed) - skb->ip_summed = CHECKSUM_NONE; - else if (skb->ip_summed == CHECKSUM_HW) - skb->csum = csum_add(skb->csum, fp->csum); - } - - skb->dst = dst_clone(head->dst); - skb->pkt_type = head->pkt_type; - skb->protocol = head->protocol; - skb->dev = dev; - - /* - * Clearly bogus, because security markings of the individual - * fragments should have been checked for consistency before - * gluing, and intermediate coalescing of fragments may have - * taken place in ip_defrag() before ip_glue() ever got called. - * If we're not going to do the consistency checking, we might - * as well take the value associated with the first fragment. - * --rct - */ - skb->security = head->security; - -#ifdef CONFIG_NETFILTER - /* Connection association is same as fragment (if any). */ - skb->nfct = head->nfct; - nf_conntrack_get(skb->nfct); -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = head->nf_debug; -#endif -#endif + /* If the first fragment is fragmented itself, we split + * it to two chunks: the first with data and paged part + * and the second, holding only fragments. */ + if (skb_shinfo(head)->frag_list) { + struct sk_buff *clone; + int i, plen = 0; + + if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL) + goto out_nomem; + clone->next = head->next; + head->next = clone; + skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list; + skb_shinfo(head)->frag_list = NULL; + for (i=0; i<skb_shinfo(head)->nr_frags; i++) + plen += skb_shinfo(head)->frags[i].size; + clone->len = clone->data_len = head->data_len - plen; + head->data_len -= clone->len; + head->len -= clone->len; + clone->csum = 0; + clone->ip_summed = head->ip_summed; + atomic_add(clone->truesize, &ip_frag_mem); + } - /* Done with all fragments. Fixup the new IP header. */ - iph = skb->nh.iph; + skb_shinfo(head)->frag_list = head->next; + skb_push(head, head->data - head->nh.raw); + atomic_sub(head->truesize, &ip_frag_mem); + + for (fp=head->next; fp; fp = fp->next) { + head->data_len += fp->len; + head->len += fp->len; + if (head->ip_summed != fp->ip_summed) + head->ip_summed = CHECKSUM_NONE; + else if (head->ip_summed == CHECKSUM_HW) + head->csum = csum_add(head->csum, fp->csum); + head->truesize += fp->truesize; + atomic_sub(fp->truesize, &ip_frag_mem); + } + + head->next = NULL; + head->dev = dev; + head->stamp = qp->stamp; + + iph = head->nh.iph; iph->frag_off = 0; iph->tot_len = htons(len); IP_INC_STATS_BH(IpReasmOKs); - return skb; + qp->fragments = NULL; + return head; out_nomem: NETDEBUG(printk(KERN_ERR diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/ip_gre.c linux.ac/net/ipv4/ip_gre.c --- linux.vanilla/net/ipv4/ip_gre.c Wed Nov 29 05:53:45 2000 +++ linux.ac/net/ipv4/ip_gre.c Sat Apr 14 01:49:52 2001 @@ -313,7 +313,7 @@ } -void ipgre_err(struct sk_buff *skb, unsigned char *dp, int len) +void ipgre_err(struct sk_buff *skb, u32 info) { #ifndef I_WISH_WORLD_WERE_PERFECT @@ -330,8 +330,8 @@ by themself??? */ - struct iphdr *iph = (struct iphdr*)dp; - u16 *p = (u16*)(dp+(iph->ihl<<2)); + struct iphdr *iph = (struct iphdr*)skb->data; + u16 *p = (u16*)(skb->data+(iph->ihl<<2)); int grehlen = (iph->ihl<<2) + 4; int type = skb->h.icmph->type; int code = skb->h.icmph->code; @@ -350,7 +350,7 @@ } /* If only 8 bytes returned, keyed message will be dropped here */ - if (len < grehlen) + if (skb_headlen(skb) < grehlen) return; switch (type) { @@ -559,17 +559,24 @@ #endif } -int ipgre_rcv(struct sk_buff *skb, unsigned short len) +int ipgre_rcv(struct sk_buff *skb) { - struct iphdr *iph = skb->nh.iph; - u8 *h = skb->h.raw; - u16 flags = *(u16*)h; + struct iphdr *iph; + u8 *h; + u16 flags; u16 csum = 0; u32 key = 0; u32 seqno = 0; struct ip_tunnel *tunnel; int offset = 4; + if (!pskb_may_pull(skb, 16)) + goto drop_nolock; + + iph = skb->nh.iph; + h = skb->data; + flags = *(u16*)h; + if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) { /* - Version must be 0. - We do not support routing headers. @@ -578,7 +585,16 @@ goto drop_nolock; if (flags&GRE_CSUM) { - csum = ip_compute_csum(h, len); + if (skb->ip_summed == CHECKSUM_HW) { + csum = (u16)csum_fold(skb->csum); + if (csum) + skb->ip_summed = CHECKSUM_NONE; + } + if (skb->ip_summed == CHECKSUM_NONE) { + skb->csum = skb_checksum(skb, 0, skb->len, 0); + skb->ip_summed = CHECKSUM_HW; + csum = (u16)csum_fold(skb->csum); + } offset += 4; } if (flags&GRE_KEY) { @@ -594,9 +610,11 @@ read_lock(&ipgre_lock); if ((tunnel = ipgre_tunnel_lookup(iph->saddr, iph->daddr, key)) != NULL) { skb->mac.raw = skb->nh.raw; - skb->nh.raw = skb_pull(skb, h + offset - skb->data); + skb->nh.raw = __pskb_pull(skb, offset); memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); - skb->ip_summed = 0; + if (skb->ip_summed == CHECKSUM_HW) + skb->csum = csum_sub(skb->csum, + csum_partial(skb->mac.raw, skb->nh.raw-skb->mac.raw, 0)); skb->protocol = *(u16*)(h + 2); skb->pkt_type = PACKET_HOST; #ifdef CONFIG_NET_IPGRE_BROADCAST @@ -1263,14 +1281,7 @@ printk(KERN_INFO "GRE over IPv4 tunneling driver\n"); ipgre_fb_tunnel_dev.priv = (void*)&ipgre_fb_tunnel; -#ifdef MODULE register_netdev(&ipgre_fb_tunnel_dev); -#else - rtnl_lock(); - register_netdevice(&ipgre_fb_tunnel_dev); - rtnl_unlock(); -#endif - inet_add_protocol(&ipgre_protocol); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/ip_input.c linux.ac/net/ipv4/ip_input.c --- linux.vanilla/net/ipv4/ip_input.c Mon Dec 11 20:37:04 2000 +++ linux.ac/net/ipv4/ip_input.c Sat Apr 14 01:49:53 2001 @@ -5,7 +5,7 @@ * * The Internet Protocol (IP) module. * - * Version: $Id: ip_input.c,v 1.51 2000/12/08 17:15:53 davem Exp $ + * Version: $Id: ip_input.c,v 1.53 2000/12/18 19:01:50 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -207,8 +207,7 @@ skb2 = skb_clone(skb, GFP_ATOMIC); if(skb2 != NULL) { ret = 1; - ipprot->handler(skb2, - ntohs(iph->tot_len) - (iph->ihl * 4)); + ipprot->handler(skb2); } } ipprot = (struct inet_protocol *) ipprot->next; @@ -219,18 +218,31 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb) { - struct iphdr *iph = skb->nh.iph; + int ihl = skb->nh.iph->ihl*4; #ifdef CONFIG_NETFILTER_DEBUG nf_debug_ip_local_deliver(skb); #endif /*CONFIG_NETFILTER_DEBUG*/ + /* Pull out additionl 8 bytes to save some space in protocols. */ + if (!pskb_may_pull(skb, ihl+8)) + goto out; + __skb_pull(skb, ihl); + +#ifdef CONFIG_NETFILTER + /* Free reference early: we don't need it any more, and it may + hold ip_conntrack module loaded indefinitely. */ + nf_conntrack_put(skb->nfct); + skb->nfct = NULL; +#endif /*CONFIG_NETFILTER*/ + /* Point into the IP datagram, just past the header. */ - skb->h.raw = skb->nh.raw + iph->ihl*4; + skb->h.raw = skb->data; { /* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */ - int hash = iph->protocol & (MAX_INET_PROTOS - 1); + int protocol = skb->nh.iph->protocol; + int hash = protocol & (MAX_INET_PROTOS - 1); struct sock *raw_sk = raw_v4_htable[hash]; struct inet_protocol *ipprot; int flag; @@ -239,23 +251,22 @@ * don't care less */ if(raw_sk != NULL) - raw_sk = raw_v4_input(skb, iph, hash); + raw_sk = raw_v4_input(skb, skb->nh.iph, hash); ipprot = (struct inet_protocol *) inet_protos[hash]; flag = 0; if(ipprot != NULL) { if(raw_sk == NULL && ipprot->next == NULL && - ipprot->protocol == iph->protocol) { + ipprot->protocol == protocol) { int ret; - + /* Fast path... */ - ret = ipprot->handler(skb, (ntohs(iph->tot_len) - - (iph->ihl * 4))); + ret = ipprot->handler(skb); return ret; } else { - flag = ip_run_ipprot(skb, iph, ipprot, (raw_sk != NULL)); + flag = ip_run_ipprot(skb, skb->nh.iph, ipprot, (raw_sk != NULL)); } } @@ -269,6 +280,7 @@ sock_put(raw_sk); } else if (!flag) { /* Free and report errors */ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0); +out: kfree_skb(skb); } } @@ -281,13 +293,11 @@ */ int ip_local_deliver(struct sk_buff *skb) { - struct iphdr *iph = skb->nh.iph; - /* * Reassemble IP fragments. */ - if (iph->frag_off & htons(IP_MF|IP_OFFSET)) { + if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) { skb = ip_defrag(skb); if (!skb) return 0; @@ -333,9 +343,8 @@ --ANK (980813) */ - skb = skb_cow(skb, skb_headroom(skb)); - if (skb == NULL) - return NET_RX_DROP; + if (skb_cow(skb, skb_headroom(skb))) + goto drop; iph = skb->nh.iph; skb->ip_summed = 0; @@ -387,6 +396,11 @@ if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) goto out; + if (!pskb_may_pull(skb, sizeof(struct iphdr))) + goto inhdr_error; + + iph = skb->nh.iph; + /* * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum. * @@ -398,9 +412,13 @@ * 4. Doesn't have a bogus length */ - if (skb->len < sizeof(struct iphdr) || skb->len < (iph->ihl<<2)) + if (iph->ihl < 5 || iph->version != 4) goto inhdr_error; - if (iph->ihl < 5 || iph->version != 4 || ip_fast_csum((u8 *)iph, iph->ihl) != 0) + + if (!pskb_may_pull(skb, iph->ihl*4)) + goto inhdr_error; + + if (ip_fast_csum((u8 *)iph, iph->ihl) != 0) goto inhdr_error; { @@ -412,7 +430,11 @@ * is IP we can trim to the true length of the frame. * Note this now means skb->len holds ntohs(iph->tot_len). */ - __skb_trim(skb, len); + if (skb->len > len) { + __pskb_trim(skb, len); + if (skb->ip_summed == CHECKSUM_HW) + skb->ip_summed = CHECKSUM_NONE; + } } return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/ip_nat_dumb.c linux.ac/net/ipv4/ip_nat_dumb.c --- linux.vanilla/net/ipv4/ip_nat_dumb.c Fri Oct 27 19:03:14 2000 +++ linux.ac/net/ipv4/ip_nat_dumb.c Sat Apr 14 01:49:53 2001 @@ -5,7 +5,7 @@ * * Dumb Network Address Translation. * - * Version: $Id: ip_nat_dumb.c,v 1.10 2000/10/24 22:54:26 davem Exp $ + * Version: $Id: ip_nat_dumb.c,v 1.11 2000/12/13 18:31:48 davem Exp $ * * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * @@ -70,8 +70,14 @@ cksum = (u16*)&((struct tcphdr*)(((char*)iph) + (iph->ihl<<2)))->check; if ((u8*)(cksum+1) > skb->tail) goto truncated; - check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, ~(*cksum)); - *cksum = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check); + check = *cksum; + if (skb->ip_summed != CHECKSUM_HW) + check = ~check; + check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, check); + check = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check); + if (skb->ip_summed == CHECKSUM_HW) + check = ~check; + *cksum = check; break; case IPPROTO_UDP: cksum = (u16*)&((struct udphdr*)(((char*)iph) + (iph->ihl<<2)))->check; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/ip_output.c linux.ac/net/ipv4/ip_output.c --- linux.vanilla/net/ipv4/ip_output.c Fri Oct 27 19:03:14 2000 +++ linux.ac/net/ipv4/ip_output.c Sat Apr 14 01:49:53 2001 @@ -5,7 +5,7 @@ * * The Internet Protocol (IP) output module. * - * Version: $Id: ip_output.c,v 1.87 2000/10/25 20:07:22 davem Exp $ + * Version: $Id: ip_output.c,v 1.91 2001/03/29 06:25:55 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -95,7 +95,7 @@ static int ip_dev_loopback_xmit(struct sk_buff *newskb) { newskb->mac.raw = newskb->data; - skb_pull(newskb, newskb->nh.raw - newskb->data); + __skb_pull(newskb, newskb->nh.raw - newskb->data); newskb->pkt_type = PACKET_LOOPBACK; newskb->ip_summed = CHECKSUM_UNNECESSARY; BUG_TRAP(newskb->dst); @@ -141,7 +141,7 @@ iph->saddr = rt->rt_src; iph->protocol = sk->protocol; iph->tot_len = htons(skb->len); - ip_select_ident(iph, &rt->u.dst); + ip_select_ident(iph, &rt->u.dst, sk); skb->nh.iph = iph; if (opt && opt->optlen) { @@ -307,7 +307,7 @@ if (ip_dont_fragment(sk, &rt->u.dst)) iph->frag_off |= __constant_htons(IP_DF); - ip_select_ident(iph, &rt->u.dst); + ip_select_ident(iph, &rt->u.dst, sk); /* Add an IP checksum. */ ip_send_check(iph); @@ -328,7 +328,10 @@ kfree_skb(skb); return -EMSGSIZE; } - ip_select_ident(iph, &rt->u.dst); + ip_select_ident(iph, &rt->u.dst, sk); + if (skb->ip_summed == CHECKSUM_HW && + (skb = skb_checksum_help(skb)) == NULL) + return -ENOMEM; return ip_fragment(skb, skb->dst->output); } @@ -358,6 +361,7 @@ sk->bound_dev_if)) goto no_route; __sk_dst_set(sk, &rt->u.dst); + sk->route_caps = rt->u.dst.dev->features; } skb->dst = dst_clone(&rt->u.dst); @@ -425,7 +429,7 @@ int err; int offset, mf; int mtu; - u16 id = 0; + u16 id; int hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15; int nfrags=0; @@ -495,6 +499,8 @@ * Begin outputting the bytes. */ + id = (sk ? sk->protinfo.af_inet.id++ : 0); + do { char *data; struct sk_buff * skb; @@ -503,7 +509,7 @@ * Get the memory we require with some space left for alignment. */ - skb = sock_alloc_send_skb(sk, fraglen+hh_len+15, 0, flags&MSG_DONTWAIT, &err); + skb = sock_alloc_send_skb(sk, fraglen+hh_len+15, flags&MSG_DONTWAIT, &err); if (skb == NULL) goto error; @@ -659,7 +665,7 @@ int hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15; skb = sock_alloc_send_skb(sk, length+hh_len+15, - 0, flags&MSG_DONTWAIT, &err); + flags&MSG_DONTWAIT, &err); if(skb==NULL) goto error; skb_reserve(skb, hh_len); @@ -677,7 +683,7 @@ iph->tot_len = htons(length); iph->frag_off = df; iph->ttl=sk->protinfo.af_inet.mc_ttl; - ip_select_ident(iph, &rt->u.dst); + ip_select_ident(iph, &rt->u.dst, sk); if (rt->rt_type != RTN_MULTICAST) iph->ttl=sk->protinfo.af_inet.ttl; iph->protocol=sk->protocol; @@ -722,8 +728,8 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) { struct iphdr *iph; - unsigned char *raw; - unsigned char *ptr; + int raw = 0; + int ptr; struct net_device *dev; struct sk_buff *skb2; unsigned int mtu, hlen, left, len; @@ -738,17 +744,16 @@ * Point into the IP datagram header. */ - raw = skb->nh.raw; - iph = (struct iphdr*)raw; + iph = skb->nh.iph; /* * Setup starting values. */ hlen = iph->ihl * 4; - left = ntohs(iph->tot_len) - hlen; /* Space per frame */ + left = skb->len - hlen; /* Space per frame */ mtu = rt->u.dst.pmtu - hlen; /* Size of data space */ - ptr = raw + hlen; /* Where to start from */ + ptr = raw + hlen; /* Where to start from */ /* * Fragment the datagram. @@ -806,12 +811,13 @@ * Copy the packet header into the new buffer. */ - memcpy(skb2->nh.raw, raw, hlen); + memcpy(skb2->nh.raw, skb->data, hlen); /* * Copy a block of the IP datagram. */ - memcpy(skb2->h.raw, ptr, len); + if (skb_copy_bits(skb, ptr, skb2->h.raw, len)) + BUG(); left -= len; /* @@ -828,6 +834,9 @@ */ if (offset == 0) ip_options_fragment(skb); + + /* Copy the flags to each fragment. */ + IPCB(skb2)->flags = IPCB(skb)->flags; /* * Added AC : If we are fragmenting a fragment that's not the diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/ip_sockglue.c linux.ac/net/ipv4/ip_sockglue.c --- linux.vanilla/net/ipv4/ip_sockglue.c Wed Nov 29 05:53:45 2000 +++ linux.ac/net/ipv4/ip_sockglue.c Sat Apr 14 01:49:53 2001 @@ -5,7 +5,7 @@ * * The IP to API glue. * - * Version: $Id: ip_sockglue.c,v 1.54 2000/11/28 13:34:56 davem Exp $ + * Version: $Id: ip_sockglue.c,v 1.56 2001/02/18 09:07:58 davem Exp $ * * Authors: see ip.c * @@ -257,9 +257,8 @@ serr->port = port; skb->h.raw = payload; - skb_pull(skb, payload - skb->data); - - if (sock_queue_err_skb(sk, skb)) + if (!skb_pull(skb, payload - skb->data) || + sock_queue_err_skb(sk, skb)) kfree_skb(skb); } @@ -292,7 +291,7 @@ serr->port = port; skb->h.raw = skb->tail; - skb_pull(skb, skb->tail - skb->data); + __skb_pull(skb, skb->tail - skb->data); if (sock_queue_err_skb(sk, skb)) kfree_skb(skb); @@ -323,7 +322,7 @@ msg->msg_flags |= MSG_TRUNC; copied = len; } - err = memcpy_toiovec(msg->msg_iov, skb->data, copied); + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (err) goto out_free_skb; @@ -333,9 +332,10 @@ sin = (struct sockaddr_in *)msg->msg_name; if (sin) { - sin->sin_family = AF_INET; + sin->sin_family = AF_INET; sin->sin_addr.s_addr = *(u32*)(skb->nh.raw + serr->addr_offset); - sin->sin_port = serr->port; + sin->sin_port = serr->port; + memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); } memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); @@ -344,6 +344,8 @@ if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP) { sin->sin_family = AF_INET; sin->sin_addr.s_addr = skb->nh.iph->saddr; + sin->sin_port = 0; + memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); if (sk->protinfo.af_inet.cmsg_flags) ip_cmsg_recv(msg, skb); } @@ -661,7 +663,9 @@ if(get_user(len,optlen)) return -EFAULT; - + if(len < 0) + return -EINVAL; + lock_sock(sk); switch(optname) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/ipip.c linux.ac/net/ipv4/ipip.c --- linux.vanilla/net/ipv4/ipip.c Wed Nov 29 05:53:45 2000 +++ linux.ac/net/ipv4/ipip.c Sat Apr 14 01:49:54 2001 @@ -1,7 +1,7 @@ /* * Linux NET3: IP/IP protocol decoder. * - * Version: $Id: ipip.c,v 1.41 2000/11/28 13:13:27 davem Exp $ + * Version: $Id: ipip.c,v 1.44 2001/03/29 06:29:09 davem Exp $ * * Authors: * Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95 @@ -123,11 +123,13 @@ static int ipip_tunnel_init(struct net_device *dev); static struct net_device ipip_fb_tunnel_dev = { - "tunl0", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, ipip_fb_tunnel_init, + name: "tunl0", + init: ipip_fb_tunnel_init, }; static struct ip_tunnel ipip_fb_tunnel = { - NULL, &ipip_fb_tunnel_dev, {0, }, 0, 0, 0, 0, 0, 0, 0, {"tunl0", } + dev: &ipip_fb_tunnel_dev, + parms: { name: "tunl0", } }; static struct ip_tunnel *tunnels_r_l[HASH_SIZE]; @@ -281,14 +283,12 @@ write_lock_bh(&ipip_lock); tunnels_wc[0] = NULL; write_unlock_bh(&ipip_lock); - dev_put(dev); - } else { + } else ipip_tunnel_unlink((struct ip_tunnel*)dev->priv); - dev_put(dev); - } + dev_put(dev); } -void ipip_err(struct sk_buff *skb, unsigned char *dp, int len) +void ipip_err(struct sk_buff *skb, u32 info) { #ifndef I_WISH_WORLD_WERE_PERFECT @@ -296,14 +296,11 @@ 8 bytes of packet payload. It means, that precise relaying of ICMP in the real Internet is absolutely infeasible. */ - struct iphdr *iph = (struct iphdr*)dp; + struct iphdr *iph = (struct iphdr*)skb->data; int type = skb->h.icmph->type; int code = skb->h.icmph->code; struct ip_tunnel *t; - if (len < sizeof(struct iphdr)) - return; - switch (type) { default: case ICMP_PARAMETERPROB: @@ -473,17 +470,19 @@ IP_ECN_set_ce(iph); } -int ipip_rcv(struct sk_buff *skb, unsigned short len) +int ipip_rcv(struct sk_buff *skb) { struct iphdr *iph; struct ip_tunnel *tunnel; + if (!pskb_may_pull(skb, sizeof(struct iphdr))) + goto out; + iph = skb->nh.iph; skb->mac.raw = skb->nh.raw; - skb->nh.raw = skb_pull(skb, skb->h.raw - skb->data); + skb->nh.raw = skb->data; memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); skb->protocol = __constant_htons(ETH_P_IP); - skb->ip_summed = 0; skb->pkt_type = PACKET_HOST; read_lock(&ipip_lock); @@ -508,6 +507,7 @@ read_unlock(&ipip_lock); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0); +out: kfree_skb(skb); return 0; } @@ -873,44 +873,34 @@ } static struct inet_protocol ipip_protocol = { - ipip_rcv, /* IPIP handler */ - ipip_err, /* TUNNEL error control */ - 0, /* next */ - IPPROTO_IPIP, /* protocol ID */ - 0, /* copy */ - NULL, /* data */ - "IPIP" /* name */ + handler: ipip_rcv, + err_handler: ipip_err, + protocol: IPPROTO_IPIP, + name: "IPIP" }; -#ifdef MODULE -int init_module(void) -#else +static const char banner[] __initdata = + KERN_INFO "IPv4 over IPv4 tunneling driver\n"; + int __init ipip_init(void) -#endif { - printk(KERN_INFO "IPv4 over IPv4 tunneling driver\n"); + printk(banner); ipip_fb_tunnel_dev.priv = (void*)&ipip_fb_tunnel; -#ifdef MODULE register_netdev(&ipip_fb_tunnel_dev); -#else - rtnl_lock(); - register_netdevice(&ipip_fb_tunnel_dev); - rtnl_unlock(); -#endif - inet_add_protocol(&ipip_protocol); return 0; } -#ifdef MODULE - -void cleanup_module(void) +static void __exit ipip_fini(void) { if ( inet_del_protocol(&ipip_protocol) < 0 ) printk(KERN_INFO "ipip close: can't remove protocol\n"); - unregister_netdevice(&ipip_fb_tunnel_dev); + unregister_netdev(&ipip_fb_tunnel_dev); } +#ifdef MODULE +module_init(ipip_init); #endif +module_exit(ipip_fini); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/ipmr.c linux.ac/net/ipv4/ipmr.c --- linux.vanilla/net/ipv4/ipmr.c Wed Nov 29 05:53:45 2000 +++ linux.ac/net/ipv4/ipmr.c Sat Apr 14 01:49:54 2001 @@ -9,7 +9,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version: $Id: ipmr.c,v 1.55 2000/11/28 13:13:27 davem Exp $ + * Version: $Id: ipmr.c,v 1.59 2001/02/23 06:32:11 davem Exp $ * * Fixes: * Michael Chastain : Incorrect size of copying. @@ -980,6 +980,9 @@ return -EFAULT; olr=min(olr,sizeof(int)); + if(olr<0) + return -EINVAL; + if(put_user(olr,optlen)) return -EFAULT; if(optname==MRT_VERSION) @@ -1092,7 +1095,7 @@ iph->protocol = IPPROTO_IPIP; iph->ihl = 5; iph->tot_len = htons(skb->len); - ip_select_ident(iph, skb->dst); + ip_select_ident(iph, skb->dst, NULL); ip_send_check(iph); skb->h.ipiph = skb->nh.iph; @@ -1383,14 +1386,22 @@ * Handle IGMP messages of PIMv1 */ -int pim_rcv_v1(struct sk_buff * skb, unsigned short len) +int pim_rcv_v1(struct sk_buff * skb) { struct igmphdr *pim = (struct igmphdr*)skb->h.raw; struct iphdr *encap; struct net_device *reg_dev = NULL; + if (skb_is_nonlinear(skb)) { + if (skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + return -ENOMEM; + } + pim = (struct igmphdr*)skb->h.raw; + } + if (!mroute_do_pim || - len < sizeof(*pim) + sizeof(*encap) || + skb->len < sizeof(*pim) + sizeof(*encap) || pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER) { kfree_skb(skb); return -EINVAL; @@ -1405,7 +1416,7 @@ */ if (!MULTICAST(encap->daddr) || ntohs(encap->tot_len) == 0 || - ntohs(encap->tot_len) + sizeof(*pim) > len) { + ntohs(encap->tot_len) + sizeof(*pim) > skb->len) { kfree_skb(skb); return -EINVAL; } @@ -1445,17 +1456,25 @@ #endif #ifdef CONFIG_IP_PIMSM_V2 -int pim_rcv(struct sk_buff * skb, unsigned short len) +int pim_rcv(struct sk_buff * skb) { struct pimreghdr *pim = (struct pimreghdr*)skb->h.raw; struct iphdr *encap; struct net_device *reg_dev = NULL; - if (len < sizeof(*pim) + sizeof(*encap) || + if (skb_is_nonlinear(skb)) { + if (skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + return -ENOMEM; + } + pim = (struct pimreghdr*)skb->h.raw; + } + + if (skb->len < sizeof(*pim) + sizeof(*encap) || pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) || (pim->flags&PIM_NULL_REGISTER) || (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 && - ip_compute_csum((void *)pim, len))) { + ip_compute_csum((void *)pim, skb->len))) { kfree_skb(skb); return -EINVAL; } @@ -1464,7 +1483,7 @@ encap = (struct iphdr*)(skb->h.raw + sizeof(struct pimreghdr)); if (!MULTICAST(encap->daddr) || ntohs(encap->tot_len) == 0 || - ntohs(encap->tot_len) + sizeof(*pim) > len) { + ntohs(encap->tot_len) + sizeof(*pim) > skb->len) { kfree_skb(skb); return -EINVAL; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/netfilter/ip_conntrack_core.c linux.ac/net/ipv4/netfilter/ip_conntrack_core.c --- linux.vanilla/net/ipv4/netfilter/ip_conntrack_core.c Mon Jan 22 21:30:21 2001 +++ linux.ac/net/ipv4/netfilter/ip_conntrack_core.c Sat Apr 14 01:49:20 2001 @@ -894,7 +894,12 @@ if (!skb) { if (sk) sock_put(sk); return skb; + } else if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + if (sk) sock_put(sk); + return NULL; } + if (sk) { skb_set_owner_w(skb, sk); sock_put(sk); @@ -986,7 +991,7 @@ return -ENOPROTOOPT; } - if (*len != sizeof(struct sockaddr_in)) { + if ((unsigned int) *len < sizeof(struct sockaddr_in)) { DEBUGP("SO_ORIGINAL_DST: len %u not %u\n", *len, sizeof(struct sockaddr_in)); return -EINVAL; @@ -1076,10 +1081,14 @@ int ret; /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB - * machine has 256 buckets. 1GB machine has 8192 buckets. */ + * machine has 256 buckets. >= 1GB machines have 8192 buckets. */ ip_conntrack_htable_size = (((num_physpages << PAGE_SHIFT) / 16384) / sizeof(struct list_head)); + if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE)) + ip_conntrack_htable_size = 8192; + if (ip_conntrack_htable_size < 16) + ip_conntrack_htable_size = 16; ip_conntrack_max = 8 * ip_conntrack_htable_size; printk("ip_conntrack (%u buckets, %d max)\n", diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/netfilter/ip_fw_compat.c linux.ac/net/ipv4/netfilter/ip_fw_compat.c --- linux.vanilla/net/ipv4/netfilter/ip_fw_compat.c Fri Feb 9 19:34:13 2001 +++ linux.ac/net/ipv4/netfilter/ip_fw_compat.c Sat Apr 14 01:49:42 2001 @@ -96,7 +96,8 @@ /* Assume worse case: any hook could change packet */ (*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED; - (*pskb)->ip_summed = CHECKSUM_NONE; + if ((*pskb)->ip_summed == CHECKSUM_HW) + (*pskb)->ip_summed = CHECKSUM_NONE; switch (hooknum) { case NF_IP_PRE_ROUTING: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/netfilter/ip_nat_standalone.c linux.ac/net/ipv4/netfilter/ip_nat_standalone.c --- linux.vanilla/net/ipv4/netfilter/ip_nat_standalone.c Sat Feb 3 19:45:55 2001 +++ linux.ac/net/ipv4/netfilter/ip_nat_standalone.c Sat Apr 14 01:49:42 2001 @@ -64,7 +64,7 @@ (*pskb)->nfcache |= NFC_UNKNOWN; /* If we had a hardware checksum before, it's now invalid */ - if ((*pskb)->pkt_type != PACKET_LOOPBACK) + if ((*pskb)->ip_summed == CHECKSUM_HW) (*pskb)->ip_summed = CHECKSUM_NONE; ct = ip_conntrack_get(*pskb, &ctinfo); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/netfilter/ipchains_core.c linux.ac/net/ipv4/netfilter/ipchains_core.c --- linux.vanilla/net/ipv4/netfilter/ipchains_core.c Fri Apr 14 01:19:57 2000 +++ linux.ac/net/ipv4/netfilter/ipchains_core.c Sat Apr 14 01:49:42 2001 @@ -871,7 +871,7 @@ if (chainptr->chain == NULL) { /* If pointer writes are atomic then turning off - * interupts is not necessary. */ + * interrupts is not necessary. */ chainptr->chain = rule; if (rule->branch) rule->branch->refcount++; return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/raw.c linux.ac/net/ipv4/raw.c --- linux.vanilla/net/ipv4/raw.c Fri Feb 9 19:29:44 2001 +++ linux.ac/net/ipv4/raw.c Sat Apr 14 01:49:55 2001 @@ -5,7 +5,7 @@ * * RAW - implementation of IP "raw" sockets. * - * Version: $Id: raw.c,v 1.56 2000/11/28 13:38:38 davem Exp $ + * Version: $Id: raw.c,v 1.60 2001/02/23 06:32:11 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -170,11 +170,10 @@ return sk; } -void raw_err (struct sock *sk, struct sk_buff *skb) +void raw_err (struct sock *sk, struct sk_buff *skb, u32 info) { int type = skb->h.icmph->type; int code = skb->h.icmph->code; - u32 info = 0; int err = 0; int harderr = 0; @@ -195,7 +194,6 @@ return; case ICMP_PARAMETERPROB: err = EPROTO; - info = ntohl(skb->h.icmph->un.gateway)>>24; harderr = 1; break; case ICMP_DEST_UNREACH: @@ -207,12 +205,17 @@ if (code == ICMP_FRAG_NEEDED) { harderr = (sk->protinfo.af_inet.pmtudisc != IP_PMTUDISC_DONT); err = EMSGSIZE; - info = ntohs(skb->h.icmph->un.frag.mtu); } } - if (sk->protinfo.af_inet.recverr) - ip_icmp_error(sk, skb, err, 0, info, (u8 *)(skb->h.icmph + 1)); + if (sk->protinfo.af_inet.recverr) { + struct iphdr *iph = (struct iphdr*)skb->data; + u8 *payload = skb->data+(iph->ihl<<2); + + if (sk->protinfo.af_inet.hdrincl) + payload = skb->data; + ip_icmp_error(sk, skb, err, 0, info, payload); + } if (sk->protinfo.af_inet.recverr || harderr) { sk->err = err; @@ -235,18 +238,9 @@ return NET_RX_SUCCESS; } -/* - * This should be the easiest of all, all we do is - * copy it into a buffer. All demultiplexing is done - * in ip.c - */ - int raw_rcv(struct sock *sk, struct sk_buff *skb) { - /* Now we need to copy this into memory. */ - skb_trim(skb, ntohs(skb->nh.iph->tot_len)); - - skb->h.raw = skb->nh.raw; + skb_push(skb, skb->data-skb->nh.raw); raw_rcv_skb(sk, skb); return 0; @@ -296,7 +290,7 @@ * ip_build_xmit clean (well less messy). */ if (!iph->id) - ip_select_ident(iph, rfh->dst); + ip_select_ident(iph, rfh->dst, NULL); iph->check=ip_fast_csum((unsigned char *)iph, iph->ihl); } return 0; @@ -498,7 +492,7 @@ msg->msg_flags |= MSG_TRUNC; copied = len; } - + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (err) goto done; @@ -540,6 +534,8 @@ if (get_user(len,optlen)) return -EFAULT; + if (len < 0) + return -EINVAL; if (len > sizeof(struct icmp_filter)) len = sizeof(struct icmp_filter); if (put_user(len, optlen)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/route.c linux.ac/net/ipv4/route.c --- linux.vanilla/net/ipv4/route.c Tue Oct 10 18:33:52 2000 +++ linux.ac/net/ipv4/route.c Sat Apr 14 01:49:55 2001 @@ -5,7 +5,7 @@ * * ROUTE - implementation of the IP router. * - * Version: $Id: route.c,v 1.91 2000/10/03 07:29:00 anton Exp $ + * Version: $Id: route.c,v 1.93 2001/02/22 01:03:05 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -115,7 +115,7 @@ int ip_rt_gc_elasticity = 8; int ip_rt_mtu_expires = 10*60*HZ; int ip_rt_min_pmtu = 512+20+20; -int ip_rt_min_advmss = 536; +int ip_rt_min_advmss = 256; static unsigned long rt_deadline; @@ -667,7 +667,7 @@ spin_lock_bh(&ip_fb_id_lock); salt = secure_ip_id(ip_fallback_id ^ iph->daddr); - iph->id = salt & 0xFFFF; + iph->id = htons(salt & 0xFFFF); ip_fallback_id = salt; spin_unlock_bh(&ip_fb_id_lock); } @@ -684,7 +684,7 @@ so that we need not to grab a lock to dereference it. */ if (rt->peer) { - iph->id = inet_getid(rt->peer); + iph->id = htons(inet_getid(rt->peer)); return; } } else { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/syncookies.c linux.ac/net/ipv4/syncookies.c --- linux.vanilla/net/ipv4/syncookies.c Fri Feb 9 19:29:44 2001 +++ linux.ac/net/ipv4/syncookies.c Sat Apr 14 01:49:55 2001 @@ -9,7 +9,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * $Id: syncookies.c,v 1.12 2000/07/26 01:04:19 davem Exp $ + * $Id: syncookies.c,v 1.13 2001/02/13 01:17:26 davem Exp $ * * Missing: IPv6 support. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/tcp.c linux.ac/net/ipv4/tcp.c --- linux.vanilla/net/ipv4/tcp.c Fri Feb 9 19:34:13 2001 +++ linux.ac/net/ipv4/tcp.c Sat Apr 14 01:49:56 2001 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp.c,v 1.180 2000/11/28 17:04:09 davem Exp $ + * Version: $Id: tcp.c,v 1.201 2001/03/06 22:42:56 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -520,6 +520,7 @@ sk->ack_backlog = 0; tp->accept_queue = tp->accept_queue_tail = NULL; tp->syn_wait_lock = RW_LOCK_UNLOCKED; + tcp_delack_init(tp); lopt = kmalloc(sizeof(struct tcp_listen_opt), GFP_KERNEL); if (!lopt) @@ -642,11 +643,8 @@ if(sk->err) return sock_error(sk); if((1 << sk->state) & - ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) { - if(sk->keepopen && !(flags&MSG_NOSIGNAL)) - send_sig(SIGPIPE, tsk, 0); + ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) return -EPIPE; - } if(!*timeo_p) return -EAGAIN; if(signal_pending(tsk)) @@ -675,56 +673,326 @@ /* * Wait for more memory for a socket */ -static long wait_for_tcp_memory(struct sock * sk, long timeo) +static int wait_for_tcp_memory(struct sock * sk, long *timeo) { + int err = 0; long vm_wait = 0; - long current_timeo = timeo; + long current_timeo = *timeo; DECLARE_WAITQUEUE(wait, current); if (tcp_memory_free(sk)) current_timeo = vm_wait = (net_random()%(HZ/5))+2; - clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); - add_wait_queue(sk->sleep, &wait); for (;;) { - set_bit(SOCK_NOSPACE, &sk->socket->flags); + set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); set_current_state(TASK_INTERRUPTIBLE); + if (sk->err || (sk->shutdown & SEND_SHUTDOWN)) + goto do_error; + if (!*timeo) + goto do_nonblock; if (signal_pending(current)) - break; + goto do_interrupted; + clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); if (tcp_memory_free(sk) && !vm_wait) break; - if (sk->shutdown & SEND_SHUTDOWN) - break; - if (sk->err) - break; + + set_bit(SOCK_NOSPACE, &sk->socket->flags); + sk->tp_pinfo.af_tcp.write_pending++; release_sock(sk); if (!tcp_memory_free(sk) || vm_wait) current_timeo = schedule_timeout(current_timeo); lock_sock(sk); + sk->tp_pinfo.af_tcp.write_pending--; + if (vm_wait) { - if (timeo != MAX_SCHEDULE_TIMEOUT && - (timeo -= vm_wait-current_timeo) < 0) - timeo = 0; - break; - } else { - timeo = current_timeo; + vm_wait -= current_timeo; + current_timeo = *timeo; + if (current_timeo != MAX_SCHEDULE_TIMEOUT && + (current_timeo -= vm_wait) < 0) + current_timeo = 0; + vm_wait = 0; } + *timeo = current_timeo; } +out: current->state = TASK_RUNNING; remove_wait_queue(sk->sleep, &wait); - return timeo; + return err; + +do_error: + err = -EPIPE; + goto out; +do_nonblock: + err = -EAGAIN; + goto out; +do_interrupted: + err = sock_intr_errno(*timeo); + goto out; } -/* When all user supplied data has been queued set the PSH bit */ -#define PSH_NEEDED (seglen == 0 && iovlen == 0) +ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags); -/* - * This routine copies from a user buffer into a socket, - * and starts the transmit system. - */ +static inline int +can_coalesce(struct sk_buff *skb, int i, struct page *page, int off) +{ + if (i) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1]; + return page == frag->page && + off == frag->page_offset+frag->size; + } + return 0; +} + +static inline void +fill_page_desc(struct sk_buff *skb, int i, struct page *page, int off, int size) +{ + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + frag->page = page; + frag->page_offset = off; + frag->size = size; + skb_shinfo(skb)->nr_frags = i+1; +} + +static inline void tcp_mark_push(struct tcp_opt *tp, struct sk_buff *skb) +{ + TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; + tp->pushed_seq = tp->write_seq; +} + +static inline int forced_push(struct tcp_opt *tp) +{ + return after(tp->write_seq, tp->pushed_seq + (tp->max_window>>1)); +} + +static inline void +skb_entail(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb) +{ + skb->csum = 0; + TCP_SKB_CB(skb)->seq = tp->write_seq; + TCP_SKB_CB(skb)->end_seq = tp->write_seq; + TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK; + TCP_SKB_CB(skb)->sacked = 0; + __skb_queue_tail(&sk->write_queue, skb); + tcp_charge_skb(sk, skb); + if (tp->send_head == NULL) + tp->send_head = skb; +} + +static inline void +tcp_mark_urg(struct tcp_opt *tp, int flags, struct sk_buff *skb) +{ + if (flags & MSG_OOB) { + tp->urg_mode = 1; + tp->snd_up = tp->write_seq; + TCP_SKB_CB(skb)->sacked |= TCPCB_URG; + } +} + +static inline void +tcp_push(struct sock *sk, struct tcp_opt *tp, int flags, int mss_now, int nonagle) +{ + if (tp->send_head) { + struct sk_buff *skb = sk->write_queue.prev; + if (!(flags&MSG_MORE) || forced_push(tp)) + tcp_mark_push(tp, skb); + tcp_mark_urg(tp, flags, skb); + __tcp_push_pending_frames(sk, tp, mss_now, (flags&MSG_MORE) ? 2 : nonagle); + } +} + +static int tcp_error(struct sock *sk, int flags, int err) +{ + if (err == -EPIPE) + err = sock_error(sk) ? : -EPIPE; + if (err == -EPIPE && !(flags&MSG_NOSIGNAL)) + send_sig(SIGPIPE, current, 0); + return err; +} + +ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + int mss_now; + int err; + ssize_t copied; + long timeo = sock_sndtimeo(sk, flags&MSG_DONTWAIT); + + /* Wait for a connection to finish. */ + if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) + if((err = wait_for_tcp_connect(sk, 0, &timeo)) != 0) + goto out_err; + + clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); + + mss_now = tcp_current_mss(sk); + copied = 0; + + err = -EPIPE; + if (sk->err || (sk->shutdown & SEND_SHUTDOWN)) + goto do_error; + + while (psize > 0) { + struct sk_buff *skb = sk->write_queue.prev; + int offset, size, copy, i; + struct page *page; + + page = pages[poffset/PAGE_SIZE]; + offset = poffset % PAGE_SIZE; + size = min(psize, PAGE_SIZE-offset); + + if (tp->send_head==NULL || (copy = mss_now - skb->len) <= 0) { +new_segment: + if (!tcp_memory_free(sk)) + goto wait_for_sndbuf; + + skb = tcp_alloc_pskb(sk, 0, tp->mss_cache, sk->allocation); + if (skb == NULL) + goto wait_for_memory; + + skb_entail(sk, tp, skb); + copy = mss_now; + } + + if (copy > size) + copy = size; + + i = skb_shinfo(skb)->nr_frags; + if (can_coalesce(skb, i, page, offset)) { + skb_shinfo(skb)->frags[i-1].size += copy; + } else if (i < MAX_SKB_FRAGS) { + get_page(page); + fill_page_desc(skb, i, page, offset, copy); + } else { + tcp_mark_push(tp, skb); + goto new_segment; + } + + skb->len += copy; + skb->data_len += copy; + skb->ip_summed = CHECKSUM_HW; + tp->write_seq += copy; + TCP_SKB_CB(skb)->end_seq += copy; + + if (!copied) + TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH; + + copied += copy; + poffset += copy; + if (!(psize -= copy)) + goto out; + + if (skb->len != mss_now || (flags&MSG_OOB)) + continue; + + if (forced_push(tp)) { + tcp_mark_push(tp, skb); + __tcp_push_pending_frames(sk, tp, mss_now, 1); + } else if (skb == tp->send_head) + tcp_push_one(sk, mss_now); + continue; + +wait_for_sndbuf: + set_bit(SOCK_NOSPACE, &sk->socket->flags); +wait_for_memory: + if (copied) + tcp_push(sk, tp, flags&~MSG_MORE, mss_now, 1); + + if ((err = wait_for_tcp_memory(sk, &timeo)) != 0) + goto do_error; + + mss_now = tcp_current_mss(sk); + } + +out: + if (copied) + tcp_push(sk, tp, flags, mss_now, tp->nonagle); + return copied; + +do_error: + if (copied) + goto out; +out_err: + return tcp_error(sk, flags, err); +} + +ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags) +{ + ssize_t res; + struct sock *sk = sock->sk; + +#define TCP_ZC_CSUM_FLAGS (NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM) + + if (!(sk->route_caps & NETIF_F_SG) || + !(sk->route_caps & TCP_ZC_CSUM_FLAGS)) + return sock_no_sendpage(sock, page, offset, size, flags); + +#undef TCP_ZC_CSUM_FLAGS + + lock_sock(sk); + TCP_CHECK_TIMER(sk); + res = do_tcp_sendpages(sk, &page, offset, size, flags); + TCP_CHECK_TIMER(sk); + release_sock(sk); + return res; +} + +#define TCP_PAGE(sk) (sk->tp_pinfo.af_tcp.sndmsg_page) +#define TCP_OFF(sk) (sk->tp_pinfo.af_tcp.sndmsg_off) + +static inline int +tcp_copy_to_page(struct sock *sk, char *from, struct sk_buff *skb, + struct page *page, int off, int copy) +{ + int err = 0; + unsigned int csum; + + csum = csum_and_copy_from_user(from, page_address(page)+off, + copy, 0, &err); + if (!err) { + if (skb->ip_summed == CHECKSUM_NONE) + skb->csum = csum_block_add(skb->csum, csum, skb->len); + skb->len += copy; + skb->data_len += copy; + skb->truesize += copy; + sk->wmem_queued += copy; + sk->forward_alloc -= copy; + } + return err; +} + +static inline int +skb_add_data(struct sk_buff *skb, char *from, int copy) +{ + int err = 0; + unsigned int csum; + int off = skb->len; + + csum = csum_and_copy_from_user(from, skb_put(skb, copy), + copy, 0, &err); + if (!err) { + skb->csum = csum_block_add(skb->csum, csum, off); + return 0; + } + + __skb_trim(skb, off); + return -EFAULT; +} + +static inline int select_size(struct sock *sk, struct tcp_opt *tp) +{ + int tmp = tp->mss_cache; + + if (sk->route_caps&NETIF_F_SG) { + int pgbreak = SKB_MAX_HEAD(MAX_TCP_HEADER); + + if (tmp >= pgbreak && tmp <= pgbreak + (MAX_SKB_FRAGS-1)*PAGE_SIZE) + tmp = pgbreak; + } + return tmp; +} int tcp_sendmsg(struct sock *sk, struct msghdr *msg, int size) { @@ -736,20 +1004,18 @@ int err, copied; long timeo; - err = 0; tp = &(sk->tp_pinfo.af_tcp); lock_sock(sk); TCP_CHECK_TIMER(sk); flags = msg->msg_flags; - timeo = sock_sndtimeo(sk, flags&MSG_DONTWAIT); /* Wait for a connection to finish. */ if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) if((err = wait_for_tcp_connect(sk, flags, &timeo)) != 0) - goto out_unlock; + goto out_err; /* This should be in poll */ clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); @@ -761,6 +1027,10 @@ iov = msg->msg_iov; copied = 0; + err = -EPIPE; + if (sk->err || (sk->shutdown&SEND_SHUTDOWN)) + goto do_error; + while (--iovlen >= 0) { int seglen=iov->iov_len; unsigned char * from=iov->iov_base; @@ -768,200 +1038,159 @@ iov++; while (seglen > 0) { - int copy, tmp, queue_it; - - if (err) - goto do_fault2; - - /* Stop on errors. */ - if (sk->err) - goto do_sock_err; - - /* Make sure that we are established. */ - if (sk->shutdown & SEND_SHUTDOWN) - goto do_shutdown; - - /* Now we need to check if we have a half - * built packet we can tack some data onto. - */ + int copy; + skb = sk->write_queue.prev; - if (tp->send_head && - (mss_now > skb->len)) { - copy = skb->len; - if (skb_tailroom(skb) > 0) { - int last_byte_was_odd = (copy % 4); - - copy = mss_now - copy; - if(copy > skb_tailroom(skb)) - copy = skb_tailroom(skb); - if(copy > seglen) - copy = seglen; - if(last_byte_was_odd) { - if(copy_from_user(skb_put(skb, copy), - from, copy)) - err = -EFAULT; - skb->csum = csum_partial(skb->data, - skb->len, 0); - } else { - skb->csum = - csum_and_copy_from_user( - from, skb_put(skb, copy), - copy, skb->csum, &err); - } - /* - * FIXME: the *_user functions should - * return how much data was - * copied before the fault - * occurred and then a partial - * packet with this data should - * be sent. Unfortunately - * csum_and_copy_from_user doesn't - * return this information. - * ATM it might send partly zeroed - * data in this case. - */ - tp->write_seq += copy; - TCP_SKB_CB(skb)->end_seq += copy; - from += copy; - copied += copy; - seglen -= copy; - if (PSH_NEEDED || - after(tp->write_seq, tp->pushed_seq+(tp->max_window>>1))) { - TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; - tp->pushed_seq = tp->write_seq; - } - if (flags&MSG_OOB) { - tp->urg_mode = 1; - tp->snd_up = tp->write_seq; - TCP_SKB_CB(skb)->sacked |= TCPCB_URG; - } - continue; - } else { - TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; - tp->pushed_seq = tp->write_seq; - } - } - copy = min(seglen, mss_now); + if (tp->send_head == NULL || + (copy = mss_now - skb->len) <= 0) { - /* Determine how large of a buffer to allocate. */ - tmp = MAX_TCP_HEADER + 15 + tp->mss_cache; - if (copy < mss_now && !(flags & MSG_OOB)) { - /* What is happening here is that we want to - * tack on later members of the users iovec - * if possible into a single frame. When we - * leave this loop our we check to see if - * we can send queued frames onto the wire. +new_segment: + /* Allocate new segment. If the interface is SG, + * allocate skb fitting to single page. */ - queue_it = 1; - } else { - queue_it = 0; - } - - skb = NULL; - if (tcp_memory_free(sk)) - skb = tcp_alloc_skb(sk, tmp, sk->allocation); - if (skb == NULL) { - /* If we didn't get any memory, we need to sleep. */ - set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); - set_bit(SOCK_NOSPACE, &sk->socket->flags); + if (!tcp_memory_free(sk)) + goto wait_for_sndbuf; - __tcp_push_pending_frames(sk, tp, mss_now, 1); - - if (!timeo) { - err = -EAGAIN; - goto do_interrupted; + skb = tcp_alloc_pskb(sk, select_size(sk, tp), 0, sk->allocation); + if (skb == NULL) + goto wait_for_memory; + + skb_entail(sk, tp, skb); + copy = mss_now; + } + + /* Try to append data to the end of skb. */ + if (copy > seglen) + copy = seglen; + + /* Where to copy to? */ + if (skb_tailroom(skb) > 0) { + /* We have some space in skb head. Superb! */ + if (copy > skb_tailroom(skb)) + copy = skb_tailroom(skb); + if ((err = skb_add_data(skb, from, copy)) != 0) + goto do_fault; + } else { + int merge = 0; + int i = skb_shinfo(skb)->nr_frags; + struct page *page = TCP_PAGE(sk); + int off = TCP_OFF(sk); + + if (can_coalesce(skb, i, page, off) && off != PAGE_SIZE) { + /* We can extend the last page fragment. */ + merge = 1; + } else if (i == MAX_SKB_FRAGS || + (i == 0 && !(sk->route_caps&NETIF_F_SG))) { + /* Need to add new fragment and cannot + * do this because interface is non-SG, + * or because all the page slots are busy. + */ + tcp_mark_push(tp, skb); + goto new_segment; + } else if (page) { + /* If page is cached, align + * offset to L1 cache boundary + */ + off = (off+L1_CACHE_BYTES-1)&~(L1_CACHE_BYTES-1); + if (off == PAGE_SIZE) { + put_page(page); + TCP_PAGE(sk) = page = NULL; + } } - if (signal_pending(current)) { - err = sock_intr_errno(timeo); - goto do_interrupted; + + if (!page) { + /* Allocate new cache page. */ + if (!(page=tcp_alloc_page(sk))) + goto wait_for_memory; + off = 0; } - timeo = wait_for_tcp_memory(sk, timeo); - /* If SACK's were formed or PMTU events happened, - * we must find out about it. - */ - mss_now = tcp_current_mss(sk); - continue; - } + if (copy > PAGE_SIZE-off) + copy = PAGE_SIZE-off; - seglen -= copy; + /* Time to copy data. We are close to the end! */ + err = tcp_copy_to_page(sk, from, skb, page, off, copy); + if (err) + goto do_error; + + /* Update the skb. */ + if (merge) { + skb_shinfo(skb)->frags[i-1].size += copy; + } else { + fill_page_desc(skb, i, page, off, copy); + if (TCP_PAGE(sk)) { + get_page(page); + } else if (off + copy < PAGE_SIZE) { + get_page(page); + TCP_PAGE(sk) = page; + } + } - /* Prepare control bits for TCP header creation engine. */ - if (PSH_NEEDED || - after(tp->write_seq+copy, tp->pushed_seq+(tp->max_window>>1))) { - TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK|TCPCB_FLAG_PSH; - tp->pushed_seq = tp->write_seq + copy; - } else { - TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK; - } - TCP_SKB_CB(skb)->sacked = 0; - if (flags & MSG_OOB) { - TCP_SKB_CB(skb)->sacked |= TCPCB_URG; - tp->urg_mode = 1; - tp->snd_up = tp->write_seq + copy; + TCP_OFF(sk) = off+copy; } - /* TCP data bytes are SKB_PUT() on top, later - * TCP+IP+DEV headers are SKB_PUSH()'d beneath. - * Reserve header space and checksum the data. - */ - skb_reserve(skb, MAX_TCP_HEADER); - skb->csum = csum_and_copy_from_user(from, - skb_put(skb, copy), copy, 0, &err); + if (!copied) + TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH; - if (err) - goto do_fault; + tp->write_seq += copy; + TCP_SKB_CB(skb)->end_seq += copy; from += copy; copied += copy; + seglen -= copy; + + if (skb->len != mss_now || (flags&MSG_OOB)) + continue; - TCP_SKB_CB(skb)->seq = tp->write_seq; - TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + copy; + if (forced_push(tp)) { + tcp_mark_push(tp, skb); + __tcp_push_pending_frames(sk, tp, mss_now, 1); + } else if (skb == tp->send_head) + tcp_push_one(sk, mss_now); + continue; - /* This advances tp->write_seq for us. */ - tcp_send_skb(sk, skb, queue_it, mss_now); +wait_for_sndbuf: + set_bit(SOCK_NOSPACE, &sk->socket->flags); +wait_for_memory: + if (copied) + tcp_push(sk, tp, flags&~MSG_MORE, mss_now, 1); + + if ((err = wait_for_tcp_memory(sk, &timeo)) != 0) + goto do_error; + + mss_now = tcp_current_mss(sk); } } - err = copied; + out: - __tcp_push_pending_frames(sk, tp, mss_now, tp->nonagle); -out_unlock: + if (copied) + tcp_push(sk, tp, flags, mss_now, tp->nonagle); TCP_CHECK_TIMER(sk); release_sock(sk); - return err; + return copied; -do_sock_err: - if (copied) - err = copied; - else - err = sock_error(sk); - goto out; -do_shutdown: - if (copied) - err = copied; - else { - if (!(flags&MSG_NOSIGNAL)) - send_sig(SIGPIPE, current, 0); - err = -EPIPE; - } - goto out; -do_interrupted: - if (copied) - err = copied; - goto out_unlock; do_fault: - __kfree_skb(skb); -do_fault2: + if (skb->len==0) { + if (tp->send_head == skb) { + tp->send_head = skb->prev; + if (tp->send_head == (struct sk_buff*)&sk->write_queue) + tp->send_head = NULL; + } + __skb_unlink(skb, skb->list); + tcp_free_skb(sk, skb); + } + +do_error: if (copied) - err = copied; - else - err = -EFAULT; - goto out; + goto out; +out_err: + err = tcp_error(sk, flags, err); + TCP_CHECK_TIMER(sk); + release_sock(sk); + return err; } -#undef PSH_NEEDED - /* * Handle reading urgent data. BSD has very simple semantics for * this, no blocking and very strange errors 8) @@ -991,7 +1220,7 @@ msg->msg_flags|=MSG_OOB; if(len>0) { - if (!(flags & MSG_PEEK)) + if (!(flags & MSG_PEEK) && !(flags & MSG_TRUNC)) err = memcpy_toiovec(msg->msg_iov, &c, 1); len = 1; } else @@ -1033,17 +1262,13 @@ static void cleanup_rbuf(struct sock *sk, int copied) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - struct sk_buff *skb; int time_to_ack = 0; - /* NOTE! The socket must be locked, so that we don't get - * a messed-up receive queue. - */ - while ((skb=skb_peek(&sk->receive_queue)) != NULL) { - if (!skb->used) - break; - tcp_eat_skb(sk, skb); - } +#if TCP_DEBUG + struct sk_buff *skb = skb_peek(&sk->receive_queue); + + BUG_TRAP(skb==NULL || before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq)); +#endif if (tcp_ack_scheduled(tp)) { /* Delayed ACKs frequently hit locked sockets during bulk receive. */ @@ -1219,8 +1444,7 @@ goto found_ok_skb; if (skb->h.th->fin) goto found_fin_ok; - if (!(flags & MSG_PEEK)) - skb->used = 1; + BUG_TRAP(flags&MSG_PEEK); skb = skb->next; } while (skb != (struct sk_buff *)&sk->receive_queue); @@ -1233,7 +1457,8 @@ if (sk->err || sk->state == TCP_CLOSE || (sk->shutdown & RCV_SHUTDOWN) || - !timeo) + !timeo || + (flags & MSG_PEEK)) break; } else { if (sk->done) @@ -1358,15 +1583,16 @@ ++*seq; offset++; used--; + if (!used) + goto skip_copy; } } else used = urg_offset; } } - err = 0; if (!(flags&MSG_TRUNC)) { - err = memcpy_toiovec(msg->msg_iov, ((unsigned char *)skb->h.th) + skb->h.th->doff*4 + offset, used); + err = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, used); if (err) { /* Exception. Bailout! */ if (!copied) @@ -1379,37 +1605,25 @@ copied += used; len -= used; - if (after(tp->copied_seq,tp->urg_seq)) { +skip_copy: + if (tp->urg_data && after(tp->copied_seq,tp->urg_seq)) { tp->urg_data = 0; - if (skb_queue_len(&tp->out_of_order_queue) == 0 -#ifdef TCP_FORMAL_WINDOW - && tcp_receive_window(tp) -#endif - ) { - tcp_fast_path_on(tp); - } + tcp_fast_path_check(sk, tp); } if (used + offset < skb->len) continue; - /* Process the FIN. We may also need to handle PSH - * here and make it break out of MSG_WAITALL. - */ if (skb->h.th->fin) goto found_fin_ok; - if (flags & MSG_PEEK) - continue; - skb->used = 1; - tcp_eat_skb(sk, skb); + if (!(flags & MSG_PEEK)) + tcp_eat_skb(sk, skb); continue; found_fin_ok: + /* Process the FIN. */ ++*seq; - if (flags & MSG_PEEK) - break; - - /* All is done. */ - skb->used = 1; + if (!(flags & MSG_PEEK)) + tcp_eat_skb(sk, skb); break; } while (len > 0); @@ -1556,7 +1770,7 @@ /* It cannot be in hash table! */ BUG_TRAP(sk->pprev==NULL); - /* It it has not 0 sk->num, it must be bound */ + /* If it has not 0 sk->num, it must be bound */ BUG_TRAP(!sk->num || sk->prev!=NULL); #ifdef TCP_DEBUG @@ -2041,7 +2255,7 @@ tp->defer_accept = 0; if (val > 0) { /* Translate value in seconds to number of retransmits */ - while (val > ((TCP_TIMEOUT_INIT/HZ)<<tp->defer_accept)) + while (tp->defer_accept < 32 && val > ((TCP_TIMEOUT_INIT/HZ)<<tp->defer_accept)) tp->defer_accept++; tp->defer_accept++; } @@ -2060,6 +2274,21 @@ } break; + case TCP_QUICKACK: + if (!val) { + tp->ack.pingpong = 1; + } else { + tp->ack.pingpong = 0; + if ((1<<sk->state)&(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT) && + tcp_ack_scheduled(tp)) { + tp->ack.pending |= TCP_ACK_PUSHED; + cleanup_rbuf(sk, 1); + if (!(val & 1)) + tp->ack.pingpong = 1; + } + } + break; + default: err = -ENOPROTOOPT; break; @@ -2082,6 +2311,9 @@ return -EFAULT; len = min(len, sizeof(int)); + + if(len < 0) + return -EINVAL; switch(optname) { case TCP_MAXSEG: @@ -2180,6 +2412,9 @@ return -EFAULT; return 0; } + case TCP_QUICKACK: + val = !tp->ack.pingpong; + break; default: return -ENOPROTOOPT; }; @@ -2230,7 +2465,10 @@ * * The methodology is similar to that of the buffer cache. */ - goal = num_physpages >> (23 - PAGE_SHIFT); + if (num_physpages >= (128 * 1024)) + goal = num_physpages >> (21 - PAGE_SHIFT); + else + goal = num_physpages >> (23 - PAGE_SHIFT); for(order = 0; (1UL << order) < goal; order++) ; @@ -2284,9 +2522,9 @@ } tcp_port_rover = sysctl_local_port_range[0] - 1; - sysctl_tcp_mem[0] = 64<<order; - sysctl_tcp_mem[1] = 200<<order; - sysctl_tcp_mem[2] = 256<<order; + sysctl_tcp_mem[0] = 768<<order; + sysctl_tcp_mem[1] = 1024<<order; + sysctl_tcp_mem[2] = 1536<<order; if (sysctl_tcp_mem[2] - sysctl_tcp_mem[1] > 512) sysctl_tcp_mem[1] = sysctl_tcp_mem[2] - 512; if (sysctl_tcp_mem[1] - sysctl_tcp_mem[0] > 512) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/tcp_input.c linux.ac/net/ipv4/tcp_input.c --- linux.vanilla/net/ipv4/tcp_input.c Fri Feb 9 19:34:13 2001 +++ linux.ac/net/ipv4/tcp_input.c Sat Apr 14 01:49:56 2001 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_input.c,v 1.205 2000/12/13 18:31:48 davem Exp $ + * Version: $Id: tcp_input.c,v 1.226 2001/03/07 22:00:57 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -137,7 +137,7 @@ * * "len" is invariant segment length, including TCP header. */ - len = skb->tail - skb->h.raw; + len += skb->data - skb->h.raw; if (len >= TCP_MIN_RCVMSS + sizeof(struct tcphdr) || /* If PSH is not set, packet should be * full sized, provided peer TCP is not badly broken. @@ -378,7 +378,8 @@ /* The _first_ data packet received, initialize * delayed ACK engine. */ - tcp_enter_quickack_mode(tp); + tcp_incr_quickack(tp); + tp->ack.ato = TCP_ATO_MIN; } else { int m = now - tp->ack.lrcvtime; @@ -510,7 +511,7 @@ } /* Save metrics learned by this TCP session. - This function is called only, when TCP finishes sucessfully + This function is called only, when TCP finishes successfully i.e. when it enters TIME-WAIT or goes from LAST-ACK to CLOSE. */ void tcp_update_metrics(struct sock *sk) @@ -1016,7 +1017,7 @@ tp->fackets_out = cnt; } } - tp->left_out = tp->sacked_out + tp->lost_out; + tcp_sync_left_out(tp); tp->reordering = min(tp->reordering, sysctl_tcp_reordering); tp->ca_state = TCP_CA_Loss; @@ -1052,6 +1053,15 @@ return IsReno(tp) ? tp->sacked_out+1 : tp->fackets_out; } +static inline int tcp_skb_timedout(struct tcp_opt *tp, struct sk_buff *skb) +{ + return (tcp_time_stamp - TCP_SKB_CB(skb)->when > tp->rto); +} + +static inline int tcp_head_timedout(struct sock *sk, struct tcp_opt *tp) +{ + return tp->packets_out && tcp_skb_timedout(tp, skb_peek(&sk->write_queue)); +} /* Linux NewReno/SACK/FACK/ECN state machine. * -------------------------------------- @@ -1157,7 +1167,13 @@ if (tcp_fackets_out(tp) > tp->reordering) return 1; - /* Trick#3: It is still not OK... But will it be useful to delay + /* Trick#3 : when we use RFC2988 timer restart, fast + * retransmit can be triggered by timeout of queue head. + */ + if (tcp_head_timedout(sk, tp)) + return 1; + + /* Trick#4: It is still not OK... But will it be useful to delay * recovery more? */ if (tp->packets_out <= tp->reordering && @@ -1178,8 +1194,10 @@ */ static void tcp_check_reno_reordering(struct tcp_opt *tp, int addend) { - if (tp->sacked_out + 1 > tp->packets_out) { - tp->sacked_out = tp->packets_out ? tp->packets_out - 1 : 0; + int holes = min(max(tp->lost_out, 1), tp->packets_out); + + if (tp->sacked_out + holes > tp->packets_out) { + tp->sacked_out = tp->packets_out - holes; tcp_update_reordering(tp, tp->packets_out+addend, 0); } } @@ -1190,7 +1208,7 @@ { ++tp->sacked_out; tcp_check_reno_reordering(tp, 0); - tp->left_out = tp->sacked_out + tp->lost_out; + tcp_sync_left_out(tp); } /* Account for ACK, ACKing some data in Reno Recovery phase. */ @@ -1198,17 +1216,14 @@ static void tcp_remove_reno_sacks(struct sock *sk, struct tcp_opt *tp, int acked) { if (acked > 0) { - /* One ACK eated lost packet. Must eat! */ - BUG_TRAP(tp->lost_out == 0); - - /* The rest eat duplicate ACKs. */ + /* One ACK acked hole. The rest eat duplicate ACKs. */ if (acked-1 >= tp->sacked_out) tp->sacked_out = 0; else tp->sacked_out -= acked-1; } tcp_check_reno_reordering(tp, acked); - tp->left_out = tp->sacked_out + tp->lost_out; + tcp_sync_left_out(tp); } static inline void tcp_reset_reno_sack(struct tcp_opt *tp) @@ -1234,7 +1249,7 @@ tp->lost_out++; } } - tp->left_out = tp->sacked_out + tp->lost_out; + tcp_sync_left_out(tp); } /* Account newly detected lost packet(s) */ @@ -1249,6 +1264,24 @@ } else { tcp_mark_head_lost(sk, tp, 1, tp->high_seq); } + + /* New heuristics: it is possible only after we switched + * to restart timer each time when something is ACKed. + * Hence, we can detect timed out packets during fast + * retransmit without falling to slow start. + */ + if (tcp_head_timedout(sk, tp)) { + struct sk_buff *skb; + + for_retrans_queue(skb, sk, tp) { + if (tcp_skb_timedout(tp, skb) && + !(TCP_SKB_CB(skb)->sacked&TCPCB_TAGBITS)) { + TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; + tp->lost_out++; + } + } + tcp_sync_left_out(tp); + } } /* CWND moderation, preventing bursts due to too big ACKs @@ -1490,7 +1523,7 @@ } /* D. Synchronize left_out to current state. */ - tp->left_out = tp->sacked_out + tp->lost_out; + tcp_sync_left_out(tp); /* E. Check state exit conditions. State can be terminated * when high_seq is ACKed. */ @@ -1516,8 +1549,13 @@ case TCP_CA_Disorder: tcp_try_undo_dsack(sk, tp); - tp->undo_marker = 0; - tp->ca_state = TCP_CA_Open; + if (!tp->undo_marker || + /* For SACK case do not Open to allow to undo + * catching for all duplicate ACKs. */ + IsReno(tp) || tp->snd_una != tp->high_seq) { + tp->undo_marker = 0; + tp->ca_state = TCP_CA_Open; + } break; case TCP_CA_Recovery: @@ -1544,8 +1582,8 @@ } break; case TCP_CA_Loss: - if (flag & FLAG_ACKED) - tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); + if (flag&FLAG_DATA_ACKED) + tp->retransmits = 0; if (!tcp_try_undo_loss(sk, tp)) { tcp_moderate_cwnd(tp); tcp_xmit_retransmit_queue(sk); @@ -1593,7 +1631,7 @@ tp->ca_state = TCP_CA_Recovery; } - if (is_dupack) + if (is_dupack || tcp_head_timedout(sk, tp)) tcp_update_scoreboard(sk, tp); tcp_cwnd_down(tp); tcp_xmit_retransmit_queue(sk); @@ -1613,16 +1651,18 @@ * * See draft-ietf-tcplw-high-performance-00, section 3.3. * 1998/04/10 Andrey V. Savochkin <saw@msu.ru> + * + * Changed: reset backoff as soon as we see the first valid sample. + * If we do not, we get strongly overstimated rto. With timestamps + * samples are accepted even from very old segments: f.e., when rtt=1 + * increases to 8, we retransmit 5 times and after 8 seconds delayed + * answer arrives rto becomes 120 seconds! If at least one of segments + * in window is lost... Voila. --ANK (010210) */ seq_rtt = tcp_time_stamp - tp->rcv_tsecr; tcp_rtt_estimator(tp, seq_rtt); tcp_set_rto(tp); - if (tp->backoff) { - if (!tp->retransmits || !(flag & FLAG_RETRANS_DATA_ACKED)) - tp->backoff = 0; - else - tp->rto <<= tp->backoff; - } + tp->backoff = 0; tcp_bound_rto(tp); } @@ -1642,15 +1682,7 @@ tcp_rtt_estimator(tp, seq_rtt); tcp_set_rto(tp); - if (tp->backoff) { - /* To relax it? We have valid sample as soon as we are - * here. Why not to clear backoff? - */ - if (!tp->retransmits) - tp->backoff = 0; - else - tp->rto <<= tp->backoff; - } + tp->backoff = 0; tcp_bound_rto(tp); } @@ -1684,15 +1716,11 @@ } else tp->snd_cwnd_cnt++; } + tp->snd_cwnd_stamp = tcp_time_stamp; } /* Restart timer after forward progress on connection. - * RFC2988 recommends (and BSD does) to restart timer to now+rto, - * which is certainly wrong and effectively means that - * rto includes one more _full_ rtt. - * - * For details see: - * ftp://ftp.inr.ac.ru:/ip-routing/README.rto + * RFC2988 recommends to restart timer to now+rto. */ static __inline__ void tcp_ack_packets_out(struct sock *sk, struct tcp_opt *tp) @@ -1700,12 +1728,7 @@ if (tp->packets_out==0) { tcp_clear_xmit_timer(sk, TCP_TIME_RETRANS); } else { - struct sk_buff *skb = skb_peek(&sk->write_queue); - __u32 when = tp->rto + tp->rttvar - (tcp_time_stamp - TCP_SKB_CB(skb)->when); - - if ((__s32)when < (__s32)tp->rttvar) - when = tp->rttvar; - tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, min(when, TCP_RTO_MAX)); + tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); } } @@ -1857,12 +1880,7 @@ /* Note, it is the only place, where * fast path is recovered for sending TCP. */ - if (skb_queue_len(&tp->out_of_order_queue) == 0 && -#ifdef TCP_FORMAL_WINDOW - tcp_receive_window(tp) && -#endif - !tp->urg_data) - tcp_fast_path_on(tp); + tcp_fast_path_check(sk, tp); if (nwin > tp->max_window) { tp->max_window = nwin; @@ -1873,16 +1891,6 @@ tp->snd_una = ack; -#ifdef TCP_DEBUG - if (before(tp->snd_una + tp->snd_wnd, tp->snd_nxt)) { - if (tp->snd_nxt-(tp->snd_una + tp->snd_wnd) >= (1<<tp->snd_wscale) - && net_ratelimit()) - printk(KERN_DEBUG "TCP: peer %u.%u.%u.%u:%u/%u shrinks window %u:%u:%u. Bad, what else can I say?\n", - NIPQUAD(sk->daddr), htons(sk->dport), sk->num, - tp->snd_una, tp->snd_wnd, tp->snd_nxt); - } -#endif - return flag; } @@ -2224,7 +2232,6 @@ { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - tp->fin_seq = TCP_SKB_CB(skb)->end_seq; tcp_schedule_ack(tp); sk->shutdown |= RCV_SHUTDOWN; @@ -2506,10 +2513,27 @@ } } +static inline int tcp_rmem_schedule(struct sock *sk, struct sk_buff *skb) +{ + return (int)skb->truesize <= sk->forward_alloc || + tcp_mem_schedule(sk, skb->truesize, 1); +} + +static int tcp_prune_queue(struct sock *sk); + static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) { + struct tcphdr *th = skb->h.th; struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - int eaten = 0; + int eaten = -1; + + th = skb->h.th; + __skb_pull(skb, th->doff*4); + + if (skb->len == 0 && !th->fin) + goto drop; + + TCP_ECN_accept_cwr(tp, skb); if (tp->dsack) { tp->dsack = 0; @@ -2535,26 +2559,32 @@ __set_current_state(TASK_RUNNING); local_bh_enable(); - if (memcpy_toiovec(tp->ucopy.iov, skb->data, chunk)) { + if (skb_copy_datagram_iovec(skb, 0, tp->ucopy.iov, chunk)) { sk->err = EFAULT; sk->error_report(sk); } local_bh_disable(); tp->ucopy.len -= chunk; tp->copied_seq += chunk; - eaten = (chunk == skb->len && !skb->h.th->fin); + eaten = (chunk == skb->len && !th->fin); } - if (!eaten) { + if (eaten <= 0) { queue_and_out: + if (eaten < 0 && + (atomic_read(&sk->rmem_alloc) > sk->rcvbuf || + !tcp_rmem_schedule(sk, skb))) { + if (tcp_prune_queue(sk) < 0 || !tcp_rmem_schedule(sk, skb)) + goto drop; + } tcp_set_owner_r(skb, sk); __skb_queue_tail(&sk->receive_queue, skb); } tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; if(skb->len) tcp_event_data_recv(sk, tp, skb); - if(skb->h.th->fin) - tcp_fin(skb, sk, skb->h.th); + if(th->fin) + tcp_fin(skb, sk, th); if (skb_queue_len(&tp->out_of_order_queue)) { tcp_ofo_queue(sk); @@ -2569,15 +2599,9 @@ if(tp->num_sacks) tcp_sack_remove(tp); - /* Turn on fast path. */ - if (skb_queue_len(&tp->out_of_order_queue) == 0 && -#ifdef TCP_FORMAL_WINDOW - tcp_receive_window(tp) && -#endif - !tp->urg_data) - tcp_fast_path_on(tp); + tcp_fast_path_check(sk, tp); - if (eaten) { + if (eaten > 0) { __kfree_skb(skb); } else if (!sk->dead) sk->data_ready(sk, 0); @@ -2592,17 +2616,12 @@ out_of_window: tcp_schedule_ack(tp); +drop: __kfree_skb(skb); return; } - /* Out of window. F.e. zero window probe. - * - * Note: it is highly possible that we may open window and enqueue - * this segment now. However, this will be known only after we queue - * it, which will result in queue full of successive 1 byte BSD - * window probes, it is SWS in fact. So, always reject it and send ACK. - */ + /* Out of window. F.e. zero window probe. */ if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt+tcp_receive_window(tp))) goto out_of_window; @@ -2626,6 +2645,12 @@ TCP_ECN_check_ce(tp, skb); + if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf || + !tcp_rmem_schedule(sk, skb)) { + if (tcp_prune_queue(sk) < 0 || !tcp_rmem_schedule(sk, skb)) + goto drop; + } + /* Disable header prediction. */ tp->pred_flags = 0; tcp_schedule_ack(tp); @@ -2704,52 +2729,142 @@ } } - -static void tcp_collapse_queue(struct sock *sk, struct sk_buff_head *q) +/* Collapse contiguous sequence of skbs head..tail with + * sequence numbers start..end. + * Segments with FIN/SYN are not collapsed (only because this + * simplifies code) + */ +static void +tcp_collapse(struct sock *sk, struct sk_buff *head, + struct sk_buff *tail, u32 start, u32 end) { - struct sk_buff *skb = skb_peek(q); - struct sk_buff *skb_next; + struct sk_buff *skb; - while (skb && - skb != (struct sk_buff *)q && - (skb_next = skb->next) != (struct sk_buff *)q) { - struct tcp_skb_cb *scb = TCP_SKB_CB(skb); - struct tcp_skb_cb *scb_next = TCP_SKB_CB(skb_next); - - if (scb->end_seq == scb_next->seq && - skb_tailroom(skb) >= skb_next->len && -#define TCP_DONT_COLLAPSE (TCP_FLAG_FIN|TCP_FLAG_URG|TCP_FLAG_SYN) - !(tcp_flag_word(skb->h.th)&TCP_DONT_COLLAPSE) && - !(tcp_flag_word(skb_next->h.th)&TCP_DONT_COLLAPSE)) { - /* OK to collapse two skbs to one */ - memcpy(skb_put(skb, skb_next->len), skb_next->data, skb_next->len); - __skb_unlink(skb_next, skb_next->list); - scb->end_seq = scb_next->end_seq; - __kfree_skb(skb_next); + /* First, check that queue is collapsable and find + * the point where collapsing can be useful. */ + for (skb = head; skb != tail; ) { + /* No new bits? It is possible on ofo queue. */ + if (!before(start, TCP_SKB_CB(skb)->end_seq)) { + struct sk_buff *next = skb->next; + __skb_unlink(skb, skb->list); + __kfree_skb(skb); NET_INC_STATS_BH(TCPRcvCollapsed); - } else { - /* Lots of spare tailroom, reallocate this skb to trim it. */ - if (tcp_win_from_space(skb->truesize) > skb->len && - skb_tailroom(skb) > sizeof(struct sk_buff) + 16) { - struct sk_buff *nskb; - - nskb = skb_copy_expand(skb, skb_headroom(skb), 0, GFP_ATOMIC); - if (nskb) { - tcp_set_owner_r(nskb, sk); - memcpy(nskb->data-skb_headroom(skb), - skb->data-skb_headroom(skb), - skb_headroom(skb)); - __skb_append(skb, nskb); - __skb_unlink(skb, skb->list); - __kfree_skb(skb); - } + skb = next; + continue; + } + + /* The first skb to collapse is: + * - not SYN/FIN and + * - bloated or contains data before "start" or + * overlaps to the next one. + */ + if (!skb->h.th->syn && !skb->h.th->fin && + (tcp_win_from_space(skb->truesize) > skb->len || + before(TCP_SKB_CB(skb)->seq, start) || + (skb->next != tail && + TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb->next)->seq))) + break; + + /* Decided to skip this, advance start seq. */ + start = TCP_SKB_CB(skb)->end_seq; + skb = skb->next; + } + if (skb == tail || skb->h.th->syn || skb->h.th->fin) + return; + + while (before(start, end)) { + struct sk_buff *nskb; + int header = skb_headroom(skb); + int copy = (PAGE_SIZE - sizeof(struct sk_buff) - + sizeof(struct skb_shared_info) - header - 31)&~15; + + /* Too big header? This can happen with IPv6. */ + if (copy < 0) + return; + if (end-start < copy) + copy = end-start; + nskb = alloc_skb(copy+header, GFP_ATOMIC); + if (!nskb) + return; + skb_reserve(nskb, header); + memcpy(nskb->head, skb->head, header); + nskb->nh.raw = nskb->head + (skb->nh.raw-skb->head); + nskb->h.raw = nskb->head + (skb->h.raw-skb->head); + nskb->mac.raw = nskb->head + (skb->mac.raw-skb->head); + memcpy(nskb->cb, skb->cb, sizeof(skb->cb)); + TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(nskb)->end_seq = start; + __skb_insert(nskb, skb->prev, skb, skb->list); + tcp_set_owner_r(nskb, sk); + + /* Copy data, releasing collapsed skbs. */ + while (copy > 0) { + int offset = start - TCP_SKB_CB(skb)->seq; + int size = TCP_SKB_CB(skb)->end_seq - start; + + if (offset < 0) BUG(); + if (size > 0) { + size = min(copy, size); + if (skb_copy_bits(skb, offset, skb_put(nskb, size), size)) + BUG(); + TCP_SKB_CB(nskb)->end_seq += size; + copy -= size; + start += size; + } + if (!before(start, TCP_SKB_CB(skb)->end_seq)) { + struct sk_buff *next = skb->next; + __skb_unlink(skb, skb->list); + __kfree_skb(skb); + NET_INC_STATS_BH(TCPRcvCollapsed); + skb = next; + if (skb == tail || skb->h.th->syn || skb->h.th->fin) + return; } - skb = skb_next; } } } -/* Clean the out_of_order queue if we can, trying to get +/* Collapse ofo queue. Algorithm: select contiguous sequence of skbs + * and tcp_collapse() them until all the queue is collapsed. + */ +static void tcp_collapse_ofo_queue(struct sock *sk) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + struct sk_buff *skb = skb_peek(&tp->out_of_order_queue); + struct sk_buff *head; + u32 start, end; + + if (skb == NULL) + return; + + start = TCP_SKB_CB(skb)->seq; + end = TCP_SKB_CB(skb)->end_seq; + head = skb; + + for (;;) { + skb = skb->next; + + /* Segment is terminated when we see gap or when + * we are at the end of all the queue. */ + if (skb == (struct sk_buff *)&tp->out_of_order_queue || + after(TCP_SKB_CB(skb)->seq, end) || + before(TCP_SKB_CB(skb)->end_seq, start)) { + tcp_collapse(sk, head, skb, start, end); + head = skb; + if (skb == (struct sk_buff *)&tp->out_of_order_queue) + break; + /* Start new segment */ + start = TCP_SKB_CB(skb)->seq; + end = TCP_SKB_CB(skb)->end_seq; + } else { + if (before(TCP_SKB_CB(skb)->seq, start)) + start = TCP_SKB_CB(skb)->seq; + if (after(TCP_SKB_CB(skb)->end_seq, end)) + end = TCP_SKB_CB(skb)->end_seq; + } + } +} + +/* Reduce allocated memory if we can, trying to get * the socket within its memory limits again. * * Return less than zero if we should start dropping frames @@ -2769,8 +2884,10 @@ else if (tcp_memory_pressure) tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4*tp->advmss); - tcp_collapse_queue(sk, &sk->receive_queue); - tcp_collapse_queue(sk, &tp->out_of_order_queue); + tcp_collapse_ofo_queue(sk); + tcp_collapse(sk, sk->receive_queue.next, + (struct sk_buff*)&sk->receive_queue, + tp->copied_seq, tp->rcv_nxt); tcp_mem_reclaim(sk); if (atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) @@ -2804,59 +2921,10 @@ NET_INC_STATS_BH(RcvPruned); /* Massive buffer overcommit. */ + tp->pred_flags = 0; return -1; } -static inline int tcp_rmem_schedule(struct sock *sk, struct sk_buff *skb) -{ - return (int)skb->truesize <= sk->forward_alloc || - tcp_mem_schedule(sk, skb->truesize, 1); -} - -/* - * This routine handles the data. If there is room in the buffer, - * it will be have already been moved into it. If there is no - * room, then we will just have to discard the packet. - */ - -static void tcp_data(struct sk_buff *skb, struct sock *sk, unsigned int len) -{ - struct tcphdr *th; - struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - - th = skb->h.th; - skb_pull(skb, th->doff*4); - skb_trim(skb, len - (th->doff*4)); - - if (skb->len == 0 && !th->fin) - goto drop; - - TCP_ECN_accept_cwr(tp, skb); - - /* - * If our receive queue has grown past its limits shrink it. - * Make sure to do this before moving rcv_nxt, otherwise - * data might be acked for that we don't have enough room. - */ - if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf || - !tcp_rmem_schedule(sk, skb)) { - if (tcp_prune_queue(sk) < 0 || !tcp_rmem_schedule(sk, skb)) - goto drop; - } - - tcp_data_queue(sk, skb); - -#ifdef TCP_DEBUG - if (before(tp->rcv_nxt, tp->copied_seq)) { - printk(KERN_DEBUG "*** tcp.c:tcp_data bug acked < copied\n"); - tp->rcv_nxt = tp->copied_seq; - } -#endif - return; - -drop: - __kfree_skb(skb); -} /* RFC2861, slow part. Adjust cwnd, after it was not full during one rto. * As additional protections, we do not touch cwnd in retransmission phases, @@ -2937,7 +3005,7 @@ if (after(TCP_SKB_CB(skb)->end_seq, tp->snd_una + tp->snd_wnd) || tcp_packets_in_flight(tp) >= tp->snd_cwnd || - tcp_write_xmit(sk)) + tcp_write_xmit(sk, tp->nonagle)) tcp_check_probe_timer(sk, tp); } @@ -3009,6 +3077,19 @@ if (after(tp->copied_seq, ptr)) return; + /* Do not replay urg ptr. + * + * NOTE: interesting situation not covered by specs. + * Misbehaving sender may send urg ptr, pointing to segment, + * which we already have in ofo queue. We are not able to fetch + * such data and will stay in TCP_URG_NOTYET until will be eaten + * by recvmsg(). Seems, we are not obliged to handle such wicked + * situations. But it is worth to think about possibility of some + * DoSes using some hypothetical application level deadlock. + */ + if (before(ptr, tp->rcv_nxt)) + return; + /* Do we already have a newer (or duplicate) urgent pointer? */ if (tp->urg_data && !after(ptr, tp->urg_seq)) return; @@ -3027,9 +3108,27 @@ * tp->copied_seq since we would read the last urgent byte again * as data, nor can we alter copied_seq until this data arrives * or we break the sematics of SIOCATMARK (and thus sockatmark()) - */ - if (tp->urg_seq == tp->copied_seq) - tp->copied_seq++; /* Move the copied sequence on correctly */ + * + * NOTE. Double Dutch. Rendering to plain English: author of comment + * above did something sort of send("A", MSG_OOB); send("B", MSG_OOB); + * and expect that both A and B disappear from stream. This is _wrong_. + * Though this happens in BSD with high probability, this is occasional. + * Any application relying on this is buggy. Note also, that fix "works" + * only in this artificial test. Insert some normal data between A and B and we will + * decline of BSD again. Verdict: it is better to remove to trap + * buggy users. + */ + if (tp->urg_seq == tp->copied_seq && tp->urg_data && + !sk->urginline && + tp->copied_seq != tp->rcv_nxt) { + struct sk_buff *skb = skb_peek(&sk->receive_queue); + tp->copied_seq++; + if (skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq)) { + __skb_unlink(skb, skb->list); + __kfree_skb(skb); + } + } + tp->urg_data = TCP_URG_NOTYET; tp->urg_seq = ptr; @@ -3038,7 +3137,7 @@ } /* This is the 'fast' part of urgent handling. */ -static inline void tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long len) +static inline void tcp_urg(struct sock *sk, struct sk_buff *skb, struct tcphdr *th) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); @@ -3048,11 +3147,14 @@ /* Do we wait for any urgent data? - normally not... */ if (tp->urg_data == TCP_URG_NOTYET) { - u32 ptr = tp->urg_seq - ntohl(th->seq) + (th->doff*4); + u32 ptr = tp->urg_seq - ntohl(th->seq) + (th->doff*4) - th->syn; /* Is the urgent pointer pointing into this packet? */ - if (ptr < len) { - tp->urg_data = TCP_URG_VALID | *(ptr + (unsigned char *) th); + if (ptr < skb->len) { + u8 tmp; + if (skb_copy_bits(skb, ptr, &tmp, 1)) + BUG(); + tp->urg_data = TCP_URG_VALID | tmp; if (!sk->dead) sk->data_ready(sk,0); } @@ -3067,9 +3169,9 @@ local_bh_enable(); if (skb->ip_summed==CHECKSUM_UNNECESSARY) - err = memcpy_toiovec(tp->ucopy.iov, skb->h.raw + hlen, chunk); + err = skb_copy_datagram_iovec(skb, hlen, tp->ucopy.iov, chunk); else - err = copy_and_csum_toiovec(tp->ucopy.iov, skb, hlen); + err = skb_copy_and_csum_datagram_iovec(skb, hlen, tp->ucopy.iov); if (!err) { update: @@ -3117,32 +3219,6 @@ * disabled when: * - A zero window was announced from us - zero window probing * is only handled properly in the slow path. - * [ NOTE: actually, it was made incorrectly and nobody ever noticed - * this! Reason is clear: 1. Correct senders do not send - * to zero window. 2. Even if a sender sends to zero window, - * nothing terrible occurs. - * - * For now I cleaned this and fast path is really always disabled, - * when window is zero, but I would be more happy to remove these - * checks. Code will be only cleaner and _faster_. --ANK - * - * Later note. I've just found that slow path also accepts - * out of window segments, look at tcp_sequence(). So... - * it is the last argument: I repair all and comment out - * repaired code by TCP_FORMAL_WINDOW. - * [ I remember one rhyme from a chidren's book. (I apologize, - * the trasnlation is not rhymed 8)): people in one (jewish) village - * decided to build sauna, but divided to two parties. - * The first one insisted that battens should not be dubbed, - * another objected that foots will suffer of splinters, - * the first fended that dubbed wet battens are too slippy - * and people will fall and it is much more serious! - * Certaiinly, all they went to rabbi. - * After some thinking, he judged: "Do not be lazy! - * Certainly, dub the battens! But put them by dubbed surface down." - * ] - * ] - * * - Out of order segments arrived. * - Urgent data is expected. * - There is no buffer space left @@ -3348,7 +3424,7 @@ tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq); - if(th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) { + if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { TCP_INC_STATS_BH(TcpInErrs); NET_INC_STATS_BH(TCPAbortOnSyn); tcp_reset(sk); @@ -3360,10 +3436,10 @@ tcp_ack(sk, skb, FLAG_SLOWPATH); /* Process urgent data. */ - tcp_urg(sk, th, len); + tcp_urg(sk, skb, th); /* step 7: process the segment text */ - tcp_data(skb, sk, len); + tcp_data_queue(sk, skb); tcp_data_snd_check(sk); tcp_ack_snd_check(sk); @@ -3452,8 +3528,6 @@ */ tp->snd_wnd = ntohs(th->window); tcp_init_wl(tp, TCP_SKB_CB(skb)->ack_seq, TCP_SKB_CB(skb)->seq); - tp->syn_seq = TCP_SKB_CB(skb)->seq; - tp->fin_seq = TCP_SKB_CB(skb)->seq; if (tp->wscale_ok == 0) { tp->snd_wscale = tp->rcv_wscale = 0; @@ -3488,7 +3562,7 @@ /* Remember, tcp_poll() does not lock socket! * Change state from SYN-SENT only after copied_seq - * is initilized. */ + * is initialized. */ tp->copied_seq = tp->rcv_nxt; mb(); tcp_set_state(sk, TCP_ESTABLISHED); @@ -3498,7 +3572,7 @@ sk_wake_async(sk, 0, POLL_OUT); } - if (tp->write_pending || tp->defer_accept) { + if (tp->write_pending || tp->defer_accept || tp->ack.pingpong) { /* Save one ACK. Data will be ready after * several ticks, if write_pending is set. * @@ -3508,6 +3582,8 @@ */ tcp_schedule_ack(tp); tp->ack.lrcvtime = tcp_time_stamp; + tp->ack.ato = TCP_ATO_MIN; + tcp_incr_quickack(tp); tcp_enter_quickack_mode(tp); tcp_reset_xmit_timer(sk, TCP_TIME_DACK, TCP_DELACK_MAX); @@ -3683,21 +3759,9 @@ /* step 4: * - * Check for a SYN, and ensure it matches the SYN we were - * first sent. We have to handle the rather unusual (but valid) - * sequence that KA9Q derived products may generate of - * - * SYN - * SYN|ACK Data - * ACK (lost) - * SYN|ACK Data + More Data - * .. we must ACK not RST... - * - * We keep syn_seq as the sequence space occupied by the - * original syn. + * Check for a SYN in window. */ - - if (th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) { + if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { NET_INC_STATS_BH(TCPAbortOnSyn); tcp_reset(sk); return 1; @@ -3806,13 +3870,13 @@ step6: /* step 6: check the URG bit */ - tcp_urg(sk, th, len); + tcp_urg(sk, skb, th); /* step 7: process the segment text */ switch (sk->state) { case TCP_CLOSE_WAIT: case TCP_CLOSING: - if (!before(TCP_SKB_CB(skb)->seq, tp->fin_seq)) + if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) break; case TCP_FIN_WAIT1: case TCP_FIN_WAIT2: @@ -3830,7 +3894,7 @@ } /* Fall through */ case TCP_ESTABLISHED: - tcp_data(skb, sk, len); + tcp_data_queue(sk, skb); queued = 1; break; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/tcp_ipv4.c linux.ac/net/ipv4/tcp_ipv4.c --- linux.vanilla/net/ipv4/tcp_ipv4.c Mon Jan 1 19:01:58 2001 +++ linux.ac/net/ipv4/tcp_ipv4.c Sat Apr 14 01:49:57 2001 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_ipv4.c,v 1.222 2000/12/08 17:15:53 davem Exp $ + * Version: $Id: tcp_ipv4.c,v 1.228 2001/04/06 18:41:36 davem Exp $ * * IPv4 specific functions * @@ -670,6 +670,7 @@ } __sk_dst_set(sk, &rt->u.dst); + sk->route_caps = rt->u.dst.dev->features; if (!sk->protinfo.af_inet.opt || !sk->protinfo.af_inet.opt->srr) daddr = rt->rt_dst; @@ -717,6 +718,7 @@ tp->ext_header_len = 0; if (sk->protinfo.af_inet.opt) tp->ext_header_len = sk->protinfo.af_inet.opt->optlen; + sk->protinfo.af_inet.id = tp->write_seq^jiffies; tp->mss_clamp = 536; @@ -726,6 +728,7 @@ failure: __sk_dst_reset(sk); + sk->route_caps = 0; sk->dport = 0; return err; } @@ -850,32 +853,21 @@ * */ -void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len) +void tcp_v4_err(struct sk_buff *skb, u32 info) { - struct iphdr *iph = (struct iphdr*)dp; - struct tcphdr *th; + struct iphdr *iph = (struct iphdr*)skb->data; + struct tcphdr *th = (struct tcphdr*)(skb->data+(iph->ihl<<2)); struct tcp_opt *tp; int type = skb->h.icmph->type; int code = skb->h.icmph->code; -#if ICMP_MIN_LENGTH < 14 - int no_flags = 0; -#else -#define no_flags 0 -#endif struct sock *sk; __u32 seq; int err; - if (len < (iph->ihl << 2) + ICMP_MIN_LENGTH) { + if (skb->len < (iph->ihl << 2) + 8) { ICMP_INC_STATS_BH(IcmpInErrors); return; } -#if ICMP_MIN_LENGTH < 14 - if (len < (iph->ihl << 2) + 14) - no_flags = 1; -#endif - - th = (struct tcphdr*)(dp+(iph->ihl<<2)); sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, th->source, tcp_v4_iif(skb)); if (sk == NULL) { @@ -921,7 +913,7 @@ if (code == ICMP_FRAG_NEEDED) { /* PMTU discovery (RFC1191) */ if (sk->lock.users == 0) - do_pmtu_discovery(sk, iph, ntohs(skb->h.icmph->un.frag.mtu)); + do_pmtu_discovery(sk, iph, info); goto out; } @@ -940,15 +932,6 @@ if (sk->lock.users != 0) goto out; - /* The final ACK of the handshake should be already - * handled in the new socket context, not here. - * Strictly speaking - an ICMP error for the final - * ACK should set the opening flag, but that is too - * complicated right now. - */ - if (!no_flags && !th->syn && !th->ack) - goto out; - req = tcp_v4_search_req(tp, iph, th, &prev); if (!req) goto out; @@ -976,8 +959,6 @@ case TCP_SYN_RECV: /* Cannot happen. It can f.e. if SYNs crossed. */ - if (!no_flags && !th->syn) - goto out; if (sk->lock.users == 0) { TCP_INC_STATS_BH(TcpAttemptFails); sk->err = err; @@ -1023,8 +1004,13 @@ void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len, struct sk_buff *skb) { - th->check = tcp_v4_check(th, len, sk->saddr, sk->daddr, - csum_partial((char *)th, th->doff<<2, skb->csum)); + if (skb->ip_summed == CHECKSUM_HW) { + th->check = ~tcp_v4_check(th, len, sk->saddr, sk->daddr, 0); + skb->csum = offsetof(struct tcphdr, check); + } else { + th->check = tcp_v4_check(th, len, sk->saddr, sk->daddr, + csum_partial((char *)th, th->doff<<2, skb->csum)); + } } /* @@ -1445,6 +1431,7 @@ goto exit; newsk->dst_cache = dst; + newsk->route_caps = dst->dev->features; newtp = &(newsk->tp_pinfo.af_tcp); newsk->daddr = req->af.v4_req.rmt_addr; @@ -1457,6 +1444,7 @@ newtp->ext_header_len = 0; if (newsk->protinfo.af_inet.opt) newtp->ext_header_len = newsk->protinfo.af_inet.opt->optlen; + newsk->protinfo.af_inet.id = newtp->write_seq^jiffies; tcp_sync_mss(newsk, dst->pmtu); newtp->advmss = dst->advmss; @@ -1512,23 +1500,23 @@ static int tcp_v4_checksum_init(struct sk_buff *skb) { if (skb->ip_summed == CHECKSUM_HW) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + if (!tcp_v4_check(skb->h.th,skb->len,skb->nh.iph->saddr, + skb->nh.iph->daddr,skb->csum)) + return 0; + + NETDEBUG(printk(KERN_DEBUG "hw tcp v4 csum failed\n")); + skb->ip_summed = CHECKSUM_NONE; + } + if (skb->len <= 76) { if (tcp_v4_check(skb->h.th,skb->len,skb->nh.iph->saddr, - skb->nh.iph->daddr,skb->csum)) { - NETDEBUG(printk(KERN_DEBUG "hw tcp v4 csum failed\n")); + skb->nh.iph->daddr, + skb_checksum(skb, 0, skb->len, 0))) return -1; - } skb->ip_summed = CHECKSUM_UNNECESSARY; } else { - if (skb->len <= 76) { - if (tcp_v4_check(skb->h.th,skb->len,skb->nh.iph->saddr, - skb->nh.iph->daddr, - csum_partial((char *)skb->h.th, skb->len, 0))) - return -1; - skb->ip_summed = CHECKSUM_UNNECESSARY; - } else { - skb->csum = ~tcp_v4_check(skb->h.th,skb->len,skb->nh.iph->saddr, - skb->nh.iph->daddr,0); - } + skb->csum = ~tcp_v4_check(skb->h.th,skb->len,skb->nh.iph->saddr, + skb->nh.iph->daddr,0); } return 0; } @@ -1601,7 +1589,7 @@ * From tcp_input.c */ -int tcp_v4_rcv(struct sk_buff *skb, unsigned short len) +int tcp_v4_rcv(struct sk_buff *skb) { struct tcphdr *th; struct sock *sk; @@ -1610,31 +1598,35 @@ if (skb->pkt_type!=PACKET_HOST) goto discard_it; - th = skb->h.th; - - /* Pull up the IP header. */ - __skb_pull(skb, skb->h.raw - skb->data); - /* Count it even if it's bad */ TCP_INC_STATS_BH(TcpInSegs); + if (!pskb_may_pull(skb, sizeof(struct tcphdr))) + goto discard_it; + + th = skb->h.th; + + if (th->doff < sizeof(struct tcphdr)/4) + goto bad_packet; + if (!pskb_may_pull(skb, th->doff*4)) + goto discard_it; + /* An explanation is required here, I think. * Packet length and doff are validated by header prediction, * provided case of th->doff==0 is elimineted. * So, we defer the checks. */ - if (th->doff < sizeof(struct tcphdr)/4 || - (skb->ip_summed != CHECKSUM_UNNECESSARY && + if ((skb->ip_summed != CHECKSUM_UNNECESSARY && tcp_v4_checksum_init(skb) < 0)) goto bad_packet; + th = skb->h.th; TCP_SKB_CB(skb)->seq = ntohl(th->seq); TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + - len - th->doff*4); + skb->len - th->doff*4); TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); TCP_SKB_CB(skb)->when = 0; TCP_SKB_CB(skb)->flags = skb->nh.iph->tos; TCP_SKB_CB(skb)->sacked = 0; - skb->used = 0; sk = __tcp_v4_lookup(skb->nh.iph->saddr, th->source, skb->nh.iph->daddr, ntohs(th->dest), tcp_v4_iif(skb)); @@ -1665,7 +1657,7 @@ return ret; no_tcp_socket: - if (len < (th->doff<<2) || tcp_checksum_complete(skb)) { + if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { bad_packet: TCP_INC_STATS_BH(TcpInErrs); } else { @@ -1682,7 +1674,7 @@ goto discard_it; do_time_wait: - if (len < (th->doff<<2) || tcp_checksum_complete(skb)) { + if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { TCP_INC_STATS_BH(TcpInErrs); goto discard_and_relse; } @@ -1740,7 +1732,7 @@ return err; __sk_dst_set(sk, &rt->u.dst); - /* sk->route_caps = rt->u.dst.dev->features; */ + sk->route_caps = rt->u.dst.dev->features; new_saddr = rt->rt_src; @@ -1788,20 +1780,19 @@ sk->bound_dev_if); if (!err) { __sk_dst_set(sk, &rt->u.dst); - /* sk->route_caps = rt->u.dst.dev->features; */ + sk->route_caps = rt->u.dst.dev->features; return 0; } /* Routing failed... */ - /* sk->route_caps = 0; */ + sk->route_caps = 0; if (!sysctl_ip_dynaddr || sk->state != TCP_SYN_SENT || (sk->userlocks & SOCK_BINDADDR_LOCK) || - (err = tcp_v4_reselect_saddr(sk)) != 0) { + (err = tcp_v4_reselect_saddr(sk)) != 0) sk->err_soft=-err; - /* sk->error_report(sk); */ - } + return err; } @@ -1940,7 +1931,7 @@ /* Cleanup up the write buffer. */ tcp_writequeue_purge(sk); - /* Cleans up our, hopefuly empty, out_of_order_queue. */ + /* Cleans up our, hopefully empty, out_of_order_queue. */ __skb_queue_purge(&tp->out_of_order_queue); /* Clean prequeue, it must be empty really */ @@ -1950,6 +1941,10 @@ if(sk->prev != NULL) tcp_put_port(sk); + /* If sendmsg cached page exists, toss it. */ + if (tp->sndmsg_page != NULL) + __free_page(tp->sndmsg_page); + atomic_dec(&tcp_sockets_allocated); return 0; @@ -2076,7 +2071,7 @@ if (pos >= offset) { get_tcp_sock(sk, tmpbuf, num); len += sprintf(buffer+len, "%-*s\n", TMPSZ-1, tmpbuf); - if (len >= length) { + if (pos >= offset + length) { tcp_listen_unlock(); goto out_no_bh; } @@ -2097,7 +2092,7 @@ continue; get_openreq(sk, req, tmpbuf, num, uid); len += sprintf(buffer+len, "%-*s\n", TMPSZ-1, tmpbuf); - if(len >= length) { + if (pos >= offset + length) { read_unlock_bh(&tp->syn_wait_lock); tcp_listen_unlock(); goto out_no_bh; @@ -2129,7 +2124,7 @@ continue; get_tcp_sock(sk, tmpbuf, num); len += sprintf(buffer+len, "%-*s\n", TMPSZ-1, tmpbuf); - if(len >= length) { + if (pos >= offset + length) { read_unlock(&head->lock); goto out; } @@ -2144,7 +2139,7 @@ continue; get_timewait_sock(tw, tmpbuf, num); len += sprintf(buffer+len, "%-*s\n", TMPSZ-1, tmpbuf); - if(len >= length) { + if (pos >= offset + length) { read_unlock(&head->lock); goto out; } @@ -2159,7 +2154,7 @@ begin = len - (pos - offset); *start = buffer + begin; len -= begin; - if(len > length) + if (len > length) len = length; if (len < 0) len = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/tcp_minisocks.c linux.ac/net/ipv4/tcp_minisocks.c --- linux.vanilla/net/ipv4/tcp_minisocks.c Wed Nov 29 05:53:45 2000 +++ linux.ac/net/ipv4/tcp_minisocks.c Sat Apr 14 01:49:57 2001 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_minisocks.c,v 1.5 2000/11/28 17:04:10 davem Exp $ + * Version: $Id: tcp_minisocks.c,v 1.9 2001/03/06 22:42:56 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -105,7 +105,7 @@ * lifetime in the internet, which results in wrong conclusion, that * it is set to catch "old duplicate segments" wandering out of their path. * It is not quite correct. This timeout is calculated so that it exceeds - * maximal retransmision timeout enough to allow to lose one (or more) + * maximal retransmission timeout enough to allow to lose one (or more) * segments sent by peer and our ACKs. This time may be calculated from RTO. * * When TIME-WAIT socket receives RST, it means that another end * finally closed and we are allowed to kill TIME-WAIT too. @@ -155,7 +155,7 @@ if (th->rst) goto kill; - if (th->syn && TCP_SKB_CB(skb)->seq != tw->syn_seq) + if (th->syn && !before(TCP_SKB_CB(skb)->seq, tw->rcv_nxt)) goto kill_with_rst; /* Dup ACK? */ @@ -377,7 +377,6 @@ tw->rcv_nxt = tp->rcv_nxt; tw->snd_nxt = tp->snd_nxt; tw->rcv_wnd = tcp_receive_window(tp); - tw->syn_seq = tp->syn_seq; tw->ts_recent = tp->ts_recent; tw->ts_recent_stamp= tp->ts_recent_stamp; tw->pprev_death = NULL; @@ -691,8 +690,6 @@ newtp->snd_una = req->snt_isn + 1; newtp->snd_sml = req->snt_isn + 1; - tcp_delack_init(newtp); - tcp_prequeue_init(newtp); tcp_init_wl(newtp, req->snt_isn, req->rcv_isn); @@ -734,8 +731,6 @@ newtp->probes_out = 0; newtp->num_sacks = 0; - newtp->syn_seq = req->rcv_isn; - newtp->fin_seq = req->rcv_isn; newtp->urg_data = 0; newtp->listen_opt = NULL; newtp->accept_queue = newtp->accept_queue_tail = NULL; @@ -822,7 +817,7 @@ } } - /* Check for pure retransmited SYN. */ + /* Check for pure retransmitted SYN. */ if (TCP_SKB_CB(skb)->seq == req->rcv_isn && flg == TCP_FLAG_SYN && !paws_reject) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/tcp_output.c linux.ac/net/ipv4/tcp_output.c --- linux.vanilla/net/ipv4/tcp_output.c Wed Nov 29 05:53:45 2000 +++ linux.ac/net/ipv4/tcp_output.c Sat Apr 14 01:49:57 2001 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_output.c,v 1.129 2000/11/28 17:04:10 davem Exp $ + * Version: $Id: tcp_output.c,v 1.136 2001/03/06 22:42:56 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -166,20 +166,9 @@ /* RFC1323 scaling applied */ new_win >>= tp->rcv_wscale; -#ifdef TCP_FORMAL_WINDOW - if (new_win == 0) { - /* If we advertise zero window, disable fast path. */ + /* If we advertise zero window, disable fast path. */ + if (new_win == 0) tp->pred_flags = 0; - } else if (cur_win == 0 && tp->pred_flags == 0 && - skb_queue_len(&tp->out_of_order_queue) == 0 && - !tp->urg_data) { - /* If we open zero window, enable fast path. - Without this it will be open by the first data packet, - it is too late to merge checksumming to copy. - */ - tcp_fast_path_on(tp); - } -#endif return new_win; } @@ -337,6 +326,91 @@ tp->send_head = skb; } +/* Send _single_ skb sitting at the send head. This function requires + * true push pending frames to setup probe timer etc. + */ +void tcp_push_one(struct sock *sk, unsigned cur_mss) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + struct sk_buff *skb = tp->send_head; + + if (tcp_snd_test(tp, skb, cur_mss, 1)) { + /* Send it out now. */ + TCP_SKB_CB(skb)->when = tcp_time_stamp; + if (tcp_transmit_skb(sk, skb_clone(skb, sk->allocation)) == 0) { + tp->send_head = NULL; + tp->snd_nxt = TCP_SKB_CB(skb)->end_seq; + if (tp->packets_out++ == 0) + tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); + return; + } + } +} + +/* Split fragmented skb to two parts at length len. */ + +static void skb_split(struct sk_buff *skb, struct sk_buff *skb1, u32 len) +{ + int i; + int pos = skb->len - skb->data_len; + + if (len < pos) { + /* Split line is inside header. */ + memcpy(skb_put(skb1, pos-len), skb->data + len, pos-len); + + /* And move data appendix as is. */ + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) + skb_shinfo(skb1)->frags[i] = skb_shinfo(skb)->frags[i]; + + skb_shinfo(skb1)->nr_frags = skb_shinfo(skb)->nr_frags; + skb_shinfo(skb)->nr_frags = 0; + + skb1->data_len = skb->data_len; + skb1->len += skb1->data_len; + skb->data_len = 0; + skb->len = len; + skb->tail = skb->data+len; + } else { + int k = 0; + int nfrags = skb_shinfo(skb)->nr_frags; + + /* Second chunk has no header, nothing to copy. */ + + skb_shinfo(skb)->nr_frags = 0; + skb1->len = skb1->data_len = skb->len - len; + skb->len = len; + skb->data_len = len - pos; + + for (i=0; i<nfrags; i++) { + int size = skb_shinfo(skb)->frags[i].size; + if (pos + size > len) { + skb_shinfo(skb1)->frags[k] = skb_shinfo(skb)->frags[i]; + + if (pos < len) { + /* Split frag. + * We have to variants in this case: + * 1. Move all the frag to the second + * part, if it is possible. F.e. + * this approach is mandatory for TUX, + * where splitting is expensive. + * 2. Split is accurately. We make this. + */ + get_page(skb_shinfo(skb)->frags[i].page); + skb_shinfo(skb1)->frags[0].page_offset += (len-pos); + skb_shinfo(skb1)->frags[0].size -= (len-pos); + skb_shinfo(skb)->frags[i].size = len-pos; + skb_shinfo(skb)->nr_frags++; + } + k++; + } else { + skb_shinfo(skb)->nr_frags++; + } + pos += size; + } + skb_shinfo(skb1)->nr_frags = k; + } +} + /* Function to create two new TCP segments. Shrinks the given segment * to the specified size and appends a new segment with the rest of the * packet to the list. This won't be called frequently, I hope. @@ -349,19 +423,22 @@ int nsize = skb->len - len; u16 flags; + if (skb_cloned(skb) && + skb_is_nonlinear(skb) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) + return -ENOMEM; + /* Get a new skb... force flag on. */ - buff = tcp_alloc_skb(sk, nsize + MAX_TCP_HEADER, GFP_ATOMIC); + buff = tcp_alloc_skb(sk, nsize, GFP_ATOMIC); if (buff == NULL) return -ENOMEM; /* We'll just try again later. */ tcp_charge_skb(sk, buff); - /* Reserve space for headers. */ - skb_reserve(buff, MAX_TCP_HEADER); - /* Correct the sequence numbers. */ TCP_SKB_CB(buff)->seq = TCP_SKB_CB(skb)->seq + len; TCP_SKB_CB(buff)->end_seq = TCP_SKB_CB(skb)->end_seq; - + TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq; + /* PSH and FIN should only be set in the second packet. */ flags = TCP_SKB_CB(skb)->flags; TCP_SKB_CB(skb)->flags = flags & ~(TCPCB_FLAG_FIN|TCPCB_FLAG_PSH); @@ -371,18 +448,22 @@ tp->lost_out++; tp->left_out++; } - TCP_SKB_CB(buff)->sacked &= ~TCPCB_AT_TAIL; + TCP_SKB_CB(skb)->sacked &= ~TCPCB_AT_TAIL; - /* Copy and checksum data tail into the new buffer. */ - buff->csum = csum_partial_copy_nocheck(skb->data + len, skb_put(buff, nsize), - nsize, 0); + if (!skb_shinfo(skb)->nr_frags && skb->ip_summed != CHECKSUM_HW) { + /* Copy and checksum data tail into the new buffer. */ + buff->csum = csum_partial_copy_nocheck(skb->data + len, skb_put(buff, nsize), + nsize, 0); - /* This takes care of the FIN sequence number too. */ - TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq; - skb_trim(skb, len); + skb_trim(skb, len); - /* Rechecksum original buffer. */ - skb->csum = csum_partial(skb->data, skb->len, 0); + skb->csum = csum_block_sub(skb->csum, buff->csum, len); + } else { + skb->ip_summed = CHECKSUM_HW; + skb_split(skb, buff, len); + } + + buff->ip_summed = skb->ip_summed; /* Looks stupid, but our code really uses when of * skbs, which it never sent before. --ANK @@ -461,7 +542,7 @@ * Returns 1, if no segments are in flight and we have queued segments, but * cannot send anything now because of SWS or another problem. */ -int tcp_write_xmit(struct sock *sk) +int tcp_write_xmit(struct sock *sk, int nonagle) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); unsigned int mss_now; @@ -482,7 +563,7 @@ mss_now = tcp_current_mss(sk); while((skb = tp->send_head) && - tcp_snd_test(tp, skb, mss_now, tcp_skb_is_last(sk, skb) ? tp->nonagle : 1)) { + tcp_snd_test(tp, skb, mss_now, tcp_skb_is_last(sk, skb) ? nonagle : 1)) { if (skb->len > mss_now) { if (tcp_fragment(sk, skb, mss_now)) break; @@ -568,22 +649,21 @@ * but may be worse for the performance because of rcv_mss * fluctuations. --SAW 1998/11/1 */ - unsigned int mss = tp->ack.rcv_mss; - int free_space; - u32 window; - - /* Sometimes free_space can be < 0. */ - free_space = tcp_space(sk); - if (tp->window_clamp < mss) - mss = tp->window_clamp; + int mss = tp->ack.rcv_mss; + int free_space = tcp_space(sk); + int full_space = min(tp->window_clamp, tcp_full_space(sk)); + int window; + + if (mss > full_space) + mss = full_space; - if (free_space < (int)min(tp->window_clamp, tcp_full_space(sk)) / 2) { + if (free_space < full_space/2) { tp->ack.quick = 0; if (tcp_memory_pressure) tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4*tp->advmss); - if (free_space < ((int)mss)) + if (free_space < mss) return 0; } @@ -599,9 +679,8 @@ * is too small. */ window = tp->rcv_wnd; - if ((((int) window) <= (free_space - ((int) mss))) || - (((int) window) > free_space)) - window = (((unsigned int) free_space)/mss)*mss; + if (window <= free_space - mss || window > free_space) + window = (free_space/mss)*mss; return window; } @@ -638,19 +717,14 @@ /* Ok. We will be able to collapse the packet. */ __skb_unlink(next_skb, next_skb->list); - if(skb->len % 4) { - /* Must copy and rechecksum all data. */ + if (next_skb->ip_summed == CHECKSUM_HW) + skb->ip_summed = CHECKSUM_HW; + + if (skb->ip_summed != CHECKSUM_HW) { memcpy(skb_put(skb, next_skb_size), next_skb->data, next_skb_size); - skb->csum = csum_partial(skb->data, skb->len, 0); - } else { - /* Optimize, actually we could also combine next_skb->csum - * to skb->csum using a single add w/carry operation too. - */ - skb->csum = csum_partial_copy_nocheck(next_skb->data, - skb_put(skb, next_skb_size), - next_skb_size, skb->csum); + skb->csum = csum_block_add(skb->csum, next_skb->csum, skb->len); } - + /* Update sequence range on original skb. */ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(next_skb)->end_seq; @@ -668,11 +742,12 @@ tp->lost_out--; tp->left_out--; } + /* Reno case is special. Sigh... */ if (!tp->sack_ok && tp->sacked_out) { - /* Reno case is special. Sigh... */ tp->sacked_out--; tp->left_out--; } + /* Not quite right: it can be > snd.fack, but * it is better to underestimate fackets. */ @@ -712,7 +787,7 @@ if (!lost) return; - tp->left_out = tp->sacked_out + tp->lost_out; + tcp_sync_left_out(tp); /* Don't muck with the congestion window here. * Reason is that we do not increase amount of _data_ @@ -745,6 +820,15 @@ if (atomic_read(&sk->wmem_alloc) > min(sk->wmem_queued+(sk->wmem_queued>>2),sk->sndbuf)) return -EAGAIN; + /* If receiver has shrunk his window, and skb is out of + * new window, do not retransmit it. The exception is the + * case, when window is shrunk to zero. In this case + * our retransmit serves as a zero window probe. + */ + if (!before(TCP_SKB_CB(skb)->seq, tp->snd_una+tp->snd_wnd) + && TCP_SKB_CB(skb)->seq != tp->snd_una) + return -EAGAIN; + if(skb->len > cur_mss) { if(tcp_fragment(sk, skb, cur_mss)) return -ENOMEM; /* We'll try again later. */ @@ -758,6 +842,7 @@ (skb->len < (cur_mss >> 1)) && (skb->next != tp->send_head) && (skb->next != (struct sk_buff *)&sk->write_queue) && + (skb_shinfo(skb)->nr_frags == 0 && skb_shinfo(skb->next)->nr_frags == 0) && (sysctl_tcp_retrans_collapse != 0)) tcp_retrans_try_collapse(sk, skb, cur_mss); @@ -771,9 +856,11 @@ if(skb->len > 0 && (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) && tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) { - TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1; - skb_trim(skb, 0); - skb->csum = 0; + if (!pskb_trim(skb, 0)) { + TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1; + skb->ip_summed = CHECKSUM_NONE; + skb->csum = 0; + } } /* Make a copy, if the first transmission SKB clone we made @@ -782,7 +869,7 @@ TCP_SKB_CB(skb)->when = tcp_time_stamp; err = tcp_transmit_skb(sk, (skb_cloned(skb) ? - skb_copy(skb, GFP_ATOMIC): + pskb_copy(skb, GFP_ATOMIC): skb_clone(skb, GFP_ATOMIC))); if (err == 0) { @@ -912,28 +999,10 @@ */ mss_now = tcp_current_mss(sk); - /* Please, find seven differences of 2.3.33 and loook - * what I broke here. 8) --ANK - */ - if(tp->send_head != NULL) { - /* tcp_write_xmit() takes care of the rest. */ TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_FIN; TCP_SKB_CB(skb)->end_seq++; tp->write_seq++; - - /* Special case to avoid Nagle bogosity. If this - * segment is the last segment, and it was queued - * due to Nagle/SWS-avoidance, send it out now. - */ - if(tp->send_head == skb && - !after(tp->write_seq, tp->snd_una + tp->snd_wnd)) { - TCP_SKB_CB(skb)->when = tcp_time_stamp; - if (!tcp_transmit_skb(sk, skb_clone(skb, GFP_KERNEL))) - update_send_head(sk, tp, skb); - else - tcp_check_probe_timer(sk, tp); - } } else { /* Socket is locked, keep trying until memory is available. */ for (;;) { @@ -953,9 +1022,9 @@ /* FIN eats a sequence byte, write_seq advanced by tcp_send_skb(). */ TCP_SKB_CB(skb)->seq = tp->write_seq; TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1; - tcp_send_skb(sk, skb, 0, mss_now); - __tcp_push_pending_frames(sk, tp, mss_now, 1); + tcp_send_skb(sk, skb, 1, mss_now); } + __tcp_push_pending_frames(sk, tp, mss_now, 1); } /* We get here when a process closes a file descriptor (either due to @@ -1224,23 +1293,6 @@ tp->ack.timeout = timeout; if (!mod_timer(&tp->delack_timer, timeout)) sock_hold(sk); - -#ifdef TCP_FORMAL_WINDOW - /* Explanation. Header prediction path does not handle - * case of zero window. If we send ACK immediately, pred_flags - * are reset when sending ACK. If rcv_nxt is advanced and - * ack is not sent, than delayed ack is scheduled. - * Hence, it is the best place to check for zero window. - */ - if (tp->pred_flags) { - if (tcp_receive_window(tp) == 0) - tp->pred_flags = 0; - } else { - if (skb_queue_len(&tp->out_of_order_queue) == 0 && - !tp->urg_data) - tcp_fast_path_on(tp); - } -#endif } /* This routine sends an ack and also updates the window. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/tcp_timer.c linux.ac/net/ipv4/tcp_timer.c --- linux.vanilla/net/ipv4/tcp_timer.c Fri Feb 9 19:34:13 2001 +++ linux.ac/net/ipv4/tcp_timer.c Sat Apr 14 01:49:58 2001 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_timer.c,v 1.81 2001/01/01 02:38:30 davem Exp $ + * Version: $Id: tcp_timer.c,v 1.83 2001/03/07 22:00:57 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -326,6 +326,29 @@ BUG_TRAP(!skb_queue_empty(&sk->write_queue)); + if (tp->snd_wnd == 0 && !sk->dead && + !((1<<sk->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV))) { + /* Receiver dastardly shrinks window. Our retransmits + * become zero probes, but we should not timeout this + * connection. If the socket is an orphan, time it out, + * we cannot allow such beasts to hang infinitely. + */ +#ifdef TCP_DEBUG + if (net_ratelimit()) + printk(KERN_DEBUG "TCP: Treason uncloaked! Peer %u.%u.%u.%u:%u/%u shrinks window %u:%u. Repaired.\n", + NIPQUAD(sk->daddr), htons(sk->dport), sk->num, + tp->snd_una, tp->snd_nxt); +#endif + if (tcp_time_stamp - tp->rcv_tstamp > TCP_RTO_MAX) { + tcp_write_err(sk); + goto out; + } + tcp_enter_loss(sk, 0); + tcp_retransmit_skb(sk, skb_peek(&sk->write_queue)); + __sk_dst_reset(sk); + goto out_reset_timer; + } + if (tcp_write_timeout(sk)) goto out; @@ -379,6 +402,8 @@ */ tp->backoff++; tp->retransmits++; + +out_reset_timer: tp->rto = min(tp->rto << 1, TCP_RTO_MAX); tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); if (tp->retransmits > sysctl_tcp_retries1) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/udp.c linux.ac/net/ipv4/udp.c --- linux.vanilla/net/ipv4/udp.c Fri Feb 9 19:34:13 2001 +++ linux.ac/net/ipv4/udp.c Sat Apr 14 01:49:58 2001 @@ -5,7 +5,7 @@ * * The User Datagram Protocol (UDP). * - * Version: $Id: udp.c,v 1.91 2000/11/28 13:38:38 davem Exp $ + * Version: $Id: udp.c,v 1.98 2001/03/06 21:15:10 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -291,22 +291,16 @@ * to find the appropriate port. */ -void udp_err(struct sk_buff *skb, unsigned char *dp, int len) +void udp_err(struct sk_buff *skb, u32 info) { - struct iphdr *iph = (struct iphdr*)dp; - struct udphdr *uh = (struct udphdr*)(dp+(iph->ihl<<2)); + struct iphdr *iph = (struct iphdr*)skb->data; + struct udphdr *uh = (struct udphdr*)(skb->data+(iph->ihl<<2)); int type = skb->h.icmph->type; int code = skb->h.icmph->code; struct sock *sk; int harderr; - u32 info; int err; - if (len < (iph->ihl<<2)+sizeof(struct udphdr)) { - ICMP_INC_STATS_BH(IcmpInErrors); - return; - } - sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex); if (sk == NULL) { ICMP_INC_STATS_BH(IcmpInErrors); @@ -314,7 +308,6 @@ } err = 0; - info = 0; harderr = 0; switch (type) { @@ -326,14 +319,12 @@ goto out; case ICMP_PARAMETERPROB: err = EPROTO; - info = ntohl(skb->h.icmph->un.gateway)>>24; harderr = 1; break; case ICMP_DEST_UNREACH: if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ if (sk->protinfo.af_inet.pmtudisc != IP_PMTUDISC_DONT) { err = EMSGSIZE; - info = ntohs(skb->h.icmph->un.frag.mtu); harderr = 1; break; } @@ -379,10 +370,7 @@ }; /* - * Copy and checksum a UDP packet from user space into a buffer. We still have - * to do the planning to get ip_build_xmit to spot direct transfer to network - * card and provide an additional callback mode for direct user->board I/O - * transfers. That one will be fun. + * Copy and checksum a UDP packet from user space into a buffer. */ static int udp_getfrag(const void *p, char * to, unsigned int offset, unsigned int fraglen) @@ -409,10 +397,7 @@ } /* - * Unchecksummed UDP is sufficiently critical to stuff like ATM video conferencing - * that we use two routines for this for speed. Probably we ought to have a - * CONFIG_FAST_NET set for >10Mb/second boards to activate this sort of coding. - * Timing needed to verify if this is a valid decision. + * Copy a UDP packet from user space into a buffer without checksumming. */ static int udp_getfrag_nosum(const void *p, char * to, unsigned int offset, unsigned int fraglen) @@ -625,7 +610,7 @@ static __inline__ int __udp_checksum_complete(struct sk_buff *skb) { - return (unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum)); + return (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); } static __inline__ int udp_checksum_complete(struct sk_buff *skb) @@ -655,11 +640,6 @@ if (flags & MSG_ERRQUEUE) return ip_recv_error(sk, msg, len); - /* - * From here the generic datagram does a lot of the work. Come - * the finished NET3, it will do _ALL_ the work! - */ - skb = skb_recv_datagram(sk, flags, noblock, &err); if (!skb) goto out; @@ -679,9 +659,9 @@ err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, copied); } else { - err = copy_and_csum_toiovec(msg->msg_iov, skb, sizeof(struct udphdr)); + err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); - if (err) + if (err == -EINVAL) goto csum_copy_err; } @@ -758,6 +738,7 @@ sk->daddr = rt->rt_dst; sk->dport = usin->sin_port; sk->state = TCP_ESTABLISHED; + sk->protinfo.af_inet.id = jiffies; sk_dst_set(sk, &rt->u.dst); return(0); @@ -872,10 +853,13 @@ if (uh->check == 0) { skb->ip_summed = CHECKSUM_UNNECESSARY; } else if (skb->ip_summed == CHECKSUM_HW) { - if (udp_check(uh, ulen, saddr, daddr, skb->csum)) - return -1; skb->ip_summed = CHECKSUM_UNNECESSARY; - } else if (skb->ip_summed != CHECKSUM_UNNECESSARY) + if (!udp_check(uh, ulen, saddr, daddr, skb->csum)) + return 0; + NETDEBUG(printk(KERN_DEBUG "udp v4 hw csum failure.\n")); + skb->ip_summed = CHECKSUM_NONE; + } + if (skb->ip_summed != CHECKSUM_UNNECESSARY) skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); /* Probably, we should checksum udp header (it should be in cache * in any case) and data in tiny packets (< rx copybreak). @@ -887,7 +871,7 @@ * All we need to do is get the socket, and then do a checksum. */ -int udp_rcv(struct sk_buff *skb, unsigned short len) +int udp_rcv(struct sk_buff *skb) { struct sock *sk; struct udphdr *uh; @@ -895,29 +879,22 @@ struct rtable *rt = (struct rtable*)skb->dst; u32 saddr = skb->nh.iph->saddr; u32 daddr = skb->nh.iph->daddr; - - /* - * Get the header. - */ - - uh = skb->h.uh; - __skb_pull(skb, skb->h.raw - skb->data); + int len = skb->len; IP_INC_STATS_BH(IpInDelivers); /* * Validate the packet and the UDP length. */ - - ulen = ntohs(uh->len); + ulen = ntohs(skb->h.uh->len); - if (ulen > len || ulen < sizeof(*uh)) { - NETDEBUG(printk(KERN_DEBUG "UDP: short packet: %d/%d\n", ulen, len)); - UDP_INC_STATS_BH(UdpInErrors); - kfree_skb(skb); - return(0); - } - skb_trim(skb, ulen); + if (ulen > len || ulen < sizeof(*uh)) + goto short_packet; + + if (pskb_trim(skb, ulen)) + goto short_packet; + + uh = skb->h.uh; if (udp_checksum_init(skb, uh, ulen, saddr, daddr) < 0) goto csum_error; @@ -944,6 +921,12 @@ * Hmm. We got an UDP packet to a port to which we * don't wanna listen. Ignore it. */ + kfree_skb(skb); + return(0); + +short_packet: + NETDEBUG(printk(KERN_DEBUG "UDP: short packet: %d/%d\n", ulen, len)); + UDP_INC_STATS_BH(UdpInErrors); kfree_skb(skb); return(0); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv6/af_inet6.c linux.ac/net/ipv6/af_inet6.c --- linux.vanilla/net/ipv6/af_inet6.c Mon Oct 23 23:48:28 2000 +++ linux.ac/net/ipv6/af_inet6.c Sat Apr 14 01:50:35 2001 @@ -7,7 +7,7 @@ * * Adapted from linux/net/ipv4/af_inet.c * - * $Id: af_inet6.c,v 1.60 2000/10/19 01:05:34 davem Exp $ + * $Id: af_inet6.c,v 1.63 2001/03/02 03:13:05 davem Exp $ * * Fixes: * Hideaki YOSHIFUJI : sin6_scope_id support @@ -461,6 +461,7 @@ sendmsg: inet_sendmsg, /* ok */ recvmsg: inet_recvmsg, /* ok */ mmap: sock_no_mmap, + sendpage: tcp_sendpage }; struct proto_ops inet6_dgram_ops = { @@ -481,6 +482,7 @@ sendmsg: inet_sendmsg, /* ok */ recvmsg: inet_recvmsg, /* ok */ mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; struct net_proto_family inet6_family_ops = { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv6/datagram.c linux.ac/net/ipv6/datagram.c --- linux.vanilla/net/ipv6/datagram.c Wed Nov 29 05:53:45 2000 +++ linux.ac/net/ipv6/datagram.c Sat Apr 14 01:50:35 2001 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: datagram.c,v 1.21 2000/11/28 13:42:08 davem Exp $ + * $Id: datagram.c,v 1.22 2000/12/13 18:31:50 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -57,7 +57,7 @@ serr->port = port; skb->h.raw = payload; - skb_pull(skb, payload - skb->data); + __skb_pull(skb, payload - skb->data); if (sock_queue_err_skb(sk, skb)) kfree_skb(skb); @@ -92,7 +92,7 @@ serr->port = fl->uli_u.ports.dport; skb->h.raw = skb->tail; - skb_pull(skb, skb->tail - skb->data); + __skb_pull(skb, skb->tail - skb->data); if (sock_queue_err_skb(sk, skb)) kfree_skb(skb); @@ -123,7 +123,7 @@ msg->msg_flags |= MSG_TRUNC; copied = len; } - err = memcpy_toiovec(msg->msg_iov, skb->data, copied); + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (err) goto out_free_skb; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv6/exthdrs.c linux.ac/net/ipv6/exthdrs.c --- linux.vanilla/net/ipv6/exthdrs.c Sun Jan 9 05:36:21 2000 +++ linux.ac/net/ipv6/exthdrs.c Sat Apr 14 01:50:35 2001 @@ -7,7 +7,7 @@ * Andi Kleen <ak@muc.de> * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> * - * $Id: exthdrs.c,v 1.10 2000/01/09 02:19:55 davem Exp $ + * $Id: exthdrs.c,v 1.12 2001/01/22 02:36:37 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -15,6 +15,11 @@ * 2 of the License, or (at your option) any later version. */ +/* Changes: + * yoshfuji : ensure not to overrun while parsing + * tlv options. + */ + #include <linux/errno.h> #include <linux/types.h> #include <linux/socket.h> @@ -41,15 +46,15 @@ /* * Parsing inbound headers. * - * Parsing function "func" returns pointer to the place, + * Parsing function "func" returns offset wrt skb->nh of the place, * where next nexthdr value is stored or NULL, if parsing - * failed. It should also update skb->h. + * failed. It should also update skb->h tp point at the next header. */ struct hdrtype_proc { int type; - u8* (*func) (struct sk_buff **, u8 *ptr); + int (*func) (struct sk_buff **, int offset); }; /* @@ -63,7 +68,7 @@ struct tlvtype_proc { int type; - int (*func) (struct sk_buff *, __u8 *ptr); + int (*func) (struct sk_buff *, int offset); }; /********************* @@ -72,12 +77,12 @@ /* An unknown option is detected, decide what to do */ -int ip6_tlvopt_unknown(struct sk_buff *skb, u8 *opt) +int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff) { - switch ((opt[0] & 0xC0) >> 6) { + switch ((skb->nh.raw[optoff] & 0xC0) >> 6) { case 0: /* ignore */ return 1; - + case 1: /* drop packet */ break; @@ -88,7 +93,7 @@ if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr)) break; case 2: /* send ICMP PARM PROB regardless and drop packet */ - icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, opt); + icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff); return 0; }; @@ -98,24 +103,21 @@ /* Parse tlv encoded option header (hop-by-hop or destination) */ -static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb, - __u8 *nhptr) +static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb) { struct tlvtype_proc *curr; - u8 *ptr = skb->h.raw; - int len = ((ptr[1]+1)<<3) - 2; + int off = skb->h.raw - skb->nh.raw; + int len = ((skb->h.raw[1]+1)<<3); - ptr += 2; + if ((skb->h.raw + len) - skb->data > skb_headlen(skb)) + goto bad; - if (skb->tail - (ptr + len) < 0) { - kfree_skb(skb); - return 0; - } + len -= 2; while (len > 0) { - int optlen = ptr[1]+2; + int optlen = skb->nh.raw[off+1]+2; - switch (ptr[0]) { + switch (skb->nh.raw[off]) { case IPV6_TLV_PAD0: optlen = 1; break; @@ -124,24 +126,30 @@ break; default: /* Other TLV code so scan list */ + if (optlen > len) + goto bad; for (curr=procs; curr->type >= 0; curr++) { - if (curr->type == ptr[0]) { - if (curr->func(skb, ptr) == 0) + if (curr->type == skb->nh.raw[off]) { + /* type specific length/alignment + checks will be perfomed in the + func(). */ + if (curr->func(skb, off) == 0) return 0; break; } } if (curr->type < 0) { - if (ip6_tlvopt_unknown(skb, ptr) == 0) + if (ip6_tlvopt_unknown(skb, off) == 0) return 0; } break; } - ptr += optlen; + off += optlen; len -= optlen; } if (len == 0) return 1; +bad: kfree_skb(skb); return 0; } @@ -155,37 +163,42 @@ {-1, NULL} }; -static u8 *ipv6_dest_opt(struct sk_buff **skb_ptr, u8 *nhptr) +static int ipv6_dest_opt(struct sk_buff **skb_ptr, int nhoff) { struct sk_buff *skb=*skb_ptr; struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb; - struct ipv6_destopt_hdr *hdr = (struct ipv6_destopt_hdr *) skb->h.raw; - opt->dst1 = (u8*)hdr - skb->nh.raw; + if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) || + !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) { + kfree_skb(skb); + return -1; + } + + opt->dst1 = skb->h.raw - skb->nh.raw; - if (ip6_parse_tlv(tlvprocdestopt_lst, skb, nhptr)) { - skb->h.raw += ((hdr->hdrlen+1)<<3); - return &hdr->nexthdr; + if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) { + skb->h.raw += ((skb->h.raw[1]+1)<<3); + return opt->dst1; } - return NULL; + return -1; } /******************************** NONE header. No data in packet. ********************************/ -static u8 *ipv6_nodata(struct sk_buff **skb_ptr, u8 *nhptr) +static int ipv6_nodata(struct sk_buff **skb_ptr, int nhoff) { kfree_skb(*skb_ptr); - return NULL; + return -1; } /******************************** Routing header. ********************************/ -static u8* ipv6_routing_header(struct sk_buff **skb_ptr, u8 *nhptr) +static int ipv6_routing_header(struct sk_buff **skb_ptr, int nhoff) { struct sk_buff *skb = *skb_ptr; struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb; @@ -194,36 +207,38 @@ int addr_type; int n, i; - struct ipv6_rt_hdr *hdr = (struct ipv6_rt_hdr *) skb->h.raw; + struct ipv6_rt_hdr *hdr; struct rt0_hdr *rthdr; - if (((hdr->hdrlen+1)<<3) > skb->tail - skb->h.raw) { + if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) || + !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) { IP6_INC_STATS_BH(Ip6InHdrErrors); kfree_skb(skb); - return NULL; + return -1; + } + + hdr = (struct ipv6_rt_hdr *) skb->h.raw; + + if ((ipv6_addr_type(&skb->nh.ipv6h->daddr)&IPV6_ADDR_MULTICAST) || + skb->pkt_type != PACKET_HOST) { + kfree_skb(skb); + return -1; } looped_back: if (hdr->segments_left == 0) { - opt->srcrt = (u8*)hdr - skb->nh.raw; + opt->srcrt = skb->h.raw - skb->nh.raw; skb->h.raw += (hdr->hdrlen + 1) << 3; opt->dst0 = opt->dst1; opt->dst1 = 0; - return &hdr->nexthdr; + return (&hdr->nexthdr) - skb->nh.raw; } - if (hdr->type != IPV6_SRCRT_TYPE_0 || hdr->hdrlen & 0x01) { - u8 *pos = (u8*) hdr; - - if (hdr->type != IPV6_SRCRT_TYPE_0) - pos += 2; - else - pos += 1; - - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, pos); - return NULL; + if (hdr->type != IPV6_SRCRT_TYPE_0 || (hdr->hdrlen & 0x01)) { + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, hdr->type != IPV6_SRCRT_TYPE_0 ? 2 : 1); + return -1; } - + /* * This is the routing header forwarding algorithm from * RFC 1883, page 17. @@ -232,8 +247,8 @@ n = hdr->hdrlen >> 1; if (hdr->segments_left > n) { - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, &hdr->segments_left); - return NULL; + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw); + return -1; } /* We are about to mangle packet header. Be careful! @@ -243,12 +258,15 @@ struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC); kfree_skb(skb); if (skb2 == NULL) - return NULL; + return -1; *skb_ptr = skb = skb2; opt = (struct inet6_skb_parm *)skb2->cb; hdr = (struct ipv6_rt_hdr *) skb2->h.raw; } + if (skb->ip_summed == CHECKSUM_HW) + skb->ip_summed = CHECKSUM_NONE; + i = n - --hdr->segments_left; rthdr = (struct rt0_hdr *) hdr; @@ -257,9 +275,9 @@ addr_type = ipv6_addr_type(addr); - if (addr_type == IPV6_ADDR_MULTICAST) { + if (addr_type&IPV6_ADDR_MULTICAST) { kfree_skb(skb); - return NULL; + return -1; } ipv6_addr_copy(&daddr, addr); @@ -270,21 +288,21 @@ ip6_route_input(skb); if (skb->dst->error) { skb->dst->input(skb); - return NULL; + return -1; } if (skb->dst->dev->flags&IFF_LOOPBACK) { if (skb->nh.ipv6h->hop_limit <= 1) { icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0, skb->dev); kfree_skb(skb); - return NULL; + return -1; } skb->nh.ipv6h->hop_limit--; goto looped_back; } skb->dst->input(skb); - return NULL; + return -1; } /* @@ -374,20 +392,30 @@ and opt->hdrlen is even. Shit! --ANK (980730) */ -static u8 *ipv6_auth_hdr(struct sk_buff **skb_ptr, u8 *nhptr) +static int ipv6_auth_hdr(struct sk_buff **skb_ptr, int nhoff) { struct sk_buff *skb=*skb_ptr; struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb; - struct ipv6_opt_hdr *hdr = (struct ipv6_opt_hdr *)skb->h.raw; - int len = (hdr->hdrlen+2)<<2; + int len; + + if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8)) + goto fail; + + len = (skb->h.raw[1]+1)<<2; if (len&7) - return NULL; - opt->auth = (u8*)hdr - skb->nh.raw; - if (skb->h.raw + len > skb->tail) - return NULL; + goto fail; + + if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+len)) + goto fail; + + opt->auth = skb->h.raw - skb->nh.raw; skb->h.raw += len; - return &hdr->nexthdr; + return opt->auth; + +fail: + kfree_skb(skb); + return -1; } /* This list MUST NOT contain entry for NEXTHDR_HOP. @@ -408,22 +436,22 @@ {-1, NULL} }; -u8 *ipv6_parse_exthdrs(struct sk_buff **skb_in, u8 *nhptr) +int ipv6_parse_exthdrs(struct sk_buff **skb_in, int nhoff) { struct hdrtype_proc *hdrt; - u8 nexthdr = *nhptr; + u8 nexthdr = (*skb_in)->nh.raw[nhoff]; restart: for (hdrt=hdrproc_lst; hdrt->type >= 0; hdrt++) { if (hdrt->type == nexthdr) { - if ((nhptr = hdrt->func(skb_in, nhptr)) != NULL) { - nexthdr = *nhptr; + if ((nhoff = hdrt->func(skb_in, nhoff)) >= 0) { + nexthdr = (*skb_in)->nh.raw[nhoff]; goto restart; } - return NULL; + return -1; } } - return nhptr; + return nhoff; } @@ -433,37 +461,37 @@ /* Router Alert as of draft-ietf-ipngwg-ipv6router-alert-04 */ -static int ipv6_hop_ra(struct sk_buff *skb, u8 *ptr) +static int ipv6_hop_ra(struct sk_buff *skb, int optoff) { - if (ptr[1] == 2) { - ((struct inet6_skb_parm*)skb->cb)->ra = ptr - skb->nh.raw; + if (skb->nh.raw[optoff+1] == 2) { + ((struct inet6_skb_parm*)skb->cb)->ra = optoff; return 1; } if (net_ratelimit()) - printk(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n", ptr[1]); + printk(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n", skb->nh.raw[optoff+1]); kfree_skb(skb); return 0; } /* Jumbo payload */ -static int ipv6_hop_jumbo(struct sk_buff *skb, u8 *ptr) +static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff) { u32 pkt_len; - if (ptr[1] != 4 || ((ptr-skb->nh.raw)&3) != 2) { + if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) { if (net_ratelimit()) - printk(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", ptr[1]); + printk(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", skb->nh.raw[optoff+1]); goto drop; } - pkt_len = ntohl(*(u32*)(ptr+2)); + pkt_len = ntohl(*(u32*)(skb->nh.raw+optoff+2)); if (pkt_len < 0x10000) { - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, ptr+2); + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2); return 0; } if (skb->nh.ipv6h->payload_len) { - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, ptr); + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff); return 0; } @@ -471,7 +499,11 @@ IP6_INC_STATS_BH(Ip6InTruncatedPkts); goto drop; } - skb_trim(skb, pkt_len + sizeof(struct ipv6hdr)); + if (pkt_len + sizeof(struct ipv6hdr) < skb->len) { + __pskb_trim(skb, pkt_len + sizeof(struct ipv6hdr)); + if (skb->ip_summed == CHECKSUM_HW) + skb->ip_summed = CHECKSUM_NONE; + } return 1; drop: @@ -485,12 +517,12 @@ {-1, NULL} }; -u8 * ipv6_parse_hopopts(struct sk_buff *skb, u8 *nhptr) +int ipv6_parse_hopopts(struct sk_buff *skb, int nhoff) { ((struct inet6_skb_parm*)skb->cb)->hop = sizeof(struct ipv6hdr); - if (ip6_parse_tlv(tlvprochopopt_lst, skb, nhptr)) - return nhptr+((nhptr[1]+1)<<3); - return NULL; + if (ip6_parse_tlv(tlvprochopopt_lst, skb)) + return sizeof(struct ipv6hdr); + return -1; } /* @@ -684,7 +716,7 @@ * find out if nexthdr is a well-known extension header or a protocol */ -static __inline__ int ipv6_ext_hdr(u8 nexthdr) +int ipv6_ext_hdr(u8 nexthdr) { /* * find out if nexthdr is an extension header or a protocol @@ -739,33 +771,36 @@ * --ANK (980726) */ -u8 *ipv6_skip_exthdr(struct ipv6_opt_hdr *hdr, u8 *nexthdrp, int len) +int ipv6_skip_exthdr(struct sk_buff *skb, int start, u8 *nexthdrp, int len) { u8 nexthdr = *nexthdrp; while (ipv6_ext_hdr(nexthdr)) { - int hdrlen; + struct ipv6_opt_hdr hdr; + int hdrlen; - if (len < sizeof(struct ipv6_opt_hdr)) - return NULL; + if (len < (int)sizeof(struct ipv6_opt_hdr)) + return -1; if (nexthdr == NEXTHDR_NONE) - return NULL; + return -1; + if (skb_copy_bits(skb, start, &hdr, sizeof(hdr))) + BUG(); if (nexthdr == NEXTHDR_FRAGMENT) { - struct frag_hdr *fhdr = (struct frag_hdr *) hdr; + struct frag_hdr *fhdr = (struct frag_hdr *) &hdr; if (ntohs(fhdr->frag_off) & ~0x7) break; hdrlen = 8; } else if (nexthdr == NEXTHDR_AUTH) - hdrlen = (hdr->hdrlen+2)<<2; + hdrlen = (hdr.hdrlen+2)<<2; else - hdrlen = ipv6_optlen(hdr); + hdrlen = ipv6_optlen(&hdr); - nexthdr = hdr->nexthdr; - hdr = (struct ipv6_opt_hdr *) ((u8*)hdr + hdrlen); + nexthdr = hdr.nexthdr; len -= hdrlen; + start += hdrlen; } *nexthdrp = nexthdr; - return (u8*)hdr; + return start; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv6/icmp.c linux.ac/net/ipv6/icmp.c --- linux.vanilla/net/ipv6/icmp.c Mon Jan 1 19:01:58 2001 +++ linux.ac/net/ipv6/icmp.c Sat Apr 14 01:50:35 2001 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: icmp.c,v 1.28 2000/03/25 01:55:20 davem Exp $ + * $Id: icmp.c,v 1.31 2001/01/22 02:36:37 davem Exp $ * * Based on net/ipv4/icmp.c * @@ -23,6 +23,8 @@ * Andi Kleen : exception handling * Andi Kleen add rate limits. never reply to a icmp. * add more length checks and other fixes. + * yoshfuji : ensure to sent parameter problem for + * fragments. */ #define __NO_VERSION__ @@ -66,7 +68,7 @@ struct socket *icmpv6_socket; -int icmpv6_rcv(struct sk_buff *skb, unsigned long len); +int icmpv6_rcv(struct sk_buff *skb); static struct inet6_protocol icmpv6_protocol = { @@ -81,7 +83,8 @@ struct icmpv6_msg { struct icmp6hdr icmph; - __u8 *data; + struct sk_buff *skb; + int offset; struct in6_addr *daddr; int len; __u32 csum; @@ -136,19 +139,10 @@ struct icmp6hdr *icmph; __u32 csum; - /* - * in theory offset must be 0 since we never send more - * than IPV6_MIN_MTU bytes on an error or more than the path mtu - * on an echo reply. (those are the rules on RFC 1883) - * - * Luckily, this statement is obsolete after - * draft-ietf-ipngwg-icmp-v2-00 --ANK (980730) - */ - if (offset) { - csum = csum_partial_copy_nocheck((void *) msg->data + - offset - sizeof(struct icmp6hdr), - buff, len, msg->csum); + csum = skb_copy_and_csum_bits(msg->skb, msg->offset + + (offset - sizeof(struct icmp6hdr)), + buff, len, msg->csum); msg->csum = csum; return 0; } @@ -156,9 +150,9 @@ csum = csum_partial_copy_nocheck((void *) &msg->icmph, buff, sizeof(struct icmp6hdr), msg->csum); - csum = csum_partial_copy_nocheck((void *) msg->data, - buff + sizeof(struct icmp6hdr), - len - sizeof(struct icmp6hdr), csum); + csum = skb_copy_and_csum_bits(msg->skb, msg->offset, + buff + sizeof(struct icmp6hdr), + len - sizeof(struct icmp6hdr), csum); icmph = (struct icmp6hdr *) buff; @@ -171,11 +165,9 @@ /* * Slightly more convenient version of icmpv6_send. */ -void icmpv6_param_prob(struct sk_buff *skb, int code, void *pos) +void icmpv6_param_prob(struct sk_buff *skb, int code, int pos) { - int offset = (u8*)pos - (u8*)skb->nh.ipv6h; - - icmpv6_send(skb, ICMPV6_PARAMPROB, code, offset, skb->dev); + icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev); kfree_skb(skb); } @@ -186,29 +178,30 @@ * - it was icmp error message. * - it is truncated, so that it is known, that protocol is ICMPV6 * (i.e. in the middle of some exthdr) - * - it is not the first fragment. BTW IPv6 specs say nothing about - * this case, but it is clear, that our reply would be useless - * for sender. * * --ANK (980726) */ -static int is_ineligible(struct ipv6hdr *hdr, int len) +static int is_ineligible(struct sk_buff *skb) { - u8 *ptr; - __u8 nexthdr = hdr->nexthdr; + int ptr = (u8*)(skb->nh.ipv6h+1) - skb->data; + int len = skb->len - ptr; + __u8 nexthdr = skb->nh.ipv6h->nexthdr; - if (len < (int)sizeof(*hdr)) + if (len < 0) return 1; - ptr = ipv6_skip_exthdr((struct ipv6_opt_hdr *)(hdr+1), &nexthdr, len - sizeof(*hdr)); - if (!ptr) + ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, len); + if (ptr < 0) return 0; if (nexthdr == IPPROTO_ICMPV6) { - struct icmp6hdr *ihdr = (struct icmp6hdr *)ptr; - return (ptr - (u8*)hdr) > len || !(ihdr->icmp6_type & 0x80); + u8 type; + if (skb_copy_bits(skb, ptr+offsetof(struct icmp6hdr, icmp6_type), + &type, 1) + || !(type & 0x80)) + return 1; } - return nexthdr == NEXTHDR_FRAGMENT; + return 0; } int sysctl_icmpv6_time = 1*HZ; @@ -263,9 +256,12 @@ static __inline__ int opt_unrec(struct sk_buff *skb, __u32 offset) { - u8 *buff = skb->nh.raw; + u8 optval; - return ( ( *(buff + offset) & 0xC0 ) == 0x80 ); + offset += skb->nh.raw - skb->data; + if (skb_copy_bits(skb, offset, &optval, 1)) + return 1; + return (optval&0xC0) == 0x80; } /* @@ -284,15 +280,8 @@ int addr_type = 0; int len; - /* - * sanity check pointer in case of parameter problem - */ - - if (type == ICMPV6_PARAMPROB && - (info > (skb->tail - ((unsigned char *) hdr)))) { - printk(KERN_DEBUG "icmpv6_send: bug! pointer > skb\n"); + if ((u8*)hdr < skb->head || (u8*)(hdr+1) > skb->tail) return; - } /* * Make sure we respect the rules @@ -300,7 +289,6 @@ * Rule (e.1) is enforced by not using icmpv6_send * in any code that processes icmp errors. */ - addr_type = ipv6_addr_type(&hdr->daddr); if (ipv6_chk_addr(&hdr->daddr, skb->dev)) @@ -341,9 +329,9 @@ /* * Never answer to a ICMP packet. */ - if (is_ineligible(hdr, (u8*)skb->tail - (u8*)hdr)) { + if (is_ineligible(skb)) { if (net_ratelimit()) - printk(KERN_DEBUG "icmpv6_send: no reply to icmp error/fragment\n"); + printk(KERN_DEBUG "icmpv6_send: no reply to icmp error\n"); return; } @@ -371,12 +359,13 @@ msg.icmph.icmp6_cksum = 0; msg.icmph.icmp6_pointer = htonl(info); - msg.data = skb->nh.raw; + msg.skb = skb; + msg.offset = skb->nh.raw - skb->data; msg.csum = 0; msg.daddr = &hdr->saddr; - len = min((skb->tail - ((unsigned char *) hdr)) + sizeof(struct icmp6hdr), - IPV6_MIN_MTU - sizeof(struct ipv6hdr)); + len = skb->len - msg.offset + sizeof(struct icmp6hdr); + len = min(len, IPV6_MIN_MTU - sizeof(struct ipv6hdr)); if (len < 0) { printk(KERN_DEBUG "icmp: len problem\n"); @@ -397,37 +386,30 @@ static void icmpv6_echo_reply(struct sk_buff *skb) { struct sock *sk = icmpv6_socket->sk; - struct ipv6hdr *hdr = skb->nh.ipv6h; struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw; struct in6_addr *saddr; struct icmpv6_msg msg; struct flowi fl; - unsigned char *data; - int len; - - data = (char *) (icmph + 1); - saddr = &hdr->daddr; + saddr = &skb->nh.ipv6h->daddr; if (ipv6_addr_type(saddr) & IPV6_ADDR_MULTICAST) saddr = NULL; - len = skb->tail - data; - len += sizeof(struct icmp6hdr); - msg.icmph.icmp6_type = ICMPV6_ECHO_REPLY; msg.icmph.icmp6_code = 0; msg.icmph.icmp6_cksum = 0; msg.icmph.icmp6_identifier = icmph->icmp6_identifier; msg.icmph.icmp6_sequence = icmph->icmp6_sequence; - msg.data = data; + msg.skb = skb; + msg.offset = 0; msg.csum = 0; - msg.len = len; - msg.daddr = &hdr->saddr; + msg.len = skb->len + sizeof(struct icmp6hdr); + msg.daddr = &skb->nh.ipv6h->saddr; fl.proto = IPPROTO_ICMPV6; - fl.nl_u.ip6_u.daddr = &hdr->saddr; + fl.nl_u.ip6_u.daddr = msg.daddr; fl.nl_u.ip6_u.saddr = saddr; fl.oif = skb->dev->ifindex; fl.fl6_flowlabel = 0; @@ -437,7 +419,7 @@ if (icmpv6_xmit_lock_bh()) return; - ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1, + ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, msg.len, NULL, -1, MSG_DONTWAIT); ICMP6_INC_STATS_BH(Icmp6OutEchoReplies); ICMP6_INC_STATS_BH(Icmp6OutMsgs); @@ -445,29 +427,35 @@ icmpv6_xmit_unlock_bh(); } -static void icmpv6_notify(struct sk_buff *skb, - int type, int code, u32 info, unsigned char *buff, int len) +static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info) { - struct in6_addr *saddr = &skb->nh.ipv6h->saddr; - struct in6_addr *daddr = &skb->nh.ipv6h->daddr; - struct ipv6hdr *hdr = (struct ipv6hdr *) buff; + struct in6_addr *saddr, *daddr; struct inet6_protocol *ipprot; struct sock *sk; - u8 *pb; + int inner_offset; int hash; u8 nexthdr; - nexthdr = hdr->nexthdr; - - len -= sizeof(struct ipv6hdr); - if (len < 0) + if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) return; - /* now skip over extension headers */ - pb = ipv6_skip_exthdr((struct ipv6_opt_hdr *) (hdr + 1), &nexthdr, len); - if (!pb) + nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr; + if (ipv6_ext_hdr(nexthdr)) { + /* now skip over extension headers */ + inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, skb->len - sizeof(struct ipv6hdr)); + if (inner_offset<0) + return; + } else { + inner_offset = sizeof(struct ipv6hdr); + } + + /* Checkin header including 8 bytes of inner protocol header. */ + if (!pskb_may_pull(skb, inner_offset+8)) return; + saddr = &skb->nh.ipv6h->saddr; + daddr = &skb->nh.ipv6h->daddr; + /* BUGGG_FUTURE: we should try to parse exthdrs in this packet. Without this we will not able f.e. to make source routed pmtu discovery. @@ -484,13 +472,13 @@ continue; if (ipprot->err_handler) - ipprot->err_handler(skb, hdr, NULL, type, code, pb, info); + ipprot->err_handler(skb, NULL, type, code, inner_offset, info); } read_lock(&raw_v6_lock); if ((sk = raw_v6_htable[hash]) != NULL) { while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr))) { - rawv6_err(sk, skb, hdr, NULL, type, code, pb, info); + rawv6_err(sk, skb, NULL, type, code, inner_offset, info); sk = sk->next; } } @@ -501,28 +489,31 @@ * Handle icmp messages */ -int icmpv6_rcv(struct sk_buff *skb, unsigned long len) +int icmpv6_rcv(struct sk_buff *skb) { struct net_device *dev = skb->dev; - struct in6_addr *saddr = &skb->nh.ipv6h->saddr; - struct in6_addr *daddr = &skb->nh.ipv6h->daddr; + struct in6_addr *saddr, *daddr; struct ipv6hdr *orig_hdr; - struct icmp6hdr *hdr = (struct icmp6hdr *) skb->h.raw; - int ulen; + struct icmp6hdr *hdr; int type; ICMP6_INC_STATS_BH(Icmp6InMsgs); - if (len < sizeof(struct icmp6hdr)) - goto discard_it; + saddr = &skb->nh.ipv6h->saddr; + daddr = &skb->nh.ipv6h->daddr; /* Perform checksum. */ - switch (skb->ip_summed) { - case CHECKSUM_NONE: - skb->csum = csum_partial((char *)hdr, len, 0); - case CHECKSUM_HW: - if (csum_ipv6_magic(saddr, daddr, len, IPPROTO_ICMPV6, + if (skb->ip_summed == CHECKSUM_HW) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, skb->csum)) { + printk(KERN_DEBUG "ICMPv6 hw checksum failed\n"); + skb->ip_summed = CHECKSUM_NONE; + } + } + if (skb->ip_summed == CHECKSUM_NONE) { + if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, + skb_checksum(skb, 0, skb->len, 0))) { printk(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n", ntohs(saddr->in6_u.u6_addr16[0]), ntohs(saddr->in6_u.u6_addr16[1]), @@ -542,14 +533,12 @@ ntohs(daddr->in6_u.u6_addr16[7])); goto discard_it; } - default:; - /* CHECKSUM_UNNECESSARY */ - }; + } - /* - * length of original packet carried in skb - */ - ulen = skb->tail - (unsigned char *) (hdr + 1); + if (!pskb_pull(skb, sizeof(struct icmp6hdr))) + goto discard_it; + + hdr = (struct icmp6hdr *) skb->h.raw; type = hdr->icmp6_type; @@ -559,7 +548,6 @@ (&icmpv6_statistics[smp_processor_id()*2].Icmp6InEchos)[type-ICMPV6_ECHO_REQUEST]++; switch (type) { - case ICMPV6_ECHO_REQUEST: icmpv6_echo_reply(skb); break; @@ -574,10 +562,12 @@ destination cache will allow to solve this problem --ANK (980726) */ + if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) + goto discard_it; + hdr = (struct icmp6hdr *) skb->data; orig_hdr = (struct ipv6hdr *) (hdr + 1); - if (ulen >= sizeof(struct ipv6hdr)) - rt6_pmtu_discovery(&orig_hdr->daddr, &orig_hdr->saddr, dev, - ntohl(hdr->icmp6_mtu)); + rt6_pmtu_discovery(&orig_hdr->daddr, &orig_hdr->saddr, dev, + ntohl(hdr->icmp6_mtu)); /* * Drop through to notify @@ -586,8 +576,7 @@ case ICMPV6_DEST_UNREACH: case ICMPV6_TIME_EXCEED: case ICMPV6_PARAMPROB: - icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu, - (char *) (hdr + 1), ulen); + icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu); break; case NDISC_ROUTER_SOLICITATION: @@ -595,15 +584,21 @@ case NDISC_NEIGHBOUR_SOLICITATION: case NDISC_NEIGHBOUR_ADVERTISEMENT: case NDISC_REDIRECT: - ndisc_rcv(skb, len); + if (skb_is_nonlinear(skb) && + skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + return 0; + } + + ndisc_rcv(skb); break; case ICMPV6_MGM_QUERY: - igmp6_event_query(skb, hdr, len); + igmp6_event_query(skb); break; case ICMPV6_MGM_REPORT: - igmp6_event_report(skb, hdr, len); + igmp6_event_report(skb); break; case ICMPV6_MGM_REDUCTION: @@ -612,7 +607,7 @@ default: if (net_ratelimit()) printk(KERN_DEBUG "icmpv6: msg of unkown type\n"); - + /* informational */ if (type & 0x80) break; @@ -622,8 +617,7 @@ * must pass to upper level */ - icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu, - (char *) (hdr + 1), ulen); + icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu); }; kfree_skb(skb); return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv6/ip6_input.c linux.ac/net/ipv6/ip6_input.c --- linux.vanilla/net/ipv6/ip6_input.c Mon Dec 11 20:37:04 2000 +++ linux.ac/net/ipv6/ip6_input.c Sat Apr 14 01:50:36 2001 @@ -6,7 +6,7 @@ * Pedro Roque <roque@di.fc.ul.pt> * Ian P. Morris <I.P.Morris@soton.ac.uk> * - * $Id: ip6_input.c,v 1.18 2000/12/08 17:15:54 davem Exp $ + * $Id: ip6_input.c,v 1.19 2000/12/13 18:31:50 davem Exp $ * * Based in linux/net/ipv4/ip_input.c * @@ -44,7 +44,6 @@ static inline int ip6_rcv_finish( struct sk_buff *skb) { - if (skb->dst == NULL) ip6_route_input(skb); @@ -69,9 +68,15 @@ */ ((struct inet6_skb_parm *)skb->cb)->iif = dev->ifindex; + if (skb->len < sizeof(struct ipv6hdr)) + goto err; + + if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) + goto drop; + hdr = skb->nh.ipv6h; - if (skb->len < sizeof(struct ipv6hdr) || hdr->version != 6) + if (hdr->version != 6) goto err; pkt_len = ntohs(hdr->payload_len); @@ -80,16 +85,24 @@ if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) { if (pkt_len + sizeof(struct ipv6hdr) > skb->len) goto truncated; - skb_trim(skb, pkt_len + sizeof(struct ipv6hdr)); + if (pkt_len + sizeof(struct ipv6hdr) < skb->len) { + if (__pskb_trim(skb, pkt_len + sizeof(struct ipv6hdr))) + goto drop; + hdr = skb->nh.ipv6h; + if (skb->ip_summed == CHECKSUM_HW) + skb->ip_summed = CHECKSUM_NONE; + } } if (hdr->nexthdr == NEXTHDR_HOP) { skb->h.raw = (u8*)(hdr+1); - if (!ipv6_parse_hopopts(skb, &hdr->nexthdr)) { + if (ipv6_parse_hopopts(skb, offsetof(struct ipv6hdr, nexthdr)) < 0) { IP6_INC_STATS_BH(Ip6InHdrErrors); return 0; } + hdr = skb->nh.ipv6h; } + return NF_HOOK(PF_INET6,NF_IP6_PRE_ROUTING, skb, dev, NULL, ip6_rcv_finish); truncated: IP6_INC_STATS_BH(Ip6InTruncatedPkts); @@ -111,12 +124,11 @@ struct ipv6hdr *hdr = skb->nh.ipv6h; struct inet6_protocol *ipprot; struct sock *raw_sk; - __u8 *nhptr; + int nhoff; int nexthdr; int found = 0; u8 hash; - int len; - + skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr); /* @@ -124,13 +136,13 @@ */ nexthdr = hdr->nexthdr; - nhptr = &hdr->nexthdr; + nhoff = offsetof(struct ipv6hdr, nexthdr); /* Skip hop-by-hop options, they are already parsed. */ if (nexthdr == NEXTHDR_HOP) { - nhptr = (u8*)(hdr+1); - nexthdr = *nhptr; - skb->h.raw += (nhptr[1]+1)<<3; + nhoff = sizeof(struct ipv6hdr); + nexthdr = skb->h.raw[0]; + skb->h.raw += (skb->h.raw[1]+1)<<3; } /* This check is sort of optimization. @@ -138,17 +150,23 @@ which are missing with probability of 200% */ if (nexthdr != IPPROTO_TCP && nexthdr != IPPROTO_UDP) { - nhptr = ipv6_parse_exthdrs(&skb, nhptr); - if (nhptr == NULL) + nhoff = ipv6_parse_exthdrs(&skb, nhoff); + if (nhoff < 0) return 0; - nexthdr = *nhptr; + nexthdr = skb->nh.raw[nhoff]; hdr = skb->nh.ipv6h; } - len = skb->tail - skb->h.raw; + + if (!pskb_pull(skb, skb->h.raw - skb->data)) + goto discard; + + if (skb->ip_summed == CHECKSUM_HW) + skb->csum = csum_sub(skb->csum, + csum_partial(skb->nh.raw, skb->h.raw-skb->nh.raw, 0)); raw_sk = raw_v6_htable[nexthdr&(MAX_INET_PROTOS-1)]; if (raw_sk) - raw_sk = ipv6_raw_deliver(skb, nexthdr, len); + raw_sk = ipv6_raw_deliver(skb, nexthdr); hash = nexthdr & (MAX_INET_PROTOS - 1); for (ipprot = (struct inet6_protocol *) inet6_protos[hash]; @@ -163,12 +181,12 @@ buff = skb_clone(skb, GFP_ATOMIC); if (buff) - ipprot->handler(buff, len); + ipprot->handler(buff); found = 1; } if (raw_sk) { - rawv6_rcv(raw_sk, skb, len); + rawv6_rcv(raw_sk, skb); sock_put(raw_sk); found = 1; } @@ -178,9 +196,13 @@ */ if (!found) { IP6_INC_STATS_BH(Ip6InUnknownProtos); - icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhptr); + icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhoff); } + return 0; + +discard: + kfree_skb(skb); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv6/ip6_output.c linux.ac/net/ipv6/ip6_output.c --- linux.vanilla/net/ipv6/ip6_output.c Thu Jun 22 15:23:26 2000 +++ linux.ac/net/ipv6/ip6_output.c Sat Apr 14 01:50:36 2001 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: ip6_output.c,v 1.27 2000/06/21 17:18:40 davem Exp $ + * $Id: ip6_output.c,v 1.30 2001/03/03 01:20:10 davem Exp $ * * Based on linux/net/ipv4/ip_output.c * @@ -85,7 +85,7 @@ static int ip6_dev_loopback_xmit(struct sk_buff *newskb) { newskb->mac.raw = newskb->data; - skb_pull(newskb, newskb->nh.raw - newskb->data); + __skb_pull(newskb, newskb->nh.raw - newskb->data); newskb->pkt_type = PACKET_LOOPBACK; newskb->ip_summed = CHECKSUM_UNNECESSARY; BUG_TRAP(newskb->dst); @@ -113,7 +113,7 @@ is not supported in any case. */ if (newskb) - NF_HOOK(PF_INET, NF_IP6_POST_ROUTING, newskb, NULL, + NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, newskb, NULL, newskb->dev, ip6_dev_loopback_xmit); @@ -405,7 +405,7 @@ last_skb = sock_alloc_send_skb(sk, unfrag_len + frag_len + dst->dev->hard_header_len + 15, - 0, flags & MSG_DONTWAIT, &err); + flags & MSG_DONTWAIT, &err); if (last_skb == NULL) return err; @@ -624,7 +624,7 @@ goto out; skb = sock_alloc_send_skb(sk, pktlength + 15 + - dev->hard_header_len, 0, + dev->hard_header_len, flags & MSG_DONTWAIT, &err); if (skb == NULL) { @@ -697,14 +697,14 @@ if (last) { struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2) - rawv6_rcv(last, skb2, skb2->len); + rawv6_rcv(last, skb2); } last = sk; } } if (last) { - rawv6_rcv(last, skb, skb->len); + rawv6_rcv(last, skb); read_unlock(&ip6_ra_lock); return 1; } @@ -724,7 +724,9 @@ struct inet6_skb_parm *opt =(struct inet6_skb_parm*)skb->cb; if (ipv6_devconf.forwarding == 0 && opt->srcrt == 0) - goto drop; + goto error; + + skb->ip_summed = CHECKSUM_NONE; /* * We DO NOT make any processing on @@ -785,7 +787,7 @@ } else if (ipv6_addr_type(&hdr->saddr)&(IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK |IPV6_ADDR_LINKLOCAL)) { /* This check is security critical. */ - goto drop; + goto error; } if (skb->len > dst->pmtu) { @@ -797,8 +799,8 @@ return -EMSGSIZE; } - if ((skb = skb_cow(skb, dst->dev->hard_header_len)) == NULL) - return 0; + if (skb_cow(skb, dst->dev->hard_header_len)) + goto drop; hdr = skb->nh.ipv6h; @@ -809,8 +811,9 @@ IP6_INC_STATS_BH(Ip6OutForwDatagrams); return NF_HOOK(PF_INET6,NF_IP6_FORWARD, skb, skb->dev, dst->dev, ip6_forward_finish); -drop: +error: IP6_INC_STATS_BH(Ip6InAddrErrors); +drop: kfree_skb(skb); return -EINVAL; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv6/mcast.c linux.ac/net/ipv6/mcast.c --- linux.vanilla/net/ipv6/mcast.c Mon Sep 18 23:04:13 2000 +++ linux.ac/net/ipv6/mcast.c Sat Apr 14 01:50:37 2001 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: mcast.c,v 1.33 2000/09/18 05:59:48 davem Exp $ + * $Id: mcast.c,v 1.36 2001/03/03 01:20:10 davem Exp $ * * Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c * @@ -15,6 +15,11 @@ * 2 of the License, or (at your option) any later version. */ +/* Changes: + * + * yoshfuji : fix format of router-alert option + */ + #define __NO_VERSION__ #include <linux/config.h> #include <linux/module.h> @@ -392,17 +397,19 @@ spin_unlock(&ma->mca_lock); } -int igmp6_event_query(struct sk_buff *skb, struct icmp6hdr *hdr, int len) +int igmp6_event_query(struct sk_buff *skb) { struct ifmcaddr6 *ma; struct in6_addr *addrp; unsigned long resptime; struct inet6_dev *idev; + struct icmp6hdr *hdr; - - if (len < sizeof(struct icmp6hdr) + sizeof(struct in6_addr)) + if (!pskb_may_pull(skb, sizeof(struct in6_addr))) return -EINVAL; + hdr = (struct icmp6hdr*) skb->h.raw; + /* Drop queries with not link local source */ if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL)) return -EINVAL; @@ -437,19 +444,22 @@ } -int igmp6_event_report(struct sk_buff *skb, struct icmp6hdr *hdr, int len) +int igmp6_event_report(struct sk_buff *skb) { struct ifmcaddr6 *ma; struct in6_addr *addrp; struct inet6_dev *idev; + struct icmp6hdr *hdr; /* Our own report looped back. Ignore it. */ if (skb->pkt_type == PACKET_LOOPBACK) return 0; - if (len < sizeof(struct icmp6hdr) + sizeof(struct in6_addr)) + if (!pskb_may_pull(skb, sizeof(struct in6_addr))) return -EINVAL; + hdr = (struct icmp6hdr*) skb->h.raw; + /* Drop reports with not link local source */ if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL)) return -EINVAL; @@ -491,7 +501,7 @@ struct in6_addr all_routers; int err, len, payload_len, full_len; u8 ra[8] = { IPPROTO_ICMPV6, 0, - IPV6_TLV_ROUTERALERT, 0, 0, 0, + IPV6_TLV_ROUTERALERT, 2, 0, 0, IPV6_TLV_PADN, 0 }; snd_addr = addr; @@ -504,7 +514,7 @@ payload_len = len + sizeof(ra); full_len = sizeof(struct ipv6hdr) + payload_len; - skb = sock_alloc_send_skb(sk, dev->hard_header_len + full_len + 15, 0, 0, &err); + skb = sock_alloc_send_skb(sk, dev->hard_header_len + full_len + 15, 0, &err); if (skb == NULL) return; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv6/ndisc.c linux.ac/net/ipv6/ndisc.c --- linux.vanilla/net/ipv6/ndisc.c Wed Nov 29 05:53:45 2000 +++ linux.ac/net/ipv6/ndisc.c Sat Apr 14 01:50:37 2001 @@ -338,7 +338,7 @@ } skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15, - 0, 0, &err); + 0, &err); if (skb == NULL) { ND_PRINTK1("send_na: alloc skb failed\n"); @@ -397,7 +397,7 @@ len += NDISC_OPT_SPACE(dev->addr_len); skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15, - 0, 0, &err); + 0, &err); if (skb == NULL) { ND_PRINTK1("send_ns: alloc skb failed\n"); return; @@ -458,7 +458,7 @@ len += NDISC_OPT_SPACE(dev->addr_len); skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15, - 0, 0, &err); + 0, &err); if (skb == NULL) { ND_PRINTK1("send_ns: alloc skb failed\n"); return; @@ -869,7 +869,7 @@ } buff = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15, - 0, 0, &err); + 0, &err); if (buff == NULL) { ND_PRINTK1("ndisc_send_redirect: alloc_skb failed\n"); return; @@ -957,11 +957,11 @@ static void pndisc_redo(struct sk_buff *skb) { - ndisc_rcv(skb, skb->len); + ndisc_rcv(skb); kfree_skb(skb); } -int ndisc_rcv(struct sk_buff *skb, unsigned long len) +int ndisc_rcv(struct sk_buff *skb) { struct net_device *dev = skb->dev; struct in6_addr *saddr = &skb->nh.ipv6h->saddr; @@ -969,6 +969,8 @@ struct nd_msg *msg = (struct nd_msg *) skb->h.raw; struct neighbour *neigh; struct inet6_ifaddr *ifp; + + __skb_push(skb, skb->data-skb->h.raw); switch (msg->icmph.icmp6_type) { case NDISC_NEIGHBOUR_SOLICITATION: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv6/raw.c linux.ac/net/ipv6/raw.c --- linux.vanilla/net/ipv6/raw.c Fri Feb 9 19:29:44 2001 +++ linux.ac/net/ipv6/raw.c Sat Apr 14 01:50:38 2001 @@ -7,7 +7,7 @@ * * Adapted from linux/net/ipv4/raw.c * - * $Id: raw.c,v 1.42 2000/11/28 13:38:38 davem Exp $ + * $Id: raw.c,v 1.45 2001/02/18 09:10:42 davem Exp $ * * Fixes: * Hideaki YOSHIFUJI : sin6_scope_id support @@ -116,8 +116,11 @@ struct raw6_opt *opt; opt = &sk->tp_pinfo.tp_raw; - icmph = (struct icmp6hdr *) (skb->nh.ipv6h + 1); - return test_bit(icmph->icmp6_type, &opt->filter); + if (pskb_may_pull(skb, sizeof(struct icmp6hdr))) { + icmph = (struct icmp6hdr *) skb->data; + return test_bit(icmph->icmp6_type, &opt->filter); + } + return 0; } /* @@ -125,8 +128,7 @@ * (should consider queueing the skb in the sock receive_queue * without calling rawv6.c) */ -struct sock * ipv6_raw_deliver(struct sk_buff *skb, - int nexthdr, unsigned long len) +struct sock * ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) { struct in6_addr *saddr; struct in6_addr *daddr; @@ -163,7 +165,7 @@ buff = skb_clone(skb, GFP_ATOMIC); if (buff) - rawv6_rcv(sk2, buff, len); + rawv6_rcv(sk2, buff); } } @@ -177,8 +179,6 @@ return sk; } - - /* This cleans up af_inet6 a bit. -DaveM */ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) { @@ -239,16 +239,13 @@ return err; } -void rawv6_err(struct sock *sk, struct sk_buff *skb, struct ipv6hdr *hdr, +void rawv6_err(struct sock *sk, struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, unsigned char *buff, u32 info) + int type, int code, int offset, u32 info) { int err; int harderr; - if (buff > skb->tail) - return; - /* Report error on raw socket, if: 1. User requested recverr. 2. Socket is connected (otherwise the error indication @@ -261,8 +258,12 @@ if (type == ICMPV6_PKT_TOOBIG) harderr = (sk->net_pinfo.af_inet6.pmtudisc == IPV6_PMTUDISC_DO); - if (sk->net_pinfo.af_inet6.recverr) - ipv6_icmp_error(sk, skb, err, 0, ntohl(info), buff); + if (sk->net_pinfo.af_inet6.recverr) { + u8 *payload = skb->data; + if (!sk->protinfo.af_inet.hdrincl) + payload += offset; + ipv6_icmp_error(sk, skb, err, 0, ntohl(info), payload); + } if (sk->net_pinfo.af_inet6.recverr || harderr) { sk->err = err; @@ -290,10 +291,12 @@ * maybe we could have the network decide uppon a hint if it * should call raw_rcv for demultiplexing */ -int rawv6_rcv(struct sock *sk, struct sk_buff *skb, unsigned long len) +int rawv6_rcv(struct sock *sk, struct sk_buff *skb) { - if (sk->protinfo.af_inet.hdrincl) + if (sk->protinfo.af_inet.hdrincl) { + __skb_push(skb, skb->nh.raw - skb->data); skb->h.raw = skb->nh.raw; + } rawv6_rcv_skb(sk, skb); return 0; @@ -325,7 +328,7 @@ if (!skb) goto out; - copied = skb->tail - skb->h.raw; + copied = skb->len; if (copied > len) { copied = len; msg->msg_flags |= MSG_TRUNC; @@ -594,6 +597,8 @@ case ICMPV6_FILTER: if (get_user(len, optlen)) return -EFAULT; + if (len < 0) + return -EINVAL; if (len > sizeof(struct icmp6_filter)) len = sizeof(struct icmp6_filter); if (put_user(len, optlen)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv6/reassembly.c linux.ac/net/ipv6/reassembly.c --- linux.vanilla/net/ipv6/reassembly.c Tue Apr 3 17:32:30 2001 +++ linux.ac/net/ipv6/reassembly.c Sat Apr 14 01:50:38 2001 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: reassembly.c,v 1.22 2000/12/08 17:41:54 davem Exp $ + * $Id: reassembly.c,v 1.26 2001/03/07 22:00:57 davem Exp $ * * Based on: net/ipv4/ip_fragment.c * @@ -79,11 +79,12 @@ int len; int meat; int iif; + struct timeval stamp; + unsigned int csum; __u8 last_in; /* has first/last segment arrived? */ #define COMPLETE 4 #define FIRST_IN 2 #define LAST_IN 1 - __u8 nexthdr; __u16 nhoffset; struct frag_queue **pprev; }; @@ -349,7 +350,7 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, - struct frag_hdr *fhdr, u8 *nhptr) + struct frag_hdr *fhdr, int nhoff) { struct sk_buff *prev, *next; int offset, end; @@ -362,10 +363,14 @@ ((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1))); if ((unsigned int)end >= 65536) { - icmpv6_param_prob(skb,ICMPV6_HDR_FIELD, (u8*)&fhdr->frag_off); - goto err; + icmpv6_param_prob(skb,ICMPV6_HDR_FIELD, (u8*)&fhdr->frag_off - skb->nh.raw); + return; } + if (skb->ip_summed == CHECKSUM_HW) + skb->csum = csum_sub(skb->csum, + csum_partial(skb->nh.raw, (u8*)(fhdr+1)-skb->nh.raw, 0)); + /* Is this the final fragment? */ if (!(fhdr->frag_off & __constant_htons(0x0001))) { /* If we already have some bits beyond end @@ -381,16 +386,12 @@ * Required by the RFC. */ if (end & 0x7) { - printk(KERN_DEBUG "fragment not rounded to 8bytes\n"); - - /* - It is not in specs, but I see no reasons - to send an error in this case. --ANK + /* RFC2460 says always send parameter problem in + * this case. -DaveM */ - if (offset == 0) - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, - &skb->nh.ipv6h->payload_len); - goto err; + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, + offsetof(struct ipv6hdr, payload_len)); + return; } if (end > fq->len) { /* Some bits beyond end -> corruption. */ @@ -404,8 +405,14 @@ goto err; /* Point into the IP datagram 'data' part. */ - skb_pull(skb, (u8 *) (fhdr + 1) - skb->data); - skb_trim(skb, end - offset); + if (!pskb_pull(skb, (u8 *) (fhdr + 1) - skb->data)) + goto err; + if (end-offset < skb->len) { + if (pskb_trim(skb, end - offset)) + goto err; + if (skb->ip_summed != CHECKSUM_UNNECESSARY) + skb->ip_summed = CHECKSUM_NONE; + } /* Find out which fragments are in front and at the back of us * in the chain of fragments so far. We must know where to put @@ -429,7 +436,10 @@ offset += i; if (end <= offset) goto err; - skb_pull(skb, i); + if (!pskb_pull(skb, i)) + goto err; + if (skb->ip_summed != CHECKSUM_UNNECESSARY) + skb->ip_summed = CHECKSUM_NONE; } } @@ -443,9 +453,12 @@ /* Eat head of the next overlapped fragment * and leave the loop. The next ones cannot overlap. */ + if (!pskb_pull(next, i)) + goto err; FRAG6_CB(next)->offset += i; /* next fragment */ - skb_pull(next, i); fq->meat -= i; + if (next->ip_summed != CHECKSUM_UNNECESSARY) + next->ip_summed = CHECKSUM_NONE; break; } else { struct sk_buff *free_it = next; @@ -474,20 +487,18 @@ else fq->fragments = skb; - fq->iif = skb->dev->ifindex; + if (skb->dev) + fq->iif = skb->dev->ifindex; skb->dev = NULL; + fq->stamp = skb->stamp; fq->meat += skb->len; atomic_add(skb->truesize, &ip6_frag_mem); - /* First fragment. - nexthdr and nhptr are get from the first fragment. - Moreover, nexthdr is UNDEFINED for all the fragments but the - first one. - (fixed --ANK (980728)) + /* The first fragment. + * nhoffset is obtained from the first fragment, of course. */ if (offset == 0) { - fq->nexthdr = fhdr->nexthdr; - fq->nhoffset = nhptr - skb->nh.raw; + fq->nhoffset = nhoff; fq->last_in |= FIRST_IN; } return; @@ -505,21 +516,13 @@ * queue is eligible for reassembly i.e. it is not COMPLETE, * the last and the first frames arrived and all the bits are here. */ -static u8 *ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, +static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, struct net_device *dev) { struct sk_buff *fp, *head = fq->fragments; - struct sk_buff *skb; + int remove_fraghdr = 0; int payload_len; - int unfrag_len; - int copy; - u8 *nhptr; - - /* - * we know the m_flag arrived and we have a queue, - * starting from 0, without gaps. - * this means we have all fragments. - */ + int nhoff; fq_kill(fq); @@ -527,40 +530,86 @@ BUG_TRAP(FRAG6_CB(head)->offset == 0); /* Unfragmented part is taken from the first segment. */ - unfrag_len = head->h.raw - (u8 *) (head->nh.ipv6h + 1); - payload_len = unfrag_len + fq->len; + payload_len = (head->data - head->nh.raw) - sizeof(struct ipv6hdr) + fq->len; + nhoff = head->h.raw - head->nh.raw; - if (payload_len > 65535) - goto out_oversize; + if (payload_len > 65535) { + payload_len -= 8; + if (payload_len > 65535) + goto out_oversize; + remove_fraghdr = 1; + } - if ((skb = dev_alloc_skb(sizeof(struct ipv6hdr) + payload_len))==NULL) + /* Head of list must not be cloned. */ + if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC)) goto out_oom; - copy = unfrag_len + sizeof(struct ipv6hdr); - - skb->mac.raw = skb->data; - skb->nh.ipv6h = (struct ipv6hdr *) skb->data; - skb->dev = dev; - skb->protocol = __constant_htons(ETH_P_IPV6); - skb->pkt_type = head->pkt_type; - FRAG6_CB(skb)->h = FRAG6_CB(head)->h; - skb->dst = dst_clone(head->dst); - - memcpy(skb_put(skb, copy), head->nh.ipv6h, copy); - nhptr = skb->nh.raw + fq->nhoffset; - *nhptr = fq->nexthdr; - - skb->h.raw = skb->tail; - - skb->nh.ipv6h->payload_len = ntohs(payload_len); - - *skb_in = skb; + /* If the first fragment is fragmented itself, we split + * it to two chunks: the first with data and paged part + * and the second, holding only fragments. */ + if (skb_shinfo(head)->frag_list) { + struct sk_buff *clone; + int i, plen = 0; + + if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL) + goto out_oom; + clone->next = head->next; + head->next = clone; + skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list; + skb_shinfo(head)->frag_list = NULL; + for (i=0; i<skb_shinfo(head)->nr_frags; i++) + plen += skb_shinfo(head)->frags[i].size; + clone->len = clone->data_len = head->data_len - plen; + head->data_len -= clone->len; + head->len -= clone->len; + clone->csum = 0; + clone->ip_summed = head->ip_summed; + atomic_add(clone->truesize, &ip6_frag_mem); + } + + /* Normally we do not remove frag header from datagram, but + * we have to do this and to relocate header, when payload + * is > 65535-8. */ + if (remove_fraghdr) { + nhoff = fq->nhoffset; + head->nh.raw[nhoff] = head->h.raw[0]; + memmove(head->head+8, head->head, (head->data-head->head)-8); + head->mac.raw += 8; + head->nh.raw += 8; + } else { + ((struct frag_hdr*)head->h.raw)->frag_off = 0; + } - for (fp = fq->fragments; fp; fp=fp->next) - memcpy(skb_put(skb, fp->len), fp->data, fp->len); + skb_shinfo(head)->frag_list = head->next; + head->h.raw = head->data; + skb_push(head, head->data - head->nh.raw); + atomic_sub(head->truesize, &ip6_frag_mem); + + for (fp=head->next; fp; fp = fp->next) { + head->data_len += fp->len; + head->len += fp->len; + if (head->ip_summed != fp->ip_summed) + head->ip_summed = CHECKSUM_NONE; + else if (head->ip_summed == CHECKSUM_HW) + head->csum = csum_add(head->csum, fp->csum); + head->truesize += fp->truesize; + atomic_sub(fp->truesize, &ip6_frag_mem); + } + + head->next = NULL; + head->dev = dev; + head->stamp = fq->stamp; + head->nh.ipv6h->payload_len = ntohs(payload_len); + + *skb_in = head; + + /* Yes, and fold redundant checksum back. 8) */ + if (head->ip_summed == CHECKSUM_HW) + head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum); IP6_INC_STATS_BH(Ip6ReasmOKs); - return nhptr; + fq->fragments = NULL; + return nhoff; out_oversize: if (net_ratelimit()) @@ -571,14 +620,14 @@ printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n"); out_fail: IP6_INC_STATS_BH(Ip6ReasmFails); - return NULL; + return -1; } -u8* ipv6_reassembly(struct sk_buff **skbp, __u8 *nhptr) +int ipv6_reassembly(struct sk_buff **skbp, int nhoff) { struct sk_buff *skb = *skbp; - struct frag_hdr *fhdr = (struct frag_hdr *) (skb->h.raw); struct net_device *dev = skb->dev; + struct frag_hdr *fhdr; struct frag_queue *fq; struct ipv6hdr *hdr; @@ -588,31 +637,34 @@ /* Jumbo payload inhibits frag. header */ if (hdr->payload_len==0) { - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw); - return NULL; + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw); + return -1; } - if ((u8 *)(fhdr+1) > skb->tail) { - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw); - return NULL; + if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+sizeof(struct frag_hdr))) { + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw); + return -1; } + hdr = skb->nh.ipv6h; + fhdr = (struct frag_hdr *)skb->h.raw; + if (!(fhdr->frag_off & __constant_htons(0xFFF9))) { /* It is not a fragmented frame */ skb->h.raw += sizeof(struct frag_hdr); IP6_INC_STATS_BH(Ip6ReasmOKs); - return &fhdr->nexthdr; + return (u8*)fhdr - skb->nh.raw; } if (atomic_read(&ip6_frag_mem) > sysctl_ip6frag_high_thresh) ip6_evictor(); if ((fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr)) != NULL) { - u8 *ret = NULL; + int ret = -1; spin_lock(&fq->lock); - ip6_frag_queue(fq, skb, fhdr, nhptr); + ip6_frag_queue(fq, skb, fhdr, nhoff); if (fq->last_in == (FIRST_IN|LAST_IN) && fq->meat == fq->len) @@ -625,5 +677,5 @@ IP6_INC_STATS_BH(Ip6ReasmFails); kfree_skb(skb); - return NULL; + return -1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv6/sit.c linux.ac/net/ipv6/sit.c --- linux.vanilla/net/ipv6/sit.c Wed Nov 29 05:53:45 2000 +++ linux.ac/net/ipv6/sit.c Sat Apr 14 01:50:39 2001 @@ -6,7 +6,7 @@ * Pedro Roque <roque@di.fc.ul.pt> * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> * - * $Id: sit.c,v 1.47 2000/11/28 13:49:22 davem Exp $ + * $Id: sit.c,v 1.49 2001/03/19 20:31:17 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -229,7 +229,7 @@ } -void ipip6_err(struct sk_buff *skb, unsigned char *dp, int len) +void ipip6_err(struct sk_buff *skb, u32 info) { #ifndef I_WISH_WORLD_WERE_PERFECT @@ -237,14 +237,11 @@ 8 bytes of packet payload. It means, that precise relaying of ICMP in the real Internet is absolutely infeasible. */ - struct iphdr *iph = (struct iphdr*)dp; + struct iphdr *iph = (struct iphdr*)skb->data; int type = skb->h.icmph->type; int code = skb->h.icmph->code; struct ip_tunnel *t; - if (len < sizeof(struct iphdr)) - return; - switch (type) { default: case ICMP_PARAMETERPROB: @@ -382,20 +379,22 @@ IP6_ECN_set_ce(skb->nh.ipv6h); } -int ipip6_rcv(struct sk_buff *skb, unsigned short len) +int ipip6_rcv(struct sk_buff *skb) { struct iphdr *iph; struct ip_tunnel *tunnel; + if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) + goto out; + iph = skb->nh.iph; read_lock(&ipip6_lock); if ((tunnel = ipip6_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) { skb->mac.raw = skb->nh.raw; - skb->nh.raw = skb_pull(skb, skb->h.raw - skb->data); + skb->nh.raw = skb->data; memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); skb->protocol = __constant_htons(ETH_P_IPV6); - skb->ip_summed = 0; skb->pkt_type = PACKET_HOST; tunnel->stat.rx_packets++; tunnel->stat.rx_bytes += skb->len; @@ -418,6 +417,7 @@ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0); kfree_skb(skb); read_unlock(&ipip6_lock); +out: return 0; } @@ -842,7 +842,7 @@ void sit_cleanup(void) { inet_del_protocol(&sit_protocol); - unregister_netdevice(&ipip6_fb_tunnel_dev); + unregister_netdev(&ipip6_fb_tunnel_dev); } #endif @@ -852,13 +852,7 @@ ipip6_fb_tunnel_dev.priv = (void*)&ipip6_fb_tunnel; strcpy(ipip6_fb_tunnel_dev.name, ipip6_fb_tunnel.parms.name); -#ifdef MODULE register_netdev(&ipip6_fb_tunnel_dev); -#else - rtnl_lock(); - register_netdevice(&ipip6_fb_tunnel_dev); - rtnl_unlock(); -#endif inet_add_protocol(&sit_protocol); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv6/tcp_ipv6.c linux.ac/net/ipv6/tcp_ipv6.c --- linux.vanilla/net/ipv6/tcp_ipv6.c Tue Apr 3 17:32:30 2001 +++ linux.ac/net/ipv6/tcp_ipv6.c Sat Apr 14 01:50:39 2001 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: tcp_ipv6.c,v 1.128 2000/12/08 17:15:54 davem Exp $ + * $Id: tcp_ipv6.c,v 1.135 2001/04/06 18:41:36 davem Exp $ * * Based on: * linux/net/ipv4/tcp.c @@ -635,6 +635,7 @@ } ip6_dst_store(sk, dst, NULL); + sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM; if (saddr == NULL) { err = ipv6_get_saddr(dst, &np->daddr, &saddr_buf); @@ -678,25 +679,23 @@ failure: __sk_dst_reset(sk); sk->dport = 0; + sk->route_caps = 0; return err; } -void tcp_v6_err(struct sk_buff *skb, struct ipv6hdr *hdr, - struct inet6_skb_parm *opt, - int type, int code, unsigned char *header, __u32 info) +void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + int type, int code, int offset, __u32 info) { + struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; struct in6_addr *saddr = &hdr->saddr; struct in6_addr *daddr = &hdr->daddr; - struct tcphdr *th = (struct tcphdr *)header; + struct tcphdr *th = (struct tcphdr *)(skb->data+offset); struct ipv6_pinfo *np; struct sock *sk; int err; struct tcp_opt *tp; __u32 seq; - if (header + 8 > skb->tail) - return; - sk = tcp_v6_lookup(daddr, th->dest, saddr, th->source, skb->dev->ifindex); if (sk == NULL) { @@ -914,10 +913,15 @@ struct sk_buff *skb) { struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6; - - th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, - csum_partial((char *)th, th->doff<<2, - skb->csum)); + + if (skb->ip_summed == CHECKSUM_HW) { + th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0); + skb->csum = offsetof(struct tcphdr, check); + } else { + th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, + csum_partial((char *)th, th->doff<<2, + skb->csum)); + } } @@ -1298,6 +1302,7 @@ MOD_INC_USE_COUNT; ip6_dst_store(newsk, dst, NULL); + sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM; newtp = &(newsk->tp_pinfo.af_tcp); @@ -1371,22 +1376,20 @@ static int tcp_v6_checksum_init(struct sk_buff *skb) { if (skb->ip_summed == CHECKSUM_HW) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, + &skb->nh.ipv6h->daddr,skb->csum)) + return 0; + NETDEBUG(printk(KERN_DEBUG "hw tcp v6 csum failed\n")); + } + if (skb->len <= 76) { if (tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, - &skb->nh.ipv6h->daddr,skb->csum)) { - NETDEBUG(printk(KERN_DEBUG "hw tcp v6 csum failed\n")); + &skb->nh.ipv6h->daddr,skb_checksum(skb, 0, skb->len, 0))) return -1; - } skb->ip_summed = CHECKSUM_UNNECESSARY; } else { - if (skb->len <= 76) { - if (tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, - &skb->nh.ipv6h->daddr,csum_partial((char *)skb->h.th, skb->len, 0))) - return -1; - skb->ip_summed = CHECKSUM_UNNECESSARY; - } else { - skb->csum = ~tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, - &skb->nh.ipv6h->daddr,0); - } + skb->csum = ~tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, + &skb->nh.ipv6h->daddr,0); } return 0; } @@ -1526,46 +1529,45 @@ return 0; } -int tcp_v6_rcv(struct sk_buff *skb, unsigned long len) +int tcp_v6_rcv(struct sk_buff *skb) { struct tcphdr *th; struct sock *sk; - struct in6_addr *saddr = &skb->nh.ipv6h->saddr; - struct in6_addr *daddr = &skb->nh.ipv6h->daddr; int ret; - th = skb->h.th; - if (skb->pkt_type != PACKET_HOST) goto discard_it; /* - * Pull up the IP header. + * Count it even if it's bad. */ + TCP_INC_STATS_BH(TcpInSegs); - __skb_pull(skb, skb->h.raw - skb->data); + if (!pskb_may_pull(skb, sizeof(struct tcphdr))) + goto discard_it; - /* - * Count it even if it's bad. - */ + th = skb->h.th; - TCP_INC_STATS_BH(TcpInSegs); + if (th->doff < sizeof(struct tcphdr)/4) + goto bad_packet; + if (!pskb_may_pull(skb, th->doff*4)) + goto discard_it; - if (th->doff < sizeof(struct tcphdr)/4 || - (skb->ip_summed != CHECKSUM_UNNECESSARY && + if ((skb->ip_summed != CHECKSUM_UNNECESSARY && tcp_v6_checksum_init(skb) < 0)) goto bad_packet; + th = skb->h.th; TCP_SKB_CB(skb)->seq = ntohl(th->seq); TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + - len - th->doff*4); + skb->len - th->doff*4); TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); TCP_SKB_CB(skb)->when = 0; TCP_SKB_CB(skb)->flags = ip6_get_dsfield(skb->nh.ipv6h); TCP_SKB_CB(skb)->sacked = 0; - skb->used = 0; - sk = __tcp_v6_lookup(saddr, th->source, daddr, ntohs(th->dest), tcp_v6_iif(skb)); + sk = __tcp_v6_lookup(&skb->nh.ipv6h->saddr, th->source, + &skb->nh.ipv6h->daddr, ntohs(th->dest), tcp_v6_iif(skb)); if (!sk) goto no_tcp_socket; @@ -1591,7 +1593,7 @@ return ret; no_tcp_socket: - if (len < (th->doff<<2) || tcp_checksum_complete(skb)) { + if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { bad_packet: TCP_INC_STATS_BH(TcpInErrs); } else { @@ -1612,7 +1614,7 @@ goto discard_it; do_time_wait: - if (len < (th->doff<<2) || tcp_checksum_complete(skb)) { + if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { TCP_INC_STATS_BH(TcpInErrs); sock_put(sk); goto discard_it; @@ -1673,10 +1675,12 @@ if (dst->error) { err = dst->error; dst_release(dst); + sk->route_caps = 0; return err; } ip6_dst_store(sk, dst, NULL); + sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM; } return 0; @@ -1837,7 +1841,7 @@ /* Cleanup up the write buffer. */ tcp_writequeue_purge(sk); - /* Cleans up our, hopefuly empty, out_of_order_queue. */ + /* Cleans up our, hopefully empty, out_of_order_queue. */ __skb_queue_purge(&tp->out_of_order_queue); /* Clean prequeue, it must be empty really */ @@ -1847,6 +1851,10 @@ if(sk->prev != NULL) tcp_put_port(sk); + /* If sendmsg cached page exists, toss it. */ + if (tp->sndmsg_page != NULL) + __free_page(tp->sndmsg_page); + atomic_dec(&tcp_sockets_allocated); return inet6_destroy_sock(sk); @@ -1967,7 +1975,7 @@ off_t begin, pos = 0; char tmpbuf[LINE_LEN+2]; - if(offset < LINE_LEN+1) + if (offset < LINE_LEN+1) len += sprintf(buffer, LINE_FMT, " sl " /* 6 */ "local_address " /* 38 */ @@ -1997,7 +2005,7 @@ if (pos >= offset) { get_tcp6_sock(sk, tmpbuf, num); len += sprintf(buffer+len, LINE_FMT, tmpbuf); - if (len >= length) { + if (pos >= offset + length) { tcp_listen_unlock(); goto out_no_bh; } @@ -2016,7 +2024,7 @@ continue; get_openreq6(sk, req, tmpbuf, num, uid); len += sprintf(buffer+len, LINE_FMT, tmpbuf); - if(len >= length) { + if (pos >= offset + length) { read_unlock_bh(&tp->syn_wait_lock); tcp_listen_unlock(); goto out_no_bh; @@ -2048,7 +2056,7 @@ continue; get_tcp6_sock(sk, tmpbuf, num); len += sprintf(buffer+len, LINE_FMT, tmpbuf); - if(len >= length) { + if (pos >= offset + length) { read_unlock(&head->lock); goto out; } @@ -2063,7 +2071,7 @@ continue; get_timewait6_sock(tw, tmpbuf, num); len += sprintf(buffer+len, LINE_FMT, tmpbuf); - if(len >= length) { + if (pos >= offset + length) { read_unlock(&head->lock); goto out; } @@ -2078,7 +2086,7 @@ begin = len - (pos - offset); *start = buffer + begin; len -= begin; - if(len > length) + if (len > length) len = length; if (len < 0) len = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv6/udp.c linux.ac/net/ipv6/udp.c --- linux.vanilla/net/ipv6/udp.c Mon Jan 1 19:01:58 2001 +++ linux.ac/net/ipv6/udp.c Sat Apr 14 01:50:40 2001 @@ -7,7 +7,7 @@ * * Based on linux/ipv4/udp.c * - * $Id: udp.c,v 1.59 2000/11/28 13:38:38 davem Exp $ + * $Id: udp.c,v 1.62 2001/03/06 21:15:11 davem Exp $ * * Fixes: * Hideaki YOSHIFUJI : sin6_scope_id support @@ -391,13 +391,13 @@ err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, copied); } else if (msg->msg_flags&MSG_TRUNC) { - if ((unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum))) + if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) goto csum_copy_err; err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, copied); } else { - err = copy_and_csum_toiovec(msg->msg_iov, skb, sizeof(struct udphdr)); - if (err) + err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); + if (err == -EINVAL) goto csum_copy_err; } if (err) @@ -461,22 +461,17 @@ goto out_free; } -void udpv6_err(struct sk_buff *skb, struct ipv6hdr *hdr, - struct inet6_skb_parm *opt, - int type, int code, unsigned char *buff, __u32 info) +void udpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + int type, int code, int offset, __u32 info) { + struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; struct net_device *dev = skb->dev; struct in6_addr *saddr = &hdr->saddr; struct in6_addr *daddr = &hdr->daddr; + struct udphdr *uh = (struct udphdr*)(skb->data+offset); struct sock *sk; - struct udphdr *uh; int err; - if (buff + sizeof(struct udphdr) > skb->tail) - return; - - uh = (struct udphdr *) buff; - sk = udp_v6_lookup(daddr, uh->dest, saddr, uh->source, dev->ifindex); if (sk == NULL) @@ -577,8 +572,8 @@ buff = NULL; sk2 = sk; - while((sk2 = udp_v6_mcast_next(sk2->next, uh->dest, saddr, - uh->source, daddr, dif))) { + while((sk2 = udp_v6_mcast_next(sk2->next, uh->dest, daddr, + uh->source, saddr, dif))) { if (!buff) { buff = skb_clone(skb, GFP_ATOMIC); if (!buff) @@ -596,31 +591,29 @@ read_unlock(&udp_hash_lock); } -int udpv6_rcv(struct sk_buff *skb, unsigned long len) +int udpv6_rcv(struct sk_buff *skb) { struct sock *sk; struct udphdr *uh; struct net_device *dev = skb->dev; - struct in6_addr *saddr = &skb->nh.ipv6h->saddr; - struct in6_addr *daddr = &skb->nh.ipv6h->daddr; - u32 ulen; + struct in6_addr *saddr, *daddr; + u32 ulen = 0; + if (!pskb_may_pull(skb, sizeof(struct udphdr))) + goto short_packet; + + saddr = &skb->nh.ipv6h->saddr; + daddr = &skb->nh.ipv6h->daddr; uh = skb->h.uh; - __skb_pull(skb, skb->h.raw - skb->data); ulen = ntohs(uh->len); /* Check for jumbo payload */ - if (ulen == 0 && skb->nh.ipv6h->payload_len == 0) - ulen = len; + if (ulen == 0) + ulen = skb->len; - if (ulen > len || len < sizeof(*uh)) { - if (net_ratelimit()) - printk(KERN_DEBUG "UDP: short packet: %d/%ld\n", ulen, len); - UDP6_INC_STATS_BH(UdpInErrors); - kfree_skb(skb); - return(0); - } + if (ulen > skb->len || ulen < sizeof(*uh)) + goto short_packet; if (uh->check == 0) { /* IPv6 draft-v2 section 8.1 says that we SHOULD log @@ -631,17 +624,24 @@ goto discard; } - skb_trim(skb, ulen); + if (ulen < skb->len) { + if (__pskb_trim(skb, ulen)) + goto discard; + saddr = &skb->nh.ipv6h->saddr; + daddr = &skb->nh.ipv6h->daddr; + uh = skb->h.uh; + } if (skb->ip_summed==CHECKSUM_HW) { - if (csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) - goto discard; skb->ip_summed = CHECKSUM_UNNECESSARY; - } else if (skb->ip_summed != CHECKSUM_UNNECESSARY) + if (csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) { + NETDEBUG(printk(KERN_DEBUG "udp v6 hw csum failure.\n")); + skb->ip_summed = CHECKSUM_NONE; + } + } + if (skb->ip_summed != CHECKSUM_UNNECESSARY) skb->csum = ~csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, 0); - len = ulen; - /* * Multicast receive code */ @@ -656,12 +656,11 @@ * check socket cache ... must talk to Alan about his plans * for sock caches... i'll skip this for now. */ - sk = udp_v6_lookup(saddr, uh->source, daddr, uh->dest, dev->ifindex); - + if (sk == NULL) { if (skb->ip_summed != CHECKSUM_UNNECESSARY && - (unsigned short)csum_fold(csum_partial((char*)uh, len, skb->csum))) + (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) goto discard; UDP6_INC_STATS_BH(UdpNoPorts); @@ -676,7 +675,11 @@ udpv6_queue_rcv_skb(sk, skb); sock_put(sk); return(0); - + +short_packet: + if (net_ratelimit()) + printk(KERN_DEBUG "UDP: short packet: %d/%u\n", ulen, skb->len); + discard: UDP6_INC_STATS_BH(UdpInErrors); kfree_skb(skb); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipx/af_ipx.c linux.ac/net/ipx/af_ipx.c --- linux.vanilla/net/ipx/af_ipx.c Tue Apr 3 17:32:30 2001 +++ linux.ac/net/ipx/af_ipx.c Sat Apr 14 01:50:54 2001 @@ -123,7 +123,7 @@ static unsigned char ipxcfg_max_hops = 16; static char ipxcfg_auto_select_primary; static char ipxcfg_auto_create_interfaces; -static int sysctl_ipx_pprop_broadcasting = 1; +int sysctl_ipx_pprop_broadcasting = 1; /* Global Variables */ static struct datalink_proto *p8022_datalink; @@ -1542,7 +1542,7 @@ ipx_offset = intrfc->if_ipx_offset; size = sizeof(struct ipxhdr) + len + ipx_offset; - skb = sock_alloc_send_skb(sk, size, 0, noblock, &err); + skb = sock_alloc_send_skb(sk, size, noblock, &err); if (!skb) goto out_put; @@ -2531,6 +2531,7 @@ sendmsg: ipx_sendmsg, recvmsg: ipx_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #include <linux/smp_lock.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipx/af_spx.c linux.ac/net/ipx/af_spx.c --- linux.vanilla/net/ipx/af_spx.c Mon Aug 7 06:20:09 2000 +++ linux.ac/net/ipx/af_spx.c Sat Apr 14 01:50:59 2001 @@ -31,8 +31,6 @@ * This material is provided "as is" and at no charge. */ -#include <linux/config.h> -#if defined(CONFIG_SPX) || defined(CONFIG_SPX_MODULE) #include <linux/module.h> #include <net/ipx.h> #include <net/spx.h> @@ -440,7 +438,7 @@ save_flags(flags); cli(); - skb = sock_alloc_send_skb(sk, size, 1, 0, &err); + skb = sock_alloc_send_skb(sk, size, 0, &err); if(skb == NULL) { restore_flags(flags); return (-ENOMEM); @@ -742,7 +740,7 @@ size = offset + sizeof(struct ipxspxhdr) + len; cli(); - skb = sock_alloc_send_skb(sk, size, 0, flags&MSG_DONTWAIT, &err); + skb = sock_alloc_send_skb(sk, size, flags&MSG_DONTWAIT, &err); sti(); if(skb == NULL) return (err); @@ -901,20 +899,20 @@ sendmsg: spx_sendmsg, recvmsg: spx_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #include <linux/smp_lock.h> SOCKOPS_WRAP(spx, PF_IPX); - -static struct net_proto_family spx_family_ops= -{ - PF_IPX, - spx_create +static struct net_proto_family spx_family_ops = { + family: PF_IPX, + create: spx_create, }; +static const char banner[] __initdata = KERN_INFO "NET4: Sequenced Packet eXchange (SPX) 0.02 for Linux NET4.0\n"; -void spx_proto_init(void) +static int __init spx_proto_init(void) { int error; @@ -926,29 +924,14 @@ /* route socket(PF_IPX, SOCK_SEQPACKET) calls through spx_create() */ - printk(KERN_INFO "NET4: Sequenced Packet eXchange (SPX) 0.02 for Linux NET4.0\n"); - return; + printk(banner); + return 0; } +module_init(spx_proto_init); -void spx_proto_finito(void) +static void __exit spx_proto_finito(void) { ipx_unregister_spx(); return; } - -#ifdef MODULE - -int init_module(void) -{ - spx_proto_init(); - return 0; -} - -void cleanup_module(void) -{ - spx_proto_finito(); - return; -} - -#endif /* MODULE */ -#endif /* CONFIG_SPX || CONFIG_SPX_MODULE */ +module_exit(spx_proto_finito); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipx/sysctl_net_ipx.c linux.ac/net/ipx/sysctl_net_ipx.c --- linux.vanilla/net/ipx/sysctl_net_ipx.c Tue Apr 3 17:32:30 2001 +++ linux.ac/net/ipx/sysctl_net_ipx.c Sat Apr 14 01:51:05 2001 @@ -6,6 +6,7 @@ * Added /proc/sys/net/ipx/ipx_pprop_broadcasting - acme March 4, 2001 */ +#include <linux/config.h> #include <linux/mm.h> #include <linux/sysctl.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/irda/af_irda.c linux.ac/net/irda/af_irda.c --- linux.vanilla/net/irda/af_irda.c Tue Apr 3 17:32:31 2001 +++ linux.ac/net/irda/af_irda.c Sat Apr 14 01:51:11 2001 @@ -439,7 +439,7 @@ * We were waiting for a node to be discovered, but nothing has come up * so far. Wake up the user and tell him that we failed... */ -static void irda_discovery_timeout(u_long priv) +static void irda_discovery_timeout(u_long priv) { struct irda_sock *self; @@ -776,7 +776,6 @@ struct sock *sk = sock->sk; struct sockaddr_irda *addr = (struct sockaddr_irda *) uaddr; struct irda_sock *self; - __u16 hints = 0; int err; IRDA_DEBUG(2, __FUNCTION__ "()\n"); @@ -821,15 +820,6 @@ self->stsap_sel, IAS_KERNEL_ATTR); irias_insert_object(self->ias_obj); -#if 1 /* Will be removed in near future */ - - /* Fill in some default hint bits values */ - if (strncmp(addr->sir_name, "OBEX", 4) == 0) - hints = irlmp_service_to_hint(S_OBEX); - - if (hints) - self->skey = irlmp_register_service(hints); -#endif return 0; } @@ -1257,7 +1247,7 @@ len = self->max_data_size; } - skb = sock_alloc_send_skb(sk, len + self->max_header_size, 0, + skb = sock_alloc_send_skb(sk, len + self->max_header_size, msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) return -ENOBUFS; @@ -1500,7 +1490,7 @@ len = self->max_data_size; } - skb = sock_alloc_send_skb(sk, len + self->max_header_size, 0, + skb = sock_alloc_send_skb(sk, len + self->max_header_size, msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) return -ENOBUFS; @@ -1563,7 +1553,7 @@ len = self->max_data_size; } - skb = sock_alloc_send_skb(sk, len + self->max_header_size, 0, + skb = sock_alloc_send_skb(sk, len + self->max_header_size, msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) return -ENOBUFS; @@ -2256,6 +2246,7 @@ sendmsg: irda_sendmsg, recvmsg: irda_recvmsg_stream, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; static struct proto_ops SOCKOPS_WRAPPED(irda_seqpacket_ops) = { @@ -2276,6 +2267,7 @@ sendmsg: irda_sendmsg, recvmsg: irda_recvmsg_dgram, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; static struct proto_ops SOCKOPS_WRAPPED(irda_dgram_ops) = { @@ -2296,6 +2288,7 @@ sendmsg: irda_sendmsg_dgram, recvmsg: irda_recvmsg_dgram, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #ifdef CONFIG_IRDA_ULTRA @@ -2317,6 +2310,7 @@ sendmsg: irda_sendmsg_ultra, recvmsg: irda_recvmsg_dgram, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #endif /* CONFIG_IRDA_ULTRA */ @@ -2324,6 +2318,9 @@ SOCKOPS_WRAP(irda_stream, PF_IRDA); SOCKOPS_WRAP(irda_seqpacket, PF_IRDA); SOCKOPS_WRAP(irda_dgram, PF_IRDA); +#ifdef CONFIG_IRDA_ULTRA +SOCKOPS_WRAP(irda_ultra, PF_IRDA); +#endif /* CONFIG_IRDA_ULTRA */ /* * Function irda_device_event (this, event, ptr) @@ -2412,7 +2409,9 @@ #endif return 0; } -module_init(irda_proto_init); +#ifdef MODULE +module_init(irda_proto_init); /* If non-module, called from init/main.c */ +#endif /* * Function irda_proto_cleanup (void) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/irda/irias_object.c linux.ac/net/irda/irias_object.c --- linux.vanilla/net/irda/irias_object.c Tue Apr 3 17:32:31 2001 +++ linux.ac/net/irda/irias_object.c Tue Apr 3 17:55:21 2001 @@ -34,7 +34,7 @@ /* * Used when a missing value needs to be returned */ -struct ias_value missing = { IAS_MISSING, 0, 0, 0}; +struct ias_value missing = { IAS_MISSING, 0, 0, 0, {0}}; /* * Function strdup (str) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/irda/irlap.c linux.ac/net/irda/irlap.c --- linux.vanilla/net/irda/irlap.c Tue Apr 3 17:32:31 2001 +++ linux.ac/net/irda/irlap.c Tue Apr 3 17:55:21 2001 @@ -860,13 +860,6 @@ /* Free sliding window buffered packets */ while ((skb = skb_dequeue(&self->wx_list)) != NULL) dev_kfree_skb(skb); - -#ifdef CONFIG_IRDA_RECYCLE_RR - if (self->recycle_rr_skb) { - dev_kfree_skb(self->recycle_rr_skb); - self->recycle_rr_skb = NULL; - } -#endif } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/irda/irlap_frame.c linux.ac/net/irda/irlap_frame.c --- linux.vanilla/net/irda/irlap_frame.c Thu Feb 8 23:14:08 2001 +++ linux.ac/net/irda/irlap_frame.c Tue Apr 3 17:55:21 2001 @@ -742,12 +742,6 @@ return; } - /* - * make sure the skb->sk accounting of memory usage is sane - */ - if (skb->sk != NULL) - skb_set_owner_w(tx_skb, skb->sk); - /* * Insert frame in store, in case of retransmissions */ @@ -788,12 +782,6 @@ return; } - /* - * make sure the skb->sk accounting of memory usage is sane - */ - if (skb->sk != NULL) - skb_set_owner_w(tx_skb, skb->sk); - /* * Insert frame in store, in case of retransmissions */ @@ -863,9 +851,6 @@ return; } - if (skb->sk != NULL) - skb_set_owner_w(tx_skb, skb->sk); - /* Insert frame in store */ skb_queue_tail(&self->wx_list, skb_get(skb)); @@ -917,9 +902,6 @@ return; } - if (skb->sk != NULL) - skb_set_owner_w(tx_skb, skb->sk); - /* Insert frame in store */ skb_queue_tail(&self->wx_list, skb_get(skb)); @@ -973,12 +955,6 @@ tx_skb->next = tx_skb->prev = NULL; tx_skb->list = NULL; - /* - * make sure the skb->sk accounting of memory usage is sane - */ - if (skb->sk != NULL) - skb_set_owner_w(tx_skb, skb->sk); - /* Clear old Nr field + poll bit */ tx_skb->data[1] &= 0x0f; @@ -1058,12 +1034,6 @@ /* Unlink tx_skb from list */ tx_skb->next = tx_skb->prev = NULL; tx_skb->list = NULL; - - /* - * make sure the skb->sk accounting of memory usage is sane - */ - if (skb->sk != NULL) - skb_set_owner_w(tx_skb, skb->sk); /* Clear old Nr field + poll bit */ tx_skb->data[1] &= 0x0f; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/irda/irlmp.c linux.ac/net/irda/irlmp.c --- linux.vanilla/net/irda/irlmp.c Tue Apr 3 17:32:31 2001 +++ linux.ac/net/irda/irlmp.c Tue Apr 3 17:55:21 2001 @@ -959,6 +959,7 @@ { ASSERT(self != NULL, return -1;); ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); + ASSERT(skb->sk == NULL, /* Just a warning - NOP */;); /* Make room for MUX header */ ASSERT(skb_headroom(skb) >= LMP_HEADER, return -1;); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/irda/irlmp_event.c linux.ac/net/irda/irlmp_event.c --- linux.vanilla/net/irda/irlmp_event.c Sun Nov 12 02:11:22 2000 +++ linux.ac/net/irda/irlmp_event.c Tue Apr 3 17:55:21 2001 @@ -472,8 +472,6 @@ irlmp_start_watchdog_timer(self, 5*HZ); break; case LM_CONNECT_INDICATION: - irlmp_next_lsap_state(self, LSAP_CONNECT_PEND); - if (self->conn_skb) { WARNING(__FUNCTION__ "(), busy with another request!\n"); @@ -481,6 +479,8 @@ } self->conn_skb = skb; + irlmp_next_lsap_state(self, LSAP_CONNECT_PEND); + irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL); break; default: @@ -562,6 +562,15 @@ switch (event) { case LM_CONNECT_REQUEST: /* Keep state */ + break; + case LM_CONNECT_INDICATION: + /* Will happen in some rare cases when the socket get stuck, + * the other side retries the connect request. + * We just unstuck the socket - Jean II */ + IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_INDICATION, " + "LSAP stuck in CONNECT_PEND state...\n"); + /* Keep state */ + irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL); break; case LM_CONNECT_RESPONSE: IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_RESPONSE, " diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/irda/irnet/irnet.h linux.ac/net/irda/irnet/irnet.h --- linux.vanilla/net/irda/irnet/irnet.h Tue Apr 3 17:32:31 2001 +++ linux.ac/net/irda/irnet/irnet.h Tue Apr 3 17:55:21 2001 @@ -5,7 +5,7 @@ * * This file contains definitions and declarations global to the IrNET module, * all grouped in one place... - * This file is a private header, so other modules don't want to know + * This file is a *private* header, so other modules don't want to know * what's in there... * * Note : as most part of the Linux kernel, this module is available @@ -52,15 +52,13 @@ * o multipoint operation (limited by IrLAP specification) * o information in /proc/net/irda/irnet * o IrNET events on /dev/irnet (for user space daemon) - * o IrNET deamon (irnetd) to automatically handle incoming requests + * o IrNET daemon (irnetd) to automatically handle incoming requests * o Windows 2000 compatibility (tested, but need more work) * Currently missing : * o Lot's of testing (that's your job) * o Connection retries (may be too hard to do) * o Check pppd persist mode - * o User space deamon (to automatically handle incoming requests) - * o A registered device number (coming, waiting from an answer) - * o Final integration in Linux-IrDA (up to Dag) + * o User space daemon (to automatically handle incoming requests) * * The setup is not currently the most easy, but this should get much * better when everything will get integrated... @@ -159,6 +157,17 @@ * o Add IRNET_NOANSWER_FROM event (mostly to help support) * o Release flow control in disconnect_indication * o Block packets while connecting (speed up connections) + * + * v5 - 11/01/01 - Jean II + * o Init self->max_header_size, just in case... + * o Set up ap->chan.hdrlen, to get zero copy on tx side working. + * o avoid tx->ttp->flow->ppp->tx->... loop, by checking flow state + * Thanks to Christian Gennerat for finding this bug ! + * --- + * o Declare the proper MTU/MRU that we can support + * (but PPP doesn't read the MTU value :-() + * o Declare hashbin HB_NOLOCK instead of HB_LOCAL to avoid + * disabling and enabling irq twice */ /***************************** INCLUDES *****************************/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/irda/irnet/irnet_irda.c linux.ac/net/irda/irnet/irnet_irda.c --- linux.vanilla/net/irda/irnet/irnet_irda.c Tue Apr 3 17:32:31 2001 +++ linux.ac/net/irda/irnet/irnet_irda.c Tue Apr 3 17:55:21 2001 @@ -1039,6 +1039,7 @@ LOCAL_FLOW flow) { irnet_socket * self = (irnet_socket *) instance; + LOCAL_FLOW oldflow = self->tx_flow; DENTER(IRDA_TCB_TRACE, "(self=0x%X, flow=%d)\n", (unsigned int) self, flow); @@ -1050,7 +1051,11 @@ { case FLOW_START: DEBUG(IRDA_CB_INFO, "IrTTP wants us to start again\n"); - ppp_output_wakeup(&self->chan); + /* Check if we really need to wake up PPP */ + if(oldflow == FLOW_STOP) + ppp_output_wakeup(&self->chan); + else + DEBUG(IRDA_CB_INFO, "But we were already transmitting !!!\n"); break; case FLOW_STOP: DEBUG(IRDA_CB_INFO, "IrTTP wants us to slow down\n"); @@ -1426,7 +1431,7 @@ memset(&irnet_server, 0, sizeof(struct irnet_root)); /* Setup start of irnet instance list */ - irnet_server.list = hashbin_new(HB_LOCAL); + irnet_server.list = hashbin_new(HB_NOLOCK); DABORT(irnet_server.list == NULL, -ENOMEM, MODULE_ERROR, "Can't allocate hashbin!\n"); /* Init spinlock for instance list */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/irda/irnet/irnet_irda.h linux.ac/net/irda/irnet/irnet_irda.h --- linux.vanilla/net/irda/irnet/irnet_irda.h Mon Dec 11 21:33:15 2000 +++ linux.ac/net/irda/irnet/irnet_irda.h Tue Apr 3 17:55:21 2001 @@ -13,8 +13,9 @@ #define IRNET_IRDA_H /***************************** INCLUDES *****************************/ - #include <linux/config.h> +/* Please add other headers in irnet.h */ + #include "irnet.h" /* Module global include */ /************************ CONSTANTS & MACROS ************************/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/irda/irnet/irnet_ppp.c linux.ac/net/irda/irnet/irnet_ppp.c --- linux.vanilla/net/irda/irnet/irnet_ppp.c Sun Nov 12 02:11:23 2000 +++ linux.ac/net/irda/irnet/irnet_ppp.c Tue Apr 3 17:55:21 2001 @@ -394,8 +394,11 @@ /* PPP channel setup */ ap->ppp_open = 0; ap->chan.private = ap; + ap->chan.ops = &irnet_ppp_ops; + ap->chan.mtu = (2048 - TTP_MAX_HEADER - 2 - PPP_HDRLEN); + ap->chan.hdrlen = 2 + TTP_MAX_HEADER; /* for A/C + Max IrDA hdr */ /* PPP parameters */ - ap->mru = PPP_MRU; + ap->mru = (2048 - TTP_MAX_HEADER - 2 - PPP_HDRLEN); ap->xaccm[0] = ~0U; ap->xaccm[3] = 0x60000000U; ap->raccm = ~0U; @@ -568,10 +571,7 @@ if((val == N_SYNC_PPP) || (val == N_PPP)) { DEBUG(FS_INFO, "Entering PPP discipline.\n"); - /* PPP channel setup */ - ap->chan.private = ap; - ap->chan.ops = &irnet_ppp_ops; - ap->chan.mtu = PPP_MRU; + /* PPP channel setup (ap->chan in configued in dev_irnet_open())*/ err = ppp_register_channel(&ap->chan); if(err == 0) { @@ -769,7 +769,7 @@ /* prepend address/control fields if necessary */ if(needaddr) { - skb_push(skb,2); + skb_push(skb, 2); skb->data[0] = PPP_ALLSTATIONS; skb->data[1] = PPP_UI; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/irda/irttp.c linux.ac/net/irda/irttp.c --- linux.vanilla/net/irda/irttp.c Thu Feb 8 23:14:08 2001 +++ linux.ac/net/irda/irttp.c Tue Apr 3 17:55:21 2001 @@ -369,7 +369,7 @@ } else { /* * Fragment the frame, this function will also queue the - * fragments, we don't care about the fact the the transmit + * fragments, we don't care about the fact the transmit * queue may be overfilled by all the segments for a little * while */ @@ -454,6 +454,46 @@ */ skb->data[0] |= (n & 0x7f); + /* Detach from socket. + * The current skb has a reference to the socket that sent + * it (skb->sk). When we pass it to IrLMP, the skb will be + * stored in in IrLAP (self->wx_list). When we are within + * IrLAP, we loose the notion of socket, so we should not + * have a reference to a socket. So, we drop it here. + * + * Why does it matter ? + * When the skb is freed (kfree_skb), if it is associated + * with a socket, it release buffer space on the socket + * (through sock_wfree() and sock_def_write_space()). + * If the socket no longer exist, we may crash. Hard. + * When we close a socket, we make sure that associated packets + * in IrTTP are freed. However, we have no way to cancel + * the packet that we have passed to IrLAP. So, if a packet + * remains in IrLAP (retry on the link or else) after we + * close the socket, we are dead ! + * Jean II */ + if (skb->sk != NULL) { + struct sk_buff *tx_skb; + + /* IrSOCK application, IrOBEX, ... */ + IRDA_DEBUG(4, __FUNCTION__ "() : Detaching SKB from socket.\n"); + /* Note : still looking for a more efficient way + * to do that - Jean II */ + + /* Get another skb on the same buffer, but without + * a reference to the socket (skb->sk = NULL) */ + tx_skb = skb_clone(skb, GFP_ATOMIC); + if (tx_skb != NULL) { + /* Release the skb associated with the + * socket, and use the new skb insted */ + kfree_skb(skb); + skb = tx_skb; + } + } else { + /* IrCOMM over IrTTP, IrLAN, ... */ + IRDA_DEBUG(4, __FUNCTION__ "() : Got SKB not attached to a socket.\n"); + } + irlmp_data_request(self->lsap, skb); self->stats.tx_packets++; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/lapb/lapb_iface.c linux.ac/net/lapb/lapb_iface.c --- linux.vanilla/net/lapb/lapb_iface.c Sat Feb 17 00:06:17 2001 +++ linux.ac/net/lapb/lapb_iface.c Sat Apr 14 01:51:18 2001 @@ -15,7 +15,6 @@ * 2000-10-29 Henner Eisen lapb_data_indication() return status. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/types.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/netlink/af_netlink.c linux.ac/net/netlink/af_netlink.c --- linux.vanilla/net/netlink/af_netlink.c Fri Feb 9 19:29:44 2001 +++ linux.ac/net/netlink/af_netlink.c Sat Apr 14 01:51:18 2001 @@ -962,6 +962,7 @@ sendmsg: netlink_sendmsg, recvmsg: netlink_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; struct net_proto_family netlink_family_ops = { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/netrom/af_netrom.c linux.ac/net/netrom/af_netrom.c --- linux.vanilla/net/netrom/af_netrom.c Fri Dec 29 22:35:47 2000 +++ linux.ac/net/netrom/af_netrom.c Sat Apr 14 19:02:26 2001 @@ -407,6 +407,9 @@ if (get_user(len, optlen)) return -EFAULT; + if (len < 0) + return -EINVAL; + switch (optname) { case NETROM_T1: val = sk->protinfo.nr->t1 / HZ; @@ -1010,7 +1013,7 @@ SOCK_DEBUG(sk, "NET/ROM: sendto: building packet.\n"); size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN; - if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) + if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) return err; skb_reserve(skb, size - len); @@ -1224,10 +1227,9 @@ return(len); } -static struct net_proto_family nr_family_ops = -{ - PF_NETROM, - nr_create +static struct net_proto_family nr_family_ops = { + family: PF_NETROM, + create: nr_create, }; static struct proto_ops SOCKOPS_WRAPPED(nr_proto_ops) = { @@ -1248,22 +1250,29 @@ sendmsg: nr_sendmsg, recvmsg: nr_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #include <linux/smp_lock.h> SOCKOPS_WRAP(nr_proto, PF_NETROM); static struct notifier_block nr_dev_notifier = { - nr_device_event, - 0 + notifier_call: nr_device_event, }; static struct net_device *dev_nr; +static const char banner[] __initdata = KERN_INFO "G4KLX NET/ROM for Linux. Version 0.7 for AX25.037 Linux 2.4\n"; + static int __init nr_proto_init(void) { int i; + if (nr_ndevs > 0x7fffffff/sizeof(struct net_device)) { + printk(KERN_ERR "NET/ROM: nr_proto_init - nr_ndevs parameter to large\n"); + return -1; + } + if ((dev_nr = kmalloc(nr_ndevs * sizeof(struct net_device), GFP_KERNEL)) == NULL) { printk(KERN_ERR "NET/ROM: nr_proto_init - unable to allocate device structure\n"); return -1; @@ -1279,7 +1288,7 @@ sock_register(&nr_family_ops); register_netdevice_notifier(&nr_dev_notifier); - printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.7 for AX25.037 Linux 2.4\n"); + printk(banner); ax25_protocol_register(AX25_P_NETROM, nr_route_frame); ax25_linkfail_register(nr_link_failed); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/netrom/nr_out.c linux.ac/net/netrom/nr_out.c --- linux.vanilla/net/netrom/nr_out.c Fri Dec 29 22:44:46 2000 +++ linux.ac/net/netrom/nr_out.c Sat Apr 14 01:51:53 2001 @@ -56,7 +56,7 @@ frontlen = skb_headroom(skb); while (skb->len > 0) { - if ((skbn = sock_alloc_send_skb(sk, frontlen + NR_MAX_PACKET_SIZE, 0, 0, &err)) == NULL) + if ((skbn = sock_alloc_send_skb(sk, frontlen + NR_MAX_PACKET_SIZE, 0, &err)) == NULL) return; skb_reserve(skbn, frontlen); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/netsyms.c linux.ac/net/netsyms.c --- linux.vanilla/net/netsyms.c Tue Apr 3 17:32:31 2001 +++ linux.ac/net/netsyms.c Sat Apr 14 01:51:59 2001 @@ -130,15 +130,27 @@ EXPORT_SYMBOL(sock_no_sendmsg); EXPORT_SYMBOL(sock_no_recvmsg); EXPORT_SYMBOL(sock_no_mmap); +EXPORT_SYMBOL(sock_no_sendpage); EXPORT_SYMBOL(sock_rfree); EXPORT_SYMBOL(sock_wfree); EXPORT_SYMBOL(sock_wmalloc); EXPORT_SYMBOL(sock_rmalloc); +EXPORT_SYMBOL(skb_linearize); +EXPORT_SYMBOL(skb_checksum); +EXPORT_SYMBOL(skb_checksum_help); EXPORT_SYMBOL(skb_recv_datagram); EXPORT_SYMBOL(skb_free_datagram); EXPORT_SYMBOL(skb_copy_datagram); EXPORT_SYMBOL(skb_copy_datagram_iovec); +EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec); +EXPORT_SYMBOL(skb_copy_bits); +EXPORT_SYMBOL(skb_copy_and_csum_bits); EXPORT_SYMBOL(skb_copy_expand); +EXPORT_SYMBOL(___pskb_trim); +EXPORT_SYMBOL(__pskb_pull_tail); +EXPORT_SYMBOL(pskb_expand_head); +EXPORT_SYMBOL(pskb_copy); +EXPORT_SYMBOL(skb_realloc_headroom); EXPORT_SYMBOL(datagram_poll); EXPORT_SYMBOL(put_cmsg); EXPORT_SYMBOL(sock_kmalloc); @@ -190,7 +202,6 @@ EXPORT_SYMBOL(scm_fp_dup); EXPORT_SYMBOL(files_stat); EXPORT_SYMBOL(memcpy_toiovec); -EXPORT_SYMBOL(csum_partial); #ifdef CONFIG_IPX_MODULE EXPORT_SYMBOL(make_8023_client); @@ -225,7 +236,6 @@ EXPORT_SYMBOL(ip_route_output_key); EXPORT_SYMBOL(ip_route_input); EXPORT_SYMBOL(icmp_send); -EXPORT_SYMBOL(icmp_reply); EXPORT_SYMBOL(ip_options_compile); EXPORT_SYMBOL(ip_options_undo); EXPORT_SYMBOL(arp_send); @@ -295,7 +305,6 @@ EXPORT_SYMBOL(ip_queue_xmit); EXPORT_SYMBOL(memcpy_fromiovecend); EXPORT_SYMBOL(csum_partial_copy_fromiovecend); -EXPORT_SYMBOL(copy_and_csum_toiovec); EXPORT_SYMBOL(tcp_v4_lookup_listener); /* UDP/TCP exported functions for TCPv6 */ EXPORT_SYMBOL(udp_ioctl); @@ -362,6 +371,7 @@ EXPORT_SYMBOL(sysctl_tcp_wmem); EXPORT_SYMBOL(sysctl_tcp_ecn); EXPORT_SYMBOL(tcp_cwnd_application_limited); +EXPORT_SYMBOL(tcp_sendpage); EXPORT_SYMBOL(xrlim_allow); @@ -487,8 +497,6 @@ EXPORT_SYMBOL(dev_mc_add); EXPORT_SYMBOL(dev_mc_delete); EXPORT_SYMBOL(dev_mc_upload); -EXPORT_SYMBOL(n_tty_ioctl); -EXPORT_SYMBOL(tty_register_ldisc); EXPORT_SYMBOL(__kill_fasync); EXPORT_SYMBOL(if_port_text); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/packet/af_packet.c linux.ac/net/packet/af_packet.c --- linux.vanilla/net/packet/af_packet.c Fri Feb 9 19:29:44 2001 +++ linux.ac/net/packet/af_packet.c Sat Apr 14 01:52:05 2001 @@ -5,7 +5,7 @@ * * PACKET - implements raw packet sockets. * - * Version: $Id: af_packet.c,v 1.47 2000/12/08 17:15:54 davem Exp $ + * Version: $Id: af_packet.c,v 1.54 2001/03/03 01:20:11 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -149,7 +149,7 @@ */ /* List of all packet sockets. */ -static struct sock * packet_sklist = NULL; +static struct sock * packet_sklist; static rwlock_t packet_sklist_lock = RW_LOCK_UNLOCKED; atomic_t packet_socks_nr; @@ -404,6 +404,7 @@ struct sockaddr_ll *sll; struct packet_opt *po; u8 * skb_head = skb->data; + int skb_len = skb->len; #ifdef CONFIG_FILTER unsigned snaplen; #endif @@ -461,7 +462,7 @@ if (skb_head != skb->data) { skb->data = skb_head; - skb->len = skb->tail - skb->data; + skb->len = skb_len; } kfree_skb(skb); skb = nskb; @@ -479,8 +480,8 @@ sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); #ifdef CONFIG_FILTER - if (skb->len > snaplen) - __skb_trim(skb, snaplen); + if (pskb_trim(skb, snaplen)) + goto drop_n_acct; #endif skb_set_owner_r(skb, sk); @@ -502,7 +503,7 @@ #endif if (skb_head != skb->data && skb_shared(skb)) { skb->data = skb_head; - skb->len = skb->tail - skb->data; + skb->len = skb_len; } drop: kfree_skb(skb); @@ -517,6 +518,7 @@ struct sockaddr_ll *sll; struct tpacket_hdr *h; u8 * skb_head = skb->data; + int skb_len = skb->len; unsigned snaplen; unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER; unsigned short macoff, netoff; @@ -534,6 +536,8 @@ else if (skb->pkt_type == PACKET_OUTGOING) { /* Special case: outgoing packets have ll header at head */ skb_pull(skb, skb->nh.raw - skb->data); + if (skb->ip_summed == CHECKSUM_HW) + status |= TP_STATUS_CSUMNOTREADY; } } @@ -580,6 +584,8 @@ if ((int)snaplen < 0) snaplen = 0; } + if (snaplen > skb->len-skb->data_len) + snaplen = skb->len-skb->data_len; spin_lock(&sk->receive_queue.lock); h = po->iovec[po->head]; @@ -623,7 +629,7 @@ drop_n_restore: if (skb_head != skb->data && skb_shared(skb)) { skb->data = skb_head; - skb->len = skb->tail - skb->data; + skb->len = skb_len; } drop: kfree_skb(skb); @@ -682,7 +688,7 @@ if (len > dev->mtu+reserve) goto out_unlock; - skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0, + skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, msg->msg_flags & MSG_DONTWAIT, &err); if (skb==NULL) goto out_unlock; @@ -1051,8 +1057,7 @@ msg->msg_flags|=MSG_TRUNC; } - /* We can't use skb_copy_datagram here */ - err = memcpy_toiovec(msg->msg_iov, skb->data, copied); + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (err) goto out_free; @@ -1318,6 +1323,9 @@ if (get_user(len,optlen)) return -EFAULT; + if (len < 0) + return -EINVAL; + switch(optname) { case PACKET_STATISTICS: { @@ -1780,6 +1788,7 @@ sendmsg: packet_sendmsg_spkt, recvmsg: packet_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #endif @@ -1801,17 +1810,16 @@ sendmsg: packet_sendmsg, recvmsg: packet_recvmsg, mmap: packet_mmap, + sendpage: sock_no_sendpage, }; static struct net_proto_family packet_family_ops = { - PF_PACKET, - packet_create + family: PF_PACKET, + create: packet_create, }; -struct notifier_block packet_netdev_notifier={ - packet_notifier, - NULL, - 0 +static struct notifier_block packet_netdev_notifier = { + notifier_call: packet_notifier, }; #ifdef CONFIG_PROC_FS @@ -1864,19 +1872,14 @@ } #endif - - static void __exit packet_exit(void) { -#ifdef CONFIG_PROC_FS remove_proc_entry("net/packet", 0); -#endif unregister_netdevice_notifier(&packet_netdev_notifier); sock_unregister(PF_PACKET); return; } - static int __init packet_init(void) { sock_register(&packet_family_ops); @@ -1886,7 +1889,6 @@ #endif return 0; } - module_init(packet_init); module_exit(packet_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/rose/af_rose.c linux.ac/net/rose/af_rose.c --- linux.vanilla/net/rose/af_rose.c Fri Dec 29 22:35:47 2000 +++ linux.ac/net/rose/af_rose.c Sat Apr 14 01:52:10 2001 @@ -70,7 +70,7 @@ int sysctl_rose_maximum_vcs = ROSE_DEFAULT_MAXVC; int sysctl_rose_window_size = ROSE_DEFAULT_WINDOW_SIZE; -static struct sock *volatile rose_list = NULL; +static struct sock *rose_list; static struct proto_ops rose_proto_ops; @@ -471,7 +471,10 @@ if (get_user(len, optlen)) return -EFAULT; - + + if (len < 0) + return -EINVAL; + switch (optname) { case ROSE_DEFER: val = sk->protinfo.rose->defer; @@ -1056,7 +1059,7 @@ SOCK_DEBUG(sk, "ROSE: sendto: building packet.\n"); size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN; - if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) + if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) return err; skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN); @@ -1118,7 +1121,7 @@ frontlen = skb_headroom(skb); while (skb->len > 0) { - if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_PACLEN, 0, 0, &err)) == NULL) + if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_PACLEN, 0, &err)) == NULL) return err; skbn->sk = sk; @@ -1392,8 +1395,8 @@ } static struct net_proto_family rose_family_ops = { - PF_ROSE, - rose_create + family: PF_ROSE, + create: rose_create, }; static struct proto_ops SOCKOPS_WRAPPED(rose_proto_ops) = { @@ -1414,24 +1417,31 @@ sendmsg: rose_sendmsg, recvmsg: rose_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #include <linux/smp_lock.h> SOCKOPS_WRAP(rose_proto, PF_ROSE); static struct notifier_block rose_dev_notifier = { - rose_device_event, - 0 + notifier_call: rose_device_event, }; static struct net_device *dev_rose; +static const char banner[] = KERN_INFO "F6FBB/G4KLX ROSE for Linux. Version 0.62 for AX25.037 Linux 2.4\n"; + static int __init rose_proto_init(void) { int i; rose_callsign = null_ax25_address; + if (rose_ndevs > 0x7FFFFFFF/sizeof(struct net_device)) { + printk(KERN_ERR "ROSE: rose_proto_init - rose_ndevs parameter to large\n"); + return -1; + } + if ((dev_rose = kmalloc(rose_ndevs * sizeof(struct net_device), GFP_KERNEL)) == NULL) { printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate device structure\n"); return -1; @@ -1447,7 +1457,7 @@ sock_register(&rose_family_ops); register_netdevice_notifier(&rose_dev_notifier); - printk(KERN_INFO "F6FBB/G4KLX ROSE for Linux. Version 0.62 for AX25.037 Linux 2.4\n"); + printk(banner); ax25_protocol_register(AX25_P_ROSE, rose_route_frame); ax25_linkfail_register(rose_link_failed); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/socket.c linux.ac/net/socket.c --- linux.vanilla/net/socket.c Fri Nov 17 19:36:27 2000 +++ linux.ac/net/socket.c Sat Apr 14 01:52:18 2001 @@ -71,6 +71,7 @@ #include <linux/poll.h> #include <linux/cache.h> #include <linux/module.h> +#include <linux/highmem.h> #if defined(CONFIG_KMOD) && defined(CONFIG_NET) #include <linux/kmod.h> @@ -104,6 +105,8 @@ unsigned long count, loff_t *ppos); static ssize_t sock_writev(struct file *file, const struct iovec *vector, unsigned long count, loff_t *ppos); +static ssize_t sock_writepage(struct file *file, struct page *page, + int offset, size_t size, loff_t *ppos, int more); /* @@ -122,7 +125,8 @@ release: sock_close, fasync: sock_fasync, readv: sock_readv, - writev: sock_writev + writev: sock_writev, + writepage: sock_writepage }; /* @@ -602,6 +606,24 @@ return sock_sendmsg(sock, &msg, size); } +ssize_t sock_writepage(struct file *file, struct page *page, + int offset, size_t size, loff_t *ppos, int more) +{ + struct socket *sock; + int flags; + + if (ppos != &file->f_pos) + return -ESPIPE; + + sock = socki_lookup(file->f_dentry->d_inode); + + flags = !(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT; + if (more) + flags |= MSG_MORE; + + return sock->ops->sendpage(sock, page, offset, size, flags); +} + int sock_readv_writev(int type, struct inode * inode, struct file * file, const struct iovec * iov, long count, long size) { @@ -1269,7 +1291,10 @@ { int err; struct socket *sock; - + + if (optlen < 0) + return -EINVAL; + if ((sock = sockfd_lookup(fd, &err))!=NULL) { if (level == SOL_SOCKET) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/sunrpc/clnt.c linux.ac/net/sunrpc/clnt.c --- linux.vanilla/net/sunrpc/clnt.c Fri Feb 9 19:29:44 2001 +++ linux.ac/net/sunrpc/clnt.c Tue Apr 3 17:55:22 2001 @@ -694,9 +694,14 @@ } if (task->tk_status < 12) { - printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n", - clnt->cl_protname, task->tk_status); - rpc_exit(task, -EIO); + if (!clnt->cl_softrtry) { + task->tk_action = call_transmit; + clnt->cl_stats->rpcretrans++; + } else { + printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n", + clnt->cl_protname, task->tk_status); + rpc_exit(task, -EIO); + } return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/sunrpc/sched.c linux.ac/net/sunrpc/sched.c --- linux.vanilla/net/sunrpc/sched.c Fri Feb 9 19:29:44 2001 +++ linux.ac/net/sunrpc/sched.c Tue Apr 10 18:27:38 2001 @@ -1072,6 +1072,8 @@ current->pgrp = 1; strcpy(current->comm, "rpciod"); + current->flags |= PF_MEMALLOC; + dprintk("RPC: rpciod starting (pid %d)\n", rpciod_pid); while (rpciod_users) { if (signalled()) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/sunrpc/svcsock.c linux.ac/net/sunrpc/svcsock.c --- linux.vanilla/net/sunrpc/svcsock.c Tue Apr 3 17:32:31 2001 +++ linux.ac/net/sunrpc/svcsock.c Sat Apr 14 01:52:29 2001 @@ -381,10 +381,17 @@ dprintk("svc: recvfrom returned error %d\n", -err); } + /* Sorry. */ + if (skb_is_nonlinear(skb)) { + if (skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + svc_sock_received(svsk, 0); + return 0; + } + } + if (skb->ip_summed != CHECKSUM_UNNECESSARY) { - unsigned int csum = skb->csum; - csum = csum_partial(skb->h.raw, skb->len, csum); - if ((unsigned short)csum_fold(csum)) { + if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) { skb_free_datagram(svsk->sk_sk, skb); svc_sock_received(svsk, 0); return 0; @@ -395,7 +402,7 @@ svsk->sk_data = 1; len = skb->len - sizeof(struct udphdr); - data = (u32 *) (skb->h.raw + sizeof(struct udphdr)); + data = (u32 *) (skb->data + sizeof(struct udphdr)); rqstp->rq_skbuff = skb; rqstp->rq_argbuf.base = data; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/sunrpc/sysctl.c linux.ac/net/sunrpc/sysctl.c --- linux.vanilla/net/sunrpc/sysctl.c Mon Oct 2 04:35:16 2000 +++ linux.ac/net/sunrpc/sysctl.c Tue Apr 3 17:55:22 2001 @@ -63,7 +63,7 @@ { char tmpbuf[20], *p, c; unsigned int value; - int left, len; + size_t left, len; if ((file->f_pos && !write) || !*lenp) { *lenp = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/sunrpc/xprt.c linux.ac/net/sunrpc/xprt.c --- linux.vanilla/net/sunrpc/xprt.c Fri Feb 9 19:29:44 2001 +++ linux.ac/net/sunrpc/xprt.c Sat Apr 14 01:52:34 2001 @@ -591,7 +591,7 @@ struct sk_buff *skb, int copied) { - __u8 *pkt_data = skb->h.raw + sizeof(struct udphdr); + int offset = sizeof(struct udphdr); __u8 *cur_ptr = iov->iov_base; __kernel_size_t cur_len = iov->iov_len; unsigned int csum = skb->csum; @@ -599,18 +599,18 @@ int slack = skb->len - copied - sizeof(struct udphdr); if (need_csum) - csum = csum_partial(skb->h.raw, sizeof(struct udphdr), csum); + csum = csum_partial(skb->data, sizeof(struct udphdr), csum); while (copied > 0) { if (cur_len) { int to_move = cur_len; if (to_move > copied) to_move = copied; if (need_csum) - csum = csum_partial_copy_nocheck(pkt_data, cur_ptr, - to_move, csum); + csum = skb_copy_and_csum_bits(skb, offset, cur_ptr, + to_move, csum); else - memcpy(cur_ptr, pkt_data, to_move); - pkt_data += to_move; + skb_copy_bits(skb, offset, cur_ptr, to_move); + offset += to_move; copied -= to_move; cur_ptr += to_move; cur_len -= to_move; @@ -623,7 +623,7 @@ } if (need_csum) { if (slack > 0) - csum = csum_partial(pkt_data, slack, csum); + csum = skb_checksum(skb, offset, slack, csum); if ((unsigned short)csum_fold(csum)) return -1; } @@ -1116,6 +1116,7 @@ struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt; struct rpc_rqst *req = task->tk_rqstp; + spin_lock_bh(&xprt_sock_lock); spin_lock(&xprt_lock); if (xprt->snd_task && xprt->snd_task != task) { dprintk("RPC: %4d TCP write queue full (task %d)\n", @@ -1131,6 +1132,7 @@ req->rq_bytes_sent = 0; } spin_unlock(&xprt_lock); + spin_unlock_bh(&xprt_sock_lock); return xprt->snd_task == task; } @@ -1143,10 +1145,12 @@ struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt; if (xprt->snd_task && xprt->snd_task == task) { + spin_lock_bh(&xprt_sock_lock); spin_lock(&xprt_lock); xprt->snd_task = NULL; rpc_wake_up_next(&xprt->sending); spin_unlock(&xprt_lock); + spin_unlock_bh(&xprt_sock_lock); } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/sysctl_net.c linux.ac/net/sysctl_net.c --- linux.vanilla/net/sysctl_net.c Tue Apr 3 17:32:31 2001 +++ linux.ac/net/sysctl_net.c Tue Apr 3 17:55:22 2001 @@ -34,10 +34,6 @@ extern ctl_table tr_table[]; #endif -#ifdef CONFIG_ECONET -extern ctl_table econet_table[]; -#endif - ctl_table net_table[] = { {NET_CORE, "core", NULL, 0, 0555, core_table}, #ifdef CONFIG_NET @@ -52,9 +48,6 @@ #endif #ifdef CONFIG_TR {NET_TR, "token-ring", NULL, 0, 0555, tr_table}, -#endif -#ifdef CONFIG_ECONET - {NET_ECONET, "econet", NULL, 0, 0555, econet_table}, #endif {0} }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/unix/af_unix.c linux.ac/net/unix/af_unix.c --- linux.vanilla/net/unix/af_unix.c Tue Apr 3 17:32:31 2001 +++ linux.ac/net/unix/af_unix.c Sat Apr 14 01:52:49 2001 @@ -8,7 +8,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version: $Id: af_unix.c,v 1.111 2001/02/02 11:37:28 davem Exp $ + * Version: $Id: af_unix.c,v 1.116 2001/03/03 01:20:11 davem Exp $ * * Fixes: * Linus Torvalds : Assorted bug cures. @@ -1182,7 +1182,7 @@ if ((unsigned)len > sk->sndbuf - 32) goto out; - skb = sock_alloc_send_skb(sk, len, 0, msg->msg_flags&MSG_DONTWAIT, &err); + skb = sock_alloc_send_skb(sk, len, msg->msg_flags&MSG_DONTWAIT, &err); if (skb==NULL) goto out; @@ -1285,7 +1285,6 @@ struct sockaddr_un *sunaddr=msg->msg_name; int err,size; struct sk_buff *skb; - int limit=0; int sent=0; err = -EOPNOTSUPP; @@ -1319,25 +1318,19 @@ if (size > sk->sndbuf/2 - 64) size = sk->sndbuf/2 - 64; - if (size > (128 * 1024) / 2) - size = (128 * 1024) / 2; - - /* - * Keep to page sized kmalloc()'s as various people - * have suggested. Big mallocs stress the vm too - * much. - */ - - if (size > PAGE_SIZE-16) - limit = PAGE_SIZE-16; /* Fall back to a page if we can't grab a big buffer this instant */ - else - limit = 0; /* Otherwise just grab and wait */ + /* Until we figure a better way to express this goal. Its + arguable btw that it should be based on the size of the + cache / 2 * number of colours */ +#define KMALLOC_MAXSIZE 131072 + if( size > KMALLOC_MAXSIZE / 2) + size = KMALLOC_MAXSIZE / 2; + /* * Grab a buffer */ - skb=sock_alloc_send_skb(sk,size,limit,msg->msg_flags&MSG_DONTWAIT, &err); + skb=sock_alloc_send_skb(sk,size,msg->msg_flags&MSG_DONTWAIT, &err); if (skb==NULL) goto out_err; @@ -1821,6 +1814,7 @@ sendmsg: unix_stream_sendmsg, recvmsg: unix_stream_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; struct proto_ops unix_dgram_ops = { @@ -1841,6 +1835,7 @@ sendmsg: unix_dgram_sendmsg, recvmsg: unix_dgram_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; struct net_proto_family unix_family_ops = { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/wanrouter/Makefile linux.ac/net/wanrouter/Makefile --- linux.vanilla/net/wanrouter/Makefile Fri Dec 29 22:07:24 2000 +++ linux.ac/net/wanrouter/Makefile Sat Apr 14 01:53:03 2001 @@ -12,7 +12,7 @@ export-objs := wanmain.o obj-y := wanproc.o wanmain.o -obj-m := $(O_TARGET) +obj-m := $(O_TARGET) af_wanpipe.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/wanrouter/af_wanpipe.c linux.ac/net/wanrouter/af_wanpipe.c --- linux.vanilla/net/wanrouter/af_wanpipe.c Thu Jan 1 01:00:00 1970 +++ linux.ac/net/wanrouter/af_wanpipe.c Sat Apr 14 01:53:03 2001 @@ -0,0 +1,2765 @@ +/***************************************************************************** +* af_wanpipe.c WANPIPE(tm) Secure Socket Layer. +* +* Author: Nenad Corbic <ncorbic@sangoma.com> +* +* Copyright: (c) 2000 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Due Credit: +* Wanpipe socket layer is based on Packet and +* the X25 socket layers. The above sockets were +* used for the specific use of Sangoma Technoloiges +* API programs. +* Packet socket Authors: Ross Biro, Fred N. van Kempen and +* Alan Cox. +* X25 socket Author: Jonathan Naylor. +* ============================================================================ +* Apr 25, 2000 Nenad Corbic o Added the ability to send zero length packets. +* Mar 13, 2000 Nenad Corbic o Added a tx buffer check via ioctl call. +* Mar 06, 2000 Nenad Corbic o Fixed the corrupt sock lcn problem. +* Server and client applicaton can run +* simultaneously without conflicts. +* Feb 29, 2000 Nenad Corbic o Added support for PVC protocols, such as +* CHDLC, Frame Relay and HDLC API. +* Jan 17, 2000 Nenad Corbic o Initial version, based on AF_PACKET socket. +* X25API support only. +* +******************************************************************************/ + +#include <linux/version.h> +#include <linux/config.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/fcntl.h> +#include <linux/socket.h> +#include <linux/in.h> +#include <linux/inet.h> +#include <linux/netdevice.h> +#include <linux/poll.h> +#include <linux/wireless.h> +#include <linux/kmod.h> +#include <net/ip.h> +#include <net/protocol.h> +#include <linux/skbuff.h> +#include <net/sock.h> +#include <linux/errno.h> +#include <linux/timer.h> +#include <asm/system.h> +#include <asm/uaccess.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/wanpipe.h> +#include <linux/if_wanpipe.h> +#include <linux/pkt_sched.h> +#include <linux/tcp.h> +#include <linux/if_wanpipe_common.h> +#include <linux/sdla_x25.h> + +#ifdef CONFIG_INET +#include <net/inet_common.h> +#endif + +#define SLOW_BACKOFF 0.1*HZ +#define FAST_BACKOFF 0.01*HZ + +//#define PRINT_DEBUG +#ifdef PRINT_DEBUG + #define DBG_PRINTK(format, a...) printk(format, ## a) +#else + #define DBG_PRINTK(format, a...) +#endif + +#if defined(LINUX_2_1) + #define dev_put(a) + #define __sock_put(a) + #define sock_hold(a) + #define DECLARE_WAITQUEUE(a,b) \ + struct wait_queue a = { b, NULL } +#endif + +/* SECURE SOCKET IMPLEMENTATION + * + * TRANSMIT: + * + * When the user sends a packet via send() system call + * the wanpipe_sendmsg() function is executed. + * + * Each packet is enqueud into sk->write_queue transmit + * queue. When the packet is enqueued, a delayed transmit + * timer is triggerd which acts as a Bottom Half hander. + * + * wanpipe_delay_transmit() function (BH), dequeues packets + * from the sk->write_queue transmit queue and sends it + * to the deriver via dev->hard_start_xmit(skb, dev) function. + * Note, this function is actual a function pointer of if_send() + * routine in the wanpipe driver. + * + * X25API GUARANTEED DELIVERY: + * + * In order to provide 100% guaranteed packet delivery, + * an atomic 'packet_sent' counter is implemented. Counter + * is incremented for each packet enqueued + * into sk->write_queue. Counter is decremented each + * time wanpipe_delayed_transmit() function successfuly + * passes the packet to the driver. Before each send(), a poll + * routine checks the sock resources The maximum value of + * packet sent counter is 1, thus if one packet is queued, the + * application will block untill that packet is passed to the + * driver. + * + * RECEIVE: + * + * Wanpipe device drivers call the socket bottom half + * function, wanpipe_rcv() to queue the incoming packets + * into an AF_WANPIPE socket queue. Based on wanpipe_rcv() + * return code, the driver knows whether the packet was + * sucessfully queued. If the socket queue is full, + * protocol flow control is used by the driver, if any, + * to slow down the traffic untill the sock queue is free. + * + * Every time a packet arrives into a socket queue the + * socket wakes up processes which are waiting to receive + * data. + * + * If the socket queue is full, the driver sets a block + * bit which signals the socket to kick the wanpipe driver + * bottom half hander when the socket queue is partialy + * empty. wanpipe_recvmsg() function performs this action. + * + * In case of x25api, packets will never be dropped, since + * flow control is available. + * + * In case of streaming protocols like CHDLC, packets will + * be dropped but the statistics will be generated. + */ + + +/* The code below is used to test memory leaks. It prints out + * a message every time kmalloc and kfree system calls get executed. + * If the calls match there is no leak :) + */ + +/***********FOR DEBUGGING PURPOSES********************************************* +#define KMEM_SAFETYZONE 8 + +static void * dbg_kmalloc(unsigned int size, int prio, int line) { + void * v = kmalloc(size,prio); + printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); + return v; +} +static void dbg_kfree(void * v, int line) { + printk(KERN_INFO "line %d kfree(%p)\n",line,v); + kfree(v); +} + +#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) +#define kfree(x) dbg_kfree(x,__LINE__) +******************************************************************************/ + + +/* List of all wanpipe sockets. */ +struct sock * wanpipe_sklist = NULL; +static rwlock_t wanpipe_sklist_lock = RW_LOCK_UNLOCKED; + +atomic_t wanpipe_socks_nr; +static unsigned long wanpipe_tx_critical=0; + +#if 0 +/* Private wanpipe socket structures. */ +struct wanpipe_opt +{ + void *mbox; /* Mail box */ + void *card; /* Card bouded to */ + netdevice_t *dev; /* Bounded device */ + unsigned short lcn; /* Binded LCN */ + unsigned char svc; /* 0=pvc, 1=svc */ + unsigned char timer; /* flag for delayed transmit*/ + struct timer_list tx_timer; + unsigned poll_cnt; + unsigned char force; /* Used to force sock release */ + atomic_t packet_sent; +}; +#endif + +static int sk_count=0; +extern struct proto_ops wanpipe_ops; +static unsigned long find_free_critical=0; + +static void wanpipe_unlink_driver (struct sock *); +static void wanpipe_link_driver (netdevice_t *,struct sock *sk); +static void wanpipe_wakeup_driver(struct sock *sk); +static int execute_command(struct sock *, unsigned char, unsigned int); +static int check_dev (netdevice_t *, sdla_t *); +netdevice_t * wanpipe_find_free_dev (sdla_t *); +static void wanpipe_unlink_card (struct sock *); +static int wanpipe_link_card (struct sock *); +static struct sock *wanpipe_make_new(struct sock *); +static struct sock *wanpipe_alloc_socket(void); +static inline int get_atomic_device (netdevice_t *); +static int wanpipe_exec_cmd(struct sock *, int, unsigned int); +static int get_ioctl_cmd (struct sock *, void *); +static int set_ioctl_cmd (struct sock *, void *); +static void release_device (netdevice_t *); +static void wanpipe_kill_sock_timer (unsigned long data); +static void wanpipe_kill_sock_irq (struct sock *); +static void wanpipe_kill_sock_accept (struct sock *); +static int wanpipe_do_bind(struct sock *, netdevice_t *, int); +struct sock * get_newsk_from_skb (struct sk_buff *); +static int wanpipe_debug (struct sock *, void *); +static void wanpipe_delayed_transmit (unsigned long data); +static void release_driver(struct sock *); +static void start_cleanup_timer (struct sock *); +static void check_write_queue(struct sock *); +static int check_driver_busy (struct sock *); + +/*============================================================ + * wanpipe_rcv + * + * Wanpipe socket bottom half handler. This function + * is called by the WANPIPE device drivers to queue a + * incomming packet into the socket receive queue. + * Once the packet is queued, all processes waiting to + * read are woken up. + * + * During socket bind, this function is bounded into + * WANPIPE driver private. + *===========================================================*/ + +static int wanpipe_rcv(struct sk_buff *skb, netdevice_t *dev, struct sock *sk) +{ + struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)skb->cb; + wanpipe_common_t *chan = dev->priv; + /* + * When we registered the protocol we saved the socket in the data + * field for just this event. + */ + + skb->dev = dev; + + sll->sll_family = AF_WANPIPE; + sll->sll_hatype = dev->type; + sll->sll_protocol = skb->protocol; + sll->sll_pkttype = skb->pkt_type; + sll->sll_ifindex = dev->ifindex; + sll->sll_halen = 0; + + if (dev->hard_header_parse) + sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); + + /* + * WAN_PACKET_DATA : Data which should be passed up the receive queue. + * WAN_PACKET_ASYC : Asynchronous data like place call, which should + * be passed up the listening sock. + * WAN_PACKET_ERR : Asynchronous data like clear call or restart + * which should go into an error queue. + */ + switch (skb->pkt_type){ + + case WAN_PACKET_DATA: + if (sock_queue_rcv_skb(sk,skb)<0){ + return -ENOMEM; + } + break; + case WAN_PACKET_CMD: + sk->state = chan->state; + /* Bug fix: update Mar6. + * Do not set the sock lcn number here, since + * cmd is not guaranteed to be executed on the + * board, thus Lcn could be wrong */ + sk->data_ready(sk,skb->len); + kfree_skb(skb); + break; + case WAN_PACKET_ERR: + sk->state = chan->state; + if (sock_queue_err_skb(sk,skb)<0){ + return -ENOMEM; + } + break; + default: + printk(KERN_INFO "wansock: BH Illegal Packet Type Dropping\n"); + kfree_skb(skb); + break; + } + +//?????????????????????? +// if (sk->state == WANSOCK_DISCONNECTED){ +// if (sk->zapped){ +// //printk(KERN_INFO "wansock: Disconnected, killing early\n"); +// wanpipe_unlink_driver(sk); +// sk->bound_dev_if = 0; +// } +// } + + return 0; +} + +/*============================================================ + * wanpipe_listen_rcv + * + * Wanpipe LISTEN socket bottom half handler. This function + * is called by the WANPIPE device drivers to queue an + * incomming call into the socket listening queue. + * Once the packet is queued, the waiting accept() process + * is woken up. + * + * During socket bind, this function is bounded into + * WANPIPE driver private. + * + * IMPORTANT NOTE: + * The accept call() is waiting for an skb packet + * which contains a pointer to a device structure. + * + * When we do a bind to a device structre, we + * bind a newly created socket into "chan->sk". Thus, + * when accept receives the skb packet, it will know + * from which dev it came form, and in turn it will know + * the address of the new sock. + * + * NOTE: This function gets called from driver ISR. + *===========================================================*/ + +static int wanpipe_listen_rcv (struct sk_buff *skb, struct sock *sk) +{ + + struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)skb->cb; + struct sock *newsk; + netdevice_t *dev; + sdla_t *card; + mbox_cmd_t *mbox_ptr; + wanpipe_common_t *chan; + + /* Find a free device, if none found, all svc's are busy + */ + + card = (sdla_t*)sk->protinfo.af_wanpipe->card; + if (!card){ + printk(KERN_INFO "wansock: LISTEN ERROR, No Card\n"); + return -ENODEV; + } + + dev = wanpipe_find_free_dev(card); + if (!dev){ + printk(KERN_INFO "wansock: LISTEN ERROR, No Free Device\n"); + return -ENODEV; + } + + chan=dev->priv; + chan->state = WANSOCK_CONNECTING; + + /* Allocate a new sock, which accept will bind + * and pass up to the user + */ + if ((newsk = wanpipe_make_new(sk)) == NULL){ + release_device(dev); + return -ENOMEM; + } + + + /* Initialize the new sock structure + */ + newsk->bound_dev_if = dev->ifindex; + newsk->protinfo.af_wanpipe->card = sk->protinfo.af_wanpipe->card; + + /* Insert the sock into the main wanpipe + * sock list. + */ + atomic_inc(&wanpipe_socks_nr); + + /* Allocate and fill in the new Mail Box. Then + * bind the mail box to the sock. It will be + * used by the ioctl call to read call information + * and to execute commands. + */ + if ((mbox_ptr = kmalloc(sizeof(mbox_cmd_t), GFP_ATOMIC)) == NULL) { + wanpipe_kill_sock_irq (newsk); + release_device(dev); + return -ENOMEM; + } + memset(mbox_ptr, 0, sizeof(mbox_cmd_t)); + memcpy(mbox_ptr,skb->data,skb->len); + + /* Register the lcn on which incoming call came + * from. Thus, if we have to clear it, we know + * whic lcn to clear + */ + + newsk->protinfo.af_wanpipe->lcn = mbox_ptr->cmd.lcn; + newsk->protinfo.af_wanpipe->mbox = (void *)mbox_ptr; + + DBG_PRINTK(KERN_INFO "NEWSOCK : Device %s, bind to lcn %i\n", + dev->name,mbox_ptr->cmd.lcn); + + chan->lcn = mbox_ptr->cmd.lcn; + card->u.x.svc_to_dev_map[(chan->lcn%MAX_X25_LCN)] = dev; + + newsk->zapped=0; + newsk->num = htons(X25_PROT); + + if (wanpipe_do_bind(newsk,dev,newsk->num)){ + wanpipe_kill_sock_irq (newsk); + release_device(dev); + return -EINVAL; + } + newsk->state = WANSOCK_CONNECTING; + + + /* Fill in the standard sock address info */ + + sll->sll_family = AF_WANPIPE; + sll->sll_hatype = dev->type; + sll->sll_protocol = skb->protocol; + sll->sll_pkttype = skb->pkt_type; + sll->sll_ifindex = dev->ifindex; + sll->sll_halen = 0; + + skb->dev = dev; + sk->ack_backlog++; + + /* We must do this manually, since the sock_queue_rcv_skb() + * function sets the skb->dev to NULL. However, we use + * the dev field in the accept function.*/ + if (atomic_read(&sk->rmem_alloc) + skb->truesize >= + (unsigned)sk->rcvbuf){ + + wanpipe_unlink_driver(newsk); + wanpipe_kill_sock_irq (newsk); + --sk->ack_backlog; + return -ENOMEM; + } + + skb_set_owner_r(skb, sk); + skb_queue_tail(&sk->receive_queue, skb); + sk->data_ready(sk,skb->len); + + return 0; +} + + + +/*============================================================ + * wanpipe_make_new + * + * Create a new sock, and allocate a wanpipe private + * structure to it. Also, copy the important data + * from the original sock to the new sock. + * + * This function is used by wanpipe_listen_rcv() listen + * bottom half handler. A copy of the listening sock + * is created using this function. + * + *===========================================================*/ + +static struct sock *wanpipe_make_new(struct sock *osk) +{ + struct sock *sk; + + if (osk->type != SOCK_RAW) + return NULL; + + if ((sk = wanpipe_alloc_socket()) == NULL) + return NULL; + + sk->type = osk->type; + sk->socket = osk->socket; + sk->priority = osk->priority; + sk->protocol = osk->protocol; + sk->num = osk->num; + sk->rcvbuf = osk->rcvbuf; + sk->sndbuf = osk->sndbuf; + sk->debug = osk->debug; + sk->state = WANSOCK_CONNECTING; + sk->sleep = osk->sleep; + + return sk; +} + +/*============================================================ + * wanpipe_make_new + * + * Allocate memory for the a new sock, and sock + * private data. + * + * Increment the module use count. + * + * This function is used by wanpipe_create() and + * wanpipe_make_new() functions. + * + *===========================================================*/ + +static struct sock *wanpipe_alloc_socket(void) +{ + struct sock *sk; + struct wanpipe_opt *wan_opt; + + if ((sk = sk_alloc(PF_WANPIPE, GFP_ATOMIC, 1)) == NULL) + return NULL; + + if ((wan_opt = kmalloc(sizeof(struct wanpipe_opt), GFP_ATOMIC)) == NULL) { + sk_free(sk); + return NULL; + } + memset(wan_opt, 0x00, sizeof(struct wanpipe_opt)); + + sk->protinfo.af_wanpipe = wan_opt; + sk->protinfo.destruct_hook = wan_opt; + + /* Use timer to send data to the driver. This will act + * as a BH handler for sendmsg functions */ + sk->protinfo.af_wanpipe->tx_timer.data=(unsigned long)sk; + sk->protinfo.af_wanpipe->tx_timer.function=wanpipe_delayed_transmit; + + MOD_INC_USE_COUNT; + + sock_init_data(NULL, sk); + return sk; +} + + +/*============================================================ + * wanpipe_sendmsg + * + * This function implements a sendto() system call, + * for AF_WANPIPE socket family. + * During socket bind() sk->bound_dev_if is initialized + * to a correct network device. This number is used + * to find a network device to which the packet should + * be passed to. + * + * Each packet is queued into sk->write_queue and + * delayed transmit bottom half handler is marked for + * execution. + * + * A socket must be in WANSOCK_CONNECTED state before + * a packet is queued into sk->write_queue. + *===========================================================*/ + +static int wanpipe_sendmsg(struct socket *sock, struct msghdr *msg, int len, + struct scm_cookie *scm) +{ + struct sock *sk = sock->sk; + struct wan_sockaddr_ll *saddr=(struct wan_sockaddr_ll *)msg->msg_name; + struct sk_buff *skb; + netdevice_t *dev; + unsigned short proto; + unsigned char *addr; + int ifindex, err, reserve = 0; + + + if (!sk->zapped) + return -ENETDOWN; + + if (sk->state != WANSOCK_CONNECTED) + return -ENOTCONN; + + if (msg->msg_flags&~MSG_DONTWAIT) + return(-EINVAL); + + /* it was <=, now one can send + * zero length packets */ + if (len < sizeof(x25api_hdr_t)) + return -EINVAL; + + if (saddr == NULL) { + ifindex = sk->bound_dev_if; + proto = sk->num; + addr = NULL; + + }else{ + if (msg->msg_namelen < sizeof(struct wan_sockaddr_ll)){ + return -EINVAL; + } + + ifindex = sk->bound_dev_if; + proto = saddr->sll_protocol; + addr = saddr->sll_addr; + } + + dev = dev_get_by_index(ifindex); + if (dev == NULL){ + printk(KERN_INFO "wansock: Send failed, dev index: %i\n",ifindex); + return -ENXIO; + } + dev_put(dev); + + if (sock->type == SOCK_RAW) + reserve = dev->hard_header_len; + + if (len > dev->mtu+reserve){ + return -EMSGSIZE; + } + + #ifndef LINUX_2_4 + dev_lock_list(); + #endif + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3) + skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, + msg->msg_flags & MSG_DONTWAIT, &err); + #else + skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0, + msg->msg_flags & MSG_DONTWAIT, &err); + #endif + + if (skb==NULL){ + goto out_unlock; + } + + skb_reserve(skb, (dev->hard_header_len+15)&~15); + skb->nh.raw = skb->data; + + /* Returns -EFAULT on error */ + err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); + if (err){ + goto out_free; + } + + if (dev->hard_header) { + int res; + err = -EINVAL; + res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len); + if (res<0){ + goto out_free; + } + } + + skb->protocol = proto; + skb->dev = dev; + skb->priority = sk->priority; + skb->pkt_type = WAN_PACKET_DATA; + + err = -ENETDOWN; + if (!(dev->flags & IFF_UP)) + goto out_free; + + #ifndef LINUX_2_4 + dev_unlock_list(); + #endif + + if (atomic_read(&sk->wmem_alloc) + skb->truesize > (unsigned int)sk->sndbuf){ + kfree_skb(skb); + return -ENOBUFS; + } + + skb_queue_tail(&sk->write_queue,skb); + atomic_inc(&sk->protinfo.af_wanpipe->packet_sent); + + if (!(test_and_set_bit(0,&sk->protinfo.af_wanpipe->timer))){ + del_timer(&sk->protinfo.af_wanpipe->tx_timer); + sk->protinfo.af_wanpipe->tx_timer.expires=jiffies+1; + add_timer(&sk->protinfo.af_wanpipe->tx_timer); + } + + return(len); + +out_free: + kfree_skb(skb); +out_unlock: +#ifndef LINUX_2_4 + dev_unlock_list(); +#endif + return err; +} + +/*============================================================ + * wanpipe_delayed_tarnsmit + * + * Transmit bottom half handeler. It dequeues packets + * from sk->write_queue and passes them to the + * driver. If the driver is busy, the packet is + * re-enqueued. + * + * Packet Sent counter is decremented on successful + * transmission. + *===========================================================*/ + + +static void wanpipe_delayed_transmit (unsigned long data) +{ + struct sock *sk=(struct sock *)data; + struct sk_buff *skb; + netdevice_t *dev = sk->protinfo.af_wanpipe->dev; + sdla_t *card = (sdla_t*)sk->protinfo.af_wanpipe->card; + + if (!card || !dev){ + clear_bit (0,&sk->protinfo.af_wanpipe->timer); + DBG_PRINTK(KERN_INFO "wansock: Transmit delay, no dev or card\n"); + return; + } + + if (sk->state != WANSOCK_CONNECTED || !sk->zapped){ + clear_bit (0,&sk->protinfo.af_wanpipe->timer); + DBG_PRINTK(KERN_INFO "wansock: Tx Timer, State not CONNECTED\n"); + return; + } + + /* If driver is executing command, we must offload + * the board by not sending data. Otherwise a + * pending command will never get a free buffer + * to execute */ + if (atomic_read(&card->u.x.command_busy)){ + sk->protinfo.af_wanpipe->tx_timer.expires=jiffies+SLOW_BACKOFF; + add_timer(&sk->protinfo.af_wanpipe->tx_timer); + DBG_PRINTK(KERN_INFO "wansock: Tx Timer, command bys BACKOFF\n"); + return; + } + + + if (test_and_set_bit(0,&wanpipe_tx_critical)){ + printk(KERN_INFO "WanSock: Tx timer critical %s\n",dev->name); + sk->protinfo.af_wanpipe->tx_timer.expires=jiffies+SLOW_BACKOFF; + add_timer(&sk->protinfo.af_wanpipe->tx_timer); + return; + } + + /* Check for a packet in the fifo and send */ + if ((skb=skb_dequeue(&sk->write_queue)) != NULL){ + + if (dev->hard_start_xmit(skb, dev) != 0){ + + /* Driver failed to transmit, re-enqueue + * the packet and retry again later */ + skb_queue_head(&sk->write_queue,skb); + clear_bit(0,&wanpipe_tx_critical); + return; + }else{ + + /* Packet Sent successful. Check for more packets + * if more packets, re-trigger the transmit routine + * other wise exit + */ + atomic_dec(&sk->protinfo.af_wanpipe->packet_sent); + + if (skb_peek(&sk->write_queue) == NULL){ + /* If there is nothing to send, kick + * the poll routine, which will trigger + * the application to send more data */ + sk->data_ready(sk,0); + clear_bit (0,&sk->protinfo.af_wanpipe->timer); + }else{ + /* Reschedule as fast as possible */ + sk->protinfo.af_wanpipe->tx_timer.expires=jiffies+1; + add_timer(&sk->protinfo.af_wanpipe->tx_timer); + } + } + } + clear_bit(0,&wanpipe_tx_critical); +} + +/*============================================================ + * execute_command + * + * Execute x25api commands. The atomic variable + * chan->command is used to indicate to the driver that + * command is pending for exection. The acutal command + * structure is placed into a sock mbox structure + * (sk->protinfo.af_wanpipe->mbox). + * + * The sock private structure, mbox is + * used as shared memory between sock and the driver. + * Driver uses the sock mbox to execute the command + * and return the result. + * + * For all command except PLACE CALL, the function + * waits for the result. PLACE CALL can be ether + * blocking or nonblocking. The user sets this option + * via ioctl call. + *===========================================================*/ + + +static int execute_command(struct sock *sk, unsigned char cmd, unsigned int flags) +{ + netdevice_t *dev; + wanpipe_common_t *chan=NULL; + int err=0; + DECLARE_WAITQUEUE(wait, current); + + dev = dev_get_by_index(sk->bound_dev_if); + if (dev == NULL){ + printk(KERN_INFO "wansock: Exec failed no dev %i\n", + sk->bound_dev_if); + return -ENODEV; + } + dev_put(dev); + + if ((chan=dev->priv) == NULL){ + printk(KERN_INFO "wansock: Exec cmd failed no priv area\n"); + return -ENODEV; + } + + if (atomic_read(&chan->command)){ + printk(KERN_INFO "wansock: ERROR: Command already running %x, %s\n", + atomic_read(&chan->command),dev->name); + return -EINVAL; + } + + if (!sk->protinfo.af_wanpipe->mbox){ + printk(KERN_INFO "wansock: In execute without MBOX\n"); + return -EINVAL; + } + + ((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.command=cmd; + ((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.lcn = + sk->protinfo.af_wanpipe->lcn; + ((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.result=0x7F; + + + if (flags & O_NONBLOCK){ + cmd |= 0x80; + atomic_set(&chan->command, cmd); + }else{ + atomic_set(&chan->command, cmd); + } + + add_wait_queue(sk->sleep,&wait); + current->state = TASK_INTERRUPTIBLE; + for (;;){ + if (((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.result != 0x7F) { + err = 0; + break; + } + if (signal_pending(current)) { + err = -ERESTARTSYS; + break; + } + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(sk->sleep,&wait); + + return err; +} + +/*============================================================ + * wanpipe_destroy_timer + * + * Used by wanpipe_release, to delay release of + * the socket. + *===========================================================*/ + +static void wanpipe_destroy_timer(unsigned long data) +{ + struct sock *sk=(struct sock *)data; + + if ((!atomic_read(&sk->wmem_alloc) && !atomic_read(&sk->rmem_alloc)) || + (++sk->protinfo.af_wanpipe->force == 5)) { + + if (atomic_read(&sk->wmem_alloc) || atomic_read(&sk->rmem_alloc)) + printk(KERN_INFO "wansock: Warning, Packet Discarded due to sock shutdown!\n"); + + if (sk->protinfo.af_wanpipe){ + kfree(sk->protinfo.af_wanpipe); + sk->protinfo.af_wanpipe=NULL; + } + + #ifdef LINUX_2_4 + if (atomic_read(&sk->refcnt) != 1){ + atomic_set(&sk->refcnt,1); + DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i ! :delay.\n", + atomic_read(&sk->refcnt)); + } + sock_put(sk); + #else + sk_free(sk); + #endif + atomic_dec(&wanpipe_socks_nr); + MOD_DEC_USE_COUNT; + return; + } + + sk->timer.expires=jiffies+5*HZ; + add_timer(&sk->timer); + printk(KERN_INFO "wansock: packet sk destroy delayed\n"); +} + +/*============================================================ + * wanpipe_unlink_driver + * + * When the socket is released, this function is + * used to remove links that bind the sock and the + * driver together. + *===========================================================*/ +static void wanpipe_unlink_driver (struct sock *sk) +{ + netdevice_t *dev; + wanpipe_common_t *chan=NULL; + + sk->zapped=0; + sk->state = WANSOCK_DISCONNECTED; + sk->protinfo.af_wanpipe->dev = NULL; + + dev = dev_get_by_index(sk->bound_dev_if); + if (!dev){ + printk(KERN_INFO "wansock: No dev on release\n"); + return; + } + dev_put(dev); + + if ((chan = dev->priv) == NULL){ + printk(KERN_INFO "wansock: No Priv Area on release\n"); + return; + } + + set_bit(0,&chan->common_critical); + chan->sk=NULL; + chan->func=NULL; + chan->mbox=NULL; + chan->tx_timer=NULL; + clear_bit(0,&chan->common_critical); + release_device(dev); + + return; +} + +/*============================================================ + * wanpipe_link_driver + * + * Upon successful bind(), sock is linked to a driver + * by binding in the wanpipe_rcv() bottom half handler + * to the driver function pointer, as well as sock and + * sock mailbox addresses. This way driver can pass + * data up the socket. + *===========================================================*/ + +static void wanpipe_link_driver (netdevice_t *dev, struct sock *sk) +{ + wanpipe_common_t *chan = dev->priv; + if (!chan) + return; + set_bit(0,&chan->common_critical); + chan->sk=sk; + chan->func=wanpipe_rcv; + chan->mbox=sk->protinfo.af_wanpipe->mbox; + chan->tx_timer = &sk->protinfo.af_wanpipe->tx_timer; + sk->protinfo.af_wanpipe->dev=dev; + sk->zapped = 1; + clear_bit(0,&chan->common_critical); +} + + +/*============================================================ + * release_device + * + * During sock release, clear a critical bit, which + * marks the device a being taken. + *===========================================================*/ + + +static void release_device (netdevice_t *dev) +{ + wanpipe_common_t *chan=dev->priv; + clear_bit(0,(void*)&chan->rw_bind); +} + +/*============================================================ + * wanpipe_release + * + * Close a PACKET socket. This is fairly simple. We + * immediately go to 'closed' state and remove our + * protocol entry in the device list. + *===========================================================*/ + +#ifdef LINUX_2_4 +static int wanpipe_release(struct socket *sock) +#else +static int wanpipe_release(struct socket *sock, struct socket *peersock) +#endif +{ + +#ifndef LINUX_2_4 + struct sk_buff *skb; +#endif + struct sock *sk = sock->sk; + struct sock **skp; + + if (!sk) + return 0; + + check_write_queue(sk); + + /* Kill the tx timer, if we don't kill it now, the timer + * will run after we kill the sock. Timer code will + * try to access the sock which has been killed and cause + * kernel panic */ + + del_timer(&sk->protinfo.af_wanpipe->tx_timer); + + /* + * Unhook packet receive handler. + */ + + if (sk->num == htons(X25_PROT) && sk->state != WANSOCK_DISCONNECTED && sk->zapped){ + netdevice_t *dev = dev_get_by_index(sk->bound_dev_if); + wanpipe_common_t *chan; + if (dev){ + chan=dev->priv; + atomic_set(&chan->disconnect,1); + DBG_PRINTK(KERN_INFO "wansock: Sending Clear Indication %i\n", + sk->state); + dev_put(dev); + } + } + + set_bit(1,&wanpipe_tx_critical); + write_lock(&wanpipe_sklist_lock); + for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->next) { + if (*skp == sk) { + *skp = sk->next; + __sock_put(sk); + break; + } + } + write_unlock(&wanpipe_sklist_lock); + clear_bit(1,&wanpipe_tx_critical); + + + + release_driver(sk); + + + /* + * Now the socket is dead. No more input will appear. + */ + + sk->state_change(sk); /* It is useless. Just for sanity. */ + + sock->sk = NULL; + sk->socket = NULL; + sk->dead = 1; + + /* Purge queues */ +#ifdef LINUX_2_4 + skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->write_queue); + skb_queue_purge(&sk->error_queue); +#else + + while ((skb=skb_dequeue(&sk->receive_queue))!=NULL){ + kfree_skb(skb); + } + while ((skb=skb_dequeue(&sk->error_queue))!=NULL){ + kfree_skb(skb); + } + while ((skb=skb_dequeue(&sk->write_queue))!=NULL){ + kfree_skb(skb); + } +#endif + if (atomic_read(&sk->rmem_alloc) || atomic_read(&sk->wmem_alloc)) { + del_timer(&sk->timer); + printk(KERN_INFO "wansock: Killing in Timer R %i , W %i\n", + atomic_read(&sk->rmem_alloc),atomic_read(&sk->wmem_alloc)); + sk->timer.data=(unsigned long)sk; + sk->timer.expires=jiffies+HZ; + sk->timer.function=wanpipe_destroy_timer; + add_timer(&sk->timer); + return 0; + } + + if (sk->protinfo.af_wanpipe){ + kfree(sk->protinfo.af_wanpipe); + sk->protinfo.af_wanpipe=NULL; + } + + #ifdef LINUX_2_4 + if (atomic_read(&sk->refcnt) != 1){ + DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i !:release.\n", + atomic_read(&sk->refcnt)); + atomic_set(&sk->refcnt,1); + } + sock_put(sk); + #else + sk_free(sk); + #endif + atomic_dec(&wanpipe_socks_nr); + MOD_DEC_USE_COUNT; + return 0; +} + +/*============================================================ + * check_write_queue + * + * During sock shutdown, if the sock state is + * WANSOCK_CONNECTED and there is transmit data + * pending. Wait until data is released + * before proceeding. + *===========================================================*/ + +static void check_write_queue(struct sock *sk) +{ + + if (sk->state != WANSOCK_CONNECTED) + return; + + if (!atomic_read(&sk->wmem_alloc)) + return; + + printk(KERN_INFO "wansock: MAJOR ERROR, Data lost on sock release !!!\n"); + +} + +/*============================================================ + * release_driver + * + * This function is called during sock shutdown, to + * release any resources and links that bind the sock + * to the driver. It also changes the state of the + * sock to WANSOCK_DISCONNECTED + *===========================================================*/ + +static void release_driver(struct sock *sk) +{ + struct sk_buff *skb=NULL; + struct sock *deadsk=NULL; + + if (sk->state == WANSOCK_LISTEN || sk->state == WANSOCK_BIND_LISTEN){ + while ((skb=skb_dequeue(&sk->receive_queue))!=NULL){ + if ((deadsk = get_newsk_from_skb(skb))){ + DBG_PRINTK (KERN_INFO "wansock: RELEASE: FOUND DEAD SOCK\n"); + deadsk->dead=1; + start_cleanup_timer(deadsk); + } + kfree_skb(skb); + } + if (sk->zapped) + wanpipe_unlink_card(sk); + }else{ + if (sk->zapped) + wanpipe_unlink_driver(sk); + } + sk->state = WANSOCK_DISCONNECTED; + sk->bound_dev_if = 0; + sk->zapped=0; + + if (sk->protinfo.af_wanpipe){ + if (sk->protinfo.af_wanpipe->mbox){ + kfree(sk->protinfo.af_wanpipe->mbox); + sk->protinfo.af_wanpipe->mbox=NULL; + } + } +} + +/*============================================================ + * start_cleanup_timer + * + * If new incoming call's are pending but the socket + * is being released, start the timer which will + * envoke the kill routines for pending socks. + *===========================================================*/ + + +static void start_cleanup_timer (struct sock *sk) +{ + del_timer(&sk->timer); + sk->timer.data = (unsigned long)sk; + sk->timer.expires = jiffies + HZ; + sk->timer.function = wanpipe_kill_sock_timer; + add_timer(&sk->timer); +} + + +/*============================================================ + * wanpipe_kill_sock + * + * This is a function which performs actual killing + * of the sock. It releases socket resources, + * and unlinks the sock from the driver. + *===========================================================*/ + +static void wanpipe_kill_sock_timer (unsigned long data) +{ + + struct sock *sk = (struct sock *)data; +#ifndef LINUX_2_4 + struct sk_buff *skb; +#endif + + struct sock **skp; + + if (!sk) + return; + + /* This functin can be called from interrupt. We must use + * appropriate locks */ + + if (test_bit(1,&wanpipe_tx_critical)){ + sk->timer.expires=jiffies+10; + add_timer(&sk->timer); + return; + } + + write_lock(&wanpipe_sklist_lock); + for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->next) { + if (*skp == sk) { + *skp = sk->next; + __sock_put(sk); + break; + } + } + write_unlock(&wanpipe_sklist_lock); + + + if (sk->num == htons(X25_PROT) && sk->state != WANSOCK_DISCONNECTED){ + netdevice_t *dev = dev_get_by_index(sk->bound_dev_if); + wanpipe_common_t *chan; + if (dev){ + chan=dev->priv; + atomic_set(&chan->disconnect,1); + dev_put(dev); + } + } + + release_driver(sk); + + sk->socket = NULL; + + /* Purge queues */ +#ifdef LINUX_2_4 + skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->write_queue); + skb_queue_purge(&sk->error_queue); +#else + while ((skb=skb_dequeue(&sk->receive_queue)) != NULL){ + kfree_skb(skb); + } + while ((skb=skb_dequeue(&sk->write_queue)) != NULL) { + kfree_skb(skb); + } + while ((skb=skb_dequeue(&sk->error_queue)) != NULL){ + kfree_skb(skb); + } +#endif + + if (atomic_read(&sk->rmem_alloc) || atomic_read(&sk->wmem_alloc)) { + del_timer(&sk->timer); + printk(KERN_INFO "wansock: Killing SOCK in Timer\n"); + sk->timer.data=(unsigned long)sk; + sk->timer.expires=jiffies+HZ; + sk->timer.function=wanpipe_destroy_timer; + add_timer(&sk->timer); + return; + } + + if (sk->protinfo.af_wanpipe){ + kfree(sk->protinfo.af_wanpipe); + sk->protinfo.af_wanpipe=NULL; + } + + #ifdef LINUX_2_4 + if (atomic_read(&sk->refcnt) != 1){ + atomic_set(&sk->refcnt,1); + DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i ! :timer.\n", + atomic_read(&sk->refcnt)); + } + sock_put(sk); + #else + sk_free(sk); + #endif + atomic_dec(&wanpipe_socks_nr); + MOD_DEC_USE_COUNT; + return; +} + +static void wanpipe_kill_sock_accept (struct sock *sk) +{ + + struct sock **skp; + + if (!sk) + return; + + /* This functin can be called from interrupt. We must use + * appropriate locks */ + + write_lock(&wanpipe_sklist_lock); + for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->next) { + if (*skp == sk) { + *skp = sk->next; + __sock_put(sk); + break; + } + } + write_unlock(&wanpipe_sklist_lock); + + sk->socket = NULL; + + + if (sk->protinfo.af_wanpipe){ + kfree(sk->protinfo.af_wanpipe); + sk->protinfo.af_wanpipe=NULL; + } + + #ifdef LINUX_2_4 + if (atomic_read(&sk->refcnt) != 1){ + atomic_set(&sk->refcnt,1); + DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i ! :timer.\n", + atomic_read(&sk->refcnt)); + } + sock_put(sk); + #else + sk_free(sk); + #endif + atomic_dec(&wanpipe_socks_nr); + MOD_DEC_USE_COUNT; + return; +} + + +static void wanpipe_kill_sock_irq (struct sock *sk) +{ + + if (!sk) + return; + + sk->socket = NULL; + + if (sk->protinfo.af_wanpipe){ + kfree(sk->protinfo.af_wanpipe); + sk->protinfo.af_wanpipe=NULL; + } + + #ifdef LINUX_2_4 + if (atomic_read(&sk->refcnt) != 1){ + atomic_set(&sk->refcnt,1); + DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i !:listen.\n", + atomic_read(&sk->refcnt)); + } + sock_put(sk); + #else + sk_free(sk); + #endif + atomic_dec(&wanpipe_socks_nr); + MOD_DEC_USE_COUNT; + return; +} + + +/*============================================================ + * wanpipe_do_bind + * + * Bottom half of the binding system call. + * Once the wanpipe_bind() function checks the + * legality of the call, this function binds the + * sock to the driver. + *===========================================================*/ + +static int wanpipe_do_bind(struct sock *sk, netdevice_t *dev, int protocol) +{ + wanpipe_common_t *chan=NULL; + int err=0; + + if (sk->zapped){ + err = -EALREADY; + goto bind_unlock_exit; + } + + sk->num = protocol; + + if (protocol == 0){ + release_device(dev); + err = -EINVAL; + goto bind_unlock_exit; + } + + if (dev) { + if (dev->flags&IFF_UP) { + chan=dev->priv; + sk->state = chan->state; + + if (sk->num == htons(X25_PROT) && + sk->state != WANSOCK_DISCONNECTED && + sk->state != WANSOCK_CONNECTING){ + DBG_PRINTK(KERN_INFO + "wansock: Binding to Device not DISCONNECTED %i\n", + sk->state); + release_device(dev); + err = -EAGAIN; + goto bind_unlock_exit; + } + + wanpipe_link_driver(dev,sk); + sk->bound_dev_if = dev->ifindex; + + /* X25 Specific option */ + if (sk->num == htons(X25_PROT)) + sk->protinfo.af_wanpipe->svc = chan->svc; + + } else { + sk->err = ENETDOWN; + sk->error_report(sk); + release_device(dev); + err = -EINVAL; + } + } else { + err = -ENODEV; + } +bind_unlock_exit: + /* FIXME where is this lock */ + + return err; +} + +/*============================================================ + * wanpipe_bind + * + * BIND() System call, which is bound to the AF_WANPIPE + * operations structure. It checks for correct wanpipe + * card name, and cross references interface names with + * the card names. Thus, interface name must belong to + * the actual card. + *===========================================================*/ + + +static int wanpipe_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) +{ + struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)uaddr; + struct sock *sk=sock->sk; + netdevice_t *dev = NULL; + sdla_t *card=NULL; + char name[15]; + + /* + * Check legality + */ + + if (addr_len < sizeof(struct wan_sockaddr_ll)){ + printk(KERN_INFO "wansock: Address length error\n"); + return -EINVAL; + } + if (sll->sll_family != AF_WANPIPE){ + printk(KERN_INFO "wansock: Illegal family name specified.\n"); + return -EINVAL; + } + + card = wanpipe_find_card (sll->sll_card); + if (!card){ + printk(KERN_INFO "wansock: Wanpipe card not found: %s\n",sll->sll_card); + return -ENODEV; + }else{ + sk->protinfo.af_wanpipe->card = (void *)card; + } + + if (!strcmp(sll->sll_device,"svc_listen")){ + + /* Bind a sock to a card structure for listening + */ + int err=0; + + /* This is x25 specific area if protocol doesn't + * match, return error */ + if (sll->sll_protocol != htons(X25_PROT)) + return -EINVAL; + + err= wanpipe_link_card (sk); + if (err < 0) + return err; + + if (sll->sll_protocol) + sk->num = sll->sll_protocol; + sk->state = WANSOCK_BIND_LISTEN; + return 0; + + }else if (!strcmp(sll->sll_device,"svc_connect")){ + + /* This is x25 specific area if protocol doesn't + * match, return error */ + if (sll->sll_protocol != htons(X25_PROT)) + return -EINVAL; + + /* Find a free device + */ + dev = wanpipe_find_free_dev(card); + if (dev == NULL){ + DBG_PRINTK(KERN_INFO "wansock: No free network devices for card %s\n", + card->devname); + return -EINVAL; + } + }else{ + /* Bind a socket to a interface name + * This is used by PVC mostly + */ + strncpy(name,sll->sll_device,14); + name[14]=0; +#ifdef LINUX_2_4 + dev = dev_get_by_name(name); +#else + dev = dev_get(name); +#endif + if (dev == NULL){ + printk(KERN_INFO "wansock: Failed to get Dev from name: %s,\n", + name); + return -ENODEV; + } + + dev_put(dev); + + if (check_dev(dev, card)){ + printk(KERN_INFO "wansock: Device %s, doesn't belong to card %s\n", + dev->name, card->devname); + return -EINVAL; + } + if (get_atomic_device (dev)) + return -EINVAL; + } + + return wanpipe_do_bind(sk, dev, sll->sll_protocol ? : sk->num); +} + +/*============================================================ + * get_atomic_device + * + * Sets a bit atomically which indicates that + * the interface is taken. This avoids race conditions. + *===========================================================*/ + + +static inline int get_atomic_device (netdevice_t *dev) +{ + wanpipe_common_t *chan = dev->priv; + if (!test_and_set_bit(0,(void *)&chan->rw_bind)){ + return 0; + } + return 1; +} + +/*============================================================ + * check_dev + * + * Check that device name belongs to a particular card. + *===========================================================*/ + +static int check_dev (netdevice_t *dev, sdla_t *card) +{ + netdevice_t* tmp_dev; + + for (tmp_dev = card->wandev.dev; tmp_dev; tmp_dev=*((netdevice_t**)tmp_dev->priv)){ + if (tmp_dev->ifindex == dev->ifindex){ + return 0; + } + } + return 1; +} + +/*============================================================ + * wanpipe_find_free_dev + * + * Find a free network interface. If found set atomic + * bit indicating that the interface is taken. + * X25API Specific. + *===========================================================*/ + +netdevice_t * wanpipe_find_free_dev (sdla_t *card) +{ + netdevice_t* dev; + volatile wanpipe_common_t *chan; + + if (test_and_set_bit(0,&find_free_critical)){ + printk(KERN_INFO "CRITICAL in Find Free\n"); + } + + for (dev = card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){ + chan = dev->priv; + if (!chan) + continue; + if (chan->usedby == API && chan->svc){ + if (!get_atomic_device (dev)){ + if (chan->state != WANSOCK_DISCONNECTED){ + release_device(dev); + }else{ + clear_bit(0,&find_free_critical); + return dev; + } + } + } + } + clear_bit(0,&find_free_critical); + return NULL; +} + +/*============================================================ + * wanpipe_create + * + * SOCKET() System call. It allocates a sock structure + * and adds the socket to the wanpipe_sk_list. + * Crates AF_WANPIPE socket. + *===========================================================*/ + +static int wanpipe_create(struct socket *sock, int protocol) +{ + struct sock *sk; + + //FIXME: This checks for root user, SECURITY ? + //if (!capable(CAP_NET_RAW)) + // return -EPERM; + + if (sock->type != SOCK_DGRAM && sock->type != SOCK_RAW) + return -ESOCKTNOSUPPORT; + + sock->state = SS_UNCONNECTED; + + if ((sk = wanpipe_alloc_socket()) == NULL) + return -ENOBUFS; + + sk->reuse = 1; + sock->ops = &wanpipe_ops; + sock_init_data(sock,sk); + + sk->zapped=0; + sk->family = PF_WANPIPE; + sk->num = protocol; + sk->state = WANSOCK_DISCONNECTED; + sk->ack_backlog = 0; + sk->bound_dev_if=0; + + atomic_inc(&wanpipe_socks_nr); + + /* We must disable interrupts because the ISR + * can also change the list */ + set_bit(1,&wanpipe_tx_critical); + write_lock(&wanpipe_sklist_lock); + sk->next = wanpipe_sklist; + wanpipe_sklist = sk; + sock_hold(sk); + write_unlock(&wanpipe_sklist_lock); + clear_bit(1,&wanpipe_tx_critical); + + return(0); +} + + +/*============================================================ + * wanpipe_recvmsg + * + * Pull a packet from our receive queue and hand it + * to the user. If necessary we block. + *===========================================================*/ + +static int wanpipe_recvmsg(struct socket *sock, struct msghdr *msg, int len, + int flags, struct scm_cookie *scm) +{ + struct sock *sk = sock->sk; + struct sk_buff *skb; + int copied, err=-ENOBUFS; + + + /* + * If the address length field is there to be filled in, we fill + * it in now. + */ + + msg->msg_namelen = sizeof(struct wan_sockaddr_ll); + + /* + * Call the generic datagram receiver. This handles all sorts + * of horrible races and re-entrancy so we can forget about it + * in the protocol layers. + * + * Now it will return ENETDOWN, if device have just gone down, + * but then it will block. + */ + + if (flags & MSG_OOB){ + skb=skb_dequeue(&sk->error_queue); + }else{ + skb=skb_recv_datagram(sk,flags,1,&err); + } + /* + * An error occurred so return it. Because skb_recv_datagram() + * handles the blocking we don't see and worry about blocking + * retries. + */ + + if(skb==NULL) + goto out; + + /* + * You lose any data beyond the buffer you gave. If it worries a + * user program they can ask the device for its MTU anyway. + */ + + copied = skb->len; + if (copied > len) + { + copied=len; + msg->msg_flags|=MSG_TRUNC; + } + + wanpipe_wakeup_driver(sk); + + /* We can't use skb_copy_datagram here */ + err = memcpy_toiovec(msg->msg_iov, skb->data, copied); + if (err) + goto out_free; + +#ifdef LINUX_2_1 + sk->stamp=skb->stamp; +#else + sock_recv_timestamp(msg, sk, skb); +#endif + + if (msg->msg_name) + memcpy(msg->msg_name, skb->cb, msg->msg_namelen); + + /* + * Free or return the buffer as appropriate. Again this + * hides all the races and re-entrancy issues from us. + */ + err = (flags&MSG_TRUNC) ? skb->len : copied; + +out_free: + skb_free_datagram(sk, skb); +out: + return err; +} + + +/*============================================================ + * wanpipe_wakeup_driver + * + * If socket receive buffer is full and driver cannot + * pass data up the sock, it sets a packet_block flag. + * This function check that flag and if sock receive + * queue has room it kicks the driver BH handler. + * + * This way, driver doesn't have to poll the sock + * receive queue. + *===========================================================*/ + +static void wanpipe_wakeup_driver(struct sock *sk) +{ + netdevice_t *dev=NULL; + wanpipe_common_t *chan=NULL; + + dev = dev_get_by_index(sk->bound_dev_if); + if (!dev) + return; + + dev_put(dev); + + if ((chan = dev->priv) == NULL) + return; + + if (atomic_read(&chan->receive_block)){ + if (atomic_read(&sk->rmem_alloc) < ((unsigned)sk->rcvbuf*0.9) ){ + printk(KERN_INFO "wansock: Queuing task for wanpipe\n"); + atomic_set(&chan->receive_block,0); + wanpipe_queue_tq(&chan->wanpipe_task); + wanpipe_mark_bh(); + } + } +} + +/*============================================================ + * wanpipe_getname + * + * I don't know what to do with this yet. + * User can use this function to get sock address + * information. Not very useful for Sangoma's purposes. + *===========================================================*/ + + +static int wanpipe_getname(struct socket *sock, struct sockaddr *uaddr, + int *uaddr_len, int peer) +{ + netdevice_t *dev; + struct sock *sk = sock->sk; + struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)uaddr; + + sll->sll_family = AF_WANPIPE; + sll->sll_ifindex = sk->bound_dev_if; + sll->sll_protocol = sk->num; + dev = dev_get_by_index(sk->bound_dev_if); + if (dev) { + sll->sll_hatype = dev->type; + sll->sll_halen = dev->addr_len; + memcpy(sll->sll_addr, dev->dev_addr, dev->addr_len); + } else { + sll->sll_hatype = 0; /* Bad: we have no ARPHRD_UNSPEC */ + sll->sll_halen = 0; + } + *uaddr_len = sizeof(*sll); + + dev_put(dev); + + return 0; +} + +/*============================================================ + * wanpipe_notifier + * + * If driver turns off network interface, this function + * will be envoked. Currently I treate it as a + * call disconnect. More thought should go into this + * function. + * + * FIXME: More thought should go into this function. + * + *===========================================================*/ + +static int wanpipe_notifier(struct notifier_block *this, unsigned long msg, void *data) +{ + struct sock *sk; + netdevice_t *dev = (netdevice_t*)data; + struct wanpipe_opt *po; + + for (sk = wanpipe_sklist; sk; sk = sk->next) { + + if ((po = sk->protinfo.af_wanpipe)==NULL) + continue; + if (dev == NULL) + continue; + + switch (msg) { + case NETDEV_DOWN: + case NETDEV_UNREGISTER: + if (dev->ifindex == sk->bound_dev_if) { + printk(KERN_INFO "wansock: Device down %s\n",dev->name); + if (sk->zapped){ + wanpipe_unlink_driver(sk); + sk->err = ENETDOWN; + sk->error_report(sk); + } + + if (msg == NETDEV_UNREGISTER) { + printk(KERN_INFO "wansock: Unregistering Device: %s\n", + dev->name); + wanpipe_unlink_driver(sk); + sk->bound_dev_if = 0; + } + } + break; + case NETDEV_UP: + if (dev->ifindex == sk->bound_dev_if && sk->num && !sk->zapped) { + printk(KERN_INFO "wansock: Registering Device: %s\n", + dev->name); + wanpipe_link_driver(dev,sk); + } + break; + } + } + return NOTIFY_DONE; +} + +/*============================================================ + * wanpipe_ioctl + * + * Execute a user commands, and set socket options. + * + * FIXME: More thought should go into this function. + * + *===========================================================*/ + +static int wanpipe_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + struct sock *sk = sock->sk; + int err; + int pid; + + switch(cmd) + { + case FIOSETOWN: + case SIOCSPGRP: + err = get_user(pid, (int *) arg); + if (err) + return err; + if (current->pid != pid && current->pgrp != -pid && + !capable(CAP_NET_ADMIN)) + return -EPERM; + sk->proc = pid; + return(0); + case FIOGETOWN: + case SIOCGPGRP: + return put_user(sk->proc, (int *)arg); + case SIOCGSTAMP: + if(sk->stamp.tv_sec==0) + return -ENOENT; + err = -EFAULT; + if (!copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval))) + err = 0; + return err; + + case SIOC_WANPIPE_CHECK_TX: + + return atomic_read(&sk->wmem_alloc); + + case SIOC_WANPIPE_SOCK_STATE: + + if (sk->state == WANSOCK_CONNECTED) + return 0; + + return 1; + + + case SIOC_WANPIPE_GET_CALL_DATA: + + return get_ioctl_cmd (sk,(void*)arg); + + case SIOC_WANPIPE_SET_CALL_DATA: + + return set_ioctl_cmd (sk,(void*)arg); + + case SIOC_WANPIPE_ACCEPT_CALL: + case SIOC_WANPIPE_CLEAR_CALL: + case SIOC_WANPIPE_RESET_CALL: + + if ((err=set_ioctl_cmd(sk,(void*)arg)) < 0) + return err; + + err=wanpipe_exec_cmd(sk,cmd,0); + get_ioctl_cmd(sk,(void*)arg); + return err; + + case SIOC_WANPIPE_DEBUG: + + return wanpipe_debug(sk,(void*)arg); + + case SIOC_WANPIPE_SET_NONBLOCK: + + if (sk->state != WANSOCK_DISCONNECTED) + return -EINVAL; + + sock->file->f_flags |= O_NONBLOCK; + return 0; + + case SIOCGIFFLAGS: +#ifndef CONFIG_INET + case SIOCSIFFLAGS: +#endif + case SIOCGIFCONF: + case SIOCGIFMETRIC: + case SIOCSIFMETRIC: + case SIOCGIFMEM: + case SIOCSIFMEM: + case SIOCGIFMTU: + case SIOCSIFMTU: + case SIOCSIFLINK: + case SIOCGIFHWADDR: + case SIOCSIFHWADDR: + case SIOCSIFMAP: + case SIOCGIFMAP: + case SIOCSIFSLAVE: + case SIOCGIFSLAVE: + case SIOCGIFINDEX: + case SIOCGIFNAME: + case SIOCGIFCOUNT: + case SIOCSIFHWBROADCAST: + return(dev_ioctl(cmd,(void *) arg)); + +#ifdef CONFIG_INET + case SIOCADDRT: + case SIOCDELRT: + case SIOCDARP: + case SIOCGARP: + case SIOCSARP: + case SIOCDRARP: + case SIOCGRARP: + case SIOCSRARP: + case SIOCGIFADDR: + case SIOCSIFADDR: + case SIOCGIFBRDADDR: + case SIOCSIFBRDADDR: + case SIOCGIFNETMASK: + case SIOCSIFNETMASK: + case SIOCGIFDSTADDR: + case SIOCSIFDSTADDR: + case SIOCSIFFLAGS: + case SIOCADDDLCI: + case SIOCDELDLCI: + return inet_dgram_ops.ioctl(sock, cmd, arg); +#endif + + default: + if ((cmd >= SIOCDEVPRIVATE) && + (cmd <= (SIOCDEVPRIVATE + 15))) + return(dev_ioctl(cmd,(void *) arg)); + +#ifdef CONFIG_NET_RADIO + if((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) + return(dev_ioctl(cmd,(void *) arg)); +#endif + return -EOPNOTSUPP; + } + /*NOTREACHED*/ +} + +/*============================================================ + * wanpipe_debug + * + * This function will pass up information about all + * active sockets. + * + * FIXME: More thought should go into this function. + * + *===========================================================*/ + +static int wanpipe_debug (struct sock *origsk, void *arg) +{ + struct sock *sk=NULL; + netdevice_t *dev=NULL; + wanpipe_common_t *chan=NULL; + int cnt=0, err=0; + wan_debug_t *dbg_data = (wan_debug_t *)arg; + + for (sk = wanpipe_sklist; sk; sk = sk->next){ + + if (sk == origsk){ + continue; + } + + if ((err=put_user(1, &dbg_data->debug[cnt].free))) + return err; + if ((err=put_user(sk->state, &dbg_data->debug[cnt].sk_state))) + return err; + if ((err=put_user(sk->rcvbuf, &dbg_data->debug[cnt].rcvbuf))) + return err; + if ((err=put_user(atomic_read(&sk->rmem_alloc), &dbg_data->debug[cnt].rmem))) + return err; + if ((err=put_user(atomic_read(&sk->wmem_alloc), &dbg_data->debug[cnt].wmem))) + return err; + if ((err=put_user(sk->sndbuf, &dbg_data->debug[cnt].sndbuf))) + return err; + if ((err=put_user(sk_count, &dbg_data->debug[cnt].sk_count))) + return err; + if ((err=put_user(sk->protinfo.af_wanpipe->poll_cnt, + &dbg_data->debug[cnt].poll_cnt))) + return err; + if ((err=put_user(sk->bound_dev_if, &dbg_data->debug[cnt].bound))) + return err; + + if (sk->bound_dev_if){ + dev = dev_get_by_index(sk->bound_dev_if); + if (!dev) + continue; + + chan=dev->priv; + dev_put(dev); + + if ((err=put_user(chan->state, &dbg_data->debug[cnt].d_state))) + return err; + if ((err=put_user(chan->svc, &dbg_data->debug[cnt].svc))) + return err; + + if ((err=put_user(atomic_read(&chan->command), + &dbg_data->debug[cnt].command))) + return err; + + + if (sk->protinfo.af_wanpipe){ + sdla_t *card = (sdla_t*)sk->protinfo.af_wanpipe->card; + + if (card){ + if ((err=put_user(atomic_read(&card->u.x.command_busy), + &dbg_data->debug[cnt].cmd_busy))) + return err; + } + + if ((err=put_user(sk->protinfo.af_wanpipe->lcn, + &dbg_data->debug[cnt].lcn))) + return err; + + if (sk->protinfo.af_wanpipe->mbox){ + if ((err=put_user(1, &dbg_data->debug[cnt].mbox))) + return err; + } + } + + if ((err=put_user(atomic_read(&chan->receive_block), + &dbg_data->debug[cnt].rblock))) + return err; + + if (copy_to_user(dbg_data->debug[cnt].name, dev->name, strlen(dev->name))) + return -EFAULT; + } + + if (++cnt == MAX_NUM_DEBUG) + break; + } + return 0; +} + +/*============================================================ + * get_ioctl_cmd + * + * Pass up the contents of socket MBOX to the user. + *===========================================================*/ + +static int get_ioctl_cmd (struct sock *sk, void *arg) +{ + x25api_t *usr_data = (x25api_t *)arg; + mbox_cmd_t *mbox_ptr; + int err; + + if (usr_data == NULL) + return -EINVAL; + + if (!sk->protinfo.af_wanpipe->mbox){ + return -EINVAL; + } + + mbox_ptr = (mbox_cmd_t *)sk->protinfo.af_wanpipe->mbox; + + if ((err=put_user(mbox_ptr->cmd.qdm, &usr_data->hdr.qdm))) + return err; + if ((err=put_user(mbox_ptr->cmd.cause, &usr_data->hdr.cause))) + return err; + if ((err=put_user(mbox_ptr->cmd.diagn, &usr_data->hdr.diagn))) + return err; + if ((err=put_user(mbox_ptr->cmd.length, &usr_data->hdr.length))) + return err; + if ((err=put_user(mbox_ptr->cmd.result, &usr_data->hdr.result))) + return err; + if ((err=put_user(mbox_ptr->cmd.lcn, &usr_data->hdr.lcn))) + return err; + + if (mbox_ptr->cmd.length > 0){ + if (mbox_ptr->cmd.length > X25_MAX_DATA) + return -EINVAL; + + if (copy_to_user(usr_data->data, mbox_ptr->data, mbox_ptr->cmd.length)){ + printk(KERN_INFO "wansock: Copy failed !!!\n"); + return -EFAULT; + } + } + return 0; +} + +/*============================================================ + * set_ioctl_cmd + * + * Before command can be execute, socket MBOX must + * be created, and initialized with user data. + *===========================================================*/ + +static int set_ioctl_cmd (struct sock *sk, void *arg) +{ + x25api_t *usr_data = (x25api_t *)arg; + mbox_cmd_t *mbox_ptr; + int err; + + if (!sk->protinfo.af_wanpipe->mbox){ + void *mbox_ptr; + netdevice_t *dev = dev_get_by_index(sk->bound_dev_if); + if (!dev) + return -ENODEV; + + dev_put(dev); + + if ((mbox_ptr = kmalloc(sizeof(mbox_cmd_t), GFP_ATOMIC)) == NULL) + return -ENOMEM; + + memset(mbox_ptr, 0, sizeof(mbox_cmd_t)); + sk->protinfo.af_wanpipe->mbox = mbox_ptr; + + wanpipe_link_driver(dev,sk); + } + + mbox_ptr = (mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox; + memset(mbox_ptr, 0, sizeof(mbox_cmd_t)); + + if (usr_data == NULL){ + return 0; + } + if ((err=get_user(mbox_ptr->cmd.qdm, &usr_data->hdr.qdm))) + return err; + if ((err=get_user(mbox_ptr->cmd.cause, &usr_data->hdr.cause))) + return err; + if ((err=get_user(mbox_ptr->cmd.diagn, &usr_data->hdr.diagn))) + return err; + if ((err=get_user(mbox_ptr->cmd.length, &usr_data->hdr.length))) + return err; + if ((err=get_user(mbox_ptr->cmd.result, &usr_data->hdr.result))) + return err; + + if (mbox_ptr->cmd.length > 0){ + if (mbox_ptr->cmd.length > X25_MAX_DATA) + return -EINVAL; + + if (copy_from_user(mbox_ptr->data, usr_data->data, mbox_ptr->cmd.length)){ + printk(KERN_INFO "Copy failed\n"); + return -EFAULT; + } + } + return 0; +} + + +/*====================================================================== + * wanpipe_poll + * + * Datagram poll: Again totally generic. This also handles + * sequenced packet sockets providing the socket receive queue + * is only ever holding data ready to receive. + * + * Note: when you _don't_ use this routine for this protocol, + * and you use a different write policy from sock_writeable() + * then please supply your own write_space callback. + *=====================================================================*/ + +unsigned int wanpipe_poll(struct file * file, struct socket *sock, poll_table *wait) +{ + struct sock *sk = sock->sk; + unsigned int mask; + + ++sk->protinfo.af_wanpipe->poll_cnt; + + poll_wait(file, sk->sleep, wait); + mask = 0; + + /* exceptional events? */ + if (sk->err || !skb_queue_empty(&sk->error_queue)){ + mask |= POLLPRI; + return mask; + } + if (sk->shutdown & RCV_SHUTDOWN) + mask |= POLLHUP; + + /* readable? */ + if (!skb_queue_empty(&sk->receive_queue)){ + mask |= POLLIN | POLLRDNORM; + } + + /* connection hasn't started yet */ + if (sk->state == WANSOCK_CONNECTING){ + return mask; + } + + if (sk->state == WANSOCK_DISCONNECTED){ + mask = POLLPRI; + return mask; + } + + /* This check blocks the user process if there is + * a packet already queued in the socket write queue. + * This option is only for X25API protocol, for other + * protocol like chdlc enable streaming mode, + * where multiple packets can be pending in the socket + * transmit queue */ + + if (sk->num == htons(X25_PROT)){ + if (atomic_read(&sk->protinfo.af_wanpipe->packet_sent)) + return mask; + } + + /* writable? */ + if (sock_writeable(sk)){ + mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + }else{ + #ifdef LINUX_2_4 + set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); + #else + sk->socket->flags |= SO_NOSPACE; + #endif + } + + return mask; +} + +/*====================================================================== + * wanpipe_listen + * + * X25API Specific function. Set a socket into LISTENING MODE. + *=====================================================================*/ + + +static int wanpipe_listen(struct socket *sock, int backlog) +{ + struct sock *sk = sock->sk; + + /* This is x25 specific area if protocol doesn't + * match, return error */ + if (sk->num != htons(X25_PROT)) + return -EINVAL; + + if (sk->state == WANSOCK_BIND_LISTEN) { + + sk->max_ack_backlog = backlog; + sk->state = WANSOCK_LISTEN; + return 0; + }else{ + printk(KERN_INFO "wansock: Listening sock was not binded\n"); + } + + return -EINVAL; +} + +/*====================================================================== + * wanpipe_link_card + * + * Connects the listening socket to the driver + *=====================================================================*/ + +static int wanpipe_link_card (struct sock *sk) +{ + sdla_t *card; + + card = (sdla_t*)sk->protinfo.af_wanpipe->card; + if (!card) + return -ENOMEM; + + if ((card->sk != NULL) || (card->func != NULL)){ + printk(KERN_INFO "wansock: Listening queue is already established\n"); + return -EINVAL; + } + + card->sk=sk; + card->func=wanpipe_listen_rcv; + sk->zapped=1; + + return 0; +} + +/*====================================================================== + * wanpipe_listen + * + * X25API Specific function. Disconnect listening socket from + * the driver. + *=====================================================================*/ + +static void wanpipe_unlink_card (struct sock *sk) +{ + sdla_t *card; + + card = (sdla_t*)sk->protinfo.af_wanpipe->card; + + if (card){ + card->sk=NULL; + card->func=NULL; + } +} + +/*====================================================================== + * wanpipe_exec_cmd + * + * Ioctl function calls this function to execute user command. + * Connect() sytem call also calls this function to execute + * place call. This function blocks until command is executed. + *=====================================================================*/ + +static int wanpipe_exec_cmd(struct sock *sk, int cmd, unsigned int flags) +{ + int err = -EINVAL; + mbox_cmd_t *mbox_ptr = (mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox; + + if (!mbox_ptr){ + printk(KERN_INFO "NO MBOX PTR !!!!!\n"); + return -EINVAL; + } + + /* This is x25 specific area if protocol doesn't + * match, return error */ + if (sk->num != htons(X25_PROT)) + return -EINVAL; + + + switch (cmd){ + + case SIOC_WANPIPE_ACCEPT_CALL: + + if (sk->state != WANSOCK_CONNECTING){ + err = -EHOSTDOWN; + break; + } + + err = execute_command(sk,X25_ACCEPT_CALL,0); + if (err < 0) + break; + + /* Update. Mar6 2000. + * Do not set the sock lcn number here, since + * it is done in wanpipe_listen_rcv(). + */ + if (sk->state == WANSOCK_CONNECTED){ + sk->protinfo.af_wanpipe->lcn = + ((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.lcn; + DBG_PRINTK(KERN_INFO "\nwansock: Accept OK %i\n", + sk->protinfo.af_wanpipe->lcn ); + err = 0; + + }else{ + DBG_PRINTK (KERN_INFO "\nwansock: Accept Failed %i\n", + sk->protinfo.af_wanpipe->lcn); + sk->protinfo.af_wanpipe->lcn = 0; + err = -ECONNREFUSED; + } + break; + + case SIOC_WANPIPE_CLEAR_CALL: + + if (sk->state == WANSOCK_DISCONNECTED){ + err = -EINVAL; + break; + } + + + /* Check if data buffers are pending for transmission, + * if so, check wheter user wants to wait untill data + * is transmitted, or clear a call and drop packets */ + + if (atomic_read(&sk->wmem_alloc) || check_driver_busy(sk)){ + mbox_cmd_t *mbox = sk->protinfo.af_wanpipe->mbox; + if (mbox->cmd.qdm & 0x80){ + mbox->cmd.result = 0x35; + err = -EAGAIN; + break; + } + } + + sk->state = WANSOCK_DISCONNECTING; + + err = execute_command(sk,X25_CLEAR_CALL,0); + if (err < 0) + break; + + err = -ECONNREFUSED; + if (sk->state == WANSOCK_DISCONNECTED){ + DBG_PRINTK(KERN_INFO "\nwansock: CLEAR OK %i\n", + sk->protinfo.af_wanpipe->lcn); + sk->protinfo.af_wanpipe->lcn=0; + err = 0; + } + break; + + case SIOC_WANPIPE_RESET_CALL: + + if (sk->state != WANSOCK_CONNECTED){ + err = -EINVAL; + break; + } + + + /* Check if data buffers are pending for transmission, + * if so, check wheter user wants to wait untill data + * is transmitted, or reset a call and drop packets */ + + if (atomic_read(&sk->wmem_alloc) || check_driver_busy(sk)){ + mbox_cmd_t *mbox = sk->protinfo.af_wanpipe->mbox; + if (mbox->cmd.qdm & 0x80){ + mbox->cmd.result = 0x35; + err = -EAGAIN; + break; + } + } + + + err = execute_command(sk, X25_RESET,0); + if (err < 0) + break; + + err = mbox_ptr->cmd.result; + break; + + + case X25_PLACE_CALL: + + err=execute_command(sk,X25_PLACE_CALL,flags); + if (err < 0) + break; + + if (sk->state == WANSOCK_CONNECTED){ + + sk->protinfo.af_wanpipe->lcn = + ((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.lcn; + + DBG_PRINTK(KERN_INFO "\nwansock: PLACE CALL OK %i\n", + sk->protinfo.af_wanpipe->lcn); + err = 0; + + }else if (sk->state == WANSOCK_CONNECTING && (flags & O_NONBLOCK)){ + sk->protinfo.af_wanpipe->lcn = + ((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.lcn; + DBG_PRINTK(KERN_INFO "\nwansock: Place Call OK: Waiting %i\n", + sk->protinfo.af_wanpipe->lcn); + + err = 0; + + }else{ + DBG_PRINTK(KERN_INFO "\nwansock: Place call Failed\n"); + err = -ECONNREFUSED; + } + + break; + + default: + return -EINVAL; + } + + return err; +} + +static int check_driver_busy (struct sock *sk) +{ + netdevice_t *dev = dev_get_by_index(sk->bound_dev_if); + wanpipe_common_t *chan; + + if (!dev) + return 0; + + dev_put(dev); + + if ((chan=dev->priv) == NULL) + return 0; + + return atomic_read(&chan->driver_busy); +} + + +/*====================================================================== + * wanpipe_accept + * + * ACCEPT() System call. X25API Specific function. + * For each incoming call, create a new socket and + * return it to the user. + *=====================================================================*/ + +static int wanpipe_accept(struct socket *sock, struct socket *newsock, int flags) +{ + struct sock *sk; + struct sock *newsk; + struct sk_buff *skb; + DECLARE_WAITQUEUE(wait, current); + int err=0; + + if (newsock->sk != NULL){ + wanpipe_kill_sock_accept(newsock->sk); + newsock->sk=NULL; + } + + if ((sk = sock->sk) == NULL) + return -EINVAL; + + if (sk->type != SOCK_RAW) + return -EOPNOTSUPP; + + if (sk->state != WANSOCK_LISTEN) + return -EINVAL; + + if (sk->num != htons(X25_PROT)) + return -EINVAL; + + add_wait_queue(sk->sleep,&wait); + current->state = TASK_INTERRUPTIBLE; + for (;;){ + skb = skb_dequeue(&sk->receive_queue); + if (skb){ + err=0; + break; + } + if (signal_pending(current)) { + err = -ERESTARTSYS; + break; + } + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(sk->sleep,&wait); + + if (err != 0) + return err; + + newsk = get_newsk_from_skb(skb); + if (!newsk){ + return -EINVAL; + } + + set_bit(1,&wanpipe_tx_critical); + write_lock(&wanpipe_sklist_lock); + newsk->next = wanpipe_sklist; + wanpipe_sklist = newsk; + sock_hold(sk); + write_unlock(&wanpipe_sklist_lock); + clear_bit(1,&wanpipe_tx_critical); + + newsk->pair = NULL; + newsk->socket = newsock; + newsk->sleep = &newsock->wait; + + /* Now attach up the new socket */ + sk->ack_backlog--; + newsock->sk = newsk; + + kfree_skb(skb); + + DBG_PRINTK(KERN_INFO "\nwansock: ACCEPT Got LCN %i\n",newsk->protinfo.af_wanpipe->lcn); + return 0; +} + +/*====================================================================== + * get_newsk_from_skb + * + * Accept() uses this function to get the address of the new + * socket structure. + *=====================================================================*/ + +struct sock * get_newsk_from_skb (struct sk_buff *skb) +{ + netdevice_t *dev = skb->dev; + wanpipe_common_t *chan; + + if (!dev){ + return NULL; + } + + if ((chan = dev->priv) == NULL){ + return NULL; + } + + if (!chan->sk){ + return NULL; + } + return (struct sock *)chan->sk; +} + +/*====================================================================== + * wanpipe_connect + * + * CONNECT() System Call. X25API specific function + * Check the state of the sock, and execute PLACE_CALL command. + * Connect can ether block or return without waiting for connection, + * if specified by user. + *=====================================================================*/ + +static int wanpipe_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) +{ + struct sock *sk = sock->sk; + struct wan_sockaddr_ll *addr = (struct wan_sockaddr_ll*)uaddr; + netdevice_t *dev; + int err; + + if (sk->num != htons(X25_PROT)) + return -EINVAL; + + if (sk->state == WANSOCK_CONNECTED) + return EISCONN; /* No reconnect on a seqpacket socket */ + + if (sk->state != WAN_DISCONNECTED){ + printk(KERN_INFO "wansock: Trying to connect on channel NON DISCONNECT\n"); + return -ECONNREFUSED; + } + + sk->state = WANSOCK_DISCONNECTED; + sock->state = SS_UNCONNECTED; + + if (addr_len != sizeof(struct wan_sockaddr_ll)) + return -EINVAL; + + if (addr->sll_family != AF_WANPIPE) + return -EINVAL; + + if ((dev = dev_get_by_index(sk->bound_dev_if)) == NULL) + return -ENETUNREACH; + + dev_put(dev); + + if (!sk->zapped) /* Must bind first - autobinding does not work */ + return -EINVAL; + + sock->state = SS_CONNECTING; + sk->state = WANSOCK_CONNECTING; + + if (!sk->protinfo.af_wanpipe->mbox){ + if (sk->protinfo.af_wanpipe->svc){ + return -EINVAL; + }else{ + int err; + if ((err=set_ioctl_cmd(sk,NULL)) < 0) + return err; + } + } + + if ((err=wanpipe_exec_cmd(sk, X25_PLACE_CALL,flags)) != 0){ + sock->state = SS_UNCONNECTED; + sk->state = WANSOCK_CONNECTED; + return err; + } + + if (sk->state != WANSOCK_CONNECTED && (flags & O_NONBLOCK)){ + return 0; + } + + if (sk->state != WANSOCK_CONNECTED) { + sock->state = SS_UNCONNECTED; + return -ECONNREFUSED; + } + + sock->state = SS_CONNECTED; + return 0; +} + +#ifdef LINUX_2_4 +struct proto_ops wanpipe_ops = { + family: PF_WANPIPE, + + release: wanpipe_release, + bind: wanpipe_bind, + connect: wanpipe_connect, + socketpair: sock_no_socketpair, + accept: wanpipe_accept, + getname: wanpipe_getname, + poll: wanpipe_poll, + ioctl: wanpipe_ioctl, + listen: wanpipe_listen, + shutdown: sock_no_shutdown, + setsockopt: sock_no_setsockopt, + getsockopt: sock_no_getsockopt, + sendmsg: wanpipe_sendmsg, + recvmsg: wanpipe_recvmsg +}; +#else +struct proto_ops wanpipe_ops = { + PF_WANPIPE, + + sock_no_dup, + wanpipe_release, + wanpipe_bind, + wanpipe_connect, + sock_no_socketpair, + wanpipe_accept, + wanpipe_getname, + wanpipe_poll, + wanpipe_ioctl, + wanpipe_listen, + sock_no_shutdown, + sock_no_setsockopt, + sock_no_getsockopt, + sock_no_fcntl, + wanpipe_sendmsg, + wanpipe_recvmsg +}; +#endif + + +static struct net_proto_family wanpipe_family_ops = { + PF_WANPIPE, + wanpipe_create +}; + +struct notifier_block wanpipe_netdev_notifier={ + wanpipe_notifier, + NULL, + 0 +}; + + +#ifdef MODULE +void cleanup_module(void) +{ + printk(KERN_INFO "wansock: Cleaning up \n"); + unregister_netdevice_notifier(&wanpipe_netdev_notifier); + sock_unregister(PF_WANPIPE); + return; +} + + +int init_module(void) +{ + + printk(KERN_INFO "wansock: Registering Socket \n"); + sock_register(&wanpipe_family_ops); + register_netdevice_notifier(&wanpipe_netdev_notifier); + return 0; +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/wanrouter/patchlevel linux.ac/net/wanrouter/patchlevel --- linux.vanilla/net/wanrouter/patchlevel Thu Jan 7 17:25:02 1999 +++ linux.ac/net/wanrouter/patchlevel Sat Apr 14 01:53:13 2001 @@ -1 +1 @@ -2.0.3 +2.2.1 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/wanrouter/wanmain.c linux.ac/net/wanrouter/wanmain.c --- linux.vanilla/net/wanrouter/wanmain.c Tue Apr 3 17:32:31 2001 +++ linux.ac/net/wanrouter/wanmain.c Sat Apr 14 01:53:13 2001 @@ -18,6 +18,14 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Nov 24, 2000 Nenad Corbic Updated for 2.4.X kernels +* Nov 07, 2000 Nenad Corbic Fixed the Mulit-Port PPP for kernels 2.2.16 and +* greater. +* Aug 2, 2000 Nenad Corbic Block the Multi-Port PPP from running on +* kernels 2.2.16 or greater. The SyncPPP +* has changed. +* Jul 13, 2000 Nenad Corbic Added SyncPPP support +* Added extra debugging in device_setup(). * Oct 01, 1999 Gideon Hack Update for s514 PCI card * Dec 27, 1996 Gene Kozin Initial version (based on Sangoma's WANPIPE) * Jan 16, 1997 Gene Kozin router_devlist made public @@ -31,7 +39,6 @@ * Dec 22, 1998 Arnaldo Melo vmalloc/vfree used in device_setup to allocate * kernel memory and copy configuration data to * kernel space (for big firmwares) -* May 19, 1999 Arnaldo Melo __init in wanrouter_init * Jun 02, 1999 Gideon Hack Updates for Linux 2.0.X and 2.2.X kernels. *****************************************************************************/ @@ -41,17 +48,95 @@ #include <linux/errno.h> /* return codes */ #include <linux/kernel.h> #include <linux/module.h> /* support for loadable modules */ -#include <linux/slab.h> /* kmalloc(), kfree() */ +#include <linux/malloc.h> /* kmalloc(), kfree() */ #include <linux/mm.h> /* verify_area(), etc. */ #include <linux/string.h> /* inline mem*, str* functions */ -#include <linux/vmalloc.h> /* vmalloc, vfree */ -#include <asm/segment.h> /* kernel <-> user copy */ + #include <asm/byteorder.h> /* htons(), etc. */ -#include <asm/uaccess.h> /* copy_to/from_user */ #include <linux/wanrouter.h> /* WAN router API definitions */ -#include <linux/init.h> /* __init et al. */ +#if defined(LINUX_2_4) + #include <linux/vmalloc.h> /* vmalloc, vfree */ + #include <asm/uaccess.h> /* copy_to/from_user */ + #include <linux/init.h> /* __initfunc et al. */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3) + #include <net/syncppp.h> +#else + #include <../drivers/net/wan/syncppp.h> +#endif + +#elif defined(LINUX_2_1) + #define LINUX_2_1 + #include <linux/vmalloc.h> /* vmalloc, vfree */ + #include <asm/uaccess.h> /* copy_to/from_user */ + #include <linux/init.h> /* __initfunc et al. */ + #include <../drivers/net/syncppp.h> + +#else + #include <asm/segment.h> /* kernel <-> user copy */ +#endif + +#define KMEM_SAFETYZONE 8 + +/***********FOR DEBUGGING PURPOSES********************************************* +static void * dbg_kmalloc(unsigned int size, int prio, int line) { + int i = 0; + void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); + char * c1 = v; + c1 += sizeof(unsigned int); + *((unsigned int *)v) = size; + + for (i = 0; i < KMEM_SAFETYZONE; i++) { + c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; + c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; + c1 += 8; + } + c1 += size; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; + c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; + c1 += 8; + } + v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; + printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); + return v; +} +static void dbg_kfree(void * v, int line) { + unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); + unsigned int size = *sp; + char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; + int i = 0; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' + || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { + printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); + printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, + c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); + } + c1 += 8; + } + c1 += size; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' + || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' + ) { + printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); + printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, + c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); + } + c1 += 8; + } + printk(KERN_INFO "line %d kfree(%p)\n",line,v); + v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); + kfree(v); +} + +#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) +#define kfree(x) dbg_kfree(x,__LINE__) +*****************************************************************************/ + /* * Defines and Macros @@ -91,14 +176,18 @@ */ static wan_device_t *find_device (char *name); -static int delete_interface (wan_device_t *wandev, char *name, int force); +static int delete_interface (wan_device_t *wandev, char *name); +void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags); +void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags); + + /* * Global Data */ -static char fullname[] = "WAN Router"; -static char copyright[] = "(c) 1995-1999 Sangoma Technologies Inc."; +static char fullname[] = "Sangoma WANPIPE Router"; +static char copyright[] = "(c) 1995-2000 Sangoma Technologies Inc."; static char modname[] = ROUTER_NAME; /* short module name */ wan_device_t* router_devlist = NULL; /* list of registered devices */ static int devcnt = 0; @@ -113,31 +202,41 @@ #endif #ifndef MODULE -int __init wanrouter_init(void) + +int wanrouter_init(void) { int err; - extern int wanpipe_init(void), - cyclomx_init(void); + extern int wanpipe_init(void); + extern int sdladrv_init(void); printk(KERN_INFO "%s v%u.%u %s\n", fullname, ROUTER_VERSION, ROUTER_RELEASE, copyright); + err = wanrouter_proc_init(); - if (err) - printk(KERN_ERR "%s: can't create entry in proc filesystem!\n", modname); + if (err){ + printk(KERN_INFO "%s: can't create entry in proc filesystem!\n", modname); + } + + /* + * Initialise compiled in boards + */ - /* - * Initialise compiled in boards - */ - #ifdef CONFIG_VENDOR_SANGOMA + sdladrv_init(); wanpipe_init(); #endif -#ifdef CONFIG_CYCLADES_SYNC - cyclomx_init(); -#endif + return err; } + +#ifdef LINUX_2_4 +static void __exit wanrouter_cleanup (void) +{ + wanrouter_proc_cleanup(); +} +#endif + #else /* @@ -161,9 +260,13 @@ printk(KERN_INFO "%s v%u.%u %s\n", fullname, ROUTER_VERSION, ROUTER_RELEASE, copyright); + err = wanrouter_proc_init(); - if (err) printk(KERN_ERR + + if (err){ + printk(KERN_INFO "%s: can't create entry in proc filesystem!\n", modname); + } return err; } @@ -207,7 +310,7 @@ if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC) || (wandev->name == NULL)) return -EINVAL; - + namelen = strlen(wandev->name); if (!namelen || (namelen > WAN_DRVNAME_SZ)) return -EINVAL; @@ -219,12 +322,13 @@ printk(KERN_INFO "%s: registering WAN device %s\n", modname, wandev->name); #endif + /* * Register /proc directory entry */ err = wanrouter_proc_add(wandev); if (err) { - printk(KERN_ERR + printk(KERN_INFO "%s: can't create /proc/net/router/%s entry!\n", modname, wandev->name); return err; @@ -274,17 +378,17 @@ #ifdef WANDEBUG printk(KERN_INFO "%s: unregistering WAN device %s\n", modname, name); #endif - + if (wandev->state != WAN_UNCONFIGURED) { - while(wandev->dev) - delete_interface(wandev, wandev->dev->name, 1); - if (wandev->shutdown) - wandev->shutdown(wandev); + device_shutdown(wandev); } - if (prev) + + if (prev){ prev->next = wandev->next; - else + }else{ router_devlist = wandev->next; + } + --devcnt; wanrouter_proc_delete(wandev); MOD_DEC_USE_COUNT; @@ -302,12 +406,12 @@ */ -int wanrouter_encapsulate (struct sk_buff* skb, struct net_device* dev) +int wanrouter_encapsulate (struct sk_buff *skb, netdevice_t *dev, + unsigned short type) { int hdr_len = 0; - switch (skb->protocol) - { + switch (type) { case ETH_P_IP: /* IP datagram encapsulation */ hdr_len += 1; skb_push(skb, 1); @@ -321,18 +425,19 @@ skb->data[0] = 0; skb->data[1] = NLPID_SNAP; memcpy(&skb->data[2], oui_ether, sizeof(oui_ether)); - *((unsigned short*)&skb->data[5]) = htons(skb->protocol); + *((unsigned short*)&skb->data[5]) = htons(type); break; default: /* Unknown packet type */ printk(KERN_INFO "%s: unsupported Ethertype 0x%04X on interface %s!\n", - modname, skb->protocol, dev->name); + modname, type, dev->name); hdr_len = -EINVAL; } return hdr_len; } + /* * Decapsulate packet. * @@ -344,21 +449,19 @@ */ -unsigned short wanrouter_type_trans (struct sk_buff* skb, struct net_device* dev) +unsigned short wanrouter_type_trans (struct sk_buff *skb, netdevice_t *dev) { int cnt = skb->data[0] ? 0 : 1; /* there may be a pad present */ unsigned short ethertype; - switch (skb->data[cnt]) - { + switch (skb->data[cnt]) { case NLPID_IP: /* IP datagramm */ ethertype = htons(ETH_P_IP); cnt += 1; break; case NLPID_SNAP: /* SNAP encapsulation */ - if (memcmp(&skb->data[cnt + 1], oui_ether, sizeof(oui_ether))) - { + if (memcmp(&skb->data[cnt + 1], oui_ether, sizeof(oui_ether))){ printk(KERN_INFO "%s: unsupported SNAP OUI %02X-%02X-%02X " "on interface %s!\n", modname, @@ -380,8 +483,8 @@ } skb->protocol = ethertype; skb->pkt_type = PACKET_HOST; /* Physically point to point */ - skb->mac.raw = skb->data; skb_pull(skb, cnt); + skb->mac.raw = skb->data; return ethertype; } @@ -399,9 +502,11 @@ struct proc_dir_entry *dent; wan_device_t *wandev; + #if defined (LINUX_2_1) || defined (LINUX_2_4) if (!capable(CAP_NET_ADMIN)){ return -EPERM; } + #endif if ((cmd >> 8) != ROUTER_IOCTL) return -EINVAL; @@ -466,44 +571,105 @@ wandev_conf_t *conf; int err = -EINVAL; - if (wandev->setup == NULL) /* Nothing to do ? */ + if (wandev->setup == NULL){ /* Nothing to do ? */ + printk(KERN_INFO "%s: ERROR, No setup script: wandev->setup()\n", + wandev->name); return 0; + } + + #ifdef LINUX_2_0 + err = verify_area (VERIFY_READ, u_conf, sizeof(wandev_conf_t)); + if(err){ + return err; + } + #endif conf = kmalloc(sizeof(wandev_conf_t), GFP_KERNEL); - if (conf == NULL) + if (conf == NULL){ + printk(KERN_INFO "%s: ERROR, Failed to allocate kernel memory !\n", + wandev->name); return -ENOBUFS; - + } + + #if defined (LINUX_2_1) || defined (LINUX_2_4) if(copy_from_user(conf, u_conf, sizeof(wandev_conf_t))) { + printk(KERN_INFO "%s: Failed to copy user config data to kernel space!\n", + wandev->name); kfree(conf); return -EFAULT; } + #else + memcpy_fromfs ((void *)conf, (void *)u_conf, sizeof(wandev_conf_t)); + #endif - if (conf->magic != ROUTER_MAGIC) { + if (conf->magic != ROUTER_MAGIC){ kfree(conf); + printk(KERN_INFO "%s: ERROR, Invalid MAGIC Number\n", + wandev->name); return -EINVAL; } - if (conf->data_size && conf->data) { + if (conf->data_size && conf->data){ if(conf->data_size > 128000 || conf->data_size < 0) { kfree(conf); + printk(KERN_INFO + "%s: ERROR, Invalid firmware data size %i !\n", + wandev->name, conf->data_size); return -EINVAL;; } +#if defined (LINUX_2_1) || defined (LINUX_2_4) data = vmalloc(conf->data_size); if (data) { if(!copy_from_user(data, conf->data, conf->data_size)){ conf->data=data; err = wandev->setup(wandev,conf); - } - else + }else{ + printk(KERN_INFO + "%s: ERROR, Faild to copy from user data !\n", + wandev->name); err = -EFAULT; - } - else + } + }else{ + printk(KERN_INFO + "%s: ERROR, Faild allocate kernel memory !\n", + wandev->name); err = -ENOBUFS; - - if (data) + } + + if (data){ vfree(data); + } +#else + err = verify_area(VERIFY_READ, conf->data, conf->data_size); + if (!err) { + data = kmalloc(conf->data_size, GFP_KERNEL); + if (data) { + memcpy_fromfs(data, (void*)conf->data, + conf->data_size); + conf->data = data; + }else{ + printk(KERN_INFO + "%s: ERROR, Faild allocate kernel memory !\n",wandev->name); + err = -ENOMEM; + } + }else{ + printk(KERN_INFO + "%s: ERROR, Faild to copy from user data !\n",wandev->name); + } + if (!err){ + err = wandev->setup(wandev, conf); + } + + if (data){ + kfree(data); + } +#endif + }else{ + printk(KERN_INFO + "%s: ERROR, No firmware found ! Firmware size = %i !\n", + wandev->name, conf->data_size); } kfree(conf); @@ -516,27 +682,37 @@ * o call driver's shutdown() entry point */ -static int device_shutdown (wan_device_t* wandev) +static int device_shutdown (wan_device_t *wandev) { - struct net_device* dev; - - if (wandev->state == WAN_UNCONFIGURED) + netdevice_t *dev; + int err=0; + + if (wandev->state == WAN_UNCONFIGURED){ return 0; + } + + printk(KERN_INFO "\n%s: Shutting Down!\n",wandev->name); - for (dev = wandev->dev; dev;) - { - if (delete_interface(wandev, dev->name, 0)) - { - struct net_device **slave = dev->priv; - dev = *slave; + for (dev = wandev->dev; dev;) { + if ((err=delete_interface(wandev, dev->name)) != 0){ + return err; } + + /* The above function deallocates the current dev + * structure. Therefore, we cannot use dev->priv + * as the next element: wandev->dev points to the + * next element */ + dev = wandev->dev; } - if (wandev->ndev) + + if (wandev->ndev){ return -EBUSY; /* there are opened interfaces */ - + } + if (wandev->shutdown) - return wandev->shutdown(wandev); - return 0; + err=wandev->shutdown(wandev); + + return err; } /* @@ -547,6 +723,13 @@ { wandev_stat_t stat; + #ifdef LINUX_2_0 + int err; + err = verify_area(VERIFY_WRITE, u_stat, sizeof(wandev_stat_t)); + if (err) + return err; + #endif + memset(&stat, 0, sizeof(stat)); /* Ask device driver to update device statistics */ @@ -557,8 +740,12 @@ stat.ndev = wandev->ndev; stat.state = wandev->state; + #if defined (LINUX_2_1) || defined (LINUX_2_4) if(copy_to_user(u_stat, &stat, sizeof(stat))) return -EFAULT; + #else + memcpy_tofs((void*)u_stat, (void*)&stat, sizeof(stat)); + #endif return 0; } @@ -573,58 +760,149 @@ * o register network interface */ -static int device_new_if (wan_device_t* wandev, wanif_conf_t* u_conf) +static int device_new_if (wan_device_t *wandev, wanif_conf_t *u_conf) { wanif_conf_t conf; - struct net_device *dev; + netdevice_t *dev=NULL; + #ifdef CONFIG_WANPIPE_MULTPPP + struct ppp_device *pppdev=NULL; + #endif int err; if ((wandev->state == WAN_UNCONFIGURED) || (wandev->new_if == NULL)) return -ENODEV; - + + #if defined (LINUX_2_1) || defined (LINUX_2_4) if(copy_from_user(&conf, u_conf, sizeof(wanif_conf_t))) return -EFAULT; + #else + err = verify_area(VERIFY_READ, u_conf, sizeof(wanif_conf_t)); + if (err) + return err; + memcpy_fromfs((void*)&conf, (void*)u_conf, sizeof(wanif_conf_t)); + #endif if (conf.magic != ROUTER_MAGIC) return -EINVAL; + + err = -EPROTONOSUPPORT; + + +#ifdef CONFIG_WANPIPE_MULTPPP + if (conf.config_id == WANCONFIG_MPPP){ + + pppdev = kmalloc(sizeof(struct ppp_device), GFP_KERNEL); + if (pppdev == NULL){ + return -ENOBUFS; + } + memset(pppdev, 0, sizeof(struct ppp_device)); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16) + pppdev->dev = kmalloc(sizeof(netdevice_t), GFP_KERNEL); + if (pppdev->dev == NULL){ + return -ENOBUFS; + } + memset(pppdev->dev, 0, sizeof(netdevice_t)); + #endif - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (dev == NULL) - return -ENOBUFS; + err = wandev->new_if(wandev, (netdevice_t *)pppdev, &conf); - memset(dev, 0, sizeof(struct net_device)); - err = wandev->new_if(wandev, dev, &conf); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16) + dev = pppdev->dev; + #else + dev = &pppdev->dev; + #endif + + }else{ + + dev = kmalloc(sizeof(netdevice_t), GFP_KERNEL); + if (dev == NULL){ + return -ENOBUFS; + } + memset(dev, 0, sizeof(netdevice_t)); + err = wandev->new_if(wandev, dev, &conf); + } + +#else + /* Sync PPP is disabled */ + if (conf.config_id != WANCONFIG_MPPP){ + + dev = kmalloc(sizeof(netdevice_t), GFP_KERNEL); + if (dev == NULL){ + return -ENOBUFS; + } + memset(dev, 0, sizeof(netdevice_t)); + err = wandev->new_if(wandev, dev, &conf); + }else{ + printk(KERN_INFO "%s: Wanpipe Mulit-Port PPP support has not been compiled in!\n", + wandev->name); + return err; + } +#endif + if (!err) { /* Register network interface. This will invoke init() * function supplied by the driver. If device registered * successfully, add it to the interface list. */ - if (dev->name == NULL) + + if (dev->name == NULL){ err = -EINVAL; - - else if (dev_get(dev->name)) + }else if (dev_get(dev->name)){ err = -EEXIST; /* name already exists */ - else { -#ifdef WANDEBUG + }else{ + + #ifdef WANDEBUG printk(KERN_INFO "%s: registering interface %s...\n", modname, dev->name); -#endif + #endif + err = register_netdev(dev); if (!err) { - struct net_device **slave = dev->priv; + netdevice_t *slave=NULL; + unsigned long smp_flags=0; + + lock_adapter_irq(&wandev->lock, &smp_flags); + + if (wandev->dev == NULL){ + wandev->dev = dev; + }else{ + for (slave=wandev->dev; + *((netdevice_t**)slave->priv); + slave=*((netdevice_t**)slave->priv)); - cli(); /***** critical section start *****/ - *slave = wandev->dev; - wandev->dev = dev; + *((netdevice_t**)slave->priv) = dev; + } ++wandev->ndev; - sti(); /****** critical section end ******/ + + unlock_adapter_irq(&wandev->lock, &smp_flags); return 0; /* done !!! */ } } if (wandev->del_if) wandev->del_if(wandev, dev); } - kfree(dev); + + /* This code has moved from del_if() function */ + if (dev->priv){ + kfree(dev->priv); + dev->priv=NULL; + } + + + #ifdef CONFIG_WANPIPE_MULTPPP + if (conf.config_id == WANCONFIG_MPPP){ + kfree(pppdev); + }else{ + kfree(dev); + } + #else + /* Sync PPP is disabled */ + if (conf.config_id != WANCONFIG_MPPP){ + kfree(dev); + } + #endif + return err; } @@ -638,15 +916,43 @@ static int device_del_if (wan_device_t *wandev, char *u_name) { char name[WAN_IFNAME_SZ + 1]; + int err = 0; if (wandev->state == WAN_UNCONFIGURED) return -ENODEV; + #ifdef LINUX_2_0 + err = verify_area(VERIFY_READ, u_name, WAN_IFNAME_SZ); + if (err) + return err; + #endif + memset(name, 0, sizeof(name)); + #if defined (LINUX_2_1) || defined (LINUX_2_4) if(copy_from_user(name, u_name, WAN_IFNAME_SZ)) return -EFAULT; - return delete_interface(wandev, name, 0); + #else + memcpy_fromfs((void*)name, (void*)u_name, WAN_IFNAME_SZ); + #endif + + err = delete_interface(wandev, name); + if (err) + return(err); + + /* If last interface being deleted, shutdown card + * This helps with administration at leaf nodes + * (You can tell if the person at the other end of the phone + * has an interface configured) and avoids DoS vulnerabilities + * in binary driver files - this fixes a problem with the current + * Sangoma driver going into strange states when all the network + * interfaces are deleted and the link irrecoverably disconnected. + */ + + if (!wandev->ndev && wandev->shutdown){ + err = wandev->shutdown(wandev); + } + return err; } @@ -685,59 +991,102 @@ * sure that opened interfaces are not removed! */ -static int delete_interface (wan_device_t *wandev, char *name, int force) +static int delete_interface (wan_device_t *wandev, char *name) { - struct net_device *dev, *prev; + netdevice_t *dev=NULL, *prev=NULL; + unsigned long smp_flags=0; + lock_adapter_irq(&wandev->lock, &smp_flags); dev = wandev->dev; prev = NULL; while (dev && strcmp(name, dev->name)) { - struct net_device **slave = dev->priv; - + netdevice_t **slave = dev->priv; prev = dev; dev = *slave; } - - if (dev == NULL) + unlock_adapter_irq(&wandev->lock, &smp_flags); + + if (dev == NULL){ return -ENODEV; /* interface not found */ - - if (netif_running(dev)) { - if (force) { - printk(KERN_WARNING - "%s: deleting opened interface %s!\n", - modname, name); - } - else - return -EBUSY; /* interface in use */ + } + + #ifdef LINUX_2_4 + if (netif_running(dev)){ + #else + if (dev->start) { + #endif + return -EBUSY; /* interface in use */ } if (wandev->del_if) wandev->del_if(wandev, dev); - cli(); /***** critical section start *****/ + lock_adapter_irq(&wandev->lock, &smp_flags); if (prev) { - struct net_device **prev_slave = prev->priv; - struct net_device **slave = dev->priv; + netdevice_t **prev_slave = prev->priv; + netdevice_t **slave = dev->priv; *prev_slave = *slave; } else { - struct net_device **slave = dev->priv; - + netdevice_t **slave = dev->priv; wandev->dev = *slave; } --wandev->ndev; - sti(); /****** critical section end ******/ + unlock_adapter_irq(&wandev->lock, &smp_flags); + + printk(KERN_INFO "%s: unregistering '%s'\n", wandev->name, dev->name); + + /* Due to new interface linking method using dev->priv, + * this code has moved from del_if() function.*/ + if (dev->priv){ + kfree(dev->priv); + dev->priv=NULL; + } - printk("Unregistering '%s'\n", dev->name); unregister_netdev(dev); + + #ifdef LINUX_2_4 + kfree(dev); + #else + if (dev->name){ + kfree(dev->name); + } kfree(dev); + #endif + return 0; } +void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags) +{ + #ifdef LINUX_2_0 + save_flags(*smp_flags); + cli(); + #else + spin_lock_irqsave(lock, *smp_flags); + #endif +} + + +void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags) +{ + #ifdef LINUX_2_0 + restore_flags(*smp_flags); + #else + spin_unlock_irqrestore(lock, *smp_flags); + #endif +} + + + +#if defined (LINUX_2_1) || defined (LINUX_2_4) EXPORT_SYMBOL(register_wan_device); EXPORT_SYMBOL(unregister_wan_device); EXPORT_SYMBOL(wanrouter_encapsulate); EXPORT_SYMBOL(wanrouter_type_trans); +EXPORT_SYMBOL(lock_adapter_irq); +EXPORT_SYMBOL(unlock_adapter_irq); +#endif /* * End diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/wanrouter/wanproc.c linux.ac/net/wanrouter/wanproc.c --- linux.vanilla/net/wanrouter/wanproc.c Fri Feb 9 19:34:13 2001 +++ linux.ac/net/wanrouter/wanproc.c Sat Apr 14 01:53:13 2001 @@ -13,7 +13,6 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ -* Jan 20, 2001 Arnaldo C.Melo Fix leak on error in router_proc_read, cleanups * Jun 02, 1999 Gideon Hack Updates for Linux 2.2.X kernels. * Jun 29, 1997 Alan Cox Merged with 1.0.3 vendor code * Jan 29, 1997 Gene Kozin v1.0.1. Implemented /proc read routines @@ -26,397 +25,1017 @@ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ #include <linux/kernel.h> -#include <linux/slab.h> /* kmalloc(), kfree() */ +#include <linux/malloc.h> /* kmalloc(), kfree() */ #include <linux/mm.h> /* verify_area(), etc. */ #include <linux/string.h> /* inline mem*, str* functions */ -#include <linux/init.h> /* __init et al. */ -#include <asm/segment.h> /* kernel <-> user copy */ #include <asm/byteorder.h> /* htons(), etc. */ -#include <asm/uaccess.h> /* copy_to_user */ #include <asm/io.h> #include <linux/wanrouter.h> /* WAN router API definitions */ -/****** Defines and Macros **************************************************/ -#define PROC_STATS_FORMAT "%30s: %12lu\n" +#if defined(LINUX_2_1) || defined(LINUX_2_4) + #include <linux/init.h> /* __initfunc et al. */ + #include <asm/uaccess.h> /* copy_to_user */ + #define PROC_STATS_FORMAT "%30s: %12lu\n" +#else + #define PROC_STATS_FORMAT "%30s: %12u\n" + #include <asm/segment.h> /* kernel <-> user copy */ +#endif + + +/****** Defines and Macros **************************************************/ #ifndef min #define min(a,b) (((a)<(b))?(a):(b)) #endif +#ifndef max +#define max(a,b) (((a)>(b))?(a):(b)) +#endif #define PROC_BUFSZ 4000 /* buffer size for printing proc info */ +#define PROT_DECODE(prot) ((prot == WANCONFIG_FR) ? " FR" :\ + (prot == WANCONFIG_X25) ? " X25" : \ + (prot == WANCONFIG_PPP) ? " PPP" : \ + (prot == WANCONFIG_CHDLC) ? " CHDLC": \ + (prot == WANCONFIG_MPPP) ? " MPPP" : \ + " Unknown" ) + +/****** Data Types **********************************************************/ + +typedef struct wan_stat_entry +{ + struct wan_stat_entry *next; + char *description; /* description string */ + void *data; /* -> data */ + unsigned data_type; /* data type */ +} wan_stat_entry_t; + /****** Function Prototypes *************************************************/ #ifdef CONFIG_PROC_FS -/* Proc filesystem interface */ -static int router_proc_perms(struct inode *, int); -static ssize_t router_proc_read(struct file* file, char* buf, size_t count, loff_t *ppos); -/* Methods for preparing data for reading proc entries */ +#ifdef LINUX_2_4 /* Start of LINUX 2.4.X code */ -static int config_get_info(char* buf, char** start, off_t offs, int len); -static int status_get_info(char* buf, char** start, off_t offs, int len); -static int wandev_get_info(char* buf, char** start, off_t offs, int len); -/* Miscellaneous */ + /* Proc filesystem interface */ + static int router_proc_perms(struct inode *, int); + static ssize_t router_proc_read(struct file* file, char* buf, size_t count, loff_t *ppos); + + /* Methods for preparing data for reading proc entries */ + + static int config_get_info(char* buf, char** start, off_t offs, int len); + static int status_get_info(char* buf, char** start, off_t offs, int len); + static int wandev_get_info(char* buf, char** start, off_t offs, int len); + + /* Miscellaneous */ + + /* + * Structures for interfacing with the /proc filesystem. + * Router creates its own directory /proc/net/router with the folowing + * entries: + * config device configuration + * status global device statistics + * <device> entry for each WAN device + */ + + /* + * Generic /proc/net/router/<file> file and inode operations + */ + static struct file_operations router_fops = + { + read: router_proc_read, + }; + + static struct inode_operations router_inode = + { + permission: router_proc_perms, + }; + + /* + * /proc/net/router/<device> file operations + */ + + static struct file_operations wandev_fops = + { + read: router_proc_read, + ioctl: wanrouter_ioctl, + }; + + /* + * /proc/net/router + */ + + static struct proc_dir_entry *proc_router; + + /* Strings */ + static char conf_hdr[] = + "Device name | port |IRQ|DMA| mem.addr |mem.size|" + "option1|option2|option3|option4\n"; + + static char stat_hdr[] = + "Device name |protocol|station|interface|clocking|baud rate" + "| MTU |ndev|link state\n"; + + + /* + * Interface functions + */ + + /* + * Initialize router proc interface. + */ + + int __init wanrouter_proc_init (void) + { + struct proc_dir_entry *p; + proc_router = proc_mkdir(ROUTER_NAME, proc_net); + if (!proc_router) + goto fail; + + p = create_proc_entry("config",0,proc_router); + if (!p) + goto fail_config; + p->proc_fops = &router_fops; + p->proc_iops = &router_inode; + p->get_info = config_get_info; + p = create_proc_entry("status",0,proc_router); + if (!p) + goto fail_stat; + p->proc_fops = &router_fops; + p->proc_iops = &router_inode; + p->get_info = status_get_info; + return 0; + fail_stat: + remove_proc_entry("config", proc_router); + fail_config: + remove_proc_entry(ROUTER_NAME, proc_net); + fail: + return -ENOMEM; + } -/* - * Structures for interfacing with the /proc filesystem. - * Router creates its own directory /proc/net/wanrouter with the folowing - * entries: - * config device configuration - * status global device statistics - * <device> entry for each WAN device - */ + /* + * Clean up router proc interface. + */ + + void wanrouter_proc_cleanup (void) + { + remove_proc_entry("config", proc_router); + remove_proc_entry("status", proc_router); + remove_proc_entry(ROUTER_NAME,proc_net); + } -/* - * Generic /proc/net/wanrouter/<file> file and inode operations - */ -static struct file_operations router_fops = -{ - read: router_proc_read, -}; + /* + * Add directory entry for WAN device. + */ + + int wanrouter_proc_add (wan_device_t* wandev) + { + if (wandev->magic != ROUTER_MAGIC) + return -EINVAL; + + wandev->dent = create_proc_entry(wandev->name, 0, proc_router); + if (!wandev->dent) + return -ENOMEM; + wandev->dent->proc_fops = &wandev_fops; + wandev->dent->proc_iops = &router_inode; + wandev->dent->get_info = wandev_get_info; + wandev->dent->data = wandev; + return 0; + } -static struct inode_operations router_inode = -{ - permission: router_proc_perms, -}; + /* + * Delete directory entry for WAN device. + */ + + int wanrouter_proc_delete(wan_device_t* wandev) + { + if (wandev->magic != ROUTER_MAGIC) + return -EINVAL; + remove_proc_entry(wandev->name, proc_router); + return 0; + } -/* - * /proc/net/wanrouter/<device> file operations - */ + /****** Proc filesystem entry points ****************************************/ -static struct file_operations wandev_fops = -{ - read: router_proc_read, - ioctl: wanrouter_ioctl, -}; + /* + * Verify access rights. + */ -/* - * /proc/net/wanrouter - */ + static int router_proc_perms (struct inode* inode, int op) + { + return 0; + } -static struct proc_dir_entry *proc_router; + /* + * Read router proc directory entry. + * This is universal routine for reading all entries in /proc/net/wanrouter + * directory. Each directory entry contains a pointer to the 'method' for + * preparing data for that entry. + * o verify arguments + * o allocate kernel buffer + * o call get_info() to prepare data + * o copy data to user space + * o release kernel buffer + * + * Return: number of bytes copied to user space (0, if no data) + * <0 error + */ + + static ssize_t router_proc_read(struct file* file, char* buf, size_t count, + loff_t *ppos) + { + struct inode *inode = file->f_dentry->d_inode; + struct proc_dir_entry* dent; + char* page; + int pos, offs, len; + + if (count <= 0) + return 0; + + dent = inode->u.generic_ip; + if ((dent == NULL) || (dent->get_info == NULL)) + return 0; + + page = kmalloc(PROC_BUFSZ, GFP_KERNEL); + if (page == NULL) + return -ENOBUFS; + + pos = dent->get_info(page, dent->data, 0, 0); + offs = file->f_pos; + if (offs < pos) { + len = min(pos - offs, count); + if(copy_to_user(buf, (page + offs), len)) + return -EFAULT; + file->f_pos += len; + } + else + len = 0; + kfree(page); + return len; + } -/* Strings */ -static char conf_hdr[] = - "Device name | port |IRQ|DMA| mem.addr |mem.size|" - "option1|option2|option3|option4\n"; - -static char stat_hdr[] = - "Device name |station|interface|clocking|baud rate| MTU |ndev" - "|link state\n"; + /* + * Prepare data for reading 'Config' entry. + * Return length of data. + */ + + static int config_get_info(char* buf, char** start, off_t offs, int len) + { + int cnt = sizeof(conf_hdr) - 1; + wan_device_t* wandev; + strcpy(buf, conf_hdr); + for (wandev = router_devlist; + wandev && (cnt < (PROC_BUFSZ - 120)); + wandev = wandev->next) { + if (wandev->state) cnt += sprintf(&buf[cnt], + "%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n", + wandev->name, + wandev->ioport, + wandev->irq, + wandev->dma, + wandev->maddr, + wandev->msize, + wandev->hw_opt[0], + wandev->hw_opt[1], + wandev->hw_opt[2], + wandev->hw_opt[3]); + } + return cnt; + } -/* - * Interface functions - */ + /* + * Prepare data for reading 'Status' entry. + * Return length of data. + */ + + static int status_get_info(char* buf, char** start, off_t offs, int len) + { + int cnt = 0; + wan_device_t* wandev; + + //cnt += sprintf(&buf[cnt], "\nSTATUS:\n\n"); + strcpy(&buf[cnt], stat_hdr); + cnt += sizeof(stat_hdr) - 1; + + for (wandev = router_devlist; + wandev && (cnt < (PROC_BUFSZ - 80)); + wandev = wandev->next) { + if (!wandev->state) continue; + cnt += sprintf(&buf[cnt], + "%-15s|%-8s|%-7s|%-9s|%-8s|%9u|%5u|%3u |", + wandev->name, + PROT_DECODE(wandev->config_id), + wandev->config_id == WANCONFIG_FR ? + (wandev->station ? " Node" : " CPE") : + (wandev->config_id == WANCONFIG_X25 ? + (wandev->station ? " DCE" : " DTE") : + (" N/A")), + wandev->interface ? " V.35" : " RS-232", + wandev->clocking ? "internal" : "external", + wandev->bps, + wandev->mtu, + wandev->ndev); + + switch (wandev->state) { + + case WAN_UNCONFIGURED: + cnt += sprintf(&buf[cnt], "%-12s\n", "unconfigured"); + break; + + case WAN_DISCONNECTED: + cnt += sprintf(&buf[cnt], "%-12s\n", "disconnected"); + break; + + case WAN_CONNECTING: + cnt += sprintf(&buf[cnt], "%-12s\n", "connecting"); + break; + + case WAN_CONNECTED: + cnt += sprintf(&buf[cnt], "%-12s\n", "connected"); + break; -/* - * Initialize router proc interface. - */ + default: + cnt += sprintf(&buf[cnt], "%-12s\n", "invalid"); + break; + } + } + return cnt; + } -int __init wanrouter_proc_init (void) -{ - struct proc_dir_entry *p; - proc_router = proc_mkdir(ROUTER_NAME, proc_net); - if (!proc_router) - goto fail; - - p = create_proc_entry("config",0,proc_router); - if (!p) - goto fail_config; - p->proc_fops = &router_fops; - p->proc_iops = &router_inode; - p->get_info = config_get_info; - p = create_proc_entry("status",0,proc_router); - if (!p) - goto fail_stat; - p->proc_fops = &router_fops; - p->proc_iops = &router_inode; - p->get_info = status_get_info; - return 0; -fail_stat: - remove_proc_entry("config", proc_router); -fail_config: - remove_proc_entry(ROUTER_NAME, proc_net); -fail: - return -ENOMEM; -} + /* + * Prepare data for reading <device> entry. + * Return length of data. + * + * On entry, the 'start' argument will contain a pointer to WAN device + * data space. + */ + + static int wandev_get_info(char* buf, char** start, off_t offs, int len) + { + wan_device_t* wandev = (void*)start; + int cnt = 0; + int rslt = 0; + + if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC)) + return 0; + if (!wandev->state) + return sprintf(&buf[cnt], "device is not configured!\n"); + + /* Update device statistics */ + if (wandev->update) { + + rslt = wandev->update(wandev); + if(rslt) { + switch (rslt) { + case -EAGAIN: + return sprintf(&buf[cnt], "Device is busy!\n"); + + default: + return sprintf(&buf[cnt], + "Device is not configured!\n"); + } + } + } -/* - * Clean up router proc interface. - */ + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "total packets received", wandev->stats.rx_packets); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "total packets transmitted", wandev->stats.tx_packets); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "total bytes received", wandev->stats.rx_bytes); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "total bytes transmitted", wandev->stats.tx_bytes); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "bad packets received", wandev->stats.rx_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "packet transmit problems", wandev->stats.tx_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "received frames dropped", wandev->stats.rx_dropped); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "transmit frames dropped", wandev->stats.tx_dropped); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "multicast packets received", wandev->stats.multicast); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "transmit collisions", wandev->stats.collisions); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "receive length errors", wandev->stats.rx_length_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "receiver overrun errors", wandev->stats.rx_over_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "CRC errors", wandev->stats.rx_crc_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "frame format errors (aborts)", wandev->stats.rx_frame_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "receiver fifo overrun", wandev->stats.rx_fifo_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "receiver missed packet", wandev->stats.rx_missed_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "aborted frames transmitted", wandev->stats.tx_aborted_errors); + return cnt; + } -void wanrouter_proc_cleanup (void) -{ - remove_proc_entry("config", proc_router); - remove_proc_entry("status", proc_router); - remove_proc_entry(ROUTER_NAME,proc_net); -} -/* - * Add directory entry for WAN device. - */ +#else /* ------------------- END OF LINUX 2.4.X VERSION -------------*/ -int wanrouter_proc_add (wan_device_t* wandev) -{ - if (wandev->magic != ROUTER_MAGIC) - return -EINVAL; - - wandev->dent = create_proc_entry(wandev->name, 0, proc_router); - if (!wandev->dent) - return -ENOMEM; - wandev->dent->proc_fops = &wandev_fops; - wandev->dent->proc_iops = &router_inode; - wandev->dent->get_info = wandev_get_info; - wandev->dent->data = wandev; - return 0; -} -/* - * Delete directory entry for WAN device. - */ - -int wanrouter_proc_delete(wan_device_t* wandev) -{ - if (wandev->magic != ROUTER_MAGIC) - return -EINVAL; - remove_proc_entry(wandev->name, proc_router); - return 0; -} -/****** Proc filesystem entry points ****************************************/ + /* Proc filesystem interface */ + static int router_proc_perms(struct inode *, int); +#ifdef LINUX_2_1 + static ssize_t router_proc_read(struct file *file, char *buf, size_t count, loff_t *ppos); +#else + static int router_proc_read( + struct inode* inode, struct file* file, char* buf, int count); + static int device_write( + struct inode* inode, struct file* file, const char* buf, int count); +#endif -/* - * Verify access rights. - */ + /* Methods for preparing data for reading proc entries */ + static int config_get_info(char* buf, char** start, off_t offs, int len, + int dummy); + static int status_get_info(char* buf, char** start, off_t offs, int len, + int dummy); + static int wandev_get_info(char* buf, char** start, off_t offs, int len, + int dummy); + + /* Miscellaneous */ + + /* + * Global Data + */ + + /* + * Names of the proc directory entries + */ + + static char name_root[] = ROUTER_NAME; + static char name_conf[] = "config"; + static char name_stat[] = "status"; + + /* + * Structures for interfacing with the /proc filesystem. + * Router creates its own directory /proc/net/router with the folowing + * entries: + * config device configuration + * status global device statistics + * <device> entry for each WAN device + */ + + /* + * Generic /proc/net/router/<file> file and inode operations + */ +#ifdef LINUX_2_1 + static struct file_operations router_fops = + { + NULL, /* lseek */ + router_proc_read, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* flush */ + NULL, /* no special release code */ + NULL /* can't fsync */ + }; +#else + static struct file_operations router_fops = + { + NULL, /* lseek */ + router_proc_read, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* can't fsync */ + }; +#endif -static int router_proc_perms (struct inode* inode, int op) -{ - return 0; -} + static struct inode_operations router_inode = + { + &router_fops, + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* follow link */ + NULL, /* readlink */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + router_proc_perms + }; + + /* + * /proc/net/router/<device> file and inode operations + */ + +#ifdef LINUX_2_1 + static struct file_operations wandev_fops = + { + NULL, /* lseek */ + router_proc_read, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + wanrouter_ioctl, /* ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* flush */ + NULL, /* no special release code */ + NULL /* can't fsync */ + }; +#else + static struct file_operations wandev_fops = + { + NULL, /* lseek */ + router_proc_read, /* read */ + device_write, /* write */ + NULL, /* readdir */ + NULL, /* select */ + wanrouter_ioctl, /* ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* can't fsync */ + }; +#endif -/* - * Read router proc directory entry. - * This is universal routine for reading all entries in /proc/net/wanrouter - * directory. Each directory entry contains a pointer to the 'method' for - * preparing data for that entry. - * o verify arguments - * o allocate kernel buffer - * o call get_info() to prepare data - * o copy data to user space - * o release kernel buffer - * - * Return: number of bytes copied to user space (0, if no data) - * <0 error - */ + static struct inode_operations wandev_inode = + { + &wandev_fops, + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + router_proc_perms + }; + + /* + * Proc filesystem derectory entries. + */ + + /* + * /proc/net/router + */ + + static struct proc_dir_entry proc_router = + { + 0, /* .low_ino */ + sizeof(name_root) - 1, /* .namelen */ + name_root, /* .name */ + 0555 | S_IFDIR, /* .mode */ + 2, /* .nlink */ + 0, /* .uid */ + 0, /* .gid */ + 0, /* .size */ + &proc_dir_inode_operations, /* .ops */ + NULL, /* .get_info */ + NULL, /* .fill_node */ + NULL, /* .next */ + NULL, /* .parent */ + NULL, /* .subdir */ + NULL, /* .data */ + }; + + /* + * /proc/net/router/config + */ + + static struct proc_dir_entry proc_router_conf = + { + 0, /* .low_ino */ + sizeof(name_conf) - 1, /* .namelen */ + name_conf, /* .name */ + 0444 | S_IFREG, /* .mode */ + 1, /* .nlink */ + 0, /* .uid */ + 0, /* .gid */ + 0, /* .size */ + &router_inode, /* .ops */ + &config_get_info, /* .get_info */ + NULL, /* .fill_node */ + NULL, /* .next */ + NULL, /* .parent */ + NULL, /* .subdir */ + NULL, /* .data */ + }; + + /* + * /proc/net/router/status + */ + + static struct proc_dir_entry proc_router_stat = + { + 0, /* .low_ino */ + sizeof(name_stat) - 1, /* .namelen */ + name_stat, /* .name */ + 0444 | S_IFREG, /* .mode */ + 1, /* .nlink */ + 0, /* .uid */ + 0, /* .gid */ + 0, /* .size */ + &router_inode, /* .ops */ + status_get_info, /* .get_info */ + NULL, /* .fill_node */ + NULL, /* .next */ + NULL, /* .parent */ + NULL, /* .subdir */ + NULL, /* .data */ + }; + + /* Strings */ + static char conf_hdr[] = + "Device name | port |IRQ|DMA| mem.addr |mem.size|" + "option1|option2|option3|option4\n"; + + static char stat_hdr[] = + "Device name |protocol|station|interface|clocking|baud rate| MTU |ndev" + "|link state\n"; + + + /* + * Interface functions + */ + + /* + * Initialize router proc interface. + */ + +#ifdef LINUX_2_1 + __initfunc(int wanrouter_proc_init (void)) + { + int err = proc_register(proc_net, &proc_router); + + if (!err) { + proc_register(&proc_router, &proc_router_conf); + proc_register(&proc_router, &proc_router_stat); + } + return err; + } +#else + int wanrouter_proc_init (void) + { + int err = proc_register_dynamic(&proc_net, &proc_router); + + if (!err) { + proc_register_dynamic(&proc_router, &proc_router_conf); + proc_register_dynamic(&proc_router, &proc_router_stat); + } + return err; + } +#endif -static ssize_t router_proc_read(struct file* file, char* buf, size_t count, - loff_t *ppos) -{ - struct inode *inode = file->f_dentry->d_inode; - struct proc_dir_entry* dent; - char* page; - int pos, offs, len; + /* + * Clean up router proc interface. + */ + + void wanrouter_proc_cleanup (void) + { + proc_unregister(&proc_router, proc_router_conf.low_ino); + proc_unregister(&proc_router, proc_router_stat.low_ino); +#ifdef LINUX_2_1 + proc_unregister(proc_net, proc_router.low_ino); +#else + proc_unregister(&proc_net, proc_router.low_ino); +#endif + } - if (count <= 0) - return 0; - - dent = inode->u.generic_ip; - if ((dent == NULL) || (dent->get_info == NULL)) - return 0; + /* + * Add directory entry for WAN device. + */ + + int wanrouter_proc_add (wan_device_t* wandev) + { + if (wandev->magic != ROUTER_MAGIC) + return -EINVAL; - page = kmalloc(PROC_BUFSZ, GFP_KERNEL); - if (page == NULL) - return -ENOBUFS; - - pos = dent->get_info(page, dent->data, 0, 0); - offs = file->f_pos; - if (offs < pos) { - len = min(pos - offs, count); - if(copy_to_user(buf, (page + offs), len)) { - len = -EFAULT; - goto out; - } - file->f_pos += len; - } - else - len = 0; -out: kfree(page); - return len; -} - -/* - * Prepare data for reading 'Config' entry. - * Return length of data. - */ + memset(&wandev->dent, 0, sizeof(wandev->dent)); + wandev->dent.namelen = strlen(wandev->name); + wandev->dent.name = wandev->name; + wandev->dent.mode = 0444 | S_IFREG; + wandev->dent.nlink = 1; + wandev->dent.ops = &wandev_inode; + wandev->dent.get_info = &wandev_get_info; + wandev->dent.data = wandev; +#ifdef LINUX_2_1 + return proc_register(&proc_router, &wandev->dent); +#else + return proc_register_dynamic(&proc_router, &wandev->dent); +#endif + } -static int config_get_info(char* buf, char** start, off_t offs, int len) -{ - int cnt = sizeof(conf_hdr) - 1; - wan_device_t* wandev; - strcpy(buf, conf_hdr); - for (wandev = router_devlist; - wandev && (cnt < (PROC_BUFSZ - 120)); - wandev = wandev->next) { - if (wandev->state) cnt += sprintf(&buf[cnt], - "%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n", - wandev->name, - wandev->ioport, - wandev->irq, - wandev->dma, - wandev->maddr, - wandev->msize, - wandev->hw_opt[0], - wandev->hw_opt[1], - wandev->hw_opt[2], - wandev->hw_opt[3]); + /* + * Delete directory entry for WAN device. + */ + + int wanrouter_proc_delete(wan_device_t* wandev) + { + if (wandev->magic != ROUTER_MAGIC) + return -EINVAL; + proc_unregister(&proc_router, wandev->dent.low_ino); + return 0; } - return cnt; -} + /****** Proc filesystem entry points ****************************************/ -/* - * Prepare data for reading 'Status' entry. - * Return length of data. - */ + /* + * Verify access rights. + */ -static int status_get_info(char* buf, char** start, off_t offs, int len) -{ - int cnt = 0; - wan_device_t* wandev; + static int router_proc_perms (struct inode* inode, int op) + { + return 0; + } - cnt += sprintf(&buf[cnt], "\nSTATUS FOR PORT 0\n\n"); - strcpy(&buf[cnt], stat_hdr); - cnt += sizeof(stat_hdr) - 1; - - for (wandev = router_devlist; - wandev && (cnt < (PROC_BUFSZ - 80)); - wandev = wandev->next) { - if (!wandev->state) continue; - cnt += sprintf(&buf[cnt], - "%-15s|%-7s|%-9s|%-8s|%9u|%5u|%3u |", - wandev->name, - wandev->station ? " DCE" : " DTE", - wandev->interface ? " V.35" : " RS-232", - wandev->clocking ? "internal" : "external", - wandev->bps, - wandev->mtu, - wandev->ndev); - - switch (wandev->state) { - - case WAN_UNCONFIGURED: - cnt += sprintf(&buf[cnt], "%-12s\n", "unconfigured"); - break; - - case WAN_DISCONNECTED: - cnt += sprintf(&buf[cnt], "%-12s\n", "disconnected"); - break; - - case WAN_CONNECTING: - cnt += sprintf(&buf[cnt], "%-12s\n", "connecting"); - break; - - case WAN_CONNECTED: - cnt += sprintf(&buf[cnt], "%-12s\n", "connected"); - break; - - default: - cnt += sprintf(&buf[cnt], "%-12s\n", "invalid"); - break; + /* + * Read router proc directory entry. + * This is universal routine for reading all entries in /proc/net/wanrouter + * directory. Each directory entry contains a pointer to the 'method' for + * preparing data for that entry. + * o verify arguments + * o allocate kernel buffer + * o call get_info() to prepare data + * o copy data to user space + * o release kernel buffer + * + * Return: number of bytes copied to user space (0, if no data) + * <0 error + */ +#ifdef LINUX_2_1 + static ssize_t router_proc_read(struct file* file, char* buf, size_t count, + loff_t *ppos) + { + struct inode *inode = file->f_dentry->d_inode; + struct proc_dir_entry* dent; + char* page; + int pos, offs, len; + + if (count <= 0) + return 0; + + dent = inode->u.generic_ip; + if ((dent == NULL) || (dent->get_info == NULL)) + return 0; + + page = kmalloc(PROC_BUFSZ, GFP_KERNEL); + if (page == NULL) + return -ENOBUFS; + + pos = dent->get_info(page, dent->data, 0, 0, 0); + offs = file->f_pos; + if (offs < pos) { + len = min(pos - offs, count); + if(copy_to_user(buf, (page + offs), len)) + return -EFAULT; + file->f_pos += len; } + else + len = 0; + kfree(page); + return len; } - return cnt; -} -/* - * Prepare data for reading <device> entry. - * Return length of data. - * - * On entry, the 'start' argument will contain a pointer to WAN device - * data space. - */ +#else + static int router_proc_read( + struct inode* inode, struct file* file, char* buf, int count) + { + struct proc_dir_entry* dent; + char* page; + int err, pos, offs, len; + + if (count <= 0) + return 0; + dent = inode->u.generic_ip; + if ((dent == NULL) || (dent->get_info == NULL)) + return -ENODATA; + err = verify_area(VERIFY_WRITE, buf, count); + if (err) return err; + + page = kmalloc(PROC_BUFSZ, GFP_KERNEL); + if (page == NULL) + return -ENOMEM; + + pos = dent->get_info(page, dent->data, 0, 0, 0); + offs = file->f_pos; + if (offs < pos) { + len = min(pos - offs, count); + memcpy_tofs((void*)buf, (void*)(page + offs), len); + file->f_pos += len; + } + else len = 0; + kfree(page); + return len; + } +#endif -static int wandev_get_info(char* buf, char** start, off_t offs, int len) -{ - wan_device_t* wandev = (void*)start; - int cnt = 0; - int rslt = 0; - if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC)) - return 0; - if (!wandev->state) - return sprintf(&buf[cnt], "device is not configured!\n"); + /* + * Prepare data for reading 'Config' entry. + * Return length of data. + */ + + static int config_get_info(char* buf, char** start, off_t offs, int len, + int dummy) + { + int cnt = sizeof(conf_hdr) - 1; + wan_device_t* wandev; + strcpy(buf, conf_hdr); + for (wandev = router_devlist; + wandev && (cnt < (PROC_BUFSZ - 120)); + wandev = wandev->next) { + if (wandev->state) cnt += sprintf(&buf[cnt], + "%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n", + wandev->name, + wandev->ioport, + wandev->irq, + wandev->dma, + wandev->maddr, + wandev->msize, + wandev->hw_opt[0], + wandev->hw_opt[1], + wandev->hw_opt[2], + wandev->hw_opt[3]); + } - /* Update device statistics */ - if (wandev->update) { + return cnt; + } - rslt = wandev->update(wandev); - if(rslt) { - switch (rslt) { - case -EAGAIN: - return sprintf(&buf[cnt], "Device is busy!\n"); + /* + * Prepare data for reading 'Status' entry. + * Return length of data. + */ + + static int status_get_info(char* buf, char** start, off_t offs, int len, + int dummy) + { + int cnt = 0; + wan_device_t* wandev; + + //cnt += sprintf(&buf[cnt], "\nSTATUS:\n\n"); + strcpy(&buf[cnt], stat_hdr); + cnt += sizeof(stat_hdr) - 1; + + for (wandev = router_devlist; + wandev && (cnt < (PROC_BUFSZ - 80)); + wandev = wandev->next) { + if (!wandev->state) continue; + cnt += sprintf(&buf[cnt], + "%-15s|%-8s|%-7s|%-9s|%-8s|%9u|%5u|%3u |", + wandev->name, + PROT_DECODE(wandev->config_id), + wandev->config_id == WANCONFIG_FR ? + (wandev->station ? " Node" : " CPE") : + (wandev->config_id == WANCONFIG_X25 ? + (wandev->station ? " DCE" : " DTE") : + (" N/A")), + wandev->interface ? " V.35" : " RS-232", + wandev->clocking ? "internal" : "external", + wandev->bps, + wandev->mtu, + wandev->ndev); + + switch (wandev->state) { + + case WAN_UNCONFIGURED: + cnt += sprintf(&buf[cnt], "%-12s\n", "unconfigured"); + break; + + case WAN_DISCONNECTED: + cnt += sprintf(&buf[cnt], "%-12s\n", "disconnected"); + break; + + case WAN_CONNECTING: + cnt += sprintf(&buf[cnt], "%-12s\n", "connecting"); + break; + + case WAN_CONNECTED: + cnt += sprintf(&buf[cnt], "%-12s\n", "connected"); + break; + + case WAN_FT1_READY: + cnt += sprintf(&buf[cnt], "%-12s\n", "ft1 ready"); + break; default: - return sprintf(&buf[cnt], - "Device is not configured!\n"); + cnt += sprintf(&buf[cnt], "%-12s\n", "invalid"); + break; } } + return cnt; } - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "total packets received", wandev->stats.rx_packets); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "total packets transmitted", wandev->stats.tx_packets); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "total bytes received", wandev->stats.rx_bytes); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "total bytes transmitted", wandev->stats.tx_bytes); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "bad packets received", wandev->stats.rx_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "packet transmit problems", wandev->stats.tx_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "received frames dropped", wandev->stats.rx_dropped); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "transmit frames dropped", wandev->stats.tx_dropped); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "multicast packets received", wandev->stats.multicast); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "transmit collisions", wandev->stats.collisions); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "receive length errors", wandev->stats.rx_length_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "receiver overrun errors", wandev->stats.rx_over_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "CRC errors", wandev->stats.rx_crc_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "frame format errors (aborts)", wandev->stats.rx_frame_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "receiver fifo overrun", wandev->stats.rx_fifo_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "receiver missed packet", wandev->stats.rx_missed_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "aborted frames transmitted", wandev->stats.tx_aborted_errors); - return cnt; -} + /* + * Prepare data for reading <device> entry. + * Return length of data. + * + * On entry, the 'start' argument will contain a pointer to WAN device + * data space. + */ + + static int wandev_get_info(char* buf, char** start, off_t offs, int len, + int dummy) + { + wan_device_t* wandev = (void*)start; + int cnt = 0; + int rslt = 0; + + if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC)) + return 0; + if (!wandev->state) + return sprintf(&buf[cnt], "Device is not configured!\n"); + + /* Update device statistics */ + if (wandev->update) { + + rslt = wandev->update(wandev); + if(rslt) { + switch (rslt) { + case -EAGAIN: + return sprintf(&buf[cnt], "Device is busy!\n"); + + default: + return sprintf(&buf[cnt], + "Device is not configured!\n"); + } + } + } + + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "total packets received", wandev->stats.rx_packets); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "total packets transmitted", wandev->stats.tx_packets); +#ifdef LINUX_2_1 + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "total bytes received", wandev->stats.rx_bytes); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "total bytes transmitted", wandev->stats.tx_bytes); +#endif + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "bad packets received", wandev->stats.rx_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "packet transmit problems", wandev->stats.tx_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "received frames dropped", wandev->stats.rx_dropped); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "transmit frames dropped", wandev->stats.tx_dropped); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "multicast packets received", wandev->stats.multicast); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "transmit collisions", wandev->stats.collisions); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "receive length errors", wandev->stats.rx_length_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "receiver overrun errors", wandev->stats.rx_over_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "CRC errors", wandev->stats.rx_crc_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "frame format errors (aborts)", wandev->stats.rx_frame_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "receiver fifo overrun", wandev->stats.rx_fifo_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "receiver missed packet", wandev->stats.rx_missed_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "aborted frames transmitted", wandev->stats.tx_aborted_errors); + + return cnt; + } + +#endif /* End of ifdef LINUX_2_4 */ + -/* - * End - */ - #else /* * No /proc - output stubs */ - -int __init wanrouter_proc_init(void) + +__initfunc(int wanrouter_proc_init(void)) { return 0; } @@ -436,6 +1055,33 @@ return 0; } +#endif + +/*============================================================================ + * Write WAN device ???. + * o Find WAN device associated with this node + */ +#ifdef LINUX_2_0 +static int device_write( + struct inode* inode, struct file* file, const char* buf, int count) +{ + int err = verify_area(VERIFY_READ, buf, count); + struct proc_dir_entry* dent; + wan_device_t* wandev; + + if (err) return err; + + dent = inode->u.generic_ip; + if ((dent == NULL) || (dent->data == NULL)) + return -ENODATA; + + wandev = dent->data; + + printk(KERN_ERR "%s: writing %d bytes to %s...\n", + name_root, count, dent->name); + + return 0; +} #endif /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/x25/af_x25.c linux.ac/net/x25/af_x25.c --- linux.vanilla/net/x25/af_x25.c Mon Jan 22 21:32:10 2001 +++ linux.ac/net/x25/af_x25.c Sat Apr 14 01:53:21 2001 @@ -409,6 +409,9 @@ len = min(len, sizeof(int)); + if (len < 0) + return -EINVAL; + if (put_user(len, optlen)) return -EFAULT; @@ -912,7 +915,7 @@ size = len + X25_MAX_L2_LEN + X25_EXT_MIN_LEN; - if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) + if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) return err; X25_SKB_CB(skb)->flags = msg->msg_flags; @@ -1283,6 +1286,7 @@ sendmsg: x25_sendmsg, recvmsg: x25_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #include <linux/smp_lock.h> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/x25/x25_out.c linux.ac/net/x25/x25_out.c --- linux.vanilla/net/x25/x25_out.c Wed Jan 24 23:28:36 2001 +++ linux.ac/net/x25/x25_out.c Sat Apr 14 01:53:21 2001 @@ -79,7 +79,7 @@ frontlen = skb_headroom(skb); while (skb->len > 0) { - if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len, 0, noblock, &err)) == NULL){ + if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len, noblock, &err)) == NULL){ if(err == -EWOULDBLOCK && noblock){ kfree_skb(skb); return sent; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/scripts/lxdialog/checklist.c linux.ac/scripts/lxdialog/checklist.c --- linux.vanilla/scripts/lxdialog/checklist.c Sun Feb 4 18:05:30 2001 +++ linux.ac/scripts/lxdialog/checklist.c Tue Apr 10 18:27:46 2001 @@ -211,13 +211,15 @@ status[i+scroll], i, i == choice); } - wnoutrefresh (list); - print_arrows(dialog, choice, item_no, scroll, box_y, box_x + check_x + 5, list_height); print_buttons(dialog, height, width, 0); + wnoutrefresh (list); + wnoutrefresh (dialog); + doupdate (); + while (key != ESC) { key = wgetch (dialog); @@ -355,7 +357,11 @@ case ESC: break; } + + /* Now, update everything... */ + doupdate (); } + delwin (dialog); free (status); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/scripts/tkgen.c linux.ac/scripts/tkgen.c --- linux.vanilla/scripts/tkgen.c Mon Jun 19 21:45:52 2000 +++ linux.ac/scripts/tkgen.c Tue Apr 10 18:27:46 2001 @@ -155,7 +155,7 @@ printf("\"catch {focus $oldFocus}; " ); /* * We are checking which windows should be destroyed and which are - * common parrents with the next one. Remember that menu_num field + * common parents with the next one. Remember that menu_num field * in mainmenu_option record reports number of its *parent* menu. */ if ( menu_num < tot_menu_num diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/scripts/ver_linux linux.ac/scripts/ver_linux --- linux.vanilla/scripts/ver_linux Tue Apr 3 17:32:31 2001 +++ linux.ac/scripts/ver_linux Sat Apr 14 01:53:25 2001 @@ -20,7 +20,9 @@ ld -v 2>&1 | awk -F\) '{print $1}' | awk \ '/BFD/{print "binutils ",$NF}' -mount --version | awk -F\- '{print "util-linux ", $NF}' +fdformat --version | awk -F\- '{print "util-linux ", $NF}' + +mount --version | awk -F\- '{print "mount ", $NF}' insmod -V 2>&1 | awk 'NR==1 {print "modutils ",$NF}'